From bb87a81d69aad5eaa82ce64a7ccda8104dbb6b20 Mon Sep 17 00:00:00 2001 From: Slushie Date: Sun, 20 Jun 2021 17:59:25 +0100 Subject: [PATCH 01/17] feat: add contributors command --- src/commands/contributors.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/commands/contributors.py diff --git a/src/commands/contributors.py b/src/commands/contributors.py new file mode 100644 index 0000000..1421c7d --- /dev/null +++ b/src/commands/contributors.py @@ -0,0 +1,17 @@ +import requests +from decorators import static_command +description = "shows the contributors of the bot" + +@static_command +def main(): + try: + resp = requests.get("https://api.github.com/repos/adibozzhanov/PyukuBot/contributors?anon=1") + resp.raise_for_status() + except requests.HTTPError: + return "Error. Github API cannot be accessed." + else: + data = resp.json() + contributors = [user["login"] for user in data] + if len(contributors) == 1: + return "The contributor to PyukuBot is" + contributors[0] + "." + return "The contributors to PyukuBot are " + ", ".join(contributors[:-1]) + " and " + contributors[-1] + "." From bd5c43406696e906166adf4093fc4f082a54a271 Mon Sep 17 00:00:00 2001 From: Slushie Date: Sun, 20 Jun 2021 18:15:20 +0100 Subject: [PATCH 02/17] feat: remove use of eval --- src/commands/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/commands/__init__.py b/src/commands/__init__.py index ee09104..03be63b 100644 --- a/src/commands/__init__.py +++ b/src/commands/__init__.py @@ -1,4 +1,5 @@ from os import walk +from importlib import import_module f = [] commands = {} @@ -13,6 +14,5 @@ # Import each of them and populate the commands dictionary for each in f: cm = each[:len(each)- 3] # Truncate the .py at the end - exec(f"from .{cm} import *") - commands[cm] = (eval(f"{cm}.main"), eval(f"{cm}.description")) - + module = import_module(f".{cm}", "commands") + commands[cm] = module.main, module.description From 7e024dd9322c87987eb2e4a62df83227b4587459 Mon Sep 17 00:00:00 2001 From: adibozzhanov Date: Sun, 20 Jun 2021 18:19:38 +0100 Subject: [PATCH 03/17] fix: git ignore --- .gitignore | 1 + src/.token~ | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 src/.token~ diff --git a/.gitignore b/.gitignore index f26b9ef..5b50af3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .token +.token~ __pycache__ \ No newline at end of file diff --git a/src/.token~ b/src/.token~ deleted file mode 100644 index 724e240..0000000 --- a/src/.token~ +++ /dev/null @@ -1 +0,0 @@ -1850056100:AAGki5PflfrwQlX4aQ7a6ErnCCxfwLRrxyA From 89f978406f07da9b7e9aa1a8b0ef1c72bb993574 Mon Sep 17 00:00:00 2001 From: Adi Bozzhanov Date: Fri, 25 Jun 2021 20:21:26 +0100 Subject: [PATCH 04/17] formatted all the code --- src/commands/__init__.py | 4 ++-- src/commands/contributors.py | 14 ++++++++++++-- src/commands/flip.py | 2 ++ src/commands/hello_pyuku.py | 9 ++++++++- src/commands/roll.py | 3 ++- src/commands/yn.py | 4 +--- src/decorators.py | 13 ++++++------- src/pyuku.py | 11 ++--------- src/run.py | 2 -- 9 files changed, 35 insertions(+), 27 deletions(-) diff --git a/src/commands/__init__.py b/src/commands/__init__.py index 03be63b..6a9f343 100644 --- a/src/commands/__init__.py +++ b/src/commands/__init__.py @@ -6,13 +6,13 @@ # Make a list of command names -for (dirpath,dirnames,filenames) in walk("commands"): +for (dirpath, dirnames, filenames) in walk("commands"): if dirpath == "commands": f.extend(filenames) f.remove("__init__.py") # Import each of them and populate the commands dictionary for each in f: - cm = each[:len(each)- 3] # Truncate the .py at the end + cm = each[: len(each) - 3] # Truncate the .py at the end module = import_module(f".{cm}", "commands") commands[cm] = module.main, module.description diff --git a/src/commands/contributors.py b/src/commands/contributors.py index 1421c7d..37d8193 100644 --- a/src/commands/contributors.py +++ b/src/commands/contributors.py @@ -1,11 +1,15 @@ import requests from decorators import static_command + description = "shows the contributors of the bot" + @static_command def main(): try: - resp = requests.get("https://api.github.com/repos/adibozzhanov/PyukuBot/contributors?anon=1") + resp = requests.get( + "https://api.github.com/repos/adibozzhanov/PyukuBot/contributors?anon=1" + ) resp.raise_for_status() except requests.HTTPError: return "Error. Github API cannot be accessed." @@ -14,4 +18,10 @@ def main(): contributors = [user["login"] for user in data] if len(contributors) == 1: return "The contributor to PyukuBot is" + contributors[0] + "." - return "The contributors to PyukuBot are " + ", ".join(contributors[:-1]) + " and " + contributors[-1] + "." + return ( + "The contributors to PyukuBot are " + + ", ".join(contributors[:-1]) + + " and " + + contributors[-1] + + "." + ) diff --git a/src/commands/flip.py b/src/commands/flip.py index 40cc5aa..7f27946 100644 --- a/src/commands/flip.py +++ b/src/commands/flip.py @@ -1,7 +1,9 @@ import random from decorators import static_command + description = "flips a coin" + @static_command def main(): choices = ["HEADS", "TAILS"] diff --git a/src/commands/hello_pyuku.py b/src/commands/hello_pyuku.py index 4a65c26..de70396 100644 --- a/src/commands/hello_pyuku.py +++ b/src/commands/hello_pyuku.py @@ -2,7 +2,14 @@ from decorators import named_static_command description = "says hello to the user" + + @named_static_command def main(name): - greetings = ["pleased to meet you", "it's very nice to meet you", "fuck you", "pleased to make your acquaintance"] + greetings = [ + "pleased to meet you", + "it's very nice to meet you", + "fuck you", + "pleased to make your acquaintance", + ] return f"Hello {name}, {choice(greetings)}!" diff --git a/src/commands/roll.py b/src/commands/roll.py index cb313af..d46e637 100644 --- a/src/commands/roll.py +++ b/src/commands/roll.py @@ -3,7 +3,8 @@ description = "rolls a number between 0 and 100" + @named_static_command def main(name): - num = random.randint(0,100) + num = random.randint(0, 100) return f"{name} rolled a number: {num}" diff --git a/src/commands/yn.py b/src/commands/yn.py index d3d37a6..bc6603f 100644 --- a/src/commands/yn.py +++ b/src/commands/yn.py @@ -3,10 +3,8 @@ description = "answers yes or no" + @static_command def main(): answers = ["YES", "NO"] return random.choice(answers) - - - diff --git a/src/decorators.py b/src/decorators.py index c6496c2..2e243fe 100644 --- a/src/decorators.py +++ b/src/decorators.py @@ -1,4 +1,4 @@ -bot = None # this will get overwritten in the bot class. Very hacky but Idc +bot = None # this will get overwritten in the bot class. Very hacky but Idc # Documentaion for how to use these can be found in the readme @@ -8,18 +8,17 @@ def static_command(func): def command(update, context): chat_id = update.message.chat.id text = func() - bot.send_message(chat_id = chat_id, text = text) + bot.send_message(chat_id=chat_id, text=text) + return command + # use that if you want to include senders name in the reply message def named_static_command(func): def command(update, context): chat_id = update.message.chat.id name = update.message.from_user.first_name text = func(name) - bot.send_message(chat_id = chat_id, text = text) + bot.send_message(chat_id=chat_id, text=text) + return command - - - - diff --git a/src/pyuku.py b/src/pyuku.py index 4d0049d..187728c 100644 --- a/src/pyuku.py +++ b/src/pyuku.py @@ -4,12 +4,12 @@ from telegram import Bot from telegram.ext import Updater, CommandHandler, MessageHandler, Filters -class Pyuku(Bot): +class Pyuku(Bot): def __init__(self, token): super().__init__(token) - updater = Updater(token, use_context = True) + updater = Updater(token, use_context=True) self.dp = updater.dispatcher @@ -29,10 +29,3 @@ def initHandlers(self): # Help is a special command handler that contains info about each command # Thus we create it automatically after all handlers are initialised - - - - - - - diff --git a/src/run.py b/src/run.py index 1d78de5..4413552 100644 --- a/src/run.py +++ b/src/run.py @@ -7,7 +7,5 @@ with open(".token", "r") as tokenFile: token = tokenFile.readline().strip() Pyuku(token) - except IOError: print("No token file detected.") - From 682c7a8142c336c991685d1fd8bc2daf06791515 Mon Sep 17 00:00:00 2001 From: Adi Bozzhanov Date: Mon, 28 Jun 2021 12:53:57 +0100 Subject: [PATCH 05/17] feat: added a comment --- src/bot.py | 76 +++++++++++++++++++++++++++++++++++++++++++++++++ src/bottoken.py | 1 + src/pyuku.py | 2 +- 3 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 src/bot.py create mode 100644 src/bottoken.py diff --git a/src/bot.py b/src/bot.py new file mode 100644 index 0000000..5564a48 --- /dev/null +++ b/src/bot.py @@ -0,0 +1,76 @@ +import random +from bottoken import TOKEN +from telegram import Bot + +from telegram.ext import Updater, CommandHandler, MessageHandler, Filters + + +class Pyukumuku(Bot): + def __init__(self): + super().__init__(TOKEN) + self.coin = ["HEADS", "TAILS"] + self.yesno = ["YES", "NO"] + + + updater = Updater(TOKEN, use_context = True) + + dp = updater.dispatcher + + dp.add_handler(CommandHandler("flip", self.flip)) + dp.add_handler(CommandHandler("yn", self.yn)) + dp.add_handler(CommandHandler("roll", self.roll)) + dp.add_handler(CommandHandler("help", self.help)) + dp.add_error_handler(self.error) + + updater.start_polling() + print("Pyukumuku is running") + updater.idle() + + + def help(self, update, context): + chat_id = update.message.chat.id + msg_id = update.message.message_id + + self.sendMessage(chat_id = chat_id, text = f"Commands:\n/flip - flips a coin\n/yn - yes/no answer\n/roll - a random number between n1 and n2") + + + def flip(self,update, context): + chat_id = update.message.chat.id + msg_id = update.message.message_id + + c = random.choice(self.coin) + self.sendMessage(chat_id = chat_id, text = f"The coin landed on {c}") + + def yn(self, update, context): + chat_id = update.message.chat.id + msg_id = update.message.message_id + + c = random.choice(self.yesno) + self.sendMessage(chat_id = chat_id, text = f"I am confident that the answer is {c}") + + def roll(self, update, context): + chat_id = update.message.chat.id + msg_id = update.message.message_id + name = update.message.from_user.first_name + + try: + val1, val2 = context.args[0], context.args[1] + ret = random.randint(int(val1), int(val2)) + self.sendMessage(chat_id = chat_id, text = f"Here is a numebr for you: {ret}") + except: + self.sendMessage(chat_id = chat_id, text = f"I'm sorry {name}, but it seems like your brain is too small to use roll.\n\nHint: roll n1 n2. (n1 < n2)") + + + + + def error(self,update, context): + print(f"Update {update} caused an error {context.error}") + + + + + + +if __name__ == "__main__": + Pyukumuku() + diff --git a/src/bottoken.py b/src/bottoken.py new file mode 100644 index 0000000..2b0154c --- /dev/null +++ b/src/bottoken.py @@ -0,0 +1 @@ +TOKEN = "1850056100:AAGki5PflfrwQlX4aQ7a6ErnCCxfwLRrxyA" diff --git a/src/pyuku.py b/src/pyuku.py index 187728c..8ad1b60 100644 --- a/src/pyuku.py +++ b/src/pyuku.py @@ -4,7 +4,7 @@ from telegram import Bot from telegram.ext import Updater, CommandHandler, MessageHandler, Filters - +# This is the main bot class class Pyuku(Bot): def __init__(self, token): super().__init__(token) From ba7e1e86d69f6f196c9ee1599dc200a1785a9548 Mon Sep 17 00:00:00 2001 From: Adi Bozzhanov Date: Tue, 29 Jun 2021 02:17:10 +0100 Subject: [PATCH 06/17] fix: removed bot.py --- src/bot.py | 76 ------------------------------------------------------ 1 file changed, 76 deletions(-) delete mode 100644 src/bot.py diff --git a/src/bot.py b/src/bot.py deleted file mode 100644 index 5564a48..0000000 --- a/src/bot.py +++ /dev/null @@ -1,76 +0,0 @@ -import random -from bottoken import TOKEN -from telegram import Bot - -from telegram.ext import Updater, CommandHandler, MessageHandler, Filters - - -class Pyukumuku(Bot): - def __init__(self): - super().__init__(TOKEN) - self.coin = ["HEADS", "TAILS"] - self.yesno = ["YES", "NO"] - - - updater = Updater(TOKEN, use_context = True) - - dp = updater.dispatcher - - dp.add_handler(CommandHandler("flip", self.flip)) - dp.add_handler(CommandHandler("yn", self.yn)) - dp.add_handler(CommandHandler("roll", self.roll)) - dp.add_handler(CommandHandler("help", self.help)) - dp.add_error_handler(self.error) - - updater.start_polling() - print("Pyukumuku is running") - updater.idle() - - - def help(self, update, context): - chat_id = update.message.chat.id - msg_id = update.message.message_id - - self.sendMessage(chat_id = chat_id, text = f"Commands:\n/flip - flips a coin\n/yn - yes/no answer\n/roll - a random number between n1 and n2") - - - def flip(self,update, context): - chat_id = update.message.chat.id - msg_id = update.message.message_id - - c = random.choice(self.coin) - self.sendMessage(chat_id = chat_id, text = f"The coin landed on {c}") - - def yn(self, update, context): - chat_id = update.message.chat.id - msg_id = update.message.message_id - - c = random.choice(self.yesno) - self.sendMessage(chat_id = chat_id, text = f"I am confident that the answer is {c}") - - def roll(self, update, context): - chat_id = update.message.chat.id - msg_id = update.message.message_id - name = update.message.from_user.first_name - - try: - val1, val2 = context.args[0], context.args[1] - ret = random.randint(int(val1), int(val2)) - self.sendMessage(chat_id = chat_id, text = f"Here is a numebr for you: {ret}") - except: - self.sendMessage(chat_id = chat_id, text = f"I'm sorry {name}, but it seems like your brain is too small to use roll.\n\nHint: roll n1 n2. (n1 < n2)") - - - - - def error(self,update, context): - print(f"Update {update} caused an error {context.error}") - - - - - - -if __name__ == "__main__": - Pyukumuku() - From 439de51b2cd0bed5deb9624ea52b1e34e47827ff Mon Sep 17 00:00:00 2001 From: Adi Bozzhanov Date: Tue, 29 Jun 2021 02:40:52 +0100 Subject: [PATCH 07/17] feat: setup virtual environment --- venv/bin/Activate.ps1 | 241 + venv/bin/activate | 76 + venv/bin/activate.csh | 37 + venv/bin/activate.fish | 75 + venv/bin/chardetect | 8 + venv/bin/easy_install | 8 + venv/bin/easy_install-3.8 | 8 + venv/bin/pip | 8 + venv/bin/pip3 | 8 + venv/bin/pip3.8 | 8 + venv/bin/python | 1 + venv/bin/python3 | 1 + .../APScheduler-3.6.3.dist-info/INSTALLER | 1 + .../APScheduler-3.6.3.dist-info/LICENSE.txt | 19 + .../APScheduler-3.6.3.dist-info/METADATA | 133 + .../APScheduler-3.6.3.dist-info/RECORD | 83 + .../APScheduler-3.6.3.dist-info/WHEEL | 6 + .../entry_points.txt | 24 + .../APScheduler-3.6.3.dist-info/top_level.txt | 1 + .../site-packages/apscheduler/__init__.py | 10 + .../site-packages/apscheduler/events.py | 94 + .../apscheduler/executors/__init__.py | 0 .../apscheduler/executors/asyncio.py | 59 + .../apscheduler/executors/base.py | 146 + .../apscheduler/executors/base_py3.py | 41 + .../apscheduler/executors/debug.py | 20 + .../apscheduler/executors/gevent.py | 30 + .../apscheduler/executors/pool.py | 54 + .../apscheduler/executors/tornado.py | 54 + .../apscheduler/executors/twisted.py | 25 + .../site-packages/apscheduler/job.py | 301 + .../apscheduler/jobstores/__init__.py | 0 .../apscheduler/jobstores/base.py | 143 + .../apscheduler/jobstores/memory.py | 108 + .../apscheduler/jobstores/mongodb.py | 141 + .../apscheduler/jobstores/redis.py | 150 + .../apscheduler/jobstores/rethinkdb.py | 155 + .../apscheduler/jobstores/sqlalchemy.py | 154 + .../apscheduler/jobstores/zookeeper.py | 179 + .../apscheduler/schedulers/__init__.py | 12 + .../apscheduler/schedulers/asyncio.py | 68 + .../apscheduler/schedulers/background.py | 41 + .../apscheduler/schedulers/base.py | 1022 ++ .../apscheduler/schedulers/blocking.py | 33 + .../apscheduler/schedulers/gevent.py | 35 + .../apscheduler/schedulers/qt.py | 43 + .../apscheduler/schedulers/tornado.py | 63 + .../apscheduler/schedulers/twisted.py | 62 + .../apscheduler/triggers/__init__.py | 0 .../apscheduler/triggers/base.py | 48 + .../apscheduler/triggers/combining.py | 95 + .../apscheduler/triggers/cron/__init__.py | 238 + .../apscheduler/triggers/cron/expressions.py | 251 + .../apscheduler/triggers/cron/fields.py | 111 + .../apscheduler/triggers/date.py | 51 + .../apscheduler/triggers/interval.py | 106 + .../site-packages/apscheduler/util.py | 429 + .../cachetools-4.2.2.dist-info/INSTALLER | 1 + .../cachetools-4.2.2.dist-info/LICENSE | 20 + .../cachetools-4.2.2.dist-info/METADATA | 129 + .../cachetools-4.2.2.dist-info/RECORD | 28 + .../cachetools-4.2.2.dist-info/WHEEL | 5 + .../cachetools-4.2.2.dist-info/top_level.txt | 1 + .../site-packages/cachetools/__init__.py | 24 + .../site-packages/cachetools/cache.py | 117 + .../site-packages/cachetools/decorators.py | 102 + .../site-packages/cachetools/fifo.py | 31 + .../site-packages/cachetools/func.py | 176 + .../site-packages/cachetools/keys.py | 52 + .../python3.8/site-packages/cachetools/lfu.py | 34 + .../python3.8/site-packages/cachetools/lru.py | 40 + .../python3.8/site-packages/cachetools/mru.py | 40 + .../python3.8/site-packages/cachetools/rr.py | 34 + .../python3.8/site-packages/cachetools/ttl.py | 207 + .../certifi-2021.5.30.dist-info/INSTALLER | 1 + .../certifi-2021.5.30.dist-info/LICENSE | 21 + .../certifi-2021.5.30.dist-info/METADATA | 83 + .../certifi-2021.5.30.dist-info/RECORD | 13 + .../certifi-2021.5.30.dist-info/WHEEL | 6 + .../certifi-2021.5.30.dist-info/top_level.txt | 1 + .../site-packages/certifi/__init__.py | 3 + .../site-packages/certifi/__main__.py | 12 + .../site-packages/certifi/cacert.pem | 4257 +++++++++ .../python3.8/site-packages/certifi/core.py | 60 + .../chardet-4.0.0.dist-info/INSTALLER | 1 + .../chardet-4.0.0.dist-info/LICENSE | 504 + .../chardet-4.0.0.dist-info/METADATA | 101 + .../chardet-4.0.0.dist-info/RECORD | 94 + .../chardet-4.0.0.dist-info/WHEEL | 6 + .../chardet-4.0.0.dist-info/entry_points.txt | 3 + .../chardet-4.0.0.dist-info/top_level.txt | 1 + .../site-packages/chardet/__init__.py | 83 + .../site-packages/chardet/big5freq.py | 386 + .../site-packages/chardet/big5prober.py | 47 + .../site-packages/chardet/chardistribution.py | 233 + .../chardet/charsetgroupprober.py | 107 + .../site-packages/chardet/charsetprober.py | 145 + .../site-packages/chardet/cli/__init__.py | 1 + .../site-packages/chardet/cli/chardetect.py | 84 + .../chardet/codingstatemachine.py | 88 + .../python3.8/site-packages/chardet/compat.py | 36 + .../site-packages/chardet/cp949prober.py | 49 + .../python3.8/site-packages/chardet/enums.py | 76 + .../site-packages/chardet/escprober.py | 101 + .../python3.8/site-packages/chardet/escsm.py | 246 + .../site-packages/chardet/eucjpprober.py | 92 + .../site-packages/chardet/euckrfreq.py | 195 + .../site-packages/chardet/euckrprober.py | 47 + .../site-packages/chardet/euctwfreq.py | 387 + .../site-packages/chardet/euctwprober.py | 46 + .../site-packages/chardet/gb2312freq.py | 283 + .../site-packages/chardet/gb2312prober.py | 46 + .../site-packages/chardet/hebrewprober.py | 292 + .../site-packages/chardet/jisfreq.py | 325 + .../python3.8/site-packages/chardet/jpcntx.py | 233 + .../chardet/langbulgarianmodel.py | 4650 +++++++++ .../site-packages/chardet/langgreekmodel.py | 4398 +++++++++ .../site-packages/chardet/langhebrewmodel.py | 4383 +++++++++ .../chardet/langhungarianmodel.py | 4650 +++++++++ .../site-packages/chardet/langrussianmodel.py | 5718 +++++++++++ .../site-packages/chardet/langthaimodel.py | 4383 +++++++++ .../site-packages/chardet/langturkishmodel.py | 4383 +++++++++ .../site-packages/chardet/latin1prober.py | 145 + .../site-packages/chardet/mbcharsetprober.py | 91 + .../site-packages/chardet/mbcsgroupprober.py | 54 + .../python3.8/site-packages/chardet/mbcssm.py | 572 ++ .../chardet/metadata/__init__.py | 0 .../chardet/metadata/languages.py | 310 + .../site-packages/chardet/sbcharsetprober.py | 145 + .../site-packages/chardet/sbcsgroupprober.py | 83 + .../site-packages/chardet/sjisprober.py | 92 + .../chardet/universaldetector.py | 286 + .../site-packages/chardet/utf8prober.py | 82 + .../site-packages/chardet/version.py | 9 + .../python3.8/site-packages/easy_install.py | 5 + .../idna-2.10.dist-info/INSTALLER | 1 + .../idna-2.10.dist-info/LICENSE.rst | 34 + .../idna-2.10.dist-info/METADATA | 243 + .../site-packages/idna-2.10.dist-info/RECORD | 22 + .../site-packages/idna-2.10.dist-info/WHEEL | 6 + .../idna-2.10.dist-info/top_level.txt | 1 + .../python3.8/site-packages/idna/__init__.py | 2 + .../lib/python3.8/site-packages/idna/codec.py | 118 + .../python3.8/site-packages/idna/compat.py | 12 + venv/lib/python3.8/site-packages/idna/core.py | 400 + .../python3.8/site-packages/idna/idnadata.py | 2050 ++++ .../python3.8/site-packages/idna/intranges.py | 53 + .../site-packages/idna/package_data.py | 2 + .../python3.8/site-packages/idna/uts46data.py | 8357 +++++++++++++++++ .../pip-20.1.1.dist-info/INSTALLER | 1 + .../pip-20.1.1.dist-info/LICENSE.txt | 20 + .../pip-20.1.1.dist-info/METADATA | 87 + .../site-packages/pip-20.1.1.dist-info/RECORD | 272 + .../site-packages/pip-20.1.1.dist-info/WHEEL | 6 + .../pip-20.1.1.dist-info/entry_points.txt | 5 + .../pip-20.1.1.dist-info/top_level.txt | 1 + .../python3.8/site-packages/pip/__init__.py | 18 + .../python3.8/site-packages/pip/__main__.py | 26 + .../site-packages/pip/_internal/__init__.py | 17 + .../site-packages/pip/_internal/build_env.py | 219 + .../site-packages/pip/_internal/cache.py | 349 + .../pip/_internal/cli/__init__.py | 4 + .../pip/_internal/cli/autocompletion.py | 164 + .../pip/_internal/cli/base_command.py | 228 + .../pip/_internal/cli/cmdoptions.py | 962 ++ .../pip/_internal/cli/command_context.py | 36 + .../site-packages/pip/_internal/cli/main.py | 75 + .../pip/_internal/cli/main_parser.py | 99 + .../site-packages/pip/_internal/cli/parser.py | 266 + .../pip/_internal/cli/progress_bars.py | 277 + .../pip/_internal/cli/req_command.py | 408 + .../pip/_internal/cli/spinners.py | 173 + .../pip/_internal/cli/status_codes.py | 8 + .../pip/_internal/commands/__init__.py | 122 + .../pip/_internal/commands/cache.py | 181 + .../pip/_internal/commands/check.py | 51 + .../pip/_internal/commands/completion.py | 95 + .../pip/_internal/commands/configuration.py | 233 + .../pip/_internal/commands/debug.py | 258 + .../pip/_internal/commands/download.py | 142 + .../pip/_internal/commands/freeze.py | 99 + .../pip/_internal/commands/hash.py | 58 + .../pip/_internal/commands/help.py | 41 + .../pip/_internal/commands/install.py | 717 ++ .../pip/_internal/commands/list.py | 301 + .../pip/_internal/commands/search.py | 146 + .../pip/_internal/commands/show.py | 180 + .../pip/_internal/commands/uninstall.py | 89 + .../pip/_internal/commands/wheel.py | 190 + .../pip/_internal/configuration.py | 426 + .../pip/_internal/distributions/__init__.py | 24 + .../pip/_internal/distributions/base.py | 45 + .../pip/_internal/distributions/installed.py | 24 + .../pip/_internal/distributions/sdist.py | 104 + .../pip/_internal/distributions/wheel.py | 36 + .../site-packages/pip/_internal/exceptions.py | 308 + .../pip/_internal/index/__init__.py | 2 + .../pip/_internal/index/collector.py | 661 ++ .../pip/_internal/index/package_finder.py | 1016 ++ .../site-packages/pip/_internal/locations.py | 200 + .../site-packages/pip/_internal/main.py | 16 + .../pip/_internal/models/__init__.py | 2 + .../pip/_internal/models/candidate.py | 36 + .../pip/_internal/models/direct_url.py | 245 + .../pip/_internal/models/format_control.py | 84 + .../pip/_internal/models/index.py | 31 + .../pip/_internal/models/link.py | 236 + .../pip/_internal/models/scheme.py | 25 + .../pip/_internal/models/search_scope.py | 133 + .../pip/_internal/models/selection_prefs.py | 47 + .../pip/_internal/models/target_python.py | 110 + .../pip/_internal/models/wheel.py | 78 + .../pip/_internal/network/__init__.py | 2 + .../pip/_internal/network/auth.py | 298 + .../pip/_internal/network/cache.py | 81 + .../pip/_internal/network/download.py | 200 + .../pip/_internal/network/session.py | 421 + .../pip/_internal/network/utils.py | 48 + .../pip/_internal/network/xmlrpc.py | 44 + .../pip/_internal/operations/__init__.py | 0 .../_internal/operations/build/__init__.py | 0 .../_internal/operations/build/metadata.py | 40 + .../operations/build/metadata_legacy.py | 77 + .../pip/_internal/operations/build/wheel.py | 46 + .../operations/build/wheel_legacy.py | 115 + .../pip/_internal/operations/check.py | 163 + .../pip/_internal/operations/freeze.py | 272 + .../_internal/operations/install/__init__.py | 2 + .../operations/install/editable_legacy.py | 52 + .../_internal/operations/install/legacy.py | 142 + .../pip/_internal/operations/install/wheel.py | 631 ++ .../pip/_internal/operations/prepare.py | 568 ++ .../site-packages/pip/_internal/pyproject.py | 196 + .../pip/_internal/req/__init__.py | 92 + .../pip/_internal/req/constructors.py | 464 + .../pip/_internal/req/req_file.py | 582 ++ .../pip/_internal/req/req_install.py | 850 ++ .../pip/_internal/req/req_set.py | 202 + .../pip/_internal/req/req_tracker.py | 151 + .../pip/_internal/req/req_uninstall.py | 649 ++ .../pip/_internal/resolution/__init__.py | 0 .../pip/_internal/resolution/base.py | 20 + .../_internal/resolution/legacy/__init__.py | 0 .../_internal/resolution/legacy/resolver.py | 459 + .../resolution/resolvelib/__init__.py | 0 .../_internal/resolution/resolvelib/base.py | 52 + .../resolution/resolvelib/candidates.py | 450 + .../resolution/resolvelib/factory.py | 201 + .../resolution/resolvelib/provider.py | 54 + .../resolution/resolvelib/requirements.py | 119 + .../resolution/resolvelib/resolver.py | 174 + .../pip/_internal/self_outdated_check.py | 242 + .../pip/_internal/utils/__init__.py | 0 .../pip/_internal/utils/appdirs.py | 44 + .../pip/_internal/utils/compat.py | 270 + .../pip/_internal/utils/compatibility_tags.py | 169 + .../pip/_internal/utils/deprecation.py | 104 + .../pip/_internal/utils/direct_url_helpers.py | 130 + .../pip/_internal/utils/distutils_args.py | 48 + .../pip/_internal/utils/encoding.py | 42 + .../pip/_internal/utils/entrypoints.py | 31 + .../pip/_internal/utils/filesystem.py | 222 + .../pip/_internal/utils/filetypes.py | 16 + .../pip/_internal/utils/glibc.py | 98 + .../pip/_internal/utils/hashes.py | 133 + .../_internal/utils/inject_securetransport.py | 36 + .../pip/_internal/utils/logging.py | 399 + .../site-packages/pip/_internal/utils/misc.py | 927 ++ .../pip/_internal/utils/models.py | 42 + .../pip/_internal/utils/packaging.py | 94 + .../pip/_internal/utils/pkg_resources.py | 44 + .../pip/_internal/utils/setuptools_build.py | 181 + .../pip/_internal/utils/subprocess.py | 277 + .../pip/_internal/utils/temp_dir.py | 271 + .../pip/_internal/utils/typing.py | 38 + .../pip/_internal/utils/unpacking.py | 272 + .../site-packages/pip/_internal/utils/urls.py | 55 + .../pip/_internal/utils/virtualenv.py | 116 + .../pip/_internal/utils/wheel.py | 225 + .../pip/_internal/vcs/__init__.py | 15 + .../site-packages/pip/_internal/vcs/bazaar.py | 120 + .../site-packages/pip/_internal/vcs/git.py | 394 + .../pip/_internal/vcs/mercurial.py | 161 + .../pip/_internal/vcs/subversion.py | 334 + .../pip/_internal/vcs/versioncontrol.py | 723 ++ .../pip/_internal/wheel_builder.py | 309 + .../site-packages/pip/_vendor/__init__.py | 123 + .../pkg_resources-0.0.0.dist-info/AUTHORS.txt | 566 ++ .../pkg_resources-0.0.0.dist-info/INSTALLER | 1 + .../pkg_resources-0.0.0.dist-info/LICENSE.txt | 20 + .../pkg_resources-0.0.0.dist-info/METADATA | 13 + .../pkg_resources-0.0.0.dist-info/RECORD | 38 + .../pkg_resources-0.0.0.dist-info/WHEEL | 6 + .../site-packages/pkg_resources/__init__.py | 3296 +++++++ .../pkg_resources/_vendor/__init__.py | 0 .../pkg_resources/_vendor/appdirs.py | 608 ++ .../_vendor/packaging/__about__.py | 21 + .../_vendor/packaging/__init__.py | 14 + .../_vendor/packaging/_compat.py | 30 + .../_vendor/packaging/_structures.py | 68 + .../_vendor/packaging/markers.py | 301 + .../_vendor/packaging/requirements.py | 127 + .../_vendor/packaging/specifiers.py | 774 ++ .../pkg_resources/_vendor/packaging/utils.py | 14 + .../_vendor/packaging/version.py | 393 + .../pkg_resources/_vendor/pyparsing.py | 5742 +++++++++++ .../pkg_resources/_vendor/six.py | 868 ++ .../pkg_resources/extern/__init__.py | 73 + .../site-packages/pkg_resources/py31compat.py | 23 + .../INSTALLER | 1 + .../LICENSE.dual | 792 ++ .../METADATA | 285 + .../python_telegram_bot-13.6.dist-info/RECORD | 365 + .../python_telegram_bot-13.6.dist-info/WHEEL | 5 + .../top_level.txt | 1 + .../pytz-2021.1.dist-info/DESCRIPTION.rst | 598 ++ .../pytz-2021.1.dist-info/INSTALLER | 1 + .../pytz-2021.1.dist-info/LICENSE.txt | 19 + .../pytz-2021.1.dist-info/METADATA | 634 ++ .../pytz-2021.1.dist-info/RECORD | 620 ++ .../site-packages/pytz-2021.1.dist-info/WHEEL | 6 + .../pytz-2021.1.dist-info/metadata.json | 1 + .../pytz-2021.1.dist-info/top_level.txt | 1 + .../pytz-2021.1.dist-info/zip-safe | 1 + .../python3.8/site-packages/pytz/__init__.py | 1558 +++ .../site-packages/pytz/exceptions.py | 59 + venv/lib/python3.8/site-packages/pytz/lazy.py | 172 + .../python3.8/site-packages/pytz/reference.py | 140 + .../python3.8/site-packages/pytz/tzfile.py | 133 + .../python3.8/site-packages/pytz/tzinfo.py | 577 ++ .../pytz/zoneinfo/Africa/Abidjan | Bin 0 -> 148 bytes .../site-packages/pytz/zoneinfo/Africa/Accra | Bin 0 -> 1060 bytes .../pytz/zoneinfo/Africa/Addis_Ababa | Bin 0 -> 265 bytes .../pytz/zoneinfo/Africa/Algiers | Bin 0 -> 735 bytes .../site-packages/pytz/zoneinfo/Africa/Asmara | Bin 0 -> 265 bytes .../site-packages/pytz/zoneinfo/Africa/Asmera | Bin 0 -> 265 bytes .../site-packages/pytz/zoneinfo/Africa/Bamako | Bin 0 -> 148 bytes .../site-packages/pytz/zoneinfo/Africa/Bangui | Bin 0 -> 235 bytes .../site-packages/pytz/zoneinfo/Africa/Banjul | Bin 0 -> 148 bytes .../site-packages/pytz/zoneinfo/Africa/Bissau | Bin 0 -> 194 bytes .../pytz/zoneinfo/Africa/Blantyre | Bin 0 -> 149 bytes .../pytz/zoneinfo/Africa/Brazzaville | Bin 0 -> 235 bytes .../pytz/zoneinfo/Africa/Bujumbura | Bin 0 -> 149 bytes .../site-packages/pytz/zoneinfo/Africa/Cairo | Bin 0 -> 1955 bytes .../pytz/zoneinfo/Africa/Casablanca | Bin 0 -> 2429 bytes .../site-packages/pytz/zoneinfo/Africa/Ceuta | Bin 0 -> 2036 bytes .../pytz/zoneinfo/Africa/Conakry | Bin 0 -> 148 bytes .../site-packages/pytz/zoneinfo/Africa/Dakar | Bin 0 -> 148 bytes .../pytz/zoneinfo/Africa/Dar_es_Salaam | Bin 0 -> 265 bytes .../pytz/zoneinfo/Africa/Djibouti | Bin 0 -> 265 bytes .../site-packages/pytz/zoneinfo/Africa/Douala | Bin 0 -> 235 bytes .../pytz/zoneinfo/Africa/El_Aaiun | Bin 0 -> 2295 bytes .../pytz/zoneinfo/Africa/Freetown | Bin 0 -> 148 bytes .../pytz/zoneinfo/Africa/Gaborone | Bin 0 -> 149 bytes .../site-packages/pytz/zoneinfo/Africa/Harare | Bin 0 -> 149 bytes .../pytz/zoneinfo/Africa/Johannesburg | Bin 0 -> 246 bytes .../site-packages/pytz/zoneinfo/Africa/Juba | Bin 0 -> 679 bytes .../pytz/zoneinfo/Africa/Kampala | Bin 0 -> 265 bytes .../pytz/zoneinfo/Africa/Khartoum | Bin 0 -> 679 bytes .../site-packages/pytz/zoneinfo/Africa/Kigali | Bin 0 -> 149 bytes .../pytz/zoneinfo/Africa/Kinshasa | Bin 0 -> 235 bytes .../site-packages/pytz/zoneinfo/Africa/Lagos | Bin 0 -> 235 bytes .../pytz/zoneinfo/Africa/Libreville | Bin 0 -> 235 bytes .../site-packages/pytz/zoneinfo/Africa/Lome | Bin 0 -> 148 bytes .../site-packages/pytz/zoneinfo/Africa/Luanda | Bin 0 -> 235 bytes .../pytz/zoneinfo/Africa/Lubumbashi | Bin 0 -> 149 bytes .../site-packages/pytz/zoneinfo/Africa/Lusaka | Bin 0 -> 149 bytes .../site-packages/pytz/zoneinfo/Africa/Malabo | Bin 0 -> 235 bytes .../site-packages/pytz/zoneinfo/Africa/Maputo | Bin 0 -> 149 bytes .../site-packages/pytz/zoneinfo/Africa/Maseru | Bin 0 -> 246 bytes .../pytz/zoneinfo/Africa/Mbabane | Bin 0 -> 246 bytes .../pytz/zoneinfo/Africa/Mogadishu | Bin 0 -> 265 bytes .../pytz/zoneinfo/Africa/Monrovia | Bin 0 -> 208 bytes .../pytz/zoneinfo/Africa/Nairobi | Bin 0 -> 265 bytes .../pytz/zoneinfo/Africa/Ndjamena | Bin 0 -> 199 bytes .../site-packages/pytz/zoneinfo/Africa/Niamey | Bin 0 -> 235 bytes .../pytz/zoneinfo/Africa/Nouakchott | Bin 0 -> 148 bytes .../pytz/zoneinfo/Africa/Ouagadougou | Bin 0 -> 148 bytes .../pytz/zoneinfo/Africa/Porto-Novo | Bin 0 -> 235 bytes .../pytz/zoneinfo/Africa/Sao_Tome | Bin 0 -> 254 bytes .../pytz/zoneinfo/Africa/Timbuktu | Bin 0 -> 148 bytes .../pytz/zoneinfo/Africa/Tripoli | Bin 0 -> 625 bytes .../site-packages/pytz/zoneinfo/Africa/Tunis | Bin 0 -> 689 bytes .../pytz/zoneinfo/Africa/Windhoek | Bin 0 -> 955 bytes .../site-packages/pytz/zoneinfo/America/Adak | Bin 0 -> 2356 bytes .../pytz/zoneinfo/America/Anchorage | Bin 0 -> 2371 bytes .../pytz/zoneinfo/America/Anguilla | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/Antigua | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/Araguaina | Bin 0 -> 884 bytes .../zoneinfo/America/Argentina/Buenos_Aires | Bin 0 -> 1076 bytes .../pytz/zoneinfo/America/Argentina/Catamarca | Bin 0 -> 1076 bytes .../zoneinfo/America/Argentina/ComodRivadavia | Bin 0 -> 1076 bytes .../pytz/zoneinfo/America/Argentina/Cordoba | Bin 0 -> 1076 bytes .../pytz/zoneinfo/America/Argentina/Jujuy | Bin 0 -> 1048 bytes .../pytz/zoneinfo/America/Argentina/La_Rioja | Bin 0 -> 1090 bytes .../pytz/zoneinfo/America/Argentina/Mendoza | Bin 0 -> 1076 bytes .../zoneinfo/America/Argentina/Rio_Gallegos | Bin 0 -> 1076 bytes .../pytz/zoneinfo/America/Argentina/Salta | Bin 0 -> 1048 bytes .../pytz/zoneinfo/America/Argentina/San_Juan | Bin 0 -> 1090 bytes .../pytz/zoneinfo/America/Argentina/San_Luis | Bin 0 -> 1102 bytes .../pytz/zoneinfo/America/Argentina/Tucuman | Bin 0 -> 1104 bytes .../pytz/zoneinfo/America/Argentina/Ushuaia | Bin 0 -> 1076 bytes .../site-packages/pytz/zoneinfo/America/Aruba | Bin 0 -> 186 bytes .../pytz/zoneinfo/America/Asuncion | Bin 0 -> 2044 bytes .../pytz/zoneinfo/America/Atikokan | Bin 0 -> 336 bytes .../site-packages/pytz/zoneinfo/America/Atka | Bin 0 -> 2356 bytes .../site-packages/pytz/zoneinfo/America/Bahia | Bin 0 -> 1024 bytes .../pytz/zoneinfo/America/Bahia_Banderas | Bin 0 -> 1546 bytes .../pytz/zoneinfo/America/Barbados | Bin 0 -> 314 bytes .../site-packages/pytz/zoneinfo/America/Belem | Bin 0 -> 576 bytes .../pytz/zoneinfo/America/Belize | Bin 0 -> 1614 bytes .../pytz/zoneinfo/America/Blanc-Sablon | Bin 0 -> 298 bytes .../pytz/zoneinfo/America/Boa_Vista | Bin 0 -> 632 bytes .../pytz/zoneinfo/America/Bogota | Bin 0 -> 246 bytes .../site-packages/pytz/zoneinfo/America/Boise | Bin 0 -> 2394 bytes .../pytz/zoneinfo/America/Buenos_Aires | Bin 0 -> 1076 bytes .../pytz/zoneinfo/America/Cambridge_Bay | Bin 0 -> 2084 bytes .../pytz/zoneinfo/America/Campo_Grande | Bin 0 -> 1444 bytes .../pytz/zoneinfo/America/Cancun | Bin 0 -> 782 bytes .../pytz/zoneinfo/America/Caracas | Bin 0 -> 264 bytes .../pytz/zoneinfo/America/Catamarca | Bin 0 -> 1076 bytes .../pytz/zoneinfo/America/Cayenne | Bin 0 -> 198 bytes .../pytz/zoneinfo/America/Cayman | Bin 0 -> 182 bytes .../pytz/zoneinfo/America/Chicago | Bin 0 -> 3576 bytes .../pytz/zoneinfo/America/Chihuahua | Bin 0 -> 1484 bytes .../pytz/zoneinfo/America/Coral_Harbour | Bin 0 -> 336 bytes .../pytz/zoneinfo/America/Cordoba | Bin 0 -> 1076 bytes .../pytz/zoneinfo/America/Costa_Rica | Bin 0 -> 316 bytes .../pytz/zoneinfo/America/Creston | Bin 0 -> 208 bytes .../pytz/zoneinfo/America/Cuiaba | Bin 0 -> 1416 bytes .../pytz/zoneinfo/America/Curacao | Bin 0 -> 186 bytes .../pytz/zoneinfo/America/Danmarkshavn | Bin 0 -> 698 bytes .../pytz/zoneinfo/America/Dawson | Bin 0 -> 1614 bytes .../pytz/zoneinfo/America/Dawson_Creek | Bin 0 -> 1050 bytes .../pytz/zoneinfo/America/Denver | Bin 0 -> 2444 bytes .../pytz/zoneinfo/America/Detroit | Bin 0 -> 2230 bytes .../pytz/zoneinfo/America/Dominica | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/Edmonton | Bin 0 -> 2332 bytes .../pytz/zoneinfo/America/Eirunepe | Bin 0 -> 656 bytes .../pytz/zoneinfo/America/El_Salvador | Bin 0 -> 224 bytes .../pytz/zoneinfo/America/Ensenada | Bin 0 -> 2342 bytes .../pytz/zoneinfo/America/Fort_Nelson | Bin 0 -> 2240 bytes .../pytz/zoneinfo/America/Fort_Wayne | Bin 0 -> 1666 bytes .../pytz/zoneinfo/America/Fortaleza | Bin 0 -> 716 bytes .../pytz/zoneinfo/America/Glace_Bay | Bin 0 -> 2192 bytes .../pytz/zoneinfo/America/Godthab | Bin 0 -> 1878 bytes .../pytz/zoneinfo/America/Goose_Bay | Bin 0 -> 3210 bytes .../pytz/zoneinfo/America/Grand_Turk | Bin 0 -> 1834 bytes .../pytz/zoneinfo/America/Grenada | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/Guadeloupe | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/Guatemala | Bin 0 -> 280 bytes .../pytz/zoneinfo/America/Guayaquil | Bin 0 -> 246 bytes .../pytz/zoneinfo/America/Guyana | Bin 0 -> 236 bytes .../pytz/zoneinfo/America/Halifax | Bin 0 -> 3424 bytes .../pytz/zoneinfo/America/Havana | Bin 0 -> 2416 bytes .../pytz/zoneinfo/America/Hermosillo | Bin 0 -> 416 bytes .../zoneinfo/America/Indiana/Indianapolis | Bin 0 -> 1666 bytes .../pytz/zoneinfo/America/Indiana/Knox | Bin 0 -> 2428 bytes .../pytz/zoneinfo/America/Indiana/Marengo | Bin 0 -> 1722 bytes .../pytz/zoneinfo/America/Indiana/Petersburg | Bin 0 -> 1904 bytes .../pytz/zoneinfo/America/Indiana/Tell_City | Bin 0 -> 1684 bytes .../pytz/zoneinfo/America/Indiana/Vevay | Bin 0 -> 1414 bytes .../pytz/zoneinfo/America/Indiana/Vincennes | Bin 0 -> 1694 bytes .../pytz/zoneinfo/America/Indiana/Winamac | Bin 0 -> 1778 bytes .../pytz/zoneinfo/America/Indianapolis | Bin 0 -> 1666 bytes .../pytz/zoneinfo/America/Inuvik | Bin 0 -> 1894 bytes .../pytz/zoneinfo/America/Iqaluit | Bin 0 -> 2032 bytes .../pytz/zoneinfo/America/Jamaica | Bin 0 -> 482 bytes .../site-packages/pytz/zoneinfo/America/Jujuy | Bin 0 -> 1048 bytes .../pytz/zoneinfo/America/Juneau | Bin 0 -> 2353 bytes .../pytz/zoneinfo/America/Kentucky/Louisville | Bin 0 -> 2772 bytes .../pytz/zoneinfo/America/Kentucky/Monticello | Bin 0 -> 2352 bytes .../pytz/zoneinfo/America/Knox_IN | Bin 0 -> 2428 bytes .../pytz/zoneinfo/America/Kralendijk | Bin 0 -> 186 bytes .../pytz/zoneinfo/America/La_Paz | Bin 0 -> 232 bytes .../site-packages/pytz/zoneinfo/America/Lima | Bin 0 -> 406 bytes .../pytz/zoneinfo/America/Los_Angeles | Bin 0 -> 2836 bytes .../pytz/zoneinfo/America/Louisville | Bin 0 -> 2772 bytes .../pytz/zoneinfo/America/Lower_Princes | Bin 0 -> 186 bytes .../pytz/zoneinfo/America/Maceio | Bin 0 -> 744 bytes .../pytz/zoneinfo/America/Managua | Bin 0 -> 430 bytes .../pytz/zoneinfo/America/Manaus | Bin 0 -> 604 bytes .../pytz/zoneinfo/America/Marigot | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/Martinique | Bin 0 -> 232 bytes .../pytz/zoneinfo/America/Matamoros | Bin 0 -> 1390 bytes .../pytz/zoneinfo/America/Mazatlan | Bin 0 -> 1526 bytes .../pytz/zoneinfo/America/Mendoza | Bin 0 -> 1076 bytes .../pytz/zoneinfo/America/Menominee | Bin 0 -> 2274 bytes .../pytz/zoneinfo/America/Merida | Bin 0 -> 1422 bytes .../pytz/zoneinfo/America/Metlakatla | Bin 0 -> 1423 bytes .../pytz/zoneinfo/America/Mexico_City | Bin 0 -> 1584 bytes .../pytz/zoneinfo/America/Miquelon | Bin 0 -> 1666 bytes .../pytz/zoneinfo/America/Moncton | Bin 0 -> 3154 bytes .../pytz/zoneinfo/America/Monterrey | Bin 0 -> 1390 bytes .../pytz/zoneinfo/America/Montevideo | Bin 0 -> 1510 bytes .../pytz/zoneinfo/America/Montreal | Bin 0 -> 3494 bytes .../pytz/zoneinfo/America/Montserrat | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/Nassau | Bin 0 -> 2388 bytes .../pytz/zoneinfo/America/New_York | Bin 0 -> 3536 bytes .../pytz/zoneinfo/America/Nipigon | Bin 0 -> 2122 bytes .../site-packages/pytz/zoneinfo/America/Nome | Bin 0 -> 2367 bytes .../pytz/zoneinfo/America/Noronha | Bin 0 -> 716 bytes .../pytz/zoneinfo/America/North_Dakota/Beulah | Bin 0 -> 2380 bytes .../pytz/zoneinfo/America/North_Dakota/Center | Bin 0 -> 2380 bytes .../zoneinfo/America/North_Dakota/New_Salem | Bin 0 -> 2380 bytes .../site-packages/pytz/zoneinfo/America/Nuuk | Bin 0 -> 1878 bytes .../pytz/zoneinfo/America/Ojinaga | Bin 0 -> 1484 bytes .../pytz/zoneinfo/America/Panama | Bin 0 -> 182 bytes .../pytz/zoneinfo/America/Pangnirtung | Bin 0 -> 2094 bytes .../pytz/zoneinfo/America/Paramaribo | Bin 0 -> 262 bytes .../pytz/zoneinfo/America/Phoenix | Bin 0 -> 328 bytes .../pytz/zoneinfo/America/Port-au-Prince | Bin 0 -> 1434 bytes .../pytz/zoneinfo/America/Port_of_Spain | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/Porto_Acre | Bin 0 -> 628 bytes .../pytz/zoneinfo/America/Porto_Velho | Bin 0 -> 576 bytes .../pytz/zoneinfo/America/Puerto_Rico | Bin 0 -> 246 bytes .../pytz/zoneinfo/America/Punta_Arenas | Bin 0 -> 1902 bytes .../pytz/zoneinfo/America/Rainy_River | Bin 0 -> 2122 bytes .../pytz/zoneinfo/America/Rankin_Inlet | Bin 0 -> 1892 bytes .../pytz/zoneinfo/America/Recife | Bin 0 -> 716 bytes .../pytz/zoneinfo/America/Regina | Bin 0 -> 980 bytes .../pytz/zoneinfo/America/Resolute | Bin 0 -> 1892 bytes .../pytz/zoneinfo/America/Rio_Branco | Bin 0 -> 628 bytes .../pytz/zoneinfo/America/Rosario | Bin 0 -> 1076 bytes .../pytz/zoneinfo/America/Santa_Isabel | Bin 0 -> 2342 bytes .../pytz/zoneinfo/America/Santarem | Bin 0 -> 602 bytes .../pytz/zoneinfo/America/Santiago | Bin 0 -> 2529 bytes .../pytz/zoneinfo/America/Santo_Domingo | Bin 0 -> 458 bytes .../pytz/zoneinfo/America/Sao_Paulo | Bin 0 -> 1444 bytes .../pytz/zoneinfo/America/Scoresbysund | Bin 0 -> 1916 bytes .../pytz/zoneinfo/America/Shiprock | Bin 0 -> 2444 bytes .../site-packages/pytz/zoneinfo/America/Sitka | Bin 0 -> 2329 bytes .../pytz/zoneinfo/America/St_Barthelemy | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/St_Johns | Bin 0 -> 3655 bytes .../pytz/zoneinfo/America/St_Kitts | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/St_Lucia | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/St_Thomas | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/St_Vincent | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/Swift_Current | Bin 0 -> 560 bytes .../pytz/zoneinfo/America/Tegucigalpa | Bin 0 -> 252 bytes .../site-packages/pytz/zoneinfo/America/Thule | Bin 0 -> 1502 bytes .../pytz/zoneinfo/America/Thunder_Bay | Bin 0 -> 2202 bytes .../pytz/zoneinfo/America/Tijuana | Bin 0 -> 2342 bytes .../pytz/zoneinfo/America/Toronto | Bin 0 -> 3494 bytes .../pytz/zoneinfo/America/Tortola | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/Vancouver | Bin 0 -> 2892 bytes .../pytz/zoneinfo/America/Virgin | Bin 0 -> 148 bytes .../pytz/zoneinfo/America/Whitehorse | Bin 0 -> 1614 bytes .../pytz/zoneinfo/America/Winnipeg | Bin 0 -> 2868 bytes .../pytz/zoneinfo/America/Yakutat | Bin 0 -> 2305 bytes .../pytz/zoneinfo/America/Yellowknife | Bin 0 -> 1966 bytes .../pytz/zoneinfo/Antarctica/Casey | Bin 0 -> 384 bytes .../pytz/zoneinfo/Antarctica/Davis | Bin 0 -> 297 bytes .../pytz/zoneinfo/Antarctica/DumontDUrville | Bin 0 -> 194 bytes .../pytz/zoneinfo/Antarctica/Macquarie | Bin 0 -> 2260 bytes .../pytz/zoneinfo/Antarctica/Mawson | Bin 0 -> 199 bytes .../pytz/zoneinfo/Antarctica/McMurdo | Bin 0 -> 2437 bytes .../pytz/zoneinfo/Antarctica/Palmer | Bin 0 -> 1418 bytes .../pytz/zoneinfo/Antarctica/Rothera | Bin 0 -> 164 bytes .../pytz/zoneinfo/Antarctica/South_Pole | Bin 0 -> 2437 bytes .../pytz/zoneinfo/Antarctica/Syowa | Bin 0 -> 165 bytes .../pytz/zoneinfo/Antarctica/Troll | Bin 0 -> 1162 bytes .../pytz/zoneinfo/Antarctica/Vostok | Bin 0 -> 165 bytes .../pytz/zoneinfo/Arctic/Longyearbyen | Bin 0 -> 2228 bytes .../site-packages/pytz/zoneinfo/Asia/Aden | Bin 0 -> 165 bytes .../site-packages/pytz/zoneinfo/Asia/Almaty | Bin 0 -> 997 bytes .../site-packages/pytz/zoneinfo/Asia/Amman | Bin 0 -> 1853 bytes .../site-packages/pytz/zoneinfo/Asia/Anadyr | Bin 0 -> 1188 bytes .../site-packages/pytz/zoneinfo/Asia/Aqtau | Bin 0 -> 983 bytes .../site-packages/pytz/zoneinfo/Asia/Aqtobe | Bin 0 -> 1011 bytes .../site-packages/pytz/zoneinfo/Asia/Ashgabat | Bin 0 -> 619 bytes .../pytz/zoneinfo/Asia/Ashkhabad | Bin 0 -> 619 bytes .../site-packages/pytz/zoneinfo/Asia/Atyrau | Bin 0 -> 991 bytes .../site-packages/pytz/zoneinfo/Asia/Baghdad | Bin 0 -> 983 bytes .../site-packages/pytz/zoneinfo/Asia/Bahrain | Bin 0 -> 199 bytes .../site-packages/pytz/zoneinfo/Asia/Baku | Bin 0 -> 1227 bytes .../site-packages/pytz/zoneinfo/Asia/Bangkok | Bin 0 -> 199 bytes .../site-packages/pytz/zoneinfo/Asia/Barnaul | Bin 0 -> 1221 bytes .../site-packages/pytz/zoneinfo/Asia/Beirut | Bin 0 -> 2154 bytes .../site-packages/pytz/zoneinfo/Asia/Bishkek | Bin 0 -> 983 bytes .../site-packages/pytz/zoneinfo/Asia/Brunei | Bin 0 -> 203 bytes .../site-packages/pytz/zoneinfo/Asia/Calcutta | Bin 0 -> 285 bytes .../site-packages/pytz/zoneinfo/Asia/Chita | Bin 0 -> 1221 bytes .../pytz/zoneinfo/Asia/Choibalsan | Bin 0 -> 949 bytes .../pytz/zoneinfo/Asia/Chongqing | Bin 0 -> 561 bytes .../pytz/zoneinfo/Asia/Chungking | Bin 0 -> 561 bytes .../site-packages/pytz/zoneinfo/Asia/Colombo | Bin 0 -> 372 bytes .../site-packages/pytz/zoneinfo/Asia/Dacca | Bin 0 -> 337 bytes .../site-packages/pytz/zoneinfo/Asia/Damascus | Bin 0 -> 2294 bytes .../site-packages/pytz/zoneinfo/Asia/Dhaka | Bin 0 -> 337 bytes .../site-packages/pytz/zoneinfo/Asia/Dili | Bin 0 -> 227 bytes .../site-packages/pytz/zoneinfo/Asia/Dubai | Bin 0 -> 165 bytes .../site-packages/pytz/zoneinfo/Asia/Dushanbe | Bin 0 -> 591 bytes .../pytz/zoneinfo/Asia/Famagusta | Bin 0 -> 2028 bytes .../site-packages/pytz/zoneinfo/Asia/Gaza | Bin 0 -> 2422 bytes .../site-packages/pytz/zoneinfo/Asia/Harbin | Bin 0 -> 561 bytes .../site-packages/pytz/zoneinfo/Asia/Hebron | Bin 0 -> 2450 bytes .../pytz/zoneinfo/Asia/Ho_Chi_Minh | Bin 0 -> 351 bytes .../pytz/zoneinfo/Asia/Hong_Kong | Bin 0 -> 1203 bytes .../site-packages/pytz/zoneinfo/Asia/Hovd | Bin 0 -> 891 bytes .../site-packages/pytz/zoneinfo/Asia/Irkutsk | Bin 0 -> 1243 bytes .../site-packages/pytz/zoneinfo/Asia/Istanbul | Bin 0 -> 1947 bytes .../site-packages/pytz/zoneinfo/Asia/Jakarta | Bin 0 -> 355 bytes .../site-packages/pytz/zoneinfo/Asia/Jayapura | Bin 0 -> 221 bytes .../pytz/zoneinfo/Asia/Jerusalem | Bin 0 -> 2388 bytes .../site-packages/pytz/zoneinfo/Asia/Kabul | Bin 0 -> 208 bytes .../pytz/zoneinfo/Asia/Kamchatka | Bin 0 -> 1166 bytes .../site-packages/pytz/zoneinfo/Asia/Karachi | Bin 0 -> 379 bytes .../site-packages/pytz/zoneinfo/Asia/Kashgar | Bin 0 -> 165 bytes .../pytz/zoneinfo/Asia/Kathmandu | Bin 0 -> 212 bytes .../site-packages/pytz/zoneinfo/Asia/Katmandu | Bin 0 -> 212 bytes .../site-packages/pytz/zoneinfo/Asia/Khandyga | Bin 0 -> 1271 bytes .../site-packages/pytz/zoneinfo/Asia/Kolkata | Bin 0 -> 285 bytes .../pytz/zoneinfo/Asia/Krasnoyarsk | Bin 0 -> 1207 bytes .../pytz/zoneinfo/Asia/Kuala_Lumpur | Bin 0 -> 383 bytes .../site-packages/pytz/zoneinfo/Asia/Kuching | Bin 0 -> 483 bytes .../site-packages/pytz/zoneinfo/Asia/Kuwait | Bin 0 -> 165 bytes .../site-packages/pytz/zoneinfo/Asia/Macao | Bin 0 -> 1227 bytes .../site-packages/pytz/zoneinfo/Asia/Macau | Bin 0 -> 1227 bytes .../site-packages/pytz/zoneinfo/Asia/Magadan | Bin 0 -> 1222 bytes .../site-packages/pytz/zoneinfo/Asia/Makassar | Bin 0 -> 254 bytes .../site-packages/pytz/zoneinfo/Asia/Manila | Bin 0 -> 328 bytes .../site-packages/pytz/zoneinfo/Asia/Muscat | Bin 0 -> 165 bytes .../site-packages/pytz/zoneinfo/Asia/Nicosia | Bin 0 -> 2002 bytes .../pytz/zoneinfo/Asia/Novokuznetsk | Bin 0 -> 1165 bytes .../pytz/zoneinfo/Asia/Novosibirsk | Bin 0 -> 1221 bytes .../site-packages/pytz/zoneinfo/Asia/Omsk | Bin 0 -> 1207 bytes .../site-packages/pytz/zoneinfo/Asia/Oral | Bin 0 -> 1005 bytes .../pytz/zoneinfo/Asia/Phnom_Penh | Bin 0 -> 199 bytes .../pytz/zoneinfo/Asia/Pontianak | Bin 0 -> 353 bytes .../pytz/zoneinfo/Asia/Pyongyang | Bin 0 -> 237 bytes .../site-packages/pytz/zoneinfo/Asia/Qatar | Bin 0 -> 199 bytes .../site-packages/pytz/zoneinfo/Asia/Qostanay | Bin 0 -> 1011 bytes .../pytz/zoneinfo/Asia/Qyzylorda | Bin 0 -> 1025 bytes .../site-packages/pytz/zoneinfo/Asia/Rangoon | Bin 0 -> 268 bytes .../site-packages/pytz/zoneinfo/Asia/Riyadh | Bin 0 -> 165 bytes .../site-packages/pytz/zoneinfo/Asia/Saigon | Bin 0 -> 351 bytes .../site-packages/pytz/zoneinfo/Asia/Sakhalin | Bin 0 -> 1202 bytes .../pytz/zoneinfo/Asia/Samarkand | Bin 0 -> 577 bytes .../site-packages/pytz/zoneinfo/Asia/Seoul | Bin 0 -> 617 bytes .../site-packages/pytz/zoneinfo/Asia/Shanghai | Bin 0 -> 561 bytes .../pytz/zoneinfo/Asia/Singapore | Bin 0 -> 383 bytes .../pytz/zoneinfo/Asia/Srednekolymsk | Bin 0 -> 1208 bytes .../site-packages/pytz/zoneinfo/Asia/Taipei | Bin 0 -> 761 bytes .../site-packages/pytz/zoneinfo/Asia/Tashkent | Bin 0 -> 591 bytes .../site-packages/pytz/zoneinfo/Asia/Tbilisi | Bin 0 -> 1035 bytes .../site-packages/pytz/zoneinfo/Asia/Tehran | Bin 0 -> 2582 bytes .../site-packages/pytz/zoneinfo/Asia/Tel_Aviv | Bin 0 -> 2388 bytes .../site-packages/pytz/zoneinfo/Asia/Thimbu | Bin 0 -> 203 bytes .../site-packages/pytz/zoneinfo/Asia/Thimphu | Bin 0 -> 203 bytes .../site-packages/pytz/zoneinfo/Asia/Tokyo | Bin 0 -> 309 bytes .../site-packages/pytz/zoneinfo/Asia/Tomsk | Bin 0 -> 1221 bytes .../pytz/zoneinfo/Asia/Ujung_Pandang | Bin 0 -> 254 bytes .../pytz/zoneinfo/Asia/Ulaanbaatar | Bin 0 -> 891 bytes .../pytz/zoneinfo/Asia/Ulan_Bator | Bin 0 -> 891 bytes .../site-packages/pytz/zoneinfo/Asia/Urumqi | Bin 0 -> 165 bytes .../site-packages/pytz/zoneinfo/Asia/Ust-Nera | Bin 0 -> 1252 bytes .../pytz/zoneinfo/Asia/Vientiane | Bin 0 -> 199 bytes .../pytz/zoneinfo/Asia/Vladivostok | Bin 0 -> 1208 bytes .../site-packages/pytz/zoneinfo/Asia/Yakutsk | Bin 0 -> 1207 bytes .../site-packages/pytz/zoneinfo/Asia/Yangon | Bin 0 -> 268 bytes .../pytz/zoneinfo/Asia/Yekaterinburg | Bin 0 -> 1243 bytes .../site-packages/pytz/zoneinfo/Asia/Yerevan | Bin 0 -> 1151 bytes .../pytz/zoneinfo/Atlantic/Azores | Bin 0 -> 3484 bytes .../pytz/zoneinfo/Atlantic/Bermuda | Bin 0 -> 2396 bytes .../pytz/zoneinfo/Atlantic/Canary | Bin 0 -> 1897 bytes .../pytz/zoneinfo/Atlantic/Cape_Verde | Bin 0 -> 270 bytes .../pytz/zoneinfo/Atlantic/Faeroe | Bin 0 -> 1815 bytes .../pytz/zoneinfo/Atlantic/Faroe | Bin 0 -> 1815 bytes .../pytz/zoneinfo/Atlantic/Jan_Mayen | Bin 0 -> 2228 bytes .../pytz/zoneinfo/Atlantic/Madeira | Bin 0 -> 3475 bytes .../pytz/zoneinfo/Atlantic/Reykjavik | Bin 0 -> 1162 bytes .../pytz/zoneinfo/Atlantic/South_Georgia | Bin 0 -> 164 bytes .../pytz/zoneinfo/Atlantic/St_Helena | Bin 0 -> 148 bytes .../pytz/zoneinfo/Atlantic/Stanley | Bin 0 -> 1214 bytes .../site-packages/pytz/zoneinfo/Australia/ACT | Bin 0 -> 2190 bytes .../pytz/zoneinfo/Australia/Adelaide | Bin 0 -> 2208 bytes .../pytz/zoneinfo/Australia/Brisbane | Bin 0 -> 419 bytes .../pytz/zoneinfo/Australia/Broken_Hill | Bin 0 -> 2229 bytes .../pytz/zoneinfo/Australia/Canberra | Bin 0 -> 2190 bytes .../pytz/zoneinfo/Australia/Currie | Bin 0 -> 2358 bytes .../pytz/zoneinfo/Australia/Darwin | Bin 0 -> 325 bytes .../pytz/zoneinfo/Australia/Eucla | Bin 0 -> 470 bytes .../pytz/zoneinfo/Australia/Hobart | Bin 0 -> 2358 bytes .../site-packages/pytz/zoneinfo/Australia/LHI | Bin 0 -> 1860 bytes .../pytz/zoneinfo/Australia/Lindeman | Bin 0 -> 475 bytes .../pytz/zoneinfo/Australia/Lord_Howe | Bin 0 -> 1860 bytes .../pytz/zoneinfo/Australia/Melbourne | Bin 0 -> 2190 bytes .../site-packages/pytz/zoneinfo/Australia/NSW | Bin 0 -> 2190 bytes .../pytz/zoneinfo/Australia/North | Bin 0 -> 325 bytes .../pytz/zoneinfo/Australia/Perth | Bin 0 -> 446 bytes .../pytz/zoneinfo/Australia/Queensland | Bin 0 -> 419 bytes .../pytz/zoneinfo/Australia/South | Bin 0 -> 2208 bytes .../pytz/zoneinfo/Australia/Sydney | Bin 0 -> 2190 bytes .../pytz/zoneinfo/Australia/Tasmania | Bin 0 -> 2358 bytes .../pytz/zoneinfo/Australia/Victoria | Bin 0 -> 2190 bytes .../pytz/zoneinfo/Australia/West | Bin 0 -> 446 bytes .../pytz/zoneinfo/Australia/Yancowinna | Bin 0 -> 2229 bytes .../site-packages/pytz/zoneinfo/Brazil/Acre | Bin 0 -> 628 bytes .../pytz/zoneinfo/Brazil/DeNoronha | Bin 0 -> 716 bytes .../site-packages/pytz/zoneinfo/Brazil/East | Bin 0 -> 1444 bytes .../site-packages/pytz/zoneinfo/Brazil/West | Bin 0 -> 604 bytes .../python3.8/site-packages/pytz/zoneinfo/CET | Bin 0 -> 2094 bytes .../site-packages/pytz/zoneinfo/CST6CDT | Bin 0 -> 2310 bytes .../pytz/zoneinfo/Canada/Atlantic | Bin 0 -> 3424 bytes .../pytz/zoneinfo/Canada/Central | Bin 0 -> 2868 bytes .../pytz/zoneinfo/Canada/Eastern | Bin 0 -> 3494 bytes .../pytz/zoneinfo/Canada/Mountain | Bin 0 -> 2332 bytes .../pytz/zoneinfo/Canada/Newfoundland | Bin 0 -> 3655 bytes .../pytz/zoneinfo/Canada/Pacific | Bin 0 -> 2892 bytes .../pytz/zoneinfo/Canada/Saskatchewan | Bin 0 -> 980 bytes .../site-packages/pytz/zoneinfo/Canada/Yukon | Bin 0 -> 1614 bytes .../pytz/zoneinfo/Chile/Continental | Bin 0 -> 2529 bytes .../pytz/zoneinfo/Chile/EasterIsland | Bin 0 -> 2233 bytes .../site-packages/pytz/zoneinfo/Cuba | Bin 0 -> 2416 bytes .../python3.8/site-packages/pytz/zoneinfo/EET | Bin 0 -> 1908 bytes .../python3.8/site-packages/pytz/zoneinfo/EST | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/EST5EDT | Bin 0 -> 2310 bytes .../site-packages/pytz/zoneinfo/Egypt | Bin 0 -> 1955 bytes .../site-packages/pytz/zoneinfo/Eire | Bin 0 -> 3492 bytes .../site-packages/pytz/zoneinfo/Etc/GMT | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+0 | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+1 | Bin 0 -> 116 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+10 | Bin 0 -> 117 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+11 | Bin 0 -> 117 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+12 | Bin 0 -> 117 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+2 | Bin 0 -> 116 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+3 | Bin 0 -> 116 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+4 | Bin 0 -> 116 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+5 | Bin 0 -> 116 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+6 | Bin 0 -> 116 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+7 | Bin 0 -> 116 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+8 | Bin 0 -> 116 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+9 | Bin 0 -> 116 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-0 | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-1 | Bin 0 -> 117 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-10 | Bin 0 -> 118 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-11 | Bin 0 -> 118 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-12 | Bin 0 -> 118 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-13 | Bin 0 -> 118 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-14 | Bin 0 -> 118 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-2 | Bin 0 -> 117 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-3 | Bin 0 -> 117 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-4 | Bin 0 -> 117 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-5 | Bin 0 -> 117 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-6 | Bin 0 -> 117 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-7 | Bin 0 -> 117 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-8 | Bin 0 -> 117 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-9 | Bin 0 -> 117 bytes .../site-packages/pytz/zoneinfo/Etc/GMT0 | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/Etc/Greenwich | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/Etc/UCT | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/Etc/UTC | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/Etc/Universal | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/Etc/Zulu | Bin 0 -> 114 bytes .../pytz/zoneinfo/Europe/Amsterdam | Bin 0 -> 2910 bytes .../pytz/zoneinfo/Europe/Andorra | Bin 0 -> 1742 bytes .../pytz/zoneinfo/Europe/Astrakhan | Bin 0 -> 1165 bytes .../site-packages/pytz/zoneinfo/Europe/Athens | Bin 0 -> 2262 bytes .../pytz/zoneinfo/Europe/Belfast | Bin 0 -> 3648 bytes .../pytz/zoneinfo/Europe/Belgrade | Bin 0 -> 1920 bytes .../site-packages/pytz/zoneinfo/Europe/Berlin | Bin 0 -> 2298 bytes .../pytz/zoneinfo/Europe/Bratislava | Bin 0 -> 2301 bytes .../pytz/zoneinfo/Europe/Brussels | Bin 0 -> 2933 bytes .../pytz/zoneinfo/Europe/Bucharest | Bin 0 -> 2184 bytes .../pytz/zoneinfo/Europe/Budapest | Bin 0 -> 2368 bytes .../pytz/zoneinfo/Europe/Busingen | Bin 0 -> 1909 bytes .../pytz/zoneinfo/Europe/Chisinau | Bin 0 -> 2390 bytes .../pytz/zoneinfo/Europe/Copenhagen | Bin 0 -> 2137 bytes .../site-packages/pytz/zoneinfo/Europe/Dublin | Bin 0 -> 3492 bytes .../pytz/zoneinfo/Europe/Gibraltar | Bin 0 -> 3052 bytes .../pytz/zoneinfo/Europe/Guernsey | Bin 0 -> 3648 bytes .../pytz/zoneinfo/Europe/Helsinki | Bin 0 -> 1900 bytes .../pytz/zoneinfo/Europe/Isle_of_Man | Bin 0 -> 3648 bytes .../pytz/zoneinfo/Europe/Istanbul | Bin 0 -> 1947 bytes .../site-packages/pytz/zoneinfo/Europe/Jersey | Bin 0 -> 3648 bytes .../pytz/zoneinfo/Europe/Kaliningrad | Bin 0 -> 1493 bytes .../site-packages/pytz/zoneinfo/Europe/Kiev | Bin 0 -> 2088 bytes .../site-packages/pytz/zoneinfo/Europe/Kirov | Bin 0 -> 1153 bytes .../site-packages/pytz/zoneinfo/Europe/Lisbon | Bin 0 -> 3469 bytes .../pytz/zoneinfo/Europe/Ljubljana | Bin 0 -> 1920 bytes .../site-packages/pytz/zoneinfo/Europe/London | Bin 0 -> 3648 bytes .../pytz/zoneinfo/Europe/Luxembourg | Bin 0 -> 2946 bytes .../site-packages/pytz/zoneinfo/Europe/Madrid | Bin 0 -> 2614 bytes .../site-packages/pytz/zoneinfo/Europe/Malta | Bin 0 -> 2620 bytes .../pytz/zoneinfo/Europe/Mariehamn | Bin 0 -> 1900 bytes .../site-packages/pytz/zoneinfo/Europe/Minsk | Bin 0 -> 1321 bytes .../site-packages/pytz/zoneinfo/Europe/Monaco | Bin 0 -> 2944 bytes .../site-packages/pytz/zoneinfo/Europe/Moscow | Bin 0 -> 1535 bytes .../pytz/zoneinfo/Europe/Nicosia | Bin 0 -> 2002 bytes .../site-packages/pytz/zoneinfo/Europe/Oslo | Bin 0 -> 2228 bytes .../site-packages/pytz/zoneinfo/Europe/Paris | Bin 0 -> 2962 bytes .../pytz/zoneinfo/Europe/Podgorica | Bin 0 -> 1920 bytes .../site-packages/pytz/zoneinfo/Europe/Prague | Bin 0 -> 2301 bytes .../site-packages/pytz/zoneinfo/Europe/Riga | Bin 0 -> 2198 bytes .../site-packages/pytz/zoneinfo/Europe/Rome | Bin 0 -> 2641 bytes .../site-packages/pytz/zoneinfo/Europe/Samara | Bin 0 -> 1215 bytes .../pytz/zoneinfo/Europe/San_Marino | Bin 0 -> 2641 bytes .../pytz/zoneinfo/Europe/Sarajevo | Bin 0 -> 1920 bytes .../pytz/zoneinfo/Europe/Saratov | Bin 0 -> 1183 bytes .../pytz/zoneinfo/Europe/Simferopol | Bin 0 -> 1453 bytes .../site-packages/pytz/zoneinfo/Europe/Skopje | Bin 0 -> 1920 bytes .../site-packages/pytz/zoneinfo/Europe/Sofia | Bin 0 -> 2077 bytes .../pytz/zoneinfo/Europe/Stockholm | Bin 0 -> 1909 bytes .../pytz/zoneinfo/Europe/Tallinn | Bin 0 -> 2148 bytes .../site-packages/pytz/zoneinfo/Europe/Tirane | Bin 0 -> 2084 bytes .../pytz/zoneinfo/Europe/Tiraspol | Bin 0 -> 2390 bytes .../pytz/zoneinfo/Europe/Ulyanovsk | Bin 0 -> 1267 bytes .../pytz/zoneinfo/Europe/Uzhgorod | Bin 0 -> 2050 bytes .../site-packages/pytz/zoneinfo/Europe/Vaduz | Bin 0 -> 1909 bytes .../pytz/zoneinfo/Europe/Vatican | Bin 0 -> 2641 bytes .../site-packages/pytz/zoneinfo/Europe/Vienna | Bin 0 -> 2200 bytes .../pytz/zoneinfo/Europe/Vilnius | Bin 0 -> 2162 bytes .../pytz/zoneinfo/Europe/Volgograd | Bin 0 -> 1165 bytes .../site-packages/pytz/zoneinfo/Europe/Warsaw | Bin 0 -> 2654 bytes .../site-packages/pytz/zoneinfo/Europe/Zagreb | Bin 0 -> 1920 bytes .../pytz/zoneinfo/Europe/Zaporozhye | Bin 0 -> 2106 bytes .../site-packages/pytz/zoneinfo/Europe/Zurich | Bin 0 -> 1909 bytes .../site-packages/pytz/zoneinfo/Factory | Bin 0 -> 116 bytes .../python3.8/site-packages/pytz/zoneinfo/GB | Bin 0 -> 3648 bytes .../site-packages/pytz/zoneinfo/GB-Eire | Bin 0 -> 3648 bytes .../python3.8/site-packages/pytz/zoneinfo/GMT | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/GMT+0 | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/GMT-0 | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/GMT0 | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/Greenwich | Bin 0 -> 114 bytes .../python3.8/site-packages/pytz/zoneinfo/HST | Bin 0 -> 115 bytes .../site-packages/pytz/zoneinfo/Hongkong | Bin 0 -> 1203 bytes .../site-packages/pytz/zoneinfo/Iceland | Bin 0 -> 1162 bytes .../pytz/zoneinfo/Indian/Antananarivo | Bin 0 -> 265 bytes .../site-packages/pytz/zoneinfo/Indian/Chagos | Bin 0 -> 199 bytes .../pytz/zoneinfo/Indian/Christmas | Bin 0 -> 165 bytes .../site-packages/pytz/zoneinfo/Indian/Cocos | Bin 0 -> 174 bytes .../site-packages/pytz/zoneinfo/Indian/Comoro | Bin 0 -> 265 bytes .../pytz/zoneinfo/Indian/Kerguelen | Bin 0 -> 165 bytes .../site-packages/pytz/zoneinfo/Indian/Mahe | Bin 0 -> 165 bytes .../pytz/zoneinfo/Indian/Maldives | Bin 0 -> 199 bytes .../pytz/zoneinfo/Indian/Mauritius | Bin 0 -> 241 bytes .../pytz/zoneinfo/Indian/Mayotte | Bin 0 -> 265 bytes .../pytz/zoneinfo/Indian/Reunion | Bin 0 -> 165 bytes .../site-packages/pytz/zoneinfo/Iran | Bin 0 -> 2582 bytes .../site-packages/pytz/zoneinfo/Israel | Bin 0 -> 2388 bytes .../site-packages/pytz/zoneinfo/Jamaica | Bin 0 -> 482 bytes .../site-packages/pytz/zoneinfo/Japan | Bin 0 -> 309 bytes .../site-packages/pytz/zoneinfo/Kwajalein | Bin 0 -> 316 bytes .../site-packages/pytz/zoneinfo/Libya | Bin 0 -> 625 bytes .../python3.8/site-packages/pytz/zoneinfo/MET | Bin 0 -> 2094 bytes .../python3.8/site-packages/pytz/zoneinfo/MST | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/MST7MDT | Bin 0 -> 2310 bytes .../pytz/zoneinfo/Mexico/BajaNorte | Bin 0 -> 2342 bytes .../pytz/zoneinfo/Mexico/BajaSur | Bin 0 -> 1526 bytes .../pytz/zoneinfo/Mexico/General | Bin 0 -> 1584 bytes .../python3.8/site-packages/pytz/zoneinfo/NZ | Bin 0 -> 2437 bytes .../site-packages/pytz/zoneinfo/NZ-CHAT | Bin 0 -> 2068 bytes .../site-packages/pytz/zoneinfo/Navajo | Bin 0 -> 2444 bytes .../python3.8/site-packages/pytz/zoneinfo/PRC | Bin 0 -> 561 bytes .../site-packages/pytz/zoneinfo/PST8PDT | Bin 0 -> 2310 bytes .../site-packages/pytz/zoneinfo/Pacific/Apia | Bin 0 -> 1097 bytes .../pytz/zoneinfo/Pacific/Auckland | Bin 0 -> 2437 bytes .../pytz/zoneinfo/Pacific/Bougainville | Bin 0 -> 268 bytes .../pytz/zoneinfo/Pacific/Chatham | Bin 0 -> 2068 bytes .../site-packages/pytz/zoneinfo/Pacific/Chuuk | Bin 0 -> 269 bytes .../pytz/zoneinfo/Pacific/Easter | Bin 0 -> 2233 bytes .../site-packages/pytz/zoneinfo/Pacific/Efate | Bin 0 -> 538 bytes .../pytz/zoneinfo/Pacific/Enderbury | Bin 0 -> 234 bytes .../pytz/zoneinfo/Pacific/Fakaofo | Bin 0 -> 200 bytes .../site-packages/pytz/zoneinfo/Pacific/Fiji | Bin 0 -> 1077 bytes .../pytz/zoneinfo/Pacific/Funafuti | Bin 0 -> 166 bytes .../pytz/zoneinfo/Pacific/Galapagos | Bin 0 -> 238 bytes .../pytz/zoneinfo/Pacific/Gambier | Bin 0 -> 164 bytes .../pytz/zoneinfo/Pacific/Guadalcanal | Bin 0 -> 166 bytes .../site-packages/pytz/zoneinfo/Pacific/Guam | Bin 0 -> 494 bytes .../pytz/zoneinfo/Pacific/Honolulu | Bin 0 -> 329 bytes .../pytz/zoneinfo/Pacific/Johnston | Bin 0 -> 329 bytes .../pytz/zoneinfo/Pacific/Kiritimati | Bin 0 -> 238 bytes .../pytz/zoneinfo/Pacific/Kosrae | Bin 0 -> 351 bytes .../pytz/zoneinfo/Pacific/Kwajalein | Bin 0 -> 316 bytes .../pytz/zoneinfo/Pacific/Majuro | Bin 0 -> 310 bytes .../pytz/zoneinfo/Pacific/Marquesas | Bin 0 -> 173 bytes .../pytz/zoneinfo/Pacific/Midway | Bin 0 -> 175 bytes .../site-packages/pytz/zoneinfo/Pacific/Nauru | Bin 0 -> 252 bytes .../site-packages/pytz/zoneinfo/Pacific/Niue | Bin 0 -> 241 bytes .../pytz/zoneinfo/Pacific/Norfolk | Bin 0 -> 880 bytes .../pytz/zoneinfo/Pacific/Noumea | Bin 0 -> 304 bytes .../pytz/zoneinfo/Pacific/Pago_Pago | Bin 0 -> 175 bytes .../site-packages/pytz/zoneinfo/Pacific/Palau | Bin 0 -> 180 bytes .../pytz/zoneinfo/Pacific/Pitcairn | Bin 0 -> 202 bytes .../pytz/zoneinfo/Pacific/Pohnpei | Bin 0 -> 303 bytes .../pytz/zoneinfo/Pacific/Ponape | Bin 0 -> 303 bytes .../pytz/zoneinfo/Pacific/Port_Moresby | Bin 0 -> 186 bytes .../pytz/zoneinfo/Pacific/Rarotonga | Bin 0 -> 577 bytes .../pytz/zoneinfo/Pacific/Saipan | Bin 0 -> 494 bytes .../site-packages/pytz/zoneinfo/Pacific/Samoa | Bin 0 -> 175 bytes .../pytz/zoneinfo/Pacific/Tahiti | Bin 0 -> 165 bytes .../pytz/zoneinfo/Pacific/Tarawa | Bin 0 -> 166 bytes .../pytz/zoneinfo/Pacific/Tongatapu | Bin 0 -> 372 bytes .../site-packages/pytz/zoneinfo/Pacific/Truk | Bin 0 -> 269 bytes .../site-packages/pytz/zoneinfo/Pacific/Wake | Bin 0 -> 166 bytes .../pytz/zoneinfo/Pacific/Wallis | Bin 0 -> 166 bytes .../site-packages/pytz/zoneinfo/Pacific/Yap | Bin 0 -> 269 bytes .../site-packages/pytz/zoneinfo/Poland | Bin 0 -> 2654 bytes .../site-packages/pytz/zoneinfo/Portugal | Bin 0 -> 3469 bytes .../python3.8/site-packages/pytz/zoneinfo/ROC | Bin 0 -> 761 bytes .../python3.8/site-packages/pytz/zoneinfo/ROK | Bin 0 -> 617 bytes .../site-packages/pytz/zoneinfo/Singapore | Bin 0 -> 383 bytes .../site-packages/pytz/zoneinfo/Turkey | Bin 0 -> 1947 bytes .../python3.8/site-packages/pytz/zoneinfo/UCT | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/US/Alaska | Bin 0 -> 2371 bytes .../site-packages/pytz/zoneinfo/US/Aleutian | Bin 0 -> 2356 bytes .../site-packages/pytz/zoneinfo/US/Arizona | Bin 0 -> 328 bytes .../site-packages/pytz/zoneinfo/US/Central | Bin 0 -> 3576 bytes .../pytz/zoneinfo/US/East-Indiana | Bin 0 -> 1666 bytes .../site-packages/pytz/zoneinfo/US/Eastern | Bin 0 -> 3536 bytes .../site-packages/pytz/zoneinfo/US/Hawaii | Bin 0 -> 329 bytes .../pytz/zoneinfo/US/Indiana-Starke | Bin 0 -> 2428 bytes .../site-packages/pytz/zoneinfo/US/Michigan | Bin 0 -> 2230 bytes .../site-packages/pytz/zoneinfo/US/Mountain | Bin 0 -> 2444 bytes .../site-packages/pytz/zoneinfo/US/Pacific | Bin 0 -> 2836 bytes .../site-packages/pytz/zoneinfo/US/Samoa | Bin 0 -> 175 bytes .../python3.8/site-packages/pytz/zoneinfo/UTC | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/Universal | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/W-SU | Bin 0 -> 1535 bytes .../python3.8/site-packages/pytz/zoneinfo/WET | Bin 0 -> 1905 bytes .../site-packages/pytz/zoneinfo/Zulu | Bin 0 -> 114 bytes .../site-packages/pytz/zoneinfo/iso3166.tab | 274 + .../site-packages/pytz/zoneinfo/leapseconds | 82 + .../site-packages/pytz/zoneinfo/tzdata.zi | 4459 +++++++++ .../site-packages/pytz/zoneinfo/zone.tab | 451 + .../site-packages/pytz/zoneinfo/zone1970.tab | 383 + .../requests-2.25.1.dist-info/INSTALLER | 1 + .../requests-2.25.1.dist-info/LICENSE | 175 + .../requests-2.25.1.dist-info/METADATA | 103 + .../requests-2.25.1.dist-info/RECORD | 42 + .../requests-2.25.1.dist-info/WHEEL | 6 + .../requests-2.25.1.dist-info/top_level.txt | 1 + .../site-packages/requests/__init__.py | 137 + .../site-packages/requests/__version__.py | 14 + .../site-packages/requests/_internal_utils.py | 42 + .../site-packages/requests/adapters.py | 533 ++ .../python3.8/site-packages/requests/api.py | 161 + .../python3.8/site-packages/requests/auth.py | 305 + .../python3.8/site-packages/requests/certs.py | 18 + .../site-packages/requests/compat.py | 72 + .../site-packages/requests/cookies.py | 549 ++ .../site-packages/requests/exceptions.py | 123 + .../python3.8/site-packages/requests/help.py | 119 + .../python3.8/site-packages/requests/hooks.py | 34 + .../site-packages/requests/models.py | 956 ++ .../site-packages/requests/packages.py | 14 + .../site-packages/requests/sessions.py | 781 ++ .../site-packages/requests/status_codes.py | 123 + .../site-packages/requests/structures.py | 105 + .../python3.8/site-packages/requests/utils.py | 992 ++ .../setuptools-44.0.0.dist-info/AUTHORS.txt | 566 ++ .../setuptools-44.0.0.dist-info/INSTALLER | 1 + .../setuptools-44.0.0.dist-info/LICENSE.txt | 20 + .../setuptools-44.0.0.dist-info/METADATA | 82 + .../setuptools-44.0.0.dist-info/RECORD | 163 + .../setuptools-44.0.0.dist-info/WHEEL | 6 + .../dependency_links.txt | 2 + .../entry_points.txt | 68 + .../setuptools-44.0.0.dist-info/top_level.txt | 3 + .../setuptools-44.0.0.dist-info/zip-safe | 1 + .../site-packages/setuptools/__init__.py | 228 + .../setuptools/_deprecation_warning.py | 7 + .../site-packages/setuptools/_imp.py | 73 + .../setuptools/_vendor/__init__.py | 0 .../setuptools/_vendor/ordered_set.py | 488 + .../setuptools/_vendor/packaging/__about__.py | 27 + .../setuptools/_vendor/packaging/__init__.py | 26 + .../setuptools/_vendor/packaging/_compat.py | 31 + .../_vendor/packaging/_structures.py | 68 + .../setuptools/_vendor/packaging/markers.py | 296 + .../_vendor/packaging/requirements.py | 138 + .../_vendor/packaging/specifiers.py | 749 ++ .../setuptools/_vendor/packaging/tags.py | 404 + .../setuptools/_vendor/packaging/utils.py | 57 + .../setuptools/_vendor/packaging/version.py | 420 + .../setuptools/_vendor/pyparsing.py | 5742 +++++++++++ .../site-packages/setuptools/_vendor/six.py | 868 ++ .../site-packages/setuptools/archive_util.py | 173 + .../site-packages/setuptools/build_meta.py | 257 + .../site-packages/setuptools/cli-32.exe | Bin 0 -> 65536 bytes .../site-packages/setuptools/cli-64.exe | Bin 0 -> 74752 bytes .../site-packages/setuptools/cli.exe | Bin 0 -> 65536 bytes .../setuptools/command/__init__.py | 17 + .../site-packages/setuptools/command/alias.py | 80 + .../setuptools/command/bdist_egg.py | 502 + .../setuptools/command/bdist_rpm.py | 43 + .../setuptools/command/bdist_wininst.py | 21 + .../setuptools/command/build_clib.py | 98 + .../setuptools/command/build_ext.py | 327 + .../setuptools/command/build_py.py | 270 + .../setuptools/command/develop.py | 221 + .../setuptools/command/dist_info.py | 36 + .../setuptools/command/easy_install.py | 2402 +++++ .../setuptools/command/egg_info.py | 717 ++ .../setuptools/command/install.py | 125 + .../setuptools/command/install_egg_info.py | 82 + .../setuptools/command/install_lib.py | 147 + .../setuptools/command/install_scripts.py | 65 + .../setuptools/command/launcher manifest.xml | 15 + .../setuptools/command/py36compat.py | 136 + .../setuptools/command/register.py | 18 + .../setuptools/command/rotate.py | 66 + .../setuptools/command/saveopts.py | 22 + .../site-packages/setuptools/command/sdist.py | 252 + .../setuptools/command/setopt.py | 149 + .../site-packages/setuptools/command/test.py | 279 + .../setuptools/command/upload.py | 17 + .../setuptools/command/upload_docs.py | 206 + .../site-packages/setuptools/config.py | 659 ++ .../site-packages/setuptools/dep_util.py | 23 + .../site-packages/setuptools/depends.py | 176 + .../site-packages/setuptools/dist.py | 1274 +++ .../site-packages/setuptools/errors.py | 16 + .../site-packages/setuptools/extension.py | 57 + .../setuptools/extern/__init__.py | 73 + .../site-packages/setuptools/glob.py | 174 + .../site-packages/setuptools/gui-32.exe | Bin 0 -> 65536 bytes .../site-packages/setuptools/gui-64.exe | Bin 0 -> 75264 bytes .../site-packages/setuptools/gui.exe | Bin 0 -> 65536 bytes .../site-packages/setuptools/installer.py | 150 + .../site-packages/setuptools/launch.py | 35 + .../site-packages/setuptools/lib2to3_ex.py | 62 + .../site-packages/setuptools/monkey.py | 179 + .../site-packages/setuptools/msvc.py | 1679 ++++ .../site-packages/setuptools/namespaces.py | 107 + .../site-packages/setuptools/package_index.py | 1136 +++ .../site-packages/setuptools/py27compat.py | 60 + .../site-packages/setuptools/py31compat.py | 32 + .../site-packages/setuptools/py33compat.py | 59 + .../site-packages/setuptools/py34compat.py | 13 + .../site-packages/setuptools/sandbox.py | 491 + .../setuptools/script (dev).tmpl | 6 + .../site-packages/setuptools/script.tmpl | 3 + .../site-packages/setuptools/site-patch.py | 74 + .../site-packages/setuptools/ssl_support.py | 260 + .../site-packages/setuptools/unicode_utils.py | 44 + .../site-packages/setuptools/version.py | 6 + .../site-packages/setuptools/wheel.py | 220 + .../setuptools/windows_support.py | 29 + .../six-1.16.0.dist-info/INSTALLER | 1 + .../six-1.16.0.dist-info/LICENSE | 18 + .../six-1.16.0.dist-info/METADATA | 49 + .../site-packages/six-1.16.0.dist-info/RECORD | 8 + .../site-packages/six-1.16.0.dist-info/WHEEL | 6 + .../six-1.16.0.dist-info/top_level.txt | 1 + venv/lib/python3.8/site-packages/six.py | 998 ++ .../site-packages/telegram/__init__.py | 294 + .../site-packages/telegram/__main__.py | 54 + .../python3.8/site-packages/telegram/base.py | 152 + .../python3.8/site-packages/telegram/bot.py | 5318 +++++++++++ .../site-packages/telegram/botcommand.py | 50 + .../site-packages/telegram/callbackquery.py | 658 ++ .../python3.8/site-packages/telegram/chat.py | 1559 +++ .../site-packages/telegram/chataction.py | 70 + .../site-packages/telegram/chatinvitelink.py | 114 + .../site-packages/telegram/chatlocation.py | 73 + .../site-packages/telegram/chatmember.py | 253 + .../telegram/chatmemberupdated.py | 173 + .../site-packages/telegram/chatpermissions.py | 124 + .../telegram/choseninlineresult.py | 98 + .../site-packages/telegram/constants.py | 345 + .../python3.8/site-packages/telegram/dice.py | 92 + .../python3.8/site-packages/telegram/error.py | 151 + .../site-packages/telegram/ext/__init__.py | 104 + .../telegram/ext/basepersistence.py | 538 ++ .../telegram/ext/callbackcontext.py | 361 + .../telegram/ext/callbackdatacache.py | 427 + .../telegram/ext/callbackqueryhandler.py | 236 + .../telegram/ext/chatmemberhandler.py | 145 + .../telegram/ext/choseninlineresulthandler.py | 160 + .../telegram/ext/commandhandler.py | 456 + .../telegram/ext/contexttypes.py | 194 + .../telegram/ext/conversationhandler.py | 725 ++ .../site-packages/telegram/ext/defaults.py | 267 + .../telegram/ext/dictpersistence.py | 404 + .../site-packages/telegram/ext/dispatcher.py | 820 ++ .../site-packages/telegram/ext/extbot.py | 326 + .../site-packages/telegram/ext/filters.py | 2313 +++++ .../site-packages/telegram/ext/handler.py | 260 + .../telegram/ext/inlinequeryhandler.py | 221 + .../site-packages/telegram/ext/jobqueue.py | 656 ++ .../telegram/ext/messagehandler.py | 208 + .../telegram/ext/messagequeue.py | 334 + .../telegram/ext/picklepersistence.py | 463 + .../telegram/ext/pollanswerhandler.py | 98 + .../site-packages/telegram/ext/pollhandler.py | 98 + .../telegram/ext/precheckoutqueryhandler.py | 98 + .../telegram/ext/regexhandler.py | 166 + .../telegram/ext/shippingqueryhandler.py | 97 + .../telegram/ext/stringcommandhandler.py | 149 + .../telegram/ext/stringregexhandler.py | 166 + .../site-packages/telegram/ext/typehandler.py | 108 + .../site-packages/telegram/ext/updater.py | 890 ++ .../telegram/ext/utils/__init__.py | 17 + .../telegram/ext/utils/promise.py | 158 + .../site-packages/telegram/ext/utils/types.py | 62 + .../telegram/ext/utils/webhookhandler.py | 177 + .../site-packages/telegram/files/__init__.py | 0 .../site-packages/telegram/files/animation.py | 137 + .../site-packages/telegram/files/audio.py | 141 + .../site-packages/telegram/files/chatphoto.py | 132 + .../site-packages/telegram/files/contact.py | 68 + .../site-packages/telegram/files/document.py | 125 + .../site-packages/telegram/files/file.py | 213 + .../site-packages/telegram/files/inputfile.py | 119 + .../telegram/files/inputmedia.py | 525 ++ .../site-packages/telegram/files/location.py | 91 + .../site-packages/telegram/files/photosize.py | 98 + .../site-packages/telegram/files/sticker.py | 288 + .../site-packages/telegram/files/venue.py | 107 + .../site-packages/telegram/files/video.py | 138 + .../site-packages/telegram/files/videonote.py | 124 + .../site-packages/telegram/files/voice.py | 106 + .../site-packages/telegram/forcereply.py | 61 + .../site-packages/telegram/games/__init__.py | 0 .../telegram/games/callbackgame.py | 27 + .../site-packages/telegram/games/game.py | 186 + .../telegram/games/gamehighscore.py | 67 + .../site-packages/telegram/inline/__init__.py | 0 .../telegram/inline/inlinekeyboardbutton.py | 162 + .../telegram/inline/inlinekeyboardmarkup.py | 138 + .../telegram/inline/inlinequery.py | 168 + .../telegram/inline/inlinequeryresult.py | 71 + .../inline/inlinequeryresultarticle.py | 105 + .../telegram/inline/inlinequeryresultaudio.py | 116 + .../inline/inlinequeryresultcachedaudio.py | 100 + .../inline/inlinequeryresultcacheddocument.py | 113 + .../inline/inlinequeryresultcachedgif.py | 108 + .../inline/inlinequeryresultcachedmpeg4gif.py | 108 + .../inline/inlinequeryresultcachedphoto.py | 114 + .../inline/inlinequeryresultcachedsticker.py | 71 + .../inline/inlinequeryresultcachedvideo.py | 113 + .../inline/inlinequeryresultcachedvoice.py | 105 + .../inline/inlinequeryresultcontact.py | 107 + .../inline/inlinequeryresultdocument.py | 135 + .../telegram/inline/inlinequeryresultgame.py | 62 + .../telegram/inline/inlinequeryresultgif.py | 137 + .../inline/inlinequeryresultlocation.py | 131 + .../inline/inlinequeryresultmpeg4gif.py | 136 + .../telegram/inline/inlinequeryresultphoto.py | 129 + .../telegram/inline/inlinequeryresultvenue.py | 133 + .../telegram/inline/inlinequeryresultvideo.py | 146 + .../telegram/inline/inlinequeryresultvoice.py | 112 + .../inline/inputcontactmessagecontent.py | 66 + .../inline/inputinvoicemessagecontent.py | 242 + .../inline/inputlocationmessagecontent.py | 88 + .../telegram/inline/inputmessagecontent.py | 34 + .../inline/inputtextmessagecontent.py | 88 + .../inline/inputvenuemessagecontent.py | 102 + .../site-packages/telegram/keyboardbutton.py | 83 + .../telegram/keyboardbuttonpolltype.py | 45 + .../site-packages/telegram/loginurl.py | 89 + .../site-packages/telegram/message.py | 2888 ++++++ .../telegram/messageautodeletetimerchanged.py | 56 + .../site-packages/telegram/messageentity.py | 129 + .../site-packages/telegram/messageid.py | 40 + .../site-packages/telegram/parsemode.py | 45 + .../telegram/passport/__init__.py | 0 .../telegram/passport/credentials.py | 497 + .../site-packages/telegram/passport/data.py | 153 + .../passport/encryptedpassportelement.py | 266 + .../telegram/passport/passportdata.py | 121 + .../passport/passportelementerrors.py | 382 + .../telegram/passport/passportfile.py | 160 + .../telegram/payment/__init__.py | 0 .../site-packages/telegram/payment/invoice.py | 86 + .../telegram/payment/labeledprice.py | 54 + .../telegram/payment/orderinfo.py | 79 + .../telegram/payment/precheckoutquery.py | 140 + .../telegram/payment/shippingaddress.py | 86 + .../telegram/payment/shippingoption.py | 70 + .../telegram/payment/shippingquery.py | 113 + .../telegram/payment/successfulpayment.py | 107 + .../python3.8/site-packages/telegram/poll.py | 295 + .../telegram/proximityalerttriggered.py | 69 + .../python3.8/site-packages/telegram/py.typed | 0 .../telegram/replykeyboardmarkup.py | 251 + .../telegram/replykeyboardremove.py | 64 + .../site-packages/telegram/replymarkup.py | 33 + .../site-packages/telegram/update.py | 388 + .../python3.8/site-packages/telegram/user.py | 1142 +++ .../telegram/userprofilephotos.py | 79 + .../site-packages/telegram/utils/__init__.py | 0 .../site-packages/telegram/utils/deprecate.py | 45 + .../site-packages/telegram/utils/helpers.py | 596 ++ .../site-packages/telegram/utils/promise.py | 38 + .../site-packages/telegram/utils/request.py | 395 + .../site-packages/telegram/utils/types.py | 57 + .../telegram/utils/webhookhandler.py | 35 + .../site-packages/telegram/vendor/__init__.py | 0 .../telegram/vendor/ptb_urllib3/__init__.py | 0 .../vendor/ptb_urllib3/urllib3/__init__.py | 96 + .../ptb_urllib3/urllib3/_collections.py | 327 + .../vendor/ptb_urllib3/urllib3/connection.py | 369 + .../ptb_urllib3/urllib3/connectionpool.py | 912 ++ .../ptb_urllib3/urllib3/contrib/__init__.py | 0 .../ptb_urllib3/urllib3/contrib/appengine.py | 296 + .../ptb_urllib3/urllib3/contrib/ntlmpool.py | 112 + .../ptb_urllib3/urllib3/contrib/pyopenssl.py | 450 + .../ptb_urllib3/urllib3/contrib/socks.py | 192 + .../vendor/ptb_urllib3/urllib3/exceptions.py | 246 + .../vendor/ptb_urllib3/urllib3/fields.py | 178 + .../vendor/ptb_urllib3/urllib3/filepost.py | 94 + .../ptb_urllib3/urllib3/packages/__init__.py | 5 + .../urllib3/packages/backports/__init__.py | 0 .../urllib3/packages/backports/makefile.py | 53 + .../urllib3/packages/ordered_dict.py | 259 + .../ptb_urllib3/urllib3/packages/six.py | 868 ++ .../packages/ssl_match_hostname/__init__.py | 19 + .../ssl_match_hostname/_implementation.py | 157 + .../vendor/ptb_urllib3/urllib3/poolmanager.py | 363 + .../vendor/ptb_urllib3/urllib3/request.py | 148 + .../vendor/ptb_urllib3/urllib3/response.py | 618 ++ .../ptb_urllib3/urllib3/util/__init__.py | 52 + .../ptb_urllib3/urllib3/util/connection.py | 130 + .../ptb_urllib3/urllib3/util/request.py | 118 + .../ptb_urllib3/urllib3/util/response.py | 81 + .../vendor/ptb_urllib3/urllib3/util/retry.py | 389 + .../ptb_urllib3/urllib3/util/selectors.py | 529 ++ .../vendor/ptb_urllib3/urllib3/util/ssl_.py | 336 + .../ptb_urllib3/urllib3/util/timeout.py | 242 + .../vendor/ptb_urllib3/urllib3/util/url.py | 226 + .../vendor/ptb_urllib3/urllib3/util/wait.py | 40 + .../site-packages/telegram/version.py | 24 + .../site-packages/telegram/voicechat.py | 169 + .../site-packages/telegram/webhookinfo.py | 110 + .../tornado-6.1.dist-info/INSTALLER | 1 + .../tornado-6.1.dist-info/LICENSE | 202 + .../tornado-6.1.dist-info/METADATA | 70 + .../tornado-6.1.dist-info/RECORD | 165 + .../site-packages/tornado-6.1.dist-info/WHEEL | 5 + .../tornado-6.1.dist-info/top_level.txt | 1 + .../site-packages/tornado/__init__.py | 26 + .../site-packages/tornado/_locale_data.py | 80 + .../python3.8/site-packages/tornado/auth.py | 1187 +++ .../site-packages/tornado/autoreload.py | 363 + .../site-packages/tornado/concurrent.py | 263 + .../site-packages/tornado/curl_httpclient.py | 583 ++ .../python3.8/site-packages/tornado/escape.py | 402 + .../python3.8/site-packages/tornado/gen.py | 872 ++ .../site-packages/tornado/http1connection.py | 842 ++ .../site-packages/tornado/httpclient.py | 790 ++ .../site-packages/tornado/httpserver.py | 398 + .../site-packages/tornado/httputil.py | 1133 +++ .../python3.8/site-packages/tornado/ioloop.py | 944 ++ .../site-packages/tornado/iostream.py | 1660 ++++ .../python3.8/site-packages/tornado/locale.py | 581 ++ .../python3.8/site-packages/tornado/locks.py | 571 ++ .../python3.8/site-packages/tornado/log.py | 339 + .../site-packages/tornado/netutil.py | 617 ++ .../site-packages/tornado/options.py | 735 ++ .../tornado/platform/__init__.py | 0 .../site-packages/tornado/platform/asyncio.py | 611 ++ .../tornado/platform/caresresolver.py | 89 + .../site-packages/tornado/platform/twisted.py | 146 + .../site-packages/tornado/process.py | 373 + .../python3.8/site-packages/tornado/py.typed | 0 .../python3.8/site-packages/tornado/queues.py | 414 + .../site-packages/tornado/routing.py | 717 ++ .../tornado/simple_httpclient.py | 699 ++ .../speedups.cpython-38-x86_64-linux-gnu.so | Bin 0 -> 29256 bytes .../site-packages/tornado/tcpclient.py | 328 + .../site-packages/tornado/tcpserver.py | 334 + .../site-packages/tornado/template.py | 1048 +++ .../site-packages/tornado/test/__main__.py | 12 + .../tornado/test/asyncio_test.py | 190 + .../site-packages/tornado/test/auth_test.py | 609 ++ .../tornado/test/autoreload_test.py | 127 + .../tornado/test/concurrent_test.py | 212 + .../tornado/test/csv_translations/fr_FR.csv | 1 + .../tornado/test/curl_httpclient_test.py | 129 + .../site-packages/tornado/test/escape_test.py | 322 + .../site-packages/tornado/test/gen_test.py | 1119 +++ .../fr_FR/LC_MESSAGES/tornado_test.mo | Bin 0 -> 665 bytes .../fr_FR/LC_MESSAGES/tornado_test.po | 47 + .../tornado/test/http1connection_test.py | 61 + .../tornado/test/httpclient_test.py | 898 ++ .../tornado/test/httpserver_test.py | 1339 +++ .../tornado/test/httputil_test.py | 521 + .../site-packages/tornado/test/import_test.py | 66 + .../site-packages/tornado/test/ioloop_test.py | 725 ++ .../tornado/test/iostream_test.py | 1282 +++ .../site-packages/tornado/test/locale_test.py | 151 + .../site-packages/tornado/test/locks_test.py | 535 ++ .../site-packages/tornado/test/log_test.py | 245 + .../tornado/test/netutil_test.py | 233 + .../tornado/test/options_test.cfg | 7 + .../tornado/test/options_test.py | 328 + .../tornado/test/options_test_types.cfg | 11 + .../tornado/test/options_test_types_str.cfg | 8 + .../tornado/test/process_test.py | 274 + .../site-packages/tornado/test/queues_test.py | 431 + .../tornado/test/resolve_test_helper.py | 10 + .../tornado/test/routing_test.py | 276 + .../site-packages/tornado/test/runtests.py | 241 + .../tornado/test/simple_httpclient_test.py | 834 ++ .../tornado/test/static/dir/index.html | 1 + .../tornado/test/static/robots.txt | 2 + .../tornado/test/static/sample.xml | 23 + .../tornado/test/static/sample.xml.bz2 | Bin 0 -> 285 bytes .../tornado/test/static/sample.xml.gz | Bin 0 -> 264 bytes .../site-packages/tornado/test/static_foo.txt | 2 + .../tornado/test/tcpclient_test.py | 438 + .../tornado/test/tcpserver_test.py | 192 + .../tornado/test/template_test.py | 536 ++ .../tornado/test/templates/utf8.html | 1 + .../site-packages/tornado/test/test.crt | 20 + .../site-packages/tornado/test/test.key | 28 + .../tornado/test/testing_test.py | 353 + .../tornado/test/twisted_test.py | 247 + .../site-packages/tornado/test/util.py | 114 + .../site-packages/tornado/test/util_test.py | 308 + .../site-packages/tornado/test/web_test.py | 3156 +++++++ .../tornado/test/websocket_test.py | 840 ++ .../site-packages/tornado/test/wsgi_test.py | 20 + .../site-packages/tornado/testing.py | 818 ++ .../python3.8/site-packages/tornado/util.py | 474 + .../python3.8/site-packages/tornado/web.py | 3588 +++++++ .../site-packages/tornado/websocket.py | 1666 ++++ .../python3.8/site-packages/tornado/wsgi.py | 199 + .../tzlocal-2.1.dist-info/INSTALLER | 1 + .../tzlocal-2.1.dist-info/LICENSE.txt | 19 + .../tzlocal-2.1.dist-info/METADATA | 326 + .../tzlocal-2.1.dist-info/RECORD | 17 + .../site-packages/tzlocal-2.1.dist-info/WHEEL | 6 + .../tzlocal-2.1.dist-info/top_level.txt | 1 + .../tzlocal-2.1.dist-info/zip-safe | 1 + .../site-packages/tzlocal/__init__.py | 5 + .../python3.8/site-packages/tzlocal/unix.py | 174 + .../python3.8/site-packages/tzlocal/utils.py | 46 + .../python3.8/site-packages/tzlocal/win32.py | 104 + .../site-packages/tzlocal/windows_tz.py | 697 ++ .../urllib3-1.26.6.dist-info/INSTALLER | 1 + .../urllib3-1.26.6.dist-info/LICENSE.txt | 21 + .../urllib3-1.26.6.dist-info/METADATA | 1388 +++ .../urllib3-1.26.6.dist-info/RECORD | 84 + .../urllib3-1.26.6.dist-info/WHEEL | 6 + .../urllib3-1.26.6.dist-info/top_level.txt | 1 + .../site-packages/urllib3/__init__.py | 85 + .../site-packages/urllib3/_collections.py | 337 + .../site-packages/urllib3/_version.py | 2 + .../site-packages/urllib3/connection.py | 539 ++ .../site-packages/urllib3/connectionpool.py | 1067 +++ .../site-packages/urllib3/contrib/__init__.py | 0 .../urllib3/contrib/_appengine_environ.py | 36 + .../contrib/_securetransport/__init__.py | 0 .../contrib/_securetransport/bindings.py | 519 + .../contrib/_securetransport/low_level.py | 396 + .../urllib3/contrib/appengine.py | 314 + .../site-packages/urllib3/contrib/ntlmpool.py | 130 + .../urllib3/contrib/pyopenssl.py | 511 + .../urllib3/contrib/securetransport.py | 922 ++ .../site-packages/urllib3/contrib/socks.py | 216 + .../site-packages/urllib3/exceptions.py | 323 + .../python3.8/site-packages/urllib3/fields.py | 274 + .../site-packages/urllib3/filepost.py | 98 + .../urllib3/packages/__init__.py | 5 + .../urllib3/packages/backports/__init__.py | 0 .../urllib3/packages/backports/makefile.py | 51 + .../site-packages/urllib3/packages/six.py | 1077 +++ .../packages/ssl_match_hostname/__init__.py | 24 + .../ssl_match_hostname/_implementation.py | 160 + .../site-packages/urllib3/poolmanager.py | 536 ++ .../site-packages/urllib3/request.py | 170 + .../site-packages/urllib3/response.py | 821 ++ .../site-packages/urllib3/util/__init__.py | 49 + .../site-packages/urllib3/util/connection.py | 150 + .../site-packages/urllib3/util/proxy.py | 56 + .../site-packages/urllib3/util/queue.py | 22 + .../site-packages/urllib3/util/request.py | 143 + .../site-packages/urllib3/util/response.py | 107 + .../site-packages/urllib3/util/retry.py | 602 ++ .../site-packages/urllib3/util/ssl_.py | 495 + .../urllib3/util/ssltransport.py | 221 + .../site-packages/urllib3/util/timeout.py | 268 + .../site-packages/urllib3/util/url.py | 432 + .../site-packages/urllib3/util/wait.py | 153 + venv/lib64 | 1 + venv/pyvenv.cfg | 3 + .../CacheControl-0.12.6-py2.py3-none-any.whl | Bin 0 -> 23290 bytes .../appdirs-1.4.4-py2.py3-none-any.whl | Bin 0 -> 14131 bytes .../certifi-2020.4.5.1-py2.py3-none-any.whl | Bin 0 -> 161630 bytes .../chardet-3.0.4-py2.py3-none-any.whl | Bin 0 -> 136755 bytes .../colorama-0.4.3-py2.py3-none-any.whl | Bin 0 -> 20362 bytes .../contextlib2-0.6.0-py2.py3-none-any.whl | Bin 0 -> 12457 bytes .../distlib-0.3.0-py2.py3-none-any.whl | Bin 0 -> 147296 bytes .../distro-1.5.0-py2.py3-none-any.whl | Bin 0 -> 19272 bytes .../html5lib-1.0.1-py2.py3-none-any.whl | Bin 0 -> 115285 bytes .../idna-2.9-py2.py3-none-any.whl | Bin 0 -> 62768 bytes .../ipaddr-2.2.0-py2.py3-none-any.whl | Bin 0 -> 19552 bytes .../lockfile-0.12.2-py2.py3-none-any.whl | Bin 0 -> 17238 bytes .../msgpack-0.6.2-py2.py3-none-any.whl | Bin 0 -> 88193 bytes .../packaging-20.3-py2.py3-none-any.whl | Bin 0 -> 37509 bytes .../pep517-0.8.2-py2.py3-none-any.whl | Bin 0 -> 21951 bytes .../pip-20.1.1-py2.py3-none-any.whl | Bin 0 -> 285469 bytes .../pkg_resources-0.0.0-py2.py3-none-any.whl | Bin 0 -> 122578 bytes .../progress-1.5-py2.py3-none-any.whl | Bin 0 -> 12812 bytes .../pyparsing-2.4.7-py2.py3-none-any.whl | Bin 0 -> 72474 bytes .../requests-2.23.0-py2.py3-none-any.whl | Bin 0 -> 63192 bytes .../resolvelib-0.3.0-py2.py3-none-any.whl | Bin 0 -> 15663 bytes .../retrying-1.3.3-py2.py3-none-any.whl | Bin 0 -> 11621 bytes .../setuptools-44.0.0-py2.py3-none-any.whl | Bin 0 -> 472710 bytes .../six-1.15.0-py2.py3-none-any.whl | Bin 0 -> 15549 bytes .../toml-0.10.1-py2.py3-none-any.whl | Bin 0 -> 20955 bytes .../urllib3-1.25.9-py2.py3-none-any.whl | Bin 0 -> 123228 bytes .../webencodings-0.5.1-py2.py3-none-any.whl | Bin 0 -> 15749 bytes .../wheel-0.34.2-py2.py3-none-any.whl | Bin 0 -> 30875 bytes 1410 files changed, 242633 insertions(+) create mode 100644 venv/bin/Activate.ps1 create mode 100644 venv/bin/activate create mode 100644 venv/bin/activate.csh create mode 100644 venv/bin/activate.fish create mode 100755 venv/bin/chardetect create mode 100755 venv/bin/easy_install create mode 100755 venv/bin/easy_install-3.8 create mode 100755 venv/bin/pip create mode 100755 venv/bin/pip3 create mode 100755 venv/bin/pip3.8 create mode 120000 venv/bin/python create mode 120000 venv/bin/python3 create mode 100644 venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/INSTALLER create mode 100644 venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/LICENSE.txt create mode 100644 venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/METADATA create mode 100644 venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/RECORD create mode 100644 venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/WHEEL create mode 100644 venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/entry_points.txt create mode 100644 venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/top_level.txt create mode 100644 venv/lib/python3.8/site-packages/apscheduler/__init__.py create mode 100644 venv/lib/python3.8/site-packages/apscheduler/events.py create mode 100644 venv/lib/python3.8/site-packages/apscheduler/executors/__init__.py create mode 100644 venv/lib/python3.8/site-packages/apscheduler/executors/asyncio.py create mode 100644 venv/lib/python3.8/site-packages/apscheduler/executors/base.py create mode 100644 venv/lib/python3.8/site-packages/apscheduler/executors/base_py3.py create mode 100644 venv/lib/python3.8/site-packages/apscheduler/executors/debug.py create mode 100644 venv/lib/python3.8/site-packages/apscheduler/executors/gevent.py create mode 100644 venv/lib/python3.8/site-packages/apscheduler/executors/pool.py create mode 100644 venv/lib/python3.8/site-packages/apscheduler/executors/tornado.py create mode 100644 venv/lib/python3.8/site-packages/apscheduler/executors/twisted.py create mode 100644 venv/lib/python3.8/site-packages/apscheduler/job.py create mode 100644 venv/lib/python3.8/site-packages/apscheduler/jobstores/__init__.py create mode 100644 venv/lib/python3.8/site-packages/apscheduler/jobstores/base.py create mode 100644 venv/lib/python3.8/site-packages/apscheduler/jobstores/memory.py create mode 100644 venv/lib/python3.8/site-packages/apscheduler/jobstores/mongodb.py create mode 100644 venv/lib/python3.8/site-packages/apscheduler/jobstores/redis.py create mode 100644 venv/lib/python3.8/site-packages/apscheduler/jobstores/rethinkdb.py create mode 100644 venv/lib/python3.8/site-packages/apscheduler/jobstores/sqlalchemy.py create mode 100644 venv/lib/python3.8/site-packages/apscheduler/jobstores/zookeeper.py create mode 100644 venv/lib/python3.8/site-packages/apscheduler/schedulers/__init__.py create mode 100644 venv/lib/python3.8/site-packages/apscheduler/schedulers/asyncio.py create mode 100644 venv/lib/python3.8/site-packages/apscheduler/schedulers/background.py create mode 100644 venv/lib/python3.8/site-packages/apscheduler/schedulers/base.py create mode 100644 venv/lib/python3.8/site-packages/apscheduler/schedulers/blocking.py create mode 100644 venv/lib/python3.8/site-packages/apscheduler/schedulers/gevent.py create mode 100644 venv/lib/python3.8/site-packages/apscheduler/schedulers/qt.py create mode 100644 venv/lib/python3.8/site-packages/apscheduler/schedulers/tornado.py create mode 100644 venv/lib/python3.8/site-packages/apscheduler/schedulers/twisted.py create mode 100644 venv/lib/python3.8/site-packages/apscheduler/triggers/__init__.py create mode 100644 venv/lib/python3.8/site-packages/apscheduler/triggers/base.py create mode 100644 venv/lib/python3.8/site-packages/apscheduler/triggers/combining.py create mode 100644 venv/lib/python3.8/site-packages/apscheduler/triggers/cron/__init__.py create mode 100644 venv/lib/python3.8/site-packages/apscheduler/triggers/cron/expressions.py create mode 100644 venv/lib/python3.8/site-packages/apscheduler/triggers/cron/fields.py create mode 100644 venv/lib/python3.8/site-packages/apscheduler/triggers/date.py create mode 100644 venv/lib/python3.8/site-packages/apscheduler/triggers/interval.py create mode 100644 venv/lib/python3.8/site-packages/apscheduler/util.py create mode 100644 venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/INSTALLER create mode 100644 venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/LICENSE create mode 100644 venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/METADATA create mode 100644 venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/RECORD create mode 100644 venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/WHEEL create mode 100644 venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/top_level.txt create mode 100644 venv/lib/python3.8/site-packages/cachetools/__init__.py create mode 100644 venv/lib/python3.8/site-packages/cachetools/cache.py create mode 100644 venv/lib/python3.8/site-packages/cachetools/decorators.py create mode 100644 venv/lib/python3.8/site-packages/cachetools/fifo.py create mode 100644 venv/lib/python3.8/site-packages/cachetools/func.py create mode 100644 venv/lib/python3.8/site-packages/cachetools/keys.py create mode 100644 venv/lib/python3.8/site-packages/cachetools/lfu.py create mode 100644 venv/lib/python3.8/site-packages/cachetools/lru.py create mode 100644 venv/lib/python3.8/site-packages/cachetools/mru.py create mode 100644 venv/lib/python3.8/site-packages/cachetools/rr.py create mode 100644 venv/lib/python3.8/site-packages/cachetools/ttl.py create mode 100644 venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/INSTALLER create mode 100644 venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/LICENSE create mode 100644 venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/METADATA create mode 100644 venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/RECORD create mode 100644 venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/WHEEL create mode 100644 venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/top_level.txt create mode 100644 venv/lib/python3.8/site-packages/certifi/__init__.py create mode 100644 venv/lib/python3.8/site-packages/certifi/__main__.py create mode 100644 venv/lib/python3.8/site-packages/certifi/cacert.pem create mode 100644 venv/lib/python3.8/site-packages/certifi/core.py create mode 100644 venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/INSTALLER create mode 100644 venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/LICENSE create mode 100644 venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/METADATA create mode 100644 venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/RECORD create mode 100644 venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/WHEEL create mode 100644 venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/entry_points.txt create mode 100644 venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/top_level.txt create mode 100644 venv/lib/python3.8/site-packages/chardet/__init__.py create mode 100644 venv/lib/python3.8/site-packages/chardet/big5freq.py create mode 100644 venv/lib/python3.8/site-packages/chardet/big5prober.py create mode 100644 venv/lib/python3.8/site-packages/chardet/chardistribution.py create mode 100644 venv/lib/python3.8/site-packages/chardet/charsetgroupprober.py create mode 100644 venv/lib/python3.8/site-packages/chardet/charsetprober.py create mode 100644 venv/lib/python3.8/site-packages/chardet/cli/__init__.py create mode 100644 venv/lib/python3.8/site-packages/chardet/cli/chardetect.py create mode 100644 venv/lib/python3.8/site-packages/chardet/codingstatemachine.py create mode 100644 venv/lib/python3.8/site-packages/chardet/compat.py create mode 100644 venv/lib/python3.8/site-packages/chardet/cp949prober.py create mode 100644 venv/lib/python3.8/site-packages/chardet/enums.py create mode 100644 venv/lib/python3.8/site-packages/chardet/escprober.py create mode 100644 venv/lib/python3.8/site-packages/chardet/escsm.py create mode 100644 venv/lib/python3.8/site-packages/chardet/eucjpprober.py create mode 100644 venv/lib/python3.8/site-packages/chardet/euckrfreq.py create mode 100644 venv/lib/python3.8/site-packages/chardet/euckrprober.py create mode 100644 venv/lib/python3.8/site-packages/chardet/euctwfreq.py create mode 100644 venv/lib/python3.8/site-packages/chardet/euctwprober.py create mode 100644 venv/lib/python3.8/site-packages/chardet/gb2312freq.py create mode 100644 venv/lib/python3.8/site-packages/chardet/gb2312prober.py create mode 100644 venv/lib/python3.8/site-packages/chardet/hebrewprober.py create mode 100644 venv/lib/python3.8/site-packages/chardet/jisfreq.py create mode 100644 venv/lib/python3.8/site-packages/chardet/jpcntx.py create mode 100644 venv/lib/python3.8/site-packages/chardet/langbulgarianmodel.py create mode 100644 venv/lib/python3.8/site-packages/chardet/langgreekmodel.py create mode 100644 venv/lib/python3.8/site-packages/chardet/langhebrewmodel.py create mode 100644 venv/lib/python3.8/site-packages/chardet/langhungarianmodel.py create mode 100644 venv/lib/python3.8/site-packages/chardet/langrussianmodel.py create mode 100644 venv/lib/python3.8/site-packages/chardet/langthaimodel.py create mode 100644 venv/lib/python3.8/site-packages/chardet/langturkishmodel.py create mode 100644 venv/lib/python3.8/site-packages/chardet/latin1prober.py create mode 100644 venv/lib/python3.8/site-packages/chardet/mbcharsetprober.py create mode 100644 venv/lib/python3.8/site-packages/chardet/mbcsgroupprober.py create mode 100644 venv/lib/python3.8/site-packages/chardet/mbcssm.py create mode 100644 venv/lib/python3.8/site-packages/chardet/metadata/__init__.py create mode 100644 venv/lib/python3.8/site-packages/chardet/metadata/languages.py create mode 100644 venv/lib/python3.8/site-packages/chardet/sbcharsetprober.py create mode 100644 venv/lib/python3.8/site-packages/chardet/sbcsgroupprober.py create mode 100644 venv/lib/python3.8/site-packages/chardet/sjisprober.py create mode 100644 venv/lib/python3.8/site-packages/chardet/universaldetector.py create mode 100644 venv/lib/python3.8/site-packages/chardet/utf8prober.py create mode 100644 venv/lib/python3.8/site-packages/chardet/version.py create mode 100644 venv/lib/python3.8/site-packages/easy_install.py create mode 100644 venv/lib/python3.8/site-packages/idna-2.10.dist-info/INSTALLER create mode 100644 venv/lib/python3.8/site-packages/idna-2.10.dist-info/LICENSE.rst create mode 100644 venv/lib/python3.8/site-packages/idna-2.10.dist-info/METADATA create mode 100644 venv/lib/python3.8/site-packages/idna-2.10.dist-info/RECORD create mode 100644 venv/lib/python3.8/site-packages/idna-2.10.dist-info/WHEEL create mode 100644 venv/lib/python3.8/site-packages/idna-2.10.dist-info/top_level.txt create mode 100644 venv/lib/python3.8/site-packages/idna/__init__.py create mode 100644 venv/lib/python3.8/site-packages/idna/codec.py create mode 100644 venv/lib/python3.8/site-packages/idna/compat.py create mode 100644 venv/lib/python3.8/site-packages/idna/core.py create mode 100644 venv/lib/python3.8/site-packages/idna/idnadata.py create mode 100644 venv/lib/python3.8/site-packages/idna/intranges.py create mode 100644 venv/lib/python3.8/site-packages/idna/package_data.py create mode 100644 venv/lib/python3.8/site-packages/idna/uts46data.py create mode 100644 venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/INSTALLER create mode 100644 venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/LICENSE.txt create mode 100644 venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/METADATA create mode 100644 venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/RECORD create mode 100644 venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/WHEEL create mode 100644 venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/entry_points.txt create mode 100644 venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/top_level.txt create mode 100644 venv/lib/python3.8/site-packages/pip/__init__.py create mode 100644 venv/lib/python3.8/site-packages/pip/__main__.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/__init__.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/build_env.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/cache.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/cli/__init__.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/cli/autocompletion.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/cli/base_command.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/cli/cmdoptions.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/cli/command_context.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/cli/main.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/cli/main_parser.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/cli/parser.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/cli/progress_bars.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/cli/req_command.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/cli/spinners.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/cli/status_codes.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/commands/__init__.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/commands/cache.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/commands/check.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/commands/completion.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/commands/configuration.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/commands/debug.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/commands/download.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/commands/freeze.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/commands/hash.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/commands/help.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/commands/install.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/commands/list.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/commands/search.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/commands/show.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/commands/uninstall.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/commands/wheel.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/configuration.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/distributions/__init__.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/distributions/base.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/distributions/installed.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/distributions/sdist.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/distributions/wheel.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/exceptions.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/index/__init__.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/index/collector.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/index/package_finder.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/locations.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/main.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/models/__init__.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/models/candidate.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/models/direct_url.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/models/format_control.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/models/index.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/models/link.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/models/scheme.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/models/search_scope.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/models/selection_prefs.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/models/target_python.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/models/wheel.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/network/__init__.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/network/auth.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/network/cache.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/network/download.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/network/session.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/network/utils.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/network/xmlrpc.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/operations/__init__.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/operations/build/__init__.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/operations/build/metadata.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/operations/build/metadata_legacy.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/operations/build/wheel.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/operations/build/wheel_legacy.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/operations/check.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/operations/freeze.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/operations/install/__init__.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/operations/install/editable_legacy.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/operations/install/legacy.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/operations/install/wheel.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/operations/prepare.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/pyproject.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/req/__init__.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/req/constructors.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/req/req_file.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/req/req_install.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/req/req_set.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/req/req_tracker.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/req/req_uninstall.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/resolution/__init__.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/resolution/base.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/resolution/legacy/__init__.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/resolution/legacy/resolver.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/__init__.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/base.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/candidates.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/factory.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/provider.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/requirements.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/resolver.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/self_outdated_check.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/__init__.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/appdirs.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/compat.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/compatibility_tags.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/deprecation.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/direct_url_helpers.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/distutils_args.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/encoding.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/entrypoints.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/filesystem.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/filetypes.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/glibc.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/hashes.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/inject_securetransport.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/logging.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/misc.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/models.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/packaging.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/pkg_resources.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/setuptools_build.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/subprocess.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/temp_dir.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/typing.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/unpacking.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/urls.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/virtualenv.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/wheel.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/vcs/__init__.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/vcs/bazaar.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/vcs/git.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/vcs/mercurial.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/vcs/subversion.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/vcs/versioncontrol.py create mode 100644 venv/lib/python3.8/site-packages/pip/_internal/wheel_builder.py create mode 100644 venv/lib/python3.8/site-packages/pip/_vendor/__init__.py create mode 100644 venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/AUTHORS.txt create mode 100644 venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/INSTALLER create mode 100644 venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/LICENSE.txt create mode 100644 venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/METADATA create mode 100644 venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/RECORD create mode 100644 venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/WHEEL create mode 100644 venv/lib/python3.8/site-packages/pkg_resources/__init__.py create mode 100644 venv/lib/python3.8/site-packages/pkg_resources/_vendor/__init__.py create mode 100644 venv/lib/python3.8/site-packages/pkg_resources/_vendor/appdirs.py create mode 100644 venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__about__.py create mode 100644 venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__init__.py create mode 100644 venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/_compat.py create mode 100644 venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/_structures.py create mode 100644 venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/markers.py create mode 100644 venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/requirements.py create mode 100644 venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/specifiers.py create mode 100644 venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/utils.py create mode 100644 venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/version.py create mode 100644 venv/lib/python3.8/site-packages/pkg_resources/_vendor/pyparsing.py create mode 100644 venv/lib/python3.8/site-packages/pkg_resources/_vendor/six.py create mode 100644 venv/lib/python3.8/site-packages/pkg_resources/extern/__init__.py create mode 100644 venv/lib/python3.8/site-packages/pkg_resources/py31compat.py create mode 100644 venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/INSTALLER create mode 100644 venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/LICENSE.dual create mode 100644 venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/METADATA create mode 100644 venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/RECORD create mode 100644 venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/WHEEL create mode 100644 venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/top_level.txt create mode 100644 venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/DESCRIPTION.rst create mode 100644 venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/INSTALLER create mode 100644 venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/LICENSE.txt create mode 100644 venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/METADATA create mode 100644 venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/RECORD create mode 100644 venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/WHEEL create mode 100644 venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/metadata.json create mode 100644 venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/top_level.txt create mode 100644 venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/zip-safe create mode 100644 venv/lib/python3.8/site-packages/pytz/__init__.py create mode 100644 venv/lib/python3.8/site-packages/pytz/exceptions.py create mode 100644 venv/lib/python3.8/site-packages/pytz/lazy.py create mode 100644 venv/lib/python3.8/site-packages/pytz/reference.py create mode 100644 venv/lib/python3.8/site-packages/pytz/tzfile.py create mode 100644 venv/lib/python3.8/site-packages/pytz/tzinfo.py create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Abidjan create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Accra create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Addis_Ababa create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Algiers create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Asmara create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Asmera create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Bamako create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Bangui create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Banjul create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Bissau create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Blantyre create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Brazzaville create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Bujumbura create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Cairo create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Casablanca create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Ceuta create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Conakry create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Dakar create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Dar_es_Salaam create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Djibouti create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Douala create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/El_Aaiun create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Freetown create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Gaborone create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Harare create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Johannesburg create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Juba create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Kampala create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Khartoum create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Kigali create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Kinshasa create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Lagos create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Libreville create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Lome create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Luanda create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Lubumbashi create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Lusaka create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Malabo create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Maputo create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Maseru create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Mbabane create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Mogadishu create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Monrovia create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Nairobi create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Ndjamena create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Niamey create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Nouakchott create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Ouagadougou create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Porto-Novo create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Sao_Tome create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Timbuktu create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Tripoli create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Tunis create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Windhoek create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Adak create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Anchorage create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Anguilla create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Antigua create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Araguaina create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Buenos_Aires create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Catamarca create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/ComodRivadavia create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Cordoba create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Jujuy create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/La_Rioja create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Mendoza create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Rio_Gallegos create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Salta create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/San_Juan create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/San_Luis create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Tucuman create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Ushuaia create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Aruba create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Asuncion create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Atikokan create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Atka create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Bahia create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Bahia_Banderas create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Barbados create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Belem create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Belize create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Blanc-Sablon create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Boa_Vista create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Bogota create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Boise create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Buenos_Aires create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Cambridge_Bay create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Campo_Grande create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Cancun create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Caracas create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Catamarca create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Cayenne create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Cayman create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Chicago create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Chihuahua create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Coral_Harbour create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Cordoba create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Costa_Rica create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Creston create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Cuiaba create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Curacao create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Danmarkshavn create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Dawson create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Dawson_Creek create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Denver create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Detroit create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Dominica create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Edmonton create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Eirunepe create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/El_Salvador create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Ensenada create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Fort_Nelson create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Fort_Wayne create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Fortaleza create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Glace_Bay create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Godthab create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Goose_Bay create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Grand_Turk create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Grenada create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Guadeloupe create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Guatemala create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Guayaquil create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Guyana create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Halifax create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Havana create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Hermosillo create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Indianapolis create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Knox create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Marengo create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Petersburg create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Tell_City create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Vevay create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Vincennes create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Winamac create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indianapolis create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Inuvik create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Iqaluit create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Jamaica create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Jujuy create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Juneau create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Kentucky/Louisville create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Kentucky/Monticello create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Knox_IN create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Kralendijk create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/La_Paz create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Lima create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Los_Angeles create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Louisville create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Lower_Princes create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Maceio create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Managua create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Manaus create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Marigot create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Martinique create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Matamoros create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Mazatlan create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Mendoza create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Menominee create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Merida create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Metlakatla create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Mexico_City create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Miquelon create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Moncton create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Monterrey create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Montevideo create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Montreal create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Montserrat create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Nassau create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/New_York create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Nipigon create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Nome create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Noronha create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/North_Dakota/Beulah create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/North_Dakota/Center create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/North_Dakota/New_Salem create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Nuuk create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Ojinaga create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Panama create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Pangnirtung create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Paramaribo create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Phoenix create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Port-au-Prince create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Port_of_Spain create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Porto_Acre create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Porto_Velho create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Puerto_Rico create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Punta_Arenas create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Rainy_River create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Rankin_Inlet create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Recife create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Regina create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Resolute create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Rio_Branco create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Rosario create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Santa_Isabel create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Santarem create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Santiago create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Santo_Domingo create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Sao_Paulo create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Scoresbysund create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Shiprock create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Sitka create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Barthelemy create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Johns create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Kitts create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Lucia create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Thomas create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Vincent create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Swift_Current create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Tegucigalpa create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Thule create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Thunder_Bay create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Tijuana create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Toronto create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Tortola create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Vancouver create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Virgin create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Whitehorse create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Winnipeg create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Yakutat create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Yellowknife create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Casey create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Davis create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/DumontDUrville create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Macquarie create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Mawson create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/McMurdo create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Palmer create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Rothera create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/South_Pole create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Syowa create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Troll create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Vostok create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Arctic/Longyearbyen create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Aden create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Almaty create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Amman create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Anadyr create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Aqtau create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Aqtobe create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ashgabat create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ashkhabad create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Atyrau create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Baghdad create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Bahrain create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Baku create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Bangkok create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Barnaul create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Beirut create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Bishkek create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Brunei create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Calcutta create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Chita create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Choibalsan create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Chongqing create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Chungking create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Colombo create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Dacca create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Damascus create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Dhaka create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Dili create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Dubai create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Dushanbe create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Famagusta create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Gaza create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Harbin create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Hebron create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ho_Chi_Minh create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Hong_Kong create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Hovd create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Irkutsk create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Istanbul create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Jakarta create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Jayapura create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Jerusalem create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kabul create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kamchatka create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Karachi create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kashgar create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kathmandu create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Katmandu create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Khandyga create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kolkata create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Krasnoyarsk create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kuala_Lumpur create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kuching create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kuwait create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Macao create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Macau create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Magadan create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Makassar create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Manila create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Muscat create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Nicosia create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Novokuznetsk create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Novosibirsk create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Omsk create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Oral create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Phnom_Penh create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Pontianak create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Pyongyang create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Qatar create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Qostanay create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Qyzylorda create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Rangoon create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Riyadh create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Saigon create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Sakhalin create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Samarkand create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Seoul create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Shanghai create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Singapore create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Srednekolymsk create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Taipei create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Tashkent create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Tbilisi create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Tehran create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Tel_Aviv create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Thimbu create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Thimphu create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Tokyo create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Tomsk create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ujung_Pandang create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ulaanbaatar create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ulan_Bator create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Urumqi create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ust-Nera create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Vientiane create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Vladivostok create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Yakutsk create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Yangon create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Yekaterinburg create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Yerevan create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Azores create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Bermuda create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Canary create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Cape_Verde create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Faeroe create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Faroe create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Jan_Mayen create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Madeira create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Reykjavik create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/South_Georgia create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/St_Helena create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Stanley create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/ACT create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Adelaide create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Brisbane create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Broken_Hill create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Canberra create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Currie create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Darwin create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Eucla create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Hobart create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/LHI create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Lindeman create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Lord_Howe create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Melbourne create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/NSW create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/North create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Perth create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Queensland create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/South create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Sydney create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Tasmania create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Victoria create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/West create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Yancowinna create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Brazil/Acre create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Brazil/DeNoronha create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Brazil/East create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Brazil/West create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/CET create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/CST6CDT create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Atlantic create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Central create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Eastern create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Mountain create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Newfoundland create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Pacific create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Saskatchewan create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Yukon create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Chile/Continental create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Chile/EasterIsland create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Cuba create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/EET create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/EST create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/EST5EDT create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Egypt create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Eire create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+0 create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+1 create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+10 create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+11 create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+12 create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+2 create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+3 create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+4 create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+5 create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+6 create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+7 create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+8 create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+9 create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-0 create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-1 create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-10 create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-11 create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-12 create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-13 create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-14 create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-2 create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-3 create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-4 create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-5 create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-6 create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-7 create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-8 create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-9 create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT0 create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/Greenwich create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/UCT create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/UTC create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/Universal create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/Zulu create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Amsterdam create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Andorra create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Astrakhan create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Athens create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Belfast create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Belgrade create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Berlin create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Bratislava create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Brussels create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Bucharest create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Budapest create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Busingen create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Chisinau create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Copenhagen create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Dublin create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Gibraltar create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Guernsey create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Helsinki create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Isle_of_Man create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Istanbul create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Jersey create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Kaliningrad create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Kiev create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Kirov create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Lisbon create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Ljubljana create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/London create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Luxembourg create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Madrid create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Malta create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Mariehamn create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Minsk create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Monaco create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Moscow create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Nicosia create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Oslo create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Paris create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Podgorica create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Prague create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Riga create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Rome create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Samara create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/San_Marino create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Sarajevo create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Saratov create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Simferopol create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Skopje create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Sofia create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Stockholm create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Tallinn create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Tirane create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Tiraspol create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Ulyanovsk create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Uzhgorod create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Vaduz create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Vatican create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Vienna create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Vilnius create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Volgograd create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Warsaw create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Zagreb create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Zaporozhye create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Zurich create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Factory create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/GB create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/GB-Eire create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/GMT create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/GMT+0 create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/GMT-0 create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/GMT0 create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Greenwich create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/HST create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Hongkong create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Iceland create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Antananarivo create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Chagos create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Christmas create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Cocos create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Comoro create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Kerguelen create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Mahe create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Maldives create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Mauritius create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Mayotte create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Reunion create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Iran create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Israel create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Jamaica create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Japan create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Kwajalein create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Libya create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/MET create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/MST create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/MST7MDT create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Mexico/BajaNorte create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Mexico/BajaSur create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Mexico/General create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/NZ create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/NZ-CHAT create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Navajo create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/PRC create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/PST8PDT create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Apia create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Auckland create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Bougainville create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Chatham create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Chuuk create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Easter create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Efate create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Enderbury create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Fakaofo create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Fiji create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Funafuti create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Galapagos create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Gambier create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Guadalcanal create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Guam create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Honolulu create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Johnston create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Kiritimati create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Kosrae create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Kwajalein create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Majuro create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Marquesas create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Midway create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Nauru create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Niue create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Norfolk create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Noumea create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Pago_Pago create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Palau create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Pitcairn create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Pohnpei create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Ponape create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Port_Moresby create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Rarotonga create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Saipan create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Samoa create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Tahiti create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Tarawa create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Tongatapu create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Truk create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Wake create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Wallis create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Yap create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Poland create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Portugal create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/ROC create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/ROK create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Singapore create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Turkey create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/UCT create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Alaska create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Aleutian create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Arizona create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Central create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/US/East-Indiana create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Eastern create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Hawaii create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Indiana-Starke create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Michigan create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Mountain create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Pacific create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Samoa create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/UTC create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Universal create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/W-SU create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/WET create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Zulu create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/iso3166.tab create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/leapseconds create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/tzdata.zi create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/zone.tab create mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/zone1970.tab create mode 100644 venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/INSTALLER create mode 100644 venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/LICENSE create mode 100644 venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/METADATA create mode 100644 venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/RECORD create mode 100644 venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/WHEEL create mode 100644 venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/top_level.txt create mode 100644 venv/lib/python3.8/site-packages/requests/__init__.py create mode 100644 venv/lib/python3.8/site-packages/requests/__version__.py create mode 100644 venv/lib/python3.8/site-packages/requests/_internal_utils.py create mode 100644 venv/lib/python3.8/site-packages/requests/adapters.py create mode 100644 venv/lib/python3.8/site-packages/requests/api.py create mode 100644 venv/lib/python3.8/site-packages/requests/auth.py create mode 100644 venv/lib/python3.8/site-packages/requests/certs.py create mode 100644 venv/lib/python3.8/site-packages/requests/compat.py create mode 100644 venv/lib/python3.8/site-packages/requests/cookies.py create mode 100644 venv/lib/python3.8/site-packages/requests/exceptions.py create mode 100644 venv/lib/python3.8/site-packages/requests/help.py create mode 100644 venv/lib/python3.8/site-packages/requests/hooks.py create mode 100644 venv/lib/python3.8/site-packages/requests/models.py create mode 100644 venv/lib/python3.8/site-packages/requests/packages.py create mode 100644 venv/lib/python3.8/site-packages/requests/sessions.py create mode 100644 venv/lib/python3.8/site-packages/requests/status_codes.py create mode 100644 venv/lib/python3.8/site-packages/requests/structures.py create mode 100644 venv/lib/python3.8/site-packages/requests/utils.py create mode 100644 venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/AUTHORS.txt create mode 100644 venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/INSTALLER create mode 100644 venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/LICENSE.txt create mode 100644 venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/METADATA create mode 100644 venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/RECORD create mode 100644 venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/WHEEL create mode 100644 venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/dependency_links.txt create mode 100644 venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/entry_points.txt create mode 100644 venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/top_level.txt create mode 100644 venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/zip-safe create mode 100644 venv/lib/python3.8/site-packages/setuptools/__init__.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/_deprecation_warning.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/_imp.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/_vendor/__init__.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/_vendor/ordered_set.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__about__.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__init__.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/_compat.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/_structures.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/markers.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/requirements.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/specifiers.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/tags.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/utils.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/version.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/_vendor/pyparsing.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/_vendor/six.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/archive_util.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/build_meta.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/cli-32.exe create mode 100644 venv/lib/python3.8/site-packages/setuptools/cli-64.exe create mode 100644 venv/lib/python3.8/site-packages/setuptools/cli.exe create mode 100644 venv/lib/python3.8/site-packages/setuptools/command/__init__.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/command/alias.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/command/bdist_egg.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/command/bdist_rpm.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/command/bdist_wininst.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/command/build_clib.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/command/build_ext.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/command/build_py.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/command/develop.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/command/dist_info.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/command/easy_install.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/command/egg_info.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/command/install.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/command/install_egg_info.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/command/install_lib.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/command/install_scripts.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/command/launcher manifest.xml create mode 100644 venv/lib/python3.8/site-packages/setuptools/command/py36compat.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/command/register.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/command/rotate.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/command/saveopts.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/command/sdist.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/command/setopt.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/command/test.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/command/upload.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/command/upload_docs.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/config.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/dep_util.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/depends.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/dist.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/errors.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/extension.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/extern/__init__.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/glob.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/gui-32.exe create mode 100644 venv/lib/python3.8/site-packages/setuptools/gui-64.exe create mode 100644 venv/lib/python3.8/site-packages/setuptools/gui.exe create mode 100644 venv/lib/python3.8/site-packages/setuptools/installer.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/launch.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/lib2to3_ex.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/monkey.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/msvc.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/namespaces.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/package_index.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/py27compat.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/py31compat.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/py33compat.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/py34compat.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/sandbox.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/script (dev).tmpl create mode 100644 venv/lib/python3.8/site-packages/setuptools/script.tmpl create mode 100644 venv/lib/python3.8/site-packages/setuptools/site-patch.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/ssl_support.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/unicode_utils.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/version.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/wheel.py create mode 100644 venv/lib/python3.8/site-packages/setuptools/windows_support.py create mode 100644 venv/lib/python3.8/site-packages/six-1.16.0.dist-info/INSTALLER create mode 100644 venv/lib/python3.8/site-packages/six-1.16.0.dist-info/LICENSE create mode 100644 venv/lib/python3.8/site-packages/six-1.16.0.dist-info/METADATA create mode 100644 venv/lib/python3.8/site-packages/six-1.16.0.dist-info/RECORD create mode 100644 venv/lib/python3.8/site-packages/six-1.16.0.dist-info/WHEEL create mode 100644 venv/lib/python3.8/site-packages/six-1.16.0.dist-info/top_level.txt create mode 100644 venv/lib/python3.8/site-packages/six.py create mode 100644 venv/lib/python3.8/site-packages/telegram/__init__.py create mode 100644 venv/lib/python3.8/site-packages/telegram/__main__.py create mode 100644 venv/lib/python3.8/site-packages/telegram/base.py create mode 100644 venv/lib/python3.8/site-packages/telegram/bot.py create mode 100644 venv/lib/python3.8/site-packages/telegram/botcommand.py create mode 100644 venv/lib/python3.8/site-packages/telegram/callbackquery.py create mode 100644 venv/lib/python3.8/site-packages/telegram/chat.py create mode 100644 venv/lib/python3.8/site-packages/telegram/chataction.py create mode 100644 venv/lib/python3.8/site-packages/telegram/chatinvitelink.py create mode 100644 venv/lib/python3.8/site-packages/telegram/chatlocation.py create mode 100644 venv/lib/python3.8/site-packages/telegram/chatmember.py create mode 100644 venv/lib/python3.8/site-packages/telegram/chatmemberupdated.py create mode 100644 venv/lib/python3.8/site-packages/telegram/chatpermissions.py create mode 100644 venv/lib/python3.8/site-packages/telegram/choseninlineresult.py create mode 100644 venv/lib/python3.8/site-packages/telegram/constants.py create mode 100644 venv/lib/python3.8/site-packages/telegram/dice.py create mode 100644 venv/lib/python3.8/site-packages/telegram/error.py create mode 100644 venv/lib/python3.8/site-packages/telegram/ext/__init__.py create mode 100644 venv/lib/python3.8/site-packages/telegram/ext/basepersistence.py create mode 100644 venv/lib/python3.8/site-packages/telegram/ext/callbackcontext.py create mode 100644 venv/lib/python3.8/site-packages/telegram/ext/callbackdatacache.py create mode 100644 venv/lib/python3.8/site-packages/telegram/ext/callbackqueryhandler.py create mode 100644 venv/lib/python3.8/site-packages/telegram/ext/chatmemberhandler.py create mode 100644 venv/lib/python3.8/site-packages/telegram/ext/choseninlineresulthandler.py create mode 100644 venv/lib/python3.8/site-packages/telegram/ext/commandhandler.py create mode 100644 venv/lib/python3.8/site-packages/telegram/ext/contexttypes.py create mode 100644 venv/lib/python3.8/site-packages/telegram/ext/conversationhandler.py create mode 100644 venv/lib/python3.8/site-packages/telegram/ext/defaults.py create mode 100644 venv/lib/python3.8/site-packages/telegram/ext/dictpersistence.py create mode 100644 venv/lib/python3.8/site-packages/telegram/ext/dispatcher.py create mode 100644 venv/lib/python3.8/site-packages/telegram/ext/extbot.py create mode 100644 venv/lib/python3.8/site-packages/telegram/ext/filters.py create mode 100644 venv/lib/python3.8/site-packages/telegram/ext/handler.py create mode 100644 venv/lib/python3.8/site-packages/telegram/ext/inlinequeryhandler.py create mode 100644 venv/lib/python3.8/site-packages/telegram/ext/jobqueue.py create mode 100644 venv/lib/python3.8/site-packages/telegram/ext/messagehandler.py create mode 100644 venv/lib/python3.8/site-packages/telegram/ext/messagequeue.py create mode 100644 venv/lib/python3.8/site-packages/telegram/ext/picklepersistence.py create mode 100644 venv/lib/python3.8/site-packages/telegram/ext/pollanswerhandler.py create mode 100644 venv/lib/python3.8/site-packages/telegram/ext/pollhandler.py create mode 100644 venv/lib/python3.8/site-packages/telegram/ext/precheckoutqueryhandler.py create mode 100644 venv/lib/python3.8/site-packages/telegram/ext/regexhandler.py create mode 100644 venv/lib/python3.8/site-packages/telegram/ext/shippingqueryhandler.py create mode 100644 venv/lib/python3.8/site-packages/telegram/ext/stringcommandhandler.py create mode 100644 venv/lib/python3.8/site-packages/telegram/ext/stringregexhandler.py create mode 100644 venv/lib/python3.8/site-packages/telegram/ext/typehandler.py create mode 100644 venv/lib/python3.8/site-packages/telegram/ext/updater.py create mode 100644 venv/lib/python3.8/site-packages/telegram/ext/utils/__init__.py create mode 100644 venv/lib/python3.8/site-packages/telegram/ext/utils/promise.py create mode 100644 venv/lib/python3.8/site-packages/telegram/ext/utils/types.py create mode 100644 venv/lib/python3.8/site-packages/telegram/ext/utils/webhookhandler.py create mode 100644 venv/lib/python3.8/site-packages/telegram/files/__init__.py create mode 100644 venv/lib/python3.8/site-packages/telegram/files/animation.py create mode 100644 venv/lib/python3.8/site-packages/telegram/files/audio.py create mode 100644 venv/lib/python3.8/site-packages/telegram/files/chatphoto.py create mode 100644 venv/lib/python3.8/site-packages/telegram/files/contact.py create mode 100644 venv/lib/python3.8/site-packages/telegram/files/document.py create mode 100644 venv/lib/python3.8/site-packages/telegram/files/file.py create mode 100644 venv/lib/python3.8/site-packages/telegram/files/inputfile.py create mode 100644 venv/lib/python3.8/site-packages/telegram/files/inputmedia.py create mode 100644 venv/lib/python3.8/site-packages/telegram/files/location.py create mode 100644 venv/lib/python3.8/site-packages/telegram/files/photosize.py create mode 100644 venv/lib/python3.8/site-packages/telegram/files/sticker.py create mode 100644 venv/lib/python3.8/site-packages/telegram/files/venue.py create mode 100644 venv/lib/python3.8/site-packages/telegram/files/video.py create mode 100644 venv/lib/python3.8/site-packages/telegram/files/videonote.py create mode 100644 venv/lib/python3.8/site-packages/telegram/files/voice.py create mode 100644 venv/lib/python3.8/site-packages/telegram/forcereply.py create mode 100644 venv/lib/python3.8/site-packages/telegram/games/__init__.py create mode 100644 venv/lib/python3.8/site-packages/telegram/games/callbackgame.py create mode 100644 venv/lib/python3.8/site-packages/telegram/games/game.py create mode 100644 venv/lib/python3.8/site-packages/telegram/games/gamehighscore.py create mode 100644 venv/lib/python3.8/site-packages/telegram/inline/__init__.py create mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinekeyboardbutton.py create mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinekeyboardmarkup.py create mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequery.py create mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresult.py create mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultarticle.py create mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultaudio.py create mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedaudio.py create mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcacheddocument.py create mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedgif.py create mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedmpeg4gif.py create mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedphoto.py create mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedsticker.py create mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedvideo.py create mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedvoice.py create mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcontact.py create mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultdocument.py create mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultgame.py create mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultgif.py create mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultlocation.py create mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultmpeg4gif.py create mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultphoto.py create mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultvenue.py create mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultvideo.py create mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultvoice.py create mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inputcontactmessagecontent.py create mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inputinvoicemessagecontent.py create mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inputlocationmessagecontent.py create mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inputmessagecontent.py create mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inputtextmessagecontent.py create mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inputvenuemessagecontent.py create mode 100644 venv/lib/python3.8/site-packages/telegram/keyboardbutton.py create mode 100644 venv/lib/python3.8/site-packages/telegram/keyboardbuttonpolltype.py create mode 100644 venv/lib/python3.8/site-packages/telegram/loginurl.py create mode 100644 venv/lib/python3.8/site-packages/telegram/message.py create mode 100644 venv/lib/python3.8/site-packages/telegram/messageautodeletetimerchanged.py create mode 100644 venv/lib/python3.8/site-packages/telegram/messageentity.py create mode 100644 venv/lib/python3.8/site-packages/telegram/messageid.py create mode 100644 venv/lib/python3.8/site-packages/telegram/parsemode.py create mode 100644 venv/lib/python3.8/site-packages/telegram/passport/__init__.py create mode 100644 venv/lib/python3.8/site-packages/telegram/passport/credentials.py create mode 100644 venv/lib/python3.8/site-packages/telegram/passport/data.py create mode 100644 venv/lib/python3.8/site-packages/telegram/passport/encryptedpassportelement.py create mode 100644 venv/lib/python3.8/site-packages/telegram/passport/passportdata.py create mode 100644 venv/lib/python3.8/site-packages/telegram/passport/passportelementerrors.py create mode 100644 venv/lib/python3.8/site-packages/telegram/passport/passportfile.py create mode 100644 venv/lib/python3.8/site-packages/telegram/payment/__init__.py create mode 100644 venv/lib/python3.8/site-packages/telegram/payment/invoice.py create mode 100644 venv/lib/python3.8/site-packages/telegram/payment/labeledprice.py create mode 100644 venv/lib/python3.8/site-packages/telegram/payment/orderinfo.py create mode 100644 venv/lib/python3.8/site-packages/telegram/payment/precheckoutquery.py create mode 100644 venv/lib/python3.8/site-packages/telegram/payment/shippingaddress.py create mode 100644 venv/lib/python3.8/site-packages/telegram/payment/shippingoption.py create mode 100644 venv/lib/python3.8/site-packages/telegram/payment/shippingquery.py create mode 100644 venv/lib/python3.8/site-packages/telegram/payment/successfulpayment.py create mode 100644 venv/lib/python3.8/site-packages/telegram/poll.py create mode 100644 venv/lib/python3.8/site-packages/telegram/proximityalerttriggered.py create mode 100644 venv/lib/python3.8/site-packages/telegram/py.typed create mode 100644 venv/lib/python3.8/site-packages/telegram/replykeyboardmarkup.py create mode 100644 venv/lib/python3.8/site-packages/telegram/replykeyboardremove.py create mode 100644 venv/lib/python3.8/site-packages/telegram/replymarkup.py create mode 100644 venv/lib/python3.8/site-packages/telegram/update.py create mode 100644 venv/lib/python3.8/site-packages/telegram/user.py create mode 100644 venv/lib/python3.8/site-packages/telegram/userprofilephotos.py create mode 100644 venv/lib/python3.8/site-packages/telegram/utils/__init__.py create mode 100644 venv/lib/python3.8/site-packages/telegram/utils/deprecate.py create mode 100644 venv/lib/python3.8/site-packages/telegram/utils/helpers.py create mode 100644 venv/lib/python3.8/site-packages/telegram/utils/promise.py create mode 100644 venv/lib/python3.8/site-packages/telegram/utils/request.py create mode 100644 venv/lib/python3.8/site-packages/telegram/utils/types.py create mode 100644 venv/lib/python3.8/site-packages/telegram/utils/webhookhandler.py create mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/__init__.py create mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/__init__.py create mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/__init__.py create mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/_collections.py create mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/connection.py create mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/connectionpool.py create mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/contrib/__init__.py create mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/contrib/appengine.py create mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/contrib/ntlmpool.py create mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/contrib/pyopenssl.py create mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/contrib/socks.py create mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/exceptions.py create mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/fields.py create mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/filepost.py create mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/__init__.py create mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/backports/__init__.py create mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/backports/makefile.py create mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/ordered_dict.py create mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/six.py create mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/ssl_match_hostname/__init__.py create mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/ssl_match_hostname/_implementation.py create mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/poolmanager.py create mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/request.py create mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/response.py create mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/__init__.py create mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/connection.py create mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/request.py create mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/response.py create mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/retry.py create mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/selectors.py create mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/ssl_.py create mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/timeout.py create mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/url.py create mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/wait.py create mode 100644 venv/lib/python3.8/site-packages/telegram/version.py create mode 100644 venv/lib/python3.8/site-packages/telegram/voicechat.py create mode 100644 venv/lib/python3.8/site-packages/telegram/webhookinfo.py create mode 100644 venv/lib/python3.8/site-packages/tornado-6.1.dist-info/INSTALLER create mode 100644 venv/lib/python3.8/site-packages/tornado-6.1.dist-info/LICENSE create mode 100644 venv/lib/python3.8/site-packages/tornado-6.1.dist-info/METADATA create mode 100644 venv/lib/python3.8/site-packages/tornado-6.1.dist-info/RECORD create mode 100644 venv/lib/python3.8/site-packages/tornado-6.1.dist-info/WHEEL create mode 100644 venv/lib/python3.8/site-packages/tornado-6.1.dist-info/top_level.txt create mode 100644 venv/lib/python3.8/site-packages/tornado/__init__.py create mode 100644 venv/lib/python3.8/site-packages/tornado/_locale_data.py create mode 100644 venv/lib/python3.8/site-packages/tornado/auth.py create mode 100644 venv/lib/python3.8/site-packages/tornado/autoreload.py create mode 100644 venv/lib/python3.8/site-packages/tornado/concurrent.py create mode 100644 venv/lib/python3.8/site-packages/tornado/curl_httpclient.py create mode 100644 venv/lib/python3.8/site-packages/tornado/escape.py create mode 100644 venv/lib/python3.8/site-packages/tornado/gen.py create mode 100644 venv/lib/python3.8/site-packages/tornado/http1connection.py create mode 100644 venv/lib/python3.8/site-packages/tornado/httpclient.py create mode 100644 venv/lib/python3.8/site-packages/tornado/httpserver.py create mode 100644 venv/lib/python3.8/site-packages/tornado/httputil.py create mode 100644 venv/lib/python3.8/site-packages/tornado/ioloop.py create mode 100644 venv/lib/python3.8/site-packages/tornado/iostream.py create mode 100644 venv/lib/python3.8/site-packages/tornado/locale.py create mode 100644 venv/lib/python3.8/site-packages/tornado/locks.py create mode 100644 venv/lib/python3.8/site-packages/tornado/log.py create mode 100644 venv/lib/python3.8/site-packages/tornado/netutil.py create mode 100644 venv/lib/python3.8/site-packages/tornado/options.py create mode 100644 venv/lib/python3.8/site-packages/tornado/platform/__init__.py create mode 100644 venv/lib/python3.8/site-packages/tornado/platform/asyncio.py create mode 100644 venv/lib/python3.8/site-packages/tornado/platform/caresresolver.py create mode 100644 venv/lib/python3.8/site-packages/tornado/platform/twisted.py create mode 100644 venv/lib/python3.8/site-packages/tornado/process.py create mode 100644 venv/lib/python3.8/site-packages/tornado/py.typed create mode 100644 venv/lib/python3.8/site-packages/tornado/queues.py create mode 100644 venv/lib/python3.8/site-packages/tornado/routing.py create mode 100644 venv/lib/python3.8/site-packages/tornado/simple_httpclient.py create mode 100755 venv/lib/python3.8/site-packages/tornado/speedups.cpython-38-x86_64-linux-gnu.so create mode 100644 venv/lib/python3.8/site-packages/tornado/tcpclient.py create mode 100644 venv/lib/python3.8/site-packages/tornado/tcpserver.py create mode 100644 venv/lib/python3.8/site-packages/tornado/template.py create mode 100644 venv/lib/python3.8/site-packages/tornado/test/__main__.py create mode 100644 venv/lib/python3.8/site-packages/tornado/test/asyncio_test.py create mode 100644 venv/lib/python3.8/site-packages/tornado/test/auth_test.py create mode 100644 venv/lib/python3.8/site-packages/tornado/test/autoreload_test.py create mode 100644 venv/lib/python3.8/site-packages/tornado/test/concurrent_test.py create mode 100644 venv/lib/python3.8/site-packages/tornado/test/csv_translations/fr_FR.csv create mode 100644 venv/lib/python3.8/site-packages/tornado/test/curl_httpclient_test.py create mode 100644 venv/lib/python3.8/site-packages/tornado/test/escape_test.py create mode 100644 venv/lib/python3.8/site-packages/tornado/test/gen_test.py create mode 100644 venv/lib/python3.8/site-packages/tornado/test/gettext_translations/fr_FR/LC_MESSAGES/tornado_test.mo create mode 100644 venv/lib/python3.8/site-packages/tornado/test/gettext_translations/fr_FR/LC_MESSAGES/tornado_test.po create mode 100644 venv/lib/python3.8/site-packages/tornado/test/http1connection_test.py create mode 100644 venv/lib/python3.8/site-packages/tornado/test/httpclient_test.py create mode 100644 venv/lib/python3.8/site-packages/tornado/test/httpserver_test.py create mode 100644 venv/lib/python3.8/site-packages/tornado/test/httputil_test.py create mode 100644 venv/lib/python3.8/site-packages/tornado/test/import_test.py create mode 100644 venv/lib/python3.8/site-packages/tornado/test/ioloop_test.py create mode 100644 venv/lib/python3.8/site-packages/tornado/test/iostream_test.py create mode 100644 venv/lib/python3.8/site-packages/tornado/test/locale_test.py create mode 100644 venv/lib/python3.8/site-packages/tornado/test/locks_test.py create mode 100644 venv/lib/python3.8/site-packages/tornado/test/log_test.py create mode 100644 venv/lib/python3.8/site-packages/tornado/test/netutil_test.py create mode 100644 venv/lib/python3.8/site-packages/tornado/test/options_test.cfg create mode 100644 venv/lib/python3.8/site-packages/tornado/test/options_test.py create mode 100644 venv/lib/python3.8/site-packages/tornado/test/options_test_types.cfg create mode 100644 venv/lib/python3.8/site-packages/tornado/test/options_test_types_str.cfg create mode 100644 venv/lib/python3.8/site-packages/tornado/test/process_test.py create mode 100644 venv/lib/python3.8/site-packages/tornado/test/queues_test.py create mode 100644 venv/lib/python3.8/site-packages/tornado/test/resolve_test_helper.py create mode 100644 venv/lib/python3.8/site-packages/tornado/test/routing_test.py create mode 100644 venv/lib/python3.8/site-packages/tornado/test/runtests.py create mode 100644 venv/lib/python3.8/site-packages/tornado/test/simple_httpclient_test.py create mode 100644 venv/lib/python3.8/site-packages/tornado/test/static/dir/index.html create mode 100644 venv/lib/python3.8/site-packages/tornado/test/static/robots.txt create mode 100644 venv/lib/python3.8/site-packages/tornado/test/static/sample.xml create mode 100644 venv/lib/python3.8/site-packages/tornado/test/static/sample.xml.bz2 create mode 100644 venv/lib/python3.8/site-packages/tornado/test/static/sample.xml.gz create mode 100644 venv/lib/python3.8/site-packages/tornado/test/static_foo.txt create mode 100644 venv/lib/python3.8/site-packages/tornado/test/tcpclient_test.py create mode 100644 venv/lib/python3.8/site-packages/tornado/test/tcpserver_test.py create mode 100644 venv/lib/python3.8/site-packages/tornado/test/template_test.py create mode 100644 venv/lib/python3.8/site-packages/tornado/test/templates/utf8.html create mode 100644 venv/lib/python3.8/site-packages/tornado/test/test.crt create mode 100644 venv/lib/python3.8/site-packages/tornado/test/test.key create mode 100644 venv/lib/python3.8/site-packages/tornado/test/testing_test.py create mode 100644 venv/lib/python3.8/site-packages/tornado/test/twisted_test.py create mode 100644 venv/lib/python3.8/site-packages/tornado/test/util.py create mode 100644 venv/lib/python3.8/site-packages/tornado/test/util_test.py create mode 100644 venv/lib/python3.8/site-packages/tornado/test/web_test.py create mode 100644 venv/lib/python3.8/site-packages/tornado/test/websocket_test.py create mode 100644 venv/lib/python3.8/site-packages/tornado/test/wsgi_test.py create mode 100644 venv/lib/python3.8/site-packages/tornado/testing.py create mode 100644 venv/lib/python3.8/site-packages/tornado/util.py create mode 100644 venv/lib/python3.8/site-packages/tornado/web.py create mode 100644 venv/lib/python3.8/site-packages/tornado/websocket.py create mode 100644 venv/lib/python3.8/site-packages/tornado/wsgi.py create mode 100644 venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/INSTALLER create mode 100644 venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/LICENSE.txt create mode 100644 venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/METADATA create mode 100644 venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/RECORD create mode 100644 venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/WHEEL create mode 100644 venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/top_level.txt create mode 100644 venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/zip-safe create mode 100644 venv/lib/python3.8/site-packages/tzlocal/__init__.py create mode 100644 venv/lib/python3.8/site-packages/tzlocal/unix.py create mode 100644 venv/lib/python3.8/site-packages/tzlocal/utils.py create mode 100644 venv/lib/python3.8/site-packages/tzlocal/win32.py create mode 100644 venv/lib/python3.8/site-packages/tzlocal/windows_tz.py create mode 100644 venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/INSTALLER create mode 100644 venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/LICENSE.txt create mode 100644 venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/METADATA create mode 100644 venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/RECORD create mode 100644 venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/WHEEL create mode 100644 venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/top_level.txt create mode 100644 venv/lib/python3.8/site-packages/urllib3/__init__.py create mode 100644 venv/lib/python3.8/site-packages/urllib3/_collections.py create mode 100644 venv/lib/python3.8/site-packages/urllib3/_version.py create mode 100644 venv/lib/python3.8/site-packages/urllib3/connection.py create mode 100644 venv/lib/python3.8/site-packages/urllib3/connectionpool.py create mode 100644 venv/lib/python3.8/site-packages/urllib3/contrib/__init__.py create mode 100644 venv/lib/python3.8/site-packages/urllib3/contrib/_appengine_environ.py create mode 100644 venv/lib/python3.8/site-packages/urllib3/contrib/_securetransport/__init__.py create mode 100644 venv/lib/python3.8/site-packages/urllib3/contrib/_securetransport/bindings.py create mode 100644 venv/lib/python3.8/site-packages/urllib3/contrib/_securetransport/low_level.py create mode 100644 venv/lib/python3.8/site-packages/urllib3/contrib/appengine.py create mode 100644 venv/lib/python3.8/site-packages/urllib3/contrib/ntlmpool.py create mode 100644 venv/lib/python3.8/site-packages/urllib3/contrib/pyopenssl.py create mode 100644 venv/lib/python3.8/site-packages/urllib3/contrib/securetransport.py create mode 100644 venv/lib/python3.8/site-packages/urllib3/contrib/socks.py create mode 100644 venv/lib/python3.8/site-packages/urllib3/exceptions.py create mode 100644 venv/lib/python3.8/site-packages/urllib3/fields.py create mode 100644 venv/lib/python3.8/site-packages/urllib3/filepost.py create mode 100644 venv/lib/python3.8/site-packages/urllib3/packages/__init__.py create mode 100644 venv/lib/python3.8/site-packages/urllib3/packages/backports/__init__.py create mode 100644 venv/lib/python3.8/site-packages/urllib3/packages/backports/makefile.py create mode 100644 venv/lib/python3.8/site-packages/urllib3/packages/six.py create mode 100644 venv/lib/python3.8/site-packages/urllib3/packages/ssl_match_hostname/__init__.py create mode 100644 venv/lib/python3.8/site-packages/urllib3/packages/ssl_match_hostname/_implementation.py create mode 100644 venv/lib/python3.8/site-packages/urllib3/poolmanager.py create mode 100644 venv/lib/python3.8/site-packages/urllib3/request.py create mode 100644 venv/lib/python3.8/site-packages/urllib3/response.py create mode 100644 venv/lib/python3.8/site-packages/urllib3/util/__init__.py create mode 100644 venv/lib/python3.8/site-packages/urllib3/util/connection.py create mode 100644 venv/lib/python3.8/site-packages/urllib3/util/proxy.py create mode 100644 venv/lib/python3.8/site-packages/urllib3/util/queue.py create mode 100644 venv/lib/python3.8/site-packages/urllib3/util/request.py create mode 100644 venv/lib/python3.8/site-packages/urllib3/util/response.py create mode 100644 venv/lib/python3.8/site-packages/urllib3/util/retry.py create mode 100644 venv/lib/python3.8/site-packages/urllib3/util/ssl_.py create mode 100644 venv/lib/python3.8/site-packages/urllib3/util/ssltransport.py create mode 100644 venv/lib/python3.8/site-packages/urllib3/util/timeout.py create mode 100644 venv/lib/python3.8/site-packages/urllib3/util/url.py create mode 100644 venv/lib/python3.8/site-packages/urllib3/util/wait.py create mode 120000 venv/lib64 create mode 100644 venv/pyvenv.cfg create mode 100644 venv/share/python-wheels/CacheControl-0.12.6-py2.py3-none-any.whl create mode 100644 venv/share/python-wheels/appdirs-1.4.4-py2.py3-none-any.whl create mode 100644 venv/share/python-wheels/certifi-2020.4.5.1-py2.py3-none-any.whl create mode 100644 venv/share/python-wheels/chardet-3.0.4-py2.py3-none-any.whl create mode 100644 venv/share/python-wheels/colorama-0.4.3-py2.py3-none-any.whl create mode 100644 venv/share/python-wheels/contextlib2-0.6.0-py2.py3-none-any.whl create mode 100644 venv/share/python-wheels/distlib-0.3.0-py2.py3-none-any.whl create mode 100644 venv/share/python-wheels/distro-1.5.0-py2.py3-none-any.whl create mode 100644 venv/share/python-wheels/html5lib-1.0.1-py2.py3-none-any.whl create mode 100644 venv/share/python-wheels/idna-2.9-py2.py3-none-any.whl create mode 100644 venv/share/python-wheels/ipaddr-2.2.0-py2.py3-none-any.whl create mode 100644 venv/share/python-wheels/lockfile-0.12.2-py2.py3-none-any.whl create mode 100644 venv/share/python-wheels/msgpack-0.6.2-py2.py3-none-any.whl create mode 100644 venv/share/python-wheels/packaging-20.3-py2.py3-none-any.whl create mode 100644 venv/share/python-wheels/pep517-0.8.2-py2.py3-none-any.whl create mode 100644 venv/share/python-wheels/pip-20.1.1-py2.py3-none-any.whl create mode 100644 venv/share/python-wheels/pkg_resources-0.0.0-py2.py3-none-any.whl create mode 100644 venv/share/python-wheels/progress-1.5-py2.py3-none-any.whl create mode 100644 venv/share/python-wheels/pyparsing-2.4.7-py2.py3-none-any.whl create mode 100644 venv/share/python-wheels/requests-2.23.0-py2.py3-none-any.whl create mode 100644 venv/share/python-wheels/resolvelib-0.3.0-py2.py3-none-any.whl create mode 100644 venv/share/python-wheels/retrying-1.3.3-py2.py3-none-any.whl create mode 100644 venv/share/python-wheels/setuptools-44.0.0-py2.py3-none-any.whl create mode 100644 venv/share/python-wheels/six-1.15.0-py2.py3-none-any.whl create mode 100644 venv/share/python-wheels/toml-0.10.1-py2.py3-none-any.whl create mode 100644 venv/share/python-wheels/urllib3-1.25.9-py2.py3-none-any.whl create mode 100644 venv/share/python-wheels/webencodings-0.5.1-py2.py3-none-any.whl create mode 100644 venv/share/python-wheels/wheel-0.34.2-py2.py3-none-any.whl diff --git a/venv/bin/Activate.ps1 b/venv/bin/Activate.ps1 new file mode 100644 index 0000000..2fb3852 --- /dev/null +++ b/venv/bin/Activate.ps1 @@ -0,0 +1,241 @@ +<# +.Synopsis +Activate a Python virtual environment for the current PowerShell session. + +.Description +Pushes the python executable for a virtual environment to the front of the +$Env:PATH environment variable and sets the prompt to signify that you are +in a Python virtual environment. Makes use of the command line switches as +well as the `pyvenv.cfg` file values present in the virtual environment. + +.Parameter VenvDir +Path to the directory that contains the virtual environment to activate. The +default value for this is the parent of the directory that the Activate.ps1 +script is located within. + +.Parameter Prompt +The prompt prefix to display when this virtual environment is activated. By +default, this prompt is the name of the virtual environment folder (VenvDir) +surrounded by parentheses and followed by a single space (ie. '(.venv) '). + +.Example +Activate.ps1 +Activates the Python virtual environment that contains the Activate.ps1 script. + +.Example +Activate.ps1 -Verbose +Activates the Python virtual environment that contains the Activate.ps1 script, +and shows extra information about the activation as it executes. + +.Example +Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv +Activates the Python virtual environment located in the specified location. + +.Example +Activate.ps1 -Prompt "MyPython" +Activates the Python virtual environment that contains the Activate.ps1 script, +and prefixes the current prompt with the specified string (surrounded in +parentheses) while the virtual environment is active. + +.Notes +On Windows, it may be required to enable this Activate.ps1 script by setting the +execution policy for the user. You can do this by issuing the following PowerShell +command: + +PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser + +For more information on Execution Policies: +https://go.microsoft.com/fwlink/?LinkID=135170 + +#> +Param( + [Parameter(Mandatory = $false)] + [String] + $VenvDir, + [Parameter(Mandatory = $false)] + [String] + $Prompt +) + +<# Function declarations --------------------------------------------------- #> + +<# +.Synopsis +Remove all shell session elements added by the Activate script, including the +addition of the virtual environment's Python executable from the beginning of +the PATH variable. + +.Parameter NonDestructive +If present, do not remove this function from the global namespace for the +session. + +#> +function global:deactivate ([switch]$NonDestructive) { + # Revert to original values + + # The prior prompt: + if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) { + Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt + Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT + } + + # The prior PYTHONHOME: + if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) { + Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME + Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME + } + + # The prior PATH: + if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) { + Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH + Remove-Item -Path Env:_OLD_VIRTUAL_PATH + } + + # Just remove the VIRTUAL_ENV altogether: + if (Test-Path -Path Env:VIRTUAL_ENV) { + Remove-Item -Path env:VIRTUAL_ENV + } + + # Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether: + if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) { + Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force + } + + # Leave deactivate function in the global namespace if requested: + if (-not $NonDestructive) { + Remove-Item -Path function:deactivate + } +} + +<# +.Description +Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the +given folder, and returns them in a map. + +For each line in the pyvenv.cfg file, if that line can be parsed into exactly +two strings separated by `=` (with any amount of whitespace surrounding the =) +then it is considered a `key = value` line. The left hand string is the key, +the right hand is the value. + +If the value starts with a `'` or a `"` then the first and last character is +stripped from the value before being captured. + +.Parameter ConfigDir +Path to the directory that contains the `pyvenv.cfg` file. +#> +function Get-PyVenvConfig( + [String] + $ConfigDir +) { + Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg" + + # Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue). + $pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue + + # An empty map will be returned if no config file is found. + $pyvenvConfig = @{ } + + if ($pyvenvConfigPath) { + + Write-Verbose "File exists, parse `key = value` lines" + $pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath + + $pyvenvConfigContent | ForEach-Object { + $keyval = $PSItem -split "\s*=\s*", 2 + if ($keyval[0] -and $keyval[1]) { + $val = $keyval[1] + + # Remove extraneous quotations around a string value. + if ("'""".Contains($val.Substring(0, 1))) { + $val = $val.Substring(1, $val.Length - 2) + } + + $pyvenvConfig[$keyval[0]] = $val + Write-Verbose "Adding Key: '$($keyval[0])'='$val'" + } + } + } + return $pyvenvConfig +} + + +<# Begin Activate script --------------------------------------------------- #> + +# Determine the containing directory of this script +$VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition +$VenvExecDir = Get-Item -Path $VenvExecPath + +Write-Verbose "Activation script is located in path: '$VenvExecPath'" +Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)" +Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)" + +# Set values required in priority: CmdLine, ConfigFile, Default +# First, get the location of the virtual environment, it might not be +# VenvExecDir if specified on the command line. +if ($VenvDir) { + Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values" +} +else { + Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir." + $VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/") + Write-Verbose "VenvDir=$VenvDir" +} + +# Next, read the `pyvenv.cfg` file to determine any required value such +# as `prompt`. +$pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir + +# Next, set the prompt from the command line, or the config file, or +# just use the name of the virtual environment folder. +if ($Prompt) { + Write-Verbose "Prompt specified as argument, using '$Prompt'" +} +else { + Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value" + if ($pyvenvCfg -and $pyvenvCfg['prompt']) { + Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'" + $Prompt = $pyvenvCfg['prompt']; + } + else { + Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virutal environment)" + Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'" + $Prompt = Split-Path -Path $venvDir -Leaf + } +} + +Write-Verbose "Prompt = '$Prompt'" +Write-Verbose "VenvDir='$VenvDir'" + +# Deactivate any currently active virtual environment, but leave the +# deactivate function in place. +deactivate -nondestructive + +# Now set the environment variable VIRTUAL_ENV, used by many tools to determine +# that there is an activated venv. +$env:VIRTUAL_ENV = $VenvDir + +if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) { + + Write-Verbose "Setting prompt to '$Prompt'" + + # Set the prompt to include the env name + # Make sure _OLD_VIRTUAL_PROMPT is global + function global:_OLD_VIRTUAL_PROMPT { "" } + Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT + New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt + + function global:prompt { + Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) " + _OLD_VIRTUAL_PROMPT + } +} + +# Clear PYTHONHOME +if (Test-Path -Path Env:PYTHONHOME) { + Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME + Remove-Item -Path Env:PYTHONHOME +} + +# Add the venv to the PATH +Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH +$Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH" diff --git a/venv/bin/activate b/venv/bin/activate new file mode 100644 index 0000000..f3e9659 --- /dev/null +++ b/venv/bin/activate @@ -0,0 +1,76 @@ +# This file must be used with "source bin/activate" *from bash* +# you cannot run it directly + +deactivate () { + # reset old environment variables + if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then + PATH="${_OLD_VIRTUAL_PATH:-}" + export PATH + unset _OLD_VIRTUAL_PATH + fi + if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then + PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}" + export PYTHONHOME + unset _OLD_VIRTUAL_PYTHONHOME + fi + + # This should detect bash and zsh, which have a hash command that must + # be called to get it to forget past commands. Without forgetting + # past commands the $PATH changes we made may not be respected + if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then + hash -r + fi + + if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then + PS1="${_OLD_VIRTUAL_PS1:-}" + export PS1 + unset _OLD_VIRTUAL_PS1 + fi + + unset VIRTUAL_ENV + if [ ! "${1:-}" = "nondestructive" ] ; then + # Self destruct! + unset -f deactivate + fi +} + +# unset irrelevant variables +deactivate nondestructive + +VIRTUAL_ENV="/home/kyoumabat/Documents/PyukuBot/venv" +export VIRTUAL_ENV + +_OLD_VIRTUAL_PATH="$PATH" +PATH="$VIRTUAL_ENV/bin:$PATH" +export PATH + +# unset PYTHONHOME if set +# this will fail if PYTHONHOME is set to the empty string (which is bad anyway) +# could use `if (set -u; : $PYTHONHOME) ;` in bash +if [ -n "${PYTHONHOME:-}" ] ; then + _OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}" + unset PYTHONHOME +fi + +if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then + _OLD_VIRTUAL_PS1="${PS1:-}" + if [ "x(venv) " != x ] ; then + PS1="(venv) ${PS1:-}" + else + if [ "`basename \"$VIRTUAL_ENV\"`" = "__" ] ; then + # special case for Aspen magic directories + # see https://aspen.io/ + PS1="[`basename \`dirname \"$VIRTUAL_ENV\"\``] $PS1" + else + PS1="(`basename \"$VIRTUAL_ENV\"`)$PS1" + fi + fi + export PS1 +fi + +# This should detect bash and zsh, which have a hash command that must +# be called to get it to forget past commands. Without forgetting +# past commands the $PATH changes we made may not be respected +if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then + hash -r +fi diff --git a/venv/bin/activate.csh b/venv/bin/activate.csh new file mode 100644 index 0000000..9a704f8 --- /dev/null +++ b/venv/bin/activate.csh @@ -0,0 +1,37 @@ +# This file must be used with "source bin/activate.csh" *from csh*. +# You cannot run it directly. +# Created by Davide Di Blasi . +# Ported to Python 3.3 venv by Andrew Svetlov + +alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; test "\!:*" != "nondestructive" && unalias deactivate' + +# Unset irrelevant variables. +deactivate nondestructive + +setenv VIRTUAL_ENV "/home/kyoumabat/Documents/PyukuBot/venv" + +set _OLD_VIRTUAL_PATH="$PATH" +setenv PATH "$VIRTUAL_ENV/bin:$PATH" + + +set _OLD_VIRTUAL_PROMPT="$prompt" + +if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then + if ("venv" != "") then + set env_name = "venv" + else + if (`basename "VIRTUAL_ENV"` == "__") then + # special case for Aspen magic directories + # see https://aspen.io/ + set env_name = `basename \`dirname "$VIRTUAL_ENV"\`` + else + set env_name = `basename "$VIRTUAL_ENV"` + endif + endif + set prompt = "[$env_name] $prompt" + unset env_name +endif + +alias pydoc python -m pydoc + +rehash diff --git a/venv/bin/activate.fish b/venv/bin/activate.fish new file mode 100644 index 0000000..e9232ca --- /dev/null +++ b/venv/bin/activate.fish @@ -0,0 +1,75 @@ +# This file must be used with ". bin/activate.fish" *from fish* (http://fishshell.org) +# you cannot run it directly + +function deactivate -d "Exit virtualenv and return to normal shell environment" + # reset old environment variables + if test -n "$_OLD_VIRTUAL_PATH" + set -gx PATH $_OLD_VIRTUAL_PATH + set -e _OLD_VIRTUAL_PATH + end + if test -n "$_OLD_VIRTUAL_PYTHONHOME" + set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME + set -e _OLD_VIRTUAL_PYTHONHOME + end + + if test -n "$_OLD_FISH_PROMPT_OVERRIDE" + functions -e fish_prompt + set -e _OLD_FISH_PROMPT_OVERRIDE + functions -c _old_fish_prompt fish_prompt + functions -e _old_fish_prompt + end + + set -e VIRTUAL_ENV + if test "$argv[1]" != "nondestructive" + # Self destruct! + functions -e deactivate + end +end + +# unset irrelevant variables +deactivate nondestructive + +set -gx VIRTUAL_ENV "/home/kyoumabat/Documents/PyukuBot/venv" + +set -gx _OLD_VIRTUAL_PATH $PATH +set -gx PATH "$VIRTUAL_ENV/bin" $PATH + +# unset PYTHONHOME if set +if set -q PYTHONHOME + set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME + set -e PYTHONHOME +end + +if test -z "$VIRTUAL_ENV_DISABLE_PROMPT" + # fish uses a function instead of an env var to generate the prompt. + + # save the current fish_prompt function as the function _old_fish_prompt + functions -c fish_prompt _old_fish_prompt + + # with the original prompt function renamed, we can override with our own. + function fish_prompt + # Save the return status of the last command + set -l old_status $status + + # Prompt override? + if test -n "(venv) " + printf "%s%s" "(venv) " (set_color normal) + else + # ...Otherwise, prepend env + set -l _checkbase (basename "$VIRTUAL_ENV") + if test $_checkbase = "__" + # special case for Aspen magic directories + # see https://aspen.io/ + printf "%s[%s]%s " (set_color -b blue white) (basename (dirname "$VIRTUAL_ENV")) (set_color normal) + else + printf "%s(%s)%s" (set_color -b blue white) (basename "$VIRTUAL_ENV") (set_color normal) + end + end + + # Restore the return status of the previous command. + echo "exit $old_status" | . + _old_fish_prompt + end + + set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV" +end diff --git a/venv/bin/chardetect b/venv/bin/chardetect new file mode 100755 index 0000000..5a08aed --- /dev/null +++ b/venv/bin/chardetect @@ -0,0 +1,8 @@ +#!/home/kyoumabat/Documents/PyukuBot/venv/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from chardet.cli.chardetect import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/easy_install b/venv/bin/easy_install new file mode 100755 index 0000000..09ba853 --- /dev/null +++ b/venv/bin/easy_install @@ -0,0 +1,8 @@ +#!/home/kyoumabat/Documents/PyukuBot/venv/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from setuptools.command.easy_install import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/easy_install-3.8 b/venv/bin/easy_install-3.8 new file mode 100755 index 0000000..09ba853 --- /dev/null +++ b/venv/bin/easy_install-3.8 @@ -0,0 +1,8 @@ +#!/home/kyoumabat/Documents/PyukuBot/venv/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from setuptools.command.easy_install import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/pip b/venv/bin/pip new file mode 100755 index 0000000..89079cf --- /dev/null +++ b/venv/bin/pip @@ -0,0 +1,8 @@ +#!/home/kyoumabat/Documents/PyukuBot/venv/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from pip._internal.cli.main import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/pip3 b/venv/bin/pip3 new file mode 100755 index 0000000..89079cf --- /dev/null +++ b/venv/bin/pip3 @@ -0,0 +1,8 @@ +#!/home/kyoumabat/Documents/PyukuBot/venv/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from pip._internal.cli.main import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/pip3.8 b/venv/bin/pip3.8 new file mode 100755 index 0000000..89079cf --- /dev/null +++ b/venv/bin/pip3.8 @@ -0,0 +1,8 @@ +#!/home/kyoumabat/Documents/PyukuBot/venv/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from pip._internal.cli.main import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/python b/venv/bin/python new file mode 120000 index 0000000..b8a0adb --- /dev/null +++ b/venv/bin/python @@ -0,0 +1 @@ +python3 \ No newline at end of file diff --git a/venv/bin/python3 b/venv/bin/python3 new file mode 120000 index 0000000..ae65fda --- /dev/null +++ b/venv/bin/python3 @@ -0,0 +1 @@ +/usr/bin/python3 \ No newline at end of file diff --git a/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/INSTALLER b/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/LICENSE.txt b/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/LICENSE.txt new file mode 100644 index 0000000..07806f8 --- /dev/null +++ b/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/LICENSE.txt @@ -0,0 +1,19 @@ +This is the MIT license: http://www.opensource.org/licenses/mit-license.php + +Copyright (c) Alex Grönholm + +Permission is hereby granted, free of charge, to any person obtaining a copy of this +software and associated documentation files (the "Software"), to deal in the Software +without restriction, including without limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/METADATA b/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/METADATA new file mode 100644 index 0000000..ba40f6b --- /dev/null +++ b/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/METADATA @@ -0,0 +1,133 @@ +Metadata-Version: 2.1 +Name: APScheduler +Version: 3.6.3 +Summary: In-process task scheduler with Cron-like capabilities +Home-page: https://github.com/agronholm/apscheduler +Author: Alex Grönholm +Author-email: apscheduler@nextday.fi +License: MIT +Keywords: scheduling cron +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Programming Language :: Python +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 +Requires-Dist: setuptools (>=0.7) +Requires-Dist: six (>=1.4.0) +Requires-Dist: pytz +Requires-Dist: tzlocal (>=1.2) +Requires-Dist: futures ; python_version == "2.7" +Requires-Dist: funcsigs ; python_version == "2.7" +Provides-Extra: asyncio +Requires-Dist: trollius ; (python_version == "2.7") and extra == 'asyncio' +Provides-Extra: doc +Requires-Dist: sphinx ; extra == 'doc' +Requires-Dist: sphinx-rtd-theme ; extra == 'doc' +Provides-Extra: gevent +Requires-Dist: gevent ; extra == 'gevent' +Provides-Extra: mongodb +Requires-Dist: pymongo (>=2.8) ; extra == 'mongodb' +Provides-Extra: redis +Requires-Dist: redis (>=3.0) ; extra == 'redis' +Provides-Extra: rethinkdb +Requires-Dist: rethinkdb (>=2.4.0) ; extra == 'rethinkdb' +Provides-Extra: sqlalchemy +Requires-Dist: sqlalchemy (>=0.8) ; extra == 'sqlalchemy' +Provides-Extra: testing +Requires-Dist: pytest ; extra == 'testing' +Requires-Dist: pytest-cov ; extra == 'testing' +Requires-Dist: pytest-tornado5 ; extra == 'testing' +Requires-Dist: mock ; (python_version == "2.7") and extra == 'testing' +Requires-Dist: pytest-asyncio (<0.6) ; (python_version == "3.4") and extra == 'testing' +Requires-Dist: pytest-asyncio ; (python_version >= "3.5") and extra == 'testing' +Provides-Extra: tornado +Requires-Dist: tornado (>=4.3) ; extra == 'tornado' +Provides-Extra: twisted +Requires-Dist: twisted ; extra == 'twisted' +Provides-Extra: zookeeper +Requires-Dist: kazoo ; extra == 'zookeeper' + +.. image:: https://travis-ci.com/agronholm/apscheduler.svg?branch=master + :target: https://travis-ci.com/agronholm/apscheduler + :alt: Build Status +.. image:: https://coveralls.io/repos/github/agronholm/apscheduler/badge.svg?branch=master + :target: https://coveralls.io/github/agronholm/apscheduler?branch=master + :alt: Code Coverage + +Advanced Python Scheduler (APScheduler) is a Python library that lets you schedule your Python code +to be executed later, either just once or periodically. You can add new jobs or remove old ones on +the fly as you please. If you store your jobs in a database, they will also survive scheduler +restarts and maintain their state. When the scheduler is restarted, it will then run all the jobs +it should have run while it was offline [#f1]_. + +Among other things, APScheduler can be used as a cross-platform, application specific replacement +to platform specific schedulers, such as the cron daemon or the Windows task scheduler. Please +note, however, that APScheduler is **not** a daemon or service itself, nor does it come with any +command line tools. It is primarily meant to be run inside existing applications. That said, +APScheduler does provide some building blocks for you to build a scheduler service or to run a +dedicated scheduler process. + +APScheduler has three built-in scheduling systems you can use: + +* Cron-style scheduling (with optional start/end times) +* Interval-based execution (runs jobs on even intervals, with optional start/end times) +* One-off delayed execution (runs jobs once, on a set date/time) + +You can mix and match scheduling systems and the backends where the jobs are stored any way you +like. Supported backends for storing jobs include: + +* Memory +* `SQLAlchemy `_ (any RDBMS supported by SQLAlchemy works) +* `MongoDB `_ +* `Redis `_ +* `RethinkDB `_ +* `ZooKeeper `_ + +APScheduler also integrates with several common Python frameworks, like: + +* `asyncio `_ (:pep:`3156`) +* `gevent `_ +* `Tornado `_ +* `Twisted `_ +* `Qt `_ (using either + `PyQt `_ or + `PySide `_) + +.. [#f1] The cutoff period for this is also configurable. + + +Documentation +------------- + +Documentation can be found `here `_. + + +Source +------ + +The source can be browsed at `Github `_. + + +Reporting bugs +-------------- + +A `bug tracker `_ is provided by Github. + + +Getting help +------------ + +If you have problems or other questions, you can either: + +* Ask in the `apscheduler `_ room on Gitter +* Ask on the `APScheduler Google group `_, or +* Ask on `StackOverflow `_ and tag your + question with the ``apscheduler`` tag + + diff --git a/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/RECORD b/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/RECORD new file mode 100644 index 0000000..2c63ee3 --- /dev/null +++ b/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/RECORD @@ -0,0 +1,83 @@ +APScheduler-3.6.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +APScheduler-3.6.3.dist-info/LICENSE.txt,sha256=YWP3mH37ONa8MgzitwsvArhivEESZRbVUu8c1DJH51g,1130 +APScheduler-3.6.3.dist-info/METADATA,sha256=VHah1X4AqMCGgcvEm06M-pAqmNC9q4tOQRbUv3b0Jh0,5398 +APScheduler-3.6.3.dist-info/RECORD,, +APScheduler-3.6.3.dist-info/WHEEL,sha256=8zNYZbwQSXoB9IfXOjPfeNwvAsALAjffgk27FqvCWbo,110 +APScheduler-3.6.3.dist-info/entry_points.txt,sha256=7RgkYN_OYyCUQtIGhj-UNcelnIjsNm7nC9rogdMQh3U,1148 +APScheduler-3.6.3.dist-info/top_level.txt,sha256=O3oMCWxG-AHkecUoO6Ze7-yYjWrttL95uHO8-RFdYvE,12 +apscheduler/__init__.py,sha256=qFEK2ysRBcLiYmm3deyJJ1avUOugaM_nCGHMD42WMBw,380 +apscheduler/__pycache__/__init__.cpython-38.pyc,, +apscheduler/__pycache__/events.cpython-38.pyc,, +apscheduler/__pycache__/job.cpython-38.pyc,, +apscheduler/__pycache__/util.cpython-38.pyc,, +apscheduler/events.py,sha256=KRMTDQUS6d2uVnrQvPoz3ZPV5V9XKsCAZLsgx913FFo,3593 +apscheduler/executors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +apscheduler/executors/__pycache__/__init__.cpython-38.pyc,, +apscheduler/executors/__pycache__/asyncio.cpython-38.pyc,, +apscheduler/executors/__pycache__/base.cpython-38.pyc,, +apscheduler/executors/__pycache__/base_py3.cpython-38.pyc,, +apscheduler/executors/__pycache__/debug.cpython-38.pyc,, +apscheduler/executors/__pycache__/gevent.cpython-38.pyc,, +apscheduler/executors/__pycache__/pool.cpython-38.pyc,, +apscheduler/executors/__pycache__/tornado.cpython-38.pyc,, +apscheduler/executors/__pycache__/twisted.cpython-38.pyc,, +apscheduler/executors/asyncio.py,sha256=ji5f6Qm2uGhov-3w52CXHZi8jc5U_gS56lisQylKTBQ,2087 +apscheduler/executors/base.py,sha256=hogiMc_t-huw6BMod0HEeY2FhRNmAAUyNNuBHvIX31M,5336 +apscheduler/executors/base_py3.py,sha256=s_4siAjBHrr7JZnm64VVow9zyvs2JBc-VRPkPuDeBTI,1775 +apscheduler/executors/debug.py,sha256=15_ogSBzl8RRCfBYDnkIV2uMH8cLk1KImYmBa_NVGpc,573 +apscheduler/executors/gevent.py,sha256=aulrNmoefyBgrOkH9awRhFiXIDnSCnZ4U0o0_JXIXgc,777 +apscheduler/executors/pool.py,sha256=q9TC6KzwWI9tpLNxQhdrKRWFtsN5dmx_Vegu23BV-Sk,1672 +apscheduler/executors/tornado.py,sha256=DU75VaQ9R6nBuy8lbPUvDKUgsuJcZqwAvURC5vg3r6w,1780 +apscheduler/executors/twisted.py,sha256=bRoU0C4BoVcS6_BjKD5wfUs0IJpGkmLsRAcMH2rJJss,778 +apscheduler/job.py,sha256=zT9_GuOpxuxEPVZU38tantw9383tAPRBPoH6dd4uHGA,11088 +apscheduler/jobstores/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +apscheduler/jobstores/__pycache__/__init__.cpython-38.pyc,, +apscheduler/jobstores/__pycache__/base.cpython-38.pyc,, +apscheduler/jobstores/__pycache__/memory.cpython-38.pyc,, +apscheduler/jobstores/__pycache__/mongodb.cpython-38.pyc,, +apscheduler/jobstores/__pycache__/redis.cpython-38.pyc,, +apscheduler/jobstores/__pycache__/rethinkdb.cpython-38.pyc,, +apscheduler/jobstores/__pycache__/sqlalchemy.cpython-38.pyc,, +apscheduler/jobstores/__pycache__/zookeeper.cpython-38.pyc,, +apscheduler/jobstores/base.py,sha256=DXzSW9XscueHZHMvy1qFiG-vYqUl_MMv0n0uBSZWXGo,4523 +apscheduler/jobstores/memory.py,sha256=ZxWiKsqfsCHFvac-6X9BztuhnuSxlOYi1dhT6g-pjQo,3655 +apscheduler/jobstores/mongodb.py,sha256=e9KNzPFrjiVpiM3iPT_c0ONxZQT70VCF2rDXW0-22zk,5296 +apscheduler/jobstores/redis.py,sha256=kjQDIzPXz-Yq976U9HK3aMkcCI_QRLKgTADQWKewtik,5483 +apscheduler/jobstores/rethinkdb.py,sha256=k1rSLYJqejuhQxJY3pXwHAQYcpZ1QFJsoQ8n0oEu5MM,5863 +apscheduler/jobstores/sqlalchemy.py,sha256=5H5T05cQ2ZtkRuRb8hKkcLzZSQneAT13NMKXby3nzWE,6122 +apscheduler/jobstores/zookeeper.py,sha256=BzyqZ08XIDcbu5frQWGmDVEHAEScNxjt8oML6Tty8j8,6406 +apscheduler/schedulers/__init__.py,sha256=jM63xA_K7GSToBenhsz-SCcqfhk1pdEVb6ajwoO5Kqg,406 +apscheduler/schedulers/__pycache__/__init__.cpython-38.pyc,, +apscheduler/schedulers/__pycache__/asyncio.cpython-38.pyc,, +apscheduler/schedulers/__pycache__/background.cpython-38.pyc,, +apscheduler/schedulers/__pycache__/base.cpython-38.pyc,, +apscheduler/schedulers/__pycache__/blocking.cpython-38.pyc,, +apscheduler/schedulers/__pycache__/gevent.cpython-38.pyc,, +apscheduler/schedulers/__pycache__/qt.cpython-38.pyc,, +apscheduler/schedulers/__pycache__/tornado.cpython-38.pyc,, +apscheduler/schedulers/__pycache__/twisted.cpython-38.pyc,, +apscheduler/schedulers/asyncio.py,sha256=0j0mcDpf-zI_vQHcUCZZtBfEEZEiocEOZ767efIZ5YM,2082 +apscheduler/schedulers/background.py,sha256=dGX0T0z6T6HzZHG7njWgp90SFHpetZ4ZBUV2gGOSqoc,1505 +apscheduler/schedulers/base.py,sha256=EUGbQ5R2jGA4PEEehU2ASuKVe0SsLqtWESAtTqAJW50,42863 +apscheduler/schedulers/blocking.py,sha256=c-5YR-dKn3D82tPt38t50KGPJrAiC852v8ai2Vwanmg,924 +apscheduler/schedulers/gevent.py,sha256=csPBvV75FGcboXXsdex6fCD7J54QgBddYNdWj62ZO9g,1031 +apscheduler/schedulers/qt.py,sha256=AhHU62ybOOVSD4OhMwoPRRUCoM5cf5q26uD3hPglfnc,1297 +apscheduler/schedulers/tornado.py,sha256=D9Vaq3Ee9EFiXa1jDy9tedI048gR_YT_LAFUWqO_uEw,1926 +apscheduler/schedulers/twisted.py,sha256=D5EBjjMRtMBxy0_aAURcULAI8Ky2IvCTr9tK9sO1rYk,1844 +apscheduler/triggers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +apscheduler/triggers/__pycache__/__init__.cpython-38.pyc,, +apscheduler/triggers/__pycache__/base.cpython-38.pyc,, +apscheduler/triggers/__pycache__/combining.cpython-38.pyc,, +apscheduler/triggers/__pycache__/date.cpython-38.pyc,, +apscheduler/triggers/__pycache__/interval.cpython-38.pyc,, +apscheduler/triggers/base.py,sha256=WMo5f2g14fjO5VzpIxFQtk47Z9VEUDDPSxjoPL9FGSQ,1837 +apscheduler/triggers/combining.py,sha256=WTEnaEkBHysF1009sCvBaQa99hiy9l5Oz-hHyjy3jv8,3473 +apscheduler/triggers/cron/__init__.py,sha256=a8ASzvM7ci-djOI2jIL2XErL6zEx4Wr1012aD1XJw_w,9246 +apscheduler/triggers/cron/__pycache__/__init__.cpython-38.pyc,, +apscheduler/triggers/cron/__pycache__/expressions.cpython-38.pyc,, +apscheduler/triggers/cron/__pycache__/fields.cpython-38.pyc,, +apscheduler/triggers/cron/expressions.py,sha256=hu1kq0mKvivIw7U0D0Nnrbuk3q01dCuhZ7SHRPw6qhI,9184 +apscheduler/triggers/cron/fields.py,sha256=NWPClh1NgSOpTlJ3sm1TXM_ViC2qJGKWkd_vg0xsw7o,3510 +apscheduler/triggers/date.py,sha256=RrfB1PNO9G9e91p1BOf-y_TseVHQQR-KJPhNdPpAHcU,1705 +apscheduler/triggers/interval.py,sha256=LiIunGOd96yaiAceG1XGP8eY3JxSyHDWCipVhQWMzDU,4381 +apscheduler/util.py,sha256=bQLVYP-RHtjypxol40a_JPT1Ta9BYSlTNdsDTc7dNMU,13963 diff --git a/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/WHEEL b/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/WHEEL new file mode 100644 index 0000000..8b701e9 --- /dev/null +++ b/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.33.6) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/entry_points.txt b/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/entry_points.txt new file mode 100644 index 0000000..d2bd62b --- /dev/null +++ b/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/entry_points.txt @@ -0,0 +1,24 @@ +[apscheduler.executors] +asyncio = apscheduler.executors.asyncio:AsyncIOExecutor [asyncio] +debug = apscheduler.executors.debug:DebugExecutor +gevent = apscheduler.executors.gevent:GeventExecutor [gevent] +processpool = apscheduler.executors.pool:ProcessPoolExecutor +threadpool = apscheduler.executors.pool:ThreadPoolExecutor +tornado = apscheduler.executors.tornado:TornadoExecutor [tornado] +twisted = apscheduler.executors.twisted:TwistedExecutor [twisted] + +[apscheduler.jobstores] +memory = apscheduler.jobstores.memory:MemoryJobStore +mongodb = apscheduler.jobstores.mongodb:MongoDBJobStore [mongodb] +redis = apscheduler.jobstores.redis:RedisJobStore [redis] +rethinkdb = apscheduler.jobstores.rethinkdb:RethinkDBJobStore [rethinkdb] +sqlalchemy = apscheduler.jobstores.sqlalchemy:SQLAlchemyJobStore [sqlalchemy] +zookeeper = apscheduler.jobstores.zookeeper:ZooKeeperJobStore [zookeeper] + +[apscheduler.triggers] +and = apscheduler.triggers.combining:AndTrigger +cron = apscheduler.triggers.cron:CronTrigger +date = apscheduler.triggers.date:DateTrigger +interval = apscheduler.triggers.interval:IntervalTrigger +or = apscheduler.triggers.combining:OrTrigger + diff --git a/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/top_level.txt b/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/top_level.txt new file mode 100644 index 0000000..d31d10d --- /dev/null +++ b/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/top_level.txt @@ -0,0 +1 @@ +apscheduler diff --git a/venv/lib/python3.8/site-packages/apscheduler/__init__.py b/venv/lib/python3.8/site-packages/apscheduler/__init__.py new file mode 100644 index 0000000..968169a --- /dev/null +++ b/venv/lib/python3.8/site-packages/apscheduler/__init__.py @@ -0,0 +1,10 @@ +from pkg_resources import get_distribution, DistributionNotFound + +try: + release = get_distribution('APScheduler').version.split('-')[0] +except DistributionNotFound: + release = '3.5.0' + +version_info = tuple(int(x) if x.isdigit() else x for x in release.split('.')) +version = __version__ = '.'.join(str(x) for x in version_info[:3]) +del get_distribution, DistributionNotFound diff --git a/venv/lib/python3.8/site-packages/apscheduler/events.py b/venv/lib/python3.8/site-packages/apscheduler/events.py new file mode 100644 index 0000000..016da03 --- /dev/null +++ b/venv/lib/python3.8/site-packages/apscheduler/events.py @@ -0,0 +1,94 @@ +__all__ = ('EVENT_SCHEDULER_STARTED', 'EVENT_SCHEDULER_SHUTDOWN', 'EVENT_SCHEDULER_PAUSED', + 'EVENT_SCHEDULER_RESUMED', 'EVENT_EXECUTOR_ADDED', 'EVENT_EXECUTOR_REMOVED', + 'EVENT_JOBSTORE_ADDED', 'EVENT_JOBSTORE_REMOVED', 'EVENT_ALL_JOBS_REMOVED', + 'EVENT_JOB_ADDED', 'EVENT_JOB_REMOVED', 'EVENT_JOB_MODIFIED', 'EVENT_JOB_EXECUTED', + 'EVENT_JOB_ERROR', 'EVENT_JOB_MISSED', 'EVENT_JOB_SUBMITTED', 'EVENT_JOB_MAX_INSTANCES', + 'SchedulerEvent', 'JobEvent', 'JobExecutionEvent', 'JobSubmissionEvent') + + +EVENT_SCHEDULER_STARTED = EVENT_SCHEDULER_START = 2 ** 0 +EVENT_SCHEDULER_SHUTDOWN = 2 ** 1 +EVENT_SCHEDULER_PAUSED = 2 ** 2 +EVENT_SCHEDULER_RESUMED = 2 ** 3 +EVENT_EXECUTOR_ADDED = 2 ** 4 +EVENT_EXECUTOR_REMOVED = 2 ** 5 +EVENT_JOBSTORE_ADDED = 2 ** 6 +EVENT_JOBSTORE_REMOVED = 2 ** 7 +EVENT_ALL_JOBS_REMOVED = 2 ** 8 +EVENT_JOB_ADDED = 2 ** 9 +EVENT_JOB_REMOVED = 2 ** 10 +EVENT_JOB_MODIFIED = 2 ** 11 +EVENT_JOB_EXECUTED = 2 ** 12 +EVENT_JOB_ERROR = 2 ** 13 +EVENT_JOB_MISSED = 2 ** 14 +EVENT_JOB_SUBMITTED = 2 ** 15 +EVENT_JOB_MAX_INSTANCES = 2 ** 16 +EVENT_ALL = (EVENT_SCHEDULER_STARTED | EVENT_SCHEDULER_SHUTDOWN | EVENT_SCHEDULER_PAUSED | + EVENT_SCHEDULER_RESUMED | EVENT_EXECUTOR_ADDED | EVENT_EXECUTOR_REMOVED | + EVENT_JOBSTORE_ADDED | EVENT_JOBSTORE_REMOVED | EVENT_ALL_JOBS_REMOVED | + EVENT_JOB_ADDED | EVENT_JOB_REMOVED | EVENT_JOB_MODIFIED | EVENT_JOB_EXECUTED | + EVENT_JOB_ERROR | EVENT_JOB_MISSED | EVENT_JOB_SUBMITTED | EVENT_JOB_MAX_INSTANCES) + + +class SchedulerEvent(object): + """ + An event that concerns the scheduler itself. + + :ivar code: the type code of this event + :ivar alias: alias of the job store or executor that was added or removed (if applicable) + """ + + def __init__(self, code, alias=None): + super(SchedulerEvent, self).__init__() + self.code = code + self.alias = alias + + def __repr__(self): + return '<%s (code=%d)>' % (self.__class__.__name__, self.code) + + +class JobEvent(SchedulerEvent): + """ + An event that concerns a job. + + :ivar code: the type code of this event + :ivar job_id: identifier of the job in question + :ivar jobstore: alias of the job store containing the job in question + """ + + def __init__(self, code, job_id, jobstore): + super(JobEvent, self).__init__(code) + self.code = code + self.job_id = job_id + self.jobstore = jobstore + + +class JobSubmissionEvent(JobEvent): + """ + An event that concerns the submission of a job to its executor. + + :ivar scheduled_run_times: a list of datetimes when the job was intended to run + """ + + def __init__(self, code, job_id, jobstore, scheduled_run_times): + super(JobSubmissionEvent, self).__init__(code, job_id, jobstore) + self.scheduled_run_times = scheduled_run_times + + +class JobExecutionEvent(JobEvent): + """ + An event that concerns the running of a job within its executor. + + :ivar scheduled_run_time: the time when the job was scheduled to be run + :ivar retval: the return value of the successfully executed job + :ivar exception: the exception raised by the job + :ivar traceback: a formatted traceback for the exception + """ + + def __init__(self, code, job_id, jobstore, scheduled_run_time, retval=None, exception=None, + traceback=None): + super(JobExecutionEvent, self).__init__(code, job_id, jobstore) + self.scheduled_run_time = scheduled_run_time + self.retval = retval + self.exception = exception + self.traceback = traceback diff --git a/venv/lib/python3.8/site-packages/apscheduler/executors/__init__.py b/venv/lib/python3.8/site-packages/apscheduler/executors/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.8/site-packages/apscheduler/executors/asyncio.py b/venv/lib/python3.8/site-packages/apscheduler/executors/asyncio.py new file mode 100644 index 0000000..06fc7f9 --- /dev/null +++ b/venv/lib/python3.8/site-packages/apscheduler/executors/asyncio.py @@ -0,0 +1,59 @@ +from __future__ import absolute_import + +import sys + +from apscheduler.executors.base import BaseExecutor, run_job +from apscheduler.util import iscoroutinefunction_partial + +try: + from apscheduler.executors.base_py3 import run_coroutine_job +except ImportError: + run_coroutine_job = None + + +class AsyncIOExecutor(BaseExecutor): + """ + Runs jobs in the default executor of the event loop. + + If the job function is a native coroutine function, it is scheduled to be run directly in the + event loop as soon as possible. All other functions are run in the event loop's default + executor which is usually a thread pool. + + Plugin alias: ``asyncio`` + """ + + def start(self, scheduler, alias): + super(AsyncIOExecutor, self).start(scheduler, alias) + self._eventloop = scheduler._eventloop + self._pending_futures = set() + + def shutdown(self, wait=True): + # There is no way to honor wait=True without converting this method into a coroutine method + for f in self._pending_futures: + if not f.done(): + f.cancel() + + self._pending_futures.clear() + + def _do_submit_job(self, job, run_times): + def callback(f): + self._pending_futures.discard(f) + try: + events = f.result() + except BaseException: + self._run_job_error(job.id, *sys.exc_info()[1:]) + else: + self._run_job_success(job.id, events) + + if iscoroutinefunction_partial(job.func): + if run_coroutine_job is not None: + coro = run_coroutine_job(job, job._jobstore_alias, run_times, self._logger.name) + f = self._eventloop.create_task(coro) + else: + raise Exception('Executing coroutine based jobs is not supported with Trollius') + else: + f = self._eventloop.run_in_executor(None, run_job, job, job._jobstore_alias, run_times, + self._logger.name) + + f.add_done_callback(callback) + self._pending_futures.add(f) diff --git a/venv/lib/python3.8/site-packages/apscheduler/executors/base.py b/venv/lib/python3.8/site-packages/apscheduler/executors/base.py new file mode 100644 index 0000000..4c09fc1 --- /dev/null +++ b/venv/lib/python3.8/site-packages/apscheduler/executors/base.py @@ -0,0 +1,146 @@ +from abc import ABCMeta, abstractmethod +from collections import defaultdict +from datetime import datetime, timedelta +from traceback import format_tb +import logging +import sys + +from pytz import utc +import six + +from apscheduler.events import ( + JobExecutionEvent, EVENT_JOB_MISSED, EVENT_JOB_ERROR, EVENT_JOB_EXECUTED) + + +class MaxInstancesReachedError(Exception): + def __init__(self, job): + super(MaxInstancesReachedError, self).__init__( + 'Job "%s" has already reached its maximum number of instances (%d)' % + (job.id, job.max_instances)) + + +class BaseExecutor(six.with_metaclass(ABCMeta, object)): + """Abstract base class that defines the interface that every executor must implement.""" + + _scheduler = None + _lock = None + _logger = logging.getLogger('apscheduler.executors') + + def __init__(self): + super(BaseExecutor, self).__init__() + self._instances = defaultdict(lambda: 0) + + def start(self, scheduler, alias): + """ + Called by the scheduler when the scheduler is being started or when the executor is being + added to an already running scheduler. + + :param apscheduler.schedulers.base.BaseScheduler scheduler: the scheduler that is starting + this executor + :param str|unicode alias: alias of this executor as it was assigned to the scheduler + + """ + self._scheduler = scheduler + self._lock = scheduler._create_lock() + self._logger = logging.getLogger('apscheduler.executors.%s' % alias) + + def shutdown(self, wait=True): + """ + Shuts down this executor. + + :param bool wait: ``True`` to wait until all submitted jobs + have been executed + """ + + def submit_job(self, job, run_times): + """ + Submits job for execution. + + :param Job job: job to execute + :param list[datetime] run_times: list of datetimes specifying + when the job should have been run + :raises MaxInstancesReachedError: if the maximum number of + allowed instances for this job has been reached + + """ + assert self._lock is not None, 'This executor has not been started yet' + with self._lock: + if self._instances[job.id] >= job.max_instances: + raise MaxInstancesReachedError(job) + + self._do_submit_job(job, run_times) + self._instances[job.id] += 1 + + @abstractmethod + def _do_submit_job(self, job, run_times): + """Performs the actual task of scheduling `run_job` to be called.""" + + def _run_job_success(self, job_id, events): + """ + Called by the executor with the list of generated events when :func:`run_job` has been + successfully called. + + """ + with self._lock: + self._instances[job_id] -= 1 + if self._instances[job_id] == 0: + del self._instances[job_id] + + for event in events: + self._scheduler._dispatch_event(event) + + def _run_job_error(self, job_id, exc, traceback=None): + """Called by the executor with the exception if there is an error calling `run_job`.""" + with self._lock: + self._instances[job_id] -= 1 + if self._instances[job_id] == 0: + del self._instances[job_id] + + exc_info = (exc.__class__, exc, traceback) + self._logger.error('Error running job %s', job_id, exc_info=exc_info) + + +def run_job(job, jobstore_alias, run_times, logger_name): + """ + Called by executors to run the job. Returns a list of scheduler events to be dispatched by the + scheduler. + + """ + events = [] + logger = logging.getLogger(logger_name) + for run_time in run_times: + # See if the job missed its run time window, and handle + # possible misfires accordingly + if job.misfire_grace_time is not None: + difference = datetime.now(utc) - run_time + grace_time = timedelta(seconds=job.misfire_grace_time) + if difference > grace_time: + events.append(JobExecutionEvent(EVENT_JOB_MISSED, job.id, jobstore_alias, + run_time)) + logger.warning('Run time of job "%s" was missed by %s', job, difference) + continue + + logger.info('Running job "%s" (scheduled at %s)', job, run_time) + try: + retval = job.func(*job.args, **job.kwargs) + except BaseException: + exc, tb = sys.exc_info()[1:] + formatted_tb = ''.join(format_tb(tb)) + events.append(JobExecutionEvent(EVENT_JOB_ERROR, job.id, jobstore_alias, run_time, + exception=exc, traceback=formatted_tb)) + logger.exception('Job "%s" raised an exception', job) + + # This is to prevent cyclic references that would lead to memory leaks + if six.PY2: + sys.exc_clear() + del tb + else: + import traceback + traceback.clear_frames(tb) + del tb + else: + events.append(JobExecutionEvent(EVENT_JOB_EXECUTED, job.id, jobstore_alias, run_time, + retval=retval)) + logger.info('Job "%s" executed successfully', job) + + return events diff --git a/venv/lib/python3.8/site-packages/apscheduler/executors/base_py3.py b/venv/lib/python3.8/site-packages/apscheduler/executors/base_py3.py new file mode 100644 index 0000000..61abd84 --- /dev/null +++ b/venv/lib/python3.8/site-packages/apscheduler/executors/base_py3.py @@ -0,0 +1,41 @@ +import logging +import sys +from datetime import datetime, timedelta +from traceback import format_tb + +from pytz import utc + +from apscheduler.events import ( + JobExecutionEvent, EVENT_JOB_MISSED, EVENT_JOB_ERROR, EVENT_JOB_EXECUTED) + + +async def run_coroutine_job(job, jobstore_alias, run_times, logger_name): + """Coroutine version of run_job().""" + events = [] + logger = logging.getLogger(logger_name) + for run_time in run_times: + # See if the job missed its run time window, and handle possible misfires accordingly + if job.misfire_grace_time is not None: + difference = datetime.now(utc) - run_time + grace_time = timedelta(seconds=job.misfire_grace_time) + if difference > grace_time: + events.append(JobExecutionEvent(EVENT_JOB_MISSED, job.id, jobstore_alias, + run_time)) + logger.warning('Run time of job "%s" was missed by %s', job, difference) + continue + + logger.info('Running job "%s" (scheduled at %s)', job, run_time) + try: + retval = await job.func(*job.args, **job.kwargs) + except BaseException: + exc, tb = sys.exc_info()[1:] + formatted_tb = ''.join(format_tb(tb)) + events.append(JobExecutionEvent(EVENT_JOB_ERROR, job.id, jobstore_alias, run_time, + exception=exc, traceback=formatted_tb)) + logger.exception('Job "%s" raised an exception', job) + else: + events.append(JobExecutionEvent(EVENT_JOB_EXECUTED, job.id, jobstore_alias, run_time, + retval=retval)) + logger.info('Job "%s" executed successfully', job) + + return events diff --git a/venv/lib/python3.8/site-packages/apscheduler/executors/debug.py b/venv/lib/python3.8/site-packages/apscheduler/executors/debug.py new file mode 100644 index 0000000..ac739ae --- /dev/null +++ b/venv/lib/python3.8/site-packages/apscheduler/executors/debug.py @@ -0,0 +1,20 @@ +import sys + +from apscheduler.executors.base import BaseExecutor, run_job + + +class DebugExecutor(BaseExecutor): + """ + A special executor that executes the target callable directly instead of deferring it to a + thread or process. + + Plugin alias: ``debug`` + """ + + def _do_submit_job(self, job, run_times): + try: + events = run_job(job, job._jobstore_alias, run_times, self._logger.name) + except BaseException: + self._run_job_error(job.id, *sys.exc_info()[1:]) + else: + self._run_job_success(job.id, events) diff --git a/venv/lib/python3.8/site-packages/apscheduler/executors/gevent.py b/venv/lib/python3.8/site-packages/apscheduler/executors/gevent.py new file mode 100644 index 0000000..1235bb6 --- /dev/null +++ b/venv/lib/python3.8/site-packages/apscheduler/executors/gevent.py @@ -0,0 +1,30 @@ +from __future__ import absolute_import +import sys + +from apscheduler.executors.base import BaseExecutor, run_job + + +try: + import gevent +except ImportError: # pragma: nocover + raise ImportError('GeventExecutor requires gevent installed') + + +class GeventExecutor(BaseExecutor): + """ + Runs jobs as greenlets. + + Plugin alias: ``gevent`` + """ + + def _do_submit_job(self, job, run_times): + def callback(greenlet): + try: + events = greenlet.get() + except BaseException: + self._run_job_error(job.id, *sys.exc_info()[1:]) + else: + self._run_job_success(job.id, events) + + gevent.spawn(run_job, job, job._jobstore_alias, run_times, self._logger.name).\ + link(callback) diff --git a/venv/lib/python3.8/site-packages/apscheduler/executors/pool.py b/venv/lib/python3.8/site-packages/apscheduler/executors/pool.py new file mode 100644 index 0000000..2f4ef45 --- /dev/null +++ b/venv/lib/python3.8/site-packages/apscheduler/executors/pool.py @@ -0,0 +1,54 @@ +from abc import abstractmethod +import concurrent.futures + +from apscheduler.executors.base import BaseExecutor, run_job + + +class BasePoolExecutor(BaseExecutor): + @abstractmethod + def __init__(self, pool): + super(BasePoolExecutor, self).__init__() + self._pool = pool + + def _do_submit_job(self, job, run_times): + def callback(f): + exc, tb = (f.exception_info() if hasattr(f, 'exception_info') else + (f.exception(), getattr(f.exception(), '__traceback__', None))) + if exc: + self._run_job_error(job.id, exc, tb) + else: + self._run_job_success(job.id, f.result()) + + f = self._pool.submit(run_job, job, job._jobstore_alias, run_times, self._logger.name) + f.add_done_callback(callback) + + def shutdown(self, wait=True): + self._pool.shutdown(wait) + + +class ThreadPoolExecutor(BasePoolExecutor): + """ + An executor that runs jobs in a concurrent.futures thread pool. + + Plugin alias: ``threadpool`` + + :param max_workers: the maximum number of spawned threads. + """ + + def __init__(self, max_workers=10): + pool = concurrent.futures.ThreadPoolExecutor(int(max_workers)) + super(ThreadPoolExecutor, self).__init__(pool) + + +class ProcessPoolExecutor(BasePoolExecutor): + """ + An executor that runs jobs in a concurrent.futures process pool. + + Plugin alias: ``processpool`` + + :param max_workers: the maximum number of spawned processes. + """ + + def __init__(self, max_workers=10): + pool = concurrent.futures.ProcessPoolExecutor(int(max_workers)) + super(ProcessPoolExecutor, self).__init__(pool) diff --git a/venv/lib/python3.8/site-packages/apscheduler/executors/tornado.py b/venv/lib/python3.8/site-packages/apscheduler/executors/tornado.py new file mode 100644 index 0000000..3b97eec --- /dev/null +++ b/venv/lib/python3.8/site-packages/apscheduler/executors/tornado.py @@ -0,0 +1,54 @@ +from __future__ import absolute_import + +import sys +from concurrent.futures import ThreadPoolExecutor + +from tornado.gen import convert_yielded + +from apscheduler.executors.base import BaseExecutor, run_job + +try: + from apscheduler.executors.base_py3 import run_coroutine_job + from apscheduler.util import iscoroutinefunction_partial +except ImportError: + def iscoroutinefunction_partial(func): + return False + + +class TornadoExecutor(BaseExecutor): + """ + Runs jobs either in a thread pool or directly on the I/O loop. + + If the job function is a native coroutine function, it is scheduled to be run directly in the + I/O loop as soon as possible. All other functions are run in a thread pool. + + Plugin alias: ``tornado`` + + :param int max_workers: maximum number of worker threads in the thread pool + """ + + def __init__(self, max_workers=10): + super(TornadoExecutor, self).__init__() + self.executor = ThreadPoolExecutor(max_workers) + + def start(self, scheduler, alias): + super(TornadoExecutor, self).start(scheduler, alias) + self._ioloop = scheduler._ioloop + + def _do_submit_job(self, job, run_times): + def callback(f): + try: + events = f.result() + except BaseException: + self._run_job_error(job.id, *sys.exc_info()[1:]) + else: + self._run_job_success(job.id, events) + + if iscoroutinefunction_partial(job.func): + f = run_coroutine_job(job, job._jobstore_alias, run_times, self._logger.name) + else: + f = self.executor.submit(run_job, job, job._jobstore_alias, run_times, + self._logger.name) + + f = convert_yielded(f) + f.add_done_callback(callback) diff --git a/venv/lib/python3.8/site-packages/apscheduler/executors/twisted.py b/venv/lib/python3.8/site-packages/apscheduler/executors/twisted.py new file mode 100644 index 0000000..c7bcf64 --- /dev/null +++ b/venv/lib/python3.8/site-packages/apscheduler/executors/twisted.py @@ -0,0 +1,25 @@ +from __future__ import absolute_import + +from apscheduler.executors.base import BaseExecutor, run_job + + +class TwistedExecutor(BaseExecutor): + """ + Runs jobs in the reactor's thread pool. + + Plugin alias: ``twisted`` + """ + + def start(self, scheduler, alias): + super(TwistedExecutor, self).start(scheduler, alias) + self._reactor = scheduler._reactor + + def _do_submit_job(self, job, run_times): + def callback(success, result): + if success: + self._run_job_success(job.id, result) + else: + self._run_job_error(job.id, result.value, result.tb) + + self._reactor.getThreadPool().callInThreadWithCallback( + callback, run_job, job, job._jobstore_alias, run_times, self._logger.name) diff --git a/venv/lib/python3.8/site-packages/apscheduler/job.py b/venv/lib/python3.8/site-packages/apscheduler/job.py new file mode 100644 index 0000000..d676ca8 --- /dev/null +++ b/venv/lib/python3.8/site-packages/apscheduler/job.py @@ -0,0 +1,301 @@ +from inspect import ismethod, isclass +from uuid import uuid4 + +import six + +from apscheduler.triggers.base import BaseTrigger +from apscheduler.util import ( + ref_to_obj, obj_to_ref, datetime_repr, repr_escape, get_callable_name, check_callable_args, + convert_to_datetime) + +try: + from collections.abc import Iterable, Mapping +except ImportError: + from collections import Iterable, Mapping + + +class Job(object): + """ + Contains the options given when scheduling callables and its current schedule and other state. + This class should never be instantiated by the user. + + :var str id: the unique identifier of this job + :var str name: the description of this job + :var func: the callable to execute + :var tuple|list args: positional arguments to the callable + :var dict kwargs: keyword arguments to the callable + :var bool coalesce: whether to only run the job once when several run times are due + :var trigger: the trigger object that controls the schedule of this job + :var str executor: the name of the executor that will run this job + :var int misfire_grace_time: the time (in seconds) how much this job's execution is allowed to + be late + :var int max_instances: the maximum number of concurrently executing instances allowed for this + job + :var datetime.datetime next_run_time: the next scheduled run time of this job + + .. note:: + The ``misfire_grace_time`` has some non-obvious effects on job execution. See the + :ref:`missed-job-executions` section in the documentation for an in-depth explanation. + """ + + __slots__ = ('_scheduler', '_jobstore_alias', 'id', 'trigger', 'executor', 'func', 'func_ref', + 'args', 'kwargs', 'name', 'misfire_grace_time', 'coalesce', 'max_instances', + 'next_run_time') + + def __init__(self, scheduler, id=None, **kwargs): + super(Job, self).__init__() + self._scheduler = scheduler + self._jobstore_alias = None + self._modify(id=id or uuid4().hex, **kwargs) + + def modify(self, **changes): + """ + Makes the given changes to this job and saves it in the associated job store. + + Accepted keyword arguments are the same as the variables on this class. + + .. seealso:: :meth:`~apscheduler.schedulers.base.BaseScheduler.modify_job` + + :return Job: this job instance + + """ + self._scheduler.modify_job(self.id, self._jobstore_alias, **changes) + return self + + def reschedule(self, trigger, **trigger_args): + """ + Shortcut for switching the trigger on this job. + + .. seealso:: :meth:`~apscheduler.schedulers.base.BaseScheduler.reschedule_job` + + :return Job: this job instance + + """ + self._scheduler.reschedule_job(self.id, self._jobstore_alias, trigger, **trigger_args) + return self + + def pause(self): + """ + Temporarily suspend the execution of this job. + + .. seealso:: :meth:`~apscheduler.schedulers.base.BaseScheduler.pause_job` + + :return Job: this job instance + + """ + self._scheduler.pause_job(self.id, self._jobstore_alias) + return self + + def resume(self): + """ + Resume the schedule of this job if previously paused. + + .. seealso:: :meth:`~apscheduler.schedulers.base.BaseScheduler.resume_job` + + :return Job: this job instance + + """ + self._scheduler.resume_job(self.id, self._jobstore_alias) + return self + + def remove(self): + """ + Unschedules this job and removes it from its associated job store. + + .. seealso:: :meth:`~apscheduler.schedulers.base.BaseScheduler.remove_job` + + """ + self._scheduler.remove_job(self.id, self._jobstore_alias) + + @property + def pending(self): + """ + Returns ``True`` if the referenced job is still waiting to be added to its designated job + store. + + """ + return self._jobstore_alias is None + + # + # Private API + # + + def _get_run_times(self, now): + """ + Computes the scheduled run times between ``next_run_time`` and ``now`` (inclusive). + + :type now: datetime.datetime + :rtype: list[datetime.datetime] + + """ + run_times = [] + next_run_time = self.next_run_time + while next_run_time and next_run_time <= now: + run_times.append(next_run_time) + next_run_time = self.trigger.get_next_fire_time(next_run_time, now) + + return run_times + + def _modify(self, **changes): + """ + Validates the changes to the Job and makes the modifications if and only if all of them + validate. + + """ + approved = {} + + if 'id' in changes: + value = changes.pop('id') + if not isinstance(value, six.string_types): + raise TypeError("id must be a nonempty string") + if hasattr(self, 'id'): + raise ValueError('The job ID may not be changed') + approved['id'] = value + + if 'func' in changes or 'args' in changes or 'kwargs' in changes: + func = changes.pop('func') if 'func' in changes else self.func + args = changes.pop('args') if 'args' in changes else self.args + kwargs = changes.pop('kwargs') if 'kwargs' in changes else self.kwargs + + if isinstance(func, six.string_types): + func_ref = func + func = ref_to_obj(func) + elif callable(func): + try: + func_ref = obj_to_ref(func) + except ValueError: + # If this happens, this Job won't be serializable + func_ref = None + else: + raise TypeError('func must be a callable or a textual reference to one') + + if not hasattr(self, 'name') and changes.get('name', None) is None: + changes['name'] = get_callable_name(func) + + if isinstance(args, six.string_types) or not isinstance(args, Iterable): + raise TypeError('args must be a non-string iterable') + if isinstance(kwargs, six.string_types) or not isinstance(kwargs, Mapping): + raise TypeError('kwargs must be a dict-like object') + + check_callable_args(func, args, kwargs) + + approved['func'] = func + approved['func_ref'] = func_ref + approved['args'] = args + approved['kwargs'] = kwargs + + if 'name' in changes: + value = changes.pop('name') + if not value or not isinstance(value, six.string_types): + raise TypeError("name must be a nonempty string") + approved['name'] = value + + if 'misfire_grace_time' in changes: + value = changes.pop('misfire_grace_time') + if value is not None and (not isinstance(value, six.integer_types) or value <= 0): + raise TypeError('misfire_grace_time must be either None or a positive integer') + approved['misfire_grace_time'] = value + + if 'coalesce' in changes: + value = bool(changes.pop('coalesce')) + approved['coalesce'] = value + + if 'max_instances' in changes: + value = changes.pop('max_instances') + if not isinstance(value, six.integer_types) or value <= 0: + raise TypeError('max_instances must be a positive integer') + approved['max_instances'] = value + + if 'trigger' in changes: + trigger = changes.pop('trigger') + if not isinstance(trigger, BaseTrigger): + raise TypeError('Expected a trigger instance, got %s instead' % + trigger.__class__.__name__) + + approved['trigger'] = trigger + + if 'executor' in changes: + value = changes.pop('executor') + if not isinstance(value, six.string_types): + raise TypeError('executor must be a string') + approved['executor'] = value + + if 'next_run_time' in changes: + value = changes.pop('next_run_time') + approved['next_run_time'] = convert_to_datetime(value, self._scheduler.timezone, + 'next_run_time') + + if changes: + raise AttributeError('The following are not modifiable attributes of Job: %s' % + ', '.join(changes)) + + for key, value in six.iteritems(approved): + setattr(self, key, value) + + def __getstate__(self): + # Don't allow this Job to be serialized if the function reference could not be determined + if not self.func_ref: + raise ValueError( + 'This Job cannot be serialized since the reference to its callable (%r) could not ' + 'be determined. Consider giving a textual reference (module:function name) ' + 'instead.' % (self.func,)) + + # Instance methods cannot survive serialization as-is, so store the "self" argument + # explicitly + if ismethod(self.func) and not isclass(self.func.__self__): + args = (self.func.__self__,) + tuple(self.args) + else: + args = self.args + + return { + 'version': 1, + 'id': self.id, + 'func': self.func_ref, + 'trigger': self.trigger, + 'executor': self.executor, + 'args': args, + 'kwargs': self.kwargs, + 'name': self.name, + 'misfire_grace_time': self.misfire_grace_time, + 'coalesce': self.coalesce, + 'max_instances': self.max_instances, + 'next_run_time': self.next_run_time + } + + def __setstate__(self, state): + if state.get('version', 1) > 1: + raise ValueError('Job has version %s, but only version 1 can be handled' % + state['version']) + + self.id = state['id'] + self.func_ref = state['func'] + self.func = ref_to_obj(self.func_ref) + self.trigger = state['trigger'] + self.executor = state['executor'] + self.args = state['args'] + self.kwargs = state['kwargs'] + self.name = state['name'] + self.misfire_grace_time = state['misfire_grace_time'] + self.coalesce = state['coalesce'] + self.max_instances = state['max_instances'] + self.next_run_time = state['next_run_time'] + + def __eq__(self, other): + if isinstance(other, Job): + return self.id == other.id + return NotImplemented + + def __repr__(self): + return '' % (repr_escape(self.id), repr_escape(self.name)) + + def __str__(self): + return repr_escape(self.__unicode__()) + + def __unicode__(self): + if hasattr(self, 'next_run_time'): + status = ('next run at: ' + datetime_repr(self.next_run_time) if + self.next_run_time else 'paused') + else: + status = 'pending' + + return u'%s (trigger: %s, %s)' % (self.name, self.trigger, status) diff --git a/venv/lib/python3.8/site-packages/apscheduler/jobstores/__init__.py b/venv/lib/python3.8/site-packages/apscheduler/jobstores/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.8/site-packages/apscheduler/jobstores/base.py b/venv/lib/python3.8/site-packages/apscheduler/jobstores/base.py new file mode 100644 index 0000000..9cff66c --- /dev/null +++ b/venv/lib/python3.8/site-packages/apscheduler/jobstores/base.py @@ -0,0 +1,143 @@ +from abc import ABCMeta, abstractmethod +import logging + +import six + + +class JobLookupError(KeyError): + """Raised when the job store cannot find a job for update or removal.""" + + def __init__(self, job_id): + super(JobLookupError, self).__init__(u'No job by the id of %s was found' % job_id) + + +class ConflictingIdError(KeyError): + """Raised when the uniqueness of job IDs is being violated.""" + + def __init__(self, job_id): + super(ConflictingIdError, self).__init__( + u'Job identifier (%s) conflicts with an existing job' % job_id) + + +class TransientJobError(ValueError): + """ + Raised when an attempt to add transient (with no func_ref) job to a persistent job store is + detected. + """ + + def __init__(self, job_id): + super(TransientJobError, self).__init__( + u'Job (%s) cannot be added to this job store because a reference to the callable ' + u'could not be determined.' % job_id) + + +class BaseJobStore(six.with_metaclass(ABCMeta)): + """Abstract base class that defines the interface that every job store must implement.""" + + _scheduler = None + _alias = None + _logger = logging.getLogger('apscheduler.jobstores') + + def start(self, scheduler, alias): + """ + Called by the scheduler when the scheduler is being started or when the job store is being + added to an already running scheduler. + + :param apscheduler.schedulers.base.BaseScheduler scheduler: the scheduler that is starting + this job store + :param str|unicode alias: alias of this job store as it was assigned to the scheduler + """ + + self._scheduler = scheduler + self._alias = alias + self._logger = logging.getLogger('apscheduler.jobstores.%s' % alias) + + def shutdown(self): + """Frees any resources still bound to this job store.""" + + def _fix_paused_jobs_sorting(self, jobs): + for i, job in enumerate(jobs): + if job.next_run_time is not None: + if i > 0: + paused_jobs = jobs[:i] + del jobs[:i] + jobs.extend(paused_jobs) + break + + @abstractmethod + def lookup_job(self, job_id): + """ + Returns a specific job, or ``None`` if it isn't found.. + + The job store is responsible for setting the ``scheduler`` and ``jobstore`` attributes of + the returned job to point to the scheduler and itself, respectively. + + :param str|unicode job_id: identifier of the job + :rtype: Job + """ + + @abstractmethod + def get_due_jobs(self, now): + """ + Returns the list of jobs that have ``next_run_time`` earlier or equal to ``now``. + The returned jobs must be sorted by next run time (ascending). + + :param datetime.datetime now: the current (timezone aware) datetime + :rtype: list[Job] + """ + + @abstractmethod + def get_next_run_time(self): + """ + Returns the earliest run time of all the jobs stored in this job store, or ``None`` if + there are no active jobs. + + :rtype: datetime.datetime + """ + + @abstractmethod + def get_all_jobs(self): + """ + Returns a list of all jobs in this job store. + The returned jobs should be sorted by next run time (ascending). + Paused jobs (next_run_time == None) should be sorted last. + + The job store is responsible for setting the ``scheduler`` and ``jobstore`` attributes of + the returned jobs to point to the scheduler and itself, respectively. + + :rtype: list[Job] + """ + + @abstractmethod + def add_job(self, job): + """ + Adds the given job to this store. + + :param Job job: the job to add + :raises ConflictingIdError: if there is another job in this store with the same ID + """ + + @abstractmethod + def update_job(self, job): + """ + Replaces the job in the store with the given newer version. + + :param Job job: the job to update + :raises JobLookupError: if the job does not exist + """ + + @abstractmethod + def remove_job(self, job_id): + """ + Removes the given job from this store. + + :param str|unicode job_id: identifier of the job + :raises JobLookupError: if the job does not exist + """ + + @abstractmethod + def remove_all_jobs(self): + """Removes all jobs from this store.""" + + def __repr__(self): + return '<%s>' % self.__class__.__name__ diff --git a/venv/lib/python3.8/site-packages/apscheduler/jobstores/memory.py b/venv/lib/python3.8/site-packages/apscheduler/jobstores/memory.py new file mode 100644 index 0000000..abfe7c6 --- /dev/null +++ b/venv/lib/python3.8/site-packages/apscheduler/jobstores/memory.py @@ -0,0 +1,108 @@ +from __future__ import absolute_import + +from apscheduler.jobstores.base import BaseJobStore, JobLookupError, ConflictingIdError +from apscheduler.util import datetime_to_utc_timestamp + + +class MemoryJobStore(BaseJobStore): + """ + Stores jobs in an array in RAM. Provides no persistence support. + + Plugin alias: ``memory`` + """ + + def __init__(self): + super(MemoryJobStore, self).__init__() + # list of (job, timestamp), sorted by next_run_time and job id (ascending) + self._jobs = [] + self._jobs_index = {} # id -> (job, timestamp) lookup table + + def lookup_job(self, job_id): + return self._jobs_index.get(job_id, (None, None))[0] + + def get_due_jobs(self, now): + now_timestamp = datetime_to_utc_timestamp(now) + pending = [] + for job, timestamp in self._jobs: + if timestamp is None or timestamp > now_timestamp: + break + pending.append(job) + + return pending + + def get_next_run_time(self): + return self._jobs[0][0].next_run_time if self._jobs else None + + def get_all_jobs(self): + return [j[0] for j in self._jobs] + + def add_job(self, job): + if job.id in self._jobs_index: + raise ConflictingIdError(job.id) + + timestamp = datetime_to_utc_timestamp(job.next_run_time) + index = self._get_job_index(timestamp, job.id) + self._jobs.insert(index, (job, timestamp)) + self._jobs_index[job.id] = (job, timestamp) + + def update_job(self, job): + old_job, old_timestamp = self._jobs_index.get(job.id, (None, None)) + if old_job is None: + raise JobLookupError(job.id) + + # If the next run time has not changed, simply replace the job in its present index. + # Otherwise, reinsert the job to the list to preserve the ordering. + old_index = self._get_job_index(old_timestamp, old_job.id) + new_timestamp = datetime_to_utc_timestamp(job.next_run_time) + if old_timestamp == new_timestamp: + self._jobs[old_index] = (job, new_timestamp) + else: + del self._jobs[old_index] + new_index = self._get_job_index(new_timestamp, job.id) + self._jobs.insert(new_index, (job, new_timestamp)) + + self._jobs_index[old_job.id] = (job, new_timestamp) + + def remove_job(self, job_id): + job, timestamp = self._jobs_index.get(job_id, (None, None)) + if job is None: + raise JobLookupError(job_id) + + index = self._get_job_index(timestamp, job_id) + del self._jobs[index] + del self._jobs_index[job.id] + + def remove_all_jobs(self): + self._jobs = [] + self._jobs_index = {} + + def shutdown(self): + self.remove_all_jobs() + + def _get_job_index(self, timestamp, job_id): + """ + Returns the index of the given job, or if it's not found, the index where the job should be + inserted based on the given timestamp. + + :type timestamp: int + :type job_id: str + + """ + lo, hi = 0, len(self._jobs) + timestamp = float('inf') if timestamp is None else timestamp + while lo < hi: + mid = (lo + hi) // 2 + mid_job, mid_timestamp = self._jobs[mid] + mid_timestamp = float('inf') if mid_timestamp is None else mid_timestamp + if mid_timestamp > timestamp: + hi = mid + elif mid_timestamp < timestamp: + lo = mid + 1 + elif mid_job.id > job_id: + hi = mid + elif mid_job.id < job_id: + lo = mid + 1 + else: + return mid + + return lo diff --git a/venv/lib/python3.8/site-packages/apscheduler/jobstores/mongodb.py b/venv/lib/python3.8/site-packages/apscheduler/jobstores/mongodb.py new file mode 100644 index 0000000..7dbc3b1 --- /dev/null +++ b/venv/lib/python3.8/site-packages/apscheduler/jobstores/mongodb.py @@ -0,0 +1,141 @@ +from __future__ import absolute_import +import warnings + +from apscheduler.jobstores.base import BaseJobStore, JobLookupError, ConflictingIdError +from apscheduler.util import maybe_ref, datetime_to_utc_timestamp, utc_timestamp_to_datetime +from apscheduler.job import Job + +try: + import cPickle as pickle +except ImportError: # pragma: nocover + import pickle + +try: + from bson.binary import Binary + from pymongo.errors import DuplicateKeyError + from pymongo import MongoClient, ASCENDING +except ImportError: # pragma: nocover + raise ImportError('MongoDBJobStore requires PyMongo installed') + + +class MongoDBJobStore(BaseJobStore): + """ + Stores jobs in a MongoDB database. Any leftover keyword arguments are directly passed to + pymongo's `MongoClient + `_. + + Plugin alias: ``mongodb`` + + :param str database: database to store jobs in + :param str collection: collection to store jobs in + :param client: a :class:`~pymongo.mongo_client.MongoClient` instance to use instead of + providing connection arguments + :param int pickle_protocol: pickle protocol level to use (for serialization), defaults to the + highest available + """ + + def __init__(self, database='apscheduler', collection='jobs', client=None, + pickle_protocol=pickle.HIGHEST_PROTOCOL, **connect_args): + super(MongoDBJobStore, self).__init__() + self.pickle_protocol = pickle_protocol + + if not database: + raise ValueError('The "database" parameter must not be empty') + if not collection: + raise ValueError('The "collection" parameter must not be empty') + + if client: + self.client = maybe_ref(client) + else: + connect_args.setdefault('w', 1) + self.client = MongoClient(**connect_args) + + self.collection = self.client[database][collection] + + def start(self, scheduler, alias): + super(MongoDBJobStore, self).start(scheduler, alias) + self.collection.ensure_index('next_run_time', sparse=True) + + @property + def connection(self): + warnings.warn('The "connection" member is deprecated -- use "client" instead', + DeprecationWarning) + return self.client + + def lookup_job(self, job_id): + document = self.collection.find_one(job_id, ['job_state']) + return self._reconstitute_job(document['job_state']) if document else None + + def get_due_jobs(self, now): + timestamp = datetime_to_utc_timestamp(now) + return self._get_jobs({'next_run_time': {'$lte': timestamp}}) + + def get_next_run_time(self): + document = self.collection.find_one({'next_run_time': {'$ne': None}}, + projection=['next_run_time'], + sort=[('next_run_time', ASCENDING)]) + return utc_timestamp_to_datetime(document['next_run_time']) if document else None + + def get_all_jobs(self): + jobs = self._get_jobs({}) + self._fix_paused_jobs_sorting(jobs) + return jobs + + def add_job(self, job): + try: + self.collection.insert({ + '_id': job.id, + 'next_run_time': datetime_to_utc_timestamp(job.next_run_time), + 'job_state': Binary(pickle.dumps(job.__getstate__(), self.pickle_protocol)) + }) + except DuplicateKeyError: + raise ConflictingIdError(job.id) + + def update_job(self, job): + changes = { + 'next_run_time': datetime_to_utc_timestamp(job.next_run_time), + 'job_state': Binary(pickle.dumps(job.__getstate__(), self.pickle_protocol)) + } + result = self.collection.update({'_id': job.id}, {'$set': changes}) + if result and result['n'] == 0: + raise JobLookupError(job.id) + + def remove_job(self, job_id): + result = self.collection.remove(job_id) + if result and result['n'] == 0: + raise JobLookupError(job_id) + + def remove_all_jobs(self): + self.collection.remove() + + def shutdown(self): + self.client.close() + + def _reconstitute_job(self, job_state): + job_state = pickle.loads(job_state) + job = Job.__new__(Job) + job.__setstate__(job_state) + job._scheduler = self._scheduler + job._jobstore_alias = self._alias + return job + + def _get_jobs(self, conditions): + jobs = [] + failed_job_ids = [] + for document in self.collection.find(conditions, ['_id', 'job_state'], + sort=[('next_run_time', ASCENDING)]): + try: + jobs.append(self._reconstitute_job(document['job_state'])) + except BaseException: + self._logger.exception('Unable to restore job "%s" -- removing it', + document['_id']) + failed_job_ids.append(document['_id']) + + # Remove all the jobs we failed to restore + if failed_job_ids: + self.collection.remove({'_id': {'$in': failed_job_ids}}) + + return jobs + + def __repr__(self): + return '<%s (client=%s)>' % (self.__class__.__name__, self.client) diff --git a/venv/lib/python3.8/site-packages/apscheduler/jobstores/redis.py b/venv/lib/python3.8/site-packages/apscheduler/jobstores/redis.py new file mode 100644 index 0000000..5bb69d6 --- /dev/null +++ b/venv/lib/python3.8/site-packages/apscheduler/jobstores/redis.py @@ -0,0 +1,150 @@ +from __future__ import absolute_import +from datetime import datetime + +from pytz import utc +import six + +from apscheduler.jobstores.base import BaseJobStore, JobLookupError, ConflictingIdError +from apscheduler.util import datetime_to_utc_timestamp, utc_timestamp_to_datetime +from apscheduler.job import Job + +try: + import cPickle as pickle +except ImportError: # pragma: nocover + import pickle + +try: + from redis import Redis +except ImportError: # pragma: nocover + raise ImportError('RedisJobStore requires redis installed') + + +class RedisJobStore(BaseJobStore): + """ + Stores jobs in a Redis database. Any leftover keyword arguments are directly passed to redis's + :class:`~redis.StrictRedis`. + + Plugin alias: ``redis`` + + :param int db: the database number to store jobs in + :param str jobs_key: key to store jobs in + :param str run_times_key: key to store the jobs' run times in + :param int pickle_protocol: pickle protocol level to use (for serialization), defaults to the + highest available + """ + + def __init__(self, db=0, jobs_key='apscheduler.jobs', run_times_key='apscheduler.run_times', + pickle_protocol=pickle.HIGHEST_PROTOCOL, **connect_args): + super(RedisJobStore, self).__init__() + + if db is None: + raise ValueError('The "db" parameter must not be empty') + if not jobs_key: + raise ValueError('The "jobs_key" parameter must not be empty') + if not run_times_key: + raise ValueError('The "run_times_key" parameter must not be empty') + + self.pickle_protocol = pickle_protocol + self.jobs_key = jobs_key + self.run_times_key = run_times_key + self.redis = Redis(db=int(db), **connect_args) + + def lookup_job(self, job_id): + job_state = self.redis.hget(self.jobs_key, job_id) + return self._reconstitute_job(job_state) if job_state else None + + def get_due_jobs(self, now): + timestamp = datetime_to_utc_timestamp(now) + job_ids = self.redis.zrangebyscore(self.run_times_key, 0, timestamp) + if job_ids: + job_states = self.redis.hmget(self.jobs_key, *job_ids) + return self._reconstitute_jobs(six.moves.zip(job_ids, job_states)) + return [] + + def get_next_run_time(self): + next_run_time = self.redis.zrange(self.run_times_key, 0, 0, withscores=True) + if next_run_time: + return utc_timestamp_to_datetime(next_run_time[0][1]) + + def get_all_jobs(self): + job_states = self.redis.hgetall(self.jobs_key) + jobs = self._reconstitute_jobs(six.iteritems(job_states)) + paused_sort_key = datetime(9999, 12, 31, tzinfo=utc) + return sorted(jobs, key=lambda job: job.next_run_time or paused_sort_key) + + def add_job(self, job): + if self.redis.hexists(self.jobs_key, job.id): + raise ConflictingIdError(job.id) + + with self.redis.pipeline() as pipe: + pipe.multi() + pipe.hset(self.jobs_key, job.id, pickle.dumps(job.__getstate__(), + self.pickle_protocol)) + if job.next_run_time: + pipe.zadd(self.run_times_key, + {job.id: datetime_to_utc_timestamp(job.next_run_time)}) + + pipe.execute() + + def update_job(self, job): + if not self.redis.hexists(self.jobs_key, job.id): + raise JobLookupError(job.id) + + with self.redis.pipeline() as pipe: + pipe.hset(self.jobs_key, job.id, pickle.dumps(job.__getstate__(), + self.pickle_protocol)) + if job.next_run_time: + pipe.zadd(self.run_times_key, + {job.id: datetime_to_utc_timestamp(job.next_run_time)}) + else: + pipe.zrem(self.run_times_key, job.id) + + pipe.execute() + + def remove_job(self, job_id): + if not self.redis.hexists(self.jobs_key, job_id): + raise JobLookupError(job_id) + + with self.redis.pipeline() as pipe: + pipe.hdel(self.jobs_key, job_id) + pipe.zrem(self.run_times_key, job_id) + pipe.execute() + + def remove_all_jobs(self): + with self.redis.pipeline() as pipe: + pipe.delete(self.jobs_key) + pipe.delete(self.run_times_key) + pipe.execute() + + def shutdown(self): + self.redis.connection_pool.disconnect() + + def _reconstitute_job(self, job_state): + job_state = pickle.loads(job_state) + job = Job.__new__(Job) + job.__setstate__(job_state) + job._scheduler = self._scheduler + job._jobstore_alias = self._alias + return job + + def _reconstitute_jobs(self, job_states): + jobs = [] + failed_job_ids = [] + for job_id, job_state in job_states: + try: + jobs.append(self._reconstitute_job(job_state)) + except BaseException: + self._logger.exception('Unable to restore job "%s" -- removing it', job_id) + failed_job_ids.append(job_id) + + # Remove all the jobs we failed to restore + if failed_job_ids: + with self.redis.pipeline() as pipe: + pipe.hdel(self.jobs_key, *failed_job_ids) + pipe.zrem(self.run_times_key, *failed_job_ids) + pipe.execute() + + return jobs + + def __repr__(self): + return '<%s>' % self.__class__.__name__ diff --git a/venv/lib/python3.8/site-packages/apscheduler/jobstores/rethinkdb.py b/venv/lib/python3.8/site-packages/apscheduler/jobstores/rethinkdb.py new file mode 100644 index 0000000..d8a78cd --- /dev/null +++ b/venv/lib/python3.8/site-packages/apscheduler/jobstores/rethinkdb.py @@ -0,0 +1,155 @@ +from __future__ import absolute_import + +from apscheduler.jobstores.base import BaseJobStore, JobLookupError, ConflictingIdError +from apscheduler.util import maybe_ref, datetime_to_utc_timestamp, utc_timestamp_to_datetime +from apscheduler.job import Job + +try: + import cPickle as pickle +except ImportError: # pragma: nocover + import pickle + +try: + from rethinkdb import RethinkDB +except ImportError: # pragma: nocover + raise ImportError('RethinkDBJobStore requires rethinkdb installed') + + +class RethinkDBJobStore(BaseJobStore): + """ + Stores jobs in a RethinkDB database. Any leftover keyword arguments are directly passed to + rethinkdb's `RethinkdbClient `_. + + Plugin alias: ``rethinkdb`` + + :param str database: database to store jobs in + :param str collection: collection to store jobs in + :param client: a :class:`rethinkdb.net.Connection` instance to use instead of providing + connection arguments + :param int pickle_protocol: pickle protocol level to use (for serialization), defaults to the + highest available + """ + + def __init__(self, database='apscheduler', table='jobs', client=None, + pickle_protocol=pickle.HIGHEST_PROTOCOL, **connect_args): + super(RethinkDBJobStore, self).__init__() + + if not database: + raise ValueError('The "database" parameter must not be empty') + if not table: + raise ValueError('The "table" parameter must not be empty') + + self.database = database + self.table_name = table + self.table = None + self.client = client + self.pickle_protocol = pickle_protocol + self.connect_args = connect_args + self.r = RethinkDB() + self.conn = None + + def start(self, scheduler, alias): + super(RethinkDBJobStore, self).start(scheduler, alias) + + if self.client: + self.conn = maybe_ref(self.client) + else: + self.conn = self.r.connect(db=self.database, **self.connect_args) + + if self.database not in self.r.db_list().run(self.conn): + self.r.db_create(self.database).run(self.conn) + + if self.table_name not in self.r.table_list().run(self.conn): + self.r.table_create(self.table_name).run(self.conn) + + if 'next_run_time' not in self.r.table(self.table_name).index_list().run(self.conn): + self.r.table(self.table_name).index_create('next_run_time').run(self.conn) + + self.table = self.r.db(self.database).table(self.table_name) + + def lookup_job(self, job_id): + results = list(self.table.get_all(job_id).pluck('job_state').run(self.conn)) + return self._reconstitute_job(results[0]['job_state']) if results else None + + def get_due_jobs(self, now): + return self._get_jobs(self.r.row['next_run_time'] <= datetime_to_utc_timestamp(now)) + + def get_next_run_time(self): + results = list( + self.table + .filter(self.r.row['next_run_time'] != None) # noqa + .order_by(self.r.asc('next_run_time')) + .map(lambda x: x['next_run_time']) + .limit(1) + .run(self.conn) + ) + return utc_timestamp_to_datetime(results[0]) if results else None + + def get_all_jobs(self): + jobs = self._get_jobs() + self._fix_paused_jobs_sorting(jobs) + return jobs + + def add_job(self, job): + job_dict = { + 'id': job.id, + 'next_run_time': datetime_to_utc_timestamp(job.next_run_time), + 'job_state': self.r.binary(pickle.dumps(job.__getstate__(), self.pickle_protocol)) + } + results = self.table.insert(job_dict).run(self.conn) + if results['errors'] > 0: + raise ConflictingIdError(job.id) + + def update_job(self, job): + changes = { + 'next_run_time': datetime_to_utc_timestamp(job.next_run_time), + 'job_state': self.r.binary(pickle.dumps(job.__getstate__(), self.pickle_protocol)) + } + results = self.table.get_all(job.id).update(changes).run(self.conn) + skipped = False in map(lambda x: results[x] == 0, results.keys()) + if results['skipped'] > 0 or results['errors'] > 0 or not skipped: + raise JobLookupError(job.id) + + def remove_job(self, job_id): + results = self.table.get_all(job_id).delete().run(self.conn) + if results['deleted'] + results['skipped'] != 1: + raise JobLookupError(job_id) + + def remove_all_jobs(self): + self.table.delete().run(self.conn) + + def shutdown(self): + self.conn.close() + + def _reconstitute_job(self, job_state): + job_state = pickle.loads(job_state) + job = Job.__new__(Job) + job.__setstate__(job_state) + job._scheduler = self._scheduler + job._jobstore_alias = self._alias + return job + + def _get_jobs(self, predicate=None): + jobs = [] + failed_job_ids = [] + query = (self.table.filter(self.r.row['next_run_time'] != None).filter(predicate) # noqa + if predicate else self.table) + query = query.order_by('next_run_time', 'id').pluck('id', 'job_state') + + for document in query.run(self.conn): + try: + jobs.append(self._reconstitute_job(document['job_state'])) + except Exception: + self._logger.exception('Unable to restore job "%s" -- removing it', document['id']) + failed_job_ids.append(document['id']) + + # Remove all the jobs we failed to restore + if failed_job_ids: + self.r.expr(failed_job_ids).for_each( + lambda job_id: self.table.get_all(job_id).delete()).run(self.conn) + + return jobs + + def __repr__(self): + connection = self.conn + return '<%s (connection=%s)>' % (self.__class__.__name__, connection) diff --git a/venv/lib/python3.8/site-packages/apscheduler/jobstores/sqlalchemy.py b/venv/lib/python3.8/site-packages/apscheduler/jobstores/sqlalchemy.py new file mode 100644 index 0000000..fecbd83 --- /dev/null +++ b/venv/lib/python3.8/site-packages/apscheduler/jobstores/sqlalchemy.py @@ -0,0 +1,154 @@ +from __future__ import absolute_import + +from apscheduler.jobstores.base import BaseJobStore, JobLookupError, ConflictingIdError +from apscheduler.util import maybe_ref, datetime_to_utc_timestamp, utc_timestamp_to_datetime +from apscheduler.job import Job + +try: + import cPickle as pickle +except ImportError: # pragma: nocover + import pickle + +try: + from sqlalchemy import ( + create_engine, Table, Column, MetaData, Unicode, Float, LargeBinary, select) + from sqlalchemy.exc import IntegrityError + from sqlalchemy.sql.expression import null +except ImportError: # pragma: nocover + raise ImportError('SQLAlchemyJobStore requires SQLAlchemy installed') + + +class SQLAlchemyJobStore(BaseJobStore): + """ + Stores jobs in a database table using SQLAlchemy. + The table will be created if it doesn't exist in the database. + + Plugin alias: ``sqlalchemy`` + + :param str url: connection string (see + :ref:`SQLAlchemy documentation ` on this) + :param engine: an SQLAlchemy :class:`~sqlalchemy.engine.Engine` to use instead of creating a + new one based on ``url`` + :param str tablename: name of the table to store jobs in + :param metadata: a :class:`~sqlalchemy.schema.MetaData` instance to use instead of creating a + new one + :param int pickle_protocol: pickle protocol level to use (for serialization), defaults to the + highest available + :param str tableschema: name of the (existing) schema in the target database where the table + should be + :param dict engine_options: keyword arguments to :func:`~sqlalchemy.create_engine` + (ignored if ``engine`` is given) + """ + + def __init__(self, url=None, engine=None, tablename='apscheduler_jobs', metadata=None, + pickle_protocol=pickle.HIGHEST_PROTOCOL, tableschema=None, engine_options=None): + super(SQLAlchemyJobStore, self).__init__() + self.pickle_protocol = pickle_protocol + metadata = maybe_ref(metadata) or MetaData() + + if engine: + self.engine = maybe_ref(engine) + elif url: + self.engine = create_engine(url, **(engine_options or {})) + else: + raise ValueError('Need either "engine" or "url" defined') + + # 191 = max key length in MySQL for InnoDB/utf8mb4 tables, + # 25 = precision that translates to an 8-byte float + self.jobs_t = Table( + tablename, metadata, + Column('id', Unicode(191, _warn_on_bytestring=False), primary_key=True), + Column('next_run_time', Float(25), index=True), + Column('job_state', LargeBinary, nullable=False), + schema=tableschema + ) + + def start(self, scheduler, alias): + super(SQLAlchemyJobStore, self).start(scheduler, alias) + self.jobs_t.create(self.engine, True) + + def lookup_job(self, job_id): + selectable = select([self.jobs_t.c.job_state]).where(self.jobs_t.c.id == job_id) + job_state = self.engine.execute(selectable).scalar() + return self._reconstitute_job(job_state) if job_state else None + + def get_due_jobs(self, now): + timestamp = datetime_to_utc_timestamp(now) + return self._get_jobs(self.jobs_t.c.next_run_time <= timestamp) + + def get_next_run_time(self): + selectable = select([self.jobs_t.c.next_run_time]).\ + where(self.jobs_t.c.next_run_time != null()).\ + order_by(self.jobs_t.c.next_run_time).limit(1) + next_run_time = self.engine.execute(selectable).scalar() + return utc_timestamp_to_datetime(next_run_time) + + def get_all_jobs(self): + jobs = self._get_jobs() + self._fix_paused_jobs_sorting(jobs) + return jobs + + def add_job(self, job): + insert = self.jobs_t.insert().values(**{ + 'id': job.id, + 'next_run_time': datetime_to_utc_timestamp(job.next_run_time), + 'job_state': pickle.dumps(job.__getstate__(), self.pickle_protocol) + }) + try: + self.engine.execute(insert) + except IntegrityError: + raise ConflictingIdError(job.id) + + def update_job(self, job): + update = self.jobs_t.update().values(**{ + 'next_run_time': datetime_to_utc_timestamp(job.next_run_time), + 'job_state': pickle.dumps(job.__getstate__(), self.pickle_protocol) + }).where(self.jobs_t.c.id == job.id) + result = self.engine.execute(update) + if result.rowcount == 0: + raise JobLookupError(job.id) + + def remove_job(self, job_id): + delete = self.jobs_t.delete().where(self.jobs_t.c.id == job_id) + result = self.engine.execute(delete) + if result.rowcount == 0: + raise JobLookupError(job_id) + + def remove_all_jobs(self): + delete = self.jobs_t.delete() + self.engine.execute(delete) + + def shutdown(self): + self.engine.dispose() + + def _reconstitute_job(self, job_state): + job_state = pickle.loads(job_state) + job_state['jobstore'] = self + job = Job.__new__(Job) + job.__setstate__(job_state) + job._scheduler = self._scheduler + job._jobstore_alias = self._alias + return job + + def _get_jobs(self, *conditions): + jobs = [] + selectable = select([self.jobs_t.c.id, self.jobs_t.c.job_state]).\ + order_by(self.jobs_t.c.next_run_time) + selectable = selectable.where(*conditions) if conditions else selectable + failed_job_ids = set() + for row in self.engine.execute(selectable): + try: + jobs.append(self._reconstitute_job(row.job_state)) + except BaseException: + self._logger.exception('Unable to restore job "%s" -- removing it', row.id) + failed_job_ids.add(row.id) + + # Remove all the jobs we failed to restore + if failed_job_ids: + delete = self.jobs_t.delete().where(self.jobs_t.c.id.in_(failed_job_ids)) + self.engine.execute(delete) + + return jobs + + def __repr__(self): + return '<%s (url=%s)>' % (self.__class__.__name__, self.engine.url) diff --git a/venv/lib/python3.8/site-packages/apscheduler/jobstores/zookeeper.py b/venv/lib/python3.8/site-packages/apscheduler/jobstores/zookeeper.py new file mode 100644 index 0000000..2cca83e --- /dev/null +++ b/venv/lib/python3.8/site-packages/apscheduler/jobstores/zookeeper.py @@ -0,0 +1,179 @@ +from __future__ import absolute_import + +import os +from datetime import datetime + +from pytz import utc +from kazoo.exceptions import NoNodeError, NodeExistsError + +from apscheduler.jobstores.base import BaseJobStore, JobLookupError, ConflictingIdError +from apscheduler.util import maybe_ref, datetime_to_utc_timestamp, utc_timestamp_to_datetime +from apscheduler.job import Job + +try: + import cPickle as pickle +except ImportError: # pragma: nocover + import pickle + +try: + from kazoo.client import KazooClient +except ImportError: # pragma: nocover + raise ImportError('ZooKeeperJobStore requires Kazoo installed') + + +class ZooKeeperJobStore(BaseJobStore): + """ + Stores jobs in a ZooKeeper tree. Any leftover keyword arguments are directly passed to + kazoo's `KazooClient + `_. + + Plugin alias: ``zookeeper`` + + :param str path: path to store jobs in + :param client: a :class:`~kazoo.client.KazooClient` instance to use instead of + providing connection arguments + :param int pickle_protocol: pickle protocol level to use (for serialization), defaults to the + highest available + """ + + def __init__(self, path='/apscheduler', client=None, close_connection_on_exit=False, + pickle_protocol=pickle.HIGHEST_PROTOCOL, **connect_args): + super(ZooKeeperJobStore, self).__init__() + self.pickle_protocol = pickle_protocol + self.close_connection_on_exit = close_connection_on_exit + + if not path: + raise ValueError('The "path" parameter must not be empty') + + self.path = path + + if client: + self.client = maybe_ref(client) + else: + self.client = KazooClient(**connect_args) + self._ensured_path = False + + def _ensure_paths(self): + if not self._ensured_path: + self.client.ensure_path(self.path) + self._ensured_path = True + + def start(self, scheduler, alias): + super(ZooKeeperJobStore, self).start(scheduler, alias) + if not self.client.connected: + self.client.start() + + def lookup_job(self, job_id): + self._ensure_paths() + node_path = os.path.join(self.path, job_id) + try: + content, _ = self.client.get(node_path) + doc = pickle.loads(content) + job = self._reconstitute_job(doc['job_state']) + return job + except BaseException: + return None + + def get_due_jobs(self, now): + timestamp = datetime_to_utc_timestamp(now) + jobs = [job_def['job'] for job_def in self._get_jobs() + if job_def['next_run_time'] is not None and job_def['next_run_time'] <= timestamp] + return jobs + + def get_next_run_time(self): + next_runs = [job_def['next_run_time'] for job_def in self._get_jobs() + if job_def['next_run_time'] is not None] + return utc_timestamp_to_datetime(min(next_runs)) if len(next_runs) > 0 else None + + def get_all_jobs(self): + jobs = [job_def['job'] for job_def in self._get_jobs()] + self._fix_paused_jobs_sorting(jobs) + return jobs + + def add_job(self, job): + self._ensure_paths() + node_path = os.path.join(self.path, str(job.id)) + value = { + 'next_run_time': datetime_to_utc_timestamp(job.next_run_time), + 'job_state': job.__getstate__() + } + data = pickle.dumps(value, self.pickle_protocol) + try: + self.client.create(node_path, value=data) + except NodeExistsError: + raise ConflictingIdError(job.id) + + def update_job(self, job): + self._ensure_paths() + node_path = os.path.join(self.path, str(job.id)) + changes = { + 'next_run_time': datetime_to_utc_timestamp(job.next_run_time), + 'job_state': job.__getstate__() + } + data = pickle.dumps(changes, self.pickle_protocol) + try: + self.client.set(node_path, value=data) + except NoNodeError: + raise JobLookupError(job.id) + + def remove_job(self, job_id): + self._ensure_paths() + node_path = os.path.join(self.path, str(job_id)) + try: + self.client.delete(node_path) + except NoNodeError: + raise JobLookupError(job_id) + + def remove_all_jobs(self): + try: + self.client.delete(self.path, recursive=True) + except NoNodeError: + pass + self._ensured_path = False + + def shutdown(self): + if self.close_connection_on_exit: + self.client.stop() + self.client.close() + + def _reconstitute_job(self, job_state): + job_state = job_state + job = Job.__new__(Job) + job.__setstate__(job_state) + job._scheduler = self._scheduler + job._jobstore_alias = self._alias + return job + + def _get_jobs(self): + self._ensure_paths() + jobs = [] + failed_job_ids = [] + all_ids = self.client.get_children(self.path) + for node_name in all_ids: + try: + node_path = os.path.join(self.path, node_name) + content, _ = self.client.get(node_path) + doc = pickle.loads(content) + job_def = { + 'job_id': node_name, + 'next_run_time': doc['next_run_time'] if doc['next_run_time'] else None, + 'job_state': doc['job_state'], + 'job': self._reconstitute_job(doc['job_state']), + 'creation_time': _.ctime + } + jobs.append(job_def) + except BaseException: + self._logger.exception('Unable to restore job "%s" -- removing it' % node_name) + failed_job_ids.append(node_name) + + # Remove all the jobs we failed to restore + if failed_job_ids: + for failed_id in failed_job_ids: + self.remove_job(failed_id) + paused_sort_key = datetime(9999, 12, 31, tzinfo=utc) + return sorted(jobs, key=lambda job_def: (job_def['job'].next_run_time or paused_sort_key, + job_def['creation_time'])) + + def __repr__(self): + self._logger.exception('<%s (client=%s)>' % (self.__class__.__name__, self.client)) + return '<%s (client=%s)>' % (self.__class__.__name__, self.client) diff --git a/venv/lib/python3.8/site-packages/apscheduler/schedulers/__init__.py b/venv/lib/python3.8/site-packages/apscheduler/schedulers/__init__.py new file mode 100644 index 0000000..bd8a790 --- /dev/null +++ b/venv/lib/python3.8/site-packages/apscheduler/schedulers/__init__.py @@ -0,0 +1,12 @@ +class SchedulerAlreadyRunningError(Exception): + """Raised when attempting to start or configure the scheduler when it's already running.""" + + def __str__(self): + return 'Scheduler is already running' + + +class SchedulerNotRunningError(Exception): + """Raised when attempting to shutdown the scheduler when it's not running.""" + + def __str__(self): + return 'Scheduler is not running' diff --git a/venv/lib/python3.8/site-packages/apscheduler/schedulers/asyncio.py b/venv/lib/python3.8/site-packages/apscheduler/schedulers/asyncio.py new file mode 100644 index 0000000..289ef13 --- /dev/null +++ b/venv/lib/python3.8/site-packages/apscheduler/schedulers/asyncio.py @@ -0,0 +1,68 @@ +from __future__ import absolute_import +from functools import wraps, partial + +from apscheduler.schedulers.base import BaseScheduler +from apscheduler.util import maybe_ref + +try: + import asyncio +except ImportError: # pragma: nocover + try: + import trollius as asyncio + except ImportError: + raise ImportError( + 'AsyncIOScheduler requires either Python 3.4 or the asyncio package installed') + + +def run_in_event_loop(func): + @wraps(func) + def wrapper(self, *args, **kwargs): + wrapped = partial(func, self, *args, **kwargs) + self._eventloop.call_soon_threadsafe(wrapped) + return wrapper + + +class AsyncIOScheduler(BaseScheduler): + """ + A scheduler that runs on an asyncio (:pep:`3156`) event loop. + + The default executor can run jobs based on native coroutines (``async def``). + + Extra options: + + ============== ============================================================= + ``event_loop`` AsyncIO event loop to use (defaults to the global event loop) + ============== ============================================================= + """ + + _eventloop = None + _timeout = None + + @run_in_event_loop + def shutdown(self, wait=True): + super(AsyncIOScheduler, self).shutdown(wait) + self._stop_timer() + + def _configure(self, config): + self._eventloop = maybe_ref(config.pop('event_loop', None)) or asyncio.get_event_loop() + super(AsyncIOScheduler, self)._configure(config) + + def _start_timer(self, wait_seconds): + self._stop_timer() + if wait_seconds is not None: + self._timeout = self._eventloop.call_later(wait_seconds, self.wakeup) + + def _stop_timer(self): + if self._timeout: + self._timeout.cancel() + del self._timeout + + @run_in_event_loop + def wakeup(self): + self._stop_timer() + wait_seconds = self._process_jobs() + self._start_timer(wait_seconds) + + def _create_default_executor(self): + from apscheduler.executors.asyncio import AsyncIOExecutor + return AsyncIOExecutor() diff --git a/venv/lib/python3.8/site-packages/apscheduler/schedulers/background.py b/venv/lib/python3.8/site-packages/apscheduler/schedulers/background.py new file mode 100644 index 0000000..03f2982 --- /dev/null +++ b/venv/lib/python3.8/site-packages/apscheduler/schedulers/background.py @@ -0,0 +1,41 @@ +from __future__ import absolute_import + +from threading import Thread, Event + +from apscheduler.schedulers.base import BaseScheduler +from apscheduler.schedulers.blocking import BlockingScheduler +from apscheduler.util import asbool + + +class BackgroundScheduler(BlockingScheduler): + """ + A scheduler that runs in the background using a separate thread + (:meth:`~apscheduler.schedulers.base.BaseScheduler.start` will return immediately). + + Extra options: + + ========== ============================================================================= + ``daemon`` Set the ``daemon`` option in the background thread (defaults to ``True``, see + `the documentation + `_ + for further details) + ========== ============================================================================= + """ + + _thread = None + + def _configure(self, config): + self._daemon = asbool(config.pop('daemon', True)) + super(BackgroundScheduler, self)._configure(config) + + def start(self, *args, **kwargs): + self._event = Event() + BaseScheduler.start(self, *args, **kwargs) + self._thread = Thread(target=self._main_loop, name='APScheduler') + self._thread.daemon = self._daemon + self._thread.start() + + def shutdown(self, *args, **kwargs): + super(BackgroundScheduler, self).shutdown(*args, **kwargs) + self._thread.join() + del self._thread diff --git a/venv/lib/python3.8/site-packages/apscheduler/schedulers/base.py b/venv/lib/python3.8/site-packages/apscheduler/schedulers/base.py new file mode 100644 index 0000000..8e71154 --- /dev/null +++ b/venv/lib/python3.8/site-packages/apscheduler/schedulers/base.py @@ -0,0 +1,1022 @@ +from __future__ import print_function + +from abc import ABCMeta, abstractmethod +from threading import RLock +from datetime import datetime, timedelta +from logging import getLogger +import warnings +import sys + +from pkg_resources import iter_entry_points +from tzlocal import get_localzone +import six + +from apscheduler.schedulers import SchedulerAlreadyRunningError, SchedulerNotRunningError +from apscheduler.executors.base import MaxInstancesReachedError, BaseExecutor +from apscheduler.executors.pool import ThreadPoolExecutor +from apscheduler.jobstores.base import ConflictingIdError, JobLookupError, BaseJobStore +from apscheduler.jobstores.memory import MemoryJobStore +from apscheduler.job import Job +from apscheduler.triggers.base import BaseTrigger +from apscheduler.util import ( + asbool, asint, astimezone, maybe_ref, timedelta_seconds, undefined, TIMEOUT_MAX) +from apscheduler.events import ( + SchedulerEvent, JobEvent, JobSubmissionEvent, EVENT_SCHEDULER_START, EVENT_SCHEDULER_SHUTDOWN, + EVENT_JOBSTORE_ADDED, EVENT_JOBSTORE_REMOVED, EVENT_ALL, EVENT_JOB_MODIFIED, EVENT_JOB_REMOVED, + EVENT_JOB_ADDED, EVENT_EXECUTOR_ADDED, EVENT_EXECUTOR_REMOVED, EVENT_ALL_JOBS_REMOVED, + EVENT_JOB_SUBMITTED, EVENT_JOB_MAX_INSTANCES, EVENT_SCHEDULER_RESUMED, EVENT_SCHEDULER_PAUSED) + +try: + from collections.abc import MutableMapping +except ImportError: + from collections import MutableMapping + +#: constant indicating a scheduler's stopped state +STATE_STOPPED = 0 +#: constant indicating a scheduler's running state (started and processing jobs) +STATE_RUNNING = 1 +#: constant indicating a scheduler's paused state (started but not processing jobs) +STATE_PAUSED = 2 + + +class BaseScheduler(six.with_metaclass(ABCMeta)): + """ + Abstract base class for all schedulers. + + Takes the following keyword arguments: + + :param str|logging.Logger logger: logger to use for the scheduler's logging (defaults to + apscheduler.scheduler) + :param str|datetime.tzinfo timezone: the default time zone (defaults to the local timezone) + :param int|float jobstore_retry_interval: the minimum number of seconds to wait between + retries in the scheduler's main loop if the job store raises an exception when getting + the list of due jobs + :param dict job_defaults: default values for newly added jobs + :param dict jobstores: a dictionary of job store alias -> job store instance or configuration + dict + :param dict executors: a dictionary of executor alias -> executor instance or configuration + dict + + :ivar int state: current running state of the scheduler (one of the following constants from + ``apscheduler.schedulers.base``: ``STATE_STOPPED``, ``STATE_RUNNING``, ``STATE_PAUSED``) + + .. seealso:: :ref:`scheduler-config` + """ + + _trigger_plugins = dict((ep.name, ep) for ep in iter_entry_points('apscheduler.triggers')) + _trigger_classes = {} + _executor_plugins = dict((ep.name, ep) for ep in iter_entry_points('apscheduler.executors')) + _executor_classes = {} + _jobstore_plugins = dict((ep.name, ep) for ep in iter_entry_points('apscheduler.jobstores')) + _jobstore_classes = {} + + # + # Public API + # + + def __init__(self, gconfig={}, **options): + super(BaseScheduler, self).__init__() + self._executors = {} + self._executors_lock = self._create_lock() + self._jobstores = {} + self._jobstores_lock = self._create_lock() + self._listeners = [] + self._listeners_lock = self._create_lock() + self._pending_jobs = [] + self.state = STATE_STOPPED + self.configure(gconfig, **options) + + def configure(self, gconfig={}, prefix='apscheduler.', **options): + """ + Reconfigures the scheduler with the given options. + + Can only be done when the scheduler isn't running. + + :param dict gconfig: a "global" configuration dictionary whose values can be overridden by + keyword arguments to this method + :param str|unicode prefix: pick only those keys from ``gconfig`` that are prefixed with + this string (pass an empty string or ``None`` to use all keys) + :raises SchedulerAlreadyRunningError: if the scheduler is already running + + """ + if self.state != STATE_STOPPED: + raise SchedulerAlreadyRunningError + + # If a non-empty prefix was given, strip it from the keys in the + # global configuration dict + if prefix: + prefixlen = len(prefix) + gconfig = dict((key[prefixlen:], value) for key, value in six.iteritems(gconfig) + if key.startswith(prefix)) + + # Create a structure from the dotted options + # (e.g. "a.b.c = d" -> {'a': {'b': {'c': 'd'}}}) + config = {} + for key, value in six.iteritems(gconfig): + parts = key.split('.') + parent = config + key = parts.pop(0) + while parts: + parent = parent.setdefault(key, {}) + key = parts.pop(0) + parent[key] = value + + # Override any options with explicit keyword arguments + config.update(options) + self._configure(config) + + def start(self, paused=False): + """ + Start the configured executors and job stores and begin processing scheduled jobs. + + :param bool paused: if ``True``, don't start job processing until :meth:`resume` is called + :raises SchedulerAlreadyRunningError: if the scheduler is already running + :raises RuntimeError: if running under uWSGI with threads disabled + + """ + if self.state != STATE_STOPPED: + raise SchedulerAlreadyRunningError + + self._check_uwsgi() + + with self._executors_lock: + # Create a default executor if nothing else is configured + if 'default' not in self._executors: + self.add_executor(self._create_default_executor(), 'default') + + # Start all the executors + for alias, executor in six.iteritems(self._executors): + executor.start(self, alias) + + with self._jobstores_lock: + # Create a default job store if nothing else is configured + if 'default' not in self._jobstores: + self.add_jobstore(self._create_default_jobstore(), 'default') + + # Start all the job stores + for alias, store in six.iteritems(self._jobstores): + store.start(self, alias) + + # Schedule all pending jobs + for job, jobstore_alias, replace_existing in self._pending_jobs: + self._real_add_job(job, jobstore_alias, replace_existing) + del self._pending_jobs[:] + + self.state = STATE_PAUSED if paused else STATE_RUNNING + self._logger.info('Scheduler started') + self._dispatch_event(SchedulerEvent(EVENT_SCHEDULER_START)) + + if not paused: + self.wakeup() + + @abstractmethod + def shutdown(self, wait=True): + """ + Shuts down the scheduler, along with its executors and job stores. + + Does not interrupt any currently running jobs. + + :param bool wait: ``True`` to wait until all currently executing jobs have finished + :raises SchedulerNotRunningError: if the scheduler has not been started yet + + """ + if self.state == STATE_STOPPED: + raise SchedulerNotRunningError + + self.state = STATE_STOPPED + + # Shut down all executors + with self._executors_lock: + for executor in six.itervalues(self._executors): + executor.shutdown(wait) + + # Shut down all job stores + with self._jobstores_lock: + for jobstore in six.itervalues(self._jobstores): + jobstore.shutdown() + + self._logger.info('Scheduler has been shut down') + self._dispatch_event(SchedulerEvent(EVENT_SCHEDULER_SHUTDOWN)) + + def pause(self): + """ + Pause job processing in the scheduler. + + This will prevent the scheduler from waking up to do job processing until :meth:`resume` + is called. It will not however stop any already running job processing. + + """ + if self.state == STATE_STOPPED: + raise SchedulerNotRunningError + elif self.state == STATE_RUNNING: + self.state = STATE_PAUSED + self._logger.info('Paused scheduler job processing') + self._dispatch_event(SchedulerEvent(EVENT_SCHEDULER_PAUSED)) + + def resume(self): + """Resume job processing in the scheduler.""" + if self.state == STATE_STOPPED: + raise SchedulerNotRunningError + elif self.state == STATE_PAUSED: + self.state = STATE_RUNNING + self._logger.info('Resumed scheduler job processing') + self._dispatch_event(SchedulerEvent(EVENT_SCHEDULER_RESUMED)) + self.wakeup() + + @property + def running(self): + """ + Return ``True`` if the scheduler has been started. + + This is a shortcut for ``scheduler.state != STATE_STOPPED``. + + """ + return self.state != STATE_STOPPED + + def add_executor(self, executor, alias='default', **executor_opts): + """ + Adds an executor to this scheduler. + + Any extra keyword arguments will be passed to the executor plugin's constructor, assuming + that the first argument is the name of an executor plugin. + + :param str|unicode|apscheduler.executors.base.BaseExecutor executor: either an executor + instance or the name of an executor plugin + :param str|unicode alias: alias for the scheduler + :raises ValueError: if there is already an executor by the given alias + + """ + with self._executors_lock: + if alias in self._executors: + raise ValueError('This scheduler already has an executor by the alias of "%s"' % + alias) + + if isinstance(executor, BaseExecutor): + self._executors[alias] = executor + elif isinstance(executor, six.string_types): + self._executors[alias] = executor = self._create_plugin_instance( + 'executor', executor, executor_opts) + else: + raise TypeError('Expected an executor instance or a string, got %s instead' % + executor.__class__.__name__) + + # Start the executor right away if the scheduler is running + if self.state != STATE_STOPPED: + executor.start(self, alias) + + self._dispatch_event(SchedulerEvent(EVENT_EXECUTOR_ADDED, alias)) + + def remove_executor(self, alias, shutdown=True): + """ + Removes the executor by the given alias from this scheduler. + + :param str|unicode alias: alias of the executor + :param bool shutdown: ``True`` to shut down the executor after + removing it + + """ + with self._executors_lock: + executor = self._lookup_executor(alias) + del self._executors[alias] + + if shutdown: + executor.shutdown() + + self._dispatch_event(SchedulerEvent(EVENT_EXECUTOR_REMOVED, alias)) + + def add_jobstore(self, jobstore, alias='default', **jobstore_opts): + """ + Adds a job store to this scheduler. + + Any extra keyword arguments will be passed to the job store plugin's constructor, assuming + that the first argument is the name of a job store plugin. + + :param str|unicode|apscheduler.jobstores.base.BaseJobStore jobstore: job store to be added + :param str|unicode alias: alias for the job store + :raises ValueError: if there is already a job store by the given alias + + """ + with self._jobstores_lock: + if alias in self._jobstores: + raise ValueError('This scheduler already has a job store by the alias of "%s"' % + alias) + + if isinstance(jobstore, BaseJobStore): + self._jobstores[alias] = jobstore + elif isinstance(jobstore, six.string_types): + self._jobstores[alias] = jobstore = self._create_plugin_instance( + 'jobstore', jobstore, jobstore_opts) + else: + raise TypeError('Expected a job store instance or a string, got %s instead' % + jobstore.__class__.__name__) + + # Start the job store right away if the scheduler isn't stopped + if self.state != STATE_STOPPED: + jobstore.start(self, alias) + + # Notify listeners that a new job store has been added + self._dispatch_event(SchedulerEvent(EVENT_JOBSTORE_ADDED, alias)) + + # Notify the scheduler so it can scan the new job store for jobs + if self.state != STATE_STOPPED: + self.wakeup() + + def remove_jobstore(self, alias, shutdown=True): + """ + Removes the job store by the given alias from this scheduler. + + :param str|unicode alias: alias of the job store + :param bool shutdown: ``True`` to shut down the job store after removing it + + """ + with self._jobstores_lock: + jobstore = self._lookup_jobstore(alias) + del self._jobstores[alias] + + if shutdown: + jobstore.shutdown() + + self._dispatch_event(SchedulerEvent(EVENT_JOBSTORE_REMOVED, alias)) + + def add_listener(self, callback, mask=EVENT_ALL): + """ + add_listener(callback, mask=EVENT_ALL) + + Adds a listener for scheduler events. + + When a matching event occurs, ``callback`` is executed with the event object as its + sole argument. If the ``mask`` parameter is not provided, the callback will receive events + of all types. + + :param callback: any callable that takes one argument + :param int mask: bitmask that indicates which events should be + listened to + + .. seealso:: :mod:`apscheduler.events` + .. seealso:: :ref:`scheduler-events` + + """ + with self._listeners_lock: + self._listeners.append((callback, mask)) + + def remove_listener(self, callback): + """Removes a previously added event listener.""" + + with self._listeners_lock: + for i, (cb, _) in enumerate(self._listeners): + if callback == cb: + del self._listeners[i] + + def add_job(self, func, trigger=None, args=None, kwargs=None, id=None, name=None, + misfire_grace_time=undefined, coalesce=undefined, max_instances=undefined, + next_run_time=undefined, jobstore='default', executor='default', + replace_existing=False, **trigger_args): + """ + add_job(func, trigger=None, args=None, kwargs=None, id=None, \ + name=None, misfire_grace_time=undefined, coalesce=undefined, \ + max_instances=undefined, next_run_time=undefined, \ + jobstore='default', executor='default', \ + replace_existing=False, **trigger_args) + + Adds the given job to the job list and wakes up the scheduler if it's already running. + + Any option that defaults to ``undefined`` will be replaced with the corresponding default + value when the job is scheduled (which happens when the scheduler is started, or + immediately if the scheduler is already running). + + The ``func`` argument can be given either as a callable object or a textual reference in + the ``package.module:some.object`` format, where the first half (separated by ``:``) is an + importable module and the second half is a reference to the callable object, relative to + the module. + + The ``trigger`` argument can either be: + #. the alias name of the trigger (e.g. ``date``, ``interval`` or ``cron``), in which case + any extra keyword arguments to this method are passed on to the trigger's constructor + #. an instance of a trigger class + + :param func: callable (or a textual reference to one) to run at the given time + :param str|apscheduler.triggers.base.BaseTrigger trigger: trigger that determines when + ``func`` is called + :param list|tuple args: list of positional arguments to call func with + :param dict kwargs: dict of keyword arguments to call func with + :param str|unicode id: explicit identifier for the job (for modifying it later) + :param str|unicode name: textual description of the job + :param int misfire_grace_time: seconds after the designated runtime that the job is still + allowed to be run + :param bool coalesce: run once instead of many times if the scheduler determines that the + job should be run more than once in succession + :param int max_instances: maximum number of concurrently running instances allowed for this + job + :param datetime next_run_time: when to first run the job, regardless of the trigger (pass + ``None`` to add the job as paused) + :param str|unicode jobstore: alias of the job store to store the job in + :param str|unicode executor: alias of the executor to run the job with + :param bool replace_existing: ``True`` to replace an existing job with the same ``id`` + (but retain the number of runs from the existing one) + :rtype: Job + + """ + job_kwargs = { + 'trigger': self._create_trigger(trigger, trigger_args), + 'executor': executor, + 'func': func, + 'args': tuple(args) if args is not None else (), + 'kwargs': dict(kwargs) if kwargs is not None else {}, + 'id': id, + 'name': name, + 'misfire_grace_time': misfire_grace_time, + 'coalesce': coalesce, + 'max_instances': max_instances, + 'next_run_time': next_run_time + } + job_kwargs = dict((key, value) for key, value in six.iteritems(job_kwargs) if + value is not undefined) + job = Job(self, **job_kwargs) + + # Don't really add jobs to job stores before the scheduler is up and running + with self._jobstores_lock: + if self.state == STATE_STOPPED: + self._pending_jobs.append((job, jobstore, replace_existing)) + self._logger.info('Adding job tentatively -- it will be properly scheduled when ' + 'the scheduler starts') + else: + self._real_add_job(job, jobstore, replace_existing) + + return job + + def scheduled_job(self, trigger, args=None, kwargs=None, id=None, name=None, + misfire_grace_time=undefined, coalesce=undefined, max_instances=undefined, + next_run_time=undefined, jobstore='default', executor='default', + **trigger_args): + """ + scheduled_job(trigger, args=None, kwargs=None, id=None, \ + name=None, misfire_grace_time=undefined, \ + coalesce=undefined, max_instances=undefined, \ + next_run_time=undefined, jobstore='default', \ + executor='default',**trigger_args) + + A decorator version of :meth:`add_job`, except that ``replace_existing`` is always + ``True``. + + .. important:: The ``id`` argument must be given if scheduling a job in a persistent job + store. The scheduler cannot, however, enforce this requirement. + + """ + def inner(func): + self.add_job(func, trigger, args, kwargs, id, name, misfire_grace_time, coalesce, + max_instances, next_run_time, jobstore, executor, True, **trigger_args) + return func + return inner + + def modify_job(self, job_id, jobstore=None, **changes): + """ + Modifies the properties of a single job. + + Modifications are passed to this method as extra keyword arguments. + + :param str|unicode job_id: the identifier of the job + :param str|unicode jobstore: alias of the job store that contains the job + :return Job: the relevant job instance + + """ + with self._jobstores_lock: + job, jobstore = self._lookup_job(job_id, jobstore) + job._modify(**changes) + if jobstore: + self._lookup_jobstore(jobstore).update_job(job) + + self._dispatch_event(JobEvent(EVENT_JOB_MODIFIED, job_id, jobstore)) + + # Wake up the scheduler since the job's next run time may have been changed + if self.state == STATE_RUNNING: + self.wakeup() + + return job + + def reschedule_job(self, job_id, jobstore=None, trigger=None, **trigger_args): + """ + Constructs a new trigger for a job and updates its next run time. + + Extra keyword arguments are passed directly to the trigger's constructor. + + :param str|unicode job_id: the identifier of the job + :param str|unicode jobstore: alias of the job store that contains the job + :param trigger: alias of the trigger type or a trigger instance + :return Job: the relevant job instance + + """ + trigger = self._create_trigger(trigger, trigger_args) + now = datetime.now(self.timezone) + next_run_time = trigger.get_next_fire_time(None, now) + return self.modify_job(job_id, jobstore, trigger=trigger, next_run_time=next_run_time) + + def pause_job(self, job_id, jobstore=None): + """ + Causes the given job not to be executed until it is explicitly resumed. + + :param str|unicode job_id: the identifier of the job + :param str|unicode jobstore: alias of the job store that contains the job + :return Job: the relevant job instance + + """ + return self.modify_job(job_id, jobstore, next_run_time=None) + + def resume_job(self, job_id, jobstore=None): + """ + Resumes the schedule of the given job, or removes the job if its schedule is finished. + + :param str|unicode job_id: the identifier of the job + :param str|unicode jobstore: alias of the job store that contains the job + :return Job|None: the relevant job instance if the job was rescheduled, or ``None`` if no + next run time could be calculated and the job was removed + + """ + with self._jobstores_lock: + job, jobstore = self._lookup_job(job_id, jobstore) + now = datetime.now(self.timezone) + next_run_time = job.trigger.get_next_fire_time(None, now) + if next_run_time: + return self.modify_job(job_id, jobstore, next_run_time=next_run_time) + else: + self.remove_job(job.id, jobstore) + + def get_jobs(self, jobstore=None, pending=None): + """ + Returns a list of pending jobs (if the scheduler hasn't been started yet) and scheduled + jobs, either from a specific job store or from all of them. + + If the scheduler has not been started yet, only pending jobs can be returned because the + job stores haven't been started yet either. + + :param str|unicode jobstore: alias of the job store + :param bool pending: **DEPRECATED** + :rtype: list[Job] + + """ + if pending is not None: + warnings.warn('The "pending" option is deprecated -- get_jobs() always returns ' + 'scheduled jobs if the scheduler has been started and pending jobs ' + 'otherwise', DeprecationWarning) + + with self._jobstores_lock: + jobs = [] + if self.state == STATE_STOPPED: + for job, alias, replace_existing in self._pending_jobs: + if jobstore is None or alias == jobstore: + jobs.append(job) + else: + for alias, store in six.iteritems(self._jobstores): + if jobstore is None or alias == jobstore: + jobs.extend(store.get_all_jobs()) + + return jobs + + def get_job(self, job_id, jobstore=None): + """ + Returns the Job that matches the given ``job_id``. + + :param str|unicode job_id: the identifier of the job + :param str|unicode jobstore: alias of the job store that most likely contains the job + :return: the Job by the given ID, or ``None`` if it wasn't found + :rtype: Job + + """ + with self._jobstores_lock: + try: + return self._lookup_job(job_id, jobstore)[0] + except JobLookupError: + return + + def remove_job(self, job_id, jobstore=None): + """ + Removes a job, preventing it from being run any more. + + :param str|unicode job_id: the identifier of the job + :param str|unicode jobstore: alias of the job store that contains the job + :raises JobLookupError: if the job was not found + + """ + jobstore_alias = None + with self._jobstores_lock: + # Check if the job is among the pending jobs + if self.state == STATE_STOPPED: + for i, (job, alias, replace_existing) in enumerate(self._pending_jobs): + if job.id == job_id and jobstore in (None, alias): + del self._pending_jobs[i] + jobstore_alias = alias + break + else: + # Otherwise, try to remove it from each store until it succeeds or we run out of + # stores to check + for alias, store in six.iteritems(self._jobstores): + if jobstore in (None, alias): + try: + store.remove_job(job_id) + jobstore_alias = alias + break + except JobLookupError: + continue + + if jobstore_alias is None: + raise JobLookupError(job_id) + + # Notify listeners that a job has been removed + event = JobEvent(EVENT_JOB_REMOVED, job_id, jobstore_alias) + self._dispatch_event(event) + + self._logger.info('Removed job %s', job_id) + + def remove_all_jobs(self, jobstore=None): + """ + Removes all jobs from the specified job store, or all job stores if none is given. + + :param str|unicode jobstore: alias of the job store + + """ + with self._jobstores_lock: + if self.state == STATE_STOPPED: + if jobstore: + self._pending_jobs = [pending for pending in self._pending_jobs if + pending[1] != jobstore] + else: + self._pending_jobs = [] + else: + for alias, store in six.iteritems(self._jobstores): + if jobstore in (None, alias): + store.remove_all_jobs() + + self._dispatch_event(SchedulerEvent(EVENT_ALL_JOBS_REMOVED, jobstore)) + + def print_jobs(self, jobstore=None, out=None): + """ + print_jobs(jobstore=None, out=sys.stdout) + + Prints out a textual listing of all jobs currently scheduled on either all job stores or + just a specific one. + + :param str|unicode jobstore: alias of the job store, ``None`` to list jobs from all stores + :param file out: a file-like object to print to (defaults to **sys.stdout** if nothing is + given) + + """ + out = out or sys.stdout + with self._jobstores_lock: + if self.state == STATE_STOPPED: + print(u'Pending jobs:', file=out) + if self._pending_jobs: + for job, jobstore_alias, replace_existing in self._pending_jobs: + if jobstore in (None, jobstore_alias): + print(u' %s' % job, file=out) + else: + print(u' No pending jobs', file=out) + else: + for alias, store in sorted(six.iteritems(self._jobstores)): + if jobstore in (None, alias): + print(u'Jobstore %s:' % alias, file=out) + jobs = store.get_all_jobs() + if jobs: + for job in jobs: + print(u' %s' % job, file=out) + else: + print(u' No scheduled jobs', file=out) + + @abstractmethod + def wakeup(self): + """ + Notifies the scheduler that there may be jobs due for execution. + Triggers :meth:`_process_jobs` to be run in an implementation specific manner. + """ + + # + # Private API + # + + def _configure(self, config): + # Set general options + self._logger = maybe_ref(config.pop('logger', None)) or getLogger('apscheduler.scheduler') + self.timezone = astimezone(config.pop('timezone', None)) or get_localzone() + self.jobstore_retry_interval = float(config.pop('jobstore_retry_interval', 10)) + + # Set the job defaults + job_defaults = config.get('job_defaults', {}) + self._job_defaults = { + 'misfire_grace_time': asint(job_defaults.get('misfire_grace_time', 1)), + 'coalesce': asbool(job_defaults.get('coalesce', True)), + 'max_instances': asint(job_defaults.get('max_instances', 1)) + } + + # Configure executors + self._executors.clear() + for alias, value in six.iteritems(config.get('executors', {})): + if isinstance(value, BaseExecutor): + self.add_executor(value, alias) + elif isinstance(value, MutableMapping): + executor_class = value.pop('class', None) + plugin = value.pop('type', None) + if plugin: + executor = self._create_plugin_instance('executor', plugin, value) + elif executor_class: + cls = maybe_ref(executor_class) + executor = cls(**value) + else: + raise ValueError( + 'Cannot create executor "%s" -- either "type" or "class" must be defined' % + alias) + + self.add_executor(executor, alias) + else: + raise TypeError( + "Expected executor instance or dict for executors['%s'], got %s instead" % + (alias, value.__class__.__name__)) + + # Configure job stores + self._jobstores.clear() + for alias, value in six.iteritems(config.get('jobstores', {})): + if isinstance(value, BaseJobStore): + self.add_jobstore(value, alias) + elif isinstance(value, MutableMapping): + jobstore_class = value.pop('class', None) + plugin = value.pop('type', None) + if plugin: + jobstore = self._create_plugin_instance('jobstore', plugin, value) + elif jobstore_class: + cls = maybe_ref(jobstore_class) + jobstore = cls(**value) + else: + raise ValueError( + 'Cannot create job store "%s" -- either "type" or "class" must be ' + 'defined' % alias) + + self.add_jobstore(jobstore, alias) + else: + raise TypeError( + "Expected job store instance or dict for jobstores['%s'], got %s instead" % + (alias, value.__class__.__name__)) + + def _create_default_executor(self): + """Creates a default executor store, specific to the particular scheduler type.""" + return ThreadPoolExecutor() + + def _create_default_jobstore(self): + """Creates a default job store, specific to the particular scheduler type.""" + return MemoryJobStore() + + def _lookup_executor(self, alias): + """ + Returns the executor instance by the given name from the list of executors that were added + to this scheduler. + + :type alias: str + :raises KeyError: if no executor by the given alias is not found + + """ + try: + return self._executors[alias] + except KeyError: + raise KeyError('No such executor: %s' % alias) + + def _lookup_jobstore(self, alias): + """ + Returns the job store instance by the given name from the list of job stores that were + added to this scheduler. + + :type alias: str + :raises KeyError: if no job store by the given alias is not found + + """ + try: + return self._jobstores[alias] + except KeyError: + raise KeyError('No such job store: %s' % alias) + + def _lookup_job(self, job_id, jobstore_alias): + """ + Finds a job by its ID. + + :type job_id: str + :param str jobstore_alias: alias of a job store to look in + :return tuple[Job, str]: a tuple of job, jobstore alias (jobstore alias is None in case of + a pending job) + :raises JobLookupError: if no job by the given ID is found. + + """ + if self.state == STATE_STOPPED: + # Check if the job is among the pending jobs + for job, alias, replace_existing in self._pending_jobs: + if job.id == job_id: + return job, None + else: + # Look in all job stores + for alias, store in six.iteritems(self._jobstores): + if jobstore_alias in (None, alias): + job = store.lookup_job(job_id) + if job is not None: + return job, alias + + raise JobLookupError(job_id) + + def _dispatch_event(self, event): + """ + Dispatches the given event to interested listeners. + + :param SchedulerEvent event: the event to send + + """ + with self._listeners_lock: + listeners = tuple(self._listeners) + + for cb, mask in listeners: + if event.code & mask: + try: + cb(event) + except BaseException: + self._logger.exception('Error notifying listener') + + def _check_uwsgi(self): + """Check if we're running under uWSGI with threads disabled.""" + uwsgi_module = sys.modules.get('uwsgi') + if not getattr(uwsgi_module, 'has_threads', True): + raise RuntimeError('The scheduler seems to be running under uWSGI, but threads have ' + 'been disabled. You must run uWSGI with the --enable-threads ' + 'option for the scheduler to work.') + + def _real_add_job(self, job, jobstore_alias, replace_existing): + """ + :param Job job: the job to add + :param bool replace_existing: ``True`` to use update_job() in case the job already exists + in the store + + """ + # Fill in undefined values with defaults + replacements = {} + for key, value in six.iteritems(self._job_defaults): + if not hasattr(job, key): + replacements[key] = value + + # Calculate the next run time if there is none defined + if not hasattr(job, 'next_run_time'): + now = datetime.now(self.timezone) + replacements['next_run_time'] = job.trigger.get_next_fire_time(None, now) + + # Apply any replacements + job._modify(**replacements) + + # Add the job to the given job store + store = self._lookup_jobstore(jobstore_alias) + try: + store.add_job(job) + except ConflictingIdError: + if replace_existing: + store.update_job(job) + else: + raise + + # Mark the job as no longer pending + job._jobstore_alias = jobstore_alias + + # Notify listeners that a new job has been added + event = JobEvent(EVENT_JOB_ADDED, job.id, jobstore_alias) + self._dispatch_event(event) + + self._logger.info('Added job "%s" to job store "%s"', job.name, jobstore_alias) + + # Notify the scheduler about the new job + if self.state == STATE_RUNNING: + self.wakeup() + + def _create_plugin_instance(self, type_, alias, constructor_kwargs): + """Creates an instance of the given plugin type, loading the plugin first if necessary.""" + plugin_container, class_container, base_class = { + 'trigger': (self._trigger_plugins, self._trigger_classes, BaseTrigger), + 'jobstore': (self._jobstore_plugins, self._jobstore_classes, BaseJobStore), + 'executor': (self._executor_plugins, self._executor_classes, BaseExecutor) + }[type_] + + try: + plugin_cls = class_container[alias] + except KeyError: + if alias in plugin_container: + plugin_cls = class_container[alias] = plugin_container[alias].load() + if not issubclass(plugin_cls, base_class): + raise TypeError('The {0} entry point does not point to a {0} class'. + format(type_)) + else: + raise LookupError('No {0} by the name "{1}" was found'.format(type_, alias)) + + return plugin_cls(**constructor_kwargs) + + def _create_trigger(self, trigger, trigger_args): + if isinstance(trigger, BaseTrigger): + return trigger + elif trigger is None: + trigger = 'date' + elif not isinstance(trigger, six.string_types): + raise TypeError('Expected a trigger instance or string, got %s instead' % + trigger.__class__.__name__) + + # Use the scheduler's time zone if nothing else is specified + trigger_args.setdefault('timezone', self.timezone) + + # Instantiate the trigger class + return self._create_plugin_instance('trigger', trigger, trigger_args) + + def _create_lock(self): + """Creates a reentrant lock object.""" + return RLock() + + def _process_jobs(self): + """ + Iterates through jobs in every jobstore, starts jobs that are due and figures out how long + to wait for the next round. + + If the ``get_due_jobs()`` call raises an exception, a new wakeup is scheduled in at least + ``jobstore_retry_interval`` seconds. + + """ + if self.state == STATE_PAUSED: + self._logger.debug('Scheduler is paused -- not processing jobs') + return None + + self._logger.debug('Looking for jobs to run') + now = datetime.now(self.timezone) + next_wakeup_time = None + events = [] + + with self._jobstores_lock: + for jobstore_alias, jobstore in six.iteritems(self._jobstores): + try: + due_jobs = jobstore.get_due_jobs(now) + except Exception as e: + # Schedule a wakeup at least in jobstore_retry_interval seconds + self._logger.warning('Error getting due jobs from job store %r: %s', + jobstore_alias, e) + retry_wakeup_time = now + timedelta(seconds=self.jobstore_retry_interval) + if not next_wakeup_time or next_wakeup_time > retry_wakeup_time: + next_wakeup_time = retry_wakeup_time + + continue + + for job in due_jobs: + # Look up the job's executor + try: + executor = self._lookup_executor(job.executor) + except BaseException: + self._logger.error( + 'Executor lookup ("%s") failed for job "%s" -- removing it from the ' + 'job store', job.executor, job) + self.remove_job(job.id, jobstore_alias) + continue + + run_times = job._get_run_times(now) + run_times = run_times[-1:] if run_times and job.coalesce else run_times + if run_times: + try: + executor.submit_job(job, run_times) + except MaxInstancesReachedError: + self._logger.warning( + 'Execution of job "%s" skipped: maximum number of running ' + 'instances reached (%d)', job, job.max_instances) + event = JobSubmissionEvent(EVENT_JOB_MAX_INSTANCES, job.id, + jobstore_alias, run_times) + events.append(event) + except BaseException: + self._logger.exception('Error submitting job "%s" to executor "%s"', + job, job.executor) + else: + event = JobSubmissionEvent(EVENT_JOB_SUBMITTED, job.id, jobstore_alias, + run_times) + events.append(event) + + # Update the job if it has a next execution time. + # Otherwise remove it from the job store. + job_next_run = job.trigger.get_next_fire_time(run_times[-1], now) + if job_next_run: + job._modify(next_run_time=job_next_run) + jobstore.update_job(job) + else: + self.remove_job(job.id, jobstore_alias) + + # Set a new next wakeup time if there isn't one yet or + # the jobstore has an even earlier one + jobstore_next_run_time = jobstore.get_next_run_time() + if jobstore_next_run_time and (next_wakeup_time is None or + jobstore_next_run_time < next_wakeup_time): + next_wakeup_time = jobstore_next_run_time.astimezone(self.timezone) + + # Dispatch collected events + for event in events: + self._dispatch_event(event) + + # Determine the delay until this method should be called again + if self.state == STATE_PAUSED: + wait_seconds = None + self._logger.debug('Scheduler is paused; waiting until resume() is called') + elif next_wakeup_time is None: + wait_seconds = None + self._logger.debug('No jobs; waiting until a job is added') + else: + wait_seconds = min(max(timedelta_seconds(next_wakeup_time - now), 0), TIMEOUT_MAX) + self._logger.debug('Next wakeup is due at %s (in %f seconds)', next_wakeup_time, + wait_seconds) + + return wait_seconds diff --git a/venv/lib/python3.8/site-packages/apscheduler/schedulers/blocking.py b/venv/lib/python3.8/site-packages/apscheduler/schedulers/blocking.py new file mode 100644 index 0000000..e617157 --- /dev/null +++ b/venv/lib/python3.8/site-packages/apscheduler/schedulers/blocking.py @@ -0,0 +1,33 @@ +from __future__ import absolute_import + +from threading import Event + +from apscheduler.schedulers.base import BaseScheduler, STATE_STOPPED +from apscheduler.util import TIMEOUT_MAX + + +class BlockingScheduler(BaseScheduler): + """ + A scheduler that runs in the foreground + (:meth:`~apscheduler.schedulers.base.BaseScheduler.start` will block). + """ + _event = None + + def start(self, *args, **kwargs): + self._event = Event() + super(BlockingScheduler, self).start(*args, **kwargs) + self._main_loop() + + def shutdown(self, wait=True): + super(BlockingScheduler, self).shutdown(wait) + self._event.set() + + def _main_loop(self): + wait_seconds = TIMEOUT_MAX + while self.state != STATE_STOPPED: + self._event.wait(wait_seconds) + self._event.clear() + wait_seconds = self._process_jobs() + + def wakeup(self): + self._event.set() diff --git a/venv/lib/python3.8/site-packages/apscheduler/schedulers/gevent.py b/venv/lib/python3.8/site-packages/apscheduler/schedulers/gevent.py new file mode 100644 index 0000000..d48ed74 --- /dev/null +++ b/venv/lib/python3.8/site-packages/apscheduler/schedulers/gevent.py @@ -0,0 +1,35 @@ +from __future__ import absolute_import + +from apscheduler.schedulers.blocking import BlockingScheduler +from apscheduler.schedulers.base import BaseScheduler + +try: + from gevent.event import Event + from gevent.lock import RLock + import gevent +except ImportError: # pragma: nocover + raise ImportError('GeventScheduler requires gevent installed') + + +class GeventScheduler(BlockingScheduler): + """A scheduler that runs as a Gevent greenlet.""" + + _greenlet = None + + def start(self, *args, **kwargs): + self._event = Event() + BaseScheduler.start(self, *args, **kwargs) + self._greenlet = gevent.spawn(self._main_loop) + return self._greenlet + + def shutdown(self, *args, **kwargs): + super(GeventScheduler, self).shutdown(*args, **kwargs) + self._greenlet.join() + del self._greenlet + + def _create_lock(self): + return RLock() + + def _create_default_executor(self): + from apscheduler.executors.gevent import GeventExecutor + return GeventExecutor() diff --git a/venv/lib/python3.8/site-packages/apscheduler/schedulers/qt.py b/venv/lib/python3.8/site-packages/apscheduler/schedulers/qt.py new file mode 100644 index 0000000..0329a00 --- /dev/null +++ b/venv/lib/python3.8/site-packages/apscheduler/schedulers/qt.py @@ -0,0 +1,43 @@ +from __future__ import absolute_import + +from apscheduler.schedulers.base import BaseScheduler + +try: + from PyQt5.QtCore import QObject, QTimer +except (ImportError, RuntimeError): # pragma: nocover + try: + from PyQt4.QtCore import QObject, QTimer + except ImportError: + try: + from PySide.QtCore import QObject, QTimer # noqa + except ImportError: + raise ImportError('QtScheduler requires either PyQt5, PyQt4 or PySide installed') + + +class QtScheduler(BaseScheduler): + """A scheduler that runs in a Qt event loop.""" + + _timer = None + + def shutdown(self, *args, **kwargs): + super(QtScheduler, self).shutdown(*args, **kwargs) + self._stop_timer() + + def _start_timer(self, wait_seconds): + self._stop_timer() + if wait_seconds is not None: + wait_time = min(wait_seconds * 1000, 2147483647) + self._timer = QTimer.singleShot(wait_time, self._process_jobs) + + def _stop_timer(self): + if self._timer: + if self._timer.isActive(): + self._timer.stop() + del self._timer + + def wakeup(self): + self._start_timer(0) + + def _process_jobs(self): + wait_seconds = super(QtScheduler, self)._process_jobs() + self._start_timer(wait_seconds) diff --git a/venv/lib/python3.8/site-packages/apscheduler/schedulers/tornado.py b/venv/lib/python3.8/site-packages/apscheduler/schedulers/tornado.py new file mode 100644 index 0000000..0a9171f --- /dev/null +++ b/venv/lib/python3.8/site-packages/apscheduler/schedulers/tornado.py @@ -0,0 +1,63 @@ +from __future__ import absolute_import + +from datetime import timedelta +from functools import wraps + +from apscheduler.schedulers.base import BaseScheduler +from apscheduler.util import maybe_ref + +try: + from tornado.ioloop import IOLoop +except ImportError: # pragma: nocover + raise ImportError('TornadoScheduler requires tornado installed') + + +def run_in_ioloop(func): + @wraps(func) + def wrapper(self, *args, **kwargs): + self._ioloop.add_callback(func, self, *args, **kwargs) + return wrapper + + +class TornadoScheduler(BaseScheduler): + """ + A scheduler that runs on a Tornado IOLoop. + + The default executor can run jobs based on native coroutines (``async def``). + + =========== =============================================================== + ``io_loop`` Tornado IOLoop instance to use (defaults to the global IO loop) + =========== =============================================================== + """ + + _ioloop = None + _timeout = None + + @run_in_ioloop + def shutdown(self, wait=True): + super(TornadoScheduler, self).shutdown(wait) + self._stop_timer() + + def _configure(self, config): + self._ioloop = maybe_ref(config.pop('io_loop', None)) or IOLoop.current() + super(TornadoScheduler, self)._configure(config) + + def _start_timer(self, wait_seconds): + self._stop_timer() + if wait_seconds is not None: + self._timeout = self._ioloop.add_timeout(timedelta(seconds=wait_seconds), self.wakeup) + + def _stop_timer(self): + if self._timeout: + self._ioloop.remove_timeout(self._timeout) + del self._timeout + + def _create_default_executor(self): + from apscheduler.executors.tornado import TornadoExecutor + return TornadoExecutor() + + @run_in_ioloop + def wakeup(self): + self._stop_timer() + wait_seconds = self._process_jobs() + self._start_timer(wait_seconds) diff --git a/venv/lib/python3.8/site-packages/apscheduler/schedulers/twisted.py b/venv/lib/python3.8/site-packages/apscheduler/schedulers/twisted.py new file mode 100644 index 0000000..6b43a84 --- /dev/null +++ b/venv/lib/python3.8/site-packages/apscheduler/schedulers/twisted.py @@ -0,0 +1,62 @@ +from __future__ import absolute_import + +from functools import wraps + +from apscheduler.schedulers.base import BaseScheduler +from apscheduler.util import maybe_ref + +try: + from twisted.internet import reactor as default_reactor +except ImportError: # pragma: nocover + raise ImportError('TwistedScheduler requires Twisted installed') + + +def run_in_reactor(func): + @wraps(func) + def wrapper(self, *args, **kwargs): + self._reactor.callFromThread(func, self, *args, **kwargs) + return wrapper + + +class TwistedScheduler(BaseScheduler): + """ + A scheduler that runs on a Twisted reactor. + + Extra options: + + =========== ======================================================== + ``reactor`` Reactor instance to use (defaults to the global reactor) + =========== ======================================================== + """ + + _reactor = None + _delayedcall = None + + def _configure(self, config): + self._reactor = maybe_ref(config.pop('reactor', default_reactor)) + super(TwistedScheduler, self)._configure(config) + + @run_in_reactor + def shutdown(self, wait=True): + super(TwistedScheduler, self).shutdown(wait) + self._stop_timer() + + def _start_timer(self, wait_seconds): + self._stop_timer() + if wait_seconds is not None: + self._delayedcall = self._reactor.callLater(wait_seconds, self.wakeup) + + def _stop_timer(self): + if self._delayedcall and self._delayedcall.active(): + self._delayedcall.cancel() + del self._delayedcall + + @run_in_reactor + def wakeup(self): + self._stop_timer() + wait_seconds = self._process_jobs() + self._start_timer(wait_seconds) + + def _create_default_executor(self): + from apscheduler.executors.twisted import TwistedExecutor + return TwistedExecutor() diff --git a/venv/lib/python3.8/site-packages/apscheduler/triggers/__init__.py b/venv/lib/python3.8/site-packages/apscheduler/triggers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.8/site-packages/apscheduler/triggers/base.py b/venv/lib/python3.8/site-packages/apscheduler/triggers/base.py new file mode 100644 index 0000000..ce2526a --- /dev/null +++ b/venv/lib/python3.8/site-packages/apscheduler/triggers/base.py @@ -0,0 +1,48 @@ +from abc import ABCMeta, abstractmethod +from datetime import timedelta +import random + +import six + + +class BaseTrigger(six.with_metaclass(ABCMeta)): + """Abstract base class that defines the interface that every trigger must implement.""" + + __slots__ = () + + @abstractmethod + def get_next_fire_time(self, previous_fire_time, now): + """ + Returns the next datetime to fire on, If no such datetime can be calculated, returns + ``None``. + + :param datetime.datetime previous_fire_time: the previous time the trigger was fired + :param datetime.datetime now: current datetime + """ + + def _apply_jitter(self, next_fire_time, jitter, now): + """ + Randomize ``next_fire_time`` by adding or subtracting a random value (the jitter). If the + resulting datetime is in the past, returns the initial ``next_fire_time`` without jitter. + + ``next_fire_time - jitter <= result <= next_fire_time + jitter`` + + :param datetime.datetime|None next_fire_time: next fire time without jitter applied. If + ``None``, returns ``None``. + :param int|None jitter: maximum number of seconds to add or subtract to + ``next_fire_time``. If ``None`` or ``0``, returns ``next_fire_time`` + :param datetime.datetime now: current datetime + :return datetime.datetime|None: next fire time with a jitter. + """ + if next_fire_time is None or not jitter: + return next_fire_time + + next_fire_time_with_jitter = next_fire_time + timedelta( + seconds=random.uniform(-jitter, jitter)) + + if next_fire_time_with_jitter < now: + # Next fire time with jitter is in the past. + # Ignore jitter to avoid false misfire. + return next_fire_time + + return next_fire_time_with_jitter diff --git a/venv/lib/python3.8/site-packages/apscheduler/triggers/combining.py b/venv/lib/python3.8/site-packages/apscheduler/triggers/combining.py new file mode 100644 index 0000000..64f8301 --- /dev/null +++ b/venv/lib/python3.8/site-packages/apscheduler/triggers/combining.py @@ -0,0 +1,95 @@ +from apscheduler.triggers.base import BaseTrigger +from apscheduler.util import obj_to_ref, ref_to_obj + + +class BaseCombiningTrigger(BaseTrigger): + __slots__ = ('triggers', 'jitter') + + def __init__(self, triggers, jitter=None): + self.triggers = triggers + self.jitter = jitter + + def __getstate__(self): + return { + 'version': 1, + 'triggers': [(obj_to_ref(trigger.__class__), trigger.__getstate__()) + for trigger in self.triggers], + 'jitter': self.jitter + } + + def __setstate__(self, state): + if state.get('version', 1) > 1: + raise ValueError( + 'Got serialized data for version %s of %s, but only versions up to 1 can be ' + 'handled' % (state['version'], self.__class__.__name__)) + + self.jitter = state['jitter'] + self.triggers = [] + for clsref, state in state['triggers']: + cls = ref_to_obj(clsref) + trigger = cls.__new__(cls) + trigger.__setstate__(state) + self.triggers.append(trigger) + + def __repr__(self): + return '<{}({}{})>'.format(self.__class__.__name__, self.triggers, + ', jitter={}'.format(self.jitter) if self.jitter else '') + + +class AndTrigger(BaseCombiningTrigger): + """ + Always returns the earliest next fire time that all the given triggers can agree on. + The trigger is considered to be finished when any of the given triggers has finished its + schedule. + + Trigger alias: ``and`` + + :param list triggers: triggers to combine + :param int|None jitter: advance or delay the job execution by ``jitter`` seconds at most. + """ + + __slots__ = () + + def get_next_fire_time(self, previous_fire_time, now): + while True: + fire_times = [trigger.get_next_fire_time(previous_fire_time, now) + for trigger in self.triggers] + if None in fire_times: + return None + elif min(fire_times) == max(fire_times): + return self._apply_jitter(fire_times[0], self.jitter, now) + else: + now = max(fire_times) + + def __str__(self): + return 'and[{}]'.format(', '.join(str(trigger) for trigger in self.triggers)) + + +class OrTrigger(BaseCombiningTrigger): + """ + Always returns the earliest next fire time produced by any of the given triggers. + The trigger is considered finished when all the given triggers have finished their schedules. + + Trigger alias: ``or`` + + :param list triggers: triggers to combine + :param int|None jitter: advance or delay the job execution by ``jitter`` seconds at most. + + .. note:: Triggers that depends on the previous fire time, such as the interval trigger, may + seem to behave strangely since they are always passed the previous fire time produced by + any of the given triggers. + """ + + __slots__ = () + + def get_next_fire_time(self, previous_fire_time, now): + fire_times = [trigger.get_next_fire_time(previous_fire_time, now) + for trigger in self.triggers] + fire_times = [fire_time for fire_time in fire_times if fire_time is not None] + if fire_times: + return self._apply_jitter(min(fire_times), self.jitter, now) + else: + return None + + def __str__(self): + return 'or[{}]'.format(', '.join(str(trigger) for trigger in self.triggers)) diff --git a/venv/lib/python3.8/site-packages/apscheduler/triggers/cron/__init__.py b/venv/lib/python3.8/site-packages/apscheduler/triggers/cron/__init__.py new file mode 100644 index 0000000..ce675dd --- /dev/null +++ b/venv/lib/python3.8/site-packages/apscheduler/triggers/cron/__init__.py @@ -0,0 +1,238 @@ +from datetime import datetime, timedelta + +from tzlocal import get_localzone +import six + +from apscheduler.triggers.base import BaseTrigger +from apscheduler.triggers.cron.fields import ( + BaseField, MonthField, WeekField, DayOfMonthField, DayOfWeekField, DEFAULT_VALUES) +from apscheduler.util import datetime_ceil, convert_to_datetime, datetime_repr, astimezone + + +class CronTrigger(BaseTrigger): + """ + Triggers when current time matches all specified time constraints, + similarly to how the UNIX cron scheduler works. + + :param int|str year: 4-digit year + :param int|str month: month (1-12) + :param int|str day: day of the (1-31) + :param int|str week: ISO week (1-53) + :param int|str day_of_week: number or name of weekday (0-6 or mon,tue,wed,thu,fri,sat,sun) + :param int|str hour: hour (0-23) + :param int|str minute: minute (0-59) + :param int|str second: second (0-59) + :param datetime|str start_date: earliest possible date/time to trigger on (inclusive) + :param datetime|str end_date: latest possible date/time to trigger on (inclusive) + :param datetime.tzinfo|str timezone: time zone to use for the date/time calculations (defaults + to scheduler timezone) + :param int|None jitter: advance or delay the job execution by ``jitter`` seconds at most. + + .. note:: The first weekday is always **monday**. + """ + + FIELD_NAMES = ('year', 'month', 'day', 'week', 'day_of_week', 'hour', 'minute', 'second') + FIELDS_MAP = { + 'year': BaseField, + 'month': MonthField, + 'week': WeekField, + 'day': DayOfMonthField, + 'day_of_week': DayOfWeekField, + 'hour': BaseField, + 'minute': BaseField, + 'second': BaseField + } + + __slots__ = 'timezone', 'start_date', 'end_date', 'fields', 'jitter' + + def __init__(self, year=None, month=None, day=None, week=None, day_of_week=None, hour=None, + minute=None, second=None, start_date=None, end_date=None, timezone=None, + jitter=None): + if timezone: + self.timezone = astimezone(timezone) + elif isinstance(start_date, datetime) and start_date.tzinfo: + self.timezone = start_date.tzinfo + elif isinstance(end_date, datetime) and end_date.tzinfo: + self.timezone = end_date.tzinfo + else: + self.timezone = get_localzone() + + self.start_date = convert_to_datetime(start_date, self.timezone, 'start_date') + self.end_date = convert_to_datetime(end_date, self.timezone, 'end_date') + + self.jitter = jitter + + values = dict((key, value) for (key, value) in six.iteritems(locals()) + if key in self.FIELD_NAMES and value is not None) + self.fields = [] + assign_defaults = False + for field_name in self.FIELD_NAMES: + if field_name in values: + exprs = values.pop(field_name) + is_default = False + assign_defaults = not values + elif assign_defaults: + exprs = DEFAULT_VALUES[field_name] + is_default = True + else: + exprs = '*' + is_default = True + + field_class = self.FIELDS_MAP[field_name] + field = field_class(field_name, exprs, is_default) + self.fields.append(field) + + @classmethod + def from_crontab(cls, expr, timezone=None): + """ + Create a :class:`~CronTrigger` from a standard crontab expression. + + See https://en.wikipedia.org/wiki/Cron for more information on the format accepted here. + + :param expr: minute, hour, day of month, month, day of week + :param datetime.tzinfo|str timezone: time zone to use for the date/time calculations ( + defaults to scheduler timezone) + :return: a :class:`~CronTrigger` instance + + """ + values = expr.split() + if len(values) != 5: + raise ValueError('Wrong number of fields; got {}, expected 5'.format(len(values))) + + return cls(minute=values[0], hour=values[1], day=values[2], month=values[3], + day_of_week=values[4], timezone=timezone) + + def _increment_field_value(self, dateval, fieldnum): + """ + Increments the designated field and resets all less significant fields to their minimum + values. + + :type dateval: datetime + :type fieldnum: int + :return: a tuple containing the new date, and the number of the field that was actually + incremented + :rtype: tuple + """ + + values = {} + i = 0 + while i < len(self.fields): + field = self.fields[i] + if not field.REAL: + if i == fieldnum: + fieldnum -= 1 + i -= 1 + else: + i += 1 + continue + + if i < fieldnum: + values[field.name] = field.get_value(dateval) + i += 1 + elif i > fieldnum: + values[field.name] = field.get_min(dateval) + i += 1 + else: + value = field.get_value(dateval) + maxval = field.get_max(dateval) + if value == maxval: + fieldnum -= 1 + i -= 1 + else: + values[field.name] = value + 1 + i += 1 + + difference = datetime(**values) - dateval.replace(tzinfo=None) + return self.timezone.normalize(dateval + difference), fieldnum + + def _set_field_value(self, dateval, fieldnum, new_value): + values = {} + for i, field in enumerate(self.fields): + if field.REAL: + if i < fieldnum: + values[field.name] = field.get_value(dateval) + elif i > fieldnum: + values[field.name] = field.get_min(dateval) + else: + values[field.name] = new_value + + return self.timezone.localize(datetime(**values)) + + def get_next_fire_time(self, previous_fire_time, now): + if previous_fire_time: + start_date = min(now, previous_fire_time + timedelta(microseconds=1)) + if start_date == previous_fire_time: + start_date += timedelta(microseconds=1) + else: + start_date = max(now, self.start_date) if self.start_date else now + + fieldnum = 0 + next_date = datetime_ceil(start_date).astimezone(self.timezone) + while 0 <= fieldnum < len(self.fields): + field = self.fields[fieldnum] + curr_value = field.get_value(next_date) + next_value = field.get_next_value(next_date) + + if next_value is None: + # No valid value was found + next_date, fieldnum = self._increment_field_value(next_date, fieldnum - 1) + elif next_value > curr_value: + # A valid, but higher than the starting value, was found + if field.REAL: + next_date = self._set_field_value(next_date, fieldnum, next_value) + fieldnum += 1 + else: + next_date, fieldnum = self._increment_field_value(next_date, fieldnum) + else: + # A valid value was found, no changes necessary + fieldnum += 1 + + # Return if the date has rolled past the end date + if self.end_date and next_date > self.end_date: + return None + + if fieldnum >= 0: + next_date = self._apply_jitter(next_date, self.jitter, now) + return min(next_date, self.end_date) if self.end_date else next_date + + def __getstate__(self): + return { + 'version': 2, + 'timezone': self.timezone, + 'start_date': self.start_date, + 'end_date': self.end_date, + 'fields': self.fields, + 'jitter': self.jitter, + } + + def __setstate__(self, state): + # This is for compatibility with APScheduler 3.0.x + if isinstance(state, tuple): + state = state[1] + + if state.get('version', 1) > 2: + raise ValueError( + 'Got serialized data for version %s of %s, but only versions up to 2 can be ' + 'handled' % (state['version'], self.__class__.__name__)) + + self.timezone = state['timezone'] + self.start_date = state['start_date'] + self.end_date = state['end_date'] + self.fields = state['fields'] + self.jitter = state.get('jitter') + + def __str__(self): + options = ["%s='%s'" % (f.name, f) for f in self.fields if not f.is_default] + return 'cron[%s]' % (', '.join(options)) + + def __repr__(self): + options = ["%s='%s'" % (f.name, f) for f in self.fields if not f.is_default] + if self.start_date: + options.append("start_date=%r" % datetime_repr(self.start_date)) + if self.end_date: + options.append("end_date=%r" % datetime_repr(self.end_date)) + if self.jitter: + options.append('jitter=%s' % self.jitter) + + return "<%s (%s, timezone='%s')>" % ( + self.__class__.__name__, ', '.join(options), self.timezone) diff --git a/venv/lib/python3.8/site-packages/apscheduler/triggers/cron/expressions.py b/venv/lib/python3.8/site-packages/apscheduler/triggers/cron/expressions.py new file mode 100644 index 0000000..55a3716 --- /dev/null +++ b/venv/lib/python3.8/site-packages/apscheduler/triggers/cron/expressions.py @@ -0,0 +1,251 @@ +"""This module contains the expressions applicable for CronTrigger's fields.""" + +from calendar import monthrange +import re + +from apscheduler.util import asint + +__all__ = ('AllExpression', 'RangeExpression', 'WeekdayRangeExpression', + 'WeekdayPositionExpression', 'LastDayOfMonthExpression') + + +WEEKDAYS = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun'] +MONTHS = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec'] + + +class AllExpression(object): + value_re = re.compile(r'\*(?:/(?P\d+))?$') + + def __init__(self, step=None): + self.step = asint(step) + if self.step == 0: + raise ValueError('Increment must be higher than 0') + + def validate_range(self, field_name): + from apscheduler.triggers.cron.fields import MIN_VALUES, MAX_VALUES + + value_range = MAX_VALUES[field_name] - MIN_VALUES[field_name] + if self.step and self.step > value_range: + raise ValueError('the step value ({}) is higher than the total range of the ' + 'expression ({})'.format(self.step, value_range)) + + def get_next_value(self, date, field): + start = field.get_value(date) + minval = field.get_min(date) + maxval = field.get_max(date) + start = max(start, minval) + + if not self.step: + next = start + else: + distance_to_next = (self.step - (start - minval)) % self.step + next = start + distance_to_next + + if next <= maxval: + return next + + def __eq__(self, other): + return isinstance(other, self.__class__) and self.step == other.step + + def __str__(self): + if self.step: + return '*/%d' % self.step + return '*' + + def __repr__(self): + return "%s(%s)" % (self.__class__.__name__, self.step) + + +class RangeExpression(AllExpression): + value_re = re.compile( + r'(?P\d+)(?:-(?P\d+))?(?:/(?P\d+))?$') + + def __init__(self, first, last=None, step=None): + super(RangeExpression, self).__init__(step) + first = asint(first) + last = asint(last) + if last is None and step is None: + last = first + if last is not None and first > last: + raise ValueError('The minimum value in a range must not be higher than the maximum') + self.first = first + self.last = last + + def validate_range(self, field_name): + from apscheduler.triggers.cron.fields import MIN_VALUES, MAX_VALUES + + super(RangeExpression, self).validate_range(field_name) + if self.first < MIN_VALUES[field_name]: + raise ValueError('the first value ({}) is lower than the minimum value ({})' + .format(self.first, MIN_VALUES[field_name])) + if self.last is not None and self.last > MAX_VALUES[field_name]: + raise ValueError('the last value ({}) is higher than the maximum value ({})' + .format(self.last, MAX_VALUES[field_name])) + value_range = (self.last or MAX_VALUES[field_name]) - self.first + if self.step and self.step > value_range: + raise ValueError('the step value ({}) is higher than the total range of the ' + 'expression ({})'.format(self.step, value_range)) + + def get_next_value(self, date, field): + startval = field.get_value(date) + minval = field.get_min(date) + maxval = field.get_max(date) + + # Apply range limits + minval = max(minval, self.first) + maxval = min(maxval, self.last) if self.last is not None else maxval + nextval = max(minval, startval) + + # Apply the step if defined + if self.step: + distance_to_next = (self.step - (nextval - minval)) % self.step + nextval += distance_to_next + + return nextval if nextval <= maxval else None + + def __eq__(self, other): + return (isinstance(other, self.__class__) and self.first == other.first and + self.last == other.last) + + def __str__(self): + if self.last != self.first and self.last is not None: + range = '%d-%d' % (self.first, self.last) + else: + range = str(self.first) + + if self.step: + return '%s/%d' % (range, self.step) + return range + + def __repr__(self): + args = [str(self.first)] + if self.last != self.first and self.last is not None or self.step: + args.append(str(self.last)) + if self.step: + args.append(str(self.step)) + return "%s(%s)" % (self.__class__.__name__, ', '.join(args)) + + +class MonthRangeExpression(RangeExpression): + value_re = re.compile(r'(?P[a-z]+)(?:-(?P[a-z]+))?', re.IGNORECASE) + + def __init__(self, first, last=None): + try: + first_num = MONTHS.index(first.lower()) + 1 + except ValueError: + raise ValueError('Invalid month name "%s"' % first) + + if last: + try: + last_num = MONTHS.index(last.lower()) + 1 + except ValueError: + raise ValueError('Invalid month name "%s"' % last) + else: + last_num = None + + super(MonthRangeExpression, self).__init__(first_num, last_num) + + def __str__(self): + if self.last != self.first and self.last is not None: + return '%s-%s' % (MONTHS[self.first - 1], MONTHS[self.last - 1]) + return MONTHS[self.first - 1] + + def __repr__(self): + args = ["'%s'" % MONTHS[self.first]] + if self.last != self.first and self.last is not None: + args.append("'%s'" % MONTHS[self.last - 1]) + return "%s(%s)" % (self.__class__.__name__, ', '.join(args)) + + +class WeekdayRangeExpression(RangeExpression): + value_re = re.compile(r'(?P[a-z]+)(?:-(?P[a-z]+))?', re.IGNORECASE) + + def __init__(self, first, last=None): + try: + first_num = WEEKDAYS.index(first.lower()) + except ValueError: + raise ValueError('Invalid weekday name "%s"' % first) + + if last: + try: + last_num = WEEKDAYS.index(last.lower()) + except ValueError: + raise ValueError('Invalid weekday name "%s"' % last) + else: + last_num = None + + super(WeekdayRangeExpression, self).__init__(first_num, last_num) + + def __str__(self): + if self.last != self.first and self.last is not None: + return '%s-%s' % (WEEKDAYS[self.first], WEEKDAYS[self.last]) + return WEEKDAYS[self.first] + + def __repr__(self): + args = ["'%s'" % WEEKDAYS[self.first]] + if self.last != self.first and self.last is not None: + args.append("'%s'" % WEEKDAYS[self.last]) + return "%s(%s)" % (self.__class__.__name__, ', '.join(args)) + + +class WeekdayPositionExpression(AllExpression): + options = ['1st', '2nd', '3rd', '4th', '5th', 'last'] + value_re = re.compile(r'(?P%s) +(?P(?:\d+|\w+))' % + '|'.join(options), re.IGNORECASE) + + def __init__(self, option_name, weekday_name): + super(WeekdayPositionExpression, self).__init__(None) + try: + self.option_num = self.options.index(option_name.lower()) + except ValueError: + raise ValueError('Invalid weekday position "%s"' % option_name) + + try: + self.weekday = WEEKDAYS.index(weekday_name.lower()) + except ValueError: + raise ValueError('Invalid weekday name "%s"' % weekday_name) + + def get_next_value(self, date, field): + # Figure out the weekday of the month's first day and the number of days in that month + first_day_wday, last_day = monthrange(date.year, date.month) + + # Calculate which day of the month is the first of the target weekdays + first_hit_day = self.weekday - first_day_wday + 1 + if first_hit_day <= 0: + first_hit_day += 7 + + # Calculate what day of the month the target weekday would be + if self.option_num < 5: + target_day = first_hit_day + self.option_num * 7 + else: + target_day = first_hit_day + ((last_day - first_hit_day) // 7) * 7 + + if target_day <= last_day and target_day >= date.day: + return target_day + + def __eq__(self, other): + return (super(WeekdayPositionExpression, self).__eq__(other) and + self.option_num == other.option_num and self.weekday == other.weekday) + + def __str__(self): + return '%s %s' % (self.options[self.option_num], WEEKDAYS[self.weekday]) + + def __repr__(self): + return "%s('%s', '%s')" % (self.__class__.__name__, self.options[self.option_num], + WEEKDAYS[self.weekday]) + + +class LastDayOfMonthExpression(AllExpression): + value_re = re.compile(r'last', re.IGNORECASE) + + def __init__(self): + super(LastDayOfMonthExpression, self).__init__(None) + + def get_next_value(self, date, field): + return monthrange(date.year, date.month)[1] + + def __str__(self): + return 'last' + + def __repr__(self): + return "%s()" % self.__class__.__name__ diff --git a/venv/lib/python3.8/site-packages/apscheduler/triggers/cron/fields.py b/venv/lib/python3.8/site-packages/apscheduler/triggers/cron/fields.py new file mode 100644 index 0000000..86d620c --- /dev/null +++ b/venv/lib/python3.8/site-packages/apscheduler/triggers/cron/fields.py @@ -0,0 +1,111 @@ +"""Fields represent CronTrigger options which map to :class:`~datetime.datetime` fields.""" + +from calendar import monthrange +import re + +import six + +from apscheduler.triggers.cron.expressions import ( + AllExpression, RangeExpression, WeekdayPositionExpression, LastDayOfMonthExpression, + WeekdayRangeExpression, MonthRangeExpression) + + +__all__ = ('MIN_VALUES', 'MAX_VALUES', 'DEFAULT_VALUES', 'BaseField', 'WeekField', + 'DayOfMonthField', 'DayOfWeekField') + + +MIN_VALUES = {'year': 1970, 'month': 1, 'day': 1, 'week': 1, 'day_of_week': 0, 'hour': 0, + 'minute': 0, 'second': 0} +MAX_VALUES = {'year': 9999, 'month': 12, 'day': 31, 'week': 53, 'day_of_week': 6, 'hour': 23, + 'minute': 59, 'second': 59} +DEFAULT_VALUES = {'year': '*', 'month': 1, 'day': 1, 'week': '*', 'day_of_week': '*', 'hour': 0, + 'minute': 0, 'second': 0} +SEPARATOR = re.compile(' *, *') + + +class BaseField(object): + REAL = True + COMPILERS = [AllExpression, RangeExpression] + + def __init__(self, name, exprs, is_default=False): + self.name = name + self.is_default = is_default + self.compile_expressions(exprs) + + def get_min(self, dateval): + return MIN_VALUES[self.name] + + def get_max(self, dateval): + return MAX_VALUES[self.name] + + def get_value(self, dateval): + return getattr(dateval, self.name) + + def get_next_value(self, dateval): + smallest = None + for expr in self.expressions: + value = expr.get_next_value(dateval, self) + if smallest is None or (value is not None and value < smallest): + smallest = value + + return smallest + + def compile_expressions(self, exprs): + self.expressions = [] + + # Split a comma-separated expression list, if any + for expr in SEPARATOR.split(str(exprs).strip()): + self.compile_expression(expr) + + def compile_expression(self, expr): + for compiler in self.COMPILERS: + match = compiler.value_re.match(expr) + if match: + compiled_expr = compiler(**match.groupdict()) + + try: + compiled_expr.validate_range(self.name) + except ValueError as e: + exc = ValueError('Error validating expression {!r}: {}'.format(expr, e)) + six.raise_from(exc, None) + + self.expressions.append(compiled_expr) + return + + raise ValueError('Unrecognized expression "%s" for field "%s"' % (expr, self.name)) + + def __eq__(self, other): + return isinstance(self, self.__class__) and self.expressions == other.expressions + + def __str__(self): + expr_strings = (str(e) for e in self.expressions) + return ','.join(expr_strings) + + def __repr__(self): + return "%s('%s', '%s')" % (self.__class__.__name__, self.name, self) + + +class WeekField(BaseField): + REAL = False + + def get_value(self, dateval): + return dateval.isocalendar()[1] + + +class DayOfMonthField(BaseField): + COMPILERS = BaseField.COMPILERS + [WeekdayPositionExpression, LastDayOfMonthExpression] + + def get_max(self, dateval): + return monthrange(dateval.year, dateval.month)[1] + + +class DayOfWeekField(BaseField): + REAL = False + COMPILERS = BaseField.COMPILERS + [WeekdayRangeExpression] + + def get_value(self, dateval): + return dateval.weekday() + + +class MonthField(BaseField): + COMPILERS = BaseField.COMPILERS + [MonthRangeExpression] diff --git a/venv/lib/python3.8/site-packages/apscheduler/triggers/date.py b/venv/lib/python3.8/site-packages/apscheduler/triggers/date.py new file mode 100644 index 0000000..0768100 --- /dev/null +++ b/venv/lib/python3.8/site-packages/apscheduler/triggers/date.py @@ -0,0 +1,51 @@ +from datetime import datetime + +from tzlocal import get_localzone + +from apscheduler.triggers.base import BaseTrigger +from apscheduler.util import convert_to_datetime, datetime_repr, astimezone + + +class DateTrigger(BaseTrigger): + """ + Triggers once on the given datetime. If ``run_date`` is left empty, current time is used. + + :param datetime|str run_date: the date/time to run the job at + :param datetime.tzinfo|str timezone: time zone for ``run_date`` if it doesn't have one already + """ + + __slots__ = 'run_date' + + def __init__(self, run_date=None, timezone=None): + timezone = astimezone(timezone) or get_localzone() + if run_date is not None: + self.run_date = convert_to_datetime(run_date, timezone, 'run_date') + else: + self.run_date = datetime.now(timezone) + + def get_next_fire_time(self, previous_fire_time, now): + return self.run_date if previous_fire_time is None else None + + def __getstate__(self): + return { + 'version': 1, + 'run_date': self.run_date + } + + def __setstate__(self, state): + # This is for compatibility with APScheduler 3.0.x + if isinstance(state, tuple): + state = state[1] + + if state.get('version', 1) > 1: + raise ValueError( + 'Got serialized data for version %s of %s, but only version 1 can be handled' % + (state['version'], self.__class__.__name__)) + + self.run_date = state['run_date'] + + def __str__(self): + return 'date[%s]' % datetime_repr(self.run_date) + + def __repr__(self): + return "<%s (run_date='%s')>" % (self.__class__.__name__, datetime_repr(self.run_date)) diff --git a/venv/lib/python3.8/site-packages/apscheduler/triggers/interval.py b/venv/lib/python3.8/site-packages/apscheduler/triggers/interval.py new file mode 100644 index 0000000..831ba38 --- /dev/null +++ b/venv/lib/python3.8/site-packages/apscheduler/triggers/interval.py @@ -0,0 +1,106 @@ +from datetime import timedelta, datetime +from math import ceil + +from tzlocal import get_localzone + +from apscheduler.triggers.base import BaseTrigger +from apscheduler.util import convert_to_datetime, timedelta_seconds, datetime_repr, astimezone + + +class IntervalTrigger(BaseTrigger): + """ + Triggers on specified intervals, starting on ``start_date`` if specified, ``datetime.now()`` + + interval otherwise. + + :param int weeks: number of weeks to wait + :param int days: number of days to wait + :param int hours: number of hours to wait + :param int minutes: number of minutes to wait + :param int seconds: number of seconds to wait + :param datetime|str start_date: starting point for the interval calculation + :param datetime|str end_date: latest possible date/time to trigger on + :param datetime.tzinfo|str timezone: time zone to use for the date/time calculations + :param int|None jitter: advance or delay the job execution by ``jitter`` seconds at most. + """ + + __slots__ = 'timezone', 'start_date', 'end_date', 'interval', 'interval_length', 'jitter' + + def __init__(self, weeks=0, days=0, hours=0, minutes=0, seconds=0, start_date=None, + end_date=None, timezone=None, jitter=None): + self.interval = timedelta(weeks=weeks, days=days, hours=hours, minutes=minutes, + seconds=seconds) + self.interval_length = timedelta_seconds(self.interval) + if self.interval_length == 0: + self.interval = timedelta(seconds=1) + self.interval_length = 1 + + if timezone: + self.timezone = astimezone(timezone) + elif isinstance(start_date, datetime) and start_date.tzinfo: + self.timezone = start_date.tzinfo + elif isinstance(end_date, datetime) and end_date.tzinfo: + self.timezone = end_date.tzinfo + else: + self.timezone = get_localzone() + + start_date = start_date or (datetime.now(self.timezone) + self.interval) + self.start_date = convert_to_datetime(start_date, self.timezone, 'start_date') + self.end_date = convert_to_datetime(end_date, self.timezone, 'end_date') + + self.jitter = jitter + + def get_next_fire_time(self, previous_fire_time, now): + if previous_fire_time: + next_fire_time = previous_fire_time + self.interval + elif self.start_date > now: + next_fire_time = self.start_date + else: + timediff_seconds = timedelta_seconds(now - self.start_date) + next_interval_num = int(ceil(timediff_seconds / self.interval_length)) + next_fire_time = self.start_date + self.interval * next_interval_num + + if self.jitter is not None: + next_fire_time = self._apply_jitter(next_fire_time, self.jitter, now) + + if not self.end_date or next_fire_time <= self.end_date: + return self.timezone.normalize(next_fire_time) + + def __getstate__(self): + return { + 'version': 2, + 'timezone': self.timezone, + 'start_date': self.start_date, + 'end_date': self.end_date, + 'interval': self.interval, + 'jitter': self.jitter, + } + + def __setstate__(self, state): + # This is for compatibility with APScheduler 3.0.x + if isinstance(state, tuple): + state = state[1] + + if state.get('version', 1) > 2: + raise ValueError( + 'Got serialized data for version %s of %s, but only versions up to 2 can be ' + 'handled' % (state['version'], self.__class__.__name__)) + + self.timezone = state['timezone'] + self.start_date = state['start_date'] + self.end_date = state['end_date'] + self.interval = state['interval'] + self.interval_length = timedelta_seconds(self.interval) + self.jitter = state.get('jitter') + + def __str__(self): + return 'interval[%s]' % str(self.interval) + + def __repr__(self): + options = ['interval=%r' % self.interval, 'start_date=%r' % datetime_repr(self.start_date)] + if self.end_date: + options.append("end_date=%r" % datetime_repr(self.end_date)) + if self.jitter: + options.append('jitter=%s' % self.jitter) + + return "<%s (%s, timezone='%s')>" % ( + self.__class__.__name__, ', '.join(options), self.timezone) diff --git a/venv/lib/python3.8/site-packages/apscheduler/util.py b/venv/lib/python3.8/site-packages/apscheduler/util.py new file mode 100644 index 0000000..8b7b3f5 --- /dev/null +++ b/venv/lib/python3.8/site-packages/apscheduler/util.py @@ -0,0 +1,429 @@ +"""This module contains several handy functions primarily meant for internal use.""" + +from __future__ import division + +from datetime import date, datetime, time, timedelta, tzinfo +from calendar import timegm +from functools import partial +from inspect import isclass, ismethod +import re + +from pytz import timezone, utc, FixedOffset +import six + +try: + from inspect import signature +except ImportError: # pragma: nocover + from funcsigs import signature + +try: + from threading import TIMEOUT_MAX +except ImportError: + TIMEOUT_MAX = 4294967 # Maximum value accepted by Event.wait() on Windows + +try: + from asyncio import iscoroutinefunction +except ImportError: + try: + from trollius import iscoroutinefunction + except ImportError: + def iscoroutinefunction(func): + return False + +__all__ = ('asint', 'asbool', 'astimezone', 'convert_to_datetime', 'datetime_to_utc_timestamp', + 'utc_timestamp_to_datetime', 'timedelta_seconds', 'datetime_ceil', 'get_callable_name', + 'obj_to_ref', 'ref_to_obj', 'maybe_ref', 'repr_escape', 'check_callable_args', + 'TIMEOUT_MAX') + + +class _Undefined(object): + def __nonzero__(self): + return False + + def __bool__(self): + return False + + def __repr__(self): + return '' + + +undefined = _Undefined() #: a unique object that only signifies that no value is defined + + +def asint(text): + """ + Safely converts a string to an integer, returning ``None`` if the string is ``None``. + + :type text: str + :rtype: int + + """ + if text is not None: + return int(text) + + +def asbool(obj): + """ + Interprets an object as a boolean value. + + :rtype: bool + + """ + if isinstance(obj, str): + obj = obj.strip().lower() + if obj in ('true', 'yes', 'on', 'y', 't', '1'): + return True + if obj in ('false', 'no', 'off', 'n', 'f', '0'): + return False + raise ValueError('Unable to interpret value "%s" as boolean' % obj) + return bool(obj) + + +def astimezone(obj): + """ + Interprets an object as a timezone. + + :rtype: tzinfo + + """ + if isinstance(obj, six.string_types): + return timezone(obj) + if isinstance(obj, tzinfo): + if not hasattr(obj, 'localize') or not hasattr(obj, 'normalize'): + raise TypeError('Only timezones from the pytz library are supported') + if obj.zone == 'local': + raise ValueError( + 'Unable to determine the name of the local timezone -- you must explicitly ' + 'specify the name of the local timezone. Please refrain from using timezones like ' + 'EST to prevent problems with daylight saving time. Instead, use a locale based ' + 'timezone name (such as Europe/Helsinki).') + return obj + if obj is not None: + raise TypeError('Expected tzinfo, got %s instead' % obj.__class__.__name__) + + +_DATE_REGEX = re.compile( + r'(?P\d{4})-(?P\d{1,2})-(?P\d{1,2})' + r'(?:[ T](?P\d{1,2}):(?P\d{1,2}):(?P\d{1,2})' + r'(?:\.(?P\d{1,6}))?' + r'(?PZ|[+-]\d\d:\d\d)?)?$') + + +def convert_to_datetime(input, tz, arg_name): + """ + Converts the given object to a timezone aware datetime object. + + If a timezone aware datetime object is passed, it is returned unmodified. + If a native datetime object is passed, it is given the specified timezone. + If the input is a string, it is parsed as a datetime with the given timezone. + + Date strings are accepted in three different forms: date only (Y-m-d), date with time + (Y-m-d H:M:S) or with date+time with microseconds (Y-m-d H:M:S.micro). Additionally you can + override the time zone by giving a specific offset in the format specified by ISO 8601: + Z (UTC), +HH:MM or -HH:MM. + + :param str|datetime input: the datetime or string to convert to a timezone aware datetime + :param datetime.tzinfo tz: timezone to interpret ``input`` in + :param str arg_name: the name of the argument (used in an error message) + :rtype: datetime + + """ + if input is None: + return + elif isinstance(input, datetime): + datetime_ = input + elif isinstance(input, date): + datetime_ = datetime.combine(input, time()) + elif isinstance(input, six.string_types): + m = _DATE_REGEX.match(input) + if not m: + raise ValueError('Invalid date string') + + values = m.groupdict() + tzname = values.pop('timezone') + if tzname == 'Z': + tz = utc + elif tzname: + hours, minutes = (int(x) for x in tzname[1:].split(':')) + sign = 1 if tzname[0] == '+' else -1 + tz = FixedOffset(sign * (hours * 60 + minutes)) + + values = {k: int(v or 0) for k, v in values.items()} + datetime_ = datetime(**values) + else: + raise TypeError('Unsupported type for %s: %s' % (arg_name, input.__class__.__name__)) + + if datetime_.tzinfo is not None: + return datetime_ + if tz is None: + raise ValueError( + 'The "tz" argument must be specified if %s has no timezone information' % arg_name) + if isinstance(tz, six.string_types): + tz = timezone(tz) + + try: + return tz.localize(datetime_, is_dst=None) + except AttributeError: + raise TypeError( + 'Only pytz timezones are supported (need the localize() and normalize() methods)') + + +def datetime_to_utc_timestamp(timeval): + """ + Converts a datetime instance to a timestamp. + + :type timeval: datetime + :rtype: float + + """ + if timeval is not None: + return timegm(timeval.utctimetuple()) + timeval.microsecond / 1000000 + + +def utc_timestamp_to_datetime(timestamp): + """ + Converts the given timestamp to a datetime instance. + + :type timestamp: float + :rtype: datetime + + """ + if timestamp is not None: + return datetime.fromtimestamp(timestamp, utc) + + +def timedelta_seconds(delta): + """ + Converts the given timedelta to seconds. + + :type delta: timedelta + :rtype: float + + """ + return delta.days * 24 * 60 * 60 + delta.seconds + \ + delta.microseconds / 1000000.0 + + +def datetime_ceil(dateval): + """ + Rounds the given datetime object upwards. + + :type dateval: datetime + + """ + if dateval.microsecond > 0: + return dateval + timedelta(seconds=1, microseconds=-dateval.microsecond) + return dateval + + +def datetime_repr(dateval): + return dateval.strftime('%Y-%m-%d %H:%M:%S %Z') if dateval else 'None' + + +def get_callable_name(func): + """ + Returns the best available display name for the given function/callable. + + :rtype: str + + """ + # the easy case (on Python 3.3+) + if hasattr(func, '__qualname__'): + return func.__qualname__ + + # class methods, bound and unbound methods + f_self = getattr(func, '__self__', None) or getattr(func, 'im_self', None) + if f_self and hasattr(func, '__name__'): + f_class = f_self if isclass(f_self) else f_self.__class__ + else: + f_class = getattr(func, 'im_class', None) + + if f_class and hasattr(func, '__name__'): + return '%s.%s' % (f_class.__name__, func.__name__) + + # class or class instance + if hasattr(func, '__call__'): + # class + if hasattr(func, '__name__'): + return func.__name__ + + # instance of a class with a __call__ method + return func.__class__.__name__ + + raise TypeError('Unable to determine a name for %r -- maybe it is not a callable?' % func) + + +def obj_to_ref(obj): + """ + Returns the path to the given callable. + + :rtype: str + :raises TypeError: if the given object is not callable + :raises ValueError: if the given object is a :class:`~functools.partial`, lambda or a nested + function + + """ + if isinstance(obj, partial): + raise ValueError('Cannot create a reference to a partial()') + + name = get_callable_name(obj) + if '' in name: + raise ValueError('Cannot create a reference to a lambda') + if '' in name: + raise ValueError('Cannot create a reference to a nested function') + + if ismethod(obj): + if hasattr(obj, 'im_self') and obj.im_self: + # bound method + module = obj.im_self.__module__ + elif hasattr(obj, 'im_class') and obj.im_class: + # unbound method + module = obj.im_class.__module__ + else: + module = obj.__module__ + else: + module = obj.__module__ + return '%s:%s' % (module, name) + + +def ref_to_obj(ref): + """ + Returns the object pointed to by ``ref``. + + :type ref: str + + """ + if not isinstance(ref, six.string_types): + raise TypeError('References must be strings') + if ':' not in ref: + raise ValueError('Invalid reference') + + modulename, rest = ref.split(':', 1) + try: + obj = __import__(modulename, fromlist=[rest]) + except ImportError: + raise LookupError('Error resolving reference %s: could not import module' % ref) + + try: + for name in rest.split('.'): + obj = getattr(obj, name) + return obj + except Exception: + raise LookupError('Error resolving reference %s: error looking up object' % ref) + + +def maybe_ref(ref): + """ + Returns the object that the given reference points to, if it is indeed a reference. + If it is not a reference, the object is returned as-is. + + """ + if not isinstance(ref, str): + return ref + return ref_to_obj(ref) + + +if six.PY2: + def repr_escape(string): + if isinstance(string, six.text_type): + return string.encode('ascii', 'backslashreplace') + return string +else: + def repr_escape(string): + return string + + +def check_callable_args(func, args, kwargs): + """ + Ensures that the given callable can be called with the given arguments. + + :type args: tuple + :type kwargs: dict + + """ + pos_kwargs_conflicts = [] # parameters that have a match in both args and kwargs + positional_only_kwargs = [] # positional-only parameters that have a match in kwargs + unsatisfied_args = [] # parameters in signature that don't have a match in args or kwargs + unsatisfied_kwargs = [] # keyword-only arguments that don't have a match in kwargs + unmatched_args = list(args) # args that didn't match any of the parameters in the signature + # kwargs that didn't match any of the parameters in the signature + unmatched_kwargs = list(kwargs) + # indicates if the signature defines *args and **kwargs respectively + has_varargs = has_var_kwargs = False + + try: + sig = signature(func) + except ValueError: + # signature() doesn't work against every kind of callable + return + + for param in six.itervalues(sig.parameters): + if param.kind == param.POSITIONAL_OR_KEYWORD: + if param.name in unmatched_kwargs and unmatched_args: + pos_kwargs_conflicts.append(param.name) + elif unmatched_args: + del unmatched_args[0] + elif param.name in unmatched_kwargs: + unmatched_kwargs.remove(param.name) + elif param.default is param.empty: + unsatisfied_args.append(param.name) + elif param.kind == param.POSITIONAL_ONLY: + if unmatched_args: + del unmatched_args[0] + elif param.name in unmatched_kwargs: + unmatched_kwargs.remove(param.name) + positional_only_kwargs.append(param.name) + elif param.default is param.empty: + unsatisfied_args.append(param.name) + elif param.kind == param.KEYWORD_ONLY: + if param.name in unmatched_kwargs: + unmatched_kwargs.remove(param.name) + elif param.default is param.empty: + unsatisfied_kwargs.append(param.name) + elif param.kind == param.VAR_POSITIONAL: + has_varargs = True + elif param.kind == param.VAR_KEYWORD: + has_var_kwargs = True + + # Make sure there are no conflicts between args and kwargs + if pos_kwargs_conflicts: + raise ValueError('The following arguments are supplied in both args and kwargs: %s' % + ', '.join(pos_kwargs_conflicts)) + + # Check if keyword arguments are being fed to positional-only parameters + if positional_only_kwargs: + raise ValueError('The following arguments cannot be given as keyword arguments: %s' % + ', '.join(positional_only_kwargs)) + + # Check that the number of positional arguments minus the number of matched kwargs matches the + # argspec + if unsatisfied_args: + raise ValueError('The following arguments have not been supplied: %s' % + ', '.join(unsatisfied_args)) + + # Check that all keyword-only arguments have been supplied + if unsatisfied_kwargs: + raise ValueError( + 'The following keyword-only arguments have not been supplied in kwargs: %s' % + ', '.join(unsatisfied_kwargs)) + + # Check that the callable can accept the given number of positional arguments + if not has_varargs and unmatched_args: + raise ValueError( + 'The list of positional arguments is longer than the target callable can handle ' + '(allowed: %d, given in args: %d)' % (len(args) - len(unmatched_args), len(args))) + + # Check that the callable can accept the given keyword arguments + if not has_var_kwargs and unmatched_kwargs: + raise ValueError( + 'The target callable does not accept the following keyword arguments: %s' % + ', '.join(unmatched_kwargs)) + + +def iscoroutinefunction_partial(f): + while isinstance(f, partial): + f = f.func + + # The asyncio version of iscoroutinefunction includes testing for @coroutine + # decorations vs. the inspect version which does not. + return iscoroutinefunction(f) diff --git a/venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/INSTALLER b/venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/LICENSE b/venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/LICENSE new file mode 100644 index 0000000..fc2146e --- /dev/null +++ b/venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/LICENSE @@ -0,0 +1,20 @@ +The MIT License (MIT) + +Copyright (c) 2014-2021 Thomas Kemmer + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/METADATA b/venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/METADATA new file mode 100644 index 0000000..221d110 --- /dev/null +++ b/venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/METADATA @@ -0,0 +1,129 @@ +Metadata-Version: 2.1 +Name: cachetools +Version: 4.2.2 +Summary: Extensible memoizing collections and decorators +Home-page: https://github.com/tkem/cachetools/ +Author: Thomas Kemmer +Author-email: tkemmer@computer.org +License: MIT +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Other Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.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 :: Software Development :: Libraries :: Python Modules +Requires-Python: ~=3.5 + +cachetools +======================================================================== + +.. image:: https://img.shields.io/pypi/v/cachetools + :target: https://pypi.org/project/cachetools/ + :alt: Latest PyPI version + +.. image:: https://img.shields.io/readthedocs/cachetools + :target: https://cachetools.readthedocs.io/ + :alt: Documentation build status + +.. image:: https://img.shields.io/travis/tkem/cachetools + :target: https://travis-ci.org/tkem/cachetools/ + :alt: Travis CI build status + +.. image:: https://img.shields.io/coveralls/tkem/cachetools + :target: https://coveralls.io/r/tkem/cachetools + :alt: Test coverage + +.. image:: https://img.shields.io/github/license/tkem/cachetools + :target: https://raw.github.com/tkem/cachetools/master/LICENSE + :alt: License + +.. image:: https://img.shields.io/badge/code%20style-black-000000.svg + :target: https://github.com/psf/black + :alt: Code style: black + +This module provides various memoizing collections and decorators, +including variants of the Python Standard Library's `@lru_cache`_ +function decorator. + +.. code-block:: python + + from cachetools import cached, LRUCache, TTLCache + + # speed up calculating Fibonacci numbers with dynamic programming + @cached(cache={}) + def fib(n): + return n if n < 2 else fib(n - 1) + fib(n - 2) + + # cache least recently used Python Enhancement Proposals + @cached(cache=LRUCache(maxsize=32)) + def get_pep(num): + url = 'http://www.python.org/dev/peps/pep-%04d/' % num + with urllib.request.urlopen(url) as s: + return s.read() + + # cache weather data for no longer than ten minutes + @cached(cache=TTLCache(maxsize=1024, ttl=600)) + def get_weather(place): + return owm.weather_at_place(place).get_weather() + +For the purpose of this module, a *cache* is a mutable_ mapping_ of a +fixed maximum size. When the cache is full, i.e. by adding another +item the cache would exceed its maximum size, the cache must choose +which item(s) to discard based on a suitable `cache algorithm`_. In +general, a cache's size is the total size of its items, and an item's +size is a property or function of its value, e.g. the result of +``sys.getsizeof(value)``. For the trivial but common case that each +item counts as ``1``, a cache's size is equal to the number of its +items, or ``len(cache)``. + +Multiple cache classes based on different caching algorithms are +implemented, and decorators for easily memoizing function and method +calls are provided, too. + + +Installation +------------------------------------------------------------------------ + +cachetools is available from PyPI_ and can be installed by running:: + + pip install cachetools + + +Project Resources +------------------------------------------------------------------------ + +- `Documentation`_ +- `Issue tracker`_ +- `Source code`_ +- `Change log`_ + + +License +------------------------------------------------------------------------ + +Copyright (c) 2014-2021 Thomas Kemmer. + +Licensed under the `MIT License`_. + + +.. _@lru_cache: https://docs.python.org/3/library/functools.html#functools.lru_cache +.. _mutable: https://docs.python.org/dev/glossary.html#term-mutable +.. _mapping: https://docs.python.org/dev/glossary.html#term-mapping +.. _cache algorithm: https://en.wikipedia.org/wiki/Cache_algorithms + +.. _PyPI: https://pypi.org/project/cachetools/ +.. _Documentation: https://cachetools.readthedocs.io/ +.. _Issue tracker: https://github.com/tkem/cachetools/issues/ +.. _Source code: https://github.com/tkem/cachetools/ +.. _Change log: https://github.com/tkem/cachetools/blob/master/CHANGELOG.rst +.. _MIT License: https://raw.github.com/tkem/cachetools/master/LICENSE + + diff --git a/venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/RECORD b/venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/RECORD new file mode 100644 index 0000000..82787c0 --- /dev/null +++ b/venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/RECORD @@ -0,0 +1,28 @@ +cachetools-4.2.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +cachetools-4.2.2.dist-info/LICENSE,sha256=cJEEfa2G-tF5p3smluByDLAX4PRo1HT_PvXKLpe1qQY,1085 +cachetools-4.2.2.dist-info/METADATA,sha256=2-1CYiDO6nrahV7tMFhZBmh5AdoqIPL8gtoxsVAgYiA,4582 +cachetools-4.2.2.dist-info/RECORD,, +cachetools-4.2.2.dist-info/WHEEL,sha256=OqRkF0eY5GHssMorFjlbTIq072vpHpF60fIQA6lS9xA,92 +cachetools-4.2.2.dist-info/top_level.txt,sha256=ai2FH78TGwoBcCgVfoqbzk5IQCtnDukdSs4zKuVPvDs,11 +cachetools/__init__.py,sha256=INbZdXJjaPHFNkdeHh03OCeAKWOKvvtHeWM1rfrm7Lk,463 +cachetools/__pycache__/__init__.cpython-38.pyc,, +cachetools/__pycache__/cache.cpython-38.pyc,, +cachetools/__pycache__/decorators.cpython-38.pyc,, +cachetools/__pycache__/fifo.cpython-38.pyc,, +cachetools/__pycache__/func.cpython-38.pyc,, +cachetools/__pycache__/keys.cpython-38.pyc,, +cachetools/__pycache__/lfu.cpython-38.pyc,, +cachetools/__pycache__/lru.cpython-38.pyc,, +cachetools/__pycache__/mru.cpython-38.pyc,, +cachetools/__pycache__/rr.cpython-38.pyc,, +cachetools/__pycache__/ttl.cpython-38.pyc,, +cachetools/cache.py,sha256=8iJ0a0exyZk20UNdope-eTxC473Eiq3QHmkSOz95ojE,2886 +cachetools/decorators.py,sha256=7nKyHBQg3qNdCB_PqGXipjYwECeSXTznm5xzlAM8_Jo,2983 +cachetools/fifo.py,sha256=_T2rdopIZk7NfIOOw8FkZOtcVMUalSQt9BXisUFGzqE,946 +cachetools/func.py,sha256=OBTNzjaTlyZHKZkY812MuxrCHtuHWDTi7VTplN7vJs0,4975 +cachetools/keys.py,sha256=SfGPnF5Goo1b8V-lrhB9Jxgqd3vm80R9h50k0hsAAjM,1466 +cachetools/lfu.py,sha256=kFj6k_4E8ryoom2SiIXUpMWsCZktZ0TFSeCzoi-4aP0,1103 +cachetools/lru.py,sha256=LD-A5cVyMLyeTMENwuyNcqBcjZ_QnaWTPJX4-4ii9zs,1224 +cachetools/mru.py,sha256=7o99EG4Tg6BdoAPUNpiPmtxM3Paudw9whOONOcGLPkM,1244 +cachetools/rr.py,sha256=zxhJi_Qkp3BQ_1vxj1atAWONfANYzwJficGLmTTTuUs,948 +cachetools/ttl.py,sha256=kQng24LIBhvSDtzD2NRrr4mEbPN7NsyQlsOxbdffhKk,5769 diff --git a/venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/WHEEL b/venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/WHEEL new file mode 100644 index 0000000..385faab --- /dev/null +++ b/venv/lib/python3.8/site-packages/cachetools-4.2.2.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/venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/top_level.txt b/venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/top_level.txt new file mode 100644 index 0000000..50d1408 --- /dev/null +++ b/venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/top_level.txt @@ -0,0 +1 @@ +cachetools diff --git a/venv/lib/python3.8/site-packages/cachetools/__init__.py b/venv/lib/python3.8/site-packages/cachetools/__init__.py new file mode 100644 index 0000000..c9d37e2 --- /dev/null +++ b/venv/lib/python3.8/site-packages/cachetools/__init__.py @@ -0,0 +1,24 @@ +"""Extensible memoizing collections and decorators.""" + +from .cache import Cache +from .decorators import cached, cachedmethod +from .fifo import FIFOCache +from .lfu import LFUCache +from .lru import LRUCache +from .mru import MRUCache +from .rr import RRCache +from .ttl import TTLCache + +__all__ = ( + "Cache", + "FIFOCache", + "LFUCache", + "LRUCache", + "MRUCache", + "RRCache", + "TTLCache", + "cached", + "cachedmethod", +) + +__version__ = "4.2.2" diff --git a/venv/lib/python3.8/site-packages/cachetools/cache.py b/venv/lib/python3.8/site-packages/cachetools/cache.py new file mode 100644 index 0000000..973d50b --- /dev/null +++ b/venv/lib/python3.8/site-packages/cachetools/cache.py @@ -0,0 +1,117 @@ +from collections.abc import MutableMapping + + +class _DefaultSize: + + __slots__ = () + + def __getitem__(self, _): + return 1 + + def __setitem__(self, _, value): + assert value == 1 + + def pop(self, _): + return 1 + + +class Cache(MutableMapping): + """Mutable mapping to serve as a simple cache or cache base class.""" + + __marker = object() + + __size = _DefaultSize() + + def __init__(self, maxsize, getsizeof=None): + if getsizeof: + self.getsizeof = getsizeof + if self.getsizeof is not Cache.getsizeof: + self.__size = dict() + self.__data = dict() + self.__currsize = 0 + self.__maxsize = maxsize + + def __repr__(self): + return "%s(%r, maxsize=%r, currsize=%r)" % ( + self.__class__.__name__, + list(self.__data.items()), + self.__maxsize, + self.__currsize, + ) + + def __getitem__(self, key): + try: + return self.__data[key] + except KeyError: + return self.__missing__(key) + + def __setitem__(self, key, value): + maxsize = self.__maxsize + size = self.getsizeof(value) + if size > maxsize: + raise ValueError("value too large") + if key not in self.__data or self.__size[key] < size: + while self.__currsize + size > maxsize: + self.popitem() + if key in self.__data: + diffsize = size - self.__size[key] + else: + diffsize = size + self.__data[key] = value + self.__size[key] = size + self.__currsize += diffsize + + def __delitem__(self, key): + size = self.__size.pop(key) + del self.__data[key] + self.__currsize -= size + + def __contains__(self, key): + return key in self.__data + + def __missing__(self, key): + raise KeyError(key) + + def __iter__(self): + return iter(self.__data) + + def __len__(self): + return len(self.__data) + + def get(self, key, default=None): + if key in self: + return self[key] + else: + return default + + def pop(self, key, default=__marker): + if key in self: + value = self[key] + del self[key] + elif default is self.__marker: + raise KeyError(key) + else: + value = default + return value + + def setdefault(self, key, default=None): + if key in self: + value = self[key] + else: + self[key] = value = default + return value + + @property + def maxsize(self): + """The maximum size of the cache.""" + return self.__maxsize + + @property + def currsize(self): + """The current size of the cache.""" + return self.__currsize + + @staticmethod + def getsizeof(value): + """Return the size of a cache element's value.""" + return 1 diff --git a/venv/lib/python3.8/site-packages/cachetools/decorators.py b/venv/lib/python3.8/site-packages/cachetools/decorators.py new file mode 100644 index 0000000..3e78603 --- /dev/null +++ b/venv/lib/python3.8/site-packages/cachetools/decorators.py @@ -0,0 +1,102 @@ +import functools + +from .keys import hashkey + + +def cached(cache, key=hashkey, lock=None): + """Decorator to wrap a function with a memoizing callable that saves + results in a cache. + + """ + + def decorator(func): + if cache is None: + + def wrapper(*args, **kwargs): + return func(*args, **kwargs) + + elif lock is None: + + def wrapper(*args, **kwargs): + k = key(*args, **kwargs) + try: + return cache[k] + except KeyError: + pass # key not found + v = func(*args, **kwargs) + try: + cache[k] = v + except ValueError: + pass # value too large + return v + + else: + + def wrapper(*args, **kwargs): + k = key(*args, **kwargs) + try: + with lock: + return cache[k] + except KeyError: + pass # key not found + v = func(*args, **kwargs) + # in case of a race, prefer the item already in the cache + try: + with lock: + return cache.setdefault(k, v) + except ValueError: + return v # value too large + + return functools.update_wrapper(wrapper, func) + + return decorator + + +def cachedmethod(cache, key=hashkey, lock=None): + """Decorator to wrap a class or instance method with a memoizing + callable that saves results in a cache. + + """ + + def decorator(method): + if lock is None: + + def wrapper(self, *args, **kwargs): + c = cache(self) + if c is None: + return method(self, *args, **kwargs) + k = key(*args, **kwargs) + try: + return c[k] + except KeyError: + pass # key not found + v = method(self, *args, **kwargs) + try: + c[k] = v + except ValueError: + pass # value too large + return v + + else: + + def wrapper(self, *args, **kwargs): + c = cache(self) + if c is None: + return method(self, *args, **kwargs) + k = key(*args, **kwargs) + try: + with lock(self): + return c[k] + except KeyError: + pass # key not found + v = method(self, *args, **kwargs) + # in case of a race, prefer the item already in the cache + try: + with lock(self): + return c.setdefault(k, v) + except ValueError: + return v # value too large + + return functools.update_wrapper(wrapper, method) + + return decorator diff --git a/venv/lib/python3.8/site-packages/cachetools/fifo.py b/venv/lib/python3.8/site-packages/cachetools/fifo.py new file mode 100644 index 0000000..e7c377e --- /dev/null +++ b/venv/lib/python3.8/site-packages/cachetools/fifo.py @@ -0,0 +1,31 @@ +import collections + +from .cache import Cache + + +class FIFOCache(Cache): + """First In First Out (FIFO) cache implementation.""" + + def __init__(self, maxsize, getsizeof=None): + Cache.__init__(self, maxsize, getsizeof) + self.__order = collections.OrderedDict() + + def __setitem__(self, key, value, cache_setitem=Cache.__setitem__): + cache_setitem(self, key, value) + try: + self.__order.move_to_end(key) + except KeyError: + self.__order[key] = None + + def __delitem__(self, key, cache_delitem=Cache.__delitem__): + cache_delitem(self, key) + del self.__order[key] + + def popitem(self): + """Remove and return the `(key, value)` pair first inserted.""" + try: + key = next(iter(self.__order)) + except StopIteration: + raise KeyError("%s is empty" % type(self).__name__) from None + else: + return (key, self.pop(key)) diff --git a/venv/lib/python3.8/site-packages/cachetools/func.py b/venv/lib/python3.8/site-packages/cachetools/func.py new file mode 100644 index 0000000..57fb72d --- /dev/null +++ b/venv/lib/python3.8/site-packages/cachetools/func.py @@ -0,0 +1,176 @@ +"""`functools.lru_cache` compatible memoizing function decorators.""" + +import collections +import functools +import math +import random +import time + +try: + from threading import RLock +except ImportError: # pragma: no cover + from dummy_threading import RLock + +from . import keys +from .fifo import FIFOCache +from .lfu import LFUCache +from .lru import LRUCache +from .mru import MRUCache +from .rr import RRCache +from .ttl import TTLCache + +__all__ = ("lfu_cache", "lru_cache", "mru_cache", "rr_cache", "ttl_cache") + + +_CacheInfo = collections.namedtuple( + "CacheInfo", ["hits", "misses", "maxsize", "currsize"] +) + + +class _UnboundCache(dict): + @property + def maxsize(self): + return None + + @property + def currsize(self): + return len(self) + + +class _UnboundTTLCache(TTLCache): + def __init__(self, ttl, timer): + TTLCache.__init__(self, math.inf, ttl, timer) + + @property + def maxsize(self): + return None + + +def _cache(cache, typed): + maxsize = cache.maxsize + + def decorator(func): + key = keys.typedkey if typed else keys.hashkey + lock = RLock() + stats = [0, 0] + + def wrapper(*args, **kwargs): + k = key(*args, **kwargs) + with lock: + try: + v = cache[k] + stats[0] += 1 + return v + except KeyError: + stats[1] += 1 + v = func(*args, **kwargs) + # in case of a race, prefer the item already in the cache + try: + with lock: + return cache.setdefault(k, v) + except ValueError: + return v # value too large + + def cache_info(): + with lock: + hits, misses = stats + maxsize = cache.maxsize + currsize = cache.currsize + return _CacheInfo(hits, misses, maxsize, currsize) + + def cache_clear(): + with lock: + try: + cache.clear() + finally: + stats[:] = [0, 0] + + wrapper.cache_info = cache_info + wrapper.cache_clear = cache_clear + wrapper.cache_parameters = lambda: {"maxsize": maxsize, "typed": typed} + functools.update_wrapper(wrapper, func) + return wrapper + + return decorator + + +def fifo_cache(maxsize=128, typed=False): + """Decorator to wrap a function with a memoizing callable that saves + up to `maxsize` results based on a First In First Out (FIFO) + algorithm. + + """ + if maxsize is None: + return _cache(_UnboundCache(), typed) + elif callable(maxsize): + return _cache(FIFOCache(128), typed)(maxsize) + else: + return _cache(FIFOCache(maxsize), typed) + + +def lfu_cache(maxsize=128, typed=False): + """Decorator to wrap a function with a memoizing callable that saves + up to `maxsize` results based on a Least Frequently Used (LFU) + algorithm. + + """ + if maxsize is None: + return _cache(_UnboundCache(), typed) + elif callable(maxsize): + return _cache(LFUCache(128), typed)(maxsize) + else: + return _cache(LFUCache(maxsize), typed) + + +def lru_cache(maxsize=128, typed=False): + """Decorator to wrap a function with a memoizing callable that saves + up to `maxsize` results based on a Least Recently Used (LRU) + algorithm. + + """ + if maxsize is None: + return _cache(_UnboundCache(), typed) + elif callable(maxsize): + return _cache(LRUCache(128), typed)(maxsize) + else: + return _cache(LRUCache(maxsize), typed) + + +def mru_cache(maxsize=128, typed=False): + """Decorator to wrap a function with a memoizing callable that saves + up to `maxsize` results based on a Most Recently Used (MRU) + algorithm. + """ + if maxsize is None: + return _cache(_UnboundCache(), typed) + elif callable(maxsize): + return _cache(MRUCache(128), typed)(maxsize) + else: + return _cache(MRUCache(maxsize), typed) + + +def rr_cache(maxsize=128, choice=random.choice, typed=False): + """Decorator to wrap a function with a memoizing callable that saves + up to `maxsize` results based on a Random Replacement (RR) + algorithm. + + """ + if maxsize is None: + return _cache(_UnboundCache(), typed) + elif callable(maxsize): + return _cache(RRCache(128, choice), typed)(maxsize) + else: + return _cache(RRCache(maxsize, choice), typed) + + +def ttl_cache(maxsize=128, ttl=600, timer=time.monotonic, typed=False): + """Decorator to wrap a function with a memoizing callable that saves + up to `maxsize` results based on a Least Recently Used (LRU) + algorithm with a per-item time-to-live (TTL) value. + """ + if maxsize is None: + return _cache(_UnboundTTLCache(ttl, timer), typed) + elif callable(maxsize): + return _cache(TTLCache(128, ttl, timer), typed)(maxsize) + else: + return _cache(TTLCache(maxsize, ttl, timer), typed) diff --git a/venv/lib/python3.8/site-packages/cachetools/keys.py b/venv/lib/python3.8/site-packages/cachetools/keys.py new file mode 100644 index 0000000..13630a4 --- /dev/null +++ b/venv/lib/python3.8/site-packages/cachetools/keys.py @@ -0,0 +1,52 @@ +"""Key functions for memoizing decorators.""" + +__all__ = ("hashkey", "typedkey") + + +class _HashedTuple(tuple): + """A tuple that ensures that hash() will be called no more than once + per element, since cache decorators will hash the key multiple + times on a cache miss. See also _HashedSeq in the standard + library functools implementation. + + """ + + __hashvalue = None + + def __hash__(self, hash=tuple.__hash__): + hashvalue = self.__hashvalue + if hashvalue is None: + self.__hashvalue = hashvalue = hash(self) + return hashvalue + + def __add__(self, other, add=tuple.__add__): + return _HashedTuple(add(self, other)) + + def __radd__(self, other, add=tuple.__add__): + return _HashedTuple(add(other, self)) + + def __getstate__(self): + return {} + + +# used for separating keyword arguments; we do not use an object +# instance here so identity is preserved when pickling/unpickling +_kwmark = (_HashedTuple,) + + +def hashkey(*args, **kwargs): + """Return a cache key for the specified hashable arguments.""" + + if kwargs: + return _HashedTuple(args + sum(sorted(kwargs.items()), _kwmark)) + else: + return _HashedTuple(args) + + +def typedkey(*args, **kwargs): + """Return a typed cache key for the specified hashable arguments.""" + + key = hashkey(*args, **kwargs) + key += tuple(type(v) for v in args) + key += tuple(type(v) for _, v in sorted(kwargs.items())) + return key diff --git a/venv/lib/python3.8/site-packages/cachetools/lfu.py b/venv/lib/python3.8/site-packages/cachetools/lfu.py new file mode 100644 index 0000000..6289b5c --- /dev/null +++ b/venv/lib/python3.8/site-packages/cachetools/lfu.py @@ -0,0 +1,34 @@ +import collections + +from .cache import Cache + + +class LFUCache(Cache): + """Least Frequently Used (LFU) cache implementation.""" + + def __init__(self, maxsize, getsizeof=None): + Cache.__init__(self, maxsize, getsizeof) + self.__counter = collections.Counter() + + def __getitem__(self, key, cache_getitem=Cache.__getitem__): + value = cache_getitem(self, key) + if key in self: # __missing__ may not store item + self.__counter[key] -= 1 + return value + + def __setitem__(self, key, value, cache_setitem=Cache.__setitem__): + cache_setitem(self, key, value) + self.__counter[key] -= 1 + + def __delitem__(self, key, cache_delitem=Cache.__delitem__): + cache_delitem(self, key) + del self.__counter[key] + + def popitem(self): + """Remove and return the `(key, value)` pair least frequently used.""" + try: + ((key, _),) = self.__counter.most_common(1) + except ValueError: + raise KeyError("%s is empty" % type(self).__name__) from None + else: + return (key, self.pop(key)) diff --git a/venv/lib/python3.8/site-packages/cachetools/lru.py b/venv/lib/python3.8/site-packages/cachetools/lru.py new file mode 100644 index 0000000..dbbe787 --- /dev/null +++ b/venv/lib/python3.8/site-packages/cachetools/lru.py @@ -0,0 +1,40 @@ +import collections + +from .cache import Cache + + +class LRUCache(Cache): + """Least Recently Used (LRU) cache implementation.""" + + def __init__(self, maxsize, getsizeof=None): + Cache.__init__(self, maxsize, getsizeof) + self.__order = collections.OrderedDict() + + def __getitem__(self, key, cache_getitem=Cache.__getitem__): + value = cache_getitem(self, key) + if key in self: # __missing__ may not store item + self.__update(key) + return value + + def __setitem__(self, key, value, cache_setitem=Cache.__setitem__): + cache_setitem(self, key, value) + self.__update(key) + + def __delitem__(self, key, cache_delitem=Cache.__delitem__): + cache_delitem(self, key) + del self.__order[key] + + def popitem(self): + """Remove and return the `(key, value)` pair least recently used.""" + try: + key = next(iter(self.__order)) + except StopIteration: + raise KeyError("%s is empty" % type(self).__name__) from None + else: + return (key, self.pop(key)) + + def __update(self, key): + try: + self.__order.move_to_end(key) + except KeyError: + self.__order[key] = None diff --git a/venv/lib/python3.8/site-packages/cachetools/mru.py b/venv/lib/python3.8/site-packages/cachetools/mru.py new file mode 100644 index 0000000..92ec6db --- /dev/null +++ b/venv/lib/python3.8/site-packages/cachetools/mru.py @@ -0,0 +1,40 @@ +import collections + +from cachetools.cache import Cache + + +class MRUCache(Cache): + """Most Recently Used (MRU) cache implementation.""" + + def __init__(self, maxsize, getsizeof=None): + Cache.__init__(self, maxsize, getsizeof) + self.__order = collections.OrderedDict() + + def __getitem__(self, key, cache_getitem=Cache.__getitem__): + value = cache_getitem(self, key) + if key in self: # __missing__ may not store item + self.__update(key) + return value + + def __setitem__(self, key, value, cache_setitem=Cache.__setitem__): + cache_setitem(self, key, value) + self.__update(key) + + def __delitem__(self, key, cache_delitem=Cache.__delitem__): + cache_delitem(self, key) + del self.__order[key] + + def popitem(self): + """Remove and return the `(key, value)` pair most recently used.""" + try: + key = next(iter(self.__order)) + except StopIteration: + raise KeyError("%s is empty" % type(self).__name__) from None + else: + return (key, self.pop(key)) + + def __update(self, key): + try: + self.__order.move_to_end(key, last=False) + except KeyError: + self.__order[key] = None diff --git a/venv/lib/python3.8/site-packages/cachetools/rr.py b/venv/lib/python3.8/site-packages/cachetools/rr.py new file mode 100644 index 0000000..561dbe5 --- /dev/null +++ b/venv/lib/python3.8/site-packages/cachetools/rr.py @@ -0,0 +1,34 @@ +import random + +from .cache import Cache + + +# random.choice cannot be pickled in Python 2.7 +def _choice(seq): + return random.choice(seq) + + +class RRCache(Cache): + """Random Replacement (RR) cache implementation.""" + + def __init__(self, maxsize, choice=random.choice, getsizeof=None): + Cache.__init__(self, maxsize, getsizeof) + # TODO: use None as default, assing to self.choice directly? + if choice is random.choice: + self.__choice = _choice + else: + self.__choice = choice + + @property + def choice(self): + """The `choice` function used by the cache.""" + return self.__choice + + def popitem(self): + """Remove and return a random `(key, value)` pair.""" + try: + key = self.__choice(list(self)) + except IndexError: + raise KeyError("%s is empty" % type(self).__name__) from None + else: + return (key, self.pop(key)) diff --git a/venv/lib/python3.8/site-packages/cachetools/ttl.py b/venv/lib/python3.8/site-packages/cachetools/ttl.py new file mode 100644 index 0000000..eef8877 --- /dev/null +++ b/venv/lib/python3.8/site-packages/cachetools/ttl.py @@ -0,0 +1,207 @@ +import collections +import time + +from .cache import Cache + + +class _Link: + + __slots__ = ("key", "expire", "next", "prev") + + def __init__(self, key=None, expire=None): + self.key = key + self.expire = expire + + def __reduce__(self): + return _Link, (self.key, self.expire) + + def unlink(self): + next = self.next + prev = self.prev + prev.next = next + next.prev = prev + + +class _Timer: + def __init__(self, timer): + self.__timer = timer + self.__nesting = 0 + + def __call__(self): + if self.__nesting == 0: + return self.__timer() + else: + return self.__time + + def __enter__(self): + if self.__nesting == 0: + self.__time = time = self.__timer() + else: + time = self.__time + self.__nesting += 1 + return time + + def __exit__(self, *exc): + self.__nesting -= 1 + + def __reduce__(self): + return _Timer, (self.__timer,) + + def __getattr__(self, name): + return getattr(self.__timer, name) + + +class TTLCache(Cache): + """LRU Cache implementation with per-item time-to-live (TTL) value.""" + + def __init__(self, maxsize, ttl, timer=time.monotonic, getsizeof=None): + Cache.__init__(self, maxsize, getsizeof) + self.__root = root = _Link() + root.prev = root.next = root + self.__links = collections.OrderedDict() + self.__timer = _Timer(timer) + self.__ttl = ttl + + def __contains__(self, key): + try: + link = self.__links[key] # no reordering + except KeyError: + return False + else: + return not (link.expire < self.__timer()) + + def __getitem__(self, key, cache_getitem=Cache.__getitem__): + try: + link = self.__getlink(key) + except KeyError: + expired = False + else: + expired = link.expire < self.__timer() + if expired: + return self.__missing__(key) + else: + return cache_getitem(self, key) + + def __setitem__(self, key, value, cache_setitem=Cache.__setitem__): + with self.__timer as time: + self.expire(time) + cache_setitem(self, key, value) + try: + link = self.__getlink(key) + except KeyError: + self.__links[key] = link = _Link(key) + else: + link.unlink() + link.expire = time + self.__ttl + link.next = root = self.__root + link.prev = prev = root.prev + prev.next = root.prev = link + + def __delitem__(self, key, cache_delitem=Cache.__delitem__): + cache_delitem(self, key) + link = self.__links.pop(key) + link.unlink() + if link.expire < self.__timer(): + raise KeyError(key) + + def __iter__(self): + root = self.__root + curr = root.next + while curr is not root: + # "freeze" time for iterator access + with self.__timer as time: + if not (curr.expire < time): + yield curr.key + curr = curr.next + + def __len__(self): + root = self.__root + curr = root.next + time = self.__timer() + count = len(self.__links) + while curr is not root and curr.expire < time: + count -= 1 + curr = curr.next + return count + + def __setstate__(self, state): + self.__dict__.update(state) + root = self.__root + root.prev = root.next = root + for link in sorted(self.__links.values(), key=lambda obj: obj.expire): + link.next = root + link.prev = prev = root.prev + prev.next = root.prev = link + self.expire(self.__timer()) + + def __repr__(self, cache_repr=Cache.__repr__): + with self.__timer as time: + self.expire(time) + return cache_repr(self) + + @property + def currsize(self): + with self.__timer as time: + self.expire(time) + return super().currsize + + @property + def timer(self): + """The timer function used by the cache.""" + return self.__timer + + @property + def ttl(self): + """The time-to-live value of the cache's items.""" + return self.__ttl + + def expire(self, time=None): + """Remove expired items from the cache.""" + if time is None: + time = self.__timer() + root = self.__root + curr = root.next + links = self.__links + cache_delitem = Cache.__delitem__ + while curr is not root and curr.expire < time: + cache_delitem(self, curr.key) + del links[curr.key] + next = curr.next + curr.unlink() + curr = next + + def clear(self): + with self.__timer as time: + self.expire(time) + Cache.clear(self) + + def get(self, *args, **kwargs): + with self.__timer: + return Cache.get(self, *args, **kwargs) + + def pop(self, *args, **kwargs): + with self.__timer: + return Cache.pop(self, *args, **kwargs) + + def setdefault(self, *args, **kwargs): + with self.__timer: + return Cache.setdefault(self, *args, **kwargs) + + def popitem(self): + """Remove and return the `(key, value)` pair least recently used that + has not already expired. + + """ + with self.__timer as time: + self.expire(time) + try: + key = next(iter(self.__links)) + except StopIteration: + raise KeyError("%s is empty" % type(self).__name__) from None + else: + return (key, self.pop(key)) + + def __getlink(self, key): + value = self.__links[key] + self.__links.move_to_end(key) + return value diff --git a/venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/INSTALLER b/venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/LICENSE b/venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/LICENSE new file mode 100644 index 0000000..c2fda9a --- /dev/null +++ b/venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/LICENSE @@ -0,0 +1,21 @@ +This package contains a modified version of ca-bundle.crt: + +ca-bundle.crt -- Bundle of CA Root Certificates + +Certificate data from Mozilla as of: Thu Nov 3 19:04:19 2011# +This is a bundle of X.509 certificates of public Certificate Authorities +(CA). These were automatically extracted from Mozilla's root certificates +file (certdata.txt). This file can be found in the mozilla source tree: +http://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1# +It contains the certificates in PEM format and therefore +can be directly used with curl / libcurl / php_curl, or with +an Apache+mod_ssl webserver for SSL client authentication. +Just configure this file as the SSLCACertificateFile.# + +***** BEGIN LICENSE BLOCK ***** +This Source Code Form is subject to the terms of the Mozilla Public License, +v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain +one at http://mozilla.org/MPL/2.0/. + +***** END LICENSE BLOCK ***** +@(#) $RCSfile: certdata.txt,v $ $Revision: 1.80 $ $Date: 2011/11/03 15:11:58 $ diff --git a/venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/METADATA b/venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/METADATA new file mode 100644 index 0000000..df1cc0e --- /dev/null +++ b/venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/METADATA @@ -0,0 +1,83 @@ +Metadata-Version: 2.1 +Name: certifi +Version: 2021.5.30 +Summary: Python package for providing Mozilla's CA Bundle. +Home-page: https://certifiio.readthedocs.io/en/latest/ +Author: Kenneth Reitz +Author-email: me@kennethreitz.com +License: MPL-2.0 +Project-URL: Documentation, https://certifiio.readthedocs.io/en/latest/ +Project-URL: Source, https://github.com/certifi/python-certifi +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0) +Classifier: Natural Language :: English +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.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 + +Certifi: Python SSL Certificates +================================ + +`Certifi`_ provides Mozilla's carefully curated collection of Root Certificates for +validating the trustworthiness of SSL certificates while verifying the identity +of TLS hosts. It has been extracted from the `Requests`_ project. + +Installation +------------ + +``certifi`` is available on PyPI. Simply install it with ``pip``:: + + $ pip install certifi + +Usage +----- + +To reference the installed certificate authority (CA) bundle, you can use the +built-in function:: + + >>> import certifi + + >>> certifi.where() + '/usr/local/lib/python3.7/site-packages/certifi/cacert.pem' + +Or from the command line:: + + $ python -m certifi + /usr/local/lib/python3.7/site-packages/certifi/cacert.pem + +Enjoy! + +1024-bit Root Certificates +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Browsers and certificate authorities have concluded that 1024-bit keys are +unacceptably weak for certificates, particularly root certificates. For this +reason, Mozilla has removed any weak (i.e. 1024-bit key) certificate from its +bundle, replacing it with an equivalent strong (i.e. 2048-bit or greater key) +certificate from the same CA. Because Mozilla removed these certificates from +its bundle, ``certifi`` removed them as well. + +In previous versions, ``certifi`` provided the ``certifi.old_where()`` function +to intentionally re-add the 1024-bit roots back into your bundle. This was not +recommended in production and therefore was removed at the end of 2018. + +.. _`Certifi`: https://certifiio.readthedocs.io/en/latest/ +.. _`Requests`: https://requests.readthedocs.io/en/master/ + +Addition/Removal of Certificates +-------------------------------- + +Certifi does not support any addition/removal or other modification of the +CA trust store content. This project is intended to provide a reliable and +highly portable root of trust to python deployments. Look to upstream projects +for methods to use alternate trust. + + diff --git a/venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/RECORD b/venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/RECORD new file mode 100644 index 0000000..f2d2621 --- /dev/null +++ b/venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/RECORD @@ -0,0 +1,13 @@ +certifi-2021.5.30.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +certifi-2021.5.30.dist-info/LICENSE,sha256=vp2C82ES-Hp_HXTs1Ih-FGe7roh4qEAEoAEXseR1o-I,1049 +certifi-2021.5.30.dist-info/METADATA,sha256=RDzuah_IZxjVhKootR1Ha1BrDovPSA-xF-rcaD90PTo,2994 +certifi-2021.5.30.dist-info/RECORD,, +certifi-2021.5.30.dist-info/WHEEL,sha256=ADKeyaGyKF5DwBNE0sRE5pvW-bSkFMJfBuhzZ3rceP4,110 +certifi-2021.5.30.dist-info/top_level.txt,sha256=KMu4vUCfsjLrkPbSNdgdekS-pVJzBAJFO__nI8NF6-U,8 +certifi/__init__.py,sha256=-b78tXibbl0qtgCzv9tc9v6ozwcNX915lT9Tf4a9lds,62 +certifi/__main__.py,sha256=xBBoj905TUWBLRGANOcf7oi6e-3dMP4cEoG9OyMs11g,243 +certifi/__pycache__/__init__.cpython-38.pyc,, +certifi/__pycache__/__main__.cpython-38.pyc,, +certifi/__pycache__/core.cpython-38.pyc,, +certifi/cacert.pem,sha256=3i-hfE2K5o3CBKG2tYt6ehJWk2fP64o6Th83fHPoPp4,259465 +certifi/core.py,sha256=V0uyxKOYdz6ulDSusclrLmjbPgOXsD0BnEf0SQ7OnoE,2303 diff --git a/venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/WHEEL b/venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/WHEEL new file mode 100644 index 0000000..6d38aa0 --- /dev/null +++ b/venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.35.1) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/top_level.txt b/venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/top_level.txt new file mode 100644 index 0000000..963eac5 --- /dev/null +++ b/venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/top_level.txt @@ -0,0 +1 @@ +certifi diff --git a/venv/lib/python3.8/site-packages/certifi/__init__.py b/venv/lib/python3.8/site-packages/certifi/__init__.py new file mode 100644 index 0000000..eebdf88 --- /dev/null +++ b/venv/lib/python3.8/site-packages/certifi/__init__.py @@ -0,0 +1,3 @@ +from .core import contents, where + +__version__ = "2021.05.30" diff --git a/venv/lib/python3.8/site-packages/certifi/__main__.py b/venv/lib/python3.8/site-packages/certifi/__main__.py new file mode 100644 index 0000000..8945b5d --- /dev/null +++ b/venv/lib/python3.8/site-packages/certifi/__main__.py @@ -0,0 +1,12 @@ +import argparse + +from certifi import contents, where + +parser = argparse.ArgumentParser() +parser.add_argument("-c", "--contents", action="store_true") +args = parser.parse_args() + +if args.contents: + print(contents()) +else: + print(where()) diff --git a/venv/lib/python3.8/site-packages/certifi/cacert.pem b/venv/lib/python3.8/site-packages/certifi/cacert.pem new file mode 100644 index 0000000..96e2fc6 --- /dev/null +++ b/venv/lib/python3.8/site-packages/certifi/cacert.pem @@ -0,0 +1,4257 @@ + +# Issuer: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA +# Subject: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA +# Label: "GlobalSign Root CA" +# Serial: 4835703278459707669005204 +# MD5 Fingerprint: 3e:45:52:15:09:51:92:e1:b7:5d:37:9f:b1:87:29:8a +# SHA1 Fingerprint: b1:bc:96:8b:d4:f4:9d:62:2a:a8:9a:81:f2:15:01:52:a4:1d:82:9c +# SHA256 Fingerprint: eb:d4:10:40:e4:bb:3e:c7:42:c9:e3:81:d3:1e:f2:a4:1a:48:b6:68:5c:96:e7:ce:f3:c1:df:6c:d4:33:1c:99 +-----BEGIN CERTIFICATE----- +MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG +A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv +b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw +MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i +YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT +aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ +jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp +xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp +1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG +snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ +U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 +9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E +BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B +AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz +yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE +38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP +AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad +DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME +HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R2 +# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R2 +# Label: "GlobalSign Root CA - R2" +# Serial: 4835703278459682885658125 +# MD5 Fingerprint: 94:14:77:7e:3e:5e:fd:8f:30:bd:41:b0:cf:e7:d0:30 +# SHA1 Fingerprint: 75:e0:ab:b6:13:85:12:27:1c:04:f8:5f:dd:de:38:e4:b7:24:2e:fe +# SHA256 Fingerprint: ca:42:dd:41:74:5f:d0:b8:1e:b9:02:36:2c:f9:d8:bf:71:9d:a1:bd:1b:1e:fc:94:6f:5b:4c:99:f4:2c:1b:9e +-----BEGIN CERTIFICATE----- +MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G +A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp +Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1 +MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG +A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL +v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8 +eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq +tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd +C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa +zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB +mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH +V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n +bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG +3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs +J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO +291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS +ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd +AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 +TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== +-----END CERTIFICATE----- + +# Issuer: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited +# Subject: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited +# Label: "Entrust.net Premium 2048 Secure Server CA" +# Serial: 946069240 +# MD5 Fingerprint: ee:29:31:bc:32:7e:9a:e6:e8:b5:f7:51:b4:34:71:90 +# SHA1 Fingerprint: 50:30:06:09:1d:97:d4:f5:ae:39:f7:cb:e7:92:7d:7d:65:2d:34:31 +# SHA256 Fingerprint: 6d:c4:71:72:e0:1c:bc:b0:bf:62:58:0d:89:5f:e2:b8:ac:9a:d4:f8:73:80:1e:0c:10:b9:c8:37:d2:1e:b1:77 +-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML +RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp +bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 +IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0yOTA3 +MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 +LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp +YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG +A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq +K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe +sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX +MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT +XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ +HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH +4QIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJKoZIhvcNAQEFBQADggEBADub +j1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPyT/4xmf3IDExo +U8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf +zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5b +u/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+ +bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er +fF6adulZkMV8gzURZVE= +-----END CERTIFICATE----- + +# Issuer: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust +# Subject: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust +# Label: "Baltimore CyberTrust Root" +# Serial: 33554617 +# MD5 Fingerprint: ac:b6:94:a5:9c:17:e0:d7:91:52:9b:b1:97:06:a6:e4 +# SHA1 Fingerprint: d4:de:20:d0:5e:66:fc:53:fe:1a:50:88:2c:78:db:28:52:ca:e4:74 +# SHA256 Fingerprint: 16:af:57:a9:f6:76:b0:ab:12:60:95:aa:5e:ba:de:f2:2a:b3:11:19:d6:44:ac:95:cd:4b:93:db:f3:f2:6a:eb +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ +RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD +VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX +DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y +ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy +VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr +mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr +IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK +mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu +XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy +dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye +jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1 +BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 +DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92 +9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx +jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 +Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz +ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS +R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp +-----END CERTIFICATE----- + +# Issuer: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc. +# Subject: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc. +# Label: "Entrust Root Certification Authority" +# Serial: 1164660820 +# MD5 Fingerprint: d6:a5:c3:ed:5d:dd:3e:00:c1:3d:87:92:1f:1d:3f:e4 +# SHA1 Fingerprint: b3:1e:b1:b7:40:e3:6c:84:02:da:dc:37:d4:4d:f5:d4:67:49:52:f9 +# SHA256 Fingerprint: 73:c1:76:43:4f:1b:c6:d5:ad:f4:5b:0e:76:e7:27:28:7c:8d:e5:76:16:c1:e6:e6:14:1a:2b:2c:bc:7d:8e:4c +-----BEGIN CERTIFICATE----- +MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 +Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW +KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl +cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw +NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw +NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy +ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV +BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo +Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4 +4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9 +KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI +rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi +94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB +sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi +gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo +kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE +vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA +A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t +O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua +AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP +9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/ +eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m +0vdXcDazv/wor3ElhVsT/h5/WrQ8 +-----END CERTIFICATE----- + +# Issuer: CN=AAA Certificate Services O=Comodo CA Limited +# Subject: CN=AAA Certificate Services O=Comodo CA Limited +# Label: "Comodo AAA Services root" +# Serial: 1 +# MD5 Fingerprint: 49:79:04:b0:eb:87:19:ac:47:b0:bc:11:51:9b:74:d0 +# SHA1 Fingerprint: d1:eb:23:a4:6d:17:d6:8f:d9:25:64:c2:f1:f1:60:17:64:d8:e3:49 +# SHA256 Fingerprint: d7:a7:a0:fb:5d:7e:27:31:d7:71:e9:48:4e:bc:de:f7:1d:5f:0c:3e:0a:29:48:78:2b:c8:3e:e0:ea:69:9e:f4 +-----BEGIN CERTIFICATE----- +MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb +MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow +GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj +YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL +MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE +BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM +GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua +BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe +3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4 +YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR +rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm +ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU +oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF +MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v +QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t +b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF +AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q +GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz +Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2 +G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi +l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3 +smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== +-----END CERTIFICATE----- + +# Issuer: CN=QuoVadis Root CA 2 O=QuoVadis Limited +# Subject: CN=QuoVadis Root CA 2 O=QuoVadis Limited +# Label: "QuoVadis Root CA 2" +# Serial: 1289 +# MD5 Fingerprint: 5e:39:7b:dd:f8:ba:ec:82:e9:ac:62:ba:0c:54:00:2b +# SHA1 Fingerprint: ca:3a:fb:cf:12:40:36:4b:44:b2:16:20:88:80:48:39:19:93:7c:f7 +# SHA256 Fingerprint: 85:a0:dd:7d:d7:20:ad:b7:ff:05:f8:3d:54:2b:20:9d:c7:ff:45:28:f7:d6:77:b1:83:89:fe:a5:e5:c4:9e:86 +-----BEGIN CERTIFICATE----- +MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x +GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv +b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV +BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W +YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa +GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg +Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J +WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB +rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp ++ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1 +ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i +Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz +PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og +/zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH +oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI +yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud +EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2 +A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL +MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT +ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f +BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn +g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl +fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K +WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha +B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc +hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR +TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD +mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z +ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y +4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza +8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u +-----END CERTIFICATE----- + +# Issuer: CN=QuoVadis Root CA 3 O=QuoVadis Limited +# Subject: CN=QuoVadis Root CA 3 O=QuoVadis Limited +# Label: "QuoVadis Root CA 3" +# Serial: 1478 +# MD5 Fingerprint: 31:85:3c:62:94:97:63:b9:aa:fd:89:4e:af:6f:e0:cf +# SHA1 Fingerprint: 1f:49:14:f7:d8:74:95:1d:dd:ae:02:c0:be:fd:3a:2d:82:75:51:85 +# SHA256 Fingerprint: 18:f1:fc:7f:20:5d:f8:ad:dd:eb:7f:e0:07:dd:57:e3:af:37:5a:9c:4d:8d:73:54:6b:f4:f1:fe:d1:e1:8d:35 +-----BEGIN CERTIFICATE----- +MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x +GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv +b3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNV +BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W +YWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM +V0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNggDhoB +4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUr +H556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd +8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9Cabwv +vWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLT +mZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhe +btfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjc +T5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDt +WAEXMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZ +c6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A +4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYD +VR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMwgcUwgZMG +CCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0 +aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 +aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu +dC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2Nw +czALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4G +A1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJC +TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMg +Um9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM0 +7ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSem +d1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd ++LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B +4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadN +t54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6x +DYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57 +k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6s +zHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0j +Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT +mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK +4SVhM7JZG+Ju1zdXtg2pEto= +-----END CERTIFICATE----- + +# Issuer: O=SECOM Trust.net OU=Security Communication RootCA1 +# Subject: O=SECOM Trust.net OU=Security Communication RootCA1 +# Label: "Security Communication Root CA" +# Serial: 0 +# MD5 Fingerprint: f1:bc:63:6a:54:e0:b5:27:f5:cd:e7:1a:e3:4d:6e:4a +# SHA1 Fingerprint: 36:b1:2b:49:f9:81:9e:d7:4c:9e:bc:38:0f:c6:56:8f:5d:ac:b2:f7 +# SHA256 Fingerprint: e7:5e:72:ed:9f:56:0e:ec:6e:b4:80:00:73:a4:3f:c3:ad:19:19:5a:39:22:82:01:78:95:97:4a:99:02:6b:6c +-----BEGIN CERTIFICATE----- +MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEY +MBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21t +dW5pY2F0aW9uIFJvb3RDQTEwHhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5 +WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYD +VQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw8yl8 +9f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJ +DKaVv0uMDPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9 +Ms+k2Y7CI9eNqPPYJayX5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/N +QV3Is00qVUarH9oe4kA92819uZKAnDfdDJZkndwi92SL32HeFZRSFaB9UslLqCHJ +xrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2JChzAgMBAAGjPzA9MB0G +A1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYwDwYDVR0T +AQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vG +kl3g0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfr +Uj94nK9NrvjVT8+amCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5 +Bw+SUEmK3TGXX8npN6o7WWWXlDLJs58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJU +JRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ6rBK+1YWc26sTfcioU+tHXot +RSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAiFL39vmwLAw== +-----END CERTIFICATE----- + +# Issuer: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com +# Subject: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com +# Label: "XRamp Global CA Root" +# Serial: 107108908803651509692980124233745014957 +# MD5 Fingerprint: a1:0b:44:b3:ca:10:d8:00:6e:9d:0f:d8:0f:92:0a:d1 +# SHA1 Fingerprint: b8:01:86:d1:eb:9c:86:a5:41:04:cf:30:54:f3:4c:52:b7:e5:58:c6 +# SHA256 Fingerprint: ce:cd:dc:90:50:99:d8:da:df:c5:b1:d2:09:b7:37:cb:e2:c1:8c:fb:2c:10:c0:ff:0b:cf:0d:32:86:fc:1a:a2 +-----BEGIN CERTIFICATE----- +MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB +gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk +MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY +UmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcx +NDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3 +dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2Vy +dmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS6 +38eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP +KZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7Q +DxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4 +qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRa +JSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNVi +PvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0P +BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs +jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0 +eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQAD +ggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR +vbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt +qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa +IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy +i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ +O+7ETPTsJ3xCwnR8gooJybQDJbw= +-----END CERTIFICATE----- + +# Issuer: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority +# Subject: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority +# Label: "Go Daddy Class 2 CA" +# Serial: 0 +# MD5 Fingerprint: 91:de:06:25:ab:da:fd:32:17:0c:bb:25:17:2a:84:67 +# SHA1 Fingerprint: 27:96:ba:e6:3f:18:01:e2:77:26:1b:a0:d7:77:70:02:8f:20:ee:e4 +# SHA256 Fingerprint: c3:84:6b:f2:4b:9e:93:ca:64:27:4c:0e:c6:7c:1e:cc:5e:02:4f:fc:ac:d2:d7:40:19:35:0e:81:fe:54:6a:e4 +-----BEGIN CERTIFICATE----- +MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh +MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE +YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3 +MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo +ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg +MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN +ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA +PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w +wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi +EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY +avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+ +YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE +sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h +/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5 +IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD +ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy +OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P +TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ +HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER +dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf +ReYNnyicsbkqWletNw+vHX/bvZ8= +-----END CERTIFICATE----- + +# Issuer: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority +# Subject: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority +# Label: "Starfield Class 2 CA" +# Serial: 0 +# MD5 Fingerprint: 32:4a:4b:bb:c8:63:69:9b:be:74:9a:c6:dd:1d:46:24 +# SHA1 Fingerprint: ad:7e:1c:28:b0:64:ef:8f:60:03:40:20:14:c3:d0:e3:37:0e:b5:8a +# SHA256 Fingerprint: 14:65:fa:20:53:97:b8:76:fa:a6:f0:a9:95:8e:55:90:e4:0f:cc:7f:aa:4f:b7:c2:c8:67:75:21:fb:5f:b6:58 +-----BEGIN CERTIFICATE----- +MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl +MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp +U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw +NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE +ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp +ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3 +DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf +8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN ++lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0 +X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa +K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA +1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G +A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR +zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0 +YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD +bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w +DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3 +L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D +eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl +xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp +VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY +WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q= +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Assured ID Root CA" +# Serial: 17154717934120587862167794914071425081 +# MD5 Fingerprint: 87:ce:0b:7b:2a:0e:49:00:e1:58:71:9b:37:a8:93:72 +# SHA1 Fingerprint: 05:63:b8:63:0d:62:d7:5a:bb:c8:ab:1e:4b:df:b5:a8:99:b2:4d:43 +# SHA256 Fingerprint: 3e:90:99:b5:01:5e:8f:48:6c:00:bc:ea:9d:11:1e:e7:21:fa:ba:35:5a:89:bc:f1:df:69:56:1e:3d:c6:32:5c +-----BEGIN CERTIFICATE----- +MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c +JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP +mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+ +wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4 +VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/ +AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB +AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW +BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun +pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC +dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf +fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm +NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx +H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe ++o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Global Root CA" +# Serial: 10944719598952040374951832963794454346 +# MD5 Fingerprint: 79:e4:a9:84:0d:7d:3a:96:d7:c0:4f:e2:43:4c:89:2e +# SHA1 Fingerprint: a8:98:5d:3a:65:e5:e5:c4:b2:d7:d6:6d:40:c6:dd:2f:b1:9c:54:36 +# SHA256 Fingerprint: 43:48:a0:e9:44:4c:78:cb:26:5e:05:8d:5e:89:44:b4:d8:4f:96:62:bd:26:db:25:7f:89:34:a4:43:c7:01:61 +-----BEGIN CERTIFICATE----- +MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD +QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB +CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 +nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt +43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P +T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 +gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO +BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR +TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw +DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr +hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg +06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF +PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls +YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk +CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert High Assurance EV Root CA" +# Serial: 3553400076410547919724730734378100087 +# MD5 Fingerprint: d4:74:de:57:5c:39:b2:d3:9c:85:83:c5:c0:65:49:8a +# SHA1 Fingerprint: 5f:b7:ee:06:33:e2:59:db:ad:0c:4c:9a:e6:d3:8f:1a:61:c7:dc:25 +# SHA256 Fingerprint: 74:31:e5:f4:c3:c1:ce:46:90:77:4f:0b:61:e0:54:40:88:3b:a9:a0:1e:d0:0b:a6:ab:d7:80:6e:d3:b1:18:cf +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j +ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL +MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 +LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug +RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm ++9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW +PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM +xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB +Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 +hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg +EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA +FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec +nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z +eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF +hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 +Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe +vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep ++OkuE6N36B9K +-----END CERTIFICATE----- + +# Issuer: CN=DST Root CA X3 O=Digital Signature Trust Co. +# Subject: CN=DST Root CA X3 O=Digital Signature Trust Co. +# Label: "DST Root CA X3" +# Serial: 91299735575339953335919266965803778155 +# MD5 Fingerprint: 41:03:52:dc:0f:f7:50:1b:16:f0:02:8e:ba:6f:45:c5 +# SHA1 Fingerprint: da:c9:02:4f:54:d8:f6:df:94:93:5f:b1:73:26:38:ca:6a:d7:7c:13 +# SHA256 Fingerprint: 06:87:26:03:31:a7:24:03:d9:09:f1:05:e6:9b:cf:0d:32:e1:bd:24:93:ff:c6:d9:20:6d:11:bc:d6:77:07:39 +-----BEGIN CERTIFICATE----- +MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/ +MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT +DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow +PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD +Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O +rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq +OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b +xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw +7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD +aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV +HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG +SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69 +ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr +AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz +R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5 +JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo +Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ +-----END CERTIFICATE----- + +# Issuer: CN=SwissSign Gold CA - G2 O=SwissSign AG +# Subject: CN=SwissSign Gold CA - G2 O=SwissSign AG +# Label: "SwissSign Gold CA - G2" +# Serial: 13492815561806991280 +# MD5 Fingerprint: 24:77:d9:a8:91:d1:3b:fa:88:2d:c2:ff:f8:cd:33:93 +# SHA1 Fingerprint: d8:c5:38:8a:b7:30:1b:1b:6e:d4:7a:e6:45:25:3a:6f:9f:1a:27:61 +# SHA256 Fingerprint: 62:dd:0b:e9:b9:f5:0a:16:3e:a0:f8:e7:5c:05:3b:1e:ca:57:ea:55:c8:68:8f:64:7c:68:81:f2:c8:35:7b:95 +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +# Issuer: CN=SwissSign Silver CA - G2 O=SwissSign AG +# Subject: CN=SwissSign Silver CA - G2 O=SwissSign AG +# Label: "SwissSign Silver CA - G2" +# Serial: 5700383053117599563 +# MD5 Fingerprint: e0:06:a1:c9:7d:cf:c9:fc:0d:c0:56:75:96:d8:62:13 +# SHA1 Fingerprint: 9b:aa:e5:9f:56:ee:21:cb:43:5a:be:25:93:df:a7:f0:40:d1:1d:cb +# SHA256 Fingerprint: be:6c:4d:a2:bb:b9:ba:59:b6:f3:93:97:68:37:42:46:c3:c0:05:99:3f:a9:8f:02:0d:1d:ed:be:d4:8a:81:d5 +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +# Issuer: CN=SecureTrust CA O=SecureTrust Corporation +# Subject: CN=SecureTrust CA O=SecureTrust Corporation +# Label: "SecureTrust CA" +# Serial: 17199774589125277788362757014266862032 +# MD5 Fingerprint: dc:32:c3:a7:6d:25:57:c7:68:09:9d:ea:2d:a9:a2:d1 +# SHA1 Fingerprint: 87:82:c6:c3:04:35:3b:cf:d2:96:92:d2:59:3e:7d:44:d9:34:ff:11 +# SHA256 Fingerprint: f1:c1:b5:0a:e5:a2:0d:d8:03:0e:c9:f6:bc:24:82:3d:d3:67:b5:25:57:59:b4:e7:1b:61:fc:e9:f7:37:5d:73 +-----BEGIN CERTIFICATE----- +MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI +MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x +FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz +MTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENv +cnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCCASIwDQYJKoZIhvcN +AQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQXOZEz +Zum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO +0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIao +wW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj +7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS +8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjAT +BgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCeg +JYYjaHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGC +NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3 +6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/ +3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cprp6poxkm +D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS +CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR +3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= +-----END CERTIFICATE----- + +# Issuer: CN=Secure Global CA O=SecureTrust Corporation +# Subject: CN=Secure Global CA O=SecureTrust Corporation +# Label: "Secure Global CA" +# Serial: 9751836167731051554232119481456978597 +# MD5 Fingerprint: cf:f4:27:0d:d4:ed:dc:65:16:49:6d:3d:da:bf:6e:de +# SHA1 Fingerprint: 3a:44:73:5a:e5:81:90:1f:24:86:61:46:1e:3b:9c:c4:5f:f5:3a:1b +# SHA256 Fingerprint: 42:00:f5:04:3a:c8:59:0e:bb:52:7d:20:9e:d1:50:30:29:fb:cb:d4:1c:a1:b5:06:ec:27:f1:5a:de:7d:ac:69 +-----BEGIN CERTIFICATE----- +MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBK +MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x +GTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkx +MjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3Qg +Q29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jxYDiJ +iQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa +/FHtaMbQbqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJ +jnIFHovdRIWCQtBJwB1g8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnI +HmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYVHDGA76oYa8J719rO+TMg1fW9ajMtgQT7 +sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi0XPnj3pDAgMBAAGjgZ0w +gZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQF +MAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCsw +KaAnoCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsG +AQQBgjcVAQQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0L +URYD7xh8yOOvaliTFGCRsoTciE6+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXO +H0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cnCDpOGR86p1hcF895P4vkp9Mm +I50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/53CYNv6ZHdAbY +iNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc +f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW +-----END CERTIFICATE----- + +# Issuer: CN=COMODO Certification Authority O=COMODO CA Limited +# Subject: CN=COMODO Certification Authority O=COMODO CA Limited +# Label: "COMODO Certification Authority" +# Serial: 104350513648249232941998508985834464573 +# MD5 Fingerprint: 5c:48:dc:f7:42:72:ec:56:94:6d:1c:cc:71:35:80:75 +# SHA1 Fingerprint: 66:31:bf:9e:f7:4f:9e:b6:c9:d5:a6:0c:ba:6a:be:d1:f7:bd:ef:7b +# SHA256 Fingerprint: 0c:2c:d6:3d:f7:80:6f:a3:99:ed:e8:09:11:6b:57:5b:f8:79:89:f0:65:18:f9:80:8c:86:05:03:17:8b:af:66 +-----BEGIN CERTIFICATE----- +MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB +gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV +BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw +MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl +YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P +RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3 +UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI +2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8 +Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp ++2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+ +DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O +nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW +/zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g +PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u +QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY +SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv +IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ +RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4 +zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd +BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB +ZQ== +-----END CERTIFICATE----- + +# Issuer: CN=Network Solutions Certificate Authority O=Network Solutions L.L.C. +# Subject: CN=Network Solutions Certificate Authority O=Network Solutions L.L.C. +# Label: "Network Solutions Certificate Authority" +# Serial: 116697915152937497490437556386812487904 +# MD5 Fingerprint: d3:f3:a6:16:c0:fa:6b:1d:59:b1:2d:96:4d:0e:11:2e +# SHA1 Fingerprint: 74:f8:a3:c3:ef:e7:b3:90:06:4b:83:90:3c:21:64:60:20:e5:df:ce +# SHA256 Fingerprint: 15:f0:ba:00:a3:ac:7a:f3:ac:88:4c:07:2b:10:11:a0:77:bd:77:c0:97:f4:01:64:b2:f8:59:8a:bd:83:86:0c +-----BEGIN CERTIFICATE----- +MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBi +MQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu +MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3Jp +dHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMxMjM1OTU5WjBiMQswCQYDVQQGEwJV +UzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydO +ZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwz +c7MEL7xxjOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPP +OCwGJgl6cvf6UDL4wpPTaaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rl +mGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXTcrA/vGp97Eh/jcOrqnErU2lBUzS1sLnF +BgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc/Qzpf14Dl847ABSHJ3A4 +qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMBAAGjgZcw +gZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIB +BjAPBgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwu +bmV0c29sc3NsLmNvbS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3Jp +dHkuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc8 +6fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q4LqILPxFzBiwmZVRDuwduIj/ +h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/GGUsyfJj4akH +/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv +wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHN +pGxlaKFJdlxDydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey +-----END CERTIFICATE----- + +# Issuer: CN=COMODO ECC Certification Authority O=COMODO CA Limited +# Subject: CN=COMODO ECC Certification Authority O=COMODO CA Limited +# Label: "COMODO ECC Certification Authority" +# Serial: 41578283867086692638256921589707938090 +# MD5 Fingerprint: 7c:62:ff:74:9d:31:53:5e:68:4a:d5:78:aa:1e:bf:23 +# SHA1 Fingerprint: 9f:74:4e:9f:2b:4d:ba:ec:0f:31:2c:50:b6:56:3b:8e:2d:93:c3:11 +# SHA256 Fingerprint: 17:93:92:7a:06:14:54:97:89:ad:ce:2f:8f:34:f7:f0:b6:6d:0f:3a:e3:a3:b8:4d:21:ec:15:db:ba:4f:ad:c7 +-----BEGIN CERTIFICATE----- +MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL +MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE +BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT +IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw +MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy +ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N +T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv +biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR +FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J +cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW +BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm +fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv +GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= +-----END CERTIFICATE----- + +# Issuer: CN=Certigna O=Dhimyotis +# Subject: CN=Certigna O=Dhimyotis +# Label: "Certigna" +# Serial: 18364802974209362175 +# MD5 Fingerprint: ab:57:a6:5b:7d:42:82:19:b5:d8:58:26:28:5e:fd:ff +# SHA1 Fingerprint: b1:2e:13:63:45:86:a4:6f:1a:b2:60:68:37:58:2d:c4:ac:fd:94:97 +# SHA256 Fingerprint: e3:b6:a2:db:2e:d7:ce:48:84:2f:7a:c5:32:41:c7:b7:1d:54:14:4b:fb:40:c1:1f:3f:1d:0b:42:f5:ee:a1:2d +-----BEGIN CERTIFICATE----- +MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNV +BAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4X +DTA3MDYyOTE1MTMwNVoXDTI3MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQ +BgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwIQ2VydGlnbmEwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7qXOEm7RFHYeGifBZ4 +QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyHGxny +gQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbw +zBfsV1/pogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q +130yGLMLLGq/jj8UEYkgDncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2 +JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKfIrjxwo1p3Po6WAbfAgMBAAGjgbwwgbkw +DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQtCRZvgHyUtVF9lo53BEw +ZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJBgNVBAYT +AkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzj +AQ/JSP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG +9w0BAQUFAAOCAQEAhQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8h +bV6lUmPOEvjvKtpv6zf+EwLHyzs+ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFnc +fca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1kluPBS1xp81HlDQwY9qcEQCYsuu +HWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY1gkIl2PlwS6w +t0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw +WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== +-----END CERTIFICATE----- + +# Issuer: CN=Cybertrust Global Root O=Cybertrust, Inc +# Subject: CN=Cybertrust Global Root O=Cybertrust, Inc +# Label: "Cybertrust Global Root" +# Serial: 4835703278459682877484360 +# MD5 Fingerprint: 72:e4:4a:87:e3:69:40:80:77:ea:bc:e3:f4:ff:f0:e1 +# SHA1 Fingerprint: 5f:43:e5:b1:bf:f8:78:8c:ac:1c:c7:ca:4a:9a:c6:22:2b:cc:34:c6 +# SHA256 Fingerprint: 96:0a:df:00:63:e9:63:56:75:0c:29:65:dd:0a:08:67:da:0b:9c:bd:6e:77:71:4a:ea:fb:23:49:ab:39:3d:a3 +-----BEGIN CERTIFICATE----- +MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYG +A1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2Jh +bCBSb290MB4XDTA2MTIxNTA4MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UE +ChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBS +b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+Mi8vRRQZhP/8NN5 +7CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW0ozS +J8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2y +HLtgwEZLAfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iP +t3sMpTjr3kfb1V05/Iin89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNz +FtApD0mpSPCzqrdsxacwOUBdrsTiXSZT8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAY +XSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/ +MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2MDSgMqAw +hi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3Js +MB8GA1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUA +A4IBAQBW7wojoFROlZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMj +Wqd8BfP9IjsO0QbE2zZMcwSO5bAi5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUx +XOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2hO0j9n0Hq0V+09+zv+mKts2o +omcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+TX3EJIrduPuoc +A06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW +WL1WMRJOEcgh4LMRkWXbtKaIOM5V +-----END CERTIFICATE----- + +# Issuer: O=Chunghwa Telecom Co., Ltd. OU=ePKI Root Certification Authority +# Subject: O=Chunghwa Telecom Co., Ltd. OU=ePKI Root Certification Authority +# Label: "ePKI Root Certification Authority" +# Serial: 28956088682735189655030529057352760477 +# MD5 Fingerprint: 1b:2e:00:ca:26:06:90:3d:ad:fe:6f:15:68:d3:6b:b3 +# SHA1 Fingerprint: 67:65:0d:f1:7e:8e:7e:5b:82:40:a4:f4:56:4b:cf:e2:3d:69:c6:f0 +# SHA256 Fingerprint: c0:a6:f4:dc:63:a2:4b:fd:cf:54:ef:2a:6a:08:2a:0a:72:de:35:80:3e:2f:f5:ff:52:7a:e5:d8:72:06:df:d5 +-----BEGIN CERTIFICATE----- +MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBe +MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 +ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe +Fw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMxMjdaMF4xCzAJBgNVBAYTAlRXMSMw +IQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEqMCgGA1UECwwhZVBL +SSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAH +SyZbCUNsIZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAh +ijHyl3SJCRImHJ7K2RKilTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3X +DZoTM1PRYfl61dd4s5oz9wCGzh1NlDivqOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1 +TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX12ruOzjjK9SXDrkb5wdJ +fzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0OWQqraffA +sgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uU +WH1+ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLS +nT0IFaUQAS2zMnaolQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pH +dmX2Os+PYhcZewoozRrSgx4hxyy/vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJip +NiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXiZo1jDiVN1Rmy5nk3pyKdVDEC +AwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/QkqiMAwGA1UdEwQF +MAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH +ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGB +uvl2ICO1J2B01GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6Yl +PwZpVnPDimZI+ymBV3QGypzqKOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkP +JXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdVxrsStZf0X4OFunHB2WyBEXYKCrC/ +gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEPNXubrjlpC2JgQCA2 +j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+rGNm6 +5ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUB +o2M3IUxExJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS +/jQ6fbjpKdx2qcgw+BRxgMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2z +Gp1iro2C6pSe3VkQw63d4k3jMdXH7OjysP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTE +W9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+D +hNQ+IIX3Sj0rnP0qCglN6oH4EZw= +-----END CERTIFICATE----- + +# Issuer: O=certSIGN OU=certSIGN ROOT CA +# Subject: O=certSIGN OU=certSIGN ROOT CA +# Label: "certSIGN ROOT CA" +# Serial: 35210227249154 +# MD5 Fingerprint: 18:98:c0:d6:e9:3a:fc:f9:b0:f5:0c:f7:4b:01:44:17 +# SHA1 Fingerprint: fa:b7:ee:36:97:26:62:fb:2d:b0:2a:f6:bf:03:fd:e8:7c:4b:2f:9b +# SHA256 Fingerprint: ea:a9:62:c4:fa:4a:6b:af:eb:e4:15:19:6d:35:1c:cd:88:8d:4f:53:f3:fa:8a:e6:d7:c4:66:a9:4e:60:42:bb +-----BEGIN CERTIFICATE----- +MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYT +AlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBD +QTAeFw0wNjA3MDQxNzIwMDRaFw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJP +MREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTCC +ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7IJUqOtdu0KBuqV5Do +0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHHrfAQ +UySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5d +RdY4zTW2ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQ +OA7+j0xbm0bqQfWwCHTD0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwv +JoIQ4uNllAoEwF73XVv4EOLQunpL+943AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08C +AwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAcYwHQYDVR0O +BBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IBAQA+0hyJ +LjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecY +MnQ8SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ +44gx+FkagQnIl6Z0x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6I +Jd1hJyMctTEHBDa0GpC9oHRxUIltvBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNw +i/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7NzTogVZ96edhBiIL5VaZVDADlN +9u6wWk5JRFRYX0KD +-----END CERTIFICATE----- + +# Issuer: CN=NetLock Arany (Class Gold) F\u0151tan\xfas\xedtv\xe1ny O=NetLock Kft. OU=Tan\xfas\xedtv\xe1nykiad\xf3k (Certification Services) +# Subject: CN=NetLock Arany (Class Gold) F\u0151tan\xfas\xedtv\xe1ny O=NetLock Kft. OU=Tan\xfas\xedtv\xe1nykiad\xf3k (Certification Services) +# Label: "NetLock Arany (Class Gold) F\u0151tan\xfas\xedtv\xe1ny" +# Serial: 80544274841616 +# MD5 Fingerprint: c5:a1:b7:ff:73:dd:d6:d7:34:32:18:df:fc:3c:ad:88 +# SHA1 Fingerprint: 06:08:3f:59:3f:15:a1:04:a0:69:a4:6b:a9:03:d0:06:b7:97:09:91 +# SHA256 Fingerprint: 6c:61:da:c3:a2:de:f0:31:50:6b:e0:36:d2:a6:fe:40:19:94:fb:d1:3d:f9:c8:d4:66:59:92:74:c4:46:ec:98 +-----BEGIN CERTIFICATE----- +MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG +EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 +MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl +cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR +dGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgxMjA2MTUwODIxWjCB +pzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxOZXRM +b2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlm +aWNhdGlvbiBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNz +IEdvbGQpIEbFkXRhbsO6c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEAxCRec75LbRTDofTjl5Bu0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrT +lF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw/HpYzY6b7cNGbIRwXdrz +AZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAkH3B5r9s5 +VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRG +ILdwfzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2 +BJtr+UBdADTHLpl1neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAG +AQH/AgEEMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2M +U9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwWqZw8UQCgwBEIBaeZ5m8BiFRh +bvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTtaYtOUZcTh5m2C ++C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC +bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2F +uLjbvrW5KfnaNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2 +XjG4Kvte9nHfRCaexOYNkbQudZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= +-----END CERTIFICATE----- + +# Issuer: CN=Hongkong Post Root CA 1 O=Hongkong Post +# Subject: CN=Hongkong Post Root CA 1 O=Hongkong Post +# Label: "Hongkong Post Root CA 1" +# Serial: 1000 +# MD5 Fingerprint: a8:0d:6f:39:78:b9:43:6d:77:42:6d:98:5a:cc:23:ca +# SHA1 Fingerprint: d6:da:a8:20:8d:09:d2:15:4d:24:b5:2f:cb:34:6e:b2:58:b2:8a:58 +# SHA256 Fingerprint: f9:e6:7d:33:6c:51:00:2a:c0:54:c6:32:02:2d:66:dd:a2:e7:e3:ff:f1:0a:d0:61:ed:31:d8:bb:b4:10:cf:b2 +-----BEGIN CERTIFICATE----- +MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsx +FjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3Qg +Um9vdCBDQSAxMB4XDTAzMDUxNTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkG +A1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdr +b25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1ApzQ +jVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEn +PzlTCeqrauh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjh +ZY4bXSNmO7ilMlHIhqqhqZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9 +nnV0ttgCXjqQesBCNnLsak3c78QA3xMYV18meMjWCnl3v/evt3a5pQuEF10Q6m/h +q5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNVHRMBAf8ECDAGAQH/AgED +MA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7ih9legYsC +mEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI3 +7piol7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clB +oiMBdDhViw+5LmeiIAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJs +EhTkYY2sEJCehFC78JZvRZ+K88psT/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpO +fMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilTc4afU9hDDl3WY4JxHYB0yvbi +AmvZWg== +-----END CERTIFICATE----- + +# Issuer: CN=SecureSign RootCA11 O=Japan Certification Services, Inc. +# Subject: CN=SecureSign RootCA11 O=Japan Certification Services, Inc. +# Label: "SecureSign RootCA11" +# Serial: 1 +# MD5 Fingerprint: b7:52:74:e2:92:b4:80:93:f2:75:e4:cc:d7:f2:ea:26 +# SHA1 Fingerprint: 3b:c4:9f:48:f8:f3:73:a0:9c:1e:bd:f8:5b:b1:c3:65:c7:d8:11:b3 +# SHA256 Fingerprint: bf:0f:ee:fb:9e:3a:58:1a:d5:f9:e9:db:75:89:98:57:43:d2:61:08:5c:4d:31:4f:6f:5d:72:59:aa:42:16:12 +-----BEGIN CERTIFICATE----- +MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDEr +MCkGA1UEChMiSmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoG +A1UEAxMTU2VjdXJlU2lnbiBSb290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0 +MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSswKQYDVQQKEyJKYXBhbiBDZXJ0aWZp +Y2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1cmVTaWduIFJvb3RD +QTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvLTJsz +i1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8 +h9uuywGOwvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOV +MdrAG/LuYpmGYz+/3ZMqg6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9 +UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rPO7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni +8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitAbpSACW22s293bzUIUPsC +h8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZXt94wDgYD +VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB +AKChOBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xm +KbabfSVSSUOrTC4rbnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQ +X5Ucv+2rIrVls4W6ng+4reV6G4pQOh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWr +QbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01y8hSyn+B/tlr0/cR7SXf+Of5 +pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061lgeLKBObjBmN +QSdJQO7e5iNEOdyhIta6A/I= +-----END CERTIFICATE----- + +# Issuer: CN=Microsec e-Szigno Root CA 2009 O=Microsec Ltd. +# Subject: CN=Microsec e-Szigno Root CA 2009 O=Microsec Ltd. +# Label: "Microsec e-Szigno Root CA 2009" +# Serial: 14014712776195784473 +# MD5 Fingerprint: f8:49:f4:03:bc:44:2d:83:be:48:69:7d:29:64:fc:b1 +# SHA1 Fingerprint: 89:df:74:fe:5c:f4:0f:4a:80:f9:e3:37:7d:54:da:91:e1:01:31:8e +# SHA256 Fingerprint: 3c:5f:81:fe:a5:fa:b8:2c:64:bf:a2:ea:ec:af:cd:e8:e0:77:fc:86:20:a7:ca:e5:37:16:3d:f3:6e:db:f3:78 +-----BEGIN CERTIFICATE----- +MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD +VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 +ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0G +CSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTAeFw0wOTA2MTYxMTMwMThaFw0y +OTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3Qx +FjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3pp +Z25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o +dTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvP +kd6mJviZpWNwrZuuyjNAfW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tc +cbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG0IMZfcChEhyVbUr02MelTTMuhTlAdX4U +fIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKApxn1ntxVUwOXewdI/5n7 +N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm1HxdrtbC +xkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1 ++rUCAwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPM +Pcu1SCOhGnqmKrs0aDAbBgNVHREEFDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqG +SIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0olZMEyL/azXm4Q5DwpL7v8u8h +mLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfXI/OMn74dseGk +ddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 +tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c +2Pm2G2JwCz02yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5t +HMN1Rq41Bab2XD0h7lbwyYIiLXpUq3DDfSJlgnCW +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3 +# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3 +# Label: "GlobalSign Root CA - R3" +# Serial: 4835703278459759426209954 +# MD5 Fingerprint: c5:df:b8:49:ca:05:13:55:ee:2d:ba:1a:c3:3e:b0:28 +# SHA1 Fingerprint: d6:9b:56:11:48:f0:1c:77:c5:45:78:c1:09:26:df:5b:85:69:76:ad +# SHA256 Fingerprint: cb:b5:22:d7:b7:f1:27:ad:6a:01:13:86:5b:df:1c:d4:10:2e:7d:07:59:af:63:5a:7c:f4:72:0d:c9:63:c5:3b +-----BEGIN CERTIFICATE----- +MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G +A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp +Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 +MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG +A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 +RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT +gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm +KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd +QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ +XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw +DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o +LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU +RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp +jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK +6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX +mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs +Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH +WD9f +-----END CERTIFICATE----- + +# Issuer: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068 +# Subject: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068 +# Label: "Autoridad de Certificacion Firmaprofesional CIF A62634068" +# Serial: 6047274297262753887 +# MD5 Fingerprint: 73:3a:74:7a:ec:bb:a3:96:a6:c2:e4:e2:c8:9b:c0:c3 +# SHA1 Fingerprint: ae:c5:fb:3f:c8:e1:bf:c4:e5:4f:03:07:5a:9a:e8:00:b7:f7:b6:fa +# SHA256 Fingerprint: 04:04:80:28:bf:1f:28:64:d4:8f:9a:d4:d8:32:94:36:6a:82:88:56:55:3f:3b:14:30:3f:90:14:7f:5d:40:ef +-----BEGIN CERTIFICATE----- +MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UE +BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h +cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEy +MzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg +Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9 +thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM +cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG +L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i +NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h +X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b +m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy +Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja +EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T +KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF +6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh +OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYD +VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNHDhpkLzCBpgYD +VR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp +cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBv +ACAAZABlACAAbABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBl +AGwAbwBuAGEAIAAwADgAMAAxADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF +661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx51tkljYyGOylMnfX40S2wBEqgLk9 +am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qkR71kMrv2JYSiJ0L1 +ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaPT481 +PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS +3a/DTg4fJl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5k +SeTy36LssUzAKh3ntLFlosS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF +3dvd6qJ2gHN99ZwExEWN57kci57q13XRcrHedUTnQn3iV2t93Jm8PYMo6oCTjcVM +ZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoRsaS8I8nkvof/uZS2+F0g +StRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTDKCOM/icz +Q0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQB +jLMi6Et8Vcad+qMUu2WFbm5PEn4KPJ2V +-----END CERTIFICATE----- + +# Issuer: CN=Izenpe.com O=IZENPE S.A. +# Subject: CN=Izenpe.com O=IZENPE S.A. +# Label: "Izenpe.com" +# Serial: 917563065490389241595536686991402621 +# MD5 Fingerprint: a6:b0:cd:85:80:da:5c:50:34:a3:39:90:2f:55:67:73 +# SHA1 Fingerprint: 2f:78:3d:25:52:18:a7:4a:65:39:71:b5:2c:a2:9c:45:15:6f:e9:19 +# SHA256 Fingerprint: 25:30:cc:8e:98:32:15:02:ba:d9:6f:9b:1f:ba:1b:09:9e:2d:29:9e:0f:45:48:bb:91:4f:36:3b:c0:d4:53:1f +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +# Issuer: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc. +# Subject: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc. +# Label: "Go Daddy Root Certificate Authority - G2" +# Serial: 0 +# MD5 Fingerprint: 80:3a:bc:22:c1:e6:fb:8d:9b:3b:27:4a:32:1b:9a:01 +# SHA1 Fingerprint: 47:be:ab:c9:22:ea:e8:0e:78:78:34:62:a7:9f:45:c2:54:fd:e6:8b +# SHA256 Fingerprint: 45:14:0b:32:47:eb:9c:c8:c5:b4:f0:d7:b5:30:91:f7:32:92:08:9e:6e:5a:63:e2:74:9d:d3:ac:a9:19:8e:da +-----BEGIN CERTIFICATE----- +MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT +EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp +ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz +NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH +EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE +AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD +E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH +/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy +DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh +GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR +tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA +AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX +WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu +9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr +gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo +2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO +LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI +4uJEvlz36hz1 +-----END CERTIFICATE----- + +# Issuer: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc. +# Subject: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc. +# Label: "Starfield Root Certificate Authority - G2" +# Serial: 0 +# MD5 Fingerprint: d6:39:81:c6:52:7e:96:69:fc:fc:ca:66:ed:05:f2:96 +# SHA1 Fingerprint: b5:1c:06:7c:ee:2b:0c:3d:f8:55:ab:2d:92:f4:fe:39:d4:e7:0f:0e +# SHA256 Fingerprint: 2c:e1:cb:0b:f9:d2:f9:e1:02:99:3f:be:21:51:52:c3:b2:dd:0c:ab:de:1c:68:e5:31:9b:83:91:54:db:b7:f5 +-----BEGIN CERTIFICATE----- +MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT +HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs +ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw +MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 +b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj +aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp +Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg +nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1 +HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N +Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN +dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0 +HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO +BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G +CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU +sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3 +4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg +8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K +pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1 +mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 +-----END CERTIFICATE----- + +# Issuer: CN=Starfield Services Root Certificate Authority - G2 O=Starfield Technologies, Inc. +# Subject: CN=Starfield Services Root Certificate Authority - G2 O=Starfield Technologies, Inc. +# Label: "Starfield Services Root Certificate Authority - G2" +# Serial: 0 +# MD5 Fingerprint: 17:35:74:af:7b:61:1c:eb:f4:f9:3c:e2:ee:40:f9:a2 +# SHA1 Fingerprint: 92:5a:8f:8d:2c:6d:04:e0:66:5f:59:6a:ff:22:d8:63:e8:25:6f:3f +# SHA256 Fingerprint: 56:8d:69:05:a2:c8:87:08:a4:b3:02:51:90:ed:cf:ed:b1:97:4a:60:6a:13:c6:e5:29:0f:cb:2a:e6:3e:da:b5 +-----BEGIN CERTIFICATE----- +MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx +EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT +HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs +ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 +MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD +VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy +ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy +dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p +OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2 +8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K +Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe +hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk +6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw +DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q +AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI +bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB +ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z +qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd +iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn +0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN +sSi6 +-----END CERTIFICATE----- + +# Issuer: CN=AffirmTrust Commercial O=AffirmTrust +# Subject: CN=AffirmTrust Commercial O=AffirmTrust +# Label: "AffirmTrust Commercial" +# Serial: 8608355977964138876 +# MD5 Fingerprint: 82:92:ba:5b:ef:cd:8a:6f:a6:3d:55:f9:84:f6:d6:b7 +# SHA1 Fingerprint: f9:b5:b6:32:45:5f:9c:be:ec:57:5f:80:dc:e9:6e:2c:c7:b2:78:b7 +# SHA256 Fingerprint: 03:76:ab:1d:54:c5:f9:80:3c:e4:b2:e2:01:a0:ee:7e:ef:7b:57:b6:36:e8:a9:3c:9b:8d:48:60:c9:6f:5f:a7 +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz +dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL +MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp +cm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6EqdbDuKP +Hx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yr +ba0F8PrVC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPAL +MeIrJmqbTFeurCA+ukV6BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1 +yHp52UKqK39c/s4mT6NmgTWvRLpUHhwwMmWd5jyTXlBOeuM61G7MGvv50jeuJCqr +VwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNVHQ4EFgQUnZPGU4teyq8/ +nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ +KoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYG +XUPGhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNj +vbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivt +Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g +N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC +nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= +-----END CERTIFICATE----- + +# Issuer: CN=AffirmTrust Networking O=AffirmTrust +# Subject: CN=AffirmTrust Networking O=AffirmTrust +# Label: "AffirmTrust Networking" +# Serial: 8957382827206547757 +# MD5 Fingerprint: 42:65:ca:be:01:9a:9a:4c:a9:8c:41:49:cd:c0:d5:7f +# SHA1 Fingerprint: 29:36:21:02:8b:20:ed:02:f5:66:c5:32:d1:d6:ed:90:9f:45:00:2f +# SHA256 Fingerprint: 0a:81:ec:5a:92:97:77:f1:45:90:4a:f3:8d:5d:50:9f:66:b5:e2:c5:8f:cd:b5:31:05:8b:0e:17:f3:f0:b4:1b +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz +dCBOZXR3b3JraW5nMB4XDTEwMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDEL +MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp +cm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SEHi3y +YJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbua +kCNrmreIdIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRL +QESxG9fhwoXA3hA/Pe24/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp +6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gbh+0t+nvujArjqWaJGctB+d1ENmHP4ndG +yH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNVHQ4EFgQUBx/S55zawm6i +QLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ +KoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfO +tDIuUFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzu +QY0x2+c06lkh1QF612S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZ +Lgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u +olu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48 +x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= +-----END CERTIFICATE----- + +# Issuer: CN=AffirmTrust Premium O=AffirmTrust +# Subject: CN=AffirmTrust Premium O=AffirmTrust +# Label: "AffirmTrust Premium" +# Serial: 7893706540734352110 +# MD5 Fingerprint: c4:5d:0e:48:b6:ac:28:30:4e:0a:bc:f9:38:16:87:57 +# SHA1 Fingerprint: d8:a6:33:2c:e0:03:6f:b1:85:f6:63:4f:7d:6a:06:65:26:32:28:27 +# SHA256 Fingerprint: 70:a7:3f:7f:37:6b:60:07:42:48:90:45:34:b1:14:82:d5:bf:0e:69:8e:cc:49:8d:f5:25:77:eb:f2:e9:3b:9a +-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz +dCBQcmVtaXVtMB4XDTEwMDEyOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkG +A1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1U +cnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxBLf +qV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtnBKAQ +JG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ ++jjeRFcV5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrS +s8PhaJyJ+HoAVt70VZVs+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5 +HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmdGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d7 +70O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5Rp9EixAqnOEhss/n/fauG +V+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NIS+LI+H+S +qHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S +5u046uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4Ia +C1nEWTJ3s7xgaVY5/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TX +OwF0lkLgAOIua+rF7nKsu7/+6qqo+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYE +FJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ +BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByvMiPIs0laUZx2 +KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg +Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B +8OWycvpEgjNC6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQ +MKSOyARiqcTtNd56l+0OOF6SL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc +0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK+4w1IX2COPKpVJEZNZOUbWo6xbLQ +u4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmVBtWVyuEklut89pMF +u+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFgIxpH +YoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8 +GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO +RtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e +KeC2uAloGRwYQw== +-----END CERTIFICATE----- + +# Issuer: CN=AffirmTrust Premium ECC O=AffirmTrust +# Subject: CN=AffirmTrust Premium ECC O=AffirmTrust +# Label: "AffirmTrust Premium ECC" +# Serial: 8401224907861490260 +# MD5 Fingerprint: 64:b0:09:55:cf:b1:d5:99:e2:be:13:ab:a6:5d:ea:4d +# SHA1 Fingerprint: b8:23:6b:00:2f:1d:16:86:53:01:55:6c:11:a4:37:ca:eb:ff:c3:bb +# SHA256 Fingerprint: bd:71:fd:f6:da:97:e4:cf:62:d1:64:7a:dd:25:81:b0:7d:79:ad:f8:39:7e:b4:ec:ba:9c:5e:84:88:82:14:23 +-----BEGIN CERTIFICATE----- +MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC +VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ +cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ +BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt +VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D +0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9 +ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G +A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs +aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I +flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ== +-----END CERTIFICATE----- + +# Issuer: CN=Certum Trusted Network CA O=Unizeto Technologies S.A. OU=Certum Certification Authority +# Subject: CN=Certum Trusted Network CA O=Unizeto Technologies S.A. OU=Certum Certification Authority +# Label: "Certum Trusted Network CA" +# Serial: 279744 +# MD5 Fingerprint: d5:e9:81:40:c5:18:69:fc:46:2c:89:75:62:0f:aa:78 +# SHA1 Fingerprint: 07:e0:32:e0:20:b7:2c:3f:19:2f:06:28:a2:59:3a:19:a7:0f:06:9e +# SHA256 Fingerprint: 5c:58:46:8d:55:f5:8e:49:7e:74:39:82:d2:b5:00:10:b6:d1:65:37:4a:cf:83:a7:d4:a3:2d:b7:68:c4:40:8e +-----BEGIN CERTIFICATE----- +MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM +MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D +ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU +cnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIyMTIwNzM3WhcNMjkxMjMxMTIwNzM3 +WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMg +Uy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIw +IAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rH +UV+rpDKmYYe2bg+G0jACl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LM +TXPb865Px1bVWqeWifrzq2jUI4ZZJ88JJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVU +BBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4fOQtf/WsX+sWn7Et0brM +kUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0cvW0QM8x +AcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNV +HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15y +sHhE49wcrwn9I0j6vSrEuVUEtRCjjSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfL +I9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv94nYmem8 +J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY +VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI +03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= +-----END CERTIFICATE----- + +# Issuer: CN=TWCA Root Certification Authority O=TAIWAN-CA OU=Root CA +# Subject: CN=TWCA Root Certification Authority O=TAIWAN-CA OU=Root CA +# Label: "TWCA Root Certification Authority" +# Serial: 1 +# MD5 Fingerprint: aa:08:8f:f6:f9:7b:b7:f2:b1:a7:1e:9b:ea:ea:bd:79 +# SHA1 Fingerprint: cf:9e:87:6d:d3:eb:fc:42:26:97:a3:b5:a3:7a:a0:76:a9:06:23:48 +# SHA256 Fingerprint: bf:d8:8f:e1:10:1c:41:ae:3e:80:1b:f8:be:56:35:0e:e9:ba:d1:a6:b9:bd:51:5e:dc:5c:6d:5b:87:11:ac:44 +-----BEGIN CERTIFICATE----- +MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzES +MBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFU +V0NBIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMz +WhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJVEFJV0FO +LUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlm +aWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB +AQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFE +AcK0HMMxQhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HH +K3XLfJ+utdGdIzdjp9xCoi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeX +RfwZVzsrb+RH9JlF/h3x+JejiB03HFyP4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/z +rX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1ry+UPizgN7gr8/g+YnzAx +3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkq +hkiG9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeC +MErJk/9q56YAf4lCmtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdls +XebQ79NqZp4VKIV66IIArB6nCWlWQtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62D +lhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVYT0bf+215WfKEIlKuD8z7fDvn +aspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocnyYh0igzyXxfkZ +YiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== +-----END CERTIFICATE----- + +# Issuer: O=SECOM Trust Systems CO.,LTD. OU=Security Communication RootCA2 +# Subject: O=SECOM Trust Systems CO.,LTD. OU=Security Communication RootCA2 +# Label: "Security Communication RootCA2" +# Serial: 0 +# MD5 Fingerprint: 6c:39:7d:a4:0e:55:59:b2:3f:d6:41:b1:12:50:de:43 +# SHA1 Fingerprint: 5f:3b:8c:f2:f8:10:b3:7d:78:b4:ce:ec:19:19:c3:73:34:b9:c7:74 +# SHA256 Fingerprint: 51:3b:2c:ec:b8:10:d4:cd:e5:dd:85:39:1a:df:c6:c2:dd:60:d8:7b:b7:36:d2:b5:21:48:4a:a4:7a:0e:be:f6 +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDEl +MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMe +U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoX +DTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRy +dXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3VyaXR5IENvbW11bmlj +YXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANAV +OVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGr +zbl+dp+++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVM +VAX3NuRFg3sUZdbcDE3R3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQ +hNBqyjoGADdH5H5XTz+L62e4iKrFvlNVspHEfbmwhRkGeC7bYRr6hfVKkaHnFtWO +ojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1KEOtOghY6rCcMU/Gt1SSw +awNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8QIH4D5cs +OPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 +DQEBCwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpF +coJxDjrSzG+ntKEju/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXc +okgfGT+Ok+vx+hfuzU7jBBJV1uXk3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8 +t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6qtnRGEmyR7jTV7JqR50S+kDFy +1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29mvVXIwAHIRc/ +SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 +-----END CERTIFICATE----- + +# Issuer: CN=EC-ACC O=Agencia Catalana de Certificacio (NIF Q-0801176-I) OU=Serveis Publics de Certificacio/Vegeu https://www.catcert.net/verarrel (c)03/Jerarquia Entitats de Certificacio Catalanes +# Subject: CN=EC-ACC O=Agencia Catalana de Certificacio (NIF Q-0801176-I) OU=Serveis Publics de Certificacio/Vegeu https://www.catcert.net/verarrel (c)03/Jerarquia Entitats de Certificacio Catalanes +# Label: "EC-ACC" +# Serial: -23701579247955709139626555126524820479 +# MD5 Fingerprint: eb:f5:9d:29:0d:61:f9:42:1f:7c:c2:ba:6d:e3:15:09 +# SHA1 Fingerprint: 28:90:3a:63:5b:52:80:fa:e6:77:4c:0b:6d:a7:d6:ba:a6:4a:f2:e8 +# SHA256 Fingerprint: 88:49:7f:01:60:2f:31:54:24:6a:e2:8c:4d:5a:ef:10:f1:d8:7e:bb:76:62:6f:4a:e0:b7:f9:5b:a7:96:87:99 +-----BEGIN CERTIFICATE----- +MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB +8zELMAkGA1UEBhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2Vy +dGlmaWNhY2lvIChOSUYgUS0wODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1 +YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYDVQQLEyxWZWdldSBodHRwczovL3d3 +dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UECxMsSmVyYXJxdWlh +IEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMTBkVD +LUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQG +EwJFUzE7MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8g +KE5JRiBRLTA4MDExNzYtSSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBD +ZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZlZ2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQu +bmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJhcnF1aWEgRW50aXRhdHMg +ZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUNDMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R +85iKw5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm +4CgPukLjbo73FCeTae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaV +HMf5NLWUhdWZXqBIoH7nF2W4onW4HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNd +QlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0aE9jD2z3Il3rucO2n5nzbcc8t +lGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw0JDnJwIDAQAB +o4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E +BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4 +opvpXY0wfwYDVR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBo +dHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidW +ZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAwDQYJKoZIhvcN +AQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJlF7W2u++AVtd0x7Y +/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNaAl6k +SBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhy +Rp/7SNVel+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOS +Agu+TGbrIP65y7WZf+a2E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xl +nJ2lYJU6Un/10asIbvPuW/mIPX64b24D5EI= +-----END CERTIFICATE----- + +# Issuer: CN=Hellenic Academic and Research Institutions RootCA 2011 O=Hellenic Academic and Research Institutions Cert. Authority +# Subject: CN=Hellenic Academic and Research Institutions RootCA 2011 O=Hellenic Academic and Research Institutions Cert. Authority +# Label: "Hellenic Academic and Research Institutions RootCA 2011" +# Serial: 0 +# MD5 Fingerprint: 73:9f:4c:4b:73:5b:79:e9:fa:ba:1c:ef:6e:cb:d5:c9 +# SHA1 Fingerprint: fe:45:65:9b:79:03:5b:98:a1:61:b5:51:2e:ac:da:58:09:48:22:4d +# SHA256 Fingerprint: bc:10:4f:15:a4:8b:e7:09:dc:a5:42:a7:e1:d4:b9:df:6f:05:45:27:e8:02:ea:a9:2d:59:54:44:25:8a:fe:71 +-----BEGIN CERTIFICATE----- +MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1Ix +RDBCBgNVBAoTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1 +dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1p +YyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIFJvb3RDQSAyMDExMB4XDTExMTIw +NjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYTAkdSMUQwQgYDVQQK +EztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIENl +cnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl +c2VhcmNoIEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPz +dYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJ +fel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa71HFK9+WXesyHgLacEns +bgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u8yBRQlqD +75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSP +FEDH3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNV +HRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp +5dgTBCPuQSUwRwYDVR0eBEAwPqA8MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQu +b3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQub3JnMA0GCSqGSIb3DQEBBQUA +A4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVtXdMiKahsog2p +6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8 +TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7 +dIsXRSZMFpGD/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8Acys +Nnq/onN694/BtZqhFLKPM58N7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXI +l7WdmplNsDz4SgCbZN2fOUvRJ9e4 +-----END CERTIFICATE----- + +# Issuer: CN=Actalis Authentication Root CA O=Actalis S.p.A./03358520967 +# Subject: CN=Actalis Authentication Root CA O=Actalis S.p.A./03358520967 +# Label: "Actalis Authentication Root CA" +# Serial: 6271844772424770508 +# MD5 Fingerprint: 69:c1:0d:4f:07:a3:1b:c3:fe:56:3d:04:bc:11:f6:a6 +# SHA1 Fingerprint: f3:73:b3:87:06:5a:28:84:8a:f2:f3:4a:ce:19:2b:dd:c7:8e:9c:ac +# SHA256 Fingerprint: 55:92:60:84:ec:96:3a:64:b9:6e:2a:be:01:ce:0b:a8:6a:64:fb:fe:bc:c7:aa:b5:af:c1:55:b3:7f:d7:60:66 +-----BEGIN CERTIFICATE----- +MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UE +BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w +MzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 +IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDkyMjExMjIwMlowazELMAkGA1UEBhMC +SVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1 +ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENB +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNv +UTufClrJwkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX +4ay8IMKx4INRimlNAJZaby/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9 +KK3giq0itFZljoZUj5NDKd45RnijMCO6zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/ +gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1fYVEiVRvjRuPjPdA1Yprb +rxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2oxgkg4YQ +51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2F +be8lEfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxe +KF+w6D9Fz8+vm2/7hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4F +v6MGn8i1zeQf1xcGDXqVdFUNaBr8EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbn +fpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5jF66CyCU3nuDuP/jVo23Eek7 +jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLYiDrIn3hm7Ynz +ezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt +ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAL +e3KHwGCmSUyIWOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70 +jsNjLiNmsGe+b7bAEzlgqqI0JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDz +WochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKxK3JCaKygvU5a2hi/a5iB0P2avl4V +SM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+Xlff1ANATIGk0k9j +pwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC4yyX +X04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+Ok +fcvHlXHo2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7R +K4X9p2jIugErsWx0Hbhzlefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btU +ZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXemOR/qnuOf0GZvBeyqdn6/axag67XH/JJU +LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT +LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== +-----END CERTIFICATE----- + +# Issuer: CN=Buypass Class 2 Root CA O=Buypass AS-983163327 +# Subject: CN=Buypass Class 2 Root CA O=Buypass AS-983163327 +# Label: "Buypass Class 2 Root CA" +# Serial: 2 +# MD5 Fingerprint: 46:a7:d2:fe:45:fb:64:5a:a8:59:90:9b:78:44:9b:29 +# SHA1 Fingerprint: 49:0a:75:74:de:87:0a:47:fe:58:ee:f6:c7:6b:eb:c6:0b:12:40:99 +# SHA256 Fingerprint: 9a:11:40:25:19:7c:5b:b9:5d:94:e6:3d:55:cd:43:79:08:47:b6:46:b2:3c:df:11:ad:a4:a0:0e:ff:15:fb:48 +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd +MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg +Q2xhc3MgMiBSb290IENBMB4XDTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1ow +TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw +HgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB +BQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1g1Lr +6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPV +L4O2fuPn9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC91 +1K2GScuVr1QGbNgGE41b/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHx +MlAQTn/0hpPshNOOvEu/XAFOBz3cFIqUCqTqc/sLUegTBxj6DvEr0VQVfTzh97QZ +QmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeffawrbD02TTqigzXsu8lkB +arcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgIzRFo1clr +Us3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLi +FRhnBkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRS +P/TizPJhk9H9Z2vXUq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN +9SG9dKpN6nIDSdvHXx1iY8f93ZHsM+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxP +AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMmAd+BikoL1Rpzz +uvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAU18h +9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s +A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3t +OluwlN5E40EIosHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo ++fsicdl9sz1Gv7SEr5AcD48Saq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7 +KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYdDnkM/crqJIByw5c/8nerQyIKx+u2 +DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWDLfJ6v9r9jv6ly0Us +H8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0oyLQ +I+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK7 +5t98biGCwWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h +3PFaTWwyI0PurKju7koSCTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPz +Y11aWOIv4x3kqdbQCtCev9eBCfHJxyYNrJgWVqA= +-----END CERTIFICATE----- + +# Issuer: CN=Buypass Class 3 Root CA O=Buypass AS-983163327 +# Subject: CN=Buypass Class 3 Root CA O=Buypass AS-983163327 +# Label: "Buypass Class 3 Root CA" +# Serial: 2 +# MD5 Fingerprint: 3d:3b:18:9e:2c:64:5a:e8:d5:88:ce:0e:f9:37:c2:ec +# SHA1 Fingerprint: da:fa:f7:fa:66:84:ec:06:8f:14:50:bd:c7:c2:81:a5:bc:a9:64:57 +# SHA256 Fingerprint: ed:f7:eb:bc:a2:7a:2a:38:4d:38:7b:7d:40:10:c6:66:e2:ed:b4:84:3e:4c:29:b4:ae:1d:5b:93:32:e6:b2:4d +-----BEGIN CERTIFICATE----- +MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd +MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg +Q2xhc3MgMyBSb290IENBMB4XDTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFow +TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw +HgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB +BQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRHsJ8Y +ZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3E +N3coTRiR5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9 +tznDDgFHmV0ST9tD+leh7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX +0DJq1l1sDPGzbjniazEuOQAnFN44wOwZZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c +/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH2xc519woe2v1n/MuwU8X +KhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV/afmiSTY +zIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvS +O1UQRwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D +34xFMFbG02SrZvPAXpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgP +K9Dx2hzLabjKSWJtyNBjYt1gD1iqj6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3 +AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFEe4zf/lb+74suwv +Tg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAACAj +QTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV +cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXS +IGrs/CIBKM+GuIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2 +HJLw5QY33KbmkJs4j1xrG0aGQ0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsa +O5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8ZORK15FTAaggiG6cX0S5y2CBNOxv +033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2KSb12tjE8nVhz36u +dmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz6MkE +kbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg41 +3OEMXbugUZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvD +u79leNKGef9JOxqDDPDeeOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq +4/g7u9xN12TyUb7mqqta6THuBrxzvxNiCp/HuZc= +-----END CERTIFICATE----- + +# Issuer: CN=T-TeleSec GlobalRoot Class 3 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center +# Subject: CN=T-TeleSec GlobalRoot Class 3 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center +# Label: "T-TeleSec GlobalRoot Class 3" +# Serial: 1 +# MD5 Fingerprint: ca:fb:40:a8:4e:39:92:8a:1d:fe:8e:2f:c4:27:ea:ef +# SHA1 Fingerprint: 55:a6:72:3e:cb:f2:ec:cd:c3:23:74:70:19:9d:2a:be:11:e3:81:d1 +# SHA256 Fingerprint: fd:73:da:d3:1c:64:4f:f1:b4:3b:ef:0c:cd:da:96:71:0b:9c:d9:87:5e:ca:7e:31:70:7a:f3:e9:6d:52:2b:bd +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx +KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd +BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl +YyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgxMDAxMTAyOTU2WhcNMzMxMDAxMjM1 +OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy +aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 +ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN +8ELg63iIVl6bmlQdTQyK9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/ +RLyTPWGrTs0NvvAgJ1gORH8EGoel15YUNpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4 +hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZFiP0Zf3WHHx+xGwpzJFu5 +ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W0eDrXltM +EnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGj +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1 +A/d2O2GCahKqGFPrAyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOy +WL6ukK2YJ5f+AbGwUgC4TeQbIXQbfsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ +1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzTucpH9sry9uetuUg/vBa3wW30 +6gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7hP0HHRwA11fXT +91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml +e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4p +TpPDpFQUWw== +-----END CERTIFICATE----- + +# Issuer: CN=D-TRUST Root Class 3 CA 2 2009 O=D-Trust GmbH +# Subject: CN=D-TRUST Root Class 3 CA 2 2009 O=D-Trust GmbH +# Label: "D-TRUST Root Class 3 CA 2 2009" +# Serial: 623603 +# MD5 Fingerprint: cd:e0:25:69:8d:47:ac:9c:89:35:90:f7:fd:51:3d:2f +# SHA1 Fingerprint: 58:e8:ab:b0:36:15:33:fb:80:f7:9b:1b:6d:29:d3:ff:8d:5f:00:f0 +# SHA256 Fingerprint: 49:e7:a4:42:ac:f0:ea:62:87:05:00:54:b5:25:64:b6:50:e4:f4:9e:42:e3:48:d6:aa:38:e0:39:e9:57:b1:c1 +-----BEGIN CERTIFICATE----- +MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRF +MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBD +bGFzcyAzIENBIDIgMjAwOTAeFw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NTha +ME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMM +HkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOADER03 +UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42 +tSHKXzlABF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9R +ySPocq60vFYJfxLLHLGvKZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsM +lFqVlNpQmvH/pStmMaTJOKDfHR+4CS7zp+hnUquVH+BGPtikw8paxTGA6Eian5Rp +/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUCAwEAAaOCARowggEWMA8G +A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ4PGEMA4G +A1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVj +dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUy +MENBJTIwMiUyMDIwMDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRl +cmV2b2NhdGlvbmxpc3QwQ6BBoD+GPWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3Js +L2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAwOS5jcmwwDQYJKoZIhvcNAQEL +BQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm2H6NMLVwMeni +acfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 +o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4K +zCUqNQT4YJEVdT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8 +PIWmawomDeCTmGCufsYkl4phX5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3Y +Johw1+qRzT65ysCQblrGXnRl11z+o+I= +-----END CERTIFICATE----- + +# Issuer: CN=D-TRUST Root Class 3 CA 2 EV 2009 O=D-Trust GmbH +# Subject: CN=D-TRUST Root Class 3 CA 2 EV 2009 O=D-Trust GmbH +# Label: "D-TRUST Root Class 3 CA 2 EV 2009" +# Serial: 623604 +# MD5 Fingerprint: aa:c6:43:2c:5e:2d:cd:c4:34:c0:50:4f:11:02:4f:b6 +# SHA1 Fingerprint: 96:c9:1b:0b:95:b4:10:98:42:fa:d0:d8:22:79:fe:60:fa:b9:16:83 +# SHA256 Fingerprint: ee:c5:49:6b:98:8c:e9:86:25:b9:34:09:2e:ec:29:08:be:d0:b0:f3:16:c2:d4:73:0c:84:ea:f1:f3:d3:48:81 +-----BEGIN CERTIFICATE----- +MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRF +MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBD +bGFzcyAzIENBIDIgRVYgMjAwOTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUw +NDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNV +BAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAwOTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfSegpn +ljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM0 +3TP1YtHhzRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6Z +qQTMFexgaDbtCHu39b+T7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lR +p75mpoo6Kr3HGrHhFPC+Oh25z1uxav60sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8 +HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure3511H3a6UCAwEAAaOCASQw +ggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyvcop9Ntea +HNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFw +Oi8vZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xh +c3MlMjAzJTIwQ0ElMjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1E +RT9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0MEagRKBChkBodHRwOi8vd3d3LmQt +dHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xhc3NfM19jYV8yX2V2XzIwMDku +Y3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+PPoeUSbrh/Yp +3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 +nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNF +CSuGdXzfX2lXANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7na +xpeG0ILD5EJt/rDiZE4OJudANCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqX +KVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVvw9y4AyHqnxbxLFS1 +-----END CERTIFICATE----- + +# Issuer: CN=CA Disig Root R2 O=Disig a.s. +# Subject: CN=CA Disig Root R2 O=Disig a.s. +# Label: "CA Disig Root R2" +# Serial: 10572350602393338211 +# MD5 Fingerprint: 26:01:fb:d8:27:a7:17:9a:45:54:38:1a:43:01:3b:03 +# SHA1 Fingerprint: b5:61:eb:ea:a4:de:e4:25:4b:69:1a:98:a5:57:47:c2:34:c7:d9:71 +# SHA256 Fingerprint: e2:3d:4a:03:6d:7b:70:e9:f5:95:b1:42:20:79:d2:b9:1e:df:bb:1f:b6:51:a0:63:3e:aa:8a:9d:c5:f8:07:03 +-----BEGIN CERTIFICATE----- +MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNV +BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu +MRkwFwYDVQQDExBDQSBEaXNpZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQy +MDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sxEzARBgNVBAcTCkJyYXRpc2xhdmEx +EzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERpc2lnIFJvb3QgUjIw +ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbCw3Oe +NcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNH +PWSb6WiaxswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3I +x2ymrdMxp7zo5eFm1tL7A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbe +QTg06ov80egEFGEtQX6sx3dOy1FU+16SGBsEWmjGycT6txOgmLcRK7fWV8x8nhfR +yyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqVg8NTEQxzHQuyRpDRQjrO +QG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa5Beny912 +H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJ +QfYEkoopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUD +i/ZnWejBBhG93c+AAk9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORs +nLMOPReisjQS1n6yqEm70XooQL6iFh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1 +rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud +DwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5uQu0wDQYJKoZI +hvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM +tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqf +GopTpti72TVVsRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkb +lvdhuDvEK7Z4bLQjb/D907JedR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka ++elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W81k/BfDxujRNt+3vrMNDcTa/F1bal +TFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjxmHHEt38OFdAlab0i +nSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01utI3 +gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18Dr +G5gPcFw0sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3Os +zMOl6W8KjptlwlCFtaOgUxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8x +L4ysEr3vQCj8KWefshNPZiTEUxnpHikV7+ZtsH8tZ/3zbBt1RqPlShfppNcL +-----END CERTIFICATE----- + +# Issuer: CN=ACCVRAIZ1 O=ACCV OU=PKIACCV +# Subject: CN=ACCVRAIZ1 O=ACCV OU=PKIACCV +# Label: "ACCVRAIZ1" +# Serial: 6828503384748696800 +# MD5 Fingerprint: d0:a0:5a:ee:05:b6:09:94:21:a1:7d:f1:b2:29:82:02 +# SHA1 Fingerprint: 93:05:7a:88:15:c6:4f:ce:88:2f:fa:91:16:52:28:78:bc:53:64:17 +# SHA256 Fingerprint: 9a:6e:c0:12:e1:a7:da:9d:be:34:19:4d:47:8a:d7:c0:db:18:22:fb:07:1d:f1:29:81:49:6e:d1:04:38:41:13 +-----BEGIN CERTIFICATE----- +MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UE +AwwJQUNDVlJBSVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQsw +CQYDVQQGEwJFUzAeFw0xMTA1MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQ +BgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwHUEtJQUNDVjENMAsGA1UECgwEQUND +VjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCb +qau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gMjmoY +HtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWo +G2ioPej0RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpA +lHPrzg5XPAOBOp0KoVdDaaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhr +IA8wKFSVf+DuzgpmndFALW4ir50awQUZ0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/ +0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDGWuzndN9wrqODJerWx5eH +k6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs78yM2x/47 +4KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMO +m3WR5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpa +cXpkatcnYGMN285J9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPl +uUsXQA+xtrn13k/c4LOsOxFwYIRKQ26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYI +KwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRwOi8vd3d3LmFjY3YuZXMvZmls +ZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEuY3J0MB8GCCsG +AQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2 +VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeT +VfZW6oHlNsyMHj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIG +CCsGAQUFBwICMIIBFB6CARAAQQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUA +cgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBhAO0AegAgAGQAZQAgAGwAYQAgAEEA +QwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUAYwBuAG8AbABvAGcA +7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBjAHQA +cgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAA +QwBQAFMAIABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUA +czAwBggrBgEFBQcCARYkaHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2Mu +aHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRt +aW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2MV9kZXIuY3JsMA4GA1Ud +DwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZIhvcNAQEF +BQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdp +D70ER9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gU +JyCpZET/LtZ1qmxNYEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+m +AM/EKXMRNt6GGT6d7hmKG9Ww7Y49nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepD +vV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJTS+xJlsndQAJxGJ3KQhfnlms +tn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3sCPdK6jT2iWH +7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h +I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szA +h1xA2syVP1XgNce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xF +d3+YJ5oyXSrjhO7FmGYvliAd3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2H +pPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3pEfbRD0tVNEYqi4Y7 +-----END CERTIFICATE----- + +# Issuer: CN=TWCA Global Root CA O=TAIWAN-CA OU=Root CA +# Subject: CN=TWCA Global Root CA O=TAIWAN-CA OU=Root CA +# Label: "TWCA Global Root CA" +# Serial: 3262 +# MD5 Fingerprint: f9:03:7e:cf:e6:9e:3c:73:7a:2a:90:07:69:ff:2b:96 +# SHA1 Fingerprint: 9c:bb:48:53:f6:a4:f6:d3:52:a4:e8:32:52:55:60:13:f5:ad:af:65 +# SHA256 Fingerprint: 59:76:90:07:f7:68:5d:0f:cd:50:87:2f:9f:95:d5:75:5a:5b:2b:45:7d:81:f3:69:2b:61:0a:98:67:2f:0e:1b +-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcx +EjAQBgNVBAoTCVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMT +VFdDQSBHbG9iYWwgUm9vdCBDQTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5 +NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQKEwlUQUlXQU4tQ0ExEDAOBgNVBAsT +B1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3QgQ0EwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2CnJfF +10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz +0ALfUPZVr2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfCh +MBwqoJimFb3u/Rk28OKRQ4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbH +zIh1HrtsBv+baz4X7GGqcXzGHaL3SekVtTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc +46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1WKKD+u4ZqyPpcC1jcxkt2 +yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99sy2sbZCi +laLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYP +oA/pyJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQA +BDzfuBSO6N+pjWxnkjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcE +qYSjMq+u7msXi7Kx/mzhkIyIqJdIzshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm +4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6gcFGn90xHNcgL +1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn +LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WF +H6vPNOw/KP4M8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNo +RI2T9GRwoD2dKAXDOXC4Ynsg/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+ +nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlglPx4mI88k1HtQJAH32RjJMtOcQWh +15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryPA9gK8kxkRr05YuWW +6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3mi4TW +nsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5j +wa19hAM8EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWz +aGHQRiapIVJpLesux+t3zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmy +KwbQBM0= +-----END CERTIFICATE----- + +# Issuer: CN=TeliaSonera Root CA v1 O=TeliaSonera +# Subject: CN=TeliaSonera Root CA v1 O=TeliaSonera +# Label: "TeliaSonera Root CA v1" +# Serial: 199041966741090107964904287217786801558 +# MD5 Fingerprint: 37:41:49:1b:18:56:9a:26:f5:ad:c2:66:fb:40:a5:4c +# SHA1 Fingerprint: 43:13:bb:96:f1:d5:86:9b:c1:4e:6a:92:f6:cf:f6:34:69:87:82:37 +# SHA256 Fingerprint: dd:69:36:fe:21:f8:f0:77:c1:23:a1:a5:21:c1:22:24:f7:22:55:b7:3e:03:a7:26:06:93:e8:a2:4b:0f:a3:89 +-----BEGIN CERTIFICATE----- +MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAw +NzEUMBIGA1UECgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJv +b3QgQ0EgdjEwHhcNMDcxMDE4MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYD +VQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwWVGVsaWFTb25lcmEgUm9vdCBDQSB2 +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+6yfwIaPzaSZVfp3F +VRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA3GV1 +7CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+X +Z75Ljo1kB1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+ +/jXh7VB7qTCNGdMJjmhnXb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs +81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxHoLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkm +dtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3F0fUTPHSiXk+TT2YqGHe +Oh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJoWjiUIMu +sDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4 +pgd7gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fs +slESl1MpWtTwEhDcTwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQ +arMCpgKIv7NHfirZ1fpoeDVNAgMBAAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYD +VR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qWDNXr+nuqF+gTEjANBgkqhkiG +9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNmzqjMDfz1mgbl +dxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx +0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1Tj +TQpgcmLNkQfWpb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBed +Y2gea+zDTYa4EzAvXUYNR0PVG6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7 +Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpcc41teyWRyu5FrgZLAMzTsVlQ2jqI +OylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOTJsjrDNYmiLbAJM+7 +vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2qReW +t88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcn +HL/EVlP6Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVx +SK236thZiNSQvxaz2emsWWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= +-----END CERTIFICATE----- + +# Issuer: CN=E-Tugra Certification Authority O=E-Tu\u011fra EBG Bili\u015fim Teknolojileri ve Hizmetleri A.\u015e. OU=E-Tugra Sertifikasyon Merkezi +# Subject: CN=E-Tugra Certification Authority O=E-Tu\u011fra EBG Bili\u015fim Teknolojileri ve Hizmetleri A.\u015e. OU=E-Tugra Sertifikasyon Merkezi +# Label: "E-Tugra Certification Authority" +# Serial: 7667447206703254355 +# MD5 Fingerprint: b8:a1:03:63:b0:bd:21:71:70:8a:6f:13:3a:bb:79:49 +# SHA1 Fingerprint: 51:c6:e7:08:49:06:6e:f3:92:d4:5c:a0:0d:6d:a3:62:8f:c3:52:39 +# SHA256 Fingerprint: b0:bf:d5:2b:b0:d7:d9:bd:92:bf:5d:4d:c1:3d:a2:55:c0:2c:54:2f:37:83:65:ea:89:39:11:f5:5e:55:f2:3c +-----BEGIN CERTIFICATE----- +MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNV +BAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBC +aWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNV +BAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQDDB9FLVR1 +Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMwNTEyMDk0OFoXDTIz +MDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+ +BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhp +em1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN +ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA4vU/kwVRHoViVF56C/UY +B4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vdhQd2h8y/L5VMzH2nPbxH +D5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5KCKpbknSF +Q9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEo +q1+gElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3D +k14opz8n8Y4e0ypQBaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcH +fC425lAcP9tDJMW/hkd5s3kc91r0E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsut +dEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gzrt48Ue7LE3wBf4QOXVGUnhMM +ti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAqjqFGOjGY5RH8 +zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn +rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUX +U8u3Zg5mTPj5dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6 +Jyr+zE7S6E5UMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5 +XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAF +Nzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAKkEh47U6YA5n+KGCR +HTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jOXKqY +GwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c +77NCR807VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3 ++GbHeJAAFS6LrVE1Uweoa2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WK +vJUawSg5TB9D0pH0clmKuVb8P7Sd2nCcdlqMQ1DujjByTd//SffGqWfZbawCEeI6 +FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEVKV0jq9BgoRJP3vQXzTLl +yb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gTDx4JnW2P +AJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpD +y4Q08ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8d +NL/+I5c30jn6PQ0GC7TbO6Orb1wdtn7os4I07QZcJA== +-----END CERTIFICATE----- + +# Issuer: CN=T-TeleSec GlobalRoot Class 2 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center +# Subject: CN=T-TeleSec GlobalRoot Class 2 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center +# Label: "T-TeleSec GlobalRoot Class 2" +# Serial: 1 +# MD5 Fingerprint: 2b:9b:9e:e4:7b:6c:1f:00:72:1a:cc:c1:77:79:df:6a +# SHA1 Fingerprint: 59:0d:2d:7d:88:4f:40:2e:61:7e:a5:62:32:17:65:cf:17:d8:94:e9 +# SHA256 Fingerprint: 91:e2:f5:78:8d:58:10:eb:a7:ba:58:73:7d:e1:54:8a:8e:ca:cd:01:45:98:bc:0b:14:3e:04:1b:17:05:25:52 +-----BEGIN CERTIFICATE----- +MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx +KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd +BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl +YyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgxMDAxMTA0MDE0WhcNMzMxMDAxMjM1 +OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy +aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 +ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUd +AqSzm1nzHoqvNK38DcLZSBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiC +FoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/FvudocP05l03Sx5iRUKrERLMjfTlH6VJi +1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx9702cu+fjOlbpSD8DT6Iavq +jnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGVWOHAD3bZ +wI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGj +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/ +WSA2AHmgoCJrjNXyYdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhy +NsZt+U2e+iKo4YFWz827n+qrkRk4r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPAC +uvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNfvNoBYimipidx5joifsFvHZVw +IEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR3p1m0IvVVGb6 +g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN +9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlP +BSeOE6Fuwg== +-----END CERTIFICATE----- + +# Issuer: CN=Atos TrustedRoot 2011 O=Atos +# Subject: CN=Atos TrustedRoot 2011 O=Atos +# Label: "Atos TrustedRoot 2011" +# Serial: 6643877497813316402 +# MD5 Fingerprint: ae:b9:c4:32:4b:ac:7f:5d:66:cc:77:94:bb:2a:77:56 +# SHA1 Fingerprint: 2b:b1:f5:3e:55:0c:1d:c5:f1:d4:e6:b7:6a:46:4b:55:06:02:ac:21 +# SHA256 Fingerprint: f3:56:be:a2:44:b7:a9:1e:b3:5d:53:ca:9a:d7:86:4a:ce:01:8e:2d:35:d5:f8:f9:6d:df:68:a6:f4:1a:a4:74 +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE +AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG +EwJERTAeFw0xMTA3MDcxNDU4MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMM +FUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UEBhMC +REUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCVhTuXbyo7LjvPpvMp +Nb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr54rM +VD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+ +SZFhyBH+DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ +4J7sVaE3IqKHBAUsR320HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0L +cp2AMBYHlT8oDv3FdU9T1nSatCQujgKRz3bFmx5VdJx4IbHwLfELn8LVlhgf8FQi +eowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7Rl+lwrrw7GWzbITAPBgNV +HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZbNshMBgG +A1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3 +DQEBCwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8j +vZfza1zv7v1Apt+hk6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kP +DpFrdRbhIfzYJsdHt6bPWHJxfrrhTZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pc +maHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a961qn8FYiqTxlVMYVqL2Gns2D +lmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G3mB/ufNPRJLv +KrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed +-----END CERTIFICATE----- + +# Issuer: CN=QuoVadis Root CA 1 G3 O=QuoVadis Limited +# Subject: CN=QuoVadis Root CA 1 G3 O=QuoVadis Limited +# Label: "QuoVadis Root CA 1 G3" +# Serial: 687049649626669250736271037606554624078720034195 +# MD5 Fingerprint: a4:bc:5b:3f:fe:37:9a:fa:64:f0:e2:fa:05:3d:0b:ab +# SHA1 Fingerprint: 1b:8e:ea:57:96:29:1a:c9:39:ea:b8:0a:81:1a:73:73:c0:93:79:67 +# SHA256 Fingerprint: 8a:86:6f:d1:b2:76:b5:7e:57:8e:92:1c:65:82:8a:2b:ed:58:e9:f2:f2:88:05:41:34:b7:f1:f4:bf:c9:cc:74 +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc +BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00 +MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEgRzMwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakEPBtV +wedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWe +rNrwU8lmPNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF341 +68Xfuw6cwI2H44g4hWf6Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh +4Pw5qlPafX7PGglTvF0FBM+hSo+LdoINofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXp +UhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/lg6AnhF4EwfWQvTA9xO+o +abw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV7qJZjqlc +3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/G +KubX9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSt +hfbZxbGL0eUQMk1fiyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KO +Tk0k+17kBL5yG6YnLUlamXrXXAkgt3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOt +zCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZIhvcNAQELBQAD +ggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC +MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2 +cDMT/uFPpiN3GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUN +qXsCHKnQO18LwIE6PWThv6ctTr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5 +YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP+V04ikkwj+3x6xn0dxoxGE1nVGwv +b2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh3jRJjehZrJ3ydlo2 +8hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fawx/k +NSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNj +ZgKAvQU6O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhp +q1467HxpvMc7hU6eFbm0FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFt +nh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOVhMJKzRwuJIczYOXD +-----END CERTIFICATE----- + +# Issuer: CN=QuoVadis Root CA 2 G3 O=QuoVadis Limited +# Subject: CN=QuoVadis Root CA 2 G3 O=QuoVadis Limited +# Label: "QuoVadis Root CA 2 G3" +# Serial: 390156079458959257446133169266079962026824725800 +# MD5 Fingerprint: af:0c:86:6e:bf:40:2d:7f:0b:3e:12:50:ba:12:3d:06 +# SHA1 Fingerprint: 09:3c:61:f3:8b:8b:dc:7d:55:df:75:38:02:05:00:e1:25:f5:c8:36 +# SHA256 Fingerprint: 8f:e4:fb:0a:f9:3a:4d:0d:67:db:0b:eb:b2:3e:37:c7:1b:f3:25:dc:bc:dd:24:0e:a0:4d:af:58:b4:7e:18:40 +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc +BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00 +MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIgRzMwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFhZiFf +qq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMW +n4rjyduYNM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ym +c5GQYaYDFCDy54ejiK2toIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+ +O7q414AB+6XrW7PFXmAqMaCvN+ggOp+oMiwMzAkd056OXbxMmO7FGmh77FOm6RQ1 +o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+lV0POKa2Mq1W/xPtbAd0j +IaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZoL1NesNKq +IcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz +8eQQsSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43eh +vNURG3YBZwjgQQvD6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l +7ZizlWNof/k19N+IxWA1ksB8aRxhlRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALG +cC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZIhvcNAQELBQAD +ggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66 +AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RC +roijQ1h5fq7KpVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0Ga +W/ZZGYjeVYg3UQt4XAoeo0L9x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4n +lv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgzdWqTHBLmYF5vHX/JHyPLhGGfHoJE ++V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6XU/IyAgkwo1jwDQHV +csaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+NwmNtd +dbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNg +KCLjsZWDzYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeM +HVOyToV7BjjHLPj4sHKNJeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4 +WSr2Rz0ZiC3oheGe7IUIarFsNMkd7EgrO3jtZsSOeWmD3n+M +-----END CERTIFICATE----- + +# Issuer: CN=QuoVadis Root CA 3 G3 O=QuoVadis Limited +# Subject: CN=QuoVadis Root CA 3 G3 O=QuoVadis Limited +# Label: "QuoVadis Root CA 3 G3" +# Serial: 268090761170461462463995952157327242137089239581 +# MD5 Fingerprint: df:7d:b9:ad:54:6f:68:a1:df:89:57:03:97:43:b0:d7 +# SHA1 Fingerprint: 48:12:bd:92:3c:a8:c4:39:06:e7:30:6d:27:96:e6:a4:cf:22:2e:7d +# SHA256 Fingerprint: 88:ef:81:de:20:2e:b0:18:45:2e:43:f8:64:72:5c:ea:5f:bd:1f:c2:d9:d2:05:73:07:09:c5:d8:b8:69:0f:46 +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQEL +BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc +BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00 +MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM +aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMgRzMwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286IxSR +/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNu +FoM7pmRLMon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXR +U7Ox7sWTaYI+FrUoRqHe6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+c +ra1AdHkrAj80//ogaX3T7mH1urPnMNA3I4ZyYUUpSFlob3emLoG+B01vr87ERROR +FHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3UVDmrJqMz6nWB2i3ND0/k +A9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f75li59wzw +eyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634Ryl +sSqiMd5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBp +VzgeAVuNVejH38DMdyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0Q +A4XN8f+MFrXBsj6IbGB/kE+V9/YtrQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ +ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZIhvcNAQELBQAD +ggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px +KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnI +FUBhynLWcKzSt/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5Wvv +oxXqA/4Ti2Tk08HS6IT7SdEQTXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFg +u/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9DuDcpmvJRPpq3t/O5jrFc/ZSXPsoaP +0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGibIh6BJpsQBJFxwAYf +3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmDhPbl +8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+ +DhcI00iX0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HN +PlopNLk9hM6xZdRZkZFWdSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ +ywaZWWDYWGWVjUTR939+J399roD1B0y2PpxxVJkES/1Y+Zj0 +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Assured ID Root G2 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Assured ID Root G2 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Assured ID Root G2" +# Serial: 15385348160840213938643033620894905419 +# MD5 Fingerprint: 92:38:b9:f8:63:24:82:65:2c:57:33:e6:fe:81:8f:9d +# SHA1 Fingerprint: a1:4b:48:d9:43:ee:0a:0e:40:90:4f:3c:e0:a4:c0:91:93:51:5d:3f +# SHA256 Fingerprint: 7d:05:eb:b6:82:33:9f:8c:94:51:ee:09:4e:eb:fe:fa:79:53:a1:14:ed:b2:f4:49:49:45:2f:ab:7d:2f:c1:85 +-----BEGIN CERTIFICATE----- +MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv +b3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQG +EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl +cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSA +n61UQbVH35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4Htecc +biJVMWWXvdMX0h5i89vqbFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9Hp +EgjAALAcKxHad3A2m67OeYfcgnDmCXRwVWmvo2ifv922ebPynXApVfSr/5Vh88lA +bx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OPYLfykqGxvYmJHzDNw6Yu +YjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+RnlTGNAgMB +AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQW +BBTOw0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPI +QW5pJ6d1Ee88hjZv0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I +0jJmwYrA8y8678Dj1JGG0VDjA9tzd29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4Gni +lmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAWhsI6yLETcDbYz+70CjTVW0z9 +B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv +ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo +IhNzbM8m9Yop5w== +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Assured ID Root G3 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Assured ID Root G3 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Assured ID Root G3" +# Serial: 15459312981008553731928384953135426796 +# MD5 Fingerprint: 7c:7f:65:31:0c:81:df:8d:ba:3e:99:e2:5c:ad:6e:fb +# SHA1 Fingerprint: f5:17:a2:4f:9a:48:c6:c9:f8:a2:00:26:9f:dc:0f:48:2c:ab:30:89 +# SHA256 Fingerprint: 7e:37:cb:8b:4c:47:09:0c:ab:36:55:1b:a6:f4:5d:b8:40:68:0f:ba:16:6a:95:2d:b1:00:71:7f:43:05:3f:c2 +-----BEGIN CERTIFICATE----- +MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw +CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu +ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg +RzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu +Y29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJf +Zn4f5dwbRXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17Q +RSAPWXYQ1qAk8C3eNvJsKTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ +BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgFUaFNN6KDec6NHSrkhDAKBggqhkjOPQQD +AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY +JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv +6pZjamVFkpUBtA== +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Global Root G2 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Global Root G2 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Global Root G2" +# Serial: 4293743540046975378534879503202253541 +# MD5 Fingerprint: e4:a6:8a:c8:54:ac:52:42:46:0a:fd:72:48:1b:2a:44 +# SHA1 Fingerprint: df:3c:24:f9:bf:d6:66:76:1b:26:80:73:fe:06:d1:cc:8d:4f:82:a4 +# SHA256 Fingerprint: cb:3c:cb:b7:60:31:e5:e0:13:8f:8d:d3:9a:23:f9:de:47:ff:c3:5e:43:c1:14:4c:ea:27:d4:6a:5a:b1:cb:5f +-----BEGIN CERTIFICATE----- +MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH +MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT +MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j +b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG +9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI +2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx +1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ +q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz +tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ +vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP +BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV +5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY +1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4 +NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG +Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91 +8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe +pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl +MrY= +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Global Root G3 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Global Root G3 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Global Root G3" +# Serial: 7089244469030293291760083333884364146 +# MD5 Fingerprint: f5:5d:a4:50:a5:fb:28:7e:1e:0f:0d:cc:96:57:56:ca +# SHA1 Fingerprint: 7e:04:de:89:6a:3e:66:6d:00:e6:87:d3:3f:fa:d9:3b:e8:3d:34:9e +# SHA256 Fingerprint: 31:ad:66:48:f8:10:41:38:c7:38:f3:9e:a4:32:01:33:39:3e:3a:18:cc:02:29:6e:f9:7c:2a:c9:ef:67:31:d0 +-----BEGIN CERTIFICATE----- +MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw +CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu +ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe +Fw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw +EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x +IDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF +K4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG +fp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO +Z9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd +BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx +AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/ +oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8 +sycX +-----END CERTIFICATE----- + +# Issuer: CN=DigiCert Trusted Root G4 O=DigiCert Inc OU=www.digicert.com +# Subject: CN=DigiCert Trusted Root G4 O=DigiCert Inc OU=www.digicert.com +# Label: "DigiCert Trusted Root G4" +# Serial: 7451500558977370777930084869016614236 +# MD5 Fingerprint: 78:f2:fc:aa:60:1f:2f:b4:eb:c9:37:ba:53:2e:75:49 +# SHA1 Fingerprint: dd:fb:16:cd:49:31:c9:73:a2:03:7d:3f:c8:3a:4d:7d:77:5d:05:e4 +# SHA256 Fingerprint: 55:2f:7b:dc:f1:a7:af:9e:6c:e6:72:01:7f:4f:12:ab:f7:72:40:c7:8e:76:1a:c2:03:d1:d9:d2:0a:c8:99:88 +-----BEGIN CERTIFICATE----- +MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi +MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 +d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg +RzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJV +UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu +Y29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3y +ithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1If +xp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDV +ySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiO +DCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQ +jdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/ +CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCi +EhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADM +fRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QY +uKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXK +chYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t +9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +hjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD +ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2 +SV1EY+CtnJYYZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd ++SeuMIW59mdNOj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWc +fFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqa +sjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9N +cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N +0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie +4u1Ki7wb/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mI +r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1 +/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm +gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ +-----END CERTIFICATE----- + +# Issuer: CN=COMODO RSA Certification Authority O=COMODO CA Limited +# Subject: CN=COMODO RSA Certification Authority O=COMODO CA Limited +# Label: "COMODO RSA Certification Authority" +# Serial: 101909084537582093308941363524873193117 +# MD5 Fingerprint: 1b:31:b0:71:40:36:cc:14:36:91:ad:c4:3e:fd:ec:18 +# SHA1 Fingerprint: af:e5:d2:44:a8:d1:19:42:30:ff:47:9f:e2:f8:97:bb:cd:7a:8c:b4 +# SHA256 Fingerprint: 52:f0:e1:c4:e5:8e:c6:29:29:1b:60:31:7f:07:46:71:b8:5d:7e:a8:0d:5b:07:27:34:63:53:4b:32:b4:02:34 +-----BEGIN CERTIFICATE----- +MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB +hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV +BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5 +MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT +EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR +Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh +dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR +6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X +pz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC +9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV +/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf +Zd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z ++pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w +qP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah +SL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC +u9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf +Fobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq +crxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E +FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB +/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl +wFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM +4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV +2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna +FxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ +CuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK +boHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke +jkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL +S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb +QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl +0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB +NVOFBkpdn627G190 +-----END CERTIFICATE----- + +# Issuer: CN=USERTrust RSA Certification Authority O=The USERTRUST Network +# Subject: CN=USERTrust RSA Certification Authority O=The USERTRUST Network +# Label: "USERTrust RSA Certification Authority" +# Serial: 2645093764781058787591871645665788717 +# MD5 Fingerprint: 1b:fe:69:d1:91:b7:19:33:a3:72:a8:0f:e1:55:e5:b5 +# SHA1 Fingerprint: 2b:8f:1b:57:33:0d:bb:a2:d0:7a:6c:51:f7:0e:e9:0d:da:b9:ad:8e +# SHA256 Fingerprint: e7:93:c9:b0:2f:d8:aa:13:e2:1c:31:22:8a:cc:b0:81:19:64:3b:74:9c:89:89:64:b1:74:6d:46:c3:d4:cb:d2 +-----BEGIN CERTIFICATE----- +MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB +iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl +cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV +BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw +MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV +BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU +aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B +3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY +tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/ +Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2 +VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT +79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6 +c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT +Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l +c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee +UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE +Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd +BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G +A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF +Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO +VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3 +ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs +8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR +iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze +Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ +XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/ +qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB +VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB +L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG +jjxDah2nGN59PRbxYvnKkKj9 +-----END CERTIFICATE----- + +# Issuer: CN=USERTrust ECC Certification Authority O=The USERTRUST Network +# Subject: CN=USERTrust ECC Certification Authority O=The USERTRUST Network +# Label: "USERTrust ECC Certification Authority" +# Serial: 123013823720199481456569720443997572134 +# MD5 Fingerprint: fa:68:bc:d9:b5:7f:ad:fd:c9:1d:06:83:28:cc:24:c1 +# SHA1 Fingerprint: d1:cb:ca:5d:b2:d5:2a:7f:69:3b:67:4d:e5:f0:5a:1d:0c:95:7d:f0 +# SHA256 Fingerprint: 4f:f4:60:d5:4b:9c:86:da:bf:bc:fc:57:12:e0:40:0d:2b:ed:3f:bc:4d:4f:bd:aa:86:e0:6a:dc:d2:a9:ad:7a +-----BEGIN CERTIFICATE----- +MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDEL +MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl +eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT +JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMjAx +MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT +Ck5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUg +VVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlm +aWNhdGlvbiBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqflo +I+d61SRvU8Za2EurxtW20eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinng +o4N+LZfQYcTxmdwlkWOrfzCjtHDix6EznPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0G +A1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBBHU6+4WMB +zzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbW +RNZu9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg= +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R4 +# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R4 +# Label: "GlobalSign ECC Root CA - R4" +# Serial: 14367148294922964480859022125800977897474 +# MD5 Fingerprint: 20:f0:27:68:d1:7e:a0:9d:0e:e6:2a:ca:df:5c:89:8e +# SHA1 Fingerprint: 69:69:56:2e:40:80:f4:24:a1:e7:19:9f:14:ba:f3:ee:58:ab:6a:bb +# SHA256 Fingerprint: be:c9:49:11:c2:95:56:76:db:6c:0a:55:09:86:d7:6e:3b:a0:05:66:7c:44:2c:97:62:b4:fb:b7:73:de:22:8c +-----BEGIN CERTIFICATE----- +MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEk +MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpH +bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX +DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD +QSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu +MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprlOQcJ +FspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAw +DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61F +uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX +kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs +ewv4n4Q= +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R5 +# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R5 +# Label: "GlobalSign ECC Root CA - R5" +# Serial: 32785792099990507226680698011560947931244 +# MD5 Fingerprint: 9f:ad:3b:1c:02:1e:8a:ba:17:74:38:81:0c:a2:bc:08 +# SHA1 Fingerprint: 1f:24:c6:30:cd:a4:18:ef:20:69:ff:ad:4f:dd:5f:46:3a:1b:69:aa +# SHA256 Fingerprint: 17:9f:bc:14:8a:3d:d0:0f:d2:4e:a1:34:58:cc:43:bf:a7:f5:9c:81:82:d7:83:a5:13:f6:eb:ec:10:0c:89:24 +-----BEGIN CERTIFICATE----- +MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk +MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpH +bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX +DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD +QSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu +MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6SFkc +8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8ke +hOvRnkmSh5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD +VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYI +KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg +515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7yFz9SO8NdCKoCOJuxUnO +xwy8p2Fp8fc74SrL+SvzZpA3 +-----END CERTIFICATE----- + +# Issuer: CN=Staat der Nederlanden EV Root CA O=Staat der Nederlanden +# Subject: CN=Staat der Nederlanden EV Root CA O=Staat der Nederlanden +# Label: "Staat der Nederlanden EV Root CA" +# Serial: 10000013 +# MD5 Fingerprint: fc:06:af:7b:e8:1a:f1:9a:b4:e8:d2:70:1f:c0:f5:ba +# SHA1 Fingerprint: 76:e2:7e:c1:4f:db:82:c1:c0:a6:75:b5:05:be:3d:29:b4:ed:db:bb +# SHA256 Fingerprint: 4d:24:91:41:4c:fe:95:67:46:ec:4c:ef:a6:cf:6f:72:e2:8a:13:29:43:2f:9d:8a:90:7a:c4:cb:5d:ad:c1:5a +-----BEGIN CERTIFICATE----- +MIIFcDCCA1igAwIBAgIEAJiWjTANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJO +TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSkwJwYDVQQDDCBTdGFh +dCBkZXIgTmVkZXJsYW5kZW4gRVYgUm9vdCBDQTAeFw0xMDEyMDgxMTE5MjlaFw0y +MjEyMDgxMTEwMjhaMFgxCzAJBgNVBAYTAk5MMR4wHAYDVQQKDBVTdGFhdCBkZXIg +TmVkZXJsYW5kZW4xKTAnBgNVBAMMIFN0YWF0IGRlciBOZWRlcmxhbmRlbiBFViBS +b290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA48d+ifkkSzrS +M4M1LGns3Amk41GoJSt5uAg94JG6hIXGhaTK5skuU6TJJB79VWZxXSzFYGgEt9nC +UiY4iKTWO0Cmws0/zZiTs1QUWJZV1VD+hq2kY39ch/aO5ieSZxeSAgMs3NZmdO3d +Z//BYY1jTw+bbRcwJu+r0h8QoPnFfxZpgQNH7R5ojXKhTbImxrpsX23Wr9GxE46p +rfNeaXUmGD5BKyF/7otdBwadQ8QpCiv8Kj6GyzyDOvnJDdrFmeK8eEEzduG/L13l +pJhQDBXd4Pqcfzho0LKmeqfRMb1+ilgnQ7O6M5HTp5gVXJrm0w912fxBmJc+qiXb +j5IusHsMX/FjqTf5m3VpTCgmJdrV8hJwRVXj33NeN/UhbJCONVrJ0yPr08C+eKxC +KFhmpUZtcALXEPlLVPxdhkqHz3/KRawRWrUgUY0viEeXOcDPusBCAUCZSCELa6fS +/ZbV0b5GnUngC6agIk440ME8MLxwjyx1zNDFjFE7PZQIZCZhfbnDZY8UnCHQqv0X +cgOPvZuM5l5Tnrmd74K74bzickFbIZTTRTeU0d8JOV3nI6qaHcptqAqGhYqCvkIH +1vI4gnPah1vlPNOePqc7nvQDs/nxfRN0Av+7oeX6AHkcpmZBiFxgV6YuCcS6/ZrP +px9Aw7vMWgpVSzs4dlG4Y4uElBbmVvMCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFP6rAJCYniT8qcwaivsnuL8wbqg7 +MA0GCSqGSIb3DQEBCwUAA4ICAQDPdyxuVr5Os7aEAJSrR8kN0nbHhp8dB9O2tLsI +eK9p0gtJ3jPFrK3CiAJ9Brc1AsFgyb/E6JTe1NOpEyVa/m6irn0F3H3zbPB+po3u +2dfOWBfoqSmuc0iH55vKbimhZF8ZE/euBhD/UcabTVUlT5OZEAFTdfETzsemQUHS +v4ilf0X8rLiltTMMgsT7B/Zq5SWEXwbKwYY5EdtYzXc7LMJMD16a4/CrPmEbUCTC +wPTxGfARKbalGAKb12NMcIxHowNDXLldRqANb/9Zjr7dn3LDWyvfjFvO5QxGbJKy +CqNMVEIYFRIYvdr8unRu/8G2oGTYqV9Vrp9canaW2HNnh/tNf1zuacpzEPuKqf2e +vTY4SUmH9A4U8OmHuD+nT3pajnnUk+S7aFKErGzp85hwVXIy+TSrK0m1zSBi5Dp6 +Z2Orltxtrpfs/J92VoguZs9btsmksNcFuuEnL5O7Jiqik7Ab846+HUCjuTaPPoIa +Gl6I6lD4WeKDRikL40Rc4ZW2aZCaFG+XroHPaO+Zmr615+F/+PoTRxZMzG0IQOeL +eG9QgkRQP2YGiqtDhFZKDyAthg710tvSeopLzaXoTvFeJiUBWSOgftL2fiFX1ye8 +FVdMpEbB4IMeDExNH08GGeL5qPQ6gqGyeUN51q1veieQA6TqJIc/2b3Z6fJfUEkc +7uzXLg== +-----END CERTIFICATE----- + +# Issuer: CN=IdenTrust Commercial Root CA 1 O=IdenTrust +# Subject: CN=IdenTrust Commercial Root CA 1 O=IdenTrust +# Label: "IdenTrust Commercial Root CA 1" +# Serial: 13298821034946342390520003877796839426 +# MD5 Fingerprint: b3:3e:77:73:75:ee:a0:d3:e3:7e:49:63:49:59:bb:c7 +# SHA1 Fingerprint: df:71:7e:aa:4a:d9:4e:c9:55:84:99:60:2d:48:de:5f:bc:f0:3a:25 +# SHA256 Fingerprint: 5d:56:49:9b:e4:d2:e0:8b:cf:ca:d0:8a:3e:38:72:3d:50:50:3b:de:70:69:48:e4:2f:55:60:30:19:e5:28:ae +-----BEGIN CERTIFICATE----- +MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBK +MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVu +VHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQw +MTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScw +JQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwggIiMA0GCSqG +SIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ldhNlT +3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU ++ehcCuz/mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gp +S0l4PJNgiCL8mdo2yMKi1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1 +bVoE/c40yiTcdCMbXTMTEl3EASX2MN0CXZ/g1Ue9tOsbobtJSdifWwLziuQkkORi +T0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl3ZBWzvurpWCdxJ35UrCL +vYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzyNeVJSQjK +Vsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZK +dHzVWYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHT +c+XvvqDtMwt0viAgxGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hv +l7yTmvmcEpB4eoCHFddydJxVdHixuuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5N +iGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB +/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZIhvcNAQELBQAD +ggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH +6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwt +LRvM7Kqas6pgghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93 +nAbowacYXVKV7cndJZ5t+qntozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3 ++wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmVYjzlVYA211QC//G5Xc7UI2/YRYRK +W2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUXfeu+h1sXIFRRk0pT +AwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/rokTLq +l1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG +4iZZRHUe2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZ +mUlO+KWA2yUPHGNiiskzZ2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A +7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7RcGzM7vRX+Bi6hG6H +-----END CERTIFICATE----- + +# Issuer: CN=IdenTrust Public Sector Root CA 1 O=IdenTrust +# Subject: CN=IdenTrust Public Sector Root CA 1 O=IdenTrust +# Label: "IdenTrust Public Sector Root CA 1" +# Serial: 13298821034946342390521976156843933698 +# MD5 Fingerprint: 37:06:a5:b0:fc:89:9d:ba:f4:6b:8c:1a:64:cd:d5:ba +# SHA1 Fingerprint: ba:29:41:60:77:98:3f:f4:f3:ef:f2:31:05:3b:2e:ea:6d:4d:45:fd +# SHA256 Fingerprint: 30:d0:89:5a:9a:44:8a:26:20:91:63:55:22:d1:f5:20:10:b5:86:7a:ca:e1:2c:78:ef:95:8f:d4:f4:38:9f:2f +-----BEGIN CERTIFICATE----- +MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBN +MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVu +VHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcN +MzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0 +MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTyP4o7 +ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGy +RBb06tD6Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlS +bdsHyo+1W/CD80/HLaXIrcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF +/YTLNiCBWS2ab21ISGHKTN9T0a9SvESfqy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R +3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoSmJxZZoY+rfGwyj4GD3vw +EUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFnol57plzy +9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9V +GxyhLrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ +2fjXctscvG29ZV/viDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsV +WaFHVCkugyhfHMKiq3IXAAaOReyL4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gD +W/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMwDQYJKoZIhvcN +AQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj +t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHV +DRDtfULAj+7AmgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9 +TaDKQGXSc3z1i9kKlT/YPyNtGtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8G +lwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFtm6/n6J91eEyrRjuazr8FGF1NFTwW +mhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMxNRF4eKLg6TCMf4Df +WN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4Mhn5 ++bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJ +tshquDDIajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhA +GaQdp/lLQzfcaFpPz+vCZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv +8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ3Wl9af0AVqW3rLatt8o+Ae+c +-----END CERTIFICATE----- + +# Issuer: CN=Entrust Root Certification Authority - G2 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2009 Entrust, Inc. - for authorized use only +# Subject: CN=Entrust Root Certification Authority - G2 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2009 Entrust, Inc. - for authorized use only +# Label: "Entrust Root Certification Authority - G2" +# Serial: 1246989352 +# MD5 Fingerprint: 4b:e2:c9:91:96:65:0c:f4:0e:5a:93:92:a0:0a:fe:b2 +# SHA1 Fingerprint: 8c:f4:27:fd:79:0c:3a:d1:66:06:8d:e8:1e:57:ef:bb:93:22:72:d4 +# SHA256 Fingerprint: 43:df:57:74:b0:3e:7f:ef:5f:e4:0d:93:1a:7b:ed:f1:bb:2e:6b:42:73:8c:4e:6d:38:41:10:3d:3a:a7:f3:39 +-----BEGIN CERTIFICATE----- +MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50 +cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs +IEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz +dCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMDkwNzA3MTcy +NTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu +dHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt +dGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0 +aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP/vaCeb9zYQYKpSfYs1/T +RU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXzHHfV1IWN +cCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hW +wcKUs/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1 +U1+cPvQXLOZprE4yTGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0 +jaWvYkxN4FisZDQSA/i2jZRjJKRxAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ60B7vfec7aVHUbI2fkBJmqzAN +BgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5ZiXMRrEPR9RP/ +jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ +Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v +1fN2D807iDginWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4R +nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH +VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g== +-----END CERTIFICATE----- + +# Issuer: CN=Entrust Root Certification Authority - EC1 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2012 Entrust, Inc. - for authorized use only +# Subject: CN=Entrust Root Certification Authority - EC1 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2012 Entrust, Inc. - for authorized use only +# Label: "Entrust Root Certification Authority - EC1" +# Serial: 51543124481930649114116133369 +# MD5 Fingerprint: b6:7e:1d:f0:58:c5:49:6c:24:3b:3d:ed:98:18:ed:bc +# SHA1 Fingerprint: 20:d8:06:40:df:9b:25:f5:12:25:3a:11:ea:f7:59:8a:eb:14:b5:47 +# SHA256 Fingerprint: 02:ed:0e:b2:8c:14:da:45:16:5c:56:67:91:70:0d:64:51:d7:fb:56:f0:b2:ab:1d:3b:8e:b0:70:e5:6e:df:f5 +-----BEGIN CERTIFICATE----- +MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkG +A1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3 +d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVu +dHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEzMDEGA1UEAxMq +RW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRUMxMB4XDTEy +MTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYwFAYD +VQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0 +L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0g +Zm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEVDMTB2MBAGByqGSM49AgEGBSuBBAAi +A2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHyAsWfoPZb1YsGGYZPUxBt +ByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef9eNi1KlH +Bz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O +BBYEFLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVC +R98crlOZF7ZvHH3hvxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nX +hTcGtXsI/esni0qU+eH6p44mCOh8kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G +-----END CERTIFICATE----- + +# Issuer: CN=CFCA EV ROOT O=China Financial Certification Authority +# Subject: CN=CFCA EV ROOT O=China Financial Certification Authority +# Label: "CFCA EV ROOT" +# Serial: 407555286 +# MD5 Fingerprint: 74:e1:b6:ed:26:7a:7a:44:30:33:94:ab:7b:27:81:30 +# SHA1 Fingerprint: e2:b8:29:4b:55:84:ab:6b:58:c2:90:46:6c:ac:3f:b8:39:8f:84:83 +# SHA256 Fingerprint: 5c:c3:d7:8e:4e:1d:5e:45:54:7a:04:e6:87:3e:64:f9:0c:f9:53:6d:1c:cc:2e:f8:00:f3:55:c4:c5:fd:70:fd +-----BEGIN CERTIFICATE----- +MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJD +TjEwMC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9y +aXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkx +MjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEwMC4GA1UECgwnQ2hpbmEgRmluYW5j +aWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJP +T1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnVBU03 +sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpL +TIpTUnrD7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5 +/ZOkVIBMUtRSqy5J35DNuF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp +7hZZLDRJGqgG16iI0gNyejLi6mhNbiyWZXvKWfry4t3uMCz7zEasxGPrb382KzRz +EpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7xzbh72fROdOXW3NiGUgt +hxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9fpy25IGvP +a931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqot +aK8KgWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNg +TnYGmE69g60dWIolhdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfV +PKPtl8MeNPo4+QgO48BdK4PRVmrJtqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hv +cWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAfBgNVHSMEGDAWgBTj/i39KNAL +tbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAd +BgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB +ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObT +ej/tUxPQ4i9qecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdL +jOztUmCypAbqTuv0axn96/Ua4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBS +ESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sGE5uPhnEFtC+NiWYzKXZUmhH4J/qy +P5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfXBDrDMlI1Dlb4pd19 +xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjnaH9d +Ci77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN +5mydLIhyPDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe +/v5WOaHIz16eGWRGENoXkbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+Z +AAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3CekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ +5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su +-----END CERTIFICATE----- + +# Issuer: CN=OISTE WISeKey Global Root GB CA O=WISeKey OU=OISTE Foundation Endorsed +# Subject: CN=OISTE WISeKey Global Root GB CA O=WISeKey OU=OISTE Foundation Endorsed +# Label: "OISTE WISeKey Global Root GB CA" +# Serial: 157768595616588414422159278966750757568 +# MD5 Fingerprint: a4:eb:b9:61:28:2e:b7:2f:98:b0:35:26:90:99:51:1d +# SHA1 Fingerprint: 0f:f9:40:76:18:d3:d7:6a:4b:98:f0:a8:35:9e:0c:fd:27:ac:cc:ed +# SHA256 Fingerprint: 6b:9c:08:e8:6e:b0:f7:67:cf:ad:65:cd:98:b6:21:49:e5:49:4a:67:f5:84:5e:7b:d1:ed:01:9f:27:b8:6b:d6 +-----BEGIN CERTIFICATE----- +MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBt +MQswCQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUg +Rm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9i +YWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAwMzJaFw0zOTEyMDExNTEwMzFaMG0x +CzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBG +b3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2Jh +bCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3 +HEokKtaXscriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGx +WuR51jIjK+FTzJlFXHtPrby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX +1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNk +u7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4oQnc/nSMbsrY9gBQHTC5P +99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvgGUpuuy9r +M2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw +AwEB/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUB +BAMCAQAwDQYJKoZIhvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrgh +cViXfa43FK8+5/ea4n32cZiZBKpDdHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5 +gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0VQreUGdNZtGn//3ZwLWoo4rO +ZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEuiHZeeevJuQHHf +aPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic +Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM= +-----END CERTIFICATE----- + +# Issuer: CN=SZAFIR ROOT CA2 O=Krajowa Izba Rozliczeniowa S.A. +# Subject: CN=SZAFIR ROOT CA2 O=Krajowa Izba Rozliczeniowa S.A. +# Label: "SZAFIR ROOT CA2" +# Serial: 357043034767186914217277344587386743377558296292 +# MD5 Fingerprint: 11:64:c1:89:b0:24:b1:8c:b1:07:7e:89:9e:51:9e:99 +# SHA1 Fingerprint: e2:52:fa:95:3f:ed:db:24:60:bd:6e:28:f3:9c:cc:cf:5e:b3:3f:de +# SHA256 Fingerprint: a1:33:9d:33:28:1a:0b:56:e5:57:d3:d3:2b:1c:e7:f9:36:7e:b0:94:bd:5f:a7:2a:7e:50:04:c8:de:d7:ca:fe +-----BEGIN CERTIFICATE----- +MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQEL +BQAwUTELMAkGA1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6 +ZW5pb3dhIFMuQS4xGDAWBgNVBAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkw +NzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9L +cmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYDVQQDDA9TWkFGSVIg +Uk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5QqEvN +QLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT +3PSQ1hNKDJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw +3gAeqDRHu5rr/gsUvTaE2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr6 +3fE9biCloBK0TXC5ztdyO4mTp4CEHCdJckm1/zuVnsHMyAHs6A6KCpbns6aH5db5 +BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwiieDhZNRnvDF5YTy7ykHN +XGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD +AgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsF +AAOCAQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw +8PRBEew/R40/cof5O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOG +nXkZ7/e7DDWQw4rtTw/1zBLZpD67oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCP +oky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul4+vJhaAlIDf7js4MNIThPIGy +d05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6+/NNIxuZMzSg +LvWpCz/UXeHPhJ/iGcJfitYgHuNztw== +-----END CERTIFICATE----- + +# Issuer: CN=Certum Trusted Network CA 2 O=Unizeto Technologies S.A. OU=Certum Certification Authority +# Subject: CN=Certum Trusted Network CA 2 O=Unizeto Technologies S.A. OU=Certum Certification Authority +# Label: "Certum Trusted Network CA 2" +# Serial: 44979900017204383099463764357512596969 +# MD5 Fingerprint: 6d:46:9e:d9:25:6d:08:23:5b:5e:74:7d:1e:27:db:f2 +# SHA1 Fingerprint: d3:dd:48:3e:2b:bf:4c:05:e8:af:10:f5:fa:76:26:cf:d3:dc:30:92 +# SHA256 Fingerprint: b6:76:f2:ed:da:e8:77:5c:d3:6c:b0:f6:3c:d1:d4:60:39:61:f4:9e:62:65:ba:01:3a:2f:03:07:b6:d0:b8:04 +-----BEGIN CERTIFICATE----- +MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCB +gDELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu +QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIG +A1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQSAyMCIYDzIwMTExMDA2MDgz +OTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQTDEiMCAGA1UEChMZ +VW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3 +b3JrIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWA +DGSdhhuWZGc/IjoedQF97/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn +0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+oCgCXhVqqndwpyeI1B+twTUrWwbNWuKFB +OJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40bRr5HMNUuctHFY9rnY3lE +fktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2puTRZCr+E +Sv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1m +o130GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02i +sx7QBlrd9pPPV3WZ9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOW +OZV7bIBaTxNyxtd9KXpEulKkKtVBRgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgez +Tv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pyehizKV/Ma5ciSixqClnrDvFAS +adgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vMBhBgu4M1t15n +3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMC +AQYwDQYJKoZIhvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQ +F/xlhMcQSZDe28cmk4gmb3DWAl45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTf +CVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuAL55MYIR4PSFk1vtBHxgP58l1cb29 +XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMoclm2q8KMZiYcdywm +djWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tMpkT/ +WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jb +AoJnwTnbw3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksq +P/ujmv5zMnHCnsZy4YpoJ/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Ko +b7a6bINDd82Kkhehnlt4Fj1F4jNy3eFmypnTycUm/Q1oBEauttmbjL4ZvrHG8hnj +XALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLXis7VmFxWlgPF7ncGNf/P +5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7zAYspsbi +DrW5viSP +-----END CERTIFICATE----- + +# Issuer: CN=Hellenic Academic and Research Institutions RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority +# Subject: CN=Hellenic Academic and Research Institutions RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority +# Label: "Hellenic Academic and Research Institutions RootCA 2015" +# Serial: 0 +# MD5 Fingerprint: ca:ff:e2:db:03:d9:cb:4b:e9:0f:ad:84:fd:7b:18:ce +# SHA1 Fingerprint: 01:0c:06:95:a6:98:19:14:ff:bf:5f:c6:b0:b6:95:ea:29:e9:12:a6 +# SHA256 Fingerprint: a0:40:92:9a:02:ce:53:b4:ac:f4:f2:ff:c6:98:1c:e4:49:6f:75:5e:6d:45:fe:0b:2a:69:2b:cd:52:52:3f:36 +-----BEGIN CERTIFICATE----- +MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1Ix +DzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5k +IFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMT +N0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9v +dENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAxMTIxWjCBpjELMAkG +A1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNh +ZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkx +QDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1 +dGlvbnMgUm9vdENBIDIwMTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC +AQDC+Kk/G4n8PDwEXT2QNrCROnk8ZlrvbTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA +4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+ehiGsxr/CL0BgzuNtFajT0 +AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+6PAQZe10 +4S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06C +ojXdFPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV +9Cz82XBST3i4vTwri5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrD +gfgXy5I2XdGj2HUb4Ysn6npIQf1FGQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6 +Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2fu/Z8VFRfS0myGlZYeCsargq +NhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9muiNX6hME6wGko +LfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc +Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVd +ctA4GGqd83EkVAswDQYJKoZIhvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0I +XtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+D1hYc2Ryx+hFjtyp8iY/xnmMsVMI +M4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrMd/K4kPFox/la/vot +9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+yd+2V +Z5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/ea +j8GsGsVn82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnh +X9izjFk0WaSrT2y7HxjbdavYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQ +l033DlZdwJVqwjbDG2jJ9SrcR5q+ss7FJej6A7na+RZukYT1HCjI/CbM1xyQVqdf +bzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVtJ94Cj8rDtSvK6evIIVM4 +pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGaJI7ZjnHK +e7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0 +vm9qp/UsQu0yrbYhnr68 +-----END CERTIFICATE----- + +# Issuer: CN=Hellenic Academic and Research Institutions ECC RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority +# Subject: CN=Hellenic Academic and Research Institutions ECC RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority +# Label: "Hellenic Academic and Research Institutions ECC RootCA 2015" +# Serial: 0 +# MD5 Fingerprint: 81:e5:b4:17:eb:c2:f5:e1:4b:0d:41:7b:49:92:fe:ef +# SHA1 Fingerprint: 9f:f1:71:8d:92:d5:9a:f3:7d:74:97:b4:bc:6f:84:68:0b:ba:b6:66 +# SHA256 Fingerprint: 44:b5:45:aa:8a:25:e6:5a:73:ca:15:dc:27:fc:36:d2:4c:1c:b9:95:3a:06:65:39:b1:15:82:dc:48:7b:48:33 +-----BEGIN CERTIFICATE----- +MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzAN +BgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl +c2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hl +bGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgRUNDIFJv +b3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEwMzcxMlowgaoxCzAJ +BgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmljIEFj +YWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5 +MUQwQgYDVQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0 +dXRpb25zIEVDQyBSb290Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKg +QehLgoRc4vgxEZmGZE4JJS+dQS8KrjVPdJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJa +jq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoKVlp8aQuqgAkkbH7BRqNC +MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFLQi +C4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaep +lSTAGiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7Sof +TUwJCA3sS61kFyjndc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR +-----END CERTIFICATE----- + +# Issuer: CN=ISRG Root X1 O=Internet Security Research Group +# Subject: CN=ISRG Root X1 O=Internet Security Research Group +# Label: "ISRG Root X1" +# Serial: 172886928669790476064670243504169061120 +# MD5 Fingerprint: 0c:d2:f9:e0:da:17:73:e9:ed:86:4d:a5:e3:70:e7:4e +# SHA1 Fingerprint: ca:bd:2a:79:a1:07:6a:31:f2:1d:25:36:35:cb:03:9d:43:29:a5:e8 +# SHA256 Fingerprint: 96:bc:ec:06:26:49:76:f3:74:60:77:9a:cf:28:c5:a7:cf:e8:a3:c0:aa:e1:1a:8f:fc:ee:05:c0:bd:df:08:c6 +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw +TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh +cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 +WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu +ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY +MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc +h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ +0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U +A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW +T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH +B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC +B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv +KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn +OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn +jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw +qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI +rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV +HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq +hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL +ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ +3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK +NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 +ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur +TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC +jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc +oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq +4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA +mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d +emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= +-----END CERTIFICATE----- + +# Issuer: O=FNMT-RCM OU=AC RAIZ FNMT-RCM +# Subject: O=FNMT-RCM OU=AC RAIZ FNMT-RCM +# Label: "AC RAIZ FNMT-RCM" +# Serial: 485876308206448804701554682760554759 +# MD5 Fingerprint: e2:09:04:b4:d3:bd:d1:a0:14:fd:1a:d2:47:c4:57:1d +# SHA1 Fingerprint: ec:50:35:07:b2:15:c4:95:62:19:e2:a8:9a:5b:42:99:2c:4c:2c:20 +# SHA256 Fingerprint: eb:c5:57:0c:29:01:8c:4d:67:b1:aa:12:7b:af:12:f7:03:b4:61:1e:bc:17:b7:da:b5:57:38:94:17:9b:93:fa +-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsx +CzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJ +WiBGTk1ULVJDTTAeFw0wODEwMjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJ +BgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBG +Tk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALpxgHpMhm5/ +yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcfqQgf +BBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAz +WHFctPVrbtQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxF +tBDXaEAUwED653cXeuYLj2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z +374jNUUeAlz+taibmSXaXvMiwzn15Cou08YfxGyqxRxqAQVKL9LFwag0Jl1mpdIC +IfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mwWsXmo8RZZUc1g16p6DUL +mbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnTtOmlcYF7 +wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peS +MKGJ47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2 +ZSysV4999AeU14ECll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMet +UqIJ5G+GR4of6ygnXYMgrwTJbFaai0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUw +AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFPd9xf3E6Jobd2Sn9R2gzL+H +YJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwOi8vd3d3 +LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD +nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1 +RXxlDPiyN8+sD8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYM +LVN0V2Ue1bLdI4E7pWYjJ2cJj+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf +77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrTQfv6MooqtyuGC2mDOL7Nii4LcK2N +JpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW+YJF1DngoABd15jm +fZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7Ixjp +6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp +1txyM/1d8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B +9kiABdcPUXmsEKvU7ANm5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wok +RqEIr9baRRmW1FMdW4R58MD3R++Lj8UGrp1MYp3/RgT408m2ECVAdf4WqslKYIYv +uu8wd+RU4riEmViAqhOLUTpPSPaLtrM= +-----END CERTIFICATE----- + +# Issuer: CN=Amazon Root CA 1 O=Amazon +# Subject: CN=Amazon Root CA 1 O=Amazon +# Label: "Amazon Root CA 1" +# Serial: 143266978916655856878034712317230054538369994 +# MD5 Fingerprint: 43:c6:bf:ae:ec:fe:ad:2f:18:c6:88:68:30:fc:c8:e6 +# SHA1 Fingerprint: 8d:a7:f9:65:ec:5e:fc:37:91:0f:1c:6e:59:fd:c1:cc:6a:6e:de:16 +# SHA256 Fingerprint: 8e:cd:e6:88:4f:3d:87:b1:12:5b:a3:1a:c3:fc:b1:3d:70:16:de:7f:57:cc:90:4f:e1:cb:97:c6:ae:98:19:6e +-----BEGIN CERTIFICATE----- +MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF +ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 +b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL +MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv +b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj +ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM +9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw +IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6 +VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L +93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm +jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA +A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI +U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs +N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv +o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU +5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy +rqXRfboQnoZsG4q5WTP468SQvvG5 +-----END CERTIFICATE----- + +# Issuer: CN=Amazon Root CA 2 O=Amazon +# Subject: CN=Amazon Root CA 2 O=Amazon +# Label: "Amazon Root CA 2" +# Serial: 143266982885963551818349160658925006970653239 +# MD5 Fingerprint: c8:e5:8d:ce:a8:42:e2:7a:c0:2a:5c:7c:9e:26:bf:66 +# SHA1 Fingerprint: 5a:8c:ef:45:d7:a6:98:59:76:7a:8c:8b:44:96:b5:78:cf:47:4b:1a +# SHA256 Fingerprint: 1b:a5:b2:aa:8c:65:40:1a:82:96:01:18:f8:0b:ec:4f:62:30:4d:83:ce:c4:71:3a:19:c3:9c:01:1e:a4:6d:b4 +-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwF +ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 +b24gUm9vdCBDQSAyMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTEL +MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv +b3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2Wny2cSkxK +gXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4kHbZ +W0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg +1dKmSYXpN+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K +8nu+NQWpEjTj82R0Yiw9AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r +2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvdfLC6HM783k81ds8P+HgfajZRRidhW+me +z/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAExkv8LV/SasrlX6avvDXbR +8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSSbtqDT6Zj +mUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz +7Mt0Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6 ++XUyo05f7O0oYtlNc/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI +0u1ufm8/0i2BWSlmy5A5lREedCf+3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMB +Af8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSwDPBMMPQFWAJI/TPlUq9LhONm +UjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oAA7CXDpO8Wqj2 +LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY ++gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kS +k5Nrp+gvU5LEYFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl +7uxMMne0nxrpS10gxdr9HIcWxkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygm +btmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQgj9sAq+uEjonljYE1x2igGOpm/Hl +urR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbWaQbLU8uz/mtBzUF+ +fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoVYh63 +n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE +76KlXIx3KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H +9jVlpNMKVv/1F2Rs76giJUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT +4PsJYGw= +-----END CERTIFICATE----- + +# Issuer: CN=Amazon Root CA 3 O=Amazon +# Subject: CN=Amazon Root CA 3 O=Amazon +# Label: "Amazon Root CA 3" +# Serial: 143266986699090766294700635381230934788665930 +# MD5 Fingerprint: a0:d4:ef:0b:f7:b5:d8:49:95:2a:ec:f5:c4:fc:81:87 +# SHA1 Fingerprint: 0d:44:dd:8c:3c:8c:1a:1a:58:75:64:81:e9:0f:2e:2a:ff:b3:d2:6e +# SHA256 Fingerprint: 18:ce:6c:fe:7b:f1:4e:60:b2:e3:47:b8:df:e8:68:cb:31:d0:2e:bb:3a:da:27:15:69:f5:03:43:b4:6d:b3:a4 +-----BEGIN CERTIFICATE----- +MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5 +MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g +Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG +A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg +Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl +ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j +QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr +ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr +BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM +YyRIHN8wfdVoOw== +-----END CERTIFICATE----- + +# Issuer: CN=Amazon Root CA 4 O=Amazon +# Subject: CN=Amazon Root CA 4 O=Amazon +# Label: "Amazon Root CA 4" +# Serial: 143266989758080763974105200630763877849284878 +# MD5 Fingerprint: 89:bc:27:d5:eb:17:8d:06:6a:69:d5:fd:89:47:b4:cd +# SHA1 Fingerprint: f6:10:84:07:d6:f8:bb:67:98:0c:c2:e2:44:c2:eb:ae:1c:ef:63:be +# SHA256 Fingerprint: e3:5d:28:41:9e:d0:20:25:cf:a6:90:38:cd:62:39:62:45:8d:a5:c6:95:fb:de:a3:c2:2b:0b:fb:25:89:70:92 +-----BEGIN CERTIFICATE----- +MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5 +MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g +Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG +A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg +Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi +9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk +M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB +MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw +CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW +1KyLa2tJElMzrdfkviT8tQp21KW8EA== +-----END CERTIFICATE----- + +# Issuer: CN=TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 O=Turkiye Bilimsel ve Teknolojik Arastirma Kurumu - TUBITAK OU=Kamu Sertifikasyon Merkezi - Kamu SM +# Subject: CN=TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 O=Turkiye Bilimsel ve Teknolojik Arastirma Kurumu - TUBITAK OU=Kamu Sertifikasyon Merkezi - Kamu SM +# Label: "TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1" +# Serial: 1 +# MD5 Fingerprint: dc:00:81:dc:69:2f:3e:2f:b0:3b:f6:3d:5a:91:8e:49 +# SHA1 Fingerprint: 31:43:64:9b:ec:ce:27:ec:ed:3a:3f:0b:8f:0d:e4:e8:91:dd:ee:ca +# SHA256 Fingerprint: 46:ed:c3:68:90:46:d5:3a:45:3f:b3:10:4a:b8:0d:ca:ec:65:8b:26:60:ea:16:29:dd:7e:86:79:90:64:87:16 +-----BEGIN CERTIFICATE----- +MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIx +GDAWBgNVBAcTD0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxp +bXNlbCB2ZSBUZWtub2xvamlrIEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0w +KwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24gTWVya2V6aSAtIEthbXUgU00xNjA0 +BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRpZmlrYXNpIC0gU3Vy +dW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYDVQQG +EwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXll +IEJpbGltc2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklU +QUsxLTArBgNVBAsTJEthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBT +TTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11IFNNIFNTTCBLb2sgU2VydGlmaWthc2kg +LSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr3UwM6q7 +a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y86Ij5iySr +LqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INr +N3wcwv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2X +YacQuFWQfw4tJzh03+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/ +iSIzL+aFCr2lqBs23tPcLG07xxO9WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4f +AJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQUZT/HiobGPN08VFw1+DrtUgxH +V8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL +BQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh +AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPf +IPP54+M638yclNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4 +lzwDGrpDxpa5RXI4s6ehlj2Re37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c +8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0jq5Rm+K37DwhuJi1/FwcJsoz7UMCf +lo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM= +-----END CERTIFICATE----- + +# Issuer: CN=GDCA TrustAUTH R5 ROOT O=GUANG DONG CERTIFICATE AUTHORITY CO.,LTD. +# Subject: CN=GDCA TrustAUTH R5 ROOT O=GUANG DONG CERTIFICATE AUTHORITY CO.,LTD. +# Label: "GDCA TrustAUTH R5 ROOT" +# Serial: 9009899650740120186 +# MD5 Fingerprint: 63:cc:d9:3d:34:35:5c:6f:53:a3:e2:08:70:48:1f:b4 +# SHA1 Fingerprint: 0f:36:38:5b:81:1a:25:c3:9b:31:4e:83:ca:e9:34:66:70:cc:74:b4 +# SHA256 Fingerprint: bf:ff:8f:d0:44:33:48:7d:6a:8a:a6:0c:1a:29:76:7a:9f:c2:bb:b0:5e:42:0f:71:3a:13:b9:92:89:1d:38:93 +-----BEGIN CERTIFICATE----- +MIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE +BhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ +IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0 +MTEyNjA1MTMxNVoXDTQwMTIzMTE1NTk1OVowYjELMAkGA1UEBhMCQ04xMjAwBgNV +BAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMR8w +HQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMIICIjANBgkqhkiG9w0BAQEF +AAOCAg8AMIICCgKCAgEA2aMW8Mh0dHeb7zMNOwZ+Vfy1YI92hhJCfVZmPoiC7XJj +Dp6L3TQsAlFRwxn9WVSEyfFrs0yw6ehGXTjGoqcuEVe6ghWinI9tsJlKCvLriXBj +TnnEt1u9ol2x8kECK62pOqPseQrsXzrj/e+APK00mxqriCZ7VqKChh/rNYmDf1+u +KU49tm7srsHwJ5uu4/Ts765/94Y9cnrrpftZTqfrlYwiOXnhLQiPzLyRuEH3FMEj +qcOtmkVEs7LXLM3GKeJQEK5cy4KOFxg2fZfmiJqwTTQJ9Cy5WmYqsBebnh52nUpm +MUHfP/vFBu8btn4aRjb3ZGM74zkYI+dndRTVdVeSN72+ahsmUPI2JgaQxXABZG12 +ZuGR224HwGGALrIuL4xwp9E7PLOR5G62xDtw8mySlwnNR30YwPO7ng/Wi64HtloP +zgsMR6flPri9fcebNaBhlzpBdRfMK5Z3KpIhHtmVdiBnaM8Nvd/WHwlqmuLMc3Gk +L30SgLdTMEZeS1SZD2fJpcjyIMGC7J0R38IC+xo70e0gmu9lZJIQDSri3nDxGGeC +jGHeuLzRL5z7D9Ar7Rt2ueQ5Vfj4oR24qoAATILnsn8JuLwwoC8N9VKejveSswoA +HQBUlwbgsQfZxw9cZX08bVlX5O2ljelAU58VS6Bx9hoh49pwBiFYFIeFd3mqgnkC +AwEAAaNCMEAwHQYDVR0OBBYEFOLJQJ9NzuiaoXzPDj9lxSmIahlRMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDRSVfg +p8xoWLoBDysZzY2wYUWsEe1jUGn4H3++Fo/9nesLqjJHdtJnJO29fDMylyrHBYZm +DRd9FBUb1Ov9H5r2XpdptxolpAqzkT9fNqyL7FeoPueBihhXOYV0GkLH6VsTX4/5 +COmSdI31R9KrO9b7eGZONn356ZLpBN79SWP8bfsUcZNnL0dKt7n/HipzcEYwv1ry +L3ml4Y0M2fmyYzeMN2WFcGpcWwlyua1jPLHd+PwyvzeG5LuOmCd+uh8W4XAR8gPf +JWIyJyYYMoSf/wA6E7qaTfRPuBRwIrHKK5DOKcFw9C+df/KQHtZa37dG/OaG+svg +IHZ6uqbL9XzeYqWxi+7egmaKTjowHz+Ay60nugxe19CxVsp3cbK1daFQqUBDF8Io +2c9Si1vIY9RCPqAzekYu9wogRlR+ak8x8YF+QnQ4ZXMn7sZ8uI7XpTrXmKGcjBBV +09tL7ECQ8s1uV9JiDnxXk7Gnbc2dg7sq5+W2O3FYrf3RRbxake5TFW/TRQl1brqQ +XR4EzzffHqhmsYzmIGrv/EhOdJhCrylvLmrH+33RZjEizIYAfmaDDEL0vTSSwxrq +T8p+ck0LcIymSLumoRT2+1hEmRSuqguTaaApJUqlyyvdimYHFngVV3Eb7PVHhPOe +MTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g== +-----END CERTIFICATE----- + +# Issuer: CN=TrustCor RootCert CA-1 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority +# Subject: CN=TrustCor RootCert CA-1 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority +# Label: "TrustCor RootCert CA-1" +# Serial: 15752444095811006489 +# MD5 Fingerprint: 6e:85:f1:dc:1a:00:d3:22:d5:b2:b2:ac:6b:37:05:45 +# SHA1 Fingerprint: ff:bd:cd:e7:82:c8:43:5e:3c:6f:26:86:5c:ca:a8:3a:45:5b:c3:0a +# SHA256 Fingerprint: d4:0e:9c:86:cd:8f:e4:68:c1:77:69:59:f4:9e:a7:74:fa:54:86:84:b6:c4:06:f3:90:92:61:f4:dc:e2:57:5c +-----BEGIN CERTIFICATE----- +MIIEMDCCAxigAwIBAgIJANqb7HHzA7AZMA0GCSqGSIb3DQEBCwUAMIGkMQswCQYD +VQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEk +MCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U +cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRydXN0Q29y +IFJvb3RDZXJ0IENBLTEwHhcNMTYwMjA0MTIzMjE2WhcNMjkxMjMxMTcyMzE2WjCB +pDELMAkGA1UEBhMCUEExDzANBgNVBAgMBlBhbmFtYTEUMBIGA1UEBwwLUGFuYW1h +IENpdHkxJDAiBgNVBAoMG1RydXN0Q29yIFN5c3RlbXMgUy4gZGUgUi5MLjEnMCUG +A1UECwweVHJ1c3RDb3IgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MR8wHQYDVQQDDBZU +cnVzdENvciBSb290Q2VydCBDQS0xMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB +CgKCAQEAv463leLCJhJrMxnHQFgKq1mqjQCj/IDHUHuO1CAmujIS2CNUSSUQIpid +RtLByZ5OGy4sDjjzGiVoHKZaBeYei0i/mJZ0PmnK6bV4pQa81QBeCQryJ3pS/C3V +seq0iWEk8xoT26nPUu0MJLq5nux+AHT6k61sKZKuUbS701e/s/OojZz0JEsq1pme +9J7+wH5COucLlVPat2gOkEz7cD+PSiyU8ybdY2mplNgQTsVHCJCZGxdNuWxu72CV +EY4hgLW9oHPY0LJ3xEXqWib7ZnZ2+AYfYW0PVcWDtxBWcgYHpfOxGgMFZA6dWorW +hnAbJN7+KIor0Gqw/Hqi3LJ5DotlDwIDAQABo2MwYTAdBgNVHQ4EFgQU7mtJPHo/ +DeOxCbeKyKsZn3MzUOcwHwYDVR0jBBgwFoAU7mtJPHo/DeOxCbeKyKsZn3MzUOcw +DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQAD +ggEBACUY1JGPE+6PHh0RU9otRCkZoB5rMZ5NDp6tPVxBb5UrJKF5mDo4Nvu7Zp5I +/5CQ7z3UuJu0h3U/IJvOcs+hVcFNZKIZBqEHMwwLKeXx6quj7LUKdJDHfXLy11yf +ke+Ri7fc7Waiz45mO7yfOgLgJ90WmMCV1Aqk5IGadZQ1nJBfiDcGrVmVCrDRZ9MZ +yonnMlo2HD6CqFqTvsbQZJG2z9m2GM/bftJlo6bEjhcxwft+dtvTheNYsnd6djts +L1Ac59v2Z3kf9YKVmgenFK+P3CghZwnS1k1aHBkcjndcw5QkPTJrS37UeJSDvjdN +zl/HHk484IkzlQsPpTLWPFp5LBk= +-----END CERTIFICATE----- + +# Issuer: CN=TrustCor RootCert CA-2 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority +# Subject: CN=TrustCor RootCert CA-2 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority +# Label: "TrustCor RootCert CA-2" +# Serial: 2711694510199101698 +# MD5 Fingerprint: a2:e1:f8:18:0b:ba:45:d5:c7:41:2a:bb:37:52:45:64 +# SHA1 Fingerprint: b8:be:6d:cb:56:f1:55:b9:63:d4:12:ca:4e:06:34:c7:94:b2:1c:c0 +# SHA256 Fingerprint: 07:53:e9:40:37:8c:1b:d5:e3:83:6e:39:5d:ae:a5:cb:83:9e:50:46:f1:bd:0e:ae:19:51:cf:10:fe:c7:c9:65 +-----BEGIN CERTIFICATE----- +MIIGLzCCBBegAwIBAgIIJaHfyjPLWQIwDQYJKoZIhvcNAQELBQAwgaQxCzAJBgNV +BAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQw +IgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRy +dXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0eTEfMB0GA1UEAwwWVHJ1c3RDb3Ig +Um9vdENlcnQgQ0EtMjAeFw0xNjAyMDQxMjMyMjNaFw0zNDEyMzExNzI2MzlaMIGk +MQswCQYDVQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEg +Q2l0eTEkMCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYD +VQQLDB5UcnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRy +dXN0Q29yIFJvb3RDZXJ0IENBLTIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK +AoICAQCnIG7CKqJiJJWQdsg4foDSq8GbZQWU9MEKENUCrO2fk8eHyLAnK0IMPQo+ +QVqedd2NyuCb7GgypGmSaIwLgQ5WoD4a3SwlFIIvl9NkRvRUqdw6VC0xK5mC8tkq +1+9xALgxpL56JAfDQiDyitSSBBtlVkxs1Pu2YVpHI7TYabS3OtB0PAx1oYxOdqHp +2yqlO/rOsP9+aij9JxzIsekp8VduZLTQwRVtDr4uDkbIXvRR/u8OYzo7cbrPb1nK +DOObXUm4TOJXsZiKQlecdu/vvdFoqNL0Cbt3Nb4lggjEFixEIFapRBF37120Hape +az6LMvYHL1cEksr1/p3C6eizjkxLAjHZ5DxIgif3GIJ2SDpxsROhOdUuxTTCHWKF +3wP+TfSvPd9cW436cOGlfifHhi5qjxLGhF5DUVCcGZt45vz27Ud+ez1m7xMTiF88 +oWP7+ayHNZ/zgp6kPwqcMWmLmaSISo5uZk3vFsQPeSghYA2FFn3XVDjxklb9tTNM +g9zXEJ9L/cb4Qr26fHMC4P99zVvh1Kxhe1fVSntb1IVYJ12/+CtgrKAmrhQhJ8Z3 +mjOAPF5GP/fDsaOGM8boXg25NSyqRsGFAnWAoOsk+xWq5Gd/bnc/9ASKL3x74xdh +8N0JqSDIvgmk0H5Ew7IwSjiqqewYmgeCK9u4nBit2uBGF6zPXQIDAQABo2MwYTAd +BgNVHQ4EFgQU2f4hQG6UnrybPZx9mCAZ5YwwYrIwHwYDVR0jBBgwFoAU2f4hQG6U +nrybPZx9mCAZ5YwwYrIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYw +DQYJKoZIhvcNAQELBQADggIBAJ5Fngw7tu/hOsh80QA9z+LqBrWyOrsGS2h60COX +dKcs8AjYeVrXWoSK2BKaG9l9XE1wxaX5q+WjiYndAfrs3fnpkpfbsEZC89NiqpX+ +MWcUaViQCqoL7jcjx1BRtPV+nuN79+TMQjItSQzL/0kMmx40/W5ulop5A7Zv2wnL +/V9lFDfhOPXzYRZY5LVtDQsEGz9QLX+zx3oaFoBg+Iof6Rsqxvm6ARppv9JYx1RX +CI/hOWB3S6xZhBqI8d3LT3jX5+EzLfzuQfogsL7L9ziUwOHQhQ+77Sxzq+3+knYa +ZH9bDTMJBzN7Bj8RpFxwPIXAz+OQqIN3+tvmxYxoZxBnpVIt8MSZj3+/0WvitUfW +2dCFmU2Umw9Lje4AWkcdEQOsQRivh7dvDDqPys/cA8GiCcjl/YBeyGBCARsaU1q7 +N6a3vLqE6R5sGtRk2tRD/pOLS/IseRYQ1JMLiI+h2IYURpFHmygk71dSTlxCnKr3 +Sewn6EAes6aJInKc9Q0ztFijMDvd1GpUk74aTfOTlPf8hAs/hCBcNANExdqtvArB +As8e5ZTZ845b2EzwnexhF7sUMlQMAimTHpKG9n/v55IFDlndmQguLvqcAFLTxWYp +5KeXRKQOKIETNcX2b2TmQcTVL8w0RSXPQQCWPUouwpaYT05KnJe32x+SMsj/D1Fu +1uwJ +-----END CERTIFICATE----- + +# Issuer: CN=TrustCor ECA-1 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority +# Subject: CN=TrustCor ECA-1 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority +# Label: "TrustCor ECA-1" +# Serial: 9548242946988625984 +# MD5 Fingerprint: 27:92:23:1d:0a:f5:40:7c:e9:e6:6b:9d:d8:f5:e7:6c +# SHA1 Fingerprint: 58:d1:df:95:95:67:6b:63:c0:f0:5b:1c:17:4d:8b:84:0b:c8:78:bd +# SHA256 Fingerprint: 5a:88:5d:b1:9c:01:d9:12:c5:75:93:88:93:8c:af:bb:df:03:1a:b2:d4:8e:91:ee:15:58:9b:42:97:1d:03:9c +-----BEGIN CERTIFICATE----- +MIIEIDCCAwigAwIBAgIJAISCLF8cYtBAMA0GCSqGSIb3DQEBCwUAMIGcMQswCQYD +VQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEk +MCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U +cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxFzAVBgNVBAMMDlRydXN0Q29y +IEVDQS0xMB4XDTE2MDIwNDEyMzIzM1oXDTI5MTIzMTE3MjgwN1owgZwxCzAJBgNV +BAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQw +IgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRy +dXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0eTEXMBUGA1UEAwwOVHJ1c3RDb3Ig +RUNBLTEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPj+ARtZ+odnbb +3w9U73NjKYKtR8aja+3+XzP4Q1HpGjORMRegdMTUpwHmspI+ap3tDvl0mEDTPwOA +BoJA6LHip1GnHYMma6ve+heRK9jGrB6xnhkB1Zem6g23xFUfJ3zSCNV2HykVh0A5 +3ThFEXXQmqc04L/NyFIduUd+Dbi7xgz2c1cWWn5DkR9VOsZtRASqnKmcp0yJF4Ou +owReUoCLHhIlERnXDH19MURB6tuvsBzvgdAsxZohmz3tQjtQJvLsznFhBmIhVE5/ +wZ0+fyCMgMsq2JdiyIMzkX2woloPV+g7zPIlstR8L+xNxqE6FXrntl019fZISjZF +ZtS6mFjBAgMBAAGjYzBhMB0GA1UdDgQWBBREnkj1zG1I1KBLf/5ZJC+Dl5mahjAf +BgNVHSMEGDAWgBREnkj1zG1I1KBLf/5ZJC+Dl5mahjAPBgNVHRMBAf8EBTADAQH/ +MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAQEABT41XBVwm8nHc2Fv +civUwo/yQ10CzsSUuZQRg2dd4mdsdXa/uwyqNsatR5Nj3B5+1t4u/ukZMjgDfxT2 +AHMsWbEhBuH7rBiVDKP/mZb3Kyeb1STMHd3BOuCYRLDE5D53sXOpZCz2HAF8P11F +hcCF5yWPldwX8zyfGm6wyuMdKulMY/okYWLW2n62HGz1Ah3UKt1VkOsqEUc8Ll50 +soIipX1TH0XsJ5F95yIW6MBoNtjG8U+ARDL54dHRHareqKucBK+tIA5kmE2la8BI +WJZpTdwHjFGTot+fDz2LYLSCjaoITmJF4PkL0uDgPFveXHEnJcLmA4GLEFPjx1Wi +tJ/X5g== +-----END CERTIFICATE----- + +# Issuer: CN=SSL.com Root Certification Authority RSA O=SSL Corporation +# Subject: CN=SSL.com Root Certification Authority RSA O=SSL Corporation +# Label: "SSL.com Root Certification Authority RSA" +# Serial: 8875640296558310041 +# MD5 Fingerprint: 86:69:12:c0:70:f1:ec:ac:ac:c2:d5:bc:a5:5b:a1:29 +# SHA1 Fingerprint: b7:ab:33:08:d1:ea:44:77:ba:14:80:12:5a:6f:bd:a9:36:49:0c:bb +# SHA256 Fingerprint: 85:66:6a:56:2e:e0:be:5c:e9:25:c1:d8:89:0a:6f:76:a8:7e:c1:6d:4d:7d:5f:29:ea:74:19:cf:20:12:3b:69 +-----BEGIN CERTIFICATE----- +MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE +BhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQK +DA9TU0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYwMjEyMTczOTM5WhcNNDEwMjEyMTcz +OTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv +dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv +bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcN +AQEBBQADggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2R +xFdHaxh3a3by/ZPkPQ/CFp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aX +qhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcC +C52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/geoeOy3ZExqysdBP+lSgQ3 +6YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkpk8zruFvh +/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrF +YD3ZfBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93E +JNyAKoFBbZQ+yODJgUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVc +US4cK38acijnALXRdMbX5J+tB5O2UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8 +ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi81xtZPCvM8hnIk2snYxnP/Okm ++Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4sbE6x/c+cCbqi +M+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV +HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4G +A1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGV +cpNxJK1ok1iOMq8bs3AD/CUrdIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBc +Hadm47GUBwwyOabqG7B52B2ccETjit3E+ZUfijhDPwGFpUenPUayvOUiaPd7nNgs +PgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAslu1OJD7OAUN5F7kR/ +q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjqerQ0 +cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jr +a6x+3uxjMxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90I +H37hVZkLId6Tngr75qNJvTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/Y +K9f1JmzJBjSWFupwWRoyeXkLtoh/D1JIPb9s2KJELtFOt3JY04kTlf5Eq/jXixtu +nLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406ywKBjYZC6VWg3dGq2ktuf +oYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NIWuuA8ShY +Ic2wBlX7Jz9TkHCpBB5XJ7k= +-----END CERTIFICATE----- + +# Issuer: CN=SSL.com Root Certification Authority ECC O=SSL Corporation +# Subject: CN=SSL.com Root Certification Authority ECC O=SSL Corporation +# Label: "SSL.com Root Certification Authority ECC" +# Serial: 8495723813297216424 +# MD5 Fingerprint: 2e:da:e4:39:7f:9c:8f:37:d1:70:9f:26:17:51:3a:8e +# SHA1 Fingerprint: c3:19:7c:39:24:e6:54:af:1b:c4:ab:20:95:7a:e2:c3:0e:13:02:6a +# SHA256 Fingerprint: 34:17:bb:06:cc:60:07:da:1b:96:1c:92:0b:8a:b4:ce:3f:ad:82:0e:4a:a3:0b:9a:cb:c4:a7:4e:bd:ce:bc:65 +-----BEGIN CERTIFICATE----- +MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMC +VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T +U0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0 +aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNDAzWhcNNDEwMjEyMTgxNDAz +WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0 +b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBS +b290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB +BAAiA2IABEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI +7Z4INcgn64mMU1jrYor+8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPg +CemB+vNH06NjMGEwHQYDVR0OBBYEFILRhXMw5zUE044CkvvlpNHEIejNMA8GA1Ud +EwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTTjgKS++Wk0cQh6M0wDgYD +VR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCWe+0F+S8T +kdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+ +gA0z5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl +-----END CERTIFICATE----- + +# Issuer: CN=SSL.com EV Root Certification Authority RSA R2 O=SSL Corporation +# Subject: CN=SSL.com EV Root Certification Authority RSA R2 O=SSL Corporation +# Label: "SSL.com EV Root Certification Authority RSA R2" +# Serial: 6248227494352943350 +# MD5 Fingerprint: e1:1e:31:58:1a:ae:54:53:02:f6:17:6a:11:7b:4d:95 +# SHA1 Fingerprint: 74:3a:f0:52:9b:d0:32:a0:f4:4a:83:cd:d4:ba:a9:7b:7c:2e:c4:9a +# SHA256 Fingerprint: 2e:7b:f1:6c:c2:24:85:a7:bb:e2:aa:86:96:75:07:61:b0:ae:39:be:3b:2f:e9:d0:cc:6d:4e:f7:34:91:42:5c +-----BEGIN CERTIFICATE----- +MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNV +BAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UE +CgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2Vy +dGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMB4XDTE3MDUzMTE4MTQzN1oXDTQy +MDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4G +A1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQD +DC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvq +M0fNTPl9fb69LT3w23jhhqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssuf +OePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7wcXHswxzpY6IXFJ3vG2fThVUCAtZJycxa +4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTOZw+oz12WGQvE43LrrdF9 +HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+B6KjBSYR +aZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcA +b9ZhCBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQ +Gp8hLH94t2S42Oim9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQV +PWKchjgGAGYS5Fl2WlPAApiiECtoRHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMO +pgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+SlmJuwgUHfbSguPvuUCYHBBXtSu +UDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48+qvWBkofZ6aY +MBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV +HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa4 +9QaAJadz20ZpqJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBW +s47LCp1Jjr+kxJG7ZhcFUZh1++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5 +Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nxY/hoLVUE0fKNsKTPvDxeH3jnpaAg +cLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2GguDKBAdRUNf/ktUM +79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDzOFSz +/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXt +ll9ldDz7CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEm +Kf7GUmG6sXP/wwyc5WxqlD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKK +QbNmC1r7fSOl8hqw/96bg5Qu0T/fkreRrwU7ZcegbLHNYhLDkBvjJc40vG93drEQ +w/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1hlMYegouCRw2n5H9gooi +S9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX9hwJ1C07 +mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w== +-----END CERTIFICATE----- + +# Issuer: CN=SSL.com EV Root Certification Authority ECC O=SSL Corporation +# Subject: CN=SSL.com EV Root Certification Authority ECC O=SSL Corporation +# Label: "SSL.com EV Root Certification Authority ECC" +# Serial: 3182246526754555285 +# MD5 Fingerprint: 59:53:22:65:83:42:01:54:c0:ce:42:b9:5a:7c:f2:90 +# SHA1 Fingerprint: 4c:dd:51:a3:d1:f5:20:32:14:b0:c6:c5:32:23:03:91:c7:46:42:6d +# SHA256 Fingerprint: 22:a2:c1:f7:bd:ed:70:4c:c1:e7:01:b5:f4:08:c3:10:88:0f:e9:56:b5:de:2a:4a:44:f9:9c:87:3a:25:a7:c8 +-----BEGIN CERTIFICATE----- +MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMC +VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T +U0wgQ29ycG9yYXRpb24xNDAyBgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNTIzWhcNNDEwMjEyMTgx +NTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv +dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NMLmNv +bSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49 +AgEGBSuBBAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMA +VIbc/R/fALhBYlzccBYy3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1Kthku +WnBaBu2+8KGwytAJKaNjMGEwHQYDVR0OBBYEFFvKXuXe0oGqzagtZFG22XKbl+ZP +MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe5d7SgarNqC1kUbbZcpuX +5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJN+vp1RPZ +ytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZg +h5Mmm7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg== +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R6 +# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R6 +# Label: "GlobalSign Root CA - R6" +# Serial: 1417766617973444989252670301619537 +# MD5 Fingerprint: 4f:dd:07:e4:d4:22:64:39:1e:0c:37:42:ea:d1:c6:ae +# SHA1 Fingerprint: 80:94:64:0e:b5:a7:a1:ca:11:9c:1f:dd:d5:9f:81:02:63:a7:fb:d1 +# SHA256 Fingerprint: 2c:ab:ea:fe:37:d0:6c:a2:2a:ba:73:91:c0:03:3d:25:98:29:52:c4:53:64:73:49:76:3a:3a:b5:ad:6c:cf:69 +-----BEGIN CERTIFICATE----- +MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEg +MB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2Jh +bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQx +MjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSNjET +MBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCAiIwDQYJ +KoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQssgrRI +xutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1k +ZguSgMpE3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxD +aNc9PIrFsmbVkJq3MQbFvuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJw +LnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqMPKq0pPbzlUoSB239jLKJz9CgYXfIWHSw +1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+azayOeSsJDa38O+2HBNX +k7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05OWgtH8wY2 +SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/h +bguyCLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4n +WUx2OVvq+aWh2IMP0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpY +rZxCRXluDocZXFSxZba/jJvcE+kNb7gu3GduyYsRtYQUigAZcIN5kZeR1Bonvzce +MgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTAD +AQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNVHSMEGDAWgBSu +bAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN +nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGt +Ixg93eFyRJa0lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr61 +55wsTLxDKZmOMNOsIeDjHfrYBzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLj +vUYAGm0CuiVdjaExUd1URhxN25mW7xocBFymFe944Hn+Xds+qkxV/ZoVqW/hpvvf +cDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr3TsTjxKM4kEaSHpz +oHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB10jZp +nOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfs +pA9MRf/TuTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+v +JJUEeKgDu+6B5dpffItKoZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R +8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+tJDfLRVpOoERIyNiwmcUVhAn21klJwGW4 +5hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA= +-----END CERTIFICATE----- + +# Issuer: CN=OISTE WISeKey Global Root GC CA O=WISeKey OU=OISTE Foundation Endorsed +# Subject: CN=OISTE WISeKey Global Root GC CA O=WISeKey OU=OISTE Foundation Endorsed +# Label: "OISTE WISeKey Global Root GC CA" +# Serial: 44084345621038548146064804565436152554 +# MD5 Fingerprint: a9:d6:b9:2d:2f:93:64:f8:a5:69:ca:91:e9:68:07:23 +# SHA1 Fingerprint: e0:11:84:5e:34:de:be:88:81:b9:9c:f6:16:26:d1:96:1f:c3:b9:31 +# SHA256 Fingerprint: 85:60:f9:1c:36:24:da:ba:95:70:b5:fe:a0:db:e3:6f:f1:1a:83:23:be:94:86:85:4f:b3:f3:4a:55:71:19:8d +-----BEGIN CERTIFICATE----- +MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQsw +CQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91 +bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwg +Um9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRaFw00MjA1MDkwOTU4MzNaMG0xCzAJ +BgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBGb3Vu +ZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2JhbCBS +b290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4ni +eUqjFqdrVCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4W +p2OQ0jnUsYd4XxiWD1AbNTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7T +rYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0EAwMDaAAwZQIwJsdpW9zV +57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtkAjEA2zQg +Mgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9 +-----END CERTIFICATE----- + +# Issuer: CN=GTS Root R1 O=Google Trust Services LLC +# Subject: CN=GTS Root R1 O=Google Trust Services LLC +# Label: "GTS Root R1" +# Serial: 146587175971765017618439757810265552097 +# MD5 Fingerprint: 82:1a:ef:d4:d2:4a:f2:9f:e2:3d:97:06:14:70:72:85 +# SHA1 Fingerprint: e1:c9:50:e6:ef:22:f8:4c:56:45:72:8b:92:20:60:d7:d5:a7:a3:e8 +# SHA256 Fingerprint: 2a:57:54:71:e3:13:40:bc:21:58:1c:bd:2c:f1:3e:15:84:63:20:3e:ce:94:bc:f9:d3:cc:19:6b:f0:9a:54:72 +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgIQbkepxUtHDA3sM9CJuRz04TANBgkqhkiG9w0BAQwFADBH +MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM +QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy +MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl +cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaM +f/vo27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vX +mX7wCl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7 +zUjwTcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0P +fyblqAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtc +vfaHszVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4 +Zor8Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUsp +zBmkMiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOO +Rc92wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYW +k70paDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+ +DVrNVjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgF +lQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBADiW +Cu49tJYeX++dnAsznyvgyv3SjgofQXSlfKqE1OXyHuY3UjKcC9FhHb8owbZEKTV1 +d5iyfNm9dKyKaOOpMQkpAWBz40d8U6iQSifvS9efk+eCNs6aaAyC58/UEBZvXw6Z +XPYfcX3v73svfuo21pdwCxXu11xWajOl40k4DLh9+42FpLFZXvRq4d2h9mREruZR +gyFmxhE+885H7pwoHyXa/6xmld01D1zvICxi/ZG6qcz8WpyTgYMpl0p8WnK0OdC3 +d8t5/Wk6kjftbjhlRn7pYL15iJdfOBL07q9bgsiG1eGZbYwE8na6SfZu6W0eX6Dv +J4J2QPim01hcDyxC2kLGe4g0x8HYRZvBPsVhHdljUEn2NIVq4BjFbkerQUIpm/Zg +DdIx02OYI5NaAIFItO/Nis3Jz5nu2Z6qNuFoS3FJFDYoOj0dzpqPJeaAcWErtXvM ++SUWgeExX6GjfhaknBZqlxi9dnKlC54dNuYvoS++cJEPqOba+MSSQGwlfnuzCdyy +F62ARPBopY+Udf90WuioAnwMCeKpSwughQtiue+hMZL77/ZRBIls6Kl0obsXs7X9 +SQ98POyDGCBDTtWTurQ0sR8WNh8M5mQ5Fkzc4P4dyKliPUDqysU0ArSuiYgzNdws +E3PYJ/HQcu51OyLemGhmW/HGY0dVHLqlCFF1pkgl +-----END CERTIFICATE----- + +# Issuer: CN=GTS Root R2 O=Google Trust Services LLC +# Subject: CN=GTS Root R2 O=Google Trust Services LLC +# Label: "GTS Root R2" +# Serial: 146587176055767053814479386953112547951 +# MD5 Fingerprint: 44:ed:9a:0e:a4:09:3b:00:f2:ae:4c:a3:c6:61:b0:8b +# SHA1 Fingerprint: d2:73:96:2a:2a:5e:39:9f:73:3f:e1:c7:1e:64:3f:03:38:34:fc:4d +# SHA256 Fingerprint: c4:5d:7b:b0:8e:6d:67:e6:2e:42:35:11:0b:56:4e:5f:78:fd:92:ef:05:8c:84:0a:ea:4e:64:55:d7:58:5c:60 +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgIQbkepxlqz5yDFMJo/aFLybzANBgkqhkiG9w0BAQwFADBH +MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM +QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy +MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl +cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3Lv +CvptnfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3Kg +GjSY6Dlo7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9Bu +XvAuMC6C/Pq8tBcKSOWIm8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOd +re7kRXuJVfeKH2JShBKzwkCX44ofR5GmdFrS+LFjKBC4swm4VndAoiaYecb+3yXu +PuWgf9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7MkogwTZq9TwtImoS1 +mKPV+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJGr61K +8YzodDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqj +x5RWIr9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsR +nTKaG73VululycslaVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0 +kzCqgc7dGtxRcw1PcOnlthYhGXmy5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9Ok +twIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQADggIBALZp +8KZ3/p7uC4Gt4cCpx/k1HUCCq+YEtN/L9x0Pg/B+E02NjO7jMyLDOfxA325BS0JT +vhaI8dI4XsRomRyYUpOM52jtG2pzegVATX9lO9ZY8c6DR2Dj/5epnGB3GFW1fgiT +z9D2PGcDFWEJ+YF59exTpJ/JjwGLc8R3dtyDovUMSRqodt6Sm2T4syzFJ9MHwAiA +pJiS4wGWAqoC7o87xdFtCjMwc3i5T1QWvwsHoaRc5svJXISPD+AVdyx+Jn7axEvb +pxZ3B7DNdehyQtaVhJ2Gg/LkkM0JR9SLA3DaWsYDQvTtN6LwG1BUSw7YhN4ZKJmB +R64JGz9I0cNv4rBgF/XuIwKl2gBbbZCr7qLpGzvpx0QnRY5rn/WkhLx3+WuXrD5R +RaIRpsyF7gpo8j5QOHokYh4XIDdtak23CZvJ/KRY9bb7nE4Yu5UC56GtmwfuNmsk +0jmGwZODUNKBRqhfYlcsu2xkiAhu7xNUX90txGdj08+JN7+dIPT7eoOboB6BAFDC +5AwiWVIQ7UNWhwD4FFKnHYuTjKJNRn8nxnGbJN7k2oaLDX5rIMHAnuFl2GqjpuiF +izoHCBy69Y9Vmhh1fuXsgWbRIXOhNUQLgD1bnF5vKheW0YMjiGZt5obicDIvUiLn +yOd/xCxgXS/Dr55FBcOEArf9LAhST4Ldo/DUhgkC +-----END CERTIFICATE----- + +# Issuer: CN=GTS Root R3 O=Google Trust Services LLC +# Subject: CN=GTS Root R3 O=Google Trust Services LLC +# Label: "GTS Root R3" +# Serial: 146587176140553309517047991083707763997 +# MD5 Fingerprint: 1a:79:5b:6b:04:52:9c:5d:c7:74:33:1b:25:9a:f9:25 +# SHA1 Fingerprint: 30:d4:24:6f:07:ff:db:91:89:8a:0b:e9:49:66:11:eb:8c:5e:46:e5 +# SHA256 Fingerprint: 15:d5:b8:77:46:19:ea:7d:54:ce:1c:a6:d0:b0:c4:03:e0:37:a9:17:f1:31:e8:a0:4e:1e:6b:7a:71:ba:bc:e5 +-----BEGIN CERTIFICATE----- +MIICDDCCAZGgAwIBAgIQbkepx2ypcyRAiQ8DVd2NHTAKBggqhkjOPQQDAzBHMQsw +CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU +MBIGA1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw +MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp +Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout +736GjOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2A +DDL24CejQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud +DgQWBBTB8Sa6oC2uhYHP0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEAgFuk +fCPAlaUs3L6JbyO5o91lAFJekazInXJ0glMLfalAvWhgxeG4VDvBNhcl2MG9AjEA +njWSdIUlUfUk7GRSJFClH9voy8l27OyCbvWFGFPouOOaKaqW04MjyaR7YbPMAuhd +-----END CERTIFICATE----- + +# Issuer: CN=GTS Root R4 O=Google Trust Services LLC +# Subject: CN=GTS Root R4 O=Google Trust Services LLC +# Label: "GTS Root R4" +# Serial: 146587176229350439916519468929765261721 +# MD5 Fingerprint: 5d:b6:6a:c4:60:17:24:6a:1a:99:a8:4b:ee:5e:b4:26 +# SHA1 Fingerprint: 2a:1d:60:27:d9:4a:b1:0a:1c:4d:91:5c:cd:33:a0:cb:3e:2d:54:cb +# SHA256 Fingerprint: 71:cc:a5:39:1f:9e:79:4b:04:80:25:30:b3:63:e1:21:da:8a:30:43:bb:26:66:2f:ea:4d:ca:7f:c9:51:a4:bd +-----BEGIN CERTIFICATE----- +MIICCjCCAZGgAwIBAgIQbkepyIuUtui7OyrYorLBmTAKBggqhkjOPQQDAzBHMQsw +CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU +MBIGA1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw +MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp +Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzu +hXyiQHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/l +xKvRHYqjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud +DgQWBBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNnADBkAjBqUFJ0 +CMRw3J5QdCHojXohw0+WbhXRIjVhLfoIN+4Zba3bssx9BzT1YBkstTTZbyACMANx +sbqjYAuG7ZoIapVon+Kz4ZNkfF6Tpt95LY2F45TPI11xzPKwTdb+mciUqXWi4w== +-----END CERTIFICATE----- + +# Issuer: CN=UCA Global G2 Root O=UniTrust +# Subject: CN=UCA Global G2 Root O=UniTrust +# Label: "UCA Global G2 Root" +# Serial: 124779693093741543919145257850076631279 +# MD5 Fingerprint: 80:fe:f0:c4:4a:f0:5c:62:32:9f:1c:ba:78:a9:50:f8 +# SHA1 Fingerprint: 28:f9:78:16:19:7a:ff:18:25:18:aa:44:fe:c1:a0:ce:5c:b6:4c:8a +# SHA256 Fingerprint: 9b:ea:11:c9:76:fe:01:47:64:c1:be:56:a6:f9:14:b5:a5:60:31:7a:bd:99:88:39:33:82:e5:16:1a:a0:49:3c +-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIQXd+x2lqj7V2+WmUgZQOQ7zANBgkqhkiG9w0BAQsFADA9 +MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBH +bG9iYWwgRzIgUm9vdDAeFw0xNjAzMTEwMDAwMDBaFw00MDEyMzEwMDAwMDBaMD0x +CzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlUcnVzdDEbMBkGA1UEAwwSVUNBIEds +b2JhbCBHMiBSb290MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxeYr +b3zvJgUno4Ek2m/LAfmZmqkywiKHYUGRO8vDaBsGxUypK8FnFyIdK+35KYmToni9 +kmugow2ifsqTs6bRjDXVdfkX9s9FxeV67HeToI8jrg4aA3++1NDtLnurRiNb/yzm +VHqUwCoV8MmNsHo7JOHXaOIxPAYzRrZUEaalLyJUKlgNAQLx+hVRZ2zA+te2G3/R +VogvGjqNO7uCEeBHANBSh6v7hn4PJGtAnTRnvI3HLYZveT6OqTwXS3+wmeOwcWDc +C/Vkw85DvG1xudLeJ1uK6NjGruFZfc8oLTW4lVYa8bJYS7cSN8h8s+1LgOGN+jIj +tm+3SJUIsUROhYw6AlQgL9+/V087OpAh18EmNVQg7Mc/R+zvWr9LesGtOxdQXGLY +D0tK3Cv6brxzks3sx1DoQZbXqX5t2Okdj4q1uViSukqSKwxW/YDrCPBeKW4bHAyv +j5OJrdu9o54hyokZ7N+1wxrrFv54NkzWbtA+FxyQF2smuvt6L78RHBgOLXMDj6Dl +NaBa4kx1HXHhOThTeEDMg5PXCp6dW4+K5OXgSORIskfNTip1KnvyIvbJvgmRlld6 +iIis7nCs+dwp4wwcOxJORNanTrAmyPPZGpeRaOrvjUYG0lZFWJo8DA+DuAUlwznP +O6Q0ibd5Ei9Hxeepl2n8pndntd978XplFeRhVmUCAwEAAaNCMEAwDgYDVR0PAQH/ +BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFIHEjMz15DD/pQwIX4wV +ZyF0Ad/fMA0GCSqGSIb3DQEBCwUAA4ICAQATZSL1jiutROTL/7lo5sOASD0Ee/oj +L3rtNtqyzm325p7lX1iPyzcyochltq44PTUbPrw7tgTQvPlJ9Zv3hcU2tsu8+Mg5 +1eRfB70VVJd0ysrtT7q6ZHafgbiERUlMjW+i67HM0cOU2kTC5uLqGOiiHycFutfl +1qnN3e92mI0ADs0b+gO3joBYDic/UvuUospeZcnWhNq5NXHzJsBPd+aBJ9J3O5oU +b3n09tDh05S60FdRvScFDcH9yBIw7m+NESsIndTUv4BFFJqIRNow6rSn4+7vW4LV +PtateJLbXDzz2K36uGt/xDYotgIVilQsnLAXc47QN6MUPJiVAAwpBVueSUmxX8fj +y88nZY41F7dXyDDZQVu5FLbowg+UMaeUmMxq67XhJ/UQqAHojhJi6IjMtX9Gl8Cb +EGY4GjZGXyJoPd/JxhMnq1MGrKI8hgZlb7F+sSlEmqO6SWkoaY/X5V+tBIZkbxqg +DMUIYs6Ao9Dz7GjevjPHF1t/gMRMTLGmhIrDO7gJzRSBuhjjVFc2/tsvfEehOjPI ++Vg7RE+xygKJBJYoaMVLuCaJu9YzL1DV/pqJuhgyklTGW+Cd+V7lDSKb9triyCGy +YiGqhkCyLmTTX8jjfhFnRR8F/uOi77Oos/N9j/gMHyIfLXC0uAE0djAA5SN4p1bX +UB+K+wb1whnw0A== +-----END CERTIFICATE----- + +# Issuer: CN=UCA Extended Validation Root O=UniTrust +# Subject: CN=UCA Extended Validation Root O=UniTrust +# Label: "UCA Extended Validation Root" +# Serial: 106100277556486529736699587978573607008 +# MD5 Fingerprint: a1:f3:5f:43:c6:34:9b:da:bf:8c:7e:05:53:ad:96:e2 +# SHA1 Fingerprint: a3:a1:b0:6f:24:61:23:4a:e3:36:a5:c2:37:fc:a6:ff:dd:f0:d7:3a +# SHA256 Fingerprint: d4:3a:f9:b3:54:73:75:5c:96:84:fc:06:d7:d8:cb:70:ee:5c:28:e7:73:fb:29:4e:b4:1e:e7:17:22:92:4d:24 +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgIQT9Irj/VkyDOeTzRYZiNwYDANBgkqhkiG9w0BAQsFADBH +MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBF +eHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwHhcNMTUwMzEzMDAwMDAwWhcNMzgxMjMx +MDAwMDAwWjBHMQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNV +BAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCpCQcoEwKwmeBkqh5DFnpzsZGgdT6o+uM4AHrsiWog +D4vFsJszA1qGxliG1cGFu0/GnEBNyr7uaZa4rYEwmnySBesFK5pI0Lh2PpbIILvS +sPGP2KxFRv+qZ2C0d35qHzwaUnoEPQc8hQ2E0B92CvdqFN9y4zR8V05WAT558aop +O2z6+I9tTcg1367r3CTueUWnhbYFiN6IXSV8l2RnCdm/WhUFhvMJHuxYMjMR83dk +sHYf5BA1FxvyDrFspCqjc/wJHx4yGVMR59mzLC52LqGj3n5qiAno8geK+LLNEOfi +c0CTuwjRP+H8C5SzJe98ptfRr5//lpr1kXuYC3fUfugH0mK1lTnj8/FtDw5lhIpj +VMWAtuCeS31HJqcBCF3RiJ7XwzJE+oJKCmhUfzhTA8ykADNkUVkLo4KRel7sFsLz +KuZi2irbWWIQJUoqgQtHB0MGcIfS+pMRKXpITeuUx3BNr2fVUbGAIAEBtHoIppB/ +TuDvB0GHr2qlXov7z1CymlSvw4m6WC31MJixNnI5fkkE/SmnTHnkBVfblLkWU41G +sx2VYVdWf6/wFlthWG82UBEL2KwrlRYaDh8IzTY0ZRBiZtWAXxQgXy0MoHgKaNYs +1+lvK9JKBZP8nm9rZ/+I8U6laUpSNwXqxhaN0sSZ0YIrO7o1dfdRUVjzyAfd5LQD +fwIDAQABo0IwQDAdBgNVHQ4EFgQU2XQ65DA9DfcS3H5aBZ8eNJr34RQwDwYDVR0T +AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBADaN +l8xCFWQpN5smLNb7rhVpLGsaGvdftvkHTFnq88nIua7Mui563MD1sC3AO6+fcAUR +ap8lTwEpcOPlDOHqWnzcSbvBHiqB9RZLcpHIojG5qtr8nR/zXUACE/xOHAbKsxSQ +VBcZEhrxH9cMaVr2cXj0lH2RC47skFSOvG+hTKv8dGT9cZr4QQehzZHkPJrgmzI5 +c6sq1WnIeJEmMX3ixzDx/BR4dxIOE/TdFpS/S2d7cFOFyrC78zhNLJA5wA3CXWvp +4uXViI3WLL+rG761KIcSF3Ru/H38j9CHJrAb+7lsq+KePRXBOy5nAliRn+/4Qh8s +t2j1da3Ptfb/EX3C8CSlrdP6oDyp+l3cpaDvRKS+1ujl5BOWF3sGPjLtx7dCvHaj +2GU4Kzg1USEODm8uNBNA4StnDG1KQTAYI1oyVZnJF+A83vbsea0rWBmirSwiGpWO +vpaQXUJXxPkUAzUrHC1RVwinOt4/5Mi0A3PCwSaAuwtCH60NryZy2sy+s6ODWA2C +xR9GUeOcGMyNm43sSet1UNWMKFnKdDTajAshqx7qG+XH/RU+wBeq+yNuJkbL+vmx +cmtpzyKEC2IPrNkZAJSidjzULZrtBJ4tBmIQN1IchXIbJ+XMxjHsN+xjWZsLHXbM +fjKaiJUINlK73nZfdklJrX+9ZSCyycErdhh2n1ax +-----END CERTIFICATE----- + +# Issuer: CN=Certigna Root CA O=Dhimyotis OU=0002 48146308100036 +# Subject: CN=Certigna Root CA O=Dhimyotis OU=0002 48146308100036 +# Label: "Certigna Root CA" +# Serial: 269714418870597844693661054334862075617 +# MD5 Fingerprint: 0e:5c:30:62:27:eb:5b:bc:d7:ae:62:ba:e9:d5:df:77 +# SHA1 Fingerprint: 2d:0d:52:14:ff:9e:ad:99:24:01:74:20:47:6e:6c:85:27:27:f5:43 +# SHA256 Fingerprint: d4:8d:3d:23:ee:db:50:a4:59:e5:51:97:60:1c:27:77:4b:9d:7b:18:c9:4d:5a:05:95:11:a1:02:50:b9:31:68 +-----BEGIN CERTIFICATE----- +MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAw +WjELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAw +MiA0ODE0NjMwODEwMDAzNjEZMBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0x +MzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjdaMFoxCzAJBgNVBAYTAkZSMRIwEAYD +VQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYzMDgxMDAwMzYxGTAX +BgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw +ggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sO +ty3tRQgXstmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9M +CiBtnyN6tMbaLOQdLNyzKNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPu +I9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8JXrJhFwLrN1CTivngqIkicuQstDuI7pm +TLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16XdG+RCYyKfHx9WzMfgIh +C59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq4NYKpkDf +ePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3Yz +IoejwpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWT +Co/1VTp2lc5ZmIoJlXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1k +JWumIWmbat10TWuXekG9qxf5kBdIjzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5 +hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp//TBt2dzhauH8XwIDAQABo4IB +GjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE +FBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of +1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczov +L3d3d3cuY2VydGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilo +dHRwOi8vY3JsLmNlcnRpZ25hLmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYr +aHR0cDovL2NybC5kaGlteW90aXMuY29tL2NlcnRpZ25hcm9vdGNhLmNybDANBgkq +hkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOItOoldaDgvUSILSo3L +6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxPTGRG +HVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH6 +0BGM+RFq7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncB +lA2c5uk5jR+mUYyZDDl34bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdi +o2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1 +gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS6Cvu5zHbugRqh5jnxV/v +faci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaYtlu3zM63 +Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayh +jWZSaX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw +3kAP+HwV96LOPNdeE4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0= +-----END CERTIFICATE----- + +# Issuer: CN=emSign Root CA - G1 O=eMudhra Technologies Limited OU=emSign PKI +# Subject: CN=emSign Root CA - G1 O=eMudhra Technologies Limited OU=emSign PKI +# Label: "emSign Root CA - G1" +# Serial: 235931866688319308814040 +# MD5 Fingerprint: 9c:42:84:57:dd:cb:0b:a7:2e:95:ad:b6:f3:da:bc:ac +# SHA1 Fingerprint: 8a:c7:ad:8f:73:ac:4e:c1:b5:75:4d:a5:40:f4:fc:cf:7c:b5:8e:8c +# SHA256 Fingerprint: 40:f6:af:03:46:a9:9a:a1:cd:1d:55:5a:4e:9c:ce:62:c7:f9:63:46:03:ee:40:66:15:83:3d:c8:c8:d0:03:67 +-----BEGIN CERTIFICATE----- +MIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYD +VQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBU +ZWNobm9sb2dpZXMgTGltaXRlZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBH +MTAeFw0xODAyMTgxODMwMDBaFw00MzAyMTgxODMwMDBaMGcxCzAJBgNVBAYTAklO +MRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVkaHJhIFRlY2hub2xv +Z2llcyBMaW1pdGVkMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEcxMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk0u76WaK7p1b1TST0Bsew+eeuGQz +f2N4aLTNLnF115sgxk0pvLZoYIr3IZpWNVrzdr3YzZr/k1ZLpVkGoZM0Kd0WNHVO +8oG0x5ZOrRkVUkr+PHB1cM2vK6sVmjM8qrOLqs1D/fXqcP/tzxE7lM5OMhbTI0Aq +d7OvPAEsbO2ZLIvZTmmYsvePQbAyeGHWDV/D+qJAkh1cF+ZwPjXnorfCYuKrpDhM +tTk1b+oDafo6VGiFbdbyL0NVHpENDtjVaqSW0RM8LHhQ6DqS0hdW5TUaQBw+jSzt +Od9C4INBdN+jzcKGYEho42kLVACL5HZpIQ15TjQIXhTCzLG3rdd8cIrHhQIDAQAB +o0IwQDAdBgNVHQ4EFgQU++8Nhp6w492pufEhF38+/PB3KxowDgYDVR0PAQH/BAQD +AgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFn/8oz1h31x +PaOfG1vR2vjTnGs2vZupYeveFix0PZ7mddrXuqe8QhfnPZHr5X3dPpzxz5KsbEjM +wiI/aTvFthUvozXGaCocV685743QNcMYDHsAVhzNixl03r4PEuDQqqE/AjSxcM6d +GNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q+Mri/Tm3R7nrft8EI6/6nAYH +6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeihU80Bv2noWgby +RQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx +iN66zB+Afko= +-----END CERTIFICATE----- + +# Issuer: CN=emSign ECC Root CA - G3 O=eMudhra Technologies Limited OU=emSign PKI +# Subject: CN=emSign ECC Root CA - G3 O=eMudhra Technologies Limited OU=emSign PKI +# Label: "emSign ECC Root CA - G3" +# Serial: 287880440101571086945156 +# MD5 Fingerprint: ce:0b:72:d1:9f:88:8e:d0:50:03:e8:e3:b8:8b:67:40 +# SHA1 Fingerprint: 30:43:fa:4f:f2:57:dc:a0:c3:80:ee:2e:58:ea:78:b2:3f:e6:bb:c1 +# SHA256 Fingerprint: 86:a1:ec:ba:08:9c:4a:8d:3b:be:27:34:c6:12:ba:34:1d:81:3e:04:3c:f9:e8:a8:62:cd:5c:57:a3:6b:be:6b +-----BEGIN CERTIFICATE----- +MIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQG +EwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNo +bm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g +RzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4MTgzMDAwWjBrMQswCQYDVQQGEwJJ +TjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9s +b2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMw +djAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0 +WXTsuwYc58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xyS +fvalY8L1X44uT6EYGQIrMgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuB +zhccLikenEhjQjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggq +hkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+DCBeQyh+KTOgNG3qxrdWB +CUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7jHvrZQnD ++JbNR6iC8hZVdyR+EhCVBCyj +-----END CERTIFICATE----- + +# Issuer: CN=emSign Root CA - C1 O=eMudhra Inc OU=emSign PKI +# Subject: CN=emSign Root CA - C1 O=eMudhra Inc OU=emSign PKI +# Label: "emSign Root CA - C1" +# Serial: 825510296613316004955058 +# MD5 Fingerprint: d8:e3:5d:01:21:fa:78:5a:b0:df:ba:d2:ee:2a:5f:68 +# SHA1 Fingerprint: e7:2e:f1:df:fc:b2:09:28:cf:5d:d4:d5:67:37:b1:51:cb:86:4f:01 +# SHA256 Fingerprint: 12:56:09:aa:30:1d:a0:a2:49:b9:7a:82:39:cb:6a:34:21:6f:44:dc:ac:9f:39:54:b1:42:92:f2:e8:c8:60:8f +-----BEGIN CERTIFICATE----- +MIIDczCCAlugAwIBAgILAK7PALrEzzL4Q7IwDQYJKoZIhvcNAQELBQAwVjELMAkG +A1UEBhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEg +SW5jMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAw +MFoXDTQzMDIxODE4MzAwMFowVjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln +biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQDExNlbVNpZ24gUm9v +dCBDQSAtIEMxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+upufGZ +BczYKCFK83M0UYRWEPWgTywS4/oTmifQz/l5GnRfHXk5/Fv4cI7gklL35CX5VIPZ +HdPIWoU/Xse2B+4+wM6ar6xWQio5JXDWv7V7Nq2s9nPczdcdioOl+yuQFTdrHCZH +3DspVpNqs8FqOp099cGXOFgFixwR4+S0uF2FHYP+eF8LRWgYSKVGczQ7/g/IdrvH +GPMF0Ybzhe3nudkyrVWIzqa2kbBPrH4VI5b2P/AgNBbeCsbEBEV5f6f9vtKppa+c +xSMq9zwhbL2vj07FOrLzNBL834AaSaTUqZX3noleoomslMuoaJuvimUnzYnu3Yy1 +aylwQ6BpC+S5DwIDAQABo0IwQDAdBgNVHQ4EFgQU/qHgcB4qAzlSWkK+XJGFehiq +TbUwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL +BQADggEBAMJKVvoVIXsoounlHfv4LcQ5lkFMOycsxGwYFYDGrK9HWS8mC+M2sO87 +/kOXSTKZEhVb3xEp/6tT+LvBeA+snFOvV71ojD1pM/CjoCNjO2RnIkSt1XHLVip4 +kqNPEjE2NuLe/gDEo2APJ62gsIq1NnpSob0n9CAnYuhNlCQT5AoE6TyrLshDCUrG +YQTlSTR+08TI9Q/Aqum6VF7zYytPT1DU/rl7mYw9wC68AivTxEDkigcxHpvOJpkT ++xHqmiIMERnHXhuBUDDIlhJu58tBf5E7oke3VIAb3ADMmpDqw8NQBmIMMMAVSKeo +WXzhriKi4gp6D/piq1JM4fHfyr6DDUI= +-----END CERTIFICATE----- + +# Issuer: CN=emSign ECC Root CA - C3 O=eMudhra Inc OU=emSign PKI +# Subject: CN=emSign ECC Root CA - C3 O=eMudhra Inc OU=emSign PKI +# Label: "emSign ECC Root CA - C3" +# Serial: 582948710642506000014504 +# MD5 Fingerprint: 3e:53:b3:a3:81:ee:d7:10:f8:d3:b0:1d:17:92:f5:d5 +# SHA1 Fingerprint: b6:af:43:c2:9b:81:53:7d:f6:ef:6b:c3:1f:1f:60:15:0c:ee:48:66 +# SHA256 Fingerprint: bc:4d:80:9b:15:18:9d:78:db:3e:1d:8c:f4:f9:72:6a:79:5d:a1:64:3c:a5:f1:35:8e:1d:db:0e:dc:0d:7e:b3 +-----BEGIN CERTIFICATE----- +MIICKzCCAbGgAwIBAgIKe3G2gla4EnycqDAKBggqhkjOPQQDAzBaMQswCQYDVQQG +EwJVUzETMBEGA1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMx +IDAeBgNVBAMTF2VtU2lnbiBFQ0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAw +MFoXDTQzMDIxODE4MzAwMFowWjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln +biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMSAwHgYDVQQDExdlbVNpZ24gRUND +IFJvb3QgQ0EgLSBDMzB2MBAGByqGSM49AgEGBSuBBAAiA2IABP2lYa57JhAd6bci +MK4G9IGzsUJxlTm801Ljr6/58pc1kjZGDoeVjbk5Wum739D+yAdBPLtVb4Ojavti +sIGJAnB9SMVK4+kiVCJNk7tCDK93nCOmfddhEc5lx/h//vXyqaNCMEAwHQYDVR0O +BBYEFPtaSNCAIEDyqOkAB2kZd6fmw/TPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB +Af8EBTADAQH/MAoGCCqGSM49BAMDA2gAMGUCMQC02C8Cif22TGK6Q04ThHK1rt0c +3ta13FaPWEBaLd4gTCKDypOofu4SQMfWh0/434UCMBwUZOR8loMRnLDRWmFLpg9J +0wD8ofzkpf9/rdcw0Md3f76BB1UwUCAU9Vc4CqgxUQ== +-----END CERTIFICATE----- + +# Issuer: CN=Hongkong Post Root CA 3 O=Hongkong Post +# Subject: CN=Hongkong Post Root CA 3 O=Hongkong Post +# Label: "Hongkong Post Root CA 3" +# Serial: 46170865288971385588281144162979347873371282084 +# MD5 Fingerprint: 11:fc:9f:bd:73:30:02:8a:fd:3f:f3:58:b9:cb:20:f0 +# SHA1 Fingerprint: 58:a2:d0:ec:20:52:81:5b:c1:f3:f8:64:02:24:4e:c2:8e:02:4b:02 +# SHA256 Fingerprint: 5a:2f:c0:3f:0c:83:b0:90:bb:fa:40:60:4b:09:88:44:6c:76:36:18:3d:f9:84:6e:17:10:1a:44:7f:b8:ef:d6 +-----BEGIN CERTIFICATE----- +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 +mpv0 +-----END CERTIFICATE----- + +# Issuer: CN=Entrust Root Certification Authority - G4 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2015 Entrust, Inc. - for authorized use only +# Subject: CN=Entrust Root Certification Authority - G4 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2015 Entrust, Inc. - for authorized use only +# Label: "Entrust Root Certification Authority - G4" +# Serial: 289383649854506086828220374796556676440 +# MD5 Fingerprint: 89:53:f1:83:23:b7:7c:8e:05:f1:8c:71:38:4e:1f:88 +# SHA1 Fingerprint: 14:88:4e:86:26:37:b0:26:af:59:62:5c:40:77:ec:35:29:ba:96:01 +# SHA256 Fingerprint: db:35:17:d1:f6:73:2a:2d:5a:b9:7c:53:3e:c7:07:79:ee:32:70:a6:2f:b4:ac:42:38:37:24:60:e6:f0:1e:88 +-----BEGIN CERTIFICATE----- +MIIGSzCCBDOgAwIBAgIRANm1Q3+vqTkPAAAAAFVlrVgwDQYJKoZIhvcNAQELBQAw +gb4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQL +Ex9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykg +MjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAw +BgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0 +MB4XDTE1MDUyNzExMTExNloXDTM3MTIyNzExNDExNlowgb4xCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1 +c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJ +bmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3Qg +Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0MIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEAsewsQu7i0TD/pZJH4i3DumSXbcr3DbVZwbPLqGgZ +2K+EbTBwXX7zLtJTmeH+H17ZSK9dE43b/2MzTdMAArzE+NEGCJR5WIoV3imz/f3E +T+iq4qA7ec2/a0My3dl0ELn39GjUu9CH1apLiipvKgS1sqbHoHrmSKvS0VnM1n4j +5pds8ELl3FFLFUHtSUrJ3hCX1nbB76W1NhSXNdh4IjVS70O92yfbYVaCNNzLiGAM +C1rlLAHGVK/XqsEQe9IFWrhAnoanw5CGAlZSCXqc0ieCU0plUmr1POeo8pyvi73T +DtTUXm6Hnmo9RR3RXRv06QqsYJn7ibT/mCzPfB3pAqoEmh643IhuJbNsZvc8kPNX +wbMv9W3y+8qh+CmdRouzavbmZwe+LGcKKh9asj5XxNMhIWNlUpEbsZmOeX7m640A +2Vqq6nPopIICR5b+W45UYaPrL0swsIsjdXJ8ITzI9vF01Bx7owVV7rtNOzK+mndm +nqxpkCIHH2E6lr7lmk/MBTwoWdPBDFSoWWG9yHJM6Nyfh3+9nEg2XpWjDrk4JFX8 +dWbrAuMINClKxuMrLzOg2qOGpRKX/YAr2hRC45K9PvJdXmd0LhyIRyk0X+IyqJwl +N4y6mACXi0mWHv0liqzc2thddG5msP9E36EYxr5ILzeUePiVSj9/E15dWf10hkNj +c0kCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD +VR0OBBYEFJ84xFYjwznooHFs6FRM5Og6sb9nMA0GCSqGSIb3DQEBCwUAA4ICAQAS +5UKme4sPDORGpbZgQIeMJX6tuGguW8ZAdjwD+MlZ9POrYs4QjbRaZIxowLByQzTS +Gwv2LFPSypBLhmb8qoMi9IsabyZIrHZ3CL/FmFz0Jomee8O5ZDIBf9PD3Vht7LGr +hFV0d4QEJ1JrhkzO3bll/9bGXp+aEJlLdWr+aumXIOTkdnrG0CSqkM0gkLpHZPt/ +B7NTeLUKYvJzQ85BK4FqLoUWlFPUa19yIqtRLULVAJyZv967lDtX/Zr1hstWO1uI +AeV8KEsD+UmDfLJ/fOPtjqF/YFOOVZ1QNBIPt5d7bIdKROf1beyAN/BYGW5KaHbw +H5Lk6rWS02FREAutp9lfx1/cH6NcjKF+m7ee01ZvZl4HliDtC3T7Zk6LERXpgUl+ +b7DUUH8i119lAg2m9IUe2K4GS0qn0jFmwvjO5QimpAKWRGhXxNUzzxkvFMSUHHuk +2fCfDrGA4tGeEWSpiBE6doLlYsKA2KSD7ZPvfC+QsDJMlhVoSFLUmQjAJOgc47Ol +IQ6SwJAfzyBfyjs4x7dtOvPmRLgOMWuIjnDrnBdSqEGULoe256YSxXXfW8AKbnuk +5F6G+TaU33fD6Q3AOfF5u0aOq0NZJ7cguyPpVkAh7DE9ZapD8j3fcEThuk0mEDuY +n/PIjhs4ViFqUZPTkcpG2om3PVODLAgfi49T3f+sHw== +-----END CERTIFICATE----- + +# Issuer: CN=Microsoft ECC Root Certificate Authority 2017 O=Microsoft Corporation +# Subject: CN=Microsoft ECC Root Certificate Authority 2017 O=Microsoft Corporation +# Label: "Microsoft ECC Root Certificate Authority 2017" +# Serial: 136839042543790627607696632466672567020 +# MD5 Fingerprint: dd:a1:03:e6:4a:93:10:d1:bf:f0:19:42:cb:fe:ed:67 +# SHA1 Fingerprint: 99:9a:64:c3:7f:f4:7d:9f:ab:95:f1:47:69:89:14:60:ee:c4:c3:c5 +# SHA256 Fingerprint: 35:8d:f3:9d:76:4a:f9:e1:b7:66:e9:c9:72:df:35:2e:e1:5c:fa:c2:27:af:6a:d1:d7:0e:8e:4a:6e:dc:ba:02 +-----BEGIN CERTIFICATE----- +MIICWTCCAd+gAwIBAgIQZvI9r4fei7FK6gxXMQHC7DAKBggqhkjOPQQDAzBlMQsw +CQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYD +VQQDEy1NaWNyb3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIw +MTcwHhcNMTkxMjE4MjMwNjQ1WhcNNDIwNzE4MjMxNjA0WjBlMQswCQYDVQQGEwJV +UzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNy +b3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwdjAQBgcq +hkjOPQIBBgUrgQQAIgNiAATUvD0CQnVBEyPNgASGAlEvaqiBYgtlzPbKnR5vSmZR +ogPZnZH6thaxjG7efM3beaYvzrvOcS/lpaso7GMEZpn4+vKTEAXhgShC48Zo9OYb +hGBKia/teQ87zvH2RPUBeMCjVDBSMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8E +BTADAQH/MB0GA1UdDgQWBBTIy5lycFIM+Oa+sgRXKSrPQhDtNTAQBgkrBgEEAYI3 +FQEEAwIBADAKBggqhkjOPQQDAwNoADBlAjBY8k3qDPlfXu5gKcs68tvWMoQZP3zV +L8KxzJOuULsJMsbG7X7JNpQS5GiFBqIb0C8CMQCZ6Ra0DvpWSNSkMBaReNtUjGUB +iudQZsIxtzm6uBoiB078a1QWIP8rtedMDE2mT3M= +-----END CERTIFICATE----- + +# Issuer: CN=Microsoft RSA Root Certificate Authority 2017 O=Microsoft Corporation +# Subject: CN=Microsoft RSA Root Certificate Authority 2017 O=Microsoft Corporation +# Label: "Microsoft RSA Root Certificate Authority 2017" +# Serial: 40975477897264996090493496164228220339 +# MD5 Fingerprint: 10:ff:00:ff:cf:c9:f8:c7:7a:c0:ee:35:8e:c9:0f:47 +# SHA1 Fingerprint: 73:a5:e6:4a:3b:ff:83:16:ff:0e:dc:cc:61:8a:90:6e:4e:ae:4d:74 +# SHA256 Fingerprint: c7:41:f7:0f:4b:2a:8d:88:bf:2e:71:c1:41:22:ef:53:ef:10:eb:a0:cf:a5:e6:4c:fa:20:f4:18:85:30:73:e0 +-----BEGIN CERTIFICATE----- +MIIFqDCCA5CgAwIBAgIQHtOXCV/YtLNHcB6qvn9FszANBgkqhkiG9w0BAQwFADBl +MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYw +NAYDVQQDEy1NaWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 +IDIwMTcwHhcNMTkxMjE4MjI1MTIyWhcNNDIwNzE4MjMwMDIzWjBlMQswCQYDVQQG +EwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1N +aWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwggIi +MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKW76UM4wplZEWCpW9R2LBifOZ +Nt9GkMml7Xhqb0eRaPgnZ1AzHaGm++DlQ6OEAlcBXZxIQIJTELy/xztokLaCLeX0 +ZdDMbRnMlfl7rEqUrQ7eS0MdhweSE5CAg2Q1OQT85elss7YfUJQ4ZVBcF0a5toW1 +HLUX6NZFndiyJrDKxHBKrmCk3bPZ7Pw71VdyvD/IybLeS2v4I2wDwAW9lcfNcztm +gGTjGqwu+UcF8ga2m3P1eDNbx6H7JyqhtJqRjJHTOoI+dkC0zVJhUXAoP8XFWvLJ +jEm7FFtNyP9nTUwSlq31/niol4fX/V4ggNyhSyL71Imtus5Hl0dVe49FyGcohJUc +aDDv70ngNXtk55iwlNpNhTs+VcQor1fznhPbRiefHqJeRIOkpcrVE7NLP8TjwuaG +YaRSMLl6IE9vDzhTyzMMEyuP1pq9KsgtsRx9S1HKR9FIJ3Jdh+vVReZIZZ2vUpC6 +W6IYZVcSn2i51BVrlMRpIpj0M+Dt+VGOQVDJNE92kKz8OMHY4Xu54+OU4UZpyw4K +UGsTuqwPN1q3ErWQgR5WrlcihtnJ0tHXUeOrO8ZV/R4O03QK0dqq6mm4lyiPSMQH ++FJDOvTKVTUssKZqwJz58oHhEmrARdlns87/I6KJClTUFLkqqNfs+avNJVgyeY+Q +W5g5xAgGwax/Dj0ApQIDAQABo1QwUjAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/ +BAUwAwEB/zAdBgNVHQ4EFgQUCctZf4aycI8awznjwNnpv7tNsiMwEAYJKwYBBAGC +NxUBBAMCAQAwDQYJKoZIhvcNAQEMBQADggIBAKyvPl3CEZaJjqPnktaXFbgToqZC +LgLNFgVZJ8og6Lq46BrsTaiXVq5lQ7GPAJtSzVXNUzltYkyLDVt8LkS/gxCP81OC +gMNPOsduET/m4xaRhPtthH80dK2Jp86519efhGSSvpWhrQlTM93uCupKUY5vVau6 +tZRGrox/2KJQJWVggEbbMwSubLWYdFQl3JPk+ONVFT24bcMKpBLBaYVu32TxU5nh +SnUgnZUP5NbcA/FZGOhHibJXWpS2qdgXKxdJ5XbLwVaZOjex/2kskZGT4d9Mozd2 +TaGf+G0eHdP67Pv0RR0Tbc/3WeUiJ3IrhvNXuzDtJE3cfVa7o7P4NHmJweDyAmH3 +pvwPuxwXC65B2Xy9J6P9LjrRk5Sxcx0ki69bIImtt2dmefU6xqaWM/5TkshGsRGR +xpl/j8nWZjEgQRCHLQzWwa80mMpkg/sTV9HB8Dx6jKXB/ZUhoHHBk2dxEuqPiApp +GWSZI1b7rCoucL5mxAyE7+WL85MB+GqQk2dLsmijtWKP6T+MejteD+eMuMZ87zf9 +dOLITzNy4ZQ5bb0Sr74MTnB8G2+NszKTc0QWbej09+CVgI+WXTik9KveCjCHk9hN +AHFiRSdLOkKEW39lt2c0Ui2cFmuqqNh7o0JMcccMyj6D5KbvtwEwXlGjefVwaaZB +RA+GsCyRxj3qrg+E +-----END CERTIFICATE----- + +# Issuer: CN=e-Szigno Root CA 2017 O=Microsec Ltd. +# Subject: CN=e-Szigno Root CA 2017 O=Microsec Ltd. +# Label: "e-Szigno Root CA 2017" +# Serial: 411379200276854331539784714 +# MD5 Fingerprint: de:1f:f6:9e:84:ae:a7:b4:21:ce:1e:58:7d:d1:84:98 +# SHA1 Fingerprint: 89:d4:83:03:4f:9e:9a:48:80:5f:72:37:d4:a9:a6:ef:cb:7c:1f:d1 +# SHA256 Fingerprint: be:b0:0b:30:83:9b:9b:c3:2c:32:e4:44:79:05:95:06:41:f2:64:21:b1:5e:d0:89:19:8b:51:8a:e2:ea:1b:99 +-----BEGIN CERTIFICATE----- +MIICQDCCAeWgAwIBAgIMAVRI7yH9l1kN9QQKMAoGCCqGSM49BAMCMHExCzAJBgNV +BAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMgTHRk +LjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25vIFJv +b3QgQ0EgMjAxNzAeFw0xNzA4MjIxMjA3MDZaFw00MjA4MjIxMjA3MDZaMHExCzAJ +BgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMg +THRkLjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25v +IFJvb3QgQ0EgMjAxNzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJbcPYrYsHtv +xie+RJCxs1YVe45DJH0ahFnuY2iyxl6H0BVIHqiQrb1TotreOpCmYF9oMrWGQd+H +Wyx7xf58etqjYzBhMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G +A1UdDgQWBBSHERUI0arBeAyxr87GyZDvvzAEwDAfBgNVHSMEGDAWgBSHERUI0arB +eAyxr87GyZDvvzAEwDAKBggqhkjOPQQDAgNJADBGAiEAtVfd14pVCzbhhkT61Nlo +jbjcI4qKDdQvfepz7L9NbKgCIQDLpbQS+ue16M9+k/zzNY9vTlp8tLxOsvxyqltZ ++efcMQ== +-----END CERTIFICATE----- + +# Issuer: O=CERTSIGN SA OU=certSIGN ROOT CA G2 +# Subject: O=CERTSIGN SA OU=certSIGN ROOT CA G2 +# Label: "certSIGN Root CA G2" +# Serial: 313609486401300475190 +# MD5 Fingerprint: 8c:f1:75:8a:c6:19:cf:94:b7:f7:65:20:87:c3:97:c7 +# SHA1 Fingerprint: 26:f9:93:b4:ed:3d:28:27:b0:b9:4b:a7:e9:15:1d:a3:8d:92:e5:32 +# SHA256 Fingerprint: 65:7c:fe:2f:a7:3f:aa:38:46:25:71:f3:32:a2:36:3a:46:fc:e7:02:09:51:71:07:02:cd:fb:b6:ee:da:33:05 +-----BEGIN CERTIFICATE----- +MIIFRzCCAy+gAwIBAgIJEQA0tk7GNi02MA0GCSqGSIb3DQEBCwUAMEExCzAJBgNV +BAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJR04g +Uk9PVCBDQSBHMjAeFw0xNzAyMDYwOTI3MzVaFw00MjAyMDYwOTI3MzVaMEExCzAJ +BgNVBAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJ +R04gUk9PVCBDQSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDF +dRmRfUR0dIf+DjuW3NgBFszuY5HnC2/OOwppGnzC46+CjobXXo9X69MhWf05N0Iw +vlDqtg+piNguLWkh59E3GE59kdUWX2tbAMI5Qw02hVK5U2UPHULlj88F0+7cDBrZ +uIt4ImfkabBoxTzkbFpG583H+u/E7Eu9aqSs/cwoUe+StCmrqzWaTOTECMYmzPhp +n+Sc8CnTXPnGFiWeI8MgwT0PPzhAsP6CRDiqWhqKa2NYOLQV07YRaXseVO6MGiKs +cpc/I1mbySKEwQdPzH/iV8oScLumZfNpdWO9lfsbl83kqK/20U6o2YpxJM02PbyW +xPFsqa7lzw1uKA2wDrXKUXt4FMMgL3/7FFXhEZn91QqhngLjYl/rNUssuHLoPj1P +rCy7Lobio3aP5ZMqz6WryFyNSwb/EkaseMsUBzXgqd+L6a8VTxaJW732jcZZroiF +DsGJ6x9nxUWO/203Nit4ZoORUSs9/1F3dmKh7Gc+PoGD4FapUB8fepmrY7+EF3fx +DTvf95xhszWYijqy7DwaNz9+j5LP2RIUZNoQAhVB/0/E6xyjyfqZ90bp4RjZsbgy +LcsUDFDYg2WD7rlcz8sFWkz6GZdr1l0T08JcVLwyc6B49fFtHsufpaafItzRUZ6C +eWRgKRM+o/1Pcmqr4tTluCRVLERLiohEnMqE0yo7AgMBAAGjQjBAMA8GA1UdEwEB +/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSCIS1mxteg4BXrzkwJ +d8RgnlRuAzANBgkqhkiG9w0BAQsFAAOCAgEAYN4auOfyYILVAzOBywaK8SJJ6ejq +kX/GM15oGQOGO0MBzwdw5AgeZYWR5hEit/UCI46uuR59H35s5r0l1ZUa8gWmr4UC +b6741jH/JclKyMeKqdmfS0mbEVeZkkMR3rYzpMzXjWR91M08KCy0mpbqTfXERMQl +qiCA2ClV9+BB/AYm/7k29UMUA2Z44RGx2iBfRgB4ACGlHgAoYXhvqAEBj500mv/0 +OJD7uNGzcgbJceaBxXntC6Z58hMLnPddDnskk7RI24Zf3lCGeOdA5jGokHZwYa+c +NywRtYK3qq4kNFtyDGkNzVmf9nGvnAvRCjj5BiKDUyUM/FHE5r7iOZULJK2v0ZXk +ltd0ZGtxTgI8qoXzIKNDOXZbbFD+mpwUHmUUihW9o4JFWklWatKcsWMy5WHgUyIO +pwpJ6st+H6jiYoD2EEVSmAYY3qXNL3+q1Ok+CHLsIwMCPKaq2LxndD0UF/tUSxfj +03k9bWtJySgOLnRQvwzZRjoQhsmnP+mg7H/rpXdYaXHmgwo38oZJar55CJD2AhZk +PuXaTH4MNMn5X7azKFGnpyuqSfqNZSlO42sTp5SjLVFteAxEy9/eCG/Oo2Sr05WE +1LlSVHJ7liXMvGnjSG4N0MedJ5qq+BOS3R7fY581qRY27Iy4g/Q9iY/NtBde17MX +QRBdJ3NghVdJIgc= +-----END CERTIFICATE----- + +# Issuer: CN=Trustwave Global Certification Authority O=Trustwave Holdings, Inc. +# Subject: CN=Trustwave Global Certification Authority O=Trustwave Holdings, Inc. +# Label: "Trustwave Global Certification Authority" +# Serial: 1846098327275375458322922162 +# MD5 Fingerprint: f8:1c:18:2d:2f:ba:5f:6d:a1:6c:bc:c7:ab:91:c7:0e +# SHA1 Fingerprint: 2f:8f:36:4f:e1:58:97:44:21:59:87:a5:2a:9a:d0:69:95:26:7f:b5 +# SHA256 Fingerprint: 97:55:20:15:f5:dd:fc:3c:87:88:c0:06:94:45:55:40:88:94:45:00:84:f1:00:86:70:86:bc:1a:2b:b5:8d:c8 +-----BEGIN CERTIFICATE----- +MIIF2jCCA8KgAwIBAgIMBfcOhtpJ80Y1LrqyMA0GCSqGSIb3DQEBCwUAMIGIMQsw +CQYDVQQGEwJVUzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28x +ITAfBgNVBAoMGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1 +c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMx +OTM0MTJaFw00MjA4MjMxOTM0MTJaMIGIMQswCQYDVQQGEwJVUzERMA8GA1UECAwI +SWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2ZSBI +b2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZp +Y2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB +ALldUShLPDeS0YLOvR29zd24q88KPuFd5dyqCblXAj7mY2Hf8g+CY66j96xz0Xzn +swuvCAAJWX/NKSqIk4cXGIDtiLK0thAfLdZfVaITXdHG6wZWiYj+rDKd/VzDBcdu +7oaJuogDnXIhhpCujwOl3J+IKMujkkkP7NAP4m1ET4BqstTnoApTAbqOl5F2brz8 +1Ws25kCI1nsvXwXoLG0R8+eyvpJETNKXpP7ScoFDB5zpET71ixpZfR9oWN0EACyW +80OzfpgZdNmcc9kYvkHHNHnZ9GLCQ7mzJ7Aiy/k9UscwR7PJPrhq4ufogXBeQotP +JqX+OsIgbrv4Fo7NDKm0G2x2EOFYeUY+VM6AqFcJNykbmROPDMjWLBz7BegIlT1l +RtzuzWniTY+HKE40Cz7PFNm73bZQmq131BnW2hqIyE4bJ3XYsgjxroMwuREOzYfw +hI0Vcnyh78zyiGG69Gm7DIwLdVcEuE4qFC49DxweMqZiNu5m4iK4BUBjECLzMx10 +coos9TkpoNPnG4CELcU9402x/RpvumUHO1jsQkUm+9jaJXLE9gCxInm943xZYkqc +BW89zubWR2OZxiRvchLIrH+QtAuRcOi35hYQcRfO3gZPSEF9NUqjifLJS3tBEW1n +twiYTOURGa5CgNz7kAXU+FDKvuStx8KU1xad5hePrzb7AgMBAAGjQjBAMA8GA1Ud +EwEB/wQFMAMBAf8wHQYDVR0OBBYEFJngGWcNYtt2s9o9uFvo/ULSMQ6HMA4GA1Ud +DwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAmHNw4rDT7TnsTGDZqRKGFx6W +0OhUKDtkLSGm+J1WE2pIPU/HPinbbViDVD2HfSMF1OQc3Og4ZYbFdada2zUFvXfe +uyk3QAUHw5RSn8pk3fEbK9xGChACMf1KaA0HZJDmHvUqoai7PF35owgLEQzxPy0Q +lG/+4jSHg9bP5Rs1bdID4bANqKCqRieCNqcVtgimQlRXtpla4gt5kNdXElE1GYhB +aCXUNxeEFfsBctyV3lImIJgm4nb1J2/6ADtKYdkNy1GTKv0WBpanI5ojSP5RvbbE +sLFUzt5sQa0WZ37b/TjNuThOssFgy50X31ieemKyJo90lZvkWx3SD92YHJtZuSPT +MaCm/zjdzyBP6VhWOmfD0faZmZ26NraAL4hHT4a/RDqA5Dccprrql5gR0IRiR2Qe +qu5AvzSxnI9O4fKSTx+O856X3vOmeWqJcU9LJxdI/uz0UA9PSX3MReO9ekDFQdxh +VicGaeVyQYHTtgGJoC86cnn+OjC/QezHYj6RS8fZMXZC+fc8Y+wmjHMMfRod6qh8 +h6jCJ3zhM0EPz8/8AKAigJ5Kp28AsEFFtyLKaEjFQqKu3R3y4G5OBVixwJAWKqQ9 +EEC+j2Jjg6mcgn0tAumDMHzLJ8n9HmYAsC7TIS+OMxZsmO0QqAfWzJPP29FpHOTK +yeC2nOnOcXHebD8WpHk= +-----END CERTIFICATE----- + +# Issuer: CN=Trustwave Global ECC P256 Certification Authority O=Trustwave Holdings, Inc. +# Subject: CN=Trustwave Global ECC P256 Certification Authority O=Trustwave Holdings, Inc. +# Label: "Trustwave Global ECC P256 Certification Authority" +# Serial: 4151900041497450638097112925 +# MD5 Fingerprint: 5b:44:e3:8d:5d:36:86:26:e8:0d:05:d2:59:a7:83:54 +# SHA1 Fingerprint: b4:90:82:dd:45:0c:be:8b:5b:b1:66:d3:e2:a4:08:26:cd:ed:42:cf +# SHA256 Fingerprint: 94:5b:bc:82:5e:a5:54:f4:89:d1:fd:51:a7:3d:df:2e:a6:24:ac:70:19:a0:52:05:22:5c:22:a7:8c:cf:a8:b4 +-----BEGIN CERTIFICATE----- +MIICYDCCAgegAwIBAgIMDWpfCD8oXD5Rld9dMAoGCCqGSM49BAMCMIGRMQswCQYD +VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAf +BgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3 +YXZlIEdsb2JhbCBFQ0MgUDI1NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0x +NzA4MjMxOTM1MTBaFw00MjA4MjMxOTM1MTBaMIGRMQswCQYDVQQGEwJVUzERMA8G +A1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0 +d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBF +Q0MgUDI1NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTBZMBMGByqGSM49AgEGCCqG +SM49AwEHA0IABH77bOYj43MyCMpg5lOcunSNGLB4kFKA3TjASh3RqMyTpJcGOMoN +FWLGjgEqZZ2q3zSRLoHB5DOSMcT9CTqmP62jQzBBMA8GA1UdEwEB/wQFMAMBAf8w +DwYDVR0PAQH/BAUDAwcGADAdBgNVHQ4EFgQUo0EGrJBt0UrrdaVKEJmzsaGLSvcw +CgYIKoZIzj0EAwIDRwAwRAIgB+ZU2g6gWrKuEZ+Hxbb/ad4lvvigtwjzRM4q3wgh +DDcCIC0mA6AFvWvR9lz4ZcyGbbOcNEhjhAnFjXca4syc4XR7 +-----END CERTIFICATE----- + +# Issuer: CN=Trustwave Global ECC P384 Certification Authority O=Trustwave Holdings, Inc. +# Subject: CN=Trustwave Global ECC P384 Certification Authority O=Trustwave Holdings, Inc. +# Label: "Trustwave Global ECC P384 Certification Authority" +# Serial: 2704997926503831671788816187 +# MD5 Fingerprint: ea:cf:60:c4:3b:b9:15:29:40:a1:97:ed:78:27:93:d6 +# SHA1 Fingerprint: e7:f3:a3:c8:cf:6f:c3:04:2e:6d:0e:67:32:c5:9e:68:95:0d:5e:d2 +# SHA256 Fingerprint: 55:90:38:59:c8:c0:c3:eb:b8:75:9e:ce:4e:25:57:22:5f:f5:75:8b:bd:38:eb:d4:82:76:60:1e:1b:d5:80:97 +-----BEGIN CERTIFICATE----- +MIICnTCCAiSgAwIBAgIMCL2Fl2yZJ6SAaEc7MAoGCCqGSM49BAMDMIGRMQswCQYD +VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAf +BgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3 +YXZlIEdsb2JhbCBFQ0MgUDM4NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0x +NzA4MjMxOTM2NDNaFw00MjA4MjMxOTM2NDNaMIGRMQswCQYDVQQGEwJVUzERMA8G +A1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0 +d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBF +Q0MgUDM4NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTB2MBAGByqGSM49AgEGBSuB +BAAiA2IABGvaDXU1CDFHBa5FmVXxERMuSvgQMSOjfoPTfygIOiYaOs+Xgh+AtycJ +j9GOMMQKmw6sWASr9zZ9lCOkmwqKi6vr/TklZvFe/oyujUF5nQlgziip04pt89ZF +1PKYhDhloKNDMEEwDwYDVR0TAQH/BAUwAwEB/zAPBgNVHQ8BAf8EBQMDBwYAMB0G +A1UdDgQWBBRVqYSJ0sEyvRjLbKYHTsjnnb6CkDAKBggqhkjOPQQDAwNnADBkAjA3 +AZKXRRJ+oPM+rRk6ct30UJMDEr5E0k9BpIycnR+j9sKS50gU/k6bpZFXrsY3crsC +MGclCrEMXu6pY5Jv5ZAL/mYiykf9ijH3g/56vxC+GCsej/YpHpRZ744hN8tRmKVu +Sw== +-----END CERTIFICATE----- + +# Issuer: CN=NAVER Global Root Certification Authority O=NAVER BUSINESS PLATFORM Corp. +# Subject: CN=NAVER Global Root Certification Authority O=NAVER BUSINESS PLATFORM Corp. +# Label: "NAVER Global Root Certification Authority" +# Serial: 9013692873798656336226253319739695165984492813 +# MD5 Fingerprint: c8:7e:41:f6:25:3b:f5:09:b3:17:e8:46:3d:bf:d0:9b +# SHA1 Fingerprint: 8f:6b:f2:a9:27:4a:da:14:a0:c4:f4:8e:61:27:f9:c0:1e:78:5d:d1 +# SHA256 Fingerprint: 88:f4:38:dc:f8:ff:d1:fa:8f:42:91:15:ff:e5:f8:2a:e1:e0:6e:0c:70:c3:75:fa:ad:71:7b:34:a4:9e:72:65 +-----BEGIN CERTIFICATE----- +MIIFojCCA4qgAwIBAgIUAZQwHqIL3fXFMyqxQ0Rx+NZQTQ0wDQYJKoZIhvcNAQEM +BQAwaTELMAkGA1UEBhMCS1IxJjAkBgNVBAoMHU5BVkVSIEJVU0lORVNTIFBMQVRG +T1JNIENvcnAuMTIwMAYDVQQDDClOQVZFUiBHbG9iYWwgUm9vdCBDZXJ0aWZpY2F0 +aW9uIEF1dGhvcml0eTAeFw0xNzA4MTgwODU4NDJaFw0zNzA4MTgyMzU5NTlaMGkx +CzAJBgNVBAYTAktSMSYwJAYDVQQKDB1OQVZFUiBCVVNJTkVTUyBQTEFURk9STSBD +b3JwLjEyMDAGA1UEAwwpTkFWRVIgR2xvYmFsIFJvb3QgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC21PGTXLVA +iQqrDZBbUGOukJR0F0Vy1ntlWilLp1agS7gvQnXp2XskWjFlqxcX0TM62RHcQDaH +38dq6SZeWYp34+hInDEW+j6RscrJo+KfziFTowI2MMtSAuXaMl3Dxeb57hHHi8lE +HoSTGEq0n+USZGnQJoViAbbJAh2+g1G7XNr4rRVqmfeSVPc0W+m/6imBEtRTkZaz +kVrd/pBzKPswRrXKCAfHcXLJZtM0l/aM9BhK4dA9WkW2aacp+yPOiNgSnABIqKYP +szuSjXEOdMWLyEz59JuOuDxp7W87UC9Y7cSw0BwbagzivESq2M0UXZR4Yb8Obtoq +vC8MC3GmsxY/nOb5zJ9TNeIDoKAYv7vxvvTWjIcNQvcGufFt7QSUqP620wbGQGHf +nZ3zVHbOUzoBppJB7ASjjw2i1QnK1sua8e9DXcCrpUHPXFNwcMmIpi3Ua2FzUCaG +YQ5fG8Ir4ozVu53BA0K6lNpfqbDKzE0K70dpAy8i+/Eozr9dUGWokG2zdLAIx6yo +0es+nPxdGoMuK8u180SdOqcXYZaicdNwlhVNt0xz7hlcxVs+Qf6sdWA7G2POAN3a +CJBitOUt7kinaxeZVL6HSuOpXgRM6xBtVNbv8ejyYhbLgGvtPe31HzClrkvJE+2K +AQHJuFFYwGY6sWZLxNUxAmLpdIQM201GLQIDAQABo0IwQDAdBgNVHQ4EFgQU0p+I +36HNLL3s9TsBAZMzJ7LrYEswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB +Af8wDQYJKoZIhvcNAQEMBQADggIBADLKgLOdPVQG3dLSLvCkASELZ0jKbY7gyKoN +qo0hV4/GPnrK21HUUrPUloSlWGB/5QuOH/XcChWB5Tu2tyIvCZwTFrFsDDUIbatj +cu3cvuzHV+YwIHHW1xDBE1UBjCpD5EHxzzp6U5LOogMFDTjfArsQLtk70pt6wKGm ++LUx5vR1yblTmXVHIloUFcd4G7ad6Qz4G3bxhYTeodoS76TiEJd6eN4MUZeoIUCL +hr0N8F5OSza7OyAfikJW4Qsav3vQIkMsRIz75Sq0bBwcupTgE34h5prCy8VCZLQe +lHsIJchxzIdFV4XTnyliIoNRlwAYl3dqmJLJfGBs32x9SuRwTMKeuB330DTHD8z7 +p/8Dvq1wkNoL3chtl1+afwkyQf3NosxabUzyqkn+Zvjp2DXrDige7kgvOtB5CTh8 +piKCk5XQA76+AqAF3SAi428diDRgxuYKuQl1C/AH6GmWNcf7I4GOODm4RStDeKLR +LBT/DShycpWbXgnbiUSYqqFJu3FS8r/2/yehNq+4tneI3TqkbZs0kNwUXTC/t+sX +5Ie3cdCh13cV1ELX8vMxmV2b3RZtP+oGI/hGoiLtk/bdmuYqh7GYVPEi92tF4+KO +dh2ajcQGjTa3FPOdVGm3jjzVpG2Tgbet9r1ke8LJaDmgkpzNNIaRkPpkUZ3+/uul +9XXeifdy +-----END CERTIFICATE----- + +# Issuer: CN=AC RAIZ FNMT-RCM SERVIDORES SEGUROS O=FNMT-RCM OU=Ceres +# Subject: CN=AC RAIZ FNMT-RCM SERVIDORES SEGUROS O=FNMT-RCM OU=Ceres +# Label: "AC RAIZ FNMT-RCM SERVIDORES SEGUROS" +# Serial: 131542671362353147877283741781055151509 +# MD5 Fingerprint: 19:36:9c:52:03:2f:d2:d1:bb:23:cc:dd:1e:12:55:bb +# SHA1 Fingerprint: 62:ff:d9:9e:c0:65:0d:03:ce:75:93:d2:ed:3f:2d:32:c9:e3:e5:4a +# SHA256 Fingerprint: 55:41:53:b1:3d:2c:f9:dd:b7:53:bf:be:1a:4e:0a:e0:8d:0a:a4:18:70:58:fe:60:a2:b8:62:b2:e4:b8:7b:cb +-----BEGIN CERTIFICATE----- +MIICbjCCAfOgAwIBAgIQYvYybOXE42hcG2LdnC6dlTAKBggqhkjOPQQDAzB4MQsw +CQYDVQQGEwJFUzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNlcmVzMRgw +FgYDVQRhDA9WQVRFUy1RMjgyNjAwNEoxLDAqBgNVBAMMI0FDIFJBSVogRk5NVC1S +Q00gU0VSVklET1JFUyBTRUdVUk9TMB4XDTE4MTIyMDA5MzczM1oXDTQzMTIyMDA5 +MzczM1oweDELMAkGA1UEBhMCRVMxETAPBgNVBAoMCEZOTVQtUkNNMQ4wDAYDVQQL +DAVDZXJlczEYMBYGA1UEYQwPVkFURVMtUTI4MjYwMDRKMSwwKgYDVQQDDCNBQyBS +QUlaIEZOTVQtUkNNIFNFUlZJRE9SRVMgU0VHVVJPUzB2MBAGByqGSM49AgEGBSuB +BAAiA2IABPa6V1PIyqvfNkpSIeSX0oNnnvBlUdBeh8dHsVnyV0ebAAKTRBdp20LH +sbI6GA60XYyzZl2hNPk2LEnb80b8s0RpRBNm/dfF/a82Tc4DTQdxz69qBdKiQ1oK +Um8BA06Oi6NCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD +VR0OBBYEFAG5L++/EYZg8k/QQW6rcx/n0m5JMAoGCCqGSM49BAMDA2kAMGYCMQCu +SuMrQMN0EfKVrRYj3k4MGuZdpSRea0R7/DjiT8ucRRcRTBQnJlU5dUoDzBOQn5IC +MQD6SmxgiHPz7riYYqnOK8LZiqZwMR2vsJRM60/G49HzYqc8/5MuB1xJAWdpEgJy +v+c= +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign Root R46 O=GlobalSign nv-sa +# Subject: CN=GlobalSign Root R46 O=GlobalSign nv-sa +# Label: "GlobalSign Root R46" +# Serial: 1552617688466950547958867513931858518042577 +# MD5 Fingerprint: c4:14:30:e4:fa:66:43:94:2a:6a:1b:24:5f:19:d0:ef +# SHA1 Fingerprint: 53:a2:b0:4b:ca:6b:d6:45:e6:39:8a:8e:c4:0d:d2:bf:77:c3:a2:90 +# SHA256 Fingerprint: 4f:a3:12:6d:8d:3a:11:d1:c4:85:5a:4f:80:7c:ba:d6:cf:91:9d:3a:5a:88:b0:3b:ea:2c:63:72:d9:3c:40:c9 +-----BEGIN CERTIFICATE----- +MIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAUA +MEYxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYD +VQQDExNHbG9iYWxTaWduIFJvb3QgUjQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMy +MDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYt +c2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCsrHQy6LNl5brtQyYdpokNRbopiLKkHWPd08EsCVeJ +OaFV6Wc0dwxu5FUdUiXSE2te4R2pt32JMl8Nnp8semNgQB+msLZ4j5lUlghYruQG +vGIFAha/r6gjA7aUD7xubMLL1aa7DOn2wQL7Id5m3RerdELv8HQvJfTqa1VbkNud +316HCkD7rRlr+/fKYIje2sGP1q7Vf9Q8g+7XFkyDRTNrJ9CG0Bwta/OrffGFqfUo +0q3v84RLHIf8E6M6cqJaESvWJ3En7YEtbWaBkoe0G1h6zD8K+kZPTXhc+CtI4wSE +y132tGqzZfxCnlEmIyDLPRT5ge1lFgBPGmSXZgjPjHvjK8Cd+RTyG/FWaha/LIWF +zXg4mutCagI0GIMXTpRW+LaCtfOW3T3zvn8gdz57GSNrLNRyc0NXfeD412lPFzYE ++cCQYDdF3uYM2HSNrpyibXRdQr4G9dlkbgIQrImwTDsHTUB+JMWKmIJ5jqSngiCN +I/onccnfxkF0oE32kRbcRoxfKWMxWXEM2G/CtjJ9++ZdU6Z+Ffy7dXxd7Pj2Fxzs +x2sZy/N78CsHpdlseVR2bJ0cpm4O6XkMqCNqo98bMDGfsVR7/mrLZqrcZdCinkqa +ByFrgY/bxFn63iLABJzjqls2k+g9vXqhnQt2sQvHnf3PmKgGwvgqo6GDoLclcqUC +4wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQUA1yrc4GHqMywptWU4jaWSf8FmSwwDQYJKoZIhvcNAQEMBQADggIBAHx4 +7PYCLLtbfpIrXTncvtgdokIzTfnvpCo7RGkerNlFo048p9gkUbJUHJNOxO97k4Vg +JuoJSOD1u8fpaNK7ajFxzHmuEajwmf3lH7wvqMxX63bEIaZHU1VNaL8FpO7XJqti +2kM3S+LGteWygxk6x9PbTZ4IevPuzz5i+6zoYMzRx6Fcg0XERczzF2sUyQQCPtIk +pnnpHs6i58FZFZ8d4kuaPp92CC1r2LpXFNqD6v6MVenQTqnMdzGxRBF6XLE+0xRF +FRhiJBPSy03OXIPBNvIQtQ6IbbjhVp+J3pZmOUdkLG5NrmJ7v2B0GbhWrJKsFjLt +rWhV/pi60zTe9Mlhww6G9kuEYO4Ne7UyWHmRVSyBQ7N0H3qqJZ4d16GLuc1CLgSk +ZoNNiTW2bKg2SnkheCLQQrzRQDGQob4Ez8pn7fXwgNNgyYMqIgXQBztSvwyeqiv5 +u+YfjyW6hY0XHgL+XVAEV8/+LbzvXMAaq7afJMbfc2hIkCwU9D9SGuTSyxTDYWnP +4vkYxboznxSjBF25cfe1lNj2M8FawTSLfJvdkzrnE6JwYZ+vj+vYxXX4M2bUdGc6 +N3ec592kD3ZDZopD8p/7DEJ4Y9HiD2971KE9dJeFt0g5QdYg/NA6s/rob8SKunE3 +vouXsXgxT7PntgMTzlSdriVZzH81Xwj3QEUxeCp6 +-----END CERTIFICATE----- + +# Issuer: CN=GlobalSign Root E46 O=GlobalSign nv-sa +# Subject: CN=GlobalSign Root E46 O=GlobalSign nv-sa +# Label: "GlobalSign Root E46" +# Serial: 1552617690338932563915843282459653771421763 +# MD5 Fingerprint: b5:b8:66:ed:de:08:83:e3:c9:e2:01:34:06:ac:51:6f +# SHA1 Fingerprint: 39:b4:6c:d5:fe:80:06:eb:e2:2f:4a:bb:08:33:a0:af:db:b9:dd:84 +# SHA256 Fingerprint: cb:b9:c4:4d:84:b8:04:3e:10:50:ea:31:a6:9f:51:49:55:d7:bf:d2:e2:c6:b4:93:01:01:9a:d6:1d:9f:50:58 +-----BEGIN CERTIFICATE----- +MIICCzCCAZGgAwIBAgISEdK7ujNu1LzmJGjFDYQdmOhDMAoGCCqGSM49BAMDMEYx +CzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQD +ExNHbG9iYWxTaWduIFJvb3QgRTQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAw +MDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2Ex +HDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUrgQQA +IgNiAAScDrHPt+ieUnd1NPqlRqetMhkytAepJ8qUuwzSChDH2omwlwxwEwkBjtjq +R+q+soArzfwoDdusvKSGN+1wCAB16pMLey5SnCNoIwZD7JIvU4Tb+0cUB+hflGdd +yXqBPCCjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud +DgQWBBQxCpCPtsad0kRLgLWi5h+xEk8blTAKBggqhkjOPQQDAwNoADBlAjEA31SQ +7Zvvi5QCkxeCmb6zniz2C5GMn0oUsfZkvLtoURMMA/cVi4RguYv/Uo7njLwcAjA8 ++RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+CAezNIm8BZ/3Hobui3A= +-----END CERTIFICATE----- + +# Issuer: CN=GLOBALTRUST 2020 O=e-commerce monitoring GmbH +# Subject: CN=GLOBALTRUST 2020 O=e-commerce monitoring GmbH +# Label: "GLOBALTRUST 2020" +# Serial: 109160994242082918454945253 +# MD5 Fingerprint: 8a:c7:6f:cb:6d:e3:cc:a2:f1:7c:83:fa:0e:78:d7:e8 +# SHA1 Fingerprint: d0:67:c1:13:51:01:0c:aa:d0:c7:6a:65:37:31:16:26:4f:53:71:a2 +# SHA256 Fingerprint: 9a:29:6a:51:82:d1:d4:51:a2:e3:7f:43:9b:74:da:af:a2:67:52:33:29:f9:0f:9a:0d:20:07:c3:34:e2:3c:9a +-----BEGIN CERTIFICATE----- +MIIFgjCCA2qgAwIBAgILWku9WvtPilv6ZeUwDQYJKoZIhvcNAQELBQAwTTELMAkG +A1UEBhMCQVQxIzAhBgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkw +FwYDVQQDExBHTE9CQUxUUlVTVCAyMDIwMB4XDTIwMDIxMDAwMDAwMFoXDTQwMDYx +MDAwMDAwMFowTTELMAkGA1UEBhMCQVQxIzAhBgNVBAoTGmUtY29tbWVyY2UgbW9u +aXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVTVCAyMDIwMIICIjANBgkq +hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAri5WrRsc7/aVj6B3GyvTY4+ETUWiD59b +RatZe1E0+eyLinjF3WuvvcTfk0Uev5E4C64OFudBc/jbu9G4UeDLgztzOG53ig9Z +YybNpyrOVPu44sB8R85gfD+yc/LAGbaKkoc1DZAoouQVBGM+uq/ufF7MpotQsjj3 +QWPKzv9pj2gOlTblzLmMCcpL3TGQlsjMH/1WljTbjhzqLL6FLmPdqqmV0/0plRPw +yJiT2S0WR5ARg6I6IqIoV6Lr/sCMKKCmfecqQjuCgGOlYx8ZzHyyZqjC0203b+J+ +BlHZRYQfEs4kUmSFC0iAToexIiIwquuuvuAC4EDosEKAA1GqtH6qRNdDYfOiaxaJ +SaSjpCuKAsR49GiKweR6NrFvG5Ybd0mN1MkGco/PU+PcF4UgStyYJ9ORJitHHmkH +r96i5OTUawuzXnzUJIBHKWk7buis/UDr2O1xcSvy6Fgd60GXIsUf1DnQJ4+H4xj0 +4KlGDfV0OoIu0G4skaMxXDtG6nsEEFZegB31pWXogvziB4xiRfUg3kZwhqG8k9Me +dKZssCz3AwyIDMvUclOGvGBG85hqwvG/Q/lwIHfKN0F5VVJjjVsSn8VoxIidrPIw +q7ejMZdnrY8XD2zHc+0klGvIg5rQmjdJBKuxFshsSUktq6HQjJLyQUp5ISXbY9e2 +nKd+Qmn7OmMCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwHQYDVR0OBBYEFNwuH9FhN3nkq9XVsxJxaD1qaJwiMB8GA1UdIwQYMBaAFNwu +H9FhN3nkq9XVsxJxaD1qaJwiMA0GCSqGSIb3DQEBCwUAA4ICAQCR8EICaEDuw2jA +VC/f7GLDw56KoDEoqoOOpFaWEhCGVrqXctJUMHytGdUdaG/7FELYjQ7ztdGl4wJC +XtzoRlgHNQIw4Lx0SsFDKv/bGtCwr2zD/cuz9X9tAy5ZVp0tLTWMstZDFyySCstd +6IwPS3BD0IL/qMy/pJTAvoe9iuOTe8aPmxadJ2W8esVCgmxcB9CpwYhgROmYhRZf ++I/KARDOJcP5YBugxZfD0yyIMaK9MOzQ0MAS8cE54+X1+NZK3TTN+2/BT+MAi1bi +kvcoskJ3ciNnxz8RFbLEAwW+uxF7Cr+obuf/WEPPm2eggAe2HcqtbepBEX4tdJP7 +wry+UUTF72glJ4DjyKDUEuzZpTcdN3y0kcra1LGWge9oXHYQSa9+pTeAsRxSvTOB +TI/53WXZFM2KJVj04sWDpQmQ1GwUY7VA3+vA/MRYfg0UFodUJ25W5HCEuGwyEn6C +MUO+1918oa2u1qsgEu8KwxCMSZY13At1XrFP1U80DhEgB3VDRemjEdqso5nCtnkn +4rnvyOL2NSl6dPrFf4IFYqYK6miyeUcGbvJXqBUzxvd4Sj1Ce2t+/vdG6tHrju+I +aFvowdlxfv1k7/9nR4hYJS8+hge9+6jlgqispdNpQ80xiEmEU5LAsTkbOYMBMMTy +qfrQA71yN2BWHzZ8vTmR9W0Nv3vXkg== +-----END CERTIFICATE----- + +# Issuer: CN=ANF Secure Server Root CA O=ANF Autoridad de Certificacion OU=ANF CA Raiz +# Subject: CN=ANF Secure Server Root CA O=ANF Autoridad de Certificacion OU=ANF CA Raiz +# Label: "ANF Secure Server Root CA" +# Serial: 996390341000653745 +# MD5 Fingerprint: 26:a6:44:5a:d9:af:4e:2f:b2:1d:b6:65:b0:4e:e8:96 +# SHA1 Fingerprint: 5b:6e:68:d0:cc:15:b6:a0:5f:1e:c1:5f:ae:02:fc:6b:2f:5d:6f:74 +# SHA256 Fingerprint: fb:8f:ec:75:91:69:b9:10:6b:1e:51:16:44:c6:18:c5:13:04:37:3f:6c:06:43:08:8d:8b:ef:fd:1b:99:75:99 +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- + +# Issuer: CN=Certum EC-384 CA O=Asseco Data Systems S.A. OU=Certum Certification Authority +# Subject: CN=Certum EC-384 CA O=Asseco Data Systems S.A. OU=Certum Certification Authority +# Label: "Certum EC-384 CA" +# Serial: 160250656287871593594747141429395092468 +# MD5 Fingerprint: b6:65:b3:96:60:97:12:a1:ec:4e:e1:3d:a3:c6:c9:f1 +# SHA1 Fingerprint: f3:3e:78:3c:ac:df:f4:a2:cc:ac:67:55:69:56:d7:e5:16:3c:e1:ed +# SHA256 Fingerprint: 6b:32:80:85:62:53:18:aa:50:d1:73:c9:8d:8b:da:09:d5:7e:27:41:3d:11:4c:f7:87:a0:f5:d0:6c:03:0c:f6 +-----BEGIN CERTIFICATE----- +MIICZTCCAeugAwIBAgIQeI8nXIESUiClBNAt3bpz9DAKBggqhkjOPQQDAzB0MQsw +CQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScw +JQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAXBgNVBAMT +EENlcnR1bSBFQy0zODQgQ0EwHhcNMTgwMzI2MDcyNDU0WhcNNDMwMzI2MDcyNDU0 +WjB0MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBT +LkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAX +BgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATE +KI6rGFtqvm5kN2PkzeyrOvfMobgOgknXhimfoZTy42B4mIF4Bk3y7JoOV2CDn7Tm +Fy8as10CW4kjPMIRBSqniBMY81CE1700LCeJVf/OTOffph8oxPBUw7l8t1Ot68Kj +QjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI0GZnQkdjrzife81r1HfS+8 +EF9LMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNoADBlAjADVS2m5hjEfO/J +UG7BJw+ch69u1RsIGL2SKcHvlJF40jocVYli5RsJHrpka/F2tNQCMQC0QoSZ/6vn +nvuRlydd3LBbMHHOXjgaatkl5+r3YZJW+OraNsKHZZYuciUvf9/DE8k= +-----END CERTIFICATE----- + +# Issuer: CN=Certum Trusted Root CA O=Asseco Data Systems S.A. OU=Certum Certification Authority +# Subject: CN=Certum Trusted Root CA O=Asseco Data Systems S.A. OU=Certum Certification Authority +# Label: "Certum Trusted Root CA" +# Serial: 40870380103424195783807378461123655149 +# MD5 Fingerprint: 51:e1:c2:e7:fe:4c:84:af:59:0e:2f:f4:54:6f:ea:29 +# SHA1 Fingerprint: c8:83:44:c0:18:ae:9f:cc:f1:87:b7:8f:22:d1:c5:d7:45:84:ba:e5 +# SHA256 Fingerprint: fe:76:96:57:38:55:77:3e:37:a9:5e:7a:d4:d9:cc:96:c3:01:57:c1:5d:31:76:5b:a9:b1:57:04:e1:ae:78:fd +-----BEGIN CERTIFICATE----- +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 +-----END CERTIFICATE----- diff --git a/venv/lib/python3.8/site-packages/certifi/core.py b/venv/lib/python3.8/site-packages/certifi/core.py new file mode 100644 index 0000000..5d2b8cd --- /dev/null +++ b/venv/lib/python3.8/site-packages/certifi/core.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- + +""" +certifi.py +~~~~~~~~~~ + +This module returns the installation location of cacert.pem or its contents. +""" +import os + +try: + from importlib.resources import path as get_path, read_text + + _CACERT_CTX = None + _CACERT_PATH = None + + def where(): + # This is slightly terrible, but we want to delay extracting the file + # in cases where we're inside of a zipimport situation until someone + # actually calls where(), but we don't want to re-extract the file + # on every call of where(), so we'll do it once then store it in a + # global variable. + global _CACERT_CTX + global _CACERT_PATH + if _CACERT_PATH is None: + # This is slightly janky, the importlib.resources API wants you to + # manage the cleanup of this file, so it doesn't actually return a + # path, it returns a context manager that will give you the path + # when you enter it and will do any cleanup when you leave it. In + # the common case of not needing a temporary file, it will just + # return the file system location and the __exit__() is a no-op. + # + # We also have to hold onto the actual context manager, because + # it will do the cleanup whenever it gets garbage collected, so + # we will also store that at the global level as well. + _CACERT_CTX = get_path("certifi", "cacert.pem") + _CACERT_PATH = str(_CACERT_CTX.__enter__()) + + return _CACERT_PATH + + +except ImportError: + # This fallback will work for Python versions prior to 3.7 that lack the + # importlib.resources module but relies on the existing `where` function + # so won't address issues with environments like PyOxidizer that don't set + # __file__ on modules. + def read_text(_module, _path, encoding="ascii"): + with open(where(), "r", encoding=encoding) as data: + return data.read() + + # If we don't have importlib.resources, then we will just do the old logic + # of assuming we're on the filesystem and munge the path directly. + def where(): + f = os.path.dirname(__file__) + + return os.path.join(f, "cacert.pem") + + +def contents(): + return read_text("certifi", "cacert.pem", encoding="ascii") diff --git a/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/INSTALLER b/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/LICENSE b/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/LICENSE new file mode 100644 index 0000000..8add30a --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/LICENSE @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/METADATA b/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/METADATA new file mode 100644 index 0000000..590bcc3 --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/METADATA @@ -0,0 +1,101 @@ +Metadata-Version: 2.1 +Name: chardet +Version: 4.0.0 +Summary: Universal encoding detector for Python 2 and 3 +Home-page: https://github.com/chardet/chardet +Author: Mark Pilgrim +Author-email: mark@diveintomark.org +Maintainer: Daniel Blanchard +Maintainer-email: dan.blanchard@gmail.com +License: LGPL +Keywords: encoding,i18n,xml +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL) +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.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 +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: Text Processing :: Linguistic +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.* + +Chardet: The Universal Character Encoding Detector +-------------------------------------------------- + +.. image:: https://img.shields.io/travis/chardet/chardet/stable.svg + :alt: Build status + :target: https://travis-ci.org/chardet/chardet + +.. image:: https://img.shields.io/coveralls/chardet/chardet/stable.svg + :target: https://coveralls.io/r/chardet/chardet + +.. image:: https://img.shields.io/pypi/v/chardet.svg + :target: https://warehouse.python.org/project/chardet/ + :alt: Latest version on PyPI + +.. image:: https://img.shields.io/pypi/l/chardet.svg + :alt: License + + +Detects + - ASCII, UTF-8, UTF-16 (2 variants), UTF-32 (4 variants) + - Big5, GB2312, EUC-TW, HZ-GB-2312, ISO-2022-CN (Traditional and Simplified Chinese) + - EUC-JP, SHIFT_JIS, CP932, ISO-2022-JP (Japanese) + - EUC-KR, ISO-2022-KR (Korean) + - KOI8-R, MacCyrillic, IBM855, IBM866, ISO-8859-5, windows-1251 (Cyrillic) + - ISO-8859-5, windows-1251 (Bulgarian) + - ISO-8859-1, windows-1252 (Western European languages) + - ISO-8859-7, windows-1253 (Greek) + - ISO-8859-8, windows-1255 (Visual and Logical Hebrew) + - TIS-620 (Thai) + +.. note:: + Our ISO-8859-2 and windows-1250 (Hungarian) probers have been temporarily + disabled until we can retrain the models. + +Requires Python 2.7 or 3.5+. + +Installation +------------ + +Install from `PyPI `_:: + + pip install chardet + +Documentation +------------- + +For users, docs are now available at https://chardet.readthedocs.io/. + +Command-line Tool +----------------- + +chardet comes with a command-line script which reports on the encodings of one +or more files:: + + % chardetect somefile someotherfile + somefile: windows-1252 with confidence 0.5 + someotherfile: ascii with confidence 1.0 + +About +----- + +This is a continuation of Mark Pilgrim's excellent chardet. Previously, two +versions needed to be maintained: one that supported python 2.x and one that +supported python 3.x. We've recently merged with `Ian Cordasco `_'s +`charade `_ fork, so now we have one +coherent version that works for Python 2.7+ and 3.4+. + +:maintainer: Dan Blanchard + + diff --git a/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/RECORD b/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/RECORD new file mode 100644 index 0000000..4c99f45 --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/RECORD @@ -0,0 +1,94 @@ +../../../bin/chardetect,sha256=iZ9vjG7hdTs6_ydzR-AuZRrpNSZn1GEHJdPYHbCr98k,256 +chardet-4.0.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +chardet-4.0.0.dist-info/LICENSE,sha256=YJXp_6d33SKDn3gBqoRbMcntB_PWv4om3F0t7IzMDvM,26432 +chardet-4.0.0.dist-info/METADATA,sha256=ySYQAE7NPm3LwxgMqFi1zdLQ48mmwMbrJwqAWCtcbH8,3526 +chardet-4.0.0.dist-info/RECORD,, +chardet-4.0.0.dist-info/WHEEL,sha256=ADKeyaGyKF5DwBNE0sRE5pvW-bSkFMJfBuhzZ3rceP4,110 +chardet-4.0.0.dist-info/entry_points.txt,sha256=fAMmhu5eJ-zAJ-smfqQwRClQ3-nozOCmvJ6-E8lgGJo,60 +chardet-4.0.0.dist-info/top_level.txt,sha256=AowzBbZy4x8EirABDdJSLJZMkJ_53iIag8xfKR6D7kI,8 +chardet/__init__.py,sha256=mWZaWmvZkhwfBEAT9O1Y6nRTfKzhT7FHhQTTAujbqUA,3271 +chardet/__pycache__/__init__.cpython-38.pyc,, +chardet/__pycache__/big5freq.cpython-38.pyc,, +chardet/__pycache__/big5prober.cpython-38.pyc,, +chardet/__pycache__/chardistribution.cpython-38.pyc,, +chardet/__pycache__/charsetgroupprober.cpython-38.pyc,, +chardet/__pycache__/charsetprober.cpython-38.pyc,, +chardet/__pycache__/codingstatemachine.cpython-38.pyc,, +chardet/__pycache__/compat.cpython-38.pyc,, +chardet/__pycache__/cp949prober.cpython-38.pyc,, +chardet/__pycache__/enums.cpython-38.pyc,, +chardet/__pycache__/escprober.cpython-38.pyc,, +chardet/__pycache__/escsm.cpython-38.pyc,, +chardet/__pycache__/eucjpprober.cpython-38.pyc,, +chardet/__pycache__/euckrfreq.cpython-38.pyc,, +chardet/__pycache__/euckrprober.cpython-38.pyc,, +chardet/__pycache__/euctwfreq.cpython-38.pyc,, +chardet/__pycache__/euctwprober.cpython-38.pyc,, +chardet/__pycache__/gb2312freq.cpython-38.pyc,, +chardet/__pycache__/gb2312prober.cpython-38.pyc,, +chardet/__pycache__/hebrewprober.cpython-38.pyc,, +chardet/__pycache__/jisfreq.cpython-38.pyc,, +chardet/__pycache__/jpcntx.cpython-38.pyc,, +chardet/__pycache__/langbulgarianmodel.cpython-38.pyc,, +chardet/__pycache__/langgreekmodel.cpython-38.pyc,, +chardet/__pycache__/langhebrewmodel.cpython-38.pyc,, +chardet/__pycache__/langhungarianmodel.cpython-38.pyc,, +chardet/__pycache__/langrussianmodel.cpython-38.pyc,, +chardet/__pycache__/langthaimodel.cpython-38.pyc,, +chardet/__pycache__/langturkishmodel.cpython-38.pyc,, +chardet/__pycache__/latin1prober.cpython-38.pyc,, +chardet/__pycache__/mbcharsetprober.cpython-38.pyc,, +chardet/__pycache__/mbcsgroupprober.cpython-38.pyc,, +chardet/__pycache__/mbcssm.cpython-38.pyc,, +chardet/__pycache__/sbcharsetprober.cpython-38.pyc,, +chardet/__pycache__/sbcsgroupprober.cpython-38.pyc,, +chardet/__pycache__/sjisprober.cpython-38.pyc,, +chardet/__pycache__/universaldetector.cpython-38.pyc,, +chardet/__pycache__/utf8prober.cpython-38.pyc,, +chardet/__pycache__/version.cpython-38.pyc,, +chardet/big5freq.py,sha256=D_zK5GyzoVsRes0HkLJziltFQX0bKCLOrFe9_xDvO_8,31254 +chardet/big5prober.py,sha256=kBxHbdetBpPe7xrlb-e990iot64g_eGSLd32lB7_h3M,1757 +chardet/chardistribution.py,sha256=3woWS62KrGooKyqz4zQSnjFbJpa6V7g02daAibTwcl8,9411 +chardet/charsetgroupprober.py,sha256=GZLReHP6FRRn43hvSOoGCxYamErKzyp6RgOQxVeC3kg,3839 +chardet/charsetprober.py,sha256=KSmwJErjypyj0bRZmC5F5eM7c8YQgLYIjZXintZNstg,5110 +chardet/cli/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1 +chardet/cli/__pycache__/__init__.cpython-38.pyc,, +chardet/cli/__pycache__/chardetect.cpython-38.pyc,, +chardet/cli/chardetect.py,sha256=kUPeQCi-olObXpOq5MtlKuBn1EU19rkeenAMwxl7URY,2711 +chardet/codingstatemachine.py,sha256=VYp_6cyyki5sHgXDSZnXW4q1oelHc3cu9AyQTX7uug8,3590 +chardet/compat.py,sha256=40zr6wICZwknxyuLGGcIOPyve8DTebBCbbvttvnmp5Q,1200 +chardet/cp949prober.py,sha256=TZ434QX8zzBsnUvL_8wm4AQVTZ2ZkqEEQL_lNw9f9ow,1855 +chardet/enums.py,sha256=Aimwdb9as1dJKZaFNUH2OhWIVBVd6ZkJJ_WK5sNY8cU,1661 +chardet/escprober.py,sha256=kkyqVg1Yw3DIOAMJ2bdlyQgUFQhuHAW8dUGskToNWSc,3950 +chardet/escsm.py,sha256=RuXlgNvTIDarndvllNCk5WZBIpdCxQ0kcd9EAuxUh84,10510 +chardet/eucjpprober.py,sha256=iD8Jdp0ISRjgjiVN7f0e8xGeQJ5GM2oeZ1dA8nbSeUw,3749 +chardet/euckrfreq.py,sha256=-7GdmvgWez4-eO4SuXpa7tBiDi5vRXQ8WvdFAzVaSfo,13546 +chardet/euckrprober.py,sha256=MqFMTQXxW4HbzIpZ9lKDHB3GN8SP4yiHenTmf8g_PxY,1748 +chardet/euctwfreq.py,sha256=No1WyduFOgB5VITUA7PLyC5oJRNzRyMbBxaKI1l16MA,31621 +chardet/euctwprober.py,sha256=13p6EP4yRaxqnP4iHtxHOJ6R2zxHq1_m8hTRjzVZ95c,1747 +chardet/gb2312freq.py,sha256=JX8lsweKLmnCwmk8UHEQsLgkr_rP_kEbvivC4qPOrlc,20715 +chardet/gb2312prober.py,sha256=gGvIWi9WhDjE-xQXHvNIyrnLvEbMAYgyUSZ65HUfylw,1754 +chardet/hebrewprober.py,sha256=c3SZ-K7hvyzGY6JRAZxJgwJ_sUS9k0WYkvMY00YBYFo,13838 +chardet/jisfreq.py,sha256=vpmJv2Bu0J8gnMVRPHMFefTRvo_ha1mryLig8CBwgOg,25777 +chardet/jpcntx.py,sha256=PYlNqRUQT8LM3cT5FmHGP0iiscFlTWED92MALvBungo,19643 +chardet/langbulgarianmodel.py,sha256=r6tvOtO8FqhnbWBB5V4czcl1fWM4pB9lGiWQU-8gvsw,105685 +chardet/langgreekmodel.py,sha256=1cMu2wUgPB8bQ2RbVjR4LNwCCETgQ-Dwo0Eg2_uB11s,99559 +chardet/langhebrewmodel.py,sha256=urMmJHHIXtCwaWAqy1zEY_4SmwwNzt730bDOtjXzRjs,98764 +chardet/langhungarianmodel.py,sha256=ODAisvqCfes8B4FeyM_Pg9HY3ZDnEyaCiT4Bxyzoc6w,102486 +chardet/langrussianmodel.py,sha256=sPqkrBbX0QVwwy6oqRl-x7ERv2J4-zaMoCvLpkSsSJI,131168 +chardet/langthaimodel.py,sha256=ppoKOGL9OPdj9A4CUyG8R48zbnXt9MN1WXeCYepa6sc,103300 +chardet/langturkishmodel.py,sha256=H3ldicI_rhlv0r3VFpVWtUL6X30Wy596v7_YHz2sEdg,95934 +chardet/latin1prober.py,sha256=S2IoORhFk39FEFOlSFWtgVybRiP6h7BlLldHVclNkU8,5370 +chardet/mbcharsetprober.py,sha256=AR95eFH9vuqSfvLQZN-L5ijea25NOBCoXqw8s5O9xLQ,3413 +chardet/mbcsgroupprober.py,sha256=h6TRnnYq2OxG1WdD5JOyxcdVpn7dG0q-vB8nWr5mbh4,2012 +chardet/mbcssm.py,sha256=SY32wVIF3HzcjY3BaEspy9metbNSKxIIB0RKPn7tjpI,25481 +chardet/metadata/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +chardet/metadata/__pycache__/__init__.cpython-38.pyc,, +chardet/metadata/__pycache__/languages.cpython-38.pyc,, +chardet/metadata/languages.py,sha256=41tLq3eLSrBEbEVVQpVGFq9K7o1ln9b1HpY1l0hCUQo,19474 +chardet/sbcharsetprober.py,sha256=nmyMyuxzG87DN6K3Rk2MUzJLMLR69MrWpdnHzOwVUwQ,6136 +chardet/sbcsgroupprober.py,sha256=hqefQuXmiFyDBArOjujH6hd6WFXlOD1kWCsxDhjx5Vc,4309 +chardet/sjisprober.py,sha256=IIt-lZj0WJqK4rmUZzKZP4GJlE8KUEtFYVuY96ek5MQ,3774 +chardet/universaldetector.py,sha256=DpZTXCX0nUHXxkQ9sr4GZxGB_hveZ6hWt3uM94cgWKs,12503 +chardet/utf8prober.py,sha256=IdD8v3zWOsB8OLiyPi-y_fqwipRFxV9Nc1eKBLSuIEw,2766 +chardet/version.py,sha256=A4CILFAd8MRVG1HoXPp45iK9RLlWyV73a1EtwE8Tvn8,242 diff --git a/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/WHEEL b/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/WHEEL new file mode 100644 index 0000000..6d38aa0 --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.35.1) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/entry_points.txt b/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/entry_points.txt new file mode 100644 index 0000000..a884269 --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/entry_points.txt @@ -0,0 +1,3 @@ +[console_scripts] +chardetect = chardet.cli.chardetect:main + diff --git a/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/top_level.txt b/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/top_level.txt new file mode 100644 index 0000000..79236f2 --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/top_level.txt @@ -0,0 +1 @@ +chardet diff --git a/venv/lib/python3.8/site-packages/chardet/__init__.py b/venv/lib/python3.8/site-packages/chardet/__init__.py new file mode 100644 index 0000000..80ad254 --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/__init__.py @@ -0,0 +1,83 @@ +######################## BEGIN LICENSE BLOCK ######################## +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + + +from .universaldetector import UniversalDetector +from .enums import InputState +from .version import __version__, VERSION + + +__all__ = ['UniversalDetector', 'detect', 'detect_all', '__version__', 'VERSION'] + + +def detect(byte_str): + """ + Detect the encoding of the given byte string. + + :param byte_str: The byte sequence to examine. + :type byte_str: ``bytes`` or ``bytearray`` + """ + if not isinstance(byte_str, bytearray): + if not isinstance(byte_str, bytes): + raise TypeError('Expected object of type bytes or bytearray, got: ' + '{}'.format(type(byte_str))) + else: + byte_str = bytearray(byte_str) + detector = UniversalDetector() + detector.feed(byte_str) + return detector.close() + + +def detect_all(byte_str): + """ + Detect all the possible encodings of the given byte string. + + :param byte_str: The byte sequence to examine. + :type byte_str: ``bytes`` or ``bytearray`` + """ + if not isinstance(byte_str, bytearray): + if not isinstance(byte_str, bytes): + raise TypeError('Expected object of type bytes or bytearray, got: ' + '{}'.format(type(byte_str))) + else: + byte_str = bytearray(byte_str) + + detector = UniversalDetector() + detector.feed(byte_str) + detector.close() + + if detector._input_state == InputState.HIGH_BYTE: + results = [] + for prober in detector._charset_probers: + if prober.get_confidence() > detector.MINIMUM_THRESHOLD: + charset_name = prober.charset_name + lower_charset_name = prober.charset_name.lower() + # Use Windows encoding name instead of ISO-8859 if we saw any + # extra Windows-specific bytes + if lower_charset_name.startswith('iso-8859'): + if detector._has_win_bytes: + charset_name = detector.ISO_WIN_MAP.get(lower_charset_name, + charset_name) + results.append({ + 'encoding': charset_name, + 'confidence': prober.get_confidence(), + 'language': prober.language, + }) + if len(results) > 0: + return sorted(results, key=lambda result: -result['confidence']) + + return [detector.result] diff --git a/venv/lib/python3.8/site-packages/chardet/big5freq.py b/venv/lib/python3.8/site-packages/chardet/big5freq.py new file mode 100644 index 0000000..38f3251 --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/big5freq.py @@ -0,0 +1,386 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# Big5 frequency table +# by Taiwan's Mandarin Promotion Council +# +# +# 128 --> 0.42261 +# 256 --> 0.57851 +# 512 --> 0.74851 +# 1024 --> 0.89384 +# 2048 --> 0.97583 +# +# Ideal Distribution Ratio = 0.74851/(1-0.74851) =2.98 +# Random Distribution Ration = 512/(5401-512)=0.105 +# +# Typical Distribution Ratio about 25% of Ideal one, still much higher than RDR + +BIG5_TYPICAL_DISTRIBUTION_RATIO = 0.75 + +#Char to FreqOrder table +BIG5_TABLE_SIZE = 5376 + +BIG5_CHAR_TO_FREQ_ORDER = ( + 1,1801,1506, 255,1431, 198, 9, 82, 6,5008, 177, 202,3681,1256,2821, 110, # 16 +3814, 33,3274, 261, 76, 44,2114, 16,2946,2187,1176, 659,3971, 26,3451,2653, # 32 +1198,3972,3350,4202, 410,2215, 302, 590, 361,1964, 8, 204, 58,4510,5009,1932, # 48 + 63,5010,5011, 317,1614, 75, 222, 159,4203,2417,1480,5012,3555,3091, 224,2822, # 64 +3682, 3, 10,3973,1471, 29,2787,1135,2866,1940, 873, 130,3275,1123, 312,5013, # 80 +4511,2052, 507, 252, 682,5014, 142,1915, 124, 206,2947, 34,3556,3204, 64, 604, # 96 +5015,2501,1977,1978, 155,1991, 645, 641,1606,5016,3452, 337, 72, 406,5017, 80, # 112 + 630, 238,3205,1509, 263, 939,1092,2654, 756,1440,1094,3453, 449, 69,2987, 591, # 128 + 179,2096, 471, 115,2035,1844, 60, 50,2988, 134, 806,1869, 734,2036,3454, 180, # 144 + 995,1607, 156, 537,2907, 688,5018, 319,1305, 779,2145, 514,2379, 298,4512, 359, # 160 +2502, 90,2716,1338, 663, 11, 906,1099,2553, 20,2441, 182, 532,1716,5019, 732, # 176 +1376,4204,1311,1420,3206, 25,2317,1056, 113, 399, 382,1950, 242,3455,2474, 529, # 192 +3276, 475,1447,3683,5020, 117, 21, 656, 810,1297,2300,2334,3557,5021, 126,4205, # 208 + 706, 456, 150, 613,4513, 71,1118,2037,4206, 145,3092, 85, 835, 486,2115,1246, # 224 +1426, 428, 727,1285,1015, 800, 106, 623, 303,1281,5022,2128,2359, 347,3815, 221, # 240 +3558,3135,5023,1956,1153,4207, 83, 296,1199,3093, 192, 624, 93,5024, 822,1898, # 256 +2823,3136, 795,2065, 991,1554,1542,1592, 27, 43,2867, 859, 139,1456, 860,4514, # 272 + 437, 712,3974, 164,2397,3137, 695, 211,3037,2097, 195,3975,1608,3559,3560,3684, # 288 +3976, 234, 811,2989,2098,3977,2233,1441,3561,1615,2380, 668,2077,1638, 305, 228, # 304 +1664,4515, 467, 415,5025, 262,2099,1593, 239, 108, 300, 200,1033, 512,1247,2078, # 320 +5026,5027,2176,3207,3685,2682, 593, 845,1062,3277, 88,1723,2038,3978,1951, 212, # 336 + 266, 152, 149, 468,1899,4208,4516, 77, 187,5028,3038, 37, 5,2990,5029,3979, # 352 +5030,5031, 39,2524,4517,2908,3208,2079, 55, 148, 74,4518, 545, 483,1474,1029, # 368 +1665, 217,1870,1531,3138,1104,2655,4209, 24, 172,3562, 900,3980,3563,3564,4519, # 384 + 32,1408,2824,1312, 329, 487,2360,2251,2717, 784,2683, 4,3039,3351,1427,1789, # 400 + 188, 109, 499,5032,3686,1717,1790, 888,1217,3040,4520,5033,3565,5034,3352,1520, # 416 +3687,3981, 196,1034, 775,5035,5036, 929,1816, 249, 439, 38,5037,1063,5038, 794, # 432 +3982,1435,2301, 46, 178,3278,2066,5039,2381,5040, 214,1709,4521, 804, 35, 707, # 448 + 324,3688,1601,2554, 140, 459,4210,5041,5042,1365, 839, 272, 978,2262,2580,3456, # 464 +2129,1363,3689,1423, 697, 100,3094, 48, 70,1231, 495,3139,2196,5043,1294,5044, # 480 +2080, 462, 586,1042,3279, 853, 256, 988, 185,2382,3457,1698, 434,1084,5045,3458, # 496 + 314,2625,2788,4522,2335,2336, 569,2285, 637,1817,2525, 757,1162,1879,1616,3459, # 512 + 287,1577,2116, 768,4523,1671,2868,3566,2526,1321,3816, 909,2418,5046,4211, 933, # 528 +3817,4212,2053,2361,1222,4524, 765,2419,1322, 786,4525,5047,1920,1462,1677,2909, # 544 +1699,5048,4526,1424,2442,3140,3690,2600,3353,1775,1941,3460,3983,4213, 309,1369, # 560 +1130,2825, 364,2234,1653,1299,3984,3567,3985,3986,2656, 525,1085,3041, 902,2001, # 576 +1475, 964,4527, 421,1845,1415,1057,2286, 940,1364,3141, 376,4528,4529,1381, 7, # 592 +2527, 983,2383, 336,1710,2684,1846, 321,3461, 559,1131,3042,2752,1809,1132,1313, # 608 + 265,1481,1858,5049, 352,1203,2826,3280, 167,1089, 420,2827, 776, 792,1724,3568, # 624 +4214,2443,3281,5050,4215,5051, 446, 229, 333,2753, 901,3818,1200,1557,4530,2657, # 640 +1921, 395,2754,2685,3819,4216,1836, 125, 916,3209,2626,4531,5052,5053,3820,5054, # 656 +5055,5056,4532,3142,3691,1133,2555,1757,3462,1510,2318,1409,3569,5057,2146, 438, # 672 +2601,2910,2384,3354,1068, 958,3043, 461, 311,2869,2686,4217,1916,3210,4218,1979, # 688 + 383, 750,2755,2627,4219, 274, 539, 385,1278,1442,5058,1154,1965, 384, 561, 210, # 704 + 98,1295,2556,3570,5059,1711,2420,1482,3463,3987,2911,1257, 129,5060,3821, 642, # 720 + 523,2789,2790,2658,5061, 141,2235,1333, 68, 176, 441, 876, 907,4220, 603,2602, # 736 + 710, 171,3464, 404, 549, 18,3143,2398,1410,3692,1666,5062,3571,4533,2912,4534, # 752 +5063,2991, 368,5064, 146, 366, 99, 871,3693,1543, 748, 807,1586,1185, 22,2263, # 768 + 379,3822,3211,5065,3212, 505,1942,2628,1992,1382,2319,5066, 380,2362, 218, 702, # 784 +1818,1248,3465,3044,3572,3355,3282,5067,2992,3694, 930,3283,3823,5068, 59,5069, # 800 + 585, 601,4221, 497,3466,1112,1314,4535,1802,5070,1223,1472,2177,5071, 749,1837, # 816 + 690,1900,3824,1773,3988,1476, 429,1043,1791,2236,2117, 917,4222, 447,1086,1629, # 832 +5072, 556,5073,5074,2021,1654, 844,1090, 105, 550, 966,1758,2828,1008,1783, 686, # 848 +1095,5075,2287, 793,1602,5076,3573,2603,4536,4223,2948,2302,4537,3825, 980,2503, # 864 + 544, 353, 527,4538, 908,2687,2913,5077, 381,2629,1943,1348,5078,1341,1252, 560, # 880 +3095,5079,3467,2870,5080,2054, 973, 886,2081, 143,4539,5081,5082, 157,3989, 496, # 896 +4224, 57, 840, 540,2039,4540,4541,3468,2118,1445, 970,2264,1748,1966,2082,4225, # 912 +3144,1234,1776,3284,2829,3695, 773,1206,2130,1066,2040,1326,3990,1738,1725,4226, # 928 + 279,3145, 51,1544,2604, 423,1578,2131,2067, 173,4542,1880,5083,5084,1583, 264, # 944 + 610,3696,4543,2444, 280, 154,5085,5086,5087,1739, 338,1282,3096, 693,2871,1411, # 960 +1074,3826,2445,5088,4544,5089,5090,1240, 952,2399,5091,2914,1538,2688, 685,1483, # 976 +4227,2475,1436, 953,4228,2055,4545, 671,2400, 79,4229,2446,3285, 608, 567,2689, # 992 +3469,4230,4231,1691, 393,1261,1792,2401,5092,4546,5093,5094,5095,5096,1383,1672, # 1008 +3827,3213,1464, 522,1119, 661,1150, 216, 675,4547,3991,1432,3574, 609,4548,2690, # 1024 +2402,5097,5098,5099,4232,3045, 0,5100,2476, 315, 231,2447, 301,3356,4549,2385, # 1040 +5101, 233,4233,3697,1819,4550,4551,5102, 96,1777,1315,2083,5103, 257,5104,1810, # 1056 +3698,2718,1139,1820,4234,2022,1124,2164,2791,1778,2659,5105,3097, 363,1655,3214, # 1072 +5106,2993,5107,5108,5109,3992,1567,3993, 718, 103,3215, 849,1443, 341,3357,2949, # 1088 +1484,5110,1712, 127, 67, 339,4235,2403, 679,1412, 821,5111,5112, 834, 738, 351, # 1104 +2994,2147, 846, 235,1497,1881, 418,1993,3828,2719, 186,1100,2148,2756,3575,1545, # 1120 +1355,2950,2872,1377, 583,3994,4236,2581,2995,5113,1298,3699,1078,2557,3700,2363, # 1136 + 78,3829,3830, 267,1289,2100,2002,1594,4237, 348, 369,1274,2197,2178,1838,4552, # 1152 +1821,2830,3701,2757,2288,2003,4553,2951,2758, 144,3358, 882,4554,3995,2759,3470, # 1168 +4555,2915,5114,4238,1726, 320,5115,3996,3046, 788,2996,5116,2831,1774,1327,2873, # 1184 +3997,2832,5117,1306,4556,2004,1700,3831,3576,2364,2660, 787,2023, 506, 824,3702, # 1200 + 534, 323,4557,1044,3359,2024,1901, 946,3471,5118,1779,1500,1678,5119,1882,4558, # 1216 + 165, 243,4559,3703,2528, 123, 683,4239, 764,4560, 36,3998,1793, 589,2916, 816, # 1232 + 626,1667,3047,2237,1639,1555,1622,3832,3999,5120,4000,2874,1370,1228,1933, 891, # 1248 +2084,2917, 304,4240,5121, 292,2997,2720,3577, 691,2101,4241,1115,4561, 118, 662, # 1264 +5122, 611,1156, 854,2386,1316,2875, 2, 386, 515,2918,5123,5124,3286, 868,2238, # 1280 +1486, 855,2661, 785,2216,3048,5125,1040,3216,3578,5126,3146, 448,5127,1525,5128, # 1296 +2165,4562,5129,3833,5130,4242,2833,3579,3147, 503, 818,4001,3148,1568, 814, 676, # 1312 +1444, 306,1749,5131,3834,1416,1030, 197,1428, 805,2834,1501,4563,5132,5133,5134, # 1328 +1994,5135,4564,5136,5137,2198, 13,2792,3704,2998,3149,1229,1917,5138,3835,2132, # 1344 +5139,4243,4565,2404,3580,5140,2217,1511,1727,1120,5141,5142, 646,3836,2448, 307, # 1360 +5143,5144,1595,3217,5145,5146,5147,3705,1113,1356,4002,1465,2529,2530,5148, 519, # 1376 +5149, 128,2133, 92,2289,1980,5150,4003,1512, 342,3150,2199,5151,2793,2218,1981, # 1392 +3360,4244, 290,1656,1317, 789, 827,2365,5152,3837,4566, 562, 581,4004,5153, 401, # 1408 +4567,2252, 94,4568,5154,1399,2794,5155,1463,2025,4569,3218,1944,5156, 828,1105, # 1424 +4245,1262,1394,5157,4246, 605,4570,5158,1784,2876,5159,2835, 819,2102, 578,2200, # 1440 +2952,5160,1502, 436,3287,4247,3288,2836,4005,2919,3472,3473,5161,2721,2320,5162, # 1456 +5163,2337,2068, 23,4571, 193, 826,3838,2103, 699,1630,4248,3098, 390,1794,1064, # 1472 +3581,5164,1579,3099,3100,1400,5165,4249,1839,1640,2877,5166,4572,4573, 137,4250, # 1488 + 598,3101,1967, 780, 104, 974,2953,5167, 278, 899, 253, 402, 572, 504, 493,1339, # 1504 +5168,4006,1275,4574,2582,2558,5169,3706,3049,3102,2253, 565,1334,2722, 863, 41, # 1520 +5170,5171,4575,5172,1657,2338, 19, 463,2760,4251, 606,5173,2999,3289,1087,2085, # 1536 +1323,2662,3000,5174,1631,1623,1750,4252,2691,5175,2878, 791,2723,2663,2339, 232, # 1552 +2421,5176,3001,1498,5177,2664,2630, 755,1366,3707,3290,3151,2026,1609, 119,1918, # 1568 +3474, 862,1026,4253,5178,4007,3839,4576,4008,4577,2265,1952,2477,5179,1125, 817, # 1584 +4254,4255,4009,1513,1766,2041,1487,4256,3050,3291,2837,3840,3152,5180,5181,1507, # 1600 +5182,2692, 733, 40,1632,1106,2879, 345,4257, 841,2531, 230,4578,3002,1847,3292, # 1616 +3475,5183,1263, 986,3476,5184, 735, 879, 254,1137, 857, 622,1300,1180,1388,1562, # 1632 +4010,4011,2954, 967,2761,2665,1349, 592,2134,1692,3361,3003,1995,4258,1679,4012, # 1648 +1902,2188,5185, 739,3708,2724,1296,1290,5186,4259,2201,2202,1922,1563,2605,2559, # 1664 +1871,2762,3004,5187, 435,5188, 343,1108, 596, 17,1751,4579,2239,3477,3709,5189, # 1680 +4580, 294,3582,2955,1693, 477, 979, 281,2042,3583, 643,2043,3710,2631,2795,2266, # 1696 +1031,2340,2135,2303,3584,4581, 367,1249,2560,5190,3585,5191,4582,1283,3362,2005, # 1712 + 240,1762,3363,4583,4584, 836,1069,3153, 474,5192,2149,2532, 268,3586,5193,3219, # 1728 +1521,1284,5194,1658,1546,4260,5195,3587,3588,5196,4261,3364,2693,1685,4262, 961, # 1744 +1673,2632, 190,2006,2203,3841,4585,4586,5197, 570,2504,3711,1490,5198,4587,2633, # 1760 +3293,1957,4588, 584,1514, 396,1045,1945,5199,4589,1968,2449,5200,5201,4590,4013, # 1776 + 619,5202,3154,3294, 215,2007,2796,2561,3220,4591,3221,4592, 763,4263,3842,4593, # 1792 +5203,5204,1958,1767,2956,3365,3712,1174, 452,1477,4594,3366,3155,5205,2838,1253, # 1808 +2387,2189,1091,2290,4264, 492,5206, 638,1169,1825,2136,1752,4014, 648, 926,1021, # 1824 +1324,4595, 520,4596, 997, 847,1007, 892,4597,3843,2267,1872,3713,2405,1785,4598, # 1840 +1953,2957,3103,3222,1728,4265,2044,3714,4599,2008,1701,3156,1551, 30,2268,4266, # 1856 +5207,2027,4600,3589,5208, 501,5209,4267, 594,3478,2166,1822,3590,3479,3591,3223, # 1872 + 829,2839,4268,5210,1680,3157,1225,4269,5211,3295,4601,4270,3158,2341,5212,4602, # 1888 +4271,5213,4015,4016,5214,1848,2388,2606,3367,5215,4603, 374,4017, 652,4272,4273, # 1904 + 375,1140, 798,5216,5217,5218,2366,4604,2269, 546,1659, 138,3051,2450,4605,5219, # 1920 +2254, 612,1849, 910, 796,3844,1740,1371, 825,3845,3846,5220,2920,2562,5221, 692, # 1936 + 444,3052,2634, 801,4606,4274,5222,1491, 244,1053,3053,4275,4276, 340,5223,4018, # 1952 +1041,3005, 293,1168, 87,1357,5224,1539, 959,5225,2240, 721, 694,4277,3847, 219, # 1968 +1478, 644,1417,3368,2666,1413,1401,1335,1389,4019,5226,5227,3006,2367,3159,1826, # 1984 + 730,1515, 184,2840, 66,4607,5228,1660,2958, 246,3369, 378,1457, 226,3480, 975, # 2000 +4020,2959,1264,3592, 674, 696,5229, 163,5230,1141,2422,2167, 713,3593,3370,4608, # 2016 +4021,5231,5232,1186, 15,5233,1079,1070,5234,1522,3224,3594, 276,1050,2725, 758, # 2032 +1126, 653,2960,3296,5235,2342, 889,3595,4022,3104,3007, 903,1250,4609,4023,3481, # 2048 +3596,1342,1681,1718, 766,3297, 286, 89,2961,3715,5236,1713,5237,2607,3371,3008, # 2064 +5238,2962,2219,3225,2880,5239,4610,2505,2533, 181, 387,1075,4024, 731,2190,3372, # 2080 +5240,3298, 310, 313,3482,2304, 770,4278, 54,3054, 189,4611,3105,3848,4025,5241, # 2096 +1230,1617,1850, 355,3597,4279,4612,3373, 111,4280,3716,1350,3160,3483,3055,4281, # 2112 +2150,3299,3598,5242,2797,4026,4027,3009, 722,2009,5243,1071, 247,1207,2343,2478, # 2128 +1378,4613,2010, 864,1437,1214,4614, 373,3849,1142,2220, 667,4615, 442,2763,2563, # 2144 +3850,4028,1969,4282,3300,1840, 837, 170,1107, 934,1336,1883,5244,5245,2119,4283, # 2160 +2841, 743,1569,5246,4616,4284, 582,2389,1418,3484,5247,1803,5248, 357,1395,1729, # 2176 +3717,3301,2423,1564,2241,5249,3106,3851,1633,4617,1114,2086,4285,1532,5250, 482, # 2192 +2451,4618,5251,5252,1492, 833,1466,5253,2726,3599,1641,2842,5254,1526,1272,3718, # 2208 +4286,1686,1795, 416,2564,1903,1954,1804,5255,3852,2798,3853,1159,2321,5256,2881, # 2224 +4619,1610,1584,3056,2424,2764, 443,3302,1163,3161,5257,5258,4029,5259,4287,2506, # 2240 +3057,4620,4030,3162,2104,1647,3600,2011,1873,4288,5260,4289, 431,3485,5261, 250, # 2256 + 97, 81,4290,5262,1648,1851,1558, 160, 848,5263, 866, 740,1694,5264,2204,2843, # 2272 +3226,4291,4621,3719,1687, 950,2479, 426, 469,3227,3720,3721,4031,5265,5266,1188, # 2288 + 424,1996, 861,3601,4292,3854,2205,2694, 168,1235,3602,4293,5267,2087,1674,4622, # 2304 +3374,3303, 220,2565,1009,5268,3855, 670,3010, 332,1208, 717,5269,5270,3603,2452, # 2320 +4032,3375,5271, 513,5272,1209,2882,3376,3163,4623,1080,5273,5274,5275,5276,2534, # 2336 +3722,3604, 815,1587,4033,4034,5277,3605,3486,3856,1254,4624,1328,3058,1390,4035, # 2352 +1741,4036,3857,4037,5278, 236,3858,2453,3304,5279,5280,3723,3859,1273,3860,4625, # 2368 +5281, 308,5282,4626, 245,4627,1852,2480,1307,2583, 430, 715,2137,2454,5283, 270, # 2384 + 199,2883,4038,5284,3606,2727,1753, 761,1754, 725,1661,1841,4628,3487,3724,5285, # 2400 +5286, 587, 14,3305, 227,2608, 326, 480,2270, 943,2765,3607, 291, 650,1884,5287, # 2416 +1702,1226, 102,1547, 62,3488, 904,4629,3489,1164,4294,5288,5289,1224,1548,2766, # 2432 + 391, 498,1493,5290,1386,1419,5291,2056,1177,4630, 813, 880,1081,2368, 566,1145, # 2448 +4631,2291,1001,1035,2566,2609,2242, 394,1286,5292,5293,2069,5294, 86,1494,1730, # 2464 +4039, 491,1588, 745, 897,2963, 843,3377,4040,2767,2884,3306,1768, 998,2221,2070, # 2480 + 397,1827,1195,1970,3725,3011,3378, 284,5295,3861,2507,2138,2120,1904,5296,4041, # 2496 +2151,4042,4295,1036,3490,1905, 114,2567,4296, 209,1527,5297,5298,2964,2844,2635, # 2512 +2390,2728,3164, 812,2568,5299,3307,5300,1559, 737,1885,3726,1210, 885, 28,2695, # 2528 +3608,3862,5301,4297,1004,1780,4632,5302, 346,1982,2222,2696,4633,3863,1742, 797, # 2544 +1642,4043,1934,1072,1384,2152, 896,4044,3308,3727,3228,2885,3609,5303,2569,1959, # 2560 +4634,2455,1786,5304,5305,5306,4045,4298,1005,1308,3728,4299,2729,4635,4636,1528, # 2576 +2610, 161,1178,4300,1983, 987,4637,1101,4301, 631,4046,1157,3229,2425,1343,1241, # 2592 +1016,2243,2570, 372, 877,2344,2508,1160, 555,1935, 911,4047,5307, 466,1170, 169, # 2608 +1051,2921,2697,3729,2481,3012,1182,2012,2571,1251,2636,5308, 992,2345,3491,1540, # 2624 +2730,1201,2071,2406,1997,2482,5309,4638, 528,1923,2191,1503,1874,1570,2369,3379, # 2640 +3309,5310, 557,1073,5311,1828,3492,2088,2271,3165,3059,3107, 767,3108,2799,4639, # 2656 +1006,4302,4640,2346,1267,2179,3730,3230, 778,4048,3231,2731,1597,2667,5312,4641, # 2672 +5313,3493,5314,5315,5316,3310,2698,1433,3311, 131, 95,1504,4049, 723,4303,3166, # 2688 +1842,3610,2768,2192,4050,2028,2105,3731,5317,3013,4051,1218,5318,3380,3232,4052, # 2704 +4304,2584, 248,1634,3864, 912,5319,2845,3732,3060,3865, 654, 53,5320,3014,5321, # 2720 +1688,4642, 777,3494,1032,4053,1425,5322, 191, 820,2121,2846, 971,4643, 931,3233, # 2736 + 135, 664, 783,3866,1998, 772,2922,1936,4054,3867,4644,2923,3234, 282,2732, 640, # 2752 +1372,3495,1127, 922, 325,3381,5323,5324, 711,2045,5325,5326,4055,2223,2800,1937, # 2768 +4056,3382,2224,2255,3868,2305,5327,4645,3869,1258,3312,4057,3235,2139,2965,4058, # 2784 +4059,5328,2225, 258,3236,4646, 101,1227,5329,3313,1755,5330,1391,3314,5331,2924, # 2800 +2057, 893,5332,5333,5334,1402,4305,2347,5335,5336,3237,3611,5337,5338, 878,1325, # 2816 +1781,2801,4647, 259,1385,2585, 744,1183,2272,4648,5339,4060,2509,5340, 684,1024, # 2832 +4306,5341, 472,3612,3496,1165,3315,4061,4062, 322,2153, 881, 455,1695,1152,1340, # 2848 + 660, 554,2154,4649,1058,4650,4307, 830,1065,3383,4063,4651,1924,5342,1703,1919, # 2864 +5343, 932,2273, 122,5344,4652, 947, 677,5345,3870,2637, 297,1906,1925,2274,4653, # 2880 +2322,3316,5346,5347,4308,5348,4309, 84,4310, 112, 989,5349, 547,1059,4064, 701, # 2896 +3613,1019,5350,4311,5351,3497, 942, 639, 457,2306,2456, 993,2966, 407, 851, 494, # 2912 +4654,3384, 927,5352,1237,5353,2426,3385, 573,4312, 680, 921,2925,1279,1875, 285, # 2928 + 790,1448,1984, 719,2168,5354,5355,4655,4065,4066,1649,5356,1541, 563,5357,1077, # 2944 +5358,3386,3061,3498, 511,3015,4067,4068,3733,4069,1268,2572,3387,3238,4656,4657, # 2960 +5359, 535,1048,1276,1189,2926,2029,3167,1438,1373,2847,2967,1134,2013,5360,4313, # 2976 +1238,2586,3109,1259,5361, 700,5362,2968,3168,3734,4314,5363,4315,1146,1876,1907, # 2992 +4658,2611,4070, 781,2427, 132,1589, 203, 147, 273,2802,2407, 898,1787,2155,4071, # 3008 +4072,5364,3871,2803,5365,5366,4659,4660,5367,3239,5368,1635,3872, 965,5369,1805, # 3024 +2699,1516,3614,1121,1082,1329,3317,4073,1449,3873, 65,1128,2848,2927,2769,1590, # 3040 +3874,5370,5371, 12,2668, 45, 976,2587,3169,4661, 517,2535,1013,1037,3240,5372, # 3056 +3875,2849,5373,3876,5374,3499,5375,2612, 614,1999,2323,3877,3110,2733,2638,5376, # 3072 +2588,4316, 599,1269,5377,1811,3735,5378,2700,3111, 759,1060, 489,1806,3388,3318, # 3088 +1358,5379,5380,2391,1387,1215,2639,2256, 490,5381,5382,4317,1759,2392,2348,5383, # 3104 +4662,3878,1908,4074,2640,1807,3241,4663,3500,3319,2770,2349, 874,5384,5385,3501, # 3120 +3736,1859, 91,2928,3737,3062,3879,4664,5386,3170,4075,2669,5387,3502,1202,1403, # 3136 +3880,2969,2536,1517,2510,4665,3503,2511,5388,4666,5389,2701,1886,1495,1731,4076, # 3152 +2370,4667,5390,2030,5391,5392,4077,2702,1216, 237,2589,4318,2324,4078,3881,4668, # 3168 +4669,2703,3615,3504, 445,4670,5393,5394,5395,5396,2771, 61,4079,3738,1823,4080, # 3184 +5397, 687,2046, 935, 925, 405,2670, 703,1096,1860,2734,4671,4081,1877,1367,2704, # 3200 +3389, 918,2106,1782,2483, 334,3320,1611,1093,4672, 564,3171,3505,3739,3390, 945, # 3216 +2641,2058,4673,5398,1926, 872,4319,5399,3506,2705,3112, 349,4320,3740,4082,4674, # 3232 +3882,4321,3741,2156,4083,4675,4676,4322,4677,2408,2047, 782,4084, 400, 251,4323, # 3248 +1624,5400,5401, 277,3742, 299,1265, 476,1191,3883,2122,4324,4325,1109, 205,5402, # 3264 +2590,1000,2157,3616,1861,5403,5404,5405,4678,5406,4679,2573, 107,2484,2158,4085, # 3280 +3507,3172,5407,1533, 541,1301, 158, 753,4326,2886,3617,5408,1696, 370,1088,4327, # 3296 +4680,3618, 579, 327, 440, 162,2244, 269,1938,1374,3508, 968,3063, 56,1396,3113, # 3312 +2107,3321,3391,5409,1927,2159,4681,3016,5410,3619,5411,5412,3743,4682,2485,5413, # 3328 +2804,5414,1650,4683,5415,2613,5416,5417,4086,2671,3392,1149,3393,4087,3884,4088, # 3344 +5418,1076, 49,5419, 951,3242,3322,3323, 450,2850, 920,5420,1812,2805,2371,4328, # 3360 +1909,1138,2372,3885,3509,5421,3243,4684,1910,1147,1518,2428,4685,3886,5422,4686, # 3376 +2393,2614, 260,1796,3244,5423,5424,3887,3324, 708,5425,3620,1704,5426,3621,1351, # 3392 +1618,3394,3017,1887, 944,4329,3395,4330,3064,3396,4331,5427,3744, 422, 413,1714, # 3408 +3325, 500,2059,2350,4332,2486,5428,1344,1911, 954,5429,1668,5430,5431,4089,2409, # 3424 +4333,3622,3888,4334,5432,2307,1318,2512,3114, 133,3115,2887,4687, 629, 31,2851, # 3440 +2706,3889,4688, 850, 949,4689,4090,2970,1732,2089,4335,1496,1853,5433,4091, 620, # 3456 +3245, 981,1242,3745,3397,1619,3746,1643,3326,2140,2457,1971,1719,3510,2169,5434, # 3472 +3246,5435,5436,3398,1829,5437,1277,4690,1565,2048,5438,1636,3623,3116,5439, 869, # 3488 +2852, 655,3890,3891,3117,4092,3018,3892,1310,3624,4691,5440,5441,5442,1733, 558, # 3504 +4692,3747, 335,1549,3065,1756,4336,3748,1946,3511,1830,1291,1192, 470,2735,2108, # 3520 +2806, 913,1054,4093,5443,1027,5444,3066,4094,4693, 982,2672,3399,3173,3512,3247, # 3536 +3248,1947,2807,5445, 571,4694,5446,1831,5447,3625,2591,1523,2429,5448,2090, 984, # 3552 +4695,3749,1960,5449,3750, 852, 923,2808,3513,3751, 969,1519, 999,2049,2325,1705, # 3568 +5450,3118, 615,1662, 151, 597,4095,2410,2326,1049, 275,4696,3752,4337, 568,3753, # 3584 +3626,2487,4338,3754,5451,2430,2275, 409,3249,5452,1566,2888,3514,1002, 769,2853, # 3600 + 194,2091,3174,3755,2226,3327,4339, 628,1505,5453,5454,1763,2180,3019,4096, 521, # 3616 +1161,2592,1788,2206,2411,4697,4097,1625,4340,4341, 412, 42,3119, 464,5455,2642, # 3632 +4698,3400,1760,1571,2889,3515,2537,1219,2207,3893,2643,2141,2373,4699,4700,3328, # 3648 +1651,3401,3627,5456,5457,3628,2488,3516,5458,3756,5459,5460,2276,2092, 460,5461, # 3664 +4701,5462,3020, 962, 588,3629, 289,3250,2644,1116, 52,5463,3067,1797,5464,5465, # 3680 +5466,1467,5467,1598,1143,3757,4342,1985,1734,1067,4702,1280,3402, 465,4703,1572, # 3696 + 510,5468,1928,2245,1813,1644,3630,5469,4704,3758,5470,5471,2673,1573,1534,5472, # 3712 +5473, 536,1808,1761,3517,3894,3175,2645,5474,5475,5476,4705,3518,2929,1912,2809, # 3728 +5477,3329,1122, 377,3251,5478, 360,5479,5480,4343,1529, 551,5481,2060,3759,1769, # 3744 +2431,5482,2930,4344,3330,3120,2327,2109,2031,4706,1404, 136,1468,1479, 672,1171, # 3760 +3252,2308, 271,3176,5483,2772,5484,2050, 678,2736, 865,1948,4707,5485,2014,4098, # 3776 +2971,5486,2737,2227,1397,3068,3760,4708,4709,1735,2931,3403,3631,5487,3895, 509, # 3792 +2854,2458,2890,3896,5488,5489,3177,3178,4710,4345,2538,4711,2309,1166,1010, 552, # 3808 + 681,1888,5490,5491,2972,2973,4099,1287,1596,1862,3179, 358, 453, 736, 175, 478, # 3824 +1117, 905,1167,1097,5492,1854,1530,5493,1706,5494,2181,3519,2292,3761,3520,3632, # 3840 +4346,2093,4347,5495,3404,1193,2489,4348,1458,2193,2208,1863,1889,1421,3331,2932, # 3856 +3069,2182,3521, 595,2123,5496,4100,5497,5498,4349,1707,2646, 223,3762,1359, 751, # 3872 +3121, 183,3522,5499,2810,3021, 419,2374, 633, 704,3897,2394, 241,5500,5501,5502, # 3888 + 838,3022,3763,2277,2773,2459,3898,1939,2051,4101,1309,3122,2246,1181,5503,1136, # 3904 +2209,3899,2375,1446,4350,2310,4712,5504,5505,4351,1055,2615, 484,3764,5506,4102, # 3920 + 625,4352,2278,3405,1499,4353,4103,5507,4104,4354,3253,2279,2280,3523,5508,5509, # 3936 +2774, 808,2616,3765,3406,4105,4355,3123,2539, 526,3407,3900,4356, 955,5510,1620, # 3952 +4357,2647,2432,5511,1429,3766,1669,1832, 994, 928,5512,3633,1260,5513,5514,5515, # 3968 +1949,2293, 741,2933,1626,4358,2738,2460, 867,1184, 362,3408,1392,5516,5517,4106, # 3984 +4359,1770,1736,3254,2934,4713,4714,1929,2707,1459,1158,5518,3070,3409,2891,1292, # 4000 +1930,2513,2855,3767,1986,1187,2072,2015,2617,4360,5519,2574,2514,2170,3768,2490, # 4016 +3332,5520,3769,4715,5521,5522, 666,1003,3023,1022,3634,4361,5523,4716,1814,2257, # 4032 + 574,3901,1603, 295,1535, 705,3902,4362, 283, 858, 417,5524,5525,3255,4717,4718, # 4048 +3071,1220,1890,1046,2281,2461,4107,1393,1599, 689,2575, 388,4363,5526,2491, 802, # 4064 +5527,2811,3903,2061,1405,2258,5528,4719,3904,2110,1052,1345,3256,1585,5529, 809, # 4080 +5530,5531,5532, 575,2739,3524, 956,1552,1469,1144,2328,5533,2329,1560,2462,3635, # 4096 +3257,4108, 616,2210,4364,3180,2183,2294,5534,1833,5535,3525,4720,5536,1319,3770, # 4112 +3771,1211,3636,1023,3258,1293,2812,5537,5538,5539,3905, 607,2311,3906, 762,2892, # 4128 +1439,4365,1360,4721,1485,3072,5540,4722,1038,4366,1450,2062,2648,4367,1379,4723, # 4144 +2593,5541,5542,4368,1352,1414,2330,2935,1172,5543,5544,3907,3908,4724,1798,1451, # 4160 +5545,5546,5547,5548,2936,4109,4110,2492,2351, 411,4111,4112,3637,3333,3124,4725, # 4176 +1561,2674,1452,4113,1375,5549,5550, 47,2974, 316,5551,1406,1591,2937,3181,5552, # 4192 +1025,2142,3125,3182, 354,2740, 884,2228,4369,2412, 508,3772, 726,3638, 996,2433, # 4208 +3639, 729,5553, 392,2194,1453,4114,4726,3773,5554,5555,2463,3640,2618,1675,2813, # 4224 + 919,2352,2975,2353,1270,4727,4115, 73,5556,5557, 647,5558,3259,2856,2259,1550, # 4240 +1346,3024,5559,1332, 883,3526,5560,5561,5562,5563,3334,2775,5564,1212, 831,1347, # 4256 +4370,4728,2331,3909,1864,3073, 720,3910,4729,4730,3911,5565,4371,5566,5567,4731, # 4272 +5568,5569,1799,4732,3774,2619,4733,3641,1645,2376,4734,5570,2938, 669,2211,2675, # 4288 +2434,5571,2893,5572,5573,1028,3260,5574,4372,2413,5575,2260,1353,5576,5577,4735, # 4304 +3183, 518,5578,4116,5579,4373,1961,5580,2143,4374,5581,5582,3025,2354,2355,3912, # 4320 + 516,1834,1454,4117,2708,4375,4736,2229,2620,1972,1129,3642,5583,2776,5584,2976, # 4336 +1422, 577,1470,3026,1524,3410,5585,5586, 432,4376,3074,3527,5587,2594,1455,2515, # 4352 +2230,1973,1175,5588,1020,2741,4118,3528,4737,5589,2742,5590,1743,1361,3075,3529, # 4368 +2649,4119,4377,4738,2295, 895, 924,4378,2171, 331,2247,3076, 166,1627,3077,1098, # 4384 +5591,1232,2894,2231,3411,4739, 657, 403,1196,2377, 542,3775,3412,1600,4379,3530, # 4400 +5592,4740,2777,3261, 576, 530,1362,4741,4742,2540,2676,3776,4120,5593, 842,3913, # 4416 +5594,2814,2032,1014,4121, 213,2709,3413, 665, 621,4380,5595,3777,2939,2435,5596, # 4432 +2436,3335,3643,3414,4743,4381,2541,4382,4744,3644,1682,4383,3531,1380,5597, 724, # 4448 +2282, 600,1670,5598,1337,1233,4745,3126,2248,5599,1621,4746,5600, 651,4384,5601, # 4464 +1612,4385,2621,5602,2857,5603,2743,2312,3078,5604, 716,2464,3079, 174,1255,2710, # 4480 +4122,3645, 548,1320,1398, 728,4123,1574,5605,1891,1197,3080,4124,5606,3081,3082, # 4496 +3778,3646,3779, 747,5607, 635,4386,4747,5608,5609,5610,4387,5611,5612,4748,5613, # 4512 +3415,4749,2437, 451,5614,3780,2542,2073,4388,2744,4389,4125,5615,1764,4750,5616, # 4528 +4390, 350,4751,2283,2395,2493,5617,4391,4126,2249,1434,4127, 488,4752, 458,4392, # 4544 +4128,3781, 771,1330,2396,3914,2576,3184,2160,2414,1553,2677,3185,4393,5618,2494, # 4560 +2895,2622,1720,2711,4394,3416,4753,5619,2543,4395,5620,3262,4396,2778,5621,2016, # 4576 +2745,5622,1155,1017,3782,3915,5623,3336,2313, 201,1865,4397,1430,5624,4129,5625, # 4592 +5626,5627,5628,5629,4398,1604,5630, 414,1866, 371,2595,4754,4755,3532,2017,3127, # 4608 +4756,1708, 960,4399, 887, 389,2172,1536,1663,1721,5631,2232,4130,2356,2940,1580, # 4624 +5632,5633,1744,4757,2544,4758,4759,5634,4760,5635,2074,5636,4761,3647,3417,2896, # 4640 +4400,5637,4401,2650,3418,2815, 673,2712,2465, 709,3533,4131,3648,4402,5638,1148, # 4656 + 502, 634,5639,5640,1204,4762,3649,1575,4763,2623,3783,5641,3784,3128, 948,3263, # 4672 + 121,1745,3916,1110,5642,4403,3083,2516,3027,4132,3785,1151,1771,3917,1488,4133, # 4688 +1987,5643,2438,3534,5644,5645,2094,5646,4404,3918,1213,1407,2816, 531,2746,2545, # 4704 +3264,1011,1537,4764,2779,4405,3129,1061,5647,3786,3787,1867,2897,5648,2018, 120, # 4720 +4406,4407,2063,3650,3265,2314,3919,2678,3419,1955,4765,4134,5649,3535,1047,2713, # 4736 +1266,5650,1368,4766,2858, 649,3420,3920,2546,2747,1102,2859,2679,5651,5652,2000, # 4752 +5653,1111,3651,2977,5654,2495,3921,3652,2817,1855,3421,3788,5655,5656,3422,2415, # 4768 +2898,3337,3266,3653,5657,2577,5658,3654,2818,4135,1460, 856,5659,3655,5660,2899, # 4784 +2978,5661,2900,3922,5662,4408, 632,2517, 875,3923,1697,3924,2296,5663,5664,4767, # 4800 +3028,1239, 580,4768,4409,5665, 914, 936,2075,1190,4136,1039,2124,5666,5667,5668, # 4816 +5669,3423,1473,5670,1354,4410,3925,4769,2173,3084,4137, 915,3338,4411,4412,3339, # 4832 +1605,1835,5671,2748, 398,3656,4413,3926,4138, 328,1913,2860,4139,3927,1331,4414, # 4848 +3029, 937,4415,5672,3657,4140,4141,3424,2161,4770,3425, 524, 742, 538,3085,1012, # 4864 +5673,5674,3928,2466,5675, 658,1103, 225,3929,5676,5677,4771,5678,4772,5679,3267, # 4880 +1243,5680,4142, 963,2250,4773,5681,2714,3658,3186,5682,5683,2596,2332,5684,4774, # 4896 +5685,5686,5687,3536, 957,3426,2547,2033,1931,2941,2467, 870,2019,3659,1746,2780, # 4912 +2781,2439,2468,5688,3930,5689,3789,3130,3790,3537,3427,3791,5690,1179,3086,5691, # 4928 +3187,2378,4416,3792,2548,3188,3131,2749,4143,5692,3428,1556,2549,2297, 977,2901, # 4944 +2034,4144,1205,3429,5693,1765,3430,3189,2125,1271, 714,1689,4775,3538,5694,2333, # 4960 +3931, 533,4417,3660,2184, 617,5695,2469,3340,3539,2315,5696,5697,3190,5698,5699, # 4976 +3932,1988, 618, 427,2651,3540,3431,5700,5701,1244,1690,5702,2819,4418,4776,5703, # 4992 +3541,4777,5704,2284,1576, 473,3661,4419,3432, 972,5705,3662,5706,3087,5707,5708, # 5008 +4778,4779,5709,3793,4145,4146,5710, 153,4780, 356,5711,1892,2902,4420,2144, 408, # 5024 + 803,2357,5712,3933,5713,4421,1646,2578,2518,4781,4782,3934,5714,3935,4422,5715, # 5040 +2416,3433, 752,5716,5717,1962,3341,2979,5718, 746,3030,2470,4783,4423,3794, 698, # 5056 +4784,1893,4424,3663,2550,4785,3664,3936,5719,3191,3434,5720,1824,1302,4147,2715, # 5072 +3937,1974,4425,5721,4426,3192, 823,1303,1288,1236,2861,3542,4148,3435, 774,3938, # 5088 +5722,1581,4786,1304,2862,3939,4787,5723,2440,2162,1083,3268,4427,4149,4428, 344, # 5104 +1173, 288,2316, 454,1683,5724,5725,1461,4788,4150,2597,5726,5727,4789, 985, 894, # 5120 +5728,3436,3193,5729,1914,2942,3795,1989,5730,2111,1975,5731,4151,5732,2579,1194, # 5136 + 425,5733,4790,3194,1245,3796,4429,5734,5735,2863,5736, 636,4791,1856,3940, 760, # 5152 +1800,5737,4430,2212,1508,4792,4152,1894,1684,2298,5738,5739,4793,4431,4432,2213, # 5168 + 479,5740,5741, 832,5742,4153,2496,5743,2980,2497,3797, 990,3132, 627,1815,2652, # 5184 +4433,1582,4434,2126,2112,3543,4794,5744, 799,4435,3195,5745,4795,2113,1737,3031, # 5200 +1018, 543, 754,4436,3342,1676,4796,4797,4154,4798,1489,5746,3544,5747,2624,2903, # 5216 +4155,5748,5749,2981,5750,5751,5752,5753,3196,4799,4800,2185,1722,5754,3269,3270, # 5232 +1843,3665,1715, 481, 365,1976,1857,5755,5756,1963,2498,4801,5757,2127,3666,3271, # 5248 + 433,1895,2064,2076,5758, 602,2750,5759,5760,5761,5762,5763,3032,1628,3437,5764, # 5264 +3197,4802,4156,2904,4803,2519,5765,2551,2782,5766,5767,5768,3343,4804,2905,5769, # 5280 +4805,5770,2864,4806,4807,1221,2982,4157,2520,5771,5772,5773,1868,1990,5774,5775, # 5296 +5776,1896,5777,5778,4808,1897,4158, 318,5779,2095,4159,4437,5780,5781, 485,5782, # 5312 + 938,3941, 553,2680, 116,5783,3942,3667,5784,3545,2681,2783,3438,3344,2820,5785, # 5328 +3668,2943,4160,1747,2944,2983,5786,5787, 207,5788,4809,5789,4810,2521,5790,3033, # 5344 + 890,3669,3943,5791,1878,3798,3439,5792,2186,2358,3440,1652,5793,5794,5795, 941, # 5360 +2299, 208,3546,4161,2020, 330,4438,3944,2906,2499,3799,4439,4811,5796,5797,5798, # 5376 +) + diff --git a/venv/lib/python3.8/site-packages/chardet/big5prober.py b/venv/lib/python3.8/site-packages/chardet/big5prober.py new file mode 100644 index 0000000..98f9970 --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/big5prober.py @@ -0,0 +1,47 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .mbcharsetprober import MultiByteCharSetProber +from .codingstatemachine import CodingStateMachine +from .chardistribution import Big5DistributionAnalysis +from .mbcssm import BIG5_SM_MODEL + + +class Big5Prober(MultiByteCharSetProber): + def __init__(self): + super(Big5Prober, self).__init__() + self.coding_sm = CodingStateMachine(BIG5_SM_MODEL) + self.distribution_analyzer = Big5DistributionAnalysis() + self.reset() + + @property + def charset_name(self): + return "Big5" + + @property + def language(self): + return "Chinese" diff --git a/venv/lib/python3.8/site-packages/chardet/chardistribution.py b/venv/lib/python3.8/site-packages/chardet/chardistribution.py new file mode 100644 index 0000000..c0395f4 --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/chardistribution.py @@ -0,0 +1,233 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .euctwfreq import (EUCTW_CHAR_TO_FREQ_ORDER, EUCTW_TABLE_SIZE, + EUCTW_TYPICAL_DISTRIBUTION_RATIO) +from .euckrfreq import (EUCKR_CHAR_TO_FREQ_ORDER, EUCKR_TABLE_SIZE, + EUCKR_TYPICAL_DISTRIBUTION_RATIO) +from .gb2312freq import (GB2312_CHAR_TO_FREQ_ORDER, GB2312_TABLE_SIZE, + GB2312_TYPICAL_DISTRIBUTION_RATIO) +from .big5freq import (BIG5_CHAR_TO_FREQ_ORDER, BIG5_TABLE_SIZE, + BIG5_TYPICAL_DISTRIBUTION_RATIO) +from .jisfreq import (JIS_CHAR_TO_FREQ_ORDER, JIS_TABLE_SIZE, + JIS_TYPICAL_DISTRIBUTION_RATIO) + + +class CharDistributionAnalysis(object): + ENOUGH_DATA_THRESHOLD = 1024 + SURE_YES = 0.99 + SURE_NO = 0.01 + MINIMUM_DATA_THRESHOLD = 3 + + def __init__(self): + # Mapping table to get frequency order from char order (get from + # GetOrder()) + self._char_to_freq_order = None + self._table_size = None # Size of above table + # This is a constant value which varies from language to language, + # used in calculating confidence. See + # http://www.mozilla.org/projects/intl/UniversalCharsetDetection.html + # for further detail. + self.typical_distribution_ratio = None + self._done = None + self._total_chars = None + self._freq_chars = None + self.reset() + + def reset(self): + """reset analyser, clear any state""" + # If this flag is set to True, detection is done and conclusion has + # been made + self._done = False + self._total_chars = 0 # Total characters encountered + # The number of characters whose frequency order is less than 512 + self._freq_chars = 0 + + def feed(self, char, char_len): + """feed a character with known length""" + if char_len == 2: + # we only care about 2-bytes character in our distribution analysis + order = self.get_order(char) + else: + order = -1 + if order >= 0: + self._total_chars += 1 + # order is valid + if order < self._table_size: + if 512 > self._char_to_freq_order[order]: + self._freq_chars += 1 + + def get_confidence(self): + """return confidence based on existing data""" + # if we didn't receive any character in our consideration range, + # return negative answer + if self._total_chars <= 0 or self._freq_chars <= self.MINIMUM_DATA_THRESHOLD: + return self.SURE_NO + + if self._total_chars != self._freq_chars: + r = (self._freq_chars / ((self._total_chars - self._freq_chars) + * self.typical_distribution_ratio)) + if r < self.SURE_YES: + return r + + # normalize confidence (we don't want to be 100% sure) + return self.SURE_YES + + def got_enough_data(self): + # It is not necessary to receive all data to draw conclusion. + # For charset detection, certain amount of data is enough + return self._total_chars > self.ENOUGH_DATA_THRESHOLD + + def get_order(self, byte_str): + # We do not handle characters based on the original encoding string, + # but convert this encoding string to a number, here called order. + # This allows multiple encodings of a language to share one frequency + # table. + return -1 + + +class EUCTWDistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + super(EUCTWDistributionAnalysis, self).__init__() + self._char_to_freq_order = EUCTW_CHAR_TO_FREQ_ORDER + self._table_size = EUCTW_TABLE_SIZE + self.typical_distribution_ratio = EUCTW_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, byte_str): + # for euc-TW encoding, we are interested + # first byte range: 0xc4 -- 0xfe + # second byte range: 0xa1 -- 0xfe + # no validation needed here. State machine has done that + first_char = byte_str[0] + if first_char >= 0xC4: + return 94 * (first_char - 0xC4) + byte_str[1] - 0xA1 + else: + return -1 + + +class EUCKRDistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + super(EUCKRDistributionAnalysis, self).__init__() + self._char_to_freq_order = EUCKR_CHAR_TO_FREQ_ORDER + self._table_size = EUCKR_TABLE_SIZE + self.typical_distribution_ratio = EUCKR_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, byte_str): + # for euc-KR encoding, we are interested + # first byte range: 0xb0 -- 0xfe + # second byte range: 0xa1 -- 0xfe + # no validation needed here. State machine has done that + first_char = byte_str[0] + if first_char >= 0xB0: + return 94 * (first_char - 0xB0) + byte_str[1] - 0xA1 + else: + return -1 + + +class GB2312DistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + super(GB2312DistributionAnalysis, self).__init__() + self._char_to_freq_order = GB2312_CHAR_TO_FREQ_ORDER + self._table_size = GB2312_TABLE_SIZE + self.typical_distribution_ratio = GB2312_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, byte_str): + # for GB2312 encoding, we are interested + # first byte range: 0xb0 -- 0xfe + # second byte range: 0xa1 -- 0xfe + # no validation needed here. State machine has done that + first_char, second_char = byte_str[0], byte_str[1] + if (first_char >= 0xB0) and (second_char >= 0xA1): + return 94 * (first_char - 0xB0) + second_char - 0xA1 + else: + return -1 + + +class Big5DistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + super(Big5DistributionAnalysis, self).__init__() + self._char_to_freq_order = BIG5_CHAR_TO_FREQ_ORDER + self._table_size = BIG5_TABLE_SIZE + self.typical_distribution_ratio = BIG5_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, byte_str): + # for big5 encoding, we are interested + # first byte range: 0xa4 -- 0xfe + # second byte range: 0x40 -- 0x7e , 0xa1 -- 0xfe + # no validation needed here. State machine has done that + first_char, second_char = byte_str[0], byte_str[1] + if first_char >= 0xA4: + if second_char >= 0xA1: + return 157 * (first_char - 0xA4) + second_char - 0xA1 + 63 + else: + return 157 * (first_char - 0xA4) + second_char - 0x40 + else: + return -1 + + +class SJISDistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + super(SJISDistributionAnalysis, self).__init__() + self._char_to_freq_order = JIS_CHAR_TO_FREQ_ORDER + self._table_size = JIS_TABLE_SIZE + self.typical_distribution_ratio = JIS_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, byte_str): + # for sjis encoding, we are interested + # first byte range: 0x81 -- 0x9f , 0xe0 -- 0xfe + # second byte range: 0x40 -- 0x7e, 0x81 -- oxfe + # no validation needed here. State machine has done that + first_char, second_char = byte_str[0], byte_str[1] + if (first_char >= 0x81) and (first_char <= 0x9F): + order = 188 * (first_char - 0x81) + elif (first_char >= 0xE0) and (first_char <= 0xEF): + order = 188 * (first_char - 0xE0 + 31) + else: + return -1 + order = order + second_char - 0x40 + if second_char > 0x7F: + order = -1 + return order + + +class EUCJPDistributionAnalysis(CharDistributionAnalysis): + def __init__(self): + super(EUCJPDistributionAnalysis, self).__init__() + self._char_to_freq_order = JIS_CHAR_TO_FREQ_ORDER + self._table_size = JIS_TABLE_SIZE + self.typical_distribution_ratio = JIS_TYPICAL_DISTRIBUTION_RATIO + + def get_order(self, byte_str): + # for euc-JP encoding, we are interested + # first byte range: 0xa0 -- 0xfe + # second byte range: 0xa1 -- 0xfe + # no validation needed here. State machine has done that + char = byte_str[0] + if char >= 0xA0: + return 94 * (char - 0xA1) + byte_str[1] - 0xa1 + else: + return -1 diff --git a/venv/lib/python3.8/site-packages/chardet/charsetgroupprober.py b/venv/lib/python3.8/site-packages/chardet/charsetgroupprober.py new file mode 100644 index 0000000..5812cef --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/charsetgroupprober.py @@ -0,0 +1,107 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .enums import ProbingState +from .charsetprober import CharSetProber + + +class CharSetGroupProber(CharSetProber): + def __init__(self, lang_filter=None): + super(CharSetGroupProber, self).__init__(lang_filter=lang_filter) + self._active_num = 0 + self.probers = [] + self._best_guess_prober = None + + def reset(self): + super(CharSetGroupProber, self).reset() + self._active_num = 0 + for prober in self.probers: + if prober: + prober.reset() + prober.active = True + self._active_num += 1 + self._best_guess_prober = None + + @property + def charset_name(self): + if not self._best_guess_prober: + self.get_confidence() + if not self._best_guess_prober: + return None + return self._best_guess_prober.charset_name + + @property + def language(self): + if not self._best_guess_prober: + self.get_confidence() + if not self._best_guess_prober: + return None + return self._best_guess_prober.language + + def feed(self, byte_str): + for prober in self.probers: + if not prober: + continue + if not prober.active: + continue + state = prober.feed(byte_str) + if not state: + continue + if state == ProbingState.FOUND_IT: + self._best_guess_prober = prober + self._state = ProbingState.FOUND_IT + return self.state + elif state == ProbingState.NOT_ME: + prober.active = False + self._active_num -= 1 + if self._active_num <= 0: + self._state = ProbingState.NOT_ME + return self.state + return self.state + + def get_confidence(self): + state = self.state + if state == ProbingState.FOUND_IT: + return 0.99 + elif state == ProbingState.NOT_ME: + return 0.01 + best_conf = 0.0 + self._best_guess_prober = None + for prober in self.probers: + if not prober: + continue + if not prober.active: + self.logger.debug('%s not active', prober.charset_name) + continue + conf = prober.get_confidence() + self.logger.debug('%s %s confidence = %s', prober.charset_name, prober.language, conf) + if best_conf < conf: + best_conf = conf + self._best_guess_prober = prober + if not self._best_guess_prober: + return 0.0 + return best_conf diff --git a/venv/lib/python3.8/site-packages/chardet/charsetprober.py b/venv/lib/python3.8/site-packages/chardet/charsetprober.py new file mode 100644 index 0000000..eac4e59 --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/charsetprober.py @@ -0,0 +1,145 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +import logging +import re + +from .enums import ProbingState + + +class CharSetProber(object): + + SHORTCUT_THRESHOLD = 0.95 + + def __init__(self, lang_filter=None): + self._state = None + self.lang_filter = lang_filter + self.logger = logging.getLogger(__name__) + + def reset(self): + self._state = ProbingState.DETECTING + + @property + def charset_name(self): + return None + + def feed(self, buf): + pass + + @property + def state(self): + return self._state + + def get_confidence(self): + return 0.0 + + @staticmethod + def filter_high_byte_only(buf): + buf = re.sub(b'([\x00-\x7F])+', b' ', buf) + return buf + + @staticmethod + def filter_international_words(buf): + """ + We define three types of bytes: + alphabet: english alphabets [a-zA-Z] + international: international characters [\x80-\xFF] + marker: everything else [^a-zA-Z\x80-\xFF] + + The input buffer can be thought to contain a series of words delimited + by markers. This function works to filter all words that contain at + least one international character. All contiguous sequences of markers + are replaced by a single space ascii character. + + This filter applies to all scripts which do not use English characters. + """ + filtered = bytearray() + + # This regex expression filters out only words that have at-least one + # international character. The word may include one marker character at + # the end. + words = re.findall(b'[a-zA-Z]*[\x80-\xFF]+[a-zA-Z]*[^a-zA-Z\x80-\xFF]?', + buf) + + for word in words: + filtered.extend(word[:-1]) + + # If the last character in the word is a marker, replace it with a + # space as markers shouldn't affect our analysis (they are used + # similarly across all languages and may thus have similar + # frequencies). + last_char = word[-1:] + if not last_char.isalpha() and last_char < b'\x80': + last_char = b' ' + filtered.extend(last_char) + + return filtered + + @staticmethod + def filter_with_english_letters(buf): + """ + Returns a copy of ``buf`` that retains only the sequences of English + alphabet and high byte characters that are not between <> characters. + Also retains English alphabet and high byte characters immediately + before occurrences of >. + + This filter can be applied to all scripts which contain both English + characters and extended ASCII characters, but is currently only used by + ``Latin1Prober``. + """ + filtered = bytearray() + in_tag = False + prev = 0 + + for curr in range(len(buf)): + # Slice here to get bytes instead of an int with Python 3 + buf_char = buf[curr:curr + 1] + # Check if we're coming out of or entering an HTML tag + if buf_char == b'>': + in_tag = False + elif buf_char == b'<': + in_tag = True + + # If current character is not extended-ASCII and not alphabetic... + if buf_char < b'\x80' and not buf_char.isalpha(): + # ...and we're not in a tag + if curr > prev and not in_tag: + # Keep everything after last non-extended-ASCII, + # non-alphabetic character + filtered.extend(buf[prev:curr]) + # Output a space to delimit stretch we kept + filtered.extend(b' ') + prev = curr + 1 + + # If we're not in a tag... + if not in_tag: + # Keep everything after last non-extended-ASCII, non-alphabetic + # character + filtered.extend(buf[prev:]) + + return filtered diff --git a/venv/lib/python3.8/site-packages/chardet/cli/__init__.py b/venv/lib/python3.8/site-packages/chardet/cli/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/cli/__init__.py @@ -0,0 +1 @@ + diff --git a/venv/lib/python3.8/site-packages/chardet/cli/chardetect.py b/venv/lib/python3.8/site-packages/chardet/cli/chardetect.py new file mode 100644 index 0000000..e1d8cd6 --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/cli/chardetect.py @@ -0,0 +1,84 @@ +""" +Script which takes one or more file paths and reports on their detected +encodings + +Example:: + + % chardetect somefile someotherfile + somefile: windows-1252 with confidence 0.5 + someotherfile: ascii with confidence 1.0 + +If no paths are provided, it takes its input from stdin. + +""" + +from __future__ import absolute_import, print_function, unicode_literals + +import argparse +import sys + +from chardet import __version__ +from chardet.compat import PY2 +from chardet.universaldetector import UniversalDetector + + +def description_of(lines, name='stdin'): + """ + Return a string describing the probable encoding of a file or + list of strings. + + :param lines: The lines to get the encoding of. + :type lines: Iterable of bytes + :param name: Name of file or collection of lines + :type name: str + """ + u = UniversalDetector() + for line in lines: + line = bytearray(line) + u.feed(line) + # shortcut out of the loop to save reading further - particularly useful if we read a BOM. + if u.done: + break + u.close() + result = u.result + if PY2: + name = name.decode(sys.getfilesystemencoding(), 'ignore') + if result['encoding']: + return '{}: {} with confidence {}'.format(name, result['encoding'], + result['confidence']) + else: + return '{}: no result'.format(name) + + +def main(argv=None): + """ + Handles command line arguments and gets things started. + + :param argv: List of arguments, as if specified on the command-line. + If None, ``sys.argv[1:]`` is used instead. + :type argv: list of str + """ + # Get command line arguments + parser = argparse.ArgumentParser( + description="Takes one or more file paths and reports their detected \ + encodings") + parser.add_argument('input', + help='File whose encoding we would like to determine. \ + (default: stdin)', + type=argparse.FileType('rb'), nargs='*', + default=[sys.stdin if PY2 else sys.stdin.buffer]) + parser.add_argument('--version', action='version', + version='%(prog)s {}'.format(__version__)) + args = parser.parse_args(argv) + + for f in args.input: + if f.isatty(): + print("You are running chardetect interactively. Press " + + "CTRL-D twice at the start of a blank line to signal the " + + "end of your input. If you want help, run chardetect " + + "--help\n", file=sys.stderr) + print(description_of(f, f.name)) + + +if __name__ == '__main__': + main() diff --git a/venv/lib/python3.8/site-packages/chardet/codingstatemachine.py b/venv/lib/python3.8/site-packages/chardet/codingstatemachine.py new file mode 100644 index 0000000..68fba44 --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/codingstatemachine.py @@ -0,0 +1,88 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +import logging + +from .enums import MachineState + + +class CodingStateMachine(object): + """ + A state machine to verify a byte sequence for a particular encoding. For + each byte the detector receives, it will feed that byte to every active + state machine available, one byte at a time. The state machine changes its + state based on its previous state and the byte it receives. There are 3 + states in a state machine that are of interest to an auto-detector: + + START state: This is the state to start with, or a legal byte sequence + (i.e. a valid code point) for character has been identified. + + ME state: This indicates that the state machine identified a byte sequence + that is specific to the charset it is designed for and that + there is no other possible encoding which can contain this byte + sequence. This will to lead to an immediate positive answer for + the detector. + + ERROR state: This indicates the state machine identified an illegal byte + sequence for that encoding. This will lead to an immediate + negative answer for this encoding. Detector will exclude this + encoding from consideration from here on. + """ + def __init__(self, sm): + self._model = sm + self._curr_byte_pos = 0 + self._curr_char_len = 0 + self._curr_state = None + self.logger = logging.getLogger(__name__) + self.reset() + + def reset(self): + self._curr_state = MachineState.START + + def next_state(self, c): + # for each byte we get its class + # if it is first byte, we also get byte length + byte_class = self._model['class_table'][c] + if self._curr_state == MachineState.START: + self._curr_byte_pos = 0 + self._curr_char_len = self._model['char_len_table'][byte_class] + # from byte's class and state_table, we get its next state + curr_state = (self._curr_state * self._model['class_factor'] + + byte_class) + self._curr_state = self._model['state_table'][curr_state] + self._curr_byte_pos += 1 + return self._curr_state + + def get_current_charlen(self): + return self._curr_char_len + + def get_coding_state_machine(self): + return self._model['name'] + + @property + def language(self): + return self._model['language'] diff --git a/venv/lib/python3.8/site-packages/chardet/compat.py b/venv/lib/python3.8/site-packages/chardet/compat.py new file mode 100644 index 0000000..8941572 --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/compat.py @@ -0,0 +1,36 @@ +######################## BEGIN LICENSE BLOCK ######################## +# Contributor(s): +# Dan Blanchard +# Ian Cordasco +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +import sys + + +if sys.version_info < (3, 0): + PY2 = True + PY3 = False + string_types = (str, unicode) + text_type = unicode + iteritems = dict.iteritems +else: + PY2 = False + PY3 = True + string_types = (bytes, str) + text_type = str + iteritems = dict.items diff --git a/venv/lib/python3.8/site-packages/chardet/cp949prober.py b/venv/lib/python3.8/site-packages/chardet/cp949prober.py new file mode 100644 index 0000000..efd793a --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/cp949prober.py @@ -0,0 +1,49 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .chardistribution import EUCKRDistributionAnalysis +from .codingstatemachine import CodingStateMachine +from .mbcharsetprober import MultiByteCharSetProber +from .mbcssm import CP949_SM_MODEL + + +class CP949Prober(MultiByteCharSetProber): + def __init__(self): + super(CP949Prober, self).__init__() + self.coding_sm = CodingStateMachine(CP949_SM_MODEL) + # NOTE: CP949 is a superset of EUC-KR, so the distribution should be + # not different. + self.distribution_analyzer = EUCKRDistributionAnalysis() + self.reset() + + @property + def charset_name(self): + return "CP949" + + @property + def language(self): + return "Korean" diff --git a/venv/lib/python3.8/site-packages/chardet/enums.py b/venv/lib/python3.8/site-packages/chardet/enums.py new file mode 100644 index 0000000..0451207 --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/enums.py @@ -0,0 +1,76 @@ +""" +All of the Enums that are used throughout the chardet package. + +:author: Dan Blanchard (dan.blanchard@gmail.com) +""" + + +class InputState(object): + """ + This enum represents the different states a universal detector can be in. + """ + PURE_ASCII = 0 + ESC_ASCII = 1 + HIGH_BYTE = 2 + + +class LanguageFilter(object): + """ + This enum represents the different language filters we can apply to a + ``UniversalDetector``. + """ + CHINESE_SIMPLIFIED = 0x01 + CHINESE_TRADITIONAL = 0x02 + JAPANESE = 0x04 + KOREAN = 0x08 + NON_CJK = 0x10 + ALL = 0x1F + CHINESE = CHINESE_SIMPLIFIED | CHINESE_TRADITIONAL + CJK = CHINESE | JAPANESE | KOREAN + + +class ProbingState(object): + """ + This enum represents the different states a prober can be in. + """ + DETECTING = 0 + FOUND_IT = 1 + NOT_ME = 2 + + +class MachineState(object): + """ + This enum represents the different states a state machine can be in. + """ + START = 0 + ERROR = 1 + ITS_ME = 2 + + +class SequenceLikelihood(object): + """ + This enum represents the likelihood of a character following the previous one. + """ + NEGATIVE = 0 + UNLIKELY = 1 + LIKELY = 2 + POSITIVE = 3 + + @classmethod + def get_num_categories(cls): + """:returns: The number of likelihood categories in the enum.""" + return 4 + + +class CharacterCategory(object): + """ + This enum represents the different categories language models for + ``SingleByteCharsetProber`` put characters into. + + Anything less than CONTROL is considered a letter. + """ + UNDEFINED = 255 + LINE_BREAK = 254 + SYMBOL = 253 + DIGIT = 252 + CONTROL = 251 diff --git a/venv/lib/python3.8/site-packages/chardet/escprober.py b/venv/lib/python3.8/site-packages/chardet/escprober.py new file mode 100644 index 0000000..c70493f --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/escprober.py @@ -0,0 +1,101 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .charsetprober import CharSetProber +from .codingstatemachine import CodingStateMachine +from .enums import LanguageFilter, ProbingState, MachineState +from .escsm import (HZ_SM_MODEL, ISO2022CN_SM_MODEL, ISO2022JP_SM_MODEL, + ISO2022KR_SM_MODEL) + + +class EscCharSetProber(CharSetProber): + """ + This CharSetProber uses a "code scheme" approach for detecting encodings, + whereby easily recognizable escape or shift sequences are relied on to + identify these encodings. + """ + + def __init__(self, lang_filter=None): + super(EscCharSetProber, self).__init__(lang_filter=lang_filter) + self.coding_sm = [] + if self.lang_filter & LanguageFilter.CHINESE_SIMPLIFIED: + self.coding_sm.append(CodingStateMachine(HZ_SM_MODEL)) + self.coding_sm.append(CodingStateMachine(ISO2022CN_SM_MODEL)) + if self.lang_filter & LanguageFilter.JAPANESE: + self.coding_sm.append(CodingStateMachine(ISO2022JP_SM_MODEL)) + if self.lang_filter & LanguageFilter.KOREAN: + self.coding_sm.append(CodingStateMachine(ISO2022KR_SM_MODEL)) + self.active_sm_count = None + self._detected_charset = None + self._detected_language = None + self._state = None + self.reset() + + def reset(self): + super(EscCharSetProber, self).reset() + for coding_sm in self.coding_sm: + if not coding_sm: + continue + coding_sm.active = True + coding_sm.reset() + self.active_sm_count = len(self.coding_sm) + self._detected_charset = None + self._detected_language = None + + @property + def charset_name(self): + return self._detected_charset + + @property + def language(self): + return self._detected_language + + def get_confidence(self): + if self._detected_charset: + return 0.99 + else: + return 0.00 + + def feed(self, byte_str): + for c in byte_str: + for coding_sm in self.coding_sm: + if not coding_sm or not coding_sm.active: + continue + coding_state = coding_sm.next_state(c) + if coding_state == MachineState.ERROR: + coding_sm.active = False + self.active_sm_count -= 1 + if self.active_sm_count <= 0: + self._state = ProbingState.NOT_ME + return self.state + elif coding_state == MachineState.ITS_ME: + self._state = ProbingState.FOUND_IT + self._detected_charset = coding_sm.get_coding_state_machine() + self._detected_language = coding_sm.language + return self.state + + return self.state diff --git a/venv/lib/python3.8/site-packages/chardet/escsm.py b/venv/lib/python3.8/site-packages/chardet/escsm.py new file mode 100644 index 0000000..0069523 --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/escsm.py @@ -0,0 +1,246 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .enums import MachineState + +HZ_CLS = ( +1,0,0,0,0,0,0,0, # 00 - 07 +0,0,0,0,0,0,0,0, # 08 - 0f +0,0,0,0,0,0,0,0, # 10 - 17 +0,0,0,1,0,0,0,0, # 18 - 1f +0,0,0,0,0,0,0,0, # 20 - 27 +0,0,0,0,0,0,0,0, # 28 - 2f +0,0,0,0,0,0,0,0, # 30 - 37 +0,0,0,0,0,0,0,0, # 38 - 3f +0,0,0,0,0,0,0,0, # 40 - 47 +0,0,0,0,0,0,0,0, # 48 - 4f +0,0,0,0,0,0,0,0, # 50 - 57 +0,0,0,0,0,0,0,0, # 58 - 5f +0,0,0,0,0,0,0,0, # 60 - 67 +0,0,0,0,0,0,0,0, # 68 - 6f +0,0,0,0,0,0,0,0, # 70 - 77 +0,0,0,4,0,5,2,0, # 78 - 7f +1,1,1,1,1,1,1,1, # 80 - 87 +1,1,1,1,1,1,1,1, # 88 - 8f +1,1,1,1,1,1,1,1, # 90 - 97 +1,1,1,1,1,1,1,1, # 98 - 9f +1,1,1,1,1,1,1,1, # a0 - a7 +1,1,1,1,1,1,1,1, # a8 - af +1,1,1,1,1,1,1,1, # b0 - b7 +1,1,1,1,1,1,1,1, # b8 - bf +1,1,1,1,1,1,1,1, # c0 - c7 +1,1,1,1,1,1,1,1, # c8 - cf +1,1,1,1,1,1,1,1, # d0 - d7 +1,1,1,1,1,1,1,1, # d8 - df +1,1,1,1,1,1,1,1, # e0 - e7 +1,1,1,1,1,1,1,1, # e8 - ef +1,1,1,1,1,1,1,1, # f0 - f7 +1,1,1,1,1,1,1,1, # f8 - ff +) + +HZ_ST = ( +MachineState.START,MachineState.ERROR, 3,MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,# 00-07 +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,# 08-0f +MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START, 4,MachineState.ERROR,# 10-17 + 5,MachineState.ERROR, 6,MachineState.ERROR, 5, 5, 4,MachineState.ERROR,# 18-1f + 4,MachineState.ERROR, 4, 4, 4,MachineState.ERROR, 4,MachineState.ERROR,# 20-27 + 4,MachineState.ITS_ME,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,# 28-2f +) + +HZ_CHAR_LEN_TABLE = (0, 0, 0, 0, 0, 0) + +HZ_SM_MODEL = {'class_table': HZ_CLS, + 'class_factor': 6, + 'state_table': HZ_ST, + 'char_len_table': HZ_CHAR_LEN_TABLE, + 'name': "HZ-GB-2312", + 'language': 'Chinese'} + +ISO2022CN_CLS = ( +2,0,0,0,0,0,0,0, # 00 - 07 +0,0,0,0,0,0,0,0, # 08 - 0f +0,0,0,0,0,0,0,0, # 10 - 17 +0,0,0,1,0,0,0,0, # 18 - 1f +0,0,0,0,0,0,0,0, # 20 - 27 +0,3,0,0,0,0,0,0, # 28 - 2f +0,0,0,0,0,0,0,0, # 30 - 37 +0,0,0,0,0,0,0,0, # 38 - 3f +0,0,0,4,0,0,0,0, # 40 - 47 +0,0,0,0,0,0,0,0, # 48 - 4f +0,0,0,0,0,0,0,0, # 50 - 57 +0,0,0,0,0,0,0,0, # 58 - 5f +0,0,0,0,0,0,0,0, # 60 - 67 +0,0,0,0,0,0,0,0, # 68 - 6f +0,0,0,0,0,0,0,0, # 70 - 77 +0,0,0,0,0,0,0,0, # 78 - 7f +2,2,2,2,2,2,2,2, # 80 - 87 +2,2,2,2,2,2,2,2, # 88 - 8f +2,2,2,2,2,2,2,2, # 90 - 97 +2,2,2,2,2,2,2,2, # 98 - 9f +2,2,2,2,2,2,2,2, # a0 - a7 +2,2,2,2,2,2,2,2, # a8 - af +2,2,2,2,2,2,2,2, # b0 - b7 +2,2,2,2,2,2,2,2, # b8 - bf +2,2,2,2,2,2,2,2, # c0 - c7 +2,2,2,2,2,2,2,2, # c8 - cf +2,2,2,2,2,2,2,2, # d0 - d7 +2,2,2,2,2,2,2,2, # d8 - df +2,2,2,2,2,2,2,2, # e0 - e7 +2,2,2,2,2,2,2,2, # e8 - ef +2,2,2,2,2,2,2,2, # f0 - f7 +2,2,2,2,2,2,2,2, # f8 - ff +) + +ISO2022CN_ST = ( +MachineState.START, 3,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,# 00-07 +MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 08-0f +MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,# 10-17 +MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 4,MachineState.ERROR,# 18-1f +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 20-27 + 5, 6,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 28-2f +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 30-37 +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.START,# 38-3f +) + +ISO2022CN_CHAR_LEN_TABLE = (0, 0, 0, 0, 0, 0, 0, 0, 0) + +ISO2022CN_SM_MODEL = {'class_table': ISO2022CN_CLS, + 'class_factor': 9, + 'state_table': ISO2022CN_ST, + 'char_len_table': ISO2022CN_CHAR_LEN_TABLE, + 'name': "ISO-2022-CN", + 'language': 'Chinese'} + +ISO2022JP_CLS = ( +2,0,0,0,0,0,0,0, # 00 - 07 +0,0,0,0,0,0,2,2, # 08 - 0f +0,0,0,0,0,0,0,0, # 10 - 17 +0,0,0,1,0,0,0,0, # 18 - 1f +0,0,0,0,7,0,0,0, # 20 - 27 +3,0,0,0,0,0,0,0, # 28 - 2f +0,0,0,0,0,0,0,0, # 30 - 37 +0,0,0,0,0,0,0,0, # 38 - 3f +6,0,4,0,8,0,0,0, # 40 - 47 +0,9,5,0,0,0,0,0, # 48 - 4f +0,0,0,0,0,0,0,0, # 50 - 57 +0,0,0,0,0,0,0,0, # 58 - 5f +0,0,0,0,0,0,0,0, # 60 - 67 +0,0,0,0,0,0,0,0, # 68 - 6f +0,0,0,0,0,0,0,0, # 70 - 77 +0,0,0,0,0,0,0,0, # 78 - 7f +2,2,2,2,2,2,2,2, # 80 - 87 +2,2,2,2,2,2,2,2, # 88 - 8f +2,2,2,2,2,2,2,2, # 90 - 97 +2,2,2,2,2,2,2,2, # 98 - 9f +2,2,2,2,2,2,2,2, # a0 - a7 +2,2,2,2,2,2,2,2, # a8 - af +2,2,2,2,2,2,2,2, # b0 - b7 +2,2,2,2,2,2,2,2, # b8 - bf +2,2,2,2,2,2,2,2, # c0 - c7 +2,2,2,2,2,2,2,2, # c8 - cf +2,2,2,2,2,2,2,2, # d0 - d7 +2,2,2,2,2,2,2,2, # d8 - df +2,2,2,2,2,2,2,2, # e0 - e7 +2,2,2,2,2,2,2,2, # e8 - ef +2,2,2,2,2,2,2,2, # f0 - f7 +2,2,2,2,2,2,2,2, # f8 - ff +) + +ISO2022JP_ST = ( +MachineState.START, 3,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,# 00-07 +MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 08-0f +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,# 10-17 +MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,# 18-1f +MachineState.ERROR, 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 4,MachineState.ERROR,MachineState.ERROR,# 20-27 +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 6,MachineState.ITS_ME,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,# 28-2f +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,# 30-37 +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 38-3f +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.START,MachineState.START,# 40-47 +) + +ISO2022JP_CHAR_LEN_TABLE = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0) + +ISO2022JP_SM_MODEL = {'class_table': ISO2022JP_CLS, + 'class_factor': 10, + 'state_table': ISO2022JP_ST, + 'char_len_table': ISO2022JP_CHAR_LEN_TABLE, + 'name': "ISO-2022-JP", + 'language': 'Japanese'} + +ISO2022KR_CLS = ( +2,0,0,0,0,0,0,0, # 00 - 07 +0,0,0,0,0,0,0,0, # 08 - 0f +0,0,0,0,0,0,0,0, # 10 - 17 +0,0,0,1,0,0,0,0, # 18 - 1f +0,0,0,0,3,0,0,0, # 20 - 27 +0,4,0,0,0,0,0,0, # 28 - 2f +0,0,0,0,0,0,0,0, # 30 - 37 +0,0,0,0,0,0,0,0, # 38 - 3f +0,0,0,5,0,0,0,0, # 40 - 47 +0,0,0,0,0,0,0,0, # 48 - 4f +0,0,0,0,0,0,0,0, # 50 - 57 +0,0,0,0,0,0,0,0, # 58 - 5f +0,0,0,0,0,0,0,0, # 60 - 67 +0,0,0,0,0,0,0,0, # 68 - 6f +0,0,0,0,0,0,0,0, # 70 - 77 +0,0,0,0,0,0,0,0, # 78 - 7f +2,2,2,2,2,2,2,2, # 80 - 87 +2,2,2,2,2,2,2,2, # 88 - 8f +2,2,2,2,2,2,2,2, # 90 - 97 +2,2,2,2,2,2,2,2, # 98 - 9f +2,2,2,2,2,2,2,2, # a0 - a7 +2,2,2,2,2,2,2,2, # a8 - af +2,2,2,2,2,2,2,2, # b0 - b7 +2,2,2,2,2,2,2,2, # b8 - bf +2,2,2,2,2,2,2,2, # c0 - c7 +2,2,2,2,2,2,2,2, # c8 - cf +2,2,2,2,2,2,2,2, # d0 - d7 +2,2,2,2,2,2,2,2, # d8 - df +2,2,2,2,2,2,2,2, # e0 - e7 +2,2,2,2,2,2,2,2, # e8 - ef +2,2,2,2,2,2,2,2, # f0 - f7 +2,2,2,2,2,2,2,2, # f8 - ff +) + +ISO2022KR_ST = ( +MachineState.START, 3,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,# 00-07 +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,# 08-0f +MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 4,MachineState.ERROR,MachineState.ERROR,# 10-17 +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 18-1f +MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.START,MachineState.START,MachineState.START,MachineState.START,# 20-27 +) + +ISO2022KR_CHAR_LEN_TABLE = (0, 0, 0, 0, 0, 0) + +ISO2022KR_SM_MODEL = {'class_table': ISO2022KR_CLS, + 'class_factor': 6, + 'state_table': ISO2022KR_ST, + 'char_len_table': ISO2022KR_CHAR_LEN_TABLE, + 'name': "ISO-2022-KR", + 'language': 'Korean'} + + diff --git a/venv/lib/python3.8/site-packages/chardet/eucjpprober.py b/venv/lib/python3.8/site-packages/chardet/eucjpprober.py new file mode 100644 index 0000000..20ce8f7 --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/eucjpprober.py @@ -0,0 +1,92 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .enums import ProbingState, MachineState +from .mbcharsetprober import MultiByteCharSetProber +from .codingstatemachine import CodingStateMachine +from .chardistribution import EUCJPDistributionAnalysis +from .jpcntx import EUCJPContextAnalysis +from .mbcssm import EUCJP_SM_MODEL + + +class EUCJPProber(MultiByteCharSetProber): + def __init__(self): + super(EUCJPProber, self).__init__() + self.coding_sm = CodingStateMachine(EUCJP_SM_MODEL) + self.distribution_analyzer = EUCJPDistributionAnalysis() + self.context_analyzer = EUCJPContextAnalysis() + self.reset() + + def reset(self): + super(EUCJPProber, self).reset() + self.context_analyzer.reset() + + @property + def charset_name(self): + return "EUC-JP" + + @property + def language(self): + return "Japanese" + + def feed(self, byte_str): + for i in range(len(byte_str)): + # PY3K: byte_str is a byte array, so byte_str[i] is an int, not a byte + coding_state = self.coding_sm.next_state(byte_str[i]) + if coding_state == MachineState.ERROR: + self.logger.debug('%s %s prober hit error at byte %s', + self.charset_name, self.language, i) + self._state = ProbingState.NOT_ME + break + elif coding_state == MachineState.ITS_ME: + self._state = ProbingState.FOUND_IT + break + elif coding_state == MachineState.START: + char_len = self.coding_sm.get_current_charlen() + if i == 0: + self._last_char[1] = byte_str[0] + self.context_analyzer.feed(self._last_char, char_len) + self.distribution_analyzer.feed(self._last_char, char_len) + else: + self.context_analyzer.feed(byte_str[i - 1:i + 1], + char_len) + self.distribution_analyzer.feed(byte_str[i - 1:i + 1], + char_len) + + self._last_char[0] = byte_str[-1] + + if self.state == ProbingState.DETECTING: + if (self.context_analyzer.got_enough_data() and + (self.get_confidence() > self.SHORTCUT_THRESHOLD)): + self._state = ProbingState.FOUND_IT + + return self.state + + def get_confidence(self): + context_conf = self.context_analyzer.get_confidence() + distrib_conf = self.distribution_analyzer.get_confidence() + return max(context_conf, distrib_conf) diff --git a/venv/lib/python3.8/site-packages/chardet/euckrfreq.py b/venv/lib/python3.8/site-packages/chardet/euckrfreq.py new file mode 100644 index 0000000..b68078c --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/euckrfreq.py @@ -0,0 +1,195 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# Sampling from about 20M text materials include literature and computer technology + +# 128 --> 0.79 +# 256 --> 0.92 +# 512 --> 0.986 +# 1024 --> 0.99944 +# 2048 --> 0.99999 +# +# Idea Distribution Ratio = 0.98653 / (1-0.98653) = 73.24 +# Random Distribution Ration = 512 / (2350-512) = 0.279. +# +# Typical Distribution Ratio + +EUCKR_TYPICAL_DISTRIBUTION_RATIO = 6.0 + +EUCKR_TABLE_SIZE = 2352 + +# Char to FreqOrder table , +EUCKR_CHAR_TO_FREQ_ORDER = ( + 13, 130, 120,1396, 481,1719,1720, 328, 609, 212,1721, 707, 400, 299,1722, 87, +1397,1723, 104, 536,1117,1203,1724,1267, 685,1268, 508,1725,1726,1727,1728,1398, +1399,1729,1730,1731, 141, 621, 326,1057, 368,1732, 267, 488, 20,1733,1269,1734, + 945,1400,1735, 47, 904,1270,1736,1737, 773, 248,1738, 409, 313, 786, 429,1739, + 116, 987, 813,1401, 683, 75,1204, 145,1740,1741,1742,1743, 16, 847, 667, 622, + 708,1744,1745,1746, 966, 787, 304, 129,1747, 60, 820, 123, 676,1748,1749,1750, +1751, 617,1752, 626,1753,1754,1755,1756, 653,1757,1758,1759,1760,1761,1762, 856, + 344,1763,1764,1765,1766, 89, 401, 418, 806, 905, 848,1767,1768,1769, 946,1205, + 709,1770,1118,1771, 241,1772,1773,1774,1271,1775, 569,1776, 999,1777,1778,1779, +1780, 337, 751,1058, 28, 628, 254,1781, 177, 906, 270, 349, 891,1079,1782, 19, +1783, 379,1784, 315,1785, 629, 754,1402, 559,1786, 636, 203,1206,1787, 710, 567, +1788, 935, 814,1789,1790,1207, 766, 528,1791,1792,1208,1793,1794,1795,1796,1797, +1403,1798,1799, 533,1059,1404,1405,1156,1406, 936, 884,1080,1800, 351,1801,1802, +1803,1804,1805, 801,1806,1807,1808,1119,1809,1157, 714, 474,1407,1810, 298, 899, + 885,1811,1120, 802,1158,1812, 892,1813,1814,1408, 659,1815,1816,1121,1817,1818, +1819,1820,1821,1822, 319,1823, 594, 545,1824, 815, 937,1209,1825,1826, 573,1409, +1022,1827,1210,1828,1829,1830,1831,1832,1833, 556, 722, 807,1122,1060,1834, 697, +1835, 900, 557, 715,1836,1410, 540,1411, 752,1159, 294, 597,1211, 976, 803, 770, +1412,1837,1838, 39, 794,1413, 358,1839, 371, 925,1840, 453, 661, 788, 531, 723, + 544,1023,1081, 869, 91,1841, 392, 430, 790, 602,1414, 677,1082, 457,1415,1416, +1842,1843, 475, 327,1024,1417, 795, 121,1844, 733, 403,1418,1845,1846,1847, 300, + 119, 711,1212, 627,1848,1272, 207,1849,1850, 796,1213, 382,1851, 519,1852,1083, + 893,1853,1854,1855, 367, 809, 487, 671,1856, 663,1857,1858, 956, 471, 306, 857, +1859,1860,1160,1084,1861,1862,1863,1864,1865,1061,1866,1867,1868,1869,1870,1871, + 282, 96, 574,1872, 502,1085,1873,1214,1874, 907,1875,1876, 827, 977,1419,1420, +1421, 268,1877,1422,1878,1879,1880, 308,1881, 2, 537,1882,1883,1215,1884,1885, + 127, 791,1886,1273,1423,1887, 34, 336, 404, 643,1888, 571, 654, 894, 840,1889, + 0, 886,1274, 122, 575, 260, 908, 938,1890,1275, 410, 316,1891,1892, 100,1893, +1894,1123, 48,1161,1124,1025,1895, 633, 901,1276,1896,1897, 115, 816,1898, 317, +1899, 694,1900, 909, 734,1424, 572, 866,1425, 691, 85, 524,1010, 543, 394, 841, +1901,1902,1903,1026,1904,1905,1906,1907,1908,1909, 30, 451, 651, 988, 310,1910, +1911,1426, 810,1216, 93,1912,1913,1277,1217,1914, 858, 759, 45, 58, 181, 610, + 269,1915,1916, 131,1062, 551, 443,1000, 821,1427, 957, 895,1086,1917,1918, 375, +1919, 359,1920, 687,1921, 822,1922, 293,1923,1924, 40, 662, 118, 692, 29, 939, + 887, 640, 482, 174,1925, 69,1162, 728,1428, 910,1926,1278,1218,1279, 386, 870, + 217, 854,1163, 823,1927,1928,1929,1930, 834,1931, 78,1932, 859,1933,1063,1934, +1935,1936,1937, 438,1164, 208, 595,1938,1939,1940,1941,1219,1125,1942, 280, 888, +1429,1430,1220,1431,1943,1944,1945,1946,1947,1280, 150, 510,1432,1948,1949,1950, +1951,1952,1953,1954,1011,1087,1955,1433,1043,1956, 881,1957, 614, 958,1064,1065, +1221,1958, 638,1001, 860, 967, 896,1434, 989, 492, 553,1281,1165,1959,1282,1002, +1283,1222,1960,1961,1962,1963, 36, 383, 228, 753, 247, 454,1964, 876, 678,1965, +1966,1284, 126, 464, 490, 835, 136, 672, 529, 940,1088,1435, 473,1967,1968, 467, + 50, 390, 227, 587, 279, 378, 598, 792, 968, 240, 151, 160, 849, 882,1126,1285, + 639,1044, 133, 140, 288, 360, 811, 563,1027, 561, 142, 523,1969,1970,1971, 7, + 103, 296, 439, 407, 506, 634, 990,1972,1973,1974,1975, 645,1976,1977,1978,1979, +1980,1981, 236,1982,1436,1983,1984,1089, 192, 828, 618, 518,1166, 333,1127,1985, + 818,1223,1986,1987,1988,1989,1990,1991,1992,1993, 342,1128,1286, 746, 842,1994, +1995, 560, 223,1287, 98, 8, 189, 650, 978,1288,1996,1437,1997, 17, 345, 250, + 423, 277, 234, 512, 226, 97, 289, 42, 167,1998, 201,1999,2000, 843, 836, 824, + 532, 338, 783,1090, 182, 576, 436,1438,1439, 527, 500,2001, 947, 889,2002,2003, +2004,2005, 262, 600, 314, 447,2006, 547,2007, 693, 738,1129,2008, 71,1440, 745, + 619, 688,2009, 829,2010,2011, 147,2012, 33, 948,2013,2014, 74, 224,2015, 61, + 191, 918, 399, 637,2016,1028,1130, 257, 902,2017,2018,2019,2020,2021,2022,2023, +2024,2025,2026, 837,2027,2028,2029,2030, 179, 874, 591, 52, 724, 246,2031,2032, +2033,2034,1167, 969,2035,1289, 630, 605, 911,1091,1168,2036,2037,2038,1441, 912, +2039, 623,2040,2041, 253,1169,1290,2042,1442, 146, 620, 611, 577, 433,2043,1224, + 719,1170, 959, 440, 437, 534, 84, 388, 480,1131, 159, 220, 198, 679,2044,1012, + 819,1066,1443, 113,1225, 194, 318,1003,1029,2045,2046,2047,2048,1067,2049,2050, +2051,2052,2053, 59, 913, 112,2054, 632,2055, 455, 144, 739,1291,2056, 273, 681, + 499,2057, 448,2058,2059, 760,2060,2061, 970, 384, 169, 245,1132,2062,2063, 414, +1444,2064,2065, 41, 235,2066, 157, 252, 877, 568, 919, 789, 580,2067, 725,2068, +2069,1292,2070,2071,1445,2072,1446,2073,2074, 55, 588, 66,1447, 271,1092,2075, +1226,2076, 960,1013, 372,2077,2078,2079,2080,2081,1293,2082,2083,2084,2085, 850, +2086,2087,2088,2089,2090, 186,2091,1068, 180,2092,2093,2094, 109,1227, 522, 606, +2095, 867,1448,1093, 991,1171, 926, 353,1133,2096, 581,2097,2098,2099,1294,1449, +1450,2100, 596,1172,1014,1228,2101,1451,1295,1173,1229,2102,2103,1296,1134,1452, + 949,1135,2104,2105,1094,1453,1454,1455,2106,1095,2107,2108,2109,2110,2111,2112, +2113,2114,2115,2116,2117, 804,2118,2119,1230,1231, 805,1456, 405,1136,2120,2121, +2122,2123,2124, 720, 701,1297, 992,1457, 927,1004,2125,2126,2127,2128,2129,2130, + 22, 417,2131, 303,2132, 385,2133, 971, 520, 513,2134,1174, 73,1096, 231, 274, + 962,1458, 673,2135,1459,2136, 152,1137,2137,2138,2139,2140,1005,1138,1460,1139, +2141,2142,2143,2144, 11, 374, 844,2145, 154,1232, 46,1461,2146, 838, 830, 721, +1233, 106,2147, 90, 428, 462, 578, 566,1175, 352,2148,2149, 538,1234, 124,1298, +2150,1462, 761, 565,2151, 686,2152, 649,2153, 72, 173,2154, 460, 415,2155,1463, +2156,1235, 305,2157,2158,2159,2160,2161,2162, 579,2163,2164,2165,2166,2167, 747, +2168,2169,2170,2171,1464, 669,2172,2173,2174,2175,2176,1465,2177, 23, 530, 285, +2178, 335, 729,2179, 397,2180,2181,2182,1030,2183,2184, 698,2185,2186, 325,2187, +2188, 369,2189, 799,1097,1015, 348,2190,1069, 680,2191, 851,1466,2192,2193, 10, +2194, 613, 424,2195, 979, 108, 449, 589, 27, 172, 81,1031, 80, 774, 281, 350, +1032, 525, 301, 582,1176,2196, 674,1045,2197,2198,1467, 730, 762,2199,2200,2201, +2202,1468,2203, 993,2204,2205, 266,1070, 963,1140,2206,2207,2208, 664,1098, 972, +2209,2210,2211,1177,1469,1470, 871,2212,2213,2214,2215,2216,1471,2217,2218,2219, +2220,2221,2222,2223,2224,2225,2226,2227,1472,1236,2228,2229,2230,2231,2232,2233, +2234,2235,1299,2236,2237, 200,2238, 477, 373,2239,2240, 731, 825, 777,2241,2242, +2243, 521, 486, 548,2244,2245,2246,1473,1300, 53, 549, 137, 875, 76, 158,2247, +1301,1474, 469, 396,1016, 278, 712,2248, 321, 442, 503, 767, 744, 941,1237,1178, +1475,2249, 82, 178,1141,1179, 973,2250,1302,2251, 297,2252,2253, 570,2254,2255, +2256, 18, 450, 206,2257, 290, 292,1142,2258, 511, 162, 99, 346, 164, 735,2259, +1476,1477, 4, 554, 343, 798,1099,2260,1100,2261, 43, 171,1303, 139, 215,2262, +2263, 717, 775,2264,1033, 322, 216,2265, 831,2266, 149,2267,1304,2268,2269, 702, +1238, 135, 845, 347, 309,2270, 484,2271, 878, 655, 238,1006,1478,2272, 67,2273, + 295,2274,2275, 461,2276, 478, 942, 412,2277,1034,2278,2279,2280, 265,2281, 541, +2282,2283,2284,2285,2286, 70, 852,1071,2287,2288,2289,2290, 21, 56, 509, 117, + 432,2291,2292, 331, 980, 552,1101, 148, 284, 105, 393,1180,1239, 755,2293, 187, +2294,1046,1479,2295, 340,2296, 63,1047, 230,2297,2298,1305, 763,1306, 101, 800, + 808, 494,2299,2300,2301, 903,2302, 37,1072, 14, 5,2303, 79, 675,2304, 312, +2305,2306,2307,2308,2309,1480, 6,1307,2310,2311,2312, 1, 470, 35, 24, 229, +2313, 695, 210, 86, 778, 15, 784, 592, 779, 32, 77, 855, 964,2314, 259,2315, + 501, 380,2316,2317, 83, 981, 153, 689,1308,1481,1482,1483,2318,2319, 716,1484, +2320,2321,2322,2323,2324,2325,1485,2326,2327, 128, 57, 68, 261,1048, 211, 170, +1240, 31,2328, 51, 435, 742,2329,2330,2331, 635,2332, 264, 456,2333,2334,2335, + 425,2336,1486, 143, 507, 263, 943,2337, 363, 920,1487, 256,1488,1102, 243, 601, +1489,2338,2339,2340,2341,2342,2343,2344, 861,2345,2346,2347,2348,2349,2350, 395, +2351,1490,1491, 62, 535, 166, 225,2352,2353, 668, 419,1241, 138, 604, 928,2354, +1181,2355,1492,1493,2356,2357,2358,1143,2359, 696,2360, 387, 307,1309, 682, 476, +2361,2362, 332, 12, 222, 156,2363, 232,2364, 641, 276, 656, 517,1494,1495,1035, + 416, 736,1496,2365,1017, 586,2366,2367,2368,1497,2369, 242,2370,2371,2372,1498, +2373, 965, 713,2374,2375,2376,2377, 740, 982,1499, 944,1500,1007,2378,2379,1310, +1501,2380,2381,2382, 785, 329,2383,2384,1502,2385,2386,2387, 932,2388,1503,2389, +2390,2391,2392,1242,2393,2394,2395,2396,2397, 994, 950,2398,2399,2400,2401,1504, +1311,2402,2403,2404,2405,1049, 749,2406,2407, 853, 718,1144,1312,2408,1182,1505, +2409,2410, 255, 516, 479, 564, 550, 214,1506,1507,1313, 413, 239, 444, 339,1145, +1036,1508,1509,1314,1037,1510,1315,2411,1511,2412,2413,2414, 176, 703, 497, 624, + 593, 921, 302,2415, 341, 165,1103,1512,2416,1513,2417,2418,2419, 376,2420, 700, +2421,2422,2423, 258, 768,1316,2424,1183,2425, 995, 608,2426,2427,2428,2429, 221, +2430,2431,2432,2433,2434,2435,2436,2437, 195, 323, 726, 188, 897, 983,1317, 377, + 644,1050, 879,2438, 452,2439,2440,2441,2442,2443,2444, 914,2445,2446,2447,2448, + 915, 489,2449,1514,1184,2450,2451, 515, 64, 427, 495,2452, 583,2453, 483, 485, +1038, 562, 213,1515, 748, 666,2454,2455,2456,2457, 334,2458, 780, 996,1008, 705, +1243,2459,2460,2461,2462,2463, 114,2464, 493,1146, 366, 163,1516, 961,1104,2465, + 291,2466,1318,1105,2467,1517, 365,2468, 355, 951,1244,2469,1319,2470, 631,2471, +2472, 218,1320, 364, 320, 756,1518,1519,1321,1520,1322,2473,2474,2475,2476, 997, +2477,2478,2479,2480, 665,1185,2481, 916,1521,2482,2483,2484, 584, 684,2485,2486, + 797,2487,1051,1186,2488,2489,2490,1522,2491,2492, 370,2493,1039,1187, 65,2494, + 434, 205, 463,1188,2495, 125, 812, 391, 402, 826, 699, 286, 398, 155, 781, 771, + 585,2496, 590, 505,1073,2497, 599, 244, 219, 917,1018, 952, 646,1523,2498,1323, +2499,2500, 49, 984, 354, 741,2501, 625,2502,1324,2503,1019, 190, 357, 757, 491, + 95, 782, 868,2504,2505,2506,2507,2508,2509, 134,1524,1074, 422,1525, 898,2510, + 161,2511,2512,2513,2514, 769,2515,1526,2516,2517, 411,1325,2518, 472,1527,2519, +2520,2521,2522,2523,2524, 985,2525,2526,2527,2528,2529,2530, 764,2531,1245,2532, +2533, 25, 204, 311,2534, 496,2535,1052,2536,2537,2538,2539,2540,2541,2542, 199, + 704, 504, 468, 758, 657,1528, 196, 44, 839,1246, 272, 750,2543, 765, 862,2544, +2545,1326,2546, 132, 615, 933,2547, 732,2548,2549,2550,1189,1529,2551, 283,1247, +1053, 607, 929,2552,2553,2554, 930, 183, 872, 616,1040,1147,2555,1148,1020, 441, + 249,1075,2556,2557,2558, 466, 743,2559,2560,2561, 92, 514, 426, 420, 526,2562, +2563,2564,2565,2566,2567,2568, 185,2569,2570,2571,2572, 776,1530, 658,2573, 362, +2574, 361, 922,1076, 793,2575,2576,2577,2578,2579,2580,1531, 251,2581,2582,2583, +2584,1532, 54, 612, 237,1327,2585,2586, 275, 408, 647, 111,2587,1533,1106, 465, + 3, 458, 9, 38,2588, 107, 110, 890, 209, 26, 737, 498,2589,1534,2590, 431, + 202, 88,1535, 356, 287,1107, 660,1149,2591, 381,1536, 986,1150, 445,1248,1151, + 974,2592,2593, 846,2594, 446, 953, 184,1249,1250, 727,2595, 923, 193, 883,2596, +2597,2598, 102, 324, 539, 817,2599, 421,1041,2600, 832,2601, 94, 175, 197, 406, +2602, 459,2603,2604,2605,2606,2607, 330, 555,2608,2609,2610, 706,1108, 389,2611, +2612,2613,2614, 233,2615, 833, 558, 931, 954,1251,2616,2617,1537, 546,2618,2619, +1009,2620,2621,2622,1538, 690,1328,2623, 955,2624,1539,2625,2626, 772,2627,2628, +2629,2630,2631, 924, 648, 863, 603,2632,2633, 934,1540, 864, 865,2634, 642,1042, + 670,1190,2635,2636,2637,2638, 168,2639, 652, 873, 542,1054,1541,2640,2641,2642, # 512, 256 +) + diff --git a/venv/lib/python3.8/site-packages/chardet/euckrprober.py b/venv/lib/python3.8/site-packages/chardet/euckrprober.py new file mode 100644 index 0000000..345a060 --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/euckrprober.py @@ -0,0 +1,47 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .mbcharsetprober import MultiByteCharSetProber +from .codingstatemachine import CodingStateMachine +from .chardistribution import EUCKRDistributionAnalysis +from .mbcssm import EUCKR_SM_MODEL + + +class EUCKRProber(MultiByteCharSetProber): + def __init__(self): + super(EUCKRProber, self).__init__() + self.coding_sm = CodingStateMachine(EUCKR_SM_MODEL) + self.distribution_analyzer = EUCKRDistributionAnalysis() + self.reset() + + @property + def charset_name(self): + return "EUC-KR" + + @property + def language(self): + return "Korean" diff --git a/venv/lib/python3.8/site-packages/chardet/euctwfreq.py b/venv/lib/python3.8/site-packages/chardet/euctwfreq.py new file mode 100644 index 0000000..ed7a995 --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/euctwfreq.py @@ -0,0 +1,387 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# EUCTW frequency table +# Converted from big5 work +# by Taiwan's Mandarin Promotion Council +# + +# 128 --> 0.42261 +# 256 --> 0.57851 +# 512 --> 0.74851 +# 1024 --> 0.89384 +# 2048 --> 0.97583 +# +# Idea Distribution Ratio = 0.74851/(1-0.74851) =2.98 +# Random Distribution Ration = 512/(5401-512)=0.105 +# +# Typical Distribution Ratio about 25% of Ideal one, still much higher than RDR + +EUCTW_TYPICAL_DISTRIBUTION_RATIO = 0.75 + +# Char to FreqOrder table , +EUCTW_TABLE_SIZE = 5376 + +EUCTW_CHAR_TO_FREQ_ORDER = ( + 1,1800,1506, 255,1431, 198, 9, 82, 6,7310, 177, 202,3615,1256,2808, 110, # 2742 +3735, 33,3241, 261, 76, 44,2113, 16,2931,2184,1176, 659,3868, 26,3404,2643, # 2758 +1198,3869,3313,4060, 410,2211, 302, 590, 361,1963, 8, 204, 58,4296,7311,1931, # 2774 + 63,7312,7313, 317,1614, 75, 222, 159,4061,2412,1480,7314,3500,3068, 224,2809, # 2790 +3616, 3, 10,3870,1471, 29,2774,1135,2852,1939, 873, 130,3242,1123, 312,7315, # 2806 +4297,2051, 507, 252, 682,7316, 142,1914, 124, 206,2932, 34,3501,3173, 64, 604, # 2822 +7317,2494,1976,1977, 155,1990, 645, 641,1606,7318,3405, 337, 72, 406,7319, 80, # 2838 + 630, 238,3174,1509, 263, 939,1092,2644, 756,1440,1094,3406, 449, 69,2969, 591, # 2854 + 179,2095, 471, 115,2034,1843, 60, 50,2970, 134, 806,1868, 734,2035,3407, 180, # 2870 + 995,1607, 156, 537,2893, 688,7320, 319,1305, 779,2144, 514,2374, 298,4298, 359, # 2886 +2495, 90,2707,1338, 663, 11, 906,1099,2545, 20,2436, 182, 532,1716,7321, 732, # 2902 +1376,4062,1311,1420,3175, 25,2312,1056, 113, 399, 382,1949, 242,3408,2467, 529, # 2918 +3243, 475,1447,3617,7322, 117, 21, 656, 810,1297,2295,2329,3502,7323, 126,4063, # 2934 + 706, 456, 150, 613,4299, 71,1118,2036,4064, 145,3069, 85, 835, 486,2114,1246, # 2950 +1426, 428, 727,1285,1015, 800, 106, 623, 303,1281,7324,2127,2354, 347,3736, 221, # 2966 +3503,3110,7325,1955,1153,4065, 83, 296,1199,3070, 192, 624, 93,7326, 822,1897, # 2982 +2810,3111, 795,2064, 991,1554,1542,1592, 27, 43,2853, 859, 139,1456, 860,4300, # 2998 + 437, 712,3871, 164,2392,3112, 695, 211,3017,2096, 195,3872,1608,3504,3505,3618, # 3014 +3873, 234, 811,2971,2097,3874,2229,1441,3506,1615,2375, 668,2076,1638, 305, 228, # 3030 +1664,4301, 467, 415,7327, 262,2098,1593, 239, 108, 300, 200,1033, 512,1247,2077, # 3046 +7328,7329,2173,3176,3619,2673, 593, 845,1062,3244, 88,1723,2037,3875,1950, 212, # 3062 + 266, 152, 149, 468,1898,4066,4302, 77, 187,7330,3018, 37, 5,2972,7331,3876, # 3078 +7332,7333, 39,2517,4303,2894,3177,2078, 55, 148, 74,4304, 545, 483,1474,1029, # 3094 +1665, 217,1869,1531,3113,1104,2645,4067, 24, 172,3507, 900,3877,3508,3509,4305, # 3110 + 32,1408,2811,1312, 329, 487,2355,2247,2708, 784,2674, 4,3019,3314,1427,1788, # 3126 + 188, 109, 499,7334,3620,1717,1789, 888,1217,3020,4306,7335,3510,7336,3315,1520, # 3142 +3621,3878, 196,1034, 775,7337,7338, 929,1815, 249, 439, 38,7339,1063,7340, 794, # 3158 +3879,1435,2296, 46, 178,3245,2065,7341,2376,7342, 214,1709,4307, 804, 35, 707, # 3174 + 324,3622,1601,2546, 140, 459,4068,7343,7344,1365, 839, 272, 978,2257,2572,3409, # 3190 +2128,1363,3623,1423, 697, 100,3071, 48, 70,1231, 495,3114,2193,7345,1294,7346, # 3206 +2079, 462, 586,1042,3246, 853, 256, 988, 185,2377,3410,1698, 434,1084,7347,3411, # 3222 + 314,2615,2775,4308,2330,2331, 569,2280, 637,1816,2518, 757,1162,1878,1616,3412, # 3238 + 287,1577,2115, 768,4309,1671,2854,3511,2519,1321,3737, 909,2413,7348,4069, 933, # 3254 +3738,7349,2052,2356,1222,4310, 765,2414,1322, 786,4311,7350,1919,1462,1677,2895, # 3270 +1699,7351,4312,1424,2437,3115,3624,2590,3316,1774,1940,3413,3880,4070, 309,1369, # 3286 +1130,2812, 364,2230,1653,1299,3881,3512,3882,3883,2646, 525,1085,3021, 902,2000, # 3302 +1475, 964,4313, 421,1844,1415,1057,2281, 940,1364,3116, 376,4314,4315,1381, 7, # 3318 +2520, 983,2378, 336,1710,2675,1845, 321,3414, 559,1131,3022,2742,1808,1132,1313, # 3334 + 265,1481,1857,7352, 352,1203,2813,3247, 167,1089, 420,2814, 776, 792,1724,3513, # 3350 +4071,2438,3248,7353,4072,7354, 446, 229, 333,2743, 901,3739,1200,1557,4316,2647, # 3366 +1920, 395,2744,2676,3740,4073,1835, 125, 916,3178,2616,4317,7355,7356,3741,7357, # 3382 +7358,7359,4318,3117,3625,1133,2547,1757,3415,1510,2313,1409,3514,7360,2145, 438, # 3398 +2591,2896,2379,3317,1068, 958,3023, 461, 311,2855,2677,4074,1915,3179,4075,1978, # 3414 + 383, 750,2745,2617,4076, 274, 539, 385,1278,1442,7361,1154,1964, 384, 561, 210, # 3430 + 98,1295,2548,3515,7362,1711,2415,1482,3416,3884,2897,1257, 129,7363,3742, 642, # 3446 + 523,2776,2777,2648,7364, 141,2231,1333, 68, 176, 441, 876, 907,4077, 603,2592, # 3462 + 710, 171,3417, 404, 549, 18,3118,2393,1410,3626,1666,7365,3516,4319,2898,4320, # 3478 +7366,2973, 368,7367, 146, 366, 99, 871,3627,1543, 748, 807,1586,1185, 22,2258, # 3494 + 379,3743,3180,7368,3181, 505,1941,2618,1991,1382,2314,7369, 380,2357, 218, 702, # 3510 +1817,1248,3418,3024,3517,3318,3249,7370,2974,3628, 930,3250,3744,7371, 59,7372, # 3526 + 585, 601,4078, 497,3419,1112,1314,4321,1801,7373,1223,1472,2174,7374, 749,1836, # 3542 + 690,1899,3745,1772,3885,1476, 429,1043,1790,2232,2116, 917,4079, 447,1086,1629, # 3558 +7375, 556,7376,7377,2020,1654, 844,1090, 105, 550, 966,1758,2815,1008,1782, 686, # 3574 +1095,7378,2282, 793,1602,7379,3518,2593,4322,4080,2933,2297,4323,3746, 980,2496, # 3590 + 544, 353, 527,4324, 908,2678,2899,7380, 381,2619,1942,1348,7381,1341,1252, 560, # 3606 +3072,7382,3420,2856,7383,2053, 973, 886,2080, 143,4325,7384,7385, 157,3886, 496, # 3622 +4081, 57, 840, 540,2038,4326,4327,3421,2117,1445, 970,2259,1748,1965,2081,4082, # 3638 +3119,1234,1775,3251,2816,3629, 773,1206,2129,1066,2039,1326,3887,1738,1725,4083, # 3654 + 279,3120, 51,1544,2594, 423,1578,2130,2066, 173,4328,1879,7386,7387,1583, 264, # 3670 + 610,3630,4329,2439, 280, 154,7388,7389,7390,1739, 338,1282,3073, 693,2857,1411, # 3686 +1074,3747,2440,7391,4330,7392,7393,1240, 952,2394,7394,2900,1538,2679, 685,1483, # 3702 +4084,2468,1436, 953,4085,2054,4331, 671,2395, 79,4086,2441,3252, 608, 567,2680, # 3718 +3422,4087,4088,1691, 393,1261,1791,2396,7395,4332,7396,7397,7398,7399,1383,1672, # 3734 +3748,3182,1464, 522,1119, 661,1150, 216, 675,4333,3888,1432,3519, 609,4334,2681, # 3750 +2397,7400,7401,7402,4089,3025, 0,7403,2469, 315, 231,2442, 301,3319,4335,2380, # 3766 +7404, 233,4090,3631,1818,4336,4337,7405, 96,1776,1315,2082,7406, 257,7407,1809, # 3782 +3632,2709,1139,1819,4091,2021,1124,2163,2778,1777,2649,7408,3074, 363,1655,3183, # 3798 +7409,2975,7410,7411,7412,3889,1567,3890, 718, 103,3184, 849,1443, 341,3320,2934, # 3814 +1484,7413,1712, 127, 67, 339,4092,2398, 679,1412, 821,7414,7415, 834, 738, 351, # 3830 +2976,2146, 846, 235,1497,1880, 418,1992,3749,2710, 186,1100,2147,2746,3520,1545, # 3846 +1355,2935,2858,1377, 583,3891,4093,2573,2977,7416,1298,3633,1078,2549,3634,2358, # 3862 + 78,3750,3751, 267,1289,2099,2001,1594,4094, 348, 369,1274,2194,2175,1837,4338, # 3878 +1820,2817,3635,2747,2283,2002,4339,2936,2748, 144,3321, 882,4340,3892,2749,3423, # 3894 +4341,2901,7417,4095,1726, 320,7418,3893,3026, 788,2978,7419,2818,1773,1327,2859, # 3910 +3894,2819,7420,1306,4342,2003,1700,3752,3521,2359,2650, 787,2022, 506, 824,3636, # 3926 + 534, 323,4343,1044,3322,2023,1900, 946,3424,7421,1778,1500,1678,7422,1881,4344, # 3942 + 165, 243,4345,3637,2521, 123, 683,4096, 764,4346, 36,3895,1792, 589,2902, 816, # 3958 + 626,1667,3027,2233,1639,1555,1622,3753,3896,7423,3897,2860,1370,1228,1932, 891, # 3974 +2083,2903, 304,4097,7424, 292,2979,2711,3522, 691,2100,4098,1115,4347, 118, 662, # 3990 +7425, 611,1156, 854,2381,1316,2861, 2, 386, 515,2904,7426,7427,3253, 868,2234, # 4006 +1486, 855,2651, 785,2212,3028,7428,1040,3185,3523,7429,3121, 448,7430,1525,7431, # 4022 +2164,4348,7432,3754,7433,4099,2820,3524,3122, 503, 818,3898,3123,1568, 814, 676, # 4038 +1444, 306,1749,7434,3755,1416,1030, 197,1428, 805,2821,1501,4349,7435,7436,7437, # 4054 +1993,7438,4350,7439,7440,2195, 13,2779,3638,2980,3124,1229,1916,7441,3756,2131, # 4070 +7442,4100,4351,2399,3525,7443,2213,1511,1727,1120,7444,7445, 646,3757,2443, 307, # 4086 +7446,7447,1595,3186,7448,7449,7450,3639,1113,1356,3899,1465,2522,2523,7451, 519, # 4102 +7452, 128,2132, 92,2284,1979,7453,3900,1512, 342,3125,2196,7454,2780,2214,1980, # 4118 +3323,7455, 290,1656,1317, 789, 827,2360,7456,3758,4352, 562, 581,3901,7457, 401, # 4134 +4353,2248, 94,4354,1399,2781,7458,1463,2024,4355,3187,1943,7459, 828,1105,4101, # 4150 +1262,1394,7460,4102, 605,4356,7461,1783,2862,7462,2822, 819,2101, 578,2197,2937, # 4166 +7463,1502, 436,3254,4103,3255,2823,3902,2905,3425,3426,7464,2712,2315,7465,7466, # 4182 +2332,2067, 23,4357, 193, 826,3759,2102, 699,1630,4104,3075, 390,1793,1064,3526, # 4198 +7467,1579,3076,3077,1400,7468,4105,1838,1640,2863,7469,4358,4359, 137,4106, 598, # 4214 +3078,1966, 780, 104, 974,2938,7470, 278, 899, 253, 402, 572, 504, 493,1339,7471, # 4230 +3903,1275,4360,2574,2550,7472,3640,3029,3079,2249, 565,1334,2713, 863, 41,7473, # 4246 +7474,4361,7475,1657,2333, 19, 463,2750,4107, 606,7476,2981,3256,1087,2084,1323, # 4262 +2652,2982,7477,1631,1623,1750,4108,2682,7478,2864, 791,2714,2653,2334, 232,2416, # 4278 +7479,2983,1498,7480,2654,2620, 755,1366,3641,3257,3126,2025,1609, 119,1917,3427, # 4294 + 862,1026,4109,7481,3904,3760,4362,3905,4363,2260,1951,2470,7482,1125, 817,4110, # 4310 +4111,3906,1513,1766,2040,1487,4112,3030,3258,2824,3761,3127,7483,7484,1507,7485, # 4326 +2683, 733, 40,1632,1106,2865, 345,4113, 841,2524, 230,4364,2984,1846,3259,3428, # 4342 +7486,1263, 986,3429,7487, 735, 879, 254,1137, 857, 622,1300,1180,1388,1562,3907, # 4358 +3908,2939, 967,2751,2655,1349, 592,2133,1692,3324,2985,1994,4114,1679,3909,1901, # 4374 +2185,7488, 739,3642,2715,1296,1290,7489,4115,2198,2199,1921,1563,2595,2551,1870, # 4390 +2752,2986,7490, 435,7491, 343,1108, 596, 17,1751,4365,2235,3430,3643,7492,4366, # 4406 + 294,3527,2940,1693, 477, 979, 281,2041,3528, 643,2042,3644,2621,2782,2261,1031, # 4422 +2335,2134,2298,3529,4367, 367,1249,2552,7493,3530,7494,4368,1283,3325,2004, 240, # 4438 +1762,3326,4369,4370, 836,1069,3128, 474,7495,2148,2525, 268,3531,7496,3188,1521, # 4454 +1284,7497,1658,1546,4116,7498,3532,3533,7499,4117,3327,2684,1685,4118, 961,1673, # 4470 +2622, 190,2005,2200,3762,4371,4372,7500, 570,2497,3645,1490,7501,4373,2623,3260, # 4486 +1956,4374, 584,1514, 396,1045,1944,7502,4375,1967,2444,7503,7504,4376,3910, 619, # 4502 +7505,3129,3261, 215,2006,2783,2553,3189,4377,3190,4378, 763,4119,3763,4379,7506, # 4518 +7507,1957,1767,2941,3328,3646,1174, 452,1477,4380,3329,3130,7508,2825,1253,2382, # 4534 +2186,1091,2285,4120, 492,7509, 638,1169,1824,2135,1752,3911, 648, 926,1021,1324, # 4550 +4381, 520,4382, 997, 847,1007, 892,4383,3764,2262,1871,3647,7510,2400,1784,4384, # 4566 +1952,2942,3080,3191,1728,4121,2043,3648,4385,2007,1701,3131,1551, 30,2263,4122, # 4582 +7511,2026,4386,3534,7512, 501,7513,4123, 594,3431,2165,1821,3535,3432,3536,3192, # 4598 + 829,2826,4124,7514,1680,3132,1225,4125,7515,3262,4387,4126,3133,2336,7516,4388, # 4614 +4127,7517,3912,3913,7518,1847,2383,2596,3330,7519,4389, 374,3914, 652,4128,4129, # 4630 + 375,1140, 798,7520,7521,7522,2361,4390,2264, 546,1659, 138,3031,2445,4391,7523, # 4646 +2250, 612,1848, 910, 796,3765,1740,1371, 825,3766,3767,7524,2906,2554,7525, 692, # 4662 + 444,3032,2624, 801,4392,4130,7526,1491, 244,1053,3033,4131,4132, 340,7527,3915, # 4678 +1041,2987, 293,1168, 87,1357,7528,1539, 959,7529,2236, 721, 694,4133,3768, 219, # 4694 +1478, 644,1417,3331,2656,1413,1401,1335,1389,3916,7530,7531,2988,2362,3134,1825, # 4710 + 730,1515, 184,2827, 66,4393,7532,1660,2943, 246,3332, 378,1457, 226,3433, 975, # 4726 +3917,2944,1264,3537, 674, 696,7533, 163,7534,1141,2417,2166, 713,3538,3333,4394, # 4742 +3918,7535,7536,1186, 15,7537,1079,1070,7538,1522,3193,3539, 276,1050,2716, 758, # 4758 +1126, 653,2945,3263,7539,2337, 889,3540,3919,3081,2989, 903,1250,4395,3920,3434, # 4774 +3541,1342,1681,1718, 766,3264, 286, 89,2946,3649,7540,1713,7541,2597,3334,2990, # 4790 +7542,2947,2215,3194,2866,7543,4396,2498,2526, 181, 387,1075,3921, 731,2187,3335, # 4806 +7544,3265, 310, 313,3435,2299, 770,4134, 54,3034, 189,4397,3082,3769,3922,7545, # 4822 +1230,1617,1849, 355,3542,4135,4398,3336, 111,4136,3650,1350,3135,3436,3035,4137, # 4838 +2149,3266,3543,7546,2784,3923,3924,2991, 722,2008,7547,1071, 247,1207,2338,2471, # 4854 +1378,4399,2009, 864,1437,1214,4400, 373,3770,1142,2216, 667,4401, 442,2753,2555, # 4870 +3771,3925,1968,4138,3267,1839, 837, 170,1107, 934,1336,1882,7548,7549,2118,4139, # 4886 +2828, 743,1569,7550,4402,4140, 582,2384,1418,3437,7551,1802,7552, 357,1395,1729, # 4902 +3651,3268,2418,1564,2237,7553,3083,3772,1633,4403,1114,2085,4141,1532,7554, 482, # 4918 +2446,4404,7555,7556,1492, 833,1466,7557,2717,3544,1641,2829,7558,1526,1272,3652, # 4934 +4142,1686,1794, 416,2556,1902,1953,1803,7559,3773,2785,3774,1159,2316,7560,2867, # 4950 +4405,1610,1584,3036,2419,2754, 443,3269,1163,3136,7561,7562,3926,7563,4143,2499, # 4966 +3037,4406,3927,3137,2103,1647,3545,2010,1872,4144,7564,4145, 431,3438,7565, 250, # 4982 + 97, 81,4146,7566,1648,1850,1558, 160, 848,7567, 866, 740,1694,7568,2201,2830, # 4998 +3195,4147,4407,3653,1687, 950,2472, 426, 469,3196,3654,3655,3928,7569,7570,1188, # 5014 + 424,1995, 861,3546,4148,3775,2202,2685, 168,1235,3547,4149,7571,2086,1674,4408, # 5030 +3337,3270, 220,2557,1009,7572,3776, 670,2992, 332,1208, 717,7573,7574,3548,2447, # 5046 +3929,3338,7575, 513,7576,1209,2868,3339,3138,4409,1080,7577,7578,7579,7580,2527, # 5062 +3656,3549, 815,1587,3930,3931,7581,3550,3439,3777,1254,4410,1328,3038,1390,3932, # 5078 +1741,3933,3778,3934,7582, 236,3779,2448,3271,7583,7584,3657,3780,1273,3781,4411, # 5094 +7585, 308,7586,4412, 245,4413,1851,2473,1307,2575, 430, 715,2136,2449,7587, 270, # 5110 + 199,2869,3935,7588,3551,2718,1753, 761,1754, 725,1661,1840,4414,3440,3658,7589, # 5126 +7590, 587, 14,3272, 227,2598, 326, 480,2265, 943,2755,3552, 291, 650,1883,7591, # 5142 +1702,1226, 102,1547, 62,3441, 904,4415,3442,1164,4150,7592,7593,1224,1548,2756, # 5158 + 391, 498,1493,7594,1386,1419,7595,2055,1177,4416, 813, 880,1081,2363, 566,1145, # 5174 +4417,2286,1001,1035,2558,2599,2238, 394,1286,7596,7597,2068,7598, 86,1494,1730, # 5190 +3936, 491,1588, 745, 897,2948, 843,3340,3937,2757,2870,3273,1768, 998,2217,2069, # 5206 + 397,1826,1195,1969,3659,2993,3341, 284,7599,3782,2500,2137,2119,1903,7600,3938, # 5222 +2150,3939,4151,1036,3443,1904, 114,2559,4152, 209,1527,7601,7602,2949,2831,2625, # 5238 +2385,2719,3139, 812,2560,7603,3274,7604,1559, 737,1884,3660,1210, 885, 28,2686, # 5254 +3553,3783,7605,4153,1004,1779,4418,7606, 346,1981,2218,2687,4419,3784,1742, 797, # 5270 +1642,3940,1933,1072,1384,2151, 896,3941,3275,3661,3197,2871,3554,7607,2561,1958, # 5286 +4420,2450,1785,7608,7609,7610,3942,4154,1005,1308,3662,4155,2720,4421,4422,1528, # 5302 +2600, 161,1178,4156,1982, 987,4423,1101,4157, 631,3943,1157,3198,2420,1343,1241, # 5318 +1016,2239,2562, 372, 877,2339,2501,1160, 555,1934, 911,3944,7611, 466,1170, 169, # 5334 +1051,2907,2688,3663,2474,2994,1182,2011,2563,1251,2626,7612, 992,2340,3444,1540, # 5350 +2721,1201,2070,2401,1996,2475,7613,4424, 528,1922,2188,1503,1873,1570,2364,3342, # 5366 +3276,7614, 557,1073,7615,1827,3445,2087,2266,3140,3039,3084, 767,3085,2786,4425, # 5382 +1006,4158,4426,2341,1267,2176,3664,3199, 778,3945,3200,2722,1597,2657,7616,4427, # 5398 +7617,3446,7618,7619,7620,3277,2689,1433,3278, 131, 95,1504,3946, 723,4159,3141, # 5414 +1841,3555,2758,2189,3947,2027,2104,3665,7621,2995,3948,1218,7622,3343,3201,3949, # 5430 +4160,2576, 248,1634,3785, 912,7623,2832,3666,3040,3786, 654, 53,7624,2996,7625, # 5446 +1688,4428, 777,3447,1032,3950,1425,7626, 191, 820,2120,2833, 971,4429, 931,3202, # 5462 + 135, 664, 783,3787,1997, 772,2908,1935,3951,3788,4430,2909,3203, 282,2723, 640, # 5478 +1372,3448,1127, 922, 325,3344,7627,7628, 711,2044,7629,7630,3952,2219,2787,1936, # 5494 +3953,3345,2220,2251,3789,2300,7631,4431,3790,1258,3279,3954,3204,2138,2950,3955, # 5510 +3956,7632,2221, 258,3205,4432, 101,1227,7633,3280,1755,7634,1391,3281,7635,2910, # 5526 +2056, 893,7636,7637,7638,1402,4161,2342,7639,7640,3206,3556,7641,7642, 878,1325, # 5542 +1780,2788,4433, 259,1385,2577, 744,1183,2267,4434,7643,3957,2502,7644, 684,1024, # 5558 +4162,7645, 472,3557,3449,1165,3282,3958,3959, 322,2152, 881, 455,1695,1152,1340, # 5574 + 660, 554,2153,4435,1058,4436,4163, 830,1065,3346,3960,4437,1923,7646,1703,1918, # 5590 +7647, 932,2268, 122,7648,4438, 947, 677,7649,3791,2627, 297,1905,1924,2269,4439, # 5606 +2317,3283,7650,7651,4164,7652,4165, 84,4166, 112, 989,7653, 547,1059,3961, 701, # 5622 +3558,1019,7654,4167,7655,3450, 942, 639, 457,2301,2451, 993,2951, 407, 851, 494, # 5638 +4440,3347, 927,7656,1237,7657,2421,3348, 573,4168, 680, 921,2911,1279,1874, 285, # 5654 + 790,1448,1983, 719,2167,7658,7659,4441,3962,3963,1649,7660,1541, 563,7661,1077, # 5670 +7662,3349,3041,3451, 511,2997,3964,3965,3667,3966,1268,2564,3350,3207,4442,4443, # 5686 +7663, 535,1048,1276,1189,2912,2028,3142,1438,1373,2834,2952,1134,2012,7664,4169, # 5702 +1238,2578,3086,1259,7665, 700,7666,2953,3143,3668,4170,7667,4171,1146,1875,1906, # 5718 +4444,2601,3967, 781,2422, 132,1589, 203, 147, 273,2789,2402, 898,1786,2154,3968, # 5734 +3969,7668,3792,2790,7669,7670,4445,4446,7671,3208,7672,1635,3793, 965,7673,1804, # 5750 +2690,1516,3559,1121,1082,1329,3284,3970,1449,3794, 65,1128,2835,2913,2759,1590, # 5766 +3795,7674,7675, 12,2658, 45, 976,2579,3144,4447, 517,2528,1013,1037,3209,7676, # 5782 +3796,2836,7677,3797,7678,3452,7679,2602, 614,1998,2318,3798,3087,2724,2628,7680, # 5798 +2580,4172, 599,1269,7681,1810,3669,7682,2691,3088, 759,1060, 489,1805,3351,3285, # 5814 +1358,7683,7684,2386,1387,1215,2629,2252, 490,7685,7686,4173,1759,2387,2343,7687, # 5830 +4448,3799,1907,3971,2630,1806,3210,4449,3453,3286,2760,2344, 874,7688,7689,3454, # 5846 +3670,1858, 91,2914,3671,3042,3800,4450,7690,3145,3972,2659,7691,3455,1202,1403, # 5862 +3801,2954,2529,1517,2503,4451,3456,2504,7692,4452,7693,2692,1885,1495,1731,3973, # 5878 +2365,4453,7694,2029,7695,7696,3974,2693,1216, 237,2581,4174,2319,3975,3802,4454, # 5894 +4455,2694,3560,3457, 445,4456,7697,7698,7699,7700,2761, 61,3976,3672,1822,3977, # 5910 +7701, 687,2045, 935, 925, 405,2660, 703,1096,1859,2725,4457,3978,1876,1367,2695, # 5926 +3352, 918,2105,1781,2476, 334,3287,1611,1093,4458, 564,3146,3458,3673,3353, 945, # 5942 +2631,2057,4459,7702,1925, 872,4175,7703,3459,2696,3089, 349,4176,3674,3979,4460, # 5958 +3803,4177,3675,2155,3980,4461,4462,4178,4463,2403,2046, 782,3981, 400, 251,4179, # 5974 +1624,7704,7705, 277,3676, 299,1265, 476,1191,3804,2121,4180,4181,1109, 205,7706, # 5990 +2582,1000,2156,3561,1860,7707,7708,7709,4464,7710,4465,2565, 107,2477,2157,3982, # 6006 +3460,3147,7711,1533, 541,1301, 158, 753,4182,2872,3562,7712,1696, 370,1088,4183, # 6022 +4466,3563, 579, 327, 440, 162,2240, 269,1937,1374,3461, 968,3043, 56,1396,3090, # 6038 +2106,3288,3354,7713,1926,2158,4467,2998,7714,3564,7715,7716,3677,4468,2478,7717, # 6054 +2791,7718,1650,4469,7719,2603,7720,7721,3983,2661,3355,1149,3356,3984,3805,3985, # 6070 +7722,1076, 49,7723, 951,3211,3289,3290, 450,2837, 920,7724,1811,2792,2366,4184, # 6086 +1908,1138,2367,3806,3462,7725,3212,4470,1909,1147,1518,2423,4471,3807,7726,4472, # 6102 +2388,2604, 260,1795,3213,7727,7728,3808,3291, 708,7729,3565,1704,7730,3566,1351, # 6118 +1618,3357,2999,1886, 944,4185,3358,4186,3044,3359,4187,7731,3678, 422, 413,1714, # 6134 +3292, 500,2058,2345,4188,2479,7732,1344,1910, 954,7733,1668,7734,7735,3986,2404, # 6150 +4189,3567,3809,4190,7736,2302,1318,2505,3091, 133,3092,2873,4473, 629, 31,2838, # 6166 +2697,3810,4474, 850, 949,4475,3987,2955,1732,2088,4191,1496,1852,7737,3988, 620, # 6182 +3214, 981,1242,3679,3360,1619,3680,1643,3293,2139,2452,1970,1719,3463,2168,7738, # 6198 +3215,7739,7740,3361,1828,7741,1277,4476,1565,2047,7742,1636,3568,3093,7743, 869, # 6214 +2839, 655,3811,3812,3094,3989,3000,3813,1310,3569,4477,7744,7745,7746,1733, 558, # 6230 +4478,3681, 335,1549,3045,1756,4192,3682,1945,3464,1829,1291,1192, 470,2726,2107, # 6246 +2793, 913,1054,3990,7747,1027,7748,3046,3991,4479, 982,2662,3362,3148,3465,3216, # 6262 +3217,1946,2794,7749, 571,4480,7750,1830,7751,3570,2583,1523,2424,7752,2089, 984, # 6278 +4481,3683,1959,7753,3684, 852, 923,2795,3466,3685, 969,1519, 999,2048,2320,1705, # 6294 +7754,3095, 615,1662, 151, 597,3992,2405,2321,1049, 275,4482,3686,4193, 568,3687, # 6310 +3571,2480,4194,3688,7755,2425,2270, 409,3218,7756,1566,2874,3467,1002, 769,2840, # 6326 + 194,2090,3149,3689,2222,3294,4195, 628,1505,7757,7758,1763,2177,3001,3993, 521, # 6342 +1161,2584,1787,2203,2406,4483,3994,1625,4196,4197, 412, 42,3096, 464,7759,2632, # 6358 +4484,3363,1760,1571,2875,3468,2530,1219,2204,3814,2633,2140,2368,4485,4486,3295, # 6374 +1651,3364,3572,7760,7761,3573,2481,3469,7762,3690,7763,7764,2271,2091, 460,7765, # 6390 +4487,7766,3002, 962, 588,3574, 289,3219,2634,1116, 52,7767,3047,1796,7768,7769, # 6406 +7770,1467,7771,1598,1143,3691,4198,1984,1734,1067,4488,1280,3365, 465,4489,1572, # 6422 + 510,7772,1927,2241,1812,1644,3575,7773,4490,3692,7774,7775,2663,1573,1534,7776, # 6438 +7777,4199, 536,1807,1761,3470,3815,3150,2635,7778,7779,7780,4491,3471,2915,1911, # 6454 +2796,7781,3296,1122, 377,3220,7782, 360,7783,7784,4200,1529, 551,7785,2059,3693, # 6470 +1769,2426,7786,2916,4201,3297,3097,2322,2108,2030,4492,1404, 136,1468,1479, 672, # 6486 +1171,3221,2303, 271,3151,7787,2762,7788,2049, 678,2727, 865,1947,4493,7789,2013, # 6502 +3995,2956,7790,2728,2223,1397,3048,3694,4494,4495,1735,2917,3366,3576,7791,3816, # 6518 + 509,2841,2453,2876,3817,7792,7793,3152,3153,4496,4202,2531,4497,2304,1166,1010, # 6534 + 552, 681,1887,7794,7795,2957,2958,3996,1287,1596,1861,3154, 358, 453, 736, 175, # 6550 + 478,1117, 905,1167,1097,7796,1853,1530,7797,1706,7798,2178,3472,2287,3695,3473, # 6566 +3577,4203,2092,4204,7799,3367,1193,2482,4205,1458,2190,2205,1862,1888,1421,3298, # 6582 +2918,3049,2179,3474, 595,2122,7800,3997,7801,7802,4206,1707,2636, 223,3696,1359, # 6598 + 751,3098, 183,3475,7803,2797,3003, 419,2369, 633, 704,3818,2389, 241,7804,7805, # 6614 +7806, 838,3004,3697,2272,2763,2454,3819,1938,2050,3998,1309,3099,2242,1181,7807, # 6630 +1136,2206,3820,2370,1446,4207,2305,4498,7808,7809,4208,1055,2605, 484,3698,7810, # 6646 +3999, 625,4209,2273,3368,1499,4210,4000,7811,4001,4211,3222,2274,2275,3476,7812, # 6662 +7813,2764, 808,2606,3699,3369,4002,4212,3100,2532, 526,3370,3821,4213, 955,7814, # 6678 +1620,4214,2637,2427,7815,1429,3700,1669,1831, 994, 928,7816,3578,1260,7817,7818, # 6694 +7819,1948,2288, 741,2919,1626,4215,2729,2455, 867,1184, 362,3371,1392,7820,7821, # 6710 +4003,4216,1770,1736,3223,2920,4499,4500,1928,2698,1459,1158,7822,3050,3372,2877, # 6726 +1292,1929,2506,2842,3701,1985,1187,2071,2014,2607,4217,7823,2566,2507,2169,3702, # 6742 +2483,3299,7824,3703,4501,7825,7826, 666,1003,3005,1022,3579,4218,7827,4502,1813, # 6758 +2253, 574,3822,1603, 295,1535, 705,3823,4219, 283, 858, 417,7828,7829,3224,4503, # 6774 +4504,3051,1220,1889,1046,2276,2456,4004,1393,1599, 689,2567, 388,4220,7830,2484, # 6790 + 802,7831,2798,3824,2060,1405,2254,7832,4505,3825,2109,1052,1345,3225,1585,7833, # 6806 + 809,7834,7835,7836, 575,2730,3477, 956,1552,1469,1144,2323,7837,2324,1560,2457, # 6822 +3580,3226,4005, 616,2207,3155,2180,2289,7838,1832,7839,3478,4506,7840,1319,3704, # 6838 +3705,1211,3581,1023,3227,1293,2799,7841,7842,7843,3826, 607,2306,3827, 762,2878, # 6854 +1439,4221,1360,7844,1485,3052,7845,4507,1038,4222,1450,2061,2638,4223,1379,4508, # 6870 +2585,7846,7847,4224,1352,1414,2325,2921,1172,7848,7849,3828,3829,7850,1797,1451, # 6886 +7851,7852,7853,7854,2922,4006,4007,2485,2346, 411,4008,4009,3582,3300,3101,4509, # 6902 +1561,2664,1452,4010,1375,7855,7856, 47,2959, 316,7857,1406,1591,2923,3156,7858, # 6918 +1025,2141,3102,3157, 354,2731, 884,2224,4225,2407, 508,3706, 726,3583, 996,2428, # 6934 +3584, 729,7859, 392,2191,1453,4011,4510,3707,7860,7861,2458,3585,2608,1675,2800, # 6950 + 919,2347,2960,2348,1270,4511,4012, 73,7862,7863, 647,7864,3228,2843,2255,1550, # 6966 +1346,3006,7865,1332, 883,3479,7866,7867,7868,7869,3301,2765,7870,1212, 831,1347, # 6982 +4226,4512,2326,3830,1863,3053, 720,3831,4513,4514,3832,7871,4227,7872,7873,4515, # 6998 +7874,7875,1798,4516,3708,2609,4517,3586,1645,2371,7876,7877,2924, 669,2208,2665, # 7014 +2429,7878,2879,7879,7880,1028,3229,7881,4228,2408,7882,2256,1353,7883,7884,4518, # 7030 +3158, 518,7885,4013,7886,4229,1960,7887,2142,4230,7888,7889,3007,2349,2350,3833, # 7046 + 516,1833,1454,4014,2699,4231,4519,2225,2610,1971,1129,3587,7890,2766,7891,2961, # 7062 +1422, 577,1470,3008,1524,3373,7892,7893, 432,4232,3054,3480,7894,2586,1455,2508, # 7078 +2226,1972,1175,7895,1020,2732,4015,3481,4520,7896,2733,7897,1743,1361,3055,3482, # 7094 +2639,4016,4233,4521,2290, 895, 924,4234,2170, 331,2243,3056, 166,1627,3057,1098, # 7110 +7898,1232,2880,2227,3374,4522, 657, 403,1196,2372, 542,3709,3375,1600,4235,3483, # 7126 +7899,4523,2767,3230, 576, 530,1362,7900,4524,2533,2666,3710,4017,7901, 842,3834, # 7142 +7902,2801,2031,1014,4018, 213,2700,3376, 665, 621,4236,7903,3711,2925,2430,7904, # 7158 +2431,3302,3588,3377,7905,4237,2534,4238,4525,3589,1682,4239,3484,1380,7906, 724, # 7174 +2277, 600,1670,7907,1337,1233,4526,3103,2244,7908,1621,4527,7909, 651,4240,7910, # 7190 +1612,4241,2611,7911,2844,7912,2734,2307,3058,7913, 716,2459,3059, 174,1255,2701, # 7206 +4019,3590, 548,1320,1398, 728,4020,1574,7914,1890,1197,3060,4021,7915,3061,3062, # 7222 +3712,3591,3713, 747,7916, 635,4242,4528,7917,7918,7919,4243,7920,7921,4529,7922, # 7238 +3378,4530,2432, 451,7923,3714,2535,2072,4244,2735,4245,4022,7924,1764,4531,7925, # 7254 +4246, 350,7926,2278,2390,2486,7927,4247,4023,2245,1434,4024, 488,4532, 458,4248, # 7270 +4025,3715, 771,1330,2391,3835,2568,3159,2159,2409,1553,2667,3160,4249,7928,2487, # 7286 +2881,2612,1720,2702,4250,3379,4533,7929,2536,4251,7930,3231,4252,2768,7931,2015, # 7302 +2736,7932,1155,1017,3716,3836,7933,3303,2308, 201,1864,4253,1430,7934,4026,7935, # 7318 +7936,7937,7938,7939,4254,1604,7940, 414,1865, 371,2587,4534,4535,3485,2016,3104, # 7334 +4536,1708, 960,4255, 887, 389,2171,1536,1663,1721,7941,2228,4027,2351,2926,1580, # 7350 +7942,7943,7944,1744,7945,2537,4537,4538,7946,4539,7947,2073,7948,7949,3592,3380, # 7366 +2882,4256,7950,4257,2640,3381,2802, 673,2703,2460, 709,3486,4028,3593,4258,7951, # 7382 +1148, 502, 634,7952,7953,1204,4540,3594,1575,4541,2613,3717,7954,3718,3105, 948, # 7398 +3232, 121,1745,3837,1110,7955,4259,3063,2509,3009,4029,3719,1151,1771,3838,1488, # 7414 +4030,1986,7956,2433,3487,7957,7958,2093,7959,4260,3839,1213,1407,2803, 531,2737, # 7430 +2538,3233,1011,1537,7960,2769,4261,3106,1061,7961,3720,3721,1866,2883,7962,2017, # 7446 + 120,4262,4263,2062,3595,3234,2309,3840,2668,3382,1954,4542,7963,7964,3488,1047, # 7462 +2704,1266,7965,1368,4543,2845, 649,3383,3841,2539,2738,1102,2846,2669,7966,7967, # 7478 +1999,7968,1111,3596,2962,7969,2488,3842,3597,2804,1854,3384,3722,7970,7971,3385, # 7494 +2410,2884,3304,3235,3598,7972,2569,7973,3599,2805,4031,1460, 856,7974,3600,7975, # 7510 +2885,2963,7976,2886,3843,7977,4264, 632,2510, 875,3844,1697,3845,2291,7978,7979, # 7526 +4544,3010,1239, 580,4545,4265,7980, 914, 936,2074,1190,4032,1039,2123,7981,7982, # 7542 +7983,3386,1473,7984,1354,4266,3846,7985,2172,3064,4033, 915,3305,4267,4268,3306, # 7558 +1605,1834,7986,2739, 398,3601,4269,3847,4034, 328,1912,2847,4035,3848,1331,4270, # 7574 +3011, 937,4271,7987,3602,4036,4037,3387,2160,4546,3388, 524, 742, 538,3065,1012, # 7590 +7988,7989,3849,2461,7990, 658,1103, 225,3850,7991,7992,4547,7993,4548,7994,3236, # 7606 +1243,7995,4038, 963,2246,4549,7996,2705,3603,3161,7997,7998,2588,2327,7999,4550, # 7622 +8000,8001,8002,3489,3307, 957,3389,2540,2032,1930,2927,2462, 870,2018,3604,1746, # 7638 +2770,2771,2434,2463,8003,3851,8004,3723,3107,3724,3490,3390,3725,8005,1179,3066, # 7654 +8006,3162,2373,4272,3726,2541,3163,3108,2740,4039,8007,3391,1556,2542,2292, 977, # 7670 +2887,2033,4040,1205,3392,8008,1765,3393,3164,2124,1271,1689, 714,4551,3491,8009, # 7686 +2328,3852, 533,4273,3605,2181, 617,8010,2464,3308,3492,2310,8011,8012,3165,8013, # 7702 +8014,3853,1987, 618, 427,2641,3493,3394,8015,8016,1244,1690,8017,2806,4274,4552, # 7718 +8018,3494,8019,8020,2279,1576, 473,3606,4275,3395, 972,8021,3607,8022,3067,8023, # 7734 +8024,4553,4554,8025,3727,4041,4042,8026, 153,4555, 356,8027,1891,2888,4276,2143, # 7750 + 408, 803,2352,8028,3854,8029,4277,1646,2570,2511,4556,4557,3855,8030,3856,4278, # 7766 +8031,2411,3396, 752,8032,8033,1961,2964,8034, 746,3012,2465,8035,4279,3728, 698, # 7782 +4558,1892,4280,3608,2543,4559,3609,3857,8036,3166,3397,8037,1823,1302,4043,2706, # 7798 +3858,1973,4281,8038,4282,3167, 823,1303,1288,1236,2848,3495,4044,3398, 774,3859, # 7814 +8039,1581,4560,1304,2849,3860,4561,8040,2435,2161,1083,3237,4283,4045,4284, 344, # 7830 +1173, 288,2311, 454,1683,8041,8042,1461,4562,4046,2589,8043,8044,4563, 985, 894, # 7846 +8045,3399,3168,8046,1913,2928,3729,1988,8047,2110,1974,8048,4047,8049,2571,1194, # 7862 + 425,8050,4564,3169,1245,3730,4285,8051,8052,2850,8053, 636,4565,1855,3861, 760, # 7878 +1799,8054,4286,2209,1508,4566,4048,1893,1684,2293,8055,8056,8057,4287,4288,2210, # 7894 + 479,8058,8059, 832,8060,4049,2489,8061,2965,2490,3731, 990,3109, 627,1814,2642, # 7910 +4289,1582,4290,2125,2111,3496,4567,8062, 799,4291,3170,8063,4568,2112,1737,3013, # 7926 +1018, 543, 754,4292,3309,1676,4569,4570,4050,8064,1489,8065,3497,8066,2614,2889, # 7942 +4051,8067,8068,2966,8069,8070,8071,8072,3171,4571,4572,2182,1722,8073,3238,3239, # 7958 +1842,3610,1715, 481, 365,1975,1856,8074,8075,1962,2491,4573,8076,2126,3611,3240, # 7974 + 433,1894,2063,2075,8077, 602,2741,8078,8079,8080,8081,8082,3014,1628,3400,8083, # 7990 +3172,4574,4052,2890,4575,2512,8084,2544,2772,8085,8086,8087,3310,4576,2891,8088, # 8006 +4577,8089,2851,4578,4579,1221,2967,4053,2513,8090,8091,8092,1867,1989,8093,8094, # 8022 +8095,1895,8096,8097,4580,1896,4054, 318,8098,2094,4055,4293,8099,8100, 485,8101, # 8038 + 938,3862, 553,2670, 116,8102,3863,3612,8103,3498,2671,2773,3401,3311,2807,8104, # 8054 +3613,2929,4056,1747,2930,2968,8105,8106, 207,8107,8108,2672,4581,2514,8109,3015, # 8070 + 890,3614,3864,8110,1877,3732,3402,8111,2183,2353,3403,1652,8112,8113,8114, 941, # 8086 +2294, 208,3499,4057,2019, 330,4294,3865,2892,2492,3733,4295,8115,8116,8117,8118, # 8102 +) + diff --git a/venv/lib/python3.8/site-packages/chardet/euctwprober.py b/venv/lib/python3.8/site-packages/chardet/euctwprober.py new file mode 100644 index 0000000..35669cc --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/euctwprober.py @@ -0,0 +1,46 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .mbcharsetprober import MultiByteCharSetProber +from .codingstatemachine import CodingStateMachine +from .chardistribution import EUCTWDistributionAnalysis +from .mbcssm import EUCTW_SM_MODEL + +class EUCTWProber(MultiByteCharSetProber): + def __init__(self): + super(EUCTWProber, self).__init__() + self.coding_sm = CodingStateMachine(EUCTW_SM_MODEL) + self.distribution_analyzer = EUCTWDistributionAnalysis() + self.reset() + + @property + def charset_name(self): + return "EUC-TW" + + @property + def language(self): + return "Taiwan" diff --git a/venv/lib/python3.8/site-packages/chardet/gb2312freq.py b/venv/lib/python3.8/site-packages/chardet/gb2312freq.py new file mode 100644 index 0000000..697837b --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/gb2312freq.py @@ -0,0 +1,283 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# GB2312 most frequently used character table +# +# Char to FreqOrder table , from hz6763 + +# 512 --> 0.79 -- 0.79 +# 1024 --> 0.92 -- 0.13 +# 2048 --> 0.98 -- 0.06 +# 6768 --> 1.00 -- 0.02 +# +# Ideal Distribution Ratio = 0.79135/(1-0.79135) = 3.79 +# Random Distribution Ration = 512 / (3755 - 512) = 0.157 +# +# Typical Distribution Ratio about 25% of Ideal one, still much higher that RDR + +GB2312_TYPICAL_DISTRIBUTION_RATIO = 0.9 + +GB2312_TABLE_SIZE = 3760 + +GB2312_CHAR_TO_FREQ_ORDER = ( +1671, 749,1443,2364,3924,3807,2330,3921,1704,3463,2691,1511,1515, 572,3191,2205, +2361, 224,2558, 479,1711, 963,3162, 440,4060,1905,2966,2947,3580,2647,3961,3842, +2204, 869,4207, 970,2678,5626,2944,2956,1479,4048, 514,3595, 588,1346,2820,3409, + 249,4088,1746,1873,2047,1774, 581,1813, 358,1174,3590,1014,1561,4844,2245, 670, +1636,3112, 889,1286, 953, 556,2327,3060,1290,3141, 613, 185,3477,1367, 850,3820, +1715,2428,2642,2303,2732,3041,2562,2648,3566,3946,1349, 388,3098,2091,1360,3585, + 152,1687,1539, 738,1559, 59,1232,2925,2267,1388,1249,1741,1679,2960, 151,1566, +1125,1352,4271, 924,4296, 385,3166,4459, 310,1245,2850, 70,3285,2729,3534,3575, +2398,3298,3466,1960,2265, 217,3647, 864,1909,2084,4401,2773,1010,3269,5152, 853, +3051,3121,1244,4251,1895, 364,1499,1540,2313,1180,3655,2268, 562, 715,2417,3061, + 544, 336,3768,2380,1752,4075, 950, 280,2425,4382, 183,2759,3272, 333,4297,2155, +1688,2356,1444,1039,4540, 736,1177,3349,2443,2368,2144,2225, 565, 196,1482,3406, + 927,1335,4147, 692, 878,1311,1653,3911,3622,1378,4200,1840,2969,3149,2126,1816, +2534,1546,2393,2760, 737,2494, 13, 447, 245,2747, 38,2765,2129,2589,1079, 606, + 360, 471,3755,2890, 404, 848, 699,1785,1236, 370,2221,1023,3746,2074,2026,2023, +2388,1581,2119, 812,1141,3091,2536,1519, 804,2053, 406,1596,1090, 784, 548,4414, +1806,2264,2936,1100, 343,4114,5096, 622,3358, 743,3668,1510,1626,5020,3567,2513, +3195,4115,5627,2489,2991, 24,2065,2697,1087,2719, 48,1634, 315, 68, 985,2052, + 198,2239,1347,1107,1439, 597,2366,2172, 871,3307, 919,2487,2790,1867, 236,2570, +1413,3794, 906,3365,3381,1701,1982,1818,1524,2924,1205, 616,2586,2072,2004, 575, + 253,3099, 32,1365,1182, 197,1714,2454,1201, 554,3388,3224,2748, 756,2587, 250, +2567,1507,1517,3529,1922,2761,2337,3416,1961,1677,2452,2238,3153, 615, 911,1506, +1474,2495,1265,1906,2749,3756,3280,2161, 898,2714,1759,3450,2243,2444, 563, 26, +3286,2266,3769,3344,2707,3677, 611,1402, 531,1028,2871,4548,1375, 261,2948, 835, +1190,4134, 353, 840,2684,1900,3082,1435,2109,1207,1674, 329,1872,2781,4055,2686, +2104, 608,3318,2423,2957,2768,1108,3739,3512,3271,3985,2203,1771,3520,1418,2054, +1681,1153, 225,1627,2929, 162,2050,2511,3687,1954, 124,1859,2431,1684,3032,2894, + 585,4805,3969,2869,2704,2088,2032,2095,3656,2635,4362,2209, 256, 518,2042,2105, +3777,3657, 643,2298,1148,1779, 190, 989,3544, 414, 11,2135,2063,2979,1471, 403, +3678, 126, 770,1563, 671,2499,3216,2877, 600,1179, 307,2805,4937,1268,1297,2694, + 252,4032,1448,1494,1331,1394, 127,2256, 222,1647,1035,1481,3056,1915,1048, 873, +3651, 210, 33,1608,2516, 200,1520, 415, 102, 0,3389,1287, 817, 91,3299,2940, + 836,1814, 549,2197,1396,1669,2987,3582,2297,2848,4528,1070, 687, 20,1819, 121, +1552,1364,1461,1968,2617,3540,2824,2083, 177, 948,4938,2291, 110,4549,2066, 648, +3359,1755,2110,2114,4642,4845,1693,3937,3308,1257,1869,2123, 208,1804,3159,2992, +2531,2549,3361,2418,1350,2347,2800,2568,1291,2036,2680, 72, 842,1990, 212,1233, +1154,1586, 75,2027,3410,4900,1823,1337,2710,2676, 728,2810,1522,3026,4995, 157, + 755,1050,4022, 710, 785,1936,2194,2085,1406,2777,2400, 150,1250,4049,1206, 807, +1910, 534, 529,3309,1721,1660, 274, 39,2827, 661,2670,1578, 925,3248,3815,1094, +4278,4901,4252, 41,1150,3747,2572,2227,4501,3658,4902,3813,3357,3617,2884,2258, + 887, 538,4187,3199,1294,2439,3042,2329,2343,2497,1255, 107, 543,1527, 521,3478, +3568, 194,5062, 15, 961,3870,1241,1192,2664, 66,5215,3260,2111,1295,1127,2152, +3805,4135, 901,1164,1976, 398,1278, 530,1460, 748, 904,1054,1966,1426, 53,2909, + 509, 523,2279,1534, 536,1019, 239,1685, 460,2353, 673,1065,2401,3600,4298,2272, +1272,2363, 284,1753,3679,4064,1695, 81, 815,2677,2757,2731,1386, 859, 500,4221, +2190,2566, 757,1006,2519,2068,1166,1455, 337,2654,3203,1863,1682,1914,3025,1252, +1409,1366, 847, 714,2834,2038,3209, 964,2970,1901, 885,2553,1078,1756,3049, 301, +1572,3326, 688,2130,1996,2429,1805,1648,2930,3421,2750,3652,3088, 262,1158,1254, + 389,1641,1812, 526,1719, 923,2073,1073,1902, 468, 489,4625,1140, 857,2375,3070, +3319,2863, 380, 116,1328,2693,1161,2244, 273,1212,1884,2769,3011,1775,1142, 461, +3066,1200,2147,2212, 790, 702,2695,4222,1601,1058, 434,2338,5153,3640, 67,2360, +4099,2502, 618,3472,1329, 416,1132, 830,2782,1807,2653,3211,3510,1662, 192,2124, + 296,3979,1739,1611,3684, 23, 118, 324, 446,1239,1225, 293,2520,3814,3795,2535, +3116, 17,1074, 467,2692,2201, 387,2922, 45,1326,3055,1645,3659,2817, 958, 243, +1903,2320,1339,2825,1784,3289, 356, 576, 865,2315,2381,3377,3916,1088,3122,1713, +1655, 935, 628,4689,1034,1327, 441, 800, 720, 894,1979,2183,1528,5289,2702,1071, +4046,3572,2399,1571,3281, 79, 761,1103, 327, 134, 758,1899,1371,1615, 879, 442, + 215,2605,2579, 173,2048,2485,1057,2975,3317,1097,2253,3801,4263,1403,1650,2946, + 814,4968,3487,1548,2644,1567,1285, 2, 295,2636, 97, 946,3576, 832, 141,4257, +3273, 760,3821,3521,3156,2607, 949,1024,1733,1516,1803,1920,2125,2283,2665,3180, +1501,2064,3560,2171,1592, 803,3518,1416, 732,3897,4258,1363,1362,2458, 119,1427, + 602,1525,2608,1605,1639,3175, 694,3064, 10, 465, 76,2000,4846,4208, 444,3781, +1619,3353,2206,1273,3796, 740,2483, 320,1723,2377,3660,2619,1359,1137,1762,1724, +2345,2842,1850,1862, 912, 821,1866, 612,2625,1735,2573,3369,1093, 844, 89, 937, + 930,1424,3564,2413,2972,1004,3046,3019,2011, 711,3171,1452,4178, 428, 801,1943, + 432, 445,2811, 206,4136,1472, 730, 349, 73, 397,2802,2547, 998,1637,1167, 789, + 396,3217, 154,1218, 716,1120,1780,2819,4826,1931,3334,3762,2139,1215,2627, 552, +3664,3628,3232,1405,2383,3111,1356,2652,3577,3320,3101,1703, 640,1045,1370,1246, +4996, 371,1575,2436,1621,2210, 984,4033,1734,2638, 16,4529, 663,2755,3255,1451, +3917,2257,1253,1955,2234,1263,2951, 214,1229, 617, 485, 359,1831,1969, 473,2310, + 750,2058, 165, 80,2864,2419, 361,4344,2416,2479,1134, 796,3726,1266,2943, 860, +2715, 938, 390,2734,1313,1384, 248, 202, 877,1064,2854, 522,3907, 279,1602, 297, +2357, 395,3740, 137,2075, 944,4089,2584,1267,3802, 62,1533,2285, 178, 176, 780, +2440, 201,3707, 590, 478,1560,4354,2117,1075, 30, 74,4643,4004,1635,1441,2745, + 776,2596, 238,1077,1692,1912,2844, 605, 499,1742,3947, 241,3053, 980,1749, 936, +2640,4511,2582, 515,1543,2162,5322,2892,2993, 890,2148,1924, 665,1827,3581,1032, + 968,3163, 339,1044,1896, 270, 583,1791,1720,4367,1194,3488,3669, 43,2523,1657, + 163,2167, 290,1209,1622,3378, 550, 634,2508,2510, 695,2634,2384,2512,1476,1414, + 220,1469,2341,2138,2852,3183,2900,4939,2865,3502,1211,3680, 854,3227,1299,2976, +3172, 186,2998,1459, 443,1067,3251,1495, 321,1932,3054, 909, 753,1410,1828, 436, +2441,1119,1587,3164,2186,1258, 227, 231,1425,1890,3200,3942, 247, 959, 725,5254, +2741, 577,2158,2079, 929, 120, 174, 838,2813, 591,1115, 417,2024, 40,3240,1536, +1037, 291,4151,2354, 632,1298,2406,2500,3535,1825,1846,3451, 205,1171, 345,4238, + 18,1163, 811, 685,2208,1217, 425,1312,1508,1175,4308,2552,1033, 587,1381,3059, +2984,3482, 340,1316,4023,3972, 792,3176, 519, 777,4690, 918, 933,4130,2981,3741, + 90,3360,2911,2200,5184,4550, 609,3079,2030, 272,3379,2736, 363,3881,1130,1447, + 286, 779, 357,1169,3350,3137,1630,1220,2687,2391, 747,1277,3688,2618,2682,2601, +1156,3196,5290,4034,3102,1689,3596,3128, 874, 219,2783, 798, 508,1843,2461, 269, +1658,1776,1392,1913,2983,3287,2866,2159,2372, 829,4076, 46,4253,2873,1889,1894, + 915,1834,1631,2181,2318, 298, 664,2818,3555,2735, 954,3228,3117, 527,3511,2173, + 681,2712,3033,2247,2346,3467,1652, 155,2164,3382, 113,1994, 450, 899, 494, 994, +1237,2958,1875,2336,1926,3727, 545,1577,1550, 633,3473, 204,1305,3072,2410,1956, +2471, 707,2134, 841,2195,2196,2663,3843,1026,4940, 990,3252,4997, 368,1092, 437, +3212,3258,1933,1829, 675,2977,2893, 412, 943,3723,4644,3294,3283,2230,2373,5154, +2389,2241,2661,2323,1404,2524, 593, 787, 677,3008,1275,2059, 438,2709,2609,2240, +2269,2246,1446, 36,1568,1373,3892,1574,2301,1456,3962, 693,2276,5216,2035,1143, +2720,1919,1797,1811,2763,4137,2597,1830,1699,1488,1198,2090, 424,1694, 312,3634, +3390,4179,3335,2252,1214, 561,1059,3243,2295,2561, 975,5155,2321,2751,3772, 472, +1537,3282,3398,1047,2077,2348,2878,1323,3340,3076, 690,2906, 51, 369, 170,3541, +1060,2187,2688,3670,2541,1083,1683, 928,3918, 459, 109,4427, 599,3744,4286, 143, +2101,2730,2490, 82,1588,3036,2121, 281,1860, 477,4035,1238,2812,3020,2716,3312, +1530,2188,2055,1317, 843, 636,1808,1173,3495, 649, 181,1002, 147,3641,1159,2414, +3750,2289,2795, 813,3123,2610,1136,4368, 5,3391,4541,2174, 420, 429,1728, 754, +1228,2115,2219, 347,2223,2733, 735,1518,3003,2355,3134,1764,3948,3329,1888,2424, +1001,1234,1972,3321,3363,1672,1021,1450,1584, 226, 765, 655,2526,3404,3244,2302, +3665, 731, 594,2184, 319,1576, 621, 658,2656,4299,2099,3864,1279,2071,2598,2739, + 795,3086,3699,3908,1707,2352,2402,1382,3136,2475,1465,4847,3496,3865,1085,3004, +2591,1084, 213,2287,1963,3565,2250, 822, 793,4574,3187,1772,1789,3050, 595,1484, +1959,2770,1080,2650, 456, 422,2996, 940,3322,4328,4345,3092,2742, 965,2784, 739, +4124, 952,1358,2498,2949,2565, 332,2698,2378, 660,2260,2473,4194,3856,2919, 535, +1260,2651,1208,1428,1300,1949,1303,2942, 433,2455,2450,1251,1946, 614,1269, 641, +1306,1810,2737,3078,2912, 564,2365,1419,1415,1497,4460,2367,2185,1379,3005,1307, +3218,2175,1897,3063, 682,1157,4040,4005,1712,1160,1941,1399, 394, 402,2952,1573, +1151,2986,2404, 862, 299,2033,1489,3006, 346, 171,2886,3401,1726,2932, 168,2533, + 47,2507,1030,3735,1145,3370,1395,1318,1579,3609,4560,2857,4116,1457,2529,1965, + 504,1036,2690,2988,2405, 745,5871, 849,2397,2056,3081, 863,2359,3857,2096, 99, +1397,1769,2300,4428,1643,3455,1978,1757,3718,1440, 35,4879,3742,1296,4228,2280, + 160,5063,1599,2013, 166, 520,3479,1646,3345,3012, 490,1937,1545,1264,2182,2505, +1096,1188,1369,1436,2421,1667,2792,2460,1270,2122, 727,3167,2143, 806,1706,1012, +1800,3037, 960,2218,1882, 805, 139,2456,1139,1521, 851,1052,3093,3089, 342,2039, + 744,5097,1468,1502,1585,2087, 223, 939, 326,2140,2577, 892,2481,1623,4077, 982, +3708, 135,2131, 87,2503,3114,2326,1106, 876,1616, 547,2997,2831,2093,3441,4530, +4314, 9,3256,4229,4148, 659,1462,1986,1710,2046,2913,2231,4090,4880,5255,3392, +3274,1368,3689,4645,1477, 705,3384,3635,1068,1529,2941,1458,3782,1509, 100,1656, +2548, 718,2339, 408,1590,2780,3548,1838,4117,3719,1345,3530, 717,3442,2778,3220, +2898,1892,4590,3614,3371,2043,1998,1224,3483, 891, 635, 584,2559,3355, 733,1766, +1729,1172,3789,1891,2307, 781,2982,2271,1957,1580,5773,2633,2005,4195,3097,1535, +3213,1189,1934,5693,3262, 586,3118,1324,1598, 517,1564,2217,1868,1893,4445,3728, +2703,3139,1526,1787,1992,3882,2875,1549,1199,1056,2224,1904,2711,5098,4287, 338, +1993,3129,3489,2689,1809,2815,1997, 957,1855,3898,2550,3275,3057,1105,1319, 627, +1505,1911,1883,3526, 698,3629,3456,1833,1431, 746, 77,1261,2017,2296,1977,1885, + 125,1334,1600, 525,1798,1109,2222,1470,1945, 559,2236,1186,3443,2476,1929,1411, +2411,3135,1777,3372,2621,1841,1613,3229, 668,1430,1839,2643,2916, 195,1989,2671, +2358,1387, 629,3205,2293,5256,4439, 123,1310, 888,1879,4300,3021,3605,1003,1162, +3192,2910,2010, 140,2395,2859, 55,1082,2012,2901, 662, 419,2081,1438, 680,2774, +4654,3912,1620,1731,1625,5035,4065,2328, 512,1344, 802,5443,2163,2311,2537, 524, +3399, 98,1155,2103,1918,2606,3925,2816,1393,2465,1504,3773,2177,3963,1478,4346, + 180,1113,4655,3461,2028,1698, 833,2696,1235,1322,1594,4408,3623,3013,3225,2040, +3022, 541,2881, 607,3632,2029,1665,1219, 639,1385,1686,1099,2803,3231,1938,3188, +2858, 427, 676,2772,1168,2025, 454,3253,2486,3556, 230,1950, 580, 791,1991,1280, +1086,1974,2034, 630, 257,3338,2788,4903,1017, 86,4790, 966,2789,1995,1696,1131, + 259,3095,4188,1308, 179,1463,5257, 289,4107,1248, 42,3413,1725,2288, 896,1947, + 774,4474,4254, 604,3430,4264, 392,2514,2588, 452, 237,1408,3018, 988,4531,1970, +3034,3310, 540,2370,1562,1288,2990, 502,4765,1147, 4,1853,2708, 207, 294,2814, +4078,2902,2509, 684, 34,3105,3532,2551, 644, 709,2801,2344, 573,1727,3573,3557, +2021,1081,3100,4315,2100,3681, 199,2263,1837,2385, 146,3484,1195,2776,3949, 997, +1939,3973,1008,1091,1202,1962,1847,1149,4209,5444,1076, 493, 117,5400,2521, 972, +1490,2934,1796,4542,2374,1512,2933,2657, 413,2888,1135,2762,2314,2156,1355,2369, + 766,2007,2527,2170,3124,2491,2593,2632,4757,2437, 234,3125,3591,1898,1750,1376, +1942,3468,3138, 570,2127,2145,3276,4131, 962, 132,1445,4196, 19, 941,3624,3480, +3366,1973,1374,4461,3431,2629, 283,2415,2275, 808,2887,3620,2112,2563,1353,3610, + 955,1089,3103,1053, 96, 88,4097, 823,3808,1583, 399, 292,4091,3313, 421,1128, + 642,4006, 903,2539,1877,2082, 596, 29,4066,1790, 722,2157, 130, 995,1569, 769, +1485, 464, 513,2213, 288,1923,1101,2453,4316, 133, 486,2445, 50, 625, 487,2207, + 57, 423, 481,2962, 159,3729,1558, 491, 303, 482, 501, 240,2837, 112,3648,2392, +1783, 362, 8,3433,3422, 610,2793,3277,1390,1284,1654, 21,3823, 734, 367, 623, + 193, 287, 374,1009,1483, 816, 476, 313,2255,2340,1262,2150,2899,1146,2581, 782, +2116,1659,2018,1880, 255,3586,3314,1110,2867,2137,2564, 986,2767,5185,2006, 650, + 158, 926, 762, 881,3157,2717,2362,3587, 306,3690,3245,1542,3077,2427,1691,2478, +2118,2985,3490,2438, 539,2305, 983, 129,1754, 355,4201,2386, 827,2923, 104,1773, +2838,2771, 411,2905,3919, 376, 767, 122,1114, 828,2422,1817,3506, 266,3460,1007, +1609,4998, 945,2612,4429,2274, 726,1247,1964,2914,2199,2070,4002,4108, 657,3323, +1422, 579, 455,2764,4737,1222,2895,1670, 824,1223,1487,2525, 558, 861,3080, 598, +2659,2515,1967, 752,2583,2376,2214,4180, 977, 704,2464,4999,2622,4109,1210,2961, + 819,1541, 142,2284, 44, 418, 457,1126,3730,4347,4626,1644,1876,3671,1864, 302, +1063,5694, 624, 723,1984,3745,1314,1676,2488,1610,1449,3558,3569,2166,2098, 409, +1011,2325,3704,2306, 818,1732,1383,1824,1844,3757, 999,2705,3497,1216,1423,2683, +2426,2954,2501,2726,2229,1475,2554,5064,1971,1794,1666,2014,1343, 783, 724, 191, +2434,1354,2220,5065,1763,2752,2472,4152, 131, 175,2885,3434, 92,1466,4920,2616, +3871,3872,3866, 128,1551,1632, 669,1854,3682,4691,4125,1230, 188,2973,3290,1302, +1213, 560,3266, 917, 763,3909,3249,1760, 868,1958, 764,1782,2097, 145,2277,3774, +4462, 64,1491,3062, 971,2132,3606,2442, 221,1226,1617, 218, 323,1185,3207,3147, + 571, 619,1473,1005,1744,2281, 449,1887,2396,3685, 275, 375,3816,1743,3844,3731, + 845,1983,2350,4210,1377, 773, 967,3499,3052,3743,2725,4007,1697,1022,3943,1464, +3264,2855,2722,1952,1029,2839,2467, 84,4383,2215, 820,1391,2015,2448,3672, 377, +1948,2168, 797,2545,3536,2578,2645, 94,2874,1678, 405,1259,3071, 771, 546,1315, + 470,1243,3083, 895,2468, 981, 969,2037, 846,4181, 653,1276,2928, 14,2594, 557, +3007,2474, 156, 902,1338,1740,2574, 537,2518, 973,2282,2216,2433,1928, 138,2903, +1293,2631,1612, 646,3457, 839,2935, 111, 496,2191,2847, 589,3186, 149,3994,2060, +4031,2641,4067,3145,1870, 37,3597,2136,1025,2051,3009,3383,3549,1121,1016,3261, +1301, 251,2446,2599,2153, 872,3246, 637, 334,3705, 831, 884, 921,3065,3140,4092, +2198,1944, 246,2964, 108,2045,1152,1921,2308,1031, 203,3173,4170,1907,3890, 810, +1401,2003,1690, 506, 647,1242,2828,1761,1649,3208,2249,1589,3709,2931,5156,1708, + 498, 666,2613, 834,3817,1231, 184,2851,1124, 883,3197,2261,3710,1765,1553,2658, +1178,2639,2351, 93,1193, 942,2538,2141,4402, 235,1821, 870,1591,2192,1709,1871, +3341,1618,4126,2595,2334, 603, 651, 69, 701, 268,2662,3411,2555,1380,1606, 503, + 448, 254,2371,2646, 574,1187,2309,1770, 322,2235,1292,1801, 305, 566,1133, 229, +2067,2057, 706, 167, 483,2002,2672,3295,1820,3561,3067, 316, 378,2746,3452,1112, + 136,1981, 507,1651,2917,1117, 285,4591, 182,2580,3522,1304, 335,3303,1835,2504, +1795,1792,2248, 674,1018,2106,2449,1857,2292,2845, 976,3047,1781,2600,2727,1389, +1281, 52,3152, 153, 265,3950, 672,3485,3951,4463, 430,1183, 365, 278,2169, 27, +1407,1336,2304, 209,1340,1730,2202,1852,2403,2883, 979,1737,1062, 631,2829,2542, +3876,2592, 825,2086,2226,3048,3625, 352,1417,3724, 542, 991, 431,1351,3938,1861, +2294, 826,1361,2927,3142,3503,1738, 463,2462,2723, 582,1916,1595,2808, 400,3845, +3891,2868,3621,2254, 58,2492,1123, 910,2160,2614,1372,1603,1196,1072,3385,1700, +3267,1980, 696, 480,2430, 920, 799,1570,2920,1951,2041,4047,2540,1321,4223,2469, +3562,2228,1271,2602, 401,2833,3351,2575,5157, 907,2312,1256, 410, 263,3507,1582, + 996, 678,1849,2316,1480, 908,3545,2237, 703,2322, 667,1826,2849,1531,2604,2999, +2407,3146,2151,2630,1786,3711, 469,3542, 497,3899,2409, 858, 837,4446,3393,1274, + 786, 620,1845,2001,3311, 484, 308,3367,1204,1815,3691,2332,1532,2557,1842,2020, +2724,1927,2333,4440, 567, 22,1673,2728,4475,1987,1858,1144,1597, 101,1832,3601, + 12, 974,3783,4391, 951,1412, 1,3720, 453,4608,4041, 528,1041,1027,3230,2628, +1129, 875,1051,3291,1203,2262,1069,2860,2799,2149,2615,3278, 144,1758,3040, 31, + 475,1680, 366,2685,3184, 311,1642,4008,2466,5036,1593,1493,2809, 216,1420,1668, + 233, 304,2128,3284, 232,1429,1768,1040,2008,3407,2740,2967,2543, 242,2133, 778, +1565,2022,2620, 505,2189,2756,1098,2273, 372,1614, 708, 553,2846,2094,2278, 169, +3626,2835,4161, 228,2674,3165, 809,1454,1309, 466,1705,1095, 900,3423, 880,2667, +3751,5258,2317,3109,2571,4317,2766,1503,1342, 866,4447,1118, 63,2076, 314,1881, +1348,1061, 172, 978,3515,1747, 532, 511,3970, 6, 601, 905,2699,3300,1751, 276, +1467,3725,2668, 65,4239,2544,2779,2556,1604, 578,2451,1802, 992,2331,2624,1320, +3446, 713,1513,1013, 103,2786,2447,1661, 886,1702, 916, 654,3574,2031,1556, 751, +2178,2821,2179,1498,1538,2176, 271, 914,2251,2080,1325, 638,1953,2937,3877,2432, +2754, 95,3265,1716, 260,1227,4083, 775, 106,1357,3254, 426,1607, 555,2480, 772, +1985, 244,2546, 474, 495,1046,2611,1851,2061, 71,2089,1675,2590, 742,3758,2843, +3222,1433, 267,2180,2576,2826,2233,2092,3913,2435, 956,1745,3075, 856,2113,1116, + 451, 3,1988,2896,1398, 993,2463,1878,2049,1341,2718,2721,2870,2108, 712,2904, +4363,2753,2324, 277,2872,2349,2649, 384, 987, 435, 691,3000, 922, 164,3939, 652, +1500,1184,4153,2482,3373,2165,4848,2335,3775,3508,3154,2806,2830,1554,2102,1664, +2530,1434,2408, 893,1547,2623,3447,2832,2242,2532,3169,2856,3223,2078, 49,3770, +3469, 462, 318, 656,2259,3250,3069, 679,1629,2758, 344,1138,1104,3120,1836,1283, +3115,2154,1437,4448, 934, 759,1999, 794,2862,1038, 533,2560,1722,2342, 855,2626, +1197,1663,4476,3127, 85,4240,2528, 25,1111,1181,3673, 407,3470,4561,2679,2713, + 768,1925,2841,3986,1544,1165, 932, 373,1240,2146,1930,2673, 721,4766, 354,4333, + 391,2963, 187, 61,3364,1442,1102, 330,1940,1767, 341,3809,4118, 393,2496,2062, +2211, 105, 331, 300, 439, 913,1332, 626, 379,3304,1557, 328, 689,3952, 309,1555, + 931, 317,2517,3027, 325, 569, 686,2107,3084, 60,1042,1333,2794, 264,3177,4014, +1628, 258,3712, 7,4464,1176,1043,1778, 683, 114,1975, 78,1492, 383,1886, 510, + 386, 645,5291,2891,2069,3305,4138,3867,2939,2603,2493,1935,1066,1848,3588,1015, +1282,1289,4609, 697,1453,3044,2666,3611,1856,2412, 54, 719,1330, 568,3778,2459, +1748, 788, 492, 551,1191,1000, 488,3394,3763, 282,1799, 348,2016,1523,3155,2390, +1049, 382,2019,1788,1170, 729,2968,3523, 897,3926,2785,2938,3292, 350,2319,3238, +1718,1717,2655,3453,3143,4465, 161,2889,2980,2009,1421, 56,1908,1640,2387,2232, +1917,1874,2477,4921, 148, 83,3438, 592,4245,2882,1822,1055, 741, 115,1496,1624, + 381,1638,4592,1020, 516,3214, 458, 947,4575,1432, 211,1514,2926,1865,2142, 189, + 852,1221,1400,1486, 882,2299,4036, 351, 28,1122, 700,6479,6480,6481,6482,6483, #last 512 +) + diff --git a/venv/lib/python3.8/site-packages/chardet/gb2312prober.py b/venv/lib/python3.8/site-packages/chardet/gb2312prober.py new file mode 100644 index 0000000..8446d2d --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/gb2312prober.py @@ -0,0 +1,46 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .mbcharsetprober import MultiByteCharSetProber +from .codingstatemachine import CodingStateMachine +from .chardistribution import GB2312DistributionAnalysis +from .mbcssm import GB2312_SM_MODEL + +class GB2312Prober(MultiByteCharSetProber): + def __init__(self): + super(GB2312Prober, self).__init__() + self.coding_sm = CodingStateMachine(GB2312_SM_MODEL) + self.distribution_analyzer = GB2312DistributionAnalysis() + self.reset() + + @property + def charset_name(self): + return "GB2312" + + @property + def language(self): + return "Chinese" diff --git a/venv/lib/python3.8/site-packages/chardet/hebrewprober.py b/venv/lib/python3.8/site-packages/chardet/hebrewprober.py new file mode 100644 index 0000000..b0e1bf4 --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/hebrewprober.py @@ -0,0 +1,292 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Shy Shalom +# Portions created by the Initial Developer are Copyright (C) 2005 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .charsetprober import CharSetProber +from .enums import ProbingState + +# This prober doesn't actually recognize a language or a charset. +# It is a helper prober for the use of the Hebrew model probers + +### General ideas of the Hebrew charset recognition ### +# +# Four main charsets exist in Hebrew: +# "ISO-8859-8" - Visual Hebrew +# "windows-1255" - Logical Hebrew +# "ISO-8859-8-I" - Logical Hebrew +# "x-mac-hebrew" - ?? Logical Hebrew ?? +# +# Both "ISO" charsets use a completely identical set of code points, whereas +# "windows-1255" and "x-mac-hebrew" are two different proper supersets of +# these code points. windows-1255 defines additional characters in the range +# 0x80-0x9F as some misc punctuation marks as well as some Hebrew-specific +# diacritics and additional 'Yiddish' ligature letters in the range 0xc0-0xd6. +# x-mac-hebrew defines similar additional code points but with a different +# mapping. +# +# As far as an average Hebrew text with no diacritics is concerned, all four +# charsets are identical with respect to code points. Meaning that for the +# main Hebrew alphabet, all four map the same values to all 27 Hebrew letters +# (including final letters). +# +# The dominant difference between these charsets is their directionality. +# "Visual" directionality means that the text is ordered as if the renderer is +# not aware of a BIDI rendering algorithm. The renderer sees the text and +# draws it from left to right. The text itself when ordered naturally is read +# backwards. A buffer of Visual Hebrew generally looks like so: +# "[last word of first line spelled backwards] [whole line ordered backwards +# and spelled backwards] [first word of first line spelled backwards] +# [end of line] [last word of second line] ... etc' " +# adding punctuation marks, numbers and English text to visual text is +# naturally also "visual" and from left to right. +# +# "Logical" directionality means the text is ordered "naturally" according to +# the order it is read. It is the responsibility of the renderer to display +# the text from right to left. A BIDI algorithm is used to place general +# punctuation marks, numbers and English text in the text. +# +# Texts in x-mac-hebrew are almost impossible to find on the Internet. From +# what little evidence I could find, it seems that its general directionality +# is Logical. +# +# To sum up all of the above, the Hebrew probing mechanism knows about two +# charsets: +# Visual Hebrew - "ISO-8859-8" - backwards text - Words and sentences are +# backwards while line order is natural. For charset recognition purposes +# the line order is unimportant (In fact, for this implementation, even +# word order is unimportant). +# Logical Hebrew - "windows-1255" - normal, naturally ordered text. +# +# "ISO-8859-8-I" is a subset of windows-1255 and doesn't need to be +# specifically identified. +# "x-mac-hebrew" is also identified as windows-1255. A text in x-mac-hebrew +# that contain special punctuation marks or diacritics is displayed with +# some unconverted characters showing as question marks. This problem might +# be corrected using another model prober for x-mac-hebrew. Due to the fact +# that x-mac-hebrew texts are so rare, writing another model prober isn't +# worth the effort and performance hit. +# +#### The Prober #### +# +# The prober is divided between two SBCharSetProbers and a HebrewProber, +# all of which are managed, created, fed data, inquired and deleted by the +# SBCSGroupProber. The two SBCharSetProbers identify that the text is in +# fact some kind of Hebrew, Logical or Visual. The final decision about which +# one is it is made by the HebrewProber by combining final-letter scores +# with the scores of the two SBCharSetProbers to produce a final answer. +# +# The SBCSGroupProber is responsible for stripping the original text of HTML +# tags, English characters, numbers, low-ASCII punctuation characters, spaces +# and new lines. It reduces any sequence of such characters to a single space. +# The buffer fed to each prober in the SBCS group prober is pure text in +# high-ASCII. +# The two SBCharSetProbers (model probers) share the same language model: +# Win1255Model. +# The first SBCharSetProber uses the model normally as any other +# SBCharSetProber does, to recognize windows-1255, upon which this model was +# built. The second SBCharSetProber is told to make the pair-of-letter +# lookup in the language model backwards. This in practice exactly simulates +# a visual Hebrew model using the windows-1255 logical Hebrew model. +# +# The HebrewProber is not using any language model. All it does is look for +# final-letter evidence suggesting the text is either logical Hebrew or visual +# Hebrew. Disjointed from the model probers, the results of the HebrewProber +# alone are meaningless. HebrewProber always returns 0.00 as confidence +# since it never identifies a charset by itself. Instead, the pointer to the +# HebrewProber is passed to the model probers as a helper "Name Prober". +# When the Group prober receives a positive identification from any prober, +# it asks for the name of the charset identified. If the prober queried is a +# Hebrew model prober, the model prober forwards the call to the +# HebrewProber to make the final decision. In the HebrewProber, the +# decision is made according to the final-letters scores maintained and Both +# model probers scores. The answer is returned in the form of the name of the +# charset identified, either "windows-1255" or "ISO-8859-8". + +class HebrewProber(CharSetProber): + # windows-1255 / ISO-8859-8 code points of interest + FINAL_KAF = 0xea + NORMAL_KAF = 0xeb + FINAL_MEM = 0xed + NORMAL_MEM = 0xee + FINAL_NUN = 0xef + NORMAL_NUN = 0xf0 + FINAL_PE = 0xf3 + NORMAL_PE = 0xf4 + FINAL_TSADI = 0xf5 + NORMAL_TSADI = 0xf6 + + # Minimum Visual vs Logical final letter score difference. + # If the difference is below this, don't rely solely on the final letter score + # distance. + MIN_FINAL_CHAR_DISTANCE = 5 + + # Minimum Visual vs Logical model score difference. + # If the difference is below this, don't rely at all on the model score + # distance. + MIN_MODEL_DISTANCE = 0.01 + + VISUAL_HEBREW_NAME = "ISO-8859-8" + LOGICAL_HEBREW_NAME = "windows-1255" + + def __init__(self): + super(HebrewProber, self).__init__() + self._final_char_logical_score = None + self._final_char_visual_score = None + self._prev = None + self._before_prev = None + self._logical_prober = None + self._visual_prober = None + self.reset() + + def reset(self): + self._final_char_logical_score = 0 + self._final_char_visual_score = 0 + # The two last characters seen in the previous buffer, + # mPrev and mBeforePrev are initialized to space in order to simulate + # a word delimiter at the beginning of the data + self._prev = ' ' + self._before_prev = ' ' + # These probers are owned by the group prober. + + def set_model_probers(self, logicalProber, visualProber): + self._logical_prober = logicalProber + self._visual_prober = visualProber + + def is_final(self, c): + return c in [self.FINAL_KAF, self.FINAL_MEM, self.FINAL_NUN, + self.FINAL_PE, self.FINAL_TSADI] + + def is_non_final(self, c): + # The normal Tsadi is not a good Non-Final letter due to words like + # 'lechotet' (to chat) containing an apostrophe after the tsadi. This + # apostrophe is converted to a space in FilterWithoutEnglishLetters + # causing the Non-Final tsadi to appear at an end of a word even + # though this is not the case in the original text. + # The letters Pe and Kaf rarely display a related behavior of not being + # a good Non-Final letter. Words like 'Pop', 'Winamp' and 'Mubarak' + # for example legally end with a Non-Final Pe or Kaf. However, the + # benefit of these letters as Non-Final letters outweighs the damage + # since these words are quite rare. + return c in [self.NORMAL_KAF, self.NORMAL_MEM, + self.NORMAL_NUN, self.NORMAL_PE] + + def feed(self, byte_str): + # Final letter analysis for logical-visual decision. + # Look for evidence that the received buffer is either logical Hebrew + # or visual Hebrew. + # The following cases are checked: + # 1) A word longer than 1 letter, ending with a final letter. This is + # an indication that the text is laid out "naturally" since the + # final letter really appears at the end. +1 for logical score. + # 2) A word longer than 1 letter, ending with a Non-Final letter. In + # normal Hebrew, words ending with Kaf, Mem, Nun, Pe or Tsadi, + # should not end with the Non-Final form of that letter. Exceptions + # to this rule are mentioned above in isNonFinal(). This is an + # indication that the text is laid out backwards. +1 for visual + # score + # 3) A word longer than 1 letter, starting with a final letter. Final + # letters should not appear at the beginning of a word. This is an + # indication that the text is laid out backwards. +1 for visual + # score. + # + # The visual score and logical score are accumulated throughout the + # text and are finally checked against each other in GetCharSetName(). + # No checking for final letters in the middle of words is done since + # that case is not an indication for either Logical or Visual text. + # + # We automatically filter out all 7-bit characters (replace them with + # spaces) so the word boundary detection works properly. [MAP] + + if self.state == ProbingState.NOT_ME: + # Both model probers say it's not them. No reason to continue. + return ProbingState.NOT_ME + + byte_str = self.filter_high_byte_only(byte_str) + + for cur in byte_str: + if cur == ' ': + # We stand on a space - a word just ended + if self._before_prev != ' ': + # next-to-last char was not a space so self._prev is not a + # 1 letter word + if self.is_final(self._prev): + # case (1) [-2:not space][-1:final letter][cur:space] + self._final_char_logical_score += 1 + elif self.is_non_final(self._prev): + # case (2) [-2:not space][-1:Non-Final letter][ + # cur:space] + self._final_char_visual_score += 1 + else: + # Not standing on a space + if ((self._before_prev == ' ') and + (self.is_final(self._prev)) and (cur != ' ')): + # case (3) [-2:space][-1:final letter][cur:not space] + self._final_char_visual_score += 1 + self._before_prev = self._prev + self._prev = cur + + # Forever detecting, till the end or until both model probers return + # ProbingState.NOT_ME (handled above) + return ProbingState.DETECTING + + @property + def charset_name(self): + # Make the decision: is it Logical or Visual? + # If the final letter score distance is dominant enough, rely on it. + finalsub = self._final_char_logical_score - self._final_char_visual_score + if finalsub >= self.MIN_FINAL_CHAR_DISTANCE: + return self.LOGICAL_HEBREW_NAME + if finalsub <= -self.MIN_FINAL_CHAR_DISTANCE: + return self.VISUAL_HEBREW_NAME + + # It's not dominant enough, try to rely on the model scores instead. + modelsub = (self._logical_prober.get_confidence() + - self._visual_prober.get_confidence()) + if modelsub > self.MIN_MODEL_DISTANCE: + return self.LOGICAL_HEBREW_NAME + if modelsub < -self.MIN_MODEL_DISTANCE: + return self.VISUAL_HEBREW_NAME + + # Still no good, back to final letter distance, maybe it'll save the + # day. + if finalsub < 0.0: + return self.VISUAL_HEBREW_NAME + + # (finalsub > 0 - Logical) or (don't know what to do) default to + # Logical. + return self.LOGICAL_HEBREW_NAME + + @property + def language(self): + return 'Hebrew' + + @property + def state(self): + # Remain active as long as any of the model probers are active. + if (self._logical_prober.state == ProbingState.NOT_ME) and \ + (self._visual_prober.state == ProbingState.NOT_ME): + return ProbingState.NOT_ME + return ProbingState.DETECTING diff --git a/venv/lib/python3.8/site-packages/chardet/jisfreq.py b/venv/lib/python3.8/site-packages/chardet/jisfreq.py new file mode 100644 index 0000000..83fc082 --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/jisfreq.py @@ -0,0 +1,325 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +# Sampling from about 20M text materials include literature and computer technology +# +# Japanese frequency table, applied to both S-JIS and EUC-JP +# They are sorted in order. + +# 128 --> 0.77094 +# 256 --> 0.85710 +# 512 --> 0.92635 +# 1024 --> 0.97130 +# 2048 --> 0.99431 +# +# Ideal Distribution Ratio = 0.92635 / (1-0.92635) = 12.58 +# Random Distribution Ration = 512 / (2965+62+83+86-512) = 0.191 +# +# Typical Distribution Ratio, 25% of IDR + +JIS_TYPICAL_DISTRIBUTION_RATIO = 3.0 + +# Char to FreqOrder table , +JIS_TABLE_SIZE = 4368 + +JIS_CHAR_TO_FREQ_ORDER = ( + 40, 1, 6, 182, 152, 180, 295,2127, 285, 381,3295,4304,3068,4606,3165,3510, # 16 +3511,1822,2785,4607,1193,2226,5070,4608, 171,2996,1247, 18, 179,5071, 856,1661, # 32 +1262,5072, 619, 127,3431,3512,3230,1899,1700, 232, 228,1294,1298, 284, 283,2041, # 48 +2042,1061,1062, 48, 49, 44, 45, 433, 434,1040,1041, 996, 787,2997,1255,4305, # 64 +2108,4609,1684,1648,5073,5074,5075,5076,5077,5078,3687,5079,4610,5080,3927,3928, # 80 +5081,3296,3432, 290,2285,1471,2187,5082,2580,2825,1303,2140,1739,1445,2691,3375, # 96 +1691,3297,4306,4307,4611, 452,3376,1182,2713,3688,3069,4308,5083,5084,5085,5086, # 112 +5087,5088,5089,5090,5091,5092,5093,5094,5095,5096,5097,5098,5099,5100,5101,5102, # 128 +5103,5104,5105,5106,5107,5108,5109,5110,5111,5112,4097,5113,5114,5115,5116,5117, # 144 +5118,5119,5120,5121,5122,5123,5124,5125,5126,5127,5128,5129,5130,5131,5132,5133, # 160 +5134,5135,5136,5137,5138,5139,5140,5141,5142,5143,5144,5145,5146,5147,5148,5149, # 176 +5150,5151,5152,4612,5153,5154,5155,5156,5157,5158,5159,5160,5161,5162,5163,5164, # 192 +5165,5166,5167,5168,5169,5170,5171,5172,5173,5174,5175,1472, 598, 618, 820,1205, # 208 +1309,1412,1858,1307,1692,5176,5177,5178,5179,5180,5181,5182,1142,1452,1234,1172, # 224 +1875,2043,2149,1793,1382,2973, 925,2404,1067,1241, 960,1377,2935,1491, 919,1217, # 240 +1865,2030,1406,1499,2749,4098,5183,5184,5185,5186,5187,5188,2561,4099,3117,1804, # 256 +2049,3689,4309,3513,1663,5189,3166,3118,3298,1587,1561,3433,5190,3119,1625,2998, # 272 +3299,4613,1766,3690,2786,4614,5191,5192,5193,5194,2161, 26,3377, 2,3929, 20, # 288 +3691, 47,4100, 50, 17, 16, 35, 268, 27, 243, 42, 155, 24, 154, 29, 184, # 304 + 4, 91, 14, 92, 53, 396, 33, 289, 9, 37, 64, 620, 21, 39, 321, 5, # 320 + 12, 11, 52, 13, 3, 208, 138, 0, 7, 60, 526, 141, 151,1069, 181, 275, # 336 +1591, 83, 132,1475, 126, 331, 829, 15, 69, 160, 59, 22, 157, 55,1079, 312, # 352 + 109, 38, 23, 25, 10, 19, 79,5195, 61, 382,1124, 8, 30,5196,5197,5198, # 368 +5199,5200,5201,5202,5203,5204,5205,5206, 89, 62, 74, 34,2416, 112, 139, 196, # 384 + 271, 149, 84, 607, 131, 765, 46, 88, 153, 683, 76, 874, 101, 258, 57, 80, # 400 + 32, 364, 121,1508, 169,1547, 68, 235, 145,2999, 41, 360,3027, 70, 63, 31, # 416 + 43, 259, 262,1383, 99, 533, 194, 66, 93, 846, 217, 192, 56, 106, 58, 565, # 432 + 280, 272, 311, 256, 146, 82, 308, 71, 100, 128, 214, 655, 110, 261, 104,1140, # 448 + 54, 51, 36, 87, 67,3070, 185,2618,2936,2020, 28,1066,2390,2059,5207,5208, # 464 +5209,5210,5211,5212,5213,5214,5215,5216,4615,5217,5218,5219,5220,5221,5222,5223, # 480 +5224,5225,5226,5227,5228,5229,5230,5231,5232,5233,5234,5235,5236,3514,5237,5238, # 496 +5239,5240,5241,5242,5243,5244,2297,2031,4616,4310,3692,5245,3071,5246,3598,5247, # 512 +4617,3231,3515,5248,4101,4311,4618,3808,4312,4102,5249,4103,4104,3599,5250,5251, # 528 +5252,5253,5254,5255,5256,5257,5258,5259,5260,5261,5262,5263,5264,5265,5266,5267, # 544 +5268,5269,5270,5271,5272,5273,5274,5275,5276,5277,5278,5279,5280,5281,5282,5283, # 560 +5284,5285,5286,5287,5288,5289,5290,5291,5292,5293,5294,5295,5296,5297,5298,5299, # 576 +5300,5301,5302,5303,5304,5305,5306,5307,5308,5309,5310,5311,5312,5313,5314,5315, # 592 +5316,5317,5318,5319,5320,5321,5322,5323,5324,5325,5326,5327,5328,5329,5330,5331, # 608 +5332,5333,5334,5335,5336,5337,5338,5339,5340,5341,5342,5343,5344,5345,5346,5347, # 624 +5348,5349,5350,5351,5352,5353,5354,5355,5356,5357,5358,5359,5360,5361,5362,5363, # 640 +5364,5365,5366,5367,5368,5369,5370,5371,5372,5373,5374,5375,5376,5377,5378,5379, # 656 +5380,5381, 363, 642,2787,2878,2788,2789,2316,3232,2317,3434,2011, 165,1942,3930, # 672 +3931,3932,3933,5382,4619,5383,4620,5384,5385,5386,5387,5388,5389,5390,5391,5392, # 688 +5393,5394,5395,5396,5397,5398,5399,5400,5401,5402,5403,5404,5405,5406,5407,5408, # 704 +5409,5410,5411,5412,5413,5414,5415,5416,5417,5418,5419,5420,5421,5422,5423,5424, # 720 +5425,5426,5427,5428,5429,5430,5431,5432,5433,5434,5435,5436,5437,5438,5439,5440, # 736 +5441,5442,5443,5444,5445,5446,5447,5448,5449,5450,5451,5452,5453,5454,5455,5456, # 752 +5457,5458,5459,5460,5461,5462,5463,5464,5465,5466,5467,5468,5469,5470,5471,5472, # 768 +5473,5474,5475,5476,5477,5478,5479,5480,5481,5482,5483,5484,5485,5486,5487,5488, # 784 +5489,5490,5491,5492,5493,5494,5495,5496,5497,5498,5499,5500,5501,5502,5503,5504, # 800 +5505,5506,5507,5508,5509,5510,5511,5512,5513,5514,5515,5516,5517,5518,5519,5520, # 816 +5521,5522,5523,5524,5525,5526,5527,5528,5529,5530,5531,5532,5533,5534,5535,5536, # 832 +5537,5538,5539,5540,5541,5542,5543,5544,5545,5546,5547,5548,5549,5550,5551,5552, # 848 +5553,5554,5555,5556,5557,5558,5559,5560,5561,5562,5563,5564,5565,5566,5567,5568, # 864 +5569,5570,5571,5572,5573,5574,5575,5576,5577,5578,5579,5580,5581,5582,5583,5584, # 880 +5585,5586,5587,5588,5589,5590,5591,5592,5593,5594,5595,5596,5597,5598,5599,5600, # 896 +5601,5602,5603,5604,5605,5606,5607,5608,5609,5610,5611,5612,5613,5614,5615,5616, # 912 +5617,5618,5619,5620,5621,5622,5623,5624,5625,5626,5627,5628,5629,5630,5631,5632, # 928 +5633,5634,5635,5636,5637,5638,5639,5640,5641,5642,5643,5644,5645,5646,5647,5648, # 944 +5649,5650,5651,5652,5653,5654,5655,5656,5657,5658,5659,5660,5661,5662,5663,5664, # 960 +5665,5666,5667,5668,5669,5670,5671,5672,5673,5674,5675,5676,5677,5678,5679,5680, # 976 +5681,5682,5683,5684,5685,5686,5687,5688,5689,5690,5691,5692,5693,5694,5695,5696, # 992 +5697,5698,5699,5700,5701,5702,5703,5704,5705,5706,5707,5708,5709,5710,5711,5712, # 1008 +5713,5714,5715,5716,5717,5718,5719,5720,5721,5722,5723,5724,5725,5726,5727,5728, # 1024 +5729,5730,5731,5732,5733,5734,5735,5736,5737,5738,5739,5740,5741,5742,5743,5744, # 1040 +5745,5746,5747,5748,5749,5750,5751,5752,5753,5754,5755,5756,5757,5758,5759,5760, # 1056 +5761,5762,5763,5764,5765,5766,5767,5768,5769,5770,5771,5772,5773,5774,5775,5776, # 1072 +5777,5778,5779,5780,5781,5782,5783,5784,5785,5786,5787,5788,5789,5790,5791,5792, # 1088 +5793,5794,5795,5796,5797,5798,5799,5800,5801,5802,5803,5804,5805,5806,5807,5808, # 1104 +5809,5810,5811,5812,5813,5814,5815,5816,5817,5818,5819,5820,5821,5822,5823,5824, # 1120 +5825,5826,5827,5828,5829,5830,5831,5832,5833,5834,5835,5836,5837,5838,5839,5840, # 1136 +5841,5842,5843,5844,5845,5846,5847,5848,5849,5850,5851,5852,5853,5854,5855,5856, # 1152 +5857,5858,5859,5860,5861,5862,5863,5864,5865,5866,5867,5868,5869,5870,5871,5872, # 1168 +5873,5874,5875,5876,5877,5878,5879,5880,5881,5882,5883,5884,5885,5886,5887,5888, # 1184 +5889,5890,5891,5892,5893,5894,5895,5896,5897,5898,5899,5900,5901,5902,5903,5904, # 1200 +5905,5906,5907,5908,5909,5910,5911,5912,5913,5914,5915,5916,5917,5918,5919,5920, # 1216 +5921,5922,5923,5924,5925,5926,5927,5928,5929,5930,5931,5932,5933,5934,5935,5936, # 1232 +5937,5938,5939,5940,5941,5942,5943,5944,5945,5946,5947,5948,5949,5950,5951,5952, # 1248 +5953,5954,5955,5956,5957,5958,5959,5960,5961,5962,5963,5964,5965,5966,5967,5968, # 1264 +5969,5970,5971,5972,5973,5974,5975,5976,5977,5978,5979,5980,5981,5982,5983,5984, # 1280 +5985,5986,5987,5988,5989,5990,5991,5992,5993,5994,5995,5996,5997,5998,5999,6000, # 1296 +6001,6002,6003,6004,6005,6006,6007,6008,6009,6010,6011,6012,6013,6014,6015,6016, # 1312 +6017,6018,6019,6020,6021,6022,6023,6024,6025,6026,6027,6028,6029,6030,6031,6032, # 1328 +6033,6034,6035,6036,6037,6038,6039,6040,6041,6042,6043,6044,6045,6046,6047,6048, # 1344 +6049,6050,6051,6052,6053,6054,6055,6056,6057,6058,6059,6060,6061,6062,6063,6064, # 1360 +6065,6066,6067,6068,6069,6070,6071,6072,6073,6074,6075,6076,6077,6078,6079,6080, # 1376 +6081,6082,6083,6084,6085,6086,6087,6088,6089,6090,6091,6092,6093,6094,6095,6096, # 1392 +6097,6098,6099,6100,6101,6102,6103,6104,6105,6106,6107,6108,6109,6110,6111,6112, # 1408 +6113,6114,2044,2060,4621, 997,1235, 473,1186,4622, 920,3378,6115,6116, 379,1108, # 1424 +4313,2657,2735,3934,6117,3809, 636,3233, 573,1026,3693,3435,2974,3300,2298,4105, # 1440 + 854,2937,2463, 393,2581,2417, 539, 752,1280,2750,2480, 140,1161, 440, 708,1569, # 1456 + 665,2497,1746,1291,1523,3000, 164,1603, 847,1331, 537,1997, 486, 508,1693,2418, # 1472 +1970,2227, 878,1220, 299,1030, 969, 652,2751, 624,1137,3301,2619, 65,3302,2045, # 1488 +1761,1859,3120,1930,3694,3516, 663,1767, 852, 835,3695, 269, 767,2826,2339,1305, # 1504 + 896,1150, 770,1616,6118, 506,1502,2075,1012,2519, 775,2520,2975,2340,2938,4314, # 1520 +3028,2086,1224,1943,2286,6119,3072,4315,2240,1273,1987,3935,1557, 175, 597, 985, # 1536 +3517,2419,2521,1416,3029, 585, 938,1931,1007,1052,1932,1685,6120,3379,4316,4623, # 1552 + 804, 599,3121,1333,2128,2539,1159,1554,2032,3810, 687,2033,2904, 952, 675,1467, # 1568 +3436,6121,2241,1096,1786,2440,1543,1924, 980,1813,2228, 781,2692,1879, 728,1918, # 1584 +3696,4624, 548,1950,4625,1809,1088,1356,3303,2522,1944, 502, 972, 373, 513,2827, # 1600 + 586,2377,2391,1003,1976,1631,6122,2464,1084, 648,1776,4626,2141, 324, 962,2012, # 1616 +2177,2076,1384, 742,2178,1448,1173,1810, 222, 102, 301, 445, 125,2420, 662,2498, # 1632 + 277, 200,1476,1165,1068, 224,2562,1378,1446, 450,1880, 659, 791, 582,4627,2939, # 1648 +3936,1516,1274, 555,2099,3697,1020,1389,1526,3380,1762,1723,1787,2229, 412,2114, # 1664 +1900,2392,3518, 512,2597, 427,1925,2341,3122,1653,1686,2465,2499, 697, 330, 273, # 1680 + 380,2162, 951, 832, 780, 991,1301,3073, 965,2270,3519, 668,2523,2636,1286, 535, # 1696 +1407, 518, 671, 957,2658,2378, 267, 611,2197,3030,6123, 248,2299, 967,1799,2356, # 1712 + 850,1418,3437,1876,1256,1480,2828,1718,6124,6125,1755,1664,2405,6126,4628,2879, # 1728 +2829, 499,2179, 676,4629, 557,2329,2214,2090, 325,3234, 464, 811,3001, 992,2342, # 1744 +2481,1232,1469, 303,2242, 466,1070,2163, 603,1777,2091,4630,2752,4631,2714, 322, # 1760 +2659,1964,1768, 481,2188,1463,2330,2857,3600,2092,3031,2421,4632,2318,2070,1849, # 1776 +2598,4633,1302,2254,1668,1701,2422,3811,2905,3032,3123,2046,4106,1763,1694,4634, # 1792 +1604, 943,1724,1454, 917, 868,2215,1169,2940, 552,1145,1800,1228,1823,1955, 316, # 1808 +1080,2510, 361,1807,2830,4107,2660,3381,1346,1423,1134,4108,6127, 541,1263,1229, # 1824 +1148,2540, 545, 465,1833,2880,3438,1901,3074,2482, 816,3937, 713,1788,2500, 122, # 1840 +1575, 195,1451,2501,1111,6128, 859, 374,1225,2243,2483,4317, 390,1033,3439,3075, # 1856 +2524,1687, 266, 793,1440,2599, 946, 779, 802, 507, 897,1081, 528,2189,1292, 711, # 1872 +1866,1725,1167,1640, 753, 398,2661,1053, 246, 348,4318, 137,1024,3440,1600,2077, # 1888 +2129, 825,4319, 698, 238, 521, 187,2300,1157,2423,1641,1605,1464,1610,1097,2541, # 1904 +1260,1436, 759,2255,1814,2150, 705,3235, 409,2563,3304, 561,3033,2005,2564, 726, # 1920 +1956,2343,3698,4109, 949,3812,3813,3520,1669, 653,1379,2525, 881,2198, 632,2256, # 1936 +1027, 778,1074, 733,1957, 514,1481,2466, 554,2180, 702,3938,1606,1017,1398,6129, # 1952 +1380,3521, 921, 993,1313, 594, 449,1489,1617,1166, 768,1426,1360, 495,1794,3601, # 1968 +1177,3602,1170,4320,2344, 476, 425,3167,4635,3168,1424, 401,2662,1171,3382,1998, # 1984 +1089,4110, 477,3169, 474,6130,1909, 596,2831,1842, 494, 693,1051,1028,1207,3076, # 2000 + 606,2115, 727,2790,1473,1115, 743,3522, 630, 805,1532,4321,2021, 366,1057, 838, # 2016 + 684,1114,2142,4322,2050,1492,1892,1808,2271,3814,2424,1971,1447,1373,3305,1090, # 2032 +1536,3939,3523,3306,1455,2199, 336, 369,2331,1035, 584,2393, 902, 718,2600,6131, # 2048 +2753, 463,2151,1149,1611,2467, 715,1308,3124,1268, 343,1413,3236,1517,1347,2663, # 2064 +2093,3940,2022,1131,1553,2100,2941,1427,3441,2942,1323,2484,6132,1980, 872,2368, # 2080 +2441,2943, 320,2369,2116,1082, 679,1933,3941,2791,3815, 625,1143,2023, 422,2200, # 2096 +3816,6133, 730,1695, 356,2257,1626,2301,2858,2637,1627,1778, 937, 883,2906,2693, # 2112 +3002,1769,1086, 400,1063,1325,3307,2792,4111,3077, 456,2345,1046, 747,6134,1524, # 2128 + 884,1094,3383,1474,2164,1059, 974,1688,2181,2258,1047, 345,1665,1187, 358, 875, # 2144 +3170, 305, 660,3524,2190,1334,1135,3171,1540,1649,2542,1527, 927, 968,2793, 885, # 2160 +1972,1850, 482, 500,2638,1218,1109,1085,2543,1654,2034, 876, 78,2287,1482,1277, # 2176 + 861,1675,1083,1779, 724,2754, 454, 397,1132,1612,2332, 893, 672,1237, 257,2259, # 2192 +2370, 135,3384, 337,2244, 547, 352, 340, 709,2485,1400, 788,1138,2511, 540, 772, # 2208 +1682,2260,2272,2544,2013,1843,1902,4636,1999,1562,2288,4637,2201,1403,1533, 407, # 2224 + 576,3308,1254,2071, 978,3385, 170, 136,1201,3125,2664,3172,2394, 213, 912, 873, # 2240 +3603,1713,2202, 699,3604,3699, 813,3442, 493, 531,1054, 468,2907,1483, 304, 281, # 2256 +4112,1726,1252,2094, 339,2319,2130,2639, 756,1563,2944, 748, 571,2976,1588,2425, # 2272 +2715,1851,1460,2426,1528,1392,1973,3237, 288,3309, 685,3386, 296, 892,2716,2216, # 2288 +1570,2245, 722,1747,2217, 905,3238,1103,6135,1893,1441,1965, 251,1805,2371,3700, # 2304 +2601,1919,1078, 75,2182,1509,1592,1270,2640,4638,2152,6136,3310,3817, 524, 706, # 2320 +1075, 292,3818,1756,2602, 317, 98,3173,3605,3525,1844,2218,3819,2502, 814, 567, # 2336 + 385,2908,1534,6137, 534,1642,3239, 797,6138,1670,1529, 953,4323, 188,1071, 538, # 2352 + 178, 729,3240,2109,1226,1374,2000,2357,2977, 731,2468,1116,2014,2051,6139,1261, # 2368 +1593, 803,2859,2736,3443, 556, 682, 823,1541,6140,1369,2289,1706,2794, 845, 462, # 2384 +2603,2665,1361, 387, 162,2358,1740, 739,1770,1720,1304,1401,3241,1049, 627,1571, # 2400 +2427,3526,1877,3942,1852,1500, 431,1910,1503, 677, 297,2795, 286,1433,1038,1198, # 2416 +2290,1133,1596,4113,4639,2469,1510,1484,3943,6141,2442, 108, 712,4640,2372, 866, # 2432 +3701,2755,3242,1348, 834,1945,1408,3527,2395,3243,1811, 824, 994,1179,2110,1548, # 2448 +1453, 790,3003, 690,4324,4325,2832,2909,3820,1860,3821, 225,1748, 310, 346,1780, # 2464 +2470, 821,1993,2717,2796, 828, 877,3528,2860,2471,1702,2165,2910,2486,1789, 453, # 2480 + 359,2291,1676, 73,1164,1461,1127,3311, 421, 604, 314,1037, 589, 116,2487, 737, # 2496 + 837,1180, 111, 244, 735,6142,2261,1861,1362, 986, 523, 418, 581,2666,3822, 103, # 2512 + 855, 503,1414,1867,2488,1091, 657,1597, 979, 605,1316,4641,1021,2443,2078,2001, # 2528 +1209, 96, 587,2166,1032, 260,1072,2153, 173, 94, 226,3244, 819,2006,4642,4114, # 2544 +2203, 231,1744, 782, 97,2667, 786,3387, 887, 391, 442,2219,4326,1425,6143,2694, # 2560 + 633,1544,1202, 483,2015, 592,2052,1958,2472,1655, 419, 129,4327,3444,3312,1714, # 2576 +1257,3078,4328,1518,1098, 865,1310,1019,1885,1512,1734, 469,2444, 148, 773, 436, # 2592 +1815,1868,1128,1055,4329,1245,2756,3445,2154,1934,1039,4643, 579,1238, 932,2320, # 2608 + 353, 205, 801, 115,2428, 944,2321,1881, 399,2565,1211, 678, 766,3944, 335,2101, # 2624 +1459,1781,1402,3945,2737,2131,1010, 844, 981,1326,1013, 550,1816,1545,2620,1335, # 2640 +1008, 371,2881, 936,1419,1613,3529,1456,1395,2273,1834,2604,1317,2738,2503, 416, # 2656 +1643,4330, 806,1126, 229, 591,3946,1314,1981,1576,1837,1666, 347,1790, 977,3313, # 2672 + 764,2861,1853, 688,2429,1920,1462, 77, 595, 415,2002,3034, 798,1192,4115,6144, # 2688 +2978,4331,3035,2695,2582,2072,2566, 430,2430,1727, 842,1396,3947,3702, 613, 377, # 2704 + 278, 236,1417,3388,3314,3174, 757,1869, 107,3530,6145,1194, 623,2262, 207,1253, # 2720 +2167,3446,3948, 492,1117,1935, 536,1838,2757,1246,4332, 696,2095,2406,1393,1572, # 2736 +3175,1782, 583, 190, 253,1390,2230, 830,3126,3389, 934,3245,1703,1749,2979,1870, # 2752 +2545,1656,2204, 869,2346,4116,3176,1817, 496,1764,4644, 942,1504, 404,1903,1122, # 2768 +1580,3606,2945,1022, 515, 372,1735, 955,2431,3036,6146,2797,1110,2302,2798, 617, # 2784 +6147, 441, 762,1771,3447,3607,3608,1904, 840,3037, 86, 939,1385, 572,1370,2445, # 2800 +1336, 114,3703, 898, 294, 203,3315, 703,1583,2274, 429, 961,4333,1854,1951,3390, # 2816 +2373,3704,4334,1318,1381, 966,1911,2322,1006,1155, 309, 989, 458,2718,1795,1372, # 2832 +1203, 252,1689,1363,3177, 517,1936, 168,1490, 562, 193,3823,1042,4117,1835, 551, # 2848 + 470,4645, 395, 489,3448,1871,1465,2583,2641, 417,1493, 279,1295, 511,1236,1119, # 2864 + 72,1231,1982,1812,3004, 871,1564, 984,3449,1667,2696,2096,4646,2347,2833,1673, # 2880 +3609, 695,3246,2668, 807,1183,4647, 890, 388,2333,1801,1457,2911,1765,1477,1031, # 2896 +3316,3317,1278,3391,2799,2292,2526, 163,3450,4335,2669,1404,1802,6148,2323,2407, # 2912 +1584,1728,1494,1824,1269, 298, 909,3318,1034,1632, 375, 776,1683,2061, 291, 210, # 2928 +1123, 809,1249,1002,2642,3038, 206,1011,2132, 144, 975, 882,1565, 342, 667, 754, # 2944 +1442,2143,1299,2303,2062, 447, 626,2205,1221,2739,2912,1144,1214,2206,2584, 760, # 2960 +1715, 614, 950,1281,2670,2621, 810, 577,1287,2546,4648, 242,2168, 250,2643, 691, # 2976 + 123,2644, 647, 313,1029, 689,1357,2946,1650, 216, 771,1339,1306, 808,2063, 549, # 2992 + 913,1371,2913,2914,6149,1466,1092,1174,1196,1311,2605,2396,1783,1796,3079, 406, # 3008 +2671,2117,3949,4649, 487,1825,2220,6150,2915, 448,2348,1073,6151,2397,1707, 130, # 3024 + 900,1598, 329, 176,1959,2527,1620,6152,2275,4336,3319,1983,2191,3705,3610,2155, # 3040 +3706,1912,1513,1614,6153,1988, 646, 392,2304,1589,3320,3039,1826,1239,1352,1340, # 3056 +2916, 505,2567,1709,1437,2408,2547, 906,6154,2672, 384,1458,1594,1100,1329, 710, # 3072 + 423,3531,2064,2231,2622,1989,2673,1087,1882, 333, 841,3005,1296,2882,2379, 580, # 3088 +1937,1827,1293,2585, 601, 574, 249,1772,4118,2079,1120, 645, 901,1176,1690, 795, # 3104 +2207, 478,1434, 516,1190,1530, 761,2080, 930,1264, 355, 435,1552, 644,1791, 987, # 3120 + 220,1364,1163,1121,1538, 306,2169,1327,1222, 546,2645, 218, 241, 610,1704,3321, # 3136 +1984,1839,1966,2528, 451,6155,2586,3707,2568, 907,3178, 254,2947, 186,1845,4650, # 3152 + 745, 432,1757, 428,1633, 888,2246,2221,2489,3611,2118,1258,1265, 956,3127,1784, # 3168 +4337,2490, 319, 510, 119, 457,3612, 274,2035,2007,4651,1409,3128, 970,2758, 590, # 3184 +2800, 661,2247,4652,2008,3950,1420,1549,3080,3322,3951,1651,1375,2111, 485,2491, # 3200 +1429,1156,6156,2548,2183,1495, 831,1840,2529,2446, 501,1657, 307,1894,3247,1341, # 3216 + 666, 899,2156,1539,2549,1559, 886, 349,2208,3081,2305,1736,3824,2170,2759,1014, # 3232 +1913,1386, 542,1397,2948, 490, 368, 716, 362, 159, 282,2569,1129,1658,1288,1750, # 3248 +2674, 276, 649,2016, 751,1496, 658,1818,1284,1862,2209,2087,2512,3451, 622,2834, # 3264 + 376, 117,1060,2053,1208,1721,1101,1443, 247,1250,3179,1792,3952,2760,2398,3953, # 3280 +6157,2144,3708, 446,2432,1151,2570,3452,2447,2761,2835,1210,2448,3082, 424,2222, # 3296 +1251,2449,2119,2836, 504,1581,4338, 602, 817, 857,3825,2349,2306, 357,3826,1470, # 3312 +1883,2883, 255, 958, 929,2917,3248, 302,4653,1050,1271,1751,2307,1952,1430,2697, # 3328 +2719,2359, 354,3180, 777, 158,2036,4339,1659,4340,4654,2308,2949,2248,1146,2232, # 3344 +3532,2720,1696,2623,3827,6158,3129,1550,2698,1485,1297,1428, 637, 931,2721,2145, # 3360 + 914,2550,2587, 81,2450, 612, 827,2646,1242,4655,1118,2884, 472,1855,3181,3533, # 3376 +3534, 569,1353,2699,1244,1758,2588,4119,2009,2762,2171,3709,1312,1531,6159,1152, # 3392 +1938, 134,1830, 471,3710,2276,1112,1535,3323,3453,3535, 982,1337,2950, 488, 826, # 3408 + 674,1058,1628,4120,2017, 522,2399, 211, 568,1367,3454, 350, 293,1872,1139,3249, # 3424 +1399,1946,3006,1300,2360,3324, 588, 736,6160,2606, 744, 669,3536,3828,6161,1358, # 3440 + 199, 723, 848, 933, 851,1939,1505,1514,1338,1618,1831,4656,1634,3613, 443,2740, # 3456 +3829, 717,1947, 491,1914,6162,2551,1542,4121,1025,6163,1099,1223, 198,3040,2722, # 3472 + 370, 410,1905,2589, 998,1248,3182,2380, 519,1449,4122,1710, 947, 928,1153,4341, # 3488 +2277, 344,2624,1511, 615, 105, 161,1212,1076,1960,3130,2054,1926,1175,1906,2473, # 3504 + 414,1873,2801,6164,2309, 315,1319,3325, 318,2018,2146,2157, 963, 631, 223,4342, # 3520 +4343,2675, 479,3711,1197,2625,3712,2676,2361,6165,4344,4123,6166,2451,3183,1886, # 3536 +2184,1674,1330,1711,1635,1506, 799, 219,3250,3083,3954,1677,3713,3326,2081,3614, # 3552 +1652,2073,4657,1147,3041,1752, 643,1961, 147,1974,3955,6167,1716,2037, 918,3007, # 3568 +1994, 120,1537, 118, 609,3184,4345, 740,3455,1219, 332,1615,3830,6168,1621,2980, # 3584 +1582, 783, 212, 553,2350,3714,1349,2433,2082,4124, 889,6169,2310,1275,1410, 973, # 3600 + 166,1320,3456,1797,1215,3185,2885,1846,2590,2763,4658, 629, 822,3008, 763, 940, # 3616 +1990,2862, 439,2409,1566,1240,1622, 926,1282,1907,2764, 654,2210,1607, 327,1130, # 3632 +3956,1678,1623,6170,2434,2192, 686, 608,3831,3715, 903,3957,3042,6171,2741,1522, # 3648 +1915,1105,1555,2552,1359, 323,3251,4346,3457, 738,1354,2553,2311,2334,1828,2003, # 3664 +3832,1753,2351,1227,6172,1887,4125,1478,6173,2410,1874,1712,1847, 520,1204,2607, # 3680 + 264,4659, 836,2677,2102, 600,4660,3833,2278,3084,6174,4347,3615,1342, 640, 532, # 3696 + 543,2608,1888,2400,2591,1009,4348,1497, 341,1737,3616,2723,1394, 529,3252,1321, # 3712 + 983,4661,1515,2120, 971,2592, 924, 287,1662,3186,4349,2700,4350,1519, 908,1948, # 3728 +2452, 156, 796,1629,1486,2223,2055, 694,4126,1259,1036,3392,1213,2249,2742,1889, # 3744 +1230,3958,1015, 910, 408, 559,3617,4662, 746, 725, 935,4663,3959,3009,1289, 563, # 3760 + 867,4664,3960,1567,2981,2038,2626, 988,2263,2381,4351, 143,2374, 704,1895,6175, # 3776 +1188,3716,2088, 673,3085,2362,4352, 484,1608,1921,2765,2918, 215, 904,3618,3537, # 3792 + 894, 509, 976,3043,2701,3961,4353,2837,2982, 498,6176,6177,1102,3538,1332,3393, # 3808 +1487,1636,1637, 233, 245,3962, 383, 650, 995,3044, 460,1520,1206,2352, 749,3327, # 3824 + 530, 700, 389,1438,1560,1773,3963,2264, 719,2951,2724,3834, 870,1832,1644,1000, # 3840 + 839,2474,3717, 197,1630,3394, 365,2886,3964,1285,2133, 734, 922, 818,1106, 732, # 3856 + 480,2083,1774,3458, 923,2279,1350, 221,3086, 85,2233,2234,3835,1585,3010,2147, # 3872 +1387,1705,2382,1619,2475, 133, 239,2802,1991,1016,2084,2383, 411,2838,1113, 651, # 3888 +1985,1160,3328, 990,1863,3087,1048,1276,2647, 265,2627,1599,3253,2056, 150, 638, # 3904 +2019, 656, 853, 326,1479, 680,1439,4354,1001,1759, 413,3459,3395,2492,1431, 459, # 3920 +4355,1125,3329,2265,1953,1450,2065,2863, 849, 351,2678,3131,3254,3255,1104,1577, # 3936 + 227,1351,1645,2453,2193,1421,2887, 812,2121, 634, 95,2435, 201,2312,4665,1646, # 3952 +1671,2743,1601,2554,2702,2648,2280,1315,1366,2089,3132,1573,3718,3965,1729,1189, # 3968 + 328,2679,1077,1940,1136, 558,1283, 964,1195, 621,2074,1199,1743,3460,3619,1896, # 3984 +1916,1890,3836,2952,1154,2112,1064, 862, 378,3011,2066,2113,2803,1568,2839,6178, # 4000 +3088,2919,1941,1660,2004,1992,2194, 142, 707,1590,1708,1624,1922,1023,1836,1233, # 4016 +1004,2313, 789, 741,3620,6179,1609,2411,1200,4127,3719,3720,4666,2057,3721, 593, # 4032 +2840, 367,2920,1878,6180,3461,1521, 628,1168, 692,2211,2649, 300, 720,2067,2571, # 4048 +2953,3396, 959,2504,3966,3539,3462,1977, 701,6181, 954,1043, 800, 681, 183,3722, # 4064 +1803,1730,3540,4128,2103, 815,2314, 174, 467, 230,2454,1093,2134, 755,3541,3397, # 4080 +1141,1162,6182,1738,2039, 270,3256,2513,1005,1647,2185,3837, 858,1679,1897,1719, # 4096 +2954,2324,1806, 402, 670, 167,4129,1498,2158,2104, 750,6183, 915, 189,1680,1551, # 4112 + 455,4356,1501,2455, 405,1095,2955, 338,1586,1266,1819, 570, 641,1324, 237,1556, # 4128 +2650,1388,3723,6184,1368,2384,1343,1978,3089,2436, 879,3724, 792,1191, 758,3012, # 4144 +1411,2135,1322,4357, 240,4667,1848,3725,1574,6185, 420,3045,1546,1391, 714,4358, # 4160 +1967, 941,1864, 863, 664, 426, 560,1731,2680,1785,2864,1949,2363, 403,3330,1415, # 4176 +1279,2136,1697,2335, 204, 721,2097,3838, 90,6186,2085,2505, 191,3967, 124,2148, # 4192 +1376,1798,1178,1107,1898,1405, 860,4359,1243,1272,2375,2983,1558,2456,1638, 113, # 4208 +3621, 578,1923,2609, 880, 386,4130, 784,2186,2266,1422,2956,2172,1722, 497, 263, # 4224 +2514,1267,2412,2610, 177,2703,3542, 774,1927,1344, 616,1432,1595,1018, 172,4360, # 4240 +2325, 911,4361, 438,1468,3622, 794,3968,2024,2173,1681,1829,2957, 945, 895,3090, # 4256 + 575,2212,2476, 475,2401,2681, 785,2744,1745,2293,2555,1975,3133,2865, 394,4668, # 4272 +3839, 635,4131, 639, 202,1507,2195,2766,1345,1435,2572,3726,1908,1184,1181,2457, # 4288 +3727,3134,4362, 843,2611, 437, 916,4669, 234, 769,1884,3046,3047,3623, 833,6187, # 4304 +1639,2250,2402,1355,1185,2010,2047, 999, 525,1732,1290,1488,2612, 948,1578,3728, # 4320 +2413,2477,1216,2725,2159, 334,3840,1328,3624,2921,1525,4132, 564,1056, 891,4363, # 4336 +1444,1698,2385,2251,3729,1365,2281,2235,1717,6188, 864,3841,2515, 444, 527,2767, # 4352 +2922,3625, 544, 461,6189, 566, 209,2437,3398,2098,1065,2068,3331,3626,3257,2137, # 4368 #last 512 +) + + diff --git a/venv/lib/python3.8/site-packages/chardet/jpcntx.py b/venv/lib/python3.8/site-packages/chardet/jpcntx.py new file mode 100644 index 0000000..20044e4 --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/jpcntx.py @@ -0,0 +1,233 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Communicator client code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + + +# This is hiragana 2-char sequence table, the number in each cell represents its frequency category +jp2CharContext = ( +(0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1), +(2,4,0,4,0,3,0,4,0,3,4,4,4,2,4,3,3,4,3,2,3,3,4,2,3,3,3,2,4,1,4,3,3,1,5,4,3,4,3,4,3,5,3,0,3,5,4,2,0,3,1,0,3,3,0,3,3,0,1,1,0,4,3,0,3,3,0,4,0,2,0,3,5,5,5,5,4,0,4,1,0,3,4), +(0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2), +(0,4,0,5,0,5,0,4,0,4,5,4,4,3,5,3,5,1,5,3,4,3,4,4,3,4,3,3,4,3,5,4,4,3,5,5,3,5,5,5,3,5,5,3,4,5,5,3,1,3,2,0,3,4,0,4,2,0,4,2,1,5,3,2,3,5,0,4,0,2,0,5,4,4,5,4,5,0,4,0,0,4,4), +(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), +(0,3,0,4,0,3,0,3,0,4,5,4,3,3,3,3,4,3,5,4,4,3,5,4,4,3,4,3,4,4,4,4,5,3,4,4,3,4,5,5,4,5,5,1,4,5,4,3,0,3,3,1,3,3,0,4,4,0,3,3,1,5,3,3,3,5,0,4,0,3,0,4,4,3,4,3,3,0,4,1,1,3,4), +(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), +(0,4,0,3,0,3,0,4,0,3,4,4,3,2,2,1,2,1,3,1,3,3,3,3,3,4,3,1,3,3,5,3,3,0,4,3,0,5,4,3,3,5,4,4,3,4,4,5,0,1,2,0,1,2,0,2,2,0,1,0,0,5,2,2,1,4,0,3,0,1,0,4,4,3,5,4,3,0,2,1,0,4,3), +(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), +(0,3,0,5,0,4,0,2,1,4,4,2,4,1,4,2,4,2,4,3,3,3,4,3,3,3,3,1,4,2,3,3,3,1,4,4,1,1,1,4,3,3,2,0,2,4,3,2,0,3,3,0,3,1,1,0,0,0,3,3,0,4,2,2,3,4,0,4,0,3,0,4,4,5,3,4,4,0,3,0,0,1,4), +(1,4,0,4,0,4,0,4,0,3,5,4,4,3,4,3,5,4,3,3,4,3,5,4,4,4,4,3,4,2,4,3,3,1,5,4,3,2,4,5,4,5,5,4,4,5,4,4,0,3,2,2,3,3,0,4,3,1,3,2,1,4,3,3,4,5,0,3,0,2,0,4,5,5,4,5,4,0,4,0,0,5,4), +(0,5,0,5,0,4,0,3,0,4,4,3,4,3,3,3,4,0,4,4,4,3,4,3,4,3,3,1,4,2,4,3,4,0,5,4,1,4,5,4,4,5,3,2,4,3,4,3,2,4,1,3,3,3,2,3,2,0,4,3,3,4,3,3,3,4,0,4,0,3,0,4,5,4,4,4,3,0,4,1,0,1,3), +(0,3,1,4,0,3,0,2,0,3,4,4,3,1,4,2,3,3,4,3,4,3,4,3,4,4,3,2,3,1,5,4,4,1,4,4,3,5,4,4,3,5,5,4,3,4,4,3,1,2,3,1,2,2,0,3,2,0,3,1,0,5,3,3,3,4,3,3,3,3,4,4,4,4,5,4,2,0,3,3,2,4,3), +(0,2,0,3,0,1,0,1,0,0,3,2,0,0,2,0,1,0,2,1,3,3,3,1,2,3,1,0,1,0,4,2,1,1,3,3,0,4,3,3,1,4,3,3,0,3,3,2,0,0,0,0,1,0,0,2,0,0,0,0,0,4,1,0,2,3,2,2,2,1,3,3,3,4,4,3,2,0,3,1,0,3,3), +(0,4,0,4,0,3,0,3,0,4,4,4,3,3,3,3,3,3,4,3,4,2,4,3,4,3,3,2,4,3,4,5,4,1,4,5,3,5,4,5,3,5,4,0,3,5,5,3,1,3,3,2,2,3,0,3,4,1,3,3,2,4,3,3,3,4,0,4,0,3,0,4,5,4,4,5,3,0,4,1,0,3,4), +(0,2,0,3,0,3,0,0,0,2,2,2,1,0,1,0,0,0,3,0,3,0,3,0,1,3,1,0,3,1,3,3,3,1,3,3,3,0,1,3,1,3,4,0,0,3,1,1,0,3,2,0,0,0,0,1,3,0,1,0,0,3,3,2,0,3,0,0,0,0,0,3,4,3,4,3,3,0,3,0,0,2,3), +(2,3,0,3,0,2,0,1,0,3,3,4,3,1,3,1,1,1,3,1,4,3,4,3,3,3,0,0,3,1,5,4,3,1,4,3,2,5,5,4,4,4,4,3,3,4,4,4,0,2,1,1,3,2,0,1,2,0,0,1,0,4,1,3,3,3,0,3,0,1,0,4,4,4,5,5,3,0,2,0,0,4,4), +(0,2,0,1,0,3,1,3,0,2,3,3,3,0,3,1,0,0,3,0,3,2,3,1,3,2,1,1,0,0,4,2,1,0,2,3,1,4,3,2,0,4,4,3,1,3,1,3,0,1,0,0,1,0,0,0,1,0,0,0,0,4,1,1,1,2,0,3,0,0,0,3,4,2,4,3,2,0,1,0,0,3,3), +(0,1,0,4,0,5,0,4,0,2,4,4,2,3,3,2,3,3,5,3,3,3,4,3,4,2,3,0,4,3,3,3,4,1,4,3,2,1,5,5,3,4,5,1,3,5,4,2,0,3,3,0,1,3,0,4,2,0,1,3,1,4,3,3,3,3,0,3,0,1,0,3,4,4,4,5,5,0,3,0,1,4,5), +(0,2,0,3,0,3,0,0,0,2,3,1,3,0,4,0,1,1,3,0,3,4,3,2,3,1,0,3,3,2,3,1,3,0,2,3,0,2,1,4,1,2,2,0,0,3,3,0,0,2,0,0,0,1,0,0,0,0,2,2,0,3,2,1,3,3,0,2,0,2,0,0,3,3,1,2,4,0,3,0,2,2,3), +(2,4,0,5,0,4,0,4,0,2,4,4,4,3,4,3,3,3,1,2,4,3,4,3,4,4,5,0,3,3,3,3,2,0,4,3,1,4,3,4,1,4,4,3,3,4,4,3,1,2,3,0,4,2,0,4,1,0,3,3,0,4,3,3,3,4,0,4,0,2,0,3,5,3,4,5,2,0,3,0,0,4,5), +(0,3,0,4,0,1,0,1,0,1,3,2,2,1,3,0,3,0,2,0,2,0,3,0,2,0,0,0,1,0,1,1,0,0,3,1,0,0,0,4,0,3,1,0,2,1,3,0,0,0,0,0,0,3,0,0,0,0,0,0,0,4,2,2,3,1,0,3,0,0,0,1,4,4,4,3,0,0,4,0,0,1,4), +(1,4,1,5,0,3,0,3,0,4,5,4,4,3,5,3,3,4,4,3,4,1,3,3,3,3,2,1,4,1,5,4,3,1,4,4,3,5,4,4,3,5,4,3,3,4,4,4,0,3,3,1,2,3,0,3,1,0,3,3,0,5,4,4,4,4,4,4,3,3,5,4,4,3,3,5,4,0,3,2,0,4,4), +(0,2,0,3,0,1,0,0,0,1,3,3,3,2,4,1,3,0,3,1,3,0,2,2,1,1,0,0,2,0,4,3,1,0,4,3,0,4,4,4,1,4,3,1,1,3,3,1,0,2,0,0,1,3,0,0,0,0,2,0,0,4,3,2,4,3,5,4,3,3,3,4,3,3,4,3,3,0,2,1,0,3,3), +(0,2,0,4,0,3,0,2,0,2,5,5,3,4,4,4,4,1,4,3,3,0,4,3,4,3,1,3,3,2,4,3,0,3,4,3,0,3,4,4,2,4,4,0,4,5,3,3,2,2,1,1,1,2,0,1,5,0,3,3,2,4,3,3,3,4,0,3,0,2,0,4,4,3,5,5,0,0,3,0,2,3,3), +(0,3,0,4,0,3,0,1,0,3,4,3,3,1,3,3,3,0,3,1,3,0,4,3,3,1,1,0,3,0,3,3,0,0,4,4,0,1,5,4,3,3,5,0,3,3,4,3,0,2,0,1,1,1,0,1,3,0,1,2,1,3,3,2,3,3,0,3,0,1,0,1,3,3,4,4,1,0,1,2,2,1,3), +(0,1,0,4,0,4,0,3,0,1,3,3,3,2,3,1,1,0,3,0,3,3,4,3,2,4,2,0,1,0,4,3,2,0,4,3,0,5,3,3,2,4,4,4,3,3,3,4,0,1,3,0,0,1,0,0,1,0,0,0,0,4,2,3,3,3,0,3,0,0,0,4,4,4,5,3,2,0,3,3,0,3,5), +(0,2,0,3,0,0,0,3,0,1,3,0,2,0,0,0,1,0,3,1,1,3,3,0,0,3,0,0,3,0,2,3,1,0,3,1,0,3,3,2,0,4,2,2,0,2,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,2,1,2,0,1,0,1,0,0,0,1,3,1,2,0,0,0,1,0,0,1,4), +(0,3,0,3,0,5,0,1,0,2,4,3,1,3,3,2,1,1,5,2,1,0,5,1,2,0,0,0,3,3,2,2,3,2,4,3,0,0,3,3,1,3,3,0,2,5,3,4,0,3,3,0,1,2,0,2,2,0,3,2,0,2,2,3,3,3,0,2,0,1,0,3,4,4,2,5,4,0,3,0,0,3,5), +(0,3,0,3,0,3,0,1,0,3,3,3,3,0,3,0,2,0,2,1,1,0,2,0,1,0,0,0,2,1,0,0,1,0,3,2,0,0,3,3,1,2,3,1,0,3,3,0,0,1,0,0,0,0,0,2,0,0,0,0,0,2,3,1,2,3,0,3,0,1,0,3,2,1,0,4,3,0,1,1,0,3,3), +(0,4,0,5,0,3,0,3,0,4,5,5,4,3,5,3,4,3,5,3,3,2,5,3,4,4,4,3,4,3,4,5,5,3,4,4,3,4,4,5,4,4,4,3,4,5,5,4,2,3,4,2,3,4,0,3,3,1,4,3,2,4,3,3,5,5,0,3,0,3,0,5,5,5,5,4,4,0,4,0,1,4,4), +(0,4,0,4,0,3,0,3,0,3,5,4,4,2,3,2,5,1,3,2,5,1,4,2,3,2,3,3,4,3,3,3,3,2,5,4,1,3,3,5,3,4,4,0,4,4,3,1,1,3,1,0,2,3,0,2,3,0,3,0,0,4,3,1,3,4,0,3,0,2,0,4,4,4,3,4,5,0,4,0,0,3,4), +(0,3,0,3,0,3,1,2,0,3,4,4,3,3,3,0,2,2,4,3,3,1,3,3,3,1,1,0,3,1,4,3,2,3,4,4,2,4,4,4,3,4,4,3,2,4,4,3,1,3,3,1,3,3,0,4,1,0,2,2,1,4,3,2,3,3,5,4,3,3,5,4,4,3,3,0,4,0,3,2,2,4,4), +(0,2,0,1,0,0,0,0,0,1,2,1,3,0,0,0,0,0,2,0,1,2,1,0,0,1,0,0,0,0,3,0,0,1,0,1,1,3,1,0,0,0,1,1,0,1,1,0,0,0,0,0,2,0,0,0,0,0,0,0,0,1,1,2,2,0,3,4,0,0,0,1,1,0,0,1,0,0,0,0,0,1,1), +(0,1,0,0,0,1,0,0,0,0,4,0,4,1,4,0,3,0,4,0,3,0,4,0,3,0,3,0,4,1,5,1,4,0,0,3,0,5,0,5,2,0,1,0,0,0,2,1,4,0,1,3,0,0,3,0,0,3,1,1,4,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0), +(1,4,0,5,0,3,0,2,0,3,5,4,4,3,4,3,5,3,4,3,3,0,4,3,3,3,3,3,3,2,4,4,3,1,3,4,4,5,4,4,3,4,4,1,3,5,4,3,3,3,1,2,2,3,3,1,3,1,3,3,3,5,3,3,4,5,0,3,0,3,0,3,4,3,4,4,3,0,3,0,2,4,3), +(0,1,0,4,0,0,0,0,0,1,4,0,4,1,4,2,4,0,3,0,1,0,1,0,0,0,0,0,2,0,3,1,1,1,0,3,0,0,0,1,2,1,0,0,1,1,1,1,0,1,0,0,0,1,0,0,3,0,0,0,0,3,2,0,2,2,0,1,0,0,0,2,3,2,3,3,0,0,0,0,2,1,0), +(0,5,1,5,0,3,0,3,0,5,4,4,5,1,5,3,3,0,4,3,4,3,5,3,4,3,3,2,4,3,4,3,3,0,3,3,1,4,4,3,4,4,4,3,4,5,5,3,2,3,1,1,3,3,1,3,1,1,3,3,2,4,5,3,3,5,0,4,0,3,0,4,4,3,5,3,3,0,3,4,0,4,3), +(0,5,0,5,0,3,0,2,0,4,4,3,5,2,4,3,3,3,4,4,4,3,5,3,5,3,3,1,4,0,4,3,3,0,3,3,0,4,4,4,4,5,4,3,3,5,5,3,2,3,1,2,3,2,0,1,0,0,3,2,2,4,4,3,1,5,0,4,0,3,0,4,3,1,3,2,1,0,3,3,0,3,3), +(0,4,0,5,0,5,0,4,0,4,5,5,5,3,4,3,3,2,5,4,4,3,5,3,5,3,4,0,4,3,4,4,3,2,4,4,3,4,5,4,4,5,5,0,3,5,5,4,1,3,3,2,3,3,1,3,1,0,4,3,1,4,4,3,4,5,0,4,0,2,0,4,3,4,4,3,3,0,4,0,0,5,5), +(0,4,0,4,0,5,0,1,1,3,3,4,4,3,4,1,3,0,5,1,3,0,3,1,3,1,1,0,3,0,3,3,4,0,4,3,0,4,4,4,3,4,4,0,3,5,4,1,0,3,0,0,2,3,0,3,1,0,3,1,0,3,2,1,3,5,0,3,0,1,0,3,2,3,3,4,4,0,2,2,0,4,4), +(2,4,0,5,0,4,0,3,0,4,5,5,4,3,5,3,5,3,5,3,5,2,5,3,4,3,3,4,3,4,5,3,2,1,5,4,3,2,3,4,5,3,4,1,2,5,4,3,0,3,3,0,3,2,0,2,3,0,4,1,0,3,4,3,3,5,0,3,0,1,0,4,5,5,5,4,3,0,4,2,0,3,5), +(0,5,0,4,0,4,0,2,0,5,4,3,4,3,4,3,3,3,4,3,4,2,5,3,5,3,4,1,4,3,4,4,4,0,3,5,0,4,4,4,4,5,3,1,3,4,5,3,3,3,3,3,3,3,0,2,2,0,3,3,2,4,3,3,3,5,3,4,1,3,3,5,3,2,0,0,0,0,4,3,1,3,3), +(0,1,0,3,0,3,0,1,0,1,3,3,3,2,3,3,3,0,3,0,0,0,3,1,3,0,0,0,2,2,2,3,0,0,3,2,0,1,2,4,1,3,3,0,0,3,3,3,0,1,0,0,2,1,0,0,3,0,3,1,0,3,0,0,1,3,0,2,0,1,0,3,3,1,3,3,0,0,1,1,0,3,3), +(0,2,0,3,0,2,1,4,0,2,2,3,1,1,3,1,1,0,2,0,3,1,2,3,1,3,0,0,1,0,4,3,2,3,3,3,1,4,2,3,3,3,3,1,0,3,1,4,0,1,1,0,1,2,0,1,1,0,1,1,0,3,1,3,2,2,0,1,0,0,0,2,3,3,3,1,0,0,0,0,0,2,3), +(0,5,0,4,0,5,0,2,0,4,5,5,3,3,4,3,3,1,5,4,4,2,4,4,4,3,4,2,4,3,5,5,4,3,3,4,3,3,5,5,4,5,5,1,3,4,5,3,1,4,3,1,3,3,0,3,3,1,4,3,1,4,5,3,3,5,0,4,0,3,0,5,3,3,1,4,3,0,4,0,1,5,3), +(0,5,0,5,0,4,0,2,0,4,4,3,4,3,3,3,3,3,5,4,4,4,4,4,4,5,3,3,5,2,4,4,4,3,4,4,3,3,4,4,5,5,3,3,4,3,4,3,3,4,3,3,3,3,1,2,2,1,4,3,3,5,4,4,3,4,0,4,0,3,0,4,4,4,4,4,1,0,4,2,0,2,4), +(0,4,0,4,0,3,0,1,0,3,5,2,3,0,3,0,2,1,4,2,3,3,4,1,4,3,3,2,4,1,3,3,3,0,3,3,0,0,3,3,3,5,3,3,3,3,3,2,0,2,0,0,2,0,0,2,0,0,1,0,0,3,1,2,2,3,0,3,0,2,0,4,4,3,3,4,1,0,3,0,0,2,4), +(0,0,0,4,0,0,0,0,0,0,1,0,1,0,2,0,0,0,0,0,1,0,2,0,1,0,0,0,0,0,3,1,3,0,3,2,0,0,0,1,0,3,2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,4,0,2,0,0,0,0,0,0,2), +(0,2,1,3,0,2,0,2,0,3,3,3,3,1,3,1,3,3,3,3,3,3,4,2,2,1,2,1,4,0,4,3,1,3,3,3,2,4,3,5,4,3,3,3,3,3,3,3,0,1,3,0,2,0,0,1,0,0,1,0,0,4,2,0,2,3,0,3,3,0,3,3,4,2,3,1,4,0,1,2,0,2,3), +(0,3,0,3,0,1,0,3,0,2,3,3,3,0,3,1,2,0,3,3,2,3,3,2,3,2,3,1,3,0,4,3,2,0,3,3,1,4,3,3,2,3,4,3,1,3,3,1,1,0,1,1,0,1,0,1,0,1,0,0,0,4,1,1,0,3,0,3,1,0,2,3,3,3,3,3,1,0,0,2,0,3,3), +(0,0,0,0,0,0,0,0,0,0,3,0,2,0,3,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,3,0,3,0,3,1,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,2,0,2,3,0,0,0,0,0,0,0,0,3), +(0,2,0,3,1,3,0,3,0,2,3,3,3,1,3,1,3,1,3,1,3,3,3,1,3,0,2,3,1,1,4,3,3,2,3,3,1,2,2,4,1,3,3,0,1,4,2,3,0,1,3,0,3,0,0,1,3,0,2,0,0,3,3,2,1,3,0,3,0,2,0,3,4,4,4,3,1,0,3,0,0,3,3), +(0,2,0,1,0,2,0,0,0,1,3,2,2,1,3,0,1,1,3,0,3,2,3,1,2,0,2,0,1,1,3,3,3,0,3,3,1,1,2,3,2,3,3,1,2,3,2,0,0,1,0,0,0,0,0,0,3,0,1,0,0,2,1,2,1,3,0,3,0,0,0,3,4,4,4,3,2,0,2,0,0,2,4), +(0,0,0,1,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,2,2,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,3,1,0,0,0,0,0,0,0,3), +(0,3,0,3,0,2,0,3,0,3,3,3,2,3,2,2,2,0,3,1,3,3,3,2,3,3,0,0,3,0,3,2,2,0,2,3,1,4,3,4,3,3,2,3,1,5,4,4,0,3,1,2,1,3,0,3,1,1,2,0,2,3,1,3,1,3,0,3,0,1,0,3,3,4,4,2,1,0,2,1,0,2,4), +(0,1,0,3,0,1,0,2,0,1,4,2,5,1,4,0,2,0,2,1,3,1,4,0,2,1,0,0,2,1,4,1,1,0,3,3,0,5,1,3,2,3,3,1,0,3,2,3,0,1,0,0,0,0,0,0,1,0,0,0,0,4,0,1,0,3,0,2,0,1,0,3,3,3,4,3,3,0,0,0,0,2,3), +(0,0,0,1,0,0,0,0,0,0,2,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,0,0,1,0,0,0,0,0,3), +(0,1,0,3,0,4,0,3,0,2,4,3,1,0,3,2,2,1,3,1,2,2,3,1,1,1,2,1,3,0,1,2,0,1,3,2,1,3,0,5,5,1,0,0,1,3,2,1,0,3,0,0,1,0,0,0,0,0,3,4,0,1,1,1,3,2,0,2,0,1,0,2,3,3,1,2,3,0,1,0,1,0,4), +(0,0,0,1,0,3,0,3,0,2,2,1,0,0,4,0,3,0,3,1,3,0,3,0,3,0,1,0,3,0,3,1,3,0,3,3,0,0,1,2,1,1,1,0,1,2,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,2,2,1,2,0,0,2,0,0,0,0,2,3,3,3,3,0,0,0,0,1,4), +(0,0,0,3,0,3,0,0,0,0,3,1,1,0,3,0,1,0,2,0,1,0,0,0,0,0,0,0,1,0,3,0,2,0,2,3,0,0,2,2,3,1,2,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,2,0,0,0,0,2,3), +(2,4,0,5,0,5,0,4,0,3,4,3,3,3,4,3,3,3,4,3,4,4,5,4,5,5,5,2,3,0,5,5,4,1,5,4,3,1,5,4,3,4,4,3,3,4,3,3,0,3,2,0,2,3,0,3,0,0,3,3,0,5,3,2,3,3,0,3,0,3,0,3,4,5,4,5,3,0,4,3,0,3,4), +(0,3,0,3,0,3,0,3,0,3,3,4,3,2,3,2,3,0,4,3,3,3,3,3,3,3,3,0,3,2,4,3,3,1,3,4,3,4,4,4,3,4,4,3,2,4,4,1,0,2,0,0,1,1,0,2,0,0,3,1,0,5,3,2,1,3,0,3,0,1,2,4,3,2,4,3,3,0,3,2,0,4,4), +(0,3,0,3,0,1,0,0,0,1,4,3,3,2,3,1,3,1,4,2,3,2,4,2,3,4,3,0,2,2,3,3,3,0,3,3,3,0,3,4,1,3,3,0,3,4,3,3,0,1,1,0,1,0,0,0,4,0,3,0,0,3,1,2,1,3,0,4,0,1,0,4,3,3,4,3,3,0,2,0,0,3,3), +(0,3,0,4,0,1,0,3,0,3,4,3,3,0,3,3,3,1,3,1,3,3,4,3,3,3,0,0,3,1,5,3,3,1,3,3,2,5,4,3,3,4,5,3,2,5,3,4,0,1,0,0,0,0,0,2,0,0,1,1,0,4,2,2,1,3,0,3,0,2,0,4,4,3,5,3,2,0,1,1,0,3,4), +(0,5,0,4,0,5,0,2,0,4,4,3,3,2,3,3,3,1,4,3,4,1,5,3,4,3,4,0,4,2,4,3,4,1,5,4,0,4,4,4,4,5,4,1,3,5,4,2,1,4,1,1,3,2,0,3,1,0,3,2,1,4,3,3,3,4,0,4,0,3,0,4,4,4,3,3,3,0,4,2,0,3,4), +(1,4,0,4,0,3,0,1,0,3,3,3,1,1,3,3,2,2,3,3,1,0,3,2,2,1,2,0,3,1,2,1,2,0,3,2,0,2,2,3,3,4,3,0,3,3,1,2,0,1,1,3,1,2,0,0,3,0,1,1,0,3,2,2,3,3,0,3,0,0,0,2,3,3,4,3,3,0,1,0,0,1,4), +(0,4,0,4,0,4,0,0,0,3,4,4,3,1,4,2,3,2,3,3,3,1,4,3,4,0,3,0,4,2,3,3,2,2,5,4,2,1,3,4,3,4,3,1,3,3,4,2,0,2,1,0,3,3,0,0,2,0,3,1,0,4,4,3,4,3,0,4,0,1,0,2,4,4,4,4,4,0,3,2,0,3,3), +(0,0,0,1,0,4,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,3,2,0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,2), +(0,2,0,3,0,4,0,4,0,1,3,3,3,0,4,0,2,1,2,1,1,1,2,0,3,1,1,0,1,0,3,1,0,0,3,3,2,0,1,1,0,0,0,0,0,1,0,2,0,2,2,0,3,1,0,0,1,0,1,1,0,1,2,0,3,0,0,0,0,1,0,0,3,3,4,3,1,0,1,0,3,0,2), +(0,0,0,3,0,5,0,0,0,0,1,0,2,0,3,1,0,1,3,0,0,0,2,0,0,0,1,0,0,0,1,1,0,0,4,0,0,0,2,3,0,1,4,1,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,1,0,0,0,0,0,0,0,2,0,0,3,0,0,0,0,0,3), +(0,2,0,5,0,5,0,1,0,2,4,3,3,2,5,1,3,2,3,3,3,0,4,1,2,0,3,0,4,0,2,2,1,1,5,3,0,0,1,4,2,3,2,0,3,3,3,2,0,2,4,1,1,2,0,1,1,0,3,1,0,1,3,1,2,3,0,2,0,0,0,1,3,5,4,4,4,0,3,0,0,1,3), +(0,4,0,5,0,4,0,4,0,4,5,4,3,3,4,3,3,3,4,3,4,4,5,3,4,5,4,2,4,2,3,4,3,1,4,4,1,3,5,4,4,5,5,4,4,5,5,5,2,3,3,1,4,3,1,3,3,0,3,3,1,4,3,4,4,4,0,3,0,4,0,3,3,4,4,5,0,0,4,3,0,4,5), +(0,4,0,4,0,3,0,3,0,3,4,4,4,3,3,2,4,3,4,3,4,3,5,3,4,3,2,1,4,2,4,4,3,1,3,4,2,4,5,5,3,4,5,4,1,5,4,3,0,3,2,2,3,2,1,3,1,0,3,3,3,5,3,3,3,5,4,4,2,3,3,4,3,3,3,2,1,0,3,2,1,4,3), +(0,4,0,5,0,4,0,3,0,3,5,5,3,2,4,3,4,0,5,4,4,1,4,4,4,3,3,3,4,3,5,5,2,3,3,4,1,2,5,5,3,5,5,2,3,5,5,4,0,3,2,0,3,3,1,1,5,1,4,1,0,4,3,2,3,5,0,4,0,3,0,5,4,3,4,3,0,0,4,1,0,4,4), +(1,3,0,4,0,2,0,2,0,2,5,5,3,3,3,3,3,0,4,2,3,4,4,4,3,4,0,0,3,4,5,4,3,3,3,3,2,5,5,4,5,5,5,4,3,5,5,5,1,3,1,0,1,0,0,3,2,0,4,2,0,5,2,3,2,4,1,3,0,3,0,4,5,4,5,4,3,0,4,2,0,5,4), +(0,3,0,4,0,5,0,3,0,3,4,4,3,2,3,2,3,3,3,3,3,2,4,3,3,2,2,0,3,3,3,3,3,1,3,3,3,0,4,4,3,4,4,1,1,4,4,2,0,3,1,0,1,1,0,4,1,0,2,3,1,3,3,1,3,4,0,3,0,1,0,3,1,3,0,0,1,0,2,0,0,4,4), +(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), +(0,3,0,3,0,2,0,3,0,1,5,4,3,3,3,1,4,2,1,2,3,4,4,2,4,4,5,0,3,1,4,3,4,0,4,3,3,3,2,3,2,5,3,4,3,2,2,3,0,0,3,0,2,1,0,1,2,0,0,0,0,2,1,1,3,1,0,2,0,4,0,3,4,4,4,5,2,0,2,0,0,1,3), +(0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,1,0,0,1,1,0,0,0,4,2,1,1,0,1,0,3,2,0,0,3,1,1,1,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,1,0,0,0,2,0,0,0,1,4,0,4,2,1,0,0,0,0,0,1), +(0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,3,1,0,0,0,2,0,2,1,0,0,1,2,1,0,1,1,0,0,3,0,0,0,0,0,0,0,0,0,0,0,1,3,1,0,0,0,0,0,1,0,0,2,1,0,0,0,0,0,0,0,0,2), +(0,4,0,4,0,4,0,3,0,4,4,3,4,2,4,3,2,0,4,4,4,3,5,3,5,3,3,2,4,2,4,3,4,3,1,4,0,2,3,4,4,4,3,3,3,4,4,4,3,4,1,3,4,3,2,1,2,1,3,3,3,4,4,3,3,5,0,4,0,3,0,4,3,3,3,2,1,0,3,0,0,3,3), +(0,4,0,3,0,3,0,3,0,3,5,5,3,3,3,3,4,3,4,3,3,3,4,4,4,3,3,3,3,4,3,5,3,3,1,3,2,4,5,5,5,5,4,3,4,5,5,3,2,2,3,3,3,3,2,3,3,1,2,3,2,4,3,3,3,4,0,4,0,2,0,4,3,2,2,1,2,0,3,0,0,4,1), +) + +class JapaneseContextAnalysis(object): + NUM_OF_CATEGORY = 6 + DONT_KNOW = -1 + ENOUGH_REL_THRESHOLD = 100 + MAX_REL_THRESHOLD = 1000 + MINIMUM_DATA_THRESHOLD = 4 + + def __init__(self): + self._total_rel = None + self._rel_sample = None + self._need_to_skip_char_num = None + self._last_char_order = None + self._done = None + self.reset() + + def reset(self): + self._total_rel = 0 # total sequence received + # category counters, each integer counts sequence in its category + self._rel_sample = [0] * self.NUM_OF_CATEGORY + # if last byte in current buffer is not the last byte of a character, + # we need to know how many bytes to skip in next buffer + self._need_to_skip_char_num = 0 + self._last_char_order = -1 # The order of previous char + # If this flag is set to True, detection is done and conclusion has + # been made + self._done = False + + def feed(self, byte_str, num_bytes): + if self._done: + return + + # The buffer we got is byte oriented, and a character may span in more than one + # buffers. In case the last one or two byte in last buffer is not + # complete, we record how many byte needed to complete that character + # and skip these bytes here. We can choose to record those bytes as + # well and analyse the character once it is complete, but since a + # character will not make much difference, by simply skipping + # this character will simply our logic and improve performance. + i = self._need_to_skip_char_num + while i < num_bytes: + order, char_len = self.get_order(byte_str[i:i + 2]) + i += char_len + if i > num_bytes: + self._need_to_skip_char_num = i - num_bytes + self._last_char_order = -1 + else: + if (order != -1) and (self._last_char_order != -1): + self._total_rel += 1 + if self._total_rel > self.MAX_REL_THRESHOLD: + self._done = True + break + self._rel_sample[jp2CharContext[self._last_char_order][order]] += 1 + self._last_char_order = order + + def got_enough_data(self): + return self._total_rel > self.ENOUGH_REL_THRESHOLD + + def get_confidence(self): + # This is just one way to calculate confidence. It works well for me. + if self._total_rel > self.MINIMUM_DATA_THRESHOLD: + return (self._total_rel - self._rel_sample[0]) / self._total_rel + else: + return self.DONT_KNOW + + def get_order(self, byte_str): + return -1, 1 + +class SJISContextAnalysis(JapaneseContextAnalysis): + def __init__(self): + super(SJISContextAnalysis, self).__init__() + self._charset_name = "SHIFT_JIS" + + @property + def charset_name(self): + return self._charset_name + + def get_order(self, byte_str): + if not byte_str: + return -1, 1 + # find out current char's byte length + first_char = byte_str[0] + if (0x81 <= first_char <= 0x9F) or (0xE0 <= first_char <= 0xFC): + char_len = 2 + if (first_char == 0x87) or (0xFA <= first_char <= 0xFC): + self._charset_name = "CP932" + else: + char_len = 1 + + # return its order if it is hiragana + if len(byte_str) > 1: + second_char = byte_str[1] + if (first_char == 202) and (0x9F <= second_char <= 0xF1): + return second_char - 0x9F, char_len + + return -1, char_len + +class EUCJPContextAnalysis(JapaneseContextAnalysis): + def get_order(self, byte_str): + if not byte_str: + return -1, 1 + # find out current char's byte length + first_char = byte_str[0] + if (first_char == 0x8E) or (0xA1 <= first_char <= 0xFE): + char_len = 2 + elif first_char == 0x8F: + char_len = 3 + else: + char_len = 1 + + # return its order if it is hiragana + if len(byte_str) > 1: + second_char = byte_str[1] + if (first_char == 0xA4) and (0xA1 <= second_char <= 0xF3): + return second_char - 0xA1, char_len + + return -1, char_len + + diff --git a/venv/lib/python3.8/site-packages/chardet/langbulgarianmodel.py b/venv/lib/python3.8/site-packages/chardet/langbulgarianmodel.py new file mode 100644 index 0000000..561bfd9 --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/langbulgarianmodel.py @@ -0,0 +1,4650 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from chardet.sbcharsetprober import SingleByteCharSetModel + + +# 3: Positive +# 2: Likely +# 1: Unlikely +# 0: Negative + +BULGARIAN_LANG_MODEL = { + 63: { # 'e' + 63: 1, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 0, # 'а' + 18: 1, # 'б' + 9: 1, # 'в' + 20: 1, # 'г' + 11: 1, # 'д' + 3: 1, # 'е' + 23: 1, # 'ж' + 15: 1, # 'з' + 2: 0, # 'и' + 26: 1, # 'й' + 12: 1, # 'к' + 10: 1, # 'л' + 14: 1, # 'м' + 6: 1, # 'н' + 4: 1, # 'о' + 13: 1, # 'п' + 7: 1, # 'р' + 8: 1, # 'с' + 5: 1, # 'т' + 19: 0, # 'у' + 29: 1, # 'ф' + 25: 1, # 'х' + 22: 0, # 'ц' + 21: 1, # 'ч' + 27: 1, # 'ш' + 24: 1, # 'щ' + 17: 0, # 'ъ' + 52: 0, # 'ь' + 42: 0, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 45: { # '\xad' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 1, # 'Б' + 35: 1, # 'В' + 43: 0, # 'Г' + 37: 1, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 1, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 0, # 'Л' + 38: 1, # 'М' + 36: 0, # 'Н' + 41: 1, # 'О' + 30: 1, # 'П' + 39: 1, # 'Р' + 28: 1, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 1, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 0, # 'а' + 18: 0, # 'б' + 9: 0, # 'в' + 20: 0, # 'г' + 11: 0, # 'д' + 3: 0, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 0, # 'и' + 26: 0, # 'й' + 12: 0, # 'к' + 10: 0, # 'л' + 14: 0, # 'м' + 6: 0, # 'н' + 4: 0, # 'о' + 13: 0, # 'п' + 7: 0, # 'р' + 8: 0, # 'с' + 5: 0, # 'т' + 19: 0, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 0, # 'ъ' + 52: 0, # 'ь' + 42: 0, # 'ю' + 16: 0, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 31: { # 'А' + 63: 0, # 'e' + 45: 1, # '\xad' + 31: 1, # 'А' + 32: 1, # 'Б' + 35: 2, # 'В' + 43: 1, # 'Г' + 37: 2, # 'Д' + 44: 2, # 'Е' + 55: 1, # 'Ж' + 47: 2, # 'З' + 40: 1, # 'И' + 59: 1, # 'Й' + 33: 1, # 'К' + 46: 2, # 'Л' + 38: 1, # 'М' + 36: 2, # 'Н' + 41: 1, # 'О' + 30: 2, # 'П' + 39: 2, # 'Р' + 28: 2, # 'С' + 34: 2, # 'Т' + 51: 1, # 'У' + 48: 2, # 'Ф' + 49: 1, # 'Х' + 53: 1, # 'Ц' + 50: 1, # 'Ч' + 54: 1, # 'Ш' + 57: 2, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 1, # 'Я' + 1: 1, # 'а' + 18: 2, # 'б' + 9: 2, # 'в' + 20: 2, # 'г' + 11: 2, # 'д' + 3: 1, # 'е' + 23: 1, # 'ж' + 15: 2, # 'з' + 2: 0, # 'и' + 26: 2, # 'й' + 12: 2, # 'к' + 10: 3, # 'л' + 14: 2, # 'м' + 6: 3, # 'н' + 4: 0, # 'о' + 13: 2, # 'п' + 7: 2, # 'р' + 8: 2, # 'с' + 5: 2, # 'т' + 19: 1, # 'у' + 29: 2, # 'ф' + 25: 1, # 'х' + 22: 1, # 'ц' + 21: 1, # 'ч' + 27: 1, # 'ш' + 24: 0, # 'щ' + 17: 0, # 'ъ' + 52: 0, # 'ь' + 42: 0, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 32: { # 'Б' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 2, # 'А' + 32: 2, # 'Б' + 35: 1, # 'В' + 43: 1, # 'Г' + 37: 2, # 'Д' + 44: 1, # 'Е' + 55: 1, # 'Ж' + 47: 2, # 'З' + 40: 1, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 1, # 'Л' + 38: 1, # 'М' + 36: 2, # 'Н' + 41: 2, # 'О' + 30: 1, # 'П' + 39: 1, # 'Р' + 28: 2, # 'С' + 34: 2, # 'Т' + 51: 1, # 'У' + 48: 2, # 'Ф' + 49: 1, # 'Х' + 53: 1, # 'Ц' + 50: 1, # 'Ч' + 54: 0, # 'Ш' + 57: 1, # 'Щ' + 61: 2, # 'Ъ' + 60: 1, # 'Ю' + 56: 1, # 'Я' + 1: 3, # 'а' + 18: 0, # 'б' + 9: 0, # 'в' + 20: 0, # 'г' + 11: 1, # 'д' + 3: 3, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 2, # 'и' + 26: 0, # 'й' + 12: 0, # 'к' + 10: 2, # 'л' + 14: 0, # 'м' + 6: 0, # 'н' + 4: 3, # 'о' + 13: 0, # 'п' + 7: 2, # 'р' + 8: 1, # 'с' + 5: 0, # 'т' + 19: 2, # 'у' + 29: 0, # 'ф' + 25: 1, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 3, # 'ъ' + 52: 1, # 'ь' + 42: 1, # 'ю' + 16: 2, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 35: { # 'В' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 2, # 'А' + 32: 1, # 'Б' + 35: 1, # 'В' + 43: 0, # 'Г' + 37: 1, # 'Д' + 44: 2, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 2, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 1, # 'Л' + 38: 1, # 'М' + 36: 1, # 'Н' + 41: 1, # 'О' + 30: 1, # 'П' + 39: 2, # 'Р' + 28: 2, # 'С' + 34: 1, # 'Т' + 51: 1, # 'У' + 48: 2, # 'Ф' + 49: 0, # 'Х' + 53: 1, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 1, # 'Ъ' + 60: 1, # 'Ю' + 56: 2, # 'Я' + 1: 3, # 'а' + 18: 1, # 'б' + 9: 0, # 'в' + 20: 0, # 'г' + 11: 1, # 'д' + 3: 3, # 'е' + 23: 1, # 'ж' + 15: 2, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 1, # 'к' + 10: 2, # 'л' + 14: 1, # 'м' + 6: 2, # 'н' + 4: 2, # 'о' + 13: 1, # 'п' + 7: 2, # 'р' + 8: 2, # 'с' + 5: 2, # 'т' + 19: 1, # 'у' + 29: 0, # 'ф' + 25: 1, # 'х' + 22: 0, # 'ц' + 21: 2, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 2, # 'ъ' + 52: 1, # 'ь' + 42: 1, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 43: { # 'Г' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 2, # 'А' + 32: 1, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 1, # 'Д' + 44: 2, # 'Е' + 55: 0, # 'Ж' + 47: 1, # 'З' + 40: 1, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 1, # 'Л' + 38: 0, # 'М' + 36: 1, # 'Н' + 41: 1, # 'О' + 30: 0, # 'П' + 39: 1, # 'Р' + 28: 1, # 'С' + 34: 0, # 'Т' + 51: 1, # 'У' + 48: 1, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 1, # 'Щ' + 61: 1, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 2, # 'а' + 18: 1, # 'б' + 9: 1, # 'в' + 20: 0, # 'г' + 11: 1, # 'д' + 3: 3, # 'е' + 23: 1, # 'ж' + 15: 0, # 'з' + 2: 2, # 'и' + 26: 0, # 'й' + 12: 1, # 'к' + 10: 2, # 'л' + 14: 1, # 'м' + 6: 1, # 'н' + 4: 2, # 'о' + 13: 0, # 'п' + 7: 2, # 'р' + 8: 0, # 'с' + 5: 0, # 'т' + 19: 2, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 1, # 'щ' + 17: 2, # 'ъ' + 52: 1, # 'ь' + 42: 1, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 37: { # 'Д' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 2, # 'А' + 32: 1, # 'Б' + 35: 2, # 'В' + 43: 1, # 'Г' + 37: 2, # 'Д' + 44: 2, # 'Е' + 55: 2, # 'Ж' + 47: 1, # 'З' + 40: 2, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 1, # 'Л' + 38: 1, # 'М' + 36: 1, # 'Н' + 41: 2, # 'О' + 30: 2, # 'П' + 39: 1, # 'Р' + 28: 2, # 'С' + 34: 1, # 'Т' + 51: 1, # 'У' + 48: 1, # 'Ф' + 49: 0, # 'Х' + 53: 1, # 'Ц' + 50: 1, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 1, # 'Ъ' + 60: 1, # 'Ю' + 56: 1, # 'Я' + 1: 3, # 'а' + 18: 0, # 'б' + 9: 2, # 'в' + 20: 0, # 'г' + 11: 0, # 'д' + 3: 3, # 'е' + 23: 3, # 'ж' + 15: 1, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 0, # 'к' + 10: 1, # 'л' + 14: 1, # 'м' + 6: 2, # 'н' + 4: 3, # 'о' + 13: 0, # 'п' + 7: 2, # 'р' + 8: 0, # 'с' + 5: 0, # 'т' + 19: 2, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 2, # 'ъ' + 52: 1, # 'ь' + 42: 2, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 44: { # 'Е' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 1, # 'А' + 32: 1, # 'Б' + 35: 2, # 'В' + 43: 1, # 'Г' + 37: 1, # 'Д' + 44: 1, # 'Е' + 55: 1, # 'Ж' + 47: 1, # 'З' + 40: 1, # 'И' + 59: 1, # 'Й' + 33: 2, # 'К' + 46: 2, # 'Л' + 38: 1, # 'М' + 36: 2, # 'Н' + 41: 2, # 'О' + 30: 1, # 'П' + 39: 2, # 'Р' + 28: 2, # 'С' + 34: 2, # 'Т' + 51: 1, # 'У' + 48: 2, # 'Ф' + 49: 1, # 'Х' + 53: 2, # 'Ц' + 50: 1, # 'Ч' + 54: 1, # 'Ш' + 57: 1, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 1, # 'Я' + 1: 0, # 'а' + 18: 1, # 'б' + 9: 2, # 'в' + 20: 1, # 'г' + 11: 2, # 'д' + 3: 0, # 'е' + 23: 1, # 'ж' + 15: 1, # 'з' + 2: 0, # 'и' + 26: 1, # 'й' + 12: 2, # 'к' + 10: 2, # 'л' + 14: 2, # 'м' + 6: 2, # 'н' + 4: 0, # 'о' + 13: 1, # 'п' + 7: 2, # 'р' + 8: 2, # 'с' + 5: 1, # 'т' + 19: 1, # 'у' + 29: 1, # 'ф' + 25: 1, # 'х' + 22: 0, # 'ц' + 21: 1, # 'ч' + 27: 1, # 'ш' + 24: 1, # 'щ' + 17: 1, # 'ъ' + 52: 0, # 'ь' + 42: 1, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 55: { # 'Ж' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 1, # 'А' + 32: 0, # 'Б' + 35: 1, # 'В' + 43: 0, # 'Г' + 37: 1, # 'Д' + 44: 1, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 1, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 1, # 'Н' + 41: 1, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 1, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 2, # 'а' + 18: 0, # 'б' + 9: 0, # 'в' + 20: 0, # 'г' + 11: 1, # 'д' + 3: 2, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 2, # 'и' + 26: 0, # 'й' + 12: 0, # 'к' + 10: 0, # 'л' + 14: 0, # 'м' + 6: 0, # 'н' + 4: 2, # 'о' + 13: 1, # 'п' + 7: 1, # 'р' + 8: 0, # 'с' + 5: 0, # 'т' + 19: 1, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 1, # 'ъ' + 52: 1, # 'ь' + 42: 1, # 'ю' + 16: 0, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 47: { # 'З' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 2, # 'А' + 32: 1, # 'Б' + 35: 1, # 'В' + 43: 1, # 'Г' + 37: 1, # 'Д' + 44: 1, # 'Е' + 55: 0, # 'Ж' + 47: 1, # 'З' + 40: 1, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 1, # 'Л' + 38: 1, # 'М' + 36: 2, # 'Н' + 41: 1, # 'О' + 30: 1, # 'П' + 39: 1, # 'Р' + 28: 1, # 'С' + 34: 1, # 'Т' + 51: 1, # 'У' + 48: 0, # 'Ф' + 49: 1, # 'Х' + 53: 1, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 1, # 'Ъ' + 60: 0, # 'Ю' + 56: 1, # 'Я' + 1: 3, # 'а' + 18: 1, # 'б' + 9: 2, # 'в' + 20: 1, # 'г' + 11: 2, # 'д' + 3: 2, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 1, # 'и' + 26: 0, # 'й' + 12: 0, # 'к' + 10: 2, # 'л' + 14: 1, # 'м' + 6: 1, # 'н' + 4: 1, # 'о' + 13: 0, # 'п' + 7: 1, # 'р' + 8: 0, # 'с' + 5: 0, # 'т' + 19: 1, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 1, # 'ъ' + 52: 0, # 'ь' + 42: 1, # 'ю' + 16: 0, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 40: { # 'И' + 63: 0, # 'e' + 45: 1, # '\xad' + 31: 1, # 'А' + 32: 1, # 'Б' + 35: 1, # 'В' + 43: 1, # 'Г' + 37: 1, # 'Д' + 44: 2, # 'Е' + 55: 1, # 'Ж' + 47: 2, # 'З' + 40: 1, # 'И' + 59: 1, # 'Й' + 33: 2, # 'К' + 46: 2, # 'Л' + 38: 2, # 'М' + 36: 2, # 'Н' + 41: 1, # 'О' + 30: 1, # 'П' + 39: 2, # 'Р' + 28: 2, # 'С' + 34: 2, # 'Т' + 51: 0, # 'У' + 48: 1, # 'Ф' + 49: 1, # 'Х' + 53: 1, # 'Ц' + 50: 1, # 'Ч' + 54: 1, # 'Ш' + 57: 1, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 2, # 'Я' + 1: 1, # 'а' + 18: 1, # 'б' + 9: 3, # 'в' + 20: 2, # 'г' + 11: 1, # 'д' + 3: 1, # 'е' + 23: 0, # 'ж' + 15: 3, # 'з' + 2: 0, # 'и' + 26: 1, # 'й' + 12: 1, # 'к' + 10: 2, # 'л' + 14: 2, # 'м' + 6: 2, # 'н' + 4: 0, # 'о' + 13: 1, # 'п' + 7: 2, # 'р' + 8: 2, # 'с' + 5: 2, # 'т' + 19: 0, # 'у' + 29: 1, # 'ф' + 25: 1, # 'х' + 22: 1, # 'ц' + 21: 1, # 'ч' + 27: 1, # 'ш' + 24: 1, # 'щ' + 17: 0, # 'ъ' + 52: 0, # 'ь' + 42: 0, # 'ю' + 16: 0, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 59: { # 'Й' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 1, # 'Д' + 44: 1, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 1, # 'Л' + 38: 1, # 'М' + 36: 1, # 'Н' + 41: 1, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 1, # 'С' + 34: 1, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 1, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 1, # 'Я' + 1: 0, # 'а' + 18: 0, # 'б' + 9: 0, # 'в' + 20: 0, # 'г' + 11: 0, # 'д' + 3: 1, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 0, # 'и' + 26: 0, # 'й' + 12: 0, # 'к' + 10: 0, # 'л' + 14: 0, # 'м' + 6: 0, # 'н' + 4: 2, # 'о' + 13: 0, # 'п' + 7: 0, # 'р' + 8: 0, # 'с' + 5: 0, # 'т' + 19: 0, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 1, # 'ъ' + 52: 0, # 'ь' + 42: 0, # 'ю' + 16: 0, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 33: { # 'К' + 63: 0, # 'e' + 45: 1, # '\xad' + 31: 2, # 'А' + 32: 1, # 'Б' + 35: 1, # 'В' + 43: 1, # 'Г' + 37: 1, # 'Д' + 44: 1, # 'Е' + 55: 0, # 'Ж' + 47: 1, # 'З' + 40: 2, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 1, # 'Л' + 38: 0, # 'М' + 36: 2, # 'Н' + 41: 2, # 'О' + 30: 2, # 'П' + 39: 1, # 'Р' + 28: 2, # 'С' + 34: 1, # 'Т' + 51: 1, # 'У' + 48: 1, # 'Ф' + 49: 1, # 'Х' + 53: 1, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 1, # 'Ъ' + 60: 1, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 0, # 'б' + 9: 1, # 'в' + 20: 0, # 'г' + 11: 0, # 'д' + 3: 2, # 'е' + 23: 1, # 'ж' + 15: 0, # 'з' + 2: 2, # 'и' + 26: 0, # 'й' + 12: 0, # 'к' + 10: 2, # 'л' + 14: 1, # 'м' + 6: 2, # 'н' + 4: 3, # 'о' + 13: 0, # 'п' + 7: 3, # 'р' + 8: 1, # 'с' + 5: 0, # 'т' + 19: 2, # 'у' + 29: 0, # 'ф' + 25: 1, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 1, # 'ш' + 24: 0, # 'щ' + 17: 2, # 'ъ' + 52: 1, # 'ь' + 42: 2, # 'ю' + 16: 0, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 46: { # 'Л' + 63: 1, # 'e' + 45: 0, # '\xad' + 31: 2, # 'А' + 32: 1, # 'Б' + 35: 1, # 'В' + 43: 2, # 'Г' + 37: 1, # 'Д' + 44: 2, # 'Е' + 55: 0, # 'Ж' + 47: 1, # 'З' + 40: 2, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 1, # 'Л' + 38: 0, # 'М' + 36: 1, # 'Н' + 41: 2, # 'О' + 30: 1, # 'П' + 39: 0, # 'Р' + 28: 1, # 'С' + 34: 1, # 'Т' + 51: 1, # 'У' + 48: 0, # 'Ф' + 49: 1, # 'Х' + 53: 1, # 'Ц' + 50: 1, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 1, # 'Ъ' + 60: 1, # 'Ю' + 56: 1, # 'Я' + 1: 2, # 'а' + 18: 0, # 'б' + 9: 1, # 'в' + 20: 0, # 'г' + 11: 0, # 'д' + 3: 3, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 2, # 'и' + 26: 0, # 'й' + 12: 0, # 'к' + 10: 0, # 'л' + 14: 0, # 'м' + 6: 0, # 'н' + 4: 2, # 'о' + 13: 0, # 'п' + 7: 0, # 'р' + 8: 0, # 'с' + 5: 0, # 'т' + 19: 2, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 1, # 'ъ' + 52: 1, # 'ь' + 42: 2, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 38: { # 'М' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 2, # 'А' + 32: 1, # 'Б' + 35: 2, # 'В' + 43: 0, # 'Г' + 37: 1, # 'Д' + 44: 1, # 'Е' + 55: 0, # 'Ж' + 47: 1, # 'З' + 40: 2, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 1, # 'Л' + 38: 1, # 'М' + 36: 1, # 'Н' + 41: 2, # 'О' + 30: 1, # 'П' + 39: 1, # 'Р' + 28: 2, # 'С' + 34: 1, # 'Т' + 51: 1, # 'У' + 48: 1, # 'Ф' + 49: 0, # 'Х' + 53: 1, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 1, # 'Ъ' + 60: 0, # 'Ю' + 56: 1, # 'Я' + 1: 3, # 'а' + 18: 0, # 'б' + 9: 0, # 'в' + 20: 0, # 'г' + 11: 0, # 'д' + 3: 3, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 0, # 'к' + 10: 2, # 'л' + 14: 0, # 'м' + 6: 2, # 'н' + 4: 3, # 'о' + 13: 0, # 'п' + 7: 1, # 'р' + 8: 0, # 'с' + 5: 0, # 'т' + 19: 2, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 2, # 'ъ' + 52: 1, # 'ь' + 42: 2, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 36: { # 'Н' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 2, # 'А' + 32: 2, # 'Б' + 35: 1, # 'В' + 43: 1, # 'Г' + 37: 2, # 'Д' + 44: 2, # 'Е' + 55: 1, # 'Ж' + 47: 1, # 'З' + 40: 2, # 'И' + 59: 1, # 'Й' + 33: 2, # 'К' + 46: 1, # 'Л' + 38: 1, # 'М' + 36: 1, # 'Н' + 41: 2, # 'О' + 30: 1, # 'П' + 39: 1, # 'Р' + 28: 2, # 'С' + 34: 2, # 'Т' + 51: 1, # 'У' + 48: 1, # 'Ф' + 49: 1, # 'Х' + 53: 1, # 'Ц' + 50: 1, # 'Ч' + 54: 1, # 'Ш' + 57: 0, # 'Щ' + 61: 1, # 'Ъ' + 60: 1, # 'Ю' + 56: 1, # 'Я' + 1: 3, # 'а' + 18: 0, # 'б' + 9: 0, # 'в' + 20: 1, # 'г' + 11: 0, # 'д' + 3: 3, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 0, # 'к' + 10: 0, # 'л' + 14: 0, # 'м' + 6: 0, # 'н' + 4: 3, # 'о' + 13: 0, # 'п' + 7: 0, # 'р' + 8: 0, # 'с' + 5: 1, # 'т' + 19: 1, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 1, # 'ш' + 24: 0, # 'щ' + 17: 0, # 'ъ' + 52: 0, # 'ь' + 42: 2, # 'ю' + 16: 2, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 41: { # 'О' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 1, # 'А' + 32: 1, # 'Б' + 35: 2, # 'В' + 43: 1, # 'Г' + 37: 2, # 'Д' + 44: 1, # 'Е' + 55: 1, # 'Ж' + 47: 1, # 'З' + 40: 1, # 'И' + 59: 1, # 'Й' + 33: 2, # 'К' + 46: 2, # 'Л' + 38: 2, # 'М' + 36: 2, # 'Н' + 41: 2, # 'О' + 30: 1, # 'П' + 39: 2, # 'Р' + 28: 2, # 'С' + 34: 2, # 'Т' + 51: 1, # 'У' + 48: 1, # 'Ф' + 49: 1, # 'Х' + 53: 0, # 'Ц' + 50: 1, # 'Ч' + 54: 1, # 'Ш' + 57: 1, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 1, # 'Я' + 1: 1, # 'а' + 18: 2, # 'б' + 9: 2, # 'в' + 20: 2, # 'г' + 11: 1, # 'д' + 3: 1, # 'е' + 23: 1, # 'ж' + 15: 1, # 'з' + 2: 0, # 'и' + 26: 1, # 'й' + 12: 2, # 'к' + 10: 2, # 'л' + 14: 1, # 'м' + 6: 1, # 'н' + 4: 0, # 'о' + 13: 2, # 'п' + 7: 2, # 'р' + 8: 2, # 'с' + 5: 3, # 'т' + 19: 1, # 'у' + 29: 1, # 'ф' + 25: 1, # 'х' + 22: 1, # 'ц' + 21: 2, # 'ч' + 27: 0, # 'ш' + 24: 2, # 'щ' + 17: 0, # 'ъ' + 52: 0, # 'ь' + 42: 0, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 30: { # 'П' + 63: 0, # 'e' + 45: 1, # '\xad' + 31: 2, # 'А' + 32: 1, # 'Б' + 35: 1, # 'В' + 43: 1, # 'Г' + 37: 1, # 'Д' + 44: 1, # 'Е' + 55: 0, # 'Ж' + 47: 1, # 'З' + 40: 2, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 1, # 'Л' + 38: 1, # 'М' + 36: 1, # 'Н' + 41: 2, # 'О' + 30: 2, # 'П' + 39: 2, # 'Р' + 28: 2, # 'С' + 34: 1, # 'Т' + 51: 2, # 'У' + 48: 1, # 'Ф' + 49: 0, # 'Х' + 53: 1, # 'Ц' + 50: 1, # 'Ч' + 54: 1, # 'Ш' + 57: 0, # 'Щ' + 61: 1, # 'Ъ' + 60: 1, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 0, # 'б' + 9: 0, # 'в' + 20: 0, # 'г' + 11: 2, # 'д' + 3: 3, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 2, # 'и' + 26: 0, # 'й' + 12: 1, # 'к' + 10: 3, # 'л' + 14: 0, # 'м' + 6: 1, # 'н' + 4: 3, # 'о' + 13: 0, # 'п' + 7: 3, # 'р' + 8: 1, # 'с' + 5: 1, # 'т' + 19: 2, # 'у' + 29: 1, # 'ф' + 25: 1, # 'х' + 22: 0, # 'ц' + 21: 1, # 'ч' + 27: 1, # 'ш' + 24: 0, # 'щ' + 17: 2, # 'ъ' + 52: 1, # 'ь' + 42: 1, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 39: { # 'Р' + 63: 0, # 'e' + 45: 1, # '\xad' + 31: 2, # 'А' + 32: 1, # 'Б' + 35: 1, # 'В' + 43: 2, # 'Г' + 37: 2, # 'Д' + 44: 2, # 'Е' + 55: 0, # 'Ж' + 47: 1, # 'З' + 40: 2, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 0, # 'Л' + 38: 1, # 'М' + 36: 1, # 'Н' + 41: 2, # 'О' + 30: 2, # 'П' + 39: 1, # 'Р' + 28: 1, # 'С' + 34: 1, # 'Т' + 51: 1, # 'У' + 48: 1, # 'Ф' + 49: 1, # 'Х' + 53: 1, # 'Ц' + 50: 1, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 1, # 'Ъ' + 60: 1, # 'Ю' + 56: 1, # 'Я' + 1: 3, # 'а' + 18: 0, # 'б' + 9: 0, # 'в' + 20: 0, # 'г' + 11: 0, # 'д' + 3: 2, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 2, # 'и' + 26: 0, # 'й' + 12: 0, # 'к' + 10: 0, # 'л' + 14: 0, # 'м' + 6: 1, # 'н' + 4: 3, # 'о' + 13: 0, # 'п' + 7: 0, # 'р' + 8: 1, # 'с' + 5: 0, # 'т' + 19: 3, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 1, # 'ъ' + 52: 0, # 'ь' + 42: 1, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 28: { # 'С' + 63: 1, # 'e' + 45: 0, # '\xad' + 31: 3, # 'А' + 32: 2, # 'Б' + 35: 2, # 'В' + 43: 1, # 'Г' + 37: 2, # 'Д' + 44: 2, # 'Е' + 55: 1, # 'Ж' + 47: 1, # 'З' + 40: 2, # 'И' + 59: 0, # 'Й' + 33: 2, # 'К' + 46: 1, # 'Л' + 38: 1, # 'М' + 36: 1, # 'Н' + 41: 2, # 'О' + 30: 2, # 'П' + 39: 1, # 'Р' + 28: 2, # 'С' + 34: 2, # 'Т' + 51: 1, # 'У' + 48: 1, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 1, # 'Ъ' + 60: 1, # 'Ю' + 56: 1, # 'Я' + 1: 3, # 'а' + 18: 1, # 'б' + 9: 2, # 'в' + 20: 1, # 'г' + 11: 1, # 'д' + 3: 3, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 2, # 'к' + 10: 3, # 'л' + 14: 2, # 'м' + 6: 1, # 'н' + 4: 3, # 'о' + 13: 3, # 'п' + 7: 2, # 'р' + 8: 0, # 'с' + 5: 3, # 'т' + 19: 2, # 'у' + 29: 2, # 'ф' + 25: 1, # 'х' + 22: 1, # 'ц' + 21: 1, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 3, # 'ъ' + 52: 1, # 'ь' + 42: 1, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 34: { # 'Т' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 2, # 'А' + 32: 2, # 'Б' + 35: 1, # 'В' + 43: 0, # 'Г' + 37: 1, # 'Д' + 44: 2, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 2, # 'И' + 59: 0, # 'Й' + 33: 2, # 'К' + 46: 1, # 'Л' + 38: 1, # 'М' + 36: 1, # 'Н' + 41: 2, # 'О' + 30: 1, # 'П' + 39: 2, # 'Р' + 28: 2, # 'С' + 34: 1, # 'Т' + 51: 1, # 'У' + 48: 1, # 'Ф' + 49: 0, # 'Х' + 53: 1, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 1, # 'Ъ' + 60: 0, # 'Ю' + 56: 1, # 'Я' + 1: 3, # 'а' + 18: 1, # 'б' + 9: 1, # 'в' + 20: 0, # 'г' + 11: 0, # 'д' + 3: 3, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 2, # 'и' + 26: 0, # 'й' + 12: 1, # 'к' + 10: 1, # 'л' + 14: 0, # 'м' + 6: 0, # 'н' + 4: 3, # 'о' + 13: 0, # 'п' + 7: 3, # 'р' + 8: 0, # 'с' + 5: 0, # 'т' + 19: 2, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 2, # 'ъ' + 52: 0, # 'ь' + 42: 1, # 'ю' + 16: 2, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 51: { # 'У' + 63: 0, # 'e' + 45: 1, # '\xad' + 31: 1, # 'А' + 32: 1, # 'Б' + 35: 1, # 'В' + 43: 1, # 'Г' + 37: 1, # 'Д' + 44: 2, # 'Е' + 55: 1, # 'Ж' + 47: 1, # 'З' + 40: 1, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 1, # 'Л' + 38: 1, # 'М' + 36: 1, # 'Н' + 41: 0, # 'О' + 30: 1, # 'П' + 39: 1, # 'Р' + 28: 1, # 'С' + 34: 2, # 'Т' + 51: 0, # 'У' + 48: 1, # 'Ф' + 49: 1, # 'Х' + 53: 1, # 'Ц' + 50: 1, # 'Ч' + 54: 1, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 1, # 'а' + 18: 1, # 'б' + 9: 2, # 'в' + 20: 1, # 'г' + 11: 1, # 'д' + 3: 2, # 'е' + 23: 1, # 'ж' + 15: 1, # 'з' + 2: 2, # 'и' + 26: 1, # 'й' + 12: 2, # 'к' + 10: 1, # 'л' + 14: 1, # 'м' + 6: 2, # 'н' + 4: 2, # 'о' + 13: 1, # 'п' + 7: 1, # 'р' + 8: 2, # 'с' + 5: 1, # 'т' + 19: 1, # 'у' + 29: 0, # 'ф' + 25: 1, # 'х' + 22: 0, # 'ц' + 21: 2, # 'ч' + 27: 1, # 'ш' + 24: 0, # 'щ' + 17: 1, # 'ъ' + 52: 0, # 'ь' + 42: 0, # 'ю' + 16: 0, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 48: { # 'Ф' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 2, # 'А' + 32: 1, # 'Б' + 35: 1, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 1, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 2, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 1, # 'Л' + 38: 0, # 'М' + 36: 1, # 'Н' + 41: 1, # 'О' + 30: 2, # 'П' + 39: 1, # 'Р' + 28: 2, # 'С' + 34: 1, # 'Т' + 51: 1, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 2, # 'а' + 18: 0, # 'б' + 9: 0, # 'в' + 20: 0, # 'г' + 11: 0, # 'д' + 3: 2, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 2, # 'и' + 26: 0, # 'й' + 12: 0, # 'к' + 10: 2, # 'л' + 14: 0, # 'м' + 6: 0, # 'н' + 4: 2, # 'о' + 13: 0, # 'п' + 7: 2, # 'р' + 8: 0, # 'с' + 5: 0, # 'т' + 19: 1, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 1, # 'ъ' + 52: 1, # 'ь' + 42: 1, # 'ю' + 16: 0, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 49: { # 'Х' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 1, # 'А' + 32: 0, # 'Б' + 35: 1, # 'В' + 43: 1, # 'Г' + 37: 1, # 'Д' + 44: 1, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 1, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 1, # 'Л' + 38: 1, # 'М' + 36: 1, # 'Н' + 41: 1, # 'О' + 30: 1, # 'П' + 39: 1, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 1, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 2, # 'а' + 18: 0, # 'б' + 9: 1, # 'в' + 20: 0, # 'г' + 11: 0, # 'д' + 3: 2, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 2, # 'и' + 26: 0, # 'й' + 12: 0, # 'к' + 10: 1, # 'л' + 14: 1, # 'м' + 6: 0, # 'н' + 4: 2, # 'о' + 13: 0, # 'п' + 7: 2, # 'р' + 8: 0, # 'с' + 5: 0, # 'т' + 19: 2, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 2, # 'ъ' + 52: 1, # 'ь' + 42: 1, # 'ю' + 16: 0, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 53: { # 'Ц' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 1, # 'А' + 32: 0, # 'Б' + 35: 1, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 1, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 2, # 'И' + 59: 0, # 'Й' + 33: 2, # 'К' + 46: 1, # 'Л' + 38: 1, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 1, # 'Р' + 28: 2, # 'С' + 34: 0, # 'Т' + 51: 1, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 2, # 'а' + 18: 0, # 'б' + 9: 2, # 'в' + 20: 0, # 'г' + 11: 0, # 'д' + 3: 2, # 'е' + 23: 0, # 'ж' + 15: 1, # 'з' + 2: 2, # 'и' + 26: 0, # 'й' + 12: 0, # 'к' + 10: 0, # 'л' + 14: 0, # 'м' + 6: 0, # 'н' + 4: 1, # 'о' + 13: 0, # 'п' + 7: 1, # 'р' + 8: 0, # 'с' + 5: 0, # 'т' + 19: 1, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 1, # 'ъ' + 52: 0, # 'ь' + 42: 1, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 50: { # 'Ч' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 2, # 'А' + 32: 1, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 1, # 'Е' + 55: 0, # 'Ж' + 47: 1, # 'З' + 40: 1, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 1, # 'Л' + 38: 0, # 'М' + 36: 1, # 'Н' + 41: 1, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 1, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 2, # 'а' + 18: 0, # 'б' + 9: 0, # 'в' + 20: 0, # 'г' + 11: 0, # 'д' + 3: 3, # 'е' + 23: 1, # 'ж' + 15: 0, # 'з' + 2: 2, # 'и' + 26: 0, # 'й' + 12: 0, # 'к' + 10: 1, # 'л' + 14: 0, # 'м' + 6: 0, # 'н' + 4: 2, # 'о' + 13: 0, # 'п' + 7: 1, # 'р' + 8: 0, # 'с' + 5: 0, # 'т' + 19: 2, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 1, # 'ъ' + 52: 1, # 'ь' + 42: 0, # 'ю' + 16: 0, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 54: { # 'Ш' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 1, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 1, # 'Е' + 55: 0, # 'Ж' + 47: 1, # 'З' + 40: 1, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 1, # 'Н' + 41: 1, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 1, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 2, # 'а' + 18: 0, # 'б' + 9: 2, # 'в' + 20: 0, # 'г' + 11: 0, # 'д' + 3: 2, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 2, # 'и' + 26: 0, # 'й' + 12: 1, # 'к' + 10: 1, # 'л' + 14: 1, # 'м' + 6: 1, # 'н' + 4: 2, # 'о' + 13: 1, # 'п' + 7: 1, # 'р' + 8: 0, # 'с' + 5: 0, # 'т' + 19: 2, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 1, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 1, # 'ъ' + 52: 1, # 'ь' + 42: 0, # 'ю' + 16: 0, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 57: { # 'Щ' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 1, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 1, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 1, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 1, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 2, # 'а' + 18: 0, # 'б' + 9: 0, # 'в' + 20: 0, # 'г' + 11: 0, # 'д' + 3: 2, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 1, # 'и' + 26: 0, # 'й' + 12: 0, # 'к' + 10: 0, # 'л' + 14: 0, # 'м' + 6: 0, # 'н' + 4: 1, # 'о' + 13: 0, # 'п' + 7: 1, # 'р' + 8: 0, # 'с' + 5: 0, # 'т' + 19: 1, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 1, # 'ъ' + 52: 0, # 'ь' + 42: 0, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 61: { # 'Ъ' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 1, # 'Б' + 35: 1, # 'В' + 43: 0, # 'Г' + 37: 1, # 'Д' + 44: 0, # 'Е' + 55: 1, # 'Ж' + 47: 1, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 2, # 'Л' + 38: 1, # 'М' + 36: 1, # 'Н' + 41: 0, # 'О' + 30: 1, # 'П' + 39: 2, # 'Р' + 28: 1, # 'С' + 34: 1, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 1, # 'Х' + 53: 1, # 'Ц' + 50: 1, # 'Ч' + 54: 1, # 'Ш' + 57: 1, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 0, # 'а' + 18: 0, # 'б' + 9: 0, # 'в' + 20: 0, # 'г' + 11: 0, # 'д' + 3: 0, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 0, # 'и' + 26: 0, # 'й' + 12: 0, # 'к' + 10: 1, # 'л' + 14: 0, # 'м' + 6: 1, # 'н' + 4: 0, # 'о' + 13: 0, # 'п' + 7: 1, # 'р' + 8: 0, # 'с' + 5: 0, # 'т' + 19: 0, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 0, # 'ъ' + 52: 0, # 'ь' + 42: 0, # 'ю' + 16: 0, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 60: { # 'Ю' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 1, # 'А' + 32: 1, # 'Б' + 35: 0, # 'В' + 43: 1, # 'Г' + 37: 1, # 'Д' + 44: 0, # 'Е' + 55: 1, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 1, # 'Л' + 38: 0, # 'М' + 36: 1, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 1, # 'Р' + 28: 1, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 0, # 'а' + 18: 1, # 'б' + 9: 1, # 'в' + 20: 2, # 'г' + 11: 1, # 'д' + 3: 0, # 'е' + 23: 2, # 'ж' + 15: 1, # 'з' + 2: 1, # 'и' + 26: 0, # 'й' + 12: 1, # 'к' + 10: 1, # 'л' + 14: 1, # 'м' + 6: 1, # 'н' + 4: 0, # 'о' + 13: 1, # 'п' + 7: 1, # 'р' + 8: 1, # 'с' + 5: 1, # 'т' + 19: 0, # 'у' + 29: 0, # 'ф' + 25: 1, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 0, # 'ъ' + 52: 0, # 'ь' + 42: 0, # 'ю' + 16: 0, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 56: { # 'Я' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 1, # 'Б' + 35: 1, # 'В' + 43: 1, # 'Г' + 37: 1, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 1, # 'Л' + 38: 1, # 'М' + 36: 1, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 1, # 'С' + 34: 2, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 0, # 'а' + 18: 1, # 'б' + 9: 1, # 'в' + 20: 1, # 'г' + 11: 1, # 'д' + 3: 0, # 'е' + 23: 0, # 'ж' + 15: 1, # 'з' + 2: 1, # 'и' + 26: 1, # 'й' + 12: 1, # 'к' + 10: 1, # 'л' + 14: 2, # 'м' + 6: 2, # 'н' + 4: 0, # 'о' + 13: 2, # 'п' + 7: 1, # 'р' + 8: 1, # 'с' + 5: 1, # 'т' + 19: 0, # 'у' + 29: 0, # 'ф' + 25: 1, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 1, # 'ш' + 24: 0, # 'щ' + 17: 0, # 'ъ' + 52: 0, # 'ь' + 42: 1, # 'ю' + 16: 0, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 1: { # 'а' + 63: 1, # 'e' + 45: 1, # '\xad' + 31: 1, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 1, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 1, # 'а' + 18: 3, # 'б' + 9: 3, # 'в' + 20: 3, # 'г' + 11: 3, # 'д' + 3: 3, # 'е' + 23: 3, # 'ж' + 15: 3, # 'з' + 2: 3, # 'и' + 26: 3, # 'й' + 12: 3, # 'к' + 10: 3, # 'л' + 14: 3, # 'м' + 6: 3, # 'н' + 4: 2, # 'о' + 13: 3, # 'п' + 7: 3, # 'р' + 8: 3, # 'с' + 5: 3, # 'т' + 19: 3, # 'у' + 29: 3, # 'ф' + 25: 3, # 'х' + 22: 3, # 'ц' + 21: 3, # 'ч' + 27: 3, # 'ш' + 24: 3, # 'щ' + 17: 0, # 'ъ' + 52: 0, # 'ь' + 42: 1, # 'ю' + 16: 3, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 18: { # 'б' + 63: 1, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 0, # 'б' + 9: 3, # 'в' + 20: 1, # 'г' + 11: 2, # 'д' + 3: 3, # 'е' + 23: 1, # 'ж' + 15: 1, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 1, # 'к' + 10: 3, # 'л' + 14: 2, # 'м' + 6: 3, # 'н' + 4: 3, # 'о' + 13: 1, # 'п' + 7: 3, # 'р' + 8: 3, # 'с' + 5: 0, # 'т' + 19: 3, # 'у' + 29: 0, # 'ф' + 25: 2, # 'х' + 22: 1, # 'ц' + 21: 1, # 'ч' + 27: 1, # 'ш' + 24: 3, # 'щ' + 17: 3, # 'ъ' + 52: 1, # 'ь' + 42: 2, # 'ю' + 16: 3, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 9: { # 'в' + 63: 1, # 'e' + 45: 1, # '\xad' + 31: 0, # 'А' + 32: 1, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 1, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 1, # 'б' + 9: 0, # 'в' + 20: 2, # 'г' + 11: 3, # 'д' + 3: 3, # 'е' + 23: 1, # 'ж' + 15: 3, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 3, # 'к' + 10: 3, # 'л' + 14: 2, # 'м' + 6: 3, # 'н' + 4: 3, # 'о' + 13: 2, # 'п' + 7: 3, # 'р' + 8: 3, # 'с' + 5: 3, # 'т' + 19: 2, # 'у' + 29: 0, # 'ф' + 25: 2, # 'х' + 22: 2, # 'ц' + 21: 3, # 'ч' + 27: 2, # 'ш' + 24: 1, # 'щ' + 17: 3, # 'ъ' + 52: 1, # 'ь' + 42: 2, # 'ю' + 16: 3, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 20: { # 'г' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 1, # 'б' + 9: 2, # 'в' + 20: 1, # 'г' + 11: 2, # 'д' + 3: 3, # 'е' + 23: 0, # 'ж' + 15: 1, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 1, # 'к' + 10: 3, # 'л' + 14: 1, # 'м' + 6: 3, # 'н' + 4: 3, # 'о' + 13: 1, # 'п' + 7: 3, # 'р' + 8: 2, # 'с' + 5: 2, # 'т' + 19: 3, # 'у' + 29: 1, # 'ф' + 25: 1, # 'х' + 22: 0, # 'ц' + 21: 1, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 3, # 'ъ' + 52: 1, # 'ь' + 42: 1, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 11: { # 'д' + 63: 1, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 2, # 'б' + 9: 3, # 'в' + 20: 2, # 'г' + 11: 2, # 'д' + 3: 3, # 'е' + 23: 3, # 'ж' + 15: 2, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 3, # 'к' + 10: 3, # 'л' + 14: 3, # 'м' + 6: 3, # 'н' + 4: 3, # 'о' + 13: 3, # 'п' + 7: 3, # 'р' + 8: 3, # 'с' + 5: 1, # 'т' + 19: 3, # 'у' + 29: 1, # 'ф' + 25: 2, # 'х' + 22: 2, # 'ц' + 21: 2, # 'ч' + 27: 1, # 'ш' + 24: 1, # 'щ' + 17: 3, # 'ъ' + 52: 1, # 'ь' + 42: 1, # 'ю' + 16: 3, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 3: { # 'е' + 63: 0, # 'e' + 45: 1, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 2, # 'а' + 18: 3, # 'б' + 9: 3, # 'в' + 20: 3, # 'г' + 11: 3, # 'д' + 3: 2, # 'е' + 23: 3, # 'ж' + 15: 3, # 'з' + 2: 2, # 'и' + 26: 3, # 'й' + 12: 3, # 'к' + 10: 3, # 'л' + 14: 3, # 'м' + 6: 3, # 'н' + 4: 3, # 'о' + 13: 3, # 'п' + 7: 3, # 'р' + 8: 3, # 'с' + 5: 3, # 'т' + 19: 2, # 'у' + 29: 3, # 'ф' + 25: 3, # 'х' + 22: 3, # 'ц' + 21: 3, # 'ч' + 27: 3, # 'ш' + 24: 3, # 'щ' + 17: 1, # 'ъ' + 52: 0, # 'ь' + 42: 1, # 'ю' + 16: 3, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 23: { # 'ж' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 3, # 'б' + 9: 2, # 'в' + 20: 1, # 'г' + 11: 3, # 'д' + 3: 3, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 2, # 'к' + 10: 1, # 'л' + 14: 1, # 'м' + 6: 3, # 'н' + 4: 2, # 'о' + 13: 1, # 'п' + 7: 1, # 'р' + 8: 1, # 'с' + 5: 1, # 'т' + 19: 2, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 1, # 'ц' + 21: 1, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 2, # 'ъ' + 52: 0, # 'ь' + 42: 0, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 15: { # 'з' + 63: 1, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 3, # 'б' + 9: 3, # 'в' + 20: 3, # 'г' + 11: 3, # 'д' + 3: 3, # 'е' + 23: 1, # 'ж' + 15: 1, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 3, # 'к' + 10: 3, # 'л' + 14: 3, # 'м' + 6: 3, # 'н' + 4: 3, # 'о' + 13: 3, # 'п' + 7: 3, # 'р' + 8: 3, # 'с' + 5: 3, # 'т' + 19: 3, # 'у' + 29: 1, # 'ф' + 25: 2, # 'х' + 22: 2, # 'ц' + 21: 2, # 'ч' + 27: 2, # 'ш' + 24: 1, # 'щ' + 17: 2, # 'ъ' + 52: 1, # 'ь' + 42: 1, # 'ю' + 16: 2, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 2: { # 'и' + 63: 1, # 'e' + 45: 1, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 1, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 1, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 1, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 1, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 3, # 'б' + 9: 3, # 'в' + 20: 3, # 'г' + 11: 3, # 'д' + 3: 3, # 'е' + 23: 3, # 'ж' + 15: 3, # 'з' + 2: 3, # 'и' + 26: 3, # 'й' + 12: 3, # 'к' + 10: 3, # 'л' + 14: 3, # 'м' + 6: 3, # 'н' + 4: 3, # 'о' + 13: 3, # 'п' + 7: 3, # 'р' + 8: 3, # 'с' + 5: 3, # 'т' + 19: 2, # 'у' + 29: 3, # 'ф' + 25: 3, # 'х' + 22: 3, # 'ц' + 21: 3, # 'ч' + 27: 3, # 'ш' + 24: 3, # 'щ' + 17: 2, # 'ъ' + 52: 0, # 'ь' + 42: 1, # 'ю' + 16: 3, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 26: { # 'й' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 1, # 'а' + 18: 2, # 'б' + 9: 2, # 'в' + 20: 1, # 'г' + 11: 2, # 'д' + 3: 2, # 'е' + 23: 0, # 'ж' + 15: 2, # 'з' + 2: 1, # 'и' + 26: 0, # 'й' + 12: 3, # 'к' + 10: 2, # 'л' + 14: 2, # 'м' + 6: 3, # 'н' + 4: 2, # 'о' + 13: 1, # 'п' + 7: 2, # 'р' + 8: 3, # 'с' + 5: 3, # 'т' + 19: 1, # 'у' + 29: 2, # 'ф' + 25: 1, # 'х' + 22: 2, # 'ц' + 21: 2, # 'ч' + 27: 1, # 'ш' + 24: 1, # 'щ' + 17: 1, # 'ъ' + 52: 0, # 'ь' + 42: 0, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 12: { # 'к' + 63: 1, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 1, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 1, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 1, # 'б' + 9: 3, # 'в' + 20: 2, # 'г' + 11: 1, # 'д' + 3: 3, # 'е' + 23: 0, # 'ж' + 15: 2, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 1, # 'к' + 10: 3, # 'л' + 14: 2, # 'м' + 6: 3, # 'н' + 4: 3, # 'о' + 13: 1, # 'п' + 7: 3, # 'р' + 8: 3, # 'с' + 5: 3, # 'т' + 19: 3, # 'у' + 29: 1, # 'ф' + 25: 1, # 'х' + 22: 3, # 'ц' + 21: 2, # 'ч' + 27: 1, # 'ш' + 24: 0, # 'щ' + 17: 3, # 'ъ' + 52: 1, # 'ь' + 42: 2, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 10: { # 'л' + 63: 1, # 'e' + 45: 1, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 1, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 3, # 'б' + 9: 3, # 'в' + 20: 3, # 'г' + 11: 2, # 'д' + 3: 3, # 'е' + 23: 3, # 'ж' + 15: 2, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 3, # 'к' + 10: 1, # 'л' + 14: 2, # 'м' + 6: 3, # 'н' + 4: 3, # 'о' + 13: 2, # 'п' + 7: 2, # 'р' + 8: 3, # 'с' + 5: 3, # 'т' + 19: 3, # 'у' + 29: 2, # 'ф' + 25: 2, # 'х' + 22: 2, # 'ц' + 21: 2, # 'ч' + 27: 2, # 'ш' + 24: 1, # 'щ' + 17: 3, # 'ъ' + 52: 2, # 'ь' + 42: 3, # 'ю' + 16: 3, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 14: { # 'м' + 63: 1, # 'e' + 45: 0, # '\xad' + 31: 1, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 3, # 'б' + 9: 3, # 'в' + 20: 1, # 'г' + 11: 1, # 'д' + 3: 3, # 'е' + 23: 1, # 'ж' + 15: 1, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 2, # 'к' + 10: 3, # 'л' + 14: 1, # 'м' + 6: 3, # 'н' + 4: 3, # 'о' + 13: 3, # 'п' + 7: 2, # 'р' + 8: 2, # 'с' + 5: 1, # 'т' + 19: 3, # 'у' + 29: 2, # 'ф' + 25: 1, # 'х' + 22: 2, # 'ц' + 21: 2, # 'ч' + 27: 2, # 'ш' + 24: 1, # 'щ' + 17: 3, # 'ъ' + 52: 1, # 'ь' + 42: 2, # 'ю' + 16: 3, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 6: { # 'н' + 63: 1, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 1, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 2, # 'б' + 9: 2, # 'в' + 20: 3, # 'г' + 11: 3, # 'д' + 3: 3, # 'е' + 23: 2, # 'ж' + 15: 2, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 3, # 'к' + 10: 2, # 'л' + 14: 1, # 'м' + 6: 3, # 'н' + 4: 3, # 'о' + 13: 1, # 'п' + 7: 2, # 'р' + 8: 3, # 'с' + 5: 3, # 'т' + 19: 3, # 'у' + 29: 3, # 'ф' + 25: 2, # 'х' + 22: 3, # 'ц' + 21: 3, # 'ч' + 27: 2, # 'ш' + 24: 1, # 'щ' + 17: 3, # 'ъ' + 52: 2, # 'ь' + 42: 2, # 'ю' + 16: 3, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 4: { # 'о' + 63: 0, # 'e' + 45: 1, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 2, # 'а' + 18: 3, # 'б' + 9: 3, # 'в' + 20: 3, # 'г' + 11: 3, # 'д' + 3: 3, # 'е' + 23: 3, # 'ж' + 15: 3, # 'з' + 2: 3, # 'и' + 26: 3, # 'й' + 12: 3, # 'к' + 10: 3, # 'л' + 14: 3, # 'м' + 6: 3, # 'н' + 4: 2, # 'о' + 13: 3, # 'п' + 7: 3, # 'р' + 8: 3, # 'с' + 5: 3, # 'т' + 19: 2, # 'у' + 29: 3, # 'ф' + 25: 3, # 'х' + 22: 3, # 'ц' + 21: 3, # 'ч' + 27: 3, # 'ш' + 24: 3, # 'щ' + 17: 1, # 'ъ' + 52: 0, # 'ь' + 42: 1, # 'ю' + 16: 3, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 13: { # 'п' + 63: 1, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 1, # 'б' + 9: 2, # 'в' + 20: 1, # 'г' + 11: 1, # 'д' + 3: 3, # 'е' + 23: 0, # 'ж' + 15: 1, # 'з' + 2: 3, # 'и' + 26: 1, # 'й' + 12: 2, # 'к' + 10: 3, # 'л' + 14: 1, # 'м' + 6: 2, # 'н' + 4: 3, # 'о' + 13: 1, # 'п' + 7: 3, # 'р' + 8: 2, # 'с' + 5: 2, # 'т' + 19: 3, # 'у' + 29: 1, # 'ф' + 25: 1, # 'х' + 22: 2, # 'ц' + 21: 2, # 'ч' + 27: 1, # 'ш' + 24: 1, # 'щ' + 17: 3, # 'ъ' + 52: 1, # 'ь' + 42: 2, # 'ю' + 16: 2, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 7: { # 'р' + 63: 1, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 3, # 'б' + 9: 3, # 'в' + 20: 3, # 'г' + 11: 3, # 'д' + 3: 3, # 'е' + 23: 3, # 'ж' + 15: 2, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 3, # 'к' + 10: 3, # 'л' + 14: 3, # 'м' + 6: 3, # 'н' + 4: 3, # 'о' + 13: 2, # 'п' + 7: 1, # 'р' + 8: 3, # 'с' + 5: 3, # 'т' + 19: 3, # 'у' + 29: 2, # 'ф' + 25: 3, # 'х' + 22: 3, # 'ц' + 21: 2, # 'ч' + 27: 3, # 'ш' + 24: 1, # 'щ' + 17: 3, # 'ъ' + 52: 1, # 'ь' + 42: 2, # 'ю' + 16: 3, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 8: { # 'с' + 63: 1, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 2, # 'б' + 9: 3, # 'в' + 20: 2, # 'г' + 11: 2, # 'д' + 3: 3, # 'е' + 23: 0, # 'ж' + 15: 1, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 3, # 'к' + 10: 3, # 'л' + 14: 3, # 'м' + 6: 3, # 'н' + 4: 3, # 'о' + 13: 3, # 'п' + 7: 3, # 'р' + 8: 1, # 'с' + 5: 3, # 'т' + 19: 3, # 'у' + 29: 2, # 'ф' + 25: 2, # 'х' + 22: 2, # 'ц' + 21: 2, # 'ч' + 27: 2, # 'ш' + 24: 0, # 'щ' + 17: 3, # 'ъ' + 52: 2, # 'ь' + 42: 2, # 'ю' + 16: 3, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 5: { # 'т' + 63: 1, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 3, # 'б' + 9: 3, # 'в' + 20: 2, # 'г' + 11: 2, # 'д' + 3: 3, # 'е' + 23: 1, # 'ж' + 15: 1, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 3, # 'к' + 10: 3, # 'л' + 14: 2, # 'м' + 6: 3, # 'н' + 4: 3, # 'о' + 13: 2, # 'п' + 7: 3, # 'р' + 8: 3, # 'с' + 5: 3, # 'т' + 19: 3, # 'у' + 29: 1, # 'ф' + 25: 2, # 'х' + 22: 2, # 'ц' + 21: 2, # 'ч' + 27: 1, # 'ш' + 24: 1, # 'щ' + 17: 3, # 'ъ' + 52: 2, # 'ь' + 42: 2, # 'ю' + 16: 3, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 19: { # 'у' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 3, # 'б' + 9: 3, # 'в' + 20: 3, # 'г' + 11: 3, # 'д' + 3: 2, # 'е' + 23: 3, # 'ж' + 15: 3, # 'з' + 2: 2, # 'и' + 26: 2, # 'й' + 12: 3, # 'к' + 10: 3, # 'л' + 14: 3, # 'м' + 6: 3, # 'н' + 4: 2, # 'о' + 13: 3, # 'п' + 7: 3, # 'р' + 8: 3, # 'с' + 5: 3, # 'т' + 19: 1, # 'у' + 29: 2, # 'ф' + 25: 2, # 'х' + 22: 2, # 'ц' + 21: 3, # 'ч' + 27: 3, # 'ш' + 24: 2, # 'щ' + 17: 1, # 'ъ' + 52: 0, # 'ь' + 42: 1, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 29: { # 'ф' + 63: 1, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 1, # 'б' + 9: 1, # 'в' + 20: 1, # 'г' + 11: 0, # 'д' + 3: 3, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 2, # 'к' + 10: 2, # 'л' + 14: 1, # 'м' + 6: 1, # 'н' + 4: 3, # 'о' + 13: 0, # 'п' + 7: 2, # 'р' + 8: 2, # 'с' + 5: 2, # 'т' + 19: 2, # 'у' + 29: 0, # 'ф' + 25: 1, # 'х' + 22: 0, # 'ц' + 21: 1, # 'ч' + 27: 1, # 'ш' + 24: 0, # 'щ' + 17: 2, # 'ъ' + 52: 2, # 'ь' + 42: 1, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 25: { # 'х' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 1, # 'б' + 9: 3, # 'в' + 20: 0, # 'г' + 11: 1, # 'д' + 3: 2, # 'е' + 23: 0, # 'ж' + 15: 1, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 1, # 'к' + 10: 2, # 'л' + 14: 2, # 'м' + 6: 3, # 'н' + 4: 3, # 'о' + 13: 1, # 'п' + 7: 3, # 'р' + 8: 1, # 'с' + 5: 2, # 'т' + 19: 3, # 'у' + 29: 0, # 'ф' + 25: 1, # 'х' + 22: 0, # 'ц' + 21: 1, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 2, # 'ъ' + 52: 0, # 'ь' + 42: 1, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 22: { # 'ц' + 63: 1, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 1, # 'б' + 9: 2, # 'в' + 20: 1, # 'г' + 11: 1, # 'д' + 3: 3, # 'е' + 23: 0, # 'ж' + 15: 1, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 2, # 'к' + 10: 1, # 'л' + 14: 1, # 'м' + 6: 1, # 'н' + 4: 2, # 'о' + 13: 1, # 'п' + 7: 1, # 'р' + 8: 1, # 'с' + 5: 1, # 'т' + 19: 2, # 'у' + 29: 1, # 'ф' + 25: 1, # 'х' + 22: 1, # 'ц' + 21: 1, # 'ч' + 27: 1, # 'ш' + 24: 1, # 'щ' + 17: 2, # 'ъ' + 52: 1, # 'ь' + 42: 0, # 'ю' + 16: 2, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 21: { # 'ч' + 63: 1, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 1, # 'б' + 9: 3, # 'в' + 20: 1, # 'г' + 11: 0, # 'д' + 3: 3, # 'е' + 23: 1, # 'ж' + 15: 0, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 3, # 'к' + 10: 2, # 'л' + 14: 2, # 'м' + 6: 3, # 'н' + 4: 3, # 'о' + 13: 0, # 'п' + 7: 2, # 'р' + 8: 0, # 'с' + 5: 2, # 'т' + 19: 3, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 1, # 'ш' + 24: 0, # 'щ' + 17: 2, # 'ъ' + 52: 0, # 'ь' + 42: 1, # 'ю' + 16: 0, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 27: { # 'ш' + 63: 1, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 0, # 'б' + 9: 2, # 'в' + 20: 0, # 'г' + 11: 1, # 'д' + 3: 3, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 3, # 'к' + 10: 2, # 'л' + 14: 1, # 'м' + 6: 3, # 'н' + 4: 2, # 'о' + 13: 2, # 'п' + 7: 1, # 'р' + 8: 0, # 'с' + 5: 1, # 'т' + 19: 2, # 'у' + 29: 1, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 1, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 2, # 'ъ' + 52: 1, # 'ь' + 42: 1, # 'ю' + 16: 0, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 24: { # 'щ' + 63: 1, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 3, # 'а' + 18: 0, # 'б' + 9: 1, # 'в' + 20: 0, # 'г' + 11: 0, # 'д' + 3: 3, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 3, # 'и' + 26: 0, # 'й' + 12: 1, # 'к' + 10: 0, # 'л' + 14: 0, # 'м' + 6: 2, # 'н' + 4: 3, # 'о' + 13: 0, # 'п' + 7: 1, # 'р' + 8: 0, # 'с' + 5: 2, # 'т' + 19: 3, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 1, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 1, # 'ъ' + 52: 0, # 'ь' + 42: 0, # 'ю' + 16: 2, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 17: { # 'ъ' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 1, # 'а' + 18: 3, # 'б' + 9: 3, # 'в' + 20: 3, # 'г' + 11: 3, # 'д' + 3: 2, # 'е' + 23: 3, # 'ж' + 15: 3, # 'з' + 2: 1, # 'и' + 26: 2, # 'й' + 12: 3, # 'к' + 10: 3, # 'л' + 14: 3, # 'м' + 6: 3, # 'н' + 4: 3, # 'о' + 13: 3, # 'п' + 7: 3, # 'р' + 8: 3, # 'с' + 5: 3, # 'т' + 19: 1, # 'у' + 29: 1, # 'ф' + 25: 2, # 'х' + 22: 2, # 'ц' + 21: 3, # 'ч' + 27: 2, # 'ш' + 24: 3, # 'щ' + 17: 0, # 'ъ' + 52: 0, # 'ь' + 42: 2, # 'ю' + 16: 0, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 52: { # 'ь' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 0, # 'а' + 18: 0, # 'б' + 9: 0, # 'в' + 20: 0, # 'г' + 11: 0, # 'д' + 3: 1, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 0, # 'и' + 26: 0, # 'й' + 12: 1, # 'к' + 10: 0, # 'л' + 14: 0, # 'м' + 6: 1, # 'н' + 4: 3, # 'о' + 13: 0, # 'п' + 7: 0, # 'р' + 8: 0, # 'с' + 5: 1, # 'т' + 19: 0, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 1, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 0, # 'ъ' + 52: 0, # 'ь' + 42: 1, # 'ю' + 16: 0, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 42: { # 'ю' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 1, # 'а' + 18: 2, # 'б' + 9: 1, # 'в' + 20: 2, # 'г' + 11: 2, # 'д' + 3: 1, # 'е' + 23: 2, # 'ж' + 15: 2, # 'з' + 2: 1, # 'и' + 26: 1, # 'й' + 12: 2, # 'к' + 10: 2, # 'л' + 14: 2, # 'м' + 6: 2, # 'н' + 4: 1, # 'о' + 13: 1, # 'п' + 7: 2, # 'р' + 8: 2, # 'с' + 5: 2, # 'т' + 19: 1, # 'у' + 29: 1, # 'ф' + 25: 1, # 'х' + 22: 2, # 'ц' + 21: 3, # 'ч' + 27: 1, # 'ш' + 24: 1, # 'щ' + 17: 1, # 'ъ' + 52: 0, # 'ь' + 42: 0, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 16: { # 'я' + 63: 0, # 'e' + 45: 1, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 0, # 'а' + 18: 3, # 'б' + 9: 3, # 'в' + 20: 2, # 'г' + 11: 3, # 'д' + 3: 2, # 'е' + 23: 1, # 'ж' + 15: 2, # 'з' + 2: 1, # 'и' + 26: 2, # 'й' + 12: 3, # 'к' + 10: 3, # 'л' + 14: 3, # 'м' + 6: 3, # 'н' + 4: 1, # 'о' + 13: 2, # 'п' + 7: 2, # 'р' + 8: 3, # 'с' + 5: 3, # 'т' + 19: 1, # 'у' + 29: 1, # 'ф' + 25: 3, # 'х' + 22: 2, # 'ц' + 21: 1, # 'ч' + 27: 1, # 'ш' + 24: 2, # 'щ' + 17: 0, # 'ъ' + 52: 0, # 'ь' + 42: 0, # 'ю' + 16: 1, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 58: { # 'є' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 0, # 'а' + 18: 0, # 'б' + 9: 0, # 'в' + 20: 0, # 'г' + 11: 0, # 'д' + 3: 0, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 0, # 'и' + 26: 0, # 'й' + 12: 0, # 'к' + 10: 0, # 'л' + 14: 0, # 'м' + 6: 0, # 'н' + 4: 0, # 'о' + 13: 0, # 'п' + 7: 0, # 'р' + 8: 0, # 'с' + 5: 0, # 'т' + 19: 0, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 0, # 'ъ' + 52: 0, # 'ь' + 42: 0, # 'ю' + 16: 0, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, + 62: { # '№' + 63: 0, # 'e' + 45: 0, # '\xad' + 31: 0, # 'А' + 32: 0, # 'Б' + 35: 0, # 'В' + 43: 0, # 'Г' + 37: 0, # 'Д' + 44: 0, # 'Е' + 55: 0, # 'Ж' + 47: 0, # 'З' + 40: 0, # 'И' + 59: 0, # 'Й' + 33: 0, # 'К' + 46: 0, # 'Л' + 38: 0, # 'М' + 36: 0, # 'Н' + 41: 0, # 'О' + 30: 0, # 'П' + 39: 0, # 'Р' + 28: 0, # 'С' + 34: 0, # 'Т' + 51: 0, # 'У' + 48: 0, # 'Ф' + 49: 0, # 'Х' + 53: 0, # 'Ц' + 50: 0, # 'Ч' + 54: 0, # 'Ш' + 57: 0, # 'Щ' + 61: 0, # 'Ъ' + 60: 0, # 'Ю' + 56: 0, # 'Я' + 1: 0, # 'а' + 18: 0, # 'б' + 9: 0, # 'в' + 20: 0, # 'г' + 11: 0, # 'д' + 3: 0, # 'е' + 23: 0, # 'ж' + 15: 0, # 'з' + 2: 0, # 'и' + 26: 0, # 'й' + 12: 0, # 'к' + 10: 0, # 'л' + 14: 0, # 'м' + 6: 0, # 'н' + 4: 0, # 'о' + 13: 0, # 'п' + 7: 0, # 'р' + 8: 0, # 'с' + 5: 0, # 'т' + 19: 0, # 'у' + 29: 0, # 'ф' + 25: 0, # 'х' + 22: 0, # 'ц' + 21: 0, # 'ч' + 27: 0, # 'ш' + 24: 0, # 'щ' + 17: 0, # 'ъ' + 52: 0, # 'ь' + 42: 0, # 'ю' + 16: 0, # 'я' + 58: 0, # 'є' + 62: 0, # '№' + }, +} + +# 255: Undefined characters that did not exist in training text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 +# 251: Control characters + +# Character Mapping Table(s): +ISO_8859_5_BULGARIAN_CHAR_TO_ORDER = { + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 77, # 'A' + 66: 90, # 'B' + 67: 99, # 'C' + 68: 100, # 'D' + 69: 72, # 'E' + 70: 109, # 'F' + 71: 107, # 'G' + 72: 101, # 'H' + 73: 79, # 'I' + 74: 185, # 'J' + 75: 81, # 'K' + 76: 102, # 'L' + 77: 76, # 'M' + 78: 94, # 'N' + 79: 82, # 'O' + 80: 110, # 'P' + 81: 186, # 'Q' + 82: 108, # 'R' + 83: 91, # 'S' + 84: 74, # 'T' + 85: 119, # 'U' + 86: 84, # 'V' + 87: 96, # 'W' + 88: 111, # 'X' + 89: 187, # 'Y' + 90: 115, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 65, # 'a' + 98: 69, # 'b' + 99: 70, # 'c' + 100: 66, # 'd' + 101: 63, # 'e' + 102: 68, # 'f' + 103: 112, # 'g' + 104: 103, # 'h' + 105: 92, # 'i' + 106: 194, # 'j' + 107: 104, # 'k' + 108: 95, # 'l' + 109: 86, # 'm' + 110: 87, # 'n' + 111: 71, # 'o' + 112: 116, # 'p' + 113: 195, # 'q' + 114: 85, # 'r' + 115: 93, # 's' + 116: 97, # 't' + 117: 113, # 'u' + 118: 196, # 'v' + 119: 197, # 'w' + 120: 198, # 'x' + 121: 199, # 'y' + 122: 200, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 194, # '\x80' + 129: 195, # '\x81' + 130: 196, # '\x82' + 131: 197, # '\x83' + 132: 198, # '\x84' + 133: 199, # '\x85' + 134: 200, # '\x86' + 135: 201, # '\x87' + 136: 202, # '\x88' + 137: 203, # '\x89' + 138: 204, # '\x8a' + 139: 205, # '\x8b' + 140: 206, # '\x8c' + 141: 207, # '\x8d' + 142: 208, # '\x8e' + 143: 209, # '\x8f' + 144: 210, # '\x90' + 145: 211, # '\x91' + 146: 212, # '\x92' + 147: 213, # '\x93' + 148: 214, # '\x94' + 149: 215, # '\x95' + 150: 216, # '\x96' + 151: 217, # '\x97' + 152: 218, # '\x98' + 153: 219, # '\x99' + 154: 220, # '\x9a' + 155: 221, # '\x9b' + 156: 222, # '\x9c' + 157: 223, # '\x9d' + 158: 224, # '\x9e' + 159: 225, # '\x9f' + 160: 81, # '\xa0' + 161: 226, # 'Ё' + 162: 227, # 'Ђ' + 163: 228, # 'Ѓ' + 164: 229, # 'Є' + 165: 230, # 'Ѕ' + 166: 105, # 'І' + 167: 231, # 'Ї' + 168: 232, # 'Ј' + 169: 233, # 'Љ' + 170: 234, # 'Њ' + 171: 235, # 'Ћ' + 172: 236, # 'Ќ' + 173: 45, # '\xad' + 174: 237, # 'Ў' + 175: 238, # 'Џ' + 176: 31, # 'А' + 177: 32, # 'Б' + 178: 35, # 'В' + 179: 43, # 'Г' + 180: 37, # 'Д' + 181: 44, # 'Е' + 182: 55, # 'Ж' + 183: 47, # 'З' + 184: 40, # 'И' + 185: 59, # 'Й' + 186: 33, # 'К' + 187: 46, # 'Л' + 188: 38, # 'М' + 189: 36, # 'Н' + 190: 41, # 'О' + 191: 30, # 'П' + 192: 39, # 'Р' + 193: 28, # 'С' + 194: 34, # 'Т' + 195: 51, # 'У' + 196: 48, # 'Ф' + 197: 49, # 'Х' + 198: 53, # 'Ц' + 199: 50, # 'Ч' + 200: 54, # 'Ш' + 201: 57, # 'Щ' + 202: 61, # 'Ъ' + 203: 239, # 'Ы' + 204: 67, # 'Ь' + 205: 240, # 'Э' + 206: 60, # 'Ю' + 207: 56, # 'Я' + 208: 1, # 'а' + 209: 18, # 'б' + 210: 9, # 'в' + 211: 20, # 'г' + 212: 11, # 'д' + 213: 3, # 'е' + 214: 23, # 'ж' + 215: 15, # 'з' + 216: 2, # 'и' + 217: 26, # 'й' + 218: 12, # 'к' + 219: 10, # 'л' + 220: 14, # 'м' + 221: 6, # 'н' + 222: 4, # 'о' + 223: 13, # 'п' + 224: 7, # 'р' + 225: 8, # 'с' + 226: 5, # 'т' + 227: 19, # 'у' + 228: 29, # 'ф' + 229: 25, # 'х' + 230: 22, # 'ц' + 231: 21, # 'ч' + 232: 27, # 'ш' + 233: 24, # 'щ' + 234: 17, # 'ъ' + 235: 75, # 'ы' + 236: 52, # 'ь' + 237: 241, # 'э' + 238: 42, # 'ю' + 239: 16, # 'я' + 240: 62, # '№' + 241: 242, # 'ё' + 242: 243, # 'ђ' + 243: 244, # 'ѓ' + 244: 58, # 'є' + 245: 245, # 'ѕ' + 246: 98, # 'і' + 247: 246, # 'ї' + 248: 247, # 'ј' + 249: 248, # 'љ' + 250: 249, # 'њ' + 251: 250, # 'ћ' + 252: 251, # 'ќ' + 253: 91, # '§' + 254: 252, # 'ў' + 255: 253, # 'џ' +} + +ISO_8859_5_BULGARIAN_MODEL = SingleByteCharSetModel(charset_name='ISO-8859-5', + language='Bulgarian', + char_to_order_map=ISO_8859_5_BULGARIAN_CHAR_TO_ORDER, + language_model=BULGARIAN_LANG_MODEL, + typical_positive_ratio=0.969392, + keep_ascii_letters=False, + alphabet='АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЬЮЯабвгдежзийклмнопрстуфхцчшщъьюя') + +WINDOWS_1251_BULGARIAN_CHAR_TO_ORDER = { + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 77, # 'A' + 66: 90, # 'B' + 67: 99, # 'C' + 68: 100, # 'D' + 69: 72, # 'E' + 70: 109, # 'F' + 71: 107, # 'G' + 72: 101, # 'H' + 73: 79, # 'I' + 74: 185, # 'J' + 75: 81, # 'K' + 76: 102, # 'L' + 77: 76, # 'M' + 78: 94, # 'N' + 79: 82, # 'O' + 80: 110, # 'P' + 81: 186, # 'Q' + 82: 108, # 'R' + 83: 91, # 'S' + 84: 74, # 'T' + 85: 119, # 'U' + 86: 84, # 'V' + 87: 96, # 'W' + 88: 111, # 'X' + 89: 187, # 'Y' + 90: 115, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 65, # 'a' + 98: 69, # 'b' + 99: 70, # 'c' + 100: 66, # 'd' + 101: 63, # 'e' + 102: 68, # 'f' + 103: 112, # 'g' + 104: 103, # 'h' + 105: 92, # 'i' + 106: 194, # 'j' + 107: 104, # 'k' + 108: 95, # 'l' + 109: 86, # 'm' + 110: 87, # 'n' + 111: 71, # 'o' + 112: 116, # 'p' + 113: 195, # 'q' + 114: 85, # 'r' + 115: 93, # 's' + 116: 97, # 't' + 117: 113, # 'u' + 118: 196, # 'v' + 119: 197, # 'w' + 120: 198, # 'x' + 121: 199, # 'y' + 122: 200, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 206, # 'Ђ' + 129: 207, # 'Ѓ' + 130: 208, # '‚' + 131: 209, # 'ѓ' + 132: 210, # '„' + 133: 211, # '…' + 134: 212, # '†' + 135: 213, # '‡' + 136: 120, # '€' + 137: 214, # '‰' + 138: 215, # 'Љ' + 139: 216, # '‹' + 140: 217, # 'Њ' + 141: 218, # 'Ќ' + 142: 219, # 'Ћ' + 143: 220, # 'Џ' + 144: 221, # 'ђ' + 145: 78, # '‘' + 146: 64, # '’' + 147: 83, # '“' + 148: 121, # '”' + 149: 98, # '•' + 150: 117, # '–' + 151: 105, # '—' + 152: 222, # None + 153: 223, # '™' + 154: 224, # 'љ' + 155: 225, # '›' + 156: 226, # 'њ' + 157: 227, # 'ќ' + 158: 228, # 'ћ' + 159: 229, # 'џ' + 160: 88, # '\xa0' + 161: 230, # 'Ў' + 162: 231, # 'ў' + 163: 232, # 'Ј' + 164: 233, # '¤' + 165: 122, # 'Ґ' + 166: 89, # '¦' + 167: 106, # '§' + 168: 234, # 'Ё' + 169: 235, # '©' + 170: 236, # 'Є' + 171: 237, # '«' + 172: 238, # '¬' + 173: 45, # '\xad' + 174: 239, # '®' + 175: 240, # 'Ї' + 176: 73, # '°' + 177: 80, # '±' + 178: 118, # 'І' + 179: 114, # 'і' + 180: 241, # 'ґ' + 181: 242, # 'µ' + 182: 243, # '¶' + 183: 244, # '·' + 184: 245, # 'ё' + 185: 62, # '№' + 186: 58, # 'є' + 187: 246, # '»' + 188: 247, # 'ј' + 189: 248, # 'Ѕ' + 190: 249, # 'ѕ' + 191: 250, # 'ї' + 192: 31, # 'А' + 193: 32, # 'Б' + 194: 35, # 'В' + 195: 43, # 'Г' + 196: 37, # 'Д' + 197: 44, # 'Е' + 198: 55, # 'Ж' + 199: 47, # 'З' + 200: 40, # 'И' + 201: 59, # 'Й' + 202: 33, # 'К' + 203: 46, # 'Л' + 204: 38, # 'М' + 205: 36, # 'Н' + 206: 41, # 'О' + 207: 30, # 'П' + 208: 39, # 'Р' + 209: 28, # 'С' + 210: 34, # 'Т' + 211: 51, # 'У' + 212: 48, # 'Ф' + 213: 49, # 'Х' + 214: 53, # 'Ц' + 215: 50, # 'Ч' + 216: 54, # 'Ш' + 217: 57, # 'Щ' + 218: 61, # 'Ъ' + 219: 251, # 'Ы' + 220: 67, # 'Ь' + 221: 252, # 'Э' + 222: 60, # 'Ю' + 223: 56, # 'Я' + 224: 1, # 'а' + 225: 18, # 'б' + 226: 9, # 'в' + 227: 20, # 'г' + 228: 11, # 'д' + 229: 3, # 'е' + 230: 23, # 'ж' + 231: 15, # 'з' + 232: 2, # 'и' + 233: 26, # 'й' + 234: 12, # 'к' + 235: 10, # 'л' + 236: 14, # 'м' + 237: 6, # 'н' + 238: 4, # 'о' + 239: 13, # 'п' + 240: 7, # 'р' + 241: 8, # 'с' + 242: 5, # 'т' + 243: 19, # 'у' + 244: 29, # 'ф' + 245: 25, # 'х' + 246: 22, # 'ц' + 247: 21, # 'ч' + 248: 27, # 'ш' + 249: 24, # 'щ' + 250: 17, # 'ъ' + 251: 75, # 'ы' + 252: 52, # 'ь' + 253: 253, # 'э' + 254: 42, # 'ю' + 255: 16, # 'я' +} + +WINDOWS_1251_BULGARIAN_MODEL = SingleByteCharSetModel(charset_name='windows-1251', + language='Bulgarian', + char_to_order_map=WINDOWS_1251_BULGARIAN_CHAR_TO_ORDER, + language_model=BULGARIAN_LANG_MODEL, + typical_positive_ratio=0.969392, + keep_ascii_letters=False, + alphabet='АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЬЮЯабвгдежзийклмнопрстуфхцчшщъьюя') + diff --git a/venv/lib/python3.8/site-packages/chardet/langgreekmodel.py b/venv/lib/python3.8/site-packages/chardet/langgreekmodel.py new file mode 100644 index 0000000..02b94de --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/langgreekmodel.py @@ -0,0 +1,4398 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from chardet.sbcharsetprober import SingleByteCharSetModel + + +# 3: Positive +# 2: Likely +# 1: Unlikely +# 0: Negative + +GREEK_LANG_MODEL = { + 60: { # 'e' + 60: 2, # 'e' + 55: 1, # 'o' + 58: 2, # 't' + 36: 1, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 1, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 0, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 0, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 0, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 0, # 'ο' + 9: 0, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 0, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 55: { # 'o' + 60: 0, # 'e' + 55: 2, # 'o' + 58: 2, # 't' + 36: 1, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 0, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 0, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 0, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 1, # 'ν' + 30: 0, # 'ξ' + 4: 0, # 'ο' + 9: 0, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 1, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 58: { # 't' + 60: 2, # 'e' + 55: 1, # 'o' + 58: 1, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 2, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 0, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 0, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 0, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 1, # 'ο' + 9: 0, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 0, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 36: { # '·' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 0, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 0, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 0, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 0, # 'ο' + 9: 0, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 0, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 61: { # 'Ά' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 0, # 'α' + 29: 0, # 'β' + 20: 1, # 'γ' + 21: 2, # 'δ' + 3: 0, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 0, # 'ι' + 11: 0, # 'κ' + 16: 2, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 0, # 'ο' + 9: 1, # 'π' + 8: 2, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 0, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 46: { # 'Έ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 0, # 'α' + 29: 2, # 'β' + 20: 2, # 'γ' + 21: 0, # 'δ' + 3: 0, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 0, # 'ι' + 11: 2, # 'κ' + 16: 2, # 'λ' + 10: 0, # 'μ' + 6: 3, # 'ν' + 30: 2, # 'ξ' + 4: 0, # 'ο' + 9: 2, # 'π' + 8: 2, # 'ρ' + 14: 0, # 'ς' + 7: 1, # 'σ' + 2: 2, # 'τ' + 12: 0, # 'υ' + 28: 2, # 'φ' + 23: 3, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 54: { # 'Ό' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 0, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 0, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 0, # 'ι' + 11: 0, # 'κ' + 16: 2, # 'λ' + 10: 2, # 'μ' + 6: 2, # 'ν' + 30: 0, # 'ξ' + 4: 0, # 'ο' + 9: 2, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 2, # 'σ' + 2: 3, # 'τ' + 12: 0, # 'υ' + 28: 0, # 'φ' + 23: 2, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 31: { # 'Α' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 2, # 'Β' + 43: 2, # 'Γ' + 41: 1, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 2, # 'Θ' + 47: 2, # 'Ι' + 44: 2, # 'Κ' + 53: 2, # 'Λ' + 38: 2, # 'Μ' + 49: 2, # 'Ν' + 59: 1, # 'Ξ' + 39: 0, # 'Ο' + 35: 2, # 'Π' + 48: 2, # 'Ρ' + 37: 2, # 'Σ' + 33: 2, # 'Τ' + 45: 2, # 'Υ' + 56: 2, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 0, # 'α' + 29: 0, # 'β' + 20: 2, # 'γ' + 21: 0, # 'δ' + 3: 0, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 1, # 'θ' + 5: 0, # 'ι' + 11: 2, # 'κ' + 16: 3, # 'λ' + 10: 2, # 'μ' + 6: 3, # 'ν' + 30: 2, # 'ξ' + 4: 0, # 'ο' + 9: 3, # 'π' + 8: 3, # 'ρ' + 14: 2, # 'ς' + 7: 2, # 'σ' + 2: 0, # 'τ' + 12: 3, # 'υ' + 28: 2, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 2, # 'ύ' + 27: 0, # 'ώ' + }, + 51: { # 'Β' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 2, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 1, # 'Ε' + 40: 1, # 'Η' + 52: 0, # 'Θ' + 47: 1, # 'Ι' + 44: 0, # 'Κ' + 53: 1, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 2, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 2, # 'ά' + 18: 2, # 'έ' + 22: 2, # 'ή' + 15: 0, # 'ί' + 1: 2, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 2, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 2, # 'ι' + 11: 0, # 'κ' + 16: 2, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 2, # 'ο' + 9: 0, # 'π' + 8: 2, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 0, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 43: { # 'Γ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 1, # 'Α' + 51: 0, # 'Β' + 43: 2, # 'Γ' + 41: 0, # 'Δ' + 34: 2, # 'Ε' + 40: 1, # 'Η' + 52: 0, # 'Θ' + 47: 2, # 'Ι' + 44: 1, # 'Κ' + 53: 1, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 1, # 'Ο' + 35: 0, # 'Π' + 48: 2, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 2, # 'Υ' + 56: 0, # 'Φ' + 50: 1, # 'Χ' + 57: 2, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 2, # 'ί' + 1: 2, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 2, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 3, # 'ι' + 11: 0, # 'κ' + 16: 2, # 'λ' + 10: 0, # 'μ' + 6: 2, # 'ν' + 30: 0, # 'ξ' + 4: 0, # 'ο' + 9: 0, # 'π' + 8: 2, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 0, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 41: { # 'Δ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 2, # 'Ε' + 40: 2, # 'Η' + 52: 0, # 'Θ' + 47: 2, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 2, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 2, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 2, # 'ή' + 15: 2, # 'ί' + 1: 0, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 2, # 'η' + 25: 0, # 'θ' + 5: 3, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 2, # 'ο' + 9: 0, # 'π' + 8: 2, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 2, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 2, # 'ω' + 19: 1, # 'ό' + 26: 2, # 'ύ' + 27: 2, # 'ώ' + }, + 34: { # 'Ε' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 2, # 'Α' + 51: 0, # 'Β' + 43: 2, # 'Γ' + 41: 2, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 2, # 'Ι' + 44: 2, # 'Κ' + 53: 2, # 'Λ' + 38: 2, # 'Μ' + 49: 2, # 'Ν' + 59: 1, # 'Ξ' + 39: 0, # 'Ο' + 35: 2, # 'Π' + 48: 2, # 'Ρ' + 37: 2, # 'Σ' + 33: 2, # 'Τ' + 45: 2, # 'Υ' + 56: 0, # 'Φ' + 50: 2, # 'Χ' + 57: 2, # 'Ω' + 17: 3, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 3, # 'ί' + 1: 0, # 'α' + 29: 0, # 'β' + 20: 3, # 'γ' + 21: 2, # 'δ' + 3: 1, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 1, # 'θ' + 5: 2, # 'ι' + 11: 3, # 'κ' + 16: 3, # 'λ' + 10: 2, # 'μ' + 6: 3, # 'ν' + 30: 2, # 'ξ' + 4: 0, # 'ο' + 9: 3, # 'π' + 8: 2, # 'ρ' + 14: 0, # 'ς' + 7: 2, # 'σ' + 2: 2, # 'τ' + 12: 2, # 'υ' + 28: 2, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 1, # 'ύ' + 27: 0, # 'ώ' + }, + 40: { # 'Η' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 1, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 2, # 'Θ' + 47: 0, # 'Ι' + 44: 2, # 'Κ' + 53: 0, # 'Λ' + 38: 2, # 'Μ' + 49: 2, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 2, # 'Π' + 48: 2, # 'Ρ' + 37: 2, # 'Σ' + 33: 2, # 'Τ' + 45: 1, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 0, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 0, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 0, # 'ι' + 11: 0, # 'κ' + 16: 2, # 'λ' + 10: 0, # 'μ' + 6: 1, # 'ν' + 30: 0, # 'ξ' + 4: 0, # 'ο' + 9: 0, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 0, # 'υ' + 28: 0, # 'φ' + 23: 1, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 52: { # 'Θ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 2, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 2, # 'Ε' + 40: 2, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 2, # 'Ο' + 35: 0, # 'Π' + 48: 1, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 1, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 2, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 3, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 2, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 0, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 0, # 'ο' + 9: 0, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 2, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 2, # 'ύ' + 27: 0, # 'ώ' + }, + 47: { # 'Ι' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 2, # 'Α' + 51: 1, # 'Β' + 43: 1, # 'Γ' + 41: 2, # 'Δ' + 34: 2, # 'Ε' + 40: 2, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 2, # 'Κ' + 53: 2, # 'Λ' + 38: 2, # 'Μ' + 49: 2, # 'Ν' + 59: 0, # 'Ξ' + 39: 2, # 'Ο' + 35: 0, # 'Π' + 48: 2, # 'Ρ' + 37: 2, # 'Σ' + 33: 2, # 'Τ' + 45: 0, # 'Υ' + 56: 2, # 'Φ' + 50: 0, # 'Χ' + 57: 2, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 2, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 2, # 'δ' + 3: 0, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 0, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 1, # 'ν' + 30: 0, # 'ξ' + 4: 2, # 'ο' + 9: 0, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 2, # 'σ' + 2: 1, # 'τ' + 12: 0, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 1, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 44: { # 'Κ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 2, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 1, # 'Δ' + 34: 2, # 'Ε' + 40: 2, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 1, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 2, # 'Ο' + 35: 0, # 'Π' + 48: 2, # 'Ρ' + 37: 0, # 'Σ' + 33: 1, # 'Τ' + 45: 2, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 1, # 'Ω' + 17: 3, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 3, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 2, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 2, # 'ι' + 11: 0, # 'κ' + 16: 2, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 2, # 'ο' + 9: 0, # 'π' + 8: 2, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 2, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 2, # 'ό' + 26: 2, # 'ύ' + 27: 2, # 'ώ' + }, + 53: { # 'Λ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 2, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 2, # 'Ε' + 40: 2, # 'Η' + 52: 0, # 'Θ' + 47: 2, # 'Ι' + 44: 0, # 'Κ' + 53: 2, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 2, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 2, # 'Σ' + 33: 0, # 'Τ' + 45: 2, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 2, # 'Ω' + 17: 2, # 'ά' + 18: 2, # 'έ' + 22: 0, # 'ή' + 15: 2, # 'ί' + 1: 2, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 2, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 1, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 2, # 'ο' + 9: 0, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 2, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 2, # 'ό' + 26: 2, # 'ύ' + 27: 0, # 'ώ' + }, + 38: { # 'Μ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 2, # 'Α' + 51: 2, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 2, # 'Ε' + 40: 2, # 'Η' + 52: 0, # 'Θ' + 47: 2, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 2, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 2, # 'Ο' + 35: 2, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 2, # 'ά' + 18: 2, # 'έ' + 22: 2, # 'ή' + 15: 2, # 'ί' + 1: 2, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 2, # 'η' + 25: 0, # 'θ' + 5: 3, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 2, # 'ο' + 9: 3, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 2, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 2, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 49: { # 'Ν' + 60: 2, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 2, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 2, # 'Ε' + 40: 2, # 'Η' + 52: 0, # 'Θ' + 47: 2, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 2, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 2, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 2, # 'Ω' + 17: 0, # 'ά' + 18: 2, # 'έ' + 22: 0, # 'ή' + 15: 2, # 'ί' + 1: 2, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 1, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 0, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 2, # 'ο' + 9: 0, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 0, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 1, # 'ω' + 19: 2, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 59: { # 'Ξ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 1, # 'Ε' + 40: 1, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 1, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 2, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 2, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 2, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 0, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 0, # 'ο' + 9: 0, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 0, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 39: { # 'Ο' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 1, # 'Β' + 43: 2, # 'Γ' + 41: 2, # 'Δ' + 34: 2, # 'Ε' + 40: 1, # 'Η' + 52: 2, # 'Θ' + 47: 2, # 'Ι' + 44: 2, # 'Κ' + 53: 2, # 'Λ' + 38: 2, # 'Μ' + 49: 2, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 2, # 'Π' + 48: 2, # 'Ρ' + 37: 2, # 'Σ' + 33: 2, # 'Τ' + 45: 2, # 'Υ' + 56: 2, # 'Φ' + 50: 2, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 0, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 2, # 'δ' + 3: 0, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 3, # 'ι' + 11: 2, # 'κ' + 16: 2, # 'λ' + 10: 2, # 'μ' + 6: 2, # 'ν' + 30: 0, # 'ξ' + 4: 0, # 'ο' + 9: 2, # 'π' + 8: 2, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 2, # 'τ' + 12: 2, # 'υ' + 28: 1, # 'φ' + 23: 1, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 2, # 'ύ' + 27: 0, # 'ώ' + }, + 35: { # 'Π' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 2, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 2, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 2, # 'Ι' + 44: 0, # 'Κ' + 53: 2, # 'Λ' + 38: 1, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 2, # 'Ο' + 35: 0, # 'Π' + 48: 2, # 'Ρ' + 37: 0, # 'Σ' + 33: 1, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 1, # 'Χ' + 57: 2, # 'Ω' + 17: 2, # 'ά' + 18: 1, # 'έ' + 22: 1, # 'ή' + 15: 2, # 'ί' + 1: 3, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 2, # 'η' + 25: 0, # 'θ' + 5: 2, # 'ι' + 11: 0, # 'κ' + 16: 2, # 'λ' + 10: 0, # 'μ' + 6: 2, # 'ν' + 30: 0, # 'ξ' + 4: 3, # 'ο' + 9: 0, # 'π' + 8: 3, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 2, # 'υ' + 28: 0, # 'φ' + 23: 2, # 'χ' + 42: 0, # 'ψ' + 24: 2, # 'ω' + 19: 2, # 'ό' + 26: 0, # 'ύ' + 27: 3, # 'ώ' + }, + 48: { # 'Ρ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 2, # 'Α' + 51: 0, # 'Β' + 43: 1, # 'Γ' + 41: 1, # 'Δ' + 34: 2, # 'Ε' + 40: 2, # 'Η' + 52: 0, # 'Θ' + 47: 2, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 2, # 'Ν' + 59: 0, # 'Ξ' + 39: 2, # 'Ο' + 35: 0, # 'Π' + 48: 2, # 'Ρ' + 37: 0, # 'Σ' + 33: 1, # 'Τ' + 45: 1, # 'Υ' + 56: 0, # 'Φ' + 50: 1, # 'Χ' + 57: 1, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 2, # 'ί' + 1: 0, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 0, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 0, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 1, # 'ο' + 9: 0, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 3, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 2, # 'ω' + 19: 0, # 'ό' + 26: 2, # 'ύ' + 27: 0, # 'ώ' + }, + 37: { # 'Σ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 2, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 1, # 'Δ' + 34: 2, # 'Ε' + 40: 2, # 'Η' + 52: 0, # 'Θ' + 47: 2, # 'Ι' + 44: 2, # 'Κ' + 53: 0, # 'Λ' + 38: 2, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 2, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 2, # 'Σ' + 33: 2, # 'Τ' + 45: 2, # 'Υ' + 56: 0, # 'Φ' + 50: 2, # 'Χ' + 57: 2, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 2, # 'ή' + 15: 2, # 'ί' + 1: 2, # 'α' + 29: 2, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 3, # 'η' + 25: 0, # 'θ' + 5: 2, # 'ι' + 11: 2, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 2, # 'ο' + 9: 2, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 3, # 'τ' + 12: 3, # 'υ' + 28: 0, # 'φ' + 23: 2, # 'χ' + 42: 0, # 'ψ' + 24: 2, # 'ω' + 19: 0, # 'ό' + 26: 2, # 'ύ' + 27: 2, # 'ώ' + }, + 33: { # 'Τ' + 60: 0, # 'e' + 55: 1, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 2, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 2, # 'Ε' + 40: 2, # 'Η' + 52: 0, # 'Θ' + 47: 2, # 'Ι' + 44: 2, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 2, # 'Ο' + 35: 0, # 'Π' + 48: 2, # 'Ρ' + 37: 0, # 'Σ' + 33: 1, # 'Τ' + 45: 1, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 2, # 'Ω' + 17: 2, # 'ά' + 18: 2, # 'έ' + 22: 0, # 'ή' + 15: 2, # 'ί' + 1: 3, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 2, # 'ε' + 32: 0, # 'ζ' + 13: 2, # 'η' + 25: 0, # 'θ' + 5: 2, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 2, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 3, # 'ο' + 9: 0, # 'π' + 8: 2, # 'ρ' + 14: 0, # 'ς' + 7: 2, # 'σ' + 2: 0, # 'τ' + 12: 2, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 2, # 'ό' + 26: 2, # 'ύ' + 27: 3, # 'ώ' + }, + 45: { # 'Υ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 2, # 'Γ' + 41: 0, # 'Δ' + 34: 1, # 'Ε' + 40: 2, # 'Η' + 52: 2, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 1, # 'Λ' + 38: 2, # 'Μ' + 49: 2, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 2, # 'Π' + 48: 1, # 'Ρ' + 37: 2, # 'Σ' + 33: 2, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 1, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 0, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 0, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 0, # 'ι' + 11: 0, # 'κ' + 16: 2, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 0, # 'ο' + 9: 3, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 0, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 56: { # 'Φ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 1, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 1, # 'Η' + 52: 0, # 'Θ' + 47: 2, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 2, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 2, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 2, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 2, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 2, # 'ο' + 9: 0, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 2, # 'τ' + 12: 2, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 1, # 'ύ' + 27: 1, # 'ώ' + }, + 50: { # 'Χ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 1, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 2, # 'Ε' + 40: 2, # 'Η' + 52: 0, # 'Θ' + 47: 2, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 1, # 'Ν' + 59: 0, # 'Ξ' + 39: 1, # 'Ο' + 35: 0, # 'Π' + 48: 2, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 1, # 'Χ' + 57: 1, # 'Ω' + 17: 2, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 2, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 2, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 0, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 2, # 'ο' + 9: 0, # 'π' + 8: 3, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 2, # 'τ' + 12: 0, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 2, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 57: { # 'Ω' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 1, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 1, # 'Λ' + 38: 0, # 'Μ' + 49: 2, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 2, # 'Ρ' + 37: 2, # 'Σ' + 33: 2, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 0, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 0, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 0, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 0, # 'ο' + 9: 0, # 'π' + 8: 2, # 'ρ' + 14: 2, # 'ς' + 7: 2, # 'σ' + 2: 0, # 'τ' + 12: 0, # 'υ' + 28: 0, # 'φ' + 23: 1, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 17: { # 'ά' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 2, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 0, # 'α' + 29: 3, # 'β' + 20: 3, # 'γ' + 21: 3, # 'δ' + 3: 3, # 'ε' + 32: 3, # 'ζ' + 13: 0, # 'η' + 25: 3, # 'θ' + 5: 2, # 'ι' + 11: 3, # 'κ' + 16: 3, # 'λ' + 10: 3, # 'μ' + 6: 3, # 'ν' + 30: 3, # 'ξ' + 4: 0, # 'ο' + 9: 3, # 'π' + 8: 3, # 'ρ' + 14: 3, # 'ς' + 7: 3, # 'σ' + 2: 3, # 'τ' + 12: 0, # 'υ' + 28: 3, # 'φ' + 23: 3, # 'χ' + 42: 3, # 'ψ' + 24: 2, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 18: { # 'έ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 3, # 'α' + 29: 2, # 'β' + 20: 3, # 'γ' + 21: 2, # 'δ' + 3: 3, # 'ε' + 32: 2, # 'ζ' + 13: 0, # 'η' + 25: 3, # 'θ' + 5: 0, # 'ι' + 11: 3, # 'κ' + 16: 3, # 'λ' + 10: 3, # 'μ' + 6: 3, # 'ν' + 30: 3, # 'ξ' + 4: 3, # 'ο' + 9: 3, # 'π' + 8: 3, # 'ρ' + 14: 3, # 'ς' + 7: 3, # 'σ' + 2: 3, # 'τ' + 12: 0, # 'υ' + 28: 3, # 'φ' + 23: 3, # 'χ' + 42: 3, # 'ψ' + 24: 2, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 22: { # 'ή' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 1, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 0, # 'α' + 29: 0, # 'β' + 20: 3, # 'γ' + 21: 3, # 'δ' + 3: 0, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 3, # 'θ' + 5: 0, # 'ι' + 11: 3, # 'κ' + 16: 2, # 'λ' + 10: 3, # 'μ' + 6: 3, # 'ν' + 30: 2, # 'ξ' + 4: 0, # 'ο' + 9: 3, # 'π' + 8: 3, # 'ρ' + 14: 3, # 'ς' + 7: 3, # 'σ' + 2: 3, # 'τ' + 12: 0, # 'υ' + 28: 2, # 'φ' + 23: 3, # 'χ' + 42: 2, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 15: { # 'ί' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 3, # 'α' + 29: 2, # 'β' + 20: 3, # 'γ' + 21: 3, # 'δ' + 3: 3, # 'ε' + 32: 3, # 'ζ' + 13: 3, # 'η' + 25: 3, # 'θ' + 5: 0, # 'ι' + 11: 3, # 'κ' + 16: 3, # 'λ' + 10: 3, # 'μ' + 6: 3, # 'ν' + 30: 3, # 'ξ' + 4: 3, # 'ο' + 9: 3, # 'π' + 8: 3, # 'ρ' + 14: 3, # 'ς' + 7: 3, # 'σ' + 2: 3, # 'τ' + 12: 0, # 'υ' + 28: 1, # 'φ' + 23: 3, # 'χ' + 42: 2, # 'ψ' + 24: 3, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 1: { # 'α' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 2, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 2, # 'έ' + 22: 0, # 'ή' + 15: 3, # 'ί' + 1: 0, # 'α' + 29: 3, # 'β' + 20: 3, # 'γ' + 21: 3, # 'δ' + 3: 2, # 'ε' + 32: 3, # 'ζ' + 13: 1, # 'η' + 25: 3, # 'θ' + 5: 3, # 'ι' + 11: 3, # 'κ' + 16: 3, # 'λ' + 10: 3, # 'μ' + 6: 3, # 'ν' + 30: 3, # 'ξ' + 4: 2, # 'ο' + 9: 3, # 'π' + 8: 3, # 'ρ' + 14: 3, # 'ς' + 7: 3, # 'σ' + 2: 3, # 'τ' + 12: 3, # 'υ' + 28: 3, # 'φ' + 23: 3, # 'χ' + 42: 2, # 'ψ' + 24: 0, # 'ω' + 19: 2, # 'ό' + 26: 2, # 'ύ' + 27: 0, # 'ώ' + }, + 29: { # 'β' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 3, # 'ά' + 18: 2, # 'έ' + 22: 3, # 'ή' + 15: 2, # 'ί' + 1: 3, # 'α' + 29: 0, # 'β' + 20: 2, # 'γ' + 21: 2, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 2, # 'η' + 25: 0, # 'θ' + 5: 3, # 'ι' + 11: 0, # 'κ' + 16: 3, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 3, # 'ο' + 9: 0, # 'π' + 8: 3, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 0, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 2, # 'ω' + 19: 2, # 'ό' + 26: 2, # 'ύ' + 27: 2, # 'ώ' + }, + 20: { # 'γ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 3, # 'ά' + 18: 3, # 'έ' + 22: 3, # 'ή' + 15: 3, # 'ί' + 1: 3, # 'α' + 29: 0, # 'β' + 20: 3, # 'γ' + 21: 0, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 3, # 'η' + 25: 0, # 'θ' + 5: 3, # 'ι' + 11: 3, # 'κ' + 16: 3, # 'λ' + 10: 3, # 'μ' + 6: 3, # 'ν' + 30: 3, # 'ξ' + 4: 3, # 'ο' + 9: 0, # 'π' + 8: 3, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 2, # 'υ' + 28: 0, # 'φ' + 23: 3, # 'χ' + 42: 0, # 'ψ' + 24: 3, # 'ω' + 19: 3, # 'ό' + 26: 2, # 'ύ' + 27: 3, # 'ώ' + }, + 21: { # 'δ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 2, # 'ά' + 18: 3, # 'έ' + 22: 3, # 'ή' + 15: 3, # 'ί' + 1: 3, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 3, # 'η' + 25: 0, # 'θ' + 5: 3, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 3, # 'ο' + 9: 0, # 'π' + 8: 3, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 3, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 3, # 'ω' + 19: 3, # 'ό' + 26: 3, # 'ύ' + 27: 3, # 'ώ' + }, + 3: { # 'ε' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 2, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 3, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 3, # 'ί' + 1: 2, # 'α' + 29: 3, # 'β' + 20: 3, # 'γ' + 21: 3, # 'δ' + 3: 2, # 'ε' + 32: 2, # 'ζ' + 13: 0, # 'η' + 25: 3, # 'θ' + 5: 3, # 'ι' + 11: 3, # 'κ' + 16: 3, # 'λ' + 10: 3, # 'μ' + 6: 3, # 'ν' + 30: 3, # 'ξ' + 4: 2, # 'ο' + 9: 3, # 'π' + 8: 3, # 'ρ' + 14: 3, # 'ς' + 7: 3, # 'σ' + 2: 3, # 'τ' + 12: 3, # 'υ' + 28: 3, # 'φ' + 23: 3, # 'χ' + 42: 2, # 'ψ' + 24: 3, # 'ω' + 19: 2, # 'ό' + 26: 3, # 'ύ' + 27: 2, # 'ώ' + }, + 32: { # 'ζ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 2, # 'ά' + 18: 2, # 'έ' + 22: 2, # 'ή' + 15: 2, # 'ί' + 1: 2, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 3, # 'η' + 25: 0, # 'θ' + 5: 2, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 3, # 'ο' + 9: 0, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 1, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 3, # 'ω' + 19: 2, # 'ό' + 26: 0, # 'ύ' + 27: 2, # 'ώ' + }, + 13: { # 'η' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 2, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 0, # 'α' + 29: 0, # 'β' + 20: 3, # 'γ' + 21: 2, # 'δ' + 3: 0, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 3, # 'θ' + 5: 0, # 'ι' + 11: 3, # 'κ' + 16: 3, # 'λ' + 10: 3, # 'μ' + 6: 3, # 'ν' + 30: 2, # 'ξ' + 4: 0, # 'ο' + 9: 2, # 'π' + 8: 3, # 'ρ' + 14: 3, # 'ς' + 7: 3, # 'σ' + 2: 3, # 'τ' + 12: 0, # 'υ' + 28: 2, # 'φ' + 23: 3, # 'χ' + 42: 2, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 25: { # 'θ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 2, # 'ά' + 18: 3, # 'έ' + 22: 3, # 'ή' + 15: 2, # 'ί' + 1: 3, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 3, # 'η' + 25: 0, # 'θ' + 5: 3, # 'ι' + 11: 0, # 'κ' + 16: 1, # 'λ' + 10: 3, # 'μ' + 6: 2, # 'ν' + 30: 0, # 'ξ' + 4: 3, # 'ο' + 9: 0, # 'π' + 8: 3, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 3, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 3, # 'ω' + 19: 3, # 'ό' + 26: 3, # 'ύ' + 27: 3, # 'ώ' + }, + 5: { # 'ι' + 60: 0, # 'e' + 55: 1, # 'o' + 58: 0, # 't' + 36: 2, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 1, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 3, # 'ά' + 18: 3, # 'έ' + 22: 3, # 'ή' + 15: 0, # 'ί' + 1: 3, # 'α' + 29: 3, # 'β' + 20: 3, # 'γ' + 21: 3, # 'δ' + 3: 3, # 'ε' + 32: 2, # 'ζ' + 13: 3, # 'η' + 25: 3, # 'θ' + 5: 0, # 'ι' + 11: 3, # 'κ' + 16: 3, # 'λ' + 10: 3, # 'μ' + 6: 3, # 'ν' + 30: 3, # 'ξ' + 4: 3, # 'ο' + 9: 3, # 'π' + 8: 3, # 'ρ' + 14: 3, # 'ς' + 7: 3, # 'σ' + 2: 3, # 'τ' + 12: 0, # 'υ' + 28: 2, # 'φ' + 23: 3, # 'χ' + 42: 2, # 'ψ' + 24: 3, # 'ω' + 19: 3, # 'ό' + 26: 0, # 'ύ' + 27: 3, # 'ώ' + }, + 11: { # 'κ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 3, # 'ά' + 18: 3, # 'έ' + 22: 3, # 'ή' + 15: 3, # 'ί' + 1: 3, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 3, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 3, # 'η' + 25: 2, # 'θ' + 5: 3, # 'ι' + 11: 3, # 'κ' + 16: 3, # 'λ' + 10: 3, # 'μ' + 6: 2, # 'ν' + 30: 0, # 'ξ' + 4: 3, # 'ο' + 9: 2, # 'π' + 8: 3, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 3, # 'τ' + 12: 3, # 'υ' + 28: 2, # 'φ' + 23: 2, # 'χ' + 42: 0, # 'ψ' + 24: 3, # 'ω' + 19: 3, # 'ό' + 26: 3, # 'ύ' + 27: 3, # 'ώ' + }, + 16: { # 'λ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 3, # 'ά' + 18: 3, # 'έ' + 22: 3, # 'ή' + 15: 3, # 'ί' + 1: 3, # 'α' + 29: 1, # 'β' + 20: 2, # 'γ' + 21: 1, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 3, # 'η' + 25: 2, # 'θ' + 5: 3, # 'ι' + 11: 2, # 'κ' + 16: 3, # 'λ' + 10: 2, # 'μ' + 6: 2, # 'ν' + 30: 0, # 'ξ' + 4: 3, # 'ο' + 9: 3, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 3, # 'τ' + 12: 3, # 'υ' + 28: 2, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 3, # 'ω' + 19: 3, # 'ό' + 26: 3, # 'ύ' + 27: 3, # 'ώ' + }, + 10: { # 'μ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 1, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 3, # 'ά' + 18: 3, # 'έ' + 22: 3, # 'ή' + 15: 3, # 'ί' + 1: 3, # 'α' + 29: 3, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 3, # 'η' + 25: 0, # 'θ' + 5: 3, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 3, # 'μ' + 6: 3, # 'ν' + 30: 0, # 'ξ' + 4: 3, # 'ο' + 9: 3, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 2, # 'υ' + 28: 3, # 'φ' + 23: 0, # 'χ' + 42: 2, # 'ψ' + 24: 3, # 'ω' + 19: 3, # 'ό' + 26: 2, # 'ύ' + 27: 2, # 'ώ' + }, + 6: { # 'ν' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 2, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 3, # 'ά' + 18: 3, # 'έ' + 22: 3, # 'ή' + 15: 3, # 'ί' + 1: 3, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 3, # 'δ' + 3: 3, # 'ε' + 32: 2, # 'ζ' + 13: 3, # 'η' + 25: 3, # 'θ' + 5: 3, # 'ι' + 11: 0, # 'κ' + 16: 1, # 'λ' + 10: 0, # 'μ' + 6: 2, # 'ν' + 30: 0, # 'ξ' + 4: 3, # 'ο' + 9: 0, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 3, # 'σ' + 2: 3, # 'τ' + 12: 3, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 3, # 'ω' + 19: 3, # 'ό' + 26: 3, # 'ύ' + 27: 3, # 'ώ' + }, + 30: { # 'ξ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 2, # 'ά' + 18: 3, # 'έ' + 22: 3, # 'ή' + 15: 2, # 'ί' + 1: 3, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 3, # 'η' + 25: 0, # 'θ' + 5: 2, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 3, # 'ο' + 9: 0, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 3, # 'τ' + 12: 2, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 3, # 'ω' + 19: 2, # 'ό' + 26: 3, # 'ύ' + 27: 1, # 'ώ' + }, + 4: { # 'ο' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 2, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 2, # 'έ' + 22: 3, # 'ή' + 15: 3, # 'ί' + 1: 2, # 'α' + 29: 3, # 'β' + 20: 3, # 'γ' + 21: 3, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 3, # 'η' + 25: 3, # 'θ' + 5: 3, # 'ι' + 11: 3, # 'κ' + 16: 3, # 'λ' + 10: 3, # 'μ' + 6: 3, # 'ν' + 30: 2, # 'ξ' + 4: 2, # 'ο' + 9: 3, # 'π' + 8: 3, # 'ρ' + 14: 3, # 'ς' + 7: 3, # 'σ' + 2: 3, # 'τ' + 12: 3, # 'υ' + 28: 3, # 'φ' + 23: 3, # 'χ' + 42: 2, # 'ψ' + 24: 2, # 'ω' + 19: 1, # 'ό' + 26: 3, # 'ύ' + 27: 2, # 'ώ' + }, + 9: { # 'π' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 3, # 'ά' + 18: 3, # 'έ' + 22: 3, # 'ή' + 15: 3, # 'ί' + 1: 3, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 3, # 'η' + 25: 0, # 'θ' + 5: 3, # 'ι' + 11: 0, # 'κ' + 16: 3, # 'λ' + 10: 0, # 'μ' + 6: 2, # 'ν' + 30: 0, # 'ξ' + 4: 3, # 'ο' + 9: 0, # 'π' + 8: 3, # 'ρ' + 14: 2, # 'ς' + 7: 0, # 'σ' + 2: 3, # 'τ' + 12: 3, # 'υ' + 28: 0, # 'φ' + 23: 2, # 'χ' + 42: 0, # 'ψ' + 24: 3, # 'ω' + 19: 3, # 'ό' + 26: 2, # 'ύ' + 27: 3, # 'ώ' + }, + 8: { # 'ρ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 3, # 'ά' + 18: 3, # 'έ' + 22: 3, # 'ή' + 15: 3, # 'ί' + 1: 3, # 'α' + 29: 2, # 'β' + 20: 3, # 'γ' + 21: 2, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 3, # 'η' + 25: 3, # 'θ' + 5: 3, # 'ι' + 11: 3, # 'κ' + 16: 1, # 'λ' + 10: 3, # 'μ' + 6: 3, # 'ν' + 30: 2, # 'ξ' + 4: 3, # 'ο' + 9: 2, # 'π' + 8: 2, # 'ρ' + 14: 0, # 'ς' + 7: 2, # 'σ' + 2: 3, # 'τ' + 12: 3, # 'υ' + 28: 3, # 'φ' + 23: 3, # 'χ' + 42: 0, # 'ψ' + 24: 3, # 'ω' + 19: 3, # 'ό' + 26: 3, # 'ύ' + 27: 3, # 'ώ' + }, + 14: { # 'ς' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 2, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 0, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 0, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 0, # 'θ' + 5: 0, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 0, # 'ο' + 9: 0, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 0, # 'τ' + 12: 0, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 7: { # 'σ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 2, # 'ά' + 18: 2, # 'έ' + 22: 3, # 'ή' + 15: 3, # 'ί' + 1: 3, # 'α' + 29: 3, # 'β' + 20: 0, # 'γ' + 21: 2, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 3, # 'η' + 25: 3, # 'θ' + 5: 3, # 'ι' + 11: 3, # 'κ' + 16: 2, # 'λ' + 10: 3, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 3, # 'ο' + 9: 3, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 3, # 'σ' + 2: 3, # 'τ' + 12: 3, # 'υ' + 28: 3, # 'φ' + 23: 3, # 'χ' + 42: 0, # 'ψ' + 24: 3, # 'ω' + 19: 3, # 'ό' + 26: 3, # 'ύ' + 27: 2, # 'ώ' + }, + 2: { # 'τ' + 60: 0, # 'e' + 55: 2, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 3, # 'ά' + 18: 3, # 'έ' + 22: 3, # 'ή' + 15: 3, # 'ί' + 1: 3, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 3, # 'ε' + 32: 2, # 'ζ' + 13: 3, # 'η' + 25: 0, # 'θ' + 5: 3, # 'ι' + 11: 2, # 'κ' + 16: 2, # 'λ' + 10: 3, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 3, # 'ο' + 9: 0, # 'π' + 8: 3, # 'ρ' + 14: 0, # 'ς' + 7: 3, # 'σ' + 2: 3, # 'τ' + 12: 3, # 'υ' + 28: 2, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 3, # 'ω' + 19: 3, # 'ό' + 26: 3, # 'ύ' + 27: 3, # 'ώ' + }, + 12: { # 'υ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 2, # 'ά' + 18: 2, # 'έ' + 22: 3, # 'ή' + 15: 2, # 'ί' + 1: 3, # 'α' + 29: 2, # 'β' + 20: 3, # 'γ' + 21: 2, # 'δ' + 3: 2, # 'ε' + 32: 2, # 'ζ' + 13: 2, # 'η' + 25: 3, # 'θ' + 5: 2, # 'ι' + 11: 3, # 'κ' + 16: 3, # 'λ' + 10: 3, # 'μ' + 6: 3, # 'ν' + 30: 3, # 'ξ' + 4: 3, # 'ο' + 9: 3, # 'π' + 8: 3, # 'ρ' + 14: 3, # 'ς' + 7: 3, # 'σ' + 2: 3, # 'τ' + 12: 0, # 'υ' + 28: 2, # 'φ' + 23: 3, # 'χ' + 42: 2, # 'ψ' + 24: 2, # 'ω' + 19: 2, # 'ό' + 26: 0, # 'ύ' + 27: 2, # 'ώ' + }, + 28: { # 'φ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 3, # 'ά' + 18: 3, # 'έ' + 22: 3, # 'ή' + 15: 3, # 'ί' + 1: 3, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 2, # 'η' + 25: 2, # 'θ' + 5: 3, # 'ι' + 11: 0, # 'κ' + 16: 2, # 'λ' + 10: 0, # 'μ' + 6: 1, # 'ν' + 30: 0, # 'ξ' + 4: 3, # 'ο' + 9: 0, # 'π' + 8: 3, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 3, # 'τ' + 12: 3, # 'υ' + 28: 1, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 3, # 'ω' + 19: 3, # 'ό' + 26: 2, # 'ύ' + 27: 2, # 'ώ' + }, + 23: { # 'χ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 3, # 'ά' + 18: 2, # 'έ' + 22: 3, # 'ή' + 15: 3, # 'ί' + 1: 3, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 2, # 'η' + 25: 2, # 'θ' + 5: 3, # 'ι' + 11: 0, # 'κ' + 16: 2, # 'λ' + 10: 2, # 'μ' + 6: 3, # 'ν' + 30: 0, # 'ξ' + 4: 3, # 'ο' + 9: 0, # 'π' + 8: 3, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 3, # 'τ' + 12: 3, # 'υ' + 28: 0, # 'φ' + 23: 2, # 'χ' + 42: 0, # 'ψ' + 24: 3, # 'ω' + 19: 3, # 'ό' + 26: 3, # 'ύ' + 27: 3, # 'ώ' + }, + 42: { # 'ψ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 2, # 'ά' + 18: 2, # 'έ' + 22: 1, # 'ή' + 15: 2, # 'ί' + 1: 2, # 'α' + 29: 0, # 'β' + 20: 0, # 'γ' + 21: 0, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 3, # 'η' + 25: 0, # 'θ' + 5: 2, # 'ι' + 11: 0, # 'κ' + 16: 0, # 'λ' + 10: 0, # 'μ' + 6: 0, # 'ν' + 30: 0, # 'ξ' + 4: 2, # 'ο' + 9: 0, # 'π' + 8: 0, # 'ρ' + 14: 0, # 'ς' + 7: 0, # 'σ' + 2: 2, # 'τ' + 12: 1, # 'υ' + 28: 0, # 'φ' + 23: 0, # 'χ' + 42: 0, # 'ψ' + 24: 2, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 24: { # 'ω' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 1, # 'ά' + 18: 0, # 'έ' + 22: 2, # 'ή' + 15: 0, # 'ί' + 1: 0, # 'α' + 29: 2, # 'β' + 20: 3, # 'γ' + 21: 2, # 'δ' + 3: 0, # 'ε' + 32: 0, # 'ζ' + 13: 0, # 'η' + 25: 3, # 'θ' + 5: 2, # 'ι' + 11: 0, # 'κ' + 16: 2, # 'λ' + 10: 3, # 'μ' + 6: 3, # 'ν' + 30: 0, # 'ξ' + 4: 0, # 'ο' + 9: 3, # 'π' + 8: 3, # 'ρ' + 14: 3, # 'ς' + 7: 3, # 'σ' + 2: 3, # 'τ' + 12: 0, # 'υ' + 28: 2, # 'φ' + 23: 2, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 19: { # 'ό' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 0, # 'α' + 29: 3, # 'β' + 20: 3, # 'γ' + 21: 3, # 'δ' + 3: 1, # 'ε' + 32: 2, # 'ζ' + 13: 2, # 'η' + 25: 2, # 'θ' + 5: 2, # 'ι' + 11: 3, # 'κ' + 16: 3, # 'λ' + 10: 3, # 'μ' + 6: 3, # 'ν' + 30: 1, # 'ξ' + 4: 2, # 'ο' + 9: 3, # 'π' + 8: 3, # 'ρ' + 14: 3, # 'ς' + 7: 3, # 'σ' + 2: 3, # 'τ' + 12: 0, # 'υ' + 28: 2, # 'φ' + 23: 3, # 'χ' + 42: 2, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 26: { # 'ύ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 2, # 'α' + 29: 2, # 'β' + 20: 2, # 'γ' + 21: 1, # 'δ' + 3: 3, # 'ε' + 32: 0, # 'ζ' + 13: 2, # 'η' + 25: 3, # 'θ' + 5: 0, # 'ι' + 11: 3, # 'κ' + 16: 3, # 'λ' + 10: 3, # 'μ' + 6: 3, # 'ν' + 30: 2, # 'ξ' + 4: 3, # 'ο' + 9: 3, # 'π' + 8: 3, # 'ρ' + 14: 3, # 'ς' + 7: 3, # 'σ' + 2: 3, # 'τ' + 12: 0, # 'υ' + 28: 2, # 'φ' + 23: 2, # 'χ' + 42: 2, # 'ψ' + 24: 2, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, + 27: { # 'ώ' + 60: 0, # 'e' + 55: 0, # 'o' + 58: 0, # 't' + 36: 0, # '·' + 61: 0, # 'Ά' + 46: 0, # 'Έ' + 54: 0, # 'Ό' + 31: 0, # 'Α' + 51: 0, # 'Β' + 43: 0, # 'Γ' + 41: 0, # 'Δ' + 34: 0, # 'Ε' + 40: 0, # 'Η' + 52: 0, # 'Θ' + 47: 0, # 'Ι' + 44: 0, # 'Κ' + 53: 0, # 'Λ' + 38: 0, # 'Μ' + 49: 0, # 'Ν' + 59: 0, # 'Ξ' + 39: 0, # 'Ο' + 35: 0, # 'Π' + 48: 0, # 'Ρ' + 37: 0, # 'Σ' + 33: 0, # 'Τ' + 45: 0, # 'Υ' + 56: 0, # 'Φ' + 50: 0, # 'Χ' + 57: 0, # 'Ω' + 17: 0, # 'ά' + 18: 0, # 'έ' + 22: 0, # 'ή' + 15: 0, # 'ί' + 1: 0, # 'α' + 29: 1, # 'β' + 20: 0, # 'γ' + 21: 3, # 'δ' + 3: 0, # 'ε' + 32: 0, # 'ζ' + 13: 1, # 'η' + 25: 2, # 'θ' + 5: 2, # 'ι' + 11: 0, # 'κ' + 16: 2, # 'λ' + 10: 3, # 'μ' + 6: 3, # 'ν' + 30: 1, # 'ξ' + 4: 0, # 'ο' + 9: 2, # 'π' + 8: 3, # 'ρ' + 14: 3, # 'ς' + 7: 3, # 'σ' + 2: 3, # 'τ' + 12: 0, # 'υ' + 28: 1, # 'φ' + 23: 1, # 'χ' + 42: 0, # 'ψ' + 24: 0, # 'ω' + 19: 0, # 'ό' + 26: 0, # 'ύ' + 27: 0, # 'ώ' + }, +} + +# 255: Undefined characters that did not exist in training text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 +# 251: Control characters + +# Character Mapping Table(s): +WINDOWS_1253_GREEK_CHAR_TO_ORDER = { + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 82, # 'A' + 66: 100, # 'B' + 67: 104, # 'C' + 68: 94, # 'D' + 69: 98, # 'E' + 70: 101, # 'F' + 71: 116, # 'G' + 72: 102, # 'H' + 73: 111, # 'I' + 74: 187, # 'J' + 75: 117, # 'K' + 76: 92, # 'L' + 77: 88, # 'M' + 78: 113, # 'N' + 79: 85, # 'O' + 80: 79, # 'P' + 81: 118, # 'Q' + 82: 105, # 'R' + 83: 83, # 'S' + 84: 67, # 'T' + 85: 114, # 'U' + 86: 119, # 'V' + 87: 95, # 'W' + 88: 99, # 'X' + 89: 109, # 'Y' + 90: 188, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 72, # 'a' + 98: 70, # 'b' + 99: 80, # 'c' + 100: 81, # 'd' + 101: 60, # 'e' + 102: 96, # 'f' + 103: 93, # 'g' + 104: 89, # 'h' + 105: 68, # 'i' + 106: 120, # 'j' + 107: 97, # 'k' + 108: 77, # 'l' + 109: 86, # 'm' + 110: 69, # 'n' + 111: 55, # 'o' + 112: 78, # 'p' + 113: 115, # 'q' + 114: 65, # 'r' + 115: 66, # 's' + 116: 58, # 't' + 117: 76, # 'u' + 118: 106, # 'v' + 119: 103, # 'w' + 120: 87, # 'x' + 121: 107, # 'y' + 122: 112, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 255, # '€' + 129: 255, # None + 130: 255, # '‚' + 131: 255, # 'ƒ' + 132: 255, # '„' + 133: 255, # '…' + 134: 255, # '†' + 135: 255, # '‡' + 136: 255, # None + 137: 255, # '‰' + 138: 255, # None + 139: 255, # '‹' + 140: 255, # None + 141: 255, # None + 142: 255, # None + 143: 255, # None + 144: 255, # None + 145: 255, # '‘' + 146: 255, # '’' + 147: 255, # '“' + 148: 255, # '”' + 149: 255, # '•' + 150: 255, # '–' + 151: 255, # '—' + 152: 255, # None + 153: 255, # '™' + 154: 255, # None + 155: 255, # '›' + 156: 255, # None + 157: 255, # None + 158: 255, # None + 159: 255, # None + 160: 253, # '\xa0' + 161: 233, # '΅' + 162: 61, # 'Ά' + 163: 253, # '£' + 164: 253, # '¤' + 165: 253, # '¥' + 166: 253, # '¦' + 167: 253, # '§' + 168: 253, # '¨' + 169: 253, # '©' + 170: 253, # None + 171: 253, # '«' + 172: 253, # '¬' + 173: 74, # '\xad' + 174: 253, # '®' + 175: 253, # '―' + 176: 253, # '°' + 177: 253, # '±' + 178: 253, # '²' + 179: 253, # '³' + 180: 247, # '΄' + 181: 253, # 'µ' + 182: 253, # '¶' + 183: 36, # '·' + 184: 46, # 'Έ' + 185: 71, # 'Ή' + 186: 73, # 'Ί' + 187: 253, # '»' + 188: 54, # 'Ό' + 189: 253, # '½' + 190: 108, # 'Ύ' + 191: 123, # 'Ώ' + 192: 110, # 'ΐ' + 193: 31, # 'Α' + 194: 51, # 'Β' + 195: 43, # 'Γ' + 196: 41, # 'Δ' + 197: 34, # 'Ε' + 198: 91, # 'Ζ' + 199: 40, # 'Η' + 200: 52, # 'Θ' + 201: 47, # 'Ι' + 202: 44, # 'Κ' + 203: 53, # 'Λ' + 204: 38, # 'Μ' + 205: 49, # 'Ν' + 206: 59, # 'Ξ' + 207: 39, # 'Ο' + 208: 35, # 'Π' + 209: 48, # 'Ρ' + 210: 250, # None + 211: 37, # 'Σ' + 212: 33, # 'Τ' + 213: 45, # 'Υ' + 214: 56, # 'Φ' + 215: 50, # 'Χ' + 216: 84, # 'Ψ' + 217: 57, # 'Ω' + 218: 120, # 'Ϊ' + 219: 121, # 'Ϋ' + 220: 17, # 'ά' + 221: 18, # 'έ' + 222: 22, # 'ή' + 223: 15, # 'ί' + 224: 124, # 'ΰ' + 225: 1, # 'α' + 226: 29, # 'β' + 227: 20, # 'γ' + 228: 21, # 'δ' + 229: 3, # 'ε' + 230: 32, # 'ζ' + 231: 13, # 'η' + 232: 25, # 'θ' + 233: 5, # 'ι' + 234: 11, # 'κ' + 235: 16, # 'λ' + 236: 10, # 'μ' + 237: 6, # 'ν' + 238: 30, # 'ξ' + 239: 4, # 'ο' + 240: 9, # 'π' + 241: 8, # 'ρ' + 242: 14, # 'ς' + 243: 7, # 'σ' + 244: 2, # 'τ' + 245: 12, # 'υ' + 246: 28, # 'φ' + 247: 23, # 'χ' + 248: 42, # 'ψ' + 249: 24, # 'ω' + 250: 64, # 'ϊ' + 251: 75, # 'ϋ' + 252: 19, # 'ό' + 253: 26, # 'ύ' + 254: 27, # 'ώ' + 255: 253, # None +} + +WINDOWS_1253_GREEK_MODEL = SingleByteCharSetModel(charset_name='windows-1253', + language='Greek', + char_to_order_map=WINDOWS_1253_GREEK_CHAR_TO_ORDER, + language_model=GREEK_LANG_MODEL, + typical_positive_ratio=0.982851, + keep_ascii_letters=False, + alphabet='ΆΈΉΊΌΎΏΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩάέήίαβγδεζηθικλμνξοπρςστυφχψωόύώ') + +ISO_8859_7_GREEK_CHAR_TO_ORDER = { + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 82, # 'A' + 66: 100, # 'B' + 67: 104, # 'C' + 68: 94, # 'D' + 69: 98, # 'E' + 70: 101, # 'F' + 71: 116, # 'G' + 72: 102, # 'H' + 73: 111, # 'I' + 74: 187, # 'J' + 75: 117, # 'K' + 76: 92, # 'L' + 77: 88, # 'M' + 78: 113, # 'N' + 79: 85, # 'O' + 80: 79, # 'P' + 81: 118, # 'Q' + 82: 105, # 'R' + 83: 83, # 'S' + 84: 67, # 'T' + 85: 114, # 'U' + 86: 119, # 'V' + 87: 95, # 'W' + 88: 99, # 'X' + 89: 109, # 'Y' + 90: 188, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 72, # 'a' + 98: 70, # 'b' + 99: 80, # 'c' + 100: 81, # 'd' + 101: 60, # 'e' + 102: 96, # 'f' + 103: 93, # 'g' + 104: 89, # 'h' + 105: 68, # 'i' + 106: 120, # 'j' + 107: 97, # 'k' + 108: 77, # 'l' + 109: 86, # 'm' + 110: 69, # 'n' + 111: 55, # 'o' + 112: 78, # 'p' + 113: 115, # 'q' + 114: 65, # 'r' + 115: 66, # 's' + 116: 58, # 't' + 117: 76, # 'u' + 118: 106, # 'v' + 119: 103, # 'w' + 120: 87, # 'x' + 121: 107, # 'y' + 122: 112, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 255, # '\x80' + 129: 255, # '\x81' + 130: 255, # '\x82' + 131: 255, # '\x83' + 132: 255, # '\x84' + 133: 255, # '\x85' + 134: 255, # '\x86' + 135: 255, # '\x87' + 136: 255, # '\x88' + 137: 255, # '\x89' + 138: 255, # '\x8a' + 139: 255, # '\x8b' + 140: 255, # '\x8c' + 141: 255, # '\x8d' + 142: 255, # '\x8e' + 143: 255, # '\x8f' + 144: 255, # '\x90' + 145: 255, # '\x91' + 146: 255, # '\x92' + 147: 255, # '\x93' + 148: 255, # '\x94' + 149: 255, # '\x95' + 150: 255, # '\x96' + 151: 255, # '\x97' + 152: 255, # '\x98' + 153: 255, # '\x99' + 154: 255, # '\x9a' + 155: 255, # '\x9b' + 156: 255, # '\x9c' + 157: 255, # '\x9d' + 158: 255, # '\x9e' + 159: 255, # '\x9f' + 160: 253, # '\xa0' + 161: 233, # '‘' + 162: 90, # '’' + 163: 253, # '£' + 164: 253, # '€' + 165: 253, # '₯' + 166: 253, # '¦' + 167: 253, # '§' + 168: 253, # '¨' + 169: 253, # '©' + 170: 253, # 'ͺ' + 171: 253, # '«' + 172: 253, # '¬' + 173: 74, # '\xad' + 174: 253, # None + 175: 253, # '―' + 176: 253, # '°' + 177: 253, # '±' + 178: 253, # '²' + 179: 253, # '³' + 180: 247, # '΄' + 181: 248, # '΅' + 182: 61, # 'Ά' + 183: 36, # '·' + 184: 46, # 'Έ' + 185: 71, # 'Ή' + 186: 73, # 'Ί' + 187: 253, # '»' + 188: 54, # 'Ό' + 189: 253, # '½' + 190: 108, # 'Ύ' + 191: 123, # 'Ώ' + 192: 110, # 'ΐ' + 193: 31, # 'Α' + 194: 51, # 'Β' + 195: 43, # 'Γ' + 196: 41, # 'Δ' + 197: 34, # 'Ε' + 198: 91, # 'Ζ' + 199: 40, # 'Η' + 200: 52, # 'Θ' + 201: 47, # 'Ι' + 202: 44, # 'Κ' + 203: 53, # 'Λ' + 204: 38, # 'Μ' + 205: 49, # 'Ν' + 206: 59, # 'Ξ' + 207: 39, # 'Ο' + 208: 35, # 'Π' + 209: 48, # 'Ρ' + 210: 250, # None + 211: 37, # 'Σ' + 212: 33, # 'Τ' + 213: 45, # 'Υ' + 214: 56, # 'Φ' + 215: 50, # 'Χ' + 216: 84, # 'Ψ' + 217: 57, # 'Ω' + 218: 120, # 'Ϊ' + 219: 121, # 'Ϋ' + 220: 17, # 'ά' + 221: 18, # 'έ' + 222: 22, # 'ή' + 223: 15, # 'ί' + 224: 124, # 'ΰ' + 225: 1, # 'α' + 226: 29, # 'β' + 227: 20, # 'γ' + 228: 21, # 'δ' + 229: 3, # 'ε' + 230: 32, # 'ζ' + 231: 13, # 'η' + 232: 25, # 'θ' + 233: 5, # 'ι' + 234: 11, # 'κ' + 235: 16, # 'λ' + 236: 10, # 'μ' + 237: 6, # 'ν' + 238: 30, # 'ξ' + 239: 4, # 'ο' + 240: 9, # 'π' + 241: 8, # 'ρ' + 242: 14, # 'ς' + 243: 7, # 'σ' + 244: 2, # 'τ' + 245: 12, # 'υ' + 246: 28, # 'φ' + 247: 23, # 'χ' + 248: 42, # 'ψ' + 249: 24, # 'ω' + 250: 64, # 'ϊ' + 251: 75, # 'ϋ' + 252: 19, # 'ό' + 253: 26, # 'ύ' + 254: 27, # 'ώ' + 255: 253, # None +} + +ISO_8859_7_GREEK_MODEL = SingleByteCharSetModel(charset_name='ISO-8859-7', + language='Greek', + char_to_order_map=ISO_8859_7_GREEK_CHAR_TO_ORDER, + language_model=GREEK_LANG_MODEL, + typical_positive_ratio=0.982851, + keep_ascii_letters=False, + alphabet='ΆΈΉΊΌΎΏΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩάέήίαβγδεζηθικλμνξοπρςστυφχψωόύώ') + diff --git a/venv/lib/python3.8/site-packages/chardet/langhebrewmodel.py b/venv/lib/python3.8/site-packages/chardet/langhebrewmodel.py new file mode 100644 index 0000000..40fd674 --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/langhebrewmodel.py @@ -0,0 +1,4383 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from chardet.sbcharsetprober import SingleByteCharSetModel + + +# 3: Positive +# 2: Likely +# 1: Unlikely +# 0: Negative + +HEBREW_LANG_MODEL = { + 50: { # 'a' + 50: 0, # 'a' + 60: 1, # 'c' + 61: 1, # 'd' + 42: 1, # 'e' + 53: 1, # 'i' + 56: 2, # 'l' + 54: 2, # 'n' + 49: 0, # 'o' + 51: 2, # 'r' + 43: 1, # 's' + 44: 2, # 't' + 63: 1, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 0, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 1, # 'ה' + 2: 0, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 0, # 'י' + 25: 0, # 'ך' + 15: 0, # 'כ' + 4: 0, # 'ל' + 11: 0, # 'ם' + 6: 1, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 1, # 'ק' + 7: 0, # 'ר' + 10: 1, # 'ש' + 5: 0, # 'ת' + 32: 0, # '–' + 52: 1, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 60: { # 'c' + 50: 1, # 'a' + 60: 1, # 'c' + 61: 0, # 'd' + 42: 1, # 'e' + 53: 1, # 'i' + 56: 1, # 'l' + 54: 0, # 'n' + 49: 1, # 'o' + 51: 1, # 'r' + 43: 1, # 's' + 44: 2, # 't' + 63: 1, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 1, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 1, # 'ה' + 2: 0, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 0, # 'י' + 25: 0, # 'ך' + 15: 0, # 'כ' + 4: 0, # 'ל' + 11: 0, # 'ם' + 6: 1, # 'מ' + 23: 0, # 'ן' + 12: 1, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 0, # 'ר' + 10: 0, # 'ש' + 5: 0, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 61: { # 'd' + 50: 1, # 'a' + 60: 0, # 'c' + 61: 1, # 'd' + 42: 1, # 'e' + 53: 1, # 'i' + 56: 1, # 'l' + 54: 1, # 'n' + 49: 2, # 'o' + 51: 1, # 'r' + 43: 1, # 's' + 44: 0, # 't' + 63: 1, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 0, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 1, # 'ה' + 2: 0, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 0, # 'י' + 25: 0, # 'ך' + 15: 0, # 'כ' + 4: 0, # 'ל' + 11: 0, # 'ם' + 6: 0, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 0, # 'ר' + 10: 0, # 'ש' + 5: 0, # 'ת' + 32: 1, # '–' + 52: 1, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 42: { # 'e' + 50: 1, # 'a' + 60: 1, # 'c' + 61: 2, # 'd' + 42: 1, # 'e' + 53: 1, # 'i' + 56: 2, # 'l' + 54: 2, # 'n' + 49: 1, # 'o' + 51: 2, # 'r' + 43: 2, # 's' + 44: 2, # 't' + 63: 1, # 'u' + 34: 1, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 0, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 0, # 'ה' + 2: 0, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 0, # 'י' + 25: 0, # 'ך' + 15: 0, # 'כ' + 4: 0, # 'ל' + 11: 0, # 'ם' + 6: 0, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 1, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 0, # 'ר' + 10: 0, # 'ש' + 5: 0, # 'ת' + 32: 1, # '–' + 52: 2, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 53: { # 'i' + 50: 1, # 'a' + 60: 2, # 'c' + 61: 1, # 'd' + 42: 1, # 'e' + 53: 0, # 'i' + 56: 1, # 'l' + 54: 2, # 'n' + 49: 2, # 'o' + 51: 1, # 'r' + 43: 2, # 's' + 44: 2, # 't' + 63: 1, # 'u' + 34: 0, # '\xa0' + 55: 1, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 0, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 0, # 'ה' + 2: 0, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 0, # 'י' + 25: 0, # 'ך' + 15: 0, # 'כ' + 4: 0, # 'ל' + 11: 0, # 'ם' + 6: 0, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 0, # 'ר' + 10: 0, # 'ש' + 5: 0, # 'ת' + 32: 0, # '–' + 52: 1, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 56: { # 'l' + 50: 1, # 'a' + 60: 1, # 'c' + 61: 1, # 'd' + 42: 2, # 'e' + 53: 2, # 'i' + 56: 2, # 'l' + 54: 1, # 'n' + 49: 1, # 'o' + 51: 0, # 'r' + 43: 1, # 's' + 44: 1, # 't' + 63: 1, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 0, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 0, # 'ה' + 2: 0, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 0, # 'י' + 25: 0, # 'ך' + 15: 0, # 'כ' + 4: 0, # 'ל' + 11: 0, # 'ם' + 6: 0, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 0, # 'ר' + 10: 0, # 'ש' + 5: 0, # 'ת' + 32: 0, # '–' + 52: 1, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 54: { # 'n' + 50: 1, # 'a' + 60: 1, # 'c' + 61: 1, # 'd' + 42: 1, # 'e' + 53: 1, # 'i' + 56: 1, # 'l' + 54: 1, # 'n' + 49: 1, # 'o' + 51: 0, # 'r' + 43: 1, # 's' + 44: 2, # 't' + 63: 1, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 0, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 1, # 'ה' + 2: 0, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 0, # 'י' + 25: 0, # 'ך' + 15: 0, # 'כ' + 4: 0, # 'ל' + 11: 0, # 'ם' + 6: 0, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 0, # 'ר' + 10: 0, # 'ש' + 5: 0, # 'ת' + 32: 0, # '–' + 52: 2, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 49: { # 'o' + 50: 1, # 'a' + 60: 1, # 'c' + 61: 1, # 'd' + 42: 1, # 'e' + 53: 1, # 'i' + 56: 1, # 'l' + 54: 2, # 'n' + 49: 1, # 'o' + 51: 2, # 'r' + 43: 1, # 's' + 44: 1, # 't' + 63: 1, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 0, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 0, # 'ה' + 2: 0, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 0, # 'י' + 25: 0, # 'ך' + 15: 0, # 'כ' + 4: 0, # 'ל' + 11: 0, # 'ם' + 6: 0, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 0, # 'ר' + 10: 0, # 'ש' + 5: 0, # 'ת' + 32: 0, # '–' + 52: 1, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 51: { # 'r' + 50: 2, # 'a' + 60: 1, # 'c' + 61: 1, # 'd' + 42: 2, # 'e' + 53: 1, # 'i' + 56: 1, # 'l' + 54: 1, # 'n' + 49: 2, # 'o' + 51: 1, # 'r' + 43: 1, # 's' + 44: 1, # 't' + 63: 1, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 0, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 0, # 'ה' + 2: 0, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 0, # 'י' + 25: 0, # 'ך' + 15: 0, # 'כ' + 4: 0, # 'ל' + 11: 0, # 'ם' + 6: 0, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 0, # 'ר' + 10: 0, # 'ש' + 5: 0, # 'ת' + 32: 0, # '–' + 52: 2, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 43: { # 's' + 50: 1, # 'a' + 60: 1, # 'c' + 61: 0, # 'd' + 42: 2, # 'e' + 53: 1, # 'i' + 56: 1, # 'l' + 54: 1, # 'n' + 49: 1, # 'o' + 51: 1, # 'r' + 43: 1, # 's' + 44: 2, # 't' + 63: 1, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 0, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 0, # 'ה' + 2: 0, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 0, # 'י' + 25: 0, # 'ך' + 15: 0, # 'כ' + 4: 0, # 'ל' + 11: 0, # 'ם' + 6: 0, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 0, # 'ר' + 10: 0, # 'ש' + 5: 0, # 'ת' + 32: 0, # '–' + 52: 1, # '’' + 47: 0, # '“' + 46: 2, # '”' + 58: 0, # '†' + 40: 2, # '…' + }, + 44: { # 't' + 50: 1, # 'a' + 60: 1, # 'c' + 61: 0, # 'd' + 42: 2, # 'e' + 53: 2, # 'i' + 56: 1, # 'l' + 54: 0, # 'n' + 49: 1, # 'o' + 51: 1, # 'r' + 43: 1, # 's' + 44: 1, # 't' + 63: 1, # 'u' + 34: 1, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 0, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 0, # 'ה' + 2: 0, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 0, # 'י' + 25: 0, # 'ך' + 15: 0, # 'כ' + 4: 0, # 'ל' + 11: 0, # 'ם' + 6: 0, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 0, # 'ר' + 10: 0, # 'ש' + 5: 0, # 'ת' + 32: 0, # '–' + 52: 2, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 63: { # 'u' + 50: 1, # 'a' + 60: 1, # 'c' + 61: 1, # 'd' + 42: 1, # 'e' + 53: 1, # 'i' + 56: 1, # 'l' + 54: 1, # 'n' + 49: 0, # 'o' + 51: 1, # 'r' + 43: 2, # 's' + 44: 1, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 0, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 0, # 'ה' + 2: 0, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 0, # 'י' + 25: 0, # 'ך' + 15: 0, # 'כ' + 4: 0, # 'ל' + 11: 0, # 'ם' + 6: 0, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 0, # 'ר' + 10: 0, # 'ש' + 5: 0, # 'ת' + 32: 0, # '–' + 52: 1, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 34: { # '\xa0' + 50: 1, # 'a' + 60: 0, # 'c' + 61: 1, # 'd' + 42: 0, # 'e' + 53: 1, # 'i' + 56: 0, # 'l' + 54: 1, # 'n' + 49: 1, # 'o' + 51: 0, # 'r' + 43: 1, # 's' + 44: 1, # 't' + 63: 0, # 'u' + 34: 2, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 2, # 'א' + 8: 1, # 'ב' + 20: 1, # 'ג' + 16: 1, # 'ד' + 3: 1, # 'ה' + 2: 1, # 'ו' + 24: 1, # 'ז' + 14: 1, # 'ח' + 22: 1, # 'ט' + 1: 2, # 'י' + 25: 0, # 'ך' + 15: 1, # 'כ' + 4: 1, # 'ל' + 11: 0, # 'ם' + 6: 2, # 'מ' + 23: 0, # 'ן' + 12: 1, # 'נ' + 19: 1, # 'ס' + 13: 1, # 'ע' + 26: 0, # 'ף' + 18: 1, # 'פ' + 27: 0, # 'ץ' + 21: 1, # 'צ' + 17: 1, # 'ק' + 7: 1, # 'ר' + 10: 1, # 'ש' + 5: 1, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 55: { # '´' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 1, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 1, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 1, # 'ה' + 2: 1, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 2, # 'י' + 25: 0, # 'ך' + 15: 0, # 'כ' + 4: 1, # 'ל' + 11: 0, # 'ם' + 6: 1, # 'מ' + 23: 1, # 'ן' + 12: 1, # 'נ' + 19: 1, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 1, # 'ר' + 10: 1, # 'ש' + 5: 0, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 48: { # '¼' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 1, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 0, # 'ה' + 2: 1, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 0, # 'י' + 25: 0, # 'ך' + 15: 1, # 'כ' + 4: 1, # 'ל' + 11: 0, # 'ם' + 6: 1, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 0, # 'ר' + 10: 0, # 'ש' + 5: 0, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 39: { # '½' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 0, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 0, # 'ה' + 2: 0, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 0, # 'י' + 25: 0, # 'ך' + 15: 1, # 'כ' + 4: 1, # 'ל' + 11: 0, # 'ם' + 6: 0, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 1, # 'צ' + 17: 1, # 'ק' + 7: 0, # 'ר' + 10: 0, # 'ש' + 5: 0, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 57: { # '¾' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 0, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 0, # 'ה' + 2: 0, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 0, # 'י' + 25: 0, # 'ך' + 15: 0, # 'כ' + 4: 0, # 'ל' + 11: 0, # 'ם' + 6: 0, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 0, # 'ר' + 10: 0, # 'ש' + 5: 0, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 30: { # 'ְ' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 1, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 1, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 2, # 'א' + 8: 2, # 'ב' + 20: 2, # 'ג' + 16: 2, # 'ד' + 3: 2, # 'ה' + 2: 2, # 'ו' + 24: 2, # 'ז' + 14: 2, # 'ח' + 22: 2, # 'ט' + 1: 2, # 'י' + 25: 2, # 'ך' + 15: 2, # 'כ' + 4: 2, # 'ל' + 11: 1, # 'ם' + 6: 2, # 'מ' + 23: 0, # 'ן' + 12: 2, # 'נ' + 19: 2, # 'ס' + 13: 2, # 'ע' + 26: 0, # 'ף' + 18: 2, # 'פ' + 27: 0, # 'ץ' + 21: 2, # 'צ' + 17: 2, # 'ק' + 7: 2, # 'ר' + 10: 2, # 'ש' + 5: 2, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 59: { # 'ֱ' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 1, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 0, # 'א' + 8: 1, # 'ב' + 20: 1, # 'ג' + 16: 0, # 'ד' + 3: 0, # 'ה' + 2: 0, # 'ו' + 24: 1, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 1, # 'י' + 25: 0, # 'ך' + 15: 1, # 'כ' + 4: 2, # 'ל' + 11: 0, # 'ם' + 6: 2, # 'מ' + 23: 0, # 'ן' + 12: 1, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 1, # 'ר' + 10: 1, # 'ש' + 5: 0, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 41: { # 'ֲ' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 0, # 'א' + 8: 2, # 'ב' + 20: 1, # 'ג' + 16: 2, # 'ד' + 3: 1, # 'ה' + 2: 1, # 'ו' + 24: 1, # 'ז' + 14: 1, # 'ח' + 22: 1, # 'ט' + 1: 1, # 'י' + 25: 1, # 'ך' + 15: 1, # 'כ' + 4: 2, # 'ל' + 11: 0, # 'ם' + 6: 2, # 'מ' + 23: 0, # 'ן' + 12: 2, # 'נ' + 19: 1, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 1, # 'פ' + 27: 0, # 'ץ' + 21: 2, # 'צ' + 17: 1, # 'ק' + 7: 2, # 'ר' + 10: 2, # 'ש' + 5: 1, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 33: { # 'ִ' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 1, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 1, # 'ִ' + 37: 0, # 'ֵ' + 36: 1, # 'ֶ' + 31: 0, # 'ַ' + 29: 1, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 1, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 1, # 'א' + 8: 2, # 'ב' + 20: 2, # 'ג' + 16: 2, # 'ד' + 3: 1, # 'ה' + 2: 1, # 'ו' + 24: 2, # 'ז' + 14: 1, # 'ח' + 22: 1, # 'ט' + 1: 3, # 'י' + 25: 1, # 'ך' + 15: 2, # 'כ' + 4: 2, # 'ל' + 11: 2, # 'ם' + 6: 2, # 'מ' + 23: 2, # 'ן' + 12: 2, # 'נ' + 19: 2, # 'ס' + 13: 1, # 'ע' + 26: 0, # 'ף' + 18: 2, # 'פ' + 27: 1, # 'ץ' + 21: 2, # 'צ' + 17: 2, # 'ק' + 7: 2, # 'ר' + 10: 2, # 'ש' + 5: 2, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 37: { # 'ֵ' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 1, # 'ֶ' + 31: 1, # 'ַ' + 29: 1, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 2, # 'א' + 8: 2, # 'ב' + 20: 1, # 'ג' + 16: 2, # 'ד' + 3: 2, # 'ה' + 2: 1, # 'ו' + 24: 1, # 'ז' + 14: 2, # 'ח' + 22: 1, # 'ט' + 1: 3, # 'י' + 25: 2, # 'ך' + 15: 1, # 'כ' + 4: 2, # 'ל' + 11: 2, # 'ם' + 6: 1, # 'מ' + 23: 2, # 'ן' + 12: 2, # 'נ' + 19: 1, # 'ס' + 13: 2, # 'ע' + 26: 1, # 'ף' + 18: 1, # 'פ' + 27: 1, # 'ץ' + 21: 1, # 'צ' + 17: 1, # 'ק' + 7: 2, # 'ר' + 10: 2, # 'ש' + 5: 2, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 36: { # 'ֶ' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 1, # 'ֶ' + 31: 1, # 'ַ' + 29: 1, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 2, # 'א' + 8: 2, # 'ב' + 20: 1, # 'ג' + 16: 2, # 'ד' + 3: 2, # 'ה' + 2: 1, # 'ו' + 24: 1, # 'ז' + 14: 2, # 'ח' + 22: 1, # 'ט' + 1: 2, # 'י' + 25: 2, # 'ך' + 15: 1, # 'כ' + 4: 2, # 'ל' + 11: 2, # 'ם' + 6: 2, # 'מ' + 23: 2, # 'ן' + 12: 2, # 'נ' + 19: 2, # 'ס' + 13: 1, # 'ע' + 26: 1, # 'ף' + 18: 1, # 'פ' + 27: 2, # 'ץ' + 21: 1, # 'צ' + 17: 1, # 'ק' + 7: 2, # 'ר' + 10: 2, # 'ש' + 5: 2, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 31: { # 'ַ' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 1, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 1, # 'ֶ' + 31: 0, # 'ַ' + 29: 2, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 2, # 'א' + 8: 2, # 'ב' + 20: 2, # 'ג' + 16: 2, # 'ד' + 3: 2, # 'ה' + 2: 1, # 'ו' + 24: 2, # 'ז' + 14: 2, # 'ח' + 22: 2, # 'ט' + 1: 3, # 'י' + 25: 1, # 'ך' + 15: 2, # 'כ' + 4: 2, # 'ל' + 11: 2, # 'ם' + 6: 2, # 'מ' + 23: 2, # 'ן' + 12: 2, # 'נ' + 19: 2, # 'ס' + 13: 2, # 'ע' + 26: 2, # 'ף' + 18: 2, # 'פ' + 27: 1, # 'ץ' + 21: 2, # 'צ' + 17: 2, # 'ק' + 7: 2, # 'ר' + 10: 2, # 'ש' + 5: 2, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 29: { # 'ָ' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 1, # 'ַ' + 29: 2, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 1, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 2, # 'א' + 8: 2, # 'ב' + 20: 2, # 'ג' + 16: 2, # 'ד' + 3: 3, # 'ה' + 2: 2, # 'ו' + 24: 2, # 'ז' + 14: 2, # 'ח' + 22: 1, # 'ט' + 1: 2, # 'י' + 25: 2, # 'ך' + 15: 2, # 'כ' + 4: 2, # 'ל' + 11: 2, # 'ם' + 6: 2, # 'מ' + 23: 2, # 'ן' + 12: 2, # 'נ' + 19: 1, # 'ס' + 13: 2, # 'ע' + 26: 1, # 'ף' + 18: 2, # 'פ' + 27: 1, # 'ץ' + 21: 2, # 'צ' + 17: 2, # 'ק' + 7: 2, # 'ר' + 10: 2, # 'ש' + 5: 2, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 35: { # 'ֹ' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 1, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 2, # 'א' + 8: 2, # 'ב' + 20: 1, # 'ג' + 16: 2, # 'ד' + 3: 2, # 'ה' + 2: 1, # 'ו' + 24: 1, # 'ז' + 14: 1, # 'ח' + 22: 1, # 'ט' + 1: 1, # 'י' + 25: 1, # 'ך' + 15: 2, # 'כ' + 4: 2, # 'ל' + 11: 2, # 'ם' + 6: 2, # 'מ' + 23: 2, # 'ן' + 12: 2, # 'נ' + 19: 2, # 'ס' + 13: 2, # 'ע' + 26: 1, # 'ף' + 18: 2, # 'פ' + 27: 1, # 'ץ' + 21: 2, # 'צ' + 17: 2, # 'ק' + 7: 2, # 'ר' + 10: 2, # 'ש' + 5: 2, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 62: { # 'ֻ' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 0, # 'א' + 8: 1, # 'ב' + 20: 1, # 'ג' + 16: 1, # 'ד' + 3: 1, # 'ה' + 2: 1, # 'ו' + 24: 1, # 'ז' + 14: 1, # 'ח' + 22: 0, # 'ט' + 1: 1, # 'י' + 25: 0, # 'ך' + 15: 1, # 'כ' + 4: 2, # 'ל' + 11: 1, # 'ם' + 6: 1, # 'מ' + 23: 1, # 'ן' + 12: 1, # 'נ' + 19: 1, # 'ס' + 13: 1, # 'ע' + 26: 0, # 'ף' + 18: 1, # 'פ' + 27: 0, # 'ץ' + 21: 1, # 'צ' + 17: 1, # 'ק' + 7: 1, # 'ר' + 10: 1, # 'ש' + 5: 1, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 28: { # 'ּ' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 3, # 'ְ' + 59: 0, # 'ֱ' + 41: 1, # 'ֲ' + 33: 3, # 'ִ' + 37: 2, # 'ֵ' + 36: 2, # 'ֶ' + 31: 3, # 'ַ' + 29: 3, # 'ָ' + 35: 2, # 'ֹ' + 62: 1, # 'ֻ' + 28: 0, # 'ּ' + 38: 2, # 'ׁ' + 45: 1, # 'ׂ' + 9: 2, # 'א' + 8: 2, # 'ב' + 20: 1, # 'ג' + 16: 2, # 'ד' + 3: 1, # 'ה' + 2: 2, # 'ו' + 24: 1, # 'ז' + 14: 1, # 'ח' + 22: 1, # 'ט' + 1: 2, # 'י' + 25: 2, # 'ך' + 15: 2, # 'כ' + 4: 2, # 'ל' + 11: 1, # 'ם' + 6: 2, # 'מ' + 23: 1, # 'ן' + 12: 2, # 'נ' + 19: 1, # 'ס' + 13: 2, # 'ע' + 26: 1, # 'ף' + 18: 1, # 'פ' + 27: 1, # 'ץ' + 21: 1, # 'צ' + 17: 1, # 'ק' + 7: 2, # 'ר' + 10: 2, # 'ש' + 5: 2, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 38: { # 'ׁ' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 2, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 2, # 'ִ' + 37: 2, # 'ֵ' + 36: 2, # 'ֶ' + 31: 2, # 'ַ' + 29: 2, # 'ָ' + 35: 1, # 'ֹ' + 62: 1, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 0, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 0, # 'ה' + 2: 2, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 1, # 'י' + 25: 0, # 'ך' + 15: 0, # 'כ' + 4: 0, # 'ל' + 11: 0, # 'ם' + 6: 0, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 0, # 'ס' + 13: 1, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 0, # 'ר' + 10: 0, # 'ש' + 5: 0, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 45: { # 'ׂ' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 2, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 2, # 'ִ' + 37: 1, # 'ֵ' + 36: 2, # 'ֶ' + 31: 1, # 'ַ' + 29: 2, # 'ָ' + 35: 1, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 1, # 'א' + 8: 0, # 'ב' + 20: 1, # 'ג' + 16: 0, # 'ד' + 3: 1, # 'ה' + 2: 2, # 'ו' + 24: 0, # 'ז' + 14: 1, # 'ח' + 22: 0, # 'ט' + 1: 1, # 'י' + 25: 0, # 'ך' + 15: 0, # 'כ' + 4: 0, # 'ל' + 11: 1, # 'ם' + 6: 1, # 'מ' + 23: 0, # 'ן' + 12: 1, # 'נ' + 19: 0, # 'ס' + 13: 1, # 'ע' + 26: 0, # 'ף' + 18: 1, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 1, # 'ר' + 10: 0, # 'ש' + 5: 1, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 9: { # 'א' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 1, # '\xa0' + 55: 1, # '´' + 48: 1, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 2, # 'ֱ' + 41: 2, # 'ֲ' + 33: 2, # 'ִ' + 37: 2, # 'ֵ' + 36: 2, # 'ֶ' + 31: 2, # 'ַ' + 29: 2, # 'ָ' + 35: 2, # 'ֹ' + 62: 1, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 2, # 'א' + 8: 3, # 'ב' + 20: 3, # 'ג' + 16: 3, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 3, # 'ז' + 14: 3, # 'ח' + 22: 3, # 'ט' + 1: 3, # 'י' + 25: 3, # 'ך' + 15: 3, # 'כ' + 4: 3, # 'ל' + 11: 3, # 'ם' + 6: 3, # 'מ' + 23: 3, # 'ן' + 12: 3, # 'נ' + 19: 3, # 'ס' + 13: 2, # 'ע' + 26: 3, # 'ף' + 18: 3, # 'פ' + 27: 1, # 'ץ' + 21: 3, # 'צ' + 17: 3, # 'ק' + 7: 3, # 'ר' + 10: 3, # 'ש' + 5: 3, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 8: { # 'ב' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 1, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 1, # '\xa0' + 55: 1, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 2, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 2, # 'ִ' + 37: 2, # 'ֵ' + 36: 2, # 'ֶ' + 31: 2, # 'ַ' + 29: 2, # 'ָ' + 35: 2, # 'ֹ' + 62: 1, # 'ֻ' + 28: 3, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 3, # 'א' + 8: 3, # 'ב' + 20: 3, # 'ג' + 16: 3, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 3, # 'ז' + 14: 3, # 'ח' + 22: 3, # 'ט' + 1: 3, # 'י' + 25: 2, # 'ך' + 15: 3, # 'כ' + 4: 3, # 'ל' + 11: 2, # 'ם' + 6: 3, # 'מ' + 23: 3, # 'ן' + 12: 3, # 'נ' + 19: 3, # 'ס' + 13: 3, # 'ע' + 26: 1, # 'ף' + 18: 3, # 'פ' + 27: 2, # 'ץ' + 21: 3, # 'צ' + 17: 3, # 'ק' + 7: 3, # 'ר' + 10: 3, # 'ש' + 5: 3, # 'ת' + 32: 1, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 20: { # 'ג' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 1, # '\xa0' + 55: 2, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 2, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 1, # 'ִ' + 37: 1, # 'ֵ' + 36: 1, # 'ֶ' + 31: 2, # 'ַ' + 29: 2, # 'ָ' + 35: 1, # 'ֹ' + 62: 0, # 'ֻ' + 28: 2, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 2, # 'א' + 8: 3, # 'ב' + 20: 2, # 'ג' + 16: 3, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 3, # 'ז' + 14: 2, # 'ח' + 22: 2, # 'ט' + 1: 3, # 'י' + 25: 1, # 'ך' + 15: 1, # 'כ' + 4: 3, # 'ל' + 11: 3, # 'ם' + 6: 3, # 'מ' + 23: 3, # 'ן' + 12: 3, # 'נ' + 19: 2, # 'ס' + 13: 3, # 'ע' + 26: 2, # 'ף' + 18: 2, # 'פ' + 27: 1, # 'ץ' + 21: 1, # 'צ' + 17: 1, # 'ק' + 7: 3, # 'ר' + 10: 3, # 'ש' + 5: 3, # 'ת' + 32: 0, # '–' + 52: 1, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 16: { # 'ד' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 2, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 2, # 'ִ' + 37: 2, # 'ֵ' + 36: 2, # 'ֶ' + 31: 2, # 'ַ' + 29: 2, # 'ָ' + 35: 2, # 'ֹ' + 62: 1, # 'ֻ' + 28: 2, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 3, # 'א' + 8: 3, # 'ב' + 20: 3, # 'ג' + 16: 3, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 1, # 'ז' + 14: 2, # 'ח' + 22: 2, # 'ט' + 1: 3, # 'י' + 25: 2, # 'ך' + 15: 2, # 'כ' + 4: 3, # 'ל' + 11: 3, # 'ם' + 6: 3, # 'מ' + 23: 2, # 'ן' + 12: 3, # 'נ' + 19: 2, # 'ס' + 13: 3, # 'ע' + 26: 2, # 'ף' + 18: 3, # 'פ' + 27: 0, # 'ץ' + 21: 2, # 'צ' + 17: 3, # 'ק' + 7: 3, # 'ר' + 10: 3, # 'ש' + 5: 3, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 3: { # 'ה' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 1, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 1, # '\xa0' + 55: 0, # '´' + 48: 1, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 1, # 'ְ' + 59: 1, # 'ֱ' + 41: 2, # 'ֲ' + 33: 2, # 'ִ' + 37: 2, # 'ֵ' + 36: 2, # 'ֶ' + 31: 3, # 'ַ' + 29: 2, # 'ָ' + 35: 1, # 'ֹ' + 62: 1, # 'ֻ' + 28: 2, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 3, # 'א' + 8: 3, # 'ב' + 20: 3, # 'ג' + 16: 3, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 3, # 'ז' + 14: 3, # 'ח' + 22: 3, # 'ט' + 1: 3, # 'י' + 25: 1, # 'ך' + 15: 3, # 'כ' + 4: 3, # 'ל' + 11: 3, # 'ם' + 6: 3, # 'מ' + 23: 3, # 'ן' + 12: 3, # 'נ' + 19: 3, # 'ס' + 13: 3, # 'ע' + 26: 0, # 'ף' + 18: 3, # 'פ' + 27: 1, # 'ץ' + 21: 3, # 'צ' + 17: 3, # 'ק' + 7: 3, # 'ר' + 10: 3, # 'ש' + 5: 3, # 'ת' + 32: 1, # '–' + 52: 1, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 2, # '…' + }, + 2: { # 'ו' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 1, # 't' + 63: 0, # 'u' + 34: 1, # '\xa0' + 55: 1, # '´' + 48: 1, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 2, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 2, # 'ִ' + 37: 1, # 'ֵ' + 36: 1, # 'ֶ' + 31: 2, # 'ַ' + 29: 2, # 'ָ' + 35: 3, # 'ֹ' + 62: 0, # 'ֻ' + 28: 3, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 3, # 'א' + 8: 3, # 'ב' + 20: 3, # 'ג' + 16: 3, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 3, # 'ז' + 14: 3, # 'ח' + 22: 3, # 'ט' + 1: 3, # 'י' + 25: 3, # 'ך' + 15: 3, # 'כ' + 4: 3, # 'ל' + 11: 3, # 'ם' + 6: 3, # 'מ' + 23: 3, # 'ן' + 12: 3, # 'נ' + 19: 3, # 'ס' + 13: 3, # 'ע' + 26: 3, # 'ף' + 18: 3, # 'פ' + 27: 3, # 'ץ' + 21: 3, # 'צ' + 17: 3, # 'ק' + 7: 3, # 'ר' + 10: 3, # 'ש' + 5: 3, # 'ת' + 32: 1, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 2, # '…' + }, + 24: { # 'ז' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 1, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 2, # 'ְ' + 59: 0, # 'ֱ' + 41: 1, # 'ֲ' + 33: 1, # 'ִ' + 37: 2, # 'ֵ' + 36: 2, # 'ֶ' + 31: 2, # 'ַ' + 29: 2, # 'ָ' + 35: 1, # 'ֹ' + 62: 1, # 'ֻ' + 28: 2, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 3, # 'א' + 8: 2, # 'ב' + 20: 2, # 'ג' + 16: 2, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 2, # 'ז' + 14: 2, # 'ח' + 22: 1, # 'ט' + 1: 3, # 'י' + 25: 1, # 'ך' + 15: 3, # 'כ' + 4: 3, # 'ל' + 11: 2, # 'ם' + 6: 3, # 'מ' + 23: 2, # 'ן' + 12: 2, # 'נ' + 19: 1, # 'ס' + 13: 2, # 'ע' + 26: 1, # 'ף' + 18: 1, # 'פ' + 27: 0, # 'ץ' + 21: 2, # 'צ' + 17: 3, # 'ק' + 7: 3, # 'ר' + 10: 1, # 'ש' + 5: 2, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 14: { # 'ח' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 1, # '\xa0' + 55: 1, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 2, # 'ְ' + 59: 1, # 'ֱ' + 41: 2, # 'ֲ' + 33: 2, # 'ִ' + 37: 2, # 'ֵ' + 36: 2, # 'ֶ' + 31: 2, # 'ַ' + 29: 2, # 'ָ' + 35: 2, # 'ֹ' + 62: 1, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 2, # 'א' + 8: 3, # 'ב' + 20: 2, # 'ג' + 16: 3, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 3, # 'ז' + 14: 2, # 'ח' + 22: 2, # 'ט' + 1: 3, # 'י' + 25: 1, # 'ך' + 15: 2, # 'כ' + 4: 3, # 'ל' + 11: 3, # 'ם' + 6: 3, # 'מ' + 23: 2, # 'ן' + 12: 3, # 'נ' + 19: 3, # 'ס' + 13: 1, # 'ע' + 26: 2, # 'ף' + 18: 2, # 'פ' + 27: 2, # 'ץ' + 21: 3, # 'צ' + 17: 3, # 'ק' + 7: 3, # 'ר' + 10: 3, # 'ש' + 5: 3, # 'ת' + 32: 0, # '–' + 52: 1, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 22: { # 'ט' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 1, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 2, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 2, # 'ִ' + 37: 1, # 'ֵ' + 36: 1, # 'ֶ' + 31: 2, # 'ַ' + 29: 1, # 'ָ' + 35: 1, # 'ֹ' + 62: 1, # 'ֻ' + 28: 1, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 3, # 'א' + 8: 3, # 'ב' + 20: 3, # 'ג' + 16: 1, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 2, # 'ז' + 14: 3, # 'ח' + 22: 2, # 'ט' + 1: 3, # 'י' + 25: 1, # 'ך' + 15: 2, # 'כ' + 4: 3, # 'ל' + 11: 2, # 'ם' + 6: 2, # 'מ' + 23: 2, # 'ן' + 12: 3, # 'נ' + 19: 2, # 'ס' + 13: 3, # 'ע' + 26: 2, # 'ף' + 18: 3, # 'פ' + 27: 1, # 'ץ' + 21: 2, # 'צ' + 17: 2, # 'ק' + 7: 3, # 'ר' + 10: 2, # 'ש' + 5: 3, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 1: { # 'י' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 1, # '\xa0' + 55: 1, # '´' + 48: 1, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 2, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 2, # 'ִ' + 37: 2, # 'ֵ' + 36: 1, # 'ֶ' + 31: 2, # 'ַ' + 29: 2, # 'ָ' + 35: 2, # 'ֹ' + 62: 1, # 'ֻ' + 28: 2, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 3, # 'א' + 8: 3, # 'ב' + 20: 3, # 'ג' + 16: 3, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 3, # 'ז' + 14: 3, # 'ח' + 22: 3, # 'ט' + 1: 3, # 'י' + 25: 3, # 'ך' + 15: 3, # 'כ' + 4: 3, # 'ל' + 11: 3, # 'ם' + 6: 3, # 'מ' + 23: 3, # 'ן' + 12: 3, # 'נ' + 19: 3, # 'ס' + 13: 3, # 'ע' + 26: 3, # 'ף' + 18: 3, # 'פ' + 27: 3, # 'ץ' + 21: 3, # 'צ' + 17: 3, # 'ק' + 7: 3, # 'ר' + 10: 3, # 'ש' + 5: 3, # 'ת' + 32: 1, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 2, # '…' + }, + 25: { # 'ך' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 2, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 2, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 1, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 1, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 1, # 'ה' + 2: 0, # 'ו' + 24: 0, # 'ז' + 14: 1, # 'ח' + 22: 0, # 'ט' + 1: 0, # 'י' + 25: 0, # 'ך' + 15: 0, # 'כ' + 4: 1, # 'ל' + 11: 0, # 'ם' + 6: 1, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 0, # 'ר' + 10: 1, # 'ש' + 5: 0, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 15: { # 'כ' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 2, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 2, # 'ִ' + 37: 2, # 'ֵ' + 36: 2, # 'ֶ' + 31: 2, # 'ַ' + 29: 2, # 'ָ' + 35: 1, # 'ֹ' + 62: 1, # 'ֻ' + 28: 3, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 3, # 'א' + 8: 3, # 'ב' + 20: 2, # 'ג' + 16: 3, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 3, # 'ז' + 14: 3, # 'ח' + 22: 2, # 'ט' + 1: 3, # 'י' + 25: 3, # 'ך' + 15: 3, # 'כ' + 4: 3, # 'ל' + 11: 3, # 'ם' + 6: 3, # 'מ' + 23: 3, # 'ן' + 12: 3, # 'נ' + 19: 3, # 'ס' + 13: 2, # 'ע' + 26: 3, # 'ף' + 18: 3, # 'פ' + 27: 1, # 'ץ' + 21: 2, # 'צ' + 17: 2, # 'ק' + 7: 3, # 'ר' + 10: 3, # 'ש' + 5: 3, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 4: { # 'ל' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 1, # '\xa0' + 55: 1, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 3, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 2, # 'ִ' + 37: 2, # 'ֵ' + 36: 2, # 'ֶ' + 31: 2, # 'ַ' + 29: 2, # 'ָ' + 35: 2, # 'ֹ' + 62: 1, # 'ֻ' + 28: 2, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 3, # 'א' + 8: 3, # 'ב' + 20: 3, # 'ג' + 16: 3, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 3, # 'ז' + 14: 3, # 'ח' + 22: 3, # 'ט' + 1: 3, # 'י' + 25: 3, # 'ך' + 15: 3, # 'כ' + 4: 3, # 'ל' + 11: 3, # 'ם' + 6: 3, # 'מ' + 23: 2, # 'ן' + 12: 3, # 'נ' + 19: 3, # 'ס' + 13: 3, # 'ע' + 26: 2, # 'ף' + 18: 3, # 'פ' + 27: 2, # 'ץ' + 21: 3, # 'צ' + 17: 3, # 'ק' + 7: 3, # 'ר' + 10: 3, # 'ש' + 5: 3, # 'ת' + 32: 1, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 11: { # 'ם' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 1, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 1, # 'א' + 8: 1, # 'ב' + 20: 1, # 'ג' + 16: 0, # 'ד' + 3: 1, # 'ה' + 2: 1, # 'ו' + 24: 1, # 'ז' + 14: 1, # 'ח' + 22: 0, # 'ט' + 1: 1, # 'י' + 25: 0, # 'ך' + 15: 1, # 'כ' + 4: 1, # 'ל' + 11: 1, # 'ם' + 6: 1, # 'מ' + 23: 0, # 'ן' + 12: 1, # 'נ' + 19: 0, # 'ס' + 13: 1, # 'ע' + 26: 0, # 'ף' + 18: 1, # 'פ' + 27: 1, # 'ץ' + 21: 1, # 'צ' + 17: 1, # 'ק' + 7: 1, # 'ר' + 10: 1, # 'ש' + 5: 1, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 2, # '…' + }, + 6: { # 'מ' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 1, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 2, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 2, # 'ִ' + 37: 2, # 'ֵ' + 36: 2, # 'ֶ' + 31: 2, # 'ַ' + 29: 2, # 'ָ' + 35: 2, # 'ֹ' + 62: 1, # 'ֻ' + 28: 2, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 3, # 'א' + 8: 3, # 'ב' + 20: 3, # 'ג' + 16: 3, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 3, # 'ז' + 14: 3, # 'ח' + 22: 3, # 'ט' + 1: 3, # 'י' + 25: 2, # 'ך' + 15: 3, # 'כ' + 4: 3, # 'ל' + 11: 3, # 'ם' + 6: 3, # 'מ' + 23: 3, # 'ן' + 12: 3, # 'נ' + 19: 3, # 'ס' + 13: 3, # 'ע' + 26: 0, # 'ף' + 18: 3, # 'פ' + 27: 2, # 'ץ' + 21: 3, # 'צ' + 17: 3, # 'ק' + 7: 3, # 'ר' + 10: 3, # 'ש' + 5: 3, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 23: { # 'ן' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 1, # '\xa0' + 55: 0, # '´' + 48: 1, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 1, # 'א' + 8: 1, # 'ב' + 20: 1, # 'ג' + 16: 1, # 'ד' + 3: 1, # 'ה' + 2: 1, # 'ו' + 24: 0, # 'ז' + 14: 1, # 'ח' + 22: 1, # 'ט' + 1: 1, # 'י' + 25: 0, # 'ך' + 15: 1, # 'כ' + 4: 1, # 'ל' + 11: 1, # 'ם' + 6: 1, # 'מ' + 23: 0, # 'ן' + 12: 1, # 'נ' + 19: 1, # 'ס' + 13: 1, # 'ע' + 26: 1, # 'ף' + 18: 1, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 1, # 'ק' + 7: 1, # 'ר' + 10: 1, # 'ש' + 5: 1, # 'ת' + 32: 1, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 2, # '…' + }, + 12: { # 'נ' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 2, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 2, # 'ִ' + 37: 2, # 'ֵ' + 36: 2, # 'ֶ' + 31: 2, # 'ַ' + 29: 2, # 'ָ' + 35: 1, # 'ֹ' + 62: 1, # 'ֻ' + 28: 2, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 3, # 'א' + 8: 3, # 'ב' + 20: 3, # 'ג' + 16: 3, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 3, # 'ז' + 14: 3, # 'ח' + 22: 3, # 'ט' + 1: 3, # 'י' + 25: 2, # 'ך' + 15: 3, # 'כ' + 4: 3, # 'ל' + 11: 3, # 'ם' + 6: 3, # 'מ' + 23: 3, # 'ן' + 12: 3, # 'נ' + 19: 3, # 'ס' + 13: 3, # 'ע' + 26: 2, # 'ף' + 18: 3, # 'פ' + 27: 2, # 'ץ' + 21: 3, # 'צ' + 17: 3, # 'ק' + 7: 3, # 'ר' + 10: 3, # 'ש' + 5: 3, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 19: { # 'ס' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 1, # '\xa0' + 55: 1, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 2, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 2, # 'ִ' + 37: 1, # 'ֵ' + 36: 2, # 'ֶ' + 31: 2, # 'ַ' + 29: 1, # 'ָ' + 35: 1, # 'ֹ' + 62: 2, # 'ֻ' + 28: 2, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 2, # 'א' + 8: 3, # 'ב' + 20: 3, # 'ג' + 16: 3, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 1, # 'ז' + 14: 3, # 'ח' + 22: 3, # 'ט' + 1: 3, # 'י' + 25: 2, # 'ך' + 15: 3, # 'כ' + 4: 3, # 'ל' + 11: 2, # 'ם' + 6: 3, # 'מ' + 23: 2, # 'ן' + 12: 3, # 'נ' + 19: 2, # 'ס' + 13: 3, # 'ע' + 26: 3, # 'ף' + 18: 3, # 'פ' + 27: 0, # 'ץ' + 21: 2, # 'צ' + 17: 3, # 'ק' + 7: 3, # 'ר' + 10: 1, # 'ש' + 5: 3, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 13: { # 'ע' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 1, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 1, # 'ְ' + 59: 1, # 'ֱ' + 41: 2, # 'ֲ' + 33: 2, # 'ִ' + 37: 2, # 'ֵ' + 36: 2, # 'ֶ' + 31: 2, # 'ַ' + 29: 2, # 'ָ' + 35: 2, # 'ֹ' + 62: 1, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 2, # 'א' + 8: 3, # 'ב' + 20: 3, # 'ג' + 16: 3, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 3, # 'ז' + 14: 1, # 'ח' + 22: 3, # 'ט' + 1: 3, # 'י' + 25: 2, # 'ך' + 15: 2, # 'כ' + 4: 3, # 'ל' + 11: 3, # 'ם' + 6: 3, # 'מ' + 23: 2, # 'ן' + 12: 3, # 'נ' + 19: 3, # 'ס' + 13: 2, # 'ע' + 26: 1, # 'ף' + 18: 2, # 'פ' + 27: 2, # 'ץ' + 21: 3, # 'צ' + 17: 3, # 'ק' + 7: 3, # 'ר' + 10: 3, # 'ש' + 5: 3, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 26: { # 'ף' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 1, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 0, # 'ה' + 2: 1, # 'ו' + 24: 0, # 'ז' + 14: 1, # 'ח' + 22: 0, # 'ט' + 1: 0, # 'י' + 25: 0, # 'ך' + 15: 1, # 'כ' + 4: 1, # 'ל' + 11: 0, # 'ם' + 6: 1, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 1, # 'ס' + 13: 0, # 'ע' + 26: 1, # 'ף' + 18: 1, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 1, # 'ק' + 7: 1, # 'ר' + 10: 1, # 'ש' + 5: 0, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 18: { # 'פ' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 1, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 2, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 2, # 'ִ' + 37: 1, # 'ֵ' + 36: 2, # 'ֶ' + 31: 1, # 'ַ' + 29: 2, # 'ָ' + 35: 1, # 'ֹ' + 62: 1, # 'ֻ' + 28: 2, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 3, # 'א' + 8: 2, # 'ב' + 20: 3, # 'ג' + 16: 2, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 2, # 'ז' + 14: 3, # 'ח' + 22: 3, # 'ט' + 1: 3, # 'י' + 25: 2, # 'ך' + 15: 3, # 'כ' + 4: 3, # 'ל' + 11: 2, # 'ם' + 6: 2, # 'מ' + 23: 3, # 'ן' + 12: 3, # 'נ' + 19: 3, # 'ס' + 13: 3, # 'ע' + 26: 2, # 'ף' + 18: 2, # 'פ' + 27: 2, # 'ץ' + 21: 3, # 'צ' + 17: 3, # 'ק' + 7: 3, # 'ר' + 10: 3, # 'ש' + 5: 3, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 27: { # 'ץ' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 1, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 1, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 0, # 'ה' + 2: 0, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 0, # 'י' + 25: 0, # 'ך' + 15: 0, # 'כ' + 4: 1, # 'ל' + 11: 0, # 'ם' + 6: 0, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 1, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 1, # 'ר' + 10: 0, # 'ש' + 5: 1, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 21: { # 'צ' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 1, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 2, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 2, # 'ִ' + 37: 2, # 'ֵ' + 36: 1, # 'ֶ' + 31: 2, # 'ַ' + 29: 2, # 'ָ' + 35: 1, # 'ֹ' + 62: 1, # 'ֻ' + 28: 2, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 3, # 'א' + 8: 3, # 'ב' + 20: 2, # 'ג' + 16: 3, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 1, # 'ז' + 14: 3, # 'ח' + 22: 2, # 'ט' + 1: 3, # 'י' + 25: 1, # 'ך' + 15: 1, # 'כ' + 4: 3, # 'ל' + 11: 2, # 'ם' + 6: 3, # 'מ' + 23: 2, # 'ן' + 12: 3, # 'נ' + 19: 1, # 'ס' + 13: 3, # 'ע' + 26: 2, # 'ף' + 18: 3, # 'פ' + 27: 2, # 'ץ' + 21: 2, # 'צ' + 17: 3, # 'ק' + 7: 3, # 'ר' + 10: 0, # 'ש' + 5: 3, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 17: { # 'ק' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 1, # '\xa0' + 55: 1, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 2, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 2, # 'ִ' + 37: 2, # 'ֵ' + 36: 1, # 'ֶ' + 31: 2, # 'ַ' + 29: 2, # 'ָ' + 35: 2, # 'ֹ' + 62: 1, # 'ֻ' + 28: 2, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 3, # 'א' + 8: 3, # 'ב' + 20: 2, # 'ג' + 16: 3, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 2, # 'ז' + 14: 3, # 'ח' + 22: 3, # 'ט' + 1: 3, # 'י' + 25: 1, # 'ך' + 15: 1, # 'כ' + 4: 3, # 'ל' + 11: 2, # 'ם' + 6: 3, # 'מ' + 23: 2, # 'ן' + 12: 3, # 'נ' + 19: 3, # 'ס' + 13: 3, # 'ע' + 26: 2, # 'ף' + 18: 3, # 'פ' + 27: 2, # 'ץ' + 21: 3, # 'צ' + 17: 2, # 'ק' + 7: 3, # 'ר' + 10: 3, # 'ש' + 5: 3, # 'ת' + 32: 0, # '–' + 52: 1, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 7: { # 'ר' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 1, # '\xa0' + 55: 2, # '´' + 48: 1, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 2, # 'ְ' + 59: 0, # 'ֱ' + 41: 1, # 'ֲ' + 33: 2, # 'ִ' + 37: 2, # 'ֵ' + 36: 2, # 'ֶ' + 31: 2, # 'ַ' + 29: 2, # 'ָ' + 35: 2, # 'ֹ' + 62: 1, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 3, # 'א' + 8: 3, # 'ב' + 20: 3, # 'ג' + 16: 3, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 3, # 'ז' + 14: 3, # 'ח' + 22: 3, # 'ט' + 1: 3, # 'י' + 25: 3, # 'ך' + 15: 3, # 'כ' + 4: 3, # 'ל' + 11: 3, # 'ם' + 6: 3, # 'מ' + 23: 3, # 'ן' + 12: 3, # 'נ' + 19: 3, # 'ס' + 13: 3, # 'ע' + 26: 2, # 'ף' + 18: 3, # 'פ' + 27: 3, # 'ץ' + 21: 3, # 'צ' + 17: 3, # 'ק' + 7: 3, # 'ר' + 10: 3, # 'ש' + 5: 3, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 2, # '…' + }, + 10: { # 'ש' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 1, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 1, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 1, # 'ִ' + 37: 1, # 'ֵ' + 36: 1, # 'ֶ' + 31: 1, # 'ַ' + 29: 1, # 'ָ' + 35: 1, # 'ֹ' + 62: 1, # 'ֻ' + 28: 2, # 'ּ' + 38: 3, # 'ׁ' + 45: 2, # 'ׂ' + 9: 3, # 'א' + 8: 3, # 'ב' + 20: 3, # 'ג' + 16: 3, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 2, # 'ז' + 14: 3, # 'ח' + 22: 3, # 'ט' + 1: 3, # 'י' + 25: 3, # 'ך' + 15: 3, # 'כ' + 4: 3, # 'ל' + 11: 3, # 'ם' + 6: 3, # 'מ' + 23: 2, # 'ן' + 12: 3, # 'נ' + 19: 2, # 'ס' + 13: 3, # 'ע' + 26: 2, # 'ף' + 18: 3, # 'פ' + 27: 1, # 'ץ' + 21: 2, # 'צ' + 17: 3, # 'ק' + 7: 3, # 'ר' + 10: 3, # 'ש' + 5: 3, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 1, # '…' + }, + 5: { # 'ת' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 1, # '\xa0' + 55: 0, # '´' + 48: 1, # '¼' + 39: 1, # '½' + 57: 0, # '¾' + 30: 2, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 2, # 'ִ' + 37: 2, # 'ֵ' + 36: 2, # 'ֶ' + 31: 2, # 'ַ' + 29: 2, # 'ָ' + 35: 1, # 'ֹ' + 62: 1, # 'ֻ' + 28: 2, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 3, # 'א' + 8: 3, # 'ב' + 20: 3, # 'ג' + 16: 2, # 'ד' + 3: 3, # 'ה' + 2: 3, # 'ו' + 24: 2, # 'ז' + 14: 3, # 'ח' + 22: 2, # 'ט' + 1: 3, # 'י' + 25: 2, # 'ך' + 15: 3, # 'כ' + 4: 3, # 'ל' + 11: 3, # 'ם' + 6: 3, # 'מ' + 23: 3, # 'ן' + 12: 3, # 'נ' + 19: 2, # 'ס' + 13: 3, # 'ע' + 26: 2, # 'ף' + 18: 3, # 'פ' + 27: 1, # 'ץ' + 21: 2, # 'צ' + 17: 3, # 'ק' + 7: 3, # 'ר' + 10: 3, # 'ש' + 5: 3, # 'ת' + 32: 1, # '–' + 52: 1, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 2, # '…' + }, + 32: { # '–' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 1, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 1, # 'א' + 8: 1, # 'ב' + 20: 1, # 'ג' + 16: 1, # 'ד' + 3: 1, # 'ה' + 2: 1, # 'ו' + 24: 0, # 'ז' + 14: 1, # 'ח' + 22: 0, # 'ט' + 1: 1, # 'י' + 25: 0, # 'ך' + 15: 1, # 'כ' + 4: 1, # 'ל' + 11: 0, # 'ם' + 6: 1, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 1, # 'ס' + 13: 1, # 'ע' + 26: 0, # 'ף' + 18: 1, # 'פ' + 27: 0, # 'ץ' + 21: 1, # 'צ' + 17: 0, # 'ק' + 7: 1, # 'ר' + 10: 1, # 'ש' + 5: 1, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 52: { # '’' + 50: 1, # 'a' + 60: 0, # 'c' + 61: 1, # 'd' + 42: 1, # 'e' + 53: 1, # 'i' + 56: 1, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 1, # 'r' + 43: 2, # 's' + 44: 2, # 't' + 63: 1, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 0, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 0, # 'ה' + 2: 1, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 0, # 'י' + 25: 0, # 'ך' + 15: 0, # 'כ' + 4: 0, # 'ל' + 11: 0, # 'ם' + 6: 1, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 0, # 'ר' + 10: 0, # 'ש' + 5: 1, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 47: { # '“' + 50: 1, # 'a' + 60: 1, # 'c' + 61: 1, # 'd' + 42: 1, # 'e' + 53: 1, # 'i' + 56: 1, # 'l' + 54: 1, # 'n' + 49: 1, # 'o' + 51: 1, # 'r' + 43: 1, # 's' + 44: 1, # 't' + 63: 1, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 2, # 'א' + 8: 1, # 'ב' + 20: 1, # 'ג' + 16: 1, # 'ד' + 3: 1, # 'ה' + 2: 1, # 'ו' + 24: 1, # 'ז' + 14: 1, # 'ח' + 22: 1, # 'ט' + 1: 1, # 'י' + 25: 0, # 'ך' + 15: 1, # 'כ' + 4: 1, # 'ל' + 11: 0, # 'ם' + 6: 1, # 'מ' + 23: 0, # 'ן' + 12: 1, # 'נ' + 19: 1, # 'ס' + 13: 1, # 'ע' + 26: 0, # 'ף' + 18: 1, # 'פ' + 27: 0, # 'ץ' + 21: 1, # 'צ' + 17: 1, # 'ק' + 7: 1, # 'ר' + 10: 1, # 'ש' + 5: 1, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 46: { # '”' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 1, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 1, # 'א' + 8: 1, # 'ב' + 20: 1, # 'ג' + 16: 0, # 'ד' + 3: 0, # 'ה' + 2: 0, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 1, # 'י' + 25: 0, # 'ך' + 15: 1, # 'כ' + 4: 1, # 'ל' + 11: 0, # 'ם' + 6: 1, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 1, # 'צ' + 17: 0, # 'ק' + 7: 1, # 'ר' + 10: 0, # 'ש' + 5: 0, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 0, # '†' + 40: 0, # '…' + }, + 58: { # '†' + 50: 0, # 'a' + 60: 0, # 'c' + 61: 0, # 'd' + 42: 0, # 'e' + 53: 0, # 'i' + 56: 0, # 'l' + 54: 0, # 'n' + 49: 0, # 'o' + 51: 0, # 'r' + 43: 0, # 's' + 44: 0, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 0, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 0, # 'ה' + 2: 0, # 'ו' + 24: 0, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 0, # 'י' + 25: 0, # 'ך' + 15: 0, # 'כ' + 4: 0, # 'ל' + 11: 0, # 'ם' + 6: 0, # 'מ' + 23: 0, # 'ן' + 12: 0, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 0, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 0, # 'ר' + 10: 0, # 'ש' + 5: 0, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 0, # '”' + 58: 2, # '†' + 40: 0, # '…' + }, + 40: { # '…' + 50: 1, # 'a' + 60: 1, # 'c' + 61: 1, # 'd' + 42: 1, # 'e' + 53: 1, # 'i' + 56: 0, # 'l' + 54: 1, # 'n' + 49: 0, # 'o' + 51: 1, # 'r' + 43: 1, # 's' + 44: 1, # 't' + 63: 0, # 'u' + 34: 0, # '\xa0' + 55: 0, # '´' + 48: 0, # '¼' + 39: 0, # '½' + 57: 0, # '¾' + 30: 0, # 'ְ' + 59: 0, # 'ֱ' + 41: 0, # 'ֲ' + 33: 0, # 'ִ' + 37: 0, # 'ֵ' + 36: 0, # 'ֶ' + 31: 0, # 'ַ' + 29: 0, # 'ָ' + 35: 0, # 'ֹ' + 62: 0, # 'ֻ' + 28: 0, # 'ּ' + 38: 0, # 'ׁ' + 45: 0, # 'ׂ' + 9: 1, # 'א' + 8: 0, # 'ב' + 20: 0, # 'ג' + 16: 0, # 'ד' + 3: 1, # 'ה' + 2: 1, # 'ו' + 24: 1, # 'ז' + 14: 0, # 'ח' + 22: 0, # 'ט' + 1: 1, # 'י' + 25: 0, # 'ך' + 15: 1, # 'כ' + 4: 1, # 'ל' + 11: 0, # 'ם' + 6: 1, # 'מ' + 23: 0, # 'ן' + 12: 1, # 'נ' + 19: 0, # 'ס' + 13: 0, # 'ע' + 26: 0, # 'ף' + 18: 1, # 'פ' + 27: 0, # 'ץ' + 21: 0, # 'צ' + 17: 0, # 'ק' + 7: 1, # 'ר' + 10: 1, # 'ש' + 5: 1, # 'ת' + 32: 0, # '–' + 52: 0, # '’' + 47: 0, # '“' + 46: 1, # '”' + 58: 0, # '†' + 40: 2, # '…' + }, +} + +# 255: Undefined characters that did not exist in training text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 +# 251: Control characters + +# Character Mapping Table(s): +WINDOWS_1255_HEBREW_CHAR_TO_ORDER = { + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 69, # 'A' + 66: 91, # 'B' + 67: 79, # 'C' + 68: 80, # 'D' + 69: 92, # 'E' + 70: 89, # 'F' + 71: 97, # 'G' + 72: 90, # 'H' + 73: 68, # 'I' + 74: 111, # 'J' + 75: 112, # 'K' + 76: 82, # 'L' + 77: 73, # 'M' + 78: 95, # 'N' + 79: 85, # 'O' + 80: 78, # 'P' + 81: 121, # 'Q' + 82: 86, # 'R' + 83: 71, # 'S' + 84: 67, # 'T' + 85: 102, # 'U' + 86: 107, # 'V' + 87: 84, # 'W' + 88: 114, # 'X' + 89: 103, # 'Y' + 90: 115, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 50, # 'a' + 98: 74, # 'b' + 99: 60, # 'c' + 100: 61, # 'd' + 101: 42, # 'e' + 102: 76, # 'f' + 103: 70, # 'g' + 104: 64, # 'h' + 105: 53, # 'i' + 106: 105, # 'j' + 107: 93, # 'k' + 108: 56, # 'l' + 109: 65, # 'm' + 110: 54, # 'n' + 111: 49, # 'o' + 112: 66, # 'p' + 113: 110, # 'q' + 114: 51, # 'r' + 115: 43, # 's' + 116: 44, # 't' + 117: 63, # 'u' + 118: 81, # 'v' + 119: 77, # 'w' + 120: 98, # 'x' + 121: 75, # 'y' + 122: 108, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 124, # '€' + 129: 202, # None + 130: 203, # '‚' + 131: 204, # 'ƒ' + 132: 205, # '„' + 133: 40, # '…' + 134: 58, # '†' + 135: 206, # '‡' + 136: 207, # 'ˆ' + 137: 208, # '‰' + 138: 209, # None + 139: 210, # '‹' + 140: 211, # None + 141: 212, # None + 142: 213, # None + 143: 214, # None + 144: 215, # None + 145: 83, # '‘' + 146: 52, # '’' + 147: 47, # '“' + 148: 46, # '”' + 149: 72, # '•' + 150: 32, # '–' + 151: 94, # '—' + 152: 216, # '˜' + 153: 113, # '™' + 154: 217, # None + 155: 109, # '›' + 156: 218, # None + 157: 219, # None + 158: 220, # None + 159: 221, # None + 160: 34, # '\xa0' + 161: 116, # '¡' + 162: 222, # '¢' + 163: 118, # '£' + 164: 100, # '₪' + 165: 223, # '¥' + 166: 224, # '¦' + 167: 117, # '§' + 168: 119, # '¨' + 169: 104, # '©' + 170: 125, # '×' + 171: 225, # '«' + 172: 226, # '¬' + 173: 87, # '\xad' + 174: 99, # '®' + 175: 227, # '¯' + 176: 106, # '°' + 177: 122, # '±' + 178: 123, # '²' + 179: 228, # '³' + 180: 55, # '´' + 181: 229, # 'µ' + 182: 230, # '¶' + 183: 101, # '·' + 184: 231, # '¸' + 185: 232, # '¹' + 186: 120, # '÷' + 187: 233, # '»' + 188: 48, # '¼' + 189: 39, # '½' + 190: 57, # '¾' + 191: 234, # '¿' + 192: 30, # 'ְ' + 193: 59, # 'ֱ' + 194: 41, # 'ֲ' + 195: 88, # 'ֳ' + 196: 33, # 'ִ' + 197: 37, # 'ֵ' + 198: 36, # 'ֶ' + 199: 31, # 'ַ' + 200: 29, # 'ָ' + 201: 35, # 'ֹ' + 202: 235, # None + 203: 62, # 'ֻ' + 204: 28, # 'ּ' + 205: 236, # 'ֽ' + 206: 126, # '־' + 207: 237, # 'ֿ' + 208: 238, # '׀' + 209: 38, # 'ׁ' + 210: 45, # 'ׂ' + 211: 239, # '׃' + 212: 240, # 'װ' + 213: 241, # 'ױ' + 214: 242, # 'ײ' + 215: 243, # '׳' + 216: 127, # '״' + 217: 244, # None + 218: 245, # None + 219: 246, # None + 220: 247, # None + 221: 248, # None + 222: 249, # None + 223: 250, # None + 224: 9, # 'א' + 225: 8, # 'ב' + 226: 20, # 'ג' + 227: 16, # 'ד' + 228: 3, # 'ה' + 229: 2, # 'ו' + 230: 24, # 'ז' + 231: 14, # 'ח' + 232: 22, # 'ט' + 233: 1, # 'י' + 234: 25, # 'ך' + 235: 15, # 'כ' + 236: 4, # 'ל' + 237: 11, # 'ם' + 238: 6, # 'מ' + 239: 23, # 'ן' + 240: 12, # 'נ' + 241: 19, # 'ס' + 242: 13, # 'ע' + 243: 26, # 'ף' + 244: 18, # 'פ' + 245: 27, # 'ץ' + 246: 21, # 'צ' + 247: 17, # 'ק' + 248: 7, # 'ר' + 249: 10, # 'ש' + 250: 5, # 'ת' + 251: 251, # None + 252: 252, # None + 253: 128, # '\u200e' + 254: 96, # '\u200f' + 255: 253, # None +} + +WINDOWS_1255_HEBREW_MODEL = SingleByteCharSetModel(charset_name='windows-1255', + language='Hebrew', + char_to_order_map=WINDOWS_1255_HEBREW_CHAR_TO_ORDER, + language_model=HEBREW_LANG_MODEL, + typical_positive_ratio=0.984004, + keep_ascii_letters=False, + alphabet='אבגדהוזחטיךכלםמןנסעףפץצקרשתװױײ') + diff --git a/venv/lib/python3.8/site-packages/chardet/langhungarianmodel.py b/venv/lib/python3.8/site-packages/chardet/langhungarianmodel.py new file mode 100644 index 0000000..24a097f --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/langhungarianmodel.py @@ -0,0 +1,4650 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from chardet.sbcharsetprober import SingleByteCharSetModel + + +# 3: Positive +# 2: Likely +# 1: Unlikely +# 0: Negative + +HUNGARIAN_LANG_MODEL = { + 28: { # 'A' + 28: 0, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 2, # 'D' + 32: 1, # 'E' + 50: 1, # 'F' + 49: 2, # 'G' + 38: 1, # 'H' + 39: 2, # 'I' + 53: 1, # 'J' + 36: 2, # 'K' + 41: 2, # 'L' + 34: 1, # 'M' + 35: 2, # 'N' + 47: 1, # 'O' + 46: 2, # 'P' + 43: 2, # 'R' + 33: 2, # 'S' + 37: 2, # 'T' + 57: 1, # 'U' + 48: 1, # 'V' + 55: 1, # 'Y' + 52: 2, # 'Z' + 2: 0, # 'a' + 18: 1, # 'b' + 26: 1, # 'c' + 17: 2, # 'd' + 1: 1, # 'e' + 27: 1, # 'f' + 12: 1, # 'g' + 20: 1, # 'h' + 9: 1, # 'i' + 22: 1, # 'j' + 7: 2, # 'k' + 6: 2, # 'l' + 13: 2, # 'm' + 4: 2, # 'n' + 8: 0, # 'o' + 23: 2, # 'p' + 10: 2, # 'r' + 5: 1, # 's' + 3: 1, # 't' + 21: 1, # 'u' + 19: 1, # 'v' + 62: 1, # 'x' + 16: 0, # 'y' + 11: 3, # 'z' + 51: 1, # 'Á' + 44: 0, # 'É' + 61: 1, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 0, # 'á' + 15: 0, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 40: { # 'B' + 28: 2, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 2, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 1, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 1, # 'L' + 34: 0, # 'M' + 35: 1, # 'N' + 47: 2, # 'O' + 46: 0, # 'P' + 43: 1, # 'R' + 33: 1, # 'S' + 37: 1, # 'T' + 57: 1, # 'U' + 48: 1, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 2, # 'a' + 18: 0, # 'b' + 26: 0, # 'c' + 17: 0, # 'd' + 1: 3, # 'e' + 27: 0, # 'f' + 12: 0, # 'g' + 20: 0, # 'h' + 9: 2, # 'i' + 22: 1, # 'j' + 7: 0, # 'k' + 6: 1, # 'l' + 13: 0, # 'm' + 4: 0, # 'n' + 8: 2, # 'o' + 23: 1, # 'p' + 10: 2, # 'r' + 5: 0, # 's' + 3: 0, # 't' + 21: 3, # 'u' + 19: 0, # 'v' + 62: 0, # 'x' + 16: 1, # 'y' + 11: 0, # 'z' + 51: 1, # 'Á' + 44: 1, # 'É' + 61: 1, # 'Í' + 58: 1, # 'Ó' + 59: 1, # 'Ö' + 60: 1, # 'Ú' + 63: 1, # 'Ü' + 14: 2, # 'á' + 15: 2, # 'é' + 30: 1, # 'í' + 25: 1, # 'ó' + 24: 1, # 'ö' + 31: 1, # 'ú' + 29: 1, # 'ü' + 42: 1, # 'ő' + 56: 1, # 'ű' + }, + 54: { # 'C' + 28: 1, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 1, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 1, # 'H' + 39: 2, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 1, # 'L' + 34: 1, # 'M' + 35: 0, # 'N' + 47: 1, # 'O' + 46: 1, # 'P' + 43: 1, # 'R' + 33: 2, # 'S' + 37: 1, # 'T' + 57: 1, # 'U' + 48: 0, # 'V' + 55: 1, # 'Y' + 52: 1, # 'Z' + 2: 2, # 'a' + 18: 0, # 'b' + 26: 0, # 'c' + 17: 0, # 'd' + 1: 1, # 'e' + 27: 0, # 'f' + 12: 0, # 'g' + 20: 1, # 'h' + 9: 1, # 'i' + 22: 0, # 'j' + 7: 0, # 'k' + 6: 1, # 'l' + 13: 0, # 'm' + 4: 0, # 'n' + 8: 2, # 'o' + 23: 0, # 'p' + 10: 1, # 'r' + 5: 3, # 's' + 3: 0, # 't' + 21: 1, # 'u' + 19: 0, # 'v' + 62: 0, # 'x' + 16: 1, # 'y' + 11: 1, # 'z' + 51: 1, # 'Á' + 44: 1, # 'É' + 61: 1, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 1, # 'á' + 15: 1, # 'é' + 30: 1, # 'í' + 25: 1, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 45: { # 'D' + 28: 2, # 'A' + 40: 1, # 'B' + 54: 0, # 'C' + 45: 1, # 'D' + 32: 2, # 'E' + 50: 1, # 'F' + 49: 1, # 'G' + 38: 1, # 'H' + 39: 2, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 0, # 'L' + 34: 1, # 'M' + 35: 1, # 'N' + 47: 2, # 'O' + 46: 0, # 'P' + 43: 1, # 'R' + 33: 1, # 'S' + 37: 1, # 'T' + 57: 1, # 'U' + 48: 1, # 'V' + 55: 1, # 'Y' + 52: 1, # 'Z' + 2: 2, # 'a' + 18: 0, # 'b' + 26: 0, # 'c' + 17: 0, # 'd' + 1: 3, # 'e' + 27: 0, # 'f' + 12: 0, # 'g' + 20: 0, # 'h' + 9: 1, # 'i' + 22: 0, # 'j' + 7: 0, # 'k' + 6: 0, # 'l' + 13: 0, # 'm' + 4: 0, # 'n' + 8: 1, # 'o' + 23: 0, # 'p' + 10: 2, # 'r' + 5: 0, # 's' + 3: 0, # 't' + 21: 2, # 'u' + 19: 0, # 'v' + 62: 0, # 'x' + 16: 1, # 'y' + 11: 1, # 'z' + 51: 1, # 'Á' + 44: 1, # 'É' + 61: 1, # 'Í' + 58: 1, # 'Ó' + 59: 1, # 'Ö' + 60: 1, # 'Ú' + 63: 1, # 'Ü' + 14: 1, # 'á' + 15: 1, # 'é' + 30: 1, # 'í' + 25: 1, # 'ó' + 24: 1, # 'ö' + 31: 1, # 'ú' + 29: 1, # 'ü' + 42: 1, # 'ő' + 56: 0, # 'ű' + }, + 32: { # 'E' + 28: 1, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 1, # 'E' + 50: 1, # 'F' + 49: 2, # 'G' + 38: 1, # 'H' + 39: 1, # 'I' + 53: 1, # 'J' + 36: 2, # 'K' + 41: 2, # 'L' + 34: 2, # 'M' + 35: 2, # 'N' + 47: 1, # 'O' + 46: 1, # 'P' + 43: 2, # 'R' + 33: 2, # 'S' + 37: 2, # 'T' + 57: 1, # 'U' + 48: 1, # 'V' + 55: 1, # 'Y' + 52: 1, # 'Z' + 2: 1, # 'a' + 18: 1, # 'b' + 26: 1, # 'c' + 17: 2, # 'd' + 1: 1, # 'e' + 27: 1, # 'f' + 12: 3, # 'g' + 20: 1, # 'h' + 9: 1, # 'i' + 22: 1, # 'j' + 7: 1, # 'k' + 6: 2, # 'l' + 13: 2, # 'm' + 4: 2, # 'n' + 8: 0, # 'o' + 23: 1, # 'p' + 10: 2, # 'r' + 5: 2, # 's' + 3: 1, # 't' + 21: 2, # 'u' + 19: 1, # 'v' + 62: 1, # 'x' + 16: 0, # 'y' + 11: 3, # 'z' + 51: 1, # 'Á' + 44: 1, # 'É' + 61: 0, # 'Í' + 58: 1, # 'Ó' + 59: 1, # 'Ö' + 60: 0, # 'Ú' + 63: 1, # 'Ü' + 14: 0, # 'á' + 15: 0, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 1, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 50: { # 'F' + 28: 1, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 1, # 'E' + 50: 1, # 'F' + 49: 0, # 'G' + 38: 1, # 'H' + 39: 1, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 1, # 'L' + 34: 1, # 'M' + 35: 1, # 'N' + 47: 1, # 'O' + 46: 0, # 'P' + 43: 1, # 'R' + 33: 0, # 'S' + 37: 1, # 'T' + 57: 1, # 'U' + 48: 0, # 'V' + 55: 1, # 'Y' + 52: 0, # 'Z' + 2: 2, # 'a' + 18: 0, # 'b' + 26: 0, # 'c' + 17: 0, # 'd' + 1: 2, # 'e' + 27: 1, # 'f' + 12: 0, # 'g' + 20: 0, # 'h' + 9: 2, # 'i' + 22: 1, # 'j' + 7: 0, # 'k' + 6: 1, # 'l' + 13: 0, # 'm' + 4: 0, # 'n' + 8: 2, # 'o' + 23: 0, # 'p' + 10: 2, # 'r' + 5: 0, # 's' + 3: 0, # 't' + 21: 1, # 'u' + 19: 0, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 0, # 'z' + 51: 1, # 'Á' + 44: 1, # 'É' + 61: 0, # 'Í' + 58: 1, # 'Ó' + 59: 1, # 'Ö' + 60: 0, # 'Ú' + 63: 1, # 'Ü' + 14: 1, # 'á' + 15: 1, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 2, # 'ö' + 31: 1, # 'ú' + 29: 1, # 'ü' + 42: 1, # 'ő' + 56: 1, # 'ű' + }, + 49: { # 'G' + 28: 2, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 2, # 'E' + 50: 1, # 'F' + 49: 1, # 'G' + 38: 1, # 'H' + 39: 1, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 1, # 'L' + 34: 1, # 'M' + 35: 1, # 'N' + 47: 1, # 'O' + 46: 1, # 'P' + 43: 1, # 'R' + 33: 1, # 'S' + 37: 1, # 'T' + 57: 1, # 'U' + 48: 1, # 'V' + 55: 2, # 'Y' + 52: 1, # 'Z' + 2: 2, # 'a' + 18: 0, # 'b' + 26: 0, # 'c' + 17: 0, # 'd' + 1: 2, # 'e' + 27: 0, # 'f' + 12: 0, # 'g' + 20: 0, # 'h' + 9: 1, # 'i' + 22: 0, # 'j' + 7: 0, # 'k' + 6: 1, # 'l' + 13: 0, # 'm' + 4: 0, # 'n' + 8: 2, # 'o' + 23: 0, # 'p' + 10: 2, # 'r' + 5: 0, # 's' + 3: 0, # 't' + 21: 1, # 'u' + 19: 0, # 'v' + 62: 0, # 'x' + 16: 2, # 'y' + 11: 0, # 'z' + 51: 1, # 'Á' + 44: 1, # 'É' + 61: 1, # 'Í' + 58: 1, # 'Ó' + 59: 1, # 'Ö' + 60: 1, # 'Ú' + 63: 1, # 'Ü' + 14: 1, # 'á' + 15: 1, # 'é' + 30: 0, # 'í' + 25: 1, # 'ó' + 24: 1, # 'ö' + 31: 1, # 'ú' + 29: 1, # 'ü' + 42: 1, # 'ő' + 56: 0, # 'ű' + }, + 38: { # 'H' + 28: 2, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 0, # 'D' + 32: 1, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 1, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 1, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 1, # 'O' + 46: 0, # 'P' + 43: 1, # 'R' + 33: 1, # 'S' + 37: 1, # 'T' + 57: 1, # 'U' + 48: 0, # 'V' + 55: 1, # 'Y' + 52: 0, # 'Z' + 2: 3, # 'a' + 18: 0, # 'b' + 26: 0, # 'c' + 17: 0, # 'd' + 1: 2, # 'e' + 27: 0, # 'f' + 12: 0, # 'g' + 20: 0, # 'h' + 9: 2, # 'i' + 22: 1, # 'j' + 7: 0, # 'k' + 6: 1, # 'l' + 13: 1, # 'm' + 4: 0, # 'n' + 8: 3, # 'o' + 23: 0, # 'p' + 10: 1, # 'r' + 5: 0, # 's' + 3: 0, # 't' + 21: 2, # 'u' + 19: 0, # 'v' + 62: 0, # 'x' + 16: 1, # 'y' + 11: 0, # 'z' + 51: 2, # 'Á' + 44: 2, # 'É' + 61: 1, # 'Í' + 58: 1, # 'Ó' + 59: 1, # 'Ö' + 60: 1, # 'Ú' + 63: 1, # 'Ü' + 14: 2, # 'á' + 15: 1, # 'é' + 30: 2, # 'í' + 25: 1, # 'ó' + 24: 1, # 'ö' + 31: 1, # 'ú' + 29: 1, # 'ü' + 42: 1, # 'ő' + 56: 1, # 'ű' + }, + 39: { # 'I' + 28: 2, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 1, # 'E' + 50: 1, # 'F' + 49: 1, # 'G' + 38: 1, # 'H' + 39: 2, # 'I' + 53: 1, # 'J' + 36: 2, # 'K' + 41: 2, # 'L' + 34: 1, # 'M' + 35: 2, # 'N' + 47: 1, # 'O' + 46: 1, # 'P' + 43: 1, # 'R' + 33: 2, # 'S' + 37: 1, # 'T' + 57: 1, # 'U' + 48: 1, # 'V' + 55: 0, # 'Y' + 52: 2, # 'Z' + 2: 0, # 'a' + 18: 1, # 'b' + 26: 1, # 'c' + 17: 2, # 'd' + 1: 0, # 'e' + 27: 1, # 'f' + 12: 2, # 'g' + 20: 1, # 'h' + 9: 0, # 'i' + 22: 1, # 'j' + 7: 1, # 'k' + 6: 2, # 'l' + 13: 2, # 'm' + 4: 1, # 'n' + 8: 0, # 'o' + 23: 1, # 'p' + 10: 2, # 'r' + 5: 2, # 's' + 3: 2, # 't' + 21: 0, # 'u' + 19: 1, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 1, # 'z' + 51: 1, # 'Á' + 44: 1, # 'É' + 61: 0, # 'Í' + 58: 1, # 'Ó' + 59: 1, # 'Ö' + 60: 1, # 'Ú' + 63: 1, # 'Ü' + 14: 0, # 'á' + 15: 0, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 53: { # 'J' + 28: 2, # 'A' + 40: 0, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 2, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 1, # 'H' + 39: 1, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 1, # 'L' + 34: 1, # 'M' + 35: 1, # 'N' + 47: 1, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 1, # 'S' + 37: 1, # 'T' + 57: 1, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 1, # 'Z' + 2: 2, # 'a' + 18: 0, # 'b' + 26: 0, # 'c' + 17: 0, # 'd' + 1: 2, # 'e' + 27: 0, # 'f' + 12: 0, # 'g' + 20: 0, # 'h' + 9: 1, # 'i' + 22: 0, # 'j' + 7: 0, # 'k' + 6: 0, # 'l' + 13: 0, # 'm' + 4: 0, # 'n' + 8: 1, # 'o' + 23: 0, # 'p' + 10: 0, # 'r' + 5: 0, # 's' + 3: 0, # 't' + 21: 2, # 'u' + 19: 0, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 0, # 'z' + 51: 1, # 'Á' + 44: 1, # 'É' + 61: 0, # 'Í' + 58: 1, # 'Ó' + 59: 1, # 'Ö' + 60: 1, # 'Ú' + 63: 1, # 'Ü' + 14: 2, # 'á' + 15: 1, # 'é' + 30: 0, # 'í' + 25: 2, # 'ó' + 24: 2, # 'ö' + 31: 1, # 'ú' + 29: 0, # 'ü' + 42: 1, # 'ő' + 56: 0, # 'ű' + }, + 36: { # 'K' + 28: 2, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 2, # 'E' + 50: 1, # 'F' + 49: 0, # 'G' + 38: 1, # 'H' + 39: 2, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 1, # 'L' + 34: 1, # 'M' + 35: 1, # 'N' + 47: 2, # 'O' + 46: 0, # 'P' + 43: 1, # 'R' + 33: 1, # 'S' + 37: 1, # 'T' + 57: 1, # 'U' + 48: 1, # 'V' + 55: 1, # 'Y' + 52: 0, # 'Z' + 2: 2, # 'a' + 18: 0, # 'b' + 26: 0, # 'c' + 17: 0, # 'd' + 1: 2, # 'e' + 27: 1, # 'f' + 12: 0, # 'g' + 20: 1, # 'h' + 9: 3, # 'i' + 22: 0, # 'j' + 7: 0, # 'k' + 6: 1, # 'l' + 13: 1, # 'm' + 4: 1, # 'n' + 8: 2, # 'o' + 23: 0, # 'p' + 10: 2, # 'r' + 5: 0, # 's' + 3: 0, # 't' + 21: 1, # 'u' + 19: 1, # 'v' + 62: 0, # 'x' + 16: 1, # 'y' + 11: 0, # 'z' + 51: 1, # 'Á' + 44: 1, # 'É' + 61: 1, # 'Í' + 58: 1, # 'Ó' + 59: 2, # 'Ö' + 60: 1, # 'Ú' + 63: 1, # 'Ü' + 14: 2, # 'á' + 15: 2, # 'é' + 30: 1, # 'í' + 25: 1, # 'ó' + 24: 2, # 'ö' + 31: 1, # 'ú' + 29: 2, # 'ü' + 42: 1, # 'ő' + 56: 0, # 'ű' + }, + 41: { # 'L' + 28: 2, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 2, # 'E' + 50: 1, # 'F' + 49: 1, # 'G' + 38: 1, # 'H' + 39: 2, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 2, # 'L' + 34: 1, # 'M' + 35: 1, # 'N' + 47: 2, # 'O' + 46: 0, # 'P' + 43: 1, # 'R' + 33: 1, # 'S' + 37: 2, # 'T' + 57: 1, # 'U' + 48: 1, # 'V' + 55: 1, # 'Y' + 52: 1, # 'Z' + 2: 2, # 'a' + 18: 0, # 'b' + 26: 0, # 'c' + 17: 0, # 'd' + 1: 3, # 'e' + 27: 0, # 'f' + 12: 0, # 'g' + 20: 0, # 'h' + 9: 2, # 'i' + 22: 1, # 'j' + 7: 0, # 'k' + 6: 1, # 'l' + 13: 0, # 'm' + 4: 0, # 'n' + 8: 2, # 'o' + 23: 0, # 'p' + 10: 0, # 'r' + 5: 0, # 's' + 3: 0, # 't' + 21: 2, # 'u' + 19: 0, # 'v' + 62: 0, # 'x' + 16: 1, # 'y' + 11: 0, # 'z' + 51: 2, # 'Á' + 44: 1, # 'É' + 61: 1, # 'Í' + 58: 1, # 'Ó' + 59: 1, # 'Ö' + 60: 1, # 'Ú' + 63: 1, # 'Ü' + 14: 2, # 'á' + 15: 1, # 'é' + 30: 1, # 'í' + 25: 1, # 'ó' + 24: 1, # 'ö' + 31: 0, # 'ú' + 29: 1, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 34: { # 'M' + 28: 2, # 'A' + 40: 1, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 2, # 'E' + 50: 1, # 'F' + 49: 0, # 'G' + 38: 1, # 'H' + 39: 2, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 1, # 'L' + 34: 1, # 'M' + 35: 1, # 'N' + 47: 1, # 'O' + 46: 1, # 'P' + 43: 1, # 'R' + 33: 1, # 'S' + 37: 1, # 'T' + 57: 1, # 'U' + 48: 1, # 'V' + 55: 1, # 'Y' + 52: 1, # 'Z' + 2: 3, # 'a' + 18: 0, # 'b' + 26: 1, # 'c' + 17: 0, # 'd' + 1: 3, # 'e' + 27: 0, # 'f' + 12: 0, # 'g' + 20: 0, # 'h' + 9: 3, # 'i' + 22: 0, # 'j' + 7: 0, # 'k' + 6: 0, # 'l' + 13: 1, # 'm' + 4: 1, # 'n' + 8: 3, # 'o' + 23: 0, # 'p' + 10: 1, # 'r' + 5: 0, # 's' + 3: 0, # 't' + 21: 2, # 'u' + 19: 0, # 'v' + 62: 0, # 'x' + 16: 1, # 'y' + 11: 0, # 'z' + 51: 2, # 'Á' + 44: 1, # 'É' + 61: 1, # 'Í' + 58: 1, # 'Ó' + 59: 1, # 'Ö' + 60: 1, # 'Ú' + 63: 1, # 'Ü' + 14: 2, # 'á' + 15: 2, # 'é' + 30: 1, # 'í' + 25: 1, # 'ó' + 24: 1, # 'ö' + 31: 1, # 'ú' + 29: 1, # 'ü' + 42: 0, # 'ő' + 56: 1, # 'ű' + }, + 35: { # 'N' + 28: 2, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 2, # 'D' + 32: 2, # 'E' + 50: 1, # 'F' + 49: 1, # 'G' + 38: 1, # 'H' + 39: 1, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 1, # 'L' + 34: 1, # 'M' + 35: 1, # 'N' + 47: 1, # 'O' + 46: 1, # 'P' + 43: 1, # 'R' + 33: 1, # 'S' + 37: 2, # 'T' + 57: 1, # 'U' + 48: 1, # 'V' + 55: 2, # 'Y' + 52: 1, # 'Z' + 2: 3, # 'a' + 18: 0, # 'b' + 26: 0, # 'c' + 17: 0, # 'd' + 1: 3, # 'e' + 27: 0, # 'f' + 12: 0, # 'g' + 20: 0, # 'h' + 9: 2, # 'i' + 22: 0, # 'j' + 7: 0, # 'k' + 6: 0, # 'l' + 13: 0, # 'm' + 4: 1, # 'n' + 8: 2, # 'o' + 23: 0, # 'p' + 10: 0, # 'r' + 5: 0, # 's' + 3: 0, # 't' + 21: 1, # 'u' + 19: 0, # 'v' + 62: 0, # 'x' + 16: 2, # 'y' + 11: 0, # 'z' + 51: 1, # 'Á' + 44: 1, # 'É' + 61: 1, # 'Í' + 58: 1, # 'Ó' + 59: 1, # 'Ö' + 60: 1, # 'Ú' + 63: 1, # 'Ü' + 14: 1, # 'á' + 15: 2, # 'é' + 30: 1, # 'í' + 25: 1, # 'ó' + 24: 1, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 1, # 'ő' + 56: 0, # 'ű' + }, + 47: { # 'O' + 28: 1, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 1, # 'E' + 50: 1, # 'F' + 49: 1, # 'G' + 38: 1, # 'H' + 39: 1, # 'I' + 53: 1, # 'J' + 36: 2, # 'K' + 41: 2, # 'L' + 34: 2, # 'M' + 35: 2, # 'N' + 47: 1, # 'O' + 46: 1, # 'P' + 43: 2, # 'R' + 33: 2, # 'S' + 37: 2, # 'T' + 57: 1, # 'U' + 48: 1, # 'V' + 55: 1, # 'Y' + 52: 1, # 'Z' + 2: 0, # 'a' + 18: 1, # 'b' + 26: 1, # 'c' + 17: 1, # 'd' + 1: 1, # 'e' + 27: 1, # 'f' + 12: 1, # 'g' + 20: 1, # 'h' + 9: 1, # 'i' + 22: 1, # 'j' + 7: 2, # 'k' + 6: 2, # 'l' + 13: 1, # 'm' + 4: 1, # 'n' + 8: 1, # 'o' + 23: 1, # 'p' + 10: 2, # 'r' + 5: 1, # 's' + 3: 2, # 't' + 21: 1, # 'u' + 19: 0, # 'v' + 62: 1, # 'x' + 16: 0, # 'y' + 11: 1, # 'z' + 51: 1, # 'Á' + 44: 1, # 'É' + 61: 0, # 'Í' + 58: 1, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 0, # 'á' + 15: 0, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 46: { # 'P' + 28: 1, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 1, # 'E' + 50: 1, # 'F' + 49: 1, # 'G' + 38: 1, # 'H' + 39: 1, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 1, # 'L' + 34: 0, # 'M' + 35: 1, # 'N' + 47: 1, # 'O' + 46: 1, # 'P' + 43: 2, # 'R' + 33: 1, # 'S' + 37: 1, # 'T' + 57: 1, # 'U' + 48: 1, # 'V' + 55: 0, # 'Y' + 52: 1, # 'Z' + 2: 2, # 'a' + 18: 0, # 'b' + 26: 0, # 'c' + 17: 0, # 'd' + 1: 2, # 'e' + 27: 1, # 'f' + 12: 0, # 'g' + 20: 1, # 'h' + 9: 2, # 'i' + 22: 0, # 'j' + 7: 0, # 'k' + 6: 1, # 'l' + 13: 0, # 'm' + 4: 1, # 'n' + 8: 2, # 'o' + 23: 0, # 'p' + 10: 2, # 'r' + 5: 1, # 's' + 3: 0, # 't' + 21: 1, # 'u' + 19: 0, # 'v' + 62: 0, # 'x' + 16: 1, # 'y' + 11: 0, # 'z' + 51: 2, # 'Á' + 44: 1, # 'É' + 61: 1, # 'Í' + 58: 1, # 'Ó' + 59: 1, # 'Ö' + 60: 0, # 'Ú' + 63: 1, # 'Ü' + 14: 3, # 'á' + 15: 2, # 'é' + 30: 0, # 'í' + 25: 1, # 'ó' + 24: 1, # 'ö' + 31: 0, # 'ú' + 29: 1, # 'ü' + 42: 1, # 'ő' + 56: 0, # 'ű' + }, + 43: { # 'R' + 28: 2, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 2, # 'E' + 50: 1, # 'F' + 49: 1, # 'G' + 38: 1, # 'H' + 39: 2, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 1, # 'L' + 34: 1, # 'M' + 35: 1, # 'N' + 47: 2, # 'O' + 46: 1, # 'P' + 43: 1, # 'R' + 33: 2, # 'S' + 37: 2, # 'T' + 57: 1, # 'U' + 48: 1, # 'V' + 55: 1, # 'Y' + 52: 1, # 'Z' + 2: 2, # 'a' + 18: 0, # 'b' + 26: 0, # 'c' + 17: 0, # 'd' + 1: 2, # 'e' + 27: 0, # 'f' + 12: 0, # 'g' + 20: 1, # 'h' + 9: 2, # 'i' + 22: 0, # 'j' + 7: 0, # 'k' + 6: 0, # 'l' + 13: 0, # 'm' + 4: 0, # 'n' + 8: 2, # 'o' + 23: 0, # 'p' + 10: 0, # 'r' + 5: 0, # 's' + 3: 0, # 't' + 21: 1, # 'u' + 19: 0, # 'v' + 62: 0, # 'x' + 16: 1, # 'y' + 11: 0, # 'z' + 51: 2, # 'Á' + 44: 1, # 'É' + 61: 1, # 'Í' + 58: 2, # 'Ó' + 59: 1, # 'Ö' + 60: 1, # 'Ú' + 63: 1, # 'Ü' + 14: 2, # 'á' + 15: 2, # 'é' + 30: 1, # 'í' + 25: 2, # 'ó' + 24: 1, # 'ö' + 31: 1, # 'ú' + 29: 1, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 33: { # 'S' + 28: 2, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 2, # 'E' + 50: 1, # 'F' + 49: 1, # 'G' + 38: 1, # 'H' + 39: 2, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 1, # 'L' + 34: 1, # 'M' + 35: 1, # 'N' + 47: 2, # 'O' + 46: 1, # 'P' + 43: 1, # 'R' + 33: 2, # 'S' + 37: 2, # 'T' + 57: 1, # 'U' + 48: 1, # 'V' + 55: 1, # 'Y' + 52: 3, # 'Z' + 2: 2, # 'a' + 18: 0, # 'b' + 26: 1, # 'c' + 17: 0, # 'd' + 1: 2, # 'e' + 27: 0, # 'f' + 12: 0, # 'g' + 20: 1, # 'h' + 9: 2, # 'i' + 22: 0, # 'j' + 7: 1, # 'k' + 6: 1, # 'l' + 13: 1, # 'm' + 4: 0, # 'n' + 8: 2, # 'o' + 23: 1, # 'p' + 10: 0, # 'r' + 5: 0, # 's' + 3: 1, # 't' + 21: 1, # 'u' + 19: 1, # 'v' + 62: 0, # 'x' + 16: 1, # 'y' + 11: 3, # 'z' + 51: 2, # 'Á' + 44: 1, # 'É' + 61: 1, # 'Í' + 58: 1, # 'Ó' + 59: 1, # 'Ö' + 60: 1, # 'Ú' + 63: 1, # 'Ü' + 14: 2, # 'á' + 15: 1, # 'é' + 30: 1, # 'í' + 25: 1, # 'ó' + 24: 1, # 'ö' + 31: 1, # 'ú' + 29: 1, # 'ü' + 42: 1, # 'ő' + 56: 1, # 'ű' + }, + 37: { # 'T' + 28: 2, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 2, # 'E' + 50: 1, # 'F' + 49: 1, # 'G' + 38: 1, # 'H' + 39: 2, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 1, # 'L' + 34: 1, # 'M' + 35: 1, # 'N' + 47: 2, # 'O' + 46: 1, # 'P' + 43: 2, # 'R' + 33: 1, # 'S' + 37: 2, # 'T' + 57: 1, # 'U' + 48: 1, # 'V' + 55: 1, # 'Y' + 52: 1, # 'Z' + 2: 2, # 'a' + 18: 0, # 'b' + 26: 0, # 'c' + 17: 0, # 'd' + 1: 2, # 'e' + 27: 0, # 'f' + 12: 0, # 'g' + 20: 1, # 'h' + 9: 2, # 'i' + 22: 0, # 'j' + 7: 0, # 'k' + 6: 0, # 'l' + 13: 0, # 'm' + 4: 0, # 'n' + 8: 2, # 'o' + 23: 0, # 'p' + 10: 1, # 'r' + 5: 1, # 's' + 3: 0, # 't' + 21: 2, # 'u' + 19: 0, # 'v' + 62: 0, # 'x' + 16: 1, # 'y' + 11: 1, # 'z' + 51: 2, # 'Á' + 44: 2, # 'É' + 61: 1, # 'Í' + 58: 1, # 'Ó' + 59: 1, # 'Ö' + 60: 1, # 'Ú' + 63: 1, # 'Ü' + 14: 2, # 'á' + 15: 1, # 'é' + 30: 1, # 'í' + 25: 1, # 'ó' + 24: 2, # 'ö' + 31: 1, # 'ú' + 29: 1, # 'ü' + 42: 1, # 'ő' + 56: 1, # 'ű' + }, + 57: { # 'U' + 28: 1, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 1, # 'E' + 50: 1, # 'F' + 49: 1, # 'G' + 38: 1, # 'H' + 39: 1, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 1, # 'L' + 34: 1, # 'M' + 35: 1, # 'N' + 47: 1, # 'O' + 46: 1, # 'P' + 43: 1, # 'R' + 33: 2, # 'S' + 37: 1, # 'T' + 57: 0, # 'U' + 48: 1, # 'V' + 55: 0, # 'Y' + 52: 1, # 'Z' + 2: 0, # 'a' + 18: 1, # 'b' + 26: 1, # 'c' + 17: 1, # 'd' + 1: 1, # 'e' + 27: 0, # 'f' + 12: 2, # 'g' + 20: 0, # 'h' + 9: 0, # 'i' + 22: 1, # 'j' + 7: 1, # 'k' + 6: 1, # 'l' + 13: 1, # 'm' + 4: 1, # 'n' + 8: 0, # 'o' + 23: 1, # 'p' + 10: 1, # 'r' + 5: 1, # 's' + 3: 1, # 't' + 21: 0, # 'u' + 19: 0, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 1, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 1, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 0, # 'á' + 15: 0, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 48: { # 'V' + 28: 2, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 1, # 'D' + 32: 2, # 'E' + 50: 1, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 2, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 0, # 'L' + 34: 1, # 'M' + 35: 1, # 'N' + 47: 1, # 'O' + 46: 1, # 'P' + 43: 1, # 'R' + 33: 1, # 'S' + 37: 1, # 'T' + 57: 1, # 'U' + 48: 1, # 'V' + 55: 1, # 'Y' + 52: 0, # 'Z' + 2: 3, # 'a' + 18: 0, # 'b' + 26: 0, # 'c' + 17: 0, # 'd' + 1: 2, # 'e' + 27: 0, # 'f' + 12: 0, # 'g' + 20: 0, # 'h' + 9: 2, # 'i' + 22: 0, # 'j' + 7: 0, # 'k' + 6: 1, # 'l' + 13: 0, # 'm' + 4: 0, # 'n' + 8: 2, # 'o' + 23: 0, # 'p' + 10: 0, # 'r' + 5: 0, # 's' + 3: 0, # 't' + 21: 1, # 'u' + 19: 0, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 0, # 'z' + 51: 2, # 'Á' + 44: 2, # 'É' + 61: 1, # 'Í' + 58: 1, # 'Ó' + 59: 1, # 'Ö' + 60: 0, # 'Ú' + 63: 1, # 'Ü' + 14: 2, # 'á' + 15: 2, # 'é' + 30: 1, # 'í' + 25: 0, # 'ó' + 24: 1, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 55: { # 'Y' + 28: 2, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 2, # 'E' + 50: 1, # 'F' + 49: 1, # 'G' + 38: 1, # 'H' + 39: 1, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 1, # 'L' + 34: 1, # 'M' + 35: 1, # 'N' + 47: 1, # 'O' + 46: 1, # 'P' + 43: 1, # 'R' + 33: 1, # 'S' + 37: 1, # 'T' + 57: 1, # 'U' + 48: 1, # 'V' + 55: 0, # 'Y' + 52: 2, # 'Z' + 2: 1, # 'a' + 18: 0, # 'b' + 26: 0, # 'c' + 17: 1, # 'd' + 1: 1, # 'e' + 27: 0, # 'f' + 12: 0, # 'g' + 20: 0, # 'h' + 9: 0, # 'i' + 22: 0, # 'j' + 7: 0, # 'k' + 6: 0, # 'l' + 13: 0, # 'm' + 4: 0, # 'n' + 8: 1, # 'o' + 23: 1, # 'p' + 10: 0, # 'r' + 5: 0, # 's' + 3: 0, # 't' + 21: 0, # 'u' + 19: 1, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 0, # 'z' + 51: 1, # 'Á' + 44: 1, # 'É' + 61: 1, # 'Í' + 58: 1, # 'Ó' + 59: 1, # 'Ö' + 60: 1, # 'Ú' + 63: 1, # 'Ü' + 14: 0, # 'á' + 15: 0, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 52: { # 'Z' + 28: 2, # 'A' + 40: 1, # 'B' + 54: 0, # 'C' + 45: 1, # 'D' + 32: 2, # 'E' + 50: 1, # 'F' + 49: 1, # 'G' + 38: 1, # 'H' + 39: 2, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 1, # 'L' + 34: 1, # 'M' + 35: 1, # 'N' + 47: 2, # 'O' + 46: 1, # 'P' + 43: 1, # 'R' + 33: 2, # 'S' + 37: 1, # 'T' + 57: 1, # 'U' + 48: 1, # 'V' + 55: 1, # 'Y' + 52: 1, # 'Z' + 2: 1, # 'a' + 18: 0, # 'b' + 26: 0, # 'c' + 17: 0, # 'd' + 1: 1, # 'e' + 27: 0, # 'f' + 12: 0, # 'g' + 20: 0, # 'h' + 9: 1, # 'i' + 22: 0, # 'j' + 7: 0, # 'k' + 6: 0, # 'l' + 13: 0, # 'm' + 4: 1, # 'n' + 8: 1, # 'o' + 23: 0, # 'p' + 10: 1, # 'r' + 5: 2, # 's' + 3: 0, # 't' + 21: 1, # 'u' + 19: 0, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 0, # 'z' + 51: 2, # 'Á' + 44: 1, # 'É' + 61: 1, # 'Í' + 58: 1, # 'Ó' + 59: 1, # 'Ö' + 60: 1, # 'Ú' + 63: 1, # 'Ü' + 14: 1, # 'á' + 15: 1, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 1, # 'ö' + 31: 1, # 'ú' + 29: 1, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 2: { # 'a' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 1, # 'a' + 18: 3, # 'b' + 26: 3, # 'c' + 17: 3, # 'd' + 1: 2, # 'e' + 27: 2, # 'f' + 12: 3, # 'g' + 20: 3, # 'h' + 9: 3, # 'i' + 22: 3, # 'j' + 7: 3, # 'k' + 6: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 8: 2, # 'o' + 23: 3, # 'p' + 10: 3, # 'r' + 5: 3, # 's' + 3: 3, # 't' + 21: 3, # 'u' + 19: 3, # 'v' + 62: 1, # 'x' + 16: 2, # 'y' + 11: 3, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 1, # 'á' + 15: 1, # 'é' + 30: 1, # 'í' + 25: 1, # 'ó' + 24: 1, # 'ö' + 31: 1, # 'ú' + 29: 1, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 18: { # 'b' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 3, # 'a' + 18: 3, # 'b' + 26: 1, # 'c' + 17: 1, # 'd' + 1: 3, # 'e' + 27: 1, # 'f' + 12: 1, # 'g' + 20: 1, # 'h' + 9: 3, # 'i' + 22: 2, # 'j' + 7: 2, # 'k' + 6: 2, # 'l' + 13: 1, # 'm' + 4: 2, # 'n' + 8: 3, # 'o' + 23: 1, # 'p' + 10: 3, # 'r' + 5: 2, # 's' + 3: 1, # 't' + 21: 3, # 'u' + 19: 1, # 'v' + 62: 0, # 'x' + 16: 1, # 'y' + 11: 1, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 3, # 'á' + 15: 3, # 'é' + 30: 2, # 'í' + 25: 3, # 'ó' + 24: 2, # 'ö' + 31: 2, # 'ú' + 29: 2, # 'ü' + 42: 2, # 'ő' + 56: 1, # 'ű' + }, + 26: { # 'c' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 1, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 1, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 2, # 'a' + 18: 1, # 'b' + 26: 2, # 'c' + 17: 1, # 'd' + 1: 3, # 'e' + 27: 1, # 'f' + 12: 1, # 'g' + 20: 3, # 'h' + 9: 3, # 'i' + 22: 1, # 'j' + 7: 2, # 'k' + 6: 1, # 'l' + 13: 1, # 'm' + 4: 1, # 'n' + 8: 3, # 'o' + 23: 1, # 'p' + 10: 2, # 'r' + 5: 3, # 's' + 3: 2, # 't' + 21: 2, # 'u' + 19: 1, # 'v' + 62: 0, # 'x' + 16: 1, # 'y' + 11: 2, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 2, # 'á' + 15: 2, # 'é' + 30: 2, # 'í' + 25: 1, # 'ó' + 24: 1, # 'ö' + 31: 1, # 'ú' + 29: 1, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 17: { # 'd' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 3, # 'a' + 18: 2, # 'b' + 26: 1, # 'c' + 17: 2, # 'd' + 1: 3, # 'e' + 27: 1, # 'f' + 12: 1, # 'g' + 20: 2, # 'h' + 9: 3, # 'i' + 22: 3, # 'j' + 7: 2, # 'k' + 6: 1, # 'l' + 13: 2, # 'm' + 4: 3, # 'n' + 8: 3, # 'o' + 23: 1, # 'p' + 10: 3, # 'r' + 5: 3, # 's' + 3: 3, # 't' + 21: 3, # 'u' + 19: 3, # 'v' + 62: 0, # 'x' + 16: 2, # 'y' + 11: 2, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 3, # 'á' + 15: 3, # 'é' + 30: 3, # 'í' + 25: 3, # 'ó' + 24: 3, # 'ö' + 31: 2, # 'ú' + 29: 2, # 'ü' + 42: 2, # 'ő' + 56: 1, # 'ű' + }, + 1: { # 'e' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 2, # 'a' + 18: 3, # 'b' + 26: 3, # 'c' + 17: 3, # 'd' + 1: 2, # 'e' + 27: 3, # 'f' + 12: 3, # 'g' + 20: 3, # 'h' + 9: 3, # 'i' + 22: 3, # 'j' + 7: 3, # 'k' + 6: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 8: 2, # 'o' + 23: 3, # 'p' + 10: 3, # 'r' + 5: 3, # 's' + 3: 3, # 't' + 21: 2, # 'u' + 19: 3, # 'v' + 62: 2, # 'x' + 16: 2, # 'y' + 11: 3, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 3, # 'á' + 15: 1, # 'é' + 30: 1, # 'í' + 25: 1, # 'ó' + 24: 1, # 'ö' + 31: 1, # 'ú' + 29: 1, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 27: { # 'f' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 3, # 'a' + 18: 1, # 'b' + 26: 1, # 'c' + 17: 1, # 'd' + 1: 3, # 'e' + 27: 2, # 'f' + 12: 1, # 'g' + 20: 1, # 'h' + 9: 3, # 'i' + 22: 2, # 'j' + 7: 1, # 'k' + 6: 1, # 'l' + 13: 1, # 'm' + 4: 1, # 'n' + 8: 3, # 'o' + 23: 0, # 'p' + 10: 3, # 'r' + 5: 1, # 's' + 3: 1, # 't' + 21: 2, # 'u' + 19: 1, # 'v' + 62: 0, # 'x' + 16: 1, # 'y' + 11: 0, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 3, # 'á' + 15: 3, # 'é' + 30: 1, # 'í' + 25: 1, # 'ó' + 24: 3, # 'ö' + 31: 1, # 'ú' + 29: 2, # 'ü' + 42: 1, # 'ő' + 56: 1, # 'ű' + }, + 12: { # 'g' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 3, # 'a' + 18: 3, # 'b' + 26: 2, # 'c' + 17: 2, # 'd' + 1: 3, # 'e' + 27: 2, # 'f' + 12: 3, # 'g' + 20: 3, # 'h' + 9: 3, # 'i' + 22: 3, # 'j' + 7: 2, # 'k' + 6: 3, # 'l' + 13: 2, # 'm' + 4: 3, # 'n' + 8: 3, # 'o' + 23: 1, # 'p' + 10: 3, # 'r' + 5: 3, # 's' + 3: 3, # 't' + 21: 3, # 'u' + 19: 3, # 'v' + 62: 0, # 'x' + 16: 3, # 'y' + 11: 2, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 3, # 'á' + 15: 3, # 'é' + 30: 2, # 'í' + 25: 3, # 'ó' + 24: 2, # 'ö' + 31: 2, # 'ú' + 29: 2, # 'ü' + 42: 2, # 'ő' + 56: 1, # 'ű' + }, + 20: { # 'h' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 3, # 'a' + 18: 1, # 'b' + 26: 1, # 'c' + 17: 0, # 'd' + 1: 3, # 'e' + 27: 0, # 'f' + 12: 1, # 'g' + 20: 2, # 'h' + 9: 3, # 'i' + 22: 1, # 'j' + 7: 1, # 'k' + 6: 1, # 'l' + 13: 1, # 'm' + 4: 1, # 'n' + 8: 3, # 'o' + 23: 0, # 'p' + 10: 1, # 'r' + 5: 2, # 's' + 3: 1, # 't' + 21: 3, # 'u' + 19: 1, # 'v' + 62: 0, # 'x' + 16: 2, # 'y' + 11: 0, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 3, # 'á' + 15: 3, # 'é' + 30: 3, # 'í' + 25: 2, # 'ó' + 24: 2, # 'ö' + 31: 2, # 'ú' + 29: 1, # 'ü' + 42: 1, # 'ő' + 56: 1, # 'ű' + }, + 9: { # 'i' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 3, # 'a' + 18: 3, # 'b' + 26: 3, # 'c' + 17: 3, # 'd' + 1: 3, # 'e' + 27: 3, # 'f' + 12: 3, # 'g' + 20: 3, # 'h' + 9: 2, # 'i' + 22: 2, # 'j' + 7: 3, # 'k' + 6: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 8: 2, # 'o' + 23: 2, # 'p' + 10: 3, # 'r' + 5: 3, # 's' + 3: 3, # 't' + 21: 3, # 'u' + 19: 3, # 'v' + 62: 1, # 'x' + 16: 1, # 'y' + 11: 3, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 3, # 'á' + 15: 2, # 'é' + 30: 1, # 'í' + 25: 3, # 'ó' + 24: 1, # 'ö' + 31: 2, # 'ú' + 29: 1, # 'ü' + 42: 0, # 'ő' + 56: 1, # 'ű' + }, + 22: { # 'j' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 3, # 'a' + 18: 2, # 'b' + 26: 1, # 'c' + 17: 3, # 'd' + 1: 3, # 'e' + 27: 1, # 'f' + 12: 1, # 'g' + 20: 2, # 'h' + 9: 1, # 'i' + 22: 2, # 'j' + 7: 2, # 'k' + 6: 2, # 'l' + 13: 1, # 'm' + 4: 2, # 'n' + 8: 3, # 'o' + 23: 1, # 'p' + 10: 2, # 'r' + 5: 2, # 's' + 3: 3, # 't' + 21: 3, # 'u' + 19: 1, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 2, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 3, # 'á' + 15: 3, # 'é' + 30: 1, # 'í' + 25: 3, # 'ó' + 24: 3, # 'ö' + 31: 3, # 'ú' + 29: 2, # 'ü' + 42: 1, # 'ő' + 56: 1, # 'ű' + }, + 7: { # 'k' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 3, # 'a' + 18: 3, # 'b' + 26: 2, # 'c' + 17: 1, # 'd' + 1: 3, # 'e' + 27: 1, # 'f' + 12: 1, # 'g' + 20: 2, # 'h' + 9: 3, # 'i' + 22: 2, # 'j' + 7: 3, # 'k' + 6: 3, # 'l' + 13: 1, # 'm' + 4: 3, # 'n' + 8: 3, # 'o' + 23: 1, # 'p' + 10: 3, # 'r' + 5: 3, # 's' + 3: 3, # 't' + 21: 3, # 'u' + 19: 2, # 'v' + 62: 0, # 'x' + 16: 2, # 'y' + 11: 1, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 3, # 'á' + 15: 3, # 'é' + 30: 3, # 'í' + 25: 2, # 'ó' + 24: 3, # 'ö' + 31: 1, # 'ú' + 29: 3, # 'ü' + 42: 1, # 'ő' + 56: 1, # 'ű' + }, + 6: { # 'l' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 1, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 1, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 3, # 'a' + 18: 2, # 'b' + 26: 3, # 'c' + 17: 3, # 'd' + 1: 3, # 'e' + 27: 3, # 'f' + 12: 3, # 'g' + 20: 3, # 'h' + 9: 3, # 'i' + 22: 3, # 'j' + 7: 3, # 'k' + 6: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 8: 3, # 'o' + 23: 2, # 'p' + 10: 2, # 'r' + 5: 3, # 's' + 3: 3, # 't' + 21: 3, # 'u' + 19: 3, # 'v' + 62: 0, # 'x' + 16: 3, # 'y' + 11: 2, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 3, # 'á' + 15: 3, # 'é' + 30: 3, # 'í' + 25: 3, # 'ó' + 24: 3, # 'ö' + 31: 2, # 'ú' + 29: 2, # 'ü' + 42: 3, # 'ő' + 56: 1, # 'ű' + }, + 13: { # 'm' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 3, # 'a' + 18: 3, # 'b' + 26: 2, # 'c' + 17: 1, # 'd' + 1: 3, # 'e' + 27: 1, # 'f' + 12: 1, # 'g' + 20: 2, # 'h' + 9: 3, # 'i' + 22: 2, # 'j' + 7: 1, # 'k' + 6: 3, # 'l' + 13: 3, # 'm' + 4: 2, # 'n' + 8: 3, # 'o' + 23: 3, # 'p' + 10: 2, # 'r' + 5: 2, # 's' + 3: 2, # 't' + 21: 3, # 'u' + 19: 1, # 'v' + 62: 0, # 'x' + 16: 1, # 'y' + 11: 2, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 3, # 'á' + 15: 3, # 'é' + 30: 2, # 'í' + 25: 2, # 'ó' + 24: 2, # 'ö' + 31: 2, # 'ú' + 29: 2, # 'ü' + 42: 1, # 'ő' + 56: 2, # 'ű' + }, + 4: { # 'n' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 3, # 'a' + 18: 3, # 'b' + 26: 3, # 'c' + 17: 3, # 'd' + 1: 3, # 'e' + 27: 2, # 'f' + 12: 3, # 'g' + 20: 3, # 'h' + 9: 3, # 'i' + 22: 2, # 'j' + 7: 3, # 'k' + 6: 2, # 'l' + 13: 2, # 'm' + 4: 3, # 'n' + 8: 3, # 'o' + 23: 2, # 'p' + 10: 2, # 'r' + 5: 3, # 's' + 3: 3, # 't' + 21: 3, # 'u' + 19: 2, # 'v' + 62: 1, # 'x' + 16: 3, # 'y' + 11: 3, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 3, # 'á' + 15: 3, # 'é' + 30: 2, # 'í' + 25: 2, # 'ó' + 24: 3, # 'ö' + 31: 2, # 'ú' + 29: 3, # 'ü' + 42: 2, # 'ő' + 56: 1, # 'ű' + }, + 8: { # 'o' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 1, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 2, # 'a' + 18: 3, # 'b' + 26: 3, # 'c' + 17: 3, # 'd' + 1: 2, # 'e' + 27: 2, # 'f' + 12: 3, # 'g' + 20: 3, # 'h' + 9: 2, # 'i' + 22: 2, # 'j' + 7: 3, # 'k' + 6: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 8: 1, # 'o' + 23: 3, # 'p' + 10: 3, # 'r' + 5: 3, # 's' + 3: 3, # 't' + 21: 2, # 'u' + 19: 3, # 'v' + 62: 1, # 'x' + 16: 1, # 'y' + 11: 3, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 1, # 'á' + 15: 2, # 'é' + 30: 1, # 'í' + 25: 1, # 'ó' + 24: 1, # 'ö' + 31: 1, # 'ú' + 29: 1, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 23: { # 'p' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 3, # 'a' + 18: 1, # 'b' + 26: 2, # 'c' + 17: 1, # 'd' + 1: 3, # 'e' + 27: 1, # 'f' + 12: 1, # 'g' + 20: 2, # 'h' + 9: 3, # 'i' + 22: 2, # 'j' + 7: 2, # 'k' + 6: 3, # 'l' + 13: 1, # 'm' + 4: 2, # 'n' + 8: 3, # 'o' + 23: 3, # 'p' + 10: 3, # 'r' + 5: 2, # 's' + 3: 2, # 't' + 21: 3, # 'u' + 19: 2, # 'v' + 62: 0, # 'x' + 16: 1, # 'y' + 11: 2, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 3, # 'á' + 15: 3, # 'é' + 30: 2, # 'í' + 25: 2, # 'ó' + 24: 2, # 'ö' + 31: 1, # 'ú' + 29: 2, # 'ü' + 42: 1, # 'ő' + 56: 1, # 'ű' + }, + 10: { # 'r' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 3, # 'a' + 18: 3, # 'b' + 26: 3, # 'c' + 17: 3, # 'd' + 1: 3, # 'e' + 27: 2, # 'f' + 12: 3, # 'g' + 20: 2, # 'h' + 9: 3, # 'i' + 22: 3, # 'j' + 7: 3, # 'k' + 6: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 8: 3, # 'o' + 23: 2, # 'p' + 10: 3, # 'r' + 5: 3, # 's' + 3: 3, # 't' + 21: 3, # 'u' + 19: 3, # 'v' + 62: 1, # 'x' + 16: 2, # 'y' + 11: 3, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 3, # 'á' + 15: 3, # 'é' + 30: 2, # 'í' + 25: 3, # 'ó' + 24: 3, # 'ö' + 31: 3, # 'ú' + 29: 3, # 'ü' + 42: 2, # 'ő' + 56: 2, # 'ű' + }, + 5: { # 's' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 3, # 'a' + 18: 3, # 'b' + 26: 2, # 'c' + 17: 2, # 'd' + 1: 3, # 'e' + 27: 2, # 'f' + 12: 2, # 'g' + 20: 2, # 'h' + 9: 3, # 'i' + 22: 1, # 'j' + 7: 3, # 'k' + 6: 2, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 8: 3, # 'o' + 23: 2, # 'p' + 10: 3, # 'r' + 5: 3, # 's' + 3: 3, # 't' + 21: 3, # 'u' + 19: 2, # 'v' + 62: 0, # 'x' + 16: 1, # 'y' + 11: 3, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 3, # 'á' + 15: 3, # 'é' + 30: 3, # 'í' + 25: 3, # 'ó' + 24: 3, # 'ö' + 31: 3, # 'ú' + 29: 3, # 'ü' + 42: 2, # 'ő' + 56: 1, # 'ű' + }, + 3: { # 't' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 3, # 'a' + 18: 3, # 'b' + 26: 2, # 'c' + 17: 1, # 'd' + 1: 3, # 'e' + 27: 2, # 'f' + 12: 1, # 'g' + 20: 3, # 'h' + 9: 3, # 'i' + 22: 3, # 'j' + 7: 3, # 'k' + 6: 3, # 'l' + 13: 2, # 'm' + 4: 3, # 'n' + 8: 3, # 'o' + 23: 1, # 'p' + 10: 3, # 'r' + 5: 3, # 's' + 3: 3, # 't' + 21: 3, # 'u' + 19: 3, # 'v' + 62: 0, # 'x' + 16: 3, # 'y' + 11: 1, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 3, # 'á' + 15: 3, # 'é' + 30: 2, # 'í' + 25: 3, # 'ó' + 24: 3, # 'ö' + 31: 3, # 'ú' + 29: 3, # 'ü' + 42: 3, # 'ő' + 56: 2, # 'ű' + }, + 21: { # 'u' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 1, # 'a' + 18: 2, # 'b' + 26: 2, # 'c' + 17: 3, # 'd' + 1: 2, # 'e' + 27: 1, # 'f' + 12: 3, # 'g' + 20: 2, # 'h' + 9: 2, # 'i' + 22: 2, # 'j' + 7: 3, # 'k' + 6: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 8: 1, # 'o' + 23: 2, # 'p' + 10: 3, # 'r' + 5: 3, # 's' + 3: 3, # 't' + 21: 1, # 'u' + 19: 3, # 'v' + 62: 1, # 'x' + 16: 1, # 'y' + 11: 2, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 2, # 'á' + 15: 1, # 'é' + 30: 1, # 'í' + 25: 1, # 'ó' + 24: 0, # 'ö' + 31: 1, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 19: { # 'v' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 3, # 'a' + 18: 2, # 'b' + 26: 1, # 'c' + 17: 1, # 'd' + 1: 3, # 'e' + 27: 1, # 'f' + 12: 1, # 'g' + 20: 1, # 'h' + 9: 3, # 'i' + 22: 1, # 'j' + 7: 1, # 'k' + 6: 1, # 'l' + 13: 1, # 'm' + 4: 1, # 'n' + 8: 3, # 'o' + 23: 1, # 'p' + 10: 1, # 'r' + 5: 2, # 's' + 3: 2, # 't' + 21: 2, # 'u' + 19: 2, # 'v' + 62: 0, # 'x' + 16: 1, # 'y' + 11: 1, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 3, # 'á' + 15: 3, # 'é' + 30: 2, # 'í' + 25: 2, # 'ó' + 24: 2, # 'ö' + 31: 1, # 'ú' + 29: 2, # 'ü' + 42: 1, # 'ő' + 56: 1, # 'ű' + }, + 62: { # 'x' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 1, # 'a' + 18: 1, # 'b' + 26: 1, # 'c' + 17: 0, # 'd' + 1: 1, # 'e' + 27: 1, # 'f' + 12: 0, # 'g' + 20: 0, # 'h' + 9: 1, # 'i' + 22: 0, # 'j' + 7: 1, # 'k' + 6: 1, # 'l' + 13: 1, # 'm' + 4: 1, # 'n' + 8: 1, # 'o' + 23: 1, # 'p' + 10: 1, # 'r' + 5: 1, # 's' + 3: 1, # 't' + 21: 1, # 'u' + 19: 0, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 0, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 1, # 'á' + 15: 1, # 'é' + 30: 1, # 'í' + 25: 1, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 16: { # 'y' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 3, # 'a' + 18: 2, # 'b' + 26: 1, # 'c' + 17: 1, # 'd' + 1: 3, # 'e' + 27: 2, # 'f' + 12: 2, # 'g' + 20: 2, # 'h' + 9: 3, # 'i' + 22: 2, # 'j' + 7: 2, # 'k' + 6: 2, # 'l' + 13: 2, # 'm' + 4: 3, # 'n' + 8: 3, # 'o' + 23: 2, # 'p' + 10: 2, # 'r' + 5: 3, # 's' + 3: 3, # 't' + 21: 3, # 'u' + 19: 3, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 2, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 3, # 'á' + 15: 3, # 'é' + 30: 2, # 'í' + 25: 2, # 'ó' + 24: 3, # 'ö' + 31: 2, # 'ú' + 29: 2, # 'ü' + 42: 1, # 'ő' + 56: 2, # 'ű' + }, + 11: { # 'z' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 3, # 'a' + 18: 2, # 'b' + 26: 1, # 'c' + 17: 3, # 'd' + 1: 3, # 'e' + 27: 1, # 'f' + 12: 2, # 'g' + 20: 2, # 'h' + 9: 3, # 'i' + 22: 1, # 'j' + 7: 3, # 'k' + 6: 2, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 8: 3, # 'o' + 23: 1, # 'p' + 10: 2, # 'r' + 5: 3, # 's' + 3: 3, # 't' + 21: 3, # 'u' + 19: 2, # 'v' + 62: 0, # 'x' + 16: 1, # 'y' + 11: 3, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 3, # 'á' + 15: 3, # 'é' + 30: 3, # 'í' + 25: 3, # 'ó' + 24: 3, # 'ö' + 31: 2, # 'ú' + 29: 3, # 'ü' + 42: 2, # 'ő' + 56: 1, # 'ű' + }, + 51: { # 'Á' + 28: 0, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 0, # 'E' + 50: 1, # 'F' + 49: 2, # 'G' + 38: 1, # 'H' + 39: 1, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 2, # 'L' + 34: 1, # 'M' + 35: 2, # 'N' + 47: 0, # 'O' + 46: 1, # 'P' + 43: 2, # 'R' + 33: 2, # 'S' + 37: 1, # 'T' + 57: 0, # 'U' + 48: 1, # 'V' + 55: 0, # 'Y' + 52: 1, # 'Z' + 2: 0, # 'a' + 18: 1, # 'b' + 26: 1, # 'c' + 17: 1, # 'd' + 1: 0, # 'e' + 27: 0, # 'f' + 12: 1, # 'g' + 20: 1, # 'h' + 9: 0, # 'i' + 22: 1, # 'j' + 7: 1, # 'k' + 6: 2, # 'l' + 13: 2, # 'm' + 4: 0, # 'n' + 8: 0, # 'o' + 23: 1, # 'p' + 10: 1, # 'r' + 5: 1, # 's' + 3: 1, # 't' + 21: 0, # 'u' + 19: 0, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 1, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 1, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 0, # 'á' + 15: 0, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 44: { # 'É' + 28: 0, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 1, # 'E' + 50: 0, # 'F' + 49: 2, # 'G' + 38: 1, # 'H' + 39: 1, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 2, # 'L' + 34: 1, # 'M' + 35: 2, # 'N' + 47: 0, # 'O' + 46: 1, # 'P' + 43: 2, # 'R' + 33: 2, # 'S' + 37: 2, # 'T' + 57: 0, # 'U' + 48: 1, # 'V' + 55: 0, # 'Y' + 52: 1, # 'Z' + 2: 0, # 'a' + 18: 1, # 'b' + 26: 1, # 'c' + 17: 1, # 'd' + 1: 0, # 'e' + 27: 0, # 'f' + 12: 1, # 'g' + 20: 1, # 'h' + 9: 0, # 'i' + 22: 1, # 'j' + 7: 1, # 'k' + 6: 2, # 'l' + 13: 1, # 'm' + 4: 2, # 'n' + 8: 0, # 'o' + 23: 1, # 'p' + 10: 2, # 'r' + 5: 3, # 's' + 3: 1, # 't' + 21: 0, # 'u' + 19: 1, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 0, # 'z' + 51: 0, # 'Á' + 44: 1, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 0, # 'á' + 15: 0, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 61: { # 'Í' + 28: 0, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 0, # 'E' + 50: 1, # 'F' + 49: 1, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 1, # 'J' + 36: 0, # 'K' + 41: 1, # 'L' + 34: 1, # 'M' + 35: 1, # 'N' + 47: 0, # 'O' + 46: 1, # 'P' + 43: 1, # 'R' + 33: 1, # 'S' + 37: 1, # 'T' + 57: 0, # 'U' + 48: 1, # 'V' + 55: 0, # 'Y' + 52: 1, # 'Z' + 2: 0, # 'a' + 18: 0, # 'b' + 26: 0, # 'c' + 17: 0, # 'd' + 1: 0, # 'e' + 27: 0, # 'f' + 12: 2, # 'g' + 20: 0, # 'h' + 9: 0, # 'i' + 22: 0, # 'j' + 7: 0, # 'k' + 6: 0, # 'l' + 13: 1, # 'm' + 4: 0, # 'n' + 8: 0, # 'o' + 23: 0, # 'p' + 10: 1, # 'r' + 5: 0, # 's' + 3: 1, # 't' + 21: 0, # 'u' + 19: 0, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 1, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 0, # 'á' + 15: 0, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 58: { # 'Ó' + 28: 1, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 0, # 'E' + 50: 1, # 'F' + 49: 1, # 'G' + 38: 1, # 'H' + 39: 1, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 2, # 'L' + 34: 1, # 'M' + 35: 1, # 'N' + 47: 0, # 'O' + 46: 1, # 'P' + 43: 1, # 'R' + 33: 1, # 'S' + 37: 1, # 'T' + 57: 0, # 'U' + 48: 1, # 'V' + 55: 0, # 'Y' + 52: 1, # 'Z' + 2: 0, # 'a' + 18: 1, # 'b' + 26: 1, # 'c' + 17: 1, # 'd' + 1: 0, # 'e' + 27: 0, # 'f' + 12: 0, # 'g' + 20: 2, # 'h' + 9: 0, # 'i' + 22: 0, # 'j' + 7: 1, # 'k' + 6: 1, # 'l' + 13: 0, # 'm' + 4: 1, # 'n' + 8: 0, # 'o' + 23: 1, # 'p' + 10: 1, # 'r' + 5: 1, # 's' + 3: 0, # 't' + 21: 0, # 'u' + 19: 1, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 1, # 'z' + 51: 0, # 'Á' + 44: 1, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 0, # 'á' + 15: 0, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 59: { # 'Ö' + 28: 0, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 1, # 'G' + 38: 1, # 'H' + 39: 0, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 1, # 'L' + 34: 1, # 'M' + 35: 1, # 'N' + 47: 0, # 'O' + 46: 1, # 'P' + 43: 1, # 'R' + 33: 1, # 'S' + 37: 1, # 'T' + 57: 0, # 'U' + 48: 1, # 'V' + 55: 0, # 'Y' + 52: 1, # 'Z' + 2: 0, # 'a' + 18: 0, # 'b' + 26: 1, # 'c' + 17: 1, # 'd' + 1: 0, # 'e' + 27: 0, # 'f' + 12: 0, # 'g' + 20: 0, # 'h' + 9: 0, # 'i' + 22: 0, # 'j' + 7: 1, # 'k' + 6: 1, # 'l' + 13: 1, # 'm' + 4: 1, # 'n' + 8: 0, # 'o' + 23: 0, # 'p' + 10: 2, # 'r' + 5: 1, # 's' + 3: 1, # 't' + 21: 0, # 'u' + 19: 1, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 1, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 0, # 'á' + 15: 0, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 60: { # 'Ú' + 28: 0, # 'A' + 40: 1, # 'B' + 54: 1, # 'C' + 45: 1, # 'D' + 32: 0, # 'E' + 50: 1, # 'F' + 49: 1, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 1, # 'L' + 34: 1, # 'M' + 35: 1, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 1, # 'R' + 33: 1, # 'S' + 37: 1, # 'T' + 57: 0, # 'U' + 48: 1, # 'V' + 55: 0, # 'Y' + 52: 1, # 'Z' + 2: 0, # 'a' + 18: 0, # 'b' + 26: 0, # 'c' + 17: 0, # 'd' + 1: 0, # 'e' + 27: 0, # 'f' + 12: 2, # 'g' + 20: 0, # 'h' + 9: 0, # 'i' + 22: 2, # 'j' + 7: 0, # 'k' + 6: 0, # 'l' + 13: 0, # 'm' + 4: 1, # 'n' + 8: 0, # 'o' + 23: 0, # 'p' + 10: 1, # 'r' + 5: 1, # 's' + 3: 1, # 't' + 21: 0, # 'u' + 19: 0, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 0, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 0, # 'á' + 15: 0, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 63: { # 'Ü' + 28: 0, # 'A' + 40: 1, # 'B' + 54: 0, # 'C' + 45: 1, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 1, # 'G' + 38: 1, # 'H' + 39: 0, # 'I' + 53: 1, # 'J' + 36: 1, # 'K' + 41: 1, # 'L' + 34: 1, # 'M' + 35: 1, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 1, # 'R' + 33: 1, # 'S' + 37: 1, # 'T' + 57: 0, # 'U' + 48: 1, # 'V' + 55: 0, # 'Y' + 52: 1, # 'Z' + 2: 0, # 'a' + 18: 1, # 'b' + 26: 0, # 'c' + 17: 1, # 'd' + 1: 0, # 'e' + 27: 0, # 'f' + 12: 1, # 'g' + 20: 0, # 'h' + 9: 0, # 'i' + 22: 0, # 'j' + 7: 0, # 'k' + 6: 1, # 'l' + 13: 0, # 'm' + 4: 1, # 'n' + 8: 0, # 'o' + 23: 0, # 'p' + 10: 1, # 'r' + 5: 1, # 's' + 3: 1, # 't' + 21: 0, # 'u' + 19: 1, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 1, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 0, # 'á' + 15: 0, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 14: { # 'á' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 1, # 'a' + 18: 3, # 'b' + 26: 3, # 'c' + 17: 3, # 'd' + 1: 1, # 'e' + 27: 2, # 'f' + 12: 3, # 'g' + 20: 2, # 'h' + 9: 2, # 'i' + 22: 3, # 'j' + 7: 3, # 'k' + 6: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 8: 1, # 'o' + 23: 2, # 'p' + 10: 3, # 'r' + 5: 3, # 's' + 3: 3, # 't' + 21: 2, # 'u' + 19: 3, # 'v' + 62: 0, # 'x' + 16: 1, # 'y' + 11: 3, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 1, # 'á' + 15: 2, # 'é' + 30: 1, # 'í' + 25: 0, # 'ó' + 24: 1, # 'ö' + 31: 0, # 'ú' + 29: 1, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 15: { # 'é' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 1, # 'a' + 18: 3, # 'b' + 26: 2, # 'c' + 17: 3, # 'd' + 1: 1, # 'e' + 27: 1, # 'f' + 12: 3, # 'g' + 20: 3, # 'h' + 9: 2, # 'i' + 22: 2, # 'j' + 7: 3, # 'k' + 6: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 8: 1, # 'o' + 23: 3, # 'p' + 10: 3, # 'r' + 5: 3, # 's' + 3: 3, # 't' + 21: 0, # 'u' + 19: 3, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 3, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 1, # 'á' + 15: 1, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 1, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 30: { # 'í' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 0, # 'a' + 18: 1, # 'b' + 26: 2, # 'c' + 17: 1, # 'd' + 1: 0, # 'e' + 27: 1, # 'f' + 12: 3, # 'g' + 20: 0, # 'h' + 9: 0, # 'i' + 22: 1, # 'j' + 7: 1, # 'k' + 6: 2, # 'l' + 13: 2, # 'm' + 4: 3, # 'n' + 8: 0, # 'o' + 23: 1, # 'p' + 10: 3, # 'r' + 5: 2, # 's' + 3: 3, # 't' + 21: 0, # 'u' + 19: 3, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 2, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 0, # 'á' + 15: 0, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 25: { # 'ó' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 2, # 'a' + 18: 3, # 'b' + 26: 2, # 'c' + 17: 3, # 'd' + 1: 1, # 'e' + 27: 2, # 'f' + 12: 2, # 'g' + 20: 2, # 'h' + 9: 2, # 'i' + 22: 2, # 'j' + 7: 3, # 'k' + 6: 3, # 'l' + 13: 2, # 'm' + 4: 3, # 'n' + 8: 1, # 'o' + 23: 2, # 'p' + 10: 3, # 'r' + 5: 3, # 's' + 3: 3, # 't' + 21: 1, # 'u' + 19: 2, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 3, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 1, # 'á' + 15: 1, # 'é' + 30: 1, # 'í' + 25: 0, # 'ó' + 24: 1, # 'ö' + 31: 1, # 'ú' + 29: 1, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 24: { # 'ö' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 0, # 'a' + 18: 3, # 'b' + 26: 1, # 'c' + 17: 2, # 'd' + 1: 0, # 'e' + 27: 1, # 'f' + 12: 2, # 'g' + 20: 1, # 'h' + 9: 0, # 'i' + 22: 1, # 'j' + 7: 3, # 'k' + 6: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 8: 0, # 'o' + 23: 2, # 'p' + 10: 3, # 'r' + 5: 3, # 's' + 3: 3, # 't' + 21: 0, # 'u' + 19: 3, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 3, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 0, # 'á' + 15: 0, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 31: { # 'ú' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 1, # 'a' + 18: 1, # 'b' + 26: 2, # 'c' + 17: 1, # 'd' + 1: 1, # 'e' + 27: 2, # 'f' + 12: 3, # 'g' + 20: 1, # 'h' + 9: 1, # 'i' + 22: 3, # 'j' + 7: 1, # 'k' + 6: 3, # 'l' + 13: 1, # 'm' + 4: 2, # 'n' + 8: 0, # 'o' + 23: 1, # 'p' + 10: 3, # 'r' + 5: 3, # 's' + 3: 2, # 't' + 21: 1, # 'u' + 19: 1, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 2, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 1, # 'á' + 15: 1, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 29: { # 'ü' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 1, # 'a' + 18: 1, # 'b' + 26: 1, # 'c' + 17: 2, # 'd' + 1: 1, # 'e' + 27: 1, # 'f' + 12: 3, # 'g' + 20: 2, # 'h' + 9: 1, # 'i' + 22: 1, # 'j' + 7: 3, # 'k' + 6: 3, # 'l' + 13: 1, # 'm' + 4: 3, # 'n' + 8: 0, # 'o' + 23: 1, # 'p' + 10: 2, # 'r' + 5: 2, # 's' + 3: 2, # 't' + 21: 0, # 'u' + 19: 2, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 2, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 0, # 'á' + 15: 1, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 42: { # 'ő' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 1, # 'a' + 18: 2, # 'b' + 26: 1, # 'c' + 17: 2, # 'd' + 1: 1, # 'e' + 27: 1, # 'f' + 12: 1, # 'g' + 20: 1, # 'h' + 9: 1, # 'i' + 22: 1, # 'j' + 7: 2, # 'k' + 6: 3, # 'l' + 13: 1, # 'm' + 4: 2, # 'n' + 8: 1, # 'o' + 23: 1, # 'p' + 10: 2, # 'r' + 5: 2, # 's' + 3: 2, # 't' + 21: 1, # 'u' + 19: 1, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 2, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 0, # 'á' + 15: 1, # 'é' + 30: 1, # 'í' + 25: 0, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 1, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, + 56: { # 'ű' + 28: 0, # 'A' + 40: 0, # 'B' + 54: 0, # 'C' + 45: 0, # 'D' + 32: 0, # 'E' + 50: 0, # 'F' + 49: 0, # 'G' + 38: 0, # 'H' + 39: 0, # 'I' + 53: 0, # 'J' + 36: 0, # 'K' + 41: 0, # 'L' + 34: 0, # 'M' + 35: 0, # 'N' + 47: 0, # 'O' + 46: 0, # 'P' + 43: 0, # 'R' + 33: 0, # 'S' + 37: 0, # 'T' + 57: 0, # 'U' + 48: 0, # 'V' + 55: 0, # 'Y' + 52: 0, # 'Z' + 2: 1, # 'a' + 18: 1, # 'b' + 26: 0, # 'c' + 17: 1, # 'd' + 1: 1, # 'e' + 27: 1, # 'f' + 12: 1, # 'g' + 20: 1, # 'h' + 9: 1, # 'i' + 22: 1, # 'j' + 7: 1, # 'k' + 6: 1, # 'l' + 13: 0, # 'm' + 4: 2, # 'n' + 8: 0, # 'o' + 23: 0, # 'p' + 10: 1, # 'r' + 5: 1, # 's' + 3: 1, # 't' + 21: 0, # 'u' + 19: 1, # 'v' + 62: 0, # 'x' + 16: 0, # 'y' + 11: 2, # 'z' + 51: 0, # 'Á' + 44: 0, # 'É' + 61: 0, # 'Í' + 58: 0, # 'Ó' + 59: 0, # 'Ö' + 60: 0, # 'Ú' + 63: 0, # 'Ü' + 14: 0, # 'á' + 15: 0, # 'é' + 30: 0, # 'í' + 25: 0, # 'ó' + 24: 0, # 'ö' + 31: 0, # 'ú' + 29: 0, # 'ü' + 42: 0, # 'ő' + 56: 0, # 'ű' + }, +} + +# 255: Undefined characters that did not exist in training text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 +# 251: Control characters + +# Character Mapping Table(s): +WINDOWS_1250_HUNGARIAN_CHAR_TO_ORDER = { + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 28, # 'A' + 66: 40, # 'B' + 67: 54, # 'C' + 68: 45, # 'D' + 69: 32, # 'E' + 70: 50, # 'F' + 71: 49, # 'G' + 72: 38, # 'H' + 73: 39, # 'I' + 74: 53, # 'J' + 75: 36, # 'K' + 76: 41, # 'L' + 77: 34, # 'M' + 78: 35, # 'N' + 79: 47, # 'O' + 80: 46, # 'P' + 81: 72, # 'Q' + 82: 43, # 'R' + 83: 33, # 'S' + 84: 37, # 'T' + 85: 57, # 'U' + 86: 48, # 'V' + 87: 64, # 'W' + 88: 68, # 'X' + 89: 55, # 'Y' + 90: 52, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 2, # 'a' + 98: 18, # 'b' + 99: 26, # 'c' + 100: 17, # 'd' + 101: 1, # 'e' + 102: 27, # 'f' + 103: 12, # 'g' + 104: 20, # 'h' + 105: 9, # 'i' + 106: 22, # 'j' + 107: 7, # 'k' + 108: 6, # 'l' + 109: 13, # 'm' + 110: 4, # 'n' + 111: 8, # 'o' + 112: 23, # 'p' + 113: 67, # 'q' + 114: 10, # 'r' + 115: 5, # 's' + 116: 3, # 't' + 117: 21, # 'u' + 118: 19, # 'v' + 119: 65, # 'w' + 120: 62, # 'x' + 121: 16, # 'y' + 122: 11, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 161, # '€' + 129: 162, # None + 130: 163, # '‚' + 131: 164, # None + 132: 165, # '„' + 133: 166, # '…' + 134: 167, # '†' + 135: 168, # '‡' + 136: 169, # None + 137: 170, # '‰' + 138: 171, # 'Š' + 139: 172, # '‹' + 140: 173, # 'Ś' + 141: 174, # 'Ť' + 142: 175, # 'Ž' + 143: 176, # 'Ź' + 144: 177, # None + 145: 178, # '‘' + 146: 179, # '’' + 147: 180, # '“' + 148: 78, # '”' + 149: 181, # '•' + 150: 69, # '–' + 151: 182, # '—' + 152: 183, # None + 153: 184, # '™' + 154: 185, # 'š' + 155: 186, # '›' + 156: 187, # 'ś' + 157: 188, # 'ť' + 158: 189, # 'ž' + 159: 190, # 'ź' + 160: 191, # '\xa0' + 161: 192, # 'ˇ' + 162: 193, # '˘' + 163: 194, # 'Ł' + 164: 195, # '¤' + 165: 196, # 'Ą' + 166: 197, # '¦' + 167: 76, # '§' + 168: 198, # '¨' + 169: 199, # '©' + 170: 200, # 'Ş' + 171: 201, # '«' + 172: 202, # '¬' + 173: 203, # '\xad' + 174: 204, # '®' + 175: 205, # 'Ż' + 176: 81, # '°' + 177: 206, # '±' + 178: 207, # '˛' + 179: 208, # 'ł' + 180: 209, # '´' + 181: 210, # 'µ' + 182: 211, # '¶' + 183: 212, # '·' + 184: 213, # '¸' + 185: 214, # 'ą' + 186: 215, # 'ş' + 187: 216, # '»' + 188: 217, # 'Ľ' + 189: 218, # '˝' + 190: 219, # 'ľ' + 191: 220, # 'ż' + 192: 221, # 'Ŕ' + 193: 51, # 'Á' + 194: 83, # 'Â' + 195: 222, # 'Ă' + 196: 80, # 'Ä' + 197: 223, # 'Ĺ' + 198: 224, # 'Ć' + 199: 225, # 'Ç' + 200: 226, # 'Č' + 201: 44, # 'É' + 202: 227, # 'Ę' + 203: 228, # 'Ë' + 204: 229, # 'Ě' + 205: 61, # 'Í' + 206: 230, # 'Î' + 207: 231, # 'Ď' + 208: 232, # 'Đ' + 209: 233, # 'Ń' + 210: 234, # 'Ň' + 211: 58, # 'Ó' + 212: 235, # 'Ô' + 213: 66, # 'Ő' + 214: 59, # 'Ö' + 215: 236, # '×' + 216: 237, # 'Ř' + 217: 238, # 'Ů' + 218: 60, # 'Ú' + 219: 70, # 'Ű' + 220: 63, # 'Ü' + 221: 239, # 'Ý' + 222: 240, # 'Ţ' + 223: 241, # 'ß' + 224: 84, # 'ŕ' + 225: 14, # 'á' + 226: 75, # 'â' + 227: 242, # 'ă' + 228: 71, # 'ä' + 229: 82, # 'ĺ' + 230: 243, # 'ć' + 231: 73, # 'ç' + 232: 244, # 'č' + 233: 15, # 'é' + 234: 85, # 'ę' + 235: 79, # 'ë' + 236: 86, # 'ě' + 237: 30, # 'í' + 238: 77, # 'î' + 239: 87, # 'ď' + 240: 245, # 'đ' + 241: 246, # 'ń' + 242: 247, # 'ň' + 243: 25, # 'ó' + 244: 74, # 'ô' + 245: 42, # 'ő' + 246: 24, # 'ö' + 247: 248, # '÷' + 248: 249, # 'ř' + 249: 250, # 'ů' + 250: 31, # 'ú' + 251: 56, # 'ű' + 252: 29, # 'ü' + 253: 251, # 'ý' + 254: 252, # 'ţ' + 255: 253, # '˙' +} + +WINDOWS_1250_HUNGARIAN_MODEL = SingleByteCharSetModel(charset_name='windows-1250', + language='Hungarian', + char_to_order_map=WINDOWS_1250_HUNGARIAN_CHAR_TO_ORDER, + language_model=HUNGARIAN_LANG_MODEL, + typical_positive_ratio=0.947368, + keep_ascii_letters=True, + alphabet='ABCDEFGHIJKLMNOPRSTUVZabcdefghijklmnoprstuvzÁÉÍÓÖÚÜáéíóöúüŐőŰű') + +ISO_8859_2_HUNGARIAN_CHAR_TO_ORDER = { + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 28, # 'A' + 66: 40, # 'B' + 67: 54, # 'C' + 68: 45, # 'D' + 69: 32, # 'E' + 70: 50, # 'F' + 71: 49, # 'G' + 72: 38, # 'H' + 73: 39, # 'I' + 74: 53, # 'J' + 75: 36, # 'K' + 76: 41, # 'L' + 77: 34, # 'M' + 78: 35, # 'N' + 79: 47, # 'O' + 80: 46, # 'P' + 81: 71, # 'Q' + 82: 43, # 'R' + 83: 33, # 'S' + 84: 37, # 'T' + 85: 57, # 'U' + 86: 48, # 'V' + 87: 64, # 'W' + 88: 68, # 'X' + 89: 55, # 'Y' + 90: 52, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 2, # 'a' + 98: 18, # 'b' + 99: 26, # 'c' + 100: 17, # 'd' + 101: 1, # 'e' + 102: 27, # 'f' + 103: 12, # 'g' + 104: 20, # 'h' + 105: 9, # 'i' + 106: 22, # 'j' + 107: 7, # 'k' + 108: 6, # 'l' + 109: 13, # 'm' + 110: 4, # 'n' + 111: 8, # 'o' + 112: 23, # 'p' + 113: 67, # 'q' + 114: 10, # 'r' + 115: 5, # 's' + 116: 3, # 't' + 117: 21, # 'u' + 118: 19, # 'v' + 119: 65, # 'w' + 120: 62, # 'x' + 121: 16, # 'y' + 122: 11, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 159, # '\x80' + 129: 160, # '\x81' + 130: 161, # '\x82' + 131: 162, # '\x83' + 132: 163, # '\x84' + 133: 164, # '\x85' + 134: 165, # '\x86' + 135: 166, # '\x87' + 136: 167, # '\x88' + 137: 168, # '\x89' + 138: 169, # '\x8a' + 139: 170, # '\x8b' + 140: 171, # '\x8c' + 141: 172, # '\x8d' + 142: 173, # '\x8e' + 143: 174, # '\x8f' + 144: 175, # '\x90' + 145: 176, # '\x91' + 146: 177, # '\x92' + 147: 178, # '\x93' + 148: 179, # '\x94' + 149: 180, # '\x95' + 150: 181, # '\x96' + 151: 182, # '\x97' + 152: 183, # '\x98' + 153: 184, # '\x99' + 154: 185, # '\x9a' + 155: 186, # '\x9b' + 156: 187, # '\x9c' + 157: 188, # '\x9d' + 158: 189, # '\x9e' + 159: 190, # '\x9f' + 160: 191, # '\xa0' + 161: 192, # 'Ą' + 162: 193, # '˘' + 163: 194, # 'Ł' + 164: 195, # '¤' + 165: 196, # 'Ľ' + 166: 197, # 'Ś' + 167: 75, # '§' + 168: 198, # '¨' + 169: 199, # 'Š' + 170: 200, # 'Ş' + 171: 201, # 'Ť' + 172: 202, # 'Ź' + 173: 203, # '\xad' + 174: 204, # 'Ž' + 175: 205, # 'Ż' + 176: 79, # '°' + 177: 206, # 'ą' + 178: 207, # '˛' + 179: 208, # 'ł' + 180: 209, # '´' + 181: 210, # 'ľ' + 182: 211, # 'ś' + 183: 212, # 'ˇ' + 184: 213, # '¸' + 185: 214, # 'š' + 186: 215, # 'ş' + 187: 216, # 'ť' + 188: 217, # 'ź' + 189: 218, # '˝' + 190: 219, # 'ž' + 191: 220, # 'ż' + 192: 221, # 'Ŕ' + 193: 51, # 'Á' + 194: 81, # 'Â' + 195: 222, # 'Ă' + 196: 78, # 'Ä' + 197: 223, # 'Ĺ' + 198: 224, # 'Ć' + 199: 225, # 'Ç' + 200: 226, # 'Č' + 201: 44, # 'É' + 202: 227, # 'Ę' + 203: 228, # 'Ë' + 204: 229, # 'Ě' + 205: 61, # 'Í' + 206: 230, # 'Î' + 207: 231, # 'Ď' + 208: 232, # 'Đ' + 209: 233, # 'Ń' + 210: 234, # 'Ň' + 211: 58, # 'Ó' + 212: 235, # 'Ô' + 213: 66, # 'Ő' + 214: 59, # 'Ö' + 215: 236, # '×' + 216: 237, # 'Ř' + 217: 238, # 'Ů' + 218: 60, # 'Ú' + 219: 69, # 'Ű' + 220: 63, # 'Ü' + 221: 239, # 'Ý' + 222: 240, # 'Ţ' + 223: 241, # 'ß' + 224: 82, # 'ŕ' + 225: 14, # 'á' + 226: 74, # 'â' + 227: 242, # 'ă' + 228: 70, # 'ä' + 229: 80, # 'ĺ' + 230: 243, # 'ć' + 231: 72, # 'ç' + 232: 244, # 'č' + 233: 15, # 'é' + 234: 83, # 'ę' + 235: 77, # 'ë' + 236: 84, # 'ě' + 237: 30, # 'í' + 238: 76, # 'î' + 239: 85, # 'ď' + 240: 245, # 'đ' + 241: 246, # 'ń' + 242: 247, # 'ň' + 243: 25, # 'ó' + 244: 73, # 'ô' + 245: 42, # 'ő' + 246: 24, # 'ö' + 247: 248, # '÷' + 248: 249, # 'ř' + 249: 250, # 'ů' + 250: 31, # 'ú' + 251: 56, # 'ű' + 252: 29, # 'ü' + 253: 251, # 'ý' + 254: 252, # 'ţ' + 255: 253, # '˙' +} + +ISO_8859_2_HUNGARIAN_MODEL = SingleByteCharSetModel(charset_name='ISO-8859-2', + language='Hungarian', + char_to_order_map=ISO_8859_2_HUNGARIAN_CHAR_TO_ORDER, + language_model=HUNGARIAN_LANG_MODEL, + typical_positive_ratio=0.947368, + keep_ascii_letters=True, + alphabet='ABCDEFGHIJKLMNOPRSTUVZabcdefghijklmnoprstuvzÁÉÍÓÖÚÜáéíóöúüŐőŰű') + diff --git a/venv/lib/python3.8/site-packages/chardet/langrussianmodel.py b/venv/lib/python3.8/site-packages/chardet/langrussianmodel.py new file mode 100644 index 0000000..569689d --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/langrussianmodel.py @@ -0,0 +1,5718 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from chardet.sbcharsetprober import SingleByteCharSetModel + + +# 3: Positive +# 2: Likely +# 1: Unlikely +# 0: Negative + +RUSSIAN_LANG_MODEL = { + 37: { # 'А' + 37: 0, # 'А' + 44: 1, # 'Б' + 33: 1, # 'В' + 46: 1, # 'Г' + 41: 1, # 'Д' + 48: 1, # 'Е' + 56: 1, # 'Ж' + 51: 1, # 'З' + 42: 1, # 'И' + 60: 1, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 2, # 'Н' + 34: 1, # 'О' + 35: 1, # 'П' + 45: 1, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 1, # 'У' + 53: 1, # 'Ф' + 55: 1, # 'Х' + 58: 1, # 'Ц' + 50: 1, # 'Ч' + 57: 1, # 'Ш' + 63: 1, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 1, # 'Ю' + 43: 1, # 'Я' + 3: 1, # 'а' + 21: 2, # 'б' + 10: 2, # 'в' + 19: 2, # 'г' + 13: 2, # 'д' + 2: 0, # 'е' + 24: 1, # 'ж' + 20: 1, # 'з' + 4: 0, # 'и' + 23: 1, # 'й' + 11: 2, # 'к' + 8: 3, # 'л' + 12: 2, # 'м' + 5: 2, # 'н' + 1: 0, # 'о' + 15: 2, # 'п' + 9: 2, # 'р' + 7: 2, # 'с' + 6: 2, # 'т' + 14: 2, # 'у' + 39: 2, # 'ф' + 26: 2, # 'х' + 28: 0, # 'ц' + 22: 1, # 'ч' + 25: 2, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 1, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 44: { # 'Б' + 37: 1, # 'А' + 44: 0, # 'Б' + 33: 1, # 'В' + 46: 1, # 'Г' + 41: 0, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 0, # 'П' + 45: 1, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 1, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 1, # 'Я' + 3: 2, # 'а' + 21: 0, # 'б' + 10: 0, # 'в' + 19: 0, # 'г' + 13: 1, # 'д' + 2: 3, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 2, # 'л' + 12: 0, # 'м' + 5: 0, # 'н' + 1: 3, # 'о' + 15: 0, # 'п' + 9: 2, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 2, # 'ы' + 17: 1, # 'ь' + 30: 2, # 'э' + 27: 1, # 'ю' + 16: 1, # 'я' + }, + 33: { # 'В' + 37: 2, # 'А' + 44: 0, # 'Б' + 33: 1, # 'В' + 46: 0, # 'Г' + 41: 1, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 1, # 'П' + 45: 1, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 1, # 'Ш' + 63: 0, # 'Щ' + 62: 1, # 'Ы' + 61: 1, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 1, # 'Я' + 3: 2, # 'а' + 21: 1, # 'б' + 10: 1, # 'в' + 19: 1, # 'г' + 13: 2, # 'д' + 2: 3, # 'е' + 24: 0, # 'ж' + 20: 2, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 1, # 'к' + 8: 2, # 'л' + 12: 2, # 'м' + 5: 2, # 'н' + 1: 3, # 'о' + 15: 2, # 'п' + 9: 2, # 'р' + 7: 3, # 'с' + 6: 2, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 1, # 'х' + 28: 1, # 'ц' + 22: 2, # 'ч' + 25: 1, # 'ш' + 29: 0, # 'щ' + 54: 1, # 'ъ' + 18: 3, # 'ы' + 17: 1, # 'ь' + 30: 2, # 'э' + 27: 0, # 'ю' + 16: 1, # 'я' + }, + 46: { # 'Г' + 37: 1, # 'А' + 44: 1, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 1, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 1, # 'П' + 45: 1, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 2, # 'а' + 21: 0, # 'б' + 10: 1, # 'в' + 19: 0, # 'г' + 13: 2, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 2, # 'л' + 12: 1, # 'м' + 5: 1, # 'н' + 1: 3, # 'о' + 15: 0, # 'п' + 9: 2, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 1, # 'ь' + 30: 1, # 'э' + 27: 1, # 'ю' + 16: 0, # 'я' + }, + 41: { # 'Д' + 37: 1, # 'А' + 44: 0, # 'Б' + 33: 1, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 2, # 'Е' + 56: 1, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 0, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 0, # 'П' + 45: 1, # 'Р' + 32: 1, # 'С' + 40: 0, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 1, # 'Ц' + 50: 1, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 1, # 'Ы' + 61: 1, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 1, # 'Я' + 3: 3, # 'а' + 21: 0, # 'б' + 10: 2, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 2, # 'е' + 24: 3, # 'ж' + 20: 1, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 2, # 'л' + 12: 1, # 'м' + 5: 1, # 'н' + 1: 3, # 'о' + 15: 0, # 'п' + 9: 2, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 1, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 1, # 'ы' + 17: 1, # 'ь' + 30: 2, # 'э' + 27: 1, # 'ю' + 16: 1, # 'я' + }, + 48: { # 'Е' + 37: 1, # 'А' + 44: 1, # 'Б' + 33: 1, # 'В' + 46: 1, # 'Г' + 41: 1, # 'Д' + 48: 1, # 'Е' + 56: 1, # 'Ж' + 51: 1, # 'З' + 42: 1, # 'И' + 60: 1, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 2, # 'Н' + 34: 1, # 'О' + 35: 1, # 'П' + 45: 2, # 'Р' + 32: 2, # 'С' + 40: 1, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 1, # 'Х' + 58: 1, # 'Ц' + 50: 1, # 'Ч' + 57: 1, # 'Ш' + 63: 1, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 1, # 'Я' + 3: 0, # 'а' + 21: 0, # 'б' + 10: 2, # 'в' + 19: 2, # 'г' + 13: 2, # 'д' + 2: 2, # 'е' + 24: 1, # 'ж' + 20: 1, # 'з' + 4: 0, # 'и' + 23: 2, # 'й' + 11: 1, # 'к' + 8: 2, # 'л' + 12: 2, # 'м' + 5: 1, # 'н' + 1: 0, # 'о' + 15: 1, # 'п' + 9: 1, # 'р' + 7: 3, # 'с' + 6: 0, # 'т' + 14: 0, # 'у' + 39: 1, # 'ф' + 26: 1, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 1, # 'ш' + 29: 2, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 1, # 'ю' + 16: 0, # 'я' + }, + 56: { # 'Ж' + 37: 1, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 1, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 1, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 2, # 'а' + 21: 1, # 'б' + 10: 0, # 'в' + 19: 1, # 'г' + 13: 1, # 'д' + 2: 2, # 'е' + 24: 1, # 'ж' + 20: 0, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 0, # 'л' + 12: 1, # 'м' + 5: 0, # 'н' + 1: 2, # 'о' + 15: 0, # 'п' + 9: 1, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 2, # 'ю' + 16: 0, # 'я' + }, + 51: { # 'З' + 37: 1, # 'А' + 44: 0, # 'Б' + 33: 1, # 'В' + 46: 1, # 'Г' + 41: 1, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 0, # 'П' + 45: 1, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 1, # 'Ы' + 61: 1, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 1, # 'б' + 10: 2, # 'в' + 19: 0, # 'г' + 13: 2, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 1, # 'л' + 12: 1, # 'м' + 5: 2, # 'н' + 1: 2, # 'о' + 15: 0, # 'п' + 9: 1, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 1, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 1, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 0, # 'ю' + 16: 1, # 'я' + }, + 42: { # 'И' + 37: 1, # 'А' + 44: 1, # 'Б' + 33: 1, # 'В' + 46: 1, # 'Г' + 41: 1, # 'Д' + 48: 2, # 'Е' + 56: 1, # 'Ж' + 51: 1, # 'З' + 42: 1, # 'И' + 60: 1, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 1, # 'П' + 45: 1, # 'Р' + 32: 2, # 'С' + 40: 1, # 'Т' + 52: 0, # 'У' + 53: 1, # 'Ф' + 55: 1, # 'Х' + 58: 1, # 'Ц' + 50: 1, # 'Ч' + 57: 0, # 'Ш' + 63: 1, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 1, # 'Ю' + 43: 1, # 'Я' + 3: 1, # 'а' + 21: 2, # 'б' + 10: 2, # 'в' + 19: 2, # 'г' + 13: 2, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 2, # 'з' + 4: 1, # 'и' + 23: 0, # 'й' + 11: 1, # 'к' + 8: 2, # 'л' + 12: 2, # 'м' + 5: 2, # 'н' + 1: 1, # 'о' + 15: 1, # 'п' + 9: 2, # 'р' + 7: 2, # 'с' + 6: 2, # 'т' + 14: 1, # 'у' + 39: 1, # 'ф' + 26: 2, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 1, # 'ш' + 29: 1, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 1, # 'ю' + 16: 0, # 'я' + }, + 60: { # 'Й' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 1, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 0, # 'М' + 31: 1, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 1, # 'Х' + 58: 1, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 0, # 'а' + 21: 0, # 'б' + 10: 0, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 1, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 0, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 0, # 'л' + 12: 0, # 'м' + 5: 0, # 'н' + 1: 2, # 'о' + 15: 0, # 'п' + 9: 0, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 0, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 36: { # 'К' + 37: 2, # 'А' + 44: 0, # 'Б' + 33: 1, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 1, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 1, # 'Л' + 38: 0, # 'М' + 31: 1, # 'Н' + 34: 2, # 'О' + 35: 1, # 'П' + 45: 1, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 1, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 0, # 'б' + 10: 1, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 2, # 'л' + 12: 0, # 'м' + 5: 1, # 'н' + 1: 3, # 'о' + 15: 0, # 'п' + 9: 2, # 'р' + 7: 2, # 'с' + 6: 2, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 1, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 1, # 'ы' + 17: 1, # 'ь' + 30: 2, # 'э' + 27: 1, # 'ю' + 16: 0, # 'я' + }, + 49: { # 'Л' + 37: 2, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 1, # 'Г' + 41: 0, # 'Д' + 48: 1, # 'Е' + 56: 1, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 0, # 'Н' + 34: 1, # 'О' + 35: 1, # 'П' + 45: 0, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 1, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 1, # 'Ы' + 61: 1, # 'Ь' + 47: 0, # 'Э' + 59: 1, # 'Ю' + 43: 1, # 'Я' + 3: 2, # 'а' + 21: 0, # 'б' + 10: 0, # 'в' + 19: 1, # 'г' + 13: 0, # 'д' + 2: 2, # 'е' + 24: 1, # 'ж' + 20: 0, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 1, # 'л' + 12: 0, # 'м' + 5: 1, # 'н' + 1: 2, # 'о' + 15: 0, # 'п' + 9: 0, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 1, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 1, # 'ы' + 17: 1, # 'ь' + 30: 2, # 'э' + 27: 2, # 'ю' + 16: 1, # 'я' + }, + 38: { # 'М' + 37: 1, # 'А' + 44: 1, # 'Б' + 33: 1, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 1, # 'П' + 45: 1, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 1, # 'У' + 53: 1, # 'Ф' + 55: 1, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 1, # 'Ы' + 61: 0, # 'Ь' + 47: 1, # 'Э' + 59: 0, # 'Ю' + 43: 1, # 'Я' + 3: 3, # 'а' + 21: 0, # 'б' + 10: 0, # 'в' + 19: 1, # 'г' + 13: 0, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 1, # 'л' + 12: 1, # 'м' + 5: 2, # 'н' + 1: 3, # 'о' + 15: 0, # 'п' + 9: 1, # 'р' + 7: 1, # 'с' + 6: 0, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 3, # 'ы' + 17: 1, # 'ь' + 30: 2, # 'э' + 27: 1, # 'ю' + 16: 1, # 'я' + }, + 31: { # 'Н' + 37: 2, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 1, # 'Г' + 41: 1, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 1, # 'З' + 42: 2, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 0, # 'П' + 45: 1, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 1, # 'У' + 53: 1, # 'Ф' + 55: 1, # 'Х' + 58: 1, # 'Ц' + 50: 1, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 1, # 'Ы' + 61: 1, # 'Ь' + 47: 1, # 'Э' + 59: 0, # 'Ю' + 43: 1, # 'Я' + 3: 3, # 'а' + 21: 0, # 'б' + 10: 0, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 3, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 0, # 'л' + 12: 0, # 'м' + 5: 0, # 'н' + 1: 3, # 'о' + 15: 0, # 'п' + 9: 1, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 3, # 'у' + 39: 0, # 'ф' + 26: 1, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 1, # 'ы' + 17: 2, # 'ь' + 30: 1, # 'э' + 27: 1, # 'ю' + 16: 1, # 'я' + }, + 34: { # 'О' + 37: 0, # 'А' + 44: 1, # 'Б' + 33: 1, # 'В' + 46: 1, # 'Г' + 41: 2, # 'Д' + 48: 1, # 'Е' + 56: 1, # 'Ж' + 51: 1, # 'З' + 42: 1, # 'И' + 60: 1, # 'Й' + 36: 1, # 'К' + 49: 2, # 'Л' + 38: 1, # 'М' + 31: 2, # 'Н' + 34: 1, # 'О' + 35: 1, # 'П' + 45: 2, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 1, # 'У' + 53: 1, # 'Ф' + 55: 1, # 'Х' + 58: 0, # 'Ц' + 50: 1, # 'Ч' + 57: 1, # 'Ш' + 63: 1, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 1, # 'Я' + 3: 1, # 'а' + 21: 2, # 'б' + 10: 1, # 'в' + 19: 2, # 'г' + 13: 2, # 'д' + 2: 0, # 'е' + 24: 1, # 'ж' + 20: 1, # 'з' + 4: 0, # 'и' + 23: 1, # 'й' + 11: 2, # 'к' + 8: 2, # 'л' + 12: 1, # 'м' + 5: 3, # 'н' + 1: 0, # 'о' + 15: 2, # 'п' + 9: 2, # 'р' + 7: 2, # 'с' + 6: 2, # 'т' + 14: 1, # 'у' + 39: 1, # 'ф' + 26: 2, # 'х' + 28: 1, # 'ц' + 22: 2, # 'ч' + 25: 2, # 'ш' + 29: 1, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 35: { # 'П' + 37: 1, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 1, # 'Л' + 38: 0, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 1, # 'П' + 45: 2, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 1, # 'Ы' + 61: 1, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 1, # 'Я' + 3: 2, # 'а' + 21: 0, # 'б' + 10: 0, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 2, # 'л' + 12: 0, # 'м' + 5: 1, # 'н' + 1: 3, # 'о' + 15: 0, # 'п' + 9: 3, # 'р' + 7: 1, # 'с' + 6: 1, # 'т' + 14: 2, # 'у' + 39: 1, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 1, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 1, # 'ы' + 17: 2, # 'ь' + 30: 1, # 'э' + 27: 0, # 'ю' + 16: 2, # 'я' + }, + 45: { # 'Р' + 37: 2, # 'А' + 44: 1, # 'Б' + 33: 1, # 'В' + 46: 1, # 'Г' + 41: 1, # 'Д' + 48: 2, # 'Е' + 56: 1, # 'Ж' + 51: 0, # 'З' + 42: 2, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 2, # 'О' + 35: 0, # 'П' + 45: 1, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 1, # 'Х' + 58: 1, # 'Ц' + 50: 1, # 'Ч' + 57: 1, # 'Ш' + 63: 0, # 'Щ' + 62: 1, # 'Ы' + 61: 1, # 'Ь' + 47: 1, # 'Э' + 59: 1, # 'Ю' + 43: 1, # 'Я' + 3: 3, # 'а' + 21: 0, # 'б' + 10: 1, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 2, # 'е' + 24: 1, # 'ж' + 20: 0, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 0, # 'л' + 12: 0, # 'м' + 5: 0, # 'н' + 1: 3, # 'о' + 15: 0, # 'п' + 9: 1, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 2, # 'ы' + 17: 0, # 'ь' + 30: 1, # 'э' + 27: 1, # 'ю' + 16: 2, # 'я' + }, + 32: { # 'С' + 37: 1, # 'А' + 44: 1, # 'Б' + 33: 1, # 'В' + 46: 1, # 'Г' + 41: 1, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 1, # 'П' + 45: 1, # 'Р' + 32: 1, # 'С' + 40: 2, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 1, # 'Х' + 58: 1, # 'Ц' + 50: 1, # 'Ч' + 57: 1, # 'Ш' + 63: 0, # 'Щ' + 62: 1, # 'Ы' + 61: 1, # 'Ь' + 47: 1, # 'Э' + 59: 1, # 'Ю' + 43: 1, # 'Я' + 3: 2, # 'а' + 21: 1, # 'б' + 10: 2, # 'в' + 19: 1, # 'г' + 13: 2, # 'д' + 2: 3, # 'е' + 24: 1, # 'ж' + 20: 1, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 2, # 'к' + 8: 2, # 'л' + 12: 2, # 'м' + 5: 2, # 'н' + 1: 2, # 'о' + 15: 2, # 'п' + 9: 2, # 'р' + 7: 1, # 'с' + 6: 3, # 'т' + 14: 2, # 'у' + 39: 1, # 'ф' + 26: 1, # 'х' + 28: 1, # 'ц' + 22: 1, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 1, # 'ъ' + 18: 1, # 'ы' + 17: 1, # 'ь' + 30: 2, # 'э' + 27: 1, # 'ю' + 16: 1, # 'я' + }, + 40: { # 'Т' + 37: 1, # 'А' + 44: 0, # 'Б' + 33: 1, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 2, # 'О' + 35: 0, # 'П' + 45: 1, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 1, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 1, # 'Ы' + 61: 1, # 'Ь' + 47: 1, # 'Э' + 59: 1, # 'Ю' + 43: 1, # 'Я' + 3: 3, # 'а' + 21: 1, # 'б' + 10: 2, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 3, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 1, # 'к' + 8: 1, # 'л' + 12: 0, # 'м' + 5: 0, # 'н' + 1: 3, # 'о' + 15: 0, # 'п' + 9: 2, # 'р' + 7: 1, # 'с' + 6: 0, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 1, # 'щ' + 54: 0, # 'ъ' + 18: 3, # 'ы' + 17: 1, # 'ь' + 30: 2, # 'э' + 27: 1, # 'ю' + 16: 1, # 'я' + }, + 52: { # 'У' + 37: 1, # 'А' + 44: 1, # 'Б' + 33: 1, # 'В' + 46: 1, # 'Г' + 41: 1, # 'Д' + 48: 1, # 'Е' + 56: 1, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 1, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 1, # 'П' + 45: 1, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 1, # 'Х' + 58: 0, # 'Ц' + 50: 1, # 'Ч' + 57: 1, # 'Ш' + 63: 1, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 1, # 'Ю' + 43: 0, # 'Я' + 3: 1, # 'а' + 21: 2, # 'б' + 10: 2, # 'в' + 19: 1, # 'г' + 13: 2, # 'д' + 2: 1, # 'е' + 24: 2, # 'ж' + 20: 2, # 'з' + 4: 2, # 'и' + 23: 1, # 'й' + 11: 1, # 'к' + 8: 2, # 'л' + 12: 2, # 'м' + 5: 1, # 'н' + 1: 2, # 'о' + 15: 1, # 'п' + 9: 2, # 'р' + 7: 2, # 'с' + 6: 2, # 'т' + 14: 0, # 'у' + 39: 1, # 'ф' + 26: 1, # 'х' + 28: 1, # 'ц' + 22: 2, # 'ч' + 25: 1, # 'ш' + 29: 1, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 2, # 'э' + 27: 1, # 'ю' + 16: 0, # 'я' + }, + 53: { # 'Ф' + 37: 1, # 'А' + 44: 1, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 1, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 1, # 'О' + 35: 0, # 'П' + 45: 1, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 2, # 'а' + 21: 0, # 'б' + 10: 0, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 2, # 'л' + 12: 0, # 'м' + 5: 0, # 'н' + 1: 2, # 'о' + 15: 0, # 'п' + 9: 2, # 'р' + 7: 0, # 'с' + 6: 1, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 1, # 'ь' + 30: 2, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 55: { # 'Х' + 37: 1, # 'А' + 44: 0, # 'Б' + 33: 1, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 2, # 'а' + 21: 0, # 'б' + 10: 2, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 2, # 'л' + 12: 1, # 'м' + 5: 0, # 'н' + 1: 2, # 'о' + 15: 0, # 'п' + 9: 2, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 1, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 1, # 'ь' + 30: 1, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 58: { # 'Ц' + 37: 1, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 1, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 1, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 1, # 'а' + 21: 0, # 'б' + 10: 1, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 0, # 'л' + 12: 0, # 'м' + 5: 0, # 'н' + 1: 0, # 'о' + 15: 0, # 'п' + 9: 0, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 1, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 1, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 1, # 'ю' + 16: 0, # 'я' + }, + 50: { # 'Ч' + 37: 1, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 1, # 'Н' + 34: 0, # 'О' + 35: 1, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 1, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 1, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 2, # 'а' + 21: 0, # 'б' + 10: 0, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 1, # 'л' + 12: 0, # 'м' + 5: 0, # 'н' + 1: 1, # 'о' + 15: 0, # 'п' + 9: 1, # 'р' + 7: 0, # 'с' + 6: 3, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 1, # 'ь' + 30: 0, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 57: { # 'Ш' + 37: 1, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 0, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 1, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 2, # 'а' + 21: 0, # 'б' + 10: 1, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 1, # 'и' + 23: 0, # 'й' + 11: 1, # 'к' + 8: 2, # 'л' + 12: 1, # 'м' + 5: 1, # 'н' + 1: 2, # 'о' + 15: 2, # 'п' + 9: 1, # 'р' + 7: 0, # 'с' + 6: 2, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 1, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 1, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 1, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 63: { # 'Щ' + 37: 1, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 1, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 1, # 'а' + 21: 0, # 'б' + 10: 0, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 1, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 1, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 0, # 'л' + 12: 0, # 'м' + 5: 0, # 'н' + 1: 1, # 'о' + 15: 0, # 'п' + 9: 0, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 1, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 62: { # 'Ы' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 1, # 'В' + 46: 1, # 'Г' + 41: 0, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 1, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 0, # 'О' + 35: 1, # 'П' + 45: 1, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 1, # 'Х' + 58: 1, # 'Ц' + 50: 0, # 'Ч' + 57: 1, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 0, # 'а' + 21: 0, # 'б' + 10: 0, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 0, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 0, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 0, # 'л' + 12: 0, # 'м' + 5: 0, # 'н' + 1: 0, # 'о' + 15: 0, # 'п' + 9: 0, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 0, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 61: { # 'Ь' + 37: 0, # 'А' + 44: 1, # 'Б' + 33: 1, # 'В' + 46: 0, # 'Г' + 41: 1, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 0, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 1, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 1, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 1, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 1, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 1, # 'Ю' + 43: 1, # 'Я' + 3: 0, # 'а' + 21: 0, # 'б' + 10: 0, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 0, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 0, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 0, # 'л' + 12: 0, # 'м' + 5: 0, # 'н' + 1: 0, # 'о' + 15: 0, # 'п' + 9: 0, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 0, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 47: { # 'Э' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 1, # 'В' + 46: 0, # 'Г' + 41: 1, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 1, # 'Й' + 36: 1, # 'К' + 49: 1, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 0, # 'О' + 35: 1, # 'П' + 45: 1, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 1, # 'а' + 21: 1, # 'б' + 10: 2, # 'в' + 19: 1, # 'г' + 13: 2, # 'д' + 2: 0, # 'е' + 24: 1, # 'ж' + 20: 0, # 'з' + 4: 0, # 'и' + 23: 2, # 'й' + 11: 2, # 'к' + 8: 2, # 'л' + 12: 2, # 'м' + 5: 2, # 'н' + 1: 0, # 'о' + 15: 1, # 'п' + 9: 2, # 'р' + 7: 1, # 'с' + 6: 3, # 'т' + 14: 1, # 'у' + 39: 1, # 'ф' + 26: 1, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 1, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 59: { # 'Ю' + 37: 1, # 'А' + 44: 1, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 1, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 1, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 1, # 'Р' + 32: 0, # 'С' + 40: 1, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 1, # 'Ч' + 57: 0, # 'Ш' + 63: 1, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 0, # 'а' + 21: 1, # 'б' + 10: 0, # 'в' + 19: 1, # 'г' + 13: 1, # 'д' + 2: 0, # 'е' + 24: 1, # 'ж' + 20: 0, # 'з' + 4: 0, # 'и' + 23: 0, # 'й' + 11: 1, # 'к' + 8: 2, # 'л' + 12: 1, # 'м' + 5: 2, # 'н' + 1: 0, # 'о' + 15: 1, # 'п' + 9: 1, # 'р' + 7: 1, # 'с' + 6: 0, # 'т' + 14: 0, # 'у' + 39: 0, # 'ф' + 26: 1, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 43: { # 'Я' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 1, # 'В' + 46: 1, # 'Г' + 41: 0, # 'Д' + 48: 1, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 1, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 1, # 'С' + 40: 1, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 1, # 'Х' + 58: 0, # 'Ц' + 50: 1, # 'Ч' + 57: 0, # 'Ш' + 63: 1, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 1, # 'Ю' + 43: 1, # 'Я' + 3: 0, # 'а' + 21: 1, # 'б' + 10: 1, # 'в' + 19: 1, # 'г' + 13: 1, # 'д' + 2: 0, # 'е' + 24: 0, # 'ж' + 20: 1, # 'з' + 4: 0, # 'и' + 23: 1, # 'й' + 11: 1, # 'к' + 8: 1, # 'л' + 12: 1, # 'м' + 5: 2, # 'н' + 1: 0, # 'о' + 15: 1, # 'п' + 9: 1, # 'р' + 7: 1, # 'с' + 6: 0, # 'т' + 14: 0, # 'у' + 39: 0, # 'ф' + 26: 1, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 1, # 'ш' + 29: 1, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 3: { # 'а' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 1, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 1, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 2, # 'а' + 21: 3, # 'б' + 10: 3, # 'в' + 19: 3, # 'г' + 13: 3, # 'д' + 2: 3, # 'е' + 24: 3, # 'ж' + 20: 3, # 'з' + 4: 3, # 'и' + 23: 3, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 3, # 'м' + 5: 3, # 'н' + 1: 2, # 'о' + 15: 3, # 'п' + 9: 3, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 3, # 'у' + 39: 2, # 'ф' + 26: 3, # 'х' + 28: 3, # 'ц' + 22: 3, # 'ч' + 25: 3, # 'ш' + 29: 3, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 2, # 'э' + 27: 3, # 'ю' + 16: 3, # 'я' + }, + 21: { # 'б' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 1, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 2, # 'б' + 10: 2, # 'в' + 19: 1, # 'г' + 13: 2, # 'д' + 2: 3, # 'е' + 24: 2, # 'ж' + 20: 1, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 2, # 'к' + 8: 3, # 'л' + 12: 2, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 1, # 'п' + 9: 3, # 'р' + 7: 3, # 'с' + 6: 2, # 'т' + 14: 3, # 'у' + 39: 0, # 'ф' + 26: 2, # 'х' + 28: 1, # 'ц' + 22: 1, # 'ч' + 25: 2, # 'ш' + 29: 3, # 'щ' + 54: 2, # 'ъ' + 18: 3, # 'ы' + 17: 2, # 'ь' + 30: 1, # 'э' + 27: 2, # 'ю' + 16: 3, # 'я' + }, + 10: { # 'в' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 2, # 'б' + 10: 2, # 'в' + 19: 2, # 'г' + 13: 3, # 'д' + 2: 3, # 'е' + 24: 1, # 'ж' + 20: 3, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 2, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 3, # 'п' + 9: 3, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 3, # 'у' + 39: 1, # 'ф' + 26: 2, # 'х' + 28: 2, # 'ц' + 22: 2, # 'ч' + 25: 3, # 'ш' + 29: 2, # 'щ' + 54: 2, # 'ъ' + 18: 3, # 'ы' + 17: 3, # 'ь' + 30: 1, # 'э' + 27: 1, # 'ю' + 16: 3, # 'я' + }, + 19: { # 'г' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 1, # 'б' + 10: 2, # 'в' + 19: 1, # 'г' + 13: 3, # 'д' + 2: 3, # 'е' + 24: 0, # 'ж' + 20: 1, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 2, # 'к' + 8: 3, # 'л' + 12: 2, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 0, # 'п' + 9: 3, # 'р' + 7: 2, # 'с' + 6: 2, # 'т' + 14: 3, # 'у' + 39: 1, # 'ф' + 26: 1, # 'х' + 28: 1, # 'ц' + 22: 2, # 'ч' + 25: 1, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 1, # 'ы' + 17: 1, # 'ь' + 30: 1, # 'э' + 27: 1, # 'ю' + 16: 0, # 'я' + }, + 13: { # 'д' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 2, # 'б' + 10: 3, # 'в' + 19: 2, # 'г' + 13: 2, # 'д' + 2: 3, # 'е' + 24: 2, # 'ж' + 20: 2, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 2, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 2, # 'п' + 9: 3, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 3, # 'у' + 39: 1, # 'ф' + 26: 2, # 'х' + 28: 3, # 'ц' + 22: 2, # 'ч' + 25: 2, # 'ш' + 29: 1, # 'щ' + 54: 2, # 'ъ' + 18: 3, # 'ы' + 17: 3, # 'ь' + 30: 1, # 'э' + 27: 2, # 'ю' + 16: 3, # 'я' + }, + 2: { # 'е' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 2, # 'а' + 21: 3, # 'б' + 10: 3, # 'в' + 19: 3, # 'г' + 13: 3, # 'д' + 2: 3, # 'е' + 24: 3, # 'ж' + 20: 3, # 'з' + 4: 2, # 'и' + 23: 3, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 3, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 3, # 'п' + 9: 3, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 2, # 'у' + 39: 2, # 'ф' + 26: 3, # 'х' + 28: 3, # 'ц' + 22: 3, # 'ч' + 25: 3, # 'ш' + 29: 3, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 1, # 'э' + 27: 2, # 'ю' + 16: 3, # 'я' + }, + 24: { # 'ж' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 2, # 'б' + 10: 1, # 'в' + 19: 2, # 'г' + 13: 3, # 'д' + 2: 3, # 'е' + 24: 2, # 'ж' + 20: 1, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 2, # 'к' + 8: 2, # 'л' + 12: 1, # 'м' + 5: 3, # 'н' + 1: 2, # 'о' + 15: 1, # 'п' + 9: 2, # 'р' + 7: 2, # 'с' + 6: 1, # 'т' + 14: 3, # 'у' + 39: 1, # 'ф' + 26: 0, # 'х' + 28: 1, # 'ц' + 22: 2, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 1, # 'ы' + 17: 2, # 'ь' + 30: 1, # 'э' + 27: 1, # 'ю' + 16: 1, # 'я' + }, + 20: { # 'з' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 3, # 'б' + 10: 3, # 'в' + 19: 3, # 'г' + 13: 3, # 'д' + 2: 3, # 'е' + 24: 2, # 'ж' + 20: 2, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 3, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 0, # 'п' + 9: 3, # 'р' + 7: 2, # 'с' + 6: 2, # 'т' + 14: 3, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 1, # 'ц' + 22: 2, # 'ч' + 25: 1, # 'ш' + 29: 0, # 'щ' + 54: 2, # 'ъ' + 18: 3, # 'ы' + 17: 2, # 'ь' + 30: 1, # 'э' + 27: 1, # 'ю' + 16: 3, # 'я' + }, + 4: { # 'и' + 37: 1, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 1, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 3, # 'б' + 10: 3, # 'в' + 19: 3, # 'г' + 13: 3, # 'д' + 2: 3, # 'е' + 24: 3, # 'ж' + 20: 3, # 'з' + 4: 3, # 'и' + 23: 3, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 3, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 3, # 'п' + 9: 3, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 2, # 'у' + 39: 2, # 'ф' + 26: 3, # 'х' + 28: 3, # 'ц' + 22: 3, # 'ч' + 25: 3, # 'ш' + 29: 3, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 2, # 'э' + 27: 3, # 'ю' + 16: 3, # 'я' + }, + 23: { # 'й' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 1, # 'а' + 21: 1, # 'б' + 10: 1, # 'в' + 19: 2, # 'г' + 13: 3, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 2, # 'з' + 4: 1, # 'и' + 23: 0, # 'й' + 11: 2, # 'к' + 8: 2, # 'л' + 12: 2, # 'м' + 5: 3, # 'н' + 1: 2, # 'о' + 15: 1, # 'п' + 9: 2, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 1, # 'у' + 39: 2, # 'ф' + 26: 1, # 'х' + 28: 2, # 'ц' + 22: 3, # 'ч' + 25: 2, # 'ш' + 29: 1, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 1, # 'э' + 27: 1, # 'ю' + 16: 2, # 'я' + }, + 11: { # 'к' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 1, # 'б' + 10: 3, # 'в' + 19: 1, # 'г' + 13: 1, # 'д' + 2: 3, # 'е' + 24: 2, # 'ж' + 20: 2, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 2, # 'к' + 8: 3, # 'л' + 12: 1, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 0, # 'п' + 9: 3, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 3, # 'у' + 39: 1, # 'ф' + 26: 2, # 'х' + 28: 2, # 'ц' + 22: 1, # 'ч' + 25: 2, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 1, # 'ы' + 17: 1, # 'ь' + 30: 1, # 'э' + 27: 1, # 'ю' + 16: 1, # 'я' + }, + 8: { # 'л' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 2, # 'б' + 10: 2, # 'в' + 19: 3, # 'г' + 13: 2, # 'д' + 2: 3, # 'е' + 24: 3, # 'ж' + 20: 2, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 2, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 2, # 'п' + 9: 1, # 'р' + 7: 3, # 'с' + 6: 2, # 'т' + 14: 3, # 'у' + 39: 2, # 'ф' + 26: 2, # 'х' + 28: 1, # 'ц' + 22: 3, # 'ч' + 25: 2, # 'ш' + 29: 1, # 'щ' + 54: 0, # 'ъ' + 18: 3, # 'ы' + 17: 3, # 'ь' + 30: 1, # 'э' + 27: 3, # 'ю' + 16: 3, # 'я' + }, + 12: { # 'м' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 2, # 'б' + 10: 2, # 'в' + 19: 2, # 'г' + 13: 1, # 'д' + 2: 3, # 'е' + 24: 1, # 'ж' + 20: 1, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 2, # 'к' + 8: 3, # 'л' + 12: 2, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 2, # 'п' + 9: 2, # 'р' + 7: 3, # 'с' + 6: 2, # 'т' + 14: 3, # 'у' + 39: 2, # 'ф' + 26: 2, # 'х' + 28: 2, # 'ц' + 22: 2, # 'ч' + 25: 1, # 'ш' + 29: 1, # 'щ' + 54: 0, # 'ъ' + 18: 3, # 'ы' + 17: 2, # 'ь' + 30: 2, # 'э' + 27: 1, # 'ю' + 16: 3, # 'я' + }, + 5: { # 'н' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 2, # 'б' + 10: 2, # 'в' + 19: 3, # 'г' + 13: 3, # 'д' + 2: 3, # 'е' + 24: 2, # 'ж' + 20: 2, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 3, # 'к' + 8: 2, # 'л' + 12: 1, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 1, # 'п' + 9: 2, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 3, # 'у' + 39: 2, # 'ф' + 26: 2, # 'х' + 28: 3, # 'ц' + 22: 3, # 'ч' + 25: 2, # 'ш' + 29: 2, # 'щ' + 54: 1, # 'ъ' + 18: 3, # 'ы' + 17: 3, # 'ь' + 30: 1, # 'э' + 27: 3, # 'ю' + 16: 3, # 'я' + }, + 1: { # 'о' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 2, # 'а' + 21: 3, # 'б' + 10: 3, # 'в' + 19: 3, # 'г' + 13: 3, # 'д' + 2: 3, # 'е' + 24: 3, # 'ж' + 20: 3, # 'з' + 4: 3, # 'и' + 23: 3, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 3, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 3, # 'п' + 9: 3, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 2, # 'у' + 39: 2, # 'ф' + 26: 3, # 'х' + 28: 2, # 'ц' + 22: 3, # 'ч' + 25: 3, # 'ш' + 29: 3, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 2, # 'э' + 27: 3, # 'ю' + 16: 3, # 'я' + }, + 15: { # 'п' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 1, # 'б' + 10: 0, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 3, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 2, # 'к' + 8: 3, # 'л' + 12: 1, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 2, # 'п' + 9: 3, # 'р' + 7: 2, # 'с' + 6: 2, # 'т' + 14: 3, # 'у' + 39: 1, # 'ф' + 26: 0, # 'х' + 28: 2, # 'ц' + 22: 2, # 'ч' + 25: 1, # 'ш' + 29: 1, # 'щ' + 54: 0, # 'ъ' + 18: 3, # 'ы' + 17: 2, # 'ь' + 30: 1, # 'э' + 27: 1, # 'ю' + 16: 3, # 'я' + }, + 9: { # 'р' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 2, # 'б' + 10: 3, # 'в' + 19: 3, # 'г' + 13: 3, # 'д' + 2: 3, # 'е' + 24: 3, # 'ж' + 20: 2, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 3, # 'к' + 8: 2, # 'л' + 12: 3, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 2, # 'п' + 9: 2, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 3, # 'у' + 39: 2, # 'ф' + 26: 3, # 'х' + 28: 2, # 'ц' + 22: 2, # 'ч' + 25: 3, # 'ш' + 29: 2, # 'щ' + 54: 0, # 'ъ' + 18: 3, # 'ы' + 17: 3, # 'ь' + 30: 2, # 'э' + 27: 2, # 'ю' + 16: 3, # 'я' + }, + 7: { # 'с' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 1, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 2, # 'б' + 10: 3, # 'в' + 19: 2, # 'г' + 13: 3, # 'д' + 2: 3, # 'е' + 24: 2, # 'ж' + 20: 2, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 3, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 3, # 'п' + 9: 3, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 3, # 'у' + 39: 2, # 'ф' + 26: 3, # 'х' + 28: 2, # 'ц' + 22: 3, # 'ч' + 25: 2, # 'ш' + 29: 1, # 'щ' + 54: 2, # 'ъ' + 18: 3, # 'ы' + 17: 3, # 'ь' + 30: 2, # 'э' + 27: 3, # 'ю' + 16: 3, # 'я' + }, + 6: { # 'т' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 2, # 'б' + 10: 3, # 'в' + 19: 2, # 'г' + 13: 2, # 'д' + 2: 3, # 'е' + 24: 1, # 'ж' + 20: 1, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 2, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 2, # 'п' + 9: 3, # 'р' + 7: 3, # 'с' + 6: 2, # 'т' + 14: 3, # 'у' + 39: 2, # 'ф' + 26: 2, # 'х' + 28: 2, # 'ц' + 22: 2, # 'ч' + 25: 2, # 'ш' + 29: 2, # 'щ' + 54: 2, # 'ъ' + 18: 3, # 'ы' + 17: 3, # 'ь' + 30: 2, # 'э' + 27: 2, # 'ю' + 16: 3, # 'я' + }, + 14: { # 'у' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 2, # 'а' + 21: 3, # 'б' + 10: 3, # 'в' + 19: 3, # 'г' + 13: 3, # 'д' + 2: 3, # 'е' + 24: 3, # 'ж' + 20: 3, # 'з' + 4: 2, # 'и' + 23: 2, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 3, # 'м' + 5: 3, # 'н' + 1: 2, # 'о' + 15: 3, # 'п' + 9: 3, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 1, # 'у' + 39: 2, # 'ф' + 26: 3, # 'х' + 28: 2, # 'ц' + 22: 3, # 'ч' + 25: 3, # 'ш' + 29: 3, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 2, # 'э' + 27: 3, # 'ю' + 16: 2, # 'я' + }, + 39: { # 'ф' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 1, # 'б' + 10: 0, # 'в' + 19: 1, # 'г' + 13: 0, # 'д' + 2: 3, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 1, # 'к' + 8: 2, # 'л' + 12: 1, # 'м' + 5: 1, # 'н' + 1: 3, # 'о' + 15: 1, # 'п' + 9: 2, # 'р' + 7: 2, # 'с' + 6: 2, # 'т' + 14: 2, # 'у' + 39: 2, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 1, # 'ч' + 25: 1, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 2, # 'ы' + 17: 1, # 'ь' + 30: 2, # 'э' + 27: 1, # 'ю' + 16: 1, # 'я' + }, + 26: { # 'х' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 0, # 'б' + 10: 3, # 'в' + 19: 1, # 'г' + 13: 1, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 1, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 1, # 'к' + 8: 2, # 'л' + 12: 2, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 1, # 'п' + 9: 3, # 'р' + 7: 2, # 'с' + 6: 2, # 'т' + 14: 2, # 'у' + 39: 1, # 'ф' + 26: 1, # 'х' + 28: 1, # 'ц' + 22: 1, # 'ч' + 25: 2, # 'ш' + 29: 0, # 'щ' + 54: 1, # 'ъ' + 18: 0, # 'ы' + 17: 1, # 'ь' + 30: 1, # 'э' + 27: 1, # 'ю' + 16: 0, # 'я' + }, + 28: { # 'ц' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 1, # 'б' + 10: 2, # 'в' + 19: 1, # 'г' + 13: 1, # 'д' + 2: 3, # 'е' + 24: 0, # 'ж' + 20: 1, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 2, # 'к' + 8: 1, # 'л' + 12: 1, # 'м' + 5: 1, # 'н' + 1: 3, # 'о' + 15: 0, # 'п' + 9: 1, # 'р' + 7: 0, # 'с' + 6: 1, # 'т' + 14: 3, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 1, # 'ц' + 22: 0, # 'ч' + 25: 1, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 3, # 'ы' + 17: 1, # 'ь' + 30: 0, # 'э' + 27: 1, # 'ю' + 16: 0, # 'я' + }, + 22: { # 'ч' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 1, # 'б' + 10: 1, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 3, # 'е' + 24: 1, # 'ж' + 20: 0, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 3, # 'к' + 8: 2, # 'л' + 12: 1, # 'м' + 5: 3, # 'н' + 1: 2, # 'о' + 15: 0, # 'п' + 9: 2, # 'р' + 7: 1, # 'с' + 6: 3, # 'т' + 14: 3, # 'у' + 39: 1, # 'ф' + 26: 1, # 'х' + 28: 0, # 'ц' + 22: 1, # 'ч' + 25: 2, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 3, # 'ь' + 30: 0, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 25: { # 'ш' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 1, # 'б' + 10: 2, # 'в' + 19: 1, # 'г' + 13: 0, # 'д' + 2: 3, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 2, # 'м' + 5: 3, # 'н' + 1: 3, # 'о' + 15: 2, # 'п' + 9: 2, # 'р' + 7: 1, # 'с' + 6: 2, # 'т' + 14: 3, # 'у' + 39: 2, # 'ф' + 26: 1, # 'х' + 28: 1, # 'ц' + 22: 1, # 'ч' + 25: 1, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 3, # 'ь' + 30: 1, # 'э' + 27: 1, # 'ю' + 16: 0, # 'я' + }, + 29: { # 'щ' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 3, # 'а' + 21: 0, # 'б' + 10: 1, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 3, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 3, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 0, # 'л' + 12: 1, # 'м' + 5: 2, # 'н' + 1: 1, # 'о' + 15: 0, # 'п' + 9: 2, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 2, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 2, # 'ь' + 30: 0, # 'э' + 27: 0, # 'ю' + 16: 0, # 'я' + }, + 54: { # 'ъ' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 0, # 'а' + 21: 0, # 'б' + 10: 0, # 'в' + 19: 0, # 'г' + 13: 0, # 'д' + 2: 2, # 'е' + 24: 0, # 'ж' + 20: 0, # 'з' + 4: 0, # 'и' + 23: 0, # 'й' + 11: 0, # 'к' + 8: 0, # 'л' + 12: 0, # 'м' + 5: 0, # 'н' + 1: 0, # 'о' + 15: 0, # 'п' + 9: 0, # 'р' + 7: 0, # 'с' + 6: 0, # 'т' + 14: 0, # 'у' + 39: 0, # 'ф' + 26: 0, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 0, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 1, # 'ю' + 16: 2, # 'я' + }, + 18: { # 'ы' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 0, # 'а' + 21: 3, # 'б' + 10: 3, # 'в' + 19: 2, # 'г' + 13: 2, # 'д' + 2: 3, # 'е' + 24: 2, # 'ж' + 20: 2, # 'з' + 4: 2, # 'и' + 23: 3, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 3, # 'м' + 5: 3, # 'н' + 1: 1, # 'о' + 15: 3, # 'п' + 9: 3, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 1, # 'у' + 39: 0, # 'ф' + 26: 3, # 'х' + 28: 2, # 'ц' + 22: 3, # 'ч' + 25: 3, # 'ш' + 29: 2, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 0, # 'ю' + 16: 2, # 'я' + }, + 17: { # 'ь' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 0, # 'а' + 21: 2, # 'б' + 10: 2, # 'в' + 19: 2, # 'г' + 13: 2, # 'д' + 2: 3, # 'е' + 24: 1, # 'ж' + 20: 3, # 'з' + 4: 2, # 'и' + 23: 0, # 'й' + 11: 3, # 'к' + 8: 0, # 'л' + 12: 3, # 'м' + 5: 3, # 'н' + 1: 2, # 'о' + 15: 2, # 'п' + 9: 1, # 'р' + 7: 3, # 'с' + 6: 2, # 'т' + 14: 0, # 'у' + 39: 2, # 'ф' + 26: 1, # 'х' + 28: 2, # 'ц' + 22: 2, # 'ч' + 25: 3, # 'ш' + 29: 2, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 1, # 'э' + 27: 3, # 'ю' + 16: 3, # 'я' + }, + 30: { # 'э' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 1, # 'М' + 31: 1, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 1, # 'Р' + 32: 1, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 1, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 0, # 'а' + 21: 1, # 'б' + 10: 1, # 'в' + 19: 1, # 'г' + 13: 2, # 'д' + 2: 1, # 'е' + 24: 0, # 'ж' + 20: 1, # 'з' + 4: 0, # 'и' + 23: 2, # 'й' + 11: 2, # 'к' + 8: 2, # 'л' + 12: 2, # 'м' + 5: 2, # 'н' + 1: 0, # 'о' + 15: 2, # 'п' + 9: 2, # 'р' + 7: 2, # 'с' + 6: 3, # 'т' + 14: 1, # 'у' + 39: 2, # 'ф' + 26: 1, # 'х' + 28: 0, # 'ц' + 22: 0, # 'ч' + 25: 1, # 'ш' + 29: 0, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 1, # 'э' + 27: 1, # 'ю' + 16: 1, # 'я' + }, + 27: { # 'ю' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 2, # 'а' + 21: 3, # 'б' + 10: 1, # 'в' + 19: 2, # 'г' + 13: 3, # 'д' + 2: 1, # 'е' + 24: 2, # 'ж' + 20: 2, # 'з' + 4: 1, # 'и' + 23: 1, # 'й' + 11: 2, # 'к' + 8: 2, # 'л' + 12: 2, # 'м' + 5: 2, # 'н' + 1: 1, # 'о' + 15: 2, # 'п' + 9: 2, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 0, # 'у' + 39: 1, # 'ф' + 26: 2, # 'х' + 28: 2, # 'ц' + 22: 2, # 'ч' + 25: 2, # 'ш' + 29: 3, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 1, # 'э' + 27: 2, # 'ю' + 16: 1, # 'я' + }, + 16: { # 'я' + 37: 0, # 'А' + 44: 0, # 'Б' + 33: 0, # 'В' + 46: 0, # 'Г' + 41: 0, # 'Д' + 48: 0, # 'Е' + 56: 0, # 'Ж' + 51: 0, # 'З' + 42: 0, # 'И' + 60: 0, # 'Й' + 36: 0, # 'К' + 49: 0, # 'Л' + 38: 0, # 'М' + 31: 0, # 'Н' + 34: 0, # 'О' + 35: 0, # 'П' + 45: 0, # 'Р' + 32: 0, # 'С' + 40: 0, # 'Т' + 52: 0, # 'У' + 53: 0, # 'Ф' + 55: 0, # 'Х' + 58: 0, # 'Ц' + 50: 0, # 'Ч' + 57: 0, # 'Ш' + 63: 0, # 'Щ' + 62: 0, # 'Ы' + 61: 0, # 'Ь' + 47: 0, # 'Э' + 59: 0, # 'Ю' + 43: 0, # 'Я' + 3: 0, # 'а' + 21: 2, # 'б' + 10: 3, # 'в' + 19: 2, # 'г' + 13: 3, # 'д' + 2: 3, # 'е' + 24: 3, # 'ж' + 20: 3, # 'з' + 4: 2, # 'и' + 23: 2, # 'й' + 11: 3, # 'к' + 8: 3, # 'л' + 12: 3, # 'м' + 5: 3, # 'н' + 1: 0, # 'о' + 15: 2, # 'п' + 9: 2, # 'р' + 7: 3, # 'с' + 6: 3, # 'т' + 14: 1, # 'у' + 39: 1, # 'ф' + 26: 3, # 'х' + 28: 2, # 'ц' + 22: 2, # 'ч' + 25: 2, # 'ш' + 29: 3, # 'щ' + 54: 0, # 'ъ' + 18: 0, # 'ы' + 17: 0, # 'ь' + 30: 0, # 'э' + 27: 2, # 'ю' + 16: 2, # 'я' + }, +} + +# 255: Undefined characters that did not exist in training text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 +# 251: Control characters + +# Character Mapping Table(s): +IBM866_RUSSIAN_CHAR_TO_ORDER = { + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 142, # 'A' + 66: 143, # 'B' + 67: 144, # 'C' + 68: 145, # 'D' + 69: 146, # 'E' + 70: 147, # 'F' + 71: 148, # 'G' + 72: 149, # 'H' + 73: 150, # 'I' + 74: 151, # 'J' + 75: 152, # 'K' + 76: 74, # 'L' + 77: 153, # 'M' + 78: 75, # 'N' + 79: 154, # 'O' + 80: 155, # 'P' + 81: 156, # 'Q' + 82: 157, # 'R' + 83: 158, # 'S' + 84: 159, # 'T' + 85: 160, # 'U' + 86: 161, # 'V' + 87: 162, # 'W' + 88: 163, # 'X' + 89: 164, # 'Y' + 90: 165, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 71, # 'a' + 98: 172, # 'b' + 99: 66, # 'c' + 100: 173, # 'd' + 101: 65, # 'e' + 102: 174, # 'f' + 103: 76, # 'g' + 104: 175, # 'h' + 105: 64, # 'i' + 106: 176, # 'j' + 107: 177, # 'k' + 108: 77, # 'l' + 109: 72, # 'm' + 110: 178, # 'n' + 111: 69, # 'o' + 112: 67, # 'p' + 113: 179, # 'q' + 114: 78, # 'r' + 115: 73, # 's' + 116: 180, # 't' + 117: 181, # 'u' + 118: 79, # 'v' + 119: 182, # 'w' + 120: 183, # 'x' + 121: 184, # 'y' + 122: 185, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 37, # 'А' + 129: 44, # 'Б' + 130: 33, # 'В' + 131: 46, # 'Г' + 132: 41, # 'Д' + 133: 48, # 'Е' + 134: 56, # 'Ж' + 135: 51, # 'З' + 136: 42, # 'И' + 137: 60, # 'Й' + 138: 36, # 'К' + 139: 49, # 'Л' + 140: 38, # 'М' + 141: 31, # 'Н' + 142: 34, # 'О' + 143: 35, # 'П' + 144: 45, # 'Р' + 145: 32, # 'С' + 146: 40, # 'Т' + 147: 52, # 'У' + 148: 53, # 'Ф' + 149: 55, # 'Х' + 150: 58, # 'Ц' + 151: 50, # 'Ч' + 152: 57, # 'Ш' + 153: 63, # 'Щ' + 154: 70, # 'Ъ' + 155: 62, # 'Ы' + 156: 61, # 'Ь' + 157: 47, # 'Э' + 158: 59, # 'Ю' + 159: 43, # 'Я' + 160: 3, # 'а' + 161: 21, # 'б' + 162: 10, # 'в' + 163: 19, # 'г' + 164: 13, # 'д' + 165: 2, # 'е' + 166: 24, # 'ж' + 167: 20, # 'з' + 168: 4, # 'и' + 169: 23, # 'й' + 170: 11, # 'к' + 171: 8, # 'л' + 172: 12, # 'м' + 173: 5, # 'н' + 174: 1, # 'о' + 175: 15, # 'п' + 176: 191, # '░' + 177: 192, # '▒' + 178: 193, # '▓' + 179: 194, # '│' + 180: 195, # '┤' + 181: 196, # '╡' + 182: 197, # '╢' + 183: 198, # '╖' + 184: 199, # '╕' + 185: 200, # '╣' + 186: 201, # '║' + 187: 202, # '╗' + 188: 203, # '╝' + 189: 204, # '╜' + 190: 205, # '╛' + 191: 206, # '┐' + 192: 207, # '└' + 193: 208, # '┴' + 194: 209, # '┬' + 195: 210, # '├' + 196: 211, # '─' + 197: 212, # '┼' + 198: 213, # '╞' + 199: 214, # '╟' + 200: 215, # '╚' + 201: 216, # '╔' + 202: 217, # '╩' + 203: 218, # '╦' + 204: 219, # '╠' + 205: 220, # '═' + 206: 221, # '╬' + 207: 222, # '╧' + 208: 223, # '╨' + 209: 224, # '╤' + 210: 225, # '╥' + 211: 226, # '╙' + 212: 227, # '╘' + 213: 228, # '╒' + 214: 229, # '╓' + 215: 230, # '╫' + 216: 231, # '╪' + 217: 232, # '┘' + 218: 233, # '┌' + 219: 234, # '█' + 220: 235, # '▄' + 221: 236, # '▌' + 222: 237, # '▐' + 223: 238, # '▀' + 224: 9, # 'р' + 225: 7, # 'с' + 226: 6, # 'т' + 227: 14, # 'у' + 228: 39, # 'ф' + 229: 26, # 'х' + 230: 28, # 'ц' + 231: 22, # 'ч' + 232: 25, # 'ш' + 233: 29, # 'щ' + 234: 54, # 'ъ' + 235: 18, # 'ы' + 236: 17, # 'ь' + 237: 30, # 'э' + 238: 27, # 'ю' + 239: 16, # 'я' + 240: 239, # 'Ё' + 241: 68, # 'ё' + 242: 240, # 'Є' + 243: 241, # 'є' + 244: 242, # 'Ї' + 245: 243, # 'ї' + 246: 244, # 'Ў' + 247: 245, # 'ў' + 248: 246, # '°' + 249: 247, # '∙' + 250: 248, # '·' + 251: 249, # '√' + 252: 250, # '№' + 253: 251, # '¤' + 254: 252, # '■' + 255: 255, # '\xa0' +} + +IBM866_RUSSIAN_MODEL = SingleByteCharSetModel(charset_name='IBM866', + language='Russian', + char_to_order_map=IBM866_RUSSIAN_CHAR_TO_ORDER, + language_model=RUSSIAN_LANG_MODEL, + typical_positive_ratio=0.976601, + keep_ascii_letters=False, + alphabet='ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё') + +WINDOWS_1251_RUSSIAN_CHAR_TO_ORDER = { + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 142, # 'A' + 66: 143, # 'B' + 67: 144, # 'C' + 68: 145, # 'D' + 69: 146, # 'E' + 70: 147, # 'F' + 71: 148, # 'G' + 72: 149, # 'H' + 73: 150, # 'I' + 74: 151, # 'J' + 75: 152, # 'K' + 76: 74, # 'L' + 77: 153, # 'M' + 78: 75, # 'N' + 79: 154, # 'O' + 80: 155, # 'P' + 81: 156, # 'Q' + 82: 157, # 'R' + 83: 158, # 'S' + 84: 159, # 'T' + 85: 160, # 'U' + 86: 161, # 'V' + 87: 162, # 'W' + 88: 163, # 'X' + 89: 164, # 'Y' + 90: 165, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 71, # 'a' + 98: 172, # 'b' + 99: 66, # 'c' + 100: 173, # 'd' + 101: 65, # 'e' + 102: 174, # 'f' + 103: 76, # 'g' + 104: 175, # 'h' + 105: 64, # 'i' + 106: 176, # 'j' + 107: 177, # 'k' + 108: 77, # 'l' + 109: 72, # 'm' + 110: 178, # 'n' + 111: 69, # 'o' + 112: 67, # 'p' + 113: 179, # 'q' + 114: 78, # 'r' + 115: 73, # 's' + 116: 180, # 't' + 117: 181, # 'u' + 118: 79, # 'v' + 119: 182, # 'w' + 120: 183, # 'x' + 121: 184, # 'y' + 122: 185, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 191, # 'Ђ' + 129: 192, # 'Ѓ' + 130: 193, # '‚' + 131: 194, # 'ѓ' + 132: 195, # '„' + 133: 196, # '…' + 134: 197, # '†' + 135: 198, # '‡' + 136: 199, # '€' + 137: 200, # '‰' + 138: 201, # 'Љ' + 139: 202, # '‹' + 140: 203, # 'Њ' + 141: 204, # 'Ќ' + 142: 205, # 'Ћ' + 143: 206, # 'Џ' + 144: 207, # 'ђ' + 145: 208, # '‘' + 146: 209, # '’' + 147: 210, # '“' + 148: 211, # '”' + 149: 212, # '•' + 150: 213, # '–' + 151: 214, # '—' + 152: 215, # None + 153: 216, # '™' + 154: 217, # 'љ' + 155: 218, # '›' + 156: 219, # 'њ' + 157: 220, # 'ќ' + 158: 221, # 'ћ' + 159: 222, # 'џ' + 160: 223, # '\xa0' + 161: 224, # 'Ў' + 162: 225, # 'ў' + 163: 226, # 'Ј' + 164: 227, # '¤' + 165: 228, # 'Ґ' + 166: 229, # '¦' + 167: 230, # '§' + 168: 231, # 'Ё' + 169: 232, # '©' + 170: 233, # 'Є' + 171: 234, # '«' + 172: 235, # '¬' + 173: 236, # '\xad' + 174: 237, # '®' + 175: 238, # 'Ї' + 176: 239, # '°' + 177: 240, # '±' + 178: 241, # 'І' + 179: 242, # 'і' + 180: 243, # 'ґ' + 181: 244, # 'µ' + 182: 245, # '¶' + 183: 246, # '·' + 184: 68, # 'ё' + 185: 247, # '№' + 186: 248, # 'є' + 187: 249, # '»' + 188: 250, # 'ј' + 189: 251, # 'Ѕ' + 190: 252, # 'ѕ' + 191: 253, # 'ї' + 192: 37, # 'А' + 193: 44, # 'Б' + 194: 33, # 'В' + 195: 46, # 'Г' + 196: 41, # 'Д' + 197: 48, # 'Е' + 198: 56, # 'Ж' + 199: 51, # 'З' + 200: 42, # 'И' + 201: 60, # 'Й' + 202: 36, # 'К' + 203: 49, # 'Л' + 204: 38, # 'М' + 205: 31, # 'Н' + 206: 34, # 'О' + 207: 35, # 'П' + 208: 45, # 'Р' + 209: 32, # 'С' + 210: 40, # 'Т' + 211: 52, # 'У' + 212: 53, # 'Ф' + 213: 55, # 'Х' + 214: 58, # 'Ц' + 215: 50, # 'Ч' + 216: 57, # 'Ш' + 217: 63, # 'Щ' + 218: 70, # 'Ъ' + 219: 62, # 'Ы' + 220: 61, # 'Ь' + 221: 47, # 'Э' + 222: 59, # 'Ю' + 223: 43, # 'Я' + 224: 3, # 'а' + 225: 21, # 'б' + 226: 10, # 'в' + 227: 19, # 'г' + 228: 13, # 'д' + 229: 2, # 'е' + 230: 24, # 'ж' + 231: 20, # 'з' + 232: 4, # 'и' + 233: 23, # 'й' + 234: 11, # 'к' + 235: 8, # 'л' + 236: 12, # 'м' + 237: 5, # 'н' + 238: 1, # 'о' + 239: 15, # 'п' + 240: 9, # 'р' + 241: 7, # 'с' + 242: 6, # 'т' + 243: 14, # 'у' + 244: 39, # 'ф' + 245: 26, # 'х' + 246: 28, # 'ц' + 247: 22, # 'ч' + 248: 25, # 'ш' + 249: 29, # 'щ' + 250: 54, # 'ъ' + 251: 18, # 'ы' + 252: 17, # 'ь' + 253: 30, # 'э' + 254: 27, # 'ю' + 255: 16, # 'я' +} + +WINDOWS_1251_RUSSIAN_MODEL = SingleByteCharSetModel(charset_name='windows-1251', + language='Russian', + char_to_order_map=WINDOWS_1251_RUSSIAN_CHAR_TO_ORDER, + language_model=RUSSIAN_LANG_MODEL, + typical_positive_ratio=0.976601, + keep_ascii_letters=False, + alphabet='ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё') + +IBM855_RUSSIAN_CHAR_TO_ORDER = { + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 142, # 'A' + 66: 143, # 'B' + 67: 144, # 'C' + 68: 145, # 'D' + 69: 146, # 'E' + 70: 147, # 'F' + 71: 148, # 'G' + 72: 149, # 'H' + 73: 150, # 'I' + 74: 151, # 'J' + 75: 152, # 'K' + 76: 74, # 'L' + 77: 153, # 'M' + 78: 75, # 'N' + 79: 154, # 'O' + 80: 155, # 'P' + 81: 156, # 'Q' + 82: 157, # 'R' + 83: 158, # 'S' + 84: 159, # 'T' + 85: 160, # 'U' + 86: 161, # 'V' + 87: 162, # 'W' + 88: 163, # 'X' + 89: 164, # 'Y' + 90: 165, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 71, # 'a' + 98: 172, # 'b' + 99: 66, # 'c' + 100: 173, # 'd' + 101: 65, # 'e' + 102: 174, # 'f' + 103: 76, # 'g' + 104: 175, # 'h' + 105: 64, # 'i' + 106: 176, # 'j' + 107: 177, # 'k' + 108: 77, # 'l' + 109: 72, # 'm' + 110: 178, # 'n' + 111: 69, # 'o' + 112: 67, # 'p' + 113: 179, # 'q' + 114: 78, # 'r' + 115: 73, # 's' + 116: 180, # 't' + 117: 181, # 'u' + 118: 79, # 'v' + 119: 182, # 'w' + 120: 183, # 'x' + 121: 184, # 'y' + 122: 185, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 191, # 'ђ' + 129: 192, # 'Ђ' + 130: 193, # 'ѓ' + 131: 194, # 'Ѓ' + 132: 68, # 'ё' + 133: 195, # 'Ё' + 134: 196, # 'є' + 135: 197, # 'Є' + 136: 198, # 'ѕ' + 137: 199, # 'Ѕ' + 138: 200, # 'і' + 139: 201, # 'І' + 140: 202, # 'ї' + 141: 203, # 'Ї' + 142: 204, # 'ј' + 143: 205, # 'Ј' + 144: 206, # 'љ' + 145: 207, # 'Љ' + 146: 208, # 'њ' + 147: 209, # 'Њ' + 148: 210, # 'ћ' + 149: 211, # 'Ћ' + 150: 212, # 'ќ' + 151: 213, # 'Ќ' + 152: 214, # 'ў' + 153: 215, # 'Ў' + 154: 216, # 'џ' + 155: 217, # 'Џ' + 156: 27, # 'ю' + 157: 59, # 'Ю' + 158: 54, # 'ъ' + 159: 70, # 'Ъ' + 160: 3, # 'а' + 161: 37, # 'А' + 162: 21, # 'б' + 163: 44, # 'Б' + 164: 28, # 'ц' + 165: 58, # 'Ц' + 166: 13, # 'д' + 167: 41, # 'Д' + 168: 2, # 'е' + 169: 48, # 'Е' + 170: 39, # 'ф' + 171: 53, # 'Ф' + 172: 19, # 'г' + 173: 46, # 'Г' + 174: 218, # '«' + 175: 219, # '»' + 176: 220, # '░' + 177: 221, # '▒' + 178: 222, # '▓' + 179: 223, # '│' + 180: 224, # '┤' + 181: 26, # 'х' + 182: 55, # 'Х' + 183: 4, # 'и' + 184: 42, # 'И' + 185: 225, # '╣' + 186: 226, # '║' + 187: 227, # '╗' + 188: 228, # '╝' + 189: 23, # 'й' + 190: 60, # 'Й' + 191: 229, # '┐' + 192: 230, # '└' + 193: 231, # '┴' + 194: 232, # '┬' + 195: 233, # '├' + 196: 234, # '─' + 197: 235, # '┼' + 198: 11, # 'к' + 199: 36, # 'К' + 200: 236, # '╚' + 201: 237, # '╔' + 202: 238, # '╩' + 203: 239, # '╦' + 204: 240, # '╠' + 205: 241, # '═' + 206: 242, # '╬' + 207: 243, # '¤' + 208: 8, # 'л' + 209: 49, # 'Л' + 210: 12, # 'м' + 211: 38, # 'М' + 212: 5, # 'н' + 213: 31, # 'Н' + 214: 1, # 'о' + 215: 34, # 'О' + 216: 15, # 'п' + 217: 244, # '┘' + 218: 245, # '┌' + 219: 246, # '█' + 220: 247, # '▄' + 221: 35, # 'П' + 222: 16, # 'я' + 223: 248, # '▀' + 224: 43, # 'Я' + 225: 9, # 'р' + 226: 45, # 'Р' + 227: 7, # 'с' + 228: 32, # 'С' + 229: 6, # 'т' + 230: 40, # 'Т' + 231: 14, # 'у' + 232: 52, # 'У' + 233: 24, # 'ж' + 234: 56, # 'Ж' + 235: 10, # 'в' + 236: 33, # 'В' + 237: 17, # 'ь' + 238: 61, # 'Ь' + 239: 249, # '№' + 240: 250, # '\xad' + 241: 18, # 'ы' + 242: 62, # 'Ы' + 243: 20, # 'з' + 244: 51, # 'З' + 245: 25, # 'ш' + 246: 57, # 'Ш' + 247: 30, # 'э' + 248: 47, # 'Э' + 249: 29, # 'щ' + 250: 63, # 'Щ' + 251: 22, # 'ч' + 252: 50, # 'Ч' + 253: 251, # '§' + 254: 252, # '■' + 255: 255, # '\xa0' +} + +IBM855_RUSSIAN_MODEL = SingleByteCharSetModel(charset_name='IBM855', + language='Russian', + char_to_order_map=IBM855_RUSSIAN_CHAR_TO_ORDER, + language_model=RUSSIAN_LANG_MODEL, + typical_positive_ratio=0.976601, + keep_ascii_letters=False, + alphabet='ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё') + +KOI8_R_RUSSIAN_CHAR_TO_ORDER = { + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 142, # 'A' + 66: 143, # 'B' + 67: 144, # 'C' + 68: 145, # 'D' + 69: 146, # 'E' + 70: 147, # 'F' + 71: 148, # 'G' + 72: 149, # 'H' + 73: 150, # 'I' + 74: 151, # 'J' + 75: 152, # 'K' + 76: 74, # 'L' + 77: 153, # 'M' + 78: 75, # 'N' + 79: 154, # 'O' + 80: 155, # 'P' + 81: 156, # 'Q' + 82: 157, # 'R' + 83: 158, # 'S' + 84: 159, # 'T' + 85: 160, # 'U' + 86: 161, # 'V' + 87: 162, # 'W' + 88: 163, # 'X' + 89: 164, # 'Y' + 90: 165, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 71, # 'a' + 98: 172, # 'b' + 99: 66, # 'c' + 100: 173, # 'd' + 101: 65, # 'e' + 102: 174, # 'f' + 103: 76, # 'g' + 104: 175, # 'h' + 105: 64, # 'i' + 106: 176, # 'j' + 107: 177, # 'k' + 108: 77, # 'l' + 109: 72, # 'm' + 110: 178, # 'n' + 111: 69, # 'o' + 112: 67, # 'p' + 113: 179, # 'q' + 114: 78, # 'r' + 115: 73, # 's' + 116: 180, # 't' + 117: 181, # 'u' + 118: 79, # 'v' + 119: 182, # 'w' + 120: 183, # 'x' + 121: 184, # 'y' + 122: 185, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 191, # '─' + 129: 192, # '│' + 130: 193, # '┌' + 131: 194, # '┐' + 132: 195, # '└' + 133: 196, # '┘' + 134: 197, # '├' + 135: 198, # '┤' + 136: 199, # '┬' + 137: 200, # '┴' + 138: 201, # '┼' + 139: 202, # '▀' + 140: 203, # '▄' + 141: 204, # '█' + 142: 205, # '▌' + 143: 206, # '▐' + 144: 207, # '░' + 145: 208, # '▒' + 146: 209, # '▓' + 147: 210, # '⌠' + 148: 211, # '■' + 149: 212, # '∙' + 150: 213, # '√' + 151: 214, # '≈' + 152: 215, # '≤' + 153: 216, # '≥' + 154: 217, # '\xa0' + 155: 218, # '⌡' + 156: 219, # '°' + 157: 220, # '²' + 158: 221, # '·' + 159: 222, # '÷' + 160: 223, # '═' + 161: 224, # '║' + 162: 225, # '╒' + 163: 68, # 'ё' + 164: 226, # '╓' + 165: 227, # '╔' + 166: 228, # '╕' + 167: 229, # '╖' + 168: 230, # '╗' + 169: 231, # '╘' + 170: 232, # '╙' + 171: 233, # '╚' + 172: 234, # '╛' + 173: 235, # '╜' + 174: 236, # '╝' + 175: 237, # '╞' + 176: 238, # '╟' + 177: 239, # '╠' + 178: 240, # '╡' + 179: 241, # 'Ё' + 180: 242, # '╢' + 181: 243, # '╣' + 182: 244, # '╤' + 183: 245, # '╥' + 184: 246, # '╦' + 185: 247, # '╧' + 186: 248, # '╨' + 187: 249, # '╩' + 188: 250, # '╪' + 189: 251, # '╫' + 190: 252, # '╬' + 191: 253, # '©' + 192: 27, # 'ю' + 193: 3, # 'а' + 194: 21, # 'б' + 195: 28, # 'ц' + 196: 13, # 'д' + 197: 2, # 'е' + 198: 39, # 'ф' + 199: 19, # 'г' + 200: 26, # 'х' + 201: 4, # 'и' + 202: 23, # 'й' + 203: 11, # 'к' + 204: 8, # 'л' + 205: 12, # 'м' + 206: 5, # 'н' + 207: 1, # 'о' + 208: 15, # 'п' + 209: 16, # 'я' + 210: 9, # 'р' + 211: 7, # 'с' + 212: 6, # 'т' + 213: 14, # 'у' + 214: 24, # 'ж' + 215: 10, # 'в' + 216: 17, # 'ь' + 217: 18, # 'ы' + 218: 20, # 'з' + 219: 25, # 'ш' + 220: 30, # 'э' + 221: 29, # 'щ' + 222: 22, # 'ч' + 223: 54, # 'ъ' + 224: 59, # 'Ю' + 225: 37, # 'А' + 226: 44, # 'Б' + 227: 58, # 'Ц' + 228: 41, # 'Д' + 229: 48, # 'Е' + 230: 53, # 'Ф' + 231: 46, # 'Г' + 232: 55, # 'Х' + 233: 42, # 'И' + 234: 60, # 'Й' + 235: 36, # 'К' + 236: 49, # 'Л' + 237: 38, # 'М' + 238: 31, # 'Н' + 239: 34, # 'О' + 240: 35, # 'П' + 241: 43, # 'Я' + 242: 45, # 'Р' + 243: 32, # 'С' + 244: 40, # 'Т' + 245: 52, # 'У' + 246: 56, # 'Ж' + 247: 33, # 'В' + 248: 61, # 'Ь' + 249: 62, # 'Ы' + 250: 51, # 'З' + 251: 57, # 'Ш' + 252: 47, # 'Э' + 253: 63, # 'Щ' + 254: 50, # 'Ч' + 255: 70, # 'Ъ' +} + +KOI8_R_RUSSIAN_MODEL = SingleByteCharSetModel(charset_name='KOI8-R', + language='Russian', + char_to_order_map=KOI8_R_RUSSIAN_CHAR_TO_ORDER, + language_model=RUSSIAN_LANG_MODEL, + typical_positive_ratio=0.976601, + keep_ascii_letters=False, + alphabet='ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё') + +MACCYRILLIC_RUSSIAN_CHAR_TO_ORDER = { + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 142, # 'A' + 66: 143, # 'B' + 67: 144, # 'C' + 68: 145, # 'D' + 69: 146, # 'E' + 70: 147, # 'F' + 71: 148, # 'G' + 72: 149, # 'H' + 73: 150, # 'I' + 74: 151, # 'J' + 75: 152, # 'K' + 76: 74, # 'L' + 77: 153, # 'M' + 78: 75, # 'N' + 79: 154, # 'O' + 80: 155, # 'P' + 81: 156, # 'Q' + 82: 157, # 'R' + 83: 158, # 'S' + 84: 159, # 'T' + 85: 160, # 'U' + 86: 161, # 'V' + 87: 162, # 'W' + 88: 163, # 'X' + 89: 164, # 'Y' + 90: 165, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 71, # 'a' + 98: 172, # 'b' + 99: 66, # 'c' + 100: 173, # 'd' + 101: 65, # 'e' + 102: 174, # 'f' + 103: 76, # 'g' + 104: 175, # 'h' + 105: 64, # 'i' + 106: 176, # 'j' + 107: 177, # 'k' + 108: 77, # 'l' + 109: 72, # 'm' + 110: 178, # 'n' + 111: 69, # 'o' + 112: 67, # 'p' + 113: 179, # 'q' + 114: 78, # 'r' + 115: 73, # 's' + 116: 180, # 't' + 117: 181, # 'u' + 118: 79, # 'v' + 119: 182, # 'w' + 120: 183, # 'x' + 121: 184, # 'y' + 122: 185, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 37, # 'А' + 129: 44, # 'Б' + 130: 33, # 'В' + 131: 46, # 'Г' + 132: 41, # 'Д' + 133: 48, # 'Е' + 134: 56, # 'Ж' + 135: 51, # 'З' + 136: 42, # 'И' + 137: 60, # 'Й' + 138: 36, # 'К' + 139: 49, # 'Л' + 140: 38, # 'М' + 141: 31, # 'Н' + 142: 34, # 'О' + 143: 35, # 'П' + 144: 45, # 'Р' + 145: 32, # 'С' + 146: 40, # 'Т' + 147: 52, # 'У' + 148: 53, # 'Ф' + 149: 55, # 'Х' + 150: 58, # 'Ц' + 151: 50, # 'Ч' + 152: 57, # 'Ш' + 153: 63, # 'Щ' + 154: 70, # 'Ъ' + 155: 62, # 'Ы' + 156: 61, # 'Ь' + 157: 47, # 'Э' + 158: 59, # 'Ю' + 159: 43, # 'Я' + 160: 191, # '†' + 161: 192, # '°' + 162: 193, # 'Ґ' + 163: 194, # '£' + 164: 195, # '§' + 165: 196, # '•' + 166: 197, # '¶' + 167: 198, # 'І' + 168: 199, # '®' + 169: 200, # '©' + 170: 201, # '™' + 171: 202, # 'Ђ' + 172: 203, # 'ђ' + 173: 204, # '≠' + 174: 205, # 'Ѓ' + 175: 206, # 'ѓ' + 176: 207, # '∞' + 177: 208, # '±' + 178: 209, # '≤' + 179: 210, # '≥' + 180: 211, # 'і' + 181: 212, # 'µ' + 182: 213, # 'ґ' + 183: 214, # 'Ј' + 184: 215, # 'Є' + 185: 216, # 'є' + 186: 217, # 'Ї' + 187: 218, # 'ї' + 188: 219, # 'Љ' + 189: 220, # 'љ' + 190: 221, # 'Њ' + 191: 222, # 'њ' + 192: 223, # 'ј' + 193: 224, # 'Ѕ' + 194: 225, # '¬' + 195: 226, # '√' + 196: 227, # 'ƒ' + 197: 228, # '≈' + 198: 229, # '∆' + 199: 230, # '«' + 200: 231, # '»' + 201: 232, # '…' + 202: 233, # '\xa0' + 203: 234, # 'Ћ' + 204: 235, # 'ћ' + 205: 236, # 'Ќ' + 206: 237, # 'ќ' + 207: 238, # 'ѕ' + 208: 239, # '–' + 209: 240, # '—' + 210: 241, # '“' + 211: 242, # '”' + 212: 243, # '‘' + 213: 244, # '’' + 214: 245, # '÷' + 215: 246, # '„' + 216: 247, # 'Ў' + 217: 248, # 'ў' + 218: 249, # 'Џ' + 219: 250, # 'џ' + 220: 251, # '№' + 221: 252, # 'Ё' + 222: 68, # 'ё' + 223: 16, # 'я' + 224: 3, # 'а' + 225: 21, # 'б' + 226: 10, # 'в' + 227: 19, # 'г' + 228: 13, # 'д' + 229: 2, # 'е' + 230: 24, # 'ж' + 231: 20, # 'з' + 232: 4, # 'и' + 233: 23, # 'й' + 234: 11, # 'к' + 235: 8, # 'л' + 236: 12, # 'м' + 237: 5, # 'н' + 238: 1, # 'о' + 239: 15, # 'п' + 240: 9, # 'р' + 241: 7, # 'с' + 242: 6, # 'т' + 243: 14, # 'у' + 244: 39, # 'ф' + 245: 26, # 'х' + 246: 28, # 'ц' + 247: 22, # 'ч' + 248: 25, # 'ш' + 249: 29, # 'щ' + 250: 54, # 'ъ' + 251: 18, # 'ы' + 252: 17, # 'ь' + 253: 30, # 'э' + 254: 27, # 'ю' + 255: 255, # '€' +} + +MACCYRILLIC_RUSSIAN_MODEL = SingleByteCharSetModel(charset_name='MacCyrillic', + language='Russian', + char_to_order_map=MACCYRILLIC_RUSSIAN_CHAR_TO_ORDER, + language_model=RUSSIAN_LANG_MODEL, + typical_positive_ratio=0.976601, + keep_ascii_letters=False, + alphabet='ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё') + +ISO_8859_5_RUSSIAN_CHAR_TO_ORDER = { + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 142, # 'A' + 66: 143, # 'B' + 67: 144, # 'C' + 68: 145, # 'D' + 69: 146, # 'E' + 70: 147, # 'F' + 71: 148, # 'G' + 72: 149, # 'H' + 73: 150, # 'I' + 74: 151, # 'J' + 75: 152, # 'K' + 76: 74, # 'L' + 77: 153, # 'M' + 78: 75, # 'N' + 79: 154, # 'O' + 80: 155, # 'P' + 81: 156, # 'Q' + 82: 157, # 'R' + 83: 158, # 'S' + 84: 159, # 'T' + 85: 160, # 'U' + 86: 161, # 'V' + 87: 162, # 'W' + 88: 163, # 'X' + 89: 164, # 'Y' + 90: 165, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 71, # 'a' + 98: 172, # 'b' + 99: 66, # 'c' + 100: 173, # 'd' + 101: 65, # 'e' + 102: 174, # 'f' + 103: 76, # 'g' + 104: 175, # 'h' + 105: 64, # 'i' + 106: 176, # 'j' + 107: 177, # 'k' + 108: 77, # 'l' + 109: 72, # 'm' + 110: 178, # 'n' + 111: 69, # 'o' + 112: 67, # 'p' + 113: 179, # 'q' + 114: 78, # 'r' + 115: 73, # 's' + 116: 180, # 't' + 117: 181, # 'u' + 118: 79, # 'v' + 119: 182, # 'w' + 120: 183, # 'x' + 121: 184, # 'y' + 122: 185, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 191, # '\x80' + 129: 192, # '\x81' + 130: 193, # '\x82' + 131: 194, # '\x83' + 132: 195, # '\x84' + 133: 196, # '\x85' + 134: 197, # '\x86' + 135: 198, # '\x87' + 136: 199, # '\x88' + 137: 200, # '\x89' + 138: 201, # '\x8a' + 139: 202, # '\x8b' + 140: 203, # '\x8c' + 141: 204, # '\x8d' + 142: 205, # '\x8e' + 143: 206, # '\x8f' + 144: 207, # '\x90' + 145: 208, # '\x91' + 146: 209, # '\x92' + 147: 210, # '\x93' + 148: 211, # '\x94' + 149: 212, # '\x95' + 150: 213, # '\x96' + 151: 214, # '\x97' + 152: 215, # '\x98' + 153: 216, # '\x99' + 154: 217, # '\x9a' + 155: 218, # '\x9b' + 156: 219, # '\x9c' + 157: 220, # '\x9d' + 158: 221, # '\x9e' + 159: 222, # '\x9f' + 160: 223, # '\xa0' + 161: 224, # 'Ё' + 162: 225, # 'Ђ' + 163: 226, # 'Ѓ' + 164: 227, # 'Є' + 165: 228, # 'Ѕ' + 166: 229, # 'І' + 167: 230, # 'Ї' + 168: 231, # 'Ј' + 169: 232, # 'Љ' + 170: 233, # 'Њ' + 171: 234, # 'Ћ' + 172: 235, # 'Ќ' + 173: 236, # '\xad' + 174: 237, # 'Ў' + 175: 238, # 'Џ' + 176: 37, # 'А' + 177: 44, # 'Б' + 178: 33, # 'В' + 179: 46, # 'Г' + 180: 41, # 'Д' + 181: 48, # 'Е' + 182: 56, # 'Ж' + 183: 51, # 'З' + 184: 42, # 'И' + 185: 60, # 'Й' + 186: 36, # 'К' + 187: 49, # 'Л' + 188: 38, # 'М' + 189: 31, # 'Н' + 190: 34, # 'О' + 191: 35, # 'П' + 192: 45, # 'Р' + 193: 32, # 'С' + 194: 40, # 'Т' + 195: 52, # 'У' + 196: 53, # 'Ф' + 197: 55, # 'Х' + 198: 58, # 'Ц' + 199: 50, # 'Ч' + 200: 57, # 'Ш' + 201: 63, # 'Щ' + 202: 70, # 'Ъ' + 203: 62, # 'Ы' + 204: 61, # 'Ь' + 205: 47, # 'Э' + 206: 59, # 'Ю' + 207: 43, # 'Я' + 208: 3, # 'а' + 209: 21, # 'б' + 210: 10, # 'в' + 211: 19, # 'г' + 212: 13, # 'д' + 213: 2, # 'е' + 214: 24, # 'ж' + 215: 20, # 'з' + 216: 4, # 'и' + 217: 23, # 'й' + 218: 11, # 'к' + 219: 8, # 'л' + 220: 12, # 'м' + 221: 5, # 'н' + 222: 1, # 'о' + 223: 15, # 'п' + 224: 9, # 'р' + 225: 7, # 'с' + 226: 6, # 'т' + 227: 14, # 'у' + 228: 39, # 'ф' + 229: 26, # 'х' + 230: 28, # 'ц' + 231: 22, # 'ч' + 232: 25, # 'ш' + 233: 29, # 'щ' + 234: 54, # 'ъ' + 235: 18, # 'ы' + 236: 17, # 'ь' + 237: 30, # 'э' + 238: 27, # 'ю' + 239: 16, # 'я' + 240: 239, # '№' + 241: 68, # 'ё' + 242: 240, # 'ђ' + 243: 241, # 'ѓ' + 244: 242, # 'є' + 245: 243, # 'ѕ' + 246: 244, # 'і' + 247: 245, # 'ї' + 248: 246, # 'ј' + 249: 247, # 'љ' + 250: 248, # 'њ' + 251: 249, # 'ћ' + 252: 250, # 'ќ' + 253: 251, # '§' + 254: 252, # 'ў' + 255: 255, # 'џ' +} + +ISO_8859_5_RUSSIAN_MODEL = SingleByteCharSetModel(charset_name='ISO-8859-5', + language='Russian', + char_to_order_map=ISO_8859_5_RUSSIAN_CHAR_TO_ORDER, + language_model=RUSSIAN_LANG_MODEL, + typical_positive_ratio=0.976601, + keep_ascii_letters=False, + alphabet='ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё') + diff --git a/venv/lib/python3.8/site-packages/chardet/langthaimodel.py b/venv/lib/python3.8/site-packages/chardet/langthaimodel.py new file mode 100644 index 0000000..d0191f2 --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/langthaimodel.py @@ -0,0 +1,4383 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from chardet.sbcharsetprober import SingleByteCharSetModel + + +# 3: Positive +# 2: Likely +# 1: Unlikely +# 0: Negative + +THAI_LANG_MODEL = { + 5: { # 'ก' + 5: 2, # 'ก' + 30: 2, # 'ข' + 24: 2, # 'ค' + 8: 2, # 'ง' + 26: 2, # 'จ' + 52: 0, # 'ฉ' + 34: 1, # 'ช' + 51: 1, # 'ซ' + 47: 0, # 'ญ' + 58: 3, # 'ฎ' + 57: 2, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 2, # 'ณ' + 20: 2, # 'ด' + 19: 3, # 'ต' + 44: 0, # 'ถ' + 14: 2, # 'ท' + 48: 0, # 'ธ' + 3: 2, # 'น' + 17: 1, # 'บ' + 25: 2, # 'ป' + 39: 1, # 'ผ' + 62: 1, # 'ฝ' + 31: 1, # 'พ' + 54: 0, # 'ฟ' + 45: 1, # 'ภ' + 9: 2, # 'ม' + 16: 1, # 'ย' + 2: 3, # 'ร' + 61: 2, # 'ฤ' + 15: 3, # 'ล' + 12: 3, # 'ว' + 42: 2, # 'ศ' + 46: 3, # 'ษ' + 18: 2, # 'ส' + 21: 2, # 'ห' + 4: 3, # 'อ' + 63: 1, # 'ฯ' + 22: 2, # 'ะ' + 10: 3, # 'ั' + 1: 3, # 'า' + 36: 3, # 'ำ' + 23: 3, # 'ิ' + 13: 3, # 'ี' + 40: 0, # 'ึ' + 27: 2, # 'ื' + 32: 2, # 'ุ' + 35: 1, # 'ู' + 11: 2, # 'เ' + 28: 2, # 'แ' + 41: 1, # 'โ' + 29: 1, # 'ใ' + 33: 2, # 'ไ' + 50: 1, # 'ๆ' + 37: 3, # '็' + 6: 3, # '่' + 7: 3, # '้' + 38: 2, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 30: { # 'ข' + 5: 1, # 'ก' + 30: 0, # 'ข' + 24: 1, # 'ค' + 8: 1, # 'ง' + 26: 1, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 2, # 'ณ' + 20: 0, # 'ด' + 19: 2, # 'ต' + 44: 0, # 'ถ' + 14: 1, # 'ท' + 48: 0, # 'ธ' + 3: 2, # 'น' + 17: 1, # 'บ' + 25: 1, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 0, # 'ม' + 16: 2, # 'ย' + 2: 1, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 2, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 1, # 'ส' + 21: 1, # 'ห' + 4: 3, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 3, # 'ั' + 1: 3, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 2, # 'ี' + 40: 3, # 'ึ' + 27: 1, # 'ื' + 32: 1, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 1, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 1, # '็' + 6: 2, # '่' + 7: 3, # '้' + 38: 1, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 24: { # 'ค' + 5: 0, # 'ก' + 30: 0, # 'ข' + 24: 2, # 'ค' + 8: 2, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 2, # 'ณ' + 20: 2, # 'ด' + 19: 2, # 'ต' + 44: 0, # 'ถ' + 14: 1, # 'ท' + 48: 0, # 'ธ' + 3: 3, # 'น' + 17: 0, # 'บ' + 25: 1, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 2, # 'ม' + 16: 2, # 'ย' + 2: 3, # 'ร' + 61: 0, # 'ฤ' + 15: 3, # 'ล' + 12: 3, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 1, # 'ส' + 21: 0, # 'ห' + 4: 2, # 'อ' + 63: 0, # 'ฯ' + 22: 2, # 'ะ' + 10: 3, # 'ั' + 1: 2, # 'า' + 36: 3, # 'ำ' + 23: 3, # 'ิ' + 13: 2, # 'ี' + 40: 0, # 'ึ' + 27: 3, # 'ื' + 32: 3, # 'ุ' + 35: 2, # 'ู' + 11: 1, # 'เ' + 28: 0, # 'แ' + 41: 3, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 1, # '็' + 6: 3, # '่' + 7: 3, # '้' + 38: 3, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 8: { # 'ง' + 5: 3, # 'ก' + 30: 2, # 'ข' + 24: 3, # 'ค' + 8: 2, # 'ง' + 26: 2, # 'จ' + 52: 1, # 'ฉ' + 34: 2, # 'ช' + 51: 1, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 2, # 'ด' + 19: 2, # 'ต' + 44: 1, # 'ถ' + 14: 3, # 'ท' + 48: 1, # 'ธ' + 3: 3, # 'น' + 17: 2, # 'บ' + 25: 2, # 'ป' + 39: 2, # 'ผ' + 62: 1, # 'ฝ' + 31: 2, # 'พ' + 54: 0, # 'ฟ' + 45: 1, # 'ภ' + 9: 2, # 'ม' + 16: 1, # 'ย' + 2: 2, # 'ร' + 61: 0, # 'ฤ' + 15: 2, # 'ล' + 12: 2, # 'ว' + 42: 2, # 'ศ' + 46: 1, # 'ษ' + 18: 3, # 'ส' + 21: 3, # 'ห' + 4: 2, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 1, # 'ั' + 1: 3, # 'า' + 36: 0, # 'ำ' + 23: 2, # 'ิ' + 13: 1, # 'ี' + 40: 0, # 'ึ' + 27: 1, # 'ื' + 32: 1, # 'ุ' + 35: 0, # 'ู' + 11: 3, # 'เ' + 28: 2, # 'แ' + 41: 1, # 'โ' + 29: 2, # 'ใ' + 33: 2, # 'ไ' + 50: 3, # 'ๆ' + 37: 0, # '็' + 6: 2, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 26: { # 'จ' + 5: 2, # 'ก' + 30: 1, # 'ข' + 24: 0, # 'ค' + 8: 2, # 'ง' + 26: 3, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 2, # 'ด' + 19: 1, # 'ต' + 44: 1, # 'ถ' + 14: 2, # 'ท' + 48: 0, # 'ธ' + 3: 3, # 'น' + 17: 1, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 1, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 1, # 'ม' + 16: 1, # 'ย' + 2: 3, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 1, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 2, # 'ส' + 21: 1, # 'ห' + 4: 2, # 'อ' + 63: 0, # 'ฯ' + 22: 3, # 'ะ' + 10: 3, # 'ั' + 1: 3, # 'า' + 36: 3, # 'ำ' + 23: 2, # 'ิ' + 13: 1, # 'ี' + 40: 3, # 'ึ' + 27: 1, # 'ื' + 32: 3, # 'ุ' + 35: 2, # 'ู' + 11: 1, # 'เ' + 28: 1, # 'แ' + 41: 0, # 'โ' + 29: 1, # 'ใ' + 33: 1, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 2, # '่' + 7: 2, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 52: { # 'ฉ' + 5: 0, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 0, # 'น' + 17: 3, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 3, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 1, # 'ม' + 16: 1, # 'ย' + 2: 0, # 'ร' + 61: 0, # 'ฤ' + 15: 2, # 'ล' + 12: 1, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 0, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 1, # 'ะ' + 10: 1, # 'ั' + 1: 1, # 'า' + 36: 0, # 'ำ' + 23: 1, # 'ิ' + 13: 1, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 1, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 34: { # 'ช' + 5: 1, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 1, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 1, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 1, # 'ท' + 48: 0, # 'ธ' + 3: 3, # 'น' + 17: 2, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 2, # 'ม' + 16: 1, # 'ย' + 2: 1, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 1, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 0, # 'ห' + 4: 2, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 2, # 'ั' + 1: 3, # 'า' + 36: 1, # 'ำ' + 23: 3, # 'ิ' + 13: 2, # 'ี' + 40: 0, # 'ึ' + 27: 3, # 'ื' + 32: 3, # 'ุ' + 35: 1, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 1, # '็' + 6: 3, # '่' + 7: 3, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 51: { # 'ซ' + 5: 0, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 1, # 'น' + 17: 0, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 0, # 'ม' + 16: 0, # 'ย' + 2: 0, # 'ร' + 61: 0, # 'ฤ' + 15: 1, # 'ล' + 12: 0, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 1, # 'ส' + 21: 0, # 'ห' + 4: 2, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 1, # 'ั' + 1: 1, # 'า' + 36: 0, # 'ำ' + 23: 1, # 'ิ' + 13: 2, # 'ี' + 40: 3, # 'ึ' + 27: 2, # 'ื' + 32: 1, # 'ุ' + 35: 1, # 'ู' + 11: 1, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 1, # '็' + 6: 1, # '่' + 7: 2, # '้' + 38: 1, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 47: { # 'ญ' + 5: 1, # 'ก' + 30: 1, # 'ข' + 24: 0, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 1, # 'ช' + 51: 0, # 'ซ' + 47: 3, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 1, # 'ท' + 48: 0, # 'ธ' + 3: 0, # 'น' + 17: 1, # 'บ' + 25: 1, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 1, # 'ม' + 16: 0, # 'ย' + 2: 0, # 'ร' + 61: 0, # 'ฤ' + 15: 1, # 'ล' + 12: 0, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 1, # 'ส' + 21: 2, # 'ห' + 4: 1, # 'อ' + 63: 0, # 'ฯ' + 22: 1, # 'ะ' + 10: 2, # 'ั' + 1: 3, # 'า' + 36: 0, # 'ำ' + 23: 1, # 'ิ' + 13: 1, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 1, # 'เ' + 28: 1, # 'แ' + 41: 0, # 'โ' + 29: 1, # 'ใ' + 33: 0, # 'ไ' + 50: 1, # 'ๆ' + 37: 0, # '็' + 6: 2, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 58: { # 'ฎ' + 5: 2, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 0, # 'น' + 17: 0, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 0, # 'ม' + 16: 0, # 'ย' + 2: 0, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 0, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 1, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 1, # 'ิ' + 13: 2, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 57: { # 'ฏ' + 5: 0, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 0, # 'น' + 17: 0, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 0, # 'ม' + 16: 0, # 'ย' + 2: 0, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 0, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 0, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 3, # 'ิ' + 13: 1, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 49: { # 'ฐ' + 5: 1, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 0, # 'น' + 17: 2, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 2, # 'ม' + 16: 0, # 'ย' + 2: 0, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 0, # 'ว' + 42: 1, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 0, # 'ห' + 4: 1, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 3, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 1, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 53: { # 'ฑ' + 5: 0, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 0, # 'น' + 17: 0, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 0, # 'ม' + 16: 0, # 'ย' + 2: 0, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 0, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 0, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 2, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 3, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 55: { # 'ฒ' + 5: 0, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 3, # 'น' + 17: 0, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 1, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 0, # 'ม' + 16: 0, # 'ย' + 2: 0, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 0, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 0, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 1, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 43: { # 'ณ' + 5: 1, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 3, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 0, # 'น' + 17: 0, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 3, # 'ภ' + 9: 0, # 'ม' + 16: 0, # 'ย' + 2: 1, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 1, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 1, # 'ส' + 21: 1, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 3, # 'ะ' + 10: 0, # 'ั' + 1: 3, # 'า' + 36: 0, # 'ำ' + 23: 1, # 'ิ' + 13: 2, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 1, # 'เ' + 28: 1, # 'แ' + 41: 0, # 'โ' + 29: 1, # 'ใ' + 33: 1, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 3, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 20: { # 'ด' + 5: 2, # 'ก' + 30: 2, # 'ข' + 24: 2, # 'ค' + 8: 3, # 'ง' + 26: 2, # 'จ' + 52: 0, # 'ฉ' + 34: 1, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 1, # 'ด' + 19: 2, # 'ต' + 44: 1, # 'ถ' + 14: 2, # 'ท' + 48: 0, # 'ธ' + 3: 1, # 'น' + 17: 1, # 'บ' + 25: 1, # 'ป' + 39: 1, # 'ผ' + 62: 0, # 'ฝ' + 31: 1, # 'พ' + 54: 0, # 'ฟ' + 45: 1, # 'ภ' + 9: 2, # 'ม' + 16: 3, # 'ย' + 2: 2, # 'ร' + 61: 0, # 'ฤ' + 15: 2, # 'ล' + 12: 2, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 2, # 'ส' + 21: 2, # 'ห' + 4: 1, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 3, # 'ั' + 1: 2, # 'า' + 36: 2, # 'ำ' + 23: 3, # 'ิ' + 13: 3, # 'ี' + 40: 1, # 'ึ' + 27: 2, # 'ื' + 32: 3, # 'ุ' + 35: 2, # 'ู' + 11: 2, # 'เ' + 28: 2, # 'แ' + 41: 1, # 'โ' + 29: 2, # 'ใ' + 33: 2, # 'ไ' + 50: 2, # 'ๆ' + 37: 2, # '็' + 6: 1, # '่' + 7: 3, # '้' + 38: 1, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 19: { # 'ต' + 5: 2, # 'ก' + 30: 1, # 'ข' + 24: 1, # 'ค' + 8: 0, # 'ง' + 26: 1, # 'จ' + 52: 0, # 'ฉ' + 34: 1, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 1, # 'ด' + 19: 1, # 'ต' + 44: 2, # 'ถ' + 14: 1, # 'ท' + 48: 0, # 'ธ' + 3: 2, # 'น' + 17: 1, # 'บ' + 25: 1, # 'ป' + 39: 1, # 'ผ' + 62: 0, # 'ฝ' + 31: 1, # 'พ' + 54: 0, # 'ฟ' + 45: 2, # 'ภ' + 9: 1, # 'ม' + 16: 1, # 'ย' + 2: 3, # 'ร' + 61: 0, # 'ฤ' + 15: 2, # 'ล' + 12: 1, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 3, # 'ส' + 21: 0, # 'ห' + 4: 3, # 'อ' + 63: 1, # 'ฯ' + 22: 2, # 'ะ' + 10: 3, # 'ั' + 1: 3, # 'า' + 36: 2, # 'ำ' + 23: 3, # 'ิ' + 13: 2, # 'ี' + 40: 1, # 'ึ' + 27: 1, # 'ื' + 32: 3, # 'ุ' + 35: 2, # 'ู' + 11: 1, # 'เ' + 28: 1, # 'แ' + 41: 1, # 'โ' + 29: 1, # 'ใ' + 33: 1, # 'ไ' + 50: 0, # 'ๆ' + 37: 2, # '็' + 6: 3, # '่' + 7: 3, # '้' + 38: 2, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 44: { # 'ถ' + 5: 1, # 'ก' + 30: 0, # 'ข' + 24: 1, # 'ค' + 8: 0, # 'ง' + 26: 1, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 1, # 'ต' + 44: 0, # 'ถ' + 14: 1, # 'ท' + 48: 0, # 'ธ' + 3: 1, # 'น' + 17: 2, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 1, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 0, # 'ม' + 16: 0, # 'ย' + 2: 1, # 'ร' + 61: 0, # 'ฤ' + 15: 1, # 'ล' + 12: 1, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 1, # 'ส' + 21: 0, # 'ห' + 4: 1, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 2, # 'ั' + 1: 3, # 'า' + 36: 0, # 'ำ' + 23: 2, # 'ิ' + 13: 1, # 'ี' + 40: 3, # 'ึ' + 27: 2, # 'ื' + 32: 2, # 'ุ' + 35: 3, # 'ู' + 11: 1, # 'เ' + 28: 1, # 'แ' + 41: 0, # 'โ' + 29: 1, # 'ใ' + 33: 1, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 2, # '่' + 7: 3, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 14: { # 'ท' + 5: 1, # 'ก' + 30: 1, # 'ข' + 24: 3, # 'ค' + 8: 1, # 'ง' + 26: 1, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 2, # 'ด' + 19: 1, # 'ต' + 44: 0, # 'ถ' + 14: 1, # 'ท' + 48: 3, # 'ธ' + 3: 3, # 'น' + 17: 2, # 'บ' + 25: 2, # 'ป' + 39: 1, # 'ผ' + 62: 0, # 'ฝ' + 31: 2, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 1, # 'ม' + 16: 3, # 'ย' + 2: 3, # 'ร' + 61: 1, # 'ฤ' + 15: 1, # 'ล' + 12: 2, # 'ว' + 42: 3, # 'ศ' + 46: 1, # 'ษ' + 18: 1, # 'ส' + 21: 0, # 'ห' + 4: 2, # 'อ' + 63: 0, # 'ฯ' + 22: 2, # 'ะ' + 10: 3, # 'ั' + 1: 3, # 'า' + 36: 3, # 'ำ' + 23: 2, # 'ิ' + 13: 3, # 'ี' + 40: 2, # 'ึ' + 27: 1, # 'ื' + 32: 3, # 'ุ' + 35: 1, # 'ู' + 11: 0, # 'เ' + 28: 1, # 'แ' + 41: 0, # 'โ' + 29: 1, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 1, # '็' + 6: 3, # '่' + 7: 3, # '้' + 38: 2, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 48: { # 'ธ' + 5: 0, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 1, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 1, # 'น' + 17: 0, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 0, # 'ม' + 16: 0, # 'ย' + 2: 2, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 0, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 0, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 2, # 'า' + 36: 0, # 'ำ' + 23: 3, # 'ิ' + 13: 3, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 2, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 3, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 3: { # 'น' + 5: 3, # 'ก' + 30: 2, # 'ข' + 24: 3, # 'ค' + 8: 1, # 'ง' + 26: 2, # 'จ' + 52: 0, # 'ฉ' + 34: 1, # 'ช' + 51: 1, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 1, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 3, # 'ด' + 19: 3, # 'ต' + 44: 2, # 'ถ' + 14: 3, # 'ท' + 48: 3, # 'ธ' + 3: 2, # 'น' + 17: 2, # 'บ' + 25: 2, # 'ป' + 39: 2, # 'ผ' + 62: 0, # 'ฝ' + 31: 2, # 'พ' + 54: 1, # 'ฟ' + 45: 1, # 'ภ' + 9: 2, # 'ม' + 16: 2, # 'ย' + 2: 2, # 'ร' + 61: 1, # 'ฤ' + 15: 2, # 'ล' + 12: 3, # 'ว' + 42: 1, # 'ศ' + 46: 0, # 'ษ' + 18: 2, # 'ส' + 21: 2, # 'ห' + 4: 3, # 'อ' + 63: 1, # 'ฯ' + 22: 2, # 'ะ' + 10: 3, # 'ั' + 1: 3, # 'า' + 36: 3, # 'ำ' + 23: 3, # 'ิ' + 13: 3, # 'ี' + 40: 3, # 'ึ' + 27: 3, # 'ื' + 32: 3, # 'ุ' + 35: 2, # 'ู' + 11: 3, # 'เ' + 28: 2, # 'แ' + 41: 3, # 'โ' + 29: 3, # 'ใ' + 33: 3, # 'ไ' + 50: 2, # 'ๆ' + 37: 1, # '็' + 6: 3, # '่' + 7: 3, # '้' + 38: 2, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 17: { # 'บ' + 5: 3, # 'ก' + 30: 2, # 'ข' + 24: 2, # 'ค' + 8: 1, # 'ง' + 26: 1, # 'จ' + 52: 1, # 'ฉ' + 34: 1, # 'ช' + 51: 1, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 1, # 'ด' + 19: 2, # 'ต' + 44: 1, # 'ถ' + 14: 3, # 'ท' + 48: 0, # 'ธ' + 3: 3, # 'น' + 17: 3, # 'บ' + 25: 2, # 'ป' + 39: 2, # 'ผ' + 62: 0, # 'ฝ' + 31: 1, # 'พ' + 54: 1, # 'ฟ' + 45: 1, # 'ภ' + 9: 1, # 'ม' + 16: 0, # 'ย' + 2: 3, # 'ร' + 61: 0, # 'ฤ' + 15: 2, # 'ล' + 12: 3, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 2, # 'ส' + 21: 2, # 'ห' + 4: 2, # 'อ' + 63: 1, # 'ฯ' + 22: 0, # 'ะ' + 10: 3, # 'ั' + 1: 3, # 'า' + 36: 2, # 'ำ' + 23: 2, # 'ิ' + 13: 2, # 'ี' + 40: 0, # 'ึ' + 27: 2, # 'ื' + 32: 3, # 'ุ' + 35: 2, # 'ู' + 11: 2, # 'เ' + 28: 2, # 'แ' + 41: 1, # 'โ' + 29: 2, # 'ใ' + 33: 2, # 'ไ' + 50: 0, # 'ๆ' + 37: 1, # '็' + 6: 2, # '่' + 7: 2, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 25: { # 'ป' + 5: 2, # 'ก' + 30: 0, # 'ข' + 24: 1, # 'ค' + 8: 0, # 'ง' + 26: 1, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 1, # 'ซ' + 47: 0, # 'ญ' + 58: 1, # 'ฎ' + 57: 3, # 'ฏ' + 49: 1, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 1, # 'ด' + 19: 1, # 'ต' + 44: 1, # 'ถ' + 14: 1, # 'ท' + 48: 0, # 'ธ' + 3: 2, # 'น' + 17: 0, # 'บ' + 25: 1, # 'ป' + 39: 1, # 'ผ' + 62: 1, # 'ฝ' + 31: 1, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 1, # 'ม' + 16: 0, # 'ย' + 2: 3, # 'ร' + 61: 0, # 'ฤ' + 15: 3, # 'ล' + 12: 1, # 'ว' + 42: 0, # 'ศ' + 46: 1, # 'ษ' + 18: 2, # 'ส' + 21: 1, # 'ห' + 4: 2, # 'อ' + 63: 0, # 'ฯ' + 22: 1, # 'ะ' + 10: 3, # 'ั' + 1: 1, # 'า' + 36: 0, # 'ำ' + 23: 2, # 'ิ' + 13: 3, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 1, # 'ุ' + 35: 0, # 'ู' + 11: 1, # 'เ' + 28: 2, # 'แ' + 41: 0, # 'โ' + 29: 1, # 'ใ' + 33: 2, # 'ไ' + 50: 0, # 'ๆ' + 37: 3, # '็' + 6: 1, # '่' + 7: 2, # '้' + 38: 1, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 39: { # 'ผ' + 5: 1, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 1, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 2, # 'น' + 17: 0, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 1, # 'ม' + 16: 2, # 'ย' + 2: 0, # 'ร' + 61: 0, # 'ฤ' + 15: 3, # 'ล' + 12: 0, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 1, # 'ส' + 21: 0, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 1, # 'ะ' + 10: 1, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 2, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 1, # 'ื' + 32: 0, # 'ุ' + 35: 3, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 3, # '่' + 7: 1, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 62: { # 'ฝ' + 5: 0, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 1, # 'น' + 17: 0, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 0, # 'ม' + 16: 0, # 'ย' + 2: 1, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 0, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 0, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 1, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 1, # 'ี' + 40: 2, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 2, # '่' + 7: 1, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 31: { # 'พ' + 5: 1, # 'ก' + 30: 1, # 'ข' + 24: 1, # 'ค' + 8: 1, # 'ง' + 26: 1, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 1, # 'ณ' + 20: 1, # 'ด' + 19: 1, # 'ต' + 44: 0, # 'ถ' + 14: 2, # 'ท' + 48: 1, # 'ธ' + 3: 3, # 'น' + 17: 2, # 'บ' + 25: 0, # 'ป' + 39: 1, # 'ผ' + 62: 0, # 'ฝ' + 31: 1, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 1, # 'ม' + 16: 2, # 'ย' + 2: 3, # 'ร' + 61: 2, # 'ฤ' + 15: 2, # 'ล' + 12: 2, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 1, # 'ส' + 21: 1, # 'ห' + 4: 2, # 'อ' + 63: 1, # 'ฯ' + 22: 0, # 'ะ' + 10: 3, # 'ั' + 1: 3, # 'า' + 36: 0, # 'ำ' + 23: 3, # 'ิ' + 13: 2, # 'ี' + 40: 1, # 'ึ' + 27: 3, # 'ื' + 32: 1, # 'ุ' + 35: 2, # 'ู' + 11: 1, # 'เ' + 28: 1, # 'แ' + 41: 0, # 'โ' + 29: 1, # 'ใ' + 33: 1, # 'ไ' + 50: 0, # 'ๆ' + 37: 1, # '็' + 6: 0, # '่' + 7: 1, # '้' + 38: 3, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 54: { # 'ฟ' + 5: 0, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 1, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 1, # 'ต' + 44: 0, # 'ถ' + 14: 1, # 'ท' + 48: 0, # 'ธ' + 3: 0, # 'น' + 17: 0, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 2, # 'ฟ' + 45: 0, # 'ภ' + 9: 0, # 'ม' + 16: 0, # 'ย' + 2: 1, # 'ร' + 61: 0, # 'ฤ' + 15: 2, # 'ล' + 12: 0, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 1, # 'ส' + 21: 0, # 'ห' + 4: 1, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 2, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 1, # 'ิ' + 13: 1, # 'ี' + 40: 0, # 'ึ' + 27: 1, # 'ื' + 32: 1, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 1, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 2, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 45: { # 'ภ' + 5: 0, # 'ก' + 30: 0, # 'ข' + 24: 1, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 3, # 'ท' + 48: 0, # 'ธ' + 3: 0, # 'น' + 17: 0, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 1, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 0, # 'ม' + 16: 0, # 'ย' + 2: 1, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 0, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 0, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 3, # 'ั' + 1: 3, # 'า' + 36: 0, # 'ำ' + 23: 1, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 2, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 1, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 9: { # 'ม' + 5: 2, # 'ก' + 30: 2, # 'ข' + 24: 2, # 'ค' + 8: 2, # 'ง' + 26: 2, # 'จ' + 52: 0, # 'ฉ' + 34: 1, # 'ช' + 51: 1, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 1, # 'ณ' + 20: 2, # 'ด' + 19: 2, # 'ต' + 44: 1, # 'ถ' + 14: 2, # 'ท' + 48: 1, # 'ธ' + 3: 3, # 'น' + 17: 2, # 'บ' + 25: 2, # 'ป' + 39: 1, # 'ผ' + 62: 0, # 'ฝ' + 31: 3, # 'พ' + 54: 0, # 'ฟ' + 45: 1, # 'ภ' + 9: 2, # 'ม' + 16: 1, # 'ย' + 2: 2, # 'ร' + 61: 2, # 'ฤ' + 15: 2, # 'ล' + 12: 2, # 'ว' + 42: 1, # 'ศ' + 46: 1, # 'ษ' + 18: 3, # 'ส' + 21: 3, # 'ห' + 4: 3, # 'อ' + 63: 0, # 'ฯ' + 22: 1, # 'ะ' + 10: 3, # 'ั' + 1: 3, # 'า' + 36: 0, # 'ำ' + 23: 3, # 'ิ' + 13: 3, # 'ี' + 40: 0, # 'ึ' + 27: 3, # 'ื' + 32: 3, # 'ุ' + 35: 3, # 'ู' + 11: 2, # 'เ' + 28: 2, # 'แ' + 41: 2, # 'โ' + 29: 2, # 'ใ' + 33: 2, # 'ไ' + 50: 1, # 'ๆ' + 37: 1, # '็' + 6: 3, # '่' + 7: 2, # '้' + 38: 1, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 16: { # 'ย' + 5: 3, # 'ก' + 30: 1, # 'ข' + 24: 2, # 'ค' + 8: 3, # 'ง' + 26: 2, # 'จ' + 52: 0, # 'ฉ' + 34: 2, # 'ช' + 51: 0, # 'ซ' + 47: 2, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 2, # 'ด' + 19: 2, # 'ต' + 44: 1, # 'ถ' + 14: 2, # 'ท' + 48: 1, # 'ธ' + 3: 3, # 'น' + 17: 3, # 'บ' + 25: 1, # 'ป' + 39: 1, # 'ผ' + 62: 0, # 'ฝ' + 31: 1, # 'พ' + 54: 0, # 'ฟ' + 45: 1, # 'ภ' + 9: 2, # 'ม' + 16: 0, # 'ย' + 2: 2, # 'ร' + 61: 0, # 'ฤ' + 15: 1, # 'ล' + 12: 3, # 'ว' + 42: 1, # 'ศ' + 46: 0, # 'ษ' + 18: 2, # 'ส' + 21: 1, # 'ห' + 4: 2, # 'อ' + 63: 0, # 'ฯ' + 22: 2, # 'ะ' + 10: 3, # 'ั' + 1: 3, # 'า' + 36: 0, # 'ำ' + 23: 2, # 'ิ' + 13: 3, # 'ี' + 40: 1, # 'ึ' + 27: 2, # 'ื' + 32: 2, # 'ุ' + 35: 3, # 'ู' + 11: 2, # 'เ' + 28: 1, # 'แ' + 41: 1, # 'โ' + 29: 2, # 'ใ' + 33: 2, # 'ไ' + 50: 2, # 'ๆ' + 37: 1, # '็' + 6: 3, # '่' + 7: 2, # '้' + 38: 3, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 2: { # 'ร' + 5: 3, # 'ก' + 30: 2, # 'ข' + 24: 2, # 'ค' + 8: 3, # 'ง' + 26: 2, # 'จ' + 52: 0, # 'ฉ' + 34: 2, # 'ช' + 51: 1, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 3, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 3, # 'ณ' + 20: 2, # 'ด' + 19: 2, # 'ต' + 44: 3, # 'ถ' + 14: 3, # 'ท' + 48: 1, # 'ธ' + 3: 2, # 'น' + 17: 2, # 'บ' + 25: 3, # 'ป' + 39: 2, # 'ผ' + 62: 1, # 'ฝ' + 31: 2, # 'พ' + 54: 1, # 'ฟ' + 45: 1, # 'ภ' + 9: 3, # 'ม' + 16: 2, # 'ย' + 2: 3, # 'ร' + 61: 0, # 'ฤ' + 15: 2, # 'ล' + 12: 3, # 'ว' + 42: 2, # 'ศ' + 46: 2, # 'ษ' + 18: 2, # 'ส' + 21: 2, # 'ห' + 4: 3, # 'อ' + 63: 1, # 'ฯ' + 22: 3, # 'ะ' + 10: 3, # 'ั' + 1: 3, # 'า' + 36: 0, # 'ำ' + 23: 3, # 'ิ' + 13: 3, # 'ี' + 40: 2, # 'ึ' + 27: 3, # 'ื' + 32: 3, # 'ุ' + 35: 3, # 'ู' + 11: 3, # 'เ' + 28: 3, # 'แ' + 41: 1, # 'โ' + 29: 2, # 'ใ' + 33: 1, # 'ไ' + 50: 0, # 'ๆ' + 37: 3, # '็' + 6: 3, # '่' + 7: 3, # '้' + 38: 3, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 61: { # 'ฤ' + 5: 0, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 2, # 'ต' + 44: 0, # 'ถ' + 14: 2, # 'ท' + 48: 0, # 'ธ' + 3: 0, # 'น' + 17: 0, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 1, # 'ม' + 16: 0, # 'ย' + 2: 0, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 0, # 'ว' + 42: 0, # 'ศ' + 46: 2, # 'ษ' + 18: 0, # 'ส' + 21: 0, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 15: { # 'ล' + 5: 2, # 'ก' + 30: 3, # 'ข' + 24: 1, # 'ค' + 8: 3, # 'ง' + 26: 1, # 'จ' + 52: 0, # 'ฉ' + 34: 1, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 2, # 'ด' + 19: 2, # 'ต' + 44: 1, # 'ถ' + 14: 2, # 'ท' + 48: 0, # 'ธ' + 3: 1, # 'น' + 17: 2, # 'บ' + 25: 2, # 'ป' + 39: 1, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 1, # 'ภ' + 9: 1, # 'ม' + 16: 3, # 'ย' + 2: 1, # 'ร' + 61: 0, # 'ฤ' + 15: 1, # 'ล' + 12: 1, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 2, # 'ส' + 21: 1, # 'ห' + 4: 3, # 'อ' + 63: 2, # 'ฯ' + 22: 3, # 'ะ' + 10: 3, # 'ั' + 1: 3, # 'า' + 36: 2, # 'ำ' + 23: 3, # 'ิ' + 13: 3, # 'ี' + 40: 2, # 'ึ' + 27: 3, # 'ื' + 32: 2, # 'ุ' + 35: 3, # 'ู' + 11: 2, # 'เ' + 28: 1, # 'แ' + 41: 1, # 'โ' + 29: 2, # 'ใ' + 33: 1, # 'ไ' + 50: 0, # 'ๆ' + 37: 2, # '็' + 6: 3, # '่' + 7: 3, # '้' + 38: 2, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 12: { # 'ว' + 5: 3, # 'ก' + 30: 2, # 'ข' + 24: 1, # 'ค' + 8: 3, # 'ง' + 26: 2, # 'จ' + 52: 0, # 'ฉ' + 34: 1, # 'ช' + 51: 1, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 1, # 'ณ' + 20: 2, # 'ด' + 19: 1, # 'ต' + 44: 1, # 'ถ' + 14: 1, # 'ท' + 48: 0, # 'ธ' + 3: 3, # 'น' + 17: 2, # 'บ' + 25: 1, # 'ป' + 39: 1, # 'ผ' + 62: 0, # 'ฝ' + 31: 1, # 'พ' + 54: 1, # 'ฟ' + 45: 0, # 'ภ' + 9: 3, # 'ม' + 16: 3, # 'ย' + 2: 3, # 'ร' + 61: 0, # 'ฤ' + 15: 3, # 'ล' + 12: 1, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 2, # 'ส' + 21: 2, # 'ห' + 4: 2, # 'อ' + 63: 0, # 'ฯ' + 22: 2, # 'ะ' + 10: 3, # 'ั' + 1: 3, # 'า' + 36: 0, # 'ำ' + 23: 3, # 'ิ' + 13: 2, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 2, # 'ุ' + 35: 0, # 'ู' + 11: 3, # 'เ' + 28: 2, # 'แ' + 41: 1, # 'โ' + 29: 1, # 'ใ' + 33: 2, # 'ไ' + 50: 1, # 'ๆ' + 37: 0, # '็' + 6: 3, # '่' + 7: 3, # '้' + 38: 1, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 42: { # 'ศ' + 5: 1, # 'ก' + 30: 0, # 'ข' + 24: 1, # 'ค' + 8: 0, # 'ง' + 26: 1, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 1, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 1, # 'ต' + 44: 0, # 'ถ' + 14: 1, # 'ท' + 48: 0, # 'ธ' + 3: 2, # 'น' + 17: 0, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 0, # 'ม' + 16: 0, # 'ย' + 2: 2, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 2, # 'ว' + 42: 1, # 'ศ' + 46: 2, # 'ษ' + 18: 1, # 'ส' + 21: 0, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 2, # 'ั' + 1: 3, # 'า' + 36: 0, # 'ำ' + 23: 2, # 'ิ' + 13: 0, # 'ี' + 40: 3, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 2, # 'ู' + 11: 0, # 'เ' + 28: 1, # 'แ' + 41: 0, # 'โ' + 29: 1, # 'ใ' + 33: 1, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 1, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 46: { # 'ษ' + 5: 0, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 2, # 'ฎ' + 57: 1, # 'ฏ' + 49: 2, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 3, # 'ณ' + 20: 0, # 'ด' + 19: 1, # 'ต' + 44: 0, # 'ถ' + 14: 1, # 'ท' + 48: 0, # 'ธ' + 3: 0, # 'น' + 17: 0, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 1, # 'ภ' + 9: 1, # 'ม' + 16: 2, # 'ย' + 2: 2, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 0, # 'ว' + 42: 1, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 0, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 2, # 'ะ' + 10: 2, # 'ั' + 1: 3, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 1, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 1, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 2, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 18: { # 'ส' + 5: 2, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 2, # 'ง' + 26: 1, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 3, # 'ด' + 19: 3, # 'ต' + 44: 3, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 3, # 'น' + 17: 2, # 'บ' + 25: 1, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 2, # 'ภ' + 9: 3, # 'ม' + 16: 1, # 'ย' + 2: 3, # 'ร' + 61: 0, # 'ฤ' + 15: 1, # 'ล' + 12: 2, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 2, # 'ห' + 4: 3, # 'อ' + 63: 0, # 'ฯ' + 22: 2, # 'ะ' + 10: 3, # 'ั' + 1: 3, # 'า' + 36: 3, # 'ำ' + 23: 3, # 'ิ' + 13: 3, # 'ี' + 40: 2, # 'ึ' + 27: 3, # 'ื' + 32: 3, # 'ุ' + 35: 3, # 'ู' + 11: 2, # 'เ' + 28: 0, # 'แ' + 41: 1, # 'โ' + 29: 0, # 'ใ' + 33: 1, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 3, # '่' + 7: 1, # '้' + 38: 2, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 21: { # 'ห' + 5: 3, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 1, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 2, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 1, # 'ด' + 19: 3, # 'ต' + 44: 0, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 3, # 'น' + 17: 0, # 'บ' + 25: 1, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 1, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 3, # 'ม' + 16: 2, # 'ย' + 2: 3, # 'ร' + 61: 0, # 'ฤ' + 15: 3, # 'ล' + 12: 2, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 0, # 'ห' + 4: 3, # 'อ' + 63: 0, # 'ฯ' + 22: 1, # 'ะ' + 10: 3, # 'ั' + 1: 3, # 'า' + 36: 0, # 'ำ' + 23: 1, # 'ิ' + 13: 1, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 1, # 'ุ' + 35: 1, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 3, # '็' + 6: 3, # '่' + 7: 3, # '้' + 38: 2, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 4: { # 'อ' + 5: 3, # 'ก' + 30: 1, # 'ข' + 24: 2, # 'ค' + 8: 3, # 'ง' + 26: 1, # 'จ' + 52: 0, # 'ฉ' + 34: 1, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 3, # 'ด' + 19: 2, # 'ต' + 44: 1, # 'ถ' + 14: 2, # 'ท' + 48: 1, # 'ธ' + 3: 3, # 'น' + 17: 3, # 'บ' + 25: 1, # 'ป' + 39: 1, # 'ผ' + 62: 0, # 'ฝ' + 31: 1, # 'พ' + 54: 1, # 'ฟ' + 45: 1, # 'ภ' + 9: 3, # 'ม' + 16: 3, # 'ย' + 2: 3, # 'ร' + 61: 0, # 'ฤ' + 15: 2, # 'ล' + 12: 2, # 'ว' + 42: 1, # 'ศ' + 46: 0, # 'ษ' + 18: 2, # 'ส' + 21: 2, # 'ห' + 4: 3, # 'อ' + 63: 0, # 'ฯ' + 22: 2, # 'ะ' + 10: 3, # 'ั' + 1: 3, # 'า' + 36: 2, # 'ำ' + 23: 2, # 'ิ' + 13: 3, # 'ี' + 40: 0, # 'ึ' + 27: 3, # 'ื' + 32: 3, # 'ุ' + 35: 0, # 'ู' + 11: 3, # 'เ' + 28: 1, # 'แ' + 41: 1, # 'โ' + 29: 2, # 'ใ' + 33: 2, # 'ไ' + 50: 1, # 'ๆ' + 37: 1, # '็' + 6: 2, # '่' + 7: 2, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 63: { # 'ฯ' + 5: 0, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 0, # 'น' + 17: 0, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 0, # 'ม' + 16: 0, # 'ย' + 2: 0, # 'ร' + 61: 0, # 'ฤ' + 15: 2, # 'ล' + 12: 0, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 0, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 22: { # 'ะ' + 5: 3, # 'ก' + 30: 1, # 'ข' + 24: 2, # 'ค' + 8: 1, # 'ง' + 26: 2, # 'จ' + 52: 0, # 'ฉ' + 34: 3, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 3, # 'ด' + 19: 3, # 'ต' + 44: 1, # 'ถ' + 14: 3, # 'ท' + 48: 1, # 'ธ' + 3: 2, # 'น' + 17: 3, # 'บ' + 25: 2, # 'ป' + 39: 1, # 'ผ' + 62: 0, # 'ฝ' + 31: 2, # 'พ' + 54: 0, # 'ฟ' + 45: 1, # 'ภ' + 9: 3, # 'ม' + 16: 2, # 'ย' + 2: 2, # 'ร' + 61: 0, # 'ฤ' + 15: 2, # 'ล' + 12: 2, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 3, # 'ส' + 21: 3, # 'ห' + 4: 2, # 'อ' + 63: 1, # 'ฯ' + 22: 1, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 3, # 'เ' + 28: 2, # 'แ' + 41: 1, # 'โ' + 29: 2, # 'ใ' + 33: 2, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 10: { # 'ั' + 5: 3, # 'ก' + 30: 0, # 'ข' + 24: 1, # 'ค' + 8: 3, # 'ง' + 26: 3, # 'จ' + 52: 0, # 'ฉ' + 34: 1, # 'ช' + 51: 0, # 'ซ' + 47: 3, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 2, # 'ฐ' + 53: 0, # 'ฑ' + 55: 3, # 'ฒ' + 43: 3, # 'ณ' + 20: 3, # 'ด' + 19: 3, # 'ต' + 44: 0, # 'ถ' + 14: 2, # 'ท' + 48: 0, # 'ธ' + 3: 3, # 'น' + 17: 3, # 'บ' + 25: 1, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 2, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 3, # 'ม' + 16: 3, # 'ย' + 2: 0, # 'ร' + 61: 0, # 'ฤ' + 15: 2, # 'ล' + 12: 3, # 'ว' + 42: 2, # 'ศ' + 46: 0, # 'ษ' + 18: 3, # 'ส' + 21: 0, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 3, # '่' + 7: 3, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 1: { # 'า' + 5: 3, # 'ก' + 30: 2, # 'ข' + 24: 3, # 'ค' + 8: 3, # 'ง' + 26: 3, # 'จ' + 52: 0, # 'ฉ' + 34: 3, # 'ช' + 51: 1, # 'ซ' + 47: 2, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 3, # 'ณ' + 20: 3, # 'ด' + 19: 3, # 'ต' + 44: 1, # 'ถ' + 14: 3, # 'ท' + 48: 2, # 'ธ' + 3: 3, # 'น' + 17: 3, # 'บ' + 25: 2, # 'ป' + 39: 1, # 'ผ' + 62: 1, # 'ฝ' + 31: 3, # 'พ' + 54: 1, # 'ฟ' + 45: 1, # 'ภ' + 9: 3, # 'ม' + 16: 3, # 'ย' + 2: 3, # 'ร' + 61: 0, # 'ฤ' + 15: 3, # 'ล' + 12: 3, # 'ว' + 42: 2, # 'ศ' + 46: 3, # 'ษ' + 18: 3, # 'ส' + 21: 3, # 'ห' + 4: 2, # 'อ' + 63: 1, # 'ฯ' + 22: 3, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 3, # 'เ' + 28: 2, # 'แ' + 41: 1, # 'โ' + 29: 2, # 'ใ' + 33: 2, # 'ไ' + 50: 1, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 36: { # 'ำ' + 5: 2, # 'ก' + 30: 1, # 'ข' + 24: 3, # 'ค' + 8: 2, # 'ง' + 26: 1, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 1, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 1, # 'ด' + 19: 1, # 'ต' + 44: 1, # 'ถ' + 14: 1, # 'ท' + 48: 0, # 'ธ' + 3: 3, # 'น' + 17: 1, # 'บ' + 25: 1, # 'ป' + 39: 1, # 'ผ' + 62: 0, # 'ฝ' + 31: 1, # 'พ' + 54: 0, # 'ฟ' + 45: 1, # 'ภ' + 9: 1, # 'ม' + 16: 0, # 'ย' + 2: 2, # 'ร' + 61: 0, # 'ฤ' + 15: 2, # 'ล' + 12: 1, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 1, # 'ส' + 21: 3, # 'ห' + 4: 1, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 3, # 'เ' + 28: 2, # 'แ' + 41: 1, # 'โ' + 29: 2, # 'ใ' + 33: 2, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 23: { # 'ิ' + 5: 3, # 'ก' + 30: 1, # 'ข' + 24: 2, # 'ค' + 8: 3, # 'ง' + 26: 3, # 'จ' + 52: 0, # 'ฉ' + 34: 3, # 'ช' + 51: 0, # 'ซ' + 47: 2, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 3, # 'ด' + 19: 3, # 'ต' + 44: 1, # 'ถ' + 14: 3, # 'ท' + 48: 3, # 'ธ' + 3: 3, # 'น' + 17: 3, # 'บ' + 25: 2, # 'ป' + 39: 2, # 'ผ' + 62: 0, # 'ฝ' + 31: 3, # 'พ' + 54: 1, # 'ฟ' + 45: 2, # 'ภ' + 9: 3, # 'ม' + 16: 2, # 'ย' + 2: 2, # 'ร' + 61: 0, # 'ฤ' + 15: 2, # 'ล' + 12: 3, # 'ว' + 42: 3, # 'ศ' + 46: 2, # 'ษ' + 18: 2, # 'ส' + 21: 3, # 'ห' + 4: 1, # 'อ' + 63: 1, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 3, # 'เ' + 28: 1, # 'แ' + 41: 1, # 'โ' + 29: 1, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 3, # '่' + 7: 2, # '้' + 38: 2, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 13: { # 'ี' + 5: 3, # 'ก' + 30: 2, # 'ข' + 24: 2, # 'ค' + 8: 0, # 'ง' + 26: 1, # 'จ' + 52: 0, # 'ฉ' + 34: 1, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 2, # 'ด' + 19: 1, # 'ต' + 44: 0, # 'ถ' + 14: 2, # 'ท' + 48: 0, # 'ธ' + 3: 1, # 'น' + 17: 2, # 'บ' + 25: 2, # 'ป' + 39: 1, # 'ผ' + 62: 0, # 'ฝ' + 31: 2, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 2, # 'ม' + 16: 3, # 'ย' + 2: 2, # 'ร' + 61: 0, # 'ฤ' + 15: 1, # 'ล' + 12: 2, # 'ว' + 42: 1, # 'ศ' + 46: 0, # 'ษ' + 18: 2, # 'ส' + 21: 1, # 'ห' + 4: 2, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 2, # 'เ' + 28: 2, # 'แ' + 41: 1, # 'โ' + 29: 1, # 'ใ' + 33: 1, # 'ไ' + 50: 1, # 'ๆ' + 37: 0, # '็' + 6: 3, # '่' + 7: 3, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 40: { # 'ึ' + 5: 3, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 3, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 1, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 0, # 'น' + 17: 0, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 1, # 'ม' + 16: 0, # 'ย' + 2: 0, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 0, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 0, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 3, # '่' + 7: 3, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 27: { # 'ื' + 5: 0, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 1, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 1, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 2, # 'น' + 17: 3, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 2, # 'ม' + 16: 0, # 'ย' + 2: 0, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 0, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 0, # 'ห' + 4: 3, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 3, # '่' + 7: 3, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 32: { # 'ุ' + 5: 3, # 'ก' + 30: 2, # 'ข' + 24: 3, # 'ค' + 8: 3, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 2, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 1, # 'ฒ' + 43: 3, # 'ณ' + 20: 3, # 'ด' + 19: 3, # 'ต' + 44: 1, # 'ถ' + 14: 2, # 'ท' + 48: 1, # 'ธ' + 3: 2, # 'น' + 17: 2, # 'บ' + 25: 2, # 'ป' + 39: 2, # 'ผ' + 62: 0, # 'ฝ' + 31: 1, # 'พ' + 54: 0, # 'ฟ' + 45: 1, # 'ภ' + 9: 3, # 'ม' + 16: 1, # 'ย' + 2: 2, # 'ร' + 61: 0, # 'ฤ' + 15: 2, # 'ล' + 12: 1, # 'ว' + 42: 1, # 'ศ' + 46: 2, # 'ษ' + 18: 1, # 'ส' + 21: 1, # 'ห' + 4: 1, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 1, # 'เ' + 28: 0, # 'แ' + 41: 1, # 'โ' + 29: 0, # 'ใ' + 33: 1, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 3, # '่' + 7: 2, # '้' + 38: 1, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 35: { # 'ู' + 5: 3, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 2, # 'ง' + 26: 1, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 2, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 1, # 'ณ' + 20: 2, # 'ด' + 19: 2, # 'ต' + 44: 0, # 'ถ' + 14: 1, # 'ท' + 48: 0, # 'ธ' + 3: 2, # 'น' + 17: 0, # 'บ' + 25: 3, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 2, # 'ม' + 16: 0, # 'ย' + 2: 1, # 'ร' + 61: 0, # 'ฤ' + 15: 3, # 'ล' + 12: 1, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 0, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 1, # 'เ' + 28: 1, # 'แ' + 41: 1, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 3, # '่' + 7: 3, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 11: { # 'เ' + 5: 3, # 'ก' + 30: 3, # 'ข' + 24: 3, # 'ค' + 8: 2, # 'ง' + 26: 3, # 'จ' + 52: 3, # 'ฉ' + 34: 3, # 'ช' + 51: 2, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 1, # 'ณ' + 20: 3, # 'ด' + 19: 3, # 'ต' + 44: 1, # 'ถ' + 14: 3, # 'ท' + 48: 1, # 'ธ' + 3: 3, # 'น' + 17: 3, # 'บ' + 25: 3, # 'ป' + 39: 2, # 'ผ' + 62: 1, # 'ฝ' + 31: 3, # 'พ' + 54: 1, # 'ฟ' + 45: 3, # 'ภ' + 9: 3, # 'ม' + 16: 2, # 'ย' + 2: 3, # 'ร' + 61: 0, # 'ฤ' + 15: 3, # 'ล' + 12: 3, # 'ว' + 42: 2, # 'ศ' + 46: 0, # 'ษ' + 18: 3, # 'ส' + 21: 3, # 'ห' + 4: 3, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 28: { # 'แ' + 5: 3, # 'ก' + 30: 2, # 'ข' + 24: 2, # 'ค' + 8: 1, # 'ง' + 26: 2, # 'จ' + 52: 0, # 'ฉ' + 34: 1, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 2, # 'ด' + 19: 3, # 'ต' + 44: 2, # 'ถ' + 14: 3, # 'ท' + 48: 0, # 'ธ' + 3: 3, # 'น' + 17: 3, # 'บ' + 25: 2, # 'ป' + 39: 3, # 'ผ' + 62: 0, # 'ฝ' + 31: 2, # 'พ' + 54: 2, # 'ฟ' + 45: 0, # 'ภ' + 9: 2, # 'ม' + 16: 2, # 'ย' + 2: 2, # 'ร' + 61: 0, # 'ฤ' + 15: 3, # 'ล' + 12: 2, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 3, # 'ส' + 21: 3, # 'ห' + 4: 1, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 41: { # 'โ' + 5: 2, # 'ก' + 30: 1, # 'ข' + 24: 2, # 'ค' + 8: 0, # 'ง' + 26: 1, # 'จ' + 52: 1, # 'ฉ' + 34: 1, # 'ช' + 51: 1, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 3, # 'ด' + 19: 2, # 'ต' + 44: 0, # 'ถ' + 14: 2, # 'ท' + 48: 0, # 'ธ' + 3: 3, # 'น' + 17: 1, # 'บ' + 25: 3, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 1, # 'พ' + 54: 1, # 'ฟ' + 45: 1, # 'ภ' + 9: 1, # 'ม' + 16: 2, # 'ย' + 2: 2, # 'ร' + 61: 0, # 'ฤ' + 15: 3, # 'ล' + 12: 0, # 'ว' + 42: 1, # 'ศ' + 46: 0, # 'ษ' + 18: 2, # 'ส' + 21: 0, # 'ห' + 4: 2, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 29: { # 'ใ' + 5: 2, # 'ก' + 30: 0, # 'ข' + 24: 1, # 'ค' + 8: 0, # 'ง' + 26: 3, # 'จ' + 52: 0, # 'ฉ' + 34: 3, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 3, # 'ด' + 19: 1, # 'ต' + 44: 0, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 3, # 'น' + 17: 2, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 0, # 'ม' + 16: 1, # 'ย' + 2: 0, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 0, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 3, # 'ส' + 21: 3, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 33: { # 'ไ' + 5: 1, # 'ก' + 30: 2, # 'ข' + 24: 0, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 1, # 'ช' + 51: 1, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 3, # 'ด' + 19: 1, # 'ต' + 44: 0, # 'ถ' + 14: 3, # 'ท' + 48: 0, # 'ธ' + 3: 0, # 'น' + 17: 1, # 'บ' + 25: 3, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 2, # 'ฟ' + 45: 0, # 'ภ' + 9: 3, # 'ม' + 16: 0, # 'ย' + 2: 3, # 'ร' + 61: 0, # 'ฤ' + 15: 1, # 'ล' + 12: 3, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 1, # 'ส' + 21: 2, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 50: { # 'ๆ' + 5: 0, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 0, # 'น' + 17: 0, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 0, # 'ม' + 16: 0, # 'ย' + 2: 0, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 0, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 0, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 37: { # '็' + 5: 2, # 'ก' + 30: 1, # 'ข' + 24: 2, # 'ค' + 8: 2, # 'ง' + 26: 3, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 1, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 1, # 'ด' + 19: 2, # 'ต' + 44: 0, # 'ถ' + 14: 1, # 'ท' + 48: 0, # 'ธ' + 3: 3, # 'น' + 17: 3, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 2, # 'ม' + 16: 1, # 'ย' + 2: 0, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 2, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 1, # 'ส' + 21: 0, # 'ห' + 4: 1, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 1, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 1, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 6: { # '่' + 5: 2, # 'ก' + 30: 1, # 'ข' + 24: 2, # 'ค' + 8: 3, # 'ง' + 26: 2, # 'จ' + 52: 0, # 'ฉ' + 34: 1, # 'ช' + 51: 1, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 1, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 1, # 'ด' + 19: 2, # 'ต' + 44: 1, # 'ถ' + 14: 2, # 'ท' + 48: 1, # 'ธ' + 3: 3, # 'น' + 17: 1, # 'บ' + 25: 2, # 'ป' + 39: 2, # 'ผ' + 62: 1, # 'ฝ' + 31: 1, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 3, # 'ม' + 16: 3, # 'ย' + 2: 2, # 'ร' + 61: 0, # 'ฤ' + 15: 2, # 'ล' + 12: 3, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 2, # 'ส' + 21: 1, # 'ห' + 4: 3, # 'อ' + 63: 0, # 'ฯ' + 22: 1, # 'ะ' + 10: 0, # 'ั' + 1: 3, # 'า' + 36: 2, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 3, # 'เ' + 28: 2, # 'แ' + 41: 1, # 'โ' + 29: 2, # 'ใ' + 33: 2, # 'ไ' + 50: 1, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 7: { # '้' + 5: 2, # 'ก' + 30: 1, # 'ข' + 24: 2, # 'ค' + 8: 3, # 'ง' + 26: 2, # 'จ' + 52: 0, # 'ฉ' + 34: 1, # 'ช' + 51: 1, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 1, # 'ด' + 19: 2, # 'ต' + 44: 1, # 'ถ' + 14: 2, # 'ท' + 48: 0, # 'ธ' + 3: 3, # 'น' + 17: 2, # 'บ' + 25: 2, # 'ป' + 39: 2, # 'ผ' + 62: 0, # 'ฝ' + 31: 1, # 'พ' + 54: 1, # 'ฟ' + 45: 0, # 'ภ' + 9: 3, # 'ม' + 16: 2, # 'ย' + 2: 2, # 'ร' + 61: 0, # 'ฤ' + 15: 1, # 'ล' + 12: 3, # 'ว' + 42: 1, # 'ศ' + 46: 0, # 'ษ' + 18: 2, # 'ส' + 21: 2, # 'ห' + 4: 3, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 3, # 'า' + 36: 2, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 2, # 'เ' + 28: 2, # 'แ' + 41: 1, # 'โ' + 29: 2, # 'ใ' + 33: 2, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 38: { # '์' + 5: 2, # 'ก' + 30: 1, # 'ข' + 24: 1, # 'ค' + 8: 0, # 'ง' + 26: 1, # 'จ' + 52: 0, # 'ฉ' + 34: 1, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 2, # 'ด' + 19: 1, # 'ต' + 44: 1, # 'ถ' + 14: 1, # 'ท' + 48: 0, # 'ธ' + 3: 1, # 'น' + 17: 1, # 'บ' + 25: 1, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 1, # 'พ' + 54: 1, # 'ฟ' + 45: 0, # 'ภ' + 9: 2, # 'ม' + 16: 0, # 'ย' + 2: 1, # 'ร' + 61: 1, # 'ฤ' + 15: 1, # 'ล' + 12: 1, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 1, # 'ส' + 21: 1, # 'ห' + 4: 2, # 'อ' + 63: 1, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 2, # 'เ' + 28: 2, # 'แ' + 41: 1, # 'โ' + 29: 1, # 'ใ' + 33: 1, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 0, # '๑' + 59: 0, # '๒' + 60: 0, # '๕' + }, + 56: { # '๑' + 5: 0, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 0, # 'น' + 17: 0, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 0, # 'ม' + 16: 0, # 'ย' + 2: 0, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 0, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 0, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 2, # '๑' + 59: 1, # '๒' + 60: 1, # '๕' + }, + 59: { # '๒' + 5: 0, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 0, # 'น' + 17: 0, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 0, # 'ม' + 16: 0, # 'ย' + 2: 0, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 0, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 0, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 1, # '๑' + 59: 1, # '๒' + 60: 3, # '๕' + }, + 60: { # '๕' + 5: 0, # 'ก' + 30: 0, # 'ข' + 24: 0, # 'ค' + 8: 0, # 'ง' + 26: 0, # 'จ' + 52: 0, # 'ฉ' + 34: 0, # 'ช' + 51: 0, # 'ซ' + 47: 0, # 'ญ' + 58: 0, # 'ฎ' + 57: 0, # 'ฏ' + 49: 0, # 'ฐ' + 53: 0, # 'ฑ' + 55: 0, # 'ฒ' + 43: 0, # 'ณ' + 20: 0, # 'ด' + 19: 0, # 'ต' + 44: 0, # 'ถ' + 14: 0, # 'ท' + 48: 0, # 'ธ' + 3: 0, # 'น' + 17: 0, # 'บ' + 25: 0, # 'ป' + 39: 0, # 'ผ' + 62: 0, # 'ฝ' + 31: 0, # 'พ' + 54: 0, # 'ฟ' + 45: 0, # 'ภ' + 9: 0, # 'ม' + 16: 0, # 'ย' + 2: 0, # 'ร' + 61: 0, # 'ฤ' + 15: 0, # 'ล' + 12: 0, # 'ว' + 42: 0, # 'ศ' + 46: 0, # 'ษ' + 18: 0, # 'ส' + 21: 0, # 'ห' + 4: 0, # 'อ' + 63: 0, # 'ฯ' + 22: 0, # 'ะ' + 10: 0, # 'ั' + 1: 0, # 'า' + 36: 0, # 'ำ' + 23: 0, # 'ิ' + 13: 0, # 'ี' + 40: 0, # 'ึ' + 27: 0, # 'ื' + 32: 0, # 'ุ' + 35: 0, # 'ู' + 11: 0, # 'เ' + 28: 0, # 'แ' + 41: 0, # 'โ' + 29: 0, # 'ใ' + 33: 0, # 'ไ' + 50: 0, # 'ๆ' + 37: 0, # '็' + 6: 0, # '่' + 7: 0, # '้' + 38: 0, # '์' + 56: 2, # '๑' + 59: 1, # '๒' + 60: 0, # '๕' + }, +} + +# 255: Undefined characters that did not exist in training text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 +# 251: Control characters + +# Character Mapping Table(s): +TIS_620_THAI_CHAR_TO_ORDER = { + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 254, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 254, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 253, # ' ' + 33: 253, # '!' + 34: 253, # '"' + 35: 253, # '#' + 36: 253, # '$' + 37: 253, # '%' + 38: 253, # '&' + 39: 253, # "'" + 40: 253, # '(' + 41: 253, # ')' + 42: 253, # '*' + 43: 253, # '+' + 44: 253, # ',' + 45: 253, # '-' + 46: 253, # '.' + 47: 253, # '/' + 48: 252, # '0' + 49: 252, # '1' + 50: 252, # '2' + 51: 252, # '3' + 52: 252, # '4' + 53: 252, # '5' + 54: 252, # '6' + 55: 252, # '7' + 56: 252, # '8' + 57: 252, # '9' + 58: 253, # ':' + 59: 253, # ';' + 60: 253, # '<' + 61: 253, # '=' + 62: 253, # '>' + 63: 253, # '?' + 64: 253, # '@' + 65: 182, # 'A' + 66: 106, # 'B' + 67: 107, # 'C' + 68: 100, # 'D' + 69: 183, # 'E' + 70: 184, # 'F' + 71: 185, # 'G' + 72: 101, # 'H' + 73: 94, # 'I' + 74: 186, # 'J' + 75: 187, # 'K' + 76: 108, # 'L' + 77: 109, # 'M' + 78: 110, # 'N' + 79: 111, # 'O' + 80: 188, # 'P' + 81: 189, # 'Q' + 82: 190, # 'R' + 83: 89, # 'S' + 84: 95, # 'T' + 85: 112, # 'U' + 86: 113, # 'V' + 87: 191, # 'W' + 88: 192, # 'X' + 89: 193, # 'Y' + 90: 194, # 'Z' + 91: 253, # '[' + 92: 253, # '\\' + 93: 253, # ']' + 94: 253, # '^' + 95: 253, # '_' + 96: 253, # '`' + 97: 64, # 'a' + 98: 72, # 'b' + 99: 73, # 'c' + 100: 114, # 'd' + 101: 74, # 'e' + 102: 115, # 'f' + 103: 116, # 'g' + 104: 102, # 'h' + 105: 81, # 'i' + 106: 201, # 'j' + 107: 117, # 'k' + 108: 90, # 'l' + 109: 103, # 'm' + 110: 78, # 'n' + 111: 82, # 'o' + 112: 96, # 'p' + 113: 202, # 'q' + 114: 91, # 'r' + 115: 79, # 's' + 116: 84, # 't' + 117: 104, # 'u' + 118: 105, # 'v' + 119: 97, # 'w' + 120: 98, # 'x' + 121: 92, # 'y' + 122: 203, # 'z' + 123: 253, # '{' + 124: 253, # '|' + 125: 253, # '}' + 126: 253, # '~' + 127: 253, # '\x7f' + 128: 209, # '\x80' + 129: 210, # '\x81' + 130: 211, # '\x82' + 131: 212, # '\x83' + 132: 213, # '\x84' + 133: 88, # '\x85' + 134: 214, # '\x86' + 135: 215, # '\x87' + 136: 216, # '\x88' + 137: 217, # '\x89' + 138: 218, # '\x8a' + 139: 219, # '\x8b' + 140: 220, # '\x8c' + 141: 118, # '\x8d' + 142: 221, # '\x8e' + 143: 222, # '\x8f' + 144: 223, # '\x90' + 145: 224, # '\x91' + 146: 99, # '\x92' + 147: 85, # '\x93' + 148: 83, # '\x94' + 149: 225, # '\x95' + 150: 226, # '\x96' + 151: 227, # '\x97' + 152: 228, # '\x98' + 153: 229, # '\x99' + 154: 230, # '\x9a' + 155: 231, # '\x9b' + 156: 232, # '\x9c' + 157: 233, # '\x9d' + 158: 234, # '\x9e' + 159: 235, # '\x9f' + 160: 236, # None + 161: 5, # 'ก' + 162: 30, # 'ข' + 163: 237, # 'ฃ' + 164: 24, # 'ค' + 165: 238, # 'ฅ' + 166: 75, # 'ฆ' + 167: 8, # 'ง' + 168: 26, # 'จ' + 169: 52, # 'ฉ' + 170: 34, # 'ช' + 171: 51, # 'ซ' + 172: 119, # 'ฌ' + 173: 47, # 'ญ' + 174: 58, # 'ฎ' + 175: 57, # 'ฏ' + 176: 49, # 'ฐ' + 177: 53, # 'ฑ' + 178: 55, # 'ฒ' + 179: 43, # 'ณ' + 180: 20, # 'ด' + 181: 19, # 'ต' + 182: 44, # 'ถ' + 183: 14, # 'ท' + 184: 48, # 'ธ' + 185: 3, # 'น' + 186: 17, # 'บ' + 187: 25, # 'ป' + 188: 39, # 'ผ' + 189: 62, # 'ฝ' + 190: 31, # 'พ' + 191: 54, # 'ฟ' + 192: 45, # 'ภ' + 193: 9, # 'ม' + 194: 16, # 'ย' + 195: 2, # 'ร' + 196: 61, # 'ฤ' + 197: 15, # 'ล' + 198: 239, # 'ฦ' + 199: 12, # 'ว' + 200: 42, # 'ศ' + 201: 46, # 'ษ' + 202: 18, # 'ส' + 203: 21, # 'ห' + 204: 76, # 'ฬ' + 205: 4, # 'อ' + 206: 66, # 'ฮ' + 207: 63, # 'ฯ' + 208: 22, # 'ะ' + 209: 10, # 'ั' + 210: 1, # 'า' + 211: 36, # 'ำ' + 212: 23, # 'ิ' + 213: 13, # 'ี' + 214: 40, # 'ึ' + 215: 27, # 'ื' + 216: 32, # 'ุ' + 217: 35, # 'ู' + 218: 86, # 'ฺ' + 219: 240, # None + 220: 241, # None + 221: 242, # None + 222: 243, # None + 223: 244, # '฿' + 224: 11, # 'เ' + 225: 28, # 'แ' + 226: 41, # 'โ' + 227: 29, # 'ใ' + 228: 33, # 'ไ' + 229: 245, # 'ๅ' + 230: 50, # 'ๆ' + 231: 37, # '็' + 232: 6, # '่' + 233: 7, # '้' + 234: 67, # '๊' + 235: 77, # '๋' + 236: 38, # '์' + 237: 93, # 'ํ' + 238: 246, # '๎' + 239: 247, # '๏' + 240: 68, # '๐' + 241: 56, # '๑' + 242: 59, # '๒' + 243: 65, # '๓' + 244: 69, # '๔' + 245: 60, # '๕' + 246: 70, # '๖' + 247: 80, # '๗' + 248: 71, # '๘' + 249: 87, # '๙' + 250: 248, # '๚' + 251: 249, # '๛' + 252: 250, # None + 253: 251, # None + 254: 252, # None + 255: 253, # None +} + +TIS_620_THAI_MODEL = SingleByteCharSetModel(charset_name='TIS-620', + language='Thai', + char_to_order_map=TIS_620_THAI_CHAR_TO_ORDER, + language_model=THAI_LANG_MODEL, + typical_positive_ratio=0.926386, + keep_ascii_letters=False, + alphabet='กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛') + diff --git a/venv/lib/python3.8/site-packages/chardet/langturkishmodel.py b/venv/lib/python3.8/site-packages/chardet/langturkishmodel.py new file mode 100644 index 0000000..8ba9322 --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/langturkishmodel.py @@ -0,0 +1,4383 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +from chardet.sbcharsetprober import SingleByteCharSetModel + + +# 3: Positive +# 2: Likely +# 1: Unlikely +# 0: Negative + +TURKISH_LANG_MODEL = { + 23: { # 'A' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 0, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 0, # 'b' + 28: 0, # 'c' + 12: 2, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 1, # 'g' + 25: 1, # 'h' + 3: 1, # 'i' + 24: 0, # 'j' + 10: 2, # 'k' + 5: 1, # 'l' + 13: 1, # 'm' + 4: 1, # 'n' + 15: 0, # 'o' + 26: 0, # 'p' + 7: 1, # 'r' + 8: 1, # 's' + 9: 1, # 't' + 14: 1, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 3, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 1, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 0, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 0, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 37: { # 'B' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 2, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 2, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 1, # 'K' + 49: 0, # 'L' + 20: 0, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 1, # 'P' + 44: 0, # 'R' + 35: 1, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 1, # 'V' + 62: 0, # 'W' + 43: 1, # 'Y' + 56: 0, # 'Z' + 1: 2, # 'a' + 21: 0, # 'b' + 28: 2, # 'c' + 12: 0, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 0, # 'i' + 24: 0, # 'j' + 10: 0, # 'k' + 5: 0, # 'l' + 13: 1, # 'm' + 4: 1, # 'n' + 15: 0, # 'o' + 26: 0, # 'p' + 7: 0, # 'r' + 8: 0, # 's' + 9: 0, # 't' + 14: 2, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 1, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 1, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 1, # 'ö' + 17: 0, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 0, # 'ı' + 40: 1, # 'Ş' + 19: 1, # 'ş' + }, + 47: { # 'C' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 1, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 1, # 'L' + 20: 0, # 'M' + 46: 1, # 'N' + 42: 0, # 'O' + 48: 1, # 'P' + 44: 1, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 1, # 'V' + 62: 0, # 'W' + 43: 1, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 0, # 'b' + 28: 2, # 'c' + 12: 0, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 0, # 'i' + 24: 2, # 'j' + 10: 1, # 'k' + 5: 2, # 'l' + 13: 2, # 'm' + 4: 2, # 'n' + 15: 1, # 'o' + 26: 0, # 'p' + 7: 2, # 'r' + 8: 0, # 's' + 9: 0, # 't' + 14: 3, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 2, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 1, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 1, # 'ç' + 61: 0, # 'î' + 34: 1, # 'ö' + 17: 0, # 'ü' + 30: 0, # 'ğ' + 41: 1, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 39: { # 'D' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 1, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 1, # 'K' + 49: 0, # 'L' + 20: 0, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 1, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 2, # 'a' + 21: 0, # 'b' + 28: 2, # 'c' + 12: 0, # 'd' + 2: 2, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 0, # 'i' + 24: 0, # 'j' + 10: 0, # 'k' + 5: 1, # 'l' + 13: 3, # 'm' + 4: 0, # 'n' + 15: 1, # 'o' + 26: 0, # 'p' + 7: 0, # 'r' + 8: 0, # 's' + 9: 0, # 't' + 14: 1, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 1, # 'z' + 63: 0, # '·' + 54: 1, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 1, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 0, # 'ü' + 30: 1, # 'ğ' + 41: 0, # 'İ' + 6: 1, # 'ı' + 40: 1, # 'Ş' + 19: 0, # 'ş' + }, + 29: { # 'E' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 1, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 3, # 'K' + 49: 0, # 'L' + 20: 1, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 0, # 'b' + 28: 0, # 'c' + 12: 2, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 1, # 'g' + 25: 0, # 'h' + 3: 1, # 'i' + 24: 1, # 'j' + 10: 0, # 'k' + 5: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 15: 0, # 'o' + 26: 0, # 'p' + 7: 0, # 'r' + 8: 1, # 's' + 9: 1, # 't' + 14: 1, # 'u' + 32: 1, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 2, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 0, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 52: { # 'F' + 23: 0, # 'A' + 37: 1, # 'B' + 47: 1, # 'C' + 39: 1, # 'D' + 29: 1, # 'E' + 52: 2, # 'F' + 36: 0, # 'G' + 45: 2, # 'H' + 53: 1, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 1, # 'M' + 46: 1, # 'N' + 42: 1, # 'O' + 48: 2, # 'P' + 44: 1, # 'R' + 35: 1, # 'S' + 31: 1, # 'T' + 51: 1, # 'U' + 38: 1, # 'V' + 62: 0, # 'W' + 43: 2, # 'Y' + 56: 0, # 'Z' + 1: 0, # 'a' + 21: 1, # 'b' + 28: 1, # 'c' + 12: 1, # 'd' + 2: 0, # 'e' + 18: 1, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 2, # 'i' + 24: 1, # 'j' + 10: 0, # 'k' + 5: 0, # 'l' + 13: 1, # 'm' + 4: 2, # 'n' + 15: 1, # 'o' + 26: 0, # 'p' + 7: 2, # 'r' + 8: 1, # 's' + 9: 1, # 't' + 14: 1, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 1, # 'y' + 22: 1, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 1, # 'Ö' + 55: 2, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 2, # 'ö' + 17: 0, # 'ü' + 30: 1, # 'ğ' + 41: 1, # 'İ' + 6: 2, # 'ı' + 40: 0, # 'Ş' + 19: 2, # 'ş' + }, + 36: { # 'G' + 23: 1, # 'A' + 37: 0, # 'B' + 47: 1, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 1, # 'F' + 36: 2, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 2, # 'K' + 49: 0, # 'L' + 20: 0, # 'M' + 46: 2, # 'N' + 42: 1, # 'O' + 48: 1, # 'P' + 44: 1, # 'R' + 35: 1, # 'S' + 31: 0, # 'T' + 51: 1, # 'U' + 38: 2, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 0, # 'b' + 28: 1, # 'c' + 12: 0, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 0, # 'i' + 24: 1, # 'j' + 10: 1, # 'k' + 5: 0, # 'l' + 13: 3, # 'm' + 4: 2, # 'n' + 15: 0, # 'o' + 26: 1, # 'p' + 7: 0, # 'r' + 8: 1, # 's' + 9: 1, # 't' + 14: 3, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 1, # 'x' + 11: 0, # 'y' + 22: 2, # 'z' + 63: 0, # '·' + 54: 1, # 'Ç' + 50: 2, # 'Ö' + 55: 0, # 'Ü' + 59: 1, # 'â' + 33: 2, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 0, # 'ü' + 30: 1, # 'ğ' + 41: 1, # 'İ' + 6: 2, # 'ı' + 40: 2, # 'Ş' + 19: 1, # 'ş' + }, + 45: { # 'H' + 23: 0, # 'A' + 37: 1, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 2, # 'F' + 36: 2, # 'G' + 45: 1, # 'H' + 53: 1, # 'I' + 60: 0, # 'J' + 16: 2, # 'K' + 49: 1, # 'L' + 20: 0, # 'M' + 46: 1, # 'N' + 42: 1, # 'O' + 48: 1, # 'P' + 44: 0, # 'R' + 35: 2, # 'S' + 31: 0, # 'T' + 51: 1, # 'U' + 38: 2, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 0, # 'b' + 28: 2, # 'c' + 12: 0, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 2, # 'i' + 24: 0, # 'j' + 10: 1, # 'k' + 5: 0, # 'l' + 13: 2, # 'm' + 4: 0, # 'n' + 15: 1, # 'o' + 26: 1, # 'p' + 7: 1, # 'r' + 8: 0, # 's' + 9: 0, # 't' + 14: 3, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 2, # 'z' + 63: 0, # '·' + 54: 1, # 'Ç' + 50: 1, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 1, # 'ç' + 61: 0, # 'î' + 34: 1, # 'ö' + 17: 0, # 'ü' + 30: 2, # 'ğ' + 41: 1, # 'İ' + 6: 0, # 'ı' + 40: 2, # 'Ş' + 19: 1, # 'ş' + }, + 53: { # 'I' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 1, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 2, # 'K' + 49: 0, # 'L' + 20: 0, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 1, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 2, # 'a' + 21: 0, # 'b' + 28: 2, # 'c' + 12: 0, # 'd' + 2: 2, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 0, # 'i' + 24: 0, # 'j' + 10: 0, # 'k' + 5: 2, # 'l' + 13: 2, # 'm' + 4: 0, # 'n' + 15: 0, # 'o' + 26: 0, # 'p' + 7: 0, # 'r' + 8: 0, # 's' + 9: 0, # 't' + 14: 2, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 2, # 'z' + 63: 0, # '·' + 54: 1, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 2, # 'ç' + 61: 0, # 'î' + 34: 1, # 'ö' + 17: 0, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 0, # 'ı' + 40: 1, # 'Ş' + 19: 1, # 'ş' + }, + 60: { # 'J' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 1, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 0, # 'a' + 21: 1, # 'b' + 28: 0, # 'c' + 12: 1, # 'd' + 2: 0, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 1, # 'i' + 24: 0, # 'j' + 10: 0, # 'k' + 5: 0, # 'l' + 13: 0, # 'm' + 4: 1, # 'n' + 15: 0, # 'o' + 26: 0, # 'p' + 7: 0, # 'r' + 8: 1, # 's' + 9: 0, # 't' + 14: 0, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 0, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 0, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 16: { # 'K' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 3, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 2, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 2, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 2, # 'a' + 21: 3, # 'b' + 28: 0, # 'c' + 12: 3, # 'd' + 2: 1, # 'e' + 18: 3, # 'f' + 27: 3, # 'g' + 25: 3, # 'h' + 3: 3, # 'i' + 24: 2, # 'j' + 10: 3, # 'k' + 5: 0, # 'l' + 13: 0, # 'm' + 4: 3, # 'n' + 15: 0, # 'o' + 26: 1, # 'p' + 7: 3, # 'r' + 8: 3, # 's' + 9: 3, # 't' + 14: 0, # 'u' + 32: 3, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 2, # 'y' + 22: 1, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 2, # 'ü' + 30: 0, # 'ğ' + 41: 1, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 49: { # 'L' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 2, # 'E' + 52: 0, # 'F' + 36: 1, # 'G' + 45: 1, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 1, # 'M' + 46: 0, # 'N' + 42: 2, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 1, # 'Y' + 56: 0, # 'Z' + 1: 0, # 'a' + 21: 3, # 'b' + 28: 0, # 'c' + 12: 2, # 'd' + 2: 0, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 2, # 'i' + 24: 0, # 'j' + 10: 1, # 'k' + 5: 0, # 'l' + 13: 0, # 'm' + 4: 2, # 'n' + 15: 1, # 'o' + 26: 1, # 'p' + 7: 1, # 'r' + 8: 1, # 's' + 9: 1, # 't' + 14: 0, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 2, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 2, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 1, # 'ö' + 17: 1, # 'ü' + 30: 1, # 'ğ' + 41: 0, # 'İ' + 6: 2, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 20: { # 'M' + 23: 1, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 1, # 'J' + 16: 3, # 'K' + 49: 0, # 'L' + 20: 2, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 1, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 2, # 'b' + 28: 0, # 'c' + 12: 3, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 1, # 'g' + 25: 1, # 'h' + 3: 2, # 'i' + 24: 2, # 'j' + 10: 2, # 'k' + 5: 2, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 15: 0, # 'o' + 26: 1, # 'p' + 7: 3, # 'r' + 8: 0, # 's' + 9: 2, # 't' + 14: 3, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 2, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 3, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 0, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 46: { # 'N' + 23: 0, # 'A' + 37: 1, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 1, # 'F' + 36: 1, # 'G' + 45: 1, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 2, # 'K' + 49: 0, # 'L' + 20: 0, # 'M' + 46: 1, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 1, # 'R' + 35: 1, # 'S' + 31: 0, # 'T' + 51: 1, # 'U' + 38: 2, # 'V' + 62: 0, # 'W' + 43: 1, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 0, # 'b' + 28: 2, # 'c' + 12: 0, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 1, # 'g' + 25: 0, # 'h' + 3: 0, # 'i' + 24: 2, # 'j' + 10: 1, # 'k' + 5: 1, # 'l' + 13: 3, # 'm' + 4: 2, # 'n' + 15: 1, # 'o' + 26: 1, # 'p' + 7: 1, # 'r' + 8: 0, # 's' + 9: 0, # 't' + 14: 3, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 1, # 'x' + 11: 1, # 'y' + 22: 2, # 'z' + 63: 0, # '·' + 54: 1, # 'Ç' + 50: 1, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 1, # 'ö' + 17: 0, # 'ü' + 30: 0, # 'ğ' + 41: 1, # 'İ' + 6: 2, # 'ı' + 40: 1, # 'Ş' + 19: 1, # 'ş' + }, + 42: { # 'O' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 1, # 'F' + 36: 0, # 'G' + 45: 1, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 2, # 'K' + 49: 1, # 'L' + 20: 0, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 2, # 'P' + 44: 1, # 'R' + 35: 1, # 'S' + 31: 0, # 'T' + 51: 1, # 'U' + 38: 1, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 0, # 'b' + 28: 2, # 'c' + 12: 0, # 'd' + 2: 2, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 0, # 'i' + 24: 0, # 'j' + 10: 0, # 'k' + 5: 3, # 'l' + 13: 3, # 'm' + 4: 0, # 'n' + 15: 1, # 'o' + 26: 0, # 'p' + 7: 0, # 'r' + 8: 0, # 's' + 9: 0, # 't' + 14: 2, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 2, # 'z' + 63: 0, # '·' + 54: 2, # 'Ç' + 50: 1, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 2, # 'ç' + 61: 0, # 'î' + 34: 1, # 'ö' + 17: 0, # 'ü' + 30: 1, # 'ğ' + 41: 2, # 'İ' + 6: 1, # 'ı' + 40: 1, # 'Ş' + 19: 1, # 'ş' + }, + 48: { # 'P' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 2, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 2, # 'F' + 36: 1, # 'G' + 45: 1, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 2, # 'K' + 49: 0, # 'L' + 20: 0, # 'M' + 46: 1, # 'N' + 42: 1, # 'O' + 48: 1, # 'P' + 44: 0, # 'R' + 35: 1, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 1, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 2, # 'a' + 21: 0, # 'b' + 28: 2, # 'c' + 12: 0, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 0, # 'i' + 24: 0, # 'j' + 10: 1, # 'k' + 5: 0, # 'l' + 13: 2, # 'm' + 4: 0, # 'n' + 15: 2, # 'o' + 26: 0, # 'p' + 7: 0, # 'r' + 8: 0, # 's' + 9: 0, # 't' + 14: 2, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 2, # 'x' + 11: 0, # 'y' + 22: 2, # 'z' + 63: 0, # '·' + 54: 1, # 'Ç' + 50: 2, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 2, # 'ö' + 17: 0, # 'ü' + 30: 1, # 'ğ' + 41: 1, # 'İ' + 6: 0, # 'ı' + 40: 2, # 'Ş' + 19: 1, # 'ş' + }, + 44: { # 'R' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 1, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 1, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 3, # 'K' + 49: 0, # 'L' + 20: 0, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 1, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 1, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 1, # 'b' + 28: 1, # 'c' + 12: 0, # 'd' + 2: 2, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 0, # 'i' + 24: 0, # 'j' + 10: 1, # 'k' + 5: 2, # 'l' + 13: 2, # 'm' + 4: 0, # 'n' + 15: 1, # 'o' + 26: 0, # 'p' + 7: 0, # 'r' + 8: 0, # 's' + 9: 0, # 't' + 14: 2, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 1, # 'y' + 22: 2, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 1, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 1, # 'ç' + 61: 0, # 'î' + 34: 1, # 'ö' + 17: 1, # 'ü' + 30: 1, # 'ğ' + 41: 0, # 'İ' + 6: 2, # 'ı' + 40: 1, # 'Ş' + 19: 1, # 'ş' + }, + 35: { # 'S' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 1, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 1, # 'F' + 36: 1, # 'G' + 45: 1, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 3, # 'K' + 49: 1, # 'L' + 20: 1, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 1, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 1, # 'U' + 38: 1, # 'V' + 62: 0, # 'W' + 43: 1, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 0, # 'b' + 28: 2, # 'c' + 12: 0, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 0, # 'i' + 24: 0, # 'j' + 10: 1, # 'k' + 5: 1, # 'l' + 13: 2, # 'm' + 4: 1, # 'n' + 15: 0, # 'o' + 26: 0, # 'p' + 7: 0, # 'r' + 8: 0, # 's' + 9: 1, # 't' + 14: 2, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 1, # 'z' + 63: 0, # '·' + 54: 2, # 'Ç' + 50: 2, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 3, # 'ç' + 61: 0, # 'î' + 34: 1, # 'ö' + 17: 0, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 3, # 'ı' + 40: 2, # 'Ş' + 19: 1, # 'ş' + }, + 31: { # 'T' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 1, # 'J' + 16: 2, # 'K' + 49: 0, # 'L' + 20: 1, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 2, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 2, # 'b' + 28: 0, # 'c' + 12: 1, # 'd' + 2: 3, # 'e' + 18: 2, # 'f' + 27: 2, # 'g' + 25: 0, # 'h' + 3: 1, # 'i' + 24: 1, # 'j' + 10: 2, # 'k' + 5: 2, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 15: 0, # 'o' + 26: 2, # 'p' + 7: 2, # 'r' + 8: 0, # 's' + 9: 2, # 't' + 14: 2, # 'u' + 32: 1, # 'v' + 57: 1, # 'w' + 58: 1, # 'x' + 11: 2, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 1, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 51: { # 'U' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 1, # 'F' + 36: 1, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 1, # 'K' + 49: 0, # 'L' + 20: 0, # 'M' + 46: 1, # 'N' + 42: 0, # 'O' + 48: 1, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 1, # 'U' + 38: 1, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 0, # 'b' + 28: 1, # 'c' + 12: 0, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 2, # 'g' + 25: 0, # 'h' + 3: 0, # 'i' + 24: 0, # 'j' + 10: 1, # 'k' + 5: 1, # 'l' + 13: 3, # 'm' + 4: 2, # 'n' + 15: 0, # 'o' + 26: 1, # 'p' + 7: 0, # 'r' + 8: 0, # 's' + 9: 0, # 't' + 14: 2, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 2, # 'z' + 63: 0, # '·' + 54: 1, # 'Ç' + 50: 1, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 0, # 'ü' + 30: 1, # 'ğ' + 41: 1, # 'İ' + 6: 2, # 'ı' + 40: 0, # 'Ş' + 19: 1, # 'ş' + }, + 38: { # 'V' + 23: 1, # 'A' + 37: 1, # 'B' + 47: 1, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 2, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 3, # 'K' + 49: 0, # 'L' + 20: 3, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 1, # 'P' + 44: 1, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 1, # 'U' + 38: 1, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 0, # 'b' + 28: 2, # 'c' + 12: 0, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 0, # 'i' + 24: 0, # 'j' + 10: 0, # 'k' + 5: 2, # 'l' + 13: 2, # 'm' + 4: 0, # 'n' + 15: 2, # 'o' + 26: 0, # 'p' + 7: 0, # 'r' + 8: 0, # 's' + 9: 1, # 't' + 14: 3, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 1, # 'y' + 22: 2, # 'z' + 63: 0, # '·' + 54: 1, # 'Ç' + 50: 1, # 'Ö' + 55: 0, # 'Ü' + 59: 1, # 'â' + 33: 2, # 'ç' + 61: 0, # 'î' + 34: 1, # 'ö' + 17: 0, # 'ü' + 30: 1, # 'ğ' + 41: 1, # 'İ' + 6: 3, # 'ı' + 40: 2, # 'Ş' + 19: 1, # 'ş' + }, + 62: { # 'W' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 0, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 0, # 'a' + 21: 0, # 'b' + 28: 0, # 'c' + 12: 0, # 'd' + 2: 0, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 0, # 'i' + 24: 0, # 'j' + 10: 0, # 'k' + 5: 0, # 'l' + 13: 0, # 'm' + 4: 0, # 'n' + 15: 0, # 'o' + 26: 0, # 'p' + 7: 0, # 'r' + 8: 0, # 's' + 9: 0, # 't' + 14: 0, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 0, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 0, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 43: { # 'Y' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 1, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 2, # 'F' + 36: 0, # 'G' + 45: 1, # 'H' + 53: 1, # 'I' + 60: 0, # 'J' + 16: 2, # 'K' + 49: 0, # 'L' + 20: 0, # 'M' + 46: 2, # 'N' + 42: 0, # 'O' + 48: 2, # 'P' + 44: 1, # 'R' + 35: 1, # 'S' + 31: 0, # 'T' + 51: 1, # 'U' + 38: 2, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 0, # 'b' + 28: 2, # 'c' + 12: 0, # 'd' + 2: 2, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 0, # 'i' + 24: 1, # 'j' + 10: 1, # 'k' + 5: 1, # 'l' + 13: 3, # 'm' + 4: 0, # 'n' + 15: 2, # 'o' + 26: 0, # 'p' + 7: 0, # 'r' + 8: 0, # 's' + 9: 0, # 't' + 14: 3, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 1, # 'x' + 11: 0, # 'y' + 22: 2, # 'z' + 63: 0, # '·' + 54: 1, # 'Ç' + 50: 2, # 'Ö' + 55: 1, # 'Ü' + 59: 1, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 1, # 'ö' + 17: 0, # 'ü' + 30: 1, # 'ğ' + 41: 1, # 'İ' + 6: 0, # 'ı' + 40: 2, # 'Ş' + 19: 1, # 'ş' + }, + 56: { # 'Z' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 0, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 2, # 'Z' + 1: 2, # 'a' + 21: 1, # 'b' + 28: 0, # 'c' + 12: 0, # 'd' + 2: 2, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 2, # 'i' + 24: 1, # 'j' + 10: 0, # 'k' + 5: 0, # 'l' + 13: 1, # 'm' + 4: 1, # 'n' + 15: 0, # 'o' + 26: 0, # 'p' + 7: 1, # 'r' + 8: 1, # 's' + 9: 0, # 't' + 14: 2, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 1, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 1, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 1: { # 'a' + 23: 3, # 'A' + 37: 0, # 'B' + 47: 1, # 'C' + 39: 0, # 'D' + 29: 3, # 'E' + 52: 0, # 'F' + 36: 1, # 'G' + 45: 1, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 3, # 'M' + 46: 1, # 'N' + 42: 0, # 'O' + 48: 1, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 3, # 'T' + 51: 0, # 'U' + 38: 1, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 2, # 'Z' + 1: 2, # 'a' + 21: 3, # 'b' + 28: 0, # 'c' + 12: 3, # 'd' + 2: 2, # 'e' + 18: 3, # 'f' + 27: 3, # 'g' + 25: 3, # 'h' + 3: 3, # 'i' + 24: 3, # 'j' + 10: 3, # 'k' + 5: 0, # 'l' + 13: 2, # 'm' + 4: 3, # 'n' + 15: 1, # 'o' + 26: 3, # 'p' + 7: 3, # 'r' + 8: 3, # 's' + 9: 3, # 't' + 14: 3, # 'u' + 32: 3, # 'v' + 57: 2, # 'w' + 58: 0, # 'x' + 11: 3, # 'y' + 22: 0, # 'z' + 63: 1, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 1, # 'ç' + 61: 1, # 'î' + 34: 1, # 'ö' + 17: 3, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 1, # 'ş' + }, + 21: { # 'b' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 1, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 1, # 'J' + 16: 2, # 'K' + 49: 0, # 'L' + 20: 2, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 1, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 1, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 2, # 'b' + 28: 0, # 'c' + 12: 3, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 3, # 'g' + 25: 1, # 'h' + 3: 3, # 'i' + 24: 2, # 'j' + 10: 3, # 'k' + 5: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 15: 0, # 'o' + 26: 3, # 'p' + 7: 1, # 'r' + 8: 2, # 's' + 9: 2, # 't' + 14: 2, # 'u' + 32: 1, # 'v' + 57: 0, # 'w' + 58: 1, # 'x' + 11: 3, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 1, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 0, # 'ü' + 30: 1, # 'ğ' + 41: 0, # 'İ' + 6: 2, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 28: { # 'c' + 23: 0, # 'A' + 37: 1, # 'B' + 47: 1, # 'C' + 39: 1, # 'D' + 29: 2, # 'E' + 52: 0, # 'F' + 36: 2, # 'G' + 45: 2, # 'H' + 53: 1, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 2, # 'M' + 46: 1, # 'N' + 42: 1, # 'O' + 48: 2, # 'P' + 44: 1, # 'R' + 35: 1, # 'S' + 31: 2, # 'T' + 51: 2, # 'U' + 38: 2, # 'V' + 62: 0, # 'W' + 43: 3, # 'Y' + 56: 0, # 'Z' + 1: 1, # 'a' + 21: 1, # 'b' + 28: 2, # 'c' + 12: 2, # 'd' + 2: 1, # 'e' + 18: 1, # 'f' + 27: 2, # 'g' + 25: 2, # 'h' + 3: 3, # 'i' + 24: 1, # 'j' + 10: 3, # 'k' + 5: 0, # 'l' + 13: 2, # 'm' + 4: 3, # 'n' + 15: 2, # 'o' + 26: 2, # 'p' + 7: 3, # 'r' + 8: 3, # 's' + 9: 3, # 't' + 14: 1, # 'u' + 32: 0, # 'v' + 57: 1, # 'w' + 58: 0, # 'x' + 11: 2, # 'y' + 22: 1, # 'z' + 63: 1, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 1, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 1, # 'î' + 34: 2, # 'ö' + 17: 2, # 'ü' + 30: 2, # 'ğ' + 41: 1, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 2, # 'ş' + }, + 12: { # 'd' + 23: 1, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 2, # 'J' + 16: 3, # 'K' + 49: 0, # 'L' + 20: 3, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 1, # 'S' + 31: 1, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 2, # 'b' + 28: 1, # 'c' + 12: 3, # 'd' + 2: 3, # 'e' + 18: 1, # 'f' + 27: 3, # 'g' + 25: 3, # 'h' + 3: 2, # 'i' + 24: 3, # 'j' + 10: 2, # 'k' + 5: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 15: 1, # 'o' + 26: 2, # 'p' + 7: 3, # 'r' + 8: 2, # 's' + 9: 2, # 't' + 14: 3, # 'u' + 32: 1, # 'v' + 57: 0, # 'w' + 58: 1, # 'x' + 11: 3, # 'y' + 22: 1, # 'z' + 63: 1, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 1, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 2, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 2: { # 'e' + 23: 2, # 'A' + 37: 0, # 'B' + 47: 2, # 'C' + 39: 0, # 'D' + 29: 3, # 'E' + 52: 1, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 1, # 'K' + 49: 0, # 'L' + 20: 3, # 'M' + 46: 1, # 'N' + 42: 0, # 'O' + 48: 1, # 'P' + 44: 1, # 'R' + 35: 0, # 'S' + 31: 3, # 'T' + 51: 0, # 'U' + 38: 1, # 'V' + 62: 0, # 'W' + 43: 1, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 3, # 'b' + 28: 0, # 'c' + 12: 3, # 'd' + 2: 2, # 'e' + 18: 3, # 'f' + 27: 3, # 'g' + 25: 3, # 'h' + 3: 3, # 'i' + 24: 3, # 'j' + 10: 3, # 'k' + 5: 0, # 'l' + 13: 2, # 'm' + 4: 3, # 'n' + 15: 1, # 'o' + 26: 3, # 'p' + 7: 3, # 'r' + 8: 3, # 's' + 9: 3, # 't' + 14: 3, # 'u' + 32: 3, # 'v' + 57: 2, # 'w' + 58: 0, # 'x' + 11: 3, # 'y' + 22: 1, # 'z' + 63: 1, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 1, # 'ç' + 61: 0, # 'î' + 34: 1, # 'ö' + 17: 3, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 18: { # 'f' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 2, # 'K' + 49: 0, # 'L' + 20: 2, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 2, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 1, # 'b' + 28: 0, # 'c' + 12: 3, # 'd' + 2: 3, # 'e' + 18: 2, # 'f' + 27: 1, # 'g' + 25: 1, # 'h' + 3: 1, # 'i' + 24: 1, # 'j' + 10: 1, # 'k' + 5: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 15: 0, # 'o' + 26: 2, # 'p' + 7: 1, # 'r' + 8: 3, # 's' + 9: 3, # 't' + 14: 1, # 'u' + 32: 2, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 1, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 1, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 1, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 1, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 27: { # 'g' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 3, # 'K' + 49: 0, # 'L' + 20: 0, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 1, # 'S' + 31: 1, # 'T' + 51: 0, # 'U' + 38: 2, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 1, # 'b' + 28: 0, # 'c' + 12: 1, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 2, # 'g' + 25: 1, # 'h' + 3: 2, # 'i' + 24: 3, # 'j' + 10: 2, # 'k' + 5: 3, # 'l' + 13: 3, # 'm' + 4: 2, # 'n' + 15: 0, # 'o' + 26: 1, # 'p' + 7: 2, # 'r' + 8: 2, # 's' + 9: 3, # 't' + 14: 3, # 'u' + 32: 1, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 1, # 'y' + 22: 0, # 'z' + 63: 1, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 0, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 2, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 25: { # 'h' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 2, # 'K' + 49: 0, # 'L' + 20: 0, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 0, # 'b' + 28: 0, # 'c' + 12: 2, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 1, # 'g' + 25: 2, # 'h' + 3: 2, # 'i' + 24: 3, # 'j' + 10: 3, # 'k' + 5: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 15: 1, # 'o' + 26: 1, # 'p' + 7: 3, # 'r' + 8: 3, # 's' + 9: 2, # 't' + 14: 3, # 'u' + 32: 2, # 'v' + 57: 1, # 'w' + 58: 0, # 'x' + 11: 1, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 0, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 3: { # 'i' + 23: 2, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 1, # 'J' + 16: 3, # 'K' + 49: 0, # 'L' + 20: 3, # 'M' + 46: 0, # 'N' + 42: 1, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 1, # 'S' + 31: 2, # 'T' + 51: 0, # 'U' + 38: 1, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 2, # 'b' + 28: 0, # 'c' + 12: 3, # 'd' + 2: 3, # 'e' + 18: 2, # 'f' + 27: 3, # 'g' + 25: 1, # 'h' + 3: 3, # 'i' + 24: 2, # 'j' + 10: 3, # 'k' + 5: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 15: 1, # 'o' + 26: 3, # 'p' + 7: 3, # 'r' + 8: 3, # 's' + 9: 3, # 't' + 14: 3, # 'u' + 32: 2, # 'v' + 57: 1, # 'w' + 58: 1, # 'x' + 11: 3, # 'y' + 22: 1, # 'z' + 63: 1, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 1, # 'Ü' + 59: 0, # 'â' + 33: 2, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 3, # 'ü' + 30: 0, # 'ğ' + 41: 1, # 'İ' + 6: 2, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 24: { # 'j' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 1, # 'J' + 16: 2, # 'K' + 49: 0, # 'L' + 20: 2, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 1, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 1, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 1, # 'Z' + 1: 3, # 'a' + 21: 1, # 'b' + 28: 1, # 'c' + 12: 3, # 'd' + 2: 3, # 'e' + 18: 2, # 'f' + 27: 1, # 'g' + 25: 1, # 'h' + 3: 2, # 'i' + 24: 1, # 'j' + 10: 2, # 'k' + 5: 2, # 'l' + 13: 3, # 'm' + 4: 2, # 'n' + 15: 0, # 'o' + 26: 1, # 'p' + 7: 2, # 'r' + 8: 3, # 's' + 9: 2, # 't' + 14: 3, # 'u' + 32: 2, # 'v' + 57: 0, # 'w' + 58: 2, # 'x' + 11: 1, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 1, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 1, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 10: { # 'k' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 3, # 'K' + 49: 0, # 'L' + 20: 2, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 3, # 'T' + 51: 0, # 'U' + 38: 1, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 1, # 'Z' + 1: 3, # 'a' + 21: 2, # 'b' + 28: 0, # 'c' + 12: 2, # 'd' + 2: 3, # 'e' + 18: 1, # 'f' + 27: 2, # 'g' + 25: 2, # 'h' + 3: 3, # 'i' + 24: 2, # 'j' + 10: 2, # 'k' + 5: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 15: 0, # 'o' + 26: 3, # 'p' + 7: 2, # 'r' + 8: 2, # 's' + 9: 2, # 't' + 14: 3, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 1, # 'x' + 11: 3, # 'y' + 22: 0, # 'z' + 63: 1, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 3, # 'ç' + 61: 0, # 'î' + 34: 1, # 'ö' + 17: 3, # 'ü' + 30: 1, # 'ğ' + 41: 0, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 1, # 'ş' + }, + 5: { # 'l' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 3, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 2, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 1, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 0, # 'a' + 21: 3, # 'b' + 28: 0, # 'c' + 12: 3, # 'd' + 2: 1, # 'e' + 18: 3, # 'f' + 27: 3, # 'g' + 25: 2, # 'h' + 3: 3, # 'i' + 24: 2, # 'j' + 10: 3, # 'k' + 5: 1, # 'l' + 13: 1, # 'm' + 4: 3, # 'n' + 15: 0, # 'o' + 26: 2, # 'p' + 7: 3, # 'r' + 8: 3, # 's' + 9: 3, # 't' + 14: 2, # 'u' + 32: 2, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 3, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 1, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 2, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 13: { # 'm' + 23: 1, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 3, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 3, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 3, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 1, # 'Y' + 56: 0, # 'Z' + 1: 2, # 'a' + 21: 3, # 'b' + 28: 0, # 'c' + 12: 3, # 'd' + 2: 2, # 'e' + 18: 3, # 'f' + 27: 3, # 'g' + 25: 3, # 'h' + 3: 3, # 'i' + 24: 3, # 'j' + 10: 3, # 'k' + 5: 0, # 'l' + 13: 2, # 'm' + 4: 3, # 'n' + 15: 1, # 'o' + 26: 2, # 'p' + 7: 3, # 'r' + 8: 3, # 's' + 9: 3, # 't' + 14: 2, # 'u' + 32: 2, # 'v' + 57: 1, # 'w' + 58: 0, # 'x' + 11: 3, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 3, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 1, # 'ş' + }, + 4: { # 'n' + 23: 1, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 1, # 'H' + 53: 0, # 'I' + 60: 2, # 'J' + 16: 3, # 'K' + 49: 0, # 'L' + 20: 3, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 2, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 2, # 'b' + 28: 1, # 'c' + 12: 3, # 'd' + 2: 3, # 'e' + 18: 1, # 'f' + 27: 2, # 'g' + 25: 3, # 'h' + 3: 2, # 'i' + 24: 2, # 'j' + 10: 3, # 'k' + 5: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 15: 1, # 'o' + 26: 3, # 'p' + 7: 2, # 'r' + 8: 3, # 's' + 9: 3, # 't' + 14: 3, # 'u' + 32: 2, # 'v' + 57: 0, # 'w' + 58: 2, # 'x' + 11: 3, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 1, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 2, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 1, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 15: { # 'o' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 1, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 2, # 'F' + 36: 1, # 'G' + 45: 1, # 'H' + 53: 1, # 'I' + 60: 0, # 'J' + 16: 3, # 'K' + 49: 2, # 'L' + 20: 0, # 'M' + 46: 2, # 'N' + 42: 1, # 'O' + 48: 2, # 'P' + 44: 1, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 0, # 'b' + 28: 2, # 'c' + 12: 0, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 1, # 'i' + 24: 2, # 'j' + 10: 1, # 'k' + 5: 3, # 'l' + 13: 3, # 'm' + 4: 2, # 'n' + 15: 2, # 'o' + 26: 0, # 'p' + 7: 1, # 'r' + 8: 0, # 's' + 9: 0, # 't' + 14: 3, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 2, # 'x' + 11: 0, # 'y' + 22: 2, # 'z' + 63: 0, # '·' + 54: 1, # 'Ç' + 50: 2, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 3, # 'ç' + 61: 0, # 'î' + 34: 1, # 'ö' + 17: 0, # 'ü' + 30: 2, # 'ğ' + 41: 2, # 'İ' + 6: 3, # 'ı' + 40: 2, # 'Ş' + 19: 2, # 'ş' + }, + 26: { # 'p' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 3, # 'K' + 49: 0, # 'L' + 20: 1, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 1, # 'b' + 28: 0, # 'c' + 12: 1, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 1, # 'g' + 25: 1, # 'h' + 3: 2, # 'i' + 24: 3, # 'j' + 10: 1, # 'k' + 5: 3, # 'l' + 13: 3, # 'm' + 4: 2, # 'n' + 15: 0, # 'o' + 26: 2, # 'p' + 7: 2, # 'r' + 8: 1, # 's' + 9: 1, # 't' + 14: 3, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 1, # 'x' + 11: 1, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 3, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 1, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 7: { # 'r' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 1, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 2, # 'J' + 16: 3, # 'K' + 49: 0, # 'L' + 20: 2, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 2, # 'T' + 51: 1, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 1, # 'Z' + 1: 3, # 'a' + 21: 1, # 'b' + 28: 0, # 'c' + 12: 3, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 2, # 'g' + 25: 3, # 'h' + 3: 2, # 'i' + 24: 2, # 'j' + 10: 3, # 'k' + 5: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 15: 0, # 'o' + 26: 2, # 'p' + 7: 3, # 'r' + 8: 3, # 's' + 9: 3, # 't' + 14: 3, # 'u' + 32: 2, # 'v' + 57: 0, # 'w' + 58: 1, # 'x' + 11: 2, # 'y' + 22: 0, # 'z' + 63: 1, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 2, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 3, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 2, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 8: { # 's' + 23: 1, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 1, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 3, # 'K' + 49: 0, # 'L' + 20: 3, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 2, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 1, # 'Z' + 1: 3, # 'a' + 21: 2, # 'b' + 28: 1, # 'c' + 12: 3, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 2, # 'g' + 25: 2, # 'h' + 3: 2, # 'i' + 24: 3, # 'j' + 10: 3, # 'k' + 5: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 15: 0, # 'o' + 26: 3, # 'p' + 7: 3, # 'r' + 8: 3, # 's' + 9: 3, # 't' + 14: 3, # 'u' + 32: 2, # 'v' + 57: 0, # 'w' + 58: 1, # 'x' + 11: 2, # 'y' + 22: 1, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 2, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 2, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 1, # 'ş' + }, + 9: { # 't' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 1, # 'J' + 16: 3, # 'K' + 49: 0, # 'L' + 20: 2, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 2, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 1, # 'Z' + 1: 3, # 'a' + 21: 3, # 'b' + 28: 0, # 'c' + 12: 3, # 'd' + 2: 3, # 'e' + 18: 2, # 'f' + 27: 2, # 'g' + 25: 2, # 'h' + 3: 2, # 'i' + 24: 2, # 'j' + 10: 3, # 'k' + 5: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 15: 0, # 'o' + 26: 2, # 'p' + 7: 3, # 'r' + 8: 3, # 's' + 9: 3, # 't' + 14: 3, # 'u' + 32: 3, # 'v' + 57: 0, # 'w' + 58: 2, # 'x' + 11: 2, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 3, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 2, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 14: { # 'u' + 23: 3, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 3, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 1, # 'H' + 53: 0, # 'I' + 60: 1, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 3, # 'M' + 46: 2, # 'N' + 42: 0, # 'O' + 48: 1, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 3, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 1, # 'Y' + 56: 2, # 'Z' + 1: 2, # 'a' + 21: 3, # 'b' + 28: 0, # 'c' + 12: 3, # 'd' + 2: 2, # 'e' + 18: 2, # 'f' + 27: 3, # 'g' + 25: 3, # 'h' + 3: 3, # 'i' + 24: 2, # 'j' + 10: 3, # 'k' + 5: 0, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 15: 0, # 'o' + 26: 3, # 'p' + 7: 3, # 'r' + 8: 3, # 's' + 9: 3, # 't' + 14: 3, # 'u' + 32: 2, # 'v' + 57: 2, # 'w' + 58: 0, # 'x' + 11: 3, # 'y' + 22: 0, # 'z' + 63: 1, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 3, # 'ü' + 30: 1, # 'ğ' + 41: 0, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 32: { # 'v' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 3, # 'K' + 49: 0, # 'L' + 20: 1, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 0, # 'b' + 28: 0, # 'c' + 12: 3, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 0, # 'i' + 24: 1, # 'j' + 10: 1, # 'k' + 5: 3, # 'l' + 13: 2, # 'm' + 4: 3, # 'n' + 15: 0, # 'o' + 26: 1, # 'p' + 7: 1, # 'r' + 8: 2, # 's' + 9: 3, # 't' + 14: 3, # 'u' + 32: 1, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 2, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 0, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 1, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 57: { # 'w' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 0, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 1, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 1, # 'a' + 21: 0, # 'b' + 28: 0, # 'c' + 12: 0, # 'd' + 2: 2, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 1, # 'h' + 3: 0, # 'i' + 24: 0, # 'j' + 10: 1, # 'k' + 5: 0, # 'l' + 13: 0, # 'm' + 4: 1, # 'n' + 15: 0, # 'o' + 26: 0, # 'p' + 7: 0, # 'r' + 8: 1, # 's' + 9: 0, # 't' + 14: 1, # 'u' + 32: 0, # 'v' + 57: 2, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 0, # 'z' + 63: 1, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 1, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 0, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 58: { # 'x' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 1, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 1, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 1, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 0, # 'a' + 21: 1, # 'b' + 28: 0, # 'c' + 12: 2, # 'd' + 2: 1, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 2, # 'i' + 24: 2, # 'j' + 10: 1, # 'k' + 5: 0, # 'l' + 13: 0, # 'm' + 4: 2, # 'n' + 15: 0, # 'o' + 26: 0, # 'p' + 7: 1, # 'r' + 8: 2, # 's' + 9: 1, # 't' + 14: 0, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 2, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 1, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 2, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 11: { # 'y' + 23: 1, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 1, # 'J' + 16: 3, # 'K' + 49: 0, # 'L' + 20: 1, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 1, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 1, # 'Y' + 56: 1, # 'Z' + 1: 3, # 'a' + 21: 1, # 'b' + 28: 0, # 'c' + 12: 2, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 2, # 'g' + 25: 2, # 'h' + 3: 2, # 'i' + 24: 1, # 'j' + 10: 2, # 'k' + 5: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 15: 0, # 'o' + 26: 1, # 'p' + 7: 2, # 'r' + 8: 1, # 's' + 9: 2, # 't' + 14: 3, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 1, # 'x' + 11: 3, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 3, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 2, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 22: { # 'z' + 23: 2, # 'A' + 37: 2, # 'B' + 47: 1, # 'C' + 39: 2, # 'D' + 29: 3, # 'E' + 52: 1, # 'F' + 36: 2, # 'G' + 45: 2, # 'H' + 53: 1, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 3, # 'M' + 46: 2, # 'N' + 42: 2, # 'O' + 48: 2, # 'P' + 44: 1, # 'R' + 35: 1, # 'S' + 31: 3, # 'T' + 51: 2, # 'U' + 38: 2, # 'V' + 62: 0, # 'W' + 43: 2, # 'Y' + 56: 1, # 'Z' + 1: 1, # 'a' + 21: 2, # 'b' + 28: 1, # 'c' + 12: 2, # 'd' + 2: 2, # 'e' + 18: 3, # 'f' + 27: 2, # 'g' + 25: 2, # 'h' + 3: 3, # 'i' + 24: 2, # 'j' + 10: 3, # 'k' + 5: 0, # 'l' + 13: 2, # 'm' + 4: 3, # 'n' + 15: 2, # 'o' + 26: 2, # 'p' + 7: 3, # 'r' + 8: 3, # 's' + 9: 3, # 't' + 14: 0, # 'u' + 32: 2, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 3, # 'y' + 22: 2, # 'z' + 63: 1, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 2, # 'Ü' + 59: 1, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 2, # 'ö' + 17: 2, # 'ü' + 30: 2, # 'ğ' + 41: 1, # 'İ' + 6: 3, # 'ı' + 40: 1, # 'Ş' + 19: 2, # 'ş' + }, + 63: { # '·' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 0, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 0, # 'a' + 21: 0, # 'b' + 28: 0, # 'c' + 12: 0, # 'd' + 2: 1, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 0, # 'i' + 24: 0, # 'j' + 10: 0, # 'k' + 5: 0, # 'l' + 13: 2, # 'm' + 4: 0, # 'n' + 15: 0, # 'o' + 26: 0, # 'p' + 7: 0, # 'r' + 8: 0, # 's' + 9: 0, # 't' + 14: 2, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 0, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 0, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 54: { # 'Ç' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 1, # 'C' + 39: 1, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 1, # 'G' + 45: 1, # 'H' + 53: 1, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 0, # 'M' + 46: 0, # 'N' + 42: 1, # 'O' + 48: 1, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 1, # 'U' + 38: 1, # 'V' + 62: 0, # 'W' + 43: 2, # 'Y' + 56: 0, # 'Z' + 1: 0, # 'a' + 21: 1, # 'b' + 28: 0, # 'c' + 12: 1, # 'd' + 2: 0, # 'e' + 18: 0, # 'f' + 27: 1, # 'g' + 25: 0, # 'h' + 3: 3, # 'i' + 24: 0, # 'j' + 10: 1, # 'k' + 5: 0, # 'l' + 13: 0, # 'm' + 4: 2, # 'n' + 15: 1, # 'o' + 26: 0, # 'p' + 7: 2, # 'r' + 8: 0, # 's' + 9: 1, # 't' + 14: 0, # 'u' + 32: 2, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 2, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 1, # 'ö' + 17: 0, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 2, # 'ı' + 40: 0, # 'Ş' + 19: 1, # 'ş' + }, + 50: { # 'Ö' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 1, # 'C' + 39: 1, # 'D' + 29: 2, # 'E' + 52: 0, # 'F' + 36: 1, # 'G' + 45: 2, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 1, # 'M' + 46: 1, # 'N' + 42: 2, # 'O' + 48: 2, # 'P' + 44: 1, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 1, # 'U' + 38: 1, # 'V' + 62: 0, # 'W' + 43: 2, # 'Y' + 56: 0, # 'Z' + 1: 0, # 'a' + 21: 2, # 'b' + 28: 1, # 'c' + 12: 2, # 'd' + 2: 0, # 'e' + 18: 1, # 'f' + 27: 1, # 'g' + 25: 1, # 'h' + 3: 2, # 'i' + 24: 0, # 'j' + 10: 2, # 'k' + 5: 0, # 'l' + 13: 0, # 'm' + 4: 3, # 'n' + 15: 2, # 'o' + 26: 2, # 'p' + 7: 3, # 'r' + 8: 1, # 's' + 9: 2, # 't' + 14: 0, # 'u' + 32: 1, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 1, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 2, # 'ö' + 17: 2, # 'ü' + 30: 1, # 'ğ' + 41: 0, # 'İ' + 6: 2, # 'ı' + 40: 0, # 'Ş' + 19: 1, # 'ş' + }, + 55: { # 'Ü' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 2, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 1, # 'K' + 49: 0, # 'L' + 20: 0, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 1, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 1, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 2, # 'a' + 21: 0, # 'b' + 28: 2, # 'c' + 12: 0, # 'd' + 2: 2, # 'e' + 18: 0, # 'f' + 27: 1, # 'g' + 25: 0, # 'h' + 3: 0, # 'i' + 24: 0, # 'j' + 10: 0, # 'k' + 5: 1, # 'l' + 13: 1, # 'm' + 4: 1, # 'n' + 15: 0, # 'o' + 26: 0, # 'p' + 7: 0, # 'r' + 8: 0, # 's' + 9: 1, # 't' + 14: 2, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 1, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 1, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 1, # 'ö' + 17: 0, # 'ü' + 30: 1, # 'ğ' + 41: 1, # 'İ' + 6: 0, # 'ı' + 40: 0, # 'Ş' + 19: 1, # 'ş' + }, + 59: { # 'â' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 1, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 1, # 'K' + 49: 0, # 'L' + 20: 0, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 2, # 'a' + 21: 0, # 'b' + 28: 0, # 'c' + 12: 0, # 'd' + 2: 2, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 0, # 'i' + 24: 0, # 'j' + 10: 0, # 'k' + 5: 0, # 'l' + 13: 2, # 'm' + 4: 0, # 'n' + 15: 1, # 'o' + 26: 0, # 'p' + 7: 0, # 'r' + 8: 0, # 's' + 9: 0, # 't' + 14: 2, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 1, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 0, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 1, # 'ı' + 40: 1, # 'Ş' + 19: 0, # 'ş' + }, + 33: { # 'ç' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 3, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 1, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 2, # 'T' + 51: 0, # 'U' + 38: 1, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 0, # 'Z' + 1: 0, # 'a' + 21: 3, # 'b' + 28: 0, # 'c' + 12: 2, # 'd' + 2: 0, # 'e' + 18: 2, # 'f' + 27: 1, # 'g' + 25: 3, # 'h' + 3: 3, # 'i' + 24: 0, # 'j' + 10: 3, # 'k' + 5: 0, # 'l' + 13: 0, # 'm' + 4: 3, # 'n' + 15: 0, # 'o' + 26: 1, # 'p' + 7: 3, # 'r' + 8: 2, # 's' + 9: 3, # 't' + 14: 0, # 'u' + 32: 2, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 2, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 1, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 61: { # 'î' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 0, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 0, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 1, # 'Z' + 1: 2, # 'a' + 21: 0, # 'b' + 28: 0, # 'c' + 12: 0, # 'd' + 2: 2, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 0, # 'i' + 24: 1, # 'j' + 10: 0, # 'k' + 5: 0, # 'l' + 13: 1, # 'm' + 4: 1, # 'n' + 15: 0, # 'o' + 26: 0, # 'p' + 7: 0, # 'r' + 8: 0, # 's' + 9: 0, # 't' + 14: 1, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 1, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 1, # 'î' + 34: 0, # 'ö' + 17: 0, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 1, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 34: { # 'ö' + 23: 0, # 'A' + 37: 1, # 'B' + 47: 1, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 2, # 'F' + 36: 1, # 'G' + 45: 1, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 3, # 'K' + 49: 1, # 'L' + 20: 0, # 'M' + 46: 1, # 'N' + 42: 1, # 'O' + 48: 2, # 'P' + 44: 1, # 'R' + 35: 1, # 'S' + 31: 1, # 'T' + 51: 1, # 'U' + 38: 1, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 1, # 'Z' + 1: 3, # 'a' + 21: 1, # 'b' + 28: 2, # 'c' + 12: 1, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 2, # 'g' + 25: 2, # 'h' + 3: 1, # 'i' + 24: 2, # 'j' + 10: 1, # 'k' + 5: 2, # 'l' + 13: 3, # 'm' + 4: 2, # 'n' + 15: 2, # 'o' + 26: 0, # 'p' + 7: 0, # 'r' + 8: 3, # 's' + 9: 1, # 't' + 14: 3, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 1, # 'y' + 22: 2, # 'z' + 63: 0, # '·' + 54: 1, # 'Ç' + 50: 2, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 2, # 'ç' + 61: 0, # 'î' + 34: 2, # 'ö' + 17: 0, # 'ü' + 30: 2, # 'ğ' + 41: 1, # 'İ' + 6: 1, # 'ı' + 40: 2, # 'Ş' + 19: 1, # 'ş' + }, + 17: { # 'ü' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 1, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 0, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 1, # 'J' + 16: 1, # 'K' + 49: 0, # 'L' + 20: 1, # 'M' + 46: 0, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 1, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 0, # 'Y' + 56: 1, # 'Z' + 1: 3, # 'a' + 21: 0, # 'b' + 28: 0, # 'c' + 12: 1, # 'd' + 2: 3, # 'e' + 18: 1, # 'f' + 27: 2, # 'g' + 25: 0, # 'h' + 3: 1, # 'i' + 24: 1, # 'j' + 10: 2, # 'k' + 5: 3, # 'l' + 13: 2, # 'm' + 4: 3, # 'n' + 15: 0, # 'o' + 26: 2, # 'p' + 7: 2, # 'r' + 8: 3, # 's' + 9: 2, # 't' + 14: 3, # 'u' + 32: 1, # 'v' + 57: 1, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 1, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 2, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 2, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 30: { # 'ğ' + 23: 0, # 'A' + 37: 2, # 'B' + 47: 1, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 2, # 'F' + 36: 1, # 'G' + 45: 0, # 'H' + 53: 1, # 'I' + 60: 0, # 'J' + 16: 3, # 'K' + 49: 0, # 'L' + 20: 1, # 'M' + 46: 2, # 'N' + 42: 2, # 'O' + 48: 1, # 'P' + 44: 1, # 'R' + 35: 0, # 'S' + 31: 1, # 'T' + 51: 0, # 'U' + 38: 2, # 'V' + 62: 0, # 'W' + 43: 2, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 0, # 'b' + 28: 2, # 'c' + 12: 0, # 'd' + 2: 2, # 'e' + 18: 0, # 'f' + 27: 0, # 'g' + 25: 0, # 'h' + 3: 0, # 'i' + 24: 3, # 'j' + 10: 1, # 'k' + 5: 2, # 'l' + 13: 3, # 'm' + 4: 0, # 'n' + 15: 1, # 'o' + 26: 0, # 'p' + 7: 1, # 'r' + 8: 0, # 's' + 9: 0, # 't' + 14: 3, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 2, # 'z' + 63: 0, # '·' + 54: 2, # 'Ç' + 50: 2, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 1, # 'ç' + 61: 0, # 'î' + 34: 2, # 'ö' + 17: 0, # 'ü' + 30: 1, # 'ğ' + 41: 2, # 'İ' + 6: 2, # 'ı' + 40: 2, # 'Ş' + 19: 1, # 'ş' + }, + 41: { # 'İ' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 1, # 'C' + 39: 1, # 'D' + 29: 1, # 'E' + 52: 0, # 'F' + 36: 2, # 'G' + 45: 2, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 2, # 'M' + 46: 1, # 'N' + 42: 1, # 'O' + 48: 2, # 'P' + 44: 0, # 'R' + 35: 1, # 'S' + 31: 1, # 'T' + 51: 1, # 'U' + 38: 1, # 'V' + 62: 0, # 'W' + 43: 2, # 'Y' + 56: 0, # 'Z' + 1: 1, # 'a' + 21: 2, # 'b' + 28: 1, # 'c' + 12: 2, # 'd' + 2: 1, # 'e' + 18: 0, # 'f' + 27: 3, # 'g' + 25: 2, # 'h' + 3: 2, # 'i' + 24: 2, # 'j' + 10: 2, # 'k' + 5: 0, # 'l' + 13: 1, # 'm' + 4: 3, # 'n' + 15: 1, # 'o' + 26: 1, # 'p' + 7: 3, # 'r' + 8: 3, # 's' + 9: 2, # 't' + 14: 0, # 'u' + 32: 0, # 'v' + 57: 1, # 'w' + 58: 0, # 'x' + 11: 2, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 1, # 'Ü' + 59: 1, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 1, # 'ö' + 17: 1, # 'ü' + 30: 2, # 'ğ' + 41: 0, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 1, # 'ş' + }, + 6: { # 'ı' + 23: 2, # 'A' + 37: 0, # 'B' + 47: 0, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 0, # 'F' + 36: 1, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 2, # 'J' + 16: 3, # 'K' + 49: 0, # 'L' + 20: 3, # 'M' + 46: 1, # 'N' + 42: 0, # 'O' + 48: 0, # 'P' + 44: 0, # 'R' + 35: 0, # 'S' + 31: 2, # 'T' + 51: 0, # 'U' + 38: 0, # 'V' + 62: 0, # 'W' + 43: 2, # 'Y' + 56: 1, # 'Z' + 1: 3, # 'a' + 21: 2, # 'b' + 28: 1, # 'c' + 12: 3, # 'd' + 2: 3, # 'e' + 18: 3, # 'f' + 27: 3, # 'g' + 25: 2, # 'h' + 3: 3, # 'i' + 24: 3, # 'j' + 10: 3, # 'k' + 5: 3, # 'l' + 13: 3, # 'm' + 4: 3, # 'n' + 15: 0, # 'o' + 26: 3, # 'p' + 7: 3, # 'r' + 8: 3, # 's' + 9: 3, # 't' + 14: 3, # 'u' + 32: 3, # 'v' + 57: 1, # 'w' + 58: 1, # 'x' + 11: 3, # 'y' + 22: 0, # 'z' + 63: 1, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 2, # 'ç' + 61: 0, # 'î' + 34: 0, # 'ö' + 17: 3, # 'ü' + 30: 0, # 'ğ' + 41: 0, # 'İ' + 6: 3, # 'ı' + 40: 0, # 'Ş' + 19: 0, # 'ş' + }, + 40: { # 'Ş' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 1, # 'C' + 39: 1, # 'D' + 29: 1, # 'E' + 52: 0, # 'F' + 36: 1, # 'G' + 45: 2, # 'H' + 53: 1, # 'I' + 60: 0, # 'J' + 16: 0, # 'K' + 49: 0, # 'L' + 20: 2, # 'M' + 46: 1, # 'N' + 42: 1, # 'O' + 48: 2, # 'P' + 44: 2, # 'R' + 35: 1, # 'S' + 31: 1, # 'T' + 51: 0, # 'U' + 38: 1, # 'V' + 62: 0, # 'W' + 43: 2, # 'Y' + 56: 1, # 'Z' + 1: 0, # 'a' + 21: 2, # 'b' + 28: 0, # 'c' + 12: 2, # 'd' + 2: 0, # 'e' + 18: 3, # 'f' + 27: 0, # 'g' + 25: 2, # 'h' + 3: 3, # 'i' + 24: 2, # 'j' + 10: 1, # 'k' + 5: 0, # 'l' + 13: 1, # 'm' + 4: 3, # 'n' + 15: 2, # 'o' + 26: 0, # 'p' + 7: 3, # 'r' + 8: 2, # 's' + 9: 2, # 't' + 14: 1, # 'u' + 32: 3, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 2, # 'y' + 22: 0, # 'z' + 63: 0, # '·' + 54: 0, # 'Ç' + 50: 0, # 'Ö' + 55: 1, # 'Ü' + 59: 0, # 'â' + 33: 0, # 'ç' + 61: 0, # 'î' + 34: 2, # 'ö' + 17: 1, # 'ü' + 30: 2, # 'ğ' + 41: 0, # 'İ' + 6: 2, # 'ı' + 40: 1, # 'Ş' + 19: 2, # 'ş' + }, + 19: { # 'ş' + 23: 0, # 'A' + 37: 0, # 'B' + 47: 1, # 'C' + 39: 0, # 'D' + 29: 0, # 'E' + 52: 2, # 'F' + 36: 1, # 'G' + 45: 0, # 'H' + 53: 0, # 'I' + 60: 0, # 'J' + 16: 3, # 'K' + 49: 2, # 'L' + 20: 0, # 'M' + 46: 1, # 'N' + 42: 1, # 'O' + 48: 1, # 'P' + 44: 1, # 'R' + 35: 1, # 'S' + 31: 0, # 'T' + 51: 1, # 'U' + 38: 1, # 'V' + 62: 0, # 'W' + 43: 1, # 'Y' + 56: 0, # 'Z' + 1: 3, # 'a' + 21: 1, # 'b' + 28: 2, # 'c' + 12: 0, # 'd' + 2: 3, # 'e' + 18: 0, # 'f' + 27: 2, # 'g' + 25: 1, # 'h' + 3: 1, # 'i' + 24: 0, # 'j' + 10: 2, # 'k' + 5: 2, # 'l' + 13: 3, # 'm' + 4: 0, # 'n' + 15: 0, # 'o' + 26: 1, # 'p' + 7: 3, # 'r' + 8: 0, # 's' + 9: 0, # 't' + 14: 3, # 'u' + 32: 0, # 'v' + 57: 0, # 'w' + 58: 0, # 'x' + 11: 0, # 'y' + 22: 2, # 'z' + 63: 0, # '·' + 54: 1, # 'Ç' + 50: 2, # 'Ö' + 55: 0, # 'Ü' + 59: 0, # 'â' + 33: 1, # 'ç' + 61: 1, # 'î' + 34: 2, # 'ö' + 17: 0, # 'ü' + 30: 1, # 'ğ' + 41: 1, # 'İ' + 6: 1, # 'ı' + 40: 1, # 'Ş' + 19: 1, # 'ş' + }, +} + +# 255: Undefined characters that did not exist in training text +# 254: Carriage/Return +# 253: symbol (punctuation) that does not belong to word +# 252: 0 - 9 +# 251: Control characters + +# Character Mapping Table(s): +ISO_8859_9_TURKISH_CHAR_TO_ORDER = { + 0: 255, # '\x00' + 1: 255, # '\x01' + 2: 255, # '\x02' + 3: 255, # '\x03' + 4: 255, # '\x04' + 5: 255, # '\x05' + 6: 255, # '\x06' + 7: 255, # '\x07' + 8: 255, # '\x08' + 9: 255, # '\t' + 10: 255, # '\n' + 11: 255, # '\x0b' + 12: 255, # '\x0c' + 13: 255, # '\r' + 14: 255, # '\x0e' + 15: 255, # '\x0f' + 16: 255, # '\x10' + 17: 255, # '\x11' + 18: 255, # '\x12' + 19: 255, # '\x13' + 20: 255, # '\x14' + 21: 255, # '\x15' + 22: 255, # '\x16' + 23: 255, # '\x17' + 24: 255, # '\x18' + 25: 255, # '\x19' + 26: 255, # '\x1a' + 27: 255, # '\x1b' + 28: 255, # '\x1c' + 29: 255, # '\x1d' + 30: 255, # '\x1e' + 31: 255, # '\x1f' + 32: 255, # ' ' + 33: 255, # '!' + 34: 255, # '"' + 35: 255, # '#' + 36: 255, # '$' + 37: 255, # '%' + 38: 255, # '&' + 39: 255, # "'" + 40: 255, # '(' + 41: 255, # ')' + 42: 255, # '*' + 43: 255, # '+' + 44: 255, # ',' + 45: 255, # '-' + 46: 255, # '.' + 47: 255, # '/' + 48: 255, # '0' + 49: 255, # '1' + 50: 255, # '2' + 51: 255, # '3' + 52: 255, # '4' + 53: 255, # '5' + 54: 255, # '6' + 55: 255, # '7' + 56: 255, # '8' + 57: 255, # '9' + 58: 255, # ':' + 59: 255, # ';' + 60: 255, # '<' + 61: 255, # '=' + 62: 255, # '>' + 63: 255, # '?' + 64: 255, # '@' + 65: 23, # 'A' + 66: 37, # 'B' + 67: 47, # 'C' + 68: 39, # 'D' + 69: 29, # 'E' + 70: 52, # 'F' + 71: 36, # 'G' + 72: 45, # 'H' + 73: 53, # 'I' + 74: 60, # 'J' + 75: 16, # 'K' + 76: 49, # 'L' + 77: 20, # 'M' + 78: 46, # 'N' + 79: 42, # 'O' + 80: 48, # 'P' + 81: 69, # 'Q' + 82: 44, # 'R' + 83: 35, # 'S' + 84: 31, # 'T' + 85: 51, # 'U' + 86: 38, # 'V' + 87: 62, # 'W' + 88: 65, # 'X' + 89: 43, # 'Y' + 90: 56, # 'Z' + 91: 255, # '[' + 92: 255, # '\\' + 93: 255, # ']' + 94: 255, # '^' + 95: 255, # '_' + 96: 255, # '`' + 97: 1, # 'a' + 98: 21, # 'b' + 99: 28, # 'c' + 100: 12, # 'd' + 101: 2, # 'e' + 102: 18, # 'f' + 103: 27, # 'g' + 104: 25, # 'h' + 105: 3, # 'i' + 106: 24, # 'j' + 107: 10, # 'k' + 108: 5, # 'l' + 109: 13, # 'm' + 110: 4, # 'n' + 111: 15, # 'o' + 112: 26, # 'p' + 113: 64, # 'q' + 114: 7, # 'r' + 115: 8, # 's' + 116: 9, # 't' + 117: 14, # 'u' + 118: 32, # 'v' + 119: 57, # 'w' + 120: 58, # 'x' + 121: 11, # 'y' + 122: 22, # 'z' + 123: 255, # '{' + 124: 255, # '|' + 125: 255, # '}' + 126: 255, # '~' + 127: 255, # '\x7f' + 128: 180, # '\x80' + 129: 179, # '\x81' + 130: 178, # '\x82' + 131: 177, # '\x83' + 132: 176, # '\x84' + 133: 175, # '\x85' + 134: 174, # '\x86' + 135: 173, # '\x87' + 136: 172, # '\x88' + 137: 171, # '\x89' + 138: 170, # '\x8a' + 139: 169, # '\x8b' + 140: 168, # '\x8c' + 141: 167, # '\x8d' + 142: 166, # '\x8e' + 143: 165, # '\x8f' + 144: 164, # '\x90' + 145: 163, # '\x91' + 146: 162, # '\x92' + 147: 161, # '\x93' + 148: 160, # '\x94' + 149: 159, # '\x95' + 150: 101, # '\x96' + 151: 158, # '\x97' + 152: 157, # '\x98' + 153: 156, # '\x99' + 154: 155, # '\x9a' + 155: 154, # '\x9b' + 156: 153, # '\x9c' + 157: 152, # '\x9d' + 158: 151, # '\x9e' + 159: 106, # '\x9f' + 160: 150, # '\xa0' + 161: 149, # '¡' + 162: 148, # '¢' + 163: 147, # '£' + 164: 146, # '¤' + 165: 145, # '¥' + 166: 144, # '¦' + 167: 100, # '§' + 168: 143, # '¨' + 169: 142, # '©' + 170: 141, # 'ª' + 171: 140, # '«' + 172: 139, # '¬' + 173: 138, # '\xad' + 174: 137, # '®' + 175: 136, # '¯' + 176: 94, # '°' + 177: 80, # '±' + 178: 93, # '²' + 179: 135, # '³' + 180: 105, # '´' + 181: 134, # 'µ' + 182: 133, # '¶' + 183: 63, # '·' + 184: 132, # '¸' + 185: 131, # '¹' + 186: 130, # 'º' + 187: 129, # '»' + 188: 128, # '¼' + 189: 127, # '½' + 190: 126, # '¾' + 191: 125, # '¿' + 192: 124, # 'À' + 193: 104, # 'Á' + 194: 73, # 'Â' + 195: 99, # 'Ã' + 196: 79, # 'Ä' + 197: 85, # 'Å' + 198: 123, # 'Æ' + 199: 54, # 'Ç' + 200: 122, # 'È' + 201: 98, # 'É' + 202: 92, # 'Ê' + 203: 121, # 'Ë' + 204: 120, # 'Ì' + 205: 91, # 'Í' + 206: 103, # 'Î' + 207: 119, # 'Ï' + 208: 68, # 'Ğ' + 209: 118, # 'Ñ' + 210: 117, # 'Ò' + 211: 97, # 'Ó' + 212: 116, # 'Ô' + 213: 115, # 'Õ' + 214: 50, # 'Ö' + 215: 90, # '×' + 216: 114, # 'Ø' + 217: 113, # 'Ù' + 218: 112, # 'Ú' + 219: 111, # 'Û' + 220: 55, # 'Ü' + 221: 41, # 'İ' + 222: 40, # 'Ş' + 223: 86, # 'ß' + 224: 89, # 'à' + 225: 70, # 'á' + 226: 59, # 'â' + 227: 78, # 'ã' + 228: 71, # 'ä' + 229: 82, # 'å' + 230: 88, # 'æ' + 231: 33, # 'ç' + 232: 77, # 'è' + 233: 66, # 'é' + 234: 84, # 'ê' + 235: 83, # 'ë' + 236: 110, # 'ì' + 237: 75, # 'í' + 238: 61, # 'î' + 239: 96, # 'ï' + 240: 30, # 'ğ' + 241: 67, # 'ñ' + 242: 109, # 'ò' + 243: 74, # 'ó' + 244: 87, # 'ô' + 245: 102, # 'õ' + 246: 34, # 'ö' + 247: 95, # '÷' + 248: 81, # 'ø' + 249: 108, # 'ù' + 250: 76, # 'ú' + 251: 72, # 'û' + 252: 17, # 'ü' + 253: 6, # 'ı' + 254: 19, # 'ş' + 255: 107, # 'ÿ' +} + +ISO_8859_9_TURKISH_MODEL = SingleByteCharSetModel(charset_name='ISO-8859-9', + language='Turkish', + char_to_order_map=ISO_8859_9_TURKISH_CHAR_TO_ORDER, + language_model=TURKISH_LANG_MODEL, + typical_positive_ratio=0.97029, + keep_ascii_letters=True, + alphabet='ABCDEFGHIJKLMNOPRSTUVYZabcdefghijklmnoprstuvyzÂÇÎÖÛÜâçîöûüĞğİıŞş') + diff --git a/venv/lib/python3.8/site-packages/chardet/latin1prober.py b/venv/lib/python3.8/site-packages/chardet/latin1prober.py new file mode 100644 index 0000000..7d1e8c2 --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/latin1prober.py @@ -0,0 +1,145 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .charsetprober import CharSetProber +from .enums import ProbingState + +FREQ_CAT_NUM = 4 + +UDF = 0 # undefined +OTH = 1 # other +ASC = 2 # ascii capital letter +ASS = 3 # ascii small letter +ACV = 4 # accent capital vowel +ACO = 5 # accent capital other +ASV = 6 # accent small vowel +ASO = 7 # accent small other +CLASS_NUM = 8 # total classes + +Latin1_CharToClass = ( + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 00 - 07 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 08 - 0F + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 10 - 17 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 18 - 1F + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 20 - 27 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 28 - 2F + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 30 - 37 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 38 - 3F + OTH, ASC, ASC, ASC, ASC, ASC, ASC, ASC, # 40 - 47 + ASC, ASC, ASC, ASC, ASC, ASC, ASC, ASC, # 48 - 4F + ASC, ASC, ASC, ASC, ASC, ASC, ASC, ASC, # 50 - 57 + ASC, ASC, ASC, OTH, OTH, OTH, OTH, OTH, # 58 - 5F + OTH, ASS, ASS, ASS, ASS, ASS, ASS, ASS, # 60 - 67 + ASS, ASS, ASS, ASS, ASS, ASS, ASS, ASS, # 68 - 6F + ASS, ASS, ASS, ASS, ASS, ASS, ASS, ASS, # 70 - 77 + ASS, ASS, ASS, OTH, OTH, OTH, OTH, OTH, # 78 - 7F + OTH, UDF, OTH, ASO, OTH, OTH, OTH, OTH, # 80 - 87 + OTH, OTH, ACO, OTH, ACO, UDF, ACO, UDF, # 88 - 8F + UDF, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 90 - 97 + OTH, OTH, ASO, OTH, ASO, UDF, ASO, ACO, # 98 - 9F + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # A0 - A7 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # A8 - AF + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # B0 - B7 + OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # B8 - BF + ACV, ACV, ACV, ACV, ACV, ACV, ACO, ACO, # C0 - C7 + ACV, ACV, ACV, ACV, ACV, ACV, ACV, ACV, # C8 - CF + ACO, ACO, ACV, ACV, ACV, ACV, ACV, OTH, # D0 - D7 + ACV, ACV, ACV, ACV, ACV, ACO, ACO, ACO, # D8 - DF + ASV, ASV, ASV, ASV, ASV, ASV, ASO, ASO, # E0 - E7 + ASV, ASV, ASV, ASV, ASV, ASV, ASV, ASV, # E8 - EF + ASO, ASO, ASV, ASV, ASV, ASV, ASV, OTH, # F0 - F7 + ASV, ASV, ASV, ASV, ASV, ASO, ASO, ASO, # F8 - FF +) + +# 0 : illegal +# 1 : very unlikely +# 2 : normal +# 3 : very likely +Latin1ClassModel = ( +# UDF OTH ASC ASS ACV ACO ASV ASO + 0, 0, 0, 0, 0, 0, 0, 0, # UDF + 0, 3, 3, 3, 3, 3, 3, 3, # OTH + 0, 3, 3, 3, 3, 3, 3, 3, # ASC + 0, 3, 3, 3, 1, 1, 3, 3, # ASS + 0, 3, 3, 3, 1, 2, 1, 2, # ACV + 0, 3, 3, 3, 3, 3, 3, 3, # ACO + 0, 3, 1, 3, 1, 1, 1, 3, # ASV + 0, 3, 1, 3, 1, 1, 3, 3, # ASO +) + + +class Latin1Prober(CharSetProber): + def __init__(self): + super(Latin1Prober, self).__init__() + self._last_char_class = None + self._freq_counter = None + self.reset() + + def reset(self): + self._last_char_class = OTH + self._freq_counter = [0] * FREQ_CAT_NUM + CharSetProber.reset(self) + + @property + def charset_name(self): + return "ISO-8859-1" + + @property + def language(self): + return "" + + def feed(self, byte_str): + byte_str = self.filter_with_english_letters(byte_str) + for c in byte_str: + char_class = Latin1_CharToClass[c] + freq = Latin1ClassModel[(self._last_char_class * CLASS_NUM) + + char_class] + if freq == 0: + self._state = ProbingState.NOT_ME + break + self._freq_counter[freq] += 1 + self._last_char_class = char_class + + return self.state + + def get_confidence(self): + if self.state == ProbingState.NOT_ME: + return 0.01 + + total = sum(self._freq_counter) + if total < 0.01: + confidence = 0.0 + else: + confidence = ((self._freq_counter[3] - self._freq_counter[1] * 20.0) + / total) + if confidence < 0.0: + confidence = 0.0 + # lower the confidence of latin1 so that other more accurate + # detector can take priority. + confidence = confidence * 0.73 + return confidence diff --git a/venv/lib/python3.8/site-packages/chardet/mbcharsetprober.py b/venv/lib/python3.8/site-packages/chardet/mbcharsetprober.py new file mode 100644 index 0000000..6256ecf --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/mbcharsetprober.py @@ -0,0 +1,91 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# Proofpoint, Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .charsetprober import CharSetProber +from .enums import ProbingState, MachineState + + +class MultiByteCharSetProber(CharSetProber): + """ + MultiByteCharSetProber + """ + + def __init__(self, lang_filter=None): + super(MultiByteCharSetProber, self).__init__(lang_filter=lang_filter) + self.distribution_analyzer = None + self.coding_sm = None + self._last_char = [0, 0] + + def reset(self): + super(MultiByteCharSetProber, self).reset() + if self.coding_sm: + self.coding_sm.reset() + if self.distribution_analyzer: + self.distribution_analyzer.reset() + self._last_char = [0, 0] + + @property + def charset_name(self): + raise NotImplementedError + + @property + def language(self): + raise NotImplementedError + + def feed(self, byte_str): + for i in range(len(byte_str)): + coding_state = self.coding_sm.next_state(byte_str[i]) + if coding_state == MachineState.ERROR: + self.logger.debug('%s %s prober hit error at byte %s', + self.charset_name, self.language, i) + self._state = ProbingState.NOT_ME + break + elif coding_state == MachineState.ITS_ME: + self._state = ProbingState.FOUND_IT + break + elif coding_state == MachineState.START: + char_len = self.coding_sm.get_current_charlen() + if i == 0: + self._last_char[1] = byte_str[0] + self.distribution_analyzer.feed(self._last_char, char_len) + else: + self.distribution_analyzer.feed(byte_str[i - 1:i + 1], + char_len) + + self._last_char[0] = byte_str[-1] + + if self.state == ProbingState.DETECTING: + if (self.distribution_analyzer.got_enough_data() and + (self.get_confidence() > self.SHORTCUT_THRESHOLD)): + self._state = ProbingState.FOUND_IT + + return self.state + + def get_confidence(self): + return self.distribution_analyzer.get_confidence() diff --git a/venv/lib/python3.8/site-packages/chardet/mbcsgroupprober.py b/venv/lib/python3.8/site-packages/chardet/mbcsgroupprober.py new file mode 100644 index 0000000..530abe7 --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/mbcsgroupprober.py @@ -0,0 +1,54 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# Proofpoint, Inc. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .charsetgroupprober import CharSetGroupProber +from .utf8prober import UTF8Prober +from .sjisprober import SJISProber +from .eucjpprober import EUCJPProber +from .gb2312prober import GB2312Prober +from .euckrprober import EUCKRProber +from .cp949prober import CP949Prober +from .big5prober import Big5Prober +from .euctwprober import EUCTWProber + + +class MBCSGroupProber(CharSetGroupProber): + def __init__(self, lang_filter=None): + super(MBCSGroupProber, self).__init__(lang_filter=lang_filter) + self.probers = [ + UTF8Prober(), + SJISProber(), + EUCJPProber(), + GB2312Prober(), + EUCKRProber(), + CP949Prober(), + Big5Prober(), + EUCTWProber() + ] + self.reset() diff --git a/venv/lib/python3.8/site-packages/chardet/mbcssm.py b/venv/lib/python3.8/site-packages/chardet/mbcssm.py new file mode 100644 index 0000000..8360d0f --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/mbcssm.py @@ -0,0 +1,572 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .enums import MachineState + +# BIG5 + +BIG5_CLS = ( + 1,1,1,1,1,1,1,1, # 00 - 07 #allow 0x00 as legal value + 1,1,1,1,1,1,0,0, # 08 - 0f + 1,1,1,1,1,1,1,1, # 10 - 17 + 1,1,1,0,1,1,1,1, # 18 - 1f + 1,1,1,1,1,1,1,1, # 20 - 27 + 1,1,1,1,1,1,1,1, # 28 - 2f + 1,1,1,1,1,1,1,1, # 30 - 37 + 1,1,1,1,1,1,1,1, # 38 - 3f + 2,2,2,2,2,2,2,2, # 40 - 47 + 2,2,2,2,2,2,2,2, # 48 - 4f + 2,2,2,2,2,2,2,2, # 50 - 57 + 2,2,2,2,2,2,2,2, # 58 - 5f + 2,2,2,2,2,2,2,2, # 60 - 67 + 2,2,2,2,2,2,2,2, # 68 - 6f + 2,2,2,2,2,2,2,2, # 70 - 77 + 2,2,2,2,2,2,2,1, # 78 - 7f + 4,4,4,4,4,4,4,4, # 80 - 87 + 4,4,4,4,4,4,4,4, # 88 - 8f + 4,4,4,4,4,4,4,4, # 90 - 97 + 4,4,4,4,4,4,4,4, # 98 - 9f + 4,3,3,3,3,3,3,3, # a0 - a7 + 3,3,3,3,3,3,3,3, # a8 - af + 3,3,3,3,3,3,3,3, # b0 - b7 + 3,3,3,3,3,3,3,3, # b8 - bf + 3,3,3,3,3,3,3,3, # c0 - c7 + 3,3,3,3,3,3,3,3, # c8 - cf + 3,3,3,3,3,3,3,3, # d0 - d7 + 3,3,3,3,3,3,3,3, # d8 - df + 3,3,3,3,3,3,3,3, # e0 - e7 + 3,3,3,3,3,3,3,3, # e8 - ef + 3,3,3,3,3,3,3,3, # f0 - f7 + 3,3,3,3,3,3,3,0 # f8 - ff +) + +BIG5_ST = ( + MachineState.ERROR,MachineState.START,MachineState.START, 3,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#00-07 + MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,#08-0f + MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START#10-17 +) + +BIG5_CHAR_LEN_TABLE = (0, 1, 1, 2, 0) + +BIG5_SM_MODEL = {'class_table': BIG5_CLS, + 'class_factor': 5, + 'state_table': BIG5_ST, + 'char_len_table': BIG5_CHAR_LEN_TABLE, + 'name': 'Big5'} + +# CP949 + +CP949_CLS = ( + 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,0,0, # 00 - 0f + 1,1,1,1,1,1,1,1, 1,1,1,0,1,1,1,1, # 10 - 1f + 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, # 20 - 2f + 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, # 30 - 3f + 1,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4, # 40 - 4f + 4,4,5,5,5,5,5,5, 5,5,5,1,1,1,1,1, # 50 - 5f + 1,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5, # 60 - 6f + 5,5,5,5,5,5,5,5, 5,5,5,1,1,1,1,1, # 70 - 7f + 0,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6, # 80 - 8f + 6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6, # 90 - 9f + 6,7,7,7,7,7,7,7, 7,7,7,7,7,8,8,8, # a0 - af + 7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7, # b0 - bf + 7,7,7,7,7,7,9,2, 2,3,2,2,2,2,2,2, # c0 - cf + 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, # d0 - df + 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, # e0 - ef + 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,0, # f0 - ff +) + +CP949_ST = ( +#cls= 0 1 2 3 4 5 6 7 8 9 # previous state = + MachineState.ERROR,MachineState.START, 3,MachineState.ERROR,MachineState.START,MachineState.START, 4, 5,MachineState.ERROR, 6, # MachineState.START + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, # MachineState.ERROR + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME, # MachineState.ITS_ME + MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START, # 3 + MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START, # 4 + MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START, # 5 + MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START, # 6 +) + +CP949_CHAR_LEN_TABLE = (0, 1, 2, 0, 1, 1, 2, 2, 0, 2) + +CP949_SM_MODEL = {'class_table': CP949_CLS, + 'class_factor': 10, + 'state_table': CP949_ST, + 'char_len_table': CP949_CHAR_LEN_TABLE, + 'name': 'CP949'} + +# EUC-JP + +EUCJP_CLS = ( + 4,4,4,4,4,4,4,4, # 00 - 07 + 4,4,4,4,4,4,5,5, # 08 - 0f + 4,4,4,4,4,4,4,4, # 10 - 17 + 4,4,4,5,4,4,4,4, # 18 - 1f + 4,4,4,4,4,4,4,4, # 20 - 27 + 4,4,4,4,4,4,4,4, # 28 - 2f + 4,4,4,4,4,4,4,4, # 30 - 37 + 4,4,4,4,4,4,4,4, # 38 - 3f + 4,4,4,4,4,4,4,4, # 40 - 47 + 4,4,4,4,4,4,4,4, # 48 - 4f + 4,4,4,4,4,4,4,4, # 50 - 57 + 4,4,4,4,4,4,4,4, # 58 - 5f + 4,4,4,4,4,4,4,4, # 60 - 67 + 4,4,4,4,4,4,4,4, # 68 - 6f + 4,4,4,4,4,4,4,4, # 70 - 77 + 4,4,4,4,4,4,4,4, # 78 - 7f + 5,5,5,5,5,5,5,5, # 80 - 87 + 5,5,5,5,5,5,1,3, # 88 - 8f + 5,5,5,5,5,5,5,5, # 90 - 97 + 5,5,5,5,5,5,5,5, # 98 - 9f + 5,2,2,2,2,2,2,2, # a0 - a7 + 2,2,2,2,2,2,2,2, # a8 - af + 2,2,2,2,2,2,2,2, # b0 - b7 + 2,2,2,2,2,2,2,2, # b8 - bf + 2,2,2,2,2,2,2,2, # c0 - c7 + 2,2,2,2,2,2,2,2, # c8 - cf + 2,2,2,2,2,2,2,2, # d0 - d7 + 2,2,2,2,2,2,2,2, # d8 - df + 0,0,0,0,0,0,0,0, # e0 - e7 + 0,0,0,0,0,0,0,0, # e8 - ef + 0,0,0,0,0,0,0,0, # f0 - f7 + 0,0,0,0,0,0,0,5 # f8 - ff +) + +EUCJP_ST = ( + 3, 4, 3, 5,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#00-07 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.START,MachineState.ERROR,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#10-17 + MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 3,MachineState.ERROR,#18-1f + 3,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START#20-27 +) + +EUCJP_CHAR_LEN_TABLE = (2, 2, 2, 3, 1, 0) + +EUCJP_SM_MODEL = {'class_table': EUCJP_CLS, + 'class_factor': 6, + 'state_table': EUCJP_ST, + 'char_len_table': EUCJP_CHAR_LEN_TABLE, + 'name': 'EUC-JP'} + +# EUC-KR + +EUCKR_CLS = ( + 1,1,1,1,1,1,1,1, # 00 - 07 + 1,1,1,1,1,1,0,0, # 08 - 0f + 1,1,1,1,1,1,1,1, # 10 - 17 + 1,1,1,0,1,1,1,1, # 18 - 1f + 1,1,1,1,1,1,1,1, # 20 - 27 + 1,1,1,1,1,1,1,1, # 28 - 2f + 1,1,1,1,1,1,1,1, # 30 - 37 + 1,1,1,1,1,1,1,1, # 38 - 3f + 1,1,1,1,1,1,1,1, # 40 - 47 + 1,1,1,1,1,1,1,1, # 48 - 4f + 1,1,1,1,1,1,1,1, # 50 - 57 + 1,1,1,1,1,1,1,1, # 58 - 5f + 1,1,1,1,1,1,1,1, # 60 - 67 + 1,1,1,1,1,1,1,1, # 68 - 6f + 1,1,1,1,1,1,1,1, # 70 - 77 + 1,1,1,1,1,1,1,1, # 78 - 7f + 0,0,0,0,0,0,0,0, # 80 - 87 + 0,0,0,0,0,0,0,0, # 88 - 8f + 0,0,0,0,0,0,0,0, # 90 - 97 + 0,0,0,0,0,0,0,0, # 98 - 9f + 0,2,2,2,2,2,2,2, # a0 - a7 + 2,2,2,2,2,3,3,3, # a8 - af + 2,2,2,2,2,2,2,2, # b0 - b7 + 2,2,2,2,2,2,2,2, # b8 - bf + 2,2,2,2,2,2,2,2, # c0 - c7 + 2,3,2,2,2,2,2,2, # c8 - cf + 2,2,2,2,2,2,2,2, # d0 - d7 + 2,2,2,2,2,2,2,2, # d8 - df + 2,2,2,2,2,2,2,2, # e0 - e7 + 2,2,2,2,2,2,2,2, # e8 - ef + 2,2,2,2,2,2,2,2, # f0 - f7 + 2,2,2,2,2,2,2,0 # f8 - ff +) + +EUCKR_ST = ( + MachineState.ERROR,MachineState.START, 3,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#00-07 + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START #08-0f +) + +EUCKR_CHAR_LEN_TABLE = (0, 1, 2, 0) + +EUCKR_SM_MODEL = {'class_table': EUCKR_CLS, + 'class_factor': 4, + 'state_table': EUCKR_ST, + 'char_len_table': EUCKR_CHAR_LEN_TABLE, + 'name': 'EUC-KR'} + +# EUC-TW + +EUCTW_CLS = ( + 2,2,2,2,2,2,2,2, # 00 - 07 + 2,2,2,2,2,2,0,0, # 08 - 0f + 2,2,2,2,2,2,2,2, # 10 - 17 + 2,2,2,0,2,2,2,2, # 18 - 1f + 2,2,2,2,2,2,2,2, # 20 - 27 + 2,2,2,2,2,2,2,2, # 28 - 2f + 2,2,2,2,2,2,2,2, # 30 - 37 + 2,2,2,2,2,2,2,2, # 38 - 3f + 2,2,2,2,2,2,2,2, # 40 - 47 + 2,2,2,2,2,2,2,2, # 48 - 4f + 2,2,2,2,2,2,2,2, # 50 - 57 + 2,2,2,2,2,2,2,2, # 58 - 5f + 2,2,2,2,2,2,2,2, # 60 - 67 + 2,2,2,2,2,2,2,2, # 68 - 6f + 2,2,2,2,2,2,2,2, # 70 - 77 + 2,2,2,2,2,2,2,2, # 78 - 7f + 0,0,0,0,0,0,0,0, # 80 - 87 + 0,0,0,0,0,0,6,0, # 88 - 8f + 0,0,0,0,0,0,0,0, # 90 - 97 + 0,0,0,0,0,0,0,0, # 98 - 9f + 0,3,4,4,4,4,4,4, # a0 - a7 + 5,5,1,1,1,1,1,1, # a8 - af + 1,1,1,1,1,1,1,1, # b0 - b7 + 1,1,1,1,1,1,1,1, # b8 - bf + 1,1,3,1,3,3,3,3, # c0 - c7 + 3,3,3,3,3,3,3,3, # c8 - cf + 3,3,3,3,3,3,3,3, # d0 - d7 + 3,3,3,3,3,3,3,3, # d8 - df + 3,3,3,3,3,3,3,3, # e0 - e7 + 3,3,3,3,3,3,3,3, # e8 - ef + 3,3,3,3,3,3,3,3, # f0 - f7 + 3,3,3,3,3,3,3,0 # f8 - ff +) + +EUCTW_ST = ( + MachineState.ERROR,MachineState.ERROR,MachineState.START, 3, 3, 3, 4,MachineState.ERROR,#00-07 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.START,MachineState.ERROR,#10-17 + MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#18-1f + 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.ERROR,MachineState.START,MachineState.START,#20-27 + MachineState.START,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START #28-2f +) + +EUCTW_CHAR_LEN_TABLE = (0, 0, 1, 2, 2, 2, 3) + +EUCTW_SM_MODEL = {'class_table': EUCTW_CLS, + 'class_factor': 7, + 'state_table': EUCTW_ST, + 'char_len_table': EUCTW_CHAR_LEN_TABLE, + 'name': 'x-euc-tw'} + +# GB2312 + +GB2312_CLS = ( + 1,1,1,1,1,1,1,1, # 00 - 07 + 1,1,1,1,1,1,0,0, # 08 - 0f + 1,1,1,1,1,1,1,1, # 10 - 17 + 1,1,1,0,1,1,1,1, # 18 - 1f + 1,1,1,1,1,1,1,1, # 20 - 27 + 1,1,1,1,1,1,1,1, # 28 - 2f + 3,3,3,3,3,3,3,3, # 30 - 37 + 3,3,1,1,1,1,1,1, # 38 - 3f + 2,2,2,2,2,2,2,2, # 40 - 47 + 2,2,2,2,2,2,2,2, # 48 - 4f + 2,2,2,2,2,2,2,2, # 50 - 57 + 2,2,2,2,2,2,2,2, # 58 - 5f + 2,2,2,2,2,2,2,2, # 60 - 67 + 2,2,2,2,2,2,2,2, # 68 - 6f + 2,2,2,2,2,2,2,2, # 70 - 77 + 2,2,2,2,2,2,2,4, # 78 - 7f + 5,6,6,6,6,6,6,6, # 80 - 87 + 6,6,6,6,6,6,6,6, # 88 - 8f + 6,6,6,6,6,6,6,6, # 90 - 97 + 6,6,6,6,6,6,6,6, # 98 - 9f + 6,6,6,6,6,6,6,6, # a0 - a7 + 6,6,6,6,6,6,6,6, # a8 - af + 6,6,6,6,6,6,6,6, # b0 - b7 + 6,6,6,6,6,6,6,6, # b8 - bf + 6,6,6,6,6,6,6,6, # c0 - c7 + 6,6,6,6,6,6,6,6, # c8 - cf + 6,6,6,6,6,6,6,6, # d0 - d7 + 6,6,6,6,6,6,6,6, # d8 - df + 6,6,6,6,6,6,6,6, # e0 - e7 + 6,6,6,6,6,6,6,6, # e8 - ef + 6,6,6,6,6,6,6,6, # f0 - f7 + 6,6,6,6,6,6,6,0 # f8 - ff +) + +GB2312_ST = ( + MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START, 3,MachineState.ERROR,#00-07 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.START,#10-17 + 4,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#18-1f + MachineState.ERROR,MachineState.ERROR, 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,#20-27 + MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START #28-2f +) + +# To be accurate, the length of class 6 can be either 2 or 4. +# But it is not necessary to discriminate between the two since +# it is used for frequency analysis only, and we are validating +# each code range there as well. So it is safe to set it to be +# 2 here. +GB2312_CHAR_LEN_TABLE = (0, 1, 1, 1, 1, 1, 2) + +GB2312_SM_MODEL = {'class_table': GB2312_CLS, + 'class_factor': 7, + 'state_table': GB2312_ST, + 'char_len_table': GB2312_CHAR_LEN_TABLE, + 'name': 'GB2312'} + +# Shift_JIS + +SJIS_CLS = ( + 1,1,1,1,1,1,1,1, # 00 - 07 + 1,1,1,1,1,1,0,0, # 08 - 0f + 1,1,1,1,1,1,1,1, # 10 - 17 + 1,1,1,0,1,1,1,1, # 18 - 1f + 1,1,1,1,1,1,1,1, # 20 - 27 + 1,1,1,1,1,1,1,1, # 28 - 2f + 1,1,1,1,1,1,1,1, # 30 - 37 + 1,1,1,1,1,1,1,1, # 38 - 3f + 2,2,2,2,2,2,2,2, # 40 - 47 + 2,2,2,2,2,2,2,2, # 48 - 4f + 2,2,2,2,2,2,2,2, # 50 - 57 + 2,2,2,2,2,2,2,2, # 58 - 5f + 2,2,2,2,2,2,2,2, # 60 - 67 + 2,2,2,2,2,2,2,2, # 68 - 6f + 2,2,2,2,2,2,2,2, # 70 - 77 + 2,2,2,2,2,2,2,1, # 78 - 7f + 3,3,3,3,3,2,2,3, # 80 - 87 + 3,3,3,3,3,3,3,3, # 88 - 8f + 3,3,3,3,3,3,3,3, # 90 - 97 + 3,3,3,3,3,3,3,3, # 98 - 9f + #0xa0 is illegal in sjis encoding, but some pages does + #contain such byte. We need to be more error forgiven. + 2,2,2,2,2,2,2,2, # a0 - a7 + 2,2,2,2,2,2,2,2, # a8 - af + 2,2,2,2,2,2,2,2, # b0 - b7 + 2,2,2,2,2,2,2,2, # b8 - bf + 2,2,2,2,2,2,2,2, # c0 - c7 + 2,2,2,2,2,2,2,2, # c8 - cf + 2,2,2,2,2,2,2,2, # d0 - d7 + 2,2,2,2,2,2,2,2, # d8 - df + 3,3,3,3,3,3,3,3, # e0 - e7 + 3,3,3,3,3,4,4,4, # e8 - ef + 3,3,3,3,3,3,3,3, # f0 - f7 + 3,3,3,3,3,0,0,0) # f8 - ff + + +SJIS_ST = ( + MachineState.ERROR,MachineState.START,MachineState.START, 3,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#00-07 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START #10-17 +) + +SJIS_CHAR_LEN_TABLE = (0, 1, 1, 2, 0, 0) + +SJIS_SM_MODEL = {'class_table': SJIS_CLS, + 'class_factor': 6, + 'state_table': SJIS_ST, + 'char_len_table': SJIS_CHAR_LEN_TABLE, + 'name': 'Shift_JIS'} + +# UCS2-BE + +UCS2BE_CLS = ( + 0,0,0,0,0,0,0,0, # 00 - 07 + 0,0,1,0,0,2,0,0, # 08 - 0f + 0,0,0,0,0,0,0,0, # 10 - 17 + 0,0,0,3,0,0,0,0, # 18 - 1f + 0,0,0,0,0,0,0,0, # 20 - 27 + 0,3,3,3,3,3,0,0, # 28 - 2f + 0,0,0,0,0,0,0,0, # 30 - 37 + 0,0,0,0,0,0,0,0, # 38 - 3f + 0,0,0,0,0,0,0,0, # 40 - 47 + 0,0,0,0,0,0,0,0, # 48 - 4f + 0,0,0,0,0,0,0,0, # 50 - 57 + 0,0,0,0,0,0,0,0, # 58 - 5f + 0,0,0,0,0,0,0,0, # 60 - 67 + 0,0,0,0,0,0,0,0, # 68 - 6f + 0,0,0,0,0,0,0,0, # 70 - 77 + 0,0,0,0,0,0,0,0, # 78 - 7f + 0,0,0,0,0,0,0,0, # 80 - 87 + 0,0,0,0,0,0,0,0, # 88 - 8f + 0,0,0,0,0,0,0,0, # 90 - 97 + 0,0,0,0,0,0,0,0, # 98 - 9f + 0,0,0,0,0,0,0,0, # a0 - a7 + 0,0,0,0,0,0,0,0, # a8 - af + 0,0,0,0,0,0,0,0, # b0 - b7 + 0,0,0,0,0,0,0,0, # b8 - bf + 0,0,0,0,0,0,0,0, # c0 - c7 + 0,0,0,0,0,0,0,0, # c8 - cf + 0,0,0,0,0,0,0,0, # d0 - d7 + 0,0,0,0,0,0,0,0, # d8 - df + 0,0,0,0,0,0,0,0, # e0 - e7 + 0,0,0,0,0,0,0,0, # e8 - ef + 0,0,0,0,0,0,0,0, # f0 - f7 + 0,0,0,0,0,0,4,5 # f8 - ff +) + +UCS2BE_ST = ( + 5, 7, 7,MachineState.ERROR, 4, 3,MachineState.ERROR,MachineState.ERROR,#00-07 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f + MachineState.ITS_ME,MachineState.ITS_ME, 6, 6, 6, 6,MachineState.ERROR,MachineState.ERROR,#10-17 + 6, 6, 6, 6, 6,MachineState.ITS_ME, 6, 6,#18-1f + 6, 6, 6, 6, 5, 7, 7,MachineState.ERROR,#20-27 + 5, 8, 6, 6,MachineState.ERROR, 6, 6, 6,#28-2f + 6, 6, 6, 6,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START #30-37 +) + +UCS2BE_CHAR_LEN_TABLE = (2, 2, 2, 0, 2, 2) + +UCS2BE_SM_MODEL = {'class_table': UCS2BE_CLS, + 'class_factor': 6, + 'state_table': UCS2BE_ST, + 'char_len_table': UCS2BE_CHAR_LEN_TABLE, + 'name': 'UTF-16BE'} + +# UCS2-LE + +UCS2LE_CLS = ( + 0,0,0,0,0,0,0,0, # 00 - 07 + 0,0,1,0,0,2,0,0, # 08 - 0f + 0,0,0,0,0,0,0,0, # 10 - 17 + 0,0,0,3,0,0,0,0, # 18 - 1f + 0,0,0,0,0,0,0,0, # 20 - 27 + 0,3,3,3,3,3,0,0, # 28 - 2f + 0,0,0,0,0,0,0,0, # 30 - 37 + 0,0,0,0,0,0,0,0, # 38 - 3f + 0,0,0,0,0,0,0,0, # 40 - 47 + 0,0,0,0,0,0,0,0, # 48 - 4f + 0,0,0,0,0,0,0,0, # 50 - 57 + 0,0,0,0,0,0,0,0, # 58 - 5f + 0,0,0,0,0,0,0,0, # 60 - 67 + 0,0,0,0,0,0,0,0, # 68 - 6f + 0,0,0,0,0,0,0,0, # 70 - 77 + 0,0,0,0,0,0,0,0, # 78 - 7f + 0,0,0,0,0,0,0,0, # 80 - 87 + 0,0,0,0,0,0,0,0, # 88 - 8f + 0,0,0,0,0,0,0,0, # 90 - 97 + 0,0,0,0,0,0,0,0, # 98 - 9f + 0,0,0,0,0,0,0,0, # a0 - a7 + 0,0,0,0,0,0,0,0, # a8 - af + 0,0,0,0,0,0,0,0, # b0 - b7 + 0,0,0,0,0,0,0,0, # b8 - bf + 0,0,0,0,0,0,0,0, # c0 - c7 + 0,0,0,0,0,0,0,0, # c8 - cf + 0,0,0,0,0,0,0,0, # d0 - d7 + 0,0,0,0,0,0,0,0, # d8 - df + 0,0,0,0,0,0,0,0, # e0 - e7 + 0,0,0,0,0,0,0,0, # e8 - ef + 0,0,0,0,0,0,0,0, # f0 - f7 + 0,0,0,0,0,0,4,5 # f8 - ff +) + +UCS2LE_ST = ( + 6, 6, 7, 6, 4, 3,MachineState.ERROR,MachineState.ERROR,#00-07 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f + MachineState.ITS_ME,MachineState.ITS_ME, 5, 5, 5,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,#10-17 + 5, 5, 5,MachineState.ERROR, 5,MachineState.ERROR, 6, 6,#18-1f + 7, 6, 8, 8, 5, 5, 5,MachineState.ERROR,#20-27 + 5, 5, 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 5, 5,#28-2f + 5, 5, 5,MachineState.ERROR, 5,MachineState.ERROR,MachineState.START,MachineState.START #30-37 +) + +UCS2LE_CHAR_LEN_TABLE = (2, 2, 2, 2, 2, 2) + +UCS2LE_SM_MODEL = {'class_table': UCS2LE_CLS, + 'class_factor': 6, + 'state_table': UCS2LE_ST, + 'char_len_table': UCS2LE_CHAR_LEN_TABLE, + 'name': 'UTF-16LE'} + +# UTF-8 + +UTF8_CLS = ( + 1,1,1,1,1,1,1,1, # 00 - 07 #allow 0x00 as a legal value + 1,1,1,1,1,1,0,0, # 08 - 0f + 1,1,1,1,1,1,1,1, # 10 - 17 + 1,1,1,0,1,1,1,1, # 18 - 1f + 1,1,1,1,1,1,1,1, # 20 - 27 + 1,1,1,1,1,1,1,1, # 28 - 2f + 1,1,1,1,1,1,1,1, # 30 - 37 + 1,1,1,1,1,1,1,1, # 38 - 3f + 1,1,1,1,1,1,1,1, # 40 - 47 + 1,1,1,1,1,1,1,1, # 48 - 4f + 1,1,1,1,1,1,1,1, # 50 - 57 + 1,1,1,1,1,1,1,1, # 58 - 5f + 1,1,1,1,1,1,1,1, # 60 - 67 + 1,1,1,1,1,1,1,1, # 68 - 6f + 1,1,1,1,1,1,1,1, # 70 - 77 + 1,1,1,1,1,1,1,1, # 78 - 7f + 2,2,2,2,3,3,3,3, # 80 - 87 + 4,4,4,4,4,4,4,4, # 88 - 8f + 4,4,4,4,4,4,4,4, # 90 - 97 + 4,4,4,4,4,4,4,4, # 98 - 9f + 5,5,5,5,5,5,5,5, # a0 - a7 + 5,5,5,5,5,5,5,5, # a8 - af + 5,5,5,5,5,5,5,5, # b0 - b7 + 5,5,5,5,5,5,5,5, # b8 - bf + 0,0,6,6,6,6,6,6, # c0 - c7 + 6,6,6,6,6,6,6,6, # c8 - cf + 6,6,6,6,6,6,6,6, # d0 - d7 + 6,6,6,6,6,6,6,6, # d8 - df + 7,8,8,8,8,8,8,8, # e0 - e7 + 8,8,8,8,8,9,8,8, # e8 - ef + 10,11,11,11,11,11,11,11, # f0 - f7 + 12,13,13,13,14,15,0,0 # f8 - ff +) + +UTF8_ST = ( + MachineState.ERROR,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 12, 10,#00-07 + 9, 11, 8, 7, 6, 5, 4, 3,#08-0f + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#10-17 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#18-1f + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#20-27 + MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#28-2f + MachineState.ERROR,MachineState.ERROR, 5, 5, 5, 5,MachineState.ERROR,MachineState.ERROR,#30-37 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#38-3f + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 5, 5, 5,MachineState.ERROR,MachineState.ERROR,#40-47 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#48-4f + MachineState.ERROR,MachineState.ERROR, 7, 7, 7, 7,MachineState.ERROR,MachineState.ERROR,#50-57 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#58-5f + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 7, 7,MachineState.ERROR,MachineState.ERROR,#60-67 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#68-6f + MachineState.ERROR,MachineState.ERROR, 9, 9, 9, 9,MachineState.ERROR,MachineState.ERROR,#70-77 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#78-7f + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 9,MachineState.ERROR,MachineState.ERROR,#80-87 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#88-8f + MachineState.ERROR,MachineState.ERROR, 12, 12, 12, 12,MachineState.ERROR,MachineState.ERROR,#90-97 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#98-9f + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 12,MachineState.ERROR,MachineState.ERROR,#a0-a7 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#a8-af + MachineState.ERROR,MachineState.ERROR, 12, 12, 12,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#b0-b7 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#b8-bf + MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,#c0-c7 + MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR #c8-cf +) + +UTF8_CHAR_LEN_TABLE = (0, 1, 0, 0, 0, 0, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6) + +UTF8_SM_MODEL = {'class_table': UTF8_CLS, + 'class_factor': 16, + 'state_table': UTF8_ST, + 'char_len_table': UTF8_CHAR_LEN_TABLE, + 'name': 'UTF-8'} diff --git a/venv/lib/python3.8/site-packages/chardet/metadata/__init__.py b/venv/lib/python3.8/site-packages/chardet/metadata/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.8/site-packages/chardet/metadata/languages.py b/venv/lib/python3.8/site-packages/chardet/metadata/languages.py new file mode 100644 index 0000000..3237d5a --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/metadata/languages.py @@ -0,0 +1,310 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +""" +Metadata about languages used by our model training code for our +SingleByteCharSetProbers. Could be used for other things in the future. + +This code is based on the language metadata from the uchardet project. +""" +from __future__ import absolute_import, print_function + +from string import ascii_letters + + +# TODO: Add Ukranian (KOI8-U) + +class Language(object): + """Metadata about a language useful for training models + + :ivar name: The human name for the language, in English. + :type name: str + :ivar iso_code: 2-letter ISO 639-1 if possible, 3-letter ISO code otherwise, + or use another catalog as a last resort. + :type iso_code: str + :ivar use_ascii: Whether or not ASCII letters should be included in trained + models. + :type use_ascii: bool + :ivar charsets: The charsets we want to support and create data for. + :type charsets: list of str + :ivar alphabet: The characters in the language's alphabet. If `use_ascii` is + `True`, you only need to add those not in the ASCII set. + :type alphabet: str + :ivar wiki_start_pages: The Wikipedia pages to start from if we're crawling + Wikipedia for training data. + :type wiki_start_pages: list of str + """ + def __init__(self, name=None, iso_code=None, use_ascii=True, charsets=None, + alphabet=None, wiki_start_pages=None): + super(Language, self).__init__() + self.name = name + self.iso_code = iso_code + self.use_ascii = use_ascii + self.charsets = charsets + if self.use_ascii: + if alphabet: + alphabet += ascii_letters + else: + alphabet = ascii_letters + elif not alphabet: + raise ValueError('Must supply alphabet if use_ascii is False') + self.alphabet = ''.join(sorted(set(alphabet))) if alphabet else None + self.wiki_start_pages = wiki_start_pages + + def __repr__(self): + return '{}({})'.format(self.__class__.__name__, + ', '.join('{}={!r}'.format(k, v) + for k, v in self.__dict__.items() + if not k.startswith('_'))) + + +LANGUAGES = {'Arabic': Language(name='Arabic', + iso_code='ar', + use_ascii=False, + # We only support encodings that use isolated + # forms, because the current recommendation is + # that the rendering system handles presentation + # forms. This means we purposefully skip IBM864. + charsets=['ISO-8859-6', 'WINDOWS-1256', + 'CP720', 'CP864'], + alphabet=u'ءآأؤإئابةتثجحخدذرزسشصضطظعغػؼؽؾؿـفقكلمنهوىيًٌٍَُِّ', + wiki_start_pages=[u'الصفحة_الرئيسية']), + 'Belarusian': Language(name='Belarusian', + iso_code='be', + use_ascii=False, + charsets=['ISO-8859-5', 'WINDOWS-1251', + 'IBM866', 'MacCyrillic'], + alphabet=(u'АБВГДЕЁЖЗІЙКЛМНОПРСТУЎФХЦЧШЫЬЭЮЯ' + u'абвгдеёжзійклмнопрстуўфхцчшыьэюяʼ'), + wiki_start_pages=[u'Галоўная_старонка']), + 'Bulgarian': Language(name='Bulgarian', + iso_code='bg', + use_ascii=False, + charsets=['ISO-8859-5', 'WINDOWS-1251', + 'IBM855'], + alphabet=(u'АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЬЮЯ' + u'абвгдежзийклмнопрстуфхцчшщъьюя'), + wiki_start_pages=[u'Начална_страница']), + 'Czech': Language(name='Czech', + iso_code='cz', + use_ascii=True, + charsets=['ISO-8859-2', 'WINDOWS-1250'], + alphabet=u'áčďéěíňóřšťúůýžÁČĎÉĚÍŇÓŘŠŤÚŮÝŽ', + wiki_start_pages=[u'Hlavní_strana']), + 'Danish': Language(name='Danish', + iso_code='da', + use_ascii=True, + charsets=['ISO-8859-1', 'ISO-8859-15', + 'WINDOWS-1252'], + alphabet=u'æøåÆØÅ', + wiki_start_pages=[u'Forside']), + 'German': Language(name='German', + iso_code='de', + use_ascii=True, + charsets=['ISO-8859-1', 'WINDOWS-1252'], + alphabet=u'äöüßÄÖÜ', + wiki_start_pages=[u'Wikipedia:Hauptseite']), + 'Greek': Language(name='Greek', + iso_code='el', + use_ascii=False, + charsets=['ISO-8859-7', 'WINDOWS-1253'], + alphabet=(u'αβγδεζηθικλμνξοπρσςτυφχψωάέήίόύώ' + u'ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΣΤΥΦΧΨΩΆΈΉΊΌΎΏ'), + wiki_start_pages=[u'Πύλη:Κύρια']), + 'English': Language(name='English', + iso_code='en', + use_ascii=True, + charsets=['ISO-8859-1', 'WINDOWS-1252'], + wiki_start_pages=[u'Main_Page']), + 'Esperanto': Language(name='Esperanto', + iso_code='eo', + # Q, W, X, and Y not used at all + use_ascii=False, + charsets=['ISO-8859-3'], + alphabet=(u'abcĉdefgĝhĥijĵklmnoprsŝtuŭvz' + u'ABCĈDEFGĜHĤIJĴKLMNOPRSŜTUŬVZ'), + wiki_start_pages=[u'Vikipedio:Ĉefpaĝo']), + 'Spanish': Language(name='Spanish', + iso_code='es', + use_ascii=True, + charsets=['ISO-8859-1', 'ISO-8859-15', + 'WINDOWS-1252'], + alphabet=u'ñáéíóúüÑÁÉÍÓÚÜ', + wiki_start_pages=[u'Wikipedia:Portada']), + 'Estonian': Language(name='Estonian', + iso_code='et', + use_ascii=False, + charsets=['ISO-8859-4', 'ISO-8859-13', + 'WINDOWS-1257'], + # C, F, Š, Q, W, X, Y, Z, Ž are only for + # loanwords + alphabet=(u'ABDEGHIJKLMNOPRSTUVÕÄÖÜ' + u'abdeghijklmnoprstuvõäöü'), + wiki_start_pages=[u'Esileht']), + 'Finnish': Language(name='Finnish', + iso_code='fi', + use_ascii=True, + charsets=['ISO-8859-1', 'ISO-8859-15', + 'WINDOWS-1252'], + alphabet=u'ÅÄÖŠŽåäöšž', + wiki_start_pages=[u'Wikipedia:Etusivu']), + 'French': Language(name='French', + iso_code='fr', + use_ascii=True, + charsets=['ISO-8859-1', 'ISO-8859-15', + 'WINDOWS-1252'], + alphabet=u'œàâçèéîïùûêŒÀÂÇÈÉÎÏÙÛÊ', + wiki_start_pages=[u'Wikipédia:Accueil_principal', + u'Bœuf (animal)']), + 'Hebrew': Language(name='Hebrew', + iso_code='he', + use_ascii=False, + charsets=['ISO-8859-8', 'WINDOWS-1255'], + alphabet=u'אבגדהוזחטיךכלםמןנסעףפץצקרשתװױײ', + wiki_start_pages=[u'עמוד_ראשי']), + 'Croatian': Language(name='Croatian', + iso_code='hr', + # Q, W, X, Y are only used for foreign words. + use_ascii=False, + charsets=['ISO-8859-2', 'WINDOWS-1250'], + alphabet=(u'abcčćdđefghijklmnoprsštuvzž' + u'ABCČĆDĐEFGHIJKLMNOPRSŠTUVZŽ'), + wiki_start_pages=[u'Glavna_stranica']), + 'Hungarian': Language(name='Hungarian', + iso_code='hu', + # Q, W, X, Y are only used for foreign words. + use_ascii=False, + charsets=['ISO-8859-2', 'WINDOWS-1250'], + alphabet=(u'abcdefghijklmnoprstuvzáéíóöőúüű' + u'ABCDEFGHIJKLMNOPRSTUVZÁÉÍÓÖŐÚÜŰ'), + wiki_start_pages=[u'Kezdőlap']), + 'Italian': Language(name='Italian', + iso_code='it', + use_ascii=True, + charsets=['ISO-8859-1', 'ISO-8859-15', + 'WINDOWS-1252'], + alphabet=u'ÀÈÉÌÒÓÙàèéìòóù', + wiki_start_pages=[u'Pagina_principale']), + 'Lithuanian': Language(name='Lithuanian', + iso_code='lt', + use_ascii=False, + charsets=['ISO-8859-13', 'WINDOWS-1257', + 'ISO-8859-4'], + # Q, W, and X not used at all + alphabet=(u'AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ' + u'aąbcčdeęėfghiįyjklmnoprsštuųūvzž'), + wiki_start_pages=[u'Pagrindinis_puslapis']), + 'Latvian': Language(name='Latvian', + iso_code='lv', + use_ascii=False, + charsets=['ISO-8859-13', 'WINDOWS-1257', + 'ISO-8859-4'], + # Q, W, X, Y are only for loanwords + alphabet=(u'AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽ' + u'aābcčdeēfgģhiījkķlļmnņoprsštuūvzž'), + wiki_start_pages=[u'Sākumlapa']), + 'Macedonian': Language(name='Macedonian', + iso_code='mk', + use_ascii=False, + charsets=['ISO-8859-5', 'WINDOWS-1251', + 'MacCyrillic', 'IBM855'], + alphabet=(u'АБВГДЃЕЖЗЅИЈКЛЉМНЊОПРСТЌУФХЦЧЏШ' + u'абвгдѓежзѕијклљмнњопрстќуфхцчџш'), + wiki_start_pages=[u'Главна_страница']), + 'Dutch': Language(name='Dutch', + iso_code='nl', + use_ascii=True, + charsets=['ISO-8859-1', 'WINDOWS-1252'], + wiki_start_pages=[u'Hoofdpagina']), + 'Polish': Language(name='Polish', + iso_code='pl', + # Q and X are only used for foreign words. + use_ascii=False, + charsets=['ISO-8859-2', 'WINDOWS-1250'], + alphabet=(u'AĄBCĆDEĘFGHIJKLŁMNŃOÓPRSŚTUWYZŹŻ' + u'aąbcćdeęfghijklłmnńoóprsśtuwyzźż'), + wiki_start_pages=[u'Wikipedia:Strona_główna']), + 'Portuguese': Language(name='Portuguese', + iso_code='pt', + use_ascii=True, + charsets=['ISO-8859-1', 'ISO-8859-15', + 'WINDOWS-1252'], + alphabet=u'ÁÂÃÀÇÉÊÍÓÔÕÚáâãàçéêíóôõú', + wiki_start_pages=[u'Wikipédia:Página_principal']), + 'Romanian': Language(name='Romanian', + iso_code='ro', + use_ascii=True, + charsets=['ISO-8859-2', 'WINDOWS-1250'], + alphabet=u'ăâîșțĂÂÎȘȚ', + wiki_start_pages=[u'Pagina_principală']), + 'Russian': Language(name='Russian', + iso_code='ru', + use_ascii=False, + charsets=['ISO-8859-5', 'WINDOWS-1251', + 'KOI8-R', 'MacCyrillic', 'IBM866', + 'IBM855'], + alphabet=(u'абвгдеёжзийклмнопрстуфхцчшщъыьэюя' + u'АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ'), + wiki_start_pages=[u'Заглавная_страница']), + 'Slovak': Language(name='Slovak', + iso_code='sk', + use_ascii=True, + charsets=['ISO-8859-2', 'WINDOWS-1250'], + alphabet=u'áäčďéíĺľňóôŕšťúýžÁÄČĎÉÍĹĽŇÓÔŔŠŤÚÝŽ', + wiki_start_pages=[u'Hlavná_stránka']), + 'Slovene': Language(name='Slovene', + iso_code='sl', + # Q, W, X, Y are only used for foreign words. + use_ascii=False, + charsets=['ISO-8859-2', 'WINDOWS-1250'], + alphabet=(u'abcčdefghijklmnoprsštuvzž' + u'ABCČDEFGHIJKLMNOPRSŠTUVZŽ'), + wiki_start_pages=[u'Glavna_stran']), + # Serbian can be written in both Latin and Cyrillic, but there's no + # simple way to get the Latin alphabet pages from Wikipedia through + # the API, so for now we just support Cyrillic. + 'Serbian': Language(name='Serbian', + iso_code='sr', + alphabet=(u'АБВГДЂЕЖЗИЈКЛЉМНЊОПРСТЋУФХЦЧЏШ' + u'абвгдђежзијклљмнњопрстћуфхцчџш'), + charsets=['ISO-8859-5', 'WINDOWS-1251', + 'MacCyrillic', 'IBM855'], + wiki_start_pages=[u'Главна_страна']), + 'Thai': Language(name='Thai', + iso_code='th', + use_ascii=False, + charsets=['ISO-8859-11', 'TIS-620', 'CP874'], + alphabet=u'กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛', + wiki_start_pages=[u'หน้าหลัก']), + 'Turkish': Language(name='Turkish', + iso_code='tr', + # Q, W, and X are not used by Turkish + use_ascii=False, + charsets=['ISO-8859-3', 'ISO-8859-9', + 'WINDOWS-1254'], + alphabet=(u'abcçdefgğhıijklmnoöprsştuüvyzâîû' + u'ABCÇDEFGĞHIİJKLMNOÖPRSŞTUÜVYZÂÎÛ'), + wiki_start_pages=[u'Ana_Sayfa']), + 'Vietnamese': Language(name='Vietnamese', + iso_code='vi', + use_ascii=False, + # Windows-1258 is the only common 8-bit + # Vietnamese encoding supported by Python. + # From Wikipedia: + # For systems that lack support for Unicode, + # dozens of 8-bit Vietnamese code pages are + # available.[1] The most common are VISCII + # (TCVN 5712:1993), VPS, and Windows-1258.[3] + # Where ASCII is required, such as when + # ensuring readability in plain text e-mail, + # Vietnamese letters are often encoded + # according to Vietnamese Quoted-Readable + # (VIQR) or VSCII Mnemonic (VSCII-MNEM),[4] + # though usage of either variable-width + # scheme has declined dramatically following + # the adoption of Unicode on the World Wide + # Web. + charsets=['WINDOWS-1258'], + alphabet=(u'aăâbcdđeêghiklmnoôơpqrstuưvxy' + u'AĂÂBCDĐEÊGHIKLMNOÔƠPQRSTUƯVXY'), + wiki_start_pages=[u'Chữ_Quốc_ngữ']), + } diff --git a/venv/lib/python3.8/site-packages/chardet/sbcharsetprober.py b/venv/lib/python3.8/site-packages/chardet/sbcharsetprober.py new file mode 100644 index 0000000..46ba835 --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/sbcharsetprober.py @@ -0,0 +1,145 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from collections import namedtuple + +from .charsetprober import CharSetProber +from .enums import CharacterCategory, ProbingState, SequenceLikelihood + + +SingleByteCharSetModel = namedtuple('SingleByteCharSetModel', + ['charset_name', + 'language', + 'char_to_order_map', + 'language_model', + 'typical_positive_ratio', + 'keep_ascii_letters', + 'alphabet']) + + +class SingleByteCharSetProber(CharSetProber): + SAMPLE_SIZE = 64 + SB_ENOUGH_REL_THRESHOLD = 1024 # 0.25 * SAMPLE_SIZE^2 + POSITIVE_SHORTCUT_THRESHOLD = 0.95 + NEGATIVE_SHORTCUT_THRESHOLD = 0.05 + + def __init__(self, model, reversed=False, name_prober=None): + super(SingleByteCharSetProber, self).__init__() + self._model = model + # TRUE if we need to reverse every pair in the model lookup + self._reversed = reversed + # Optional auxiliary prober for name decision + self._name_prober = name_prober + self._last_order = None + self._seq_counters = None + self._total_seqs = None + self._total_char = None + self._freq_char = None + self.reset() + + def reset(self): + super(SingleByteCharSetProber, self).reset() + # char order of last character + self._last_order = 255 + self._seq_counters = [0] * SequenceLikelihood.get_num_categories() + self._total_seqs = 0 + self._total_char = 0 + # characters that fall in our sampling range + self._freq_char = 0 + + @property + def charset_name(self): + if self._name_prober: + return self._name_prober.charset_name + else: + return self._model.charset_name + + @property + def language(self): + if self._name_prober: + return self._name_prober.language + else: + return self._model.language + + def feed(self, byte_str): + # TODO: Make filter_international_words keep things in self.alphabet + if not self._model.keep_ascii_letters: + byte_str = self.filter_international_words(byte_str) + if not byte_str: + return self.state + char_to_order_map = self._model.char_to_order_map + language_model = self._model.language_model + for char in byte_str: + order = char_to_order_map.get(char, CharacterCategory.UNDEFINED) + # XXX: This was SYMBOL_CAT_ORDER before, with a value of 250, but + # CharacterCategory.SYMBOL is actually 253, so we use CONTROL + # to make it closer to the original intent. The only difference + # is whether or not we count digits and control characters for + # _total_char purposes. + if order < CharacterCategory.CONTROL: + self._total_char += 1 + # TODO: Follow uchardet's lead and discount confidence for frequent + # control characters. + # See https://github.com/BYVoid/uchardet/commit/55b4f23971db61 + if order < self.SAMPLE_SIZE: + self._freq_char += 1 + if self._last_order < self.SAMPLE_SIZE: + self._total_seqs += 1 + if not self._reversed: + lm_cat = language_model[self._last_order][order] + else: + lm_cat = language_model[order][self._last_order] + self._seq_counters[lm_cat] += 1 + self._last_order = order + + charset_name = self._model.charset_name + if self.state == ProbingState.DETECTING: + if self._total_seqs > self.SB_ENOUGH_REL_THRESHOLD: + confidence = self.get_confidence() + if confidence > self.POSITIVE_SHORTCUT_THRESHOLD: + self.logger.debug('%s confidence = %s, we have a winner', + charset_name, confidence) + self._state = ProbingState.FOUND_IT + elif confidence < self.NEGATIVE_SHORTCUT_THRESHOLD: + self.logger.debug('%s confidence = %s, below negative ' + 'shortcut threshhold %s', charset_name, + confidence, + self.NEGATIVE_SHORTCUT_THRESHOLD) + self._state = ProbingState.NOT_ME + + return self.state + + def get_confidence(self): + r = 0.01 + if self._total_seqs > 0: + r = ((1.0 * self._seq_counters[SequenceLikelihood.POSITIVE]) / + self._total_seqs / self._model.typical_positive_ratio) + r = r * self._freq_char / self._total_char + if r >= 1.0: + r = 0.99 + return r diff --git a/venv/lib/python3.8/site-packages/chardet/sbcsgroupprober.py b/venv/lib/python3.8/site-packages/chardet/sbcsgroupprober.py new file mode 100644 index 0000000..bdeef4e --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/sbcsgroupprober.py @@ -0,0 +1,83 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .charsetgroupprober import CharSetGroupProber +from .hebrewprober import HebrewProber +from .langbulgarianmodel import (ISO_8859_5_BULGARIAN_MODEL, + WINDOWS_1251_BULGARIAN_MODEL) +from .langgreekmodel import ISO_8859_7_GREEK_MODEL, WINDOWS_1253_GREEK_MODEL +from .langhebrewmodel import WINDOWS_1255_HEBREW_MODEL +# from .langhungarianmodel import (ISO_8859_2_HUNGARIAN_MODEL, +# WINDOWS_1250_HUNGARIAN_MODEL) +from .langrussianmodel import (IBM855_RUSSIAN_MODEL, IBM866_RUSSIAN_MODEL, + ISO_8859_5_RUSSIAN_MODEL, KOI8_R_RUSSIAN_MODEL, + MACCYRILLIC_RUSSIAN_MODEL, + WINDOWS_1251_RUSSIAN_MODEL) +from .langthaimodel import TIS_620_THAI_MODEL +from .langturkishmodel import ISO_8859_9_TURKISH_MODEL +from .sbcharsetprober import SingleByteCharSetProber + + +class SBCSGroupProber(CharSetGroupProber): + def __init__(self): + super(SBCSGroupProber, self).__init__() + hebrew_prober = HebrewProber() + logical_hebrew_prober = SingleByteCharSetProber(WINDOWS_1255_HEBREW_MODEL, + False, hebrew_prober) + # TODO: See if using ISO-8859-8 Hebrew model works better here, since + # it's actually the visual one + visual_hebrew_prober = SingleByteCharSetProber(WINDOWS_1255_HEBREW_MODEL, + True, hebrew_prober) + hebrew_prober.set_model_probers(logical_hebrew_prober, + visual_hebrew_prober) + # TODO: ORDER MATTERS HERE. I changed the order vs what was in master + # and several tests failed that did not before. Some thought + # should be put into the ordering, and we should consider making + # order not matter here, because that is very counter-intuitive. + self.probers = [ + SingleByteCharSetProber(WINDOWS_1251_RUSSIAN_MODEL), + SingleByteCharSetProber(KOI8_R_RUSSIAN_MODEL), + SingleByteCharSetProber(ISO_8859_5_RUSSIAN_MODEL), + SingleByteCharSetProber(MACCYRILLIC_RUSSIAN_MODEL), + SingleByteCharSetProber(IBM866_RUSSIAN_MODEL), + SingleByteCharSetProber(IBM855_RUSSIAN_MODEL), + SingleByteCharSetProber(ISO_8859_7_GREEK_MODEL), + SingleByteCharSetProber(WINDOWS_1253_GREEK_MODEL), + SingleByteCharSetProber(ISO_8859_5_BULGARIAN_MODEL), + SingleByteCharSetProber(WINDOWS_1251_BULGARIAN_MODEL), + # TODO: Restore Hungarian encodings (iso-8859-2 and windows-1250) + # after we retrain model. + # SingleByteCharSetProber(ISO_8859_2_HUNGARIAN_MODEL), + # SingleByteCharSetProber(WINDOWS_1250_HUNGARIAN_MODEL), + SingleByteCharSetProber(TIS_620_THAI_MODEL), + SingleByteCharSetProber(ISO_8859_9_TURKISH_MODEL), + hebrew_prober, + logical_hebrew_prober, + visual_hebrew_prober, + ] + self.reset() diff --git a/venv/lib/python3.8/site-packages/chardet/sjisprober.py b/venv/lib/python3.8/site-packages/chardet/sjisprober.py new file mode 100644 index 0000000..9e29623 --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/sjisprober.py @@ -0,0 +1,92 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .mbcharsetprober import MultiByteCharSetProber +from .codingstatemachine import CodingStateMachine +from .chardistribution import SJISDistributionAnalysis +from .jpcntx import SJISContextAnalysis +from .mbcssm import SJIS_SM_MODEL +from .enums import ProbingState, MachineState + + +class SJISProber(MultiByteCharSetProber): + def __init__(self): + super(SJISProber, self).__init__() + self.coding_sm = CodingStateMachine(SJIS_SM_MODEL) + self.distribution_analyzer = SJISDistributionAnalysis() + self.context_analyzer = SJISContextAnalysis() + self.reset() + + def reset(self): + super(SJISProber, self).reset() + self.context_analyzer.reset() + + @property + def charset_name(self): + return self.context_analyzer.charset_name + + @property + def language(self): + return "Japanese" + + def feed(self, byte_str): + for i in range(len(byte_str)): + coding_state = self.coding_sm.next_state(byte_str[i]) + if coding_state == MachineState.ERROR: + self.logger.debug('%s %s prober hit error at byte %s', + self.charset_name, self.language, i) + self._state = ProbingState.NOT_ME + break + elif coding_state == MachineState.ITS_ME: + self._state = ProbingState.FOUND_IT + break + elif coding_state == MachineState.START: + char_len = self.coding_sm.get_current_charlen() + if i == 0: + self._last_char[1] = byte_str[0] + self.context_analyzer.feed(self._last_char[2 - char_len:], + char_len) + self.distribution_analyzer.feed(self._last_char, char_len) + else: + self.context_analyzer.feed(byte_str[i + 1 - char_len:i + 3 + - char_len], char_len) + self.distribution_analyzer.feed(byte_str[i - 1:i + 1], + char_len) + + self._last_char[0] = byte_str[-1] + + if self.state == ProbingState.DETECTING: + if (self.context_analyzer.got_enough_data() and + (self.get_confidence() > self.SHORTCUT_THRESHOLD)): + self._state = ProbingState.FOUND_IT + + return self.state + + def get_confidence(self): + context_conf = self.context_analyzer.get_confidence() + distrib_conf = self.distribution_analyzer.get_confidence() + return max(context_conf, distrib_conf) diff --git a/venv/lib/python3.8/site-packages/chardet/universaldetector.py b/venv/lib/python3.8/site-packages/chardet/universaldetector.py new file mode 100644 index 0000000..055a8ac --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/universaldetector.py @@ -0,0 +1,286 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is Mozilla Universal charset detector code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 2001 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# Shy Shalom - original C code +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### +""" +Module containing the UniversalDetector detector class, which is the primary +class a user of ``chardet`` should use. + +:author: Mark Pilgrim (initial port to Python) +:author: Shy Shalom (original C code) +:author: Dan Blanchard (major refactoring for 3.0) +:author: Ian Cordasco +""" + + +import codecs +import logging +import re + +from .charsetgroupprober import CharSetGroupProber +from .enums import InputState, LanguageFilter, ProbingState +from .escprober import EscCharSetProber +from .latin1prober import Latin1Prober +from .mbcsgroupprober import MBCSGroupProber +from .sbcsgroupprober import SBCSGroupProber + + +class UniversalDetector(object): + """ + The ``UniversalDetector`` class underlies the ``chardet.detect`` function + and coordinates all of the different charset probers. + + To get a ``dict`` containing an encoding and its confidence, you can simply + run: + + .. code:: + + u = UniversalDetector() + u.feed(some_bytes) + u.close() + detected = u.result + + """ + + MINIMUM_THRESHOLD = 0.20 + HIGH_BYTE_DETECTOR = re.compile(b'[\x80-\xFF]') + ESC_DETECTOR = re.compile(b'(\033|~{)') + WIN_BYTE_DETECTOR = re.compile(b'[\x80-\x9F]') + ISO_WIN_MAP = {'iso-8859-1': 'Windows-1252', + 'iso-8859-2': 'Windows-1250', + 'iso-8859-5': 'Windows-1251', + 'iso-8859-6': 'Windows-1256', + 'iso-8859-7': 'Windows-1253', + 'iso-8859-8': 'Windows-1255', + 'iso-8859-9': 'Windows-1254', + 'iso-8859-13': 'Windows-1257'} + + def __init__(self, lang_filter=LanguageFilter.ALL): + self._esc_charset_prober = None + self._charset_probers = [] + self.result = None + self.done = None + self._got_data = None + self._input_state = None + self._last_char = None + self.lang_filter = lang_filter + self.logger = logging.getLogger(__name__) + self._has_win_bytes = None + self.reset() + + def reset(self): + """ + Reset the UniversalDetector and all of its probers back to their + initial states. This is called by ``__init__``, so you only need to + call this directly in between analyses of different documents. + """ + self.result = {'encoding': None, 'confidence': 0.0, 'language': None} + self.done = False + self._got_data = False + self._has_win_bytes = False + self._input_state = InputState.PURE_ASCII + self._last_char = b'' + if self._esc_charset_prober: + self._esc_charset_prober.reset() + for prober in self._charset_probers: + prober.reset() + + def feed(self, byte_str): + """ + Takes a chunk of a document and feeds it through all of the relevant + charset probers. + + After calling ``feed``, you can check the value of the ``done`` + attribute to see if you need to continue feeding the + ``UniversalDetector`` more data, or if it has made a prediction + (in the ``result`` attribute). + + .. note:: + You should always call ``close`` when you're done feeding in your + document if ``done`` is not already ``True``. + """ + if self.done: + return + + if not len(byte_str): + return + + if not isinstance(byte_str, bytearray): + byte_str = bytearray(byte_str) + + # First check for known BOMs, since these are guaranteed to be correct + if not self._got_data: + # If the data starts with BOM, we know it is UTF + if byte_str.startswith(codecs.BOM_UTF8): + # EF BB BF UTF-8 with BOM + self.result = {'encoding': "UTF-8-SIG", + 'confidence': 1.0, + 'language': ''} + elif byte_str.startswith((codecs.BOM_UTF32_LE, + codecs.BOM_UTF32_BE)): + # FF FE 00 00 UTF-32, little-endian BOM + # 00 00 FE FF UTF-32, big-endian BOM + self.result = {'encoding': "UTF-32", + 'confidence': 1.0, + 'language': ''} + elif byte_str.startswith(b'\xFE\xFF\x00\x00'): + # FE FF 00 00 UCS-4, unusual octet order BOM (3412) + self.result = {'encoding': "X-ISO-10646-UCS-4-3412", + 'confidence': 1.0, + 'language': ''} + elif byte_str.startswith(b'\x00\x00\xFF\xFE'): + # 00 00 FF FE UCS-4, unusual octet order BOM (2143) + self.result = {'encoding': "X-ISO-10646-UCS-4-2143", + 'confidence': 1.0, + 'language': ''} + elif byte_str.startswith((codecs.BOM_LE, codecs.BOM_BE)): + # FF FE UTF-16, little endian BOM + # FE FF UTF-16, big endian BOM + self.result = {'encoding': "UTF-16", + 'confidence': 1.0, + 'language': ''} + + self._got_data = True + if self.result['encoding'] is not None: + self.done = True + return + + # If none of those matched and we've only see ASCII so far, check + # for high bytes and escape sequences + if self._input_state == InputState.PURE_ASCII: + if self.HIGH_BYTE_DETECTOR.search(byte_str): + self._input_state = InputState.HIGH_BYTE + elif self._input_state == InputState.PURE_ASCII and \ + self.ESC_DETECTOR.search(self._last_char + byte_str): + self._input_state = InputState.ESC_ASCII + + self._last_char = byte_str[-1:] + + # If we've seen escape sequences, use the EscCharSetProber, which + # uses a simple state machine to check for known escape sequences in + # HZ and ISO-2022 encodings, since those are the only encodings that + # use such sequences. + if self._input_state == InputState.ESC_ASCII: + if not self._esc_charset_prober: + self._esc_charset_prober = EscCharSetProber(self.lang_filter) + if self._esc_charset_prober.feed(byte_str) == ProbingState.FOUND_IT: + self.result = {'encoding': + self._esc_charset_prober.charset_name, + 'confidence': + self._esc_charset_prober.get_confidence(), + 'language': + self._esc_charset_prober.language} + self.done = True + # If we've seen high bytes (i.e., those with values greater than 127), + # we need to do more complicated checks using all our multi-byte and + # single-byte probers that are left. The single-byte probers + # use character bigram distributions to determine the encoding, whereas + # the multi-byte probers use a combination of character unigram and + # bigram distributions. + elif self._input_state == InputState.HIGH_BYTE: + if not self._charset_probers: + self._charset_probers = [MBCSGroupProber(self.lang_filter)] + # If we're checking non-CJK encodings, use single-byte prober + if self.lang_filter & LanguageFilter.NON_CJK: + self._charset_probers.append(SBCSGroupProber()) + self._charset_probers.append(Latin1Prober()) + for prober in self._charset_probers: + if prober.feed(byte_str) == ProbingState.FOUND_IT: + self.result = {'encoding': prober.charset_name, + 'confidence': prober.get_confidence(), + 'language': prober.language} + self.done = True + break + if self.WIN_BYTE_DETECTOR.search(byte_str): + self._has_win_bytes = True + + def close(self): + """ + Stop analyzing the current document and come up with a final + prediction. + + :returns: The ``result`` attribute, a ``dict`` with the keys + `encoding`, `confidence`, and `language`. + """ + # Don't bother with checks if we're already done + if self.done: + return self.result + self.done = True + + if not self._got_data: + self.logger.debug('no data received!') + + # Default to ASCII if it is all we've seen so far + elif self._input_state == InputState.PURE_ASCII: + self.result = {'encoding': 'ascii', + 'confidence': 1.0, + 'language': ''} + + # If we have seen non-ASCII, return the best that met MINIMUM_THRESHOLD + elif self._input_state == InputState.HIGH_BYTE: + prober_confidence = None + max_prober_confidence = 0.0 + max_prober = None + for prober in self._charset_probers: + if not prober: + continue + prober_confidence = prober.get_confidence() + if prober_confidence > max_prober_confidence: + max_prober_confidence = prober_confidence + max_prober = prober + if max_prober and (max_prober_confidence > self.MINIMUM_THRESHOLD): + charset_name = max_prober.charset_name + lower_charset_name = max_prober.charset_name.lower() + confidence = max_prober.get_confidence() + # Use Windows encoding name instead of ISO-8859 if we saw any + # extra Windows-specific bytes + if lower_charset_name.startswith('iso-8859'): + if self._has_win_bytes: + charset_name = self.ISO_WIN_MAP.get(lower_charset_name, + charset_name) + self.result = {'encoding': charset_name, + 'confidence': confidence, + 'language': max_prober.language} + + # Log all prober confidences if none met MINIMUM_THRESHOLD + if self.logger.getEffectiveLevel() <= logging.DEBUG: + if self.result['encoding'] is None: + self.logger.debug('no probers hit minimum threshold') + for group_prober in self._charset_probers: + if not group_prober: + continue + if isinstance(group_prober, CharSetGroupProber): + for prober in group_prober.probers: + self.logger.debug('%s %s confidence = %s', + prober.charset_name, + prober.language, + prober.get_confidence()) + else: + self.logger.debug('%s %s confidence = %s', + group_prober.charset_name, + group_prober.language, + group_prober.get_confidence()) + return self.result diff --git a/venv/lib/python3.8/site-packages/chardet/utf8prober.py b/venv/lib/python3.8/site-packages/chardet/utf8prober.py new file mode 100644 index 0000000..6c3196c --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/utf8prober.py @@ -0,0 +1,82 @@ +######################## BEGIN LICENSE BLOCK ######################## +# The Original Code is mozilla.org code. +# +# The Initial Developer of the Original Code is +# Netscape Communications Corporation. +# Portions created by the Initial Developer are Copyright (C) 1998 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Mark Pilgrim - port to Python +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA +# 02110-1301 USA +######################### END LICENSE BLOCK ######################### + +from .charsetprober import CharSetProber +from .enums import ProbingState, MachineState +from .codingstatemachine import CodingStateMachine +from .mbcssm import UTF8_SM_MODEL + + + +class UTF8Prober(CharSetProber): + ONE_CHAR_PROB = 0.5 + + def __init__(self): + super(UTF8Prober, self).__init__() + self.coding_sm = CodingStateMachine(UTF8_SM_MODEL) + self._num_mb_chars = None + self.reset() + + def reset(self): + super(UTF8Prober, self).reset() + self.coding_sm.reset() + self._num_mb_chars = 0 + + @property + def charset_name(self): + return "utf-8" + + @property + def language(self): + return "" + + def feed(self, byte_str): + for c in byte_str: + coding_state = self.coding_sm.next_state(c) + if coding_state == MachineState.ERROR: + self._state = ProbingState.NOT_ME + break + elif coding_state == MachineState.ITS_ME: + self._state = ProbingState.FOUND_IT + break + elif coding_state == MachineState.START: + if self.coding_sm.get_current_charlen() >= 2: + self._num_mb_chars += 1 + + if self.state == ProbingState.DETECTING: + if self.get_confidence() > self.SHORTCUT_THRESHOLD: + self._state = ProbingState.FOUND_IT + + return self.state + + def get_confidence(self): + unlike = 0.99 + if self._num_mb_chars < 6: + unlike *= self.ONE_CHAR_PROB ** self._num_mb_chars + return 1.0 - unlike + else: + return unlike diff --git a/venv/lib/python3.8/site-packages/chardet/version.py b/venv/lib/python3.8/site-packages/chardet/version.py new file mode 100644 index 0000000..70369b9 --- /dev/null +++ b/venv/lib/python3.8/site-packages/chardet/version.py @@ -0,0 +1,9 @@ +""" +This module exists only to simplify retrieving the version number of chardet +from within setup.py and from chardet subpackages. + +:author: Dan Blanchard (dan.blanchard@gmail.com) +""" + +__version__ = "4.0.0" +VERSION = __version__.split('.') diff --git a/venv/lib/python3.8/site-packages/easy_install.py b/venv/lib/python3.8/site-packages/easy_install.py new file mode 100644 index 0000000..d87e984 --- /dev/null +++ b/venv/lib/python3.8/site-packages/easy_install.py @@ -0,0 +1,5 @@ +"""Run the EasyInstall command""" + +if __name__ == '__main__': + from setuptools.command.easy_install import main + main() diff --git a/venv/lib/python3.8/site-packages/idna-2.10.dist-info/INSTALLER b/venv/lib/python3.8/site-packages/idna-2.10.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python3.8/site-packages/idna-2.10.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.8/site-packages/idna-2.10.dist-info/LICENSE.rst b/venv/lib/python3.8/site-packages/idna-2.10.dist-info/LICENSE.rst new file mode 100644 index 0000000..63664b8 --- /dev/null +++ b/venv/lib/python3.8/site-packages/idna-2.10.dist-info/LICENSE.rst @@ -0,0 +1,34 @@ +License +------- + +License: bsd-3-clause + +Copyright (c) 2013-2020, Kim Davies. 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 the + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +#. THIS SOFTWARE IS PROVIDED BY THE 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 HOLDERS OR + CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE + USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + DAMAGE. diff --git a/venv/lib/python3.8/site-packages/idna-2.10.dist-info/METADATA b/venv/lib/python3.8/site-packages/idna-2.10.dist-info/METADATA new file mode 100644 index 0000000..f73c0ff --- /dev/null +++ b/venv/lib/python3.8/site-packages/idna-2.10.dist-info/METADATA @@ -0,0 +1,243 @@ +Metadata-Version: 2.1 +Name: idna +Version: 2.10 +Summary: Internationalized Domain Names in Applications (IDNA) +Home-page: https://github.com/kjd/idna +Author: Kim Davies +Author-email: kim@cynosure.com.au +License: BSD-like +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: Intended Audience :: System Administrators +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 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 :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Internet :: Name Service (DNS) +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: Utilities +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* + +Internationalized Domain Names in Applications (IDNA) +===================================================== + +Support for the Internationalised Domain Names in Applications +(IDNA) protocol as specified in `RFC 5891 `_. +This is the latest version of the protocol and is sometimes referred to as +“IDNA 2008”. + +This library also provides support for Unicode Technical Standard 46, +`Unicode IDNA Compatibility Processing `_. + +This acts as a suitable replacement for the “encodings.idna” module that +comes with the Python standard library, but only supports the +old, deprecated IDNA specification (`RFC 3490 `_). + +Basic functions are simply executed: + +.. code-block:: pycon + + # Python 3 + >>> import idna + >>> idna.encode('ドメイン.テスト') + b'xn--eckwd4c7c.xn--zckzah' + >>> print(idna.decode('xn--eckwd4c7c.xn--zckzah')) + ドメイン.テスト + + # Python 2 + >>> import idna + >>> idna.encode(u'ドメイン.テスト') + 'xn--eckwd4c7c.xn--zckzah' + >>> print idna.decode('xn--eckwd4c7c.xn--zckzah') + ドメイン.テスト + +Packages +-------- + +The latest tagged release version is published in the PyPI repository: + +.. image:: https://badge.fury.io/py/idna.svg + :target: http://badge.fury.io/py/idna + + +Installation +------------ + +To install this library, you can use pip: + +.. code-block:: bash + + $ pip install idna + +Alternatively, you can install the package using the bundled setup script: + +.. code-block:: bash + + $ python setup.py install + +This library works with Python 2.7 and Python 3.4 or later. + + +Usage +----- + +For typical usage, the ``encode`` and ``decode`` functions will take a domain +name argument and perform a conversion to A-labels or U-labels respectively. + +.. code-block:: pycon + + # Python 3 + >>> import idna + >>> idna.encode('ドメイン.テスト') + b'xn--eckwd4c7c.xn--zckzah' + >>> print(idna.decode('xn--eckwd4c7c.xn--zckzah')) + ドメイン.テスト + +You may use the codec encoding and decoding methods using the +``idna.codec`` module: + +.. code-block:: pycon + + # Python 2 + >>> import idna.codec + >>> print u'домена.испытание'.encode('idna') + xn--80ahd1agd.xn--80akhbyknj4f + >>> print 'xn--80ahd1agd.xn--80akhbyknj4f'.decode('idna') + домена.испытание + +Conversions can be applied at a per-label basis using the ``ulabel`` or ``alabel`` +functions if necessary: + +.. code-block:: pycon + + # Python 2 + >>> idna.alabel(u'测试') + 'xn--0zwm56d' + +Compatibility Mapping (UTS #46) ++++++++++++++++++++++++++++++++ + +As described in `RFC 5895 `_, the IDNA +specification no longer normalizes input from different potential ways a user +may input a domain name. This functionality, known as a “mapping”, is now +considered by the specification to be a local user-interface issue distinct +from IDNA conversion functionality. + +This library provides one such mapping, that was developed by the Unicode +Consortium. Known as `Unicode IDNA Compatibility Processing `_, +it provides for both a regular mapping for typical applications, as well as +a transitional mapping to help migrate from older IDNA 2003 applications. + +For example, “Königsgäßchen” is not a permissible label as *LATIN CAPITAL +LETTER K* is not allowed (nor are capital letters in general). UTS 46 will +convert this into lower case prior to applying the IDNA conversion. + +.. code-block:: pycon + + # Python 3 + >>> import idna + >>> idna.encode(u'Königsgäßchen') + ... + idna.core.InvalidCodepoint: Codepoint U+004B at position 1 of 'Königsgäßchen' not allowed + >>> idna.encode('Königsgäßchen', uts46=True) + b'xn--knigsgchen-b4a3dun' + >>> print(idna.decode('xn--knigsgchen-b4a3dun')) + königsgäßchen + +Transitional processing provides conversions to help transition from the older +2003 standard to the current standard. For example, in the original IDNA +specification, the *LATIN SMALL LETTER SHARP S* (ß) was converted into two +*LATIN SMALL LETTER S* (ss), whereas in the current IDNA specification this +conversion is not performed. + +.. code-block:: pycon + + # Python 2 + >>> idna.encode(u'Königsgäßchen', uts46=True, transitional=True) + 'xn--knigsgsschen-lcb0w' + +Implementors should use transitional processing with caution, only in rare +cases where conversion from legacy labels to current labels must be performed +(i.e. IDNA implementations that pre-date 2008). For typical applications +that just need to convert labels, transitional processing is unlikely to be +beneficial and could produce unexpected incompatible results. + +``encodings.idna`` Compatibility +++++++++++++++++++++++++++++++++ + +Function calls from the Python built-in ``encodings.idna`` module are +mapped to their IDNA 2008 equivalents using the ``idna.compat`` module. +Simply substitute the ``import`` clause in your code to refer to the +new module name. + +Exceptions +---------- + +All errors raised during the conversion following the specification should +raise an exception derived from the ``idna.IDNAError`` base class. + +More specific exceptions that may be generated as ``idna.IDNABidiError`` +when the error reflects an illegal combination of left-to-right and right-to-left +characters in a label; ``idna.InvalidCodepoint`` when a specific codepoint is +an illegal character in an IDN label (i.e. INVALID); and ``idna.InvalidCodepointContext`` +when the codepoint is illegal based on its positional context (i.e. it is CONTEXTO +or CONTEXTJ but the contextual requirements are not satisfied.) + +Building and Diagnostics +------------------------ + +The IDNA and UTS 46 functionality relies upon pre-calculated lookup tables for +performance. These tables are derived from computing against eligibility criteria +in the respective standards. These tables are computed using the command-line +script ``tools/idna-data``. + +This tool will fetch relevant tables from the Unicode Consortium and perform the +required calculations to identify eligibility. It has three main modes: + +* ``idna-data make-libdata``. Generates ``idnadata.py`` and ``uts46data.py``, + the pre-calculated lookup tables using for IDNA and UTS 46 conversions. Implementors + who wish to track this library against a different Unicode version may use this tool + to manually generate a different version of the ``idnadata.py`` and ``uts46data.py`` + files. + +* ``idna-data make-table``. Generate a table of the IDNA disposition + (e.g. PVALID, CONTEXTJ, CONTEXTO) in the format found in Appendix B.1 of RFC + 5892 and the pre-computed tables published by `IANA `_. + +* ``idna-data U+0061``. Prints debugging output on the various properties + associated with an individual Unicode codepoint (in this case, U+0061), that are + used to assess the IDNA and UTS 46 status of a codepoint. This is helpful in debugging + or analysis. + +The tool accepts a number of arguments, described using ``idna-data -h``. Most notably, +the ``--version`` argument allows the specification of the version of Unicode to use +in computing the table data. For example, ``idna-data --version 9.0.0 make-libdata`` +will generate library data against Unicode 9.0.0. + +Note that this script requires Python 3, but all generated library data will work +in Python 2.7. + + +Testing +------- + +The library has a test suite based on each rule of the IDNA specification, as +well as tests that are provided as part of the Unicode Technical Standard 46, +`Unicode IDNA Compatibility Processing `_. + +The tests are run automatically on each commit at Travis CI: + +.. image:: https://travis-ci.org/kjd/idna.svg?branch=master + :target: https://travis-ci.org/kjd/idna + + diff --git a/venv/lib/python3.8/site-packages/idna-2.10.dist-info/RECORD b/venv/lib/python3.8/site-packages/idna-2.10.dist-info/RECORD new file mode 100644 index 0000000..67b7cd5 --- /dev/null +++ b/venv/lib/python3.8/site-packages/idna-2.10.dist-info/RECORD @@ -0,0 +1,22 @@ +idna-2.10.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +idna-2.10.dist-info/LICENSE.rst,sha256=QSAUQg0kc9ugYRfD1Nng7sqm3eDKMM2VH07CvjlCbzI,1565 +idna-2.10.dist-info/METADATA,sha256=ZWCaQDBjdmSvx5EU7Cv6ORC-9NUQ6nXh1eXx38ySe40,9104 +idna-2.10.dist-info/RECORD,, +idna-2.10.dist-info/WHEEL,sha256=8zNYZbwQSXoB9IfXOjPfeNwvAsALAjffgk27FqvCWbo,110 +idna-2.10.dist-info/top_level.txt,sha256=jSag9sEDqvSPftxOQy-ABfGV_RSy7oFh4zZJpODV8k0,5 +idna/__init__.py,sha256=9Nt7xpyet3DmOrPUGooDdAwmHZZu1qUAy2EaJ93kGiQ,58 +idna/__pycache__/__init__.cpython-38.pyc,, +idna/__pycache__/codec.cpython-38.pyc,, +idna/__pycache__/compat.cpython-38.pyc,, +idna/__pycache__/core.cpython-38.pyc,, +idna/__pycache__/idnadata.cpython-38.pyc,, +idna/__pycache__/intranges.cpython-38.pyc,, +idna/__pycache__/package_data.cpython-38.pyc,, +idna/__pycache__/uts46data.cpython-38.pyc,, +idna/codec.py,sha256=lvYb7yu7PhAqFaAIAdWcwgaWI2UmgseUua-1c0AsG0A,3299 +idna/compat.py,sha256=R-h29D-6mrnJzbXxymrWUW7iZUvy-26TQwZ0ij57i4U,232 +idna/core.py,sha256=jCoaLb3bA2tS_DDx9PpGuNTEZZN2jAzB369aP-IHYRE,11951 +idna/idnadata.py,sha256=gmzFwZWjdms3kKZ_M_vwz7-LP_SCgYfSeE03B21Qpsk,42350 +idna/intranges.py,sha256=TY1lpxZIQWEP6tNqjZkFA5hgoMWOj1OBmnUG8ihT87E,1749 +idna/package_data.py,sha256=bxBjpLnE06_1jSYKEy5svOMu1zM3OMztXVUb1tPlcp0,22 +idna/uts46data.py,sha256=lMdw2zdjkH1JUWXPPEfFUSYT3Fyj60bBmfLvvy5m7ko,202084 diff --git a/venv/lib/python3.8/site-packages/idna-2.10.dist-info/WHEEL b/venv/lib/python3.8/site-packages/idna-2.10.dist-info/WHEEL new file mode 100644 index 0000000..8b701e9 --- /dev/null +++ b/venv/lib/python3.8/site-packages/idna-2.10.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.33.6) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/venv/lib/python3.8/site-packages/idna-2.10.dist-info/top_level.txt b/venv/lib/python3.8/site-packages/idna-2.10.dist-info/top_level.txt new file mode 100644 index 0000000..c40472e --- /dev/null +++ b/venv/lib/python3.8/site-packages/idna-2.10.dist-info/top_level.txt @@ -0,0 +1 @@ +idna diff --git a/venv/lib/python3.8/site-packages/idna/__init__.py b/venv/lib/python3.8/site-packages/idna/__init__.py new file mode 100644 index 0000000..847bf93 --- /dev/null +++ b/venv/lib/python3.8/site-packages/idna/__init__.py @@ -0,0 +1,2 @@ +from .package_data import __version__ +from .core import * diff --git a/venv/lib/python3.8/site-packages/idna/codec.py b/venv/lib/python3.8/site-packages/idna/codec.py new file mode 100644 index 0000000..98c65ea --- /dev/null +++ b/venv/lib/python3.8/site-packages/idna/codec.py @@ -0,0 +1,118 @@ +from .core import encode, decode, alabel, ulabel, IDNAError +import codecs +import re + +_unicode_dots_re = re.compile(u'[\u002e\u3002\uff0e\uff61]') + +class Codec(codecs.Codec): + + def encode(self, data, errors='strict'): + + if errors != 'strict': + raise IDNAError("Unsupported error handling \"{0}\"".format(errors)) + + if not data: + return "", 0 + + return encode(data), len(data) + + def decode(self, data, errors='strict'): + + if errors != 'strict': + raise IDNAError("Unsupported error handling \"{0}\"".format(errors)) + + if not data: + return u"", 0 + + return decode(data), len(data) + +class IncrementalEncoder(codecs.BufferedIncrementalEncoder): + def _buffer_encode(self, data, errors, final): + if errors != 'strict': + raise IDNAError("Unsupported error handling \"{0}\"".format(errors)) + + if not data: + return ("", 0) + + labels = _unicode_dots_re.split(data) + trailing_dot = u'' + if labels: + if not labels[-1]: + trailing_dot = '.' + del labels[-1] + elif not final: + # Keep potentially unfinished label until the next call + del labels[-1] + if labels: + trailing_dot = '.' + + result = [] + size = 0 + for label in labels: + result.append(alabel(label)) + if size: + size += 1 + size += len(label) + + # Join with U+002E + result = ".".join(result) + trailing_dot + size += len(trailing_dot) + return (result, size) + +class IncrementalDecoder(codecs.BufferedIncrementalDecoder): + def _buffer_decode(self, data, errors, final): + if errors != 'strict': + raise IDNAError("Unsupported error handling \"{0}\"".format(errors)) + + if not data: + return (u"", 0) + + # IDNA allows decoding to operate on Unicode strings, too. + if isinstance(data, unicode): + labels = _unicode_dots_re.split(data) + else: + # Must be ASCII string + data = str(data) + unicode(data, "ascii") + labels = data.split(".") + + trailing_dot = u'' + if labels: + if not labels[-1]: + trailing_dot = u'.' + del labels[-1] + elif not final: + # Keep potentially unfinished label until the next call + del labels[-1] + if labels: + trailing_dot = u'.' + + result = [] + size = 0 + for label in labels: + result.append(ulabel(label)) + if size: + size += 1 + size += len(label) + + result = u".".join(result) + trailing_dot + size += len(trailing_dot) + return (result, size) + + +class StreamWriter(Codec, codecs.StreamWriter): + pass + +class StreamReader(Codec, codecs.StreamReader): + pass + +def getregentry(): + return codecs.CodecInfo( + name='idna', + encode=Codec().encode, + decode=Codec().decode, + incrementalencoder=IncrementalEncoder, + incrementaldecoder=IncrementalDecoder, + streamwriter=StreamWriter, + streamreader=StreamReader, + ) diff --git a/venv/lib/python3.8/site-packages/idna/compat.py b/venv/lib/python3.8/site-packages/idna/compat.py new file mode 100644 index 0000000..4d47f33 --- /dev/null +++ b/venv/lib/python3.8/site-packages/idna/compat.py @@ -0,0 +1,12 @@ +from .core import * +from .codec import * + +def ToASCII(label): + return encode(label) + +def ToUnicode(label): + return decode(label) + +def nameprep(s): + raise NotImplementedError("IDNA 2008 does not utilise nameprep protocol") + diff --git a/venv/lib/python3.8/site-packages/idna/core.py b/venv/lib/python3.8/site-packages/idna/core.py new file mode 100644 index 0000000..41ec5c7 --- /dev/null +++ b/venv/lib/python3.8/site-packages/idna/core.py @@ -0,0 +1,400 @@ +from . import idnadata +import bisect +import unicodedata +import re +import sys +from .intranges import intranges_contain + +_virama_combining_class = 9 +_alabel_prefix = b'xn--' +_unicode_dots_re = re.compile(u'[\u002e\u3002\uff0e\uff61]') + +if sys.version_info[0] >= 3: + unicode = str + unichr = chr + +class IDNAError(UnicodeError): + """ Base exception for all IDNA-encoding related problems """ + pass + + +class IDNABidiError(IDNAError): + """ Exception when bidirectional requirements are not satisfied """ + pass + + +class InvalidCodepoint(IDNAError): + """ Exception when a disallowed or unallocated codepoint is used """ + pass + + +class InvalidCodepointContext(IDNAError): + """ Exception when the codepoint is not valid in the context it is used """ + pass + + +def _combining_class(cp): + v = unicodedata.combining(unichr(cp)) + if v == 0: + if not unicodedata.name(unichr(cp)): + raise ValueError("Unknown character in unicodedata") + return v + +def _is_script(cp, script): + return intranges_contain(ord(cp), idnadata.scripts[script]) + +def _punycode(s): + return s.encode('punycode') + +def _unot(s): + return 'U+{0:04X}'.format(s) + + +def valid_label_length(label): + + if len(label) > 63: + return False + return True + + +def valid_string_length(label, trailing_dot): + + if len(label) > (254 if trailing_dot else 253): + return False + return True + + +def check_bidi(label, check_ltr=False): + + # Bidi rules should only be applied if string contains RTL characters + bidi_label = False + for (idx, cp) in enumerate(label, 1): + direction = unicodedata.bidirectional(cp) + if direction == '': + # String likely comes from a newer version of Unicode + raise IDNABidiError('Unknown directionality in label {0} at position {1}'.format(repr(label), idx)) + if direction in ['R', 'AL', 'AN']: + bidi_label = True + if not bidi_label and not check_ltr: + return True + + # Bidi rule 1 + direction = unicodedata.bidirectional(label[0]) + if direction in ['R', 'AL']: + rtl = True + elif direction == 'L': + rtl = False + else: + raise IDNABidiError('First codepoint in label {0} must be directionality L, R or AL'.format(repr(label))) + + valid_ending = False + number_type = False + for (idx, cp) in enumerate(label, 1): + direction = unicodedata.bidirectional(cp) + + if rtl: + # Bidi rule 2 + if not direction in ['R', 'AL', 'AN', 'EN', 'ES', 'CS', 'ET', 'ON', 'BN', 'NSM']: + raise IDNABidiError('Invalid direction for codepoint at position {0} in a right-to-left label'.format(idx)) + # Bidi rule 3 + if direction in ['R', 'AL', 'EN', 'AN']: + valid_ending = True + elif direction != 'NSM': + valid_ending = False + # Bidi rule 4 + if direction in ['AN', 'EN']: + if not number_type: + number_type = direction + else: + if number_type != direction: + raise IDNABidiError('Can not mix numeral types in a right-to-left label') + else: + # Bidi rule 5 + if not direction in ['L', 'EN', 'ES', 'CS', 'ET', 'ON', 'BN', 'NSM']: + raise IDNABidiError('Invalid direction for codepoint at position {0} in a left-to-right label'.format(idx)) + # Bidi rule 6 + if direction in ['L', 'EN']: + valid_ending = True + elif direction != 'NSM': + valid_ending = False + + if not valid_ending: + raise IDNABidiError('Label ends with illegal codepoint directionality') + + return True + + +def check_initial_combiner(label): + + if unicodedata.category(label[0])[0] == 'M': + raise IDNAError('Label begins with an illegal combining character') + return True + + +def check_hyphen_ok(label): + + if label[2:4] == '--': + raise IDNAError('Label has disallowed hyphens in 3rd and 4th position') + if label[0] == '-' or label[-1] == '-': + raise IDNAError('Label must not start or end with a hyphen') + return True + + +def check_nfc(label): + + if unicodedata.normalize('NFC', label) != label: + raise IDNAError('Label must be in Normalization Form C') + + +def valid_contextj(label, pos): + + cp_value = ord(label[pos]) + + if cp_value == 0x200c: + + if pos > 0: + if _combining_class(ord(label[pos - 1])) == _virama_combining_class: + return True + + ok = False + for i in range(pos-1, -1, -1): + joining_type = idnadata.joining_types.get(ord(label[i])) + if joining_type == ord('T'): + continue + if joining_type in [ord('L'), ord('D')]: + ok = True + break + + if not ok: + return False + + ok = False + for i in range(pos+1, len(label)): + joining_type = idnadata.joining_types.get(ord(label[i])) + if joining_type == ord('T'): + continue + if joining_type in [ord('R'), ord('D')]: + ok = True + break + return ok + + if cp_value == 0x200d: + + if pos > 0: + if _combining_class(ord(label[pos - 1])) == _virama_combining_class: + return True + return False + + else: + + return False + + +def valid_contexto(label, pos, exception=False): + + cp_value = ord(label[pos]) + + if cp_value == 0x00b7: + if 0 < pos < len(label)-1: + if ord(label[pos - 1]) == 0x006c and ord(label[pos + 1]) == 0x006c: + return True + return False + + elif cp_value == 0x0375: + if pos < len(label)-1 and len(label) > 1: + return _is_script(label[pos + 1], 'Greek') + return False + + elif cp_value == 0x05f3 or cp_value == 0x05f4: + if pos > 0: + return _is_script(label[pos - 1], 'Hebrew') + return False + + elif cp_value == 0x30fb: + for cp in label: + if cp == u'\u30fb': + continue + if _is_script(cp, 'Hiragana') or _is_script(cp, 'Katakana') or _is_script(cp, 'Han'): + return True + return False + + elif 0x660 <= cp_value <= 0x669: + for cp in label: + if 0x6f0 <= ord(cp) <= 0x06f9: + return False + return True + + elif 0x6f0 <= cp_value <= 0x6f9: + for cp in label: + if 0x660 <= ord(cp) <= 0x0669: + return False + return True + + +def check_label(label): + + if isinstance(label, (bytes, bytearray)): + label = label.decode('utf-8') + if len(label) == 0: + raise IDNAError('Empty Label') + + check_nfc(label) + check_hyphen_ok(label) + check_initial_combiner(label) + + for (pos, cp) in enumerate(label): + cp_value = ord(cp) + if intranges_contain(cp_value, idnadata.codepoint_classes['PVALID']): + continue + elif intranges_contain(cp_value, idnadata.codepoint_classes['CONTEXTJ']): + try: + if not valid_contextj(label, pos): + raise InvalidCodepointContext('Joiner {0} not allowed at position {1} in {2}'.format( + _unot(cp_value), pos+1, repr(label))) + except ValueError: + raise IDNAError('Unknown codepoint adjacent to joiner {0} at position {1} in {2}'.format( + _unot(cp_value), pos+1, repr(label))) + elif intranges_contain(cp_value, idnadata.codepoint_classes['CONTEXTO']): + if not valid_contexto(label, pos): + raise InvalidCodepointContext('Codepoint {0} not allowed at position {1} in {2}'.format(_unot(cp_value), pos+1, repr(label))) + else: + raise InvalidCodepoint('Codepoint {0} at position {1} of {2} not allowed'.format(_unot(cp_value), pos+1, repr(label))) + + check_bidi(label) + + +def alabel(label): + + try: + label = label.encode('ascii') + ulabel(label) + if not valid_label_length(label): + raise IDNAError('Label too long') + return label + except UnicodeEncodeError: + pass + + if not label: + raise IDNAError('No Input') + + label = unicode(label) + check_label(label) + label = _punycode(label) + label = _alabel_prefix + label + + if not valid_label_length(label): + raise IDNAError('Label too long') + + return label + + +def ulabel(label): + + if not isinstance(label, (bytes, bytearray)): + try: + label = label.encode('ascii') + except UnicodeEncodeError: + check_label(label) + return label + + label = label.lower() + if label.startswith(_alabel_prefix): + label = label[len(_alabel_prefix):] + if not label: + raise IDNAError('Malformed A-label, no Punycode eligible content found') + if label.decode('ascii')[-1] == '-': + raise IDNAError('A-label must not end with a hyphen') + else: + check_label(label) + return label.decode('ascii') + + label = label.decode('punycode') + check_label(label) + return label + + +def uts46_remap(domain, std3_rules=True, transitional=False): + """Re-map the characters in the string according to UTS46 processing.""" + from .uts46data import uts46data + output = u"" + try: + for pos, char in enumerate(domain): + code_point = ord(char) + uts46row = uts46data[code_point if code_point < 256 else + bisect.bisect_left(uts46data, (code_point, "Z")) - 1] + status = uts46row[1] + replacement = uts46row[2] if len(uts46row) == 3 else None + if (status == "V" or + (status == "D" and not transitional) or + (status == "3" and not std3_rules and replacement is None)): + output += char + elif replacement is not None and (status == "M" or + (status == "3" and not std3_rules) or + (status == "D" and transitional)): + output += replacement + elif status != "I": + raise IndexError() + return unicodedata.normalize("NFC", output) + except IndexError: + raise InvalidCodepoint( + "Codepoint {0} not allowed at position {1} in {2}".format( + _unot(code_point), pos + 1, repr(domain))) + + +def encode(s, strict=False, uts46=False, std3_rules=False, transitional=False): + + if isinstance(s, (bytes, bytearray)): + s = s.decode("ascii") + if uts46: + s = uts46_remap(s, std3_rules, transitional) + trailing_dot = False + result = [] + if strict: + labels = s.split('.') + else: + labels = _unicode_dots_re.split(s) + if not labels or labels == ['']: + raise IDNAError('Empty domain') + if labels[-1] == '': + del labels[-1] + trailing_dot = True + for label in labels: + s = alabel(label) + if s: + result.append(s) + else: + raise IDNAError('Empty label') + if trailing_dot: + result.append(b'') + s = b'.'.join(result) + if not valid_string_length(s, trailing_dot): + raise IDNAError('Domain too long') + return s + + +def decode(s, strict=False, uts46=False, std3_rules=False): + + if isinstance(s, (bytes, bytearray)): + s = s.decode("ascii") + if uts46: + s = uts46_remap(s, std3_rules, False) + trailing_dot = False + result = [] + if not strict: + labels = _unicode_dots_re.split(s) + else: + labels = s.split(u'.') + if not labels or labels == ['']: + raise IDNAError('Empty domain') + if not labels[-1]: + del labels[-1] + trailing_dot = True + for label in labels: + s = ulabel(label) + if s: + result.append(s) + else: + raise IDNAError('Empty label') + if trailing_dot: + result.append(u'') + return u'.'.join(result) diff --git a/venv/lib/python3.8/site-packages/idna/idnadata.py b/venv/lib/python3.8/site-packages/idna/idnadata.py new file mode 100644 index 0000000..a284e4c --- /dev/null +++ b/venv/lib/python3.8/site-packages/idna/idnadata.py @@ -0,0 +1,2050 @@ +# This file is automatically generated by tools/idna-data + +__version__ = "13.0.0" +scripts = { + 'Greek': ( + 0x37000000374, + 0x37500000378, + 0x37a0000037e, + 0x37f00000380, + 0x38400000385, + 0x38600000387, + 0x3880000038b, + 0x38c0000038d, + 0x38e000003a2, + 0x3a3000003e2, + 0x3f000000400, + 0x1d2600001d2b, + 0x1d5d00001d62, + 0x1d6600001d6b, + 0x1dbf00001dc0, + 0x1f0000001f16, + 0x1f1800001f1e, + 0x1f2000001f46, + 0x1f4800001f4e, + 0x1f5000001f58, + 0x1f5900001f5a, + 0x1f5b00001f5c, + 0x1f5d00001f5e, + 0x1f5f00001f7e, + 0x1f8000001fb5, + 0x1fb600001fc5, + 0x1fc600001fd4, + 0x1fd600001fdc, + 0x1fdd00001ff0, + 0x1ff200001ff5, + 0x1ff600001fff, + 0x212600002127, + 0xab650000ab66, + 0x101400001018f, + 0x101a0000101a1, + 0x1d2000001d246, + ), + 'Han': ( + 0x2e8000002e9a, + 0x2e9b00002ef4, + 0x2f0000002fd6, + 0x300500003006, + 0x300700003008, + 0x30210000302a, + 0x30380000303c, + 0x340000004dc0, + 0x4e0000009ffd, + 0xf9000000fa6e, + 0xfa700000fada, + 0x16ff000016ff2, + 0x200000002a6de, + 0x2a7000002b735, + 0x2b7400002b81e, + 0x2b8200002cea2, + 0x2ceb00002ebe1, + 0x2f8000002fa1e, + 0x300000003134b, + ), + 'Hebrew': ( + 0x591000005c8, + 0x5d0000005eb, + 0x5ef000005f5, + 0xfb1d0000fb37, + 0xfb380000fb3d, + 0xfb3e0000fb3f, + 0xfb400000fb42, + 0xfb430000fb45, + 0xfb460000fb50, + ), + 'Hiragana': ( + 0x304100003097, + 0x309d000030a0, + 0x1b0010001b11f, + 0x1b1500001b153, + 0x1f2000001f201, + ), + 'Katakana': ( + 0x30a1000030fb, + 0x30fd00003100, + 0x31f000003200, + 0x32d0000032ff, + 0x330000003358, + 0xff660000ff70, + 0xff710000ff9e, + 0x1b0000001b001, + 0x1b1640001b168, + ), +} +joining_types = { + 0x600: 85, + 0x601: 85, + 0x602: 85, + 0x603: 85, + 0x604: 85, + 0x605: 85, + 0x608: 85, + 0x60b: 85, + 0x620: 68, + 0x621: 85, + 0x622: 82, + 0x623: 82, + 0x624: 82, + 0x625: 82, + 0x626: 68, + 0x627: 82, + 0x628: 68, + 0x629: 82, + 0x62a: 68, + 0x62b: 68, + 0x62c: 68, + 0x62d: 68, + 0x62e: 68, + 0x62f: 82, + 0x630: 82, + 0x631: 82, + 0x632: 82, + 0x633: 68, + 0x634: 68, + 0x635: 68, + 0x636: 68, + 0x637: 68, + 0x638: 68, + 0x639: 68, + 0x63a: 68, + 0x63b: 68, + 0x63c: 68, + 0x63d: 68, + 0x63e: 68, + 0x63f: 68, + 0x640: 67, + 0x641: 68, + 0x642: 68, + 0x643: 68, + 0x644: 68, + 0x645: 68, + 0x646: 68, + 0x647: 68, + 0x648: 82, + 0x649: 68, + 0x64a: 68, + 0x66e: 68, + 0x66f: 68, + 0x671: 82, + 0x672: 82, + 0x673: 82, + 0x674: 85, + 0x675: 82, + 0x676: 82, + 0x677: 82, + 0x678: 68, + 0x679: 68, + 0x67a: 68, + 0x67b: 68, + 0x67c: 68, + 0x67d: 68, + 0x67e: 68, + 0x67f: 68, + 0x680: 68, + 0x681: 68, + 0x682: 68, + 0x683: 68, + 0x684: 68, + 0x685: 68, + 0x686: 68, + 0x687: 68, + 0x688: 82, + 0x689: 82, + 0x68a: 82, + 0x68b: 82, + 0x68c: 82, + 0x68d: 82, + 0x68e: 82, + 0x68f: 82, + 0x690: 82, + 0x691: 82, + 0x692: 82, + 0x693: 82, + 0x694: 82, + 0x695: 82, + 0x696: 82, + 0x697: 82, + 0x698: 82, + 0x699: 82, + 0x69a: 68, + 0x69b: 68, + 0x69c: 68, + 0x69d: 68, + 0x69e: 68, + 0x69f: 68, + 0x6a0: 68, + 0x6a1: 68, + 0x6a2: 68, + 0x6a3: 68, + 0x6a4: 68, + 0x6a5: 68, + 0x6a6: 68, + 0x6a7: 68, + 0x6a8: 68, + 0x6a9: 68, + 0x6aa: 68, + 0x6ab: 68, + 0x6ac: 68, + 0x6ad: 68, + 0x6ae: 68, + 0x6af: 68, + 0x6b0: 68, + 0x6b1: 68, + 0x6b2: 68, + 0x6b3: 68, + 0x6b4: 68, + 0x6b5: 68, + 0x6b6: 68, + 0x6b7: 68, + 0x6b8: 68, + 0x6b9: 68, + 0x6ba: 68, + 0x6bb: 68, + 0x6bc: 68, + 0x6bd: 68, + 0x6be: 68, + 0x6bf: 68, + 0x6c0: 82, + 0x6c1: 68, + 0x6c2: 68, + 0x6c3: 82, + 0x6c4: 82, + 0x6c5: 82, + 0x6c6: 82, + 0x6c7: 82, + 0x6c8: 82, + 0x6c9: 82, + 0x6ca: 82, + 0x6cb: 82, + 0x6cc: 68, + 0x6cd: 82, + 0x6ce: 68, + 0x6cf: 82, + 0x6d0: 68, + 0x6d1: 68, + 0x6d2: 82, + 0x6d3: 82, + 0x6d5: 82, + 0x6dd: 85, + 0x6ee: 82, + 0x6ef: 82, + 0x6fa: 68, + 0x6fb: 68, + 0x6fc: 68, + 0x6ff: 68, + 0x70f: 84, + 0x710: 82, + 0x712: 68, + 0x713: 68, + 0x714: 68, + 0x715: 82, + 0x716: 82, + 0x717: 82, + 0x718: 82, + 0x719: 82, + 0x71a: 68, + 0x71b: 68, + 0x71c: 68, + 0x71d: 68, + 0x71e: 82, + 0x71f: 68, + 0x720: 68, + 0x721: 68, + 0x722: 68, + 0x723: 68, + 0x724: 68, + 0x725: 68, + 0x726: 68, + 0x727: 68, + 0x728: 82, + 0x729: 68, + 0x72a: 82, + 0x72b: 68, + 0x72c: 82, + 0x72d: 68, + 0x72e: 68, + 0x72f: 82, + 0x74d: 82, + 0x74e: 68, + 0x74f: 68, + 0x750: 68, + 0x751: 68, + 0x752: 68, + 0x753: 68, + 0x754: 68, + 0x755: 68, + 0x756: 68, + 0x757: 68, + 0x758: 68, + 0x759: 82, + 0x75a: 82, + 0x75b: 82, + 0x75c: 68, + 0x75d: 68, + 0x75e: 68, + 0x75f: 68, + 0x760: 68, + 0x761: 68, + 0x762: 68, + 0x763: 68, + 0x764: 68, + 0x765: 68, + 0x766: 68, + 0x767: 68, + 0x768: 68, + 0x769: 68, + 0x76a: 68, + 0x76b: 82, + 0x76c: 82, + 0x76d: 68, + 0x76e: 68, + 0x76f: 68, + 0x770: 68, + 0x771: 82, + 0x772: 68, + 0x773: 82, + 0x774: 82, + 0x775: 68, + 0x776: 68, + 0x777: 68, + 0x778: 82, + 0x779: 82, + 0x77a: 68, + 0x77b: 68, + 0x77c: 68, + 0x77d: 68, + 0x77e: 68, + 0x77f: 68, + 0x7ca: 68, + 0x7cb: 68, + 0x7cc: 68, + 0x7cd: 68, + 0x7ce: 68, + 0x7cf: 68, + 0x7d0: 68, + 0x7d1: 68, + 0x7d2: 68, + 0x7d3: 68, + 0x7d4: 68, + 0x7d5: 68, + 0x7d6: 68, + 0x7d7: 68, + 0x7d8: 68, + 0x7d9: 68, + 0x7da: 68, + 0x7db: 68, + 0x7dc: 68, + 0x7dd: 68, + 0x7de: 68, + 0x7df: 68, + 0x7e0: 68, + 0x7e1: 68, + 0x7e2: 68, + 0x7e3: 68, + 0x7e4: 68, + 0x7e5: 68, + 0x7e6: 68, + 0x7e7: 68, + 0x7e8: 68, + 0x7e9: 68, + 0x7ea: 68, + 0x7fa: 67, + 0x840: 82, + 0x841: 68, + 0x842: 68, + 0x843: 68, + 0x844: 68, + 0x845: 68, + 0x846: 82, + 0x847: 82, + 0x848: 68, + 0x849: 82, + 0x84a: 68, + 0x84b: 68, + 0x84c: 68, + 0x84d: 68, + 0x84e: 68, + 0x84f: 68, + 0x850: 68, + 0x851: 68, + 0x852: 68, + 0x853: 68, + 0x854: 82, + 0x855: 68, + 0x856: 82, + 0x857: 82, + 0x858: 82, + 0x860: 68, + 0x861: 85, + 0x862: 68, + 0x863: 68, + 0x864: 68, + 0x865: 68, + 0x866: 85, + 0x867: 82, + 0x868: 68, + 0x869: 82, + 0x86a: 82, + 0x8a0: 68, + 0x8a1: 68, + 0x8a2: 68, + 0x8a3: 68, + 0x8a4: 68, + 0x8a5: 68, + 0x8a6: 68, + 0x8a7: 68, + 0x8a8: 68, + 0x8a9: 68, + 0x8aa: 82, + 0x8ab: 82, + 0x8ac: 82, + 0x8ad: 85, + 0x8ae: 82, + 0x8af: 68, + 0x8b0: 68, + 0x8b1: 82, + 0x8b2: 82, + 0x8b3: 68, + 0x8b4: 68, + 0x8b6: 68, + 0x8b7: 68, + 0x8b8: 68, + 0x8b9: 82, + 0x8ba: 68, + 0x8bb: 68, + 0x8bc: 68, + 0x8bd: 68, + 0x8be: 68, + 0x8bf: 68, + 0x8c0: 68, + 0x8c1: 68, + 0x8c2: 68, + 0x8c3: 68, + 0x8c4: 68, + 0x8c5: 68, + 0x8c6: 68, + 0x8c7: 68, + 0x8e2: 85, + 0x1806: 85, + 0x1807: 68, + 0x180a: 67, + 0x180e: 85, + 0x1820: 68, + 0x1821: 68, + 0x1822: 68, + 0x1823: 68, + 0x1824: 68, + 0x1825: 68, + 0x1826: 68, + 0x1827: 68, + 0x1828: 68, + 0x1829: 68, + 0x182a: 68, + 0x182b: 68, + 0x182c: 68, + 0x182d: 68, + 0x182e: 68, + 0x182f: 68, + 0x1830: 68, + 0x1831: 68, + 0x1832: 68, + 0x1833: 68, + 0x1834: 68, + 0x1835: 68, + 0x1836: 68, + 0x1837: 68, + 0x1838: 68, + 0x1839: 68, + 0x183a: 68, + 0x183b: 68, + 0x183c: 68, + 0x183d: 68, + 0x183e: 68, + 0x183f: 68, + 0x1840: 68, + 0x1841: 68, + 0x1842: 68, + 0x1843: 68, + 0x1844: 68, + 0x1845: 68, + 0x1846: 68, + 0x1847: 68, + 0x1848: 68, + 0x1849: 68, + 0x184a: 68, + 0x184b: 68, + 0x184c: 68, + 0x184d: 68, + 0x184e: 68, + 0x184f: 68, + 0x1850: 68, + 0x1851: 68, + 0x1852: 68, + 0x1853: 68, + 0x1854: 68, + 0x1855: 68, + 0x1856: 68, + 0x1857: 68, + 0x1858: 68, + 0x1859: 68, + 0x185a: 68, + 0x185b: 68, + 0x185c: 68, + 0x185d: 68, + 0x185e: 68, + 0x185f: 68, + 0x1860: 68, + 0x1861: 68, + 0x1862: 68, + 0x1863: 68, + 0x1864: 68, + 0x1865: 68, + 0x1866: 68, + 0x1867: 68, + 0x1868: 68, + 0x1869: 68, + 0x186a: 68, + 0x186b: 68, + 0x186c: 68, + 0x186d: 68, + 0x186e: 68, + 0x186f: 68, + 0x1870: 68, + 0x1871: 68, + 0x1872: 68, + 0x1873: 68, + 0x1874: 68, + 0x1875: 68, + 0x1876: 68, + 0x1877: 68, + 0x1878: 68, + 0x1880: 85, + 0x1881: 85, + 0x1882: 85, + 0x1883: 85, + 0x1884: 85, + 0x1885: 84, + 0x1886: 84, + 0x1887: 68, + 0x1888: 68, + 0x1889: 68, + 0x188a: 68, + 0x188b: 68, + 0x188c: 68, + 0x188d: 68, + 0x188e: 68, + 0x188f: 68, + 0x1890: 68, + 0x1891: 68, + 0x1892: 68, + 0x1893: 68, + 0x1894: 68, + 0x1895: 68, + 0x1896: 68, + 0x1897: 68, + 0x1898: 68, + 0x1899: 68, + 0x189a: 68, + 0x189b: 68, + 0x189c: 68, + 0x189d: 68, + 0x189e: 68, + 0x189f: 68, + 0x18a0: 68, + 0x18a1: 68, + 0x18a2: 68, + 0x18a3: 68, + 0x18a4: 68, + 0x18a5: 68, + 0x18a6: 68, + 0x18a7: 68, + 0x18a8: 68, + 0x18aa: 68, + 0x200c: 85, + 0x200d: 67, + 0x202f: 85, + 0x2066: 85, + 0x2067: 85, + 0x2068: 85, + 0x2069: 85, + 0xa840: 68, + 0xa841: 68, + 0xa842: 68, + 0xa843: 68, + 0xa844: 68, + 0xa845: 68, + 0xa846: 68, + 0xa847: 68, + 0xa848: 68, + 0xa849: 68, + 0xa84a: 68, + 0xa84b: 68, + 0xa84c: 68, + 0xa84d: 68, + 0xa84e: 68, + 0xa84f: 68, + 0xa850: 68, + 0xa851: 68, + 0xa852: 68, + 0xa853: 68, + 0xa854: 68, + 0xa855: 68, + 0xa856: 68, + 0xa857: 68, + 0xa858: 68, + 0xa859: 68, + 0xa85a: 68, + 0xa85b: 68, + 0xa85c: 68, + 0xa85d: 68, + 0xa85e: 68, + 0xa85f: 68, + 0xa860: 68, + 0xa861: 68, + 0xa862: 68, + 0xa863: 68, + 0xa864: 68, + 0xa865: 68, + 0xa866: 68, + 0xa867: 68, + 0xa868: 68, + 0xa869: 68, + 0xa86a: 68, + 0xa86b: 68, + 0xa86c: 68, + 0xa86d: 68, + 0xa86e: 68, + 0xa86f: 68, + 0xa870: 68, + 0xa871: 68, + 0xa872: 76, + 0xa873: 85, + 0x10ac0: 68, + 0x10ac1: 68, + 0x10ac2: 68, + 0x10ac3: 68, + 0x10ac4: 68, + 0x10ac5: 82, + 0x10ac6: 85, + 0x10ac7: 82, + 0x10ac8: 85, + 0x10ac9: 82, + 0x10aca: 82, + 0x10acb: 85, + 0x10acc: 85, + 0x10acd: 76, + 0x10ace: 82, + 0x10acf: 82, + 0x10ad0: 82, + 0x10ad1: 82, + 0x10ad2: 82, + 0x10ad3: 68, + 0x10ad4: 68, + 0x10ad5: 68, + 0x10ad6: 68, + 0x10ad7: 76, + 0x10ad8: 68, + 0x10ad9: 68, + 0x10ada: 68, + 0x10adb: 68, + 0x10adc: 68, + 0x10add: 82, + 0x10ade: 68, + 0x10adf: 68, + 0x10ae0: 68, + 0x10ae1: 82, + 0x10ae2: 85, + 0x10ae3: 85, + 0x10ae4: 82, + 0x10aeb: 68, + 0x10aec: 68, + 0x10aed: 68, + 0x10aee: 68, + 0x10aef: 82, + 0x10b80: 68, + 0x10b81: 82, + 0x10b82: 68, + 0x10b83: 82, + 0x10b84: 82, + 0x10b85: 82, + 0x10b86: 68, + 0x10b87: 68, + 0x10b88: 68, + 0x10b89: 82, + 0x10b8a: 68, + 0x10b8b: 68, + 0x10b8c: 82, + 0x10b8d: 68, + 0x10b8e: 82, + 0x10b8f: 82, + 0x10b90: 68, + 0x10b91: 82, + 0x10ba9: 82, + 0x10baa: 82, + 0x10bab: 82, + 0x10bac: 82, + 0x10bad: 68, + 0x10bae: 68, + 0x10baf: 85, + 0x10d00: 76, + 0x10d01: 68, + 0x10d02: 68, + 0x10d03: 68, + 0x10d04: 68, + 0x10d05: 68, + 0x10d06: 68, + 0x10d07: 68, + 0x10d08: 68, + 0x10d09: 68, + 0x10d0a: 68, + 0x10d0b: 68, + 0x10d0c: 68, + 0x10d0d: 68, + 0x10d0e: 68, + 0x10d0f: 68, + 0x10d10: 68, + 0x10d11: 68, + 0x10d12: 68, + 0x10d13: 68, + 0x10d14: 68, + 0x10d15: 68, + 0x10d16: 68, + 0x10d17: 68, + 0x10d18: 68, + 0x10d19: 68, + 0x10d1a: 68, + 0x10d1b: 68, + 0x10d1c: 68, + 0x10d1d: 68, + 0x10d1e: 68, + 0x10d1f: 68, + 0x10d20: 68, + 0x10d21: 68, + 0x10d22: 82, + 0x10d23: 68, + 0x10f30: 68, + 0x10f31: 68, + 0x10f32: 68, + 0x10f33: 82, + 0x10f34: 68, + 0x10f35: 68, + 0x10f36: 68, + 0x10f37: 68, + 0x10f38: 68, + 0x10f39: 68, + 0x10f3a: 68, + 0x10f3b: 68, + 0x10f3c: 68, + 0x10f3d: 68, + 0x10f3e: 68, + 0x10f3f: 68, + 0x10f40: 68, + 0x10f41: 68, + 0x10f42: 68, + 0x10f43: 68, + 0x10f44: 68, + 0x10f45: 85, + 0x10f51: 68, + 0x10f52: 68, + 0x10f53: 68, + 0x10f54: 82, + 0x10fb0: 68, + 0x10fb1: 85, + 0x10fb2: 68, + 0x10fb3: 68, + 0x10fb4: 82, + 0x10fb5: 82, + 0x10fb6: 82, + 0x10fb7: 85, + 0x10fb8: 68, + 0x10fb9: 82, + 0x10fba: 82, + 0x10fbb: 68, + 0x10fbc: 68, + 0x10fbd: 82, + 0x10fbe: 68, + 0x10fbf: 68, + 0x10fc0: 85, + 0x10fc1: 68, + 0x10fc2: 82, + 0x10fc3: 82, + 0x10fc4: 68, + 0x10fc5: 85, + 0x10fc6: 85, + 0x10fc7: 85, + 0x10fc8: 85, + 0x10fc9: 82, + 0x10fca: 68, + 0x10fcb: 76, + 0x110bd: 85, + 0x110cd: 85, + 0x1e900: 68, + 0x1e901: 68, + 0x1e902: 68, + 0x1e903: 68, + 0x1e904: 68, + 0x1e905: 68, + 0x1e906: 68, + 0x1e907: 68, + 0x1e908: 68, + 0x1e909: 68, + 0x1e90a: 68, + 0x1e90b: 68, + 0x1e90c: 68, + 0x1e90d: 68, + 0x1e90e: 68, + 0x1e90f: 68, + 0x1e910: 68, + 0x1e911: 68, + 0x1e912: 68, + 0x1e913: 68, + 0x1e914: 68, + 0x1e915: 68, + 0x1e916: 68, + 0x1e917: 68, + 0x1e918: 68, + 0x1e919: 68, + 0x1e91a: 68, + 0x1e91b: 68, + 0x1e91c: 68, + 0x1e91d: 68, + 0x1e91e: 68, + 0x1e91f: 68, + 0x1e920: 68, + 0x1e921: 68, + 0x1e922: 68, + 0x1e923: 68, + 0x1e924: 68, + 0x1e925: 68, + 0x1e926: 68, + 0x1e927: 68, + 0x1e928: 68, + 0x1e929: 68, + 0x1e92a: 68, + 0x1e92b: 68, + 0x1e92c: 68, + 0x1e92d: 68, + 0x1e92e: 68, + 0x1e92f: 68, + 0x1e930: 68, + 0x1e931: 68, + 0x1e932: 68, + 0x1e933: 68, + 0x1e934: 68, + 0x1e935: 68, + 0x1e936: 68, + 0x1e937: 68, + 0x1e938: 68, + 0x1e939: 68, + 0x1e93a: 68, + 0x1e93b: 68, + 0x1e93c: 68, + 0x1e93d: 68, + 0x1e93e: 68, + 0x1e93f: 68, + 0x1e940: 68, + 0x1e941: 68, + 0x1e942: 68, + 0x1e943: 68, + 0x1e94b: 84, +} +codepoint_classes = { + 'PVALID': ( + 0x2d0000002e, + 0x300000003a, + 0x610000007b, + 0xdf000000f7, + 0xf800000100, + 0x10100000102, + 0x10300000104, + 0x10500000106, + 0x10700000108, + 0x1090000010a, + 0x10b0000010c, + 0x10d0000010e, + 0x10f00000110, + 0x11100000112, + 0x11300000114, + 0x11500000116, + 0x11700000118, + 0x1190000011a, + 0x11b0000011c, + 0x11d0000011e, + 0x11f00000120, + 0x12100000122, + 0x12300000124, + 0x12500000126, + 0x12700000128, + 0x1290000012a, + 0x12b0000012c, + 0x12d0000012e, + 0x12f00000130, + 0x13100000132, + 0x13500000136, + 0x13700000139, + 0x13a0000013b, + 0x13c0000013d, + 0x13e0000013f, + 0x14200000143, + 0x14400000145, + 0x14600000147, + 0x14800000149, + 0x14b0000014c, + 0x14d0000014e, + 0x14f00000150, + 0x15100000152, + 0x15300000154, + 0x15500000156, + 0x15700000158, + 0x1590000015a, + 0x15b0000015c, + 0x15d0000015e, + 0x15f00000160, + 0x16100000162, + 0x16300000164, + 0x16500000166, + 0x16700000168, + 0x1690000016a, + 0x16b0000016c, + 0x16d0000016e, + 0x16f00000170, + 0x17100000172, + 0x17300000174, + 0x17500000176, + 0x17700000178, + 0x17a0000017b, + 0x17c0000017d, + 0x17e0000017f, + 0x18000000181, + 0x18300000184, + 0x18500000186, + 0x18800000189, + 0x18c0000018e, + 0x19200000193, + 0x19500000196, + 0x1990000019c, + 0x19e0000019f, + 0x1a1000001a2, + 0x1a3000001a4, + 0x1a5000001a6, + 0x1a8000001a9, + 0x1aa000001ac, + 0x1ad000001ae, + 0x1b0000001b1, + 0x1b4000001b5, + 0x1b6000001b7, + 0x1b9000001bc, + 0x1bd000001c4, + 0x1ce000001cf, + 0x1d0000001d1, + 0x1d2000001d3, + 0x1d4000001d5, + 0x1d6000001d7, + 0x1d8000001d9, + 0x1da000001db, + 0x1dc000001de, + 0x1df000001e0, + 0x1e1000001e2, + 0x1e3000001e4, + 0x1e5000001e6, + 0x1e7000001e8, + 0x1e9000001ea, + 0x1eb000001ec, + 0x1ed000001ee, + 0x1ef000001f1, + 0x1f5000001f6, + 0x1f9000001fa, + 0x1fb000001fc, + 0x1fd000001fe, + 0x1ff00000200, + 0x20100000202, + 0x20300000204, + 0x20500000206, + 0x20700000208, + 0x2090000020a, + 0x20b0000020c, + 0x20d0000020e, + 0x20f00000210, + 0x21100000212, + 0x21300000214, + 0x21500000216, + 0x21700000218, + 0x2190000021a, + 0x21b0000021c, + 0x21d0000021e, + 0x21f00000220, + 0x22100000222, + 0x22300000224, + 0x22500000226, + 0x22700000228, + 0x2290000022a, + 0x22b0000022c, + 0x22d0000022e, + 0x22f00000230, + 0x23100000232, + 0x2330000023a, + 0x23c0000023d, + 0x23f00000241, + 0x24200000243, + 0x24700000248, + 0x2490000024a, + 0x24b0000024c, + 0x24d0000024e, + 0x24f000002b0, + 0x2b9000002c2, + 0x2c6000002d2, + 0x2ec000002ed, + 0x2ee000002ef, + 0x30000000340, + 0x34200000343, + 0x3460000034f, + 0x35000000370, + 0x37100000372, + 0x37300000374, + 0x37700000378, + 0x37b0000037e, + 0x39000000391, + 0x3ac000003cf, + 0x3d7000003d8, + 0x3d9000003da, + 0x3db000003dc, + 0x3dd000003de, + 0x3df000003e0, + 0x3e1000003e2, + 0x3e3000003e4, + 0x3e5000003e6, + 0x3e7000003e8, + 0x3e9000003ea, + 0x3eb000003ec, + 0x3ed000003ee, + 0x3ef000003f0, + 0x3f3000003f4, + 0x3f8000003f9, + 0x3fb000003fd, + 0x43000000460, + 0x46100000462, + 0x46300000464, + 0x46500000466, + 0x46700000468, + 0x4690000046a, + 0x46b0000046c, + 0x46d0000046e, + 0x46f00000470, + 0x47100000472, + 0x47300000474, + 0x47500000476, + 0x47700000478, + 0x4790000047a, + 0x47b0000047c, + 0x47d0000047e, + 0x47f00000480, + 0x48100000482, + 0x48300000488, + 0x48b0000048c, + 0x48d0000048e, + 0x48f00000490, + 0x49100000492, + 0x49300000494, + 0x49500000496, + 0x49700000498, + 0x4990000049a, + 0x49b0000049c, + 0x49d0000049e, + 0x49f000004a0, + 0x4a1000004a2, + 0x4a3000004a4, + 0x4a5000004a6, + 0x4a7000004a8, + 0x4a9000004aa, + 0x4ab000004ac, + 0x4ad000004ae, + 0x4af000004b0, + 0x4b1000004b2, + 0x4b3000004b4, + 0x4b5000004b6, + 0x4b7000004b8, + 0x4b9000004ba, + 0x4bb000004bc, + 0x4bd000004be, + 0x4bf000004c0, + 0x4c2000004c3, + 0x4c4000004c5, + 0x4c6000004c7, + 0x4c8000004c9, + 0x4ca000004cb, + 0x4cc000004cd, + 0x4ce000004d0, + 0x4d1000004d2, + 0x4d3000004d4, + 0x4d5000004d6, + 0x4d7000004d8, + 0x4d9000004da, + 0x4db000004dc, + 0x4dd000004de, + 0x4df000004e0, + 0x4e1000004e2, + 0x4e3000004e4, + 0x4e5000004e6, + 0x4e7000004e8, + 0x4e9000004ea, + 0x4eb000004ec, + 0x4ed000004ee, + 0x4ef000004f0, + 0x4f1000004f2, + 0x4f3000004f4, + 0x4f5000004f6, + 0x4f7000004f8, + 0x4f9000004fa, + 0x4fb000004fc, + 0x4fd000004fe, + 0x4ff00000500, + 0x50100000502, + 0x50300000504, + 0x50500000506, + 0x50700000508, + 0x5090000050a, + 0x50b0000050c, + 0x50d0000050e, + 0x50f00000510, + 0x51100000512, + 0x51300000514, + 0x51500000516, + 0x51700000518, + 0x5190000051a, + 0x51b0000051c, + 0x51d0000051e, + 0x51f00000520, + 0x52100000522, + 0x52300000524, + 0x52500000526, + 0x52700000528, + 0x5290000052a, + 0x52b0000052c, + 0x52d0000052e, + 0x52f00000530, + 0x5590000055a, + 0x56000000587, + 0x58800000589, + 0x591000005be, + 0x5bf000005c0, + 0x5c1000005c3, + 0x5c4000005c6, + 0x5c7000005c8, + 0x5d0000005eb, + 0x5ef000005f3, + 0x6100000061b, + 0x62000000640, + 0x64100000660, + 0x66e00000675, + 0x679000006d4, + 0x6d5000006dd, + 0x6df000006e9, + 0x6ea000006f0, + 0x6fa00000700, + 0x7100000074b, + 0x74d000007b2, + 0x7c0000007f6, + 0x7fd000007fe, + 0x8000000082e, + 0x8400000085c, + 0x8600000086b, + 0x8a0000008b5, + 0x8b6000008c8, + 0x8d3000008e2, + 0x8e300000958, + 0x96000000964, + 0x96600000970, + 0x97100000984, + 0x9850000098d, + 0x98f00000991, + 0x993000009a9, + 0x9aa000009b1, + 0x9b2000009b3, + 0x9b6000009ba, + 0x9bc000009c5, + 0x9c7000009c9, + 0x9cb000009cf, + 0x9d7000009d8, + 0x9e0000009e4, + 0x9e6000009f2, + 0x9fc000009fd, + 0x9fe000009ff, + 0xa0100000a04, + 0xa0500000a0b, + 0xa0f00000a11, + 0xa1300000a29, + 0xa2a00000a31, + 0xa3200000a33, + 0xa3500000a36, + 0xa3800000a3a, + 0xa3c00000a3d, + 0xa3e00000a43, + 0xa4700000a49, + 0xa4b00000a4e, + 0xa5100000a52, + 0xa5c00000a5d, + 0xa6600000a76, + 0xa8100000a84, + 0xa8500000a8e, + 0xa8f00000a92, + 0xa9300000aa9, + 0xaaa00000ab1, + 0xab200000ab4, + 0xab500000aba, + 0xabc00000ac6, + 0xac700000aca, + 0xacb00000ace, + 0xad000000ad1, + 0xae000000ae4, + 0xae600000af0, + 0xaf900000b00, + 0xb0100000b04, + 0xb0500000b0d, + 0xb0f00000b11, + 0xb1300000b29, + 0xb2a00000b31, + 0xb3200000b34, + 0xb3500000b3a, + 0xb3c00000b45, + 0xb4700000b49, + 0xb4b00000b4e, + 0xb5500000b58, + 0xb5f00000b64, + 0xb6600000b70, + 0xb7100000b72, + 0xb8200000b84, + 0xb8500000b8b, + 0xb8e00000b91, + 0xb9200000b96, + 0xb9900000b9b, + 0xb9c00000b9d, + 0xb9e00000ba0, + 0xba300000ba5, + 0xba800000bab, + 0xbae00000bba, + 0xbbe00000bc3, + 0xbc600000bc9, + 0xbca00000bce, + 0xbd000000bd1, + 0xbd700000bd8, + 0xbe600000bf0, + 0xc0000000c0d, + 0xc0e00000c11, + 0xc1200000c29, + 0xc2a00000c3a, + 0xc3d00000c45, + 0xc4600000c49, + 0xc4a00000c4e, + 0xc5500000c57, + 0xc5800000c5b, + 0xc6000000c64, + 0xc6600000c70, + 0xc8000000c84, + 0xc8500000c8d, + 0xc8e00000c91, + 0xc9200000ca9, + 0xcaa00000cb4, + 0xcb500000cba, + 0xcbc00000cc5, + 0xcc600000cc9, + 0xcca00000cce, + 0xcd500000cd7, + 0xcde00000cdf, + 0xce000000ce4, + 0xce600000cf0, + 0xcf100000cf3, + 0xd0000000d0d, + 0xd0e00000d11, + 0xd1200000d45, + 0xd4600000d49, + 0xd4a00000d4f, + 0xd5400000d58, + 0xd5f00000d64, + 0xd6600000d70, + 0xd7a00000d80, + 0xd8100000d84, + 0xd8500000d97, + 0xd9a00000db2, + 0xdb300000dbc, + 0xdbd00000dbe, + 0xdc000000dc7, + 0xdca00000dcb, + 0xdcf00000dd5, + 0xdd600000dd7, + 0xdd800000de0, + 0xde600000df0, + 0xdf200000df4, + 0xe0100000e33, + 0xe3400000e3b, + 0xe4000000e4f, + 0xe5000000e5a, + 0xe8100000e83, + 0xe8400000e85, + 0xe8600000e8b, + 0xe8c00000ea4, + 0xea500000ea6, + 0xea700000eb3, + 0xeb400000ebe, + 0xec000000ec5, + 0xec600000ec7, + 0xec800000ece, + 0xed000000eda, + 0xede00000ee0, + 0xf0000000f01, + 0xf0b00000f0c, + 0xf1800000f1a, + 0xf2000000f2a, + 0xf3500000f36, + 0xf3700000f38, + 0xf3900000f3a, + 0xf3e00000f43, + 0xf4400000f48, + 0xf4900000f4d, + 0xf4e00000f52, + 0xf5300000f57, + 0xf5800000f5c, + 0xf5d00000f69, + 0xf6a00000f6d, + 0xf7100000f73, + 0xf7400000f75, + 0xf7a00000f81, + 0xf8200000f85, + 0xf8600000f93, + 0xf9400000f98, + 0xf9900000f9d, + 0xf9e00000fa2, + 0xfa300000fa7, + 0xfa800000fac, + 0xfad00000fb9, + 0xfba00000fbd, + 0xfc600000fc7, + 0x10000000104a, + 0x10500000109e, + 0x10d0000010fb, + 0x10fd00001100, + 0x120000001249, + 0x124a0000124e, + 0x125000001257, + 0x125800001259, + 0x125a0000125e, + 0x126000001289, + 0x128a0000128e, + 0x1290000012b1, + 0x12b2000012b6, + 0x12b8000012bf, + 0x12c0000012c1, + 0x12c2000012c6, + 0x12c8000012d7, + 0x12d800001311, + 0x131200001316, + 0x13180000135b, + 0x135d00001360, + 0x138000001390, + 0x13a0000013f6, + 0x14010000166d, + 0x166f00001680, + 0x16810000169b, + 0x16a0000016eb, + 0x16f1000016f9, + 0x17000000170d, + 0x170e00001715, + 0x172000001735, + 0x174000001754, + 0x17600000176d, + 0x176e00001771, + 0x177200001774, + 0x1780000017b4, + 0x17b6000017d4, + 0x17d7000017d8, + 0x17dc000017de, + 0x17e0000017ea, + 0x18100000181a, + 0x182000001879, + 0x1880000018ab, + 0x18b0000018f6, + 0x19000000191f, + 0x19200000192c, + 0x19300000193c, + 0x19460000196e, + 0x197000001975, + 0x1980000019ac, + 0x19b0000019ca, + 0x19d0000019da, + 0x1a0000001a1c, + 0x1a2000001a5f, + 0x1a6000001a7d, + 0x1a7f00001a8a, + 0x1a9000001a9a, + 0x1aa700001aa8, + 0x1ab000001abe, + 0x1abf00001ac1, + 0x1b0000001b4c, + 0x1b5000001b5a, + 0x1b6b00001b74, + 0x1b8000001bf4, + 0x1c0000001c38, + 0x1c4000001c4a, + 0x1c4d00001c7e, + 0x1cd000001cd3, + 0x1cd400001cfb, + 0x1d0000001d2c, + 0x1d2f00001d30, + 0x1d3b00001d3c, + 0x1d4e00001d4f, + 0x1d6b00001d78, + 0x1d7900001d9b, + 0x1dc000001dfa, + 0x1dfb00001e00, + 0x1e0100001e02, + 0x1e0300001e04, + 0x1e0500001e06, + 0x1e0700001e08, + 0x1e0900001e0a, + 0x1e0b00001e0c, + 0x1e0d00001e0e, + 0x1e0f00001e10, + 0x1e1100001e12, + 0x1e1300001e14, + 0x1e1500001e16, + 0x1e1700001e18, + 0x1e1900001e1a, + 0x1e1b00001e1c, + 0x1e1d00001e1e, + 0x1e1f00001e20, + 0x1e2100001e22, + 0x1e2300001e24, + 0x1e2500001e26, + 0x1e2700001e28, + 0x1e2900001e2a, + 0x1e2b00001e2c, + 0x1e2d00001e2e, + 0x1e2f00001e30, + 0x1e3100001e32, + 0x1e3300001e34, + 0x1e3500001e36, + 0x1e3700001e38, + 0x1e3900001e3a, + 0x1e3b00001e3c, + 0x1e3d00001e3e, + 0x1e3f00001e40, + 0x1e4100001e42, + 0x1e4300001e44, + 0x1e4500001e46, + 0x1e4700001e48, + 0x1e4900001e4a, + 0x1e4b00001e4c, + 0x1e4d00001e4e, + 0x1e4f00001e50, + 0x1e5100001e52, + 0x1e5300001e54, + 0x1e5500001e56, + 0x1e5700001e58, + 0x1e5900001e5a, + 0x1e5b00001e5c, + 0x1e5d00001e5e, + 0x1e5f00001e60, + 0x1e6100001e62, + 0x1e6300001e64, + 0x1e6500001e66, + 0x1e6700001e68, + 0x1e6900001e6a, + 0x1e6b00001e6c, + 0x1e6d00001e6e, + 0x1e6f00001e70, + 0x1e7100001e72, + 0x1e7300001e74, + 0x1e7500001e76, + 0x1e7700001e78, + 0x1e7900001e7a, + 0x1e7b00001e7c, + 0x1e7d00001e7e, + 0x1e7f00001e80, + 0x1e8100001e82, + 0x1e8300001e84, + 0x1e8500001e86, + 0x1e8700001e88, + 0x1e8900001e8a, + 0x1e8b00001e8c, + 0x1e8d00001e8e, + 0x1e8f00001e90, + 0x1e9100001e92, + 0x1e9300001e94, + 0x1e9500001e9a, + 0x1e9c00001e9e, + 0x1e9f00001ea0, + 0x1ea100001ea2, + 0x1ea300001ea4, + 0x1ea500001ea6, + 0x1ea700001ea8, + 0x1ea900001eaa, + 0x1eab00001eac, + 0x1ead00001eae, + 0x1eaf00001eb0, + 0x1eb100001eb2, + 0x1eb300001eb4, + 0x1eb500001eb6, + 0x1eb700001eb8, + 0x1eb900001eba, + 0x1ebb00001ebc, + 0x1ebd00001ebe, + 0x1ebf00001ec0, + 0x1ec100001ec2, + 0x1ec300001ec4, + 0x1ec500001ec6, + 0x1ec700001ec8, + 0x1ec900001eca, + 0x1ecb00001ecc, + 0x1ecd00001ece, + 0x1ecf00001ed0, + 0x1ed100001ed2, + 0x1ed300001ed4, + 0x1ed500001ed6, + 0x1ed700001ed8, + 0x1ed900001eda, + 0x1edb00001edc, + 0x1edd00001ede, + 0x1edf00001ee0, + 0x1ee100001ee2, + 0x1ee300001ee4, + 0x1ee500001ee6, + 0x1ee700001ee8, + 0x1ee900001eea, + 0x1eeb00001eec, + 0x1eed00001eee, + 0x1eef00001ef0, + 0x1ef100001ef2, + 0x1ef300001ef4, + 0x1ef500001ef6, + 0x1ef700001ef8, + 0x1ef900001efa, + 0x1efb00001efc, + 0x1efd00001efe, + 0x1eff00001f08, + 0x1f1000001f16, + 0x1f2000001f28, + 0x1f3000001f38, + 0x1f4000001f46, + 0x1f5000001f58, + 0x1f6000001f68, + 0x1f7000001f71, + 0x1f7200001f73, + 0x1f7400001f75, + 0x1f7600001f77, + 0x1f7800001f79, + 0x1f7a00001f7b, + 0x1f7c00001f7d, + 0x1fb000001fb2, + 0x1fb600001fb7, + 0x1fc600001fc7, + 0x1fd000001fd3, + 0x1fd600001fd8, + 0x1fe000001fe3, + 0x1fe400001fe8, + 0x1ff600001ff7, + 0x214e0000214f, + 0x218400002185, + 0x2c3000002c5f, + 0x2c6100002c62, + 0x2c6500002c67, + 0x2c6800002c69, + 0x2c6a00002c6b, + 0x2c6c00002c6d, + 0x2c7100002c72, + 0x2c7300002c75, + 0x2c7600002c7c, + 0x2c8100002c82, + 0x2c8300002c84, + 0x2c8500002c86, + 0x2c8700002c88, + 0x2c8900002c8a, + 0x2c8b00002c8c, + 0x2c8d00002c8e, + 0x2c8f00002c90, + 0x2c9100002c92, + 0x2c9300002c94, + 0x2c9500002c96, + 0x2c9700002c98, + 0x2c9900002c9a, + 0x2c9b00002c9c, + 0x2c9d00002c9e, + 0x2c9f00002ca0, + 0x2ca100002ca2, + 0x2ca300002ca4, + 0x2ca500002ca6, + 0x2ca700002ca8, + 0x2ca900002caa, + 0x2cab00002cac, + 0x2cad00002cae, + 0x2caf00002cb0, + 0x2cb100002cb2, + 0x2cb300002cb4, + 0x2cb500002cb6, + 0x2cb700002cb8, + 0x2cb900002cba, + 0x2cbb00002cbc, + 0x2cbd00002cbe, + 0x2cbf00002cc0, + 0x2cc100002cc2, + 0x2cc300002cc4, + 0x2cc500002cc6, + 0x2cc700002cc8, + 0x2cc900002cca, + 0x2ccb00002ccc, + 0x2ccd00002cce, + 0x2ccf00002cd0, + 0x2cd100002cd2, + 0x2cd300002cd4, + 0x2cd500002cd6, + 0x2cd700002cd8, + 0x2cd900002cda, + 0x2cdb00002cdc, + 0x2cdd00002cde, + 0x2cdf00002ce0, + 0x2ce100002ce2, + 0x2ce300002ce5, + 0x2cec00002ced, + 0x2cee00002cf2, + 0x2cf300002cf4, + 0x2d0000002d26, + 0x2d2700002d28, + 0x2d2d00002d2e, + 0x2d3000002d68, + 0x2d7f00002d97, + 0x2da000002da7, + 0x2da800002daf, + 0x2db000002db7, + 0x2db800002dbf, + 0x2dc000002dc7, + 0x2dc800002dcf, + 0x2dd000002dd7, + 0x2dd800002ddf, + 0x2de000002e00, + 0x2e2f00002e30, + 0x300500003008, + 0x302a0000302e, + 0x303c0000303d, + 0x304100003097, + 0x30990000309b, + 0x309d0000309f, + 0x30a1000030fb, + 0x30fc000030ff, + 0x310500003130, + 0x31a0000031c0, + 0x31f000003200, + 0x340000004dc0, + 0x4e0000009ffd, + 0xa0000000a48d, + 0xa4d00000a4fe, + 0xa5000000a60d, + 0xa6100000a62c, + 0xa6410000a642, + 0xa6430000a644, + 0xa6450000a646, + 0xa6470000a648, + 0xa6490000a64a, + 0xa64b0000a64c, + 0xa64d0000a64e, + 0xa64f0000a650, + 0xa6510000a652, + 0xa6530000a654, + 0xa6550000a656, + 0xa6570000a658, + 0xa6590000a65a, + 0xa65b0000a65c, + 0xa65d0000a65e, + 0xa65f0000a660, + 0xa6610000a662, + 0xa6630000a664, + 0xa6650000a666, + 0xa6670000a668, + 0xa6690000a66a, + 0xa66b0000a66c, + 0xa66d0000a670, + 0xa6740000a67e, + 0xa67f0000a680, + 0xa6810000a682, + 0xa6830000a684, + 0xa6850000a686, + 0xa6870000a688, + 0xa6890000a68a, + 0xa68b0000a68c, + 0xa68d0000a68e, + 0xa68f0000a690, + 0xa6910000a692, + 0xa6930000a694, + 0xa6950000a696, + 0xa6970000a698, + 0xa6990000a69a, + 0xa69b0000a69c, + 0xa69e0000a6e6, + 0xa6f00000a6f2, + 0xa7170000a720, + 0xa7230000a724, + 0xa7250000a726, + 0xa7270000a728, + 0xa7290000a72a, + 0xa72b0000a72c, + 0xa72d0000a72e, + 0xa72f0000a732, + 0xa7330000a734, + 0xa7350000a736, + 0xa7370000a738, + 0xa7390000a73a, + 0xa73b0000a73c, + 0xa73d0000a73e, + 0xa73f0000a740, + 0xa7410000a742, + 0xa7430000a744, + 0xa7450000a746, + 0xa7470000a748, + 0xa7490000a74a, + 0xa74b0000a74c, + 0xa74d0000a74e, + 0xa74f0000a750, + 0xa7510000a752, + 0xa7530000a754, + 0xa7550000a756, + 0xa7570000a758, + 0xa7590000a75a, + 0xa75b0000a75c, + 0xa75d0000a75e, + 0xa75f0000a760, + 0xa7610000a762, + 0xa7630000a764, + 0xa7650000a766, + 0xa7670000a768, + 0xa7690000a76a, + 0xa76b0000a76c, + 0xa76d0000a76e, + 0xa76f0000a770, + 0xa7710000a779, + 0xa77a0000a77b, + 0xa77c0000a77d, + 0xa77f0000a780, + 0xa7810000a782, + 0xa7830000a784, + 0xa7850000a786, + 0xa7870000a789, + 0xa78c0000a78d, + 0xa78e0000a790, + 0xa7910000a792, + 0xa7930000a796, + 0xa7970000a798, + 0xa7990000a79a, + 0xa79b0000a79c, + 0xa79d0000a79e, + 0xa79f0000a7a0, + 0xa7a10000a7a2, + 0xa7a30000a7a4, + 0xa7a50000a7a6, + 0xa7a70000a7a8, + 0xa7a90000a7aa, + 0xa7af0000a7b0, + 0xa7b50000a7b6, + 0xa7b70000a7b8, + 0xa7b90000a7ba, + 0xa7bb0000a7bc, + 0xa7bd0000a7be, + 0xa7bf0000a7c0, + 0xa7c30000a7c4, + 0xa7c80000a7c9, + 0xa7ca0000a7cb, + 0xa7f60000a7f8, + 0xa7fa0000a828, + 0xa82c0000a82d, + 0xa8400000a874, + 0xa8800000a8c6, + 0xa8d00000a8da, + 0xa8e00000a8f8, + 0xa8fb0000a8fc, + 0xa8fd0000a92e, + 0xa9300000a954, + 0xa9800000a9c1, + 0xa9cf0000a9da, + 0xa9e00000a9ff, + 0xaa000000aa37, + 0xaa400000aa4e, + 0xaa500000aa5a, + 0xaa600000aa77, + 0xaa7a0000aac3, + 0xaadb0000aade, + 0xaae00000aaf0, + 0xaaf20000aaf7, + 0xab010000ab07, + 0xab090000ab0f, + 0xab110000ab17, + 0xab200000ab27, + 0xab280000ab2f, + 0xab300000ab5b, + 0xab600000ab6a, + 0xabc00000abeb, + 0xabec0000abee, + 0xabf00000abfa, + 0xac000000d7a4, + 0xfa0e0000fa10, + 0xfa110000fa12, + 0xfa130000fa15, + 0xfa1f0000fa20, + 0xfa210000fa22, + 0xfa230000fa25, + 0xfa270000fa2a, + 0xfb1e0000fb1f, + 0xfe200000fe30, + 0xfe730000fe74, + 0x100000001000c, + 0x1000d00010027, + 0x100280001003b, + 0x1003c0001003e, + 0x1003f0001004e, + 0x100500001005e, + 0x10080000100fb, + 0x101fd000101fe, + 0x102800001029d, + 0x102a0000102d1, + 0x102e0000102e1, + 0x1030000010320, + 0x1032d00010341, + 0x103420001034a, + 0x103500001037b, + 0x103800001039e, + 0x103a0000103c4, + 0x103c8000103d0, + 0x104280001049e, + 0x104a0000104aa, + 0x104d8000104fc, + 0x1050000010528, + 0x1053000010564, + 0x1060000010737, + 0x1074000010756, + 0x1076000010768, + 0x1080000010806, + 0x1080800010809, + 0x1080a00010836, + 0x1083700010839, + 0x1083c0001083d, + 0x1083f00010856, + 0x1086000010877, + 0x108800001089f, + 0x108e0000108f3, + 0x108f4000108f6, + 0x1090000010916, + 0x109200001093a, + 0x10980000109b8, + 0x109be000109c0, + 0x10a0000010a04, + 0x10a0500010a07, + 0x10a0c00010a14, + 0x10a1500010a18, + 0x10a1900010a36, + 0x10a3800010a3b, + 0x10a3f00010a40, + 0x10a6000010a7d, + 0x10a8000010a9d, + 0x10ac000010ac8, + 0x10ac900010ae7, + 0x10b0000010b36, + 0x10b4000010b56, + 0x10b6000010b73, + 0x10b8000010b92, + 0x10c0000010c49, + 0x10cc000010cf3, + 0x10d0000010d28, + 0x10d3000010d3a, + 0x10e8000010eaa, + 0x10eab00010ead, + 0x10eb000010eb2, + 0x10f0000010f1d, + 0x10f2700010f28, + 0x10f3000010f51, + 0x10fb000010fc5, + 0x10fe000010ff7, + 0x1100000011047, + 0x1106600011070, + 0x1107f000110bb, + 0x110d0000110e9, + 0x110f0000110fa, + 0x1110000011135, + 0x1113600011140, + 0x1114400011148, + 0x1115000011174, + 0x1117600011177, + 0x11180000111c5, + 0x111c9000111cd, + 0x111ce000111db, + 0x111dc000111dd, + 0x1120000011212, + 0x1121300011238, + 0x1123e0001123f, + 0x1128000011287, + 0x1128800011289, + 0x1128a0001128e, + 0x1128f0001129e, + 0x1129f000112a9, + 0x112b0000112eb, + 0x112f0000112fa, + 0x1130000011304, + 0x113050001130d, + 0x1130f00011311, + 0x1131300011329, + 0x1132a00011331, + 0x1133200011334, + 0x113350001133a, + 0x1133b00011345, + 0x1134700011349, + 0x1134b0001134e, + 0x1135000011351, + 0x1135700011358, + 0x1135d00011364, + 0x113660001136d, + 0x1137000011375, + 0x114000001144b, + 0x114500001145a, + 0x1145e00011462, + 0x11480000114c6, + 0x114c7000114c8, + 0x114d0000114da, + 0x11580000115b6, + 0x115b8000115c1, + 0x115d8000115de, + 0x1160000011641, + 0x1164400011645, + 0x116500001165a, + 0x11680000116b9, + 0x116c0000116ca, + 0x117000001171b, + 0x1171d0001172c, + 0x117300001173a, + 0x118000001183b, + 0x118c0000118ea, + 0x118ff00011907, + 0x119090001190a, + 0x1190c00011914, + 0x1191500011917, + 0x1191800011936, + 0x1193700011939, + 0x1193b00011944, + 0x119500001195a, + 0x119a0000119a8, + 0x119aa000119d8, + 0x119da000119e2, + 0x119e3000119e5, + 0x11a0000011a3f, + 0x11a4700011a48, + 0x11a5000011a9a, + 0x11a9d00011a9e, + 0x11ac000011af9, + 0x11c0000011c09, + 0x11c0a00011c37, + 0x11c3800011c41, + 0x11c5000011c5a, + 0x11c7200011c90, + 0x11c9200011ca8, + 0x11ca900011cb7, + 0x11d0000011d07, + 0x11d0800011d0a, + 0x11d0b00011d37, + 0x11d3a00011d3b, + 0x11d3c00011d3e, + 0x11d3f00011d48, + 0x11d5000011d5a, + 0x11d6000011d66, + 0x11d6700011d69, + 0x11d6a00011d8f, + 0x11d9000011d92, + 0x11d9300011d99, + 0x11da000011daa, + 0x11ee000011ef7, + 0x11fb000011fb1, + 0x120000001239a, + 0x1248000012544, + 0x130000001342f, + 0x1440000014647, + 0x1680000016a39, + 0x16a4000016a5f, + 0x16a6000016a6a, + 0x16ad000016aee, + 0x16af000016af5, + 0x16b0000016b37, + 0x16b4000016b44, + 0x16b5000016b5a, + 0x16b6300016b78, + 0x16b7d00016b90, + 0x16e6000016e80, + 0x16f0000016f4b, + 0x16f4f00016f88, + 0x16f8f00016fa0, + 0x16fe000016fe2, + 0x16fe300016fe5, + 0x16ff000016ff2, + 0x17000000187f8, + 0x1880000018cd6, + 0x18d0000018d09, + 0x1b0000001b11f, + 0x1b1500001b153, + 0x1b1640001b168, + 0x1b1700001b2fc, + 0x1bc000001bc6b, + 0x1bc700001bc7d, + 0x1bc800001bc89, + 0x1bc900001bc9a, + 0x1bc9d0001bc9f, + 0x1da000001da37, + 0x1da3b0001da6d, + 0x1da750001da76, + 0x1da840001da85, + 0x1da9b0001daa0, + 0x1daa10001dab0, + 0x1e0000001e007, + 0x1e0080001e019, + 0x1e01b0001e022, + 0x1e0230001e025, + 0x1e0260001e02b, + 0x1e1000001e12d, + 0x1e1300001e13e, + 0x1e1400001e14a, + 0x1e14e0001e14f, + 0x1e2c00001e2fa, + 0x1e8000001e8c5, + 0x1e8d00001e8d7, + 0x1e9220001e94c, + 0x1e9500001e95a, + 0x1fbf00001fbfa, + 0x200000002a6de, + 0x2a7000002b735, + 0x2b7400002b81e, + 0x2b8200002cea2, + 0x2ceb00002ebe1, + 0x300000003134b, + ), + 'CONTEXTJ': ( + 0x200c0000200e, + ), + 'CONTEXTO': ( + 0xb7000000b8, + 0x37500000376, + 0x5f3000005f5, + 0x6600000066a, + 0x6f0000006fa, + 0x30fb000030fc, + ), +} diff --git a/venv/lib/python3.8/site-packages/idna/intranges.py b/venv/lib/python3.8/site-packages/idna/intranges.py new file mode 100644 index 0000000..fa8a735 --- /dev/null +++ b/venv/lib/python3.8/site-packages/idna/intranges.py @@ -0,0 +1,53 @@ +""" +Given a list of integers, made up of (hopefully) a small number of long runs +of consecutive integers, compute a representation of the form +((start1, end1), (start2, end2) ...). Then answer the question "was x present +in the original list?" in time O(log(# runs)). +""" + +import bisect + +def intranges_from_list(list_): + """Represent a list of integers as a sequence of ranges: + ((start_0, end_0), (start_1, end_1), ...), such that the original + integers are exactly those x such that start_i <= x < end_i for some i. + + Ranges are encoded as single integers (start << 32 | end), not as tuples. + """ + + sorted_list = sorted(list_) + ranges = [] + last_write = -1 + for i in range(len(sorted_list)): + if i+1 < len(sorted_list): + if sorted_list[i] == sorted_list[i+1]-1: + continue + current_range = sorted_list[last_write+1:i+1] + ranges.append(_encode_range(current_range[0], current_range[-1] + 1)) + last_write = i + + return tuple(ranges) + +def _encode_range(start, end): + return (start << 32) | end + +def _decode_range(r): + return (r >> 32), (r & ((1 << 32) - 1)) + + +def intranges_contain(int_, ranges): + """Determine if `int_` falls into one of the ranges in `ranges`.""" + tuple_ = _encode_range(int_, 0) + pos = bisect.bisect_left(ranges, tuple_) + # we could be immediately ahead of a tuple (start, end) + # with start < int_ <= end + if pos > 0: + left, right = _decode_range(ranges[pos-1]) + if left <= int_ < right: + return True + # or we could be immediately behind a tuple (int_, end) + if pos < len(ranges): + left, _ = _decode_range(ranges[pos]) + if left == int_: + return True + return False diff --git a/venv/lib/python3.8/site-packages/idna/package_data.py b/venv/lib/python3.8/site-packages/idna/package_data.py new file mode 100644 index 0000000..ce1c521 --- /dev/null +++ b/venv/lib/python3.8/site-packages/idna/package_data.py @@ -0,0 +1,2 @@ +__version__ = '2.10' + diff --git a/venv/lib/python3.8/site-packages/idna/uts46data.py b/venv/lib/python3.8/site-packages/idna/uts46data.py new file mode 100644 index 0000000..3766dd4 --- /dev/null +++ b/venv/lib/python3.8/site-packages/idna/uts46data.py @@ -0,0 +1,8357 @@ +# This file is automatically generated by tools/idna-data +# vim: set fileencoding=utf-8 : + +"""IDNA Mapping Table from UTS46.""" + + +__version__ = "13.0.0" +def _seg_0(): + return [ + (0x0, '3'), + (0x1, '3'), + (0x2, '3'), + (0x3, '3'), + (0x4, '3'), + (0x5, '3'), + (0x6, '3'), + (0x7, '3'), + (0x8, '3'), + (0x9, '3'), + (0xA, '3'), + (0xB, '3'), + (0xC, '3'), + (0xD, '3'), + (0xE, '3'), + (0xF, '3'), + (0x10, '3'), + (0x11, '3'), + (0x12, '3'), + (0x13, '3'), + (0x14, '3'), + (0x15, '3'), + (0x16, '3'), + (0x17, '3'), + (0x18, '3'), + (0x19, '3'), + (0x1A, '3'), + (0x1B, '3'), + (0x1C, '3'), + (0x1D, '3'), + (0x1E, '3'), + (0x1F, '3'), + (0x20, '3'), + (0x21, '3'), + (0x22, '3'), + (0x23, '3'), + (0x24, '3'), + (0x25, '3'), + (0x26, '3'), + (0x27, '3'), + (0x28, '3'), + (0x29, '3'), + (0x2A, '3'), + (0x2B, '3'), + (0x2C, '3'), + (0x2D, 'V'), + (0x2E, 'V'), + (0x2F, '3'), + (0x30, 'V'), + (0x31, 'V'), + (0x32, 'V'), + (0x33, 'V'), + (0x34, 'V'), + (0x35, 'V'), + (0x36, 'V'), + (0x37, 'V'), + (0x38, 'V'), + (0x39, 'V'), + (0x3A, '3'), + (0x3B, '3'), + (0x3C, '3'), + (0x3D, '3'), + (0x3E, '3'), + (0x3F, '3'), + (0x40, '3'), + (0x41, 'M', u'a'), + (0x42, 'M', u'b'), + (0x43, 'M', u'c'), + (0x44, 'M', u'd'), + (0x45, 'M', u'e'), + (0x46, 'M', u'f'), + (0x47, 'M', u'g'), + (0x48, 'M', u'h'), + (0x49, 'M', u'i'), + (0x4A, 'M', u'j'), + (0x4B, 'M', u'k'), + (0x4C, 'M', u'l'), + (0x4D, 'M', u'm'), + (0x4E, 'M', u'n'), + (0x4F, 'M', u'o'), + (0x50, 'M', u'p'), + (0x51, 'M', u'q'), + (0x52, 'M', u'r'), + (0x53, 'M', u's'), + (0x54, 'M', u't'), + (0x55, 'M', u'u'), + (0x56, 'M', u'v'), + (0x57, 'M', u'w'), + (0x58, 'M', u'x'), + (0x59, 'M', u'y'), + (0x5A, 'M', u'z'), + (0x5B, '3'), + (0x5C, '3'), + (0x5D, '3'), + (0x5E, '3'), + (0x5F, '3'), + (0x60, '3'), + (0x61, 'V'), + (0x62, 'V'), + (0x63, 'V'), + ] + +def _seg_1(): + return [ + (0x64, 'V'), + (0x65, 'V'), + (0x66, 'V'), + (0x67, 'V'), + (0x68, 'V'), + (0x69, 'V'), + (0x6A, 'V'), + (0x6B, 'V'), + (0x6C, 'V'), + (0x6D, 'V'), + (0x6E, 'V'), + (0x6F, 'V'), + (0x70, 'V'), + (0x71, 'V'), + (0x72, 'V'), + (0x73, 'V'), + (0x74, 'V'), + (0x75, 'V'), + (0x76, 'V'), + (0x77, 'V'), + (0x78, 'V'), + (0x79, 'V'), + (0x7A, 'V'), + (0x7B, '3'), + (0x7C, '3'), + (0x7D, '3'), + (0x7E, '3'), + (0x7F, '3'), + (0x80, 'X'), + (0x81, 'X'), + (0x82, 'X'), + (0x83, 'X'), + (0x84, 'X'), + (0x85, 'X'), + (0x86, 'X'), + (0x87, 'X'), + (0x88, 'X'), + (0x89, 'X'), + (0x8A, 'X'), + (0x8B, 'X'), + (0x8C, 'X'), + (0x8D, 'X'), + (0x8E, 'X'), + (0x8F, 'X'), + (0x90, 'X'), + (0x91, 'X'), + (0x92, 'X'), + (0x93, 'X'), + (0x94, 'X'), + (0x95, 'X'), + (0x96, 'X'), + (0x97, 'X'), + (0x98, 'X'), + (0x99, 'X'), + (0x9A, 'X'), + (0x9B, 'X'), + (0x9C, 'X'), + (0x9D, 'X'), + (0x9E, 'X'), + (0x9F, 'X'), + (0xA0, '3', u' '), + (0xA1, 'V'), + (0xA2, 'V'), + (0xA3, 'V'), + (0xA4, 'V'), + (0xA5, 'V'), + (0xA6, 'V'), + (0xA7, 'V'), + (0xA8, '3', u' ̈'), + (0xA9, 'V'), + (0xAA, 'M', u'a'), + (0xAB, 'V'), + (0xAC, 'V'), + (0xAD, 'I'), + (0xAE, 'V'), + (0xAF, '3', u' ̄'), + (0xB0, 'V'), + (0xB1, 'V'), + (0xB2, 'M', u'2'), + (0xB3, 'M', u'3'), + (0xB4, '3', u' ́'), + (0xB5, 'M', u'μ'), + (0xB6, 'V'), + (0xB7, 'V'), + (0xB8, '3', u' ̧'), + (0xB9, 'M', u'1'), + (0xBA, 'M', u'o'), + (0xBB, 'V'), + (0xBC, 'M', u'1⁄4'), + (0xBD, 'M', u'1⁄2'), + (0xBE, 'M', u'3⁄4'), + (0xBF, 'V'), + (0xC0, 'M', u'à'), + (0xC1, 'M', u'á'), + (0xC2, 'M', u'â'), + (0xC3, 'M', u'ã'), + (0xC4, 'M', u'ä'), + (0xC5, 'M', u'å'), + (0xC6, 'M', u'æ'), + (0xC7, 'M', u'ç'), + ] + +def _seg_2(): + return [ + (0xC8, 'M', u'è'), + (0xC9, 'M', u'é'), + (0xCA, 'M', u'ê'), + (0xCB, 'M', u'ë'), + (0xCC, 'M', u'ì'), + (0xCD, 'M', u'í'), + (0xCE, 'M', u'î'), + (0xCF, 'M', u'ï'), + (0xD0, 'M', u'ð'), + (0xD1, 'M', u'ñ'), + (0xD2, 'M', u'ò'), + (0xD3, 'M', u'ó'), + (0xD4, 'M', u'ô'), + (0xD5, 'M', u'õ'), + (0xD6, 'M', u'ö'), + (0xD7, 'V'), + (0xD8, 'M', u'ø'), + (0xD9, 'M', u'ù'), + (0xDA, 'M', u'ú'), + (0xDB, 'M', u'û'), + (0xDC, 'M', u'ü'), + (0xDD, 'M', u'ý'), + (0xDE, 'M', u'þ'), + (0xDF, 'D', u'ss'), + (0xE0, 'V'), + (0xE1, 'V'), + (0xE2, 'V'), + (0xE3, 'V'), + (0xE4, 'V'), + (0xE5, 'V'), + (0xE6, 'V'), + (0xE7, 'V'), + (0xE8, 'V'), + (0xE9, 'V'), + (0xEA, 'V'), + (0xEB, 'V'), + (0xEC, 'V'), + (0xED, 'V'), + (0xEE, 'V'), + (0xEF, 'V'), + (0xF0, 'V'), + (0xF1, 'V'), + (0xF2, 'V'), + (0xF3, 'V'), + (0xF4, 'V'), + (0xF5, 'V'), + (0xF6, 'V'), + (0xF7, 'V'), + (0xF8, 'V'), + (0xF9, 'V'), + (0xFA, 'V'), + (0xFB, 'V'), + (0xFC, 'V'), + (0xFD, 'V'), + (0xFE, 'V'), + (0xFF, 'V'), + (0x100, 'M', u'ā'), + (0x101, 'V'), + (0x102, 'M', u'ă'), + (0x103, 'V'), + (0x104, 'M', u'ą'), + (0x105, 'V'), + (0x106, 'M', u'ć'), + (0x107, 'V'), + (0x108, 'M', u'ĉ'), + (0x109, 'V'), + (0x10A, 'M', u'ċ'), + (0x10B, 'V'), + (0x10C, 'M', u'č'), + (0x10D, 'V'), + (0x10E, 'M', u'ď'), + (0x10F, 'V'), + (0x110, 'M', u'đ'), + (0x111, 'V'), + (0x112, 'M', u'ē'), + (0x113, 'V'), + (0x114, 'M', u'ĕ'), + (0x115, 'V'), + (0x116, 'M', u'ė'), + (0x117, 'V'), + (0x118, 'M', u'ę'), + (0x119, 'V'), + (0x11A, 'M', u'ě'), + (0x11B, 'V'), + (0x11C, 'M', u'ĝ'), + (0x11D, 'V'), + (0x11E, 'M', u'ğ'), + (0x11F, 'V'), + (0x120, 'M', u'ġ'), + (0x121, 'V'), + (0x122, 'M', u'ģ'), + (0x123, 'V'), + (0x124, 'M', u'ĥ'), + (0x125, 'V'), + (0x126, 'M', u'ħ'), + (0x127, 'V'), + (0x128, 'M', u'ĩ'), + (0x129, 'V'), + (0x12A, 'M', u'ī'), + (0x12B, 'V'), + ] + +def _seg_3(): + return [ + (0x12C, 'M', u'ĭ'), + (0x12D, 'V'), + (0x12E, 'M', u'į'), + (0x12F, 'V'), + (0x130, 'M', u'i̇'), + (0x131, 'V'), + (0x132, 'M', u'ij'), + (0x134, 'M', u'ĵ'), + (0x135, 'V'), + (0x136, 'M', u'ķ'), + (0x137, 'V'), + (0x139, 'M', u'ĺ'), + (0x13A, 'V'), + (0x13B, 'M', u'ļ'), + (0x13C, 'V'), + (0x13D, 'M', u'ľ'), + (0x13E, 'V'), + (0x13F, 'M', u'l·'), + (0x141, 'M', u'ł'), + (0x142, 'V'), + (0x143, 'M', u'ń'), + (0x144, 'V'), + (0x145, 'M', u'ņ'), + (0x146, 'V'), + (0x147, 'M', u'ň'), + (0x148, 'V'), + (0x149, 'M', u'ʼn'), + (0x14A, 'M', u'ŋ'), + (0x14B, 'V'), + (0x14C, 'M', u'ō'), + (0x14D, 'V'), + (0x14E, 'M', u'ŏ'), + (0x14F, 'V'), + (0x150, 'M', u'ő'), + (0x151, 'V'), + (0x152, 'M', u'œ'), + (0x153, 'V'), + (0x154, 'M', u'ŕ'), + (0x155, 'V'), + (0x156, 'M', u'ŗ'), + (0x157, 'V'), + (0x158, 'M', u'ř'), + (0x159, 'V'), + (0x15A, 'M', u'ś'), + (0x15B, 'V'), + (0x15C, 'M', u'ŝ'), + (0x15D, 'V'), + (0x15E, 'M', u'ş'), + (0x15F, 'V'), + (0x160, 'M', u'š'), + (0x161, 'V'), + (0x162, 'M', u'ţ'), + (0x163, 'V'), + (0x164, 'M', u'ť'), + (0x165, 'V'), + (0x166, 'M', u'ŧ'), + (0x167, 'V'), + (0x168, 'M', u'ũ'), + (0x169, 'V'), + (0x16A, 'M', u'ū'), + (0x16B, 'V'), + (0x16C, 'M', u'ŭ'), + (0x16D, 'V'), + (0x16E, 'M', u'ů'), + (0x16F, 'V'), + (0x170, 'M', u'ű'), + (0x171, 'V'), + (0x172, 'M', u'ų'), + (0x173, 'V'), + (0x174, 'M', u'ŵ'), + (0x175, 'V'), + (0x176, 'M', u'ŷ'), + (0x177, 'V'), + (0x178, 'M', u'ÿ'), + (0x179, 'M', u'ź'), + (0x17A, 'V'), + (0x17B, 'M', u'ż'), + (0x17C, 'V'), + (0x17D, 'M', u'ž'), + (0x17E, 'V'), + (0x17F, 'M', u's'), + (0x180, 'V'), + (0x181, 'M', u'ɓ'), + (0x182, 'M', u'ƃ'), + (0x183, 'V'), + (0x184, 'M', u'ƅ'), + (0x185, 'V'), + (0x186, 'M', u'ɔ'), + (0x187, 'M', u'ƈ'), + (0x188, 'V'), + (0x189, 'M', u'ɖ'), + (0x18A, 'M', u'ɗ'), + (0x18B, 'M', u'ƌ'), + (0x18C, 'V'), + (0x18E, 'M', u'ǝ'), + (0x18F, 'M', u'ə'), + (0x190, 'M', u'ɛ'), + (0x191, 'M', u'ƒ'), + (0x192, 'V'), + (0x193, 'M', u'ɠ'), + ] + +def _seg_4(): + return [ + (0x194, 'M', u'ɣ'), + (0x195, 'V'), + (0x196, 'M', u'ɩ'), + (0x197, 'M', u'ɨ'), + (0x198, 'M', u'ƙ'), + (0x199, 'V'), + (0x19C, 'M', u'ɯ'), + (0x19D, 'M', u'ɲ'), + (0x19E, 'V'), + (0x19F, 'M', u'ɵ'), + (0x1A0, 'M', u'ơ'), + (0x1A1, 'V'), + (0x1A2, 'M', u'ƣ'), + (0x1A3, 'V'), + (0x1A4, 'M', u'ƥ'), + (0x1A5, 'V'), + (0x1A6, 'M', u'ʀ'), + (0x1A7, 'M', u'ƨ'), + (0x1A8, 'V'), + (0x1A9, 'M', u'ʃ'), + (0x1AA, 'V'), + (0x1AC, 'M', u'ƭ'), + (0x1AD, 'V'), + (0x1AE, 'M', u'ʈ'), + (0x1AF, 'M', u'ư'), + (0x1B0, 'V'), + (0x1B1, 'M', u'ʊ'), + (0x1B2, 'M', u'ʋ'), + (0x1B3, 'M', u'ƴ'), + (0x1B4, 'V'), + (0x1B5, 'M', u'ƶ'), + (0x1B6, 'V'), + (0x1B7, 'M', u'ʒ'), + (0x1B8, 'M', u'ƹ'), + (0x1B9, 'V'), + (0x1BC, 'M', u'ƽ'), + (0x1BD, 'V'), + (0x1C4, 'M', u'dž'), + (0x1C7, 'M', u'lj'), + (0x1CA, 'M', u'nj'), + (0x1CD, 'M', u'ǎ'), + (0x1CE, 'V'), + (0x1CF, 'M', u'ǐ'), + (0x1D0, 'V'), + (0x1D1, 'M', u'ǒ'), + (0x1D2, 'V'), + (0x1D3, 'M', u'ǔ'), + (0x1D4, 'V'), + (0x1D5, 'M', u'ǖ'), + (0x1D6, 'V'), + (0x1D7, 'M', u'ǘ'), + (0x1D8, 'V'), + (0x1D9, 'M', u'ǚ'), + (0x1DA, 'V'), + (0x1DB, 'M', u'ǜ'), + (0x1DC, 'V'), + (0x1DE, 'M', u'ǟ'), + (0x1DF, 'V'), + (0x1E0, 'M', u'ǡ'), + (0x1E1, 'V'), + (0x1E2, 'M', u'ǣ'), + (0x1E3, 'V'), + (0x1E4, 'M', u'ǥ'), + (0x1E5, 'V'), + (0x1E6, 'M', u'ǧ'), + (0x1E7, 'V'), + (0x1E8, 'M', u'ǩ'), + (0x1E9, 'V'), + (0x1EA, 'M', u'ǫ'), + (0x1EB, 'V'), + (0x1EC, 'M', u'ǭ'), + (0x1ED, 'V'), + (0x1EE, 'M', u'ǯ'), + (0x1EF, 'V'), + (0x1F1, 'M', u'dz'), + (0x1F4, 'M', u'ǵ'), + (0x1F5, 'V'), + (0x1F6, 'M', u'ƕ'), + (0x1F7, 'M', u'ƿ'), + (0x1F8, 'M', u'ǹ'), + (0x1F9, 'V'), + (0x1FA, 'M', u'ǻ'), + (0x1FB, 'V'), + (0x1FC, 'M', u'ǽ'), + (0x1FD, 'V'), + (0x1FE, 'M', u'ǿ'), + (0x1FF, 'V'), + (0x200, 'M', u'ȁ'), + (0x201, 'V'), + (0x202, 'M', u'ȃ'), + (0x203, 'V'), + (0x204, 'M', u'ȅ'), + (0x205, 'V'), + (0x206, 'M', u'ȇ'), + (0x207, 'V'), + (0x208, 'M', u'ȉ'), + (0x209, 'V'), + (0x20A, 'M', u'ȋ'), + (0x20B, 'V'), + (0x20C, 'M', u'ȍ'), + ] + +def _seg_5(): + return [ + (0x20D, 'V'), + (0x20E, 'M', u'ȏ'), + (0x20F, 'V'), + (0x210, 'M', u'ȑ'), + (0x211, 'V'), + (0x212, 'M', u'ȓ'), + (0x213, 'V'), + (0x214, 'M', u'ȕ'), + (0x215, 'V'), + (0x216, 'M', u'ȗ'), + (0x217, 'V'), + (0x218, 'M', u'ș'), + (0x219, 'V'), + (0x21A, 'M', u'ț'), + (0x21B, 'V'), + (0x21C, 'M', u'ȝ'), + (0x21D, 'V'), + (0x21E, 'M', u'ȟ'), + (0x21F, 'V'), + (0x220, 'M', u'ƞ'), + (0x221, 'V'), + (0x222, 'M', u'ȣ'), + (0x223, 'V'), + (0x224, 'M', u'ȥ'), + (0x225, 'V'), + (0x226, 'M', u'ȧ'), + (0x227, 'V'), + (0x228, 'M', u'ȩ'), + (0x229, 'V'), + (0x22A, 'M', u'ȫ'), + (0x22B, 'V'), + (0x22C, 'M', u'ȭ'), + (0x22D, 'V'), + (0x22E, 'M', u'ȯ'), + (0x22F, 'V'), + (0x230, 'M', u'ȱ'), + (0x231, 'V'), + (0x232, 'M', u'ȳ'), + (0x233, 'V'), + (0x23A, 'M', u'ⱥ'), + (0x23B, 'M', u'ȼ'), + (0x23C, 'V'), + (0x23D, 'M', u'ƚ'), + (0x23E, 'M', u'ⱦ'), + (0x23F, 'V'), + (0x241, 'M', u'ɂ'), + (0x242, 'V'), + (0x243, 'M', u'ƀ'), + (0x244, 'M', u'ʉ'), + (0x245, 'M', u'ʌ'), + (0x246, 'M', u'ɇ'), + (0x247, 'V'), + (0x248, 'M', u'ɉ'), + (0x249, 'V'), + (0x24A, 'M', u'ɋ'), + (0x24B, 'V'), + (0x24C, 'M', u'ɍ'), + (0x24D, 'V'), + (0x24E, 'M', u'ɏ'), + (0x24F, 'V'), + (0x2B0, 'M', u'h'), + (0x2B1, 'M', u'ɦ'), + (0x2B2, 'M', u'j'), + (0x2B3, 'M', u'r'), + (0x2B4, 'M', u'ɹ'), + (0x2B5, 'M', u'ɻ'), + (0x2B6, 'M', u'ʁ'), + (0x2B7, 'M', u'w'), + (0x2B8, 'M', u'y'), + (0x2B9, 'V'), + (0x2D8, '3', u' ̆'), + (0x2D9, '3', u' ̇'), + (0x2DA, '3', u' ̊'), + (0x2DB, '3', u' ̨'), + (0x2DC, '3', u' ̃'), + (0x2DD, '3', u' ̋'), + (0x2DE, 'V'), + (0x2E0, 'M', u'ɣ'), + (0x2E1, 'M', u'l'), + (0x2E2, 'M', u's'), + (0x2E3, 'M', u'x'), + (0x2E4, 'M', u'ʕ'), + (0x2E5, 'V'), + (0x340, 'M', u'̀'), + (0x341, 'M', u'́'), + (0x342, 'V'), + (0x343, 'M', u'̓'), + (0x344, 'M', u'̈́'), + (0x345, 'M', u'ι'), + (0x346, 'V'), + (0x34F, 'I'), + (0x350, 'V'), + (0x370, 'M', u'ͱ'), + (0x371, 'V'), + (0x372, 'M', u'ͳ'), + (0x373, 'V'), + (0x374, 'M', u'ʹ'), + (0x375, 'V'), + (0x376, 'M', u'ͷ'), + (0x377, 'V'), + ] + +def _seg_6(): + return [ + (0x378, 'X'), + (0x37A, '3', u' ι'), + (0x37B, 'V'), + (0x37E, '3', u';'), + (0x37F, 'M', u'ϳ'), + (0x380, 'X'), + (0x384, '3', u' ́'), + (0x385, '3', u' ̈́'), + (0x386, 'M', u'ά'), + (0x387, 'M', u'·'), + (0x388, 'M', u'έ'), + (0x389, 'M', u'ή'), + (0x38A, 'M', u'ί'), + (0x38B, 'X'), + (0x38C, 'M', u'ό'), + (0x38D, 'X'), + (0x38E, 'M', u'ύ'), + (0x38F, 'M', u'ώ'), + (0x390, 'V'), + (0x391, 'M', u'α'), + (0x392, 'M', u'β'), + (0x393, 'M', u'γ'), + (0x394, 'M', u'δ'), + (0x395, 'M', u'ε'), + (0x396, 'M', u'ζ'), + (0x397, 'M', u'η'), + (0x398, 'M', u'θ'), + (0x399, 'M', u'ι'), + (0x39A, 'M', u'κ'), + (0x39B, 'M', u'λ'), + (0x39C, 'M', u'μ'), + (0x39D, 'M', u'ν'), + (0x39E, 'M', u'ξ'), + (0x39F, 'M', u'ο'), + (0x3A0, 'M', u'π'), + (0x3A1, 'M', u'ρ'), + (0x3A2, 'X'), + (0x3A3, 'M', u'σ'), + (0x3A4, 'M', u'τ'), + (0x3A5, 'M', u'υ'), + (0x3A6, 'M', u'φ'), + (0x3A7, 'M', u'χ'), + (0x3A8, 'M', u'ψ'), + (0x3A9, 'M', u'ω'), + (0x3AA, 'M', u'ϊ'), + (0x3AB, 'M', u'ϋ'), + (0x3AC, 'V'), + (0x3C2, 'D', u'σ'), + (0x3C3, 'V'), + (0x3CF, 'M', u'ϗ'), + (0x3D0, 'M', u'β'), + (0x3D1, 'M', u'θ'), + (0x3D2, 'M', u'υ'), + (0x3D3, 'M', u'ύ'), + (0x3D4, 'M', u'ϋ'), + (0x3D5, 'M', u'φ'), + (0x3D6, 'M', u'π'), + (0x3D7, 'V'), + (0x3D8, 'M', u'ϙ'), + (0x3D9, 'V'), + (0x3DA, 'M', u'ϛ'), + (0x3DB, 'V'), + (0x3DC, 'M', u'ϝ'), + (0x3DD, 'V'), + (0x3DE, 'M', u'ϟ'), + (0x3DF, 'V'), + (0x3E0, 'M', u'ϡ'), + (0x3E1, 'V'), + (0x3E2, 'M', u'ϣ'), + (0x3E3, 'V'), + (0x3E4, 'M', u'ϥ'), + (0x3E5, 'V'), + (0x3E6, 'M', u'ϧ'), + (0x3E7, 'V'), + (0x3E8, 'M', u'ϩ'), + (0x3E9, 'V'), + (0x3EA, 'M', u'ϫ'), + (0x3EB, 'V'), + (0x3EC, 'M', u'ϭ'), + (0x3ED, 'V'), + (0x3EE, 'M', u'ϯ'), + (0x3EF, 'V'), + (0x3F0, 'M', u'κ'), + (0x3F1, 'M', u'ρ'), + (0x3F2, 'M', u'σ'), + (0x3F3, 'V'), + (0x3F4, 'M', u'θ'), + (0x3F5, 'M', u'ε'), + (0x3F6, 'V'), + (0x3F7, 'M', u'ϸ'), + (0x3F8, 'V'), + (0x3F9, 'M', u'σ'), + (0x3FA, 'M', u'ϻ'), + (0x3FB, 'V'), + (0x3FD, 'M', u'ͻ'), + (0x3FE, 'M', u'ͼ'), + (0x3FF, 'M', u'ͽ'), + (0x400, 'M', u'ѐ'), + (0x401, 'M', u'ё'), + (0x402, 'M', u'ђ'), + ] + +def _seg_7(): + return [ + (0x403, 'M', u'ѓ'), + (0x404, 'M', u'є'), + (0x405, 'M', u'ѕ'), + (0x406, 'M', u'і'), + (0x407, 'M', u'ї'), + (0x408, 'M', u'ј'), + (0x409, 'M', u'љ'), + (0x40A, 'M', u'њ'), + (0x40B, 'M', u'ћ'), + (0x40C, 'M', u'ќ'), + (0x40D, 'M', u'ѝ'), + (0x40E, 'M', u'ў'), + (0x40F, 'M', u'џ'), + (0x410, 'M', u'а'), + (0x411, 'M', u'б'), + (0x412, 'M', u'в'), + (0x413, 'M', u'г'), + (0x414, 'M', u'д'), + (0x415, 'M', u'е'), + (0x416, 'M', u'ж'), + (0x417, 'M', u'з'), + (0x418, 'M', u'и'), + (0x419, 'M', u'й'), + (0x41A, 'M', u'к'), + (0x41B, 'M', u'л'), + (0x41C, 'M', u'м'), + (0x41D, 'M', u'н'), + (0x41E, 'M', u'о'), + (0x41F, 'M', u'п'), + (0x420, 'M', u'р'), + (0x421, 'M', u'с'), + (0x422, 'M', u'т'), + (0x423, 'M', u'у'), + (0x424, 'M', u'ф'), + (0x425, 'M', u'х'), + (0x426, 'M', u'ц'), + (0x427, 'M', u'ч'), + (0x428, 'M', u'ш'), + (0x429, 'M', u'щ'), + (0x42A, 'M', u'ъ'), + (0x42B, 'M', u'ы'), + (0x42C, 'M', u'ь'), + (0x42D, 'M', u'э'), + (0x42E, 'M', u'ю'), + (0x42F, 'M', u'я'), + (0x430, 'V'), + (0x460, 'M', u'ѡ'), + (0x461, 'V'), + (0x462, 'M', u'ѣ'), + (0x463, 'V'), + (0x464, 'M', u'ѥ'), + (0x465, 'V'), + (0x466, 'M', u'ѧ'), + (0x467, 'V'), + (0x468, 'M', u'ѩ'), + (0x469, 'V'), + (0x46A, 'M', u'ѫ'), + (0x46B, 'V'), + (0x46C, 'M', u'ѭ'), + (0x46D, 'V'), + (0x46E, 'M', u'ѯ'), + (0x46F, 'V'), + (0x470, 'M', u'ѱ'), + (0x471, 'V'), + (0x472, 'M', u'ѳ'), + (0x473, 'V'), + (0x474, 'M', u'ѵ'), + (0x475, 'V'), + (0x476, 'M', u'ѷ'), + (0x477, 'V'), + (0x478, 'M', u'ѹ'), + (0x479, 'V'), + (0x47A, 'M', u'ѻ'), + (0x47B, 'V'), + (0x47C, 'M', u'ѽ'), + (0x47D, 'V'), + (0x47E, 'M', u'ѿ'), + (0x47F, 'V'), + (0x480, 'M', u'ҁ'), + (0x481, 'V'), + (0x48A, 'M', u'ҋ'), + (0x48B, 'V'), + (0x48C, 'M', u'ҍ'), + (0x48D, 'V'), + (0x48E, 'M', u'ҏ'), + (0x48F, 'V'), + (0x490, 'M', u'ґ'), + (0x491, 'V'), + (0x492, 'M', u'ғ'), + (0x493, 'V'), + (0x494, 'M', u'ҕ'), + (0x495, 'V'), + (0x496, 'M', u'җ'), + (0x497, 'V'), + (0x498, 'M', u'ҙ'), + (0x499, 'V'), + (0x49A, 'M', u'қ'), + (0x49B, 'V'), + (0x49C, 'M', u'ҝ'), + (0x49D, 'V'), + ] + +def _seg_8(): + return [ + (0x49E, 'M', u'ҟ'), + (0x49F, 'V'), + (0x4A0, 'M', u'ҡ'), + (0x4A1, 'V'), + (0x4A2, 'M', u'ң'), + (0x4A3, 'V'), + (0x4A4, 'M', u'ҥ'), + (0x4A5, 'V'), + (0x4A6, 'M', u'ҧ'), + (0x4A7, 'V'), + (0x4A8, 'M', u'ҩ'), + (0x4A9, 'V'), + (0x4AA, 'M', u'ҫ'), + (0x4AB, 'V'), + (0x4AC, 'M', u'ҭ'), + (0x4AD, 'V'), + (0x4AE, 'M', u'ү'), + (0x4AF, 'V'), + (0x4B0, 'M', u'ұ'), + (0x4B1, 'V'), + (0x4B2, 'M', u'ҳ'), + (0x4B3, 'V'), + (0x4B4, 'M', u'ҵ'), + (0x4B5, 'V'), + (0x4B6, 'M', u'ҷ'), + (0x4B7, 'V'), + (0x4B8, 'M', u'ҹ'), + (0x4B9, 'V'), + (0x4BA, 'M', u'һ'), + (0x4BB, 'V'), + (0x4BC, 'M', u'ҽ'), + (0x4BD, 'V'), + (0x4BE, 'M', u'ҿ'), + (0x4BF, 'V'), + (0x4C0, 'X'), + (0x4C1, 'M', u'ӂ'), + (0x4C2, 'V'), + (0x4C3, 'M', u'ӄ'), + (0x4C4, 'V'), + (0x4C5, 'M', u'ӆ'), + (0x4C6, 'V'), + (0x4C7, 'M', u'ӈ'), + (0x4C8, 'V'), + (0x4C9, 'M', u'ӊ'), + (0x4CA, 'V'), + (0x4CB, 'M', u'ӌ'), + (0x4CC, 'V'), + (0x4CD, 'M', u'ӎ'), + (0x4CE, 'V'), + (0x4D0, 'M', u'ӑ'), + (0x4D1, 'V'), + (0x4D2, 'M', u'ӓ'), + (0x4D3, 'V'), + (0x4D4, 'M', u'ӕ'), + (0x4D5, 'V'), + (0x4D6, 'M', u'ӗ'), + (0x4D7, 'V'), + (0x4D8, 'M', u'ә'), + (0x4D9, 'V'), + (0x4DA, 'M', u'ӛ'), + (0x4DB, 'V'), + (0x4DC, 'M', u'ӝ'), + (0x4DD, 'V'), + (0x4DE, 'M', u'ӟ'), + (0x4DF, 'V'), + (0x4E0, 'M', u'ӡ'), + (0x4E1, 'V'), + (0x4E2, 'M', u'ӣ'), + (0x4E3, 'V'), + (0x4E4, 'M', u'ӥ'), + (0x4E5, 'V'), + (0x4E6, 'M', u'ӧ'), + (0x4E7, 'V'), + (0x4E8, 'M', u'ө'), + (0x4E9, 'V'), + (0x4EA, 'M', u'ӫ'), + (0x4EB, 'V'), + (0x4EC, 'M', u'ӭ'), + (0x4ED, 'V'), + (0x4EE, 'M', u'ӯ'), + (0x4EF, 'V'), + (0x4F0, 'M', u'ӱ'), + (0x4F1, 'V'), + (0x4F2, 'M', u'ӳ'), + (0x4F3, 'V'), + (0x4F4, 'M', u'ӵ'), + (0x4F5, 'V'), + (0x4F6, 'M', u'ӷ'), + (0x4F7, 'V'), + (0x4F8, 'M', u'ӹ'), + (0x4F9, 'V'), + (0x4FA, 'M', u'ӻ'), + (0x4FB, 'V'), + (0x4FC, 'M', u'ӽ'), + (0x4FD, 'V'), + (0x4FE, 'M', u'ӿ'), + (0x4FF, 'V'), + (0x500, 'M', u'ԁ'), + (0x501, 'V'), + (0x502, 'M', u'ԃ'), + ] + +def _seg_9(): + return [ + (0x503, 'V'), + (0x504, 'M', u'ԅ'), + (0x505, 'V'), + (0x506, 'M', u'ԇ'), + (0x507, 'V'), + (0x508, 'M', u'ԉ'), + (0x509, 'V'), + (0x50A, 'M', u'ԋ'), + (0x50B, 'V'), + (0x50C, 'M', u'ԍ'), + (0x50D, 'V'), + (0x50E, 'M', u'ԏ'), + (0x50F, 'V'), + (0x510, 'M', u'ԑ'), + (0x511, 'V'), + (0x512, 'M', u'ԓ'), + (0x513, 'V'), + (0x514, 'M', u'ԕ'), + (0x515, 'V'), + (0x516, 'M', u'ԗ'), + (0x517, 'V'), + (0x518, 'M', u'ԙ'), + (0x519, 'V'), + (0x51A, 'M', u'ԛ'), + (0x51B, 'V'), + (0x51C, 'M', u'ԝ'), + (0x51D, 'V'), + (0x51E, 'M', u'ԟ'), + (0x51F, 'V'), + (0x520, 'M', u'ԡ'), + (0x521, 'V'), + (0x522, 'M', u'ԣ'), + (0x523, 'V'), + (0x524, 'M', u'ԥ'), + (0x525, 'V'), + (0x526, 'M', u'ԧ'), + (0x527, 'V'), + (0x528, 'M', u'ԩ'), + (0x529, 'V'), + (0x52A, 'M', u'ԫ'), + (0x52B, 'V'), + (0x52C, 'M', u'ԭ'), + (0x52D, 'V'), + (0x52E, 'M', u'ԯ'), + (0x52F, 'V'), + (0x530, 'X'), + (0x531, 'M', u'ա'), + (0x532, 'M', u'բ'), + (0x533, 'M', u'գ'), + (0x534, 'M', u'դ'), + (0x535, 'M', u'ե'), + (0x536, 'M', u'զ'), + (0x537, 'M', u'է'), + (0x538, 'M', u'ը'), + (0x539, 'M', u'թ'), + (0x53A, 'M', u'ժ'), + (0x53B, 'M', u'ի'), + (0x53C, 'M', u'լ'), + (0x53D, 'M', u'խ'), + (0x53E, 'M', u'ծ'), + (0x53F, 'M', u'կ'), + (0x540, 'M', u'հ'), + (0x541, 'M', u'ձ'), + (0x542, 'M', u'ղ'), + (0x543, 'M', u'ճ'), + (0x544, 'M', u'մ'), + (0x545, 'M', u'յ'), + (0x546, 'M', u'ն'), + (0x547, 'M', u'շ'), + (0x548, 'M', u'ո'), + (0x549, 'M', u'չ'), + (0x54A, 'M', u'պ'), + (0x54B, 'M', u'ջ'), + (0x54C, 'M', u'ռ'), + (0x54D, 'M', u'ս'), + (0x54E, 'M', u'վ'), + (0x54F, 'M', u'տ'), + (0x550, 'M', u'ր'), + (0x551, 'M', u'ց'), + (0x552, 'M', u'ւ'), + (0x553, 'M', u'փ'), + (0x554, 'M', u'ք'), + (0x555, 'M', u'օ'), + (0x556, 'M', u'ֆ'), + (0x557, 'X'), + (0x559, 'V'), + (0x587, 'M', u'եւ'), + (0x588, 'V'), + (0x58B, 'X'), + (0x58D, 'V'), + (0x590, 'X'), + (0x591, 'V'), + (0x5C8, 'X'), + (0x5D0, 'V'), + (0x5EB, 'X'), + (0x5EF, 'V'), + (0x5F5, 'X'), + (0x606, 'V'), + (0x61C, 'X'), + (0x61E, 'V'), + ] + +def _seg_10(): + return [ + (0x675, 'M', u'اٴ'), + (0x676, 'M', u'وٴ'), + (0x677, 'M', u'ۇٴ'), + (0x678, 'M', u'يٴ'), + (0x679, 'V'), + (0x6DD, 'X'), + (0x6DE, 'V'), + (0x70E, 'X'), + (0x710, 'V'), + (0x74B, 'X'), + (0x74D, 'V'), + (0x7B2, 'X'), + (0x7C0, 'V'), + (0x7FB, 'X'), + (0x7FD, 'V'), + (0x82E, 'X'), + (0x830, 'V'), + (0x83F, 'X'), + (0x840, 'V'), + (0x85C, 'X'), + (0x85E, 'V'), + (0x85F, 'X'), + (0x860, 'V'), + (0x86B, 'X'), + (0x8A0, 'V'), + (0x8B5, 'X'), + (0x8B6, 'V'), + (0x8C8, 'X'), + (0x8D3, 'V'), + (0x8E2, 'X'), + (0x8E3, 'V'), + (0x958, 'M', u'क़'), + (0x959, 'M', u'ख़'), + (0x95A, 'M', u'ग़'), + (0x95B, 'M', u'ज़'), + (0x95C, 'M', u'ड़'), + (0x95D, 'M', u'ढ़'), + (0x95E, 'M', u'फ़'), + (0x95F, 'M', u'य़'), + (0x960, 'V'), + (0x984, 'X'), + (0x985, 'V'), + (0x98D, 'X'), + (0x98F, 'V'), + (0x991, 'X'), + (0x993, 'V'), + (0x9A9, 'X'), + (0x9AA, 'V'), + (0x9B1, 'X'), + (0x9B2, 'V'), + (0x9B3, 'X'), + (0x9B6, 'V'), + (0x9BA, 'X'), + (0x9BC, 'V'), + (0x9C5, 'X'), + (0x9C7, 'V'), + (0x9C9, 'X'), + (0x9CB, 'V'), + (0x9CF, 'X'), + (0x9D7, 'V'), + (0x9D8, 'X'), + (0x9DC, 'M', u'ড়'), + (0x9DD, 'M', u'ঢ়'), + (0x9DE, 'X'), + (0x9DF, 'M', u'য়'), + (0x9E0, 'V'), + (0x9E4, 'X'), + (0x9E6, 'V'), + (0x9FF, 'X'), + (0xA01, 'V'), + (0xA04, 'X'), + (0xA05, 'V'), + (0xA0B, 'X'), + (0xA0F, 'V'), + (0xA11, 'X'), + (0xA13, 'V'), + (0xA29, 'X'), + (0xA2A, 'V'), + (0xA31, 'X'), + (0xA32, 'V'), + (0xA33, 'M', u'ਲ਼'), + (0xA34, 'X'), + (0xA35, 'V'), + (0xA36, 'M', u'ਸ਼'), + (0xA37, 'X'), + (0xA38, 'V'), + (0xA3A, 'X'), + (0xA3C, 'V'), + (0xA3D, 'X'), + (0xA3E, 'V'), + (0xA43, 'X'), + (0xA47, 'V'), + (0xA49, 'X'), + (0xA4B, 'V'), + (0xA4E, 'X'), + (0xA51, 'V'), + (0xA52, 'X'), + (0xA59, 'M', u'ਖ਼'), + (0xA5A, 'M', u'ਗ਼'), + (0xA5B, 'M', u'ਜ਼'), + ] + +def _seg_11(): + return [ + (0xA5C, 'V'), + (0xA5D, 'X'), + (0xA5E, 'M', u'ਫ਼'), + (0xA5F, 'X'), + (0xA66, 'V'), + (0xA77, 'X'), + (0xA81, 'V'), + (0xA84, 'X'), + (0xA85, 'V'), + (0xA8E, 'X'), + (0xA8F, 'V'), + (0xA92, 'X'), + (0xA93, 'V'), + (0xAA9, 'X'), + (0xAAA, 'V'), + (0xAB1, 'X'), + (0xAB2, 'V'), + (0xAB4, 'X'), + (0xAB5, 'V'), + (0xABA, 'X'), + (0xABC, 'V'), + (0xAC6, 'X'), + (0xAC7, 'V'), + (0xACA, 'X'), + (0xACB, 'V'), + (0xACE, 'X'), + (0xAD0, 'V'), + (0xAD1, 'X'), + (0xAE0, 'V'), + (0xAE4, 'X'), + (0xAE6, 'V'), + (0xAF2, 'X'), + (0xAF9, 'V'), + (0xB00, 'X'), + (0xB01, 'V'), + (0xB04, 'X'), + (0xB05, 'V'), + (0xB0D, 'X'), + (0xB0F, 'V'), + (0xB11, 'X'), + (0xB13, 'V'), + (0xB29, 'X'), + (0xB2A, 'V'), + (0xB31, 'X'), + (0xB32, 'V'), + (0xB34, 'X'), + (0xB35, 'V'), + (0xB3A, 'X'), + (0xB3C, 'V'), + (0xB45, 'X'), + (0xB47, 'V'), + (0xB49, 'X'), + (0xB4B, 'V'), + (0xB4E, 'X'), + (0xB55, 'V'), + (0xB58, 'X'), + (0xB5C, 'M', u'ଡ଼'), + (0xB5D, 'M', u'ଢ଼'), + (0xB5E, 'X'), + (0xB5F, 'V'), + (0xB64, 'X'), + (0xB66, 'V'), + (0xB78, 'X'), + (0xB82, 'V'), + (0xB84, 'X'), + (0xB85, 'V'), + (0xB8B, 'X'), + (0xB8E, 'V'), + (0xB91, 'X'), + (0xB92, 'V'), + (0xB96, 'X'), + (0xB99, 'V'), + (0xB9B, 'X'), + (0xB9C, 'V'), + (0xB9D, 'X'), + (0xB9E, 'V'), + (0xBA0, 'X'), + (0xBA3, 'V'), + (0xBA5, 'X'), + (0xBA8, 'V'), + (0xBAB, 'X'), + (0xBAE, 'V'), + (0xBBA, 'X'), + (0xBBE, 'V'), + (0xBC3, 'X'), + (0xBC6, 'V'), + (0xBC9, 'X'), + (0xBCA, 'V'), + (0xBCE, 'X'), + (0xBD0, 'V'), + (0xBD1, 'X'), + (0xBD7, 'V'), + (0xBD8, 'X'), + (0xBE6, 'V'), + (0xBFB, 'X'), + (0xC00, 'V'), + (0xC0D, 'X'), + (0xC0E, 'V'), + (0xC11, 'X'), + (0xC12, 'V'), + ] + +def _seg_12(): + return [ + (0xC29, 'X'), + (0xC2A, 'V'), + (0xC3A, 'X'), + (0xC3D, 'V'), + (0xC45, 'X'), + (0xC46, 'V'), + (0xC49, 'X'), + (0xC4A, 'V'), + (0xC4E, 'X'), + (0xC55, 'V'), + (0xC57, 'X'), + (0xC58, 'V'), + (0xC5B, 'X'), + (0xC60, 'V'), + (0xC64, 'X'), + (0xC66, 'V'), + (0xC70, 'X'), + (0xC77, 'V'), + (0xC8D, 'X'), + (0xC8E, 'V'), + (0xC91, 'X'), + (0xC92, 'V'), + (0xCA9, 'X'), + (0xCAA, 'V'), + (0xCB4, 'X'), + (0xCB5, 'V'), + (0xCBA, 'X'), + (0xCBC, 'V'), + (0xCC5, 'X'), + (0xCC6, 'V'), + (0xCC9, 'X'), + (0xCCA, 'V'), + (0xCCE, 'X'), + (0xCD5, 'V'), + (0xCD7, 'X'), + (0xCDE, 'V'), + (0xCDF, 'X'), + (0xCE0, 'V'), + (0xCE4, 'X'), + (0xCE6, 'V'), + (0xCF0, 'X'), + (0xCF1, 'V'), + (0xCF3, 'X'), + (0xD00, 'V'), + (0xD0D, 'X'), + (0xD0E, 'V'), + (0xD11, 'X'), + (0xD12, 'V'), + (0xD45, 'X'), + (0xD46, 'V'), + (0xD49, 'X'), + (0xD4A, 'V'), + (0xD50, 'X'), + (0xD54, 'V'), + (0xD64, 'X'), + (0xD66, 'V'), + (0xD80, 'X'), + (0xD81, 'V'), + (0xD84, 'X'), + (0xD85, 'V'), + (0xD97, 'X'), + (0xD9A, 'V'), + (0xDB2, 'X'), + (0xDB3, 'V'), + (0xDBC, 'X'), + (0xDBD, 'V'), + (0xDBE, 'X'), + (0xDC0, 'V'), + (0xDC7, 'X'), + (0xDCA, 'V'), + (0xDCB, 'X'), + (0xDCF, 'V'), + (0xDD5, 'X'), + (0xDD6, 'V'), + (0xDD7, 'X'), + (0xDD8, 'V'), + (0xDE0, 'X'), + (0xDE6, 'V'), + (0xDF0, 'X'), + (0xDF2, 'V'), + (0xDF5, 'X'), + (0xE01, 'V'), + (0xE33, 'M', u'ํา'), + (0xE34, 'V'), + (0xE3B, 'X'), + (0xE3F, 'V'), + (0xE5C, 'X'), + (0xE81, 'V'), + (0xE83, 'X'), + (0xE84, 'V'), + (0xE85, 'X'), + (0xE86, 'V'), + (0xE8B, 'X'), + (0xE8C, 'V'), + (0xEA4, 'X'), + (0xEA5, 'V'), + (0xEA6, 'X'), + (0xEA7, 'V'), + (0xEB3, 'M', u'ໍາ'), + (0xEB4, 'V'), + ] + +def _seg_13(): + return [ + (0xEBE, 'X'), + (0xEC0, 'V'), + (0xEC5, 'X'), + (0xEC6, 'V'), + (0xEC7, 'X'), + (0xEC8, 'V'), + (0xECE, 'X'), + (0xED0, 'V'), + (0xEDA, 'X'), + (0xEDC, 'M', u'ຫນ'), + (0xEDD, 'M', u'ຫມ'), + (0xEDE, 'V'), + (0xEE0, 'X'), + (0xF00, 'V'), + (0xF0C, 'M', u'་'), + (0xF0D, 'V'), + (0xF43, 'M', u'གྷ'), + (0xF44, 'V'), + (0xF48, 'X'), + (0xF49, 'V'), + (0xF4D, 'M', u'ཌྷ'), + (0xF4E, 'V'), + (0xF52, 'M', u'དྷ'), + (0xF53, 'V'), + (0xF57, 'M', u'བྷ'), + (0xF58, 'V'), + (0xF5C, 'M', u'ཛྷ'), + (0xF5D, 'V'), + (0xF69, 'M', u'ཀྵ'), + (0xF6A, 'V'), + (0xF6D, 'X'), + (0xF71, 'V'), + (0xF73, 'M', u'ཱི'), + (0xF74, 'V'), + (0xF75, 'M', u'ཱུ'), + (0xF76, 'M', u'ྲྀ'), + (0xF77, 'M', u'ྲཱྀ'), + (0xF78, 'M', u'ླྀ'), + (0xF79, 'M', u'ླཱྀ'), + (0xF7A, 'V'), + (0xF81, 'M', u'ཱྀ'), + (0xF82, 'V'), + (0xF93, 'M', u'ྒྷ'), + (0xF94, 'V'), + (0xF98, 'X'), + (0xF99, 'V'), + (0xF9D, 'M', u'ྜྷ'), + (0xF9E, 'V'), + (0xFA2, 'M', u'ྡྷ'), + (0xFA3, 'V'), + (0xFA7, 'M', u'ྦྷ'), + (0xFA8, 'V'), + (0xFAC, 'M', u'ྫྷ'), + (0xFAD, 'V'), + (0xFB9, 'M', u'ྐྵ'), + (0xFBA, 'V'), + (0xFBD, 'X'), + (0xFBE, 'V'), + (0xFCD, 'X'), + (0xFCE, 'V'), + (0xFDB, 'X'), + (0x1000, 'V'), + (0x10A0, 'X'), + (0x10C7, 'M', u'ⴧ'), + (0x10C8, 'X'), + (0x10CD, 'M', u'ⴭ'), + (0x10CE, 'X'), + (0x10D0, 'V'), + (0x10FC, 'M', u'ნ'), + (0x10FD, 'V'), + (0x115F, 'X'), + (0x1161, 'V'), + (0x1249, 'X'), + (0x124A, 'V'), + (0x124E, 'X'), + (0x1250, 'V'), + (0x1257, 'X'), + (0x1258, 'V'), + (0x1259, 'X'), + (0x125A, 'V'), + (0x125E, 'X'), + (0x1260, 'V'), + (0x1289, 'X'), + (0x128A, 'V'), + (0x128E, 'X'), + (0x1290, 'V'), + (0x12B1, 'X'), + (0x12B2, 'V'), + (0x12B6, 'X'), + (0x12B8, 'V'), + (0x12BF, 'X'), + (0x12C0, 'V'), + (0x12C1, 'X'), + (0x12C2, 'V'), + (0x12C6, 'X'), + (0x12C8, 'V'), + (0x12D7, 'X'), + (0x12D8, 'V'), + (0x1311, 'X'), + (0x1312, 'V'), + ] + +def _seg_14(): + return [ + (0x1316, 'X'), + (0x1318, 'V'), + (0x135B, 'X'), + (0x135D, 'V'), + (0x137D, 'X'), + (0x1380, 'V'), + (0x139A, 'X'), + (0x13A0, 'V'), + (0x13F6, 'X'), + (0x13F8, 'M', u'Ᏸ'), + (0x13F9, 'M', u'Ᏹ'), + (0x13FA, 'M', u'Ᏺ'), + (0x13FB, 'M', u'Ᏻ'), + (0x13FC, 'M', u'Ᏼ'), + (0x13FD, 'M', u'Ᏽ'), + (0x13FE, 'X'), + (0x1400, 'V'), + (0x1680, 'X'), + (0x1681, 'V'), + (0x169D, 'X'), + (0x16A0, 'V'), + (0x16F9, 'X'), + (0x1700, 'V'), + (0x170D, 'X'), + (0x170E, 'V'), + (0x1715, 'X'), + (0x1720, 'V'), + (0x1737, 'X'), + (0x1740, 'V'), + (0x1754, 'X'), + (0x1760, 'V'), + (0x176D, 'X'), + (0x176E, 'V'), + (0x1771, 'X'), + (0x1772, 'V'), + (0x1774, 'X'), + (0x1780, 'V'), + (0x17B4, 'X'), + (0x17B6, 'V'), + (0x17DE, 'X'), + (0x17E0, 'V'), + (0x17EA, 'X'), + (0x17F0, 'V'), + (0x17FA, 'X'), + (0x1800, 'V'), + (0x1806, 'X'), + (0x1807, 'V'), + (0x180B, 'I'), + (0x180E, 'X'), + (0x1810, 'V'), + (0x181A, 'X'), + (0x1820, 'V'), + (0x1879, 'X'), + (0x1880, 'V'), + (0x18AB, 'X'), + (0x18B0, 'V'), + (0x18F6, 'X'), + (0x1900, 'V'), + (0x191F, 'X'), + (0x1920, 'V'), + (0x192C, 'X'), + (0x1930, 'V'), + (0x193C, 'X'), + (0x1940, 'V'), + (0x1941, 'X'), + (0x1944, 'V'), + (0x196E, 'X'), + (0x1970, 'V'), + (0x1975, 'X'), + (0x1980, 'V'), + (0x19AC, 'X'), + (0x19B0, 'V'), + (0x19CA, 'X'), + (0x19D0, 'V'), + (0x19DB, 'X'), + (0x19DE, 'V'), + (0x1A1C, 'X'), + (0x1A1E, 'V'), + (0x1A5F, 'X'), + (0x1A60, 'V'), + (0x1A7D, 'X'), + (0x1A7F, 'V'), + (0x1A8A, 'X'), + (0x1A90, 'V'), + (0x1A9A, 'X'), + (0x1AA0, 'V'), + (0x1AAE, 'X'), + (0x1AB0, 'V'), + (0x1AC1, 'X'), + (0x1B00, 'V'), + (0x1B4C, 'X'), + (0x1B50, 'V'), + (0x1B7D, 'X'), + (0x1B80, 'V'), + (0x1BF4, 'X'), + (0x1BFC, 'V'), + (0x1C38, 'X'), + (0x1C3B, 'V'), + (0x1C4A, 'X'), + (0x1C4D, 'V'), + ] + +def _seg_15(): + return [ + (0x1C80, 'M', u'в'), + (0x1C81, 'M', u'д'), + (0x1C82, 'M', u'о'), + (0x1C83, 'M', u'с'), + (0x1C84, 'M', u'т'), + (0x1C86, 'M', u'ъ'), + (0x1C87, 'M', u'ѣ'), + (0x1C88, 'M', u'ꙋ'), + (0x1C89, 'X'), + (0x1C90, 'M', u'ა'), + (0x1C91, 'M', u'ბ'), + (0x1C92, 'M', u'გ'), + (0x1C93, 'M', u'დ'), + (0x1C94, 'M', u'ე'), + (0x1C95, 'M', u'ვ'), + (0x1C96, 'M', u'ზ'), + (0x1C97, 'M', u'თ'), + (0x1C98, 'M', u'ი'), + (0x1C99, 'M', u'კ'), + (0x1C9A, 'M', u'ლ'), + (0x1C9B, 'M', u'მ'), + (0x1C9C, 'M', u'ნ'), + (0x1C9D, 'M', u'ო'), + (0x1C9E, 'M', u'პ'), + (0x1C9F, 'M', u'ჟ'), + (0x1CA0, 'M', u'რ'), + (0x1CA1, 'M', u'ს'), + (0x1CA2, 'M', u'ტ'), + (0x1CA3, 'M', u'უ'), + (0x1CA4, 'M', u'ფ'), + (0x1CA5, 'M', u'ქ'), + (0x1CA6, 'M', u'ღ'), + (0x1CA7, 'M', u'ყ'), + (0x1CA8, 'M', u'შ'), + (0x1CA9, 'M', u'ჩ'), + (0x1CAA, 'M', u'ც'), + (0x1CAB, 'M', u'ძ'), + (0x1CAC, 'M', u'წ'), + (0x1CAD, 'M', u'ჭ'), + (0x1CAE, 'M', u'ხ'), + (0x1CAF, 'M', u'ჯ'), + (0x1CB0, 'M', u'ჰ'), + (0x1CB1, 'M', u'ჱ'), + (0x1CB2, 'M', u'ჲ'), + (0x1CB3, 'M', u'ჳ'), + (0x1CB4, 'M', u'ჴ'), + (0x1CB5, 'M', u'ჵ'), + (0x1CB6, 'M', u'ჶ'), + (0x1CB7, 'M', u'ჷ'), + (0x1CB8, 'M', u'ჸ'), + (0x1CB9, 'M', u'ჹ'), + (0x1CBA, 'M', u'ჺ'), + (0x1CBB, 'X'), + (0x1CBD, 'M', u'ჽ'), + (0x1CBE, 'M', u'ჾ'), + (0x1CBF, 'M', u'ჿ'), + (0x1CC0, 'V'), + (0x1CC8, 'X'), + (0x1CD0, 'V'), + (0x1CFB, 'X'), + (0x1D00, 'V'), + (0x1D2C, 'M', u'a'), + (0x1D2D, 'M', u'æ'), + (0x1D2E, 'M', u'b'), + (0x1D2F, 'V'), + (0x1D30, 'M', u'd'), + (0x1D31, 'M', u'e'), + (0x1D32, 'M', u'ǝ'), + (0x1D33, 'M', u'g'), + (0x1D34, 'M', u'h'), + (0x1D35, 'M', u'i'), + (0x1D36, 'M', u'j'), + (0x1D37, 'M', u'k'), + (0x1D38, 'M', u'l'), + (0x1D39, 'M', u'm'), + (0x1D3A, 'M', u'n'), + (0x1D3B, 'V'), + (0x1D3C, 'M', u'o'), + (0x1D3D, 'M', u'ȣ'), + (0x1D3E, 'M', u'p'), + (0x1D3F, 'M', u'r'), + (0x1D40, 'M', u't'), + (0x1D41, 'M', u'u'), + (0x1D42, 'M', u'w'), + (0x1D43, 'M', u'a'), + (0x1D44, 'M', u'ɐ'), + (0x1D45, 'M', u'ɑ'), + (0x1D46, 'M', u'ᴂ'), + (0x1D47, 'M', u'b'), + (0x1D48, 'M', u'd'), + (0x1D49, 'M', u'e'), + (0x1D4A, 'M', u'ə'), + (0x1D4B, 'M', u'ɛ'), + (0x1D4C, 'M', u'ɜ'), + (0x1D4D, 'M', u'g'), + (0x1D4E, 'V'), + (0x1D4F, 'M', u'k'), + (0x1D50, 'M', u'm'), + (0x1D51, 'M', u'ŋ'), + (0x1D52, 'M', u'o'), + ] + +def _seg_16(): + return [ + (0x1D53, 'M', u'ɔ'), + (0x1D54, 'M', u'ᴖ'), + (0x1D55, 'M', u'ᴗ'), + (0x1D56, 'M', u'p'), + (0x1D57, 'M', u't'), + (0x1D58, 'M', u'u'), + (0x1D59, 'M', u'ᴝ'), + (0x1D5A, 'M', u'ɯ'), + (0x1D5B, 'M', u'v'), + (0x1D5C, 'M', u'ᴥ'), + (0x1D5D, 'M', u'β'), + (0x1D5E, 'M', u'γ'), + (0x1D5F, 'M', u'δ'), + (0x1D60, 'M', u'φ'), + (0x1D61, 'M', u'χ'), + (0x1D62, 'M', u'i'), + (0x1D63, 'M', u'r'), + (0x1D64, 'M', u'u'), + (0x1D65, 'M', u'v'), + (0x1D66, 'M', u'β'), + (0x1D67, 'M', u'γ'), + (0x1D68, 'M', u'ρ'), + (0x1D69, 'M', u'φ'), + (0x1D6A, 'M', u'χ'), + (0x1D6B, 'V'), + (0x1D78, 'M', u'н'), + (0x1D79, 'V'), + (0x1D9B, 'M', u'ɒ'), + (0x1D9C, 'M', u'c'), + (0x1D9D, 'M', u'ɕ'), + (0x1D9E, 'M', u'ð'), + (0x1D9F, 'M', u'ɜ'), + (0x1DA0, 'M', u'f'), + (0x1DA1, 'M', u'ɟ'), + (0x1DA2, 'M', u'ɡ'), + (0x1DA3, 'M', u'ɥ'), + (0x1DA4, 'M', u'ɨ'), + (0x1DA5, 'M', u'ɩ'), + (0x1DA6, 'M', u'ɪ'), + (0x1DA7, 'M', u'ᵻ'), + (0x1DA8, 'M', u'ʝ'), + (0x1DA9, 'M', u'ɭ'), + (0x1DAA, 'M', u'ᶅ'), + (0x1DAB, 'M', u'ʟ'), + (0x1DAC, 'M', u'ɱ'), + (0x1DAD, 'M', u'ɰ'), + (0x1DAE, 'M', u'ɲ'), + (0x1DAF, 'M', u'ɳ'), + (0x1DB0, 'M', u'ɴ'), + (0x1DB1, 'M', u'ɵ'), + (0x1DB2, 'M', u'ɸ'), + (0x1DB3, 'M', u'ʂ'), + (0x1DB4, 'M', u'ʃ'), + (0x1DB5, 'M', u'ƫ'), + (0x1DB6, 'M', u'ʉ'), + (0x1DB7, 'M', u'ʊ'), + (0x1DB8, 'M', u'ᴜ'), + (0x1DB9, 'M', u'ʋ'), + (0x1DBA, 'M', u'ʌ'), + (0x1DBB, 'M', u'z'), + (0x1DBC, 'M', u'ʐ'), + (0x1DBD, 'M', u'ʑ'), + (0x1DBE, 'M', u'ʒ'), + (0x1DBF, 'M', u'θ'), + (0x1DC0, 'V'), + (0x1DFA, 'X'), + (0x1DFB, 'V'), + (0x1E00, 'M', u'ḁ'), + (0x1E01, 'V'), + (0x1E02, 'M', u'ḃ'), + (0x1E03, 'V'), + (0x1E04, 'M', u'ḅ'), + (0x1E05, 'V'), + (0x1E06, 'M', u'ḇ'), + (0x1E07, 'V'), + (0x1E08, 'M', u'ḉ'), + (0x1E09, 'V'), + (0x1E0A, 'M', u'ḋ'), + (0x1E0B, 'V'), + (0x1E0C, 'M', u'ḍ'), + (0x1E0D, 'V'), + (0x1E0E, 'M', u'ḏ'), + (0x1E0F, 'V'), + (0x1E10, 'M', u'ḑ'), + (0x1E11, 'V'), + (0x1E12, 'M', u'ḓ'), + (0x1E13, 'V'), + (0x1E14, 'M', u'ḕ'), + (0x1E15, 'V'), + (0x1E16, 'M', u'ḗ'), + (0x1E17, 'V'), + (0x1E18, 'M', u'ḙ'), + (0x1E19, 'V'), + (0x1E1A, 'M', u'ḛ'), + (0x1E1B, 'V'), + (0x1E1C, 'M', u'ḝ'), + (0x1E1D, 'V'), + (0x1E1E, 'M', u'ḟ'), + (0x1E1F, 'V'), + (0x1E20, 'M', u'ḡ'), + ] + +def _seg_17(): + return [ + (0x1E21, 'V'), + (0x1E22, 'M', u'ḣ'), + (0x1E23, 'V'), + (0x1E24, 'M', u'ḥ'), + (0x1E25, 'V'), + (0x1E26, 'M', u'ḧ'), + (0x1E27, 'V'), + (0x1E28, 'M', u'ḩ'), + (0x1E29, 'V'), + (0x1E2A, 'M', u'ḫ'), + (0x1E2B, 'V'), + (0x1E2C, 'M', u'ḭ'), + (0x1E2D, 'V'), + (0x1E2E, 'M', u'ḯ'), + (0x1E2F, 'V'), + (0x1E30, 'M', u'ḱ'), + (0x1E31, 'V'), + (0x1E32, 'M', u'ḳ'), + (0x1E33, 'V'), + (0x1E34, 'M', u'ḵ'), + (0x1E35, 'V'), + (0x1E36, 'M', u'ḷ'), + (0x1E37, 'V'), + (0x1E38, 'M', u'ḹ'), + (0x1E39, 'V'), + (0x1E3A, 'M', u'ḻ'), + (0x1E3B, 'V'), + (0x1E3C, 'M', u'ḽ'), + (0x1E3D, 'V'), + (0x1E3E, 'M', u'ḿ'), + (0x1E3F, 'V'), + (0x1E40, 'M', u'ṁ'), + (0x1E41, 'V'), + (0x1E42, 'M', u'ṃ'), + (0x1E43, 'V'), + (0x1E44, 'M', u'ṅ'), + (0x1E45, 'V'), + (0x1E46, 'M', u'ṇ'), + (0x1E47, 'V'), + (0x1E48, 'M', u'ṉ'), + (0x1E49, 'V'), + (0x1E4A, 'M', u'ṋ'), + (0x1E4B, 'V'), + (0x1E4C, 'M', u'ṍ'), + (0x1E4D, 'V'), + (0x1E4E, 'M', u'ṏ'), + (0x1E4F, 'V'), + (0x1E50, 'M', u'ṑ'), + (0x1E51, 'V'), + (0x1E52, 'M', u'ṓ'), + (0x1E53, 'V'), + (0x1E54, 'M', u'ṕ'), + (0x1E55, 'V'), + (0x1E56, 'M', u'ṗ'), + (0x1E57, 'V'), + (0x1E58, 'M', u'ṙ'), + (0x1E59, 'V'), + (0x1E5A, 'M', u'ṛ'), + (0x1E5B, 'V'), + (0x1E5C, 'M', u'ṝ'), + (0x1E5D, 'V'), + (0x1E5E, 'M', u'ṟ'), + (0x1E5F, 'V'), + (0x1E60, 'M', u'ṡ'), + (0x1E61, 'V'), + (0x1E62, 'M', u'ṣ'), + (0x1E63, 'V'), + (0x1E64, 'M', u'ṥ'), + (0x1E65, 'V'), + (0x1E66, 'M', u'ṧ'), + (0x1E67, 'V'), + (0x1E68, 'M', u'ṩ'), + (0x1E69, 'V'), + (0x1E6A, 'M', u'ṫ'), + (0x1E6B, 'V'), + (0x1E6C, 'M', u'ṭ'), + (0x1E6D, 'V'), + (0x1E6E, 'M', u'ṯ'), + (0x1E6F, 'V'), + (0x1E70, 'M', u'ṱ'), + (0x1E71, 'V'), + (0x1E72, 'M', u'ṳ'), + (0x1E73, 'V'), + (0x1E74, 'M', u'ṵ'), + (0x1E75, 'V'), + (0x1E76, 'M', u'ṷ'), + (0x1E77, 'V'), + (0x1E78, 'M', u'ṹ'), + (0x1E79, 'V'), + (0x1E7A, 'M', u'ṻ'), + (0x1E7B, 'V'), + (0x1E7C, 'M', u'ṽ'), + (0x1E7D, 'V'), + (0x1E7E, 'M', u'ṿ'), + (0x1E7F, 'V'), + (0x1E80, 'M', u'ẁ'), + (0x1E81, 'V'), + (0x1E82, 'M', u'ẃ'), + (0x1E83, 'V'), + (0x1E84, 'M', u'ẅ'), + ] + +def _seg_18(): + return [ + (0x1E85, 'V'), + (0x1E86, 'M', u'ẇ'), + (0x1E87, 'V'), + (0x1E88, 'M', u'ẉ'), + (0x1E89, 'V'), + (0x1E8A, 'M', u'ẋ'), + (0x1E8B, 'V'), + (0x1E8C, 'M', u'ẍ'), + (0x1E8D, 'V'), + (0x1E8E, 'M', u'ẏ'), + (0x1E8F, 'V'), + (0x1E90, 'M', u'ẑ'), + (0x1E91, 'V'), + (0x1E92, 'M', u'ẓ'), + (0x1E93, 'V'), + (0x1E94, 'M', u'ẕ'), + (0x1E95, 'V'), + (0x1E9A, 'M', u'aʾ'), + (0x1E9B, 'M', u'ṡ'), + (0x1E9C, 'V'), + (0x1E9E, 'M', u'ss'), + (0x1E9F, 'V'), + (0x1EA0, 'M', u'ạ'), + (0x1EA1, 'V'), + (0x1EA2, 'M', u'ả'), + (0x1EA3, 'V'), + (0x1EA4, 'M', u'ấ'), + (0x1EA5, 'V'), + (0x1EA6, 'M', u'ầ'), + (0x1EA7, 'V'), + (0x1EA8, 'M', u'ẩ'), + (0x1EA9, 'V'), + (0x1EAA, 'M', u'ẫ'), + (0x1EAB, 'V'), + (0x1EAC, 'M', u'ậ'), + (0x1EAD, 'V'), + (0x1EAE, 'M', u'ắ'), + (0x1EAF, 'V'), + (0x1EB0, 'M', u'ằ'), + (0x1EB1, 'V'), + (0x1EB2, 'M', u'ẳ'), + (0x1EB3, 'V'), + (0x1EB4, 'M', u'ẵ'), + (0x1EB5, 'V'), + (0x1EB6, 'M', u'ặ'), + (0x1EB7, 'V'), + (0x1EB8, 'M', u'ẹ'), + (0x1EB9, 'V'), + (0x1EBA, 'M', u'ẻ'), + (0x1EBB, 'V'), + (0x1EBC, 'M', u'ẽ'), + (0x1EBD, 'V'), + (0x1EBE, 'M', u'ế'), + (0x1EBF, 'V'), + (0x1EC0, 'M', u'ề'), + (0x1EC1, 'V'), + (0x1EC2, 'M', u'ể'), + (0x1EC3, 'V'), + (0x1EC4, 'M', u'ễ'), + (0x1EC5, 'V'), + (0x1EC6, 'M', u'ệ'), + (0x1EC7, 'V'), + (0x1EC8, 'M', u'ỉ'), + (0x1EC9, 'V'), + (0x1ECA, 'M', u'ị'), + (0x1ECB, 'V'), + (0x1ECC, 'M', u'ọ'), + (0x1ECD, 'V'), + (0x1ECE, 'M', u'ỏ'), + (0x1ECF, 'V'), + (0x1ED0, 'M', u'ố'), + (0x1ED1, 'V'), + (0x1ED2, 'M', u'ồ'), + (0x1ED3, 'V'), + (0x1ED4, 'M', u'ổ'), + (0x1ED5, 'V'), + (0x1ED6, 'M', u'ỗ'), + (0x1ED7, 'V'), + (0x1ED8, 'M', u'ộ'), + (0x1ED9, 'V'), + (0x1EDA, 'M', u'ớ'), + (0x1EDB, 'V'), + (0x1EDC, 'M', u'ờ'), + (0x1EDD, 'V'), + (0x1EDE, 'M', u'ở'), + (0x1EDF, 'V'), + (0x1EE0, 'M', u'ỡ'), + (0x1EE1, 'V'), + (0x1EE2, 'M', u'ợ'), + (0x1EE3, 'V'), + (0x1EE4, 'M', u'ụ'), + (0x1EE5, 'V'), + (0x1EE6, 'M', u'ủ'), + (0x1EE7, 'V'), + (0x1EE8, 'M', u'ứ'), + (0x1EE9, 'V'), + (0x1EEA, 'M', u'ừ'), + (0x1EEB, 'V'), + (0x1EEC, 'M', u'ử'), + (0x1EED, 'V'), + ] + +def _seg_19(): + return [ + (0x1EEE, 'M', u'ữ'), + (0x1EEF, 'V'), + (0x1EF0, 'M', u'ự'), + (0x1EF1, 'V'), + (0x1EF2, 'M', u'ỳ'), + (0x1EF3, 'V'), + (0x1EF4, 'M', u'ỵ'), + (0x1EF5, 'V'), + (0x1EF6, 'M', u'ỷ'), + (0x1EF7, 'V'), + (0x1EF8, 'M', u'ỹ'), + (0x1EF9, 'V'), + (0x1EFA, 'M', u'ỻ'), + (0x1EFB, 'V'), + (0x1EFC, 'M', u'ỽ'), + (0x1EFD, 'V'), + (0x1EFE, 'M', u'ỿ'), + (0x1EFF, 'V'), + (0x1F08, 'M', u'ἀ'), + (0x1F09, 'M', u'ἁ'), + (0x1F0A, 'M', u'ἂ'), + (0x1F0B, 'M', u'ἃ'), + (0x1F0C, 'M', u'ἄ'), + (0x1F0D, 'M', u'ἅ'), + (0x1F0E, 'M', u'ἆ'), + (0x1F0F, 'M', u'ἇ'), + (0x1F10, 'V'), + (0x1F16, 'X'), + (0x1F18, 'M', u'ἐ'), + (0x1F19, 'M', u'ἑ'), + (0x1F1A, 'M', u'ἒ'), + (0x1F1B, 'M', u'ἓ'), + (0x1F1C, 'M', u'ἔ'), + (0x1F1D, 'M', u'ἕ'), + (0x1F1E, 'X'), + (0x1F20, 'V'), + (0x1F28, 'M', u'ἠ'), + (0x1F29, 'M', u'ἡ'), + (0x1F2A, 'M', u'ἢ'), + (0x1F2B, 'M', u'ἣ'), + (0x1F2C, 'M', u'ἤ'), + (0x1F2D, 'M', u'ἥ'), + (0x1F2E, 'M', u'ἦ'), + (0x1F2F, 'M', u'ἧ'), + (0x1F30, 'V'), + (0x1F38, 'M', u'ἰ'), + (0x1F39, 'M', u'ἱ'), + (0x1F3A, 'M', u'ἲ'), + (0x1F3B, 'M', u'ἳ'), + (0x1F3C, 'M', u'ἴ'), + (0x1F3D, 'M', u'ἵ'), + (0x1F3E, 'M', u'ἶ'), + (0x1F3F, 'M', u'ἷ'), + (0x1F40, 'V'), + (0x1F46, 'X'), + (0x1F48, 'M', u'ὀ'), + (0x1F49, 'M', u'ὁ'), + (0x1F4A, 'M', u'ὂ'), + (0x1F4B, 'M', u'ὃ'), + (0x1F4C, 'M', u'ὄ'), + (0x1F4D, 'M', u'ὅ'), + (0x1F4E, 'X'), + (0x1F50, 'V'), + (0x1F58, 'X'), + (0x1F59, 'M', u'ὑ'), + (0x1F5A, 'X'), + (0x1F5B, 'M', u'ὓ'), + (0x1F5C, 'X'), + (0x1F5D, 'M', u'ὕ'), + (0x1F5E, 'X'), + (0x1F5F, 'M', u'ὗ'), + (0x1F60, 'V'), + (0x1F68, 'M', u'ὠ'), + (0x1F69, 'M', u'ὡ'), + (0x1F6A, 'M', u'ὢ'), + (0x1F6B, 'M', u'ὣ'), + (0x1F6C, 'M', u'ὤ'), + (0x1F6D, 'M', u'ὥ'), + (0x1F6E, 'M', u'ὦ'), + (0x1F6F, 'M', u'ὧ'), + (0x1F70, 'V'), + (0x1F71, 'M', u'ά'), + (0x1F72, 'V'), + (0x1F73, 'M', u'έ'), + (0x1F74, 'V'), + (0x1F75, 'M', u'ή'), + (0x1F76, 'V'), + (0x1F77, 'M', u'ί'), + (0x1F78, 'V'), + (0x1F79, 'M', u'ό'), + (0x1F7A, 'V'), + (0x1F7B, 'M', u'ύ'), + (0x1F7C, 'V'), + (0x1F7D, 'M', u'ώ'), + (0x1F7E, 'X'), + (0x1F80, 'M', u'ἀι'), + (0x1F81, 'M', u'ἁι'), + (0x1F82, 'M', u'ἂι'), + (0x1F83, 'M', u'ἃι'), + (0x1F84, 'M', u'ἄι'), + ] + +def _seg_20(): + return [ + (0x1F85, 'M', u'ἅι'), + (0x1F86, 'M', u'ἆι'), + (0x1F87, 'M', u'ἇι'), + (0x1F88, 'M', u'ἀι'), + (0x1F89, 'M', u'ἁι'), + (0x1F8A, 'M', u'ἂι'), + (0x1F8B, 'M', u'ἃι'), + (0x1F8C, 'M', u'ἄι'), + (0x1F8D, 'M', u'ἅι'), + (0x1F8E, 'M', u'ἆι'), + (0x1F8F, 'M', u'ἇι'), + (0x1F90, 'M', u'ἠι'), + (0x1F91, 'M', u'ἡι'), + (0x1F92, 'M', u'ἢι'), + (0x1F93, 'M', u'ἣι'), + (0x1F94, 'M', u'ἤι'), + (0x1F95, 'M', u'ἥι'), + (0x1F96, 'M', u'ἦι'), + (0x1F97, 'M', u'ἧι'), + (0x1F98, 'M', u'ἠι'), + (0x1F99, 'M', u'ἡι'), + (0x1F9A, 'M', u'ἢι'), + (0x1F9B, 'M', u'ἣι'), + (0x1F9C, 'M', u'ἤι'), + (0x1F9D, 'M', u'ἥι'), + (0x1F9E, 'M', u'ἦι'), + (0x1F9F, 'M', u'ἧι'), + (0x1FA0, 'M', u'ὠι'), + (0x1FA1, 'M', u'ὡι'), + (0x1FA2, 'M', u'ὢι'), + (0x1FA3, 'M', u'ὣι'), + (0x1FA4, 'M', u'ὤι'), + (0x1FA5, 'M', u'ὥι'), + (0x1FA6, 'M', u'ὦι'), + (0x1FA7, 'M', u'ὧι'), + (0x1FA8, 'M', u'ὠι'), + (0x1FA9, 'M', u'ὡι'), + (0x1FAA, 'M', u'ὢι'), + (0x1FAB, 'M', u'ὣι'), + (0x1FAC, 'M', u'ὤι'), + (0x1FAD, 'M', u'ὥι'), + (0x1FAE, 'M', u'ὦι'), + (0x1FAF, 'M', u'ὧι'), + (0x1FB0, 'V'), + (0x1FB2, 'M', u'ὰι'), + (0x1FB3, 'M', u'αι'), + (0x1FB4, 'M', u'άι'), + (0x1FB5, 'X'), + (0x1FB6, 'V'), + (0x1FB7, 'M', u'ᾶι'), + (0x1FB8, 'M', u'ᾰ'), + (0x1FB9, 'M', u'ᾱ'), + (0x1FBA, 'M', u'ὰ'), + (0x1FBB, 'M', u'ά'), + (0x1FBC, 'M', u'αι'), + (0x1FBD, '3', u' ̓'), + (0x1FBE, 'M', u'ι'), + (0x1FBF, '3', u' ̓'), + (0x1FC0, '3', u' ͂'), + (0x1FC1, '3', u' ̈͂'), + (0x1FC2, 'M', u'ὴι'), + (0x1FC3, 'M', u'ηι'), + (0x1FC4, 'M', u'ήι'), + (0x1FC5, 'X'), + (0x1FC6, 'V'), + (0x1FC7, 'M', u'ῆι'), + (0x1FC8, 'M', u'ὲ'), + (0x1FC9, 'M', u'έ'), + (0x1FCA, 'M', u'ὴ'), + (0x1FCB, 'M', u'ή'), + (0x1FCC, 'M', u'ηι'), + (0x1FCD, '3', u' ̓̀'), + (0x1FCE, '3', u' ̓́'), + (0x1FCF, '3', u' ̓͂'), + (0x1FD0, 'V'), + (0x1FD3, 'M', u'ΐ'), + (0x1FD4, 'X'), + (0x1FD6, 'V'), + (0x1FD8, 'M', u'ῐ'), + (0x1FD9, 'M', u'ῑ'), + (0x1FDA, 'M', u'ὶ'), + (0x1FDB, 'M', u'ί'), + (0x1FDC, 'X'), + (0x1FDD, '3', u' ̔̀'), + (0x1FDE, '3', u' ̔́'), + (0x1FDF, '3', u' ̔͂'), + (0x1FE0, 'V'), + (0x1FE3, 'M', u'ΰ'), + (0x1FE4, 'V'), + (0x1FE8, 'M', u'ῠ'), + (0x1FE9, 'M', u'ῡ'), + (0x1FEA, 'M', u'ὺ'), + (0x1FEB, 'M', u'ύ'), + (0x1FEC, 'M', u'ῥ'), + (0x1FED, '3', u' ̈̀'), + (0x1FEE, '3', u' ̈́'), + (0x1FEF, '3', u'`'), + (0x1FF0, 'X'), + (0x1FF2, 'M', u'ὼι'), + (0x1FF3, 'M', u'ωι'), + ] + +def _seg_21(): + return [ + (0x1FF4, 'M', u'ώι'), + (0x1FF5, 'X'), + (0x1FF6, 'V'), + (0x1FF7, 'M', u'ῶι'), + (0x1FF8, 'M', u'ὸ'), + (0x1FF9, 'M', u'ό'), + (0x1FFA, 'M', u'ὼ'), + (0x1FFB, 'M', u'ώ'), + (0x1FFC, 'M', u'ωι'), + (0x1FFD, '3', u' ́'), + (0x1FFE, '3', u' ̔'), + (0x1FFF, 'X'), + (0x2000, '3', u' '), + (0x200B, 'I'), + (0x200C, 'D', u''), + (0x200E, 'X'), + (0x2010, 'V'), + (0x2011, 'M', u'‐'), + (0x2012, 'V'), + (0x2017, '3', u' ̳'), + (0x2018, 'V'), + (0x2024, 'X'), + (0x2027, 'V'), + (0x2028, 'X'), + (0x202F, '3', u' '), + (0x2030, 'V'), + (0x2033, 'M', u'′′'), + (0x2034, 'M', u'′′′'), + (0x2035, 'V'), + (0x2036, 'M', u'‵‵'), + (0x2037, 'M', u'‵‵‵'), + (0x2038, 'V'), + (0x203C, '3', u'!!'), + (0x203D, 'V'), + (0x203E, '3', u' ̅'), + (0x203F, 'V'), + (0x2047, '3', u'??'), + (0x2048, '3', u'?!'), + (0x2049, '3', u'!?'), + (0x204A, 'V'), + (0x2057, 'M', u'′′′′'), + (0x2058, 'V'), + (0x205F, '3', u' '), + (0x2060, 'I'), + (0x2061, 'X'), + (0x2064, 'I'), + (0x2065, 'X'), + (0x2070, 'M', u'0'), + (0x2071, 'M', u'i'), + (0x2072, 'X'), + (0x2074, 'M', u'4'), + (0x2075, 'M', u'5'), + (0x2076, 'M', u'6'), + (0x2077, 'M', u'7'), + (0x2078, 'M', u'8'), + (0x2079, 'M', u'9'), + (0x207A, '3', u'+'), + (0x207B, 'M', u'−'), + (0x207C, '3', u'='), + (0x207D, '3', u'('), + (0x207E, '3', u')'), + (0x207F, 'M', u'n'), + (0x2080, 'M', u'0'), + (0x2081, 'M', u'1'), + (0x2082, 'M', u'2'), + (0x2083, 'M', u'3'), + (0x2084, 'M', u'4'), + (0x2085, 'M', u'5'), + (0x2086, 'M', u'6'), + (0x2087, 'M', u'7'), + (0x2088, 'M', u'8'), + (0x2089, 'M', u'9'), + (0x208A, '3', u'+'), + (0x208B, 'M', u'−'), + (0x208C, '3', u'='), + (0x208D, '3', u'('), + (0x208E, '3', u')'), + (0x208F, 'X'), + (0x2090, 'M', u'a'), + (0x2091, 'M', u'e'), + (0x2092, 'M', u'o'), + (0x2093, 'M', u'x'), + (0x2094, 'M', u'ə'), + (0x2095, 'M', u'h'), + (0x2096, 'M', u'k'), + (0x2097, 'M', u'l'), + (0x2098, 'M', u'm'), + (0x2099, 'M', u'n'), + (0x209A, 'M', u'p'), + (0x209B, 'M', u's'), + (0x209C, 'M', u't'), + (0x209D, 'X'), + (0x20A0, 'V'), + (0x20A8, 'M', u'rs'), + (0x20A9, 'V'), + (0x20C0, 'X'), + (0x20D0, 'V'), + (0x20F1, 'X'), + (0x2100, '3', u'a/c'), + (0x2101, '3', u'a/s'), + ] + +def _seg_22(): + return [ + (0x2102, 'M', u'c'), + (0x2103, 'M', u'°c'), + (0x2104, 'V'), + (0x2105, '3', u'c/o'), + (0x2106, '3', u'c/u'), + (0x2107, 'M', u'ɛ'), + (0x2108, 'V'), + (0x2109, 'M', u'°f'), + (0x210A, 'M', u'g'), + (0x210B, 'M', u'h'), + (0x210F, 'M', u'ħ'), + (0x2110, 'M', u'i'), + (0x2112, 'M', u'l'), + (0x2114, 'V'), + (0x2115, 'M', u'n'), + (0x2116, 'M', u'no'), + (0x2117, 'V'), + (0x2119, 'M', u'p'), + (0x211A, 'M', u'q'), + (0x211B, 'M', u'r'), + (0x211E, 'V'), + (0x2120, 'M', u'sm'), + (0x2121, 'M', u'tel'), + (0x2122, 'M', u'tm'), + (0x2123, 'V'), + (0x2124, 'M', u'z'), + (0x2125, 'V'), + (0x2126, 'M', u'ω'), + (0x2127, 'V'), + (0x2128, 'M', u'z'), + (0x2129, 'V'), + (0x212A, 'M', u'k'), + (0x212B, 'M', u'å'), + (0x212C, 'M', u'b'), + (0x212D, 'M', u'c'), + (0x212E, 'V'), + (0x212F, 'M', u'e'), + (0x2131, 'M', u'f'), + (0x2132, 'X'), + (0x2133, 'M', u'm'), + (0x2134, 'M', u'o'), + (0x2135, 'M', u'א'), + (0x2136, 'M', u'ב'), + (0x2137, 'M', u'ג'), + (0x2138, 'M', u'ד'), + (0x2139, 'M', u'i'), + (0x213A, 'V'), + (0x213B, 'M', u'fax'), + (0x213C, 'M', u'π'), + (0x213D, 'M', u'γ'), + (0x213F, 'M', u'π'), + (0x2140, 'M', u'∑'), + (0x2141, 'V'), + (0x2145, 'M', u'd'), + (0x2147, 'M', u'e'), + (0x2148, 'M', u'i'), + (0x2149, 'M', u'j'), + (0x214A, 'V'), + (0x2150, 'M', u'1⁄7'), + (0x2151, 'M', u'1⁄9'), + (0x2152, 'M', u'1⁄10'), + (0x2153, 'M', u'1⁄3'), + (0x2154, 'M', u'2⁄3'), + (0x2155, 'M', u'1⁄5'), + (0x2156, 'M', u'2⁄5'), + (0x2157, 'M', u'3⁄5'), + (0x2158, 'M', u'4⁄5'), + (0x2159, 'M', u'1⁄6'), + (0x215A, 'M', u'5⁄6'), + (0x215B, 'M', u'1⁄8'), + (0x215C, 'M', u'3⁄8'), + (0x215D, 'M', u'5⁄8'), + (0x215E, 'M', u'7⁄8'), + (0x215F, 'M', u'1⁄'), + (0x2160, 'M', u'i'), + (0x2161, 'M', u'ii'), + (0x2162, 'M', u'iii'), + (0x2163, 'M', u'iv'), + (0x2164, 'M', u'v'), + (0x2165, 'M', u'vi'), + (0x2166, 'M', u'vii'), + (0x2167, 'M', u'viii'), + (0x2168, 'M', u'ix'), + (0x2169, 'M', u'x'), + (0x216A, 'M', u'xi'), + (0x216B, 'M', u'xii'), + (0x216C, 'M', u'l'), + (0x216D, 'M', u'c'), + (0x216E, 'M', u'd'), + (0x216F, 'M', u'm'), + (0x2170, 'M', u'i'), + (0x2171, 'M', u'ii'), + (0x2172, 'M', u'iii'), + (0x2173, 'M', u'iv'), + (0x2174, 'M', u'v'), + (0x2175, 'M', u'vi'), + (0x2176, 'M', u'vii'), + (0x2177, 'M', u'viii'), + (0x2178, 'M', u'ix'), + (0x2179, 'M', u'x'), + ] + +def _seg_23(): + return [ + (0x217A, 'M', u'xi'), + (0x217B, 'M', u'xii'), + (0x217C, 'M', u'l'), + (0x217D, 'M', u'c'), + (0x217E, 'M', u'd'), + (0x217F, 'M', u'm'), + (0x2180, 'V'), + (0x2183, 'X'), + (0x2184, 'V'), + (0x2189, 'M', u'0⁄3'), + (0x218A, 'V'), + (0x218C, 'X'), + (0x2190, 'V'), + (0x222C, 'M', u'∫∫'), + (0x222D, 'M', u'∫∫∫'), + (0x222E, 'V'), + (0x222F, 'M', u'∮∮'), + (0x2230, 'M', u'∮∮∮'), + (0x2231, 'V'), + (0x2260, '3'), + (0x2261, 'V'), + (0x226E, '3'), + (0x2270, 'V'), + (0x2329, 'M', u'〈'), + (0x232A, 'M', u'〉'), + (0x232B, 'V'), + (0x2427, 'X'), + (0x2440, 'V'), + (0x244B, 'X'), + (0x2460, 'M', u'1'), + (0x2461, 'M', u'2'), + (0x2462, 'M', u'3'), + (0x2463, 'M', u'4'), + (0x2464, 'M', u'5'), + (0x2465, 'M', u'6'), + (0x2466, 'M', u'7'), + (0x2467, 'M', u'8'), + (0x2468, 'M', u'9'), + (0x2469, 'M', u'10'), + (0x246A, 'M', u'11'), + (0x246B, 'M', u'12'), + (0x246C, 'M', u'13'), + (0x246D, 'M', u'14'), + (0x246E, 'M', u'15'), + (0x246F, 'M', u'16'), + (0x2470, 'M', u'17'), + (0x2471, 'M', u'18'), + (0x2472, 'M', u'19'), + (0x2473, 'M', u'20'), + (0x2474, '3', u'(1)'), + (0x2475, '3', u'(2)'), + (0x2476, '3', u'(3)'), + (0x2477, '3', u'(4)'), + (0x2478, '3', u'(5)'), + (0x2479, '3', u'(6)'), + (0x247A, '3', u'(7)'), + (0x247B, '3', u'(8)'), + (0x247C, '3', u'(9)'), + (0x247D, '3', u'(10)'), + (0x247E, '3', u'(11)'), + (0x247F, '3', u'(12)'), + (0x2480, '3', u'(13)'), + (0x2481, '3', u'(14)'), + (0x2482, '3', u'(15)'), + (0x2483, '3', u'(16)'), + (0x2484, '3', u'(17)'), + (0x2485, '3', u'(18)'), + (0x2486, '3', u'(19)'), + (0x2487, '3', u'(20)'), + (0x2488, 'X'), + (0x249C, '3', u'(a)'), + (0x249D, '3', u'(b)'), + (0x249E, '3', u'(c)'), + (0x249F, '3', u'(d)'), + (0x24A0, '3', u'(e)'), + (0x24A1, '3', u'(f)'), + (0x24A2, '3', u'(g)'), + (0x24A3, '3', u'(h)'), + (0x24A4, '3', u'(i)'), + (0x24A5, '3', u'(j)'), + (0x24A6, '3', u'(k)'), + (0x24A7, '3', u'(l)'), + (0x24A8, '3', u'(m)'), + (0x24A9, '3', u'(n)'), + (0x24AA, '3', u'(o)'), + (0x24AB, '3', u'(p)'), + (0x24AC, '3', u'(q)'), + (0x24AD, '3', u'(r)'), + (0x24AE, '3', u'(s)'), + (0x24AF, '3', u'(t)'), + (0x24B0, '3', u'(u)'), + (0x24B1, '3', u'(v)'), + (0x24B2, '3', u'(w)'), + (0x24B3, '3', u'(x)'), + (0x24B4, '3', u'(y)'), + (0x24B5, '3', u'(z)'), + (0x24B6, 'M', u'a'), + (0x24B7, 'M', u'b'), + (0x24B8, 'M', u'c'), + (0x24B9, 'M', u'd'), + ] + +def _seg_24(): + return [ + (0x24BA, 'M', u'e'), + (0x24BB, 'M', u'f'), + (0x24BC, 'M', u'g'), + (0x24BD, 'M', u'h'), + (0x24BE, 'M', u'i'), + (0x24BF, 'M', u'j'), + (0x24C0, 'M', u'k'), + (0x24C1, 'M', u'l'), + (0x24C2, 'M', u'm'), + (0x24C3, 'M', u'n'), + (0x24C4, 'M', u'o'), + (0x24C5, 'M', u'p'), + (0x24C6, 'M', u'q'), + (0x24C7, 'M', u'r'), + (0x24C8, 'M', u's'), + (0x24C9, 'M', u't'), + (0x24CA, 'M', u'u'), + (0x24CB, 'M', u'v'), + (0x24CC, 'M', u'w'), + (0x24CD, 'M', u'x'), + (0x24CE, 'M', u'y'), + (0x24CF, 'M', u'z'), + (0x24D0, 'M', u'a'), + (0x24D1, 'M', u'b'), + (0x24D2, 'M', u'c'), + (0x24D3, 'M', u'd'), + (0x24D4, 'M', u'e'), + (0x24D5, 'M', u'f'), + (0x24D6, 'M', u'g'), + (0x24D7, 'M', u'h'), + (0x24D8, 'M', u'i'), + (0x24D9, 'M', u'j'), + (0x24DA, 'M', u'k'), + (0x24DB, 'M', u'l'), + (0x24DC, 'M', u'm'), + (0x24DD, 'M', u'n'), + (0x24DE, 'M', u'o'), + (0x24DF, 'M', u'p'), + (0x24E0, 'M', u'q'), + (0x24E1, 'M', u'r'), + (0x24E2, 'M', u's'), + (0x24E3, 'M', u't'), + (0x24E4, 'M', u'u'), + (0x24E5, 'M', u'v'), + (0x24E6, 'M', u'w'), + (0x24E7, 'M', u'x'), + (0x24E8, 'M', u'y'), + (0x24E9, 'M', u'z'), + (0x24EA, 'M', u'0'), + (0x24EB, 'V'), + (0x2A0C, 'M', u'∫∫∫∫'), + (0x2A0D, 'V'), + (0x2A74, '3', u'::='), + (0x2A75, '3', u'=='), + (0x2A76, '3', u'==='), + (0x2A77, 'V'), + (0x2ADC, 'M', u'⫝̸'), + (0x2ADD, 'V'), + (0x2B74, 'X'), + (0x2B76, 'V'), + (0x2B96, 'X'), + (0x2B97, 'V'), + (0x2C00, 'M', u'ⰰ'), + (0x2C01, 'M', u'ⰱ'), + (0x2C02, 'M', u'ⰲ'), + (0x2C03, 'M', u'ⰳ'), + (0x2C04, 'M', u'ⰴ'), + (0x2C05, 'M', u'ⰵ'), + (0x2C06, 'M', u'ⰶ'), + (0x2C07, 'M', u'ⰷ'), + (0x2C08, 'M', u'ⰸ'), + (0x2C09, 'M', u'ⰹ'), + (0x2C0A, 'M', u'ⰺ'), + (0x2C0B, 'M', u'ⰻ'), + (0x2C0C, 'M', u'ⰼ'), + (0x2C0D, 'M', u'ⰽ'), + (0x2C0E, 'M', u'ⰾ'), + (0x2C0F, 'M', u'ⰿ'), + (0x2C10, 'M', u'ⱀ'), + (0x2C11, 'M', u'ⱁ'), + (0x2C12, 'M', u'ⱂ'), + (0x2C13, 'M', u'ⱃ'), + (0x2C14, 'M', u'ⱄ'), + (0x2C15, 'M', u'ⱅ'), + (0x2C16, 'M', u'ⱆ'), + (0x2C17, 'M', u'ⱇ'), + (0x2C18, 'M', u'ⱈ'), + (0x2C19, 'M', u'ⱉ'), + (0x2C1A, 'M', u'ⱊ'), + (0x2C1B, 'M', u'ⱋ'), + (0x2C1C, 'M', u'ⱌ'), + (0x2C1D, 'M', u'ⱍ'), + (0x2C1E, 'M', u'ⱎ'), + (0x2C1F, 'M', u'ⱏ'), + (0x2C20, 'M', u'ⱐ'), + (0x2C21, 'M', u'ⱑ'), + (0x2C22, 'M', u'ⱒ'), + (0x2C23, 'M', u'ⱓ'), + (0x2C24, 'M', u'ⱔ'), + (0x2C25, 'M', u'ⱕ'), + ] + +def _seg_25(): + return [ + (0x2C26, 'M', u'ⱖ'), + (0x2C27, 'M', u'ⱗ'), + (0x2C28, 'M', u'ⱘ'), + (0x2C29, 'M', u'ⱙ'), + (0x2C2A, 'M', u'ⱚ'), + (0x2C2B, 'M', u'ⱛ'), + (0x2C2C, 'M', u'ⱜ'), + (0x2C2D, 'M', u'ⱝ'), + (0x2C2E, 'M', u'ⱞ'), + (0x2C2F, 'X'), + (0x2C30, 'V'), + (0x2C5F, 'X'), + (0x2C60, 'M', u'ⱡ'), + (0x2C61, 'V'), + (0x2C62, 'M', u'ɫ'), + (0x2C63, 'M', u'ᵽ'), + (0x2C64, 'M', u'ɽ'), + (0x2C65, 'V'), + (0x2C67, 'M', u'ⱨ'), + (0x2C68, 'V'), + (0x2C69, 'M', u'ⱪ'), + (0x2C6A, 'V'), + (0x2C6B, 'M', u'ⱬ'), + (0x2C6C, 'V'), + (0x2C6D, 'M', u'ɑ'), + (0x2C6E, 'M', u'ɱ'), + (0x2C6F, 'M', u'ɐ'), + (0x2C70, 'M', u'ɒ'), + (0x2C71, 'V'), + (0x2C72, 'M', u'ⱳ'), + (0x2C73, 'V'), + (0x2C75, 'M', u'ⱶ'), + (0x2C76, 'V'), + (0x2C7C, 'M', u'j'), + (0x2C7D, 'M', u'v'), + (0x2C7E, 'M', u'ȿ'), + (0x2C7F, 'M', u'ɀ'), + (0x2C80, 'M', u'ⲁ'), + (0x2C81, 'V'), + (0x2C82, 'M', u'ⲃ'), + (0x2C83, 'V'), + (0x2C84, 'M', u'ⲅ'), + (0x2C85, 'V'), + (0x2C86, 'M', u'ⲇ'), + (0x2C87, 'V'), + (0x2C88, 'M', u'ⲉ'), + (0x2C89, 'V'), + (0x2C8A, 'M', u'ⲋ'), + (0x2C8B, 'V'), + (0x2C8C, 'M', u'ⲍ'), + (0x2C8D, 'V'), + (0x2C8E, 'M', u'ⲏ'), + (0x2C8F, 'V'), + (0x2C90, 'M', u'ⲑ'), + (0x2C91, 'V'), + (0x2C92, 'M', u'ⲓ'), + (0x2C93, 'V'), + (0x2C94, 'M', u'ⲕ'), + (0x2C95, 'V'), + (0x2C96, 'M', u'ⲗ'), + (0x2C97, 'V'), + (0x2C98, 'M', u'ⲙ'), + (0x2C99, 'V'), + (0x2C9A, 'M', u'ⲛ'), + (0x2C9B, 'V'), + (0x2C9C, 'M', u'ⲝ'), + (0x2C9D, 'V'), + (0x2C9E, 'M', u'ⲟ'), + (0x2C9F, 'V'), + (0x2CA0, 'M', u'ⲡ'), + (0x2CA1, 'V'), + (0x2CA2, 'M', u'ⲣ'), + (0x2CA3, 'V'), + (0x2CA4, 'M', u'ⲥ'), + (0x2CA5, 'V'), + (0x2CA6, 'M', u'ⲧ'), + (0x2CA7, 'V'), + (0x2CA8, 'M', u'ⲩ'), + (0x2CA9, 'V'), + (0x2CAA, 'M', u'ⲫ'), + (0x2CAB, 'V'), + (0x2CAC, 'M', u'ⲭ'), + (0x2CAD, 'V'), + (0x2CAE, 'M', u'ⲯ'), + (0x2CAF, 'V'), + (0x2CB0, 'M', u'ⲱ'), + (0x2CB1, 'V'), + (0x2CB2, 'M', u'ⲳ'), + (0x2CB3, 'V'), + (0x2CB4, 'M', u'ⲵ'), + (0x2CB5, 'V'), + (0x2CB6, 'M', u'ⲷ'), + (0x2CB7, 'V'), + (0x2CB8, 'M', u'ⲹ'), + (0x2CB9, 'V'), + (0x2CBA, 'M', u'ⲻ'), + (0x2CBB, 'V'), + (0x2CBC, 'M', u'ⲽ'), + (0x2CBD, 'V'), + (0x2CBE, 'M', u'ⲿ'), + ] + +def _seg_26(): + return [ + (0x2CBF, 'V'), + (0x2CC0, 'M', u'ⳁ'), + (0x2CC1, 'V'), + (0x2CC2, 'M', u'ⳃ'), + (0x2CC3, 'V'), + (0x2CC4, 'M', u'ⳅ'), + (0x2CC5, 'V'), + (0x2CC6, 'M', u'ⳇ'), + (0x2CC7, 'V'), + (0x2CC8, 'M', u'ⳉ'), + (0x2CC9, 'V'), + (0x2CCA, 'M', u'ⳋ'), + (0x2CCB, 'V'), + (0x2CCC, 'M', u'ⳍ'), + (0x2CCD, 'V'), + (0x2CCE, 'M', u'ⳏ'), + (0x2CCF, 'V'), + (0x2CD0, 'M', u'ⳑ'), + (0x2CD1, 'V'), + (0x2CD2, 'M', u'ⳓ'), + (0x2CD3, 'V'), + (0x2CD4, 'M', u'ⳕ'), + (0x2CD5, 'V'), + (0x2CD6, 'M', u'ⳗ'), + (0x2CD7, 'V'), + (0x2CD8, 'M', u'ⳙ'), + (0x2CD9, 'V'), + (0x2CDA, 'M', u'ⳛ'), + (0x2CDB, 'V'), + (0x2CDC, 'M', u'ⳝ'), + (0x2CDD, 'V'), + (0x2CDE, 'M', u'ⳟ'), + (0x2CDF, 'V'), + (0x2CE0, 'M', u'ⳡ'), + (0x2CE1, 'V'), + (0x2CE2, 'M', u'ⳣ'), + (0x2CE3, 'V'), + (0x2CEB, 'M', u'ⳬ'), + (0x2CEC, 'V'), + (0x2CED, 'M', u'ⳮ'), + (0x2CEE, 'V'), + (0x2CF2, 'M', u'ⳳ'), + (0x2CF3, 'V'), + (0x2CF4, 'X'), + (0x2CF9, 'V'), + (0x2D26, 'X'), + (0x2D27, 'V'), + (0x2D28, 'X'), + (0x2D2D, 'V'), + (0x2D2E, 'X'), + (0x2D30, 'V'), + (0x2D68, 'X'), + (0x2D6F, 'M', u'ⵡ'), + (0x2D70, 'V'), + (0x2D71, 'X'), + (0x2D7F, 'V'), + (0x2D97, 'X'), + (0x2DA0, 'V'), + (0x2DA7, 'X'), + (0x2DA8, 'V'), + (0x2DAF, 'X'), + (0x2DB0, 'V'), + (0x2DB7, 'X'), + (0x2DB8, 'V'), + (0x2DBF, 'X'), + (0x2DC0, 'V'), + (0x2DC7, 'X'), + (0x2DC8, 'V'), + (0x2DCF, 'X'), + (0x2DD0, 'V'), + (0x2DD7, 'X'), + (0x2DD8, 'V'), + (0x2DDF, 'X'), + (0x2DE0, 'V'), + (0x2E53, 'X'), + (0x2E80, 'V'), + (0x2E9A, 'X'), + (0x2E9B, 'V'), + (0x2E9F, 'M', u'母'), + (0x2EA0, 'V'), + (0x2EF3, 'M', u'龟'), + (0x2EF4, 'X'), + (0x2F00, 'M', u'一'), + (0x2F01, 'M', u'丨'), + (0x2F02, 'M', u'丶'), + (0x2F03, 'M', u'丿'), + (0x2F04, 'M', u'乙'), + (0x2F05, 'M', u'亅'), + (0x2F06, 'M', u'二'), + (0x2F07, 'M', u'亠'), + (0x2F08, 'M', u'人'), + (0x2F09, 'M', u'儿'), + (0x2F0A, 'M', u'入'), + (0x2F0B, 'M', u'八'), + (0x2F0C, 'M', u'冂'), + (0x2F0D, 'M', u'冖'), + (0x2F0E, 'M', u'冫'), + (0x2F0F, 'M', u'几'), + (0x2F10, 'M', u'凵'), + (0x2F11, 'M', u'刀'), + ] + +def _seg_27(): + return [ + (0x2F12, 'M', u'力'), + (0x2F13, 'M', u'勹'), + (0x2F14, 'M', u'匕'), + (0x2F15, 'M', u'匚'), + (0x2F16, 'M', u'匸'), + (0x2F17, 'M', u'十'), + (0x2F18, 'M', u'卜'), + (0x2F19, 'M', u'卩'), + (0x2F1A, 'M', u'厂'), + (0x2F1B, 'M', u'厶'), + (0x2F1C, 'M', u'又'), + (0x2F1D, 'M', u'口'), + (0x2F1E, 'M', u'囗'), + (0x2F1F, 'M', u'土'), + (0x2F20, 'M', u'士'), + (0x2F21, 'M', u'夂'), + (0x2F22, 'M', u'夊'), + (0x2F23, 'M', u'夕'), + (0x2F24, 'M', u'大'), + (0x2F25, 'M', u'女'), + (0x2F26, 'M', u'子'), + (0x2F27, 'M', u'宀'), + (0x2F28, 'M', u'寸'), + (0x2F29, 'M', u'小'), + (0x2F2A, 'M', u'尢'), + (0x2F2B, 'M', u'尸'), + (0x2F2C, 'M', u'屮'), + (0x2F2D, 'M', u'山'), + (0x2F2E, 'M', u'巛'), + (0x2F2F, 'M', u'工'), + (0x2F30, 'M', u'己'), + (0x2F31, 'M', u'巾'), + (0x2F32, 'M', u'干'), + (0x2F33, 'M', u'幺'), + (0x2F34, 'M', u'广'), + (0x2F35, 'M', u'廴'), + (0x2F36, 'M', u'廾'), + (0x2F37, 'M', u'弋'), + (0x2F38, 'M', u'弓'), + (0x2F39, 'M', u'彐'), + (0x2F3A, 'M', u'彡'), + (0x2F3B, 'M', u'彳'), + (0x2F3C, 'M', u'心'), + (0x2F3D, 'M', u'戈'), + (0x2F3E, 'M', u'戶'), + (0x2F3F, 'M', u'手'), + (0x2F40, 'M', u'支'), + (0x2F41, 'M', u'攴'), + (0x2F42, 'M', u'文'), + (0x2F43, 'M', u'斗'), + (0x2F44, 'M', u'斤'), + (0x2F45, 'M', u'方'), + (0x2F46, 'M', u'无'), + (0x2F47, 'M', u'日'), + (0x2F48, 'M', u'曰'), + (0x2F49, 'M', u'月'), + (0x2F4A, 'M', u'木'), + (0x2F4B, 'M', u'欠'), + (0x2F4C, 'M', u'止'), + (0x2F4D, 'M', u'歹'), + (0x2F4E, 'M', u'殳'), + (0x2F4F, 'M', u'毋'), + (0x2F50, 'M', u'比'), + (0x2F51, 'M', u'毛'), + (0x2F52, 'M', u'氏'), + (0x2F53, 'M', u'气'), + (0x2F54, 'M', u'水'), + (0x2F55, 'M', u'火'), + (0x2F56, 'M', u'爪'), + (0x2F57, 'M', u'父'), + (0x2F58, 'M', u'爻'), + (0x2F59, 'M', u'爿'), + (0x2F5A, 'M', u'片'), + (0x2F5B, 'M', u'牙'), + (0x2F5C, 'M', u'牛'), + (0x2F5D, 'M', u'犬'), + (0x2F5E, 'M', u'玄'), + (0x2F5F, 'M', u'玉'), + (0x2F60, 'M', u'瓜'), + (0x2F61, 'M', u'瓦'), + (0x2F62, 'M', u'甘'), + (0x2F63, 'M', u'生'), + (0x2F64, 'M', u'用'), + (0x2F65, 'M', u'田'), + (0x2F66, 'M', u'疋'), + (0x2F67, 'M', u'疒'), + (0x2F68, 'M', u'癶'), + (0x2F69, 'M', u'白'), + (0x2F6A, 'M', u'皮'), + (0x2F6B, 'M', u'皿'), + (0x2F6C, 'M', u'目'), + (0x2F6D, 'M', u'矛'), + (0x2F6E, 'M', u'矢'), + (0x2F6F, 'M', u'石'), + (0x2F70, 'M', u'示'), + (0x2F71, 'M', u'禸'), + (0x2F72, 'M', u'禾'), + (0x2F73, 'M', u'穴'), + (0x2F74, 'M', u'立'), + (0x2F75, 'M', u'竹'), + ] + +def _seg_28(): + return [ + (0x2F76, 'M', u'米'), + (0x2F77, 'M', u'糸'), + (0x2F78, 'M', u'缶'), + (0x2F79, 'M', u'网'), + (0x2F7A, 'M', u'羊'), + (0x2F7B, 'M', u'羽'), + (0x2F7C, 'M', u'老'), + (0x2F7D, 'M', u'而'), + (0x2F7E, 'M', u'耒'), + (0x2F7F, 'M', u'耳'), + (0x2F80, 'M', u'聿'), + (0x2F81, 'M', u'肉'), + (0x2F82, 'M', u'臣'), + (0x2F83, 'M', u'自'), + (0x2F84, 'M', u'至'), + (0x2F85, 'M', u'臼'), + (0x2F86, 'M', u'舌'), + (0x2F87, 'M', u'舛'), + (0x2F88, 'M', u'舟'), + (0x2F89, 'M', u'艮'), + (0x2F8A, 'M', u'色'), + (0x2F8B, 'M', u'艸'), + (0x2F8C, 'M', u'虍'), + (0x2F8D, 'M', u'虫'), + (0x2F8E, 'M', u'血'), + (0x2F8F, 'M', u'行'), + (0x2F90, 'M', u'衣'), + (0x2F91, 'M', u'襾'), + (0x2F92, 'M', u'見'), + (0x2F93, 'M', u'角'), + (0x2F94, 'M', u'言'), + (0x2F95, 'M', u'谷'), + (0x2F96, 'M', u'豆'), + (0x2F97, 'M', u'豕'), + (0x2F98, 'M', u'豸'), + (0x2F99, 'M', u'貝'), + (0x2F9A, 'M', u'赤'), + (0x2F9B, 'M', u'走'), + (0x2F9C, 'M', u'足'), + (0x2F9D, 'M', u'身'), + (0x2F9E, 'M', u'車'), + (0x2F9F, 'M', u'辛'), + (0x2FA0, 'M', u'辰'), + (0x2FA1, 'M', u'辵'), + (0x2FA2, 'M', u'邑'), + (0x2FA3, 'M', u'酉'), + (0x2FA4, 'M', u'釆'), + (0x2FA5, 'M', u'里'), + (0x2FA6, 'M', u'金'), + (0x2FA7, 'M', u'長'), + (0x2FA8, 'M', u'門'), + (0x2FA9, 'M', u'阜'), + (0x2FAA, 'M', u'隶'), + (0x2FAB, 'M', u'隹'), + (0x2FAC, 'M', u'雨'), + (0x2FAD, 'M', u'靑'), + (0x2FAE, 'M', u'非'), + (0x2FAF, 'M', u'面'), + (0x2FB0, 'M', u'革'), + (0x2FB1, 'M', u'韋'), + (0x2FB2, 'M', u'韭'), + (0x2FB3, 'M', u'音'), + (0x2FB4, 'M', u'頁'), + (0x2FB5, 'M', u'風'), + (0x2FB6, 'M', u'飛'), + (0x2FB7, 'M', u'食'), + (0x2FB8, 'M', u'首'), + (0x2FB9, 'M', u'香'), + (0x2FBA, 'M', u'馬'), + (0x2FBB, 'M', u'骨'), + (0x2FBC, 'M', u'高'), + (0x2FBD, 'M', u'髟'), + (0x2FBE, 'M', u'鬥'), + (0x2FBF, 'M', u'鬯'), + (0x2FC0, 'M', u'鬲'), + (0x2FC1, 'M', u'鬼'), + (0x2FC2, 'M', u'魚'), + (0x2FC3, 'M', u'鳥'), + (0x2FC4, 'M', u'鹵'), + (0x2FC5, 'M', u'鹿'), + (0x2FC6, 'M', u'麥'), + (0x2FC7, 'M', u'麻'), + (0x2FC8, 'M', u'黃'), + (0x2FC9, 'M', u'黍'), + (0x2FCA, 'M', u'黑'), + (0x2FCB, 'M', u'黹'), + (0x2FCC, 'M', u'黽'), + (0x2FCD, 'M', u'鼎'), + (0x2FCE, 'M', u'鼓'), + (0x2FCF, 'M', u'鼠'), + (0x2FD0, 'M', u'鼻'), + (0x2FD1, 'M', u'齊'), + (0x2FD2, 'M', u'齒'), + (0x2FD3, 'M', u'龍'), + (0x2FD4, 'M', u'龜'), + (0x2FD5, 'M', u'龠'), + (0x2FD6, 'X'), + (0x3000, '3', u' '), + (0x3001, 'V'), + (0x3002, 'M', u'.'), + ] + +def _seg_29(): + return [ + (0x3003, 'V'), + (0x3036, 'M', u'〒'), + (0x3037, 'V'), + (0x3038, 'M', u'十'), + (0x3039, 'M', u'卄'), + (0x303A, 'M', u'卅'), + (0x303B, 'V'), + (0x3040, 'X'), + (0x3041, 'V'), + (0x3097, 'X'), + (0x3099, 'V'), + (0x309B, '3', u' ゙'), + (0x309C, '3', u' ゚'), + (0x309D, 'V'), + (0x309F, 'M', u'より'), + (0x30A0, 'V'), + (0x30FF, 'M', u'コト'), + (0x3100, 'X'), + (0x3105, 'V'), + (0x3130, 'X'), + (0x3131, 'M', u'ᄀ'), + (0x3132, 'M', u'ᄁ'), + (0x3133, 'M', u'ᆪ'), + (0x3134, 'M', u'ᄂ'), + (0x3135, 'M', u'ᆬ'), + (0x3136, 'M', u'ᆭ'), + (0x3137, 'M', u'ᄃ'), + (0x3138, 'M', u'ᄄ'), + (0x3139, 'M', u'ᄅ'), + (0x313A, 'M', u'ᆰ'), + (0x313B, 'M', u'ᆱ'), + (0x313C, 'M', u'ᆲ'), + (0x313D, 'M', u'ᆳ'), + (0x313E, 'M', u'ᆴ'), + (0x313F, 'M', u'ᆵ'), + (0x3140, 'M', u'ᄚ'), + (0x3141, 'M', u'ᄆ'), + (0x3142, 'M', u'ᄇ'), + (0x3143, 'M', u'ᄈ'), + (0x3144, 'M', u'ᄡ'), + (0x3145, 'M', u'ᄉ'), + (0x3146, 'M', u'ᄊ'), + (0x3147, 'M', u'ᄋ'), + (0x3148, 'M', u'ᄌ'), + (0x3149, 'M', u'ᄍ'), + (0x314A, 'M', u'ᄎ'), + (0x314B, 'M', u'ᄏ'), + (0x314C, 'M', u'ᄐ'), + (0x314D, 'M', u'ᄑ'), + (0x314E, 'M', u'ᄒ'), + (0x314F, 'M', u'ᅡ'), + (0x3150, 'M', u'ᅢ'), + (0x3151, 'M', u'ᅣ'), + (0x3152, 'M', u'ᅤ'), + (0x3153, 'M', u'ᅥ'), + (0x3154, 'M', u'ᅦ'), + (0x3155, 'M', u'ᅧ'), + (0x3156, 'M', u'ᅨ'), + (0x3157, 'M', u'ᅩ'), + (0x3158, 'M', u'ᅪ'), + (0x3159, 'M', u'ᅫ'), + (0x315A, 'M', u'ᅬ'), + (0x315B, 'M', u'ᅭ'), + (0x315C, 'M', u'ᅮ'), + (0x315D, 'M', u'ᅯ'), + (0x315E, 'M', u'ᅰ'), + (0x315F, 'M', u'ᅱ'), + (0x3160, 'M', u'ᅲ'), + (0x3161, 'M', u'ᅳ'), + (0x3162, 'M', u'ᅴ'), + (0x3163, 'M', u'ᅵ'), + (0x3164, 'X'), + (0x3165, 'M', u'ᄔ'), + (0x3166, 'M', u'ᄕ'), + (0x3167, 'M', u'ᇇ'), + (0x3168, 'M', u'ᇈ'), + (0x3169, 'M', u'ᇌ'), + (0x316A, 'M', u'ᇎ'), + (0x316B, 'M', u'ᇓ'), + (0x316C, 'M', u'ᇗ'), + (0x316D, 'M', u'ᇙ'), + (0x316E, 'M', u'ᄜ'), + (0x316F, 'M', u'ᇝ'), + (0x3170, 'M', u'ᇟ'), + (0x3171, 'M', u'ᄝ'), + (0x3172, 'M', u'ᄞ'), + (0x3173, 'M', u'ᄠ'), + (0x3174, 'M', u'ᄢ'), + (0x3175, 'M', u'ᄣ'), + (0x3176, 'M', u'ᄧ'), + (0x3177, 'M', u'ᄩ'), + (0x3178, 'M', u'ᄫ'), + (0x3179, 'M', u'ᄬ'), + (0x317A, 'M', u'ᄭ'), + (0x317B, 'M', u'ᄮ'), + (0x317C, 'M', u'ᄯ'), + (0x317D, 'M', u'ᄲ'), + (0x317E, 'M', u'ᄶ'), + (0x317F, 'M', u'ᅀ'), + (0x3180, 'M', u'ᅇ'), + ] + +def _seg_30(): + return [ + (0x3181, 'M', u'ᅌ'), + (0x3182, 'M', u'ᇱ'), + (0x3183, 'M', u'ᇲ'), + (0x3184, 'M', u'ᅗ'), + (0x3185, 'M', u'ᅘ'), + (0x3186, 'M', u'ᅙ'), + (0x3187, 'M', u'ᆄ'), + (0x3188, 'M', u'ᆅ'), + (0x3189, 'M', u'ᆈ'), + (0x318A, 'M', u'ᆑ'), + (0x318B, 'M', u'ᆒ'), + (0x318C, 'M', u'ᆔ'), + (0x318D, 'M', u'ᆞ'), + (0x318E, 'M', u'ᆡ'), + (0x318F, 'X'), + (0x3190, 'V'), + (0x3192, 'M', u'一'), + (0x3193, 'M', u'二'), + (0x3194, 'M', u'三'), + (0x3195, 'M', u'四'), + (0x3196, 'M', u'上'), + (0x3197, 'M', u'中'), + (0x3198, 'M', u'下'), + (0x3199, 'M', u'甲'), + (0x319A, 'M', u'乙'), + (0x319B, 'M', u'丙'), + (0x319C, 'M', u'丁'), + (0x319D, 'M', u'天'), + (0x319E, 'M', u'地'), + (0x319F, 'M', u'人'), + (0x31A0, 'V'), + (0x31E4, 'X'), + (0x31F0, 'V'), + (0x3200, '3', u'(ᄀ)'), + (0x3201, '3', u'(ᄂ)'), + (0x3202, '3', u'(ᄃ)'), + (0x3203, '3', u'(ᄅ)'), + (0x3204, '3', u'(ᄆ)'), + (0x3205, '3', u'(ᄇ)'), + (0x3206, '3', u'(ᄉ)'), + (0x3207, '3', u'(ᄋ)'), + (0x3208, '3', u'(ᄌ)'), + (0x3209, '3', u'(ᄎ)'), + (0x320A, '3', u'(ᄏ)'), + (0x320B, '3', u'(ᄐ)'), + (0x320C, '3', u'(ᄑ)'), + (0x320D, '3', u'(ᄒ)'), + (0x320E, '3', u'(가)'), + (0x320F, '3', u'(나)'), + (0x3210, '3', u'(다)'), + (0x3211, '3', u'(라)'), + (0x3212, '3', u'(마)'), + (0x3213, '3', u'(바)'), + (0x3214, '3', u'(사)'), + (0x3215, '3', u'(아)'), + (0x3216, '3', u'(자)'), + (0x3217, '3', u'(차)'), + (0x3218, '3', u'(카)'), + (0x3219, '3', u'(타)'), + (0x321A, '3', u'(파)'), + (0x321B, '3', u'(하)'), + (0x321C, '3', u'(주)'), + (0x321D, '3', u'(오전)'), + (0x321E, '3', u'(오후)'), + (0x321F, 'X'), + (0x3220, '3', u'(一)'), + (0x3221, '3', u'(二)'), + (0x3222, '3', u'(三)'), + (0x3223, '3', u'(四)'), + (0x3224, '3', u'(五)'), + (0x3225, '3', u'(六)'), + (0x3226, '3', u'(七)'), + (0x3227, '3', u'(八)'), + (0x3228, '3', u'(九)'), + (0x3229, '3', u'(十)'), + (0x322A, '3', u'(月)'), + (0x322B, '3', u'(火)'), + (0x322C, '3', u'(水)'), + (0x322D, '3', u'(木)'), + (0x322E, '3', u'(金)'), + (0x322F, '3', u'(土)'), + (0x3230, '3', u'(日)'), + (0x3231, '3', u'(株)'), + (0x3232, '3', u'(有)'), + (0x3233, '3', u'(社)'), + (0x3234, '3', u'(名)'), + (0x3235, '3', u'(特)'), + (0x3236, '3', u'(財)'), + (0x3237, '3', u'(祝)'), + (0x3238, '3', u'(労)'), + (0x3239, '3', u'(代)'), + (0x323A, '3', u'(呼)'), + (0x323B, '3', u'(学)'), + (0x323C, '3', u'(監)'), + (0x323D, '3', u'(企)'), + (0x323E, '3', u'(資)'), + (0x323F, '3', u'(協)'), + (0x3240, '3', u'(祭)'), + (0x3241, '3', u'(休)'), + (0x3242, '3', u'(自)'), + ] + +def _seg_31(): + return [ + (0x3243, '3', u'(至)'), + (0x3244, 'M', u'問'), + (0x3245, 'M', u'幼'), + (0x3246, 'M', u'文'), + (0x3247, 'M', u'箏'), + (0x3248, 'V'), + (0x3250, 'M', u'pte'), + (0x3251, 'M', u'21'), + (0x3252, 'M', u'22'), + (0x3253, 'M', u'23'), + (0x3254, 'M', u'24'), + (0x3255, 'M', u'25'), + (0x3256, 'M', u'26'), + (0x3257, 'M', u'27'), + (0x3258, 'M', u'28'), + (0x3259, 'M', u'29'), + (0x325A, 'M', u'30'), + (0x325B, 'M', u'31'), + (0x325C, 'M', u'32'), + (0x325D, 'M', u'33'), + (0x325E, 'M', u'34'), + (0x325F, 'M', u'35'), + (0x3260, 'M', u'ᄀ'), + (0x3261, 'M', u'ᄂ'), + (0x3262, 'M', u'ᄃ'), + (0x3263, 'M', u'ᄅ'), + (0x3264, 'M', u'ᄆ'), + (0x3265, 'M', u'ᄇ'), + (0x3266, 'M', u'ᄉ'), + (0x3267, 'M', u'ᄋ'), + (0x3268, 'M', u'ᄌ'), + (0x3269, 'M', u'ᄎ'), + (0x326A, 'M', u'ᄏ'), + (0x326B, 'M', u'ᄐ'), + (0x326C, 'M', u'ᄑ'), + (0x326D, 'M', u'ᄒ'), + (0x326E, 'M', u'가'), + (0x326F, 'M', u'나'), + (0x3270, 'M', u'다'), + (0x3271, 'M', u'라'), + (0x3272, 'M', u'마'), + (0x3273, 'M', u'바'), + (0x3274, 'M', u'사'), + (0x3275, 'M', u'아'), + (0x3276, 'M', u'자'), + (0x3277, 'M', u'차'), + (0x3278, 'M', u'카'), + (0x3279, 'M', u'타'), + (0x327A, 'M', u'파'), + (0x327B, 'M', u'하'), + (0x327C, 'M', u'참고'), + (0x327D, 'M', u'주의'), + (0x327E, 'M', u'우'), + (0x327F, 'V'), + (0x3280, 'M', u'一'), + (0x3281, 'M', u'二'), + (0x3282, 'M', u'三'), + (0x3283, 'M', u'四'), + (0x3284, 'M', u'五'), + (0x3285, 'M', u'六'), + (0x3286, 'M', u'七'), + (0x3287, 'M', u'八'), + (0x3288, 'M', u'九'), + (0x3289, 'M', u'十'), + (0x328A, 'M', u'月'), + (0x328B, 'M', u'火'), + (0x328C, 'M', u'水'), + (0x328D, 'M', u'木'), + (0x328E, 'M', u'金'), + (0x328F, 'M', u'土'), + (0x3290, 'M', u'日'), + (0x3291, 'M', u'株'), + (0x3292, 'M', u'有'), + (0x3293, 'M', u'社'), + (0x3294, 'M', u'名'), + (0x3295, 'M', u'特'), + (0x3296, 'M', u'財'), + (0x3297, 'M', u'祝'), + (0x3298, 'M', u'労'), + (0x3299, 'M', u'秘'), + (0x329A, 'M', u'男'), + (0x329B, 'M', u'女'), + (0x329C, 'M', u'適'), + (0x329D, 'M', u'優'), + (0x329E, 'M', u'印'), + (0x329F, 'M', u'注'), + (0x32A0, 'M', u'項'), + (0x32A1, 'M', u'休'), + (0x32A2, 'M', u'写'), + (0x32A3, 'M', u'正'), + (0x32A4, 'M', u'上'), + (0x32A5, 'M', u'中'), + (0x32A6, 'M', u'下'), + (0x32A7, 'M', u'左'), + (0x32A8, 'M', u'右'), + (0x32A9, 'M', u'医'), + (0x32AA, 'M', u'宗'), + (0x32AB, 'M', u'学'), + (0x32AC, 'M', u'監'), + (0x32AD, 'M', u'企'), + ] + +def _seg_32(): + return [ + (0x32AE, 'M', u'資'), + (0x32AF, 'M', u'協'), + (0x32B0, 'M', u'夜'), + (0x32B1, 'M', u'36'), + (0x32B2, 'M', u'37'), + (0x32B3, 'M', u'38'), + (0x32B4, 'M', u'39'), + (0x32B5, 'M', u'40'), + (0x32B6, 'M', u'41'), + (0x32B7, 'M', u'42'), + (0x32B8, 'M', u'43'), + (0x32B9, 'M', u'44'), + (0x32BA, 'M', u'45'), + (0x32BB, 'M', u'46'), + (0x32BC, 'M', u'47'), + (0x32BD, 'M', u'48'), + (0x32BE, 'M', u'49'), + (0x32BF, 'M', u'50'), + (0x32C0, 'M', u'1月'), + (0x32C1, 'M', u'2月'), + (0x32C2, 'M', u'3月'), + (0x32C3, 'M', u'4月'), + (0x32C4, 'M', u'5月'), + (0x32C5, 'M', u'6月'), + (0x32C6, 'M', u'7月'), + (0x32C7, 'M', u'8月'), + (0x32C8, 'M', u'9月'), + (0x32C9, 'M', u'10月'), + (0x32CA, 'M', u'11月'), + (0x32CB, 'M', u'12月'), + (0x32CC, 'M', u'hg'), + (0x32CD, 'M', u'erg'), + (0x32CE, 'M', u'ev'), + (0x32CF, 'M', u'ltd'), + (0x32D0, 'M', u'ア'), + (0x32D1, 'M', u'イ'), + (0x32D2, 'M', u'ウ'), + (0x32D3, 'M', u'エ'), + (0x32D4, 'M', u'オ'), + (0x32D5, 'M', u'カ'), + (0x32D6, 'M', u'キ'), + (0x32D7, 'M', u'ク'), + (0x32D8, 'M', u'ケ'), + (0x32D9, 'M', u'コ'), + (0x32DA, 'M', u'サ'), + (0x32DB, 'M', u'シ'), + (0x32DC, 'M', u'ス'), + (0x32DD, 'M', u'セ'), + (0x32DE, 'M', u'ソ'), + (0x32DF, 'M', u'タ'), + (0x32E0, 'M', u'チ'), + (0x32E1, 'M', u'ツ'), + (0x32E2, 'M', u'テ'), + (0x32E3, 'M', u'ト'), + (0x32E4, 'M', u'ナ'), + (0x32E5, 'M', u'ニ'), + (0x32E6, 'M', u'ヌ'), + (0x32E7, 'M', u'ネ'), + (0x32E8, 'M', u'ノ'), + (0x32E9, 'M', u'ハ'), + (0x32EA, 'M', u'ヒ'), + (0x32EB, 'M', u'フ'), + (0x32EC, 'M', u'ヘ'), + (0x32ED, 'M', u'ホ'), + (0x32EE, 'M', u'マ'), + (0x32EF, 'M', u'ミ'), + (0x32F0, 'M', u'ム'), + (0x32F1, 'M', u'メ'), + (0x32F2, 'M', u'モ'), + (0x32F3, 'M', u'ヤ'), + (0x32F4, 'M', u'ユ'), + (0x32F5, 'M', u'ヨ'), + (0x32F6, 'M', u'ラ'), + (0x32F7, 'M', u'リ'), + (0x32F8, 'M', u'ル'), + (0x32F9, 'M', u'レ'), + (0x32FA, 'M', u'ロ'), + (0x32FB, 'M', u'ワ'), + (0x32FC, 'M', u'ヰ'), + (0x32FD, 'M', u'ヱ'), + (0x32FE, 'M', u'ヲ'), + (0x32FF, 'M', u'令和'), + (0x3300, 'M', u'アパート'), + (0x3301, 'M', u'アルファ'), + (0x3302, 'M', u'アンペア'), + (0x3303, 'M', u'アール'), + (0x3304, 'M', u'イニング'), + (0x3305, 'M', u'インチ'), + (0x3306, 'M', u'ウォン'), + (0x3307, 'M', u'エスクード'), + (0x3308, 'M', u'エーカー'), + (0x3309, 'M', u'オンス'), + (0x330A, 'M', u'オーム'), + (0x330B, 'M', u'カイリ'), + (0x330C, 'M', u'カラット'), + (0x330D, 'M', u'カロリー'), + (0x330E, 'M', u'ガロン'), + (0x330F, 'M', u'ガンマ'), + (0x3310, 'M', u'ギガ'), + (0x3311, 'M', u'ギニー'), + ] + +def _seg_33(): + return [ + (0x3312, 'M', u'キュリー'), + (0x3313, 'M', u'ギルダー'), + (0x3314, 'M', u'キロ'), + (0x3315, 'M', u'キログラム'), + (0x3316, 'M', u'キロメートル'), + (0x3317, 'M', u'キロワット'), + (0x3318, 'M', u'グラム'), + (0x3319, 'M', u'グラムトン'), + (0x331A, 'M', u'クルゼイロ'), + (0x331B, 'M', u'クローネ'), + (0x331C, 'M', u'ケース'), + (0x331D, 'M', u'コルナ'), + (0x331E, 'M', u'コーポ'), + (0x331F, 'M', u'サイクル'), + (0x3320, 'M', u'サンチーム'), + (0x3321, 'M', u'シリング'), + (0x3322, 'M', u'センチ'), + (0x3323, 'M', u'セント'), + (0x3324, 'M', u'ダース'), + (0x3325, 'M', u'デシ'), + (0x3326, 'M', u'ドル'), + (0x3327, 'M', u'トン'), + (0x3328, 'M', u'ナノ'), + (0x3329, 'M', u'ノット'), + (0x332A, 'M', u'ハイツ'), + (0x332B, 'M', u'パーセント'), + (0x332C, 'M', u'パーツ'), + (0x332D, 'M', u'バーレル'), + (0x332E, 'M', u'ピアストル'), + (0x332F, 'M', u'ピクル'), + (0x3330, 'M', u'ピコ'), + (0x3331, 'M', u'ビル'), + (0x3332, 'M', u'ファラッド'), + (0x3333, 'M', u'フィート'), + (0x3334, 'M', u'ブッシェル'), + (0x3335, 'M', u'フラン'), + (0x3336, 'M', u'ヘクタール'), + (0x3337, 'M', u'ペソ'), + (0x3338, 'M', u'ペニヒ'), + (0x3339, 'M', u'ヘルツ'), + (0x333A, 'M', u'ペンス'), + (0x333B, 'M', u'ページ'), + (0x333C, 'M', u'ベータ'), + (0x333D, 'M', u'ポイント'), + (0x333E, 'M', u'ボルト'), + (0x333F, 'M', u'ホン'), + (0x3340, 'M', u'ポンド'), + (0x3341, 'M', u'ホール'), + (0x3342, 'M', u'ホーン'), + (0x3343, 'M', u'マイクロ'), + (0x3344, 'M', u'マイル'), + (0x3345, 'M', u'マッハ'), + (0x3346, 'M', u'マルク'), + (0x3347, 'M', u'マンション'), + (0x3348, 'M', u'ミクロン'), + (0x3349, 'M', u'ミリ'), + (0x334A, 'M', u'ミリバール'), + (0x334B, 'M', u'メガ'), + (0x334C, 'M', u'メガトン'), + (0x334D, 'M', u'メートル'), + (0x334E, 'M', u'ヤード'), + (0x334F, 'M', u'ヤール'), + (0x3350, 'M', u'ユアン'), + (0x3351, 'M', u'リットル'), + (0x3352, 'M', u'リラ'), + (0x3353, 'M', u'ルピー'), + (0x3354, 'M', u'ルーブル'), + (0x3355, 'M', u'レム'), + (0x3356, 'M', u'レントゲン'), + (0x3357, 'M', u'ワット'), + (0x3358, 'M', u'0点'), + (0x3359, 'M', u'1点'), + (0x335A, 'M', u'2点'), + (0x335B, 'M', u'3点'), + (0x335C, 'M', u'4点'), + (0x335D, 'M', u'5点'), + (0x335E, 'M', u'6点'), + (0x335F, 'M', u'7点'), + (0x3360, 'M', u'8点'), + (0x3361, 'M', u'9点'), + (0x3362, 'M', u'10点'), + (0x3363, 'M', u'11点'), + (0x3364, 'M', u'12点'), + (0x3365, 'M', u'13点'), + (0x3366, 'M', u'14点'), + (0x3367, 'M', u'15点'), + (0x3368, 'M', u'16点'), + (0x3369, 'M', u'17点'), + (0x336A, 'M', u'18点'), + (0x336B, 'M', u'19点'), + (0x336C, 'M', u'20点'), + (0x336D, 'M', u'21点'), + (0x336E, 'M', u'22点'), + (0x336F, 'M', u'23点'), + (0x3370, 'M', u'24点'), + (0x3371, 'M', u'hpa'), + (0x3372, 'M', u'da'), + (0x3373, 'M', u'au'), + (0x3374, 'M', u'bar'), + (0x3375, 'M', u'ov'), + ] + +def _seg_34(): + return [ + (0x3376, 'M', u'pc'), + (0x3377, 'M', u'dm'), + (0x3378, 'M', u'dm2'), + (0x3379, 'M', u'dm3'), + (0x337A, 'M', u'iu'), + (0x337B, 'M', u'平成'), + (0x337C, 'M', u'昭和'), + (0x337D, 'M', u'大正'), + (0x337E, 'M', u'明治'), + (0x337F, 'M', u'株式会社'), + (0x3380, 'M', u'pa'), + (0x3381, 'M', u'na'), + (0x3382, 'M', u'μa'), + (0x3383, 'M', u'ma'), + (0x3384, 'M', u'ka'), + (0x3385, 'M', u'kb'), + (0x3386, 'M', u'mb'), + (0x3387, 'M', u'gb'), + (0x3388, 'M', u'cal'), + (0x3389, 'M', u'kcal'), + (0x338A, 'M', u'pf'), + (0x338B, 'M', u'nf'), + (0x338C, 'M', u'μf'), + (0x338D, 'M', u'μg'), + (0x338E, 'M', u'mg'), + (0x338F, 'M', u'kg'), + (0x3390, 'M', u'hz'), + (0x3391, 'M', u'khz'), + (0x3392, 'M', u'mhz'), + (0x3393, 'M', u'ghz'), + (0x3394, 'M', u'thz'), + (0x3395, 'M', u'μl'), + (0x3396, 'M', u'ml'), + (0x3397, 'M', u'dl'), + (0x3398, 'M', u'kl'), + (0x3399, 'M', u'fm'), + (0x339A, 'M', u'nm'), + (0x339B, 'M', u'μm'), + (0x339C, 'M', u'mm'), + (0x339D, 'M', u'cm'), + (0x339E, 'M', u'km'), + (0x339F, 'M', u'mm2'), + (0x33A0, 'M', u'cm2'), + (0x33A1, 'M', u'm2'), + (0x33A2, 'M', u'km2'), + (0x33A3, 'M', u'mm3'), + (0x33A4, 'M', u'cm3'), + (0x33A5, 'M', u'm3'), + (0x33A6, 'M', u'km3'), + (0x33A7, 'M', u'm∕s'), + (0x33A8, 'M', u'm∕s2'), + (0x33A9, 'M', u'pa'), + (0x33AA, 'M', u'kpa'), + (0x33AB, 'M', u'mpa'), + (0x33AC, 'M', u'gpa'), + (0x33AD, 'M', u'rad'), + (0x33AE, 'M', u'rad∕s'), + (0x33AF, 'M', u'rad∕s2'), + (0x33B0, 'M', u'ps'), + (0x33B1, 'M', u'ns'), + (0x33B2, 'M', u'μs'), + (0x33B3, 'M', u'ms'), + (0x33B4, 'M', u'pv'), + (0x33B5, 'M', u'nv'), + (0x33B6, 'M', u'μv'), + (0x33B7, 'M', u'mv'), + (0x33B8, 'M', u'kv'), + (0x33B9, 'M', u'mv'), + (0x33BA, 'M', u'pw'), + (0x33BB, 'M', u'nw'), + (0x33BC, 'M', u'μw'), + (0x33BD, 'M', u'mw'), + (0x33BE, 'M', u'kw'), + (0x33BF, 'M', u'mw'), + (0x33C0, 'M', u'kω'), + (0x33C1, 'M', u'mω'), + (0x33C2, 'X'), + (0x33C3, 'M', u'bq'), + (0x33C4, 'M', u'cc'), + (0x33C5, 'M', u'cd'), + (0x33C6, 'M', u'c∕kg'), + (0x33C7, 'X'), + (0x33C8, 'M', u'db'), + (0x33C9, 'M', u'gy'), + (0x33CA, 'M', u'ha'), + (0x33CB, 'M', u'hp'), + (0x33CC, 'M', u'in'), + (0x33CD, 'M', u'kk'), + (0x33CE, 'M', u'km'), + (0x33CF, 'M', u'kt'), + (0x33D0, 'M', u'lm'), + (0x33D1, 'M', u'ln'), + (0x33D2, 'M', u'log'), + (0x33D3, 'M', u'lx'), + (0x33D4, 'M', u'mb'), + (0x33D5, 'M', u'mil'), + (0x33D6, 'M', u'mol'), + (0x33D7, 'M', u'ph'), + (0x33D8, 'X'), + (0x33D9, 'M', u'ppm'), + ] + +def _seg_35(): + return [ + (0x33DA, 'M', u'pr'), + (0x33DB, 'M', u'sr'), + (0x33DC, 'M', u'sv'), + (0x33DD, 'M', u'wb'), + (0x33DE, 'M', u'v∕m'), + (0x33DF, 'M', u'a∕m'), + (0x33E0, 'M', u'1日'), + (0x33E1, 'M', u'2日'), + (0x33E2, 'M', u'3日'), + (0x33E3, 'M', u'4日'), + (0x33E4, 'M', u'5日'), + (0x33E5, 'M', u'6日'), + (0x33E6, 'M', u'7日'), + (0x33E7, 'M', u'8日'), + (0x33E8, 'M', u'9日'), + (0x33E9, 'M', u'10日'), + (0x33EA, 'M', u'11日'), + (0x33EB, 'M', u'12日'), + (0x33EC, 'M', u'13日'), + (0x33ED, 'M', u'14日'), + (0x33EE, 'M', u'15日'), + (0x33EF, 'M', u'16日'), + (0x33F0, 'M', u'17日'), + (0x33F1, 'M', u'18日'), + (0x33F2, 'M', u'19日'), + (0x33F3, 'M', u'20日'), + (0x33F4, 'M', u'21日'), + (0x33F5, 'M', u'22日'), + (0x33F6, 'M', u'23日'), + (0x33F7, 'M', u'24日'), + (0x33F8, 'M', u'25日'), + (0x33F9, 'M', u'26日'), + (0x33FA, 'M', u'27日'), + (0x33FB, 'M', u'28日'), + (0x33FC, 'M', u'29日'), + (0x33FD, 'M', u'30日'), + (0x33FE, 'M', u'31日'), + (0x33FF, 'M', u'gal'), + (0x3400, 'V'), + (0x9FFD, 'X'), + (0xA000, 'V'), + (0xA48D, 'X'), + (0xA490, 'V'), + (0xA4C7, 'X'), + (0xA4D0, 'V'), + (0xA62C, 'X'), + (0xA640, 'M', u'ꙁ'), + (0xA641, 'V'), + (0xA642, 'M', u'ꙃ'), + (0xA643, 'V'), + (0xA644, 'M', u'ꙅ'), + (0xA645, 'V'), + (0xA646, 'M', u'ꙇ'), + (0xA647, 'V'), + (0xA648, 'M', u'ꙉ'), + (0xA649, 'V'), + (0xA64A, 'M', u'ꙋ'), + (0xA64B, 'V'), + (0xA64C, 'M', u'ꙍ'), + (0xA64D, 'V'), + (0xA64E, 'M', u'ꙏ'), + (0xA64F, 'V'), + (0xA650, 'M', u'ꙑ'), + (0xA651, 'V'), + (0xA652, 'M', u'ꙓ'), + (0xA653, 'V'), + (0xA654, 'M', u'ꙕ'), + (0xA655, 'V'), + (0xA656, 'M', u'ꙗ'), + (0xA657, 'V'), + (0xA658, 'M', u'ꙙ'), + (0xA659, 'V'), + (0xA65A, 'M', u'ꙛ'), + (0xA65B, 'V'), + (0xA65C, 'M', u'ꙝ'), + (0xA65D, 'V'), + (0xA65E, 'M', u'ꙟ'), + (0xA65F, 'V'), + (0xA660, 'M', u'ꙡ'), + (0xA661, 'V'), + (0xA662, 'M', u'ꙣ'), + (0xA663, 'V'), + (0xA664, 'M', u'ꙥ'), + (0xA665, 'V'), + (0xA666, 'M', u'ꙧ'), + (0xA667, 'V'), + (0xA668, 'M', u'ꙩ'), + (0xA669, 'V'), + (0xA66A, 'M', u'ꙫ'), + (0xA66B, 'V'), + (0xA66C, 'M', u'ꙭ'), + (0xA66D, 'V'), + (0xA680, 'M', u'ꚁ'), + (0xA681, 'V'), + (0xA682, 'M', u'ꚃ'), + (0xA683, 'V'), + (0xA684, 'M', u'ꚅ'), + (0xA685, 'V'), + (0xA686, 'M', u'ꚇ'), + (0xA687, 'V'), + ] + +def _seg_36(): + return [ + (0xA688, 'M', u'ꚉ'), + (0xA689, 'V'), + (0xA68A, 'M', u'ꚋ'), + (0xA68B, 'V'), + (0xA68C, 'M', u'ꚍ'), + (0xA68D, 'V'), + (0xA68E, 'M', u'ꚏ'), + (0xA68F, 'V'), + (0xA690, 'M', u'ꚑ'), + (0xA691, 'V'), + (0xA692, 'M', u'ꚓ'), + (0xA693, 'V'), + (0xA694, 'M', u'ꚕ'), + (0xA695, 'V'), + (0xA696, 'M', u'ꚗ'), + (0xA697, 'V'), + (0xA698, 'M', u'ꚙ'), + (0xA699, 'V'), + (0xA69A, 'M', u'ꚛ'), + (0xA69B, 'V'), + (0xA69C, 'M', u'ъ'), + (0xA69D, 'M', u'ь'), + (0xA69E, 'V'), + (0xA6F8, 'X'), + (0xA700, 'V'), + (0xA722, 'M', u'ꜣ'), + (0xA723, 'V'), + (0xA724, 'M', u'ꜥ'), + (0xA725, 'V'), + (0xA726, 'M', u'ꜧ'), + (0xA727, 'V'), + (0xA728, 'M', u'ꜩ'), + (0xA729, 'V'), + (0xA72A, 'M', u'ꜫ'), + (0xA72B, 'V'), + (0xA72C, 'M', u'ꜭ'), + (0xA72D, 'V'), + (0xA72E, 'M', u'ꜯ'), + (0xA72F, 'V'), + (0xA732, 'M', u'ꜳ'), + (0xA733, 'V'), + (0xA734, 'M', u'ꜵ'), + (0xA735, 'V'), + (0xA736, 'M', u'ꜷ'), + (0xA737, 'V'), + (0xA738, 'M', u'ꜹ'), + (0xA739, 'V'), + (0xA73A, 'M', u'ꜻ'), + (0xA73B, 'V'), + (0xA73C, 'M', u'ꜽ'), + (0xA73D, 'V'), + (0xA73E, 'M', u'ꜿ'), + (0xA73F, 'V'), + (0xA740, 'M', u'ꝁ'), + (0xA741, 'V'), + (0xA742, 'M', u'ꝃ'), + (0xA743, 'V'), + (0xA744, 'M', u'ꝅ'), + (0xA745, 'V'), + (0xA746, 'M', u'ꝇ'), + (0xA747, 'V'), + (0xA748, 'M', u'ꝉ'), + (0xA749, 'V'), + (0xA74A, 'M', u'ꝋ'), + (0xA74B, 'V'), + (0xA74C, 'M', u'ꝍ'), + (0xA74D, 'V'), + (0xA74E, 'M', u'ꝏ'), + (0xA74F, 'V'), + (0xA750, 'M', u'ꝑ'), + (0xA751, 'V'), + (0xA752, 'M', u'ꝓ'), + (0xA753, 'V'), + (0xA754, 'M', u'ꝕ'), + (0xA755, 'V'), + (0xA756, 'M', u'ꝗ'), + (0xA757, 'V'), + (0xA758, 'M', u'ꝙ'), + (0xA759, 'V'), + (0xA75A, 'M', u'ꝛ'), + (0xA75B, 'V'), + (0xA75C, 'M', u'ꝝ'), + (0xA75D, 'V'), + (0xA75E, 'M', u'ꝟ'), + (0xA75F, 'V'), + (0xA760, 'M', u'ꝡ'), + (0xA761, 'V'), + (0xA762, 'M', u'ꝣ'), + (0xA763, 'V'), + (0xA764, 'M', u'ꝥ'), + (0xA765, 'V'), + (0xA766, 'M', u'ꝧ'), + (0xA767, 'V'), + (0xA768, 'M', u'ꝩ'), + (0xA769, 'V'), + (0xA76A, 'M', u'ꝫ'), + (0xA76B, 'V'), + (0xA76C, 'M', u'ꝭ'), + (0xA76D, 'V'), + (0xA76E, 'M', u'ꝯ'), + ] + +def _seg_37(): + return [ + (0xA76F, 'V'), + (0xA770, 'M', u'ꝯ'), + (0xA771, 'V'), + (0xA779, 'M', u'ꝺ'), + (0xA77A, 'V'), + (0xA77B, 'M', u'ꝼ'), + (0xA77C, 'V'), + (0xA77D, 'M', u'ᵹ'), + (0xA77E, 'M', u'ꝿ'), + (0xA77F, 'V'), + (0xA780, 'M', u'ꞁ'), + (0xA781, 'V'), + (0xA782, 'M', u'ꞃ'), + (0xA783, 'V'), + (0xA784, 'M', u'ꞅ'), + (0xA785, 'V'), + (0xA786, 'M', u'ꞇ'), + (0xA787, 'V'), + (0xA78B, 'M', u'ꞌ'), + (0xA78C, 'V'), + (0xA78D, 'M', u'ɥ'), + (0xA78E, 'V'), + (0xA790, 'M', u'ꞑ'), + (0xA791, 'V'), + (0xA792, 'M', u'ꞓ'), + (0xA793, 'V'), + (0xA796, 'M', u'ꞗ'), + (0xA797, 'V'), + (0xA798, 'M', u'ꞙ'), + (0xA799, 'V'), + (0xA79A, 'M', u'ꞛ'), + (0xA79B, 'V'), + (0xA79C, 'M', u'ꞝ'), + (0xA79D, 'V'), + (0xA79E, 'M', u'ꞟ'), + (0xA79F, 'V'), + (0xA7A0, 'M', u'ꞡ'), + (0xA7A1, 'V'), + (0xA7A2, 'M', u'ꞣ'), + (0xA7A3, 'V'), + (0xA7A4, 'M', u'ꞥ'), + (0xA7A5, 'V'), + (0xA7A6, 'M', u'ꞧ'), + (0xA7A7, 'V'), + (0xA7A8, 'M', u'ꞩ'), + (0xA7A9, 'V'), + (0xA7AA, 'M', u'ɦ'), + (0xA7AB, 'M', u'ɜ'), + (0xA7AC, 'M', u'ɡ'), + (0xA7AD, 'M', u'ɬ'), + (0xA7AE, 'M', u'ɪ'), + (0xA7AF, 'V'), + (0xA7B0, 'M', u'ʞ'), + (0xA7B1, 'M', u'ʇ'), + (0xA7B2, 'M', u'ʝ'), + (0xA7B3, 'M', u'ꭓ'), + (0xA7B4, 'M', u'ꞵ'), + (0xA7B5, 'V'), + (0xA7B6, 'M', u'ꞷ'), + (0xA7B7, 'V'), + (0xA7B8, 'M', u'ꞹ'), + (0xA7B9, 'V'), + (0xA7BA, 'M', u'ꞻ'), + (0xA7BB, 'V'), + (0xA7BC, 'M', u'ꞽ'), + (0xA7BD, 'V'), + (0xA7BE, 'M', u'ꞿ'), + (0xA7BF, 'V'), + (0xA7C0, 'X'), + (0xA7C2, 'M', u'ꟃ'), + (0xA7C3, 'V'), + (0xA7C4, 'M', u'ꞔ'), + (0xA7C5, 'M', u'ʂ'), + (0xA7C6, 'M', u'ᶎ'), + (0xA7C7, 'M', u'ꟈ'), + (0xA7C8, 'V'), + (0xA7C9, 'M', u'ꟊ'), + (0xA7CA, 'V'), + (0xA7CB, 'X'), + (0xA7F5, 'M', u'ꟶ'), + (0xA7F6, 'V'), + (0xA7F8, 'M', u'ħ'), + (0xA7F9, 'M', u'œ'), + (0xA7FA, 'V'), + (0xA82D, 'X'), + (0xA830, 'V'), + (0xA83A, 'X'), + (0xA840, 'V'), + (0xA878, 'X'), + (0xA880, 'V'), + (0xA8C6, 'X'), + (0xA8CE, 'V'), + (0xA8DA, 'X'), + (0xA8E0, 'V'), + (0xA954, 'X'), + (0xA95F, 'V'), + (0xA97D, 'X'), + (0xA980, 'V'), + (0xA9CE, 'X'), + (0xA9CF, 'V'), + ] + +def _seg_38(): + return [ + (0xA9DA, 'X'), + (0xA9DE, 'V'), + (0xA9FF, 'X'), + (0xAA00, 'V'), + (0xAA37, 'X'), + (0xAA40, 'V'), + (0xAA4E, 'X'), + (0xAA50, 'V'), + (0xAA5A, 'X'), + (0xAA5C, 'V'), + (0xAAC3, 'X'), + (0xAADB, 'V'), + (0xAAF7, 'X'), + (0xAB01, 'V'), + (0xAB07, 'X'), + (0xAB09, 'V'), + (0xAB0F, 'X'), + (0xAB11, 'V'), + (0xAB17, 'X'), + (0xAB20, 'V'), + (0xAB27, 'X'), + (0xAB28, 'V'), + (0xAB2F, 'X'), + (0xAB30, 'V'), + (0xAB5C, 'M', u'ꜧ'), + (0xAB5D, 'M', u'ꬷ'), + (0xAB5E, 'M', u'ɫ'), + (0xAB5F, 'M', u'ꭒ'), + (0xAB60, 'V'), + (0xAB69, 'M', u'ʍ'), + (0xAB6A, 'V'), + (0xAB6C, 'X'), + (0xAB70, 'M', u'Ꭰ'), + (0xAB71, 'M', u'Ꭱ'), + (0xAB72, 'M', u'Ꭲ'), + (0xAB73, 'M', u'Ꭳ'), + (0xAB74, 'M', u'Ꭴ'), + (0xAB75, 'M', u'Ꭵ'), + (0xAB76, 'M', u'Ꭶ'), + (0xAB77, 'M', u'Ꭷ'), + (0xAB78, 'M', u'Ꭸ'), + (0xAB79, 'M', u'Ꭹ'), + (0xAB7A, 'M', u'Ꭺ'), + (0xAB7B, 'M', u'Ꭻ'), + (0xAB7C, 'M', u'Ꭼ'), + (0xAB7D, 'M', u'Ꭽ'), + (0xAB7E, 'M', u'Ꭾ'), + (0xAB7F, 'M', u'Ꭿ'), + (0xAB80, 'M', u'Ꮀ'), + (0xAB81, 'M', u'Ꮁ'), + (0xAB82, 'M', u'Ꮂ'), + (0xAB83, 'M', u'Ꮃ'), + (0xAB84, 'M', u'Ꮄ'), + (0xAB85, 'M', u'Ꮅ'), + (0xAB86, 'M', u'Ꮆ'), + (0xAB87, 'M', u'Ꮇ'), + (0xAB88, 'M', u'Ꮈ'), + (0xAB89, 'M', u'Ꮉ'), + (0xAB8A, 'M', u'Ꮊ'), + (0xAB8B, 'M', u'Ꮋ'), + (0xAB8C, 'M', u'Ꮌ'), + (0xAB8D, 'M', u'Ꮍ'), + (0xAB8E, 'M', u'Ꮎ'), + (0xAB8F, 'M', u'Ꮏ'), + (0xAB90, 'M', u'Ꮐ'), + (0xAB91, 'M', u'Ꮑ'), + (0xAB92, 'M', u'Ꮒ'), + (0xAB93, 'M', u'Ꮓ'), + (0xAB94, 'M', u'Ꮔ'), + (0xAB95, 'M', u'Ꮕ'), + (0xAB96, 'M', u'Ꮖ'), + (0xAB97, 'M', u'Ꮗ'), + (0xAB98, 'M', u'Ꮘ'), + (0xAB99, 'M', u'Ꮙ'), + (0xAB9A, 'M', u'Ꮚ'), + (0xAB9B, 'M', u'Ꮛ'), + (0xAB9C, 'M', u'Ꮜ'), + (0xAB9D, 'M', u'Ꮝ'), + (0xAB9E, 'M', u'Ꮞ'), + (0xAB9F, 'M', u'Ꮟ'), + (0xABA0, 'M', u'Ꮠ'), + (0xABA1, 'M', u'Ꮡ'), + (0xABA2, 'M', u'Ꮢ'), + (0xABA3, 'M', u'Ꮣ'), + (0xABA4, 'M', u'Ꮤ'), + (0xABA5, 'M', u'Ꮥ'), + (0xABA6, 'M', u'Ꮦ'), + (0xABA7, 'M', u'Ꮧ'), + (0xABA8, 'M', u'Ꮨ'), + (0xABA9, 'M', u'Ꮩ'), + (0xABAA, 'M', u'Ꮪ'), + (0xABAB, 'M', u'Ꮫ'), + (0xABAC, 'M', u'Ꮬ'), + (0xABAD, 'M', u'Ꮭ'), + (0xABAE, 'M', u'Ꮮ'), + (0xABAF, 'M', u'Ꮯ'), + (0xABB0, 'M', u'Ꮰ'), + (0xABB1, 'M', u'Ꮱ'), + (0xABB2, 'M', u'Ꮲ'), + (0xABB3, 'M', u'Ꮳ'), + ] + +def _seg_39(): + return [ + (0xABB4, 'M', u'Ꮴ'), + (0xABB5, 'M', u'Ꮵ'), + (0xABB6, 'M', u'Ꮶ'), + (0xABB7, 'M', u'Ꮷ'), + (0xABB8, 'M', u'Ꮸ'), + (0xABB9, 'M', u'Ꮹ'), + (0xABBA, 'M', u'Ꮺ'), + (0xABBB, 'M', u'Ꮻ'), + (0xABBC, 'M', u'Ꮼ'), + (0xABBD, 'M', u'Ꮽ'), + (0xABBE, 'M', u'Ꮾ'), + (0xABBF, 'M', u'Ꮿ'), + (0xABC0, 'V'), + (0xABEE, 'X'), + (0xABF0, 'V'), + (0xABFA, 'X'), + (0xAC00, 'V'), + (0xD7A4, 'X'), + (0xD7B0, 'V'), + (0xD7C7, 'X'), + (0xD7CB, 'V'), + (0xD7FC, 'X'), + (0xF900, 'M', u'豈'), + (0xF901, 'M', u'更'), + (0xF902, 'M', u'車'), + (0xF903, 'M', u'賈'), + (0xF904, 'M', u'滑'), + (0xF905, 'M', u'串'), + (0xF906, 'M', u'句'), + (0xF907, 'M', u'龜'), + (0xF909, 'M', u'契'), + (0xF90A, 'M', u'金'), + (0xF90B, 'M', u'喇'), + (0xF90C, 'M', u'奈'), + (0xF90D, 'M', u'懶'), + (0xF90E, 'M', u'癩'), + (0xF90F, 'M', u'羅'), + (0xF910, 'M', u'蘿'), + (0xF911, 'M', u'螺'), + (0xF912, 'M', u'裸'), + (0xF913, 'M', u'邏'), + (0xF914, 'M', u'樂'), + (0xF915, 'M', u'洛'), + (0xF916, 'M', u'烙'), + (0xF917, 'M', u'珞'), + (0xF918, 'M', u'落'), + (0xF919, 'M', u'酪'), + (0xF91A, 'M', u'駱'), + (0xF91B, 'M', u'亂'), + (0xF91C, 'M', u'卵'), + (0xF91D, 'M', u'欄'), + (0xF91E, 'M', u'爛'), + (0xF91F, 'M', u'蘭'), + (0xF920, 'M', u'鸞'), + (0xF921, 'M', u'嵐'), + (0xF922, 'M', u'濫'), + (0xF923, 'M', u'藍'), + (0xF924, 'M', u'襤'), + (0xF925, 'M', u'拉'), + (0xF926, 'M', u'臘'), + (0xF927, 'M', u'蠟'), + (0xF928, 'M', u'廊'), + (0xF929, 'M', u'朗'), + (0xF92A, 'M', u'浪'), + (0xF92B, 'M', u'狼'), + (0xF92C, 'M', u'郎'), + (0xF92D, 'M', u'來'), + (0xF92E, 'M', u'冷'), + (0xF92F, 'M', u'勞'), + (0xF930, 'M', u'擄'), + (0xF931, 'M', u'櫓'), + (0xF932, 'M', u'爐'), + (0xF933, 'M', u'盧'), + (0xF934, 'M', u'老'), + (0xF935, 'M', u'蘆'), + (0xF936, 'M', u'虜'), + (0xF937, 'M', u'路'), + (0xF938, 'M', u'露'), + (0xF939, 'M', u'魯'), + (0xF93A, 'M', u'鷺'), + (0xF93B, 'M', u'碌'), + (0xF93C, 'M', u'祿'), + (0xF93D, 'M', u'綠'), + (0xF93E, 'M', u'菉'), + (0xF93F, 'M', u'錄'), + (0xF940, 'M', u'鹿'), + (0xF941, 'M', u'論'), + (0xF942, 'M', u'壟'), + (0xF943, 'M', u'弄'), + (0xF944, 'M', u'籠'), + (0xF945, 'M', u'聾'), + (0xF946, 'M', u'牢'), + (0xF947, 'M', u'磊'), + (0xF948, 'M', u'賂'), + (0xF949, 'M', u'雷'), + (0xF94A, 'M', u'壘'), + (0xF94B, 'M', u'屢'), + (0xF94C, 'M', u'樓'), + (0xF94D, 'M', u'淚'), + (0xF94E, 'M', u'漏'), + ] + +def _seg_40(): + return [ + (0xF94F, 'M', u'累'), + (0xF950, 'M', u'縷'), + (0xF951, 'M', u'陋'), + (0xF952, 'M', u'勒'), + (0xF953, 'M', u'肋'), + (0xF954, 'M', u'凜'), + (0xF955, 'M', u'凌'), + (0xF956, 'M', u'稜'), + (0xF957, 'M', u'綾'), + (0xF958, 'M', u'菱'), + (0xF959, 'M', u'陵'), + (0xF95A, 'M', u'讀'), + (0xF95B, 'M', u'拏'), + (0xF95C, 'M', u'樂'), + (0xF95D, 'M', u'諾'), + (0xF95E, 'M', u'丹'), + (0xF95F, 'M', u'寧'), + (0xF960, 'M', u'怒'), + (0xF961, 'M', u'率'), + (0xF962, 'M', u'異'), + (0xF963, 'M', u'北'), + (0xF964, 'M', u'磻'), + (0xF965, 'M', u'便'), + (0xF966, 'M', u'復'), + (0xF967, 'M', u'不'), + (0xF968, 'M', u'泌'), + (0xF969, 'M', u'數'), + (0xF96A, 'M', u'索'), + (0xF96B, 'M', u'參'), + (0xF96C, 'M', u'塞'), + (0xF96D, 'M', u'省'), + (0xF96E, 'M', u'葉'), + (0xF96F, 'M', u'說'), + (0xF970, 'M', u'殺'), + (0xF971, 'M', u'辰'), + (0xF972, 'M', u'沈'), + (0xF973, 'M', u'拾'), + (0xF974, 'M', u'若'), + (0xF975, 'M', u'掠'), + (0xF976, 'M', u'略'), + (0xF977, 'M', u'亮'), + (0xF978, 'M', u'兩'), + (0xF979, 'M', u'凉'), + (0xF97A, 'M', u'梁'), + (0xF97B, 'M', u'糧'), + (0xF97C, 'M', u'良'), + (0xF97D, 'M', u'諒'), + (0xF97E, 'M', u'量'), + (0xF97F, 'M', u'勵'), + (0xF980, 'M', u'呂'), + (0xF981, 'M', u'女'), + (0xF982, 'M', u'廬'), + (0xF983, 'M', u'旅'), + (0xF984, 'M', u'濾'), + (0xF985, 'M', u'礪'), + (0xF986, 'M', u'閭'), + (0xF987, 'M', u'驪'), + (0xF988, 'M', u'麗'), + (0xF989, 'M', u'黎'), + (0xF98A, 'M', u'力'), + (0xF98B, 'M', u'曆'), + (0xF98C, 'M', u'歷'), + (0xF98D, 'M', u'轢'), + (0xF98E, 'M', u'年'), + (0xF98F, 'M', u'憐'), + (0xF990, 'M', u'戀'), + (0xF991, 'M', u'撚'), + (0xF992, 'M', u'漣'), + (0xF993, 'M', u'煉'), + (0xF994, 'M', u'璉'), + (0xF995, 'M', u'秊'), + (0xF996, 'M', u'練'), + (0xF997, 'M', u'聯'), + (0xF998, 'M', u'輦'), + (0xF999, 'M', u'蓮'), + (0xF99A, 'M', u'連'), + (0xF99B, 'M', u'鍊'), + (0xF99C, 'M', u'列'), + (0xF99D, 'M', u'劣'), + (0xF99E, 'M', u'咽'), + (0xF99F, 'M', u'烈'), + (0xF9A0, 'M', u'裂'), + (0xF9A1, 'M', u'說'), + (0xF9A2, 'M', u'廉'), + (0xF9A3, 'M', u'念'), + (0xF9A4, 'M', u'捻'), + (0xF9A5, 'M', u'殮'), + (0xF9A6, 'M', u'簾'), + (0xF9A7, 'M', u'獵'), + (0xF9A8, 'M', u'令'), + (0xF9A9, 'M', u'囹'), + (0xF9AA, 'M', u'寧'), + (0xF9AB, 'M', u'嶺'), + (0xF9AC, 'M', u'怜'), + (0xF9AD, 'M', u'玲'), + (0xF9AE, 'M', u'瑩'), + (0xF9AF, 'M', u'羚'), + (0xF9B0, 'M', u'聆'), + (0xF9B1, 'M', u'鈴'), + (0xF9B2, 'M', u'零'), + ] + +def _seg_41(): + return [ + (0xF9B3, 'M', u'靈'), + (0xF9B4, 'M', u'領'), + (0xF9B5, 'M', u'例'), + (0xF9B6, 'M', u'禮'), + (0xF9B7, 'M', u'醴'), + (0xF9B8, 'M', u'隸'), + (0xF9B9, 'M', u'惡'), + (0xF9BA, 'M', u'了'), + (0xF9BB, 'M', u'僚'), + (0xF9BC, 'M', u'寮'), + (0xF9BD, 'M', u'尿'), + (0xF9BE, 'M', u'料'), + (0xF9BF, 'M', u'樂'), + (0xF9C0, 'M', u'燎'), + (0xF9C1, 'M', u'療'), + (0xF9C2, 'M', u'蓼'), + (0xF9C3, 'M', u'遼'), + (0xF9C4, 'M', u'龍'), + (0xF9C5, 'M', u'暈'), + (0xF9C6, 'M', u'阮'), + (0xF9C7, 'M', u'劉'), + (0xF9C8, 'M', u'杻'), + (0xF9C9, 'M', u'柳'), + (0xF9CA, 'M', u'流'), + (0xF9CB, 'M', u'溜'), + (0xF9CC, 'M', u'琉'), + (0xF9CD, 'M', u'留'), + (0xF9CE, 'M', u'硫'), + (0xF9CF, 'M', u'紐'), + (0xF9D0, 'M', u'類'), + (0xF9D1, 'M', u'六'), + (0xF9D2, 'M', u'戮'), + (0xF9D3, 'M', u'陸'), + (0xF9D4, 'M', u'倫'), + (0xF9D5, 'M', u'崙'), + (0xF9D6, 'M', u'淪'), + (0xF9D7, 'M', u'輪'), + (0xF9D8, 'M', u'律'), + (0xF9D9, 'M', u'慄'), + (0xF9DA, 'M', u'栗'), + (0xF9DB, 'M', u'率'), + (0xF9DC, 'M', u'隆'), + (0xF9DD, 'M', u'利'), + (0xF9DE, 'M', u'吏'), + (0xF9DF, 'M', u'履'), + (0xF9E0, 'M', u'易'), + (0xF9E1, 'M', u'李'), + (0xF9E2, 'M', u'梨'), + (0xF9E3, 'M', u'泥'), + (0xF9E4, 'M', u'理'), + (0xF9E5, 'M', u'痢'), + (0xF9E6, 'M', u'罹'), + (0xF9E7, 'M', u'裏'), + (0xF9E8, 'M', u'裡'), + (0xF9E9, 'M', u'里'), + (0xF9EA, 'M', u'離'), + (0xF9EB, 'M', u'匿'), + (0xF9EC, 'M', u'溺'), + (0xF9ED, 'M', u'吝'), + (0xF9EE, 'M', u'燐'), + (0xF9EF, 'M', u'璘'), + (0xF9F0, 'M', u'藺'), + (0xF9F1, 'M', u'隣'), + (0xF9F2, 'M', u'鱗'), + (0xF9F3, 'M', u'麟'), + (0xF9F4, 'M', u'林'), + (0xF9F5, 'M', u'淋'), + (0xF9F6, 'M', u'臨'), + (0xF9F7, 'M', u'立'), + (0xF9F8, 'M', u'笠'), + (0xF9F9, 'M', u'粒'), + (0xF9FA, 'M', u'狀'), + (0xF9FB, 'M', u'炙'), + (0xF9FC, 'M', u'識'), + (0xF9FD, 'M', u'什'), + (0xF9FE, 'M', u'茶'), + (0xF9FF, 'M', u'刺'), + (0xFA00, 'M', u'切'), + (0xFA01, 'M', u'度'), + (0xFA02, 'M', u'拓'), + (0xFA03, 'M', u'糖'), + (0xFA04, 'M', u'宅'), + (0xFA05, 'M', u'洞'), + (0xFA06, 'M', u'暴'), + (0xFA07, 'M', u'輻'), + (0xFA08, 'M', u'行'), + (0xFA09, 'M', u'降'), + (0xFA0A, 'M', u'見'), + (0xFA0B, 'M', u'廓'), + (0xFA0C, 'M', u'兀'), + (0xFA0D, 'M', u'嗀'), + (0xFA0E, 'V'), + (0xFA10, 'M', u'塚'), + (0xFA11, 'V'), + (0xFA12, 'M', u'晴'), + (0xFA13, 'V'), + (0xFA15, 'M', u'凞'), + (0xFA16, 'M', u'猪'), + (0xFA17, 'M', u'益'), + (0xFA18, 'M', u'礼'), + ] + +def _seg_42(): + return [ + (0xFA19, 'M', u'神'), + (0xFA1A, 'M', u'祥'), + (0xFA1B, 'M', u'福'), + (0xFA1C, 'M', u'靖'), + (0xFA1D, 'M', u'精'), + (0xFA1E, 'M', u'羽'), + (0xFA1F, 'V'), + (0xFA20, 'M', u'蘒'), + (0xFA21, 'V'), + (0xFA22, 'M', u'諸'), + (0xFA23, 'V'), + (0xFA25, 'M', u'逸'), + (0xFA26, 'M', u'都'), + (0xFA27, 'V'), + (0xFA2A, 'M', u'飯'), + (0xFA2B, 'M', u'飼'), + (0xFA2C, 'M', u'館'), + (0xFA2D, 'M', u'鶴'), + (0xFA2E, 'M', u'郞'), + (0xFA2F, 'M', u'隷'), + (0xFA30, 'M', u'侮'), + (0xFA31, 'M', u'僧'), + (0xFA32, 'M', u'免'), + (0xFA33, 'M', u'勉'), + (0xFA34, 'M', u'勤'), + (0xFA35, 'M', u'卑'), + (0xFA36, 'M', u'喝'), + (0xFA37, 'M', u'嘆'), + (0xFA38, 'M', u'器'), + (0xFA39, 'M', u'塀'), + (0xFA3A, 'M', u'墨'), + (0xFA3B, 'M', u'層'), + (0xFA3C, 'M', u'屮'), + (0xFA3D, 'M', u'悔'), + (0xFA3E, 'M', u'慨'), + (0xFA3F, 'M', u'憎'), + (0xFA40, 'M', u'懲'), + (0xFA41, 'M', u'敏'), + (0xFA42, 'M', u'既'), + (0xFA43, 'M', u'暑'), + (0xFA44, 'M', u'梅'), + (0xFA45, 'M', u'海'), + (0xFA46, 'M', u'渚'), + (0xFA47, 'M', u'漢'), + (0xFA48, 'M', u'煮'), + (0xFA49, 'M', u'爫'), + (0xFA4A, 'M', u'琢'), + (0xFA4B, 'M', u'碑'), + (0xFA4C, 'M', u'社'), + (0xFA4D, 'M', u'祉'), + (0xFA4E, 'M', u'祈'), + (0xFA4F, 'M', u'祐'), + (0xFA50, 'M', u'祖'), + (0xFA51, 'M', u'祝'), + (0xFA52, 'M', u'禍'), + (0xFA53, 'M', u'禎'), + (0xFA54, 'M', u'穀'), + (0xFA55, 'M', u'突'), + (0xFA56, 'M', u'節'), + (0xFA57, 'M', u'練'), + (0xFA58, 'M', u'縉'), + (0xFA59, 'M', u'繁'), + (0xFA5A, 'M', u'署'), + (0xFA5B, 'M', u'者'), + (0xFA5C, 'M', u'臭'), + (0xFA5D, 'M', u'艹'), + (0xFA5F, 'M', u'著'), + (0xFA60, 'M', u'褐'), + (0xFA61, 'M', u'視'), + (0xFA62, 'M', u'謁'), + (0xFA63, 'M', u'謹'), + (0xFA64, 'M', u'賓'), + (0xFA65, 'M', u'贈'), + (0xFA66, 'M', u'辶'), + (0xFA67, 'M', u'逸'), + (0xFA68, 'M', u'難'), + (0xFA69, 'M', u'響'), + (0xFA6A, 'M', u'頻'), + (0xFA6B, 'M', u'恵'), + (0xFA6C, 'M', u'𤋮'), + (0xFA6D, 'M', u'舘'), + (0xFA6E, 'X'), + (0xFA70, 'M', u'並'), + (0xFA71, 'M', u'况'), + (0xFA72, 'M', u'全'), + (0xFA73, 'M', u'侀'), + (0xFA74, 'M', u'充'), + (0xFA75, 'M', u'冀'), + (0xFA76, 'M', u'勇'), + (0xFA77, 'M', u'勺'), + (0xFA78, 'M', u'喝'), + (0xFA79, 'M', u'啕'), + (0xFA7A, 'M', u'喙'), + (0xFA7B, 'M', u'嗢'), + (0xFA7C, 'M', u'塚'), + (0xFA7D, 'M', u'墳'), + (0xFA7E, 'M', u'奄'), + (0xFA7F, 'M', u'奔'), + (0xFA80, 'M', u'婢'), + (0xFA81, 'M', u'嬨'), + ] + +def _seg_43(): + return [ + (0xFA82, 'M', u'廒'), + (0xFA83, 'M', u'廙'), + (0xFA84, 'M', u'彩'), + (0xFA85, 'M', u'徭'), + (0xFA86, 'M', u'惘'), + (0xFA87, 'M', u'慎'), + (0xFA88, 'M', u'愈'), + (0xFA89, 'M', u'憎'), + (0xFA8A, 'M', u'慠'), + (0xFA8B, 'M', u'懲'), + (0xFA8C, 'M', u'戴'), + (0xFA8D, 'M', u'揄'), + (0xFA8E, 'M', u'搜'), + (0xFA8F, 'M', u'摒'), + (0xFA90, 'M', u'敖'), + (0xFA91, 'M', u'晴'), + (0xFA92, 'M', u'朗'), + (0xFA93, 'M', u'望'), + (0xFA94, 'M', u'杖'), + (0xFA95, 'M', u'歹'), + (0xFA96, 'M', u'殺'), + (0xFA97, 'M', u'流'), + (0xFA98, 'M', u'滛'), + (0xFA99, 'M', u'滋'), + (0xFA9A, 'M', u'漢'), + (0xFA9B, 'M', u'瀞'), + (0xFA9C, 'M', u'煮'), + (0xFA9D, 'M', u'瞧'), + (0xFA9E, 'M', u'爵'), + (0xFA9F, 'M', u'犯'), + (0xFAA0, 'M', u'猪'), + (0xFAA1, 'M', u'瑱'), + (0xFAA2, 'M', u'甆'), + (0xFAA3, 'M', u'画'), + (0xFAA4, 'M', u'瘝'), + (0xFAA5, 'M', u'瘟'), + (0xFAA6, 'M', u'益'), + (0xFAA7, 'M', u'盛'), + (0xFAA8, 'M', u'直'), + (0xFAA9, 'M', u'睊'), + (0xFAAA, 'M', u'着'), + (0xFAAB, 'M', u'磌'), + (0xFAAC, 'M', u'窱'), + (0xFAAD, 'M', u'節'), + (0xFAAE, 'M', u'类'), + (0xFAAF, 'M', u'絛'), + (0xFAB0, 'M', u'練'), + (0xFAB1, 'M', u'缾'), + (0xFAB2, 'M', u'者'), + (0xFAB3, 'M', u'荒'), + (0xFAB4, 'M', u'華'), + (0xFAB5, 'M', u'蝹'), + (0xFAB6, 'M', u'襁'), + (0xFAB7, 'M', u'覆'), + (0xFAB8, 'M', u'視'), + (0xFAB9, 'M', u'調'), + (0xFABA, 'M', u'諸'), + (0xFABB, 'M', u'請'), + (0xFABC, 'M', u'謁'), + (0xFABD, 'M', u'諾'), + (0xFABE, 'M', u'諭'), + (0xFABF, 'M', u'謹'), + (0xFAC0, 'M', u'變'), + (0xFAC1, 'M', u'贈'), + (0xFAC2, 'M', u'輸'), + (0xFAC3, 'M', u'遲'), + (0xFAC4, 'M', u'醙'), + (0xFAC5, 'M', u'鉶'), + (0xFAC6, 'M', u'陼'), + (0xFAC7, 'M', u'難'), + (0xFAC8, 'M', u'靖'), + (0xFAC9, 'M', u'韛'), + (0xFACA, 'M', u'響'), + (0xFACB, 'M', u'頋'), + (0xFACC, 'M', u'頻'), + (0xFACD, 'M', u'鬒'), + (0xFACE, 'M', u'龜'), + (0xFACF, 'M', u'𢡊'), + (0xFAD0, 'M', u'𢡄'), + (0xFAD1, 'M', u'𣏕'), + (0xFAD2, 'M', u'㮝'), + (0xFAD3, 'M', u'䀘'), + (0xFAD4, 'M', u'䀹'), + (0xFAD5, 'M', u'𥉉'), + (0xFAD6, 'M', u'𥳐'), + (0xFAD7, 'M', u'𧻓'), + (0xFAD8, 'M', u'齃'), + (0xFAD9, 'M', u'龎'), + (0xFADA, 'X'), + (0xFB00, 'M', u'ff'), + (0xFB01, 'M', u'fi'), + (0xFB02, 'M', u'fl'), + (0xFB03, 'M', u'ffi'), + (0xFB04, 'M', u'ffl'), + (0xFB05, 'M', u'st'), + (0xFB07, 'X'), + (0xFB13, 'M', u'մն'), + (0xFB14, 'M', u'մե'), + (0xFB15, 'M', u'մի'), + (0xFB16, 'M', u'վն'), + ] + +def _seg_44(): + return [ + (0xFB17, 'M', u'մխ'), + (0xFB18, 'X'), + (0xFB1D, 'M', u'יִ'), + (0xFB1E, 'V'), + (0xFB1F, 'M', u'ײַ'), + (0xFB20, 'M', u'ע'), + (0xFB21, 'M', u'א'), + (0xFB22, 'M', u'ד'), + (0xFB23, 'M', u'ה'), + (0xFB24, 'M', u'כ'), + (0xFB25, 'M', u'ל'), + (0xFB26, 'M', u'ם'), + (0xFB27, 'M', u'ר'), + (0xFB28, 'M', u'ת'), + (0xFB29, '3', u'+'), + (0xFB2A, 'M', u'שׁ'), + (0xFB2B, 'M', u'שׂ'), + (0xFB2C, 'M', u'שּׁ'), + (0xFB2D, 'M', u'שּׂ'), + (0xFB2E, 'M', u'אַ'), + (0xFB2F, 'M', u'אָ'), + (0xFB30, 'M', u'אּ'), + (0xFB31, 'M', u'בּ'), + (0xFB32, 'M', u'גּ'), + (0xFB33, 'M', u'דּ'), + (0xFB34, 'M', u'הּ'), + (0xFB35, 'M', u'וּ'), + (0xFB36, 'M', u'זּ'), + (0xFB37, 'X'), + (0xFB38, 'M', u'טּ'), + (0xFB39, 'M', u'יּ'), + (0xFB3A, 'M', u'ךּ'), + (0xFB3B, 'M', u'כּ'), + (0xFB3C, 'M', u'לּ'), + (0xFB3D, 'X'), + (0xFB3E, 'M', u'מּ'), + (0xFB3F, 'X'), + (0xFB40, 'M', u'נּ'), + (0xFB41, 'M', u'סּ'), + (0xFB42, 'X'), + (0xFB43, 'M', u'ףּ'), + (0xFB44, 'M', u'פּ'), + (0xFB45, 'X'), + (0xFB46, 'M', u'צּ'), + (0xFB47, 'M', u'קּ'), + (0xFB48, 'M', u'רּ'), + (0xFB49, 'M', u'שּ'), + (0xFB4A, 'M', u'תּ'), + (0xFB4B, 'M', u'וֹ'), + (0xFB4C, 'M', u'בֿ'), + (0xFB4D, 'M', u'כֿ'), + (0xFB4E, 'M', u'פֿ'), + (0xFB4F, 'M', u'אל'), + (0xFB50, 'M', u'ٱ'), + (0xFB52, 'M', u'ٻ'), + (0xFB56, 'M', u'پ'), + (0xFB5A, 'M', u'ڀ'), + (0xFB5E, 'M', u'ٺ'), + (0xFB62, 'M', u'ٿ'), + (0xFB66, 'M', u'ٹ'), + (0xFB6A, 'M', u'ڤ'), + (0xFB6E, 'M', u'ڦ'), + (0xFB72, 'M', u'ڄ'), + (0xFB76, 'M', u'ڃ'), + (0xFB7A, 'M', u'چ'), + (0xFB7E, 'M', u'ڇ'), + (0xFB82, 'M', u'ڍ'), + (0xFB84, 'M', u'ڌ'), + (0xFB86, 'M', u'ڎ'), + (0xFB88, 'M', u'ڈ'), + (0xFB8A, 'M', u'ژ'), + (0xFB8C, 'M', u'ڑ'), + (0xFB8E, 'M', u'ک'), + (0xFB92, 'M', u'گ'), + (0xFB96, 'M', u'ڳ'), + (0xFB9A, 'M', u'ڱ'), + (0xFB9E, 'M', u'ں'), + (0xFBA0, 'M', u'ڻ'), + (0xFBA4, 'M', u'ۀ'), + (0xFBA6, 'M', u'ہ'), + (0xFBAA, 'M', u'ھ'), + (0xFBAE, 'M', u'ے'), + (0xFBB0, 'M', u'ۓ'), + (0xFBB2, 'V'), + (0xFBC2, 'X'), + (0xFBD3, 'M', u'ڭ'), + (0xFBD7, 'M', u'ۇ'), + (0xFBD9, 'M', u'ۆ'), + (0xFBDB, 'M', u'ۈ'), + (0xFBDD, 'M', u'ۇٴ'), + (0xFBDE, 'M', u'ۋ'), + (0xFBE0, 'M', u'ۅ'), + (0xFBE2, 'M', u'ۉ'), + (0xFBE4, 'M', u'ې'), + (0xFBE8, 'M', u'ى'), + (0xFBEA, 'M', u'ئا'), + (0xFBEC, 'M', u'ئە'), + (0xFBEE, 'M', u'ئو'), + (0xFBF0, 'M', u'ئۇ'), + (0xFBF2, 'M', u'ئۆ'), + ] + +def _seg_45(): + return [ + (0xFBF4, 'M', u'ئۈ'), + (0xFBF6, 'M', u'ئې'), + (0xFBF9, 'M', u'ئى'), + (0xFBFC, 'M', u'ی'), + (0xFC00, 'M', u'ئج'), + (0xFC01, 'M', u'ئح'), + (0xFC02, 'M', u'ئم'), + (0xFC03, 'M', u'ئى'), + (0xFC04, 'M', u'ئي'), + (0xFC05, 'M', u'بج'), + (0xFC06, 'M', u'بح'), + (0xFC07, 'M', u'بخ'), + (0xFC08, 'M', u'بم'), + (0xFC09, 'M', u'بى'), + (0xFC0A, 'M', u'بي'), + (0xFC0B, 'M', u'تج'), + (0xFC0C, 'M', u'تح'), + (0xFC0D, 'M', u'تخ'), + (0xFC0E, 'M', u'تم'), + (0xFC0F, 'M', u'تى'), + (0xFC10, 'M', u'تي'), + (0xFC11, 'M', u'ثج'), + (0xFC12, 'M', u'ثم'), + (0xFC13, 'M', u'ثى'), + (0xFC14, 'M', u'ثي'), + (0xFC15, 'M', u'جح'), + (0xFC16, 'M', u'جم'), + (0xFC17, 'M', u'حج'), + (0xFC18, 'M', u'حم'), + (0xFC19, 'M', u'خج'), + (0xFC1A, 'M', u'خح'), + (0xFC1B, 'M', u'خم'), + (0xFC1C, 'M', u'سج'), + (0xFC1D, 'M', u'سح'), + (0xFC1E, 'M', u'سخ'), + (0xFC1F, 'M', u'سم'), + (0xFC20, 'M', u'صح'), + (0xFC21, 'M', u'صم'), + (0xFC22, 'M', u'ضج'), + (0xFC23, 'M', u'ضح'), + (0xFC24, 'M', u'ضخ'), + (0xFC25, 'M', u'ضم'), + (0xFC26, 'M', u'طح'), + (0xFC27, 'M', u'طم'), + (0xFC28, 'M', u'ظم'), + (0xFC29, 'M', u'عج'), + (0xFC2A, 'M', u'عم'), + (0xFC2B, 'M', u'غج'), + (0xFC2C, 'M', u'غم'), + (0xFC2D, 'M', u'فج'), + (0xFC2E, 'M', u'فح'), + (0xFC2F, 'M', u'فخ'), + (0xFC30, 'M', u'فم'), + (0xFC31, 'M', u'فى'), + (0xFC32, 'M', u'في'), + (0xFC33, 'M', u'قح'), + (0xFC34, 'M', u'قم'), + (0xFC35, 'M', u'قى'), + (0xFC36, 'M', u'قي'), + (0xFC37, 'M', u'كا'), + (0xFC38, 'M', u'كج'), + (0xFC39, 'M', u'كح'), + (0xFC3A, 'M', u'كخ'), + (0xFC3B, 'M', u'كل'), + (0xFC3C, 'M', u'كم'), + (0xFC3D, 'M', u'كى'), + (0xFC3E, 'M', u'كي'), + (0xFC3F, 'M', u'لج'), + (0xFC40, 'M', u'لح'), + (0xFC41, 'M', u'لخ'), + (0xFC42, 'M', u'لم'), + (0xFC43, 'M', u'لى'), + (0xFC44, 'M', u'لي'), + (0xFC45, 'M', u'مج'), + (0xFC46, 'M', u'مح'), + (0xFC47, 'M', u'مخ'), + (0xFC48, 'M', u'مم'), + (0xFC49, 'M', u'مى'), + (0xFC4A, 'M', u'مي'), + (0xFC4B, 'M', u'نج'), + (0xFC4C, 'M', u'نح'), + (0xFC4D, 'M', u'نخ'), + (0xFC4E, 'M', u'نم'), + (0xFC4F, 'M', u'نى'), + (0xFC50, 'M', u'ني'), + (0xFC51, 'M', u'هج'), + (0xFC52, 'M', u'هم'), + (0xFC53, 'M', u'هى'), + (0xFC54, 'M', u'هي'), + (0xFC55, 'M', u'يج'), + (0xFC56, 'M', u'يح'), + (0xFC57, 'M', u'يخ'), + (0xFC58, 'M', u'يم'), + (0xFC59, 'M', u'يى'), + (0xFC5A, 'M', u'يي'), + (0xFC5B, 'M', u'ذٰ'), + (0xFC5C, 'M', u'رٰ'), + (0xFC5D, 'M', u'ىٰ'), + (0xFC5E, '3', u' ٌّ'), + (0xFC5F, '3', u' ٍّ'), + ] + +def _seg_46(): + return [ + (0xFC60, '3', u' َّ'), + (0xFC61, '3', u' ُّ'), + (0xFC62, '3', u' ِّ'), + (0xFC63, '3', u' ّٰ'), + (0xFC64, 'M', u'ئر'), + (0xFC65, 'M', u'ئز'), + (0xFC66, 'M', u'ئم'), + (0xFC67, 'M', u'ئن'), + (0xFC68, 'M', u'ئى'), + (0xFC69, 'M', u'ئي'), + (0xFC6A, 'M', u'بر'), + (0xFC6B, 'M', u'بز'), + (0xFC6C, 'M', u'بم'), + (0xFC6D, 'M', u'بن'), + (0xFC6E, 'M', u'بى'), + (0xFC6F, 'M', u'بي'), + (0xFC70, 'M', u'تر'), + (0xFC71, 'M', u'تز'), + (0xFC72, 'M', u'تم'), + (0xFC73, 'M', u'تن'), + (0xFC74, 'M', u'تى'), + (0xFC75, 'M', u'تي'), + (0xFC76, 'M', u'ثر'), + (0xFC77, 'M', u'ثز'), + (0xFC78, 'M', u'ثم'), + (0xFC79, 'M', u'ثن'), + (0xFC7A, 'M', u'ثى'), + (0xFC7B, 'M', u'ثي'), + (0xFC7C, 'M', u'فى'), + (0xFC7D, 'M', u'في'), + (0xFC7E, 'M', u'قى'), + (0xFC7F, 'M', u'قي'), + (0xFC80, 'M', u'كا'), + (0xFC81, 'M', u'كل'), + (0xFC82, 'M', u'كم'), + (0xFC83, 'M', u'كى'), + (0xFC84, 'M', u'كي'), + (0xFC85, 'M', u'لم'), + (0xFC86, 'M', u'لى'), + (0xFC87, 'M', u'لي'), + (0xFC88, 'M', u'ما'), + (0xFC89, 'M', u'مم'), + (0xFC8A, 'M', u'نر'), + (0xFC8B, 'M', u'نز'), + (0xFC8C, 'M', u'نم'), + (0xFC8D, 'M', u'نن'), + (0xFC8E, 'M', u'نى'), + (0xFC8F, 'M', u'ني'), + (0xFC90, 'M', u'ىٰ'), + (0xFC91, 'M', u'ير'), + (0xFC92, 'M', u'يز'), + (0xFC93, 'M', u'يم'), + (0xFC94, 'M', u'ين'), + (0xFC95, 'M', u'يى'), + (0xFC96, 'M', u'يي'), + (0xFC97, 'M', u'ئج'), + (0xFC98, 'M', u'ئح'), + (0xFC99, 'M', u'ئخ'), + (0xFC9A, 'M', u'ئم'), + (0xFC9B, 'M', u'ئه'), + (0xFC9C, 'M', u'بج'), + (0xFC9D, 'M', u'بح'), + (0xFC9E, 'M', u'بخ'), + (0xFC9F, 'M', u'بم'), + (0xFCA0, 'M', u'به'), + (0xFCA1, 'M', u'تج'), + (0xFCA2, 'M', u'تح'), + (0xFCA3, 'M', u'تخ'), + (0xFCA4, 'M', u'تم'), + (0xFCA5, 'M', u'ته'), + (0xFCA6, 'M', u'ثم'), + (0xFCA7, 'M', u'جح'), + (0xFCA8, 'M', u'جم'), + (0xFCA9, 'M', u'حج'), + (0xFCAA, 'M', u'حم'), + (0xFCAB, 'M', u'خج'), + (0xFCAC, 'M', u'خم'), + (0xFCAD, 'M', u'سج'), + (0xFCAE, 'M', u'سح'), + (0xFCAF, 'M', u'سخ'), + (0xFCB0, 'M', u'سم'), + (0xFCB1, 'M', u'صح'), + (0xFCB2, 'M', u'صخ'), + (0xFCB3, 'M', u'صم'), + (0xFCB4, 'M', u'ضج'), + (0xFCB5, 'M', u'ضح'), + (0xFCB6, 'M', u'ضخ'), + (0xFCB7, 'M', u'ضم'), + (0xFCB8, 'M', u'طح'), + (0xFCB9, 'M', u'ظم'), + (0xFCBA, 'M', u'عج'), + (0xFCBB, 'M', u'عم'), + (0xFCBC, 'M', u'غج'), + (0xFCBD, 'M', u'غم'), + (0xFCBE, 'M', u'فج'), + (0xFCBF, 'M', u'فح'), + (0xFCC0, 'M', u'فخ'), + (0xFCC1, 'M', u'فم'), + (0xFCC2, 'M', u'قح'), + (0xFCC3, 'M', u'قم'), + ] + +def _seg_47(): + return [ + (0xFCC4, 'M', u'كج'), + (0xFCC5, 'M', u'كح'), + (0xFCC6, 'M', u'كخ'), + (0xFCC7, 'M', u'كل'), + (0xFCC8, 'M', u'كم'), + (0xFCC9, 'M', u'لج'), + (0xFCCA, 'M', u'لح'), + (0xFCCB, 'M', u'لخ'), + (0xFCCC, 'M', u'لم'), + (0xFCCD, 'M', u'له'), + (0xFCCE, 'M', u'مج'), + (0xFCCF, 'M', u'مح'), + (0xFCD0, 'M', u'مخ'), + (0xFCD1, 'M', u'مم'), + (0xFCD2, 'M', u'نج'), + (0xFCD3, 'M', u'نح'), + (0xFCD4, 'M', u'نخ'), + (0xFCD5, 'M', u'نم'), + (0xFCD6, 'M', u'نه'), + (0xFCD7, 'M', u'هج'), + (0xFCD8, 'M', u'هم'), + (0xFCD9, 'M', u'هٰ'), + (0xFCDA, 'M', u'يج'), + (0xFCDB, 'M', u'يح'), + (0xFCDC, 'M', u'يخ'), + (0xFCDD, 'M', u'يم'), + (0xFCDE, 'M', u'يه'), + (0xFCDF, 'M', u'ئم'), + (0xFCE0, 'M', u'ئه'), + (0xFCE1, 'M', u'بم'), + (0xFCE2, 'M', u'به'), + (0xFCE3, 'M', u'تم'), + (0xFCE4, 'M', u'ته'), + (0xFCE5, 'M', u'ثم'), + (0xFCE6, 'M', u'ثه'), + (0xFCE7, 'M', u'سم'), + (0xFCE8, 'M', u'سه'), + (0xFCE9, 'M', u'شم'), + (0xFCEA, 'M', u'شه'), + (0xFCEB, 'M', u'كل'), + (0xFCEC, 'M', u'كم'), + (0xFCED, 'M', u'لم'), + (0xFCEE, 'M', u'نم'), + (0xFCEF, 'M', u'نه'), + (0xFCF0, 'M', u'يم'), + (0xFCF1, 'M', u'يه'), + (0xFCF2, 'M', u'ـَّ'), + (0xFCF3, 'M', u'ـُّ'), + (0xFCF4, 'M', u'ـِّ'), + (0xFCF5, 'M', u'طى'), + (0xFCF6, 'M', u'طي'), + (0xFCF7, 'M', u'عى'), + (0xFCF8, 'M', u'عي'), + (0xFCF9, 'M', u'غى'), + (0xFCFA, 'M', u'غي'), + (0xFCFB, 'M', u'سى'), + (0xFCFC, 'M', u'سي'), + (0xFCFD, 'M', u'شى'), + (0xFCFE, 'M', u'شي'), + (0xFCFF, 'M', u'حى'), + (0xFD00, 'M', u'حي'), + (0xFD01, 'M', u'جى'), + (0xFD02, 'M', u'جي'), + (0xFD03, 'M', u'خى'), + (0xFD04, 'M', u'خي'), + (0xFD05, 'M', u'صى'), + (0xFD06, 'M', u'صي'), + (0xFD07, 'M', u'ضى'), + (0xFD08, 'M', u'ضي'), + (0xFD09, 'M', u'شج'), + (0xFD0A, 'M', u'شح'), + (0xFD0B, 'M', u'شخ'), + (0xFD0C, 'M', u'شم'), + (0xFD0D, 'M', u'شر'), + (0xFD0E, 'M', u'سر'), + (0xFD0F, 'M', u'صر'), + (0xFD10, 'M', u'ضر'), + (0xFD11, 'M', u'طى'), + (0xFD12, 'M', u'طي'), + (0xFD13, 'M', u'عى'), + (0xFD14, 'M', u'عي'), + (0xFD15, 'M', u'غى'), + (0xFD16, 'M', u'غي'), + (0xFD17, 'M', u'سى'), + (0xFD18, 'M', u'سي'), + (0xFD19, 'M', u'شى'), + (0xFD1A, 'M', u'شي'), + (0xFD1B, 'M', u'حى'), + (0xFD1C, 'M', u'حي'), + (0xFD1D, 'M', u'جى'), + (0xFD1E, 'M', u'جي'), + (0xFD1F, 'M', u'خى'), + (0xFD20, 'M', u'خي'), + (0xFD21, 'M', u'صى'), + (0xFD22, 'M', u'صي'), + (0xFD23, 'M', u'ضى'), + (0xFD24, 'M', u'ضي'), + (0xFD25, 'M', u'شج'), + (0xFD26, 'M', u'شح'), + (0xFD27, 'M', u'شخ'), + ] + +def _seg_48(): + return [ + (0xFD28, 'M', u'شم'), + (0xFD29, 'M', u'شر'), + (0xFD2A, 'M', u'سر'), + (0xFD2B, 'M', u'صر'), + (0xFD2C, 'M', u'ضر'), + (0xFD2D, 'M', u'شج'), + (0xFD2E, 'M', u'شح'), + (0xFD2F, 'M', u'شخ'), + (0xFD30, 'M', u'شم'), + (0xFD31, 'M', u'سه'), + (0xFD32, 'M', u'شه'), + (0xFD33, 'M', u'طم'), + (0xFD34, 'M', u'سج'), + (0xFD35, 'M', u'سح'), + (0xFD36, 'M', u'سخ'), + (0xFD37, 'M', u'شج'), + (0xFD38, 'M', u'شح'), + (0xFD39, 'M', u'شخ'), + (0xFD3A, 'M', u'طم'), + (0xFD3B, 'M', u'ظم'), + (0xFD3C, 'M', u'اً'), + (0xFD3E, 'V'), + (0xFD40, 'X'), + (0xFD50, 'M', u'تجم'), + (0xFD51, 'M', u'تحج'), + (0xFD53, 'M', u'تحم'), + (0xFD54, 'M', u'تخم'), + (0xFD55, 'M', u'تمج'), + (0xFD56, 'M', u'تمح'), + (0xFD57, 'M', u'تمخ'), + (0xFD58, 'M', u'جمح'), + (0xFD5A, 'M', u'حمي'), + (0xFD5B, 'M', u'حمى'), + (0xFD5C, 'M', u'سحج'), + (0xFD5D, 'M', u'سجح'), + (0xFD5E, 'M', u'سجى'), + (0xFD5F, 'M', u'سمح'), + (0xFD61, 'M', u'سمج'), + (0xFD62, 'M', u'سمم'), + (0xFD64, 'M', u'صحح'), + (0xFD66, 'M', u'صمم'), + (0xFD67, 'M', u'شحم'), + (0xFD69, 'M', u'شجي'), + (0xFD6A, 'M', u'شمخ'), + (0xFD6C, 'M', u'شمم'), + (0xFD6E, 'M', u'ضحى'), + (0xFD6F, 'M', u'ضخم'), + (0xFD71, 'M', u'طمح'), + (0xFD73, 'M', u'طمم'), + (0xFD74, 'M', u'طمي'), + (0xFD75, 'M', u'عجم'), + (0xFD76, 'M', u'عمم'), + (0xFD78, 'M', u'عمى'), + (0xFD79, 'M', u'غمم'), + (0xFD7A, 'M', u'غمي'), + (0xFD7B, 'M', u'غمى'), + (0xFD7C, 'M', u'فخم'), + (0xFD7E, 'M', u'قمح'), + (0xFD7F, 'M', u'قمم'), + (0xFD80, 'M', u'لحم'), + (0xFD81, 'M', u'لحي'), + (0xFD82, 'M', u'لحى'), + (0xFD83, 'M', u'لجج'), + (0xFD85, 'M', u'لخم'), + (0xFD87, 'M', u'لمح'), + (0xFD89, 'M', u'محج'), + (0xFD8A, 'M', u'محم'), + (0xFD8B, 'M', u'محي'), + (0xFD8C, 'M', u'مجح'), + (0xFD8D, 'M', u'مجم'), + (0xFD8E, 'M', u'مخج'), + (0xFD8F, 'M', u'مخم'), + (0xFD90, 'X'), + (0xFD92, 'M', u'مجخ'), + (0xFD93, 'M', u'همج'), + (0xFD94, 'M', u'همم'), + (0xFD95, 'M', u'نحم'), + (0xFD96, 'M', u'نحى'), + (0xFD97, 'M', u'نجم'), + (0xFD99, 'M', u'نجى'), + (0xFD9A, 'M', u'نمي'), + (0xFD9B, 'M', u'نمى'), + (0xFD9C, 'M', u'يمم'), + (0xFD9E, 'M', u'بخي'), + (0xFD9F, 'M', u'تجي'), + (0xFDA0, 'M', u'تجى'), + (0xFDA1, 'M', u'تخي'), + (0xFDA2, 'M', u'تخى'), + (0xFDA3, 'M', u'تمي'), + (0xFDA4, 'M', u'تمى'), + (0xFDA5, 'M', u'جمي'), + (0xFDA6, 'M', u'جحى'), + (0xFDA7, 'M', u'جمى'), + (0xFDA8, 'M', u'سخى'), + (0xFDA9, 'M', u'صحي'), + (0xFDAA, 'M', u'شحي'), + (0xFDAB, 'M', u'ضحي'), + (0xFDAC, 'M', u'لجي'), + (0xFDAD, 'M', u'لمي'), + (0xFDAE, 'M', u'يحي'), + ] + +def _seg_49(): + return [ + (0xFDAF, 'M', u'يجي'), + (0xFDB0, 'M', u'يمي'), + (0xFDB1, 'M', u'ممي'), + (0xFDB2, 'M', u'قمي'), + (0xFDB3, 'M', u'نحي'), + (0xFDB4, 'M', u'قمح'), + (0xFDB5, 'M', u'لحم'), + (0xFDB6, 'M', u'عمي'), + (0xFDB7, 'M', u'كمي'), + (0xFDB8, 'M', u'نجح'), + (0xFDB9, 'M', u'مخي'), + (0xFDBA, 'M', u'لجم'), + (0xFDBB, 'M', u'كمم'), + (0xFDBC, 'M', u'لجم'), + (0xFDBD, 'M', u'نجح'), + (0xFDBE, 'M', u'جحي'), + (0xFDBF, 'M', u'حجي'), + (0xFDC0, 'M', u'مجي'), + (0xFDC1, 'M', u'فمي'), + (0xFDC2, 'M', u'بحي'), + (0xFDC3, 'M', u'كمم'), + (0xFDC4, 'M', u'عجم'), + (0xFDC5, 'M', u'صمم'), + (0xFDC6, 'M', u'سخي'), + (0xFDC7, 'M', u'نجي'), + (0xFDC8, 'X'), + (0xFDF0, 'M', u'صلے'), + (0xFDF1, 'M', u'قلے'), + (0xFDF2, 'M', u'الله'), + (0xFDF3, 'M', u'اكبر'), + (0xFDF4, 'M', u'محمد'), + (0xFDF5, 'M', u'صلعم'), + (0xFDF6, 'M', u'رسول'), + (0xFDF7, 'M', u'عليه'), + (0xFDF8, 'M', u'وسلم'), + (0xFDF9, 'M', u'صلى'), + (0xFDFA, '3', u'صلى الله عليه وسلم'), + (0xFDFB, '3', u'جل جلاله'), + (0xFDFC, 'M', u'ریال'), + (0xFDFD, 'V'), + (0xFDFE, 'X'), + (0xFE00, 'I'), + (0xFE10, '3', u','), + (0xFE11, 'M', u'、'), + (0xFE12, 'X'), + (0xFE13, '3', u':'), + (0xFE14, '3', u';'), + (0xFE15, '3', u'!'), + (0xFE16, '3', u'?'), + (0xFE17, 'M', u'〖'), + (0xFE18, 'M', u'〗'), + (0xFE19, 'X'), + (0xFE20, 'V'), + (0xFE30, 'X'), + (0xFE31, 'M', u'—'), + (0xFE32, 'M', u'–'), + (0xFE33, '3', u'_'), + (0xFE35, '3', u'('), + (0xFE36, '3', u')'), + (0xFE37, '3', u'{'), + (0xFE38, '3', u'}'), + (0xFE39, 'M', u'〔'), + (0xFE3A, 'M', u'〕'), + (0xFE3B, 'M', u'【'), + (0xFE3C, 'M', u'】'), + (0xFE3D, 'M', u'《'), + (0xFE3E, 'M', u'》'), + (0xFE3F, 'M', u'〈'), + (0xFE40, 'M', u'〉'), + (0xFE41, 'M', u'「'), + (0xFE42, 'M', u'」'), + (0xFE43, 'M', u'『'), + (0xFE44, 'M', u'』'), + (0xFE45, 'V'), + (0xFE47, '3', u'['), + (0xFE48, '3', u']'), + (0xFE49, '3', u' ̅'), + (0xFE4D, '3', u'_'), + (0xFE50, '3', u','), + (0xFE51, 'M', u'、'), + (0xFE52, 'X'), + (0xFE54, '3', u';'), + (0xFE55, '3', u':'), + (0xFE56, '3', u'?'), + (0xFE57, '3', u'!'), + (0xFE58, 'M', u'—'), + (0xFE59, '3', u'('), + (0xFE5A, '3', u')'), + (0xFE5B, '3', u'{'), + (0xFE5C, '3', u'}'), + (0xFE5D, 'M', u'〔'), + (0xFE5E, 'M', u'〕'), + (0xFE5F, '3', u'#'), + (0xFE60, '3', u'&'), + (0xFE61, '3', u'*'), + (0xFE62, '3', u'+'), + (0xFE63, 'M', u'-'), + (0xFE64, '3', u'<'), + (0xFE65, '3', u'>'), + (0xFE66, '3', u'='), + ] + +def _seg_50(): + return [ + (0xFE67, 'X'), + (0xFE68, '3', u'\\'), + (0xFE69, '3', u'$'), + (0xFE6A, '3', u'%'), + (0xFE6B, '3', u'@'), + (0xFE6C, 'X'), + (0xFE70, '3', u' ً'), + (0xFE71, 'M', u'ـً'), + (0xFE72, '3', u' ٌ'), + (0xFE73, 'V'), + (0xFE74, '3', u' ٍ'), + (0xFE75, 'X'), + (0xFE76, '3', u' َ'), + (0xFE77, 'M', u'ـَ'), + (0xFE78, '3', u' ُ'), + (0xFE79, 'M', u'ـُ'), + (0xFE7A, '3', u' ِ'), + (0xFE7B, 'M', u'ـِ'), + (0xFE7C, '3', u' ّ'), + (0xFE7D, 'M', u'ـّ'), + (0xFE7E, '3', u' ْ'), + (0xFE7F, 'M', u'ـْ'), + (0xFE80, 'M', u'ء'), + (0xFE81, 'M', u'آ'), + (0xFE83, 'M', u'أ'), + (0xFE85, 'M', u'ؤ'), + (0xFE87, 'M', u'إ'), + (0xFE89, 'M', u'ئ'), + (0xFE8D, 'M', u'ا'), + (0xFE8F, 'M', u'ب'), + (0xFE93, 'M', u'ة'), + (0xFE95, 'M', u'ت'), + (0xFE99, 'M', u'ث'), + (0xFE9D, 'M', u'ج'), + (0xFEA1, 'M', u'ح'), + (0xFEA5, 'M', u'خ'), + (0xFEA9, 'M', u'د'), + (0xFEAB, 'M', u'ذ'), + (0xFEAD, 'M', u'ر'), + (0xFEAF, 'M', u'ز'), + (0xFEB1, 'M', u'س'), + (0xFEB5, 'M', u'ش'), + (0xFEB9, 'M', u'ص'), + (0xFEBD, 'M', u'ض'), + (0xFEC1, 'M', u'ط'), + (0xFEC5, 'M', u'ظ'), + (0xFEC9, 'M', u'ع'), + (0xFECD, 'M', u'غ'), + (0xFED1, 'M', u'ف'), + (0xFED5, 'M', u'ق'), + (0xFED9, 'M', u'ك'), + (0xFEDD, 'M', u'ل'), + (0xFEE1, 'M', u'م'), + (0xFEE5, 'M', u'ن'), + (0xFEE9, 'M', u'ه'), + (0xFEED, 'M', u'و'), + (0xFEEF, 'M', u'ى'), + (0xFEF1, 'M', u'ي'), + (0xFEF5, 'M', u'لآ'), + (0xFEF7, 'M', u'لأ'), + (0xFEF9, 'M', u'لإ'), + (0xFEFB, 'M', u'لا'), + (0xFEFD, 'X'), + (0xFEFF, 'I'), + (0xFF00, 'X'), + (0xFF01, '3', u'!'), + (0xFF02, '3', u'"'), + (0xFF03, '3', u'#'), + (0xFF04, '3', u'$'), + (0xFF05, '3', u'%'), + (0xFF06, '3', u'&'), + (0xFF07, '3', u'\''), + (0xFF08, '3', u'('), + (0xFF09, '3', u')'), + (0xFF0A, '3', u'*'), + (0xFF0B, '3', u'+'), + (0xFF0C, '3', u','), + (0xFF0D, 'M', u'-'), + (0xFF0E, 'M', u'.'), + (0xFF0F, '3', u'/'), + (0xFF10, 'M', u'0'), + (0xFF11, 'M', u'1'), + (0xFF12, 'M', u'2'), + (0xFF13, 'M', u'3'), + (0xFF14, 'M', u'4'), + (0xFF15, 'M', u'5'), + (0xFF16, 'M', u'6'), + (0xFF17, 'M', u'7'), + (0xFF18, 'M', u'8'), + (0xFF19, 'M', u'9'), + (0xFF1A, '3', u':'), + (0xFF1B, '3', u';'), + (0xFF1C, '3', u'<'), + (0xFF1D, '3', u'='), + (0xFF1E, '3', u'>'), + (0xFF1F, '3', u'?'), + (0xFF20, '3', u'@'), + (0xFF21, 'M', u'a'), + (0xFF22, 'M', u'b'), + (0xFF23, 'M', u'c'), + ] + +def _seg_51(): + return [ + (0xFF24, 'M', u'd'), + (0xFF25, 'M', u'e'), + (0xFF26, 'M', u'f'), + (0xFF27, 'M', u'g'), + (0xFF28, 'M', u'h'), + (0xFF29, 'M', u'i'), + (0xFF2A, 'M', u'j'), + (0xFF2B, 'M', u'k'), + (0xFF2C, 'M', u'l'), + (0xFF2D, 'M', u'm'), + (0xFF2E, 'M', u'n'), + (0xFF2F, 'M', u'o'), + (0xFF30, 'M', u'p'), + (0xFF31, 'M', u'q'), + (0xFF32, 'M', u'r'), + (0xFF33, 'M', u's'), + (0xFF34, 'M', u't'), + (0xFF35, 'M', u'u'), + (0xFF36, 'M', u'v'), + (0xFF37, 'M', u'w'), + (0xFF38, 'M', u'x'), + (0xFF39, 'M', u'y'), + (0xFF3A, 'M', u'z'), + (0xFF3B, '3', u'['), + (0xFF3C, '3', u'\\'), + (0xFF3D, '3', u']'), + (0xFF3E, '3', u'^'), + (0xFF3F, '3', u'_'), + (0xFF40, '3', u'`'), + (0xFF41, 'M', u'a'), + (0xFF42, 'M', u'b'), + (0xFF43, 'M', u'c'), + (0xFF44, 'M', u'd'), + (0xFF45, 'M', u'e'), + (0xFF46, 'M', u'f'), + (0xFF47, 'M', u'g'), + (0xFF48, 'M', u'h'), + (0xFF49, 'M', u'i'), + (0xFF4A, 'M', u'j'), + (0xFF4B, 'M', u'k'), + (0xFF4C, 'M', u'l'), + (0xFF4D, 'M', u'm'), + (0xFF4E, 'M', u'n'), + (0xFF4F, 'M', u'o'), + (0xFF50, 'M', u'p'), + (0xFF51, 'M', u'q'), + (0xFF52, 'M', u'r'), + (0xFF53, 'M', u's'), + (0xFF54, 'M', u't'), + (0xFF55, 'M', u'u'), + (0xFF56, 'M', u'v'), + (0xFF57, 'M', u'w'), + (0xFF58, 'M', u'x'), + (0xFF59, 'M', u'y'), + (0xFF5A, 'M', u'z'), + (0xFF5B, '3', u'{'), + (0xFF5C, '3', u'|'), + (0xFF5D, '3', u'}'), + (0xFF5E, '3', u'~'), + (0xFF5F, 'M', u'⦅'), + (0xFF60, 'M', u'⦆'), + (0xFF61, 'M', u'.'), + (0xFF62, 'M', u'「'), + (0xFF63, 'M', u'」'), + (0xFF64, 'M', u'、'), + (0xFF65, 'M', u'・'), + (0xFF66, 'M', u'ヲ'), + (0xFF67, 'M', u'ァ'), + (0xFF68, 'M', u'ィ'), + (0xFF69, 'M', u'ゥ'), + (0xFF6A, 'M', u'ェ'), + (0xFF6B, 'M', u'ォ'), + (0xFF6C, 'M', u'ャ'), + (0xFF6D, 'M', u'ュ'), + (0xFF6E, 'M', u'ョ'), + (0xFF6F, 'M', u'ッ'), + (0xFF70, 'M', u'ー'), + (0xFF71, 'M', u'ア'), + (0xFF72, 'M', u'イ'), + (0xFF73, 'M', u'ウ'), + (0xFF74, 'M', u'エ'), + (0xFF75, 'M', u'オ'), + (0xFF76, 'M', u'カ'), + (0xFF77, 'M', u'キ'), + (0xFF78, 'M', u'ク'), + (0xFF79, 'M', u'ケ'), + (0xFF7A, 'M', u'コ'), + (0xFF7B, 'M', u'サ'), + (0xFF7C, 'M', u'シ'), + (0xFF7D, 'M', u'ス'), + (0xFF7E, 'M', u'セ'), + (0xFF7F, 'M', u'ソ'), + (0xFF80, 'M', u'タ'), + (0xFF81, 'M', u'チ'), + (0xFF82, 'M', u'ツ'), + (0xFF83, 'M', u'テ'), + (0xFF84, 'M', u'ト'), + (0xFF85, 'M', u'ナ'), + (0xFF86, 'M', u'ニ'), + (0xFF87, 'M', u'ヌ'), + ] + +def _seg_52(): + return [ + (0xFF88, 'M', u'ネ'), + (0xFF89, 'M', u'ノ'), + (0xFF8A, 'M', u'ハ'), + (0xFF8B, 'M', u'ヒ'), + (0xFF8C, 'M', u'フ'), + (0xFF8D, 'M', u'ヘ'), + (0xFF8E, 'M', u'ホ'), + (0xFF8F, 'M', u'マ'), + (0xFF90, 'M', u'ミ'), + (0xFF91, 'M', u'ム'), + (0xFF92, 'M', u'メ'), + (0xFF93, 'M', u'モ'), + (0xFF94, 'M', u'ヤ'), + (0xFF95, 'M', u'ユ'), + (0xFF96, 'M', u'ヨ'), + (0xFF97, 'M', u'ラ'), + (0xFF98, 'M', u'リ'), + (0xFF99, 'M', u'ル'), + (0xFF9A, 'M', u'レ'), + (0xFF9B, 'M', u'ロ'), + (0xFF9C, 'M', u'ワ'), + (0xFF9D, 'M', u'ン'), + (0xFF9E, 'M', u'゙'), + (0xFF9F, 'M', u'゚'), + (0xFFA0, 'X'), + (0xFFA1, 'M', u'ᄀ'), + (0xFFA2, 'M', u'ᄁ'), + (0xFFA3, 'M', u'ᆪ'), + (0xFFA4, 'M', u'ᄂ'), + (0xFFA5, 'M', u'ᆬ'), + (0xFFA6, 'M', u'ᆭ'), + (0xFFA7, 'M', u'ᄃ'), + (0xFFA8, 'M', u'ᄄ'), + (0xFFA9, 'M', u'ᄅ'), + (0xFFAA, 'M', u'ᆰ'), + (0xFFAB, 'M', u'ᆱ'), + (0xFFAC, 'M', u'ᆲ'), + (0xFFAD, 'M', u'ᆳ'), + (0xFFAE, 'M', u'ᆴ'), + (0xFFAF, 'M', u'ᆵ'), + (0xFFB0, 'M', u'ᄚ'), + (0xFFB1, 'M', u'ᄆ'), + (0xFFB2, 'M', u'ᄇ'), + (0xFFB3, 'M', u'ᄈ'), + (0xFFB4, 'M', u'ᄡ'), + (0xFFB5, 'M', u'ᄉ'), + (0xFFB6, 'M', u'ᄊ'), + (0xFFB7, 'M', u'ᄋ'), + (0xFFB8, 'M', u'ᄌ'), + (0xFFB9, 'M', u'ᄍ'), + (0xFFBA, 'M', u'ᄎ'), + (0xFFBB, 'M', u'ᄏ'), + (0xFFBC, 'M', u'ᄐ'), + (0xFFBD, 'M', u'ᄑ'), + (0xFFBE, 'M', u'ᄒ'), + (0xFFBF, 'X'), + (0xFFC2, 'M', u'ᅡ'), + (0xFFC3, 'M', u'ᅢ'), + (0xFFC4, 'M', u'ᅣ'), + (0xFFC5, 'M', u'ᅤ'), + (0xFFC6, 'M', u'ᅥ'), + (0xFFC7, 'M', u'ᅦ'), + (0xFFC8, 'X'), + (0xFFCA, 'M', u'ᅧ'), + (0xFFCB, 'M', u'ᅨ'), + (0xFFCC, 'M', u'ᅩ'), + (0xFFCD, 'M', u'ᅪ'), + (0xFFCE, 'M', u'ᅫ'), + (0xFFCF, 'M', u'ᅬ'), + (0xFFD0, 'X'), + (0xFFD2, 'M', u'ᅭ'), + (0xFFD3, 'M', u'ᅮ'), + (0xFFD4, 'M', u'ᅯ'), + (0xFFD5, 'M', u'ᅰ'), + (0xFFD6, 'M', u'ᅱ'), + (0xFFD7, 'M', u'ᅲ'), + (0xFFD8, 'X'), + (0xFFDA, 'M', u'ᅳ'), + (0xFFDB, 'M', u'ᅴ'), + (0xFFDC, 'M', u'ᅵ'), + (0xFFDD, 'X'), + (0xFFE0, 'M', u'¢'), + (0xFFE1, 'M', u'£'), + (0xFFE2, 'M', u'¬'), + (0xFFE3, '3', u' ̄'), + (0xFFE4, 'M', u'¦'), + (0xFFE5, 'M', u'¥'), + (0xFFE6, 'M', u'₩'), + (0xFFE7, 'X'), + (0xFFE8, 'M', u'│'), + (0xFFE9, 'M', u'←'), + (0xFFEA, 'M', u'↑'), + (0xFFEB, 'M', u'→'), + (0xFFEC, 'M', u'↓'), + (0xFFED, 'M', u'■'), + (0xFFEE, 'M', u'○'), + (0xFFEF, 'X'), + (0x10000, 'V'), + (0x1000C, 'X'), + (0x1000D, 'V'), + ] + +def _seg_53(): + return [ + (0x10027, 'X'), + (0x10028, 'V'), + (0x1003B, 'X'), + (0x1003C, 'V'), + (0x1003E, 'X'), + (0x1003F, 'V'), + (0x1004E, 'X'), + (0x10050, 'V'), + (0x1005E, 'X'), + (0x10080, 'V'), + (0x100FB, 'X'), + (0x10100, 'V'), + (0x10103, 'X'), + (0x10107, 'V'), + (0x10134, 'X'), + (0x10137, 'V'), + (0x1018F, 'X'), + (0x10190, 'V'), + (0x1019D, 'X'), + (0x101A0, 'V'), + (0x101A1, 'X'), + (0x101D0, 'V'), + (0x101FE, 'X'), + (0x10280, 'V'), + (0x1029D, 'X'), + (0x102A0, 'V'), + (0x102D1, 'X'), + (0x102E0, 'V'), + (0x102FC, 'X'), + (0x10300, 'V'), + (0x10324, 'X'), + (0x1032D, 'V'), + (0x1034B, 'X'), + (0x10350, 'V'), + (0x1037B, 'X'), + (0x10380, 'V'), + (0x1039E, 'X'), + (0x1039F, 'V'), + (0x103C4, 'X'), + (0x103C8, 'V'), + (0x103D6, 'X'), + (0x10400, 'M', u'𐐨'), + (0x10401, 'M', u'𐐩'), + (0x10402, 'M', u'𐐪'), + (0x10403, 'M', u'𐐫'), + (0x10404, 'M', u'𐐬'), + (0x10405, 'M', u'𐐭'), + (0x10406, 'M', u'𐐮'), + (0x10407, 'M', u'𐐯'), + (0x10408, 'M', u'𐐰'), + (0x10409, 'M', u'𐐱'), + (0x1040A, 'M', u'𐐲'), + (0x1040B, 'M', u'𐐳'), + (0x1040C, 'M', u'𐐴'), + (0x1040D, 'M', u'𐐵'), + (0x1040E, 'M', u'𐐶'), + (0x1040F, 'M', u'𐐷'), + (0x10410, 'M', u'𐐸'), + (0x10411, 'M', u'𐐹'), + (0x10412, 'M', u'𐐺'), + (0x10413, 'M', u'𐐻'), + (0x10414, 'M', u'𐐼'), + (0x10415, 'M', u'𐐽'), + (0x10416, 'M', u'𐐾'), + (0x10417, 'M', u'𐐿'), + (0x10418, 'M', u'𐑀'), + (0x10419, 'M', u'𐑁'), + (0x1041A, 'M', u'𐑂'), + (0x1041B, 'M', u'𐑃'), + (0x1041C, 'M', u'𐑄'), + (0x1041D, 'M', u'𐑅'), + (0x1041E, 'M', u'𐑆'), + (0x1041F, 'M', u'𐑇'), + (0x10420, 'M', u'𐑈'), + (0x10421, 'M', u'𐑉'), + (0x10422, 'M', u'𐑊'), + (0x10423, 'M', u'𐑋'), + (0x10424, 'M', u'𐑌'), + (0x10425, 'M', u'𐑍'), + (0x10426, 'M', u'𐑎'), + (0x10427, 'M', u'𐑏'), + (0x10428, 'V'), + (0x1049E, 'X'), + (0x104A0, 'V'), + (0x104AA, 'X'), + (0x104B0, 'M', u'𐓘'), + (0x104B1, 'M', u'𐓙'), + (0x104B2, 'M', u'𐓚'), + (0x104B3, 'M', u'𐓛'), + (0x104B4, 'M', u'𐓜'), + (0x104B5, 'M', u'𐓝'), + (0x104B6, 'M', u'𐓞'), + (0x104B7, 'M', u'𐓟'), + (0x104B8, 'M', u'𐓠'), + (0x104B9, 'M', u'𐓡'), + (0x104BA, 'M', u'𐓢'), + (0x104BB, 'M', u'𐓣'), + (0x104BC, 'M', u'𐓤'), + (0x104BD, 'M', u'𐓥'), + (0x104BE, 'M', u'𐓦'), + ] + +def _seg_54(): + return [ + (0x104BF, 'M', u'𐓧'), + (0x104C0, 'M', u'𐓨'), + (0x104C1, 'M', u'𐓩'), + (0x104C2, 'M', u'𐓪'), + (0x104C3, 'M', u'𐓫'), + (0x104C4, 'M', u'𐓬'), + (0x104C5, 'M', u'𐓭'), + (0x104C6, 'M', u'𐓮'), + (0x104C7, 'M', u'𐓯'), + (0x104C8, 'M', u'𐓰'), + (0x104C9, 'M', u'𐓱'), + (0x104CA, 'M', u'𐓲'), + (0x104CB, 'M', u'𐓳'), + (0x104CC, 'M', u'𐓴'), + (0x104CD, 'M', u'𐓵'), + (0x104CE, 'M', u'𐓶'), + (0x104CF, 'M', u'𐓷'), + (0x104D0, 'M', u'𐓸'), + (0x104D1, 'M', u'𐓹'), + (0x104D2, 'M', u'𐓺'), + (0x104D3, 'M', u'𐓻'), + (0x104D4, 'X'), + (0x104D8, 'V'), + (0x104FC, 'X'), + (0x10500, 'V'), + (0x10528, 'X'), + (0x10530, 'V'), + (0x10564, 'X'), + (0x1056F, 'V'), + (0x10570, 'X'), + (0x10600, 'V'), + (0x10737, 'X'), + (0x10740, 'V'), + (0x10756, 'X'), + (0x10760, 'V'), + (0x10768, 'X'), + (0x10800, 'V'), + (0x10806, 'X'), + (0x10808, 'V'), + (0x10809, 'X'), + (0x1080A, 'V'), + (0x10836, 'X'), + (0x10837, 'V'), + (0x10839, 'X'), + (0x1083C, 'V'), + (0x1083D, 'X'), + (0x1083F, 'V'), + (0x10856, 'X'), + (0x10857, 'V'), + (0x1089F, 'X'), + (0x108A7, 'V'), + (0x108B0, 'X'), + (0x108E0, 'V'), + (0x108F3, 'X'), + (0x108F4, 'V'), + (0x108F6, 'X'), + (0x108FB, 'V'), + (0x1091C, 'X'), + (0x1091F, 'V'), + (0x1093A, 'X'), + (0x1093F, 'V'), + (0x10940, 'X'), + (0x10980, 'V'), + (0x109B8, 'X'), + (0x109BC, 'V'), + (0x109D0, 'X'), + (0x109D2, 'V'), + (0x10A04, 'X'), + (0x10A05, 'V'), + (0x10A07, 'X'), + (0x10A0C, 'V'), + (0x10A14, 'X'), + (0x10A15, 'V'), + (0x10A18, 'X'), + (0x10A19, 'V'), + (0x10A36, 'X'), + (0x10A38, 'V'), + (0x10A3B, 'X'), + (0x10A3F, 'V'), + (0x10A49, 'X'), + (0x10A50, 'V'), + (0x10A59, 'X'), + (0x10A60, 'V'), + (0x10AA0, 'X'), + (0x10AC0, 'V'), + (0x10AE7, 'X'), + (0x10AEB, 'V'), + (0x10AF7, 'X'), + (0x10B00, 'V'), + (0x10B36, 'X'), + (0x10B39, 'V'), + (0x10B56, 'X'), + (0x10B58, 'V'), + (0x10B73, 'X'), + (0x10B78, 'V'), + (0x10B92, 'X'), + (0x10B99, 'V'), + (0x10B9D, 'X'), + (0x10BA9, 'V'), + (0x10BB0, 'X'), + ] + +def _seg_55(): + return [ + (0x10C00, 'V'), + (0x10C49, 'X'), + (0x10C80, 'M', u'𐳀'), + (0x10C81, 'M', u'𐳁'), + (0x10C82, 'M', u'𐳂'), + (0x10C83, 'M', u'𐳃'), + (0x10C84, 'M', u'𐳄'), + (0x10C85, 'M', u'𐳅'), + (0x10C86, 'M', u'𐳆'), + (0x10C87, 'M', u'𐳇'), + (0x10C88, 'M', u'𐳈'), + (0x10C89, 'M', u'𐳉'), + (0x10C8A, 'M', u'𐳊'), + (0x10C8B, 'M', u'𐳋'), + (0x10C8C, 'M', u'𐳌'), + (0x10C8D, 'M', u'𐳍'), + (0x10C8E, 'M', u'𐳎'), + (0x10C8F, 'M', u'𐳏'), + (0x10C90, 'M', u'𐳐'), + (0x10C91, 'M', u'𐳑'), + (0x10C92, 'M', u'𐳒'), + (0x10C93, 'M', u'𐳓'), + (0x10C94, 'M', u'𐳔'), + (0x10C95, 'M', u'𐳕'), + (0x10C96, 'M', u'𐳖'), + (0x10C97, 'M', u'𐳗'), + (0x10C98, 'M', u'𐳘'), + (0x10C99, 'M', u'𐳙'), + (0x10C9A, 'M', u'𐳚'), + (0x10C9B, 'M', u'𐳛'), + (0x10C9C, 'M', u'𐳜'), + (0x10C9D, 'M', u'𐳝'), + (0x10C9E, 'M', u'𐳞'), + (0x10C9F, 'M', u'𐳟'), + (0x10CA0, 'M', u'𐳠'), + (0x10CA1, 'M', u'𐳡'), + (0x10CA2, 'M', u'𐳢'), + (0x10CA3, 'M', u'𐳣'), + (0x10CA4, 'M', u'𐳤'), + (0x10CA5, 'M', u'𐳥'), + (0x10CA6, 'M', u'𐳦'), + (0x10CA7, 'M', u'𐳧'), + (0x10CA8, 'M', u'𐳨'), + (0x10CA9, 'M', u'𐳩'), + (0x10CAA, 'M', u'𐳪'), + (0x10CAB, 'M', u'𐳫'), + (0x10CAC, 'M', u'𐳬'), + (0x10CAD, 'M', u'𐳭'), + (0x10CAE, 'M', u'𐳮'), + (0x10CAF, 'M', u'𐳯'), + (0x10CB0, 'M', u'𐳰'), + (0x10CB1, 'M', u'𐳱'), + (0x10CB2, 'M', u'𐳲'), + (0x10CB3, 'X'), + (0x10CC0, 'V'), + (0x10CF3, 'X'), + (0x10CFA, 'V'), + (0x10D28, 'X'), + (0x10D30, 'V'), + (0x10D3A, 'X'), + (0x10E60, 'V'), + (0x10E7F, 'X'), + (0x10E80, 'V'), + (0x10EAA, 'X'), + (0x10EAB, 'V'), + (0x10EAE, 'X'), + (0x10EB0, 'V'), + (0x10EB2, 'X'), + (0x10F00, 'V'), + (0x10F28, 'X'), + (0x10F30, 'V'), + (0x10F5A, 'X'), + (0x10FB0, 'V'), + (0x10FCC, 'X'), + (0x10FE0, 'V'), + (0x10FF7, 'X'), + (0x11000, 'V'), + (0x1104E, 'X'), + (0x11052, 'V'), + (0x11070, 'X'), + (0x1107F, 'V'), + (0x110BD, 'X'), + (0x110BE, 'V'), + (0x110C2, 'X'), + (0x110D0, 'V'), + (0x110E9, 'X'), + (0x110F0, 'V'), + (0x110FA, 'X'), + (0x11100, 'V'), + (0x11135, 'X'), + (0x11136, 'V'), + (0x11148, 'X'), + (0x11150, 'V'), + (0x11177, 'X'), + (0x11180, 'V'), + (0x111E0, 'X'), + (0x111E1, 'V'), + (0x111F5, 'X'), + (0x11200, 'V'), + (0x11212, 'X'), + ] + +def _seg_56(): + return [ + (0x11213, 'V'), + (0x1123F, 'X'), + (0x11280, 'V'), + (0x11287, 'X'), + (0x11288, 'V'), + (0x11289, 'X'), + (0x1128A, 'V'), + (0x1128E, 'X'), + (0x1128F, 'V'), + (0x1129E, 'X'), + (0x1129F, 'V'), + (0x112AA, 'X'), + (0x112B0, 'V'), + (0x112EB, 'X'), + (0x112F0, 'V'), + (0x112FA, 'X'), + (0x11300, 'V'), + (0x11304, 'X'), + (0x11305, 'V'), + (0x1130D, 'X'), + (0x1130F, 'V'), + (0x11311, 'X'), + (0x11313, 'V'), + (0x11329, 'X'), + (0x1132A, 'V'), + (0x11331, 'X'), + (0x11332, 'V'), + (0x11334, 'X'), + (0x11335, 'V'), + (0x1133A, 'X'), + (0x1133B, 'V'), + (0x11345, 'X'), + (0x11347, 'V'), + (0x11349, 'X'), + (0x1134B, 'V'), + (0x1134E, 'X'), + (0x11350, 'V'), + (0x11351, 'X'), + (0x11357, 'V'), + (0x11358, 'X'), + (0x1135D, 'V'), + (0x11364, 'X'), + (0x11366, 'V'), + (0x1136D, 'X'), + (0x11370, 'V'), + (0x11375, 'X'), + (0x11400, 'V'), + (0x1145C, 'X'), + (0x1145D, 'V'), + (0x11462, 'X'), + (0x11480, 'V'), + (0x114C8, 'X'), + (0x114D0, 'V'), + (0x114DA, 'X'), + (0x11580, 'V'), + (0x115B6, 'X'), + (0x115B8, 'V'), + (0x115DE, 'X'), + (0x11600, 'V'), + (0x11645, 'X'), + (0x11650, 'V'), + (0x1165A, 'X'), + (0x11660, 'V'), + (0x1166D, 'X'), + (0x11680, 'V'), + (0x116B9, 'X'), + (0x116C0, 'V'), + (0x116CA, 'X'), + (0x11700, 'V'), + (0x1171B, 'X'), + (0x1171D, 'V'), + (0x1172C, 'X'), + (0x11730, 'V'), + (0x11740, 'X'), + (0x11800, 'V'), + (0x1183C, 'X'), + (0x118A0, 'M', u'𑣀'), + (0x118A1, 'M', u'𑣁'), + (0x118A2, 'M', u'𑣂'), + (0x118A3, 'M', u'𑣃'), + (0x118A4, 'M', u'𑣄'), + (0x118A5, 'M', u'𑣅'), + (0x118A6, 'M', u'𑣆'), + (0x118A7, 'M', u'𑣇'), + (0x118A8, 'M', u'𑣈'), + (0x118A9, 'M', u'𑣉'), + (0x118AA, 'M', u'𑣊'), + (0x118AB, 'M', u'𑣋'), + (0x118AC, 'M', u'𑣌'), + (0x118AD, 'M', u'𑣍'), + (0x118AE, 'M', u'𑣎'), + (0x118AF, 'M', u'𑣏'), + (0x118B0, 'M', u'𑣐'), + (0x118B1, 'M', u'𑣑'), + (0x118B2, 'M', u'𑣒'), + (0x118B3, 'M', u'𑣓'), + (0x118B4, 'M', u'𑣔'), + (0x118B5, 'M', u'𑣕'), + (0x118B6, 'M', u'𑣖'), + (0x118B7, 'M', u'𑣗'), + ] + +def _seg_57(): + return [ + (0x118B8, 'M', u'𑣘'), + (0x118B9, 'M', u'𑣙'), + (0x118BA, 'M', u'𑣚'), + (0x118BB, 'M', u'𑣛'), + (0x118BC, 'M', u'𑣜'), + (0x118BD, 'M', u'𑣝'), + (0x118BE, 'M', u'𑣞'), + (0x118BF, 'M', u'𑣟'), + (0x118C0, 'V'), + (0x118F3, 'X'), + (0x118FF, 'V'), + (0x11907, 'X'), + (0x11909, 'V'), + (0x1190A, 'X'), + (0x1190C, 'V'), + (0x11914, 'X'), + (0x11915, 'V'), + (0x11917, 'X'), + (0x11918, 'V'), + (0x11936, 'X'), + (0x11937, 'V'), + (0x11939, 'X'), + (0x1193B, 'V'), + (0x11947, 'X'), + (0x11950, 'V'), + (0x1195A, 'X'), + (0x119A0, 'V'), + (0x119A8, 'X'), + (0x119AA, 'V'), + (0x119D8, 'X'), + (0x119DA, 'V'), + (0x119E5, 'X'), + (0x11A00, 'V'), + (0x11A48, 'X'), + (0x11A50, 'V'), + (0x11AA3, 'X'), + (0x11AC0, 'V'), + (0x11AF9, 'X'), + (0x11C00, 'V'), + (0x11C09, 'X'), + (0x11C0A, 'V'), + (0x11C37, 'X'), + (0x11C38, 'V'), + (0x11C46, 'X'), + (0x11C50, 'V'), + (0x11C6D, 'X'), + (0x11C70, 'V'), + (0x11C90, 'X'), + (0x11C92, 'V'), + (0x11CA8, 'X'), + (0x11CA9, 'V'), + (0x11CB7, 'X'), + (0x11D00, 'V'), + (0x11D07, 'X'), + (0x11D08, 'V'), + (0x11D0A, 'X'), + (0x11D0B, 'V'), + (0x11D37, 'X'), + (0x11D3A, 'V'), + (0x11D3B, 'X'), + (0x11D3C, 'V'), + (0x11D3E, 'X'), + (0x11D3F, 'V'), + (0x11D48, 'X'), + (0x11D50, 'V'), + (0x11D5A, 'X'), + (0x11D60, 'V'), + (0x11D66, 'X'), + (0x11D67, 'V'), + (0x11D69, 'X'), + (0x11D6A, 'V'), + (0x11D8F, 'X'), + (0x11D90, 'V'), + (0x11D92, 'X'), + (0x11D93, 'V'), + (0x11D99, 'X'), + (0x11DA0, 'V'), + (0x11DAA, 'X'), + (0x11EE0, 'V'), + (0x11EF9, 'X'), + (0x11FB0, 'V'), + (0x11FB1, 'X'), + (0x11FC0, 'V'), + (0x11FF2, 'X'), + (0x11FFF, 'V'), + (0x1239A, 'X'), + (0x12400, 'V'), + (0x1246F, 'X'), + (0x12470, 'V'), + (0x12475, 'X'), + (0x12480, 'V'), + (0x12544, 'X'), + (0x13000, 'V'), + (0x1342F, 'X'), + (0x14400, 'V'), + (0x14647, 'X'), + (0x16800, 'V'), + (0x16A39, 'X'), + (0x16A40, 'V'), + (0x16A5F, 'X'), + ] + +def _seg_58(): + return [ + (0x16A60, 'V'), + (0x16A6A, 'X'), + (0x16A6E, 'V'), + (0x16A70, 'X'), + (0x16AD0, 'V'), + (0x16AEE, 'X'), + (0x16AF0, 'V'), + (0x16AF6, 'X'), + (0x16B00, 'V'), + (0x16B46, 'X'), + (0x16B50, 'V'), + (0x16B5A, 'X'), + (0x16B5B, 'V'), + (0x16B62, 'X'), + (0x16B63, 'V'), + (0x16B78, 'X'), + (0x16B7D, 'V'), + (0x16B90, 'X'), + (0x16E40, 'M', u'𖹠'), + (0x16E41, 'M', u'𖹡'), + (0x16E42, 'M', u'𖹢'), + (0x16E43, 'M', u'𖹣'), + (0x16E44, 'M', u'𖹤'), + (0x16E45, 'M', u'𖹥'), + (0x16E46, 'M', u'𖹦'), + (0x16E47, 'M', u'𖹧'), + (0x16E48, 'M', u'𖹨'), + (0x16E49, 'M', u'𖹩'), + (0x16E4A, 'M', u'𖹪'), + (0x16E4B, 'M', u'𖹫'), + (0x16E4C, 'M', u'𖹬'), + (0x16E4D, 'M', u'𖹭'), + (0x16E4E, 'M', u'𖹮'), + (0x16E4F, 'M', u'𖹯'), + (0x16E50, 'M', u'𖹰'), + (0x16E51, 'M', u'𖹱'), + (0x16E52, 'M', u'𖹲'), + (0x16E53, 'M', u'𖹳'), + (0x16E54, 'M', u'𖹴'), + (0x16E55, 'M', u'𖹵'), + (0x16E56, 'M', u'𖹶'), + (0x16E57, 'M', u'𖹷'), + (0x16E58, 'M', u'𖹸'), + (0x16E59, 'M', u'𖹹'), + (0x16E5A, 'M', u'𖹺'), + (0x16E5B, 'M', u'𖹻'), + (0x16E5C, 'M', u'𖹼'), + (0x16E5D, 'M', u'𖹽'), + (0x16E5E, 'M', u'𖹾'), + (0x16E5F, 'M', u'𖹿'), + (0x16E60, 'V'), + (0x16E9B, 'X'), + (0x16F00, 'V'), + (0x16F4B, 'X'), + (0x16F4F, 'V'), + (0x16F88, 'X'), + (0x16F8F, 'V'), + (0x16FA0, 'X'), + (0x16FE0, 'V'), + (0x16FE5, 'X'), + (0x16FF0, 'V'), + (0x16FF2, 'X'), + (0x17000, 'V'), + (0x187F8, 'X'), + (0x18800, 'V'), + (0x18CD6, 'X'), + (0x18D00, 'V'), + (0x18D09, 'X'), + (0x1B000, 'V'), + (0x1B11F, 'X'), + (0x1B150, 'V'), + (0x1B153, 'X'), + (0x1B164, 'V'), + (0x1B168, 'X'), + (0x1B170, 'V'), + (0x1B2FC, 'X'), + (0x1BC00, 'V'), + (0x1BC6B, 'X'), + (0x1BC70, 'V'), + (0x1BC7D, 'X'), + (0x1BC80, 'V'), + (0x1BC89, 'X'), + (0x1BC90, 'V'), + (0x1BC9A, 'X'), + (0x1BC9C, 'V'), + (0x1BCA0, 'I'), + (0x1BCA4, 'X'), + (0x1D000, 'V'), + (0x1D0F6, 'X'), + (0x1D100, 'V'), + (0x1D127, 'X'), + (0x1D129, 'V'), + (0x1D15E, 'M', u'𝅗𝅥'), + (0x1D15F, 'M', u'𝅘𝅥'), + (0x1D160, 'M', u'𝅘𝅥𝅮'), + (0x1D161, 'M', u'𝅘𝅥𝅯'), + (0x1D162, 'M', u'𝅘𝅥𝅰'), + (0x1D163, 'M', u'𝅘𝅥𝅱'), + (0x1D164, 'M', u'𝅘𝅥𝅲'), + (0x1D165, 'V'), + ] + +def _seg_59(): + return [ + (0x1D173, 'X'), + (0x1D17B, 'V'), + (0x1D1BB, 'M', u'𝆹𝅥'), + (0x1D1BC, 'M', u'𝆺𝅥'), + (0x1D1BD, 'M', u'𝆹𝅥𝅮'), + (0x1D1BE, 'M', u'𝆺𝅥𝅮'), + (0x1D1BF, 'M', u'𝆹𝅥𝅯'), + (0x1D1C0, 'M', u'𝆺𝅥𝅯'), + (0x1D1C1, 'V'), + (0x1D1E9, 'X'), + (0x1D200, 'V'), + (0x1D246, 'X'), + (0x1D2E0, 'V'), + (0x1D2F4, 'X'), + (0x1D300, 'V'), + (0x1D357, 'X'), + (0x1D360, 'V'), + (0x1D379, 'X'), + (0x1D400, 'M', u'a'), + (0x1D401, 'M', u'b'), + (0x1D402, 'M', u'c'), + (0x1D403, 'M', u'd'), + (0x1D404, 'M', u'e'), + (0x1D405, 'M', u'f'), + (0x1D406, 'M', u'g'), + (0x1D407, 'M', u'h'), + (0x1D408, 'M', u'i'), + (0x1D409, 'M', u'j'), + (0x1D40A, 'M', u'k'), + (0x1D40B, 'M', u'l'), + (0x1D40C, 'M', u'm'), + (0x1D40D, 'M', u'n'), + (0x1D40E, 'M', u'o'), + (0x1D40F, 'M', u'p'), + (0x1D410, 'M', u'q'), + (0x1D411, 'M', u'r'), + (0x1D412, 'M', u's'), + (0x1D413, 'M', u't'), + (0x1D414, 'M', u'u'), + (0x1D415, 'M', u'v'), + (0x1D416, 'M', u'w'), + (0x1D417, 'M', u'x'), + (0x1D418, 'M', u'y'), + (0x1D419, 'M', u'z'), + (0x1D41A, 'M', u'a'), + (0x1D41B, 'M', u'b'), + (0x1D41C, 'M', u'c'), + (0x1D41D, 'M', u'd'), + (0x1D41E, 'M', u'e'), + (0x1D41F, 'M', u'f'), + (0x1D420, 'M', u'g'), + (0x1D421, 'M', u'h'), + (0x1D422, 'M', u'i'), + (0x1D423, 'M', u'j'), + (0x1D424, 'M', u'k'), + (0x1D425, 'M', u'l'), + (0x1D426, 'M', u'm'), + (0x1D427, 'M', u'n'), + (0x1D428, 'M', u'o'), + (0x1D429, 'M', u'p'), + (0x1D42A, 'M', u'q'), + (0x1D42B, 'M', u'r'), + (0x1D42C, 'M', u's'), + (0x1D42D, 'M', u't'), + (0x1D42E, 'M', u'u'), + (0x1D42F, 'M', u'v'), + (0x1D430, 'M', u'w'), + (0x1D431, 'M', u'x'), + (0x1D432, 'M', u'y'), + (0x1D433, 'M', u'z'), + (0x1D434, 'M', u'a'), + (0x1D435, 'M', u'b'), + (0x1D436, 'M', u'c'), + (0x1D437, 'M', u'd'), + (0x1D438, 'M', u'e'), + (0x1D439, 'M', u'f'), + (0x1D43A, 'M', u'g'), + (0x1D43B, 'M', u'h'), + (0x1D43C, 'M', u'i'), + (0x1D43D, 'M', u'j'), + (0x1D43E, 'M', u'k'), + (0x1D43F, 'M', u'l'), + (0x1D440, 'M', u'm'), + (0x1D441, 'M', u'n'), + (0x1D442, 'M', u'o'), + (0x1D443, 'M', u'p'), + (0x1D444, 'M', u'q'), + (0x1D445, 'M', u'r'), + (0x1D446, 'M', u's'), + (0x1D447, 'M', u't'), + (0x1D448, 'M', u'u'), + (0x1D449, 'M', u'v'), + (0x1D44A, 'M', u'w'), + (0x1D44B, 'M', u'x'), + (0x1D44C, 'M', u'y'), + (0x1D44D, 'M', u'z'), + (0x1D44E, 'M', u'a'), + (0x1D44F, 'M', u'b'), + (0x1D450, 'M', u'c'), + (0x1D451, 'M', u'd'), + ] + +def _seg_60(): + return [ + (0x1D452, 'M', u'e'), + (0x1D453, 'M', u'f'), + (0x1D454, 'M', u'g'), + (0x1D455, 'X'), + (0x1D456, 'M', u'i'), + (0x1D457, 'M', u'j'), + (0x1D458, 'M', u'k'), + (0x1D459, 'M', u'l'), + (0x1D45A, 'M', u'm'), + (0x1D45B, 'M', u'n'), + (0x1D45C, 'M', u'o'), + (0x1D45D, 'M', u'p'), + (0x1D45E, 'M', u'q'), + (0x1D45F, 'M', u'r'), + (0x1D460, 'M', u's'), + (0x1D461, 'M', u't'), + (0x1D462, 'M', u'u'), + (0x1D463, 'M', u'v'), + (0x1D464, 'M', u'w'), + (0x1D465, 'M', u'x'), + (0x1D466, 'M', u'y'), + (0x1D467, 'M', u'z'), + (0x1D468, 'M', u'a'), + (0x1D469, 'M', u'b'), + (0x1D46A, 'M', u'c'), + (0x1D46B, 'M', u'd'), + (0x1D46C, 'M', u'e'), + (0x1D46D, 'M', u'f'), + (0x1D46E, 'M', u'g'), + (0x1D46F, 'M', u'h'), + (0x1D470, 'M', u'i'), + (0x1D471, 'M', u'j'), + (0x1D472, 'M', u'k'), + (0x1D473, 'M', u'l'), + (0x1D474, 'M', u'm'), + (0x1D475, 'M', u'n'), + (0x1D476, 'M', u'o'), + (0x1D477, 'M', u'p'), + (0x1D478, 'M', u'q'), + (0x1D479, 'M', u'r'), + (0x1D47A, 'M', u's'), + (0x1D47B, 'M', u't'), + (0x1D47C, 'M', u'u'), + (0x1D47D, 'M', u'v'), + (0x1D47E, 'M', u'w'), + (0x1D47F, 'M', u'x'), + (0x1D480, 'M', u'y'), + (0x1D481, 'M', u'z'), + (0x1D482, 'M', u'a'), + (0x1D483, 'M', u'b'), + (0x1D484, 'M', u'c'), + (0x1D485, 'M', u'd'), + (0x1D486, 'M', u'e'), + (0x1D487, 'M', u'f'), + (0x1D488, 'M', u'g'), + (0x1D489, 'M', u'h'), + (0x1D48A, 'M', u'i'), + (0x1D48B, 'M', u'j'), + (0x1D48C, 'M', u'k'), + (0x1D48D, 'M', u'l'), + (0x1D48E, 'M', u'm'), + (0x1D48F, 'M', u'n'), + (0x1D490, 'M', u'o'), + (0x1D491, 'M', u'p'), + (0x1D492, 'M', u'q'), + (0x1D493, 'M', u'r'), + (0x1D494, 'M', u's'), + (0x1D495, 'M', u't'), + (0x1D496, 'M', u'u'), + (0x1D497, 'M', u'v'), + (0x1D498, 'M', u'w'), + (0x1D499, 'M', u'x'), + (0x1D49A, 'M', u'y'), + (0x1D49B, 'M', u'z'), + (0x1D49C, 'M', u'a'), + (0x1D49D, 'X'), + (0x1D49E, 'M', u'c'), + (0x1D49F, 'M', u'd'), + (0x1D4A0, 'X'), + (0x1D4A2, 'M', u'g'), + (0x1D4A3, 'X'), + (0x1D4A5, 'M', u'j'), + (0x1D4A6, 'M', u'k'), + (0x1D4A7, 'X'), + (0x1D4A9, 'M', u'n'), + (0x1D4AA, 'M', u'o'), + (0x1D4AB, 'M', u'p'), + (0x1D4AC, 'M', u'q'), + (0x1D4AD, 'X'), + (0x1D4AE, 'M', u's'), + (0x1D4AF, 'M', u't'), + (0x1D4B0, 'M', u'u'), + (0x1D4B1, 'M', u'v'), + (0x1D4B2, 'M', u'w'), + (0x1D4B3, 'M', u'x'), + (0x1D4B4, 'M', u'y'), + (0x1D4B5, 'M', u'z'), + (0x1D4B6, 'M', u'a'), + (0x1D4B7, 'M', u'b'), + (0x1D4B8, 'M', u'c'), + ] + +def _seg_61(): + return [ + (0x1D4B9, 'M', u'd'), + (0x1D4BA, 'X'), + (0x1D4BB, 'M', u'f'), + (0x1D4BC, 'X'), + (0x1D4BD, 'M', u'h'), + (0x1D4BE, 'M', u'i'), + (0x1D4BF, 'M', u'j'), + (0x1D4C0, 'M', u'k'), + (0x1D4C1, 'M', u'l'), + (0x1D4C2, 'M', u'm'), + (0x1D4C3, 'M', u'n'), + (0x1D4C4, 'X'), + (0x1D4C5, 'M', u'p'), + (0x1D4C6, 'M', u'q'), + (0x1D4C7, 'M', u'r'), + (0x1D4C8, 'M', u's'), + (0x1D4C9, 'M', u't'), + (0x1D4CA, 'M', u'u'), + (0x1D4CB, 'M', u'v'), + (0x1D4CC, 'M', u'w'), + (0x1D4CD, 'M', u'x'), + (0x1D4CE, 'M', u'y'), + (0x1D4CF, 'M', u'z'), + (0x1D4D0, 'M', u'a'), + (0x1D4D1, 'M', u'b'), + (0x1D4D2, 'M', u'c'), + (0x1D4D3, 'M', u'd'), + (0x1D4D4, 'M', u'e'), + (0x1D4D5, 'M', u'f'), + (0x1D4D6, 'M', u'g'), + (0x1D4D7, 'M', u'h'), + (0x1D4D8, 'M', u'i'), + (0x1D4D9, 'M', u'j'), + (0x1D4DA, 'M', u'k'), + (0x1D4DB, 'M', u'l'), + (0x1D4DC, 'M', u'm'), + (0x1D4DD, 'M', u'n'), + (0x1D4DE, 'M', u'o'), + (0x1D4DF, 'M', u'p'), + (0x1D4E0, 'M', u'q'), + (0x1D4E1, 'M', u'r'), + (0x1D4E2, 'M', u's'), + (0x1D4E3, 'M', u't'), + (0x1D4E4, 'M', u'u'), + (0x1D4E5, 'M', u'v'), + (0x1D4E6, 'M', u'w'), + (0x1D4E7, 'M', u'x'), + (0x1D4E8, 'M', u'y'), + (0x1D4E9, 'M', u'z'), + (0x1D4EA, 'M', u'a'), + (0x1D4EB, 'M', u'b'), + (0x1D4EC, 'M', u'c'), + (0x1D4ED, 'M', u'd'), + (0x1D4EE, 'M', u'e'), + (0x1D4EF, 'M', u'f'), + (0x1D4F0, 'M', u'g'), + (0x1D4F1, 'M', u'h'), + (0x1D4F2, 'M', u'i'), + (0x1D4F3, 'M', u'j'), + (0x1D4F4, 'M', u'k'), + (0x1D4F5, 'M', u'l'), + (0x1D4F6, 'M', u'm'), + (0x1D4F7, 'M', u'n'), + (0x1D4F8, 'M', u'o'), + (0x1D4F9, 'M', u'p'), + (0x1D4FA, 'M', u'q'), + (0x1D4FB, 'M', u'r'), + (0x1D4FC, 'M', u's'), + (0x1D4FD, 'M', u't'), + (0x1D4FE, 'M', u'u'), + (0x1D4FF, 'M', u'v'), + (0x1D500, 'M', u'w'), + (0x1D501, 'M', u'x'), + (0x1D502, 'M', u'y'), + (0x1D503, 'M', u'z'), + (0x1D504, 'M', u'a'), + (0x1D505, 'M', u'b'), + (0x1D506, 'X'), + (0x1D507, 'M', u'd'), + (0x1D508, 'M', u'e'), + (0x1D509, 'M', u'f'), + (0x1D50A, 'M', u'g'), + (0x1D50B, 'X'), + (0x1D50D, 'M', u'j'), + (0x1D50E, 'M', u'k'), + (0x1D50F, 'M', u'l'), + (0x1D510, 'M', u'm'), + (0x1D511, 'M', u'n'), + (0x1D512, 'M', u'o'), + (0x1D513, 'M', u'p'), + (0x1D514, 'M', u'q'), + (0x1D515, 'X'), + (0x1D516, 'M', u's'), + (0x1D517, 'M', u't'), + (0x1D518, 'M', u'u'), + (0x1D519, 'M', u'v'), + (0x1D51A, 'M', u'w'), + (0x1D51B, 'M', u'x'), + (0x1D51C, 'M', u'y'), + (0x1D51D, 'X'), + ] + +def _seg_62(): + return [ + (0x1D51E, 'M', u'a'), + (0x1D51F, 'M', u'b'), + (0x1D520, 'M', u'c'), + (0x1D521, 'M', u'd'), + (0x1D522, 'M', u'e'), + (0x1D523, 'M', u'f'), + (0x1D524, 'M', u'g'), + (0x1D525, 'M', u'h'), + (0x1D526, 'M', u'i'), + (0x1D527, 'M', u'j'), + (0x1D528, 'M', u'k'), + (0x1D529, 'M', u'l'), + (0x1D52A, 'M', u'm'), + (0x1D52B, 'M', u'n'), + (0x1D52C, 'M', u'o'), + (0x1D52D, 'M', u'p'), + (0x1D52E, 'M', u'q'), + (0x1D52F, 'M', u'r'), + (0x1D530, 'M', u's'), + (0x1D531, 'M', u't'), + (0x1D532, 'M', u'u'), + (0x1D533, 'M', u'v'), + (0x1D534, 'M', u'w'), + (0x1D535, 'M', u'x'), + (0x1D536, 'M', u'y'), + (0x1D537, 'M', u'z'), + (0x1D538, 'M', u'a'), + (0x1D539, 'M', u'b'), + (0x1D53A, 'X'), + (0x1D53B, 'M', u'd'), + (0x1D53C, 'M', u'e'), + (0x1D53D, 'M', u'f'), + (0x1D53E, 'M', u'g'), + (0x1D53F, 'X'), + (0x1D540, 'M', u'i'), + (0x1D541, 'M', u'j'), + (0x1D542, 'M', u'k'), + (0x1D543, 'M', u'l'), + (0x1D544, 'M', u'm'), + (0x1D545, 'X'), + (0x1D546, 'M', u'o'), + (0x1D547, 'X'), + (0x1D54A, 'M', u's'), + (0x1D54B, 'M', u't'), + (0x1D54C, 'M', u'u'), + (0x1D54D, 'M', u'v'), + (0x1D54E, 'M', u'w'), + (0x1D54F, 'M', u'x'), + (0x1D550, 'M', u'y'), + (0x1D551, 'X'), + (0x1D552, 'M', u'a'), + (0x1D553, 'M', u'b'), + (0x1D554, 'M', u'c'), + (0x1D555, 'M', u'd'), + (0x1D556, 'M', u'e'), + (0x1D557, 'M', u'f'), + (0x1D558, 'M', u'g'), + (0x1D559, 'M', u'h'), + (0x1D55A, 'M', u'i'), + (0x1D55B, 'M', u'j'), + (0x1D55C, 'M', u'k'), + (0x1D55D, 'M', u'l'), + (0x1D55E, 'M', u'm'), + (0x1D55F, 'M', u'n'), + (0x1D560, 'M', u'o'), + (0x1D561, 'M', u'p'), + (0x1D562, 'M', u'q'), + (0x1D563, 'M', u'r'), + (0x1D564, 'M', u's'), + (0x1D565, 'M', u't'), + (0x1D566, 'M', u'u'), + (0x1D567, 'M', u'v'), + (0x1D568, 'M', u'w'), + (0x1D569, 'M', u'x'), + (0x1D56A, 'M', u'y'), + (0x1D56B, 'M', u'z'), + (0x1D56C, 'M', u'a'), + (0x1D56D, 'M', u'b'), + (0x1D56E, 'M', u'c'), + (0x1D56F, 'M', u'd'), + (0x1D570, 'M', u'e'), + (0x1D571, 'M', u'f'), + (0x1D572, 'M', u'g'), + (0x1D573, 'M', u'h'), + (0x1D574, 'M', u'i'), + (0x1D575, 'M', u'j'), + (0x1D576, 'M', u'k'), + (0x1D577, 'M', u'l'), + (0x1D578, 'M', u'm'), + (0x1D579, 'M', u'n'), + (0x1D57A, 'M', u'o'), + (0x1D57B, 'M', u'p'), + (0x1D57C, 'M', u'q'), + (0x1D57D, 'M', u'r'), + (0x1D57E, 'M', u's'), + (0x1D57F, 'M', u't'), + (0x1D580, 'M', u'u'), + (0x1D581, 'M', u'v'), + (0x1D582, 'M', u'w'), + (0x1D583, 'M', u'x'), + ] + +def _seg_63(): + return [ + (0x1D584, 'M', u'y'), + (0x1D585, 'M', u'z'), + (0x1D586, 'M', u'a'), + (0x1D587, 'M', u'b'), + (0x1D588, 'M', u'c'), + (0x1D589, 'M', u'd'), + (0x1D58A, 'M', u'e'), + (0x1D58B, 'M', u'f'), + (0x1D58C, 'M', u'g'), + (0x1D58D, 'M', u'h'), + (0x1D58E, 'M', u'i'), + (0x1D58F, 'M', u'j'), + (0x1D590, 'M', u'k'), + (0x1D591, 'M', u'l'), + (0x1D592, 'M', u'm'), + (0x1D593, 'M', u'n'), + (0x1D594, 'M', u'o'), + (0x1D595, 'M', u'p'), + (0x1D596, 'M', u'q'), + (0x1D597, 'M', u'r'), + (0x1D598, 'M', u's'), + (0x1D599, 'M', u't'), + (0x1D59A, 'M', u'u'), + (0x1D59B, 'M', u'v'), + (0x1D59C, 'M', u'w'), + (0x1D59D, 'M', u'x'), + (0x1D59E, 'M', u'y'), + (0x1D59F, 'M', u'z'), + (0x1D5A0, 'M', u'a'), + (0x1D5A1, 'M', u'b'), + (0x1D5A2, 'M', u'c'), + (0x1D5A3, 'M', u'd'), + (0x1D5A4, 'M', u'e'), + (0x1D5A5, 'M', u'f'), + (0x1D5A6, 'M', u'g'), + (0x1D5A7, 'M', u'h'), + (0x1D5A8, 'M', u'i'), + (0x1D5A9, 'M', u'j'), + (0x1D5AA, 'M', u'k'), + (0x1D5AB, 'M', u'l'), + (0x1D5AC, 'M', u'm'), + (0x1D5AD, 'M', u'n'), + (0x1D5AE, 'M', u'o'), + (0x1D5AF, 'M', u'p'), + (0x1D5B0, 'M', u'q'), + (0x1D5B1, 'M', u'r'), + (0x1D5B2, 'M', u's'), + (0x1D5B3, 'M', u't'), + (0x1D5B4, 'M', u'u'), + (0x1D5B5, 'M', u'v'), + (0x1D5B6, 'M', u'w'), + (0x1D5B7, 'M', u'x'), + (0x1D5B8, 'M', u'y'), + (0x1D5B9, 'M', u'z'), + (0x1D5BA, 'M', u'a'), + (0x1D5BB, 'M', u'b'), + (0x1D5BC, 'M', u'c'), + (0x1D5BD, 'M', u'd'), + (0x1D5BE, 'M', u'e'), + (0x1D5BF, 'M', u'f'), + (0x1D5C0, 'M', u'g'), + (0x1D5C1, 'M', u'h'), + (0x1D5C2, 'M', u'i'), + (0x1D5C3, 'M', u'j'), + (0x1D5C4, 'M', u'k'), + (0x1D5C5, 'M', u'l'), + (0x1D5C6, 'M', u'm'), + (0x1D5C7, 'M', u'n'), + (0x1D5C8, 'M', u'o'), + (0x1D5C9, 'M', u'p'), + (0x1D5CA, 'M', u'q'), + (0x1D5CB, 'M', u'r'), + (0x1D5CC, 'M', u's'), + (0x1D5CD, 'M', u't'), + (0x1D5CE, 'M', u'u'), + (0x1D5CF, 'M', u'v'), + (0x1D5D0, 'M', u'w'), + (0x1D5D1, 'M', u'x'), + (0x1D5D2, 'M', u'y'), + (0x1D5D3, 'M', u'z'), + (0x1D5D4, 'M', u'a'), + (0x1D5D5, 'M', u'b'), + (0x1D5D6, 'M', u'c'), + (0x1D5D7, 'M', u'd'), + (0x1D5D8, 'M', u'e'), + (0x1D5D9, 'M', u'f'), + (0x1D5DA, 'M', u'g'), + (0x1D5DB, 'M', u'h'), + (0x1D5DC, 'M', u'i'), + (0x1D5DD, 'M', u'j'), + (0x1D5DE, 'M', u'k'), + (0x1D5DF, 'M', u'l'), + (0x1D5E0, 'M', u'm'), + (0x1D5E1, 'M', u'n'), + (0x1D5E2, 'M', u'o'), + (0x1D5E3, 'M', u'p'), + (0x1D5E4, 'M', u'q'), + (0x1D5E5, 'M', u'r'), + (0x1D5E6, 'M', u's'), + (0x1D5E7, 'M', u't'), + ] + +def _seg_64(): + return [ + (0x1D5E8, 'M', u'u'), + (0x1D5E9, 'M', u'v'), + (0x1D5EA, 'M', u'w'), + (0x1D5EB, 'M', u'x'), + (0x1D5EC, 'M', u'y'), + (0x1D5ED, 'M', u'z'), + (0x1D5EE, 'M', u'a'), + (0x1D5EF, 'M', u'b'), + (0x1D5F0, 'M', u'c'), + (0x1D5F1, 'M', u'd'), + (0x1D5F2, 'M', u'e'), + (0x1D5F3, 'M', u'f'), + (0x1D5F4, 'M', u'g'), + (0x1D5F5, 'M', u'h'), + (0x1D5F6, 'M', u'i'), + (0x1D5F7, 'M', u'j'), + (0x1D5F8, 'M', u'k'), + (0x1D5F9, 'M', u'l'), + (0x1D5FA, 'M', u'm'), + (0x1D5FB, 'M', u'n'), + (0x1D5FC, 'M', u'o'), + (0x1D5FD, 'M', u'p'), + (0x1D5FE, 'M', u'q'), + (0x1D5FF, 'M', u'r'), + (0x1D600, 'M', u's'), + (0x1D601, 'M', u't'), + (0x1D602, 'M', u'u'), + (0x1D603, 'M', u'v'), + (0x1D604, 'M', u'w'), + (0x1D605, 'M', u'x'), + (0x1D606, 'M', u'y'), + (0x1D607, 'M', u'z'), + (0x1D608, 'M', u'a'), + (0x1D609, 'M', u'b'), + (0x1D60A, 'M', u'c'), + (0x1D60B, 'M', u'd'), + (0x1D60C, 'M', u'e'), + (0x1D60D, 'M', u'f'), + (0x1D60E, 'M', u'g'), + (0x1D60F, 'M', u'h'), + (0x1D610, 'M', u'i'), + (0x1D611, 'M', u'j'), + (0x1D612, 'M', u'k'), + (0x1D613, 'M', u'l'), + (0x1D614, 'M', u'm'), + (0x1D615, 'M', u'n'), + (0x1D616, 'M', u'o'), + (0x1D617, 'M', u'p'), + (0x1D618, 'M', u'q'), + (0x1D619, 'M', u'r'), + (0x1D61A, 'M', u's'), + (0x1D61B, 'M', u't'), + (0x1D61C, 'M', u'u'), + (0x1D61D, 'M', u'v'), + (0x1D61E, 'M', u'w'), + (0x1D61F, 'M', u'x'), + (0x1D620, 'M', u'y'), + (0x1D621, 'M', u'z'), + (0x1D622, 'M', u'a'), + (0x1D623, 'M', u'b'), + (0x1D624, 'M', u'c'), + (0x1D625, 'M', u'd'), + (0x1D626, 'M', u'e'), + (0x1D627, 'M', u'f'), + (0x1D628, 'M', u'g'), + (0x1D629, 'M', u'h'), + (0x1D62A, 'M', u'i'), + (0x1D62B, 'M', u'j'), + (0x1D62C, 'M', u'k'), + (0x1D62D, 'M', u'l'), + (0x1D62E, 'M', u'm'), + (0x1D62F, 'M', u'n'), + (0x1D630, 'M', u'o'), + (0x1D631, 'M', u'p'), + (0x1D632, 'M', u'q'), + (0x1D633, 'M', u'r'), + (0x1D634, 'M', u's'), + (0x1D635, 'M', u't'), + (0x1D636, 'M', u'u'), + (0x1D637, 'M', u'v'), + (0x1D638, 'M', u'w'), + (0x1D639, 'M', u'x'), + (0x1D63A, 'M', u'y'), + (0x1D63B, 'M', u'z'), + (0x1D63C, 'M', u'a'), + (0x1D63D, 'M', u'b'), + (0x1D63E, 'M', u'c'), + (0x1D63F, 'M', u'd'), + (0x1D640, 'M', u'e'), + (0x1D641, 'M', u'f'), + (0x1D642, 'M', u'g'), + (0x1D643, 'M', u'h'), + (0x1D644, 'M', u'i'), + (0x1D645, 'M', u'j'), + (0x1D646, 'M', u'k'), + (0x1D647, 'M', u'l'), + (0x1D648, 'M', u'm'), + (0x1D649, 'M', u'n'), + (0x1D64A, 'M', u'o'), + (0x1D64B, 'M', u'p'), + ] + +def _seg_65(): + return [ + (0x1D64C, 'M', u'q'), + (0x1D64D, 'M', u'r'), + (0x1D64E, 'M', u's'), + (0x1D64F, 'M', u't'), + (0x1D650, 'M', u'u'), + (0x1D651, 'M', u'v'), + (0x1D652, 'M', u'w'), + (0x1D653, 'M', u'x'), + (0x1D654, 'M', u'y'), + (0x1D655, 'M', u'z'), + (0x1D656, 'M', u'a'), + (0x1D657, 'M', u'b'), + (0x1D658, 'M', u'c'), + (0x1D659, 'M', u'd'), + (0x1D65A, 'M', u'e'), + (0x1D65B, 'M', u'f'), + (0x1D65C, 'M', u'g'), + (0x1D65D, 'M', u'h'), + (0x1D65E, 'M', u'i'), + (0x1D65F, 'M', u'j'), + (0x1D660, 'M', u'k'), + (0x1D661, 'M', u'l'), + (0x1D662, 'M', u'm'), + (0x1D663, 'M', u'n'), + (0x1D664, 'M', u'o'), + (0x1D665, 'M', u'p'), + (0x1D666, 'M', u'q'), + (0x1D667, 'M', u'r'), + (0x1D668, 'M', u's'), + (0x1D669, 'M', u't'), + (0x1D66A, 'M', u'u'), + (0x1D66B, 'M', u'v'), + (0x1D66C, 'M', u'w'), + (0x1D66D, 'M', u'x'), + (0x1D66E, 'M', u'y'), + (0x1D66F, 'M', u'z'), + (0x1D670, 'M', u'a'), + (0x1D671, 'M', u'b'), + (0x1D672, 'M', u'c'), + (0x1D673, 'M', u'd'), + (0x1D674, 'M', u'e'), + (0x1D675, 'M', u'f'), + (0x1D676, 'M', u'g'), + (0x1D677, 'M', u'h'), + (0x1D678, 'M', u'i'), + (0x1D679, 'M', u'j'), + (0x1D67A, 'M', u'k'), + (0x1D67B, 'M', u'l'), + (0x1D67C, 'M', u'm'), + (0x1D67D, 'M', u'n'), + (0x1D67E, 'M', u'o'), + (0x1D67F, 'M', u'p'), + (0x1D680, 'M', u'q'), + (0x1D681, 'M', u'r'), + (0x1D682, 'M', u's'), + (0x1D683, 'M', u't'), + (0x1D684, 'M', u'u'), + (0x1D685, 'M', u'v'), + (0x1D686, 'M', u'w'), + (0x1D687, 'M', u'x'), + (0x1D688, 'M', u'y'), + (0x1D689, 'M', u'z'), + (0x1D68A, 'M', u'a'), + (0x1D68B, 'M', u'b'), + (0x1D68C, 'M', u'c'), + (0x1D68D, 'M', u'd'), + (0x1D68E, 'M', u'e'), + (0x1D68F, 'M', u'f'), + (0x1D690, 'M', u'g'), + (0x1D691, 'M', u'h'), + (0x1D692, 'M', u'i'), + (0x1D693, 'M', u'j'), + (0x1D694, 'M', u'k'), + (0x1D695, 'M', u'l'), + (0x1D696, 'M', u'm'), + (0x1D697, 'M', u'n'), + (0x1D698, 'M', u'o'), + (0x1D699, 'M', u'p'), + (0x1D69A, 'M', u'q'), + (0x1D69B, 'M', u'r'), + (0x1D69C, 'M', u's'), + (0x1D69D, 'M', u't'), + (0x1D69E, 'M', u'u'), + (0x1D69F, 'M', u'v'), + (0x1D6A0, 'M', u'w'), + (0x1D6A1, 'M', u'x'), + (0x1D6A2, 'M', u'y'), + (0x1D6A3, 'M', u'z'), + (0x1D6A4, 'M', u'ı'), + (0x1D6A5, 'M', u'ȷ'), + (0x1D6A6, 'X'), + (0x1D6A8, 'M', u'α'), + (0x1D6A9, 'M', u'β'), + (0x1D6AA, 'M', u'γ'), + (0x1D6AB, 'M', u'δ'), + (0x1D6AC, 'M', u'ε'), + (0x1D6AD, 'M', u'ζ'), + (0x1D6AE, 'M', u'η'), + (0x1D6AF, 'M', u'θ'), + (0x1D6B0, 'M', u'ι'), + ] + +def _seg_66(): + return [ + (0x1D6B1, 'M', u'κ'), + (0x1D6B2, 'M', u'λ'), + (0x1D6B3, 'M', u'μ'), + (0x1D6B4, 'M', u'ν'), + (0x1D6B5, 'M', u'ξ'), + (0x1D6B6, 'M', u'ο'), + (0x1D6B7, 'M', u'π'), + (0x1D6B8, 'M', u'ρ'), + (0x1D6B9, 'M', u'θ'), + (0x1D6BA, 'M', u'σ'), + (0x1D6BB, 'M', u'τ'), + (0x1D6BC, 'M', u'υ'), + (0x1D6BD, 'M', u'φ'), + (0x1D6BE, 'M', u'χ'), + (0x1D6BF, 'M', u'ψ'), + (0x1D6C0, 'M', u'ω'), + (0x1D6C1, 'M', u'∇'), + (0x1D6C2, 'M', u'α'), + (0x1D6C3, 'M', u'β'), + (0x1D6C4, 'M', u'γ'), + (0x1D6C5, 'M', u'δ'), + (0x1D6C6, 'M', u'ε'), + (0x1D6C7, 'M', u'ζ'), + (0x1D6C8, 'M', u'η'), + (0x1D6C9, 'M', u'θ'), + (0x1D6CA, 'M', u'ι'), + (0x1D6CB, 'M', u'κ'), + (0x1D6CC, 'M', u'λ'), + (0x1D6CD, 'M', u'μ'), + (0x1D6CE, 'M', u'ν'), + (0x1D6CF, 'M', u'ξ'), + (0x1D6D0, 'M', u'ο'), + (0x1D6D1, 'M', u'π'), + (0x1D6D2, 'M', u'ρ'), + (0x1D6D3, 'M', u'σ'), + (0x1D6D5, 'M', u'τ'), + (0x1D6D6, 'M', u'υ'), + (0x1D6D7, 'M', u'φ'), + (0x1D6D8, 'M', u'χ'), + (0x1D6D9, 'M', u'ψ'), + (0x1D6DA, 'M', u'ω'), + (0x1D6DB, 'M', u'∂'), + (0x1D6DC, 'M', u'ε'), + (0x1D6DD, 'M', u'θ'), + (0x1D6DE, 'M', u'κ'), + (0x1D6DF, 'M', u'φ'), + (0x1D6E0, 'M', u'ρ'), + (0x1D6E1, 'M', u'π'), + (0x1D6E2, 'M', u'α'), + (0x1D6E3, 'M', u'β'), + (0x1D6E4, 'M', u'γ'), + (0x1D6E5, 'M', u'δ'), + (0x1D6E6, 'M', u'ε'), + (0x1D6E7, 'M', u'ζ'), + (0x1D6E8, 'M', u'η'), + (0x1D6E9, 'M', u'θ'), + (0x1D6EA, 'M', u'ι'), + (0x1D6EB, 'M', u'κ'), + (0x1D6EC, 'M', u'λ'), + (0x1D6ED, 'M', u'μ'), + (0x1D6EE, 'M', u'ν'), + (0x1D6EF, 'M', u'ξ'), + (0x1D6F0, 'M', u'ο'), + (0x1D6F1, 'M', u'π'), + (0x1D6F2, 'M', u'ρ'), + (0x1D6F3, 'M', u'θ'), + (0x1D6F4, 'M', u'σ'), + (0x1D6F5, 'M', u'τ'), + (0x1D6F6, 'M', u'υ'), + (0x1D6F7, 'M', u'φ'), + (0x1D6F8, 'M', u'χ'), + (0x1D6F9, 'M', u'ψ'), + (0x1D6FA, 'M', u'ω'), + (0x1D6FB, 'M', u'∇'), + (0x1D6FC, 'M', u'α'), + (0x1D6FD, 'M', u'β'), + (0x1D6FE, 'M', u'γ'), + (0x1D6FF, 'M', u'δ'), + (0x1D700, 'M', u'ε'), + (0x1D701, 'M', u'ζ'), + (0x1D702, 'M', u'η'), + (0x1D703, 'M', u'θ'), + (0x1D704, 'M', u'ι'), + (0x1D705, 'M', u'κ'), + (0x1D706, 'M', u'λ'), + (0x1D707, 'M', u'μ'), + (0x1D708, 'M', u'ν'), + (0x1D709, 'M', u'ξ'), + (0x1D70A, 'M', u'ο'), + (0x1D70B, 'M', u'π'), + (0x1D70C, 'M', u'ρ'), + (0x1D70D, 'M', u'σ'), + (0x1D70F, 'M', u'τ'), + (0x1D710, 'M', u'υ'), + (0x1D711, 'M', u'φ'), + (0x1D712, 'M', u'χ'), + (0x1D713, 'M', u'ψ'), + (0x1D714, 'M', u'ω'), + (0x1D715, 'M', u'∂'), + (0x1D716, 'M', u'ε'), + ] + +def _seg_67(): + return [ + (0x1D717, 'M', u'θ'), + (0x1D718, 'M', u'κ'), + (0x1D719, 'M', u'φ'), + (0x1D71A, 'M', u'ρ'), + (0x1D71B, 'M', u'π'), + (0x1D71C, 'M', u'α'), + (0x1D71D, 'M', u'β'), + (0x1D71E, 'M', u'γ'), + (0x1D71F, 'M', u'δ'), + (0x1D720, 'M', u'ε'), + (0x1D721, 'M', u'ζ'), + (0x1D722, 'M', u'η'), + (0x1D723, 'M', u'θ'), + (0x1D724, 'M', u'ι'), + (0x1D725, 'M', u'κ'), + (0x1D726, 'M', u'λ'), + (0x1D727, 'M', u'μ'), + (0x1D728, 'M', u'ν'), + (0x1D729, 'M', u'ξ'), + (0x1D72A, 'M', u'ο'), + (0x1D72B, 'M', u'π'), + (0x1D72C, 'M', u'ρ'), + (0x1D72D, 'M', u'θ'), + (0x1D72E, 'M', u'σ'), + (0x1D72F, 'M', u'τ'), + (0x1D730, 'M', u'υ'), + (0x1D731, 'M', u'φ'), + (0x1D732, 'M', u'χ'), + (0x1D733, 'M', u'ψ'), + (0x1D734, 'M', u'ω'), + (0x1D735, 'M', u'∇'), + (0x1D736, 'M', u'α'), + (0x1D737, 'M', u'β'), + (0x1D738, 'M', u'γ'), + (0x1D739, 'M', u'δ'), + (0x1D73A, 'M', u'ε'), + (0x1D73B, 'M', u'ζ'), + (0x1D73C, 'M', u'η'), + (0x1D73D, 'M', u'θ'), + (0x1D73E, 'M', u'ι'), + (0x1D73F, 'M', u'κ'), + (0x1D740, 'M', u'λ'), + (0x1D741, 'M', u'μ'), + (0x1D742, 'M', u'ν'), + (0x1D743, 'M', u'ξ'), + (0x1D744, 'M', u'ο'), + (0x1D745, 'M', u'π'), + (0x1D746, 'M', u'ρ'), + (0x1D747, 'M', u'σ'), + (0x1D749, 'M', u'τ'), + (0x1D74A, 'M', u'υ'), + (0x1D74B, 'M', u'φ'), + (0x1D74C, 'M', u'χ'), + (0x1D74D, 'M', u'ψ'), + (0x1D74E, 'M', u'ω'), + (0x1D74F, 'M', u'∂'), + (0x1D750, 'M', u'ε'), + (0x1D751, 'M', u'θ'), + (0x1D752, 'M', u'κ'), + (0x1D753, 'M', u'φ'), + (0x1D754, 'M', u'ρ'), + (0x1D755, 'M', u'π'), + (0x1D756, 'M', u'α'), + (0x1D757, 'M', u'β'), + (0x1D758, 'M', u'γ'), + (0x1D759, 'M', u'δ'), + (0x1D75A, 'M', u'ε'), + (0x1D75B, 'M', u'ζ'), + (0x1D75C, 'M', u'η'), + (0x1D75D, 'M', u'θ'), + (0x1D75E, 'M', u'ι'), + (0x1D75F, 'M', u'κ'), + (0x1D760, 'M', u'λ'), + (0x1D761, 'M', u'μ'), + (0x1D762, 'M', u'ν'), + (0x1D763, 'M', u'ξ'), + (0x1D764, 'M', u'ο'), + (0x1D765, 'M', u'π'), + (0x1D766, 'M', u'ρ'), + (0x1D767, 'M', u'θ'), + (0x1D768, 'M', u'σ'), + (0x1D769, 'M', u'τ'), + (0x1D76A, 'M', u'υ'), + (0x1D76B, 'M', u'φ'), + (0x1D76C, 'M', u'χ'), + (0x1D76D, 'M', u'ψ'), + (0x1D76E, 'M', u'ω'), + (0x1D76F, 'M', u'∇'), + (0x1D770, 'M', u'α'), + (0x1D771, 'M', u'β'), + (0x1D772, 'M', u'γ'), + (0x1D773, 'M', u'δ'), + (0x1D774, 'M', u'ε'), + (0x1D775, 'M', u'ζ'), + (0x1D776, 'M', u'η'), + (0x1D777, 'M', u'θ'), + (0x1D778, 'M', u'ι'), + (0x1D779, 'M', u'κ'), + (0x1D77A, 'M', u'λ'), + (0x1D77B, 'M', u'μ'), + ] + +def _seg_68(): + return [ + (0x1D77C, 'M', u'ν'), + (0x1D77D, 'M', u'ξ'), + (0x1D77E, 'M', u'ο'), + (0x1D77F, 'M', u'π'), + (0x1D780, 'M', u'ρ'), + (0x1D781, 'M', u'σ'), + (0x1D783, 'M', u'τ'), + (0x1D784, 'M', u'υ'), + (0x1D785, 'M', u'φ'), + (0x1D786, 'M', u'χ'), + (0x1D787, 'M', u'ψ'), + (0x1D788, 'M', u'ω'), + (0x1D789, 'M', u'∂'), + (0x1D78A, 'M', u'ε'), + (0x1D78B, 'M', u'θ'), + (0x1D78C, 'M', u'κ'), + (0x1D78D, 'M', u'φ'), + (0x1D78E, 'M', u'ρ'), + (0x1D78F, 'M', u'π'), + (0x1D790, 'M', u'α'), + (0x1D791, 'M', u'β'), + (0x1D792, 'M', u'γ'), + (0x1D793, 'M', u'δ'), + (0x1D794, 'M', u'ε'), + (0x1D795, 'M', u'ζ'), + (0x1D796, 'M', u'η'), + (0x1D797, 'M', u'θ'), + (0x1D798, 'M', u'ι'), + (0x1D799, 'M', u'κ'), + (0x1D79A, 'M', u'λ'), + (0x1D79B, 'M', u'μ'), + (0x1D79C, 'M', u'ν'), + (0x1D79D, 'M', u'ξ'), + (0x1D79E, 'M', u'ο'), + (0x1D79F, 'M', u'π'), + (0x1D7A0, 'M', u'ρ'), + (0x1D7A1, 'M', u'θ'), + (0x1D7A2, 'M', u'σ'), + (0x1D7A3, 'M', u'τ'), + (0x1D7A4, 'M', u'υ'), + (0x1D7A5, 'M', u'φ'), + (0x1D7A6, 'M', u'χ'), + (0x1D7A7, 'M', u'ψ'), + (0x1D7A8, 'M', u'ω'), + (0x1D7A9, 'M', u'∇'), + (0x1D7AA, 'M', u'α'), + (0x1D7AB, 'M', u'β'), + (0x1D7AC, 'M', u'γ'), + (0x1D7AD, 'M', u'δ'), + (0x1D7AE, 'M', u'ε'), + (0x1D7AF, 'M', u'ζ'), + (0x1D7B0, 'M', u'η'), + (0x1D7B1, 'M', u'θ'), + (0x1D7B2, 'M', u'ι'), + (0x1D7B3, 'M', u'κ'), + (0x1D7B4, 'M', u'λ'), + (0x1D7B5, 'M', u'μ'), + (0x1D7B6, 'M', u'ν'), + (0x1D7B7, 'M', u'ξ'), + (0x1D7B8, 'M', u'ο'), + (0x1D7B9, 'M', u'π'), + (0x1D7BA, 'M', u'ρ'), + (0x1D7BB, 'M', u'σ'), + (0x1D7BD, 'M', u'τ'), + (0x1D7BE, 'M', u'υ'), + (0x1D7BF, 'M', u'φ'), + (0x1D7C0, 'M', u'χ'), + (0x1D7C1, 'M', u'ψ'), + (0x1D7C2, 'M', u'ω'), + (0x1D7C3, 'M', u'∂'), + (0x1D7C4, 'M', u'ε'), + (0x1D7C5, 'M', u'θ'), + (0x1D7C6, 'M', u'κ'), + (0x1D7C7, 'M', u'φ'), + (0x1D7C8, 'M', u'ρ'), + (0x1D7C9, 'M', u'π'), + (0x1D7CA, 'M', u'ϝ'), + (0x1D7CC, 'X'), + (0x1D7CE, 'M', u'0'), + (0x1D7CF, 'M', u'1'), + (0x1D7D0, 'M', u'2'), + (0x1D7D1, 'M', u'3'), + (0x1D7D2, 'M', u'4'), + (0x1D7D3, 'M', u'5'), + (0x1D7D4, 'M', u'6'), + (0x1D7D5, 'M', u'7'), + (0x1D7D6, 'M', u'8'), + (0x1D7D7, 'M', u'9'), + (0x1D7D8, 'M', u'0'), + (0x1D7D9, 'M', u'1'), + (0x1D7DA, 'M', u'2'), + (0x1D7DB, 'M', u'3'), + (0x1D7DC, 'M', u'4'), + (0x1D7DD, 'M', u'5'), + (0x1D7DE, 'M', u'6'), + (0x1D7DF, 'M', u'7'), + (0x1D7E0, 'M', u'8'), + (0x1D7E1, 'M', u'9'), + (0x1D7E2, 'M', u'0'), + (0x1D7E3, 'M', u'1'), + ] + +def _seg_69(): + return [ + (0x1D7E4, 'M', u'2'), + (0x1D7E5, 'M', u'3'), + (0x1D7E6, 'M', u'4'), + (0x1D7E7, 'M', u'5'), + (0x1D7E8, 'M', u'6'), + (0x1D7E9, 'M', u'7'), + (0x1D7EA, 'M', u'8'), + (0x1D7EB, 'M', u'9'), + (0x1D7EC, 'M', u'0'), + (0x1D7ED, 'M', u'1'), + (0x1D7EE, 'M', u'2'), + (0x1D7EF, 'M', u'3'), + (0x1D7F0, 'M', u'4'), + (0x1D7F1, 'M', u'5'), + (0x1D7F2, 'M', u'6'), + (0x1D7F3, 'M', u'7'), + (0x1D7F4, 'M', u'8'), + (0x1D7F5, 'M', u'9'), + (0x1D7F6, 'M', u'0'), + (0x1D7F7, 'M', u'1'), + (0x1D7F8, 'M', u'2'), + (0x1D7F9, 'M', u'3'), + (0x1D7FA, 'M', u'4'), + (0x1D7FB, 'M', u'5'), + (0x1D7FC, 'M', u'6'), + (0x1D7FD, 'M', u'7'), + (0x1D7FE, 'M', u'8'), + (0x1D7FF, 'M', u'9'), + (0x1D800, 'V'), + (0x1DA8C, 'X'), + (0x1DA9B, 'V'), + (0x1DAA0, 'X'), + (0x1DAA1, 'V'), + (0x1DAB0, 'X'), + (0x1E000, 'V'), + (0x1E007, 'X'), + (0x1E008, 'V'), + (0x1E019, 'X'), + (0x1E01B, 'V'), + (0x1E022, 'X'), + (0x1E023, 'V'), + (0x1E025, 'X'), + (0x1E026, 'V'), + (0x1E02B, 'X'), + (0x1E100, 'V'), + (0x1E12D, 'X'), + (0x1E130, 'V'), + (0x1E13E, 'X'), + (0x1E140, 'V'), + (0x1E14A, 'X'), + (0x1E14E, 'V'), + (0x1E150, 'X'), + (0x1E2C0, 'V'), + (0x1E2FA, 'X'), + (0x1E2FF, 'V'), + (0x1E300, 'X'), + (0x1E800, 'V'), + (0x1E8C5, 'X'), + (0x1E8C7, 'V'), + (0x1E8D7, 'X'), + (0x1E900, 'M', u'𞤢'), + (0x1E901, 'M', u'𞤣'), + (0x1E902, 'M', u'𞤤'), + (0x1E903, 'M', u'𞤥'), + (0x1E904, 'M', u'𞤦'), + (0x1E905, 'M', u'𞤧'), + (0x1E906, 'M', u'𞤨'), + (0x1E907, 'M', u'𞤩'), + (0x1E908, 'M', u'𞤪'), + (0x1E909, 'M', u'𞤫'), + (0x1E90A, 'M', u'𞤬'), + (0x1E90B, 'M', u'𞤭'), + (0x1E90C, 'M', u'𞤮'), + (0x1E90D, 'M', u'𞤯'), + (0x1E90E, 'M', u'𞤰'), + (0x1E90F, 'M', u'𞤱'), + (0x1E910, 'M', u'𞤲'), + (0x1E911, 'M', u'𞤳'), + (0x1E912, 'M', u'𞤴'), + (0x1E913, 'M', u'𞤵'), + (0x1E914, 'M', u'𞤶'), + (0x1E915, 'M', u'𞤷'), + (0x1E916, 'M', u'𞤸'), + (0x1E917, 'M', u'𞤹'), + (0x1E918, 'M', u'𞤺'), + (0x1E919, 'M', u'𞤻'), + (0x1E91A, 'M', u'𞤼'), + (0x1E91B, 'M', u'𞤽'), + (0x1E91C, 'M', u'𞤾'), + (0x1E91D, 'M', u'𞤿'), + (0x1E91E, 'M', u'𞥀'), + (0x1E91F, 'M', u'𞥁'), + (0x1E920, 'M', u'𞥂'), + (0x1E921, 'M', u'𞥃'), + (0x1E922, 'V'), + (0x1E94C, 'X'), + (0x1E950, 'V'), + (0x1E95A, 'X'), + (0x1E95E, 'V'), + (0x1E960, 'X'), + ] + +def _seg_70(): + return [ + (0x1EC71, 'V'), + (0x1ECB5, 'X'), + (0x1ED01, 'V'), + (0x1ED3E, 'X'), + (0x1EE00, 'M', u'ا'), + (0x1EE01, 'M', u'ب'), + (0x1EE02, 'M', u'ج'), + (0x1EE03, 'M', u'د'), + (0x1EE04, 'X'), + (0x1EE05, 'M', u'و'), + (0x1EE06, 'M', u'ز'), + (0x1EE07, 'M', u'ح'), + (0x1EE08, 'M', u'ط'), + (0x1EE09, 'M', u'ي'), + (0x1EE0A, 'M', u'ك'), + (0x1EE0B, 'M', u'ل'), + (0x1EE0C, 'M', u'م'), + (0x1EE0D, 'M', u'ن'), + (0x1EE0E, 'M', u'س'), + (0x1EE0F, 'M', u'ع'), + (0x1EE10, 'M', u'ف'), + (0x1EE11, 'M', u'ص'), + (0x1EE12, 'M', u'ق'), + (0x1EE13, 'M', u'ر'), + (0x1EE14, 'M', u'ش'), + (0x1EE15, 'M', u'ت'), + (0x1EE16, 'M', u'ث'), + (0x1EE17, 'M', u'خ'), + (0x1EE18, 'M', u'ذ'), + (0x1EE19, 'M', u'ض'), + (0x1EE1A, 'M', u'ظ'), + (0x1EE1B, 'M', u'غ'), + (0x1EE1C, 'M', u'ٮ'), + (0x1EE1D, 'M', u'ں'), + (0x1EE1E, 'M', u'ڡ'), + (0x1EE1F, 'M', u'ٯ'), + (0x1EE20, 'X'), + (0x1EE21, 'M', u'ب'), + (0x1EE22, 'M', u'ج'), + (0x1EE23, 'X'), + (0x1EE24, 'M', u'ه'), + (0x1EE25, 'X'), + (0x1EE27, 'M', u'ح'), + (0x1EE28, 'X'), + (0x1EE29, 'M', u'ي'), + (0x1EE2A, 'M', u'ك'), + (0x1EE2B, 'M', u'ل'), + (0x1EE2C, 'M', u'م'), + (0x1EE2D, 'M', u'ن'), + (0x1EE2E, 'M', u'س'), + (0x1EE2F, 'M', u'ع'), + (0x1EE30, 'M', u'ف'), + (0x1EE31, 'M', u'ص'), + (0x1EE32, 'M', u'ق'), + (0x1EE33, 'X'), + (0x1EE34, 'M', u'ش'), + (0x1EE35, 'M', u'ت'), + (0x1EE36, 'M', u'ث'), + (0x1EE37, 'M', u'خ'), + (0x1EE38, 'X'), + (0x1EE39, 'M', u'ض'), + (0x1EE3A, 'X'), + (0x1EE3B, 'M', u'غ'), + (0x1EE3C, 'X'), + (0x1EE42, 'M', u'ج'), + (0x1EE43, 'X'), + (0x1EE47, 'M', u'ح'), + (0x1EE48, 'X'), + (0x1EE49, 'M', u'ي'), + (0x1EE4A, 'X'), + (0x1EE4B, 'M', u'ل'), + (0x1EE4C, 'X'), + (0x1EE4D, 'M', u'ن'), + (0x1EE4E, 'M', u'س'), + (0x1EE4F, 'M', u'ع'), + (0x1EE50, 'X'), + (0x1EE51, 'M', u'ص'), + (0x1EE52, 'M', u'ق'), + (0x1EE53, 'X'), + (0x1EE54, 'M', u'ش'), + (0x1EE55, 'X'), + (0x1EE57, 'M', u'خ'), + (0x1EE58, 'X'), + (0x1EE59, 'M', u'ض'), + (0x1EE5A, 'X'), + (0x1EE5B, 'M', u'غ'), + (0x1EE5C, 'X'), + (0x1EE5D, 'M', u'ں'), + (0x1EE5E, 'X'), + (0x1EE5F, 'M', u'ٯ'), + (0x1EE60, 'X'), + (0x1EE61, 'M', u'ب'), + (0x1EE62, 'M', u'ج'), + (0x1EE63, 'X'), + (0x1EE64, 'M', u'ه'), + (0x1EE65, 'X'), + (0x1EE67, 'M', u'ح'), + (0x1EE68, 'M', u'ط'), + (0x1EE69, 'M', u'ي'), + (0x1EE6A, 'M', u'ك'), + ] + +def _seg_71(): + return [ + (0x1EE6B, 'X'), + (0x1EE6C, 'M', u'م'), + (0x1EE6D, 'M', u'ن'), + (0x1EE6E, 'M', u'س'), + (0x1EE6F, 'M', u'ع'), + (0x1EE70, 'M', u'ف'), + (0x1EE71, 'M', u'ص'), + (0x1EE72, 'M', u'ق'), + (0x1EE73, 'X'), + (0x1EE74, 'M', u'ش'), + (0x1EE75, 'M', u'ت'), + (0x1EE76, 'M', u'ث'), + (0x1EE77, 'M', u'خ'), + (0x1EE78, 'X'), + (0x1EE79, 'M', u'ض'), + (0x1EE7A, 'M', u'ظ'), + (0x1EE7B, 'M', u'غ'), + (0x1EE7C, 'M', u'ٮ'), + (0x1EE7D, 'X'), + (0x1EE7E, 'M', u'ڡ'), + (0x1EE7F, 'X'), + (0x1EE80, 'M', u'ا'), + (0x1EE81, 'M', u'ب'), + (0x1EE82, 'M', u'ج'), + (0x1EE83, 'M', u'د'), + (0x1EE84, 'M', u'ه'), + (0x1EE85, 'M', u'و'), + (0x1EE86, 'M', u'ز'), + (0x1EE87, 'M', u'ح'), + (0x1EE88, 'M', u'ط'), + (0x1EE89, 'M', u'ي'), + (0x1EE8A, 'X'), + (0x1EE8B, 'M', u'ل'), + (0x1EE8C, 'M', u'م'), + (0x1EE8D, 'M', u'ن'), + (0x1EE8E, 'M', u'س'), + (0x1EE8F, 'M', u'ع'), + (0x1EE90, 'M', u'ف'), + (0x1EE91, 'M', u'ص'), + (0x1EE92, 'M', u'ق'), + (0x1EE93, 'M', u'ر'), + (0x1EE94, 'M', u'ش'), + (0x1EE95, 'M', u'ت'), + (0x1EE96, 'M', u'ث'), + (0x1EE97, 'M', u'خ'), + (0x1EE98, 'M', u'ذ'), + (0x1EE99, 'M', u'ض'), + (0x1EE9A, 'M', u'ظ'), + (0x1EE9B, 'M', u'غ'), + (0x1EE9C, 'X'), + (0x1EEA1, 'M', u'ب'), + (0x1EEA2, 'M', u'ج'), + (0x1EEA3, 'M', u'د'), + (0x1EEA4, 'X'), + (0x1EEA5, 'M', u'و'), + (0x1EEA6, 'M', u'ز'), + (0x1EEA7, 'M', u'ح'), + (0x1EEA8, 'M', u'ط'), + (0x1EEA9, 'M', u'ي'), + (0x1EEAA, 'X'), + (0x1EEAB, 'M', u'ل'), + (0x1EEAC, 'M', u'م'), + (0x1EEAD, 'M', u'ن'), + (0x1EEAE, 'M', u'س'), + (0x1EEAF, 'M', u'ع'), + (0x1EEB0, 'M', u'ف'), + (0x1EEB1, 'M', u'ص'), + (0x1EEB2, 'M', u'ق'), + (0x1EEB3, 'M', u'ر'), + (0x1EEB4, 'M', u'ش'), + (0x1EEB5, 'M', u'ت'), + (0x1EEB6, 'M', u'ث'), + (0x1EEB7, 'M', u'خ'), + (0x1EEB8, 'M', u'ذ'), + (0x1EEB9, 'M', u'ض'), + (0x1EEBA, 'M', u'ظ'), + (0x1EEBB, 'M', u'غ'), + (0x1EEBC, 'X'), + (0x1EEF0, 'V'), + (0x1EEF2, 'X'), + (0x1F000, 'V'), + (0x1F02C, 'X'), + (0x1F030, 'V'), + (0x1F094, 'X'), + (0x1F0A0, 'V'), + (0x1F0AF, 'X'), + (0x1F0B1, 'V'), + (0x1F0C0, 'X'), + (0x1F0C1, 'V'), + (0x1F0D0, 'X'), + (0x1F0D1, 'V'), + (0x1F0F6, 'X'), + (0x1F101, '3', u'0,'), + (0x1F102, '3', u'1,'), + (0x1F103, '3', u'2,'), + (0x1F104, '3', u'3,'), + (0x1F105, '3', u'4,'), + (0x1F106, '3', u'5,'), + (0x1F107, '3', u'6,'), + (0x1F108, '3', u'7,'), + ] + +def _seg_72(): + return [ + (0x1F109, '3', u'8,'), + (0x1F10A, '3', u'9,'), + (0x1F10B, 'V'), + (0x1F110, '3', u'(a)'), + (0x1F111, '3', u'(b)'), + (0x1F112, '3', u'(c)'), + (0x1F113, '3', u'(d)'), + (0x1F114, '3', u'(e)'), + (0x1F115, '3', u'(f)'), + (0x1F116, '3', u'(g)'), + (0x1F117, '3', u'(h)'), + (0x1F118, '3', u'(i)'), + (0x1F119, '3', u'(j)'), + (0x1F11A, '3', u'(k)'), + (0x1F11B, '3', u'(l)'), + (0x1F11C, '3', u'(m)'), + (0x1F11D, '3', u'(n)'), + (0x1F11E, '3', u'(o)'), + (0x1F11F, '3', u'(p)'), + (0x1F120, '3', u'(q)'), + (0x1F121, '3', u'(r)'), + (0x1F122, '3', u'(s)'), + (0x1F123, '3', u'(t)'), + (0x1F124, '3', u'(u)'), + (0x1F125, '3', u'(v)'), + (0x1F126, '3', u'(w)'), + (0x1F127, '3', u'(x)'), + (0x1F128, '3', u'(y)'), + (0x1F129, '3', u'(z)'), + (0x1F12A, 'M', u'〔s〕'), + (0x1F12B, 'M', u'c'), + (0x1F12C, 'M', u'r'), + (0x1F12D, 'M', u'cd'), + (0x1F12E, 'M', u'wz'), + (0x1F12F, 'V'), + (0x1F130, 'M', u'a'), + (0x1F131, 'M', u'b'), + (0x1F132, 'M', u'c'), + (0x1F133, 'M', u'd'), + (0x1F134, 'M', u'e'), + (0x1F135, 'M', u'f'), + (0x1F136, 'M', u'g'), + (0x1F137, 'M', u'h'), + (0x1F138, 'M', u'i'), + (0x1F139, 'M', u'j'), + (0x1F13A, 'M', u'k'), + (0x1F13B, 'M', u'l'), + (0x1F13C, 'M', u'm'), + (0x1F13D, 'M', u'n'), + (0x1F13E, 'M', u'o'), + (0x1F13F, 'M', u'p'), + (0x1F140, 'M', u'q'), + (0x1F141, 'M', u'r'), + (0x1F142, 'M', u's'), + (0x1F143, 'M', u't'), + (0x1F144, 'M', u'u'), + (0x1F145, 'M', u'v'), + (0x1F146, 'M', u'w'), + (0x1F147, 'M', u'x'), + (0x1F148, 'M', u'y'), + (0x1F149, 'M', u'z'), + (0x1F14A, 'M', u'hv'), + (0x1F14B, 'M', u'mv'), + (0x1F14C, 'M', u'sd'), + (0x1F14D, 'M', u'ss'), + (0x1F14E, 'M', u'ppv'), + (0x1F14F, 'M', u'wc'), + (0x1F150, 'V'), + (0x1F16A, 'M', u'mc'), + (0x1F16B, 'M', u'md'), + (0x1F16C, 'M', u'mr'), + (0x1F16D, 'V'), + (0x1F190, 'M', u'dj'), + (0x1F191, 'V'), + (0x1F1AE, 'X'), + (0x1F1E6, 'V'), + (0x1F200, 'M', u'ほか'), + (0x1F201, 'M', u'ココ'), + (0x1F202, 'M', u'サ'), + (0x1F203, 'X'), + (0x1F210, 'M', u'手'), + (0x1F211, 'M', u'字'), + (0x1F212, 'M', u'双'), + (0x1F213, 'M', u'デ'), + (0x1F214, 'M', u'二'), + (0x1F215, 'M', u'多'), + (0x1F216, 'M', u'解'), + (0x1F217, 'M', u'天'), + (0x1F218, 'M', u'交'), + (0x1F219, 'M', u'映'), + (0x1F21A, 'M', u'無'), + (0x1F21B, 'M', u'料'), + (0x1F21C, 'M', u'前'), + (0x1F21D, 'M', u'後'), + (0x1F21E, 'M', u'再'), + (0x1F21F, 'M', u'新'), + (0x1F220, 'M', u'初'), + (0x1F221, 'M', u'終'), + (0x1F222, 'M', u'生'), + (0x1F223, 'M', u'販'), + ] + +def _seg_73(): + return [ + (0x1F224, 'M', u'声'), + (0x1F225, 'M', u'吹'), + (0x1F226, 'M', u'演'), + (0x1F227, 'M', u'投'), + (0x1F228, 'M', u'捕'), + (0x1F229, 'M', u'一'), + (0x1F22A, 'M', u'三'), + (0x1F22B, 'M', u'遊'), + (0x1F22C, 'M', u'左'), + (0x1F22D, 'M', u'中'), + (0x1F22E, 'M', u'右'), + (0x1F22F, 'M', u'指'), + (0x1F230, 'M', u'走'), + (0x1F231, 'M', u'打'), + (0x1F232, 'M', u'禁'), + (0x1F233, 'M', u'空'), + (0x1F234, 'M', u'合'), + (0x1F235, 'M', u'満'), + (0x1F236, 'M', u'有'), + (0x1F237, 'M', u'月'), + (0x1F238, 'M', u'申'), + (0x1F239, 'M', u'割'), + (0x1F23A, 'M', u'営'), + (0x1F23B, 'M', u'配'), + (0x1F23C, 'X'), + (0x1F240, 'M', u'〔本〕'), + (0x1F241, 'M', u'〔三〕'), + (0x1F242, 'M', u'〔二〕'), + (0x1F243, 'M', u'〔安〕'), + (0x1F244, 'M', u'〔点〕'), + (0x1F245, 'M', u'〔打〕'), + (0x1F246, 'M', u'〔盗〕'), + (0x1F247, 'M', u'〔勝〕'), + (0x1F248, 'M', u'〔敗〕'), + (0x1F249, 'X'), + (0x1F250, 'M', u'得'), + (0x1F251, 'M', u'可'), + (0x1F252, 'X'), + (0x1F260, 'V'), + (0x1F266, 'X'), + (0x1F300, 'V'), + (0x1F6D8, 'X'), + (0x1F6E0, 'V'), + (0x1F6ED, 'X'), + (0x1F6F0, 'V'), + (0x1F6FD, 'X'), + (0x1F700, 'V'), + (0x1F774, 'X'), + (0x1F780, 'V'), + (0x1F7D9, 'X'), + (0x1F7E0, 'V'), + (0x1F7EC, 'X'), + (0x1F800, 'V'), + (0x1F80C, 'X'), + (0x1F810, 'V'), + (0x1F848, 'X'), + (0x1F850, 'V'), + (0x1F85A, 'X'), + (0x1F860, 'V'), + (0x1F888, 'X'), + (0x1F890, 'V'), + (0x1F8AE, 'X'), + (0x1F8B0, 'V'), + (0x1F8B2, 'X'), + (0x1F900, 'V'), + (0x1F979, 'X'), + (0x1F97A, 'V'), + (0x1F9CC, 'X'), + (0x1F9CD, 'V'), + (0x1FA54, 'X'), + (0x1FA60, 'V'), + (0x1FA6E, 'X'), + (0x1FA70, 'V'), + (0x1FA75, 'X'), + (0x1FA78, 'V'), + (0x1FA7B, 'X'), + (0x1FA80, 'V'), + (0x1FA87, 'X'), + (0x1FA90, 'V'), + (0x1FAA9, 'X'), + (0x1FAB0, 'V'), + (0x1FAB7, 'X'), + (0x1FAC0, 'V'), + (0x1FAC3, 'X'), + (0x1FAD0, 'V'), + (0x1FAD7, 'X'), + (0x1FB00, 'V'), + (0x1FB93, 'X'), + (0x1FB94, 'V'), + (0x1FBCB, 'X'), + (0x1FBF0, 'M', u'0'), + (0x1FBF1, 'M', u'1'), + (0x1FBF2, 'M', u'2'), + (0x1FBF3, 'M', u'3'), + (0x1FBF4, 'M', u'4'), + (0x1FBF5, 'M', u'5'), + (0x1FBF6, 'M', u'6'), + (0x1FBF7, 'M', u'7'), + (0x1FBF8, 'M', u'8'), + (0x1FBF9, 'M', u'9'), + ] + +def _seg_74(): + return [ + (0x1FBFA, 'X'), + (0x20000, 'V'), + (0x2A6DE, 'X'), + (0x2A700, 'V'), + (0x2B735, 'X'), + (0x2B740, 'V'), + (0x2B81E, 'X'), + (0x2B820, 'V'), + (0x2CEA2, 'X'), + (0x2CEB0, 'V'), + (0x2EBE1, 'X'), + (0x2F800, 'M', u'丽'), + (0x2F801, 'M', u'丸'), + (0x2F802, 'M', u'乁'), + (0x2F803, 'M', u'𠄢'), + (0x2F804, 'M', u'你'), + (0x2F805, 'M', u'侮'), + (0x2F806, 'M', u'侻'), + (0x2F807, 'M', u'倂'), + (0x2F808, 'M', u'偺'), + (0x2F809, 'M', u'備'), + (0x2F80A, 'M', u'僧'), + (0x2F80B, 'M', u'像'), + (0x2F80C, 'M', u'㒞'), + (0x2F80D, 'M', u'𠘺'), + (0x2F80E, 'M', u'免'), + (0x2F80F, 'M', u'兔'), + (0x2F810, 'M', u'兤'), + (0x2F811, 'M', u'具'), + (0x2F812, 'M', u'𠔜'), + (0x2F813, 'M', u'㒹'), + (0x2F814, 'M', u'內'), + (0x2F815, 'M', u'再'), + (0x2F816, 'M', u'𠕋'), + (0x2F817, 'M', u'冗'), + (0x2F818, 'M', u'冤'), + (0x2F819, 'M', u'仌'), + (0x2F81A, 'M', u'冬'), + (0x2F81B, 'M', u'况'), + (0x2F81C, 'M', u'𩇟'), + (0x2F81D, 'M', u'凵'), + (0x2F81E, 'M', u'刃'), + (0x2F81F, 'M', u'㓟'), + (0x2F820, 'M', u'刻'), + (0x2F821, 'M', u'剆'), + (0x2F822, 'M', u'割'), + (0x2F823, 'M', u'剷'), + (0x2F824, 'M', u'㔕'), + (0x2F825, 'M', u'勇'), + (0x2F826, 'M', u'勉'), + (0x2F827, 'M', u'勤'), + (0x2F828, 'M', u'勺'), + (0x2F829, 'M', u'包'), + (0x2F82A, 'M', u'匆'), + (0x2F82B, 'M', u'北'), + (0x2F82C, 'M', u'卉'), + (0x2F82D, 'M', u'卑'), + (0x2F82E, 'M', u'博'), + (0x2F82F, 'M', u'即'), + (0x2F830, 'M', u'卽'), + (0x2F831, 'M', u'卿'), + (0x2F834, 'M', u'𠨬'), + (0x2F835, 'M', u'灰'), + (0x2F836, 'M', u'及'), + (0x2F837, 'M', u'叟'), + (0x2F838, 'M', u'𠭣'), + (0x2F839, 'M', u'叫'), + (0x2F83A, 'M', u'叱'), + (0x2F83B, 'M', u'吆'), + (0x2F83C, 'M', u'咞'), + (0x2F83D, 'M', u'吸'), + (0x2F83E, 'M', u'呈'), + (0x2F83F, 'M', u'周'), + (0x2F840, 'M', u'咢'), + (0x2F841, 'M', u'哶'), + (0x2F842, 'M', u'唐'), + (0x2F843, 'M', u'啓'), + (0x2F844, 'M', u'啣'), + (0x2F845, 'M', u'善'), + (0x2F847, 'M', u'喙'), + (0x2F848, 'M', u'喫'), + (0x2F849, 'M', u'喳'), + (0x2F84A, 'M', u'嗂'), + (0x2F84B, 'M', u'圖'), + (0x2F84C, 'M', u'嘆'), + (0x2F84D, 'M', u'圗'), + (0x2F84E, 'M', u'噑'), + (0x2F84F, 'M', u'噴'), + (0x2F850, 'M', u'切'), + (0x2F851, 'M', u'壮'), + (0x2F852, 'M', u'城'), + (0x2F853, 'M', u'埴'), + (0x2F854, 'M', u'堍'), + (0x2F855, 'M', u'型'), + (0x2F856, 'M', u'堲'), + (0x2F857, 'M', u'報'), + (0x2F858, 'M', u'墬'), + (0x2F859, 'M', u'𡓤'), + (0x2F85A, 'M', u'売'), + (0x2F85B, 'M', u'壷'), + ] + +def _seg_75(): + return [ + (0x2F85C, 'M', u'夆'), + (0x2F85D, 'M', u'多'), + (0x2F85E, 'M', u'夢'), + (0x2F85F, 'M', u'奢'), + (0x2F860, 'M', u'𡚨'), + (0x2F861, 'M', u'𡛪'), + (0x2F862, 'M', u'姬'), + (0x2F863, 'M', u'娛'), + (0x2F864, 'M', u'娧'), + (0x2F865, 'M', u'姘'), + (0x2F866, 'M', u'婦'), + (0x2F867, 'M', u'㛮'), + (0x2F868, 'X'), + (0x2F869, 'M', u'嬈'), + (0x2F86A, 'M', u'嬾'), + (0x2F86C, 'M', u'𡧈'), + (0x2F86D, 'M', u'寃'), + (0x2F86E, 'M', u'寘'), + (0x2F86F, 'M', u'寧'), + (0x2F870, 'M', u'寳'), + (0x2F871, 'M', u'𡬘'), + (0x2F872, 'M', u'寿'), + (0x2F873, 'M', u'将'), + (0x2F874, 'X'), + (0x2F875, 'M', u'尢'), + (0x2F876, 'M', u'㞁'), + (0x2F877, 'M', u'屠'), + (0x2F878, 'M', u'屮'), + (0x2F879, 'M', u'峀'), + (0x2F87A, 'M', u'岍'), + (0x2F87B, 'M', u'𡷤'), + (0x2F87C, 'M', u'嵃'), + (0x2F87D, 'M', u'𡷦'), + (0x2F87E, 'M', u'嵮'), + (0x2F87F, 'M', u'嵫'), + (0x2F880, 'M', u'嵼'), + (0x2F881, 'M', u'巡'), + (0x2F882, 'M', u'巢'), + (0x2F883, 'M', u'㠯'), + (0x2F884, 'M', u'巽'), + (0x2F885, 'M', u'帨'), + (0x2F886, 'M', u'帽'), + (0x2F887, 'M', u'幩'), + (0x2F888, 'M', u'㡢'), + (0x2F889, 'M', u'𢆃'), + (0x2F88A, 'M', u'㡼'), + (0x2F88B, 'M', u'庰'), + (0x2F88C, 'M', u'庳'), + (0x2F88D, 'M', u'庶'), + (0x2F88E, 'M', u'廊'), + (0x2F88F, 'M', u'𪎒'), + (0x2F890, 'M', u'廾'), + (0x2F891, 'M', u'𢌱'), + (0x2F893, 'M', u'舁'), + (0x2F894, 'M', u'弢'), + (0x2F896, 'M', u'㣇'), + (0x2F897, 'M', u'𣊸'), + (0x2F898, 'M', u'𦇚'), + (0x2F899, 'M', u'形'), + (0x2F89A, 'M', u'彫'), + (0x2F89B, 'M', u'㣣'), + (0x2F89C, 'M', u'徚'), + (0x2F89D, 'M', u'忍'), + (0x2F89E, 'M', u'志'), + (0x2F89F, 'M', u'忹'), + (0x2F8A0, 'M', u'悁'), + (0x2F8A1, 'M', u'㤺'), + (0x2F8A2, 'M', u'㤜'), + (0x2F8A3, 'M', u'悔'), + (0x2F8A4, 'M', u'𢛔'), + (0x2F8A5, 'M', u'惇'), + (0x2F8A6, 'M', u'慈'), + (0x2F8A7, 'M', u'慌'), + (0x2F8A8, 'M', u'慎'), + (0x2F8A9, 'M', u'慌'), + (0x2F8AA, 'M', u'慺'), + (0x2F8AB, 'M', u'憎'), + (0x2F8AC, 'M', u'憲'), + (0x2F8AD, 'M', u'憤'), + (0x2F8AE, 'M', u'憯'), + (0x2F8AF, 'M', u'懞'), + (0x2F8B0, 'M', u'懲'), + (0x2F8B1, 'M', u'懶'), + (0x2F8B2, 'M', u'成'), + (0x2F8B3, 'M', u'戛'), + (0x2F8B4, 'M', u'扝'), + (0x2F8B5, 'M', u'抱'), + (0x2F8B6, 'M', u'拔'), + (0x2F8B7, 'M', u'捐'), + (0x2F8B8, 'M', u'𢬌'), + (0x2F8B9, 'M', u'挽'), + (0x2F8BA, 'M', u'拼'), + (0x2F8BB, 'M', u'捨'), + (0x2F8BC, 'M', u'掃'), + (0x2F8BD, 'M', u'揤'), + (0x2F8BE, 'M', u'𢯱'), + (0x2F8BF, 'M', u'搢'), + (0x2F8C0, 'M', u'揅'), + (0x2F8C1, 'M', u'掩'), + (0x2F8C2, 'M', u'㨮'), + ] + +def _seg_76(): + return [ + (0x2F8C3, 'M', u'摩'), + (0x2F8C4, 'M', u'摾'), + (0x2F8C5, 'M', u'撝'), + (0x2F8C6, 'M', u'摷'), + (0x2F8C7, 'M', u'㩬'), + (0x2F8C8, 'M', u'敏'), + (0x2F8C9, 'M', u'敬'), + (0x2F8CA, 'M', u'𣀊'), + (0x2F8CB, 'M', u'旣'), + (0x2F8CC, 'M', u'書'), + (0x2F8CD, 'M', u'晉'), + (0x2F8CE, 'M', u'㬙'), + (0x2F8CF, 'M', u'暑'), + (0x2F8D0, 'M', u'㬈'), + (0x2F8D1, 'M', u'㫤'), + (0x2F8D2, 'M', u'冒'), + (0x2F8D3, 'M', u'冕'), + (0x2F8D4, 'M', u'最'), + (0x2F8D5, 'M', u'暜'), + (0x2F8D6, 'M', u'肭'), + (0x2F8D7, 'M', u'䏙'), + (0x2F8D8, 'M', u'朗'), + (0x2F8D9, 'M', u'望'), + (0x2F8DA, 'M', u'朡'), + (0x2F8DB, 'M', u'杞'), + (0x2F8DC, 'M', u'杓'), + (0x2F8DD, 'M', u'𣏃'), + (0x2F8DE, 'M', u'㭉'), + (0x2F8DF, 'M', u'柺'), + (0x2F8E0, 'M', u'枅'), + (0x2F8E1, 'M', u'桒'), + (0x2F8E2, 'M', u'梅'), + (0x2F8E3, 'M', u'𣑭'), + (0x2F8E4, 'M', u'梎'), + (0x2F8E5, 'M', u'栟'), + (0x2F8E6, 'M', u'椔'), + (0x2F8E7, 'M', u'㮝'), + (0x2F8E8, 'M', u'楂'), + (0x2F8E9, 'M', u'榣'), + (0x2F8EA, 'M', u'槪'), + (0x2F8EB, 'M', u'檨'), + (0x2F8EC, 'M', u'𣚣'), + (0x2F8ED, 'M', u'櫛'), + (0x2F8EE, 'M', u'㰘'), + (0x2F8EF, 'M', u'次'), + (0x2F8F0, 'M', u'𣢧'), + (0x2F8F1, 'M', u'歔'), + (0x2F8F2, 'M', u'㱎'), + (0x2F8F3, 'M', u'歲'), + (0x2F8F4, 'M', u'殟'), + (0x2F8F5, 'M', u'殺'), + (0x2F8F6, 'M', u'殻'), + (0x2F8F7, 'M', u'𣪍'), + (0x2F8F8, 'M', u'𡴋'), + (0x2F8F9, 'M', u'𣫺'), + (0x2F8FA, 'M', u'汎'), + (0x2F8FB, 'M', u'𣲼'), + (0x2F8FC, 'M', u'沿'), + (0x2F8FD, 'M', u'泍'), + (0x2F8FE, 'M', u'汧'), + (0x2F8FF, 'M', u'洖'), + (0x2F900, 'M', u'派'), + (0x2F901, 'M', u'海'), + (0x2F902, 'M', u'流'), + (0x2F903, 'M', u'浩'), + (0x2F904, 'M', u'浸'), + (0x2F905, 'M', u'涅'), + (0x2F906, 'M', u'𣴞'), + (0x2F907, 'M', u'洴'), + (0x2F908, 'M', u'港'), + (0x2F909, 'M', u'湮'), + (0x2F90A, 'M', u'㴳'), + (0x2F90B, 'M', u'滋'), + (0x2F90C, 'M', u'滇'), + (0x2F90D, 'M', u'𣻑'), + (0x2F90E, 'M', u'淹'), + (0x2F90F, 'M', u'潮'), + (0x2F910, 'M', u'𣽞'), + (0x2F911, 'M', u'𣾎'), + (0x2F912, 'M', u'濆'), + (0x2F913, 'M', u'瀹'), + (0x2F914, 'M', u'瀞'), + (0x2F915, 'M', u'瀛'), + (0x2F916, 'M', u'㶖'), + (0x2F917, 'M', u'灊'), + (0x2F918, 'M', u'災'), + (0x2F919, 'M', u'灷'), + (0x2F91A, 'M', u'炭'), + (0x2F91B, 'M', u'𠔥'), + (0x2F91C, 'M', u'煅'), + (0x2F91D, 'M', u'𤉣'), + (0x2F91E, 'M', u'熜'), + (0x2F91F, 'X'), + (0x2F920, 'M', u'爨'), + (0x2F921, 'M', u'爵'), + (0x2F922, 'M', u'牐'), + (0x2F923, 'M', u'𤘈'), + (0x2F924, 'M', u'犀'), + (0x2F925, 'M', u'犕'), + (0x2F926, 'M', u'𤜵'), + ] + +def _seg_77(): + return [ + (0x2F927, 'M', u'𤠔'), + (0x2F928, 'M', u'獺'), + (0x2F929, 'M', u'王'), + (0x2F92A, 'M', u'㺬'), + (0x2F92B, 'M', u'玥'), + (0x2F92C, 'M', u'㺸'), + (0x2F92E, 'M', u'瑇'), + (0x2F92F, 'M', u'瑜'), + (0x2F930, 'M', u'瑱'), + (0x2F931, 'M', u'璅'), + (0x2F932, 'M', u'瓊'), + (0x2F933, 'M', u'㼛'), + (0x2F934, 'M', u'甤'), + (0x2F935, 'M', u'𤰶'), + (0x2F936, 'M', u'甾'), + (0x2F937, 'M', u'𤲒'), + (0x2F938, 'M', u'異'), + (0x2F939, 'M', u'𢆟'), + (0x2F93A, 'M', u'瘐'), + (0x2F93B, 'M', u'𤾡'), + (0x2F93C, 'M', u'𤾸'), + (0x2F93D, 'M', u'𥁄'), + (0x2F93E, 'M', u'㿼'), + (0x2F93F, 'M', u'䀈'), + (0x2F940, 'M', u'直'), + (0x2F941, 'M', u'𥃳'), + (0x2F942, 'M', u'𥃲'), + (0x2F943, 'M', u'𥄙'), + (0x2F944, 'M', u'𥄳'), + (0x2F945, 'M', u'眞'), + (0x2F946, 'M', u'真'), + (0x2F948, 'M', u'睊'), + (0x2F949, 'M', u'䀹'), + (0x2F94A, 'M', u'瞋'), + (0x2F94B, 'M', u'䁆'), + (0x2F94C, 'M', u'䂖'), + (0x2F94D, 'M', u'𥐝'), + (0x2F94E, 'M', u'硎'), + (0x2F94F, 'M', u'碌'), + (0x2F950, 'M', u'磌'), + (0x2F951, 'M', u'䃣'), + (0x2F952, 'M', u'𥘦'), + (0x2F953, 'M', u'祖'), + (0x2F954, 'M', u'𥚚'), + (0x2F955, 'M', u'𥛅'), + (0x2F956, 'M', u'福'), + (0x2F957, 'M', u'秫'), + (0x2F958, 'M', u'䄯'), + (0x2F959, 'M', u'穀'), + (0x2F95A, 'M', u'穊'), + (0x2F95B, 'M', u'穏'), + (0x2F95C, 'M', u'𥥼'), + (0x2F95D, 'M', u'𥪧'), + (0x2F95F, 'X'), + (0x2F960, 'M', u'䈂'), + (0x2F961, 'M', u'𥮫'), + (0x2F962, 'M', u'篆'), + (0x2F963, 'M', u'築'), + (0x2F964, 'M', u'䈧'), + (0x2F965, 'M', u'𥲀'), + (0x2F966, 'M', u'糒'), + (0x2F967, 'M', u'䊠'), + (0x2F968, 'M', u'糨'), + (0x2F969, 'M', u'糣'), + (0x2F96A, 'M', u'紀'), + (0x2F96B, 'M', u'𥾆'), + (0x2F96C, 'M', u'絣'), + (0x2F96D, 'M', u'䌁'), + (0x2F96E, 'M', u'緇'), + (0x2F96F, 'M', u'縂'), + (0x2F970, 'M', u'繅'), + (0x2F971, 'M', u'䌴'), + (0x2F972, 'M', u'𦈨'), + (0x2F973, 'M', u'𦉇'), + (0x2F974, 'M', u'䍙'), + (0x2F975, 'M', u'𦋙'), + (0x2F976, 'M', u'罺'), + (0x2F977, 'M', u'𦌾'), + (0x2F978, 'M', u'羕'), + (0x2F979, 'M', u'翺'), + (0x2F97A, 'M', u'者'), + (0x2F97B, 'M', u'𦓚'), + (0x2F97C, 'M', u'𦔣'), + (0x2F97D, 'M', u'聠'), + (0x2F97E, 'M', u'𦖨'), + (0x2F97F, 'M', u'聰'), + (0x2F980, 'M', u'𣍟'), + (0x2F981, 'M', u'䏕'), + (0x2F982, 'M', u'育'), + (0x2F983, 'M', u'脃'), + (0x2F984, 'M', u'䐋'), + (0x2F985, 'M', u'脾'), + (0x2F986, 'M', u'媵'), + (0x2F987, 'M', u'𦞧'), + (0x2F988, 'M', u'𦞵'), + (0x2F989, 'M', u'𣎓'), + (0x2F98A, 'M', u'𣎜'), + (0x2F98B, 'M', u'舁'), + (0x2F98C, 'M', u'舄'), + (0x2F98D, 'M', u'辞'), + ] + +def _seg_78(): + return [ + (0x2F98E, 'M', u'䑫'), + (0x2F98F, 'M', u'芑'), + (0x2F990, 'M', u'芋'), + (0x2F991, 'M', u'芝'), + (0x2F992, 'M', u'劳'), + (0x2F993, 'M', u'花'), + (0x2F994, 'M', u'芳'), + (0x2F995, 'M', u'芽'), + (0x2F996, 'M', u'苦'), + (0x2F997, 'M', u'𦬼'), + (0x2F998, 'M', u'若'), + (0x2F999, 'M', u'茝'), + (0x2F99A, 'M', u'荣'), + (0x2F99B, 'M', u'莭'), + (0x2F99C, 'M', u'茣'), + (0x2F99D, 'M', u'莽'), + (0x2F99E, 'M', u'菧'), + (0x2F99F, 'M', u'著'), + (0x2F9A0, 'M', u'荓'), + (0x2F9A1, 'M', u'菊'), + (0x2F9A2, 'M', u'菌'), + (0x2F9A3, 'M', u'菜'), + (0x2F9A4, 'M', u'𦰶'), + (0x2F9A5, 'M', u'𦵫'), + (0x2F9A6, 'M', u'𦳕'), + (0x2F9A7, 'M', u'䔫'), + (0x2F9A8, 'M', u'蓱'), + (0x2F9A9, 'M', u'蓳'), + (0x2F9AA, 'M', u'蔖'), + (0x2F9AB, 'M', u'𧏊'), + (0x2F9AC, 'M', u'蕤'), + (0x2F9AD, 'M', u'𦼬'), + (0x2F9AE, 'M', u'䕝'), + (0x2F9AF, 'M', u'䕡'), + (0x2F9B0, 'M', u'𦾱'), + (0x2F9B1, 'M', u'𧃒'), + (0x2F9B2, 'M', u'䕫'), + (0x2F9B3, 'M', u'虐'), + (0x2F9B4, 'M', u'虜'), + (0x2F9B5, 'M', u'虧'), + (0x2F9B6, 'M', u'虩'), + (0x2F9B7, 'M', u'蚩'), + (0x2F9B8, 'M', u'蚈'), + (0x2F9B9, 'M', u'蜎'), + (0x2F9BA, 'M', u'蛢'), + (0x2F9BB, 'M', u'蝹'), + (0x2F9BC, 'M', u'蜨'), + (0x2F9BD, 'M', u'蝫'), + (0x2F9BE, 'M', u'螆'), + (0x2F9BF, 'X'), + (0x2F9C0, 'M', u'蟡'), + (0x2F9C1, 'M', u'蠁'), + (0x2F9C2, 'M', u'䗹'), + (0x2F9C3, 'M', u'衠'), + (0x2F9C4, 'M', u'衣'), + (0x2F9C5, 'M', u'𧙧'), + (0x2F9C6, 'M', u'裗'), + (0x2F9C7, 'M', u'裞'), + (0x2F9C8, 'M', u'䘵'), + (0x2F9C9, 'M', u'裺'), + (0x2F9CA, 'M', u'㒻'), + (0x2F9CB, 'M', u'𧢮'), + (0x2F9CC, 'M', u'𧥦'), + (0x2F9CD, 'M', u'䚾'), + (0x2F9CE, 'M', u'䛇'), + (0x2F9CF, 'M', u'誠'), + (0x2F9D0, 'M', u'諭'), + (0x2F9D1, 'M', u'變'), + (0x2F9D2, 'M', u'豕'), + (0x2F9D3, 'M', u'𧲨'), + (0x2F9D4, 'M', u'貫'), + (0x2F9D5, 'M', u'賁'), + (0x2F9D6, 'M', u'贛'), + (0x2F9D7, 'M', u'起'), + (0x2F9D8, 'M', u'𧼯'), + (0x2F9D9, 'M', u'𠠄'), + (0x2F9DA, 'M', u'跋'), + (0x2F9DB, 'M', u'趼'), + (0x2F9DC, 'M', u'跰'), + (0x2F9DD, 'M', u'𠣞'), + (0x2F9DE, 'M', u'軔'), + (0x2F9DF, 'M', u'輸'), + (0x2F9E0, 'M', u'𨗒'), + (0x2F9E1, 'M', u'𨗭'), + (0x2F9E2, 'M', u'邔'), + (0x2F9E3, 'M', u'郱'), + (0x2F9E4, 'M', u'鄑'), + (0x2F9E5, 'M', u'𨜮'), + (0x2F9E6, 'M', u'鄛'), + (0x2F9E7, 'M', u'鈸'), + (0x2F9E8, 'M', u'鋗'), + (0x2F9E9, 'M', u'鋘'), + (0x2F9EA, 'M', u'鉼'), + (0x2F9EB, 'M', u'鏹'), + (0x2F9EC, 'M', u'鐕'), + (0x2F9ED, 'M', u'𨯺'), + (0x2F9EE, 'M', u'開'), + (0x2F9EF, 'M', u'䦕'), + (0x2F9F0, 'M', u'閷'), + (0x2F9F1, 'M', u'𨵷'), + ] + +def _seg_79(): + return [ + (0x2F9F2, 'M', u'䧦'), + (0x2F9F3, 'M', u'雃'), + (0x2F9F4, 'M', u'嶲'), + (0x2F9F5, 'M', u'霣'), + (0x2F9F6, 'M', u'𩅅'), + (0x2F9F7, 'M', u'𩈚'), + (0x2F9F8, 'M', u'䩮'), + (0x2F9F9, 'M', u'䩶'), + (0x2F9FA, 'M', u'韠'), + (0x2F9FB, 'M', u'𩐊'), + (0x2F9FC, 'M', u'䪲'), + (0x2F9FD, 'M', u'𩒖'), + (0x2F9FE, 'M', u'頋'), + (0x2FA00, 'M', u'頩'), + (0x2FA01, 'M', u'𩖶'), + (0x2FA02, 'M', u'飢'), + (0x2FA03, 'M', u'䬳'), + (0x2FA04, 'M', u'餩'), + (0x2FA05, 'M', u'馧'), + (0x2FA06, 'M', u'駂'), + (0x2FA07, 'M', u'駾'), + (0x2FA08, 'M', u'䯎'), + (0x2FA09, 'M', u'𩬰'), + (0x2FA0A, 'M', u'鬒'), + (0x2FA0B, 'M', u'鱀'), + (0x2FA0C, 'M', u'鳽'), + (0x2FA0D, 'M', u'䳎'), + (0x2FA0E, 'M', u'䳭'), + (0x2FA0F, 'M', u'鵧'), + (0x2FA10, 'M', u'𪃎'), + (0x2FA11, 'M', u'䳸'), + (0x2FA12, 'M', u'𪄅'), + (0x2FA13, 'M', u'𪈎'), + (0x2FA14, 'M', u'𪊑'), + (0x2FA15, 'M', u'麻'), + (0x2FA16, 'M', u'䵖'), + (0x2FA17, 'M', u'黹'), + (0x2FA18, 'M', u'黾'), + (0x2FA19, 'M', u'鼅'), + (0x2FA1A, 'M', u'鼏'), + (0x2FA1B, 'M', u'鼖'), + (0x2FA1C, 'M', u'鼻'), + (0x2FA1D, 'M', u'𪘀'), + (0x2FA1E, 'X'), + (0x30000, 'V'), + (0x3134B, 'X'), + (0xE0100, 'I'), + (0xE01F0, 'X'), + ] + +uts46data = tuple( + _seg_0() + + _seg_1() + + _seg_2() + + _seg_3() + + _seg_4() + + _seg_5() + + _seg_6() + + _seg_7() + + _seg_8() + + _seg_9() + + _seg_10() + + _seg_11() + + _seg_12() + + _seg_13() + + _seg_14() + + _seg_15() + + _seg_16() + + _seg_17() + + _seg_18() + + _seg_19() + + _seg_20() + + _seg_21() + + _seg_22() + + _seg_23() + + _seg_24() + + _seg_25() + + _seg_26() + + _seg_27() + + _seg_28() + + _seg_29() + + _seg_30() + + _seg_31() + + _seg_32() + + _seg_33() + + _seg_34() + + _seg_35() + + _seg_36() + + _seg_37() + + _seg_38() + + _seg_39() + + _seg_40() + + _seg_41() + + _seg_42() + + _seg_43() + + _seg_44() + + _seg_45() + + _seg_46() + + _seg_47() + + _seg_48() + + _seg_49() + + _seg_50() + + _seg_51() + + _seg_52() + + _seg_53() + + _seg_54() + + _seg_55() + + _seg_56() + + _seg_57() + + _seg_58() + + _seg_59() + + _seg_60() + + _seg_61() + + _seg_62() + + _seg_63() + + _seg_64() + + _seg_65() + + _seg_66() + + _seg_67() + + _seg_68() + + _seg_69() + + _seg_70() + + _seg_71() + + _seg_72() + + _seg_73() + + _seg_74() + + _seg_75() + + _seg_76() + + _seg_77() + + _seg_78() + + _seg_79() +) diff --git a/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/INSTALLER b/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/LICENSE.txt b/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/LICENSE.txt new file mode 100644 index 0000000..737fec5 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/LICENSE.txt @@ -0,0 +1,20 @@ +Copyright (c) 2008-2019 The pip developers (see AUTHORS.txt file) + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/METADATA b/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/METADATA new file mode 100644 index 0000000..1413a04 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/METADATA @@ -0,0 +1,87 @@ +Metadata-Version: 2.1 +Name: pip +Version: 20.1.1 +Summary: The PyPA recommended tool for installing Python packages. +Home-page: https://pip.pypa.io/ +Author: The pip developers +Author-email: pypa-dev@groups.google.com +License: MIT +Project-URL: Documentation, https://pip.pypa.io +Project-URL: Source, https://github.com/pypa/pip +Keywords: distutils easy_install egg setuptools wheel virtualenv +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Topic :: Software Development :: Build Tools +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 :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Requires-Python: >=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.* + +pip - The Python Package Installer +================================== + +.. image:: https://img.shields.io/pypi/v/pip.svg + :target: https://pypi.org/project/pip/ + +.. image:: https://readthedocs.org/projects/pip/badge/?version=latest + :target: https://pip.pypa.io/en/latest + +pip is the `package installer`_ for Python. You can use pip to install packages from the `Python Package Index`_ and other indexes. + +Please take a look at our documentation for how to install and use pip: + +* `Installation`_ +* `Usage`_ + +We release updates regularly, with a new version every 3 months. Find more details in our documentation: + +* `Release notes`_ +* `Release process`_ + +In 2020, we're working on improvements to the heart of pip. Please `learn more and take our survey`_ to help us do it right. + +If you find bugs, need help, or want to talk to the developers, please use our mailing lists or chat rooms: + +* `Issue tracking`_ +* `Discourse channel`_ +* `User IRC`_ + +If you want to get involved head over to GitHub to get the source code, look at our development documentation and feel free to jump on the developer mailing lists and chat rooms: + +* `GitHub page`_ +* `Development documentation`_ +* `Development mailing list`_ +* `Development IRC`_ + +Code of Conduct +--------------- + +Everyone interacting in the pip project's codebases, issue trackers, chat +rooms, and mailing lists is expected to follow the `PyPA Code of Conduct`_. + +.. _package installer: https://packaging.python.org/guides/tool-recommendations/ +.. _Python Package Index: https://pypi.org +.. _Installation: https://pip.pypa.io/en/stable/installing.html +.. _Usage: https://pip.pypa.io/en/stable/ +.. _Release notes: https://pip.pypa.io/en/stable/news.html +.. _Release process: https://pip.pypa.io/en/latest/development/release-process/ +.. _GitHub page: https://github.com/pypa/pip +.. _Development documentation: https://pip.pypa.io/en/latest/development +.. _learn more and take our survey: https://pyfound.blogspot.com/2020/03/new-pip-resolver-to-roll-out-this-year.html +.. _Issue tracking: https://github.com/pypa/pip/issues +.. _Discourse channel: https://discuss.python.org/c/packaging +.. _Development mailing list: https://groups.google.com/forum/#!forum/pypa-dev +.. _User IRC: https://webchat.freenode.net/?channels=%23pypa +.. _Development IRC: https://webchat.freenode.net/?channels=%23pypa-dev +.. _PyPA Code of Conduct: https://www.pypa.io/en/latest/code-of-conduct/ + + diff --git a/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/RECORD b/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/RECORD new file mode 100644 index 0000000..f1a4bc9 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/RECORD @@ -0,0 +1,272 @@ +../../../bin/pip,sha256=8la4mTr7BY9yuqHo7raN_MZEVPRXD8ILt6zG5VmCPcU,256 +../../../bin/pip3,sha256=8la4mTr7BY9yuqHo7raN_MZEVPRXD8ILt6zG5VmCPcU,256 +../../../bin/pip3.8,sha256=8la4mTr7BY9yuqHo7raN_MZEVPRXD8ILt6zG5VmCPcU,256 +pip-20.1.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +pip-20.1.1.dist-info/LICENSE.txt,sha256=W6Ifuwlk-TatfRU2LR7W1JMcyMj5_y1NkRkOEJvnRDE,1090 +pip-20.1.1.dist-info/METADATA,sha256=dwRFheMvgIBpyZllM4tVlf5TfjoXc1ZxlsJf0ze61_M,3634 +pip-20.1.1.dist-info/RECORD,, +pip-20.1.1.dist-info/WHEEL,sha256=kGT74LWyRUZrL4VgLh6_g12IeVl_9u9ZVhadrgXZUEY,110 +pip-20.1.1.dist-info/entry_points.txt,sha256=HtfDOwpUlr9s73jqLQ6wF9V0_0qvUXJwCBz7Vwx0Ue0,125 +pip-20.1.1.dist-info/top_level.txt,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +pip/__init__.py,sha256=9lnkMA2mCKfgnTkqep7tMbosgEJ4rENcyu2tcqDwUNw,455 +pip/__main__.py,sha256=bqCAM1cj1HwHCDx3WJa-LJxOBXimGxE8OjBqAvnhVg0,911 +pip/__pycache__/__init__.cpython-38.pyc,, +pip/__pycache__/__main__.cpython-38.pyc,, +pip/_internal/__init__.py,sha256=2si23JBW1erg19xIJ8CD6tfGknz0ijtXmzuXjGfGMGE,495 +pip/_internal/__pycache__/__init__.cpython-38.pyc,, +pip/_internal/__pycache__/build_env.cpython-38.pyc,, +pip/_internal/__pycache__/cache.cpython-38.pyc,, +pip/_internal/__pycache__/configuration.cpython-38.pyc,, +pip/_internal/__pycache__/exceptions.cpython-38.pyc,, +pip/_internal/__pycache__/locations.cpython-38.pyc,, +pip/_internal/__pycache__/main.cpython-38.pyc,, +pip/_internal/__pycache__/pyproject.cpython-38.pyc,, +pip/_internal/__pycache__/self_outdated_check.cpython-38.pyc,, +pip/_internal/__pycache__/wheel_builder.cpython-38.pyc,, +pip/_internal/build_env.py,sha256=2P0xaKpDhEfrA5P7cXnbx9QpL52Hc1Uturp8EIcjGRg,7506 +pip/_internal/cache.py,sha256=aXPdcihRKQVH26jl1cxSKTmTnV0_hNMs7cGADMUFi1Y,12334 +pip/_internal/cli/__init__.py,sha256=FkHBgpxxb-_gd6r1FjnNhfMOzAUYyXoXKJ6abijfcFU,132 +pip/_internal/cli/__pycache__/__init__.cpython-38.pyc,, +pip/_internal/cli/__pycache__/autocompletion.cpython-38.pyc,, +pip/_internal/cli/__pycache__/base_command.cpython-38.pyc,, +pip/_internal/cli/__pycache__/cmdoptions.cpython-38.pyc,, +pip/_internal/cli/__pycache__/command_context.cpython-38.pyc,, +pip/_internal/cli/__pycache__/main.cpython-38.pyc,, +pip/_internal/cli/__pycache__/main_parser.cpython-38.pyc,, +pip/_internal/cli/__pycache__/parser.cpython-38.pyc,, +pip/_internal/cli/__pycache__/progress_bars.cpython-38.pyc,, +pip/_internal/cli/__pycache__/req_command.cpython-38.pyc,, +pip/_internal/cli/__pycache__/spinners.cpython-38.pyc,, +pip/_internal/cli/__pycache__/status_codes.cpython-38.pyc,, +pip/_internal/cli/autocompletion.py,sha256=ekGNtcDI0p7rFVc-7s4T9Tbss4Jgb7vsB649XJIblRg,6547 +pip/_internal/cli/base_command.py,sha256=O5fT5HHfc_UYNvhqK0rjfh_13K3fIVQzcKUF4xKbFts,8024 +pip/_internal/cli/cmdoptions.py,sha256=6m_aB70I097DJygO3Uh065ow5Mq1XKsGX-WozPoVX7I,28402 +pip/_internal/cli/command_context.py,sha256=ygMVoTy2jpNilKT-6416gFSQpaBtrKRBbVbi2fy__EU,975 +pip/_internal/cli/main.py,sha256=Hxc9dZyW3xiDsYZX-_J2cGXT5DWNLNn_Y7o9oUme-Ec,2616 +pip/_internal/cli/main_parser.py,sha256=voAtjo4WVPIYeu7Fqabva9SXaB3BjG0gH93GBfe6jHQ,2843 +pip/_internal/cli/parser.py,sha256=4FfwW8xB84CrkLs35ud90ZkhCcWyVkx17XD6j3XCW7c,9480 +pip/_internal/cli/progress_bars.py,sha256=WtKOHkePvHwnlhDUotAmKpjBH6hBdVTOnxSiiuCC2l8,9031 +pip/_internal/cli/req_command.py,sha256=NajtG3IfB3YkiM7LANLttyJTfPtgB-3CTErY0YR0k50,15309 +pip/_internal/cli/spinners.py,sha256=PS9s53LB5aDPelIn8FhKerK3bOdgeefFH5wSWJ2PCzI,5509 +pip/_internal/cli/status_codes.py,sha256=F6uDG6Gj7RNKQJUDnd87QKqI16Us-t-B0wPF_4QMpWc,156 +pip/_internal/commands/__init__.py,sha256=yoLAnmEXjoQgYfDuwsuWG3RzzD19oeHobGEhmpIYsB4,4100 +pip/_internal/commands/__pycache__/__init__.cpython-38.pyc,, +pip/_internal/commands/__pycache__/cache.cpython-38.pyc,, +pip/_internal/commands/__pycache__/check.cpython-38.pyc,, +pip/_internal/commands/__pycache__/completion.cpython-38.pyc,, +pip/_internal/commands/__pycache__/configuration.cpython-38.pyc,, +pip/_internal/commands/__pycache__/debug.cpython-38.pyc,, +pip/_internal/commands/__pycache__/download.cpython-38.pyc,, +pip/_internal/commands/__pycache__/freeze.cpython-38.pyc,, +pip/_internal/commands/__pycache__/hash.cpython-38.pyc,, +pip/_internal/commands/__pycache__/help.cpython-38.pyc,, +pip/_internal/commands/__pycache__/install.cpython-38.pyc,, +pip/_internal/commands/__pycache__/list.cpython-38.pyc,, +pip/_internal/commands/__pycache__/search.cpython-38.pyc,, +pip/_internal/commands/__pycache__/show.cpython-38.pyc,, +pip/_internal/commands/__pycache__/uninstall.cpython-38.pyc,, +pip/_internal/commands/__pycache__/wheel.cpython-38.pyc,, +pip/_internal/commands/cache.py,sha256=LZCLVEYCr5Ugh81Zt07Hz5v6SIt0QQzr2-npj3M44aE,5676 +pip/_internal/commands/check.py,sha256=fqRrz2uKPC8Qsx2rgLygAD2Rbr-qxp1Q55zUoyZzB9Q,1677 +pip/_internal/commands/completion.py,sha256=BoEW3RZQZhsZe5to1aOe245dcBLkf-PTCJL7_u9A-Es,2957 +pip/_internal/commands/configuration.py,sha256=y74Vl2p41dBOE2NwUzW4YqnbGbl9r0lsCyBlHguDAWA,7206 +pip/_internal/commands/debug.py,sha256=e02Tb4jG7RhyrxTjCRGo8J-Oy92Y7AhXp8L9JYJUj5w,8153 +pip/_internal/commands/download.py,sha256=thDfHi0qY6DQ_1GkYPTutwta3tA0RaHJhKycepC4FgA,4740 +pip/_internal/commands/freeze.py,sha256=gtUPVHnJ2qyx1o8E6e1ZkMTRzk8rGD6YJI1olILEYC4,3359 +pip/_internal/commands/hash.py,sha256=KckEd5FeomfsRgZmRzhJRPYSsz-HXbFZGNdrzp12ftQ,1742 +pip/_internal/commands/help.py,sha256=s8bDMJbRVxs9ehLKuD4mXTsv1bTRapy1jDwaTCE90qw,1193 +pip/_internal/commands/install.py,sha256=kKjVLbM30lHb2QmDvTyVHm3RGybaZyGTdE4AESPrd9k,26464 +pip/_internal/commands/list.py,sha256=QKQt4z9hVYYxU7vwHGubR2in2cuS_K-alUvC5WGUJ7s,10238 +pip/_internal/commands/search.py,sha256=KjAz-s9mwkiLfDd-cpQO3pL6KFoOyl1RKlvxnJj3zz8,5191 +pip/_internal/commands/show.py,sha256=RqSX_KvzcZWz1gxIOZEnnk4-VeSkNvr0yWz5jF6JrcY,6791 +pip/_internal/commands/uninstall.py,sha256=D2Otze7J-RJvjfozRq2Yon9NKJrg4cbBGFuXyEwBMR0,3202 +pip/_internal/commands/wheel.py,sha256=oxyo51V1m_Hu4U-HCS53vBx5-82Q6GOhn1doOgAr3KE,6431 +pip/_internal/configuration.py,sha256=k3Y3HMMMm_fzNqX75QoNuHvjX8tplmNBuIJJpDHmf9M,14349 +pip/_internal/distributions/__init__.py,sha256=ECBUW5Gtu9TjJwyFLvim-i6kUMYVuikNh9I5asL6tbA,959 +pip/_internal/distributions/__pycache__/__init__.cpython-38.pyc,, +pip/_internal/distributions/__pycache__/base.cpython-38.pyc,, +pip/_internal/distributions/__pycache__/installed.cpython-38.pyc,, +pip/_internal/distributions/__pycache__/sdist.cpython-38.pyc,, +pip/_internal/distributions/__pycache__/wheel.cpython-38.pyc,, +pip/_internal/distributions/base.py,sha256=ruprpM_L2T2HNi3KLUHlbHimZ1sWVw-3Q0Lb8O7TDAI,1425 +pip/_internal/distributions/installed.py,sha256=YqlkBKr6TVP1MAYS6SG8ojud21wVOYLMZ8jMLJe9MSU,760 +pip/_internal/distributions/sdist.py,sha256=D4XTMlCwgPlK69l62GLYkNSVTVe99fR5iAcVt2EbGok,4086 +pip/_internal/distributions/wheel.py,sha256=95uD-TfaYoq3KiKBdzk9YMN4RRqJ28LNoSTS2K46gek,1294 +pip/_internal/exceptions.py,sha256=B3tSkzheqSfGoGt5OcAOhLhfnWWMzfJ60URvZWwkwHw,10308 +pip/_internal/index/__init__.py,sha256=vpt-JeTZefh8a-FC22ZeBSXFVbuBcXSGiILhQZJaNpQ,30 +pip/_internal/index/__pycache__/__init__.cpython-38.pyc,, +pip/_internal/index/__pycache__/collector.cpython-38.pyc,, +pip/_internal/index/__pycache__/package_finder.cpython-38.pyc,, +pip/_internal/index/collector.py,sha256=tFpQdkBlbNzdwlep7a5_o9unymgWuEmo2WtARsagiao,21547 +pip/_internal/index/package_finder.py,sha256=2Uq4RPSRboyRPj1Zp3-SB8ZFNLAEMrZv6G2yH-wVjIA,37676 +pip/_internal/locations.py,sha256=vXf8886o1_lUY3jnT-0RMG1Puo64TgiuMIzccVawP4A,6873 +pip/_internal/main.py,sha256=IVBnUQ-FG7DK6617uEXRB5_QJqspAsBFmTmTesYkbdQ,437 +pip/_internal/models/__init__.py,sha256=3DHUd_qxpPozfzouoqa9g9ts1Czr5qaHfFxbnxriepM,63 +pip/_internal/models/__pycache__/__init__.cpython-38.pyc,, +pip/_internal/models/__pycache__/candidate.cpython-38.pyc,, +pip/_internal/models/__pycache__/direct_url.cpython-38.pyc,, +pip/_internal/models/__pycache__/format_control.cpython-38.pyc,, +pip/_internal/models/__pycache__/index.cpython-38.pyc,, +pip/_internal/models/__pycache__/link.cpython-38.pyc,, +pip/_internal/models/__pycache__/scheme.cpython-38.pyc,, +pip/_internal/models/__pycache__/search_scope.cpython-38.pyc,, +pip/_internal/models/__pycache__/selection_prefs.cpython-38.pyc,, +pip/_internal/models/__pycache__/target_python.cpython-38.pyc,, +pip/_internal/models/__pycache__/wheel.cpython-38.pyc,, +pip/_internal/models/candidate.py,sha256=Y58Bcm6oXUj0iS-yhmerlGo5CQJI2p0Ww9h6hR9zQDw,1150 +pip/_internal/models/direct_url.py,sha256=MnBLPci1hE9Ndh6d3m0LAqB7hX3ci80CCJTE5eerFaQ,6900 +pip/_internal/models/format_control.py,sha256=ICzVjjGwfZYdX-eLLKHjMHLutEJlAGpfj09OG_eMqac,2673 +pip/_internal/models/index.py,sha256=K59A8-hVhBM20Xkahr4dTwP7OjkJyEqXH11UwHFVgqM,1060 +pip/_internal/models/link.py,sha256=KobEaGViwOzyPBD7kgzpGqyrQfh5zjlonOStCGAhl2U,7302 +pip/_internal/models/scheme.py,sha256=vvhBrrno7eVDXcdKHiZWwxhPHf4VG5uSCEkC0QDR2RU,679 +pip/_internal/models/search_scope.py,sha256=AYbFyfEen5cx0kRZTMgUWUxzcMr5nDk32MO4S67Ror4,4712 +pip/_internal/models/selection_prefs.py,sha256=rPeif2KKjhTPXeMoQYffjqh10oWpXhdkxRDaPT1HO8k,1908 +pip/_internal/models/target_python.py,sha256=bbOSwPmojPMtCW6i2XMNjVJzt_2GQYfx3FcGQY8pL44,3842 +pip/_internal/models/wheel.py,sha256=FTfzVb4WIbfIehxhdlAVvCil_MQ0-W44oyN56cE6NHc,2772 +pip/_internal/network/__init__.py,sha256=jf6Tt5nV_7zkARBrKojIXItgejvoegVJVKUbhAa5Ioc,50 +pip/_internal/network/__pycache__/__init__.cpython-38.pyc,, +pip/_internal/network/__pycache__/auth.cpython-38.pyc,, +pip/_internal/network/__pycache__/cache.cpython-38.pyc,, +pip/_internal/network/__pycache__/download.cpython-38.pyc,, +pip/_internal/network/__pycache__/session.cpython-38.pyc,, +pip/_internal/network/__pycache__/utils.cpython-38.pyc,, +pip/_internal/network/__pycache__/xmlrpc.cpython-38.pyc,, +pip/_internal/network/auth.py,sha256=HJg5peC3gL44H7pmZhCPnu2MrwpAalOSF7d1jmNDqt8,11125 +pip/_internal/network/cache.py,sha256=51CExcRkXWrgMZ7WsrZ6cmijKfViD5tVgKbBvJHO1IE,2394 +pip/_internal/network/download.py,sha256=MIisedL1oFOSrYAN119HDlIuFfw6eL6CNY7oJhHIzUc,6269 +pip/_internal/network/session.py,sha256=Zs0uiyPxTpfpgSv-ZI9hK9TjasmTplBuBivOTcUiJME,15208 +pip/_internal/network/utils.py,sha256=iiixo1OeaQ3niUWiBjg59PN6f1w7vvTww1vFriTD_IU,1959 +pip/_internal/network/xmlrpc.py,sha256=AL115M3vFJ8xiHVJneb8Hi0ZFeRvdPhblC89w25OG5s,1597 +pip/_internal/operations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip/_internal/operations/__pycache__/__init__.cpython-38.pyc,, +pip/_internal/operations/__pycache__/check.cpython-38.pyc,, +pip/_internal/operations/__pycache__/freeze.cpython-38.pyc,, +pip/_internal/operations/__pycache__/prepare.cpython-38.pyc,, +pip/_internal/operations/build/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip/_internal/operations/build/__pycache__/__init__.cpython-38.pyc,, +pip/_internal/operations/build/__pycache__/metadata.cpython-38.pyc,, +pip/_internal/operations/build/__pycache__/metadata_legacy.cpython-38.pyc,, +pip/_internal/operations/build/__pycache__/wheel.cpython-38.pyc,, +pip/_internal/operations/build/__pycache__/wheel_legacy.cpython-38.pyc,, +pip/_internal/operations/build/metadata.py,sha256=yHMi5gHYXcXyHcvUPWHdO-UyOo3McFWljn_nHfM1O9c,1307 +pip/_internal/operations/build/metadata_legacy.py,sha256=VgzBTk8naIO8-8N_ifEYF7ZAxWUDhphWVIaVlZ2FqYM,2011 +pip/_internal/operations/build/wheel.py,sha256=ntltdNP6D2Tpr4V0agssu6rE0F9LaBpJkYT6zSdhEbw,1469 +pip/_internal/operations/build/wheel_legacy.py,sha256=N1aqNZyGURBX0Bj6wPmB0t4866oMbxoHUpC9pz6FyT0,3356 +pip/_internal/operations/check.py,sha256=a6uHG0daoWpmSPCdL7iYJaGQYZ-CRvPvTnCv2PnIIs0,5353 +pip/_internal/operations/freeze.py,sha256=mGT2OFjMOb0FlVjgedAzJ9GbNOgNwYiL0130xx60pHA,10587 +pip/_internal/operations/install/__init__.py,sha256=mX7hyD2GNBO2mFGokDQ30r_GXv7Y_PLdtxcUv144e-s,51 +pip/_internal/operations/install/__pycache__/__init__.cpython-38.pyc,, +pip/_internal/operations/install/__pycache__/editable_legacy.cpython-38.pyc,, +pip/_internal/operations/install/__pycache__/legacy.cpython-38.pyc,, +pip/_internal/operations/install/__pycache__/wheel.cpython-38.pyc,, +pip/_internal/operations/install/editable_legacy.py,sha256=rJ_xs2qtDUjpY2-n6eYlVyZiNoKbOtZXZrYrcnIELt4,1488 +pip/_internal/operations/install/legacy.py,sha256=YkKdL_tyNwDP2huOGxmopySh5Pz2v_wRVeSTEa6ZUco,4686 +pip/_internal/operations/install/wheel.py,sha256=8IO3GYTtrJ42cqipLOh0rxex4j-PfU8m71HVB0tOQd0,23885 +pip/_internal/operations/prepare.py,sha256=RDwtSetVTfv-nv1-_apYBA3Dez5ngBmOYzcuZy2Q3vk,20030 +pip/_internal/pyproject.py,sha256=VJKsrXORGiGoDPVKCQhuu4tWlQSTOhoiRlVLRNu4rx4,7400 +pip/_internal/req/__init__.py,sha256=UVaYPlHZVGRBQQPjvGC_6jJDQtewXm0ws-8Lxhg_TiY,2671 +pip/_internal/req/__pycache__/__init__.cpython-38.pyc,, +pip/_internal/req/__pycache__/constructors.cpython-38.pyc,, +pip/_internal/req/__pycache__/req_file.cpython-38.pyc,, +pip/_internal/req/__pycache__/req_install.cpython-38.pyc,, +pip/_internal/req/__pycache__/req_set.cpython-38.pyc,, +pip/_internal/req/__pycache__/req_tracker.cpython-38.pyc,, +pip/_internal/req/__pycache__/req_uninstall.cpython-38.pyc,, +pip/_internal/req/constructors.py,sha256=i_dU2sYtSk5GMsad68gBx26tfneRmhPF2sYGe4uPnu8,15441 +pip/_internal/req/req_file.py,sha256=5QlZr36kkw1Jsbr8vFO-fGUEAef9h-AoRRqjx8EYSuQ,19075 +pip/_internal/req/req_install.py,sha256=9yn_fBFTyzHPMjYG5WXBB2WiGQvk3BT6gYl9Khw8ZoE,31713 +pip/_internal/req/req_set.py,sha256=EBHZ9zWSR8arxjcadyU2OotZIECemM8oOFQ0nK-Bb7E,7792 +pip/_internal/req/req_tracker.py,sha256=cAKhSw-QbhGxqPF1Wc0zD6jo932jpdYF3ROfRSH8hes,4744 +pip/_internal/req/req_uninstall.py,sha256=NdErRQBpNScsdwJAo3O_zo2KPPfQyVMJ_Q2mxPWYyOA,23734 +pip/_internal/resolution/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip/_internal/resolution/__pycache__/__init__.cpython-38.pyc,, +pip/_internal/resolution/__pycache__/base.cpython-38.pyc,, +pip/_internal/resolution/base.py,sha256=xi72YmIS-lEjyK13PN_3qkGGthA4yGoK0C6qWynyHrE,682 +pip/_internal/resolution/legacy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip/_internal/resolution/legacy/__pycache__/__init__.cpython-38.pyc,, +pip/_internal/resolution/legacy/__pycache__/resolver.cpython-38.pyc,, +pip/_internal/resolution/legacy/resolver.py,sha256=56GuGHWcseV24cvTCOuRHMAF_Er1UeDxn5m18XMkHBs,17587 +pip/_internal/resolution/resolvelib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip/_internal/resolution/resolvelib/__pycache__/__init__.cpython-38.pyc,, +pip/_internal/resolution/resolvelib/__pycache__/base.cpython-38.pyc,, +pip/_internal/resolution/resolvelib/__pycache__/candidates.cpython-38.pyc,, +pip/_internal/resolution/resolvelib/__pycache__/factory.cpython-38.pyc,, +pip/_internal/resolution/resolvelib/__pycache__/provider.cpython-38.pyc,, +pip/_internal/resolution/resolvelib/__pycache__/requirements.cpython-38.pyc,, +pip/_internal/resolution/resolvelib/__pycache__/resolver.cpython-38.pyc,, +pip/_internal/resolution/resolvelib/base.py,sha256=l2Z3-1Qg243lWzwFbaN17qixA4U8LYr-qMhZTdaHROc,1502 +pip/_internal/resolution/resolvelib/candidates.py,sha256=wzi9t3aX1Twi3xTNEkpG6eWOd0dEg5uKul-QkK3arvw,15173 +pip/_internal/resolution/resolvelib/factory.py,sha256=mDs3p8D9N9zfYvn_iIx0saDLHF1SF7KHBQlA1gWSWVQ,7574 +pip/_internal/resolution/resolvelib/provider.py,sha256=0fKuPuEoD5T7w-YwKgQZc1AmgSnAkrxGnLBOf-_6Kiw,1703 +pip/_internal/resolution/resolvelib/requirements.py,sha256=bu9Y4YINHjvBm-NBKvnxw9IYHW4t6rRlm4-QKVqLDsM,3872 +pip/_internal/resolution/resolvelib/resolver.py,sha256=3LXhhCz6CtIpih8tK2nHeRvVEjVJmXrqxNCM1FQM1U0,6673 +pip/_internal/self_outdated_check.py,sha256=3KO1pTJUuYaiV9X0t87I9PimkGL82HbhLWbocqKZpBU,8009 +pip/_internal/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pip/_internal/utils/__pycache__/__init__.cpython-38.pyc,, +pip/_internal/utils/__pycache__/appdirs.cpython-38.pyc,, +pip/_internal/utils/__pycache__/compat.cpython-38.pyc,, +pip/_internal/utils/__pycache__/compatibility_tags.cpython-38.pyc,, +pip/_internal/utils/__pycache__/deprecation.cpython-38.pyc,, +pip/_internal/utils/__pycache__/direct_url_helpers.cpython-38.pyc,, +pip/_internal/utils/__pycache__/distutils_args.cpython-38.pyc,, +pip/_internal/utils/__pycache__/encoding.cpython-38.pyc,, +pip/_internal/utils/__pycache__/entrypoints.cpython-38.pyc,, +pip/_internal/utils/__pycache__/filesystem.cpython-38.pyc,, +pip/_internal/utils/__pycache__/filetypes.cpython-38.pyc,, +pip/_internal/utils/__pycache__/glibc.cpython-38.pyc,, +pip/_internal/utils/__pycache__/hashes.cpython-38.pyc,, +pip/_internal/utils/__pycache__/inject_securetransport.cpython-38.pyc,, +pip/_internal/utils/__pycache__/logging.cpython-38.pyc,, +pip/_internal/utils/__pycache__/misc.cpython-38.pyc,, +pip/_internal/utils/__pycache__/models.cpython-38.pyc,, +pip/_internal/utils/__pycache__/packaging.cpython-38.pyc,, +pip/_internal/utils/__pycache__/pkg_resources.cpython-38.pyc,, +pip/_internal/utils/__pycache__/setuptools_build.cpython-38.pyc,, +pip/_internal/utils/__pycache__/subprocess.cpython-38.pyc,, +pip/_internal/utils/__pycache__/temp_dir.cpython-38.pyc,, +pip/_internal/utils/__pycache__/typing.cpython-38.pyc,, +pip/_internal/utils/__pycache__/unpacking.cpython-38.pyc,, +pip/_internal/utils/__pycache__/urls.cpython-38.pyc,, +pip/_internal/utils/__pycache__/virtualenv.cpython-38.pyc,, +pip/_internal/utils/__pycache__/wheel.cpython-38.pyc,, +pip/_internal/utils/appdirs.py,sha256=RZzUG-Bkh2b-miX0DSZ3v703_-bgK-v0PfWCCjwVE9g,1349 +pip/_internal/utils/compat.py,sha256=ZRJsXMjq373p0US54CUkKRkpLH-ioOM3H3yAhmbUPcs,8898 +pip/_internal/utils/compatibility_tags.py,sha256=b2NWEbxfsrB2pBLwJkNVSYUrIAsumQ2IWDoNabbwLPs,5492 +pip/_internal/utils/deprecation.py,sha256=pBnNogoA4UGTxa_JDnPXBRRYpKMbExAhXpBwAwklOBs,3318 +pip/_internal/utils/direct_url_helpers.py,sha256=bZCBNwPQVyZpYGjX_VcomvVvRHvKw-9JzEV-Ft09LQc,4359 +pip/_internal/utils/distutils_args.py,sha256=a56mblNxk9BGifbpEETG61mmBrqhjtjRkJ4HYn-oOEE,1350 +pip/_internal/utils/encoding.py,sha256=hxZz0t3Whw3d4MHQEiofxalTlfKwxFdLc8fpeGfhKo8,1320 +pip/_internal/utils/entrypoints.py,sha256=vHcNpnksCv6mllihU6hfifdsKPEjwcaJ1aLIXEaynaU,1152 +pip/_internal/utils/filesystem.py,sha256=fqpFwT280152rlX1RjJqjoLp_MXVA8HzKTtDmsl15Ps,6813 +pip/_internal/utils/filetypes.py,sha256=R2FwzoeX7b-rZALOXx5cuO8VPPMhUQ4ne7wm3n3IcWA,571 +pip/_internal/utils/glibc.py,sha256=LOeNGgawCKS-4ke9fii78fwXD73dtNav3uxz1Bf-Ab8,3297 +pip/_internal/utils/hashes.py,sha256=LQVOt2LTWAdBJH6WPim1YGdF0J-0AfBBLghIDlY1-80,3986 +pip/_internal/utils/inject_securetransport.py,sha256=M17ZlFVY66ApgeASVjKKLKNz0LAfk-SyU0HZ4ZB6MmI,810 +pip/_internal/utils/logging.py,sha256=YIfuDUEkmdn9cIRQ_Ec8rgXs1m5nOwDECtZqM4CBH5U,13093 +pip/_internal/utils/misc.py,sha256=d6Gvup_5Uus2jBxsUHwnSP1HDiGsb9oBNZKhdgbAMnE,26798 +pip/_internal/utils/models.py,sha256=IA0hw_T4awQzui0kqfIEASm5yLtgZAB08ag59Nip5G8,1148 +pip/_internal/utils/packaging.py,sha256=VtiwcAAL7LBi7tGL2je7LeW4bE11KMHGCsJ1NZY5XtM,3035 +pip/_internal/utils/pkg_resources.py,sha256=ZX-k7V5q_aNWyDse92nN7orN1aCpRLsaxzpkBZ1XKzU,1254 +pip/_internal/utils/setuptools_build.py,sha256=E1KswI7wfNnCDE5R6G8c9ZbByENpu7NqocjY26PCQDw,5058 +pip/_internal/utils/subprocess.py,sha256=vI2QWpNDqM-dkn-z8i1Yrfxnn5sYniPeWn6FhTxX4dY,9902 +pip/_internal/utils/temp_dir.py,sha256=H8yUBrRWqTM83cuUu7jVvw_xKL9eZtg_IIbXQtjMLlA,8185 +pip/_internal/utils/typing.py,sha256=xkYwOeHlf4zsHXBDC4310HtEqwhQcYXFPq2h35Tcrl0,1401 +pip/_internal/utils/unpacking.py,sha256=M944JTSiapBOSKLWu7lbawpVHSE7flfzZTEr3TAG7v8,9438 +pip/_internal/utils/urls.py,sha256=q2rw1kMiiig_XZcoyJSsWMJQqYw-2wUmrMoST4mCW_I,1527 +pip/_internal/utils/virtualenv.py,sha256=iVJ8ZlbNtGon6I4uZFsY2SidrUf1vt3YHrgS5CuU98w,3553 +pip/_internal/utils/wheel.py,sha256=ofsZEN35YhSxRYC4gfzpTtqa_UQ8GF1tl4jtyUdd0gU,7306 +pip/_internal/vcs/__init__.py,sha256=viJxJRqRE_mVScum85bgQIXAd6o0ozFt18VpC-qIJrM,617 +pip/_internal/vcs/__pycache__/__init__.cpython-38.pyc,, +pip/_internal/vcs/__pycache__/bazaar.cpython-38.pyc,, +pip/_internal/vcs/__pycache__/git.cpython-38.pyc,, +pip/_internal/vcs/__pycache__/mercurial.cpython-38.pyc,, +pip/_internal/vcs/__pycache__/subversion.cpython-38.pyc,, +pip/_internal/vcs/__pycache__/versioncontrol.cpython-38.pyc,, +pip/_internal/vcs/bazaar.py,sha256=84q1-kj1_nJ9AMzMu8RmMp-riRZu81M7K9kowcYgi3U,3957 +pip/_internal/vcs/git.py,sha256=wlvvVT-hPRwCvkihEoOCZmkCzMzosmV43_DTPvEVA_M,14165 +pip/_internal/vcs/mercurial.py,sha256=wVdmoFH-RYoaxjtuAqw40b0daMPX-Fr_26W1ME_9HZU,5347 +pip/_internal/vcs/subversion.py,sha256=6shByxeASetbM7WCj6WNoPcuLfBK65DoOEqbkSiWPAI,12331 +pip/_internal/vcs/versioncontrol.py,sha256=RtSrHr96CynqXYBQIC61cVY_9C0e7hk8dXUV-BpHmpI,23591 +pip/_internal/wheel_builder.py,sha256=p9ZFawfCR1GXchTRY6oq7Qx5enLLjs2SouafNFNsAAE,9590 +pip/_vendor/__init__.py,sha256=9W5OMec7OR5iGiLkewOfrMJ9Wt-FjLAezVSYzwHc2ds,5156 +pip/_vendor/__pycache__/__init__.cpython-38.pyc,, diff --git a/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/WHEEL b/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/WHEEL new file mode 100644 index 0000000..ef99c6c --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip-20.1.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/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/entry_points.txt b/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/entry_points.txt new file mode 100644 index 0000000..d48bd8a --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/entry_points.txt @@ -0,0 +1,5 @@ +[console_scripts] +pip = pip._internal.cli.main:main +pip3 = pip._internal.cli.main:main +pip3.8 = pip._internal.cli.main:main + diff --git a/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/top_level.txt b/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/top_level.txt new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/top_level.txt @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.8/site-packages/pip/__init__.py b/venv/lib/python3.8/site-packages/pip/__init__.py new file mode 100644 index 0000000..3dcf3a9 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/__init__.py @@ -0,0 +1,18 @@ +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import List, Optional + + +__version__ = "20.1.1" + + +def main(args=None): + # type: (Optional[List[str]]) -> int + """This is an internal API only meant for use by pip's own console scripts. + + For additional details, see https://github.com/pypa/pip/issues/7498. + """ + from pip._internal.utils.entrypoints import _wrapper + + return _wrapper(args) diff --git a/venv/lib/python3.8/site-packages/pip/__main__.py b/venv/lib/python3.8/site-packages/pip/__main__.py new file mode 100644 index 0000000..7c2505f --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/__main__.py @@ -0,0 +1,26 @@ +from __future__ import absolute_import + +import os +import sys + +# Remove '' and current working directory from the first entry +# of sys.path, if present to avoid using current directory +# in pip commands check, freeze, install, list and show, +# when invoked as python -m pip +if sys.path[0] in ('', os.getcwd()): + sys.path.pop(0) + +# If we are running from a wheel, add the wheel to sys.path +# This allows the usage python pip-*.whl/pip install pip-*.whl +if __package__ == '': + # __file__ is pip-*.whl/pip/__main__.py + # first dirname call strips of '/__main__.py', second strips off '/pip' + # Resulting path is the name of the wheel itself + # Add that to sys.path so we can import pip + path = os.path.dirname(os.path.dirname(__file__)) + sys.path.insert(0, path) + +from pip._internal.cli.main import main as _main # isort:skip # noqa + +if __name__ == '__main__': + sys.exit(_main()) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/__init__.py b/venv/lib/python3.8/site-packages/pip/_internal/__init__.py new file mode 100644 index 0000000..264c2ca --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/__init__.py @@ -0,0 +1,17 @@ +import pip._internal.utils.inject_securetransport # noqa +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Optional, List + + +def main(args=None): + # type: (Optional[List[str]]) -> int + """This is preserved for old console scripts that may still be referencing + it. + + For additional details, see https://github.com/pypa/pip/issues/7498. + """ + from pip._internal.utils.entrypoints import _wrapper + + return _wrapper(args) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/build_env.py b/venv/lib/python3.8/site-packages/pip/_internal/build_env.py new file mode 100644 index 0000000..b8f005f --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/build_env.py @@ -0,0 +1,219 @@ +"""Build Environment used for isolation during sdist building +""" + +# The following comment should be removed at some point in the future. +# mypy: strict-optional=False +# mypy: disallow-untyped-defs=False + +import logging +import os +import sys +import textwrap +from collections import OrderedDict +from distutils.sysconfig import get_python_lib +from sysconfig import get_paths + +from pip._vendor.pkg_resources import Requirement, VersionConflict, WorkingSet + +from pip import __file__ as pip_location +from pip._internal.cli.spinners import open_spinner +from pip._internal.utils.subprocess import call_subprocess +from pip._internal.utils.temp_dir import TempDirectory, tempdir_kinds +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Tuple, Set, Iterable, Optional, List + from pip._internal.index.package_finder import PackageFinder + +logger = logging.getLogger(__name__) + + +class _Prefix: + + def __init__(self, path): + # type: (str) -> None + self.path = path + self.setup = False + self.bin_dir = get_paths( + 'nt' if os.name == 'nt' else 'posix_prefix', + vars={'base': path, 'platbase': path} + )['scripts'] + # Note: prefer distutils' sysconfig to get the + # library paths so PyPy is correctly supported. + purelib = get_python_lib(plat_specific=False, prefix=path) + platlib = get_python_lib(plat_specific=True, prefix=path) + if purelib == platlib: + self.lib_dirs = [purelib] + else: + self.lib_dirs = [purelib, platlib] + + +class BuildEnvironment(object): + """Creates and manages an isolated environment to install build deps + """ + + def __init__(self): + # type: () -> None + temp_dir = TempDirectory( + kind=tempdir_kinds.BUILD_ENV, globally_managed=True + ) + + self._prefixes = OrderedDict(( + (name, _Prefix(os.path.join(temp_dir.path, name))) + for name in ('normal', 'overlay') + )) + + self._bin_dirs = [] # type: List[str] + self._lib_dirs = [] # type: List[str] + for prefix in reversed(list(self._prefixes.values())): + self._bin_dirs.append(prefix.bin_dir) + self._lib_dirs.extend(prefix.lib_dirs) + + # Customize site to: + # - ensure .pth files are honored + # - prevent access to system site packages + system_sites = { + os.path.normcase(site) for site in ( + get_python_lib(plat_specific=False), + get_python_lib(plat_specific=True), + ) + } + self._site_dir = os.path.join(temp_dir.path, 'site') + if not os.path.exists(self._site_dir): + os.mkdir(self._site_dir) + with open(os.path.join(self._site_dir, 'sitecustomize.py'), 'w') as fp: + fp.write(textwrap.dedent( + ''' + import os, site, sys + + # First, drop system-sites related paths. + original_sys_path = sys.path[:] + known_paths = set() + for path in {system_sites!r}: + site.addsitedir(path, known_paths=known_paths) + system_paths = set( + os.path.normcase(path) + for path in sys.path[len(original_sys_path):] + ) + original_sys_path = [ + path for path in original_sys_path + if os.path.normcase(path) not in system_paths + ] + sys.path = original_sys_path + + # Second, add lib directories. + # ensuring .pth file are processed. + for path in {lib_dirs!r}: + assert not path in sys.path + site.addsitedir(path) + ''' + ).format(system_sites=system_sites, lib_dirs=self._lib_dirs)) + + def __enter__(self): + self._save_env = { + name: os.environ.get(name, None) + for name in ('PATH', 'PYTHONNOUSERSITE', 'PYTHONPATH') + } + + path = self._bin_dirs[:] + old_path = self._save_env['PATH'] + if old_path: + path.extend(old_path.split(os.pathsep)) + + pythonpath = [self._site_dir] + + os.environ.update({ + 'PATH': os.pathsep.join(path), + 'PYTHONNOUSERSITE': '1', + 'PYTHONPATH': os.pathsep.join(pythonpath), + }) + + def __exit__(self, exc_type, exc_val, exc_tb): + for varname, old_value in self._save_env.items(): + if old_value is None: + os.environ.pop(varname, None) + else: + os.environ[varname] = old_value + + def check_requirements(self, reqs): + # type: (Iterable[str]) -> Tuple[Set[Tuple[str, str]], Set[str]] + """Return 2 sets: + - conflicting requirements: set of (installed, wanted) reqs tuples + - missing requirements: set of reqs + """ + missing = set() + conflicting = set() + if reqs: + ws = WorkingSet(self._lib_dirs) + for req in reqs: + try: + if ws.find(Requirement.parse(req)) is None: + missing.add(req) + except VersionConflict as e: + conflicting.add((str(e.args[0].as_requirement()), + str(e.args[1]))) + return conflicting, missing + + def install_requirements( + self, + finder, # type: PackageFinder + requirements, # type: Iterable[str] + prefix_as_string, # type: str + message # type: Optional[str] + ): + # type: (...) -> None + prefix = self._prefixes[prefix_as_string] + assert not prefix.setup + prefix.setup = True + if not requirements: + return + args = [ + sys.executable, os.path.dirname(pip_location), 'install', + '--ignore-installed', '--no-user', '--prefix', prefix.path, + '--no-warn-script-location', + ] # type: List[str] + if logger.getEffectiveLevel() <= logging.DEBUG: + args.append('-v') + for format_control in ('no_binary', 'only_binary'): + formats = getattr(finder.format_control, format_control) + args.extend(('--' + format_control.replace('_', '-'), + ','.join(sorted(formats or {':none:'})))) + + index_urls = finder.index_urls + if index_urls: + args.extend(['-i', index_urls[0]]) + for extra_index in index_urls[1:]: + args.extend(['--extra-index-url', extra_index]) + else: + args.append('--no-index') + for link in finder.find_links: + args.extend(['--find-links', link]) + + for host in finder.trusted_hosts: + args.extend(['--trusted-host', host]) + if finder.allow_all_prereleases: + args.append('--pre') + args.append('--') + args.extend(requirements) + with open_spinner(message) as spinner: + call_subprocess(args, spinner=spinner) + + +class NoOpBuildEnvironment(BuildEnvironment): + """A no-op drop-in replacement for BuildEnvironment + """ + + def __init__(self): + pass + + def __enter__(self): + pass + + def __exit__(self, exc_type, exc_val, exc_tb): + pass + + def cleanup(self): + pass + + def install_requirements(self, finder, requirements, prefix, message): + raise NotImplementedError() diff --git a/venv/lib/python3.8/site-packages/pip/_internal/cache.py b/venv/lib/python3.8/site-packages/pip/_internal/cache.py new file mode 100644 index 0000000..b534f0c --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/cache.py @@ -0,0 +1,349 @@ +"""Cache Management +""" + +# The following comment should be removed at some point in the future. +# mypy: strict-optional=False + +import hashlib +import json +import logging +import os + +from pip._vendor.packaging.tags import interpreter_name, interpreter_version +from pip._vendor.packaging.utils import canonicalize_name + +from pip._internal.exceptions import InvalidWheelFilename +from pip._internal.models.link import Link +from pip._internal.models.wheel import Wheel +from pip._internal.utils.temp_dir import TempDirectory, tempdir_kinds +from pip._internal.utils.typing import MYPY_CHECK_RUNNING +from pip._internal.utils.urls import path_to_url + +if MYPY_CHECK_RUNNING: + from typing import Optional, Set, List, Any, Dict + + from pip._vendor.packaging.tags import Tag + + from pip._internal.models.format_control import FormatControl + +logger = logging.getLogger(__name__) + + +def _hash_dict(d): + # type: (Dict[str, str]) -> str + """Return a stable sha224 of a dictionary.""" + s = json.dumps(d, sort_keys=True, separators=(",", ":"), ensure_ascii=True) + return hashlib.sha224(s.encode("ascii")).hexdigest() + + +class Cache(object): + """An abstract class - provides cache directories for data from links + + + :param cache_dir: The root of the cache. + :param format_control: An object of FormatControl class to limit + binaries being read from the cache. + :param allowed_formats: which formats of files the cache should store. + ('binary' and 'source' are the only allowed values) + """ + + def __init__(self, cache_dir, format_control, allowed_formats): + # type: (str, FormatControl, Set[str]) -> None + super(Cache, self).__init__() + assert not cache_dir or os.path.isabs(cache_dir) + self.cache_dir = cache_dir or None + self.format_control = format_control + self.allowed_formats = allowed_formats + + _valid_formats = {"source", "binary"} + assert self.allowed_formats.union(_valid_formats) == _valid_formats + + def _get_cache_path_parts_legacy(self, link): + # type: (Link) -> List[str] + """Get parts of part that must be os.path.joined with cache_dir + + Legacy cache key (pip < 20) for compatibility with older caches. + """ + + # We want to generate an url to use as our cache key, we don't want to + # just re-use the URL because it might have other items in the fragment + # and we don't care about those. + key_parts = [link.url_without_fragment] + if link.hash_name is not None and link.hash is not None: + key_parts.append("=".join([link.hash_name, link.hash])) + key_url = "#".join(key_parts) + + # Encode our key url with sha224, we'll use this because it has similar + # security properties to sha256, but with a shorter total output (and + # thus less secure). However the differences don't make a lot of + # difference for our use case here. + hashed = hashlib.sha224(key_url.encode()).hexdigest() + + # We want to nest the directories some to prevent having a ton of top + # level directories where we might run out of sub directories on some + # FS. + parts = [hashed[:2], hashed[2:4], hashed[4:6], hashed[6:]] + + return parts + + def _get_cache_path_parts(self, link): + # type: (Link) -> List[str] + """Get parts of part that must be os.path.joined with cache_dir + """ + + # We want to generate an url to use as our cache key, we don't want to + # just re-use the URL because it might have other items in the fragment + # and we don't care about those. + key_parts = {"url": link.url_without_fragment} + if link.hash_name is not None and link.hash is not None: + key_parts[link.hash_name] = link.hash + if link.subdirectory_fragment: + key_parts["subdirectory"] = link.subdirectory_fragment + + # Include interpreter name, major and minor version in cache key + # to cope with ill-behaved sdists that build a different wheel + # depending on the python version their setup.py is being run on, + # and don't encode the difference in compatibility tags. + # https://github.com/pypa/pip/issues/7296 + key_parts["interpreter_name"] = interpreter_name() + key_parts["interpreter_version"] = interpreter_version() + + # Encode our key url with sha224, we'll use this because it has similar + # security properties to sha256, but with a shorter total output (and + # thus less secure). However the differences don't make a lot of + # difference for our use case here. + hashed = _hash_dict(key_parts) + + # We want to nest the directories some to prevent having a ton of top + # level directories where we might run out of sub directories on some + # FS. + parts = [hashed[:2], hashed[2:4], hashed[4:6], hashed[6:]] + + return parts + + def _get_candidates(self, link, canonical_package_name): + # type: (Link, Optional[str]) -> List[Any] + can_not_cache = ( + not self.cache_dir or + not canonical_package_name or + not link + ) + if can_not_cache: + return [] + + formats = self.format_control.get_allowed_formats( + canonical_package_name + ) + if not self.allowed_formats.intersection(formats): + return [] + + candidates = [] + path = self.get_path_for_link(link) + if os.path.isdir(path): + for candidate in os.listdir(path): + candidates.append((candidate, path)) + # TODO remove legacy path lookup in pip>=21 + legacy_path = self.get_path_for_link_legacy(link) + if os.path.isdir(legacy_path): + for candidate in os.listdir(legacy_path): + candidates.append((candidate, legacy_path)) + return candidates + + def get_path_for_link_legacy(self, link): + # type: (Link) -> str + raise NotImplementedError() + + def get_path_for_link(self, link): + # type: (Link) -> str + """Return a directory to store cached items in for link. + """ + raise NotImplementedError() + + def get( + self, + link, # type: Link + package_name, # type: Optional[str] + supported_tags, # type: List[Tag] + ): + # type: (...) -> Link + """Returns a link to a cached item if it exists, otherwise returns the + passed link. + """ + raise NotImplementedError() + + +class SimpleWheelCache(Cache): + """A cache of wheels for future installs. + """ + + def __init__(self, cache_dir, format_control): + # type: (str, FormatControl) -> None + super(SimpleWheelCache, self).__init__( + cache_dir, format_control, {"binary"} + ) + + def get_path_for_link_legacy(self, link): + # type: (Link) -> str + parts = self._get_cache_path_parts_legacy(link) + return os.path.join(self.cache_dir, "wheels", *parts) + + def get_path_for_link(self, link): + # type: (Link) -> str + """Return a directory to store cached wheels for link + + Because there are M wheels for any one sdist, we provide a directory + to cache them in, and then consult that directory when looking up + cache hits. + + We only insert things into the cache if they have plausible version + numbers, so that we don't contaminate the cache with things that were + not unique. E.g. ./package might have dozens of installs done for it + and build a version of 0.0...and if we built and cached a wheel, we'd + end up using the same wheel even if the source has been edited. + + :param link: The link of the sdist for which this will cache wheels. + """ + parts = self._get_cache_path_parts(link) + + # Store wheels within the root cache_dir + return os.path.join(self.cache_dir, "wheels", *parts) + + def get( + self, + link, # type: Link + package_name, # type: Optional[str] + supported_tags, # type: List[Tag] + ): + # type: (...) -> Link + candidates = [] + + if not package_name: + return link + + canonical_package_name = canonicalize_name(package_name) + for wheel_name, wheel_dir in self._get_candidates( + link, canonical_package_name + ): + try: + wheel = Wheel(wheel_name) + except InvalidWheelFilename: + continue + if canonicalize_name(wheel.name) != canonical_package_name: + logger.debug( + "Ignoring cached wheel {} for {} as it " + "does not match the expected distribution name {}.".format( + wheel_name, link, package_name + ) + ) + continue + if not wheel.supported(supported_tags): + # Built for a different python/arch/etc + continue + candidates.append( + ( + wheel.support_index_min(supported_tags), + wheel_name, + wheel_dir, + ) + ) + + if not candidates: + return link + + _, wheel_name, wheel_dir = min(candidates) + return Link(path_to_url(os.path.join(wheel_dir, wheel_name))) + + +class EphemWheelCache(SimpleWheelCache): + """A SimpleWheelCache that creates it's own temporary cache directory + """ + + def __init__(self, format_control): + # type: (FormatControl) -> None + self._temp_dir = TempDirectory( + kind=tempdir_kinds.EPHEM_WHEEL_CACHE, + globally_managed=True, + ) + + super(EphemWheelCache, self).__init__( + self._temp_dir.path, format_control + ) + + +class CacheEntry(object): + def __init__( + self, + link, # type: Link + persistent, # type: bool + ): + self.link = link + self.persistent = persistent + + +class WheelCache(Cache): + """Wraps EphemWheelCache and SimpleWheelCache into a single Cache + + This Cache allows for gracefully degradation, using the ephem wheel cache + when a certain link is not found in the simple wheel cache first. + """ + + def __init__(self, cache_dir, format_control): + # type: (str, FormatControl) -> None + super(WheelCache, self).__init__( + cache_dir, format_control, {'binary'} + ) + self._wheel_cache = SimpleWheelCache(cache_dir, format_control) + self._ephem_cache = EphemWheelCache(format_control) + + def get_path_for_link_legacy(self, link): + # type: (Link) -> str + return self._wheel_cache.get_path_for_link_legacy(link) + + def get_path_for_link(self, link): + # type: (Link) -> str + return self._wheel_cache.get_path_for_link(link) + + def get_ephem_path_for_link(self, link): + # type: (Link) -> str + return self._ephem_cache.get_path_for_link(link) + + def get( + self, + link, # type: Link + package_name, # type: Optional[str] + supported_tags, # type: List[Tag] + ): + # type: (...) -> Link + cache_entry = self.get_cache_entry(link, package_name, supported_tags) + if cache_entry is None: + return link + return cache_entry.link + + def get_cache_entry( + self, + link, # type: Link + package_name, # type: Optional[str] + supported_tags, # type: List[Tag] + ): + # type: (...) -> Optional[CacheEntry] + """Returns a CacheEntry with a link to a cached item if it exists or + None. The cache entry indicates if the item was found in the persistent + or ephemeral cache. + """ + retval = self._wheel_cache.get( + link=link, + package_name=package_name, + supported_tags=supported_tags, + ) + if retval is not link: + return CacheEntry(retval, persistent=True) + + retval = self._ephem_cache.get( + link=link, + package_name=package_name, + supported_tags=supported_tags, + ) + if retval is not link: + return CacheEntry(retval, persistent=False) + + return None diff --git a/venv/lib/python3.8/site-packages/pip/_internal/cli/__init__.py b/venv/lib/python3.8/site-packages/pip/_internal/cli/__init__.py new file mode 100644 index 0000000..e589bb9 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/cli/__init__.py @@ -0,0 +1,4 @@ +"""Subpackage containing all of pip's command line interface related code +""" + +# This file intentionally does not import submodules diff --git a/venv/lib/python3.8/site-packages/pip/_internal/cli/autocompletion.py b/venv/lib/python3.8/site-packages/pip/_internal/cli/autocompletion.py new file mode 100644 index 0000000..329de60 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/cli/autocompletion.py @@ -0,0 +1,164 @@ +"""Logic that powers autocompletion installed by ``pip completion``. +""" + +import optparse +import os +import sys +from itertools import chain + +from pip._internal.cli.main_parser import create_main_parser +from pip._internal.commands import commands_dict, create_command +from pip._internal.utils.misc import get_installed_distributions +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Any, Iterable, List, Optional + + +def autocomplete(): + # type: () -> None + """Entry Point for completion of main and subcommand options. + """ + # Don't complete if user hasn't sourced bash_completion file. + if 'PIP_AUTO_COMPLETE' not in os.environ: + return + cwords = os.environ['COMP_WORDS'].split()[1:] + cword = int(os.environ['COMP_CWORD']) + try: + current = cwords[cword - 1] + except IndexError: + current = '' + + parser = create_main_parser() + subcommands = list(commands_dict) + options = [] + + # subcommand + subcommand_name = None # type: Optional[str] + for word in cwords: + if word in subcommands: + subcommand_name = word + break + # subcommand options + if subcommand_name is not None: + # special case: 'help' subcommand has no options + if subcommand_name == 'help': + sys.exit(1) + # special case: list locally installed dists for show and uninstall + should_list_installed = ( + subcommand_name in ['show', 'uninstall'] and + not current.startswith('-') + ) + if should_list_installed: + installed = [] + lc = current.lower() + for dist in get_installed_distributions(local_only=True): + if dist.key.startswith(lc) and dist.key not in cwords[1:]: + installed.append(dist.key) + # if there are no dists installed, fall back to option completion + if installed: + for dist in installed: + print(dist) + sys.exit(1) + + subcommand = create_command(subcommand_name) + + for opt in subcommand.parser.option_list_all: + if opt.help != optparse.SUPPRESS_HELP: + for opt_str in opt._long_opts + opt._short_opts: + options.append((opt_str, opt.nargs)) + + # filter out previously specified options from available options + prev_opts = [x.split('=')[0] for x in cwords[1:cword - 1]] + options = [(x, v) for (x, v) in options if x not in prev_opts] + # filter options by current input + options = [(k, v) for k, v in options if k.startswith(current)] + # get completion type given cwords and available subcommand options + completion_type = get_path_completion_type( + cwords, cword, subcommand.parser.option_list_all, + ) + # get completion files and directories if ``completion_type`` is + # ````, ```` or ```` + if completion_type: + paths = auto_complete_paths(current, completion_type) + options = [(path, 0) for path in paths] + for option in options: + opt_label = option[0] + # append '=' to options which require args + if option[1] and option[0][:2] == "--": + opt_label += '=' + print(opt_label) + else: + # show main parser options only when necessary + + opts = [i.option_list for i in parser.option_groups] + opts.append(parser.option_list) + flattened_opts = chain.from_iterable(opts) + if current.startswith('-'): + for opt in flattened_opts: + if opt.help != optparse.SUPPRESS_HELP: + subcommands += opt._long_opts + opt._short_opts + else: + # get completion type given cwords and all available options + completion_type = get_path_completion_type(cwords, cword, + flattened_opts) + if completion_type: + subcommands = list(auto_complete_paths(current, + completion_type)) + + print(' '.join([x for x in subcommands if x.startswith(current)])) + sys.exit(1) + + +def get_path_completion_type(cwords, cword, opts): + # type: (List[str], int, Iterable[Any]) -> Optional[str] + """Get the type of path completion (``file``, ``dir``, ``path`` or None) + + :param cwords: same as the environmental variable ``COMP_WORDS`` + :param cword: same as the environmental variable ``COMP_CWORD`` + :param opts: The available options to check + :return: path completion type (``file``, ``dir``, ``path`` or None) + """ + if cword < 2 or not cwords[cword - 2].startswith('-'): + return None + for opt in opts: + if opt.help == optparse.SUPPRESS_HELP: + continue + for o in str(opt).split('/'): + if cwords[cword - 2].split('=')[0] == o: + if not opt.metavar or any( + x in ('path', 'file', 'dir') + for x in opt.metavar.split('/')): + return opt.metavar + return None + + +def auto_complete_paths(current, completion_type): + # type: (str, str) -> Iterable[str] + """If ``completion_type`` is ``file`` or ``path``, list all regular files + and directories starting with ``current``; otherwise only list directories + starting with ``current``. + + :param current: The word to be completed + :param completion_type: path completion type(`file`, `path` or `dir`)i + :return: A generator of regular files and/or directories + """ + directory, filename = os.path.split(current) + current_path = os.path.abspath(directory) + # Don't complete paths if they can't be accessed + if not os.access(current_path, os.R_OK): + return + filename = os.path.normcase(filename) + # list all files that start with ``filename`` + file_list = (x for x in os.listdir(current_path) + if os.path.normcase(x).startswith(filename)) + for f in file_list: + opt = os.path.join(current_path, f) + comp_file = os.path.normcase(os.path.join(directory, f)) + # complete regular files when there is not ```` after option + # complete directories when there is ````, ```` or + # ````after option + if completion_type != 'dir' and os.path.isfile(opt): + yield comp_file + elif os.path.isdir(opt): + yield os.path.join(comp_file, '') diff --git a/venv/lib/python3.8/site-packages/pip/_internal/cli/base_command.py b/venv/lib/python3.8/site-packages/pip/_internal/cli/base_command.py new file mode 100644 index 0000000..1fa5ba0 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/cli/base_command.py @@ -0,0 +1,228 @@ +"""Base Command class, and related routines""" + +from __future__ import absolute_import, print_function + +import logging +import logging.config +import optparse +import os +import platform +import sys +import traceback + +from pip._internal.cli import cmdoptions +from pip._internal.cli.command_context import CommandContextMixIn +from pip._internal.cli.parser import ( + ConfigOptionParser, + UpdatingDefaultsHelpFormatter, +) +from pip._internal.cli.status_codes import ( + ERROR, + PREVIOUS_BUILD_DIR_ERROR, + SUCCESS, + UNKNOWN_ERROR, + VIRTUALENV_NOT_FOUND, +) +from pip._internal.exceptions import ( + BadCommand, + CommandError, + InstallationError, + PreviousBuildDirError, + UninstallationError, +) +from pip._internal.utils.deprecation import deprecated +from pip._internal.utils.filesystem import check_path_owner +from pip._internal.utils.logging import BrokenStdoutLoggingError, setup_logging +from pip._internal.utils.misc import get_prog, normalize_path +from pip._internal.utils.temp_dir import ( + global_tempdir_manager, + tempdir_registry, +) +from pip._internal.utils.typing import MYPY_CHECK_RUNNING +from pip._internal.utils.virtualenv import running_under_virtualenv + +if MYPY_CHECK_RUNNING: + from typing import List, Optional, Tuple, Any + from optparse import Values + + from pip._internal.utils.temp_dir import ( + TempDirectoryTypeRegistry as TempDirRegistry + ) + +__all__ = ['Command'] + +logger = logging.getLogger(__name__) + + +class Command(CommandContextMixIn): + usage = None # type: str + ignore_require_venv = False # type: bool + + def __init__(self, name, summary, isolated=False): + # type: (str, str, bool) -> None + super(Command, self).__init__() + parser_kw = { + 'usage': self.usage, + 'prog': '{} {}'.format(get_prog(), name), + 'formatter': UpdatingDefaultsHelpFormatter(), + 'add_help_option': False, + 'name': name, + 'description': self.__doc__, + 'isolated': isolated, + } + + self.name = name + self.summary = summary + self.parser = ConfigOptionParser(**parser_kw) + + self.tempdir_registry = None # type: Optional[TempDirRegistry] + + # Commands should add options to this option group + optgroup_name = '{} Options'.format(self.name.capitalize()) + self.cmd_opts = optparse.OptionGroup(self.parser, optgroup_name) + + # Add the general options + gen_opts = cmdoptions.make_option_group( + cmdoptions.general_group, + self.parser, + ) + self.parser.add_option_group(gen_opts) + + def handle_pip_version_check(self, options): + # type: (Values) -> None + """ + This is a no-op so that commands by default do not do the pip version + check. + """ + # Make sure we do the pip version check if the index_group options + # are present. + assert not hasattr(options, 'no_index') + + def run(self, options, args): + # type: (Values, List[Any]) -> Any + raise NotImplementedError + + def parse_args(self, args): + # type: (List[str]) -> Tuple[Any, Any] + # factored out for testability + return self.parser.parse_args(args) + + def main(self, args): + # type: (List[str]) -> int + try: + with self.main_context(): + return self._main(args) + finally: + logging.shutdown() + + def _main(self, args): + # type: (List[str]) -> int + # We must initialize this before the tempdir manager, otherwise the + # configuration would not be accessible by the time we clean up the + # tempdir manager. + self.tempdir_registry = self.enter_context(tempdir_registry()) + # Intentionally set as early as possible so globally-managed temporary + # directories are available to the rest of the code. + self.enter_context(global_tempdir_manager()) + + options, args = self.parse_args(args) + + # Set verbosity so that it can be used elsewhere. + self.verbosity = options.verbose - options.quiet + + level_number = setup_logging( + verbosity=self.verbosity, + no_color=options.no_color, + user_log_file=options.log, + ) + + if ( + sys.version_info[:2] == (2, 7) and + not options.no_python_version_warning + ): + message = ( + "pip 21.0 will drop support for Python 2.7 in January 2021. " + "More details about Python 2 support in pip, can be found at " + "https://pip.pypa.io/en/latest/development/release-process/#python-2-support" # noqa + ) + if platform.python_implementation() == "CPython": + message = ( + "Python 2.7 reached the end of its life on January " + "1st, 2020. Please upgrade your Python as Python 2.7 " + "is no longer maintained. " + ) + message + deprecated(message, replacement=None, gone_in=None) + + # TODO: Try to get these passing down from the command? + # without resorting to os.environ to hold these. + # This also affects isolated builds and it should. + + if options.no_input: + os.environ['PIP_NO_INPUT'] = '1' + + if options.exists_action: + os.environ['PIP_EXISTS_ACTION'] = ' '.join(options.exists_action) + + if options.require_venv and not self.ignore_require_venv: + # If a venv is required check if it can really be found + if not running_under_virtualenv(): + logger.critical( + 'Could not find an activated virtualenv (required).' + ) + sys.exit(VIRTUALENV_NOT_FOUND) + + if options.cache_dir: + options.cache_dir = normalize_path(options.cache_dir) + if not check_path_owner(options.cache_dir): + logger.warning( + "The directory '%s' or its parent directory is not owned " + "or is not writable by the current user. The cache " + "has been disabled. Check the permissions and owner of " + "that directory. If executing pip with sudo, you may want " + "sudo's -H flag.", + options.cache_dir, + ) + options.cache_dir = None + + try: + status = self.run(options, args) + # FIXME: all commands should return an exit status + # and when it is done, isinstance is not needed anymore + if isinstance(status, int): + return status + except PreviousBuildDirError as exc: + logger.critical(str(exc)) + logger.debug('Exception information:', exc_info=True) + + return PREVIOUS_BUILD_DIR_ERROR + except (InstallationError, UninstallationError, BadCommand) as exc: + logger.critical(str(exc)) + logger.debug('Exception information:', exc_info=True) + + return ERROR + except CommandError as exc: + logger.critical('%s', exc) + logger.debug('Exception information:', exc_info=True) + + return ERROR + except BrokenStdoutLoggingError: + # Bypass our logger and write any remaining messages to stderr + # because stdout no longer works. + print('ERROR: Pipe to stdout was broken', file=sys.stderr) + if level_number <= logging.DEBUG: + traceback.print_exc(file=sys.stderr) + + return ERROR + except KeyboardInterrupt: + logger.critical('Operation cancelled by user') + logger.debug('Exception information:', exc_info=True) + + return ERROR + except BaseException: + logger.critical('Exception:', exc_info=True) + + return UNKNOWN_ERROR + finally: + self.handle_pip_version_check(options) + + return SUCCESS diff --git a/venv/lib/python3.8/site-packages/pip/_internal/cli/cmdoptions.py b/venv/lib/python3.8/site-packages/pip/_internal/cli/cmdoptions.py new file mode 100644 index 0000000..c234784 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/cli/cmdoptions.py @@ -0,0 +1,962 @@ +""" +shared options and groups + +The principle here is to define options once, but *not* instantiate them +globally. One reason being that options with action='append' can carry state +between parses. pip parses general options twice internally, and shouldn't +pass on state. To be consistent, all options will follow this design. +""" + +# The following comment should be removed at some point in the future. +# mypy: strict-optional=False + +from __future__ import absolute_import + +import logging +import os +import textwrap +import warnings +from distutils.util import strtobool +from functools import partial +from optparse import SUPPRESS_HELP, Option, OptionGroup +from textwrap import dedent + +from pip._internal.cli.progress_bars import BAR_TYPES +from pip._internal.exceptions import CommandError +from pip._internal.locations import USER_CACHE_DIR, get_src_prefix +from pip._internal.models.format_control import FormatControl +from pip._internal.models.index import PyPI +from pip._internal.models.target_python import TargetPython +from pip._internal.utils.hashes import STRONG_HASHES +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Any, Callable, Dict, Optional, Tuple + from optparse import OptionParser, Values + from pip._internal.cli.parser import ConfigOptionParser + +logger = logging.getLogger(__name__) + + +def raise_option_error(parser, option, msg): + # type: (OptionParser, Option, str) -> None + """ + Raise an option parsing error using parser.error(). + + Args: + parser: an OptionParser instance. + option: an Option instance. + msg: the error text. + """ + msg = '{} error: {}'.format(option, msg) + msg = textwrap.fill(' '.join(msg.split())) + parser.error(msg) + + +def make_option_group(group, parser): + # type: (Dict[str, Any], ConfigOptionParser) -> OptionGroup + """ + Return an OptionGroup object + group -- assumed to be dict with 'name' and 'options' keys + parser -- an optparse Parser + """ + option_group = OptionGroup(parser, group['name']) + for option in group['options']: + option_group.add_option(option()) + return option_group + + +def check_install_build_global(options, check_options=None): + # type: (Values, Optional[Values]) -> None + """Disable wheels if per-setup.py call options are set. + + :param options: The OptionParser options to update. + :param check_options: The options to check, if not supplied defaults to + options. + """ + if check_options is None: + check_options = options + + def getname(n): + # type: (str) -> Optional[Any] + return getattr(check_options, n, None) + names = ["build_options", "global_options", "install_options"] + if any(map(getname, names)): + control = options.format_control + control.disallow_binaries() + warnings.warn( + 'Disabling all use of wheels due to the use of --build-option ' + '/ --global-option / --install-option.', stacklevel=2, + ) + + +def check_dist_restriction(options, check_target=False): + # type: (Values, bool) -> None + """Function for determining if custom platform options are allowed. + + :param options: The OptionParser options. + :param check_target: Whether or not to check if --target is being used. + """ + dist_restriction_set = any([ + options.python_version, + options.platform, + options.abi, + options.implementation, + ]) + + binary_only = FormatControl(set(), {':all:'}) + sdist_dependencies_allowed = ( + options.format_control != binary_only and + not options.ignore_dependencies + ) + + # Installations or downloads using dist restrictions must not combine + # source distributions and dist-specific wheels, as they are not + # guaranteed to be locally compatible. + if dist_restriction_set and sdist_dependencies_allowed: + raise CommandError( + "When restricting platform and interpreter constraints using " + "--python-version, --platform, --abi, or --implementation, " + "either --no-deps must be set, or --only-binary=:all: must be " + "set and --no-binary must not be set (or must be set to " + ":none:)." + ) + + if check_target: + if dist_restriction_set and not options.target_dir: + raise CommandError( + "Can not use any platform or abi specific options unless " + "installing via '--target'" + ) + + +def _path_option_check(option, opt, value): + # type: (Option, str, str) -> str + return os.path.expanduser(value) + + +class PipOption(Option): + TYPES = Option.TYPES + ("path",) + TYPE_CHECKER = Option.TYPE_CHECKER.copy() + TYPE_CHECKER["path"] = _path_option_check + + +########### +# options # +########### + +help_ = partial( + Option, + '-h', '--help', + dest='help', + action='help', + help='Show help.', +) # type: Callable[..., Option] + +isolated_mode = partial( + Option, + "--isolated", + dest="isolated_mode", + action="store_true", + default=False, + help=( + "Run pip in an isolated mode, ignoring environment variables and user " + "configuration." + ), +) # type: Callable[..., Option] + +require_virtualenv = partial( + Option, + # Run only if inside a virtualenv, bail if not. + '--require-virtualenv', '--require-venv', + dest='require_venv', + action='store_true', + default=False, + help=SUPPRESS_HELP +) # type: Callable[..., Option] + +verbose = partial( + Option, + '-v', '--verbose', + dest='verbose', + action='count', + default=0, + help='Give more output. Option is additive, and can be used up to 3 times.' +) # type: Callable[..., Option] + +no_color = partial( + Option, + '--no-color', + dest='no_color', + action='store_true', + default=False, + help="Suppress colored output", +) # type: Callable[..., Option] + +version = partial( + Option, + '-V', '--version', + dest='version', + action='store_true', + help='Show version and exit.', +) # type: Callable[..., Option] + +quiet = partial( + Option, + '-q', '--quiet', + dest='quiet', + action='count', + default=0, + help=( + 'Give less output. Option is additive, and can be used up to 3' + ' times (corresponding to WARNING, ERROR, and CRITICAL logging' + ' levels).' + ), +) # type: Callable[..., Option] + +progress_bar = partial( + Option, + '--progress-bar', + dest='progress_bar', + type='choice', + choices=list(BAR_TYPES.keys()), + default='on', + help=( + 'Specify type of progress to be displayed [' + + '|'.join(BAR_TYPES.keys()) + '] (default: %default)' + ), +) # type: Callable[..., Option] + +log = partial( + PipOption, + "--log", "--log-file", "--local-log", + dest="log", + metavar="path", + type="path", + help="Path to a verbose appending log." +) # type: Callable[..., Option] + +no_input = partial( + Option, + # Don't ask for input + '--no-input', + dest='no_input', + action='store_true', + default=False, + help=SUPPRESS_HELP +) # type: Callable[..., Option] + +proxy = partial( + Option, + '--proxy', + dest='proxy', + type='str', + default='', + help="Specify a proxy in the form [user:passwd@]proxy.server:port." +) # type: Callable[..., Option] + +retries = partial( + Option, + '--retries', + dest='retries', + type='int', + default=5, + help="Maximum number of retries each connection should attempt " + "(default %default times).", +) # type: Callable[..., Option] + +timeout = partial( + Option, + '--timeout', '--default-timeout', + metavar='sec', + dest='timeout', + type='float', + default=15, + help='Set the socket timeout (default %default seconds).', +) # type: Callable[..., Option] + + +def exists_action(): + # type: () -> Option + return Option( + # Option when path already exist + '--exists-action', + dest='exists_action', + type='choice', + choices=['s', 'i', 'w', 'b', 'a'], + default=[], + action='append', + metavar='action', + help="Default action when a path already exists: " + "(s)witch, (i)gnore, (w)ipe, (b)ackup, (a)bort.", + ) + + +cert = partial( + PipOption, + '--cert', + dest='cert', + type='path', + metavar='path', + help="Path to alternate CA bundle.", +) # type: Callable[..., Option] + +client_cert = partial( + PipOption, + '--client-cert', + dest='client_cert', + type='path', + default=None, + metavar='path', + help="Path to SSL client certificate, a single file containing the " + "private key and the certificate in PEM format.", +) # type: Callable[..., Option] + +index_url = partial( + Option, + '-i', '--index-url', '--pypi-url', + dest='index_url', + metavar='URL', + default=PyPI.simple_url, + help="Base URL of the Python Package Index (default %default). " + "This should point to a repository compliant with PEP 503 " + "(the simple repository API) or a local directory laid out " + "in the same format.", +) # type: Callable[..., Option] + + +def extra_index_url(): + # type: () -> Option + return Option( + '--extra-index-url', + dest='extra_index_urls', + metavar='URL', + action='append', + default=[], + help="Extra URLs of package indexes to use in addition to " + "--index-url. Should follow the same rules as " + "--index-url.", + ) + + +no_index = partial( + Option, + '--no-index', + dest='no_index', + action='store_true', + default=False, + help='Ignore package index (only looking at --find-links URLs instead).', +) # type: Callable[..., Option] + + +def find_links(): + # type: () -> Option + return Option( + '-f', '--find-links', + dest='find_links', + action='append', + default=[], + metavar='url', + help="If a URL or path to an html file, then parse for links to " + "archives such as sdist (.tar.gz) or wheel (.whl) files. " + "If a local path or file:// URL that's a directory, " + "then look for archives in the directory listing. " + "Links to VCS project URLs are not supported.", + ) + + +def trusted_host(): + # type: () -> Option + return Option( + "--trusted-host", + dest="trusted_hosts", + action="append", + metavar="HOSTNAME", + default=[], + help="Mark this host or host:port pair as trusted, even though it " + "does not have valid or any HTTPS.", + ) + + +def constraints(): + # type: () -> Option + return Option( + '-c', '--constraint', + dest='constraints', + action='append', + default=[], + metavar='file', + help='Constrain versions using the given constraints file. ' + 'This option can be used multiple times.' + ) + + +def requirements(): + # type: () -> Option + return Option( + '-r', '--requirement', + dest='requirements', + action='append', + default=[], + metavar='file', + help='Install from the given requirements file. ' + 'This option can be used multiple times.' + ) + + +def editable(): + # type: () -> Option + return Option( + '-e', '--editable', + dest='editables', + action='append', + default=[], + metavar='path/url', + help=('Install a project in editable mode (i.e. setuptools ' + '"develop mode") from a local project path or a VCS url.'), + ) + + +def _handle_src(option, opt_str, value, parser): + # type: (Option, str, str, OptionParser) -> None + value = os.path.abspath(value) + setattr(parser.values, option.dest, value) + + +src = partial( + PipOption, + '--src', '--source', '--source-dir', '--source-directory', + dest='src_dir', + type='path', + metavar='dir', + default=get_src_prefix(), + action='callback', + callback=_handle_src, + help='Directory to check out editable projects into. ' + 'The default in a virtualenv is "/src". ' + 'The default for global installs is "/src".' +) # type: Callable[..., Option] + + +def _get_format_control(values, option): + # type: (Values, Option) -> Any + """Get a format_control object.""" + return getattr(values, option.dest) + + +def _handle_no_binary(option, opt_str, value, parser): + # type: (Option, str, str, OptionParser) -> None + existing = _get_format_control(parser.values, option) + FormatControl.handle_mutual_excludes( + value, existing.no_binary, existing.only_binary, + ) + + +def _handle_only_binary(option, opt_str, value, parser): + # type: (Option, str, str, OptionParser) -> None + existing = _get_format_control(parser.values, option) + FormatControl.handle_mutual_excludes( + value, existing.only_binary, existing.no_binary, + ) + + +def no_binary(): + # type: () -> Option + format_control = FormatControl(set(), set()) + return Option( + "--no-binary", dest="format_control", action="callback", + callback=_handle_no_binary, type="str", + default=format_control, + help='Do not use binary packages. Can be supplied multiple times, and ' + 'each time adds to the existing value. Accepts either ":all:" to ' + 'disable all binary packages, ":none:" to empty the set (notice ' + 'the colons), or one or more package names with commas between ' + 'them (no colons). Note that some packages are tricky to compile ' + 'and may fail to install when this option is used on them.', + ) + + +def only_binary(): + # type: () -> Option + format_control = FormatControl(set(), set()) + return Option( + "--only-binary", dest="format_control", action="callback", + callback=_handle_only_binary, type="str", + default=format_control, + help='Do not use source packages. Can be supplied multiple times, and ' + 'each time adds to the existing value. Accepts either ":all:" to ' + 'disable all source packages, ":none:" to empty the set, or one ' + 'or more package names with commas between them. Packages ' + 'without binary distributions will fail to install when this ' + 'option is used on them.', + ) + + +platform = partial( + Option, + '--platform', + dest='platform', + metavar='platform', + default=None, + help=("Only use wheels compatible with . " + "Defaults to the platform of the running system."), +) # type: Callable[..., Option] + + +# This was made a separate function for unit-testing purposes. +def _convert_python_version(value): + # type: (str) -> Tuple[Tuple[int, ...], Optional[str]] + """ + Convert a version string like "3", "37", or "3.7.3" into a tuple of ints. + + :return: A 2-tuple (version_info, error_msg), where `error_msg` is + non-None if and only if there was a parsing error. + """ + if not value: + # The empty string is the same as not providing a value. + return (None, None) + + parts = value.split('.') + if len(parts) > 3: + return ((), 'at most three version parts are allowed') + + if len(parts) == 1: + # Then we are in the case of "3" or "37". + value = parts[0] + if len(value) > 1: + parts = [value[0], value[1:]] + + try: + version_info = tuple(int(part) for part in parts) + except ValueError: + return ((), 'each version part must be an integer') + + return (version_info, None) + + +def _handle_python_version(option, opt_str, value, parser): + # type: (Option, str, str, OptionParser) -> None + """ + Handle a provided --python-version value. + """ + version_info, error_msg = _convert_python_version(value) + if error_msg is not None: + msg = ( + 'invalid --python-version value: {!r}: {}'.format( + value, error_msg, + ) + ) + raise_option_error(parser, option=option, msg=msg) + + parser.values.python_version = version_info + + +python_version = partial( + Option, + '--python-version', + dest='python_version', + metavar='python_version', + action='callback', + callback=_handle_python_version, type='str', + default=None, + help=dedent("""\ + The Python interpreter version to use for wheel and "Requires-Python" + compatibility checks. Defaults to a version derived from the running + interpreter. The version can be specified using up to three dot-separated + integers (e.g. "3" for 3.0.0, "3.7" for 3.7.0, or "3.7.3"). A major-minor + version can also be given as a string without dots (e.g. "37" for 3.7.0). + """), +) # type: Callable[..., Option] + + +implementation = partial( + Option, + '--implementation', + dest='implementation', + metavar='implementation', + default=None, + help=("Only use wheels compatible with Python " + "implementation , e.g. 'pp', 'jy', 'cp', " + " or 'ip'. If not specified, then the current " + "interpreter implementation is used. Use 'py' to force " + "implementation-agnostic wheels."), +) # type: Callable[..., Option] + + +abi = partial( + Option, + '--abi', + dest='abi', + metavar='abi', + default=None, + help=("Only use wheels compatible with Python " + "abi , e.g. 'pypy_41'. If not specified, then the " + "current interpreter abi tag is used. Generally " + "you will need to specify --implementation, " + "--platform, and --python-version when using " + "this option."), +) # type: Callable[..., Option] + + +def add_target_python_options(cmd_opts): + # type: (OptionGroup) -> None + cmd_opts.add_option(platform()) + cmd_opts.add_option(python_version()) + cmd_opts.add_option(implementation()) + cmd_opts.add_option(abi()) + + +def make_target_python(options): + # type: (Values) -> TargetPython + target_python = TargetPython( + platform=options.platform, + py_version_info=options.python_version, + abi=options.abi, + implementation=options.implementation, + ) + + return target_python + + +def prefer_binary(): + # type: () -> Option + return Option( + "--prefer-binary", + dest="prefer_binary", + action="store_true", + default=False, + help="Prefer older binary packages over newer source packages." + ) + + +cache_dir = partial( + PipOption, + "--cache-dir", + dest="cache_dir", + default=USER_CACHE_DIR, + metavar="dir", + type='path', + help="Store the cache data in ." +) # type: Callable[..., Option] + + +def _handle_no_cache_dir(option, opt, value, parser): + # type: (Option, str, str, OptionParser) -> None + """ + Process a value provided for the --no-cache-dir option. + + This is an optparse.Option callback for the --no-cache-dir option. + """ + # The value argument will be None if --no-cache-dir is passed via the + # command-line, since the option doesn't accept arguments. However, + # the value can be non-None if the option is triggered e.g. by an + # environment variable, like PIP_NO_CACHE_DIR=true. + if value is not None: + # Then parse the string value to get argument error-checking. + try: + strtobool(value) + except ValueError as exc: + raise_option_error(parser, option=option, msg=str(exc)) + + # Originally, setting PIP_NO_CACHE_DIR to a value that strtobool() + # converted to 0 (like "false" or "no") caused cache_dir to be disabled + # rather than enabled (logic would say the latter). Thus, we disable + # the cache directory not just on values that parse to True, but (for + # backwards compatibility reasons) also on values that parse to False. + # In other words, always set it to False if the option is provided in + # some (valid) form. + parser.values.cache_dir = False + + +no_cache = partial( + Option, + "--no-cache-dir", + dest="cache_dir", + action="callback", + callback=_handle_no_cache_dir, + help="Disable the cache.", +) # type: Callable[..., Option] + +no_deps = partial( + Option, + '--no-deps', '--no-dependencies', + dest='ignore_dependencies', + action='store_true', + default=False, + help="Don't install package dependencies.", +) # type: Callable[..., Option] + + +def _handle_build_dir(option, opt, value, parser): + # type: (Option, str, str, OptionParser) -> None + if value: + value = os.path.abspath(value) + setattr(parser.values, option.dest, value) + + +build_dir = partial( + PipOption, + '-b', '--build', '--build-dir', '--build-directory', + dest='build_dir', + type='path', + metavar='dir', + action='callback', + callback=_handle_build_dir, + help='Directory to unpack packages into and build in. Note that ' + 'an initial build still takes place in a temporary directory. ' + 'The location of temporary directories can be controlled by setting ' + 'the TMPDIR environment variable (TEMP on Windows) appropriately. ' + 'When passed, build directories are not cleaned in case of failures.' +) # type: Callable[..., Option] + +ignore_requires_python = partial( + Option, + '--ignore-requires-python', + dest='ignore_requires_python', + action='store_true', + help='Ignore the Requires-Python information.' +) # type: Callable[..., Option] + +no_build_isolation = partial( + Option, + '--no-build-isolation', + dest='build_isolation', + action='store_false', + default=True, + help='Disable isolation when building a modern source distribution. ' + 'Build dependencies specified by PEP 518 must be already installed ' + 'if this option is used.' +) # type: Callable[..., Option] + + +def _handle_no_use_pep517(option, opt, value, parser): + # type: (Option, str, str, OptionParser) -> None + """ + Process a value provided for the --no-use-pep517 option. + + This is an optparse.Option callback for the no_use_pep517 option. + """ + # Since --no-use-pep517 doesn't accept arguments, the value argument + # will be None if --no-use-pep517 is passed via the command-line. + # However, the value can be non-None if the option is triggered e.g. + # by an environment variable, for example "PIP_NO_USE_PEP517=true". + if value is not None: + msg = """A value was passed for --no-use-pep517, + probably using either the PIP_NO_USE_PEP517 environment variable + or the "no-use-pep517" config file option. Use an appropriate value + of the PIP_USE_PEP517 environment variable or the "use-pep517" + config file option instead. + """ + raise_option_error(parser, option=option, msg=msg) + + # Otherwise, --no-use-pep517 was passed via the command-line. + parser.values.use_pep517 = False + + +use_pep517 = partial( + Option, + '--use-pep517', + dest='use_pep517', + action='store_true', + default=None, + help='Use PEP 517 for building source distributions ' + '(use --no-use-pep517 to force legacy behaviour).' +) # type: Any + +no_use_pep517 = partial( + Option, + '--no-use-pep517', + dest='use_pep517', + action='callback', + callback=_handle_no_use_pep517, + default=None, + help=SUPPRESS_HELP +) # type: Any + +install_options = partial( + Option, + '--install-option', + dest='install_options', + action='append', + metavar='options', + help="Extra arguments to be supplied to the setup.py install " + "command (use like --install-option=\"--install-scripts=/usr/local/" + "bin\"). Use multiple --install-option options to pass multiple " + "options to setup.py install. If you are using an option with a " + "directory path, be sure to use absolute path.", +) # type: Callable[..., Option] + +global_options = partial( + Option, + '--global-option', + dest='global_options', + action='append', + metavar='options', + help="Extra global options to be supplied to the setup.py " + "call before the install command.", +) # type: Callable[..., Option] + +no_clean = partial( + Option, + '--no-clean', + action='store_true', + default=False, + help="Don't clean up build directories." +) # type: Callable[..., Option] + +pre = partial( + Option, + '--pre', + action='store_true', + default=False, + help="Include pre-release and development versions. By default, " + "pip only finds stable versions.", +) # type: Callable[..., Option] + +disable_pip_version_check = partial( + Option, + "--disable-pip-version-check", + dest="disable_pip_version_check", + action="store_true", + default=True, + help="Don't periodically check PyPI to determine whether a new version " + "of pip is available for download. Implied with --no-index.", +) # type: Callable[..., Option] + + +# Deprecated, Remove later +always_unzip = partial( + Option, + '-Z', '--always-unzip', + dest='always_unzip', + action='store_true', + help=SUPPRESS_HELP, +) # type: Callable[..., Option] + + +def _handle_merge_hash(option, opt_str, value, parser): + # type: (Option, str, str, OptionParser) -> None + """Given a value spelled "algo:digest", append the digest to a list + pointed to in a dict by the algo name.""" + if not parser.values.hashes: + parser.values.hashes = {} + try: + algo, digest = value.split(':', 1) + except ValueError: + parser.error('Arguments to {} must be a hash name ' + 'followed by a value, like --hash=sha256:' + 'abcde...'.format(opt_str)) + if algo not in STRONG_HASHES: + parser.error('Allowed hash algorithms for {} are {}.'.format( + opt_str, ', '.join(STRONG_HASHES))) + parser.values.hashes.setdefault(algo, []).append(digest) + + +hash = partial( + Option, + '--hash', + # Hash values eventually end up in InstallRequirement.hashes due to + # __dict__ copying in process_line(). + dest='hashes', + action='callback', + callback=_handle_merge_hash, + type='string', + help="Verify that the package's archive matches this " + 'hash before installing. Example: --hash=sha256:abcdef...', +) # type: Callable[..., Option] + + +require_hashes = partial( + Option, + '--require-hashes', + dest='require_hashes', + action='store_true', + default=False, + help='Require a hash to check each requirement against, for ' + 'repeatable installs. This option is implied when any package in a ' + 'requirements file has a --hash option.', +) # type: Callable[..., Option] + + +list_path = partial( + PipOption, + '--path', + dest='path', + type='path', + action='append', + help='Restrict to the specified installation path for listing ' + 'packages (can be used multiple times).' +) # type: Callable[..., Option] + + +def check_list_path_option(options): + # type: (Values) -> None + if options.path and (options.user or options.local): + raise CommandError( + "Cannot combine '--path' with '--user' or '--local'" + ) + + +no_python_version_warning = partial( + Option, + '--no-python-version-warning', + dest='no_python_version_warning', + action='store_true', + default=False, + help='Silence deprecation warnings for upcoming unsupported Pythons.', +) # type: Callable[..., Option] + + +unstable_feature = partial( + Option, + '--unstable-feature', + dest='unstable_features', + metavar='feature', + action='append', + default=[], + choices=['resolver'], + help=SUPPRESS_HELP, # TODO: Enable this when the resolver actually works. + # help='Enable unstable feature(s) that may be backward incompatible.', +) # type: Callable[..., Option] + + +########## +# groups # +########## + +general_group = { + 'name': 'General Options', + 'options': [ + help_, + isolated_mode, + require_virtualenv, + verbose, + version, + quiet, + log, + no_input, + proxy, + retries, + timeout, + exists_action, + trusted_host, + cert, + client_cert, + cache_dir, + no_cache, + disable_pip_version_check, + no_color, + no_python_version_warning, + unstable_feature, + ] +} # type: Dict[str, Any] + +index_group = { + 'name': 'Package Index Options', + 'options': [ + index_url, + extra_index_url, + no_index, + find_links, + ] +} # type: Dict[str, Any] diff --git a/venv/lib/python3.8/site-packages/pip/_internal/cli/command_context.py b/venv/lib/python3.8/site-packages/pip/_internal/cli/command_context.py new file mode 100644 index 0000000..d1a64a7 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/cli/command_context.py @@ -0,0 +1,36 @@ +from contextlib import contextmanager + +from pip._vendor.contextlib2 import ExitStack + +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Iterator, ContextManager, TypeVar + + _T = TypeVar('_T', covariant=True) + + +class CommandContextMixIn(object): + def __init__(self): + # type: () -> None + super(CommandContextMixIn, self).__init__() + self._in_main_context = False + self._main_context = ExitStack() + + @contextmanager + def main_context(self): + # type: () -> Iterator[None] + assert not self._in_main_context + + self._in_main_context = True + try: + with self._main_context: + yield + finally: + self._in_main_context = False + + def enter_context(self, context_provider): + # type: (ContextManager[_T]) -> _T + assert self._in_main_context + + return self._main_context.enter_context(context_provider) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/cli/main.py b/venv/lib/python3.8/site-packages/pip/_internal/cli/main.py new file mode 100644 index 0000000..172f30d --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/cli/main.py @@ -0,0 +1,75 @@ +"""Primary application entrypoint. +""" +from __future__ import absolute_import + +import locale +import logging +import os +import sys + +from pip._internal.cli.autocompletion import autocomplete +from pip._internal.cli.main_parser import parse_command +from pip._internal.commands import create_command +from pip._internal.exceptions import PipError +from pip._internal.utils import deprecation +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import List, Optional + +logger = logging.getLogger(__name__) + + +# Do not import and use main() directly! Using it directly is actively +# discouraged by pip's maintainers. The name, location and behavior of +# this function is subject to change, so calling it directly is not +# portable across different pip versions. + +# In addition, running pip in-process is unsupported and unsafe. This is +# elaborated in detail at +# https://pip.pypa.io/en/stable/user_guide/#using-pip-from-your-program. +# That document also provides suggestions that should work for nearly +# all users that are considering importing and using main() directly. + +# However, we know that certain users will still want to invoke pip +# in-process. If you understand and accept the implications of using pip +# in an unsupported manner, the best approach is to use runpy to avoid +# depending on the exact location of this entry point. + +# The following example shows how to use runpy to invoke pip in that +# case: +# +# sys.argv = ["pip", your, args, here] +# runpy.run_module("pip", run_name="__main__") +# +# Note that this will exit the process after running, unlike a direct +# call to main. As it is not safe to do any processing after calling +# main, this should not be an issue in practice. + +def main(args=None): + # type: (Optional[List[str]]) -> int + if args is None: + args = sys.argv[1:] + + # Configure our deprecation warnings to be sent through loggers + deprecation.install_warning_logger() + + autocomplete() + + try: + cmd_name, cmd_args = parse_command(args) + except PipError as exc: + sys.stderr.write("ERROR: {}".format(exc)) + sys.stderr.write(os.linesep) + sys.exit(1) + + # Needed for locale.getpreferredencoding(False) to work + # in pip._internal.utils.encoding.auto_decode + try: + locale.setlocale(locale.LC_ALL, '') + except locale.Error as e: + # setlocale can apparently crash if locale are uninitialized + logger.debug("Ignoring error %s when setting locale", e) + command = create_command(cmd_name, isolated=("--isolated" in cmd_args)) + + return command.main(cmd_args) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/cli/main_parser.py b/venv/lib/python3.8/site-packages/pip/_internal/cli/main_parser.py new file mode 100644 index 0000000..08c82c1 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/cli/main_parser.py @@ -0,0 +1,99 @@ +"""A single place for constructing and exposing the main parser +""" + +import os +import sys + +from pip._internal.cli import cmdoptions +from pip._internal.cli.parser import ( + ConfigOptionParser, + UpdatingDefaultsHelpFormatter, +) +from pip._internal.commands import commands_dict, get_similar_commands +from pip._internal.exceptions import CommandError +from pip._internal.utils.misc import get_pip_version, get_prog +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Tuple, List + + +__all__ = ["create_main_parser", "parse_command"] + + +def create_main_parser(): + # type: () -> ConfigOptionParser + """Creates and returns the main parser for pip's CLI + """ + + parser_kw = { + 'usage': '\n%prog [options]', + 'add_help_option': False, + 'formatter': UpdatingDefaultsHelpFormatter(), + 'name': 'global', + 'prog': get_prog(), + } + + parser = ConfigOptionParser(**parser_kw) + parser.disable_interspersed_args() + + parser.version = get_pip_version() + + # add the general options + gen_opts = cmdoptions.make_option_group(cmdoptions.general_group, parser) + parser.add_option_group(gen_opts) + + # so the help formatter knows + parser.main = True # type: ignore + + # create command listing for description + description = [''] + [ + '{name:27} {command_info.summary}'.format(**locals()) + for name, command_info in commands_dict.items() + ] + parser.description = '\n'.join(description) + + return parser + + +def parse_command(args): + # type: (List[str]) -> Tuple[str, List[str]] + parser = create_main_parser() + + # Note: parser calls disable_interspersed_args(), so the result of this + # call is to split the initial args into the general options before the + # subcommand and everything else. + # For example: + # args: ['--timeout=5', 'install', '--user', 'INITools'] + # general_options: ['--timeout==5'] + # args_else: ['install', '--user', 'INITools'] + general_options, args_else = parser.parse_args(args) + + # --version + if general_options.version: + sys.stdout.write(parser.version) # type: ignore + sys.stdout.write(os.linesep) + sys.exit() + + # pip || pip help -> print_help() + if not args_else or (args_else[0] == 'help' and len(args_else) == 1): + parser.print_help() + sys.exit() + + # the subcommand name + cmd_name = args_else[0] + + if cmd_name not in commands_dict: + guess = get_similar_commands(cmd_name) + + msg = ['unknown command "{}"'.format(cmd_name)] + if guess: + msg.append('maybe you meant "{}"'.format(guess)) + + raise CommandError(' - '.join(msg)) + + # all the args without the subcommand + cmd_args = args[:] + cmd_args.remove(cmd_name) + + return cmd_name, cmd_args diff --git a/venv/lib/python3.8/site-packages/pip/_internal/cli/parser.py b/venv/lib/python3.8/site-packages/pip/_internal/cli/parser.py new file mode 100644 index 0000000..04e00b7 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/cli/parser.py @@ -0,0 +1,266 @@ +"""Base option parser setup""" + +# The following comment should be removed at some point in the future. +# mypy: disallow-untyped-defs=False + +from __future__ import absolute_import + +import logging +import optparse +import sys +import textwrap +from distutils.util import strtobool + +from pip._vendor.six import string_types + +from pip._internal.cli.status_codes import UNKNOWN_ERROR +from pip._internal.configuration import Configuration, ConfigurationError +from pip._internal.utils.compat import get_terminal_size + +logger = logging.getLogger(__name__) + + +class PrettyHelpFormatter(optparse.IndentedHelpFormatter): + """A prettier/less verbose help formatter for optparse.""" + + def __init__(self, *args, **kwargs): + # help position must be aligned with __init__.parseopts.description + kwargs['max_help_position'] = 30 + kwargs['indent_increment'] = 1 + kwargs['width'] = get_terminal_size()[0] - 2 + optparse.IndentedHelpFormatter.__init__(self, *args, **kwargs) + + def format_option_strings(self, option): + return self._format_option_strings(option) + + def _format_option_strings(self, option, mvarfmt=' <{}>', optsep=', '): + """ + Return a comma-separated list of option strings and metavars. + + :param option: tuple of (short opt, long opt), e.g: ('-f', '--format') + :param mvarfmt: metavar format string + :param optsep: separator + """ + opts = [] + + if option._short_opts: + opts.append(option._short_opts[0]) + if option._long_opts: + opts.append(option._long_opts[0]) + if len(opts) > 1: + opts.insert(1, optsep) + + if option.takes_value(): + metavar = option.metavar or option.dest.lower() + opts.append(mvarfmt.format(metavar.lower())) + + return ''.join(opts) + + def format_heading(self, heading): + if heading == 'Options': + return '' + return heading + ':\n' + + def format_usage(self, usage): + """ + Ensure there is only one newline between usage and the first heading + if there is no description. + """ + msg = '\nUsage: {}\n'.format( + self.indent_lines(textwrap.dedent(usage), " ")) + return msg + + def format_description(self, description): + # leave full control over description to us + if description: + if hasattr(self.parser, 'main'): + label = 'Commands' + else: + label = 'Description' + # some doc strings have initial newlines, some don't + description = description.lstrip('\n') + # some doc strings have final newlines and spaces, some don't + description = description.rstrip() + # dedent, then reindent + description = self.indent_lines(textwrap.dedent(description), " ") + description = '{}:\n{}\n'.format(label, description) + return description + else: + return '' + + def format_epilog(self, epilog): + # leave full control over epilog to us + if epilog: + return epilog + else: + return '' + + def indent_lines(self, text, indent): + new_lines = [indent + line for line in text.split('\n')] + return "\n".join(new_lines) + + +class UpdatingDefaultsHelpFormatter(PrettyHelpFormatter): + """Custom help formatter for use in ConfigOptionParser. + + This is updates the defaults before expanding them, allowing + them to show up correctly in the help listing. + """ + + def expand_default(self, option): + if self.parser is not None: + self.parser._update_defaults(self.parser.defaults) + return optparse.IndentedHelpFormatter.expand_default(self, option) + + +class CustomOptionParser(optparse.OptionParser): + + def insert_option_group(self, idx, *args, **kwargs): + """Insert an OptionGroup at a given position.""" + group = self.add_option_group(*args, **kwargs) + + self.option_groups.pop() + self.option_groups.insert(idx, group) + + return group + + @property + def option_list_all(self): + """Get a list of all options, including those in option groups.""" + res = self.option_list[:] + for i in self.option_groups: + res.extend(i.option_list) + + return res + + +class ConfigOptionParser(CustomOptionParser): + """Custom option parser which updates its defaults by checking the + configuration files and environmental variables""" + + def __init__(self, *args, **kwargs): + self.name = kwargs.pop('name') + + isolated = kwargs.pop("isolated", False) + self.config = Configuration(isolated) + + assert self.name + optparse.OptionParser.__init__(self, *args, **kwargs) + + def check_default(self, option, key, val): + try: + return option.check_value(key, val) + except optparse.OptionValueError as exc: + print("An error occurred during configuration: {}".format(exc)) + sys.exit(3) + + def _get_ordered_configuration_items(self): + # Configuration gives keys in an unordered manner. Order them. + override_order = ["global", self.name, ":env:"] + + # Pool the options into different groups + section_items = {name: [] for name in override_order} + for section_key, val in self.config.items(): + # ignore empty values + if not val: + logger.debug( + "Ignoring configuration key '%s' as it's value is empty.", + section_key + ) + continue + + section, key = section_key.split(".", 1) + if section in override_order: + section_items[section].append((key, val)) + + # Yield each group in their override order + for section in override_order: + for key, val in section_items[section]: + yield key, val + + def _update_defaults(self, defaults): + """Updates the given defaults with values from the config files and + the environ. Does a little special handling for certain types of + options (lists).""" + + # Accumulate complex default state. + self.values = optparse.Values(self.defaults) + late_eval = set() + # Then set the options with those values + for key, val in self._get_ordered_configuration_items(): + # '--' because configuration supports only long names + option = self.get_option('--' + key) + + # Ignore options not present in this parser. E.g. non-globals put + # in [global] by users that want them to apply to all applicable + # commands. + if option is None: + continue + + if option.action in ('store_true', 'store_false', 'count'): + try: + val = strtobool(val) + except ValueError: + error_msg = invalid_config_error_message( + option.action, key, val + ) + self.error(error_msg) + + elif option.action == 'append': + val = val.split() + val = [self.check_default(option, key, v) for v in val] + elif option.action == 'callback': + late_eval.add(option.dest) + opt_str = option.get_opt_string() + val = option.convert_value(opt_str, val) + # From take_action + args = option.callback_args or () + kwargs = option.callback_kwargs or {} + option.callback(option, opt_str, val, self, *args, **kwargs) + else: + val = self.check_default(option, key, val) + + defaults[option.dest] = val + + for key in late_eval: + defaults[key] = getattr(self.values, key) + self.values = None + return defaults + + def get_default_values(self): + """Overriding to make updating the defaults after instantiation of + the option parser possible, _update_defaults() does the dirty work.""" + if not self.process_default_values: + # Old, pre-Optik 1.5 behaviour. + return optparse.Values(self.defaults) + + # Load the configuration, or error out in case of an error + try: + self.config.load() + except ConfigurationError as err: + self.exit(UNKNOWN_ERROR, str(err)) + + defaults = self._update_defaults(self.defaults.copy()) # ours + for option in self._get_all_options(): + default = defaults.get(option.dest) + if isinstance(default, string_types): + opt_str = option.get_opt_string() + defaults[option.dest] = option.check_value(opt_str, default) + return optparse.Values(defaults) + + def error(self, msg): + self.print_usage(sys.stderr) + self.exit(UNKNOWN_ERROR, "{}\n".format(msg)) + + +def invalid_config_error_message(action, key, val): + """Returns a better error message when invalid configuration option + is provided.""" + if action in ('store_true', 'store_false'): + return ("{0} is not a valid value for {1} option, " + "please specify a boolean value like yes/no, " + "true/false or 1/0 instead.").format(val, key) + + return ("{0} is not a valid value for {1} option, " + "please specify a numerical value like 1/0 " + "instead.").format(val, key) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/cli/progress_bars.py b/venv/lib/python3.8/site-packages/pip/_internal/cli/progress_bars.py new file mode 100644 index 0000000..7ed2247 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/cli/progress_bars.py @@ -0,0 +1,277 @@ +from __future__ import division + +import itertools +import sys +from signal import SIGINT, default_int_handler, signal + +from pip._vendor import six +from pip._vendor.progress.bar import Bar, FillingCirclesBar, IncrementalBar +from pip._vendor.progress.spinner import Spinner + +from pip._internal.utils.compat import WINDOWS +from pip._internal.utils.logging import get_indentation +from pip._internal.utils.misc import format_size +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Any, Dict, List + +try: + from pip._vendor import colorama +# Lots of different errors can come from this, including SystemError and +# ImportError. +except Exception: + colorama = None + + +def _select_progress_class(preferred, fallback): + # type: (Bar, Bar) -> Bar + encoding = getattr(preferred.file, "encoding", None) + + # If we don't know what encoding this file is in, then we'll just assume + # that it doesn't support unicode and use the ASCII bar. + if not encoding: + return fallback + + # Collect all of the possible characters we want to use with the preferred + # bar. + characters = [ + getattr(preferred, "empty_fill", six.text_type()), + getattr(preferred, "fill", six.text_type()), + ] + characters += list(getattr(preferred, "phases", [])) + + # Try to decode the characters we're using for the bar using the encoding + # of the given file, if this works then we'll assume that we can use the + # fancier bar and if not we'll fall back to the plaintext bar. + try: + six.text_type().join(characters).encode(encoding) + except UnicodeEncodeError: + return fallback + else: + return preferred + + +_BaseBar = _select_progress_class(IncrementalBar, Bar) # type: Any + + +class InterruptibleMixin(object): + """ + Helper to ensure that self.finish() gets called on keyboard interrupt. + + This allows downloads to be interrupted without leaving temporary state + (like hidden cursors) behind. + + This class is similar to the progress library's existing SigIntMixin + helper, but as of version 1.2, that helper has the following problems: + + 1. It calls sys.exit(). + 2. It discards the existing SIGINT handler completely. + 3. It leaves its own handler in place even after an uninterrupted finish, + which will have unexpected delayed effects if the user triggers an + unrelated keyboard interrupt some time after a progress-displaying + download has already completed, for example. + """ + + def __init__(self, *args, **kwargs): + # type: (List[Any], Dict[Any, Any]) -> None + """ + Save the original SIGINT handler for later. + """ + super(InterruptibleMixin, self).__init__( # type: ignore + *args, + **kwargs + ) + + self.original_handler = signal(SIGINT, self.handle_sigint) + + # If signal() returns None, the previous handler was not installed from + # Python, and we cannot restore it. This probably should not happen, + # but if it does, we must restore something sensible instead, at least. + # The least bad option should be Python's default SIGINT handler, which + # just raises KeyboardInterrupt. + if self.original_handler is None: + self.original_handler = default_int_handler + + def finish(self): + # type: () -> None + """ + Restore the original SIGINT handler after finishing. + + This should happen regardless of whether the progress display finishes + normally, or gets interrupted. + """ + super(InterruptibleMixin, self).finish() # type: ignore + signal(SIGINT, self.original_handler) + + def handle_sigint(self, signum, frame): # type: ignore + """ + Call self.finish() before delegating to the original SIGINT handler. + + This handler should only be in place while the progress display is + active. + """ + self.finish() + self.original_handler(signum, frame) + + +class SilentBar(Bar): + + def update(self): + # type: () -> None + pass + + +class BlueEmojiBar(IncrementalBar): + + suffix = "%(percent)d%%" + bar_prefix = " " + bar_suffix = " " + phases = (u"\U0001F539", u"\U0001F537", u"\U0001F535") # type: Any + + +class DownloadProgressMixin(object): + + def __init__(self, *args, **kwargs): + # type: (List[Any], Dict[Any, Any]) -> None + super(DownloadProgressMixin, self).__init__( # type: ignore + *args, + **kwargs + ) + self.message = (" " * ( + get_indentation() + 2 + )) + self.message # type: str + + @property + def downloaded(self): + # type: () -> str + return format_size(self.index) # type: ignore + + @property + def download_speed(self): + # type: () -> str + # Avoid zero division errors... + if self.avg == 0.0: # type: ignore + return "..." + return format_size(1 / self.avg) + "/s" # type: ignore + + @property + def pretty_eta(self): + # type: () -> str + if self.eta: # type: ignore + return "eta {}".format(self.eta_td) # type: ignore + return "" + + def iter(self, it): # type: ignore + for x in it: + yield x + self.next(len(x)) + self.finish() + + +class WindowsMixin(object): + + def __init__(self, *args, **kwargs): + # type: (List[Any], Dict[Any, Any]) -> None + # The Windows terminal does not support the hide/show cursor ANSI codes + # even with colorama. So we'll ensure that hide_cursor is False on + # Windows. + # This call needs to go before the super() call, so that hide_cursor + # is set in time. The base progress bar class writes the "hide cursor" + # code to the terminal in its init, so if we don't set this soon + # enough, we get a "hide" with no corresponding "show"... + if WINDOWS and self.hide_cursor: # type: ignore + self.hide_cursor = False + + super(WindowsMixin, self).__init__(*args, **kwargs) # type: ignore + + # Check if we are running on Windows and we have the colorama module, + # if we do then wrap our file with it. + if WINDOWS and colorama: + self.file = colorama.AnsiToWin32(self.file) # type: ignore + # The progress code expects to be able to call self.file.isatty() + # but the colorama.AnsiToWin32() object doesn't have that, so we'll + # add it. + self.file.isatty = lambda: self.file.wrapped.isatty() + # The progress code expects to be able to call self.file.flush() + # but the colorama.AnsiToWin32() object doesn't have that, so we'll + # add it. + self.file.flush = lambda: self.file.wrapped.flush() + + +class BaseDownloadProgressBar(WindowsMixin, InterruptibleMixin, + DownloadProgressMixin): + + file = sys.stdout + message = "%(percent)d%%" + suffix = "%(downloaded)s %(download_speed)s %(pretty_eta)s" + +# NOTE: The "type: ignore" comments on the following classes are there to +# work around https://github.com/python/typing/issues/241 + + +class DefaultDownloadProgressBar(BaseDownloadProgressBar, + _BaseBar): + pass + + +class DownloadSilentBar(BaseDownloadProgressBar, SilentBar): # type: ignore + pass + + +class DownloadBar(BaseDownloadProgressBar, # type: ignore + Bar): + pass + + +class DownloadFillingCirclesBar(BaseDownloadProgressBar, # type: ignore + FillingCirclesBar): + pass + + +class DownloadBlueEmojiProgressBar(BaseDownloadProgressBar, # type: ignore + BlueEmojiBar): + pass + + +class DownloadProgressSpinner(WindowsMixin, InterruptibleMixin, + DownloadProgressMixin, Spinner): + + file = sys.stdout + suffix = "%(downloaded)s %(download_speed)s" + + def next_phase(self): # type: ignore + if not hasattr(self, "_phaser"): + self._phaser = itertools.cycle(self.phases) + return next(self._phaser) + + def update(self): + # type: () -> None + message = self.message % self + phase = self.next_phase() + suffix = self.suffix % self + line = ''.join([ + message, + " " if message else "", + phase, + " " if suffix else "", + suffix, + ]) + + self.writeln(line) + + +BAR_TYPES = { + "off": (DownloadSilentBar, DownloadSilentBar), + "on": (DefaultDownloadProgressBar, DownloadProgressSpinner), + "ascii": (DownloadBar, DownloadProgressSpinner), + "pretty": (DownloadFillingCirclesBar, DownloadProgressSpinner), + "emoji": (DownloadBlueEmojiProgressBar, DownloadProgressSpinner) +} + + +def DownloadProgressProvider(progress_bar, max=None): # type: ignore + if max is None or max == 0: + return BAR_TYPES[progress_bar][1]().iter + else: + return BAR_TYPES[progress_bar][0](max=max).iter diff --git a/venv/lib/python3.8/site-packages/pip/_internal/cli/req_command.py b/venv/lib/python3.8/site-packages/pip/_internal/cli/req_command.py new file mode 100644 index 0000000..104b033 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/cli/req_command.py @@ -0,0 +1,408 @@ +"""Contains the Command base classes that depend on PipSession. + +The classes in this module are in a separate module so the commands not +needing download / PackageFinder capability don't unnecessarily import the +PackageFinder machinery and all its vendored dependencies, etc. +""" + +import logging +import os +from functools import partial + +from pip._internal.cli import cmdoptions +from pip._internal.cli.base_command import Command +from pip._internal.cli.command_context import CommandContextMixIn +from pip._internal.exceptions import CommandError, PreviousBuildDirError +from pip._internal.index.package_finder import PackageFinder +from pip._internal.models.selection_prefs import SelectionPreferences +from pip._internal.network.download import Downloader +from pip._internal.network.session import PipSession +from pip._internal.operations.prepare import RequirementPreparer +from pip._internal.req.constructors import ( + install_req_from_editable, + install_req_from_line, + install_req_from_parsed_requirement, + install_req_from_req_string, +) +from pip._internal.req.req_file import parse_requirements +from pip._internal.req.req_set import RequirementSet +from pip._internal.self_outdated_check import ( + make_link_collector, + pip_self_version_check, +) +from pip._internal.utils.temp_dir import tempdir_kinds +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from optparse import Values + from typing import Any, List, Optional, Tuple + + from pip._internal.cache import WheelCache + from pip._internal.models.target_python import TargetPython + from pip._internal.req.req_install import InstallRequirement + from pip._internal.req.req_tracker import RequirementTracker + from pip._internal.resolution.base import BaseResolver + from pip._internal.utils.temp_dir import ( + TempDirectory, + TempDirectoryTypeRegistry, + ) + + +logger = logging.getLogger(__name__) + + +class SessionCommandMixin(CommandContextMixIn): + + """ + A class mixin for command classes needing _build_session(). + """ + def __init__(self): + # type: () -> None + super(SessionCommandMixin, self).__init__() + self._session = None # Optional[PipSession] + + @classmethod + def _get_index_urls(cls, options): + # type: (Values) -> Optional[List[str]] + """Return a list of index urls from user-provided options.""" + index_urls = [] + if not getattr(options, "no_index", False): + url = getattr(options, "index_url", None) + if url: + index_urls.append(url) + urls = getattr(options, "extra_index_urls", None) + if urls: + index_urls.extend(urls) + # Return None rather than an empty list + return index_urls or None + + def get_default_session(self, options): + # type: (Values) -> PipSession + """Get a default-managed session.""" + if self._session is None: + self._session = self.enter_context(self._build_session(options)) + # there's no type annotation on requests.Session, so it's + # automatically ContextManager[Any] and self._session becomes Any, + # then https://github.com/python/mypy/issues/7696 kicks in + assert self._session is not None + return self._session + + def _build_session(self, options, retries=None, timeout=None): + # type: (Values, Optional[int], Optional[int]) -> PipSession + assert not options.cache_dir or os.path.isabs(options.cache_dir) + session = PipSession( + cache=( + os.path.join(options.cache_dir, "http") + if options.cache_dir else None + ), + retries=retries if retries is not None else options.retries, + trusted_hosts=options.trusted_hosts, + index_urls=self._get_index_urls(options), + ) + + # Handle custom ca-bundles from the user + if options.cert: + session.verify = options.cert + + # Handle SSL client certificate + if options.client_cert: + session.cert = options.client_cert + + # Handle timeouts + if options.timeout or timeout: + session.timeout = ( + timeout if timeout is not None else options.timeout + ) + + # Handle configured proxies + if options.proxy: + session.proxies = { + "http": options.proxy, + "https": options.proxy, + } + + # Determine if we can prompt the user for authentication or not + session.auth.prompting = not options.no_input + + return session + + +class IndexGroupCommand(Command, SessionCommandMixin): + + """ + Abstract base class for commands with the index_group options. + + This also corresponds to the commands that permit the pip version check. + """ + + def handle_pip_version_check(self, options): + # type: (Values) -> None + """ + Do the pip version check if not disabled. + + This overrides the default behavior of not doing the check. + """ + # Make sure the index_group options are present. + assert hasattr(options, 'no_index') + + if options.disable_pip_version_check or options.no_index: + return + + # Otherwise, check if we're using the latest version of pip available. + session = self._build_session( + options, + retries=0, + timeout=min(5, options.timeout) + ) + with session: + pip_self_version_check(session, options) + + +KEEPABLE_TEMPDIR_TYPES = [ + tempdir_kinds.BUILD_ENV, + tempdir_kinds.EPHEM_WHEEL_CACHE, + tempdir_kinds.REQ_BUILD, +] + + +def with_cleanup(func): + # type: (Any) -> Any + """Decorator for common logic related to managing temporary + directories. + """ + def configure_tempdir_registry(registry): + # type: (TempDirectoryTypeRegistry) -> None + for t in KEEPABLE_TEMPDIR_TYPES: + registry.set_delete(t, False) + + def wrapper(self, options, args): + # type: (RequirementCommand, Values, List[Any]) -> Optional[int] + assert self.tempdir_registry is not None + if options.no_clean: + configure_tempdir_registry(self.tempdir_registry) + + try: + return func(self, options, args) + except PreviousBuildDirError: + # This kind of conflict can occur when the user passes an explicit + # build directory with a pre-existing folder. In that case we do + # not want to accidentally remove it. + configure_tempdir_registry(self.tempdir_registry) + raise + + return wrapper + + +class RequirementCommand(IndexGroupCommand): + + def __init__(self, *args, **kw): + # type: (Any, Any) -> None + super(RequirementCommand, self).__init__(*args, **kw) + + self.cmd_opts.add_option(cmdoptions.no_clean()) + + @staticmethod + def make_requirement_preparer( + temp_build_dir, # type: TempDirectory + options, # type: Values + req_tracker, # type: RequirementTracker + session, # type: PipSession + finder, # type: PackageFinder + use_user_site, # type: bool + download_dir=None, # type: str + wheel_download_dir=None, # type: str + ): + # type: (...) -> RequirementPreparer + """ + Create a RequirementPreparer instance for the given parameters. + """ + downloader = Downloader(session, progress_bar=options.progress_bar) + + temp_build_dir_path = temp_build_dir.path + assert temp_build_dir_path is not None + + return RequirementPreparer( + build_dir=temp_build_dir_path, + src_dir=options.src_dir, + download_dir=download_dir, + wheel_download_dir=wheel_download_dir, + build_isolation=options.build_isolation, + req_tracker=req_tracker, + downloader=downloader, + finder=finder, + require_hashes=options.require_hashes, + use_user_site=use_user_site, + ) + + @staticmethod + def make_resolver( + preparer, # type: RequirementPreparer + finder, # type: PackageFinder + options, # type: Values + wheel_cache=None, # type: Optional[WheelCache] + use_user_site=False, # type: bool + ignore_installed=True, # type: bool + ignore_requires_python=False, # type: bool + force_reinstall=False, # type: bool + upgrade_strategy="to-satisfy-only", # type: str + use_pep517=None, # type: Optional[bool] + py_version_info=None # type: Optional[Tuple[int, ...]] + ): + # type: (...) -> BaseResolver + """ + Create a Resolver instance for the given parameters. + """ + make_install_req = partial( + install_req_from_req_string, + isolated=options.isolated_mode, + use_pep517=use_pep517, + ) + # The long import name and duplicated invocation is needed to convince + # Mypy into correctly typechecking. Otherwise it would complain the + # "Resolver" class being redefined. + if 'resolver' in options.unstable_features: + import pip._internal.resolution.resolvelib.resolver + return pip._internal.resolution.resolvelib.resolver.Resolver( + preparer=preparer, + finder=finder, + wheel_cache=wheel_cache, + make_install_req=make_install_req, + use_user_site=use_user_site, + ignore_dependencies=options.ignore_dependencies, + ignore_installed=ignore_installed, + ignore_requires_python=ignore_requires_python, + force_reinstall=force_reinstall, + upgrade_strategy=upgrade_strategy, + py_version_info=py_version_info, + ) + import pip._internal.resolution.legacy.resolver + return pip._internal.resolution.legacy.resolver.Resolver( + preparer=preparer, + finder=finder, + wheel_cache=wheel_cache, + make_install_req=make_install_req, + use_user_site=use_user_site, + ignore_dependencies=options.ignore_dependencies, + ignore_installed=ignore_installed, + ignore_requires_python=ignore_requires_python, + force_reinstall=force_reinstall, + upgrade_strategy=upgrade_strategy, + py_version_info=py_version_info, + ) + + def get_requirements( + self, + args, # type: List[str] + options, # type: Values + finder, # type: PackageFinder + session, # type: PipSession + check_supported_wheels=True, # type: bool + ): + # type: (...) -> List[InstallRequirement] + """ + Parse command-line arguments into the corresponding requirements. + """ + requirement_set = RequirementSet( + check_supported_wheels=check_supported_wheels + ) + for filename in options.constraints: + for parsed_req in parse_requirements( + filename, + constraint=True, finder=finder, options=options, + session=session): + req_to_add = install_req_from_parsed_requirement( + parsed_req, + isolated=options.isolated_mode, + ) + req_to_add.is_direct = True + requirement_set.add_requirement(req_to_add) + + for req in args: + req_to_add = install_req_from_line( + req, None, isolated=options.isolated_mode, + use_pep517=options.use_pep517, + ) + req_to_add.is_direct = True + requirement_set.add_requirement(req_to_add) + + for req in options.editables: + req_to_add = install_req_from_editable( + req, + isolated=options.isolated_mode, + use_pep517=options.use_pep517, + ) + req_to_add.is_direct = True + requirement_set.add_requirement(req_to_add) + + # NOTE: options.require_hashes may be set if --require-hashes is True + for filename in options.requirements: + for parsed_req in parse_requirements( + filename, + finder=finder, options=options, session=session): + req_to_add = install_req_from_parsed_requirement( + parsed_req, + isolated=options.isolated_mode, + use_pep517=options.use_pep517 + ) + req_to_add.is_direct = True + requirement_set.add_requirement(req_to_add) + + # If any requirement has hash options, enable hash checking. + requirements = requirement_set.all_requirements + if any(req.has_hash_options for req in requirements): + options.require_hashes = True + + if not (args or options.editables or options.requirements): + opts = {'name': self.name} + if options.find_links: + raise CommandError( + 'You must give at least one requirement to {name} ' + '(maybe you meant "pip {name} {links}"?)'.format( + **dict(opts, links=' '.join(options.find_links)))) + else: + raise CommandError( + 'You must give at least one requirement to {name} ' + '(see "pip help {name}")'.format(**opts)) + + return requirements + + @staticmethod + def trace_basic_info(finder): + # type: (PackageFinder) -> None + """ + Trace basic information about the provided objects. + """ + # Display where finder is looking for packages + search_scope = finder.search_scope + locations = search_scope.get_formatted_locations() + if locations: + logger.info(locations) + + def _build_package_finder( + self, + options, # type: Values + session, # type: PipSession + target_python=None, # type: Optional[TargetPython] + ignore_requires_python=None, # type: Optional[bool] + ): + # type: (...) -> PackageFinder + """ + Create a package finder appropriate to this requirement command. + + :param ignore_requires_python: Whether to ignore incompatible + "Requires-Python" values in links. Defaults to False. + """ + link_collector = make_link_collector(session, options=options) + selection_prefs = SelectionPreferences( + allow_yanked=True, + format_control=options.format_control, + allow_all_prereleases=options.pre, + prefer_binary=options.prefer_binary, + ignore_requires_python=ignore_requires_python, + ) + + return PackageFinder.create( + link_collector=link_collector, + selection_prefs=selection_prefs, + target_python=target_python, + ) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/cli/spinners.py b/venv/lib/python3.8/site-packages/pip/_internal/cli/spinners.py new file mode 100644 index 0000000..c6c4c5c --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/cli/spinners.py @@ -0,0 +1,173 @@ +from __future__ import absolute_import, division + +import contextlib +import itertools +import logging +import sys +import time + +from pip._vendor.progress import HIDE_CURSOR, SHOW_CURSOR + +from pip._internal.utils.compat import WINDOWS +from pip._internal.utils.logging import get_indentation +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Iterator, IO + +logger = logging.getLogger(__name__) + + +class SpinnerInterface(object): + def spin(self): + # type: () -> None + raise NotImplementedError() + + def finish(self, final_status): + # type: (str) -> None + raise NotImplementedError() + + +class InteractiveSpinner(SpinnerInterface): + def __init__(self, message, file=None, spin_chars="-\\|/", + # Empirically, 8 updates/second looks nice + min_update_interval_seconds=0.125): + # type: (str, IO[str], str, float) -> None + self._message = message + if file is None: + file = sys.stdout + self._file = file + self._rate_limiter = RateLimiter(min_update_interval_seconds) + self._finished = False + + self._spin_cycle = itertools.cycle(spin_chars) + + self._file.write(" " * get_indentation() + self._message + " ... ") + self._width = 0 + + def _write(self, status): + # type: (str) -> None + assert not self._finished + # Erase what we wrote before by backspacing to the beginning, writing + # spaces to overwrite the old text, and then backspacing again + backup = "\b" * self._width + self._file.write(backup + " " * self._width + backup) + # Now we have a blank slate to add our status + self._file.write(status) + self._width = len(status) + self._file.flush() + self._rate_limiter.reset() + + def spin(self): + # type: () -> None + if self._finished: + return + if not self._rate_limiter.ready(): + return + self._write(next(self._spin_cycle)) + + def finish(self, final_status): + # type: (str) -> None + if self._finished: + return + self._write(final_status) + self._file.write("\n") + self._file.flush() + self._finished = True + + +# Used for dumb terminals, non-interactive installs (no tty), etc. +# We still print updates occasionally (once every 60 seconds by default) to +# act as a keep-alive for systems like Travis-CI that take lack-of-output as +# an indication that a task has frozen. +class NonInteractiveSpinner(SpinnerInterface): + def __init__(self, message, min_update_interval_seconds=60): + # type: (str, float) -> None + self._message = message + self._finished = False + self._rate_limiter = RateLimiter(min_update_interval_seconds) + self._update("started") + + def _update(self, status): + # type: (str) -> None + assert not self._finished + self._rate_limiter.reset() + logger.info("%s: %s", self._message, status) + + def spin(self): + # type: () -> None + if self._finished: + return + if not self._rate_limiter.ready(): + return + self._update("still running...") + + def finish(self, final_status): + # type: (str) -> None + if self._finished: + return + self._update( + "finished with status '{final_status}'".format(**locals())) + self._finished = True + + +class RateLimiter(object): + def __init__(self, min_update_interval_seconds): + # type: (float) -> None + self._min_update_interval_seconds = min_update_interval_seconds + self._last_update = 0 # type: float + + def ready(self): + # type: () -> bool + now = time.time() + delta = now - self._last_update + return delta >= self._min_update_interval_seconds + + def reset(self): + # type: () -> None + self._last_update = time.time() + + +@contextlib.contextmanager +def open_spinner(message): + # type: (str) -> Iterator[SpinnerInterface] + # Interactive spinner goes directly to sys.stdout rather than being routed + # through the logging system, but it acts like it has level INFO, + # i.e. it's only displayed if we're at level INFO or better. + # Non-interactive spinner goes through the logging system, so it is always + # in sync with logging configuration. + if sys.stdout.isatty() and logger.getEffectiveLevel() <= logging.INFO: + spinner = InteractiveSpinner(message) # type: SpinnerInterface + else: + spinner = NonInteractiveSpinner(message) + try: + with hidden_cursor(sys.stdout): + yield spinner + except KeyboardInterrupt: + spinner.finish("canceled") + raise + except Exception: + spinner.finish("error") + raise + else: + spinner.finish("done") + + +@contextlib.contextmanager +def hidden_cursor(file): + # type: (IO[str]) -> Iterator[None] + # The Windows terminal does not support the hide/show cursor ANSI codes, + # even via colorama. So don't even try. + if WINDOWS: + yield + # We don't want to clutter the output with control characters if we're + # writing to a file, or if the user is running with --quiet. + # See https://github.com/pypa/pip/issues/3418 + elif not file.isatty() or logger.getEffectiveLevel() > logging.INFO: + yield + else: + file.write(HIDE_CURSOR) + try: + yield + finally: + file.write(SHOW_CURSOR) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/cli/status_codes.py b/venv/lib/python3.8/site-packages/pip/_internal/cli/status_codes.py new file mode 100644 index 0000000..275360a --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/cli/status_codes.py @@ -0,0 +1,8 @@ +from __future__ import absolute_import + +SUCCESS = 0 +ERROR = 1 +UNKNOWN_ERROR = 2 +VIRTUALENV_NOT_FOUND = 3 +PREVIOUS_BUILD_DIR_ERROR = 4 +NO_MATCHES_FOUND = 23 diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/__init__.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/__init__.py new file mode 100644 index 0000000..6825fa6 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/commands/__init__.py @@ -0,0 +1,122 @@ +""" +Package containing all pip commands +""" + +# The following comment should be removed at some point in the future. +# mypy: disallow-untyped-defs=False +# There is currently a bug in python/typeshed mentioned at +# https://github.com/python/typeshed/issues/3906 which causes the +# return type of difflib.get_close_matches to be reported +# as List[Sequence[str]] whereas it should have been List[str] + +from __future__ import absolute_import + +import importlib +from collections import OrderedDict, namedtuple + +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Any + from pip._internal.cli.base_command import Command + + +CommandInfo = namedtuple('CommandInfo', 'module_path, class_name, summary') + +# The ordering matters for help display. +# Also, even though the module path starts with the same +# "pip._internal.commands" prefix in each case, we include the full path +# because it makes testing easier (specifically when modifying commands_dict +# in test setup / teardown by adding info for a FakeCommand class defined +# in a test-related module). +# Finally, we need to pass an iterable of pairs here rather than a dict +# so that the ordering won't be lost when using Python 2.7. +commands_dict = OrderedDict([ + ('install', CommandInfo( + 'pip._internal.commands.install', 'InstallCommand', + 'Install packages.', + )), + ('download', CommandInfo( + 'pip._internal.commands.download', 'DownloadCommand', + 'Download packages.', + )), + ('uninstall', CommandInfo( + 'pip._internal.commands.uninstall', 'UninstallCommand', + 'Uninstall packages.', + )), + ('freeze', CommandInfo( + 'pip._internal.commands.freeze', 'FreezeCommand', + 'Output installed packages in requirements format.', + )), + ('list', CommandInfo( + 'pip._internal.commands.list', 'ListCommand', + 'List installed packages.', + )), + ('show', CommandInfo( + 'pip._internal.commands.show', 'ShowCommand', + 'Show information about installed packages.', + )), + ('check', CommandInfo( + 'pip._internal.commands.check', 'CheckCommand', + 'Verify installed packages have compatible dependencies.', + )), + ('config', CommandInfo( + 'pip._internal.commands.configuration', 'ConfigurationCommand', + 'Manage local and global configuration.', + )), + ('search', CommandInfo( + 'pip._internal.commands.search', 'SearchCommand', + 'Search PyPI for packages.', + )), + ('cache', CommandInfo( + 'pip._internal.commands.cache', 'CacheCommand', + "Inspect and manage pip's wheel cache.", + )), + ('wheel', CommandInfo( + 'pip._internal.commands.wheel', 'WheelCommand', + 'Build wheels from your requirements.', + )), + ('hash', CommandInfo( + 'pip._internal.commands.hash', 'HashCommand', + 'Compute hashes of package archives.', + )), + ('completion', CommandInfo( + 'pip._internal.commands.completion', 'CompletionCommand', + 'A helper command used for command completion.', + )), + ('debug', CommandInfo( + 'pip._internal.commands.debug', 'DebugCommand', + 'Show information useful for debugging.', + )), + ('help', CommandInfo( + 'pip._internal.commands.help', 'HelpCommand', + 'Show help for commands.', + )), +]) # type: OrderedDict[str, CommandInfo] + + +def create_command(name, **kwargs): + # type: (str, **Any) -> Command + """ + Create an instance of the Command class with the given name. + """ + module_path, class_name, summary = commands_dict[name] + module = importlib.import_module(module_path) + command_class = getattr(module, class_name) + command = command_class(name=name, summary=summary, **kwargs) + + return command + + +def get_similar_commands(name): + """Command name auto-correct.""" + from difflib import get_close_matches + + name = name.lower() + + close_commands = get_close_matches(name, commands_dict.keys()) + + if close_commands: + return close_commands[0] + else: + return False diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/cache.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/cache.py new file mode 100644 index 0000000..ca6d437 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/commands/cache.py @@ -0,0 +1,181 @@ +from __future__ import absolute_import + +import logging +import os +import textwrap + +import pip._internal.utils.filesystem as filesystem +from pip._internal.cli.base_command import Command +from pip._internal.cli.status_codes import ERROR, SUCCESS +from pip._internal.exceptions import CommandError, PipError +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from optparse import Values + from typing import Any, List + + +logger = logging.getLogger(__name__) + + +class CacheCommand(Command): + """ + Inspect and manage pip's wheel cache. + + Subcommands: + + dir: Show the cache directory. + info: Show information about the cache. + list: List filenames of packages stored in the cache. + remove: Remove one or more package from the cache. + purge: Remove all items from the cache. + + can be a glob expression or a package name. + """ + + ignore_require_venv = True + usage = """ + %prog dir + %prog info + %prog list [] + %prog remove + %prog purge + """ + + def run(self, options, args): + # type: (Values, List[Any]) -> int + handlers = { + "dir": self.get_cache_dir, + "info": self.get_cache_info, + "list": self.list_cache_items, + "remove": self.remove_cache_items, + "purge": self.purge_cache, + } + + if not options.cache_dir: + logger.error("pip cache commands can not " + "function since cache is disabled.") + return ERROR + + # Determine action + if not args or args[0] not in handlers: + logger.error("Need an action ({}) to perform.".format( + ", ".join(sorted(handlers))) + ) + return ERROR + + action = args[0] + + # Error handling happens here, not in the action-handlers. + try: + handlers[action](options, args[1:]) + except PipError as e: + logger.error(e.args[0]) + return ERROR + + return SUCCESS + + def get_cache_dir(self, options, args): + # type: (Values, List[Any]) -> None + if args: + raise CommandError('Too many arguments') + + logger.info(options.cache_dir) + + def get_cache_info(self, options, args): + # type: (Values, List[Any]) -> None + if args: + raise CommandError('Too many arguments') + + num_packages = len(self._find_wheels(options, '*')) + + cache_location = self._wheels_cache_dir(options) + cache_size = filesystem.format_directory_size(cache_location) + + message = textwrap.dedent(""" + Location: {location} + Size: {size} + Number of wheels: {package_count} + """).format( + location=cache_location, + package_count=num_packages, + size=cache_size, + ).strip() + + logger.info(message) + + def list_cache_items(self, options, args): + # type: (Values, List[Any]) -> None + if len(args) > 1: + raise CommandError('Too many arguments') + + if args: + pattern = args[0] + else: + pattern = '*' + + files = self._find_wheels(options, pattern) + + if not files: + logger.info('Nothing cached.') + return + + results = [] + for filename in files: + wheel = os.path.basename(filename) + size = filesystem.format_file_size(filename) + results.append(' - {} ({})'.format(wheel, size)) + logger.info('Cache contents:\n') + logger.info('\n'.join(sorted(results))) + + def remove_cache_items(self, options, args): + # type: (Values, List[Any]) -> None + if len(args) > 1: + raise CommandError('Too many arguments') + + if not args: + raise CommandError('Please provide a pattern') + + files = self._find_wheels(options, args[0]) + if not files: + raise CommandError('No matching packages') + + for filename in files: + os.unlink(filename) + logger.debug('Removed %s', filename) + logger.info('Files removed: %s', len(files)) + + def purge_cache(self, options, args): + # type: (Values, List[Any]) -> None + if args: + raise CommandError('Too many arguments') + + return self.remove_cache_items(options, ['*']) + + def _wheels_cache_dir(self, options): + # type: (Values) -> str + return os.path.join(options.cache_dir, 'wheels') + + def _find_wheels(self, options, pattern): + # type: (Values, str) -> List[str] + wheel_dir = self._wheels_cache_dir(options) + + # The wheel filename format, as specified in PEP 427, is: + # {distribution}-{version}(-{build})?-{python}-{abi}-{platform}.whl + # + # Additionally, non-alphanumeric values in the distribution are + # normalized to underscores (_), meaning hyphens can never occur + # before `-{version}`. + # + # Given that information: + # - If the pattern we're given contains a hyphen (-), the user is + # providing at least the version. Thus, we can just append `*.whl` + # to match the rest of it. + # - If the pattern we're given doesn't contain a hyphen (-), the + # user is only providing the name. Thus, we append `-*.whl` to + # match the hyphen before the version, followed by anything else. + # + # PEP 427: https://www.python.org/dev/peps/pep-0427/ + pattern = pattern + ("*.whl" if "-" in pattern else "-*.whl") + + return filesystem.find_files(wheel_dir, pattern) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/check.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/check.py new file mode 100644 index 0000000..b557ca6 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/commands/check.py @@ -0,0 +1,51 @@ +import logging + +from pip._internal.cli.base_command import Command +from pip._internal.cli.status_codes import ERROR, SUCCESS +from pip._internal.operations.check import ( + check_package_set, + create_package_set_from_installed, +) +from pip._internal.utils.misc import write_output +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +logger = logging.getLogger(__name__) + +if MYPY_CHECK_RUNNING: + from typing import List, Any + from optparse import Values + + +class CheckCommand(Command): + """Verify installed packages have compatible dependencies.""" + + usage = """ + %prog [options]""" + + def run(self, options, args): + # type: (Values, List[Any]) -> int + + package_set, parsing_probs = create_package_set_from_installed() + missing, conflicting = check_package_set(package_set) + + for project_name in missing: + version = package_set[project_name].version + for dependency in missing[project_name]: + write_output( + "%s %s requires %s, which is not installed.", + project_name, version, dependency[0], + ) + + for project_name in conflicting: + version = package_set[project_name].version + for dep_name, dep_version, req in conflicting[project_name]: + write_output( + "%s %s has requirement %s, but you have %s %s.", + project_name, version, req, dep_name, dep_version, + ) + + if missing or conflicting or parsing_probs: + return ERROR + else: + write_output("No broken requirements found.") + return SUCCESS diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/completion.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/completion.py new file mode 100644 index 0000000..910fcbf --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/commands/completion.py @@ -0,0 +1,95 @@ +# The following comment should be removed at some point in the future. +# mypy: disallow-untyped-defs=False + +from __future__ import absolute_import + +import sys +import textwrap + +from pip._internal.cli.base_command import Command +from pip._internal.utils.misc import get_prog + +BASE_COMPLETION = """ +# pip {shell} completion start{script}# pip {shell} completion end +""" + +COMPLETION_SCRIPTS = { + 'bash': """ + _pip_completion() + {{ + COMPREPLY=( $( COMP_WORDS="${{COMP_WORDS[*]}}" \\ + COMP_CWORD=$COMP_CWORD \\ + PIP_AUTO_COMPLETE=1 $1 2>/dev/null ) ) + }} + complete -o default -F _pip_completion {prog} + """, + 'zsh': """ + function _pip_completion {{ + local words cword + read -Ac words + read -cn cword + reply=( $( COMP_WORDS="$words[*]" \\ + COMP_CWORD=$(( cword-1 )) \\ + PIP_AUTO_COMPLETE=1 $words[1] 2>/dev/null )) + }} + compctl -K _pip_completion {prog} + """, + 'fish': """ + function __fish_complete_pip + set -lx COMP_WORDS (commandline -o) "" + set -lx COMP_CWORD ( \\ + math (contains -i -- (commandline -t) $COMP_WORDS)-1 \\ + ) + set -lx PIP_AUTO_COMPLETE 1 + string split \\ -- (eval $COMP_WORDS[1]) + end + complete -fa "(__fish_complete_pip)" -c {prog} + """, +} + + +class CompletionCommand(Command): + """A helper command to be used for command completion.""" + + ignore_require_venv = True + + def __init__(self, *args, **kw): + super(CompletionCommand, self).__init__(*args, **kw) + + cmd_opts = self.cmd_opts + + cmd_opts.add_option( + '--bash', '-b', + action='store_const', + const='bash', + dest='shell', + help='Emit completion code for bash') + cmd_opts.add_option( + '--zsh', '-z', + action='store_const', + const='zsh', + dest='shell', + help='Emit completion code for zsh') + cmd_opts.add_option( + '--fish', '-f', + action='store_const', + const='fish', + dest='shell', + help='Emit completion code for fish') + + self.parser.insert_option_group(0, cmd_opts) + + def run(self, options, args): + """Prints the completion code of the given shell""" + shells = COMPLETION_SCRIPTS.keys() + shell_options = ['--' + shell for shell in sorted(shells)] + if options.shell in shells: + script = textwrap.dedent( + COMPLETION_SCRIPTS.get(options.shell, '').format( + prog=get_prog()) + ) + print(BASE_COMPLETION.format(script=script, shell=options.shell)) + else: + sys.stderr.write( + 'ERROR: You must pass {}\n' .format(' or '.join(shell_options)) + ) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/configuration.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/configuration.py new file mode 100644 index 0000000..b801be6 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/commands/configuration.py @@ -0,0 +1,233 @@ +# The following comment should be removed at some point in the future. +# mypy: disallow-untyped-defs=False + +import logging +import os +import subprocess + +from pip._internal.cli.base_command import Command +from pip._internal.cli.status_codes import ERROR, SUCCESS +from pip._internal.configuration import ( + Configuration, + get_configuration_files, + kinds, +) +from pip._internal.exceptions import PipError +from pip._internal.utils.misc import get_prog, write_output + +logger = logging.getLogger(__name__) + + +class ConfigurationCommand(Command): + """Manage local and global configuration. + + Subcommands: + + list: List the active configuration (or from the file specified) + edit: Edit the configuration file in an editor + get: Get the value associated with name + set: Set the name=value + unset: Unset the value associated with name + + If none of --user, --global and --site are passed, a virtual + environment configuration file is used if one is active and the file + exists. Otherwise, all modifications happen on the to the user file by + default. + """ + + ignore_require_venv = True + usage = """ + %prog [] list + %prog [] [--editor ] edit + + %prog [] get name + %prog [] set name value + %prog [] unset name + """ + + def __init__(self, *args, **kwargs): + super(ConfigurationCommand, self).__init__(*args, **kwargs) + + self.configuration = None + + self.cmd_opts.add_option( + '--editor', + dest='editor', + action='store', + default=None, + help=( + 'Editor to use to edit the file. Uses VISUAL or EDITOR ' + 'environment variables if not provided.' + ) + ) + + self.cmd_opts.add_option( + '--global', + dest='global_file', + action='store_true', + default=False, + help='Use the system-wide configuration file only' + ) + + self.cmd_opts.add_option( + '--user', + dest='user_file', + action='store_true', + default=False, + help='Use the user configuration file only' + ) + + self.cmd_opts.add_option( + '--site', + dest='site_file', + action='store_true', + default=False, + help='Use the current environment configuration file only' + ) + + self.parser.insert_option_group(0, self.cmd_opts) + + def run(self, options, args): + handlers = { + "list": self.list_values, + "edit": self.open_in_editor, + "get": self.get_name, + "set": self.set_name_value, + "unset": self.unset_name + } + + # Determine action + if not args or args[0] not in handlers: + logger.error("Need an action ({}) to perform.".format( + ", ".join(sorted(handlers))) + ) + return ERROR + + action = args[0] + + # Determine which configuration files are to be loaded + # Depends on whether the command is modifying. + try: + load_only = self._determine_file( + options, need_value=(action in ["get", "set", "unset", "edit"]) + ) + except PipError as e: + logger.error(e.args[0]) + return ERROR + + # Load a new configuration + self.configuration = Configuration( + isolated=options.isolated_mode, load_only=load_only + ) + self.configuration.load() + + # Error handling happens here, not in the action-handlers. + try: + handlers[action](options, args[1:]) + except PipError as e: + logger.error(e.args[0]) + return ERROR + + return SUCCESS + + def _determine_file(self, options, need_value): + file_options = [key for key, value in ( + (kinds.USER, options.user_file), + (kinds.GLOBAL, options.global_file), + (kinds.SITE, options.site_file), + ) if value] + + if not file_options: + if not need_value: + return None + # Default to user, unless there's a site file. + elif any( + os.path.exists(site_config_file) + for site_config_file in get_configuration_files()[kinds.SITE] + ): + return kinds.SITE + else: + return kinds.USER + elif len(file_options) == 1: + return file_options[0] + + raise PipError( + "Need exactly one file to operate upon " + "(--user, --site, --global) to perform." + ) + + def list_values(self, options, args): + self._get_n_args(args, "list", n=0) + + for key, value in sorted(self.configuration.items()): + write_output("%s=%r", key, value) + + def get_name(self, options, args): + key = self._get_n_args(args, "get [name]", n=1) + value = self.configuration.get_value(key) + + write_output("%s", value) + + def set_name_value(self, options, args): + key, value = self._get_n_args(args, "set [name] [value]", n=2) + self.configuration.set_value(key, value) + + self._save_configuration() + + def unset_name(self, options, args): + key = self._get_n_args(args, "unset [name]", n=1) + self.configuration.unset_value(key) + + self._save_configuration() + + def open_in_editor(self, options, args): + editor = self._determine_editor(options) + + fname = self.configuration.get_file_to_edit() + if fname is None: + raise PipError("Could not determine appropriate file.") + + try: + subprocess.check_call([editor, fname]) + except subprocess.CalledProcessError as e: + raise PipError( + "Editor Subprocess exited with exit code {}" + .format(e.returncode) + ) + + def _get_n_args(self, args, example, n): + """Helper to make sure the command got the right number of arguments + """ + if len(args) != n: + msg = ( + 'Got unexpected number of arguments, expected {}. ' + '(example: "{} config {}")' + ).format(n, get_prog(), example) + raise PipError(msg) + + if n == 1: + return args[0] + else: + return args + + def _save_configuration(self): + # We successfully ran a modifying command. Need to save the + # configuration. + try: + self.configuration.save() + except Exception: + logger.error( + "Unable to save configuration. Please report this as a bug.", + exc_info=1 + ) + raise PipError("Internal Error.") + + def _determine_editor(self, options): + if options.editor is not None: + return options.editor + elif "VISUAL" in os.environ: + return os.environ["VISUAL"] + elif "EDITOR" in os.environ: + return os.environ["EDITOR"] + else: + raise PipError("Could not determine editor to use.") diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/debug.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/debug.py new file mode 100644 index 0000000..665ffe9 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/commands/debug.py @@ -0,0 +1,258 @@ +# The following comment should be removed at some point in the future. +# mypy: disallow-untyped-defs=False + +from __future__ import absolute_import + +import locale +import logging +import os +import sys + +import pip._vendor +from pip._vendor import pkg_resources +from pip._vendor.certifi import where + +from pip import __file__ as pip_location +from pip._internal.cli import cmdoptions +from pip._internal.cli.base_command import Command +from pip._internal.cli.cmdoptions import make_target_python +from pip._internal.cli.status_codes import SUCCESS +from pip._internal.utils.logging import indent_log +from pip._internal.utils.misc import get_pip_version +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from types import ModuleType + from typing import Any, List, Optional, Dict + from optparse import Values + +logger = logging.getLogger(__name__) + + +def show_value(name, value): + # type: (str, Optional[str]) -> None + logger.info('{}: {}'.format(name, value)) + + +def show_sys_implementation(): + # type: () -> None + logger.info('sys.implementation:') + if hasattr(sys, 'implementation'): + implementation = sys.implementation # type: ignore + implementation_name = implementation.name + else: + implementation_name = '' + + with indent_log(): + show_value('name', implementation_name) + + +def create_vendor_txt_map(): + # type: () -> Dict[str, str] + vendor_txt_path = os.path.join( + os.path.dirname(pip_location), + '_vendor', + 'vendor.txt' + ) + + with open(vendor_txt_path) as f: + # Purge non version specifying lines. + # Also, remove any space prefix or suffixes (including comments). + lines = [line.strip().split(' ', 1)[0] + for line in f.readlines() if '==' in line] + + # Transform into "module" -> version dict. + return dict(line.split('==', 1) for line in lines) # type: ignore + +def create_debundle_txt_map(): + # type: () -> Dict[str, str] + wheels = [fn for fn in os.listdir(pip._vendor.WHEEL_DIR)] + # Transform into "module" -> version dict. + return dict((wheel.split('-')[0], wheel.split('-')[1]) for wheel in wheels) # type: ignore + +def get_module_from_module_name(module_name): + # type: (str) -> ModuleType + + # Module name can be uppercase in vendor.txt for some reason... + module_name = module_name.lower() + # PATCH: setuptools is actually only pkg_resources. + if module_name == 'setuptools': + module_name = 'pkg_resources' + + __import__( + 'pip._vendor.{}'.format(module_name), + globals(), + locals(), + level=0 + ) + return getattr(pip._vendor, module_name) + + +def get_vendor_version_from_module(module_name): + # type: (str) -> str + + module = get_module_from_module_name(module_name) + version = getattr(module, '__version__', None) + + if not version: + # Try to find version in debundled module info + pkg_set = pkg_resources.WorkingSet( + [os.path.dirname(getattr(module, '__file__'))] + ) + package = pkg_set.find(pkg_resources.Requirement.parse(module_name)) + version = getattr(package, 'version', None) + + return version + + +def show_actual_vendor_versions(vendor_txt_versions): + # type: (Dict[str, str]) -> None + # Logs the actual version and print extra info + # if there is a conflict or if the actual version could not be imported. + + for module_name, expected_version in vendor_txt_versions.items(): + extra_message = '' + actual_version = get_vendor_version_from_module(module_name) + if not actual_version: + extra_message = ' (Unable to locate actual module version, using'\ + ' vendor.txt specified version)' + actual_version = expected_version + elif actual_version != expected_version: + extra_message = ' (CONFLICT: vendor.txt suggests version should'\ + ' be {})'.format(expected_version) + + logger.info( + '{name}=={actual}{extra}'.format( + name=module_name, + actual=actual_version, + extra=extra_message + ) + ) + + +def show_vendor_versions(): + # type: () -> None + logger.info('vendored library versions:') + + vendor_txt_versions = create_vendor_txt_map() + with indent_log(): + show_actual_vendor_versions(vendor_txt_versions) + +def show_debundled_versions(): + # type: () -> None + logger.info('debundled wheel versions:') + debundle_txt_versions = create_debundle_txt_map() + for module_name, installed_version in sorted(debundle_txt_versions.items()): + with indent_log(): + logger.info( + '{name}=={actual}'.format( + name=module_name, + actual=installed_version, + ) + ) + +def show_tags(options): + # type: (Values) -> None + tag_limit = 10 + + target_python = make_target_python(options) + tags = target_python.get_tags() + + # Display the target options that were explicitly provided. + formatted_target = target_python.format_given() + suffix = '' + if formatted_target: + suffix = ' (target: {})'.format(formatted_target) + + msg = 'Compatible tags: {}{}'.format(len(tags), suffix) + logger.info(msg) + + if options.verbose < 1 and len(tags) > tag_limit: + tags_limited = True + tags = tags[:tag_limit] + else: + tags_limited = False + + with indent_log(): + for tag in tags: + logger.info(str(tag)) + + if tags_limited: + msg = ( + '...\n' + '[First {tag_limit} tags shown. Pass --verbose to show all.]' + ).format(tag_limit=tag_limit) + logger.info(msg) + + +def ca_bundle_info(config): + levels = set() + for key, value in config.items(): + levels.add(key.split('.')[0]) + + if not levels: + return "Not specified" + + levels_that_override_global = ['install', 'wheel', 'download'] + global_overriding_level = [ + level for level in levels if level in levels_that_override_global + ] + if not global_overriding_level: + return 'global' + + if 'global' in levels: + levels.remove('global') + return ", ".join(levels) + + +class DebugCommand(Command): + """ + Display debug information. + """ + + usage = """ + %prog """ + ignore_require_venv = True + + def __init__(self, *args, **kw): + super(DebugCommand, self).__init__(*args, **kw) + + cmd_opts = self.cmd_opts + cmdoptions.add_target_python_options(cmd_opts) + self.parser.insert_option_group(0, cmd_opts) + self.parser.config.load() + + def run(self, options, args): + # type: (Values, List[Any]) -> int + logger.warning( + "This command is only meant for debugging. " + "Do not use this with automation for parsing and getting these " + "details, since the output and options of this command may " + "change without notice." + ) + show_value('pip version', get_pip_version()) + show_value('sys.version', sys.version) + show_value('sys.executable', sys.executable) + show_value('sys.getdefaultencoding', sys.getdefaultencoding()) + show_value('sys.getfilesystemencoding', sys.getfilesystemencoding()) + show_value( + 'locale.getpreferredencoding', locale.getpreferredencoding(), + ) + show_value('sys.platform', sys.platform) + show_sys_implementation() + + show_value("'cert' config value", ca_bundle_info(self.parser.config)) + show_value("REQUESTS_CA_BUNDLE", os.environ.get('REQUESTS_CA_BUNDLE')) + show_value("CURL_CA_BUNDLE", os.environ.get('CURL_CA_BUNDLE')) + show_value("pip._vendor.certifi.where()", where()) + show_value("pip._vendor.DEBUNDLED", pip._vendor.DEBUNDLED) + + if not pip._vendor.DEBUNDLED: + show_vendor_versions() + else: + show_value("pip._vendor.WHEEL_DIR", pip._vendor.WHEEL_DIR) + show_debundled_versions() + + show_tags(options) + + return SUCCESS diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/download.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/download.py new file mode 100644 index 0000000..c829550 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/commands/download.py @@ -0,0 +1,142 @@ +# The following comment should be removed at some point in the future. +# mypy: disallow-untyped-defs=False + +from __future__ import absolute_import + +import logging +import os + +from pip._internal.cli import cmdoptions +from pip._internal.cli.cmdoptions import make_target_python +from pip._internal.cli.req_command import RequirementCommand, with_cleanup +from pip._internal.req.req_tracker import get_requirement_tracker +from pip._internal.utils.misc import ensure_dir, normalize_path, write_output +from pip._internal.utils.temp_dir import TempDirectory + +logger = logging.getLogger(__name__) + + +class DownloadCommand(RequirementCommand): + """ + Download packages from: + + - PyPI (and other indexes) using requirement specifiers. + - VCS project urls. + - Local project directories. + - Local or remote source archives. + + pip also supports downloading from "requirements files", which provide + an easy way to specify a whole environment to be downloaded. + """ + + usage = """ + %prog [options] [package-index-options] ... + %prog [options] -r [package-index-options] ... + %prog [options] ... + %prog [options] ... + %prog [options] ...""" + + def __init__(self, *args, **kw): + super(DownloadCommand, self).__init__(*args, **kw) + + cmd_opts = self.cmd_opts + + cmd_opts.add_option(cmdoptions.constraints()) + cmd_opts.add_option(cmdoptions.requirements()) + cmd_opts.add_option(cmdoptions.build_dir()) + cmd_opts.add_option(cmdoptions.no_deps()) + cmd_opts.add_option(cmdoptions.global_options()) + cmd_opts.add_option(cmdoptions.no_binary()) + cmd_opts.add_option(cmdoptions.only_binary()) + cmd_opts.add_option(cmdoptions.prefer_binary()) + cmd_opts.add_option(cmdoptions.src()) + cmd_opts.add_option(cmdoptions.pre()) + cmd_opts.add_option(cmdoptions.require_hashes()) + cmd_opts.add_option(cmdoptions.progress_bar()) + cmd_opts.add_option(cmdoptions.no_build_isolation()) + cmd_opts.add_option(cmdoptions.use_pep517()) + cmd_opts.add_option(cmdoptions.no_use_pep517()) + + cmd_opts.add_option( + '-d', '--dest', '--destination-dir', '--destination-directory', + dest='download_dir', + metavar='dir', + default=os.curdir, + help=("Download packages into ."), + ) + + cmdoptions.add_target_python_options(cmd_opts) + + index_opts = cmdoptions.make_option_group( + cmdoptions.index_group, + self.parser, + ) + + self.parser.insert_option_group(0, index_opts) + self.parser.insert_option_group(0, cmd_opts) + + @with_cleanup + def run(self, options, args): + options.ignore_installed = True + # editable doesn't really make sense for `pip download`, but the bowels + # of the RequirementSet code require that property. + options.editables = [] + + cmdoptions.check_dist_restriction(options) + + options.download_dir = normalize_path(options.download_dir) + + ensure_dir(options.download_dir) + + session = self.get_default_session(options) + + target_python = make_target_python(options) + finder = self._build_package_finder( + options=options, + session=session, + target_python=target_python, + ) + build_delete = (not (options.no_clean or options.build_dir)) + + req_tracker = self.enter_context(get_requirement_tracker()) + + directory = TempDirectory( + options.build_dir, + delete=build_delete, + kind="download", + globally_managed=True, + ) + + reqs = self.get_requirements(args, options, finder, session) + + preparer = self.make_requirement_preparer( + temp_build_dir=directory, + options=options, + req_tracker=req_tracker, + session=session, + finder=finder, + download_dir=options.download_dir, + use_user_site=False, + ) + + resolver = self.make_resolver( + preparer=preparer, + finder=finder, + options=options, + py_version_info=options.python_version, + ) + + self.trace_basic_info(finder) + + requirement_set = resolver.resolve( + reqs, check_supported_wheels=True + ) + + downloaded = ' '.join([ + req.name for req in requirement_set.requirements.values() + if req.successfully_downloaded + ]) + if downloaded: + write_output('Successfully downloaded %s', downloaded) + + return requirement_set diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/freeze.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/freeze.py new file mode 100644 index 0000000..9e873a9 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/commands/freeze.py @@ -0,0 +1,99 @@ +# The following comment should be removed at some point in the future. +# mypy: disallow-untyped-defs=False + +from __future__ import absolute_import + +import sys + +from pip._internal.cache import WheelCache +from pip._internal.cli import cmdoptions +from pip._internal.cli.base_command import Command +from pip._internal.models.format_control import FormatControl +from pip._internal.operations.freeze import freeze +from pip._internal.utils.compat import stdlib_pkgs + +DEV_PKGS = {'pip', 'setuptools', 'distribute', 'wheel', 'pkg-resources'} + + +class FreezeCommand(Command): + """ + Output installed packages in requirements format. + + packages are listed in a case-insensitive sorted order. + """ + + usage = """ + %prog [options]""" + log_streams = ("ext://sys.stderr", "ext://sys.stderr") + + def __init__(self, *args, **kw): + super(FreezeCommand, self).__init__(*args, **kw) + + self.cmd_opts.add_option( + '-r', '--requirement', + dest='requirements', + action='append', + default=[], + metavar='file', + help="Use the order in the given requirements file and its " + "comments when generating output. This option can be " + "used multiple times.") + self.cmd_opts.add_option( + '-f', '--find-links', + dest='find_links', + action='append', + default=[], + metavar='URL', + help='URL for finding packages, which will be added to the ' + 'output.') + self.cmd_opts.add_option( + '-l', '--local', + dest='local', + action='store_true', + default=False, + help='If in a virtualenv that has global access, do not output ' + 'globally-installed packages.') + self.cmd_opts.add_option( + '--user', + dest='user', + action='store_true', + default=False, + help='Only output packages installed in user-site.') + self.cmd_opts.add_option(cmdoptions.list_path()) + self.cmd_opts.add_option( + '--all', + dest='freeze_all', + action='store_true', + help='Do not skip these packages in the output:' + ' {}'.format(', '.join(DEV_PKGS))) + self.cmd_opts.add_option( + '--exclude-editable', + dest='exclude_editable', + action='store_true', + help='Exclude editable package from output.') + + self.parser.insert_option_group(0, self.cmd_opts) + + def run(self, options, args): + format_control = FormatControl(set(), set()) + wheel_cache = WheelCache(options.cache_dir, format_control) + skip = set(stdlib_pkgs) + if not options.freeze_all: + skip.update(DEV_PKGS) + + cmdoptions.check_list_path_option(options) + + freeze_kwargs = dict( + requirement=options.requirements, + find_links=options.find_links, + local_only=options.local, + user_only=options.user, + paths=options.path, + isolated=options.isolated_mode, + wheel_cache=wheel_cache, + skip=skip, + exclude_editable=options.exclude_editable, + ) + + for line in freeze(**freeze_kwargs): + sys.stdout.write(line + '\n') diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/hash.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/hash.py new file mode 100644 index 0000000..f266861 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/commands/hash.py @@ -0,0 +1,58 @@ +# The following comment should be removed at some point in the future. +# mypy: disallow-untyped-defs=False + +from __future__ import absolute_import + +import hashlib +import logging +import sys + +from pip._internal.cli.base_command import Command +from pip._internal.cli.status_codes import ERROR +from pip._internal.utils.hashes import FAVORITE_HASH, STRONG_HASHES +from pip._internal.utils.misc import read_chunks, write_output + +logger = logging.getLogger(__name__) + + +class HashCommand(Command): + """ + Compute a hash of a local package archive. + + These can be used with --hash in a requirements file to do repeatable + installs. + """ + + usage = '%prog [options] ...' + ignore_require_venv = True + + def __init__(self, *args, **kw): + super(HashCommand, self).__init__(*args, **kw) + self.cmd_opts.add_option( + '-a', '--algorithm', + dest='algorithm', + choices=STRONG_HASHES, + action='store', + default=FAVORITE_HASH, + help='The hash algorithm to use: one of {}'.format( + ', '.join(STRONG_HASHES))) + self.parser.insert_option_group(0, self.cmd_opts) + + def run(self, options, args): + if not args: + self.parser.print_usage(sys.stderr) + return ERROR + + algorithm = options.algorithm + for path in args: + write_output('%s:\n--hash=%s:%s', + path, algorithm, _hash_of_file(path, algorithm)) + + +def _hash_of_file(path, algorithm): + """Return the hash digest of a file.""" + with open(path, 'rb') as archive: + hash = hashlib.new(algorithm) + for chunk in read_chunks(archive): + hash.update(chunk) + return hash.hexdigest() diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/help.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/help.py new file mode 100644 index 0000000..c17d7a4 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/commands/help.py @@ -0,0 +1,41 @@ +# The following comment should be removed at some point in the future. +# mypy: disallow-untyped-defs=False + +from __future__ import absolute_import + +from pip._internal.cli.base_command import Command +from pip._internal.cli.status_codes import SUCCESS +from pip._internal.exceptions import CommandError + + +class HelpCommand(Command): + """Show help for commands""" + + usage = """ + %prog """ + ignore_require_venv = True + + def run(self, options, args): + from pip._internal.commands import ( + commands_dict, create_command, get_similar_commands, + ) + + try: + # 'pip help' with no args is handled by pip.__init__.parseopt() + cmd_name = args[0] # the command we need help for + except IndexError: + return SUCCESS + + if cmd_name not in commands_dict: + guess = get_similar_commands(cmd_name) + + msg = ['unknown command "{}"'.format(cmd_name)] + if guess: + msg.append('maybe you meant "{}"'.format(guess)) + + raise CommandError(' - '.join(msg)) + + command = create_command(cmd_name) + command.parser.print_help() + + return SUCCESS diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/install.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/install.py new file mode 100644 index 0000000..b40f045 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/commands/install.py @@ -0,0 +1,717 @@ +# The following comment should be removed at some point in the future. +# It's included for now because without it InstallCommand.run() has a +# couple errors where we have to know req.name is str rather than +# Optional[str] for the InstallRequirement req. +# mypy: strict-optional=False +# mypy: disallow-untyped-defs=False + +from __future__ import absolute_import + +import errno +import logging +import operator +import os +import shutil +import site +from optparse import SUPPRESS_HELP + +from pip._vendor import pkg_resources +from pip._vendor.packaging.utils import canonicalize_name + +from pip._internal.cache import WheelCache +from pip._internal.cli import cmdoptions +from pip._internal.cli.cmdoptions import make_target_python +from pip._internal.cli.req_command import RequirementCommand, with_cleanup +from pip._internal.cli.status_codes import ERROR, SUCCESS +from pip._internal.exceptions import CommandError, InstallationError +from pip._internal.locations import distutils_scheme +from pip._internal.operations.check import check_install_conflicts +from pip._internal.req import install_given_reqs +from pip._internal.req.req_tracker import get_requirement_tracker +from pip._internal.utils.deprecation import deprecated +from pip._internal.utils.distutils_args import parse_distutils_args +from pip._internal.utils.filesystem import test_writable_dir +from pip._internal.utils.misc import ( + ensure_dir, + get_installed_version, + protect_pip_from_modification_on_windows, + write_output, +) +from pip._internal.utils.temp_dir import TempDirectory +from pip._internal.utils.typing import MYPY_CHECK_RUNNING +from pip._internal.utils.virtualenv import virtualenv_no_global +from pip._internal.wheel_builder import build, should_build_for_install_command + +if MYPY_CHECK_RUNNING: + from optparse import Values + from typing import Any, Iterable, List, Optional + + from pip._internal.models.format_control import FormatControl + from pip._internal.req.req_install import InstallRequirement + from pip._internal.wheel_builder import BinaryAllowedPredicate + +from pip._internal.locations import running_under_virtualenv + +logger = logging.getLogger(__name__) + + +def get_check_binary_allowed(format_control): + # type: (FormatControl) -> BinaryAllowedPredicate + def check_binary_allowed(req): + # type: (InstallRequirement) -> bool + if req.use_pep517: + return True + canonical_name = canonicalize_name(req.name) + allowed_formats = format_control.get_allowed_formats(canonical_name) + return "binary" in allowed_formats + + return check_binary_allowed + + +class InstallCommand(RequirementCommand): + """ + Install packages from: + + - PyPI (and other indexes) using requirement specifiers. + - VCS project urls. + - Local project directories. + - Local or remote source archives. + + pip also supports installing from "requirements files", which provide + an easy way to specify a whole environment to be installed. + """ + + usage = """ + %prog [options] [package-index-options] ... + %prog [options] -r [package-index-options] ... + %prog [options] [-e] ... + %prog [options] [-e] ... + %prog [options] ...""" + + def __init__(self, *args, **kw): + super(InstallCommand, self).__init__(*args, **kw) + + cmd_opts = self.cmd_opts + + cmd_opts.add_option(cmdoptions.requirements()) + cmd_opts.add_option(cmdoptions.constraints()) + cmd_opts.add_option(cmdoptions.no_deps()) + cmd_opts.add_option(cmdoptions.pre()) + + cmd_opts.add_option(cmdoptions.editable()) + cmd_opts.add_option( + '-t', '--target', + dest='target_dir', + metavar='dir', + default=None, + help='Install packages into . ' + 'By default this will not replace existing files/folders in ' + '. Use --upgrade to replace existing packages in ' + 'with new versions.' + ) + cmdoptions.add_target_python_options(cmd_opts) + + cmd_opts.add_option( + '--user', + dest='use_user_site', + action='store_true', + help="Install to the Python user install directory for your " + "platform. Typically ~/.local/, or %APPDATA%\\Python on " + "Windows. (See the Python documentation for site.USER_BASE " + "for full details.) On Debian systems, this is the " + "default when running outside of a virtual environment " + "and not as root.") + + cmd_opts.add_option( + '--no-user', + dest='use_system_location', + action='store_true', + help=SUPPRESS_HELP) + cmd_opts.add_option( + '--root', + dest='root_path', + metavar='dir', + default=None, + help="Install everything relative to this alternate root " + "directory.") + cmd_opts.add_option( + '--prefix', + dest='prefix_path', + metavar='dir', + default=None, + help="Installation prefix where lib, bin and other top-level " + "folders are placed") + + cmd_opts.add_option( + '--system', + dest='use_system_location', + action='store_true', + help="Install using the system scheme (overrides --user on " + "Debian systems)") + + cmd_opts.add_option(cmdoptions.build_dir()) + + cmd_opts.add_option(cmdoptions.src()) + + cmd_opts.add_option( + '-U', '--upgrade', + dest='upgrade', + action='store_true', + help='Upgrade all specified packages to the newest available ' + 'version. The handling of dependencies depends on the ' + 'upgrade-strategy used.' + ) + + cmd_opts.add_option( + '--upgrade-strategy', + dest='upgrade_strategy', + default='only-if-needed', + choices=['only-if-needed', 'eager'], + help='Determines how dependency upgrading should be handled ' + '[default: %default]. ' + '"eager" - dependencies are upgraded regardless of ' + 'whether the currently installed version satisfies the ' + 'requirements of the upgraded package(s). ' + '"only-if-needed" - are upgraded only when they do not ' + 'satisfy the requirements of the upgraded package(s).' + ) + + cmd_opts.add_option( + '--force-reinstall', + dest='force_reinstall', + action='store_true', + help='Reinstall all packages even if they are already ' + 'up-to-date.') + + cmd_opts.add_option( + '-I', '--ignore-installed', + dest='ignore_installed', + action='store_true', + help='Ignore the installed packages, overwriting them. ' + 'This can break your system if the existing package ' + 'is of a different version or was installed ' + 'with a different package manager!' + ) + + cmd_opts.add_option(cmdoptions.ignore_requires_python()) + cmd_opts.add_option(cmdoptions.no_build_isolation()) + cmd_opts.add_option(cmdoptions.use_pep517()) + cmd_opts.add_option(cmdoptions.no_use_pep517()) + + cmd_opts.add_option(cmdoptions.install_options()) + cmd_opts.add_option(cmdoptions.global_options()) + + cmd_opts.add_option( + "--compile", + action="store_true", + dest="compile", + default=True, + help="Compile Python source files to bytecode", + ) + + cmd_opts.add_option( + "--no-compile", + action="store_false", + dest="compile", + help="Do not compile Python source files to bytecode", + ) + + cmd_opts.add_option( + "--no-warn-script-location", + action="store_false", + dest="warn_script_location", + default=True, + help="Do not warn when installing scripts outside PATH", + ) + cmd_opts.add_option( + "--no-warn-conflicts", + action="store_false", + dest="warn_about_conflicts", + default=True, + help="Do not warn about broken dependencies", + ) + + cmd_opts.add_option(cmdoptions.no_binary()) + cmd_opts.add_option(cmdoptions.only_binary()) + cmd_opts.add_option(cmdoptions.prefer_binary()) + cmd_opts.add_option(cmdoptions.require_hashes()) + cmd_opts.add_option(cmdoptions.progress_bar()) + + index_opts = cmdoptions.make_option_group( + cmdoptions.index_group, + self.parser, + ) + + self.parser.insert_option_group(0, index_opts) + self.parser.insert_option_group(0, cmd_opts) + + @with_cleanup + def run(self, options, args): + # type: (Values, List[Any]) -> int + if options.use_user_site and options.target_dir is not None: + raise CommandError("Can not combine '--user' and '--target'") + + cmdoptions.check_install_build_global(options) + upgrade_strategy = "to-satisfy-only" + if options.upgrade: + upgrade_strategy = options.upgrade_strategy + + cmdoptions.check_dist_restriction(options, check_target=True) + + if options.python_version: + python_versions = [options.python_version] + else: + python_versions = None + + # compute install location defaults + if (not options.use_user_site and not options.prefix_path and not + options.target_dir and not options.use_system_location): + if not running_under_virtualenv() and os.geteuid() != 0: + options.use_user_site = True + + if options.use_system_location: + options.use_user_site = False + + options.src_dir = os.path.abspath(options.src_dir) + install_options = options.install_options or [] + + options.use_user_site = decide_user_install( + options.use_user_site, + prefix_path=options.prefix_path, + target_dir=options.target_dir, + root_path=options.root_path, + isolated_mode=options.isolated_mode, + ) + + target_temp_dir = None # type: Optional[TempDirectory] + target_temp_dir_path = None # type: Optional[str] + if options.target_dir: + options.ignore_installed = True + options.target_dir = os.path.abspath(options.target_dir) + if (os.path.exists(options.target_dir) and not + os.path.isdir(options.target_dir)): + raise CommandError( + "Target path exists but is not a directory, will not " + "continue." + ) + + # Create a target directory for using with the target option + target_temp_dir = TempDirectory(kind="target") + target_temp_dir_path = target_temp_dir.path + + global_options = options.global_options or [] + + session = self.get_default_session(options) + + target_python = make_target_python(options) + finder = self._build_package_finder( + options=options, + session=session, + target_python=target_python, + ignore_requires_python=options.ignore_requires_python, + ) + build_delete = (not (options.no_clean or options.build_dir)) + wheel_cache = WheelCache(options.cache_dir, options.format_control) + + req_tracker = self.enter_context(get_requirement_tracker()) + + directory = TempDirectory( + options.build_dir, + delete=build_delete, + kind="install", + globally_managed=True, + ) + + try: + reqs = self.get_requirements( + args, options, finder, session, + check_supported_wheels=not options.target_dir, + ) + + warn_deprecated_install_options( + reqs, options.install_options + ) + + preparer = self.make_requirement_preparer( + temp_build_dir=directory, + options=options, + req_tracker=req_tracker, + session=session, + finder=finder, + use_user_site=options.use_user_site, + ) + resolver = self.make_resolver( + preparer=preparer, + finder=finder, + options=options, + wheel_cache=wheel_cache, + use_user_site=options.use_user_site, + ignore_installed=options.ignore_installed, + ignore_requires_python=options.ignore_requires_python, + force_reinstall=options.force_reinstall, + upgrade_strategy=upgrade_strategy, + use_pep517=options.use_pep517, + ) + + self.trace_basic_info(finder) + + requirement_set = resolver.resolve( + reqs, check_supported_wheels=not options.target_dir + ) + + try: + pip_req = requirement_set.get_requirement("pip") + except KeyError: + modifying_pip = None + else: + # If we're not replacing an already installed pip, + # we're not modifying it. + modifying_pip = pip_req.satisfied_by is None + protect_pip_from_modification_on_windows( + modifying_pip=modifying_pip + ) + + check_binary_allowed = get_check_binary_allowed( + finder.format_control + ) + + reqs_to_build = [ + r for r in requirement_set.requirements.values() + if should_build_for_install_command( + r, check_binary_allowed + ) + ] + + _, build_failures = build( + reqs_to_build, + wheel_cache=wheel_cache, + build_options=[], + global_options=[], + ) + + # If we're using PEP 517, we cannot do a direct install + # so we fail here. + # We don't care about failures building legacy + # requirements, as we'll fall through to a direct + # install for those. + pep517_build_failures = [ + r for r in build_failures if r.use_pep517 + ] + if pep517_build_failures: + raise InstallationError( + "Could not build wheels for {} which use" + " PEP 517 and cannot be installed directly".format( + ", ".join(r.name for r in pep517_build_failures))) + + to_install = resolver.get_installation_order( + requirement_set + ) + + # Consistency Checking of the package set we're installing. + should_warn_about_conflicts = ( + not options.ignore_dependencies and + options.warn_about_conflicts + ) + if should_warn_about_conflicts: + self._warn_about_conflicts(to_install) + + # Don't warn about script install locations if + # --target has been specified + warn_script_location = options.warn_script_location + if options.target_dir: + warn_script_location = False + + installed = install_given_reqs( + to_install, + install_options, + global_options, + root=options.root_path, + home=target_temp_dir_path, + prefix=options.prefix_path, + pycompile=options.compile, + warn_script_location=warn_script_location, + use_user_site=options.use_user_site, + ) + + lib_locations = get_lib_location_guesses( + user=options.use_user_site, + home=target_temp_dir_path, + root=options.root_path, + prefix=options.prefix_path, + isolated=options.isolated_mode, + ) + working_set = pkg_resources.WorkingSet(lib_locations) + + installed.sort(key=operator.attrgetter('name')) + items = [] + for result in installed: + item = result.name + try: + installed_version = get_installed_version( + result.name, working_set=working_set + ) + if installed_version: + item += '-' + installed_version + except Exception: + pass + items.append(item) + installed_desc = ' '.join(items) + if installed_desc: + write_output( + 'Successfully installed %s', installed_desc, + ) + except EnvironmentError as error: + show_traceback = (self.verbosity >= 1) + + message = create_env_error_message( + error, show_traceback, options.use_user_site, + ) + logger.error(message, exc_info=show_traceback) + + return ERROR + + if options.target_dir: + self._handle_target_dir( + options.target_dir, target_temp_dir, options.upgrade + ) + + return SUCCESS + + def _handle_target_dir(self, target_dir, target_temp_dir, upgrade): + ensure_dir(target_dir) + + # Checking both purelib and platlib directories for installed + # packages to be moved to target directory + lib_dir_list = [] + + with target_temp_dir: + # Checking both purelib and platlib directories for installed + # packages to be moved to target directory + scheme = distutils_scheme('', home=target_temp_dir.path) + purelib_dir = scheme['purelib'] + platlib_dir = scheme['platlib'] + data_dir = scheme['data'] + + if os.path.exists(purelib_dir): + lib_dir_list.append(purelib_dir) + if os.path.exists(platlib_dir) and platlib_dir != purelib_dir: + lib_dir_list.append(platlib_dir) + if os.path.exists(data_dir): + lib_dir_list.append(data_dir) + + for lib_dir in lib_dir_list: + for item in os.listdir(lib_dir): + if lib_dir == data_dir: + ddir = os.path.join(data_dir, item) + if any(s.startswith(ddir) for s in lib_dir_list[:-1]): + continue + target_item_dir = os.path.join(target_dir, item) + if os.path.exists(target_item_dir): + if not upgrade: + logger.warning( + 'Target directory %s already exists. Specify ' + '--upgrade to force replacement.', + target_item_dir + ) + continue + if os.path.islink(target_item_dir): + logger.warning( + 'Target directory %s already exists and is ' + 'a link. pip will not automatically replace ' + 'links, please remove if replacement is ' + 'desired.', + target_item_dir + ) + continue + if os.path.isdir(target_item_dir): + shutil.rmtree(target_item_dir) + else: + os.remove(target_item_dir) + + shutil.move( + os.path.join(lib_dir, item), + target_item_dir + ) + + def _warn_about_conflicts(self, to_install): + try: + package_set, _dep_info = check_install_conflicts(to_install) + except Exception: + logger.error("Error checking for conflicts.", exc_info=True) + return + missing, conflicting = _dep_info + + # NOTE: There is some duplication here from pip check + for project_name in missing: + version = package_set[project_name][0] + for dependency in missing[project_name]: + logger.critical( + "%s %s requires %s, which is not installed.", + project_name, version, dependency[1], + ) + + for project_name in conflicting: + version = package_set[project_name][0] + for dep_name, dep_version, req in conflicting[project_name]: + logger.critical( + "%s %s has requirement %s, but you'll have %s %s which is " + "incompatible.", + project_name, version, req, dep_name, dep_version, + ) + + +def get_lib_location_guesses(*args, **kwargs): + scheme = distutils_scheme('', *args, **kwargs) + return [scheme['purelib'], scheme['platlib']] + + +def site_packages_writable(**kwargs): + return all( + test_writable_dir(d) for d in set(get_lib_location_guesses(**kwargs)) + ) + + +def decide_user_install( + use_user_site, # type: Optional[bool] + prefix_path=None, # type: Optional[str] + target_dir=None, # type: Optional[str] + root_path=None, # type: Optional[str] + isolated_mode=False, # type: bool +): + # type: (...) -> bool + """Determine whether to do a user install based on the input options. + + If use_user_site is False, no additional checks are done. + If use_user_site is True, it is checked for compatibility with other + options. + If use_user_site is None, the default behaviour depends on the environment, + which is provided by the other arguments. + """ + # In some cases (config from tox), use_user_site can be set to an integer + # rather than a bool, which 'use_user_site is False' wouldn't catch. + if (use_user_site is not None) and (not use_user_site): + logger.debug("Non-user install by explicit request") + return False + + if use_user_site: + if prefix_path: + raise CommandError( + "Can not combine '--user' and '--prefix' as they imply " + "different installation locations" + ) + if virtualenv_no_global(): + raise InstallationError( + "Can not perform a '--user' install. User site-packages " + "are not visible in this virtualenv." + ) + logger.debug("User install by explicit request") + return True + + # If we are here, user installs have not been explicitly requested/avoided + assert use_user_site is None + + # user install incompatible with --prefix/--target + if prefix_path or target_dir: + logger.debug("Non-user install due to --prefix or --target option") + return False + + # If user installs are not enabled, choose a non-user install + if not site.ENABLE_USER_SITE: + logger.debug("Non-user install because user site-packages disabled") + return False + + # If we have permission for a non-user install, do that, + # otherwise do a user install. + if site_packages_writable(root=root_path, isolated=isolated_mode): + logger.debug("Non-user install because site-packages writeable") + return False + + logger.info("Defaulting to user installation because normal site-packages " + "is not writeable") + return True + + +def warn_deprecated_install_options(requirements, options): + # type: (List[InstallRequirement], Optional[List[str]]) -> None + """If any location-changing --install-option arguments were passed for + requirements or on the command-line, then show a deprecation warning. + """ + def format_options(option_names): + # type: (Iterable[str]) -> List[str] + return ["--{}".format(name.replace("_", "-")) for name in option_names] + + offenders = [] + + for requirement in requirements: + install_options = requirement.install_options + location_options = parse_distutils_args(install_options) + if location_options: + offenders.append( + "{!r} from {}".format( + format_options(location_options.keys()), requirement + ) + ) + + if options: + location_options = parse_distutils_args(options) + if location_options: + offenders.append( + "{!r} from command line".format( + format_options(location_options.keys()) + ) + ) + + if not offenders: + return + + deprecated( + reason=( + "Location-changing options found in --install-option: {}. " + "This configuration may cause unexpected behavior and is " + "unsupported.".format( + "; ".join(offenders) + ) + ), + replacement=( + "using pip-level options like --user, --prefix, --root, and " + "--target" + ), + gone_in="20.2", + issue=7309, + ) + + +def create_env_error_message(error, show_traceback, using_user_site): + """Format an error message for an EnvironmentError + + It may occur anytime during the execution of the install command. + """ + parts = [] + + # Mention the error if we are not going to show a traceback + parts.append("Could not install packages due to an EnvironmentError") + if not show_traceback: + parts.append(": ") + parts.append(str(error)) + else: + parts.append(".") + + # Spilt the error indication from a helper message (if any) + parts[-1] += "\n" + + # Suggest useful actions to the user: + # (1) using user site-packages or (2) verifying the permissions + if error.errno == errno.EACCES: + user_option_part = "Consider using the `--user` option" + permissions_part = "Check the permissions" + + if not using_user_site: + parts.extend([ + user_option_part, " or ", + permissions_part.lower(), + ]) + else: + parts.append(permissions_part) + parts.append(".\n") + + return "".join(parts).strip() + "\n" diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/list.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/list.py new file mode 100644 index 0000000..13715ce --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/commands/list.py @@ -0,0 +1,301 @@ +# The following comment should be removed at some point in the future. +# mypy: disallow-untyped-defs=False + +from __future__ import absolute_import + +import json +import logging + +from pip._vendor import six + +from pip._internal.cli import cmdoptions +from pip._internal.cli.req_command import IndexGroupCommand +from pip._internal.exceptions import CommandError +from pip._internal.index.package_finder import PackageFinder +from pip._internal.models.selection_prefs import SelectionPreferences +from pip._internal.self_outdated_check import make_link_collector +from pip._internal.utils.misc import ( + dist_is_editable, + get_installed_distributions, + tabulate, + write_output, +) +from pip._internal.utils.packaging import get_installer + +from pip._vendor.packaging.version import parse + +logger = logging.getLogger(__name__) + + +class ListCommand(IndexGroupCommand): + """ + List installed packages, including editables. + + Packages are listed in a case-insensitive sorted order. + """ + + usage = """ + %prog [options]""" + + def __init__(self, *args, **kw): + super(ListCommand, self).__init__(*args, **kw) + + cmd_opts = self.cmd_opts + + cmd_opts.add_option( + '-o', '--outdated', + action='store_true', + default=False, + help='List outdated packages') + cmd_opts.add_option( + '-u', '--uptodate', + action='store_true', + default=False, + help='List uptodate packages') + cmd_opts.add_option( + '-e', '--editable', + action='store_true', + default=False, + help='List editable projects.') + cmd_opts.add_option( + '-l', '--local', + action='store_true', + default=False, + help=('If in a virtualenv that has global access, do not list ' + 'globally-installed packages.'), + ) + self.cmd_opts.add_option( + '--user', + dest='user', + action='store_true', + default=False, + help='Only output packages installed in user-site.') + cmd_opts.add_option(cmdoptions.list_path()) + cmd_opts.add_option( + '--pre', + action='store_true', + default=False, + help=("Include pre-release and development versions. By default, " + "pip only finds stable versions."), + ) + + cmd_opts.add_option( + '--format', + action='store', + dest='list_format', + default="columns", + choices=('columns', 'freeze', 'json'), + help="Select the output format among: columns (default), freeze, " + "or json", + ) + + cmd_opts.add_option( + '--not-required', + action='store_true', + dest='not_required', + help="List packages that are not dependencies of " + "installed packages.", + ) + + cmd_opts.add_option( + '--exclude-editable', + action='store_false', + dest='include_editable', + help='Exclude editable package from output.', + ) + cmd_opts.add_option( + '--include-editable', + action='store_true', + dest='include_editable', + help='Include editable package from output.', + default=True, + ) + index_opts = cmdoptions.make_option_group( + cmdoptions.index_group, self.parser + ) + + self.parser.insert_option_group(0, index_opts) + self.parser.insert_option_group(0, cmd_opts) + + def _build_package_finder(self, options, session): + """ + Create a package finder appropriate to this list command. + """ + link_collector = make_link_collector(session, options=options) + + # Pass allow_yanked=False to ignore yanked versions. + selection_prefs = SelectionPreferences( + allow_yanked=False, + allow_all_prereleases=options.pre, + ) + + return PackageFinder.create( + link_collector=link_collector, + selection_prefs=selection_prefs, + ) + + def run(self, options, args): + if options.outdated and options.uptodate: + raise CommandError( + "Options --outdated and --uptodate cannot be combined.") + + cmdoptions.check_list_path_option(options) + + packages = get_installed_distributions( + local_only=options.local, + user_only=options.user, + editables_only=options.editable, + include_editables=options.include_editable, + paths=options.path, + ) + + # get_not_required must be called firstly in order to find and + # filter out all dependencies correctly. Otherwise a package + # can't be identified as requirement because some parent packages + # could be filtered out before. + if options.not_required: + packages = self.get_not_required(packages, options) + + if options.outdated: + packages = self.get_outdated(packages, options) + elif options.uptodate: + packages = self.get_uptodate(packages, options) + + self.output_package_listing(packages, options) + + def get_outdated(self, packages, options): + return [ + dist for dist in self.iter_packages_latest_infos(packages, options) + if parse(str(dist.latest_version)) > parse(str(dist.parsed_version)) + ] + + def get_uptodate(self, packages, options): + return [ + dist for dist in self.iter_packages_latest_infos(packages, options) + if parse(str(dist.latest_version)) == parse(str(dist.parsed_version)) + ] + + def get_not_required(self, packages, options): + dep_keys = set() + for dist in packages: + dep_keys.update(requirement.key for requirement in dist.requires()) + return {pkg for pkg in packages if pkg.key not in dep_keys} + + def iter_packages_latest_infos(self, packages, options): + with self._build_session(options) as session: + finder = self._build_package_finder(options, session) + + def latest_info(dist): + typ = 'unknown' + all_candidates = finder.find_all_candidates(dist.key) + if not options.pre: + # Remove prereleases + all_candidates = [candidate for candidate in all_candidates + if not candidate.version.is_prerelease] + + evaluator = finder.make_candidate_evaluator( + project_name=dist.project_name, + ) + best_candidate = evaluator.sort_best_candidate(all_candidates) + if best_candidate is None: + return None + + remote_version = best_candidate.version + if best_candidate.link.is_wheel: + typ = 'wheel' + else: + typ = 'sdist' + # This is dirty but makes the rest of the code much cleaner + dist.latest_version = remote_version + dist.latest_filetype = typ + return dist + + for dist in map(latest_info, packages): + if dist is not None: + yield dist + + def output_package_listing(self, packages, options): + packages = sorted( + packages, + key=lambda dist: dist.project_name.lower(), + ) + if options.list_format == 'columns' and packages: + data, header = format_for_columns(packages, options) + self.output_package_listing_columns(data, header) + elif options.list_format == 'freeze': + for dist in packages: + if options.verbose >= 1: + write_output("%s==%s (%s)", dist.project_name, + dist.version, dist.location) + else: + write_output("%s==%s", dist.project_name, dist.version) + elif options.list_format == 'json': + write_output(format_for_json(packages, options)) + + def output_package_listing_columns(self, data, header): + # insert the header first: we need to know the size of column names + if len(data) > 0: + data.insert(0, header) + + pkg_strings, sizes = tabulate(data) + + # Create and add a separator. + if len(data) > 0: + pkg_strings.insert(1, " ".join(map(lambda x: '-' * x, sizes))) + + for val in pkg_strings: + write_output(val) + + +def format_for_columns(pkgs, options): + """ + Convert the package data into something usable + by output_package_listing_columns. + """ + running_outdated = options.outdated + # Adjust the header for the `pip list --outdated` case. + if running_outdated: + header = ["Package", "Version", "Latest", "Type"] + else: + header = ["Package", "Version"] + + data = [] + if options.verbose >= 1 or any(dist_is_editable(x) for x in pkgs): + header.append("Location") + if options.verbose >= 1: + header.append("Installer") + + for proj in pkgs: + # if we're working on the 'outdated' list, separate out the + # latest_version and type + row = [proj.project_name, proj.version] + + if running_outdated: + row.append(proj.latest_version) + row.append(proj.latest_filetype) + + if options.verbose >= 1 or dist_is_editable(proj): + row.append(proj.location) + if options.verbose >= 1: + row.append(get_installer(proj)) + + data.append(row) + + return data, header + + +def format_for_json(packages, options): + data = [] + for dist in packages: + info = { + 'name': dist.project_name, + 'version': six.text_type(dist.version), + } + if options.verbose >= 1: + info['location'] = dist.location + info['installer'] = get_installer(dist) + if options.outdated: + info['latest_version'] = six.text_type(dist.latest_version) + info['latest_filetype'] = dist.latest_filetype + data.append(info) + return json.dumps(data) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/search.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/search.py new file mode 100644 index 0000000..e5f286e --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/commands/search.py @@ -0,0 +1,146 @@ +# The following comment should be removed at some point in the future. +# mypy: disallow-untyped-defs=False + +from __future__ import absolute_import + +import logging +import sys +import textwrap +from collections import OrderedDict + +from pip._vendor import pkg_resources +from pip._vendor.packaging.version import parse as parse_version +# NOTE: XMLRPC Client is not annotated in typeshed as on 2017-07-17, which is +# why we ignore the type on this import +from pip._vendor.six.moves import xmlrpc_client # type: ignore + +from pip._internal.cli.base_command import Command +from pip._internal.cli.req_command import SessionCommandMixin +from pip._internal.cli.status_codes import NO_MATCHES_FOUND, SUCCESS +from pip._internal.exceptions import CommandError +from pip._internal.models.index import PyPI +from pip._internal.network.xmlrpc import PipXmlrpcTransport +from pip._internal.utils.compat import get_terminal_size +from pip._internal.utils.logging import indent_log +from pip._internal.utils.misc import write_output + +logger = logging.getLogger(__name__) + + +class SearchCommand(Command, SessionCommandMixin): + """Search for PyPI packages whose name or summary contains .""" + + usage = """ + %prog [options] """ + ignore_require_venv = True + + def __init__(self, *args, **kw): + super(SearchCommand, self).__init__(*args, **kw) + self.cmd_opts.add_option( + '-i', '--index', + dest='index', + metavar='URL', + default=PyPI.pypi_url, + help='Base URL of Python Package Index (default %default)') + + self.parser.insert_option_group(0, self.cmd_opts) + + def run(self, options, args): + if not args: + raise CommandError('Missing required argument (search query).') + query = args + pypi_hits = self.search(query, options) + hits = transform_hits(pypi_hits) + + terminal_width = None + if sys.stdout.isatty(): + terminal_width = get_terminal_size()[0] + + print_results(hits, terminal_width=terminal_width) + if pypi_hits: + return SUCCESS + return NO_MATCHES_FOUND + + def search(self, query, options): + index_url = options.index + + session = self.get_default_session(options) + + transport = PipXmlrpcTransport(index_url, session) + pypi = xmlrpc_client.ServerProxy(index_url, transport) + hits = pypi.search({'name': query, 'summary': query}, 'or') + return hits + + +def transform_hits(hits): + """ + The list from pypi is really a list of versions. We want a list of + packages with the list of versions stored inline. This converts the + list from pypi into one we can use. + """ + packages = OrderedDict() + for hit in hits: + name = hit['name'] + summary = hit['summary'] + version = hit['version'] + + if name not in packages.keys(): + packages[name] = { + 'name': name, + 'summary': summary, + 'versions': [version], + } + else: + packages[name]['versions'].append(version) + + # if this is the highest version, replace summary and score + if version == highest_version(packages[name]['versions']): + packages[name]['summary'] = summary + + return list(packages.values()) + + +def print_results(hits, name_column_width=None, terminal_width=None): + if not hits: + return + if name_column_width is None: + name_column_width = max([ + len(hit['name']) + len(highest_version(hit.get('versions', ['-']))) + for hit in hits + ]) + 4 + + installed_packages = [p.project_name for p in pkg_resources.working_set] + for hit in hits: + name = hit['name'] + summary = hit['summary'] or '' + latest = highest_version(hit.get('versions', ['-'])) + if terminal_width is not None: + target_width = terminal_width - name_column_width - 5 + if target_width > 10: + # wrap and indent summary to fit terminal + summary = textwrap.wrap(summary, target_width) + summary = ('\n' + ' ' * (name_column_width + 3)).join(summary) + + line = '{name_latest:{name_column_width}} - {summary}'.format( + name_latest='{name} ({latest})'.format(**locals()), + **locals()) + try: + write_output(line) + if name in installed_packages: + dist = pkg_resources.get_distribution(name) + with indent_log(): + if dist.version == latest: + write_output('INSTALLED: %s (latest)', dist.version) + else: + write_output('INSTALLED: %s', dist.version) + if parse_version(latest).pre: + write_output('LATEST: %s (pre-release; install' + ' with "pip install --pre")', latest) + else: + write_output('LATEST: %s', latest) + except UnicodeEncodeError: + pass + + +def highest_version(versions): + return max(versions, key=parse_version) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/show.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/show.py new file mode 100644 index 0000000..a61294b --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/commands/show.py @@ -0,0 +1,180 @@ +# The following comment should be removed at some point in the future. +# mypy: disallow-untyped-defs=False + +from __future__ import absolute_import + +import logging +import os +from email.parser import FeedParser + +from pip._vendor import pkg_resources +from pip._vendor.packaging.utils import canonicalize_name + +from pip._internal.cli.base_command import Command +from pip._internal.cli.status_codes import ERROR, SUCCESS +from pip._internal.utils.misc import write_output + +logger = logging.getLogger(__name__) + + +class ShowCommand(Command): + """ + Show information about one or more installed packages. + + The output is in RFC-compliant mail header format. + """ + + usage = """ + %prog [options] ...""" + ignore_require_venv = True + + def __init__(self, *args, **kw): + super(ShowCommand, self).__init__(*args, **kw) + self.cmd_opts.add_option( + '-f', '--files', + dest='files', + action='store_true', + default=False, + help='Show the full list of installed files for each package.') + + self.parser.insert_option_group(0, self.cmd_opts) + + def run(self, options, args): + if not args: + logger.warning('ERROR: Please provide a package name or names.') + return ERROR + query = args + + results = search_packages_info(query) + if not print_results( + results, list_files=options.files, verbose=options.verbose): + return ERROR + return SUCCESS + + +def search_packages_info(query): + """ + Gather details from installed distributions. Print distribution name, + version, location, and installed files. Installed files requires a + pip generated 'installed-files.txt' in the distributions '.egg-info' + directory. + """ + installed = {} + for p in pkg_resources.working_set: + installed[canonicalize_name(p.project_name)] = p + + query_names = [canonicalize_name(name) for name in query] + missing = sorted( + [name for name, pkg in zip(query, query_names) if pkg not in installed] + ) + if missing: + logger.warning('Package(s) not found: %s', ', '.join(missing)) + + def get_requiring_packages(package_name): + canonical_name = canonicalize_name(package_name) + return [ + pkg.project_name for pkg in pkg_resources.working_set + if canonical_name in + [canonicalize_name(required.name) for required in + pkg.requires()] + ] + + for dist in [installed[pkg] for pkg in query_names if pkg in installed]: + package = { + 'name': dist.project_name, + 'version': dist.version, + 'location': dist.location, + 'requires': [dep.project_name for dep in dist.requires()], + 'required_by': get_requiring_packages(dist.project_name) + } + file_list = None + metadata = None + if isinstance(dist, pkg_resources.DistInfoDistribution): + # RECORDs should be part of .dist-info metadatas + if dist.has_metadata('RECORD'): + lines = dist.get_metadata_lines('RECORD') + paths = [l.split(',')[0] for l in lines] + paths = [os.path.join(dist.location, p) for p in paths] + file_list = [os.path.relpath(p, dist.location) for p in paths] + + if dist.has_metadata('METADATA'): + metadata = dist.get_metadata('METADATA') + else: + # Otherwise use pip's log for .egg-info's + if dist.has_metadata('installed-files.txt'): + paths = dist.get_metadata_lines('installed-files.txt') + paths = [os.path.join(dist.egg_info, p) for p in paths] + file_list = [os.path.relpath(p, dist.location) for p in paths] + + if dist.has_metadata('PKG-INFO'): + metadata = dist.get_metadata('PKG-INFO') + + if dist.has_metadata('entry_points.txt'): + entry_points = dist.get_metadata_lines('entry_points.txt') + package['entry_points'] = entry_points + + if dist.has_metadata('INSTALLER'): + for line in dist.get_metadata_lines('INSTALLER'): + if line.strip(): + package['installer'] = line.strip() + break + + # @todo: Should pkg_resources.Distribution have a + # `get_pkg_info` method? + feed_parser = FeedParser() + feed_parser.feed(metadata) + pkg_info_dict = feed_parser.close() + for key in ('metadata-version', 'summary', + 'home-page', 'author', 'author-email', 'license'): + package[key] = pkg_info_dict.get(key) + + # It looks like FeedParser cannot deal with repeated headers + classifiers = [] + for line in metadata.splitlines(): + if line.startswith('Classifier: '): + classifiers.append(line[len('Classifier: '):]) + package['classifiers'] = classifiers + + if file_list: + package['files'] = sorted(file_list) + yield package + + +def print_results(distributions, list_files=False, verbose=False): + """ + Print the information from installed distributions found. + """ + results_printed = False + for i, dist in enumerate(distributions): + results_printed = True + if i > 0: + write_output("---") + + write_output("Name: %s", dist.get('name', '')) + write_output("Version: %s", dist.get('version', '')) + write_output("Summary: %s", dist.get('summary', '')) + write_output("Home-page: %s", dist.get('home-page', '')) + write_output("Author: %s", dist.get('author', '')) + write_output("Author-email: %s", dist.get('author-email', '')) + write_output("License: %s", dist.get('license', '')) + write_output("Location: %s", dist.get('location', '')) + write_output("Requires: %s", ', '.join(dist.get('requires', []))) + write_output("Required-by: %s", ', '.join(dist.get('required_by', []))) + + if verbose: + write_output("Metadata-Version: %s", + dist.get('metadata-version', '')) + write_output("Installer: %s", dist.get('installer', '')) + write_output("Classifiers:") + for classifier in dist.get('classifiers', []): + write_output(" %s", classifier) + write_output("Entry-points:") + for entry in dist.get('entry_points', []): + write_output(" %s", entry.strip()) + if list_files: + write_output("Files:") + for line in dist.get('files', []): + write_output(" %s", line.strip()) + if "files" not in dist: + write_output("Cannot locate installed-files.txt") + return results_printed diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/uninstall.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/uninstall.py new file mode 100644 index 0000000..5db4fb4 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/commands/uninstall.py @@ -0,0 +1,89 @@ +# The following comment should be removed at some point in the future. +# mypy: disallow-untyped-defs=False + +from __future__ import absolute_import + +from pip._vendor.packaging.utils import canonicalize_name + +from pip._internal.cli.base_command import Command +from pip._internal.cli.req_command import SessionCommandMixin +from pip._internal.exceptions import InstallationError +from pip._internal.req import parse_requirements +from pip._internal.req.constructors import ( + install_req_from_line, + install_req_from_parsed_requirement, +) +from pip._internal.utils.misc import protect_pip_from_modification_on_windows + + +class UninstallCommand(Command, SessionCommandMixin): + """ + Uninstall packages. + + pip is able to uninstall most installed packages. Known exceptions are: + + - Pure distutils packages installed with ``python setup.py install``, which + leave behind no metadata to determine what files were installed. + - Script wrappers installed by ``python setup.py develop``. + """ + + usage = """ + %prog [options] ... + %prog [options] -r ...""" + + def __init__(self, *args, **kw): + super(UninstallCommand, self).__init__(*args, **kw) + self.cmd_opts.add_option( + '-r', '--requirement', + dest='requirements', + action='append', + default=[], + metavar='file', + help='Uninstall all the packages listed in the given requirements ' + 'file. This option can be used multiple times.', + ) + self.cmd_opts.add_option( + '-y', '--yes', + dest='yes', + action='store_true', + help="Don't ask for confirmation of uninstall deletions.") + + self.parser.insert_option_group(0, self.cmd_opts) + + def run(self, options, args): + session = self.get_default_session(options) + + reqs_to_uninstall = {} + for name in args: + req = install_req_from_line( + name, isolated=options.isolated_mode, + ) + if req.name: + reqs_to_uninstall[canonicalize_name(req.name)] = req + for filename in options.requirements: + for parsed_req in parse_requirements( + filename, + options=options, + session=session): + req = install_req_from_parsed_requirement( + parsed_req, + isolated=options.isolated_mode + ) + if req.name: + reqs_to_uninstall[canonicalize_name(req.name)] = req + if not reqs_to_uninstall: + raise InstallationError( + 'You must give at least one requirement to {self.name} (see ' + '"pip help {self.name}")'.format(**locals()) + ) + + protect_pip_from_modification_on_windows( + modifying_pip="pip" in reqs_to_uninstall + ) + + for req in reqs_to_uninstall.values(): + uninstall_pathset = req.uninstall( + auto_confirm=options.yes, verbose=self.verbosity > 0, + ) + if uninstall_pathset: + uninstall_pathset.commit() diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/wheel.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/wheel.py new file mode 100644 index 0000000..48f3bfa --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/commands/wheel.py @@ -0,0 +1,190 @@ +# -*- coding: utf-8 -*- + +# The following comment should be removed at some point in the future. +# mypy: disallow-untyped-defs=False + +from __future__ import absolute_import + +import logging +import os +import shutil + +from pip._internal.cache import WheelCache +from pip._internal.cli import cmdoptions +from pip._internal.cli.req_command import RequirementCommand, with_cleanup +from pip._internal.exceptions import CommandError +from pip._internal.req.req_tracker import get_requirement_tracker +from pip._internal.utils.misc import ensure_dir, normalize_path +from pip._internal.utils.temp_dir import TempDirectory +from pip._internal.utils.typing import MYPY_CHECK_RUNNING +from pip._internal.wheel_builder import build, should_build_for_wheel_command + +if MYPY_CHECK_RUNNING: + from optparse import Values + from typing import Any, List + + +logger = logging.getLogger(__name__) + + +class WheelCommand(RequirementCommand): + """ + Build Wheel archives for your requirements and dependencies. + + Wheel is a built-package format, and offers the advantage of not + recompiling your software during every install. For more details, see the + wheel docs: https://wheel.readthedocs.io/en/latest/ + + Requirements: setuptools>=0.8, and wheel. + + 'pip wheel' uses the bdist_wheel setuptools extension from the wheel + package to build individual wheels. + + """ + + usage = """ + %prog [options] ... + %prog [options] -r ... + %prog [options] [-e] ... + %prog [options] [-e] ... + %prog [options] ...""" + + def __init__(self, *args, **kw): + super(WheelCommand, self).__init__(*args, **kw) + + cmd_opts = self.cmd_opts + + cmd_opts.add_option( + '-w', '--wheel-dir', + dest='wheel_dir', + metavar='dir', + default=os.curdir, + help=("Build wheels into , where the default is the " + "current working directory."), + ) + cmd_opts.add_option(cmdoptions.no_binary()) + cmd_opts.add_option(cmdoptions.only_binary()) + cmd_opts.add_option(cmdoptions.prefer_binary()) + cmd_opts.add_option( + '--build-option', + dest='build_options', + metavar='options', + action='append', + help="Extra arguments to be supplied to 'setup.py bdist_wheel'.", + ) + cmd_opts.add_option(cmdoptions.no_build_isolation()) + cmd_opts.add_option(cmdoptions.use_pep517()) + cmd_opts.add_option(cmdoptions.no_use_pep517()) + cmd_opts.add_option(cmdoptions.constraints()) + cmd_opts.add_option(cmdoptions.editable()) + cmd_opts.add_option(cmdoptions.requirements()) + cmd_opts.add_option(cmdoptions.src()) + cmd_opts.add_option(cmdoptions.ignore_requires_python()) + cmd_opts.add_option(cmdoptions.no_deps()) + cmd_opts.add_option(cmdoptions.build_dir()) + cmd_opts.add_option(cmdoptions.progress_bar()) + + cmd_opts.add_option( + '--global-option', + dest='global_options', + action='append', + metavar='options', + help="Extra global options to be supplied to the setup.py " + "call before the 'bdist_wheel' command.") + + cmd_opts.add_option( + '--pre', + action='store_true', + default=False, + help=("Include pre-release and development versions. By default, " + "pip only finds stable versions."), + ) + + cmd_opts.add_option(cmdoptions.require_hashes()) + + index_opts = cmdoptions.make_option_group( + cmdoptions.index_group, + self.parser, + ) + + self.parser.insert_option_group(0, index_opts) + self.parser.insert_option_group(0, cmd_opts) + + @with_cleanup + def run(self, options, args): + # type: (Values, List[Any]) -> None + cmdoptions.check_install_build_global(options) + + session = self.get_default_session(options) + + finder = self._build_package_finder(options, session) + build_delete = (not (options.no_clean or options.build_dir)) + wheel_cache = WheelCache(options.cache_dir, options.format_control) + + options.wheel_dir = normalize_path(options.wheel_dir) + ensure_dir(options.wheel_dir) + + req_tracker = self.enter_context(get_requirement_tracker()) + + directory = TempDirectory( + options.build_dir, + delete=build_delete, + kind="wheel", + globally_managed=True, + ) + + reqs = self.get_requirements(args, options, finder, session) + + preparer = self.make_requirement_preparer( + temp_build_dir=directory, + options=options, + req_tracker=req_tracker, + session=session, + finder=finder, + wheel_download_dir=options.wheel_dir, + use_user_site=False, + ) + + resolver = self.make_resolver( + preparer=preparer, + finder=finder, + options=options, + wheel_cache=wheel_cache, + ignore_requires_python=options.ignore_requires_python, + use_pep517=options.use_pep517, + ) + + self.trace_basic_info(finder) + + requirement_set = resolver.resolve( + reqs, check_supported_wheels=True + ) + + reqs_to_build = [ + r for r in requirement_set.requirements.values() + if should_build_for_wheel_command(r) + ] + + # build wheels + build_successes, build_failures = build( + reqs_to_build, + wheel_cache=wheel_cache, + build_options=options.build_options or [], + global_options=options.global_options or [], + ) + for req in build_successes: + assert req.link and req.link.is_wheel + assert req.local_file_path + # copy from cache to target directory + try: + shutil.copy(req.local_file_path, options.wheel_dir) + except OSError as e: + logger.warning( + "Building wheel for %s failed: %s", + req.name, e, + ) + build_failures.append(req) + if len(build_failures) != 0: + raise CommandError( + "Failed to build one or more wheels" + ) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/configuration.py b/venv/lib/python3.8/site-packages/pip/_internal/configuration.py new file mode 100644 index 0000000..2648b8a --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/configuration.py @@ -0,0 +1,426 @@ +"""Configuration management setup + +Some terminology: +- name + As written in config files. +- value + Value associated with a name +- key + Name combined with it's section (section.name) +- variant + A single word describing where the configuration key-value pair came from +""" + +# The following comment should be removed at some point in the future. +# mypy: strict-optional=False + +import locale +import logging +import os +import sys + +from pip._vendor.six.moves import configparser + +from pip._internal.exceptions import ( + ConfigurationError, + ConfigurationFileCouldNotBeLoaded, +) +from pip._internal.utils import appdirs +from pip._internal.utils.compat import WINDOWS, expanduser +from pip._internal.utils.misc import ensure_dir, enum +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import ( + Any, Dict, Iterable, List, NewType, Optional, Tuple + ) + + RawConfigParser = configparser.RawConfigParser # Shorthand + Kind = NewType("Kind", str) + +logger = logging.getLogger(__name__) + + +# NOTE: Maybe use the optionx attribute to normalize keynames. +def _normalize_name(name): + # type: (str) -> str + """Make a name consistent regardless of source (environment or file) + """ + name = name.lower().replace('_', '-') + if name.startswith('--'): + name = name[2:] # only prefer long opts + return name + + +def _disassemble_key(name): + # type: (str) -> List[str] + if "." not in name: + error_message = ( + "Key does not contain dot separated section and key. " + "Perhaps you wanted to use 'global.{}' instead?" + ).format(name) + raise ConfigurationError(error_message) + return name.split(".", 1) + + +# The kinds of configurations there are. +kinds = enum( + USER="user", # User Specific + GLOBAL="global", # System Wide + SITE="site", # [Virtual] Environment Specific + ENV="env", # from PIP_CONFIG_FILE + ENV_VAR="env-var", # from Environment Variables +) + + +CONFIG_BASENAME = 'pip.ini' if WINDOWS else 'pip.conf' + + +def get_configuration_files(): + # type: () -> Dict[Kind, List[str]] + global_config_files = [ + os.path.join(path, CONFIG_BASENAME) + for path in appdirs.site_config_dirs('pip') + ] + + site_config_file = os.path.join(sys.prefix, CONFIG_BASENAME) + legacy_config_file = os.path.join( + expanduser('~'), + 'pip' if WINDOWS else '.pip', + CONFIG_BASENAME, + ) + new_config_file = os.path.join( + appdirs.user_config_dir("pip"), CONFIG_BASENAME + ) + return { + kinds.GLOBAL: global_config_files, + kinds.SITE: [site_config_file], + kinds.USER: [legacy_config_file, new_config_file], + } + + +class Configuration(object): + """Handles management of configuration. + + Provides an interface to accessing and managing configuration files. + + This class converts provides an API that takes "section.key-name" style + keys and stores the value associated with it as "key-name" under the + section "section". + + This allows for a clean interface wherein the both the section and the + key-name are preserved in an easy to manage form in the configuration files + and the data stored is also nice. + """ + + def __init__(self, isolated, load_only=None): + # type: (bool, Kind) -> None + super(Configuration, self).__init__() + + _valid_load_only = [kinds.USER, kinds.GLOBAL, kinds.SITE, None] + if load_only not in _valid_load_only: + raise ConfigurationError( + "Got invalid value for load_only - should be one of {}".format( + ", ".join(map(repr, _valid_load_only[:-1])) + ) + ) + self.isolated = isolated # type: bool + self.load_only = load_only # type: Optional[Kind] + + # The order here determines the override order. + self._override_order = [ + kinds.GLOBAL, kinds.USER, kinds.SITE, kinds.ENV, kinds.ENV_VAR + ] + + self._ignore_env_names = ["version", "help"] + + # Because we keep track of where we got the data from + self._parsers = { + variant: [] for variant in self._override_order + } # type: Dict[Kind, List[Tuple[str, RawConfigParser]]] + self._config = { + variant: {} for variant in self._override_order + } # type: Dict[Kind, Dict[str, Any]] + self._modified_parsers = [] # type: List[Tuple[str, RawConfigParser]] + + def load(self): + # type: () -> None + """Loads configuration from configuration files and environment + """ + self._load_config_files() + if not self.isolated: + self._load_environment_vars() + + def get_file_to_edit(self): + # type: () -> Optional[str] + """Returns the file with highest priority in configuration + """ + assert self.load_only is not None, \ + "Need to be specified a file to be editing" + + try: + return self._get_parser_to_modify()[0] + except IndexError: + return None + + def items(self): + # type: () -> Iterable[Tuple[str, Any]] + """Returns key-value pairs like dict.items() representing the loaded + configuration + """ + return self._dictionary.items() + + def get_value(self, key): + # type: (str) -> Any + """Get a value from the configuration. + """ + try: + return self._dictionary[key] + except KeyError: + raise ConfigurationError("No such key - {}".format(key)) + + def set_value(self, key, value): + # type: (str, Any) -> None + """Modify a value in the configuration. + """ + self._ensure_have_load_only() + + fname, parser = self._get_parser_to_modify() + + if parser is not None: + section, name = _disassemble_key(key) + + # Modify the parser and the configuration + if not parser.has_section(section): + parser.add_section(section) + parser.set(section, name, value) + + self._config[self.load_only][key] = value + self._mark_as_modified(fname, parser) + + def unset_value(self, key): + # type: (str) -> None + """Unset a value in the configuration. + """ + self._ensure_have_load_only() + + if key not in self._config[self.load_only]: + raise ConfigurationError("No such key - {}".format(key)) + + fname, parser = self._get_parser_to_modify() + + if parser is not None: + section, name = _disassemble_key(key) + + # Remove the key in the parser + modified_something = False + if parser.has_section(section): + # Returns whether the option was removed or not + modified_something = parser.remove_option(section, name) + + if modified_something: + # name removed from parser, section may now be empty + section_iter = iter(parser.items(section)) + try: + val = next(section_iter) + except StopIteration: + val = None + + if val is None: + parser.remove_section(section) + + self._mark_as_modified(fname, parser) + else: + raise ConfigurationError( + "Fatal Internal error [id=1]. Please report as a bug." + ) + + del self._config[self.load_only][key] + + def save(self): + # type: () -> None + """Save the current in-memory state. + """ + self._ensure_have_load_only() + + for fname, parser in self._modified_parsers: + logger.info("Writing to %s", fname) + + # Ensure directory exists. + ensure_dir(os.path.dirname(fname)) + + with open(fname, "w") as f: + parser.write(f) + + # + # Private routines + # + + def _ensure_have_load_only(self): + # type: () -> None + if self.load_only is None: + raise ConfigurationError("Needed a specific file to be modifying.") + logger.debug("Will be working with %s variant only", self.load_only) + + @property + def _dictionary(self): + # type: () -> Dict[str, Any] + """A dictionary representing the loaded configuration. + """ + # NOTE: Dictionaries are not populated if not loaded. So, conditionals + # are not needed here. + retval = {} + + for variant in self._override_order: + retval.update(self._config[variant]) + + return retval + + def _load_config_files(self): + # type: () -> None + """Loads configuration from configuration files + """ + config_files = dict(self._iter_config_files()) + if config_files[kinds.ENV][0:1] == [os.devnull]: + logger.debug( + "Skipping loading configuration files due to " + "environment's PIP_CONFIG_FILE being os.devnull" + ) + return + + for variant, files in config_files.items(): + for fname in files: + # If there's specific variant set in `load_only`, load only + # that variant, not the others. + if self.load_only is not None and variant != self.load_only: + logger.debug( + "Skipping file '%s' (variant: %s)", fname, variant + ) + continue + + parser = self._load_file(variant, fname) + + # Keeping track of the parsers used + self._parsers[variant].append((fname, parser)) + + def _load_file(self, variant, fname): + # type: (Kind, str) -> RawConfigParser + logger.debug("For variant '%s', will try loading '%s'", variant, fname) + parser = self._construct_parser(fname) + + for section in parser.sections(): + items = parser.items(section) + self._config[variant].update(self._normalized_keys(section, items)) + + return parser + + def _construct_parser(self, fname): + # type: (str) -> RawConfigParser + parser = configparser.RawConfigParser() + # If there is no such file, don't bother reading it but create the + # parser anyway, to hold the data. + # Doing this is useful when modifying and saving files, where we don't + # need to construct a parser. + if os.path.exists(fname): + try: + parser.read(fname) + except UnicodeDecodeError: + # See https://github.com/pypa/pip/issues/4963 + raise ConfigurationFileCouldNotBeLoaded( + reason="contains invalid {} characters".format( + locale.getpreferredencoding(False) + ), + fname=fname, + ) + except configparser.Error as error: + # See https://github.com/pypa/pip/issues/4893 + raise ConfigurationFileCouldNotBeLoaded(error=error) + return parser + + def _load_environment_vars(self): + # type: () -> None + """Loads configuration from environment variables + """ + self._config[kinds.ENV_VAR].update( + self._normalized_keys(":env:", self._get_environ_vars()) + ) + + def _normalized_keys(self, section, items): + # type: (str, Iterable[Tuple[str, Any]]) -> Dict[str, Any] + """Normalizes items to construct a dictionary with normalized keys. + + This routine is where the names become keys and are made the same + regardless of source - configuration files or environment. + """ + normalized = {} + for name, val in items: + key = section + "." + _normalize_name(name) + normalized[key] = val + return normalized + + def _get_environ_vars(self): + # type: () -> Iterable[Tuple[str, str]] + """Returns a generator with all environmental vars with prefix PIP_""" + for key, val in os.environ.items(): + should_be_yielded = ( + key.startswith("PIP_") and + key[4:].lower() not in self._ignore_env_names + ) + if should_be_yielded: + yield key[4:].lower(), val + + # XXX: This is patched in the tests. + def _iter_config_files(self): + # type: () -> Iterable[Tuple[Kind, List[str]]] + """Yields variant and configuration files associated with it. + + This should be treated like items of a dictionary. + """ + # SMELL: Move the conditions out of this function + + # environment variables have the lowest priority + config_file = os.environ.get('PIP_CONFIG_FILE', None) + if config_file is not None: + yield kinds.ENV, [config_file] + else: + yield kinds.ENV, [] + + config_files = get_configuration_files() + + # at the base we have any global configuration + yield kinds.GLOBAL, config_files[kinds.GLOBAL] + + # per-user configuration next + should_load_user_config = not self.isolated and not ( + config_file and os.path.exists(config_file) + ) + if should_load_user_config: + # The legacy config file is overridden by the new config file + yield kinds.USER, config_files[kinds.USER] + + # finally virtualenv configuration first trumping others + yield kinds.SITE, config_files[kinds.SITE] + + def _get_parser_to_modify(self): + # type: () -> Tuple[str, RawConfigParser] + # Determine which parser to modify + parsers = self._parsers[self.load_only] + if not parsers: + # This should not happen if everything works correctly. + raise ConfigurationError( + "Fatal Internal error [id=2]. Please report as a bug." + ) + + # Use the highest priority parser. + return parsers[-1] + + # XXX: This is patched in the tests. + def _mark_as_modified(self, fname, parser): + # type: (str, RawConfigParser) -> None + file_parser_tuple = (fname, parser) + if file_parser_tuple not in self._modified_parsers: + self._modified_parsers.append(file_parser_tuple) + + def __repr__(self): + # type: () -> str + return "{}({!r})".format(self.__class__.__name__, self._dictionary) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/distributions/__init__.py b/venv/lib/python3.8/site-packages/pip/_internal/distributions/__init__.py new file mode 100644 index 0000000..d5c1afc --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/distributions/__init__.py @@ -0,0 +1,24 @@ +from pip._internal.distributions.sdist import SourceDistribution +from pip._internal.distributions.wheel import WheelDistribution +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from pip._internal.distributions.base import AbstractDistribution + from pip._internal.req.req_install import InstallRequirement + + +def make_distribution_for_install_requirement(install_req): + # type: (InstallRequirement) -> AbstractDistribution + """Returns a Distribution for the given InstallRequirement + """ + # Editable requirements will always be source distributions. They use the + # legacy logic until we create a modern standard for them. + if install_req.editable: + return SourceDistribution(install_req) + + # If it's a wheel, it's a WheelDistribution + if install_req.is_wheel: + return WheelDistribution(install_req) + + # Otherwise, a SourceDistribution + return SourceDistribution(install_req) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/distributions/base.py b/venv/lib/python3.8/site-packages/pip/_internal/distributions/base.py new file mode 100644 index 0000000..b836b98 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/distributions/base.py @@ -0,0 +1,45 @@ +import abc + +from pip._vendor.six import add_metaclass + +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Optional + + from pip._vendor.pkg_resources import Distribution + from pip._internal.req import InstallRequirement + from pip._internal.index.package_finder import PackageFinder + + +@add_metaclass(abc.ABCMeta) +class AbstractDistribution(object): + """A base class for handling installable artifacts. + + The requirements for anything installable are as follows: + + - we must be able to determine the requirement name + (or we can't correctly handle the non-upgrade case). + + - for packages with setup requirements, we must also be able + to determine their requirements without installing additional + packages (for the same reason as run-time dependencies) + + - we must be able to create a Distribution object exposing the + above metadata. + """ + + def __init__(self, req): + # type: (InstallRequirement) -> None + super(AbstractDistribution, self).__init__() + self.req = req + + @abc.abstractmethod + def get_pkg_resources_distribution(self): + # type: () -> Optional[Distribution] + raise NotImplementedError() + + @abc.abstractmethod + def prepare_distribution_metadata(self, finder, build_isolation): + # type: (PackageFinder, bool) -> None + raise NotImplementedError() diff --git a/venv/lib/python3.8/site-packages/pip/_internal/distributions/installed.py b/venv/lib/python3.8/site-packages/pip/_internal/distributions/installed.py new file mode 100644 index 0000000..0d15bf4 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/distributions/installed.py @@ -0,0 +1,24 @@ +from pip._internal.distributions.base import AbstractDistribution +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Optional + + from pip._vendor.pkg_resources import Distribution + from pip._internal.index.package_finder import PackageFinder + + +class InstalledDistribution(AbstractDistribution): + """Represents an installed package. + + This does not need any preparation as the required information has already + been computed. + """ + + def get_pkg_resources_distribution(self): + # type: () -> Optional[Distribution] + return self.req.satisfied_by + + def prepare_distribution_metadata(self, finder, build_isolation): + # type: (PackageFinder, bool) -> None + pass diff --git a/venv/lib/python3.8/site-packages/pip/_internal/distributions/sdist.py b/venv/lib/python3.8/site-packages/pip/_internal/distributions/sdist.py new file mode 100644 index 0000000..be3d7d9 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/distributions/sdist.py @@ -0,0 +1,104 @@ +import logging + +from pip._internal.build_env import BuildEnvironment +from pip._internal.distributions.base import AbstractDistribution +from pip._internal.exceptions import InstallationError +from pip._internal.utils.subprocess import runner_with_spinner_message +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Set, Tuple + + from pip._vendor.pkg_resources import Distribution + from pip._internal.index.package_finder import PackageFinder + + +logger = logging.getLogger(__name__) + + +class SourceDistribution(AbstractDistribution): + """Represents a source distribution. + + The preparation step for these needs metadata for the packages to be + generated, either using PEP 517 or using the legacy `setup.py egg_info`. + """ + + def get_pkg_resources_distribution(self): + # type: () -> Distribution + return self.req.get_dist() + + def prepare_distribution_metadata(self, finder, build_isolation): + # type: (PackageFinder, bool) -> None + # Load pyproject.toml, to determine whether PEP 517 is to be used + self.req.load_pyproject_toml() + + # Set up the build isolation, if this requirement should be isolated + should_isolate = self.req.use_pep517 and build_isolation + if should_isolate: + self._setup_isolation(finder) + + self.req.prepare_metadata() + + def _setup_isolation(self, finder): + # type: (PackageFinder) -> None + def _raise_conflicts(conflicting_with, conflicting_reqs): + # type: (str, Set[Tuple[str, str]]) -> None + format_string = ( + "Some build dependencies for {requirement} " + "conflict with {conflicting_with}: {description}." + ) + error_message = format_string.format( + requirement=self.req, + conflicting_with=conflicting_with, + description=', '.join( + '{} is incompatible with {}'.format(installed, wanted) + for installed, wanted in sorted(conflicting) + ) + ) + raise InstallationError(error_message) + + # Isolate in a BuildEnvironment and install the build-time + # requirements. + pyproject_requires = self.req.pyproject_requires + assert pyproject_requires is not None + + self.req.build_env = BuildEnvironment() + self.req.build_env.install_requirements( + finder, pyproject_requires, 'overlay', + "Installing build dependencies" + ) + conflicting, missing = self.req.build_env.check_requirements( + self.req.requirements_to_check + ) + if conflicting: + _raise_conflicts("PEP 517/518 supported requirements", + conflicting) + if missing: + logger.warning( + "Missing build requirements in pyproject.toml for %s.", + self.req, + ) + logger.warning( + "The project does not specify a build backend, and " + "pip cannot fall back to setuptools without %s.", + " and ".join(map(repr, sorted(missing))) + ) + # Install any extra build dependencies that the backend requests. + # This must be done in a second pass, as the pyproject.toml + # dependencies must be installed before we can call the backend. + with self.req.build_env: + runner = runner_with_spinner_message( + "Getting requirements to build wheel" + ) + backend = self.req.pep517_backend + assert backend is not None + with backend.subprocess_runner(runner): + reqs = backend.get_requires_for_build_wheel() + + conflicting, missing = self.req.build_env.check_requirements(reqs) + if conflicting: + _raise_conflicts("the backend dependencies", conflicting) + self.req.build_env.install_requirements( + finder, missing, 'normal', + "Installing backend dependencies" + ) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/distributions/wheel.py b/venv/lib/python3.8/site-packages/pip/_internal/distributions/wheel.py new file mode 100644 index 0000000..bf3482b --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/distributions/wheel.py @@ -0,0 +1,36 @@ +from zipfile import ZipFile + +from pip._internal.distributions.base import AbstractDistribution +from pip._internal.utils.typing import MYPY_CHECK_RUNNING +from pip._internal.utils.wheel import pkg_resources_distribution_for_wheel + +if MYPY_CHECK_RUNNING: + from pip._vendor.pkg_resources import Distribution + from pip._internal.index.package_finder import PackageFinder + + +class WheelDistribution(AbstractDistribution): + """Represents a wheel distribution. + + This does not need any preparation as wheels can be directly unpacked. + """ + + def get_pkg_resources_distribution(self): + # type: () -> Distribution + """Loads the metadata from the wheel file into memory and returns a + Distribution that uses it, not relying on the wheel file or + requirement. + """ + # Set as part of preparation during download. + assert self.req.local_file_path + # Wheels are never unnamed. + assert self.req.name + + with ZipFile(self.req.local_file_path, allowZip64=True) as z: + return pkg_resources_distribution_for_wheel( + z, self.req.name, self.req.local_file_path + ) + + def prepare_distribution_metadata(self, finder, build_isolation): + # type: (PackageFinder, bool) -> None + pass diff --git a/venv/lib/python3.8/site-packages/pip/_internal/exceptions.py b/venv/lib/python3.8/site-packages/pip/_internal/exceptions.py new file mode 100644 index 0000000..8ac8548 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/exceptions.py @@ -0,0 +1,308 @@ +"""Exceptions used throughout package""" + +# The following comment should be removed at some point in the future. +# mypy: disallow-untyped-defs=False + +from __future__ import absolute_import + +from itertools import chain, groupby, repeat + +from pip._vendor.six import iteritems + +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Optional + from pip._vendor.pkg_resources import Distribution + from pip._internal.req.req_install import InstallRequirement + + +class PipError(Exception): + """Base pip exception""" + + +class ConfigurationError(PipError): + """General exception in configuration""" + + +class InstallationError(PipError): + """General exception during installation""" + + +class UninstallationError(PipError): + """General exception during uninstallation""" + + +class NoneMetadataError(PipError): + """ + Raised when accessing "METADATA" or "PKG-INFO" metadata for a + pip._vendor.pkg_resources.Distribution object and + `dist.has_metadata('METADATA')` returns True but + `dist.get_metadata('METADATA')` returns None (and similarly for + "PKG-INFO"). + """ + + def __init__(self, dist, metadata_name): + # type: (Distribution, str) -> None + """ + :param dist: A Distribution object. + :param metadata_name: The name of the metadata being accessed + (can be "METADATA" or "PKG-INFO"). + """ + self.dist = dist + self.metadata_name = metadata_name + + def __str__(self): + # type: () -> str + # Use `dist` in the error message because its stringification + # includes more information, like the version and location. + return ( + 'None {} metadata found for distribution: {}'.format( + self.metadata_name, self.dist, + ) + ) + + +class DistributionNotFound(InstallationError): + """Raised when a distribution cannot be found to satisfy a requirement""" + + +class RequirementsFileParseError(InstallationError): + """Raised when a general error occurs parsing a requirements file line.""" + + +class BestVersionAlreadyInstalled(PipError): + """Raised when the most up-to-date version of a package is already + installed.""" + + +class BadCommand(PipError): + """Raised when virtualenv or a command is not found""" + + +class CommandError(PipError): + """Raised when there is an error in command-line arguments""" + + +class PreviousBuildDirError(PipError): + """Raised when there's a previous conflicting build directory""" + + +class InvalidWheelFilename(InstallationError): + """Invalid wheel filename.""" + + +class UnsupportedWheel(InstallationError): + """Unsupported wheel.""" + + +class HashErrors(InstallationError): + """Multiple HashError instances rolled into one for reporting""" + + def __init__(self): + self.errors = [] + + def append(self, error): + self.errors.append(error) + + def __str__(self): + lines = [] + self.errors.sort(key=lambda e: e.order) + for cls, errors_of_cls in groupby(self.errors, lambda e: e.__class__): + lines.append(cls.head) + lines.extend(e.body() for e in errors_of_cls) + if lines: + return '\n'.join(lines) + + def __nonzero__(self): + return bool(self.errors) + + def __bool__(self): + return self.__nonzero__() + + +class HashError(InstallationError): + """ + A failure to verify a package against known-good hashes + + :cvar order: An int sorting hash exception classes by difficulty of + recovery (lower being harder), so the user doesn't bother fretting + about unpinned packages when he has deeper issues, like VCS + dependencies, to deal with. Also keeps error reports in a + deterministic order. + :cvar head: A section heading for display above potentially many + exceptions of this kind + :ivar req: The InstallRequirement that triggered this error. This is + pasted on after the exception is instantiated, because it's not + typically available earlier. + + """ + req = None # type: Optional[InstallRequirement] + head = '' + + def body(self): + """Return a summary of me for display under the heading. + + This default implementation simply prints a description of the + triggering requirement. + + :param req: The InstallRequirement that provoked this error, with + its link already populated by the resolver's _populate_link(). + + """ + return ' {}'.format(self._requirement_name()) + + def __str__(self): + return '{}\n{}'.format(self.head, self.body()) + + def _requirement_name(self): + """Return a description of the requirement that triggered me. + + This default implementation returns long description of the req, with + line numbers + + """ + return str(self.req) if self.req else 'unknown package' + + +class VcsHashUnsupported(HashError): + """A hash was provided for a version-control-system-based requirement, but + we don't have a method for hashing those.""" + + order = 0 + head = ("Can't verify hashes for these requirements because we don't " + "have a way to hash version control repositories:") + + +class DirectoryUrlHashUnsupported(HashError): + """A hash was provided for a version-control-system-based requirement, but + we don't have a method for hashing those.""" + + order = 1 + head = ("Can't verify hashes for these file:// requirements because they " + "point to directories:") + + +class HashMissing(HashError): + """A hash was needed for a requirement but is absent.""" + + order = 2 + head = ('Hashes are required in --require-hashes mode, but they are ' + 'missing from some requirements. Here is a list of those ' + 'requirements along with the hashes their downloaded archives ' + 'actually had. Add lines like these to your requirements files to ' + 'prevent tampering. (If you did not enable --require-hashes ' + 'manually, note that it turns on automatically when any package ' + 'has a hash.)') + + def __init__(self, gotten_hash): + """ + :param gotten_hash: The hash of the (possibly malicious) archive we + just downloaded + """ + self.gotten_hash = gotten_hash + + def body(self): + # Dodge circular import. + from pip._internal.utils.hashes import FAVORITE_HASH + + package = None + if self.req: + # In the case of URL-based requirements, display the original URL + # seen in the requirements file rather than the package name, + # so the output can be directly copied into the requirements file. + package = (self.req.original_link if self.req.original_link + # In case someone feeds something downright stupid + # to InstallRequirement's constructor. + else getattr(self.req, 'req', None)) + return ' {} --hash={}:{}'.format(package or 'unknown package', + FAVORITE_HASH, + self.gotten_hash) + + +class HashUnpinned(HashError): + """A requirement had a hash specified but was not pinned to a specific + version.""" + + order = 3 + head = ('In --require-hashes mode, all requirements must have their ' + 'versions pinned with ==. These do not:') + + +class HashMismatch(HashError): + """ + Distribution file hash values don't match. + + :ivar package_name: The name of the package that triggered the hash + mismatch. Feel free to write to this after the exception is raise to + improve its error message. + + """ + order = 4 + head = ('THESE PACKAGES DO NOT MATCH THE HASHES FROM THE REQUIREMENTS ' + 'FILE. If you have updated the package versions, please update ' + 'the hashes. Otherwise, examine the package contents carefully; ' + 'someone may have tampered with them.') + + def __init__(self, allowed, gots): + """ + :param allowed: A dict of algorithm names pointing to lists of allowed + hex digests + :param gots: A dict of algorithm names pointing to hashes we + actually got from the files under suspicion + """ + self.allowed = allowed + self.gots = gots + + def body(self): + return ' {}:\n{}'.format(self._requirement_name(), + self._hash_comparison()) + + def _hash_comparison(self): + """ + Return a comparison of actual and expected hash values. + + Example:: + + Expected sha256 abcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcde + or 123451234512345123451234512345123451234512345 + Got bcdefbcdefbcdefbcdefbcdefbcdefbcdefbcdefbcdef + + """ + def hash_then_or(hash_name): + # For now, all the decent hashes have 6-char names, so we can get + # away with hard-coding space literals. + return chain([hash_name], repeat(' or')) + + lines = [] + for hash_name, expecteds in iteritems(self.allowed): + prefix = hash_then_or(hash_name) + lines.extend((' Expected {} {}'.format(next(prefix), e)) + for e in expecteds) + lines.append(' Got {}\n'.format( + self.gots[hash_name].hexdigest())) + return '\n'.join(lines) + + +class UnsupportedPythonVersion(InstallationError): + """Unsupported python version according to Requires-Python package + metadata.""" + + +class ConfigurationFileCouldNotBeLoaded(ConfigurationError): + """When there are errors while loading a configuration file + """ + + def __init__(self, reason="could not be loaded", fname=None, error=None): + super(ConfigurationFileCouldNotBeLoaded, self).__init__(error) + self.reason = reason + self.fname = fname + self.error = error + + def __str__(self): + if self.fname is not None: + message_part = " in {}.".format(self.fname) + else: + assert self.error is not None + message_part = ".\n{}\n".format(self.error.message) + return "Configuration file {}{}".format(self.reason, message_part) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/index/__init__.py b/venv/lib/python3.8/site-packages/pip/_internal/index/__init__.py new file mode 100644 index 0000000..7a17b7b --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/index/__init__.py @@ -0,0 +1,2 @@ +"""Index interaction code +""" diff --git a/venv/lib/python3.8/site-packages/pip/_internal/index/collector.py b/venv/lib/python3.8/site-packages/pip/_internal/index/collector.py new file mode 100644 index 0000000..e2c800c --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/index/collector.py @@ -0,0 +1,661 @@ +""" +The main purpose of this module is to expose LinkCollector.collect_links(). +""" + +import cgi +import functools +import itertools +import logging +import mimetypes +import os +import re +from collections import OrderedDict + +from pip._vendor import html5lib, requests +from pip._vendor.distlib.compat import unescape +from pip._vendor.requests.exceptions import HTTPError, RetryError, SSLError +from pip._vendor.six.moves.urllib import parse as urllib_parse +from pip._vendor.six.moves.urllib import request as urllib_request + +from pip._internal.models.link import Link +from pip._internal.utils.filetypes import ARCHIVE_EXTENSIONS +from pip._internal.utils.misc import pairwise, redact_auth_from_url +from pip._internal.utils.typing import MYPY_CHECK_RUNNING +from pip._internal.utils.urls import path_to_url, url_to_path +from pip._internal.vcs import is_url, vcs + +if MYPY_CHECK_RUNNING: + from typing import ( + Callable, Iterable, List, MutableMapping, Optional, + Protocol, Sequence, Tuple, TypeVar, Union, + ) + import xml.etree.ElementTree + + from pip._vendor.requests import Response + + from pip._internal.models.search_scope import SearchScope + from pip._internal.network.session import PipSession + + HTMLElement = xml.etree.ElementTree.Element + ResponseHeaders = MutableMapping[str, str] + + # Used in the @lru_cache polyfill. + F = TypeVar('F') + + class LruCache(Protocol): + def __call__(self, maxsize=None): + # type: (Optional[int]) -> Callable[[F], F] + raise NotImplementedError + + +logger = logging.getLogger(__name__) + + +# Fallback to noop_lru_cache in Python 2 +# TODO: this can be removed when python 2 support is dropped! +def noop_lru_cache(maxsize=None): + # type: (Optional[int]) -> Callable[[F], F] + def _wrapper(f): + # type: (F) -> F + return f + return _wrapper + + +_lru_cache = getattr(functools, "lru_cache", noop_lru_cache) # type: LruCache + + +def _match_vcs_scheme(url): + # type: (str) -> Optional[str] + """Look for VCS schemes in the URL. + + Returns the matched VCS scheme, or None if there's no match. + """ + for scheme in vcs.schemes: + if url.lower().startswith(scheme) and url[len(scheme)] in '+:': + return scheme + return None + + +def _is_url_like_archive(url): + # type: (str) -> bool + """Return whether the URL looks like an archive. + """ + filename = Link(url).filename + for bad_ext in ARCHIVE_EXTENSIONS: + if filename.endswith(bad_ext): + return True + return False + + +class _NotHTML(Exception): + def __init__(self, content_type, request_desc): + # type: (str, str) -> None + super(_NotHTML, self).__init__(content_type, request_desc) + self.content_type = content_type + self.request_desc = request_desc + + +def _ensure_html_header(response): + # type: (Response) -> None + """Check the Content-Type header to ensure the response contains HTML. + + Raises `_NotHTML` if the content type is not text/html. + """ + content_type = response.headers.get("Content-Type", "") + if not content_type.lower().startswith("text/html"): + raise _NotHTML(content_type, response.request.method) + + +class _NotHTTP(Exception): + pass + + +def _ensure_html_response(url, session): + # type: (str, PipSession) -> None + """Send a HEAD request to the URL, and ensure the response contains HTML. + + Raises `_NotHTTP` if the URL is not available for a HEAD request, or + `_NotHTML` if the content type is not text/html. + """ + scheme, netloc, path, query, fragment = urllib_parse.urlsplit(url) + if scheme not in {'http', 'https'}: + raise _NotHTTP() + + resp = session.head(url, allow_redirects=True) + resp.raise_for_status() + + _ensure_html_header(resp) + + +def _get_html_response(url, session): + # type: (str, PipSession) -> Response + """Access an HTML page with GET, and return the response. + + This consists of three parts: + + 1. If the URL looks suspiciously like an archive, send a HEAD first to + check the Content-Type is HTML, to avoid downloading a large file. + Raise `_NotHTTP` if the content type cannot be determined, or + `_NotHTML` if it is not HTML. + 2. Actually perform the request. Raise HTTP exceptions on network failures. + 3. Check the Content-Type header to make sure we got HTML, and raise + `_NotHTML` otherwise. + """ + if _is_url_like_archive(url): + _ensure_html_response(url, session=session) + + logger.debug('Getting page %s', redact_auth_from_url(url)) + + resp = session.get( + url, + headers={ + "Accept": "text/html", + # We don't want to blindly returned cached data for + # /simple/, because authors generally expecting that + # twine upload && pip install will function, but if + # they've done a pip install in the last ~10 minutes + # it won't. Thus by setting this to zero we will not + # blindly use any cached data, however the benefit of + # using max-age=0 instead of no-cache, is that we will + # still support conditional requests, so we will still + # minimize traffic sent in cases where the page hasn't + # changed at all, we will just always incur the round + # trip for the conditional GET now instead of only + # once per 10 minutes. + # For more information, please see pypa/pip#5670. + "Cache-Control": "max-age=0", + }, + ) + resp.raise_for_status() + + # The check for archives above only works if the url ends with + # something that looks like an archive. However that is not a + # requirement of an url. Unless we issue a HEAD request on every + # url we cannot know ahead of time for sure if something is HTML + # or not. However we can check after we've downloaded it. + _ensure_html_header(resp) + + return resp + + +def _get_encoding_from_headers(headers): + # type: (ResponseHeaders) -> Optional[str] + """Determine if we have any encoding information in our headers. + """ + if headers and "Content-Type" in headers: + content_type, params = cgi.parse_header(headers["Content-Type"]) + if "charset" in params: + return params['charset'] + return None + + +def _determine_base_url(document, page_url): + # type: (HTMLElement, str) -> str + """Determine the HTML document's base URL. + + This looks for a ```` tag in the HTML document. If present, its href + attribute denotes the base URL of anchor tags in the document. If there is + no such tag (or if it does not have a valid href attribute), the HTML + file's URL is used as the base URL. + + :param document: An HTML document representation. The current + implementation expects the result of ``html5lib.parse()``. + :param page_url: The URL of the HTML document. + """ + for base in document.findall(".//base"): + href = base.get("href") + if href is not None: + return href + return page_url + + +def _clean_url_path_part(part): + # type: (str) -> str + """ + Clean a "part" of a URL path (i.e. after splitting on "@" characters). + """ + # We unquote prior to quoting to make sure nothing is double quoted. + return urllib_parse.quote(urllib_parse.unquote(part)) + + +def _clean_file_url_path(part): + # type: (str) -> str + """ + Clean the first part of a URL path that corresponds to a local + filesystem path (i.e. the first part after splitting on "@" characters). + """ + # We unquote prior to quoting to make sure nothing is double quoted. + # Also, on Windows the path part might contain a drive letter which + # should not be quoted. On Linux where drive letters do not + # exist, the colon should be quoted. We rely on urllib.request + # to do the right thing here. + return urllib_request.pathname2url(urllib_request.url2pathname(part)) + + +# percent-encoded: / +_reserved_chars_re = re.compile('(@|%2F)', re.IGNORECASE) + + +def _clean_url_path(path, is_local_path): + # type: (str, bool) -> str + """ + Clean the path portion of a URL. + """ + if is_local_path: + clean_func = _clean_file_url_path + else: + clean_func = _clean_url_path_part + + # Split on the reserved characters prior to cleaning so that + # revision strings in VCS URLs are properly preserved. + parts = _reserved_chars_re.split(path) + + cleaned_parts = [] + for to_clean, reserved in pairwise(itertools.chain(parts, [''])): + cleaned_parts.append(clean_func(to_clean)) + # Normalize %xx escapes (e.g. %2f -> %2F) + cleaned_parts.append(reserved.upper()) + + return ''.join(cleaned_parts) + + +def _clean_link(url): + # type: (str) -> str + """ + Make sure a link is fully quoted. + For example, if ' ' occurs in the URL, it will be replaced with "%20", + and without double-quoting other characters. + """ + # Split the URL into parts according to the general structure + # `scheme://netloc/path;parameters?query#fragment`. + result = urllib_parse.urlparse(url) + # If the netloc is empty, then the URL refers to a local filesystem path. + is_local_path = not result.netloc + path = _clean_url_path(result.path, is_local_path=is_local_path) + return urllib_parse.urlunparse(result._replace(path=path)) + + +def _create_link_from_element( + anchor, # type: HTMLElement + page_url, # type: str + base_url, # type: str +): + # type: (...) -> Optional[Link] + """ + Convert an anchor element in a simple repository page to a Link. + """ + href = anchor.get("href") + if not href: + return None + + url = _clean_link(urllib_parse.urljoin(base_url, href)) + pyrequire = anchor.get('data-requires-python') + pyrequire = unescape(pyrequire) if pyrequire else None + + yanked_reason = anchor.get('data-yanked') + if yanked_reason: + # This is a unicode string in Python 2 (and 3). + yanked_reason = unescape(yanked_reason) + + link = Link( + url, + comes_from=page_url, + requires_python=pyrequire, + yanked_reason=yanked_reason, + ) + + return link + + +class CacheablePageContent(object): + def __init__(self, page): + # type: (HTMLPage) -> None + assert page.cache_link_parsing + self.page = page + + def __eq__(self, other): + # type: (object) -> bool + return (isinstance(other, type(self)) and + self.page.url == other.page.url) + + def __hash__(self): + # type: () -> int + return hash(self.page.url) + + +def with_cached_html_pages( + fn, # type: Callable[[HTMLPage], Iterable[Link]] +): + # type: (...) -> Callable[[HTMLPage], List[Link]] + """ + Given a function that parses an Iterable[Link] from an HTMLPage, cache the + function's result (keyed by CacheablePageContent), unless the HTMLPage + `page` has `page.cache_link_parsing == False`. + """ + + @_lru_cache(maxsize=None) + def wrapper(cacheable_page): + # type: (CacheablePageContent) -> List[Link] + return list(fn(cacheable_page.page)) + + @functools.wraps(fn) + def wrapper_wrapper(page): + # type: (HTMLPage) -> List[Link] + if page.cache_link_parsing: + return wrapper(CacheablePageContent(page)) + return list(fn(page)) + + return wrapper_wrapper + + +@with_cached_html_pages +def parse_links(page): + # type: (HTMLPage) -> Iterable[Link] + """ + Parse an HTML document, and yield its anchor elements as Link objects. + """ + document = html5lib.parse( + page.content, + transport_encoding=page.encoding, + namespaceHTMLElements=False, + ) + + url = page.url + base_url = _determine_base_url(document, url) + for anchor in document.findall(".//a"): + link = _create_link_from_element( + anchor, + page_url=url, + base_url=base_url, + ) + if link is None: + continue + yield link + + +class HTMLPage(object): + """Represents one page, along with its URL""" + + def __init__( + self, + content, # type: bytes + encoding, # type: Optional[str] + url, # type: str + cache_link_parsing=True, # type: bool + ): + # type: (...) -> None + """ + :param encoding: the encoding to decode the given content. + :param url: the URL from which the HTML was downloaded. + :param cache_link_parsing: whether links parsed from this page's url + should be cached. PyPI index urls should + have this set to False, for example. + """ + self.content = content + self.encoding = encoding + self.url = url + self.cache_link_parsing = cache_link_parsing + + def __str__(self): + # type: () -> str + return redact_auth_from_url(self.url) + + +def _handle_get_page_fail( + link, # type: Link + reason, # type: Union[str, Exception] + meth=None # type: Optional[Callable[..., None]] +): + # type: (...) -> None + if meth is None: + meth = logger.debug + meth("Could not fetch URL %s: %s - skipping", link, reason) + + +def _make_html_page(response, cache_link_parsing=True): + # type: (Response, bool) -> HTMLPage + encoding = _get_encoding_from_headers(response.headers) + return HTMLPage( + response.content, + encoding=encoding, + url=response.url, + cache_link_parsing=cache_link_parsing) + + +def _get_html_page(link, session=None): + # type: (Link, Optional[PipSession]) -> Optional[HTMLPage] + if session is None: + raise TypeError( + "_get_html_page() missing 1 required keyword argument: 'session'" + ) + + url = link.url.split('#', 1)[0] + + # Check for VCS schemes that do not support lookup as web pages. + vcs_scheme = _match_vcs_scheme(url) + if vcs_scheme: + logger.debug('Cannot look at %s URL %s', vcs_scheme, link) + return None + + # Tack index.html onto file:// URLs that point to directories + scheme, _, path, _, _, _ = urllib_parse.urlparse(url) + if (scheme == 'file' and os.path.isdir(urllib_request.url2pathname(path))): + # add trailing slash if not present so urljoin doesn't trim + # final segment + if not url.endswith('/'): + url += '/' + url = urllib_parse.urljoin(url, 'index.html') + logger.debug(' file: URL is directory, getting %s', url) + + try: + resp = _get_html_response(url, session=session) + except _NotHTTP: + logger.debug( + 'Skipping page %s because it looks like an archive, and cannot ' + 'be checked by HEAD.', link, + ) + except _NotHTML as exc: + logger.debug( + 'Skipping page %s because the %s request got Content-Type: %s', + link, exc.request_desc, exc.content_type, + ) + except HTTPError as exc: + _handle_get_page_fail(link, exc) + except RetryError as exc: + _handle_get_page_fail(link, exc) + except SSLError as exc: + reason = "There was a problem confirming the ssl certificate: " + reason += str(exc) + _handle_get_page_fail(link, reason, meth=logger.info) + except requests.ConnectionError as exc: + _handle_get_page_fail(link, "connection error: {}".format(exc)) + except requests.Timeout: + _handle_get_page_fail(link, "timed out") + else: + return _make_html_page(resp, + cache_link_parsing=link.cache_link_parsing) + return None + + +def _remove_duplicate_links(links): + # type: (Iterable[Link]) -> List[Link] + """ + Return a list of links, with duplicates removed and ordering preserved. + """ + # We preserve the ordering when removing duplicates because we can. + return list(OrderedDict.fromkeys(links)) + + +def group_locations(locations, expand_dir=False): + # type: (Sequence[str], bool) -> Tuple[List[str], List[str]] + """ + Divide a list of locations into two groups: "files" (archives) and "urls." + + :return: A pair of lists (files, urls). + """ + files = [] + urls = [] + + # puts the url for the given file path into the appropriate list + def sort_path(path): + # type: (str) -> None + url = path_to_url(path) + if mimetypes.guess_type(url, strict=False)[0] == 'text/html': + urls.append(url) + else: + files.append(url) + + for url in locations: + + is_local_path = os.path.exists(url) + is_file_url = url.startswith('file:') + + if is_local_path or is_file_url: + if is_local_path: + path = url + else: + path = url_to_path(url) + if os.path.isdir(path): + if expand_dir: + path = os.path.realpath(path) + for item in os.listdir(path): + sort_path(os.path.join(path, item)) + elif is_file_url: + urls.append(url) + else: + logger.warning( + "Path '{0}' is ignored: " + "it is a directory.".format(path), + ) + elif os.path.isfile(path): + sort_path(path) + else: + logger.warning( + "Url '%s' is ignored: it is neither a file " + "nor a directory.", url, + ) + elif is_url(url): + # Only add url with clear scheme + urls.append(url) + else: + logger.warning( + "Url '%s' is ignored. It is either a non-existing " + "path or lacks a specific scheme.", url, + ) + + return files, urls + + +class CollectedLinks(object): + + """ + Encapsulates the return value of a call to LinkCollector.collect_links(). + + The return value includes both URLs to project pages containing package + links, as well as individual package Link objects collected from other + sources. + + This info is stored separately as: + + (1) links from the configured file locations, + (2) links from the configured find_links, and + (3) urls to HTML project pages, as described by the PEP 503 simple + repository API. + """ + + def __init__( + self, + files, # type: List[Link] + find_links, # type: List[Link] + project_urls, # type: List[Link] + ): + # type: (...) -> None + """ + :param files: Links from file locations. + :param find_links: Links from find_links. + :param project_urls: URLs to HTML project pages, as described by + the PEP 503 simple repository API. + """ + self.files = files + self.find_links = find_links + self.project_urls = project_urls + + +class LinkCollector(object): + + """ + Responsible for collecting Link objects from all configured locations, + making network requests as needed. + + The class's main method is its collect_links() method. + """ + + def __init__( + self, + session, # type: PipSession + search_scope, # type: SearchScope + ): + # type: (...) -> None + self.search_scope = search_scope + self.session = session + + @property + def find_links(self): + # type: () -> List[str] + return self.search_scope.find_links + + def fetch_page(self, location): + # type: (Link) -> Optional[HTMLPage] + """ + Fetch an HTML page containing package links. + """ + return _get_html_page(location, session=self.session) + + def collect_links(self, project_name): + # type: (str) -> CollectedLinks + """Find all available links for the given project name. + + :return: All the Link objects (unfiltered), as a CollectedLinks object. + """ + search_scope = self.search_scope + index_locations = search_scope.get_index_urls_locations(project_name) + index_file_loc, index_url_loc = group_locations(index_locations) + fl_file_loc, fl_url_loc = group_locations( + self.find_links, expand_dir=True, + ) + + file_links = [ + Link(url) for url in itertools.chain(index_file_loc, fl_file_loc) + ] + + # We trust every directly linked archive in find_links + find_link_links = [Link(url, '-f') for url in self.find_links] + + # We trust every url that the user has given us whether it was given + # via --index-url or --find-links. + # We want to filter out anything that does not have a secure origin. + url_locations = [ + link for link in itertools.chain( + # Mark PyPI indices as "cache_link_parsing == False" -- this + # will avoid caching the result of parsing the page for links. + (Link(url, cache_link_parsing=False) for url in index_url_loc), + (Link(url) for url in fl_url_loc), + ) + if self.session.is_secure_origin(link) + ] + + url_locations = _remove_duplicate_links(url_locations) + lines = [ + '{} location(s) to search for versions of {}:'.format( + len(url_locations), project_name, + ), + ] + for link in url_locations: + lines.append('* {}'.format(link)) + logger.debug('\n'.join(lines)) + + return CollectedLinks( + files=file_links, + find_links=find_link_links, + project_urls=url_locations, + ) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/index/package_finder.py b/venv/lib/python3.8/site-packages/pip/_internal/index/package_finder.py new file mode 100644 index 0000000..e88ad9f --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/index/package_finder.py @@ -0,0 +1,1016 @@ +"""Routines related to PyPI, indexes""" + +# The following comment should be removed at some point in the future. +# mypy: strict-optional=False + +from __future__ import absolute_import + +import logging +import re + +from pip._vendor.packaging import specifiers +from pip._vendor.packaging.utils import canonicalize_name +from pip._vendor.packaging.version import parse as parse_version + +from pip._internal.exceptions import ( + BestVersionAlreadyInstalled, + DistributionNotFound, + InvalidWheelFilename, + UnsupportedWheel, +) +from pip._internal.index.collector import parse_links +from pip._internal.models.candidate import InstallationCandidate +from pip._internal.models.format_control import FormatControl +from pip._internal.models.link import Link +from pip._internal.models.selection_prefs import SelectionPreferences +from pip._internal.models.target_python import TargetPython +from pip._internal.models.wheel import Wheel +from pip._internal.utils.filetypes import WHEEL_EXTENSION +from pip._internal.utils.logging import indent_log +from pip._internal.utils.misc import build_netloc +from pip._internal.utils.packaging import check_requires_python +from pip._internal.utils.typing import MYPY_CHECK_RUNNING +from pip._internal.utils.unpacking import SUPPORTED_EXTENSIONS +from pip._internal.utils.urls import url_to_path + +if MYPY_CHECK_RUNNING: + from typing import ( + FrozenSet, Iterable, List, Optional, Set, Text, Tuple, Union, + ) + + from pip._vendor.packaging.tags import Tag + from pip._vendor.packaging.version import _BaseVersion + + from pip._internal.index.collector import LinkCollector + from pip._internal.models.search_scope import SearchScope + from pip._internal.req import InstallRequirement + from pip._internal.utils.hashes import Hashes + + BuildTag = Union[Tuple[()], Tuple[int, str]] + CandidateSortingKey = ( + Tuple[int, int, int, _BaseVersion, BuildTag, Optional[int]] + ) + + +__all__ = ['FormatControl', 'BestCandidateResult', 'PackageFinder'] + + +logger = logging.getLogger(__name__) + + +def _check_link_requires_python( + link, # type: Link + version_info, # type: Tuple[int, int, int] + ignore_requires_python=False, # type: bool +): + # type: (...) -> bool + """ + Return whether the given Python version is compatible with a link's + "Requires-Python" value. + + :param version_info: A 3-tuple of ints representing the Python + major-minor-micro version to check. + :param ignore_requires_python: Whether to ignore the "Requires-Python" + value if the given Python version isn't compatible. + """ + try: + is_compatible = check_requires_python( + link.requires_python, version_info=version_info, + ) + except specifiers.InvalidSpecifier: + logger.debug( + "Ignoring invalid Requires-Python (%r) for link: %s", + link.requires_python, link, + ) + else: + if not is_compatible: + version = '.'.join(map(str, version_info)) + if not ignore_requires_python: + logger.debug( + 'Link requires a different Python (%s not in: %r): %s', + version, link.requires_python, link, + ) + return False + + logger.debug( + 'Ignoring failed Requires-Python check (%s not in: %r) ' + 'for link: %s', + version, link.requires_python, link, + ) + + return True + + +class LinkEvaluator(object): + + """ + Responsible for evaluating links for a particular project. + """ + + _py_version_re = re.compile(r'-py([123]\.?[0-9]?)$') + + # Don't include an allow_yanked default value to make sure each call + # site considers whether yanked releases are allowed. This also causes + # that decision to be made explicit in the calling code, which helps + # people when reading the code. + def __init__( + self, + project_name, # type: str + canonical_name, # type: str + formats, # type: FrozenSet[str] + target_python, # type: TargetPython + allow_yanked, # type: bool + ignore_requires_python=None, # type: Optional[bool] + ): + # type: (...) -> None + """ + :param project_name: The user supplied package name. + :param canonical_name: The canonical package name. + :param formats: The formats allowed for this package. Should be a set + with 'binary' or 'source' or both in it. + :param target_python: The target Python interpreter to use when + evaluating link compatibility. This is used, for example, to + check wheel compatibility, as well as when checking the Python + version, e.g. the Python version embedded in a link filename + (or egg fragment) and against an HTML link's optional PEP 503 + "data-requires-python" attribute. + :param allow_yanked: Whether files marked as yanked (in the sense + of PEP 592) are permitted to be candidates for install. + :param ignore_requires_python: Whether to ignore incompatible + PEP 503 "data-requires-python" values in HTML links. Defaults + to False. + """ + if ignore_requires_python is None: + ignore_requires_python = False + + self._allow_yanked = allow_yanked + self._canonical_name = canonical_name + self._ignore_requires_python = ignore_requires_python + self._formats = formats + self._target_python = target_python + + self.project_name = project_name + + def evaluate_link(self, link): + # type: (Link) -> Tuple[bool, Optional[Text]] + """ + Determine whether a link is a candidate for installation. + + :return: A tuple (is_candidate, result), where `result` is (1) a + version string if `is_candidate` is True, and (2) if + `is_candidate` is False, an optional string to log the reason + the link fails to qualify. + """ + version = None + if link.is_yanked and not self._allow_yanked: + reason = link.yanked_reason or '' + # Mark this as a unicode string to prevent "UnicodeEncodeError: + # 'ascii' codec can't encode character" in Python 2 when + # the reason contains non-ascii characters. + return (False, u'yanked for reason: {}'.format(reason)) + + if link.egg_fragment: + egg_info = link.egg_fragment + ext = link.ext + else: + egg_info, ext = link.splitext() + if not ext: + return (False, 'not a file') + if ext not in SUPPORTED_EXTENSIONS: + return (False, 'unsupported archive format: {}'.format(ext)) + if "binary" not in self._formats and ext == WHEEL_EXTENSION: + reason = 'No binaries permitted for {}'.format( + self.project_name) + return (False, reason) + if "macosx10" in link.path and ext == '.zip': + return (False, 'macosx10 one') + if ext == WHEEL_EXTENSION: + try: + wheel = Wheel(link.filename) + except InvalidWheelFilename: + return (False, 'invalid wheel filename') + if canonicalize_name(wheel.name) != self._canonical_name: + reason = 'wrong project name (not {})'.format( + self.project_name) + return (False, reason) + + supported_tags = self._target_python.get_tags() + if not wheel.supported(supported_tags): + # Include the wheel's tags in the reason string to + # simplify troubleshooting compatibility issues. + file_tags = wheel.get_formatted_file_tags() + reason = ( + "none of the wheel's tags match: {}".format( + ', '.join(file_tags) + ) + ) + return (False, reason) + + version = wheel.version + + # This should be up by the self.ok_binary check, but see issue 2700. + if "source" not in self._formats and ext != WHEEL_EXTENSION: + reason = 'No sources permitted for {}'.format(self.project_name) + return (False, reason) + + if not version: + version = _extract_version_from_fragment( + egg_info, self._canonical_name, + ) + if not version: + reason = 'Missing project version for {}'.format(self.project_name) + return (False, reason) + + match = self._py_version_re.search(version) + if match: + version = version[:match.start()] + py_version = match.group(1) + if py_version != self._target_python.py_version: + return (False, 'Python version is incorrect') + + supports_python = _check_link_requires_python( + link, version_info=self._target_python.py_version_info, + ignore_requires_python=self._ignore_requires_python, + ) + if not supports_python: + # Return None for the reason text to suppress calling + # _log_skipped_link(). + return (False, None) + + logger.debug('Found link %s, version: %s', link, version) + + return (True, version) + + +def filter_unallowed_hashes( + candidates, # type: List[InstallationCandidate] + hashes, # type: Hashes + project_name, # type: str +): + # type: (...) -> List[InstallationCandidate] + """ + Filter out candidates whose hashes aren't allowed, and return a new + list of candidates. + + If at least one candidate has an allowed hash, then all candidates with + either an allowed hash or no hash specified are returned. Otherwise, + the given candidates are returned. + + Including the candidates with no hash specified when there is a match + allows a warning to be logged if there is a more preferred candidate + with no hash specified. Returning all candidates in the case of no + matches lets pip report the hash of the candidate that would otherwise + have been installed (e.g. permitting the user to more easily update + their requirements file with the desired hash). + """ + if not hashes: + logger.debug( + 'Given no hashes to check %s links for project %r: ' + 'discarding no candidates', + len(candidates), + project_name, + ) + # Make sure we're not returning back the given value. + return list(candidates) + + matches_or_no_digest = [] + # Collect the non-matches for logging purposes. + non_matches = [] + match_count = 0 + for candidate in candidates: + link = candidate.link + if not link.has_hash: + pass + elif link.is_hash_allowed(hashes=hashes): + match_count += 1 + else: + non_matches.append(candidate) + continue + + matches_or_no_digest.append(candidate) + + if match_count: + filtered = matches_or_no_digest + else: + # Make sure we're not returning back the given value. + filtered = list(candidates) + + if len(filtered) == len(candidates): + discard_message = 'discarding no candidates' + else: + discard_message = 'discarding {} non-matches:\n {}'.format( + len(non_matches), + '\n '.join(str(candidate.link) for candidate in non_matches) + ) + + logger.debug( + 'Checked %s links for project %r against %s hashes ' + '(%s matches, %s no digest): %s', + len(candidates), + project_name, + hashes.digest_count, + match_count, + len(matches_or_no_digest) - match_count, + discard_message + ) + + return filtered + + +class CandidatePreferences(object): + + """ + Encapsulates some of the preferences for filtering and sorting + InstallationCandidate objects. + """ + + def __init__( + self, + prefer_binary=False, # type: bool + allow_all_prereleases=False, # type: bool + ): + # type: (...) -> None + """ + :param allow_all_prereleases: Whether to allow all pre-releases. + """ + self.allow_all_prereleases = allow_all_prereleases + self.prefer_binary = prefer_binary + + +class BestCandidateResult(object): + """A collection of candidates, returned by `PackageFinder.find_best_candidate`. + + This class is only intended to be instantiated by CandidateEvaluator's + `compute_best_candidate()` method. + """ + + def __init__( + self, + candidates, # type: List[InstallationCandidate] + applicable_candidates, # type: List[InstallationCandidate] + best_candidate, # type: Optional[InstallationCandidate] + ): + # type: (...) -> None + """ + :param candidates: A sequence of all available candidates found. + :param applicable_candidates: The applicable candidates. + :param best_candidate: The most preferred candidate found, or None + if no applicable candidates were found. + """ + assert set(applicable_candidates) <= set(candidates) + + if best_candidate is None: + assert not applicable_candidates + else: + assert best_candidate in applicable_candidates + + self._applicable_candidates = applicable_candidates + self._candidates = candidates + + self.best_candidate = best_candidate + + def iter_all(self): + # type: () -> Iterable[InstallationCandidate] + """Iterate through all candidates. + """ + return iter(self._candidates) + + def iter_applicable(self): + # type: () -> Iterable[InstallationCandidate] + """Iterate through the applicable candidates. + """ + return iter(self._applicable_candidates) + + +class CandidateEvaluator(object): + + """ + Responsible for filtering and sorting candidates for installation based + on what tags are valid. + """ + + @classmethod + def create( + cls, + project_name, # type: str + target_python=None, # type: Optional[TargetPython] + prefer_binary=False, # type: bool + allow_all_prereleases=False, # type: bool + specifier=None, # type: Optional[specifiers.BaseSpecifier] + hashes=None, # type: Optional[Hashes] + ): + # type: (...) -> CandidateEvaluator + """Create a CandidateEvaluator object. + + :param target_python: The target Python interpreter to use when + checking compatibility. If None (the default), a TargetPython + object will be constructed from the running Python. + :param specifier: An optional object implementing `filter` + (e.g. `packaging.specifiers.SpecifierSet`) to filter applicable + versions. + :param hashes: An optional collection of allowed hashes. + """ + if target_python is None: + target_python = TargetPython() + if specifier is None: + specifier = specifiers.SpecifierSet() + + supported_tags = target_python.get_tags() + + return cls( + project_name=project_name, + supported_tags=supported_tags, + specifier=specifier, + prefer_binary=prefer_binary, + allow_all_prereleases=allow_all_prereleases, + hashes=hashes, + ) + + def __init__( + self, + project_name, # type: str + supported_tags, # type: List[Tag] + specifier, # type: specifiers.BaseSpecifier + prefer_binary=False, # type: bool + allow_all_prereleases=False, # type: bool + hashes=None, # type: Optional[Hashes] + ): + # type: (...) -> None + """ + :param supported_tags: The PEP 425 tags supported by the target + Python in order of preference (most preferred first). + """ + self._allow_all_prereleases = allow_all_prereleases + self._hashes = hashes + self._prefer_binary = prefer_binary + self._project_name = project_name + self._specifier = specifier + self._supported_tags = supported_tags + + def get_applicable_candidates( + self, + candidates, # type: List[InstallationCandidate] + ): + # type: (...) -> List[InstallationCandidate] + """ + Return the applicable candidates from a list of candidates. + """ + # Using None infers from the specifier instead. + allow_prereleases = self._allow_all_prereleases or None + specifier = self._specifier + versions = { + str(v) for v in specifier.filter( + # We turn the version object into a str here because otherwise + # when we're debundled but setuptools isn't, Python will see + # packaging.version.Version and + # pkg_resources._vendor.packaging.version.Version as different + # types. This way we'll use a str as a common data interchange + # format. If we stop using the pkg_resources provided specifier + # and start using our own, we can drop the cast to str(). + (str(c.version) for c in candidates), + prereleases=allow_prereleases, + ) + } + + # Again, converting version to str to deal with debundling. + applicable_candidates = [ + c for c in candidates if str(c.version) in versions + ] + + filtered_applicable_candidates = filter_unallowed_hashes( + candidates=applicable_candidates, + hashes=self._hashes, + project_name=self._project_name, + ) + + return sorted(filtered_applicable_candidates, key=self._sort_key) + + def _sort_key(self, candidate): + # type: (InstallationCandidate) -> CandidateSortingKey + """ + Function to pass as the `key` argument to a call to sorted() to sort + InstallationCandidates by preference. + + Returns a tuple such that tuples sorting as greater using Python's + default comparison operator are more preferred. + + The preference is as follows: + + First and foremost, candidates with allowed (matching) hashes are + always preferred over candidates without matching hashes. This is + because e.g. if the only candidate with an allowed hash is yanked, + we still want to use that candidate. + + Second, excepting hash considerations, candidates that have been + yanked (in the sense of PEP 592) are always less preferred than + candidates that haven't been yanked. Then: + + If not finding wheels, they are sorted by version only. + If finding wheels, then the sort order is by version, then: + 1. existing installs + 2. wheels ordered via Wheel.support_index_min(self._supported_tags) + 3. source archives + If prefer_binary was set, then all wheels are sorted above sources. + + Note: it was considered to embed this logic into the Link + comparison operators, but then different sdist links + with the same version, would have to be considered equal + """ + valid_tags = self._supported_tags + support_num = len(valid_tags) + build_tag = () # type: BuildTag + binary_preference = 0 + link = candidate.link + if link.is_wheel: + # can raise InvalidWheelFilename + wheel = Wheel(link.filename) + if not wheel.supported(valid_tags): + raise UnsupportedWheel( + "{} is not a supported wheel for this platform. It " + "can't be sorted.".format(wheel.filename) + ) + if self._prefer_binary: + binary_preference = 1 + pri = -(wheel.support_index_min(valid_tags)) + if wheel.build_tag is not None: + match = re.match(r'^(\d+)(.*)$', wheel.build_tag) + build_tag_groups = match.groups() + build_tag = (int(build_tag_groups[0]), build_tag_groups[1]) + else: # sdist + pri = -(support_num) + has_allowed_hash = int(link.is_hash_allowed(self._hashes)) + yank_value = -1 * int(link.is_yanked) # -1 for yanked. + return ( + has_allowed_hash, yank_value, binary_preference, candidate.version, + build_tag, pri, + ) + + def sort_best_candidate( + self, + candidates, # type: List[InstallationCandidate] + ): + # type: (...) -> Optional[InstallationCandidate] + """ + Return the best candidate per the instance's sort order, or None if + no candidate is acceptable. + """ + if not candidates: + return None + + best_candidate = max(candidates, key=self._sort_key) + + # Log a warning per PEP 592 if necessary before returning. + link = best_candidate.link + if link.is_yanked: + reason = link.yanked_reason or '' + msg = ( + # Mark this as a unicode string to prevent + # "UnicodeEncodeError: 'ascii' codec can't encode character" + # in Python 2 when the reason contains non-ascii characters. + u'The candidate selected for download or install is a ' + 'yanked version: {candidate}\n' + 'Reason for being yanked: {reason}' + ).format(candidate=best_candidate, reason=reason) + logger.warning(msg) + + return best_candidate + + def compute_best_candidate( + self, + candidates, # type: List[InstallationCandidate] + ): + # type: (...) -> BestCandidateResult + """ + Compute and return a `BestCandidateResult` instance. + """ + applicable_candidates = self.get_applicable_candidates(candidates) + + best_candidate = self.sort_best_candidate(applicable_candidates) + + return BestCandidateResult( + candidates, + applicable_candidates=applicable_candidates, + best_candidate=best_candidate, + ) + + +class PackageFinder(object): + """This finds packages. + + This is meant to match easy_install's technique for looking for + packages, by reading pages and looking for appropriate links. + """ + + def __init__( + self, + link_collector, # type: LinkCollector + target_python, # type: TargetPython + allow_yanked, # type: bool + format_control=None, # type: Optional[FormatControl] + candidate_prefs=None, # type: CandidatePreferences + ignore_requires_python=None, # type: Optional[bool] + ): + # type: (...) -> None + """ + This constructor is primarily meant to be used by the create() class + method and from tests. + + :param format_control: A FormatControl object, used to control + the selection of source packages / binary packages when consulting + the index and links. + :param candidate_prefs: Options to use when creating a + CandidateEvaluator object. + """ + if candidate_prefs is None: + candidate_prefs = CandidatePreferences() + + format_control = format_control or FormatControl(set(), set()) + + self._allow_yanked = allow_yanked + self._candidate_prefs = candidate_prefs + self._ignore_requires_python = ignore_requires_python + self._link_collector = link_collector + self._target_python = target_python + + self.format_control = format_control + + # These are boring links that have already been logged somehow. + self._logged_links = set() # type: Set[Link] + + # Don't include an allow_yanked default value to make sure each call + # site considers whether yanked releases are allowed. This also causes + # that decision to be made explicit in the calling code, which helps + # people when reading the code. + @classmethod + def create( + cls, + link_collector, # type: LinkCollector + selection_prefs, # type: SelectionPreferences + target_python=None, # type: Optional[TargetPython] + ): + # type: (...) -> PackageFinder + """Create a PackageFinder. + + :param selection_prefs: The candidate selection preferences, as a + SelectionPreferences object. + :param target_python: The target Python interpreter to use when + checking compatibility. If None (the default), a TargetPython + object will be constructed from the running Python. + """ + if target_python is None: + target_python = TargetPython() + + candidate_prefs = CandidatePreferences( + prefer_binary=selection_prefs.prefer_binary, + allow_all_prereleases=selection_prefs.allow_all_prereleases, + ) + + return cls( + candidate_prefs=candidate_prefs, + link_collector=link_collector, + target_python=target_python, + allow_yanked=selection_prefs.allow_yanked, + format_control=selection_prefs.format_control, + ignore_requires_python=selection_prefs.ignore_requires_python, + ) + + @property + def search_scope(self): + # type: () -> SearchScope + return self._link_collector.search_scope + + @search_scope.setter + def search_scope(self, search_scope): + # type: (SearchScope) -> None + self._link_collector.search_scope = search_scope + + @property + def find_links(self): + # type: () -> List[str] + return self._link_collector.find_links + + @property + def index_urls(self): + # type: () -> List[str] + return self.search_scope.index_urls + + @property + def trusted_hosts(self): + # type: () -> Iterable[str] + for host_port in self._link_collector.session.pip_trusted_origins: + yield build_netloc(*host_port) + + @property + def allow_all_prereleases(self): + # type: () -> bool + return self._candidate_prefs.allow_all_prereleases + + def set_allow_all_prereleases(self): + # type: () -> None + self._candidate_prefs.allow_all_prereleases = True + + def make_link_evaluator(self, project_name): + # type: (str) -> LinkEvaluator + canonical_name = canonicalize_name(project_name) + formats = self.format_control.get_allowed_formats(canonical_name) + + return LinkEvaluator( + project_name=project_name, + canonical_name=canonical_name, + formats=formats, + target_python=self._target_python, + allow_yanked=self._allow_yanked, + ignore_requires_python=self._ignore_requires_python, + ) + + def _sort_links(self, links): + # type: (Iterable[Link]) -> List[Link] + """ + Returns elements of links in order, non-egg links first, egg links + second, while eliminating duplicates + """ + eggs, no_eggs = [], [] + seen = set() # type: Set[Link] + for link in links: + if link not in seen: + seen.add(link) + if link.egg_fragment: + eggs.append(link) + else: + no_eggs.append(link) + return no_eggs + eggs + + def _log_skipped_link(self, link, reason): + # type: (Link, Text) -> None + if link not in self._logged_links: + # Mark this as a unicode string to prevent "UnicodeEncodeError: + # 'ascii' codec can't encode character" in Python 2 when + # the reason contains non-ascii characters. + # Also, put the link at the end so the reason is more visible + # and because the link string is usually very long. + logger.debug(u'Skipping link: %s: %s', reason, link) + self._logged_links.add(link) + + def get_install_candidate(self, link_evaluator, link): + # type: (LinkEvaluator, Link) -> Optional[InstallationCandidate] + """ + If the link is a candidate for install, convert it to an + InstallationCandidate and return it. Otherwise, return None. + """ + is_candidate, result = link_evaluator.evaluate_link(link) + if not is_candidate: + if result: + self._log_skipped_link(link, reason=result) + return None + + return InstallationCandidate( + name=link_evaluator.project_name, + link=link, + # Convert the Text result to str since InstallationCandidate + # accepts str. + version=str(result), + ) + + def evaluate_links(self, link_evaluator, links): + # type: (LinkEvaluator, Iterable[Link]) -> List[InstallationCandidate] + """ + Convert links that are candidates to InstallationCandidate objects. + """ + candidates = [] + for link in self._sort_links(links): + candidate = self.get_install_candidate(link_evaluator, link) + if candidate is not None: + candidates.append(candidate) + + return candidates + + def process_project_url(self, project_url, link_evaluator): + # type: (Link, LinkEvaluator) -> List[InstallationCandidate] + logger.debug( + 'Fetching project page and analyzing links: %s', project_url, + ) + html_page = self._link_collector.fetch_page(project_url) + if html_page is None: + return [] + + page_links = list(parse_links(html_page)) + + with indent_log(): + package_links = self.evaluate_links( + link_evaluator, + links=page_links, + ) + + return package_links + + def find_all_candidates(self, project_name): + # type: (str) -> List[InstallationCandidate] + """Find all available InstallationCandidate for project_name + + This checks index_urls and find_links. + All versions found are returned as an InstallationCandidate list. + + See LinkEvaluator.evaluate_link() for details on which files + are accepted. + """ + collected_links = self._link_collector.collect_links(project_name) + + link_evaluator = self.make_link_evaluator(project_name) + + find_links_versions = self.evaluate_links( + link_evaluator, + links=collected_links.find_links, + ) + + page_versions = [] + for project_url in collected_links.project_urls: + package_links = self.process_project_url( + project_url, link_evaluator=link_evaluator, + ) + page_versions.extend(package_links) + + file_versions = self.evaluate_links( + link_evaluator, + links=collected_links.files, + ) + if file_versions: + file_versions.sort(reverse=True) + logger.debug( + 'Local files found: %s', + ', '.join([ + url_to_path(candidate.link.url) + for candidate in file_versions + ]) + ) + + # This is an intentional priority ordering + return file_versions + find_links_versions + page_versions + + def make_candidate_evaluator( + self, + project_name, # type: str + specifier=None, # type: Optional[specifiers.BaseSpecifier] + hashes=None, # type: Optional[Hashes] + ): + # type: (...) -> CandidateEvaluator + """Create a CandidateEvaluator object to use. + """ + candidate_prefs = self._candidate_prefs + return CandidateEvaluator.create( + project_name=project_name, + target_python=self._target_python, + prefer_binary=candidate_prefs.prefer_binary, + allow_all_prereleases=candidate_prefs.allow_all_prereleases, + specifier=specifier, + hashes=hashes, + ) + + def find_best_candidate( + self, + project_name, # type: str + specifier=None, # type: Optional[specifiers.BaseSpecifier] + hashes=None, # type: Optional[Hashes] + ): + # type: (...) -> BestCandidateResult + """Find matches for the given project and specifier. + + :param specifier: An optional object implementing `filter` + (e.g. `packaging.specifiers.SpecifierSet`) to filter applicable + versions. + + :return: A `BestCandidateResult` instance. + """ + candidates = self.find_all_candidates(project_name) + candidate_evaluator = self.make_candidate_evaluator( + project_name=project_name, + specifier=specifier, + hashes=hashes, + ) + return candidate_evaluator.compute_best_candidate(candidates) + + def find_requirement(self, req, upgrade): + # type: (InstallRequirement, bool) -> Optional[Link] + """Try to find a Link matching req + + Expects req, an InstallRequirement and upgrade, a boolean + Returns a Link if found, + Raises DistributionNotFound or BestVersionAlreadyInstalled otherwise + """ + hashes = req.hashes(trust_internet=False) + best_candidate_result = self.find_best_candidate( + req.name, specifier=req.specifier, hashes=hashes, + ) + best_candidate = best_candidate_result.best_candidate + + installed_version = None # type: Optional[_BaseVersion] + if req.satisfied_by is not None: + installed_version = parse_version(req.satisfied_by.version) + + def _format_versions(cand_iter): + # type: (Iterable[InstallationCandidate]) -> str + # This repeated parse_version and str() conversion is needed to + # handle different vendoring sources from pip and pkg_resources. + # If we stop using the pkg_resources provided specifier and start + # using our own, we can drop the cast to str(). + return ", ".join(sorted( + {str(c.version) for c in cand_iter}, + key=parse_version, + )) or "none" + + if installed_version is None and best_candidate is None: + logger.critical( + 'Could not find a version that satisfies the requirement %s ' + '(from versions: %s)', + req, + _format_versions(best_candidate_result.iter_all()), + ) + + raise DistributionNotFound( + 'No matching distribution found for {}'.format( + req) + ) + + best_installed = False + if installed_version and ( + best_candidate is None or + best_candidate.version <= installed_version): + best_installed = True + + if not upgrade and installed_version is not None: + if best_installed: + logger.debug( + 'Existing installed version (%s) is most up-to-date and ' + 'satisfies requirement', + installed_version, + ) + else: + logger.debug( + 'Existing installed version (%s) satisfies requirement ' + '(most up-to-date version is %s)', + installed_version, + best_candidate.version, + ) + return None + + if best_installed: + # We have an existing version, and its the best version + logger.debug( + 'Installed version (%s) is most up-to-date (past versions: ' + '%s)', + installed_version, + _format_versions(best_candidate_result.iter_applicable()), + ) + raise BestVersionAlreadyInstalled + + logger.debug( + 'Using version %s (newest of versions: %s)', + best_candidate.version, + _format_versions(best_candidate_result.iter_applicable()), + ) + return best_candidate.link + + +def _find_name_version_sep(fragment, canonical_name): + # type: (str, str) -> int + """Find the separator's index based on the package's canonical name. + + :param fragment: A + filename "fragment" (stem) or + egg fragment. + :param canonical_name: The package's canonical name. + + This function is needed since the canonicalized name does not necessarily + have the same length as the egg info's name part. An example:: + + >>> fragment = 'foo__bar-1.0' + >>> canonical_name = 'foo-bar' + >>> _find_name_version_sep(fragment, canonical_name) + 8 + """ + # Project name and version must be separated by one single dash. Find all + # occurrences of dashes; if the string in front of it matches the canonical + # name, this is the one separating the name and version parts. + for i, c in enumerate(fragment): + if c != "-": + continue + if canonicalize_name(fragment[:i]) == canonical_name: + return i + raise ValueError("{} does not match {}".format(fragment, canonical_name)) + + +def _extract_version_from_fragment(fragment, canonical_name): + # type: (str, str) -> Optional[str] + """Parse the version string from a + filename + "fragment" (stem) or egg fragment. + + :param fragment: The string to parse. E.g. foo-2.1 + :param canonical_name: The canonicalized name of the package this + belongs to. + """ + try: + version_start = _find_name_version_sep(fragment, canonical_name) + 1 + except ValueError: + return None + version = fragment[version_start:] + if not version: + return None + return version diff --git a/venv/lib/python3.8/site-packages/pip/_internal/locations.py b/venv/lib/python3.8/site-packages/pip/_internal/locations.py new file mode 100644 index 0000000..5dfcd73 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/locations.py @@ -0,0 +1,200 @@ +"""Locations where we look for configs, install stuff, etc""" + +# The following comment should be removed at some point in the future. +# mypy: strict-optional=False + +from __future__ import absolute_import + +import os +import os.path +import platform +import site +import sys +import sysconfig +from distutils import sysconfig as distutils_sysconfig +from distutils.command.install import SCHEME_KEYS # type: ignore +from distutils.command.install import install as distutils_install_command + +from pip._internal.models.scheme import Scheme +from pip._internal.utils import appdirs +from pip._internal.utils.compat import WINDOWS +from pip._internal.utils.typing import MYPY_CHECK_RUNNING, cast +from pip._internal.utils.virtualenv import running_under_virtualenv + +if MYPY_CHECK_RUNNING: + from typing import Dict, List, Optional, Union + + from distutils.cmd import Command as DistutilsCommand + + +# Application Directories +USER_CACHE_DIR = appdirs.user_cache_dir("pip") + + +def get_major_minor_version(): + # type: () -> str + """ + Return the major-minor version of the current Python as a string, e.g. + "3.7" or "3.10". + """ + return '{}.{}'.format(*sys.version_info) + + +def get_src_prefix(): + # type: () -> str + if running_under_virtualenv(): + src_prefix = os.path.join(sys.prefix, 'src') + else: + # FIXME: keep src in cwd for now (it is not a temporary folder) + try: + src_prefix = os.path.join(os.getcwd(), 'src') + except OSError: + # In case the current working directory has been renamed or deleted + sys.exit( + "The folder you are executing pip from can no longer be found." + ) + + # under macOS + virtualenv sys.prefix is not properly resolved + # it is something like /path/to/python/bin/.. + return os.path.abspath(src_prefix) + + +# FIXME doesn't account for venv linked to global site-packages + +# The python2.7 part of this is Debian specific: +# https://github.com/pypa/pip/issues/5193 +# https://bitbucket.org/pypy/pypy/issues/2506/sysconfig-returns-incorrect-paths +can_not_depend_on_purelib = ( + sys.version_info[:2] == (2, 7) or + platform.python_implementation().lower() == "pypy" +) +site_packages = None # type: Optional[str] +if can_not_depend_on_purelib: + site_packages = distutils_sysconfig.get_python_lib() +else: + site_packages = sysconfig.get_path("purelib") + +try: + # Use getusersitepackages if this is present, as it ensures that the + # value is initialised properly. + user_site = site.getusersitepackages() +except AttributeError: + user_site = site.USER_SITE + +if WINDOWS: + bin_py = os.path.join(sys.prefix, 'Scripts') + bin_user = os.path.join(user_site, 'Scripts') + # buildout uses 'bin' on Windows too? + if not os.path.exists(bin_py): + bin_py = os.path.join(sys.prefix, 'bin') + bin_user = os.path.join(user_site, 'bin') +else: + bin_py = os.path.join(sys.prefix, 'bin') + bin_user = os.path.join(user_site, 'bin') + + # Forcing to use /usr/local/bin for standard macOS framework installs + # Also log to ~/Library/Logs/ for use with the Console.app log viewer + if sys.platform[:6] == 'darwin' and sys.prefix[:16] == '/System/Library/': + bin_py = '/usr/local/bin' + + +def distutils_scheme( + dist_name, user=False, home=None, root=None, isolated=False, prefix=None +): + # type:(str, bool, str, str, bool, str) -> Dict[str, str] + """ + Return a distutils install scheme + """ + from distutils.dist import Distribution + + dist_args = {'name': dist_name} # type: Dict[str, Union[str, List[str]]] + if isolated: + dist_args["script_args"] = ["--no-user-cfg"] + + d = Distribution(dist_args) + d.parse_config_files() + obj = None # type: Optional[DistutilsCommand] + obj = d.get_command_obj('install', create=True) + assert obj is not None + i = cast(distutils_install_command, obj) + # NOTE: setting user or home has the side-effect of creating the home dir + # or user base for installations during finalize_options() + # ideally, we'd prefer a scheme class that has no side-effects. + assert not (user and prefix), "user={} prefix={}".format(user, prefix) + assert not (home and prefix), "home={} prefix={}".format(home, prefix) + i.user = user or i.user + if user or home: + i.prefix = "" + i.prefix = prefix or i.prefix + i.home = home or i.home + i.root = root or i.root + i.finalize_options() + + scheme = {} + for key in SCHEME_KEYS: + scheme[key] = getattr(i, 'install_' + key) + + # install_lib specified in setup.cfg should install *everything* + # into there (i.e. it takes precedence over both purelib and + # platlib). Note, i.install_lib is *always* set after + # finalize_options(); we only want to override here if the user + # has explicitly requested it hence going back to the config + if 'install_lib' in d.get_option_dict('install'): + scheme.update(dict(purelib=i.install_lib, platlib=i.install_lib)) + + if running_under_virtualenv(): + scheme['headers'] = os.path.join( + sys.prefix, + 'include', + 'site', + 'python{}'.format(get_major_minor_version()), + dist_name, + ) + + if root is not None: + path_no_drive = os.path.splitdrive( + os.path.abspath(scheme["headers"]))[1] + scheme["headers"] = os.path.join( + root, + path_no_drive[1:], + ) + + return scheme + + +def get_scheme( + dist_name, # type: str + user=False, # type: bool + home=None, # type: Optional[str] + root=None, # type: Optional[str] + isolated=False, # type: bool + prefix=None, # type: Optional[str] +): + # type: (...) -> Scheme + """ + Get the "scheme" corresponding to the input parameters. The distutils + documentation provides the context for the available schemes: + https://docs.python.org/3/install/index.html#alternate-installation + + :param dist_name: the name of the package to retrieve the scheme for, used + in the headers scheme path + :param user: indicates to use the "user" scheme + :param home: indicates to use the "home" scheme and provides the base + directory for the same + :param root: root under which other directories are re-based + :param isolated: equivalent to --no-user-cfg, i.e. do not consider + ~/.pydistutils.cfg (posix) or ~/pydistutils.cfg (non-posix) for + scheme paths + :param prefix: indicates to use the "prefix" scheme and provides the + base directory for the same + """ + scheme = distutils_scheme( + dist_name, user, home, root, isolated, prefix + ) + return Scheme( + platlib=scheme["platlib"], + purelib=scheme["purelib"], + headers=scheme["headers"], + scripts=scheme["scripts"], + data=scheme["data"], + ) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/main.py b/venv/lib/python3.8/site-packages/pip/_internal/main.py new file mode 100644 index 0000000..3208d5b --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/main.py @@ -0,0 +1,16 @@ +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Optional, List + + +def main(args=None): + # type: (Optional[List[str]]) -> int + """This is preserved for old console scripts that may still be referencing + it. + + For additional details, see https://github.com/pypa/pip/issues/7498. + """ + from pip._internal.utils.entrypoints import _wrapper + + return _wrapper(args) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/models/__init__.py b/venv/lib/python3.8/site-packages/pip/_internal/models/__init__.py new file mode 100644 index 0000000..7855226 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/models/__init__.py @@ -0,0 +1,2 @@ +"""A package that contains models that represent entities. +""" diff --git a/venv/lib/python3.8/site-packages/pip/_internal/models/candidate.py b/venv/lib/python3.8/site-packages/pip/_internal/models/candidate.py new file mode 100644 index 0000000..1dc1a57 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/models/candidate.py @@ -0,0 +1,36 @@ +from pip._vendor.packaging.version import parse as parse_version + +from pip._internal.utils.models import KeyBasedCompareMixin +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from pip._vendor.packaging.version import _BaseVersion + from pip._internal.models.link import Link + + +class InstallationCandidate(KeyBasedCompareMixin): + """Represents a potential "candidate" for installation. + """ + + def __init__(self, name, version, link): + # type: (str, str, Link) -> None + self.name = name + self.version = parse_version(version) # type: _BaseVersion + self.link = link + + super(InstallationCandidate, self).__init__( + key=(self.name, self.version, self.link), + defining_class=InstallationCandidate + ) + + def __repr__(self): + # type: () -> str + return "".format( + self.name, self.version, self.link, + ) + + def __str__(self): + # type: () -> str + return '{!r} candidate (version {} at {})'.format( + self.name, self.version, self.link, + ) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/models/direct_url.py b/venv/lib/python3.8/site-packages/pip/_internal/models/direct_url.py new file mode 100644 index 0000000..87bd9fe --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/models/direct_url.py @@ -0,0 +1,245 @@ +""" PEP 610 """ +import json +import re + +from pip._vendor import six +from pip._vendor.six.moves.urllib import parse as urllib_parse + +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import ( + Any, Dict, Iterable, Optional, Type, TypeVar, Union + ) + + T = TypeVar("T") + + +DIRECT_URL_METADATA_NAME = "direct_url.json" +ENV_VAR_RE = re.compile(r"^\$\{[A-Za-z0-9-_]+\}(:\$\{[A-Za-z0-9-_]+\})?$") + +__all__ = [ + "DirectUrl", + "DirectUrlValidationError", + "DirInfo", + "ArchiveInfo", + "VcsInfo", +] + + +class DirectUrlValidationError(Exception): + pass + + +def _get(d, expected_type, key, default=None): + # type: (Dict[str, Any], Type[T], str, Optional[T]) -> Optional[T] + """Get value from dictionary and verify expected type.""" + if key not in d: + return default + value = d[key] + if six.PY2 and expected_type is str: + expected_type = six.string_types # type: ignore + if not isinstance(value, expected_type): + raise DirectUrlValidationError( + "{!r} has unexpected type for {} (expected {})".format( + value, key, expected_type + ) + ) + return value + + +def _get_required(d, expected_type, key, default=None): + # type: (Dict[str, Any], Type[T], str, Optional[T]) -> T + value = _get(d, expected_type, key, default) + if value is None: + raise DirectUrlValidationError("{} must have a value".format(key)) + return value + + +def _exactly_one_of(infos): + # type: (Iterable[Optional[InfoType]]) -> InfoType + infos = [info for info in infos if info is not None] + if not infos: + raise DirectUrlValidationError( + "missing one of archive_info, dir_info, vcs_info" + ) + if len(infos) > 1: + raise DirectUrlValidationError( + "more than one of archive_info, dir_info, vcs_info" + ) + assert infos[0] is not None + return infos[0] + + +def _filter_none(**kwargs): + # type: (Any) -> Dict[str, Any] + """Make dict excluding None values.""" + return {k: v for k, v in kwargs.items() if v is not None} + + +class VcsInfo(object): + name = "vcs_info" + + def __init__( + self, + vcs, # type: str + commit_id, # type: str + requested_revision=None, # type: Optional[str] + resolved_revision=None, # type: Optional[str] + resolved_revision_type=None, # type: Optional[str] + ): + self.vcs = vcs + self.requested_revision = requested_revision + self.commit_id = commit_id + self.resolved_revision = resolved_revision + self.resolved_revision_type = resolved_revision_type + + @classmethod + def _from_dict(cls, d): + # type: (Optional[Dict[str, Any]]) -> Optional[VcsInfo] + if d is None: + return None + return cls( + vcs=_get_required(d, str, "vcs"), + commit_id=_get_required(d, str, "commit_id"), + requested_revision=_get(d, str, "requested_revision"), + resolved_revision=_get(d, str, "resolved_revision"), + resolved_revision_type=_get(d, str, "resolved_revision_type"), + ) + + def _to_dict(self): + # type: () -> Dict[str, Any] + return _filter_none( + vcs=self.vcs, + requested_revision=self.requested_revision, + commit_id=self.commit_id, + resolved_revision=self.resolved_revision, + resolved_revision_type=self.resolved_revision_type, + ) + + +class ArchiveInfo(object): + name = "archive_info" + + def __init__( + self, + hash=None, # type: Optional[str] + ): + self.hash = hash + + @classmethod + def _from_dict(cls, d): + # type: (Optional[Dict[str, Any]]) -> Optional[ArchiveInfo] + if d is None: + return None + return cls(hash=_get(d, str, "hash")) + + def _to_dict(self): + # type: () -> Dict[str, Any] + return _filter_none(hash=self.hash) + + +class DirInfo(object): + name = "dir_info" + + def __init__( + self, + editable=False, # type: bool + ): + self.editable = editable + + @classmethod + def _from_dict(cls, d): + # type: (Optional[Dict[str, Any]]) -> Optional[DirInfo] + if d is None: + return None + return cls( + editable=_get_required(d, bool, "editable", default=False) + ) + + def _to_dict(self): + # type: () -> Dict[str, Any] + return _filter_none(editable=self.editable or None) + + +if MYPY_CHECK_RUNNING: + InfoType = Union[ArchiveInfo, DirInfo, VcsInfo] + + +class DirectUrl(object): + + def __init__( + self, + url, # type: str + info, # type: InfoType + subdirectory=None, # type: Optional[str] + ): + self.url = url + self.info = info + self.subdirectory = subdirectory + + def _remove_auth_from_netloc(self, netloc): + # type: (str) -> str + if "@" not in netloc: + return netloc + user_pass, netloc_no_user_pass = netloc.split("@", 1) + if ( + isinstance(self.info, VcsInfo) and + self.info.vcs == "git" and + user_pass == "git" + ): + return netloc + if ENV_VAR_RE.match(user_pass): + return netloc + return netloc_no_user_pass + + @property + def redacted_url(self): + # type: () -> str + """url with user:password part removed unless it is formed with + environment variables as specified in PEP 610, or it is ``git`` + in the case of a git URL. + """ + purl = urllib_parse.urlsplit(self.url) + netloc = self._remove_auth_from_netloc(purl.netloc) + surl = urllib_parse.urlunsplit( + (purl.scheme, netloc, purl.path, purl.query, purl.fragment) + ) + return surl + + def validate(self): + # type: () -> None + self.from_dict(self.to_dict()) + + @classmethod + def from_dict(cls, d): + # type: (Dict[str, Any]) -> DirectUrl + return DirectUrl( + url=_get_required(d, str, "url"), + subdirectory=_get(d, str, "subdirectory"), + info=_exactly_one_of( + [ + ArchiveInfo._from_dict(_get(d, dict, "archive_info")), + DirInfo._from_dict(_get(d, dict, "dir_info")), + VcsInfo._from_dict(_get(d, dict, "vcs_info")), + ] + ), + ) + + def to_dict(self): + # type: () -> Dict[str, Any] + res = _filter_none( + url=self.redacted_url, + subdirectory=self.subdirectory, + ) + res[self.info.name] = self.info._to_dict() + return res + + @classmethod + def from_json(cls, s): + # type: (str) -> DirectUrl + return cls.from_dict(json.loads(s)) + + def to_json(self): + # type: () -> str + return json.dumps(self.to_dict(), sort_keys=True) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/models/format_control.py b/venv/lib/python3.8/site-packages/pip/_internal/models/format_control.py new file mode 100644 index 0000000..2e13727 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/models/format_control.py @@ -0,0 +1,84 @@ +# The following comment should be removed at some point in the future. +# mypy: strict-optional=False + +from pip._vendor.packaging.utils import canonicalize_name + +from pip._internal.exceptions import CommandError +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Optional, Set, FrozenSet + + +class FormatControl(object): + """Helper for managing formats from which a package can be installed. + """ + + def __init__(self, no_binary=None, only_binary=None): + # type: (Optional[Set[str]], Optional[Set[str]]) -> None + if no_binary is None: + no_binary = set() + if only_binary is None: + only_binary = set() + + self.no_binary = no_binary + self.only_binary = only_binary + + def __eq__(self, other): + # type: (object) -> bool + return self.__dict__ == other.__dict__ + + def __ne__(self, other): + # type: (object) -> bool + return not self.__eq__(other) + + def __repr__(self): + # type: () -> str + return "{}({}, {})".format( + self.__class__.__name__, + self.no_binary, + self.only_binary + ) + + @staticmethod + def handle_mutual_excludes(value, target, other): + # type: (str, Optional[Set[str]], Optional[Set[str]]) -> None + if value.startswith('-'): + raise CommandError( + "--no-binary / --only-binary option requires 1 argument." + ) + new = value.split(',') + while ':all:' in new: + other.clear() + target.clear() + target.add(':all:') + del new[:new.index(':all:') + 1] + # Without a none, we want to discard everything as :all: covers it + if ':none:' not in new: + return + for name in new: + if name == ':none:': + target.clear() + continue + name = canonicalize_name(name) + other.discard(name) + target.add(name) + + def get_allowed_formats(self, canonical_name): + # type: (str) -> FrozenSet[str] + result = {"binary", "source"} + if canonical_name in self.only_binary: + result.discard('source') + elif canonical_name in self.no_binary: + result.discard('binary') + elif ':all:' in self.only_binary: + result.discard('source') + elif ':all:' in self.no_binary: + result.discard('binary') + return frozenset(result) + + def disallow_binaries(self): + # type: () -> None + self.handle_mutual_excludes( + ':all:', self.no_binary, self.only_binary, + ) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/models/index.py b/venv/lib/python3.8/site-packages/pip/_internal/models/index.py new file mode 100644 index 0000000..ead1efb --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/models/index.py @@ -0,0 +1,31 @@ +from pip._vendor.six.moves.urllib import parse as urllib_parse + + +class PackageIndex(object): + """Represents a Package Index and provides easier access to endpoints + """ + + def __init__(self, url, file_storage_domain): + # type: (str, str) -> None + super(PackageIndex, self).__init__() + self.url = url + self.netloc = urllib_parse.urlsplit(url).netloc + self.simple_url = self._url_for_path('simple') + self.pypi_url = self._url_for_path('pypi') + + # This is part of a temporary hack used to block installs of PyPI + # packages which depend on external urls only necessary until PyPI can + # block such packages themselves + self.file_storage_domain = file_storage_domain + + def _url_for_path(self, path): + # type: (str) -> str + return urllib_parse.urljoin(self.url, path) + + +PyPI = PackageIndex( + 'https://pypi.org/', file_storage_domain='files.pythonhosted.org' +) +TestPyPI = PackageIndex( + 'https://test.pypi.org/', file_storage_domain='test-files.pythonhosted.org' +) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/models/link.py b/venv/lib/python3.8/site-packages/pip/_internal/models/link.py new file mode 100644 index 0000000..df4f8f0 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/models/link.py @@ -0,0 +1,236 @@ +import os +import posixpath +import re + +from pip._vendor.six.moves.urllib import parse as urllib_parse + +from pip._internal.utils.filetypes import WHEEL_EXTENSION +from pip._internal.utils.misc import ( + redact_auth_from_url, + split_auth_from_netloc, + splitext, +) +from pip._internal.utils.models import KeyBasedCompareMixin +from pip._internal.utils.typing import MYPY_CHECK_RUNNING +from pip._internal.utils.urls import path_to_url, url_to_path + +if MYPY_CHECK_RUNNING: + from typing import Optional, Text, Tuple, Union + from pip._internal.index.collector import HTMLPage + from pip._internal.utils.hashes import Hashes + + +class Link(KeyBasedCompareMixin): + """Represents a parsed link from a Package Index's simple URL + """ + + def __init__( + self, + url, # type: str + comes_from=None, # type: Optional[Union[str, HTMLPage]] + requires_python=None, # type: Optional[str] + yanked_reason=None, # type: Optional[Text] + cache_link_parsing=True, # type: bool + ): + # type: (...) -> None + """ + :param url: url of the resource pointed to (href of the link) + :param comes_from: instance of HTMLPage where the link was found, + or string. + :param requires_python: String containing the `Requires-Python` + metadata field, specified in PEP 345. This may be specified by + a data-requires-python attribute in the HTML link tag, as + described in PEP 503. + :param yanked_reason: the reason the file has been yanked, if the + file has been yanked, or None if the file hasn't been yanked. + This is the value of the "data-yanked" attribute, if present, in + a simple repository HTML link. If the file has been yanked but + no reason was provided, this should be the empty string. See + PEP 592 for more information and the specification. + :param cache_link_parsing: A flag that is used elsewhere to determine + whether resources retrieved from this link + should be cached. PyPI index urls should + generally have this set to False, for + example. + """ + + # url can be a UNC windows share + if url.startswith('\\\\'): + url = path_to_url(url) + + self._parsed_url = urllib_parse.urlsplit(url) + # Store the url as a private attribute to prevent accidentally + # trying to set a new value. + self._url = url + + self.comes_from = comes_from + self.requires_python = requires_python if requires_python else None + self.yanked_reason = yanked_reason + + super(Link, self).__init__(key=url, defining_class=Link) + + self.cache_link_parsing = cache_link_parsing + + def __str__(self): + # type: () -> str + if self.requires_python: + rp = ' (requires-python:{})'.format(self.requires_python) + else: + rp = '' + if self.comes_from: + return '{} (from {}){}'.format( + redact_auth_from_url(self._url), self.comes_from, rp) + else: + return redact_auth_from_url(str(self._url)) + + def __repr__(self): + # type: () -> str + return ''.format(self) + + @property + def url(self): + # type: () -> str + return self._url + + @property + def filename(self): + # type: () -> str + path = self.path.rstrip('/') + name = posixpath.basename(path) + if not name: + # Make sure we don't leak auth information if the netloc + # includes a username and password. + netloc, user_pass = split_auth_from_netloc(self.netloc) + return netloc + + name = urllib_parse.unquote(name) + assert name, ( + 'URL {self._url!r} produced no filename'.format(**locals())) + return name + + @property + def file_path(self): + # type: () -> str + return url_to_path(self.url) + + @property + def scheme(self): + # type: () -> str + return self._parsed_url.scheme + + @property + def netloc(self): + # type: () -> str + """ + This can contain auth information. + """ + return self._parsed_url.netloc + + @property + def path(self): + # type: () -> str + return urllib_parse.unquote(self._parsed_url.path) + + def splitext(self): + # type: () -> Tuple[str, str] + return splitext(posixpath.basename(self.path.rstrip('/'))) + + @property + def ext(self): + # type: () -> str + return self.splitext()[1] + + @property + def url_without_fragment(self): + # type: () -> str + scheme, netloc, path, query, fragment = self._parsed_url + return urllib_parse.urlunsplit((scheme, netloc, path, query, None)) + + _egg_fragment_re = re.compile(r'[#&]egg=([^&]*)') + + @property + def egg_fragment(self): + # type: () -> Optional[str] + match = self._egg_fragment_re.search(self._url) + if not match: + return None + return match.group(1) + + _subdirectory_fragment_re = re.compile(r'[#&]subdirectory=([^&]*)') + + @property + def subdirectory_fragment(self): + # type: () -> Optional[str] + match = self._subdirectory_fragment_re.search(self._url) + if not match: + return None + return match.group(1) + + _hash_re = re.compile( + r'(sha1|sha224|sha384|sha256|sha512|md5)=([a-f0-9]+)' + ) + + @property + def hash(self): + # type: () -> Optional[str] + match = self._hash_re.search(self._url) + if match: + return match.group(2) + return None + + @property + def hash_name(self): + # type: () -> Optional[str] + match = self._hash_re.search(self._url) + if match: + return match.group(1) + return None + + @property + def show_url(self): + # type: () -> str + return posixpath.basename(self._url.split('#', 1)[0].split('?', 1)[0]) + + @property + def is_file(self): + # type: () -> bool + return self.scheme == 'file' + + def is_existing_dir(self): + # type: () -> bool + return self.is_file and os.path.isdir(self.file_path) + + @property + def is_wheel(self): + # type: () -> bool + return self.ext == WHEEL_EXTENSION + + @property + def is_vcs(self): + # type: () -> bool + from pip._internal.vcs import vcs + + return self.scheme in vcs.all_schemes + + @property + def is_yanked(self): + # type: () -> bool + return self.yanked_reason is not None + + @property + def has_hash(self): + # type: () -> bool + return self.hash_name is not None + + def is_hash_allowed(self, hashes): + # type: (Optional[Hashes]) -> bool + """ + Return True if the link has a hash and it is allowed. + """ + if hashes is None or not self.has_hash: + return False + # Assert non-None so mypy knows self.hash_name and self.hash are str. + assert self.hash_name is not None + assert self.hash is not None + + return hashes.is_hash_allowed(self.hash_name, hex_digest=self.hash) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/models/scheme.py b/venv/lib/python3.8/site-packages/pip/_internal/models/scheme.py new file mode 100644 index 0000000..af07b40 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/models/scheme.py @@ -0,0 +1,25 @@ +""" +For types associated with installation schemes. + +For a general overview of available schemes and their context, see +https://docs.python.org/3/install/index.html#alternate-installation. +""" + + +class Scheme(object): + """A Scheme holds paths which are used as the base directories for + artifacts associated with a Python package. + """ + def __init__( + self, + platlib, # type: str + purelib, # type: str + headers, # type: str + scripts, # type: str + data, # type: str + ): + self.platlib = platlib + self.purelib = purelib + self.headers = headers + self.scripts = scripts + self.data = data diff --git a/venv/lib/python3.8/site-packages/pip/_internal/models/search_scope.py b/venv/lib/python3.8/site-packages/pip/_internal/models/search_scope.py new file mode 100644 index 0000000..7a0008e --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/models/search_scope.py @@ -0,0 +1,133 @@ +import itertools +import logging +import os +import posixpath + +from pip._vendor.packaging.utils import canonicalize_name +from pip._vendor.six.moves.urllib import parse as urllib_parse + +from pip._internal.models.index import PyPI +from pip._internal.utils.compat import has_tls +from pip._internal.utils.misc import normalize_path, redact_auth_from_url +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import List + + +logger = logging.getLogger(__name__) + + +class SearchScope(object): + + """ + Encapsulates the locations that pip is configured to search. + """ + + @classmethod + def create( + cls, + find_links, # type: List[str] + index_urls, # type: List[str] + ): + # type: (...) -> SearchScope + """ + Create a SearchScope object after normalizing the `find_links`. + """ + # Build find_links. If an argument starts with ~, it may be + # a local file relative to a home directory. So try normalizing + # it and if it exists, use the normalized version. + # This is deliberately conservative - it might be fine just to + # blindly normalize anything starting with a ~... + built_find_links = [] # type: List[str] + for link in find_links: + if link.startswith('~'): + new_link = normalize_path(link) + if os.path.exists(new_link): + link = new_link + built_find_links.append(link) + + # If we don't have TLS enabled, then WARN if anyplace we're looking + # relies on TLS. + if not has_tls(): + for link in itertools.chain(index_urls, built_find_links): + parsed = urllib_parse.urlparse(link) + if parsed.scheme == 'https': + logger.warning( + 'pip is configured with locations that require ' + 'TLS/SSL, however the ssl module in Python is not ' + 'available.' + ) + break + + return cls( + find_links=built_find_links, + index_urls=index_urls, + ) + + def __init__( + self, + find_links, # type: List[str] + index_urls, # type: List[str] + ): + # type: (...) -> None + self.find_links = find_links + self.index_urls = index_urls + + def get_formatted_locations(self): + # type: () -> str + lines = [] + redacted_index_urls = [] + if self.index_urls and self.index_urls != [PyPI.simple_url]: + for url in self.index_urls: + + redacted_index_url = redact_auth_from_url(url) + + # Parse the URL + purl = urllib_parse.urlsplit(redacted_index_url) + + # URL is generally invalid if scheme and netloc is missing + # there are issues with Python and URL parsing, so this test + # is a bit crude. See bpo-20271, bpo-23505. Python doesn't + # always parse invalid URLs correctly - it should raise + # exceptions for malformed URLs + if not purl.scheme and not purl.netloc: + logger.warning( + 'The index url "{}" seems invalid, ' + 'please provide a scheme.'.format(redacted_index_url)) + + redacted_index_urls.append(redacted_index_url) + + lines.append('Looking in indexes: {}'.format( + ', '.join(redacted_index_urls))) + + if self.find_links: + lines.append( + 'Looking in links: {}'.format(', '.join( + redact_auth_from_url(url) for url in self.find_links)) + ) + return '\n'.join(lines) + + def get_index_urls_locations(self, project_name): + # type: (str) -> List[str] + """Returns the locations found via self.index_urls + + Checks the url_name on the main (first in the list) index and + use this url_name to produce all locations + """ + + def mkurl_pypi_url(url): + # type: (str) -> str + loc = posixpath.join( + url, + urllib_parse.quote(canonicalize_name(project_name))) + # For maximum compatibility with easy_install, ensure the path + # ends in a trailing slash. Although this isn't in the spec + # (and PyPI can handle it without the slash) some other index + # implementations might break if they relied on easy_install's + # behavior. + if not loc.endswith('/'): + loc = loc + '/' + return loc + + return [mkurl_pypi_url(url) for url in self.index_urls] diff --git a/venv/lib/python3.8/site-packages/pip/_internal/models/selection_prefs.py b/venv/lib/python3.8/site-packages/pip/_internal/models/selection_prefs.py new file mode 100644 index 0000000..f58fdce --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/models/selection_prefs.py @@ -0,0 +1,47 @@ +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Optional + from pip._internal.models.format_control import FormatControl + + +class SelectionPreferences(object): + + """ + Encapsulates the candidate selection preferences for downloading + and installing files. + """ + + # Don't include an allow_yanked default value to make sure each call + # site considers whether yanked releases are allowed. This also causes + # that decision to be made explicit in the calling code, which helps + # people when reading the code. + def __init__( + self, + allow_yanked, # type: bool + allow_all_prereleases=False, # type: bool + format_control=None, # type: Optional[FormatControl] + prefer_binary=False, # type: bool + ignore_requires_python=None, # type: Optional[bool] + ): + # type: (...) -> None + """Create a SelectionPreferences object. + + :param allow_yanked: Whether files marked as yanked (in the sense + of PEP 592) are permitted to be candidates for install. + :param format_control: A FormatControl object or None. Used to control + the selection of source packages / binary packages when consulting + the index and links. + :param prefer_binary: Whether to prefer an old, but valid, binary + dist over a new source dist. + :param ignore_requires_python: Whether to ignore incompatible + "Requires-Python" values in links. Defaults to False. + """ + if ignore_requires_python is None: + ignore_requires_python = False + + self.allow_yanked = allow_yanked + self.allow_all_prereleases = allow_all_prereleases + self.format_control = format_control + self.prefer_binary = prefer_binary + self.ignore_requires_python = ignore_requires_python diff --git a/venv/lib/python3.8/site-packages/pip/_internal/models/target_python.py b/venv/lib/python3.8/site-packages/pip/_internal/models/target_python.py new file mode 100644 index 0000000..84f1c20 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/models/target_python.py @@ -0,0 +1,110 @@ +import sys + +from pip._internal.utils.compatibility_tags import ( + get_supported, + version_info_to_nodot, +) +from pip._internal.utils.misc import normalize_version_info +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import List, Optional, Tuple + + from pip._vendor.packaging.tags import Tag + + +class TargetPython(object): + + """ + Encapsulates the properties of a Python interpreter one is targeting + for a package install, download, etc. + """ + + def __init__( + self, + platform=None, # type: Optional[str] + py_version_info=None, # type: Optional[Tuple[int, ...]] + abi=None, # type: Optional[str] + implementation=None, # type: Optional[str] + ): + # type: (...) -> None + """ + :param platform: A string or None. If None, searches for packages + that are supported by the current system. Otherwise, will find + packages that can be built on the platform passed in. These + packages will only be downloaded for distribution: they will + not be built locally. + :param py_version_info: An optional tuple of ints representing the + Python version information to use (e.g. `sys.version_info[:3]`). + This can have length 1, 2, or 3 when provided. + :param abi: A string or None. This is passed to compatibility_tags.py's + get_supported() function as is. + :param implementation: A string or None. This is passed to + compatibility_tags.py's get_supported() function as is. + """ + # Store the given py_version_info for when we call get_supported(). + self._given_py_version_info = py_version_info + + if py_version_info is None: + py_version_info = sys.version_info[:3] + else: + py_version_info = normalize_version_info(py_version_info) + + py_version = '.'.join(map(str, py_version_info[:2])) + + self.abi = abi + self.implementation = implementation + self.platform = platform + self.py_version = py_version + self.py_version_info = py_version_info + + # This is used to cache the return value of get_tags(). + self._valid_tags = None # type: Optional[List[Tag]] + + def format_given(self): + # type: () -> str + """ + Format the given, non-None attributes for display. + """ + display_version = None + if self._given_py_version_info is not None: + display_version = '.'.join( + str(part) for part in self._given_py_version_info + ) + + key_values = [ + ('platform', self.platform), + ('version_info', display_version), + ('abi', self.abi), + ('implementation', self.implementation), + ] + return ' '.join( + '{}={!r}'.format(key, value) for key, value in key_values + if value is not None + ) + + def get_tags(self): + # type: () -> List[Tag] + """ + Return the supported PEP 425 tags to check wheel candidates against. + + The tags are returned in order of preference (most preferred first). + """ + if self._valid_tags is None: + # Pass versions=None if no py_version_info was given since + # versions=None uses special default logic. + py_version_info = self._given_py_version_info + if py_version_info is None: + version = None + else: + version = version_info_to_nodot(py_version_info) + + tags = get_supported( + version=version, + platform=self.platform, + abi=self.abi, + impl=self.implementation, + ) + self._valid_tags = tags + + return self._valid_tags diff --git a/venv/lib/python3.8/site-packages/pip/_internal/models/wheel.py b/venv/lib/python3.8/site-packages/pip/_internal/models/wheel.py new file mode 100644 index 0000000..4d4068f --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/models/wheel.py @@ -0,0 +1,78 @@ +"""Represents a wheel file and provides access to the various parts of the +name that have meaning. +""" +import re + +from pip._vendor.packaging.tags import Tag + +from pip._internal.exceptions import InvalidWheelFilename +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import List + + +class Wheel(object): + """A wheel file""" + + wheel_file_re = re.compile( + r"""^(?P(?P.+?)-(?P.*?)) + ((-(?P\d[^-]*?))?-(?P.+?)-(?P.+?)-(?P.+?) + \.whl|\.dist-info)$""", + re.VERBOSE + ) + + def __init__(self, filename): + # type: (str) -> None + """ + :raises InvalidWheelFilename: when the filename is invalid for a wheel + """ + wheel_info = self.wheel_file_re.match(filename) + if not wheel_info: + raise InvalidWheelFilename( + "{} is not a valid wheel filename.".format(filename) + ) + self.filename = filename + self.name = wheel_info.group('name').replace('_', '-') + # we'll assume "_" means "-" due to wheel naming scheme + # (https://github.com/pypa/pip/issues/1150) + self.version = wheel_info.group('ver').replace('_', '-') + self.build_tag = wheel_info.group('build') + self.pyversions = wheel_info.group('pyver').split('.') + self.abis = wheel_info.group('abi').split('.') + self.plats = wheel_info.group('plat').split('.') + + # All the tag combinations from this file + self.file_tags = { + Tag(x, y, z) for x in self.pyversions + for y in self.abis for z in self.plats + } + + def get_formatted_file_tags(self): + # type: () -> List[str] + """Return the wheel's tags as a sorted list of strings.""" + return sorted(str(tag) for tag in self.file_tags) + + def support_index_min(self, tags): + # type: (List[Tag]) -> int + """Return the lowest index that one of the wheel's file_tag combinations + achieves in the given list of supported tags. + + For example, if there are 8 supported tags and one of the file tags + is first in the list, then return 0. + + :param tags: the PEP 425 tags to check the wheel against, in order + with most preferred first. + + :raises ValueError: If none of the wheel's file tags match one of + the supported tags. + """ + return min(tags.index(tag) for tag in self.file_tags if tag in tags) + + def supported(self, tags): + # type: (List[Tag]) -> bool + """Return whether the wheel is compatible with one of the given tags. + + :param tags: the PEP 425 tags to check the wheel against. + """ + return not self.file_tags.isdisjoint(tags) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/network/__init__.py b/venv/lib/python3.8/site-packages/pip/_internal/network/__init__.py new file mode 100644 index 0000000..b51bde9 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/network/__init__.py @@ -0,0 +1,2 @@ +"""Contains purely network-related utilities. +""" diff --git a/venv/lib/python3.8/site-packages/pip/_internal/network/auth.py b/venv/lib/python3.8/site-packages/pip/_internal/network/auth.py new file mode 100644 index 0000000..94da3d4 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/network/auth.py @@ -0,0 +1,298 @@ +"""Network Authentication Helpers + +Contains interface (MultiDomainBasicAuth) and associated glue code for +providing credentials in the context of network requests. +""" + +# The following comment should be removed at some point in the future. +# mypy: disallow-untyped-defs=False + +import logging + +from pip._vendor.requests.auth import AuthBase, HTTPBasicAuth +from pip._vendor.requests.utils import get_netrc_auth +from pip._vendor.six.moves.urllib import parse as urllib_parse + +from pip._internal.utils.misc import ( + ask, + ask_input, + ask_password, + remove_auth_from_url, + split_auth_netloc_from_url, +) +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from optparse import Values + from typing import Dict, Optional, Tuple + + from pip._internal.vcs.versioncontrol import AuthInfo + + Credentials = Tuple[str, str, str] + +logger = logging.getLogger(__name__) + +try: + import keyring # noqa +except ImportError: + keyring = None +except Exception as exc: + logger.warning( + "Keyring is skipped due to an exception: %s", str(exc), + ) + keyring = None + + +def get_keyring_auth(url, username): + """Return the tuple auth for a given url from keyring.""" + if not url or not keyring: + return None + + try: + try: + get_credential = keyring.get_credential + except AttributeError: + pass + else: + logger.debug("Getting credentials from keyring for %s", url) + cred = get_credential(url, username) + if cred is not None: + return cred.username, cred.password + return None + + if username: + logger.debug("Getting password from keyring for %s", url) + password = keyring.get_password(url, username) + if password: + return username, password + + except Exception as exc: + logger.warning( + "Keyring is skipped due to an exception: %s", str(exc), + ) + + +class MultiDomainBasicAuth(AuthBase): + + def __init__(self, prompting=True, index_urls=None): + # type: (bool, Optional[Values]) -> None + self.prompting = prompting + self.index_urls = index_urls + self.passwords = {} # type: Dict[str, AuthInfo] + # When the user is prompted to enter credentials and keyring is + # available, we will offer to save them. If the user accepts, + # this value is set to the credentials they entered. After the + # request authenticates, the caller should call + # ``save_credentials`` to save these. + self._credentials_to_save = None # type: Optional[Credentials] + + def _get_index_url(self, url): + """Return the original index URL matching the requested URL. + + Cached or dynamically generated credentials may work against + the original index URL rather than just the netloc. + + The provided url should have had its username and password + removed already. If the original index url had credentials then + they will be included in the return value. + + Returns None if no matching index was found, or if --no-index + was specified by the user. + """ + if not url or not self.index_urls: + return None + + for u in self.index_urls: + prefix = remove_auth_from_url(u).rstrip("/") + "/" + if url.startswith(prefix): + return u + + def _get_new_credentials(self, original_url, allow_netrc=True, + allow_keyring=True): + """Find and return credentials for the specified URL.""" + # Split the credentials and netloc from the url. + url, netloc, url_user_password = split_auth_netloc_from_url( + original_url, + ) + + # Start with the credentials embedded in the url + username, password = url_user_password + if username is not None and password is not None: + logger.debug("Found credentials in url for %s", netloc) + return url_user_password + + # Find a matching index url for this request + index_url = self._get_index_url(url) + if index_url: + # Split the credentials from the url. + index_info = split_auth_netloc_from_url(index_url) + if index_info: + index_url, _, index_url_user_password = index_info + logger.debug("Found index url %s", index_url) + + # If an index URL was found, try its embedded credentials + if index_url and index_url_user_password[0] is not None: + username, password = index_url_user_password + if username is not None and password is not None: + logger.debug("Found credentials in index url for %s", netloc) + return index_url_user_password + + # Get creds from netrc if we still don't have them + if allow_netrc: + netrc_auth = get_netrc_auth(original_url) + if netrc_auth: + logger.debug("Found credentials in netrc for %s", netloc) + return netrc_auth + + # If we don't have a password and keyring is available, use it. + if allow_keyring: + # The index url is more specific than the netloc, so try it first + kr_auth = ( + get_keyring_auth(index_url, username) or + get_keyring_auth(netloc, username) + ) + if kr_auth: + logger.debug("Found credentials in keyring for %s", netloc) + return kr_auth + + return username, password + + def _get_url_and_credentials(self, original_url): + """Return the credentials to use for the provided URL. + + If allowed, netrc and keyring may be used to obtain the + correct credentials. + + Returns (url_without_credentials, username, password). Note + that even if the original URL contains credentials, this + function may return a different username and password. + """ + url, netloc, _ = split_auth_netloc_from_url(original_url) + + # Use any stored credentials that we have for this netloc + username, password = self.passwords.get(netloc, (None, None)) + + if username is None and password is None: + # No stored credentials. Acquire new credentials without prompting + # the user. (e.g. from netrc, keyring, or the URL itself) + username, password = self._get_new_credentials(original_url) + + if username is not None or password is not None: + # Convert the username and password if they're None, so that + # this netloc will show up as "cached" in the conditional above. + # Further, HTTPBasicAuth doesn't accept None, so it makes sense to + # cache the value that is going to be used. + username = username or "" + password = password or "" + + # Store any acquired credentials. + self.passwords[netloc] = (username, password) + + assert ( + # Credentials were found + (username is not None and password is not None) or + # Credentials were not found + (username is None and password is None) + ), "Could not load credentials from url: {}".format(original_url) + + return url, username, password + + def __call__(self, req): + # Get credentials for this request + url, username, password = self._get_url_and_credentials(req.url) + + # Set the url of the request to the url without any credentials + req.url = url + + if username is not None and password is not None: + # Send the basic auth with this request + req = HTTPBasicAuth(username, password)(req) + + # Attach a hook to handle 401 responses + req.register_hook("response", self.handle_401) + + return req + + # Factored out to allow for easy patching in tests + def _prompt_for_password(self, netloc): + username = ask_input("User for {}: ".format(netloc)) + if not username: + return None, None + auth = get_keyring_auth(netloc, username) + if auth: + return auth[0], auth[1], False + password = ask_password("Password: ") + return username, password, True + + # Factored out to allow for easy patching in tests + def _should_save_password_to_keyring(self): + if not keyring: + return False + return ask("Save credentials to keyring [y/N]: ", ["y", "n"]) == "y" + + def handle_401(self, resp, **kwargs): + # We only care about 401 responses, anything else we want to just + # pass through the actual response + if resp.status_code != 401: + return resp + + # We are not able to prompt the user so simply return the response + if not self.prompting: + return resp + + parsed = urllib_parse.urlparse(resp.url) + + # Prompt the user for a new username and password + username, password, save = self._prompt_for_password(parsed.netloc) + + # Store the new username and password to use for future requests + self._credentials_to_save = None + if username is not None and password is not None: + self.passwords[parsed.netloc] = (username, password) + + # Prompt to save the password to keyring + if save and self._should_save_password_to_keyring(): + self._credentials_to_save = (parsed.netloc, username, password) + + # Consume content and release the original connection to allow our new + # request to reuse the same one. + resp.content + resp.raw.release_conn() + + # Add our new username and password to the request + req = HTTPBasicAuth(username or "", password or "")(resp.request) + req.register_hook("response", self.warn_on_401) + + # On successful request, save the credentials that were used to + # keyring. (Note that if the user responded "no" above, this member + # is not set and nothing will be saved.) + if self._credentials_to_save: + req.register_hook("response", self.save_credentials) + + # Send our new request + new_resp = resp.connection.send(req, **kwargs) + new_resp.history.append(resp) + + return new_resp + + def warn_on_401(self, resp, **kwargs): + """Response callback to warn about incorrect credentials.""" + if resp.status_code == 401: + logger.warning( + '401 Error, Credentials not correct for %s', resp.request.url, + ) + + def save_credentials(self, resp, **kwargs): + """Response callback to save credentials on success.""" + assert keyring is not None, "should never reach here without keyring" + if not keyring: + return + + creds = self._credentials_to_save + self._credentials_to_save = None + if creds and resp.status_code < 400: + try: + logger.info('Saving credentials to keyring') + keyring.set_password(*creds) + except Exception: + logger.exception('Failed to save credentials') diff --git a/venv/lib/python3.8/site-packages/pip/_internal/network/cache.py b/venv/lib/python3.8/site-packages/pip/_internal/network/cache.py new file mode 100644 index 0000000..c9386e1 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/network/cache.py @@ -0,0 +1,81 @@ +"""HTTP cache implementation. +""" + +# The following comment should be removed at some point in the future. +# mypy: disallow-untyped-defs=False + +import os +from contextlib import contextmanager + +from pip._vendor.cachecontrol.cache import BaseCache +from pip._vendor.cachecontrol.caches import FileCache +from pip._vendor.requests.models import Response + +from pip._internal.utils.filesystem import adjacent_tmp_file, replace +from pip._internal.utils.misc import ensure_dir +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Optional + + +def is_from_cache(response): + # type: (Response) -> bool + return getattr(response, "from_cache", False) + + +@contextmanager +def suppressed_cache_errors(): + """If we can't access the cache then we can just skip caching and process + requests as if caching wasn't enabled. + """ + try: + yield + except (OSError, IOError): + pass + + +class SafeFileCache(BaseCache): + """ + A file based cache which is safe to use even when the target directory may + not be accessible or writable. + """ + + def __init__(self, directory): + # type: (str) -> None + assert directory is not None, "Cache directory must not be None." + super(SafeFileCache, self).__init__() + self.directory = directory + + def _get_cache_path(self, name): + # type: (str) -> str + # From cachecontrol.caches.file_cache.FileCache._fn, brought into our + # class for backwards-compatibility and to avoid using a non-public + # method. + hashed = FileCache.encode(name) + parts = list(hashed[:5]) + [hashed] + return os.path.join(self.directory, *parts) + + def get(self, key): + # type: (str) -> Optional[bytes] + path = self._get_cache_path(key) + with suppressed_cache_errors(): + with open(path, 'rb') as f: + return f.read() + + def set(self, key, value): + # type: (str, bytes) -> None + path = self._get_cache_path(key) + with suppressed_cache_errors(): + ensure_dir(os.path.dirname(path)) + + with adjacent_tmp_file(path) as f: + f.write(value) + + replace(f.name, path) + + def delete(self, key): + # type: (str) -> None + path = self._get_cache_path(key) + with suppressed_cache_errors(): + os.remove(path) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/network/download.py b/venv/lib/python3.8/site-packages/pip/_internal/network/download.py new file mode 100644 index 0000000..2f3e08a --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/network/download.py @@ -0,0 +1,200 @@ +"""Download files with progress indicators. +""" +import cgi +import logging +import mimetypes +import os + +from pip._vendor import requests +from pip._vendor.requests.models import CONTENT_CHUNK_SIZE + +from pip._internal.cli.progress_bars import DownloadProgressProvider +from pip._internal.models.index import PyPI +from pip._internal.network.cache import is_from_cache +from pip._internal.network.utils import response_chunks +from pip._internal.utils.misc import ( + format_size, + redact_auth_from_url, + splitext, +) +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Iterable, Optional + + from pip._vendor.requests.models import Response + + from pip._internal.models.link import Link + from pip._internal.network.session import PipSession + +logger = logging.getLogger(__name__) + + +def _get_http_response_size(resp): + # type: (Response) -> Optional[int] + try: + return int(resp.headers['content-length']) + except (ValueError, KeyError, TypeError): + return None + + +def _prepare_download( + resp, # type: Response + link, # type: Link + progress_bar # type: str +): + # type: (...) -> Iterable[bytes] + total_length = _get_http_response_size(resp) + + if link.netloc == PyPI.file_storage_domain: + url = link.show_url + else: + url = link.url_without_fragment + + logged_url = redact_auth_from_url(url) + + if total_length: + logged_url = '{} ({})'.format(logged_url, format_size(total_length)) + + if is_from_cache(resp): + logger.info("Using cached %s", logged_url) + else: + logger.info("Downloading %s", logged_url) + + if logger.getEffectiveLevel() > logging.INFO: + show_progress = False + elif is_from_cache(resp): + show_progress = False + elif not total_length: + show_progress = True + elif total_length > (40 * 1000): + show_progress = True + else: + show_progress = False + + chunks = response_chunks(resp, CONTENT_CHUNK_SIZE) + + if not show_progress: + return chunks + + return DownloadProgressProvider( + progress_bar, max=total_length + )(chunks) + + +def sanitize_content_filename(filename): + # type: (str) -> str + """ + Sanitize the "filename" value from a Content-Disposition header. + """ + return os.path.basename(filename) + + +def parse_content_disposition(content_disposition, default_filename): + # type: (str, str) -> str + """ + Parse the "filename" value from a Content-Disposition header, and + return the default filename if the result is empty. + """ + _type, params = cgi.parse_header(content_disposition) + filename = params.get('filename') + if filename: + # We need to sanitize the filename to prevent directory traversal + # in case the filename contains ".." path parts. + filename = sanitize_content_filename(filename) + return filename or default_filename + + +def _get_http_response_filename(resp, link): + # type: (Response, Link) -> str + """Get an ideal filename from the given HTTP response, falling back to + the link filename if not provided. + """ + filename = link.filename # fallback + # Have a look at the Content-Disposition header for a better guess + content_disposition = resp.headers.get('content-disposition') + if content_disposition: + filename = parse_content_disposition(content_disposition, filename) + ext = splitext(filename)[1] # type: Optional[str] + if not ext: + ext = mimetypes.guess_extension( + resp.headers.get('content-type', '') + ) + if ext: + filename += ext + if not ext and link.url != resp.url: + ext = os.path.splitext(resp.url)[1] + if ext: + filename += ext + return filename + + +def _http_get_download(session, link): + # type: (PipSession, Link) -> Response + target_url = link.url.split('#', 1)[0] + resp = session.get( + target_url, + # We use Accept-Encoding: identity here because requests + # defaults to accepting compressed responses. This breaks in + # a variety of ways depending on how the server is configured. + # - Some servers will notice that the file isn't a compressible + # file and will leave the file alone and with an empty + # Content-Encoding + # - Some servers will notice that the file is already + # compressed and will leave the file alone and will add a + # Content-Encoding: gzip header + # - Some servers won't notice anything at all and will take + # a file that's already been compressed and compress it again + # and set the Content-Encoding: gzip header + # By setting this to request only the identity encoding We're + # hoping to eliminate the third case. Hopefully there does not + # exist a server which when given a file will notice it is + # already compressed and that you're not asking for a + # compressed file and will then decompress it before sending + # because if that's the case I don't think it'll ever be + # possible to make this work. + headers={"Accept-Encoding": "identity"}, + stream=True, + ) + resp.raise_for_status() + return resp + + +class Download(object): + def __init__( + self, + response, # type: Response + filename, # type: str + chunks, # type: Iterable[bytes] + ): + # type: (...) -> None + self.response = response + self.filename = filename + self.chunks = chunks + + +class Downloader(object): + def __init__( + self, + session, # type: PipSession + progress_bar, # type: str + ): + # type: (...) -> None + self._session = session + self._progress_bar = progress_bar + + def __call__(self, link): + # type: (Link) -> Download + try: + resp = _http_get_download(self._session, link) + except requests.HTTPError as e: + logger.critical( + "HTTP error %s while getting %s", e.response.status_code, link + ) + raise + + return Download( + resp, + _get_http_response_filename(resp, link), + _prepare_download(resp, link, self._progress_bar), + ) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/network/session.py b/venv/lib/python3.8/site-packages/pip/_internal/network/session.py new file mode 100644 index 0000000..39a4a54 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/network/session.py @@ -0,0 +1,421 @@ +"""PipSession and supporting code, containing all pip-specific +network request configuration and behavior. +""" + +# The following comment should be removed at some point in the future. +# mypy: disallow-untyped-defs=False + +import email.utils +import json +import logging +import mimetypes +import os +import platform +import sys +import warnings + +from pip._vendor import requests, six, urllib3 +from pip._vendor.cachecontrol import CacheControlAdapter +from pip._vendor.requests.adapters import BaseAdapter, HTTPAdapter +from pip._vendor.requests.models import Response +from pip._vendor.requests.structures import CaseInsensitiveDict +from pip._vendor.six.moves.urllib import parse as urllib_parse +from pip._vendor.urllib3.exceptions import InsecureRequestWarning + +from pip import __version__ +from pip._internal.network.auth import MultiDomainBasicAuth +from pip._internal.network.cache import SafeFileCache +# Import ssl from compat so the initial import occurs in only one place. +from pip._internal.utils.compat import has_tls, ipaddress +from pip._internal.utils.glibc import libc_ver +from pip._internal.utils.misc import ( + build_url_from_netloc, + get_installed_version, + parse_netloc, +) +from pip._internal.utils.typing import MYPY_CHECK_RUNNING +from pip._internal.utils.urls import url_to_path + +if MYPY_CHECK_RUNNING: + from typing import ( + Iterator, List, Optional, Tuple, Union, + ) + + from pip._internal.models.link import Link + + SecureOrigin = Tuple[str, str, Optional[Union[int, str]]] + + +logger = logging.getLogger(__name__) + + +# Ignore warning raised when using --trusted-host. +warnings.filterwarnings("ignore", category=InsecureRequestWarning) + + +SECURE_ORIGINS = [ + # protocol, hostname, port + # Taken from Chrome's list of secure origins (See: http://bit.ly/1qrySKC) + ("https", "*", "*"), + ("*", "localhost", "*"), + ("*", "127.0.0.0/8", "*"), + ("*", "::1/128", "*"), + ("file", "*", None), + # ssh is always secure. + ("ssh", "*", "*"), +] # type: List[SecureOrigin] + + +# These are environment variables present when running under various +# CI systems. For each variable, some CI systems that use the variable +# are indicated. The collection was chosen so that for each of a number +# of popular systems, at least one of the environment variables is used. +# This list is used to provide some indication of and lower bound for +# CI traffic to PyPI. Thus, it is okay if the list is not comprehensive. +# For more background, see: https://github.com/pypa/pip/issues/5499 +CI_ENVIRONMENT_VARIABLES = ( + # Azure Pipelines + 'BUILD_BUILDID', + # Jenkins + 'BUILD_ID', + # AppVeyor, CircleCI, Codeship, Gitlab CI, Shippable, Travis CI + 'CI', + # Explicit environment variable. + 'PIP_IS_CI', +) + + +def looks_like_ci(): + # type: () -> bool + """ + Return whether it looks like pip is running under CI. + """ + # We don't use the method of checking for a tty (e.g. using isatty()) + # because some CI systems mimic a tty (e.g. Travis CI). Thus that + # method doesn't provide definitive information in either direction. + return any(name in os.environ for name in CI_ENVIRONMENT_VARIABLES) + + +def user_agent(): + """ + Return a string representing the user agent. + """ + data = { + "installer": {"name": "pip", "version": __version__}, + "python": platform.python_version(), + "implementation": { + "name": platform.python_implementation(), + }, + } + + if data["implementation"]["name"] == 'CPython': + data["implementation"]["version"] = platform.python_version() + elif data["implementation"]["name"] == 'PyPy': + if sys.pypy_version_info.releaselevel == 'final': + pypy_version_info = sys.pypy_version_info[:3] + else: + pypy_version_info = sys.pypy_version_info + data["implementation"]["version"] = ".".join( + [str(x) for x in pypy_version_info] + ) + elif data["implementation"]["name"] == 'Jython': + # Complete Guess + data["implementation"]["version"] = platform.python_version() + elif data["implementation"]["name"] == 'IronPython': + # Complete Guess + data["implementation"]["version"] = platform.python_version() + + if sys.platform.startswith("linux"): + from pip._vendor import distro + distro_infos = dict(filter( + lambda x: x[1], + zip(["name", "version", "id"], distro.linux_distribution()), + )) + libc = dict(filter( + lambda x: x[1], + zip(["lib", "version"], libc_ver()), + )) + if libc: + distro_infos["libc"] = libc + if distro_infos: + data["distro"] = distro_infos + + if sys.platform.startswith("darwin") and platform.mac_ver()[0]: + data["distro"] = {"name": "macOS", "version": platform.mac_ver()[0]} + + if platform.system(): + data.setdefault("system", {})["name"] = platform.system() + + if platform.release(): + data.setdefault("system", {})["release"] = platform.release() + + if platform.machine(): + data["cpu"] = platform.machine() + + if has_tls(): + import _ssl as ssl + data["openssl_version"] = ssl.OPENSSL_VERSION + + setuptools_version = get_installed_version("setuptools") + if setuptools_version is not None: + data["setuptools_version"] = setuptools_version + + # Use None rather than False so as not to give the impression that + # pip knows it is not being run under CI. Rather, it is a null or + # inconclusive result. Also, we include some value rather than no + # value to make it easier to know that the check has been run. + data["ci"] = True if looks_like_ci() else None + + user_data = os.environ.get("PIP_USER_AGENT_USER_DATA") + if user_data is not None: + data["user_data"] = user_data + + return "{data[installer][name]}/{data[installer][version]} {json}".format( + data=data, + json=json.dumps(data, separators=(",", ":"), sort_keys=True), + ) + + +class LocalFSAdapter(BaseAdapter): + + def send(self, request, stream=None, timeout=None, verify=None, cert=None, + proxies=None): + pathname = url_to_path(request.url) + + resp = Response() + resp.status_code = 200 + resp.url = request.url + + try: + stats = os.stat(pathname) + except OSError as exc: + resp.status_code = 404 + resp.raw = exc + else: + modified = email.utils.formatdate(stats.st_mtime, usegmt=True) + content_type = mimetypes.guess_type(pathname)[0] or "text/plain" + resp.headers = CaseInsensitiveDict({ + "Content-Type": content_type, + "Content-Length": stats.st_size, + "Last-Modified": modified, + }) + + resp.raw = open(pathname, "rb") + resp.close = resp.raw.close + + return resp + + def close(self): + pass + + +class InsecureHTTPAdapter(HTTPAdapter): + + def cert_verify(self, conn, url, verify, cert): + super(InsecureHTTPAdapter, self).cert_verify( + conn=conn, url=url, verify=False, cert=cert + ) + + +class InsecureCacheControlAdapter(CacheControlAdapter): + + def cert_verify(self, conn, url, verify, cert): + super(InsecureCacheControlAdapter, self).cert_verify( + conn=conn, url=url, verify=False, cert=cert + ) + + +class PipSession(requests.Session): + + timeout = None # type: Optional[int] + + def __init__(self, *args, **kwargs): + """ + :param trusted_hosts: Domains not to emit warnings for when not using + HTTPS. + """ + retries = kwargs.pop("retries", 0) + cache = kwargs.pop("cache", None) + trusted_hosts = kwargs.pop("trusted_hosts", []) # type: List[str] + index_urls = kwargs.pop("index_urls", None) + + super(PipSession, self).__init__(*args, **kwargs) + + # Namespace the attribute with "pip_" just in case to prevent + # possible conflicts with the base class. + self.pip_trusted_origins = [] # type: List[Tuple[str, Optional[int]]] + + # Attach our User Agent to the request + self.headers["User-Agent"] = user_agent() + + # Attach our Authentication handler to the session + self.auth = MultiDomainBasicAuth(index_urls=index_urls) + + # Create our urllib3.Retry instance which will allow us to customize + # how we handle retries. + retries = urllib3.Retry( + # Set the total number of retries that a particular request can + # have. + total=retries, + + # A 503 error from PyPI typically means that the Fastly -> Origin + # connection got interrupted in some way. A 503 error in general + # is typically considered a transient error so we'll go ahead and + # retry it. + # A 500 may indicate transient error in Amazon S3 + # A 520 or 527 - may indicate transient error in CloudFlare + status_forcelist=[500, 503, 520, 527], + + # Add a small amount of back off between failed requests in + # order to prevent hammering the service. + backoff_factor=0.25, + ) + + # Our Insecure HTTPAdapter disables HTTPS validation. It does not + # support caching so we'll use it for all http:// URLs. + # If caching is disabled, we will also use it for + # https:// hosts that we've marked as ignoring + # TLS errors for (trusted-hosts). + insecure_adapter = InsecureHTTPAdapter(max_retries=retries) + + # We want to _only_ cache responses on securely fetched origins or when + # the host is specified as trusted. We do this because + # we can't validate the response of an insecurely/untrusted fetched + # origin, and we don't want someone to be able to poison the cache and + # require manual eviction from the cache to fix it. + if cache: + secure_adapter = CacheControlAdapter( + cache=SafeFileCache(cache), + max_retries=retries, + ) + self._trusted_host_adapter = InsecureCacheControlAdapter( + cache=SafeFileCache(cache), + max_retries=retries, + ) + else: + secure_adapter = HTTPAdapter(max_retries=retries) + self._trusted_host_adapter = insecure_adapter + + self.mount("https://", secure_adapter) + self.mount("http://", insecure_adapter) + + # Enable file:// urls + self.mount("file://", LocalFSAdapter()) + + for host in trusted_hosts: + self.add_trusted_host(host, suppress_logging=True) + + def add_trusted_host(self, host, source=None, suppress_logging=False): + # type: (str, Optional[str], bool) -> None + """ + :param host: It is okay to provide a host that has previously been + added. + :param source: An optional source string, for logging where the host + string came from. + """ + if not suppress_logging: + msg = 'adding trusted host: {!r}'.format(host) + if source is not None: + msg += ' (from {})'.format(source) + logger.info(msg) + + host_port = parse_netloc(host) + if host_port not in self.pip_trusted_origins: + self.pip_trusted_origins.append(host_port) + + self.mount( + build_url_from_netloc(host) + '/', + self._trusted_host_adapter + ) + if not host_port[1]: + # Mount wildcard ports for the same host. + self.mount( + build_url_from_netloc(host) + ':', + self._trusted_host_adapter + ) + + def iter_secure_origins(self): + # type: () -> Iterator[SecureOrigin] + for secure_origin in SECURE_ORIGINS: + yield secure_origin + for host, port in self.pip_trusted_origins: + yield ('*', host, '*' if port is None else port) + + def is_secure_origin(self, location): + # type: (Link) -> bool + # Determine if this url used a secure transport mechanism + parsed = urllib_parse.urlparse(str(location)) + origin_protocol, origin_host, origin_port = ( + parsed.scheme, parsed.hostname, parsed.port, + ) + + # The protocol to use to see if the protocol matches. + # Don't count the repository type as part of the protocol: in + # cases such as "git+ssh", only use "ssh". (I.e., Only verify against + # the last scheme.) + origin_protocol = origin_protocol.rsplit('+', 1)[-1] + + # Determine if our origin is a secure origin by looking through our + # hardcoded list of secure origins, as well as any additional ones + # configured on this PackageFinder instance. + for secure_origin in self.iter_secure_origins(): + secure_protocol, secure_host, secure_port = secure_origin + if origin_protocol != secure_protocol and secure_protocol != "*": + continue + + try: + addr = ipaddress.ip_address( + None + if origin_host is None + else six.ensure_text(origin_host) + ) + network = ipaddress.ip_network( + six.ensure_text(secure_host) + ) + except ValueError: + # We don't have both a valid address or a valid network, so + # we'll check this origin against hostnames. + if ( + origin_host and + origin_host.lower() != secure_host.lower() and + secure_host != "*" + ): + continue + else: + # We have a valid address and network, so see if the address + # is contained within the network. + if addr not in network: + continue + + # Check to see if the port matches. + if ( + origin_port != secure_port and + secure_port != "*" and + secure_port is not None + ): + continue + + # If we've gotten here, then this origin matches the current + # secure origin and we should return True + return True + + # If we've gotten to this point, then the origin isn't secure and we + # will not accept it as a valid location to search. We will however + # log a warning that we are ignoring it. + logger.warning( + "The repository located at %s is not a trusted or secure host and " + "is being ignored. If this repository is available via HTTPS we " + "recommend you use HTTPS instead, otherwise you may silence " + "this warning and allow it anyway with '--trusted-host %s'.", + origin_host, + origin_host, + ) + + return False + + def request(self, method, url, *args, **kwargs): + # Allow setting a default timeout on a session + kwargs.setdefault("timeout", self.timeout) + + # Dispatch the actual request + return super(PipSession, self).request(method, url, *args, **kwargs) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/network/utils.py b/venv/lib/python3.8/site-packages/pip/_internal/network/utils.py new file mode 100644 index 0000000..a19050b --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/network/utils.py @@ -0,0 +1,48 @@ +from pip._vendor.requests.models import CONTENT_CHUNK_SIZE, Response + +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Iterator + + +def response_chunks(response, chunk_size=CONTENT_CHUNK_SIZE): + # type: (Response, int) -> Iterator[bytes] + """Given a requests Response, provide the data chunks. + """ + try: + # Special case for urllib3. + for chunk in response.raw.stream( + chunk_size, + # We use decode_content=False here because we don't + # want urllib3 to mess with the raw bytes we get + # from the server. If we decompress inside of + # urllib3 then we cannot verify the checksum + # because the checksum will be of the compressed + # file. This breakage will only occur if the + # server adds a Content-Encoding header, which + # depends on how the server was configured: + # - Some servers will notice that the file isn't a + # compressible file and will leave the file alone + # and with an empty Content-Encoding + # - Some servers will notice that the file is + # already compressed and will leave the file + # alone and will add a Content-Encoding: gzip + # header + # - Some servers won't notice anything at all and + # will take a file that's already been compressed + # and compress it again and set the + # Content-Encoding: gzip header + # + # By setting this not to decode automatically we + # hope to eliminate problems with the second case. + decode_content=False, + ): + yield chunk + except AttributeError: + # Standard file-like object. + while True: + chunk = response.raw.read(chunk_size) + if not chunk: + break + yield chunk diff --git a/venv/lib/python3.8/site-packages/pip/_internal/network/xmlrpc.py b/venv/lib/python3.8/site-packages/pip/_internal/network/xmlrpc.py new file mode 100644 index 0000000..121edd9 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/network/xmlrpc.py @@ -0,0 +1,44 @@ +"""xmlrpclib.Transport implementation +""" + +# The following comment should be removed at some point in the future. +# mypy: disallow-untyped-defs=False + +import logging + +from pip._vendor import requests +# NOTE: XMLRPC Client is not annotated in typeshed as on 2017-07-17, which is +# why we ignore the type on this import +from pip._vendor.six.moves import xmlrpc_client # type: ignore +from pip._vendor.six.moves.urllib import parse as urllib_parse + +logger = logging.getLogger(__name__) + + +class PipXmlrpcTransport(xmlrpc_client.Transport): + """Provide a `xmlrpclib.Transport` implementation via a `PipSession` + object. + """ + + def __init__(self, index_url, session, use_datetime=False): + xmlrpc_client.Transport.__init__(self, use_datetime) + index_parts = urllib_parse.urlparse(index_url) + self._scheme = index_parts.scheme + self._session = session + + def request(self, host, handler, request_body, verbose=False): + parts = (self._scheme, host, handler, None, None, None) + url = urllib_parse.urlunparse(parts) + try: + headers = {'Content-Type': 'text/xml'} + response = self._session.post(url, data=request_body, + headers=headers, stream=True) + response.raise_for_status() + self.verbose = verbose + return self.parse_response(response.raw) + except requests.HTTPError as exc: + logger.critical( + "HTTP error %s while getting %s", + exc.response.status_code, url, + ) + raise diff --git a/venv/lib/python3.8/site-packages/pip/_internal/operations/__init__.py b/venv/lib/python3.8/site-packages/pip/_internal/operations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.8/site-packages/pip/_internal/operations/build/__init__.py b/venv/lib/python3.8/site-packages/pip/_internal/operations/build/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.8/site-packages/pip/_internal/operations/build/metadata.py b/venv/lib/python3.8/site-packages/pip/_internal/operations/build/metadata.py new file mode 100644 index 0000000..b13fbde --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/operations/build/metadata.py @@ -0,0 +1,40 @@ +"""Metadata generation logic for source distributions. +""" + +import logging +import os + +from pip._internal.utils.subprocess import runner_with_spinner_message +from pip._internal.utils.temp_dir import TempDirectory +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from pip._internal.build_env import BuildEnvironment + from pip._vendor.pep517.wrappers import Pep517HookCaller + +logger = logging.getLogger(__name__) + + +def generate_metadata(build_env, backend): + # type: (BuildEnvironment, Pep517HookCaller) -> str + """Generate metadata using mechanisms described in PEP 517. + + Returns the generated metadata directory. + """ + metadata_tmpdir = TempDirectory( + kind="modern-metadata", globally_managed=True + ) + + metadata_dir = metadata_tmpdir.path + + with build_env: + # Note that Pep517HookCaller implements a fallback for + # prepare_metadata_for_build_wheel, so we don't have to + # consider the possibility that this hook doesn't exist. + runner = runner_with_spinner_message("Preparing wheel metadata") + with backend.subprocess_runner(runner): + distinfo_dir = backend.prepare_metadata_for_build_wheel( + metadata_dir + ) + + return os.path.join(metadata_dir, distinfo_dir) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/operations/build/metadata_legacy.py b/venv/lib/python3.8/site-packages/pip/_internal/operations/build/metadata_legacy.py new file mode 100644 index 0000000..14762ae --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/operations/build/metadata_legacy.py @@ -0,0 +1,77 @@ +"""Metadata generation logic for legacy source distributions. +""" + +import logging +import os + +from pip._internal.exceptions import InstallationError +from pip._internal.utils.setuptools_build import make_setuptools_egg_info_args +from pip._internal.utils.subprocess import call_subprocess +from pip._internal.utils.temp_dir import TempDirectory +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from pip._internal.build_env import BuildEnvironment + +logger = logging.getLogger(__name__) + + +def _find_egg_info(directory): + # type: (str) -> str + """Find an .egg-info subdirectory in `directory`. + """ + filenames = [ + f for f in os.listdir(directory) if f.endswith(".egg-info") + ] + + if not filenames: + raise InstallationError( + "No .egg-info directory found in {}".format(directory) + ) + + if len(filenames) > 1: + raise InstallationError( + "More than one .egg-info directory found in {}".format( + directory + ) + ) + + return os.path.join(directory, filenames[0]) + + +def generate_metadata( + build_env, # type: BuildEnvironment + setup_py_path, # type: str + source_dir, # type: str + isolated, # type: bool + details, # type: str +): + # type: (...) -> str + """Generate metadata using setup.py-based defacto mechanisms. + + Returns the generated metadata directory. + """ + logger.debug( + 'Running setup.py (path:%s) egg_info for package %s', + setup_py_path, details, + ) + + egg_info_dir = TempDirectory( + kind="pip-egg-info", globally_managed=True + ).path + + args = make_setuptools_egg_info_args( + setup_py_path, + egg_info_dir=egg_info_dir, + no_user_config=isolated, + ) + + with build_env: + call_subprocess( + args, + cwd=source_dir, + command_desc='python setup.py egg_info', + ) + + # Return the .egg-info directory. + return _find_egg_info(egg_info_dir) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/operations/build/wheel.py b/venv/lib/python3.8/site-packages/pip/_internal/operations/build/wheel.py new file mode 100644 index 0000000..1266ce0 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/operations/build/wheel.py @@ -0,0 +1,46 @@ +import logging +import os + +from pip._internal.utils.subprocess import runner_with_spinner_message +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import List, Optional + from pip._vendor.pep517.wrappers import Pep517HookCaller + +logger = logging.getLogger(__name__) + + +def build_wheel_pep517( + name, # type: str + backend, # type: Pep517HookCaller + metadata_directory, # type: str + build_options, # type: List[str] + tempd, # type: str +): + # type: (...) -> Optional[str] + """Build one InstallRequirement using the PEP 517 build process. + + Returns path to wheel if successfully built. Otherwise, returns None. + """ + assert metadata_directory is not None + if build_options: + # PEP 517 does not support --build-options + logger.error('Cannot build wheel for %s using PEP 517 when ' + '--build-option is present' % (name,)) + return None + try: + logger.debug('Destination directory: %s', tempd) + + runner = runner_with_spinner_message( + 'Building wheel for {} (PEP 517)'.format(name) + ) + with backend.subprocess_runner(runner): + wheel_name = backend.build_wheel( + tempd, + metadata_directory=metadata_directory, + ) + except Exception: + logger.error('Failed building wheel for %s', name) + return None + return os.path.join(tempd, wheel_name) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/operations/build/wheel_legacy.py b/venv/lib/python3.8/site-packages/pip/_internal/operations/build/wheel_legacy.py new file mode 100644 index 0000000..37dc876 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/operations/build/wheel_legacy.py @@ -0,0 +1,115 @@ +import logging +import os.path + +from pip._internal.cli.spinners import open_spinner +from pip._internal.utils.setuptools_build import ( + make_setuptools_bdist_wheel_args, +) +from pip._internal.utils.subprocess import ( + LOG_DIVIDER, + call_subprocess, + format_command_args, +) +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import List, Optional, Text + +logger = logging.getLogger(__name__) + + +def format_command_result( + command_args, # type: List[str] + command_output, # type: Text +): + # type: (...) -> str + """Format command information for logging.""" + command_desc = format_command_args(command_args) + text = 'Command arguments: {}\n'.format(command_desc) + + if not command_output: + text += 'Command output: None' + elif logger.getEffectiveLevel() > logging.DEBUG: + text += 'Command output: [use --verbose to show]' + else: + if not command_output.endswith('\n'): + command_output += '\n' + text += 'Command output:\n{}{}'.format(command_output, LOG_DIVIDER) + + return text + + +def get_legacy_build_wheel_path( + names, # type: List[str] + temp_dir, # type: str + name, # type: str + command_args, # type: List[str] + command_output, # type: Text +): + # type: (...) -> Optional[str] + """Return the path to the wheel in the temporary build directory.""" + # Sort for determinism. + names = sorted(names) + if not names: + msg = ( + 'Legacy build of wheel for {!r} created no files.\n' + ).format(name) + msg += format_command_result(command_args, command_output) + logger.warning(msg) + return None + + if len(names) > 1: + msg = ( + 'Legacy build of wheel for {!r} created more than one file.\n' + 'Filenames (choosing first): {}\n' + ).format(name, names) + msg += format_command_result(command_args, command_output) + logger.warning(msg) + + return os.path.join(temp_dir, names[0]) + + +def build_wheel_legacy( + name, # type: str + setup_py_path, # type: str + source_dir, # type: str + global_options, # type: List[str] + build_options, # type: List[str] + tempd, # type: str +): + # type: (...) -> Optional[str] + """Build one unpacked package using the "legacy" build process. + + Returns path to wheel if successfully built. Otherwise, returns None. + """ + wheel_args = make_setuptools_bdist_wheel_args( + setup_py_path, + global_options=global_options, + build_options=build_options, + destination_dir=tempd, + ) + + spin_message = 'Building wheel for {} (setup.py)'.format(name) + with open_spinner(spin_message) as spinner: + logger.debug('Destination directory: %s', tempd) + + try: + output = call_subprocess( + wheel_args, + cwd=source_dir, + spinner=spinner, + ) + except Exception: + spinner.finish("error") + logger.error('Failed building wheel for %s', name) + return None + + names = os.listdir(tempd) + wheel_path = get_legacy_build_wheel_path( + names=names, + temp_dir=tempd, + name=name, + command_args=wheel_args, + command_output=output, + ) + return wheel_path diff --git a/venv/lib/python3.8/site-packages/pip/_internal/operations/check.py b/venv/lib/python3.8/site-packages/pip/_internal/operations/check.py new file mode 100644 index 0000000..b85a123 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/operations/check.py @@ -0,0 +1,163 @@ +"""Validation of dependencies of packages +""" + +# The following comment should be removed at some point in the future. +# mypy: strict-optional=False +# mypy: disallow-untyped-defs=False + +import logging +from collections import namedtuple + +from pip._vendor.packaging.utils import canonicalize_name +from pip._vendor.pkg_resources import RequirementParseError + +from pip._internal.distributions import ( + make_distribution_for_install_requirement, +) +from pip._internal.utils.misc import get_installed_distributions +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +logger = logging.getLogger(__name__) + +if MYPY_CHECK_RUNNING: + from pip._internal.req.req_install import InstallRequirement + from typing import ( + Any, Callable, Dict, Optional, Set, Tuple, List + ) + + # Shorthands + PackageSet = Dict[str, 'PackageDetails'] + Missing = Tuple[str, Any] + Conflicting = Tuple[str, str, Any] + + MissingDict = Dict[str, List[Missing]] + ConflictingDict = Dict[str, List[Conflicting]] + CheckResult = Tuple[MissingDict, ConflictingDict] + +PackageDetails = namedtuple('PackageDetails', ['version', 'requires']) + + +def create_package_set_from_installed(**kwargs): + # type: (**Any) -> Tuple[PackageSet, bool] + """Converts a list of distributions into a PackageSet. + """ + # Default to using all packages installed on the system + if kwargs == {}: + kwargs = {"local_only": False, "skip": ()} + + package_set = {} + problems = False + for dist in get_installed_distributions(**kwargs): + name = canonicalize_name(dist.project_name) + try: + package_set[name] = PackageDetails(dist.version, dist.requires()) + except RequirementParseError as e: + # Don't crash on broken metadata + logger.warning("Error parsing requirements for %s: %s", name, e) + problems = True + return package_set, problems + + +def check_package_set(package_set, should_ignore=None): + # type: (PackageSet, Optional[Callable[[str], bool]]) -> CheckResult + """Check if a package set is consistent + + If should_ignore is passed, it should be a callable that takes a + package name and returns a boolean. + """ + if should_ignore is None: + def should_ignore(name): + return False + + missing = {} + conflicting = {} + + for package_name in package_set: + # Info about dependencies of package_name + missing_deps = set() # type: Set[Missing] + conflicting_deps = set() # type: Set[Conflicting] + + if should_ignore(package_name): + continue + + for req in package_set[package_name].requires: + name = canonicalize_name(req.project_name) # type: str + + # Check if it's missing + if name not in package_set: + missed = True + if req.marker is not None: + missed = req.marker.evaluate() + if missed: + missing_deps.add((name, req)) + continue + + # Check if there's a conflict + version = package_set[name].version # type: str + if not req.specifier.contains(version, prereleases=True): + conflicting_deps.add((name, version, req)) + + if missing_deps: + missing[package_name] = sorted(missing_deps, key=str) + if conflicting_deps: + conflicting[package_name] = sorted(conflicting_deps, key=str) + + return missing, conflicting + + +def check_install_conflicts(to_install): + # type: (List[InstallRequirement]) -> Tuple[PackageSet, CheckResult] + """For checking if the dependency graph would be consistent after \ + installing given requirements + """ + # Start from the current state + package_set, _ = create_package_set_from_installed() + # Install packages + would_be_installed = _simulate_installation_of(to_install, package_set) + + # Only warn about directly-dependent packages; create a whitelist of them + whitelist = _create_whitelist(would_be_installed, package_set) + + return ( + package_set, + check_package_set( + package_set, should_ignore=lambda name: name not in whitelist + ) + ) + + +def _simulate_installation_of(to_install, package_set): + # type: (List[InstallRequirement], PackageSet) -> Set[str] + """Computes the version of packages after installing to_install. + """ + + # Keep track of packages that were installed + installed = set() + + # Modify it as installing requirement_set would (assuming no errors) + for inst_req in to_install: + abstract_dist = make_distribution_for_install_requirement(inst_req) + dist = abstract_dist.get_pkg_resources_distribution() + + name = canonicalize_name(dist.key) + package_set[name] = PackageDetails(dist.version, dist.requires()) + + installed.add(name) + + return installed + + +def _create_whitelist(would_be_installed, package_set): + # type: (Set[str], PackageSet) -> Set[str] + packages_affected = set(would_be_installed) + + for package_name in package_set: + if package_name in packages_affected: + continue + + for req in package_set[package_name].requires: + if canonicalize_name(req.name) in packages_affected: + packages_affected.add(package_name) + break + + return packages_affected diff --git a/venv/lib/python3.8/site-packages/pip/_internal/operations/freeze.py b/venv/lib/python3.8/site-packages/pip/_internal/operations/freeze.py new file mode 100644 index 0000000..aa6b052 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/operations/freeze.py @@ -0,0 +1,272 @@ +# The following comment should be removed at some point in the future. +# mypy: strict-optional=False +# mypy: disallow-untyped-defs=False + +from __future__ import absolute_import + +import collections +import logging +import os + +from pip._vendor import six +from pip._vendor.packaging.utils import canonicalize_name +from pip._vendor.pkg_resources import RequirementParseError + +from pip._internal.exceptions import BadCommand, InstallationError +from pip._internal.req.constructors import ( + install_req_from_editable, + install_req_from_line, +) +from pip._internal.req.req_file import COMMENT_RE +from pip._internal.utils.direct_url_helpers import ( + direct_url_as_pep440_direct_reference, + dist_get_direct_url, +) +from pip._internal.utils.misc import ( + dist_is_editable, + get_installed_distributions, +) +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import ( + Iterator, Optional, List, Container, Set, Dict, Tuple, Iterable, Union + ) + from pip._internal.cache import WheelCache + from pip._vendor.pkg_resources import ( + Distribution, Requirement + ) + + RequirementInfo = Tuple[Optional[Union[str, Requirement]], bool, List[str]] + + +logger = logging.getLogger(__name__) + + +def freeze( + requirement=None, # type: Optional[List[str]] + find_links=None, # type: Optional[List[str]] + local_only=None, # type: Optional[bool] + user_only=None, # type: Optional[bool] + paths=None, # type: Optional[List[str]] + isolated=False, # type: bool + wheel_cache=None, # type: Optional[WheelCache] + exclude_editable=False, # type: bool + skip=() # type: Container[str] +): + # type: (...) -> Iterator[str] + find_links = find_links or [] + + for link in find_links: + yield '-f {}'.format(link) + installations = {} # type: Dict[str, FrozenRequirement] + for dist in get_installed_distributions(local_only=local_only, + skip=(), + user_only=user_only, + paths=paths): + try: + req = FrozenRequirement.from_dist(dist) + except RequirementParseError as exc: + # We include dist rather than dist.project_name because the + # dist string includes more information, like the version and + # location. We also include the exception message to aid + # troubleshooting. + logger.warning( + 'Could not generate requirement for distribution %r: %s', + dist, exc + ) + continue + if exclude_editable and req.editable: + continue + installations[req.canonical_name] = req + + if requirement: + # the options that don't get turned into an InstallRequirement + # should only be emitted once, even if the same option is in multiple + # requirements files, so we need to keep track of what has been emitted + # so that we don't emit it again if it's seen again + emitted_options = set() # type: Set[str] + # keep track of which files a requirement is in so that we can + # give an accurate warning if a requirement appears multiple times. + req_files = collections.defaultdict(list) # type: Dict[str, List[str]] + for req_file_path in requirement: + with open(req_file_path) as req_file: + for line in req_file: + if (not line.strip() or + line.strip().startswith('#') or + line.startswith(( + '-r', '--requirement', + '-Z', '--always-unzip', + '-f', '--find-links', + '-i', '--index-url', + '--pre', + '--trusted-host', + '--process-dependency-links', + '--extra-index-url'))): + line = line.rstrip() + if line not in emitted_options: + emitted_options.add(line) + yield line + continue + + if line.startswith('-e') or line.startswith('--editable'): + if line.startswith('-e'): + line = line[2:].strip() + else: + line = line[len('--editable'):].strip().lstrip('=') + line_req = install_req_from_editable( + line, + isolated=isolated, + ) + else: + line_req = install_req_from_line( + COMMENT_RE.sub('', line).strip(), + isolated=isolated, + ) + + if not line_req.name: + logger.info( + "Skipping line in requirement file [%s] because " + "it's not clear what it would install: %s", + req_file_path, line.strip(), + ) + logger.info( + " (add #egg=PackageName to the URL to avoid" + " this warning)" + ) + else: + line_req_canonical_name = canonicalize_name( + line_req.name) + if line_req_canonical_name not in installations: + # either it's not installed, or it is installed + # but has been processed already + if not req_files[line_req.name]: + logger.warning( + "Requirement file [%s] contains %s, but " + "package %r is not installed", + req_file_path, + COMMENT_RE.sub('', line).strip(), + line_req.name + ) + else: + req_files[line_req.name].append(req_file_path) + else: + yield str(installations[ + line_req_canonical_name]).rstrip() + del installations[line_req_canonical_name] + req_files[line_req.name].append(req_file_path) + + # Warn about requirements that were included multiple times (in a + # single requirements file or in different requirements files). + for name, files in six.iteritems(req_files): + if len(files) > 1: + logger.warning("Requirement %s included multiple times [%s]", + name, ', '.join(sorted(set(files)))) + + yield( + '## The following requirements were added by ' + 'pip freeze:' + ) + for installation in sorted( + installations.values(), key=lambda x: x.name.lower()): + if installation.canonical_name not in skip: + yield str(installation).rstrip() + + +def get_requirement_info(dist): + # type: (Distribution) -> RequirementInfo + """ + Compute and return values (req, editable, comments) for use in + FrozenRequirement.from_dist(). + """ + if not dist_is_editable(dist): + return (None, False, []) + + location = os.path.normcase(os.path.abspath(dist.location)) + + from pip._internal.vcs import vcs, RemoteNotFoundError + vcs_backend = vcs.get_backend_for_dir(location) + + if vcs_backend is None: + req = dist.as_requirement() + logger.debug( + 'No VCS found for editable requirement "%s" in: %r', req, + location, + ) + comments = [ + '# Editable install with no version control ({})'.format(req) + ] + return (location, True, comments) + + try: + req = vcs_backend.get_src_requirement(location, dist.project_name) + except RemoteNotFoundError: + req = dist.as_requirement() + comments = [ + '# Editable {} install with no remote ({})'.format( + type(vcs_backend).__name__, req, + ) + ] + return (location, True, comments) + + except BadCommand: + logger.warning( + 'cannot determine version of editable source in %s ' + '(%s command not found in path)', + location, + vcs_backend.name, + ) + return (None, True, []) + + except InstallationError as exc: + logger.warning( + "Error when trying to get requirement for VCS system %s, " + "falling back to uneditable format", exc + ) + else: + if req is not None: + return (req, True, []) + + logger.warning( + 'Could not determine repository location of %s', location + ) + comments = ['## !! Could not determine repository location'] + + return (None, False, comments) + + +class FrozenRequirement(object): + def __init__(self, name, req, editable, comments=()): + # type: (str, Union[str, Requirement], bool, Iterable[str]) -> None + self.name = name + self.canonical_name = canonicalize_name(name) + self.req = req + self.editable = editable + self.comments = comments + + @classmethod + def from_dist(cls, dist): + # type: (Distribution) -> FrozenRequirement + # TODO `get_requirement_info` is taking care of editable requirements. + # TODO This should be refactored when we will add detection of + # editable that provide .dist-info metadata. + req, editable, comments = get_requirement_info(dist) + if req is None and not editable: + # if PEP 610 metadata is present, attempt to use it + direct_url = dist_get_direct_url(dist) + if direct_url: + req = direct_url_as_pep440_direct_reference( + direct_url, dist.project_name + ) + comments = [] + if req is None: + # name==version requirement + req = dist.as_requirement() + + return cls(dist.project_name, req, editable, comments=comments) + + def __str__(self): + req = self.req + if self.editable: + req = '-e {}'.format(req) + return '\n'.join(list(self.comments) + [str(req)]) + '\n' diff --git a/venv/lib/python3.8/site-packages/pip/_internal/operations/install/__init__.py b/venv/lib/python3.8/site-packages/pip/_internal/operations/install/__init__.py new file mode 100644 index 0000000..24d6a5d --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/operations/install/__init__.py @@ -0,0 +1,2 @@ +"""For modules related to installing packages. +""" diff --git a/venv/lib/python3.8/site-packages/pip/_internal/operations/install/editable_legacy.py b/venv/lib/python3.8/site-packages/pip/_internal/operations/install/editable_legacy.py new file mode 100644 index 0000000..a668a61 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/operations/install/editable_legacy.py @@ -0,0 +1,52 @@ +"""Legacy editable installation process, i.e. `setup.py develop`. +""" +import logging + +from pip._internal.utils.logging import indent_log +from pip._internal.utils.setuptools_build import make_setuptools_develop_args +from pip._internal.utils.subprocess import call_subprocess +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import List, Optional, Sequence + + from pip._internal.build_env import BuildEnvironment + + +logger = logging.getLogger(__name__) + + +def install_editable( + install_options, # type: List[str] + global_options, # type: Sequence[str] + prefix, # type: Optional[str] + home, # type: Optional[str] + use_user_site, # type: bool + name, # type: str + setup_py_path, # type: str + isolated, # type: bool + build_env, # type: BuildEnvironment + unpacked_source_directory, # type: str +): + # type: (...) -> None + """Install a package in editable mode. Most arguments are pass-through + to setuptools. + """ + logger.info('Running setup.py develop for %s', name) + + args = make_setuptools_develop_args( + setup_py_path, + global_options=global_options, + install_options=install_options, + no_user_config=isolated, + prefix=prefix, + home=home, + use_user_site=use_user_site, + ) + + with indent_log(): + with build_env: + call_subprocess( + args, + cwd=unpacked_source_directory, + ) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/operations/install/legacy.py b/venv/lib/python3.8/site-packages/pip/_internal/operations/install/legacy.py new file mode 100644 index 0000000..0fac905 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/operations/install/legacy.py @@ -0,0 +1,142 @@ +"""Legacy installation process, i.e. `setup.py install`. +""" + +import logging +import os +import sys +from distutils.util import change_root + +from pip._internal.utils.deprecation import deprecated +from pip._internal.utils.logging import indent_log +from pip._internal.utils.misc import ensure_dir +from pip._internal.utils.setuptools_build import make_setuptools_install_args +from pip._internal.utils.subprocess import runner_with_spinner_message +from pip._internal.utils.temp_dir import TempDirectory +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import List, Optional, Sequence + + from pip._internal.build_env import BuildEnvironment + from pip._internal.models.scheme import Scheme + + +logger = logging.getLogger(__name__) + + +class LegacyInstallFailure(Exception): + def __init__(self): + # type: () -> None + self.parent = sys.exc_info() + + +def install( + install_options, # type: List[str] + global_options, # type: Sequence[str] + root, # type: Optional[str] + home, # type: Optional[str] + prefix, # type: Optional[str] + use_user_site, # type: bool + pycompile, # type: bool + scheme, # type: Scheme + setup_py_path, # type: str + isolated, # type: bool + req_name, # type: str + build_env, # type: BuildEnvironment + unpacked_source_directory, # type: str + req_description, # type: str +): + # type: (...) -> bool + + header_dir = scheme.headers + + with TempDirectory(kind="record") as temp_dir: + try: + record_filename = os.path.join(temp_dir.path, 'install-record.txt') + install_args = make_setuptools_install_args( + setup_py_path, + global_options=global_options, + install_options=install_options, + record_filename=record_filename, + root=root, + prefix=prefix, + header_dir=header_dir, + home=home, + use_user_site=use_user_site, + no_user_config=isolated, + pycompile=pycompile, + ) + + runner = runner_with_spinner_message( + "Running setup.py install for {}".format(req_name) + ) + with indent_log(), build_env: + runner( + cmd=install_args, + cwd=unpacked_source_directory, + ) + + if not os.path.exists(record_filename): + logger.debug('Record file %s not found', record_filename) + # Signal to the caller that we didn't install the new package + return False + + except Exception: + # Signal to the caller that we didn't install the new package + raise LegacyInstallFailure + + # At this point, we have successfully installed the requirement. + + # We intentionally do not use any encoding to read the file because + # setuptools writes the file using distutils.file_util.write_file, + # which does not specify an encoding. + with open(record_filename) as f: + record_lines = f.read().splitlines() + + def prepend_root(path): + # type: (str) -> str + if root is None or not os.path.isabs(path): + return path + else: + return change_root(root, path) + + for line in record_lines: + directory = os.path.dirname(line) + if directory.endswith('.egg-info'): + egg_info_dir = prepend_root(directory) + break + else: + deprecated( + reason=( + "{} did not indicate that it installed an " + ".egg-info directory. Only setup.py projects " + "generating .egg-info directories are supported." + ).format(req_description), + replacement=( + "for maintainers: updating the setup.py of {0}. " + "For users: contact the maintainers of {0} to let " + "them know to update their setup.py.".format( + req_name + ) + ), + gone_in="20.2", + issue=6998, + ) + # FIXME: put the record somewhere + return True + + new_lines = [] + for line in record_lines: + filename = line.strip() + if os.path.isdir(filename): + filename += os.path.sep + new_lines.append( + os.path.relpath(prepend_root(filename), egg_info_dir) + ) + new_lines.sort() + ensure_dir(egg_info_dir) + inst_files_path = os.path.join(egg_info_dir, 'installed-files.txt') + with open(inst_files_path, 'w') as f: + f.write('\n'.join(new_lines) + '\n') + + return True diff --git a/venv/lib/python3.8/site-packages/pip/_internal/operations/install/wheel.py b/venv/lib/python3.8/site-packages/pip/_internal/operations/install/wheel.py new file mode 100644 index 0000000..2fb86b8 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/operations/install/wheel.py @@ -0,0 +1,631 @@ +"""Support for installing and building the "wheel" binary package format. +""" + +# The following comment should be removed at some point in the future. +# mypy: strict-optional=False + +from __future__ import absolute_import + +import collections +import compileall +import contextlib +import csv +import logging +import os.path +import re +import shutil +import stat +import sys +import warnings +from base64 import urlsafe_b64encode +from itertools import starmap +from zipfile import ZipFile + +from pip._vendor import pkg_resources +from pip._vendor.distlib.scripts import ScriptMaker +from pip._vendor.distlib.util import get_export_entry +from pip._vendor.six import StringIO + +from pip._internal.exceptions import InstallationError +from pip._internal.locations import get_major_minor_version +from pip._internal.models.direct_url import DIRECT_URL_METADATA_NAME, DirectUrl +from pip._internal.utils.filesystem import adjacent_tmp_file, replace +from pip._internal.utils.misc import captured_stdout, ensure_dir, hash_file +from pip._internal.utils.temp_dir import TempDirectory +from pip._internal.utils.typing import MYPY_CHECK_RUNNING +from pip._internal.utils.unpacking import current_umask, unpack_file +from pip._internal.utils.wheel import parse_wheel + +if MYPY_CHECK_RUNNING: + from email.message import Message + from typing import ( + Dict, List, Optional, Sequence, Tuple, Any, + Iterable, Iterator, Callable, Set, + ) + + from pip._internal.models.scheme import Scheme + from pip._internal.utils.filesystem import NamedTemporaryFileResult + + InstalledCSVRow = Tuple[str, ...] + + +logger = logging.getLogger(__name__) + + +def normpath(src, p): + # type: (str, str) -> str + return os.path.relpath(src, p).replace(os.path.sep, '/') + + +def rehash(path, blocksize=1 << 20): + # type: (str, int) -> Tuple[str, str] + """Return (encoded_digest, length) for path using hashlib.sha256()""" + h, length = hash_file(path, blocksize) + digest = 'sha256=' + urlsafe_b64encode( + h.digest() + ).decode('latin1').rstrip('=') + # unicode/str python2 issues + return (digest, str(length)) # type: ignore + + +def csv_io_kwargs(mode): + # type: (str) -> Dict[str, Any] + """Return keyword arguments to properly open a CSV file + in the given mode. + """ + if sys.version_info.major < 3: + return {'mode': '{}b'.format(mode)} + else: + return {'mode': mode, 'newline': ''} + + +def fix_script(path): + # type: (str) -> Optional[bool] + """Replace #!python with #!/path/to/python + Return True if file was changed. + """ + # XXX RECORD hashes will need to be updated + if os.path.isfile(path): + with open(path, 'rb') as script: + firstline = script.readline() + if not firstline.startswith(b'#!python'): + return False + exename = sys.executable.encode(sys.getfilesystemencoding()) + firstline = b'#!' + exename + os.linesep.encode("ascii") + rest = script.read() + with open(path, 'wb') as script: + script.write(firstline) + script.write(rest) + return True + return None + + +def wheel_root_is_purelib(metadata): + # type: (Message) -> bool + return metadata.get("Root-Is-Purelib", "").lower() == "true" + + +def get_entrypoints(filename): + # type: (str) -> Tuple[Dict[str, str], Dict[str, str]] + if not os.path.exists(filename): + return {}, {} + + # This is done because you can pass a string to entry_points wrappers which + # means that they may or may not be valid INI files. The attempt here is to + # strip leading and trailing whitespace in order to make them valid INI + # files. + with open(filename) as fp: + data = StringIO() + for line in fp: + data.write(line.strip()) + data.write("\n") + data.seek(0) + + # get the entry points and then the script names + entry_points = pkg_resources.EntryPoint.parse_map(data) + console = entry_points.get('console_scripts', {}) + gui = entry_points.get('gui_scripts', {}) + + def _split_ep(s): + # type: (pkg_resources.EntryPoint) -> Tuple[str, str] + """get the string representation of EntryPoint, + remove space and split on '=' + """ + split_parts = str(s).replace(" ", "").split("=") + return split_parts[0], split_parts[1] + + # convert the EntryPoint objects into strings with module:function + console = dict(_split_ep(v) for v in console.values()) + gui = dict(_split_ep(v) for v in gui.values()) + return console, gui + + +def message_about_scripts_not_on_PATH(scripts): + # type: (Sequence[str]) -> Optional[str] + """Determine if any scripts are not on PATH and format a warning. + Returns a warning message if one or more scripts are not on PATH, + otherwise None. + """ + if not scripts: + return None + + # Group scripts by the path they were installed in + grouped_by_dir = collections.defaultdict(set) # type: Dict[str, Set[str]] + for destfile in scripts: + parent_dir = os.path.dirname(destfile) + script_name = os.path.basename(destfile) + grouped_by_dir[parent_dir].add(script_name) + + # We don't want to warn for directories that are on PATH. + not_warn_dirs = [ + os.path.normcase(i).rstrip(os.sep) for i in + os.environ.get("PATH", "").split(os.pathsep) + ] + # If an executable sits with sys.executable, we don't warn for it. + # This covers the case of venv invocations without activating the venv. + not_warn_dirs.append(os.path.normcase(os.path.dirname(sys.executable))) + warn_for = { + parent_dir: scripts for parent_dir, scripts in grouped_by_dir.items() + if os.path.normcase(parent_dir) not in not_warn_dirs + } # type: Dict[str, Set[str]] + if not warn_for: + return None + + # Format a message + msg_lines = [] + for parent_dir, dir_scripts in warn_for.items(): + sorted_scripts = sorted(dir_scripts) # type: List[str] + if len(sorted_scripts) == 1: + start_text = "script {} is".format(sorted_scripts[0]) + else: + start_text = "scripts {} are".format( + ", ".join(sorted_scripts[:-1]) + " and " + sorted_scripts[-1] + ) + + msg_lines.append( + "The {} installed in '{}' which is not on PATH." + .format(start_text, parent_dir) + ) + + last_line_fmt = ( + "Consider adding {} to PATH or, if you prefer " + "to suppress this warning, use --no-warn-script-location." + ) + if len(msg_lines) == 1: + msg_lines.append(last_line_fmt.format("this directory")) + else: + msg_lines.append(last_line_fmt.format("these directories")) + + # Add a note if any directory starts with ~ + warn_for_tilde = any( + i[0] == "~" for i in os.environ.get("PATH", "").split(os.pathsep) if i + ) + if warn_for_tilde: + tilde_warning_msg = ( + "NOTE: The current PATH contains path(s) starting with `~`, " + "which may not be expanded by all applications." + ) + msg_lines.append(tilde_warning_msg) + + # Returns the formatted multiline message + return "\n".join(msg_lines) + + +def sorted_outrows(outrows): + # type: (Iterable[InstalledCSVRow]) -> List[InstalledCSVRow] + """Return the given rows of a RECORD file in sorted order. + + Each row is a 3-tuple (path, hash, size) and corresponds to a record of + a RECORD file (see PEP 376 and PEP 427 for details). For the rows + passed to this function, the size can be an integer as an int or string, + or the empty string. + """ + # Normally, there should only be one row per path, in which case the + # second and third elements don't come into play when sorting. + # However, in cases in the wild where a path might happen to occur twice, + # we don't want the sort operation to trigger an error (but still want + # determinism). Since the third element can be an int or string, we + # coerce each element to a string to avoid a TypeError in this case. + # For additional background, see-- + # https://github.com/pypa/pip/issues/5868 + return sorted(outrows, key=lambda row: tuple(str(x) for x in row)) + + +def get_csv_rows_for_installed( + old_csv_rows, # type: Iterable[List[str]] + installed, # type: Dict[str, str] + changed, # type: Set[str] + generated, # type: List[str] + lib_dir, # type: str +): + # type: (...) -> List[InstalledCSVRow] + """ + :param installed: A map from archive RECORD path to installation RECORD + path. + """ + installed_rows = [] # type: List[InstalledCSVRow] + for row in old_csv_rows: + if len(row) > 3: + logger.warning( + 'RECORD line has more than three elements: {}'.format(row) + ) + # Make a copy because we are mutating the row. + row = list(row) + old_path = row[0] + new_path = installed.pop(old_path, old_path) + row[0] = new_path + if new_path in changed: + digest, length = rehash(new_path) + row[1] = digest + row[2] = length + installed_rows.append(tuple(row)) + for f in generated: + digest, length = rehash(f) + installed_rows.append((normpath(f, lib_dir), digest, str(length))) + for f in installed: + installed_rows.append((installed[f], '', '')) + return installed_rows + + +class MissingCallableSuffix(Exception): + pass + + +def _raise_for_invalid_entrypoint(specification): + # type: (str) -> None + entry = get_export_entry(specification) + if entry is not None and entry.suffix is None: + raise MissingCallableSuffix(str(entry)) + + +class PipScriptMaker(ScriptMaker): + def make(self, specification, options=None): + # type: (str, Dict[str, Any]) -> List[str] + _raise_for_invalid_entrypoint(specification) + return super(PipScriptMaker, self).make(specification, options) + + +def install_unpacked_wheel( + name, # type: str + wheeldir, # type: str + wheel_zip, # type: ZipFile + scheme, # type: Scheme + req_description, # type: str + pycompile=True, # type: bool + warn_script_location=True, # type: bool + direct_url=None, # type: Optional[DirectUrl] +): + # type: (...) -> None + """Install a wheel. + + :param name: Name of the project to install + :param wheeldir: Base directory of the unpacked wheel + :param wheel_zip: open ZipFile for wheel being installed + :param scheme: Distutils scheme dictating the install directories + :param req_description: String used in place of the requirement, for + logging + :param pycompile: Whether to byte-compile installed Python files + :param warn_script_location: Whether to check that scripts are installed + into a directory on PATH + :raises UnsupportedWheel: + * when the directory holds an unpacked wheel with incompatible + Wheel-Version + * when the .dist-info dir does not match the wheel + """ + # TODO: Investigate and break this up. + # TODO: Look into moving this into a dedicated class for representing an + # installation. + + source = wheeldir.rstrip(os.path.sep) + os.path.sep + + info_dir, metadata = parse_wheel(wheel_zip, name) + + if wheel_root_is_purelib(metadata): + lib_dir = scheme.purelib + else: + lib_dir = scheme.platlib + + subdirs = os.listdir(source) + data_dirs = [s for s in subdirs if s.endswith('.data')] + + # Record details of the files moved + # installed = files copied from the wheel to the destination + # changed = files changed while installing (scripts #! line typically) + # generated = files newly generated during the install (script wrappers) + installed = {} # type: Dict[str, str] + changed = set() + generated = [] # type: List[str] + + # Compile all of the pyc files that we're going to be installing + if pycompile: + with captured_stdout() as stdout: + with warnings.catch_warnings(): + warnings.filterwarnings('ignore') + compileall.compile_dir(source, force=True, quiet=True) + logger.debug(stdout.getvalue()) + + def record_installed(srcfile, destfile, modified=False): + # type: (str, str, bool) -> None + """Map archive RECORD paths to installation RECORD paths.""" + oldpath = normpath(srcfile, wheeldir) + newpath = normpath(destfile, lib_dir) + installed[oldpath] = newpath + if modified: + changed.add(destfile) + + def clobber( + source, # type: str + dest, # type: str + is_base, # type: bool + fixer=None, # type: Optional[Callable[[str], Any]] + filter=None # type: Optional[Callable[[str], bool]] + ): + # type: (...) -> None + ensure_dir(dest) # common for the 'include' path + + for dir, subdirs, files in os.walk(source): + basedir = dir[len(source):].lstrip(os.path.sep) + destdir = os.path.join(dest, basedir) + if is_base and basedir == '': + subdirs[:] = [s for s in subdirs if not s.endswith('.data')] + for f in files: + # Skip unwanted files + if filter and filter(f): + continue + srcfile = os.path.join(dir, f) + destfile = os.path.join(dest, basedir, f) + # directory creation is lazy and after the file filtering above + # to ensure we don't install empty dirs; empty dirs can't be + # uninstalled. + ensure_dir(destdir) + + # copyfile (called below) truncates the destination if it + # exists and then writes the new contents. This is fine in most + # cases, but can cause a segfault if pip has loaded a shared + # object (e.g. from pyopenssl through its vendored urllib3) + # Since the shared object is mmap'd an attempt to call a + # symbol in it will then cause a segfault. Unlinking the file + # allows writing of new contents while allowing the process to + # continue to use the old copy. + if os.path.exists(destfile): + os.unlink(destfile) + + # We use copyfile (not move, copy, or copy2) to be extra sure + # that we are not moving directories over (copyfile fails for + # directories) as well as to ensure that we are not copying + # over any metadata because we want more control over what + # metadata we actually copy over. + shutil.copyfile(srcfile, destfile) + + # Copy over the metadata for the file, currently this only + # includes the atime and mtime. + st = os.stat(srcfile) + if hasattr(os, "utime"): + os.utime(destfile, (st.st_atime, st.st_mtime)) + + # If our file is executable, then make our destination file + # executable. + if os.access(srcfile, os.X_OK): + st = os.stat(srcfile) + permissions = ( + st.st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH + ) + os.chmod(destfile, permissions) + + changed = False + if fixer: + changed = fixer(destfile) + record_installed(srcfile, destfile, changed) + + clobber(source, lib_dir, True) + + dest_info_dir = os.path.join(lib_dir, info_dir) + + # Get the defined entry points + ep_file = os.path.join(dest_info_dir, 'entry_points.txt') + console, gui = get_entrypoints(ep_file) + + def is_entrypoint_wrapper(name): + # type: (str) -> bool + # EP, EP.exe and EP-script.py are scripts generated for + # entry point EP by setuptools + if name.lower().endswith('.exe'): + matchname = name[:-4] + elif name.lower().endswith('-script.py'): + matchname = name[:-10] + elif name.lower().endswith(".pya"): + matchname = name[:-4] + else: + matchname = name + # Ignore setuptools-generated scripts + return (matchname in console or matchname in gui) + + for datadir in data_dirs: + fixer = None + filter = None + for subdir in os.listdir(os.path.join(wheeldir, datadir)): + fixer = None + if subdir == 'scripts': + fixer = fix_script + filter = is_entrypoint_wrapper + source = os.path.join(wheeldir, datadir, subdir) + dest = getattr(scheme, subdir) + clobber(source, dest, False, fixer=fixer, filter=filter) + + maker = PipScriptMaker(None, scheme.scripts) + + # Ensure old scripts are overwritten. + # See https://github.com/pypa/pip/issues/1800 + maker.clobber = True + + # Ensure we don't generate any variants for scripts because this is almost + # never what somebody wants. + # See https://bitbucket.org/pypa/distlib/issue/35/ + maker.variants = {''} + + # This is required because otherwise distlib creates scripts that are not + # executable. + # See https://bitbucket.org/pypa/distlib/issue/32/ + maker.set_mode = True + + scripts_to_generate = [] + + # Special case pip and setuptools to generate versioned wrappers + # + # The issue is that some projects (specifically, pip and setuptools) use + # code in setup.py to create "versioned" entry points - pip2.7 on Python + # 2.7, pip3.3 on Python 3.3, etc. But these entry points are baked into + # the wheel metadata at build time, and so if the wheel is installed with + # a *different* version of Python the entry points will be wrong. The + # correct fix for this is to enhance the metadata to be able to describe + # such versioned entry points, but that won't happen till Metadata 2.0 is + # available. + # In the meantime, projects using versioned entry points will either have + # incorrect versioned entry points, or they will not be able to distribute + # "universal" wheels (i.e., they will need a wheel per Python version). + # + # Because setuptools and pip are bundled with _ensurepip and virtualenv, + # we need to use universal wheels. So, as a stopgap until Metadata 2.0, we + # override the versioned entry points in the wheel and generate the + # correct ones. This code is purely a short-term measure until Metadata 2.0 + # is available. + # + # To add the level of hack in this section of code, in order to support + # ensurepip this code will look for an ``ENSUREPIP_OPTIONS`` environment + # variable which will control which version scripts get installed. + # + # ENSUREPIP_OPTIONS=altinstall + # - Only pipX.Y and easy_install-X.Y will be generated and installed + # ENSUREPIP_OPTIONS=install + # - pipX.Y, pipX, easy_install-X.Y will be generated and installed. Note + # that this option is technically if ENSUREPIP_OPTIONS is set and is + # not altinstall + # DEFAULT + # - The default behavior is to install pip, pipX, pipX.Y, easy_install + # and easy_install-X.Y. + pip_script = console.pop('pip', None) + if pip_script: + if "ENSUREPIP_OPTIONS" not in os.environ: + scripts_to_generate.append('pip = ' + pip_script) + + if os.environ.get("ENSUREPIP_OPTIONS", "") != "altinstall": + scripts_to_generate.append( + 'pip{} = {}'.format(sys.version_info[0], pip_script) + ) + + scripts_to_generate.append( + 'pip{} = {}'.format(get_major_minor_version(), pip_script) + ) + # Delete any other versioned pip entry points + pip_ep = [k for k in console if re.match(r'pip(\d(\.\d)?)?$', k)] + for k in pip_ep: + del console[k] + easy_install_script = console.pop('easy_install', None) + if easy_install_script: + if "ENSUREPIP_OPTIONS" not in os.environ: + scripts_to_generate.append( + 'easy_install = ' + easy_install_script + ) + + scripts_to_generate.append( + 'easy_install-{} = {}'.format( + get_major_minor_version(), easy_install_script + ) + ) + # Delete any other versioned easy_install entry points + easy_install_ep = [ + k for k in console if re.match(r'easy_install(-\d\.\d)?$', k) + ] + for k in easy_install_ep: + del console[k] + + # Generate the console and GUI entry points specified in the wheel + scripts_to_generate.extend(starmap('{} = {}'.format, console.items())) + + gui_scripts_to_generate = list(starmap('{} = {}'.format, gui.items())) + + generated_console_scripts = [] # type: List[str] + + try: + generated_console_scripts = maker.make_multiple(scripts_to_generate) + generated.extend(generated_console_scripts) + + generated.extend( + maker.make_multiple(gui_scripts_to_generate, {'gui': True}) + ) + except MissingCallableSuffix as e: + entry = e.args[0] + raise InstallationError( + "Invalid script entry point: {} for req: {} - A callable " + "suffix is required. Cf https://packaging.python.org/" + "specifications/entry-points/#use-for-scripts for more " + "information.".format(entry, req_description) + ) + + if warn_script_location: + msg = message_about_scripts_not_on_PATH(generated_console_scripts) + if msg is not None: + logger.warning(msg) + + generated_file_mode = 0o666 & ~current_umask() + + @contextlib.contextmanager + def _generate_file(path, **kwargs): + # type: (str, **Any) -> Iterator[NamedTemporaryFileResult] + with adjacent_tmp_file(path, **kwargs) as f: + yield f + os.chmod(f.name, generated_file_mode) + replace(f.name, path) + + # Record pip as the installer + installer_path = os.path.join(dest_info_dir, 'INSTALLER') + with _generate_file(installer_path) as installer_file: + installer_file.write(b'pip\n') + generated.append(installer_path) + + # Record the PEP 610 direct URL reference + if direct_url is not None: + direct_url_path = os.path.join(dest_info_dir, DIRECT_URL_METADATA_NAME) + with _generate_file(direct_url_path) as direct_url_file: + direct_url_file.write(direct_url.to_json().encode("utf-8")) + generated.append(direct_url_path) + + # Record details of all files installed + record_path = os.path.join(dest_info_dir, 'RECORD') + with open(record_path, **csv_io_kwargs('r')) as record_file: + rows = get_csv_rows_for_installed( + csv.reader(record_file), + installed=installed, + changed=changed, + generated=generated, + lib_dir=lib_dir) + with _generate_file(record_path, **csv_io_kwargs('w')) as record_file: + writer = csv.writer(record_file) + writer.writerows(sorted_outrows(rows)) # sort to simplify testing + + +def install_wheel( + name, # type: str + wheel_path, # type: str + scheme, # type: Scheme + req_description, # type: str + pycompile=True, # type: bool + warn_script_location=True, # type: bool + _temp_dir_for_testing=None, # type: Optional[str] + direct_url=None, # type: Optional[DirectUrl] +): + # type: (...) -> None + with TempDirectory( + path=_temp_dir_for_testing, kind="unpacked-wheel" + ) as unpacked_dir, ZipFile(wheel_path, allowZip64=True) as z: + unpack_file(wheel_path, unpacked_dir.path) + install_unpacked_wheel( + name=name, + wheeldir=unpacked_dir.path, + wheel_zip=z, + scheme=scheme, + req_description=req_description, + pycompile=pycompile, + warn_script_location=warn_script_location, + direct_url=direct_url, + ) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/operations/prepare.py b/venv/lib/python3.8/site-packages/pip/_internal/operations/prepare.py new file mode 100644 index 0000000..1fcbb77 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/operations/prepare.py @@ -0,0 +1,568 @@ +"""Prepares a distribution for installation +""" + +# The following comment should be removed at some point in the future. +# mypy: strict-optional=False + +import logging +import mimetypes +import os +import shutil + +from pip._vendor import requests +from pip._vendor.six import PY2 + +from pip._internal.distributions import ( + make_distribution_for_install_requirement, +) +from pip._internal.distributions.installed import InstalledDistribution +from pip._internal.exceptions import ( + DirectoryUrlHashUnsupported, + HashMismatch, + HashUnpinned, + InstallationError, + PreviousBuildDirError, + VcsHashUnsupported, +) +from pip._internal.utils.filesystem import copy2_fixed +from pip._internal.utils.hashes import MissingHashes +from pip._internal.utils.logging import indent_log +from pip._internal.utils.misc import ( + display_path, + hide_url, + path_to_display, + rmtree, +) +from pip._internal.utils.temp_dir import TempDirectory +from pip._internal.utils.typing import MYPY_CHECK_RUNNING +from pip._internal.utils.unpacking import unpack_file +from pip._internal.vcs import vcs + +if MYPY_CHECK_RUNNING: + from typing import ( + Callable, List, Optional, Tuple, + ) + + from mypy_extensions import TypedDict + + from pip._internal.distributions import AbstractDistribution + from pip._internal.index.package_finder import PackageFinder + from pip._internal.models.link import Link + from pip._internal.network.download import Downloader + from pip._internal.req.req_install import InstallRequirement + from pip._internal.req.req_tracker import RequirementTracker + from pip._internal.utils.hashes import Hashes + + if PY2: + CopytreeKwargs = TypedDict( + 'CopytreeKwargs', + { + 'ignore': Callable[[str, List[str]], List[str]], + 'symlinks': bool, + }, + total=False, + ) + else: + CopytreeKwargs = TypedDict( + 'CopytreeKwargs', + { + 'copy_function': Callable[[str, str], None], + 'ignore': Callable[[str, List[str]], List[str]], + 'ignore_dangling_symlinks': bool, + 'symlinks': bool, + }, + total=False, + ) + +logger = logging.getLogger(__name__) + + +def _get_prepared_distribution( + req, # type: InstallRequirement + req_tracker, # type: RequirementTracker + finder, # type: PackageFinder + build_isolation # type: bool +): + # type: (...) -> AbstractDistribution + """Prepare a distribution for installation. + """ + abstract_dist = make_distribution_for_install_requirement(req) + with req_tracker.track(req): + abstract_dist.prepare_distribution_metadata(finder, build_isolation) + return abstract_dist + + +def unpack_vcs_link(link, location): + # type: (Link, str) -> None + vcs_backend = vcs.get_backend_for_scheme(link.scheme) + assert vcs_backend is not None + vcs_backend.unpack(location, url=hide_url(link.url)) + + +class File(object): + def __init__(self, path, content_type): + # type: (str, str) -> None + self.path = path + self.content_type = content_type + + +def get_http_url( + link, # type: Link + downloader, # type: Downloader + download_dir=None, # type: Optional[str] + hashes=None, # type: Optional[Hashes] +): + # type: (...) -> File + temp_dir = TempDirectory(kind="unpack", globally_managed=True) + # If a download dir is specified, is the file already downloaded there? + already_downloaded_path = None + if download_dir: + already_downloaded_path = _check_download_dir( + link, download_dir, hashes + ) + + if already_downloaded_path: + from_path = already_downloaded_path + content_type = mimetypes.guess_type(from_path)[0] + else: + # let's download to a tmp dir + from_path, content_type = _download_http_url( + link, downloader, temp_dir.path, hashes + ) + + return File(from_path, content_type) + + +def _copy2_ignoring_special_files(src, dest): + # type: (str, str) -> None + """Copying special files is not supported, but as a convenience to users + we skip errors copying them. This supports tools that may create e.g. + socket files in the project source directory. + """ + try: + copy2_fixed(src, dest) + except shutil.SpecialFileError as e: + # SpecialFileError may be raised due to either the source or + # destination. If the destination was the cause then we would actually + # care, but since the destination directory is deleted prior to + # copy we ignore all of them assuming it is caused by the source. + logger.warning( + "Ignoring special file error '%s' encountered copying %s to %s.", + str(e), + path_to_display(src), + path_to_display(dest), + ) + + +def _copy_source_tree(source, target): + # type: (str, str) -> None + target_abspath = os.path.abspath(target) + target_basename = os.path.basename(target_abspath) + target_dirname = os.path.dirname(target_abspath) + + def ignore(d, names): + # type: (str, List[str]) -> List[str] + skipped = [] # type: List[str] + if d == source: + # Pulling in those directories can potentially be very slow, + # exclude the following directories if they appear in the top + # level dir (and only it). + # See discussion at https://github.com/pypa/pip/pull/6770 + skipped += ['.tox', '.nox'] + if os.path.abspath(d) == target_dirname: + # Prevent an infinite recursion if the target is in source. + # This can happen when TMPDIR is set to ${PWD}/... + # and we copy PWD to TMPDIR. + skipped += [target_basename] + return skipped + + kwargs = dict(ignore=ignore, symlinks=True) # type: CopytreeKwargs + + if not PY2: + # Python 2 does not support copy_function, so we only ignore + # errors on special file copy in Python 3. + kwargs['copy_function'] = _copy2_ignoring_special_files + + shutil.copytree(source, target, **kwargs) + + +def get_file_url( + link, # type: Link + download_dir=None, # type: Optional[str] + hashes=None # type: Optional[Hashes] +): + # type: (...) -> File + """Get file and optionally check its hash. + """ + # If a download dir is specified, is the file already there and valid? + already_downloaded_path = None + if download_dir: + already_downloaded_path = _check_download_dir( + link, download_dir, hashes + ) + + if already_downloaded_path: + from_path = already_downloaded_path + else: + from_path = link.file_path + + # If --require-hashes is off, `hashes` is either empty, the + # link's embedded hash, or MissingHashes; it is required to + # match. If --require-hashes is on, we are satisfied by any + # hash in `hashes` matching: a URL-based or an option-based + # one; no internet-sourced hash will be in `hashes`. + if hashes: + hashes.check_against_path(from_path) + + content_type = mimetypes.guess_type(from_path)[0] + + return File(from_path, content_type) + + +def unpack_url( + link, # type: Link + location, # type: str + downloader, # type: Downloader + download_dir=None, # type: Optional[str] + hashes=None, # type: Optional[Hashes] +): + # type: (...) -> Optional[File] + """Unpack link into location, downloading if required. + + :param hashes: A Hashes object, one of whose embedded hashes must match, + or HashMismatch will be raised. If the Hashes is empty, no matches are + required, and unhashable types of requirements (like VCS ones, which + would ordinarily raise HashUnsupported) are allowed. + """ + # non-editable vcs urls + if link.is_vcs: + unpack_vcs_link(link, location) + return None + + # If it's a url to a local directory + if link.is_existing_dir(): + if os.path.isdir(location): + rmtree(location) + _copy_source_tree(link.file_path, location) + return None + + # file urls + if link.is_file: + file = get_file_url(link, download_dir, hashes=hashes) + + # http urls + else: + file = get_http_url( + link, + downloader, + download_dir, + hashes=hashes, + ) + + # unpack the archive to the build dir location. even when only downloading + # archives, they have to be unpacked to parse dependencies + unpack_file(file.path, location, file.content_type) + + return file + + +def _download_http_url( + link, # type: Link + downloader, # type: Downloader + temp_dir, # type: str + hashes, # type: Optional[Hashes] +): + # type: (...) -> Tuple[str, str] + """Download link url into temp_dir using provided session""" + download = downloader(link) + + file_path = os.path.join(temp_dir, download.filename) + with open(file_path, 'wb') as content_file: + for chunk in download.chunks: + content_file.write(chunk) + + if hashes: + hashes.check_against_path(file_path) + + return file_path, download.response.headers.get('content-type', '') + + +def _check_download_dir(link, download_dir, hashes): + # type: (Link, str, Optional[Hashes]) -> Optional[str] + """ Check download_dir for previously downloaded file with correct hash + If a correct file is found return its path else None + """ + download_path = os.path.join(download_dir, link.filename) + + if not os.path.exists(download_path): + return None + + # If already downloaded, does its hash match? + logger.info('File was already downloaded %s', download_path) + if hashes: + try: + hashes.check_against_path(download_path) + except HashMismatch: + logger.warning( + 'Previously-downloaded file %s has bad hash. ' + 'Re-downloading.', + download_path + ) + os.unlink(download_path) + return None + return download_path + + +class RequirementPreparer(object): + """Prepares a Requirement + """ + + def __init__( + self, + build_dir, # type: str + download_dir, # type: Optional[str] + src_dir, # type: str + wheel_download_dir, # type: Optional[str] + build_isolation, # type: bool + req_tracker, # type: RequirementTracker + downloader, # type: Downloader + finder, # type: PackageFinder + require_hashes, # type: bool + use_user_site, # type: bool + ): + # type: (...) -> None + super(RequirementPreparer, self).__init__() + + self.src_dir = src_dir + self.build_dir = build_dir + self.req_tracker = req_tracker + self.downloader = downloader + self.finder = finder + + # Where still-packed archives should be written to. If None, they are + # not saved, and are deleted immediately after unpacking. + self.download_dir = download_dir + + # Where still-packed .whl files should be written to. If None, they are + # written to the download_dir parameter. Separate to download_dir to + # permit only keeping wheel archives for pip wheel. + self.wheel_download_dir = wheel_download_dir + + # NOTE + # download_dir and wheel_download_dir overlap semantically and may + # be combined if we're willing to have non-wheel archives present in + # the wheelhouse output by 'pip wheel'. + + # Is build isolation allowed? + self.build_isolation = build_isolation + + # Should hash-checking be required? + self.require_hashes = require_hashes + + # Should install in user site-packages? + self.use_user_site = use_user_site + + @property + def _download_should_save(self): + # type: () -> bool + if not self.download_dir: + return False + + if os.path.exists(self.download_dir): + return True + + logger.critical('Could not find download directory') + raise InstallationError( + "Could not find or access download directory '{}'" + .format(self.download_dir)) + + def prepare_linked_requirement( + self, + req, # type: InstallRequirement + ): + # type: (...) -> AbstractDistribution + """Prepare a requirement that would be obtained from req.link + """ + assert req.link + link = req.link + + # TODO: Breakup into smaller functions + if link.scheme == 'file': + path = link.file_path + logger.info('Processing %s', display_path(path)) + else: + logger.info('Collecting %s', req.req or req) + + download_dir = self.download_dir + if link.is_wheel and self.wheel_download_dir: + # when doing 'pip wheel` we download wheels to a + # dedicated dir. + download_dir = self.wheel_download_dir + + if link.is_wheel: + if download_dir: + # When downloading, we only unpack wheels to get + # metadata. + autodelete_unpacked = True + else: + # When installing a wheel, we use the unpacked + # wheel. + autodelete_unpacked = False + else: + # We always delete unpacked sdists after pip runs. + autodelete_unpacked = True + + with indent_log(): + # Since source_dir is only set for editable requirements. + assert req.source_dir is None + req.ensure_has_source_dir(self.build_dir, autodelete_unpacked) + # If a checkout exists, it's unwise to keep going. version + # inconsistencies are logged later, but do not fail the + # installation. + # FIXME: this won't upgrade when there's an existing + # package unpacked in `req.source_dir` + if os.path.exists(os.path.join(req.source_dir, 'setup.py')): + raise PreviousBuildDirError( + "pip can't proceed with requirements '{}' due to a" + " pre-existing build directory ({}). This is " + "likely due to a previous installation that failed" + ". pip is being responsible and not assuming it " + "can delete this. Please delete it and try again." + .format(req, req.source_dir) + ) + + # Now that we have the real link, we can tell what kind of + # requirements we have and raise some more informative errors + # than otherwise. (For example, we can raise VcsHashUnsupported + # for a VCS URL rather than HashMissing.) + if self.require_hashes: + # We could check these first 2 conditions inside + # unpack_url and save repetition of conditions, but then + # we would report less-useful error messages for + # unhashable requirements, complaining that there's no + # hash provided. + if link.is_vcs: + raise VcsHashUnsupported() + elif link.is_existing_dir(): + raise DirectoryUrlHashUnsupported() + if not req.original_link and not req.is_pinned: + # Unpinned packages are asking for trouble when a new + # version is uploaded. This isn't a security check, but + # it saves users a surprising hash mismatch in the + # future. + # + # file:/// URLs aren't pinnable, so don't complain + # about them not being pinned. + raise HashUnpinned() + + hashes = req.hashes(trust_internet=not self.require_hashes) + if self.require_hashes and not hashes: + # Known-good hashes are missing for this requirement, so + # shim it with a facade object that will provoke hash + # computation and then raise a HashMissing exception + # showing the user what the hash should be. + hashes = MissingHashes() + + try: + local_file = unpack_url( + link, req.source_dir, self.downloader, download_dir, + hashes=hashes, + ) + except requests.HTTPError as exc: + logger.critical( + 'Could not install requirement %s because of error %s', + req, + exc, + ) + raise InstallationError( + 'Could not install requirement {} because of HTTP ' + 'error {} for URL {}'.format(req, exc, link) + ) + + # For use in later processing, preserve the file path on the + # requirement. + if local_file: + req.local_file_path = local_file.path + + abstract_dist = _get_prepared_distribution( + req, self.req_tracker, self.finder, self.build_isolation, + ) + + if download_dir: + if link.is_existing_dir(): + logger.info('Link is a directory, ignoring download_dir') + elif local_file: + download_location = os.path.join( + download_dir, link.filename + ) + if not os.path.exists(download_location): + shutil.copy(local_file.path, download_location) + logger.info( + 'Saved %s', display_path(download_location) + ) + + if self._download_should_save: + # Make a .zip of the source_dir we already created. + if link.is_vcs: + req.archive(self.download_dir) + return abstract_dist + + def prepare_editable_requirement( + self, + req, # type: InstallRequirement + ): + # type: (...) -> AbstractDistribution + """Prepare an editable requirement + """ + assert req.editable, "cannot prepare a non-editable req as editable" + + logger.info('Obtaining %s', req) + + with indent_log(): + if self.require_hashes: + raise InstallationError( + 'The editable requirement {} cannot be installed when ' + 'requiring hashes, because there is no single file to ' + 'hash.'.format(req) + ) + req.ensure_has_source_dir(self.src_dir) + req.update_editable(not self._download_should_save) + + abstract_dist = _get_prepared_distribution( + req, self.req_tracker, self.finder, self.build_isolation, + ) + + if self._download_should_save: + req.archive(self.download_dir) + req.check_if_exists(self.use_user_site) + + return abstract_dist + + def prepare_installed_requirement( + self, + req, # type: InstallRequirement + skip_reason # type: str + ): + # type: (...) -> AbstractDistribution + """Prepare an already-installed requirement + """ + assert req.satisfied_by, "req should have been satisfied but isn't" + assert skip_reason is not None, ( + "did not get skip reason skipped but req.satisfied_by " + "is set to {}".format(req.satisfied_by) + ) + logger.info( + 'Requirement %s: %s (%s)', + skip_reason, req, req.satisfied_by.version + ) + with indent_log(): + if self.require_hashes: + logger.debug( + 'Since it is already installed, we are trusting this ' + 'package without checking its hash. To ensure a ' + 'completely repeatable environment, install into an ' + 'empty virtualenv.' + ) + abstract_dist = InstalledDistribution(req) + + return abstract_dist diff --git a/venv/lib/python3.8/site-packages/pip/_internal/pyproject.py b/venv/lib/python3.8/site-packages/pip/_internal/pyproject.py new file mode 100644 index 0000000..6b4faf7 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/pyproject.py @@ -0,0 +1,196 @@ +from __future__ import absolute_import + +import io +import os +import sys +from collections import namedtuple + +from pip._vendor import six, toml +from pip._vendor.packaging.requirements import InvalidRequirement, Requirement + +from pip._internal.exceptions import InstallationError +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Any, Optional, List + + +def _is_list_of_str(obj): + # type: (Any) -> bool + return ( + isinstance(obj, list) and + all(isinstance(item, six.string_types) for item in obj) + ) + + +def make_pyproject_path(unpacked_source_directory): + # type: (str) -> str + path = os.path.join(unpacked_source_directory, 'pyproject.toml') + + # Python2 __file__ should not be unicode + if six.PY2 and isinstance(path, six.text_type): + path = path.encode(sys.getfilesystemencoding()) + + return path + + +BuildSystemDetails = namedtuple('BuildSystemDetails', [ + 'requires', 'backend', 'check', 'backend_path' +]) + + +def load_pyproject_toml( + use_pep517, # type: Optional[bool] + pyproject_toml, # type: str + setup_py, # type: str + req_name # type: str +): + # type: (...) -> Optional[BuildSystemDetails] + """Load the pyproject.toml file. + + Parameters: + use_pep517 - Has the user requested PEP 517 processing? None + means the user hasn't explicitly specified. + pyproject_toml - Location of the project's pyproject.toml file + setup_py - Location of the project's setup.py file + req_name - The name of the requirement we're processing (for + error reporting) + + Returns: + None if we should use the legacy code path, otherwise a tuple + ( + requirements from pyproject.toml, + name of PEP 517 backend, + requirements we should check are installed after setting + up the build environment + directory paths to import the backend from (backend-path), + relative to the project root. + ) + """ + has_pyproject = os.path.isfile(pyproject_toml) + has_setup = os.path.isfile(setup_py) + + if has_pyproject: + with io.open(pyproject_toml, encoding="utf-8") as f: + pp_toml = toml.load(f) + build_system = pp_toml.get("build-system") + else: + build_system = None + + # The following cases must use PEP 517 + # We check for use_pep517 being non-None and falsey because that means + # the user explicitly requested --no-use-pep517. The value 0 as + # opposed to False can occur when the value is provided via an + # environment variable or config file option (due to the quirk of + # strtobool() returning an integer in pip's configuration code). + if has_pyproject and not has_setup: + if use_pep517 is not None and not use_pep517: + raise InstallationError( + "Disabling PEP 517 processing is invalid: " + "project does not have a setup.py" + ) + use_pep517 = True + elif build_system and "build-backend" in build_system: + if use_pep517 is not None and not use_pep517: + raise InstallationError( + "Disabling PEP 517 processing is invalid: " + "project specifies a build backend of {} " + "in pyproject.toml".format( + build_system["build-backend"] + ) + ) + use_pep517 = True + + # If we haven't worked out whether to use PEP 517 yet, + # and the user hasn't explicitly stated a preference, + # we do so if the project has a pyproject.toml file. + elif use_pep517 is None: + use_pep517 = has_pyproject + + # At this point, we know whether we're going to use PEP 517. + assert use_pep517 is not None + + # If we're using the legacy code path, there is nothing further + # for us to do here. + if not use_pep517: + return None + + if build_system is None: + # Either the user has a pyproject.toml with no build-system + # section, or the user has no pyproject.toml, but has opted in + # explicitly via --use-pep517. + # In the absence of any explicit backend specification, we + # assume the setuptools backend that most closely emulates the + # traditional direct setup.py execution, and require wheel and + # a version of setuptools that supports that backend. + + build_system = { + "requires": ["setuptools>=40.8.0", "wheel"], + "build-backend": "setuptools.build_meta:__legacy__", + } + + # If we're using PEP 517, we have build system information (either + # from pyproject.toml, or defaulted by the code above). + # Note that at this point, we do not know if the user has actually + # specified a backend, though. + assert build_system is not None + + # Ensure that the build-system section in pyproject.toml conforms + # to PEP 518. + error_template = ( + "{package} has a pyproject.toml file that does not comply " + "with PEP 518: {reason}" + ) + + # Specifying the build-system table but not the requires key is invalid + if "requires" not in build_system: + raise InstallationError( + error_template.format(package=req_name, reason=( + "it has a 'build-system' table but not " + "'build-system.requires' which is mandatory in the table" + )) + ) + + # Error out if requires is not a list of strings + requires = build_system["requires"] + if not _is_list_of_str(requires): + raise InstallationError(error_template.format( + package=req_name, + reason="'build-system.requires' is not a list of strings.", + )) + + # Each requirement must be valid as per PEP 508 + for requirement in requires: + try: + Requirement(requirement) + except InvalidRequirement: + raise InstallationError( + error_template.format( + package=req_name, + reason=( + "'build-system.requires' contains an invalid " + "requirement: {!r}".format(requirement) + ), + ) + ) + + backend = build_system.get("build-backend") + backend_path = build_system.get("backend-path", []) + check = [] # type: List[str] + if backend is None: + # If the user didn't specify a backend, we assume they want to use + # the setuptools backend. But we can't be sure they have included + # a version of setuptools which supplies the backend, or wheel + # (which is needed by the backend) in their requirements. So we + # make a note to check that those requirements are present once + # we have set up the environment. + # This is quite a lot of work to check for a very specific case. But + # the problem is, that case is potentially quite common - projects that + # adopted PEP 518 early for the ability to specify requirements to + # execute setup.py, but never considered needing to mention the build + # tools themselves. The original PEP 518 code had a similar check (but + # implemented in a different way). + backend = "setuptools.build_meta:__legacy__" + check = ["setuptools>=40.8.0", "wheel"] + + return BuildSystemDetails(requires, backend, check, backend_path) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/req/__init__.py b/venv/lib/python3.8/site-packages/pip/_internal/req/__init__.py new file mode 100644 index 0000000..d2d027a --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/req/__init__.py @@ -0,0 +1,92 @@ +# The following comment should be removed at some point in the future. +# mypy: strict-optional=False + +from __future__ import absolute_import + +import logging + +from pip._internal.utils.logging import indent_log +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +from .req_file import parse_requirements +from .req_install import InstallRequirement +from .req_set import RequirementSet + +if MYPY_CHECK_RUNNING: + from typing import Any, List, Sequence + +__all__ = [ + "RequirementSet", "InstallRequirement", + "parse_requirements", "install_given_reqs", +] + +logger = logging.getLogger(__name__) + + +class InstallationResult(object): + def __init__(self, name): + # type: (str) -> None + self.name = name + + def __repr__(self): + # type: () -> str + return "InstallationResult(name={!r})".format(self.name) + + +def install_given_reqs( + to_install, # type: List[InstallRequirement] + install_options, # type: List[str] + global_options=(), # type: Sequence[str] + *args, # type: Any + **kwargs # type: Any +): + # type: (...) -> List[InstallationResult] + """ + Install everything in the given list. + + (to be called after having downloaded and unpacked the packages) + """ + + if to_install: + logger.info( + 'Installing collected packages: %s', + ', '.join([req.name for req in to_install]), + ) + + installed = [] + + with indent_log(): + for requirement in to_install: + if requirement.should_reinstall: + logger.info('Attempting uninstall: %s', requirement.name) + with indent_log(): + uninstalled_pathset = requirement.uninstall( + auto_confirm=True + ) + try: + requirement.install( + install_options, + global_options, + *args, + **kwargs + ) + except Exception: + should_rollback = ( + requirement.should_reinstall and + not requirement.install_succeeded + ) + # if install did not succeed, rollback previous uninstall + if should_rollback: + uninstalled_pathset.rollback() + raise + else: + should_commit = ( + requirement.should_reinstall and + requirement.install_succeeded + ) + if should_commit: + uninstalled_pathset.commit() + + installed.append(InstallationResult(requirement.name)) + + return installed diff --git a/venv/lib/python3.8/site-packages/pip/_internal/req/constructors.py b/venv/lib/python3.8/site-packages/pip/_internal/req/constructors.py new file mode 100644 index 0000000..c9f1fe7 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/req/constructors.py @@ -0,0 +1,464 @@ +"""Backing implementation for InstallRequirement's various constructors + +The idea here is that these formed a major chunk of InstallRequirement's size +so, moving them and support code dedicated to them outside of that class +helps creates for better understandability for the rest of the code. + +These are meant to be used elsewhere within pip to create instances of +InstallRequirement. +""" + +# The following comment should be removed at some point in the future. +# mypy: strict-optional=False + +import logging +import os +import re + +from pip._vendor.packaging.markers import Marker +from pip._vendor.packaging.requirements import InvalidRequirement, Requirement +from pip._vendor.packaging.specifiers import Specifier +from pip._vendor.pkg_resources import RequirementParseError, parse_requirements + +from pip._internal.exceptions import InstallationError +from pip._internal.models.index import PyPI, TestPyPI +from pip._internal.models.link import Link +from pip._internal.models.wheel import Wheel +from pip._internal.pyproject import make_pyproject_path +from pip._internal.req.req_install import InstallRequirement +from pip._internal.utils.filetypes import ARCHIVE_EXTENSIONS +from pip._internal.utils.misc import is_installable_dir, splitext +from pip._internal.utils.typing import MYPY_CHECK_RUNNING +from pip._internal.utils.urls import path_to_url +from pip._internal.vcs import is_url, vcs + +if MYPY_CHECK_RUNNING: + from typing import ( + Any, Dict, Optional, Set, Tuple, Union, + ) + from pip._internal.req.req_file import ParsedRequirement + + +__all__ = [ + "install_req_from_editable", "install_req_from_line", + "parse_editable" +] + +logger = logging.getLogger(__name__) +operators = Specifier._operators.keys() + + +def is_archive_file(name): + # type: (str) -> bool + """Return True if `name` is a considered as an archive file.""" + ext = splitext(name)[1].lower() + if ext in ARCHIVE_EXTENSIONS: + return True + return False + + +def _strip_extras(path): + # type: (str) -> Tuple[str, Optional[str]] + m = re.match(r'^(.+)(\[[^\]]+\])$', path) + extras = None + if m: + path_no_extras = m.group(1) + extras = m.group(2) + else: + path_no_extras = path + + return path_no_extras, extras + + +def convert_extras(extras): + # type: (Optional[str]) -> Set[str] + if not extras: + return set() + return Requirement("placeholder" + extras.lower()).extras + + +def parse_editable(editable_req): + # type: (str) -> Tuple[Optional[str], str, Optional[Set[str]]] + """Parses an editable requirement into: + - a requirement name + - an URL + - extras + - editable options + Accepted requirements: + svn+http://blahblah@rev#egg=Foobar[baz]&subdirectory=version_subdir + .[some_extra] + """ + + url = editable_req + + # If a file path is specified with extras, strip off the extras. + url_no_extras, extras = _strip_extras(url) + + if os.path.isdir(url_no_extras): + if not os.path.exists(os.path.join(url_no_extras, 'setup.py')): + msg = ( + 'File "setup.py" not found. Directory cannot be installed ' + 'in editable mode: {}'.format(os.path.abspath(url_no_extras)) + ) + pyproject_path = make_pyproject_path(url_no_extras) + if os.path.isfile(pyproject_path): + msg += ( + '\n(A "pyproject.toml" file was found, but editable ' + 'mode currently requires a setup.py based build.)' + ) + raise InstallationError(msg) + + # Treating it as code that has already been checked out + url_no_extras = path_to_url(url_no_extras) + + if url_no_extras.lower().startswith('file:'): + package_name = Link(url_no_extras).egg_fragment + if extras: + return ( + package_name, + url_no_extras, + Requirement("placeholder" + extras.lower()).extras, + ) + else: + return package_name, url_no_extras, None + + for version_control in vcs: + if url.lower().startswith('{}:'.format(version_control)): + url = '{}+{}'.format(version_control, url) + break + + if '+' not in url: + raise InstallationError( + '{} is not a valid editable requirement. ' + 'It should either be a path to a local project or a VCS URL ' + '(beginning with svn+, git+, hg+, or bzr+).'.format(editable_req) + ) + + vc_type = url.split('+', 1)[0].lower() + + if not vcs.get_backend(vc_type): + backends = ", ".join([bends.name + '+URL' for bends in vcs.backends]) + error_message = "For --editable={}, " \ + "only {} are currently supported".format( + editable_req, backends) + raise InstallationError(error_message) + + package_name = Link(url).egg_fragment + if not package_name: + raise InstallationError( + "Could not detect requirement name for '{}', please specify one " + "with #egg=your_package_name".format(editable_req) + ) + return package_name, url, None + + +def deduce_helpful_msg(req): + # type: (str) -> str + """Returns helpful msg in case requirements file does not exist, + or cannot be parsed. + + :params req: Requirements file path + """ + msg = "" + if os.path.exists(req): + msg = " It does exist." + # Try to parse and check if it is a requirements file. + try: + with open(req, 'r') as fp: + # parse first line only + next(parse_requirements(fp.read())) + msg += ( + "The argument you provided " + "({}) appears to be a" + " requirements file. If that is the" + " case, use the '-r' flag to install" + " the packages specified within it." + ).format(req) + except RequirementParseError: + logger.debug("Cannot parse '{}' as requirements \ + file".format(req), exc_info=True) + else: + msg += " File '{}' does not exist.".format(req) + return msg + + +class RequirementParts(object): + def __init__( + self, + requirement, # type: Optional[Requirement] + link, # type: Optional[Link] + markers, # type: Optional[Marker] + extras, # type: Set[str] + ): + self.requirement = requirement + self.link = link + self.markers = markers + self.extras = extras + + +def parse_req_from_editable(editable_req): + # type: (str) -> RequirementParts + name, url, extras_override = parse_editable(editable_req) + + if name is not None: + try: + req = Requirement(name) + except InvalidRequirement: + raise InstallationError("Invalid requirement: '{}'".format(name)) + else: + req = None + + link = Link(url) + + return RequirementParts(req, link, None, extras_override) + + +# ---- The actual constructors follow ---- + + +def install_req_from_editable( + editable_req, # type: str + comes_from=None, # type: Optional[Union[InstallRequirement, str]] + use_pep517=None, # type: Optional[bool] + isolated=False, # type: bool + options=None, # type: Optional[Dict[str, Any]] + constraint=False # type: bool +): + # type: (...) -> InstallRequirement + + parts = parse_req_from_editable(editable_req) + + return InstallRequirement( + parts.requirement, + comes_from=comes_from, + editable=True, + link=parts.link, + constraint=constraint, + use_pep517=use_pep517, + isolated=isolated, + install_options=options.get("install_options", []) if options else [], + global_options=options.get("global_options", []) if options else [], + hash_options=options.get("hashes", {}) if options else {}, + extras=parts.extras, + ) + + +def _looks_like_path(name): + # type: (str) -> bool + """Checks whether the string "looks like" a path on the filesystem. + + This does not check whether the target actually exists, only judge from the + appearance. + + Returns true if any of the following conditions is true: + * a path separator is found (either os.path.sep or os.path.altsep); + * a dot is found (which represents the current directory). + """ + if os.path.sep in name: + return True + if os.path.altsep is not None and os.path.altsep in name: + return True + if name.startswith("."): + return True + return False + + +def _get_url_from_path(path, name): + # type: (str, str) -> str + """ + First, it checks whether a provided path is an installable directory + (e.g. it has a setup.py). If it is, returns the path. + + If false, check if the path is an archive file (such as a .whl). + The function checks if the path is a file. If false, if the path has + an @, it will treat it as a PEP 440 URL requirement and return the path. + """ + if _looks_like_path(name) and os.path.isdir(path): + if is_installable_dir(path): + return path_to_url(path) + raise InstallationError( + "Directory {name!r} is not installable. Neither 'setup.py' " + "nor 'pyproject.toml' found.".format(**locals()) + ) + if not is_archive_file(path): + return None + if os.path.isfile(path): + return path_to_url(path) + urlreq_parts = name.split('@', 1) + if len(urlreq_parts) >= 2 and not _looks_like_path(urlreq_parts[0]): + # If the path contains '@' and the part before it does not look + # like a path, try to treat it as a PEP 440 URL req instead. + return None + logger.warning( + 'Requirement %r looks like a filename, but the ' + 'file does not exist', + name + ) + return path_to_url(path) + + +def parse_req_from_line(name, line_source): + # type: (str, Optional[str]) -> RequirementParts + if is_url(name): + marker_sep = '; ' + else: + marker_sep = ';' + if marker_sep in name: + name, markers_as_string = name.split(marker_sep, 1) + markers_as_string = markers_as_string.strip() + if not markers_as_string: + markers = None + else: + markers = Marker(markers_as_string) + else: + markers = None + name = name.strip() + req_as_string = None + path = os.path.normpath(os.path.abspath(name)) + link = None + extras_as_string = None + + if is_url(name): + link = Link(name) + else: + p, extras_as_string = _strip_extras(path) + url = _get_url_from_path(p, name) + if url is not None: + link = Link(url) + + # it's a local file, dir, or url + if link: + # Handle relative file URLs + if link.scheme == 'file' and re.search(r'\.\./', link.url): + link = Link( + path_to_url(os.path.normpath(os.path.abspath(link.path)))) + # wheel file + if link.is_wheel: + wheel = Wheel(link.filename) # can raise InvalidWheelFilename + req_as_string = "{wheel.name}=={wheel.version}".format(**locals()) + else: + # set the req to the egg fragment. when it's not there, this + # will become an 'unnamed' requirement + req_as_string = link.egg_fragment + + # a requirement specifier + else: + req_as_string = name + + extras = convert_extras(extras_as_string) + + def with_source(text): + # type: (str) -> str + if not line_source: + return text + return '{} (from {})'.format(text, line_source) + + if req_as_string is not None: + try: + req = Requirement(req_as_string) + except InvalidRequirement: + if os.path.sep in req_as_string: + add_msg = "It looks like a path." + add_msg += deduce_helpful_msg(req_as_string) + elif ('=' in req_as_string and + not any(op in req_as_string for op in operators)): + add_msg = "= is not a valid operator. Did you mean == ?" + else: + add_msg = '' + msg = with_source( + 'Invalid requirement: {!r}'.format(req_as_string) + ) + if add_msg: + msg += '\nHint: {}'.format(add_msg) + raise InstallationError(msg) + else: + req = None + + return RequirementParts(req, link, markers, extras) + + +def install_req_from_line( + name, # type: str + comes_from=None, # type: Optional[Union[str, InstallRequirement]] + use_pep517=None, # type: Optional[bool] + isolated=False, # type: bool + options=None, # type: Optional[Dict[str, Any]] + constraint=False, # type: bool + line_source=None, # type: Optional[str] +): + # type: (...) -> InstallRequirement + """Creates an InstallRequirement from a name, which might be a + requirement, directory containing 'setup.py', filename, or URL. + + :param line_source: An optional string describing where the line is from, + for logging purposes in case of an error. + """ + parts = parse_req_from_line(name, line_source) + + return InstallRequirement( + parts.requirement, comes_from, link=parts.link, markers=parts.markers, + use_pep517=use_pep517, isolated=isolated, + install_options=options.get("install_options", []) if options else [], + global_options=options.get("global_options", []) if options else [], + hash_options=options.get("hashes", {}) if options else {}, + constraint=constraint, + extras=parts.extras, + ) + + +def install_req_from_req_string( + req_string, # type: str + comes_from=None, # type: Optional[InstallRequirement] + isolated=False, # type: bool + use_pep517=None # type: Optional[bool] +): + # type: (...) -> InstallRequirement + try: + req = Requirement(req_string) + except InvalidRequirement: + raise InstallationError("Invalid requirement: '{}'".format(req_string)) + + domains_not_allowed = [ + PyPI.file_storage_domain, + TestPyPI.file_storage_domain, + ] + if (req.url and comes_from and comes_from.link and + comes_from.link.netloc in domains_not_allowed): + # Explicitly disallow pypi packages that depend on external urls + raise InstallationError( + "Packages installed from PyPI cannot depend on packages " + "which are not also hosted on PyPI.\n" + "{} depends on {} ".format(comes_from.name, req) + ) + + return InstallRequirement( + req, comes_from, isolated=isolated, use_pep517=use_pep517 + ) + + +def install_req_from_parsed_requirement( + parsed_req, # type: ParsedRequirement + isolated=False, # type: bool + use_pep517=None # type: Optional[bool] +): + # type: (...) -> InstallRequirement + if parsed_req.is_editable: + req = install_req_from_editable( + parsed_req.requirement, + comes_from=parsed_req.comes_from, + use_pep517=use_pep517, + constraint=parsed_req.constraint, + isolated=isolated, + ) + + else: + req = install_req_from_line( + parsed_req.requirement, + comes_from=parsed_req.comes_from, + use_pep517=use_pep517, + isolated=isolated, + options=parsed_req.options, + constraint=parsed_req.constraint, + line_source=parsed_req.line_source, + ) + return req diff --git a/venv/lib/python3.8/site-packages/pip/_internal/req/req_file.py b/venv/lib/python3.8/site-packages/pip/_internal/req/req_file.py new file mode 100644 index 0000000..63cab76 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/req/req_file.py @@ -0,0 +1,582 @@ +""" +Requirements file parsing +""" + +# The following comment should be removed at some point in the future. +# mypy: strict-optional=False + +from __future__ import absolute_import + +import optparse +import os +import re +import shlex +import sys + +from pip._vendor.six.moves.urllib import parse as urllib_parse + +from pip._internal.cli import cmdoptions +from pip._internal.exceptions import ( + InstallationError, + RequirementsFileParseError, +) +from pip._internal.models.search_scope import SearchScope +from pip._internal.utils.encoding import auto_decode +from pip._internal.utils.typing import MYPY_CHECK_RUNNING +from pip._internal.utils.urls import get_url_scheme + +if MYPY_CHECK_RUNNING: + from optparse import Values + from typing import ( + Any, Callable, Dict, Iterator, List, NoReturn, Optional, Text, Tuple, + ) + + from pip._internal.index.package_finder import PackageFinder + from pip._internal.network.session import PipSession + + ReqFileLines = Iterator[Tuple[int, Text]] + + LineParser = Callable[[Text], Tuple[str, Values]] + + +__all__ = ['parse_requirements'] + +SCHEME_RE = re.compile(r'^(http|https|file):', re.I) +COMMENT_RE = re.compile(r'(^|\s+)#.*$') + +# Matches environment variable-style values in '${MY_VARIABLE_1}' with the +# variable name consisting of only uppercase letters, digits or the '_' +# (underscore). This follows the POSIX standard defined in IEEE Std 1003.1, +# 2013 Edition. +ENV_VAR_RE = re.compile(r'(?P\$\{(?P[A-Z0-9_]+)\})') + +SUPPORTED_OPTIONS = [ + cmdoptions.index_url, + cmdoptions.extra_index_url, + cmdoptions.no_index, + cmdoptions.constraints, + cmdoptions.requirements, + cmdoptions.editable, + cmdoptions.find_links, + cmdoptions.no_binary, + cmdoptions.only_binary, + cmdoptions.require_hashes, + cmdoptions.pre, + cmdoptions.trusted_host, + cmdoptions.always_unzip, # Deprecated +] # type: List[Callable[..., optparse.Option]] + +# options to be passed to requirements +SUPPORTED_OPTIONS_REQ = [ + cmdoptions.install_options, + cmdoptions.global_options, + cmdoptions.hash, +] # type: List[Callable[..., optparse.Option]] + +# the 'dest' string values +SUPPORTED_OPTIONS_REQ_DEST = [str(o().dest) for o in SUPPORTED_OPTIONS_REQ] + + +class ParsedRequirement(object): + def __init__( + self, + requirement, # type:str + is_editable, # type: bool + comes_from, # type: str + constraint, # type: bool + options=None, # type: Optional[Dict[str, Any]] + line_source=None, # type: Optional[str] + ): + # type: (...) -> None + self.requirement = requirement + self.is_editable = is_editable + self.comes_from = comes_from + self.options = options + self.constraint = constraint + self.line_source = line_source + + +class ParsedLine(object): + def __init__( + self, + filename, # type: str + lineno, # type: int + comes_from, # type: str + args, # type: str + opts, # type: Values + constraint, # type: bool + ): + # type: (...) -> None + self.filename = filename + self.lineno = lineno + self.comes_from = comes_from + self.opts = opts + self.constraint = constraint + + if args: + self.is_requirement = True + self.is_editable = False + self.requirement = args + elif opts.editables: + self.is_requirement = True + self.is_editable = True + # We don't support multiple -e on one line + self.requirement = opts.editables[0] + else: + self.is_requirement = False + + +def parse_requirements( + filename, # type: str + session, # type: PipSession + finder=None, # type: Optional[PackageFinder] + comes_from=None, # type: Optional[str] + options=None, # type: Optional[optparse.Values] + constraint=False, # type: bool +): + # type: (...) -> Iterator[ParsedRequirement] + """Parse a requirements file and yield InstallRequirement instances. + + :param filename: Path or url of requirements file. + :param session: PipSession instance. + :param finder: Instance of pip.index.PackageFinder. + :param comes_from: Origin description of requirements. + :param options: cli options. + :param constraint: If true, parsing a constraint file rather than + requirements file. + """ + line_parser = get_line_parser(finder) + parser = RequirementsFileParser(session, line_parser, comes_from) + + for parsed_line in parser.parse(filename, constraint): + parsed_req = handle_line( + parsed_line, + options=options, + finder=finder, + session=session + ) + if parsed_req is not None: + yield parsed_req + + +def preprocess(content): + # type: (Text) -> ReqFileLines + """Split, filter, and join lines, and return a line iterator + + :param content: the content of the requirements file + """ + lines_enum = enumerate(content.splitlines(), start=1) # type: ReqFileLines + lines_enum = join_lines(lines_enum) + lines_enum = ignore_comments(lines_enum) + lines_enum = expand_env_variables(lines_enum) + return lines_enum + + +def handle_requirement_line( + line, # type: ParsedLine + options=None, # type: Optional[optparse.Values] +): + # type: (...) -> ParsedRequirement + + # preserve for the nested code path + line_comes_from = '{} {} (line {})'.format( + '-c' if line.constraint else '-r', line.filename, line.lineno, + ) + + assert line.is_requirement + + if line.is_editable: + # For editable requirements, we don't support per-requirement + # options, so just return the parsed requirement. + return ParsedRequirement( + requirement=line.requirement, + is_editable=line.is_editable, + comes_from=line_comes_from, + constraint=line.constraint, + ) + else: + if options: + # Disable wheels if the user has specified build options + cmdoptions.check_install_build_global(options, line.opts) + + # get the options that apply to requirements + req_options = {} + for dest in SUPPORTED_OPTIONS_REQ_DEST: + if dest in line.opts.__dict__ and line.opts.__dict__[dest]: + req_options[dest] = line.opts.__dict__[dest] + + line_source = 'line {} of {}'.format(line.lineno, line.filename) + return ParsedRequirement( + requirement=line.requirement, + is_editable=line.is_editable, + comes_from=line_comes_from, + constraint=line.constraint, + options=req_options, + line_source=line_source, + ) + + +def handle_option_line( + opts, # type: Values + filename, # type: str + lineno, # type: int + finder=None, # type: Optional[PackageFinder] + options=None, # type: Optional[optparse.Values] + session=None, # type: Optional[PipSession] +): + # type: (...) -> None + + # percolate hash-checking option upward + if opts.require_hashes: + options.require_hashes = opts.require_hashes + + # set finder options + elif finder: + find_links = finder.find_links + index_urls = finder.index_urls + if opts.index_url: + index_urls = [opts.index_url] + if opts.no_index is True: + index_urls = [] + if opts.extra_index_urls: + index_urls.extend(opts.extra_index_urls) + if opts.find_links: + # FIXME: it would be nice to keep track of the source + # of the find_links: support a find-links local path + # relative to a requirements file. + value = opts.find_links[0] + req_dir = os.path.dirname(os.path.abspath(filename)) + relative_to_reqs_file = os.path.join(req_dir, value) + if os.path.exists(relative_to_reqs_file): + value = relative_to_reqs_file + find_links.append(value) + + search_scope = SearchScope( + find_links=find_links, + index_urls=index_urls, + ) + finder.search_scope = search_scope + + if opts.pre: + finder.set_allow_all_prereleases() + + if session: + for host in opts.trusted_hosts or []: + source = 'line {} of {}'.format(lineno, filename) + session.add_trusted_host(host, source=source) + + +def handle_line( + line, # type: ParsedLine + options=None, # type: Optional[optparse.Values] + finder=None, # type: Optional[PackageFinder] + session=None, # type: Optional[PipSession] +): + # type: (...) -> Optional[ParsedRequirement] + """Handle a single parsed requirements line; This can result in + creating/yielding requirements, or updating the finder. + + :param line: The parsed line to be processed. + :param options: CLI options. + :param finder: The finder - updated by non-requirement lines. + :param session: The session - updated by non-requirement lines. + + Returns a ParsedRequirement object if the line is a requirement line, + otherwise returns None. + + For lines that contain requirements, the only options that have an effect + are from SUPPORTED_OPTIONS_REQ, and they are scoped to the + requirement. Other options from SUPPORTED_OPTIONS may be present, but are + ignored. + + For lines that do not contain requirements, the only options that have an + effect are from SUPPORTED_OPTIONS. Options from SUPPORTED_OPTIONS_REQ may + be present, but are ignored. These lines may contain multiple options + (although our docs imply only one is supported), and all our parsed and + affect the finder. + """ + + if line.is_requirement: + parsed_req = handle_requirement_line(line, options) + return parsed_req + else: + handle_option_line( + line.opts, + line.filename, + line.lineno, + finder, + options, + session, + ) + return None + + +class RequirementsFileParser(object): + def __init__( + self, + session, # type: PipSession + line_parser, # type: LineParser + comes_from, # type: str + ): + # type: (...) -> None + self._session = session + self._line_parser = line_parser + self._comes_from = comes_from + + def parse(self, filename, constraint): + # type: (str, bool) -> Iterator[ParsedLine] + """Parse a given file, yielding parsed lines. + """ + for line in self._parse_and_recurse(filename, constraint): + yield line + + def _parse_and_recurse(self, filename, constraint): + # type: (str, bool) -> Iterator[ParsedLine] + for line in self._parse_file(filename, constraint): + if ( + not line.is_requirement and + (line.opts.requirements or line.opts.constraints) + ): + # parse a nested requirements file + if line.opts.requirements: + req_path = line.opts.requirements[0] + nested_constraint = False + else: + req_path = line.opts.constraints[0] + nested_constraint = True + + # original file is over http + if SCHEME_RE.search(filename): + # do a url join so relative paths work + req_path = urllib_parse.urljoin(filename, req_path) + # original file and nested file are paths + elif not SCHEME_RE.search(req_path): + # do a join so relative paths work + req_path = os.path.join( + os.path.dirname(filename), req_path, + ) + + for inner_line in self._parse_and_recurse( + req_path, nested_constraint, + ): + yield inner_line + else: + yield line + + def _parse_file(self, filename, constraint): + # type: (str, bool) -> Iterator[ParsedLine] + _, content = get_file_content( + filename, self._session, comes_from=self._comes_from + ) + + lines_enum = preprocess(content) + + for line_number, line in lines_enum: + try: + args_str, opts = self._line_parser(line) + except OptionParsingError as e: + # add offending line + msg = 'Invalid requirement: {}\n{}'.format(line, e.msg) + raise RequirementsFileParseError(msg) + + yield ParsedLine( + filename, + line_number, + self._comes_from, + args_str, + opts, + constraint, + ) + + +def get_line_parser(finder): + # type: (Optional[PackageFinder]) -> LineParser + def parse_line(line): + # type: (Text) -> Tuple[str, Values] + # Build new parser for each line since it accumulates appendable + # options. + parser = build_parser() + defaults = parser.get_default_values() + defaults.index_url = None + if finder: + defaults.format_control = finder.format_control + + args_str, options_str = break_args_options(line) + # Prior to 2.7.3, shlex cannot deal with unicode entries + if sys.version_info < (2, 7, 3): + # https://github.com/python/mypy/issues/1174 + options_str = options_str.encode('utf8') # type: ignore + + # https://github.com/python/mypy/issues/1174 + opts, _ = parser.parse_args( + shlex.split(options_str), defaults) # type: ignore + + return args_str, opts + + return parse_line + + +def break_args_options(line): + # type: (Text) -> Tuple[str, Text] + """Break up the line into an args and options string. We only want to shlex + (and then optparse) the options, not the args. args can contain markers + which are corrupted by shlex. + """ + tokens = line.split(' ') + args = [] + options = tokens[:] + for token in tokens: + if token.startswith('-') or token.startswith('--'): + break + else: + args.append(token) + options.pop(0) + return ' '.join(args), ' '.join(options) # type: ignore + + +class OptionParsingError(Exception): + def __init__(self, msg): + # type: (str) -> None + self.msg = msg + + +def build_parser(): + # type: () -> optparse.OptionParser + """ + Return a parser for parsing requirement lines + """ + parser = optparse.OptionParser(add_help_option=False) + + option_factories = SUPPORTED_OPTIONS + SUPPORTED_OPTIONS_REQ + for option_factory in option_factories: + option = option_factory() + parser.add_option(option) + + # By default optparse sys.exits on parsing errors. We want to wrap + # that in our own exception. + def parser_exit(self, msg): + # type: (Any, str) -> NoReturn + raise OptionParsingError(msg) + # NOTE: mypy disallows assigning to a method + # https://github.com/python/mypy/issues/2427 + parser.exit = parser_exit # type: ignore + + return parser + + +def join_lines(lines_enum): + # type: (ReqFileLines) -> ReqFileLines + """Joins a line ending in '\' with the previous line (except when following + comments). The joined line takes on the index of the first line. + """ + primary_line_number = None + new_line = [] # type: List[Text] + for line_number, line in lines_enum: + if not line.endswith('\\') or COMMENT_RE.match(line): + if COMMENT_RE.match(line): + # this ensures comments are always matched later + line = ' ' + line + if new_line: + new_line.append(line) + yield primary_line_number, ''.join(new_line) + new_line = [] + else: + yield line_number, line + else: + if not new_line: + primary_line_number = line_number + new_line.append(line.strip('\\')) + + # last line contains \ + if new_line: + yield primary_line_number, ''.join(new_line) + + # TODO: handle space after '\'. + + +def ignore_comments(lines_enum): + # type: (ReqFileLines) -> ReqFileLines + """ + Strips comments and filter empty lines. + """ + for line_number, line in lines_enum: + line = COMMENT_RE.sub('', line) + line = line.strip() + if line: + yield line_number, line + + +def expand_env_variables(lines_enum): + # type: (ReqFileLines) -> ReqFileLines + """Replace all environment variables that can be retrieved via `os.getenv`. + + The only allowed format for environment variables defined in the + requirement file is `${MY_VARIABLE_1}` to ensure two things: + + 1. Strings that contain a `$` aren't accidentally (partially) expanded. + 2. Ensure consistency across platforms for requirement files. + + These points are the result of a discussion on the `github pull + request #3514 `_. + + Valid characters in variable names follow the `POSIX standard + `_ and are limited + to uppercase letter, digits and the `_` (underscore). + """ + for line_number, line in lines_enum: + for env_var, var_name in ENV_VAR_RE.findall(line): + value = os.getenv(var_name) + if not value: + continue + + line = line.replace(env_var, value) + + yield line_number, line + + +def get_file_content(url, session, comes_from=None): + # type: (str, PipSession, Optional[str]) -> Tuple[str, Text] + """Gets the content of a file; it may be a filename, file: URL, or + http: URL. Returns (location, content). Content is unicode. + Respects # -*- coding: declarations on the retrieved files. + + :param url: File path or url. + :param session: PipSession instance. + :param comes_from: Origin description of requirements. + """ + scheme = get_url_scheme(url) + + if scheme in ['http', 'https']: + # FIXME: catch some errors + resp = session.get(url) + resp.raise_for_status() + return resp.url, resp.text + + elif scheme == 'file': + if comes_from and comes_from.startswith('http'): + raise InstallationError( + 'Requirements file {} references URL {}, ' + 'which is local'.format(comes_from, url) + ) + + path = url.split(':', 1)[1] + path = path.replace('\\', '/') + match = _url_slash_drive_re.match(path) + if match: + path = match.group(1) + ':' + path.split('|', 1)[1] + path = urllib_parse.unquote(path) + if path.startswith('/'): + path = '/' + path.lstrip('/') + url = path + + try: + with open(url, 'rb') as f: + content = auto_decode(f.read()) + except IOError as exc: + raise InstallationError( + 'Could not open requirements file: {}'.format(exc) + ) + return url, content + + +_url_slash_drive_re = re.compile(r'/*([a-z])\|', re.I) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/req/req_install.py b/venv/lib/python3.8/site-packages/pip/_internal/req/req_install.py new file mode 100644 index 0000000..3b28209 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/req/req_install.py @@ -0,0 +1,850 @@ +# The following comment should be removed at some point in the future. +# mypy: strict-optional=False + +from __future__ import absolute_import + +import logging +import os +import shutil +import sys +import zipfile + +from pip._vendor import pkg_resources, six +from pip._vendor.packaging.requirements import Requirement +from pip._vendor.packaging.utils import canonicalize_name +from pip._vendor.packaging.version import Version +from pip._vendor.packaging.version import parse as parse_version +from pip._vendor.pep517.wrappers import Pep517HookCaller + +from pip._internal.build_env import NoOpBuildEnvironment +from pip._internal.exceptions import InstallationError +from pip._internal.locations import get_scheme +from pip._internal.models.link import Link +from pip._internal.operations.build.metadata import generate_metadata +from pip._internal.operations.build.metadata_legacy import \ + generate_metadata as generate_metadata_legacy +from pip._internal.operations.install.editable_legacy import \ + install_editable as install_editable_legacy +from pip._internal.operations.install.legacy import LegacyInstallFailure +from pip._internal.operations.install.legacy import install as install_legacy +from pip._internal.operations.install.wheel import install_wheel +from pip._internal.pyproject import load_pyproject_toml, make_pyproject_path +from pip._internal.req.req_uninstall import UninstallPathSet +from pip._internal.utils.deprecation import deprecated +from pip._internal.utils.direct_url_helpers import direct_url_from_link +from pip._internal.utils.hashes import Hashes +from pip._internal.utils.logging import indent_log +from pip._internal.utils.misc import ( + ask_path_exists, + backup_dir, + display_path, + dist_in_site_packages, + dist_in_usersite, + get_installed_version, + hide_url, + redact_auth_from_url, +) +from pip._internal.utils.packaging import get_metadata +from pip._internal.utils.temp_dir import TempDirectory, tempdir_kinds +from pip._internal.utils.typing import MYPY_CHECK_RUNNING +from pip._internal.utils.virtualenv import running_under_virtualenv +from pip._internal.vcs import vcs + +if MYPY_CHECK_RUNNING: + from typing import ( + Any, Dict, Iterable, List, Optional, Sequence, Union, + ) + from pip._internal.build_env import BuildEnvironment + from pip._vendor.pkg_resources import Distribution + from pip._vendor.packaging.specifiers import SpecifierSet + from pip._vendor.packaging.markers import Marker + + +logger = logging.getLogger(__name__) + + +def _get_dist(metadata_directory): + # type: (str) -> Distribution + """Return a pkg_resources.Distribution for the provided + metadata directory. + """ + dist_dir = metadata_directory.rstrip(os.sep) + + # Build a PathMetadata object, from path to metadata. :wink: + base_dir, dist_dir_name = os.path.split(dist_dir) + metadata = pkg_resources.PathMetadata(base_dir, dist_dir) + + # Determine the correct Distribution object type. + if dist_dir.endswith(".egg-info"): + dist_cls = pkg_resources.Distribution + dist_name = os.path.splitext(dist_dir_name)[0] + else: + assert dist_dir.endswith(".dist-info") + dist_cls = pkg_resources.DistInfoDistribution + dist_name = os.path.splitext(dist_dir_name)[0].split("-")[0] + + return dist_cls( + base_dir, + project_name=dist_name, + metadata=metadata, + ) + + +class InstallRequirement(object): + """ + Represents something that may be installed later on, may have information + about where to fetch the relevant requirement and also contains logic for + installing the said requirement. + """ + + def __init__( + self, + req, # type: Optional[Requirement] + comes_from, # type: Optional[Union[str, InstallRequirement]] + editable=False, # type: bool + link=None, # type: Optional[Link] + markers=None, # type: Optional[Marker] + use_pep517=None, # type: Optional[bool] + isolated=False, # type: bool + install_options=None, # type: Optional[List[str]] + global_options=None, # type: Optional[List[str]] + hash_options=None, # type: Optional[Dict[str, List[str]]] + constraint=False, # type: bool + extras=() # type: Iterable[str] + ): + # type: (...) -> None + assert req is None or isinstance(req, Requirement), req + self.req = req + self.comes_from = comes_from + self.constraint = constraint + self.editable = editable + + # source_dir is the local directory where the linked requirement is + # located, or unpacked. In case unpacking is needed, creating and + # populating source_dir is done by the RequirementPreparer. Note this + # is not necessarily the directory where pyproject.toml or setup.py is + # located - that one is obtained via unpacked_source_directory. + self.source_dir = None # type: Optional[str] + if self.editable: + assert link + if link.is_file: + self.source_dir = os.path.normpath( + os.path.abspath(link.file_path) + ) + + if link is None and req and req.url: + # PEP 508 URL requirement + link = Link(req.url) + self.link = self.original_link = link + self.original_link_is_in_wheel_cache = False + + # Path to any downloaded or already-existing package. + self.local_file_path = None # type: Optional[str] + if self.link and self.link.is_file: + self.local_file_path = self.link.file_path + + if extras: + self.extras = extras + elif req: + self.extras = { + pkg_resources.safe_extra(extra) for extra in req.extras + } + else: + self.extras = set() + if markers is None and req: + markers = req.marker + self.markers = markers + + # This holds the pkg_resources.Distribution object if this requirement + # is already available: + self.satisfied_by = None # type: Optional[Distribution] + # Whether the installation process should try to uninstall an existing + # distribution before installing this requirement. + self.should_reinstall = False + # Temporary build location + self._temp_build_dir = None # type: Optional[TempDirectory] + # Set to True after successful installation + self.install_succeeded = None # type: Optional[bool] + # Supplied options + self.install_options = install_options if install_options else [] + self.global_options = global_options if global_options else [] + self.hash_options = hash_options if hash_options else {} + # Set to True after successful preparation of this requirement + self.prepared = False + self.is_direct = False + + # Set by the legacy resolver when the requirement has been downloaded + # TODO: This introduces a strong coupling between the resolver and the + # requirement (the coupling was previously between the resolver + # and the requirement set). This should be refactored to allow + # the requirement to decide for itself when it has been + # successfully downloaded - but that is more tricky to get right, + # se we are making the change in stages. + self.successfully_downloaded = False + + self.isolated = isolated + self.build_env = NoOpBuildEnvironment() # type: BuildEnvironment + + # For PEP 517, the directory where we request the project metadata + # gets stored. We need this to pass to build_wheel, so the backend + # can ensure that the wheel matches the metadata (see the PEP for + # details). + self.metadata_directory = None # type: Optional[str] + + # The static build requirements (from pyproject.toml) + self.pyproject_requires = None # type: Optional[List[str]] + + # Build requirements that we will check are available + self.requirements_to_check = [] # type: List[str] + + # The PEP 517 backend we should use to build the project + self.pep517_backend = None # type: Optional[Pep517HookCaller] + + # Are we using PEP 517 for this requirement? + # After pyproject.toml has been loaded, the only valid values are True + # and False. Before loading, None is valid (meaning "use the default"). + # Setting an explicit value before loading pyproject.toml is supported, + # but after loading this flag should be treated as read only. + self.use_pep517 = use_pep517 + + def __str__(self): + # type: () -> str + if self.req: + s = str(self.req) + if self.link: + s += ' from {}'.format(redact_auth_from_url(self.link.url)) + elif self.link: + s = redact_auth_from_url(self.link.url) + else: + s = '' + if self.satisfied_by is not None: + s += ' in {}'.format(display_path(self.satisfied_by.location)) + if self.comes_from: + if isinstance(self.comes_from, six.string_types): + comes_from = self.comes_from # type: Optional[str] + else: + comes_from = self.comes_from.from_path() + if comes_from: + s += ' (from {})'.format(comes_from) + return s + + def __repr__(self): + # type: () -> str + return '<{} object: {} editable={!r}>'.format( + self.__class__.__name__, str(self), self.editable) + + def format_debug(self): + # type: () -> str + """An un-tested helper for getting state, for debugging. + """ + attributes = vars(self) + names = sorted(attributes) + + state = ( + "{}={!r}".format(attr, attributes[attr]) for attr in sorted(names) + ) + return '<{name} object: {{{state}}}>'.format( + name=self.__class__.__name__, + state=", ".join(state), + ) + + # Things that are valid for all kinds of requirements? + @property + def name(self): + # type: () -> Optional[str] + if self.req is None: + return None + return six.ensure_str(pkg_resources.safe_name(self.req.name)) + + @property + def specifier(self): + # type: () -> SpecifierSet + return self.req.specifier + + @property + def is_pinned(self): + # type: () -> bool + """Return whether I am pinned to an exact version. + + For example, some-package==1.2 is pinned; some-package>1.2 is not. + """ + specifiers = self.specifier + return (len(specifiers) == 1 and + next(iter(specifiers)).operator in {'==', '==='}) + + @property + def installed_version(self): + # type: () -> Optional[str] + return get_installed_version(self.name) + + def match_markers(self, extras_requested=None): + # type: (Optional[Iterable[str]]) -> bool + if not extras_requested: + # Provide an extra to safely evaluate the markers + # without matching any extra + extras_requested = ('',) + if self.markers is not None: + return any( + self.markers.evaluate({'extra': extra}) + for extra in extras_requested) + else: + return True + + @property + def has_hash_options(self): + # type: () -> bool + """Return whether any known-good hashes are specified as options. + + These activate --require-hashes mode; hashes specified as part of a + URL do not. + + """ + return bool(self.hash_options) + + def hashes(self, trust_internet=True): + # type: (bool) -> Hashes + """Return a hash-comparer that considers my option- and URL-based + hashes to be known-good. + + Hashes in URLs--ones embedded in the requirements file, not ones + downloaded from an index server--are almost peers with ones from + flags. They satisfy --require-hashes (whether it was implicitly or + explicitly activated) but do not activate it. md5 and sha224 are not + allowed in flags, which should nudge people toward good algos. We + always OR all hashes together, even ones from URLs. + + :param trust_internet: Whether to trust URL-based (#md5=...) hashes + downloaded from the internet, as by populate_link() + + """ + good_hashes = self.hash_options.copy() + link = self.link if trust_internet else self.original_link + if link and link.hash: + good_hashes.setdefault(link.hash_name, []).append(link.hash) + return Hashes(good_hashes) + + def from_path(self): + # type: () -> Optional[str] + """Format a nice indicator to show where this "comes from" + """ + if self.req is None: + return None + s = str(self.req) + if self.comes_from: + if isinstance(self.comes_from, six.string_types): + comes_from = self.comes_from + else: + comes_from = self.comes_from.from_path() + if comes_from: + s += '->' + comes_from + return s + + def ensure_build_location(self, build_dir, autodelete): + # type: (str, bool) -> str + assert build_dir is not None + if self._temp_build_dir is not None: + assert self._temp_build_dir.path + return self._temp_build_dir.path + if self.req is None: + # Some systems have /tmp as a symlink which confuses custom + # builds (such as numpy). Thus, we ensure that the real path + # is returned. + self._temp_build_dir = TempDirectory( + kind=tempdir_kinds.REQ_BUILD, globally_managed=True + ) + + return self._temp_build_dir.path + if self.editable: + name = self.name.lower() + else: + name = self.name + # FIXME: Is there a better place to create the build_dir? (hg and bzr + # need this) + if not os.path.exists(build_dir): + logger.debug('Creating directory %s', build_dir) + os.makedirs(build_dir) + actual_build_dir = os.path.join(build_dir, name) + # `None` indicates that we respect the globally-configured deletion + # settings, which is what we actually want when auto-deleting. + delete_arg = None if autodelete else False + return TempDirectory( + path=actual_build_dir, + delete=delete_arg, + kind=tempdir_kinds.REQ_BUILD, + globally_managed=True, + ).path + + def _set_requirement(self): + # type: () -> None + """Set requirement after generating metadata. + """ + assert self.req is None + assert self.metadata is not None + assert self.source_dir is not None + + # Construct a Requirement object from the generated metadata + if isinstance(parse_version(self.metadata["Version"]), Version): + op = "==" + else: + op = "===" + + self.req = Requirement( + "".join([ + self.metadata["Name"], + op, + self.metadata["Version"], + ]) + ) + + def warn_on_mismatching_name(self): + # type: () -> None + metadata_name = canonicalize_name(self.metadata["Name"]) + if canonicalize_name(self.req.name) == metadata_name: + # Everything is fine. + return + + # If we're here, there's a mismatch. Log a warning about it. + logger.warning( + 'Generating metadata for package %s ' + 'produced metadata for project name %s. Fix your ' + '#egg=%s fragments.', + self.name, metadata_name, self.name + ) + self.req = Requirement(metadata_name) + + def check_if_exists(self, use_user_site): + # type: (bool) -> None + """Find an installed distribution that satisfies or conflicts + with this requirement, and set self.satisfied_by or + self.should_reinstall appropriately. + """ + if self.req is None: + return + # get_distribution() will resolve the entire list of requirements + # anyway, and we've already determined that we need the requirement + # in question, so strip the marker so that we don't try to + # evaluate it. + no_marker = Requirement(str(self.req)) + no_marker.marker = None + try: + self.satisfied_by = pkg_resources.get_distribution(str(no_marker)) + except pkg_resources.DistributionNotFound: + return + except pkg_resources.VersionConflict: + existing_dist = pkg_resources.get_distribution( + self.req.name + ) + if use_user_site: + if dist_in_usersite(existing_dist): + self.should_reinstall = True + elif (running_under_virtualenv() and + dist_in_site_packages(existing_dist)): + raise InstallationError( + "Will not install to the user site because it will " + "lack sys.path precedence to {} in {}".format( + existing_dist.project_name, existing_dist.location) + ) + else: + self.should_reinstall = True + else: + if self.editable and self.satisfied_by: + self.should_reinstall = True + # when installing editables, nothing pre-existing should ever + # satisfy + self.satisfied_by = None + + # Things valid for wheels + @property + def is_wheel(self): + # type: () -> bool + if not self.link: + return False + return self.link.is_wheel + + # Things valid for sdists + @property + def unpacked_source_directory(self): + # type: () -> str + return os.path.join( + self.source_dir, + self.link and self.link.subdirectory_fragment or '') + + @property + def setup_py_path(self): + # type: () -> str + assert self.source_dir, "No source dir for {}".format(self) + setup_py = os.path.join(self.unpacked_source_directory, 'setup.py') + + # Python2 __file__ should not be unicode + if six.PY2 and isinstance(setup_py, six.text_type): + setup_py = setup_py.encode(sys.getfilesystemencoding()) + + return setup_py + + @property + def pyproject_toml_path(self): + # type: () -> str + assert self.source_dir, "No source dir for {}".format(self) + return make_pyproject_path(self.unpacked_source_directory) + + def load_pyproject_toml(self): + # type: () -> None + """Load the pyproject.toml file. + + After calling this routine, all of the attributes related to PEP 517 + processing for this requirement have been set. In particular, the + use_pep517 attribute can be used to determine whether we should + follow the PEP 517 or legacy (setup.py) code path. + """ + pyproject_toml_data = load_pyproject_toml( + self.use_pep517, + self.pyproject_toml_path, + self.setup_py_path, + str(self) + ) + + if pyproject_toml_data is None: + self.use_pep517 = False + return + + self.use_pep517 = True + requires, backend, check, backend_path = pyproject_toml_data + self.requirements_to_check = check + self.pyproject_requires = requires + self.pep517_backend = Pep517HookCaller( + self.unpacked_source_directory, backend, backend_path=backend_path, + ) + + def _generate_metadata(self): + # type: () -> str + """Invokes metadata generator functions, with the required arguments. + """ + if not self.use_pep517: + assert self.unpacked_source_directory + + return generate_metadata_legacy( + build_env=self.build_env, + setup_py_path=self.setup_py_path, + source_dir=self.unpacked_source_directory, + isolated=self.isolated, + details=self.name or "from {}".format(self.link) + ) + + assert self.pep517_backend is not None + + return generate_metadata( + build_env=self.build_env, + backend=self.pep517_backend, + ) + + def prepare_metadata(self): + # type: () -> None + """Ensure that project metadata is available. + + Under PEP 517, call the backend hook to prepare the metadata. + Under legacy processing, call setup.py egg-info. + """ + assert self.source_dir + + with indent_log(): + self.metadata_directory = self._generate_metadata() + + # Act on the newly generated metadata, based on the name and version. + if not self.name: + self._set_requirement() + else: + self.warn_on_mismatching_name() + + self.assert_source_matches_version() + + @property + def metadata(self): + # type: () -> Any + if not hasattr(self, '_metadata'): + self._metadata = get_metadata(self.get_dist()) + + return self._metadata + + def get_dist(self): + # type: () -> Distribution + return _get_dist(self.metadata_directory) + + def assert_source_matches_version(self): + # type: () -> None + assert self.source_dir + version = self.metadata['version'] + if self.req.specifier and version not in self.req.specifier: + logger.warning( + 'Requested %s, but installing version %s', + self, + version, + ) + else: + logger.debug( + 'Source in %s has version %s, which satisfies requirement %s', + display_path(self.source_dir), + version, + self, + ) + + # For both source distributions and editables + def ensure_has_source_dir(self, parent_dir, autodelete=False): + # type: (str, bool) -> None + """Ensure that a source_dir is set. + + This will create a temporary build dir if the name of the requirement + isn't known yet. + + :param parent_dir: The ideal pip parent_dir for the source_dir. + Generally src_dir for editables and build_dir for sdists. + :return: self.source_dir + """ + if self.source_dir is None: + self.source_dir = self.ensure_build_location( + parent_dir, autodelete + ) + + # For editable installations + def update_editable(self, obtain=True): + # type: (bool) -> None + if not self.link: + logger.debug( + "Cannot update repository at %s; repository location is " + "unknown", + self.source_dir, + ) + return + assert self.editable + assert self.source_dir + if self.link.scheme == 'file': + # Static paths don't get updated + return + assert '+' in self.link.url, \ + "bad url: {self.link.url!r}".format(**locals()) + vc_type, url = self.link.url.split('+', 1) + vcs_backend = vcs.get_backend(vc_type) + if vcs_backend: + if not self.link.is_vcs: + reason = ( + "This form of VCS requirement is being deprecated: {}." + ).format( + self.link.url + ) + replacement = None + if self.link.url.startswith("git+git@"): + replacement = ( + "git+https://git@example.com/..., " + "git+ssh://git@example.com/..., " + "or the insecure git+git://git@example.com/..." + ) + deprecated(reason, replacement, gone_in="21.0", issue=7554) + hidden_url = hide_url(self.link.url) + if obtain: + vcs_backend.obtain(self.source_dir, url=hidden_url) + else: + vcs_backend.export(self.source_dir, url=hidden_url) + else: + assert 0, ( + 'Unexpected version control type (in {}): {}'.format( + self.link, vc_type)) + + # Top-level Actions + def uninstall(self, auto_confirm=False, verbose=False): + # type: (bool, bool) -> Optional[UninstallPathSet] + """ + Uninstall the distribution currently satisfying this requirement. + + Prompts before removing or modifying files unless + ``auto_confirm`` is True. + + Refuses to delete or modify files outside of ``sys.prefix`` - + thus uninstallation within a virtual environment can only + modify that virtual environment, even if the virtualenv is + linked to global site-packages. + + """ + assert self.req + try: + dist = pkg_resources.get_distribution(self.req.name) + except pkg_resources.DistributionNotFound: + logger.warning("Skipping %s as it is not installed.", self.name) + return None + else: + logger.info('Found existing installation: %s', dist) + + uninstalled_pathset = UninstallPathSet.from_dist(dist) + uninstalled_pathset.remove(auto_confirm, verbose) + return uninstalled_pathset + + def _get_archive_name(self, path, parentdir, rootdir): + # type: (str, str, str) -> str + + def _clean_zip_name(name, prefix): + # type: (str, str) -> str + assert name.startswith(prefix + os.path.sep), ( + "name {name!r} doesn't start with prefix {prefix!r}" + .format(**locals()) + ) + name = name[len(prefix) + 1:] + name = name.replace(os.path.sep, '/') + return name + + path = os.path.join(parentdir, path) + name = _clean_zip_name(path, rootdir) + return self.name + '/' + name + + def archive(self, build_dir): + # type: (str) -> None + """Saves archive to provided build_dir. + + Used for saving downloaded VCS requirements as part of `pip download`. + """ + assert self.source_dir + + create_archive = True + archive_name = '{}-{}.zip'.format(self.name, self.metadata["version"]) + archive_path = os.path.join(build_dir, archive_name) + + if os.path.exists(archive_path): + response = ask_path_exists( + 'The file {} exists. (i)gnore, (w)ipe, ' + '(b)ackup, (a)bort '.format( + display_path(archive_path)), + ('i', 'w', 'b', 'a')) + if response == 'i': + create_archive = False + elif response == 'w': + logger.warning('Deleting %s', display_path(archive_path)) + os.remove(archive_path) + elif response == 'b': + dest_file = backup_dir(archive_path) + logger.warning( + 'Backing up %s to %s', + display_path(archive_path), + display_path(dest_file), + ) + shutil.move(archive_path, dest_file) + elif response == 'a': + sys.exit(-1) + + if not create_archive: + return + + zip_output = zipfile.ZipFile( + archive_path, 'w', zipfile.ZIP_DEFLATED, allowZip64=True, + ) + with zip_output: + dir = os.path.normcase( + os.path.abspath(self.unpacked_source_directory) + ) + for dirpath, dirnames, filenames in os.walk(dir): + for dirname in dirnames: + dir_arcname = self._get_archive_name( + dirname, parentdir=dirpath, rootdir=dir, + ) + zipdir = zipfile.ZipInfo(dir_arcname + '/') + zipdir.external_attr = 0x1ED << 16 # 0o755 + zip_output.writestr(zipdir, '') + for filename in filenames: + file_arcname = self._get_archive_name( + filename, parentdir=dirpath, rootdir=dir, + ) + filename = os.path.join(dirpath, filename) + zip_output.write(filename, file_arcname) + + logger.info('Saved %s', display_path(archive_path)) + + def install( + self, + install_options, # type: List[str] + global_options=None, # type: Optional[Sequence[str]] + root=None, # type: Optional[str] + home=None, # type: Optional[str] + prefix=None, # type: Optional[str] + warn_script_location=True, # type: bool + use_user_site=False, # type: bool + pycompile=True # type: bool + ): + # type: (...) -> None + scheme = get_scheme( + self.name, + user=use_user_site, + home=home, + root=root, + isolated=self.isolated, + prefix=prefix, + ) + + global_options = global_options if global_options is not None else [] + if self.editable: + install_editable_legacy( + install_options, + global_options, + prefix=prefix, + home=home, + use_user_site=use_user_site, + name=self.name, + setup_py_path=self.setup_py_path, + isolated=self.isolated, + build_env=self.build_env, + unpacked_source_directory=self.unpacked_source_directory, + ) + self.install_succeeded = True + return + + if self.is_wheel: + assert self.local_file_path + direct_url = None + if self.original_link: + direct_url = direct_url_from_link( + self.original_link, + self.source_dir, + self.original_link_is_in_wheel_cache, + ) + install_wheel( + self.name, + self.local_file_path, + scheme=scheme, + req_description=str(self.req), + pycompile=pycompile, + warn_script_location=warn_script_location, + direct_url=direct_url, + ) + self.install_succeeded = True + return + + # TODO: Why don't we do this for editable installs? + + # Extend the list of global and install options passed on to + # the setup.py call with the ones from the requirements file. + # Options specified in requirements file override those + # specified on the command line, since the last option given + # to setup.py is the one that is used. + global_options = list(global_options) + self.global_options + install_options = list(install_options) + self.install_options + + try: + success = install_legacy( + install_options=install_options, + global_options=global_options, + root=root, + home=home, + prefix=prefix, + use_user_site=use_user_site, + pycompile=pycompile, + scheme=scheme, + setup_py_path=self.setup_py_path, + isolated=self.isolated, + req_name=self.name, + build_env=self.build_env, + unpacked_source_directory=self.unpacked_source_directory, + req_description=str(self.req), + ) + except LegacyInstallFailure as exc: + self.install_succeeded = False + six.reraise(*exc.parent) + except Exception: + self.install_succeeded = True + raise + + self.install_succeeded = success diff --git a/venv/lib/python3.8/site-packages/pip/_internal/req/req_set.py b/venv/lib/python3.8/site-packages/pip/_internal/req/req_set.py new file mode 100644 index 0000000..f168ce1 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/req/req_set.py @@ -0,0 +1,202 @@ +# The following comment should be removed at some point in the future. +# mypy: strict-optional=False + +from __future__ import absolute_import + +import logging +from collections import OrderedDict + +from pip._vendor.packaging.utils import canonicalize_name + +from pip._internal.exceptions import InstallationError +from pip._internal.models.wheel import Wheel +from pip._internal.utils import compatibility_tags +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Dict, Iterable, List, Optional, Tuple + from pip._internal.req.req_install import InstallRequirement + + +logger = logging.getLogger(__name__) + + +class RequirementSet(object): + + def __init__(self, check_supported_wheels=True): + # type: (bool) -> None + """Create a RequirementSet. + """ + + self.requirements = OrderedDict() # type: Dict[str, InstallRequirement] # noqa: E501 + self.check_supported_wheels = check_supported_wheels + + self.unnamed_requirements = [] # type: List[InstallRequirement] + + def __str__(self): + # type: () -> str + requirements = sorted( + (req for req in self.requirements.values() if not req.comes_from), + key=lambda req: canonicalize_name(req.name), + ) + return ' '.join(str(req.req) for req in requirements) + + def __repr__(self): + # type: () -> str + requirements = sorted( + self.requirements.values(), + key=lambda req: canonicalize_name(req.name), + ) + + format_string = '<{classname} object; {count} requirement(s): {reqs}>' + return format_string.format( + classname=self.__class__.__name__, + count=len(requirements), + reqs=', '.join(str(req.req) for req in requirements), + ) + + def add_unnamed_requirement(self, install_req): + # type: (InstallRequirement) -> None + assert not install_req.name + self.unnamed_requirements.append(install_req) + + def add_named_requirement(self, install_req): + # type: (InstallRequirement) -> None + assert install_req.name + + project_name = canonicalize_name(install_req.name) + self.requirements[project_name] = install_req + + def add_requirement( + self, + install_req, # type: InstallRequirement + parent_req_name=None, # type: Optional[str] + extras_requested=None # type: Optional[Iterable[str]] + ): + # type: (...) -> Tuple[List[InstallRequirement], Optional[InstallRequirement]] # noqa: E501 + """Add install_req as a requirement to install. + + :param parent_req_name: The name of the requirement that needed this + added. The name is used because when multiple unnamed requirements + resolve to the same name, we could otherwise end up with dependency + links that point outside the Requirements set. parent_req must + already be added. Note that None implies that this is a user + supplied requirement, vs an inferred one. + :param extras_requested: an iterable of extras used to evaluate the + environment markers. + :return: Additional requirements to scan. That is either [] if + the requirement is not applicable, or [install_req] if the + requirement is applicable and has just been added. + """ + # If the markers do not match, ignore this requirement. + if not install_req.match_markers(extras_requested): + logger.info( + "Ignoring %s: markers '%s' don't match your environment", + install_req.name, install_req.markers, + ) + return [], None + + # If the wheel is not supported, raise an error. + # Should check this after filtering out based on environment markers to + # allow specifying different wheels based on the environment/OS, in a + # single requirements file. + if install_req.link and install_req.link.is_wheel: + wheel = Wheel(install_req.link.filename) + tags = compatibility_tags.get_supported() + if (self.check_supported_wheels and not wheel.supported(tags)): + raise InstallationError( + "{} is not a supported wheel on this platform.".format( + wheel.filename) + ) + + # This next bit is really a sanity check. + assert install_req.is_direct == (parent_req_name is None), ( + "a direct req shouldn't have a parent and also, " + "a non direct req should have a parent" + ) + + # Unnamed requirements are scanned again and the requirement won't be + # added as a dependency until after scanning. + if not install_req.name: + self.add_unnamed_requirement(install_req) + return [install_req], None + + try: + existing_req = self.get_requirement(install_req.name) + except KeyError: + existing_req = None + + has_conflicting_requirement = ( + parent_req_name is None and + existing_req and + not existing_req.constraint and + existing_req.extras == install_req.extras and + existing_req.req.specifier != install_req.req.specifier + ) + if has_conflicting_requirement: + raise InstallationError( + "Double requirement given: {} (already in {}, name={!r})" + .format(install_req, existing_req, install_req.name) + ) + + # When no existing requirement exists, add the requirement as a + # dependency and it will be scanned again after. + if not existing_req: + self.add_named_requirement(install_req) + # We'd want to rescan this requirement later + return [install_req], install_req + + # Assume there's no need to scan, and that we've already + # encountered this for scanning. + if install_req.constraint or not existing_req.constraint: + return [], existing_req + + does_not_satisfy_constraint = ( + install_req.link and + not ( + existing_req.link and + install_req.link.path == existing_req.link.path + ) + ) + if does_not_satisfy_constraint: + raise InstallationError( + "Could not satisfy constraints for '{}': " + "installation from path or url cannot be " + "constrained to a version".format(install_req.name) + ) + # If we're now installing a constraint, mark the existing + # object for real installation. + existing_req.constraint = False + existing_req.extras = tuple(sorted( + set(existing_req.extras) | set(install_req.extras) + )) + logger.debug( + "Setting %s extras to: %s", + existing_req, existing_req.extras, + ) + # Return the existing requirement for addition to the parent and + # scanning again. + return [existing_req], existing_req + + def has_requirement(self, name): + # type: (str) -> bool + project_name = canonicalize_name(name) + + return ( + project_name in self.requirements and + not self.requirements[project_name].constraint + ) + + def get_requirement(self, name): + # type: (str) -> InstallRequirement + project_name = canonicalize_name(name) + + if project_name in self.requirements: + return self.requirements[project_name] + + raise KeyError("No project with the name {name!r}".format(**locals())) + + @property + def all_requirements(self): + # type: () -> List[InstallRequirement] + return self.unnamed_requirements + list(self.requirements.values()) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/req/req_tracker.py b/venv/lib/python3.8/site-packages/pip/_internal/req/req_tracker.py new file mode 100644 index 0000000..14adeab --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/req/req_tracker.py @@ -0,0 +1,151 @@ +# The following comment should be removed at some point in the future. +# mypy: strict-optional=False + +from __future__ import absolute_import + +import contextlib +import errno +import hashlib +import logging +import os + +from pip._vendor import contextlib2 + +from pip._internal.utils.temp_dir import TempDirectory +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from types import TracebackType + from typing import Dict, Iterator, Optional, Set, Type, Union + from pip._internal.req.req_install import InstallRequirement + from pip._internal.models.link import Link + +logger = logging.getLogger(__name__) + + +@contextlib.contextmanager +def update_env_context_manager(**changes): + # type: (str) -> Iterator[None] + target = os.environ + + # Save values from the target and change them. + non_existent_marker = object() + saved_values = {} # type: Dict[str, Union[object, str]] + for name, new_value in changes.items(): + try: + saved_values[name] = target[name] + except KeyError: + saved_values[name] = non_existent_marker + target[name] = new_value + + try: + yield + finally: + # Restore original values in the target. + for name, original_value in saved_values.items(): + if original_value is non_existent_marker: + del target[name] + else: + assert isinstance(original_value, str) # for mypy + target[name] = original_value + + +@contextlib.contextmanager +def get_requirement_tracker(): + # type: () -> Iterator[RequirementTracker] + root = os.environ.get('PIP_REQ_TRACKER') + with contextlib2.ExitStack() as ctx: + if root is None: + root = ctx.enter_context( + TempDirectory(kind='req-tracker') + ).path + ctx.enter_context(update_env_context_manager(PIP_REQ_TRACKER=root)) + logger.debug("Initialized build tracking at %s", root) + + with RequirementTracker(root) as tracker: + yield tracker + + +class RequirementTracker(object): + + def __init__(self, root): + # type: (str) -> None + self._root = root + self._entries = set() # type: Set[InstallRequirement] + logger.debug("Created build tracker: %s", self._root) + + def __enter__(self): + # type: () -> RequirementTracker + logger.debug("Entered build tracker: %s", self._root) + return self + + def __exit__( + self, + exc_type, # type: Optional[Type[BaseException]] + exc_val, # type: Optional[BaseException] + exc_tb # type: Optional[TracebackType] + ): + # type: (...) -> None + self.cleanup() + + def _entry_path(self, link): + # type: (Link) -> str + hashed = hashlib.sha224(link.url_without_fragment.encode()).hexdigest() + return os.path.join(self._root, hashed) + + def add(self, req): + # type: (InstallRequirement) -> None + """Add an InstallRequirement to build tracking. + """ + + # Get the file to write information about this requirement. + entry_path = self._entry_path(req.link) + + # Try reading from the file. If it exists and can be read from, a build + # is already in progress, so a LookupError is raised. + try: + with open(entry_path) as fp: + contents = fp.read() + except IOError as e: + # if the error is anything other than "file does not exist", raise. + if e.errno != errno.ENOENT: + raise + else: + message = '{} is already being built: {}'.format( + req.link, contents) + raise LookupError(message) + + # If we're here, req should really not be building already. + assert req not in self._entries + + # Start tracking this requirement. + with open(entry_path, 'w') as fp: + fp.write(str(req)) + self._entries.add(req) + + logger.debug('Added %s to build tracker %r', req, self._root) + + def remove(self, req): + # type: (InstallRequirement) -> None + """Remove an InstallRequirement from build tracking. + """ + + # Delete the created file and the corresponding entries. + os.unlink(self._entry_path(req.link)) + self._entries.remove(req) + + logger.debug('Removed %s from build tracker %r', req, self._root) + + def cleanup(self): + # type: () -> None + for req in set(self._entries): + self.remove(req) + + logger.debug("Removed build tracker: %r", self._root) + + @contextlib.contextmanager + def track(self, req): + # type: (InstallRequirement) -> Iterator[None] + self.add(req) + yield + self.remove(req) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/req/req_uninstall.py b/venv/lib/python3.8/site-packages/pip/_internal/req/req_uninstall.py new file mode 100644 index 0000000..559061a --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/req/req_uninstall.py @@ -0,0 +1,649 @@ +from __future__ import absolute_import + +import csv +import functools +import logging +import os +import sys +import sysconfig + +from pip._vendor import pkg_resources + +from pip._internal.exceptions import UninstallationError +from pip._internal.locations import bin_py, bin_user +from pip._internal.utils.compat import WINDOWS, cache_from_source, uses_pycache +from pip._internal.utils.logging import indent_log +from pip._internal.utils.misc import ( + FakeFile, + ask, + dist_in_usersite, + dist_is_local, + egg_link_path, + is_local, + normalize_path, + renames, + rmtree, +) +from pip._internal.utils.temp_dir import AdjacentTempDirectory, TempDirectory +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import ( + Any, Callable, Dict, Iterable, Iterator, List, Optional, Set, Tuple, + ) + from pip._vendor.pkg_resources import Distribution + +logger = logging.getLogger(__name__) + + +def _script_names(dist, script_name, is_gui): + # type: (Distribution, str, bool) -> List[str] + """Create the fully qualified name of the files created by + {console,gui}_scripts for the given ``dist``. + Returns the list of file names + """ + if dist_in_usersite(dist): + bin_dir = bin_user + else: + bin_dir = bin_py + exe_name = os.path.join(bin_dir, script_name) + paths_to_remove = [exe_name] + if WINDOWS: + paths_to_remove.append(exe_name + '.exe') + paths_to_remove.append(exe_name + '.exe.manifest') + if is_gui: + paths_to_remove.append(exe_name + '-script.pyw') + else: + paths_to_remove.append(exe_name + '-script.py') + return paths_to_remove + + +def _unique(fn): + # type: (Callable[..., Iterator[Any]]) -> Callable[..., Iterator[Any]] + @functools.wraps(fn) + def unique(*args, **kw): + # type: (Any, Any) -> Iterator[Any] + seen = set() # type: Set[Any] + for item in fn(*args, **kw): + if item not in seen: + seen.add(item) + yield item + return unique + + +@_unique +def uninstallation_paths(dist): + # type: (Distribution) -> Iterator[str] + """ + Yield all the uninstallation paths for dist based on RECORD-without-.py[co] + + Yield paths to all the files in RECORD. For each .py file in RECORD, add + the .pyc and .pyo in the same directory. + + UninstallPathSet.add() takes care of the __pycache__ .py[co]. + """ + r = csv.reader(FakeFile(dist.get_metadata_lines('RECORD'))) + for row in r: + path = os.path.join(dist.location, row[0]) + yield path + if path.endswith('.py'): + dn, fn = os.path.split(path) + base = fn[:-3] + path = os.path.join(dn, base + '.pyc') + yield path + path = os.path.join(dn, base + '.pyo') + yield path + + +def compact(paths): + # type: (Iterable[str]) -> Set[str] + """Compact a path set to contain the minimal number of paths + necessary to contain all paths in the set. If /a/path/ and + /a/path/to/a/file.txt are both in the set, leave only the + shorter path.""" + + sep = os.path.sep + short_paths = set() # type: Set[str] + for path in sorted(paths, key=len): + should_skip = any( + path.startswith(shortpath.rstrip("*")) and + path[len(shortpath.rstrip("*").rstrip(sep))] == sep + for shortpath in short_paths + ) + if not should_skip: + short_paths.add(path) + return short_paths + + +def compress_for_rename(paths): + # type: (Iterable[str]) -> Set[str] + """Returns a set containing the paths that need to be renamed. + + This set may include directories when the original sequence of paths + included every file on disk. + """ + case_map = dict((os.path.normcase(p), p) for p in paths) + remaining = set(case_map) + unchecked = sorted(set(os.path.split(p)[0] + for p in case_map.values()), key=len) + wildcards = set() # type: Set[str] + + def norm_join(*a): + # type: (str) -> str + return os.path.normcase(os.path.join(*a)) + + for root in unchecked: + if any(os.path.normcase(root).startswith(w) + for w in wildcards): + # This directory has already been handled. + continue + + all_files = set() # type: Set[str] + all_subdirs = set() # type: Set[str] + for dirname, subdirs, files in os.walk(root): + all_subdirs.update(norm_join(root, dirname, d) + for d in subdirs) + all_files.update(norm_join(root, dirname, f) + for f in files) + # If all the files we found are in our remaining set of files to + # remove, then remove them from the latter set and add a wildcard + # for the directory. + if not (all_files - remaining): + remaining.difference_update(all_files) + wildcards.add(root + os.sep) + + return set(map(case_map.__getitem__, remaining)) | wildcards + + +def compress_for_output_listing(paths): + # type: (Iterable[str]) -> Tuple[Set[str], Set[str]] + """Returns a tuple of 2 sets of which paths to display to user + + The first set contains paths that would be deleted. Files of a package + are not added and the top-level directory of the package has a '*' added + at the end - to signify that all it's contents are removed. + + The second set contains files that would have been skipped in the above + folders. + """ + + will_remove = set(paths) + will_skip = set() + + # Determine folders and files + folders = set() + files = set() + for path in will_remove: + if path.endswith(".pyc"): + continue + if path.endswith("__init__.py") or ".dist-info" in path: + folders.add(os.path.dirname(path)) + files.add(path) + + # probably this one https://github.com/python/mypy/issues/390 + _normcased_files = set(map(os.path.normcase, files)) # type: ignore + + folders = compact(folders) + + # This walks the tree using os.walk to not miss extra folders + # that might get added. + for folder in folders: + for dirpath, _, dirfiles in os.walk(folder): + for fname in dirfiles: + if fname.endswith(".pyc"): + continue + + file_ = os.path.join(dirpath, fname) + if (os.path.isfile(file_) and + os.path.normcase(file_) not in _normcased_files): + # We are skipping this file. Add it to the set. + will_skip.add(file_) + + will_remove = files | { + os.path.join(folder, "*") for folder in folders + } + + return will_remove, will_skip + + +class StashedUninstallPathSet(object): + """A set of file rename operations to stash files while + tentatively uninstalling them.""" + def __init__(self): + # type: () -> None + # Mapping from source file root to [Adjacent]TempDirectory + # for files under that directory. + self._save_dirs = {} # type: Dict[str, TempDirectory] + # (old path, new path) tuples for each move that may need + # to be undone. + self._moves = [] # type: List[Tuple[str, str]] + + def _get_directory_stash(self, path): + # type: (str) -> str + """Stashes a directory. + + Directories are stashed adjacent to their original location if + possible, or else moved/copied into the user's temp dir.""" + + try: + save_dir = AdjacentTempDirectory(path) # type: TempDirectory + except OSError: + save_dir = TempDirectory(kind="uninstall") + self._save_dirs[os.path.normcase(path)] = save_dir + + return save_dir.path + + def _get_file_stash(self, path): + # type: (str) -> str + """Stashes a file. + + If no root has been provided, one will be created for the directory + in the user's temp directory.""" + path = os.path.normcase(path) + head, old_head = os.path.dirname(path), None + save_dir = None + + while head != old_head: + try: + save_dir = self._save_dirs[head] + break + except KeyError: + pass + head, old_head = os.path.dirname(head), head + else: + # Did not find any suitable root + head = os.path.dirname(path) + save_dir = TempDirectory(kind='uninstall') + self._save_dirs[head] = save_dir + + relpath = os.path.relpath(path, head) + if relpath and relpath != os.path.curdir: + return os.path.join(save_dir.path, relpath) + return save_dir.path + + def stash(self, path): + # type: (str) -> str + """Stashes the directory or file and returns its new location. + Handle symlinks as files to avoid modifying the symlink targets. + """ + path_is_dir = os.path.isdir(path) and not os.path.islink(path) + if path_is_dir: + new_path = self._get_directory_stash(path) + else: + new_path = self._get_file_stash(path) + + self._moves.append((path, new_path)) + if (path_is_dir and os.path.isdir(new_path)): + # If we're moving a directory, we need to + # remove the destination first or else it will be + # moved to inside the existing directory. + # We just created new_path ourselves, so it will + # be removable. + os.rmdir(new_path) + renames(path, new_path) + return new_path + + def commit(self): + # type: () -> None + """Commits the uninstall by removing stashed files.""" + for _, save_dir in self._save_dirs.items(): + save_dir.cleanup() + self._moves = [] + self._save_dirs = {} + + def rollback(self): + # type: () -> None + """Undoes the uninstall by moving stashed files back.""" + for p in self._moves: + logger.info("Moving to %s\n from %s", *p) + + for new_path, path in self._moves: + try: + logger.debug('Replacing %s from %s', new_path, path) + if os.path.isfile(new_path) or os.path.islink(new_path): + os.unlink(new_path) + elif os.path.isdir(new_path): + rmtree(new_path) + renames(path, new_path) + except OSError as ex: + logger.error("Failed to restore %s", new_path) + logger.debug("Exception: %s", ex) + + self.commit() + + @property + def can_rollback(self): + # type: () -> bool + return bool(self._moves) + + +class UninstallPathSet(object): + """A set of file paths to be removed in the uninstallation of a + requirement.""" + def __init__(self, dist): + # type: (Distribution) -> None + self.paths = set() # type: Set[str] + self._refuse = set() # type: Set[str] + self.pth = {} # type: Dict[str, UninstallPthEntries] + self.dist = dist + self._moved_paths = StashedUninstallPathSet() + + def _permitted(self, path): + # type: (str) -> bool + """ + Return True if the given path is one we are permitted to + remove/modify, False otherwise. + + """ + return is_local(path) + + def add(self, path): + # type: (str) -> None + head, tail = os.path.split(path) + + # we normalize the head to resolve parent directory symlinks, but not + # the tail, since we only want to uninstall symlinks, not their targets + path = os.path.join(normalize_path(head), os.path.normcase(tail)) + + if not os.path.exists(path): + return + if self._permitted(path): + self.paths.add(path) + else: + self._refuse.add(path) + + # __pycache__ files can show up after 'installed-files.txt' is created, + # due to imports + if os.path.splitext(path)[1] == '.py' and uses_pycache: + self.add(cache_from_source(path)) + + def add_pth(self, pth_file, entry): + # type: (str, str) -> None + pth_file = normalize_path(pth_file) + if self._permitted(pth_file): + if pth_file not in self.pth: + self.pth[pth_file] = UninstallPthEntries(pth_file) + self.pth[pth_file].add(entry) + else: + self._refuse.add(pth_file) + + def remove(self, auto_confirm=False, verbose=False): + # type: (bool, bool) -> None + """Remove paths in ``self.paths`` with confirmation (unless + ``auto_confirm`` is True).""" + + if not self.paths: + logger.info( + "Can't uninstall '%s'. No files were found to uninstall.", + self.dist.project_name, + ) + return + + dist_name_version = ( + self.dist.project_name + "-" + self.dist.version + ) + logger.info('Uninstalling %s:', dist_name_version) + + with indent_log(): + if auto_confirm or self._allowed_to_proceed(verbose): + moved = self._moved_paths + + for_rename = compress_for_rename(self.paths) + + for path in sorted(compact(for_rename)): + moved.stash(path) + logger.debug('Removing file or directory %s', path) + + for pth in self.pth.values(): + pth.remove() + + logger.info('Successfully uninstalled %s', dist_name_version) + + def _allowed_to_proceed(self, verbose): + # type: (bool) -> bool + """Display which files would be deleted and prompt for confirmation + """ + + def _display(msg, paths): + # type: (str, Iterable[str]) -> None + if not paths: + return + + logger.info(msg) + with indent_log(): + for path in sorted(compact(paths)): + logger.info(path) + + if not verbose: + will_remove, will_skip = compress_for_output_listing(self.paths) + else: + # In verbose mode, display all the files that are going to be + # deleted. + will_remove = set(self.paths) + will_skip = set() + + _display('Would remove:', will_remove) + _display('Would not remove (might be manually added):', will_skip) + _display('Would not remove (outside of prefix):', self._refuse) + if verbose: + _display('Will actually move:', compress_for_rename(self.paths)) + + return ask('Proceed (y/n)? ', ('y', 'n')) == 'y' + + def rollback(self): + # type: () -> None + """Rollback the changes previously made by remove().""" + if not self._moved_paths.can_rollback: + logger.error( + "Can't roll back %s; was not uninstalled", + self.dist.project_name, + ) + return + logger.info('Rolling back uninstall of %s', self.dist.project_name) + self._moved_paths.rollback() + for pth in self.pth.values(): + pth.rollback() + + def commit(self): + # type: () -> None + """Remove temporary save dir: rollback will no longer be possible.""" + self._moved_paths.commit() + + @classmethod + def from_dist(cls, dist): + # type: (Distribution) -> UninstallPathSet + dist_path = normalize_path(dist.location) + if not dist_is_local(dist): + logger.info( + "Not uninstalling %s at %s, outside environment %s", + dist.key, + dist_path, + sys.prefix, + ) + return cls(dist) + + if dist_path in {p for p in {sysconfig.get_path("stdlib"), + sysconfig.get_path("platstdlib")} + if p}: + logger.info( + "Not uninstalling %s at %s, as it is in the standard library.", + dist.key, + dist_path, + ) + return cls(dist) + + paths_to_remove = cls(dist) + develop_egg_link = egg_link_path(dist) + develop_egg_link_egg_info = '{}.egg-info'.format( + pkg_resources.to_filename(dist.project_name)) + egg_info_exists = dist.egg_info and os.path.exists(dist.egg_info) + # Special case for distutils installed package + distutils_egg_info = getattr(dist._provider, 'path', None) + + # Uninstall cases order do matter as in the case of 2 installs of the + # same package, pip needs to uninstall the currently detected version + if (egg_info_exists and dist.egg_info.endswith('.egg-info') and + not dist.egg_info.endswith(develop_egg_link_egg_info)): + # if dist.egg_info.endswith(develop_egg_link_egg_info), we + # are in fact in the develop_egg_link case + paths_to_remove.add(dist.egg_info) + if dist.has_metadata('installed-files.txt'): + for installed_file in dist.get_metadata( + 'installed-files.txt').splitlines(): + path = os.path.normpath( + os.path.join(dist.egg_info, installed_file) + ) + paths_to_remove.add(path) + # FIXME: need a test for this elif block + # occurs with --single-version-externally-managed/--record outside + # of pip + elif dist.has_metadata('top_level.txt'): + if dist.has_metadata('namespace_packages.txt'): + namespaces = dist.get_metadata('namespace_packages.txt') + else: + namespaces = [] + for top_level_pkg in [ + p for p + in dist.get_metadata('top_level.txt').splitlines() + if p and p not in namespaces]: + path = os.path.join(dist.location, top_level_pkg) + paths_to_remove.add(path) + paths_to_remove.add(path + '.py') + paths_to_remove.add(path + '.pyc') + paths_to_remove.add(path + '.pyo') + + elif distutils_egg_info: + raise UninstallationError( + "Cannot uninstall {!r}. It is a distutils installed project " + "and thus we cannot accurately determine which files belong " + "to it which would lead to only a partial uninstall.".format( + dist.project_name, + ) + ) + + elif dist.location.endswith('.egg'): + # package installed by easy_install + # We cannot match on dist.egg_name because it can slightly vary + # i.e. setuptools-0.6c11-py2.6.egg vs setuptools-0.6rc11-py2.6.egg + paths_to_remove.add(dist.location) + easy_install_egg = os.path.split(dist.location)[1] + easy_install_pth = os.path.join(os.path.dirname(dist.location), + 'easy-install.pth') + paths_to_remove.add_pth(easy_install_pth, './' + easy_install_egg) + + elif egg_info_exists and dist.egg_info.endswith('.dist-info'): + for path in uninstallation_paths(dist): + paths_to_remove.add(path) + + elif develop_egg_link: + # develop egg + with open(develop_egg_link, 'r') as fh: + link_pointer = os.path.normcase(fh.readline().strip()) + assert (link_pointer == dist.location), ( + 'Egg-link {} does not match installed location of {} ' + '(at {})'.format( + link_pointer, dist.project_name, dist.location) + ) + paths_to_remove.add(develop_egg_link) + easy_install_pth = os.path.join(os.path.dirname(develop_egg_link), + 'easy-install.pth') + paths_to_remove.add_pth(easy_install_pth, dist.location) + + else: + logger.debug( + 'Not sure how to uninstall: %s - Check: %s', + dist, dist.location, + ) + + # find distutils scripts= scripts + if dist.has_metadata('scripts') and dist.metadata_isdir('scripts'): + for script in dist.metadata_listdir('scripts'): + if dist_in_usersite(dist): + bin_dir = bin_user + else: + bin_dir = bin_py + paths_to_remove.add(os.path.join(bin_dir, script)) + if WINDOWS: + paths_to_remove.add(os.path.join(bin_dir, script) + '.bat') + + # find console_scripts + _scripts_to_remove = [] + console_scripts = dist.get_entry_map(group='console_scripts') + for name in console_scripts.keys(): + _scripts_to_remove.extend(_script_names(dist, name, False)) + # find gui_scripts + gui_scripts = dist.get_entry_map(group='gui_scripts') + for name in gui_scripts.keys(): + _scripts_to_remove.extend(_script_names(dist, name, True)) + + for s in _scripts_to_remove: + paths_to_remove.add(s) + + return paths_to_remove + + +class UninstallPthEntries(object): + def __init__(self, pth_file): + # type: (str) -> None + self.file = pth_file + self.entries = set() # type: Set[str] + self._saved_lines = None # type: Optional[List[bytes]] + + def add(self, entry): + # type: (str) -> None + entry = os.path.normcase(entry) + # On Windows, os.path.normcase converts the entry to use + # backslashes. This is correct for entries that describe absolute + # paths outside of site-packages, but all the others use forward + # slashes. + # os.path.splitdrive is used instead of os.path.isabs because isabs + # treats non-absolute paths with drive letter markings like c:foo\bar + # as absolute paths. It also does not recognize UNC paths if they don't + # have more than "\\sever\share". Valid examples: "\\server\share\" or + # "\\server\share\folder". Python 2.7.8+ support UNC in splitdrive. + if WINDOWS and not os.path.splitdrive(entry)[0]: + entry = entry.replace('\\', '/') + self.entries.add(entry) + + def remove(self): + # type: () -> None + logger.debug('Removing pth entries from %s:', self.file) + + # If the file doesn't exist, log a warning and return + if not os.path.isfile(self.file): + logger.warning( + "Cannot remove entries from nonexistent file {}".format( + self.file) + ) + return + with open(self.file, 'rb') as fh: + # windows uses '\r\n' with py3k, but uses '\n' with py2.x + lines = fh.readlines() + self._saved_lines = lines + if any(b'\r\n' in line for line in lines): + endline = '\r\n' + else: + endline = '\n' + # handle missing trailing newline + if lines and not lines[-1].endswith(endline.encode("utf-8")): + lines[-1] = lines[-1] + endline.encode("utf-8") + for entry in self.entries: + try: + logger.debug('Removing entry: %s', entry) + lines.remove((entry + endline).encode("utf-8")) + except ValueError: + pass + with open(self.file, 'wb') as fh: + fh.writelines(lines) + + def rollback(self): + # type: () -> bool + if self._saved_lines is None: + logger.error( + 'Cannot roll back changes to %s, none were made', self.file + ) + return False + logger.debug('Rolling %s back to previous state', self.file) + with open(self.file, 'wb') as fh: + fh.writelines(self._saved_lines) + return True diff --git a/venv/lib/python3.8/site-packages/pip/_internal/resolution/__init__.py b/venv/lib/python3.8/site-packages/pip/_internal/resolution/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.8/site-packages/pip/_internal/resolution/base.py b/venv/lib/python3.8/site-packages/pip/_internal/resolution/base.py new file mode 100644 index 0000000..2fa118b --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/resolution/base.py @@ -0,0 +1,20 @@ +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Callable, List + from pip._internal.req.req_install import InstallRequirement + from pip._internal.req.req_set import RequirementSet + + InstallRequirementProvider = Callable[ + [str, InstallRequirement], InstallRequirement + ] + + +class BaseResolver(object): + def resolve(self, root_reqs, check_supported_wheels): + # type: (List[InstallRequirement], bool) -> RequirementSet + raise NotImplementedError() + + def get_installation_order(self, req_set): + # type: (RequirementSet) -> List[InstallRequirement] + raise NotImplementedError() diff --git a/venv/lib/python3.8/site-packages/pip/_internal/resolution/legacy/__init__.py b/venv/lib/python3.8/site-packages/pip/_internal/resolution/legacy/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.8/site-packages/pip/_internal/resolution/legacy/resolver.py b/venv/lib/python3.8/site-packages/pip/_internal/resolution/legacy/resolver.py new file mode 100644 index 0000000..cdb44d1 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/resolution/legacy/resolver.py @@ -0,0 +1,459 @@ +"""Dependency Resolution + +The dependency resolution in pip is performed as follows: + +for top-level requirements: + a. only one spec allowed per project, regardless of conflicts or not. + otherwise a "double requirement" exception is raised + b. they override sub-dependency requirements. +for sub-dependencies + a. "first found, wins" (where the order is breadth first) +""" + +# The following comment should be removed at some point in the future. +# mypy: strict-optional=False +# mypy: disallow-untyped-defs=False + +import logging +import sys +from collections import defaultdict +from itertools import chain + +from pip._vendor.packaging import specifiers + +from pip._internal.exceptions import ( + BestVersionAlreadyInstalled, + DistributionNotFound, + HashError, + HashErrors, + UnsupportedPythonVersion, +) +from pip._internal.req.req_set import RequirementSet +from pip._internal.resolution.base import BaseResolver +from pip._internal.utils.compatibility_tags import get_supported +from pip._internal.utils.logging import indent_log +from pip._internal.utils.misc import dist_in_usersite, normalize_version_info +from pip._internal.utils.packaging import ( + check_requires_python, + get_requires_python, +) +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import DefaultDict, List, Optional, Set, Tuple + from pip._vendor import pkg_resources + + from pip._internal.cache import WheelCache + from pip._internal.distributions import AbstractDistribution + from pip._internal.index.package_finder import PackageFinder + from pip._internal.operations.prepare import RequirementPreparer + from pip._internal.req.req_install import InstallRequirement + from pip._internal.resolution.base import InstallRequirementProvider + + DiscoveredDependencies = DefaultDict[str, List[InstallRequirement]] + +logger = logging.getLogger(__name__) + + +def _check_dist_requires_python( + dist, # type: pkg_resources.Distribution + version_info, # type: Tuple[int, int, int] + ignore_requires_python=False, # type: bool +): + # type: (...) -> None + """ + Check whether the given Python version is compatible with a distribution's + "Requires-Python" value. + + :param version_info: A 3-tuple of ints representing the Python + major-minor-micro version to check. + :param ignore_requires_python: Whether to ignore the "Requires-Python" + value if the given Python version isn't compatible. + + :raises UnsupportedPythonVersion: When the given Python version isn't + compatible. + """ + requires_python = get_requires_python(dist) + try: + is_compatible = check_requires_python( + requires_python, version_info=version_info, + ) + except specifiers.InvalidSpecifier as exc: + logger.warning( + "Package %r has an invalid Requires-Python: %s", + dist.project_name, exc, + ) + return + + if is_compatible: + return + + version = '.'.join(map(str, version_info)) + if ignore_requires_python: + logger.debug( + 'Ignoring failed Requires-Python check for package %r: ' + '%s not in %r', + dist.project_name, version, requires_python, + ) + return + + raise UnsupportedPythonVersion( + 'Package {!r} requires a different Python: {} not in {!r}'.format( + dist.project_name, version, requires_python, + )) + + +class Resolver(BaseResolver): + """Resolves which packages need to be installed/uninstalled to perform \ + the requested operation without breaking the requirements of any package. + """ + + _allowed_strategies = {"eager", "only-if-needed", "to-satisfy-only"} + + def __init__( + self, + preparer, # type: RequirementPreparer + finder, # type: PackageFinder + wheel_cache, # type: Optional[WheelCache] + make_install_req, # type: InstallRequirementProvider + use_user_site, # type: bool + ignore_dependencies, # type: bool + ignore_installed, # type: bool + ignore_requires_python, # type: bool + force_reinstall, # type: bool + upgrade_strategy, # type: str + py_version_info=None, # type: Optional[Tuple[int, ...]] + ): + # type: (...) -> None + super(Resolver, self).__init__() + assert upgrade_strategy in self._allowed_strategies + + if py_version_info is None: + py_version_info = sys.version_info[:3] + else: + py_version_info = normalize_version_info(py_version_info) + + self._py_version_info = py_version_info + + self.preparer = preparer + self.finder = finder + self.wheel_cache = wheel_cache + + self.upgrade_strategy = upgrade_strategy + self.force_reinstall = force_reinstall + self.ignore_dependencies = ignore_dependencies + self.ignore_installed = ignore_installed + self.ignore_requires_python = ignore_requires_python + self.use_user_site = use_user_site + self._make_install_req = make_install_req + + self._discovered_dependencies = \ + defaultdict(list) # type: DiscoveredDependencies + + def resolve(self, root_reqs, check_supported_wheels): + # type: (List[InstallRequirement], bool) -> RequirementSet + """Resolve what operations need to be done + + As a side-effect of this method, the packages (and their dependencies) + are downloaded, unpacked and prepared for installation. This + preparation is done by ``pip.operations.prepare``. + + Once PyPI has static dependency metadata available, it would be + possible to move the preparation to become a step separated from + dependency resolution. + """ + requirement_set = RequirementSet( + check_supported_wheels=check_supported_wheels + ) + for req in root_reqs: + requirement_set.add_requirement(req) + + # Actually prepare the files, and collect any exceptions. Most hash + # exceptions cannot be checked ahead of time, because + # _populate_link() needs to be called before we can make decisions + # based on link type. + discovered_reqs = [] # type: List[InstallRequirement] + hash_errors = HashErrors() + for req in chain(root_reqs, discovered_reqs): + try: + discovered_reqs.extend(self._resolve_one(requirement_set, req)) + except HashError as exc: + exc.req = req + hash_errors.append(exc) + + if hash_errors: + raise hash_errors + + return requirement_set + + def _is_upgrade_allowed(self, req): + # type: (InstallRequirement) -> bool + if self.upgrade_strategy == "to-satisfy-only": + return False + elif self.upgrade_strategy == "eager": + return True + else: + assert self.upgrade_strategy == "only-if-needed" + return req.is_direct + + def _set_req_to_reinstall(self, req): + # type: (InstallRequirement) -> None + """ + Set a requirement to be installed. + """ + # Don't uninstall the conflict if doing a user install and the + # conflict is not a user install. + if not self.use_user_site or dist_in_usersite(req.satisfied_by): + req.should_reinstall = True + req.satisfied_by = None + + def _check_skip_installed(self, req_to_install): + # type: (InstallRequirement) -> Optional[str] + """Check if req_to_install should be skipped. + + This will check if the req is installed, and whether we should upgrade + or reinstall it, taking into account all the relevant user options. + + After calling this req_to_install will only have satisfied_by set to + None if the req_to_install is to be upgraded/reinstalled etc. Any + other value will be a dist recording the current thing installed that + satisfies the requirement. + + Note that for vcs urls and the like we can't assess skipping in this + routine - we simply identify that we need to pull the thing down, + then later on it is pulled down and introspected to assess upgrade/ + reinstalls etc. + + :return: A text reason for why it was skipped, or None. + """ + if self.ignore_installed: + return None + + req_to_install.check_if_exists(self.use_user_site) + if not req_to_install.satisfied_by: + return None + + if self.force_reinstall: + self._set_req_to_reinstall(req_to_install) + return None + + if not self._is_upgrade_allowed(req_to_install): + if self.upgrade_strategy == "only-if-needed": + return 'already satisfied, skipping upgrade' + return 'already satisfied' + + # Check for the possibility of an upgrade. For link-based + # requirements we have to pull the tree down and inspect to assess + # the version #, so it's handled way down. + if not req_to_install.link: + try: + self.finder.find_requirement(req_to_install, upgrade=True) + except BestVersionAlreadyInstalled: + # Then the best version is installed. + return 'already up-to-date' + except DistributionNotFound: + # No distribution found, so we squash the error. It will + # be raised later when we re-try later to do the install. + # Why don't we just raise here? + pass + + self._set_req_to_reinstall(req_to_install) + return None + + def _populate_link(self, req): + # type: (InstallRequirement) -> None + """Ensure that if a link can be found for this, that it is found. + + Note that req.link may still be None - if the requirement is already + installed and not needed to be upgraded based on the return value of + _is_upgrade_allowed(). + + If preparer.require_hashes is True, don't use the wheel cache, because + cached wheels, always built locally, have different hashes than the + files downloaded from the index server and thus throw false hash + mismatches. Furthermore, cached wheels at present have undeterministic + contents due to file modification times. + """ + upgrade = self._is_upgrade_allowed(req) + if req.link is None: + req.link = self.finder.find_requirement(req, upgrade) + + if self.wheel_cache is None or self.preparer.require_hashes: + return + cache_entry = self.wheel_cache.get_cache_entry( + link=req.link, + package_name=req.name, + supported_tags=get_supported(), + ) + if cache_entry is not None: + logger.debug('Using cached wheel link: %s', cache_entry.link) + if req.link is req.original_link and cache_entry.persistent: + req.original_link_is_in_wheel_cache = True + req.link = cache_entry.link + + def _get_abstract_dist_for(self, req): + # type: (InstallRequirement) -> AbstractDistribution + """Takes a InstallRequirement and returns a single AbstractDist \ + representing a prepared variant of the same. + """ + if req.editable: + return self.preparer.prepare_editable_requirement(req) + + # satisfied_by is only evaluated by calling _check_skip_installed, + # so it must be None here. + assert req.satisfied_by is None + skip_reason = self._check_skip_installed(req) + + if req.satisfied_by: + return self.preparer.prepare_installed_requirement( + req, skip_reason + ) + + # We eagerly populate the link, since that's our "legacy" behavior. + self._populate_link(req) + abstract_dist = self.preparer.prepare_linked_requirement(req) + + # NOTE + # The following portion is for determining if a certain package is + # going to be re-installed/upgraded or not and reporting to the user. + # This should probably get cleaned up in a future refactor. + + # req.req is only avail after unpack for URL + # pkgs repeat check_if_exists to uninstall-on-upgrade + # (#14) + if not self.ignore_installed: + req.check_if_exists(self.use_user_site) + + if req.satisfied_by: + should_modify = ( + self.upgrade_strategy != "to-satisfy-only" or + self.force_reinstall or + self.ignore_installed or + req.link.scheme == 'file' + ) + if should_modify: + self._set_req_to_reinstall(req) + else: + logger.info( + 'Requirement already satisfied (use --upgrade to upgrade):' + ' %s', req, + ) + + return abstract_dist + + def _resolve_one( + self, + requirement_set, # type: RequirementSet + req_to_install, # type: InstallRequirement + ): + # type: (...) -> List[InstallRequirement] + """Prepare a single requirements file. + + :return: A list of additional InstallRequirements to also install. + """ + # Tell user what we are doing for this requirement: + # obtain (editable), skipping, processing (local url), collecting + # (remote url or package name) + if req_to_install.constraint or req_to_install.prepared: + return [] + + req_to_install.prepared = True + + abstract_dist = self._get_abstract_dist_for(req_to_install) + + # Parse and return dependencies + dist = abstract_dist.get_pkg_resources_distribution() + # This will raise UnsupportedPythonVersion if the given Python + # version isn't compatible with the distribution's Requires-Python. + _check_dist_requires_python( + dist, version_info=self._py_version_info, + ignore_requires_python=self.ignore_requires_python, + ) + + more_reqs = [] # type: List[InstallRequirement] + + def add_req(subreq, extras_requested): + sub_install_req = self._make_install_req( + str(subreq), + req_to_install, + ) + parent_req_name = req_to_install.name + to_scan_again, add_to_parent = requirement_set.add_requirement( + sub_install_req, + parent_req_name=parent_req_name, + extras_requested=extras_requested, + ) + if parent_req_name and add_to_parent: + self._discovered_dependencies[parent_req_name].append( + add_to_parent + ) + more_reqs.extend(to_scan_again) + + with indent_log(): + # We add req_to_install before its dependencies, so that we + # can refer to it when adding dependencies. + if not requirement_set.has_requirement(req_to_install.name): + # 'unnamed' requirements will get added here + # 'unnamed' requirements can only come from being directly + # provided by the user. + assert req_to_install.is_direct + requirement_set.add_requirement( + req_to_install, parent_req_name=None, + ) + + if not self.ignore_dependencies: + if req_to_install.extras: + logger.debug( + "Installing extra requirements: %r", + ','.join(req_to_install.extras), + ) + missing_requested = sorted( + set(req_to_install.extras) - set(dist.extras) + ) + for missing in missing_requested: + logger.warning( + '%s does not provide the extra \'%s\'', + dist, missing + ) + + available_requested = sorted( + set(dist.extras) & set(req_to_install.extras) + ) + for subreq in dist.requires(available_requested): + add_req(subreq, extras_requested=available_requested) + + if not req_to_install.editable and not req_to_install.satisfied_by: + # XXX: --no-install leads this to report 'Successfully + # downloaded' for only non-editable reqs, even though we took + # action on them. + req_to_install.successfully_downloaded = True + + return more_reqs + + def get_installation_order(self, req_set): + # type: (RequirementSet) -> List[InstallRequirement] + """Create the installation order. + + The installation order is topological - requirements are installed + before the requiring thing. We break cycles at an arbitrary point, + and make no other guarantees. + """ + # The current implementation, which we may change at any point + # installs the user specified things in the order given, except when + # dependencies must come earlier to achieve topological order. + order = [] + ordered_reqs = set() # type: Set[InstallRequirement] + + def schedule(req): + if req.satisfied_by or req in ordered_reqs: + return + if req.constraint: + return + ordered_reqs.add(req) + for dep in self._discovered_dependencies[req.name]: + schedule(dep) + order.append(req) + + for install_req in req_set.requirements.values(): + schedule(install_req) + return order diff --git a/venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/__init__.py b/venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/base.py b/venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/base.py new file mode 100644 index 0000000..5f99618 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/base.py @@ -0,0 +1,52 @@ +from pip._vendor.packaging.utils import canonicalize_name + +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Optional, Sequence, Set + + from pip._internal.req.req_install import InstallRequirement + from pip._vendor.packaging.version import _BaseVersion + + +def format_name(project, extras): + # type: (str, Set[str]) -> str + if not extras: + return project + canonical_extras = sorted(canonicalize_name(e) for e in extras) + return "{}[{}]".format(project, ",".join(canonical_extras)) + + +class Requirement(object): + @property + def name(self): + # type: () -> str + raise NotImplementedError("Subclass should override") + + def find_matches(self): + # type: () -> Sequence[Candidate] + raise NotImplementedError("Subclass should override") + + def is_satisfied_by(self, candidate): + # type: (Candidate) -> bool + return False + + +class Candidate(object): + @property + def name(self): + # type: () -> str + raise NotImplementedError("Override in subclass") + + @property + def version(self): + # type: () -> _BaseVersion + raise NotImplementedError("Override in subclass") + + def get_dependencies(self): + # type: () -> Sequence[Requirement] + raise NotImplementedError("Override in subclass") + + def get_install_requirement(self): + # type: () -> Optional[InstallRequirement] + raise NotImplementedError("Override in subclass") diff --git a/venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/candidates.py b/venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/candidates.py new file mode 100644 index 0000000..f8461ad --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/candidates.py @@ -0,0 +1,450 @@ +import logging +import sys + +from pip._vendor.packaging.specifiers import InvalidSpecifier, SpecifierSet +from pip._vendor.packaging.utils import canonicalize_name +from pip._vendor.packaging.version import Version + +from pip._internal.req.constructors import ( + install_req_from_editable, + install_req_from_line, +) +from pip._internal.req.req_install import InstallRequirement +from pip._internal.utils.misc import normalize_version_info +from pip._internal.utils.packaging import get_requires_python +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +from .base import Candidate, format_name + +if MYPY_CHECK_RUNNING: + from typing import Any, Optional, Sequence, Set, Tuple, Union + + from pip._vendor.packaging.version import _BaseVersion + from pip._vendor.pkg_resources import Distribution + + from pip._internal.distributions import AbstractDistribution + from pip._internal.models.link import Link + + from .base import Requirement + from .factory import Factory + + BaseCandidate = Union[ + "AlreadyInstalledCandidate", + "EditableCandidate", + "LinkCandidate", + ] + + +logger = logging.getLogger(__name__) + + +def make_install_req_from_link(link, parent): + # type: (Link, InstallRequirement) -> InstallRequirement + assert not parent.editable, "parent is editable" + return install_req_from_line( + link.url, + comes_from=parent.comes_from, + use_pep517=parent.use_pep517, + isolated=parent.isolated, + constraint=parent.constraint, + options=dict( + install_options=parent.install_options, + global_options=parent.global_options, + hashes=parent.hash_options + ), + ) + + +def make_install_req_from_editable(link, parent): + # type: (Link, InstallRequirement) -> InstallRequirement + assert parent.editable, "parent not editable" + return install_req_from_editable( + link.url, + comes_from=parent.comes_from, + use_pep517=parent.use_pep517, + isolated=parent.isolated, + constraint=parent.constraint, + options=dict( + install_options=parent.install_options, + global_options=parent.global_options, + hashes=parent.hash_options + ), + ) + + +def make_install_req_from_dist(dist, parent): + # type: (Distribution, InstallRequirement) -> InstallRequirement + ireq = install_req_from_line( + "{}=={}".format( + canonicalize_name(dist.project_name), + dist.parsed_version, + ), + comes_from=parent.comes_from, + use_pep517=parent.use_pep517, + isolated=parent.isolated, + constraint=parent.constraint, + options=dict( + install_options=parent.install_options, + global_options=parent.global_options, + hashes=parent.hash_options + ), + ) + ireq.satisfied_by = dist + return ireq + + +class _InstallRequirementBackedCandidate(Candidate): + def __init__( + self, + link, # type: Link + ireq, # type: InstallRequirement + factory, # type: Factory + name=None, # type: Optional[str] + version=None, # type: Optional[_BaseVersion] + ): + # type: (...) -> None + self.link = link + self._factory = factory + self._ireq = ireq + self._name = name + self._version = version + self._dist = None # type: Optional[Distribution] + + def __repr__(self): + # type: () -> str + return "{class_name}({link!r})".format( + class_name=self.__class__.__name__, + link=str(self.link), + ) + + def __eq__(self, other): + # type: (Any) -> bool + if isinstance(other, self.__class__): + return self.link == other.link + return False + + # Needed for Python 2, which does not implement this by default + def __ne__(self, other): + # type: (Any) -> bool + return not self.__eq__(other) + + @property + def name(self): + # type: () -> str + """The normalised name of the project the candidate refers to""" + if self._name is None: + self._name = canonicalize_name(self.dist.project_name) + return self._name + + @property + def version(self): + # type: () -> _BaseVersion + if self._version is None: + self._version = self.dist.parsed_version + return self._version + + def _prepare_abstract_distribution(self): + # type: () -> AbstractDistribution + raise NotImplementedError("Override in subclass") + + def _prepare(self): + # type: () -> None + if self._dist is not None: + return + + abstract_dist = self._prepare_abstract_distribution() + self._dist = abstract_dist.get_pkg_resources_distribution() + assert self._dist is not None, "Distribution already installed" + + # TODO: Abort cleanly here, as the resolution has been + # based on the wrong name/version until now, and + # so is wrong. + # TODO: (Longer term) Rather than abort, reject this candidate + # and backtrack. This would need resolvelib support. + # These should be "proper" errors, not just asserts, as they + # can result from user errors like a requirement "foo @ URL" + # when the project at URL has a name of "bar" in its metadata. + assert ( + self._name is None or + self._name == canonicalize_name(self._dist.project_name) + ), "Name mismatch: {!r} vs {!r}".format( + self._name, canonicalize_name(self._dist.project_name), + ) + assert ( + self._version is None or + self._version == self._dist.parsed_version + ), "Version mismatch: {!r} vs {!r}".format( + self._version, self._dist.parsed_version, + ) + + @property + def dist(self): + # type: () -> Distribution + self._prepare() + return self._dist + + def _get_requires_python_specifier(self): + # type: () -> Optional[SpecifierSet] + requires_python = get_requires_python(self.dist) + if requires_python is None: + return None + try: + spec = SpecifierSet(requires_python) + except InvalidSpecifier as e: + logger.warning( + "Package %r has an invalid Requires-Python: %s", self.name, e, + ) + return None + return spec + + def get_dependencies(self): + # type: () -> Sequence[Requirement] + deps = [ + self._factory.make_requirement_from_spec(str(r), self._ireq) + for r in self.dist.requires() + ] + python_dep = self._factory.make_requires_python_requirement( + self._get_requires_python_specifier(), + ) + if python_dep: + deps.append(python_dep) + return deps + + def get_install_requirement(self): + # type: () -> Optional[InstallRequirement] + self._prepare() + return self._ireq + + +class LinkCandidate(_InstallRequirementBackedCandidate): + def __init__( + self, + link, # type: Link + parent, # type: InstallRequirement + factory, # type: Factory + name=None, # type: Optional[str] + version=None, # type: Optional[_BaseVersion] + ): + # type: (...) -> None + super(LinkCandidate, self).__init__( + link=link, + ireq=make_install_req_from_link(link, parent), + factory=factory, + name=name, + version=version, + ) + + def _prepare_abstract_distribution(self): + # type: () -> AbstractDistribution + return self._factory.preparer.prepare_linked_requirement(self._ireq) + + +class EditableCandidate(_InstallRequirementBackedCandidate): + def __init__( + self, + link, # type: Link + parent, # type: InstallRequirement + factory, # type: Factory + name=None, # type: Optional[str] + version=None, # type: Optional[_BaseVersion] + ): + # type: (...) -> None + super(EditableCandidate, self).__init__( + link=link, + ireq=make_install_req_from_editable(link, parent), + factory=factory, + name=name, + version=version, + ) + + def _prepare_abstract_distribution(self): + # type: () -> AbstractDistribution + return self._factory.preparer.prepare_editable_requirement(self._ireq) + + +class AlreadyInstalledCandidate(Candidate): + def __init__( + self, + dist, # type: Distribution + parent, # type: InstallRequirement + factory, # type: Factory + ): + # type: (...) -> None + self.dist = dist + self._ireq = make_install_req_from_dist(dist, parent) + self._factory = factory + + # This is just logging some messages, so we can do it eagerly. + # The returned dist would be exactly the same as self.dist because we + # set satisfied_by in make_install_req_from_dist. + # TODO: Supply reason based on force_reinstall and upgrade_strategy. + skip_reason = "already satisfied" + factory.preparer.prepare_installed_requirement(self._ireq, skip_reason) + + def __repr__(self): + # type: () -> str + return "{class_name}({distribution!r})".format( + class_name=self.__class__.__name__, + distribution=self.dist, + ) + + def __eq__(self, other): + # type: (Any) -> bool + if isinstance(other, self.__class__): + return self.name == other.name and self.version == other.version + return False + + # Needed for Python 2, which does not implement this by default + def __ne__(self, other): + # type: (Any) -> bool + return not self.__eq__(other) + + @property + def name(self): + # type: () -> str + return canonicalize_name(self.dist.project_name) + + @property + def version(self): + # type: () -> _BaseVersion + return self.dist.parsed_version + + def get_dependencies(self): + # type: () -> Sequence[Requirement] + return [ + self._factory.make_requirement_from_spec(str(r), self._ireq) + for r in self.dist.requires() + ] + + def get_install_requirement(self): + # type: () -> Optional[InstallRequirement] + return None + + +class ExtrasCandidate(Candidate): + """A candidate that has 'extras', indicating additional dependencies. + + Requirements can be for a project with dependencies, something like + foo[extra]. The extras don't affect the project/version being installed + directly, but indicate that we need additional dependencies. We model that + by having an artificial ExtrasCandidate that wraps the "base" candidate. + + The ExtrasCandidate differs from the base in the following ways: + + 1. It has a unique name, of the form foo[extra]. This causes the resolver + to treat it as a separate node in the dependency graph. + 2. When we're getting the candidate's dependencies, + a) We specify that we want the extra dependencies as well. + b) We add a dependency on the base candidate (matching the name and + version). See below for why this is needed. + 3. We return None for the underlying InstallRequirement, as the base + candidate will provide it, and we don't want to end up with duplicates. + + The dependency on the base candidate is needed so that the resolver can't + decide that it should recommend foo[extra1] version 1.0 and foo[extra2] + version 2.0. Having those candidates depend on foo=1.0 and foo=2.0 + respectively forces the resolver to recognise that this is a conflict. + """ + def __init__( + self, + base, # type: BaseCandidate + extras, # type: Set[str] + ): + # type: (...) -> None + self.base = base + self.extras = extras + + def __repr__(self): + # type: () -> str + return "{class_name}(base={base!r}, extras={extras!r})".format( + class_name=self.__class__.__name__, + base=self.base, + extras=self.extras, + ) + + def __eq__(self, other): + # type: (Any) -> bool + if isinstance(other, self.__class__): + return self.base == other.base and self.extras == other.extras + return False + + # Needed for Python 2, which does not implement this by default + def __ne__(self, other): + # type: (Any) -> bool + return not self.__eq__(other) + + @property + def name(self): + # type: () -> str + """The normalised name of the project the candidate refers to""" + return format_name(self.base.name, self.extras) + + @property + def version(self): + # type: () -> _BaseVersion + return self.base.version + + def get_dependencies(self): + # type: () -> Sequence[Requirement] + factory = self.base._factory + + # The user may have specified extras that the candidate doesn't + # support. We ignore any unsupported extras here. + valid_extras = self.extras.intersection(self.base.dist.extras) + invalid_extras = self.extras.difference(self.base.dist.extras) + if invalid_extras: + logger.warning( + "Invalid extras specified in %s: %s", + self.name, + ','.join(sorted(invalid_extras)) + ) + + deps = [ + factory.make_requirement_from_spec(str(r), self.base._ireq) + for r in self.base.dist.requires(valid_extras) + ] + # Add a dependency on the exact base. + # (See note 2b in the class docstring) + spec = "{}=={}".format(self.base.name, self.base.version) + deps.append(factory.make_requirement_from_spec(spec, self.base._ireq)) + return deps + + def get_install_requirement(self): + # type: () -> Optional[InstallRequirement] + # We don't return anything here, because we always + # depend on the base candidate, and we'll get the + # install requirement from that. + return None + + +class RequiresPythonCandidate(Candidate): + def __init__(self, py_version_info): + # type: (Optional[Tuple[int, ...]]) -> None + if py_version_info is not None: + version_info = normalize_version_info(py_version_info) + else: + version_info = sys.version_info[:3] + self._version = Version(".".join(str(c) for c in version_info)) + + # We don't need to implement __eq__() and __ne__() since there is always + # only one RequiresPythonCandidate in a resolution, i.e. the host Python. + # The built-in object.__eq__() and object.__ne__() do exactly what we want. + + @property + def name(self): + # type: () -> str + # Avoid conflicting with the PyPI package "Python". + return "" + + @property + def version(self): + # type: () -> _BaseVersion + return self._version + + def get_dependencies(self): + # type: () -> Sequence[Requirement] + return [] + + def get_install_requirement(self): + # type: () -> Optional[InstallRequirement] + return None diff --git a/venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/factory.py b/venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/factory.py new file mode 100644 index 0000000..23686f7 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/factory.py @@ -0,0 +1,201 @@ +from pip._vendor.packaging.utils import canonicalize_name + +from pip._internal.exceptions import ( + InstallationError, + UnsupportedPythonVersion, +) +from pip._internal.utils.misc import get_installed_distributions +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +from .candidates import ( + AlreadyInstalledCandidate, + EditableCandidate, + ExtrasCandidate, + LinkCandidate, + RequiresPythonCandidate, +) +from .requirements import ( + ExplicitRequirement, + RequiresPythonRequirement, + SpecifierRequirement, +) + +if MYPY_CHECK_RUNNING: + from typing import Dict, Iterator, Optional, Set, Tuple, TypeVar + + from pip._vendor.packaging.specifiers import SpecifierSet + from pip._vendor.packaging.version import _BaseVersion + from pip._vendor.pkg_resources import Distribution + from pip._vendor.resolvelib import ResolutionImpossible + + from pip._internal.index.package_finder import PackageFinder + from pip._internal.models.link import Link + from pip._internal.operations.prepare import RequirementPreparer + from pip._internal.req.req_install import InstallRequirement + from pip._internal.resolution.base import InstallRequirementProvider + + from .base import Candidate, Requirement + from .candidates import BaseCandidate + + C = TypeVar("C") + Cache = Dict[Link, C] + + +class Factory(object): + def __init__( + self, + finder, # type: PackageFinder + preparer, # type: RequirementPreparer + make_install_req, # type: InstallRequirementProvider + force_reinstall, # type: bool + ignore_installed, # type: bool + ignore_requires_python, # type: bool + py_version_info=None, # type: Optional[Tuple[int, ...]] + ): + # type: (...) -> None + self.finder = finder + self.preparer = preparer + self._python_candidate = RequiresPythonCandidate(py_version_info) + self._make_install_req_from_spec = make_install_req + self._force_reinstall = force_reinstall + self._ignore_requires_python = ignore_requires_python + + self._link_candidate_cache = {} # type: Cache[LinkCandidate] + self._editable_candidate_cache = {} # type: Cache[EditableCandidate] + + if not ignore_installed: + self._installed_dists = { + canonicalize_name(dist.project_name): dist + for dist in get_installed_distributions() + } + else: + self._installed_dists = {} + + def _make_candidate_from_dist( + self, + dist, # type: Distribution + extras, # type: Set[str] + parent, # type: InstallRequirement + ): + # type: (...) -> Candidate + base = AlreadyInstalledCandidate(dist, parent, factory=self) + if extras: + return ExtrasCandidate(base, extras) + return base + + def _make_candidate_from_link( + self, + link, # type: Link + extras, # type: Set[str] + parent, # type: InstallRequirement + name=None, # type: Optional[str] + version=None, # type: Optional[_BaseVersion] + ): + # type: (...) -> Candidate + # TODO: Check already installed candidate, and use it if the link and + # editable flag match. + if parent.editable: + if link not in self._editable_candidate_cache: + self._editable_candidate_cache[link] = EditableCandidate( + link, parent, factory=self, name=name, version=version, + ) + base = self._editable_candidate_cache[link] # type: BaseCandidate + else: + if link not in self._link_candidate_cache: + self._link_candidate_cache[link] = LinkCandidate( + link, parent, factory=self, name=name, version=version, + ) + base = self._link_candidate_cache[link] + if extras: + return ExtrasCandidate(base, extras) + return base + + def iter_found_candidates(self, ireq, extras): + # type: (InstallRequirement, Set[str]) -> Iterator[Candidate] + name = canonicalize_name(ireq.req.name) + if not self._force_reinstall: + installed_dist = self._installed_dists.get(name) + else: + installed_dist = None + + found = self.finder.find_best_candidate( + project_name=ireq.req.name, + specifier=ireq.req.specifier, + hashes=ireq.hashes(trust_internet=False), + ) + for ican in found.iter_applicable(): + if (installed_dist is not None and + installed_dist.parsed_version == ican.version): + continue + yield self._make_candidate_from_link( + link=ican.link, + extras=extras, + parent=ireq, + name=name, + version=ican.version, + ) + + # Return installed distribution if it matches the specifier. This is + # done last so the resolver will prefer it over downloading links. + if (installed_dist is not None and + installed_dist.parsed_version in ireq.req.specifier): + yield self._make_candidate_from_dist( + dist=installed_dist, + extras=extras, + parent=ireq, + ) + + def make_requirement_from_install_req(self, ireq): + # type: (InstallRequirement) -> Requirement + if ireq.link: + # TODO: Get name and version from ireq, if possible? + # Specifically, this might be needed in "name @ URL" + # syntax - need to check where that syntax is handled. + cand = self._make_candidate_from_link( + ireq.link, extras=set(), parent=ireq, + ) + return ExplicitRequirement(cand) + return SpecifierRequirement(ireq, factory=self) + + def make_requirement_from_spec(self, specifier, comes_from): + # type: (str, InstallRequirement) -> Requirement + ireq = self._make_install_req_from_spec(specifier, comes_from) + return self.make_requirement_from_install_req(ireq) + + def make_requires_python_requirement(self, specifier): + # type: (Optional[SpecifierSet]) -> Optional[Requirement] + if self._ignore_requires_python or specifier is None: + return None + return RequiresPythonRequirement(specifier, self._python_candidate) + + def should_reinstall(self, candidate): + # type: (Candidate) -> bool + # TODO: Are there more cases this needs to return True? Editable? + return candidate.name in self._installed_dists + + def _report_requires_python_error( + self, + requirement, # type: RequiresPythonRequirement + parent, # type: Candidate + ): + # type: (...) -> UnsupportedPythonVersion + template = ( + "Package {package!r} requires a different Python: " + "{version} not in {specifier!r}" + ) + message = template.format( + package=parent.name, + version=self._python_candidate.version, + specifier=str(requirement.specifier), + ) + return UnsupportedPythonVersion(message) + + def get_installation_error(self, e): + # type: (ResolutionImpossible) -> Optional[InstallationError] + for cause in e.causes: + if isinstance(cause.requirement, RequiresPythonRequirement): + return self._report_requires_python_error( + cause.requirement, + cause.parent, + ) + return None diff --git a/venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/provider.py b/venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/provider.py new file mode 100644 index 0000000..5c3d210 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/provider.py @@ -0,0 +1,54 @@ +from pip._vendor.resolvelib.providers import AbstractProvider + +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Any, Optional, Sequence, Tuple, Union + + from pip._internal.req.req_install import InstallRequirement + + from .base import Requirement, Candidate + from .factory import Factory + + +class PipProvider(AbstractProvider): + def __init__( + self, + factory, # type: Factory + ignore_dependencies, # type: bool + ): + # type: (...) -> None + self._factory = factory + self._ignore_dependencies = ignore_dependencies + + def get_install_requirement(self, c): + # type: (Candidate) -> Optional[InstallRequirement] + return c.get_install_requirement() + + def identify(self, dependency): + # type: (Union[Requirement, Candidate]) -> str + return dependency.name + + def get_preference( + self, + resolution, # type: Optional[Candidate] + candidates, # type: Sequence[Candidate] + information # type: Sequence[Tuple[Requirement, Candidate]] + ): + # type: (...) -> Any + # Use the "usual" value for now + return len(candidates) + + def find_matches(self, requirement): + # type: (Requirement) -> Sequence[Candidate] + return requirement.find_matches() + + def is_satisfied_by(self, requirement, candidate): + # type: (Requirement, Candidate) -> bool + return requirement.is_satisfied_by(candidate) + + def get_dependencies(self, candidate): + # type: (Candidate) -> Sequence[Requirement] + if self._ignore_dependencies: + return [] + return candidate.get_dependencies() diff --git a/venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/requirements.py b/venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/requirements.py new file mode 100644 index 0000000..d2e4479 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/requirements.py @@ -0,0 +1,119 @@ +from pip._vendor.packaging.utils import canonicalize_name + +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +from .base import Requirement, format_name + +if MYPY_CHECK_RUNNING: + from typing import Sequence + + from pip._vendor.packaging.specifiers import SpecifierSet + + from pip._internal.req.req_install import InstallRequirement + + from .base import Candidate + from .factory import Factory + + +class ExplicitRequirement(Requirement): + def __init__(self, candidate): + # type: (Candidate) -> None + self.candidate = candidate + + def __repr__(self): + # type: () -> str + return "{class_name}({candidate!r})".format( + class_name=self.__class__.__name__, + candidate=self.candidate, + ) + + @property + def name(self): + # type: () -> str + # No need to canonicalise - the candidate did this + return self.candidate.name + + def find_matches(self): + # type: () -> Sequence[Candidate] + return [self.candidate] + + def is_satisfied_by(self, candidate): + # type: (Candidate) -> bool + return candidate == self.candidate + + +class SpecifierRequirement(Requirement): + def __init__(self, ireq, factory): + # type: (InstallRequirement, Factory) -> None + assert ireq.link is None, "This is a link, not a specifier" + self._ireq = ireq + self._factory = factory + self.extras = ireq.req.extras + + def __str__(self): + # type: () -> str + return str(self._ireq.req) + + def __repr__(self): + # type: () -> str + return "{class_name}({requirement!r})".format( + class_name=self.__class__.__name__, + requirement=str(self._ireq.req), + ) + + @property + def name(self): + # type: () -> str + canonical_name = canonicalize_name(self._ireq.req.name) + return format_name(canonical_name, self.extras) + + def find_matches(self): + # type: () -> Sequence[Candidate] + it = self._factory.iter_found_candidates(self._ireq, self.extras) + return list(it) + + def is_satisfied_by(self, candidate): + # type: (Candidate) -> bool + assert candidate.name == self.name, \ + "Internal issue: Candidate is not for this requirement " \ + " {} vs {}".format(candidate.name, self.name) + # We can safely always allow prereleases here since PackageFinder + # already implements the prerelease logic, and would have filtered out + # prerelease candidates if the user does not expect them. + spec = self._ireq.req.specifier + return spec.contains(candidate.version, prereleases=True) + + +class RequiresPythonRequirement(Requirement): + """A requirement representing Requires-Python metadata. + """ + def __init__(self, specifier, match): + # type: (SpecifierSet, Candidate) -> None + self.specifier = specifier + self._candidate = match + + def __repr__(self): + # type: () -> str + return "{class_name}({specifier!r})".format( + class_name=self.__class__.__name__, + specifier=str(self.specifier), + ) + + @property + def name(self): + # type: () -> str + return self._candidate.name + + def find_matches(self): + # type: () -> Sequence[Candidate] + if self._candidate.version in self.specifier: + return [self._candidate] + return [] + + def is_satisfied_by(self, candidate): + # type: (Candidate) -> bool + assert candidate.name == self._candidate.name, "Not Python candidate" + # We can safely always allow prereleases here since PackageFinder + # already implements the prerelease logic, and would have filtered out + # prerelease candidates if the user does not expect them. + return self.specifier.contains(candidate.version, prereleases=True) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/resolver.py b/venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/resolver.py new file mode 100644 index 0000000..cba5a49 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/resolver.py @@ -0,0 +1,174 @@ +import functools +import logging + +from pip._vendor import six +from pip._vendor.packaging.utils import canonicalize_name +from pip._vendor.resolvelib import BaseReporter, ResolutionImpossible +from pip._vendor.resolvelib import Resolver as RLResolver + +from pip._internal.exceptions import InstallationError +from pip._internal.req.req_set import RequirementSet +from pip._internal.resolution.base import BaseResolver +from pip._internal.resolution.resolvelib.provider import PipProvider +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +from .factory import Factory + +if MYPY_CHECK_RUNNING: + from typing import Dict, List, Optional, Tuple + + from pip._vendor.resolvelib.resolvers import Result + + from pip._internal.cache import WheelCache + from pip._internal.index.package_finder import PackageFinder + from pip._internal.operations.prepare import RequirementPreparer + from pip._internal.req.req_install import InstallRequirement + from pip._internal.resolution.base import InstallRequirementProvider + + +logger = logging.getLogger(__name__) + + +class Resolver(BaseResolver): + def __init__( + self, + preparer, # type: RequirementPreparer + finder, # type: PackageFinder + wheel_cache, # type: Optional[WheelCache] + make_install_req, # type: InstallRequirementProvider + use_user_site, # type: bool + ignore_dependencies, # type: bool + ignore_installed, # type: bool + ignore_requires_python, # type: bool + force_reinstall, # type: bool + upgrade_strategy, # type: str + py_version_info=None, # type: Optional[Tuple[int, ...]] + ): + super(Resolver, self).__init__() + self.factory = Factory( + finder=finder, + preparer=preparer, + make_install_req=make_install_req, + force_reinstall=force_reinstall, + ignore_installed=ignore_installed, + ignore_requires_python=ignore_requires_python, + py_version_info=py_version_info, + ) + self.ignore_dependencies = ignore_dependencies + self._result = None # type: Optional[Result] + + def resolve(self, root_reqs, check_supported_wheels): + # type: (List[InstallRequirement], bool) -> RequirementSet + + # FIXME: Implement constraints. + if any(r.constraint for r in root_reqs): + raise InstallationError("Constraints are not yet supported.") + + provider = PipProvider( + factory=self.factory, + ignore_dependencies=self.ignore_dependencies, + ) + reporter = BaseReporter() + resolver = RLResolver(provider, reporter) + + requirements = [ + self.factory.make_requirement_from_install_req(r) + for r in root_reqs + ] + + try: + self._result = resolver.resolve(requirements) + + except ResolutionImpossible as e: + error = self.factory.get_installation_error(e) + if not error: + # TODO: This needs fixing, we need to look at the + # factory.get_installation_error infrastructure, as that + # doesn't really allow for the logger.critical calls I'm + # using here. + for req, parent in e.causes: + logger.critical( + "Could not find a version that satisfies " + + "the requirement " + + str(req) + + ("" if parent is None else " (from {})".format( + parent.name + )) + ) + raise InstallationError( + "No matching distribution found for " + + ", ".join([r.name for r, _ in e.causes]) + ) + raise + six.raise_from(error, e) + + req_set = RequirementSet(check_supported_wheels=check_supported_wheels) + for candidate in self._result.mapping.values(): + ireq = provider.get_install_requirement(candidate) + if ireq is None: + continue + ireq.should_reinstall = self.factory.should_reinstall(candidate) + req_set.add_named_requirement(ireq) + + return req_set + + def get_installation_order(self, req_set): + # type: (RequirementSet) -> List[InstallRequirement] + """Create a list that orders given requirements for installation. + + The returned list should contain all requirements in ``req_set``, + so the caller can loop through it and have a requirement installed + before the requiring thing. + + The current implementation walks the resolved dependency graph, and + make sure every node has a greater "weight" than all its parents. + """ + assert self._result is not None, "must call resolve() first" + weights = {} # type: Dict[Optional[str], int] + + graph = self._result.graph + key_count = len(self._result.mapping) + 1 # Packages plus sentinal. + while len(weights) < key_count: + progressed = False + for key in graph: + if key in weights: + continue + parents = list(graph.iter_parents(key)) + if not all(p in weights for p in parents): + continue + if parents: + weight = max(weights[p] for p in parents) + 1 + else: + weight = 0 + weights[key] = weight + progressed = True + + # FIXME: This check will fail if there are unbreakable cycles. + # Implement something to forcifully break them up to continue. + if not progressed: + raise InstallationError( + "Could not determine installation order due to cicular " + "dependency." + ) + + sorted_items = sorted( + req_set.requirements.items(), + key=functools.partial(_req_set_item_sorter, weights=weights), + reverse=True, + ) + return [ireq for _, ireq in sorted_items] + + +def _req_set_item_sorter( + item, # type: Tuple[str, InstallRequirement] + weights, # type: Dict[Optional[str], int] +): + # type: (...) -> Tuple[int, str] + """Key function used to sort install requirements for installation. + + Based on the "weight" mapping calculated in ``get_installation_order()``. + The canonical package name is returned as the second member as a tie- + breaker to ensure the result is predictable, which is useful in tests. + """ + name = canonicalize_name(item[0]) + return weights[name], name diff --git a/venv/lib/python3.8/site-packages/pip/_internal/self_outdated_check.py b/venv/lib/python3.8/site-packages/pip/_internal/self_outdated_check.py new file mode 100644 index 0000000..8fc3c59 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/self_outdated_check.py @@ -0,0 +1,242 @@ +# The following comment should be removed at some point in the future. +# mypy: disallow-untyped-defs=False + +from __future__ import absolute_import + +import datetime +import hashlib +import json +import logging +import os.path +import sys + +from pip._vendor import pkg_resources +from pip._vendor.packaging import version as packaging_version +from pip._vendor.six import ensure_binary + +from pip._internal.index.collector import LinkCollector +from pip._internal.index.package_finder import PackageFinder +from pip._internal.models.search_scope import SearchScope +from pip._internal.models.selection_prefs import SelectionPreferences +from pip._internal.utils.filesystem import ( + adjacent_tmp_file, + check_path_owner, + replace, +) +from pip._internal.utils.misc import ( + ensure_dir, + get_installed_version, + redact_auth_from_url, +) +from pip._internal.utils.packaging import get_installer +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + import optparse + from optparse import Values + from typing import Any, Dict, Text, Union + + from pip._internal.network.session import PipSession + + +SELFCHECK_DATE_FMT = "%Y-%m-%dT%H:%M:%SZ" + + +logger = logging.getLogger(__name__) + + +def make_link_collector( + session, # type: PipSession + options, # type: Values + suppress_no_index=False, # type: bool +): + # type: (...) -> LinkCollector + """ + :param session: The Session to use to make requests. + :param suppress_no_index: Whether to ignore the --no-index option + when constructing the SearchScope object. + """ + index_urls = [options.index_url] + options.extra_index_urls + if options.no_index and not suppress_no_index: + logger.debug( + 'Ignoring indexes: %s', + ','.join(redact_auth_from_url(url) for url in index_urls), + ) + index_urls = [] + + # Make sure find_links is a list before passing to create(). + find_links = options.find_links or [] + + search_scope = SearchScope.create( + find_links=find_links, index_urls=index_urls, + ) + + link_collector = LinkCollector(session=session, search_scope=search_scope) + + return link_collector + + +def _get_statefile_name(key): + # type: (Union[str, Text]) -> str + key_bytes = ensure_binary(key) + name = hashlib.sha224(key_bytes).hexdigest() + return name + + +class SelfCheckState(object): + def __init__(self, cache_dir): + # type: (str) -> None + self.state = {} # type: Dict[str, Any] + self.statefile_path = None + + # Try to load the existing state + if cache_dir: + self.statefile_path = os.path.join( + cache_dir, "selfcheck", _get_statefile_name(self.key) + ) + try: + with open(self.statefile_path) as statefile: + self.state = json.load(statefile) + except (IOError, ValueError, KeyError): + # Explicitly suppressing exceptions, since we don't want to + # error out if the cache file is invalid. + pass + + @property + def key(self): + return sys.prefix + + def save(self, pypi_version, current_time): + # type: (str, datetime.datetime) -> None + # If we do not have a path to cache in, don't bother saving. + if not self.statefile_path: + return + + # Check to make sure that we own the directory + if not check_path_owner(os.path.dirname(self.statefile_path)): + return + + # Now that we've ensured the directory is owned by this user, we'll go + # ahead and make sure that all our directories are created. + ensure_dir(os.path.dirname(self.statefile_path)) + + state = { + # Include the key so it's easy to tell which pip wrote the + # file. + "key": self.key, + "last_check": current_time.strftime(SELFCHECK_DATE_FMT), + "pypi_version": pypi_version, + } + + text = json.dumps(state, sort_keys=True, separators=(",", ":")) + + with adjacent_tmp_file(self.statefile_path) as f: + f.write(ensure_binary(text)) + + try: + # Since we have a prefix-specific state file, we can just + # overwrite whatever is there, no need to check. + replace(f.name, self.statefile_path) + except OSError: + # Best effort. + pass + + +def was_installed_by_pip(pkg): + # type: (str) -> bool + """Checks whether pkg was installed by pip + + This is used not to display the upgrade message when pip is in fact + installed by system package manager, such as dnf on Fedora. + """ + try: + dist = pkg_resources.get_distribution(pkg) + return "pip" == get_installer(dist) + except pkg_resources.DistributionNotFound: + return False + + +def pip_self_version_check(session, options): + # type: (PipSession, optparse.Values) -> None + """Check for an update for pip. + + Limit the frequency of checks to once per week. State is stored either in + the active virtualenv or in the user's USER_CACHE_DIR keyed off the prefix + of the pip script path. + """ + installed_version = get_installed_version("pip") + if not installed_version: + return + + pip_version = packaging_version.parse(installed_version) + pypi_version = None + + try: + state = SelfCheckState(cache_dir=options.cache_dir) + + current_time = datetime.datetime.utcnow() + # Determine if we need to refresh the state + if "last_check" in state.state and "pypi_version" in state.state: + last_check = datetime.datetime.strptime( + state.state["last_check"], + SELFCHECK_DATE_FMT + ) + if (current_time - last_check).total_seconds() < 7 * 24 * 60 * 60: + pypi_version = state.state["pypi_version"] + + # Refresh the version if we need to or just see if we need to warn + if pypi_version is None: + # Lets use PackageFinder to see what the latest pip version is + link_collector = make_link_collector( + session, + options=options, + suppress_no_index=True, + ) + + # Pass allow_yanked=False so we don't suggest upgrading to a + # yanked version. + selection_prefs = SelectionPreferences( + allow_yanked=False, + allow_all_prereleases=False, # Explicitly set to False + ) + + finder = PackageFinder.create( + link_collector=link_collector, + selection_prefs=selection_prefs, + ) + best_candidate = finder.find_best_candidate("pip").best_candidate + if best_candidate is None: + return + pypi_version = str(best_candidate.version) + + # save that we've performed a check + state.save(pypi_version, current_time) + + remote_version = packaging_version.parse(pypi_version) + + local_version_is_older = ( + pip_version < remote_version and + pip_version.base_version != remote_version.base_version and + was_installed_by_pip('pip') + ) + + # Determine if our pypi_version is older + if not local_version_is_older: + return + + # We cannot tell how the current pip is available in the current + # command context, so be pragmatic here and suggest the command + # that's always available. This does not accommodate spaces in + # `sys.executable`. + pip_cmd = "{} -m pip".format(sys.executable) + logger.warning( + "You are using pip version %s; however, version %s is " + "available.\nYou should consider upgrading via the " + "'%s install --upgrade pip' command.", + pip_version, pypi_version, pip_cmd + ) + except Exception: + logger.debug( + "There was an error checking the latest version of pip", + exc_info=True, + ) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/__init__.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/appdirs.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/appdirs.py new file mode 100644 index 0000000..3989ed3 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/utils/appdirs.py @@ -0,0 +1,44 @@ +""" +This code wraps the vendored appdirs module to so the return values are +compatible for the current pip code base. + +The intention is to rewrite current usages gradually, keeping the tests pass, +and eventually drop this after all usages are changed. +""" + +from __future__ import absolute_import + +import os + +from pip._vendor import appdirs as _appdirs + +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import List + + +def user_cache_dir(appname): + # type: (str) -> str + return _appdirs.user_cache_dir(appname, appauthor=False) + + +def user_config_dir(appname, roaming=True): + # type: (str, bool) -> str + path = _appdirs.user_config_dir(appname, appauthor=False, roaming=roaming) + if _appdirs.system == "darwin" and not os.path.isdir(path): + path = os.path.expanduser('~/.config/') + if appname: + path = os.path.join(path, appname) + return path + + +# for the discussion regarding site_config_dir locations +# see +def site_config_dirs(appname): + # type: (str) -> List[str] + dirval = _appdirs.site_config_dir(appname, appauthor=False, multipath=True) + if _appdirs.system not in ["win32", "darwin"]: + # always look in /etc directly as well + return dirval.split(os.pathsep) + ['/etc'] + return [dirval] diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/compat.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/compat.py new file mode 100644 index 0000000..d939e21 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/utils/compat.py @@ -0,0 +1,270 @@ +"""Stuff that differs in different Python versions and platform +distributions.""" + +# The following comment should be removed at some point in the future. +# mypy: disallow-untyped-defs=False + +from __future__ import absolute_import, division + +import codecs +import locale +import logging +import os +import shutil +import sys + +from pip._vendor.six import PY2, text_type + +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Optional, Text, Tuple, Union + +try: + import ipaddress +except ImportError: + try: + from pip._vendor import ipaddress # type: ignore + except ImportError: + import ipaddr as ipaddress # type: ignore + ipaddress.ip_address = ipaddress.IPAddress # type: ignore + ipaddress.ip_network = ipaddress.IPNetwork # type: ignore + + +__all__ = [ + "ipaddress", "uses_pycache", "console_to_str", + "get_path_uid", "stdlib_pkgs", "WINDOWS", "samefile", "get_terminal_size", +] + + +logger = logging.getLogger(__name__) + +if PY2: + import imp + + try: + cache_from_source = imp.cache_from_source # type: ignore + except AttributeError: + # does not use __pycache__ + cache_from_source = None + + uses_pycache = cache_from_source is not None +else: + uses_pycache = True + from importlib.util import cache_from_source + + +if PY2: + # In Python 2.7, backslashreplace exists + # but does not support use for decoding. + # We implement our own replace handler for this + # situation, so that we can consistently use + # backslash replacement for all versions. + def backslashreplace_decode_fn(err): + raw_bytes = (err.object[i] for i in range(err.start, err.end)) + # Python 2 gave us characters - convert to numeric bytes + raw_bytes = (ord(b) for b in raw_bytes) + return u"".join(map(u"\\x{:x}".format, raw_bytes)), err.end + codecs.register_error( + "backslashreplace_decode", + backslashreplace_decode_fn, + ) + backslashreplace_decode = "backslashreplace_decode" +else: + backslashreplace_decode = "backslashreplace" + + +def has_tls(): + # type: () -> bool + try: + import _ssl # noqa: F401 # ignore unused + return True + except ImportError: + pass + + from pip._vendor.urllib3.util import IS_PYOPENSSL + return IS_PYOPENSSL + + +def str_to_display(data, desc=None): + # type: (Union[bytes, Text], Optional[str]) -> Text + """ + For display or logging purposes, convert a bytes object (or text) to + text (e.g. unicode in Python 2) safe for output. + + :param desc: An optional phrase describing the input data, for use in + the log message if a warning is logged. Defaults to "Bytes object". + + This function should never error out and so can take a best effort + approach. It is okay to be lossy if needed since the return value is + just for display. + + We assume the data is in the locale preferred encoding. If it won't + decode properly, we warn the user but decode as best we can. + + We also ensure that the output can be safely written to standard output + without encoding errors. + """ + if isinstance(data, text_type): + return data + + # Otherwise, data is a bytes object (str in Python 2). + # First, get the encoding we assume. This is the preferred + # encoding for the locale, unless that is not found, or + # it is ASCII, in which case assume UTF-8 + encoding = locale.getpreferredencoding() + if (not encoding) or codecs.lookup(encoding).name == "ascii": + encoding = "utf-8" + + # Now try to decode the data - if we fail, warn the user and + # decode with replacement. + try: + decoded_data = data.decode(encoding) + except UnicodeDecodeError: + if desc is None: + desc = 'Bytes object' + msg_format = '{} does not appear to be encoded as %s'.format(desc) + logger.warning(msg_format, encoding) + decoded_data = data.decode(encoding, errors=backslashreplace_decode) + + # Make sure we can print the output, by encoding it to the output + # encoding with replacement of unencodable characters, and then + # decoding again. + # We use stderr's encoding because it's less likely to be + # redirected and if we don't find an encoding we skip this + # step (on the assumption that output is wrapped by something + # that won't fail). + # The double getattr is to deal with the possibility that we're + # being called in a situation where sys.__stderr__ doesn't exist, + # or doesn't have an encoding attribute. Neither of these cases + # should occur in normal pip use, but there's no harm in checking + # in case people use pip in (unsupported) unusual situations. + output_encoding = getattr(getattr(sys, "__stderr__", None), + "encoding", None) + + if output_encoding: + output_encoded = decoded_data.encode( + output_encoding, + errors="backslashreplace" + ) + decoded_data = output_encoded.decode(output_encoding) + + return decoded_data + + +def console_to_str(data): + # type: (bytes) -> Text + """Return a string, safe for output, of subprocess output. + """ + return str_to_display(data, desc='Subprocess output') + + +def get_path_uid(path): + # type: (str) -> int + """ + Return path's uid. + + Does not follow symlinks: + https://github.com/pypa/pip/pull/935#discussion_r5307003 + + Placed this function in compat due to differences on AIX and + Jython, that should eventually go away. + + :raises OSError: When path is a symlink or can't be read. + """ + if hasattr(os, 'O_NOFOLLOW'): + fd = os.open(path, os.O_RDONLY | os.O_NOFOLLOW) + file_uid = os.fstat(fd).st_uid + os.close(fd) + else: # AIX and Jython + # WARNING: time of check vulnerability, but best we can do w/o NOFOLLOW + if not os.path.islink(path): + # older versions of Jython don't have `os.fstat` + file_uid = os.stat(path).st_uid + else: + # raise OSError for parity with os.O_NOFOLLOW above + raise OSError( + "{} is a symlink; Will not return uid for symlinks".format( + path) + ) + return file_uid + + +def expanduser(path): + # type: (str) -> str + """ + Expand ~ and ~user constructions. + + Includes a workaround for https://bugs.python.org/issue14768 + """ + expanded = os.path.expanduser(path) + if path.startswith('~/') and expanded.startswith('//'): + expanded = expanded[1:] + return expanded + + +# packages in the stdlib that may have installation metadata, but should not be +# considered 'installed'. this theoretically could be determined based on +# dist.location (py27:`sysconfig.get_paths()['stdlib']`, +# py26:sysconfig.get_config_vars('LIBDEST')), but fear platform variation may +# make this ineffective, so hard-coding +stdlib_pkgs = {"python", "wsgiref", "argparse"} + + +# windows detection, covers cpython and ironpython +WINDOWS = (sys.platform.startswith("win") or + (sys.platform == 'cli' and os.name == 'nt')) + + +def samefile(file1, file2): + # type: (str, str) -> bool + """Provide an alternative for os.path.samefile on Windows/Python2""" + if hasattr(os.path, 'samefile'): + return os.path.samefile(file1, file2) + else: + path1 = os.path.normcase(os.path.abspath(file1)) + path2 = os.path.normcase(os.path.abspath(file2)) + return path1 == path2 + + +if hasattr(shutil, 'get_terminal_size'): + def get_terminal_size(): + # type: () -> Tuple[int, int] + """ + Returns a tuple (x, y) representing the width(x) and the height(y) + in characters of the terminal window. + """ + return tuple(shutil.get_terminal_size()) # type: ignore +else: + def get_terminal_size(): + # type: () -> Tuple[int, int] + """ + Returns a tuple (x, y) representing the width(x) and the height(y) + in characters of the terminal window. + """ + def ioctl_GWINSZ(fd): + try: + import fcntl + import termios + import struct + cr = struct.unpack_from( + 'hh', + fcntl.ioctl(fd, termios.TIOCGWINSZ, '12345678') + ) + except Exception: + return None + if cr == (0, 0): + return None + return cr + cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2) + if not cr: + if sys.platform != "win32": + try: + fd = os.open(os.ctermid(), os.O_RDONLY) + cr = ioctl_GWINSZ(fd) + os.close(fd) + except Exception: + pass + if not cr: + cr = (os.environ.get('LINES', 25), os.environ.get('COLUMNS', 80)) + return int(cr[1]), int(cr[0]) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/compatibility_tags.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/compatibility_tags.py new file mode 100644 index 0000000..47d04f0 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/utils/compatibility_tags.py @@ -0,0 +1,169 @@ +"""Generate and work with PEP 425 Compatibility Tags. +""" + +from __future__ import absolute_import + +import logging +import re + +from pip._vendor.packaging.tags import ( + Tag, + compatible_tags, + cpython_tags, + generic_tags, + interpreter_name, + interpreter_version, + mac_platforms, +) + +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import List, Optional, Tuple + + from pip._vendor.packaging.tags import PythonVersion + +logger = logging.getLogger(__name__) + +_osx_arch_pat = re.compile(r'(.+)_(\d+)_(\d+)_(.+)') + + +def version_info_to_nodot(version_info): + # type: (Tuple[int, ...]) -> str + # Only use up to the first two numbers. + return ''.join(map(str, version_info[:2])) + + +def _mac_platforms(arch): + # type: (str) -> List[str] + match = _osx_arch_pat.match(arch) + if match: + name, major, minor, actual_arch = match.groups() + mac_version = (int(major), int(minor)) + arches = [ + # Since we have always only checked that the platform starts + # with "macosx", for backwards-compatibility we extract the + # actual prefix provided by the user in case they provided + # something like "macosxcustom_". It may be good to remove + # this as undocumented or deprecate it in the future. + '{}_{}'.format(name, arch[len('macosx_'):]) + for arch in mac_platforms(mac_version, actual_arch) + ] + else: + # arch pattern didn't match (?!) + arches = [arch] + return arches + + +def _custom_manylinux_platforms(arch): + # type: (str) -> List[str] + arches = [arch] + arch_prefix, arch_sep, arch_suffix = arch.partition('_') + if arch_prefix == 'manylinux2014': + # manylinux1/manylinux2010 wheels run on most manylinux2014 systems + # with the exception of wheels depending on ncurses. PEP 599 states + # manylinux1/manylinux2010 wheels should be considered + # manylinux2014 wheels: + # https://www.python.org/dev/peps/pep-0599/#backwards-compatibility-with-manylinux2010-wheels + if arch_suffix in {'i686', 'x86_64'}: + arches.append('manylinux2010' + arch_sep + arch_suffix) + arches.append('manylinux1' + arch_sep + arch_suffix) + elif arch_prefix == 'manylinux2010': + # manylinux1 wheels run on most manylinux2010 systems with the + # exception of wheels depending on ncurses. PEP 571 states + # manylinux1 wheels should be considered manylinux2010 wheels: + # https://www.python.org/dev/peps/pep-0571/#backwards-compatibility-with-manylinux1-wheels + arches.append('manylinux1' + arch_sep + arch_suffix) + return arches + + +def _get_custom_platforms(arch): + # type: (str) -> List[str] + arch_prefix, arch_sep, arch_suffix = arch.partition('_') + if arch.startswith('macosx'): + arches = _mac_platforms(arch) + elif arch_prefix in ['manylinux2014', 'manylinux2010']: + arches = _custom_manylinux_platforms(arch) + else: + arches = [arch] + return arches + + +def _get_python_version(version): + # type: (str) -> PythonVersion + if len(version) > 1: + return int(version[0]), int(version[1:]) + else: + return (int(version[0]),) + + +def _get_custom_interpreter(implementation=None, version=None): + # type: (Optional[str], Optional[str]) -> str + if implementation is None: + implementation = interpreter_name() + if version is None: + version = interpreter_version() + return "{}{}".format(implementation, version) + + +def get_supported( + version=None, # type: Optional[str] + platform=None, # type: Optional[str] + impl=None, # type: Optional[str] + abi=None # type: Optional[str] +): + # type: (...) -> List[Tag] + """Return a list of supported tags for each version specified in + `versions`. + + :param version: a string version, of the form "33" or "32", + or None. The version will be assumed to support our ABI. + :param platform: specify the exact platform you want valid + tags for, or None. If None, use the local system platform. + :param impl: specify the exact implementation you want valid + tags for, or None. If None, use the local interpreter impl. + :param abi: specify the exact abi you want valid + tags for, or None. If None, use the local interpreter abi. + """ + supported = [] # type: List[Tag] + + python_version = None # type: Optional[PythonVersion] + if version is not None: + python_version = _get_python_version(version) + + interpreter = _get_custom_interpreter(impl, version) + + abis = None # type: Optional[List[str]] + if abi is not None: + abis = [abi] + + platforms = None # type: Optional[List[str]] + if platform is not None: + platforms = _get_custom_platforms(platform) + + is_cpython = (impl or interpreter_name()) == "cp" + if is_cpython: + supported.extend( + cpython_tags( + python_version=python_version, + abis=abis, + platforms=platforms, + ) + ) + else: + supported.extend( + generic_tags( + interpreter=interpreter, + abis=abis, + platforms=platforms, + ) + ) + supported.extend( + compatible_tags( + python_version=python_version, + interpreter=interpreter, + platforms=platforms, + ) + ) + + return supported diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/deprecation.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/deprecation.py new file mode 100644 index 0000000..2f20cfd --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/utils/deprecation.py @@ -0,0 +1,104 @@ +""" +A module that implements tooling to enable easy warnings about deprecations. +""" + +# The following comment should be removed at some point in the future. +# mypy: disallow-untyped-defs=False + +from __future__ import absolute_import + +import logging +import warnings + +from pip._vendor.packaging.version import parse + +from pip import __version__ as current_version +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Any, Optional + + +DEPRECATION_MSG_PREFIX = "DEPRECATION: " + + +class PipDeprecationWarning(Warning): + pass + + +_original_showwarning = None # type: Any + + +# Warnings <-> Logging Integration +def _showwarning(message, category, filename, lineno, file=None, line=None): + if file is not None: + if _original_showwarning is not None: + _original_showwarning( + message, category, filename, lineno, file, line, + ) + elif issubclass(category, PipDeprecationWarning): + # We use a specially named logger which will handle all of the + # deprecation messages for pip. + logger = logging.getLogger("pip._internal.deprecations") + logger.warning(message) + else: + _original_showwarning( + message, category, filename, lineno, file, line, + ) + + +def install_warning_logger(): + # type: () -> None + # Enable our Deprecation Warnings + warnings.simplefilter("default", PipDeprecationWarning, append=True) + + global _original_showwarning + + if _original_showwarning is None: + _original_showwarning = warnings.showwarning + warnings.showwarning = _showwarning + + +def deprecated(reason, replacement, gone_in, issue=None): + # type: (str, Optional[str], Optional[str], Optional[int]) -> None + """Helper to deprecate existing functionality. + + reason: + Textual reason shown to the user about why this functionality has + been deprecated. + replacement: + Textual suggestion shown to the user about what alternative + functionality they can use. + gone_in: + The version of pip does this functionality should get removed in. + Raises errors if pip's current version is greater than or equal to + this. + issue: + Issue number on the tracker that would serve as a useful place for + users to find related discussion and provide feedback. + + Always pass replacement, gone_in and issue as keyword arguments for clarity + at the call site. + """ + + # Construct a nice message. + # This is eagerly formatted as we want it to get logged as if someone + # typed this entire message out. + sentences = [ + (reason, DEPRECATION_MSG_PREFIX + "{}"), + (gone_in, "pip {} will remove support for this functionality."), + (replacement, "A possible replacement is {}."), + (issue, ( + "You can find discussion regarding this at " + "https://github.com/pypa/pip/issues/{}." + )), + ] + message = " ".join( + template.format(val) for val, template in sentences if val is not None + ) + + # Raise as an error if it has to be removed. + if gone_in is not None and parse(current_version) >= parse(gone_in): + raise PipDeprecationWarning(message) + + warnings.warn(message, category=PipDeprecationWarning, stacklevel=2) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/direct_url_helpers.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/direct_url_helpers.py new file mode 100644 index 0000000..f1fe209 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/utils/direct_url_helpers.py @@ -0,0 +1,130 @@ +import logging + +from pip._internal.models.direct_url import ( + DIRECT_URL_METADATA_NAME, + ArchiveInfo, + DirectUrl, + DirectUrlValidationError, + DirInfo, + VcsInfo, +) +from pip._internal.utils.typing import MYPY_CHECK_RUNNING +from pip._internal.vcs import vcs + +try: + from json import JSONDecodeError +except ImportError: + # PY2 + JSONDecodeError = ValueError # type: ignore + +if MYPY_CHECK_RUNNING: + from typing import Optional + + from pip._internal.models.link import Link + + from pip._vendor.pkg_resources import Distribution + +logger = logging.getLogger(__name__) + + +def direct_url_as_pep440_direct_reference(direct_url, name): + # type: (DirectUrl, str) -> str + """Convert a DirectUrl to a pip requirement string.""" + direct_url.validate() # if invalid, this is a pip bug + requirement = name + " @ " + fragments = [] + if isinstance(direct_url.info, VcsInfo): + requirement += "{}+{}@{}".format( + direct_url.info.vcs, direct_url.url, direct_url.info.commit_id + ) + elif isinstance(direct_url.info, ArchiveInfo): + requirement += direct_url.url + if direct_url.info.hash: + fragments.append(direct_url.info.hash) + else: + assert isinstance(direct_url.info, DirInfo) + # pip should never reach this point for editables, since + # pip freeze inspects the editable project location to produce + # the requirement string + assert not direct_url.info.editable + requirement += direct_url.url + if direct_url.subdirectory: + fragments.append("subdirectory=" + direct_url.subdirectory) + if fragments: + requirement += "#" + "&".join(fragments) + return requirement + + +def direct_url_from_link(link, source_dir=None, link_is_in_wheel_cache=False): + # type: (Link, Optional[str], bool) -> DirectUrl + if link.is_vcs: + vcs_backend = vcs.get_backend_for_scheme(link.scheme) + assert vcs_backend + url, requested_revision, _ = ( + vcs_backend.get_url_rev_and_auth(link.url_without_fragment) + ) + # For VCS links, we need to find out and add commit_id. + if link_is_in_wheel_cache: + # If the requested VCS link corresponds to a cached + # wheel, it means the requested revision was an + # immutable commit hash, otherwise it would not have + # been cached. In that case we don't have a source_dir + # with the VCS checkout. + assert requested_revision + commit_id = requested_revision + else: + # If the wheel was not in cache, it means we have + # had to checkout from VCS to build and we have a source_dir + # which we can inspect to find out the commit id. + assert source_dir + commit_id = vcs_backend.get_revision(source_dir) + return DirectUrl( + url=url, + info=VcsInfo( + vcs=vcs_backend.name, + commit_id=commit_id, + requested_revision=requested_revision, + ), + subdirectory=link.subdirectory_fragment, + ) + elif link.is_existing_dir(): + return DirectUrl( + url=link.url_without_fragment, + info=DirInfo(), + subdirectory=link.subdirectory_fragment, + ) + else: + hash = None + hash_name = link.hash_name + if hash_name: + hash = "{}={}".format(hash_name, link.hash) + return DirectUrl( + url=link.url_without_fragment, + info=ArchiveInfo(hash=hash), + subdirectory=link.subdirectory_fragment, + ) + + +def dist_get_direct_url(dist): + # type: (Distribution) -> Optional[DirectUrl] + """Obtain a DirectUrl from a pkg_resource.Distribution. + + Returns None if the distribution has no `direct_url.json` metadata, + or if `direct_url.json` is invalid. + """ + if not dist.has_metadata(DIRECT_URL_METADATA_NAME): + return None + try: + return DirectUrl.from_json(dist.get_metadata(DIRECT_URL_METADATA_NAME)) + except ( + DirectUrlValidationError, + JSONDecodeError, + UnicodeDecodeError + ) as e: + logger.warning( + "Error parsing %s for %s: %s", + DIRECT_URL_METADATA_NAME, + dist.project_name, + e, + ) + return None diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/distutils_args.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/distutils_args.py new file mode 100644 index 0000000..e38e402 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/utils/distutils_args.py @@ -0,0 +1,48 @@ +from distutils.errors import DistutilsArgError +from distutils.fancy_getopt import FancyGetopt + +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Dict, List + + +_options = [ + ("exec-prefix=", None, ""), + ("home=", None, ""), + ("install-base=", None, ""), + ("install-data=", None, ""), + ("install-headers=", None, ""), + ("install-lib=", None, ""), + ("install-platlib=", None, ""), + ("install-purelib=", None, ""), + ("install-scripts=", None, ""), + ("prefix=", None, ""), + ("root=", None, ""), + ("user", None, ""), +] + + +# typeshed doesn't permit Tuple[str, None, str], see python/typeshed#3469. +_distutils_getopt = FancyGetopt(_options) # type: ignore + + +def parse_distutils_args(args): + # type: (List[str]) -> Dict[str, str] + """Parse provided arguments, returning an object that has the + matched arguments. + + Any unknown arguments are ignored. + """ + result = {} + for arg in args: + try: + _, match = _distutils_getopt.getopt(args=[arg]) + except DistutilsArgError: + # We don't care about any other options, which here may be + # considered unrecognized since our option list is not + # exhaustive. + pass + else: + result.update(match.__dict__) + return result diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/encoding.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/encoding.py new file mode 100644 index 0000000..ab4d4b9 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/utils/encoding.py @@ -0,0 +1,42 @@ +# The following comment should be removed at some point in the future. +# mypy: strict-optional=False + +import codecs +import locale +import re +import sys + +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import List, Tuple, Text + +BOMS = [ + (codecs.BOM_UTF8, 'utf-8'), + (codecs.BOM_UTF16, 'utf-16'), + (codecs.BOM_UTF16_BE, 'utf-16-be'), + (codecs.BOM_UTF16_LE, 'utf-16-le'), + (codecs.BOM_UTF32, 'utf-32'), + (codecs.BOM_UTF32_BE, 'utf-32-be'), + (codecs.BOM_UTF32_LE, 'utf-32-le'), +] # type: List[Tuple[bytes, Text]] + +ENCODING_RE = re.compile(br'coding[:=]\s*([-\w.]+)') + + +def auto_decode(data): + # type: (bytes) -> Text + """Check a bytes string for a BOM to correctly detect the encoding + + Fallback to locale.getpreferredencoding(False) like open() on Python3""" + for bom, encoding in BOMS: + if data.startswith(bom): + return data[len(bom):].decode(encoding) + # Lets check the first two lines as in PEP263 + for line in data.split(b'\n')[:2]: + if line[0:1] == b'#' and ENCODING_RE.search(line): + encoding = ENCODING_RE.search(line).groups()[0].decode('ascii') + return data.decode(encoding) + return data.decode( + locale.getpreferredencoding(False) or sys.getdefaultencoding(), + ) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/entrypoints.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/entrypoints.py new file mode 100644 index 0000000..befd01c --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/utils/entrypoints.py @@ -0,0 +1,31 @@ +import sys + +from pip._internal.cli.main import main +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Optional, List + + +def _wrapper(args=None): + # type: (Optional[List[str]]) -> int + """Central wrapper for all old entrypoints. + + Historically pip has had several entrypoints defined. Because of issues + arising from PATH, sys.path, multiple Pythons, their interactions, and most + of them having a pip installed, users suffer every time an entrypoint gets + moved. + + To alleviate this pain, and provide a mechanism for warning users and + directing them to an appropriate place for help, we now define all of + our old entrypoints as wrappers for the current one. + """ + sys.stderr.write( + "WARNING: pip is being invoked by an old script wrapper. This will " + "fail in a future version of pip.\n" + "Please see https://github.com/pypa/pip/issues/5599 for advice on " + "fixing the underlying issue.\n" + "To avoid this problem you can invoke Python with '-m pip' instead of " + "running pip directly.\n" + ) + return main(args) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/filesystem.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/filesystem.py new file mode 100644 index 0000000..437a7fd --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/utils/filesystem.py @@ -0,0 +1,222 @@ +import errno +import fnmatch +import os +import os.path +import random +import shutil +import stat +import sys +from contextlib import contextmanager +from tempfile import NamedTemporaryFile + +# NOTE: retrying is not annotated in typeshed as on 2017-07-17, which is +# why we ignore the type on this import. +from pip._vendor.retrying import retry # type: ignore +from pip._vendor.six import PY2 + +from pip._internal.utils.compat import get_path_uid +from pip._internal.utils.misc import format_size +from pip._internal.utils.typing import MYPY_CHECK_RUNNING, cast + +if MYPY_CHECK_RUNNING: + from typing import Any, BinaryIO, Iterator, List, Union + + class NamedTemporaryFileResult(BinaryIO): + @property + def file(self): + # type: () -> BinaryIO + pass + + +def check_path_owner(path): + # type: (str) -> bool + # If we don't have a way to check the effective uid of this process, then + # we'll just assume that we own the directory. + if sys.platform == "win32" or not hasattr(os, "geteuid"): + return True + + assert os.path.isabs(path) + + previous = None + while path != previous: + if os.path.lexists(path): + # Check if path is writable by current user. + if os.geteuid() == 0: + # Special handling for root user in order to handle properly + # cases where users use sudo without -H flag. + try: + path_uid = get_path_uid(path) + except OSError: + return False + return path_uid == 0 + else: + return os.access(path, os.W_OK) + else: + previous, path = path, os.path.dirname(path) + return False # assume we don't own the path + + +def copy2_fixed(src, dest): + # type: (str, str) -> None + """Wrap shutil.copy2() but map errors copying socket files to + SpecialFileError as expected. + + See also https://bugs.python.org/issue37700. + """ + try: + shutil.copy2(src, dest) + except (OSError, IOError): + for f in [src, dest]: + try: + is_socket_file = is_socket(f) + except OSError: + # An error has already occurred. Another error here is not + # a problem and we can ignore it. + pass + else: + if is_socket_file: + raise shutil.SpecialFileError( + "`{f}` is a socket".format(**locals())) + + raise + + +def is_socket(path): + # type: (str) -> bool + return stat.S_ISSOCK(os.lstat(path).st_mode) + + +@contextmanager +def adjacent_tmp_file(path, **kwargs): + # type: (str, **Any) -> Iterator[NamedTemporaryFileResult] + """Return a file-like object pointing to a tmp file next to path. + + The file is created securely and is ensured to be written to disk + after the context reaches its end. + + kwargs will be passed to tempfile.NamedTemporaryFile to control + the way the temporary file will be opened. + """ + with NamedTemporaryFile( + delete=False, + dir=os.path.dirname(path), + prefix=os.path.basename(path), + suffix='.tmp', + **kwargs + ) as f: + result = cast('NamedTemporaryFileResult', f) + try: + yield result + finally: + result.file.flush() + os.fsync(result.file.fileno()) + + +_replace_retry = retry(stop_max_delay=1000, wait_fixed=250) + +if PY2: + @_replace_retry + def replace(src, dest): + # type: (str, str) -> None + try: + os.rename(src, dest) + except OSError: + os.remove(dest) + os.rename(src, dest) + +else: + replace = _replace_retry(os.replace) + + +# test_writable_dir and _test_writable_dir_win are copied from Flit, +# with the author's agreement to also place them under pip's license. +def test_writable_dir(path): + # type: (str) -> bool + """Check if a directory is writable. + + Uses os.access() on POSIX, tries creating files on Windows. + """ + # If the directory doesn't exist, find the closest parent that does. + while not os.path.isdir(path): + parent = os.path.dirname(path) + if parent == path: + break # Should never get here, but infinite loops are bad + path = parent + + if os.name == 'posix': + return os.access(path, os.W_OK) + + return _test_writable_dir_win(path) + + +def _test_writable_dir_win(path): + # type: (str) -> bool + # os.access doesn't work on Windows: http://bugs.python.org/issue2528 + # and we can't use tempfile: http://bugs.python.org/issue22107 + basename = 'accesstest_deleteme_fishfingers_custard_' + alphabet = 'abcdefghijklmnopqrstuvwxyz0123456789' + for i in range(10): + name = basename + ''.join(random.choice(alphabet) for _ in range(6)) + file = os.path.join(path, name) + try: + fd = os.open(file, os.O_RDWR | os.O_CREAT | os.O_EXCL) + # Python 2 doesn't support FileExistsError and PermissionError. + except OSError as e: + # exception FileExistsError + if e.errno == errno.EEXIST: + continue + # exception PermissionError + if e.errno == errno.EPERM or e.errno == errno.EACCES: + # This could be because there's a directory with the same name. + # But it's highly unlikely there's a directory called that, + # so we'll assume it's because the parent dir is not writable. + return False + raise + else: + os.close(fd) + os.unlink(file) + return True + + # This should never be reached + raise EnvironmentError( + 'Unexpected condition testing for writable directory' + ) + + +def find_files(path, pattern): + # type: (str, str) -> List[str] + """Returns a list of absolute paths of files beneath path, recursively, + with filenames which match the UNIX-style shell glob pattern.""" + result = [] # type: List[str] + for root, dirs, files in os.walk(path): + matches = fnmatch.filter(files, pattern) + result.extend(os.path.join(root, f) for f in matches) + return result + + +def file_size(path): + # type: (str) -> Union[int, float] + # If it's a symlink, return 0. + if os.path.islink(path): + return 0 + return os.path.getsize(path) + + +def format_file_size(path): + # type: (str) -> str + return format_size(file_size(path)) + + +def directory_size(path): + # type: (str) -> Union[int, float] + size = 0.0 + for root, _dirs, files in os.walk(path): + for filename in files: + file_path = os.path.join(root, filename) + size += file_size(file_path) + return size + + +def format_directory_size(path): + # type: (str) -> str + return format_size(directory_size(path)) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/filetypes.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/filetypes.py new file mode 100644 index 0000000..daa0ca7 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/utils/filetypes.py @@ -0,0 +1,16 @@ +"""Filetype information. +""" +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Tuple + +WHEEL_EXTENSION = '.whl' +BZ2_EXTENSIONS = ('.tar.bz2', '.tbz') # type: Tuple[str, ...] +XZ_EXTENSIONS = ('.tar.xz', '.txz', '.tlz', + '.tar.lz', '.tar.lzma') # type: Tuple[str, ...] +ZIP_EXTENSIONS = ('.zip', WHEEL_EXTENSION) # type: Tuple[str, ...] +TAR_EXTENSIONS = ('.tar.gz', '.tgz', '.tar') # type: Tuple[str, ...] +ARCHIVE_EXTENSIONS = ( + ZIP_EXTENSIONS + BZ2_EXTENSIONS + TAR_EXTENSIONS + XZ_EXTENSIONS +) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/glibc.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/glibc.py new file mode 100644 index 0000000..3610424 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/utils/glibc.py @@ -0,0 +1,98 @@ +# The following comment should be removed at some point in the future. +# mypy: strict-optional=False + +from __future__ import absolute_import + +import os +import sys + +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Optional, Tuple + + +def glibc_version_string(): + # type: () -> Optional[str] + "Returns glibc version string, or None if not using glibc." + return glibc_version_string_confstr() or glibc_version_string_ctypes() + + +def glibc_version_string_confstr(): + # type: () -> Optional[str] + "Primary implementation of glibc_version_string using os.confstr." + # os.confstr is quite a bit faster than ctypes.DLL. It's also less likely + # to be broken or missing. This strategy is used in the standard library + # platform module: + # https://github.com/python/cpython/blob/fcf1d003bf4f0100c9d0921ff3d70e1127ca1b71/Lib/platform.py#L175-L183 + if sys.platform == "win32": + return None + try: + # os.confstr("CS_GNU_LIBC_VERSION") returns a string like "glibc 2.17": + _, version = os.confstr("CS_GNU_LIBC_VERSION").split() + except (AttributeError, OSError, ValueError): + # os.confstr() or CS_GNU_LIBC_VERSION not available (or a bad value)... + return None + return version + + +def glibc_version_string_ctypes(): + # type: () -> Optional[str] + "Fallback implementation of glibc_version_string using ctypes." + + try: + import ctypes + except ImportError: + return None + + # ctypes.CDLL(None) internally calls dlopen(NULL), and as the dlopen + # manpage says, "If filename is NULL, then the returned handle is for the + # main program". This way we can let the linker do the work to figure out + # which libc our process is actually using. + process_namespace = ctypes.CDLL(None) + try: + gnu_get_libc_version = process_namespace.gnu_get_libc_version + except AttributeError: + # Symbol doesn't exist -> therefore, we are not linked to + # glibc. + return None + + # Call gnu_get_libc_version, which returns a string like "2.5" + gnu_get_libc_version.restype = ctypes.c_char_p + version_str = gnu_get_libc_version() + # py2 / py3 compatibility: + if not isinstance(version_str, str): + version_str = version_str.decode("ascii") + + return version_str + + +# platform.libc_ver regularly returns completely nonsensical glibc +# versions. E.g. on my computer, platform says: +# +# ~$ python2.7 -c 'import platform; print(platform.libc_ver())' +# ('glibc', '2.7') +# ~$ python3.5 -c 'import platform; print(platform.libc_ver())' +# ('glibc', '2.9') +# +# But the truth is: +# +# ~$ ldd --version +# ldd (Debian GLIBC 2.22-11) 2.22 +# +# This is unfortunate, because it means that the linehaul data on libc +# versions that was generated by pip 8.1.2 and earlier is useless and +# misleading. Solution: instead of using platform, use our code that actually +# works. +def libc_ver(): + # type: () -> Tuple[str, str] + """Try to determine the glibc version + + Returns a tuple of strings (lib, version) which default to empty strings + in case the lookup fails. + """ + glibc_version = glibc_version_string() + if glibc_version is None: + return ("", "") + else: + return ("glibc", glibc_version) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/hashes.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/hashes.py new file mode 100644 index 0000000..396cf82 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/utils/hashes.py @@ -0,0 +1,133 @@ +from __future__ import absolute_import + +import hashlib + +from pip._vendor.six import iteritems, iterkeys, itervalues + +from pip._internal.exceptions import ( + HashMismatch, + HashMissing, + InstallationError, +) +from pip._internal.utils.misc import read_chunks +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import ( + Dict, List, BinaryIO, NoReturn, Iterator + ) + from pip._vendor.six import PY3 + if PY3: + from hashlib import _Hash + else: + from hashlib import _hash as _Hash + + +# The recommended hash algo of the moment. Change this whenever the state of +# the art changes; it won't hurt backward compatibility. +FAVORITE_HASH = 'sha256' + + +# Names of hashlib algorithms allowed by the --hash option and ``pip hash`` +# Currently, those are the ones at least as collision-resistant as sha256. +STRONG_HASHES = ['sha256', 'sha384', 'sha512'] + + +class Hashes(object): + """A wrapper that builds multiple hashes at once and checks them against + known-good values + + """ + def __init__(self, hashes=None): + # type: (Dict[str, List[str]]) -> None + """ + :param hashes: A dict of algorithm names pointing to lists of allowed + hex digests + """ + self._allowed = {} if hashes is None else hashes + + @property + def digest_count(self): + # type: () -> int + return sum(len(digests) for digests in self._allowed.values()) + + def is_hash_allowed( + self, + hash_name, # type: str + hex_digest, # type: str + ): + # type: (...) -> bool + """Return whether the given hex digest is allowed.""" + return hex_digest in self._allowed.get(hash_name, []) + + def check_against_chunks(self, chunks): + # type: (Iterator[bytes]) -> None + """Check good hashes against ones built from iterable of chunks of + data. + + Raise HashMismatch if none match. + + """ + gots = {} + for hash_name in iterkeys(self._allowed): + try: + gots[hash_name] = hashlib.new(hash_name) + except (ValueError, TypeError): + raise InstallationError( + 'Unknown hash name: {}'.format(hash_name) + ) + + for chunk in chunks: + for hash in itervalues(gots): + hash.update(chunk) + + for hash_name, got in iteritems(gots): + if got.hexdigest() in self._allowed[hash_name]: + return + self._raise(gots) + + def _raise(self, gots): + # type: (Dict[str, _Hash]) -> NoReturn + raise HashMismatch(self._allowed, gots) + + def check_against_file(self, file): + # type: (BinaryIO) -> None + """Check good hashes against a file-like object + + Raise HashMismatch if none match. + + """ + return self.check_against_chunks(read_chunks(file)) + + def check_against_path(self, path): + # type: (str) -> None + with open(path, 'rb') as file: + return self.check_against_file(file) + + def __nonzero__(self): + # type: () -> bool + """Return whether I know any known-good hashes.""" + return bool(self._allowed) + + def __bool__(self): + # type: () -> bool + return self.__nonzero__() + + +class MissingHashes(Hashes): + """A workalike for Hashes used when we're missing a hash for a requirement + + It computes the actual hash of the requirement and raises a HashMissing + exception showing it to the user. + + """ + def __init__(self): + # type: () -> None + """Don't offer the ``hashes`` kwarg.""" + # Pass our favorite hash in to generate a "gotten hash". With the + # empty list, it will never match, so an error will always raise. + super(MissingHashes, self).__init__(hashes={FAVORITE_HASH: []}) + + def _raise(self, gots): + # type: (Dict[str, _Hash]) -> NoReturn + raise HashMissing(gots[FAVORITE_HASH].hexdigest()) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/inject_securetransport.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/inject_securetransport.py new file mode 100644 index 0000000..5b93b1d --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/utils/inject_securetransport.py @@ -0,0 +1,36 @@ +"""A helper module that injects SecureTransport, on import. + +The import should be done as early as possible, to ensure all requests and +sessions (or whatever) are created after injecting SecureTransport. + +Note that we only do the injection on macOS, when the linked OpenSSL is too +old to handle TLSv1.2. +""" + +import sys + + +def inject_securetransport(): + # type: () -> None + # Only relevant on macOS + if sys.platform != "darwin": + return + + try: + import ssl + except ImportError: + return + + # Checks for OpenSSL 1.0.1 + if ssl.OPENSSL_VERSION_NUMBER >= 0x1000100f: + return + + try: + from pip._vendor.urllib3.contrib import securetransport + except (ImportError, OSError): + return + + securetransport.inject_into_urllib3() + + +inject_securetransport() diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/logging.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/logging.py new file mode 100644 index 0000000..9a017cf --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/utils/logging.py @@ -0,0 +1,399 @@ +# The following comment should be removed at some point in the future. +# mypy: disallow-untyped-defs=False + +from __future__ import absolute_import + +import contextlib +import errno +import logging +import logging.handlers +import os +import sys +from logging import Filter, getLogger + +from pip._vendor.six import PY2 + +from pip._internal.utils.compat import WINDOWS +from pip._internal.utils.deprecation import DEPRECATION_MSG_PREFIX +from pip._internal.utils.misc import ensure_dir + +try: + import threading +except ImportError: + import dummy_threading as threading # type: ignore + + +try: + # Use "import as" and set colorama in the else clause to avoid mypy + # errors and get the following correct revealed type for colorama: + # `Union[_importlib_modulespec.ModuleType, None]` + # Otherwise, we get an error like the following in the except block: + # > Incompatible types in assignment (expression has type "None", + # variable has type Module) + # TODO: eliminate the need to use "import as" once mypy addresses some + # of its issues with conditional imports. Here is an umbrella issue: + # https://github.com/python/mypy/issues/1297 + from pip._vendor import colorama as _colorama +# Lots of different errors can come from this, including SystemError and +# ImportError. +except Exception: + colorama = None +else: + # Import Fore explicitly rather than accessing below as colorama.Fore + # to avoid the following error running mypy: + # > Module has no attribute "Fore" + # TODO: eliminate the need to import Fore once mypy addresses some of its + # issues with conditional imports. This particular case could be an + # instance of the following issue (but also see the umbrella issue above): + # https://github.com/python/mypy/issues/3500 + from pip._vendor.colorama import Fore + + colorama = _colorama + + +_log_state = threading.local() +subprocess_logger = getLogger('pip.subprocessor') + + +class BrokenStdoutLoggingError(Exception): + """ + Raised if BrokenPipeError occurs for the stdout stream while logging. + """ + pass + + +# BrokenPipeError does not exist in Python 2 and, in addition, manifests +# differently in Windows and non-Windows. +if WINDOWS: + # In Windows, a broken pipe can show up as EINVAL rather than EPIPE: + # https://bugs.python.org/issue19612 + # https://bugs.python.org/issue30418 + if PY2: + def _is_broken_pipe_error(exc_class, exc): + """See the docstring for non-Windows Python 3 below.""" + return (exc_class is IOError and + exc.errno in (errno.EINVAL, errno.EPIPE)) + else: + # In Windows, a broken pipe IOError became OSError in Python 3. + def _is_broken_pipe_error(exc_class, exc): + """See the docstring for non-Windows Python 3 below.""" + return ((exc_class is BrokenPipeError) or # noqa: F821 + (exc_class is OSError and + exc.errno in (errno.EINVAL, errno.EPIPE))) +elif PY2: + def _is_broken_pipe_error(exc_class, exc): + """See the docstring for non-Windows Python 3 below.""" + return (exc_class is IOError and exc.errno == errno.EPIPE) +else: + # Then we are in the non-Windows Python 3 case. + def _is_broken_pipe_error(exc_class, exc): + """ + Return whether an exception is a broken pipe error. + + Args: + exc_class: an exception class. + exc: an exception instance. + """ + return (exc_class is BrokenPipeError) # noqa: F821 + + +@contextlib.contextmanager +def indent_log(num=2): + """ + A context manager which will cause the log output to be indented for any + log messages emitted inside it. + """ + # For thread-safety + _log_state.indentation = get_indentation() + _log_state.indentation += num + try: + yield + finally: + _log_state.indentation -= num + + +def get_indentation(): + return getattr(_log_state, 'indentation', 0) + + +class IndentingFormatter(logging.Formatter): + + def __init__(self, *args, **kwargs): + """ + A logging.Formatter that obeys the indent_log() context manager. + + :param add_timestamp: A bool indicating output lines should be prefixed + with their record's timestamp. + """ + self.add_timestamp = kwargs.pop("add_timestamp", False) + super(IndentingFormatter, self).__init__(*args, **kwargs) + + def get_message_start(self, formatted, levelno): + """ + Return the start of the formatted log message (not counting the + prefix to add to each line). + """ + if levelno < logging.WARNING: + return '' + if formatted.startswith(DEPRECATION_MSG_PREFIX): + # Then the message already has a prefix. We don't want it to + # look like "WARNING: DEPRECATION: ...." + return '' + if levelno < logging.ERROR: + return 'WARNING: ' + + return 'ERROR: ' + + def format(self, record): + """ + Calls the standard formatter, but will indent all of the log message + lines by our current indentation level. + """ + formatted = super(IndentingFormatter, self).format(record) + message_start = self.get_message_start(formatted, record.levelno) + formatted = message_start + formatted + + prefix = '' + if self.add_timestamp: + # TODO: Use Formatter.default_time_format after dropping PY2. + t = self.formatTime(record, "%Y-%m-%dT%H:%M:%S") + prefix = '{t},{record.msecs:03.0f} '.format(**locals()) + prefix += " " * get_indentation() + formatted = "".join([ + prefix + line + for line in formatted.splitlines(True) + ]) + return formatted + + +def _color_wrap(*colors): + def wrapped(inp): + return "".join(list(colors) + [inp, colorama.Style.RESET_ALL]) + return wrapped + + +class ColorizedStreamHandler(logging.StreamHandler): + + # Don't build up a list of colors if we don't have colorama + if colorama: + COLORS = [ + # This needs to be in order from highest logging level to lowest. + (logging.ERROR, _color_wrap(Fore.RED)), + (logging.WARNING, _color_wrap(Fore.YELLOW)), + ] + else: + COLORS = [] + + def __init__(self, stream=None, no_color=None): + logging.StreamHandler.__init__(self, stream) + self._no_color = no_color + + if WINDOWS and colorama: + self.stream = colorama.AnsiToWin32(self.stream) + + def _using_stdout(self): + """ + Return whether the handler is using sys.stdout. + """ + if WINDOWS and colorama: + # Then self.stream is an AnsiToWin32 object. + return self.stream.wrapped is sys.stdout + + return self.stream is sys.stdout + + def should_color(self): + # Don't colorize things if we do not have colorama or if told not to + if not colorama or self._no_color: + return False + + real_stream = ( + self.stream if not isinstance(self.stream, colorama.AnsiToWin32) + else self.stream.wrapped + ) + + # If the stream is a tty we should color it + if hasattr(real_stream, "isatty") and real_stream.isatty(): + return True + + # If we have an ANSI term we should color it + if os.environ.get("TERM") == "ANSI": + return True + + # If anything else we should not color it + return False + + def format(self, record): + msg = logging.StreamHandler.format(self, record) + + if self.should_color(): + for level, color in self.COLORS: + if record.levelno >= level: + msg = color(msg) + break + + return msg + + # The logging module says handleError() can be customized. + def handleError(self, record): + exc_class, exc = sys.exc_info()[:2] + # If a broken pipe occurred while calling write() or flush() on the + # stdout stream in logging's Handler.emit(), then raise our special + # exception so we can handle it in main() instead of logging the + # broken pipe error and continuing. + if (exc_class and self._using_stdout() and + _is_broken_pipe_error(exc_class, exc)): + raise BrokenStdoutLoggingError() + + return super(ColorizedStreamHandler, self).handleError(record) + + +class BetterRotatingFileHandler(logging.handlers.RotatingFileHandler): + + def _open(self): + ensure_dir(os.path.dirname(self.baseFilename)) + return logging.handlers.RotatingFileHandler._open(self) + + +class MaxLevelFilter(Filter): + + def __init__(self, level): + self.level = level + + def filter(self, record): + return record.levelno < self.level + + +class ExcludeLoggerFilter(Filter): + + """ + A logging Filter that excludes records from a logger (or its children). + """ + + def filter(self, record): + # The base Filter class allows only records from a logger (or its + # children). + return not super(ExcludeLoggerFilter, self).filter(record) + + +def setup_logging(verbosity, no_color, user_log_file): + """Configures and sets up all of the logging + + Returns the requested logging level, as its integer value. + """ + + # Determine the level to be logging at. + if verbosity >= 1: + level = "DEBUG" + elif verbosity == -1: + level = "WARNING" + elif verbosity == -2: + level = "ERROR" + elif verbosity <= -3: + level = "CRITICAL" + else: + level = "INFO" + + level_number = getattr(logging, level) + + # The "root" logger should match the "console" level *unless* we also need + # to log to a user log file. + include_user_log = user_log_file is not None + if include_user_log: + additional_log_file = user_log_file + root_level = "DEBUG" + else: + additional_log_file = "/dev/null" + root_level = level + + # Disable any logging besides WARNING unless we have DEBUG level logging + # enabled for vendored libraries. + vendored_log_level = "WARNING" if level in ["INFO", "ERROR"] else "DEBUG" + + # Shorthands for clarity + log_streams = { + "stdout": "ext://sys.stdout", + "stderr": "ext://sys.stderr", + } + handler_classes = { + "stream": "pip._internal.utils.logging.ColorizedStreamHandler", + "file": "pip._internal.utils.logging.BetterRotatingFileHandler", + } + handlers = ["console", "console_errors", "console_subprocess"] + ( + ["user_log"] if include_user_log else [] + ) + + logging.config.dictConfig({ + "version": 1, + "disable_existing_loggers": False, + "filters": { + "exclude_warnings": { + "()": "pip._internal.utils.logging.MaxLevelFilter", + "level": logging.WARNING, + }, + "restrict_to_subprocess": { + "()": "logging.Filter", + "name": subprocess_logger.name, + }, + "exclude_subprocess": { + "()": "pip._internal.utils.logging.ExcludeLoggerFilter", + "name": subprocess_logger.name, + }, + }, + "formatters": { + "indent": { + "()": IndentingFormatter, + "format": "%(message)s", + }, + "indent_with_timestamp": { + "()": IndentingFormatter, + "format": "%(message)s", + "add_timestamp": True, + }, + }, + "handlers": { + "console": { + "level": level, + "class": handler_classes["stream"], + "no_color": no_color, + "stream": log_streams["stdout"], + "filters": ["exclude_subprocess", "exclude_warnings"], + "formatter": "indent", + }, + "console_errors": { + "level": "WARNING", + "class": handler_classes["stream"], + "no_color": no_color, + "stream": log_streams["stderr"], + "filters": ["exclude_subprocess"], + "formatter": "indent", + }, + # A handler responsible for logging to the console messages + # from the "subprocessor" logger. + "console_subprocess": { + "level": level, + "class": handler_classes["stream"], + "no_color": no_color, + "stream": log_streams["stderr"], + "filters": ["restrict_to_subprocess"], + "formatter": "indent", + }, + "user_log": { + "level": "DEBUG", + "class": handler_classes["file"], + "filename": additional_log_file, + "delay": True, + "formatter": "indent_with_timestamp", + }, + }, + "root": { + "level": root_level, + "handlers": handlers, + }, + "loggers": { + "pip._vendor": { + "level": vendored_log_level + } + }, + }) + + return level_number diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/misc.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/misc.py new file mode 100644 index 0000000..0f388eb --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/utils/misc.py @@ -0,0 +1,927 @@ +# The following comment should be removed at some point in the future. +# mypy: strict-optional=False +# mypy: disallow-untyped-defs=False + +from __future__ import absolute_import + +import contextlib +import errno +import getpass +import hashlib +import io +import logging +import os +import posixpath +import shutil +import stat +import sys +from collections import deque + +from pip._vendor import pkg_resources +# NOTE: retrying is not annotated in typeshed as on 2017-07-17, which is +# why we ignore the type on this import. +from pip._vendor.retrying import retry # type: ignore +from pip._vendor.six import PY2, text_type +from pip._vendor.six.moves import input, map, zip_longest +from pip._vendor.six.moves.urllib import parse as urllib_parse +from pip._vendor.six.moves.urllib.parse import unquote as urllib_unquote + +from pip import __version__ +from pip._internal.exceptions import CommandError +from pip._internal.locations import ( + get_major_minor_version, + site_packages, + user_site, +) +from pip._internal.utils.compat import ( + WINDOWS, + expanduser, + stdlib_pkgs, + str_to_display, +) +from pip._internal.utils.typing import MYPY_CHECK_RUNNING, cast +from pip._internal.utils.virtualenv import ( + running_under_virtualenv, + virtualenv_no_global, +) + +if PY2: + from io import BytesIO as StringIO +else: + from io import StringIO + +if MYPY_CHECK_RUNNING: + from typing import ( + Any, AnyStr, Container, Iterable, Iterator, List, Optional, Text, + Tuple, Union, + ) + from pip._vendor.pkg_resources import Distribution + + VersionInfo = Tuple[int, int, int] + + +__all__ = ['rmtree', 'display_path', 'backup_dir', + 'ask', 'splitext', + 'format_size', 'is_installable_dir', + 'normalize_path', + 'renames', 'get_prog', + 'captured_stdout', 'ensure_dir', + 'get_installed_version', 'remove_auth_from_url'] + + +logger = logging.getLogger(__name__) + + +def get_pip_version(): + # type: () -> str + pip_pkg_dir = os.path.join(os.path.dirname(__file__), "..", "..") + pip_pkg_dir = os.path.abspath(pip_pkg_dir) + + return ( + 'pip {} from {} (python {})'.format( + __version__, pip_pkg_dir, get_major_minor_version(), + ) + ) + + +def normalize_version_info(py_version_info): + # type: (Tuple[int, ...]) -> Tuple[int, int, int] + """ + Convert a tuple of ints representing a Python version to one of length + three. + + :param py_version_info: a tuple of ints representing a Python version, + or None to specify no version. The tuple can have any length. + + :return: a tuple of length three if `py_version_info` is non-None. + Otherwise, return `py_version_info` unchanged (i.e. None). + """ + if len(py_version_info) < 3: + py_version_info += (3 - len(py_version_info)) * (0,) + elif len(py_version_info) > 3: + py_version_info = py_version_info[:3] + + return cast('VersionInfo', py_version_info) + + +def ensure_dir(path): + # type: (AnyStr) -> None + """os.path.makedirs without EEXIST.""" + try: + os.makedirs(path) + except OSError as e: + # Windows can raise spurious ENOTEMPTY errors. See #6426. + if e.errno != errno.EEXIST and e.errno != errno.ENOTEMPTY: + raise + + +def get_prog(): + # type: () -> str + try: + prog = os.path.basename(sys.argv[0]) + if prog in ('__main__.py', '-c'): + return "{} -m pip".format(sys.executable) + else: + return prog + except (AttributeError, TypeError, IndexError): + pass + return 'pip' + + +# Retry every half second for up to 3 seconds +@retry(stop_max_delay=3000, wait_fixed=500) +def rmtree(dir, ignore_errors=False): + # type: (str, bool) -> None + shutil.rmtree(dir, ignore_errors=ignore_errors, + onerror=rmtree_errorhandler) + + +def rmtree_errorhandler(func, path, exc_info): + """On Windows, the files in .svn are read-only, so when rmtree() tries to + remove them, an exception is thrown. We catch that here, remove the + read-only attribute, and hopefully continue without problems.""" + try: + has_attr_readonly = not (os.stat(path).st_mode & stat.S_IWRITE) + except (IOError, OSError): + # it's equivalent to os.path.exists + return + + if has_attr_readonly: + # convert to read/write + os.chmod(path, stat.S_IWRITE) + # use the original function to repeat the operation + func(path) + return + else: + raise + + +def path_to_display(path): + # type: (Optional[Union[str, Text]]) -> Optional[Text] + """ + Convert a bytes (or text) path to text (unicode in Python 2) for display + and logging purposes. + + This function should never error out. Also, this function is mainly needed + for Python 2 since in Python 3 str paths are already text. + """ + if path is None: + return None + if isinstance(path, text_type): + return path + # Otherwise, path is a bytes object (str in Python 2). + try: + display_path = path.decode(sys.getfilesystemencoding(), 'strict') + except UnicodeDecodeError: + # Include the full bytes to make troubleshooting easier, even though + # it may not be very human readable. + if PY2: + # Convert the bytes to a readable str representation using + # repr(), and then convert the str to unicode. + # Also, we add the prefix "b" to the repr() return value both + # to make the Python 2 output look like the Python 3 output, and + # to signal to the user that this is a bytes representation. + display_path = str_to_display('b{!r}'.format(path)) + else: + # Silence the "F821 undefined name 'ascii'" flake8 error since + # in Python 3 ascii() is a built-in. + display_path = ascii(path) # noqa: F821 + + return display_path + + +def display_path(path): + # type: (Union[str, Text]) -> str + """Gives the display value for a given path, making it relative to cwd + if possible.""" + path = os.path.normcase(os.path.abspath(path)) + if sys.version_info[0] == 2: + path = path.decode(sys.getfilesystemencoding(), 'replace') + path = path.encode(sys.getdefaultencoding(), 'replace') + if path.startswith(os.getcwd() + os.path.sep): + path = '.' + path[len(os.getcwd()):] + return path + + +def backup_dir(dir, ext='.bak'): + # type: (str, str) -> str + """Figure out the name of a directory to back up the given dir to + (adding .bak, .bak2, etc)""" + n = 1 + extension = ext + while os.path.exists(dir + extension): + n += 1 + extension = ext + str(n) + return dir + extension + + +def ask_path_exists(message, options): + # type: (str, Iterable[str]) -> str + for action in os.environ.get('PIP_EXISTS_ACTION', '').split(): + if action in options: + return action + return ask(message, options) + + +def _check_no_input(message): + # type: (str) -> None + """Raise an error if no input is allowed.""" + if os.environ.get('PIP_NO_INPUT'): + raise Exception( + 'No input was expected ($PIP_NO_INPUT set); question: {}'.format( + message) + ) + + +def ask(message, options): + # type: (str, Iterable[str]) -> str + """Ask the message interactively, with the given possible responses""" + while 1: + _check_no_input(message) + response = input(message) + response = response.strip().lower() + if response not in options: + print( + 'Your response ({!r}) was not one of the expected responses: ' + '{}'.format(response, ', '.join(options)) + ) + else: + return response + + +def ask_input(message): + # type: (str) -> str + """Ask for input interactively.""" + _check_no_input(message) + return input(message) + + +def ask_password(message): + # type: (str) -> str + """Ask for a password interactively.""" + _check_no_input(message) + return getpass.getpass(message) + + +def format_size(bytes): + # type: (float) -> str + if bytes > 1000 * 1000: + return '{:.1f} MB'.format(bytes / 1000.0 / 1000) + elif bytes > 10 * 1000: + return '{} kB'.format(int(bytes / 1000)) + elif bytes > 1000: + return '{:.1f} kB'.format(bytes / 1000.0) + else: + return '{} bytes'.format(int(bytes)) + + +def tabulate(rows): + # type: (Iterable[Iterable[Any]]) -> Tuple[List[str], List[int]] + """Return a list of formatted rows and a list of column sizes. + + For example:: + + >>> tabulate([['foobar', 2000], [0xdeadbeef]]) + (['foobar 2000', '3735928559'], [10, 4]) + """ + rows = [tuple(map(str, row)) for row in rows] + sizes = [max(map(len, col)) for col in zip_longest(*rows, fillvalue='')] + table = [" ".join(map(str.ljust, row, sizes)).rstrip() for row in rows] + return table, sizes + + +def is_installable_dir(path): + # type: (str) -> bool + """Is path is a directory containing setup.py or pyproject.toml? + """ + if not os.path.isdir(path): + return False + setup_py = os.path.join(path, 'setup.py') + if os.path.isfile(setup_py): + return True + pyproject_toml = os.path.join(path, 'pyproject.toml') + if os.path.isfile(pyproject_toml): + return True + return False + + +def read_chunks(file, size=io.DEFAULT_BUFFER_SIZE): + """Yield pieces of data from a file-like object until EOF.""" + while True: + chunk = file.read(size) + if not chunk: + break + yield chunk + + +def normalize_path(path, resolve_symlinks=True): + # type: (str, bool) -> str + """ + Convert a path to its canonical, case-normalized, absolute version. + + """ + path = expanduser(path) + if resolve_symlinks: + path = os.path.realpath(path) + else: + path = os.path.abspath(path) + return os.path.normcase(path) + + +def splitext(path): + # type: (str) -> Tuple[str, str] + """Like os.path.splitext, but take off .tar too""" + base, ext = posixpath.splitext(path) + if base.lower().endswith('.tar'): + ext = base[-4:] + ext + base = base[:-4] + return base, ext + + +def renames(old, new): + # type: (str, str) -> None + """Like os.renames(), but handles renaming across devices.""" + # Implementation borrowed from os.renames(). + head, tail = os.path.split(new) + if head and tail and not os.path.exists(head): + os.makedirs(head) + + shutil.move(old, new) + + head, tail = os.path.split(old) + if head and tail: + try: + os.removedirs(head) + except OSError: + pass + + +def is_local(path): + # type: (str) -> bool + """ + Return True if this is a path pip is allowed to modify. + + If we're in a virtualenv, sys.prefix points to the virtualenv's + prefix; only sys.prefix is considered local. + + If we're not in a virtualenv, in general we can modify anything. + However, if the OS vendor has configured distutils to install + somewhere other than sys.prefix (which could be a subdirectory of + sys.prefix, e.g. /usr/local), we consider sys.prefix itself nonlocal + and the domain of the OS vendor. (In other words, everything _other + than_ sys.prefix is considered local.) + + Caution: this function assumes the head of path has been normalized + with normalize_path. + """ + + path = normalize_path(path) + prefix = normalize_path(sys.prefix) + + if running_under_virtualenv(): + return path.startswith(normalize_path(sys.prefix)) + else: + from pip._internal.locations import distutils_scheme + if path.startswith(prefix): + for local_path in distutils_scheme("").values(): + if path.startswith(normalize_path(local_path)): + return True + return False + else: + return True + + +def dist_is_local(dist): + # type: (Distribution) -> bool + """ + Return True if given Distribution object is installed somewhere pip + is allowed to modify. + + """ + return is_local(dist_location(dist)) + + +def dist_in_usersite(dist): + # type: (Distribution) -> bool + """ + Return True if given Distribution is installed in user site. + """ + return dist_location(dist).startswith(normalize_path(user_site)) + + +def dist_in_site_packages(dist): + # type: (Distribution) -> bool + """ + Return True if given Distribution is installed in + sysconfig.get_python_lib(). + """ + return dist_location(dist).startswith(normalize_path(site_packages)) + + +def dist_is_editable(dist): + # type: (Distribution) -> bool + """ + Return True if given Distribution is an editable install. + """ + return bool(egg_link_path(dist)) + + +def get_installed_distributions( + local_only=True, # type: bool + skip=stdlib_pkgs, # type: Container[str] + include_editables=True, # type: bool + editables_only=False, # type: bool + user_only=False, # type: bool + paths=None # type: Optional[List[str]] +): + # type: (...) -> List[Distribution] + """ + Return a list of installed Distribution objects. + + If ``local_only`` is True (default), only return installations + local to the current virtualenv, if in a virtualenv. + + ``skip`` argument is an iterable of lower-case project names to + ignore; defaults to stdlib_pkgs + + If ``include_editables`` is False, don't report editables. + + If ``editables_only`` is True , only report editables. + + If ``user_only`` is True , only report installations in the user + site directory. + + If ``paths`` is set, only report the distributions present at the + specified list of locations. + """ + if paths: + working_set = pkg_resources.WorkingSet(paths) + else: + working_set = pkg_resources.working_set + + if local_only: + local_test = dist_is_local + else: + def local_test(d): + return True + + if include_editables: + def editable_test(d): + return True + else: + def editable_test(d): + return not dist_is_editable(d) + + if editables_only: + def editables_only_test(d): + return dist_is_editable(d) + else: + def editables_only_test(d): + return True + + if user_only: + user_test = dist_in_usersite + else: + def user_test(d): + return True + + return [d for d in working_set + if local_test(d) and + d.key not in skip and + editable_test(d) and + editables_only_test(d) and + user_test(d) + ] + + +def egg_link_path(dist): + # type: (Distribution) -> Optional[str] + """ + Return the path for the .egg-link file if it exists, otherwise, None. + + There's 3 scenarios: + 1) not in a virtualenv + try to find in site.USER_SITE, then site_packages + 2) in a no-global virtualenv + try to find in site_packages + 3) in a yes-global virtualenv + try to find in site_packages, then site.USER_SITE + (don't look in global location) + + For #1 and #3, there could be odd cases, where there's an egg-link in 2 + locations. + + This method will just return the first one found. + """ + sites = [] + if running_under_virtualenv(): + sites.append(site_packages) + if not virtualenv_no_global() and user_site: + sites.append(user_site) + else: + if user_site: + sites.append(user_site) + sites.append(site_packages) + + for site in sites: + egglink = os.path.join(site, dist.project_name) + '.egg-link' + if os.path.isfile(egglink): + return egglink + return None + + +def dist_location(dist): + # type: (Distribution) -> str + """ + Get the site-packages location of this distribution. Generally + this is dist.location, except in the case of develop-installed + packages, where dist.location is the source code location, and we + want to know where the egg-link file is. + + The returned location is normalized (in particular, with symlinks removed). + """ + egg_link = egg_link_path(dist) + if egg_link: + return normalize_path(egg_link) + return normalize_path(dist.location) + + +def write_output(msg, *args): + # type: (str, str) -> None + logger.info(msg, *args) + + +class FakeFile(object): + """Wrap a list of lines in an object with readline() to make + ConfigParser happy.""" + def __init__(self, lines): + self._gen = (l for l in lines) + + def readline(self): + try: + try: + return next(self._gen) + except NameError: + return self._gen.next() + except StopIteration: + return '' + + def __iter__(self): + return self._gen + + +class StreamWrapper(StringIO): + + @classmethod + def from_stream(cls, orig_stream): + cls.orig_stream = orig_stream + return cls() + + # compileall.compile_dir() needs stdout.encoding to print to stdout + @property + def encoding(self): + return self.orig_stream.encoding + + +@contextlib.contextmanager +def captured_output(stream_name): + """Return a context manager used by captured_stdout/stdin/stderr + that temporarily replaces the sys stream *stream_name* with a StringIO. + + Taken from Lib/support/__init__.py in the CPython repo. + """ + orig_stdout = getattr(sys, stream_name) + setattr(sys, stream_name, StreamWrapper.from_stream(orig_stdout)) + try: + yield getattr(sys, stream_name) + finally: + setattr(sys, stream_name, orig_stdout) + + +def captured_stdout(): + """Capture the output of sys.stdout: + + with captured_stdout() as stdout: + print('hello') + self.assertEqual(stdout.getvalue(), 'hello\n') + + Taken from Lib/support/__init__.py in the CPython repo. + """ + return captured_output('stdout') + + +def captured_stderr(): + """ + See captured_stdout(). + """ + return captured_output('stderr') + + +class cached_property(object): + """A property that is only computed once per instance and then replaces + itself with an ordinary attribute. Deleting the attribute resets the + property. + + Source: https://github.com/bottlepy/bottle/blob/0.11.5/bottle.py#L175 + """ + + def __init__(self, func): + self.__doc__ = getattr(func, '__doc__') + self.func = func + + def __get__(self, obj, cls): + if obj is None: + # We're being accessed from the class itself, not from an object + return self + value = obj.__dict__[self.func.__name__] = self.func(obj) + return value + + +def get_installed_version(dist_name, working_set=None): + """Get the installed version of dist_name avoiding pkg_resources cache""" + # Create a requirement that we'll look for inside of setuptools. + req = pkg_resources.Requirement.parse(dist_name) + + if working_set is None: + # We want to avoid having this cached, so we need to construct a new + # working set each time. + working_set = pkg_resources.WorkingSet() + + # Get the installed distribution from our working set + dist = working_set.find(req) + + # Check to see if we got an installed distribution or not, if we did + # we want to return it's version. + return dist.version if dist else None + + +def consume(iterator): + """Consume an iterable at C speed.""" + deque(iterator, maxlen=0) + + +# Simulates an enum +def enum(*sequential, **named): + enums = dict(zip(sequential, range(len(sequential))), **named) + reverse = {value: key for key, value in enums.items()} + enums['reverse_mapping'] = reverse + return type('Enum', (), enums) + + +def build_netloc(host, port): + # type: (str, Optional[int]) -> str + """ + Build a netloc from a host-port pair + """ + if port is None: + return host + if ':' in host: + # Only wrap host with square brackets when it is IPv6 + host = '[{}]'.format(host) + return '{}:{}'.format(host, port) + + +def build_url_from_netloc(netloc, scheme='https'): + # type: (str, str) -> str + """ + Build a full URL from a netloc. + """ + if netloc.count(':') >= 2 and '@' not in netloc and '[' not in netloc: + # It must be a bare IPv6 address, so wrap it with brackets. + netloc = '[{}]'.format(netloc) + return '{}://{}'.format(scheme, netloc) + + +def parse_netloc(netloc): + # type: (str) -> Tuple[str, Optional[int]] + """ + Return the host-port pair from a netloc. + """ + url = build_url_from_netloc(netloc) + parsed = urllib_parse.urlparse(url) + return parsed.hostname, parsed.port + + +def split_auth_from_netloc(netloc): + """ + Parse out and remove the auth information from a netloc. + + Returns: (netloc, (username, password)). + """ + if '@' not in netloc: + return netloc, (None, None) + + # Split from the right because that's how urllib.parse.urlsplit() + # behaves if more than one @ is present (which can be checked using + # the password attribute of urlsplit()'s return value). + auth, netloc = netloc.rsplit('@', 1) + if ':' in auth: + # Split from the left because that's how urllib.parse.urlsplit() + # behaves if more than one : is present (which again can be checked + # using the password attribute of the return value) + user_pass = auth.split(':', 1) + else: + user_pass = auth, None + + user_pass = tuple( + None if x is None else urllib_unquote(x) for x in user_pass + ) + + return netloc, user_pass + + +def redact_netloc(netloc): + # type: (str) -> str + """ + Replace the sensitive data in a netloc with "****", if it exists. + + For example: + - "user:pass@example.com" returns "user:****@example.com" + - "accesstoken@example.com" returns "****@example.com" + """ + netloc, (user, password) = split_auth_from_netloc(netloc) + if user is None: + return netloc + if password is None: + user = '****' + password = '' + else: + user = urllib_parse.quote(user) + password = ':****' + return '{user}{password}@{netloc}'.format(user=user, + password=password, + netloc=netloc) + + +def _transform_url(url, transform_netloc): + """Transform and replace netloc in a url. + + transform_netloc is a function taking the netloc and returning a + tuple. The first element of this tuple is the new netloc. The + entire tuple is returned. + + Returns a tuple containing the transformed url as item 0 and the + original tuple returned by transform_netloc as item 1. + """ + purl = urllib_parse.urlsplit(url) + netloc_tuple = transform_netloc(purl.netloc) + # stripped url + url_pieces = ( + purl.scheme, netloc_tuple[0], purl.path, purl.query, purl.fragment + ) + surl = urllib_parse.urlunsplit(url_pieces) + return surl, netloc_tuple + + +def _get_netloc(netloc): + return split_auth_from_netloc(netloc) + + +def _redact_netloc(netloc): + return (redact_netloc(netloc),) + + +def split_auth_netloc_from_url(url): + # type: (str) -> Tuple[str, str, Tuple[str, str]] + """ + Parse a url into separate netloc, auth, and url with no auth. + + Returns: (url_without_auth, netloc, (username, password)) + """ + url_without_auth, (netloc, auth) = _transform_url(url, _get_netloc) + return url_without_auth, netloc, auth + + +def remove_auth_from_url(url): + # type: (str) -> str + """Return a copy of url with 'username:password@' removed.""" + # username/pass params are passed to subversion through flags + # and are not recognized in the url. + return _transform_url(url, _get_netloc)[0] + + +def redact_auth_from_url(url): + # type: (str) -> str + """Replace the password in a given url with ****.""" + return _transform_url(url, _redact_netloc)[0] + + +class HiddenText(object): + def __init__( + self, + secret, # type: str + redacted, # type: str + ): + # type: (...) -> None + self.secret = secret + self.redacted = redacted + + def __repr__(self): + # type: (...) -> str + return ''.format(str(self)) + + def __str__(self): + # type: (...) -> str + return self.redacted + + # This is useful for testing. + def __eq__(self, other): + # type: (Any) -> bool + if type(self) != type(other): + return False + + # The string being used for redaction doesn't also have to match, + # just the raw, original string. + return (self.secret == other.secret) + + # We need to provide an explicit __ne__ implementation for Python 2. + # TODO: remove this when we drop PY2 support. + def __ne__(self, other): + # type: (Any) -> bool + return not self == other + + +def hide_value(value): + # type: (str) -> HiddenText + return HiddenText(value, redacted='****') + + +def hide_url(url): + # type: (str) -> HiddenText + redacted = redact_auth_from_url(url) + return HiddenText(url, redacted=redacted) + + +def protect_pip_from_modification_on_windows(modifying_pip): + # type: (bool) -> None + """Protection of pip.exe from modification on Windows + + On Windows, any operation modifying pip should be run as: + python -m pip ... + """ + pip_names = [ + "pip.exe", + "pip{}.exe".format(sys.version_info[0]), + "pip{}.{}.exe".format(*sys.version_info[:2]) + ] + + # See https://github.com/pypa/pip/issues/1299 for more discussion + should_show_use_python_msg = ( + modifying_pip and + WINDOWS and + os.path.basename(sys.argv[0]) in pip_names + ) + + if should_show_use_python_msg: + new_command = [ + sys.executable, "-m", "pip" + ] + sys.argv[1:] + raise CommandError( + 'To modify pip, please run the following command:\n{}' + .format(" ".join(new_command)) + ) + + +def is_console_interactive(): + # type: () -> bool + """Is this console interactive? + """ + return sys.stdin is not None and sys.stdin.isatty() + + +def hash_file(path, blocksize=1 << 20): + # type: (str, int) -> Tuple[Any, int] + """Return (hash, length) for path using hashlib.sha256() + """ + + h = hashlib.sha256() + length = 0 + with open(path, 'rb') as f: + for block in read_chunks(f, size=blocksize): + length += len(block) + h.update(block) + return h, length + + +def is_wheel_installed(): + """ + Return whether the wheel package is installed. + """ + try: + import wheel # noqa: F401 + except ImportError: + return False + + return True + + +def pairwise(iterable): + # type: (Iterable[Any]) -> Iterator[Tuple[Any, Any]] + """ + Return paired elements. + + For example: + s -> (s0, s1), (s2, s3), (s4, s5), ... + """ + iterable = iter(iterable) + return zip_longest(iterable, iterable) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/models.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/models.py new file mode 100644 index 0000000..29e1441 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/utils/models.py @@ -0,0 +1,42 @@ +"""Utilities for defining models +""" +# The following comment should be removed at some point in the future. +# mypy: disallow-untyped-defs=False + +import operator + + +class KeyBasedCompareMixin(object): + """Provides comparison capabilities that is based on a key + """ + + def __init__(self, key, defining_class): + self._compare_key = key + self._defining_class = defining_class + + def __hash__(self): + return hash(self._compare_key) + + def __lt__(self, other): + return self._compare(other, operator.__lt__) + + def __le__(self, other): + return self._compare(other, operator.__le__) + + def __gt__(self, other): + return self._compare(other, operator.__gt__) + + def __ge__(self, other): + return self._compare(other, operator.__ge__) + + def __eq__(self, other): + return self._compare(other, operator.__eq__) + + def __ne__(self, other): + return self._compare(other, operator.__ne__) + + def _compare(self, other, method): + if not isinstance(other, self._defining_class): + return NotImplemented + + return method(self._compare_key, other._compare_key) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/packaging.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/packaging.py new file mode 100644 index 0000000..68aa86e --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/utils/packaging.py @@ -0,0 +1,94 @@ +from __future__ import absolute_import + +import logging +from email.parser import FeedParser + +from pip._vendor import pkg_resources +from pip._vendor.packaging import specifiers, version + +from pip._internal.exceptions import NoneMetadataError +from pip._internal.utils.misc import display_path +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Optional, Tuple + from email.message import Message + from pip._vendor.pkg_resources import Distribution + + +logger = logging.getLogger(__name__) + + +def check_requires_python(requires_python, version_info): + # type: (Optional[str], Tuple[int, ...]) -> bool + """ + Check if the given Python version matches a "Requires-Python" specifier. + + :param version_info: A 3-tuple of ints representing a Python + major-minor-micro version to check (e.g. `sys.version_info[:3]`). + + :return: `True` if the given Python version satisfies the requirement. + Otherwise, return `False`. + + :raises InvalidSpecifier: If `requires_python` has an invalid format. + """ + if requires_python is None: + # The package provides no information + return True + requires_python_specifier = specifiers.SpecifierSet(requires_python) + + python_version = version.parse('.'.join(map(str, version_info))) + return python_version in requires_python_specifier + + +def get_metadata(dist): + # type: (Distribution) -> Message + """ + :raises NoneMetadataError: if the distribution reports `has_metadata()` + True but `get_metadata()` returns None. + """ + metadata_name = 'METADATA' + if (isinstance(dist, pkg_resources.DistInfoDistribution) and + dist.has_metadata(metadata_name)): + metadata = dist.get_metadata(metadata_name) + elif dist.has_metadata('PKG-INFO'): + metadata_name = 'PKG-INFO' + metadata = dist.get_metadata(metadata_name) + else: + logger.warning("No metadata found in %s", display_path(dist.location)) + metadata = '' + + if metadata is None: + raise NoneMetadataError(dist, metadata_name) + + feed_parser = FeedParser() + # The following line errors out if with a "NoneType" TypeError if + # passed metadata=None. + feed_parser.feed(metadata) + return feed_parser.close() + + +def get_requires_python(dist): + # type: (pkg_resources.Distribution) -> Optional[str] + """ + Return the "Requires-Python" metadata for a distribution, or None + if not present. + """ + pkg_info_dict = get_metadata(dist) + requires_python = pkg_info_dict.get('Requires-Python') + + if requires_python is not None: + # Convert to a str to satisfy the type checker, since requires_python + # can be a Header object. + requires_python = str(requires_python) + + return requires_python + + +def get_installer(dist): + # type: (Distribution) -> str + if dist.has_metadata('INSTALLER'): + for line in dist.get_metadata_lines('INSTALLER'): + if line.strip(): + return line.strip() + return '' diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/pkg_resources.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/pkg_resources.py new file mode 100644 index 0000000..0bc129a --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/utils/pkg_resources.py @@ -0,0 +1,44 @@ +from pip._vendor.pkg_resources import yield_lines +from pip._vendor.six import ensure_str + +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Dict, Iterable, List + + +class DictMetadata(object): + """IMetadataProvider that reads metadata files from a dictionary. + """ + def __init__(self, metadata): + # type: (Dict[str, bytes]) -> None + self._metadata = metadata + + def has_metadata(self, name): + # type: (str) -> bool + return name in self._metadata + + def get_metadata(self, name): + # type: (str) -> str + try: + return ensure_str(self._metadata[name]) + except UnicodeDecodeError as e: + # Mirrors handling done in pkg_resources.NullProvider. + e.reason += " in {} file".format(name) + raise + + def get_metadata_lines(self, name): + # type: (str) -> Iterable[str] + return yield_lines(self.get_metadata(name)) + + def metadata_isdir(self, name): + # type: (str) -> bool + return False + + def metadata_listdir(self, name): + # type: (str) -> List[str] + return [] + + def run_script(self, script_name, namespace): + # type: (str, str) -> None + pass diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/setuptools_build.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/setuptools_build.py new file mode 100644 index 0000000..2a664b0 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/utils/setuptools_build.py @@ -0,0 +1,181 @@ +import sys + +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import List, Optional, Sequence + +# Shim to wrap setup.py invocation with setuptools +# +# We set sys.argv[0] to the path to the underlying setup.py file so +# setuptools / distutils don't take the path to the setup.py to be "-c" when +# invoking via the shim. This avoids e.g. the following manifest_maker +# warning: "warning: manifest_maker: standard file '-c' not found". +_SETUPTOOLS_SHIM = ( + "import sys, setuptools, tokenize; sys.argv[0] = {0!r}; __file__={0!r};" + "f=getattr(tokenize, 'open', open)(__file__);" + "code=f.read().replace('\\r\\n', '\\n');" + "f.close();" + "exec(compile(code, __file__, 'exec'))" +) + + +def make_setuptools_shim_args( + setup_py_path, # type: str + global_options=None, # type: Sequence[str] + no_user_config=False, # type: bool + unbuffered_output=False # type: bool +): + # type: (...) -> List[str] + """ + Get setuptools command arguments with shim wrapped setup file invocation. + + :param setup_py_path: The path to setup.py to be wrapped. + :param global_options: Additional global options. + :param no_user_config: If True, disables personal user configuration. + :param unbuffered_output: If True, adds the unbuffered switch to the + argument list. + """ + args = [sys.executable] + if unbuffered_output: + args += ["-u"] + args += ["-c", _SETUPTOOLS_SHIM.format(setup_py_path)] + if global_options: + args += global_options + if no_user_config: + args += ["--no-user-cfg"] + return args + + +def make_setuptools_bdist_wheel_args( + setup_py_path, # type: str + global_options, # type: Sequence[str] + build_options, # type: Sequence[str] + destination_dir, # type: str +): + # type: (...) -> List[str] + # NOTE: Eventually, we'd want to also -S to the flags here, when we're + # isolating. Currently, it breaks Python in virtualenvs, because it + # relies on site.py to find parts of the standard library outside the + # virtualenv. + args = make_setuptools_shim_args( + setup_py_path, + global_options=global_options, + unbuffered_output=True + ) + args += ["bdist_wheel", "-d", destination_dir] + args += build_options + return args + + +def make_setuptools_clean_args( + setup_py_path, # type: str + global_options, # type: Sequence[str] +): + # type: (...) -> List[str] + args = make_setuptools_shim_args( + setup_py_path, + global_options=global_options, + unbuffered_output=True + ) + args += ["clean", "--all"] + return args + + +def make_setuptools_develop_args( + setup_py_path, # type: str + global_options, # type: Sequence[str] + install_options, # type: Sequence[str] + no_user_config, # type: bool + prefix, # type: Optional[str] + home, # type: Optional[str] + use_user_site, # type: bool +): + # type: (...) -> List[str] + assert not (use_user_site and prefix) + + args = make_setuptools_shim_args( + setup_py_path, + global_options=global_options, + no_user_config=no_user_config, + ) + + args += ["develop", "--no-deps"] + + args += install_options + + if prefix: + args += ["--prefix", prefix] + if home is not None: + args += ["--home", home] + + if use_user_site: + args += ["--user", "--prefix="] + + return args + + +def make_setuptools_egg_info_args( + setup_py_path, # type: str + egg_info_dir, # type: Optional[str] + no_user_config, # type: bool +): + # type: (...) -> List[str] + args = make_setuptools_shim_args( + setup_py_path, no_user_config=no_user_config + ) + + args += ["egg_info"] + + if egg_info_dir: + args += ["--egg-base", egg_info_dir] + + return args + + +def make_setuptools_install_args( + setup_py_path, # type: str + global_options, # type: Sequence[str] + install_options, # type: Sequence[str] + record_filename, # type: str + root, # type: Optional[str] + prefix, # type: Optional[str] + header_dir, # type: Optional[str] + home, # type: Optional[str] + use_user_site, # type: bool + no_user_config, # type: bool + pycompile # type: bool +): + # type: (...) -> List[str] + assert not (use_user_site and prefix) + assert not (use_user_site and root) + + args = make_setuptools_shim_args( + setup_py_path, + global_options=global_options, + no_user_config=no_user_config, + unbuffered_output=True + ) + args += ["install", "--record", record_filename] + args += ["--single-version-externally-managed"] + + if root is not None: + args += ["--root", root] + if prefix is not None: + args += ["--prefix", prefix] + if home is not None: + args += ["--home", home] + if use_user_site: + args += ["--user", "--prefix="] + + if pycompile: + args += ["--compile"] + else: + args += ["--no-compile"] + + if header_dir: + args += ["--install-headers", header_dir] + + args += install_options + + return args diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/subprocess.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/subprocess.py new file mode 100644 index 0000000..55c82da --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/utils/subprocess.py @@ -0,0 +1,277 @@ +# The following comment should be removed at some point in the future. +# mypy: strict-optional=False + +from __future__ import absolute_import + +import logging +import os +import subprocess + +from pip._vendor.six.moves import shlex_quote + +from pip._internal.cli.spinners import SpinnerInterface, open_spinner +from pip._internal.exceptions import InstallationError +from pip._internal.utils.compat import console_to_str, str_to_display +from pip._internal.utils.logging import subprocess_logger +from pip._internal.utils.misc import HiddenText, path_to_display +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import ( + Any, Callable, Iterable, List, Mapping, Optional, Text, Union, + ) + + CommandArgs = List[Union[str, HiddenText]] + + +LOG_DIVIDER = '----------------------------------------' + + +def make_command(*args): + # type: (Union[str, HiddenText, CommandArgs]) -> CommandArgs + """ + Create a CommandArgs object. + """ + command_args = [] # type: CommandArgs + for arg in args: + # Check for list instead of CommandArgs since CommandArgs is + # only known during type-checking. + if isinstance(arg, list): + command_args.extend(arg) + else: + # Otherwise, arg is str or HiddenText. + command_args.append(arg) + + return command_args + + +def format_command_args(args): + # type: (Union[List[str], CommandArgs]) -> str + """ + Format command arguments for display. + """ + # For HiddenText arguments, display the redacted form by calling str(). + # Also, we don't apply str() to arguments that aren't HiddenText since + # this can trigger a UnicodeDecodeError in Python 2 if the argument + # has type unicode and includes a non-ascii character. (The type + # checker doesn't ensure the annotations are correct in all cases.) + return ' '.join( + shlex_quote(str(arg)) if isinstance(arg, HiddenText) + else shlex_quote(arg) for arg in args + ) + + +def reveal_command_args(args): + # type: (Union[List[str], CommandArgs]) -> List[str] + """ + Return the arguments in their raw, unredacted form. + """ + return [ + arg.secret if isinstance(arg, HiddenText) else arg for arg in args + ] + + +def make_subprocess_output_error( + cmd_args, # type: Union[List[str], CommandArgs] + cwd, # type: Optional[str] + lines, # type: List[Text] + exit_status, # type: int +): + # type: (...) -> Text + """ + Create and return the error message to use to log a subprocess error + with command output. + + :param lines: A list of lines, each ending with a newline. + """ + command = format_command_args(cmd_args) + # Convert `command` and `cwd` to text (unicode in Python 2) so we can use + # them as arguments in the unicode format string below. This avoids + # "UnicodeDecodeError: 'ascii' codec can't decode byte ..." in Python 2 + # if either contains a non-ascii character. + command_display = str_to_display(command, desc='command bytes') + cwd_display = path_to_display(cwd) + + # We know the joined output value ends in a newline. + output = ''.join(lines) + msg = ( + # Use a unicode string to avoid "UnicodeEncodeError: 'ascii' + # codec can't encode character ..." in Python 2 when a format + # argument (e.g. `output`) has a non-ascii character. + u'Command errored out with exit status {exit_status}:\n' + ' command: {command_display}\n' + ' cwd: {cwd_display}\n' + 'Complete output ({line_count} lines):\n{output}{divider}' + ).format( + exit_status=exit_status, + command_display=command_display, + cwd_display=cwd_display, + line_count=len(lines), + output=output, + divider=LOG_DIVIDER, + ) + return msg + + +def call_subprocess( + cmd, # type: Union[List[str], CommandArgs] + show_stdout=False, # type: bool + cwd=None, # type: Optional[str] + on_returncode='raise', # type: str + extra_ok_returncodes=None, # type: Optional[Iterable[int]] + command_desc=None, # type: Optional[str] + extra_environ=None, # type: Optional[Mapping[str, Any]] + unset_environ=None, # type: Optional[Iterable[str]] + spinner=None, # type: Optional[SpinnerInterface] + log_failed_cmd=True # type: Optional[bool] +): + # type: (...) -> Text + """ + Args: + show_stdout: if true, use INFO to log the subprocess's stderr and + stdout streams. Otherwise, use DEBUG. Defaults to False. + extra_ok_returncodes: an iterable of integer return codes that are + acceptable, in addition to 0. Defaults to None, which means []. + unset_environ: an iterable of environment variable names to unset + prior to calling subprocess.Popen(). + log_failed_cmd: if false, failed commands are not logged, only raised. + """ + if extra_ok_returncodes is None: + extra_ok_returncodes = [] + if unset_environ is None: + unset_environ = [] + # Most places in pip use show_stdout=False. What this means is-- + # + # - We connect the child's output (combined stderr and stdout) to a + # single pipe, which we read. + # - We log this output to stderr at DEBUG level as it is received. + # - If DEBUG logging isn't enabled (e.g. if --verbose logging wasn't + # requested), then we show a spinner so the user can still see the + # subprocess is in progress. + # - If the subprocess exits with an error, we log the output to stderr + # at ERROR level if it hasn't already been displayed to the console + # (e.g. if --verbose logging wasn't enabled). This way we don't log + # the output to the console twice. + # + # If show_stdout=True, then the above is still done, but with DEBUG + # replaced by INFO. + if show_stdout: + # Then log the subprocess output at INFO level. + log_subprocess = subprocess_logger.info + used_level = logging.INFO + else: + # Then log the subprocess output using DEBUG. This also ensures + # it will be logged to the log file (aka user_log), if enabled. + log_subprocess = subprocess_logger.debug + used_level = logging.DEBUG + + # Whether the subprocess will be visible in the console. + showing_subprocess = subprocess_logger.getEffectiveLevel() <= used_level + + # Only use the spinner if we're not showing the subprocess output + # and we have a spinner. + use_spinner = not showing_subprocess and spinner is not None + + if command_desc is None: + command_desc = format_command_args(cmd) + + log_subprocess("Running command %s", command_desc) + env = os.environ.copy() + if extra_environ: + env.update(extra_environ) + for name in unset_environ: + env.pop(name, None) + try: + proc = subprocess.Popen( + # Convert HiddenText objects to the underlying str. + reveal_command_args(cmd), + stderr=subprocess.STDOUT, stdin=subprocess.PIPE, + stdout=subprocess.PIPE, cwd=cwd, env=env, + ) + proc.stdin.close() + except Exception as exc: + if log_failed_cmd: + subprocess_logger.critical( + "Error %s while executing command %s", exc, command_desc, + ) + raise + all_output = [] + while True: + # The "line" value is a unicode string in Python 2. + line = console_to_str(proc.stdout.readline()) + if not line: + break + line = line.rstrip() + all_output.append(line + '\n') + + # Show the line immediately. + log_subprocess(line) + # Update the spinner. + if use_spinner: + spinner.spin() + try: + proc.wait() + finally: + if proc.stdout: + proc.stdout.close() + proc_had_error = ( + proc.returncode and proc.returncode not in extra_ok_returncodes + ) + if use_spinner: + if proc_had_error: + spinner.finish("error") + else: + spinner.finish("done") + if proc_had_error: + if on_returncode == 'raise': + if not showing_subprocess and log_failed_cmd: + # Then the subprocess streams haven't been logged to the + # console yet. + msg = make_subprocess_output_error( + cmd_args=cmd, + cwd=cwd, + lines=all_output, + exit_status=proc.returncode, + ) + subprocess_logger.error(msg) + exc_msg = ( + 'Command errored out with exit status {}: {} ' + 'Check the logs for full command output.' + ).format(proc.returncode, command_desc) + raise InstallationError(exc_msg) + elif on_returncode == 'warn': + subprocess_logger.warning( + 'Command "{}" had error code {} in {}'.format( + command_desc, proc.returncode, cwd) + ) + elif on_returncode == 'ignore': + pass + else: + raise ValueError('Invalid value: on_returncode={!r}'.format( + on_returncode)) + return ''.join(all_output) + + +def runner_with_spinner_message(message): + # type: (str) -> Callable[..., None] + """Provide a subprocess_runner that shows a spinner message. + + Intended for use with for pep517's Pep517HookCaller. Thus, the runner has + an API that matches what's expected by Pep517HookCaller.subprocess_runner. + """ + + def runner( + cmd, # type: List[str] + cwd=None, # type: Optional[str] + extra_environ=None # type: Optional[Mapping[str, Any]] + ): + # type: (...) -> None + with open_spinner(message) as spinner: + call_subprocess( + cmd, + cwd=cwd, + extra_environ=extra_environ, + spinner=spinner, + ) + + return runner diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/temp_dir.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/temp_dir.py new file mode 100644 index 0000000..201ba6d --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/utils/temp_dir.py @@ -0,0 +1,271 @@ +from __future__ import absolute_import + +import errno +import itertools +import logging +import os.path +import tempfile +from contextlib import contextmanager + +from pip._vendor.contextlib2 import ExitStack + +from pip._internal.utils.misc import enum, rmtree +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Any, Dict, Iterator, Optional, TypeVar, Union + + _T = TypeVar('_T', bound='TempDirectory') + + +logger = logging.getLogger(__name__) + + +# Kinds of temporary directories. Only needed for ones that are +# globally-managed. +tempdir_kinds = enum( + BUILD_ENV="build-env", + EPHEM_WHEEL_CACHE="ephem-wheel-cache", + REQ_BUILD="req-build", +) + + +_tempdir_manager = None # type: Optional[ExitStack] + + +@contextmanager +def global_tempdir_manager(): + # type: () -> Iterator[None] + global _tempdir_manager + with ExitStack() as stack: + old_tempdir_manager, _tempdir_manager = _tempdir_manager, stack + try: + yield + finally: + _tempdir_manager = old_tempdir_manager + + +class TempDirectoryTypeRegistry(object): + """Manages temp directory behavior + """ + + def __init__(self): + # type: () -> None + self._should_delete = {} # type: Dict[str, bool] + + def set_delete(self, kind, value): + # type: (str, bool) -> None + """Indicate whether a TempDirectory of the given kind should be + auto-deleted. + """ + self._should_delete[kind] = value + + def get_delete(self, kind): + # type: (str) -> bool + """Get configured auto-delete flag for a given TempDirectory type, + default True. + """ + return self._should_delete.get(kind, True) + + +_tempdir_registry = None # type: Optional[TempDirectoryTypeRegistry] + + +@contextmanager +def tempdir_registry(): + # type: () -> Iterator[TempDirectoryTypeRegistry] + """Provides a scoped global tempdir registry that can be used to dictate + whether directories should be deleted. + """ + global _tempdir_registry + old_tempdir_registry = _tempdir_registry + _tempdir_registry = TempDirectoryTypeRegistry() + try: + yield _tempdir_registry + finally: + _tempdir_registry = old_tempdir_registry + + +class _Default(object): + pass + + +_default = _Default() + + +class TempDirectory(object): + """Helper class that owns and cleans up a temporary directory. + + This class can be used as a context manager or as an OO representation of a + temporary directory. + + Attributes: + path + Location to the created temporary directory + delete + Whether the directory should be deleted when exiting + (when used as a contextmanager) + + Methods: + cleanup() + Deletes the temporary directory + + When used as a context manager, if the delete attribute is True, on + exiting the context the temporary directory is deleted. + """ + + def __init__( + self, + path=None, # type: Optional[str] + delete=_default, # type: Union[bool, None, _Default] + kind="temp", # type: str + globally_managed=False, # type: bool + ): + super(TempDirectory, self).__init__() + + if delete is _default: + if path is not None: + # If we were given an explicit directory, resolve delete option + # now. + delete = False + else: + # Otherwise, we wait until cleanup and see what + # tempdir_registry says. + delete = None + + if path is None: + path = self._create(kind) + + self._path = path + self._deleted = False + self.delete = delete + self.kind = kind + + if globally_managed: + assert _tempdir_manager is not None + _tempdir_manager.enter_context(self) + + @property + def path(self): + # type: () -> str + assert not self._deleted, ( + "Attempted to access deleted path: {}".format(self._path) + ) + return self._path + + def __repr__(self): + # type: () -> str + return "<{} {!r}>".format(self.__class__.__name__, self.path) + + def __enter__(self): + # type: (_T) -> _T + return self + + def __exit__(self, exc, value, tb): + # type: (Any, Any, Any) -> None + if self.delete is not None: + delete = self.delete + elif _tempdir_registry: + delete = _tempdir_registry.get_delete(self.kind) + else: + delete = True + + if delete: + self.cleanup() + + def _create(self, kind): + # type: (str) -> str + """Create a temporary directory and store its path in self.path + """ + # We realpath here because some systems have their default tmpdir + # symlinked to another directory. This tends to confuse build + # scripts, so we canonicalize the path by traversing potential + # symlinks here. + path = os.path.realpath( + tempfile.mkdtemp(prefix="pip-{}-".format(kind)) + ) + logger.debug("Created temporary directory: {}".format(path)) + return path + + def cleanup(self): + # type: () -> None + """Remove the temporary directory created and reset state + """ + self._deleted = True + if os.path.exists(self._path): + rmtree(self._path) + + +class AdjacentTempDirectory(TempDirectory): + """Helper class that creates a temporary directory adjacent to a real one. + + Attributes: + original + The original directory to create a temp directory for. + path + After calling create() or entering, contains the full + path to the temporary directory. + delete + Whether the directory should be deleted when exiting + (when used as a contextmanager) + + """ + # The characters that may be used to name the temp directory + # We always prepend a ~ and then rotate through these until + # a usable name is found. + # pkg_resources raises a different error for .dist-info folder + # with leading '-' and invalid metadata + LEADING_CHARS = "-~.=%0123456789" + + def __init__(self, original, delete=None): + # type: (str, Optional[bool]) -> None + self.original = original.rstrip('/\\') + super(AdjacentTempDirectory, self).__init__(delete=delete) + + @classmethod + def _generate_names(cls, name): + # type: (str) -> Iterator[str] + """Generates a series of temporary names. + + The algorithm replaces the leading characters in the name + with ones that are valid filesystem characters, but are not + valid package names (for both Python and pip definitions of + package). + """ + for i in range(1, len(name)): + for candidate in itertools.combinations_with_replacement( + cls.LEADING_CHARS, i - 1): + new_name = '~' + ''.join(candidate) + name[i:] + if new_name != name: + yield new_name + + # If we make it this far, we will have to make a longer name + for i in range(len(cls.LEADING_CHARS)): + for candidate in itertools.combinations_with_replacement( + cls.LEADING_CHARS, i): + new_name = '~' + ''.join(candidate) + name + if new_name != name: + yield new_name + + def _create(self, kind): + # type: (str) -> str + root, name = os.path.split(self.original) + for candidate in self._generate_names(name): + path = os.path.join(root, candidate) + try: + os.mkdir(path) + except OSError as ex: + # Continue if the name exists already + if ex.errno != errno.EEXIST: + raise + else: + path = os.path.realpath(path) + break + else: + # Final fallback on the default behavior. + path = os.path.realpath( + tempfile.mkdtemp(prefix="pip-{}-".format(kind)) + ) + + logger.debug("Created temporary directory: {}".format(path)) + return path diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/typing.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/typing.py new file mode 100644 index 0000000..8505a29 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/utils/typing.py @@ -0,0 +1,38 @@ +"""For neatly implementing static typing in pip. + +`mypy` - the static type analysis tool we use - uses the `typing` module, which +provides core functionality fundamental to mypy's functioning. + +Generally, `typing` would be imported at runtime and used in that fashion - +it acts as a no-op at runtime and does not have any run-time overhead by +design. + +As it turns out, `typing` is not vendorable - it uses separate sources for +Python 2/Python 3. Thus, this codebase can not expect it to be present. +To work around this, mypy allows the typing import to be behind a False-y +optional to prevent it from running at runtime and type-comments can be used +to remove the need for the types to be accessible directly during runtime. + +This module provides the False-y guard in a nicely named fashion so that a +curious maintainer can reach here to read this. + +In pip, all static-typing related imports should be guarded as follows: + + from pip._internal.utils.typing import MYPY_CHECK_RUNNING + + if MYPY_CHECK_RUNNING: + from typing import ... + +Ref: https://github.com/python/mypy/issues/3216 +""" + +MYPY_CHECK_RUNNING = False + + +if MYPY_CHECK_RUNNING: + from typing import cast +else: + # typing's cast() is needed at runtime, but we don't want to import typing. + # Thus, we use a dummy no-op version, which we tell mypy to ignore. + def cast(type_, value): # type: ignore + return value diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/unpacking.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/unpacking.py new file mode 100644 index 0000000..7252dc2 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/utils/unpacking.py @@ -0,0 +1,272 @@ +"""Utilities related archives. +""" + +# The following comment should be removed at some point in the future. +# mypy: strict-optional=False +# mypy: disallow-untyped-defs=False + +from __future__ import absolute_import + +import logging +import os +import shutil +import stat +import tarfile +import zipfile + +from pip._internal.exceptions import InstallationError +from pip._internal.utils.filetypes import ( + BZ2_EXTENSIONS, + TAR_EXTENSIONS, + XZ_EXTENSIONS, + ZIP_EXTENSIONS, +) +from pip._internal.utils.misc import ensure_dir +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Iterable, List, Optional, Text, Union + + +logger = logging.getLogger(__name__) + + +SUPPORTED_EXTENSIONS = ZIP_EXTENSIONS + TAR_EXTENSIONS + +try: + import bz2 # noqa + SUPPORTED_EXTENSIONS += BZ2_EXTENSIONS +except ImportError: + logger.debug('bz2 module is not available') + +try: + # Only for Python 3.3+ + import lzma # noqa + SUPPORTED_EXTENSIONS += XZ_EXTENSIONS +except ImportError: + logger.debug('lzma module is not available') + + +def current_umask(): + """Get the current umask which involves having to set it temporarily.""" + mask = os.umask(0) + os.umask(mask) + return mask + + +def split_leading_dir(path): + # type: (Union[str, Text]) -> List[Union[str, Text]] + path = path.lstrip('/').lstrip('\\') + if ( + '/' in path and ( + ('\\' in path and path.find('/') < path.find('\\')) or + '\\' not in path + ) + ): + return path.split('/', 1) + elif '\\' in path: + return path.split('\\', 1) + else: + return [path, ''] + + +def has_leading_dir(paths): + # type: (Iterable[Union[str, Text]]) -> bool + """Returns true if all the paths have the same leading path name + (i.e., everything is in one subdirectory in an archive)""" + common_prefix = None + for path in paths: + prefix, rest = split_leading_dir(path) + if not prefix: + return False + elif common_prefix is None: + common_prefix = prefix + elif prefix != common_prefix: + return False + return True + + +def is_within_directory(directory, target): + # type: ((Union[str, Text]), (Union[str, Text])) -> bool + """ + Return true if the absolute path of target is within the directory + """ + abs_directory = os.path.abspath(directory) + abs_target = os.path.abspath(target) + + prefix = os.path.commonprefix([abs_directory, abs_target]) + return prefix == abs_directory + + +def unzip_file(filename, location, flatten=True): + # type: (str, str, bool) -> None + """ + Unzip the file (with path `filename`) to the destination `location`. All + files are written based on system defaults and umask (i.e. permissions are + not preserved), except that regular file members with any execute + permissions (user, group, or world) have "chmod +x" applied after being + written. Note that for windows, any execute changes using os.chmod are + no-ops per the python docs. + """ + ensure_dir(location) + zipfp = open(filename, 'rb') + try: + zip = zipfile.ZipFile(zipfp, allowZip64=True) + leading = has_leading_dir(zip.namelist()) and flatten + for info in zip.infolist(): + name = info.filename + fn = name + if leading: + fn = split_leading_dir(name)[1] + fn = os.path.join(location, fn) + dir = os.path.dirname(fn) + if not is_within_directory(location, fn): + message = ( + 'The zip file ({}) has a file ({}) trying to install ' + 'outside target directory ({})' + ) + raise InstallationError(message.format(filename, fn, location)) + if fn.endswith('/') or fn.endswith('\\'): + # A directory + ensure_dir(fn) + else: + ensure_dir(dir) + # Don't use read() to avoid allocating an arbitrarily large + # chunk of memory for the file's content + fp = zip.open(name) + try: + with open(fn, 'wb') as destfp: + shutil.copyfileobj(fp, destfp) + finally: + fp.close() + mode = info.external_attr >> 16 + # if mode and regular file and any execute permissions for + # user/group/world? + if mode and stat.S_ISREG(mode) and mode & 0o111: + # make dest file have execute for user/group/world + # (chmod +x) no-op on windows per python docs + os.chmod(fn, (0o777 - current_umask() | 0o111)) + finally: + zipfp.close() + + +def untar_file(filename, location): + # type: (str, str) -> None + """ + Untar the file (with path `filename`) to the destination `location`. + All files are written based on system defaults and umask (i.e. permissions + are not preserved), except that regular file members with any execute + permissions (user, group, or world) have "chmod +x" applied after being + written. Note that for windows, any execute changes using os.chmod are + no-ops per the python docs. + """ + ensure_dir(location) + if filename.lower().endswith('.gz') or filename.lower().endswith('.tgz'): + mode = 'r:gz' + elif filename.lower().endswith(BZ2_EXTENSIONS): + mode = 'r:bz2' + elif filename.lower().endswith(XZ_EXTENSIONS): + mode = 'r:xz' + elif filename.lower().endswith('.tar'): + mode = 'r' + else: + logger.warning( + 'Cannot determine compression type for file %s', filename, + ) + mode = 'r:*' + tar = tarfile.open(filename, mode) + try: + leading = has_leading_dir([ + member.name for member in tar.getmembers() + ]) + for member in tar.getmembers(): + fn = member.name + if leading: + # https://github.com/python/mypy/issues/1174 + fn = split_leading_dir(fn)[1] # type: ignore + path = os.path.join(location, fn) + if not is_within_directory(location, path): + message = ( + 'The tar file ({}) has a file ({}) trying to install ' + 'outside target directory ({})' + ) + raise InstallationError( + message.format(filename, path, location) + ) + if member.isdir(): + ensure_dir(path) + elif member.issym(): + try: + # https://github.com/python/typeshed/issues/2673 + tar._extract_member(member, path) # type: ignore + except Exception as exc: + # Some corrupt tar files seem to produce this + # (specifically bad symlinks) + logger.warning( + 'In the tar file %s the member %s is invalid: %s', + filename, member.name, exc, + ) + continue + else: + try: + fp = tar.extractfile(member) + except (KeyError, AttributeError) as exc: + # Some corrupt tar files seem to produce this + # (specifically bad symlinks) + logger.warning( + 'In the tar file %s the member %s is invalid: %s', + filename, member.name, exc, + ) + continue + ensure_dir(os.path.dirname(path)) + with open(path, 'wb') as destfp: + shutil.copyfileobj(fp, destfp) + fp.close() + # Update the timestamp (useful for cython compiled files) + # https://github.com/python/typeshed/issues/2673 + tar.utime(member, path) # type: ignore + # member have any execute permissions for user/group/world? + if member.mode & 0o111: + # make dest file have execute for user/group/world + # no-op on windows per python docs + os.chmod(path, (0o777 - current_umask() | 0o111)) + finally: + tar.close() + + +def unpack_file( + filename, # type: str + location, # type: str + content_type=None, # type: Optional[str] +): + # type: (...) -> None + filename = os.path.realpath(filename) + if ( + content_type == 'application/zip' or + filename.lower().endswith(ZIP_EXTENSIONS) or + zipfile.is_zipfile(filename) + ): + unzip_file( + filename, + location, + flatten=not filename.endswith('.whl') + ) + elif ( + content_type == 'application/x-gzip' or + tarfile.is_tarfile(filename) or + filename.lower().endswith( + TAR_EXTENSIONS + BZ2_EXTENSIONS + XZ_EXTENSIONS + ) + ): + untar_file(filename, location) + else: + # FIXME: handle? + # FIXME: magic signatures? + logger.critical( + 'Cannot unpack file %s (downloaded from %s, content-type: %s); ' + 'cannot detect archive format', + filename, location, content_type, + ) + raise InstallationError( + 'Cannot determine archive format of {}'.format(location) + ) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/urls.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/urls.py new file mode 100644 index 0000000..f37bc8f --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/utils/urls.py @@ -0,0 +1,55 @@ +import os +import sys + +from pip._vendor.six.moves.urllib import parse as urllib_parse +from pip._vendor.six.moves.urllib import request as urllib_request + +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import Optional, Text, Union + + +def get_url_scheme(url): + # type: (Union[str, Text]) -> Optional[Text] + if ':' not in url: + return None + return url.split(':', 1)[0].lower() + + +def path_to_url(path): + # type: (Union[str, Text]) -> str + """ + Convert a path to a file: URL. The path will be made absolute and have + quoted path parts. + """ + path = os.path.normpath(os.path.abspath(path)) + url = urllib_parse.urljoin('file:', urllib_request.pathname2url(path)) + return url + + +def url_to_path(url): + # type: (str) -> str + """ + Convert a file: URL to a path. + """ + assert url.startswith('file:'), ( + "You can only turn file: urls into filenames (not {url!r})" + .format(**locals())) + + _, netloc, path, _, _ = urllib_parse.urlsplit(url) + + if not netloc or netloc == 'localhost': + # According to RFC 8089, same as empty authority. + netloc = '' + elif sys.platform == 'win32': + # If we have a UNC path, prepend UNC share notation. + netloc = '\\\\' + netloc + else: + raise ValueError( + 'non-local file URIs are not supported on this platform: {url!r}' + .format(**locals()) + ) + + path = urllib_request.url2pathname(netloc + path) + return path diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/virtualenv.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/virtualenv.py new file mode 100644 index 0000000..596a69a --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/utils/virtualenv.py @@ -0,0 +1,116 @@ +from __future__ import absolute_import + +import logging +import os +import re +import site +import sys + +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from typing import List, Optional + +logger = logging.getLogger(__name__) +_INCLUDE_SYSTEM_SITE_PACKAGES_REGEX = re.compile( + r"include-system-site-packages\s*=\s*(?Ptrue|false)" +) + + +def _running_under_venv(): + # type: () -> bool + """Checks if sys.base_prefix and sys.prefix match. + + This handles PEP 405 compliant virtual environments. + """ + return sys.prefix != getattr(sys, "base_prefix", sys.prefix) + + +def _running_under_regular_virtualenv(): + # type: () -> bool + """Checks if sys.real_prefix is set. + + This handles virtual environments created with pypa's virtualenv. + """ + # pypa/virtualenv case + return hasattr(sys, 'real_prefix') + + +def running_under_virtualenv(): + # type: () -> bool + """Return True if we're running inside a virtualenv, False otherwise. + """ + return _running_under_venv() or _running_under_regular_virtualenv() + + +def _get_pyvenv_cfg_lines(): + # type: () -> Optional[List[str]] + """Reads {sys.prefix}/pyvenv.cfg and returns its contents as list of lines + + Returns None, if it could not read/access the file. + """ + pyvenv_cfg_file = os.path.join(sys.prefix, 'pyvenv.cfg') + try: + with open(pyvenv_cfg_file) as f: + return f.read().splitlines() # avoids trailing newlines + except IOError: + return None + + +def _no_global_under_venv(): + # type: () -> bool + """Check `{sys.prefix}/pyvenv.cfg` for system site-packages inclusion + + PEP 405 specifies that when system site-packages are not supposed to be + visible from a virtual environment, `pyvenv.cfg` must contain the following + line: + + include-system-site-packages = false + + Additionally, log a warning if accessing the file fails. + """ + cfg_lines = _get_pyvenv_cfg_lines() + if cfg_lines is None: + # We're not in a "sane" venv, so assume there is no system + # site-packages access (since that's PEP 405's default state). + logger.warning( + "Could not access 'pyvenv.cfg' despite a virtual environment " + "being active. Assuming global site-packages is not accessible " + "in this environment." + ) + return True + + for line in cfg_lines: + match = _INCLUDE_SYSTEM_SITE_PACKAGES_REGEX.match(line) + if match is not None and match.group('value') == 'false': + return True + return False + + +def _no_global_under_regular_virtualenv(): + # type: () -> bool + """Check if "no-global-site-packages.txt" exists beside site.py + + This mirrors logic in pypa/virtualenv for determining whether system + site-packages are visible in the virtual environment. + """ + site_mod_dir = os.path.dirname(os.path.abspath(site.__file__)) + no_global_site_packages_file = os.path.join( + site_mod_dir, 'no-global-site-packages.txt', + ) + return os.path.exists(no_global_site_packages_file) + + +def virtualenv_no_global(): + # type: () -> bool + """Returns a boolean, whether running in venv with no system site-packages. + """ + # PEP 405 compliance needs to be checked first since virtualenv >=20 would + # return True for both checks, but is only able to use the PEP 405 config. + if _running_under_venv(): + return _no_global_under_venv() + + if _running_under_regular_virtualenv(): + return _no_global_under_regular_virtualenv() + + return False diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/wheel.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/wheel.py new file mode 100644 index 0000000..3ebb771 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/utils/wheel.py @@ -0,0 +1,225 @@ +"""Support functions for working with wheel files. +""" + +from __future__ import absolute_import + +import logging +from email.parser import Parser +from zipfile import ZipFile + +from pip._vendor.packaging.utils import canonicalize_name +from pip._vendor.pkg_resources import DistInfoDistribution +from pip._vendor.six import PY2, ensure_str + +from pip._internal.exceptions import UnsupportedWheel +from pip._internal.utils.pkg_resources import DictMetadata +from pip._internal.utils.typing import MYPY_CHECK_RUNNING + +if MYPY_CHECK_RUNNING: + from email.message import Message + from typing import Dict, Tuple + + from pip._vendor.pkg_resources import Distribution + +if PY2: + from zipfile import BadZipfile as BadZipFile +else: + from zipfile import BadZipFile + + +VERSION_COMPATIBLE = (1, 0) + + +logger = logging.getLogger(__name__) + + +class WheelMetadata(DictMetadata): + """Metadata provider that maps metadata decoding exceptions to our + internal exception type. + """ + def __init__(self, metadata, wheel_name): + # type: (Dict[str, bytes], str) -> None + super(WheelMetadata, self).__init__(metadata) + self._wheel_name = wheel_name + + def get_metadata(self, name): + # type: (str) -> str + try: + return super(WheelMetadata, self).get_metadata(name) + except UnicodeDecodeError as e: + # Augment the default error with the origin of the file. + raise UnsupportedWheel( + "Error decoding metadata for {}: {}".format( + self._wheel_name, e + ) + ) + + +def pkg_resources_distribution_for_wheel(wheel_zip, name, location): + # type: (ZipFile, str, str) -> Distribution + """Get a pkg_resources distribution given a wheel. + + :raises UnsupportedWheel: on any errors + """ + info_dir, _ = parse_wheel(wheel_zip, name) + + metadata_files = [ + p for p in wheel_zip.namelist() if p.startswith("{}/".format(info_dir)) + ] + + metadata_text = {} # type: Dict[str, bytes] + for path in metadata_files: + # If a flag is set, namelist entries may be unicode in Python 2. + # We coerce them to native str type to match the types used in the rest + # of the code. This cannot fail because unicode can always be encoded + # with UTF-8. + full_path = ensure_str(path) + _, metadata_name = full_path.split("/", 1) + + try: + metadata_text[metadata_name] = read_wheel_metadata_file( + wheel_zip, full_path + ) + except UnsupportedWheel as e: + raise UnsupportedWheel( + "{} has an invalid wheel, {}".format(name, str(e)) + ) + + metadata = WheelMetadata(metadata_text, location) + + return DistInfoDistribution( + location=location, metadata=metadata, project_name=name + ) + + +def parse_wheel(wheel_zip, name): + # type: (ZipFile, str) -> Tuple[str, Message] + """Extract information from the provided wheel, ensuring it meets basic + standards. + + Returns the name of the .dist-info directory and the parsed WHEEL metadata. + """ + try: + info_dir = wheel_dist_info_dir(wheel_zip, name) + metadata = wheel_metadata(wheel_zip, info_dir) + version = wheel_version(metadata) + except UnsupportedWheel as e: + raise UnsupportedWheel( + "{} has an invalid wheel, {}".format(name, str(e)) + ) + + check_compatibility(version, name) + + return info_dir, metadata + + +def wheel_dist_info_dir(source, name): + # type: (ZipFile, str) -> str + """Returns the name of the contained .dist-info directory. + + Raises AssertionError or UnsupportedWheel if not found, >1 found, or + it doesn't match the provided name. + """ + # Zip file path separators must be / + subdirs = list(set(p.split("/")[0] for p in source.namelist())) + + info_dirs = [s for s in subdirs if s.endswith('.dist-info')] + + if not info_dirs: + raise UnsupportedWheel(".dist-info directory not found") + + if len(info_dirs) > 1: + raise UnsupportedWheel( + "multiple .dist-info directories found: {}".format( + ", ".join(info_dirs) + ) + ) + + info_dir = info_dirs[0] + + info_dir_name = canonicalize_name(info_dir) + canonical_name = canonicalize_name(name) + if not info_dir_name.startswith(canonical_name): + raise UnsupportedWheel( + ".dist-info directory {!r} does not start with {!r}".format( + info_dir, canonical_name + ) + ) + + # Zip file paths can be unicode or str depending on the zip entry flags, + # so normalize it. + return ensure_str(info_dir) + + +def read_wheel_metadata_file(source, path): + # type: (ZipFile, str) -> bytes + try: + return source.read(path) + # BadZipFile for general corruption, KeyError for missing entry, + # and RuntimeError for password-protected files + except (BadZipFile, KeyError, RuntimeError) as e: + raise UnsupportedWheel( + "could not read {!r} file: {!r}".format(path, e) + ) + + +def wheel_metadata(source, dist_info_dir): + # type: (ZipFile, str) -> Message + """Return the WHEEL metadata of an extracted wheel, if possible. + Otherwise, raise UnsupportedWheel. + """ + path = "{}/WHEEL".format(dist_info_dir) + # Zip file path separators must be / + wheel_contents = read_wheel_metadata_file(source, path) + + try: + wheel_text = ensure_str(wheel_contents) + except UnicodeDecodeError as e: + raise UnsupportedWheel("error decoding {!r}: {!r}".format(path, e)) + + # FeedParser (used by Parser) does not raise any exceptions. The returned + # message may have .defects populated, but for backwards-compatibility we + # currently ignore them. + return Parser().parsestr(wheel_text) + + +def wheel_version(wheel_data): + # type: (Message) -> Tuple[int, ...] + """Given WHEEL metadata, return the parsed Wheel-Version. + Otherwise, raise UnsupportedWheel. + """ + version_text = wheel_data["Wheel-Version"] + if version_text is None: + raise UnsupportedWheel("WHEEL is missing Wheel-Version") + + version = version_text.strip() + + try: + return tuple(map(int, version.split('.'))) + except ValueError: + raise UnsupportedWheel("invalid Wheel-Version: {!r}".format(version)) + + +def check_compatibility(version, name): + # type: (Tuple[int, ...], str) -> None + """Raises errors or warns if called with an incompatible Wheel-Version. + + pip should refuse to install a Wheel-Version that's a major series + ahead of what it's compatible with (e.g 2.0 > 1.1); and warn when + installing a version only minor version ahead (e.g 1.2 > 1.1). + + version: a 2-tuple representing a Wheel-Version (Major, Minor) + name: name of wheel or package to raise exception about + + :raises UnsupportedWheel: when an incompatible Wheel-Version is given + """ + if version[0] > VERSION_COMPATIBLE[0]: + raise UnsupportedWheel( + "{}'s Wheel-Version ({}) is not compatible with this version " + "of pip".format(name, '.'.join(map(str, version))) + ) + elif version > VERSION_COMPATIBLE: + logger.warning( + 'Installing from a newer Wheel-Version (%s)', + '.'.join(map(str, version)), + ) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/vcs/__init__.py b/venv/lib/python3.8/site-packages/pip/_internal/vcs/__init__.py new file mode 100644 index 0000000..2a4eb13 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/vcs/__init__.py @@ -0,0 +1,15 @@ +# Expose a limited set of classes and functions so callers outside of +# the vcs package don't need to import deeper than `pip._internal.vcs`. +# (The test directory and imports protected by MYPY_CHECK_RUNNING may +# still need to import from a vcs sub-package.) +# Import all vcs modules to register each VCS in the VcsSupport object. +import pip._internal.vcs.bazaar +import pip._internal.vcs.git +import pip._internal.vcs.mercurial +import pip._internal.vcs.subversion # noqa: F401 +from pip._internal.vcs.versioncontrol import ( # noqa: F401 + RemoteNotFoundError, + is_url, + make_vcs_requirement_url, + vcs, +) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/vcs/bazaar.py b/venv/lib/python3.8/site-packages/pip/_internal/vcs/bazaar.py new file mode 100644 index 0000000..347c06f --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/vcs/bazaar.py @@ -0,0 +1,120 @@ +# The following comment should be removed at some point in the future. +# mypy: disallow-untyped-defs=False + +from __future__ import absolute_import + +import logging +import os + +from pip._vendor.six.moves.urllib import parse as urllib_parse + +from pip._internal.utils.misc import display_path, rmtree +from pip._internal.utils.subprocess import make_command +from pip._internal.utils.typing import MYPY_CHECK_RUNNING +from pip._internal.utils.urls import path_to_url +from pip._internal.vcs.versioncontrol import VersionControl, vcs + +if MYPY_CHECK_RUNNING: + from typing import Optional, Tuple + from pip._internal.utils.misc import HiddenText + from pip._internal.vcs.versioncontrol import AuthInfo, RevOptions + + +logger = logging.getLogger(__name__) + + +class Bazaar(VersionControl): + name = 'bzr' + dirname = '.bzr' + repo_name = 'branch' + schemes = ( + 'bzr', 'bzr+http', 'bzr+https', 'bzr+ssh', 'bzr+sftp', 'bzr+ftp', + 'bzr+lp', + ) + + def __init__(self, *args, **kwargs): + super(Bazaar, self).__init__(*args, **kwargs) + # This is only needed for python <2.7.5 + # Register lp but do not expose as a scheme to support bzr+lp. + if getattr(urllib_parse, 'uses_fragment', None): + urllib_parse.uses_fragment.extend(['lp']) + + @staticmethod + def get_base_rev_args(rev): + return ['-r', rev] + + def export(self, location, url): + # type: (str, HiddenText) -> None + """ + Export the Bazaar repository at the url to the destination location + """ + # Remove the location to make sure Bazaar can export it correctly + if os.path.exists(location): + rmtree(location) + + url, rev_options = self.get_url_rev_options(url) + self.run_command( + make_command('export', location, url, rev_options.to_args()), + show_stdout=False, + ) + + def fetch_new(self, dest, url, rev_options): + # type: (str, HiddenText, RevOptions) -> None + rev_display = rev_options.to_display() + logger.info( + 'Checking out %s%s to %s', + url, + rev_display, + display_path(dest), + ) + cmd_args = ( + make_command('branch', '-q', rev_options.to_args(), url, dest) + ) + self.run_command(cmd_args) + + def switch(self, dest, url, rev_options): + # type: (str, HiddenText, RevOptions) -> None + self.run_command(make_command('switch', url), cwd=dest) + + def update(self, dest, url, rev_options): + # type: (str, HiddenText, RevOptions) -> None + cmd_args = make_command('pull', '-q', rev_options.to_args()) + self.run_command(cmd_args, cwd=dest) + + @classmethod + def get_url_rev_and_auth(cls, url): + # type: (str) -> Tuple[str, Optional[str], AuthInfo] + # hotfix the URL scheme after removing bzr+ from bzr+ssh:// readd it + url, rev, user_pass = super(Bazaar, cls).get_url_rev_and_auth(url) + if url.startswith('ssh://'): + url = 'bzr+' + url + return url, rev, user_pass + + @classmethod + def get_remote_url(cls, location): + urls = cls.run_command(['info'], show_stdout=False, cwd=location) + for line in urls.splitlines(): + line = line.strip() + for x in ('checkout of branch: ', + 'parent branch: '): + if line.startswith(x): + repo = line.split(x)[1] + if cls._is_local_repository(repo): + return path_to_url(repo) + return repo + return None + + @classmethod + def get_revision(cls, location): + revision = cls.run_command( + ['revno'], show_stdout=False, cwd=location, + ) + return revision.splitlines()[-1] + + @classmethod + def is_commit_id_equal(cls, dest, name): + """Always assume the versions don't match""" + return False + + +vcs.register(Bazaar) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/vcs/git.py b/venv/lib/python3.8/site-packages/pip/_internal/vcs/git.py new file mode 100644 index 0000000..e173ec8 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/vcs/git.py @@ -0,0 +1,394 @@ +# The following comment should be removed at some point in the future. +# mypy: disallow-untyped-defs=False + +from __future__ import absolute_import + +import logging +import os.path +import re + +from pip._vendor.packaging.version import parse as parse_version +from pip._vendor.six.moves.urllib import parse as urllib_parse +from pip._vendor.six.moves.urllib import request as urllib_request + +from pip._internal.exceptions import BadCommand, InstallationError +from pip._internal.utils.misc import display_path, hide_url +from pip._internal.utils.subprocess import make_command +from pip._internal.utils.temp_dir import TempDirectory +from pip._internal.utils.typing import MYPY_CHECK_RUNNING +from pip._internal.vcs.versioncontrol import ( + RemoteNotFoundError, + VersionControl, + find_path_to_setup_from_repo_root, + vcs, +) + +if MYPY_CHECK_RUNNING: + from typing import Optional, Tuple + from pip._internal.utils.misc import HiddenText + from pip._internal.vcs.versioncontrol import AuthInfo, RevOptions + + +urlsplit = urllib_parse.urlsplit +urlunsplit = urllib_parse.urlunsplit + + +logger = logging.getLogger(__name__) + + +HASH_REGEX = re.compile('^[a-fA-F0-9]{40}$') + + +def looks_like_hash(sha): + return bool(HASH_REGEX.match(sha)) + + +class Git(VersionControl): + name = 'git' + dirname = '.git' + repo_name = 'clone' + schemes = ( + 'git', 'git+http', 'git+https', 'git+ssh', 'git+git', 'git+file', + ) + # Prevent the user's environment variables from interfering with pip: + # https://github.com/pypa/pip/issues/1130 + unset_environ = ('GIT_DIR', 'GIT_WORK_TREE') + default_arg_rev = 'HEAD' + + @staticmethod + def get_base_rev_args(rev): + return [rev] + + def is_immutable_rev_checkout(self, url, dest): + # type: (str, str) -> bool + _, rev_options = self.get_url_rev_options(hide_url(url)) + if not rev_options.rev: + return False + if not self.is_commit_id_equal(dest, rev_options.rev): + # the current commit is different from rev, + # which means rev was something else than a commit hash + return False + # return False in the rare case rev is both a commit hash + # and a tag or a branch; we don't want to cache in that case + # because that branch/tag could point to something else in the future + is_tag_or_branch = bool( + self.get_revision_sha(dest, rev_options.rev)[0] + ) + return not is_tag_or_branch + + def get_git_version(self): + VERSION_PFX = 'git version ' + version = self.run_command(['version'], show_stdout=False) + if version.startswith(VERSION_PFX): + version = version[len(VERSION_PFX):].split()[0] + else: + version = '' + # get first 3 positions of the git version because + # on windows it is x.y.z.windows.t, and this parses as + # LegacyVersion which always smaller than a Version. + version = '.'.join(version.split('.')[:3]) + return parse_version(version) + + @classmethod + def get_current_branch(cls, location): + """ + Return the current branch, or None if HEAD isn't at a branch + (e.g. detached HEAD). + """ + # git-symbolic-ref exits with empty stdout if "HEAD" is a detached + # HEAD rather than a symbolic ref. In addition, the -q causes the + # command to exit with status code 1 instead of 128 in this case + # and to suppress the message to stderr. + args = ['symbolic-ref', '-q', 'HEAD'] + output = cls.run_command( + args, extra_ok_returncodes=(1, ), show_stdout=False, cwd=location, + ) + ref = output.strip() + + if ref.startswith('refs/heads/'): + return ref[len('refs/heads/'):] + + return None + + def export(self, location, url): + # type: (str, HiddenText) -> None + """Export the Git repository at the url to the destination location""" + if not location.endswith('/'): + location = location + '/' + + with TempDirectory(kind="export") as temp_dir: + self.unpack(temp_dir.path, url=url) + self.run_command( + ['checkout-index', '-a', '-f', '--prefix', location], + show_stdout=False, cwd=temp_dir.path + ) + + @classmethod + def get_revision_sha(cls, dest, rev): + """ + Return (sha_or_none, is_branch), where sha_or_none is a commit hash + if the revision names a remote branch or tag, otherwise None. + + Args: + dest: the repository directory. + rev: the revision name. + """ + # Pass rev to pre-filter the list. + output = cls.run_command(['show-ref', rev], cwd=dest, + show_stdout=False, on_returncode='ignore') + refs = {} + for line in output.strip().splitlines(): + try: + sha, ref = line.split() + except ValueError: + # Include the offending line to simplify troubleshooting if + # this error ever occurs. + raise ValueError('unexpected show-ref line: {!r}'.format(line)) + + refs[ref] = sha + + branch_ref = 'refs/remotes/origin/{}'.format(rev) + tag_ref = 'refs/tags/{}'.format(rev) + + sha = refs.get(branch_ref) + if sha is not None: + return (sha, True) + + sha = refs.get(tag_ref) + + return (sha, False) + + @classmethod + def resolve_revision(cls, dest, url, rev_options): + # type: (str, HiddenText, RevOptions) -> RevOptions + """ + Resolve a revision to a new RevOptions object with the SHA1 of the + branch, tag, or ref if found. + + Args: + rev_options: a RevOptions object. + """ + rev = rev_options.arg_rev + # The arg_rev property's implementation for Git ensures that the + # rev return value is always non-None. + assert rev is not None + + sha, is_branch = cls.get_revision_sha(dest, rev) + + if sha is not None: + rev_options = rev_options.make_new(sha) + rev_options.branch_name = rev if is_branch else None + + return rev_options + + # Do not show a warning for the common case of something that has + # the form of a Git commit hash. + if not looks_like_hash(rev): + logger.warning( + "Did not find branch or tag '%s', assuming revision or ref.", + rev, + ) + + if not rev.startswith('refs/'): + return rev_options + + # If it looks like a ref, we have to fetch it explicitly. + cls.run_command( + make_command('fetch', '-q', url, rev_options.to_args()), + cwd=dest, + ) + # Change the revision to the SHA of the ref we fetched + sha = cls.get_revision(dest, rev='FETCH_HEAD') + rev_options = rev_options.make_new(sha) + + return rev_options + + @classmethod + def is_commit_id_equal(cls, dest, name): + """ + Return whether the current commit hash equals the given name. + + Args: + dest: the repository directory. + name: a string name. + """ + if not name: + # Then avoid an unnecessary subprocess call. + return False + + return cls.get_revision(dest) == name + + def fetch_new(self, dest, url, rev_options): + # type: (str, HiddenText, RevOptions) -> None + rev_display = rev_options.to_display() + logger.info('Cloning %s%s to %s', url, rev_display, display_path(dest)) + self.run_command(make_command('clone', '-q', url, dest)) + + if rev_options.rev: + # Then a specific revision was requested. + rev_options = self.resolve_revision(dest, url, rev_options) + branch_name = getattr(rev_options, 'branch_name', None) + if branch_name is None: + # Only do a checkout if the current commit id doesn't match + # the requested revision. + if not self.is_commit_id_equal(dest, rev_options.rev): + cmd_args = make_command( + 'checkout', '-q', rev_options.to_args(), + ) + self.run_command(cmd_args, cwd=dest) + elif self.get_current_branch(dest) != branch_name: + # Then a specific branch was requested, and that branch + # is not yet checked out. + track_branch = 'origin/{}'.format(branch_name) + cmd_args = [ + 'checkout', '-b', branch_name, '--track', track_branch, + ] + self.run_command(cmd_args, cwd=dest) + + #: repo may contain submodules + self.update_submodules(dest) + + def switch(self, dest, url, rev_options): + # type: (str, HiddenText, RevOptions) -> None + self.run_command( + make_command('config', 'remote.origin.url', url), + cwd=dest, + ) + cmd_args = make_command('checkout', '-q', rev_options.to_args()) + self.run_command(cmd_args, cwd=dest) + + self.update_submodules(dest) + + def update(self, dest, url, rev_options): + # type: (str, HiddenText, RevOptions) -> None + # First fetch changes from the default remote + if self.get_git_version() >= parse_version('1.9.0'): + # fetch tags in addition to everything else + self.run_command(['fetch', '-q', '--tags'], cwd=dest) + else: + self.run_command(['fetch', '-q'], cwd=dest) + # Then reset to wanted revision (maybe even origin/master) + rev_options = self.resolve_revision(dest, url, rev_options) + cmd_args = make_command('reset', '--hard', '-q', rev_options.to_args()) + self.run_command(cmd_args, cwd=dest) + #: update submodules + self.update_submodules(dest) + + @classmethod + def get_remote_url(cls, location): + """ + Return URL of the first remote encountered. + + Raises RemoteNotFoundError if the repository does not have a remote + url configured. + """ + # We need to pass 1 for extra_ok_returncodes since the command + # exits with return code 1 if there are no matching lines. + stdout = cls.run_command( + ['config', '--get-regexp', r'remote\..*\.url'], + extra_ok_returncodes=(1, ), show_stdout=False, cwd=location, + ) + remotes = stdout.splitlines() + try: + found_remote = remotes[0] + except IndexError: + raise RemoteNotFoundError + + for remote in remotes: + if remote.startswith('remote.origin.url '): + found_remote = remote + break + url = found_remote.split(' ')[1] + return url.strip() + + @classmethod + def get_revision(cls, location, rev=None): + if rev is None: + rev = 'HEAD' + current_rev = cls.run_command( + ['rev-parse', rev], show_stdout=False, cwd=location, + ) + return current_rev.strip() + + @classmethod + def get_subdirectory(cls, location): + """ + Return the path to setup.py, relative to the repo root. + Return None if setup.py is in the repo root. + """ + # find the repo root + git_dir = cls.run_command( + ['rev-parse', '--git-dir'], + show_stdout=False, cwd=location).strip() + if not os.path.isabs(git_dir): + git_dir = os.path.join(location, git_dir) + repo_root = os.path.abspath(os.path.join(git_dir, '..')) + return find_path_to_setup_from_repo_root(location, repo_root) + + @classmethod + def get_url_rev_and_auth(cls, url): + # type: (str) -> Tuple[str, Optional[str], AuthInfo] + """ + Prefixes stub URLs like 'user@hostname:user/repo.git' with 'ssh://'. + That's required because although they use SSH they sometimes don't + work with a ssh:// scheme (e.g. GitHub). But we need a scheme for + parsing. Hence we remove it again afterwards and return it as a stub. + """ + # Works around an apparent Git bug + # (see https://article.gmane.org/gmane.comp.version-control.git/146500) + scheme, netloc, path, query, fragment = urlsplit(url) + if scheme.endswith('file'): + initial_slashes = path[:-len(path.lstrip('/'))] + newpath = ( + initial_slashes + + urllib_request.url2pathname(path) + .replace('\\', '/').lstrip('/') + ) + url = urlunsplit((scheme, netloc, newpath, query, fragment)) + after_plus = scheme.find('+') + 1 + url = scheme[:after_plus] + urlunsplit( + (scheme[after_plus:], netloc, newpath, query, fragment), + ) + + if '://' not in url: + assert 'file:' not in url + url = url.replace('git+', 'git+ssh://') + url, rev, user_pass = super(Git, cls).get_url_rev_and_auth(url) + url = url.replace('ssh://', '') + else: + url, rev, user_pass = super(Git, cls).get_url_rev_and_auth(url) + + return url, rev, user_pass + + @classmethod + def update_submodules(cls, location): + if not os.path.exists(os.path.join(location, '.gitmodules')): + return + cls.run_command( + ['submodule', 'update', '--init', '--recursive', '-q'], + cwd=location, + ) + + @classmethod + def get_repository_root(cls, location): + loc = super(Git, cls).get_repository_root(location) + if loc: + return loc + try: + r = cls.run_command( + ['rev-parse', '--show-toplevel'], + cwd=location, + show_stdout=False, + on_returncode='raise', + log_failed_cmd=False, + ) + except BadCommand: + logger.debug("could not determine if %s is under git control " + "because git is not available", location) + return None + except InstallationError: + return None + return os.path.normpath(r.rstrip('\r\n')) + + +vcs.register(Git) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/vcs/mercurial.py b/venv/lib/python3.8/site-packages/pip/_internal/vcs/mercurial.py new file mode 100644 index 0000000..75e903c --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/vcs/mercurial.py @@ -0,0 +1,161 @@ +# The following comment should be removed at some point in the future. +# mypy: disallow-untyped-defs=False + +from __future__ import absolute_import + +import logging +import os + +from pip._vendor.six.moves import configparser + +from pip._internal.exceptions import BadCommand, InstallationError +from pip._internal.utils.misc import display_path +from pip._internal.utils.subprocess import make_command +from pip._internal.utils.temp_dir import TempDirectory +from pip._internal.utils.typing import MYPY_CHECK_RUNNING +from pip._internal.utils.urls import path_to_url +from pip._internal.vcs.versioncontrol import ( + VersionControl, + find_path_to_setup_from_repo_root, + vcs, +) + +if MYPY_CHECK_RUNNING: + from pip._internal.utils.misc import HiddenText + from pip._internal.vcs.versioncontrol import RevOptions + + +logger = logging.getLogger(__name__) + + +class Mercurial(VersionControl): + name = 'hg' + dirname = '.hg' + repo_name = 'clone' + schemes = ( + 'hg', 'hg+file', 'hg+http', 'hg+https', 'hg+ssh', 'hg+static-http', + ) + + @staticmethod + def get_base_rev_args(rev): + return [rev] + + def export(self, location, url): + # type: (str, HiddenText) -> None + """Export the Hg repository at the url to the destination location""" + with TempDirectory(kind="export") as temp_dir: + self.unpack(temp_dir.path, url=url) + + self.run_command( + ['archive', location], show_stdout=False, cwd=temp_dir.path + ) + + def fetch_new(self, dest, url, rev_options): + # type: (str, HiddenText, RevOptions) -> None + rev_display = rev_options.to_display() + logger.info( + 'Cloning hg %s%s to %s', + url, + rev_display, + display_path(dest), + ) + self.run_command(make_command('clone', '--noupdate', '-q', url, dest)) + self.run_command( + make_command('update', '-q', rev_options.to_args()), + cwd=dest, + ) + + def switch(self, dest, url, rev_options): + # type: (str, HiddenText, RevOptions) -> None + repo_config = os.path.join(dest, self.dirname, 'hgrc') + config = configparser.RawConfigParser() + try: + config.read(repo_config) + config.set('paths', 'default', url.secret) + with open(repo_config, 'w') as config_file: + config.write(config_file) + except (OSError, configparser.NoSectionError) as exc: + logger.warning( + 'Could not switch Mercurial repository to %s: %s', url, exc, + ) + else: + cmd_args = make_command('update', '-q', rev_options.to_args()) + self.run_command(cmd_args, cwd=dest) + + def update(self, dest, url, rev_options): + # type: (str, HiddenText, RevOptions) -> None + self.run_command(['pull', '-q'], cwd=dest) + cmd_args = make_command('update', '-q', rev_options.to_args()) + self.run_command(cmd_args, cwd=dest) + + @classmethod + def get_remote_url(cls, location): + url = cls.run_command( + ['showconfig', 'paths.default'], + show_stdout=False, cwd=location).strip() + if cls._is_local_repository(url): + url = path_to_url(url) + return url.strip() + + @classmethod + def get_revision(cls, location): + """ + Return the repository-local changeset revision number, as an integer. + """ + current_revision = cls.run_command( + ['parents', '--template={rev}'], + show_stdout=False, cwd=location).strip() + return current_revision + + @classmethod + def get_requirement_revision(cls, location): + """ + Return the changeset identification hash, as a 40-character + hexadecimal string + """ + current_rev_hash = cls.run_command( + ['parents', '--template={node}'], + show_stdout=False, cwd=location).strip() + return current_rev_hash + + @classmethod + def is_commit_id_equal(cls, dest, name): + """Always assume the versions don't match""" + return False + + @classmethod + def get_subdirectory(cls, location): + """ + Return the path to setup.py, relative to the repo root. + Return None if setup.py is in the repo root. + """ + # find the repo root + repo_root = cls.run_command( + ['root'], show_stdout=False, cwd=location).strip() + if not os.path.isabs(repo_root): + repo_root = os.path.abspath(os.path.join(location, repo_root)) + return find_path_to_setup_from_repo_root(location, repo_root) + + @classmethod + def get_repository_root(cls, location): + loc = super(Mercurial, cls).get_repository_root(location) + if loc: + return loc + try: + r = cls.run_command( + ['root'], + cwd=location, + show_stdout=False, + on_returncode='raise', + log_failed_cmd=False, + ) + except BadCommand: + logger.debug("could not determine if %s is under hg control " + "because hg is not available", location) + return None + except InstallationError: + return None + return os.path.normpath(r.rstrip('\r\n')) + + +vcs.register(Mercurial) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/vcs/subversion.py b/venv/lib/python3.8/site-packages/pip/_internal/vcs/subversion.py new file mode 100644 index 0000000..0ec6597 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/vcs/subversion.py @@ -0,0 +1,334 @@ +# The following comment should be removed at some point in the future. +# mypy: disallow-untyped-defs=False + +from __future__ import absolute_import + +import logging +import os +import re + +from pip._internal.utils.logging import indent_log +from pip._internal.utils.misc import ( + display_path, + is_console_interactive, + rmtree, + split_auth_from_netloc, +) +from pip._internal.utils.subprocess import make_command +from pip._internal.utils.typing import MYPY_CHECK_RUNNING +from pip._internal.vcs.versioncontrol import VersionControl, vcs + +_svn_xml_url_re = re.compile('url="([^"]+)"') +_svn_rev_re = re.compile(r'committed-rev="(\d+)"') +_svn_info_xml_rev_re = re.compile(r'\s*revision="(\d+)"') +_svn_info_xml_url_re = re.compile(r'(.*)') + + +if MYPY_CHECK_RUNNING: + from typing import Optional, Tuple + from pip._internal.utils.subprocess import CommandArgs + from pip._internal.utils.misc import HiddenText + from pip._internal.vcs.versioncontrol import AuthInfo, RevOptions + + +logger = logging.getLogger(__name__) + + +class Subversion(VersionControl): + name = 'svn' + dirname = '.svn' + repo_name = 'checkout' + schemes = ('svn', 'svn+ssh', 'svn+http', 'svn+https', 'svn+svn') + + @classmethod + def should_add_vcs_url_prefix(cls, remote_url): + return True + + @staticmethod + def get_base_rev_args(rev): + return ['-r', rev] + + @classmethod + def get_revision(cls, location): + """ + Return the maximum revision for all files under a given location + """ + # Note: taken from setuptools.command.egg_info + revision = 0 + + for base, dirs, files in os.walk(location): + if cls.dirname not in dirs: + dirs[:] = [] + continue # no sense walking uncontrolled subdirs + dirs.remove(cls.dirname) + entries_fn = os.path.join(base, cls.dirname, 'entries') + if not os.path.exists(entries_fn): + # FIXME: should we warn? + continue + + dirurl, localrev = cls._get_svn_url_rev(base) + + if base == location: + base = dirurl + '/' # save the root url + elif not dirurl or not dirurl.startswith(base): + dirs[:] = [] + continue # not part of the same svn tree, skip it + revision = max(revision, localrev) + return revision + + @classmethod + def get_netloc_and_auth(cls, netloc, scheme): + """ + This override allows the auth information to be passed to svn via the + --username and --password options instead of via the URL. + """ + if scheme == 'ssh': + # The --username and --password options can't be used for + # svn+ssh URLs, so keep the auth information in the URL. + return super(Subversion, cls).get_netloc_and_auth(netloc, scheme) + + return split_auth_from_netloc(netloc) + + @classmethod + def get_url_rev_and_auth(cls, url): + # type: (str) -> Tuple[str, Optional[str], AuthInfo] + # hotfix the URL scheme after removing svn+ from svn+ssh:// readd it + url, rev, user_pass = super(Subversion, cls).get_url_rev_and_auth(url) + if url.startswith('ssh://'): + url = 'svn+' + url + return url, rev, user_pass + + @staticmethod + def make_rev_args(username, password): + # type: (Optional[str], Optional[HiddenText]) -> CommandArgs + extra_args = [] # type: CommandArgs + if username: + extra_args += ['--username', username] + if password: + extra_args += ['--password', password] + + return extra_args + + @classmethod + def get_remote_url(cls, location): + # In cases where the source is in a subdirectory, not alongside + # setup.py we have to look up in the location until we find a real + # setup.py + orig_location = location + while not os.path.exists(os.path.join(location, 'setup.py')): + last_location = location + location = os.path.dirname(location) + if location == last_location: + # We've traversed up to the root of the filesystem without + # finding setup.py + logger.warning( + "Could not find setup.py for directory %s (tried all " + "parent directories)", + orig_location, + ) + return None + + return cls._get_svn_url_rev(location)[0] + + @classmethod + def _get_svn_url_rev(cls, location): + from pip._internal.exceptions import InstallationError + + entries_path = os.path.join(location, cls.dirname, 'entries') + if os.path.exists(entries_path): + with open(entries_path) as f: + data = f.read() + else: # subversion >= 1.7 does not have the 'entries' file + data = '' + + if (data.startswith('8') or + data.startswith('9') or + data.startswith('10')): + data = list(map(str.splitlines, data.split('\n\x0c\n'))) + del data[0][0] # get rid of the '8' + url = data[0][3] + revs = [int(d[9]) for d in data if len(d) > 9 and d[9]] + [0] + elif data.startswith('= 1.7 + # Note that using get_remote_call_options is not necessary here + # because `svn info` is being run against a local directory. + # We don't need to worry about making sure interactive mode + # is being used to prompt for passwords, because passwords + # are only potentially needed for remote server requests. + xml = cls.run_command( + ['info', '--xml', location], + show_stdout=False, + ) + url = _svn_info_xml_url_re.search(xml).group(1) + revs = [ + int(m.group(1)) for m in _svn_info_xml_rev_re.finditer(xml) + ] + except InstallationError: + url, revs = None, [] + + if revs: + rev = max(revs) + else: + rev = 0 + + return url, rev + + @classmethod + def is_commit_id_equal(cls, dest, name): + """Always assume the versions don't match""" + return False + + def __init__(self, use_interactive=None): + # type: (bool) -> None + if use_interactive is None: + use_interactive = is_console_interactive() + self.use_interactive = use_interactive + + # This member is used to cache the fetched version of the current + # ``svn`` client. + # Special value definitions: + # None: Not evaluated yet. + # Empty tuple: Could not parse version. + self._vcs_version = None # type: Optional[Tuple[int, ...]] + + super(Subversion, self).__init__() + + def call_vcs_version(self): + # type: () -> Tuple[int, ...] + """Query the version of the currently installed Subversion client. + + :return: A tuple containing the parts of the version information or + ``()`` if the version returned from ``svn`` could not be parsed. + :raises: BadCommand: If ``svn`` is not installed. + """ + # Example versions: + # svn, version 1.10.3 (r1842928) + # compiled Feb 25 2019, 14:20:39 on x86_64-apple-darwin17.0.0 + # svn, version 1.7.14 (r1542130) + # compiled Mar 28 2018, 08:49:13 on x86_64-pc-linux-gnu + version_prefix = 'svn, version ' + version = self.run_command(['--version'], show_stdout=False) + if not version.startswith(version_prefix): + return () + + version = version[len(version_prefix):].split()[0] + version_list = version.split('.') + try: + parsed_version = tuple(map(int, version_list)) + except ValueError: + return () + + return parsed_version + + def get_vcs_version(self): + # type: () -> Tuple[int, ...] + """Return the version of the currently installed Subversion client. + + If the version of the Subversion client has already been queried, + a cached value will be used. + + :return: A tuple containing the parts of the version information or + ``()`` if the version returned from ``svn`` could not be parsed. + :raises: BadCommand: If ``svn`` is not installed. + """ + if self._vcs_version is not None: + # Use cached version, if available. + # If parsing the version failed previously (empty tuple), + # do not attempt to parse it again. + return self._vcs_version + + vcs_version = self.call_vcs_version() + self._vcs_version = vcs_version + return vcs_version + + def get_remote_call_options(self): + # type: () -> CommandArgs + """Return options to be used on calls to Subversion that contact the server. + + These options are applicable for the following ``svn`` subcommands used + in this class. + + - checkout + - export + - switch + - update + + :return: A list of command line arguments to pass to ``svn``. + """ + if not self.use_interactive: + # --non-interactive switch is available since Subversion 0.14.4. + # Subversion < 1.8 runs in interactive mode by default. + return ['--non-interactive'] + + svn_version = self.get_vcs_version() + # By default, Subversion >= 1.8 runs in non-interactive mode if + # stdin is not a TTY. Since that is how pip invokes SVN, in + # call_subprocess(), pip must pass --force-interactive to ensure + # the user can be prompted for a password, if required. + # SVN added the --force-interactive option in SVN 1.8. Since + # e.g. RHEL/CentOS 7, which is supported until 2024, ships with + # SVN 1.7, pip should continue to support SVN 1.7. Therefore, pip + # can't safely add the option if the SVN version is < 1.8 (or unknown). + if svn_version >= (1, 8): + return ['--force-interactive'] + + return [] + + def export(self, location, url): + # type: (str, HiddenText) -> None + """Export the svn repository at the url to the destination location""" + url, rev_options = self.get_url_rev_options(url) + + logger.info('Exporting svn repository %s to %s', url, location) + with indent_log(): + if os.path.exists(location): + # Subversion doesn't like to check out over an existing + # directory --force fixes this, but was only added in svn 1.5 + rmtree(location) + cmd_args = make_command( + 'export', self.get_remote_call_options(), + rev_options.to_args(), url, location, + ) + self.run_command(cmd_args, show_stdout=False) + + def fetch_new(self, dest, url, rev_options): + # type: (str, HiddenText, RevOptions) -> None + rev_display = rev_options.to_display() + logger.info( + 'Checking out %s%s to %s', + url, + rev_display, + display_path(dest), + ) + cmd_args = make_command( + 'checkout', '-q', self.get_remote_call_options(), + rev_options.to_args(), url, dest, + ) + self.run_command(cmd_args) + + def switch(self, dest, url, rev_options): + # type: (str, HiddenText, RevOptions) -> None + cmd_args = make_command( + 'switch', self.get_remote_call_options(), rev_options.to_args(), + url, dest, + ) + self.run_command(cmd_args) + + def update(self, dest, url, rev_options): + # type: (str, HiddenText, RevOptions) -> None + cmd_args = make_command( + 'update', self.get_remote_call_options(), rev_options.to_args(), + dest, + ) + self.run_command(cmd_args) + + +vcs.register(Subversion) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/vcs/versioncontrol.py b/venv/lib/python3.8/site-packages/pip/_internal/vcs/versioncontrol.py new file mode 100644 index 0000000..71b4650 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/vcs/versioncontrol.py @@ -0,0 +1,723 @@ +"""Handles all VCS (version control) support""" + +from __future__ import absolute_import + +import errno +import logging +import os +import shutil +import sys + +from pip._vendor import pkg_resources +from pip._vendor.six.moves.urllib import parse as urllib_parse + +from pip._internal.exceptions import BadCommand, InstallationError +from pip._internal.utils.compat import samefile +from pip._internal.utils.misc import ( + ask_path_exists, + backup_dir, + display_path, + hide_url, + hide_value, + rmtree, +) +from pip._internal.utils.subprocess import call_subprocess, make_command +from pip._internal.utils.typing import MYPY_CHECK_RUNNING +from pip._internal.utils.urls import get_url_scheme + +if MYPY_CHECK_RUNNING: + from typing import ( + Any, Dict, Iterable, Iterator, List, Mapping, Optional, Text, Tuple, + Type, Union + ) + from pip._internal.cli.spinners import SpinnerInterface + from pip._internal.utils.misc import HiddenText + from pip._internal.utils.subprocess import CommandArgs + + AuthInfo = Tuple[Optional[str], Optional[str]] + + +__all__ = ['vcs'] + + +logger = logging.getLogger(__name__) + + +def is_url(name): + # type: (Union[str, Text]) -> bool + """ + Return true if the name looks like a URL. + """ + scheme = get_url_scheme(name) + if scheme is None: + return False + return scheme in ['http', 'https', 'file', 'ftp'] + vcs.all_schemes + + +def make_vcs_requirement_url(repo_url, rev, project_name, subdir=None): + # type: (str, str, str, Optional[str]) -> str + """ + Return the URL for a VCS requirement. + + Args: + repo_url: the remote VCS url, with any needed VCS prefix (e.g. "git+"). + project_name: the (unescaped) project name. + """ + egg_project_name = pkg_resources.to_filename(project_name) + req = '{}@{}#egg={}'.format(repo_url, rev, egg_project_name) + if subdir: + req += '&subdirectory={}'.format(subdir) + + return req + + +def find_path_to_setup_from_repo_root(location, repo_root): + # type: (str, str) -> Optional[str] + """ + Find the path to `setup.py` by searching up the filesystem from `location`. + Return the path to `setup.py` relative to `repo_root`. + Return None if `setup.py` is in `repo_root` or cannot be found. + """ + # find setup.py + orig_location = location + while not os.path.exists(os.path.join(location, 'setup.py')): + last_location = location + location = os.path.dirname(location) + if location == last_location: + # We've traversed up to the root of the filesystem without + # finding setup.py + logger.warning( + "Could not find setup.py for directory %s (tried all " + "parent directories)", + orig_location, + ) + return None + + if samefile(repo_root, location): + return None + + return os.path.relpath(location, repo_root) + + +class RemoteNotFoundError(Exception): + pass + + +class RevOptions(object): + + """ + Encapsulates a VCS-specific revision to install, along with any VCS + install options. + + Instances of this class should be treated as if immutable. + """ + + def __init__( + self, + vc_class, # type: Type[VersionControl] + rev=None, # type: Optional[str] + extra_args=None, # type: Optional[CommandArgs] + ): + # type: (...) -> None + """ + Args: + vc_class: a VersionControl subclass. + rev: the name of the revision to install. + extra_args: a list of extra options. + """ + if extra_args is None: + extra_args = [] + + self.extra_args = extra_args + self.rev = rev + self.vc_class = vc_class + self.branch_name = None # type: Optional[str] + + def __repr__(self): + # type: () -> str + return ''.format(self.vc_class.name, self.rev) + + @property + def arg_rev(self): + # type: () -> Optional[str] + if self.rev is None: + return self.vc_class.default_arg_rev + + return self.rev + + def to_args(self): + # type: () -> CommandArgs + """ + Return the VCS-specific command arguments. + """ + args = [] # type: CommandArgs + rev = self.arg_rev + if rev is not None: + args += self.vc_class.get_base_rev_args(rev) + args += self.extra_args + + return args + + def to_display(self): + # type: () -> str + if not self.rev: + return '' + + return ' (to revision {})'.format(self.rev) + + def make_new(self, rev): + # type: (str) -> RevOptions + """ + Make a copy of the current instance, but with a new rev. + + Args: + rev: the name of the revision for the new object. + """ + return self.vc_class.make_rev_options(rev, extra_args=self.extra_args) + + +class VcsSupport(object): + _registry = {} # type: Dict[str, VersionControl] + schemes = ['ssh', 'git', 'hg', 'bzr', 'sftp', 'svn'] + + def __init__(self): + # type: () -> None + # Register more schemes with urlparse for various version control + # systems + urllib_parse.uses_netloc.extend(self.schemes) + # Python >= 2.7.4, 3.3 doesn't have uses_fragment + if getattr(urllib_parse, 'uses_fragment', None): + urllib_parse.uses_fragment.extend(self.schemes) + super(VcsSupport, self).__init__() + + def __iter__(self): + # type: () -> Iterator[str] + return self._registry.__iter__() + + @property + def backends(self): + # type: () -> List[VersionControl] + return list(self._registry.values()) + + @property + def dirnames(self): + # type: () -> List[str] + return [backend.dirname for backend in self.backends] + + @property + def all_schemes(self): + # type: () -> List[str] + schemes = [] # type: List[str] + for backend in self.backends: + schemes.extend(backend.schemes) + return schemes + + def register(self, cls): + # type: (Type[VersionControl]) -> None + if not hasattr(cls, 'name'): + logger.warning('Cannot register VCS %s', cls.__name__) + return + if cls.name not in self._registry: + self._registry[cls.name] = cls() + logger.debug('Registered VCS backend: %s', cls.name) + + def unregister(self, name): + # type: (str) -> None + if name in self._registry: + del self._registry[name] + + def get_backend_for_dir(self, location): + # type: (str) -> Optional[VersionControl] + """ + Return a VersionControl object if a repository of that type is found + at the given directory. + """ + vcs_backends = {} + for vcs_backend in self._registry.values(): + repo_path = vcs_backend.get_repository_root(location) + if not repo_path: + continue + logger.debug('Determine that %s uses VCS: %s', + location, vcs_backend.name) + vcs_backends[repo_path] = vcs_backend + + if not vcs_backends: + return None + + # Choose the VCS in the inner-most directory. Since all repository + # roots found here would be either `location` or one of its + # parents, the longest path should have the most path components, + # i.e. the backend representing the inner-most repository. + inner_most_repo_path = max(vcs_backends, key=len) + return vcs_backends[inner_most_repo_path] + + def get_backend_for_scheme(self, scheme): + # type: (str) -> Optional[VersionControl] + """ + Return a VersionControl object or None. + """ + for vcs_backend in self._registry.values(): + if scheme in vcs_backend.schemes: + return vcs_backend + return None + + def get_backend(self, name): + # type: (str) -> Optional[VersionControl] + """ + Return a VersionControl object or None. + """ + name = name.lower() + return self._registry.get(name) + + +vcs = VcsSupport() + + +class VersionControl(object): + name = '' + dirname = '' + repo_name = '' + # List of supported schemes for this Version Control + schemes = () # type: Tuple[str, ...] + # Iterable of environment variable names to pass to call_subprocess(). + unset_environ = () # type: Tuple[str, ...] + default_arg_rev = None # type: Optional[str] + + @classmethod + def should_add_vcs_url_prefix(cls, remote_url): + # type: (str) -> bool + """ + Return whether the vcs prefix (e.g. "git+") should be added to a + repository's remote url when used in a requirement. + """ + return not remote_url.lower().startswith('{}:'.format(cls.name)) + + @classmethod + def get_subdirectory(cls, location): + # type: (str) -> Optional[str] + """ + Return the path to setup.py, relative to the repo root. + Return None if setup.py is in the repo root. + """ + return None + + @classmethod + def get_requirement_revision(cls, repo_dir): + # type: (str) -> str + """ + Return the revision string that should be used in a requirement. + """ + return cls.get_revision(repo_dir) + + @classmethod + def get_src_requirement(cls, repo_dir, project_name): + # type: (str, str) -> Optional[str] + """ + Return the requirement string to use to redownload the files + currently at the given repository directory. + + Args: + project_name: the (unescaped) project name. + + The return value has a form similar to the following: + + {repository_url}@{revision}#egg={project_name} + """ + repo_url = cls.get_remote_url(repo_dir) + if repo_url is None: + return None + + if cls.should_add_vcs_url_prefix(repo_url): + repo_url = '{}+{}'.format(cls.name, repo_url) + + revision = cls.get_requirement_revision(repo_dir) + subdir = cls.get_subdirectory(repo_dir) + req = make_vcs_requirement_url(repo_url, revision, project_name, + subdir=subdir) + + return req + + @staticmethod + def get_base_rev_args(rev): + # type: (str) -> List[str] + """ + Return the base revision arguments for a vcs command. + + Args: + rev: the name of a revision to install. Cannot be None. + """ + raise NotImplementedError + + def is_immutable_rev_checkout(self, url, dest): + # type: (str, str) -> bool + """ + Return true if the commit hash checked out at dest matches + the revision in url. + + Always return False, if the VCS does not support immutable commit + hashes. + + This method does not check if there are local uncommitted changes + in dest after checkout, as pip currently has no use case for that. + """ + return False + + @classmethod + def make_rev_options(cls, rev=None, extra_args=None): + # type: (Optional[str], Optional[CommandArgs]) -> RevOptions + """ + Return a RevOptions object. + + Args: + rev: the name of a revision to install. + extra_args: a list of extra options. + """ + return RevOptions(cls, rev, extra_args=extra_args) + + @classmethod + def _is_local_repository(cls, repo): + # type: (str) -> bool + """ + posix absolute paths start with os.path.sep, + win32 ones start with drive (like c:\\folder) + """ + drive, tail = os.path.splitdrive(repo) + return repo.startswith(os.path.sep) or bool(drive) + + def export(self, location, url): + # type: (str, HiddenText) -> None + """ + Export the repository at the url to the destination location + i.e. only download the files, without vcs informations + + :param url: the repository URL starting with a vcs prefix. + """ + raise NotImplementedError + + @classmethod + def get_netloc_and_auth(cls, netloc, scheme): + # type: (str, str) -> Tuple[str, Tuple[Optional[str], Optional[str]]] + """ + Parse the repository URL's netloc, and return the new netloc to use + along with auth information. + + Args: + netloc: the original repository URL netloc. + scheme: the repository URL's scheme without the vcs prefix. + + This is mainly for the Subversion class to override, so that auth + information can be provided via the --username and --password options + instead of through the URL. For other subclasses like Git without + such an option, auth information must stay in the URL. + + Returns: (netloc, (username, password)). + """ + return netloc, (None, None) + + @classmethod + def get_url_rev_and_auth(cls, url): + # type: (str) -> Tuple[str, Optional[str], AuthInfo] + """ + Parse the repository URL to use, and return the URL, revision, + and auth info to use. + + Returns: (url, rev, (username, password)). + """ + scheme, netloc, path, query, frag = urllib_parse.urlsplit(url) + if '+' not in scheme: + raise ValueError( + "Sorry, {!r} is a malformed VCS url. " + "The format is +://, " + "e.g. svn+http://myrepo/svn/MyApp#egg=MyApp".format(url) + ) + # Remove the vcs prefix. + scheme = scheme.split('+', 1)[1] + netloc, user_pass = cls.get_netloc_and_auth(netloc, scheme) + rev = None + if '@' in path: + path, rev = path.rsplit('@', 1) + if not rev: + raise InstallationError( + "The URL {!r} has an empty revision (after @) " + "which is not supported. Include a revision after @ " + "or remove @ from the URL.".format(url) + ) + url = urllib_parse.urlunsplit((scheme, netloc, path, query, '')) + return url, rev, user_pass + + @staticmethod + def make_rev_args(username, password): + # type: (Optional[str], Optional[HiddenText]) -> CommandArgs + """ + Return the RevOptions "extra arguments" to use in obtain(). + """ + return [] + + def get_url_rev_options(self, url): + # type: (HiddenText) -> Tuple[HiddenText, RevOptions] + """ + Return the URL and RevOptions object to use in obtain() and in + some cases export(), as a tuple (url, rev_options). + """ + secret_url, rev, user_pass = self.get_url_rev_and_auth(url.secret) + username, secret_password = user_pass + password = None # type: Optional[HiddenText] + if secret_password is not None: + password = hide_value(secret_password) + extra_args = self.make_rev_args(username, password) + rev_options = self.make_rev_options(rev, extra_args=extra_args) + + return hide_url(secret_url), rev_options + + @staticmethod + def normalize_url(url): + # type: (str) -> str + """ + Normalize a URL for comparison by unquoting it and removing any + trailing slash. + """ + return urllib_parse.unquote(url).rstrip('/') + + @classmethod + def compare_urls(cls, url1, url2): + # type: (str, str) -> bool + """ + Compare two repo URLs for identity, ignoring incidental differences. + """ + return (cls.normalize_url(url1) == cls.normalize_url(url2)) + + def fetch_new(self, dest, url, rev_options): + # type: (str, HiddenText, RevOptions) -> None + """ + Fetch a revision from a repository, in the case that this is the + first fetch from the repository. + + Args: + dest: the directory to fetch the repository to. + rev_options: a RevOptions object. + """ + raise NotImplementedError + + def switch(self, dest, url, rev_options): + # type: (str, HiddenText, RevOptions) -> None + """ + Switch the repo at ``dest`` to point to ``URL``. + + Args: + rev_options: a RevOptions object. + """ + raise NotImplementedError + + def update(self, dest, url, rev_options): + # type: (str, HiddenText, RevOptions) -> None + """ + Update an already-existing repo to the given ``rev_options``. + + Args: + rev_options: a RevOptions object. + """ + raise NotImplementedError + + @classmethod + def is_commit_id_equal(cls, dest, name): + # type: (str, Optional[str]) -> bool + """ + Return whether the id of the current commit equals the given name. + + Args: + dest: the repository directory. + name: a string name. + """ + raise NotImplementedError + + def obtain(self, dest, url): + # type: (str, HiddenText) -> None + """ + Install or update in editable mode the package represented by this + VersionControl object. + + :param dest: the repository directory in which to install or update. + :param url: the repository URL starting with a vcs prefix. + """ + url, rev_options = self.get_url_rev_options(url) + + if not os.path.exists(dest): + self.fetch_new(dest, url, rev_options) + return + + rev_display = rev_options.to_display() + if self.is_repository_directory(dest): + existing_url = self.get_remote_url(dest) + if self.compare_urls(existing_url, url.secret): + logger.debug( + '%s in %s exists, and has correct URL (%s)', + self.repo_name.title(), + display_path(dest), + url, + ) + if not self.is_commit_id_equal(dest, rev_options.rev): + logger.info( + 'Updating %s %s%s', + display_path(dest), + self.repo_name, + rev_display, + ) + self.update(dest, url, rev_options) + else: + logger.info('Skipping because already up-to-date.') + return + + logger.warning( + '%s %s in %s exists with URL %s', + self.name, + self.repo_name, + display_path(dest), + existing_url, + ) + prompt = ('(s)witch, (i)gnore, (w)ipe, (b)ackup ', + ('s', 'i', 'w', 'b')) + else: + logger.warning( + 'Directory %s already exists, and is not a %s %s.', + dest, + self.name, + self.repo_name, + ) + # https://github.com/python/mypy/issues/1174 + prompt = ('(i)gnore, (w)ipe, (b)ackup ', # type: ignore + ('i', 'w', 'b')) + + logger.warning( + 'The plan is to install the %s repository %s', + self.name, + url, + ) + response = ask_path_exists('What to do? {}'.format( + prompt[0]), prompt[1]) + + if response == 'a': + sys.exit(-1) + + if response == 'w': + logger.warning('Deleting %s', display_path(dest)) + rmtree(dest) + self.fetch_new(dest, url, rev_options) + return + + if response == 'b': + dest_dir = backup_dir(dest) + logger.warning( + 'Backing up %s to %s', display_path(dest), dest_dir, + ) + shutil.move(dest, dest_dir) + self.fetch_new(dest, url, rev_options) + return + + # Do nothing if the response is "i". + if response == 's': + logger.info( + 'Switching %s %s to %s%s', + self.repo_name, + display_path(dest), + url, + rev_display, + ) + self.switch(dest, url, rev_options) + + def unpack(self, location, url): + # type: (str, HiddenText) -> None + """ + Clean up current location and download the url repository + (and vcs infos) into location + + :param url: the repository URL starting with a vcs prefix. + """ + if os.path.exists(location): + rmtree(location) + self.obtain(location, url=url) + + @classmethod + def get_remote_url(cls, location): + # type: (str) -> str + """ + Return the url used at location + + Raises RemoteNotFoundError if the repository does not have a remote + url configured. + """ + raise NotImplementedError + + @classmethod + def get_revision(cls, location): + # type: (str) -> str + """ + Return the current commit id of the files at the given location. + """ + raise NotImplementedError + + @classmethod + def run_command( + cls, + cmd, # type: Union[List[str], CommandArgs] + show_stdout=True, # type: bool + cwd=None, # type: Optional[str] + on_returncode='raise', # type: str + extra_ok_returncodes=None, # type: Optional[Iterable[int]] + command_desc=None, # type: Optional[str] + extra_environ=None, # type: Optional[Mapping[str, Any]] + spinner=None, # type: Optional[SpinnerInterface] + log_failed_cmd=True # type: bool + ): + # type: (...) -> Text + """ + Run a VCS subcommand + This is simply a wrapper around call_subprocess that adds the VCS + command name, and checks that the VCS is available + """ + cmd = make_command(cls.name, *cmd) + try: + return call_subprocess(cmd, show_stdout, cwd, + on_returncode=on_returncode, + extra_ok_returncodes=extra_ok_returncodes, + command_desc=command_desc, + extra_environ=extra_environ, + unset_environ=cls.unset_environ, + spinner=spinner, + log_failed_cmd=log_failed_cmd) + except OSError as e: + # errno.ENOENT = no such file or directory + # In other words, the VCS executable isn't available + if e.errno == errno.ENOENT: + raise BadCommand( + 'Cannot find command {cls.name!r} - do you have ' + '{cls.name!r} installed and in your ' + 'PATH?'.format(**locals())) + else: + raise # re-raise exception if a different error occurred + + @classmethod + def is_repository_directory(cls, path): + # type: (str) -> bool + """ + Return whether a directory path is a repository directory. + """ + logger.debug('Checking in %s for %s (%s)...', + path, cls.dirname, cls.name) + return os.path.exists(os.path.join(path, cls.dirname)) + + @classmethod + def get_repository_root(cls, location): + # type: (str) -> Optional[str] + """ + Return the "root" (top-level) directory controlled by the vcs, + or `None` if the directory is not in any. + + It is meant to be overridden to implement smarter detection + mechanisms for specific vcs. + + This can do more than is_repository_directory() alone. For + example, the Git override checks that Git is actually available. + """ + if cls.is_repository_directory(location): + return location + return None diff --git a/venv/lib/python3.8/site-packages/pip/_internal/wheel_builder.py b/venv/lib/python3.8/site-packages/pip/_internal/wheel_builder.py new file mode 100644 index 0000000..fcaeeb6 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_internal/wheel_builder.py @@ -0,0 +1,309 @@ +"""Orchestrator for building wheels from InstallRequirements. +""" + +# The following comment should be removed at some point in the future. +# mypy: strict-optional=False + +import logging +import os.path +import re +import shutil + +from pip._internal.models.link import Link +from pip._internal.operations.build.wheel import build_wheel_pep517 +from pip._internal.operations.build.wheel_legacy import build_wheel_legacy +from pip._internal.utils.logging import indent_log +from pip._internal.utils.misc import ensure_dir, hash_file, is_wheel_installed +from pip._internal.utils.setuptools_build import make_setuptools_clean_args +from pip._internal.utils.subprocess import call_subprocess +from pip._internal.utils.temp_dir import TempDirectory +from pip._internal.utils.typing import MYPY_CHECK_RUNNING +from pip._internal.utils.urls import path_to_url +from pip._internal.vcs import vcs + +if MYPY_CHECK_RUNNING: + from typing import ( + Any, Callable, Iterable, List, Optional, Pattern, Tuple, + ) + + from pip._internal.cache import WheelCache + from pip._internal.req.req_install import InstallRequirement + + BinaryAllowedPredicate = Callable[[InstallRequirement], bool] + BuildResult = Tuple[List[InstallRequirement], List[InstallRequirement]] + +logger = logging.getLogger(__name__) + + +def _contains_egg_info( + s, _egg_info_re=re.compile(r'([a-z0-9_.]+)-([a-z0-9_.!+-]+)', re.I)): + # type: (str, Pattern[str]) -> bool + """Determine whether the string looks like an egg_info. + + :param s: The string to parse. E.g. foo-2.1 + """ + return bool(_egg_info_re.search(s)) + + +def _should_build( + req, # type: InstallRequirement + need_wheel, # type: bool + check_binary_allowed, # type: BinaryAllowedPredicate +): + # type: (...) -> bool + """Return whether an InstallRequirement should be built into a wheel.""" + if req.constraint: + # never build requirements that are merely constraints + return False + if req.is_wheel: + if need_wheel: + logger.info( + 'Skipping %s, due to already being wheel.', req.name, + ) + return False + + if need_wheel: + # i.e. pip wheel, not pip install + return True + + # From this point, this concerns the pip install command only + # (need_wheel=False). + + if req.editable or not req.source_dir: + return False + + if not check_binary_allowed(req): + logger.info( + "Skipping wheel build for %s, due to binaries " + "being disabled for it.", req.name, + ) + return False + + if not req.use_pep517 and not is_wheel_installed(): + # we don't build legacy requirements if wheel is not installed + logger.info( + "Using legacy setup.py install for %s, " + "since package 'wheel' is not installed.", req.name, + ) + return False + + return True + + +def should_build_for_wheel_command( + req, # type: InstallRequirement +): + # type: (...) -> bool + return _should_build( + req, need_wheel=True, check_binary_allowed=_always_true + ) + + +def should_build_for_install_command( + req, # type: InstallRequirement + check_binary_allowed, # type: BinaryAllowedPredicate +): + # type: (...) -> bool + return _should_build( + req, need_wheel=False, check_binary_allowed=check_binary_allowed + ) + + +def _should_cache( + req, # type: InstallRequirement +): + # type: (...) -> Optional[bool] + """ + Return whether a built InstallRequirement can be stored in the persistent + wheel cache, assuming the wheel cache is available, and _should_build() + has determined a wheel needs to be built. + """ + if not should_build_for_install_command( + req, check_binary_allowed=_always_true + ): + # never cache if pip install would not have built + # (editable mode, etc) + return False + + if req.link and req.link.is_vcs: + # VCS checkout. Do not cache + # unless it points to an immutable commit hash. + assert not req.editable + assert req.source_dir + vcs_backend = vcs.get_backend_for_scheme(req.link.scheme) + assert vcs_backend + if vcs_backend.is_immutable_rev_checkout(req.link.url, req.source_dir): + return True + return False + + base, ext = req.link.splitext() + if _contains_egg_info(base): + return True + + # Otherwise, do not cache. + return False + + +def _get_cache_dir( + req, # type: InstallRequirement + wheel_cache, # type: WheelCache +): + # type: (...) -> str + """Return the persistent or temporary cache directory where the built + wheel need to be stored. + """ + cache_available = bool(wheel_cache.cache_dir) + if cache_available and _should_cache(req): + cache_dir = wheel_cache.get_path_for_link(req.link) + else: + cache_dir = wheel_cache.get_ephem_path_for_link(req.link) + return cache_dir + + +def _always_true(_): + # type: (Any) -> bool + return True + + +def _build_one( + req, # type: InstallRequirement + output_dir, # type: str + build_options, # type: List[str] + global_options, # type: List[str] +): + # type: (...) -> Optional[str] + """Build one wheel. + + :return: The filename of the built wheel, or None if the build failed. + """ + try: + ensure_dir(output_dir) + except OSError as e: + logger.warning( + "Building wheel for %s failed: %s", + req.name, e, + ) + return None + + # Install build deps into temporary directory (PEP 518) + with req.build_env: + return _build_one_inside_env( + req, output_dir, build_options, global_options + ) + + +def _build_one_inside_env( + req, # type: InstallRequirement + output_dir, # type: str + build_options, # type: List[str] + global_options, # type: List[str] +): + # type: (...) -> Optional[str] + with TempDirectory(kind="wheel") as temp_dir: + if req.use_pep517: + wheel_path = build_wheel_pep517( + name=req.name, + backend=req.pep517_backend, + metadata_directory=req.metadata_directory, + build_options=build_options, + tempd=temp_dir.path, + ) + else: + wheel_path = build_wheel_legacy( + name=req.name, + setup_py_path=req.setup_py_path, + source_dir=req.unpacked_source_directory, + global_options=global_options, + build_options=build_options, + tempd=temp_dir.path, + ) + + if wheel_path is not None: + wheel_name = os.path.basename(wheel_path) + dest_path = os.path.join(output_dir, wheel_name) + try: + wheel_hash, length = hash_file(wheel_path) + shutil.move(wheel_path, dest_path) + logger.info('Created wheel for %s: ' + 'filename=%s size=%d sha256=%s', + req.name, wheel_name, length, + wheel_hash.hexdigest()) + logger.info('Stored in directory: %s', output_dir) + return dest_path + except Exception as e: + logger.warning( + "Building wheel for %s failed: %s", + req.name, e, + ) + # Ignore return, we can't do anything else useful. + if not req.use_pep517: + _clean_one_legacy(req, global_options) + return None + + +def _clean_one_legacy(req, global_options): + # type: (InstallRequirement, List[str]) -> bool + clean_args = make_setuptools_clean_args( + req.setup_py_path, + global_options=global_options, + ) + + logger.info('Running setup.py clean for %s', req.name) + try: + call_subprocess(clean_args, cwd=req.source_dir) + return True + except Exception: + logger.error('Failed cleaning build dir for %s', req.name) + return False + + +def build( + requirements, # type: Iterable[InstallRequirement] + wheel_cache, # type: WheelCache + build_options, # type: List[str] + global_options, # type: List[str] +): + # type: (...) -> BuildResult + """Build wheels. + + :return: The list of InstallRequirement that succeeded to build and + the list of InstallRequirement that failed to build. + """ + if not requirements: + return [], [] + + # Build the wheels. + logger.info( + 'Building wheels for collected packages: %s', + ', '.join(req.name for req in requirements), + ) + + with indent_log(): + build_successes, build_failures = [], [] + for req in requirements: + cache_dir = _get_cache_dir(req, wheel_cache) + wheel_file = _build_one( + req, cache_dir, build_options, global_options + ) + if wheel_file: + # Update the link for this. + req.link = Link(path_to_url(wheel_file)) + req.local_file_path = req.link.file_path + assert req.link.is_wheel + build_successes.append(req) + else: + build_failures.append(req) + + # notify success/failure + if build_successes: + logger.info( + 'Successfully built %s', + ' '.join([req.name for req in build_successes]), + ) + if build_failures: + logger.info( + 'Failed to build %s', + ' '.join([req.name for req in build_failures]), + ) + # Return a list of requirements that failed to build + return build_successes, build_failures diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/__init__.py b/venv/lib/python3.8/site-packages/pip/_vendor/__init__.py new file mode 100644 index 0000000..d4e20fe --- /dev/null +++ b/venv/lib/python3.8/site-packages/pip/_vendor/__init__.py @@ -0,0 +1,123 @@ +""" +pip._vendor is for vendoring dependencies of pip to prevent needing pip to +depend on something external. + +Files inside of pip._vendor should be considered immutable and should only be +updated to versions from upstream. +""" +from __future__ import absolute_import + +import glob +import os.path +import sys + +# Downstream redistributors which have debundled our dependencies should also +# patch this value to be true. This will trigger the additional patching +# to cause things like "six" to be available as pip. +DEBUNDLED = True + +# By default, look in this directory for a bunch of .whl files which we will +# add to the beginning of sys.path before attempting to import anything. This +# is done to support downstream re-distributors like Debian and Fedora who +# wish to create their own Wheels for our dependencies to aid in debundling. +prefix = getattr(sys, "base_prefix", sys.prefix) +if prefix.startswith('/usr/lib/pypy'): + prefix = '/usr' +WHEEL_DIR = os.path.abspath(os.path.join(prefix, 'share', 'python-wheels')) + + +# Define a small helper function to alias our vendored modules to the real ones +# if the vendored ones do not exist. This idea of this was taken from +# https://github.com/kennethreitz/requests/pull/2567. +def vendored(modulename): + vendored_name = "{0}.{1}".format(__name__, modulename) + + try: + __import__(modulename, globals(), locals(), level=0) + except ImportError: + # We can just silently allow import failures to pass here. If we + # got to this point it means that ``import pip._vendor.whatever`` + # failed and so did ``import whatever``. Since we're importing this + # upfront in an attempt to alias imports, not erroring here will + # just mean we get a regular import error whenever pip *actually* + # tries to import one of these modules to use it, which actually + # gives us a better error message than we would have otherwise + # gotten. + pass + else: + sys.modules[vendored_name] = sys.modules[modulename] + base, head = vendored_name.rsplit(".", 1) + setattr(sys.modules[base], head, sys.modules[modulename]) + + +# If we're operating in a debundled setup, then we want to go ahead and trigger +# the aliasing of our vendored libraries as well as looking for wheels to add +# to our sys.path. This will cause all of this code to be a no-op typically +# however downstream redistributors can enable it in a consistent way across +# all platforms. +if DEBUNDLED: + # Actually look inside of WHEEL_DIR to find .whl files and add them to the + # front of our sys.path. + sys.path[:] = [fn for fn in glob.iglob(os.path.join(WHEEL_DIR, '*.whl')) + if not (os.path.basename(fn).startswith('wheel') or + os.path.basename(fn).startswith('pip'))] + sys.path + + # Actually alias all of our vendored dependencies. + vendored("appdirs") + vendored("cachecontrol") + vendored("certifi") + vendored("colorama") + vendored("contextlib2") + vendored("distlib") + vendored("distro") + vendored("html5lib") + vendored("six") + vendored("six.moves") + vendored("six.moves.urllib") + vendored("six.moves.urllib.parse") + vendored("packaging") + vendored("packaging.version") + vendored("packaging.specifiers") + vendored("pep517") + vendored("pkg_resources") + vendored("progress") + vendored("retrying") + vendored("requests") + vendored("requests.exceptions") + vendored("requests.packages") + vendored("requests.packages.urllib3") + vendored("requests.packages.urllib3._collections") + vendored("requests.packages.urllib3.connection") + vendored("requests.packages.urllib3.connectionpool") + vendored("requests.packages.urllib3.contrib") + vendored("requests.packages.urllib3.contrib.ntlmpool") + vendored("requests.packages.urllib3.contrib.pyopenssl") + vendored("requests.packages.urllib3.exceptions") + vendored("requests.packages.urllib3.fields") + vendored("requests.packages.urllib3.filepost") + vendored("requests.packages.urllib3.packages") + try: + vendored("requests.packages.urllib3.packages.ordered_dict") + vendored("requests.packages.urllib3.packages.six") + except ImportError: + # Debian already unbundles these from requests. + pass + vendored("requests.packages.urllib3.packages.ssl_match_hostname") + vendored("requests.packages.urllib3.packages.ssl_match_hostname." + "_implementation") + vendored("requests.packages.urllib3.poolmanager") + vendored("requests.packages.urllib3.request") + vendored("requests.packages.urllib3.response") + vendored("requests.packages.urllib3.util") + vendored("requests.packages.urllib3.util.connection") + vendored("requests.packages.urllib3.util.request") + vendored("requests.packages.urllib3.util.response") + vendored("requests.packages.urllib3.util.retry") + vendored("requests.packages.urllib3.util.ssl_") + vendored("requests.packages.urllib3.util.timeout") + vendored("requests.packages.urllib3.util.url") + vendored("resolvelib") + vendored("toml") + vendored("toml.encoder") + vendored("toml.decoder") + vendored("urllib3") diff --git a/venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/AUTHORS.txt b/venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/AUTHORS.txt new file mode 100644 index 0000000..04c42fc --- /dev/null +++ b/venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/AUTHORS.txt @@ -0,0 +1,566 @@ +@Switch01 +A_Rog +Aakanksha Agrawal +Abhinav Sagar +ABHYUDAY PRATAP SINGH +abs51295 +AceGentile +Adam Chainz +Adam Tse +Adam Wentz +admin +Adrien Morison +ahayrapetyan +Ahilya +AinsworthK +Akash Srivastava +Alan Yee +Albert Tugushev +Albert-Guan +albertg +Aleks Bunin +Alethea Flowers +Alex Gaynor +Alex Grönholm +Alex Loosley +Alex Morega +Alex Stachowiak +Alexander Shtyrov +Alexandre Conrad +Alexey Popravka +Alli +Ami Fischman +Ananya Maiti +Anatoly Techtonik +Anders Kaseorg +Andre Aguiar +Andreas Lutro +Andrei Geacar +Andrew Gaul +Andrey Bulgakov +Andrés Delfino +Andy Freeland +Andy Kluger +Ani Hayrapetyan +Aniruddha Basak +Anish Tambe +Anrs Hu +Anthony Sottile +Antoine Musso +Anton Ovchinnikov +Anton Patrushev +Antonio Alvarado Hernandez +Antony Lee +Antti Kaihola +Anubhav Patel +Anudit Nagar +Anuj Godase +AQNOUCH Mohammed +AraHaan +Arindam Choudhury +Armin Ronacher +Artem +Ashley Manton +Ashwin Ramaswami +atse +Atsushi Odagiri +Avner Cohen +Baptiste Mispelon +Barney Gale +barneygale +Bartek Ogryczak +Bastian Venthur +Ben Darnell +Ben Hoyt +Ben Rosser +Bence Nagy +Benjamin Peterson +Benjamin VanEvery +Benoit Pierre +Berker Peksag +Bernardo B. Marques +Bernhard M. Wiedemann +Bertil Hatt +Bhavam Vidyarthi +Bogdan Opanchuk +BorisZZZ +Brad Erickson +Bradley Ayers +Brandon L. Reiss +Brandt Bucher +Brett Randall +Brian Cristante +Brian Rosner +BrownTruck +Bruno Oliveira +Bruno Renié +Bstrdsmkr +Buck Golemon +burrows +Bussonnier Matthias +c22 +Caleb Martinez +Calvin Smith +Carl Meyer +Carlos Liam +Carol Willing +Carter Thayer +Cass +Chandrasekhar Atina +Chih-Hsuan Yen +Chris Brinker +Chris Hunt +Chris Jerdonek +Chris McDonough +Chris Wolfe +Christian Clauss +Christian Heimes +Christian Oudard +Christoph Reiter +Christopher Hunt +Christopher Snyder +cjc7373 +Clark Boylan +Clay McClure +Cody +Cody Soyland +Colin Watson +Connor Osborn +Cooper Lees +Cooper Ry Lees +Cory Benfield +Cory Wright +Craig Kerstiens +Cristian Sorinel +Curtis Doty +cytolentino +Damian Quiroga +Dan Black +Dan Savilonis +Dan Sully +daniel +Daniel Collins +Daniel Hahler +Daniel Holth +Daniel Jost +Daniel Shaulov +Daniele Esposti +Daniele Procida +Danny Hermes +Danny McClanahan +Dav Clark +Dave Abrahams +Dave Jones +David Aguilar +David Black +David Bordeynik +David Caro +David Evans +David Linke +David Pursehouse +David Tucker +David Wales +Davidovich +Deepak Sharma +derwolfe +Desetude +Devesh Kumar Singh +Diego Caraballo +DiegoCaraballo +Dmitry Gladkov +Domen Kožar +Donald Stufft +Dongweiming +Douglas Thor +DrFeathers +Dustin Ingram +Dwayne Bailey +Ed Morley +Eitan Adler +ekristina +elainechan +Eli Schwartz +Ellen Marie Dash +Emil Burzo +Emil Styrke +Endoh Takanao +enoch +Erdinc Mutlu +Eric Gillingham +Eric Hanchrow +Eric Hopper +Erik M. Bray +Erik Rose +Ernest W Durbin III +Ernest W. Durbin III +Erwin Janssen +Eugene Vereshchagin +everdimension +Felix Yan +fiber-space +Filip Kokosiński +Florian Briand +Florian Rathgeber +Francesco +Francesco Montesano +Frost Ming +Gabriel Curio +Gabriel de Perthuis +Garry Polley +gdanielson +Geoffrey Lehée +Geoffrey Sneddon +George Song +Georgi Valkov +ghost +Giftlin Rajaiah +gizmoguy1 +gkdoc +Gopinath M +GOTO Hayato +gpiks +Guilherme Espada +gutsytechster +Guy Rozendorn +gzpan123 +Hanjun Kim +Hari Charan +Harsh Vardhan +Herbert Pfennig +Hsiaoming Yang +Hugo +Hugo Lopes Tavares +Hugo van Kemenade +hugovk +Hynek Schlawack +Ian Bicking +Ian Cordasco +Ian Lee +Ian Stapleton Cordasco +Ian Wienand +Igor Kuzmitshov +Igor Sobreira +Ilan Schnell +Ilya Baryshev +INADA Naoki +Ionel Cristian Mărieș +Ionel Maries Cristian +Ivan Pozdeev +Jacob Kim +jakirkham +Jakub Stasiak +Jakub Vysoky +Jakub Wilk +James Cleveland +James Firth +James Polley +Jan Pokorný +Jannis Leidel +jarondl +Jason R. Coombs +Jay Graves +Jean-Christophe Fillion-Robin +Jeff Barber +Jeff Dairiki +Jelmer Vernooij +jenix21 +Jeremy Stanley +Jeremy Zafran +Jiashuo Li +Jim Garrison +Jivan Amara +John Paton +John T. Wodder II +John-Scott Atlakson +johnthagen +Jon Banafato +Jon Dufresne +Jon Parise +Jonas Nockert +Jonathan Herbert +Joost Molenaar +Jorge Niedbalski +Joseph Long +Josh Bronson +Josh Hansen +Josh Schneier +Juanjo Bazán +Julian Berman +Julian Gethmann +Julien Demoor +jwg4 +Jyrki Pulliainen +Kai Chen +Kamal Bin Mustafa +kaustav haldar +keanemind +Keith Maxwell +Kelsey Hightower +Kenneth Belitzky +Kenneth Reitz +Kevin Burke +Kevin Carter +Kevin Frommelt +Kevin R Patterson +Kexuan Sun +Kit Randel +KOLANICH +kpinc +Krishna Oza +Kumar McMillan +Kyle Persohn +lakshmanaram +Laszlo Kiss-Kollar +Laurent Bristiel +Laurie Opperman +Leon Sasson +Lev Givon +Lincoln de Sousa +Lipis +Loren Carvalho +Lucas Cimon +Ludovic Gasc +Luke Macken +Luo Jiebin +luojiebin +luz.paz +László Kiss Kollár +Marc Abramowitz +Marc Tamlyn +Marcus Smith +Mariatta +Mark Kohler +Mark Williams +Markus Hametner +Masaki +Masklinn +Matej Stuchlik +Mathew Jennings +Mathieu Bridon +Matt Good +Matt Maker +Matt Robenolt +matthew +Matthew Einhorn +Matthew Gilliard +Matthew Iversen +Matthew Trumbell +Matthew Willson +Matthias Bussonnier +mattip +Maxim Kurnikov +Maxime Rouyrre +mayeut +mbaluna +mdebi +memoselyk +Michael +Michael Aquilina +Michael E. Karpeles +Michael Klich +Michael Williamson +michaelpacer +Mickaël Schoentgen +Miguel Araujo Perez +Mihir Singh +Mike +Mike Hendricks +Min RK +MinRK +Miro Hrončok +Monica Baluna +montefra +Monty Taylor +Nate Coraor +Nathaniel J. Smith +Nehal J Wani +Neil Botelho +Nguyễn Gia Phong +Nick Coghlan +Nick Stenning +Nick Timkovich +Nicolas Bock +Nikhil Benesch +Nikolay Korolev +Nitesh Sharma +Noah Gorny +Nowell Strite +NtaleGrey +nvdv +Ofekmeister +ofrinevo +Oliver Jeeves +Oliver Tonnhofer +Olivier Girardot +Olivier Grisel +Ollie Rutherfurd +OMOTO Kenji +Omry Yadan +onlinejudge95 +Oren Held +Oscar Benjamin +Oz N Tiram +Pachwenko +Patrick Dubroy +Patrick Jenkins +Patrick Lawson +patricktokeeffe +Patrik Kopkan +Paul Kehrer +Paul Moore +Paul Nasrat +Paul Oswald +Paul van der Linden +Paulus Schoutsen +Pavithra Eswaramoorthy +Pawel Jasinski +Pekka Klärck +Peter Lisák +Peter Waller +petr-tik +Phaneendra Chiruvella +Phil Freo +Phil Pennock +Phil Whelan +Philip Jägenstedt +Philip Molloy +Philippe Ombredanne +Pi Delport +Pierre-Yves Rofes +pip +Prabakaran Kumaresshan +Prabhjyotsing Surjit Singh Sodhi +Prabhu Marappan +Pradyun Gedam +Prashant Sharma +Pratik Mallya +Preet Thakkar +Preston Holmes +Przemek Wrzos +Pulkit Goyal +Qiangning Hong +Quentin Pradet +R. David Murray +Rafael Caricio +Ralf Schmitt +Razzi Abuissa +rdb +Reece Dunham +Remi Rampin +Rene Dudfield +Riccardo Magliocchetti +Richard Jones +Ricky Ng-Adam +RobberPhex +Robert Collins +Robert McGibbon +Robert T. McGibbon +robin elisha robinson +Roey Berman +Rohan Jain +Roman Bogorodskiy +Romuald Brunet +Ronny Pfannschmidt +Rory McCann +Ross Brattain +Roy Wellington Ⅳ +Ryan Wooden +ryneeverett +Sachi King +Salvatore Rinchiera +Savio Jomton +schlamar +Scott Kitterman +Sean +seanj +Sebastian Jordan +Sebastian Schaetz +Segev Finer +SeongSoo Cho +Sergey Vasilyev +Seth Woodworth +Shlomi Fish +Shovan Maity +Simeon Visser +Simon Cross +Simon Pichugin +sinoroc +sinscary +Sorin Sbarnea +Stavros Korokithakis +Stefan Scherfke +Stefano Rivera +Stephan Erb +stepshal +Steve (Gadget) Barnes +Steve Barnes +Steve Dower +Steve Kowalik +Steven Myint +stonebig +Stéphane Bidoul +Stéphane Bidoul (ACSONE) +Stéphane Klein +Sumana Harihareswara +Sviatoslav Sydorenko +Swat009 +Takayuki SHIMIZUKAWA +tbeswick +Thijs Triemstra +Thomas Fenzl +Thomas Grainger +Thomas Guettler +Thomas Johansson +Thomas Kluyver +Thomas Smith +Tim D. Smith +Tim Gates +Tim Harder +Tim Heap +tim smith +tinruufu +Tom Forbes +Tom Freudenheim +Tom V +Tomas Hrnciar +Tomas Orsava +Tomer Chachamu +Tony Beswick +Tony Zhaocheng Tan +TonyBeswick +toonarmycaptain +Toshio Kuratomi +Travis Swicegood +Tzu-ping Chung +Valentin Haenel +Victor Stinner +victorvpaulo +Viktor Szépe +Ville Skyttä +Vinay Sajip +Vincent Philippon +Vinicyus Macedo +Vitaly Babiy +Vladimir Rutsky +W. Trevor King +Wil Tan +Wilfred Hughes +William ML Leslie +William T Olson +Wilson Mo +wim glenn +Wolfgang Maier +Xavier Fernandez +xoviat +xtreak +YAMAMOTO Takashi +Yen Chi Hsuan +Yeray Diaz Diaz +Yoval P +Yu Jian +Yuan Jing Vincent Yan +Zearin +Zhiping Deng +Zvezdan Petkovic +Łukasz Langa +Семён Марьясин diff --git a/venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/INSTALLER b/venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/LICENSE.txt b/venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/LICENSE.txt new file mode 100644 index 0000000..737fec5 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/LICENSE.txt @@ -0,0 +1,20 @@ +Copyright (c) 2008-2019 The pip developers (see AUTHORS.txt file) + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/METADATA b/venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/METADATA new file mode 100644 index 0000000..cf6c930 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/METADATA @@ -0,0 +1,13 @@ +Metadata-Version: 2.1 +Name: pkg_resources +Version: 0.0.0 +Summary: UNKNOWN +Home-page: UNKNOWN +Author: UNKNOWN +Author-email: UNKNOWN +License: UNKNOWN +Platform: UNKNOWN + +UNKNOWN + + diff --git a/venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/RECORD b/venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/RECORD new file mode 100644 index 0000000..562db11 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/RECORD @@ -0,0 +1,38 @@ +pkg_resources-0.0.0.dist-info/AUTHORS.txt,sha256=RnTFYKrTgbpfWnZMizLRq0u31iGDJMbs-iqvafo1CcA,7734 +pkg_resources-0.0.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +pkg_resources-0.0.0.dist-info/LICENSE.txt,sha256=W6Ifuwlk-TatfRU2LR7W1JMcyMj5_y1NkRkOEJvnRDE,1090 +pkg_resources-0.0.0.dist-info/METADATA,sha256=V9_WPOtD1FnuKrTGv6Ique7kAOn2lasvT8W0_iMCCCk,177 +pkg_resources-0.0.0.dist-info/RECORD,, +pkg_resources-0.0.0.dist-info/WHEEL,sha256=kGT74LWyRUZrL4VgLh6_g12IeVl_9u9ZVhadrgXZUEY,110 +pkg_resources/__init__.py,sha256=0IssxXPnaDKpYZRra8Ime0JG4hwosQljItGD0bnIkGk,108349 +pkg_resources/__pycache__/__init__.cpython-38.pyc,, +pkg_resources/__pycache__/py31compat.cpython-38.pyc,, +pkg_resources/_vendor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +pkg_resources/_vendor/__pycache__/__init__.cpython-38.pyc,, +pkg_resources/_vendor/__pycache__/appdirs.cpython-38.pyc,, +pkg_resources/_vendor/__pycache__/pyparsing.cpython-38.pyc,, +pkg_resources/_vendor/__pycache__/six.cpython-38.pyc,, +pkg_resources/_vendor/appdirs.py,sha256=MievUEuv3l_mQISH5SF0shDk_BNhHHzYiAPrT3ITN4I,24701 +pkg_resources/_vendor/packaging/__about__.py,sha256=zkcCPTN_6TcLW0Nrlg0176-R1QQ_WVPTm8sz1R4-HjM,720 +pkg_resources/_vendor/packaging/__init__.py,sha256=_vNac5TrzwsrzbOFIbF-5cHqc_Y2aPT2D7zrIR06BOo,513 +pkg_resources/_vendor/packaging/__pycache__/__about__.cpython-38.pyc,, +pkg_resources/_vendor/packaging/__pycache__/__init__.cpython-38.pyc,, +pkg_resources/_vendor/packaging/__pycache__/_compat.cpython-38.pyc,, +pkg_resources/_vendor/packaging/__pycache__/_structures.cpython-38.pyc,, +pkg_resources/_vendor/packaging/__pycache__/markers.cpython-38.pyc,, +pkg_resources/_vendor/packaging/__pycache__/requirements.cpython-38.pyc,, +pkg_resources/_vendor/packaging/__pycache__/specifiers.cpython-38.pyc,, +pkg_resources/_vendor/packaging/__pycache__/utils.cpython-38.pyc,, +pkg_resources/_vendor/packaging/__pycache__/version.cpython-38.pyc,, +pkg_resources/_vendor/packaging/_compat.py,sha256=Vi_A0rAQeHbU-a9X0tt1yQm9RqkgQbDSxzRw8WlU9kA,860 +pkg_resources/_vendor/packaging/_structures.py,sha256=RImECJ4c_wTlaTYYwZYLHEiebDMaAJmK1oPARhw1T5o,1416 +pkg_resources/_vendor/packaging/markers.py,sha256=uEcBBtGvzqltgnArqb9c4RrcInXezDLos14zbBHhWJo,8248 +pkg_resources/_vendor/packaging/requirements.py,sha256=SikL2UynbsT0qtY9ltqngndha_sfo0w6XGFhAhoSoaQ,4355 +pkg_resources/_vendor/packaging/specifiers.py,sha256=SAMRerzO3fK2IkFZCaZkuwZaL_EGqHNOz4pni4vhnN0,28025 +pkg_resources/_vendor/packaging/utils.py,sha256=3m6WvPm6NNxE8rkTGmn0r75B_GZSGg7ikafxHsBN1WA,421 +pkg_resources/_vendor/packaging/version.py,sha256=OwGnxYfr2ghNzYx59qWIBkrK3SnB6n-Zfd1XaLpnnM0,11556 +pkg_resources/_vendor/pyparsing.py,sha256=tmrp-lu-qO1i75ZzIN5A12nKRRD1Cm4Vpk-5LR9rims,232055 +pkg_resources/_vendor/six.py,sha256=A6hdJZVjI3t_geebZ9BzUvwRrIXo0lfwzQlM2LcKyas,30098 +pkg_resources/extern/__init__.py,sha256=cHiEfHuLmm6rs5Ve_ztBfMI7Lr31vss-D4wkqF5xzlI,2498 +pkg_resources/extern/__pycache__/__init__.cpython-38.pyc,, +pkg_resources/py31compat.py,sha256=-WQ0e4c3RG_acdhwC3gLiXhP_lg4G5q7XYkZkQg0gxU,558 diff --git a/venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/WHEEL b/venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/WHEEL new file mode 100644 index 0000000..ef99c6c --- /dev/null +++ b/venv/lib/python3.8/site-packages/pkg_resources-0.0.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/venv/lib/python3.8/site-packages/pkg_resources/__init__.py b/venv/lib/python3.8/site-packages/pkg_resources/__init__.py new file mode 100644 index 0000000..2f5aa64 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pkg_resources/__init__.py @@ -0,0 +1,3296 @@ +# coding: utf-8 +""" +Package resource API +-------------------- + +A resource is a logical file contained within a package, or a logical +subdirectory thereof. The package resource API expects resource names +to have their path parts separated with ``/``, *not* whatever the local +path separator is. Do not use os.path operations to manipulate resource +names being passed into the API. + +The package resource API is designed to work with normal filesystem packages, +.egg files, and unpacked .egg files. It can also work in a limited way with +.zip files and with custom PEP 302 loaders that support the ``get_data()`` +method. +""" + +from __future__ import absolute_import + +import sys +import os +import io +import time +import re +import types +import zipfile +import zipimport +import warnings +import stat +import functools +import pkgutil +import operator +import platform +import collections +import plistlib +import email.parser +import errno +import tempfile +import textwrap +import itertools +import inspect +import ntpath +import posixpath +from pkgutil import get_importer + +try: + import _imp +except ImportError: + # Python 3.2 compatibility + import imp as _imp + +try: + FileExistsError +except NameError: + FileExistsError = OSError + +from pkg_resources.extern import six +from pkg_resources.extern.six.moves import urllib, map, filter + +# capture these to bypass sandboxing +from os import utime +try: + from os import mkdir, rename, unlink + WRITE_SUPPORT = True +except ImportError: + # no write support, probably under GAE + WRITE_SUPPORT = False + +from os import open as os_open +from os.path import isdir, split + +try: + import importlib.machinery as importlib_machinery + # access attribute to force import under delayed import mechanisms. + importlib_machinery.__name__ +except ImportError: + importlib_machinery = None + +from . import py31compat +from pkg_resources.extern import appdirs +from pkg_resources.extern import packaging +__import__('pkg_resources.extern.packaging.version') +__import__('pkg_resources.extern.packaging.specifiers') +__import__('pkg_resources.extern.packaging.requirements') +__import__('pkg_resources.extern.packaging.markers') + + +__metaclass__ = type + + +if (3, 0) < sys.version_info < (3, 5): + raise RuntimeError("Python 3.5 or later is required") + +if six.PY2: + # Those builtin exceptions are only defined in Python 3 + PermissionError = None + NotADirectoryError = None + +# declare some globals that will be defined later to +# satisfy the linters. +require = None +working_set = None +add_activation_listener = None +resources_stream = None +cleanup_resources = None +resource_dir = None +resource_stream = None +set_extraction_path = None +resource_isdir = None +resource_string = None +iter_entry_points = None +resource_listdir = None +resource_filename = None +resource_exists = None +_distribution_finders = None +_namespace_handlers = None +_namespace_packages = None + + +class PEP440Warning(RuntimeWarning): + """ + Used when there is an issue with a version or specifier not complying with + PEP 440. + """ + + +def parse_version(v): + try: + return packaging.version.Version(v) + except packaging.version.InvalidVersion: + return packaging.version.LegacyVersion(v) + + +_state_vars = {} + + +def _declare_state(vartype, **kw): + globals().update(kw) + _state_vars.update(dict.fromkeys(kw, vartype)) + + +def __getstate__(): + state = {} + g = globals() + for k, v in _state_vars.items(): + state[k] = g['_sget_' + v](g[k]) + return state + + +def __setstate__(state): + g = globals() + for k, v in state.items(): + g['_sset_' + _state_vars[k]](k, g[k], v) + return state + + +def _sget_dict(val): + return val.copy() + + +def _sset_dict(key, ob, state): + ob.clear() + ob.update(state) + + +def _sget_object(val): + return val.__getstate__() + + +def _sset_object(key, ob, state): + ob.__setstate__(state) + + +_sget_none = _sset_none = lambda *args: None + + +def get_supported_platform(): + """Return this platform's maximum compatible version. + + distutils.util.get_platform() normally reports the minimum version + of Mac OS X that would be required to *use* extensions produced by + distutils. But what we want when checking compatibility is to know the + version of Mac OS X that we are *running*. To allow usage of packages that + explicitly require a newer version of Mac OS X, we must also know the + current version of the OS. + + If this condition occurs for any other platform with a version in its + platform strings, this function should be extended accordingly. + """ + plat = get_build_platform() + m = macosVersionString.match(plat) + if m is not None and sys.platform == "darwin": + try: + plat = 'macosx-%s-%s' % ('.'.join(_macosx_vers()[:2]), m.group(3)) + except ValueError: + # not Mac OS X + pass + return plat + + +__all__ = [ + # Basic resource access and distribution/entry point discovery + 'require', 'run_script', 'get_provider', 'get_distribution', + 'load_entry_point', 'get_entry_map', 'get_entry_info', + 'iter_entry_points', + 'resource_string', 'resource_stream', 'resource_filename', + 'resource_listdir', 'resource_exists', 'resource_isdir', + + # Environmental control + 'declare_namespace', 'working_set', 'add_activation_listener', + 'find_distributions', 'set_extraction_path', 'cleanup_resources', + 'get_default_cache', + + # Primary implementation classes + 'Environment', 'WorkingSet', 'ResourceManager', + 'Distribution', 'Requirement', 'EntryPoint', + + # Exceptions + 'ResolutionError', 'VersionConflict', 'DistributionNotFound', + 'UnknownExtra', 'ExtractionError', + + # Warnings + 'PEP440Warning', + + # Parsing functions and string utilities + 'parse_requirements', 'parse_version', 'safe_name', 'safe_version', + 'get_platform', 'compatible_platforms', 'yield_lines', 'split_sections', + 'safe_extra', 'to_filename', 'invalid_marker', 'evaluate_marker', + + # filesystem utilities + 'ensure_directory', 'normalize_path', + + # Distribution "precedence" constants + 'EGG_DIST', 'BINARY_DIST', 'SOURCE_DIST', 'CHECKOUT_DIST', 'DEVELOP_DIST', + + # "Provider" interfaces, implementations, and registration/lookup APIs + 'IMetadataProvider', 'IResourceProvider', 'FileMetadata', + 'PathMetadata', 'EggMetadata', 'EmptyProvider', 'empty_provider', + 'NullProvider', 'EggProvider', 'DefaultProvider', 'ZipProvider', + 'register_finder', 'register_namespace_handler', 'register_loader_type', + 'fixup_namespace_packages', 'get_importer', + + # Warnings + 'PkgResourcesDeprecationWarning', + + # Deprecated/backward compatibility only + 'run_main', 'AvailableDistributions', +] + + +class ResolutionError(Exception): + """Abstract base for dependency resolution errors""" + + def __repr__(self): + return self.__class__.__name__ + repr(self.args) + + +class VersionConflict(ResolutionError): + """ + An already-installed version conflicts with the requested version. + + Should be initialized with the installed Distribution and the requested + Requirement. + """ + + _template = "{self.dist} is installed but {self.req} is required" + + @property + def dist(self): + return self.args[0] + + @property + def req(self): + return self.args[1] + + def report(self): + return self._template.format(**locals()) + + def with_context(self, required_by): + """ + If required_by is non-empty, return a version of self that is a + ContextualVersionConflict. + """ + if not required_by: + return self + args = self.args + (required_by,) + return ContextualVersionConflict(*args) + + +class ContextualVersionConflict(VersionConflict): + """ + A VersionConflict that accepts a third parameter, the set of the + requirements that required the installed Distribution. + """ + + _template = VersionConflict._template + ' by {self.required_by}' + + @property + def required_by(self): + return self.args[2] + + +class DistributionNotFound(ResolutionError): + """A requested distribution was not found""" + + _template = ("The '{self.req}' distribution was not found " + "and is required by {self.requirers_str}") + + @property + def req(self): + return self.args[0] + + @property + def requirers(self): + return self.args[1] + + @property + def requirers_str(self): + if not self.requirers: + return 'the application' + return ', '.join(self.requirers) + + def report(self): + return self._template.format(**locals()) + + def __str__(self): + return self.report() + + +class UnknownExtra(ResolutionError): + """Distribution doesn't have an "extra feature" of the given name""" + + +_provider_factories = {} + +PY_MAJOR = '{}.{}'.format(*sys.version_info) +EGG_DIST = 3 +BINARY_DIST = 2 +SOURCE_DIST = 1 +CHECKOUT_DIST = 0 +DEVELOP_DIST = -1 + + +def register_loader_type(loader_type, provider_factory): + """Register `provider_factory` to make providers for `loader_type` + + `loader_type` is the type or class of a PEP 302 ``module.__loader__``, + and `provider_factory` is a function that, passed a *module* object, + returns an ``IResourceProvider`` for that module. + """ + _provider_factories[loader_type] = provider_factory + + +def get_provider(moduleOrReq): + """Return an IResourceProvider for the named module or requirement""" + if isinstance(moduleOrReq, Requirement): + return working_set.find(moduleOrReq) or require(str(moduleOrReq))[0] + try: + module = sys.modules[moduleOrReq] + except KeyError: + __import__(moduleOrReq) + module = sys.modules[moduleOrReq] + loader = getattr(module, '__loader__', None) + return _find_adapter(_provider_factories, loader)(module) + + +def _macosx_vers(_cache=[]): + if not _cache: + version = platform.mac_ver()[0] + # fallback for MacPorts + if version == '': + plist = '/System/Library/CoreServices/SystemVersion.plist' + if os.path.exists(plist): + if hasattr(plistlib, 'readPlist'): + plist_content = plistlib.readPlist(plist) + if 'ProductVersion' in plist_content: + version = plist_content['ProductVersion'] + + _cache.append(version.split('.')) + return _cache[0] + + +def _macosx_arch(machine): + return {'PowerPC': 'ppc', 'Power_Macintosh': 'ppc'}.get(machine, machine) + + +def get_build_platform(): + """Return this platform's string for platform-specific distributions + + XXX Currently this is the same as ``distutils.util.get_platform()``, but it + needs some hacks for Linux and Mac OS X. + """ + from sysconfig import get_platform + + plat = get_platform() + if sys.platform == "darwin" and not plat.startswith('macosx-'): + try: + version = _macosx_vers() + machine = os.uname()[4].replace(" ", "_") + return "macosx-%d.%d-%s" % ( + int(version[0]), int(version[1]), + _macosx_arch(machine), + ) + except ValueError: + # if someone is running a non-Mac darwin system, this will fall + # through to the default implementation + pass + return plat + + +macosVersionString = re.compile(r"macosx-(\d+)\.(\d+)-(.*)") +darwinVersionString = re.compile(r"darwin-(\d+)\.(\d+)\.(\d+)-(.*)") +# XXX backward compat +get_platform = get_build_platform + + +def compatible_platforms(provided, required): + """Can code for the `provided` platform run on the `required` platform? + + Returns true if either platform is ``None``, or the platforms are equal. + + XXX Needs compatibility checks for Linux and other unixy OSes. + """ + if provided is None or required is None or provided == required: + # easy case + return True + + # Mac OS X special cases + reqMac = macosVersionString.match(required) + if reqMac: + provMac = macosVersionString.match(provided) + + # is this a Mac package? + if not provMac: + # this is backwards compatibility for packages built before + # setuptools 0.6. All packages built after this point will + # use the new macosx designation. + provDarwin = darwinVersionString.match(provided) + if provDarwin: + dversion = int(provDarwin.group(1)) + macosversion = "%s.%s" % (reqMac.group(1), reqMac.group(2)) + if dversion == 7 and macosversion >= "10.3" or \ + dversion == 8 and macosversion >= "10.4": + return True + # egg isn't macosx or legacy darwin + return False + + # are they the same major version and machine type? + if provMac.group(1) != reqMac.group(1) or \ + provMac.group(3) != reqMac.group(3): + return False + + # is the required OS major update >= the provided one? + if int(provMac.group(2)) > int(reqMac.group(2)): + return False + + return True + + # XXX Linux and other platforms' special cases should go here + return False + + +def run_script(dist_spec, script_name): + """Locate distribution `dist_spec` and run its `script_name` script""" + ns = sys._getframe(1).f_globals + name = ns['__name__'] + ns.clear() + ns['__name__'] = name + require(dist_spec)[0].run_script(script_name, ns) + + +# backward compatibility +run_main = run_script + + +def get_distribution(dist): + """Return a current distribution object for a Requirement or string""" + if isinstance(dist, six.string_types): + dist = Requirement.parse(dist) + if isinstance(dist, Requirement): + dist = get_provider(dist) + if not isinstance(dist, Distribution): + raise TypeError("Expected string, Requirement, or Distribution", dist) + return dist + + +def load_entry_point(dist, group, name): + """Return `name` entry point of `group` for `dist` or raise ImportError""" + return get_distribution(dist).load_entry_point(group, name) + + +def get_entry_map(dist, group=None): + """Return the entry point map for `group`, or the full entry map""" + return get_distribution(dist).get_entry_map(group) + + +def get_entry_info(dist, group, name): + """Return the EntryPoint object for `group`+`name`, or ``None``""" + return get_distribution(dist).get_entry_info(group, name) + + +class IMetadataProvider: + def has_metadata(name): + """Does the package's distribution contain the named metadata?""" + + def get_metadata(name): + """The named metadata resource as a string""" + + def get_metadata_lines(name): + """Yield named metadata resource as list of non-blank non-comment lines + + Leading and trailing whitespace is stripped from each line, and lines + with ``#`` as the first non-blank character are omitted.""" + + def metadata_isdir(name): + """Is the named metadata a directory? (like ``os.path.isdir()``)""" + + def metadata_listdir(name): + """List of metadata names in the directory (like ``os.listdir()``)""" + + def run_script(script_name, namespace): + """Execute the named script in the supplied namespace dictionary""" + + +class IResourceProvider(IMetadataProvider): + """An object that provides access to package resources""" + + def get_resource_filename(manager, resource_name): + """Return a true filesystem path for `resource_name` + + `manager` must be an ``IResourceManager``""" + + def get_resource_stream(manager, resource_name): + """Return a readable file-like object for `resource_name` + + `manager` must be an ``IResourceManager``""" + + def get_resource_string(manager, resource_name): + """Return a string containing the contents of `resource_name` + + `manager` must be an ``IResourceManager``""" + + def has_resource(resource_name): + """Does the package contain the named resource?""" + + def resource_isdir(resource_name): + """Is the named resource a directory? (like ``os.path.isdir()``)""" + + def resource_listdir(resource_name): + """List of resource names in the directory (like ``os.listdir()``)""" + + +class WorkingSet: + """A collection of active distributions on sys.path (or a similar list)""" + + def __init__(self, entries=None): + """Create working set from list of path entries (default=sys.path)""" + self.entries = [] + self.entry_keys = {} + self.by_key = {} + self.callbacks = [] + + if entries is None: + entries = sys.path + + for entry in entries: + self.add_entry(entry) + + @classmethod + def _build_master(cls): + """ + Prepare the master working set. + """ + ws = cls() + try: + from __main__ import __requires__ + except ImportError: + # The main program does not list any requirements + return ws + + # ensure the requirements are met + try: + ws.require(__requires__) + except VersionConflict: + return cls._build_from_requirements(__requires__) + + return ws + + @classmethod + def _build_from_requirements(cls, req_spec): + """ + Build a working set from a requirement spec. Rewrites sys.path. + """ + # try it without defaults already on sys.path + # by starting with an empty path + ws = cls([]) + reqs = parse_requirements(req_spec) + dists = ws.resolve(reqs, Environment()) + for dist in dists: + ws.add(dist) + + # add any missing entries from sys.path + for entry in sys.path: + if entry not in ws.entries: + ws.add_entry(entry) + + # then copy back to sys.path + sys.path[:] = ws.entries + return ws + + def add_entry(self, entry): + """Add a path item to ``.entries``, finding any distributions on it + + ``find_distributions(entry, True)`` is used to find distributions + corresponding to the path entry, and they are added. `entry` is + always appended to ``.entries``, even if it is already present. + (This is because ``sys.path`` can contain the same value more than + once, and the ``.entries`` of the ``sys.path`` WorkingSet should always + equal ``sys.path``.) + """ + self.entry_keys.setdefault(entry, []) + self.entries.append(entry) + for dist in find_distributions(entry, True): + self.add(dist, entry, False) + + def __contains__(self, dist): + """True if `dist` is the active distribution for its project""" + return self.by_key.get(dist.key) == dist + + def find(self, req): + """Find a distribution matching requirement `req` + + If there is an active distribution for the requested project, this + returns it as long as it meets the version requirement specified by + `req`. But, if there is an active distribution for the project and it + does *not* meet the `req` requirement, ``VersionConflict`` is raised. + If there is no active distribution for the requested project, ``None`` + is returned. + """ + dist = self.by_key.get(req.key) + if dist is not None and dist not in req: + # XXX add more info + raise VersionConflict(dist, req) + return dist + + def iter_entry_points(self, group, name=None): + """Yield entry point objects from `group` matching `name` + + If `name` is None, yields all entry points in `group` from all + distributions in the working set, otherwise only ones matching + both `group` and `name` are yielded (in distribution order). + """ + return ( + entry + for dist in self + for entry in dist.get_entry_map(group).values() + if name is None or name == entry.name + ) + + def run_script(self, requires, script_name): + """Locate distribution for `requires` and run `script_name` script""" + ns = sys._getframe(1).f_globals + name = ns['__name__'] + ns.clear() + ns['__name__'] = name + self.require(requires)[0].run_script(script_name, ns) + + def __iter__(self): + """Yield distributions for non-duplicate projects in the working set + + The yield order is the order in which the items' path entries were + added to the working set. + """ + seen = {} + for item in self.entries: + if item not in self.entry_keys: + # workaround a cache issue + continue + + for key in self.entry_keys[item]: + if key not in seen: + seen[key] = 1 + yield self.by_key[key] + + def add(self, dist, entry=None, insert=True, replace=False): + """Add `dist` to working set, associated with `entry` + + If `entry` is unspecified, it defaults to the ``.location`` of `dist`. + On exit from this routine, `entry` is added to the end of the working + set's ``.entries`` (if it wasn't already present). + + `dist` is only added to the working set if it's for a project that + doesn't already have a distribution in the set, unless `replace=True`. + If it's added, any callbacks registered with the ``subscribe()`` method + will be called. + """ + if insert: + dist.insert_on(self.entries, entry, replace=replace) + + if entry is None: + entry = dist.location + keys = self.entry_keys.setdefault(entry, []) + keys2 = self.entry_keys.setdefault(dist.location, []) + if not replace and dist.key in self.by_key: + # ignore hidden distros + return + + self.by_key[dist.key] = dist + if dist.key not in keys: + keys.append(dist.key) + if dist.key not in keys2: + keys2.append(dist.key) + self._added_new(dist) + + def resolve(self, requirements, env=None, installer=None, + replace_conflicting=False, extras=None): + """List all distributions needed to (recursively) meet `requirements` + + `requirements` must be a sequence of ``Requirement`` objects. `env`, + if supplied, should be an ``Environment`` instance. If + not supplied, it defaults to all distributions available within any + entry or distribution in the working set. `installer`, if supplied, + will be invoked with each requirement that cannot be met by an + already-installed distribution; it should return a ``Distribution`` or + ``None``. + + Unless `replace_conflicting=True`, raises a VersionConflict exception + if + any requirements are found on the path that have the correct name but + the wrong version. Otherwise, if an `installer` is supplied it will be + invoked to obtain the correct version of the requirement and activate + it. + + `extras` is a list of the extras to be used with these requirements. + This is important because extra requirements may look like `my_req; + extra = "my_extra"`, which would otherwise be interpreted as a purely + optional requirement. Instead, we want to be able to assert that these + requirements are truly required. + """ + + # set up the stack + requirements = list(requirements)[::-1] + # set of processed requirements + processed = {} + # key -> dist + best = {} + to_activate = [] + + req_extras = _ReqExtras() + + # Mapping of requirement to set of distributions that required it; + # useful for reporting info about conflicts. + required_by = collections.defaultdict(set) + + while requirements: + # process dependencies breadth-first + req = requirements.pop(0) + if req in processed: + # Ignore cyclic or redundant dependencies + continue + + if not req_extras.markers_pass(req, extras): + continue + + dist = best.get(req.key) + if dist is None: + # Find the best distribution and add it to the map + dist = self.by_key.get(req.key) + if dist is None or (dist not in req and replace_conflicting): + ws = self + if env is None: + if dist is None: + env = Environment(self.entries) + else: + # Use an empty environment and workingset to avoid + # any further conflicts with the conflicting + # distribution + env = Environment([]) + ws = WorkingSet([]) + dist = best[req.key] = env.best_match( + req, ws, installer, + replace_conflicting=replace_conflicting + ) + if dist is None: + requirers = required_by.get(req, None) + raise DistributionNotFound(req, requirers) + to_activate.append(dist) + if dist not in req: + # Oops, the "best" so far conflicts with a dependency + dependent_req = required_by[req] + raise VersionConflict(dist, req).with_context(dependent_req) + + # push the new requirements onto the stack + new_requirements = dist.requires(req.extras)[::-1] + requirements.extend(new_requirements) + + # Register the new requirements needed by req + for new_requirement in new_requirements: + required_by[new_requirement].add(req.project_name) + req_extras[new_requirement] = req.extras + + processed[req] = True + + # return list of distros to activate + return to_activate + + def find_plugins( + self, plugin_env, full_env=None, installer=None, fallback=True): + """Find all activatable distributions in `plugin_env` + + Example usage:: + + distributions, errors = working_set.find_plugins( + Environment(plugin_dirlist) + ) + # add plugins+libs to sys.path + map(working_set.add, distributions) + # display errors + print('Could not load', errors) + + The `plugin_env` should be an ``Environment`` instance that contains + only distributions that are in the project's "plugin directory" or + directories. The `full_env`, if supplied, should be an ``Environment`` + contains all currently-available distributions. If `full_env` is not + supplied, one is created automatically from the ``WorkingSet`` this + method is called on, which will typically mean that every directory on + ``sys.path`` will be scanned for distributions. + + `installer` is a standard installer callback as used by the + ``resolve()`` method. The `fallback` flag indicates whether we should + attempt to resolve older versions of a plugin if the newest version + cannot be resolved. + + This method returns a 2-tuple: (`distributions`, `error_info`), where + `distributions` is a list of the distributions found in `plugin_env` + that were loadable, along with any other distributions that are needed + to resolve their dependencies. `error_info` is a dictionary mapping + unloadable plugin distributions to an exception instance describing the + error that occurred. Usually this will be a ``DistributionNotFound`` or + ``VersionConflict`` instance. + """ + + plugin_projects = list(plugin_env) + # scan project names in alphabetic order + plugin_projects.sort() + + error_info = {} + distributions = {} + + if full_env is None: + env = Environment(self.entries) + env += plugin_env + else: + env = full_env + plugin_env + + shadow_set = self.__class__([]) + # put all our entries in shadow_set + list(map(shadow_set.add, self)) + + for project_name in plugin_projects: + + for dist in plugin_env[project_name]: + + req = [dist.as_requirement()] + + try: + resolvees = shadow_set.resolve(req, env, installer) + + except ResolutionError as v: + # save error info + error_info[dist] = v + if fallback: + # try the next older version of project + continue + else: + # give up on this project, keep going + break + + else: + list(map(shadow_set.add, resolvees)) + distributions.update(dict.fromkeys(resolvees)) + + # success, no need to try any more versions of this project + break + + distributions = list(distributions) + distributions.sort() + + return distributions, error_info + + def require(self, *requirements): + """Ensure that distributions matching `requirements` are activated + + `requirements` must be a string or a (possibly-nested) sequence + thereof, specifying the distributions and versions required. The + return value is a sequence of the distributions that needed to be + activated to fulfill the requirements; all relevant distributions are + included, even if they were already activated in this working set. + """ + needed = self.resolve(parse_requirements(requirements)) + + for dist in needed: + self.add(dist) + + return needed + + def subscribe(self, callback, existing=True): + """Invoke `callback` for all distributions + + If `existing=True` (default), + call on all existing ones, as well. + """ + if callback in self.callbacks: + return + self.callbacks.append(callback) + if not existing: + return + for dist in self: + callback(dist) + + def _added_new(self, dist): + for callback in self.callbacks: + callback(dist) + + def __getstate__(self): + return ( + self.entries[:], self.entry_keys.copy(), self.by_key.copy(), + self.callbacks[:] + ) + + def __setstate__(self, e_k_b_c): + entries, keys, by_key, callbacks = e_k_b_c + self.entries = entries[:] + self.entry_keys = keys.copy() + self.by_key = by_key.copy() + self.callbacks = callbacks[:] + + +class _ReqExtras(dict): + """ + Map each requirement to the extras that demanded it. + """ + + def markers_pass(self, req, extras=None): + """ + Evaluate markers for req against each extra that + demanded it. + + Return False if the req has a marker and fails + evaluation. Otherwise, return True. + """ + extra_evals = ( + req.marker.evaluate({'extra': extra}) + for extra in self.get(req, ()) + (extras or (None,)) + ) + return not req.marker or any(extra_evals) + + +class Environment: + """Searchable snapshot of distributions on a search path""" + + def __init__( + self, search_path=None, platform=get_supported_platform(), + python=PY_MAJOR): + """Snapshot distributions available on a search path + + Any distributions found on `search_path` are added to the environment. + `search_path` should be a sequence of ``sys.path`` items. If not + supplied, ``sys.path`` is used. + + `platform` is an optional string specifying the name of the platform + that platform-specific distributions must be compatible with. If + unspecified, it defaults to the current platform. `python` is an + optional string naming the desired version of Python (e.g. ``'3.6'``); + it defaults to the current version. + + You may explicitly set `platform` (and/or `python`) to ``None`` if you + wish to map *all* distributions, not just those compatible with the + running platform or Python version. + """ + self._distmap = {} + self.platform = platform + self.python = python + self.scan(search_path) + + def can_add(self, dist): + """Is distribution `dist` acceptable for this environment? + + The distribution must match the platform and python version + requirements specified when this environment was created, or False + is returned. + """ + py_compat = ( + self.python is None + or dist.py_version is None + or dist.py_version == self.python + ) + return py_compat and compatible_platforms(dist.platform, self.platform) + + def remove(self, dist): + """Remove `dist` from the environment""" + self._distmap[dist.key].remove(dist) + + def scan(self, search_path=None): + """Scan `search_path` for distributions usable in this environment + + Any distributions found are added to the environment. + `search_path` should be a sequence of ``sys.path`` items. If not + supplied, ``sys.path`` is used. Only distributions conforming to + the platform/python version defined at initialization are added. + """ + if search_path is None: + search_path = sys.path + + for item in search_path: + for dist in find_distributions(item): + self.add(dist) + + def __getitem__(self, project_name): + """Return a newest-to-oldest list of distributions for `project_name` + + Uses case-insensitive `project_name` comparison, assuming all the + project's distributions use their project's name converted to all + lowercase as their key. + + """ + distribution_key = project_name.lower() + return self._distmap.get(distribution_key, []) + + def add(self, dist): + """Add `dist` if we ``can_add()`` it and it has not already been added + """ + if self.can_add(dist) and dist.has_version(): + dists = self._distmap.setdefault(dist.key, []) + if dist not in dists: + dists.append(dist) + dists.sort(key=operator.attrgetter('hashcmp'), reverse=True) + + def best_match( + self, req, working_set, installer=None, replace_conflicting=False): + """Find distribution best matching `req` and usable on `working_set` + + This calls the ``find(req)`` method of the `working_set` to see if a + suitable distribution is already active. (This may raise + ``VersionConflict`` if an unsuitable version of the project is already + active in the specified `working_set`.) If a suitable distribution + isn't active, this method returns the newest distribution in the + environment that meets the ``Requirement`` in `req`. If no suitable + distribution is found, and `installer` is supplied, then the result of + calling the environment's ``obtain(req, installer)`` method will be + returned. + """ + try: + dist = working_set.find(req) + except VersionConflict: + if not replace_conflicting: + raise + dist = None + if dist is not None: + return dist + for dist in self[req.key]: + if dist in req: + return dist + # try to download/install + return self.obtain(req, installer) + + def obtain(self, requirement, installer=None): + """Obtain a distribution matching `requirement` (e.g. via download) + + Obtain a distro that matches requirement (e.g. via download). In the + base ``Environment`` class, this routine just returns + ``installer(requirement)``, unless `installer` is None, in which case + None is returned instead. This method is a hook that allows subclasses + to attempt other ways of obtaining a distribution before falling back + to the `installer` argument.""" + if installer is not None: + return installer(requirement) + + def __iter__(self): + """Yield the unique project names of the available distributions""" + for key in self._distmap.keys(): + if self[key]: + yield key + + def __iadd__(self, other): + """In-place addition of a distribution or environment""" + if isinstance(other, Distribution): + self.add(other) + elif isinstance(other, Environment): + for project in other: + for dist in other[project]: + self.add(dist) + else: + raise TypeError("Can't add %r to environment" % (other,)) + return self + + def __add__(self, other): + """Add an environment or distribution to an environment""" + new = self.__class__([], platform=None, python=None) + for env in self, other: + new += env + return new + + +# XXX backward compatibility +AvailableDistributions = Environment + + +class ExtractionError(RuntimeError): + """An error occurred extracting a resource + + The following attributes are available from instances of this exception: + + manager + The resource manager that raised this exception + + cache_path + The base directory for resource extraction + + original_error + The exception instance that caused extraction to fail + """ + + +class ResourceManager: + """Manage resource extraction and packages""" + extraction_path = None + + def __init__(self): + self.cached_files = {} + + def resource_exists(self, package_or_requirement, resource_name): + """Does the named resource exist?""" + return get_provider(package_or_requirement).has_resource(resource_name) + + def resource_isdir(self, package_or_requirement, resource_name): + """Is the named resource an existing directory?""" + return get_provider(package_or_requirement).resource_isdir( + resource_name + ) + + def resource_filename(self, package_or_requirement, resource_name): + """Return a true filesystem path for specified resource""" + return get_provider(package_or_requirement).get_resource_filename( + self, resource_name + ) + + def resource_stream(self, package_or_requirement, resource_name): + """Return a readable file-like object for specified resource""" + return get_provider(package_or_requirement).get_resource_stream( + self, resource_name + ) + + def resource_string(self, package_or_requirement, resource_name): + """Return specified resource as a string""" + return get_provider(package_or_requirement).get_resource_string( + self, resource_name + ) + + def resource_listdir(self, package_or_requirement, resource_name): + """List the contents of the named resource directory""" + return get_provider(package_or_requirement).resource_listdir( + resource_name + ) + + def extraction_error(self): + """Give an error message for problems extracting file(s)""" + + old_exc = sys.exc_info()[1] + cache_path = self.extraction_path or get_default_cache() + + tmpl = textwrap.dedent(""" + Can't extract file(s) to egg cache + + The following error occurred while trying to extract file(s) + to the Python egg cache: + + {old_exc} + + The Python egg cache directory is currently set to: + + {cache_path} + + Perhaps your account does not have write access to this directory? + You can change the cache directory by setting the PYTHON_EGG_CACHE + environment variable to point to an accessible directory. + """).lstrip() + err = ExtractionError(tmpl.format(**locals())) + err.manager = self + err.cache_path = cache_path + err.original_error = old_exc + raise err + + def get_cache_path(self, archive_name, names=()): + """Return absolute location in cache for `archive_name` and `names` + + The parent directory of the resulting path will be created if it does + not already exist. `archive_name` should be the base filename of the + enclosing egg (which may not be the name of the enclosing zipfile!), + including its ".egg" extension. `names`, if provided, should be a + sequence of path name parts "under" the egg's extraction location. + + This method should only be called by resource providers that need to + obtain an extraction location, and only for names they intend to + extract, as it tracks the generated names for possible cleanup later. + """ + extract_path = self.extraction_path or get_default_cache() + target_path = os.path.join(extract_path, archive_name + '-tmp', *names) + try: + _bypass_ensure_directory(target_path) + except Exception: + self.extraction_error() + + self._warn_unsafe_extraction_path(extract_path) + + self.cached_files[target_path] = 1 + return target_path + + @staticmethod + def _warn_unsafe_extraction_path(path): + """ + If the default extraction path is overridden and set to an insecure + location, such as /tmp, it opens up an opportunity for an attacker to + replace an extracted file with an unauthorized payload. Warn the user + if a known insecure location is used. + + See Distribute #375 for more details. + """ + if os.name == 'nt' and not path.startswith(os.environ['windir']): + # On Windows, permissions are generally restrictive by default + # and temp directories are not writable by other users, so + # bypass the warning. + return + mode = os.stat(path).st_mode + if mode & stat.S_IWOTH or mode & stat.S_IWGRP: + msg = ( + "%s is writable by group/others and vulnerable to attack " + "when " + "used with get_resource_filename. Consider a more secure " + "location (set with .set_extraction_path or the " + "PYTHON_EGG_CACHE environment variable)." % path + ) + warnings.warn(msg, UserWarning) + + def postprocess(self, tempname, filename): + """Perform any platform-specific postprocessing of `tempname` + + This is where Mac header rewrites should be done; other platforms don't + have anything special they should do. + + Resource providers should call this method ONLY after successfully + extracting a compressed resource. They must NOT call it on resources + that are already in the filesystem. + + `tempname` is the current (temporary) name of the file, and `filename` + is the name it will be renamed to by the caller after this routine + returns. + """ + + if os.name == 'posix': + # Make the resource executable + mode = ((os.stat(tempname).st_mode) | 0o555) & 0o7777 + os.chmod(tempname, mode) + + def set_extraction_path(self, path): + """Set the base path where resources will be extracted to, if needed. + + If you do not call this routine before any extractions take place, the + path defaults to the return value of ``get_default_cache()``. (Which + is based on the ``PYTHON_EGG_CACHE`` environment variable, with various + platform-specific fallbacks. See that routine's documentation for more + details.) + + Resources are extracted to subdirectories of this path based upon + information given by the ``IResourceProvider``. You may set this to a + temporary directory, but then you must call ``cleanup_resources()`` to + delete the extracted files when done. There is no guarantee that + ``cleanup_resources()`` will be able to remove all extracted files. + + (Note: you may not change the extraction path for a given resource + manager once resources have been extracted, unless you first call + ``cleanup_resources()``.) + """ + if self.cached_files: + raise ValueError( + "Can't change extraction path, files already extracted" + ) + + self.extraction_path = path + + def cleanup_resources(self, force=False): + """ + Delete all extracted resource files and directories, returning a list + of the file and directory names that could not be successfully removed. + This function does not have any concurrency protection, so it should + generally only be called when the extraction path is a temporary + directory exclusive to a single process. This method is not + automatically called; you must call it explicitly or register it as an + ``atexit`` function if you wish to ensure cleanup of a temporary + directory used for extractions. + """ + # XXX + + +def get_default_cache(): + """ + Return the ``PYTHON_EGG_CACHE`` environment variable + or a platform-relevant user cache dir for an app + named "Python-Eggs". + """ + return ( + os.environ.get('PYTHON_EGG_CACHE') + or appdirs.user_cache_dir(appname='Python-Eggs') + ) + + +def safe_name(name): + """Convert an arbitrary string to a standard distribution name + + Any runs of non-alphanumeric/. characters are replaced with a single '-'. + """ + return re.sub('[^A-Za-z0-9.]+', '-', name) + + +def safe_version(version): + """ + Convert an arbitrary string to a standard version string + """ + try: + # normalize the version + return str(packaging.version.Version(version)) + except packaging.version.InvalidVersion: + version = version.replace(' ', '.') + return re.sub('[^A-Za-z0-9.]+', '-', version) + + +def safe_extra(extra): + """Convert an arbitrary string to a standard 'extra' name + + Any runs of non-alphanumeric characters are replaced with a single '_', + and the result is always lowercased. + """ + return re.sub('[^A-Za-z0-9.-]+', '_', extra).lower() + + +def to_filename(name): + """Convert a project or version name to its filename-escaped form + + Any '-' characters are currently replaced with '_'. + """ + return name.replace('-', '_') + + +def invalid_marker(text): + """ + Validate text as a PEP 508 environment marker; return an exception + if invalid or False otherwise. + """ + try: + evaluate_marker(text) + except SyntaxError as e: + e.filename = None + e.lineno = None + return e + return False + + +def evaluate_marker(text, extra=None): + """ + Evaluate a PEP 508 environment marker. + Return a boolean indicating the marker result in this environment. + Raise SyntaxError if marker is invalid. + + This implementation uses the 'pyparsing' module. + """ + try: + marker = packaging.markers.Marker(text) + return marker.evaluate() + except packaging.markers.InvalidMarker as e: + raise SyntaxError(e) + + +class NullProvider: + """Try to implement resources and metadata for arbitrary PEP 302 loaders""" + + egg_name = None + egg_info = None + loader = None + + def __init__(self, module): + self.loader = getattr(module, '__loader__', None) + self.module_path = os.path.dirname(getattr(module, '__file__', '')) + + def get_resource_filename(self, manager, resource_name): + return self._fn(self.module_path, resource_name) + + def get_resource_stream(self, manager, resource_name): + return io.BytesIO(self.get_resource_string(manager, resource_name)) + + def get_resource_string(self, manager, resource_name): + return self._get(self._fn(self.module_path, resource_name)) + + def has_resource(self, resource_name): + return self._has(self._fn(self.module_path, resource_name)) + + def _get_metadata_path(self, name): + return self._fn(self.egg_info, name) + + def has_metadata(self, name): + if not self.egg_info: + return self.egg_info + + path = self._get_metadata_path(name) + return self._has(path) + + def get_metadata(self, name): + if not self.egg_info: + return "" + path = self._get_metadata_path(name) + value = self._get(path) + if six.PY2: + return value + try: + return value.decode('utf-8') + except UnicodeDecodeError as exc: + # Include the path in the error message to simplify + # troubleshooting, and without changing the exception type. + exc.reason += ' in {} file at path: {}'.format(name, path) + raise + + def get_metadata_lines(self, name): + return yield_lines(self.get_metadata(name)) + + def resource_isdir(self, resource_name): + return self._isdir(self._fn(self.module_path, resource_name)) + + def metadata_isdir(self, name): + return self.egg_info and self._isdir(self._fn(self.egg_info, name)) + + def resource_listdir(self, resource_name): + return self._listdir(self._fn(self.module_path, resource_name)) + + def metadata_listdir(self, name): + if self.egg_info: + return self._listdir(self._fn(self.egg_info, name)) + return [] + + def run_script(self, script_name, namespace): + script = 'scripts/' + script_name + if not self.has_metadata(script): + raise ResolutionError( + "Script {script!r} not found in metadata at {self.egg_info!r}" + .format(**locals()), + ) + script_text = self.get_metadata(script).replace('\r\n', '\n') + script_text = script_text.replace('\r', '\n') + script_filename = self._fn(self.egg_info, script) + namespace['__file__'] = script_filename + if os.path.exists(script_filename): + source = open(script_filename).read() + code = compile(source, script_filename, 'exec') + exec(code, namespace, namespace) + else: + from linecache import cache + cache[script_filename] = ( + len(script_text), 0, script_text.split('\n'), script_filename + ) + script_code = compile(script_text, script_filename, 'exec') + exec(script_code, namespace, namespace) + + def _has(self, path): + raise NotImplementedError( + "Can't perform this operation for unregistered loader type" + ) + + def _isdir(self, path): + raise NotImplementedError( + "Can't perform this operation for unregistered loader type" + ) + + def _listdir(self, path): + raise NotImplementedError( + "Can't perform this operation for unregistered loader type" + ) + + def _fn(self, base, resource_name): + self._validate_resource_path(resource_name) + if resource_name: + return os.path.join(base, *resource_name.split('/')) + return base + + @staticmethod + def _validate_resource_path(path): + """ + Validate the resource paths according to the docs. + https://setuptools.readthedocs.io/en/latest/pkg_resources.html#basic-resource-access + + >>> warned = getfixture('recwarn') + >>> warnings.simplefilter('always') + >>> vrp = NullProvider._validate_resource_path + >>> vrp('foo/bar.txt') + >>> bool(warned) + False + >>> vrp('../foo/bar.txt') + >>> bool(warned) + True + >>> warned.clear() + >>> vrp('/foo/bar.txt') + >>> bool(warned) + True + >>> vrp('foo/../../bar.txt') + >>> bool(warned) + True + >>> warned.clear() + >>> vrp('foo/f../bar.txt') + >>> bool(warned) + False + + Windows path separators are straight-up disallowed. + >>> vrp(r'\\foo/bar.txt') + Traceback (most recent call last): + ... + ValueError: Use of .. or absolute path in a resource path \ +is not allowed. + + >>> vrp(r'C:\\foo/bar.txt') + Traceback (most recent call last): + ... + ValueError: Use of .. or absolute path in a resource path \ +is not allowed. + + Blank values are allowed + + >>> vrp('') + >>> bool(warned) + False + + Non-string values are not. + + >>> vrp(None) + Traceback (most recent call last): + ... + AttributeError: ... + """ + invalid = ( + os.path.pardir in path.split(posixpath.sep) or + posixpath.isabs(path) or + ntpath.isabs(path) + ) + if not invalid: + return + + msg = "Use of .. or absolute path in a resource path is not allowed." + + # Aggressively disallow Windows absolute paths + if ntpath.isabs(path) and not posixpath.isabs(path): + raise ValueError(msg) + + # for compatibility, warn; in future + # raise ValueError(msg) + warnings.warn( + msg[:-1] + " and will raise exceptions in a future release.", + DeprecationWarning, + stacklevel=4, + ) + + def _get(self, path): + if hasattr(self.loader, 'get_data'): + return self.loader.get_data(path) + raise NotImplementedError( + "Can't perform this operation for loaders without 'get_data()'" + ) + + +register_loader_type(object, NullProvider) + + +class EggProvider(NullProvider): + """Provider based on a virtual filesystem""" + + def __init__(self, module): + NullProvider.__init__(self, module) + self._setup_prefix() + + def _setup_prefix(self): + # we assume here that our metadata may be nested inside a "basket" + # of multiple eggs; that's why we use module_path instead of .archive + path = self.module_path + old = None + while path != old: + if _is_egg_path(path): + self.egg_name = os.path.basename(path) + self.egg_info = os.path.join(path, 'EGG-INFO') + self.egg_root = path + break + old = path + path, base = os.path.split(path) + + +class DefaultProvider(EggProvider): + """Provides access to package resources in the filesystem""" + + def _has(self, path): + return os.path.exists(path) + + def _isdir(self, path): + return os.path.isdir(path) + + def _listdir(self, path): + return os.listdir(path) + + def get_resource_stream(self, manager, resource_name): + return open(self._fn(self.module_path, resource_name), 'rb') + + def _get(self, path): + with open(path, 'rb') as stream: + return stream.read() + + @classmethod + def _register(cls): + loader_names = 'SourceFileLoader', 'SourcelessFileLoader', + for name in loader_names: + loader_cls = getattr(importlib_machinery, name, type(None)) + register_loader_type(loader_cls, cls) + + +DefaultProvider._register() + + +class EmptyProvider(NullProvider): + """Provider that returns nothing for all requests""" + + module_path = None + + _isdir = _has = lambda self, path: False + + def _get(self, path): + return '' + + def _listdir(self, path): + return [] + + def __init__(self): + pass + + +empty_provider = EmptyProvider() + + +class ZipManifests(dict): + """ + zip manifest builder + """ + + @classmethod + def build(cls, path): + """ + Build a dictionary similar to the zipimport directory + caches, except instead of tuples, store ZipInfo objects. + + Use a platform-specific path separator (os.sep) for the path keys + for compatibility with pypy on Windows. + """ + with zipfile.ZipFile(path) as zfile: + items = ( + ( + name.replace('/', os.sep), + zfile.getinfo(name), + ) + for name in zfile.namelist() + ) + return dict(items) + + load = build + + +class MemoizedZipManifests(ZipManifests): + """ + Memoized zipfile manifests. + """ + manifest_mod = collections.namedtuple('manifest_mod', 'manifest mtime') + + def load(self, path): + """ + Load a manifest at path or return a suitable manifest already loaded. + """ + path = os.path.normpath(path) + mtime = os.stat(path).st_mtime + + if path not in self or self[path].mtime != mtime: + manifest = self.build(path) + self[path] = self.manifest_mod(manifest, mtime) + + return self[path].manifest + + +class ZipProvider(EggProvider): + """Resource support for zips and eggs""" + + eagers = None + _zip_manifests = MemoizedZipManifests() + + def __init__(self, module): + EggProvider.__init__(self, module) + self.zip_pre = self.loader.archive + os.sep + + def _zipinfo_name(self, fspath): + # Convert a virtual filename (full path to file) into a zipfile subpath + # usable with the zipimport directory cache for our target archive + fspath = fspath.rstrip(os.sep) + if fspath == self.loader.archive: + return '' + if fspath.startswith(self.zip_pre): + return fspath[len(self.zip_pre):] + raise AssertionError( + "%s is not a subpath of %s" % (fspath, self.zip_pre) + ) + + def _parts(self, zip_path): + # Convert a zipfile subpath into an egg-relative path part list. + # pseudo-fs path + fspath = self.zip_pre + zip_path + if fspath.startswith(self.egg_root + os.sep): + return fspath[len(self.egg_root) + 1:].split(os.sep) + raise AssertionError( + "%s is not a subpath of %s" % (fspath, self.egg_root) + ) + + @property + def zipinfo(self): + return self._zip_manifests.load(self.loader.archive) + + def get_resource_filename(self, manager, resource_name): + if not self.egg_name: + raise NotImplementedError( + "resource_filename() only supported for .egg, not .zip" + ) + # no need to lock for extraction, since we use temp names + zip_path = self._resource_to_zip(resource_name) + eagers = self._get_eager_resources() + if '/'.join(self._parts(zip_path)) in eagers: + for name in eagers: + self._extract_resource(manager, self._eager_to_zip(name)) + return self._extract_resource(manager, zip_path) + + @staticmethod + def _get_date_and_size(zip_stat): + size = zip_stat.file_size + # ymdhms+wday, yday, dst + date_time = zip_stat.date_time + (0, 0, -1) + # 1980 offset already done + timestamp = time.mktime(date_time) + return timestamp, size + + def _extract_resource(self, manager, zip_path): + + if zip_path in self._index(): + for name in self._index()[zip_path]: + last = self._extract_resource( + manager, os.path.join(zip_path, name) + ) + # return the extracted directory name + return os.path.dirname(last) + + timestamp, size = self._get_date_and_size(self.zipinfo[zip_path]) + + if not WRITE_SUPPORT: + raise IOError('"os.rename" and "os.unlink" are not supported ' + 'on this platform') + try: + + real_path = manager.get_cache_path( + self.egg_name, self._parts(zip_path) + ) + + if self._is_current(real_path, zip_path): + return real_path + + outf, tmpnam = _mkstemp( + ".$extract", + dir=os.path.dirname(real_path), + ) + os.write(outf, self.loader.get_data(zip_path)) + os.close(outf) + utime(tmpnam, (timestamp, timestamp)) + manager.postprocess(tmpnam, real_path) + + try: + rename(tmpnam, real_path) + + except os.error: + if os.path.isfile(real_path): + if self._is_current(real_path, zip_path): + # the file became current since it was checked above, + # so proceed. + return real_path + # Windows, del old file and retry + elif os.name == 'nt': + unlink(real_path) + rename(tmpnam, real_path) + return real_path + raise + + except os.error: + # report a user-friendly error + manager.extraction_error() + + return real_path + + def _is_current(self, file_path, zip_path): + """ + Return True if the file_path is current for this zip_path + """ + timestamp, size = self._get_date_and_size(self.zipinfo[zip_path]) + if not os.path.isfile(file_path): + return False + stat = os.stat(file_path) + if stat.st_size != size or stat.st_mtime != timestamp: + return False + # check that the contents match + zip_contents = self.loader.get_data(zip_path) + with open(file_path, 'rb') as f: + file_contents = f.read() + return zip_contents == file_contents + + def _get_eager_resources(self): + if self.eagers is None: + eagers = [] + for name in ('native_libs.txt', 'eager_resources.txt'): + if self.has_metadata(name): + eagers.extend(self.get_metadata_lines(name)) + self.eagers = eagers + return self.eagers + + def _index(self): + try: + return self._dirindex + except AttributeError: + ind = {} + for path in self.zipinfo: + parts = path.split(os.sep) + while parts: + parent = os.sep.join(parts[:-1]) + if parent in ind: + ind[parent].append(parts[-1]) + break + else: + ind[parent] = [parts.pop()] + self._dirindex = ind + return ind + + def _has(self, fspath): + zip_path = self._zipinfo_name(fspath) + return zip_path in self.zipinfo or zip_path in self._index() + + def _isdir(self, fspath): + return self._zipinfo_name(fspath) in self._index() + + def _listdir(self, fspath): + return list(self._index().get(self._zipinfo_name(fspath), ())) + + def _eager_to_zip(self, resource_name): + return self._zipinfo_name(self._fn(self.egg_root, resource_name)) + + def _resource_to_zip(self, resource_name): + return self._zipinfo_name(self._fn(self.module_path, resource_name)) + + +register_loader_type(zipimport.zipimporter, ZipProvider) + + +class FileMetadata(EmptyProvider): + """Metadata handler for standalone PKG-INFO files + + Usage:: + + metadata = FileMetadata("/path/to/PKG-INFO") + + This provider rejects all data and metadata requests except for PKG-INFO, + which is treated as existing, and will be the contents of the file at + the provided location. + """ + + def __init__(self, path): + self.path = path + + def _get_metadata_path(self, name): + return self.path + + def has_metadata(self, name): + return name == 'PKG-INFO' and os.path.isfile(self.path) + + def get_metadata(self, name): + if name != 'PKG-INFO': + raise KeyError("No metadata except PKG-INFO is available") + + with io.open(self.path, encoding='utf-8', errors="replace") as f: + metadata = f.read() + self._warn_on_replacement(metadata) + return metadata + + def _warn_on_replacement(self, metadata): + # Python 2.7 compat for: replacement_char = '�' + replacement_char = b'\xef\xbf\xbd'.decode('utf-8') + if replacement_char in metadata: + tmpl = "{self.path} could not be properly decoded in UTF-8" + msg = tmpl.format(**locals()) + warnings.warn(msg) + + def get_metadata_lines(self, name): + return yield_lines(self.get_metadata(name)) + + +class PathMetadata(DefaultProvider): + """Metadata provider for egg directories + + Usage:: + + # Development eggs: + + egg_info = "/path/to/PackageName.egg-info" + base_dir = os.path.dirname(egg_info) + metadata = PathMetadata(base_dir, egg_info) + dist_name = os.path.splitext(os.path.basename(egg_info))[0] + dist = Distribution(basedir, project_name=dist_name, metadata=metadata) + + # Unpacked egg directories: + + egg_path = "/path/to/PackageName-ver-pyver-etc.egg" + metadata = PathMetadata(egg_path, os.path.join(egg_path,'EGG-INFO')) + dist = Distribution.from_filename(egg_path, metadata=metadata) + """ + + def __init__(self, path, egg_info): + self.module_path = path + self.egg_info = egg_info + + +class EggMetadata(ZipProvider): + """Metadata provider for .egg files""" + + def __init__(self, importer): + """Create a metadata provider from a zipimporter""" + + self.zip_pre = importer.archive + os.sep + self.loader = importer + if importer.prefix: + self.module_path = os.path.join(importer.archive, importer.prefix) + else: + self.module_path = importer.archive + self._setup_prefix() + + +_declare_state('dict', _distribution_finders={}) + + +def register_finder(importer_type, distribution_finder): + """Register `distribution_finder` to find distributions in sys.path items + + `importer_type` is the type or class of a PEP 302 "Importer" (sys.path item + handler), and `distribution_finder` is a callable that, passed a path + item and the importer instance, yields ``Distribution`` instances found on + that path item. See ``pkg_resources.find_on_path`` for an example.""" + _distribution_finders[importer_type] = distribution_finder + + +def find_distributions(path_item, only=False): + """Yield distributions accessible via `path_item`""" + importer = get_importer(path_item) + finder = _find_adapter(_distribution_finders, importer) + return finder(importer, path_item, only) + + +def find_eggs_in_zip(importer, path_item, only=False): + """ + Find eggs in zip files; possibly multiple nested eggs. + """ + if importer.archive.endswith('.whl'): + # wheels are not supported with this finder + # they don't have PKG-INFO metadata, and won't ever contain eggs + return + metadata = EggMetadata(importer) + if metadata.has_metadata('PKG-INFO'): + yield Distribution.from_filename(path_item, metadata=metadata) + if only: + # don't yield nested distros + return + for subitem in metadata.resource_listdir(''): + if _is_egg_path(subitem): + subpath = os.path.join(path_item, subitem) + dists = find_eggs_in_zip(zipimport.zipimporter(subpath), subpath) + for dist in dists: + yield dist + elif subitem.lower().endswith('.dist-info'): + subpath = os.path.join(path_item, subitem) + submeta = EggMetadata(zipimport.zipimporter(subpath)) + submeta.egg_info = subpath + yield Distribution.from_location(path_item, subitem, submeta) + + +register_finder(zipimport.zipimporter, find_eggs_in_zip) + + +def find_nothing(importer, path_item, only=False): + return () + + +register_finder(object, find_nothing) + + +def _by_version_descending(names): + """ + Given a list of filenames, return them in descending order + by version number. + + >>> names = 'bar', 'foo', 'Python-2.7.10.egg', 'Python-2.7.2.egg' + >>> _by_version_descending(names) + ['Python-2.7.10.egg', 'Python-2.7.2.egg', 'foo', 'bar'] + >>> names = 'Setuptools-1.2.3b1.egg', 'Setuptools-1.2.3.egg' + >>> _by_version_descending(names) + ['Setuptools-1.2.3.egg', 'Setuptools-1.2.3b1.egg'] + >>> names = 'Setuptools-1.2.3b1.egg', 'Setuptools-1.2.3.post1.egg' + >>> _by_version_descending(names) + ['Setuptools-1.2.3.post1.egg', 'Setuptools-1.2.3b1.egg'] + """ + def _by_version(name): + """ + Parse each component of the filename + """ + name, ext = os.path.splitext(name) + parts = itertools.chain(name.split('-'), [ext]) + return [packaging.version.parse(part) for part in parts] + + return sorted(names, key=_by_version, reverse=True) + + +def find_on_path(importer, path_item, only=False): + """Yield distributions accessible on a sys.path directory""" + path_item = _normalize_cached(path_item) + + if _is_unpacked_egg(path_item): + yield Distribution.from_filename( + path_item, metadata=PathMetadata( + path_item, os.path.join(path_item, 'EGG-INFO') + ) + ) + return + + entries = safe_listdir(path_item) + + # for performance, before sorting by version, + # screen entries for only those that will yield + # distributions + filtered = ( + entry + for entry in entries + if dist_factory(path_item, entry, only) + ) + + # scan for .egg and .egg-info in directory + path_item_entries = _by_version_descending(filtered) + for entry in path_item_entries: + fullpath = os.path.join(path_item, entry) + factory = dist_factory(path_item, entry, only) + for dist in factory(fullpath): + yield dist + + +def dist_factory(path_item, entry, only): + """ + Return a dist_factory for a path_item and entry + """ + lower = entry.lower() + is_meta = any(map(lower.endswith, ('.egg-info', '.dist-info'))) + return ( + distributions_from_metadata + if is_meta else + find_distributions + if not only and _is_egg_path(entry) else + resolve_egg_link + if not only and lower.endswith('.egg-link') else + NoDists() + ) + + +class NoDists: + """ + >>> bool(NoDists()) + False + + >>> list(NoDists()('anything')) + [] + """ + def __bool__(self): + return False + if six.PY2: + __nonzero__ = __bool__ + + def __call__(self, fullpath): + return iter(()) + + +def safe_listdir(path): + """ + Attempt to list contents of path, but suppress some exceptions. + """ + try: + return os.listdir(path) + except (PermissionError, NotADirectoryError): + pass + except OSError as e: + # Ignore the directory if does not exist, not a directory or + # permission denied + ignorable = ( + e.errno in (errno.ENOTDIR, errno.EACCES, errno.ENOENT) + # Python 2 on Windows needs to be handled this way :( + or getattr(e, "winerror", None) == 267 + ) + if not ignorable: + raise + return () + + +def distributions_from_metadata(path): + root = os.path.dirname(path) + if os.path.isdir(path): + if len(os.listdir(path)) == 0: + # empty metadata dir; skip + return + metadata = PathMetadata(root, path) + else: + metadata = FileMetadata(path) + entry = os.path.basename(path) + yield Distribution.from_location( + root, entry, metadata, precedence=DEVELOP_DIST, + ) + + +def non_empty_lines(path): + """ + Yield non-empty lines from file at path + """ + with open(path) as f: + for line in f: + line = line.strip() + if line: + yield line + + +def resolve_egg_link(path): + """ + Given a path to an .egg-link, resolve distributions + present in the referenced path. + """ + referenced_paths = non_empty_lines(path) + resolved_paths = ( + os.path.join(os.path.dirname(path), ref) + for ref in referenced_paths + ) + dist_groups = map(find_distributions, resolved_paths) + return next(dist_groups, ()) + + +register_finder(pkgutil.ImpImporter, find_on_path) + +if hasattr(importlib_machinery, 'FileFinder'): + register_finder(importlib_machinery.FileFinder, find_on_path) + +_declare_state('dict', _namespace_handlers={}) +_declare_state('dict', _namespace_packages={}) + + +def register_namespace_handler(importer_type, namespace_handler): + """Register `namespace_handler` to declare namespace packages + + `importer_type` is the type or class of a PEP 302 "Importer" (sys.path item + handler), and `namespace_handler` is a callable like this:: + + def namespace_handler(importer, path_entry, moduleName, module): + # return a path_entry to use for child packages + + Namespace handlers are only called if the importer object has already + agreed that it can handle the relevant path item, and they should only + return a subpath if the module __path__ does not already contain an + equivalent subpath. For an example namespace handler, see + ``pkg_resources.file_ns_handler``. + """ + _namespace_handlers[importer_type] = namespace_handler + + +def _handle_ns(packageName, path_item): + """Ensure that named package includes a subpath of path_item (if needed)""" + + importer = get_importer(path_item) + if importer is None: + return None + + # capture warnings due to #1111 + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + loader = importer.find_module(packageName) + + if loader is None: + return None + module = sys.modules.get(packageName) + if module is None: + module = sys.modules[packageName] = types.ModuleType(packageName) + module.__path__ = [] + _set_parent_ns(packageName) + elif not hasattr(module, '__path__'): + raise TypeError("Not a package:", packageName) + handler = _find_adapter(_namespace_handlers, importer) + subpath = handler(importer, path_item, packageName, module) + if subpath is not None: + path = module.__path__ + path.append(subpath) + loader.load_module(packageName) + _rebuild_mod_path(path, packageName, module) + return subpath + + +def _rebuild_mod_path(orig_path, package_name, module): + """ + Rebuild module.__path__ ensuring that all entries are ordered + corresponding to their sys.path order + """ + sys_path = [_normalize_cached(p) for p in sys.path] + + def safe_sys_path_index(entry): + """ + Workaround for #520 and #513. + """ + try: + return sys_path.index(entry) + except ValueError: + return float('inf') + + def position_in_sys_path(path): + """ + Return the ordinal of the path based on its position in sys.path + """ + path_parts = path.split(os.sep) + module_parts = package_name.count('.') + 1 + parts = path_parts[:-module_parts] + return safe_sys_path_index(_normalize_cached(os.sep.join(parts))) + + new_path = sorted(orig_path, key=position_in_sys_path) + new_path = [_normalize_cached(p) for p in new_path] + + if isinstance(module.__path__, list): + module.__path__[:] = new_path + else: + module.__path__ = new_path + + +def declare_namespace(packageName): + """Declare that package 'packageName' is a namespace package""" + + _imp.acquire_lock() + try: + if packageName in _namespace_packages: + return + + path = sys.path + parent, _, _ = packageName.rpartition('.') + + if parent: + declare_namespace(parent) + if parent not in _namespace_packages: + __import__(parent) + try: + path = sys.modules[parent].__path__ + except AttributeError: + raise TypeError("Not a package:", parent) + + # Track what packages are namespaces, so when new path items are added, + # they can be updated + _namespace_packages.setdefault(parent or None, []).append(packageName) + _namespace_packages.setdefault(packageName, []) + + for path_item in path: + # Ensure all the parent's path items are reflected in the child, + # if they apply + _handle_ns(packageName, path_item) + + finally: + _imp.release_lock() + + +def fixup_namespace_packages(path_item, parent=None): + """Ensure that previously-declared namespace packages include path_item""" + _imp.acquire_lock() + try: + for package in _namespace_packages.get(parent, ()): + subpath = _handle_ns(package, path_item) + if subpath: + fixup_namespace_packages(subpath, package) + finally: + _imp.release_lock() + + +def file_ns_handler(importer, path_item, packageName, module): + """Compute an ns-package subpath for a filesystem or zipfile importer""" + + subpath = os.path.join(path_item, packageName.split('.')[-1]) + normalized = _normalize_cached(subpath) + for item in module.__path__: + if _normalize_cached(item) == normalized: + break + else: + # Only return the path if it's not already there + return subpath + + +register_namespace_handler(pkgutil.ImpImporter, file_ns_handler) +register_namespace_handler(zipimport.zipimporter, file_ns_handler) + +if hasattr(importlib_machinery, 'FileFinder'): + register_namespace_handler(importlib_machinery.FileFinder, file_ns_handler) + + +def null_ns_handler(importer, path_item, packageName, module): + return None + + +register_namespace_handler(object, null_ns_handler) + + +def normalize_path(filename): + """Normalize a file/dir name for comparison purposes""" + return os.path.normcase(os.path.realpath(os.path.normpath(_cygwin_patch(filename)))) + + +def _cygwin_patch(filename): # pragma: nocover + """ + Contrary to POSIX 2008, on Cygwin, getcwd (3) contains + symlink components. Using + os.path.abspath() works around this limitation. A fix in os.getcwd() + would probably better, in Cygwin even more so, except + that this seems to be by design... + """ + return os.path.abspath(filename) if sys.platform == 'cygwin' else filename + + +def _normalize_cached(filename, _cache={}): + try: + return _cache[filename] + except KeyError: + _cache[filename] = result = normalize_path(filename) + return result + + +def _is_egg_path(path): + """ + Determine if given path appears to be an egg. + """ + return path.lower().endswith('.egg') + + +def _is_unpacked_egg(path): + """ + Determine if given path appears to be an unpacked egg. + """ + return ( + _is_egg_path(path) and + os.path.isfile(os.path.join(path, 'EGG-INFO', 'PKG-INFO')) + ) + + +def _set_parent_ns(packageName): + parts = packageName.split('.') + name = parts.pop() + if parts: + parent = '.'.join(parts) + setattr(sys.modules[parent], name, sys.modules[packageName]) + + +def yield_lines(strs): + """Yield non-empty/non-comment lines of a string or sequence""" + if isinstance(strs, six.string_types): + for s in strs.splitlines(): + s = s.strip() + # skip blank lines/comments + if s and not s.startswith('#'): + yield s + else: + for ss in strs: + for s in yield_lines(ss): + yield s + + +MODULE = re.compile(r"\w+(\.\w+)*$").match +EGG_NAME = re.compile( + r""" + (?P[^-]+) ( + -(?P[^-]+) ( + -py(?P[^-]+) ( + -(?P.+) + )? + )? + )? + """, + re.VERBOSE | re.IGNORECASE, +).match + + +class EntryPoint: + """Object representing an advertised importable object""" + + def __init__(self, name, module_name, attrs=(), extras=(), dist=None): + if not MODULE(module_name): + raise ValueError("Invalid module name", module_name) + self.name = name + self.module_name = module_name + self.attrs = tuple(attrs) + self.extras = tuple(extras) + self.dist = dist + + def __str__(self): + s = "%s = %s" % (self.name, self.module_name) + if self.attrs: + s += ':' + '.'.join(self.attrs) + if self.extras: + s += ' [%s]' % ','.join(self.extras) + return s + + def __repr__(self): + return "EntryPoint.parse(%r)" % str(self) + + def load(self, require=True, *args, **kwargs): + """ + Require packages for this EntryPoint, then resolve it. + """ + if not require or args or kwargs: + warnings.warn( + "Parameters to load are deprecated. Call .resolve and " + ".require separately.", + PkgResourcesDeprecationWarning, + stacklevel=2, + ) + if require: + self.require(*args, **kwargs) + return self.resolve() + + def resolve(self): + """ + Resolve the entry point from its module and attrs. + """ + module = __import__(self.module_name, fromlist=['__name__'], level=0) + try: + return functools.reduce(getattr, self.attrs, module) + except AttributeError as exc: + raise ImportError(str(exc)) + + def require(self, env=None, installer=None): + if self.extras and not self.dist: + raise UnknownExtra("Can't require() without a distribution", self) + + # Get the requirements for this entry point with all its extras and + # then resolve them. We have to pass `extras` along when resolving so + # that the working set knows what extras we want. Otherwise, for + # dist-info distributions, the working set will assume that the + # requirements for that extra are purely optional and skip over them. + reqs = self.dist.requires(self.extras) + items = working_set.resolve(reqs, env, installer, extras=self.extras) + list(map(working_set.add, items)) + + pattern = re.compile( + r'\s*' + r'(?P.+?)\s*' + r'=\s*' + r'(?P[\w.]+)\s*' + r'(:\s*(?P[\w.]+))?\s*' + r'(?P\[.*\])?\s*$' + ) + + @classmethod + def parse(cls, src, dist=None): + """Parse a single entry point from string `src` + + Entry point syntax follows the form:: + + name = some.module:some.attr [extra1, extra2] + + The entry name and module name are required, but the ``:attrs`` and + ``[extras]`` parts are optional + """ + m = cls.pattern.match(src) + if not m: + msg = "EntryPoint must be in 'name=module:attrs [extras]' format" + raise ValueError(msg, src) + res = m.groupdict() + extras = cls._parse_extras(res['extras']) + attrs = res['attr'].split('.') if res['attr'] else () + return cls(res['name'], res['module'], attrs, extras, dist) + + @classmethod + def _parse_extras(cls, extras_spec): + if not extras_spec: + return () + req = Requirement.parse('x' + extras_spec) + if req.specs: + raise ValueError() + return req.extras + + @classmethod + def parse_group(cls, group, lines, dist=None): + """Parse an entry point group""" + if not MODULE(group): + raise ValueError("Invalid group name", group) + this = {} + for line in yield_lines(lines): + ep = cls.parse(line, dist) + if ep.name in this: + raise ValueError("Duplicate entry point", group, ep.name) + this[ep.name] = ep + return this + + @classmethod + def parse_map(cls, data, dist=None): + """Parse a map of entry point groups""" + if isinstance(data, dict): + data = data.items() + else: + data = split_sections(data) + maps = {} + for group, lines in data: + if group is None: + if not lines: + continue + raise ValueError("Entry points must be listed in groups") + group = group.strip() + if group in maps: + raise ValueError("Duplicate group name", group) + maps[group] = cls.parse_group(group, lines, dist) + return maps + + +def _remove_md5_fragment(location): + if not location: + return '' + parsed = urllib.parse.urlparse(location) + if parsed[-1].startswith('md5='): + return urllib.parse.urlunparse(parsed[:-1] + ('',)) + return location + + +def _version_from_file(lines): + """ + Given an iterable of lines from a Metadata file, return + the value of the Version field, if present, or None otherwise. + """ + def is_version_line(line): + return line.lower().startswith('version:') + version_lines = filter(is_version_line, lines) + line = next(iter(version_lines), '') + _, _, value = line.partition(':') + return safe_version(value.strip()) or None + + +class Distribution: + """Wrap an actual or potential sys.path entry w/metadata""" + PKG_INFO = 'PKG-INFO' + + def __init__( + self, location=None, metadata=None, project_name=None, + version=None, py_version=PY_MAJOR, platform=None, + precedence=EGG_DIST): + self.project_name = safe_name(project_name or 'Unknown') + if version is not None: + self._version = safe_version(version) + self.py_version = py_version + self.platform = platform + self.location = location + self.precedence = precedence + self._provider = metadata or empty_provider + + @classmethod + def from_location(cls, location, basename, metadata=None, **kw): + project_name, version, py_version, platform = [None] * 4 + basename, ext = os.path.splitext(basename) + if ext.lower() in _distributionImpl: + cls = _distributionImpl[ext.lower()] + + match = EGG_NAME(basename) + if match: + project_name, version, py_version, platform = match.group( + 'name', 'ver', 'pyver', 'plat' + ) + return cls( + location, metadata, project_name=project_name, version=version, + py_version=py_version, platform=platform, **kw + )._reload_version() + + def _reload_version(self): + return self + + @property + def hashcmp(self): + return ( + self.parsed_version, + self.precedence, + self.key, + _remove_md5_fragment(self.location), + self.py_version or '', + self.platform or '', + ) + + def __hash__(self): + return hash(self.hashcmp) + + def __lt__(self, other): + return self.hashcmp < other.hashcmp + + def __le__(self, other): + return self.hashcmp <= other.hashcmp + + def __gt__(self, other): + return self.hashcmp > other.hashcmp + + def __ge__(self, other): + return self.hashcmp >= other.hashcmp + + def __eq__(self, other): + if not isinstance(other, self.__class__): + # It's not a Distribution, so they are not equal + return False + return self.hashcmp == other.hashcmp + + def __ne__(self, other): + return not self == other + + # These properties have to be lazy so that we don't have to load any + # metadata until/unless it's actually needed. (i.e., some distributions + # may not know their name or version without loading PKG-INFO) + + @property + def key(self): + try: + return self._key + except AttributeError: + self._key = key = self.project_name.lower() + return key + + @property + def parsed_version(self): + if not hasattr(self, "_parsed_version"): + self._parsed_version = parse_version(self.version) + + return self._parsed_version + + def _warn_legacy_version(self): + LV = packaging.version.LegacyVersion + is_legacy = isinstance(self._parsed_version, LV) + if not is_legacy: + return + + # While an empty version is technically a legacy version and + # is not a valid PEP 440 version, it's also unlikely to + # actually come from someone and instead it is more likely that + # it comes from setuptools attempting to parse a filename and + # including it in the list. So for that we'll gate this warning + # on if the version is anything at all or not. + if not self.version: + return + + tmpl = textwrap.dedent(""" + '{project_name} ({version})' is being parsed as a legacy, + non PEP 440, + version. You may find odd behavior and sort order. + In particular it will be sorted as less than 0.0. It + is recommended to migrate to PEP 440 compatible + versions. + """).strip().replace('\n', ' ') + + warnings.warn(tmpl.format(**vars(self)), PEP440Warning) + + @property + def version(self): + try: + return self._version + except AttributeError: + version = self._get_version() + if version is None: + path = self._get_metadata_path_for_display(self.PKG_INFO) + msg = ( + "Missing 'Version:' header and/or {} file at path: {}" + ).format(self.PKG_INFO, path) + raise ValueError(msg, self) + + return version + + @property + def _dep_map(self): + """ + A map of extra to its list of (direct) requirements + for this distribution, including the null extra. + """ + try: + return self.__dep_map + except AttributeError: + self.__dep_map = self._filter_extras(self._build_dep_map()) + return self.__dep_map + + @staticmethod + def _filter_extras(dm): + """ + Given a mapping of extras to dependencies, strip off + environment markers and filter out any dependencies + not matching the markers. + """ + for extra in list(filter(None, dm)): + new_extra = extra + reqs = dm.pop(extra) + new_extra, _, marker = extra.partition(':') + fails_marker = marker and ( + invalid_marker(marker) + or not evaluate_marker(marker) + ) + if fails_marker: + reqs = [] + new_extra = safe_extra(new_extra) or None + + dm.setdefault(new_extra, []).extend(reqs) + return dm + + def _build_dep_map(self): + dm = {} + for name in 'requires.txt', 'depends.txt': + for extra, reqs in split_sections(self._get_metadata(name)): + dm.setdefault(extra, []).extend(parse_requirements(reqs)) + return dm + + def requires(self, extras=()): + """List of Requirements needed for this distro if `extras` are used""" + dm = self._dep_map + deps = [] + deps.extend(dm.get(None, ())) + for ext in extras: + try: + deps.extend(dm[safe_extra(ext)]) + except KeyError: + raise UnknownExtra( + "%s has no such extra feature %r" % (self, ext) + ) + return deps + + def _get_metadata_path_for_display(self, name): + """ + Return the path to the given metadata file, if available. + """ + try: + # We need to access _get_metadata_path() on the provider object + # directly rather than through this class's __getattr__() + # since _get_metadata_path() is marked private. + path = self._provider._get_metadata_path(name) + + # Handle exceptions e.g. in case the distribution's metadata + # provider doesn't support _get_metadata_path(). + except Exception: + return '[could not detect]' + + return path + + def _get_metadata(self, name): + if self.has_metadata(name): + for line in self.get_metadata_lines(name): + yield line + + def _get_version(self): + lines = self._get_metadata(self.PKG_INFO) + version = _version_from_file(lines) + + return version + + def activate(self, path=None, replace=False): + """Ensure distribution is importable on `path` (default=sys.path)""" + if path is None: + path = sys.path + self.insert_on(path, replace=replace) + if path is sys.path: + fixup_namespace_packages(self.location) + for pkg in self._get_metadata('namespace_packages.txt'): + if pkg in sys.modules: + declare_namespace(pkg) + + def egg_name(self): + """Return what this distribution's standard .egg filename should be""" + filename = "%s-%s-py%s" % ( + to_filename(self.project_name), to_filename(self.version), + self.py_version or PY_MAJOR + ) + + if self.platform: + filename += '-' + self.platform + return filename + + def __repr__(self): + if self.location: + return "%s (%s)" % (self, self.location) + else: + return str(self) + + def __str__(self): + try: + version = getattr(self, 'version', None) + except ValueError: + version = None + version = version or "[unknown version]" + return "%s %s" % (self.project_name, version) + + def __getattr__(self, attr): + """Delegate all unrecognized public attributes to .metadata provider""" + if attr.startswith('_'): + raise AttributeError(attr) + return getattr(self._provider, attr) + + def __dir__(self): + return list( + set(super(Distribution, self).__dir__()) + | set( + attr for attr in self._provider.__dir__() + if not attr.startswith('_') + ) + ) + + if not hasattr(object, '__dir__'): + # python 2.7 not supported + del __dir__ + + @classmethod + def from_filename(cls, filename, metadata=None, **kw): + return cls.from_location( + _normalize_cached(filename), os.path.basename(filename), metadata, + **kw + ) + + def as_requirement(self): + """Return a ``Requirement`` that matches this distribution exactly""" + if isinstance(self.parsed_version, packaging.version.Version): + spec = "%s==%s" % (self.project_name, self.parsed_version) + else: + spec = "%s===%s" % (self.project_name, self.parsed_version) + + return Requirement.parse(spec) + + def load_entry_point(self, group, name): + """Return the `name` entry point of `group` or raise ImportError""" + ep = self.get_entry_info(group, name) + if ep is None: + raise ImportError("Entry point %r not found" % ((group, name),)) + return ep.load() + + def get_entry_map(self, group=None): + """Return the entry point map for `group`, or the full entry map""" + try: + ep_map = self._ep_map + except AttributeError: + ep_map = self._ep_map = EntryPoint.parse_map( + self._get_metadata('entry_points.txt'), self + ) + if group is not None: + return ep_map.get(group, {}) + return ep_map + + def get_entry_info(self, group, name): + """Return the EntryPoint object for `group`+`name`, or ``None``""" + return self.get_entry_map(group).get(name) + + def insert_on(self, path, loc=None, replace=False): + """Ensure self.location is on path + + If replace=False (default): + - If location is already in path anywhere, do nothing. + - Else: + - If it's an egg and its parent directory is on path, + insert just ahead of the parent. + - Else: add to the end of path. + If replace=True: + - If location is already on path anywhere (not eggs) + or higher priority than its parent (eggs) + do nothing. + - Else: + - If it's an egg and its parent directory is on path, + insert just ahead of the parent, + removing any lower-priority entries. + - Else: add it to the front of path. + """ + + loc = loc or self.location + if not loc: + return + + nloc = _normalize_cached(loc) + bdir = os.path.dirname(nloc) + npath = [(p and _normalize_cached(p) or p) for p in path] + + for p, item in enumerate(npath): + if item == nloc: + if replace: + break + else: + # don't modify path (even removing duplicates) if + # found and not replace + return + elif item == bdir and self.precedence == EGG_DIST: + # if it's an .egg, give it precedence over its directory + # UNLESS it's already been added to sys.path and replace=False + if (not replace) and nloc in npath[p:]: + return + if path is sys.path: + self.check_version_conflict() + path.insert(p, loc) + npath.insert(p, nloc) + break + else: + if path is sys.path: + self.check_version_conflict() + if replace: + path.insert(0, loc) + else: + path.append(loc) + return + + # p is the spot where we found or inserted loc; now remove duplicates + while True: + try: + np = npath.index(nloc, p + 1) + except ValueError: + break + else: + del npath[np], path[np] + # ha! + p = np + + return + + def check_version_conflict(self): + if self.key == 'setuptools': + # ignore the inevitable setuptools self-conflicts :( + return + + nsp = dict.fromkeys(self._get_metadata('namespace_packages.txt')) + loc = normalize_path(self.location) + for modname in self._get_metadata('top_level.txt'): + if (modname not in sys.modules or modname in nsp + or modname in _namespace_packages): + continue + if modname in ('pkg_resources', 'setuptools', 'site'): + continue + fn = getattr(sys.modules[modname], '__file__', None) + if fn and (normalize_path(fn).startswith(loc) or + fn.startswith(self.location)): + continue + issue_warning( + "Module %s was already imported from %s, but %s is being added" + " to sys.path" % (modname, fn, self.location), + ) + + def has_version(self): + try: + self.version + except ValueError: + issue_warning("Unbuilt egg for " + repr(self)) + return False + return True + + def clone(self, **kw): + """Copy this distribution, substituting in any changed keyword args""" + names = 'project_name version py_version platform location precedence' + for attr in names.split(): + kw.setdefault(attr, getattr(self, attr, None)) + kw.setdefault('metadata', self._provider) + return self.__class__(**kw) + + @property + def extras(self): + return [dep for dep in self._dep_map if dep] + + +class EggInfoDistribution(Distribution): + def _reload_version(self): + """ + Packages installed by distutils (e.g. numpy or scipy), + which uses an old safe_version, and so + their version numbers can get mangled when + converted to filenames (e.g., 1.11.0.dev0+2329eae to + 1.11.0.dev0_2329eae). These distributions will not be + parsed properly + downstream by Distribution and safe_version, so + take an extra step and try to get the version number from + the metadata file itself instead of the filename. + """ + md_version = self._get_version() + if md_version: + self._version = md_version + return self + + +class DistInfoDistribution(Distribution): + """ + Wrap an actual or potential sys.path entry + w/metadata, .dist-info style. + """ + PKG_INFO = 'METADATA' + EQEQ = re.compile(r"([\(,])\s*(\d.*?)\s*([,\)])") + + @property + def _parsed_pkg_info(self): + """Parse and cache metadata""" + try: + return self._pkg_info + except AttributeError: + metadata = self.get_metadata(self.PKG_INFO) + self._pkg_info = email.parser.Parser().parsestr(metadata) + return self._pkg_info + + @property + def _dep_map(self): + try: + return self.__dep_map + except AttributeError: + self.__dep_map = self._compute_dependencies() + return self.__dep_map + + def _compute_dependencies(self): + """Recompute this distribution's dependencies.""" + dm = self.__dep_map = {None: []} + + reqs = [] + # Including any condition expressions + for req in self._parsed_pkg_info.get_all('Requires-Dist') or []: + reqs.extend(parse_requirements(req)) + + def reqs_for_extra(extra): + for req in reqs: + if not req.marker or req.marker.evaluate({'extra': extra}): + yield req + + common = frozenset(reqs_for_extra(None)) + dm[None].extend(common) + + for extra in self._parsed_pkg_info.get_all('Provides-Extra') or []: + s_extra = safe_extra(extra.strip()) + dm[s_extra] = list(frozenset(reqs_for_extra(extra)) - common) + + return dm + + +_distributionImpl = { + '.egg': Distribution, + '.egg-info': EggInfoDistribution, + '.dist-info': DistInfoDistribution, +} + + +def issue_warning(*args, **kw): + level = 1 + g = globals() + try: + # find the first stack frame that is *not* code in + # the pkg_resources module, to use for the warning + while sys._getframe(level).f_globals is g: + level += 1 + except ValueError: + pass + warnings.warn(stacklevel=level + 1, *args, **kw) + + +class RequirementParseError(ValueError): + def __str__(self): + return ' '.join(self.args) + + +def parse_requirements(strs): + """Yield ``Requirement`` objects for each specification in `strs` + + `strs` must be a string, or a (possibly-nested) iterable thereof. + """ + # create a steppable iterator, so we can handle \-continuations + lines = iter(yield_lines(strs)) + + for line in lines: + # Drop comments -- a hash without a space may be in a URL. + if ' #' in line: + line = line[:line.find(' #')] + # If there is a line continuation, drop it, and append the next line. + if line.endswith('\\'): + line = line[:-2].strip() + try: + line += next(lines) + except StopIteration: + return + yield Requirement(line) + + +class Requirement(packaging.requirements.Requirement): + def __init__(self, requirement_string): + """DO NOT CALL THIS UNDOCUMENTED METHOD; use Requirement.parse()!""" + try: + super(Requirement, self).__init__(requirement_string) + except packaging.requirements.InvalidRequirement as e: + raise RequirementParseError(str(e)) + self.unsafe_name = self.name + project_name = safe_name(self.name) + self.project_name, self.key = project_name, project_name.lower() + self.specs = [ + (spec.operator, spec.version) for spec in self.specifier] + self.extras = tuple(map(safe_extra, self.extras)) + self.hashCmp = ( + self.key, + self.url, + self.specifier, + frozenset(self.extras), + str(self.marker) if self.marker else None, + ) + self.__hash = hash(self.hashCmp) + + def __eq__(self, other): + return ( + isinstance(other, Requirement) and + self.hashCmp == other.hashCmp + ) + + def __ne__(self, other): + return not self == other + + def __contains__(self, item): + if isinstance(item, Distribution): + if item.key != self.key: + return False + + item = item.version + + # Allow prereleases always in order to match the previous behavior of + # this method. In the future this should be smarter and follow PEP 440 + # more accurately. + return self.specifier.contains(item, prereleases=True) + + def __hash__(self): + return self.__hash + + def __repr__(self): + return "Requirement.parse(%r)" % str(self) + + @staticmethod + def parse(s): + req, = parse_requirements(s) + return req + + +def _always_object(classes): + """ + Ensure object appears in the mro even + for old-style classes. + """ + if object not in classes: + return classes + (object,) + return classes + + +def _find_adapter(registry, ob): + """Return an adapter factory for `ob` from `registry`""" + types = _always_object(inspect.getmro(getattr(ob, '__class__', type(ob)))) + for t in types: + if t in registry: + return registry[t] + + +def ensure_directory(path): + """Ensure that the parent directory of `path` exists""" + dirname = os.path.dirname(path) + py31compat.makedirs(dirname, exist_ok=True) + + +def _bypass_ensure_directory(path): + """Sandbox-bypassing version of ensure_directory()""" + if not WRITE_SUPPORT: + raise IOError('"os.mkdir" not supported on this platform.') + dirname, filename = split(path) + if dirname and filename and not isdir(dirname): + _bypass_ensure_directory(dirname) + try: + mkdir(dirname, 0o755) + except FileExistsError: + pass + + +def split_sections(s): + """Split a string or iterable thereof into (section, content) pairs + + Each ``section`` is a stripped version of the section header ("[section]") + and each ``content`` is a list of stripped lines excluding blank lines and + comment-only lines. If there are any such lines before the first section + header, they're returned in a first ``section`` of ``None``. + """ + section = None + content = [] + for line in yield_lines(s): + if line.startswith("["): + if line.endswith("]"): + if section or content: + yield section, content + section = line[1:-1].strip() + content = [] + else: + raise ValueError("Invalid section heading", line) + else: + content.append(line) + + # wrap up last segment + yield section, content + + +def _mkstemp(*args, **kw): + old_open = os.open + try: + # temporarily bypass sandboxing + os.open = os_open + return tempfile.mkstemp(*args, **kw) + finally: + # and then put it back + os.open = old_open + + +# Silence the PEP440Warning by default, so that end users don't get hit by it +# randomly just because they use pkg_resources. We want to append the rule +# because we want earlier uses of filterwarnings to take precedence over this +# one. +warnings.filterwarnings("ignore", category=PEP440Warning, append=True) + + +# from jaraco.functools 1.3 +def _call_aside(f, *args, **kwargs): + f(*args, **kwargs) + return f + + +@_call_aside +def _initialize(g=globals()): + "Set up global resource manager (deliberately not state-saved)" + manager = ResourceManager() + g['_manager'] = manager + g.update( + (name, getattr(manager, name)) + for name in dir(manager) + if not name.startswith('_') + ) + + +@_call_aside +def _initialize_master_working_set(): + """ + Prepare the master working set and make the ``require()`` + API available. + + This function has explicit effects on the global state + of pkg_resources. It is intended to be invoked once at + the initialization of this module. + + Invocation by other packages is unsupported and done + at their own risk. + """ + working_set = WorkingSet._build_master() + _declare_state('object', working_set=working_set) + + require = working_set.require + iter_entry_points = working_set.iter_entry_points + add_activation_listener = working_set.subscribe + run_script = working_set.run_script + # backward compatibility + run_main = run_script + # Activate all distributions already on sys.path with replace=False and + # ensure that all distributions added to the working set in the future + # (e.g. by calling ``require()``) will get activated as well, + # with higher priority (replace=True). + tuple( + dist.activate(replace=False) + for dist in working_set + ) + add_activation_listener( + lambda dist: dist.activate(replace=True), + existing=False, + ) + working_set.entries = [] + # match order + list(map(working_set.add_entry, sys.path)) + globals().update(locals()) + +class PkgResourcesDeprecationWarning(Warning): + """ + Base class for warning about deprecations in ``pkg_resources`` + + This class is not derived from ``DeprecationWarning``, and as such is + visible by default. + """ diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/__init__.py b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/appdirs.py b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/appdirs.py new file mode 100644 index 0000000..ae67001 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/appdirs.py @@ -0,0 +1,608 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# Copyright (c) 2005-2010 ActiveState Software Inc. +# Copyright (c) 2013 Eddy Petrișor + +"""Utilities for determining application-specific dirs. + +See for details and usage. +""" +# Dev Notes: +# - MSDN on where to store app data files: +# http://support.microsoft.com/default.aspx?scid=kb;en-us;310294#XSLTH3194121123120121120120 +# - Mac OS X: http://developer.apple.com/documentation/MacOSX/Conceptual/BPFileSystem/index.html +# - XDG spec for Un*x: http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html + +__version_info__ = (1, 4, 3) +__version__ = '.'.join(map(str, __version_info__)) + + +import sys +import os + +PY3 = sys.version_info[0] == 3 + +if PY3: + unicode = str + +if sys.platform.startswith('java'): + import platform + os_name = platform.java_ver()[3][0] + if os_name.startswith('Windows'): # "Windows XP", "Windows 7", etc. + system = 'win32' + elif os_name.startswith('Mac'): # "Mac OS X", etc. + system = 'darwin' + else: # "Linux", "SunOS", "FreeBSD", etc. + # Setting this to "linux2" is not ideal, but only Windows or Mac + # are actually checked for and the rest of the module expects + # *sys.platform* style strings. + system = 'linux2' +else: + system = sys.platform + + + +def user_data_dir(appname=None, appauthor=None, version=None, roaming=False): + r"""Return full path to the user-specific data dir for this application. + + "appname" is the name of application. + If None, just the system directory is returned. + "appauthor" (only used on Windows) is the name of the + appauthor or distributing body for this application. Typically + it is the owning company name. This falls back to appname. You may + pass False to disable it. + "version" is an optional version path element to append to the + path. You might want to use this if you want multiple versions + of your app to be able to run independently. If used, this + would typically be ".". + Only applied when appname is present. + "roaming" (boolean, default False) can be set True to use the Windows + roaming appdata directory. That means that for users on a Windows + network setup for roaming profiles, this user data will be + sync'd on login. See + + for a discussion of issues. + + Typical user data directories are: + Mac OS X: ~/Library/Application Support/ + Unix: ~/.local/share/ # or in $XDG_DATA_HOME, if defined + Win XP (not roaming): C:\Documents and Settings\\Application Data\\ + Win XP (roaming): C:\Documents and Settings\\Local Settings\Application Data\\ + Win 7 (not roaming): C:\Users\\AppData\Local\\ + Win 7 (roaming): C:\Users\\AppData\Roaming\\ + + For Unix, we follow the XDG spec and support $XDG_DATA_HOME. + That means, by default "~/.local/share/". + """ + if system == "win32": + if appauthor is None: + appauthor = appname + const = roaming and "CSIDL_APPDATA" or "CSIDL_LOCAL_APPDATA" + path = os.path.normpath(_get_win_folder(const)) + if appname: + if appauthor is not False: + path = os.path.join(path, appauthor, appname) + else: + path = os.path.join(path, appname) + elif system == 'darwin': + path = os.path.expanduser('~/Library/Application Support/') + if appname: + path = os.path.join(path, appname) + else: + path = os.getenv('XDG_DATA_HOME', os.path.expanduser("~/.local/share")) + if appname: + path = os.path.join(path, appname) + if appname and version: + path = os.path.join(path, version) + return path + + +def site_data_dir(appname=None, appauthor=None, version=None, multipath=False): + r"""Return full path to the user-shared data dir for this application. + + "appname" is the name of application. + If None, just the system directory is returned. + "appauthor" (only used on Windows) is the name of the + appauthor or distributing body for this application. Typically + it is the owning company name. This falls back to appname. You may + pass False to disable it. + "version" is an optional version path element to append to the + path. You might want to use this if you want multiple versions + of your app to be able to run independently. If used, this + would typically be ".". + Only applied when appname is present. + "multipath" is an optional parameter only applicable to *nix + which indicates that the entire list of data dirs should be + returned. By default, the first item from XDG_DATA_DIRS is + returned, or '/usr/local/share/', + if XDG_DATA_DIRS is not set + + Typical site data directories are: + Mac OS X: /Library/Application Support/ + Unix: /usr/local/share/ or /usr/share/ + Win XP: C:\Documents and Settings\All Users\Application Data\\ + Vista: (Fail! "C:\ProgramData" is a hidden *system* directory on Vista.) + Win 7: C:\ProgramData\\ # Hidden, but writeable on Win 7. + + For Unix, this is using the $XDG_DATA_DIRS[0] default. + + WARNING: Do not use this on Windows. See the Vista-Fail note above for why. + """ + if system == "win32": + if appauthor is None: + appauthor = appname + path = os.path.normpath(_get_win_folder("CSIDL_COMMON_APPDATA")) + if appname: + if appauthor is not False: + path = os.path.join(path, appauthor, appname) + else: + path = os.path.join(path, appname) + elif system == 'darwin': + path = os.path.expanduser('/Library/Application Support') + if appname: + path = os.path.join(path, appname) + else: + # XDG default for $XDG_DATA_DIRS + # only first, if multipath is False + path = os.getenv('XDG_DATA_DIRS', + os.pathsep.join(['/usr/local/share', '/usr/share'])) + pathlist = [os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep)] + if appname: + if version: + appname = os.path.join(appname, version) + pathlist = [os.sep.join([x, appname]) for x in pathlist] + + if multipath: + path = os.pathsep.join(pathlist) + else: + path = pathlist[0] + return path + + if appname and version: + path = os.path.join(path, version) + return path + + +def user_config_dir(appname=None, appauthor=None, version=None, roaming=False): + r"""Return full path to the user-specific config dir for this application. + + "appname" is the name of application. + If None, just the system directory is returned. + "appauthor" (only used on Windows) is the name of the + appauthor or distributing body for this application. Typically + it is the owning company name. This falls back to appname. You may + pass False to disable it. + "version" is an optional version path element to append to the + path. You might want to use this if you want multiple versions + of your app to be able to run independently. If used, this + would typically be ".". + Only applied when appname is present. + "roaming" (boolean, default False) can be set True to use the Windows + roaming appdata directory. That means that for users on a Windows + network setup for roaming profiles, this user data will be + sync'd on login. See + + for a discussion of issues. + + Typical user config directories are: + Mac OS X: same as user_data_dir + Unix: ~/.config/ # or in $XDG_CONFIG_HOME, if defined + Win *: same as user_data_dir + + For Unix, we follow the XDG spec and support $XDG_CONFIG_HOME. + That means, by default "~/.config/". + """ + if system in ["win32", "darwin"]: + path = user_data_dir(appname, appauthor, None, roaming) + else: + path = os.getenv('XDG_CONFIG_HOME', os.path.expanduser("~/.config")) + if appname: + path = os.path.join(path, appname) + if appname and version: + path = os.path.join(path, version) + return path + + +def site_config_dir(appname=None, appauthor=None, version=None, multipath=False): + r"""Return full path to the user-shared data dir for this application. + + "appname" is the name of application. + If None, just the system directory is returned. + "appauthor" (only used on Windows) is the name of the + appauthor or distributing body for this application. Typically + it is the owning company name. This falls back to appname. You may + pass False to disable it. + "version" is an optional version path element to append to the + path. You might want to use this if you want multiple versions + of your app to be able to run independently. If used, this + would typically be ".". + Only applied when appname is present. + "multipath" is an optional parameter only applicable to *nix + which indicates that the entire list of config dirs should be + returned. By default, the first item from XDG_CONFIG_DIRS is + returned, or '/etc/xdg/', if XDG_CONFIG_DIRS is not set + + Typical site config directories are: + Mac OS X: same as site_data_dir + Unix: /etc/xdg/ or $XDG_CONFIG_DIRS[i]/ for each value in + $XDG_CONFIG_DIRS + Win *: same as site_data_dir + Vista: (Fail! "C:\ProgramData" is a hidden *system* directory on Vista.) + + For Unix, this is using the $XDG_CONFIG_DIRS[0] default, if multipath=False + + WARNING: Do not use this on Windows. See the Vista-Fail note above for why. + """ + if system in ["win32", "darwin"]: + path = site_data_dir(appname, appauthor) + if appname and version: + path = os.path.join(path, version) + else: + # XDG default for $XDG_CONFIG_DIRS + # only first, if multipath is False + path = os.getenv('XDG_CONFIG_DIRS', '/etc/xdg') + pathlist = [os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep)] + if appname: + if version: + appname = os.path.join(appname, version) + pathlist = [os.sep.join([x, appname]) for x in pathlist] + + if multipath: + path = os.pathsep.join(pathlist) + else: + path = pathlist[0] + return path + + +def user_cache_dir(appname=None, appauthor=None, version=None, opinion=True): + r"""Return full path to the user-specific cache dir for this application. + + "appname" is the name of application. + If None, just the system directory is returned. + "appauthor" (only used on Windows) is the name of the + appauthor or distributing body for this application. Typically + it is the owning company name. This falls back to appname. You may + pass False to disable it. + "version" is an optional version path element to append to the + path. You might want to use this if you want multiple versions + of your app to be able to run independently. If used, this + would typically be ".". + Only applied when appname is present. + "opinion" (boolean) can be False to disable the appending of + "Cache" to the base app data dir for Windows. See + discussion below. + + Typical user cache directories are: + Mac OS X: ~/Library/Caches/ + Unix: ~/.cache/ (XDG default) + Win XP: C:\Documents and Settings\\Local Settings\Application Data\\\Cache + Vista: C:\Users\\AppData\Local\\\Cache + + On Windows the only suggestion in the MSDN docs is that local settings go in + the `CSIDL_LOCAL_APPDATA` directory. This is identical to the non-roaming + app data dir (the default returned by `user_data_dir` above). Apps typically + put cache data somewhere *under* the given dir here. Some examples: + ...\Mozilla\Firefox\Profiles\\Cache + ...\Acme\SuperApp\Cache\1.0 + OPINION: This function appends "Cache" to the `CSIDL_LOCAL_APPDATA` value. + This can be disabled with the `opinion=False` option. + """ + if system == "win32": + if appauthor is None: + appauthor = appname + path = os.path.normpath(_get_win_folder("CSIDL_LOCAL_APPDATA")) + if appname: + if appauthor is not False: + path = os.path.join(path, appauthor, appname) + else: + path = os.path.join(path, appname) + if opinion: + path = os.path.join(path, "Cache") + elif system == 'darwin': + path = os.path.expanduser('~/Library/Caches') + if appname: + path = os.path.join(path, appname) + else: + path = os.getenv('XDG_CACHE_HOME', os.path.expanduser('~/.cache')) + if appname: + path = os.path.join(path, appname) + if appname and version: + path = os.path.join(path, version) + return path + + +def user_state_dir(appname=None, appauthor=None, version=None, roaming=False): + r"""Return full path to the user-specific state dir for this application. + + "appname" is the name of application. + If None, just the system directory is returned. + "appauthor" (only used on Windows) is the name of the + appauthor or distributing body for this application. Typically + it is the owning company name. This falls back to appname. You may + pass False to disable it. + "version" is an optional version path element to append to the + path. You might want to use this if you want multiple versions + of your app to be able to run independently. If used, this + would typically be ".". + Only applied when appname is present. + "roaming" (boolean, default False) can be set True to use the Windows + roaming appdata directory. That means that for users on a Windows + network setup for roaming profiles, this user data will be + sync'd on login. See + + for a discussion of issues. + + Typical user state directories are: + Mac OS X: same as user_data_dir + Unix: ~/.local/state/ # or in $XDG_STATE_HOME, if defined + Win *: same as user_data_dir + + For Unix, we follow this Debian proposal + to extend the XDG spec and support $XDG_STATE_HOME. + + That means, by default "~/.local/state/". + """ + if system in ["win32", "darwin"]: + path = user_data_dir(appname, appauthor, None, roaming) + else: + path = os.getenv('XDG_STATE_HOME', os.path.expanduser("~/.local/state")) + if appname: + path = os.path.join(path, appname) + if appname and version: + path = os.path.join(path, version) + return path + + +def user_log_dir(appname=None, appauthor=None, version=None, opinion=True): + r"""Return full path to the user-specific log dir for this application. + + "appname" is the name of application. + If None, just the system directory is returned. + "appauthor" (only used on Windows) is the name of the + appauthor or distributing body for this application. Typically + it is the owning company name. This falls back to appname. You may + pass False to disable it. + "version" is an optional version path element to append to the + path. You might want to use this if you want multiple versions + of your app to be able to run independently. If used, this + would typically be ".". + Only applied when appname is present. + "opinion" (boolean) can be False to disable the appending of + "Logs" to the base app data dir for Windows, and "log" to the + base cache dir for Unix. See discussion below. + + Typical user log directories are: + Mac OS X: ~/Library/Logs/ + Unix: ~/.cache//log # or under $XDG_CACHE_HOME if defined + Win XP: C:\Documents and Settings\\Local Settings\Application Data\\\Logs + Vista: C:\Users\\AppData\Local\\\Logs + + On Windows the only suggestion in the MSDN docs is that local settings + go in the `CSIDL_LOCAL_APPDATA` directory. (Note: I'm interested in + examples of what some windows apps use for a logs dir.) + + OPINION: This function appends "Logs" to the `CSIDL_LOCAL_APPDATA` + value for Windows and appends "log" to the user cache dir for Unix. + This can be disabled with the `opinion=False` option. + """ + if system == "darwin": + path = os.path.join( + os.path.expanduser('~/Library/Logs'), + appname) + elif system == "win32": + path = user_data_dir(appname, appauthor, version) + version = False + if opinion: + path = os.path.join(path, "Logs") + else: + path = user_cache_dir(appname, appauthor, version) + version = False + if opinion: + path = os.path.join(path, "log") + if appname and version: + path = os.path.join(path, version) + return path + + +class AppDirs(object): + """Convenience wrapper for getting application dirs.""" + def __init__(self, appname=None, appauthor=None, version=None, + roaming=False, multipath=False): + self.appname = appname + self.appauthor = appauthor + self.version = version + self.roaming = roaming + self.multipath = multipath + + @property + def user_data_dir(self): + return user_data_dir(self.appname, self.appauthor, + version=self.version, roaming=self.roaming) + + @property + def site_data_dir(self): + return site_data_dir(self.appname, self.appauthor, + version=self.version, multipath=self.multipath) + + @property + def user_config_dir(self): + return user_config_dir(self.appname, self.appauthor, + version=self.version, roaming=self.roaming) + + @property + def site_config_dir(self): + return site_config_dir(self.appname, self.appauthor, + version=self.version, multipath=self.multipath) + + @property + def user_cache_dir(self): + return user_cache_dir(self.appname, self.appauthor, + version=self.version) + + @property + def user_state_dir(self): + return user_state_dir(self.appname, self.appauthor, + version=self.version) + + @property + def user_log_dir(self): + return user_log_dir(self.appname, self.appauthor, + version=self.version) + + +#---- internal support stuff + +def _get_win_folder_from_registry(csidl_name): + """This is a fallback technique at best. I'm not sure if using the + registry for this guarantees us the correct answer for all CSIDL_* + names. + """ + if PY3: + import winreg as _winreg + else: + import _winreg + + shell_folder_name = { + "CSIDL_APPDATA": "AppData", + "CSIDL_COMMON_APPDATA": "Common AppData", + "CSIDL_LOCAL_APPDATA": "Local AppData", + }[csidl_name] + + key = _winreg.OpenKey( + _winreg.HKEY_CURRENT_USER, + r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders" + ) + dir, type = _winreg.QueryValueEx(key, shell_folder_name) + return dir + + +def _get_win_folder_with_pywin32(csidl_name): + from win32com.shell import shellcon, shell + dir = shell.SHGetFolderPath(0, getattr(shellcon, csidl_name), 0, 0) + # Try to make this a unicode path because SHGetFolderPath does + # not return unicode strings when there is unicode data in the + # path. + try: + dir = unicode(dir) + + # Downgrade to short path name if have highbit chars. See + # . + has_high_char = False + for c in dir: + if ord(c) > 255: + has_high_char = True + break + if has_high_char: + try: + import win32api + dir = win32api.GetShortPathName(dir) + except ImportError: + pass + except UnicodeError: + pass + return dir + + +def _get_win_folder_with_ctypes(csidl_name): + import ctypes + + csidl_const = { + "CSIDL_APPDATA": 26, + "CSIDL_COMMON_APPDATA": 35, + "CSIDL_LOCAL_APPDATA": 28, + }[csidl_name] + + buf = ctypes.create_unicode_buffer(1024) + ctypes.windll.shell32.SHGetFolderPathW(None, csidl_const, None, 0, buf) + + # Downgrade to short path name if have highbit chars. See + # . + has_high_char = False + for c in buf: + if ord(c) > 255: + has_high_char = True + break + if has_high_char: + buf2 = ctypes.create_unicode_buffer(1024) + if ctypes.windll.kernel32.GetShortPathNameW(buf.value, buf2, 1024): + buf = buf2 + + return buf.value + +def _get_win_folder_with_jna(csidl_name): + import array + from com.sun import jna + from com.sun.jna.platform import win32 + + buf_size = win32.WinDef.MAX_PATH * 2 + buf = array.zeros('c', buf_size) + shell = win32.Shell32.INSTANCE + shell.SHGetFolderPath(None, getattr(win32.ShlObj, csidl_name), None, win32.ShlObj.SHGFP_TYPE_CURRENT, buf) + dir = jna.Native.toString(buf.tostring()).rstrip("\0") + + # Downgrade to short path name if have highbit chars. See + # . + has_high_char = False + for c in dir: + if ord(c) > 255: + has_high_char = True + break + if has_high_char: + buf = array.zeros('c', buf_size) + kernel = win32.Kernel32.INSTANCE + if kernel.GetShortPathName(dir, buf, buf_size): + dir = jna.Native.toString(buf.tostring()).rstrip("\0") + + return dir + +if system == "win32": + try: + import win32com.shell + _get_win_folder = _get_win_folder_with_pywin32 + except ImportError: + try: + from ctypes import windll + _get_win_folder = _get_win_folder_with_ctypes + except ImportError: + try: + import com.sun.jna + _get_win_folder = _get_win_folder_with_jna + except ImportError: + _get_win_folder = _get_win_folder_from_registry + + +#---- self test code + +if __name__ == "__main__": + appname = "MyApp" + appauthor = "MyCompany" + + props = ("user_data_dir", + "user_config_dir", + "user_cache_dir", + "user_state_dir", + "user_log_dir", + "site_data_dir", + "site_config_dir") + + print("-- app dirs %s --" % __version__) + + print("-- app dirs (with optional 'version')") + dirs = AppDirs(appname, appauthor, version="1.0") + for prop in props: + print("%s: %s" % (prop, getattr(dirs, prop))) + + print("\n-- app dirs (without optional 'version')") + dirs = AppDirs(appname, appauthor) + for prop in props: + print("%s: %s" % (prop, getattr(dirs, prop))) + + print("\n-- app dirs (without optional 'appauthor')") + dirs = AppDirs(appname) + for prop in props: + print("%s: %s" % (prop, getattr(dirs, prop))) + + print("\n-- app dirs (with disabled 'appauthor')") + dirs = AppDirs(appname, appauthor=False) + for prop in props: + print("%s: %s" % (prop, getattr(dirs, prop))) diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__about__.py b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__about__.py new file mode 100644 index 0000000..95d330e --- /dev/null +++ b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__about__.py @@ -0,0 +1,21 @@ +# 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 __future__ import absolute_import, division, print_function + +__all__ = [ + "__title__", "__summary__", "__uri__", "__version__", "__author__", + "__email__", "__license__", "__copyright__", +] + +__title__ = "packaging" +__summary__ = "Core utilities for Python packages" +__uri__ = "https://github.com/pypa/packaging" + +__version__ = "16.8" + +__author__ = "Donald Stufft and individual contributors" +__email__ = "donald@stufft.io" + +__license__ = "BSD or Apache License, Version 2.0" +__copyright__ = "Copyright 2014-2016 %s" % __author__ diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__init__.py b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__init__.py new file mode 100644 index 0000000..5ee6220 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__init__.py @@ -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 __future__ import absolute_import, division, print_function + +from .__about__ import ( + __author__, __copyright__, __email__, __license__, __summary__, __title__, + __uri__, __version__ +) + +__all__ = [ + "__title__", "__summary__", "__uri__", "__version__", "__author__", + "__email__", "__license__", "__copyright__", +] diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/_compat.py b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/_compat.py new file mode 100644 index 0000000..210bb80 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/_compat.py @@ -0,0 +1,30 @@ +# 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 __future__ import absolute_import, division, print_function + +import sys + + +PY2 = sys.version_info[0] == 2 +PY3 = sys.version_info[0] == 3 + +# flake8: noqa + +if PY3: + string_types = str, +else: + string_types = basestring, + + +def with_metaclass(meta, *bases): + """ + Create a base class with a metaclass. + """ + # This requires a bit of explanation: the basic idea is to make a dummy + # metaclass for one level of class instantiation that replaces itself with + # the actual metaclass. + class metaclass(meta): + def __new__(cls, name, this_bases, d): + return meta(name, bases, d) + return type.__new__(metaclass, 'temporary_class', (), {}) diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/_structures.py b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/_structures.py new file mode 100644 index 0000000..ccc2786 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/_structures.py @@ -0,0 +1,68 @@ +# 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 __future__ import absolute_import, division, print_function + + +class Infinity(object): + + def __repr__(self): + return "Infinity" + + def __hash__(self): + return hash(repr(self)) + + def __lt__(self, other): + return False + + def __le__(self, other): + return False + + def __eq__(self, other): + return isinstance(other, self.__class__) + + def __ne__(self, other): + return not isinstance(other, self.__class__) + + def __gt__(self, other): + return True + + def __ge__(self, other): + return True + + def __neg__(self): + return NegativeInfinity + +Infinity = Infinity() + + +class NegativeInfinity(object): + + def __repr__(self): + return "-Infinity" + + def __hash__(self): + return hash(repr(self)) + + def __lt__(self, other): + return True + + def __le__(self, other): + return True + + def __eq__(self, other): + return isinstance(other, self.__class__) + + def __ne__(self, other): + return not isinstance(other, self.__class__) + + def __gt__(self, other): + return False + + def __ge__(self, other): + return False + + def __neg__(self): + return Infinity + +NegativeInfinity = NegativeInfinity() diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/markers.py b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/markers.py new file mode 100644 index 0000000..892e578 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/markers.py @@ -0,0 +1,301 @@ +# 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 __future__ import absolute_import, division, print_function + +import operator +import os +import platform +import sys + +from pkg_resources.extern.pyparsing import ParseException, ParseResults, stringStart, stringEnd +from pkg_resources.extern.pyparsing import ZeroOrMore, Group, Forward, QuotedString +from pkg_resources.extern.pyparsing import Literal as L # noqa + +from ._compat import string_types +from .specifiers import Specifier, InvalidSpecifier + + +__all__ = [ + "InvalidMarker", "UndefinedComparison", "UndefinedEnvironmentName", + "Marker", "default_environment", +] + + +class InvalidMarker(ValueError): + """ + An invalid marker was found, users should refer to PEP 508. + """ + + +class UndefinedComparison(ValueError): + """ + An invalid operation was attempted on a value that doesn't support it. + """ + + +class UndefinedEnvironmentName(ValueError): + """ + A name was attempted to be used that does not exist inside of the + environment. + """ + + +class Node(object): + + def __init__(self, value): + self.value = value + + def __str__(self): + return str(self.value) + + def __repr__(self): + return "<{0}({1!r})>".format(self.__class__.__name__, str(self)) + + def serialize(self): + raise NotImplementedError + + +class Variable(Node): + + def serialize(self): + return str(self) + + +class Value(Node): + + def serialize(self): + return '"{0}"'.format(self) + + +class Op(Node): + + def serialize(self): + return str(self) + + +VARIABLE = ( + L("implementation_version") | + L("platform_python_implementation") | + L("implementation_name") | + L("python_full_version") | + L("platform_release") | + L("platform_version") | + L("platform_machine") | + L("platform_system") | + L("python_version") | + L("sys_platform") | + L("os_name") | + L("os.name") | # PEP-345 + L("sys.platform") | # PEP-345 + L("platform.version") | # PEP-345 + L("platform.machine") | # PEP-345 + L("platform.python_implementation") | # PEP-345 + L("python_implementation") | # undocumented setuptools legacy + L("extra") +) +ALIASES = { + 'os.name': 'os_name', + 'sys.platform': 'sys_platform', + 'platform.version': 'platform_version', + 'platform.machine': 'platform_machine', + 'platform.python_implementation': 'platform_python_implementation', + 'python_implementation': 'platform_python_implementation' +} +VARIABLE.setParseAction(lambda s, l, t: Variable(ALIASES.get(t[0], t[0]))) + +VERSION_CMP = ( + L("===") | + L("==") | + L(">=") | + L("<=") | + L("!=") | + L("~=") | + L(">") | + L("<") +) + +MARKER_OP = VERSION_CMP | L("not in") | L("in") +MARKER_OP.setParseAction(lambda s, l, t: Op(t[0])) + +MARKER_VALUE = QuotedString("'") | QuotedString('"') +MARKER_VALUE.setParseAction(lambda s, l, t: Value(t[0])) + +BOOLOP = L("and") | L("or") + +MARKER_VAR = VARIABLE | MARKER_VALUE + +MARKER_ITEM = Group(MARKER_VAR + MARKER_OP + MARKER_VAR) +MARKER_ITEM.setParseAction(lambda s, l, t: tuple(t[0])) + +LPAREN = L("(").suppress() +RPAREN = L(")").suppress() + +MARKER_EXPR = Forward() +MARKER_ATOM = MARKER_ITEM | Group(LPAREN + MARKER_EXPR + RPAREN) +MARKER_EXPR << MARKER_ATOM + ZeroOrMore(BOOLOP + MARKER_EXPR) + +MARKER = stringStart + MARKER_EXPR + stringEnd + + +def _coerce_parse_result(results): + if isinstance(results, ParseResults): + return [_coerce_parse_result(i) for i in results] + else: + return results + + +def _format_marker(marker, first=True): + assert isinstance(marker, (list, tuple, string_types)) + + # Sometimes we have a structure like [[...]] which is a single item list + # where the single item is itself it's own list. In that case we want skip + # the rest of this function so that we don't get extraneous () on the + # outside. + if (isinstance(marker, list) and len(marker) == 1 and + isinstance(marker[0], (list, tuple))): + return _format_marker(marker[0]) + + if isinstance(marker, list): + inner = (_format_marker(m, first=False) for m in marker) + if first: + return " ".join(inner) + else: + return "(" + " ".join(inner) + ")" + elif isinstance(marker, tuple): + return " ".join([m.serialize() for m in marker]) + else: + return marker + + +_operators = { + "in": lambda lhs, rhs: lhs in rhs, + "not in": lambda lhs, rhs: lhs not in rhs, + "<": operator.lt, + "<=": operator.le, + "==": operator.eq, + "!=": operator.ne, + ">=": operator.ge, + ">": operator.gt, +} + + +def _eval_op(lhs, op, rhs): + try: + spec = Specifier("".join([op.serialize(), rhs])) + except InvalidSpecifier: + pass + else: + return spec.contains(lhs) + + oper = _operators.get(op.serialize()) + if oper is None: + raise UndefinedComparison( + "Undefined {0!r} on {1!r} and {2!r}.".format(op, lhs, rhs) + ) + + return oper(lhs, rhs) + + +_undefined = object() + + +def _get_env(environment, name): + value = environment.get(name, _undefined) + + if value is _undefined: + raise UndefinedEnvironmentName( + "{0!r} does not exist in evaluation environment.".format(name) + ) + + return value + + +def _evaluate_markers(markers, environment): + groups = [[]] + + for marker in markers: + assert isinstance(marker, (list, tuple, string_types)) + + if isinstance(marker, list): + groups[-1].append(_evaluate_markers(marker, environment)) + elif isinstance(marker, tuple): + lhs, op, rhs = marker + + if isinstance(lhs, Variable): + lhs_value = _get_env(environment, lhs.value) + rhs_value = rhs.value + else: + lhs_value = lhs.value + rhs_value = _get_env(environment, rhs.value) + + groups[-1].append(_eval_op(lhs_value, op, rhs_value)) + else: + assert marker in ["and", "or"] + if marker == "or": + groups.append([]) + + return any(all(item) for item in groups) + + +def format_full_version(info): + version = '{0.major}.{0.minor}.{0.micro}'.format(info) + kind = info.releaselevel + if kind != 'final': + version += kind[0] + str(info.serial) + return version + + +def default_environment(): + if hasattr(sys, 'implementation'): + iver = format_full_version(sys.implementation.version) + implementation_name = sys.implementation.name + else: + iver = '0' + implementation_name = '' + + return { + "implementation_name": implementation_name, + "implementation_version": iver, + "os_name": os.name, + "platform_machine": platform.machine(), + "platform_release": platform.release(), + "platform_system": platform.system(), + "platform_version": platform.version(), + "python_full_version": platform.python_version(), + "platform_python_implementation": platform.python_implementation(), + "python_version": platform.python_version()[:3], + "sys_platform": sys.platform, + } + + +class Marker(object): + + def __init__(self, marker): + try: + self._markers = _coerce_parse_result(MARKER.parseString(marker)) + except ParseException as e: + err_str = "Invalid marker: {0!r}, parse error at {1!r}".format( + marker, marker[e.loc:e.loc + 8]) + raise InvalidMarker(err_str) + + def __str__(self): + return _format_marker(self._markers) + + def __repr__(self): + return "".format(str(self)) + + def evaluate(self, environment=None): + """Evaluate a marker. + + Return the boolean from evaluating the given marker against the + environment. environment is an optional argument to override all or + part of the determined environment. + + The environment is determined from the current Python process. + """ + current_environment = default_environment() + if environment is not None: + current_environment.update(environment) + + return _evaluate_markers(self._markers, current_environment) diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/requirements.py b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/requirements.py new file mode 100644 index 0000000..0c8c4a3 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/requirements.py @@ -0,0 +1,127 @@ +# 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 __future__ import absolute_import, division, print_function + +import string +import re + +from pkg_resources.extern.pyparsing import stringStart, stringEnd, originalTextFor, ParseException +from pkg_resources.extern.pyparsing import ZeroOrMore, Word, Optional, Regex, Combine +from pkg_resources.extern.pyparsing import Literal as L # noqa +from pkg_resources.extern.six.moves.urllib import parse as urlparse + +from .markers import MARKER_EXPR, Marker +from .specifiers import LegacySpecifier, Specifier, SpecifierSet + + +class InvalidRequirement(ValueError): + """ + An invalid requirement was found, users should refer to PEP 508. + """ + + +ALPHANUM = Word(string.ascii_letters + string.digits) + +LBRACKET = L("[").suppress() +RBRACKET = L("]").suppress() +LPAREN = L("(").suppress() +RPAREN = L(")").suppress() +COMMA = L(",").suppress() +SEMICOLON = L(";").suppress() +AT = L("@").suppress() + +PUNCTUATION = Word("-_.") +IDENTIFIER_END = ALPHANUM | (ZeroOrMore(PUNCTUATION) + ALPHANUM) +IDENTIFIER = Combine(ALPHANUM + ZeroOrMore(IDENTIFIER_END)) + +NAME = IDENTIFIER("name") +EXTRA = IDENTIFIER + +URI = Regex(r'[^ ]+')("url") +URL = (AT + URI) + +EXTRAS_LIST = EXTRA + ZeroOrMore(COMMA + EXTRA) +EXTRAS = (LBRACKET + Optional(EXTRAS_LIST) + RBRACKET)("extras") + +VERSION_PEP440 = Regex(Specifier._regex_str, re.VERBOSE | re.IGNORECASE) +VERSION_LEGACY = Regex(LegacySpecifier._regex_str, re.VERBOSE | re.IGNORECASE) + +VERSION_ONE = VERSION_PEP440 ^ VERSION_LEGACY +VERSION_MANY = Combine(VERSION_ONE + ZeroOrMore(COMMA + VERSION_ONE), + joinString=",", adjacent=False)("_raw_spec") +_VERSION_SPEC = Optional(((LPAREN + VERSION_MANY + RPAREN) | VERSION_MANY)) +_VERSION_SPEC.setParseAction(lambda s, l, t: t._raw_spec or '') + +VERSION_SPEC = originalTextFor(_VERSION_SPEC)("specifier") +VERSION_SPEC.setParseAction(lambda s, l, t: t[1]) + +MARKER_EXPR = originalTextFor(MARKER_EXPR())("marker") +MARKER_EXPR.setParseAction( + lambda s, l, t: Marker(s[t._original_start:t._original_end]) +) +MARKER_SEPERATOR = SEMICOLON +MARKER = MARKER_SEPERATOR + MARKER_EXPR + +VERSION_AND_MARKER = VERSION_SPEC + Optional(MARKER) +URL_AND_MARKER = URL + Optional(MARKER) + +NAMED_REQUIREMENT = \ + NAME + Optional(EXTRAS) + (URL_AND_MARKER | VERSION_AND_MARKER) + +REQUIREMENT = stringStart + NAMED_REQUIREMENT + stringEnd + + +class Requirement(object): + """Parse a requirement. + + Parse a given requirement string into its parts, such as name, specifier, + URL, and extras. Raises InvalidRequirement on a badly-formed requirement + string. + """ + + # TODO: Can we test whether something is contained within a requirement? + # If so how do we do that? Do we need to test against the _name_ of + # the thing as well as the version? What about the markers? + # TODO: Can we normalize the name and extra name? + + def __init__(self, requirement_string): + try: + req = REQUIREMENT.parseString(requirement_string) + except ParseException as e: + raise InvalidRequirement( + "Invalid requirement, parse error at \"{0!r}\"".format( + requirement_string[e.loc:e.loc + 8])) + + self.name = req.name + if req.url: + parsed_url = urlparse.urlparse(req.url) + if not (parsed_url.scheme and parsed_url.netloc) or ( + not parsed_url.scheme and not parsed_url.netloc): + raise InvalidRequirement("Invalid URL given") + self.url = req.url + else: + self.url = None + self.extras = set(req.extras.asList() if req.extras else []) + self.specifier = SpecifierSet(req.specifier) + self.marker = req.marker if req.marker else None + + def __str__(self): + parts = [self.name] + + if self.extras: + parts.append("[{0}]".format(",".join(sorted(self.extras)))) + + if self.specifier: + parts.append(str(self.specifier)) + + if self.url: + parts.append("@ {0}".format(self.url)) + + if self.marker: + parts.append("; {0}".format(self.marker)) + + return "".join(parts) + + def __repr__(self): + return "".format(str(self)) diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/specifiers.py b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/specifiers.py new file mode 100644 index 0000000..7f5a76c --- /dev/null +++ b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/specifiers.py @@ -0,0 +1,774 @@ +# 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 __future__ import absolute_import, division, print_function + +import abc +import functools +import itertools +import re + +from ._compat import string_types, with_metaclass +from .version import Version, LegacyVersion, parse + + +class InvalidSpecifier(ValueError): + """ + An invalid specifier was found, users should refer to PEP 440. + """ + + +class BaseSpecifier(with_metaclass(abc.ABCMeta, object)): + + @abc.abstractmethod + def __str__(self): + """ + Returns the str representation of this Specifier like object. This + should be representative of the Specifier itself. + """ + + @abc.abstractmethod + def __hash__(self): + """ + Returns a hash value for this Specifier like object. + """ + + @abc.abstractmethod + def __eq__(self, other): + """ + Returns a boolean representing whether or not the two Specifier like + objects are equal. + """ + + @abc.abstractmethod + def __ne__(self, other): + """ + Returns a boolean representing whether or not the two Specifier like + objects are not equal. + """ + + @abc.abstractproperty + def prereleases(self): + """ + Returns whether or not pre-releases as a whole are allowed by this + specifier. + """ + + @prereleases.setter + def prereleases(self, value): + """ + Sets whether or not pre-releases as a whole are allowed by this + specifier. + """ + + @abc.abstractmethod + def contains(self, item, prereleases=None): + """ + Determines if the given item is contained within this specifier. + """ + + @abc.abstractmethod + def filter(self, iterable, prereleases=None): + """ + Takes an iterable of items and filters them so that only items which + are contained within this specifier are allowed in it. + """ + + +class _IndividualSpecifier(BaseSpecifier): + + _operators = {} + + def __init__(self, spec="", prereleases=None): + match = self._regex.search(spec) + if not match: + raise InvalidSpecifier("Invalid specifier: '{0}'".format(spec)) + + self._spec = ( + match.group("operator").strip(), + match.group("version").strip(), + ) + + # Store whether or not this Specifier should accept prereleases + self._prereleases = prereleases + + def __repr__(self): + pre = ( + ", prereleases={0!r}".format(self.prereleases) + if self._prereleases is not None + else "" + ) + + return "<{0}({1!r}{2})>".format( + self.__class__.__name__, + str(self), + pre, + ) + + def __str__(self): + return "{0}{1}".format(*self._spec) + + def __hash__(self): + return hash(self._spec) + + def __eq__(self, other): + if isinstance(other, string_types): + try: + other = self.__class__(other) + except InvalidSpecifier: + return NotImplemented + elif not isinstance(other, self.__class__): + return NotImplemented + + return self._spec == other._spec + + def __ne__(self, other): + if isinstance(other, string_types): + try: + other = self.__class__(other) + except InvalidSpecifier: + return NotImplemented + elif not isinstance(other, self.__class__): + return NotImplemented + + return self._spec != other._spec + + def _get_operator(self, op): + return getattr(self, "_compare_{0}".format(self._operators[op])) + + def _coerce_version(self, version): + if not isinstance(version, (LegacyVersion, Version)): + version = parse(version) + return version + + @property + def operator(self): + return self._spec[0] + + @property + def version(self): + return self._spec[1] + + @property + def prereleases(self): + return self._prereleases + + @prereleases.setter + def prereleases(self, value): + self._prereleases = value + + def __contains__(self, item): + return self.contains(item) + + def contains(self, item, prereleases=None): + # Determine if prereleases are to be allowed or not. + if prereleases is None: + prereleases = self.prereleases + + # Normalize item to a Version or LegacyVersion, this allows us to have + # a shortcut for ``"2.0" in Specifier(">=2") + item = self._coerce_version(item) + + # Determine if we should be supporting prereleases in this specifier + # or not, if we do not support prereleases than we can short circuit + # logic if this version is a prereleases. + if item.is_prerelease and not prereleases: + return False + + # Actually do the comparison to determine if this item is contained + # within this Specifier or not. + return self._get_operator(self.operator)(item, self.version) + + def filter(self, iterable, prereleases=None): + yielded = False + found_prereleases = [] + + kw = {"prereleases": prereleases if prereleases is not None else True} + + # Attempt to iterate over all the values in the iterable and if any of + # them match, yield them. + for version in iterable: + parsed_version = self._coerce_version(version) + + if self.contains(parsed_version, **kw): + # If our version is a prerelease, and we were not set to allow + # prereleases, then we'll store it for later incase nothing + # else matches this specifier. + if (parsed_version.is_prerelease and not + (prereleases or self.prereleases)): + found_prereleases.append(version) + # Either this is not a prerelease, or we should have been + # accepting prereleases from the begining. + else: + yielded = True + yield version + + # Now that we've iterated over everything, determine if we've yielded + # any values, and if we have not and we have any prereleases stored up + # then we will go ahead and yield the prereleases. + if not yielded and found_prereleases: + for version in found_prereleases: + yield version + + +class LegacySpecifier(_IndividualSpecifier): + + _regex_str = ( + r""" + (?P(==|!=|<=|>=|<|>)) + \s* + (?P + [^,;\s)]* # Since this is a "legacy" specifier, and the version + # string can be just about anything, we match everything + # except for whitespace, a semi-colon for marker support, + # a closing paren since versions can be enclosed in + # them, and a comma since it's a version separator. + ) + """ + ) + + _regex = re.compile( + r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE) + + _operators = { + "==": "equal", + "!=": "not_equal", + "<=": "less_than_equal", + ">=": "greater_than_equal", + "<": "less_than", + ">": "greater_than", + } + + def _coerce_version(self, version): + if not isinstance(version, LegacyVersion): + version = LegacyVersion(str(version)) + return version + + def _compare_equal(self, prospective, spec): + return prospective == self._coerce_version(spec) + + def _compare_not_equal(self, prospective, spec): + return prospective != self._coerce_version(spec) + + def _compare_less_than_equal(self, prospective, spec): + return prospective <= self._coerce_version(spec) + + def _compare_greater_than_equal(self, prospective, spec): + return prospective >= self._coerce_version(spec) + + def _compare_less_than(self, prospective, spec): + return prospective < self._coerce_version(spec) + + def _compare_greater_than(self, prospective, spec): + return prospective > self._coerce_version(spec) + + +def _require_version_compare(fn): + @functools.wraps(fn) + def wrapped(self, prospective, spec): + if not isinstance(prospective, Version): + return False + return fn(self, prospective, spec) + return wrapped + + +class Specifier(_IndividualSpecifier): + + _regex_str = ( + r""" + (?P(~=|==|!=|<=|>=|<|>|===)) + (?P + (?: + # The identity operators allow for an escape hatch that will + # do an exact string match of the version you wish to install. + # This will not be parsed by PEP 440 and we cannot determine + # any semantic meaning from it. This operator is discouraged + # but included entirely as an escape hatch. + (?<====) # Only match for the identity operator + \s* + [^\s]* # We just match everything, except for whitespace + # since we are only testing for strict identity. + ) + | + (?: + # The (non)equality operators allow for wild card and local + # versions to be specified so we have to define these two + # operators separately to enable that. + (?<===|!=) # Only match for equals and not equals + + \s* + v? + (?:[0-9]+!)? # epoch + [0-9]+(?:\.[0-9]+)* # release + (?: # pre release + [-_\.]? + (a|b|c|rc|alpha|beta|pre|preview) + [-_\.]? + [0-9]* + )? + (?: # post release + (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*) + )? + + # You cannot use a wild card and a dev or local version + # together so group them with a | and make them optional. + (?: + (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release + (?:\+[a-z0-9]+(?:[-_\.][a-z0-9]+)*)? # local + | + \.\* # Wild card syntax of .* + )? + ) + | + (?: + # The compatible operator requires at least two digits in the + # release segment. + (?<=~=) # Only match for the compatible operator + + \s* + v? + (?:[0-9]+!)? # epoch + [0-9]+(?:\.[0-9]+)+ # release (We have a + instead of a *) + (?: # pre release + [-_\.]? + (a|b|c|rc|alpha|beta|pre|preview) + [-_\.]? + [0-9]* + )? + (?: # post release + (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*) + )? + (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release + ) + | + (?: + # All other operators only allow a sub set of what the + # (non)equality operators do. Specifically they do not allow + # local versions to be specified nor do they allow the prefix + # matching wild cards. + (?=": "greater_than_equal", + "<": "less_than", + ">": "greater_than", + "===": "arbitrary", + } + + @_require_version_compare + def _compare_compatible(self, prospective, spec): + # Compatible releases have an equivalent combination of >= and ==. That + # is that ~=2.2 is equivalent to >=2.2,==2.*. This allows us to + # implement this in terms of the other specifiers instead of + # implementing it ourselves. The only thing we need to do is construct + # the other specifiers. + + # We want everything but the last item in the version, but we want to + # ignore post and dev releases and we want to treat the pre-release as + # it's own separate segment. + prefix = ".".join( + list( + itertools.takewhile( + lambda x: (not x.startswith("post") and not + x.startswith("dev")), + _version_split(spec), + ) + )[:-1] + ) + + # Add the prefix notation to the end of our string + prefix += ".*" + + return (self._get_operator(">=")(prospective, spec) and + self._get_operator("==")(prospective, prefix)) + + @_require_version_compare + def _compare_equal(self, prospective, spec): + # We need special logic to handle prefix matching + if spec.endswith(".*"): + # In the case of prefix matching we want to ignore local segment. + prospective = Version(prospective.public) + # Split the spec out by dots, and pretend that there is an implicit + # dot in between a release segment and a pre-release segment. + spec = _version_split(spec[:-2]) # Remove the trailing .* + + # Split the prospective version out by dots, and pretend that there + # is an implicit dot in between a release segment and a pre-release + # segment. + prospective = _version_split(str(prospective)) + + # Shorten the prospective version to be the same length as the spec + # so that we can determine if the specifier is a prefix of the + # prospective version or not. + prospective = prospective[:len(spec)] + + # Pad out our two sides with zeros so that they both equal the same + # length. + spec, prospective = _pad_version(spec, prospective) + else: + # Convert our spec string into a Version + spec = Version(spec) + + # If the specifier does not have a local segment, then we want to + # act as if the prospective version also does not have a local + # segment. + if not spec.local: + prospective = Version(prospective.public) + + return prospective == spec + + @_require_version_compare + def _compare_not_equal(self, prospective, spec): + return not self._compare_equal(prospective, spec) + + @_require_version_compare + def _compare_less_than_equal(self, prospective, spec): + return prospective <= Version(spec) + + @_require_version_compare + def _compare_greater_than_equal(self, prospective, spec): + return prospective >= Version(spec) + + @_require_version_compare + def _compare_less_than(self, prospective, spec): + # Convert our spec to a Version instance, since we'll want to work with + # it as a version. + spec = Version(spec) + + # Check to see if the prospective version is less than the spec + # version. If it's not we can short circuit and just return False now + # instead of doing extra unneeded work. + if not prospective < spec: + return False + + # This special case is here so that, unless the specifier itself + # includes is a pre-release version, that we do not accept pre-release + # versions for the version mentioned in the specifier (e.g. <3.1 should + # not match 3.1.dev0, but should match 3.0.dev0). + if not spec.is_prerelease and prospective.is_prerelease: + if Version(prospective.base_version) == Version(spec.base_version): + return False + + # If we've gotten to here, it means that prospective version is both + # less than the spec version *and* it's not a pre-release of the same + # version in the spec. + return True + + @_require_version_compare + def _compare_greater_than(self, prospective, spec): + # Convert our spec to a Version instance, since we'll want to work with + # it as a version. + spec = Version(spec) + + # Check to see if the prospective version is greater than the spec + # version. If it's not we can short circuit and just return False now + # instead of doing extra unneeded work. + if not prospective > spec: + return False + + # This special case is here so that, unless the specifier itself + # includes is a post-release version, that we do not accept + # post-release versions for the version mentioned in the specifier + # (e.g. >3.1 should not match 3.0.post0, but should match 3.2.post0). + if not spec.is_postrelease and prospective.is_postrelease: + if Version(prospective.base_version) == Version(spec.base_version): + return False + + # Ensure that we do not allow a local version of the version mentioned + # in the specifier, which is techincally greater than, to match. + if prospective.local is not None: + if Version(prospective.base_version) == Version(spec.base_version): + return False + + # If we've gotten to here, it means that prospective version is both + # greater than the spec version *and* it's not a pre-release of the + # same version in the spec. + return True + + def _compare_arbitrary(self, prospective, spec): + return str(prospective).lower() == str(spec).lower() + + @property + def prereleases(self): + # If there is an explicit prereleases set for this, then we'll just + # blindly use that. + if self._prereleases is not None: + return self._prereleases + + # Look at all of our specifiers and determine if they are inclusive + # operators, and if they are if they are including an explicit + # prerelease. + operator, version = self._spec + if operator in ["==", ">=", "<=", "~=", "==="]: + # The == specifier can include a trailing .*, if it does we + # want to remove before parsing. + if operator == "==" and version.endswith(".*"): + version = version[:-2] + + # Parse the version, and if it is a pre-release than this + # specifier allows pre-releases. + if parse(version).is_prerelease: + return True + + return False + + @prereleases.setter + def prereleases(self, value): + self._prereleases = value + + +_prefix_regex = re.compile(r"^([0-9]+)((?:a|b|c|rc)[0-9]+)$") + + +def _version_split(version): + result = [] + for item in version.split("."): + match = _prefix_regex.search(item) + if match: + result.extend(match.groups()) + else: + result.append(item) + return result + + +def _pad_version(left, right): + left_split, right_split = [], [] + + # Get the release segment of our versions + left_split.append(list(itertools.takewhile(lambda x: x.isdigit(), left))) + right_split.append(list(itertools.takewhile(lambda x: x.isdigit(), right))) + + # Get the rest of our versions + left_split.append(left[len(left_split[0]):]) + right_split.append(right[len(right_split[0]):]) + + # Insert our padding + left_split.insert( + 1, + ["0"] * max(0, len(right_split[0]) - len(left_split[0])), + ) + right_split.insert( + 1, + ["0"] * max(0, len(left_split[0]) - len(right_split[0])), + ) + + return ( + list(itertools.chain(*left_split)), + list(itertools.chain(*right_split)), + ) + + +class SpecifierSet(BaseSpecifier): + + def __init__(self, specifiers="", prereleases=None): + # Split on , to break each indidivual specifier into it's own item, and + # strip each item to remove leading/trailing whitespace. + specifiers = [s.strip() for s in specifiers.split(",") if s.strip()] + + # Parsed each individual specifier, attempting first to make it a + # Specifier and falling back to a LegacySpecifier. + parsed = set() + for specifier in specifiers: + try: + parsed.add(Specifier(specifier)) + except InvalidSpecifier: + parsed.add(LegacySpecifier(specifier)) + + # Turn our parsed specifiers into a frozen set and save them for later. + self._specs = frozenset(parsed) + + # Store our prereleases value so we can use it later to determine if + # we accept prereleases or not. + self._prereleases = prereleases + + def __repr__(self): + pre = ( + ", prereleases={0!r}".format(self.prereleases) + if self._prereleases is not None + else "" + ) + + return "".format(str(self), pre) + + def __str__(self): + return ",".join(sorted(str(s) for s in self._specs)) + + def __hash__(self): + return hash(self._specs) + + def __and__(self, other): + if isinstance(other, string_types): + other = SpecifierSet(other) + elif not isinstance(other, SpecifierSet): + return NotImplemented + + specifier = SpecifierSet() + specifier._specs = frozenset(self._specs | other._specs) + + if self._prereleases is None and other._prereleases is not None: + specifier._prereleases = other._prereleases + elif self._prereleases is not None and other._prereleases is None: + specifier._prereleases = self._prereleases + elif self._prereleases == other._prereleases: + specifier._prereleases = self._prereleases + else: + raise ValueError( + "Cannot combine SpecifierSets with True and False prerelease " + "overrides." + ) + + return specifier + + def __eq__(self, other): + if isinstance(other, string_types): + other = SpecifierSet(other) + elif isinstance(other, _IndividualSpecifier): + other = SpecifierSet(str(other)) + elif not isinstance(other, SpecifierSet): + return NotImplemented + + return self._specs == other._specs + + def __ne__(self, other): + if isinstance(other, string_types): + other = SpecifierSet(other) + elif isinstance(other, _IndividualSpecifier): + other = SpecifierSet(str(other)) + elif not isinstance(other, SpecifierSet): + return NotImplemented + + return self._specs != other._specs + + def __len__(self): + return len(self._specs) + + def __iter__(self): + return iter(self._specs) + + @property + def prereleases(self): + # If we have been given an explicit prerelease modifier, then we'll + # pass that through here. + if self._prereleases is not None: + return self._prereleases + + # If we don't have any specifiers, and we don't have a forced value, + # then we'll just return None since we don't know if this should have + # pre-releases or not. + if not self._specs: + return None + + # Otherwise we'll see if any of the given specifiers accept + # prereleases, if any of them do we'll return True, otherwise False. + return any(s.prereleases for s in self._specs) + + @prereleases.setter + def prereleases(self, value): + self._prereleases = value + + def __contains__(self, item): + return self.contains(item) + + def contains(self, item, prereleases=None): + # Ensure that our item is a Version or LegacyVersion instance. + if not isinstance(item, (LegacyVersion, Version)): + item = parse(item) + + # Determine if we're forcing a prerelease or not, if we're not forcing + # one for this particular filter call, then we'll use whatever the + # SpecifierSet thinks for whether or not we should support prereleases. + if prereleases is None: + prereleases = self.prereleases + + # We can determine if we're going to allow pre-releases by looking to + # see if any of the underlying items supports them. If none of them do + # and this item is a pre-release then we do not allow it and we can + # short circuit that here. + # Note: This means that 1.0.dev1 would not be contained in something + # like >=1.0.devabc however it would be in >=1.0.debabc,>0.0.dev0 + if not prereleases and item.is_prerelease: + return False + + # We simply dispatch to the underlying specs here to make sure that the + # given version is contained within all of them. + # Note: This use of all() here means that an empty set of specifiers + # will always return True, this is an explicit design decision. + return all( + s.contains(item, prereleases=prereleases) + for s in self._specs + ) + + def filter(self, iterable, prereleases=None): + # Determine if we're forcing a prerelease or not, if we're not forcing + # one for this particular filter call, then we'll use whatever the + # SpecifierSet thinks for whether or not we should support prereleases. + if prereleases is None: + prereleases = self.prereleases + + # If we have any specifiers, then we want to wrap our iterable in the + # filter method for each one, this will act as a logical AND amongst + # each specifier. + if self._specs: + for spec in self._specs: + iterable = spec.filter(iterable, prereleases=bool(prereleases)) + return iterable + # If we do not have any specifiers, then we need to have a rough filter + # which will filter out any pre-releases, unless there are no final + # releases, and which will filter out LegacyVersion in general. + else: + filtered = [] + found_prereleases = [] + + for item in iterable: + # Ensure that we some kind of Version class for this item. + if not isinstance(item, (LegacyVersion, Version)): + parsed_version = parse(item) + else: + parsed_version = item + + # Filter out any item which is parsed as a LegacyVersion + if isinstance(parsed_version, LegacyVersion): + continue + + # Store any item which is a pre-release for later unless we've + # already found a final version or we are accepting prereleases + if parsed_version.is_prerelease and not prereleases: + if not filtered: + found_prereleases.append(item) + else: + filtered.append(item) + + # If we've found no items except for pre-releases, then we'll go + # ahead and use the pre-releases + if not filtered and found_prereleases and prereleases is None: + return found_prereleases + + return filtered diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/utils.py b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/utils.py new file mode 100644 index 0000000..942387c --- /dev/null +++ b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/utils.py @@ -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 __future__ import absolute_import, division, print_function + +import re + + +_canonicalize_regex = re.compile(r"[-_.]+") + + +def canonicalize_name(name): + # This is taken from PEP 503. + return _canonicalize_regex.sub("-", name).lower() diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/version.py b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/version.py new file mode 100644 index 0000000..83b5ee8 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/version.py @@ -0,0 +1,393 @@ +# 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 __future__ import absolute_import, division, print_function + +import collections +import itertools +import re + +from ._structures import Infinity + + +__all__ = [ + "parse", "Version", "LegacyVersion", "InvalidVersion", "VERSION_PATTERN" +] + + +_Version = collections.namedtuple( + "_Version", + ["epoch", "release", "dev", "pre", "post", "local"], +) + + +def parse(version): + """ + Parse the given version string and return either a :class:`Version` object + or a :class:`LegacyVersion` object depending on if the given version is + a valid PEP 440 version or a legacy version. + """ + try: + return Version(version) + except InvalidVersion: + return LegacyVersion(version) + + +class InvalidVersion(ValueError): + """ + An invalid version was found, users should refer to PEP 440. + """ + + +class _BaseVersion(object): + + def __hash__(self): + return hash(self._key) + + def __lt__(self, other): + return self._compare(other, lambda s, o: s < o) + + def __le__(self, other): + return self._compare(other, lambda s, o: s <= o) + + def __eq__(self, other): + return self._compare(other, lambda s, o: s == o) + + def __ge__(self, other): + return self._compare(other, lambda s, o: s >= o) + + def __gt__(self, other): + return self._compare(other, lambda s, o: s > o) + + def __ne__(self, other): + return self._compare(other, lambda s, o: s != o) + + def _compare(self, other, method): + if not isinstance(other, _BaseVersion): + return NotImplemented + + return method(self._key, other._key) + + +class LegacyVersion(_BaseVersion): + + def __init__(self, version): + self._version = str(version) + self._key = _legacy_cmpkey(self._version) + + def __str__(self): + return self._version + + def __repr__(self): + return "".format(repr(str(self))) + + @property + def public(self): + return self._version + + @property + def base_version(self): + return self._version + + @property + def local(self): + return None + + @property + def is_prerelease(self): + return False + + @property + def is_postrelease(self): + return False + + +_legacy_version_component_re = re.compile( + r"(\d+ | [a-z]+ | \.| -)", re.VERBOSE, +) + +_legacy_version_replacement_map = { + "pre": "c", "preview": "c", "-": "final-", "rc": "c", "dev": "@", +} + + +def _parse_version_parts(s): + for part in _legacy_version_component_re.split(s): + part = _legacy_version_replacement_map.get(part, part) + + if not part or part == ".": + continue + + if part[:1] in "0123456789": + # pad for numeric comparison + yield part.zfill(8) + else: + yield "*" + part + + # ensure that alpha/beta/candidate are before final + yield "*final" + + +def _legacy_cmpkey(version): + # We hardcode an epoch of -1 here. A PEP 440 version can only have a epoch + # greater than or equal to 0. This will effectively put the LegacyVersion, + # which uses the defacto standard originally implemented by setuptools, + # as before all PEP 440 versions. + epoch = -1 + + # This scheme is taken from pkg_resources.parse_version setuptools prior to + # it's adoption of the packaging library. + parts = [] + for part in _parse_version_parts(version.lower()): + if part.startswith("*"): + # remove "-" before a prerelease tag + if part < "*final": + while parts and parts[-1] == "*final-": + parts.pop() + + # remove trailing zeros from each series of numeric parts + while parts and parts[-1] == "00000000": + parts.pop() + + parts.append(part) + parts = tuple(parts) + + return epoch, parts + +# Deliberately not anchored to the start and end of the string, to make it +# easier for 3rd party code to reuse +VERSION_PATTERN = r""" + v? + (?: + (?:(?P[0-9]+)!)? # epoch + (?P[0-9]+(?:\.[0-9]+)*) # release segment + (?P
                                          # pre-release
+            [-_\.]?
+            (?P(a|b|c|rc|alpha|beta|pre|preview))
+            [-_\.]?
+            (?P[0-9]+)?
+        )?
+        (?P                                         # post release
+            (?:-(?P[0-9]+))
+            |
+            (?:
+                [-_\.]?
+                (?Ppost|rev|r)
+                [-_\.]?
+                (?P[0-9]+)?
+            )
+        )?
+        (?P                                          # dev release
+            [-_\.]?
+            (?Pdev)
+            [-_\.]?
+            (?P[0-9]+)?
+        )?
+    )
+    (?:\+(?P[a-z0-9]+(?:[-_\.][a-z0-9]+)*))?       # local version
+"""
+
+
+class Version(_BaseVersion):
+
+    _regex = re.compile(
+        r"^\s*" + VERSION_PATTERN + r"\s*$",
+        re.VERBOSE | re.IGNORECASE,
+    )
+
+    def __init__(self, version):
+        # Validate the version and parse it into pieces
+        match = self._regex.search(version)
+        if not match:
+            raise InvalidVersion("Invalid version: '{0}'".format(version))
+
+        # Store the parsed out pieces of the version
+        self._version = _Version(
+            epoch=int(match.group("epoch")) if match.group("epoch") else 0,
+            release=tuple(int(i) for i in match.group("release").split(".")),
+            pre=_parse_letter_version(
+                match.group("pre_l"),
+                match.group("pre_n"),
+            ),
+            post=_parse_letter_version(
+                match.group("post_l"),
+                match.group("post_n1") or match.group("post_n2"),
+            ),
+            dev=_parse_letter_version(
+                match.group("dev_l"),
+                match.group("dev_n"),
+            ),
+            local=_parse_local_version(match.group("local")),
+        )
+
+        # Generate a key which will be used for sorting
+        self._key = _cmpkey(
+            self._version.epoch,
+            self._version.release,
+            self._version.pre,
+            self._version.post,
+            self._version.dev,
+            self._version.local,
+        )
+
+    def __repr__(self):
+        return "".format(repr(str(self)))
+
+    def __str__(self):
+        parts = []
+
+        # Epoch
+        if self._version.epoch != 0:
+            parts.append("{0}!".format(self._version.epoch))
+
+        # Release segment
+        parts.append(".".join(str(x) for x in self._version.release))
+
+        # Pre-release
+        if self._version.pre is not None:
+            parts.append("".join(str(x) for x in self._version.pre))
+
+        # Post-release
+        if self._version.post is not None:
+            parts.append(".post{0}".format(self._version.post[1]))
+
+        # Development release
+        if self._version.dev is not None:
+            parts.append(".dev{0}".format(self._version.dev[1]))
+
+        # Local version segment
+        if self._version.local is not None:
+            parts.append(
+                "+{0}".format(".".join(str(x) for x in self._version.local))
+            )
+
+        return "".join(parts)
+
+    @property
+    def public(self):
+        return str(self).split("+", 1)[0]
+
+    @property
+    def base_version(self):
+        parts = []
+
+        # Epoch
+        if self._version.epoch != 0:
+            parts.append("{0}!".format(self._version.epoch))
+
+        # Release segment
+        parts.append(".".join(str(x) for x in self._version.release))
+
+        return "".join(parts)
+
+    @property
+    def local(self):
+        version_string = str(self)
+        if "+" in version_string:
+            return version_string.split("+", 1)[1]
+
+    @property
+    def is_prerelease(self):
+        return bool(self._version.dev or self._version.pre)
+
+    @property
+    def is_postrelease(self):
+        return bool(self._version.post)
+
+
+def _parse_letter_version(letter, number):
+    if letter:
+        # We consider there to be an implicit 0 in a pre-release if there is
+        # not a numeral associated with it.
+        if number is None:
+            number = 0
+
+        # We normalize any letters to their lower case form
+        letter = letter.lower()
+
+        # We consider some words to be alternate spellings of other words and
+        # in those cases we want to normalize the spellings to our preferred
+        # spelling.
+        if letter == "alpha":
+            letter = "a"
+        elif letter == "beta":
+            letter = "b"
+        elif letter in ["c", "pre", "preview"]:
+            letter = "rc"
+        elif letter in ["rev", "r"]:
+            letter = "post"
+
+        return letter, int(number)
+    if not letter and number:
+        # We assume if we are given a number, but we are not given a letter
+        # then this is using the implicit post release syntax (e.g. 1.0-1)
+        letter = "post"
+
+        return letter, int(number)
+
+
+_local_version_seperators = re.compile(r"[\._-]")
+
+
+def _parse_local_version(local):
+    """
+    Takes a string like abc.1.twelve and turns it into ("abc", 1, "twelve").
+    """
+    if local is not None:
+        return tuple(
+            part.lower() if not part.isdigit() else int(part)
+            for part in _local_version_seperators.split(local)
+        )
+
+
+def _cmpkey(epoch, release, pre, post, dev, local):
+    # When we compare a release version, we want to compare it with all of the
+    # trailing zeros removed. So we'll use a reverse the list, drop all the now
+    # leading zeros until we come to something non zero, then take the rest
+    # re-reverse it back into the correct order and make it a tuple and use
+    # that for our sorting key.
+    release = tuple(
+        reversed(list(
+            itertools.dropwhile(
+                lambda x: x == 0,
+                reversed(release),
+            )
+        ))
+    )
+
+    # We need to "trick" the sorting algorithm to put 1.0.dev0 before 1.0a0.
+    # We'll do this by abusing the pre segment, but we _only_ want to do this
+    # if there is not a pre or a post segment. If we have one of those then
+    # the normal sorting rules will handle this case correctly.
+    if pre is None and post is None and dev is not None:
+        pre = -Infinity
+    # Versions without a pre-release (except as noted above) should sort after
+    # those with one.
+    elif pre is None:
+        pre = Infinity
+
+    # Versions without a post segment should sort before those with one.
+    if post is None:
+        post = -Infinity
+
+    # Versions without a development segment should sort after those with one.
+    if dev is None:
+        dev = Infinity
+
+    if local is None:
+        # Versions without a local segment should sort before those with one.
+        local = -Infinity
+    else:
+        # Versions with a local segment need that segment parsed to implement
+        # the sorting rules in PEP440.
+        # - Alpha numeric segments sort before numeric segments
+        # - Alpha numeric segments sort lexicographically
+        # - Numeric segments sort numerically
+        # - Shorter versions sort before longer versions when the prefixes
+        #   match exactly
+        local = tuple(
+            (i, "") if isinstance(i, int) else (-Infinity, i)
+            for i in local
+        )
+
+    return epoch, release, pre, post, dev, local
diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/pyparsing.py b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/pyparsing.py
new file mode 100644
index 0000000..cf75e1e
--- /dev/null
+++ b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/pyparsing.py
@@ -0,0 +1,5742 @@
+# module pyparsing.py
+#
+# Copyright (c) 2003-2018  Paul T. McGuire
+#
+# 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.
+#
+
+__doc__ = \
+"""
+pyparsing module - Classes and methods to define and execute parsing grammars
+=============================================================================
+
+The pyparsing module is an alternative approach to creating and executing simple grammars,
+vs. the traditional lex/yacc approach, or the use of regular expressions.  With pyparsing, you
+don't need to learn a new syntax for defining grammars or matching expressions - the parsing module
+provides a library of classes that you use to construct the grammar directly in Python.
+
+Here is a program to parse "Hello, World!" (or any greeting of the form 
+C{", !"}), built up using L{Word}, L{Literal}, and L{And} elements 
+(L{'+'} operator gives L{And} expressions, strings are auto-converted to
+L{Literal} expressions)::
+
+    from pyparsing import Word, alphas
+
+    # define grammar of a greeting
+    greet = Word(alphas) + "," + Word(alphas) + "!"
+
+    hello = "Hello, World!"
+    print (hello, "->", greet.parseString(hello))
+
+The program outputs the following::
+
+    Hello, World! -> ['Hello', ',', 'World', '!']
+
+The Python representation of the grammar is quite readable, owing to the self-explanatory
+class names, and the use of '+', '|' and '^' operators.
+
+The L{ParseResults} object returned from L{ParserElement.parseString} can be accessed as a nested list, a dictionary, or an
+object with named attributes.
+
+The pyparsing module handles some of the problems that are typically vexing when writing text parsers:
+ - extra or missing whitespace (the above program will also handle "Hello,World!", "Hello  ,  World  !", etc.)
+ - quoted strings
+ - embedded comments
+
+
+Getting Started -
+-----------------
+Visit the classes L{ParserElement} and L{ParseResults} to see the base classes that most other pyparsing
+classes inherit from. Use the docstrings for examples of how to:
+ - construct literal match expressions from L{Literal} and L{CaselessLiteral} classes
+ - construct character word-group expressions using the L{Word} class
+ - see how to create repetitive expressions using L{ZeroOrMore} and L{OneOrMore} classes
+ - use L{'+'}, L{'|'}, L{'^'}, and L{'&'} operators to combine simple expressions into more complex ones
+ - associate names with your parsed results using L{ParserElement.setResultsName}
+ - find some helpful expression short-cuts like L{delimitedList} and L{oneOf}
+ - find more useful common expressions in the L{pyparsing_common} namespace class
+"""
+
+__version__ = "2.2.1"
+__versionTime__ = "18 Sep 2018 00:49 UTC"
+__author__ = "Paul McGuire "
+
+import string
+from weakref import ref as wkref
+import copy
+import sys
+import warnings
+import re
+import sre_constants
+import collections
+import pprint
+import traceback
+import types
+from datetime import datetime
+
+try:
+    from _thread import RLock
+except ImportError:
+    from threading import RLock
+
+try:
+    # Python 3
+    from collections.abc import Iterable
+    from collections.abc import MutableMapping
+except ImportError:
+    # Python 2.7
+    from collections import Iterable
+    from collections import MutableMapping
+
+try:
+    from collections import OrderedDict as _OrderedDict
+except ImportError:
+    try:
+        from ordereddict import OrderedDict as _OrderedDict
+    except ImportError:
+        _OrderedDict = None
+
+#~ sys.stderr.write( "testing pyparsing module, version %s, %s\n" % (__version__,__versionTime__ ) )
+
+__all__ = [
+'And', 'CaselessKeyword', 'CaselessLiteral', 'CharsNotIn', 'Combine', 'Dict', 'Each', 'Empty',
+'FollowedBy', 'Forward', 'GoToColumn', 'Group', 'Keyword', 'LineEnd', 'LineStart', 'Literal',
+'MatchFirst', 'NoMatch', 'NotAny', 'OneOrMore', 'OnlyOnce', 'Optional', 'Or',
+'ParseBaseException', 'ParseElementEnhance', 'ParseException', 'ParseExpression', 'ParseFatalException',
+'ParseResults', 'ParseSyntaxException', 'ParserElement', 'QuotedString', 'RecursiveGrammarException',
+'Regex', 'SkipTo', 'StringEnd', 'StringStart', 'Suppress', 'Token', 'TokenConverter', 
+'White', 'Word', 'WordEnd', 'WordStart', 'ZeroOrMore',
+'alphanums', 'alphas', 'alphas8bit', 'anyCloseTag', 'anyOpenTag', 'cStyleComment', 'col',
+'commaSeparatedList', 'commonHTMLEntity', 'countedArray', 'cppStyleComment', 'dblQuotedString',
+'dblSlashComment', 'delimitedList', 'dictOf', 'downcaseTokens', 'empty', 'hexnums',
+'htmlComment', 'javaStyleComment', 'line', 'lineEnd', 'lineStart', 'lineno',
+'makeHTMLTags', 'makeXMLTags', 'matchOnlyAtCol', 'matchPreviousExpr', 'matchPreviousLiteral',
+'nestedExpr', 'nullDebugAction', 'nums', 'oneOf', 'opAssoc', 'operatorPrecedence', 'printables',
+'punc8bit', 'pythonStyleComment', 'quotedString', 'removeQuotes', 'replaceHTMLEntity', 
+'replaceWith', 'restOfLine', 'sglQuotedString', 'srange', 'stringEnd',
+'stringStart', 'traceParseAction', 'unicodeString', 'upcaseTokens', 'withAttribute',
+'indentedBlock', 'originalTextFor', 'ungroup', 'infixNotation','locatedExpr', 'withClass',
+'CloseMatch', 'tokenMap', 'pyparsing_common',
+]
+
+system_version = tuple(sys.version_info)[:3]
+PY_3 = system_version[0] == 3
+if PY_3:
+    _MAX_INT = sys.maxsize
+    basestring = str
+    unichr = chr
+    _ustr = str
+
+    # build list of single arg builtins, that can be used as parse actions
+    singleArgBuiltins = [sum, len, sorted, reversed, list, tuple, set, any, all, min, max]
+
+else:
+    _MAX_INT = sys.maxint
+    range = xrange
+
+    def _ustr(obj):
+        """Drop-in replacement for str(obj) that tries to be Unicode friendly. It first tries
+           str(obj). If that fails with a UnicodeEncodeError, then it tries unicode(obj). It
+           then < returns the unicode object | encodes it with the default encoding | ... >.
+        """
+        if isinstance(obj,unicode):
+            return obj
+
+        try:
+            # If this works, then _ustr(obj) has the same behaviour as str(obj), so
+            # it won't break any existing code.
+            return str(obj)
+
+        except UnicodeEncodeError:
+            # Else encode it
+            ret = unicode(obj).encode(sys.getdefaultencoding(), 'xmlcharrefreplace')
+            xmlcharref = Regex(r'&#\d+;')
+            xmlcharref.setParseAction(lambda t: '\\u' + hex(int(t[0][2:-1]))[2:])
+            return xmlcharref.transformString(ret)
+
+    # build list of single arg builtins, tolerant of Python version, that can be used as parse actions
+    singleArgBuiltins = []
+    import __builtin__
+    for fname in "sum len sorted reversed list tuple set any all min max".split():
+        try:
+            singleArgBuiltins.append(getattr(__builtin__,fname))
+        except AttributeError:
+            continue
+            
+_generatorType = type((y for y in range(1)))
+ 
+def _xml_escape(data):
+    """Escape &, <, >, ", ', etc. in a string of data."""
+
+    # ampersand must be replaced first
+    from_symbols = '&><"\''
+    to_symbols = ('&'+s+';' for s in "amp gt lt quot apos".split())
+    for from_,to_ in zip(from_symbols, to_symbols):
+        data = data.replace(from_, to_)
+    return data
+
+class _Constants(object):
+    pass
+
+alphas     = string.ascii_uppercase + string.ascii_lowercase
+nums       = "0123456789"
+hexnums    = nums + "ABCDEFabcdef"
+alphanums  = alphas + nums
+_bslash    = chr(92)
+printables = "".join(c for c in string.printable if c not in string.whitespace)
+
+class ParseBaseException(Exception):
+    """base exception class for all parsing runtime exceptions"""
+    # Performance tuning: we construct a *lot* of these, so keep this
+    # constructor as small and fast as possible
+    def __init__( self, pstr, loc=0, msg=None, elem=None ):
+        self.loc = loc
+        if msg is None:
+            self.msg = pstr
+            self.pstr = ""
+        else:
+            self.msg = msg
+            self.pstr = pstr
+        self.parserElement = elem
+        self.args = (pstr, loc, msg)
+
+    @classmethod
+    def _from_exception(cls, pe):
+        """
+        internal factory method to simplify creating one type of ParseException 
+        from another - avoids having __init__ signature conflicts among subclasses
+        """
+        return cls(pe.pstr, pe.loc, pe.msg, pe.parserElement)
+
+    def __getattr__( self, aname ):
+        """supported attributes by name are:
+            - lineno - returns the line number of the exception text
+            - col - returns the column number of the exception text
+            - line - returns the line containing the exception text
+        """
+        if( aname == "lineno" ):
+            return lineno( self.loc, self.pstr )
+        elif( aname in ("col", "column") ):
+            return col( self.loc, self.pstr )
+        elif( aname == "line" ):
+            return line( self.loc, self.pstr )
+        else:
+            raise AttributeError(aname)
+
+    def __str__( self ):
+        return "%s (at char %d), (line:%d, col:%d)" % \
+                ( self.msg, self.loc, self.lineno, self.column )
+    def __repr__( self ):
+        return _ustr(self)
+    def markInputline( self, markerString = ">!<" ):
+        """Extracts the exception line from the input string, and marks
+           the location of the exception with a special symbol.
+        """
+        line_str = self.line
+        line_column = self.column - 1
+        if markerString:
+            line_str = "".join((line_str[:line_column],
+                                markerString, line_str[line_column:]))
+        return line_str.strip()
+    def __dir__(self):
+        return "lineno col line".split() + dir(type(self))
+
+class ParseException(ParseBaseException):
+    """
+    Exception thrown when parse expressions don't match class;
+    supported attributes by name are:
+     - lineno - returns the line number of the exception text
+     - col - returns the column number of the exception text
+     - line - returns the line containing the exception text
+        
+    Example::
+        try:
+            Word(nums).setName("integer").parseString("ABC")
+        except ParseException as pe:
+            print(pe)
+            print("column: {}".format(pe.col))
+            
+    prints::
+       Expected integer (at char 0), (line:1, col:1)
+        column: 1
+    """
+    pass
+
+class ParseFatalException(ParseBaseException):
+    """user-throwable exception thrown when inconsistent parse content
+       is found; stops all parsing immediately"""
+    pass
+
+class ParseSyntaxException(ParseFatalException):
+    """just like L{ParseFatalException}, but thrown internally when an
+       L{ErrorStop} ('-' operator) indicates that parsing is to stop 
+       immediately because an unbacktrackable syntax error has been found"""
+    pass
+
+#~ class ReparseException(ParseBaseException):
+    #~ """Experimental class - parse actions can raise this exception to cause
+       #~ pyparsing to reparse the input string:
+        #~ - with a modified input string, and/or
+        #~ - with a modified start location
+       #~ Set the values of the ReparseException in the constructor, and raise the
+       #~ exception in a parse action to cause pyparsing to use the new string/location.
+       #~ Setting the values as None causes no change to be made.
+       #~ """
+    #~ def __init_( self, newstring, restartLoc ):
+        #~ self.newParseText = newstring
+        #~ self.reparseLoc = restartLoc
+
+class RecursiveGrammarException(Exception):
+    """exception thrown by L{ParserElement.validate} if the grammar could be improperly recursive"""
+    def __init__( self, parseElementList ):
+        self.parseElementTrace = parseElementList
+
+    def __str__( self ):
+        return "RecursiveGrammarException: %s" % self.parseElementTrace
+
+class _ParseResultsWithOffset(object):
+    def __init__(self,p1,p2):
+        self.tup = (p1,p2)
+    def __getitem__(self,i):
+        return self.tup[i]
+    def __repr__(self):
+        return repr(self.tup[0])
+    def setOffset(self,i):
+        self.tup = (self.tup[0],i)
+
+class ParseResults(object):
+    """
+    Structured parse results, to provide multiple means of access to the parsed data:
+       - as a list (C{len(results)})
+       - by list index (C{results[0], results[1]}, etc.)
+       - by attribute (C{results.} - see L{ParserElement.setResultsName})
+
+    Example::
+        integer = Word(nums)
+        date_str = (integer.setResultsName("year") + '/' 
+                        + integer.setResultsName("month") + '/' 
+                        + integer.setResultsName("day"))
+        # equivalent form:
+        # date_str = integer("year") + '/' + integer("month") + '/' + integer("day")
+
+        # parseString returns a ParseResults object
+        result = date_str.parseString("1999/12/31")
+
+        def test(s, fn=repr):
+            print("%s -> %s" % (s, fn(eval(s))))
+        test("list(result)")
+        test("result[0]")
+        test("result['month']")
+        test("result.day")
+        test("'month' in result")
+        test("'minutes' in result")
+        test("result.dump()", str)
+    prints::
+        list(result) -> ['1999', '/', '12', '/', '31']
+        result[0] -> '1999'
+        result['month'] -> '12'
+        result.day -> '31'
+        'month' in result -> True
+        'minutes' in result -> False
+        result.dump() -> ['1999', '/', '12', '/', '31']
+        - day: 31
+        - month: 12
+        - year: 1999
+    """
+    def __new__(cls, toklist=None, name=None, asList=True, modal=True ):
+        if isinstance(toklist, cls):
+            return toklist
+        retobj = object.__new__(cls)
+        retobj.__doinit = True
+        return retobj
+
+    # Performance tuning: we construct a *lot* of these, so keep this
+    # constructor as small and fast as possible
+    def __init__( self, toklist=None, name=None, asList=True, modal=True, isinstance=isinstance ):
+        if self.__doinit:
+            self.__doinit = False
+            self.__name = None
+            self.__parent = None
+            self.__accumNames = {}
+            self.__asList = asList
+            self.__modal = modal
+            if toklist is None:
+                toklist = []
+            if isinstance(toklist, list):
+                self.__toklist = toklist[:]
+            elif isinstance(toklist, _generatorType):
+                self.__toklist = list(toklist)
+            else:
+                self.__toklist = [toklist]
+            self.__tokdict = dict()
+
+        if name is not None and name:
+            if not modal:
+                self.__accumNames[name] = 0
+            if isinstance(name,int):
+                name = _ustr(name) # will always return a str, but use _ustr for consistency
+            self.__name = name
+            if not (isinstance(toklist, (type(None), basestring, list)) and toklist in (None,'',[])):
+                if isinstance(toklist,basestring):
+                    toklist = [ toklist ]
+                if asList:
+                    if isinstance(toklist,ParseResults):
+                        self[name] = _ParseResultsWithOffset(toklist.copy(),0)
+                    else:
+                        self[name] = _ParseResultsWithOffset(ParseResults(toklist[0]),0)
+                    self[name].__name = name
+                else:
+                    try:
+                        self[name] = toklist[0]
+                    except (KeyError,TypeError,IndexError):
+                        self[name] = toklist
+
+    def __getitem__( self, i ):
+        if isinstance( i, (int,slice) ):
+            return self.__toklist[i]
+        else:
+            if i not in self.__accumNames:
+                return self.__tokdict[i][-1][0]
+            else:
+                return ParseResults([ v[0] for v in self.__tokdict[i] ])
+
+    def __setitem__( self, k, v, isinstance=isinstance ):
+        if isinstance(v,_ParseResultsWithOffset):
+            self.__tokdict[k] = self.__tokdict.get(k,list()) + [v]
+            sub = v[0]
+        elif isinstance(k,(int,slice)):
+            self.__toklist[k] = v
+            sub = v
+        else:
+            self.__tokdict[k] = self.__tokdict.get(k,list()) + [_ParseResultsWithOffset(v,0)]
+            sub = v
+        if isinstance(sub,ParseResults):
+            sub.__parent = wkref(self)
+
+    def __delitem__( self, i ):
+        if isinstance(i,(int,slice)):
+            mylen = len( self.__toklist )
+            del self.__toklist[i]
+
+            # convert int to slice
+            if isinstance(i, int):
+                if i < 0:
+                    i += mylen
+                i = slice(i, i+1)
+            # get removed indices
+            removed = list(range(*i.indices(mylen)))
+            removed.reverse()
+            # fixup indices in token dictionary
+            for name,occurrences in self.__tokdict.items():
+                for j in removed:
+                    for k, (value, position) in enumerate(occurrences):
+                        occurrences[k] = _ParseResultsWithOffset(value, position - (position > j))
+        else:
+            del self.__tokdict[i]
+
+    def __contains__( self, k ):
+        return k in self.__tokdict
+
+    def __len__( self ): return len( self.__toklist )
+    def __bool__(self): return ( not not self.__toklist )
+    __nonzero__ = __bool__
+    def __iter__( self ): return iter( self.__toklist )
+    def __reversed__( self ): return iter( self.__toklist[::-1] )
+    def _iterkeys( self ):
+        if hasattr(self.__tokdict, "iterkeys"):
+            return self.__tokdict.iterkeys()
+        else:
+            return iter(self.__tokdict)
+
+    def _itervalues( self ):
+        return (self[k] for k in self._iterkeys())
+            
+    def _iteritems( self ):
+        return ((k, self[k]) for k in self._iterkeys())
+
+    if PY_3:
+        keys = _iterkeys       
+        """Returns an iterator of all named result keys (Python 3.x only)."""
+
+        values = _itervalues
+        """Returns an iterator of all named result values (Python 3.x only)."""
+
+        items = _iteritems
+        """Returns an iterator of all named result key-value tuples (Python 3.x only)."""
+
+    else:
+        iterkeys = _iterkeys
+        """Returns an iterator of all named result keys (Python 2.x only)."""
+
+        itervalues = _itervalues
+        """Returns an iterator of all named result values (Python 2.x only)."""
+
+        iteritems = _iteritems
+        """Returns an iterator of all named result key-value tuples (Python 2.x only)."""
+
+        def keys( self ):
+            """Returns all named result keys (as a list in Python 2.x, as an iterator in Python 3.x)."""
+            return list(self.iterkeys())
+
+        def values( self ):
+            """Returns all named result values (as a list in Python 2.x, as an iterator in Python 3.x)."""
+            return list(self.itervalues())
+                
+        def items( self ):
+            """Returns all named result key-values (as a list of tuples in Python 2.x, as an iterator in Python 3.x)."""
+            return list(self.iteritems())
+
+    def haskeys( self ):
+        """Since keys() returns an iterator, this method is helpful in bypassing
+           code that looks for the existence of any defined results names."""
+        return bool(self.__tokdict)
+        
+    def pop( self, *args, **kwargs):
+        """
+        Removes and returns item at specified index (default=C{last}).
+        Supports both C{list} and C{dict} semantics for C{pop()}. If passed no
+        argument or an integer argument, it will use C{list} semantics
+        and pop tokens from the list of parsed tokens. If passed a 
+        non-integer argument (most likely a string), it will use C{dict}
+        semantics and pop the corresponding value from any defined 
+        results names. A second default return value argument is 
+        supported, just as in C{dict.pop()}.
+
+        Example::
+            def remove_first(tokens):
+                tokens.pop(0)
+            print(OneOrMore(Word(nums)).parseString("0 123 321")) # -> ['0', '123', '321']
+            print(OneOrMore(Word(nums)).addParseAction(remove_first).parseString("0 123 321")) # -> ['123', '321']
+
+            label = Word(alphas)
+            patt = label("LABEL") + OneOrMore(Word(nums))
+            print(patt.parseString("AAB 123 321").dump())
+
+            # Use pop() in a parse action to remove named result (note that corresponding value is not
+            # removed from list form of results)
+            def remove_LABEL(tokens):
+                tokens.pop("LABEL")
+                return tokens
+            patt.addParseAction(remove_LABEL)
+            print(patt.parseString("AAB 123 321").dump())
+        prints::
+            ['AAB', '123', '321']
+            - LABEL: AAB
+
+            ['AAB', '123', '321']
+        """
+        if not args:
+            args = [-1]
+        for k,v in kwargs.items():
+            if k == 'default':
+                args = (args[0], v)
+            else:
+                raise TypeError("pop() got an unexpected keyword argument '%s'" % k)
+        if (isinstance(args[0], int) or 
+                        len(args) == 1 or 
+                        args[0] in self):
+            index = args[0]
+            ret = self[index]
+            del self[index]
+            return ret
+        else:
+            defaultvalue = args[1]
+            return defaultvalue
+
+    def get(self, key, defaultValue=None):
+        """
+        Returns named result matching the given key, or if there is no
+        such name, then returns the given C{defaultValue} or C{None} if no
+        C{defaultValue} is specified.
+
+        Similar to C{dict.get()}.
+        
+        Example::
+            integer = Word(nums)
+            date_str = integer("year") + '/' + integer("month") + '/' + integer("day")           
+
+            result = date_str.parseString("1999/12/31")
+            print(result.get("year")) # -> '1999'
+            print(result.get("hour", "not specified")) # -> 'not specified'
+            print(result.get("hour")) # -> None
+        """
+        if key in self:
+            return self[key]
+        else:
+            return defaultValue
+
+    def insert( self, index, insStr ):
+        """
+        Inserts new element at location index in the list of parsed tokens.
+        
+        Similar to C{list.insert()}.
+
+        Example::
+            print(OneOrMore(Word(nums)).parseString("0 123 321")) # -> ['0', '123', '321']
+
+            # use a parse action to insert the parse location in the front of the parsed results
+            def insert_locn(locn, tokens):
+                tokens.insert(0, locn)
+            print(OneOrMore(Word(nums)).addParseAction(insert_locn).parseString("0 123 321")) # -> [0, '0', '123', '321']
+        """
+        self.__toklist.insert(index, insStr)
+        # fixup indices in token dictionary
+        for name,occurrences in self.__tokdict.items():
+            for k, (value, position) in enumerate(occurrences):
+                occurrences[k] = _ParseResultsWithOffset(value, position + (position > index))
+
+    def append( self, item ):
+        """
+        Add single element to end of ParseResults list of elements.
+
+        Example::
+            print(OneOrMore(Word(nums)).parseString("0 123 321")) # -> ['0', '123', '321']
+            
+            # use a parse action to compute the sum of the parsed integers, and add it to the end
+            def append_sum(tokens):
+                tokens.append(sum(map(int, tokens)))
+            print(OneOrMore(Word(nums)).addParseAction(append_sum).parseString("0 123 321")) # -> ['0', '123', '321', 444]
+        """
+        self.__toklist.append(item)
+
+    def extend( self, itemseq ):
+        """
+        Add sequence of elements to end of ParseResults list of elements.
+
+        Example::
+            patt = OneOrMore(Word(alphas))
+            
+            # use a parse action to append the reverse of the matched strings, to make a palindrome
+            def make_palindrome(tokens):
+                tokens.extend(reversed([t[::-1] for t in tokens]))
+                return ''.join(tokens)
+            print(patt.addParseAction(make_palindrome).parseString("lskdj sdlkjf lksd")) # -> 'lskdjsdlkjflksddsklfjkldsjdksl'
+        """
+        if isinstance(itemseq, ParseResults):
+            self += itemseq
+        else:
+            self.__toklist.extend(itemseq)
+
+    def clear( self ):
+        """
+        Clear all elements and results names.
+        """
+        del self.__toklist[:]
+        self.__tokdict.clear()
+
+    def __getattr__( self, name ):
+        try:
+            return self[name]
+        except KeyError:
+            return ""
+            
+        if name in self.__tokdict:
+            if name not in self.__accumNames:
+                return self.__tokdict[name][-1][0]
+            else:
+                return ParseResults([ v[0] for v in self.__tokdict[name] ])
+        else:
+            return ""
+
+    def __add__( self, other ):
+        ret = self.copy()
+        ret += other
+        return ret
+
+    def __iadd__( self, other ):
+        if other.__tokdict:
+            offset = len(self.__toklist)
+            addoffset = lambda a: offset if a<0 else a+offset
+            otheritems = other.__tokdict.items()
+            otherdictitems = [(k, _ParseResultsWithOffset(v[0],addoffset(v[1])) )
+                                for (k,vlist) in otheritems for v in vlist]
+            for k,v in otherdictitems:
+                self[k] = v
+                if isinstance(v[0],ParseResults):
+                    v[0].__parent = wkref(self)
+            
+        self.__toklist += other.__toklist
+        self.__accumNames.update( other.__accumNames )
+        return self
+
+    def __radd__(self, other):
+        if isinstance(other,int) and other == 0:
+            # useful for merging many ParseResults using sum() builtin
+            return self.copy()
+        else:
+            # this may raise a TypeError - so be it
+            return other + self
+        
+    def __repr__( self ):
+        return "(%s, %s)" % ( repr( self.__toklist ), repr( self.__tokdict ) )
+
+    def __str__( self ):
+        return '[' + ', '.join(_ustr(i) if isinstance(i, ParseResults) else repr(i) for i in self.__toklist) + ']'
+
+    def _asStringList( self, sep='' ):
+        out = []
+        for item in self.__toklist:
+            if out and sep:
+                out.append(sep)
+            if isinstance( item, ParseResults ):
+                out += item._asStringList()
+            else:
+                out.append( _ustr(item) )
+        return out
+
+    def asList( self ):
+        """
+        Returns the parse results as a nested list of matching tokens, all converted to strings.
+
+        Example::
+            patt = OneOrMore(Word(alphas))
+            result = patt.parseString("sldkj lsdkj sldkj")
+            # even though the result prints in string-like form, it is actually a pyparsing ParseResults
+            print(type(result), result) # ->  ['sldkj', 'lsdkj', 'sldkj']
+            
+            # Use asList() to create an actual list
+            result_list = result.asList()
+            print(type(result_list), result_list) # ->  ['sldkj', 'lsdkj', 'sldkj']
+        """
+        return [res.asList() if isinstance(res,ParseResults) else res for res in self.__toklist]
+
+    def asDict( self ):
+        """
+        Returns the named parse results as a nested dictionary.
+
+        Example::
+            integer = Word(nums)
+            date_str = integer("year") + '/' + integer("month") + '/' + integer("day")
+            
+            result = date_str.parseString('12/31/1999')
+            print(type(result), repr(result)) # ->  (['12', '/', '31', '/', '1999'], {'day': [('1999', 4)], 'year': [('12', 0)], 'month': [('31', 2)]})
+            
+            result_dict = result.asDict()
+            print(type(result_dict), repr(result_dict)) # ->  {'day': '1999', 'year': '12', 'month': '31'}
+
+            # even though a ParseResults supports dict-like access, sometime you just need to have a dict
+            import json
+            print(json.dumps(result)) # -> Exception: TypeError: ... is not JSON serializable
+            print(json.dumps(result.asDict())) # -> {"month": "31", "day": "1999", "year": "12"}
+        """
+        if PY_3:
+            item_fn = self.items
+        else:
+            item_fn = self.iteritems
+            
+        def toItem(obj):
+            if isinstance(obj, ParseResults):
+                if obj.haskeys():
+                    return obj.asDict()
+                else:
+                    return [toItem(v) for v in obj]
+            else:
+                return obj
+                
+        return dict((k,toItem(v)) for k,v in item_fn())
+
+    def copy( self ):
+        """
+        Returns a new copy of a C{ParseResults} object.
+        """
+        ret = ParseResults( self.__toklist )
+        ret.__tokdict = self.__tokdict.copy()
+        ret.__parent = self.__parent
+        ret.__accumNames.update( self.__accumNames )
+        ret.__name = self.__name
+        return ret
+
+    def asXML( self, doctag=None, namedItemsOnly=False, indent="", formatted=True ):
+        """
+        (Deprecated) Returns the parse results as XML. Tags are created for tokens and lists that have defined results names.
+        """
+        nl = "\n"
+        out = []
+        namedItems = dict((v[1],k) for (k,vlist) in self.__tokdict.items()
+                                                            for v in vlist)
+        nextLevelIndent = indent + "  "
+
+        # collapse out indents if formatting is not desired
+        if not formatted:
+            indent = ""
+            nextLevelIndent = ""
+            nl = ""
+
+        selfTag = None
+        if doctag is not None:
+            selfTag = doctag
+        else:
+            if self.__name:
+                selfTag = self.__name
+
+        if not selfTag:
+            if namedItemsOnly:
+                return ""
+            else:
+                selfTag = "ITEM"
+
+        out += [ nl, indent, "<", selfTag, ">" ]
+
+        for i,res in enumerate(self.__toklist):
+            if isinstance(res,ParseResults):
+                if i in namedItems:
+                    out += [ res.asXML(namedItems[i],
+                                        namedItemsOnly and doctag is None,
+                                        nextLevelIndent,
+                                        formatted)]
+                else:
+                    out += [ res.asXML(None,
+                                        namedItemsOnly and doctag is None,
+                                        nextLevelIndent,
+                                        formatted)]
+            else:
+                # individual token, see if there is a name for it
+                resTag = None
+                if i in namedItems:
+                    resTag = namedItems[i]
+                if not resTag:
+                    if namedItemsOnly:
+                        continue
+                    else:
+                        resTag = "ITEM"
+                xmlBodyText = _xml_escape(_ustr(res))
+                out += [ nl, nextLevelIndent, "<", resTag, ">",
+                                                xmlBodyText,
+                                                "" ]
+
+        out += [ nl, indent, "" ]
+        return "".join(out)
+
+    def __lookup(self,sub):
+        for k,vlist in self.__tokdict.items():
+            for v,loc in vlist:
+                if sub is v:
+                    return k
+        return None
+
+    def getName(self):
+        r"""
+        Returns the results name for this token expression. Useful when several 
+        different expressions might match at a particular location.
+
+        Example::
+            integer = Word(nums)
+            ssn_expr = Regex(r"\d\d\d-\d\d-\d\d\d\d")
+            house_number_expr = Suppress('#') + Word(nums, alphanums)
+            user_data = (Group(house_number_expr)("house_number") 
+                        | Group(ssn_expr)("ssn")
+                        | Group(integer)("age"))
+            user_info = OneOrMore(user_data)
+            
+            result = user_info.parseString("22 111-22-3333 #221B")
+            for item in result:
+                print(item.getName(), ':', item[0])
+        prints::
+            age : 22
+            ssn : 111-22-3333
+            house_number : 221B
+        """
+        if self.__name:
+            return self.__name
+        elif self.__parent:
+            par = self.__parent()
+            if par:
+                return par.__lookup(self)
+            else:
+                return None
+        elif (len(self) == 1 and
+               len(self.__tokdict) == 1 and
+               next(iter(self.__tokdict.values()))[0][1] in (0,-1)):
+            return next(iter(self.__tokdict.keys()))
+        else:
+            return None
+
+    def dump(self, indent='', depth=0, full=True):
+        """
+        Diagnostic method for listing out the contents of a C{ParseResults}.
+        Accepts an optional C{indent} argument so that this string can be embedded
+        in a nested display of other data.
+
+        Example::
+            integer = Word(nums)
+            date_str = integer("year") + '/' + integer("month") + '/' + integer("day")
+            
+            result = date_str.parseString('12/31/1999')
+            print(result.dump())
+        prints::
+            ['12', '/', '31', '/', '1999']
+            - day: 1999
+            - month: 31
+            - year: 12
+        """
+        out = []
+        NL = '\n'
+        out.append( indent+_ustr(self.asList()) )
+        if full:
+            if self.haskeys():
+                items = sorted((str(k), v) for k,v in self.items())
+                for k,v in items:
+                    if out:
+                        out.append(NL)
+                    out.append( "%s%s- %s: " % (indent,('  '*depth), k) )
+                    if isinstance(v,ParseResults):
+                        if v:
+                            out.append( v.dump(indent,depth+1) )
+                        else:
+                            out.append(_ustr(v))
+                    else:
+                        out.append(repr(v))
+            elif any(isinstance(vv,ParseResults) for vv in self):
+                v = self
+                for i,vv in enumerate(v):
+                    if isinstance(vv,ParseResults):
+                        out.append("\n%s%s[%d]:\n%s%s%s" % (indent,('  '*(depth)),i,indent,('  '*(depth+1)),vv.dump(indent,depth+1) ))
+                    else:
+                        out.append("\n%s%s[%d]:\n%s%s%s" % (indent,('  '*(depth)),i,indent,('  '*(depth+1)),_ustr(vv)))
+            
+        return "".join(out)
+
+    def pprint(self, *args, **kwargs):
+        """
+        Pretty-printer for parsed results as a list, using the C{pprint} module.
+        Accepts additional positional or keyword args as defined for the 
+        C{pprint.pprint} method. (U{http://docs.python.org/3/library/pprint.html#pprint.pprint})
+
+        Example::
+            ident = Word(alphas, alphanums)
+            num = Word(nums)
+            func = Forward()
+            term = ident | num | Group('(' + func + ')')
+            func <<= ident + Group(Optional(delimitedList(term)))
+            result = func.parseString("fna a,b,(fnb c,d,200),100")
+            result.pprint(width=40)
+        prints::
+            ['fna',
+             ['a',
+              'b',
+              ['(', 'fnb', ['c', 'd', '200'], ')'],
+              '100']]
+        """
+        pprint.pprint(self.asList(), *args, **kwargs)
+
+    # add support for pickle protocol
+    def __getstate__(self):
+        return ( self.__toklist,
+                 ( self.__tokdict.copy(),
+                   self.__parent is not None and self.__parent() or None,
+                   self.__accumNames,
+                   self.__name ) )
+
+    def __setstate__(self,state):
+        self.__toklist = state[0]
+        (self.__tokdict,
+         par,
+         inAccumNames,
+         self.__name) = state[1]
+        self.__accumNames = {}
+        self.__accumNames.update(inAccumNames)
+        if par is not None:
+            self.__parent = wkref(par)
+        else:
+            self.__parent = None
+
+    def __getnewargs__(self):
+        return self.__toklist, self.__name, self.__asList, self.__modal
+
+    def __dir__(self):
+        return (dir(type(self)) + list(self.keys()))
+
+MutableMapping.register(ParseResults)
+
+def col (loc,strg):
+    """Returns current column within a string, counting newlines as line separators.
+   The first column is number 1.
+
+   Note: the default parsing behavior is to expand tabs in the input string
+   before starting the parsing process.  See L{I{ParserElement.parseString}} for more information
+   on parsing strings containing C{}s, and suggested methods to maintain a
+   consistent view of the parsed string, the parse location, and line and column
+   positions within the parsed string.
+   """
+    s = strg
+    return 1 if 0} for more information
+   on parsing strings containing C{}s, and suggested methods to maintain a
+   consistent view of the parsed string, the parse location, and line and column
+   positions within the parsed string.
+   """
+    return strg.count("\n",0,loc) + 1
+
+def line( loc, strg ):
+    """Returns the line of text containing loc within a string, counting newlines as line separators.
+       """
+    lastCR = strg.rfind("\n", 0, loc)
+    nextCR = strg.find("\n", loc)
+    if nextCR >= 0:
+        return strg[lastCR+1:nextCR]
+    else:
+        return strg[lastCR+1:]
+
+def _defaultStartDebugAction( instring, loc, expr ):
+    print (("Match " + _ustr(expr) + " at loc " + _ustr(loc) + "(%d,%d)" % ( lineno(loc,instring), col(loc,instring) )))
+
+def _defaultSuccessDebugAction( instring, startloc, endloc, expr, toks ):
+    print ("Matched " + _ustr(expr) + " -> " + str(toks.asList()))
+
+def _defaultExceptionDebugAction( instring, loc, expr, exc ):
+    print ("Exception raised:" + _ustr(exc))
+
+def nullDebugAction(*args):
+    """'Do-nothing' debug action, to suppress debugging output during parsing."""
+    pass
+
+# Only works on Python 3.x - nonlocal is toxic to Python 2 installs
+#~ 'decorator to trim function calls to match the arity of the target'
+#~ def _trim_arity(func, maxargs=3):
+    #~ if func in singleArgBuiltins:
+        #~ return lambda s,l,t: func(t)
+    #~ limit = 0
+    #~ foundArity = False
+    #~ def wrapper(*args):
+        #~ nonlocal limit,foundArity
+        #~ while 1:
+            #~ try:
+                #~ ret = func(*args[limit:])
+                #~ foundArity = True
+                #~ return ret
+            #~ except TypeError:
+                #~ if limit == maxargs or foundArity:
+                    #~ raise
+                #~ limit += 1
+                #~ continue
+    #~ return wrapper
+
+# this version is Python 2.x-3.x cross-compatible
+'decorator to trim function calls to match the arity of the target'
+def _trim_arity(func, maxargs=2):
+    if func in singleArgBuiltins:
+        return lambda s,l,t: func(t)
+    limit = [0]
+    foundArity = [False]
+    
+    # traceback return data structure changed in Py3.5 - normalize back to plain tuples
+    if system_version[:2] >= (3,5):
+        def extract_stack(limit=0):
+            # special handling for Python 3.5.0 - extra deep call stack by 1
+            offset = -3 if system_version == (3,5,0) else -2
+            frame_summary = traceback.extract_stack(limit=-offset+limit-1)[offset]
+            return [frame_summary[:2]]
+        def extract_tb(tb, limit=0):
+            frames = traceback.extract_tb(tb, limit=limit)
+            frame_summary = frames[-1]
+            return [frame_summary[:2]]
+    else:
+        extract_stack = traceback.extract_stack
+        extract_tb = traceback.extract_tb
+    
+    # synthesize what would be returned by traceback.extract_stack at the call to 
+    # user's parse action 'func', so that we don't incur call penalty at parse time
+    
+    LINE_DIFF = 6
+    # IF ANY CODE CHANGES, EVEN JUST COMMENTS OR BLANK LINES, BETWEEN THE NEXT LINE AND 
+    # THE CALL TO FUNC INSIDE WRAPPER, LINE_DIFF MUST BE MODIFIED!!!!
+    this_line = extract_stack(limit=2)[-1]
+    pa_call_line_synth = (this_line[0], this_line[1]+LINE_DIFF)
+
+    def wrapper(*args):
+        while 1:
+            try:
+                ret = func(*args[limit[0]:])
+                foundArity[0] = True
+                return ret
+            except TypeError:
+                # re-raise TypeErrors if they did not come from our arity testing
+                if foundArity[0]:
+                    raise
+                else:
+                    try:
+                        tb = sys.exc_info()[-1]
+                        if not extract_tb(tb, limit=2)[-1][:2] == pa_call_line_synth:
+                            raise
+                    finally:
+                        del tb
+
+                if limit[0] <= maxargs:
+                    limit[0] += 1
+                    continue
+                raise
+
+    # copy func name to wrapper for sensible debug output
+    func_name = ""
+    try:
+        func_name = getattr(func, '__name__', 
+                            getattr(func, '__class__').__name__)
+    except Exception:
+        func_name = str(func)
+    wrapper.__name__ = func_name
+
+    return wrapper
+
+class ParserElement(object):
+    """Abstract base level parser element class."""
+    DEFAULT_WHITE_CHARS = " \n\t\r"
+    verbose_stacktrace = False
+
+    @staticmethod
+    def setDefaultWhitespaceChars( chars ):
+        r"""
+        Overrides the default whitespace chars
+
+        Example::
+            # default whitespace chars are space,  and newline
+            OneOrMore(Word(alphas)).parseString("abc def\nghi jkl")  # -> ['abc', 'def', 'ghi', 'jkl']
+            
+            # change to just treat newline as significant
+            ParserElement.setDefaultWhitespaceChars(" \t")
+            OneOrMore(Word(alphas)).parseString("abc def\nghi jkl")  # -> ['abc', 'def']
+        """
+        ParserElement.DEFAULT_WHITE_CHARS = chars
+
+    @staticmethod
+    def inlineLiteralsUsing(cls):
+        """
+        Set class to be used for inclusion of string literals into a parser.
+        
+        Example::
+            # default literal class used is Literal
+            integer = Word(nums)
+            date_str = integer("year") + '/' + integer("month") + '/' + integer("day")           
+
+            date_str.parseString("1999/12/31")  # -> ['1999', '/', '12', '/', '31']
+
+
+            # change to Suppress
+            ParserElement.inlineLiteralsUsing(Suppress)
+            date_str = integer("year") + '/' + integer("month") + '/' + integer("day")           
+
+            date_str.parseString("1999/12/31")  # -> ['1999', '12', '31']
+        """
+        ParserElement._literalStringClass = cls
+
+    def __init__( self, savelist=False ):
+        self.parseAction = list()
+        self.failAction = None
+        #~ self.name = ""  # don't define self.name, let subclasses try/except upcall
+        self.strRepr = None
+        self.resultsName = None
+        self.saveAsList = savelist
+        self.skipWhitespace = True
+        self.whiteChars = ParserElement.DEFAULT_WHITE_CHARS
+        self.copyDefaultWhiteChars = True
+        self.mayReturnEmpty = False # used when checking for left-recursion
+        self.keepTabs = False
+        self.ignoreExprs = list()
+        self.debug = False
+        self.streamlined = False
+        self.mayIndexError = True # used to optimize exception handling for subclasses that don't advance parse index
+        self.errmsg = ""
+        self.modalResults = True # used to mark results names as modal (report only last) or cumulative (list all)
+        self.debugActions = ( None, None, None ) #custom debug actions
+        self.re = None
+        self.callPreparse = True # used to avoid redundant calls to preParse
+        self.callDuringTry = False
+
+    def copy( self ):
+        """
+        Make a copy of this C{ParserElement}.  Useful for defining different parse actions
+        for the same parsing pattern, using copies of the original parse element.
+        
+        Example::
+            integer = Word(nums).setParseAction(lambda toks: int(toks[0]))
+            integerK = integer.copy().addParseAction(lambda toks: toks[0]*1024) + Suppress("K")
+            integerM = integer.copy().addParseAction(lambda toks: toks[0]*1024*1024) + Suppress("M")
+            
+            print(OneOrMore(integerK | integerM | integer).parseString("5K 100 640K 256M"))
+        prints::
+            [5120, 100, 655360, 268435456]
+        Equivalent form of C{expr.copy()} is just C{expr()}::
+            integerM = integer().addParseAction(lambda toks: toks[0]*1024*1024) + Suppress("M")
+        """
+        cpy = copy.copy( self )
+        cpy.parseAction = self.parseAction[:]
+        cpy.ignoreExprs = self.ignoreExprs[:]
+        if self.copyDefaultWhiteChars:
+            cpy.whiteChars = ParserElement.DEFAULT_WHITE_CHARS
+        return cpy
+
+    def setName( self, name ):
+        """
+        Define name for this expression, makes debugging and exception messages clearer.
+        
+        Example::
+            Word(nums).parseString("ABC")  # -> Exception: Expected W:(0123...) (at char 0), (line:1, col:1)
+            Word(nums).setName("integer").parseString("ABC")  # -> Exception: Expected integer (at char 0), (line:1, col:1)
+        """
+        self.name = name
+        self.errmsg = "Expected " + self.name
+        if hasattr(self,"exception"):
+            self.exception.msg = self.errmsg
+        return self
+
+    def setResultsName( self, name, listAllMatches=False ):
+        """
+        Define name for referencing matching tokens as a nested attribute
+        of the returned parse results.
+        NOTE: this returns a *copy* of the original C{ParserElement} object;
+        this is so that the client can define a basic element, such as an
+        integer, and reference it in multiple places with different names.
+
+        You can also set results names using the abbreviated syntax,
+        C{expr("name")} in place of C{expr.setResultsName("name")} - 
+        see L{I{__call__}<__call__>}.
+
+        Example::
+            date_str = (integer.setResultsName("year") + '/' 
+                        + integer.setResultsName("month") + '/' 
+                        + integer.setResultsName("day"))
+
+            # equivalent form:
+            date_str = integer("year") + '/' + integer("month") + '/' + integer("day")
+        """
+        newself = self.copy()
+        if name.endswith("*"):
+            name = name[:-1]
+            listAllMatches=True
+        newself.resultsName = name
+        newself.modalResults = not listAllMatches
+        return newself
+
+    def setBreak(self,breakFlag = True):
+        """Method to invoke the Python pdb debugger when this element is
+           about to be parsed. Set C{breakFlag} to True to enable, False to
+           disable.
+        """
+        if breakFlag:
+            _parseMethod = self._parse
+            def breaker(instring, loc, doActions=True, callPreParse=True):
+                import pdb
+                pdb.set_trace()
+                return _parseMethod( instring, loc, doActions, callPreParse )
+            breaker._originalParseMethod = _parseMethod
+            self._parse = breaker
+        else:
+            if hasattr(self._parse,"_originalParseMethod"):
+                self._parse = self._parse._originalParseMethod
+        return self
+
+    def setParseAction( self, *fns, **kwargs ):
+        """
+        Define one or more actions to perform when successfully matching parse element definition.
+        Parse action fn is a callable method with 0-3 arguments, called as C{fn(s,loc,toks)},
+        C{fn(loc,toks)}, C{fn(toks)}, or just C{fn()}, where:
+         - s   = the original string being parsed (see note below)
+         - loc = the location of the matching substring
+         - toks = a list of the matched tokens, packaged as a C{L{ParseResults}} object
+        If the functions in fns modify the tokens, they can return them as the return
+        value from fn, and the modified list of tokens will replace the original.
+        Otherwise, fn does not need to return any value.
+
+        Optional keyword arguments:
+         - callDuringTry = (default=C{False}) indicate if parse action should be run during lookaheads and alternate testing
+
+        Note: the default parsing behavior is to expand tabs in the input string
+        before starting the parsing process.  See L{I{parseString}} for more information
+        on parsing strings containing C{}s, and suggested methods to maintain a
+        consistent view of the parsed string, the parse location, and line and column
+        positions within the parsed string.
+        
+        Example::
+            integer = Word(nums)
+            date_str = integer + '/' + integer + '/' + integer
+
+            date_str.parseString("1999/12/31")  # -> ['1999', '/', '12', '/', '31']
+
+            # use parse action to convert to ints at parse time
+            integer = Word(nums).setParseAction(lambda toks: int(toks[0]))
+            date_str = integer + '/' + integer + '/' + integer
+
+            # note that integer fields are now ints, not strings
+            date_str.parseString("1999/12/31")  # -> [1999, '/', 12, '/', 31]
+        """
+        self.parseAction = list(map(_trim_arity, list(fns)))
+        self.callDuringTry = kwargs.get("callDuringTry", False)
+        return self
+
+    def addParseAction( self, *fns, **kwargs ):
+        """
+        Add one or more parse actions to expression's list of parse actions. See L{I{setParseAction}}.
+        
+        See examples in L{I{copy}}.
+        """
+        self.parseAction += list(map(_trim_arity, list(fns)))
+        self.callDuringTry = self.callDuringTry or kwargs.get("callDuringTry", False)
+        return self
+
+    def addCondition(self, *fns, **kwargs):
+        """Add a boolean predicate function to expression's list of parse actions. See 
+        L{I{setParseAction}} for function call signatures. Unlike C{setParseAction}, 
+        functions passed to C{addCondition} need to return boolean success/fail of the condition.
+
+        Optional keyword arguments:
+         - message = define a custom message to be used in the raised exception
+         - fatal   = if True, will raise ParseFatalException to stop parsing immediately; otherwise will raise ParseException
+         
+        Example::
+            integer = Word(nums).setParseAction(lambda toks: int(toks[0]))
+            year_int = integer.copy()
+            year_int.addCondition(lambda toks: toks[0] >= 2000, message="Only support years 2000 and later")
+            date_str = year_int + '/' + integer + '/' + integer
+
+            result = date_str.parseString("1999/12/31")  # -> Exception: Only support years 2000 and later (at char 0), (line:1, col:1)
+        """
+        msg = kwargs.get("message", "failed user-defined condition")
+        exc_type = ParseFatalException if kwargs.get("fatal", False) else ParseException
+        for fn in fns:
+            def pa(s,l,t):
+                if not bool(_trim_arity(fn)(s,l,t)):
+                    raise exc_type(s,l,msg)
+            self.parseAction.append(pa)
+        self.callDuringTry = self.callDuringTry or kwargs.get("callDuringTry", False)
+        return self
+
+    def setFailAction( self, fn ):
+        """Define action to perform if parsing fails at this expression.
+           Fail acton fn is a callable function that takes the arguments
+           C{fn(s,loc,expr,err)} where:
+            - s = string being parsed
+            - loc = location where expression match was attempted and failed
+            - expr = the parse expression that failed
+            - err = the exception thrown
+           The function returns no value.  It may throw C{L{ParseFatalException}}
+           if it is desired to stop parsing immediately."""
+        self.failAction = fn
+        return self
+
+    def _skipIgnorables( self, instring, loc ):
+        exprsFound = True
+        while exprsFound:
+            exprsFound = False
+            for e in self.ignoreExprs:
+                try:
+                    while 1:
+                        loc,dummy = e._parse( instring, loc )
+                        exprsFound = True
+                except ParseException:
+                    pass
+        return loc
+
+    def preParse( self, instring, loc ):
+        if self.ignoreExprs:
+            loc = self._skipIgnorables( instring, loc )
+
+        if self.skipWhitespace:
+            wt = self.whiteChars
+            instrlen = len(instring)
+            while loc < instrlen and instring[loc] in wt:
+                loc += 1
+
+        return loc
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        return loc, []
+
+    def postParse( self, instring, loc, tokenlist ):
+        return tokenlist
+
+    #~ @profile
+    def _parseNoCache( self, instring, loc, doActions=True, callPreParse=True ):
+        debugging = ( self.debug ) #and doActions )
+
+        if debugging or self.failAction:
+            #~ print ("Match",self,"at loc",loc,"(%d,%d)" % ( lineno(loc,instring), col(loc,instring) ))
+            if (self.debugActions[0] ):
+                self.debugActions[0]( instring, loc, self )
+            if callPreParse and self.callPreparse:
+                preloc = self.preParse( instring, loc )
+            else:
+                preloc = loc
+            tokensStart = preloc
+            try:
+                try:
+                    loc,tokens = self.parseImpl( instring, preloc, doActions )
+                except IndexError:
+                    raise ParseException( instring, len(instring), self.errmsg, self )
+            except ParseBaseException as err:
+                #~ print ("Exception raised:", err)
+                if self.debugActions[2]:
+                    self.debugActions[2]( instring, tokensStart, self, err )
+                if self.failAction:
+                    self.failAction( instring, tokensStart, self, err )
+                raise
+        else:
+            if callPreParse and self.callPreparse:
+                preloc = self.preParse( instring, loc )
+            else:
+                preloc = loc
+            tokensStart = preloc
+            if self.mayIndexError or preloc >= len(instring):
+                try:
+                    loc,tokens = self.parseImpl( instring, preloc, doActions )
+                except IndexError:
+                    raise ParseException( instring, len(instring), self.errmsg, self )
+            else:
+                loc,tokens = self.parseImpl( instring, preloc, doActions )
+
+        tokens = self.postParse( instring, loc, tokens )
+
+        retTokens = ParseResults( tokens, self.resultsName, asList=self.saveAsList, modal=self.modalResults )
+        if self.parseAction and (doActions or self.callDuringTry):
+            if debugging:
+                try:
+                    for fn in self.parseAction:
+                        tokens = fn( instring, tokensStart, retTokens )
+                        if tokens is not None:
+                            retTokens = ParseResults( tokens,
+                                                      self.resultsName,
+                                                      asList=self.saveAsList and isinstance(tokens,(ParseResults,list)),
+                                                      modal=self.modalResults )
+                except ParseBaseException as err:
+                    #~ print "Exception raised in user parse action:", err
+                    if (self.debugActions[2] ):
+                        self.debugActions[2]( instring, tokensStart, self, err )
+                    raise
+            else:
+                for fn in self.parseAction:
+                    tokens = fn( instring, tokensStart, retTokens )
+                    if tokens is not None:
+                        retTokens = ParseResults( tokens,
+                                                  self.resultsName,
+                                                  asList=self.saveAsList and isinstance(tokens,(ParseResults,list)),
+                                                  modal=self.modalResults )
+        if debugging:
+            #~ print ("Matched",self,"->",retTokens.asList())
+            if (self.debugActions[1] ):
+                self.debugActions[1]( instring, tokensStart, loc, self, retTokens )
+
+        return loc, retTokens
+
+    def tryParse( self, instring, loc ):
+        try:
+            return self._parse( instring, loc, doActions=False )[0]
+        except ParseFatalException:
+            raise ParseException( instring, loc, self.errmsg, self)
+    
+    def canParseNext(self, instring, loc):
+        try:
+            self.tryParse(instring, loc)
+        except (ParseException, IndexError):
+            return False
+        else:
+            return True
+
+    class _UnboundedCache(object):
+        def __init__(self):
+            cache = {}
+            self.not_in_cache = not_in_cache = object()
+
+            def get(self, key):
+                return cache.get(key, not_in_cache)
+
+            def set(self, key, value):
+                cache[key] = value
+
+            def clear(self):
+                cache.clear()
+                
+            def cache_len(self):
+                return len(cache)
+
+            self.get = types.MethodType(get, self)
+            self.set = types.MethodType(set, self)
+            self.clear = types.MethodType(clear, self)
+            self.__len__ = types.MethodType(cache_len, self)
+
+    if _OrderedDict is not None:
+        class _FifoCache(object):
+            def __init__(self, size):
+                self.not_in_cache = not_in_cache = object()
+
+                cache = _OrderedDict()
+
+                def get(self, key):
+                    return cache.get(key, not_in_cache)
+
+                def set(self, key, value):
+                    cache[key] = value
+                    while len(cache) > size:
+                        try:
+                            cache.popitem(False)
+                        except KeyError:
+                            pass
+
+                def clear(self):
+                    cache.clear()
+
+                def cache_len(self):
+                    return len(cache)
+
+                self.get = types.MethodType(get, self)
+                self.set = types.MethodType(set, self)
+                self.clear = types.MethodType(clear, self)
+                self.__len__ = types.MethodType(cache_len, self)
+
+    else:
+        class _FifoCache(object):
+            def __init__(self, size):
+                self.not_in_cache = not_in_cache = object()
+
+                cache = {}
+                key_fifo = collections.deque([], size)
+
+                def get(self, key):
+                    return cache.get(key, not_in_cache)
+
+                def set(self, key, value):
+                    cache[key] = value
+                    while len(key_fifo) > size:
+                        cache.pop(key_fifo.popleft(), None)
+                    key_fifo.append(key)
+
+                def clear(self):
+                    cache.clear()
+                    key_fifo.clear()
+
+                def cache_len(self):
+                    return len(cache)
+
+                self.get = types.MethodType(get, self)
+                self.set = types.MethodType(set, self)
+                self.clear = types.MethodType(clear, self)
+                self.__len__ = types.MethodType(cache_len, self)
+
+    # argument cache for optimizing repeated calls when backtracking through recursive expressions
+    packrat_cache = {} # this is set later by enabledPackrat(); this is here so that resetCache() doesn't fail
+    packrat_cache_lock = RLock()
+    packrat_cache_stats = [0, 0]
+
+    # this method gets repeatedly called during backtracking with the same arguments -
+    # we can cache these arguments and save ourselves the trouble of re-parsing the contained expression
+    def _parseCache( self, instring, loc, doActions=True, callPreParse=True ):
+        HIT, MISS = 0, 1
+        lookup = (self, instring, loc, callPreParse, doActions)
+        with ParserElement.packrat_cache_lock:
+            cache = ParserElement.packrat_cache
+            value = cache.get(lookup)
+            if value is cache.not_in_cache:
+                ParserElement.packrat_cache_stats[MISS] += 1
+                try:
+                    value = self._parseNoCache(instring, loc, doActions, callPreParse)
+                except ParseBaseException as pe:
+                    # cache a copy of the exception, without the traceback
+                    cache.set(lookup, pe.__class__(*pe.args))
+                    raise
+                else:
+                    cache.set(lookup, (value[0], value[1].copy()))
+                    return value
+            else:
+                ParserElement.packrat_cache_stats[HIT] += 1
+                if isinstance(value, Exception):
+                    raise value
+                return (value[0], value[1].copy())
+
+    _parse = _parseNoCache
+
+    @staticmethod
+    def resetCache():
+        ParserElement.packrat_cache.clear()
+        ParserElement.packrat_cache_stats[:] = [0] * len(ParserElement.packrat_cache_stats)
+
+    _packratEnabled = False
+    @staticmethod
+    def enablePackrat(cache_size_limit=128):
+        """Enables "packrat" parsing, which adds memoizing to the parsing logic.
+           Repeated parse attempts at the same string location (which happens
+           often in many complex grammars) can immediately return a cached value,
+           instead of re-executing parsing/validating code.  Memoizing is done of
+           both valid results and parsing exceptions.
+           
+           Parameters:
+            - cache_size_limit - (default=C{128}) - if an integer value is provided
+              will limit the size of the packrat cache; if None is passed, then
+              the cache size will be unbounded; if 0 is passed, the cache will
+              be effectively disabled.
+            
+           This speedup may break existing programs that use parse actions that
+           have side-effects.  For this reason, packrat parsing is disabled when
+           you first import pyparsing.  To activate the packrat feature, your
+           program must call the class method C{ParserElement.enablePackrat()}.  If
+           your program uses C{psyco} to "compile as you go", you must call
+           C{enablePackrat} before calling C{psyco.full()}.  If you do not do this,
+           Python will crash.  For best results, call C{enablePackrat()} immediately
+           after importing pyparsing.
+           
+           Example::
+               import pyparsing
+               pyparsing.ParserElement.enablePackrat()
+        """
+        if not ParserElement._packratEnabled:
+            ParserElement._packratEnabled = True
+            if cache_size_limit is None:
+                ParserElement.packrat_cache = ParserElement._UnboundedCache()
+            else:
+                ParserElement.packrat_cache = ParserElement._FifoCache(cache_size_limit)
+            ParserElement._parse = ParserElement._parseCache
+
+    def parseString( self, instring, parseAll=False ):
+        """
+        Execute the parse expression with the given string.
+        This is the main interface to the client code, once the complete
+        expression has been built.
+
+        If you want the grammar to require that the entire input string be
+        successfully parsed, then set C{parseAll} to True (equivalent to ending
+        the grammar with C{L{StringEnd()}}).
+
+        Note: C{parseString} implicitly calls C{expandtabs()} on the input string,
+        in order to report proper column numbers in parse actions.
+        If the input string contains tabs and
+        the grammar uses parse actions that use the C{loc} argument to index into the
+        string being parsed, you can ensure you have a consistent view of the input
+        string by:
+         - calling C{parseWithTabs} on your grammar before calling C{parseString}
+           (see L{I{parseWithTabs}})
+         - define your parse action using the full C{(s,loc,toks)} signature, and
+           reference the input string using the parse action's C{s} argument
+         - explictly expand the tabs in your input string before calling
+           C{parseString}
+        
+        Example::
+            Word('a').parseString('aaaaabaaa')  # -> ['aaaaa']
+            Word('a').parseString('aaaaabaaa', parseAll=True)  # -> Exception: Expected end of text
+        """
+        ParserElement.resetCache()
+        if not self.streamlined:
+            self.streamline()
+            #~ self.saveAsList = True
+        for e in self.ignoreExprs:
+            e.streamline()
+        if not self.keepTabs:
+            instring = instring.expandtabs()
+        try:
+            loc, tokens = self._parse( instring, 0 )
+            if parseAll:
+                loc = self.preParse( instring, loc )
+                se = Empty() + StringEnd()
+                se._parse( instring, loc )
+        except ParseBaseException as exc:
+            if ParserElement.verbose_stacktrace:
+                raise
+            else:
+                # catch and re-raise exception from here, clears out pyparsing internal stack trace
+                raise exc
+        else:
+            return tokens
+
+    def scanString( self, instring, maxMatches=_MAX_INT, overlap=False ):
+        """
+        Scan the input string for expression matches.  Each match will return the
+        matching tokens, start location, and end location.  May be called with optional
+        C{maxMatches} argument, to clip scanning after 'n' matches are found.  If
+        C{overlap} is specified, then overlapping matches will be reported.
+
+        Note that the start and end locations are reported relative to the string
+        being parsed.  See L{I{parseString}} for more information on parsing
+        strings with embedded tabs.
+
+        Example::
+            source = "sldjf123lsdjjkf345sldkjf879lkjsfd987"
+            print(source)
+            for tokens,start,end in Word(alphas).scanString(source):
+                print(' '*start + '^'*(end-start))
+                print(' '*start + tokens[0])
+        
+        prints::
+        
+            sldjf123lsdjjkf345sldkjf879lkjsfd987
+            ^^^^^
+            sldjf
+                    ^^^^^^^
+                    lsdjjkf
+                              ^^^^^^
+                              sldkjf
+                                       ^^^^^^
+                                       lkjsfd
+        """
+        if not self.streamlined:
+            self.streamline()
+        for e in self.ignoreExprs:
+            e.streamline()
+
+        if not self.keepTabs:
+            instring = _ustr(instring).expandtabs()
+        instrlen = len(instring)
+        loc = 0
+        preparseFn = self.preParse
+        parseFn = self._parse
+        ParserElement.resetCache()
+        matches = 0
+        try:
+            while loc <= instrlen and matches < maxMatches:
+                try:
+                    preloc = preparseFn( instring, loc )
+                    nextLoc,tokens = parseFn( instring, preloc, callPreParse=False )
+                except ParseException:
+                    loc = preloc+1
+                else:
+                    if nextLoc > loc:
+                        matches += 1
+                        yield tokens, preloc, nextLoc
+                        if overlap:
+                            nextloc = preparseFn( instring, loc )
+                            if nextloc > loc:
+                                loc = nextLoc
+                            else:
+                                loc += 1
+                        else:
+                            loc = nextLoc
+                    else:
+                        loc = preloc+1
+        except ParseBaseException as exc:
+            if ParserElement.verbose_stacktrace:
+                raise
+            else:
+                # catch and re-raise exception from here, clears out pyparsing internal stack trace
+                raise exc
+
+    def transformString( self, instring ):
+        """
+        Extension to C{L{scanString}}, to modify matching text with modified tokens that may
+        be returned from a parse action.  To use C{transformString}, define a grammar and
+        attach a parse action to it that modifies the returned token list.
+        Invoking C{transformString()} on a target string will then scan for matches,
+        and replace the matched text patterns according to the logic in the parse
+        action.  C{transformString()} returns the resulting transformed string.
+        
+        Example::
+            wd = Word(alphas)
+            wd.setParseAction(lambda toks: toks[0].title())
+            
+            print(wd.transformString("now is the winter of our discontent made glorious summer by this sun of york."))
+        Prints::
+            Now Is The Winter Of Our Discontent Made Glorious Summer By This Sun Of York.
+        """
+        out = []
+        lastE = 0
+        # force preservation of s, to minimize unwanted transformation of string, and to
+        # keep string locs straight between transformString and scanString
+        self.keepTabs = True
+        try:
+            for t,s,e in self.scanString( instring ):
+                out.append( instring[lastE:s] )
+                if t:
+                    if isinstance(t,ParseResults):
+                        out += t.asList()
+                    elif isinstance(t,list):
+                        out += t
+                    else:
+                        out.append(t)
+                lastE = e
+            out.append(instring[lastE:])
+            out = [o for o in out if o]
+            return "".join(map(_ustr,_flatten(out)))
+        except ParseBaseException as exc:
+            if ParserElement.verbose_stacktrace:
+                raise
+            else:
+                # catch and re-raise exception from here, clears out pyparsing internal stack trace
+                raise exc
+
+    def searchString( self, instring, maxMatches=_MAX_INT ):
+        """
+        Another extension to C{L{scanString}}, simplifying the access to the tokens found
+        to match the given parse expression.  May be called with optional
+        C{maxMatches} argument, to clip searching after 'n' matches are found.
+        
+        Example::
+            # a capitalized word starts with an uppercase letter, followed by zero or more lowercase letters
+            cap_word = Word(alphas.upper(), alphas.lower())
+            
+            print(cap_word.searchString("More than Iron, more than Lead, more than Gold I need Electricity"))
+
+            # the sum() builtin can be used to merge results into a single ParseResults object
+            print(sum(cap_word.searchString("More than Iron, more than Lead, more than Gold I need Electricity")))
+        prints::
+            [['More'], ['Iron'], ['Lead'], ['Gold'], ['I'], ['Electricity']]
+            ['More', 'Iron', 'Lead', 'Gold', 'I', 'Electricity']
+        """
+        try:
+            return ParseResults([ t for t,s,e in self.scanString( instring, maxMatches ) ])
+        except ParseBaseException as exc:
+            if ParserElement.verbose_stacktrace:
+                raise
+            else:
+                # catch and re-raise exception from here, clears out pyparsing internal stack trace
+                raise exc
+
+    def split(self, instring, maxsplit=_MAX_INT, includeSeparators=False):
+        """
+        Generator method to split a string using the given expression as a separator.
+        May be called with optional C{maxsplit} argument, to limit the number of splits;
+        and the optional C{includeSeparators} argument (default=C{False}), if the separating
+        matching text should be included in the split results.
+        
+        Example::        
+            punc = oneOf(list(".,;:/-!?"))
+            print(list(punc.split("This, this?, this sentence, is badly punctuated!")))
+        prints::
+            ['This', ' this', '', ' this sentence', ' is badly punctuated', '']
+        """
+        splits = 0
+        last = 0
+        for t,s,e in self.scanString(instring, maxMatches=maxsplit):
+            yield instring[last:s]
+            if includeSeparators:
+                yield t[0]
+            last = e
+        yield instring[last:]
+
+    def __add__(self, other ):
+        """
+        Implementation of + operator - returns C{L{And}}. Adding strings to a ParserElement
+        converts them to L{Literal}s by default.
+        
+        Example::
+            greet = Word(alphas) + "," + Word(alphas) + "!"
+            hello = "Hello, World!"
+            print (hello, "->", greet.parseString(hello))
+        Prints::
+            Hello, World! -> ['Hello', ',', 'World', '!']
+        """
+        if isinstance( other, basestring ):
+            other = ParserElement._literalStringClass( other )
+        if not isinstance( other, ParserElement ):
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+                    SyntaxWarning, stacklevel=2)
+            return None
+        return And( [ self, other ] )
+
+    def __radd__(self, other ):
+        """
+        Implementation of + operator when left operand is not a C{L{ParserElement}}
+        """
+        if isinstance( other, basestring ):
+            other = ParserElement._literalStringClass( other )
+        if not isinstance( other, ParserElement ):
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+                    SyntaxWarning, stacklevel=2)
+            return None
+        return other + self
+
+    def __sub__(self, other):
+        """
+        Implementation of - operator, returns C{L{And}} with error stop
+        """
+        if isinstance( other, basestring ):
+            other = ParserElement._literalStringClass( other )
+        if not isinstance( other, ParserElement ):
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+                    SyntaxWarning, stacklevel=2)
+            return None
+        return self + And._ErrorStop() + other
+
+    def __rsub__(self, other ):
+        """
+        Implementation of - operator when left operand is not a C{L{ParserElement}}
+        """
+        if isinstance( other, basestring ):
+            other = ParserElement._literalStringClass( other )
+        if not isinstance( other, ParserElement ):
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+                    SyntaxWarning, stacklevel=2)
+            return None
+        return other - self
+
+    def __mul__(self,other):
+        """
+        Implementation of * operator, allows use of C{expr * 3} in place of
+        C{expr + expr + expr}.  Expressions may also me multiplied by a 2-integer
+        tuple, similar to C{{min,max}} multipliers in regular expressions.  Tuples
+        may also include C{None} as in:
+         - C{expr*(n,None)} or C{expr*(n,)} is equivalent
+              to C{expr*n + L{ZeroOrMore}(expr)}
+              (read as "at least n instances of C{expr}")
+         - C{expr*(None,n)} is equivalent to C{expr*(0,n)}
+              (read as "0 to n instances of C{expr}")
+         - C{expr*(None,None)} is equivalent to C{L{ZeroOrMore}(expr)}
+         - C{expr*(1,None)} is equivalent to C{L{OneOrMore}(expr)}
+
+        Note that C{expr*(None,n)} does not raise an exception if
+        more than n exprs exist in the input stream; that is,
+        C{expr*(None,n)} does not enforce a maximum number of expr
+        occurrences.  If this behavior is desired, then write
+        C{expr*(None,n) + ~expr}
+        """
+        if isinstance(other,int):
+            minElements, optElements = other,0
+        elif isinstance(other,tuple):
+            other = (other + (None, None))[:2]
+            if other[0] is None:
+                other = (0, other[1])
+            if isinstance(other[0],int) and other[1] is None:
+                if other[0] == 0:
+                    return ZeroOrMore(self)
+                if other[0] == 1:
+                    return OneOrMore(self)
+                else:
+                    return self*other[0] + ZeroOrMore(self)
+            elif isinstance(other[0],int) and isinstance(other[1],int):
+                minElements, optElements = other
+                optElements -= minElements
+            else:
+                raise TypeError("cannot multiply 'ParserElement' and ('%s','%s') objects", type(other[0]),type(other[1]))
+        else:
+            raise TypeError("cannot multiply 'ParserElement' and '%s' objects", type(other))
+
+        if minElements < 0:
+            raise ValueError("cannot multiply ParserElement by negative value")
+        if optElements < 0:
+            raise ValueError("second tuple value must be greater or equal to first tuple value")
+        if minElements == optElements == 0:
+            raise ValueError("cannot multiply ParserElement by 0 or (0,0)")
+
+        if (optElements):
+            def makeOptionalList(n):
+                if n>1:
+                    return Optional(self + makeOptionalList(n-1))
+                else:
+                    return Optional(self)
+            if minElements:
+                if minElements == 1:
+                    ret = self + makeOptionalList(optElements)
+                else:
+                    ret = And([self]*minElements) + makeOptionalList(optElements)
+            else:
+                ret = makeOptionalList(optElements)
+        else:
+            if minElements == 1:
+                ret = self
+            else:
+                ret = And([self]*minElements)
+        return ret
+
+    def __rmul__(self, other):
+        return self.__mul__(other)
+
+    def __or__(self, other ):
+        """
+        Implementation of | operator - returns C{L{MatchFirst}}
+        """
+        if isinstance( other, basestring ):
+            other = ParserElement._literalStringClass( other )
+        if not isinstance( other, ParserElement ):
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+                    SyntaxWarning, stacklevel=2)
+            return None
+        return MatchFirst( [ self, other ] )
+
+    def __ror__(self, other ):
+        """
+        Implementation of | operator when left operand is not a C{L{ParserElement}}
+        """
+        if isinstance( other, basestring ):
+            other = ParserElement._literalStringClass( other )
+        if not isinstance( other, ParserElement ):
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+                    SyntaxWarning, stacklevel=2)
+            return None
+        return other | self
+
+    def __xor__(self, other ):
+        """
+        Implementation of ^ operator - returns C{L{Or}}
+        """
+        if isinstance( other, basestring ):
+            other = ParserElement._literalStringClass( other )
+        if not isinstance( other, ParserElement ):
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+                    SyntaxWarning, stacklevel=2)
+            return None
+        return Or( [ self, other ] )
+
+    def __rxor__(self, other ):
+        """
+        Implementation of ^ operator when left operand is not a C{L{ParserElement}}
+        """
+        if isinstance( other, basestring ):
+            other = ParserElement._literalStringClass( other )
+        if not isinstance( other, ParserElement ):
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+                    SyntaxWarning, stacklevel=2)
+            return None
+        return other ^ self
+
+    def __and__(self, other ):
+        """
+        Implementation of & operator - returns C{L{Each}}
+        """
+        if isinstance( other, basestring ):
+            other = ParserElement._literalStringClass( other )
+        if not isinstance( other, ParserElement ):
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+                    SyntaxWarning, stacklevel=2)
+            return None
+        return Each( [ self, other ] )
+
+    def __rand__(self, other ):
+        """
+        Implementation of & operator when left operand is not a C{L{ParserElement}}
+        """
+        if isinstance( other, basestring ):
+            other = ParserElement._literalStringClass( other )
+        if not isinstance( other, ParserElement ):
+            warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+                    SyntaxWarning, stacklevel=2)
+            return None
+        return other & self
+
+    def __invert__( self ):
+        """
+        Implementation of ~ operator - returns C{L{NotAny}}
+        """
+        return NotAny( self )
+
+    def __call__(self, name=None):
+        """
+        Shortcut for C{L{setResultsName}}, with C{listAllMatches=False}.
+        
+        If C{name} is given with a trailing C{'*'} character, then C{listAllMatches} will be
+        passed as C{True}.
+           
+        If C{name} is omitted, same as calling C{L{copy}}.
+
+        Example::
+            # these are equivalent
+            userdata = Word(alphas).setResultsName("name") + Word(nums+"-").setResultsName("socsecno")
+            userdata = Word(alphas)("name") + Word(nums+"-")("socsecno")             
+        """
+        if name is not None:
+            return self.setResultsName(name)
+        else:
+            return self.copy()
+
+    def suppress( self ):
+        """
+        Suppresses the output of this C{ParserElement}; useful to keep punctuation from
+        cluttering up returned output.
+        """
+        return Suppress( self )
+
+    def leaveWhitespace( self ):
+        """
+        Disables the skipping of whitespace before matching the characters in the
+        C{ParserElement}'s defined pattern.  This is normally only used internally by
+        the pyparsing module, but may be needed in some whitespace-sensitive grammars.
+        """
+        self.skipWhitespace = False
+        return self
+
+    def setWhitespaceChars( self, chars ):
+        """
+        Overrides the default whitespace chars
+        """
+        self.skipWhitespace = True
+        self.whiteChars = chars
+        self.copyDefaultWhiteChars = False
+        return self
+
+    def parseWithTabs( self ):
+        """
+        Overrides default behavior to expand C{}s to spaces before parsing the input string.
+        Must be called before C{parseString} when the input grammar contains elements that
+        match C{} characters.
+        """
+        self.keepTabs = True
+        return self
+
+    def ignore( self, other ):
+        """
+        Define expression to be ignored (e.g., comments) while doing pattern
+        matching; may be called repeatedly, to define multiple comment or other
+        ignorable patterns.
+        
+        Example::
+            patt = OneOrMore(Word(alphas))
+            patt.parseString('ablaj /* comment */ lskjd') # -> ['ablaj']
+            
+            patt.ignore(cStyleComment)
+            patt.parseString('ablaj /* comment */ lskjd') # -> ['ablaj', 'lskjd']
+        """
+        if isinstance(other, basestring):
+            other = Suppress(other)
+
+        if isinstance( other, Suppress ):
+            if other not in self.ignoreExprs:
+                self.ignoreExprs.append(other)
+        else:
+            self.ignoreExprs.append( Suppress( other.copy() ) )
+        return self
+
+    def setDebugActions( self, startAction, successAction, exceptionAction ):
+        """
+        Enable display of debugging messages while doing pattern matching.
+        """
+        self.debugActions = (startAction or _defaultStartDebugAction,
+                             successAction or _defaultSuccessDebugAction,
+                             exceptionAction or _defaultExceptionDebugAction)
+        self.debug = True
+        return self
+
+    def setDebug( self, flag=True ):
+        """
+        Enable display of debugging messages while doing pattern matching.
+        Set C{flag} to True to enable, False to disable.
+
+        Example::
+            wd = Word(alphas).setName("alphaword")
+            integer = Word(nums).setName("numword")
+            term = wd | integer
+            
+            # turn on debugging for wd
+            wd.setDebug()
+
+            OneOrMore(term).parseString("abc 123 xyz 890")
+        
+        prints::
+            Match alphaword at loc 0(1,1)
+            Matched alphaword -> ['abc']
+            Match alphaword at loc 3(1,4)
+            Exception raised:Expected alphaword (at char 4), (line:1, col:5)
+            Match alphaword at loc 7(1,8)
+            Matched alphaword -> ['xyz']
+            Match alphaword at loc 11(1,12)
+            Exception raised:Expected alphaword (at char 12), (line:1, col:13)
+            Match alphaword at loc 15(1,16)
+            Exception raised:Expected alphaword (at char 15), (line:1, col:16)
+
+        The output shown is that produced by the default debug actions - custom debug actions can be
+        specified using L{setDebugActions}. Prior to attempting
+        to match the C{wd} expression, the debugging message C{"Match  at loc (,)"}
+        is shown. Then if the parse succeeds, a C{"Matched"} message is shown, or an C{"Exception raised"}
+        message is shown. Also note the use of L{setName} to assign a human-readable name to the expression,
+        which makes debugging and exception messages easier to understand - for instance, the default
+        name created for the C{Word} expression without calling C{setName} is C{"W:(ABCD...)"}.
+        """
+        if flag:
+            self.setDebugActions( _defaultStartDebugAction, _defaultSuccessDebugAction, _defaultExceptionDebugAction )
+        else:
+            self.debug = False
+        return self
+
+    def __str__( self ):
+        return self.name
+
+    def __repr__( self ):
+        return _ustr(self)
+
+    def streamline( self ):
+        self.streamlined = True
+        self.strRepr = None
+        return self
+
+    def checkRecursion( self, parseElementList ):
+        pass
+
+    def validate( self, validateTrace=[] ):
+        """
+        Check defined expressions for valid structure, check for infinite recursive definitions.
+        """
+        self.checkRecursion( [] )
+
+    def parseFile( self, file_or_filename, parseAll=False ):
+        """
+        Execute the parse expression on the given file or filename.
+        If a filename is specified (instead of a file object),
+        the entire file is opened, read, and closed before parsing.
+        """
+        try:
+            file_contents = file_or_filename.read()
+        except AttributeError:
+            with open(file_or_filename, "r") as f:
+                file_contents = f.read()
+        try:
+            return self.parseString(file_contents, parseAll)
+        except ParseBaseException as exc:
+            if ParserElement.verbose_stacktrace:
+                raise
+            else:
+                # catch and re-raise exception from here, clears out pyparsing internal stack trace
+                raise exc
+
+    def __eq__(self,other):
+        if isinstance(other, ParserElement):
+            return self is other or vars(self) == vars(other)
+        elif isinstance(other, basestring):
+            return self.matches(other)
+        else:
+            return super(ParserElement,self)==other
+
+    def __ne__(self,other):
+        return not (self == other)
+
+    def __hash__(self):
+        return hash(id(self))
+
+    def __req__(self,other):
+        return self == other
+
+    def __rne__(self,other):
+        return not (self == other)
+
+    def matches(self, testString, parseAll=True):
+        """
+        Method for quick testing of a parser against a test string. Good for simple 
+        inline microtests of sub expressions while building up larger parser.
+           
+        Parameters:
+         - testString - to test against this expression for a match
+         - parseAll - (default=C{True}) - flag to pass to C{L{parseString}} when running tests
+            
+        Example::
+            expr = Word(nums)
+            assert expr.matches("100")
+        """
+        try:
+            self.parseString(_ustr(testString), parseAll=parseAll)
+            return True
+        except ParseBaseException:
+            return False
+                
+    def runTests(self, tests, parseAll=True, comment='#', fullDump=True, printResults=True, failureTests=False):
+        """
+        Execute the parse expression on a series of test strings, showing each
+        test, the parsed results or where the parse failed. Quick and easy way to
+        run a parse expression against a list of sample strings.
+           
+        Parameters:
+         - tests - a list of separate test strings, or a multiline string of test strings
+         - parseAll - (default=C{True}) - flag to pass to C{L{parseString}} when running tests           
+         - comment - (default=C{'#'}) - expression for indicating embedded comments in the test 
+              string; pass None to disable comment filtering
+         - fullDump - (default=C{True}) - dump results as list followed by results names in nested outline;
+              if False, only dump nested list
+         - printResults - (default=C{True}) prints test output to stdout
+         - failureTests - (default=C{False}) indicates if these tests are expected to fail parsing
+
+        Returns: a (success, results) tuple, where success indicates that all tests succeeded
+        (or failed if C{failureTests} is True), and the results contain a list of lines of each 
+        test's output
+        
+        Example::
+            number_expr = pyparsing_common.number.copy()
+
+            result = number_expr.runTests('''
+                # unsigned integer
+                100
+                # negative integer
+                -100
+                # float with scientific notation
+                6.02e23
+                # integer with scientific notation
+                1e-12
+                ''')
+            print("Success" if result[0] else "Failed!")
+
+            result = number_expr.runTests('''
+                # stray character
+                100Z
+                # missing leading digit before '.'
+                -.100
+                # too many '.'
+                3.14.159
+                ''', failureTests=True)
+            print("Success" if result[0] else "Failed!")
+        prints::
+            # unsigned integer
+            100
+            [100]
+
+            # negative integer
+            -100
+            [-100]
+
+            # float with scientific notation
+            6.02e23
+            [6.02e+23]
+
+            # integer with scientific notation
+            1e-12
+            [1e-12]
+
+            Success
+            
+            # stray character
+            100Z
+               ^
+            FAIL: Expected end of text (at char 3), (line:1, col:4)
+
+            # missing leading digit before '.'
+            -.100
+            ^
+            FAIL: Expected {real number with scientific notation | real number | signed integer} (at char 0), (line:1, col:1)
+
+            # too many '.'
+            3.14.159
+                ^
+            FAIL: Expected end of text (at char 4), (line:1, col:5)
+
+            Success
+
+        Each test string must be on a single line. If you want to test a string that spans multiple
+        lines, create a test like this::
+
+            expr.runTest(r"this is a test\\n of strings that spans \\n 3 lines")
+        
+        (Note that this is a raw string literal, you must include the leading 'r'.)
+        """
+        if isinstance(tests, basestring):
+            tests = list(map(str.strip, tests.rstrip().splitlines()))
+        if isinstance(comment, basestring):
+            comment = Literal(comment)
+        allResults = []
+        comments = []
+        success = True
+        for t in tests:
+            if comment is not None and comment.matches(t, False) or comments and not t:
+                comments.append(t)
+                continue
+            if not t:
+                continue
+            out = ['\n'.join(comments), t]
+            comments = []
+            try:
+                t = t.replace(r'\n','\n')
+                result = self.parseString(t, parseAll=parseAll)
+                out.append(result.dump(full=fullDump))
+                success = success and not failureTests
+            except ParseBaseException as pe:
+                fatal = "(FATAL)" if isinstance(pe, ParseFatalException) else ""
+                if '\n' in t:
+                    out.append(line(pe.loc, t))
+                    out.append(' '*(col(pe.loc,t)-1) + '^' + fatal)
+                else:
+                    out.append(' '*pe.loc + '^' + fatal)
+                out.append("FAIL: " + str(pe))
+                success = success and failureTests
+                result = pe
+            except Exception as exc:
+                out.append("FAIL-EXCEPTION: " + str(exc))
+                success = success and failureTests
+                result = exc
+
+            if printResults:
+                if fullDump:
+                    out.append('')
+                print('\n'.join(out))
+
+            allResults.append((t, result))
+        
+        return success, allResults
+
+        
+class Token(ParserElement):
+    """
+    Abstract C{ParserElement} subclass, for defining atomic matching patterns.
+    """
+    def __init__( self ):
+        super(Token,self).__init__( savelist=False )
+
+
+class Empty(Token):
+    """
+    An empty token, will always match.
+    """
+    def __init__( self ):
+        super(Empty,self).__init__()
+        self.name = "Empty"
+        self.mayReturnEmpty = True
+        self.mayIndexError = False
+
+
+class NoMatch(Token):
+    """
+    A token that will never match.
+    """
+    def __init__( self ):
+        super(NoMatch,self).__init__()
+        self.name = "NoMatch"
+        self.mayReturnEmpty = True
+        self.mayIndexError = False
+        self.errmsg = "Unmatchable token"
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        raise ParseException(instring, loc, self.errmsg, self)
+
+
+class Literal(Token):
+    """
+    Token to exactly match a specified string.
+    
+    Example::
+        Literal('blah').parseString('blah')  # -> ['blah']
+        Literal('blah').parseString('blahfooblah')  # -> ['blah']
+        Literal('blah').parseString('bla')  # -> Exception: Expected "blah"
+    
+    For case-insensitive matching, use L{CaselessLiteral}.
+    
+    For keyword matching (force word break before and after the matched string),
+    use L{Keyword} or L{CaselessKeyword}.
+    """
+    def __init__( self, matchString ):
+        super(Literal,self).__init__()
+        self.match = matchString
+        self.matchLen = len(matchString)
+        try:
+            self.firstMatchChar = matchString[0]
+        except IndexError:
+            warnings.warn("null string passed to Literal; use Empty() instead",
+                            SyntaxWarning, stacklevel=2)
+            self.__class__ = Empty
+        self.name = '"%s"' % _ustr(self.match)
+        self.errmsg = "Expected " + self.name
+        self.mayReturnEmpty = False
+        self.mayIndexError = False
+
+    # Performance tuning: this routine gets called a *lot*
+    # if this is a single character match string  and the first character matches,
+    # short-circuit as quickly as possible, and avoid calling startswith
+    #~ @profile
+    def parseImpl( self, instring, loc, doActions=True ):
+        if (instring[loc] == self.firstMatchChar and
+            (self.matchLen==1 or instring.startswith(self.match,loc)) ):
+            return loc+self.matchLen, self.match
+        raise ParseException(instring, loc, self.errmsg, self)
+_L = Literal
+ParserElement._literalStringClass = Literal
+
+class Keyword(Token):
+    """
+    Token to exactly match a specified string as a keyword, that is, it must be
+    immediately followed by a non-keyword character.  Compare with C{L{Literal}}:
+     - C{Literal("if")} will match the leading C{'if'} in C{'ifAndOnlyIf'}.
+     - C{Keyword("if")} will not; it will only match the leading C{'if'} in C{'if x=1'}, or C{'if(y==2)'}
+    Accepts two optional constructor arguments in addition to the keyword string:
+     - C{identChars} is a string of characters that would be valid identifier characters,
+          defaulting to all alphanumerics + "_" and "$"
+     - C{caseless} allows case-insensitive matching, default is C{False}.
+       
+    Example::
+        Keyword("start").parseString("start")  # -> ['start']
+        Keyword("start").parseString("starting")  # -> Exception
+
+    For case-insensitive matching, use L{CaselessKeyword}.
+    """
+    DEFAULT_KEYWORD_CHARS = alphanums+"_$"
+
+    def __init__( self, matchString, identChars=None, caseless=False ):
+        super(Keyword,self).__init__()
+        if identChars is None:
+            identChars = Keyword.DEFAULT_KEYWORD_CHARS
+        self.match = matchString
+        self.matchLen = len(matchString)
+        try:
+            self.firstMatchChar = matchString[0]
+        except IndexError:
+            warnings.warn("null string passed to Keyword; use Empty() instead",
+                            SyntaxWarning, stacklevel=2)
+        self.name = '"%s"' % self.match
+        self.errmsg = "Expected " + self.name
+        self.mayReturnEmpty = False
+        self.mayIndexError = False
+        self.caseless = caseless
+        if caseless:
+            self.caselessmatch = matchString.upper()
+            identChars = identChars.upper()
+        self.identChars = set(identChars)
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if self.caseless:
+            if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and
+                 (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) and
+                 (loc == 0 or instring[loc-1].upper() not in self.identChars) ):
+                return loc+self.matchLen, self.match
+        else:
+            if (instring[loc] == self.firstMatchChar and
+                (self.matchLen==1 or instring.startswith(self.match,loc)) and
+                (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen] not in self.identChars) and
+                (loc == 0 or instring[loc-1] not in self.identChars) ):
+                return loc+self.matchLen, self.match
+        raise ParseException(instring, loc, self.errmsg, self)
+
+    def copy(self):
+        c = super(Keyword,self).copy()
+        c.identChars = Keyword.DEFAULT_KEYWORD_CHARS
+        return c
+
+    @staticmethod
+    def setDefaultKeywordChars( chars ):
+        """Overrides the default Keyword chars
+        """
+        Keyword.DEFAULT_KEYWORD_CHARS = chars
+
+class CaselessLiteral(Literal):
+    """
+    Token to match a specified string, ignoring case of letters.
+    Note: the matched results will always be in the case of the given
+    match string, NOT the case of the input text.
+
+    Example::
+        OneOrMore(CaselessLiteral("CMD")).parseString("cmd CMD Cmd10") # -> ['CMD', 'CMD', 'CMD']
+        
+    (Contrast with example for L{CaselessKeyword}.)
+    """
+    def __init__( self, matchString ):
+        super(CaselessLiteral,self).__init__( matchString.upper() )
+        # Preserve the defining literal.
+        self.returnString = matchString
+        self.name = "'%s'" % self.returnString
+        self.errmsg = "Expected " + self.name
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if instring[ loc:loc+self.matchLen ].upper() == self.match:
+            return loc+self.matchLen, self.returnString
+        raise ParseException(instring, loc, self.errmsg, self)
+
+class CaselessKeyword(Keyword):
+    """
+    Caseless version of L{Keyword}.
+
+    Example::
+        OneOrMore(CaselessKeyword("CMD")).parseString("cmd CMD Cmd10") # -> ['CMD', 'CMD']
+        
+    (Contrast with example for L{CaselessLiteral}.)
+    """
+    def __init__( self, matchString, identChars=None ):
+        super(CaselessKeyword,self).__init__( matchString, identChars, caseless=True )
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and
+             (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) ):
+            return loc+self.matchLen, self.match
+        raise ParseException(instring, loc, self.errmsg, self)
+
+class CloseMatch(Token):
+    """
+    A variation on L{Literal} which matches "close" matches, that is, 
+    strings with at most 'n' mismatching characters. C{CloseMatch} takes parameters:
+     - C{match_string} - string to be matched
+     - C{maxMismatches} - (C{default=1}) maximum number of mismatches allowed to count as a match
+    
+    The results from a successful parse will contain the matched text from the input string and the following named results:
+     - C{mismatches} - a list of the positions within the match_string where mismatches were found
+     - C{original} - the original match_string used to compare against the input string
+    
+    If C{mismatches} is an empty list, then the match was an exact match.
+    
+    Example::
+        patt = CloseMatch("ATCATCGAATGGA")
+        patt.parseString("ATCATCGAAXGGA") # -> (['ATCATCGAAXGGA'], {'mismatches': [[9]], 'original': ['ATCATCGAATGGA']})
+        patt.parseString("ATCAXCGAAXGGA") # -> Exception: Expected 'ATCATCGAATGGA' (with up to 1 mismatches) (at char 0), (line:1, col:1)
+
+        # exact match
+        patt.parseString("ATCATCGAATGGA") # -> (['ATCATCGAATGGA'], {'mismatches': [[]], 'original': ['ATCATCGAATGGA']})
+
+        # close match allowing up to 2 mismatches
+        patt = CloseMatch("ATCATCGAATGGA", maxMismatches=2)
+        patt.parseString("ATCAXCGAAXGGA") # -> (['ATCAXCGAAXGGA'], {'mismatches': [[4, 9]], 'original': ['ATCATCGAATGGA']})
+    """
+    def __init__(self, match_string, maxMismatches=1):
+        super(CloseMatch,self).__init__()
+        self.name = match_string
+        self.match_string = match_string
+        self.maxMismatches = maxMismatches
+        self.errmsg = "Expected %r (with up to %d mismatches)" % (self.match_string, self.maxMismatches)
+        self.mayIndexError = False
+        self.mayReturnEmpty = False
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        start = loc
+        instrlen = len(instring)
+        maxloc = start + len(self.match_string)
+
+        if maxloc <= instrlen:
+            match_string = self.match_string
+            match_stringloc = 0
+            mismatches = []
+            maxMismatches = self.maxMismatches
+
+            for match_stringloc,s_m in enumerate(zip(instring[loc:maxloc], self.match_string)):
+                src,mat = s_m
+                if src != mat:
+                    mismatches.append(match_stringloc)
+                    if len(mismatches) > maxMismatches:
+                        break
+            else:
+                loc = match_stringloc + 1
+                results = ParseResults([instring[start:loc]])
+                results['original'] = self.match_string
+                results['mismatches'] = mismatches
+                return loc, results
+
+        raise ParseException(instring, loc, self.errmsg, self)
+
+
+class Word(Token):
+    """
+    Token for matching words composed of allowed character sets.
+    Defined with string containing all allowed initial characters,
+    an optional string containing allowed body characters (if omitted,
+    defaults to the initial character set), and an optional minimum,
+    maximum, and/or exact length.  The default value for C{min} is 1 (a
+    minimum value < 1 is not valid); the default values for C{max} and C{exact}
+    are 0, meaning no maximum or exact length restriction. An optional
+    C{excludeChars} parameter can list characters that might be found in 
+    the input C{bodyChars} string; useful to define a word of all printables
+    except for one or two characters, for instance.
+    
+    L{srange} is useful for defining custom character set strings for defining 
+    C{Word} expressions, using range notation from regular expression character sets.
+    
+    A common mistake is to use C{Word} to match a specific literal string, as in 
+    C{Word("Address")}. Remember that C{Word} uses the string argument to define
+    I{sets} of matchable characters. This expression would match "Add", "AAA",
+    "dAred", or any other word made up of the characters 'A', 'd', 'r', 'e', and 's'.
+    To match an exact literal string, use L{Literal} or L{Keyword}.
+
+    pyparsing includes helper strings for building Words:
+     - L{alphas}
+     - L{nums}
+     - L{alphanums}
+     - L{hexnums}
+     - L{alphas8bit} (alphabetic characters in ASCII range 128-255 - accented, tilded, umlauted, etc.)
+     - L{punc8bit} (non-alphabetic characters in ASCII range 128-255 - currency, symbols, superscripts, diacriticals, etc.)
+     - L{printables} (any non-whitespace character)
+
+    Example::
+        # a word composed of digits
+        integer = Word(nums) # equivalent to Word("0123456789") or Word(srange("0-9"))
+        
+        # a word with a leading capital, and zero or more lowercase
+        capital_word = Word(alphas.upper(), alphas.lower())
+
+        # hostnames are alphanumeric, with leading alpha, and '-'
+        hostname = Word(alphas, alphanums+'-')
+        
+        # roman numeral (not a strict parser, accepts invalid mix of characters)
+        roman = Word("IVXLCDM")
+        
+        # any string of non-whitespace characters, except for ','
+        csv_value = Word(printables, excludeChars=",")
+    """
+    def __init__( self, initChars, bodyChars=None, min=1, max=0, exact=0, asKeyword=False, excludeChars=None ):
+        super(Word,self).__init__()
+        if excludeChars:
+            initChars = ''.join(c for c in initChars if c not in excludeChars)
+            if bodyChars:
+                bodyChars = ''.join(c for c in bodyChars if c not in excludeChars)
+        self.initCharsOrig = initChars
+        self.initChars = set(initChars)
+        if bodyChars :
+            self.bodyCharsOrig = bodyChars
+            self.bodyChars = set(bodyChars)
+        else:
+            self.bodyCharsOrig = initChars
+            self.bodyChars = set(initChars)
+
+        self.maxSpecified = max > 0
+
+        if min < 1:
+            raise ValueError("cannot specify a minimum length < 1; use Optional(Word()) if zero-length word is permitted")
+
+        self.minLen = min
+
+        if max > 0:
+            self.maxLen = max
+        else:
+            self.maxLen = _MAX_INT
+
+        if exact > 0:
+            self.maxLen = exact
+            self.minLen = exact
+
+        self.name = _ustr(self)
+        self.errmsg = "Expected " + self.name
+        self.mayIndexError = False
+        self.asKeyword = asKeyword
+
+        if ' ' not in self.initCharsOrig+self.bodyCharsOrig and (min==1 and max==0 and exact==0):
+            if self.bodyCharsOrig == self.initCharsOrig:
+                self.reString = "[%s]+" % _escapeRegexRangeChars(self.initCharsOrig)
+            elif len(self.initCharsOrig) == 1:
+                self.reString = "%s[%s]*" % \
+                                      (re.escape(self.initCharsOrig),
+                                      _escapeRegexRangeChars(self.bodyCharsOrig),)
+            else:
+                self.reString = "[%s][%s]*" % \
+                                      (_escapeRegexRangeChars(self.initCharsOrig),
+                                      _escapeRegexRangeChars(self.bodyCharsOrig),)
+            if self.asKeyword:
+                self.reString = r"\b"+self.reString+r"\b"
+            try:
+                self.re = re.compile( self.reString )
+            except Exception:
+                self.re = None
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if self.re:
+            result = self.re.match(instring,loc)
+            if not result:
+                raise ParseException(instring, loc, self.errmsg, self)
+
+            loc = result.end()
+            return loc, result.group()
+
+        if not(instring[ loc ] in self.initChars):
+            raise ParseException(instring, loc, self.errmsg, self)
+
+        start = loc
+        loc += 1
+        instrlen = len(instring)
+        bodychars = self.bodyChars
+        maxloc = start + self.maxLen
+        maxloc = min( maxloc, instrlen )
+        while loc < maxloc and instring[loc] in bodychars:
+            loc += 1
+
+        throwException = False
+        if loc - start < self.minLen:
+            throwException = True
+        if self.maxSpecified and loc < instrlen and instring[loc] in bodychars:
+            throwException = True
+        if self.asKeyword:
+            if (start>0 and instring[start-1] in bodychars) or (loc4:
+                    return s[:4]+"..."
+                else:
+                    return s
+
+            if ( self.initCharsOrig != self.bodyCharsOrig ):
+                self.strRepr = "W:(%s,%s)" % ( charsAsStr(self.initCharsOrig), charsAsStr(self.bodyCharsOrig) )
+            else:
+                self.strRepr = "W:(%s)" % charsAsStr(self.initCharsOrig)
+
+        return self.strRepr
+
+
+class Regex(Token):
+    r"""
+    Token for matching strings that match a given regular expression.
+    Defined with string specifying the regular expression in a form recognized by the inbuilt Python re module.
+    If the given regex contains named groups (defined using C{(?P...)}), these will be preserved as 
+    named parse results.
+
+    Example::
+        realnum = Regex(r"[+-]?\d+\.\d*")
+        date = Regex(r'(?P\d{4})-(?P\d\d?)-(?P\d\d?)')
+        # ref: http://stackoverflow.com/questions/267399/how-do-you-match-only-valid-roman-numerals-with-a-regular-expression
+        roman = Regex(r"M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})")
+    """
+    compiledREtype = type(re.compile("[A-Z]"))
+    def __init__( self, pattern, flags=0):
+        """The parameters C{pattern} and C{flags} are passed to the C{re.compile()} function as-is. See the Python C{re} module for an explanation of the acceptable patterns and flags."""
+        super(Regex,self).__init__()
+
+        if isinstance(pattern, basestring):
+            if not pattern:
+                warnings.warn("null string passed to Regex; use Empty() instead",
+                        SyntaxWarning, stacklevel=2)
+
+            self.pattern = pattern
+            self.flags = flags
+
+            try:
+                self.re = re.compile(self.pattern, self.flags)
+                self.reString = self.pattern
+            except sre_constants.error:
+                warnings.warn("invalid pattern (%s) passed to Regex" % pattern,
+                    SyntaxWarning, stacklevel=2)
+                raise
+
+        elif isinstance(pattern, Regex.compiledREtype):
+            self.re = pattern
+            self.pattern = \
+            self.reString = str(pattern)
+            self.flags = flags
+            
+        else:
+            raise ValueError("Regex may only be constructed with a string or a compiled RE object")
+
+        self.name = _ustr(self)
+        self.errmsg = "Expected " + self.name
+        self.mayIndexError = False
+        self.mayReturnEmpty = True
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        result = self.re.match(instring,loc)
+        if not result:
+            raise ParseException(instring, loc, self.errmsg, self)
+
+        loc = result.end()
+        d = result.groupdict()
+        ret = ParseResults(result.group())
+        if d:
+            for k in d:
+                ret[k] = d[k]
+        return loc,ret
+
+    def __str__( self ):
+        try:
+            return super(Regex,self).__str__()
+        except Exception:
+            pass
+
+        if self.strRepr is None:
+            self.strRepr = "Re:(%s)" % repr(self.pattern)
+
+        return self.strRepr
+
+
+class QuotedString(Token):
+    r"""
+    Token for matching strings that are delimited by quoting characters.
+    
+    Defined with the following parameters:
+        - quoteChar - string of one or more characters defining the quote delimiting string
+        - escChar - character to escape quotes, typically backslash (default=C{None})
+        - escQuote - special quote sequence to escape an embedded quote string (such as SQL's "" to escape an embedded ") (default=C{None})
+        - multiline - boolean indicating whether quotes can span multiple lines (default=C{False})
+        - unquoteResults - boolean indicating whether the matched text should be unquoted (default=C{True})
+        - endQuoteChar - string of one or more characters defining the end of the quote delimited string (default=C{None} => same as quoteChar)
+        - convertWhitespaceEscapes - convert escaped whitespace (C{'\t'}, C{'\n'}, etc.) to actual whitespace (default=C{True})
+
+    Example::
+        qs = QuotedString('"')
+        print(qs.searchString('lsjdf "This is the quote" sldjf'))
+        complex_qs = QuotedString('{{', endQuoteChar='}}')
+        print(complex_qs.searchString('lsjdf {{This is the "quote"}} sldjf'))
+        sql_qs = QuotedString('"', escQuote='""')
+        print(sql_qs.searchString('lsjdf "This is the quote with ""embedded"" quotes" sldjf'))
+    prints::
+        [['This is the quote']]
+        [['This is the "quote"']]
+        [['This is the quote with "embedded" quotes']]
+    """
+    def __init__( self, quoteChar, escChar=None, escQuote=None, multiline=False, unquoteResults=True, endQuoteChar=None, convertWhitespaceEscapes=True):
+        super(QuotedString,self).__init__()
+
+        # remove white space from quote chars - wont work anyway
+        quoteChar = quoteChar.strip()
+        if not quoteChar:
+            warnings.warn("quoteChar cannot be the empty string",SyntaxWarning,stacklevel=2)
+            raise SyntaxError()
+
+        if endQuoteChar is None:
+            endQuoteChar = quoteChar
+        else:
+            endQuoteChar = endQuoteChar.strip()
+            if not endQuoteChar:
+                warnings.warn("endQuoteChar cannot be the empty string",SyntaxWarning,stacklevel=2)
+                raise SyntaxError()
+
+        self.quoteChar = quoteChar
+        self.quoteCharLen = len(quoteChar)
+        self.firstQuoteChar = quoteChar[0]
+        self.endQuoteChar = endQuoteChar
+        self.endQuoteCharLen = len(endQuoteChar)
+        self.escChar = escChar
+        self.escQuote = escQuote
+        self.unquoteResults = unquoteResults
+        self.convertWhitespaceEscapes = convertWhitespaceEscapes
+
+        if multiline:
+            self.flags = re.MULTILINE | re.DOTALL
+            self.pattern = r'%s(?:[^%s%s]' % \
+                ( re.escape(self.quoteChar),
+                  _escapeRegexRangeChars(self.endQuoteChar[0]),
+                  (escChar is not None and _escapeRegexRangeChars(escChar) or '') )
+        else:
+            self.flags = 0
+            self.pattern = r'%s(?:[^%s\n\r%s]' % \
+                ( re.escape(self.quoteChar),
+                  _escapeRegexRangeChars(self.endQuoteChar[0]),
+                  (escChar is not None and _escapeRegexRangeChars(escChar) or '') )
+        if len(self.endQuoteChar) > 1:
+            self.pattern += (
+                '|(?:' + ')|(?:'.join("%s[^%s]" % (re.escape(self.endQuoteChar[:i]),
+                                               _escapeRegexRangeChars(self.endQuoteChar[i]))
+                                    for i in range(len(self.endQuoteChar)-1,0,-1)) + ')'
+                )
+        if escQuote:
+            self.pattern += (r'|(?:%s)' % re.escape(escQuote))
+        if escChar:
+            self.pattern += (r'|(?:%s.)' % re.escape(escChar))
+            self.escCharReplacePattern = re.escape(self.escChar)+"(.)"
+        self.pattern += (r')*%s' % re.escape(self.endQuoteChar))
+
+        try:
+            self.re = re.compile(self.pattern, self.flags)
+            self.reString = self.pattern
+        except sre_constants.error:
+            warnings.warn("invalid pattern (%s) passed to Regex" % self.pattern,
+                SyntaxWarning, stacklevel=2)
+            raise
+
+        self.name = _ustr(self)
+        self.errmsg = "Expected " + self.name
+        self.mayIndexError = False
+        self.mayReturnEmpty = True
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        result = instring[loc] == self.firstQuoteChar and self.re.match(instring,loc) or None
+        if not result:
+            raise ParseException(instring, loc, self.errmsg, self)
+
+        loc = result.end()
+        ret = result.group()
+
+        if self.unquoteResults:
+
+            # strip off quotes
+            ret = ret[self.quoteCharLen:-self.endQuoteCharLen]
+
+            if isinstance(ret,basestring):
+                # replace escaped whitespace
+                if '\\' in ret and self.convertWhitespaceEscapes:
+                    ws_map = {
+                        r'\t' : '\t',
+                        r'\n' : '\n',
+                        r'\f' : '\f',
+                        r'\r' : '\r',
+                    }
+                    for wslit,wschar in ws_map.items():
+                        ret = ret.replace(wslit, wschar)
+
+                # replace escaped characters
+                if self.escChar:
+                    ret = re.sub(self.escCharReplacePattern, r"\g<1>", ret)
+
+                # replace escaped quotes
+                if self.escQuote:
+                    ret = ret.replace(self.escQuote, self.endQuoteChar)
+
+        return loc, ret
+
+    def __str__( self ):
+        try:
+            return super(QuotedString,self).__str__()
+        except Exception:
+            pass
+
+        if self.strRepr is None:
+            self.strRepr = "quoted string, starting with %s ending with %s" % (self.quoteChar, self.endQuoteChar)
+
+        return self.strRepr
+
+
+class CharsNotIn(Token):
+    """
+    Token for matching words composed of characters I{not} in a given set (will
+    include whitespace in matched characters if not listed in the provided exclusion set - see example).
+    Defined with string containing all disallowed characters, and an optional
+    minimum, maximum, and/or exact length.  The default value for C{min} is 1 (a
+    minimum value < 1 is not valid); the default values for C{max} and C{exact}
+    are 0, meaning no maximum or exact length restriction.
+
+    Example::
+        # define a comma-separated-value as anything that is not a ','
+        csv_value = CharsNotIn(',')
+        print(delimitedList(csv_value).parseString("dkls,lsdkjf,s12 34,@!#,213"))
+    prints::
+        ['dkls', 'lsdkjf', 's12 34', '@!#', '213']
+    """
+    def __init__( self, notChars, min=1, max=0, exact=0 ):
+        super(CharsNotIn,self).__init__()
+        self.skipWhitespace = False
+        self.notChars = notChars
+
+        if min < 1:
+            raise ValueError("cannot specify a minimum length < 1; use Optional(CharsNotIn()) if zero-length char group is permitted")
+
+        self.minLen = min
+
+        if max > 0:
+            self.maxLen = max
+        else:
+            self.maxLen = _MAX_INT
+
+        if exact > 0:
+            self.maxLen = exact
+            self.minLen = exact
+
+        self.name = _ustr(self)
+        self.errmsg = "Expected " + self.name
+        self.mayReturnEmpty = ( self.minLen == 0 )
+        self.mayIndexError = False
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if instring[loc] in self.notChars:
+            raise ParseException(instring, loc, self.errmsg, self)
+
+        start = loc
+        loc += 1
+        notchars = self.notChars
+        maxlen = min( start+self.maxLen, len(instring) )
+        while loc < maxlen and \
+              (instring[loc] not in notchars):
+            loc += 1
+
+        if loc - start < self.minLen:
+            raise ParseException(instring, loc, self.errmsg, self)
+
+        return loc, instring[start:loc]
+
+    def __str__( self ):
+        try:
+            return super(CharsNotIn, self).__str__()
+        except Exception:
+            pass
+
+        if self.strRepr is None:
+            if len(self.notChars) > 4:
+                self.strRepr = "!W:(%s...)" % self.notChars[:4]
+            else:
+                self.strRepr = "!W:(%s)" % self.notChars
+
+        return self.strRepr
+
+class White(Token):
+    """
+    Special matching class for matching whitespace.  Normally, whitespace is ignored
+    by pyparsing grammars.  This class is included when some whitespace structures
+    are significant.  Define with a string containing the whitespace characters to be
+    matched; default is C{" \\t\\r\\n"}.  Also takes optional C{min}, C{max}, and C{exact} arguments,
+    as defined for the C{L{Word}} class.
+    """
+    whiteStrs = {
+        " " : "",
+        "\t": "",
+        "\n": "",
+        "\r": "",
+        "\f": "",
+        }
+    def __init__(self, ws=" \t\r\n", min=1, max=0, exact=0):
+        super(White,self).__init__()
+        self.matchWhite = ws
+        self.setWhitespaceChars( "".join(c for c in self.whiteChars if c not in self.matchWhite) )
+        #~ self.leaveWhitespace()
+        self.name = ("".join(White.whiteStrs[c] for c in self.matchWhite))
+        self.mayReturnEmpty = True
+        self.errmsg = "Expected " + self.name
+
+        self.minLen = min
+
+        if max > 0:
+            self.maxLen = max
+        else:
+            self.maxLen = _MAX_INT
+
+        if exact > 0:
+            self.maxLen = exact
+            self.minLen = exact
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if not(instring[ loc ] in self.matchWhite):
+            raise ParseException(instring, loc, self.errmsg, self)
+        start = loc
+        loc += 1
+        maxloc = start + self.maxLen
+        maxloc = min( maxloc, len(instring) )
+        while loc < maxloc and instring[loc] in self.matchWhite:
+            loc += 1
+
+        if loc - start < self.minLen:
+            raise ParseException(instring, loc, self.errmsg, self)
+
+        return loc, instring[start:loc]
+
+
+class _PositionToken(Token):
+    def __init__( self ):
+        super(_PositionToken,self).__init__()
+        self.name=self.__class__.__name__
+        self.mayReturnEmpty = True
+        self.mayIndexError = False
+
+class GoToColumn(_PositionToken):
+    """
+    Token to advance to a specific column of input text; useful for tabular report scraping.
+    """
+    def __init__( self, colno ):
+        super(GoToColumn,self).__init__()
+        self.col = colno
+
+    def preParse( self, instring, loc ):
+        if col(loc,instring) != self.col:
+            instrlen = len(instring)
+            if self.ignoreExprs:
+                loc = self._skipIgnorables( instring, loc )
+            while loc < instrlen and instring[loc].isspace() and col( loc, instring ) != self.col :
+                loc += 1
+        return loc
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        thiscol = col( loc, instring )
+        if thiscol > self.col:
+            raise ParseException( instring, loc, "Text not in expected column", self )
+        newloc = loc + self.col - thiscol
+        ret = instring[ loc: newloc ]
+        return newloc, ret
+
+
+class LineStart(_PositionToken):
+    """
+    Matches if current position is at the beginning of a line within the parse string
+    
+    Example::
+    
+        test = '''\
+        AAA this line
+        AAA and this line
+          AAA but not this one
+        B AAA and definitely not this one
+        '''
+
+        for t in (LineStart() + 'AAA' + restOfLine).searchString(test):
+            print(t)
+    
+    Prints::
+        ['AAA', ' this line']
+        ['AAA', ' and this line']    
+
+    """
+    def __init__( self ):
+        super(LineStart,self).__init__()
+        self.errmsg = "Expected start of line"
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if col(loc, instring) == 1:
+            return loc, []
+        raise ParseException(instring, loc, self.errmsg, self)
+
+class LineEnd(_PositionToken):
+    """
+    Matches if current position is at the end of a line within the parse string
+    """
+    def __init__( self ):
+        super(LineEnd,self).__init__()
+        self.setWhitespaceChars( ParserElement.DEFAULT_WHITE_CHARS.replace("\n","") )
+        self.errmsg = "Expected end of line"
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if loc len(instring):
+            return loc, []
+        else:
+            raise ParseException(instring, loc, self.errmsg, self)
+
+class WordStart(_PositionToken):
+    """
+    Matches if the current position is at the beginning of a Word, and
+    is not preceded by any character in a given set of C{wordChars}
+    (default=C{printables}). To emulate the C{\b} behavior of regular expressions,
+    use C{WordStart(alphanums)}. C{WordStart} will also match at the beginning of
+    the string being parsed, or at the beginning of a line.
+    """
+    def __init__(self, wordChars = printables):
+        super(WordStart,self).__init__()
+        self.wordChars = set(wordChars)
+        self.errmsg = "Not at the start of a word"
+
+    def parseImpl(self, instring, loc, doActions=True ):
+        if loc != 0:
+            if (instring[loc-1] in self.wordChars or
+                instring[loc] not in self.wordChars):
+                raise ParseException(instring, loc, self.errmsg, self)
+        return loc, []
+
+class WordEnd(_PositionToken):
+    """
+    Matches if the current position is at the end of a Word, and
+    is not followed by any character in a given set of C{wordChars}
+    (default=C{printables}). To emulate the C{\b} behavior of regular expressions,
+    use C{WordEnd(alphanums)}. C{WordEnd} will also match at the end of
+    the string being parsed, or at the end of a line.
+    """
+    def __init__(self, wordChars = printables):
+        super(WordEnd,self).__init__()
+        self.wordChars = set(wordChars)
+        self.skipWhitespace = False
+        self.errmsg = "Not at the end of a word"
+
+    def parseImpl(self, instring, loc, doActions=True ):
+        instrlen = len(instring)
+        if instrlen>0 and loc maxExcLoc:
+                    maxException = err
+                    maxExcLoc = err.loc
+            except IndexError:
+                if len(instring) > maxExcLoc:
+                    maxException = ParseException(instring,len(instring),e.errmsg,self)
+                    maxExcLoc = len(instring)
+            else:
+                # save match among all matches, to retry longest to shortest
+                matches.append((loc2, e))
+
+        if matches:
+            matches.sort(key=lambda x: -x[0])
+            for _,e in matches:
+                try:
+                    return e._parse( instring, loc, doActions )
+                except ParseException as err:
+                    err.__traceback__ = None
+                    if err.loc > maxExcLoc:
+                        maxException = err
+                        maxExcLoc = err.loc
+
+        if maxException is not None:
+            maxException.msg = self.errmsg
+            raise maxException
+        else:
+            raise ParseException(instring, loc, "no defined alternatives to match", self)
+
+
+    def __ixor__(self, other ):
+        if isinstance( other, basestring ):
+            other = ParserElement._literalStringClass( other )
+        return self.append( other ) #Or( [ self, other ] )
+
+    def __str__( self ):
+        if hasattr(self,"name"):
+            return self.name
+
+        if self.strRepr is None:
+            self.strRepr = "{" + " ^ ".join(_ustr(e) for e in self.exprs) + "}"
+
+        return self.strRepr
+
+    def checkRecursion( self, parseElementList ):
+        subRecCheckList = parseElementList[:] + [ self ]
+        for e in self.exprs:
+            e.checkRecursion( subRecCheckList )
+
+
+class MatchFirst(ParseExpression):
+    """
+    Requires that at least one C{ParseExpression} is found.
+    If two expressions match, the first one listed is the one that will match.
+    May be constructed using the C{'|'} operator.
+
+    Example::
+        # construct MatchFirst using '|' operator
+        
+        # watch the order of expressions to match
+        number = Word(nums) | Combine(Word(nums) + '.' + Word(nums))
+        print(number.searchString("123 3.1416 789")) #  Fail! -> [['123'], ['3'], ['1416'], ['789']]
+
+        # put more selective expression first
+        number = Combine(Word(nums) + '.' + Word(nums)) | Word(nums)
+        print(number.searchString("123 3.1416 789")) #  Better -> [['123'], ['3.1416'], ['789']]
+    """
+    def __init__( self, exprs, savelist = False ):
+        super(MatchFirst,self).__init__(exprs, savelist)
+        if self.exprs:
+            self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs)
+        else:
+            self.mayReturnEmpty = True
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        maxExcLoc = -1
+        maxException = None
+        for e in self.exprs:
+            try:
+                ret = e._parse( instring, loc, doActions )
+                return ret
+            except ParseException as err:
+                if err.loc > maxExcLoc:
+                    maxException = err
+                    maxExcLoc = err.loc
+            except IndexError:
+                if len(instring) > maxExcLoc:
+                    maxException = ParseException(instring,len(instring),e.errmsg,self)
+                    maxExcLoc = len(instring)
+
+        # only got here if no expression matched, raise exception for match that made it the furthest
+        else:
+            if maxException is not None:
+                maxException.msg = self.errmsg
+                raise maxException
+            else:
+                raise ParseException(instring, loc, "no defined alternatives to match", self)
+
+    def __ior__(self, other ):
+        if isinstance( other, basestring ):
+            other = ParserElement._literalStringClass( other )
+        return self.append( other ) #MatchFirst( [ self, other ] )
+
+    def __str__( self ):
+        if hasattr(self,"name"):
+            return self.name
+
+        if self.strRepr is None:
+            self.strRepr = "{" + " | ".join(_ustr(e) for e in self.exprs) + "}"
+
+        return self.strRepr
+
+    def checkRecursion( self, parseElementList ):
+        subRecCheckList = parseElementList[:] + [ self ]
+        for e in self.exprs:
+            e.checkRecursion( subRecCheckList )
+
+
+class Each(ParseExpression):
+    """
+    Requires all given C{ParseExpression}s to be found, but in any order.
+    Expressions may be separated by whitespace.
+    May be constructed using the C{'&'} operator.
+
+    Example::
+        color = oneOf("RED ORANGE YELLOW GREEN BLUE PURPLE BLACK WHITE BROWN")
+        shape_type = oneOf("SQUARE CIRCLE TRIANGLE STAR HEXAGON OCTAGON")
+        integer = Word(nums)
+        shape_attr = "shape:" + shape_type("shape")
+        posn_attr = "posn:" + Group(integer("x") + ',' + integer("y"))("posn")
+        color_attr = "color:" + color("color")
+        size_attr = "size:" + integer("size")
+
+        # use Each (using operator '&') to accept attributes in any order 
+        # (shape and posn are required, color and size are optional)
+        shape_spec = shape_attr & posn_attr & Optional(color_attr) & Optional(size_attr)
+
+        shape_spec.runTests('''
+            shape: SQUARE color: BLACK posn: 100, 120
+            shape: CIRCLE size: 50 color: BLUE posn: 50,80
+            color:GREEN size:20 shape:TRIANGLE posn:20,40
+            '''
+            )
+    prints::
+        shape: SQUARE color: BLACK posn: 100, 120
+        ['shape:', 'SQUARE', 'color:', 'BLACK', 'posn:', ['100', ',', '120']]
+        - color: BLACK
+        - posn: ['100', ',', '120']
+          - x: 100
+          - y: 120
+        - shape: SQUARE
+
+
+        shape: CIRCLE size: 50 color: BLUE posn: 50,80
+        ['shape:', 'CIRCLE', 'size:', '50', 'color:', 'BLUE', 'posn:', ['50', ',', '80']]
+        - color: BLUE
+        - posn: ['50', ',', '80']
+          - x: 50
+          - y: 80
+        - shape: CIRCLE
+        - size: 50
+
+
+        color: GREEN size: 20 shape: TRIANGLE posn: 20,40
+        ['color:', 'GREEN', 'size:', '20', 'shape:', 'TRIANGLE', 'posn:', ['20', ',', '40']]
+        - color: GREEN
+        - posn: ['20', ',', '40']
+          - x: 20
+          - y: 40
+        - shape: TRIANGLE
+        - size: 20
+    """
+    def __init__( self, exprs, savelist = True ):
+        super(Each,self).__init__(exprs, savelist)
+        self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs)
+        self.skipWhitespace = True
+        self.initExprGroups = True
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if self.initExprGroups:
+            self.opt1map = dict((id(e.expr),e) for e in self.exprs if isinstance(e,Optional))
+            opt1 = [ e.expr for e in self.exprs if isinstance(e,Optional) ]
+            opt2 = [ e for e in self.exprs if e.mayReturnEmpty and not isinstance(e,Optional)]
+            self.optionals = opt1 + opt2
+            self.multioptionals = [ e.expr for e in self.exprs if isinstance(e,ZeroOrMore) ]
+            self.multirequired = [ e.expr for e in self.exprs if isinstance(e,OneOrMore) ]
+            self.required = [ e for e in self.exprs if not isinstance(e,(Optional,ZeroOrMore,OneOrMore)) ]
+            self.required += self.multirequired
+            self.initExprGroups = False
+        tmpLoc = loc
+        tmpReqd = self.required[:]
+        tmpOpt  = self.optionals[:]
+        matchOrder = []
+
+        keepMatching = True
+        while keepMatching:
+            tmpExprs = tmpReqd + tmpOpt + self.multioptionals + self.multirequired
+            failed = []
+            for e in tmpExprs:
+                try:
+                    tmpLoc = e.tryParse( instring, tmpLoc )
+                except ParseException:
+                    failed.append(e)
+                else:
+                    matchOrder.append(self.opt1map.get(id(e),e))
+                    if e in tmpReqd:
+                        tmpReqd.remove(e)
+                    elif e in tmpOpt:
+                        tmpOpt.remove(e)
+            if len(failed) == len(tmpExprs):
+                keepMatching = False
+
+        if tmpReqd:
+            missing = ", ".join(_ustr(e) for e in tmpReqd)
+            raise ParseException(instring,loc,"Missing one or more required elements (%s)" % missing )
+
+        # add any unmatched Optionals, in case they have default values defined
+        matchOrder += [e for e in self.exprs if isinstance(e,Optional) and e.expr in tmpOpt]
+
+        resultlist = []
+        for e in matchOrder:
+            loc,results = e._parse(instring,loc,doActions)
+            resultlist.append(results)
+
+        finalResults = sum(resultlist, ParseResults([]))
+        return loc, finalResults
+
+    def __str__( self ):
+        if hasattr(self,"name"):
+            return self.name
+
+        if self.strRepr is None:
+            self.strRepr = "{" + " & ".join(_ustr(e) for e in self.exprs) + "}"
+
+        return self.strRepr
+
+    def checkRecursion( self, parseElementList ):
+        subRecCheckList = parseElementList[:] + [ self ]
+        for e in self.exprs:
+            e.checkRecursion( subRecCheckList )
+
+
+class ParseElementEnhance(ParserElement):
+    """
+    Abstract subclass of C{ParserElement}, for combining and post-processing parsed tokens.
+    """
+    def __init__( self, expr, savelist=False ):
+        super(ParseElementEnhance,self).__init__(savelist)
+        if isinstance( expr, basestring ):
+            if issubclass(ParserElement._literalStringClass, Token):
+                expr = ParserElement._literalStringClass(expr)
+            else:
+                expr = ParserElement._literalStringClass(Literal(expr))
+        self.expr = expr
+        self.strRepr = None
+        if expr is not None:
+            self.mayIndexError = expr.mayIndexError
+            self.mayReturnEmpty = expr.mayReturnEmpty
+            self.setWhitespaceChars( expr.whiteChars )
+            self.skipWhitespace = expr.skipWhitespace
+            self.saveAsList = expr.saveAsList
+            self.callPreparse = expr.callPreparse
+            self.ignoreExprs.extend(expr.ignoreExprs)
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if self.expr is not None:
+            return self.expr._parse( instring, loc, doActions, callPreParse=False )
+        else:
+            raise ParseException("",loc,self.errmsg,self)
+
+    def leaveWhitespace( self ):
+        self.skipWhitespace = False
+        self.expr = self.expr.copy()
+        if self.expr is not None:
+            self.expr.leaveWhitespace()
+        return self
+
+    def ignore( self, other ):
+        if isinstance( other, Suppress ):
+            if other not in self.ignoreExprs:
+                super( ParseElementEnhance, self).ignore( other )
+                if self.expr is not None:
+                    self.expr.ignore( self.ignoreExprs[-1] )
+        else:
+            super( ParseElementEnhance, self).ignore( other )
+            if self.expr is not None:
+                self.expr.ignore( self.ignoreExprs[-1] )
+        return self
+
+    def streamline( self ):
+        super(ParseElementEnhance,self).streamline()
+        if self.expr is not None:
+            self.expr.streamline()
+        return self
+
+    def checkRecursion( self, parseElementList ):
+        if self in parseElementList:
+            raise RecursiveGrammarException( parseElementList+[self] )
+        subRecCheckList = parseElementList[:] + [ self ]
+        if self.expr is not None:
+            self.expr.checkRecursion( subRecCheckList )
+
+    def validate( self, validateTrace=[] ):
+        tmp = validateTrace[:]+[self]
+        if self.expr is not None:
+            self.expr.validate(tmp)
+        self.checkRecursion( [] )
+
+    def __str__( self ):
+        try:
+            return super(ParseElementEnhance,self).__str__()
+        except Exception:
+            pass
+
+        if self.strRepr is None and self.expr is not None:
+            self.strRepr = "%s:(%s)" % ( self.__class__.__name__, _ustr(self.expr) )
+        return self.strRepr
+
+
+class FollowedBy(ParseElementEnhance):
+    """
+    Lookahead matching of the given parse expression.  C{FollowedBy}
+    does I{not} advance the parsing position within the input string, it only
+    verifies that the specified parse expression matches at the current
+    position.  C{FollowedBy} always returns a null token list.
+
+    Example::
+        # use FollowedBy to match a label only if it is followed by a ':'
+        data_word = Word(alphas)
+        label = data_word + FollowedBy(':')
+        attr_expr = Group(label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join))
+        
+        OneOrMore(attr_expr).parseString("shape: SQUARE color: BLACK posn: upper left").pprint()
+    prints::
+        [['shape', 'SQUARE'], ['color', 'BLACK'], ['posn', 'upper left']]
+    """
+    def __init__( self, expr ):
+        super(FollowedBy,self).__init__(expr)
+        self.mayReturnEmpty = True
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        self.expr.tryParse( instring, loc )
+        return loc, []
+
+
+class NotAny(ParseElementEnhance):
+    """
+    Lookahead to disallow matching with the given parse expression.  C{NotAny}
+    does I{not} advance the parsing position within the input string, it only
+    verifies that the specified parse expression does I{not} match at the current
+    position.  Also, C{NotAny} does I{not} skip over leading whitespace. C{NotAny}
+    always returns a null token list.  May be constructed using the '~' operator.
+
+    Example::
+        
+    """
+    def __init__( self, expr ):
+        super(NotAny,self).__init__(expr)
+        #~ self.leaveWhitespace()
+        self.skipWhitespace = False  # do NOT use self.leaveWhitespace(), don't want to propagate to exprs
+        self.mayReturnEmpty = True
+        self.errmsg = "Found unwanted token, "+_ustr(self.expr)
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        if self.expr.canParseNext(instring, loc):
+            raise ParseException(instring, loc, self.errmsg, self)
+        return loc, []
+
+    def __str__( self ):
+        if hasattr(self,"name"):
+            return self.name
+
+        if self.strRepr is None:
+            self.strRepr = "~{" + _ustr(self.expr) + "}"
+
+        return self.strRepr
+
+class _MultipleMatch(ParseElementEnhance):
+    def __init__( self, expr, stopOn=None):
+        super(_MultipleMatch, self).__init__(expr)
+        self.saveAsList = True
+        ender = stopOn
+        if isinstance(ender, basestring):
+            ender = ParserElement._literalStringClass(ender)
+        self.not_ender = ~ender if ender is not None else None
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        self_expr_parse = self.expr._parse
+        self_skip_ignorables = self._skipIgnorables
+        check_ender = self.not_ender is not None
+        if check_ender:
+            try_not_ender = self.not_ender.tryParse
+        
+        # must be at least one (but first see if we are the stopOn sentinel;
+        # if so, fail)
+        if check_ender:
+            try_not_ender(instring, loc)
+        loc, tokens = self_expr_parse( instring, loc, doActions, callPreParse=False )
+        try:
+            hasIgnoreExprs = (not not self.ignoreExprs)
+            while 1:
+                if check_ender:
+                    try_not_ender(instring, loc)
+                if hasIgnoreExprs:
+                    preloc = self_skip_ignorables( instring, loc )
+                else:
+                    preloc = loc
+                loc, tmptokens = self_expr_parse( instring, preloc, doActions )
+                if tmptokens or tmptokens.haskeys():
+                    tokens += tmptokens
+        except (ParseException,IndexError):
+            pass
+
+        return loc, tokens
+        
+class OneOrMore(_MultipleMatch):
+    """
+    Repetition of one or more of the given expression.
+    
+    Parameters:
+     - expr - expression that must match one or more times
+     - stopOn - (default=C{None}) - expression for a terminating sentinel
+          (only required if the sentinel would ordinarily match the repetition 
+          expression)          
+
+    Example::
+        data_word = Word(alphas)
+        label = data_word + FollowedBy(':')
+        attr_expr = Group(label + Suppress(':') + OneOrMore(data_word).setParseAction(' '.join))
+
+        text = "shape: SQUARE posn: upper left color: BLACK"
+        OneOrMore(attr_expr).parseString(text).pprint()  # Fail! read 'color' as data instead of next label -> [['shape', 'SQUARE color']]
+
+        # use stopOn attribute for OneOrMore to avoid reading label string as part of the data
+        attr_expr = Group(label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join))
+        OneOrMore(attr_expr).parseString(text).pprint() # Better -> [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'BLACK']]
+        
+        # could also be written as
+        (attr_expr * (1,)).parseString(text).pprint()
+    """
+
+    def __str__( self ):
+        if hasattr(self,"name"):
+            return self.name
+
+        if self.strRepr is None:
+            self.strRepr = "{" + _ustr(self.expr) + "}..."
+
+        return self.strRepr
+
+class ZeroOrMore(_MultipleMatch):
+    """
+    Optional repetition of zero or more of the given expression.
+    
+    Parameters:
+     - expr - expression that must match zero or more times
+     - stopOn - (default=C{None}) - expression for a terminating sentinel
+          (only required if the sentinel would ordinarily match the repetition 
+          expression)          
+
+    Example: similar to L{OneOrMore}
+    """
+    def __init__( self, expr, stopOn=None):
+        super(ZeroOrMore,self).__init__(expr, stopOn=stopOn)
+        self.mayReturnEmpty = True
+        
+    def parseImpl( self, instring, loc, doActions=True ):
+        try:
+            return super(ZeroOrMore, self).parseImpl(instring, loc, doActions)
+        except (ParseException,IndexError):
+            return loc, []
+
+    def __str__( self ):
+        if hasattr(self,"name"):
+            return self.name
+
+        if self.strRepr is None:
+            self.strRepr = "[" + _ustr(self.expr) + "]..."
+
+        return self.strRepr
+
+class _NullToken(object):
+    def __bool__(self):
+        return False
+    __nonzero__ = __bool__
+    def __str__(self):
+        return ""
+
+_optionalNotMatched = _NullToken()
+class Optional(ParseElementEnhance):
+    """
+    Optional matching of the given expression.
+
+    Parameters:
+     - expr - expression that must match zero or more times
+     - default (optional) - value to be returned if the optional expression is not found.
+
+    Example::
+        # US postal code can be a 5-digit zip, plus optional 4-digit qualifier
+        zip = Combine(Word(nums, exact=5) + Optional('-' + Word(nums, exact=4)))
+        zip.runTests('''
+            # traditional ZIP code
+            12345
+            
+            # ZIP+4 form
+            12101-0001
+            
+            # invalid ZIP
+            98765-
+            ''')
+    prints::
+        # traditional ZIP code
+        12345
+        ['12345']
+
+        # ZIP+4 form
+        12101-0001
+        ['12101-0001']
+
+        # invalid ZIP
+        98765-
+             ^
+        FAIL: Expected end of text (at char 5), (line:1, col:6)
+    """
+    def __init__( self, expr, default=_optionalNotMatched ):
+        super(Optional,self).__init__( expr, savelist=False )
+        self.saveAsList = self.expr.saveAsList
+        self.defaultValue = default
+        self.mayReturnEmpty = True
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        try:
+            loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False )
+        except (ParseException,IndexError):
+            if self.defaultValue is not _optionalNotMatched:
+                if self.expr.resultsName:
+                    tokens = ParseResults([ self.defaultValue ])
+                    tokens[self.expr.resultsName] = self.defaultValue
+                else:
+                    tokens = [ self.defaultValue ]
+            else:
+                tokens = []
+        return loc, tokens
+
+    def __str__( self ):
+        if hasattr(self,"name"):
+            return self.name
+
+        if self.strRepr is None:
+            self.strRepr = "[" + _ustr(self.expr) + "]"
+
+        return self.strRepr
+
+class SkipTo(ParseElementEnhance):
+    """
+    Token for skipping over all undefined text until the matched expression is found.
+
+    Parameters:
+     - expr - target expression marking the end of the data to be skipped
+     - include - (default=C{False}) if True, the target expression is also parsed 
+          (the skipped text and target expression are returned as a 2-element list).
+     - ignore - (default=C{None}) used to define grammars (typically quoted strings and 
+          comments) that might contain false matches to the target expression
+     - failOn - (default=C{None}) define expressions that are not allowed to be 
+          included in the skipped test; if found before the target expression is found, 
+          the SkipTo is not a match
+
+    Example::
+        report = '''
+            Outstanding Issues Report - 1 Jan 2000
+
+               # | Severity | Description                               |  Days Open
+            -----+----------+-------------------------------------------+-----------
+             101 | Critical | Intermittent system crash                 |          6
+              94 | Cosmetic | Spelling error on Login ('log|n')         |         14
+              79 | Minor    | System slow when running too many reports |         47
+            '''
+        integer = Word(nums)
+        SEP = Suppress('|')
+        # use SkipTo to simply match everything up until the next SEP
+        # - ignore quoted strings, so that a '|' character inside a quoted string does not match
+        # - parse action will call token.strip() for each matched token, i.e., the description body
+        string_data = SkipTo(SEP, ignore=quotedString)
+        string_data.setParseAction(tokenMap(str.strip))
+        ticket_expr = (integer("issue_num") + SEP 
+                      + string_data("sev") + SEP 
+                      + string_data("desc") + SEP 
+                      + integer("days_open"))
+        
+        for tkt in ticket_expr.searchString(report):
+            print tkt.dump()
+    prints::
+        ['101', 'Critical', 'Intermittent system crash', '6']
+        - days_open: 6
+        - desc: Intermittent system crash
+        - issue_num: 101
+        - sev: Critical
+        ['94', 'Cosmetic', "Spelling error on Login ('log|n')", '14']
+        - days_open: 14
+        - desc: Spelling error on Login ('log|n')
+        - issue_num: 94
+        - sev: Cosmetic
+        ['79', 'Minor', 'System slow when running too many reports', '47']
+        - days_open: 47
+        - desc: System slow when running too many reports
+        - issue_num: 79
+        - sev: Minor
+    """
+    def __init__( self, other, include=False, ignore=None, failOn=None ):
+        super( SkipTo, self ).__init__( other )
+        self.ignoreExpr = ignore
+        self.mayReturnEmpty = True
+        self.mayIndexError = False
+        self.includeMatch = include
+        self.asList = False
+        if isinstance(failOn, basestring):
+            self.failOn = ParserElement._literalStringClass(failOn)
+        else:
+            self.failOn = failOn
+        self.errmsg = "No match found for "+_ustr(self.expr)
+
+    def parseImpl( self, instring, loc, doActions=True ):
+        startloc = loc
+        instrlen = len(instring)
+        expr = self.expr
+        expr_parse = self.expr._parse
+        self_failOn_canParseNext = self.failOn.canParseNext if self.failOn is not None else None
+        self_ignoreExpr_tryParse = self.ignoreExpr.tryParse if self.ignoreExpr is not None else None
+        
+        tmploc = loc
+        while tmploc <= instrlen:
+            if self_failOn_canParseNext is not None:
+                # break if failOn expression matches
+                if self_failOn_canParseNext(instring, tmploc):
+                    break
+                    
+            if self_ignoreExpr_tryParse is not None:
+                # advance past ignore expressions
+                while 1:
+                    try:
+                        tmploc = self_ignoreExpr_tryParse(instring, tmploc)
+                    except ParseBaseException:
+                        break
+            
+            try:
+                expr_parse(instring, tmploc, doActions=False, callPreParse=False)
+            except (ParseException, IndexError):
+                # no match, advance loc in string
+                tmploc += 1
+            else:
+                # matched skipto expr, done
+                break
+
+        else:
+            # ran off the end of the input string without matching skipto expr, fail
+            raise ParseException(instring, loc, self.errmsg, self)
+
+        # build up return values
+        loc = tmploc
+        skiptext = instring[startloc:loc]
+        skipresult = ParseResults(skiptext)
+        
+        if self.includeMatch:
+            loc, mat = expr_parse(instring,loc,doActions,callPreParse=False)
+            skipresult += mat
+
+        return loc, skipresult
+
+class Forward(ParseElementEnhance):
+    """
+    Forward declaration of an expression to be defined later -
+    used for recursive grammars, such as algebraic infix notation.
+    When the expression is known, it is assigned to the C{Forward} variable using the '<<' operator.
+
+    Note: take care when assigning to C{Forward} not to overlook precedence of operators.
+    Specifically, '|' has a lower precedence than '<<', so that::
+        fwdExpr << a | b | c
+    will actually be evaluated as::
+        (fwdExpr << a) | b | c
+    thereby leaving b and c out as parseable alternatives.  It is recommended that you
+    explicitly group the values inserted into the C{Forward}::
+        fwdExpr << (a | b | c)
+    Converting to use the '<<=' operator instead will avoid this problem.
+
+    See L{ParseResults.pprint} for an example of a recursive parser created using
+    C{Forward}.
+    """
+    def __init__( self, other=None ):
+        super(Forward,self).__init__( other, savelist=False )
+
+    def __lshift__( self, other ):
+        if isinstance( other, basestring ):
+            other = ParserElement._literalStringClass(other)
+        self.expr = other
+        self.strRepr = None
+        self.mayIndexError = self.expr.mayIndexError
+        self.mayReturnEmpty = self.expr.mayReturnEmpty
+        self.setWhitespaceChars( self.expr.whiteChars )
+        self.skipWhitespace = self.expr.skipWhitespace
+        self.saveAsList = self.expr.saveAsList
+        self.ignoreExprs.extend(self.expr.ignoreExprs)
+        return self
+        
+    def __ilshift__(self, other):
+        return self << other
+    
+    def leaveWhitespace( self ):
+        self.skipWhitespace = False
+        return self
+
+    def streamline( self ):
+        if not self.streamlined:
+            self.streamlined = True
+            if self.expr is not None:
+                self.expr.streamline()
+        return self
+
+    def validate( self, validateTrace=[] ):
+        if self not in validateTrace:
+            tmp = validateTrace[:]+[self]
+            if self.expr is not None:
+                self.expr.validate(tmp)
+        self.checkRecursion([])
+
+    def __str__( self ):
+        if hasattr(self,"name"):
+            return self.name
+        return self.__class__.__name__ + ": ..."
+
+        # stubbed out for now - creates awful memory and perf issues
+        self._revertClass = self.__class__
+        self.__class__ = _ForwardNoRecurse
+        try:
+            if self.expr is not None:
+                retString = _ustr(self.expr)
+            else:
+                retString = "None"
+        finally:
+            self.__class__ = self._revertClass
+        return self.__class__.__name__ + ": " + retString
+
+    def copy(self):
+        if self.expr is not None:
+            return super(Forward,self).copy()
+        else:
+            ret = Forward()
+            ret <<= self
+            return ret
+
+class _ForwardNoRecurse(Forward):
+    def __str__( self ):
+        return "..."
+
+class TokenConverter(ParseElementEnhance):
+    """
+    Abstract subclass of C{ParseExpression}, for converting parsed results.
+    """
+    def __init__( self, expr, savelist=False ):
+        super(TokenConverter,self).__init__( expr )#, savelist )
+        self.saveAsList = False
+
+class Combine(TokenConverter):
+    """
+    Converter to concatenate all matching tokens to a single string.
+    By default, the matching patterns must also be contiguous in the input string;
+    this can be disabled by specifying C{'adjacent=False'} in the constructor.
+
+    Example::
+        real = Word(nums) + '.' + Word(nums)
+        print(real.parseString('3.1416')) # -> ['3', '.', '1416']
+        # will also erroneously match the following
+        print(real.parseString('3. 1416')) # -> ['3', '.', '1416']
+
+        real = Combine(Word(nums) + '.' + Word(nums))
+        print(real.parseString('3.1416')) # -> ['3.1416']
+        # no match when there are internal spaces
+        print(real.parseString('3. 1416')) # -> Exception: Expected W:(0123...)
+    """
+    def __init__( self, expr, joinString="", adjacent=True ):
+        super(Combine,self).__init__( expr )
+        # suppress whitespace-stripping in contained parse expressions, but re-enable it on the Combine itself
+        if adjacent:
+            self.leaveWhitespace()
+        self.adjacent = adjacent
+        self.skipWhitespace = True
+        self.joinString = joinString
+        self.callPreparse = True
+
+    def ignore( self, other ):
+        if self.adjacent:
+            ParserElement.ignore(self, other)
+        else:
+            super( Combine, self).ignore( other )
+        return self
+
+    def postParse( self, instring, loc, tokenlist ):
+        retToks = tokenlist.copy()
+        del retToks[:]
+        retToks += ParseResults([ "".join(tokenlist._asStringList(self.joinString)) ], modal=self.modalResults)
+
+        if self.resultsName and retToks.haskeys():
+            return [ retToks ]
+        else:
+            return retToks
+
+class Group(TokenConverter):
+    """
+    Converter to return the matched tokens as a list - useful for returning tokens of C{L{ZeroOrMore}} and C{L{OneOrMore}} expressions.
+
+    Example::
+        ident = Word(alphas)
+        num = Word(nums)
+        term = ident | num
+        func = ident + Optional(delimitedList(term))
+        print(func.parseString("fn a,b,100"))  # -> ['fn', 'a', 'b', '100']
+
+        func = ident + Group(Optional(delimitedList(term)))
+        print(func.parseString("fn a,b,100"))  # -> ['fn', ['a', 'b', '100']]
+    """
+    def __init__( self, expr ):
+        super(Group,self).__init__( expr )
+        self.saveAsList = True
+
+    def postParse( self, instring, loc, tokenlist ):
+        return [ tokenlist ]
+
+class Dict(TokenConverter):
+    """
+    Converter to return a repetitive expression as a list, but also as a dictionary.
+    Each element can also be referenced using the first token in the expression as its key.
+    Useful for tabular report scraping when the first column can be used as a item key.
+
+    Example::
+        data_word = Word(alphas)
+        label = data_word + FollowedBy(':')
+        attr_expr = Group(label + Suppress(':') + OneOrMore(data_word).setParseAction(' '.join))
+
+        text = "shape: SQUARE posn: upper left color: light blue texture: burlap"
+        attr_expr = (label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join))
+        
+        # print attributes as plain groups
+        print(OneOrMore(attr_expr).parseString(text).dump())
+        
+        # instead of OneOrMore(expr), parse using Dict(OneOrMore(Group(expr))) - Dict will auto-assign names
+        result = Dict(OneOrMore(Group(attr_expr))).parseString(text)
+        print(result.dump())
+        
+        # access named fields as dict entries, or output as dict
+        print(result['shape'])        
+        print(result.asDict())
+    prints::
+        ['shape', 'SQUARE', 'posn', 'upper left', 'color', 'light blue', 'texture', 'burlap']
+
+        [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'light blue'], ['texture', 'burlap']]
+        - color: light blue
+        - posn: upper left
+        - shape: SQUARE
+        - texture: burlap
+        SQUARE
+        {'color': 'light blue', 'posn': 'upper left', 'texture': 'burlap', 'shape': 'SQUARE'}
+    See more examples at L{ParseResults} of accessing fields by results name.
+    """
+    def __init__( self, expr ):
+        super(Dict,self).__init__( expr )
+        self.saveAsList = True
+
+    def postParse( self, instring, loc, tokenlist ):
+        for i,tok in enumerate(tokenlist):
+            if len(tok) == 0:
+                continue
+            ikey = tok[0]
+            if isinstance(ikey,int):
+                ikey = _ustr(tok[0]).strip()
+            if len(tok)==1:
+                tokenlist[ikey] = _ParseResultsWithOffset("",i)
+            elif len(tok)==2 and not isinstance(tok[1],ParseResults):
+                tokenlist[ikey] = _ParseResultsWithOffset(tok[1],i)
+            else:
+                dictvalue = tok.copy() #ParseResults(i)
+                del dictvalue[0]
+                if len(dictvalue)!= 1 or (isinstance(dictvalue,ParseResults) and dictvalue.haskeys()):
+                    tokenlist[ikey] = _ParseResultsWithOffset(dictvalue,i)
+                else:
+                    tokenlist[ikey] = _ParseResultsWithOffset(dictvalue[0],i)
+
+        if self.resultsName:
+            return [ tokenlist ]
+        else:
+            return tokenlist
+
+
+class Suppress(TokenConverter):
+    """
+    Converter for ignoring the results of a parsed expression.
+
+    Example::
+        source = "a, b, c,d"
+        wd = Word(alphas)
+        wd_list1 = wd + ZeroOrMore(',' + wd)
+        print(wd_list1.parseString(source))
+
+        # often, delimiters that are useful during parsing are just in the
+        # way afterward - use Suppress to keep them out of the parsed output
+        wd_list2 = wd + ZeroOrMore(Suppress(',') + wd)
+        print(wd_list2.parseString(source))
+    prints::
+        ['a', ',', 'b', ',', 'c', ',', 'd']
+        ['a', 'b', 'c', 'd']
+    (See also L{delimitedList}.)
+    """
+    def postParse( self, instring, loc, tokenlist ):
+        return []
+
+    def suppress( self ):
+        return self
+
+
+class OnlyOnce(object):
+    """
+    Wrapper for parse actions, to ensure they are only called once.
+    """
+    def __init__(self, methodCall):
+        self.callable = _trim_arity(methodCall)
+        self.called = False
+    def __call__(self,s,l,t):
+        if not self.called:
+            results = self.callable(s,l,t)
+            self.called = True
+            return results
+        raise ParseException(s,l,"")
+    def reset(self):
+        self.called = False
+
+def traceParseAction(f):
+    """
+    Decorator for debugging parse actions. 
+    
+    When the parse action is called, this decorator will print C{">> entering I{method-name}(line:I{current_source_line}, I{parse_location}, I{matched_tokens})".}
+    When the parse action completes, the decorator will print C{"<<"} followed by the returned value, or any exception that the parse action raised.
+
+    Example::
+        wd = Word(alphas)
+
+        @traceParseAction
+        def remove_duplicate_chars(tokens):
+            return ''.join(sorted(set(''.join(tokens))))
+
+        wds = OneOrMore(wd).setParseAction(remove_duplicate_chars)
+        print(wds.parseString("slkdjs sld sldd sdlf sdljf"))
+    prints::
+        >>entering remove_duplicate_chars(line: 'slkdjs sld sldd sdlf sdljf', 0, (['slkdjs', 'sld', 'sldd', 'sdlf', 'sdljf'], {}))
+        <3:
+            thisFunc = paArgs[0].__class__.__name__ + '.' + thisFunc
+        sys.stderr.write( ">>entering %s(line: '%s', %d, %r)\n" % (thisFunc,line(l,s),l,t) )
+        try:
+            ret = f(*paArgs)
+        except Exception as exc:
+            sys.stderr.write( "< ['aa', 'bb', 'cc']
+        delimitedList(Word(hexnums), delim=':', combine=True).parseString("AA:BB:CC:DD:EE") # -> ['AA:BB:CC:DD:EE']
+    """
+    dlName = _ustr(expr)+" ["+_ustr(delim)+" "+_ustr(expr)+"]..."
+    if combine:
+        return Combine( expr + ZeroOrMore( delim + expr ) ).setName(dlName)
+    else:
+        return ( expr + ZeroOrMore( Suppress( delim ) + expr ) ).setName(dlName)
+
+def countedArray( expr, intExpr=None ):
+    """
+    Helper to define a counted list of expressions.
+    This helper defines a pattern of the form::
+        integer expr expr expr...
+    where the leading integer tells how many expr expressions follow.
+    The matched tokens returns the array of expr tokens as a list - the leading count token is suppressed.
+    
+    If C{intExpr} is specified, it should be a pyparsing expression that produces an integer value.
+
+    Example::
+        countedArray(Word(alphas)).parseString('2 ab cd ef')  # -> ['ab', 'cd']
+
+        # in this parser, the leading integer value is given in binary,
+        # '10' indicating that 2 values are in the array
+        binaryConstant = Word('01').setParseAction(lambda t: int(t[0], 2))
+        countedArray(Word(alphas), intExpr=binaryConstant).parseString('10 ab cd ef')  # -> ['ab', 'cd']
+    """
+    arrayExpr = Forward()
+    def countFieldParseAction(s,l,t):
+        n = t[0]
+        arrayExpr << (n and Group(And([expr]*n)) or Group(empty))
+        return []
+    if intExpr is None:
+        intExpr = Word(nums).setParseAction(lambda t:int(t[0]))
+    else:
+        intExpr = intExpr.copy()
+    intExpr.setName("arrayLen")
+    intExpr.addParseAction(countFieldParseAction, callDuringTry=True)
+    return ( intExpr + arrayExpr ).setName('(len) ' + _ustr(expr) + '...')
+
+def _flatten(L):
+    ret = []
+    for i in L:
+        if isinstance(i,list):
+            ret.extend(_flatten(i))
+        else:
+            ret.append(i)
+    return ret
+
+def matchPreviousLiteral(expr):
+    """
+    Helper to define an expression that is indirectly defined from
+    the tokens matched in a previous expression, that is, it looks
+    for a 'repeat' of a previous expression.  For example::
+        first = Word(nums)
+        second = matchPreviousLiteral(first)
+        matchExpr = first + ":" + second
+    will match C{"1:1"}, but not C{"1:2"}.  Because this matches a
+    previous literal, will also match the leading C{"1:1"} in C{"1:10"}.
+    If this is not desired, use C{matchPreviousExpr}.
+    Do I{not} use with packrat parsing enabled.
+    """
+    rep = Forward()
+    def copyTokenToRepeater(s,l,t):
+        if t:
+            if len(t) == 1:
+                rep << t[0]
+            else:
+                # flatten t tokens
+                tflat = _flatten(t.asList())
+                rep << And(Literal(tt) for tt in tflat)
+        else:
+            rep << Empty()
+    expr.addParseAction(copyTokenToRepeater, callDuringTry=True)
+    rep.setName('(prev) ' + _ustr(expr))
+    return rep
+
+def matchPreviousExpr(expr):
+    """
+    Helper to define an expression that is indirectly defined from
+    the tokens matched in a previous expression, that is, it looks
+    for a 'repeat' of a previous expression.  For example::
+        first = Word(nums)
+        second = matchPreviousExpr(first)
+        matchExpr = first + ":" + second
+    will match C{"1:1"}, but not C{"1:2"}.  Because this matches by
+    expressions, will I{not} match the leading C{"1:1"} in C{"1:10"};
+    the expressions are evaluated first, and then compared, so
+    C{"1"} is compared with C{"10"}.
+    Do I{not} use with packrat parsing enabled.
+    """
+    rep = Forward()
+    e2 = expr.copy()
+    rep <<= e2
+    def copyTokenToRepeater(s,l,t):
+        matchTokens = _flatten(t.asList())
+        def mustMatchTheseTokens(s,l,t):
+            theseTokens = _flatten(t.asList())
+            if  theseTokens != matchTokens:
+                raise ParseException("",0,"")
+        rep.setParseAction( mustMatchTheseTokens, callDuringTry=True )
+    expr.addParseAction(copyTokenToRepeater, callDuringTry=True)
+    rep.setName('(prev) ' + _ustr(expr))
+    return rep
+
+def _escapeRegexRangeChars(s):
+    #~  escape these chars: ^-]
+    for c in r"\^-]":
+        s = s.replace(c,_bslash+c)
+    s = s.replace("\n",r"\n")
+    s = s.replace("\t",r"\t")
+    return _ustr(s)
+
+def oneOf( strs, caseless=False, useRegex=True ):
+    """
+    Helper to quickly define a set of alternative Literals, and makes sure to do
+    longest-first testing when there is a conflict, regardless of the input order,
+    but returns a C{L{MatchFirst}} for best performance.
+
+    Parameters:
+     - strs - a string of space-delimited literals, or a collection of string literals
+     - caseless - (default=C{False}) - treat all literals as caseless
+     - useRegex - (default=C{True}) - as an optimization, will generate a Regex
+          object; otherwise, will generate a C{MatchFirst} object (if C{caseless=True}, or
+          if creating a C{Regex} raises an exception)
+
+    Example::
+        comp_oper = oneOf("< = > <= >= !=")
+        var = Word(alphas)
+        number = Word(nums)
+        term = var | number
+        comparison_expr = term + comp_oper + term
+        print(comparison_expr.searchString("B = 12  AA=23 B<=AA AA>12"))
+    prints::
+        [['B', '=', '12'], ['AA', '=', '23'], ['B', '<=', 'AA'], ['AA', '>', '12']]
+    """
+    if caseless:
+        isequal = ( lambda a,b: a.upper() == b.upper() )
+        masks = ( lambda a,b: b.upper().startswith(a.upper()) )
+        parseElementClass = CaselessLiteral
+    else:
+        isequal = ( lambda a,b: a == b )
+        masks = ( lambda a,b: b.startswith(a) )
+        parseElementClass = Literal
+
+    symbols = []
+    if isinstance(strs,basestring):
+        symbols = strs.split()
+    elif isinstance(strs, Iterable):
+        symbols = list(strs)
+    else:
+        warnings.warn("Invalid argument to oneOf, expected string or iterable",
+                SyntaxWarning, stacklevel=2)
+    if not symbols:
+        return NoMatch()
+
+    i = 0
+    while i < len(symbols)-1:
+        cur = symbols[i]
+        for j,other in enumerate(symbols[i+1:]):
+            if ( isequal(other, cur) ):
+                del symbols[i+j+1]
+                break
+            elif ( masks(cur, other) ):
+                del symbols[i+j+1]
+                symbols.insert(i,other)
+                cur = other
+                break
+        else:
+            i += 1
+
+    if not caseless and useRegex:
+        #~ print (strs,"->", "|".join( [ _escapeRegexChars(sym) for sym in symbols] ))
+        try:
+            if len(symbols)==len("".join(symbols)):
+                return Regex( "[%s]" % "".join(_escapeRegexRangeChars(sym) for sym in symbols) ).setName(' | '.join(symbols))
+            else:
+                return Regex( "|".join(re.escape(sym) for sym in symbols) ).setName(' | '.join(symbols))
+        except Exception:
+            warnings.warn("Exception creating Regex for oneOf, building MatchFirst",
+                    SyntaxWarning, stacklevel=2)
+
+
+    # last resort, just use MatchFirst
+    return MatchFirst(parseElementClass(sym) for sym in symbols).setName(' | '.join(symbols))
+
+def dictOf( key, value ):
+    """
+    Helper to easily and clearly define a dictionary by specifying the respective patterns
+    for the key and value.  Takes care of defining the C{L{Dict}}, C{L{ZeroOrMore}}, and C{L{Group}} tokens
+    in the proper order.  The key pattern can include delimiting markers or punctuation,
+    as long as they are suppressed, thereby leaving the significant key text.  The value
+    pattern can include named results, so that the C{Dict} results can include named token
+    fields.
+
+    Example::
+        text = "shape: SQUARE posn: upper left color: light blue texture: burlap"
+        attr_expr = (label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join))
+        print(OneOrMore(attr_expr).parseString(text).dump())
+        
+        attr_label = label
+        attr_value = Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join)
+
+        # similar to Dict, but simpler call format
+        result = dictOf(attr_label, attr_value).parseString(text)
+        print(result.dump())
+        print(result['shape'])
+        print(result.shape)  # object attribute access works too
+        print(result.asDict())
+    prints::
+        [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'light blue'], ['texture', 'burlap']]
+        - color: light blue
+        - posn: upper left
+        - shape: SQUARE
+        - texture: burlap
+        SQUARE
+        SQUARE
+        {'color': 'light blue', 'shape': 'SQUARE', 'posn': 'upper left', 'texture': 'burlap'}
+    """
+    return Dict( ZeroOrMore( Group ( key + value ) ) )
+
+def originalTextFor(expr, asString=True):
+    """
+    Helper to return the original, untokenized text for a given expression.  Useful to
+    restore the parsed fields of an HTML start tag into the raw tag text itself, or to
+    revert separate tokens with intervening whitespace back to the original matching
+    input text. By default, returns astring containing the original parsed text.  
+       
+    If the optional C{asString} argument is passed as C{False}, then the return value is a 
+    C{L{ParseResults}} containing any results names that were originally matched, and a 
+    single token containing the original matched text from the input string.  So if 
+    the expression passed to C{L{originalTextFor}} contains expressions with defined
+    results names, you must set C{asString} to C{False} if you want to preserve those
+    results name values.
+
+    Example::
+        src = "this is test  bold text  normal text "
+        for tag in ("b","i"):
+            opener,closer = makeHTMLTags(tag)
+            patt = originalTextFor(opener + SkipTo(closer) + closer)
+            print(patt.searchString(src)[0])
+    prints::
+        [' bold text ']
+        ['text']
+    """
+    locMarker = Empty().setParseAction(lambda s,loc,t: loc)
+    endlocMarker = locMarker.copy()
+    endlocMarker.callPreparse = False
+    matchExpr = locMarker("_original_start") + expr + endlocMarker("_original_end")
+    if asString:
+        extractText = lambda s,l,t: s[t._original_start:t._original_end]
+    else:
+        def extractText(s,l,t):
+            t[:] = [s[t.pop('_original_start'):t.pop('_original_end')]]
+    matchExpr.setParseAction(extractText)
+    matchExpr.ignoreExprs = expr.ignoreExprs
+    return matchExpr
+
+def ungroup(expr): 
+    """
+    Helper to undo pyparsing's default grouping of And expressions, even
+    if all but one are non-empty.
+    """
+    return TokenConverter(expr).setParseAction(lambda t:t[0])
+
+def locatedExpr(expr):
+    """
+    Helper to decorate a returned token with its starting and ending locations in the input string.
+    This helper adds the following results names:
+     - locn_start = location where matched expression begins
+     - locn_end = location where matched expression ends
+     - value = the actual parsed results
+
+    Be careful if the input text contains C{} characters, you may want to call
+    C{L{ParserElement.parseWithTabs}}
+
+    Example::
+        wd = Word(alphas)
+        for match in locatedExpr(wd).searchString("ljsdf123lksdjjf123lkkjj1222"):
+            print(match)
+    prints::
+        [[0, 'ljsdf', 5]]
+        [[8, 'lksdjjf', 15]]
+        [[18, 'lkkjj', 23]]
+    """
+    locator = Empty().setParseAction(lambda s,l,t: l)
+    return Group(locator("locn_start") + expr("value") + locator.copy().leaveWhitespace()("locn_end"))
+
+
+# convenience constants for positional expressions
+empty       = Empty().setName("empty")
+lineStart   = LineStart().setName("lineStart")
+lineEnd     = LineEnd().setName("lineEnd")
+stringStart = StringStart().setName("stringStart")
+stringEnd   = StringEnd().setName("stringEnd")
+
+_escapedPunc = Word( _bslash, r"\[]-*.$+^?()~ ", exact=2 ).setParseAction(lambda s,l,t:t[0][1])
+_escapedHexChar = Regex(r"\\0?[xX][0-9a-fA-F]+").setParseAction(lambda s,l,t:unichr(int(t[0].lstrip(r'\0x'),16)))
+_escapedOctChar = Regex(r"\\0[0-7]+").setParseAction(lambda s,l,t:unichr(int(t[0][1:],8)))
+_singleChar = _escapedPunc | _escapedHexChar | _escapedOctChar | CharsNotIn(r'\]', exact=1)
+_charRange = Group(_singleChar + Suppress("-") + _singleChar)
+_reBracketExpr = Literal("[") + Optional("^").setResultsName("negate") + Group( OneOrMore( _charRange | _singleChar ) ).setResultsName("body") + "]"
+
+def srange(s):
+    r"""
+    Helper to easily define string ranges for use in Word construction.  Borrows
+    syntax from regexp '[]' string range definitions::
+        srange("[0-9]")   -> "0123456789"
+        srange("[a-z]")   -> "abcdefghijklmnopqrstuvwxyz"
+        srange("[a-z$_]") -> "abcdefghijklmnopqrstuvwxyz$_"
+    The input string must be enclosed in []'s, and the returned string is the expanded
+    character set joined into a single string.
+    The values enclosed in the []'s may be:
+     - a single character
+     - an escaped character with a leading backslash (such as C{\-} or C{\]})
+     - an escaped hex character with a leading C{'\x'} (C{\x21}, which is a C{'!'} character) 
+         (C{\0x##} is also supported for backwards compatibility) 
+     - an escaped octal character with a leading C{'\0'} (C{\041}, which is a C{'!'} character)
+     - a range of any of the above, separated by a dash (C{'a-z'}, etc.)
+     - any combination of the above (C{'aeiouy'}, C{'a-zA-Z0-9_$'}, etc.)
+    """
+    _expanded = lambda p: p if not isinstance(p,ParseResults) else ''.join(unichr(c) for c in range(ord(p[0]),ord(p[1])+1))
+    try:
+        return "".join(_expanded(part) for part in _reBracketExpr.parseString(s).body)
+    except Exception:
+        return ""
+
+def matchOnlyAtCol(n):
+    """
+    Helper method for defining parse actions that require matching at a specific
+    column in the input text.
+    """
+    def verifyCol(strg,locn,toks):
+        if col(locn,strg) != n:
+            raise ParseException(strg,locn,"matched token not at column %d" % n)
+    return verifyCol
+
+def replaceWith(replStr):
+    """
+    Helper method for common parse actions that simply return a literal value.  Especially
+    useful when used with C{L{transformString}()}.
+
+    Example::
+        num = Word(nums).setParseAction(lambda toks: int(toks[0]))
+        na = oneOf("N/A NA").setParseAction(replaceWith(math.nan))
+        term = na | num
+        
+        OneOrMore(term).parseString("324 234 N/A 234") # -> [324, 234, nan, 234]
+    """
+    return lambda s,l,t: [replStr]
+
+def removeQuotes(s,l,t):
+    """
+    Helper parse action for removing quotation marks from parsed quoted strings.
+
+    Example::
+        # by default, quotation marks are included in parsed results
+        quotedString.parseString("'Now is the Winter of our Discontent'") # -> ["'Now is the Winter of our Discontent'"]
+
+        # use removeQuotes to strip quotation marks from parsed results
+        quotedString.setParseAction(removeQuotes)
+        quotedString.parseString("'Now is the Winter of our Discontent'") # -> ["Now is the Winter of our Discontent"]
+    """
+    return t[0][1:-1]
+
+def tokenMap(func, *args):
+    """
+    Helper to define a parse action by mapping a function to all elements of a ParseResults list.If any additional 
+    args are passed, they are forwarded to the given function as additional arguments after
+    the token, as in C{hex_integer = Word(hexnums).setParseAction(tokenMap(int, 16))}, which will convert the
+    parsed data to an integer using base 16.
+
+    Example (compare the last to example in L{ParserElement.transformString}::
+        hex_ints = OneOrMore(Word(hexnums)).setParseAction(tokenMap(int, 16))
+        hex_ints.runTests('''
+            00 11 22 aa FF 0a 0d 1a
+            ''')
+        
+        upperword = Word(alphas).setParseAction(tokenMap(str.upper))
+        OneOrMore(upperword).runTests('''
+            my kingdom for a horse
+            ''')
+
+        wd = Word(alphas).setParseAction(tokenMap(str.title))
+        OneOrMore(wd).setParseAction(' '.join).runTests('''
+            now is the winter of our discontent made glorious summer by this sun of york
+            ''')
+    prints::
+        00 11 22 aa FF 0a 0d 1a
+        [0, 17, 34, 170, 255, 10, 13, 26]
+
+        my kingdom for a horse
+        ['MY', 'KINGDOM', 'FOR', 'A', 'HORSE']
+
+        now is the winter of our discontent made glorious summer by this sun of york
+        ['Now Is The Winter Of Our Discontent Made Glorious Summer By This Sun Of York']
+    """
+    def pa(s,l,t):
+        return [func(tokn, *args) for tokn in t]
+
+    try:
+        func_name = getattr(func, '__name__', 
+                            getattr(func, '__class__').__name__)
+    except Exception:
+        func_name = str(func)
+    pa.__name__ = func_name
+
+    return pa
+
+upcaseTokens = tokenMap(lambda t: _ustr(t).upper())
+"""(Deprecated) Helper parse action to convert tokens to upper case. Deprecated in favor of L{pyparsing_common.upcaseTokens}"""
+
+downcaseTokens = tokenMap(lambda t: _ustr(t).lower())
+"""(Deprecated) Helper parse action to convert tokens to lower case. Deprecated in favor of L{pyparsing_common.downcaseTokens}"""
+    
+def _makeTags(tagStr, xml):
+    """Internal helper to construct opening and closing tag expressions, given a tag name"""
+    if isinstance(tagStr,basestring):
+        resname = tagStr
+        tagStr = Keyword(tagStr, caseless=not xml)
+    else:
+        resname = tagStr.name
+
+    tagAttrName = Word(alphas,alphanums+"_-:")
+    if (xml):
+        tagAttrValue = dblQuotedString.copy().setParseAction( removeQuotes )
+        openTag = Suppress("<") + tagStr("tag") + \
+                Dict(ZeroOrMore(Group( tagAttrName + Suppress("=") + tagAttrValue ))) + \
+                Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">")
+    else:
+        printablesLessRAbrack = "".join(c for c in printables if c not in ">")
+        tagAttrValue = quotedString.copy().setParseAction( removeQuotes ) | Word(printablesLessRAbrack)
+        openTag = Suppress("<") + tagStr("tag") + \
+                Dict(ZeroOrMore(Group( tagAttrName.setParseAction(downcaseTokens) + \
+                Optional( Suppress("=") + tagAttrValue ) ))) + \
+                Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">")
+    closeTag = Combine(_L("")
+
+    openTag = openTag.setResultsName("start"+"".join(resname.replace(":"," ").title().split())).setName("<%s>" % resname)
+    closeTag = closeTag.setResultsName("end"+"".join(resname.replace(":"," ").title().split())).setName("" % resname)
+    openTag.tag = resname
+    closeTag.tag = resname
+    return openTag, closeTag
+
+def makeHTMLTags(tagStr):
+    """
+    Helper to construct opening and closing tag expressions for HTML, given a tag name. Matches
+    tags in either upper or lower case, attributes with namespaces and with quoted or unquoted values.
+
+    Example::
+        text = 'More info at the pyparsing wiki page'
+        # makeHTMLTags returns pyparsing expressions for the opening and closing tags as a 2-tuple
+        a,a_end = makeHTMLTags("A")
+        link_expr = a + SkipTo(a_end)("link_text") + a_end
+        
+        for link in link_expr.searchString(text):
+            # attributes in the  tag (like "href" shown here) are also accessible as named results
+            print(link.link_text, '->', link.href)
+    prints::
+        pyparsing -> http://pyparsing.wikispaces.com
+    """
+    return _makeTags( tagStr, False )
+
+def makeXMLTags(tagStr):
+    """
+    Helper to construct opening and closing tag expressions for XML, given a tag name. Matches
+    tags only in the given upper/lower case.
+
+    Example: similar to L{makeHTMLTags}
+    """
+    return _makeTags( tagStr, True )
+
+def withAttribute(*args,**attrDict):
+    """
+    Helper to create a validating parse action to be used with start tags created
+    with C{L{makeXMLTags}} or C{L{makeHTMLTags}}. Use C{withAttribute} to qualify a starting tag
+    with a required attribute value, to avoid false matches on common tags such as
+    C{} or C{
}. + + Call C{withAttribute} with a series of attribute names and values. Specify the list + of filter attributes names and values as: + - keyword arguments, as in C{(align="right")}, or + - as an explicit dict with C{**} operator, when an attribute name is also a Python + reserved word, as in C{**{"class":"Customer", "align":"right"}} + - a list of name-value tuples, as in ( ("ns1:class", "Customer"), ("ns2:align","right") ) + For attribute names with a namespace prefix, you must use the second form. Attribute + names are matched insensitive to upper/lower case. + + If just testing for C{class} (with or without a namespace), use C{L{withClass}}. + + To verify that the attribute exists, but without specifying a value, pass + C{withAttribute.ANY_VALUE} as the value. + + Example:: + html = ''' +
+ Some text +
1 4 0 1 0
+
1,3 2,3 1,1
+
this has no type
+
+ + ''' + div,div_end = makeHTMLTags("div") + + # only match div tag having a type attribute with value "grid" + div_grid = div().setParseAction(withAttribute(type="grid")) + grid_expr = div_grid + SkipTo(div | div_end)("body") + for grid_header in grid_expr.searchString(html): + print(grid_header.body) + + # construct a match with any div tag having a type attribute, regardless of the value + div_any_type = div().setParseAction(withAttribute(type=withAttribute.ANY_VALUE)) + div_expr = div_any_type + SkipTo(div | div_end)("body") + for div_header in div_expr.searchString(html): + print(div_header.body) + prints:: + 1 4 0 1 0 + + 1 4 0 1 0 + 1,3 2,3 1,1 + """ + if args: + attrs = args[:] + else: + attrs = attrDict.items() + attrs = [(k,v) for k,v in attrs] + def pa(s,l,tokens): + for attrName,attrValue in attrs: + if attrName not in tokens: + raise ParseException(s,l,"no matching attribute " + attrName) + if attrValue != withAttribute.ANY_VALUE and tokens[attrName] != attrValue: + raise ParseException(s,l,"attribute '%s' has value '%s', must be '%s'" % + (attrName, tokens[attrName], attrValue)) + return pa +withAttribute.ANY_VALUE = object() + +def withClass(classname, namespace=''): + """ + Simplified version of C{L{withAttribute}} when matching on a div class - made + difficult because C{class} is a reserved word in Python. + + Example:: + html = ''' +
+ Some text +
1 4 0 1 0
+
1,3 2,3 1,1
+
this <div> has no class
+
+ + ''' + div,div_end = makeHTMLTags("div") + div_grid = div().setParseAction(withClass("grid")) + + grid_expr = div_grid + SkipTo(div | div_end)("body") + for grid_header in grid_expr.searchString(html): + print(grid_header.body) + + div_any_type = div().setParseAction(withClass(withAttribute.ANY_VALUE)) + div_expr = div_any_type + SkipTo(div | div_end)("body") + for div_header in div_expr.searchString(html): + print(div_header.body) + prints:: + 1 4 0 1 0 + + 1 4 0 1 0 + 1,3 2,3 1,1 + """ + classattr = "%s:class" % namespace if namespace else "class" + return withAttribute(**{classattr : classname}) + +opAssoc = _Constants() +opAssoc.LEFT = object() +opAssoc.RIGHT = object() + +def infixNotation( baseExpr, opList, lpar=Suppress('('), rpar=Suppress(')') ): + """ + Helper method for constructing grammars of expressions made up of + operators working in a precedence hierarchy. Operators may be unary or + binary, left- or right-associative. Parse actions can also be attached + to operator expressions. The generated parser will also recognize the use + of parentheses to override operator precedences (see example below). + + Note: if you define a deep operator list, you may see performance issues + when using infixNotation. See L{ParserElement.enablePackrat} for a + mechanism to potentially improve your parser performance. + + Parameters: + - baseExpr - expression representing the most basic element for the nested + - opList - list of tuples, one for each operator precedence level in the + expression grammar; each tuple is of the form + (opExpr, numTerms, rightLeftAssoc, parseAction), where: + - opExpr is the pyparsing expression for the operator; + may also be a string, which will be converted to a Literal; + if numTerms is 3, opExpr is a tuple of two expressions, for the + two operators separating the 3 terms + - numTerms is the number of terms for this operator (must + be 1, 2, or 3) + - rightLeftAssoc is the indicator whether the operator is + right or left associative, using the pyparsing-defined + constants C{opAssoc.RIGHT} and C{opAssoc.LEFT}. + - parseAction is the parse action to be associated with + expressions matching this operator expression (the + parse action tuple member may be omitted); if the parse action + is passed a tuple or list of functions, this is equivalent to + calling C{setParseAction(*fn)} (L{ParserElement.setParseAction}) + - lpar - expression for matching left-parentheses (default=C{Suppress('(')}) + - rpar - expression for matching right-parentheses (default=C{Suppress(')')}) + + Example:: + # simple example of four-function arithmetic with ints and variable names + integer = pyparsing_common.signed_integer + varname = pyparsing_common.identifier + + arith_expr = infixNotation(integer | varname, + [ + ('-', 1, opAssoc.RIGHT), + (oneOf('* /'), 2, opAssoc.LEFT), + (oneOf('+ -'), 2, opAssoc.LEFT), + ]) + + arith_expr.runTests(''' + 5+3*6 + (5+3)*6 + -2--11 + ''', fullDump=False) + prints:: + 5+3*6 + [[5, '+', [3, '*', 6]]] + + (5+3)*6 + [[[5, '+', 3], '*', 6]] + + -2--11 + [[['-', 2], '-', ['-', 11]]] + """ + ret = Forward() + lastExpr = baseExpr | ( lpar + ret + rpar ) + for i,operDef in enumerate(opList): + opExpr,arity,rightLeftAssoc,pa = (operDef + (None,))[:4] + termName = "%s term" % opExpr if arity < 3 else "%s%s term" % opExpr + if arity == 3: + if opExpr is None or len(opExpr) != 2: + raise ValueError("if numterms=3, opExpr must be a tuple or list of two expressions") + opExpr1, opExpr2 = opExpr + thisExpr = Forward().setName(termName) + if rightLeftAssoc == opAssoc.LEFT: + if arity == 1: + matchExpr = FollowedBy(lastExpr + opExpr) + Group( lastExpr + OneOrMore( opExpr ) ) + elif arity == 2: + if opExpr is not None: + matchExpr = FollowedBy(lastExpr + opExpr + lastExpr) + Group( lastExpr + OneOrMore( opExpr + lastExpr ) ) + else: + matchExpr = FollowedBy(lastExpr+lastExpr) + Group( lastExpr + OneOrMore(lastExpr) ) + elif arity == 3: + matchExpr = FollowedBy(lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr) + \ + Group( lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr ) + else: + raise ValueError("operator must be unary (1), binary (2), or ternary (3)") + elif rightLeftAssoc == opAssoc.RIGHT: + if arity == 1: + # try to avoid LR with this extra test + if not isinstance(opExpr, Optional): + opExpr = Optional(opExpr) + matchExpr = FollowedBy(opExpr.expr + thisExpr) + Group( opExpr + thisExpr ) + elif arity == 2: + if opExpr is not None: + matchExpr = FollowedBy(lastExpr + opExpr + thisExpr) + Group( lastExpr + OneOrMore( opExpr + thisExpr ) ) + else: + matchExpr = FollowedBy(lastExpr + thisExpr) + Group( lastExpr + OneOrMore( thisExpr ) ) + elif arity == 3: + matchExpr = FollowedBy(lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr) + \ + Group( lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr ) + else: + raise ValueError("operator must be unary (1), binary (2), or ternary (3)") + else: + raise ValueError("operator must indicate right or left associativity") + if pa: + if isinstance(pa, (tuple, list)): + matchExpr.setParseAction(*pa) + else: + matchExpr.setParseAction(pa) + thisExpr <<= ( matchExpr.setName(termName) | lastExpr ) + lastExpr = thisExpr + ret <<= lastExpr + return ret + +operatorPrecedence = infixNotation +"""(Deprecated) Former name of C{L{infixNotation}}, will be dropped in a future release.""" + +dblQuotedString = Combine(Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*')+'"').setName("string enclosed in double quotes") +sglQuotedString = Combine(Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*")+"'").setName("string enclosed in single quotes") +quotedString = Combine(Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*')+'"'| + Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*")+"'").setName("quotedString using single or double quotes") +unicodeString = Combine(_L('u') + quotedString.copy()).setName("unicode string literal") + +def nestedExpr(opener="(", closer=")", content=None, ignoreExpr=quotedString.copy()): + """ + Helper method for defining nested lists enclosed in opening and closing + delimiters ("(" and ")" are the default). + + Parameters: + - opener - opening character for a nested list (default=C{"("}); can also be a pyparsing expression + - closer - closing character for a nested list (default=C{")"}); can also be a pyparsing expression + - content - expression for items within the nested lists (default=C{None}) + - ignoreExpr - expression for ignoring opening and closing delimiters (default=C{quotedString}) + + If an expression is not provided for the content argument, the nested + expression will capture all whitespace-delimited content between delimiters + as a list of separate values. + + Use the C{ignoreExpr} argument to define expressions that may contain + opening or closing characters that should not be treated as opening + or closing characters for nesting, such as quotedString or a comment + expression. Specify multiple expressions using an C{L{Or}} or C{L{MatchFirst}}. + The default is L{quotedString}, but if no expressions are to be ignored, + then pass C{None} for this argument. + + Example:: + data_type = oneOf("void int short long char float double") + decl_data_type = Combine(data_type + Optional(Word('*'))) + ident = Word(alphas+'_', alphanums+'_') + number = pyparsing_common.number + arg = Group(decl_data_type + ident) + LPAR,RPAR = map(Suppress, "()") + + code_body = nestedExpr('{', '}', ignoreExpr=(quotedString | cStyleComment)) + + c_function = (decl_data_type("type") + + ident("name") + + LPAR + Optional(delimitedList(arg), [])("args") + RPAR + + code_body("body")) + c_function.ignore(cStyleComment) + + source_code = ''' + int is_odd(int x) { + return (x%2); + } + + int dec_to_hex(char hchar) { + if (hchar >= '0' && hchar <= '9') { + return (ord(hchar)-ord('0')); + } else { + return (10+ord(hchar)-ord('A')); + } + } + ''' + for func in c_function.searchString(source_code): + print("%(name)s (%(type)s) args: %(args)s" % func) + + prints:: + is_odd (int) args: [['int', 'x']] + dec_to_hex (int) args: [['char', 'hchar']] + """ + if opener == closer: + raise ValueError("opening and closing strings cannot be the same") + if content is None: + if isinstance(opener,basestring) and isinstance(closer,basestring): + if len(opener) == 1 and len(closer)==1: + if ignoreExpr is not None: + content = (Combine(OneOrMore(~ignoreExpr + + CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS,exact=1)) + ).setParseAction(lambda t:t[0].strip())) + else: + content = (empty.copy()+CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS + ).setParseAction(lambda t:t[0].strip())) + else: + if ignoreExpr is not None: + content = (Combine(OneOrMore(~ignoreExpr + + ~Literal(opener) + ~Literal(closer) + + CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1)) + ).setParseAction(lambda t:t[0].strip())) + else: + content = (Combine(OneOrMore(~Literal(opener) + ~Literal(closer) + + CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1)) + ).setParseAction(lambda t:t[0].strip())) + else: + raise ValueError("opening and closing arguments must be strings if no content expression is given") + ret = Forward() + if ignoreExpr is not None: + ret <<= Group( Suppress(opener) + ZeroOrMore( ignoreExpr | ret | content ) + Suppress(closer) ) + else: + ret <<= Group( Suppress(opener) + ZeroOrMore( ret | content ) + Suppress(closer) ) + ret.setName('nested %s%s expression' % (opener,closer)) + return ret + +def indentedBlock(blockStatementExpr, indentStack, indent=True): + """ + Helper method for defining space-delimited indentation blocks, such as + those used to define block statements in Python source code. + + Parameters: + - blockStatementExpr - expression defining syntax of statement that + is repeated within the indented block + - indentStack - list created by caller to manage indentation stack + (multiple statementWithIndentedBlock expressions within a single grammar + should share a common indentStack) + - indent - boolean indicating whether block must be indented beyond the + the current level; set to False for block of left-most statements + (default=C{True}) + + A valid block must contain at least one C{blockStatement}. + + Example:: + data = ''' + def A(z): + A1 + B = 100 + G = A2 + A2 + A3 + B + def BB(a,b,c): + BB1 + def BBA(): + bba1 + bba2 + bba3 + C + D + def spam(x,y): + def eggs(z): + pass + ''' + + + indentStack = [1] + stmt = Forward() + + identifier = Word(alphas, alphanums) + funcDecl = ("def" + identifier + Group( "(" + Optional( delimitedList(identifier) ) + ")" ) + ":") + func_body = indentedBlock(stmt, indentStack) + funcDef = Group( funcDecl + func_body ) + + rvalue = Forward() + funcCall = Group(identifier + "(" + Optional(delimitedList(rvalue)) + ")") + rvalue << (funcCall | identifier | Word(nums)) + assignment = Group(identifier + "=" + rvalue) + stmt << ( funcDef | assignment | identifier ) + + module_body = OneOrMore(stmt) + + parseTree = module_body.parseString(data) + parseTree.pprint() + prints:: + [['def', + 'A', + ['(', 'z', ')'], + ':', + [['A1'], [['B', '=', '100']], [['G', '=', 'A2']], ['A2'], ['A3']]], + 'B', + ['def', + 'BB', + ['(', 'a', 'b', 'c', ')'], + ':', + [['BB1'], [['def', 'BBA', ['(', ')'], ':', [['bba1'], ['bba2'], ['bba3']]]]]], + 'C', + 'D', + ['def', + 'spam', + ['(', 'x', 'y', ')'], + ':', + [[['def', 'eggs', ['(', 'z', ')'], ':', [['pass']]]]]]] + """ + def checkPeerIndent(s,l,t): + if l >= len(s): return + curCol = col(l,s) + if curCol != indentStack[-1]: + if curCol > indentStack[-1]: + raise ParseFatalException(s,l,"illegal nesting") + raise ParseException(s,l,"not a peer entry") + + def checkSubIndent(s,l,t): + curCol = col(l,s) + if curCol > indentStack[-1]: + indentStack.append( curCol ) + else: + raise ParseException(s,l,"not a subentry") + + def checkUnindent(s,l,t): + if l >= len(s): return + curCol = col(l,s) + if not(indentStack and curCol < indentStack[-1] and curCol <= indentStack[-2]): + raise ParseException(s,l,"not an unindent") + indentStack.pop() + + NL = OneOrMore(LineEnd().setWhitespaceChars("\t ").suppress()) + INDENT = (Empty() + Empty().setParseAction(checkSubIndent)).setName('INDENT') + PEER = Empty().setParseAction(checkPeerIndent).setName('') + UNDENT = Empty().setParseAction(checkUnindent).setName('UNINDENT') + if indent: + smExpr = Group( Optional(NL) + + #~ FollowedBy(blockStatementExpr) + + INDENT + (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) + UNDENT) + else: + smExpr = Group( Optional(NL) + + (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) ) + blockStatementExpr.ignore(_bslash + LineEnd()) + return smExpr.setName('indented block') + +alphas8bit = srange(r"[\0xc0-\0xd6\0xd8-\0xf6\0xf8-\0xff]") +punc8bit = srange(r"[\0xa1-\0xbf\0xd7\0xf7]") + +anyOpenTag,anyCloseTag = makeHTMLTags(Word(alphas,alphanums+"_:").setName('any tag')) +_htmlEntityMap = dict(zip("gt lt amp nbsp quot apos".split(),'><& "\'')) +commonHTMLEntity = Regex('&(?P' + '|'.join(_htmlEntityMap.keys()) +");").setName("common HTML entity") +def replaceHTMLEntity(t): + """Helper parser action to replace common HTML entities with their special characters""" + return _htmlEntityMap.get(t.entity) + +# it's easy to get these comment structures wrong - they're very common, so may as well make them available +cStyleComment = Combine(Regex(r"/\*(?:[^*]|\*(?!/))*") + '*/').setName("C style comment") +"Comment of the form C{/* ... */}" + +htmlComment = Regex(r"").setName("HTML comment") +"Comment of the form C{}" + +restOfLine = Regex(r".*").leaveWhitespace().setName("rest of line") +dblSlashComment = Regex(r"//(?:\\\n|[^\n])*").setName("// comment") +"Comment of the form C{// ... (to end of line)}" + +cppStyleComment = Combine(Regex(r"/\*(?:[^*]|\*(?!/))*") + '*/'| dblSlashComment).setName("C++ style comment") +"Comment of either form C{L{cStyleComment}} or C{L{dblSlashComment}}" + +javaStyleComment = cppStyleComment +"Same as C{L{cppStyleComment}}" + +pythonStyleComment = Regex(r"#.*").setName("Python style comment") +"Comment of the form C{# ... (to end of line)}" + +_commasepitem = Combine(OneOrMore(Word(printables, excludeChars=',') + + Optional( Word(" \t") + + ~Literal(",") + ~LineEnd() ) ) ).streamline().setName("commaItem") +commaSeparatedList = delimitedList( Optional( quotedString.copy() | _commasepitem, default="") ).setName("commaSeparatedList") +"""(Deprecated) Predefined expression of 1 or more printable words or quoted strings, separated by commas. + This expression is deprecated in favor of L{pyparsing_common.comma_separated_list}.""" + +# some other useful expressions - using lower-case class name since we are really using this as a namespace +class pyparsing_common: + """ + Here are some common low-level expressions that may be useful in jump-starting parser development: + - numeric forms (L{integers}, L{reals}, L{scientific notation}) + - common L{programming identifiers} + - network addresses (L{MAC}, L{IPv4}, L{IPv6}) + - ISO8601 L{dates} and L{datetime} + - L{UUID} + - L{comma-separated list} + Parse actions: + - C{L{convertToInteger}} + - C{L{convertToFloat}} + - C{L{convertToDate}} + - C{L{convertToDatetime}} + - C{L{stripHTMLTags}} + - C{L{upcaseTokens}} + - C{L{downcaseTokens}} + + Example:: + pyparsing_common.number.runTests(''' + # any int or real number, returned as the appropriate type + 100 + -100 + +100 + 3.14159 + 6.02e23 + 1e-12 + ''') + + pyparsing_common.fnumber.runTests(''' + # any int or real number, returned as float + 100 + -100 + +100 + 3.14159 + 6.02e23 + 1e-12 + ''') + + pyparsing_common.hex_integer.runTests(''' + # hex numbers + 100 + FF + ''') + + pyparsing_common.fraction.runTests(''' + # fractions + 1/2 + -3/4 + ''') + + pyparsing_common.mixed_integer.runTests(''' + # mixed fractions + 1 + 1/2 + -3/4 + 1-3/4 + ''') + + import uuid + pyparsing_common.uuid.setParseAction(tokenMap(uuid.UUID)) + pyparsing_common.uuid.runTests(''' + # uuid + 12345678-1234-5678-1234-567812345678 + ''') + prints:: + # any int or real number, returned as the appropriate type + 100 + [100] + + -100 + [-100] + + +100 + [100] + + 3.14159 + [3.14159] + + 6.02e23 + [6.02e+23] + + 1e-12 + [1e-12] + + # any int or real number, returned as float + 100 + [100.0] + + -100 + [-100.0] + + +100 + [100.0] + + 3.14159 + [3.14159] + + 6.02e23 + [6.02e+23] + + 1e-12 + [1e-12] + + # hex numbers + 100 + [256] + + FF + [255] + + # fractions + 1/2 + [0.5] + + -3/4 + [-0.75] + + # mixed fractions + 1 + [1] + + 1/2 + [0.5] + + -3/4 + [-0.75] + + 1-3/4 + [1.75] + + # uuid + 12345678-1234-5678-1234-567812345678 + [UUID('12345678-1234-5678-1234-567812345678')] + """ + + convertToInteger = tokenMap(int) + """ + Parse action for converting parsed integers to Python int + """ + + convertToFloat = tokenMap(float) + """ + Parse action for converting parsed numbers to Python float + """ + + integer = Word(nums).setName("integer").setParseAction(convertToInteger) + """expression that parses an unsigned integer, returns an int""" + + hex_integer = Word(hexnums).setName("hex integer").setParseAction(tokenMap(int,16)) + """expression that parses a hexadecimal integer, returns an int""" + + signed_integer = Regex(r'[+-]?\d+').setName("signed integer").setParseAction(convertToInteger) + """expression that parses an integer with optional leading sign, returns an int""" + + fraction = (signed_integer().setParseAction(convertToFloat) + '/' + signed_integer().setParseAction(convertToFloat)).setName("fraction") + """fractional expression of an integer divided by an integer, returns a float""" + fraction.addParseAction(lambda t: t[0]/t[-1]) + + mixed_integer = (fraction | signed_integer + Optional(Optional('-').suppress() + fraction)).setName("fraction or mixed integer-fraction") + """mixed integer of the form 'integer - fraction', with optional leading integer, returns float""" + mixed_integer.addParseAction(sum) + + real = Regex(r'[+-]?\d+\.\d*').setName("real number").setParseAction(convertToFloat) + """expression that parses a floating point number and returns a float""" + + sci_real = Regex(r'[+-]?\d+([eE][+-]?\d+|\.\d*([eE][+-]?\d+)?)').setName("real number with scientific notation").setParseAction(convertToFloat) + """expression that parses a floating point number with optional scientific notation and returns a float""" + + # streamlining this expression makes the docs nicer-looking + number = (sci_real | real | signed_integer).streamline() + """any numeric expression, returns the corresponding Python type""" + + fnumber = Regex(r'[+-]?\d+\.?\d*([eE][+-]?\d+)?').setName("fnumber").setParseAction(convertToFloat) + """any int or real number, returned as float""" + + identifier = Word(alphas+'_', alphanums+'_').setName("identifier") + """typical code identifier (leading alpha or '_', followed by 0 or more alphas, nums, or '_')""" + + ipv4_address = Regex(r'(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})(\.(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})){3}').setName("IPv4 address") + "IPv4 address (C{0.0.0.0 - 255.255.255.255})" + + _ipv6_part = Regex(r'[0-9a-fA-F]{1,4}').setName("hex_integer") + _full_ipv6_address = (_ipv6_part + (':' + _ipv6_part)*7).setName("full IPv6 address") + _short_ipv6_address = (Optional(_ipv6_part + (':' + _ipv6_part)*(0,6)) + "::" + Optional(_ipv6_part + (':' + _ipv6_part)*(0,6))).setName("short IPv6 address") + _short_ipv6_address.addCondition(lambda t: sum(1 for tt in t if pyparsing_common._ipv6_part.matches(tt)) < 8) + _mixed_ipv6_address = ("::ffff:" + ipv4_address).setName("mixed IPv6 address") + ipv6_address = Combine((_full_ipv6_address | _mixed_ipv6_address | _short_ipv6_address).setName("IPv6 address")).setName("IPv6 address") + "IPv6 address (long, short, or mixed form)" + + mac_address = Regex(r'[0-9a-fA-F]{2}([:.-])[0-9a-fA-F]{2}(?:\1[0-9a-fA-F]{2}){4}').setName("MAC address") + "MAC address xx:xx:xx:xx:xx (may also have '-' or '.' delimiters)" + + @staticmethod + def convertToDate(fmt="%Y-%m-%d"): + """ + Helper to create a parse action for converting parsed date string to Python datetime.date + + Params - + - fmt - format to be passed to datetime.strptime (default=C{"%Y-%m-%d"}) + + Example:: + date_expr = pyparsing_common.iso8601_date.copy() + date_expr.setParseAction(pyparsing_common.convertToDate()) + print(date_expr.parseString("1999-12-31")) + prints:: + [datetime.date(1999, 12, 31)] + """ + def cvt_fn(s,l,t): + try: + return datetime.strptime(t[0], fmt).date() + except ValueError as ve: + raise ParseException(s, l, str(ve)) + return cvt_fn + + @staticmethod + def convertToDatetime(fmt="%Y-%m-%dT%H:%M:%S.%f"): + """ + Helper to create a parse action for converting parsed datetime string to Python datetime.datetime + + Params - + - fmt - format to be passed to datetime.strptime (default=C{"%Y-%m-%dT%H:%M:%S.%f"}) + + Example:: + dt_expr = pyparsing_common.iso8601_datetime.copy() + dt_expr.setParseAction(pyparsing_common.convertToDatetime()) + print(dt_expr.parseString("1999-12-31T23:59:59.999")) + prints:: + [datetime.datetime(1999, 12, 31, 23, 59, 59, 999000)] + """ + def cvt_fn(s,l,t): + try: + return datetime.strptime(t[0], fmt) + except ValueError as ve: + raise ParseException(s, l, str(ve)) + return cvt_fn + + iso8601_date = Regex(r'(?P\d{4})(?:-(?P\d\d)(?:-(?P\d\d))?)?').setName("ISO8601 date") + "ISO8601 date (C{yyyy-mm-dd})" + + iso8601_datetime = Regex(r'(?P\d{4})-(?P\d\d)-(?P\d\d)[T ](?P\d\d):(?P\d\d)(:(?P\d\d(\.\d*)?)?)?(?PZ|[+-]\d\d:?\d\d)?').setName("ISO8601 datetime") + "ISO8601 datetime (C{yyyy-mm-ddThh:mm:ss.s(Z|+-00:00)}) - trailing seconds, milliseconds, and timezone optional; accepts separating C{'T'} or C{' '}" + + uuid = Regex(r'[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}').setName("UUID") + "UUID (C{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx})" + + _html_stripper = anyOpenTag.suppress() | anyCloseTag.suppress() + @staticmethod + def stripHTMLTags(s, l, tokens): + """ + Parse action to remove HTML tags from web page HTML source + + Example:: + # strip HTML links from normal text + text = 'More info at the
pyparsing wiki page' + td,td_end = makeHTMLTags("TD") + table_text = td + SkipTo(td_end).setParseAction(pyparsing_common.stripHTMLTags)("body") + td_end + + print(table_text.parseString(text).body) # -> 'More info at the pyparsing wiki page' + """ + return pyparsing_common._html_stripper.transformString(tokens[0]) + + _commasepitem = Combine(OneOrMore(~Literal(",") + ~LineEnd() + Word(printables, excludeChars=',') + + Optional( White(" \t") ) ) ).streamline().setName("commaItem") + comma_separated_list = delimitedList( Optional( quotedString.copy() | _commasepitem, default="") ).setName("comma separated list") + """Predefined expression of 1 or more printable words or quoted strings, separated by commas.""" + + upcaseTokens = staticmethod(tokenMap(lambda t: _ustr(t).upper())) + """Parse action to convert tokens to upper case.""" + + downcaseTokens = staticmethod(tokenMap(lambda t: _ustr(t).lower())) + """Parse action to convert tokens to lower case.""" + + +if __name__ == "__main__": + + selectToken = CaselessLiteral("select") + fromToken = CaselessLiteral("from") + + ident = Word(alphas, alphanums + "_$") + + columnName = delimitedList(ident, ".", combine=True).setParseAction(upcaseTokens) + columnNameList = Group(delimitedList(columnName)).setName("columns") + columnSpec = ('*' | columnNameList) + + tableName = delimitedList(ident, ".", combine=True).setParseAction(upcaseTokens) + tableNameList = Group(delimitedList(tableName)).setName("tables") + + simpleSQL = selectToken("command") + columnSpec("columns") + fromToken + tableNameList("tables") + + # demo runTests method, including embedded comments in test string + simpleSQL.runTests(""" + # '*' as column list and dotted table name + select * from SYS.XYZZY + + # caseless match on "SELECT", and casts back to "select" + SELECT * from XYZZY, ABC + + # list of column names, and mixed case SELECT keyword + Select AA,BB,CC from Sys.dual + + # multiple tables + Select A, B, C from Sys.dual, Table2 + + # invalid SELECT keyword - should fail + Xelect A, B, C from Sys.dual + + # incomplete command - should fail + Select + + # invalid column name - should fail + Select ^^^ frox Sys.dual + + """) + + pyparsing_common.number.runTests(""" + 100 + -100 + +100 + 3.14159 + 6.02e23 + 1e-12 + """) + + # any int or real number, returned as float + pyparsing_common.fnumber.runTests(""" + 100 + -100 + +100 + 3.14159 + 6.02e23 + 1e-12 + """) + + pyparsing_common.hex_integer.runTests(""" + 100 + FF + """) + + import uuid + pyparsing_common.uuid.setParseAction(tokenMap(uuid.UUID)) + pyparsing_common.uuid.runTests(""" + 12345678-1234-5678-1234-567812345678 + """) diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/six.py b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/six.py new file mode 100644 index 0000000..190c023 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/six.py @@ -0,0 +1,868 @@ +"""Utilities for writing code that runs on Python 2 and 3""" + +# Copyright (c) 2010-2015 Benjamin Peterson +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from __future__ import absolute_import + +import functools +import itertools +import operator +import sys +import types + +__author__ = "Benjamin Peterson " +__version__ = "1.10.0" + + +# Useful for very coarse version differentiation. +PY2 = sys.version_info[0] == 2 +PY3 = sys.version_info[0] == 3 +PY34 = sys.version_info[0:2] >= (3, 4) + +if PY3: + string_types = str, + integer_types = int, + class_types = type, + text_type = str + binary_type = bytes + + MAXSIZE = sys.maxsize +else: + string_types = basestring, + integer_types = (int, long) + class_types = (type, types.ClassType) + text_type = unicode + binary_type = str + + if sys.platform.startswith("java"): + # Jython always uses 32 bits. + MAXSIZE = int((1 << 31) - 1) + else: + # It's possible to have sizeof(long) != sizeof(Py_ssize_t). + class X(object): + + def __len__(self): + return 1 << 31 + try: + len(X()) + except OverflowError: + # 32-bit + MAXSIZE = int((1 << 31) - 1) + else: + # 64-bit + MAXSIZE = int((1 << 63) - 1) + del X + + +def _add_doc(func, doc): + """Add documentation to a function.""" + func.__doc__ = doc + + +def _import_module(name): + """Import module, returning the module after the last dot.""" + __import__(name) + return sys.modules[name] + + +class _LazyDescr(object): + + def __init__(self, name): + self.name = name + + def __get__(self, obj, tp): + result = self._resolve() + setattr(obj, self.name, result) # Invokes __set__. + try: + # This is a bit ugly, but it avoids running this again by + # removing this descriptor. + delattr(obj.__class__, self.name) + except AttributeError: + pass + return result + + +class MovedModule(_LazyDescr): + + def __init__(self, name, old, new=None): + super(MovedModule, self).__init__(name) + if PY3: + if new is None: + new = name + self.mod = new + else: + self.mod = old + + def _resolve(self): + return _import_module(self.mod) + + def __getattr__(self, attr): + _module = self._resolve() + value = getattr(_module, attr) + setattr(self, attr, value) + return value + + +class _LazyModule(types.ModuleType): + + def __init__(self, name): + super(_LazyModule, self).__init__(name) + self.__doc__ = self.__class__.__doc__ + + def __dir__(self): + attrs = ["__doc__", "__name__"] + attrs += [attr.name for attr in self._moved_attributes] + return attrs + + # Subclasses should override this + _moved_attributes = [] + + +class MovedAttribute(_LazyDescr): + + def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None): + super(MovedAttribute, self).__init__(name) + if PY3: + if new_mod is None: + new_mod = name + self.mod = new_mod + if new_attr is None: + if old_attr is None: + new_attr = name + else: + new_attr = old_attr + self.attr = new_attr + else: + self.mod = old_mod + if old_attr is None: + old_attr = name + self.attr = old_attr + + def _resolve(self): + module = _import_module(self.mod) + return getattr(module, self.attr) + + +class _SixMetaPathImporter(object): + + """ + A meta path importer to import six.moves and its submodules. + + This class implements a PEP302 finder and loader. It should be compatible + with Python 2.5 and all existing versions of Python3 + """ + + def __init__(self, six_module_name): + self.name = six_module_name + self.known_modules = {} + + def _add_module(self, mod, *fullnames): + for fullname in fullnames: + self.known_modules[self.name + "." + fullname] = mod + + def _get_module(self, fullname): + return self.known_modules[self.name + "." + fullname] + + def find_module(self, fullname, path=None): + if fullname in self.known_modules: + return self + return None + + def __get_module(self, fullname): + try: + return self.known_modules[fullname] + except KeyError: + raise ImportError("This loader does not know module " + fullname) + + def load_module(self, fullname): + try: + # in case of a reload + return sys.modules[fullname] + except KeyError: + pass + mod = self.__get_module(fullname) + if isinstance(mod, MovedModule): + mod = mod._resolve() + else: + mod.__loader__ = self + sys.modules[fullname] = mod + return mod + + def is_package(self, fullname): + """ + Return true, if the named module is a package. + + We need this method to get correct spec objects with + Python 3.4 (see PEP451) + """ + return hasattr(self.__get_module(fullname), "__path__") + + def get_code(self, fullname): + """Return None + + Required, if is_package is implemented""" + self.__get_module(fullname) # eventually raises ImportError + return None + get_source = get_code # same as get_code + +_importer = _SixMetaPathImporter(__name__) + + +class _MovedItems(_LazyModule): + + """Lazy loading of moved objects""" + __path__ = [] # mark as package + + +_moved_attributes = [ + MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"), + MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"), + MovedAttribute("filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"), + MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"), + MovedAttribute("intern", "__builtin__", "sys"), + MovedAttribute("map", "itertools", "builtins", "imap", "map"), + MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"), + MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"), + MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"), + MovedAttribute("reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload"), + MovedAttribute("reduce", "__builtin__", "functools"), + MovedAttribute("shlex_quote", "pipes", "shlex", "quote"), + MovedAttribute("StringIO", "StringIO", "io"), + MovedAttribute("UserDict", "UserDict", "collections"), + MovedAttribute("UserList", "UserList", "collections"), + MovedAttribute("UserString", "UserString", "collections"), + MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"), + MovedAttribute("zip", "itertools", "builtins", "izip", "zip"), + MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"), + MovedModule("builtins", "__builtin__"), + MovedModule("configparser", "ConfigParser"), + MovedModule("copyreg", "copy_reg"), + MovedModule("dbm_gnu", "gdbm", "dbm.gnu"), + MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread"), + MovedModule("http_cookiejar", "cookielib", "http.cookiejar"), + MovedModule("http_cookies", "Cookie", "http.cookies"), + MovedModule("html_entities", "htmlentitydefs", "html.entities"), + MovedModule("html_parser", "HTMLParser", "html.parser"), + MovedModule("http_client", "httplib", "http.client"), + MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"), + MovedModule("email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart"), + MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"), + MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"), + MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"), + MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"), + MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"), + MovedModule("cPickle", "cPickle", "pickle"), + MovedModule("queue", "Queue"), + MovedModule("reprlib", "repr"), + MovedModule("socketserver", "SocketServer"), + MovedModule("_thread", "thread", "_thread"), + MovedModule("tkinter", "Tkinter"), + MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"), + MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"), + MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"), + MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"), + MovedModule("tkinter_tix", "Tix", "tkinter.tix"), + MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"), + MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"), + MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"), + MovedModule("tkinter_colorchooser", "tkColorChooser", + "tkinter.colorchooser"), + MovedModule("tkinter_commondialog", "tkCommonDialog", + "tkinter.commondialog"), + MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"), + MovedModule("tkinter_font", "tkFont", "tkinter.font"), + MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"), + MovedModule("tkinter_tksimpledialog", "tkSimpleDialog", + "tkinter.simpledialog"), + MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"), + MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"), + MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"), + MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"), + MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"), + MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"), +] +# Add windows specific modules. +if sys.platform == "win32": + _moved_attributes += [ + MovedModule("winreg", "_winreg"), + ] + +for attr in _moved_attributes: + setattr(_MovedItems, attr.name, attr) + if isinstance(attr, MovedModule): + _importer._add_module(attr, "moves." + attr.name) +del attr + +_MovedItems._moved_attributes = _moved_attributes + +moves = _MovedItems(__name__ + ".moves") +_importer._add_module(moves, "moves") + + +class Module_six_moves_urllib_parse(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_parse""" + + +_urllib_parse_moved_attributes = [ + MovedAttribute("ParseResult", "urlparse", "urllib.parse"), + MovedAttribute("SplitResult", "urlparse", "urllib.parse"), + MovedAttribute("parse_qs", "urlparse", "urllib.parse"), + MovedAttribute("parse_qsl", "urlparse", "urllib.parse"), + MovedAttribute("urldefrag", "urlparse", "urllib.parse"), + MovedAttribute("urljoin", "urlparse", "urllib.parse"), + MovedAttribute("urlparse", "urlparse", "urllib.parse"), + MovedAttribute("urlsplit", "urlparse", "urllib.parse"), + MovedAttribute("urlunparse", "urlparse", "urllib.parse"), + MovedAttribute("urlunsplit", "urlparse", "urllib.parse"), + MovedAttribute("quote", "urllib", "urllib.parse"), + MovedAttribute("quote_plus", "urllib", "urllib.parse"), + MovedAttribute("unquote", "urllib", "urllib.parse"), + MovedAttribute("unquote_plus", "urllib", "urllib.parse"), + MovedAttribute("urlencode", "urllib", "urllib.parse"), + MovedAttribute("splitquery", "urllib", "urllib.parse"), + MovedAttribute("splittag", "urllib", "urllib.parse"), + MovedAttribute("splituser", "urllib", "urllib.parse"), + MovedAttribute("uses_fragment", "urlparse", "urllib.parse"), + MovedAttribute("uses_netloc", "urlparse", "urllib.parse"), + MovedAttribute("uses_params", "urlparse", "urllib.parse"), + MovedAttribute("uses_query", "urlparse", "urllib.parse"), + MovedAttribute("uses_relative", "urlparse", "urllib.parse"), +] +for attr in _urllib_parse_moved_attributes: + setattr(Module_six_moves_urllib_parse, attr.name, attr) +del attr + +Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes + +_importer._add_module(Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"), + "moves.urllib_parse", "moves.urllib.parse") + + +class Module_six_moves_urllib_error(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_error""" + + +_urllib_error_moved_attributes = [ + MovedAttribute("URLError", "urllib2", "urllib.error"), + MovedAttribute("HTTPError", "urllib2", "urllib.error"), + MovedAttribute("ContentTooShortError", "urllib", "urllib.error"), +] +for attr in _urllib_error_moved_attributes: + setattr(Module_six_moves_urllib_error, attr.name, attr) +del attr + +Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes + +_importer._add_module(Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"), + "moves.urllib_error", "moves.urllib.error") + + +class Module_six_moves_urllib_request(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_request""" + + +_urllib_request_moved_attributes = [ + MovedAttribute("urlopen", "urllib2", "urllib.request"), + MovedAttribute("install_opener", "urllib2", "urllib.request"), + MovedAttribute("build_opener", "urllib2", "urllib.request"), + MovedAttribute("pathname2url", "urllib", "urllib.request"), + MovedAttribute("url2pathname", "urllib", "urllib.request"), + MovedAttribute("getproxies", "urllib", "urllib.request"), + MovedAttribute("Request", "urllib2", "urllib.request"), + MovedAttribute("OpenerDirector", "urllib2", "urllib.request"), + MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"), + MovedAttribute("ProxyHandler", "urllib2", "urllib.request"), + MovedAttribute("BaseHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"), + MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"), + MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"), + MovedAttribute("FileHandler", "urllib2", "urllib.request"), + MovedAttribute("FTPHandler", "urllib2", "urllib.request"), + MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"), + MovedAttribute("UnknownHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"), + MovedAttribute("urlretrieve", "urllib", "urllib.request"), + MovedAttribute("urlcleanup", "urllib", "urllib.request"), + MovedAttribute("URLopener", "urllib", "urllib.request"), + MovedAttribute("FancyURLopener", "urllib", "urllib.request"), + MovedAttribute("proxy_bypass", "urllib", "urllib.request"), +] +for attr in _urllib_request_moved_attributes: + setattr(Module_six_moves_urllib_request, attr.name, attr) +del attr + +Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes + +_importer._add_module(Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"), + "moves.urllib_request", "moves.urllib.request") + + +class Module_six_moves_urllib_response(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_response""" + + +_urllib_response_moved_attributes = [ + MovedAttribute("addbase", "urllib", "urllib.response"), + MovedAttribute("addclosehook", "urllib", "urllib.response"), + MovedAttribute("addinfo", "urllib", "urllib.response"), + MovedAttribute("addinfourl", "urllib", "urllib.response"), +] +for attr in _urllib_response_moved_attributes: + setattr(Module_six_moves_urllib_response, attr.name, attr) +del attr + +Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes + +_importer._add_module(Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"), + "moves.urllib_response", "moves.urllib.response") + + +class Module_six_moves_urllib_robotparser(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_robotparser""" + + +_urllib_robotparser_moved_attributes = [ + MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"), +] +for attr in _urllib_robotparser_moved_attributes: + setattr(Module_six_moves_urllib_robotparser, attr.name, attr) +del attr + +Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes + +_importer._add_module(Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"), + "moves.urllib_robotparser", "moves.urllib.robotparser") + + +class Module_six_moves_urllib(types.ModuleType): + + """Create a six.moves.urllib namespace that resembles the Python 3 namespace""" + __path__ = [] # mark as package + parse = _importer._get_module("moves.urllib_parse") + error = _importer._get_module("moves.urllib_error") + request = _importer._get_module("moves.urllib_request") + response = _importer._get_module("moves.urllib_response") + robotparser = _importer._get_module("moves.urllib_robotparser") + + def __dir__(self): + return ['parse', 'error', 'request', 'response', 'robotparser'] + +_importer._add_module(Module_six_moves_urllib(__name__ + ".moves.urllib"), + "moves.urllib") + + +def add_move(move): + """Add an item to six.moves.""" + setattr(_MovedItems, move.name, move) + + +def remove_move(name): + """Remove item from six.moves.""" + try: + delattr(_MovedItems, name) + except AttributeError: + try: + del moves.__dict__[name] + except KeyError: + raise AttributeError("no such move, %r" % (name,)) + + +if PY3: + _meth_func = "__func__" + _meth_self = "__self__" + + _func_closure = "__closure__" + _func_code = "__code__" + _func_defaults = "__defaults__" + _func_globals = "__globals__" +else: + _meth_func = "im_func" + _meth_self = "im_self" + + _func_closure = "func_closure" + _func_code = "func_code" + _func_defaults = "func_defaults" + _func_globals = "func_globals" + + +try: + advance_iterator = next +except NameError: + def advance_iterator(it): + return it.next() +next = advance_iterator + + +try: + callable = callable +except NameError: + def callable(obj): + return any("__call__" in klass.__dict__ for klass in type(obj).__mro__) + + +if PY3: + def get_unbound_function(unbound): + return unbound + + create_bound_method = types.MethodType + + def create_unbound_method(func, cls): + return func + + Iterator = object +else: + def get_unbound_function(unbound): + return unbound.im_func + + def create_bound_method(func, obj): + return types.MethodType(func, obj, obj.__class__) + + def create_unbound_method(func, cls): + return types.MethodType(func, None, cls) + + class Iterator(object): + + def next(self): + return type(self).__next__(self) + + callable = callable +_add_doc(get_unbound_function, + """Get the function out of a possibly unbound function""") + + +get_method_function = operator.attrgetter(_meth_func) +get_method_self = operator.attrgetter(_meth_self) +get_function_closure = operator.attrgetter(_func_closure) +get_function_code = operator.attrgetter(_func_code) +get_function_defaults = operator.attrgetter(_func_defaults) +get_function_globals = operator.attrgetter(_func_globals) + + +if PY3: + def iterkeys(d, **kw): + return iter(d.keys(**kw)) + + def itervalues(d, **kw): + return iter(d.values(**kw)) + + def iteritems(d, **kw): + return iter(d.items(**kw)) + + def iterlists(d, **kw): + return iter(d.lists(**kw)) + + viewkeys = operator.methodcaller("keys") + + viewvalues = operator.methodcaller("values") + + viewitems = operator.methodcaller("items") +else: + def iterkeys(d, **kw): + return d.iterkeys(**kw) + + def itervalues(d, **kw): + return d.itervalues(**kw) + + def iteritems(d, **kw): + return d.iteritems(**kw) + + def iterlists(d, **kw): + return d.iterlists(**kw) + + viewkeys = operator.methodcaller("viewkeys") + + viewvalues = operator.methodcaller("viewvalues") + + viewitems = operator.methodcaller("viewitems") + +_add_doc(iterkeys, "Return an iterator over the keys of a dictionary.") +_add_doc(itervalues, "Return an iterator over the values of a dictionary.") +_add_doc(iteritems, + "Return an iterator over the (key, value) pairs of a dictionary.") +_add_doc(iterlists, + "Return an iterator over the (key, [values]) pairs of a dictionary.") + + +if PY3: + def b(s): + return s.encode("latin-1") + + def u(s): + return s + unichr = chr + import struct + int2byte = struct.Struct(">B").pack + del struct + byte2int = operator.itemgetter(0) + indexbytes = operator.getitem + iterbytes = iter + import io + StringIO = io.StringIO + BytesIO = io.BytesIO + _assertCountEqual = "assertCountEqual" + if sys.version_info[1] <= 1: + _assertRaisesRegex = "assertRaisesRegexp" + _assertRegex = "assertRegexpMatches" + else: + _assertRaisesRegex = "assertRaisesRegex" + _assertRegex = "assertRegex" +else: + def b(s): + return s + # Workaround for standalone backslash + + def u(s): + return unicode(s.replace(r'\\', r'\\\\'), "unicode_escape") + unichr = unichr + int2byte = chr + + def byte2int(bs): + return ord(bs[0]) + + def indexbytes(buf, i): + return ord(buf[i]) + iterbytes = functools.partial(itertools.imap, ord) + import StringIO + StringIO = BytesIO = StringIO.StringIO + _assertCountEqual = "assertItemsEqual" + _assertRaisesRegex = "assertRaisesRegexp" + _assertRegex = "assertRegexpMatches" +_add_doc(b, """Byte literal""") +_add_doc(u, """Text literal""") + + +def assertCountEqual(self, *args, **kwargs): + return getattr(self, _assertCountEqual)(*args, **kwargs) + + +def assertRaisesRegex(self, *args, **kwargs): + return getattr(self, _assertRaisesRegex)(*args, **kwargs) + + +def assertRegex(self, *args, **kwargs): + return getattr(self, _assertRegex)(*args, **kwargs) + + +if PY3: + exec_ = getattr(moves.builtins, "exec") + + def reraise(tp, value, tb=None): + if value is None: + value = tp() + if value.__traceback__ is not tb: + raise value.with_traceback(tb) + raise value + +else: + def exec_(_code_, _globs_=None, _locs_=None): + """Execute code in a namespace.""" + if _globs_ is None: + frame = sys._getframe(1) + _globs_ = frame.f_globals + if _locs_ is None: + _locs_ = frame.f_locals + del frame + elif _locs_ is None: + _locs_ = _globs_ + exec("""exec _code_ in _globs_, _locs_""") + + exec_("""def reraise(tp, value, tb=None): + raise tp, value, tb +""") + + +if sys.version_info[:2] == (3, 2): + exec_("""def raise_from(value, from_value): + if from_value is None: + raise value + raise value from from_value +""") +elif sys.version_info[:2] > (3, 2): + exec_("""def raise_from(value, from_value): + raise value from from_value +""") +else: + def raise_from(value, from_value): + raise value + + +print_ = getattr(moves.builtins, "print", None) +if print_ is None: + def print_(*args, **kwargs): + """The new-style print function for Python 2.4 and 2.5.""" + fp = kwargs.pop("file", sys.stdout) + if fp is None: + return + + def write(data): + if not isinstance(data, basestring): + data = str(data) + # If the file has an encoding, encode unicode with it. + if (isinstance(fp, file) and + isinstance(data, unicode) and + fp.encoding is not None): + errors = getattr(fp, "errors", None) + if errors is None: + errors = "strict" + data = data.encode(fp.encoding, errors) + fp.write(data) + want_unicode = False + sep = kwargs.pop("sep", None) + if sep is not None: + if isinstance(sep, unicode): + want_unicode = True + elif not isinstance(sep, str): + raise TypeError("sep must be None or a string") + end = kwargs.pop("end", None) + if end is not None: + if isinstance(end, unicode): + want_unicode = True + elif not isinstance(end, str): + raise TypeError("end must be None or a string") + if kwargs: + raise TypeError("invalid keyword arguments to print()") + if not want_unicode: + for arg in args: + if isinstance(arg, unicode): + want_unicode = True + break + if want_unicode: + newline = unicode("\n") + space = unicode(" ") + else: + newline = "\n" + space = " " + if sep is None: + sep = space + if end is None: + end = newline + for i, arg in enumerate(args): + if i: + write(sep) + write(arg) + write(end) +if sys.version_info[:2] < (3, 3): + _print = print_ + + def print_(*args, **kwargs): + fp = kwargs.get("file", sys.stdout) + flush = kwargs.pop("flush", False) + _print(*args, **kwargs) + if flush and fp is not None: + fp.flush() + +_add_doc(reraise, """Reraise an exception.""") + +if sys.version_info[0:2] < (3, 4): + def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS, + updated=functools.WRAPPER_UPDATES): + def wrapper(f): + f = functools.wraps(wrapped, assigned, updated)(f) + f.__wrapped__ = wrapped + return f + return wrapper +else: + wraps = functools.wraps + + +def with_metaclass(meta, *bases): + """Create a base class with a metaclass.""" + # This requires a bit of explanation: the basic idea is to make a dummy + # metaclass for one level of class instantiation that replaces itself with + # the actual metaclass. + class metaclass(meta): + + def __new__(cls, name, this_bases, d): + return meta(name, bases, d) + return type.__new__(metaclass, 'temporary_class', (), {}) + + +def add_metaclass(metaclass): + """Class decorator for creating a class with a metaclass.""" + def wrapper(cls): + orig_vars = cls.__dict__.copy() + slots = orig_vars.get('__slots__') + if slots is not None: + if isinstance(slots, str): + slots = [slots] + for slots_var in slots: + orig_vars.pop(slots_var) + orig_vars.pop('__dict__', None) + orig_vars.pop('__weakref__', None) + return metaclass(cls.__name__, cls.__bases__, orig_vars) + return wrapper + + +def python_2_unicode_compatible(klass): + """ + A decorator that defines __unicode__ and __str__ methods under Python 2. + Under Python 3 it does nothing. + + To support Python 2 and 3 with a single code base, define a __str__ method + returning text and apply this decorator to the class. + """ + if PY2: + if '__str__' not in klass.__dict__: + raise ValueError("@python_2_unicode_compatible cannot be applied " + "to %s because it doesn't define __str__()." % + klass.__name__) + klass.__unicode__ = klass.__str__ + klass.__str__ = lambda self: self.__unicode__().encode('utf-8') + return klass + + +# Complete the moves implementation. +# This code is at the end of this module to speed up module loading. +# Turn this module into a package. +__path__ = [] # required for PEP 302 and PEP 451 +__package__ = __name__ # see PEP 366 @ReservedAssignment +if globals().get("__spec__") is not None: + __spec__.submodule_search_locations = [] # PEP 451 @UndefinedVariable +# Remove other six meta path importers, since they cause problems. This can +# happen if six is removed from sys.modules and then reloaded. (Setuptools does +# this for some reason.) +if sys.meta_path: + for i, importer in enumerate(sys.meta_path): + # Here's some real nastiness: Another "instance" of the six module might + # be floating around. Therefore, we can't use isinstance() to check for + # the six meta path importer, since the other six instance will have + # inserted an importer with different class. + if (type(importer).__name__ == "_SixMetaPathImporter" and + importer.name == __name__): + del sys.meta_path[i] + break + del i, importer +# Finally, add the importer to the meta path import hook. +sys.meta_path.append(_importer) diff --git a/venv/lib/python3.8/site-packages/pkg_resources/extern/__init__.py b/venv/lib/python3.8/site-packages/pkg_resources/extern/__init__.py new file mode 100644 index 0000000..c1eb9e9 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pkg_resources/extern/__init__.py @@ -0,0 +1,73 @@ +import sys + + +class VendorImporter: + """ + A PEP 302 meta path importer for finding optionally-vendored + or otherwise naturally-installed packages from root_name. + """ + + def __init__(self, root_name, vendored_names=(), vendor_pkg=None): + self.root_name = root_name + self.vendored_names = set(vendored_names) + self.vendor_pkg = vendor_pkg or root_name.replace('extern', '_vendor') + + @property + def search_path(self): + """ + Search first the vendor package then as a natural package. + """ + yield self.vendor_pkg + '.' + yield '' + + def find_module(self, fullname, path=None): + """ + Return self when fullname starts with root_name and the + target module is one vendored through this importer. + """ + root, base, target = fullname.partition(self.root_name + '.') + if root: + return + if not any(map(target.startswith, self.vendored_names)): + return + return self + + def load_module(self, fullname): + """ + Iterate over the search path to locate and load fullname. + """ + root, base, target = fullname.partition(self.root_name + '.') + for prefix in self.search_path: + try: + extant = prefix + target + __import__(extant) + mod = sys.modules[extant] + sys.modules[fullname] = mod + # mysterious hack: + # Remove the reference to the extant package/module + # on later Python versions to cause relative imports + # in the vendor package to resolve the same modules + # as those going through this importer. + if prefix and sys.version_info > (3, 3): + del sys.modules[extant] + return mod + except ImportError: + pass + else: + raise ImportError( + "The '{target}' package is required; " + "normally this is bundled with this package so if you get " + "this warning, consult the packager of your " + "distribution.".format(**locals()) + ) + + def install(self): + """ + Install this importer into sys.meta_path if not already present. + """ + if self not in sys.meta_path: + sys.meta_path.append(self) + + +names = 'packaging', 'pyparsing', 'six', 'appdirs' +VendorImporter(__name__, names).install() diff --git a/venv/lib/python3.8/site-packages/pkg_resources/py31compat.py b/venv/lib/python3.8/site-packages/pkg_resources/py31compat.py new file mode 100644 index 0000000..a381c42 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pkg_resources/py31compat.py @@ -0,0 +1,23 @@ +import os +import errno +import sys + +from .extern import six + + +def _makedirs_31(path, exist_ok=False): + try: + os.makedirs(path) + except OSError as exc: + if not exist_ok or exc.errno != errno.EEXIST: + raise + + +# rely on compatibility behavior until mode considerations +# and exists_ok considerations are disentangled. +# See https://github.com/pypa/setuptools/pull/1083#issuecomment-315168663 +needs_makedirs = ( + six.PY2 or + (3, 4) <= sys.version_info < (3, 4, 1) +) +makedirs = _makedirs_31 if needs_makedirs else os.makedirs diff --git a/venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/INSTALLER b/venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/LICENSE.dual b/venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/LICENSE.dual new file mode 100644 index 0000000..c2730fd --- /dev/null +++ b/venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/LICENSE.dual @@ -0,0 +1,792 @@ + NOTICE: You can find here the GPLv3 license and after the Lesser GPLv3 license. +You may choose either license. + + + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. [http://fsf.org/] + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + + This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + + 0. Additional Definitions. + + As used herein, "this License" refers to version 3 of the GNU Lesser +General Public License, and the "GNU GPL" refers to version 3 of the GNU +General Public License. + + "The Library" refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An "Application" is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A "Combined Work" is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the "Linked +Version". + + The "Minimal Corresponding Source" for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The "Corresponding Application Code" for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + + 1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + + 2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort to + ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + + 3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that the + Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this license + document. + + 4. Combined Works. + + You may convey a Combined Work under terms of your choice that, +taken together, effectively do not restrict modification of the +portions of the Library contained in the Combined Work and reverse +engineering for debugging such modifications, if you also do each of +the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this license + document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of this + License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (a) uses at run time + a copy of the Library already present on the user's computer + system, and (b) will operate properly with a modified version + of the Library that is interface-compatible with the Linked + Version. + + e) Provide Installation Information, but only if you would otherwise + be required to provide such information under section 6 of the + GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the + Application with a modified version of the Linked Version. (If + you use option 4d0, the Installation Information must accompany + the Minimal Corresponding Source and Corresponding Application + Code. If you use option 4d1, you must provide the Installation + Information in the manner specified by section 6 of the GNU GPL + for conveying Corresponding Source.) + + 5. Combined Libraries. + + You may place library facilities that are a work based on the +Library side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work based + on the Library, uncombined with any other library facilities, + conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of it + is a work based on the Library, and explaining where to find the + accompanying uncombined form of the same work. + + 6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + + Each version is given a distinguishing version number. If the +Library as you received it specifies that a certain numbered version +of the GNU Lesser General Public License "or any later version" +applies to it, you have the option of following the terms and +conditions either of that published version or of any later version +published by the Free Software Foundation. If the Library as you +received it does not specify a version number of the GNU Lesser +General Public License, you may choose any version of the GNU Lesser +General Public License ever published by the Free Software Foundation. + + If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the +Library. + + + + + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. [http://fsf.org/] + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. diff --git a/venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/METADATA b/venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/METADATA new file mode 100644 index 0000000..7007758 --- /dev/null +++ b/venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/METADATA @@ -0,0 +1,285 @@ +Metadata-Version: 2.1 +Name: python-telegram-bot +Version: 13.6 +Summary: We have made you a wrapper you can't refuse +Home-page: https://python-telegram-bot.org/ +Author: Leandro Toledo +Author-email: devs@python-telegram-bot.org +License: LGPLv3 +Download-URL: https://pypi.org/project/python-telegram-bot/ +Project-URL: Documentation, https://python-telegram-bot.readthedocs.io +Project-URL: Bug Tracker, https://github.com/python-telegram-bot/python-telegram-bot/issues +Project-URL: Source Code, https://github.com/python-telegram-bot/python-telegram-bot +Project-URL: News, https://t.me/pythontelegrambotchannel +Project-URL: Changelog, https://python-telegram-bot.readthedocs.io/en/stable/changelog.html +Keywords: python telegram bot api wrapper +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3) +Classifier: Operating System :: OS Independent +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: Communications :: Chat +Classifier: Topic :: Internet +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/x-rst +Requires-Dist: certifi +Requires-Dist: tornado (>=6.1) +Requires-Dist: APScheduler (==3.6.3) +Requires-Dist: pytz (>=2018.6) +Requires-Dist: cachetools (==4.2.2) +Provides-Extra: json +Requires-Dist: ujson ; extra == 'json' +Provides-Extra: passport +Requires-Dist: cryptography (!=3.4,!=3.4.1,!=3.4.2,!=3.4.3) ; extra == 'passport' +Provides-Extra: socks +Requires-Dist: PySocks ; extra == 'socks' + +.. + Make user to apply any changes to this file to README_RAW.rst as well! + +.. image:: https://github.com/python-telegram-bot/logos/blob/master/logo-text/png/ptb-logo-text_768.png?raw=true + :align: center + :target: https://python-telegram-bot.org + :alt: python-telegram-bot Logo + +We have made you a wrapper you can't refuse + +We have a vibrant community of developers helping each other in our `Telegram group `_. Join us! + +*Stay tuned for library updates and new releases on our* `Telegram Channel `_. + +.. image:: https://img.shields.io/pypi/v/python-telegram-bot.svg + :target: https://pypi.org/project/python-telegram-bot/ + :alt: PyPi Package Version + +.. image:: https://img.shields.io/pypi/pyversions/python-telegram-bot.svg + :target: https://pypi.org/project/python-telegram-bot/ + :alt: Supported Python versions + +.. image:: https://img.shields.io/badge/Bot%20API-5.2-blue?logo=telegram + :target: https://core.telegram.org/bots/api-changelog + :alt: Supported Bot API versions + +.. image:: https://img.shields.io/pypi/dm/python-telegram-bot + :target: https://pypistats.org/packages/python-telegram-bot + :alt: PyPi Package Monthly Download + +.. image:: https://readthedocs.org/projects/python-telegram-bot/badge/?version=stable + :target: https://python-telegram-bot.readthedocs.io/en/stable/?badge=stable + :alt: Documentation Status + +.. image:: https://img.shields.io/pypi/l/python-telegram-bot.svg + :target: https://www.gnu.org/licenses/lgpl-3.0.html + :alt: LGPLv3 License + +.. image:: https://github.com/python-telegram-bot/python-telegram-bot/workflows/GitHub%20Actions/badge.svg + :target: https://github.com/python-telegram-bot/python-telegram-bot/ + :alt: Github Actions workflow + +.. image:: https://codecov.io/gh/python-telegram-bot/python-telegram-bot/branch/master/graph/badge.svg + :target: https://codecov.io/gh/python-telegram-bot/python-telegram-bot + :alt: Code coverage + +.. image:: http://isitmaintained.com/badge/resolution/python-telegram-bot/python-telegram-bot.svg + :target: http://isitmaintained.com/project/python-telegram-bot/python-telegram-bot + :alt: Median time to resolve an issue + +.. image:: https://api.codacy.com/project/badge/Grade/99d901eaa09b44b4819aec05c330c968 + :target: https://www.codacy.com/app/python-telegram-bot/python-telegram-bot?utm_source=github.com&utm_medium=referral&utm_content=python-telegram-bot/python-telegram-bot&utm_campaign=Badge_Grade + :alt: Code quality: Codacy + +.. image:: https://deepsource.io/gh/python-telegram-bot/python-telegram-bot.svg/?label=active+issues + :target: https://deepsource.io/gh/python-telegram-bot/python-telegram-bot/?ref=repository-badge + :alt: Code quality: DeepSource + +.. image:: https://img.shields.io/badge/code%20style-black-000000.svg + :target: https://github.com/psf/black + +.. image:: https://img.shields.io/badge/Telegram-Group-blue.svg?logo=telegram + :target: https://telegram.me/pythontelegrambotgroup + :alt: Telegram Group + +================= +Table of contents +================= + +- `Introduction`_ + +- `Telegram API support`_ + +- `Installing`_ + +- `Getting started`_ + + #. `Learning by example`_ + + #. `Logging`_ + + #. `Documentation`_ + +- `Getting help`_ + +- `Contributing`_ + +- `License`_ + +============ +Introduction +============ + +This library provides a pure Python interface for the +`Telegram Bot API `_. +It's compatible with Python versions 3.6.2+. PTB might also work on `PyPy `_, though there have been a lot of issues before. Hence, PyPy is not officially supported. + +In addition to the pure API implementation, this library features a number of high-level classes to +make the development of bots easy and straightforward. These classes are contained in the +``telegram.ext`` submodule. + +A pure API implementation *without* ``telegram.ext`` is available as the standalone package ``python-telegram-bot-raw``. `See here for details. `_ + +---- +Note +---- + +Installing both ``python-telegram-bot`` and ``python-telegram-bot-raw`` in conjunction will result in undesired side-effects, so only install *one* of both. + +==================== +Telegram API support +==================== + +All types and methods of the Telegram Bot API **5.2** are supported. + +========== +Installing +========== + +You can install or upgrade python-telegram-bot with: + +.. code:: shell + + $ pip install python-telegram-bot --upgrade + +Or you can install from source with: + +.. code:: shell + + $ git clone https://github.com/python-telegram-bot/python-telegram-bot --recursive + $ cd python-telegram-bot + $ python setup.py install + +In case you have a previously cloned local repository already, you should initialize the added urllib3 submodule before installing with: + +.. code:: shell + + $ git submodule update --init --recursive + +--------------------- +Optional Dependencies +--------------------- + +PTB can be installed with optional dependencies: + +* ``pip install python-telegram-bot[passport]`` installs the `cryptography `_ library. Use this, if you want to use Telegram Passport related functionality. +* ``pip install python-telegram-bot[ujson]`` installs the `ujson `_ library. It will then be used for JSON de- & encoding, which can bring speed up compared to the standard `json `_ library. +* ``pip install python-telegram-bot[socks]`` installs the `PySocks `_ library. Use this, if you want to work behind a Socks5 server. + +=============== +Getting started +=============== + +Our Wiki contains a lot of resources to get you started with ``python-telegram-bot``: + +- `Introduction to the API `_ +- Tutorial: `Your first Bot `_ + +Other references: + +- `Telegram API documentation `_ +- `python-telegram-bot documentation `_ + +------------------- +Learning by example +------------------- + +We believe that the best way to learn this package is by example. Here +are some examples for you to review. Even if it is not your approach for learning, please take a +look at ``echobot.py``, it is the de facto base for most of the bots out there. Best of all, +the code for these examples are released to the public domain, so you can start by grabbing the +code and building on top of it. + +Visit `this page `_ to discover the official examples or look at the examples on the `wiki `_ to see other bots the community has built. + +------- +Logging +------- + +This library uses the ``logging`` module. To set up logging to standard output, put: + +.. code:: python + + import logging + logging.basicConfig(level=logging.DEBUG, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') + +at the beginning of your script. + +You can also use logs in your application by calling ``logging.getLogger()`` and setting the log level you want: + +.. code:: python + + logger = logging.getLogger() + logger.setLevel(logging.INFO) + +If you want DEBUG logs instead: + +.. code:: python + + logger.setLevel(logging.DEBUG) + + +============= +Documentation +============= + +``python-telegram-bot``'s documentation lives at `readthedocs.io `_. + +============ +Getting help +============ + +You can get help in several ways: + +1. We have a vibrant community of developers helping each other in our `Telegram group `_. Join us! + +2. Report bugs, request new features or ask questions by `creating an issue `_ or `a discussion `_. + +3. Our `Wiki pages `_ offer a growing amount of resources. + +4. You can even ask for help on Stack Overflow using the `python-telegram-bot tag `_. + + +============ +Contributing +============ + +Contributions of all sizes are welcome. Please review our `contribution guidelines `_ to get started. You can also help by `reporting bugs `_. + +======== +Donating +======== +Occasionally we are asked if we accept donations to support the development. While we appreciate the thought, maintaining PTB is our hobby and we have almost no running costs for it. We therefore have nothing set up to accept donations. If you still want to donate, we kindly ask you to donate to another open source project/initiative of your choice instead. + +======= +License +======= + +You may copy, distribute and modify the software provided that modifications are described and licensed for free under `LGPL-3 `_. Derivatives works (including modifications or anything statically linked to the library) can only be redistributed under LGPL-3, but applications that use the library don't have to be. + + diff --git a/venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/RECORD b/venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/RECORD new file mode 100644 index 0000000..6aaf6ff --- /dev/null +++ b/venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/RECORD @@ -0,0 +1,365 @@ +python_telegram_bot-13.6.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +python_telegram_bot-13.6.dist-info/LICENSE.dual,sha256=eblsAdLmpvSxNh8leJceEVCwU7rNitnIgMs8X_kIEd8,40192 +python_telegram_bot-13.6.dist-info/METADATA,sha256=B8PggedtxXvPXZ0BrmN10TXhZgI26UXIRmvpALLSkac,11561 +python_telegram_bot-13.6.dist-info/RECORD,, +python_telegram_bot-13.6.dist-info/WHEEL,sha256=OqRkF0eY5GHssMorFjlbTIq072vpHpF60fIQA6lS9xA,92 +python_telegram_bot-13.6.dist-info/top_level.txt,sha256=tfrh9q1x_2mn166E6RftggS4sc4T_5C1BYamJkSoWg0,9 +telegram/__init__.py,sha256=N_TlcPZ2dH5XsqLHi69EiuN9gBeRpWsppreNYoyHZpI,10121 +telegram/__main__.py,sha256=9NpdO-07LdnbowBaEn2e2W6FwQVJrrARQ0KKF3_9FjM,1779 +telegram/__pycache__/__init__.cpython-38.pyc,, +telegram/__pycache__/__main__.cpython-38.pyc,, +telegram/__pycache__/base.cpython-38.pyc,, +telegram/__pycache__/bot.cpython-38.pyc,, +telegram/__pycache__/botcommand.cpython-38.pyc,, +telegram/__pycache__/callbackquery.cpython-38.pyc,, +telegram/__pycache__/chat.cpython-38.pyc,, +telegram/__pycache__/chataction.cpython-38.pyc,, +telegram/__pycache__/chatinvitelink.cpython-38.pyc,, +telegram/__pycache__/chatlocation.cpython-38.pyc,, +telegram/__pycache__/chatmember.cpython-38.pyc,, +telegram/__pycache__/chatmemberupdated.cpython-38.pyc,, +telegram/__pycache__/chatpermissions.cpython-38.pyc,, +telegram/__pycache__/choseninlineresult.cpython-38.pyc,, +telegram/__pycache__/constants.cpython-38.pyc,, +telegram/__pycache__/dice.cpython-38.pyc,, +telegram/__pycache__/error.cpython-38.pyc,, +telegram/__pycache__/forcereply.cpython-38.pyc,, +telegram/__pycache__/keyboardbutton.cpython-38.pyc,, +telegram/__pycache__/keyboardbuttonpolltype.cpython-38.pyc,, +telegram/__pycache__/loginurl.cpython-38.pyc,, +telegram/__pycache__/message.cpython-38.pyc,, +telegram/__pycache__/messageautodeletetimerchanged.cpython-38.pyc,, +telegram/__pycache__/messageentity.cpython-38.pyc,, +telegram/__pycache__/messageid.cpython-38.pyc,, +telegram/__pycache__/parsemode.cpython-38.pyc,, +telegram/__pycache__/poll.cpython-38.pyc,, +telegram/__pycache__/proximityalerttriggered.cpython-38.pyc,, +telegram/__pycache__/replykeyboardmarkup.cpython-38.pyc,, +telegram/__pycache__/replykeyboardremove.cpython-38.pyc,, +telegram/__pycache__/replymarkup.cpython-38.pyc,, +telegram/__pycache__/update.cpython-38.pyc,, +telegram/__pycache__/user.cpython-38.pyc,, +telegram/__pycache__/userprofilephotos.cpython-38.pyc,, +telegram/__pycache__/version.cpython-38.pyc,, +telegram/__pycache__/voicechat.cpython-38.pyc,, +telegram/__pycache__/webhookinfo.cpython-38.pyc,, +telegram/base.py,sha256=f1TSIMJTVpnoy0yZkyk4LwcNK5nacOKSYl26gYV1Q94,5148 +telegram/bot.py,sha256=x6fFEqq__TWT1K-hCHGOZSlNTx8sDgioMxw86-hH2t4,239317 +telegram/botcommand.py,sha256=bgKiJEvPaUI5p00zuegf60H_C0aQSPbgE08iNYvICXw,1869 +telegram/callbackquery.py,sha256=Iph4EsFAFyTn-oHYylCLj9r1jVTF_a5IWjq6jm_fhrg,23195 +telegram/chat.py,sha256=_NnCfjxOLiCwMWTjsLDmFAKPp3rFuAp21IUeR-j_rm8,55782 +telegram/chataction.py,sha256=jViLHxzfZcm05tCVG_eFG_XOK7UO2fkPwEIiuuS4Lkk,3198 +telegram/chatinvitelink.py,sha256=1zS2R9uOCJf-Wd18XinK6achbsHgKMj83-dkHBaZ9EA,4245 +telegram/chatlocation.py,sha256=WgqFNGY-xK-bjVSOrliiAQJR4adG_pLJSykAaob--ug,2513 +telegram/chatmember.py,sha256=39wU5kcPQ54J8wuhG3vgVByVxkDdX7qDjPZxVOqQZOQ,12103 +telegram/chatmemberupdated.py,sha256=vzyCiH_j3rkf8Kpx_It6_LDxhe33q_81uzotf2s7E2Q,6597 +telegram/chatpermissions.py,sha256=6VOGVVkb0GHT-TIJR3tJragH78Y5UuCyAEPGD3Voq5Q,6007 +telegram/choseninlineresult.py,sha256=m8pDt1h5PSKCT8SQctxzpZn3PLlVQ8WrLWO3NyxWphE,3816 +telegram/constants.py,sha256=1O8I4rwW5aaPERb9iafFFsypFKGn-fsnXw1xPitSyPI,11889 +telegram/dice.py,sha256=IkQwhw2ybsTv1cMstYMinQTRBtYk1cQxpDTKoCRzEjc,4002 +telegram/error.py,sha256=CIz8GVcw33b5rCeg8yjQm-TUicaWq8J4jHek-JcBe7s,4255 +telegram/ext/__init__.py,sha256=GHh7agiC9e7z55uVEZt9Jwv8jVkbpATRZBI4VDbe5IA,3573 +telegram/ext/__pycache__/__init__.cpython-38.pyc,, +telegram/ext/__pycache__/basepersistence.cpython-38.pyc,, +telegram/ext/__pycache__/callbackcontext.cpython-38.pyc,, +telegram/ext/__pycache__/callbackdatacache.cpython-38.pyc,, +telegram/ext/__pycache__/callbackqueryhandler.cpython-38.pyc,, +telegram/ext/__pycache__/chatmemberhandler.cpython-38.pyc,, +telegram/ext/__pycache__/choseninlineresulthandler.cpython-38.pyc,, +telegram/ext/__pycache__/commandhandler.cpython-38.pyc,, +telegram/ext/__pycache__/contexttypes.cpython-38.pyc,, +telegram/ext/__pycache__/conversationhandler.cpython-38.pyc,, +telegram/ext/__pycache__/defaults.cpython-38.pyc,, +telegram/ext/__pycache__/dictpersistence.cpython-38.pyc,, +telegram/ext/__pycache__/dispatcher.cpython-38.pyc,, +telegram/ext/__pycache__/extbot.cpython-38.pyc,, +telegram/ext/__pycache__/filters.cpython-38.pyc,, +telegram/ext/__pycache__/handler.cpython-38.pyc,, +telegram/ext/__pycache__/inlinequeryhandler.cpython-38.pyc,, +telegram/ext/__pycache__/jobqueue.cpython-38.pyc,, +telegram/ext/__pycache__/messagehandler.cpython-38.pyc,, +telegram/ext/__pycache__/messagequeue.cpython-38.pyc,, +telegram/ext/__pycache__/picklepersistence.cpython-38.pyc,, +telegram/ext/__pycache__/pollanswerhandler.cpython-38.pyc,, +telegram/ext/__pycache__/pollhandler.cpython-38.pyc,, +telegram/ext/__pycache__/precheckoutqueryhandler.cpython-38.pyc,, +telegram/ext/__pycache__/regexhandler.cpython-38.pyc,, +telegram/ext/__pycache__/shippingqueryhandler.cpython-38.pyc,, +telegram/ext/__pycache__/stringcommandhandler.cpython-38.pyc,, +telegram/ext/__pycache__/stringregexhandler.cpython-38.pyc,, +telegram/ext/__pycache__/typehandler.cpython-38.pyc,, +telegram/ext/__pycache__/updater.cpython-38.pyc,, +telegram/ext/basepersistence.py,sha256=NBiKFM459u9alDsZ5bqcWXNUwKhT9oowLFNVT61dWro,22470 +telegram/ext/callbackcontext.py,sha256=qWpfL3XNou8UqINMOINOKykhHMVF1sPIIHBszYcnX8g,14479 +telegram/ext/callbackdatacache.py,sha256=XC2TzHv3m2c_pEIMWu8topAkK-6tSD139eK2ntDyxL0,17176 +telegram/ext/callbackqueryhandler.py,sha256=esS6E2tnjh33VkNpRMMzzQAhwWjQeqnvZ5n3rwuQWAI,10842 +telegram/ext/chatmemberhandler.py,sha256=z963kWStcZvIUhozMHVC-nH31XBQJx5y4tQjFxFtWV0,7034 +telegram/ext/choseninlineresulthandler.py,sha256=7Qz6BXq8bWqXo0N8eyYvOsdVkW5RWcOztw7ZOUmbtu4,7130 +telegram/ext/commandhandler.py,sha256=s8OmFtEJf3n5IrDj32D22L8NTU7i1aeGoAYZbW4utBQ,20693 +telegram/ext/contexttypes.py,sha256=vVsQHu9CptNlpgY68ZXithJ-L0mNlVxQ9hX3NW6S5wM,5801 +telegram/ext/conversationhandler.py,sha256=aHxPSynyJlcq4Wr_4EHMnW3EnfiSaKBVThFDCKnjl9U,31360 +telegram/ext/defaults.py,sha256=t5VJGJQAHuQbFY-Opp_3a4cC8NWwEw3Td5f1vAieYts,10386 +telegram/ext/dictpersistence.py,sha256=DVlhmZwY9MbI_iinqPlip5W9PkXSEvaXdysgvc7pF9w,15999 +telegram/ext/dispatcher.py,sha256=PXIadx5GpZfjRuejKC3x7KhXVuaWKbr56XrRUCaue5k,33944 +telegram/ext/extbot.py,sha256=-mXD03mEy8yq9LAAesrNCww7hpz1rgEzn6bezl2IvOI,13322 +telegram/ext/filters.py,sha256=BTayVEqP7e39wJk6wOhHJBH3diYPk_ZGWFHoXFbMwJg,86691 +telegram/ext/handler.py,sha256=55ym84weyrctws7DyJxmgDqbN783XYPBjI9SNqvtG3o,11226 +telegram/ext/inlinequeryhandler.py,sha256=XoQpqYO4Iqbd-eu4pLXlRH77LARHpViv72_eAcOI2lc,9794 +telegram/ext/jobqueue.py,sha256=PFDtgA52Nqg7JczdULQqQeVi6t9QtNiMg46Omd8o4qo,26886 +telegram/ext/messagehandler.py,sha256=ja7kp2X9R4n3RYGWR1ZCWUvCKjjxrRQbVFaPVbnXV30,9710 +telegram/ext/messagequeue.py,sha256=3CWaqCFZFrSEz4qw9To6sBm5nUckzmduMgqvUp17ylg,14773 +telegram/ext/picklepersistence.py,sha256=ICPpzyQOtpQgstFtaCA79ZmIxzsTmpXiMSKNnuYPHTk,18675 +telegram/ext/pollanswerhandler.py,sha256=rlxyHBkAvXKRjCvb36LGFzbJgHKr-F2HtVQT3dcZ6Wo,4832 +telegram/ext/pollhandler.py,sha256=U2COPncVo5M0kVMCi0UOFVV4734GTr7UOEu1GhFFUUg,4808 +telegram/ext/precheckoutqueryhandler.py,sha256=bEPlYbCZ2idBH2dsmXvlzkIuqkeW-3blAZrAyfMIz10,4845 +telegram/ext/regexhandler.py,sha256=MpxYTTkB_3XrjWryGSFNG_Tj_jzCNBTGDJCbk1deKcw,7823 +telegram/ext/shippingqueryhandler.py,sha256=RW75T7EP-0BohJ3QCa2TwJixcRhs0GOBdeeOqhgh3Lo,4831 +telegram/ext/stringcommandhandler.py,sha256=UxC59oVahZoUpxW4vDSv2XG8LU8cRc7FQmpSgdtojVs,6445 +telegram/ext/stringregexhandler.py,sha256=IwpbnDlL3FKVBwtm9zx7gH0_SqWUjwgIFQOBGMIIBOs,7164 +telegram/ext/typehandler.py,sha256=OmNsYXq30XnNXFJ6ZAt_GH1qHTg-hSOOS8OjplGhq4g,4743 +telegram/ext/updater.py,sha256=y1OUfzzzi6_0wm7Pc8bXX42l_UASrwIiSCe_q_U2uYw,35830 +telegram/ext/utils/__init__.py,sha256=YtDH89cdcr4SOQDEiTOonwD8c3Mn7vSQEBEIJ2gjVGE,800 +telegram/ext/utils/__pycache__/__init__.cpython-38.pyc,, +telegram/ext/utils/__pycache__/promise.cpython-38.pyc,, +telegram/ext/utils/__pycache__/types.cpython-38.pyc,, +telegram/ext/utils/__pycache__/webhookhandler.cpython-38.pyc,, +telegram/ext/utils/promise.py,sha256=zDZ4WQLKYTNbBj8KB4OoKS3AiqhYySIE-X-bE4u92zM,5804 +telegram/ext/utils/types.py,sha256=0v13OdC53ez3k3OL6XiM6vLQ2af2z0h5TmQ1stRc_E4,1905 +telegram/ext/utils/webhookhandler.py,sha256=xw4HEPyI5ZCVpEj2NiQXbOiDnzQ1R_ZpXx741coYX4o,6101 +telegram/files/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +telegram/files/__pycache__/__init__.cpython-38.pyc,, +telegram/files/__pycache__/animation.cpython-38.pyc,, +telegram/files/__pycache__/audio.cpython-38.pyc,, +telegram/files/__pycache__/chatphoto.cpython-38.pyc,, +telegram/files/__pycache__/contact.cpython-38.pyc,, +telegram/files/__pycache__/document.cpython-38.pyc,, +telegram/files/__pycache__/file.cpython-38.pyc,, +telegram/files/__pycache__/inputfile.cpython-38.pyc,, +telegram/files/__pycache__/inputmedia.cpython-38.pyc,, +telegram/files/__pycache__/location.cpython-38.pyc,, +telegram/files/__pycache__/photosize.cpython-38.pyc,, +telegram/files/__pycache__/sticker.cpython-38.pyc,, +telegram/files/__pycache__/venue.cpython-38.pyc,, +telegram/files/__pycache__/video.cpython-38.pyc,, +telegram/files/__pycache__/videonote.cpython-38.pyc,, +telegram/files/__pycache__/voice.cpython-38.pyc,, +telegram/files/animation.py,sha256=MiDxXbqRTLyc5b5Hqif2jb7iGFfrcgHUJjB9QDkDZG4,5198 +telegram/files/audio.py,sha256=-pPB_qQX1m62nau4s4W2TEYeXdiqQ9Ti1Ndad8cz3LY,5397 +telegram/files/chatphoto.py,sha256=J8XTGbf3KZauYIdMqjR33_VhHIx4SKMPW-VCYH0M6xo,5179 +telegram/files/contact.py,sha256=ETMl2rm7Lh-AvZ9f7Jkg3HKBJ5ouFZLjhX33npOjJ60,2540 +telegram/files/document.py,sha256=wk0Kz-3wsb2JfxaE9X3JJOYFtoeYdj5wu8CJHOhO8wo,4486 +telegram/files/file.py,sha256=0818-6TUkbtFm2UdDHwLUxF4NVBpy0-DrAwzjJAZsgY,8343 +telegram/files/inputfile.py,sha256=AbYIBOoe6ua0-C-ZWOPDR38aBdfnuZQzEzyUF9dvVlQ,4251 +telegram/files/inputmedia.py,sha256=dzX1_Q3ca9nxY0esabKHPxmyb5HFjICY8DTlGrkMKJg,22605 +telegram/files/location.py,sha256=yjccX_saJOgm5kxcZyH8nVf3DiCUaYZk0cjWT8ClWPM,3831 +telegram/files/photosize.py,sha256=j1z9wKd-K0ViwqhPwsOLEDLql2ViIrXXsPIgueMwbCM,3626 +telegram/files/sticker.py,sha256=oVEt_WDQ1HsgW2e_aElSnCiU9Qcx6w19QpbrWhvNBU4,10869 +telegram/files/venue.py,sha256=CHuBeNtK01qZtJpW0FNYjndbI668XVzPwfyPzvoBYgE,3970 +telegram/files/video.py,sha256=IAGDMTvc-11ng5JtKYT9tTtfo5cu9RJfbt6ljfLBJZY,5076 +telegram/files/videonote.py,sha256=Kr0weVSSRc0NOR95WAvCexqy9FRmFXrtHh28W0-ayDk,4497 +telegram/files/voice.py,sha256=lyUqA5eXTn-OObOklPmKGVVgYxbejyKyllvZYD4jw5k,3858 +telegram/forcereply.py,sha256=voUc7RP-ftOucMK5oO8XTS-P3jv7RLa33qtqO5Dnc9k,2441 +telegram/games/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +telegram/games/__pycache__/__init__.cpython-38.pyc,, +telegram/games/__pycache__/callbackgame.cpython-38.pyc,, +telegram/games/__pycache__/game.cpython-38.pyc,, +telegram/games/__pycache__/gamehighscore.cpython-38.pyc,, +telegram/games/callbackgame.py,sha256=mQBXmlXtFcXTl_IzKIudmj5uLM6ZV44aN437SCTOjmg,1074 +telegram/games/game.py,sha256=aiD63lDhG3iWih_iuYZecH78mcq8s8Y4IMp04CcwPhs,7698 +telegram/games/gamehighscore.py,sha256=frQay4m5ImX3f5iY5k6gUr66tgVCtMYaQR_VJwHN5nE,2320 +telegram/inline/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +telegram/inline/__pycache__/__init__.cpython-38.pyc,, +telegram/inline/__pycache__/inlinekeyboardbutton.cpython-38.pyc,, +telegram/inline/__pycache__/inlinekeyboardmarkup.cpython-38.pyc,, +telegram/inline/__pycache__/inlinequery.cpython-38.pyc,, +telegram/inline/__pycache__/inlinequeryresult.cpython-38.pyc,, +telegram/inline/__pycache__/inlinequeryresultarticle.cpython-38.pyc,, +telegram/inline/__pycache__/inlinequeryresultaudio.cpython-38.pyc,, +telegram/inline/__pycache__/inlinequeryresultcachedaudio.cpython-38.pyc,, +telegram/inline/__pycache__/inlinequeryresultcacheddocument.cpython-38.pyc,, +telegram/inline/__pycache__/inlinequeryresultcachedgif.cpython-38.pyc,, +telegram/inline/__pycache__/inlinequeryresultcachedmpeg4gif.cpython-38.pyc,, +telegram/inline/__pycache__/inlinequeryresultcachedphoto.cpython-38.pyc,, +telegram/inline/__pycache__/inlinequeryresultcachedsticker.cpython-38.pyc,, +telegram/inline/__pycache__/inlinequeryresultcachedvideo.cpython-38.pyc,, +telegram/inline/__pycache__/inlinequeryresultcachedvoice.cpython-38.pyc,, +telegram/inline/__pycache__/inlinequeryresultcontact.cpython-38.pyc,, +telegram/inline/__pycache__/inlinequeryresultdocument.cpython-38.pyc,, +telegram/inline/__pycache__/inlinequeryresultgame.cpython-38.pyc,, +telegram/inline/__pycache__/inlinequeryresultgif.cpython-38.pyc,, +telegram/inline/__pycache__/inlinequeryresultlocation.cpython-38.pyc,, +telegram/inline/__pycache__/inlinequeryresultmpeg4gif.cpython-38.pyc,, +telegram/inline/__pycache__/inlinequeryresultphoto.cpython-38.pyc,, +telegram/inline/__pycache__/inlinequeryresultvenue.cpython-38.pyc,, +telegram/inline/__pycache__/inlinequeryresultvideo.cpython-38.pyc,, +telegram/inline/__pycache__/inlinequeryresultvoice.cpython-38.pyc,, +telegram/inline/__pycache__/inputcontactmessagecontent.cpython-38.pyc,, +telegram/inline/__pycache__/inputinvoicemessagecontent.cpython-38.pyc,, +telegram/inline/__pycache__/inputlocationmessagecontent.cpython-38.pyc,, +telegram/inline/__pycache__/inputmessagecontent.cpython-38.pyc,, +telegram/inline/__pycache__/inputtextmessagecontent.cpython-38.pyc,, +telegram/inline/__pycache__/inputvenuemessagecontent.cpython-38.pyc,, +telegram/inline/inlinekeyboardbutton.py,sha256=2MrCxkNUIieGPkjqUb5TXAMWp_lpJFBfx_L-959UuLo,7533 +telegram/inline/inlinekeyboardmarkup.py,sha256=83BXE_ciG1-fF3ShTuZoHgCS4ZhkGkcrf3h_brR3rcY,4862 +telegram/inline/inlinequery.py,sha256=wTudQMAAlMNbYTcb7OiVpiAsbVj62qezBV_LK5rlsHw,6662 +telegram/inline/inlinequeryresult.py,sha256=OqC6oXJGzhrvUT67LpFFicX29sW45xuMtuSsS78XPAo,2449 +telegram/inline/inlinequeryresultarticle.py,sha256=TFv89JZJvjZ2qcruVBJEMFw2QmJS4Wn99Z9Xq7FXGL0,3996 +telegram/inline/inlinequeryresultaudio.py,sha256=XUaInEkm2XfJCnjD8LH7Sp2hR07F37pb6vr-pmlmvoE,5037 +telegram/inline/inlinequeryresultcachedaudio.py,sha256=Yiwg-c0n_XzzwgiPY8XYHfPy3DgLrtGdjERIAcMgQ-Q,4545 +telegram/inline/inlinequeryresultcacheddocument.py,sha256=2IU_1GnOLI-TXDSJQvKdULpqYggT0cfuT3vuT3iKg-Q,5085 +telegram/inline/inlinequeryresultcachedgif.py,sha256=tCEXNh1ixoXLHb9xrLekFXAzqrhSoKRRG0RUkbxO0v4,4856 +telegram/inline/inlinequeryresultcachedmpeg4gif.py,sha256=pxQxmbmHCvWQsNHoNo02yRsuIMLNkLaq5D0791eAYU4,4918 +telegram/inline/inlinequeryresultcachedphoto.py,sha256=pxfVtchG5UIcH0GN_I9BHdonAQAYlCrITLUeO4_Ecjw,5076 +telegram/inline/inlinequeryresultcachedsticker.py,sha256=-VWXhDCLJa4xNhPZdy-aZC1s8Tx36mvGolGfAqTaBkU,2915 +telegram/inline/inlinequeryresultcachedvideo.py,sha256=Z7aitBF-uJhq5d2fiZGcWEeIDsiHSUzWEDSB7dVBzC4,5054 +telegram/inline/inlinequeryresultcachedvoice.py,sha256=g0Dv0T--yAuivRBYwXNlyy7EmiGSjX-X5dWf81Bl_W4,4738 +telegram/inline/inlinequeryresultcontact.py,sha256=tnkIXR4hct850i5tj3BiFSZAJXoAbQ7I8fKK3BQHdic,4272 +telegram/inline/inlinequeryresultdocument.py,sha256=vaJ721JP8xU6akJ57u56rC6Vtmkv1JhZf9PxkCE1CHo,6083 +telegram/inline/inlinequeryresultgame.py,sha256=h3_9yMc9rLIu41iz9NE1bR0ypJTmfCjDs3QKxmO0Q8A,2201 +telegram/inline/inlinequeryresultgif.py,sha256=OUPkWmRy8OVlhFEtVGFGbGAinh6Kj2Y5O3ueEE0wjYs,6189 +telegram/inline/inlinequeryresultlocation.py,sha256=t7B_9C7Np5F-P15KUMVxqtqUl_e5d7PgzXeO6o34Uns,5749 +telegram/inline/inlinequeryresultmpeg4gif.py,sha256=fVcN4kHK97ZIWzwBNjnJBEHcm73rkEadn7bFN-9nds4,6226 +telegram/inline/inlinequeryresultphoto.py,sha256=7db_Z4xX2M0AZxDxbM-7qPb46tqjF2s2RvrNnS6yQaw,5864 +telegram/inline/inlinequeryresultvenue.py,sha256=Tr6A8pEWhGp2m4r_zAzdVO3aiNsPxIO7731ELBzz1SU,5638 +telegram/inline/inlinequeryresultvideo.py,sha256=iMOeCdLgzl5Yzbz6HqFVaOuFgxk6d2Pp51wHoiBdLoc,6674 +telegram/inline/inlinequeryresultvoice.py,sha256=ZxeuwSvtPI14kq9ZpKeb33YcXMOrQNHonM_AgQVqF3E,4961 +telegram/inline/inputcontactmessagecontent.py,sha256=-tMq8mbCfWtcUPM45AL7TkTSQD9kgjbfyEVnZbqE0eA,2454 +telegram/inline/inputinvoicemessagecontent.py,sha256=gZgu7C5bckjnf6o53kXED4oVzWDVzMlp7dmB-EkWRIc,11009 +telegram/inline/inputlocationmessagecontent.py,sha256=FFXOULbhPsAHdHaf3R4RiNvYnwxEYV5vAdS2lRt5au0,3863 +telegram/inline/inputmessagecontent.py,sha256=LSwjSkgQBCUXM8P3fskqKC_XeVwntnhVADahhFef1ec,1332 +telegram/inline/inputtextmessagecontent.py,sha256=MBQPMJP56dPk0ShlZjPEwJJq7bR5-rdpDc10eVqAh9k,3882 +telegram/inline/inputvenuemessagecontent.py,sha256=iNhMa_Byw3fLLMXYYEDUTU46CK8oCkEifMmls9eNk0Y,3981 +telegram/keyboardbutton.py,sha256=dMnONHaACh_82UkBn0pLoEkzn2_u5_4OERQMgzpxfnQ,3614 +telegram/keyboardbuttonpolltype.py,sha256=khznebYXZEBIkC7hiE6dV_kOeDkqLRD15eSVq3r5JFY,1837 +telegram/loginurl.py,sha256=aTwonylgx2GAT1VNBxZ-VcValRb3bV5ukXBj7pIPuGA,4093 +telegram/message.py,sha256=U2LLQPU1nqSXTZvdAa7wocjhg3wR3-3kgcnt3Bpzlvs,118913 +telegram/messageautodeletetimerchanged.py,sha256=VwOzVTEIwfOuyYMYZMWK9lSU9EqiAW-jdVKJe8_NbO4,1913 +telegram/messageentity.py,sha256=EVF3GmlsZF8nCrIbYrvegfOdAGiVR4cqO81-P6lR1bY,5705 +telegram/messageid.py,sha256=j5FbZweDWc5BtDwP7isMXeVJwPXjB05crfX5oGqx9Bw,1481 +telegram/parsemode.py,sha256=3wfYxMmkLe2VDlwwi1vEODOPH-pqavwLZzZdziX_pHA,1783 +telegram/passport/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +telegram/passport/__pycache__/__init__.cpython-38.pyc,, +telegram/passport/__pycache__/credentials.cpython-38.pyc,, +telegram/passport/__pycache__/data.cpython-38.pyc,, +telegram/passport/__pycache__/encryptedpassportelement.cpython-38.pyc,, +telegram/passport/__pycache__/passportdata.cpython-38.pyc,, +telegram/passport/__pycache__/passportelementerrors.cpython-38.pyc,, +telegram/passport/__pycache__/passportfile.cpython-38.pyc,, +telegram/passport/credentials.py,sha256=uZOfAn4wwO2BTmZuK464PftcoWH7V8ZAmOJnpLXXlQQ,19374 +telegram/passport/data.py,sha256=U2ML0fQRj5FeWYq7SjYxtvirgncLR_piUPF3fNRoGJY,4692 +telegram/passport/encryptedpassportelement.py,sha256=LfyLTZLSC2kNG2PPJIV4NtIjUTECKPNitTngmaal_p0,12172 +telegram/passport/passportdata.py,sha256=sUpEpIgpNCjNy96AOt2YKcBVicOhajW99xiUQfiBi3Y,4938 +telegram/passport/passportelementerrors.py,sha256=D0bPvBqJ9zDmZOz73B8NFOPIq41tD8GmGie-cq2-gF8,16267 +telegram/passport/passportfile.py,sha256=7ez3MkDij2t-Yx_50qp0ZnsCIjI0-s5qBTexxUEfSyo,5601 +telegram/payment/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +telegram/payment/__pycache__/__init__.cpython-38.pyc,, +telegram/payment/__pycache__/invoice.cpython-38.pyc,, +telegram/payment/__pycache__/labeledprice.cpython-38.pyc,, +telegram/payment/__pycache__/orderinfo.cpython-38.pyc,, +telegram/payment/__pycache__/precheckoutquery.cpython-38.pyc,, +telegram/payment/__pycache__/shippingaddress.cpython-38.pyc,, +telegram/payment/__pycache__/shippingoption.cpython-38.pyc,, +telegram/payment/__pycache__/shippingquery.cpython-38.pyc,, +telegram/payment/__pycache__/successfulpayment.cpython-38.pyc,, +telegram/payment/invoice.py,sha256=H7jODpfFqnwM-xARAaYHFfkoGJh0mPWj3sXbM2U6rBo,3166 +telegram/payment/labeledprice.py,sha256=O6J1HcTXJabd59mfcUVriJaPeLaN7jpAP13vFa1P3ac,2182 +telegram/payment/orderinfo.py,sha256=0LDmlGgOUcHmbvHBHv2kR5OUWTOwi3kUYfLohCc1tIY,2881 +telegram/payment/precheckoutquery.py,sha256=A0OjB5MiazpEguqMo95RTThXWD_gQmMtiWpq9rtVmdk,5229 +telegram/payment/shippingaddress.py,sha256=kU5r3z_IsCzHCIIOxt6jKJFuZrErW7b8ITlfLJGHn0c,2858 +telegram/payment/shippingoption.py,sha256=D5zoKG-9_Ck5QxLrhE62vnBlRBebhS9xEzhIkGzMY5M,2330 +telegram/payment/shippingquery.py,sha256=JZXVUgjMzgp5YUjRcJ0dw35eaogv90pWlW1kCtiZ2Ok,4118 +telegram/payment/successfulpayment.py,sha256=SlEQNz9c0eyUpyWwOcdz9SsFsq-OykOLv9YHbJfZqlU,4400 +telegram/poll.py,sha256=0em8JTuq3-VsADHKWB0q9NaKcgjGvVtMmpoB5Wa3hEM,12268 +telegram/proximityalerttriggered.py,sha256=lHcbWyTK9tdRDA3M95xda1L-Y5eoNI8EswH1e7NGrZY,2654 +telegram/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +telegram/replykeyboardmarkup.py,sha256=zwhQ188D22COkzCToQRydECt4MQbc0zYa7ePi4dyUco,11030 +telegram/replykeyboardremove.py,sha256=_UBdjJM5C6wT49sSi_6as-6Ds8umCCV-HMb4eC8GWjk,2743 +telegram/replymarkup.py,sha256=uLMNo9tBHTF8nntypyj4-8GqjTCNL_RuQcTt1GlZmT8,1200 +telegram/update.py,sha256=8V8-X19fjcTV0rL7rRfGKLKB3YUE7FdL3EVGR0PY4mY,15537 +telegram/user.py,sha256=CS2qMeJKQRamPK2on3gI1tgYjo82bZQtt22vE02mM9M,40818 +telegram/userprofilephotos.py,sha256=1rphFGeYc3KDFRyanaXLa9e_J2U8IjCFja6Xx-8WlXs,2808 +telegram/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +telegram/utils/__pycache__/__init__.cpython-38.pyc,, +telegram/utils/__pycache__/deprecate.cpython-38.pyc,, +telegram/utils/__pycache__/helpers.cpython-38.pyc,, +telegram/utils/__pycache__/promise.cpython-38.pyc,, +telegram/utils/__pycache__/request.cpython-38.pyc,, +telegram/utils/__pycache__/types.cpython-38.pyc,, +telegram/utils/__pycache__/webhookhandler.cpython-38.pyc,, +telegram/utils/deprecate.py,sha256=FRNL22xXKuxuRwtvKbRVnaIxqW9ZPcws-fOc9bBNGcE,1934 +telegram/utils/helpers.py,sha256=3XcMeYB-rvJNiGn39S51wrNOAmQPB_rcvbqep_-30ak,20674 +telegram/utils/promise.py,sha256=1KHB0dSGQ-blNFpvoKTVtYP6zsECnbItWh-IH1t06s4,1350 +telegram/utils/request.py,sha256=u5BsS_0AiVD872PmZJrWA0i00KnYBw163T0y8EU8DoA,15475 +telegram/utils/types.py,sha256=K73MKOxQz5-FX--6ZtUb3nD6EUO1LYv0IUWiTEj2fhI,2114 +telegram/utils/webhookhandler.py,sha256=Ujxsba_gr15yJcA45HsW9kzJDW1z8ezIjh7BIRLORXo,1383 +telegram/vendor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +telegram/vendor/__pycache__/__init__.cpython-38.pyc,, +telegram/vendor/ptb_urllib3/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +telegram/vendor/ptb_urllib3/__pycache__/__init__.cpython-38.pyc,, +telegram/vendor/ptb_urllib3/urllib3/__init__.py,sha256=jut63xC48t8AA78QgpglAJnVynOfmBCa5E9DdlDq9Jk,2851 +telegram/vendor/ptb_urllib3/urllib3/__pycache__/__init__.cpython-38.pyc,, +telegram/vendor/ptb_urllib3/urllib3/__pycache__/_collections.cpython-38.pyc,, +telegram/vendor/ptb_urllib3/urllib3/__pycache__/connection.cpython-38.pyc,, +telegram/vendor/ptb_urllib3/urllib3/__pycache__/connectionpool.cpython-38.pyc,, +telegram/vendor/ptb_urllib3/urllib3/__pycache__/exceptions.cpython-38.pyc,, +telegram/vendor/ptb_urllib3/urllib3/__pycache__/fields.cpython-38.pyc,, +telegram/vendor/ptb_urllib3/urllib3/__pycache__/filepost.cpython-38.pyc,, +telegram/vendor/ptb_urllib3/urllib3/__pycache__/poolmanager.cpython-38.pyc,, +telegram/vendor/ptb_urllib3/urllib3/__pycache__/request.cpython-38.pyc,, +telegram/vendor/ptb_urllib3/urllib3/__pycache__/response.cpython-38.pyc,, +telegram/vendor/ptb_urllib3/urllib3/_collections.py,sha256=zzeg3Qqib_rTpTRwkAd1RVS68bBJbQiGRdH7TthOr-U,10638 +telegram/vendor/ptb_urllib3/urllib3/connection.py,sha256=nz3JRA97jiEjuiGccBEPDD4OaxdGssZWbQJnnwGSF14,12709 +telegram/vendor/ptb_urllib3/urllib3/connectionpool.py,sha256=jeEgyqFevm4u8b40HsEy3xkItJ0-MgSeLQRtmB8Eu9Y,35475 +telegram/vendor/ptb_urllib3/urllib3/contrib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +telegram/vendor/ptb_urllib3/urllib3/contrib/__pycache__/__init__.cpython-38.pyc,, +telegram/vendor/ptb_urllib3/urllib3/contrib/__pycache__/appengine.cpython-38.pyc,, +telegram/vendor/ptb_urllib3/urllib3/contrib/__pycache__/ntlmpool.cpython-38.pyc,, +telegram/vendor/ptb_urllib3/urllib3/contrib/__pycache__/pyopenssl.cpython-38.pyc,, +telegram/vendor/ptb_urllib3/urllib3/contrib/__pycache__/socks.cpython-38.pyc,, +telegram/vendor/ptb_urllib3/urllib3/contrib/appengine.py,sha256=41l3arTy-kBBpOdVpSPYVC64Qo7RLnXnDED6hcIthA0,10865 +telegram/vendor/ptb_urllib3/urllib3/contrib/ntlmpool.py,sha256=Q9-rO5Rh2-IqyEd4ZicpTDfMnOlf0IPPCkjhChBCjV4,4478 +telegram/vendor/ptb_urllib3/urllib3/contrib/pyopenssl.py,sha256=qjfb01ERFADeSS8FZI28tMEf2RWveUZ6fYxwoNG8qcI,15139 +telegram/vendor/ptb_urllib3/urllib3/contrib/socks.py,sha256=Iom0snbHkCuZbZ7Sle2Kueha1W0jYAJ0SyCOtePLaio,6391 +telegram/vendor/ptb_urllib3/urllib3/exceptions.py,sha256=dz1gBEgtROnLrW8V911KhVZWeAn3H2OhDGztWNXQpr0,6603 +telegram/vendor/ptb_urllib3/urllib3/fields.py,sha256=YrNRM8RBUmM8guXKUQFa3kwj6XvQZ78Z8inE6l-YK-E,5943 +telegram/vendor/ptb_urllib3/urllib3/filepost.py,sha256=NF6Rly66bilWU-sdULXjCdQgN1uRxfFRedeifcRLzkU,2321 +telegram/vendor/ptb_urllib3/urllib3/packages/__init__.py,sha256=nlChrGzkjCkmhCX9HrF_qHPUgosfsPQkVIJxiiLhk9g,109 +telegram/vendor/ptb_urllib3/urllib3/packages/__pycache__/__init__.cpython-38.pyc,, +telegram/vendor/ptb_urllib3/urllib3/packages/__pycache__/ordered_dict.cpython-38.pyc,, +telegram/vendor/ptb_urllib3/urllib3/packages/__pycache__/six.cpython-38.pyc,, +telegram/vendor/ptb_urllib3/urllib3/packages/backports/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +telegram/vendor/ptb_urllib3/urllib3/packages/backports/__pycache__/__init__.cpython-38.pyc,, +telegram/vendor/ptb_urllib3/urllib3/packages/backports/__pycache__/makefile.cpython-38.pyc,, +telegram/vendor/ptb_urllib3/urllib3/packages/backports/makefile.py,sha256=r1IADol_pBBq2Y1ub4CPyuS2hXuShK47nfFngZRcRhI,1461 +telegram/vendor/ptb_urllib3/urllib3/packages/ordered_dict.py,sha256=VQaPONfhVMsb8B63Xg7ZOydJqIE_jzeMhVN3Pec6ogw,8935 +telegram/vendor/ptb_urllib3/urllib3/packages/six.py,sha256=A6hdJZVjI3t_geebZ9BzUvwRrIXo0lfwzQlM2LcKyas,30098 +telegram/vendor/ptb_urllib3/urllib3/packages/ssl_match_hostname/__init__.py,sha256=WBVbxQBojNAxfZwNavkox3BgJiMA9BJmm-_fwd0jD_o,688 +telegram/vendor/ptb_urllib3/urllib3/packages/ssl_match_hostname/__pycache__/__init__.cpython-38.pyc,, +telegram/vendor/ptb_urllib3/urllib3/packages/ssl_match_hostname/__pycache__/_implementation.cpython-38.pyc,, +telegram/vendor/ptb_urllib3/urllib3/packages/ssl_match_hostname/_implementation.py,sha256=lAj7qGCZLOldhn8gZDY6Tqp4mvgkbTfy4k4gDIDRo8g,5702 +telegram/vendor/ptb_urllib3/urllib3/poolmanager.py,sha256=XiePLnfcp7MrVijdmsK_icTO_NqIeV8Q-A3RjE-CvW8,13053 +telegram/vendor/ptb_urllib3/urllib3/request.py,sha256=wrt2D0SWLLgTRKrRnaZophq2xXpCvNRd7RMT6F5o5hY,5946 +telegram/vendor/ptb_urllib3/urllib3/response.py,sha256=Adir6jrilGFwEq6EP2IrBGxzGf3CjengxFq5qqF_2P8,22662 +telegram/vendor/ptb_urllib3/urllib3/util/__init__.py,sha256=3UlYoBSPyTrRiuTCmDNOYiBagiS9pJ665VrxoAAKCsc,994 +telegram/vendor/ptb_urllib3/urllib3/util/__pycache__/__init__.cpython-38.pyc,, +telegram/vendor/ptb_urllib3/urllib3/util/__pycache__/connection.cpython-38.pyc,, +telegram/vendor/ptb_urllib3/urllib3/util/__pycache__/request.cpython-38.pyc,, +telegram/vendor/ptb_urllib3/urllib3/util/__pycache__/response.cpython-38.pyc,, +telegram/vendor/ptb_urllib3/urllib3/util/__pycache__/retry.cpython-38.pyc,, +telegram/vendor/ptb_urllib3/urllib3/util/__pycache__/selectors.cpython-38.pyc,, +telegram/vendor/ptb_urllib3/urllib3/util/__pycache__/ssl_.cpython-38.pyc,, +telegram/vendor/ptb_urllib3/urllib3/util/__pycache__/timeout.cpython-38.pyc,, +telegram/vendor/ptb_urllib3/urllib3/util/__pycache__/url.cpython-38.pyc,, +telegram/vendor/ptb_urllib3/urllib3/util/__pycache__/wait.cpython-38.pyc,, +telegram/vendor/ptb_urllib3/urllib3/util/connection.py,sha256=_6_5JZJF3HHRXR7HaxHg3mk7qMKK3N0nl3DL8gFAfo4,4237 +telegram/vendor/ptb_urllib3/urllib3/util/request.py,sha256=UBgRm7xqZU1ybd_Eo0ExdDhFk1AzAl_Z7iuCMIL6SYI,3704 +telegram/vendor/ptb_urllib3/urllib3/util/response.py,sha256=SSNL888W-MQ8t3HAi44kNGgF682p6H__ytEXzBYxV_M,2343 +telegram/vendor/ptb_urllib3/urllib3/util/retry.py,sha256=zxU3zfwglKT0mKwpSzw3aYyug6mumuDfFVBCZCNVQ6A,14123 +telegram/vendor/ptb_urllib3/urllib3/util/selectors.py,sha256=D29bI1M9WAkHoalIQFDN638Y-L0WVLOOfYC7bjNbaZY,18929 +telegram/vendor/ptb_urllib3/urllib3/util/ssl_.py,sha256=4f7gDIXTKnmnPoWPq-yG18a-pipOCnYQeJyU4zNjlss,12046 +telegram/vendor/ptb_urllib3/urllib3/util/timeout.py,sha256=7lHNrgL5YH2cI1j-yZnzV_J8jBlRVdmFhQaNyM1_2b8,9757 +telegram/vendor/ptb_urllib3/urllib3/util/url.py,sha256=91q1Ap45PqXfRuff5Qnx7Xz2TXalp7axXxjbEB67N6w,6289 +telegram/vendor/ptb_urllib3/urllib3/util/wait.py,sha256=Q_pd_bD6iaPgRKwEmcjTYDrSPj4Dd4ojykmqA398b8o,1451 +telegram/version.py,sha256=nCPjK3yUyceutls8PHAD26qUjwu_tuMChogdPkYwiG8,956 +telegram/voicechat.py,sha256=AbpdZ6zrViwTd-3F8mUH5BGMRObGCbN6sUmssKIlXoE,5209 +telegram/webhookinfo.py,sha256=EHVB03pTveBVpbMUvBoNVXG-YNX39Q6U_WiBHz5Pt6k,4665 diff --git a/venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/WHEEL b/venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/WHEEL new file mode 100644 index 0000000..385faab --- /dev/null +++ b/venv/lib/python3.8/site-packages/python_telegram_bot-13.6.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/venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/top_level.txt b/venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/top_level.txt new file mode 100644 index 0000000..51e6be6 --- /dev/null +++ b/venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/top_level.txt @@ -0,0 +1 @@ +telegram diff --git a/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/DESCRIPTION.rst b/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/DESCRIPTION.rst new file mode 100644 index 0000000..1729548 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/DESCRIPTION.rst @@ -0,0 +1,598 @@ +pytz - World Timezone Definitions for Python +============================================ + +:Author: Stuart Bishop + +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. `_. + + +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+0020' + +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) +datetime.timedelta(0, 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) `_ +project provides translations. Thomas Khyn's +`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 `_. 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 `_, and the +`Atom feed `_ +hosted there. + + +Bugs, Feature Requests & Patches +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Bugs can be reported using `Launchpad Bugs `_. + + +Security Issues +~~~~~~~~~~~~~~~ + +Reports about security issues can be made via `Tidelift `_. + + +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: +http://www.twinsun.com/tz/tz-link.htm + + +Contact +~~~~~~~ + +Stuart Bishop + + + + diff --git a/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/INSTALLER b/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/LICENSE.txt b/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/LICENSE.txt new file mode 100644 index 0000000..5f1c112 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/LICENSE.txt @@ -0,0 +1,19 @@ +Copyright (c) 2003-2019 Stuart Bishop + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/METADATA b/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/METADATA new file mode 100644 index 0000000..2fcd986 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/METADATA @@ -0,0 +1,634 @@ +Metadata-Version: 2.0 +Name: pytz +Version: 2021.1 +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: Topic :: Software Development :: Libraries :: Python Modules + +pytz - World Timezone Definitions for Python +============================================ + +:Author: Stuart Bishop + +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. `_. + + +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+0020' + +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) +datetime.timedelta(0, 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) `_ +project provides translations. Thomas Khyn's +`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 `_. 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 `_, and the +`Atom feed `_ +hosted there. + + +Bugs, Feature Requests & Patches +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Bugs can be reported using `Launchpad Bugs `_. + + +Security Issues +~~~~~~~~~~~~~~~ + +Reports about security issues can be made via `Tidelift `_. + + +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: +http://www.twinsun.com/tz/tz-link.htm + + +Contact +~~~~~~~ + +Stuart Bishop + + + + diff --git a/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/RECORD b/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/RECORD new file mode 100644 index 0000000..fcf52aa --- /dev/null +++ b/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/RECORD @@ -0,0 +1,620 @@ +pytz-2021.1.dist-info/DESCRIPTION.rst,sha256=ovmwqIt48fGpf9TczEWesZm0IiGilc_OZOjBt_tim30,19920 +pytz-2021.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +pytz-2021.1.dist-info/LICENSE.txt,sha256=vosaN-vibFkqkPbA6zMQOn84POL010mMCvmlJpkKB7g,1088 +pytz-2021.1.dist-info/METADATA,sha256=kTNHa1f5tk5725uGfhpiJEY6J6m2fcDDXD62EBk3DNI,21412 +pytz-2021.1.dist-info/RECORD,, +pytz-2021.1.dist-info/WHEEL,sha256=kdsN-5OJAZIiHN-iO4Rhl82KyS0bDWf4uBwMbkNafr8,110 +pytz-2021.1.dist-info/metadata.json,sha256=E_bzRXeDscpn48NauiutB0Z_tAPTWdw-bvwTjz3pzLc,1587 +pytz-2021.1.dist-info/top_level.txt,sha256=6xRYlt934v1yHb1JIrXgHyGxn3cqACvd-yE8ski_kcc,5 +pytz-2021.1.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1 +pytz/__init__.py,sha256=kA0Hlp5D5MTPPuf88KVg8pYRwJRGxTQJJuVN794hwsU,35147 +pytz/__pycache__/__init__.cpython-38.pyc,, +pytz/__pycache__/exceptions.cpython-38.pyc,, +pytz/__pycache__/lazy.cpython-38.pyc,, +pytz/__pycache__/reference.cpython-38.pyc,, +pytz/__pycache__/tzfile.cpython-38.pyc,, +pytz/__pycache__/tzinfo.cpython-38.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=c0Z3DcevVpxyT9HOgW1xSf_f8-MDQgBZ-qFVfMlZ4RU,1060 +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=L6zLQLnQtLkEELOGfm6USaHY33qAEPgGV822-iU1vxc,1955 +pytz/zoneinfo/Africa/Casablanca,sha256=qzlDyFvkLZWy8Bydogdx_cxZCkWzRwEEsuVWstJI_-s,2429 +pytz/zoneinfo/Africa/Ceuta,sha256=jp7xqONgZ3NPnElHzJEVusHKM9rxDK1nxJm4-i7Ln8o,2036 +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=Ja0t5t3QHHrvY0EGgxadypAabj4GjMLuQTTbOAur5M0,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=17gT2eOVMFKJF_sypwDPudkFwGEijrRfkBU-aK3FL60,148 +pytz/zoneinfo/America/Antigua,sha256=17gT2eOVMFKJF_sypwDPudkFwGEijrRfkBU-aK3FL60,148 +pytz/zoneinfo/America/Araguaina,sha256=kppiiytmSQeesflyNGYM3r8NVUl1C-ggu08s9_Tt-co,884 +pytz/zoneinfo/America/Argentina/Buenos_Aires,sha256=ntn_GFHadbrFJ4ZuhU6h2uzbFwmDyS9mXV5S28pkGF8,1076 +pytz/zoneinfo/America/Argentina/Catamarca,sha256=diH1f96kbbY-7gJYQnSCNHs3n9dwHJqUhSdGNx1L7I0,1076 +pytz/zoneinfo/America/Argentina/ComodRivadavia,sha256=diH1f96kbbY-7gJYQnSCNHs3n9dwHJqUhSdGNx1L7I0,1076 +pytz/zoneinfo/America/Argentina/Cordoba,sha256=1XqIP8Qo2bPR7909hrAI-qAttybmwEW4ms7FjZA5Yfw,1076 +pytz/zoneinfo/America/Argentina/Jujuy,sha256=5HR0TlZFifwJ5nLTmg7yWXgCTx9mRhahfs4_Wq70wOY,1048 +pytz/zoneinfo/America/Argentina/La_Rioja,sha256=Zf_E3akFE1YUt9MZ4xxbRnOrp2bH1D-Bjsc0SLFfRyU,1090 +pytz/zoneinfo/America/Argentina/Mendoza,sha256=5DJiYYeQpcLBR_IoIJtk43IswJeGYawx5GykszuJ-Nw,1076 +pytz/zoneinfo/America/Argentina/Rio_Gallegos,sha256=T97WADwva6JbxICviNQUt_7iw9c-nloI4QJCscENSck,1076 +pytz/zoneinfo/America/Argentina/Salta,sha256=ATw0uR6szWKPs6jzdn6revS7UxCXD26ORK6jlmsjL18,1048 +pytz/zoneinfo/America/Argentina/San_Juan,sha256=qlW693a0Tnofy-RdcVBuWY3DvTTGxWwcYdKU3Y98pX8,1090 +pytz/zoneinfo/America/Argentina/San_Luis,sha256=WYdcro5-Fe-N6LkQsKwx_1tVozmnBp58DO1-BJs2suo,1102 +pytz/zoneinfo/America/Argentina/Tucuman,sha256=wsjg1a5AM1dP2gjr112k3vt54trcOOM_StF74xzvBJc,1104 +pytz/zoneinfo/America/Argentina/Ushuaia,sha256=9548Vvq_kpw_NX5s65vYuIbqvwGV-PBxqwmcrflLI0U,1076 +pytz/zoneinfo/America/Aruba,sha256=ZGEIylAZ5iy_rIBsXREtH_ZfWRIkLI9dQjP_EIyn3sY,186 +pytz/zoneinfo/America/Asuncion,sha256=FTLtFk6MjJoh5VIDgJ2Sf4B_iNeCDxrV0MWwQL-sOVM,2044 +pytz/zoneinfo/America/Atikokan,sha256=4a94GtPHUdQ-2sdz9WinsKn9V_QiM4XmFj48FTPMeSA,336 +pytz/zoneinfo/America/Atka,sha256=IB1DhwJQAKbhPJ9jHLf8zW5Dad7HIkBS-dhv64E1OlM,2356 +pytz/zoneinfo/America/Bahia,sha256=cmLkSAAzINlzYGXBqADEU3uPgA9S5nt-p1AV3Zy86VY,1024 +pytz/zoneinfo/America/Bahia_Banderas,sha256=BNjbcHSlPsJ4UpJx-gs1hpIyx2ScBieh1nyDuGb0PcE,1546 +pytz/zoneinfo/America/Barbados,sha256=Y0XwBAv5eSAZHNixVIhRvPxNWqP2a1FCH2_z2Vrd-sc,314 +pytz/zoneinfo/America/Belem,sha256=_258hQZLCEXBX8xRLyQSw-AE-jiDmjVwJX32mN5UUEk,576 +pytz/zoneinfo/America/Belize,sha256=pkfLY2KfPchbeJa1pWcXmWAwp4ZlRvxWLVezXnrbkws,1614 +pytz/zoneinfo/America/Blanc-Sablon,sha256=tVN5ZPmIO3vc3_ayowg6qbvjheg4OJtDFT9y8IuW334,298 +pytz/zoneinfo/America/Boa_Vista,sha256=V4VVOkrFUV1qUfVp9E974IOJFmA5QxQrctatTBEb-hs,632 +pytz/zoneinfo/America/Bogota,sha256=ZaQKTZi35AMdlROs0vjEDA_phR8ztJOnjA8aLJZ5tHw,246 +pytz/zoneinfo/America/Boise,sha256=Yv4AXa2nSH_oVo3FZqZCR7V7z7c6WnQgKIUyNUpzGXA,2394 +pytz/zoneinfo/America/Buenos_Aires,sha256=ntn_GFHadbrFJ4ZuhU6h2uzbFwmDyS9mXV5S28pkGF8,1076 +pytz/zoneinfo/America/Cambridge_Bay,sha256=Nanl8yH4SshljhEjDe-PZCYEXbUuuZGmkbAAt2dB-bk,2084 +pytz/zoneinfo/America/Campo_Grande,sha256=5BBENR3_8gJp4F_Uj2RRknvRc4JJWNRPnZU9E7tb8QI,1444 +pytz/zoneinfo/America/Cancun,sha256=YR2U5T6mDGd5xm8EVA_TM1NwSRMYPNYWvV7wuthnX0I,782 +pytz/zoneinfo/America/Caracas,sha256=2NpwXPEtQkI82WCZuQWHXf66VCADcawMpfhKTsuA0x4,264 +pytz/zoneinfo/America/Catamarca,sha256=diH1f96kbbY-7gJYQnSCNHs3n9dwHJqUhSdGNx1L7I0,1076 +pytz/zoneinfo/America/Cayenne,sha256=atVbW5ChJiKQ_q-3kFs-DLTTZa9ptkiHkmJlq4AXoY4,198 +pytz/zoneinfo/America/Cayman,sha256=kayA_pdpMcSQ0FjIzotdcf-m1JYfbKE-qcFT8LC8zqA,182 +pytz/zoneinfo/America/Chicago,sha256=4aZFw-svkMyXmSpNufqzK-xveos-oVJDpEyI8Yu9HQE,3576 +pytz/zoneinfo/America/Chihuahua,sha256=cewXJyEw4KCoz33yl8o2tUJZmugBWH4R0Aovdmuqf-o,1484 +pytz/zoneinfo/America/Coral_Harbour,sha256=4a94GtPHUdQ-2sdz9WinsKn9V_QiM4XmFj48FTPMeSA,336 +pytz/zoneinfo/America/Cordoba,sha256=1XqIP8Qo2bPR7909hrAI-qAttybmwEW4ms7FjZA5Yfw,1076 +pytz/zoneinfo/America/Costa_Rica,sha256=74rYa6lrgIkyls9PkHo8SCYl9oOqiuG5S7MWdnJelP4,316 +pytz/zoneinfo/America/Creston,sha256=dNOa71QgQ2d5uh7cl-xZme-8u3nMR9GJ7PSktWIDORQ,208 +pytz/zoneinfo/America/Cuiaba,sha256=M0FsR8T9s4jFSuzD8Qi6pqtb6Rf2NTzyVHKGZrn56n4,1416 +pytz/zoneinfo/America/Curacao,sha256=ZGEIylAZ5iy_rIBsXREtH_ZfWRIkLI9dQjP_EIyn3sY,186 +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=6_yPo1_mvnt9DgpPzr0QdHsjdsfUG6ALnagQLML1DSM,2444 +pytz/zoneinfo/America/Detroit,sha256=hecz8yqY2Cj5B61G3gLZdAVZvRgK9l0P90c_gN-uD5g,2230 +pytz/zoneinfo/America/Dominica,sha256=17gT2eOVMFKJF_sypwDPudkFwGEijrRfkBU-aK3FL60,148 +pytz/zoneinfo/America/Edmonton,sha256=-TkIfc3QlvaCf0p8COZ43Y1HRBAl-nARUi-JdXeK1vE,2332 +pytz/zoneinfo/America/Eirunepe,sha256=pS90HZzRwH4Tf8ugmKHfiphX7zCPqZkh_0CNb-fEMAM,656 +pytz/zoneinfo/America/El_Salvador,sha256=gvGN8Lkj-sGm2_rs8OUjAMf1oMtKp2Xes6UfWT0WqgU,224 +pytz/zoneinfo/America/Ensenada,sha256=OHHtvy3J70z6wvKBHgPqMEnGs6SXp8fkf0WX9ZiOODk,2342 +pytz/zoneinfo/America/Fort_Nelson,sha256=erfODr3DrSpz65kAdO7Ts2dGbZxvddEP6gx4BX3y2J0,2240 +pytz/zoneinfo/America/Fort_Wayne,sha256=GrNub1_3Um5Qh67wOx58_TEAz4fwAeAlk2AlMTVA_sI,1666 +pytz/zoneinfo/America/Fortaleza,sha256=mITuMrRLRTWyoiF04Oy_UZ8gxZofTpXDblM8t7ch7Sg,716 +pytz/zoneinfo/America/Glace_Bay,sha256=G8DGLGCapH_aYCF_OhaL5Qonf7FOAgAPwelO5htCWBc,2192 +pytz/zoneinfo/America/Godthab,sha256=FtlXWP_hBNuwBHkI2b1yne_tSUJpwLtWLyTHZoFZkmM,1878 +pytz/zoneinfo/America/Goose_Bay,sha256=JgaLueghSvX2g725FOfIgpgvsqxZGykWOhAZWGpQZRY,3210 +pytz/zoneinfo/America/Grand_Turk,sha256=4YOFEPK60Bel2_fCsY6vSZxUcMJKjiKtyOf_Q0khEwU,1834 +pytz/zoneinfo/America/Grenada,sha256=17gT2eOVMFKJF_sypwDPudkFwGEijrRfkBU-aK3FL60,148 +pytz/zoneinfo/America/Guadeloupe,sha256=17gT2eOVMFKJF_sypwDPudkFwGEijrRfkBU-aK3FL60,148 +pytz/zoneinfo/America/Guatemala,sha256=dugUgCd6QY52yHkHuUP4jRWzo5x439IQigaYCvEF46Q,280 +pytz/zoneinfo/America/Guayaquil,sha256=PbcF4bvGAm-aFwdtGPotJy3kb4NwoyWwxgwL98BeUWA,246 +pytz/zoneinfo/America/Guyana,sha256=mDyb0FtGOpwGPq864vAHX22LY0Pxex94f1wVMyo36d0,236 +pytz/zoneinfo/America/Halifax,sha256=TZpmc5PwWoLfTfQoQ_b3U17BE2iVKSeNkR0Ho8mbTn8,3424 +pytz/zoneinfo/America/Havana,sha256=HUQeAuKBsEkI5SLZjqynXICOUVOajkKzKH5r-Ov5Odc,2416 +pytz/zoneinfo/America/Hermosillo,sha256=9Ij30JYmMscC1XHi4o9v-uSXoUuE8V9zhGz2iV5hVFI,416 +pytz/zoneinfo/America/Indiana/Indianapolis,sha256=GrNub1_3Um5Qh67wOx58_TEAz4fwAeAlk2AlMTVA_sI,1666 +pytz/zoneinfo/America/Indiana/Knox,sha256=BiALShjiOLg1o8mMRWJ1jyTlJkgvwzte7B9WSOvTUNg,2428 +pytz/zoneinfo/America/Indiana/Marengo,sha256=CPYY3XgJFNEzONxei7x04wOGI_b86RAn4jBPewi1HZw,1722 +pytz/zoneinfo/America/Indiana/Petersburg,sha256=axot1SloP27ZWjezmo7kldu9qA2frEtPVqWngcXtft0,1904 +pytz/zoneinfo/America/Indiana/Tell_City,sha256=GrWNjb1i4sbIYlJ8fU0viJ2Q5JmrlvLgcLQILnk3El8,1684 +pytz/zoneinfo/America/Indiana/Vevay,sha256=GGosHbQUoIDOKPZxdal42X40veEITMmrnlKOnLUhb-c,1414 +pytz/zoneinfo/America/Indiana/Vincennes,sha256=gh7LAbHbMD92eo9C_c5IiwQ1fJvxhdJN402Q_4YJdLg,1694 +pytz/zoneinfo/America/Indiana/Winamac,sha256=yS-_aKSC4crd0WdNutkHRHxUjmBCU56QVQcqy7kYpbQ,1778 +pytz/zoneinfo/America/Indianapolis,sha256=GrNub1_3Um5Qh67wOx58_TEAz4fwAeAlk2AlMTVA_sI,1666 +pytz/zoneinfo/America/Inuvik,sha256=MU_oDiidQaijt1KV0B5h9LqHoCrJ8ieldD9tsiJiX5o,1894 +pytz/zoneinfo/America/Iqaluit,sha256=6PitEMSFWcSb-Io8fvm4oQ_7v39G_qANc6reTjXoZJ0,2032 +pytz/zoneinfo/America/Jamaica,sha256=wlagieUPRf5-beie-h7QsONbNzjGsm8vMs8uf28pw28,482 +pytz/zoneinfo/America/Jujuy,sha256=5HR0TlZFifwJ5nLTmg7yWXgCTx9mRhahfs4_Wq70wOY,1048 +pytz/zoneinfo/America/Juneau,sha256=k7hxb0aGRnfnE-DBi3LkcjAzRPyAf0_Hw0vVFfjGeb0,2353 +pytz/zoneinfo/America/Kentucky/Louisville,sha256=-yqgeeHZdq6oP3_WzVvYOmqV9HQv8y7ZWmc9bzHvJAY,2772 +pytz/zoneinfo/America/Kentucky/Monticello,sha256=NJMKjG7jjlRzZhndMPw51bYW0D3jviW2Qbl70YcU0Gg,2352 +pytz/zoneinfo/America/Knox_IN,sha256=BiALShjiOLg1o8mMRWJ1jyTlJkgvwzte7B9WSOvTUNg,2428 +pytz/zoneinfo/America/Kralendijk,sha256=ZGEIylAZ5iy_rIBsXREtH_ZfWRIkLI9dQjP_EIyn3sY,186 +pytz/zoneinfo/America/La_Paz,sha256=PAGF2VU_QOw2xT1Cqdp2P8Aj9hXMVWlCByV7cvfIQ_k,232 +pytz/zoneinfo/America/Lima,sha256=JHDCg95uw6BEu4a4Gfyikm1s8rm8AsYPG8dJxQQNZFs,406 +pytz/zoneinfo/America/Los_Angeles,sha256=VOy1PikdjiVdJ7lukVGzwl8uDxV_KYqznkTm5BLEiDM,2836 +pytz/zoneinfo/America/Louisville,sha256=-yqgeeHZdq6oP3_WzVvYOmqV9HQv8y7ZWmc9bzHvJAY,2772 +pytz/zoneinfo/America/Lower_Princes,sha256=ZGEIylAZ5iy_rIBsXREtH_ZfWRIkLI9dQjP_EIyn3sY,186 +pytz/zoneinfo/America/Maceio,sha256=pzjNghmeHhvF4aI3cDq2G_5t71BSNGIbRAF5NmJyDmw,744 +pytz/zoneinfo/America/Managua,sha256=xBzF01AHn2E2fD8Qdy-DHFe36UqoeNpKPfChduBKWdk,430 +pytz/zoneinfo/America/Manaus,sha256=lp6RlkcXJQ7mSsKqnEgC8svJVrFDJk_16xxvfpNSpK4,604 +pytz/zoneinfo/America/Marigot,sha256=17gT2eOVMFKJF_sypwDPudkFwGEijrRfkBU-aK3FL60,148 +pytz/zoneinfo/America/Martinique,sha256=fMs80kOU2YFvC0f9y2eje97JeAtTYBamXrnlTunNLzQ,232 +pytz/zoneinfo/America/Matamoros,sha256=RlEMOT_zvCLQ8s7TNvRE2PnC4H9JrxO7MGxmfu5xPPI,1390 +pytz/zoneinfo/America/Mazatlan,sha256=aIyre-8trAXSHtqxbuu6gDDkWCUjI_SdAKPIjz74M2E,1526 +pytz/zoneinfo/America/Mendoza,sha256=5DJiYYeQpcLBR_IoIJtk43IswJeGYawx5GykszuJ-Nw,1076 +pytz/zoneinfo/America/Menominee,sha256=Arv9WLbfhNcpRsUjHDU757BEdwlp08Gt30AixG3gZ04,2274 +pytz/zoneinfo/America/Merida,sha256=BJQ5mzAT-akb_EA7WqGdNheCorDqLBnDS_4X3YJz0rc,1422 +pytz/zoneinfo/America/Metlakatla,sha256=twmieGTVY2V-U8nFxqvx7asYv8GVjeWdLtrOI7UApVI,1423 +pytz/zoneinfo/America/Mexico_City,sha256=DSpTe5TT0KBsxGx79Rs7ah-zJpiGOJKwPjztovRN0b4,1584 +pytz/zoneinfo/America/Miquelon,sha256=LNbkN87EnZUa41Xizko5VIN55EyQvf5Kk5b5AfNQG8Q,1666 +pytz/zoneinfo/America/Moncton,sha256=Wmv-bk9aKKcWWzOpc1UFu67HOfwaIk2Wmh3LgqGctys,3154 +pytz/zoneinfo/America/Monterrey,sha256=HA4yn9jQHk9i0PqiB7fSoFdzXtB1DT1cheGRPXrQNdQ,1390 +pytz/zoneinfo/America/Montevideo,sha256=4jcgTegK5X8F0yNYzk-3oySZ4U9XQ09UbTJ_mlu8N70,1510 +pytz/zoneinfo/America/Montreal,sha256=ggOSzbHkmfgu9wTQzP0MUKsrKMbgveuAeThh1eFl1a0,3494 +pytz/zoneinfo/America/Montserrat,sha256=17gT2eOVMFKJF_sypwDPudkFwGEijrRfkBU-aK3FL60,148 +pytz/zoneinfo/America/Nassau,sha256=MEpB_L1x3UnwwqjOwNqDvCfgQYPOnhB2jewLwiOxV4g,2388 +pytz/zoneinfo/America/New_York,sha256=7AoiEGjr3wV4P7C4Qs35COZqwr2mjNDq7ocpsSPFOM8,3536 +pytz/zoneinfo/America/Nipigon,sha256=EGPXcOin8mfzFTkYJm4ICpY7fyE24I2pXg4ejafSMyU,2122 +pytz/zoneinfo/America/Nome,sha256=2izM3-P-PqJ9za6MdhzFfMvPFNq7Gim69tAvEwPeY2s,2367 +pytz/zoneinfo/America/Noronha,sha256=3R4lLV8jg5SljhC5OVVCk51Y77Efjo6zCe-oppg_FFo,716 +pytz/zoneinfo/America/North_Dakota/Beulah,sha256=PHlzEk3wsNXYsfMZZSio7ZfdnyxPFpOhK3dS-1AJKGg,2380 +pytz/zoneinfo/America/North_Dakota/Center,sha256=PaM52_JOVMEpVdw5qiOlhkp3qA0xp0d6Z9neOatmLKo,2380 +pytz/zoneinfo/America/North_Dakota/New_Salem,sha256=o0xmH1FUh3lVFLtP5Lb9c0PfSyaPTsRvQSQYwnn_yls,2380 +pytz/zoneinfo/America/Nuuk,sha256=FtlXWP_hBNuwBHkI2b1yne_tSUJpwLtWLyTHZoFZkmM,1878 +pytz/zoneinfo/America/Ojinaga,sha256=cO3V-x_1Q-mpbJgKNd6-WTfxDEHBV1aqS4wzVl5A0Q4,1484 +pytz/zoneinfo/America/Panama,sha256=kayA_pdpMcSQ0FjIzotdcf-m1JYfbKE-qcFT8LC8zqA,182 +pytz/zoneinfo/America/Pangnirtung,sha256=P9Kw_I-NxcUYJIr1j40jTn9q7F8TPAE_FqXsfLYF86A,2094 +pytz/zoneinfo/America/Paramaribo,sha256=Hm5tDwUmnoTrTUPEO4WArfSF74ZjywVEocy4kL51FzA,262 +pytz/zoneinfo/America/Phoenix,sha256=nEOwYOnGxENw9zW8m50PGxbtVfTrX3QYAo4x4LgOLfI,328 +pytz/zoneinfo/America/Port-au-Prince,sha256=09ZAJd4IOiMpfdpUuF1U44R_hRt6BvpAkFXOnYO9yOM,1434 +pytz/zoneinfo/America/Port_of_Spain,sha256=17gT2eOVMFKJF_sypwDPudkFwGEijrRfkBU-aK3FL60,148 +pytz/zoneinfo/America/Porto_Acre,sha256=17onkm8P_VgMkErjK9rr0qwNni7qp9tgcUZ93g3ltOs,628 +pytz/zoneinfo/America/Porto_Velho,sha256=ZRfzgGEu26hnl3JPtiZLOSFGj_WBSbOKdiLC1xIyc5c,576 +pytz/zoneinfo/America/Puerto_Rico,sha256=hJHlV_-AGoMGUWuMpZRv9fLmghrzFHfrR9fRkcxaZJc,246 +pytz/zoneinfo/America/Punta_Arenas,sha256=kpqStczF3X0yK0lwOcxmwbQM8ZV9MrNktm7orJF-EJc,1902 +pytz/zoneinfo/America/Rainy_River,sha256=r6kx6lD2IzCdygkj-DKyL2tPSn7k0Zil7PSHCBFKOa0,2122 +pytz/zoneinfo/America/Rankin_Inlet,sha256=KpQX97-EuF4MNyxQrtOKP616CK_vjniM-lo14WGVz0c,1892 +pytz/zoneinfo/America/Recife,sha256=ijFN2ZzZe5oBYdl8Ag3SwmGjj2JeVYYX2Vo767g2s6I,716 +pytz/zoneinfo/America/Regina,sha256=yjqT08pHbICYe83H8JmtaDBvCFqRv7Tfze3Y8xuXukw,980 +pytz/zoneinfo/America/Resolute,sha256=VP_u5XsepfSwx7Ou9zjGw2p5Qi10AIA54sP1J2DkppM,1892 +pytz/zoneinfo/America/Rio_Branco,sha256=17onkm8P_VgMkErjK9rr0qwNni7qp9tgcUZ93g3ltOs,628 +pytz/zoneinfo/America/Rosario,sha256=1XqIP8Qo2bPR7909hrAI-qAttybmwEW4ms7FjZA5Yfw,1076 +pytz/zoneinfo/America/Santa_Isabel,sha256=OHHtvy3J70z6wvKBHgPqMEnGs6SXp8fkf0WX9ZiOODk,2342 +pytz/zoneinfo/America/Santarem,sha256=Gl_lI3pPZ57UIYXWcmaTpFqWDA5re6bHh1nWs_Z0-Nc,602 +pytz/zoneinfo/America/Santiago,sha256=GB14PW0xABV283dXc8qL-nnDW-ViFUR3bne7sg0Aido,2529 +pytz/zoneinfo/America/Santo_Domingo,sha256=DKtaEj8fQ92ybITTWU4Bm160S9pzJmUVbjaWRnenxU4,458 +pytz/zoneinfo/America/Sao_Paulo,sha256=cO3VGekMGdSf1y4f_UgkpDMRes26-l1oGUoDglIiUQg,1444 +pytz/zoneinfo/America/Scoresbysund,sha256=dfHb86egoiNykb3bR3OHXpGFPm_Apck8BLiVTCqVAVc,1916 +pytz/zoneinfo/America/Shiprock,sha256=6_yPo1_mvnt9DgpPzr0QdHsjdsfUG6ALnagQLML1DSM,2444 +pytz/zoneinfo/America/Sitka,sha256=aiS7Fk37hZpzZ9VkeJQeF-BqTLRC1QOTCgMAJwT8UxA,2329 +pytz/zoneinfo/America/St_Barthelemy,sha256=17gT2eOVMFKJF_sypwDPudkFwGEijrRfkBU-aK3FL60,148 +pytz/zoneinfo/America/St_Johns,sha256=r1-17uKv27eZ3JsVkw_DLZQbo6wvjuuVu7C2pDsmOgI,3655 +pytz/zoneinfo/America/St_Kitts,sha256=17gT2eOVMFKJF_sypwDPudkFwGEijrRfkBU-aK3FL60,148 +pytz/zoneinfo/America/St_Lucia,sha256=17gT2eOVMFKJF_sypwDPudkFwGEijrRfkBU-aK3FL60,148 +pytz/zoneinfo/America/St_Thomas,sha256=17gT2eOVMFKJF_sypwDPudkFwGEijrRfkBU-aK3FL60,148 +pytz/zoneinfo/America/St_Vincent,sha256=17gT2eOVMFKJF_sypwDPudkFwGEijrRfkBU-aK3FL60,148 +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=cJ9lcf2mDZttEx_ttYYoZAJfuGhSsDgNV2PI-ggWdPE,2202 +pytz/zoneinfo/America/Tijuana,sha256=OHHtvy3J70z6wvKBHgPqMEnGs6SXp8fkf0WX9ZiOODk,2342 +pytz/zoneinfo/America/Toronto,sha256=ggOSzbHkmfgu9wTQzP0MUKsrKMbgveuAeThh1eFl1a0,3494 +pytz/zoneinfo/America/Tortola,sha256=17gT2eOVMFKJF_sypwDPudkFwGEijrRfkBU-aK3FL60,148 +pytz/zoneinfo/America/Vancouver,sha256=sknKH0jSPWam-DHfM35qXs8Nam7d5TFlkUI9Sgxryyg,2892 +pytz/zoneinfo/America/Virgin,sha256=17gT2eOVMFKJF_sypwDPudkFwGEijrRfkBU-aK3FL60,148 +pytz/zoneinfo/America/Whitehorse,sha256=Kfv607qGHJxXGBP1nPJyNg2_duWrmxhZGFQr82ukgq8,1614 +pytz/zoneinfo/America/Winnipeg,sha256=7P-_YQrneFcon7QKSTOnkiGjEppFDn3Z48MJ1qq8VBw,2868 +pytz/zoneinfo/America/Yakutat,sha256=tFwnKbvwhyyn4LNTAn5ye_JWDdxjCerNDt7oOwUwO2M,2305 +pytz/zoneinfo/America/Yellowknife,sha256=pfFvC8NEy373KbO6r6ec-Gw_O0D2h64mXU1X1AsUDgE,1966 +pytz/zoneinfo/Antarctica/Casey,sha256=a_ShNA5q27F-GNPiFPttIhhdHc1MP485jX6pwRjZ_t0,384 +pytz/zoneinfo/Antarctica/Davis,sha256=6PokyOaaISRTN13sisuGgdt5vG5A2YqNooJpfLTb5SQ,297 +pytz/zoneinfo/Antarctica/DumontDUrville,sha256=g8HQLY-aN3p6az-04KdHOdZYFnN__-8ltHRuY9eQX-I,194 +pytz/zoneinfo/Antarctica/Macquarie,sha256=ie7RlaU8RHTorVVj-MX8StKMqx_oXf4UH2PUqpzcwe0,2260 +pytz/zoneinfo/Antarctica/Mawson,sha256=9TW1g_z0tk5EfeB7K69VJo8agO7-K9ZxWbiqNKnUZNE,199 +pytz/zoneinfo/Antarctica/McMurdo,sha256=gADjoyPo_QISQU6UJrAgcHp3HDaMoOFRdH-d23uBSyc,2437 +pytz/zoneinfo/Antarctica/Palmer,sha256=DW_DXByXg5MnMZ-w1bNdu8b0lKOYD_EgrPRd5EcyEm4,1418 +pytz/zoneinfo/Antarctica/Rothera,sha256=QQI1m1IN4_2e6Bb0z-rOYaOwxp4XjMJDOKM9SFDUPKg,164 +pytz/zoneinfo/Antarctica/South_Pole,sha256=gADjoyPo_QISQU6UJrAgcHp3HDaMoOFRdH-d23uBSyc,2437 +pytz/zoneinfo/Antarctica/Syowa,sha256=VnmdVypdJUhsBw1XuXZEcEQIFmoiqoYcdpl8ht37QgY,165 +pytz/zoneinfo/Antarctica/Troll,sha256=3zrh-P_jMCss9GGwHJJHkypZZydq4mkgo_TDqctn3c4,1162 +pytz/zoneinfo/Antarctica/Vostok,sha256=6tx86WD3MVGJBCbOJUCoA6YlGwCn2BT4B85Zss0vz4Y,165 +pytz/zoneinfo/Arctic/Longyearbyen,sha256=UdCERhj1JYpx3ojmilaRoyVoR4qMA1-PEv6hGwnpsJA,2228 +pytz/zoneinfo/Asia/Aden,sha256=rq9KPj8l0FBnnKn93WkMeA1IngNtTzk5_oV4sEZhc4w,165 +pytz/zoneinfo/Asia/Almaty,sha256=rBIl_pqZNmKZabjEa4mcsLahl9PbAdZJpQMQLVmcfBU,997 +pytz/zoneinfo/Asia/Amman,sha256=bvwhc1hPCGvQMqWzaoCHrCA_y78n3H-Z2t4wHSocuAw,1853 +pytz/zoneinfo/Asia/Anadyr,sha256=hDDTly45ejoVVP9Al07TmKpTACNGJaIPlcXLRbsG_4g,1188 +pytz/zoneinfo/Asia/Aqtau,sha256=A5exZN256JagFJTcasgdCrQ8giOqZ2EFMRVYBWTaqZA,983 +pytz/zoneinfo/Asia/Aqtobe,sha256=LQ7P5LEEe7jbWbjqvzmM79c0o6AdZeCExQS-fOWp8yw,1011 +pytz/zoneinfo/Asia/Ashgabat,sha256=L4DYV2mZWycsYeHIypXzO6ZNY3tD8wjgxfPR2ZPW26c,619 +pytz/zoneinfo/Asia/Ashkhabad,sha256=L4DYV2mZWycsYeHIypXzO6ZNY3tD8wjgxfPR2ZPW26c,619 +pytz/zoneinfo/Asia/Atyrau,sha256=3uEo89ORyDJqQ_TtaQdIf9UPaB8WqIRQVi0geeY9gVE,991 +pytz/zoneinfo/Asia/Baghdad,sha256=lQMSUnOuijbcoTaCqMNnYhnvKtS2IVP_kXFAzePVNDU,983 +pytz/zoneinfo/Asia/Bahrain,sha256=V0rFJdLHIrToJ5Wl28VzVowwCVZoY8ZZSeNp-7kOvjY,199 +pytz/zoneinfo/Asia/Baku,sha256=vhHnliaOdRyNudl0sFJFdLynEg0Hc0I-IiZNfbDeCbM,1227 +pytz/zoneinfo/Asia/Bangkok,sha256=eYq0vh89N1j069URoQvtBu0ndEal6FPrtbF8WCKKpDw,199 +pytz/zoneinfo/Asia/Barnaul,sha256=2c1Cq8XYlBgybRQMP8w0NCf7kaLDrPZtGn4M5iJZbJo,1221 +pytz/zoneinfo/Asia/Beirut,sha256=_Z_2ZAg_iL9vU51JDB8CB04uXBDrf1kLIis-JnXaS2o,2154 +pytz/zoneinfo/Asia/Bishkek,sha256=do_4ki1JvSKupUrvlz9jRkHspDhdvk1D2IkByFskjJM,983 +pytz/zoneinfo/Asia/Brunei,sha256=BMMjwEmZ9rMoNpWfg8IrlLhRbMKbdW48padRF-FGolc,203 +pytz/zoneinfo/Asia/Calcutta,sha256=6Qw0EDbLcgMgDik8s7UTJn4QSjmllPNeGVJU5rwKF88,285 +pytz/zoneinfo/Asia/Chita,sha256=4ICOcAVAEWnP-cdf_YJu1_kCYnYPG2_vYfSbuNI-VwI,1221 +pytz/zoneinfo/Asia/Choibalsan,sha256=sJQAAjiT9VyG73dYhpYkq4tcmfITcPpiAa8YXsDlKag,949 +pytz/zoneinfo/Asia/Chongqing,sha256=ZP_C5DqUQ1oEPAQNHTr36S0DGtx453N68YYbqk7u8-Y,561 +pytz/zoneinfo/Asia/Chungking,sha256=ZP_C5DqUQ1oEPAQNHTr36S0DGtx453N68YYbqk7u8-Y,561 +pytz/zoneinfo/Asia/Colombo,sha256=HGea9jswIIgz7k20LTzbKtQyUun67IP5HvsZrmAJZJY,372 +pytz/zoneinfo/Asia/Dacca,sha256=3K5llGhcpCdZMMcJuomICVv7lZlDRpU4PUb5DtFx8l4,337 +pytz/zoneinfo/Asia/Damascus,sha256=6mcB6bxH1KsLqzb_LmJUT3tUDnq9_ScLFKoMFkcZy3A,2294 +pytz/zoneinfo/Asia/Dhaka,sha256=3K5llGhcpCdZMMcJuomICVv7lZlDRpU4PUb5DtFx8l4,337 +pytz/zoneinfo/Asia/Dili,sha256=ptjbacc9JK0pv2JpD-gHMglrwYNj9LMMIua0U0ZTMUc,227 +pytz/zoneinfo/Asia/Dubai,sha256=-ga0m3ua9Y6kSWREz2_VdtcVAkq83WrW3vxjBI7WNGs,165 +pytz/zoneinfo/Asia/Dushanbe,sha256=FUk9Tt_GimfRulcWamEvuOvA7FQ52YfZqQ2w88qMx6M,591 +pytz/zoneinfo/Asia/Famagusta,sha256=CFrcygd8ude5x6OEtfM_Dw0KYHoxpPPzq46KoHVxjjc,2028 +pytz/zoneinfo/Asia/Gaza,sha256=LPrVQ4DY43CC-2CnMLx6VEt4IP26P6Jw0HRlhbEbXHo,2422 +pytz/zoneinfo/Asia/Harbin,sha256=ZP_C5DqUQ1oEPAQNHTr36S0DGtx453N68YYbqk7u8-Y,561 +pytz/zoneinfo/Asia/Hebron,sha256=dXAP5ZeuPWJZLh6Y41hEz3owiuqElZxn1SKtdWaeKtw,2450 +pytz/zoneinfo/Asia/Ho_Chi_Minh,sha256=L5TXNg6-odIIn-JAyLTR8fKFiUFBNFwy0HzwZchbnm4,351 +pytz/zoneinfo/Asia/Hong_Kong,sha256=UcnFEc9S8hMWl9giVXni4TAhLPWX0H12XvwSt4AJHew,1203 +pytz/zoneinfo/Asia/Hovd,sha256=JUnOos7PNTi2VRKxD6XnaVR3NpuhsX_Pi18rIzVe1xw,891 +pytz/zoneinfo/Asia/Irkutsk,sha256=iUJZCVBjpfB4rNKJOr6g0zUZtccYYk_Gk0wTklx8Yj0,1243 +pytz/zoneinfo/Asia/Istanbul,sha256=2S0A_f7VxvyErJMMCPqK33AChA29IVkMr1o-SpMtMxk,1947 +pytz/zoneinfo/Asia/Jakarta,sha256=_WRgz6Zb6wxIXtMwpKjG4w4PJtDRzkhdrw-3a4NCBFA,355 +pytz/zoneinfo/Asia/Jayapura,sha256=ihzUd-L8HUVqG-Na10MyPE-YYwjVFj-xerqjTN4EJZs,221 +pytz/zoneinfo/Asia/Jerusalem,sha256=JUuWQmW5Tha0pJjw61Q5aN7CX0z4D7ops9OOSnda6Dc,2388 +pytz/zoneinfo/Asia/Kabul,sha256=ial7SvweHTQXDl79MnXm6QHtiw2i7Zt1e5urLXU8Sq8,208 +pytz/zoneinfo/Asia/Kamchatka,sha256=pBA0RbynKTKsMCmf2hJMZ_hgVUPemms-VceMMJ7QC64,1166 +pytz/zoneinfo/Asia/Karachi,sha256=iB-mWMTXUyfBwAkZdz8_UmEw0xsgxIub-KNI7akzhkk,379 +pytz/zoneinfo/Asia/Kashgar,sha256=AEXDJ5PxQOhePZZw1QZl98moDNa-bW3I3WVNQZHBPYA,165 +pytz/zoneinfo/Asia/Kathmandu,sha256=TUeW7rDSifOTSsNxvo9igIYZfGITEZUf-0EjglyRDWs,212 +pytz/zoneinfo/Asia/Katmandu,sha256=TUeW7rDSifOTSsNxvo9igIYZfGITEZUf-0EjglyRDWs,212 +pytz/zoneinfo/Asia/Khandyga,sha256=XYzE2tsE5Say9pg0cHDQkEE9aTuy2piFSLAGx_d-dmM,1271 +pytz/zoneinfo/Asia/Kolkata,sha256=6Qw0EDbLcgMgDik8s7UTJn4QSjmllPNeGVJU5rwKF88,285 +pytz/zoneinfo/Asia/Krasnoyarsk,sha256=nzRw4PI2AiK_Ge854b8U7TSDw0LGQy3ca5YuOOU2XwI,1207 +pytz/zoneinfo/Asia/Kuala_Lumpur,sha256=RfiIYo6sMEkSA8m5iUmyOyJzKZrgRs8ehGuDZwoq88k,383 +pytz/zoneinfo/Asia/Kuching,sha256=KsAtQ0aocINozixwW7CkorY-1PTLlsj7UUnQGQMEYTQ,483 +pytz/zoneinfo/Asia/Kuwait,sha256=rq9KPj8l0FBnnKn93WkMeA1IngNtTzk5_oV4sEZhc4w,165 +pytz/zoneinfo/Asia/Macao,sha256=MvAkRyRsrA2r052ItlyF5bh2FheRjI0jPwg0uIiH2Yk,1227 +pytz/zoneinfo/Asia/Macau,sha256=MvAkRyRsrA2r052ItlyF5bh2FheRjI0jPwg0uIiH2Yk,1227 +pytz/zoneinfo/Asia/Magadan,sha256=cqwjKQt8TlznM1w2DezAZuz1EjeOfLxPeSY19i9zkfQ,1222 +pytz/zoneinfo/Asia/Makassar,sha256=OhJtCqSTEU-u5n0opBVO5Bu-wQzcYPy9S_6aAhJXgOw,254 +pytz/zoneinfo/Asia/Manila,sha256=ujfq0kl1EhxcYSOrG-FS750aNaYUt1TT4bFuK4EcL_c,328 +pytz/zoneinfo/Asia/Muscat,sha256=-ga0m3ua9Y6kSWREz2_VdtcVAkq83WrW3vxjBI7WNGs,165 +pytz/zoneinfo/Asia/Nicosia,sha256=0Unm0IFT7HyGeQ7F3vTa_-klfysCgrulqFO6BD1plZU,2002 +pytz/zoneinfo/Asia/Novokuznetsk,sha256=vQGcqKdmYmWDdl73QPZTcyadnope1RPJ4oBgZelQu90,1165 +pytz/zoneinfo/Asia/Novosibirsk,sha256=ApL3s20HX2eIAno03HCa2RXdlLotVb9JvnZl7W1sM00,1221 +pytz/zoneinfo/Asia/Omsk,sha256=wxbEesfe7dJOkNPffqTwT6wuTSSTM6E9f0uFMAyzMCM,1207 +pytz/zoneinfo/Asia/Oral,sha256=iMjqD4LvDgyxN15v7CqyEdBDyBFaOlChwX1wHz2JiVQ,1005 +pytz/zoneinfo/Asia/Phnom_Penh,sha256=eYq0vh89N1j069URoQvtBu0ndEal6FPrtbF8WCKKpDw,199 +pytz/zoneinfo/Asia/Pontianak,sha256=inOXwuKtjKv1z_eliPZSIqjSt6whtuxhPeG1YpjU_BQ,353 +pytz/zoneinfo/Asia/Pyongyang,sha256=_-g3GnDAtfDX4XAktXH9jFouLUDmOovnjoOfvRpUDsE,237 +pytz/zoneinfo/Asia/Qatar,sha256=V0rFJdLHIrToJ5Wl28VzVowwCVZoY8ZZSeNp-7kOvjY,199 +pytz/zoneinfo/Asia/Qostanay,sha256=UGYEvmZfAAS9D6EMGd0n6-r_Az_zgTDSWLPeHzFLfu0,1011 +pytz/zoneinfo/Asia/Qyzylorda,sha256=aiSRxwoUbQ-TBHf2wcyaOhQb86j3jQpXwcQaSPnAtwU,1025 +pytz/zoneinfo/Asia/Rangoon,sha256=ZHuX-XVHr8dGJjrPQ5cW7b8jQUv3ihyd-VzN545mlMA,268 +pytz/zoneinfo/Asia/Riyadh,sha256=rq9KPj8l0FBnnKn93WkMeA1IngNtTzk5_oV4sEZhc4w,165 +pytz/zoneinfo/Asia/Saigon,sha256=L5TXNg6-odIIn-JAyLTR8fKFiUFBNFwy0HzwZchbnm4,351 +pytz/zoneinfo/Asia/Sakhalin,sha256=95AdPwOgSe0g9wdx67kKLDbjvY3FtpeVBoAWbJVco0w,1202 +pytz/zoneinfo/Asia/Samarkand,sha256=BBe6Gg_KlSQuS5hAyvvhZWmClcLJaFjnCNGC391HHQM,577 +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=hIgr_LHMTWh3GgeG-MmLHBp-9anUxQcfMlKFtX8WvmU,383 +pytz/zoneinfo/Asia/Srednekolymsk,sha256=0DllW8q5VgXEMV5c_nLJElZsNpauvNhNACQpcgdqEl0,1208 +pytz/zoneinfo/Asia/Taipei,sha256=DMmQwOpPql25ue3Nf8vAKKT4em06D1Z9rHbLIitxixk,761 +pytz/zoneinfo/Asia/Tashkent,sha256=LS-yTxh0v1vmJoQ9I6fY-IERk7ukPmovVx2Ut_-b-Ig,591 +pytz/zoneinfo/Asia/Tbilisi,sha256=w6UNxgyn4BVVTF5WkAtxo_u7nnIY26makKQ5nRgifds,1035 +pytz/zoneinfo/Asia/Tehran,sha256=ATT50Q0hK6uSba5_WnOE3Px0OWxIwxaqK5Oi10P2A-M,2582 +pytz/zoneinfo/Asia/Tel_Aviv,sha256=JUuWQmW5Tha0pJjw61Q5aN7CX0z4D7ops9OOSnda6Dc,2388 +pytz/zoneinfo/Asia/Thimbu,sha256=uia8or5dtDkxVUZrcLwkjbTz9C7ZhLq0T4jlE4YvuvQ,203 +pytz/zoneinfo/Asia/Thimphu,sha256=uia8or5dtDkxVUZrcLwkjbTz9C7ZhLq0T4jlE4YvuvQ,203 +pytz/zoneinfo/Asia/Tokyo,sha256=oCueZgRNxcNcX3ZGdif9y6Su4cyVhga4XHdwlcrYLOs,309 +pytz/zoneinfo/Asia/Tomsk,sha256=77YgdJLxETRKjQjnaHHf54xBAqNywTDwQQmZ5v6Aq28,1221 +pytz/zoneinfo/Asia/Ujung_Pandang,sha256=OhJtCqSTEU-u5n0opBVO5Bu-wQzcYPy9S_6aAhJXgOw,254 +pytz/zoneinfo/Asia/Ulaanbaatar,sha256=uyQSzIBl0f2TXHrmUm3VPs1C9ro013hYmAlx6yUjh3Y,891 +pytz/zoneinfo/Asia/Ulan_Bator,sha256=uyQSzIBl0f2TXHrmUm3VPs1C9ro013hYmAlx6yUjh3Y,891 +pytz/zoneinfo/Asia/Urumqi,sha256=AEXDJ5PxQOhePZZw1QZl98moDNa-bW3I3WVNQZHBPYA,165 +pytz/zoneinfo/Asia/Ust-Nera,sha256=JAZhRAPdbOL9AL-WHOL8aZjxdZxLmGDNBGMCw9TKtR8,1252 +pytz/zoneinfo/Asia/Vientiane,sha256=eYq0vh89N1j069URoQvtBu0ndEal6FPrtbF8WCKKpDw,199 +pytz/zoneinfo/Asia/Vladivostok,sha256=Wokhgtj2nwUj992h7SyfB_fRNHAKfPNzhsf_oZpim8c,1208 +pytz/zoneinfo/Asia/Yakutsk,sha256=RVCIl52EvMrp2RG2hg2cjDSr9QhsscaAT-NV81xw7zc,1207 +pytz/zoneinfo/Asia/Yangon,sha256=ZHuX-XVHr8dGJjrPQ5cW7b8jQUv3ihyd-VzN545mlMA,268 +pytz/zoneinfo/Asia/Yekaterinburg,sha256=NzVc2DiPeyw0FdMHwSPQJF9k3tvWdtrETZiN58pyxLk,1243 +pytz/zoneinfo/Asia/Yerevan,sha256=k0WHtWQW_cBCjcEv8nP01cVPeTVDlf18lQ0_u6cin1o,1151 +pytz/zoneinfo/Atlantic/Azores,sha256=ut7TdE-xiQNjRybg56Tt5b7Zo5zqbuF5IFci2aDMs1Q,3484 +pytz/zoneinfo/Atlantic/Bermuda,sha256=LNGKfMsnYvwImjTyzXrLhMOHHDu7qI67RbYNKvvI15I,2396 +pytz/zoneinfo/Atlantic/Canary,sha256=ymK9ufqphvNjDK3hzikN4GfkcR3QeCBiPKyVc6FjlbA,1897 +pytz/zoneinfo/Atlantic/Cape_Verde,sha256=ESQvE3deMI-lx9mG0yJLEsFX5KRl-7c6gD5O2h0Zm9Q,270 +pytz/zoneinfo/Atlantic/Faeroe,sha256=NibdZPZtapnYR_myIZnMdTaSKGsOBGgujj0_T2NvAzs,1815 +pytz/zoneinfo/Atlantic/Faroe,sha256=NibdZPZtapnYR_myIZnMdTaSKGsOBGgujj0_T2NvAzs,1815 +pytz/zoneinfo/Atlantic/Jan_Mayen,sha256=UdCERhj1JYpx3ojmilaRoyVoR4qMA1-PEv6hGwnpsJA,2228 +pytz/zoneinfo/Atlantic/Madeira,sha256=e1K2l8ykd8xpznQNs3SSuIZ1ZfVx2Y69EXrhvYV3P14,3475 +pytz/zoneinfo/Atlantic/Reykjavik,sha256=mSkaRBGZLeUrm88EeHcaWnEd35Wn-Ag2G10HtI3G2fg,1162 +pytz/zoneinfo/Atlantic/South_Georgia,sha256=QZ72fRKp6Kgvy7DfyHGht1MVnzGgSPujLQd4XMjNrrc,164 +pytz/zoneinfo/Atlantic/St_Helena,sha256=0u-sTl8j2IyV1ywdtCgHFw9S9D3ZiiBa9akqkbny2Zc,148 +pytz/zoneinfo/Atlantic/Stanley,sha256=exKMLw-P952wS1FTxVjnUU1mkD2OvKUDwtDt8IGgf8w,1214 +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=LxEuFWyMse_cALVtRWCkf6sIIEk13jQ4JXW8k2agSd8,470 +pytz/zoneinfo/Australia/Hobart,sha256=GLQSzgIfsWxOvmKOrhpfofWqINQf6h36NYy3mcq6gcg,2358 +pytz/zoneinfo/Australia/LHI,sha256=Luf0Lx_iJHuh3kZd4LxRjf36tLF5-wW2UFMVNKNT7gg,1860 +pytz/zoneinfo/Australia/Lindeman,sha256=xM6Udx22oLNoLR1Y7GQhHOYov8nw3xQNqgc_NVQ2JK4,475 +pytz/zoneinfo/Australia/Lord_Howe,sha256=Luf0Lx_iJHuh3kZd4LxRjf36tLF5-wW2UFMVNKNT7gg,1860 +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=17onkm8P_VgMkErjK9rr0qwNni7qp9tgcUZ93g3ltOs,628 +pytz/zoneinfo/Brazil/DeNoronha,sha256=3R4lLV8jg5SljhC5OVVCk51Y77Efjo6zCe-oppg_FFo,716 +pytz/zoneinfo/Brazil/East,sha256=cO3VGekMGdSf1y4f_UgkpDMRes26-l1oGUoDglIiUQg,1444 +pytz/zoneinfo/Brazil/West,sha256=lp6RlkcXJQ7mSsKqnEgC8svJVrFDJk_16xxvfpNSpK4,604 +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=Kfv607qGHJxXGBP1nPJyNg2_duWrmxhZGFQr82ukgq8,1614 +pytz/zoneinfo/Chile/Continental,sha256=GB14PW0xABV283dXc8qL-nnDW-ViFUR3bne7sg0Aido,2529 +pytz/zoneinfo/Chile/EasterIsland,sha256=paHp1QRXIa02kgd0-4V6vWXdqcwheow-hJQD9VqacfQ,2233 +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=L6zLQLnQtLkEELOGfm6USaHY33qAEPgGV822-iU1vxc,1955 +pytz/zoneinfo/Eire,sha256=-JSA3vsi44F1DE8supVjSppH2Vpp12WjJI0_COtAmqU,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=pw8HngVt3bU5QrRzu70qOmf69TIyklkglvVUte9ntKo,2910 +pytz/zoneinfo/Europe/Andorra,sha256=gTB5jCQmvIw3JJi1_vAcOYuhtzPBR6RXUx9gVV6p6ug,1742 +pytz/zoneinfo/Europe/Astrakhan,sha256=ywtzL92KVfoybOmAhE9eHqmMcvJZm5b0js5GDdWIJEQ,1165 +pytz/zoneinfo/Europe/Athens,sha256=XDY-FBUddRyQHN8GxQLZ4awjuOlWlzlUdjv7OdXFNzA,2262 +pytz/zoneinfo/Europe/Belfast,sha256=xp08wV44TZMmAdBqppttDChQAb8tRN03GcEht99RYtY,3648 +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=q7iAbkd7y9QvbAi6XGZEUOTwNDCRYWRu9VQCxUrZ01U,2137 +pytz/zoneinfo/Europe/Dublin,sha256=-JSA3vsi44F1DE8supVjSppH2Vpp12WjJI0_COtAmqU,3492 +pytz/zoneinfo/Europe/Gibraltar,sha256=egOcazf2u1njGZ0tDj-f1NzZT_K5rpUKSqtShxO7U6c,3052 +pytz/zoneinfo/Europe/Guernsey,sha256=xp08wV44TZMmAdBqppttDChQAb8tRN03GcEht99RYtY,3648 +pytz/zoneinfo/Europe/Helsinki,sha256=GEkB7LsVhmegt7YuuWheCDvDGC7b7Nw9bTdDGS9qkJc,1900 +pytz/zoneinfo/Europe/Isle_of_Man,sha256=xp08wV44TZMmAdBqppttDChQAb8tRN03GcEht99RYtY,3648 +pytz/zoneinfo/Europe/Istanbul,sha256=2S0A_f7VxvyErJMMCPqK33AChA29IVkMr1o-SpMtMxk,1947 +pytz/zoneinfo/Europe/Jersey,sha256=xp08wV44TZMmAdBqppttDChQAb8tRN03GcEht99RYtY,3648 +pytz/zoneinfo/Europe/Kaliningrad,sha256=s7GXSe1YvMcs7AiUhHNTA6I4nAOQn_Kmz_ZqJYO-LMM,1493 +pytz/zoneinfo/Europe/Kiev,sha256=iVkTPFkl2tADYapa1HASlaV3tT2VsJpTPTTJC_9HtAk,2088 +pytz/zoneinfo/Europe/Kirov,sha256=Sr4HEUwk3tPTXioeCLhvlgKbCAFU7Gy2UB3f--uWLDc,1153 +pytz/zoneinfo/Europe/Lisbon,sha256=L6n3snx6pNHHJIL6JOLFOAlYkQ2J5uB_y5MG_Ic_PDU,3469 +pytz/zoneinfo/Europe/Ljubljana,sha256=OpWtsGFWBE_S-mYoQcAmjCta9HwbGQANnSmVY9OHCTo,1920 +pytz/zoneinfo/Europe/London,sha256=xp08wV44TZMmAdBqppttDChQAb8tRN03GcEht99RYtY,3648 +pytz/zoneinfo/Europe/Luxembourg,sha256=974Dvf_X1QISKG1zIiTJJIfGavobO21HUVS-HfysOcY,2946 +pytz/zoneinfo/Europe/Madrid,sha256=MTTMnrbDDtexRikd72-FbQEpCZjc63_UtBIiDomD95c,2614 +pytz/zoneinfo/Europe/Malta,sha256=xRwBfrV8hOihGtqcek5_B6l5hjc206g3yfbEWXIaUis,2620 +pytz/zoneinfo/Europe/Mariehamn,sha256=GEkB7LsVhmegt7YuuWheCDvDGC7b7Nw9bTdDGS9qkJc,1900 +pytz/zoneinfo/Europe/Minsk,sha256=mn86zdrNWpJYDfE51Iy9n1-Zi2piTyb9EPaS2A-uGJQ,1321 +pytz/zoneinfo/Europe/Monaco,sha256=50uVZXYXXqfnr-K4tsSNl26CZbRju65C-STp818wX84,2944 +pytz/zoneinfo/Europe/Moscow,sha256=KmkofRcj6T8Ph28PJChm8JVp13uRvef6TZ0GuPzUiDw,1535 +pytz/zoneinfo/Europe/Nicosia,sha256=0Unm0IFT7HyGeQ7F3vTa_-klfysCgrulqFO6BD1plZU,2002 +pytz/zoneinfo/Europe/Oslo,sha256=UdCERhj1JYpx3ojmilaRoyVoR4qMA1-PEv6hGwnpsJA,2228 +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=-X5F_d3Dz0kBRWiUTXUN-fgeCHbUEHLaaHIwEPZEdUQ,2641 +pytz/zoneinfo/Europe/Samara,sha256=z2innqSZ8_lkEy8cIyF9JM_FfnO2sWZaqeFqOh8pD7M,1215 +pytz/zoneinfo/Europe/San_Marino,sha256=-X5F_d3Dz0kBRWiUTXUN-fgeCHbUEHLaaHIwEPZEdUQ,2641 +pytz/zoneinfo/Europe/Sarajevo,sha256=OpWtsGFWBE_S-mYoQcAmjCta9HwbGQANnSmVY9OHCTo,1920 +pytz/zoneinfo/Europe/Saratov,sha256=BMej49HlQG24CWCh5VOENrB3jPuJPScPszRtb7MrJ3I,1183 +pytz/zoneinfo/Europe/Simferopol,sha256=_M6LXB5Rqh932nKIJotGjT8YNszAOb7RjHN5ng-uW1Y,1453 +pytz/zoneinfo/Europe/Skopje,sha256=OpWtsGFWBE_S-mYoQcAmjCta9HwbGQANnSmVY9OHCTo,1920 +pytz/zoneinfo/Europe/Sofia,sha256=hCQKXfMNrnA5xHNw_uzTjKzVw4-Bvsq5oGO4yUCv5tY,2077 +pytz/zoneinfo/Europe/Stockholm,sha256=Xgp4GSh8-pzdeJeP8TQ20jWDDUj17R69h6RYTbLYd2g,1909 +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=nFsgcVTmTiiFzHtyJDRnO-3H4GRAfAeceb6b2jFHLUQ,1267 +pytz/zoneinfo/Europe/Uzhgorod,sha256=TIG1rC4QR7nz-vO1VtmN9mDMVjKPDKi7mEB9KpfJOBA,2050 +pytz/zoneinfo/Europe/Vaduz,sha256=K5QY7Ujj2VUchKR4bhhb0hgdAJhmwED71ykXDQOGKe8,1909 +pytz/zoneinfo/Europe/Vatican,sha256=-X5F_d3Dz0kBRWiUTXUN-fgeCHbUEHLaaHIwEPZEdUQ,2641 +pytz/zoneinfo/Europe/Vienna,sha256=ZmI3kADE6bnrJEccqh73XXBY36L1G4DkpiTQImtNrUk,2200 +pytz/zoneinfo/Europe/Vilnius,sha256=UFzRX3orCTB8d9IzlxJPy5eUA2oBPuCu1UJl-2D7C3U,2162 +pytz/zoneinfo/Europe/Volgograd,sha256=XZNEUXwnmGdOTld_9Lug2CFfXbFCJFZC45nOMb59FRk,1165 +pytz/zoneinfo/Europe/Warsaw,sha256=TiLDPbeVF0ckgLVEkaSeDaKZ8wctdJDOl_HE_Wd5rKs,2654 +pytz/zoneinfo/Europe/Zagreb,sha256=OpWtsGFWBE_S-mYoQcAmjCta9HwbGQANnSmVY9OHCTo,1920 +pytz/zoneinfo/Europe/Zaporozhye,sha256=V0dhGl3gET8OftMezf8CVy-W00Z7FtuEev5TjI2Rnyw,2106 +pytz/zoneinfo/Europe/Zurich,sha256=K5QY7Ujj2VUchKR4bhhb0hgdAJhmwED71ykXDQOGKe8,1909 +pytz/zoneinfo/Factory,sha256=aFFlKx93HXoJoF4SSuTlD8cZtJA-ne5oKzAa6eX2V4k,116 +pytz/zoneinfo/GB,sha256=xp08wV44TZMmAdBqppttDChQAb8tRN03GcEht99RYtY,3648 +pytz/zoneinfo/GB-Eire,sha256=xp08wV44TZMmAdBqppttDChQAb8tRN03GcEht99RYtY,3648 +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=UcnFEc9S8hMWl9giVXni4TAhLPWX0H12XvwSt4AJHew,1203 +pytz/zoneinfo/Iceland,sha256=mSkaRBGZLeUrm88EeHcaWnEd35Wn-Ag2G10HtI3G2fg,1162 +pytz/zoneinfo/Indian/Antananarivo,sha256=yJsuJTqJJqbOz37_NOS_zbf-JNr_IthHGMMN7sDqSWg,265 +pytz/zoneinfo/Indian/Chagos,sha256=23B26pwwK0gxW7TP76GltyY-RU_o6RGGSrF93pF7S1E,199 +pytz/zoneinfo/Indian/Christmas,sha256=J4I0WDX_LYAJxsx2vU0EdxFJQKRE-rRL1UvNQv09pCs,165 +pytz/zoneinfo/Indian/Cocos,sha256=PX-k8JpghajjvhljtBjWozaiu9NhUSpVeoACy2cAxN8,174 +pytz/zoneinfo/Indian/Comoro,sha256=yJsuJTqJJqbOz37_NOS_zbf-JNr_IthHGMMN7sDqSWg,265 +pytz/zoneinfo/Indian/Kerguelen,sha256=oIvd6bmQFMLUefoBn4c1fQTOAawGcrPcmge2jU7BsYo,165 +pytz/zoneinfo/Indian/Mahe,sha256=ZNXjaoL_o6572xXgsgSmbd5D_SkaCaayolpSN1je82w,165 +pytz/zoneinfo/Indian/Maldives,sha256=dUQBbrmoB3odWsMt3K1YUnB447A6nkW3aR1aHzdLF7M,199 +pytz/zoneinfo/Indian/Mauritius,sha256=k6vWUVcfU3gS1K12e_aMw6BeSdMvdLyCJRCAL7CD0go,241 +pytz/zoneinfo/Indian/Mayotte,sha256=yJsuJTqJJqbOz37_NOS_zbf-JNr_IthHGMMN7sDqSWg,265 +pytz/zoneinfo/Indian/Reunion,sha256=lHnSVh7CYCuDBEM4dYsWDk006BSAznkCPxjiTtL_WiI,165 +pytz/zoneinfo/Iran,sha256=ATT50Q0hK6uSba5_WnOE3Px0OWxIwxaqK5Oi10P2A-M,2582 +pytz/zoneinfo/Israel,sha256=JUuWQmW5Tha0pJjw61Q5aN7CX0z4D7ops9OOSnda6Dc,2388 +pytz/zoneinfo/Jamaica,sha256=wlagieUPRf5-beie-h7QsONbNzjGsm8vMs8uf28pw28,482 +pytz/zoneinfo/Japan,sha256=oCueZgRNxcNcX3ZGdif9y6Su4cyVhga4XHdwlcrYLOs,309 +pytz/zoneinfo/Kwajalein,sha256=L4nH3qxv5EBKVRxYt67b9IfZfBzg5KJk19iu7x3oBMk,316 +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=OHHtvy3J70z6wvKBHgPqMEnGs6SXp8fkf0WX9ZiOODk,2342 +pytz/zoneinfo/Mexico/BajaSur,sha256=aIyre-8trAXSHtqxbuu6gDDkWCUjI_SdAKPIjz74M2E,1526 +pytz/zoneinfo/Mexico/General,sha256=DSpTe5TT0KBsxGx79Rs7ah-zJpiGOJKwPjztovRN0b4,1584 +pytz/zoneinfo/NZ,sha256=gADjoyPo_QISQU6UJrAgcHp3HDaMoOFRdH-d23uBSyc,2437 +pytz/zoneinfo/NZ-CHAT,sha256=lkVqaSF1WWpv_B2K-k2uJp2setRVK6XbjsQ38gDGVEg,2068 +pytz/zoneinfo/Navajo,sha256=6_yPo1_mvnt9DgpPzr0QdHsjdsfUG6ALnagQLML1DSM,2444 +pytz/zoneinfo/PRC,sha256=ZP_C5DqUQ1oEPAQNHTr36S0DGtx453N68YYbqk7u8-Y,561 +pytz/zoneinfo/PST8PDT,sha256=Q7TCLkE69a6g7mPoPAkqhg-0dStyiAC0jVlM72KG_R8,2310 +pytz/zoneinfo/Pacific/Apia,sha256=p1vFsjfezDCHmPOnmgG47q7wTPM5feosoWN3ucgGnrw,1097 +pytz/zoneinfo/Pacific/Auckland,sha256=gADjoyPo_QISQU6UJrAgcHp3HDaMoOFRdH-d23uBSyc,2437 +pytz/zoneinfo/Pacific/Bougainville,sha256=ZKDa_S_2gSlmOWizV1DqxH3wbE58rfK1vKZHZqrrtjI,268 +pytz/zoneinfo/Pacific/Chatham,sha256=lkVqaSF1WWpv_B2K-k2uJp2setRVK6XbjsQ38gDGVEg,2068 +pytz/zoneinfo/Pacific/Chuuk,sha256=6IYDKViuRDC_RVx1AJOxazVET6cZtdv_LFE6xbtGItI,269 +pytz/zoneinfo/Pacific/Easter,sha256=paHp1QRXIa02kgd0-4V6vWXdqcwheow-hJQD9VqacfQ,2233 +pytz/zoneinfo/Pacific/Efate,sha256=pG4NMVeM3hBJTZnZmqeLqz3Q5oCggTW4HO-R9Fe926A,538 +pytz/zoneinfo/Pacific/Enderbury,sha256=zqW7qAC_6FTcgrGEMhpIsl1oV9I46gY2nH3pwadll68,234 +pytz/zoneinfo/Pacific/Fakaofo,sha256=gow-SgE5r5c8J_Ag5nvJ5SUPDg6yH8pth_a-QLDcPv8,200 +pytz/zoneinfo/Pacific/Fiji,sha256=W6rxVK44zQaoLWLexVRoav16jMcuWYbNskIa5Ld9H-Q,1077 +pytz/zoneinfo/Pacific/Funafuti,sha256=P-XYwlWQpWvS3Q_TYFe37BrgxKJy5tg7PHEQNCDGv5U,166 +pytz/zoneinfo/Pacific/Galapagos,sha256=MdtlC-ffp8reICzDxsQ8tWMsTkq5ZcN-j3OyyhjokV8,238 +pytz/zoneinfo/Pacific/Gambier,sha256=z6eYF8sszLjkfpqmWnbBBAUB-ibaR5nodKaAYbvXOe0,164 +pytz/zoneinfo/Pacific/Guadalcanal,sha256=6GX-XpxcCyA64qUMdxJMFMq4sPk0ZjhexqGbryzfgjE,166 +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/Kiritimati,sha256=VHR3iuwiv3tx65WtitVHCoQEg3VJd812VZ5djuSyUxc,238 +pytz/zoneinfo/Pacific/Kosrae,sha256=Vm5AKI6NvuYSz58s8922WNIiWoqPcix2JOJOix1mlSU,351 +pytz/zoneinfo/Pacific/Kwajalein,sha256=L4nH3qxv5EBKVRxYt67b9IfZfBzg5KJk19iu7x3oBMk,316 +pytz/zoneinfo/Pacific/Majuro,sha256=Dwqh7gXoz7Duwu1n7XF8yEjhM4ULEs42LSQyy7F-qzQ,310 +pytz/zoneinfo/Pacific/Marquesas,sha256=uzsjVolutGRXp_FRnvXoU0ApDEb4ZaYoz_r60D7jufg,173 +pytz/zoneinfo/Pacific/Midway,sha256=fCYrYphYY6rUfxOw712y5cyRe104AC3pouqD3bCINFg,175 +pytz/zoneinfo/Pacific/Nauru,sha256=oGxocYsqssZ_EeQHf3cUP5cg0qtqzx1BzoEjVWjE_7g,252 +pytz/zoneinfo/Pacific/Niue,sha256=lSsVlJJ458vNuIgjZESQyatsJV3LpWGyHqbYXMXPjZ4,241 +pytz/zoneinfo/Pacific/Norfolk,sha256=CdEXM9SKYC9Wn7aMxD2sV5i8zE88NQo25Z_L874JthI,880 +pytz/zoneinfo/Pacific/Noumea,sha256=FSanpAOCE7WHQeiop4QErKV9ZC3Tzu2GxkH8-tIXsHY,304 +pytz/zoneinfo/Pacific/Pago_Pago,sha256=fCYrYphYY6rUfxOw712y5cyRe104AC3pouqD3bCINFg,175 +pytz/zoneinfo/Pacific/Palau,sha256=CRW__McXPlOaxo2S9kHMHaBdjv7u59ZWEwYuJConzmQ,180 +pytz/zoneinfo/Pacific/Pitcairn,sha256=O65Ed1FOCF_0rEjpYPAquDwtAF3hxyJNiujgpgZV0kc,202 +pytz/zoneinfo/Pacific/Pohnpei,sha256=YqXrKwjhUnxWyV6PFg1L6_zu84MfPW82dypf0S7pHtQ,303 +pytz/zoneinfo/Pacific/Ponape,sha256=YqXrKwjhUnxWyV6PFg1L6_zu84MfPW82dypf0S7pHtQ,303 +pytz/zoneinfo/Pacific/Port_Moresby,sha256=ei_XjmiRDLh-RU94uvz9CCIIRFH1r0X7WL-sB-6DF60,186 +pytz/zoneinfo/Pacific/Rarotonga,sha256=UfUhlaG0u7yOlzoKnHE9pRiHqQ2N_M9n5WHaCCwtbV4,577 +pytz/zoneinfo/Pacific/Saipan,sha256=Ex9znmf6rNfGze6gNpZJCMr1TT4rkl2SnrhecrdJufI,494 +pytz/zoneinfo/Pacific/Samoa,sha256=fCYrYphYY6rUfxOw712y5cyRe104AC3pouqD3bCINFg,175 +pytz/zoneinfo/Pacific/Tahiti,sha256=9iozXRFYDhBOLijmDk2mRS4Mb-LXWW1u7n790jBNKxM,165 +pytz/zoneinfo/Pacific/Tarawa,sha256=vT6UxW7KeGptdh80Fj9ASATGmLx8Wai630lML4mwg80,166 +pytz/zoneinfo/Pacific/Tongatapu,sha256=ht8ZhdveQXJqsxYtSEcqmRTzXA3OtqYoi4WVBvOPGhw,372 +pytz/zoneinfo/Pacific/Truk,sha256=6IYDKViuRDC_RVx1AJOxazVET6cZtdv_LFE6xbtGItI,269 +pytz/zoneinfo/Pacific/Wake,sha256=dTJxldgcad-kGrODwo4cAHGRSsS-K3fjeZ62WEUhmFk,166 +pytz/zoneinfo/Pacific/Wallis,sha256=CAlw1H5gkER5lkvtmHY-ppoGL3hNmYxfMaXQpI0fTOE,166 +pytz/zoneinfo/Pacific/Yap,sha256=6IYDKViuRDC_RVx1AJOxazVET6cZtdv_LFE6xbtGItI,269 +pytz/zoneinfo/Poland,sha256=TiLDPbeVF0ckgLVEkaSeDaKZ8wctdJDOl_HE_Wd5rKs,2654 +pytz/zoneinfo/Portugal,sha256=L6n3snx6pNHHJIL6JOLFOAlYkQ2J5uB_y5MG_Ic_PDU,3469 +pytz/zoneinfo/ROC,sha256=DMmQwOpPql25ue3Nf8vAKKT4em06D1Z9rHbLIitxixk,761 +pytz/zoneinfo/ROK,sha256=LI9LsV3XcJC0l-KoQf8zI-y7rk-du57erS-N2Ptdi7Q,617 +pytz/zoneinfo/Singapore,sha256=hIgr_LHMTWh3GgeG-MmLHBp-9anUxQcfMlKFtX8WvmU,383 +pytz/zoneinfo/Turkey,sha256=2S0A_f7VxvyErJMMCPqK33AChA29IVkMr1o-SpMtMxk,1947 +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=nEOwYOnGxENw9zW8m50PGxbtVfTrX3QYAo4x4LgOLfI,328 +pytz/zoneinfo/US/Central,sha256=4aZFw-svkMyXmSpNufqzK-xveos-oVJDpEyI8Yu9HQE,3576 +pytz/zoneinfo/US/East-Indiana,sha256=GrNub1_3Um5Qh67wOx58_TEAz4fwAeAlk2AlMTVA_sI,1666 +pytz/zoneinfo/US/Eastern,sha256=7AoiEGjr3wV4P7C4Qs35COZqwr2mjNDq7ocpsSPFOM8,3536 +pytz/zoneinfo/US/Hawaii,sha256=fwPRv1Jk56sCOi75uZfd_Iy2k2aSQHx3B2K5xUlSPzM,329 +pytz/zoneinfo/US/Indiana-Starke,sha256=BiALShjiOLg1o8mMRWJ1jyTlJkgvwzte7B9WSOvTUNg,2428 +pytz/zoneinfo/US/Michigan,sha256=hecz8yqY2Cj5B61G3gLZdAVZvRgK9l0P90c_gN-uD5g,2230 +pytz/zoneinfo/US/Mountain,sha256=6_yPo1_mvnt9DgpPzr0QdHsjdsfUG6ALnagQLML1DSM,2444 +pytz/zoneinfo/US/Pacific,sha256=VOy1PikdjiVdJ7lukVGzwl8uDxV_KYqznkTm5BLEiDM,2836 +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=BMh_yY7MXp8DMEy71jarFX3IJSNpwuEyIjIo2HKUXD4,4463 +pytz/zoneinfo/leapseconds,sha256=WFKV3wNak8BTFEaUwFFeLO5bUOa0moZ3S-255JLAank,3392 +pytz/zoneinfo/tzdata.zi,sha256=35McqINLMRv5Nhy80Nw8u3IhmB4nL9cSWWhZiSl3_nk,113161 +pytz/zoneinfo/zone.tab,sha256=2wzsaOCfYuhhMxZsFO9y1ckAPgD4uzBfbff64XV1qWU,19321 +pytz/zoneinfo/zone1970.tab,sha256=EBkiCpmeio73EQXCl7T9lGFBT19NJwWPw8tqkCc0QRI,17835 diff --git a/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/WHEEL b/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/WHEEL new file mode 100644 index 0000000..7332a41 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.30.0) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/metadata.json b/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/metadata.json new file mode 100644 index 0000000..1a0df75 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/metadata.json @@ -0,0 +1 @@ +{"classifiers": ["Development Status :: 6 - Mature", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.4", "Programming Language :: Python :: 2.5", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.1", "Programming Language :: Python :: 3.2", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Software Development :: Libraries :: Python Modules"], "download_url": "https://pypi.org/project/pytz/", "extensions": {"python.details": {"contacts": [{"email": "stuart@stuartbishop.net", "name": "Stuart Bishop", "role": "author"}, {"email": "stuart@stuartbishop.net", "name": "Stuart Bishop", "role": "maintainer"}], "document_names": {"description": "DESCRIPTION.rst", "license": "LICENSE.txt"}, "project_urls": {"Home": "http://pythonhosted.org/pytz"}}}, "generator": "bdist_wheel (0.30.0)", "keywords": ["timezone", "tzinfo", "datetime", "olson", "time"], "license": "MIT", "metadata_version": "2.0", "name": "pytz", "platform": "Independent", "summary": "World timezone definitions, modern and historical", "version": "2021.1"} \ No newline at end of file diff --git a/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/top_level.txt b/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/top_level.txt new file mode 100644 index 0000000..af44f19 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/top_level.txt @@ -0,0 +1 @@ +pytz diff --git a/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/zip-safe b/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/zip-safe new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/zip-safe @@ -0,0 +1 @@ + diff --git a/venv/lib/python3.8/site-packages/pytz/__init__.py b/venv/lib/python3.8/site-packages/pytz/__init__.py new file mode 100644 index 0000000..e2f49fa --- /dev/null +++ b/venv/lib/python3.8/site-packages/pytz/__init__.py @@ -0,0 +1,1558 @@ +''' +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 = '2021a' +VERSION = '2021.1' # 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.path.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) # 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 "" + + 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 = \ +['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/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/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/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 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/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/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_Velho', + 'America/Puerto_Rico', + 'America/Punta_Arenas', + 'America/Rainy_River', + '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/Thunder_Bay', + 'America/Tijuana', + 'America/Toronto', + 'America/Tortola', + 'America/Vancouver', + '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/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/Kiev', + 'Europe/Kirov', + '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/Uzhgorod', + 'Europe/Vaduz', + 'Europe/Vatican', + 'Europe/Vienna', + 'Europe/Vilnius', + 'Europe/Volgograd', + 'Europe/Warsaw', + 'Europe/Zagreb', + 'Europe/Zaporozhye', + '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/Enderbury', + 'Pacific/Fakaofo', + 'Pacific/Fiji', + 'Pacific/Funafuti', + 'Pacific/Galapagos', + 'Pacific/Gambier', + 'Pacific/Guadalcanal', + 'Pacific/Guam', + 'Pacific/Honolulu', + '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/venv/lib/python3.8/site-packages/pytz/exceptions.py b/venv/lib/python3.8/site-packages/pytz/exceptions.py new file mode 100644 index 0000000..4b20bde --- /dev/null +++ b/venv/lib/python3.8/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/venv/lib/python3.8/site-packages/pytz/lazy.py b/venv/lib/python3.8/site-packages/pytz/lazy.py new file mode 100644 index 0000000..39344fc --- /dev/null +++ b/venv/lib/python3.8/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/venv/lib/python3.8/site-packages/pytz/reference.py b/venv/lib/python3.8/site-packages/pytz/reference.py new file mode 100644 index 0000000..f765ca0 --- /dev/null +++ b/venv/lib/python3.8/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/venv/lib/python3.8/site-packages/pytz/tzfile.py b/venv/lib/python3.8/site-packages/pytz/tzfile.py new file mode 100644 index 0000000..99e7448 --- /dev/null +++ b/venv/lib/python3.8/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/venv/lib/python3.8/site-packages/pytz/tzinfo.py b/venv/lib/python3.8/site-packages/pytz/tzinfo.py new file mode 100644 index 0000000..725978d --- /dev/null +++ b/venv/lib/python3.8/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 '' % (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 '' % ( + self.zone, self._tzname, self._utcoffset, dst + ) + else: + return '' % ( + 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/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Abidjan b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Abidjan new file mode 100644 index 0000000000000000000000000000000000000000..28b32ab2e0b9053f39a91d9f28b6072e41423954 GIT binary patch literal 148 zcmWHE%1kq2zzZ0GvP?kCG3nVP561uh|5!kkv-tRiFt`J82nmM#2LhZ1aRE&;-~s@2 CSQl9U literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Accra b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Accra new file mode 100644 index 0000000000000000000000000000000000000000..d0083ed886487a1594af7f5f8897cf45885aeb71 GIT binary patch literal 1060 zcmc)IO-K}B9LMolU9`4Ph=heO9`XU%UWioiMqK#Q51n@Eh<6~Jaq6-;Pn4KT{;Dxnqi*LvU6D2-#2-<^;E+9 z=hY-{E96;wqxO13W;oZG`7vj^8&anGL#yqnDXO0QEq!Nk$=pr7wb@Sz)q6gw?+p&9 zz9U`w{>^XZLF15p*s)$csecF+W2o$YV_X!=W8o7)gmxtG&AU*2T$x2x^IT$_4) zX_tO7zNiLI7xdHYCNs46mwncCR6XCkRlhiM#SE`HZbw>b%*gizJ6gX_jlNl@$Ew@S zSa86O+dxfRy`T%*R-0F6EA`}>W>q}2!xk?$cD^gUKR1<`Qqw#8;-4>8nVGto^p}&@ z%-4z&>C)~ARa!{JXE**dvxUj@{K|SY-@6nqi!AFdFN^+lhhg}dzcv~~qUgmuuX2S~ z#Tk*4Z}zt&y)C|<@Vz~MK5h5Chjqh$nY&rhm!ojy|BhKVhU14NmWM*PuP-+1gp{&8c z!oZ+qz`(`8ptgpA55o5G4PnqWFfuk^aCHQ;OiURq3(N literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Algiers b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Algiers new file mode 100644 index 0000000000000000000000000000000000000000..6cfd8a16e16ec08c7cd83e6c0e1f9e1bbc5dc18a GIT binary patch literal 735 zcmc(cy)Q#y6o=1kuUi`BDmsWkq>~`2@DC^s0jTmZVtF=Cg8YM;% z1BOV56Q39_`U7bWbVr9mP^H=`H76m zSNfgZ%bc@!HL3QuKAnR?pDLtI)M2(+9S!=`@p?oRM>bXQ+;VQJmQ$L)$d+E43gw+) z`(az;aW!B+%>D_ zc4ssxhUs$uIHuL0k7?b$A0I?-yD7 B^{M~> literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Asmara b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Asmara new file mode 100644 index 0000000000000000000000000000000000000000..9dcfc19c56e62b12b730f4335b34479695f273f5 GIT binary patch literal 265 zcmWHE%1kq2zzbM`vLGzd{r}>hjqh$nY&rhm!ojy|BhKVhU14NmWM*PuP-+1gp{&8c z!oZ+qz`(`8ptgpA55o5G4PnqWFfuk^aCHQ;OiURq3(N literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Asmera b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Asmera new file mode 100644 index 0000000000000000000000000000000000000000..9dcfc19c56e62b12b730f4335b34479695f273f5 GIT binary patch literal 265 zcmWHE%1kq2zzbM`vLGzd{r}>hjqh$nY&rhm!ojy|BhKVhU14NmWM*PuP-+1gp{&8c z!oZ+qz`(`8ptgpA55o5G4PnqWFfuk^aCHQ;OiURq3(N literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Bamako b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Bamako new file mode 100644 index 0000000000000000000000000000000000000000..28b32ab2e0b9053f39a91d9f28b6072e41423954 GIT binary patch literal 148 zcmWHE%1kq2zzZ0GvP?kCG3nVP561uh|5!kkv-tRiFt`J82nmM#2LhZ1aRE&;-~s@2 CSQl9U literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Bangui b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Bangui new file mode 100644 index 0000000000000000000000000000000000000000..afb6a4a8fb17b0d4670b8ea1b38f5cc6100244e4 GIT binary patch literal 235 zcmWHE%1kq2zzbM_vLGzfwz}YAPe200v{lX*7Y4qsU}RuoW?*2}hw28ZVdr4rU|`@A xVBqud4PkHxVr>HhV*`e8#}I}P5^VYp1R&c$G{{B}4YCzPlWsE?(0W}%E&#0|N_42?K|ZZwP~~ ffgyuCkY->6p%4;G{tpBo(?LcNZvz+5G6OCE+{Pmd literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Blantyre b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Blantyre new file mode 100644 index 0000000000000000000000000000000000000000..52753c0f87bbfa457ada89d400908a3d6537ac0e GIT binary patch literal 149 zcmWHE%1kq2zzZ0GvP?kC(d2gY3y>q%15z%dz`)|;8^Yl17{U-jf+7Eb0H;A*K+|-M FxBzz~6CMBn literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Brazzaville b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Brazzaville new file mode 100644 index 0000000000000000000000000000000000000000..afb6a4a8fb17b0d4670b8ea1b38f5cc6100244e4 GIT binary patch literal 235 zcmWHE%1kq2zzbM_vLGzfwz}YAPe200v{lX*7Y4qsU}RuoW?*2}hw28ZVdr4rU|`@A xVBqud4PkHxVr>HhV*`e8#}I}P5^VYp1R&c$G{{B}4YCzPlWsE?(0W}%E&#q%15z%dz`)|;8^Yl17{U-jf+7Eb0H;A*K+|-M FxBzz~6CMBn literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Cairo b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Cairo new file mode 100644 index 0000000000000000000000000000000000000000..d3f819623fc9ef90d327380fad15341ec1a0e202 GIT binary patch literal 1955 zcmdVaZ)nw39LMoGe-G^V-ra*L3BUZ7pvu|6G|i=@<8oQbzt(p;QznmXNO4 zL87pXustvmRJ5YhGPA6O3K`U#)lS9~6!a`2m)ShcP1()0&imNI2ztIf3v&OeEVgu zZhv*9(eJL&-#s6iV=uiIbd^6GcJ-D7=SH@K=Q=|D%lV8w|M3&z*Y+mcy{SiB_+X#3 zYYNqG8-KDr%a@6Z4U=T=oDHh4cB{NJC8jQyAG4PSlcN8+Y}w!0CNlk%_V>dB>dL7@ zcHpgb>W>3Ga`1)yLTo9tkySsdtfpmh$l|ydT7Oy&o3UMFFNoRUxg9E}ASrXYM~LXK zXKb`Rp+=q^u(^9bSEG)U%4=Th6Qg%NV#hpPq+&0>F2~l^iE&TH<@kzDG2!08UYj>w zP2AROCuXWep4?&cPBp4Yy$O5$A)zLBNEzQcTTI!%!``4)sr*eRDITcIALZNYkhlFiz$zOs4I$&hZPswgUXyw!^-dX26uM75zg7y93)zw z4ex4R9n5{_!LX{~{^0J7Yt6j620j0&It{-E#+*?n2(R*S&4zeIsuidFRMm zN8UT~=8<=gynW>TBMl%OcwGxf4_?;<(go56(g)HA(h1TE(hJfI(hbrM(ht%Q(vjD- zg!JTfO(9(&Z6SRjjiK+1FSN$F-hk$i?vVC4`a>Gz=n!cU>Cx+&7FuDz~pq;I5gq;sToj^2^xk?xW9Ir>L7fMW-c zEkO1F*#wSV@Vae4_QC5m0@(>(K7*$iYiknKSB1KAK{N02Q+_5|4!WLLayTabP6 zx{X102H6^9Z;;JFb_dxWWPgwiLUst*B4m${O+t3b>$VBmC$HNmWT%j=LiP&TEU()w auiGwUzr1e4yl%(v|FmUMH)~mZN$5l{B`ll2!c#XC?l+xCu56QT8 z9~rBkC*$y2Dl{OB!k&(zu=EiXR%K7&FR!KWNnhG#JV@IzPb7w*`%V>Z39<{%( zh%zics*JDKt2uTvUUO&6Gxt2twV&l{divpANU+ew&K@*4;Lggi_w5D1Ath{V(~fe?zRrQ$$ZET)zVgkX3e83@rp$Ob|< z5YmAV4-e!6As|yr2tq`rmJx)IAfyB#CI~q}2ns?{rWTc{Wd$KDQ%eg%T&9*6guqNK zF;j~SLS_&`Gqu!AEj9?bnOblVk~6jFAY^B1;Xz2x)Z#O>{2&Uz)Fl8>1g0(nh(a)R zDL@p1smlSPAWU5n5Jh3?vVbTIQhggoAXAqRL=l;~j35dLqLd(t38I`J3d+%1*IdfV!5cW9}u?jp?SWV0>$(b7;t}y4GkevCxe-Y;V zWXW0J`~lAe{*v?XPfsfBkGMrwWzbJi-UQFZUa#|9 z93wf8+1=suW9ua6@xff)m&}u#w(?1yZ9hoP(sc2?^qk}*qxemklJlfG$M;W~Bxl)V zB>(+Wo*8^z-rB))`D4jhQIf*v6}^(P(&EPZN|Kyaepx(MrAp2-ZeD!5K0lu%IUAhH_-nqf|hukISt;RIo-x`&i!#VeO f9=^Eo|Ne2C?T_GpyEprv(D`rZA5-5IKJ)(u0)S^{ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Ceuta b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Ceuta new file mode 100644 index 0000000000000000000000000000000000000000..850c8f06fa7918684e67e9ab8192ac933dac90b3 GIT binary patch literal 2036 zcmdtiUr3dA9LMqJsm>Iq?(0}J%Ca)EKPNqEx@wx$Nu^C|=BezDnPpbX&Q50~+DcC( z{X^t?Aw@)+QCP@wZP>c7h@v7XBnXR&2#WqPN>))r#Qok6gI(-uH@n#H;W@8|0|(B< z^ZxjjuCGY7{&B+0H{6_BbMrhTWIn#XwI%Sw5&z0o*Q-G5Q@?ex^LS6&@l@-l=J|nB zyFamh-n-TMCEyA5CIn~pUVIe@-%uY4zp}CC!)K9JWLaKMRA+W5y7BkGM>h*Yl6W*Q z>`aR_vOy(o+YT938I;k>SId}upTuY8$XIuVB*Z4lxX4c>(dE^|w^MZd;{=`1Jwzv7 z4%12P@6~D2pWGOf2tr=Ro6=l6;=v!ztCI;QK4U9&X%P^`|Zh}T*5(`0t8OTFd8Wlq9V&GGh0 zuB%h?;vY!f%O^5-;02l6bydE2bX2}Ro5EnK`$7gVm% zqR%STm!GE#htAVQ?g_f+okxoY=SuPIk9Eo0@v`*SH@d7lLY6njNJ;x|vZC&_ls0wA z%F=Er+x|jVWuKANCD*k)?x3v6YSW7F)4Fzq>e^=qbX{Li*I%vCukZVG!--{Dd1aGq z+>@pLmLmCPU7QAXrOT$mObJ#Dm2Xo<%I2IuWJ`=CRmp?3s^_6pN59kR8<(W!d>R zEh9Z6O(R_+Z6kdnjU$~Sts}i7%_H4An)Z?Y9nA(HJAiBfvIoc}AiIEU1F{duMj$(Z zYz49x$YvnB;b^u4*$+pvA;^v(TY~HfvMI=}AlriM3$iiD&LCTZ>B2*3sO9ooEGsXevbCe literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Conakry b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Conakry new file mode 100644 index 0000000000000000000000000000000000000000..28b32ab2e0b9053f39a91d9f28b6072e41423954 GIT binary patch literal 148 zcmWHE%1kq2zzZ0GvP?kCG3nVP561uh|5!kkv-tRiFt`J82nmM#2LhZ1aRE&;-~s@2 CSQl9U literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Dakar b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Dakar new file mode 100644 index 0000000000000000000000000000000000000000..28b32ab2e0b9053f39a91d9f28b6072e41423954 GIT binary patch literal 148 zcmWHE%1kq2zzZ0GvP?kCG3nVP561uh|5!kkv-tRiFt`J82nmM#2LhZ1aRE&;-~s@2 CSQl9U literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Dar_es_Salaam b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Dar_es_Salaam new file mode 100644 index 0000000000000000000000000000000000000000..9dcfc19c56e62b12b730f4335b34479695f273f5 GIT binary patch literal 265 zcmWHE%1kq2zzbM`vLGzd{r}>hjqh$nY&rhm!ojy|BhKVhU14NmWM*PuP-+1gp{&8c z!oZ+qz`(`8ptgpA55o5G4PnqWFfuk^aCHQ;OiURq3(N literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Djibouti b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Djibouti new file mode 100644 index 0000000000000000000000000000000000000000..9dcfc19c56e62b12b730f4335b34479695f273f5 GIT binary patch literal 265 zcmWHE%1kq2zzbM`vLGzd{r}>hjqh$nY&rhm!ojy|BhKVhU14NmWM*PuP-+1gp{&8c z!oZ+qz`(`8ptgpA55o5G4PnqWFfuk^aCHQ;OiURq3(N literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Douala b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Douala new file mode 100644 index 0000000000000000000000000000000000000000..afb6a4a8fb17b0d4670b8ea1b38f5cc6100244e4 GIT binary patch literal 235 zcmWHE%1kq2zzbM_vLGzfwz}YAPe200v{lX*7Y4qsU}RuoW?*2}hw28ZVdr4rU|`@A xVBqud4PkHxVr>HhV*`e8#}I}P5^VYp1R&c$G{{B}4YCzPlWsE?(0W}%E&#VxM4$sA zZjO<1!_OqfhyB$Cr%$6UV zF+Hp8+aC`$wtqNke|7SbGj{hKdt7a&Gk!zm>}zhK1iv0ih&ZkivYIHd@O?@gzeYQJ z>S>4VZ8C2>NaohZ$UOP7vcx7)(nD#KR5+!QTD&Rw>5Y`U5J@}DhiPZ=XUh7ZMOnub zrKr1GgL?Z1swUeXmcjcJ2ssm+22RiyyzGVgFSJ3g8b z@QaPJ7-8!pj8J~BH!T0`K)3!lJFuuPc!2MN3ry_;E;s?g3lMIA@B@S+AUt7eS3vl} z)XsqL2825x`~l$*2#-Lx#MC}9wNoIxVrsWQ_{G$Yf$)r}U1MtBKsX1&JEnGzsr>`t zAX9q?!bPU`5rmUW?Ij2|nc7dLb`*rCOzkQNUzyrj5Z*GiyCD2!YKK91%+xM}@R_Nd z2H`bRyA8r`5RQZJoT*(0;X6}155jw;S-rtS=g-hk*1i2i`+5QrWzb(cW&iK#mU7H=yhrc-j3s4#`OBwliUFeAQ{ zhDgq`zAc3PviVE}9&xo2b5L@YXD2Jn17Nvq^+SV-mX|71-OuQ&F6#dG65$=Otw z$LmcuC1=8~)(+vo^`u>EFQTJ2y$rt_c&*-6qM|({_%}_e@L93uUkK{)G<7 z*=ru+xwk@cUS22v3zw}Q^ZFMHQ~dca!zE|m@DX0`_mP}e8pC=2ibrw|INUrBG)vB_ z+qUxgt4_%|^yp8#KNK%Hzn-!3JRBl9ulE^z{`!0fuaCHLc^(;%oSy7eyzV(6IY%SU z^Zuw!a*hQ&#q(ISq%15z%dz`)|;8^Yl17{U-jf+7Eb0H;A*K+|-M FxBzz~6CMBn literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Harare b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Harare new file mode 100644 index 0000000000000000000000000000000000000000..52753c0f87bbfa457ada89d400908a3d6537ac0e GIT binary patch literal 149 zcmWHE%1kq2zzZ0GvP?kC(d2gY3y>q%15z%dz`)|;8^Yl17{U-jf+7Eb0H;A*K+|-M FxBzz~6CMBn literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Johannesburg b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Johannesburg new file mode 100644 index 0000000000000000000000000000000000000000..b1c425daced454f53d7d18fea807bf8d081cf97e GIT binary patch literal 246 zcmWHE%1kq2zzf)bvMfN%*#IP(+|Fm5S=ZBWc3ytLxxT!H^L2p*jLb|x$iN`w093#r zDgjchWxxm|WfT}#e0)O~f*pfH7(z&}>OTa}0vc4x1SA0EY#XPnJp z8QJhjqh$nY&rhm!ojy|BhKVhU14NmWM*PuP-+1gp{&8c z!oZ+qz`(`8ptgpA55o5G4PnqWFfuk^aCHQ;OiURq3(N literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Khartoum b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Khartoum new file mode 100644 index 0000000000000000000000000000000000000000..8ee8cb92e72d9c507ad0ee06dc6a38406ab06f34 GIT binary patch literal 679 zcmcK1yDtPm9Ki9}d%0V8IInXYHlYv~iCh#K@yaFQkxX*ipfJ@Pg(!3qm#dJ7#vh;& z5>aWi8ja$;?cBe0o?}a$Z7-wrl zhPFRUc)6k@s%oNRFFH1%OkJ-hh>~_izi}USWxa`+jub zO_|<%Qq7f9-LiVCT4(dRZRT9H=T~HA;6QaG4|O)ap|Yr WK&F690+|Lf5&WO2xOO~41@{Xi&4u6q literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Kigali b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Kigali new file mode 100644 index 0000000000000000000000000000000000000000..52753c0f87bbfa457ada89d400908a3d6537ac0e GIT binary patch literal 149 zcmWHE%1kq2zzZ0GvP?kC(d2gY3y>q%15z%dz`)|;8^Yl17{U-jf+7Eb0H;A*K+|-M FxBzz~6CMBn literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Kinshasa b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Kinshasa new file mode 100644 index 0000000000000000000000000000000000000000..afb6a4a8fb17b0d4670b8ea1b38f5cc6100244e4 GIT binary patch literal 235 zcmWHE%1kq2zzbM_vLGzfwz}YAPe200v{lX*7Y4qsU}RuoW?*2}hw28ZVdr4rU|`@A xVBqud4PkHxVr>HhV*`e8#}I}P5^VYp1R&c$G{{B}4YCzPlWsE?(0W}%E&#HhV*`e8#}I}P5^VYp1R&c$G{{B}4YCzPlWsE?(0W}%E&#HhV*`e8#}I}P5^VYp1R&c$G{{B}4YCzPlWsE?(0W}%E&#HhV*`e8#}I}P5^VYp1R&c$G{{B}4YCzPlWsE?(0W}%E&#q%15z%dz`)|;8^Yl17{U-jf+7Eb0H;A*K+|-M FxBzz~6CMBn literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Lusaka b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Lusaka new file mode 100644 index 0000000000000000000000000000000000000000..52753c0f87bbfa457ada89d400908a3d6537ac0e GIT binary patch literal 149 zcmWHE%1kq2zzZ0GvP?kC(d2gY3y>q%15z%dz`)|;8^Yl17{U-jf+7Eb0H;A*K+|-M FxBzz~6CMBn literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Malabo b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Malabo new file mode 100644 index 0000000000000000000000000000000000000000..afb6a4a8fb17b0d4670b8ea1b38f5cc6100244e4 GIT binary patch literal 235 zcmWHE%1kq2zzbM_vLGzfwz}YAPe200v{lX*7Y4qsU}RuoW?*2}hw28ZVdr4rU|`@A xVBqud4PkHxVr>HhV*`e8#}I}P5^VYp1R&c$G{{B}4YCzPlWsE?(0W}%E&#q%15z%dz`)|;8^Yl17{U-jf+7Eb0H;A*K+|-M FxBzz~6CMBn literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Maseru b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Maseru new file mode 100644 index 0000000000000000000000000000000000000000..b1c425daced454f53d7d18fea807bf8d081cf97e GIT binary patch literal 246 zcmWHE%1kq2zzf)bvMfN%*#IP(+|Fm5S=ZBWc3ytLxxT!H^L2p*jLb|x$iN`w093#r zDgjchWxxm|WfT}#e0)O~f*pfH7(z&}>OTOThjqh$nY&rhm!ojy|BhKVhU14NmWM*PuP-+1gp{&8c z!oZ+qz`(`8ptgpA55o5G4PnqWFfuk^aCHQ;OiURq3(N literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Monrovia b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Monrovia new file mode 100644 index 0000000000000000000000000000000000000000..6d688502a1ca80f2e57a6de2790ac3193879d248 GIT binary patch literal 208 zcmWHE%1kq2zzdjxvMfN%(*PtE#OKUmJ{6V6$i)2r|JNrB3}BK4NKOJPVqoC#@eN_{ i1!8v~4k5w#|3DB`wQLTE23Z5Nje!KKxPbNhjqh$nY&rhm!ojy|BhKVhU14NmWM*PuP-+1gp{&8c z!oZ+qz`(`8ptgpA55o5G4PnqWFfuk^aCHQ;OiURq3(N literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Ndjamena b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Ndjamena new file mode 100644 index 0000000000000000000000000000000000000000..a968845e29b8b2b47d4a73f74ae04ef681d7d485 GIT binary patch literal 199 zcmWHE%1kq2zzdjxvLMVm=~+XHP+DPuu-d%@MkYoE20j^(Mm_-s76t|x1x5}Z-w=jy gM-UDUVF)3?HhV*`e8#}I}P5^VYp1R&c$G{{B}4YCzPlWsE?(0W}%E&#HhV*`e8#}I}P5^VYp1R&c$G{{B}4YCzPlWsE?(0W}%E&#-3N{@?jVZM*EQs%vx@B49?`FM-@HCOyP9P_uv%;tl)i^Sd8iFF@8 zl9lyqtMa(2t3%_edRW%a*-O7=ds5o9@5=rd(5+AXe%tM`Y%d@C9p?`+R@(48_if#^ zQ?I(WUZkU@RnN+%?#*4PcsimJsj#0+j>*1>Q{T0e5n`? z1y|&!-*2qu3%3vrOPnO;gv@@MEK$d^Xq=h##8hU1#S} z)P`MK+$q)`qW0yZXc{GOcU*3^$JA}*$-Y|)tNXcdF<5Il zp~|7vd9dQBa-S95OF6OhkTWpc>%=1gXE1$cCHx6%q8xNG>2;Zmx2oC9o67kws`*$` z} nNN6NB5*&$+gh%2d17I-(WDv+Okb$`Bq2Rv{CZK0Dk_>zRbScYW literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Windhoek b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Windhoek new file mode 100644 index 0000000000000000000000000000000000000000..abecd137b1fc3220637b22ffea0e7256a58e9377 GIT binary patch literal 955 zcmc)I!AsL&9LMqR%nh5Mk6I|nF@gftvuMYOMwIr)^XzF zN$lXk4jlx=lO6@32$Sei&_Q-G!c!0-BI)z~{Q-g}zp}kRFY>%U&gghLEN5QS{?%tc z<=TGDB)&fTvYOSqOPR@P--lc<`)RCxyizs1{w<;I|Elq+SBGnIDw6o6ZRSw73n;xRf(d1lK5Gux(-Wq_x5#j@5f(#|NUjtv+-T`&K#J&g-!k7@viBA`A!eC zubGEq8!}imZ<4V^aSB(}P+(ey4vb34BT4PNP{X-48Ch|ZC+||8H~*YJBC5c?gFsKpBi)hqNPlDl$PSP#AbUVIf$Rd=2C@&1jUYSW*b1^2SGyTxH?DR&$bPts M*pS~2DH!&j0&cX-R{#J2 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Adak b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Adak new file mode 100644 index 0000000000000000000000000000000000000000..43236498f681cc06f64ca2afa613880331fe6fbb GIT binary patch literal 2356 zcmciCZ%ma{0LSsm-|Iy&Dj-Bm!Hl7RhrdBt9tc86oi^IjQM+~Y*&*2zbbYMq#bZoSBp@5Baf)v>D*mc{?KkJo0^@vqt7j*K)_f*Qz7dmyMORerXqQyXsN^AUFrngI#QPeLpD-u*z z;!c^J5v-nYdu2{syvVthEpz9B#FOV@C(cetPtrc&0yEuYLc7kS()1Z~s}9 zUv^19TmOkFSpAJIEa+2(zuu5VDIbfXi{r95{E#Rf8IdJ3&EomNZ}s}`4ye+ulX}Bf zuc)#u1KK%SqRQ9o)*CyLRYhEt_Es)b-nm>|nRQcDUagdymWGQ>XLID{J2yo2N3rt7 z>2a}T|D1ejY(&)5Ps^=C?}*yc+q&-HNwqEIvfkb}pz6cNbVJc@)i85hHzro8#tZv& zlRH;64cF`DYm3#ZM|?e%fCW* zj|Cb zzK@T~_1P7d%kOV+T)}>Sdu_lx`(0pviLm!bzOER*zqd7DiM=mcU+Q&js4#Dpc^$7S z-`w*Hyso@;=CaOQ%n9Jb`Rn5S?~#R>Kk#ynn3sFJ-<-8){usyZgVi<2=#b%A&G?W3 zq8%X@hR88v1O|zW5*a2kPGq3SNRgph%~+AaTFq#Y;UeQj28@gt88R|vWYEZ{kzpg_ zMh1?I92q(?c4Y9#=#k-D&G@Y*07wLo5Fjx?f`CK;2?G)bBoIg>kWe78K!Slp!)n5T z#KUR=fb2@Mh(BsfTPknkY!v6=uO5kf+Q#0Uuz5+x)| zNSu&BA(28tg~SR877{J12^SJCs|gqqF{=p~5;G)dNYs$9A#pIBoav^lt?U*U?R~(!imJwY66Nx)M`SC#MEkn zibNF&D-u^Eut;Q)&?2!#f{R2K2`>^~s|hd?VXFx-5@V|gG7@DZ%t)M(KqHYxLXCH0 z9UK@EdauXrnRg$bziVB+?f+@^KheH>3o}7a6Q=0Nr5UN|sUo>FEiE-IRfPQs4Q6_I literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Anchorage b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Anchorage new file mode 100644 index 0000000000000000000000000000000000000000..9bbb2fd3b361ea8aa4c126d14df5fa370343a63f GIT binary patch literal 2371 zcmciCZA{fw0LSqQ0v8C15>k=qB=Y>=0R^EbF9-r60dl(ukxF8BSP2AU_(W1Vaw{?0 z9L`3^IkwuQo#|G(7TvVgCgupY9>$_{YbHzAdYVOYJKvM57d7AI|G)G99PW7g`??!i zp3HIl>j^WzaCr8a!#!oE`Hb$#^NlC`+&11+EPo#_Q!^(vxcqOdkdA>;SHO!YGO#<@ zHLJZu2Q@AC1=l9&kfKDNGdol}UtZ@6i<;75!xOIXAI|FAz8UpJe0f<$`i6bCpB$BU zym`hIb#PeTx#y_st}Xp?cFSH@bbY&wsc3WET~H_Iq^@?&UC^rMg)MQ#2G;7>^ysMA zAB*+;i-{_3e4)PQlvBkY3(@x;zN|!7fxNGGR4wq#mkFD`6AN>%%fyvuL{iMxGCA$2 zNS>M2so{G?>f~2CZK_SAkG!ul&cCEG2M_D4;#%***zEp@Jt`Ej#F{-qRIF#U_T|Ko7^z{KaGP$%gJ-#sZF+83&q9Xcdjty8*a z*E_1X`mA2wd{C7vdP|pAR2}u z#M%kO?^ky6Pf4q2Jddw9I5rjGOyZrWxw_&S19i% zow~)Du3CmYdefyy_0)k5`Se(tc&6(SxmibuR?kw|)_+yB=gpJPwvLI8m}%KreN1%v z=jg8dbE<3dH{Cr~tL~8rz2(||wRP}4z3q!mwY}$cz2k&O^{nmH&kf|OfWTP+LBThB zLqeUm@O3yoyykHD{T=HaL4JR4TR^D&M%Z7X>^+9BBi8Tl-x&~Z?+L4_+>W9;a~?IP z#+-8gC@*n4>bX>!OHrk{nJ0h`&tDh!e{U_^`~!#Q6?3?!_|3EI)b&qsM_*AnvOQ#f zRB1(*dLfNDq)EAYDM(fb;=r1kwql6-Y0TW+2@_ z+F>>QKpJ8-9YI=x^aN=N(iNmFNMDe~Ae}*4gY*Vz4$>W@JxG6$23bvqkQO05LYjnh z32773C!|qGr;t`5y+WFWbPH*h)$|K#nALO)X_?jZ3~3tDHKc7w-;l;3okLoO^bTnr z(mkYoR?|PEfmYK&q=i<~L!^mF7m+q1eMB0GbP{PL(o3Y7NH>voBK<@fYBe22T52^t zMVe|gT}9f8^c86=(pjXnNNJ z%NeDEoH2H4!Pm(kNNDF01QwVW3$G>#M4m*fzz*g1-7)A^&FI>e|gYshj+%>-8g}!Y%#q{irnD-O!CM zYE0wtxN2(uYnpb}mAsph*4kd3e6CDbF{V=KNK%C#s!i2P+t!F~zgRQr%#7+dJdwvA zoAr|oYdYUl>!&N9q^s{#_kS3Y0o9?Wt+nx3$=|rO+u0zn_9P!Gw{|xhRQB{nL5n2a z69!QUYq}p`Srl2->y|~V6aN9y?nXxd literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Buenos_Aires b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Buenos_Aires new file mode 100644 index 0000000000000000000000000000000000000000..260f86a9180677d86fc3280b06f01d6a6cd91c94 GIT binary patch literal 1076 zcmc)IKWLLd9Eb5YHqjUg1{4$#sn}8y5sox5;-B(LhN`qn4Je%yL?{S~gB3)hi<1zL zAP6mu?cyMK4%O0Ddm3wOhZ0Cd1c!j)rl`aatM>doH#vz;=H=ecL6#T3Pj+DNRKok? zuUr0IEoZ|Od5zu3s|OeR{fC?9_2kyPKe=>PO>MknrY6Sqbo0JHbMuvY^!lB7d?BJ| zr#Ja#Ag`Z{jQCIYmQ?9-#XQ^6&~wLw{@hAjl@Fv%xpq&zxLWWR`flrmkJrp%pH++c zgQ><+dMR_#)c1!~eY9b|hEA(SBI-BZkLu?7jA@pu>RWxtU#{-b-%Ba;W9EqZdAHwR z8BQsCJ?XC*Kdi&;XNubk6S_TGD0Za3=#Ee4i=Ernsm{u=V$A!jVtP+8UaP7dw~n@@ z8_)Ib*|_c*TC02B+Q6!ozkEW$-<}qC4_P~(^gL@z6)$LQ*?3`V zUseLG*1oL;qTIdK-oC7tk+V}J<#fqOc-engMn2M>8@|(vEQG9tEQPG)l*N$MoU$CU z9*xjnBZm(HoF&6n-e#F&|G+}AU=UaCj0-rC0(V`g@G zi?#!K^JHX1&mAbK(v^yRx~*>JPlomUYL_Y>PT6v8Ts^;5&?GDu`z8M<*NF+GNiv%_nPmer2R2-O#QsquUChY z%H8PEYsZe5X#3gX&ccLgZ!Hu%QlCx7#|y>I9UD|<L>5I>MV3X@MHWU@_R7-8+Fn^4Sshv4E9)Z#c%=fQ1f&L}2(MIul!4UY zl|qn8yiy8M3sMYH4N?wL5Bh?5k%}bvfRd1!kfM;Pkg~i|7gCs4Dnm;1N^MASNOeeg dNPS3wUa1f%(JM7#PJZqG6d5}xZT5D@egU`L>mmRE literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/ComodRivadavia b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/ComodRivadavia new file mode 100644 index 0000000000000000000000000000000000000000..0ae222a2f8bb2fb1b7abe17d08e076674c51541d GIT binary patch literal 1076 zcmc)IJ!n%=9ES1RG|?Cf78Dc_sn}9d6%J`*#E)_$LqW_^14<_c5rl%`U*xjnBZm(HoF&6n-e#F&|G+}AU=UaCj0-rC0(V`g@G zi?#!K^JHX1&mAbK(v^yRx~*>JPlomUYL_Y>PT6v8Ts^;5&?GDu`z8M<*NF+GNiv%_nPmer2R2-O#QsquUChY z%H8PEYsZe5X#3gX&ccLgZ!Hu%QlCx7#|y>I9UD|<L>5I>MV3X@MHWU@_R7-8+Fn^4Sshv4E9)Z#c%=fQ1f&L}2(MIul!4UY zl|qn8yiy8M3sMYH4N?wL5Bh?5k%}bvfRd1!kfM;Pkg~i|7gCs4Dnm;1N^MASNOeeg dNPS3wUa1f%(JM7#PJZqG6d5}xZT5D@egU`L>mmRE literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Cordoba b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Cordoba new file mode 100644 index 0000000000000000000000000000000000000000..da4c23a545b3603bcdd4555ba8feba117802e7b4 GIT binary patch literal 1076 zcmc)IKWLLd9Eb5YZK5$03@9if60xNuA{=RB#6RVg4plKr4Je%yL?{S~gB3)hi<1zL zAP6mu?W%YV)zU_L8f&ye38W%|LqKs;L}G|ld;Xqt7oE(@y`O_DFMOZu(D13G_s3tK z{JTod`YZC9xRF;6E)Mz+H@(!;Tk`(&(pfdL;gXq|n$)wc`+n)>YxU^Od-M20M9|wz;Y2j|ctvm4vG7Pn$~po_cY$;4fru>xEC(%woo>Mg7s# z;winlZoJu zSD(CHFK6>*`MGl=rygDy(2usgFvT4?U0gYht9#9lQqumMJ*Ix$9nfoI zN#(Bh>J5`eOr+yXVP}5Ibj0$7&eRvv`FW(!6(6!)@7|bQtJie5*O3>B&#TFxHTE2l?JA{hLKJ>(PJxv_giWEW%`WFKTBuk3_u<(0jV&5+%Y?U4PD z4Urv@Es;HuO_5!ZZN0KDvawfoMz%)w_R8kS?q1m**&k^D>A)*3AUz;Wc%=)Z4X^Zp zG=g-3w1V`4G=shy9;6+~JfI(>A*3UuC8Q^>G=+5Km9~(+kj9YCkk*jikmiu?ywV^;E&fq z`MN^Rx-0Uyb0e!BTnKr>EU7hWN%RwFVEYjn`&m}cv#OYcc{{#lr2^6spnU7dbaPjnf-Xp&h*ULjm z<*s+@m7|AEwB<~GYp!5g;<a%J6bUxp{WsPcoS;%i|YtxBfNhQpld`G3Mw%)?PakcFoTxELSWSTS1xllvnU*3`M@4La%7{Q2h)9D~^t~eiroh#WO z>fGXdsL8pvl~A1bpy^0oI_QzJQ+3PflG7Qa|6v~aOLuO_>_BEhrb6aICiBW{$aG$r z519~|5t$O16PXm56`2;97nvBD8JXHEb0d>`Wp-qGWPYzCfMnp66p$Q{B#1K1f37GvY;3lIjC;LXtwVLefI=@=9VzW?o4R$qh-)E7>9G hA^9N*A{inndL>6BNv~vy8TrNklxA$7M0%hr_6wX??F|3` literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Mendoza b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Mendoza new file mode 100644 index 0000000000000000000000000000000000000000..f9e677f171b3900dfd978eb8ea2aa226557d2c5b GIT binary patch literal 1076 zcmc)I&r8#B9LMpmy44a71A~4LA*7g#;KSTnP{~I;7||{^3Osd)A_$5O8T4ay=@blN z1cBnpYtW~_61DcJWh)^W%!r`FqUcsctYKDudOtsZK-8&y`Rwr>8{-SFXJ+{L(RlF3 zSD$>lO3vC#@^l`ksiYk2mbM@Cnt3M|I=lxLIl+uuJ8t`d%N=%hes`M=5E4&K^*|ZV%~| z(WG)$6MFT;J`?FYS=f@FG@a3Wp)2*(bbUEf=-!af-7iaK>+&(%WA>U@?Va9s<4{Mc z@yzTj#*8-YrvG4{9UNI>2H$2ovd+1t=9a&_!XYmI<50LI+$^8M&K1uGfpeuw5OS_; zgNSplDot(9y{|Pzxewa*r!&ETob4(hr&mrq$o#`H@{sQI=so#==U50?30VqR%PWf^ zt9fNPWIbd-WJP32WKCpIWL0EYWL;!oWM!``jjZjJ#gWyK<-M{#Qh-+~KuSPrK#K56 z6-XIK9bPE}sl+R#AhjUHAk`q{AoZXxh#RR$f)6MOsR=0xsR}8}D|I1-d8IO>G^949 hIHWqHJfuFPK%_#XM6c9{S$VYoQ)KIIX|u1l^*1v}?Na~% literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Rio_Gallegos b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Rio_Gallegos new file mode 100644 index 0000000000000000000000000000000000000000..c36587e1c292673fa537cecf729f4c873d375c9a GIT binary patch literal 1076 zcmc)IPe{{Y9LMqBbgN}TgMuO?j1-v>JWSW3Kk|eJA@X8_!czwcf}rS-LDcHfDHy~E z0>zcrpr^nRXZh5!l?NG2iJ-%v=vHK`vHtn=eLts8QKx=Cp1poQcKN~QogO}UA`$%Y z>XU!h$k}vRer{jSss|T_^uw($&Gfdco?bemW;S26GgFhM(72~(Z@f~EUca-C&$pPl z!WM0Zv*yY8xPH2?sEU`$_E}rq%pVWy`PFV!I+(Jh>Rt8XN=`2f-ZBdxuiC{yrxwiz zTZt#lQvZmp9f+#hMBRRgoKp2fOxNE}n8wC_+bC7k*V?H5R@rU77nAnK>=E_z&X8Um zODcD*SFfEsWTG9X^E+}=rX!Ziccwm@&QIs^UE4RPuJW;bJXle2vp3&et*D(hkG7}k z&&{5>Zlen;N-wXs1EcHAz?)2a#yJ;iYW~YR68`OOjx@g7iNuBOmF`j@=(Y7D84+mO|F@%3{cBURe%V z4_Odd5m^#h6Im2l6ahR- literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Salta b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Salta new file mode 100644 index 0000000000000000000000000000000000000000..0e797f2215ab398bc59b8e4d60e5260fcb365c3b GIT binary patch literal 1048 zcmc)IKWLLd9Eb5YZK5$03@9ifQn95ZA{=RBM5~-+D2Q2VKdkRuHW&PC`I} zAha~vwdgriOIz*PSfd?EAQ2H93W}Q|5<~pg^Y@&)=;Zry@8^YgdExuyhfbYL1%JHy z5`q9nlQ7i`+Dx?EA{C0JNx)T%*@Yj z)^@01o{Wv@g?(jJzFf6Ww>Hh<@vvT8O{&VljIFHPQ_rs!^-}J(S^9X*F6W$DHXm#) zkv8@03ES8oRgLkc{SrB?nyI*Mz8^QO4O!c&)YR9;u>MxtZN8V&_Q%{2^>cDiua2gb zyWXeQP8>4Pt}~?_#VOMjFP6G9pH26t^QE5c>s3$nSSb-WoiKY#$(5SgdFyCrruoe5 znNOO5;dN%<%}D2nb1u}@{+D+o{QGXhb~zE}7AAwhxpFlKJ6Ewm)VY_{P=|AGS3+^# zgO0gduH=_?(hMLCmEFgq}QzAP9;FD~Lufo`iq| zL1;;|SHbBaTGD7n(;6*U0;!1LA)t6uRAPv)j`NLo(UZH({ucJK@c+`|Cr`w@KVApz z*H!kczic13uV=-*3uE&Bre|t)OIFSyPt>!v2vV7yEc<}12et15tDsvm9 z9?z;rQ&aNs-m0ixs_Xg9ZMASLAQx7mqBfGywdP&%^h!=Hrf#Xl4_Eb4%7`WPUN;8g zYB_maxAuobE8o^%f~Q0~7Lo0DdDU5$)SX&Gd~Hq0Z;f5*do`|ql#hs?cgEz(WL%hQ z!*ccXAr;#|7c%BW z-Pdi*o2D=eWH4A~R&(*H1z{Y!Ipa;A*TgiM9Zg-qtOvmw(t?R?0D z$c)I8$ehTe$gIe;$h^qJ$jr#pPCGX;xzo;$Opna(v4-AEW0h9Oad;kCd literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/San_Luis b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/San_Luis new file mode 100644 index 0000000000000000000000000000000000000000..fe50f6211cff908f21257cb42259fe2692abdc4e GIT binary patch literal 1102 zcmc)I&r8#B9LMqR+`ed|!=Rv_bV;#<;KST9=+{SfSV_B>hw#)Pf*>e7WDsRtIt7Co zos_MlTi_?kl4<#|Wh*H$W<)ok=vGkJuu?z0pPxS<>eRk`_V}_N@P*g2r}xy!Wbnt= zLHV{(&ic#pcKdo>J-pDZA8meV#l-f+>DM~BV$(mg$K^PPJ9{-b?zK5iz* zH)`9PH&a7H`sv<^s$810&$iah^zoRUUTss=&JJ5$7*Q{-6!c8)mYMl-)z0Renl+zo zZD-odXHM9~{Y`4IShwH9)2g0K==!IkSz4E|OVyhCvDmMF)^?j;m9$-+II33ecI(x_ zv~t%{x^cM6G&P?oZ7+K9GApIg;xMGIDmQl$>@s$)M*SMv`ZBeS;$pkg<@#kkOFg zyfPj#pjSpjhD63h21Q0ihDF9j21Z6khDOFl2KUP7$nahn9|-`7z$+mjF?b~iBnl)9 zBo40xf<%IZ;+0sCV7w9y5)Kj%5)cv*5)%5DxRIcw{eY;Du#mWrz>vti5*iYlSAs*L nL&8JiLjpu1L_+jRj9v*6i4qADi4zCp5&vtT@qLo&f%f=s5oP)$ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Tucuman b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Tucuman new file mode 100644 index 0000000000000000000000000000000000000000..c954000ba9b28204cc3223628d13e9dcfa4b6eb0 GIT binary patch literal 1104 zcmc)IO=uHA9ER~tnrI9K0}6_WRBS1U2tz-N_{B&LRWX+uPPzx7axJIspYPQV);%}l8*+Ml{0e=b7P2jS7e~y#$)hbmdm@`6yCT~n`yv}7J0n{odpl)wWOt`*kL-^$;FJ!K7M#)p(ge~4 z(uPy|KpH_haY`#lFHUI&=>};B=?7^D=?Gm*JV;NHzDH9?S4dk(Ur1w4=?rPjDZL@h qIi)+KJ)}RRL8L>ZMW^(LH0hKskv5S&F)N??zZ#A1lv;OpMt=cv@bzl| literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Ushuaia b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Ushuaia new file mode 100644 index 0000000000000000000000000000000000000000..3643628a24723239a13d61b2215c907cdba03985 GIT binary patch literal 1076 zcmc)IJ!n%=9ES0mHqjUh1{4$#sn}8)5e{i%#E)_$LqUu~4Je%)L=XhU!3v_)MI3~J z1VLzNw5#ChP_1n>M`Mk4D1o$y;80N96qOj_SC9YaOirSc_j2;Pmn;|FC)a=Ccry6o z)g%9|khAWR{M^1ir0$*X)Au*NFq4~y^yI>6HMRbNothXk(~WUGbK|9Y`0A~FbS`F! z(;KwyA2N?eM)Z^2B~`juu}?SE&Fs;zo?T9;^1ie!FWptoFX#1K_LiCZaK+ANotiiA zZM8FH7Ba_dZEsZ7M(g%V?Gl$gAJAHb2 zIHlaRZoP7BzlpY;Ds0V9n6`Mn(4PKm+CQExbZl9pIx0sBoxvy7X?7J7OI5Y)=Hb?K z{h8TWOc?#(pwf%0ZSTM;)BAd`bnc?xP$U?|U$Wq8!URexT%`3|x z>mdswDmmyyD|=;WWNoi3j;xL>@0InD0=!ZIQUX!~QiNBkK*~Vs z@Jb;_C0;27sRbzpsRk(rsRw;QJV-?nd_YM^O-NBlRY+N0sS7F0E0rOod8Ia_IHWqH eJfuFPK(ADYl<1WjaZo<({}dV9BW?C{#eM;(o9jXV literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Aruba b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Aruba new file mode 100644 index 0000000000000000000000000000000000000000..f7ab6efcc0f5bfd5c4172cbe32c03a8e08b0099c GIT binary patch literal 186 zcmWHE%1kq2zzdjwvdlotH(5?k`P+;)9*j)?|L>1wVEF(4zzznM|NoC4VBqrc4PnqV eFfle@a10J%2qD4L|3CmT8AKCjIv3Ci6D|O%z%CO2 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Asuncion b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Asuncion new file mode 100644 index 0000000000000000000000000000000000000000..2f3bbda6d3586a2ef5b94bc28ff37906fbc758f5 GIT binary patch literal 2044 zcmdVa`%l$%9LMn^nI@7RGzC<&>_QKn3%bH!#A35{g%JO`U5= z;k^9hXl}Jx@m7}Q55)(6saypcR-0}nzcrnVY*{hKx6kwY2ekE5>zsW*kF#@rI@{;@ zDzB>9GBfaxufy)w5$*{#yW{he-&-D?al?#!IG~B$4R-YDYnpWNFZ=lJAsN$}ZN^rG zHQ2D;CU2Uj<0?*?@e9A!C-T$Ggp7wWF|F99jLOlJ!Df?sXQQOu?68x*{Y55!nQy0j zGFj8l)tad%%4AyeIs0V%us*e+*GykNQlFl`$~+T|$+Lwq^W20w%^1;XG9J7y&-WiU zFKCfwc7I`KTp1-<7cQ9Wc#?+RzGZXD`c>-2nQ(5k%v>3=k+GLFnisUuKf5J&;(eRj zcUSWsT(|jM-|4I$FWVQ}+BMeMYi74!mO1q;w&27WnOpU-G28b@VST@ODe{rdTiRph zkAFuOgfE!|zr}UYr0?yb-ep=esP^TKs4l+oo_(b&CdD6kwxlgxN{{y0vSv?~#D~n% z(pp)z{dTi=TDB&PHd}vglIp&DrlxbXZ0qVa zuYb5pYuhfGH;z?m-Jw>qy*j4xZSA(cC|!3fe%J2I@U$Uwr+qVdiZmux*v5e&*>xw+ z?(VrQP1n-w9=$4iJ95pwmh-Z|HPsx5ACZGQ2F*dw^M)lnk}&+gd=K}$Zw3MZ|8$?f zvVq4u?}wg166Y{?@=b9`d7#ie*%Eb6BvAe@Zo2!EUd_?u7Uageiyz?DBR3zp{YU{w z1xN`<4M-746-XIK9Y`TaB}geqEl4rGt{S8qq#mRoq#~pwq$Z>&q$;E=q%Nc|q%x#5 zq&B2Dq&i<$9#S7tAW|VxB2pt#BvK_(CQ>I-C{ig>DpISjD;BBN*OiOZixiAhjFgPj zj1-Mjjg*bljTDYlj+Bnnjuekn@9WA(>i2aEfUE$r1jrg7i-4>GvJA*NAPa%41hN#! zS|E#otOl|i$a?s?1wmE>SrTMTkVQdO1z8qkU66%ARt8xbWNnbeK~@J@9%Oxd-2x#i zov+(~|L5W*&UV{Z5OrsyAgd%Sp>RlYB&#G6it-`xZ(B1OTmS$7 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Atikokan b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Atikokan new file mode 100644 index 0000000000000000000000000000000000000000..629ed4231944255aaa0725f807517df48b39e135 GIT binary patch literal 336 zcmWHE%1kq2zyNGO5fBCeb|40^B^rRlyd4W0=I{DhaN z#K_FT`v3nb83u;`|95U+WcmMp^#TSCFq;QV3V=uk5g*?W24@!_4hG_IAPxv&a0RkK vfDuZDkl?KUKv49qB?Ux-oCl&oP6W{)XM$*uQ$aMyxnP?5PUZso!ITRCV)1m0 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Atka b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Atka new file mode 100644 index 0000000000000000000000000000000000000000..43236498f681cc06f64ca2afa613880331fe6fbb GIT binary patch literal 2356 zcmciCZ%ma{0LSsm-|Iy&Dj-Bm!Hl7RhrdBt9tc86oi^IjQM+~Y*&*2zbbYMq#bZoSBp@5Baf)v>D*mc{?KkJo0^@vqt7j*K)_f*Qz7dmyMORerXqQyXsN^AUFrngI#QPeLpD-u*z z;!c^J5v-nYdu2{syvVthEpz9B#FOV@C(cetPtrc&0yEuYLc7kS()1Z~s}9 zUv^19TmOkFSpAJIEa+2(zuu5VDIbfXi{r95{E#Rf8IdJ3&EomNZ}s}`4ye+ulX}Bf zuc)#u1KK%SqRQ9o)*CyLRYhEt_Es)b-nm>|nRQcDUagdymWGQ>XLID{J2yo2N3rt7 z>2a}T|D1ejY(&)5Ps^=C?}*yc+q&-HNwqEIvfkb}pz6cNbVJc@)i85hHzro8#tZv& zlRH;64cF`DYm3#ZM|?e%fCW* zj|Cb zzK@T~_1P7d%kOV+T)}>Sdu_lx`(0pviLm!bzOER*zqd7DiM=mcU+Q&js4#Dpc^$7S z-`w*Hyso@;=CaOQ%n9Jb`Rn5S?~#R>Kk#ynn3sFJ-<-8){usyZgVi<2=#b%A&G?W3 zq8%X@hR88v1O|zW5*a2kPGq3SNRgph%~+AaTFq#Y;UeQj28@gt88R|vWYEZ{kzpg_ zMh1?I92q(?c4Y9#=#k-D&G@Y*07wLo5Fjx?f`CK;2?G)bBoIg>kWe78K!Slp!)n5T z#KUR=fb2@Mh(BsfTPknkY!v6=uO5kf+Q#0Uuz5+x)| zNSu&BA(28tg~SR877{J12^SJCs|gqqF{=p~5;G)dNYs$9A#pIBoav^lt?U*U?R~(!imJwY66Nx)M`SC#MEkn zibNF&D-u^Eut;Q)&?2!#f{R2K2`>^~s|hd?VXFx-5@V|gG7@DZ%t)M(KqHYxLXCH0 z9UK@EdauXrnRg$bziVB+?f+@^KheH>3o}7a6Q=0Nr5UN|sUo>FEiE-IRfPQs4Q6_I literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Bahia b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Bahia new file mode 100644 index 0000000000000000000000000000000000000000..15808d30fb1bb250cce195a00a2d7dca321df7d3 GIT binary patch literal 1024 zcmbu-&r4KM7>DsYQ%OvvZCV7WuZf5?*4x}kr?R0{B%~1x^kdN~By&-V7PSa#(Ml+a zNU+UWMYM>s3C18Wu(XvCMPNEkO{;2=Q8tXl={)BTD8hR=d=__eIp3#na&RCM{q@QF zudDo7f9Ju_mSRJ1x%m5l8DGrm zKI-g`HK$~0;j7d*C($0ZN*ht~@BeE0#}3&ey|-l8IhRbV;7vOB?qd`=S1Bh}JNM>gwDxdcA?nnOKXFv}kNfw( z;@AM$A?UY2_CPj4b_x1zkbQ!FBV;FJD`YQZGh{bpJ7hm(LuALG-xAp~=r=`nMYg3b z_C+>Ec1E^F_C_{Gb`SdPk^O_d0i=VVZvp8c=$k;gK-xh1KpH_hL0Un2L7G9jLE1t3 x3HpYRj)J}=q$i{)q${K?q%Wi~q%)*7q&K8F9QJp&g6a~vK! zjkuTzxg}tO5x?q(i2oR5Z2dJZw#_WDw)ejgJNg2xokQIsq2sHytE)vMR=={6TD#=# ztUfEbv`MB!Ua|J16wB1$dMj;Rl1!WJG}8Un%Ji{1W8aj&%oxZsGDnsw*R?RQ|G|vP zYFsR`FTGa>O4iGq%0ZQzv`D%$yHsB27nvX4qz;M^S+M-NSuoiv56xUK3!it&!|#gB zBlmj5(Z`8qQM)CIudXpY<+Y-uIYAvucZ=gip{g`2PMk>aRo*2zvTXH~Dw~d#C+CJ$ z`Dlnd_2I6ncsMI7hhLbdJ11n-?K@_5%`<7XwVO4C^q8&s%h<*?S9cm3BDl&A0D9O+gq9#L6 zh@uQlA*w=jg(wTr7NRahUx>mEwZ;&Y9crB+N<*}Us14DZp*TcyhUyUAA<9Fvho}$H zACdqh14s%EbquGom^h^TN^bX3IVh^WBdO?$QU literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Barbados b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Barbados new file mode 100644 index 0000000000000000000000000000000000000000..9b90e306a68c3285f6cd2de26d02cf8e7106ae8e GIT binary patch literal 314 zcmWHE%1kq2zzev5vMfL>u(DF+>5kUqr+f^b9`H@+xxhc2;ekL&-UY$3M-PNT0xk&0 z|4$GxunS;hW`e^1|4&FWFn~#x|NpOEVC4A!|M&q09v|Nj1}7kPbOGYv5QY#ET=5?W wKrR8%AlHE04ssEg2D%DFgIorpL9PSQAQysYkSjqn$fY2fJlApooovDd0N7|!s{jB1 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Belem b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Belem new file mode 100644 index 0000000000000000000000000000000000000000..60b5924dc12f14c274073b1fe4ccc590b742da5a GIT binary patch literal 576 zcmb8sy-UMD0EY2P{6M1UW9#H1 z>ZBAzC~b^5>LU0NQsulSe?Y{9<2Qs5-Y3CYWwR^_uabS*WzWFDX&Baq7L(e~g08+(QHiRoZ&cV|pf%{;eM0si=wmYh5+QxK6?C8q?Sl!kFj8={Dy6 zPV_A;2VzQ43CAdLT`ZE=U`s57G$f slxtfdy>e|cq#M$Xzehi$A<_|PiS$I8V%5G|P}On&=<3bcy7RvG3)4mZiU0rr literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Belize b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Belize new file mode 100644 index 0000000000000000000000000000000000000000..e6f5dfa6a8d82523e8cb12f17cf73560bc09a383 GIT binary patch literal 1614 zcmdVaZD`F=0LSrr_h2?!T3U;wk(kh$3@M{aNz}!SLz!brc)>;PPakALTT^3JQh^uL|+x!wA|`+cu(&E}0+u792( z<`)i6o;iFUbt1R5vbcDTKEH68Dk&VJOQ&rW7jhk4mh2T5=SK9!o-E;?_*?p)j1-p> zw7gv2FRn!I$-t=;bv0Bb%XjsuYyJbWVr7e}Jh(|-&#qQg`9=Ch>RENuyHVfl-=}V6 zF4DI;&xq;~lXZ3dUJ>jau5TBw6*a9HvbHcs+zAeob?eea{ppYLZceOd*z;80n>1G4 z7uV&3p>EYU>x68KcBxQ$g${)pRg?ReZu0xpqsR{Z_~--CJa3#1kMGM5KP>RJWPFz` zt&5dP?2sxrMYVR<$+k1esy*DMJNERd7ge?Tr3kCeLdHS{c zhIo^;K);Ec6w%S^Wwc?pc>BX6yGvG!ckL78`$Id`hnfWWamy;zbGBQ4T0C3z7RBq& zlSivB8>0Ga;xEEHN7CsSWP!bJ66*V z(h$-S(h|}W(iGAa(iYMe(iqYi(i+km(wxvpkBD8HaeIt!q|Fh1M%%4DZ(jQ$rf9HsJyQxN&4H literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Boa_Vista b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Boa_Vista new file mode 100644 index 0000000000000000000000000000000000000000..978c33100fb2d9b14c1faa581890c16c8747b42b GIT binary patch literal 632 zcmb8syGjE=7(n6Ocp=1FV`CAGu~isMz(hnwZB-B!1Rp>VtZcLk+NKml(84lWO}P<^ z>4Kf$r3kq-7D7M+8bhLtbM^rY?l7E%fnEM@ysh2sS?A9uZclsc9z4Cy)cldncmHQy zXd&X($$7czeZKY z7!z{4tdKE&;TT6M1&S-F&77D?~8S)|Ns9#BQp~-^Z)<5CNMC7NtXZr zj~`&<`2T!iQ4YCwyHv`CG5Dl^%MArl5 ONOAy|4bT~Ord$Be(?9Y6 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Boise b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Boise new file mode 100644 index 0000000000000000000000000000000000000000..f8d54e27479149d35f6ddff12f709096f08bfac3 GIT binary patch literal 2394 zcmd_qeN5F=9LMnkf>&-loJtGg>|+#tLH8etT8ceMf^x@jSvf@1u| zSvs;zy7Z*2nToF2*bvunZDn(~HLZm`*DM=7Y_fRxb>8RS{_4NBzIVUh>$m&==k41N z*pwswaW3-@5BHLJ_)b>l)%*79&}#$nI`l$%sPC0)`tYjql#jcj^~j<>TSgiZ#9!l2 z%88$9#pJ~rIrUM2m_C&+ox{mO>`#(mozo)xsVO;QYody1n5!czC)Lct3GK=nRj&R8 zI!X?ys3XUvd+c>}-B*1&`qF6;Gt{nQKj;&2?}Vg$xm{e}^_;w6SChCg&?slGFA?#j ztK^*gG;vefZ8BkDv6>s@mWko1D)INlI_aAzl{_*_&pY$8nt%L?UeI?=r3B~6o1Z=8h5LrB`@mYqK&Hfk6~HjX%!_G z4$0D(dQp0!ORl+ED9T=aOP7CEr@XD5`u_J%LRI z$v9n|dsbC{pCN1Ke=BN-W99nkVX@)OG5O%=AyL;cA|D#;67`KI<;LDE;$iQ3-O$;o z9`W?+NBsfS7_(0|m6WNbt3mBg^(g6dmhKU;HFrvGYd$Hq$6uB^Dtg3@=?NXo>sP_iFZIrZeQM|6X}xPasGjca)6ZP2 zRjqC9diSXU)mGo6_v}wr;bG<%IU^!+=6~wvID6xSaGZlWEW&ZRm6+u??}oyn?OXD{ zm~Fok%Dp~OS!ABIKH;q~Po;VIHve&9_6@#&F*(OveMI6AGCgE|$OMrYB2z@>h)mLI zW{FG_nI|$)WTt4R$_I1h%w&Pta!ePQFEU|d#>kYBIa|%7ky%^Kw2^ru6GvvwF?D3_ z9Fs?8&oO;u{u~KFGQg1nBnKQxK(c_O0m*~aBm&67P9+EyJe@Ft6 z3?eB+a)=}m$)eSy5y_*~BofJ_)ua;1B}X!mY;vR%$tOobk&JSr6v-))R3xiNT9Le3 zO=6MET1{$^+*(a?k?bPrMe@s$U?jsFDMoV4kz^#x9BD@KY&D5SGHo@fMsjU6$wsn` oq#MaMl5iyBNXqelmUFkM{Bl$I4DZs+oXo5YZ+3QOc4n6QZ`ww0CjbBd literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Buenos_Aires b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Buenos_Aires new file mode 100644 index 0000000000000000000000000000000000000000..260f86a9180677d86fc3280b06f01d6a6cd91c94 GIT binary patch literal 1076 zcmc)IKWLLd9Eb5YHqjUg1{4$#sn}8y5sox5;-B(LhN`qn4Je%yL?{S~gB3)hi<1zL zAP6mu?cyMK4%O0Ddm3wOhZ0Cd1c!j)rl`aatM>doH#vz;=H=ecL6#T3Pj+DNRKok? zuUr0IEoZ|Od5zu3s|OeR{fC?9_2kyPKe=>PO>MknrY6Sqbo0JHbMuvY^!lB7d?BJ| zr#Ja#Ag`Z{jQCIYmQ?9-#XQ^6&~wLw{@hAjl@Fv%xpq&zxLWWR`flrmkJrp%pH++c zgQ><+dMR_#)c1!~eY9b|hEA(SBI-BZkLu?7jA@pu>RWxtU#{-b-%Ba;W9EqZdAHwR z8BQsCJ?XC*Kdi&;XNubk6S_TGD0Za3=#Ee4i=Ernsm{u=V$A!jVtP+8UaP7dw~n@@ z8_)Ib*|_c*TC02B+Q6!ozkEW$-<}qC4_P~(^gL@z6)$LQ*?3`V zUseLG*1oL;qTIdK-oC7tk+V}J<#fqOc-engMn2M>8@|(vEQG9tEQPG)l*N$MoU$CU z9s#^KxUfIg>*r9A|hfIcss2ibvH}IZwtqG z2K_Js8s8bWb$#dB3;CH)qPjf`+!yh5JUPMw``>>w}U} z`J$Runk&Eat|{_4+VLB<8;%`@U1yKZtl+a-7Syve&4mPG@fnEb14+Sj|!_)pjB zf{us@99W_YBb};f$27e-xJ50g9o5C&m((*w-|3}kd8#Dqp_JSmlhQ|DkCdhUSW|ZK z7xnD-XJuKx$2@oTh%Dd#vw8mTURlw4*{tk5tY4_^H>;ZW=<{#cb~C z(y#kYnKvR)-8|`_X$e;8misXi@%nURsNO`=rs(MLGPCvWuXu`S*AOhTFl-<**YaDIVCmavGM(-J)WL6&X11c3;CZDNhFSaoRsRG>50S< zBNG#eulkdedz0brGq_6*cbW6|dp_w41SGUBETI~E*4R^C&Lb?VIQB(_Jt9f&huq_z zYxqC-kg&rEh!+qy9IYP^Mk!8#L@Ny(iBJA6-ZkceStKF(HTf<7`=fs zhtVBKdm#ORGziimNQ)e8k04EQv|WO<$4$?bF^B~=W|L693Y%7=AOy-9c`-}X6{7_+`ztA7> F`~~dE4qX5M literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Campo_Grande b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Campo_Grande new file mode 100644 index 0000000000000000000000000000000000000000..81206247d9efa7d3dd10dd9e88c669718d86cc50 GIT binary patch literal 1444 zcmcK3%}bO)0LSsitwc60f*_oJ@W*tx_CUrgYpBo4&5qn@>rVs^7}Ah7TgW z^QqiY{8EVKR=G8&(bT;m&GebJ3>z3FyJ}q-^=Bn*| zF*@(;I<@27Bbi_ETkUL*mNI=p6|_dm!ZiybP&p_Av*V(u{D>}^2&C!vb#qN=Iy{GxHD(ktR%MZ7xiu+Z1Z)vC4*K%G~CX}fC#}3K^PKpW!vSsi~v8eLJ z%BsGNqQ(=JHP5}`&}2x~-k1_~V`p^ziT9$(bzM)yqJ19M?eBLS*Bu^=Sn9gH+KDPF z4?1Zg(_Ft3{EsTkLtV;1>adzZkV=qJkXo#!7^E7jDF>+sDF~?uDG8|wDGI3yDGRB~ zY6?RtvzpS7+K}RCp6ZbDkou4UkqVI#ks7V0NTf=uDHEyFY6?XvwVG0qT9IOrYLRl0 zdXa*Wijk6$nvtTBs;#DMq;9Jz9H|^B9jP5D9;qHFAE_T%0I~vP3CJ3dMIfuNnq?sC zu$qM+E3ulTAZtMugRBNw4zeC(LCA`bB_V4<7KN+|Sr)P`t63PbGOJk{vNo$(9I`rO bdC2;Z1!9wFWzjYm;rYi3y?JJf`F`&oyD`xr literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Cancun b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Cancun new file mode 100644 index 0000000000000000000000000000000000000000..f907f0a5ba77b9ec845c450cd535ee589b46c5ad GIT binary patch literal 782 zcmcJM%PWLY07vhbk!MjJ8=}s}r(2JnZ!3P02`EtrK}$5K&)|6TO)fy^pU>-%&)wE(=uu zT7?+ceNlt+Ibvw(S`Ckv%aPfn8tu%IR%~5am-oWsP2>1Hza6jEd)q>2y|W>FTA!sn znOY|gL@uu46Q%-(q=frF5V#SApRf@As!(vT^gSdrx33Uw=Rue zhGU3lh--*%h;xW{hgy(v8s$(vQ&) U(h<@U(i76u)Bq$V%jwvBoAJiOJ$h0>xa!J+`v3p`GcqwVF*E=Ff6#$} z0Z6(qu>AjjUpu=2qD2vpz;4R+oc>pG{|lc4YD8T b6b6tRKs3l5Ai5qXN2*)6Y=ADZGvNXNDu777 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Catamarca b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Catamarca new file mode 100644 index 0000000000000000000000000000000000000000..0ae222a2f8bb2fb1b7abe17d08e076674c51541d GIT binary patch literal 1076 zcmc)IJ!n%=9ES1RG|?Cf78Dc_sn}9d6%J`*#E)_$LqW_^14<_c5rl%`U*xjnBZm(HoF&6n-e#F&|G+}AU=UaCj0-rC0(V`g@G zi?#!K^JHX1&mAbK(v^yRx~*>JPlomUYL_Y>PT6v8Ts^;5&?GDu`z8M<*NF+GNiv%_nPmer2R2-O#QsquUChY z%H8PEYsZe5X#3gX&ccLgZ!Hu%QlCx7#|y>I9UD|<L>5I>MV3X@MHWU@_R7-8+Fn^4Sshv4E9)Z#c%=fQ1f&L}2(MIul!4UY zl|qn8yiy8M3sMYH4N?wL5Bh?5k%}bvfRd1!kfM;Pkg~i|7gCs4Dnm;1N^MASNOeeg dNPS3wUa1f%(JM7#PJZqG6d5}xZT5D@egU`L>mmRE literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Cayenne b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Cayenne new file mode 100644 index 0000000000000000000000000000000000000000..e5bc06fdbe5a3062f90274a6b5cc5c56e2d74d5f GIT binary patch literal 198 zcmWHE%1kq2zzdjxvLMVe@r(9^--k^P)c^ngpOJ~_|NnCz7#RNlKYoCL<^TVy7Z^Bv pd_x#?4NQR8m?4A&gMsG#2N@2cK^B0VQx9Ylw1mqBXqBBY7XW&PH?RNz literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Cayman b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Cayman new file mode 100644 index 0000000000000000000000000000000000000000..9964b9a33452f4b636f43703b7cdec4891cbda5f GIT binary patch literal 182 zcmWHE%1kq2zzdjwvdlot(*Pv8za+k3WcvSqYXJiTkd$Cx`Tu|C1_llv-w+08Aa)H7 ZVF)3?%>O`;*{&u4qKPq^3uu8U7XX0%EG7T| literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Chicago b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Chicago new file mode 100644 index 0000000000000000000000000000000000000000..a5b1617c7f70bfc77b7d504aaa3f23603082c3cb GIT binary patch literal 3576 zcmeI!TTs4l=1wj+F14U?9S&?zpP%=nM8G=GAw+LbysUe+MCSs)FY9gtova(V; zpca}P2#i$7LQ*ouYDzJJtQ}CHS>!6rNNMlZ^KY7Irkk2>x@b9@A2N93#ru4&8F@F3 zlD|BE`x8FA@9c-~gSGuqwlPAled8CkZuua+{;31%x%Ud>`FnmgWfH9bPJLEhaz9~S?p`LZ)Gam@O*!&vS(d4+o+wqtmzvGb%+{~vW~%C? zm+RM)$EhtdN9e6#!_>9}KV8$$qiTm9)U};$YP+AWY~Q_8z4=wAyjAHobq$TOV@18G zpV2IDS0$*OB@fE3^b*rB_cnPa`bM)m?E(Gn;44jIr`kSUj-Likex8~z%A4~JuADB<#wn>Xrn%1B-(%SZ@`P8#TAE;kwK69_qpTGEs za@Q5PTgqHfwjOA6D$tKQ7y#y7SBR(b=Wyr}X9e*!Vp4bM$=O zbK$+_m%*v}ctEZ>-jgdQ4yBmhmK6E5G2D1+!o|BO(8%gQ@hLrG`Yb*oeHRQ=zBwmp zzbW6VeiOR1f6Pb9|DiD5f5>a9f5r1Mz&x%_YFnuXwpN+I`bBzB?PF%}i;u~WH3jD6 z`wQfhq6~9tUWS~O6>ox4;^p*9Ld+Q>LnQdzvFgl#UJ2=QrV9BnSPyMKp@!`}uFrb= za}~PzGd+C$4s~|nU^(aR_3GSdKgfui-ZJOKHOcv@Yt02gTO{nFyG@v9uO2yIjv48$ z))yU4GU0Vk=!m8pRAkv=9aTL^MHgr3n3Wf(*xW)HwJ<=9PR^8zuRW~d!p6y%QSYm< z{=+1G=phr|>5)rL>@nkZx5=dkUNH%ky*hFG!{)LTZaw~KWhUg;>&r_XQdguurzg(M zSCgVkbkd}2R8sdgNsheLBsZ;*l)!Y8QoTe{yJF2%&#cl{H&0e+ON;d6tuZQnX11R4 zEZ1{#v(?O6lRl~)m= zZ|eL~-TY*V-14E<+*%kew^g>A{ER?RD|VR$aYy9#{0(Md&|WD>FEs_8E?pR3t_s~B z>N|p$t2^p8>!P0d>dvy2dPz&FT3WnF->#if2vN%T^CkeSH4LpT2+k9bdmc{pIic zuJCL{OUB9Oq^stQ(cl|KNF|h&lH#4 zHv4@3!1WJy(QDtVzMgf+J|Y{5>?E?4$X+6wiR>n_oydM78;b0xquo+uPaW;1BD;!g zE3&W1#v(h5Y%Q|4$mSxui)=5lzsLq7JB(~Gvd4~glaXC^wA+mAGqTahP9s~5>@~94 z$ZjLsjqEqF;mD37TaN6xquq35*B$M)Bm0hQyrbQDWb2W=M>ZeXePsKQ{YM($Xgh$k z0OW@JxG6$1|c0nT7>k-(KZR`64EB5Pv|s?Z|D@ywu(oukY@4d7Sb-HUr57{ zjyc+vAw6@nP2$t zJ|c}oI*GIr=_S%k9^FLR$)lf0LwR%*X(^AMI@+cpU3Ii=Mf!>~7U?X~TBNr~bCK>M z?d8#5q`^EojI@|XkC7(x=(3}2Gmkzajpos5q}52Tk!B;^M%s<^8)-Pwairx)&mC>k zd34>;ww*`c9c|-zbRKCv(tD)&NcWNUBmGBi0OSrpZUN*TaI`l8au+z-+knS?;An3I z9(MwAEAY4%keh+W-GJNEy(SH n+%L!tga6+#|L%?%V9%T}_S}g`8yz(&DkdT=Ha03YDrUfMOLBGg literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Chihuahua b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Chihuahua new file mode 100644 index 0000000000000000000000000000000000000000..8ed5f93b02001a63ce43dd221ff48cc5faa6752e GIT binary patch literal 1484 zcmd6mduYvJ9EZP$_EU!;az1*wtoj*t|t68r~^U zb1M;+w$v_eQ|ZnE?h16`Am|A#+!vbk0rS)%q+TbN>Yw|FpJyw%95&wCUt+iPRr>s>6@FhC;F&a z>M7RCBI-;=WU9{i)}}I@vvlUuTD9WMD7~^TUu8X*Dc%!_D*K94avCP9RjqGj^~QLU zTYgvaQYRT-)@8|`@!b?ewaOZKVG1W+)P=8ZnYBX)wg2`RQ#4Sn*Il}))^}&?4F^uE z;$v)U`?XRNb;7y>m*3s*i4v`X7f>Lxf)%o>!^H zkIAy@`f9cN(RA5!uEI2RiZt)bF?$cc7RLzANc%V)|Mpnc$yO1|I%ULZSsiC(tYuy6 za)k4CsNdhSygu>f`6Qj|vETOf{e>l#Jxqbv0x z#K_FT`v3nb83u;`|95U+WcmMp^#TSCFq;QV3V=uk5g*?W24@!_4hG_IAPxv&a0RkK vfDuZDkl?KUKv49qB?Ux-oCl&oP6W{)XM$*uQ$aMyxnP?5PUZso!ITRCV)1m0 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Cordoba b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Cordoba new file mode 100644 index 0000000000000000000000000000000000000000..da4c23a545b3603bcdd4555ba8feba117802e7b4 GIT binary patch literal 1076 zcmc)IKWLLd9Eb5YZK5$03@9if60xNuA{=RB#6RVg4plKr4Je%yL?{S~gB3)hi<1zL zAP6mu?W%YV)zU_L8f&ye38W%|LqKs;L}G|ld;Xqt7oE(@y`O_DFMOZu(D13G_s3tK z{JTod`YZC9xRF;6E)Mz+H@(!;Tk`(&(pfdL;gXq|n$)wc`+n)>YxU^Od-M20M9|wz;Y2j|ctvm4vG7Pn$~po_cY$;4fru>xEC(%woo>Mg7s# z;win*Z?FJzYy~kH1kXl+@2R8ET)|xJUt*lefon0jl69aG|LYq zXdb$GfsvUB3jhD#Xw1L>CRzUf-?@R2^Z)E8 y*{PPd-r^$>X|B*y<=C!NZ^$miNwj#gl~GZ=eP(*eRAwUM2v@@$%#;r z_;EL0|6I~2ruA7lvphr1R^`jtzK>$gJE7;gVpTMRl7SJ^dLIw!VC_yb3!e|A9RCTGgrfeR{cdPoPlZ;7qrQ!@WXzS`Cw zuM5tsRomY_l7*GORZ&~4EM7e?f>nbuI5RFvDvs!qiKr@D*&)kbJ`p?SlrFz>P3#=G zsdu$JR=a!8>x#pzs`7rd-c#Nw_O_mrRmo*)-?0O7zmu*)!8{rIQYxx_39`C>gQ)dH zWo?&N9Gncxy6X{9KXzIlI`LjKyRPerS)kA3y6+kt$90DXV-~w^pLXJQSA?8Qkz=mk z3H?V4=9w-%AWc|J7f2gOA4nrs(+Sdw)%1cigLH$mgY<(mgmi?og!F_oWi?$PZCOoU zNMlH6lum0%Z%A`UcSw6ke@KH?(;?EL)%1uoX*FFUZCXvANTW!nNUKP%NV7<{NV`bC zNW)0SNXu5!Gt#uxbd9u)^o=x*bdI!+^o}%-bdR);^p9-7YIcBZ!D{w^Y{F`GfoucW z2eJ`lC&*Tiy&#)Gc7tpO*$=WIWJk!BtY%NhrmSXH$hNFzU&zLgogrI8_J+--jRjg< QjOQPl^A?!p75cq@02#u{;Q#;t literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Curacao b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Curacao new file mode 100644 index 0000000000000000000000000000000000000000..f7ab6efcc0f5bfd5c4172cbe32c03a8e08b0099c GIT binary patch literal 186 zcmWHE%1kq2zzdjwvdlotH(5?k`P+;)9*j)?|L>1wVEF(4zzznM|NoC4VBqrc4PnqV eFfle@a10J%2qD4L|3CmT8AKCjIv3Ci6D|O%z%CO2 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Danmarkshavn b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Danmarkshavn new file mode 100644 index 0000000000000000000000000000000000000000..9549adcb657569ea304592a4070ceecb4550a4db GIT binary patch literal 698 zcmci9JxD@P7=Yn(Q!B*bfTdRUrw{wYAPo(8`Us^A=q^*3WMtIuIsLqRoy+m zpc8pdC&wpsPkK!E##6d46w|4|grwd_rT?*41}YI5yljx6(+^1>JWFQ#PKGzGWMr)@ z?&6WSPcyFLuk-!-1dMqtDP>IMM)|+b>Vwm045$4Ur9%0Fr!sEN?yQ=!ccmPM51if~ zsu;T{!=esS2&sgWLTc5t#gJ-9Iiwy^5UGfiL~0^Mk*Y{pq%Kkzsf?6HY9qyK+UiJo eq&_kMWD3Y6kZB+jL8gLCrsls)Cuqmz2EPDo&71K6 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Dawson b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Dawson new file mode 100644 index 0000000000000000000000000000000000000000..343b63227d2185863cd720bf449de000bbc794d0 GIT binary patch literal 1614 zcmdthNk~;u0Eh9XIix5YNKNf&$0>($$Q;uqQ$%wrpQffwNTC!-gKbI_B&aA4Nx7)( zC~cyRVn$#I1qI=v(rA$(5rh#*WkFWr?R*znwF+8wALss#cje;$x$2tsr8@q2e9RXP zPlGw!W7^HD_s-bBwUH>TpZX2-^^doYosJtAkNVm&z9&t7OKw$jas9$O<%3$%bXW$| zR*AqOmki3z6ieeXWN>7q3h@b+q3-D_bT&;dd$UwI$Afg({qHJ#a857pn^dxOrHtsf zry{HUWmNM^5uN@~#uVQbD*~U%*o0mYyD+2UecMI+)DxZXey>Dr84wczIr^VVw^D<}h zvB(_=*6T)YiuGMT^oGml#KuFf^rp@mDzAK0Z*DxR@{_eL$UmqGzD&r%#51CBVptaW z9}q=DJ+gSFOl-L_q)T2jtI`t}b=mC_RbGEwS6oU`TXSpmwpO7kojKZ7HLG0nVY)i~ zxvGAS}lMu&j<2hxuaee)d~f)>Y*ez}*pI-@|x2B1%eKj@o>4D$Ut$P6dCP z4;AJ^g|XDg<7U5qUtE8&G|N0EPo2MoEDl*6vOHvc$O4fS+L|RIYeW{wKf)@JWg_cD z7K*GCSt_ztWUrM^=t39a+1rSv<0OTeEy* z{YU{w1xN`<4M-746-XIK9Y`TaB}geqEl4p)HMXW4q#mRoq#~pwq$Z>&q$;E=q%Nc| zq%x#5q&8bq98#UFDG#a7))a_Th?I!bh!lxbiIj=di4=-dij<1fYHNx`sH7Dumjbn)ly@Uf1E)E1<+6Y}RjA#>RkYqK{Wudrez*P!CtxCusH+fnF zZM1`J3L=RJ1SxD2L2a6-oG#OJvti0ovoy2$dY_MWt=#nu=ll+{{XfaWU8xP`pKpc! z!{KYv!+TAyUPGg|{iU&ld(gkur`OGOr#oxp$^IGp)E4B~=EruzJd{l0md)g@%k$zR z|6<(9%j`}6>gqL@y>r38?my>pL&yD_u5S1C}pOU4CBlh?G7AcN4+wjVIF&FD?aJEunCn{`7 zPo0Z**80+5+QoucNnEdG|4PGfpv9Ol9CSfk-@T?RdRIobaGR=Ktx40iL(e`v2lTWh zO{>27g1>ii8LNc)wQoDN1z87K2w4ePDpJ=%7DHA;mP6J<7L3#tktLBekwuYJk!6u} zk%f_!k)@Hfk;ReKk>!!~kpd#M0;GgUtpO{*jWAtB*Xe_ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Denver b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Denver new file mode 100644 index 0000000000000000000000000000000000000000..5fbe26b1d93d1acb2561c390c1e097d07f1a262e GIT binary patch literal 2444 zcmdtjeN5F=9LMnkqQH%ZQ;8vb6-0*B?gOursm&?$b8b?d7UesOi|Njd(VTTGm*mXq%nh`_OY8GIv2h@FWtq%9yq zpPH0YHYBL9x|w=v#e|wxIIhF9MpXC}}?Nyq3Ob5vJb$tvNO`8x57 zNR>1kp=X`^LCrpNN#EFeTFvp#k~i%*sOGK=%6aQP6gTI7E^k@(wwNFHo=i^FA~|qD zr#Lo>l#!D<^^!~6I=EM-oo!U<-OuTaBb6$%*{ic&TBNeQtuklR47IRitz1+&rgD?- zlegu3q85jz%DluYBJbNMnLmDB6rB1=-u~%;Skmv%cMR+nOFMqlckbFQ3L8GsceU

gzP=p8ch855>q;fg!QFZ&W@w zvR~A+4$FrI+eK~tQMsmjy?EGpM%T5qsYlWe>qoslRUh4{JtbwzbJ?%G$?3{_+O2)z zvC4O#K(G7eXSKeoT0V9rMm+A%mrooV6%AF1vaw@WY{;FI8yk*_O>r0G=JGDFIWVsM zd54vMqPHC@P|dX-y?tkr3Jv-5Z%WwTuYY~@ z-y00>?i3;ze5)rU%)Dz6Vc(~8rXEg;xDrhw&L~3X?MMSE|QAVVWNFk9*BBexXi4+s5CQ?qMo>o&(q@q?+QlzF< zQ&gm?9A!o7%28OPvK*yFYRgevq`F9Xk@_M9Mk;JIB}Qs&HAP0MY&B&@>WmZ`sWeBa zky>*U8>u!&xsiHv6db9z)s!5mxz!XMsk+sa9jQA~c%<@3>5<=_tm4^cV&BhG ze+*UWKQByI$<q#B=s2d`FJ$YrJ$_lvkjdRn~P3}~ko#z%)CXDK-iK$}hFD^Oln^BQ-=|?&J z%teuV>|=TJ!DHf{qvW&*>Qpo>MckUeyJKn^nR1`_k=dQ10PZ zWZ@5U)U1IWvS=_QihCo{b7HnA>0BsF_hyT-a9Edb`dw7`1N!!*Ukh)+EIqq?K+H)= z*Ok-0RFxw?>$$OaRn_@Rdfr#P%GdvsyyKlG)SY`ik$1hYURAdpm-D-}iM#9f$(p8h zqP8R|>uPI6-B_RY7q3dJLRI!szq>Xi(LFxo~U0PluLS& z#J#=}x%80{u`DN3h8ix2P;5*t_Z|_;zniF6c$Zq;byD9y z(5lun?bmC27b_8bQ?A?5BGwo8$Opnf(UjgUoBbuCd9+c63o=FcBcF^UkBP|ZxpL#k zr=q2&O1ECTsveBy=!g0TRa?WjmU~XBhrLQ~YTK_iXPwns>O0hy@hdV~*(0LEXJmVJ zyJ#OcBs+d<6p!|H%g2U%VryquKK^#D=v)(!+n#qsLgF<^iP!!|KJobR8IBW=AAQM5 zipNjA;Y^6fKRBI`X5S3^PF@rYIW@~dP966?bC;M~8)67f!ryP`UyLSh4#PplgA526 zk<|o&EM#2B!1ybS3>li$j13taGCHdn9x^^;fXE1uAtGZ$28oOk874AL zWT41Mk)a}EMFxwE78$P9j29U&GGb)N$e58qBcn!!jf@)^I5Ki%=*ZZS!CTGfk>Oj- z_>ll05kNwK!~h8b5(Oj-NF0zrAdx^qfy4p{1`-V<999z#Bp^sckdPoTL4txr1qllh z7bGx9WRTDxu|a}kHPJ!BV>R(X0%SE2LPCVZ2niArB_vEpoRB~vkwQX+#0m+P)kF&k zm(|1z37FMH3<(($GbCt8)R3?taYF)!L=FiZ5<4V#Nc52KSxx+q09s81kq}x<43Qur zQAEOs#1RQ35=kVKNGy?HBGE*`X*Kag0%|o8MM7#dF-3xkL=_1u5?3U!NM!MU8(NpC Xu-DYLC|Kbs_mma|%gQ`uo>JFeUM!I( literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Dominica b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Dominica new file mode 100644 index 0000000000000000000000000000000000000000..697cf5bcf7f151ffc1c1fc4247e4e9c7e3ff01a3 GIT binary patch literal 148 zcmWHE%1kq2zzZ0GvP?kCG1=UB4deg+$3hqw{{KIIfPuxwH-y14ID{dD1VjD<0ZxOs JfTo#n0RWR(9N_=} literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Edmonton b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Edmonton new file mode 100644 index 0000000000000000000000000000000000000000..cd78a6f8be1dd55ac5afd25bbae39bd5706e42d1 GIT binary patch literal 2332 zcmdtiT};(=9LMn=gaRiXew7#s8fi%oAPgR%o+LOR8etU34pxx5GcCklf+M=| zTN$&N1S(-`g{f;cHqabyJ?PwVxvWIX%4XTWs3lG<2AKs_EIC}Cz_u&C~b1>BO?08vv{9DcLmwuEz?Nim>#!sX#`mzAI<*SSoL|uMSUjWYZX#EL#C8oGgI@&B{Y51ge9Dl zaDBwM)Ude5cAM)j^h(6pVHJ6#O`<;RRnc$vX#IMdx}kH6zHwu{y2)For>!VbF~tw+ z>A6Yj=A=7x?3_X~BiyBD1}B=Czs-}lZ^KQzKTKvF{mIOJ|FYcDd%`66X6ajB7%+1x z0(x%aXX>`>Z}ja;-c$2pj_Jf?QHc}hCCRl`C5;}Hf7(ku*3);V#1s+>y^I(Pi6$~*pxzWb{| zwP?Rf?it*r7H|7m?%lar`1^=1N^Ma^r~7qr zWQ{65*r}IX$yX(B^vTjQ)yCb@ArF7B*et8|N@-Vud1O(El=*^9d3>sPD!wzGYtd4f zecV)jpQ5W~UsP2iQF_J1h+4UKOg}o>ud3Vq`mv!-Ra19Juj*c-9(SLT+KvwMMCt)~ zvcYTWBDYI@QHiO);**BNRMT*xO1z=b#`|ubH2(0bS<|&#KXocfJ?+cY&kT&Irph?o zyv?tk&HhWTZ91gZ#hlmcmvyQ26XW8`IbeLF=VU|dcC%q_n6ba=twOVpRcqEDKo|vM^+2j&^Ct+K|N|t3#HDtPfcrvO-6@L}ZP~ zA|352k!2$5&fT9L&ft3{UUXxED@7+EpLl94rYEE-ug$Fh-ib1WQLImgnG zwR0>USv|6RWc`k|07wOp5+F4|ihxuBDFadmq!36YI7)%kf}Bc$b&&EP^>MTXLMp^jBBVwfMMA2?Q6{8L9ECzE zg_H`Z6;dpuT8_3{NWC0w!H|kM+L9qP<0u+ZHKc4v-H^f|l|xF0)D9^gQawjoKBRt* zwtz?l9c>Ab8gdj7sUk-ikveh|5~(CdDUn(t#YC!!loP3^qb(>>QAb-+q^6Fxs7O_j zvLbcmC@fN0j?yBvwrbMk?%RON`Xm(H0r0GE!!w&Pbt=N+YGl|7WdT ZHsT9y%v0Q1X_;y1DejDnw2ZWL*WZc*ZxH|h literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Eirunepe b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Eirunepe new file mode 100644 index 0000000000000000000000000000000000000000..39d6daeb9b6dd3b225b0ddacceb6984e8204ac7d GIT binary patch literal 656 zcmb8sy-Ncz7=ZEgY(Y-ZMFbJQI$Q9oAR>~ngJLQ-iGx$YKR^(dtAil8IEmuoY9}XY z9VA=P>0C=&E4Wz%@vF3!nCEaV^g?(7fjjQ^dYe0$InnWn+uNAk{inI3Y<@5!^6f2M zcvtGSdLm1U52{ojR^^d)P%iAsN^4eCFPieHa-(YAy8JvF4ZdRg@>^%s&%lyyq*JO< ze3ni3Eofd1=~g|ievi-f*nLio?|tZr%XBa~|Ei}B4pqGGMNjKTmB`d&YTH*EepLI$ z7$?$k^*D|(cUd8fDe6enn8LN_ zwW0WgwMG;tiWS9+Vn%VJ*irl_h7`xJ){^2G)|ygWDYkZY0$++T#hGGF@urwl+$r`H Yf65G~Z{OW<3K6HPIk?Mq8Y@Zn4_D+KfdBvi literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/El_Salvador b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/El_Salvador new file mode 100644 index 0000000000000000000000000000000000000000..e2f22304aad56062cfb66d23f3a8c296689286ed GIT binary patch literal 224 zcmWHE%1kq2zzbM`vdlotv-s*V1%+969w^4l4p6Gv_dwaEHh_r{2><_Ilfc06|NqVn zj4c2EuU^2w;o}>^;Oqj#!66JGBv|nu2td{Vtz!UL1)@RLfoPDGAeu;Pxqx9Fak&n6DH46gd6Zt(c~ zb>BpnIz#PmPhD)@EZ^sCl}lyGaycPGM!orJZ1EN~9-pMfr_}UT z)~!{`6S8#V%3`^GUZjo+&XlO>3=@5Exx@@EGqE54E-QLw%nh$z5Z$m^-+1sNSy>XU zSJiy0;xd2IH|2k*ZjSg;$0v5G_}NL55Z0m+hCern6T8*wz8;fwu33^hj~dUZU9zV6 zag%a%qoh_H(P{N@lJ4E7Gm7U*W_*dxN*kB8q1ie+W{%1pi_+`<98>GhUe!4lK2;mu ziZr);@VdIS?GJO?i-*8W6WK-d*tp#hm1F_P`op*=)90r z$s0PT^Dixt%`crY1z*>Quc^b_(_0{gJNKKSV;Nhr-n$dtfe5^u0@fPo>BD?lX_p_NwqI9&opHBOT+LLb0G4B9OxS`jWezCL}#~oa;Q?8n%m7& zr#DG+S-pAsg+vJo4hp^|IAo5!{yV=w;7Ebv1OhLM6A}otwK&)E9<;!{m3uEO@cA8I zvEM1;c{jL0C7 zQ6j@c#)%9R8L6usDl%4AJ6L42$Z(PIA_L~j88I?sWX#B*kx?VVM#hZ{92q$>bY$$v z;E~ZI!$-!C1i;ls00{vS10)DY6p%0=aX0NT85NA)!KI zg#-(U77{KbUP!=PZN!j}x!RZ^K|`X3gbj%s5;!DsNa&E*A;CkUhlJ17#t#XgtBoKM zLRT9@B#1~9kuV~0L;{IK5(y;|OC*>`G?8#3@k9dZY9oq-)YZlm3974&DiT&Cu1H{! z$ReRdVv7V9i7paeB)&+1U2TMs5WCtKBSChxQAWay#2E=R5@{sVNUZUHAM7w&^K4u5 UBwxBG&6ASkOHK8pdQ!sv0^LWd&Hw-a literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Fort_Nelson b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Fort_Nelson new file mode 100644 index 0000000000000000000000000000000000000000..5a0b7f1ca032be1adf8ba91f863e727c5ec6a026 GIT binary patch literal 2240 zcmdtiUrg0y9LMnk^7jb&%{)qk^`s_(DTW{@nyEO#KtK)_ty#9B;c99Y*4Bs?t>_;Q zI{UMVzS&KzCNgHTkqmEKt*i;lM2yHv7)mNy0ura^{abfkb=P{%p6B)3x&OR__f}S< z`~GpF+&^4Sy}NuT)VQbd;30j#EnvT@OVrNUm$!9po-5y#T{OqdpnRX%Wls3MmhQj- z)7`gEPEH)to(?OgdRz5}rcZ2d`yTzV?sePOxKn?s+-6T#m+Q~@8|*Kea`e}f40|T; z9@9UyL7wna^S{<3US4O8)=vYjxjEy{Rt`1bl_=$(jpI_W569@B5=%ZBe zy_I6ZUW$|OrzV?8+vnMc&B+>B;zp&pE^`CNOmb?Y zBu@-!ioZrudcW1w!3Sl2dyC%MRc#kE?$(8^57@NoCw0;8)%LbWcA4}YbL`^0Crn0Z zl+8@uXqKc8*sSPmlbsYP+5L%T>D7K&c4XY-^n5AH_b2FzwvXlZ`Y~Pk&TDeV)>FEw zw#lw8YS%Rny<&6IRM+M{X4hWoGIG0OWO=!6s1jS6l%v72VH+Huso`PalOo*n-}ps_La&bce4)^LHY_3( zs;}|Ic;9i}E4;pG1%*Lhajv_i?%wTganM)jzByrkzrlYopO8D7R#d%+%m|qhGACqG zo^Dpiw2*lr6GLW(OwH5H4VfG=J7jvu{E!JEGeo9{%n_L+GD~Ed$UKpWA~Qv%>gnc+ zOxDxQ7MU(GUu43_jFBlLb4DhO%o>?CGH+z!$jp(cBXdV4kIdfFO&^&*k^m$F=%s)U za=>v(0J4Cj0m%cB2qY6oDv(?t$w0D!q{GwY14#&y5hNu@PLQM^SwYf*-qmpuiv#e G%l{V~?gk?O literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Fort_Wayne b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Fort_Wayne new file mode 100644 index 0000000000000000000000000000000000000000..09511ccdcf97a5baa8e1b0eb75e040eee6b6e0c4 GIT binary patch literal 1666 zcmdVaT};kV0LStFL*AOuCUenZx^UBrvdmhxOs$2dygYfS)X7^*(Gj&G`CoXy!A)V7 zj1gwph`4Am!&tLPDN)B;GiE#Fg4v$G^F7?Tvbk}do&V?GbJNZ5`vh`JHYPfMoH6Db zE@z#&yhpm`(ReP#J$385Y}z-$J$<5IK3qA&eb}2J9~}s~PolrdCq?6QSLLwtH1(tI z&gph~rg!RRNjIEcr$zTg9C!NEQT;sF>h^bR(=P@Z+?N-Q$bt46ckp0^RE>G=tCE0x zT{q8tlQ~DeEtuxM|1w2?F#kQ+7OB1So^l$3+PD9eN{g?O>1hi@`f#((h%HnZU59jL z*nE|FwM;Mk6s;DWJSZ3UqzZp+sm!`QLuBXs<&ydku{0%KE~^|8%Ok^OAm@Py{1}!i zk}irB?+0V$3-!H%Z{Pi3)V$|q=@bSEsWXJKmn^$}xo_DFq8EfCi+vg;n z&ScNK-{G6O*dK5fq?x7iA@!2N?{$g&PIRztwO~~w!=^^t&CWy?? zYNm+H5t*db%o3ROUKeyIY$N9GOt=_6mHE4_Ah3eW^kll?b<)3P?{SV6`5GvV$ z>!b*k&+Kq~Q$+Gb87Ym4p_I0xOJ23EwRXGy^t!dad$cUAiv?G$);E_{!}vtZ>XZHE z1g+RVikOdTsvu92NRj5P=m+f{;YDv|wwq zt@m%>3RQdyXvm>JA0njZ|CORoX73;G9l>KjLYlrMUI($NLKZywc2WBZGAyeTAc`m0Wt zQHd`e(JOKeOTxSXy)tRH_YT}oMXpi?gztq z)BZPQUfV^R{_IYfU;T|;(7fN=96VxgS@oQ`HRV;Cv8cghOns=C{!)`UwnrEJoM~eQ@L_eggC1`P}>l*Qf4HRol&BWc9LiUDI}2 zs?uULTzyo+mnL*=aG$K5h_N+u2TjdqXKiF^uUUWKxZN<;Wj5|OXlsY+OkI7iy}!TM zXvJIlzzenVV0Mo_)L10-iOt$jnl25K<=U7LD~(?Uv?+c zW9>8T5=`ts;9x zHjC^Q*)FnQWW&ggku4*8MmCM?8rim|+c&atPq%Yq>&V`b%_F-jcsYq!&mtkZvIDK>C3+1nCIU5~L?cQ;@D8ZSiz{K^o)fI)k*v z)Aa^v4$>W@JxG6$1|c0nT7>inX%f;Uq)nc#Pe`LYU8j&%dAeR9%|g0`vkw>1`{M-4z&U$vX@B8DMxwydN_~QvO|KY<^ zYCe2#w`XIaqm#E{VrS2H4T*ZIT{=C|(7;<7`th80Z9cBu?jF$Ymv(5_nX?jpv`!-S z?w1~wDv=eNq-Rly^qRdudT0A2DkVeuIFlthJVyGq>nbrp=^FESpvFFr)_zT0wEvYh zI-vfmI%{5QT=fHu-*Q6}R-aK<{xMC=y)W*Pdhw(-$iT@vB`IQ`B)iKbxy3Jo!>V=g z<9RaVN2v}yn=Zp1=4eW7o~AYo)wHc6b@-le9Z?XaBex8ZQJF!So*yQoqhD%9dW&QR zUDvFrCzAF4g^UTjAY&S@$=K#YGOq53WZyim-l|F&fApYEC@z+Xm78_a^zAyiXrWFS zRHVM_ES(xUUZ*+x>9j8{%?ZhroO>O0#^+d>dFqqSY6_Ow2RcY@{X3cC|0sFYjWRc{ zN#?D8qw|NKmIb*tH9vBBBE7v8DeY*7UEG@daQkHE? z)#BPIvb-=-S8Pp^m6KAWq##sQCH9cj8Q)}02Zxj)I2w zvaYc~D|TPh^>zDnLwSw*tNiM>EGwXOtH6K$*UGYPZ*({;tLcuT_3wA{(}1>?#XH;U zbHuqk=HoV}7ZC94<@<|kH9ySaVtKe)9q&TEHq&%cPq(G!Xq(r1fq)1y+B~qrXsS_y_sT3&{ zsTC;}sTL_0sTV02sTe64sTnES)>Ms@ZENaA3P&nON=Ir(ibtwP%17!)764fRWC@Tp zKo$X61!Ng)%{m|pfvg0w6v$d2i-D{LvK+{IAPa)52(l!|njnjUtO~L$wq{+Bg|Rg& zgDefQHpt>2tAi{LvOdTH+5T566r5s~Da~Wv?lh;@6Q30CN{Dkiy@{@0UlW6W0s=0- ADF6Tf literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Goose_Bay b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Goose_Bay new file mode 100644 index 0000000000000000000000000000000000000000..a3f299079aebb8524bf77e7f92e0a7e6d0a7b6fb GIT binary patch literal 3210 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 I`12Fr0@ri+2mk;8 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Grenada b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Grenada new file mode 100644 index 0000000000000000000000000000000000000000..697cf5bcf7f151ffc1c1fc4247e4e9c7e3ff01a3 GIT binary patch literal 148 zcmWHE%1kq2zzZ0GvP?kCG1=UB4deg+$3hqw{{KIIfPuxwH-y14ID{dD1VjD<0ZxOs JfTo#n0RWR(9N_=} literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Guadeloupe b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Guadeloupe new file mode 100644 index 0000000000000000000000000000000000000000..697cf5bcf7f151ffc1c1fc4247e4e9c7e3ff01a3 GIT binary patch literal 148 zcmWHE%1kq2zzZ0GvP?kCG1=UB4deg+$3hqw{{KIIfPuxwH-y14ID{dD1VjD<0ZxOs JfTo#n0RWR(9N_=} literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Guatemala b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Guatemala new file mode 100644 index 0000000000000000000000000000000000000000..407138caf94e467b52d925f96ad80b506e16d9ec GIT binary patch literal 280 zcmWHE%1kq2zzaBmvdlotGk@-@JM5ur64=j9yCA7kksx{gNr3vRcMmj9#9VL*2}*F4 z_YPoUgu?&-SF12E{Qtjm10xHNy?}wk$2Ww**#(G$Ll{Cxu=YO?fUE{N5@bD?208&m ggPZ}TfldL@Am@N+kdr_($XOto1gCKU-Dk!H0Ozwql>h($ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Guayaquil b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Guayaquil new file mode 100644 index 0000000000000000000000000000000000000000..0559a7a4a4288d7e3c3b1bcf47c57a7ea82be2ef GIT binary patch literal 246 zcmWHE%1kq2zzbM`vMfL>&;TU1Epd|27W;ESyYQJq{r~^}8JU@wng9Ras=>hU|NpiO z2A2Q-j~`&<`2Tc3(OamXJle#{{R1E1p~wX|EFCTSpNUN zdVzuK|Nr9$82EgALl|@oj7>~IBoLc0gpgnp(D45t+d%FD*$ARRwt{HVZRWB8+HYsV F1psIVJdOYW literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Halifax b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Halifax new file mode 100644 index 0000000000000000000000000000000000000000..756099abe6cee44295a5566ad6cd0c352fb82e64 GIT binary patch literal 3424 zcmeI!dvwor9LMqB+*&Iv3>mrB(9CyZS}yHNw1bTgHVm6jB5jH#bIBT=h@DgD2<0+F zE){-jXvqBB9lCtBp(*Ag*F>2l*ZulDKmYbe$2tAkcjvpu@9b=6|Gl2?#35-fM|uA7 zR5d^0TczsIIfqlj81N7U?a# zzS-S1??=a1a?!UtHO|@d{v3C&$aVI;mf`MqraK45cXkg3k8lok80$N9JKKA>uJ9c` zA-zXt|167}-^eJIS5-;oaedVNUL8v+(8rtPsUM;j>r&5rbs{87pU|1=WZ6`CYW)OJ zR+u7B=L{4&H&&iWixEF(HZ?m(0s2z;9d)_dS$(~(uefLrub+0sB z-#=7SRTR|F{m$@^@KP6pLzZk$lM6ECQS4%ZGy(iXhJd z8FX#3ctlTyF#ttlNnl0@Z>TP?fJcwKbs`>uR`M_Zr|Mo;LsajjQ)T?|D3OqrBKvHuBl-@Dm14n7(XVq;**~*X3}{$cCMInciFeP- zfzeCF!1Dom@Dl}U@V>J;xni*zvU}2^?L9ob9?Ifoyx-KdOJm6R5Di8Pv5Bd-O```Eb_eqb(??0vjs`&i}eV#!3 z`BD2lI6fiK)3v*K2bgz|c}1cbDvu|?eoK6SZS$LleM2@5**RqEkiA1T57|9r`;h%Z zHqdHz5ZOYj*+XO#t!5XIZAA7F*+^t3k*!4b64^{-H<9f`_7mAqWJi%LMfMcgRIAxl zWLvFfUy+Tqnw>?q7TH^5bCKOewinr7WP_0%Mz$E)V`P)9W|xs|wwirLHX7M!tJ!K~ zuaV70b{pAlWWSLOM|Rw5wj9}WWYdvdN46c=cVy#{okzAF*?VO3k=?hN?ML?CY8rra z0BHfz1EdK^7mzj}eLxz4bOLDw(hH;+R?`in9Y{ZrhM?^TA7}}W=?Tyjq$@~UkiH;| zK{|u92I&pb9Hcu|(;lQhNQ00LAuU3Bgft2164EB5Pe`MXP9d#AdWAF#=@!y1tLYcg zFr;Hh%aEQSO+&hdv<>MS(m14ZNb8W^A)-HL1|kUQI=tf)edtf=$1?pl|xD|4?{(JNE*?u4_}s_>UJ zX32ydGuJ7x)5Chtc&pqydP?u>tC6^#!y4a_BMC?LYhrVvB-IzHyE0poA6cU*S@C+m zwOu^RFUsoVld}3okEBKnY3kI7J}~=%K6v(HO&fbv*K`fb+E4drdfO?%XYm=ib!9cY3sF{D2m}a8yhBO0~4SQ6KHF zv@GWhd90;GcEmTx~ zOG8JMG+s)O1I^je)Eg$vrSbCIk)Omb!2jPqf&PDaf&%}$$LH%Fbh*seb_M!;=WM?a zpYQZZ*Ze=f{Mnr2b!{~7x=iyHc+GlTEKoDkEh^>WmZ`sWeh*q}E8W9Zj{7 zayy!OBL#Of6-P>r)Ep@~Qgx*4NZs-OTli2Ddyk2JTuw?tazavKQe2MPo!~Y%cj)ib CX!a@q literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Hermosillo b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Hermosillo new file mode 100644 index 0000000000000000000000000000000000000000..791a9fa2b38729ff10032f9e1f021754c76c87f5 GIT binary patch literal 416 zcmWHE%1kq2zzg_+vTQ&svUJ;vg7u&B9&AesOW5vwDPaeXS;CILZ68j*DonUBamxn= zhJpse^cDf5VzCBe_cQ^MpdSsU>K+1SMzk`5cLV|Pu0|Cg%AR6Rs5DjuVhz2h^bR(=P@Z+?N-Q$bt46ckp0^RE>G=tCE0x zT{q8tlQ~DeEtuxM|1w2?F#kQ+7OB1So^l$3+PD9eN{g?O>1hi@`f#((h%HnZU59jL z*nE|FwM;Mk6s;DWJSZ3UqzZp+sm!`QLuBXs<&ydku{0%KE~^|8%Ok^OAm@Py{1}!i zk}irB?+0V$3-!H%Z{Pi3)V$|q=@bSEsWXJKmn^$}xo_DFq8EfCi+vg;n z&ScNK-{G6O*dK5fq?x7iA@!2N?{$g&PIRztwO~~w!=^^t&CWy?? zYNm+H5t*db%o3R-DV@{%eY?zBUH7p6`TTcudiDF_T~hY^ zO!>=&*l&2aJ@(-}THBBMeTjPSC%>tNnz6cZ&jt1M>pp#U+K@V15^B!potKU&r_Fb% zN2ODmO;=Q%boIPtzV{v07f!4<7rS@qOZ(qc-K|ynhpp>WPko{8E%U0r>I{9^GfVwg z9H*}oq?`WCbops^thpK=D_3t$G}r9^eyx4j{M_FszjU;jfiK$R`te>h*xaMd-c#zv zwv&2jX|1|7Tq?J(ddx_tM}Ge@!T4Gd#Q%PTk=+pzP&;Twy*wy^Yr|Dg$rv4+dtKf2 z#DES-{ziqo5wAldKT@Fw-jy)(wi?s3Lx*=AG!Z8%^w?wD&A9#BC9hD=-asd+HX%B)Qtlyz&~GwY+;r97wBl=}vBWm=P}>^`G6MAxVdt%r2g@Jh9@ zeuv)FnWZ*YSLjz-5><6^fqr%OST!oZ{saa&c)jya@ZWrY=fCZ~4gQBe`&a*(-~ZuP zB7Xm|g8@N){|5~++P#On&qzLH!k^#I%l68XbL_LwJ_Yv4^~zlP&IPzn@cxJO`Rx@4 z`WlcGB1=Tph%6FWC9+JXT_>_oWTnVbk+mX=b=uV;%SG0UEEriavSeh<$fA)|Bg;nC zjVv5lIkI$Q?a1PtcJ;{eop$|50gwtHB|vI`6alFMQU;_BNFk6)Af-TRfvy<5Pz}zO zgQFfuK{zUclmw{>QWT^rPFohFE>2q*j>;gVL282(2dNHH9*+7T1>&d>QX-BTAw}Y- z5>h6PIw6JPsFc%|3aJ%RETmdUxsZAx1>>j~QZkO3Aw}b;8d5fnx;bs(kjf#YLu%)= z#p9@+)0U5;eok9JjtU|rL~4i>5vd|lMx>5NA(2WVr9^7!w8ccK>9pnKsHf8wl%t|Z zNjYkY6qTc@NLe}RiWC;9EK*vewn%Z2>N;(Ck@`AqfsqP3ZHbW@BSq$@GE!!aIwOVV zs5DY)j#?wd=BT#QmK&+J(-s`5xYL##sX0<~r0Pi7k-8&=$NyL5!|X4CS@xGfV)kQ6 RGn0}Nvr|%%Qj(Ix{s3RXO|k$0 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Marengo b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Marengo new file mode 100644 index 0000000000000000000000000000000000000000..1abf75e7e864625b975feebdd0b232d0de624b27 GIT binary patch literal 1722 zcmdVaUucbC0LSt7*lf0p5t>?4b|E$U$0SXWtu-8mgBj)-o6~G~Ff;$=T==^ZN}Hsa z$lo;oLt03qB-tYQvpvQ}7|+ZF$$35Br*PrQrT6W9KX2#aT>ZX}FRyq>s`J+sZhqn6 z@|%b6*noM}9!m%uy7o=hZR-;_eBhb9w<8#6ivJ>;3L^CLmYTqelY3-a<+#AB?9uXd z{*XZX@EF;VmF~RhKT5wH7U#VEJV?JY|Mu?TSN*=D&G~TdsqSpN?R?yOU4N=qf#8)` z?H+fPQxnvl?Jrf2wMvJ`pa>N|WX~KW!p67C@Z?(}eAi$Z5q(}poY|)%^)``_R4y|! zCW_4N6FO_eLY38ArL&_ZsO$@+dQxY+ntX7lobq_Q@NO)TQ!ft{)8>0+PIai5o}MIU ztmzOlWBWVZy<5&sJ0)hf_tm*^jVkwcm!2Cuq4JJ4>v=6zYW|i>dO<^}$}gzmbzSwSs#Us5a6lwP%>My(!rOP5Vsr^?O(rKw?4{o zT=(i(PpIpju5)_X@80$u&D$B^x_54PVy1X~&cqD!%rws&^W^xPO!J*-e&h1kH~9Wx zg08vpLxOe46p=Y1lSF2TOcR->)l3wbDKb@LuE=DO*&@?L=8H@inX%PO8JV-yOd6Rr zGHqnu$i$JEqn$b*%$>_j9+*8cePsSf0!Ri(3P=uClLV55)ue&sfh2-tVl}BCxmZmy zNH$iJ4w4U&5Rws+5|R^=6p|H^7Lpf|7?PRQq=w{XHOV2_SxtIKen^5yhDeG?j!2S7 zmPndNo=Bodrbwztu2z#QlC9OGi{xuH2_qRJDI+-}Nh4V!X(M?fi6faKsUx{tP4Y__Ap*4#5^wY1K!@B6uk#4G8p=kPnP-!^vl zyg#Ytwufh%t4^N&hKJLo5AVf+e)Ydz7VP}+4;k1rHF)*q@8q-RGQp`C7v)rIzWXtK zdw6zckqkA|nxC$}#SNF1nBfaIxpVs8=T1(zpND=hzr6je8##W=oPY5nH@Ytj+|EyA zY|GK$!p7HRymNPOaaphY+PEqB?T$A2y>eA>X>!_Knn;_=!wL82>4f>~#4MLNILkzP z;?C@dn^^CtoAkt}$y!q=*{xH8oTl@VJ9i|=tNK#%UMLOnr@bTjdv}=vw@s#mTZ6)H z_Ph9zwZYUwFS)wPZmF+ZAob%Pn1=Gzu3>PqOT_OC6YqAoyGLe(_q_7F%=>z-O|Ea3 z`S0Is8aF?g(2}YuOvV zc4fYo?pyn8_nD8Sr>MvF9Ns1CCYtS&{m;r%r)%x{4QYA$V2Rz(l8}u%jGYwIPgb^v z*MEOcD&jT(h$-S(h~Zf zc%dndcEzDBq%RJQA)O(uA-y5Zd9^#FJ+Jo1p+TfWq(!7hq)DVpq)o5($)QoNc8av> z)n1Wik#3Q8k$#bek&cm;k)DyJk*<-pz1la@xK}$zTK8)2Nb^YdNc%|t$Oa%gfNTM> z2goKMyMSy1vJc2ccy%X`t?=qzAe-UU-9WYj*$-qxkR3s`1lbd0Q;=OjwguT2WMjO# zGsxC>b#IW(@#^j%+k@;6vO&lWAzOs(5&oYxsX(WyMyIMQIj3TFMO9g{y1JseqN?C; Daf7s4 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Tell_City b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Tell_City new file mode 100644 index 0000000000000000000000000000000000000000..7bbb653cd7ce09d88f8a1701853bfe92ac7db0c4 GIT binary patch literal 1684 zcmdtiOGuPa9ER~TnU<0gQsF{u(IUdp9Ls2-s}vb?vdd(pre&Ji%~PqQm7YatyNIA0 zp$1k&bdkU;LPG5V5z&Q^f-p;yYVxE8Mm1mOIS>V{YS~}D`F#v7-)H=J6`PaA9~W-E z;o*wS!+WeUAI)dos^!KP+1ePTPM>@s?;i}R$8*Nz|LSMb|IMXxQ#xht zV4PSR_f)UFEyTKDht6vo5cw~U>w*KlVtrSgE-X1Kikb`b24A<@*i~YldcK|RL$ZxS@ZIt+7r_#_jI+Z+KF;m*L+0n?aPw;>Z{fMPPeQt zT%#I}N6ASp^A|GN!t1ZUQ1c!Z8W#HNn}2(AoJ;40aGdK`T$3H=LaUf+->2En>3oVA zj&t{xE9UqA$@clhl63Q|GS3?GEcc5H^PXY8<6QRh=ZpU@mgkr&3<2F zvPfi=R`wALV<_HLms;5`X_`4149?FT>s>1wwaElEvDsEwykBhhsyHO zZH)*sijpD{%CHVn5fwxPN)ZG$1$h%j>`+Aen(tgY1znoQywBsEzrRqpYk#rx$603n za5?qn^6iV8*XYf>_|?ZhMdHab20;rYdKLbyen8Rdv5dZ(GP!+pk=Z)$hwh zaG+b(JX|koTY|DK;T83z1#-u+dC}m@lA*>|BJ^`fHkI5KO$ z8?$=%+^}jnGpYAX_o&v65#2UgqeSq5Y#-_td-D@=UnD3xGGnr{vOsh$gk@wymWaG5 zm0jseqU&ysJTU)GbSF0Jp0|tYVAQ7%-J4atjY%ypPO8HtN+0PRQAgK3(|xu5sxSFT zMmHrybndB)WyeHp`nv4@9u_A?&&rb@O2xonM4p<;5reH&^7JJ~qP<;Y|3{DO zPLw&0>pq(BcwP6-n6un|ue9$qyq&eK`|^n=yE+(h$}7xmFn6c9bs;BUz60hT$7A0R z`im%Bb6QiAV@MoGAV?%gC`c?wFjf-{5)RsU_#hyTi3kV@i3te`i3$k|i3v*sK{UBFU

CW46GxWPD@y@$16ZL!ZukRmz*B|;`IUg@P*ZrNholn<$ zcAo9eWqhYvd3!*wikw#Y$Gdbv_kLBlyG^g|C|5=6oAsK|LM8l{ zWN~AeSUasrt_%9b`cbvABs)oz^ykaqlo%1bpDs&>ghgpIr769+vRQ4Ja7$O`ZBx~em$GJ7lc?#wDQjbEMQz71x$S$t*dE#= zcRWiMJL`gSS9`puE6S1e2OTlUXRfGd3$MRlgNK;Q{AlI5TWhJ2!l>x&DANFVoyh&Ar0hivmuTdCxMxaeVd(fxj4@XHHR6qy-ru zGD2jC$QY49BBQjLVIt#128xUn87eYXWU$C+k>MiaMFxzF*lLE1jM-`ijf@%@HZpEx z;K<04p(A5Q29Jy$89p+8v;pu!1RN6r5Cakf5{1=-!66Q-2?UA6YC=I`L4rY|LBc`e zK>|V|LPA1fLV`k~vYN1vxU42HBr>ZB4T%j24v7v44~Y*65Qz{85s48A5{VKC6N%Gm z0!1RVnoyBgttMC`S|nT~UL;^7VkBfFW+Z4NY9wqVZmS6#iQH;JM`E{{;F0K&@R9hD n4*>EJKt2TcUw;fnm~TXy`9>u8rzfT+CMWn)QW8@VlSljl+LDCq literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Winamac b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Winamac new file mode 100644 index 0000000000000000000000000000000000000000..630935c1e1a8c1a87e728fc1dcc4c930e81b30e9 GIT binary patch literal 1778 zcmdtiNo-9~7{KxKsHrhEK`fd_SlCpnq=-BT(WWV$@zqe&F*eoW&>^j%?!vsmrbVPG z#28AbBGMp&L`0~X)iIT*a;g?Y@~-ngTQ)46n|ppYZ}k@6|BGbhE*&au>T$ND5X|B z7S-lS?>*v)-esOfYrJPy3e5Ay3h%|SovN{})O)#YwbGSyyjQsq^}1}d_aK4KlBMl*zx_s+SkXn-$gddSzzRs2w$WRf;yNS61kP-q%dwh7N0qL=UAyb|a;F&q)&Qtdn4zBBDRB_h)7 zcbff;6L2>~{$ebBd$QX{tB~jVFT6%uPV ZON!kr3E^RhLlcK2gp-pKlM{!;{sIlvy2bzi literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indianapolis b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indianapolis new file mode 100644 index 0000000000000000000000000000000000000000..09511ccdcf97a5baa8e1b0eb75e040eee6b6e0c4 GIT binary patch literal 1666 zcmdVaT};kV0LStFL*AOuCUenZx^UBrvdmhxOs$2dygYfS)X7^*(Gj&G`CoXy!A)V7 zj1gwph`4Am!&tLPDN)B;GiE#Fg4v$G^F7?Tvbk}do&V?GbJNZ5`vh`JHYPfMoH6Db zE@z#&yhpm`(ReP#J$385Y}z-$J$<5IK3qA&eb}2J9~}s~PolrdCq?6QSLLwtH1(tI z&gph~rg!RRNjIEcr$zTg9C!NEQT;sF>h^bR(=P@Z+?N-Q$bt46ckp0^RE>G=tCE0x zT{q8tlQ~DeEtuxM|1w2?F#kQ+7OB1So^l$3+PD9eN{g?O>1hi@`f#((h%HnZU59jL z*nE|FwM;Mk6s;DWJSZ3UqzZp+sm!`QLuBXs<&ydku{0%KE~^|8%Ok^OAm@Py{1}!i zk}irB?+0V$3-!H%Z{Pi3)V$|q=@bSEsWXJKmn^$}xo_DFq8EfCi+vg;n z&ScNK-{G6O*dK5fq?x7iA@!2N?{$g&PIRztwO~~w!=^^t&CWy?? zYNm+H5t*db%o3ROMnJib$2dy-9&dm+y96rkCaC7}x*#9=m=AQ?$SzN#O&*yDDYJS=6#qOT|-k=yFxg@sS|2sp)lb`L<@x5}{P}kJ+$wn_ zGhknLk+WKGHEtFReyD|)wo7Q>Z4DoPMwC_>6s`8zBU!-|FlcKJ#CgA4d}Ad2hH-{KXk=` zeP(6bm-=Ma0a;ahRG(_uE0sm>XjSD#sk${}qoEEHy>!@CXEmGZ<2`ouwUwsk{g3t8 z%S{sN=+-qSmrHF^QtSHj(6)R()vWmD*wzLH2vOIDw@Mr)+?T1pea zkR&cNYI5QfNq$qoAewuT(Ly?5B`DE-^+Y&&6gWnZzo zYx~Xau{)Y7J0_`-@3eh-pR^C2(Kkj@^5(!H-SbtWbad|5y{9Uqv$<9Gy_YK)<1+3W z|3CcQeSPWlCm)O(pHBCR$xNpYs>$--ObtaMrmnIwZtB*?O^lEGKmH${ZQ31A7kR$O z6Xtlv$Wun1Gslxgo;AnQMxHnF#F1z2bx$36?#Pozo;~vPk>`&jfMkHAfaJiD1d;_u z8b}^qmk5%H*QJ8w!jTM;4U!I$50Vg)5t0&;6Ot5?6_OT`7m^r~nb)O;kDlDXHVj^yrj$s^fwq>tp!F#*U7a7+O*2ON`t%mOkE$UGnufy{*0O$9O+UN;%Y zY2&h6g2+0|*wv~66jcHPoD(`EYAW|!+$`=xf- z%BF!K`9#E+K{1m4AVthS8AUMi4;ErM9Y$2FUqO2iEq=BjX>d=!_b>EGPuAnkIOlaZ zJ8VzR`;%(RJXP!c>j>H>oE$y&h&RaBb-Yh`*H|DwF2*N!8MqFOSwo)T-x3WpzoRO0|9=sfls5 zCib4J`S}*Jw)C7{d-keXmph`{-X1oOkL=Uy_nb6O40h@b?T5_9{*_viAF54zJ7jZp zpL#N#l=gydwIv>rEn{seT~R3MFY8ri%D7}cC{-z zu0_88{+r%RejAu`{W)(|N26X-OUi3nZO_I=F7|vZO0-Ux2qy(e}{tHDQRUl;`bs&Wxl^~@cwK#1tNHs_~NIghFNJU6VNKHslNL5H# zNL@%_NM%l28d96n7Kc=al!w%Z6o^!al!(-b6p2)cl!?@d6pB=el#0~qw8e5zEmAI0 zFH$g4F;X&8Gg35CHBvTGH&QrKxzm=8)b6y!Bh@=?`AGf90w61ZECI3x$RZ%CfGh*D z4#+|vE8(x3*6vQo%WA#3Hdi-oL~(=HdXUQWAU$ciCL nhO8N~XvnG|%ZC52bqm@pjM*8iO3n}0hND%(@dH literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Jamaica b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Jamaica new file mode 100644 index 0000000000000000000000000000000000000000..2a9b7fd52d37a1ffe9fc589daa04d88c6c71a6e0 GIT binary patch literal 482 zcmbu*F;Buk9ES0uk_c^)3WDIMQyobh+%-Uyi7q;I5!0=!3o!vT4otAP8W#r=1_s#J z{0waO1x)S}c>W(|V`9AK?l*LL-sn2%HPo-CDu1(bgL`?##rfCvsGjD7w>UqY7}q?; zo_eWXN!6g5cEMyW!| okUFFgsYFVVTBI1MM#_&qWD#T){QokpOmyOY16WpdI{*Lx literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Jujuy b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Jujuy new file mode 100644 index 0000000000000000000000000000000000000000..604b85663672d83658f331a69cc8f41cf2a2b5a1 GIT binary patch literal 1048 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 a9ky&cY^j0%X<2C*se#PQw9K@OxIY1Es=sdl literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Kentucky/Monticello b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Kentucky/Monticello new file mode 100644 index 0000000000000000000000000000000000000000..438e3eab4a6e581c6f5e7661098bf07b1a000593 GIT binary patch literal 2352 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 RGn0}Nvr|%%Qj(Ix{s3RXO|k$0 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Kralendijk b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Kralendijk new file mode 100644 index 0000000000000000000000000000000000000000..f7ab6efcc0f5bfd5c4172cbe32c03a8e08b0099c GIT binary patch literal 186 zcmWHE%1kq2zzdjwvdlotH(5?k`P+;)9*j)?|L>1wVEF(4zzznM|NoC4VBqrc4PnqV eFfle@a10J%2qD4L|3CmT8AKCjIv3Ci6D|O%z%CO2 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/La_Paz b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/La_Paz new file mode 100644 index 0000000000000000000000000000000000000000..a10137243577a8b312dc463571c4c94ecd3bf1f1 GIT binary patch literal 232 zcmWHE%1kq2zzbM_vLGzb03>$EO?$HA-PJ4g|NsAIWMXFi|Nnpt0|S_3`Tzf%4kO3^ z|Hlt7@c8(KFgOFTQ*a1_u7L?d2nqH8jsBn6E}a6RLH2=Zpq)VL8R~%?Qtaij0orb7 G!UX`MNklgQ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Lima b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Lima new file mode 100644 index 0000000000000000000000000000000000000000..3c6529b7567f032882863fcd48b790e0988261bf GIT binary patch literal 406 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 a9ky&cY^j0%X<2C*se#PQw9K@OxIY1Es=sdl literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Lower_Princes b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Lower_Princes new file mode 100644 index 0000000000000000000000000000000000000000..f7ab6efcc0f5bfd5c4172cbe32c03a8e08b0099c GIT binary patch literal 186 zcmWHE%1kq2zzdjwvdlotH(5?k`P+;)9*j)?|L>1wVEF(4zzznM|NoC4VBqrc4PnqV eFfle@a10J%2qD4L|3CmT8AKCjIv3Ci6D|O%z%CO2 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Maceio b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Maceio new file mode 100644 index 0000000000000000000000000000000000000000..bc8b951d2e880182a369cba8fae1270e40694aaa GIT binary patch literal 744 zcmb8sy)Q#i0EY3~`iPX2#b9V18jFw|EomE#SP6rq0|t`_6N7<-AYqaiNm$M(2DxKv zvQQ=>MAEcXI#!@YUl`1s6J(E9ahH@6k$)NLP3FD2>+@`>+$ zm3;1&N4a^CjvUJLV@YP3?(Ix+Ok_VBWo|Dg?y|cw9}kJw9c{l=O^Em7N%`URtKvw9 zET&FG$#Z3w_KWKCsak$*E-T;pmh>;&s%F(=i_nE?S(}lqwPz|Y+F%DB=0scg#csP! z3Awr`yL`hc{C;Xj5*s3VSCG+{LD74r?bxhWt!S;?t}TQ%4#*bB9>^w+W*1}|N3##I5wa7q6|xtynWNba*$&wcSIoba RxuDDa$A+GmS+XzW`2pmRDPI5p literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Managua b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Managua new file mode 100644 index 0000000000000000000000000000000000000000..e0242bff6e5df45de8b235abb4a8405fbb8ba6a6 GIT binary patch literal 430 zcmWHE%1kq2zzYO`vTQ&s(f}m(>Uz9jb1q5XTw)g>82ICX;FbIUVZ&Pwgtr6+XeLfn z&^qWHpzVD3fziqL0ZtJI9yr@)2DpUeHMq)0CNMHFGqC_6GnD@Sf4vL?1CW$pVEO-l z^#TTt|NnPxVBi6fi~fKr5DoGdhz9u$M1%YXqCtKH(I9_DJvrI;s8ae`rgL{9Z;bKW*wZtn zQg$3;9&X)kd#|0u%4*=GMaEuPC-}!w`!T~>WO1ZjjVwpjBLyOD1*Alzt$`Flsvu>M zI!Ga;5>g7Og%pdl)sS+LwjNRtsmOn%BvKP8id03)B6X3%NM+31cg1#gy+2C(bGG+< G*8c@X3!5-j=;1ext3M?f^lLZH12AWK0s$rf_~U0}im01JaW A1poj5 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Matamoros b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Matamoros new file mode 100644 index 0000000000000000000000000000000000000000..047968dfff4dba196d5c9695e79cf28395d9a0aa GIT binary patch literal 1390 zcmc)J%}Z2K9Eb5UB`A^wfe<7L6}V`coH5Nz%W`Va98DcxQZp-c)L!P4Iyh!_AkkI1 z2uvs>MB9W|o56@AtTs_d5F#yvk|YA@1VuvP?L7An2wFtH%jL7U%lmu-HLcAa@yDw& zU)P&=!+7+4!?ucVVtd8r#()l`>MsBvM(|tHCtqQUdz3)Ng`|OXPvdQCieY$ zrL%v;sQu9yoin+ra-ZDP2L>0^!8=mtg`TNHeK+Lcl2Mi47?R%Ied>s}R36>btb9At zrElfBD2Pdv1@ld!aPg-+cK5a_nk$z6o`@=rrpc1JT6KJAvn`JJwQDa47jsID3NC~6mmbzR>JadNs_*Eil5r$*{@gMUVy9*D>@ zyT;VnV6ALS=vPg?T-mhTqJpU@GWe!YwZ=MR>x5IaEiKA(Lj~getfeo6cZ!RXA9ScP zLCC@9`clSMaXB=u+Y{f4j*$ zvo*1C1ZQia;|LFl4+#*75D5{95eX8B5(yKD6A9GTM2duJYhvXH*49MJ5iSxhN5DwL z93dkya|De3vHPIvC+nV^10U#sb7y>c|jzJ)!;1~un4vv8! zBjFf|tr-h47+W(MWH`2FJjj5M5g|iD#)J$C85RDwVa1z;WtxRK{pl``E6wS5yIpQq GTKsS6)nhdP literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Mazatlan b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Mazatlan new file mode 100644 index 0000000000000000000000000000000000000000..e4a785743d75f939c3e4798ebe7c79d38e4cfd08 GIT binary patch literal 1526 zcmd6mduUH#9EZPSF0IvGatV=GiPmn+W@hYSGxpoYew!J#-)4R@cC}d>w!LL3a(Smj z%}^pNZHZYf3JBG^py1dz*TL~{c-Tq5G-J=HwpM0wF^t9X<6sgo<#my?bdYWFG>{UxPjOd63 zYt+*4UL84Mk&2r2O``h!)v}*&BzkzVS>E+RVmkfIiaTu*d;GIm+1ezlDxR6R=2jh_ z-f0qw8gydF39~veUnd3BnB>4XojlT_Qhev@l%8s}_QN>6t~*PmKAk77(~&Ceny;kS z%}^OfKFa!n2(zK|p=8EQH}2G{k~R0c$qqUq8|AIZnR;30^xZR?h7ar9`{&H&*QI*P zmAh)|%`}~N=&Z^=8LB-cS`{?9q%fsWZOaRhqJ@cSd+a3fPWG7M*gY$RCTX+YGqYXQhSW*z zkE5zCAXn;oD^&fL7}_4H_f(f#T$yf3uy2NaU5RdS|AjP`J;Z^?0}%)!5kw@1woDMA z;BTprvr_X!E{I?d$snRZWP=C?kq#oBLt8$GfD8#CA~Ixz2+5EVA|^vlh@cQjA)-QL zg$N6g79y@gTV9C34sD4cB12?`2+fchA~r*Ah~Ny#A)+&6hX~J*9wI(Nen*jOZlqmokZVbBSa4{N MD=aiPA~@9V7s`x}c>n+a literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Mendoza b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Mendoza new file mode 100644 index 0000000000000000000000000000000000000000..f9e677f171b3900dfd978eb8ea2aa226557d2c5b GIT binary patch literal 1076 zcmc)I&r8#B9LMpmy44a71A~4LA*7g#;KSTnP{~I;7||{^3Osd)A_$5O8T4ay=@blN z1cBnpYtW~_61DcJWh)^W%!r`FqUcsctYKDudOtsZK-8&y`Rwr>8{-SFXJ+{L(RlF3 zSD$>lO3vC#@^l`ksiYk2mbM@Cnt3M|I=lxLIl+uuJ8t`d%N=%hes`M=5E4&K^*|ZV%~| z(WG)$6MFT;J`?FYS=f@FG@a3Wp)2*(bbUEf=-!af-7iaK>+&(%WA>U@?Va9s<4{Mc z@yzTj#*8-YrvG4{9UNI>2H$2ovd+1t=9a&_!XYmI<50LI+$^8M&K1uGfpeuw5OS_; zgNSplDot(9y{|Pzxewa*r!&ETob4(hr&mrq$o#`H@{sQI=so#==U50?30VqR%PWf^ zt9fNPWIbd-WJP32WKCpIWL0EYWL;!oWM!``jjZjJ#gWyK<-M{#Qh-+~KuSPrK#K56 z6-XIK9bPE}sl+R#AhjUHAk`q{AoZXxh#RR$f)6MOsR=0xsR}8}D|I1-d8IO>G^949 hIHWqHJfuFPK%_#XM6c9{S$VYoQ)KIIX|u1l^*1v}?Na~% literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Menominee b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Menominee new file mode 100644 index 0000000000000000000000000000000000000000..314613866de53e1457f6cbf2fb617be7e4955edf GIT binary patch literal 2274 zcmd_qT};(=9LMn=X7P|bWKxI(r6ofSN5IgdNm0TWs{+K2BHZC~97JbK>;S7m=kg6?_cw0ylItWQk4A}8u%&2Y=;PRqEcQm!u$bo|>Ki zjm(KoQ@$y`7~jRPntS~#Gw;i@>b}$OnE40Cbm50DnEN|N^aHPoDQY^VA8g+#4^_Ob z7c?|U@yvEzQoKY;F2AozbJm;E;k~LXzQUCCZ&Br=dFJ8QUe*gwEfW9MR=wy*u2j_4 z=*7Dy%98nodTGlQS(cWe1ItfIU@S^k77R$`&*`cv{iLb-LaFNT5wo)Qys8=5V`|$! zSC0&CHme#As7JeN&13#gb=~$>S)J3X>w`7Y5Z|HKloraG(X~35nIXY%%XMRPlr;8v z^ty`|dE5~vp$rqo;rBWG*!kc>HN$*UGSTFrs++yA$dqOS8O-U;ZYs(^-5^u zxZae~A)5vd>()Ql%I5Aaz2*CI+1l2kpB?Z>+o~1%xjhLoF3SFH81J}|@Bj7}iS(UO zDiS$*C~ABp^7eieF@s+`U7e~v3-`=XN7$h2ULmu=Azsi0{>!05qotT z%j%IiA(KL8g-i>X7cw!Yof$GUWNyghkl7*ASt8R!=7~%c znJLFqk-2hA7MU%_bdmXTOc?BnZh6k|L+g5l51oHcK37a@ss`BnrtCk}4!uNV1S@ zA?ZT$g(M8g7?Lul%^8w3r_CBi+MG6T9En3R$B{ZDcO1z>vd57=B!5T(kqja!L~@8E z(P^`Yq|s^fh$PZ!Gl`@U$t6cJk!*6L6Uiq>LXnJeq!h_1M^c?Ot4La%Hm^uxoi?*b pYLVO`$wjh@q!-CA{tpryXA3>smfGW=<<0lzdi;5L-aKz^++RkMdw>7{ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Merida b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Merida new file mode 100644 index 0000000000000000000000000000000000000000..ea852da33a81478433a389e2b4da03b425d9f764 GIT binary patch literal 1422 zcmd7ROGs2<7>Ds!GcpT|LWwRQ5r|-;j+e~Jv{46hCT~-km6y`7Ny|?yvGVePA_!%< z2qFoh=tiNnNHSYUkc&uyLMovMiileD6-ZLnbe?G+v&ue7Mo3ASGj#FF{ON{$WjBLFzZSq?eNWt-Erm!kn7uAoL;>`Kl;~FsA zqCV>FvF)ZrCUj}USylRaNbi_#Q)OfQdgo-h+I4MEcHhoW<-Mn*;`Az2>1&dzj&!pp z*CTt&qfB*7iqxbB8}H&GUAywFsr{0q_x%_*z9*4-|I4eU?$(U1AAg_@^iS!7m#?UX z#(P@z^s2_P7t-XdQ_X3kawx~G4lg?=Epa~6@~u-^!}Cn*RFxe0w8k90>yTrQ!%f@8 z3f(^V*>rSe>dwBWCMY;)&Odnk{_C?M*7v-G`28a{C6sT_!r#BR+#YchdnDU>9a$dn z{6!3Y>j;8$hyn=%iGw2$BodBLkXSf^L89RZC!iG%M?gqKNJvObNKi;rNLWZ*NMJ~0 zNN7lGNN`AWNO%FQ_&5R#Xhp~oA`&Ar^ZjQi_$T>nsV&@1RiJl{TBz|N70j&`rLqNuW3<4PiG7MxK$Uu;h zAVWdM!Z8?RG#tZ0#=|k7fYyjOh7`~m6UU&CQE?0l85c4zWMuf?3@yxBU5d51Sa*^w Q!4@CuPKdW9+v3B10g}OV)Bpeg literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Metlakatla b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Metlakatla new file mode 100644 index 0000000000000000000000000000000000000000..1e94be3d552ea0d6e29824469866c2a51a187be9 GIT binary patch literal 1423 zcmb``Pe>F|0LSs!b#+}`Ybwn@2YD1|n#pMR?-Y_`Vv^#zshMSIV*mV$Xr(C_<{=zC zgdMU6VbsAKI@uwMqEjg5A&NjMh%P1_Iuw!9`;K`k^wJFPeTLoZ_ZO&cI-RNg^?21U z9G+5j_)hFo*UO;*ZjJ>D^i5C?lL`f$uhJo!VJsz zNw2YFdav)7K7G#gO+FD3UoA88{gm{-ozt`qru5DC9|-;Ch`wdW6kEI7^=(aU zBD$(Vk0}a>?RhzRY)ZC>+fi=D`{G1`JIf4aeU!mZ2aU=^TU5SCHL6xVi0TQyadh#y zs3|xgYX+8$V>1(?wtn6?K0YW;lq^|wgLmY~J#*Hn#;dYE%CZ^?8)d_nQL8bzNH)%P zSWVvDvS~7Co%tLk&)#S^&dsNa^PLsO1aa@Um#ljyKwx=S6$WPov}TL(yT! zTAjIbvUBl=)fH#Su96z(9T1iGmdPcet@f%E;ZIl22 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Mexico_City b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Mexico_City new file mode 100644 index 0000000000000000000000000000000000000000..e7fb6f2953d123efbc2550f450decd794b017d4f GIT binary patch literal 1584 zcmd6m*-Mo{07pkNDie $G*m5W&p7va(E5OmA-2B`dv}Ub9R`EwQp3Pz0e&AEHHs zDB38p9x}}yBv3FC!-&dAE)*g4&=g40_BH4G1A?H3e#6Z9;CnsCSy17Q5Pw{W`8(U( z#aDW#WY3o>Pp>=Ibw6R;)#n%E>igNMhbHg1hR;T2jO2XwjC^>LG3Gt&8M~jGF>yY? z^SZwIX?S_Ph^U(@Ba`z*RMrO>9TY2KBA&>#bC!#B%ck_Y_rJvY?~irtw2#`*`$%u> z`JpxqwClLjlWKF9)LW_tReZ}Sxi$TgN+_+CiECQaw!}=C4<8=*&v#s;CvkC*pKTic{<@4AiB; zF`_KaTe}x#sqz)?borMkweRP!t{7jU_P@EV58RzmmBT~wVCRIYx_V7k*F03RwN2I( zyb`tU1F|l5KpaYP$iqv!Mg5uzUH`2~H2A0LhKXWv^g)6+Hs-GzFBhrfw?FF> z&GD+K{h9Xi=FBq3$A0UE} z^9=7H?lb&{G{EQp(gLIhNE47QAZ#HMKl(hH;+NH>sn82vyRVsr#)iP00J zDMnY2witau8iRCZ)3gTZ4bmK>J4kzw{vZuPI)t|Fvgd6L*Y>JH!zc8Xg)J;s_55jSda-{SB~`;=}*| literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Miquelon b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Miquelon new file mode 100644 index 0000000000000000000000000000000000000000..b924b7100438cfacf25c56c494fd1abf3f262100 GIT binary patch literal 1666 zcmd7S-Afcv0EY3=#6pS!2_iwPOtIY6-Obv{wqs>dy6s6a}cD!cYTZyKprji>#{ki0UcjvL-KH)O-!d+LRxn_GOZc#14zdooKn^(<8C7 zGg0q)HKgjAEM4FGKs6M9(7R7}sXbXw_1=b7wQu?jy+2f;_K!c2P5u_qG;&=w&nOqo z{m10Np8?U*9g(eXlSEs4zC83WTC`WXWXFY3(P7(mRP=;@a!1?ti&D$7?Pto0vF#yk zO|tEe@1rIc1jANNQP^^2`po0C!hbO^^Zzy@V~z|B85=S2qlp3u!_mZn1cF3@go4C^1cO9_goDI`1cXF{gyd*q zLV|KMQ6XVDnz)d_kjRkGkl2vmkm!)`kob@QkqD6xkrs+EgYc`M+FoUJe9`4TaW^3-qe;(c+uR< zKlx`kt4XdkG|ZtSVgj1Zc?2cR#G?qBfr6TuT)Ca^)648d?|RX>JJ09Yv-|q@O`4PW zcDU_tr@Q&W<(xK`cmGx9v8sK)C@NbccO1MV$|pvt@_j??hXMoCp$*;a6&)^hc=2_6 z<;4bdWaba{@5?LI(TK0?RogyO)qOs;*W^4<$9zuNkH6Zkj<=TBPxMPyC+bgDo-DX3 zYlq&;sgWU!Q7#AR}rF+VzVJ^`eJ4j#e?XPYGd+1;KT~jx^H|m@B zYt*mJ)w-qrOVwIatZyBz7Pm{PWZRBn(Y|h%ytA@U+|4eK_vS4Wza?hL`_T#F_mT1P z!LUsAN3SsX&}*7{_+YB;xDl#c=R@?P?Uf3*Wgn5gzqNdZQCfl+m?za^%B|R!UpA2nJRl8$XC5~=V{+9v(;0Dvvlue<5i!` zak_76pz@0wp!-F2s;7rN(*8pRi2h!eb%4hs5zy|E1Fl>afoB@zGe?eyfqN_Epq-zK z!FhLd(1&ZpkmR#^Xx2{kY~+6Z+|-ZM^M0S|;1LT{aObyjxOc1?-mqDYxH(+CP?6>g zsT<)4EsA!AmG*FqToL3Pwf>f4bjBoC_#)+qh#lk_GvgaaWUzss+uv6t&W)C0<9#uG zVvwAXcV5g4^pr`-2SrjxlT3-+E>fC2^z4CUYIaqlPVL;P=6q4DUvF@#xvPtHT1C1_ zpI@lw71@nDx1?HSC%5UGb;atv$XdN9yHG9m+oy9A7pmOOGcrG_K;$=+%BB8U zVrj)jx$Hr_c)w_gTz)=GI9H^~56XPSiu4I`<>ouW!?Vj{eqFmg=Hui3_+R_xb{~zg z+1%~}du(0Z?sLk+%k4f^Y3pIV`&!Sw@d-(`DKnF7lVi-qS>}o)Ga}}A{Pj%w7xUvb zCw*Y+cgPGOQ-sVBGD((ZmXK+(H1mW^6f#rDR3USPOcpX*$aEp|g-jSSW5|?QnmI!z z&C<*oGHuAbS(=GMW)7J;WbTm3LuL<|K4ktZ%>*Jdh)f|ehsY!%vxrP1GLOhaA~T6h zB{G-DWFoVPOeZp*$b=#@YH6kvnNws^ky%Bi6`5CLVv(6erWTo7WO9+&MWz>-Uu1%j z8Ahhq(#$b3$;d1t(~Qs zN9G-wcx2|0sYm7>nS5mSk?BX~A4vd`0VD;MCI?6okSri+K=Obj0?7oD3M3auGLUQ_ z=|J* zB_vHqo{&T#nL<*9|JBPq5tIYyFfX|jx@+0x`0Ni>pa qB-Kc+kz^y;#{bj(kLmU{O&??09+D6d79KV#Bw_UEu+d?oy#EAS!oC#% literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Monterrey b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Monterrey new file mode 100644 index 0000000000000000000000000000000000000000..a8928c8dc94aaebfaf9cdeb93011d41b482a4cc6 GIT binary patch literal 1390 zcmc)J$xBsX7{~EP6EX{g!WIo67KmWi+04o`&5P;H)N7iRL+Q1vmakf3h7Aj+E$5g304X2Qb{cQppqg}B{}|~S~+`(q%3}KQr`WNRo@?& z)af9-dib7MGxS5R9qlt|$6o1m1InZ~j_Hh^qiTKrIh|SEsIp>u^oFbgl^yES?&S%} zJ<}~YL18NAd5vs*^Ht^Ea!cOC0^>OuC7Z5IoBX!9viZm}Q&1JD3mZmEQN|qY%^NVq z;UD#u=nhjN6S_3)lq!8aq_qWR)EFw89*`ohgSNg_`#B z6}n?^%5-*T=&rseCLr*iJeGC#i-=`iJtIMuHF7;5IM3si%p&{E@{0E_e!gWN0H6W_ z4hR$s93UttIABn4Z~&no;eg`Q#=-%Hf`$Tzf`ToKqVe2RsTs4uBMd91tlOIY3fSQeaYWQh-vBQlL_>QouU3(Nf@2@KOL%5OYAL zVCDc#LCpc1f|~<41vv+F3U&&3r#5;Dd4V5w4Kg(e2u8b?&Y4}W#(y^?;omZsLQkdcx}+% zCg^A0ktJ{P&mL=PYgL2(^B>7MUDSBM{@DPHU3E@3^c_QY&BBxAak z*>NY+W!&?pr`=sG-uRj-5kI)olQ<()B!-*psY79rRNG)DKN%1yD=X}jg9~Na;Y4prF^IFbLK5l21*URjo0#8m>lE`s3+Vc}~<$Sr!Uhtw{qqbhykZYg-j9@5yy4nrr=)t%*)xZ=t`c>4UR& z%N&1j`;_3if>?ib@O^N7`j9^)oM7l%uRpAma!rVt_}hC@?4;N@eUG2+aroeG?pUSn z1uV;)F-mnuEw@tld#ou+J#t*BoR&VHJ$6k~>eUO^Or_oqyFBCXm4T2I(9c4#L_hiY zf>S?v<}FXZE!J{Ga7c7Wcu0ImfJlT$ zh)9e`kVuqBm`I#P9Vikh5~@+hiUe!a(IVj*b-YNxMjbH{GMbp#A3<~JsDZGJI&LIz zqmCR29f{qjgGZt_>hO{HkpUnhK!#w{V?YLhi~<=3G7e-Q$ViNOD9BihdN9anjCwf8 zc#r`hBSMCRj0qVOGAg4U7BViQ9vCt*WN66Pkij9NLxzWp4;dgbLS%@@7?D9DqcrMa TVp#u2|Lr&v3iM=GX`rV^4u^l-@waFg%5>%F-Ky$v zfxf-JOx(#oA@%A4QJuL<-d&I_?xkeO`xEDh2eE1LVV|+$QAmP(+;Oh@%O_Gk@f@R` zJRYrUuJ=|?&qnBHM_VfA9)IoH=u)<9r*>O%S=E}WbZzMr?&6uOGfWAOs7tbL=mFu` zx7UxyZiaWYj%{~=z z__*%p@lR)ZkT1<&e`+!k(Tihwg4GV#nF#uq<~mJTgR%m{TD}`uobb z_@g4O=AIlCo+n0K^U!-;n(IH|=Rf2Q`_zK6bkuu5So=Do-N=~adC6cou^z>uZ>YY@7 zJtMzNrNle6%q&pvhATZYC0ot%JD_LB&Qr6Umt< zeE)2uNY8M{`FmQ4j0rJv!Iw5s%k6poYP&zrum4lOb-4;w*laG>kzzM@m#c7_&C~ks zZGAQzVvn;8=x^SU=6%b&!{W?%*=%msN8EFap36KlZ>LovI;YY?F2>=oSBm_tdkRTvYK*E5;!O{c* zi3Ab~Bo;_8kZ2&`K;nS}1c?X|5+o)_P>`q~VL{@81jf=t1_=!k8zeYrMTakhhsVSR z2oMq>Bt%GzkRTyZLc)Z^2?-PuDN7S7BvweUkZ2*{LgIx442c*LG9+e5(2%GhVMF4E z1P+ND5;{v0J0y5W^pNl&@k0WLL=Xuf5}O(dL1 zJduDR5k*3Z#1siC5>+IuNL-P?B9TQxYiVMO1Q&@e5?&;}NPv+DBOyj&j072pG7@Ga z&PbpwO{9@fTbfuS!L~HfM#7E68wofPaU|qO%#olYQAfg##2pE|rHMQedP@^~B>0vl z`bhYZ_#+1Zas(iU0CEf<2LW;vAcp~R93Te*awH&!f~7eYkb}X}91Y0fU}=sAM-##_e!|ATe{f01&0NPcCmNu8r(HF)a!2+Ad$WR literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Montserrat b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Montserrat new file mode 100644 index 0000000000000000000000000000000000000000..697cf5bcf7f151ffc1c1fc4247e4e9c7e3ff01a3 GIT binary patch literal 148 zcmWHE%1kq2zzZ0GvP?kCG1=UB4deg+$3hqw{{KIIfPuxwH-y14ID{dD1VjD<0ZxOs JfTo#n0RWR(9N_=} literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Nassau b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Nassau new file mode 100644 index 0000000000000000000000000000000000000000..d807a61d4e9b725648fbbfb1bd6c93046d9785aa GIT binary patch literal 2388 zcmdtie@xV60LSqIQR#qyk|ISis0ie@B8XR_!Y8^D8f=UY8dGhx&i52*}?SuM@xL)XMSu zcB(&OU2-C_Moo-Y>&YJ$sXs3j>l^20tKi8b9eN|A9Nj@3)_z5W?^Jq<42lSGLr$$! zVp_>%IX(BZh@3MZZ;Cr2oQ}iNsh<~7YOjp`>Qxof?~^y5YE!XqKBwajZc*|3>h&!x z52{-m+BN+DaYy8+o*5n`X8z)ov#yMaq`{x$?1A$l`Pk?3 z&R33!Iev$}Yfq<0srpW*ZtYcf7o5@eEPp}WoAA0$%h;~cf*;FtXO&7HeobclSg7Xq zwad&QugL0YklDu}r&&-cJz~>pilvD?&Wv%8{#| z91&}h;-$ChobXPL$+ZPgwdPs`|_|T@yU2YL5)*b;BKMecK8BNMDoMP}i+D z_N-FE^Pb$)-Y7O_b;(D49#Iz)koE2yQ9oKMeQEK+_nAvJOdAsoZzs#GBVUNdu43JE z{+fEspQIn}9a7CzK`r;6P)`&ny{)-hZBIC@cT}{f9l^`eU(_Z1!vivq7!ZNJ!?I<( zRy@_SS3Z5oC3dy?K#X< zeMj4G+)9tvQTDL8Ys{@Qx75pi!v6kv|HaZm=CC$oamebB&M3#uG5m_X% zN@ST7qDFIRgqzFhAkTM{3Knh_sl|V{?)B-66QVpaWNIj5(AQeGMg46^l z3Q`rMELKw&q%c-f8Kg8wZII$1)j`UG)CVaLQX!;7NR5ypAyq=kgwzQsl+{!UDHT#H zq*zF`ka8jQLJEdd3@I5>Go)xp)sV7TP2G^fSxx1T(pgRIkm4cLL&}HL4=Es0L8OF8 z4Ur-uRYb~YHFZP^X*HEZN@+EFTTP{rQd>=}kz!j-wUKfo^+pPg kR2(TeQgi(O7Tsw=Utl7i>6w?EpPifO$;->m%g%NF1yhyakpKVy literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/New_York b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/New_York new file mode 100644 index 0000000000000000000000000000000000000000..2f75480e069b60b6c58a9137c7eebd4796f74226 GIT binary patch literal 3536 zcmeI!Sx}W_9LMpa;)WucQm$lLAu8a83sO>PgnGmjT+r~zKnAt=mx@@5l_ud#S(Afp zgQ+NJDQ=jk;TkzM<%0WykET>6`Y0}>c}~ywz3nD0y6a`$^Et!dc=!AM;}TLQ^>F>; zscV13%X8Jfd~fl#{m5MvC`-5fp}tz+l4YO&q?RXNloj)S*LjoI$;$A2wQA%6lOK?+ z3VMEH3Opnbtdl%(plWh2bG+#$MfQ!leVGemFr@17u536ZLKXyRx;OQN?XeNpZyywcY2o*Ygn>_($mdA&IiTdbB#=7bOQy_ESH;Z{$eFTXIC* z*JU#8--7(j?+@S9SL)p`SMD6ue^iv2 ztH-zK%F-fpZD*OfUU)>z(js+Z(Pp_hcZsS>%aL0XW~tk;8FFX9ICVEHL8?2=)PMR% z%Do0-^}Xsb=KgQ}^yv}bEu!YeeWlHXO4au8RcW{TpbFgZvpl+N zgKD4dGLOCUiRuu4(R7?#s2>mCXPy}Rv3@dOl?m!RO$T}QO0aLd4lZ9Qov-xKT}rZ~ zYgwEM$xW5eO}$lE<`C)jNlVo|CB^i3rcvex`4m)4FfP zb<^+u4joZ?*z`Y>t0N1q$y3|k)=w`wBm=&fsH4(0$}{uls%K*t%X3LDtASzZGHBp) zYEV^yi4K{dqstbW7{6z9%%-VkaAik521wxg=IP|-eY7@k$yc~n>W&y=xG6a%=FkE*j6qh*H5C|M!1 zsuR?kx$ntaCnMGD%oLfkHBem`HU8;7i8vfMrso_7U>3{Iw{k_+_E!XApdVkne z%g5_2Uhit)d~fW0HXZ7Ya}643-;wqmZQtQ>cFSC@TFysY4K~ngpTs)mBV-GaJw!GU z*+pa4 zZ;{PKb{E-RN4vks20PjvMz$E)V`P(&T}HMU*=J;8OBau!btwef>G!yA2 z(oRR)Po$xawxdW(k)9$=MY@W#73nL|SfsN^Ymwd}%|*J4v=`|w(qKp1VWh=KkC7%L zT}IlB^ciV1(rKjCNUxD*Bi%;Y?P&XrG~Cg49BH|u?K#qPr0YoAk-j61M>>zR9_c;O ze5CtG`yFlnksH9#-T}xh;Armwa!WYcdjh#B9PM3!+!n}vf!r9#oq^mM$i0Ew9LU{)+#bmNf!rXD_6|XA5l4HE zAUBDly-SeW1i4R;8wI&jkXr@0SMdLv<=@{dzV?&}wR literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Nipigon b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Nipigon new file mode 100644 index 0000000000000000000000000000000000000000..f6a856e693420d6d989c45acff2c48b60db69186 GIT binary patch literal 2122 zcmdtie@xVM9LMo5L`4TAloTnELB$T?_+h7LRG6^q)DzOfluSPwcta@Oq1~Vib)lsH zxJJWT?OJKg+8mkLv>KCg=GMxT)%rF1)E0kK*vIG(7aP~-`T4iM`m3$)?elqjcmLc! z_j*Q~+csBu|9Gyn-*9;P?csgqPJ1Oz49F|*|EkVj4mW=KtdR>vf64_lrPJq($TiuA zl+QaTKC?$<=-ra}&1*XAR7|ct*{5f``HabaakI|Z+iI@sxnE!37BVx}mgwBD-`ub; zQ{U*%FnNW3byNC;nU$KMX8qxl**{LG{PVxb%_HYj!O_pxOP|ws5s+lYtsI)*QMl_1$ypqzm$$fRav4<0>|d7^4?`q zF_5P!V=+_J^_Q9#3Y$Auey@VXbIts!VYT4uEK@!ETU|Z=yIDB(p{ zu@19zqDU`$d9N)0s#Zm|x66w63RT0ph%^qSsRwGxW#tp&YE^!YM4Qg4=+vaF4!)&U z|2)I2DLA9ooW5k%P9N6IhepjqWBc^FzT@WM;SRmN<$&3cSfN$qUD?>*t~Qko$|JFe zYRT%B)=;@>ooJR=agK_8RwHd!O{%sd1+r!QOVvKO$aI{$q#upvo5zMmb!XGGk^RT@ z<3Vk@IuGcrxgVKr4Ly3>^bZoR9#rwM5$VqBR^7t~rRQ?9dNQ$Fp8C2*ZSRfA(-0^pPWibOD0dg?WMc-Om}B5k3_xtI(t^x^PoMA zQTvznycBmu|HTxN_UXE~s}`9AG7DrH$UKmVIPFaMA*O=N1(}S~&IXwdG9P3@$c&IF zA#*||h0F?>7BVknV#v&psUdSiCWp+EUypf3`Ge@S5%pI9LGJB_;J~DqK0Z0ar z6d*Z3l7M6ZNduAxBoRm^kW?VKaN1-b*>Ku)Ao+0GgdiC~Qi9|JNeYq`BrQl@ki;OF zK~jU{#%Ys-WXEaKgXG6)6NF?4NfDAGBuPk?kTfBALK1~!3P}}`Dl?TA^CIK1R@!9+7u!=M3RVP5lJJG gMKgp!e)-z};S{j)bs0vh+Mk*@@eShD0|-JD?=?ku03 zjJfW3&I6BP%iH zE0L7)rj;}`sglEAvXaNYR4G^5tkjYBRNC1WWcuJim2tF1F6@0yiC1iy*(60)N0!Vk z*(MfMMa!I|29cZfi(Kq{Smeb|xAHFCEAl6Qw(k2dT-<;DbE`llst1NoSP$+FRZI5o zw_L4PRN?lwWl_b)>Y;{xvUuTJYH9H%x%9^iq9lF5Dmi;fltyl}N{DtZDo@Tu>G|dnu{yzTt^OcI zR8L*7YK9`jW81WiFO*>>mq*9F~O|tRo z9@UgoDw{s(RL#y**?ice)?JE}Pw(vz&-hZT^cb0gz)n|3Y zOp4BmBUYz>rs~Q&BfG|bQ{Ayjc8{D_8?Nn<8wcN2o6dF0&AqRwp5q?byQWWV8OW0X zfztwlf^YVOggS5G<8T~naX9?`M%xkO_jl9St1wK$kB@gR*5VVStqhkWTnVbk+mB2Vv*Gv^>UH*A`3=V zj4T;hGqPx8)yT4ubt4N$R*ozkSv#_LWcA4Mk@XvO0gSo=NC}V{AVol`fRq8L15ya2 z5=beKS|G(hs)3ZlsOy0g#HcHRlmw{>QWT^rNLi4&Aca9HgOmoT4N@GWI!Jkt`XB`| z>IxwxLTZE*38@lNCZtYCp^!=;r9x_j6bq>qQZA#e7g8{zt{74>qplfJG^A=s*^s&+ zg+nTbln$vKQaq%3NcoJqen!N6c`+Gv&R`0dJCVwlie`!KZg6Ca^JXxlk|Mzo>rcnk(D9R M$}=-FGBZT@pJb_W#sB~S literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Noronha b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Noronha new file mode 100644 index 0000000000000000000000000000000000000000..f140726f2a6945357b325f0bb452dce7557bbff7 GIT binary patch literal 716 zcmb8sJugF10Eh8=FG5N7hdF}`Ba&Jz4!x`?)^N-K1EQg&RpMHB=XHU!a!O~)?Eq0Om3afOv zS7!3d;$}q4o6@t)wqNROdR*jcjWWM`Aqu%IS&WCo>rPp}HB5>3qZ#?pDpX~u#@y~XjxpsIx89ihqSG`n8FvN-hwKSE@qZMt zA2n1#%J|wkNFk&WQp(rXLW=p?YDhVx9#Rmgh?GQXB1Ms^NLgQ77b)y(D literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/North_Dakota/Beulah b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/North_Dakota/Beulah new file mode 100644 index 0000000000000000000000000000000000000000..246345dde7cada7b0de81cc23fabc66b60d51e79 GIT binary patch literal 2380 zcmd_qZ%oxy9LMo<5xsH)JDC^)LTO1LAfOnK6a_?(1mP7>2%|v6{_yh;B!+lOg7Khv zmWxp)L7~-}33GEeHqy-2R_4Oyv^Gjx|19dR++u;;&ig#=QLSfv?|%37yZ8C$?Ok8L zF-83C+~yx1uFE{UM=JBxb0|ZC>K)~ z%H*|=GQ{*yy7a#lDMWXKbahONfTyp?8C$|tVD$n$vv^9)%9_;fq%q}wAyo&-6DsKN zp!E1&SJ!>rr-LuPCqho_(Q}UXiR<6)mGb31;)c%WH`X%RF1m5%jn6|rL{b=(!NSUU2Cjz8z9gr4Vh;?WYdthG)j z?OUOe>)K?>w)tv#-bT5iWJ0CJ+%H$Ae4*}e$H}yaKSbL1!7_dFqR9C07kTHG!(!Ed zM`sQn5O?kUS>L^Xx5#SvRNvFKU)@_YptEasshnjm>fD?SD);x(GB2S;)U3 zTxYC_soZC<8RJHAQP#Y8)GX9`rk+vU_Bj#rz%`^I^^D_=Zu*6(|=X{mVX$R%Gx zX^3$4p7L!;{Z(vjIOy9J`kB~X)ZyDcJ+7M4`kkh+vua0JyR&0tP&H3%a(4FYQ_ox| za9Ua$)vlpk9Py4`?ylz6aZH z>GvNWaLwaggsm?0iozW8tT9iSd5XOv+x*Tpzd4uv2Jb&uo8MejVDJF4I%Ijs`j7=8 zD@2xPHETo`iL4S?CbCYn3+08Ca%QQ(S~(VrtQJ`=vR-7t$cn9I$;g_mX3@y1k!2(6 z=2$qga*m}VYv))zvU-l?BkSiV08#;t5+F4|ihxwXYRZ7r0VxDh38WNAEs$a$)j-OD z)PtiSNJThGg4D!nih@+dYRZDtg`+S?WsuS!wLyx5R0k;!QXiy1NQICRAvHpZgjC6D z%7oO3qfkhtI7)@oilbOawK&R!)C(yXQZb}tNX@LKXh_wprff*vtfp{C~W3& literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/North_Dakota/Center b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/North_Dakota/Center new file mode 100644 index 0000000000000000000000000000000000000000..1fa0703778034551487b7b55d80d41ad220f2102 GIT binary patch literal 2380 zcmd_qUrd#C9LMqBLG%EDJ((235lRa}0Rh8+q%0r?c?9*yA0Y~Z5X<=a2NX5>l?>*E z`D`x2{t!5FwK8OGhI1p#YOQoGY|hq3YRego^{l*bf#>P>{@r%vMOS^#p7VOnx&OQa z>ziK46#qJ}{)dO_)(`JKrN4TQwN3}*9O&s zb*{B=(^>IA))ni)l21iq^cgE@ku8#fKikO>TSfBtX?xK`Kr9}4Q>9$kAX9sHsI=n+ za!GrYN8&({e+u^(Cmlx{ER} z?NQ}f!?OI>cu^VugH!pH5LLkw&ia9?qI$f?spblzG zhSUM|d}Fn&kLpwnMR~Gea-(WYN|24`N>r2ABb$z?kuP=^i;!|ks;M~bEDkVdrg?hDTwhZy;&x}w5ueb4;HS<6FxNd)#5U%@ipC{CH-?K%Sd5<*T zmg}B8=9$a8h*{|m2!DZo*6OE1KV<=tuYc$3-<-#ML*O>n=IW~rjXZ{|4p|T>M|g8Knj6W0x1Pj3#1rGHIQ;3 z_24K7QW1`lAT=@Sq99c<>arkp;V2AJ8Kg8wZII$1)j`U`Q6Hp092G)J#8D%pNE}r% z>N0WE2`LmurI1n~wL*%8R0}B=QZJ-nNX3wnAvH7VqH$EssLRGtH=`~bN9B;xA+LMalH0m;P)X}I5$x%t9lpM80ipfz;q?{b}L<)*j6e%fE zQ>3U!RgJo=NL`J(ut;T%y0l1bk>YYx7b!1CeUSolR2V5SM~#spb5z-=%Z$|7s0)o$ v+Nev7)EX%^Qf;K%NWGDQ>3JbO85tC(BY#_DMO_Wi(IYdh`DcF8G5y!9*q(Fx_NMvrj^|J41?wES zaPz0)&h#ttuEKZ3qVTgaF2NFUQ(sx}zHK6Y^o*5oEg%*Ty>2C5P&%pWMJxGaiC)rD zXQdokrc>)$W!m<+dTIVfxvXSdr^h`km#2N9@9`$cjHo|E#`mEzbKnQtd}xeMzsnxLW!5H0#x;QdCi8g)Z)xt=6o_)+LSC)!OJ-9awi!1tvYZ zG<`soej6joV?MXbKNMp9)G2#I?^RJT+G$s|ejpwl+GSVO921XqRoajH-`Cac&FYDy zUj1ZUg{lc_)3y28s&;IXu8WIRb>|9oz1O4ak0L?ITpLgsnO^d}dC$88H zrC~xHJZo=F|5a>jc*EWv{+ZZO)Nb#X8q-Y~y{c*SyxtknrgjeX>*n!IYFF1Gz57z3 z+SAggpBqS2EmdWDZ|5u((7ko|G~#`y2pfYoVU9@!H#pp5;NWRQ1@Fp z&gnkS9NtC5Dt|!ubIr5XJZ0u74u~A{JIDOyJnlCH{=wQDb5+5ieaPyNw)mMHY;#*wrin z!BG&TA{-?_YT{~&f>g!Tlm)2^M`4i4Af-WSgA@m;4pJVZK1hL(3LzyzYJ?OCsgkQH z6H+IRLLrsnC>2sGj$$Fz;wTqVFQi~d#gLLAHFGsZ0 zqMM{d) z6e%iFRaaA1q^_=}ut;THO=*$ZBE{vXE>d2O`XUA9s4!Aujv6CH=BTo(DKk=MS5s)D v(ype|NUf1#Bh^OAjno?{IR3vX?lWOuZUUd^Uz(hjoRa8IO-)WsPVxN((J^&k literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Nuuk b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Nuuk new file mode 100644 index 0000000000000000000000000000000000000000..0160308bf63690a6dee51c3c8849f494a47186c2 GIT binary patch literal 1878 zcmdVaYfQ~?9LMpKG}g?%E(w*86i#(IN4ZrlsfLd0K`zN92??PUaTqhR*1opJ48yc$ zMmz`)a+&KGVzXv$W172}4Rc%j`@R3>kw>1`{M-4z&U$vX@B8DMxwydN_~QvO|KY<^ zYCe2#w`XIaqm#E{VrS2H4T*ZIT{=C|(7;<7`th80Z9cBu?jF$Ymv(5_nX?jpv`!-S z?w1~wDv=eNq-Rly^qRdudT0A2DkVeuIFlthJVyGq>nbrp=^FESpvFFr)_zT0wEvYh zI-vfmI%{5QT=fHu-*Q6}R-aK<{xMC=y)W*Pdhw(-$iT@vB`IQ`B)iKbxy3Jo!>V=g z<9RaVN2v}yn=Zp1=4eW7o~AYo)wHc6b@-le9Z?XaBex8ZQJF!So*yQoqhD%9dW&QR zUDvFrCzAF4g^UTjAY&S@$=K#YGOq53WZyim-l|F&fApYEC@z+Xm78_a^zAyiXrWFS zRHVM_ES(xUUZ*+x>9j8{%?ZhroO>O0#^+d>dFqqSY6_Ow2RcY@{X3cC|0sFYjWRc{ zN#?D8qw|NKmIb*tH9vBBBE7v8DeY*7UEG@daQkHE? z)#BPIvb-=-S8Pp^m6KAWq##sQCH9cj8Q)}02Zxj)I2w zvaYc~D|TPh^>zDnLwSw*tNiM>EGwXOtH6K$*UGYPZ*({;tLcuT_3wA{(}1>?#XH;U zbHuqk=HoV}7ZC94<@<|kH9ySaVtKe)9q&TEHq&%cPq(G!Xq(r1fq)1y+B~qrXsS_y_sT3&{ zsTC;}sTL_0sTV02sTe64sTnES)>Ms@ZENaA3P&nON=Ir(ibtwP%17!)764fRWC@Tp zKo$X61!Ng)%{m|pfvg0w6v$d2i-D{LvK+{IAPa)52(l!|njnjUtO~L$wq{+Bg|Rg& zgDefQHpt>2tAi{LvOdTH+5T566r5s~Da~Wv?lh;@6Q30CN{Dkiy@{@0UlW6W0s=0- ADF6Tf literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Ojinaga b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Ojinaga new file mode 100644 index 0000000000000000000000000000000000000000..fc4a03e36931bbca9b00e0344d3659e4af700be5 GIT binary patch literal 1484 zcmd7RT}V@59LMp;vJ^2rL_wfLP#}aZH}f^KOlz4gOV?Uvx=J0((v>o-e0d;Ay7DPR z0#gc-E+Q0>WdwF*cZGQo7Gy#8LKIjK38ts#d%6#TF8Uu1pTl)#6RM4WMCX+l)oo->Zl+!2+XQ^v9JE264q z)Tkb)7e3ddI^NYKPo#{flm39LS=FOzoyD^DOGx>XQl$ThR|TTtW#C?pI`#gmtnWQ+ zoSuvmXF}OV!_b^)^duO;?kRCLebG4AI4YXfzBZamdqwlof(m7g$k5Cy)v~Tfwv0bg z=jTK6!oV$caoQ_e+b^lMu^ic6RjWF#C(4LrJj?YH8S!r)(;P??!ZiDph&0W+H$}8* zJ{XROi%Lv=l!DZP6oXWQlw+yup*;%Xs0b;Eqb8&% zq$;E=q%KQc7*ZKWX-I7x#Ua&kl!w&EQ6N$wQX*0#QY2C(QYKQTr7jey)KZs<)QS{~ zREw00)Qc31RE(62)Ql93RBfrtM(VcIg(H<)>e7+gIf_TB=O`bkpJM^Y3OJU4tN~dB zvI=Aw$T}?bLXeeM>ZKrSvDAw}R)Z`DSr5m8kQH$(30V`zqL5W_EDKqerCu1aGE2QQ vWNnsuamebBO`;*{&u4qKPq^3uu8U7XX0%EG7T| literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Pangnirtung b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Pangnirtung new file mode 100644 index 0000000000000000000000000000000000000000..3e4e0db6ae0a5a704f8cdd549071cc5b7124e2fd GIT binary patch literal 2094 zcmeIyaZFWJ0LStBf|Qu7oKYx92^pa9-UEAuh6Mq=J?+U2AEsb>H0TYXIGHjqLt8q_ zfBd5cZZ(#}Kb);u8LrmGpfzi?)>WdlYH+H>A8oWlwB<72?R-zQ+S=OM`m_6X?&t3Q z^R~D5`zD&(AFgozb}cY(I9&V8;kjgJqVeE|&wMQ|7XBzNiW%>xP`LV1am(nU_SNe8 zEqPvcELYu7neuKdzM^spa^1xlQ))@zio0a?7m@qbl$&>9QY;-CbMs#t6*rw2a&O-I zgIe~~VYi^^6IHnDgm+8ioLau_Y46tTRT(q&*g~nWKvh`{#mSw#`JBCUy4Z4N_~69h`3{ZmafeGTvbk|oYj{< z&}+_L(06_@sH)CtgovT^>e3m zv~0VIjvv*rtQr+N+o{*h6sq+vJ}dA0v|7aXcgPLr3Pi)!xODr|#r;(w*|>LFY|L9I z6HV`n#N|1;DRNqD`u1AAIsd%c{O+vYk~*cDPmb%B$)jrPp<(^tNT=G?I-s`?Zcrlr zhTL(aL+mW;mk%Z5qBW~WwnamtZKhc!ix!IHM^&4_dMu*!?ydp#c=kJbPeZTTlbVv1T$|v8<7k%4e^1yLNqy?@@OHaG{A3yWv|NhCi=8vcUK>luysXMyj3qXO62H`%-iEcX4kUUioG{>v{p%Xkhf|Lgm*aM-DNAmP-w=4>>lu8v#6 zspps%wH)*8I05^Wzuo?PPW+2m_~v37$UKmVSj|k3sUUOVyO<0z8)Q1je2@ttGeV|> z%*kpdh0F?>7BVknV#v&psUdSiCWp)pnI1AfWP->Ht!9eI9Ia-O$Sjd*BJ)Hhip&(5 zDl%7OvdCwdyR+h$B1uKH# N(s+4!usj&f{1s}GV)+07 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Paramaribo b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Paramaribo new file mode 100644 index 0000000000000000000000000000000000000000..bc8a6edf1331b6912c26e81078b00c8e5d87ffdf GIT binary patch literal 262 zcmWHE%1kq2zzbM`vLGxpk+pBfJ}vJfmy&e0NbfV;QUCw{e?}%|7MB12&v-B}07)AL z5Zebto;$(7@&EtT3k-Zdz99?&K&)$EY-|7`8A3>~6llkPki{SxWI2ciIRNBjkRw2J RJy47+hj7^donvRr1pph+PYM74 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Phoenix b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Phoenix new file mode 100644 index 0000000000000000000000000000000000000000..ac6bb0c78291f1e341f42c34639458fb385bf8ed GIT binary patch literal 328 zcmWHE%1kq2zzev6vMfL>&;TUnEwh?1e>Z!>f;O263unD-INixJ;k@{Lne+Wm*Ia0n zlKJ(cRN(iE2nHrbAY=wYMyCJ&r@dof`2TL6| z7(z&J%6}k;W8v8VqCrjq(I97mXpqxDG{|`%8stO}4RR)!209f)gPaSZK~4tIWICG* I=zeo90HHg7VgLXD literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Port-au-Prince b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Port-au-Prince new file mode 100644 index 0000000000000000000000000000000000000000..287f1439266639f9564149d6e162feaba3fbed86 GIT binary patch literal 1434 zcmd7ROGs2v0Eh8AWkP}r7lNf}Z_#uf+EkRmP-9XwdDBsHG&_|xjG7)F+1SGh3ZYF% zr7l83o-{pf>KhmpQ-7T$s&#|6nL`sKEH= zmH6}9N-fVRr}c5Ax%K;^^ljsd9iM%RXFi$f?Z$Xp=In^IceF{>*7aNa26rhDxF`4b zG>QZHeez&9AnKB%vcAM6>OY2LI6FmzUlhqm;;e|=%9IV$uSH|uMyu)Nj5^$zVKom; zs+NkFB`=JqRJzJ@v`clw-pS4leWG(}Oh(h9B073ac6|wnV}s}9@i#@{ zM0Z%8e2^)+Yq!f&1BP(SpZDudSn&7#`|Vtw;_*jr!_cSSNQlRuJ$5XN#~F$uf~R_yqz%BC*w>Ah969AkiSvsnb!bRzNN`AWNO(wmNPtL$NQg*`NRUXBNSH{RNT5ihNT^7x zNU%t>NVrJ6wmM)WVkBfFW+Z4NY9wqVZX|FdawK#lb|iQtdL(=#ep@{NWCXT)2*?<0 z^&pT@Aj3e$feZv02{II9EXZJx(ICS?#$&4ogp9~m4+$BQtsWFIDr8v5xR8M%BSVIU c|K-?{^zOWRe|dpIXMxk57w~wT9;Z9$2O7SHqW}N^ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Port_of_Spain b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Port_of_Spain new file mode 100644 index 0000000000000000000000000000000000000000..697cf5bcf7f151ffc1c1fc4247e4e9c7e3ff01a3 GIT binary patch literal 148 zcmWHE%1kq2zzZ0GvP?kCG1=UB4deg+$3hqw{{KIIfPuxwH-y14ID{dD1VjD<0ZxOs JfTo#n0RWR(9N_=} literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Porto_Acre b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Porto_Acre new file mode 100644 index 0000000000000000000000000000000000000000..a374cb43d98bfbd06c82ca306a74f96993fd5657 GIT binary patch literal 628 zcmb8sJxIeq7=YnRY(b*vB7%roy9@pmL_{)nP`pYead0ZQxd`GC9dvQ&B#Mh`J2^?~ zbX(CWb7`xBn?(@+N@_Xp4bFk)INpPUgzt&BwVR(8u}{j}Ce0o^FP#?3!+BBeZmY_> zly}X7TU&aNwbrPtk9C83W#4Ud=4A6KbRQeH^2yt9KQG3EujHZot&Zf+(6Vahva(%$ zc0=ba2#X`C(@M+Vvr9E`Uy_ptA8P747o-+m)%5X+Ob@)M?2a!t{e<$h*0vS1`fOWk zwI_tuRb?f#uH1-z&f@>Pw(g0U*+sK6!s}sb^I^^8l%Fkd=ef3Z2=K7p! zR_43CAdLT`ZE=U`s w57G$f6l+@{y<%-Mq#M$Xzehi$A<_|PiS$I8V$QysP}On&=<3bex(iwF7t{3qt^fc4 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Puerto_Rico b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Puerto_Rico new file mode 100644 index 0000000000000000000000000000000000000000..a662a57137b69e8ba445e899566222cdd422a764 GIT binary patch literal 246 zcmWHE%1kq2zyK^j5fBCe7+atL$T|JZ=)fiAF9nwp-dm5HWJGNmqij1 zNs{<&F56`JB~6%|^WZcqOKFH?A@|GQ@BJ^Hc;ta6&guVuo%U??eSZp;l&ng&{`f?g zzwq$cVjg~XuQacHB6r5o;-~%-}wI-*dk-90;0?D2HAB@ zt%%(f(s6kQMYmOTI(|f%=sx3!?h#k5dJfyBd%oGMdWA35y@HEX?`KnVLQR_L^PpJv zJ&>UKUCfgGOTVcB`x0ehg+~nB;Fg2Zzly>0+U1bmZDMGerH6jLA%?yEq=&bj6eB*~ z(j#v+s!=UxbkeC4YII$d9SbzpNTpd_W!k+6k^Uk{PdfKfOuiGNGxju#%(ERjYwZOwr7Eap{#`Y7%_W`fJFlkY z9n#a|_o|%nwKC^jsmhHzD04g9BJWL^oOykNm=!FNv+FH2r)H9z+vFAV{5$mgV;7V^ zyHzhJ->()XeUSOZn^Zy6Ls^*mOcY*xrHiKRQWdssyWB31E6n}t>v5ZJr|^IJ^?Gf) zai?XO_cbfbwi}ccVcWO070uga-l2di_SauR0V{US+yX1#JY&QJ^Q4%^XHL<4T&~|1 z{KX-g|JyFv-R~Q6(8y6Ehm9OJa^T33BZrP0J96;I(IbbC9KWLp0Eqwz0g1uU1c5~1 zXu?3^KqnA>5D6a>3J?nt3=$0z4iXO%5E7B22?>b_2?~h{2@8n}2@Hu02@Q!22@Z)4 z2@i=62@r|U(S(S^=xBmOqC~<(;zR;PB1J+)Vnu>QqD8_*;za^RB6c((BQYaEBT*w^ zBXJ{vBatJaBe5gFBhe$_Bk>~xfQ$e#1jra5gMf^JqZtNd9FT!PMgkcMWGs-uKt=-@ z4rDx#0YOFt84_en9L=C0qvB|W1sNA)V33hPh6WiMWN?ttL52qzA7p@#5kiIt86#wn Y9L*>p!-N&)M73kLj7&m*mXG2{wMlfKEtyLlR7n zCfKLsnsXgG@tYGi@pQ9JI(5iSe&vu!I@)BfeWJ-sX^GhD8X{(Db)iizD>T}~Jb zn+k@^&E?1Joa8r6=G=WYb8Jwv5;ohc;a;74vBb{ne_De>nmievKn%gl) z^6H}|e`mZbD6KNLuD&P*nM=&V{4ZqD_%u^E{byTvVazPP@|j)o$vJb|x3Afy$49m3 zodfpvgTs2qvtsXTJgs-NJt=oryr9eK8l`xCo0b%>l9E5(GNswuZRyZaQw6{f9oXnMq+8SMXc#5oATBNI+FUgv;3=OY6E8)?AMhf~Q@>9C0 zO8?4MeQZqi*h#yt`v+4qe8kqaePr(K-)+~|y=3m|thF0LALz#R7TJ{Dt()s>q%Lv4 zZYeF2EhAgCJ~Kn=zbw~=@d0UgJ*e9*{3s6`E;A1f#O(IyJoC`;^R_XPXyo9B_ThqG z&5p(w?at&u(^S!Jo5n^oTG%bo;Q`&1vR`)f_h`%It+KnbL-%}LE_+*>_0hhdw63qz z$Bs;rxIkRss&U-^=@W~+TxCowcIrf6TrBqL^CsTEPxN=v@=(|;D|Tm%JC*LN47lH#n20)7(+9NY7E^V$}zO_bm~F$gD42m5TYVPM~IRPEg@<$^n@tN&=jI7Lsw6y zEJRyRr!GWah{6z!Au2<3hA0iu8lpBsZ;0Xy%^|8YbcZO<(B9Lj&(I%|07eENDS+ev zk_1Q=AZdW)0g?zvCLpPRgOLqSmkvfgJY7N<8G)n(k`qW$AX$N=1(Fv?Vj!7; zqy~~3PnR4>c065r82RyZ31Vajk|IWqAW33m36ds8o*;>WWD1fhNUk8sf@I6nr3;cT zPnR%A#ynlhAUT61jgd7-+8B9*B#x0eNa`55gCviUJx`ZDNd7!s0wEdnbSZ@75Rybl m79nYb>Hf~)63SJ7Z-K~8>7ZZMRWmy?&1oA5XN!8Dlw literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Rankin_Inlet b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Rankin_Inlet new file mode 100644 index 0000000000000000000000000000000000000000..3a70587472c633aaa178c7f979b8b3884d604372 GIT binary patch literal 1892 zcmdUveN5DK9LGOLPK}M6DT+vtkAxn_9fqC{q{T4?ilm$bLS~90n)31K5FhaC#`GV{ zKb%j~;lt2>s+nV=u0@umTdO%nb8QvVTGrf{U#%^tjPv{Y`M=qpzHfK0?e2E>&*$}u zF0NmhD^Fdc`*fgtCjYs2o&1|KZ|Q^A8gCA(uaMzYVVhhWmJ!oa?Z~WDNf|p$M-A?i z)Pzx*dOyXCzV%4cx*nQWzWP$dqp8<|-51KT$(^6C zZNEu%&tY5B@{PRPxz#SIJtOb6*4U+`Uz_*$H0iSJHnY60T5FSbn-xX*x}tZLsmsjJ zx*tkR{UD##f9f}@Z~v}q4i?J?*W-3=Y_hC7d&@RdB#G|3V%O*0l?@H2?Z)IT*;Ka2 zZtCwfv2dHldaj!-DZ6z`=Q-2#V3lrd-EX%2RHECPH=7+7{o1_b9kcWBOPb(Ic;Q(e z1D^St|M`ng4lf?RcG))|9{>1+ycmyP`plQas|;x5Erh{F(% zAudCFhByuJ8sfG`=QqT0kIr+3>mHr&4Cf)7e_ zgh$s2NGm+LUO<}R(RBmT4oE*34S{ro(Go~c7)^n6h0zvBUl@(?=sE*wjYroTNOL^8 s?m*fD=?|nqkPbmw1nCic9-EZt0yWhI%3nGqkQ)g4OGBYRC=g713}O-J3jhEB literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Recife b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Recife new file mode 100644 index 0000000000000000000000000000000000000000..d7abb168a7434579852b7533fe062fed9297ec2b GIT binary patch literal 716 zcmb8sy)T170LSsC^%5z;Vld!nBnFa8OG-3iBw>(rz+e*6iNRnIF_PUH{KC%F^0A5;gMUCATqHt^7hF5K z5s4sImBW-o-ctz1OIfDJyk9wlE5VNMb9AR0SH8o0K8Ime^L)c~(HBK>;#@M{a5=^1 z@}BkTp#6HRuUB^_((Lz*Rqls^2hPW`Lbp%db>g{K-MAZa5?2bW#P?n2({6_KIet0v zwK?4#sNZr1Yc}1X`|Xk8!U=ceX0J1vy6h7SJ!;nJl3)J^^zSb%GB@9?|GbIW^Zl)Qq0P3PSX3`Y zpWA<5KGsVQOYP-n`FiEfEqk^6ky^_rk@eeoYW-iXY^}O#duCF0hLh?-;M7k_>ZxBJ z{rIBibu5c`-rKG~s(IIv?!Slpr{XD@6_sJBEH$^*+^6PNho!{4a{|ZD@EQJm&m00E z5s(l_3?v8=1qp-1@il>vNWLZ%5(^22L_@+M@sNN>L?k2<6A9{Tq9S3DxJY1M6B!AO z#72T6(UI^-d}IK=W(3F(kTD>GKt_QK0~rT05M(6CP>``8gF!}v3O6*LRG7d!-P)%6Mh literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Resolute b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Resolute new file mode 100644 index 0000000000000000000000000000000000000000..0a73b753ba597f89cd57cc3875e7869dc133778c GIT binary patch literal 1892 zcmdUvT};(=9EZP$TpAm-OcIeGEk*QjI0r+ICY5p+gG78eA_%^u7-AY<-wvWiKQ^XU z<%P>^I!uS&lvBrin~Tg+H>Yz9b#5Bdn$Eege!XnDU>twX-y5!+UiM*!=j@z6y%=gL#p;J$s)y^^o@Hk*HQW-fg+uHnvWb>%XwGHjEJ!}9u+R69H?RZ>Pz))7Pc zBsF1#rv8;;M&9k!w9fy`8$bQ3>BnxHjQv0Ao3U49RP%lvJ^xR6Yt;|-?Yu4-Q?k#F zO+GG}fUXuTYiy69h>dqnnSXrwc0K%J!d}J-l)s6+syLXDy>P{W>ysC>x!P0rZzJ} zYp;};y1_oJJM1^B?*Fcz>?)SkSL1d~Y=V4xrS)fW{GZX+GsvI<=3Xg3(V)cU)BU)!VAy( zGibn*1K&UE-w$~1$>GK07ti_z#pB<7D=)?4r;qxQ_${wK`6N3Sl!8bkDh2c0%dyZg z`W$x~cjI;;_Y1jU{yBHdxMj#aGj1Ak*NoeS+&AOKJ-R!G+&bjmAvX`Xd&uoW?w{cR z!~=#45FZ#$K)hhM;nDd4am1tZ1mX(B7l<8SIzJhXdUT#LT=nRDWjG7*7UC|% zUx>pHk0CBYe1L68nXS_J74{697+(FJOf3zWZfVjwpV^p}Q0flwfr_!wfe>F)pl literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Rio_Branco b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Rio_Branco new file mode 100644 index 0000000000000000000000000000000000000000..a374cb43d98bfbd06c82ca306a74f96993fd5657 GIT binary patch literal 628 zcmb8sJxIeq7=YnRY(b*vB7%roy9@pmL_{)nP`pYead0ZQxd`GC9dvQ&B#Mh`J2^?~ zbX(CWb7`xBn?(@+N@_Xp4bFk)INpPUgzt&BwVR(8u}{j}Ce0o^FP#?3!+BBeZmY_> zly}X7TU&aNwbrPtk9C83W#4Ud=4A6KbRQeH^2yt9KQG3EujHZot&Zf+(6Vahva(%$ zc0=ba2#X`C(@M+Vvr9E`Uy_ptA8P747o-+m)%5X+Ob@)M?2a!t{e<$h*0vS1`fOWk zwI_tuRb?f#uH1-z&f@>Pw(g0U*+sK6!s}sb^I^^8lYxU^Od-M20M9|wz;Y2j|ctvm4vG7Pn$~po_cY$;4fru>xEC(%woo>Mg7s# z;win9Fak&n6DH46gd6Zt(c~ zb>BpnIz#PmPhD)@EZ^sCl}lyGaycPGM!orJZ1EN~9-pMfr_}UT z)~!{`6S8#V%3`^GUZjo+&XlO>3=@5Exx@@EGqE54E-QLw%nh$z5Z$m^-+1sNSy>XU zSJiy0;xd2IH|2k*ZjSg;$0v5G_}NL55Z0m+hCern6T8*wz8;fwu33^hj~dUZU9zV6 zag%a%qoh_H(P{N@lJ4E7Gm7U*W_*dxN*kB8q1ie+W{%1pi_+`<98>GhUe!4lK2;mu ziZr);@VdIS?GJO?i-*8W6WK-d*tp#hm1F_P`op*=)90r z$s0PT^Dixt%`crY1z*>Quc^b_(_0{gJNKKSV;Nhr-n$dtfe5^u0@fPo>BD?lX_p_NwqI9&opHBOT+LLb0G4B9OxS`jWezCL}#~oa;Q?8n%m7& zr#DG+S-pAsg+vJo4hp^|IAo5!{yV=w;7Ebv1OhLM6A}otwK&)E9<;!{m3uEO@cA8I zvEM1;c{jL0C7 zQ6j@c#)%9R8L6usDl%4AJ6L42$Z(PIA_L~j88I?sWX#B*kx?VVM#hZ{92q$>bY$$v z;E~ZI!$-!C1i;ls00{vS10)DY6p%0=aX0NT85NA)!KI zg#-(U77{KbUP!=PZN!j}x!RZ^K|`X3gbj%s5;!DsNa&E*A;CkUhlJ17#t#XgtBoKM zLRT9@B#1~9kuV~0L;{IK5(y;|OC*>`G?8#3@k9dZY9oq-)YZlm3974&DiT&Cu1H{! z$ReRdVv7V9i7paeB)&+1U2TMs5WCtKBSChxQAWay#2E=R5@{sVNUZUHAM7w&^K4u5 UBwxBG&6ASkOHK8pdQ!sv0^LWd&Hw-a literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Santarem b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Santarem new file mode 100644 index 0000000000000000000000000000000000000000..c28f36063bd264e932a1910861e884d2a1669b00 GIT binary patch literal 602 zcmb8sy-UMD0EY2v8>Pgr#l=DE$Et8x2N97|mkufj0l~>h5nOapT#ByUMbN=foo-CU zAzKj~1ks^1wToLo1wTrwocH7pD4Gy{fk49h#9Q559~Ui;jD70ZtMlk`Kj-(Xy!t;& zy7)GyuBwN!JbA6kQCd~{UV=(-Lx#-}RXvI1Q+Tdw-mH8-?g~EIw&Z89qrSRFb$xkC z)l2uX;nsr2MZ0cBz3RJA(ET^3YGChKXU^t>!EC694tCXW$D_`zZL7R7CYfk)rc%b- z`a&4J#5JuxP;_L>mhKc?C*8s;LCW9@8YIx-(g5Nk6aDPnC7BngrQ zNrU7;5+Rw8R7fr)S**>5q>Hurkc3D^ek3W8oJdk6E0Pw;izLRpeMgJPiR9lhyVExK HOxFDc#B>P9 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Santiago b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Santiago new file mode 100644 index 0000000000000000000000000000000000000000..816a0428188d99f437004312ee73c3860ee0f54f GIT binary patch literal 2529 zcmd_rZA{fw0LStF``6Q16DwjdDa7DQQf;@WRtZuwbh!8o-9po=lfs0>Q(RB`rrM}=kC6|+wXfy z%c?3et$#eB<`-U`m(0ue*xlx67fTlJ_ndbhZ2orOkhMdr@}_~Vraalb(DI>dUtn zbh+Qoc~!pStn~K8kLaFr``x`)J-Tl&!96s+S`Kah&ilpLcKzkF(`q<#l^$;FkXL=V z@><7b?r8S>4T3cVI1uRG;aVWYpw z@WU5HME{74Z1aliU+j~UwsecACx>P{$(D7Z_YTD->IelNensGc|-cUOuR1_q6Fbt&gkJ=eO##jhmF%y+@`O z6sn93RWdVgM7ZQKIX8Tfm>1bAvx0|Jwlzs+e-bKkzE9EfkNzO;JRPZXpBfT*hsSjO z)?;Epn@`J?AFG91PUwQnH`QHBpVNzCo>7JA-LmlKTD2s)Q!W_`5KG4!WzoqRakp=+ zT-Ix;8QA`MrqHHO0~YeS(ooEQumjZ>kU;Y>H(M38;c^Qwny>lM*b5+z&w ze!nBY;dBHBOnjUH&LHy!hx|uA!G3@LyOw32fqs9VvO@j-L2X5FI?Orjbwo{^{Jy-n z)LLoYIbyDPUFMxwqQhaPW*^k3}L{6+q%Ju?Q7og!OB_KIv4*)6hNWWUIUksTvj zM)r(s+ScqE**3CoWaGAG=g8KPy(62qHM>W)kM{ogLIZeA2Y?nJJwTd(bOC7t(g&mw zwx$zEE0A6w%|N<=v;*k}(h#I0NK25OAWcEKg0uzc3(^={(;1{Swx%~obCB*J?Lqp3 zGzjSs(jufsNRyB*A#FnXgfz<5bP8z|(krA{NVkx7A^k!chI9;R8PYSPX-LD%!kv<}gL^_GI($@46X{N2|Celu% zpGZTIjv_5ZdWtj^=_=Azq_0S0k&h)kv>xO|y}1Bke}|jWitTIMQ;Y=Sb6$t|M(n`i?Xn={(YUr1!R_`AGMX z_9OjA?f~Q-K<)zMK0xjS GE$lDZUi%6F literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Santo_Domingo b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Santo_Domingo new file mode 100644 index 0000000000000000000000000000000000000000..4fe36fd4c11f998ba3f626c5e23d97bd82d12791 GIT binary patch literal 458 zcmWHE%1kq2zzYO{vTQ&s-2fzZ-FHg(#o>M7*Yd*-|CfKfz~Eecg0cPb1;$_X9?S(F z0+{czc(4Xs3Siye>A`NWC4hawo)eq`(*i7i?|ERQ`7nWznTeSN4q2I5|Nq}t!N33{ z6Btj(iu}6==_zZx~4N^xBsjd@jR9zpF?tV?FW0bt4fT`t(N}#elb4QE(1Qd z_))z~{#x#K1l8P^2sz(!NyQG_kZ~8@t9Z557Vbfn zaJfNli0W5~l`HMUiPIt}>${ya+$WL~Vr263NtI$v%al7UV&kV3_NJ3AmD=-Erq%U| zbk!y|?|CR>(?z)@)~j5Hgzb(vAu>EZnGt*;GDW=19IRJaGp}t==QWW%J}I}|OjXE=i_Wt5q;=q;TvP@*FgGUQxxwT&T@>8VmqeoOE zM#+kSb)qtSN>+Bvi>ir1S$*9v4*P5En))8m=r~Sz*n)lGjx$_hS&lOq2wUtp@7`ET zOT0cSO}g}TTfYCOLO;}@45SXDE(ECrDFvy;sEa|WG3s)VdXR#Uijb0!nvkN9s*tjf zx{SIoq%xx}4XF(&j^?QjDG#X+DG;d;DG{mBsEb6ZH0m;uI*qzeq*9|U6{!^|7O55~ z7pWI17^xU38L1g58mZc-%SP%p>cWxAkZi+k@AuHkp&oV$vAuBWLr6FrG>ct_e dLzaiE4_P2K>Q)wPgJI$SSYc$2-eRsh@()nK$prua literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Scoresbysund b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Scoresbysund new file mode 100644 index 0000000000000000000000000000000000000000..e20e9e1c4272adc40c07562bb3d6767cb056b550 GIT binary patch literal 1916 zcmdVaT}ah;9LMp$Q#gNnQ{olndcD0+qjvQZqJe&*R z`~LW9wl(Ki|9H(Zf8oum!@PNxLmzo!BfV`a=jA1T5ta0$KRWW3#spu{n1>fNcJh?Y zzt*n{zB-_B=PyY7;E*I7J|YXdRT6i8EYG#J%kx_rWRb@wN$wI!b`(fTe5x#th?UgP zVojaS)3hH`G<_mkmwYozGlu_A$FW~Dv-hTE?YXSkJI<@K@ua$HZ%9u2u;dnwNZy7| zBtM}~3UWH7V8$;?<9c=J?Rr`EXNNAoP%JNgU#;$eIxQSou0?xS>54<~y0SS*SM6CQ zt4l+*xG_%Fr2MQU#WPYG`kj^~{UBviKS_D;B`F^tm6s-u%G#k5;u-r~y*=GhG5DFT zYipDB-Mh8&<^8&$wMjR=(5gO9nQn@y&?-l|Ry}rVbyTTTU!SY5Os7fB*+;s0B3!og z&ym{U-{n>RL#gW>m)Ghhq<+`0`ud7<(oj35jfn@Psc=Y}!_Mf|1l6tgKGl|)cHK7G zrElE!>6^zlYwNe$<*j{%+BUFJ-fl_MclPGX_DZ+3H^<1ku7$Fr(iM@A0cY5C{Z46Z~vQ=zshZ5(xa( zVp)N}aAKe!(h_V=?D#^D7;{Po-8^;wzD9P@Tr8BQmkm=~X!2g~;_F4+9D0j`*@ za>>XwBNvTaHFDXu=DLv!N3I;XbmZERi$|^=xqRgMkphqkkP?s@kRp&OkTQ@uY)v6Z zB}geqEl4p)HAp!~JxD=FMMz0VO-NBlRY+M#UACq$q%vDm8d4il98w)p9#S7tAW|Vx zB2pt#BvK_(CQ>I-C{n4dDHW;J))b3WiGvJA*NAPa%41hN#!TG*P!Kvn};4rD!$1wmE> zSrTMTkVQdO1z8qkU66%ARt8xbWNmEC;vlPIYnBIDA7p`$6+)H>StDeTkX5q%-!D_R d+bmX*%WXER$l=Y+%Fl9UI~`t^(|&S=KLvok!I1y} literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Shiprock b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Shiprock new file mode 100644 index 0000000000000000000000000000000000000000..5fbe26b1d93d1acb2561c390c1e097d07f1a262e GIT binary patch literal 2444 zcmdtjeN5F=9LMnkqQH%ZQ;8vb6-0*B?gOursm&?$b8b?d7UesOi|Njd(VTTGm*mXq%nh`_OY8GIv2h@FWtq%9yq zpPH0YHYBL9x|w=v#e|wxIIhF9MpXC}}?Nyq3Ob5vJb$tvNO`8x57 zNR>1kp=X`^LCrpNN#EFeTFvp#k~i%*sOGK=%6aQP6gTI7E^k@(wwNFHo=i^FA~|qD zr#Lo>l#!D<^^!~6I=EM-oo!U<-OuTaBb6$%*{ic&TBNeQtuklR47IRitz1+&rgD?- zlegu3q85jz%DluYBJbNMnLmDB6rB1=-u~%;Skmv%cMR+nOFMqlckbFQ3L8GsceU

gzP=p8ch855>q;fg!QFZ&W@w zvR~A+4$FrI+eK~tQMsmjy?EGpM%T5qsYlWe>qoslRUh4{JtbwzbJ?%G$?3{_+O2)z zvC4O#K(G7eXSKeoT0V9rMm+A%mrooV6%AF1vaw@WY{;FI8yk*_O>r0G=JGDFIWVsM zd54vMqPHC@P|dX-y?tkr3Jv-5Z%WwTuYY~@ z-y00>?i3;ze5)rU%)Dz6Vc(~8rXEg;xDrhw&L~3X?MMSE|QAVVWNFk9*BBexXi4+s5CQ?qMo>o&(q@q?+QlzF< zQ&gm?9A!o7%28OPvK*yFYRgevq`F9Xk@_M9Mk;JIB}Qs&HAP0MY&B&@>WmZ`sWeBa zky>*U8>u!&xsiHv6db9z)s!5mxz!XMsk+sa9jQA~c%<@3>5Bz0( zYMX;ubev<=mU^aJ=~`I2)|SZ#w_fI=bZeGV*Lqux8))@)K9yl(%-|NuSuMerXFHSr0@9k1I96RLP_{Kru z4D51l+8GizZ)kU>wX7Ej^(&mjO24?Jq{x|`UMP}M>q0YPlSFbvK`1#h!AbsMk)C;e zo=O>;t7o0?sM&|3^{xB9Q=+p(-qv$Ur3PloIcvTZa|^D@c}qVMX^CG+U&folH#wox zy)TON@h^48#Ws;Sd|YRpd0u4??$bF()~W^F&uaNnt;!85nb)4D@+-E<+v^fkfv;H> z=KZ3IJon1tlxd>)!hBgW@w2$&L$AE^>}R4>r|G-iIVSE7#ps25_lkR3FY2=GZ>vQ$ zAM3@<1FC$%LA|7WlUnlQIa!h2FDlNQl$G%tMdgtpx%6_QsCxN*z3kI2RlRw?zW=QT zRnxdb*X}7*%S(g$fzH{gE~QfY11{zNJyQn?&a1#T_sNyB!(!zJ8M1!zoM;$|lMjub z6ph=j$cKlA#H!{|`N&|ec(nSGZtC5y9?Krlj|X?C=6J1FR|M7S%e!^ZSE+)hJ9LXD zQ?(oj=rtGO)suVL;_1#6a;=UNt$`xh)^|m$E1V(Mw~mVT#0l9^b69kQr|Zt* z5!E^Vo9;@|s%!YH-tg;gwQ=xWz3KA~wYmFMz2#^?b+78t&-527cf=HTuXZ9DXI_jckf9-Cvzo!79UT{j$799^ z3=kP1GDKvI$RLqXBEz(raUuh?nvo(yMaGH@78xxvTx7h+fRPa+Lq^7o3>q0VGHhhr z$iR`2BSW{Ev0KgHk*^Ruf(%zE%@pB*I9Dkr*REMxu;_8UKoNWJJ`p-sl+5 nb$tJ>bC2(TZ}dNr{`2Cc-6d2!t2#d?FGpro=jP_*=1A`!V0=z$ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Barthelemy b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Barthelemy new file mode 100644 index 0000000000000000000000000000000000000000..697cf5bcf7f151ffc1c1fc4247e4e9c7e3ff01a3 GIT binary patch literal 148 zcmWHE%1kq2zzZ0GvP?kCG1=UB4deg+$3hqw{{KIIfPuxwH-y14ID{dD1VjD<0ZxOs JfTo#n0RWR(9N_=} literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Johns b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Johns new file mode 100644 index 0000000000000000000000000000000000000000..65a5b0c720dad151ffdcba3dbe91c8bd638845c6 GIT binary patch literal 3655 zcmeI!c~F#f9LMp+gDcHj5j!juuoOA8R?9L2`Du%oBL1}16dpAygY5AtBXOLLDRsuQ zV=|z!f|Lj;T{Skl>`^gCP5U`+bZv-ep}BY;${S9wkjrz@V&n5bgwR^MMy}GWhrN~q8T=CXJi%T{=?R(7`biKZ&r~8d% zEv|Lu1^1gqt?R96J$!GcYw)1IBJHpcDhebBS(ht+X4j?JF^eFFLWr`K5ro=#C;jcF|o-WQ_| z_5VqHEy9(G_(B|xZBU1gm5C#r!sLPU z?y9;w&ssg=&ZwyCyNaIrza={4jEFwfBzt|Y#8vygmREngRa{fKMPB>bTG4yn-oSN* z*~aw~D+7J*&;P3Lkmm#a#!UCebek85y%4)X z7oPPG+ffp@<;WcWtrgYg@NF6X+g28vx4)9;ACXsR-mz?~F)|~^ywgZ9QU;}(sVSX} z)YA(BX#?Z^X$K|;Mz`PL+0POn?e1WHhl02|7a`%zjkKBKx0k*mWNDGi2*y<)A zT|nA^^Z{uE(g~y$NH1)4GmviB>UJRgKpKK{1ZfG<6Qn6fSCFad z9Hcw8x;;pLkOm}Lpq1F4(T1zJfwR_`;h+G>INbmL|TaS5NRUPMWl^LACX2PokUuR z^b%<%(oLkDNI#K=+UkxXEk$~YG!^M8(pIFeNMn)CBCSPwi!>MMF4A6G-Cv}^wz|Ve zi;*59O-8zmv>E9$(rBd9NUM=vBh5y-jkFu-H_~uh-EpMlNY9a`BV9+@j`SUAJkoij z^+@lL<|Exl+Hb4-k8A*2y#tUfV5|24vI&q~fNTR~A0Qh6*$K#2K=uN%8Iaw8YzJGt zACL`Ut9JylC2aMcKsE)kE0Ar0>K%e?5nH`S zkWFH%cL}mhkbQz|6lA9$TLsxG$Yw!y3$k61{eo;5TfJkDEn}B;d)@d*Rc6BFYT;}ar(2eU89 AC;$Ke literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Kitts b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Kitts new file mode 100644 index 0000000000000000000000000000000000000000..697cf5bcf7f151ffc1c1fc4247e4e9c7e3ff01a3 GIT binary patch literal 148 zcmWHE%1kq2zzZ0GvP?kCG1=UB4deg+$3hqw{{KIIfPuxwH-y14ID{dD1VjD<0ZxOs JfTo#n0RWR(9N_=} literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Lucia b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Lucia new file mode 100644 index 0000000000000000000000000000000000000000..697cf5bcf7f151ffc1c1fc4247e4e9c7e3ff01a3 GIT binary patch literal 148 zcmWHE%1kq2zzZ0GvP?kCG1=UB4deg+$3hqw{{KIIfPuxwH-y14ID{dD1VjD<0ZxOs JfTo#n0RWR(9N_=} literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Thomas b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Thomas new file mode 100644 index 0000000000000000000000000000000000000000..697cf5bcf7f151ffc1c1fc4247e4e9c7e3ff01a3 GIT binary patch literal 148 zcmWHE%1kq2zzZ0GvP?kCG1=UB4deg+$3hqw{{KIIfPuxwH-y14ID{dD1VjD<0ZxOs JfTo#n0RWR(9N_=} literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Vincent b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Vincent new file mode 100644 index 0000000000000000000000000000000000000000..697cf5bcf7f151ffc1c1fc4247e4e9c7e3ff01a3 GIT binary patch literal 148 zcmWHE%1kq2zzZ0GvP?kCG1=UB4deg+$3hqw{{KIIfPuxwH-y14ID{dD1VjD<0ZxOs JfTo#n0RWR(9N_=} literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Swift_Current b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Swift_Current new file mode 100644 index 0000000000000000000000000000000000000000..8e9ef255eeb11515b84126d9ee5c0c6b3c72f2a0 GIT binary patch literal 560 zcmchTtxH2;6o=29*AK?PHz>Pnf?;Jz(0@Rq17TML+sa@`EoPIj_O2KNba#TXX#lUSMSY}+(~!w(sW;H($D71TY6sJU&m(9Y0B^+ zGNWokKI$VoKDZXYn6U{jG3D#}{idBe?Ta{fRr7r3&aBMEcPie7Eeo6ZQ1Tl(1)Uw8 ztx(qWCf?5u|54Lvs0yhIsSK$NsUB17Lli(XKvY0UA>oEWT literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Tegucigalpa b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Tegucigalpa new file mode 100644 index 0000000000000000000000000000000000000000..2adacb2e500e2f9621b2debc1756d308747b67f6 GIT binary patch literal 252 zcmWHE%1kq2zzf)cvdlotv&6^SMPb&R2Z}MX1C*-vJy5o(4RDF=dEj#G#04fsF#P|2 zoecxS|NlETFtYsrzj^@!hmUUvgR=_|2Zu0(kYL$=AOKkiavI1|5Dl^zM1w2`(I5wa RXpkeoG_elh0=mYG3jhxjJc9rL literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Thule b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Thule new file mode 100644 index 0000000000000000000000000000000000000000..6f802f1c2acf9cc73481ae86c9e099fcfc28cf25 GIT binary patch literal 1502 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 UBwxBG&6ASkOHK8pdQ!sv0^LWd&Hw-a literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Toronto b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Toronto new file mode 100644 index 0000000000000000000000000000000000000000..6752c5b05285678b86aea170f0921fc5f5e57738 GIT binary patch literal 3494 zcmeI!Sx}W_9LMp4A`+sAikYIhq=?EQh6_?+E`)l-1x#^!H1rH&^5lY8h%GMZ)G&<( zl@6x3Vul+gX$Wd+)08OgDL$H#3+RJ;qUZE{-`j5Tu8UsgJ)bkox&D3saS2IN!)*U} z>X`rV^4u^l-@waFg%5>%F-Ky$v zfxf-JOx(#oA@%A4QJuL<-d&I_?xkeO`xEDh2eE1LVV|+$QAmP(+;Oh@%O_Gk@f@R` zJRYrUuJ=|?&qnBHM_VfA9)IoH=u)<9r*>O%S=E}WbZzMr?&6uOGfWAOs7tbL=mFu` zx7UxyZiaWYj%{~=z z__*%p@lR)ZkT1<&e`+!k(Tihwg4GV#nF#uq<~mJTgR%m{TD}`uobb z_@g4O=AIlCo+n0K^U!-;n(IH|=Rf2Q`_zK6bkuu5So=Do-N=~adC6cou^z>uZ>YY@7 zJtMzNrNle6%q&pvhATZYC0ot%JD_LB&Qr6Umt< zeE)2uNY8M{`FmQ4j0rJv!Iw5s%k6poYP&zrum4lOb-4;w*laG>kzzM@m#c7_&C~ks zZGAQzVvn;8=x^SU=6%b&!{W?%*=%msN8EFap36KlZ>LovI;YY?F2>=oSBm_tdkRTvYK*E5;!O{c* zi3Ab~Bo;_8kZ2&`K;nS}1c?X|5+o)_P>`q~VL{@81jf=t1_=!k8zeYrMTakhhsVSR z2oMq>Bt%GzkRTyZLc)Z^2?-PuDN7S7BvweUkZ2*{LgIx442c*LG9+e5(2%GhVMF4E z1P+ND5;{v0J0y5W^pNl&@k0WLL=Xuf5}O(dL1 zJduDR5k*3Z#1siC5>+IuNL-P?B9TQxYiVMO1Q&@e5?&;}NPv+DBOyj&j072pG7@Ga z&PbpwO{9@fTbfuS!L~HfM#7E68wofPaU|qO%#olYQAfg##2pE|rHMQedP@^~B>0vl z`bhYZ_#+1Zas(iU0CEf<2LW;vAcp~R93Te*awH&!f~7eYkb}X}91Y0fU}=sAM-##_e!|ATe{f01&0NPcCmNu8r(HF)a!2+Ad$WR literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Tortola b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Tortola new file mode 100644 index 0000000000000000000000000000000000000000..697cf5bcf7f151ffc1c1fc4247e4e9c7e3ff01a3 GIT binary patch literal 148 zcmWHE%1kq2zzZ0GvP?kCG1=UB4deg+$3hqw{{KIIfPuxwH-y14ID{dD1VjD<0ZxOs JfTo#n0RWR(9N_=} literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Vancouver b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Vancouver new file mode 100644 index 0000000000000000000000000000000000000000..bb60cbced30763c08b6cf73554c8d6651ff387d0 GIT binary patch literal 2892 zcmd_rZ%oxy9LMns{^5_3Cle(?JE@7FBA_UWW*Y8_iKtvj%S61!b6&sk{JuY)g+&F) zu78{!_CH)st-XBr+hU)}gNNn4Ly_j|t*zW(dW z8Ondqtpgv%E7z_#9rRLf6}+LB?zU#Q>Ao~pddv+sJ*S3ANa7_Es@o(?eQUy9^%8z% zpXt?HExnuSRYYBd-0@kp>a%CBR&Q0PJGUC$cVmgVt7xt6mpflYW_Wb}3FFm(xN$ma zaJIQSEJ{ZQrfjyXp!mZtIYIkjoLlxW#w)>pfe&?s*IYQdS?4< z_3%42GVA0DleuZT%>Hzi$y&5t=Ilr?b0_7>Jg+j@F=^tN-(fsm10^TrgvmKSQ7;&D zRW0};M(6q))xzC={iyGNT2$7oAFJJ|@|GXfiz_#(C7C{1`r>x8Y*d{*Ubx;YkEoJ- zcdp5AFO$O9G*eh#AVnbqP0=SaWW|Mmd16PtUip2DTIF@?C#(IcI44f8E^k(A#`V%` zi;t?3$acLhYqwe#2orB=o$>nGWJ6Sy*-%?A8#~L))0Nfo%&7viskB0#JvhUZ=9S3i zUGXM3D7ag9`}{Zm0)bcGbh!e7cTG_DK%jh!E7bY!?YwGMrpGlW-QH|_AF+3i$NtJ) zt{~^}{EIpS?8%$#y@XT(DFspsq!^C28b~>idLRWsDuR>*sR>dPM_U!7EJ$6D!XTAF zN`uq}DGpK{q&!G{kOCnULP~_x2q}`ItrAiuM_VVPP)MbaQX#cMiiK1QDHl>Nq+m$J zkdh%aLyCq}4JjK^H%D7Iq;g2ksUuQI zM_Wmxlt?X+Vj|T<%8AqyDJW7=q@+kqk)k41MaqiQ6)7xISw~x1q_#+Lk?JDlMe2(b z7^yH)Vx-1Mk&!ARWk%}kXbX*0+R>I8sWnn;q}oWik$NKqM=Fk#9H}`{bfoG?*^#;< zg-0syXiJaO9w|OjeWd(I{gDMgRsdN7WDSr-Kvn@+24o!^?Lr_c;b@lvSqn$I7|3cM z%Ym#1vLMKcAWMR*39=~2svygPtc#;v7-VG}?b0A?<7gKLSsi3~ko7?p2w5RyiI6oy z771A;WSNk4LKX^HDM!0h$XYqt#X?rg(JmLVUdVzWD~2o?vS!GlA*+Tg8?tW5!XYc? zXqOIIJ4d^C$m%)Tn-T>HGQvYrE;2hx zn`onm5m-V&LAa=V(IP`42qTcnf-J??`7X3-6}0L;&ix(l%EkY)H?$l{xBc<>m@gcj zCUdyQb(+`Uy{VC#6ERvp_Zt}+p6;Bwm@qOO^Q~?AP=@@T)~*&4hQ(6E0kNj#qzrJ> ziojC449d+G!HHQiB)Ue0`h>_Z_e>SGkfGPU3s&LNK|12$4;4AOsMih6DA}GYqq-ib z=sJHH)B0M(W`2@!W%tGUz!x$;X;8$k%pNdtROHRv-8ZVU@UnjHDKd5Z)9GMgDDRSn*WbV?O$a}IZ^Jkul zf{_rtW#W$5+WS*)yM9@0Kk-KI=)SEAt0wi%=1Zz5P3z*KE>bXZ8r18-2JS#aJgQ7K}bbNNk~mdQAkxtSx8+-VMt|2 zX-I9BrZ}WJOH&?FpQR}fsSqgsS+s@sS_y_sT3&{snyaHi&SfA%0=q6GzB9S XBPAm>BSj-sBW2_NRkyE+KHK*fniI0_ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Winnipeg b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Winnipeg new file mode 100644 index 0000000000000000000000000000000000000000..ac40299f6b27043e8f2454ac594b0ec184c1a237 GIT binary patch literal 2868 zcmeH|ZA_JA9EbnMHxNb5#0UvYD~2Khis1`osbi1`>Jd@M)G)*{9^X)W!GDX1ep0i1 z8Aa--yvPWN?JTU&l{>tnyO`?;R;d^qQPIoIW# zp7&au{A+&Z35Ojthx=Y?E~TFP4W&m9rk7Rj&<_vZb&hNwsYla_-EY^n>FNG=oYS*9 zyESX)%9+VC-Lq59N^Reh?)UNg<(yQwbwS&tu3@8l-hABo6WQ*C`Yrn7t_@CoRiXa0 zZlTjqmZcZ-yiQ|LqFzcK=3Jf;u2&+1ou;Hw@^jCj?$wAexq7R&d(HfsYt=38^`=I- zQG3j7K7LGo+4!Y@~V>eavRDec_jum;E;4RCjAmxfK+weBkkJiJ7^ z9oQk=cfBJ$w!JNntXnKS3+KqAc^T4cT9O1MCrIz%k@8q%hy?c=r;q!$N=Um14Y?Jp zeHuG!X!SjP;_K@gw&#L|?>MP_3%bjbZ&hf&DZfhpdEd!X@ip>v%IES-&=(RhV1q=o zRcmCxLW!*3s{^iiWnk5N8dc-ypt7YJy?2rhE}Et>n}%v^Zh^!t>a9bPGG*wb7LAV> zA;aQ+&}aQZC85u6lF-y9!|&J0h~o`1^86tgRne-6hdz+!*4OLvrK@Fh{$YKgxKv+E z+o@x6R_WNm#X4^6L}%RX{gO0jzME9DO_BrC+~mD0B&9jled+xzI=*&-le)4{C+v%H z(z3HOeREG|;;2NOwB(L6IW%0oQ)(S=t4A~9E1irhVUihk#?AajWLn!kcY1lFWYuqV zvx|?(%T>$W895)zD`na4%+w<~tEAAGJ*Zq?&CPOh0@vuAq(o;<^IXl12zPQ%rf8m@ z$I1IFO6N6Qa$et@EN`6hx$_GK%9|Az-TaI|an>Jo7sTI`h4~-3i-M|UaaxJHxUE?W z63U%|`ct|rc#X5HYL6DS%ypKRZPFFzQk<1VOLSFblv6Zgs;=JJ&1vVcul61Oy7}|% zgRUJr{kN|NeaFK*^ZCkei1>U5c6&Pbe4lO?e|z86UVHrW`S?_?j2UarWOJsPlkPSD zZV`{iVVG^T;r24WnDbs*+}*au=Dh=m{~g4hURB#4zDW`fws(ijS2DNAE2h^-*T zf>;Y;E{MG#27_1(Vlqo(GljbQ`#}r{u^_~R z5F1(=BSNeQF(bo{5JNI7$uK3umJDMutjRDZ!=4O-GAzn4Da57>qgooPLd*)WE5xu6 z%R)>Gu`R>65bH9`%djuQzzhpBOl)av3^B5$u`3Q){*VGdDgY^grKtg<2$rS_ zj51i7Ixq?WsRX1HkXk^B0jUP09FTfI3IeGJq$HN6CXk|7nyN6$VrlBaC=8@BjM6}A z!zd1H{edq(YDqL23jklBKBHrfQI~S(>^*3TJ652Pqw-c97yhss||_q<--K0{&gV029YyCX!L9L!#rN PW1>=HW20lEV*>sFRXeOf literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Yakutat b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Yakutat new file mode 100644 index 0000000000000000000000000000000000000000..da209f9f0a07625ec83d4ec84917216347f5687f GIT binary patch literal 2305 zcmciCZA{fw0LSqQ0v8C165>IklMf(I*TYrdQk0<(ArcVRn-Ezjc88T zNJX?1>d5*O6;+n3o$?Rme6e1~Bz&P_4xf>+Ka8mxz8=+apHGSScZc{!-^$>=3zQCv@J~7gYYxLG3!aSuN>(PRp0;RDoYfcc)t|t$bE4Ye-auS*^0j z{i`Z=-X}fjbA{)^Vp%fti@5WHSb5jfr=nD6>bu`QF7DYAt(PA-Ant9ysLOV~rB>8_ zq*u1?SLI9I&=uv|RmD%|WM%%Ks62a0R>f}QA~=&5lF*fj65} zZSyW&x35&ym-_XCfeh7;5E&sdL}ZLs zGe~5VRx?awoX9|tks?Dy#)=FU87(qgWW30Lkr5+9M#hW`8W}Y*Y-HS4GjOXJIWlx) z?8xAe(Idl0#*YL5i2xD;BnC(jkSHKwu$nj^fv}oLAfZ5Ffdm7I1`-Y=9!Nlth#(; zY9fn-)@ovl1lMY!i-Z@6FA`uR!bpgb7~?-djtGyu=Ie~Qj_=hX_n4mkFI~PGW@~I& Zb%VErZs*l3b-7(Kucn~DRp64be*u!YOXvUq literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Yellowknife b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Yellowknife new file mode 100644 index 0000000000000000000000000000000000000000..e6afa390e879f97cef351e382ae62daf183e8d77 GIT binary patch literal 1966 zcmdtiZ%h<)9LMo5V5v9M-)0yJnrV7M+;N~JkeL;9Azc`rh(wqM-cBn>-OUW~*TOL# z@m)FAX0n_%AGDIxwVE5vHGEPwcW$je3s-4vmJO>-HkIr5{yptckJ|dWyO(2QJo&vp z@s{Maa{0&I>3+h8+v`63f9^HJb3={;m0Z5Y~#Qvde5`s7!wHrCyzPkpr7Hnb*n-QYs|^s0JoOl8~kg&~b^xNPIMW@%H! zIooul#56DXNt#DznoX0V(sFFvJTrD&T6@#x*^z!}Yd>u^5ABfWVi$BvU!UC?I;qbm zlD2)uLG6gv+m34~O$0+WalToTQ)k)a`_;Pr=j(RI;70Spg_-hVs>-}{Vq7|#3QX5P zT3)WWZFY8^mR)(5%@!Ui*nfKnwn&Q8wWip3VaxI(tTXO-+Q{=pp19XNbL6Qb&z(QQlSiIC$J0liKSu&c z21p7>4qlf8k_D0mk_VCqk_nOuk_(ayk_|^XNIo11AsKmHN=Qy#mlTo}M_Nc;NMcB4 zNNPxKNODMaNP0+qNPKOI|lk$UJ%7L?JVUOcgR$$Yde2g-jRzPv$G&hHa(Ww368J RaCtaV5-TeUmxUvNzX6=<+*SYp literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Casey b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Casey new file mode 100644 index 0000000000000000000000000000000000000000..cbcbe4e339d934f57725542db534641292fd077c GIT binary patch literal 384 zcmWHE%1kq2zyPd35fBCeULXdsdH%_rY4Ezmrr_Ow>Vx0PIST&HXD38(SvN#2;TMSB zDdG^*E87q|&D9_-`6xqt#R8l9|Ns9pGBGkS12G6PflLE|f(8Z_28LN17&wsGx&{Ue z+6ER3+J=T8MT`(4gaiiy?fVaMBuFR7p&%OMSP%_zFo*^@8bpH}4x&Mh2hku8fM}2> eKs3lBAR6Qu5CC}yL{r66TsA;Y+UXh^asdDb$3#&8 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Davis b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Davis new file mode 100644 index 0000000000000000000000000000000000000000..916f2c25926bf444b7c366110a29a3fafb17fbc0 GIT binary patch literal 297 zcmWHE%1kq2zyK^j5fBCe4j=}xd7jU4VEE>KU*MnnY6h=cA_m^me>wQATxH|3Pj5(I9t# mXpmb#0OTGJ4RRBR2DuAFgWLw9>w#*?aUYir(8YGT=3D^3yE`2K literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/DumontDUrville b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/DumontDUrville new file mode 100644 index 0000000000000000000000000000000000000000..a71b39c0046b02c20e17d33d333e5af0b01eced2 GIT binary patch literal 194 zcmWHE%1kq2zzbM_vP?kCab-_g!#$IPgy%L)4fX&3|7T=iWQ6JLS-`-eYhb{jZD_y{ lLV}qHLbH-)ANRONBcqDnRrq&DjPK8=Cg{)Dbmc)b&8!^Z?WHHDc)0P@x7aE)@ZWL z4i;F#aHJ(RCfQxb1~jKCU~}z)&0Bq3cQ^m2d*L&;QO|8DAktrjB5FbD9d~9oK^&Wv6WkTw5sM~TU`*;19=0MpYggC zBp$Uw?}J(sep+jO?^e-MCow58nE*B08trAw@AWwQBw zaaKMj(ki0Itzz;gd*te6tGsf-sy-UB>Y;vn^z0>Vcwv27imZ;zjzX-}NI&9)uBZco|| zw!P(RYuOsE)~Y|Wqj*d^bHCEAln=E#ZcuFzr_^@+HSHNYr1mdOPkqp;y>Hj)>46U0 z*B!9^N48twK&?HqW4(DoLc=`X(ErTi{LU^fb}3AHrQZ`F-8$d8|NAE0=hLc!GQac6 z_w&)?;QtrXnRM9ajS*%-m>FTFgqag&QkYp`riI;kabRNL%nUI#U~a(VFtY=u=h~Sc zW`eGr8DggB+Lo0+0qw9)Lt(G6AFllM5gj zm~3Fu0ptUd5FjI%l(=?sf=LRH6--(%dBG$GlNlg2nA`x#!DI(W4<56B*nJ|KTU0)Y$yDFkweNup~fiz0y3{r~^}8JU=1nnDs7SQr@G0vI@S4Gb8x4a|Vp flp%x!gMsG#2N@1B5o7^~Cdv{n8=zHox~5zJ1PSA%fg=bv;M3<`l~;Bp6&Pg?QG|tvwhyj zAMJ9$ReW=AkU!LC?{4+IxLf=he^>vZV;WF`h)Mv65!F;auiZ<3IynG({!T0$KW656~-Zu-t&CT*T2 zH}_nSuo6F+{Q96w$rzTY8{6fUSRV~9{Y0k){h+rx9Wvc(fzAjxD>Kea)0xA4GOO2H zBR+1H$UWf__0|@Nt{)@LhP4v2=Dfs~TkmS#5^lCvXHb8F5>UR8kJRXn0gB|`4b zP+gYlFRtmmx_t5l$@hL!^RExeJ>Ng41>d&IiW8=~yI+!f_tnYDmNvcbg%T-zew*H3 zo+V;d>H~R^vMMuQi(&%g!I_D=I`E7PN|efC%&c|jC|Sf>(g4LiBkP#kv`TF zDvuvZ*C$#N^vPYTq-INq);^OaPno}|m&0q+KfT_g$NZkQk?UT@Vc*hRe9v$=4A;Nd-gWDl-1kd7cN zL3)BT1?dXX7NjpoW01}utwDN&G{@HJ4$>Z^KS+a+4k0ZBCSMvi8K@GCelt@tDi_ik&YrQMS6-f73nI{R-~^;W0B4x ztwnl^G#BYE(q5#$wpN3Y4kIl_dWjO zBP~aIjx-(VI?{He??~g3&g1`~^}hTCM90PFy3<@yIZ4jB&e*7&InFp|Y|L!mKLIzD B3|asH literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Palmer b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Palmer new file mode 100644 index 0000000000000000000000000000000000000000..3dd85f84ff48fb8553b4a964659872ae1fb7d33d GIT binary patch literal 1418 zcmd7ROGs2v0Eh8=$4LiGDqN)YveI6Yb##1;=Hui8P0P%YlrV^bNH3xhrKTQc>goQF_|a7(e|BUF=TwG_ zx>lil$<3D+ihdOzxm(8%?o$fREu6T$i?Rp)smh9xwK_kEjyDWlUgIh@@9`* zkuxP$R=tzS39m&;(9$WB_r(sVmYQx1Q zy>ah8C61nuX+@y{pUjRNRzYi?3_kOTocDg6d-H?X^dwg2 zoqR6xZ;a`JrfyN#KB#5rsoH$tjxGvxsp9erx+LzjDowjBOTVx<$ z^f!x&!FpNQXQ{2dxpLd%C{b12rnh%=tLmarz2nGPRpTF*p@xI1Hs+PA%MOdWo{ze| z__%6y9LHnNUfu|=Jty*?FRz#X%Ca11KwDnN8GdQ|9OvyDdoE|ooM)cQzH9kXg|JdZ zhPeag{vCmB&wPxr_Ak;fzsMmESCa^miK|Hk$puLU$p%RW$p_tpIGBw1GNgp$gd~Mz zPSA%fg=bv;M3<`l~;Bp6&Pg?QG|tvwhyj zAMJ9$ReW=AkU!LC?{4+IxLf=he^>vZV;WF`h)Mv65!F;auiZ<3IynG({!T0$KW656~-Zu-t&CT*T2 zH}_nSuo6F+{Q96w$rzTY8{6fUSRV~9{Y0k){h+rx9Wvc(fzAjxD>Kea)0xA4GOO2H zBR+1H$UWf__0|@Nt{)@LhP4v2=Dfs~TkmS#5^lCvXHb8F5>UR8kJRXn0gB|`4b zP+gYlFRtmmx_t5l$@hL!^RExeJ>Ng41>d&IiW8=~yI+!f_tnYDmNvcbg%T-zew*H3 zo+V;d>H~R^vMMuQi(&%g!I_D=I`E7PN|efC%&c|jC|Sf>(g4LiBkP#kv`TF zDvuvZ*C$#N^vPYTq-INq);^OaPno}|m&0q+KfT_g$NZkQk?UT@Vc*hRe9v$=4A;Nd-gWDl-1kd7cN zL3)BT1?dXX7NjpoW01}utwDN&G{@HJ4$>Z^KS+a+4k0ZBCSMvi8K@GCelt@tDi_ik&YrQMS6-f73nI{R-~^;W0B4x ztwnl^G#BYE(q5#$wpN3Y4kIl_dWjO zBP~aIjx-(VI?{He??~g3&g1`~^}hTCM90PFy3<@yIZ4jB&e*7&InFp|Y|L!mKLIzD B3|asH literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Syowa b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Syowa new file mode 100644 index 0000000000000000000000000000000000000000..254af7d12f38af0abd6302a4df574e45b50d1805 GIT binary patch literal 165 zcmWHE%1kq2zzdjwvLMXyd}9Pd{r~^}85v>fwG0?obPWs`v<-|ILP#(PXvlw%X&`{x NL@pbkxpun7TmV+`7QFxf literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Troll b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Troll new file mode 100644 index 0000000000000000000000000000000000000000..5e565da2f6b138b70179cb7e72347163ab44b6ab GIT binary patch literal 1162 zcmc)IPe_w-9LMoz{(&({z6Ro9ioUZkkLh=Lj(yL5fW5L2U)-OucN2v&@+B}J$nv2JfC;8b1)Wk zR$Y1K35Tn}9PZcDtqnVMp?t0HT`vt=7PYZ{MMC*+G+g>o!b=O%l>0)OGBdJk{;up! zKal3x=Ng$9mzIZjbWb87d&jS6>w)XKFW#qZJK`E`4(tBn7H#)$)AnUoJBmWm@ot?S z{JB*+pZw6SIiDQ5T`1j;zslj%cj>v2kt02Ga&+vA9^3g;j(5*$Z^@+e)uc7%o!0)1 zs{NmD>cGmd4$dU?#D}P!yx*nq*F$pZT8$>A+T`>=iJrMyB}1*%G8`+Gvw=-=uJMsFd zvMaJJvM;hRvNN(ZvNy6hvOBUpvOm%Q(t*{qfb?KBO(0z$Z6JLhjUb&MtsuQ1%^=+% z?I8Ui4Iv#NEg?NwO;bo$NLxr>NMlH6NNY%MNOMScNP9?sNP|d+NQ+31R?{TXrPZ{F w^ocZzbc(c!^olf#bZh+&?fR-s$+fQe4%U_h{gKM@s&cm?;Ex1cdspfE4Vhy68UO$Q literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Vostok b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Vostok new file mode 100644 index 0000000000000000000000000000000000000000..728305305df3d82fca7829ff3e9581583758dbeb GIT binary patch literal 165 zcmWHE%1kq2zzdjwvLMXyGNQAg{{R2~jEpe#AqfmDx&{Ue+6HC}AtaatG~_?XG>|#C OP2{oxnro+P#svVn4Hz*1 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Arctic/Longyearbyen b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Arctic/Longyearbyen new file mode 100644 index 0000000000000000000000000000000000000000..15a34c3cedb7c9ca519c195f5ec0ce9d8d1885a5 GIT binary patch literal 2228 zcmdtiUrd#C9LMp4h!iXLF@<9RLLs4r{0IL8nH_C^m}%m*Ry9k7iT-4 zcWA|i+8p2CPPBW&hx3^G@O5K9#*!!t)WmCH>KQ8zjHx8*Ju6N5 zT&06wX;I{xTGZF0n+9Ic;?9>;*87G9ceQHCf#>Yzh6dfzy3Ll}_NXnZUuWgB>n&7P zYPb5A*z)w5wtO_pDq>4i@$qGL`^XHfcigfP10_yE9$h`i(a+$iDv7+e#+{`!nUEO+3q|Yvb*-LwEA~9>h7II*3eO| zd+L(x-W~bcxU^8=TEFhgo~BL3KkNQUJ~d{>TI0|cYMMA|O~>C+^WZ6a;FS(-?(4QK zyWg^{oqO!T=6%+(tHs7ejEjgI{|{Hxg#Z5X`C_KH|FAD1IbyueH&MQe|GfY4=CAi< z!H_RdT+S`THzM3Y_YnFQi}}r+@Zj`%WI3L0J;;KP6(LJP)`TnySrxJ@WL?O@kd+}z zL)L~Y4p|+tJY;>y0+AIWOGMU)EYj1hl3&g;k#!;qMOKO|)zhsNSuC^a9z2vFUPNvF-cJcbx^(Lq&tA`-jWPEAr2B^+M9g0g z&!4*;R<6BMzGvTOCfCA8gD*1GwOMaX#pgiH=E|Ge)#Z#Y@AKBp4`uwh5v~6;s15IL zY2)i&ZF=6NfrlYIHc+q4eU*AV{!3dzYkI=Jq$dx5)1Z4tf*U{O)bfv1>(jTX)`hQf zdTv%i(^)z5VN%*ACgkj^F*!FpBH??3(tdkfBTpXb`R-xuxN%)O8*XYe(yq~+n8y6q zBvz=?i(6so%57^rUnPl;KI#6lA<3~V>3O#(a=###UasqCu~>8+Jn;MBE-QH)Dld6a z`Ucl-W3IIDzg$ikdwut@tHPM{9dl&wdGC(P-r4_|zN={y3U}J`f<2>rjd3|g`X4IT zA6}#cQiE@y2vP+p<7n$3g^)@}DWn!s45@~cL+T*~k%~x3q$W}nsfv_E>N?uONM)q7 zqpgh;N2(*`k^0C2kQE?HK-PdP0$ByJ3}hY1LLBW%kfk`4| literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Amman b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Amman new file mode 100644 index 0000000000000000000000000000000000000000..c9e8707912d45ec0f9eaf56d46877fe9289d4a11 GIT binary patch literal 1853 zcmdVaYfQ~?9LMo~u94#SVO05u%YAKfy9+?MaW-~M5 z0kIk4fqUiwJ@B9F=K6ITv#{APHskmHV>7dvht7XHuhZG-+4ubk9?n|)xZ9W4A`jtfx$--v8csADCeRKp83#)2)%a($rhsY{hIUlGwZh8dsDmzT_4eH7!cwBlb%|q)SFS zw@6}5gCxG%r(>S1(Xltq%ea;T9e;eUBsJE{goZkqSXUvFc4o`u!dyu%|DaPcf;u&+ zP^WnUnvxu&sqWF57STh~+WKg^%PZ-vpLNEo?lQCKzGhr`Cz;znN!G!el3j66a*h}H zXT|T4K+XxB-Ft)N`gUmUm))Azvs&{Wtk*g3@-_eLLY;d(N$2gJs`HQa*MhY}biuCi zBJ(@y!rFeaC^b?F^S?^b&BNJ}ptma?Z8b;*Hkvh-4; zF57lU%NsZA^75^^qOL?&W|eEOFkM%9{aTSxER|h-TIHE8RUfmZ+8r&`cj9Dqn_Fs5 z^^)4wH?n5Ods*A;(sfmLWc~IwZRh;k6XLX=_8~mqKmYdL?zg}H{HtHSbvPo9a$M1| z&h`#R_&`VJpYME=kr{BLq|D+iz^|Onz&{-6SM%af`A?1&IauUqZO!2#$7^d27&&6( zkdb3X4jMUXf`KKq5dwKw_{pK_F2eVIXlJfgq6} zp&+p!!64Bf;UMuK0U;3~At5o@nxK%Vkg$-rkid}0kkF9Wkl>K$knoWBkN}Ygkr0s> zksxhNlt`GiCQc+!BvK?)BvvF?Bw8d~Bwi$7Bw{3FTN5)9w5^F62^)zU2^@(W2_1F$7zTe=c0P^i7Fi(TA^cu35g%~OJjSbH0}N_TY@Fh9D6U# zKjx&RVqUkrdoEkQz17>MveG*HOt;<3>-ML&bmIJk?if3xlLs#7&a*dVd(UCrwg0qq z*QRw(*FM?dY0$kj-O~FxC4H_s>3bQGogciCdaz8=Gx0+ICHvTjZQGWs#O1ck)3d1P zx!7CuqWFzJug%9iN=*#$$7ZLMTdBOZyh=TOrIvEG%z5Gd?`z9^W-O8qE>otCX^MWd31F^Gj^zL?-1+m=&28nb*-wjLeKojm(Wqj?9iskIauGfMkHA zfaHKAfn@An73aAPFHEAt@m_AxR-wA!#9bA&DWGIhxdv z+#F4ENOnkiNPb9yNQOv?NRCL7NR~*NNS;WdNTx`tNUn}1StMIWlP;1kk}#4nk}{5% R?f>JPeQhT7L?jmX{RF};8GZl& literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Aqtau b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Aqtau new file mode 100644 index 0000000000000000000000000000000000000000..e2d0f919541fc9d64f01d8c6128c7e73a94869cf GIT binary patch literal 983 zcmd7QK}ge40LSq+bvmYmCpTT%Ds$?ZuIa|CY3m{$COqN~f+)O$32CRH)FJTD2!ak# zp2UM>bchIrJXz48W9U106ZIXubm?GSWRCT|f0Y8ec%%w zmmUx4@Pj^md8|`k$%XXQOr36xmh`pI58YO~rz7548ToZ2+xLsAFIxAdhbq~WOLr662m4{a!fijrP4bo z(^t%?o1cT`)^?Z5yiKb9^?Eh%G@x!T9H{KQLv^Qc!OWG*Wlu$ARfRph)qkBezT+3Z znzN_ZD@1qL{tY6X6;(nEO5qd2QKF7#k9|J9bA0Ww@BaB@ZrBmgc&~jV?IXq42;t#y z&Jn==?lKXO5PS(SkRYx$3K9m1g9Jh%A)%01NH8QC5)O%n1VkbtA(5C!P$a6W4U5D@ z0=wGCNN6NB5*&$+gh%2d1F#52fD8c{12PC?6v!}K?KqHuxZ05*LqW!Z383H9wzzvsKPExKB$LoA#W>;I7kn_#^-zUy52xKN6`E9&K)d2Lyr z($;5Vdgakwb!G>&ZM<8rjzsiYx?ZnG%i13KsU6{O>ITB%{yCP;gQG&%;#Q&S^H=Hq z@JXVt_vFU*uJpXvl-}Zs+C}Ovj10aH>Fs?-(l1>Zdh3_Wlk+mXb|BdYKjco)=yIh}@%d|NYy9>I)Kwklf>j@? zFYrEKOk$P)C6zU`#^l5VjmZ~$^}HJUT74!bK6~}#nd3vkiT1_qGhv@eZf1Vp@ zLnE<~;GQ-*5*~?<3;-DcG6ZA{$RLnWAj3e$feZv02{IH35vj6}9 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ashgabat b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ashgabat new file mode 100644 index 0000000000000000000000000000000000000000..73891af1ee95a4d5d602967fd5a965c8a7ec1327 GIT binary patch literal 619 zcmci8J4?e*7=Ym~rq$YZaM51krCy^Jp@=OCMLLK$ROk>8#Gz9`a1|YdE^g{Sa1gqQ zLl(D!{s4z>cW`lWaZnf063^ROaBy+)gp)U%gmBK|ZSU3=<=4^wy_z=VdEhd2wszfU zl?L4te<*pINkndPiTBrwZ&&urMM|JM7QLP6-VA(yLD-`~5_4e7eNTJEDmP-;6 z@v2rtWW6Hs?!CKWnU&5rye)5flFcodSuiut55zJ?;6(g1}FJpkPoy+BGN? z7zz#rh=N3cqF_VUC literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ashkhabad b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ashkhabad new file mode 100644 index 0000000000000000000000000000000000000000..73891af1ee95a4d5d602967fd5a965c8a7ec1327 GIT binary patch literal 619 zcmci8J4?e*7=Ym~rq$YZaM51krCy^Jp@=OCMLLK$ROk>8#Gz9`a1|YdE^g{Sa1gqQ zLl(D!{s4z>cW`lWaZnf063^ROaBy+)gp)U%gmBK|ZSU3=<=4^wy_z=VdEhd2wszfU zl?L4te<*pINkndPiTBrwZ&&urMM|JM7QLP6-VA(yLD-`~5_4e7eNTJEDmP-;6 z@v2rtWW6Hs?!CKWnU&5rye)5flFcodSuiut55zJ?;6(g1}FJpkPoy+BGN? z7zz#rh=N3cqF_VUC literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Atyrau b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Atyrau new file mode 100644 index 0000000000000000000000000000000000000000..8b5153e0545f550c6f9b0da9ce134a8a7a4ebe36 GIT binary patch literal 991 zcmd7QKWGzS9Eb5YH8CM6l0llZX*AW^*u=JH(u7pgKQ6%`!b=Ghq=k2g1;t4$3M~{Q zIJwnHIutDq;*f$)Ds<>5_BXf{HG_+bL+cW1N#EzHlEKBz9GB1K0!PU6tz5r3pHY8( z1%KVmTDd;?qI*TZUJvQ6=m#ef*hoa0du!2eyY=p!WTNN&y?X3zO?qE0NPKl(PCc5D z(@R$+aeGYqW>a#e9Fw!fPU%k{$hp{e83=umq%WkCKYr@-U-!-6{by$I<7b`P+Sch; zoBG1~h8}wSR1eoy^vKLM?w7AsRNBefGiT4dJx6(z zQXXEFe~4gzdy5cA3?4!dB#NsIgTz4sA(4K#-BR+Myt0K?Z}21{n@A c9%Mksh>#&6W5Q+I;=dYHuxN)iF_a4)0w=fGaR2}S literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Baghdad b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Baghdad new file mode 100644 index 0000000000000000000000000000000000000000..f7162edf93c28193436cc379c0dfe4185e368a42 GIT binary patch literal 983 zcmchVKS-2u9EZQBUWiIXi=KZoQ#&i&8QFj%aO{-8uXUz!?TXmk0bUc0a^v5X~&{rIWzeOIpUKGhrR542_J zqquXk()xN|+n()e`;(A(cl)(tU`9F<&!wyNlXgee^k!L5dd?n7uf%mCl}ZINGXGpz z!BbpWBH{P;tw{Kt*mI2|*&=Z-kazN&=u1kcy=$GQy_tYG838~dfP}z^Ax#?uBnn0tkT@WLFd|`u0*M6@3?mvyIE;800YM^y Ygv5x65fq%TuKs&eIj)VYEfUQ+2Jt=1sQ>@~ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Bahrain b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Bahrain new file mode 100644 index 0000000000000000000000000000000000000000..63188b269d077e29f48a42a03c2a52aefdb61320 GIT binary patch literal 199 zcmWHE%1kq2zzdjxvLMW}@Y7ramaa($>i_@$&&b5Yz+eyn(rDqpz{0?wWx&AU;~T=D kZD0b##tb1O7z{M;Kge*9X&?(gG*Omt*#NDw(>3M-02;d=O#lD@ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Baku b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Baku new file mode 100644 index 0000000000000000000000000000000000000000..a0de74b958e42ade6f93ec0c4bc06ae714d5c606 GIT binary patch literal 1227 zcmdVZPe_w-7{KvoZL>KocCk5^{WDwYinTvBOKs(!q0O4Q6ry5>k_w3xb(8!-B^{)o z@DO?K5Eez9QelUVCIlTa34Ra}6xAsLE7tG()*y-w9ec*R@4I*7h3)w)bMVAaSpFEd zxx&G;nS*oBZQn%un-}HjiolKhs>=D0*YzafU9#P)d@Fh1Vk}fOcPa0mxu#c7UC`B& zXZ4!#V|wk#fL=G8)awt$^@dcPu4%5)8-r!K*8f#+DtoU3PG2_g$(`N&x-?h!Y$;d& z_+4(>;RR3l%tKG4<&H%AE=#QXsx*dAO5?ZF68Dd(_{)B2`f^y5 z2UY7>MD4n{QYD5e)b5K7vZv#-YCF0@+G`h7N83l~bWW>e%~MH!crIP`2huhFNV;E5 z$lkk?lA61(daj(8eN)%f{!>{=kDpV$gCnYMcu@6kKcX_JCUwA@Py<1~8Z8tGHv6(4 z4~O%YN6GRMhpY7GJH=1@rFN06GyJ~wA#sRwrfn{fctXmH&&4Y?bLIEXq;1 zW{xPg5t}vEsr4%J534obsK9zDE9Ne&nX+oix~-a(Q`SydJ!SnA0u%-m3KR|$5)>8` z8WbKBA`~VRDikghGFA;63LOd`3Ly$33MC3B22u>H7-(5FycmdCHOv^OQMfUXqp+jU zqwu2;q%fpVWZ+04$-t6AlYu9Ns8z$1fvQ!*m4Pe+TL!umz6^vZj2S3XI8#VdSW{?I WcvFbeQDfmhVD4@^wW36~AfDmz_sE&#dsBrE^` literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Barnaul b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Barnaul new file mode 100644 index 0000000000000000000000000000000000000000..759592a255408caf354d0c4a2e406ee5a1638181 GIT binary patch literal 1221 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Chungking b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Chungking new file mode 100644 index 0000000000000000000000000000000000000000..91f6f8bc2e234bafd484146986bdb289082c3588 GIT binary patch literal 561 zcmbu*zb^w}9LMo*sb7uZVlR)P+QDKF36WCLNNV90hMH8mol%_2lQ6N|X0Wt&|A0ig zYPz+k{ufWWnRwpMAJ9ZRm*-x?E%$l*C$;LT3_WT4b=2NzZC~|=C*8PAnz!SMZcTj$ zt?sL|$L>r!EJ$Z#%XIIr^!v`U`Pj?IXSr#5n@#x|uLk|}K=-#pGy8I==4y|zif-%k z``2;iyrCBIr}1LxMlH>RUUvCRWd{{6H&If#PQe>V40%K@diI|riW5nZK+9zLz?b5# zy+^+If0*`TPqbFdBNLIC$W&ym(@sWaJMDC2K9T^*fTTcjAW4ucNE)Zj!x|DHnUGXS cE+iR}4M~UOLlQb|MkJ;4e>qdO>B@TQ7g9&Lh5!Hn literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Colombo b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Colombo new file mode 100644 index 0000000000000000000000000000000000000000..62c64d85dfbdc41ae8e78bc8304ceb35b16b4255 GIT binary patch literal 372 zcmWHE%1kq2zzaBmvK&Ax(Eudc=kAp`9VMf2W~%mrOQj7KhRYZkd#ogVz%V76u022#^sW35NQNXZ07XEuKE5Fg zzCf&PU}|gtB+Wn=$O<9Bfk6BJhi#jw0-`|<1<@eKf@qL~K{UwGAa{Wr4x&Mh2hku8 XfarRl8mfDO%LeQ%J6%&NV*@S#78_5_ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Dacca b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Dacca new file mode 100644 index 0000000000000000000000000000000000000000..b11c92841068c12a5d0102402127ff4537a66899 GIT binary patch literal 337 zcmWHE%1kq2zzaBlvTQ&s(*Pt+-EP}(hP6=Q%v7TlcUN4R;bnb9z}x1=g!=#g|1&Z% zGqJF;urM%$904k22)e)kWJhN(08Q|XVBiCaCoqUGFeDW)O8EGOFn9p5wt<~zhz06V-;=l}o! literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Damascus b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Damascus new file mode 100644 index 0000000000000000000000000000000000000000..d9104a7ab8cb13b4c87eb25ff633b03ec12ddd81 GIT binary patch literal 2294 zcmdVadrVe!9LMn=AVP>}q$@82QW4|w0FQtL2o@4y5B3Wl92b=zQ4$h#6e1LmD`WBBdXH@7F7-Rln+Z&lxF_T+RLy(>n{zNl*BP|Vln;gAmd%5%kH zxbih)q-lvcnzhXsD}C3z8tu2QWn2)~CNu2uh;POCg_HKg_ygk4kN+^P4}LCg^fVhc z`-M5Vqt6xx(?me+pb^+vYX%iY*i)*1GlLUeu&3t5h>-BljL=0TX6Ww|c3ALE5q92V zOuG~=!rwn;Oh1!rM%0(vGmbQgnZ9R@J4R25IfD(x+<{eMUjMKWRk~0_?-?>;3bu+n zch9jGWH*b2^#|=m-jB@K*nDI0?3HF*aGVi$wbEMh)ARDKi}O_c+1WDTXo5=YuF^?e z1(s)TyG(9xQz;Ga>C`HryfRHM&AF)3QXiM;QJ<=e$S%Ds@KtNs$a#79P_%W=H-4FU zxKDjcfSLH|EkoSjYSOxJp zvS6%46;9iv3(rkht9}WT4<5f=`Of?(i}sJJ)rU{ZhnfeK+t(L@0*>ZW7)fzruwhpAKEx+EB zTTk4k+Rj*ZK5vSL?f$;g^rokb(7=2$keZe-!e$~l&f ztes==$m%(kkF1}g07wNmN`TaWqXZ=4 z2~rcJC`eV1vLJOq3WHR})hP{98>Bc$b&&EP^+5`RR0t^%QX`~DNR^N>A$39ug;WYD zm8(-Lq*$&_wUBZl^+F1UR17H@QZuAzNY#+CA$3Cvhg1$JovTwjq@T$Ir`-Sm literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Dhaka b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Dhaka new file mode 100644 index 0000000000000000000000000000000000000000..b11c92841068c12a5d0102402127ff4537a66899 GIT binary patch literal 337 zcmWHE%1kq2zzaBlvTQ&s(*Pt+-EP}(hP6=Q%v7TlcUN4R;bnb9z}x1=g!=#g|1&Z% zGqJF;urM%$904k22)e)kWJhN(08Q|XVBiCaCoqUGFeDW)O8EGOFn9p5wt<~zhz06V-;=l}o! literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Dili b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Dili new file mode 100644 index 0000000000000000000000000000000000000000..30943bbd0a8251404c407cde82243294071baf22 GIT binary patch literal 227 zcmWHE%1kq2zzbM`vdlotGwGSck<&AcK5)M>D6l*{lcE0q|No3kj7&@n45fQOMiewK zurM&xO<>^g@eN_nHn0FXJlkxFunoOW8uKS;^P~_plx8n5JG}UKtuk6 SOaqyL+e9uKpt*LsCR_liP#c>7 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Dushanbe b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Dushanbe new file mode 100644 index 0000000000000000000000000000000000000000..82d85b8c1b387ffc54acf509ac75220465b64d4c GIT binary patch literal 591 zcmWHE%1kq2zzR5^qLM%w#1>d3+1#*o@p}VN_1Xnu5}O3XIW{VY|9m<@;^mVClD8!V zq|Rh6kls^vKxR$)0ogeb2jqG@56IV89Z<;8KA;#Qb3n<5_kgnXzXK}T?+>U-KRBSq zeer-g%U=ieFYg>QPW1=W|NsA=k(mhsSy+)E8#_A#gF^$zL2dyIEDQ`u1&lx^g(NWW zz(|+~BTxjS#>Y2=LEFF-h|Pi645XET5ePy^@G#Il|3RJx(IAh5%m8^FM1ukVM1ukW zOalV~M1ukYM1ukZM1ukaM1ukbM1ukcM1ukdM1ukeM1ukfM1ukgM1ukhM1ukiM1ukj sM1ukkM1uklM1ukmM1uknOalWGM1ukpMArk|PV+$JvH=FQovtYt0Q1Os`2YX_ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Famagusta b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Famagusta new file mode 100644 index 0000000000000000000000000000000000000000..653b146a60e5e5641a07bfc82f9590dad1ed69f5 GIT binary patch literal 2028 zcmdtiZ%kEn9LMo5|YK$W8Ab<;+SwjLrfF`|J?@? zbB?*M#@1ZAE`fk>4WB&$86P_ur_n98msd@+9Mx0pL*`@echd% zdmsJYpXkbUu>#|<>v{JMZ?2v0oA1eAew-d0K5)$O_wTop{;qLGe0Rwl*0; z-5#){d8wVecF20M(lN(GCOBim7tC>)=dJN$y3Le?BUZ}24)diupI8%qs5f8!zRn7K z({868-Q}bmjM?d(wNA$NH|&WG<<6wl+4d_HSx#p02zzoc$(a%uw5KKwIMWi7%xU-i z*7TnT%&hBot?Y}}%o!*9tYG&EGpFmgmD~QQnYU%X6{=}A^Q(HDg2+BQT%yj*oXvJ& zT9Y%YpjBoK#br*QOXu{jk)nTEbndsM^6JfZwYaBROU};Kc^wOM{^zOsS}ao+v=_<3 zMTuHk6Oh-Z{HkT8L$WCGik4^IlJdb{WO2fIS=@J7-n?@}-s=5YDz2W>$lgv_a`dn+ zZEO^?bC)h#u}9x-sMX5Z4H~T|*LPBu=<;BeE`Jcx6?WWy@BVaIdHPRXb;B>Kzetv< zlXvC)_&ura>JzK_hOF7~yM8eLjI6D?sx=u0q_(72V=tW2x-`|g-#*j&p(b5-xlPyi zNA<(6R%yefO|oHki8l6B%EtN({ivf*HZ3cbrdWz>&QF&uWq(O?vLP*bS~=NS$a5|Nryho$Qb?^5LC|NYp4RtK=hU%m{_~mCtAR9ua+tqyDdZaoqU}jy!Vg zk)w|se zBrhZ}Br_y6BsWhtIV3wIJtRLQK_o*YMI=WgNhC`oO(ahwQ6y6&RU}tWH(4ZGPd8m8 zUnF59VncO-cvdrvogB!5qL0+1O%rU01(WD<~BK&Ani z2V^3UnLwrjnG0kxklFBbrvsS}WI~V`L8b(m6J%15SwW@+nHOYYkeNZI2ALaVa*)|U zrpMErA7p}%8A7HAnImM9kXb^e37IEkqL7(FrV5!WWU`RiLZ-{poiAjXrVN=g oWYUmXL#7RxH++UB&hIW?P5~PjjD&Lwb3=LIU?e}}eVgh353H8ZHvj+t literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Gaza b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Gaza new file mode 100644 index 0000000000000000000000000000000000000000..a4ca1c6e028f91977916e3ab1f45d5be135eea02 GIT binary patch literal 2422 zcmd_rZA?{l0LStF4dijwNNrA$heQS9NkD=i3A`YfEuG6615doZ~;96%*qr?%PW;4WGK# zl+R>`={q(c{n`@DSwH_SXNMNbc@wAQ{C(9j@RQ%vg57my(77oYEDstXFMT9Kb34rk zOWs!tLyC>Cf;hQIq#KL__ip%-JjO+7OOUtumd`7oSu!qaU&{nxD%ugoSn&iU|l*wc-yOBIquTn;&`N-8$ zmD-bOrhS^B9z7OjE^k?=()W9rk2TCt8AUIu%#uE}BIAVH9^EFh?w>TW@BKk#_iuNu z9Ga_gP6U{_Ur(r2htuTaM`M~-mvxzWZ;dxUv8>xzv-65H3J<6!9bIy*{jjkvu|+y^ ztBmz?dew%ABDrC-+r4qtS-J62t2_V35n0gLWg?`CdKKc2!k`7%}DRR=OdOFczoj>sgDSt8R!=7~%cnJF?=WUk0$k=a`6=_2#B)DuQ# zj7%AsGcsvp*2uJxc_R}?W{yl9nL9FhWcHSN`pEn(bpntKASvLNN)9Y_5|At)X+ZLT zBm&6KwMkJ3&B9Tm5>Qo}RwA9H&vWcV< z$tRLfB%?@5k(?q)MY4*d70D}-SR}JZYLVPp>f|EXMbeAp7fCRZVI;*!j*%oISw_-~ zNUkk)vXN|C>U1OdMiP!>97#Enb0q2bKhL_K?tXMU{{f=%5@Hf#5@QpS Nqwr!EJ$Z#%XIIr^!v`U`Pj?IXSr#5n@#x|uLk|}K=-#pGy8I==4y|zif-%k z``2;iyrCBIr}1LxMlH>RUUvCRWd{{6H&If#PQe>V40%K@diI|riW5nZK+9zLz?b5# zy+^+If0*`TPqbFdBNLIC$W&ym(@sWaJMDC2K9T^*fTTcjAW4ucNE)Zj!x|DHnUGXS cE+iR}4M~UOLlQb|MkJ;4e>qdO>B@TQ7g9&Lh5!Hn literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Hebron b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Hebron new file mode 100644 index 0000000000000000000000000000000000000000..1a206a70c7da285a55cf3790e116e633fbd0a14a GIT binary patch literal 2450 zcmd_rZA?{l0LStF4dijwOl_u!kf=aB2}lqmffoc5Jn7ZR^B)DwLZmds0J#-o>q+No zOQ(e^#>TQqbF4W>87ni>?g=$(y7})#LOjGx1p_1ce-Eo(=$qEd&e=Vm!`Z#OVEn$< zk-xbjPTX<$=_kB6_Ujk-GoAW!I?p9ekF|=g5)V1g{?zY0cjOQ8&6o3pYwyd#Y-DO0VJar;3p1w2TP-fjl(A`DGR__<HHlIEjV zOH{He-Aws3O+9ur#9Z1uU#0H#G9Pc4qS6XqRO!V%YFXOHZhK^_%(#Et$h`LlmD#(s zdilUCm36|)$o_gvtvH+_pZMU4T3Om@=Dam}D0fMhkz44mavQH0tF~X3M!`Pyq@z== zwjVau#5YSvcBQd)X17`wRw&mEce&S3KO@&)Y;ot^I3n{qn%o8F_sGI`mZ_p+8;s)J zJ7vk6tEDW?lcjZ4YQxfGxv|htWr1^Lc}lFR@J>>j0%oX9J#*Akw@1|GQ{(FC%ipVK zTCb|g&xhrfrq5JW%O$zB;(b-!cw9ca>ZE+G?4aBh{hr)zub0o?*C=;H9#A`mDrC*n zT2Fwj~gLj@D zp1#(3w~zjZXF>$^=zo0?9%J(qA|Ock{&k&vqOVh}C)2F={C&?mSLQfGM#dU04v}rw zFMTg;Hh!N?GkK?faQurQPUxe)bH#(mAT9MMkzpd^L_>llu>Ifhqu+%X?f`CMUKPq9c z)Nw!pfkXlc1riG+7)Ugba3JwO0)j*Y2?-JtBq&H!kgy}l`BZGtni477QBsxfV zkoX`0LL!8O2#JxU4iXY2Buq%0kU$}kLPCYa3JI2_jusLwBwk3skcc56Lt=&m4T%~O zHY9FH;E>26p+jP4se^|^4+$RN?B<@Jyk;vo!KJ@gplAYppE}QP6N>(=YeRD6G1e{nIIbER1ghvE{Fy>8AOAe4FVvigFrn{ Qj0(=@vH^O=PS>0Z0O4(7+W-In literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Hong_Kong b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Hong_Kong new file mode 100644 index 0000000000000000000000000000000000000000..23d0375fba3377a3d513d849c0d29c82ad2add64 GIT binary patch literal 1203 zcmd7QU1-f=0LSs?e_rh{a>4}{MD&!#u^Z16wn@Wr?82!@F;a5cyrs<5X_8uzPOZ35 zlB;KwMCrM5X)}@6?btZ;wsRV0UUrThHplb*N4apbJI}v!K2QJ4|L+^$p4eL{{&|AG z->$cEpK~&?C)FKW5$W!4kKBzOKKAHhCiS?fxAjT;HuJRhn(8^S%Jiwm)Q!q-i<4?>_HJ49?^4D5I{AIDR{h8{>hb$K&BU!5{qt(IDP35k#hHc1 zN&2;BQ0$sAK(5XV%%W`T@hnjZ#w48aqN`((L zYscgDIUaw&KAu013GDw1@PE zH0WwOL|R08M4CjpM7K>Y^vSV}0-YkQBE2HbBHbeGBK^ABhLMh4ZOcf{NYhByNZa_o L^&PV1SE$f0t#TGS literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Hovd b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Hovd new file mode 100644 index 0000000000000000000000000000000000000000..4cb800a9187901afa985f1ae67565d654021cabc GIT binary patch literal 891 zcmcK2yDvjw7=ZDwR3b{8MdDVi`=#nm1+Dvn4wBPKh!7EROLXYy@(m)0;TyW?aE68s zhBH`*MS{sjEJh5($R?@t_yZ&cZ}a6hG-;amdG*Pqg% zgDQA*h{D?`Rdf-M#V3B{jJsvYflIm8)1-UVrb?%tW!dPHD(}9L6`pHVS(KDjj$>7A zzZTUWS6a>Uv8cU2((11Egy(cut52*5Z){m>*ba)u=$O_t-zb`=7gbAeRJQs@RGZf; z+nx2QBPUmOy`5N;znTm(Cm$F8h!H{X1_jb3=GYfgKY!GP({Bv?3{6j z@{(paV@-xX_sxlyak-UBrEKYGfBd8i5qf7)`Yh{+NL!{5a}kj}7Sx5Osl$4m*7FJd z4=c6)Ns6`dyQ~&jFS25WH6yD=){U$jSv#_NWc^42BmdHJCYvBkDLH<2FNKO=YX8V VkJecrr-A=`9$7uskp#THtZ(&(y9)pS literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Irkutsk b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Irkutsk new file mode 100644 index 0000000000000000000000000000000000000000..4dcbbb7ea21e193cd2e2578a17bc955caea227a4 GIT binary patch literal 1243 zcmdVZPe_wt9Ki8sxz)13A)40Io>E(Dt=24?I{(zNvE~lNh!`1ISqL3QL>NepOu9sL z$PUusN9HX$X@m$Ocqovdj0y?*d+8De5k%Q~zOM~Nbm`dp^1h#U&&CUTf8RHm>Nyou zf8AF9UX2*JF3FhF?c$=T@sT-Ksi!NmrhI6j%sHgWzCB8pe|(r(JO5*0-E1P`o=i!_ z-MCcV3QN^hzpU@85`CsfHXK#5G5%Sqo8C!{Z%%66GqP#bxOnVuwdc!Iz4^nFfVcNT z!24`WZzymwf1_7#yWFFK7{{XyORx^;L$w{=hJJp<2WZ~KUjoOmGn zY6o?DWLWk)PU~oOpF}?mNUY$P#2$Ccf%k0^zZaE`*-o9f=9Ogpg{wcC&DxgP3zl}r z^1OY8Gw(zG7k^%_bU2jinl?|Avt6mIhH>Q9m8&C> zR55e-0=v!8V2%*CRm!%sCI4Z>=AUH`-@nv~j2am?w`1hU*pbm&n(-qEAQ>PjAUPmO zAXy-3AbB8(AekVkAh{sPAlV@4Ao*CDgpiDolq^k7NK!~vNLolbc_B#vZ`q>lZjf&VD?!mxP(TKu8HUwI%CVE_OC literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Istanbul b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Istanbul new file mode 100644 index 0000000000000000000000000000000000000000..508446bb6aee2841ab88e82607a6ad6e748e7db7 GIT binary patch literal 1947 zcmd_qZ%9>V0LSs?`nP+{bz_9Pc+<9~_m!HcdDyFf5t&8ib5V%gGPe4 zDT7wf8GBJA#8%G0%Gwr#Q7fV`boS>^w&_xK##j)+dz&KFpX24? zi_7!<#nx`!TqvHq()1_XTs!s6b0DtYtbL=0+9zk2?YA!2M>jP($98{cbkxSpFUrr_ zojD=rc&Nqh3Wv?E-yYc~#`ZcVFBcd+d&-?&&&x*d@=^20YjLBmuiLz_&1>8|T4MHB zCK$J(>CR8HcH2MajW`3|4fbHdL38kKx&6z%ubtaB)*D0pwmJM&neo^CZ_WD+BgW{K z6!SrL#7=4YRHl|3mZ{_K3vZxVdhI^p8+%u#efc;(d9XsJchtpS>O3WhR!&dcWf2>VMI-DFOXULcc|>J%F@nCx#(P$Ec+-&mbVL8 zu{l*PZVRd03~S5>X%Ehh5vi}YR0f7O>qUr(RhKSb;W4!HhJChEWG89)v?a@bwvt0(2&@W;P_pM4hhdy$Hzs0t~x?4LPTOjf<&T3!bIY9)qx_By6RAoSdn0n zXpwM{c#(jSh>?(yn3157sFARdxLtMNNaRT9NbE@PNc2efNc_kEAR~Yb0Wt>2ARwcF z3_)KLRyMcD F_XJx;ZRG#} literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Jakarta b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Jakarta new file mode 100644 index 0000000000000000000000000000000000000000..5baa3a8f2ed24f68c49bd7e3ccd4772a8e734414 GIT binary patch literal 355 zcmWHE%1kq2zzaBlvg|;t&;TS>Rv`g&Zj0+JvKYZD`D1(s+DBS!4q_J)SNV;_f0|%JR=i?i~ nplx6Y!o~&+;hrH3AtYGx9|%AefoPCrAev+gxq!CnT5)}0ASznEwjORPnc1y=ZvwV@dUv>5msW0ETB3++HNcY~I;%{k^ zuXfeR$rpRo*X6CMr!rW23q7j$T!DNW_nA5sUM8n!UX;^AemT>YBz+&I$ywti`L3-? zooo778TB>teSV$%&|aZ_OevM08Z%Y@b<1R++LZGlC)Hr|VKq3oRa~|8hU;>xKXB|9 zEvPxsKkMf|wAoQb+MJ0K+Kqdvw6OL|#@r`r{o$QgwFvEXZ{&`nT2$8i{+mh~jhiEj zz4Hn^+AXrg8y!4iM1M2jzjdhFxb2fE-k6?YZGKCHf5EYGBlZP{f8oAWhP$-I8@DaS z@MIqM$7jB3BrLA-CdR*~CC$0wPY!9&l7DUXE(&m|McocPb*xm~-ZyUC;UCfOJW`}B ze&djycIaL0uAMvdCA9~QrJGaqW!@$&J$tV#&&<_V#BP#|@G*1c^gLNPTxPBsPL|B` zqk2~7^|HEszj^oDn^MBv23PNMdf}VA1?P#!B*tT31^^BPJAJC+@t=lZAOPA7Dj+$EWJXu%Qr9Y77 zl(OPh{lTz7DNlP@uW$ya^>eHB_5B0tq09ODhT|RT;j^jwBX7Q?Do^;#jnC{>Rm~~p zqvcgffA$7*)0%pDtbD@U?A|EV8GYvCGjgTIJ+9YWh?gxh&gfgZX33KmKGL@y9+hof z2ld+5LR8(6r}d|5epB1`l<5xVHB%-(0h6zjZ&RI9ozq;?T=?I7M53J5|GGq8k^qtU z9*0XLEK;V6q%L*L{QEDHf6dPE$!hD#T46nTXuXIy91gzzdJ*yci^W~FF8_m1Cy?bK z>$9~Mh^!D$SBOjI0=0GO}i5(a5Ti zWh3iG7LKeOSvs%T3>*pwdtyKY}1V{~#A|O>j%7D}XDFjjpq!dUkkYXU! zK+1vC11Shn5u_xxR!xwiAXP!ig46{m3{n}SG)Qfb;vm&Q%7fGgDG*X2q(rt>jgTVQ zT2(^IgwzQs6jCXqR7kCmVjQb${>kVqwwQX;iPipfz;q?{b}L<-7LQKY0C zHARZbQB|a@NL_8M!XlMLN{iGMDK1i7q`XLdkpd$XMoP?4W2DF&RYuCpQDWSv ywMxxVYoyp5)keyV)Eg-{{y!@oWEFm4f|dH%oJ4n$J1H(9B{nDC<4$&ag8l@yuiuRT literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kabul b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kabul new file mode 100644 index 0000000000000000000000000000000000000000..d19b9bd51d701d8bfe7b3e95c9f6f3c736a9aeee GIT binary patch literal 208 zcmWHE%1kq2zzdjxvLMXY03;MIs_6H6$BL& zNYsit^lwDO4iyv&JdEfd;UNgD;0sC6C3dKT6|CR;S;B%Y-Fn9MdiFd!JnZw1?>MkO zWc~G+_xozEk@H3Ow_nLVxt*M>@cJT4s}ku-&#v*xnajbd&zBJNnmb!HFxI23XM(!+Sc3-lE>=4cmeA2^Y3r_+b=!W(`nnQnw?9bx z&uQtXnbD5-FJ;5`ce*i?lFq3Y+I2Up-Oq1n`0PFHNuJWkzH{1p`lf6eIH-MlPD+1s zOb7aQ%jU9H9c=2C!7ou6Ds7RW*8$n`(Ie4E3nexY$_-!49~sT(^RCj8!pmJ&^qMob z=u7d9KhMq2+?F+#;g3zGEpz^K(&e$N)VQ@^_H*`%%Umh^hP$!hxaGHP^KLWm!eB0r z_&@At9zV~9$c{V)TOxZRn>w0Zk!_KEk&Tg^k*$%vk FzW|Yw7d`+0 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Karachi b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Karachi new file mode 100644 index 0000000000000000000000000000000000000000..ba65c0e8d31cb1d59935878af29baac722f45936 GIT binary patch literal 379 zcmWHE%1kq2zzev6vTQ&s+gbN#$(gA}D=w7?&A7Yb!3rk-)dn`}T{qay*I3};xWK@Z z+kJuOle-39Z>kj-nHZT_S-_Bi!R`*o0^bM*76yjs3`Q;n2DbnP0S1PU1V#}sThhlj zghAWD)Yt$>nt@4Eh5+y25Fio45JG|*{{sQYogf}v1BeFs155+`0-~wyA1>Kf4i literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kathmandu b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kathmandu new file mode 100644 index 0000000000000000000000000000000000000000..a5d510753f02d5dedcf1ffac153558466dca9b99 GIT binary patch literal 212 zcmWHE%1kq2zzdjxvLGz5@KbGzoP@!O`v3p`GcqwTF!=ugY4nX?U}0bgxWmBZ;~T=D qZD49_03uCH8A3=f9BAf$kOd$UL6(4MqAlXG0b6LNYiea;$^`(OKO|oO literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Katmandu b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Katmandu new file mode 100644 index 0000000000000000000000000000000000000000..a5d510753f02d5dedcf1ffac153558466dca9b99 GIT binary patch literal 212 zcmWHE%1kq2zzdjxvLGz5@KbGzoP@!O`v3p`GcqwTF!=ugY4nX?U}0bgxWmBZ;~T=D qZD49_03uCH8A3=f9BAf$kOd$UL6(4MqAlXG0b6LNYiea;$^`(OKO|oO literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Khandyga b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Khandyga new file mode 100644 index 0000000000000000000000000000000000000000..72bea64ba83546e72ff9d6a4f9a9e64cc2d93b47 GIT binary patch literal 1271 zcmdVZPe_wt9Ki8sy6K!5&mq%V=E|*QQ`=U_mQK@YGB+b?rz8;iYekIcP!R5g{@6j{ zIRwG*P?U9%@K7C=xAag*P`k)csW%2C7ar`u)Mf=t~2GFPN*%D z5mh(dqPC9JtNLqFxh`1Lw!u}kJ-(zG+UAwpH>*6(7ivf46Xmsjklybza%b+9tMSTt zSL6I+xohU0^gX*Rn;u=2&3DhqmK%d|_vM82pNz=B@v|y;DXR8F`qkbe9<{HoNwo&c zRqL4{NP^eJ2P{>f&Q0P$jPzX^NnbnjioG7HsYE~3l6kZf! z6lN4^6mAr96m}GP6n+$f6owRvW;I6&Nwb(HwUC1_{j!ssI20 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kolkata b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kolkata new file mode 100644 index 0000000000000000000000000000000000000000..0014046d29a38e9b8006f746fea794d7f71eb479 GIT binary patch literal 285 zcmWHE%1kq2zzf)bvMfL>)Bq&f=kD2c>UNLD8P-CHGgFOLTq+To!N|l6gbWNpH-HKl zyxl;meIpn+7#N~67^~5w?UK*{(az6b z8-Qq#8$dM39UvOy7BCHT4~T}kiG`Vk8Rn><3m``Uod$Fi&}lqirwM?Z=7HfnE}%JssI_(gPus;<25hEe#4|NC>vVw?M zRF~)yj_45alj;(lDx!lFMASi|BnvuZ5nUu=J>S;`5?#9WyuACod)}89w%<3k{a{zb z{B?PM?>1VwF1|52``i7&vA~?r;q=_nj4AO97MD!E?l1lHDm`!1YvzyaNc)Dnb;0dU z^=TAFk z&YJdR`i(!YJ#M!#+lu&iQ+tfP?(KJZjM>|33Ui;i9hcq7J!9-MxqVaE-jOn4iP|$} z&l+B4TvIFc4un?k#Qp|-yM3797R2*$CNHRz^jy4@6A0#0pBP1mxCnPB(DFC;M}GbA-6H%FTslAWVX z56KTn5Xlfp5y=rr63G%t6Uh@v6v-4x70DGz7RlDpriTV#D@XZGbF|`urM$r6@ZLLS777;kqkgGvw}g0fuU{!g9HOZK?8$~ zk8cP=Fc51Sn1is90f;mPk(NMg!4N`%LxJx2UuPD&3Pgh(45C4f2GJmggJ_WBK{Ut% cAR6Qekb6NM0nzn9F`9XX%LeErJ6#Jd04>j8q5uE@ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kuching b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kuching new file mode 100644 index 0000000000000000000000000000000000000000..c86750cb7d512966b1a8b19cb44531a618b00930 GIT binary patch literal 483 zcmWHE%1kq2zzc+dvTQ&sv9^nC!mf1pj{Vi@4f{V!2ONxD({S+Wf`G$z4;T(_yL{oO zf^fsp8SDYa8QmF-@%RkG$>{wTP96E*aN6c`!0Cw*43|7|Kh*#K|DTbW2?eq+ zGcz!x7l0g+S;4@ p>mVBBeGm-_0uT)f1~3f_3J?tn4v?Sgfov)V36~8pi0pJNxB$;9wBrB( literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kuwait b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kuwait new file mode 100644 index 0000000000000000000000000000000000000000..2aea25f8c210369e0b805d0dd5f0e899190c2340 GIT binary patch literal 165 zcmWHE%1kq2zzdjwvLMWHRoZMz{r~^}85tQEw9kO_Xc;iD`1pn}Xd4(agpgno(2)Ni S(?Dk6Hj&E)Xs(^EF&6;xtQkK5 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Macao b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Macao new file mode 100644 index 0000000000000000000000000000000000000000..cac65063d0dbf48e37c547fba3b67f34110d5a90 GIT binary patch literal 1227 zcmd7RPe>F|0LSq+?!R0$N(#IcMKK|v1<`m2O@$@W40a(XO1(se)e!wZEJXxCBAxUQ zMIC~%s6$abB0QF4iDlZdnc5$B(b{~O+N$ODzC+zS)UA22pU1#n_V?Y$&W63~#k^18 z_uG(``;v1FyP7*gM^)$e)1hax54S(>nXBu%e7*Z+{VBWWMB08;eoOUky=nIysZy^? z!zxx(sbc9FJD%5T$7B8Wo74llU$)zCyGGT(wYVC*e@_jad8FR8w5s#__jpo?#7g9Of%&$A{ z%JK8X=C`tLYhqu%Il26fH5HmLzpsi~>80U6eU&w3vH+rnV>Vz3MyUEJ-cbM5zPpn|#hMCjX zX5~I^G8bPevGNZ!I)*1pAH(aL=NSIKK0@q2%+GG07G5Emt{Mx3h+Y)Ad>V`Xyysq3 z9T64bh$viFEDDQDL`7wUFABpDk$>1UqaSufwsqC}A{!$+BU>YTBby_;BikeUBMl%O zxat;=9$a-3NEb*ONFPWeNGC`uNH0h;NH<73NIytJNJp-^C8Q@;-4xOl(iYMe(iqYi z(i+km(j3wq(jL+u(jd|y(jw9$(xj{I5@{3Z6KNFb6x~+2&?}E_7U&jf7wH#i80i>k h8R^+oH;r`ds@q2TMjA&tM_R}Kt@oh*AFQ>4zW`b`JQ@H1 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Macau b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Macau new file mode 100644 index 0000000000000000000000000000000000000000..cac65063d0dbf48e37c547fba3b67f34110d5a90 GIT binary patch literal 1227 zcmd7RPe>F|0LSq+?!R0$N(#IcMKK|v1<`m2O@$@W40a(XO1(se)e!wZEJXxCBAxUQ zMIC~%s6$abB0QF4iDlZdnc5$B(b{~O+N$ODzC+zS)UA22pU1#n_V?Y$&W63~#k^18 z_uG(``;v1FyP7*gM^)$e)1hax54S(>nXBu%e7*Z+{VBWWMB08;eoOUky=nIysZy^? z!zxx(sbc9FJD%5T$7B8Wo74llU$)zCyGGT(wYVC*e@_jad8FR8w5s#__jpo?#7g9Of%&$A{ z%JK8X=C`tLYhqu%Il26fH5HmLzpsi~>80U6eU&w3vH+rnV>Vz3MyUEJ-cbM5zPpn|#hMCjX zX5~I^G8bPevGNZ!I)*1pAH(aL=NSIKK0@q2%+GG07G5Emt{Mx3h+Y)Ad>V`Xyysq3 z9T64bh$viFEDDQDL`7wUFABpDk$>1UqaSufwsqC}A{!$+BU>YTBby_;BikeUBMl%O zxat;=9$a-3NEb*ONFPWeNGC`uNH0h;NH<73NIytJNJp-^C8Q@;-4xOl(iYMe(iqYi z(i+km(j3wq(jL+u(jd|y(jw9$(xj{I5@{3Z6KNFb6x~+2&?}E_7U&jf7wH#i80i>k h8R^+oH;r`ds@q2TMjA&tM_R}Kt@oh*AFQ>4zW`b`JQ@H1 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Magadan b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Magadan new file mode 100644 index 0000000000000000000000000000000000000000..b4fcac18e3540f029f01bbf2751045b3983d96fa GIT binary patch literal 1222 zcmd7QPe_wt9Ki8sZMLNzB*;Ilm9}izQnzKx+FaH$v28SD5LrRcAE;e^LusOLRm05HJ zc|iBXMGjR&b+5NydcPi%K6{7sy^YA>kF}C`=8@!VNT)`Ml1bzjkGe=MV@PL6Ye;WMbC#w% zq&-X1AJQPwA<`n!Bhn<&CDJC+C(*v$ zbrTqPz-$2@-w+00Al5dp0AfpqaL*7&h7c00{0{^mYe6)~Y7h;w9z;{%1TK(6bS=05 Dzv?@= literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Manila b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Manila new file mode 100644 index 0000000000000000000000000000000000000000..f4f4b04efa2b6a442d4072b3899f4dae69bdd771 GIT binary patch literal 328 zcmWHE%1kq2zzaBmvaCQX&;TS3&iT@CNX($%^rz+Xf0}q7l;~T;d-~zXJlkxFunoOW8uKS;^P~_plx8n5JG}UKtuk6 SOaqyL+e9uKpt*LsCR_liP#c>7 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Nicosia b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Nicosia new file mode 100644 index 0000000000000000000000000000000000000000..f7f10ab7665e94ca44fd8cd98a362cd4b304eff1 GIT binary patch literal 2002 zcmdVaZAeuI9LMqNOjy@ye{0UQ>qF(rhpu|nY}s_Jnc9QbPV-i-GEb#fYtAi8r(5m5 z$Yg}XzY-#9P-GGju7RsTPxL@E2zOwMF+w`6v5iOxDx!vL=X;=6dll@>&gI_E<)ZKY z-(P6e#&DkJUr&tl3vZr?^XB{bW1l8}H+J}I+dH(^ihWjRkGpWq7~flHPS|zFdZp86 zO6yW9Zo{ZKvC1|k1t;6D=3h4AQ!kmXP3kogqK}#h54()l@9s1w|JZ1}aiziZo$Is` zPwudj4u!4c?s_|A+d^wfQ@K5LO{O)iBEwEC8fU%fkF}@!MywgJ!**IstdaKEYo`A; zY-Id&-^{%FgE4bp(De6yV`TN5GP67P897_`nt{4jBe$mC&I|6b@{84;m9@nxNNTZX z=e5i1(TL3P_2`_TbyE0Oo6bF7B5&WS)}p>zEj~L}-|3pK^A0BJyWv!w-&rW{mBnaD zolh1_|3gblMx`v~do54BE#)J>%cAH@vS{$SEWUeGmh_*HiW?U-xVu{_Pae^w&COzT z@6cr{cj^00^;-2-lZGnFb$LRiuJC8*iYEcBjxUqypC{@EkJDw<=|{TyrdQS+j+2^! z`?5CjP-=Sy#jL$4>$cz1_4CfihMF5%mvTVri~BYF^0(TMq}uT3er+6W(T&$Tbkk5s zKRmu#o33q^kG?F{=DsTVxG_aP=_-)T%Zj8WoFH3rlVxk^Q)!L!NLx<4wmtY&+9y2G zcI&EijQpaXo$8a%2hZxZ1DADs|5y4&N3TY9NA#tr7kfpI`A=USPs&1WF*6V~#^Xtx z;u-t=lV2)=Ax~*(6(1q~Dk{qT2))2<|Lr{7H~-F!BX^G6I&$yG%_Db@+&*&uNCQX* zNDD|0NE1jGNE@zBA4nreCrB$uFGw>;H%L23KS)DJM@UOZPe@ZpS4dk(U#?DLNM}fE zNN-4UNOwqkNPkF!NQX#^NRLR9NS8>PNT04wqe!Q&POC_-NV7<{NV`bCNW)0SNXtmi zNYhByNZUx?NaIN7u1@Pn@2*bsNcTwlNdL$NAUl9;0kQ|kCLp_jYy+|n$VMPL;p%J! zvKOw-W+1zPYzML*$c7+0f@}%0C&;ECyMk;BvM4YD_`&gLMygKQ77Kgb3l zJA`ZzvPZ}!A-jZZ6S7apMj<Z91c0qO^C*L2;4Y=QCdH(?jq|NOB literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Novokuznetsk b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Novokuznetsk new file mode 100644 index 0000000000000000000000000000000000000000..d983276119c95872882589a9fdd829eb1f86f606 GIT binary patch literal 1165 zcmd7QPe_w-9LMqBa+Wy>FXd{jmdln->)Wcin%b5v^IuS`gZ-iCj~EC^f2bf($O-T<4SkR?g&)8nio@b1)&pW;SV0Xm) z^_cnlYSPMi`7LiC_h4u&FgtW8Gsl}X6(vLE72n?sct5?)%pLWZc_TYAzTqC7f4fWl z*V}Z#g}5#}RjYwszb@K2ODo&+8jOF{#o;ln^1ak0p2r$;f059)_p)^SU84HLxkUA= zM^f|To`mmbr8aw2>aLuXWrN3M`OzMc{avzR*PuoY@79%#-MVUPQdj#oX*3el=+7FB z`4SR)Tc&G%RLa`n35}1srQwE08Xta?rZb;q-L+?uIPgM}r^j`D>aH~Jd#W3%E=#KU zrfw`gCN079+A?uTTZ?+N_4yHP`>X|HKA(3LO`CkUiwhppXB50C zyz%F`{g~UBEjj+!^d4i+`vzPk#_a7gWmB(HS6ueW2;3q>O&Dgq6YULr>M z5D|oI^b~QRKMyhJP(6+wLhNBkNxk$^QND!LI^SzT4?*YEIG^pwmKDDxMky;fisG7(pRU4RAb>5e1b=foJcYd_|GjFUl?_SILvzKN4 z#8YeS^ZQodLBJDq)%=hGlSQV>TbM91WfqgRHPc2Wj!d1!t6r69G~nqrV@kaBEIJxD=FMYg6S7BwM7Aypw|A$1{zA(bJe zA+;gJA=TNM@{sy$O@T;-NQp>|NRddDNSR2TNTEojNU2DzNU=z@NV!P8wx(dDVp~%( eQZrICQZ-UGQa4gK4w)wY-^$%Bruw$VX7^8#1sDDR literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Omsk b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Omsk new file mode 100644 index 0000000000000000000000000000000000000000..b29b7693118fb1ed214adb8a4e686172d0914b2f GIT binary patch literal 1207 zcmd7QUr1A77=ZD!oHf*71f_FYmf5mp9apa9zuwd-%UL5vL>NR?A{0c3R1^~CT||UI zM9{?ODuS%M2%$IVDkKV|8xex+qKg#Dn=o77b8Il8o9;S?v){Mx91d*nlRVOMDrEij z$p5|DWMu6fej;PfM&|6*fy=2iMWfzA&*QSf@1JfIeV$4ArhMMwiJp{yyiZFWc5CU~ z!@BlbOxIni)w0t;UEf)v8{#XqyzZxN49;nV|ATJIf2RTWq6Fq=W%JCJMCJKgiOR{h zvgOrF2|gW_t@lTyYG_EdT^*F|y?tVz=$7iEH#KzbjP7XY)tv_qXie!M4Tq{Vycp4l zf4@Ygi*@&cEw$r6v~FsZ)Iab^!}ED*99)n+cixMfoR+-bX<>Wvi+OgpH8P;Im?z#cW&0Xd_~rm z>>GcsJ#M#UwY=uvZB1Baef+G;V_C^#Rzc=7v*R*5nP)8XOlIFIh<7Bdpj~6GUFHh& zGRw7eB>!Qg=GUYdD>7PM!+4PqBV%?nqejM!j2sy|GJ0hENCHR(ND4>}ND@dENE%2U zNFqokNGgsd7bF=Z8%L84k`Iy)k`a;;k`s~?k`1E-B#LB;q>AKZaI!qYxKp+L*LkaykNl}NugF}!y zM0JV|MbaT67SySt4jn~)hi+>84qZBQF*=CJ`o14Mbnw!x=izx?;~9+cyg&Zb<>{Q+ z^@!{|9aj0g??wE<>f6PZN_*-~tt0j+84bTqMmK&wiG5$M#aB|v&ZV2R#QUn<|MG_I zdOU3p+&yOx-accK*GBB2^J&{%PT0exR@;-=vPTlX-O-jGF6G4~^(!LBzHLhHt!L8v zlG2Y`tC&H8eIgHt6Z? z**TlToZdFO+&#~jY!B}xoi$CyOjJzR7+*rI+>PG9@sk)3*J*Jn5TEc1W+h zUIo2)wR(g&{C_B+f4)u)qzFGk6{HMOCr}F^m5@?MEuUngk@84=WC6$ukR>2%Pz;MeR)H)7SqHKZWF>*R6l5)dx)@|N j$a0YNAPYiPge(bJ6S62|RXD3n{;y?4O1ikQzI@~luEgG{ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Phnom_Penh b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Phnom_Penh new file mode 100644 index 0000000000000000000000000000000000000000..c292ac5b5f489a88bf10a1263b14e7412479d9e7 GIT binary patch literal 199 zcmWHE%1kq2zzdjxvLMXU03;S=r5~yP|NlQD6B7eNoDEO}M6xh2Bo#1l`1pn}I03P? lfjL762?hhr`yaNg^$3UtSpYJ%9>^wW36~AfDmz_sE&#dsBrE^` literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Pontianak b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Pontianak new file mode 100644 index 0000000000000000000000000000000000000000..12ce24cbeae404efe6921081d21289be452ff88d GIT binary patch literal 353 zcmWHE%1kq2zzaBlvg|-C-~GRjVVBr_hSQZxI4*^~E4XfRjN{gSHHI%+_jM@VDrsP3 zVrF7tVr64sNNWI@2qak;7&0pufF{&UVBlk5C}?010+V743`qqH(muW+3;{r_ZD4L} z03B{AP0kJkfT8~$l)M|(!}vx KKp*Iua{&O~6I|B- literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Pyongyang b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Pyongyang new file mode 100644 index 0000000000000000000000000000000000000000..7ad7e0b2cf8fa4fc844fe8cc9c58e4f3018cead1 GIT binary patch literal 237 zcmWHE%1kq2zzbM`vMfN%(|!HpoJr5beq7Q|EC@ZvR1o#1w1AO`nUR@+q4WvJi1H4Q z!nz3z9AJ{g$2Ww*J2-^F3y4EVu;@P!fGh*iAPYe>$Wo9UAd5jXNtSZ~U7>5q1ppt4 BHM0N! literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Qatar b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Qatar new file mode 100644 index 0000000000000000000000000000000000000000..63188b269d077e29f48a42a03c2a52aefdb61320 GIT binary patch literal 199 zcmWHE%1kq2zzdjxvLMW}@Y7ramaa($>i_@$&&b5Yz+eyn(rDqpz{0?wWx&AU;~T=D kZD0b##tb1O7z{M;Kge*9X&?(gG*Omt*#NDw(>3M-02;d=O#lD@ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Qostanay b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Qostanay new file mode 100644 index 0000000000000000000000000000000000000000..73b9d963efc99f7af196755a6b2be015d9cb7a67 GIT binary patch literal 1011 zcmd7QPe_w-9LMqB=AZV*Ll^VUG@q<|)cLPD$J9C3Wq45dA_E~N>|jFBNfZSIAw~ps zt5bB4ln&8hLY*q`&@t$H@Fv>DO9UROi`baI_hW}0x^!y~+iQEC@i6xOCdg^Z$C;c2d>lld9@VzP}H_JE86~I zQLjFk(~gZPb?%SqwS2F3PDk{5szGl=%X%|%qFv#y>ehwD{q;ypFUlXd*VLiE>txk-Q`i zyLI#|En^=;I)30t>Xj=K@BNZ~7?jE9$CA1GU2YeRZdNK4pTDNI#&3_h`l{nnpz1^Q z1^Yf2G-iB<|0S6*wZ>${1dPcQd=0!B`&xY_D?WSm;+q#&`R4RY&P0de_Bmpo32tVL z&wJ$lA%^|^6@nm9xC>#BI7lE*8wm-8#6p50(U5RRJR~3z5ebRJM1mqwk+4WyBrp=$ z(}qT3Bf&jwbR;|y9~l5L0%Qot7?43AqdHdjZ1K-@S_BTl0t@B5S&Vjg%%1D zy6C1Z;t*6Eq(cgIQlW#R;BRmcinw$U!9iW5hV*?-hZMSWYeMdm+=YYW`4*>c&nC>i zkJ$gSNh|Mx*#@#j~y^V`o_*Ou>{{BXDCzOCq~wFT{d zI;*E2+|-`s>+0PZ)ib35Jv-s*xlEg$kJt5r`$KzUU)2xC#Q*(Q`nGq<{fm#K|C8ni z-hY(%#-?0+u`Yv;p2<+<5**A{lR*%W}lWoc0`YzWhMoaGJ>Pn;02stgSEslMLk2F1x zh9k`%_q>ldjxpIXe@;4YT8$})i5OEXhuSzAdu%>akWg@y^Z&lX)rlKL6CWP2ucUpY zxS25_9;SGJBK8L~sDhN?F4RE^A(aAcDWn!s45@~cL+T*~k%~x3q$W}nsfv_E>LP`a z%1G%zTN^2kR1dV}k^0C2kQE?HK-PdP0$ByJ3}hY1LXedpOF`BWXcvR5CeSViSr4)x jWJSo5kToHTLRN(=3t1PkFkG>14&Tb689Tk)U^2Q35s(4S?M3@|NsBb$i&RV#J~`x50nFuEDQ|M z84Mf@40RJ2_#kW_-w=i%Al5c8Gd2K{mJA^zSPHb`f7rIpiy#_gIfw>107Qcv0kXFq U$R^7nTsB}w+3A{D85?i`02U)YF8}}l literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Riyadh b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Riyadh new file mode 100644 index 0000000000000000000000000000000000000000..2aea25f8c210369e0b805d0dd5f0e899190c2340 GIT binary patch literal 165 zcmWHE%1kq2zzdjwvLMWHRoZMz{r~^}85tQEw9kO_Xc;iD`1pn}Xd4(agpgno(2)Ni S(?Dk6Hj&E)Xs(^EF&6;xtQkK5 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Saigon b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Saigon new file mode 100644 index 0000000000000000000000000000000000000000..e2934e371b6d5cf80244d8d55594f7094bc9cbb8 GIT binary patch literal 351 zcmWHE%1kq2zzev5vTQ&s+R@|OFmbUq*ICnN4HqNN6@gplAYppE}QP6N>(=YeRD6G1e{nIIbER1ghvE{Fy>8AOAe4FVvigFrn{ Qj0(=@vH^O=PS>0Z0O4(7+W-In literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Sakhalin b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Sakhalin new file mode 100644 index 0000000000000000000000000000000000000000..485459ce0397787a099064952c66989712ae707f GIT binary patch literal 1202 zcmd7QO-R#W9KiA4+I-0hBFb4y)6|wNbz5bcFZr6RZ8TzZ=mmn_uw5RaLlo!(Wf4hq z=pPy&by5bCAd&*7N#-{qH&aVf%fO2m4Nj z<&U%U=V_NM&#Nz+=aaL+3A4t(Gf`ZUn(`K&e(9aR)n4*xG_f{2JGE}6GU3Yv)%yDt zs&r(PDjRaE4HxEAdFrF8IP_X=j6PMB&6BDsa8FhHhSjEJ*OcG$*!bth&E^l|Qgd#f z)V#WCwoIQlfk!E`_0C~adoyn8F14BZv-Ku;yxfG2#8miYN8KhFQGKh6*)l%d-wR$OnDT*nQ a88lNwQ&ckp*24cOyQsxtZ>tT3ihckL$`3{W literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Samarkand b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Samarkand new file mode 100644 index 0000000000000000000000000000000000000000..030d47ce0785f3bdb75314e0d03fb20c3e0172d5 GIT binary patch literal 577 zcmcK0yGz4R6oB!Qw$ajdaM3o#M|?&sf{672rF0U93K;@|I5-sqS8)-#)JgvYhe9`T zh=ZGhtKe{U2NxFy9n?jz#QPON1Q!PrZhqlH!aZNOwOe11U$5S;UB}3K-5S pkUB^qq!LmJsf83nsv+f&dPu>prXo@j8|Li)S2I&Kc`I|J%qQNwd4B)^ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Seoul b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Seoul new file mode 100644 index 0000000000000000000000000000000000000000..96199e73e73aafacd89e48cb2855a96d7a134e1d GIT binary patch literal 617 zcmcK0&npB`0KoA#c14?7Qk#qN;~H)21*|8mE0H7m3)~$w^8n2PbF# z11Bj5<7Z79v(sWdtRCqDe zrQF$~?N;}4SK)_!eU|oa+)Z_Rl=SZWlDaRvd8LVN^{{vxJ~p>l{!C1ko3cUBW6PlY zZdH<#vT}N9J-znH=fe~0${ffUzTkLIj4PT-sxB!bUMdJ9HS;4`<_Paj~Sf_ zk+0|1^BW>A#EK*IS7G01i1zwqZHGN4*)daOrc5!aS7z80<{zH@sRvJ|JfA{9VTh_J zC>#_L3JZmX!b2gVFj1%|Tof`28-*^a=A#fs)r=HM3MYk>!b+h<3SJ5^g_-^%bwazR G2NGX5oeD|- literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Shanghai b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Shanghai new file mode 100644 index 0000000000000000000000000000000000000000..91f6f8bc2e234bafd484146986bdb289082c3588 GIT binary patch literal 561 zcmbu*zb^w}9LMo*sb7uZVlR)P+QDKF36WCLNNV90hMH8mol%_2lQ6N|X0Wt&|A0ig zYPz+k{ufWWnRwpMAJ9ZRm*-x?E%$l*C$;LT3_WT4b=2NzZC~|=C*8PAnz!SMZcTj$ zt?sL|$L>r!EJ$Z#%XIIr^!v`U`Pj?IXSr#5n@#x|uLk|}K=-#pGy8I==4y|zif-%k z``2;iyrCBIr}1LxMlH>RUUvCRWd{{6H&If#PQe>V40%K@diI|riW5nZK+9zLz?b5# zy+^+If0*`TPqbFdBNLIC$W&ym(@sWaJMDC2K9T^*fTTcjAW4ucNE)Zj!x|DHnUGXS cE+iR}4M~UOLlQb|MkJ;4e>qdO>B@TQ7g9&Lh5!Hn literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Singapore b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Singapore new file mode 100644 index 0000000000000000000000000000000000000000..2364b2178b03853b1771cb3f34b964fdb82e2e91 GIT binary patch literal 383 zcmWHE%1kq2zzaBmvK&CH&;TUbnp+p|O81*^fa^)Zsm)IlPEU;Ixa5)hL2Tkzj{5)q z|1&Z%v#_$Uva>TVB*p^OgGd$zhNJ?J5$OtyJRp(*NM=?r2r)3!O<<5qL% aJOOeq$Ri-S9wfUK)Z7$PHbQ=xXC96|^pmzBY9i$E(szYRd z4$)ym1r=JX=wK4zVTZs&5+Tw-ItbZ8f_MloMX;XlYl9J8y7j!g`@DPJmlw9*H#KtR zbV&VmmH*!DHF90~w61;m<-^IPD*v8jb!|FV<39Vo=KKAg+Le3By2bh2ra52IGZU2h zY@>MZZj{aAPT6vCRT|QtrSa$o*&3S_U-*@53p|k~Pe!(vUlYG;TKiWg^p52T)jWDw zH7{J%JKtQ;fvL3K_2`&xxt-9hm!rDve47rQY|z&6xP;F6rM)9?bLx&ha49Rj{iC|?#0@#v zG@|?aL=Kfi^nhr0Ei6yNys+U;^Fb*r9#cl?1e*ONJiTdB+oRZ;jX>^RI$;TdI~DeS9?cp{|&R?wUw zb6UJiIo4L{A4Y0^O`fqLqvbV>7a1`!W?M6AWZcNek+CDAN5+pNfMkHAfaHKAfn~qC>H1bDSuWlg({)8fn$xc`;|*J#xO-p(2CBaxpP! zF58!Nv~NpYRXxacS-!d{2uRF3r{YPoI{q3ox6z>79b~EdjZFQpRBayLKICa?-8_d% zwdsFX=^riPejHU9;SufGSur^$GurEfl`F}W{HseO5V!v$N=u5!(73pHy0X6C_!}MZ zH968?Z(pq=&L1)*?CISxxkxS~8Ilc2hvY*NA{mjCNX{>9QY0&q7RiewMlvI*k=#gf zBs-EG$&XBc%z#XR%<-k21epby2AKz$2$>0)3YiO;jM~h`VLD_!WI|*{{KqLhcGr>$ F&nGsEUL61c literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Tashkent b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Tashkent new file mode 100644 index 0000000000000000000000000000000000000000..32a9d7d0c9cbfa841cc4e922fd1b486a34b57370 GIT binary patch literal 591 zcmWHE%1kq2zzR5^qLM%w#1>d3+040h@p}VN_1Xnu5}O3XIW{VY|9m<@;^mVClD8!V zq|Rh6kls^vKxR$)0ogeb2jqG@56IV89Z<;8KA;#Qb3n<5_kgnXzXK}T?+>U-KRBSq zeer-g%U=ieFYg>Qp1cjH|Ns9#BQp~OvaljSHgurM$r6)*yw6q3Ne z10!J~j6e~P8Xw;f25kdVAT|eLGmusWMj!|w!NWlJ{0Dg&M1wpIG6Up!5Df|d5Df|h zFbxa{5Df|p5Df|t5Df|x5Df|#5Df|(5Df|-5Df|>5Df|_5Df|}5Df}25Df}65Df}A s5Df}E5Df}I5Df}M5Df}QFbxb$5Df}Y5M2*+JIw=?%LW+KcDklq0A1~R=>Px# literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Tbilisi b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Tbilisi new file mode 100644 index 0000000000000000000000000000000000000000..b608d79748884c4a8271e695fe4ed992a91fea65 GIT binary patch literal 1035 zcmd6lJ!lj`7(i#^Mej!oi)sFjuBWEvF(!Nw+utl!(@z{1AP9d_O@J1p$JSDm^xJEZ=4 zWwv+ALe_1!WO|Za_P%`B9kdnh*?k@FbbIoxX15Qgg-kAA`P^ zFHHY48w@;pXa?^-2#zh*&GGpgMqj<8Ph45D!=tld>Ed`;?yA|5p`LK$mv8;N(S9Rm zPi}PUQ>&Zy^jbn!9%s$y%4a=R-!NyEUu!edFsAV;9AE7GF>&_m+(HyZUQ1%f)@a@N z$JmujwaDPf_T%QUR5FoJsu;<1>PQ|e53X@=jM(lJ6mUb!i8m_c$)!~FAGF92W22lsm2T=&o2vG^q z2~i5s3Q-Hu3sDTw3{efy4N)Fbv_sTG^g|MWWB^G4k^>|ONEVPZAbCI%fn)+n1(Hil xNd}TlOi2fl4YUzr!H#S&G{{}x>-pT*~ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Tehran b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Tehran new file mode 100644 index 0000000000000000000000000000000000000000..8cec5ad7de2f2c14dd4b0a6c375d7198ef7429b6 GIT binary patch literal 2582 zcmchYYfP499L66Mg&7_KDr+uXW>A2@`>OBl2?$bdK?RXRc}!GL6DS2rJfewdKnY<& ziidzg(ZV2aQb-f(1|iY#6i{Yv;wHmQ+)Ul*xi06|`jWw(_s5^>8hp8adm?8ojk6g4 z__fGP9n5D)!Sc2GT&uGlaBROEnCulWC_BJsQ0KUSC!^xE^P~{vV!Nqby`EC;!&0?- z>u&Y(>0SDjnirHuS+n%q6D_>5d+U)Kwkq!=oAg;wEque5X-nWOWwmtaQ6o~+XxHI# zOy5#5=1#P>U2jw3!Zta!evlYfHBgQ}m?tI_1nP;ITKTO`mHr72M8KR<{c4!E3iKbT zgM2Gg@YQ-L&xeUAb<<_Y(H0R}lCG!bJE&<}D&_RF@gi(VhYp{esAhyF=!l88)lAQQ zGIFS!i0a>>qm5ZAy30|<{E;nQKbs}rsC5yuj-1f5izll&x!rPZMw*zH;-=@vA5w3| zl<5T_78NV5$b}wpV$pLhda+Z!T6{lP#&tG{`1VG*q&Y$?t?ALr$~UXG_FCogoGOu! z9;Xvm-c(7k1@i5vVd9-hL*)uvu~_+1giaoONu@Ys$dr3dBDJGRzuW4s-aGB5S5?=l zw6Ya)b>UsHCaYMl-Qc0tC0>^67t9xSz3hA2_v-UlzYW7jU>)YCy z3=v>B8-~BMd-~z;r%sDBBF)Fc$7=O4KS!I-C_LsB`R^-hc(k$}^9xG@u{Qj7EDpr# zKrD|m*9T&OAXW%si6GVpVv(e|N)XEgu}%;R1+h{PO9io35Q_z|S`f)q_|*i1mXo0E7h~OaNg62qQpP0m2Lr zc7QMhge4$M0bvUWV?bB~!WF?^q_0JH(Iu{ziGrX?7#0)$9!|& zQ0AMv?=sK0zK;2pi)(p*(9oOrR#ndawu3hIKg_?zJTr3{^Q_f_nP(>yGXH4qZr&e< z59htzubKTE-)Q!8huJg##CaR@JUbinyxY~xcl>#r_oo*EdGD;f#eV+LRQ3x>hBN z;^D~tH_uiwuW%aAyyD&s=9QgE%)f0<fZ@1tFKpLp#g`zLL|?Ef&LoB651Y0PUK+?m(@b(neGjYGVDY_szIso@Iy zx;l>i`Z8DM4TS~FPiF-)Z(QHRyeX-X_s_8rywA)q*l!NXVE?Se%KY4mRm^{JiD%x@ zr;~ZhotwPRcdX!j;o?yCFV+{ce@V?`e)+&<=D+4=FmKItV&1mq3Eu6A+j;*s*Ps30 y!|MK*x8&n}2S57j|INF&-vqv){k*K>tUl(?=KI;tGsHI5+cL^C#4^Tevftk%?{cC5 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Tel_Aviv b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Tel_Aviv new file mode 100644 index 0000000000000000000000000000000000000000..1ebd0664aa29c0abd722661f761031ec0304631c GIT binary patch literal 2388 zcmd_qZ%kEn9LMqRO}t*foJ^@^$e%I_#mnWdRFaCKU?8`+F@%6)1ZE)}lgJeEm)c)U zw-&XgqFcm9rNg4O=Au^9Xd}28i&V_hACLmvX$1;P?Yz(0SnE+wdeZmq+}GLVDWA8m za6?6+{Nn)}0ASznEwjORPnc1y=ZvwV@dUv>5msW0ETB3++HNcY~I;%{k^ zuXfeR$rpRo*X6CMr!rW23q7j$T!DNW_nA5sUM8n!UX;^AemT>YBz+&I$ywti`L3-? zooo778TB>teSV$%&|aZ_OevM08Z%Y@b<1R++LZGlC)Hr|VKq3oRa~|8hU;>xKXB|9 zEvPxsKkMf|wAoQb+MJ0K+Kqdvw6OL|#@r`r{o$QgwFvEXZ{&`nT2$8i{+mh~jhiEj zz4Hn^+AXrg8y!4iM1M2jzjdhFxb2fE-k6?YZGKCHf5EYGBlZP{f8oAWhP$-I8@DaS z@MIqM$7jB3BrLA-CdR*~CC$0wPY!9&l7DUXE(&m|McocPb*xm~-ZyUC;UCfOJW`}B ze&djycIaL0uAMvdCA9~QrJGaqW!@$&J$tV#&&<_V#BP#|@G*1c^gLNPTxPBsPL|B` zqk2~7^|HEszj^oDn^MBv23PNMdf}VA1?P#!B*tT31^^BPJAJC+@t=lZAOPA7Dj+$EWJXu%Qr9Y77 zl(OPh{lTz7DNlP@uW$ya^>eHB_5B0tq09ODhT|RT;j^jwBX7Q?Do^;#jnC{>Rm~~p zqvcgffA$7*)0%pDtbD@U?A|EV8GYvCGjgTIJ+9YWh?gxh&gfgZX33KmKGL@y9+hof z2ld+5LR8(6r}d|5epB1`l<5xVHB%-(0h6zjZ&RI9ozq;?T=?I7M53J5|GGq8k^qtU z9*0XLEK;V6q%L*L{QEDHf6dPE$!hD#T46nTXuXIy91gzzdJ*yci^W~FF8_m1Cy?bK z>$9~Mh^!D$SBOjI0=0GO}i5(a5Ti zWh3iG7LKeOSvs%T3>*pwdtyKY}1V{~#A|O>j%7D}XDFjjpq!dUkkYXU! zK+1vC11Shn5u_xxR!xwiAXP!ig46{m3{n}SG)Qfb;vm&Q%7fGgDG*X2q(rt>jgTVQ zT2(^IgwzQs6jCXqR7kCmVjQb${>kVqwwQX;iPipfz;q?{b}L<-7LQKY0C zHARZbQB|a@NL_8M!XlMLN{iGMDK1i7q`XLdkpd$XMoP?4W2DF&RYuCpQDWSv ywMxxVYoyp5)keyV)Eg-{{y!@oWEFm4f|dH%oJ4n$J1H(9B{nDC<4$&ag8l@yuiuRT literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Thimbu b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Thimbu new file mode 100644 index 0000000000000000000000000000000000000000..fe409c7a2a40294af6bae4523492be88d38a97bc GIT binary patch literal 203 zcmWHE%1kq2zzdjxvLMWN^_ggiVxsSg`v3p`GcqwTFof`cH2Ov`umIT!3|v0GAq?6E krp5+9(u^U51fzi_{s$QkG7n@0h$hk+E*qd_cDiO<0C>Y6?EnA( literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Thimphu b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Thimphu new file mode 100644 index 0000000000000000000000000000000000000000..fe409c7a2a40294af6bae4523492be88d38a97bc GIT binary patch literal 203 zcmWHE%1kq2zzdjxvLMWN^_ggiVxsSg`v3p`GcqwTFof`cH2Ov`umIT!3|v0GAq?6E krp5+9(u^U51fzi_{s$QkG7n@0h$hk+E*qd_cDiO<0C>Y6?EnA( literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Tokyo b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Tokyo new file mode 100644 index 0000000000000000000000000000000000000000..26f4d34d67b46513491f26c2e661c6e653cc130d GIT binary patch literal 309 zcmWHE%1kq2zyK^j5fBCeP9O%cc^ZJkbvvel>u)1J-1zaU;O1HD54YJFKHOd_`{B;B zM<4F?{Qtnr$OM5549(0y^$a}=7=fDWCNOY7NFU!21}_&N4h{iHGlFmk36A&=1gVFX r6o6=uW56`fK_D9BC=d;D7>EWr4om|b2%FikPnRzXoXRXO%NnJw;gZrHZ~Dt-CNe7~J;ut>LmBT#uUhq> zL;3Ess@2z`YR$zOResW^)^;vc70I0PN580b!D&_LeXZ7eUaElkSp??Ziwz&&$*OZ# zW!3l#QT^(X2tLk=n(R$cd*h1OICxfUI@2q}u@15M@SqBvKBBhN_o%J=8`U=79u*Gx zRrqJMig=}nOckr`^A%#p$gGM^nj&`3BVuDSs{YxWY`8oxcix_m^7xc&9QbPOia(c4 z-Q!ks<&cawJ+*ch4#*b&Evseru9YabU?s*bS*;&Bt>nXQt8MhWY`-42Qps=PK;paA zm&@fG1xpqVvoP-{a^`)>yWw&c{c)I1(=?2I_xYbwM-6?Q?svEhqbqF`FMclWIP}iK zGhJz}d8VyBWduc7pAmi5@fyRSm*GhL!&LPT$uU`Ey1a!6BU5HEX)pOsRk*>R@Z|Rgj9r-gw%u-g;a%hSY`>XRE72%Cpt=Aq658A|)a<+Ug>aDv>ggI*~$=N|92LT9IOrYLRl0dTn*V jNX53gWTa-KXryYSY@}|aaO~4f{J)jEW4ii=+B)|yku?`w literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ujung_Pandang b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ujung_Pandang new file mode 100644 index 0000000000000000000000000000000000000000..556ba866933d37f3cfcf8042045d64e209bae30f GIT binary patch literal 254 zcmWHE%1kq2zzbM_vaCQXy6{u%gk54+C!Fq(ZMYQnu7Ht=87P*v$ zbrTqPz-$2@-w+00Al5dp0AfpqaL*7&h7c00{0{^mYe6)~Y7h;w9z;{%1TK(6bS=05 Dzv?@= literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ulaanbaatar b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ulaanbaatar new file mode 100644 index 0000000000000000000000000000000000000000..2e20cc3a438bb2076bfc1856045075dd041cad3d GIT binary patch literal 891 zcmcK2yDvjw9Eb6@N+K?CNhEG{Ek#vJ>)zI-HPL|-iOWD5i5R?t3E>^Ygq*>E7|vj0 z)0DwzFxXrMF*0<5mk2Ok>zJ@WjijE6*~p0a_vJ_ExoJi=|@>J{Ge)kFQwgiq3X(xWPSFb za-=5=$45dmyc`&f_Xncsdev~oS4H#5jN#g!5iMIm!@Uv|o>-O9IyA_3_Q_?6F9 zDcfxosw3ATdy?mRZ~RR2pPcG}{XH$XwX657NUcA%tPe!Tw88MG9`gCLu-&T<*+%on zi;nb(j5#^+xvo#XhU8`{m9kjV{`g}RBIaYLdC43bnk7>RsYK35Br2SqPV?(Fzb+B| z!=&bal44f=F4H3OA`>GsBU2-DBa_TBsr2DNsr`5P5?Or)zI-HPL|-iOWD5i5R?t3E>^Ygq*>E7|vj0 z)0DwzFxXrMF*0<5mk2Ok>zJ@WjijE6*~p0a_vJ_ExoJi=|@>J{Ge)kFQwgiq3X(xWPSFb za-=5=$45dmyc`&f_Xncsdev~oS4H#5jN#g!5iMIm!@Uv|o>-O9IyA_3_Q_?6F9 zDcfxosw3ATdy?mRZ~RR2pPcG}{XH$XwX657NUcA%tPe!Tw88MG9`gCLu-&T<*+%on zi;nb(j5#^+xvo#XhU8`{m9kjV{`g}RBIaYLdC43bnk7>RsYK35Br2SqPV?(Fzb+B| z!=&bal44f=F4H3OA`>GsBU2-DBa_TBsr2DNsr`5P5?Or>Kf4i literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ust-Nera b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ust-Nera new file mode 100644 index 0000000000000000000000000000000000000000..9e4a78f6a547de2a91e728ac4ab5ffa4884105b4 GIT binary patch literal 1252 zcmdVZPe_wt9Ki8sZOdsLBuZCnr7c^w)NPr}HrL8jY+H%#lGUj{P$T#e9i$+G{y=1Z z4$)ymf2gp)!h=Z+4?7eck_eFwR;TJ9K|I7RMX;XlYX^}o9eZA0KJT9QWw7`6U8e8o zk+AyfTKs3X-N?23-usXFXZK&KW&S-<<<1tWUB}*5|G1NI&)n`=K0R4jG2!d+j0a`q zaIJW6Es<4&c3FM8C^gwHQoHY+tVzBSU-Y@G4Lp`QPfpe?x-5RjnD!Tk^!m?3s=j}> zs-L=~H@rBd1EX2J@xgxGa3if7&&PGs$tE2G&yrlj@fjNURnCei8FI`(i(d?WBAw2d?(+3Y*SEdWZEu$DH&NO7sY;Shy^@*;>-3e9>^fddWRiJ3P%4#d3mkUq za4wv4l)2`7n0sUXb-B~!QtDzSuUO71hf-&*E3=au;Z;8>*ed5=+syvpUA2_E%G{lO zhMiP8qXNN*Ia^gA6f$SnoI$=?DckJI{KJ^duPZTXWZW!9j*J}{y`>pHk^qtck^+(g zk_3_kk_M6ok_eIsk_wUwk_?g!k`9uOrAY|Mh($`4CMP5*Br7B>BrhZ}Br_y6BsU~E zBs(NMBtIlUOOqjzqNT|ZNfOBtNfXHvNfgNxNfpTzNfyZ#Nf*f%Nf^l(N!ilmj3jMo hvPRNI@oJF!he>0Ma=vO;tio-#cvx!EIt4L literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Vientiane b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Vientiane new file mode 100644 index 0000000000000000000000000000000000000000..c292ac5b5f489a88bf10a1263b14e7412479d9e7 GIT binary patch literal 199 zcmWHE%1kq2zzdjxvLMXU03;S=r5~yP|NlQD6B7eNoDEO}M6xh2Bo#1l`1pn}I03P? lfjL762?hhr`yaNg^$3UtSpYJ%9>^wW36~AfDmz_sE&#dsBrE^` literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Vladivostok b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Vladivostok new file mode 100644 index 0000000000000000000000000000000000000000..8ab253ce73555cbbf42ec67a8560acef080fc480 GIT binary patch literal 1208 zcmd7QPe{{o7{~EvI%}xGI^?XSS!&CcZ9hxVoGWK@tT~9-C2KI~AL1=K*dO$PiU=e+ zbSRMsOzL3KAq~cEStkh(br~J3ymSen4jIJyzJE3t(WP6Tq3=1zK%ZA?aOiBC{B>2o zUyYdZ-2LcyEIm6lx3b9>&D7LhT=cj`mOQIZj@Evj$!yLqEpAz`GTvNRx6TB#Zn8n^ z$2aP>D`na+{8hJ~Sk@hhciPzfTATbYwAuSucUIj~pYxUYzRk(5B;6KeEp>yoVYKC&P+@1)vQLMH>B^>q#kY_l4#$k_E#h% z)|k=Qmvb5~k7)c&T#tNe(!^804lMLa^411TC9*4Hg+jqmUbgmdR+K!}tuOhZ^cR0V zcR8IRm#6sej@}mYeBznIB{Kd%s*B%?uQ<#r#rKGLPw{oB9!RFdAM6spWtp!aA102q zrT*ch=C3JmR?2Dl7|u&MG3Cs5&8aEprktE|cFO4~=cf>$FrZMNaG;Q&u%OVO@SqT( zFriSfYq&7TP}tZtbQpXXgcyt%lo*^Cq!_Fiv?#nN#3;-t)F|BS8gdkNb`3oWKL$Yx zLk2|#M+Qj-O9o8_PYO{6QwmiER|;7MTf2rXg|A&hn8KJsnZlVtn!=in83X@0?aGj` K9&WXQmA?Rv8vN}5 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Yakutsk b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Yakutsk new file mode 100644 index 0000000000000000000000000000000000000000..c815e99b1a8f2d4b9bd45d3a6f39c95db5bbf563 GIT binary patch literal 1207 zcmd7QPe_wt9Ki8sId!PS?^0UJTG!8Q%RUXJ=8aEH%pYw@d503Zpg*SN z*Xwj)x3C zyj2o;KdsRp1+seRjW&*dl%~61BsTa`n$NwKmTUd8X3v1EJ@Z^!+pkF5t_Ql#e_Yzz z(z-r>t8`Qz){d!T+L^aeJ6~x0^a`>^^bx+eaIT+ z&x~tkCI4Zh_GvPV6&Wpy@ggHe#_VWEjf@)^IWl%+^vL*;1dt4n6p$Q{B#|-y zM3797R2*$CNHRz^jy4@6A0#0pBP1mxCnPB(DFC;M}GbA-6H%FTslAWVX56KTn z5Xlfp5y=rr63G%t6Uh@v6v-4x70DGz7RlDpri5s(4S?M3@|NsBb$i&RV#J~`x50nFuEDQ|M z84Mf@40RJ2_#kW_-w=i%Al5c8Gd2K{mJA^zSPHb`f7rIpiy#_gIfw>107Qcv0kXFq U$R^7nTsB}w+3A{D85?i`02U)YF8}}l literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Yekaterinburg b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Yekaterinburg new file mode 100644 index 0000000000000000000000000000000000000000..6958d7edddb85d298c5f2b890b21d9ca2056e9c5 GIT binary patch literal 1243 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Bermuda b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Bermuda new file mode 100644 index 0000000000000000000000000000000000000000..527524ed295aba41b9a0448ffd7993c489a2cb99 GIT binary patch literal 2396 zcmdti|4)@w0LSr*n8TY8DHI8qXoVPD;o?OE3^n8qggDB@_#$*N5J8C`K}e#Sl+rJ> z6ajCJVtn}lIo|cDxb9mfueZD{ zCZ^nSvZ`Cn?3u5BUNcAeE$x-_0}l(ktzFu0H;DW7KDl7*J>@@8AOpUsR}XwvrvpF8 zR}Z#6s~0vVsYMlQbx=W=3eE`C4<*j3hgaOwAb1i!B%SC*;B*{@`j-L0Y~ zj>wh2M5!nH8)fupx`^p4l8)XLVpa1x8T+nX#FZClXYH>d-kq#hZ@nN~k>NVQ`Gr_B z&#MzdhgIUt4ZZg636(T7sFTOvQ7JuIuKTW5J=OMuO#RTK)>n7Q4J|cdW6oRh>C#-0 zwrZE$l;#qfem|<+F-v`J_9$E%Fq5}kP~SZ(guFSD*VMRrrMeCAY;$l0DMMf)FO zOG<>?T6az4hWScQ-nYVYcUo?9b%<@#K01F%pUOWor3+?{s=}_bx@e+FZErcQi~CDd zNolKou5-PT+1>K_gT-P;%pv(gd8#P&uasr(2vK$`OO{9ait_UgSut-~RD2#ND`(D$ z-G`&~o{Lkesy;x!*mG7@=iSyXwH;SAu1mVMx>da#d{Xbt*{$}@j>!7NL!y47S2l!H ziiZAn+4yIcc%^fn+<(m>nwksbt9^l@xg=S>cI1wj<73WT-~Z(CdIytiHm`Ri(`T;r z?dSDgRz3^7-g5)Cz^rVKZDX#v#tmuans3j)Sen;76$eAok;NgaLzaiE4_P3xLS%`^ z8j(dJt3;NGtP@!%vQlKJ$XYGUVv*Han&l$vwKNMxR%~gOjI0@1G_q=B*(M}5){QJ2 zS-GWII7qDFIRgqzFhAkTM{3Knj6W0x5;1sRdFDq#8&$ka{2m zK`Mfj1gQy96r?IhS&+IQg|Rf1K}ut3YJ(I9sSZ*eq&`T2kP0CsLTZE*38@lNCZtYC zp^!=;rLr`&LW+e{3n>>;FQi~d#gLLAHA9MqR1GN`Qa7YLKMr z>W35%sUT89q=rZlkt!l(MCynX($Z8CDW#>UB~naFQ%$6tNIj8)A{9kSiqsS-DpFOX ztVmsv!XlMLN^5Cqixk(=R2M0)rKvAcV5GuGiIEy3MMkQOlo_crQfQ>oNU1GNt&w6| ynrb8Ewlwud3XW79DLGPer07W1@&8wLyUF`%llkcEc!$#w8=V~&=ZJH}+W!Xk<^WLu literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Canary b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Canary new file mode 100644 index 0000000000000000000000000000000000000000..f3192156ff043a529461aa9004a8de9dda326f7d GIT binary patch literal 1897 zcmdVaUrd#C9LMqJ2qGUvpA-5QdEdkL@gpEV~`qiI@cUy zpEjm*<+A0Nb4p%NT_Cmo&X%&aWKPYs<;woe(acdgM!)ydO`BKVwE3{Z>ltU`>ihmg z*KTdh_wIVeyT9<^X>}jo6MJH7hcA?l%$yP_@}?HtR#L`qnl|M-CC8js^39Jl{n~qa z;M=2m@Uu6Ra%R9%Pxe~cTW{NpPFeb{JvOtc#b(uRwAocr%P20lhk`|xnVMyDCQi4k zxH4tkny2g^GnF$mO%H!DL67wPrQoq&G`IV*a`%0$yd7s0YB;5E-6hL!>9c~8ew(-Q zpcSSav7-DoD;n*v`6=C+e|5brxYMeI17-Hul^PZI)T^X_p%(2g)#5i(wWKjarTZ4x z;}vl#Ye=ytGOw$=Y}6{^zEWkz_f~o1CtDixi7g#GYfoN#*PiMV%qfLrdRqC1KWm*-?(W;S+q-A-Frl@wI5SQSBC=QVq)X|_n)z`KjeAt_ples znR)S^H^~AM|NCAQiF$KGVQ+PL)P1U>d>04={v~=3r#t2z&KEgh{sU*s!zm-@jGQ!b z*1qnvk@H4Q96593)RA*XP98aXgfR3U~c7%9jt%njv* LgOPBEw}gKHM@+Br literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Cape_Verde b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Cape_Verde new file mode 100644 index 0000000000000000000000000000000000000000..e2a49d248de086306d2dd16a2b2d497a008c8f07 GIT binary patch literal 270 zcmWHE%1kq2zyPd35fBCe7@KF(vsDYuOr4`}sia1LTl~92{r~^}8JU<_SpNTi`GtYu z|NqAi7=Y}L9~e0hYz7V=-w*~}10x_dWME(fnFu06NU#`a&wr5RAR6QV5Djt!$SjaU TKy*D&jBLkn*#I49XUGKr1p`uu literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Faeroe b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Faeroe new file mode 100644 index 0000000000000000000000000000000000000000..4dab7ef0859c244b916d61b7489d7371881e0ca2 GIT binary patch literal 1815 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Reykjavik b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Reykjavik new file mode 100644 index 0000000000000000000000000000000000000000..10e0fc8190a401f67b861ced3b8b16401432a565 GIT binary patch literal 1162 zcmc)IO-K}R7{~FMc3s3G76L_sdZN@of-OT3ifGF^)E;6NqAo5`K~YdqbStrh=!Nu9 zr>&mEQ}hObVC*3X5;d*O)NM6;HCOFLvurJE`hUluOP9Jdf0)lObDQ5cvUS(aW!4`r z->6ryGlzUr;hNonBBBmp){qnZ^h`zgWN8UF^^~1?}89g7= zvE9ezsS+s@sS_y_sT3&{sTC;}sn*q$i`0u0j8u&OzvLVfbs*;_NO)Hd literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/South_Georgia b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/South_Georgia new file mode 100644 index 0000000000000000000000000000000000000000..446660861227aa8ceb7084f48c3b2654ea64f4dc GIT binary patch literal 164 zcmWHE%1kq2zzdjwvLMXS03_=F|Nqa(`2YXi0}KrR|37}fz~bW@!k}wl#1KM)NkBvX TXSV$Xnt{(mE*qe^c1BzPW>qAj literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/St_Helena b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/St_Helena new file mode 100644 index 0000000000000000000000000000000000000000..28b32ab2e0b9053f39a91d9f28b6072e41423954 GIT binary patch literal 148 zcmWHE%1kq2zzZ0GvP?kCG3nVP561uh|5!kkv-tRiFt`J82nmM#2LhZ1aRE&;-~s@2 CSQl9U literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Stanley b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Stanley new file mode 100644 index 0000000000000000000000000000000000000000..88077f110715ac1e349708821ac1e00f35bf6395 GIT binary patch literal 1214 zcmd7QK}ge40LStFQn6NtgaW6jvr?RCzHK^Fr#(~Dmf@;hT!&^vXb@4iPP2lNAjrCR zsF0|jSCD1kuDvUY3)*vzjw&Y`$d&~T_K;$%&DjMwVV%~ z5}uM@((`g!m3>Qj%WobM8=g;jE6(?c${YJt)sc|&PIRj3NU7X7TBSDmmgMFEm#SIy zPS*M>MeU~T?~F*?jn6f3)-X?R?i&Uvzss zlaQxZN4wi^C3cK_iT0FTNc46;i}o%ZOY~LWjrJ|a|5$S^E*G^$wjUW<#%N# zbAxC6`J~p`Rj^{&Q&ec4k%5tsk)a*U*vR0>=*aNM_(%Xq1g0H} z5FAYmNDxRANEk>QNFYcgNGM1wNH9n=NH|D5NI;GzA|xb76B7~?5)~2_5*HE}5*ZR2 z5*rd65*-pA5+4$vqlpj+(b2?+1c^k6go(t71d2q8go?z91dBwAgp0(B1ng)cMnZNp fF(W}cny8Vmk+_k-k;pM=w)`(bcZW^(T|xJ6rOjxH*U)-=Z=%8eBQtBVe#Il5_B8|$WGX7+pDy6mRAdfx5#ynCJ|%$97M)faB@d)n--6Wy9! z)@*ZZ$mXtoP4nu0)ZKIUYJUEp=8s>~g2XN@7`~*$uwzQ>dPfV#g1Wc$GfVp7s4Z%G z%aXerET!~_`HvS_>gIA=+?ZxdmS@`1jZv01E8do+PS~;=vh=t}rCsE5}C)+fB#Y(RZS=n%}mG_>tN6uf?qi+ssbL)rN@?w`BYid`;wqts{^nfb!f~rcd zR&_$LYNB&gJH5fS`YLVf&qcOvG|TEfPqXcP_t+EfM%k06Z?&ghnXsqrn(e6n*6O#1 zs-f&RHRg{gm@%Sf5(l(1rboNN-qx;(Q`$XtR88NQ_I%o)XFsUabKQsS`Hp7WdwhpA zAE>Z>jT>x|@0S12BOSizF0xLZ^|@R9a=XI*I@c8hv?@D`qbMNxd<-u-us>jfzz%^edUksRHVNz!vrW%#pO}q$c00vv6|+~&W-+_PY!}!sX2X~r16v06 z3~bu7+cmIl&u-tq#yz{816v37j@dkB_n7Tt_K#@*rURH3V0wUQ0;UU?Hh6Y@z%;_M z>jb71m|kF-0dxas2hb0oAwWlfmSB1UGzHTYOj|I00UG1kbp~h+&>NsRKzD%l0Q~_P z1at^!5vE6&CSkgSX%nVTm_~Vaox-#V(<@A~Fx|qm3+NZnFrZ^V%YdE%O#`|Hv<>JR z&^VxTnAUlAy~8vQ(>+Z4F#W?c5Ys_S3o$*!G!f_`&_ZW=qAuk ppr1fPF&)LU6w_1ue{O0xbzPL|r?g20ss7~DWPeh@Qk1eJ{7;jB{Fnd$ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Adelaide b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Adelaide new file mode 100644 index 0000000000000000000000000000000000000000..f5dedca59e2b220f7395c73f60ff26e610373e8b GIT binary patch literal 2208 zcmd7UZ%kEn9LMo<|1iFn62urI4dPFx6n`#Y3=9!PQj!aVHv3bXr5f#ZYxJjS>WTYaJ;N@Ix&FT1@@lHw`uTSGPL^3@Q$sFIP_e}N3y^)KW zb?K01_b=3(lOfIBRw3SljhffIUh}(3v|vfOE~-n>`;zBtVZNn>e@1K3yksf*YD$a$ zn3lz7$Mya%C#7WI2U&9FoRo$?kflckq-@h$vTX0DF0a@pQO zRUb}`*R`{qx_0^(edPL8t^fLpHcXt?#&<{b(No__)6ivUj=U!=IxLTc24&smh^()F zK^|Y#BO8i3WaGjn*_7my*7%UNIRe^tqfs|cuGYZC5^W#N){eJRbj#~;+WC^DPxRi< zCxhQ;usv3uYM7R;%AaIw@uY0ayd+QGeoneQ?@0IW1G0VUkc7VIlN}dA(sMc>J5Ro% zyN-qRnS1=) z6|yZ`voB<0wq|F@){wm+n?rVoY!BHVvO#2r$QF@3BAc`|yF|8WYxaq3)Yj}2*{ZGC zE3#Q+x5##p{URGic8qKp*)y_fWY@^Hk$oc@w>3LQwr*?oj%*&;J+ggd|40Ln4j?T+ zdVn+m=>pOQqz_0VY)vPSR@j_mK7>{X-gvbP#DF(nF+)NEeYdB7H;}iF6Wa zCDKcznYN~zNIQ{!A`L}4inJ8zDbiG=t4LcNZl~)eI{%I9?gRW~Fo~Us>r80fGl?~I gwL5D!Hip_}7cVaG@+`}j=grB>@n-oJL2g0J-ZwkLDAd!93UFxWH1eMHi!l}9ZUnA528U{ z0MQ_CfM}3cKs3lZAeVu>1foIS0s)ZMz%QKLjx`V Df+TPt literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Broken_Hill b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Broken_Hill new file mode 100644 index 0000000000000000000000000000000000000000..698c76e30e91f568a29daca12993cfacbfdbf83e GIT binary patch literal 2229 zcmd7Ue@xVM9LMqRaYww56hxho2Js_i6h96y28M_tDairhWd{Li{y;$T!om|xS$X4K zHb+)^b8MN8fvv4&1?t=yb4fYAAT7v|vGk6nrtE zg}+bB;yfn=ck=%W$T)zMiOCUyjwb=PZ4s zYf85TzSclXj67O9E$!t$%J#x>c`W^sJbv>z>2SX(9l!O-j)_AO{H$AcUI1Nq= z@&(;}ETm5y?9e?=HtF7Wzd9We*U@QN`+CiTY&}2VFi&+TY`OosR(O5ZveFe?*7z*T z;jn!Fzl|IC1atJ57w_jxn`8St-H08ozOQiCY-a%3jIG%XvK?EqA7n$wj*u-Od*Vyj z6tXL1TefCj$i{5V&XBFyn!O>LLw1L357{5GL1c%>7Lh$7n?!brY}3~46WJ)TQ)H{Q zX0OO*ZOv|x?IQa{HjL~T*)pUUMmBD1c8+Y_*6bbGysg* zGe~QY-XP7fHQhnlgY*Y!5Yi!}MM#g3CLvuy+Jy88X%x~aq*X|-kY?GMZXxYL`h_$M z=@`;7q-RLekgg$ZL;8j^4(S}yI;3|<^N{W#?XxxgLmG&55NRROL!^mF7m+q1eMB0G zbP{PL(o3Y7NH>vo+M0eM4MjSNv=r$n(p03YNL!JjxH*U)-=Z=%8eBQtBVe#Il5_B8|$WGX7+pDy6mRAdfx5#ynCJ|%$97M)faB@d)n--6Wy9! z)@*ZZ$mXtoP4nu0)ZKIUYJUEp=8s>~g2XN@7`~*$uwzQ>dPfV#g1Wc$GfVp7s4Z%G z%aXerET!~_`HvS_>gIA=+?ZxdmS@`1jZv01E8do+PS~;=vh=t}rCsE5}C)+fB#Y(RZS=n%}mG_>tN6uf?qi+ssbL)rN@?w`BYid`;wqts{^nfb!f~rcd zR&_$LYNB&gJH5fS`YLVf&qcOvG|TEfPqXcP_t+EfM%k06Z?&ghnXsqrn(e6n*6O#1 zs-f&RHRg{gm@%Sf5(l(1rboNN-qx;(Q`$XtR88NQ_I%o)XFsUabKQsS`Hp7WdwhpA zAE>Z>jT>x|@0S12BOSizF0xLZ^|@R9a=XI*I@c8hv?@D`qbMNxd<-u-us>jfzz%^edUksRHVNz!vrW%#pO}q$c00vv6|+~&W-+_PY!}!sX2X~r16v06 z3~bu7+cmIl&u-tq#yz{816v37j@dkB_n7Tt_K#@*rURH3V0wUQ0;UU?Hh6Y@z%;_M z>jb71m|kF-0dxas2hb0oAwWlfmSB1UGzHTYOj|I00UG1kbp~h+&>NsRKzD%l0Q~_P z1at^!5vE6&CSkgSX%nVTm_~Vaox-#V(<@A~Fx|qm3+NZnFrZ^V%YdE%O#`|Hv<>JR z&^VxTnAUlAy~8vQ(>+Z4F#W?c5Ys_S3o$*!G!f_`&_ZW=qAuk ppr1fPF&)LU6w_1ue{O0xbzPL|r?g20ss7~DWPeh@Qk1eJ{7;jB{Fnd$ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Currie b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Currie new file mode 100644 index 0000000000000000000000000000000000000000..3adb8e1bf7c6ec51f1c100538799271d7d7a6e6f GIT binary patch literal 2358 zcmds%YfP4P7>9qa=m=8Da*7C~R-8f(9w8M^990tI1%VV%Ia($NB3ZuOQ|oOlSDBkk zOOVFsiv#JPH5Qp|tPxmSN7EeD*68Hgn&nXGxt{vim%g>GXS=Wep6|cQTT)XwNB_v! zzyBU}%zL6a=h&xB_EJxxUcQiS$8EE`#bcIT09%_#QSOdGUWD~{=|njdxd zti8G?XFyS7HYqx`Q_;V@shFRKEcTOT#SNUZdtcw9_>=86`|t)O9Q0daLz!jKUw9R11GU%6yOmj|u* ze6N-CcG-hxE^5Q81KQa9j!K{I)TX9Zl~uo>%|-jPCA(f*Q_58yQ=p2_OjS;*vntOP ztNJzHs)y38=HvOc?QE1ibZV+SeBu_{{`@t2#D1_HwO?87wm{Vt|Dl~Z!>UicpoZ9f z?V8r3#-NjGymnl>ho4i^m!?NQsMDUew&=0$gZ6lv&-NbLVZME3_QcM07T_84AN{0f z!krQ5XqU%X#Ivmm`s=RA^=f%WIw#*Nc|7v|i(QR6G$iOd%)T%i!|V*RHO$^Ho5SqR zwX;3U{xBQF>=3g>%pNhD#OxBg+vLGM!PzKcr@&T$y<#>C?AEojUCe%6I~&IA*tN4| z%$_lu26hc>8`w9nabV}b)`7hPn+JC9+Sxv^f1m+C2V6TX0D9osX#%DTm^NVgfN2D# z6F@64y}&dB=myXZpdUa(fR4C!S_1S0(-fd9n6?0Y!88Ww45l?eZ!pclbO&e;rawS~ zFdcI3vr!cJodWC5g&@D{6fPP^bhUpllWkAndJ52++2DA<6 z8_+nQb3p5W-T}=6x`$~Wrhk|QVmgRvA*P3}ohD+sh-o9HkC;YcItjEA=q1ohpqoHD zfqnuF1v(0}6zD0?R7_W0J8i}E71LNuXECkC^cK@xOm{Ku#q<|wFwkM3#XygNCIek| z?X(%_Gtg+D(?F|%USpb#={Ba_`2W)HU`jqaIf<&r=O!m5Bqt=r=gvckbA$f`>c{K^4dO zc7qOPMkWYkV5nLFRL?MZ1tU;%>kI~dp3EU4p68-P>i_@$&&fL85DoGxmG$;(fG%y@MbUn~6O2dN71{^MSx)xR@rd$9)WNteE literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Hobart b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Hobart new file mode 100644 index 0000000000000000000000000000000000000000..3adb8e1bf7c6ec51f1c100538799271d7d7a6e6f GIT binary patch literal 2358 zcmds%YfP4P7>9qa=m=8Da*7C~R-8f(9w8M^990tI1%VV%Ia($NB3ZuOQ|oOlSDBkk zOOVFsiv#JPH5Qp|tPxmSN7EeD*68Hgn&nXGxt{vim%g>GXS=Wep6|cQTT)XwNB_v! zzyBU}%zL6a=h&xB_EJxxUcQiS$8EE`#bcIT09%_#QSOdGUWD~{=|njdxd zti8G?XFyS7HYqx`Q_;V@shFRKEcTOT#SNUZdtcw9_>=86`|t)O9Q0daLz!jKUw9R11GU%6yOmj|u* ze6N-CcG-hxE^5Q81KQa9j!K{I)TX9Zl~uo>%|-jPCA(f*Q_58yQ=p2_OjS;*vntOP ztNJzHs)y38=HvOc?QE1ibZV+SeBu_{{`@t2#D1_HwO?87wm{Vt|Dl~Z!>UicpoZ9f z?V8r3#-NjGymnl>ho4i^m!?NQsMDUew&=0$gZ6lv&-NbLVZME3_QcM07T_84AN{0f z!krQ5XqU%X#Ivmm`s=RA^=f%WIw#*Nc|7v|i(QR6G$iOd%)T%i!|V*RHO$^Ho5SqR zwX;3U{xBQF>=3g>%pNhD#OxBg+vLGM!PzKcr@&T$y<#>C?AEojUCe%6I~&IA*tN4| z%$_lu26hc>8`w9nabV}b)`7hPn+JC9+Sxv^f1m+C2V6TX0D9osX#%DTm^NVgfN2D# z6F@64y}&dB=myXZpdUa(fR4C!S_1S0(-fd9n6?0Y!88Ww45l?eZ!pclbO&e;rawS~ zFdcI3vr!cJodWC5g&@D{6fPP^bhUpllWkAndJ52++2DA<6 z8_+nQb3p5W-T}=6x`$~Wrhk|QVmgRvA*P3}ohD+sh-o9HkC;YcItjEA=q1ohpqoHD zfqnuF1v(0}6zD0?R7_W0J8i}E71LNuXECkC^cK@xOm{Ku#q<|wFwkM3#XygNCIek| z?X(%_Gtg+D(?F|%USpb#={Ba_`2W)HU`jqaIf<&r=O!m5Bqt=r=gvckbA$f`>jMJy=;jG(DAOR!g&UdfG30@Y}OA zHhYj3g(Y2V6@(E)Wl=8LO2&|gh$I?qQCSxuUG!T7{RXkq@BL@jgWU|~!T;+VypRLm z_b0qK+A!Yv$Dd91uY>GwQnP)0_*cWzgixVLc(Ff{m|iQ1J!>P$fvJ+*Q5H$*OP7%? zZX~rkPCnXtP^BF^Yd)@4D!sW!Mon+kqodEwm{IHX*y3Nz*jK;njLZ&`arZ}^8NbhD zp8sBd+P}tRwO?1+y?bSxe5Zn)tL3w*X5}6(5wEsHjc*J}PJU2Ls2C;_Q-`TZ-fNlk z?zIY~3^Acc_f>AkGnst-ikk9UugN>ztMjj2HU(c_)>DrkHH9mW>Sj>LOjzQEp0)g}E1$c|G=?K~WjU3)6j?#8*YI~I!t;s*Tv8W{H%U!1A^X0eS4O^^6D zoGWs&zV>X9)AhCIi=42pJ!9mQk#j~)8aZp^w2|{hP8>ON}ND@dENE%2UNFqokNGeD!NHRz^NIJeYA0#1Pn-P){k`s~?k`SW@B#mT^q>bc_B#vZ`q>ki{B#&f|q>to}OaL+i$Q1b6IY1@>nFVATka<8R0+|V9 zDv-HACIgubWIB-fKqds45oAhy?VKQ!g3JmsEy%ne6NAhQGBwEDAd}mVWe@;)8%zVe k4gw(WgK1z8fB+~MKmZgJAQ}`LAest6!UYN(T|)yd00dHiMF0Q* literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Lord_Howe b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Lord_Howe new file mode 100644 index 0000000000000000000000000000000000000000..9e04a80ecea45473faabeb609eb06cfe62193d48 GIT binary patch literal 1860 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/North b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/North new file mode 100644 index 0000000000000000000000000000000000000000..74a30879bc6180d588a706451226cb4c95faf79d GIT binary patch literal 325 zcmWHE%1kq2zzSHPqMSe)#O7-N5_9}ccFfsh#&J4i7su)2IUQ%V$99}u?$>c{K^4dO zc7qOPMkWYkV5nLFRL?MZ1tU;%>kI~%Tj6xbd4;gu z&K#f(40RJ2fz}l?FmOUhAKwrL$8Z-A5gfw6z{toDLV~0J13}3$u_quJ+uWJp!UZo&nJy4}n|)@)Vc`dJIH^JO`$M9t6=KPl9QnM?o~mvmhGeVGs@SG?)f@ U97KaW52h&%04`8a=vr_A0IP9yp8x;= literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Queensland b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Queensland new file mode 100644 index 0000000000000000000000000000000000000000..7ff9949ffa93e44835ab133998b89e440094f909 GIT binary patch literal 419 zcmWHE%1kq2zzSHPqJlsg#O7-N5_9|xHO$$g&u}_qGsEfQsSRhghc%pC?%r^2K{3Pm zcFhLn0?P&#UKs{e&$A4w?_V*fYp!QdKYxZnlXD`2=K6IE%#2K^kb$AU0%$J7tPPAn zOL`VCa6(8Q-w*~zR~HZw9KyiB$jA^vf>ZwkLDAd!93UFxWH1eMHi!l}9ZUnA528U{ z0MQ_CfM}3cKs3lZAeVu>1foIS0s)ZMz%QKLjx`V Df+TPt literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/South b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/South new file mode 100644 index 0000000000000000000000000000000000000000..f5dedca59e2b220f7395c73f60ff26e610373e8b GIT binary patch literal 2208 zcmd7UZ%kEn9LMo<|1iFn62urI4dPFx6n`#Y3=9!PQj!aVHv3bXr5f#ZYxJjS>WTYaJ;N@Ix&FT1@@lHw`uTSGPL^3@Q$sFIP_e}N3y^)KW zb?K01_b=3(lOfIBRw3SljhffIUh}(3v|vfOE~-n>`;zBtVZNn>e@1K3yksf*YD$a$ zn3lz7$Mya%C#7WI2U&9FoRo$?kflckq-@h$vTX0DF0a@pQO zRUb}`*R`{qx_0^(edPL8t^fLpHcXt?#&<{b(No__)6ivUj=U!=IxLTc24&smh^()F zK^|Y#BO8i3WaGjn*_7my*7%UNIRe^tqfs|cuGYZC5^W#N){eJRbj#~;+WC^DPxRi< zCxhQ;usv3uYM7R;%AaIw@uY0ayd+QGeoneQ?@0IW1G0VUkc7VIlN}dA(sMc>J5Ro% zyN-qRnS1=) z6|yZ`voB<0wq|F@){wm+n?rVoY!BHVvO#2r$QF@3BAc`|yF|8WYxaq3)Yj}2*{ZGC zE3#Q+x5##p{URGic8qKp*)y_fWY@^Hk$oc@w>3LQwr*?oj%*&;J+ggd|40Ln4j?T+ zdVn+m=>pOQqz_0VY)vPSR@j_mK7>{X-gvbP#DF(nF+)NEeYdB7H;}iF6Wa zCDKcznYN~zNIQ{!A`L}4inJ8zDbiG=t4LcNZl~)eI{%I9?gRW~Fo~Us>r80fGl?~I gwL5D!Hip_}7cVaG@+`}j=grB>@n-oJL2g0J-jxH*U)-=Z=%8eBQtBVe#Il5_B8|$WGX7+pDy6mRAdfx5#ynCJ|%$97M)faB@d)n--6Wy9! z)@*ZZ$mXtoP4nu0)ZKIUYJUEp=8s>~g2XN@7`~*$uwzQ>dPfV#g1Wc$GfVp7s4Z%G z%aXerET!~_`HvS_>gIA=+?ZxdmS@`1jZv01E8do+PS~;=vh=t}rCsE5}C)+fB#Y(RZS=n%}mG_>tN6uf?qi+ssbL)rN@?w`BYid`;wqts{^nfb!f~rcd zR&_$LYNB&gJH5fS`YLVf&qcOvG|TEfPqXcP_t+EfM%k06Z?&ghnXsqrn(e6n*6O#1 zs-f&RHRg{gm@%Sf5(l(1rboNN-qx;(Q`$XtR88NQ_I%o)XFsUabKQsS`Hp7WdwhpA zAE>Z>jT>x|@0S12BOSizF0xLZ^|@R9a=XI*I@c8hv?@D`qbMNxd<-u-us>jfzz%^edUksRHVNz!vrW%#pO}q$c00vv6|+~&W-+_PY!}!sX2X~r16v06 z3~bu7+cmIl&u-tq#yz{816v37j@dkB_n7Tt_K#@*rURH3V0wUQ0;UU?Hh6Y@z%;_M z>jb71m|kF-0dxas2hb0oAwWlfmSB1UGzHTYOj|I00UG1kbp~h+&>NsRKzD%l0Q~_P z1at^!5vE6&CSkgSX%nVTm_~Vaox-#V(<@A~Fx|qm3+NZnFrZ^V%YdE%O#`|Hv<>JR z&^VxTnAUlAy~8vQ(>+Z4F#W?c5Ys_S3o$*!G!f_`&_ZW=qAuk ppr1fPF&)LU6w_1ue{O0xbzPL|r?g20ss7~DWPeh@Qk1eJ{7;jB{Fnd$ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Tasmania b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Tasmania new file mode 100644 index 0000000000000000000000000000000000000000..3adb8e1bf7c6ec51f1c100538799271d7d7a6e6f GIT binary patch literal 2358 zcmds%YfP4P7>9qa=m=8Da*7C~R-8f(9w8M^990tI1%VV%Ia($NB3ZuOQ|oOlSDBkk zOOVFsiv#JPH5Qp|tPxmSN7EeD*68Hgn&nXGxt{vim%g>GXS=Wep6|cQTT)XwNB_v! zzyBU}%zL6a=h&xB_EJxxUcQiS$8EE`#bcIT09%_#QSOdGUWD~{=|njdxd zti8G?XFyS7HYqx`Q_;V@shFRKEcTOT#SNUZdtcw9_>=86`|t)O9Q0daLz!jKUw9R11GU%6yOmj|u* ze6N-CcG-hxE^5Q81KQa9j!K{I)TX9Zl~uo>%|-jPCA(f*Q_58yQ=p2_OjS;*vntOP ztNJzHs)y38=HvOc?QE1ibZV+SeBu_{{`@t2#D1_HwO?87wm{Vt|Dl~Z!>UicpoZ9f z?V8r3#-NjGymnl>ho4i^m!?NQsMDUew&=0$gZ6lv&-NbLVZME3_QcM07T_84AN{0f z!krQ5XqU%X#Ivmm`s=RA^=f%WIw#*Nc|7v|i(QR6G$iOd%)T%i!|V*RHO$^Ho5SqR zwX;3U{xBQF>=3g>%pNhD#OxBg+vLGM!PzKcr@&T$y<#>C?AEojUCe%6I~&IA*tN4| z%$_lu26hc>8`w9nabV}b)`7hPn+JC9+Sxv^f1m+C2V6TX0D9osX#%DTm^NVgfN2D# z6F@64y}&dB=myXZpdUa(fR4C!S_1S0(-fd9n6?0Y!88Ww45l?eZ!pclbO&e;rawS~ zFdcI3vr!cJodWC5g&@D{6fPP^bhUpllWkAndJ52++2DA<6 z8_+nQb3p5W-T}=6x`$~Wrhk|QVmgRvA*P3}ohD+sh-o9HkC;YcItjEA=q1ohpqoHD zfqnuF1v(0}6zD0?R7_W0J8i}E71LNuXECkC^cK@xOm{Ku#q<|wFwkM3#XygNCIek| z?X(%_Gtg+D(?F|%USpb#={Ba_`2W)HU`jqaIf<&r=O!m5Bqt=r=gvckbA$f`>zl+Ln#;nuZlq_dEl60C@%<WR zO=e7y=IElrXial0qS{y?vbyL%nxh+|+FUmkGqeBasmpGkU1S;z5 z7U>_E^!L{noq3;P?r2~4p|$s>YB2DQ1_x^G{Fzc4>dLbV9YGC;l5Ao_rcIhWLt#bn z7WPYqg{NM(@Gs&lBI>e5y!*RFUhTJ=PsHk$ufEmf)@zz__5($2zNA~*IyE(`Pq(!k z(CrB)HLa{p)Bf16=!|?tUpZkhvuiA7;8~0FXEnWeNN#pd5sVT+p5ZSnGDwq(O}OP`rwOa0@v^tvn~K3W+Uzq8D)F}t_- zW4mu;M9WT%YWcZdWgYxT_a8g16}6|da{oD7l@rqH>UPUcdChWGw_0x48s*Kcw7g$C zm4D@B6?}O>4-D+mnlp7;+qF@JNAtBVl&J@s7pSPA#MW2l+J>TgtawGD1=3=zWLBh= zMqRVg8$a2`tCy_o@&zj&?z4)%)ArEWi+cF=A#G}VUz?xn)|QqIRc<@1N6Pl8DnF>| zj2hJ>mZ&x+S9MbxZL6=!w*Fjf+eWjk{Z?yJCB_JK|049zU+;u|sP4+O+4BMm_mnm7eN(!Jh7HwY^7n zSnIw@d!}igPKY@z=SwFrbw=*&M|I$>&qxUu@%sBN%-! z2D1^*ZYP+ncy@ciYzDI%%yuyQ;m_C*W=Fu5Ji9$%Hs#sv3bQTGZeN&y4v1ZWDTE10%m`T{h@v+E4d8lX2obAavu?E(4& zGzjPr&>~EaFipaA3DYJ_pD>N`>^g;M6{c61W?{O8X&2BhpkYAAfR+J01DXbO4QLzC zH=uDq=P<4F?0Sc39;SPk_F?*mX&|P9m=!odjCx+4T}=CeTfw qoj^Z%Tj6xbd4;gu z&K#f(40RJ2fz}l?FmOUhAKwrL$8Z-A5gfw6z{toDLV~0J13}3$u_quJ+uWJp!UZo&nJy4}n|)@)Vc`dJIH^JO`$M9t6=KPl9QnM?o~mvmhGeVGs@SG?)f@ U97KaW52h&%04`8a=vr_A0IP9yp8x;= literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Yancowinna b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Yancowinna new file mode 100644 index 0000000000000000000000000000000000000000..698c76e30e91f568a29daca12993cfacbfdbf83e GIT binary patch literal 2229 zcmd7Ue@xVM9LMqRaYww56hxho2Js_i6h96y28M_tDairhWd{Li{y;$T!om|xS$X4K zHb+)^b8MN8fvv4&1?t=yb4fYAAT7v|vGk6nrtE zg}+bB;yfn=ck=%W$T)zMiOCUyjwb=PZ4s zYf85TzSclXj67O9E$!t$%J#x>c`W^sJbv>z>2SX(9l!O-j)_AO{H$AcUI1Nq= z@&(;}ETm5y?9e?=HtF7Wzd9We*U@QN`+CiTY&}2VFi&+TY`OosR(O5ZveFe?*7z*T z;jn!Fzl|IC1atJ57w_jxn`8St-H08ozOQiCY-a%3jIG%XvK?EqA7n$wj*u-Od*Vyj z6tXL1TefCj$i{5V&XBFyn!O>LLw1L357{5GL1c%>7Lh$7n?!brY}3~46WJ)TQ)H{Q zX0OO*ZOv|x?IQa{HjL~T*)pUUMmBD1c8+Y_*6bbGysg* zGe~QY-XP7fHQhnlgY*Y!5Yi!}MM#g3CLvuy+Jy88X%x~aq*X|-kY?GMZXxYL`h_$M z=@`;7q-RLekgg$ZL;8j^4(S}yI;3|<^N{W#?XxxgLmG&55NRROL!^mF7m+q1eMB0G zbP{PL(o3Y7NH>vo+M0eM4MjSNv=r$n(p03YNL!J zly}X7TU&aNwbrPtk9C83W#4Ud=4A6KbRQeH^2yt9KQG3EujHZot&Zf+(6Vahva(%$ zc0=ba2#X`C(@M+Vvr9E`Uy_ptA8P747o-+m)%5X+Ob@)M?2a!t{e<$h*0vS1`fOWk zwI_tuRb?f#uH1-z&f@>Pw(g0U*+sK6!s}sb^I^^8l7hdF}`Ba&Jz4!x`?)^N-K1EQg&RpMHB=XHU!a!O~)?Eq0Om3afOv zS7!3d;$}q4o6@t)wqNROdR*jcjWWM`Aqu%IS&WCo>rPp}HB5>3qZ#?pDpX~u#@y~XjxpsIx89ihqSG`n8FvN-hwKSE@qZMt zA2n1#%J|wkNFk&WQp(rXLW=p?YDhVx9#Rmgh?GQXB1Ms^NLgQ77b)y(D literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Brazil/East b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Brazil/East new file mode 100644 index 0000000000000000000000000000000000000000..13ff083869a9ac8476775587de8476654a100017 GIT binary patch literal 1444 zcmcK3%}bO)0LSr1D=96lLqvr-CL)&Fv}?MSnI)!{Ynh9wNeGo_9f~NbLugbI2!*`~ zb{RT^bcp9rq(Wd}sV7T}Ky=;o)Qgl+x~$gIeCH1+Iyeu*=kQ$S@csF!8|qxvUr&wx zyGY;V_a2>j(iu}6==_zZx~4N^xBsjd@jR9zpF?tV?FW0bt4fT`t(N}#elb4QE(1Qd z_))z~{#x#K1l8P^2sz(!NyQG_kZ~8@t9Z557Vbfn zaJfNli0W5~l`HMUiPIt}>${ya+$WL~Vr263NtI$v%al7UV&kV3_NJ3AmD=-Erq%U| zbk!y|?|CR>(?z)@)~j5Hgzb(vAu>EZnGt*;GDW=19IRJaGp}t==QWW%J}I}|OjXE=i_Wt5q;=q;TvP@*FgGUQxxwT&T@>8VmqeoOE zM#+kSb)qtSN>+Bvi>ir1S$*9v4*P5En))8m=r~Sz*n)lGjx$_hS&lOq2wUtp@7`ET zOT0cSO}g}TTfYCOLO;}@45SXDE(ECrDFvy;sEa|WG3s)VdXR#Uijb0!nvkN9s*tjf zx{SIoq%xx}4XF(&j^?QjDG#X+DG;d;DG{mBsEb6ZH0m;uI*qzeq*9|U6{!^|7O55~ z7pWI17^xU38L1g58mZc-%SP%p>cWxAkZi+k@AuHkp&oV$vAuBWLr6FrG>ct_e dLzaiE4_P2K>Q)wPgJI$SSYc$2-eRsh@()nK$prua literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Brazil/West b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Brazil/West new file mode 100644 index 0000000000000000000000000000000000000000..63d58f80f556e1c3135d6dbcb2a2dfc6f61b4fc9 GIT binary patch literal 604 zcmb8sJ4?e*0EXctUMTUlxHza)*A@=8gNVrSGO8d11b;w9aB|VD=-OQb9URr^jIDGy z;85H|(V?`pi(5biFQrwE=gkj@m=K;oAmMuxY;NbKo!BF3pLW@+|L8KmTpZeXE&i;j z(%YiEY8;B{Oj%aLgshFc=vrw@)H_qMaT1EB`nhZd3*!BFK!5b?h)=yMzXnsPwLU9b zm3z_lo4S3`t2*JZ{4NyK=*_7d+kaN$XG=PnsjG>DJvrI;s8ae`rgL{9Z;bKW*wZtn zQg$3;9&X)kd#|0u%4*=GMaEuPC-}!w`!T~>WO1ZjjVwpjBLyOD1*Alzt$`Flsvu>M zI!Ga;5>g7Og%pdl)sS+LwjNRtsmOn%BvKP8id03)B6X3%NM+31cg1#gy+2C(bGG+< G*8c@X3VoGa!& zHI{QoS}|75PF-NFp|$>w7LwIi!*Xr8vVU`K=IqZ{{oYSqcGF!wXM0{}zpLls_jyOw zZEGp={_(l+@6%mQ{?8bg8Q3^5dHl@2sh9?b4(XXUr2V~nG&ZAM*=GdjZVOd9+lACiiE0U(!H7o40;@^~#{i9N6f2lzH zQ3cMvskD=?=wLo?Z(Okg__fCMb0UOL(^87@S&=*zp|>+-`dLfw{7LbnB8>pd0Q2G$*RZS zQqAr@t3CLvZff0XIn%2##yRKD{>MGqDsMXrw0XiLEEFPv)~;a}~6 zWY0SDQ`C9pYwJonudZY7S@-EFJ^1RdJv1?@?R($Rj@Y0c?jBOl?jFT?7sUS;ex8?P zUV`Uk%!_l^_OCZ5p>SQq3xy-@FfK0gFE0Kc?&0$Lx&a^~K!$*f0T~1`3S=0_IFNxL zBSD6Oj0G8t`#_J;Aj3h%gA5265i%rXOvs>+Q6a-Z#^vhXKLIQ?F3<(($GbCt8)R3?taYF)!L=FiZ5<4V#zAk!5 u_T literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/CST6CDT b/venv/lib/python3.8/site-packages/pytz/zoneinfo/CST6CDT new file mode 100644 index 0000000000000000000000000000000000000000..ca67929fbeb05083c63e8319dd9ebf65b3d75e4d GIT binary patch literal 2310 zcmdtiUrg0y9LMqJpvE6LNEU@iQd%$u zEKB|4CfI*?xV`q_JGSePPak;iPdV5Yqq|=`CtvLh>eDl>$m!}xbM0!a8olHv>ItR4$_0N5;M_k%wPZ zQRaD>c)mkNe}B|?Pd4h96MM|0H}HtY1>e3{)+p))#W zN@i`7%Gwkma|+AV-AgY^cJcx>H|uMe7oMncrd~2R7lUg4=$B@}=jYWu=iV|4kBsTu z_n$NO?jF+jy(DH){Yia)>n?eq0-#w)TcF-ZrOpOL_rN0(*yN!c&c zRQa^;O!;R@RRoWll|4VH%ArnE)%vM=xPPlzRdYx^(p6<1E&fQh`v>v^two+=m zZF+5CuB;tir)!gwr1qO4T^H_=y2C!b{^HN__&&dS;#A0NXi8O29=TxZ%e+c!zF@X&O4Ex5T%}mi}Y9`RY2^+SQ@Aoh_2>Esgr=KA*I# zTA`omj1iCWsIYPN^#xAS z7*og|gF;4y3=0_-GB9LhPCGPYY{=k{(ILY_H$FZXAZJI&F+^mH9D_tgi3}4NCo)i{ z9Vs$YryVQDV3E-x!$ro63>XaRa|{|8HOH`#adQkD89B$$k+E|O-f2gV3?CUk z5&$FuNC=P^a0CH~0!J8-IB*04i3CR|oHiCnFq}3TNH~yqAOS%lf`kN#2@(_}DjZ=! z;=&OaBr+VKL1M!Z9H)&AM|hCcyR;_i5LM^KTda)cF$D@S0F$Z~`h zi7iKPoi@5ic%3%BNPwL-!bpgb7$ZSOqKt$Yi8KE10v%<$J=gZzS3D;@D?P(koSB)P InVu2#H&QWvHUIzs literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Atlantic b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Atlantic new file mode 100644 index 0000000000000000000000000000000000000000..756099abe6cee44295a5566ad6cd0c352fb82e64 GIT binary patch literal 3424 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 PW1>=HW20lEV*>sFRXeOf literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Eastern b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Eastern new file mode 100644 index 0000000000000000000000000000000000000000..6752c5b05285678b86aea170f0921fc5f5e57738 GIT binary patch literal 3494 zcmeI!Sx}W_9LMp4A`+sAikYIhq=?EQh6_?+E`)l-1x#^!H1rH&^5lY8h%GMZ)G&<( zl@6x3Vul+gX$Wd+)08OgDL$H#3+RJ;qUZE{-`j5Tu8UsgJ)bkox&D3saS2IN!)*U} z>X`rV^4u^l-@waFg%5>%F-Ky$v zfxf-JOx(#oA@%A4QJuL<-d&I_?xkeO`xEDh2eE1LVV|+$QAmP(+;Oh@%O_Gk@f@R` zJRYrUuJ=|?&qnBHM_VfA9)IoH=u)<9r*>O%S=E}WbZzMr?&6uOGfWAOs7tbL=mFu` zx7UxyZiaWYj%{~=z z__*%p@lR)ZkT1<&e`+!k(Tihwg4GV#nF#uq<~mJTgR%m{TD}`uobb z_@g4O=AIlCo+n0K^U!-;n(IH|=Rf2Q`_zK6bkuu5So=Do-N=~adC6cou^z>uZ>YY@7 zJtMzNrNle6%q&pvhATZYC0ot%JD_LB&Qr6Umt< zeE)2uNY8M{`FmQ4j0rJv!Iw5s%k6poYP&zrum4lOb-4;w*laG>kzzM@m#c7_&C~ks zZGAQzVvn;8=x^SU=6%b&!{W?%*=%msN8EFap36KlZ>LovI;YY?F2>=oSBm_tdkRTvYK*E5;!O{c* zi3Ab~Bo;_8kZ2&`K;nS}1c?X|5+o)_P>`q~VL{@81jf=t1_=!k8zeYrMTakhhsVSR z2oMq>Bt%GzkRTyZLc)Z^2?-PuDN7S7BvweUkZ2*{LgIx442c*LG9+e5(2%GhVMF4E z1P+ND5;{v0J0y5W^pNl&@k0WLL=Xuf5}O(dL1 zJduDR5k*3Z#1siC5>+IuNL-P?B9TQxYiVMO1Q&@e5?&;}NPv+DBOyj&j072pG7@Ga z&PbpwO{9@fTbfuS!L~HfM#7E68wofPaU|qO%#olYQAfg##2pE|rHMQedP@^~B>0vl z`bhYZ_#+1Zas(iU0CEf<2LW;vAcp~R93Te*awH&!f~7eYkb}X}91Y0fU}=sAM-##_e!|ATe{f01&0NPcCmNu8r(HF)a!2+Ad$WR literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Mountain b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Mountain new file mode 100644 index 0000000000000000000000000000000000000000..cd78a6f8be1dd55ac5afd25bbae39bd5706e42d1 GIT binary patch literal 2332 zcmdtiT};(=9LMn=gaRiXew7#s8fi%oAPgR%o+LOR8etU34pxx5GcCklf+M=| zTN$&N1S(-`g{f;cHqabyJ?PwVxvWIX%4XTWs3lG<2AKs_EIC}Cz_u&C~b1>BO?08vv{9DcLmwuEz?Nim>#!sX#`mzAI<*SSoL|uMSUjWYZX#EL#C8oGgI@&B{Y51ge9Dl zaDBwM)Ude5cAM)j^h(6pVHJ6#O`<;RRnc$vX#IMdx}kH6zHwu{y2)For>!VbF~tw+ z>A6Yj=A=7x?3_X~BiyBD1}B=Czs-}lZ^KQzKTKvF{mIOJ|FYcDd%`66X6ajB7%+1x z0(x%aXX>`>Z}ja;-c$2pj_Jf?QHc}hCCRl`C5;}Hf7(ku*3);V#1s+>y^I(Pi6$~*pxzWb{| zwP?Rf?it*r7H|7m?%lar`1^=1N^Ma^r~7qr zWQ{65*r}IX$yX(B^vTjQ)yCb@ArF7B*et8|N@-Vud1O(El=*^9d3>sPD!wzGYtd4f zecV)jpQ5W~UsP2iQF_J1h+4UKOg}o>ud3Vq`mv!-Ra19Juj*c-9(SLT+KvwMMCt)~ zvcYTWBDYI@QHiO);**BNRMT*xO1z=b#`|ubH2(0bS<|&#KXocfJ?+cY&kT&Irph?o zyv?tk&HhWTZ91gZ#hlmcmvyQ26XW8`IbeLF=VU|dcC%q_n6ba=twOVpRcqEDKo|vM^+2j&^Ct+K|N|t3#HDtPfcrvO-6@L}ZP~ zA|352k!2$5&fT9L&ft3{UUXxED@7+EpLl94rYEE-ug$Fh-ib1WQLImgnG zwR0>USv|6RWc`k|07wOp5+F4|ihxuBDFadmq!36YI7)%kf}Bc$b&&EP^>MTXLMp^jBBVwfMMA2?Q6{8L9ECzE zg_H`Z6;dpuT8_3{NWC0w!H|kM+L9qP<0u+ZHKc4v-H^f|l|xF0)D9^gQawjoKBRt* zwtz?l9c>Ab8gdj7sUk-ikveh|5~(CdDUn(t#YC!!loP3^qb(>>QAb-+q^6Fxs7O_j zvLbcmC@fN0j?yBvwrbMk?%RON`Xm(H0r0GE!!w&Pbt=N+YGl|7WdT ZHsT9y%v0Q1X_;y1DejDnw2ZWL*WZc*ZxH|h literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Newfoundland b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Newfoundland new file mode 100644 index 0000000000000000000000000000000000000000..65a5b0c720dad151ffdcba3dbe91c8bd638845c6 GIT binary patch literal 3655 zcmeI!c~F#f9LMp+gDcHj5j!juuoOA8R?9L2`Du%oBL1}16dpAygY5AtBXOLLDRsuQ zV=|z!f|Lj;T{Skl>`^gCP5U`+bZv-ep}BY;${S9wkjrz@V&n5bgwR^MMy}GWhrN~q8T=CXJi%T{=?R(7`biKZ&r~8d% zEv|Lu1^1gqt?R96J$!GcYw)1IBJHpcDhebBS(ht+X4j?JF^eFFLWr`K5ro=#C;jcF|o-WQ_| z_5VqHEy9(G_(B|xZBU1gm5C#r!sLPU z?y9;w&ssg=&ZwyCyNaIrza={4jEFwfBzt|Y#8vygmREngRa{fKMPB>bTG4yn-oSN* z*~aw~D+7J*&;P3Lkmm#a#!UCebek85y%4)X z7oPPG+ffp@<;WcWtrgYg@NF6X+g28vx4)9;ACXsR-mz?~F)|~^ywgZ9QU;}(sVSX} z)YA(BX#?Z^X$K|;Mz`PL+0POn?e1WHhl02|7a`%zjkKBKx0k*mWNDGi2*y<)A zT|nA^^Z{uE(g~y$NH1)4GmviB>UJRgKpKK{1ZfG<6Qn6fSCFad z9Hcw8x;;pLkOm}Lpq1F4(T1zJfwR_`;h+G>INbmL|TaS5NRUPMWl^LACX2PokUuR z^b%<%(oLkDNI#K=+UkxXEk$~YG!^M8(pIFeNMn)CBCSPwi!>MMF4A6G-Cv}^wz|Ve zi;*59O-8zmv>E9$(rBd9NUM=vBh5y-jkFu-H_~uh-EpMlNY9a`BV9+@j`SUAJkoij z^+@lL<|Exl+Hb4-k8A*2y#tUfV5|24vI&q~fNTR~A0Qh6*$K#2K=uN%8Iaw8YzJGt zACL`Ut9JylC2aMcKsE)kE0Ar0>K%e?5nH`S zkWFH%cL}mhkbQz|6lA9$TLsxG$Yw!y3$k61{eo;5TfJkDEn}B;d)@d*Rc6BFYT;}ar(2eU89 AC;$Ke literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Pacific b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Pacific new file mode 100644 index 0000000000000000000000000000000000000000..bb60cbced30763c08b6cf73554c8d6651ff387d0 GIT binary patch literal 2892 zcmd_rZ%oxy9LMns{^5_3Cle(?JE@7FBA_UWW*Y8_iKtvj%S61!b6&sk{JuY)g+&F) zu78{!_CH)st-XBr+hU)}gNNn4Ly_j|t*zW(dW z8Ondqtpgv%E7z_#9rRLf6}+LB?zU#Q>Ao~pddv+sJ*S3ANa7_Es@o(?eQUy9^%8z% zpXt?HExnuSRYYBd-0@kp>a%CBR&Q0PJGUC$cVmgVt7xt6mpflYW_Wb}3FFm(xN$ma zaJIQSEJ{ZQrfjyXp!mZtIYIkjoLlxW#w)>pfe&?s*IYQdS?4< z_3%42GVA0DleuZT%>Hzi$y&5t=Ilr?b0_7>Jg+j@F=^tN-(fsm10^TrgvmKSQ7;&D zRW0};M(6q))xzC={iyGNT2$7oAFJJ|@|GXfiz_#(C7C{1`r>x8Y*d{*Ubx;YkEoJ- zcdp5AFO$O9G*eh#AVnbqP0=SaWW|Mmd16PtUip2DTIF@?C#(IcI44f8E^k(A#`V%` zi;t?3$acLhYqwe#2orB=o$>nGWJ6Sy*-%?A8#~L))0Nfo%&7viskB0#JvhUZ=9S3i zUGXM3D7ag9`}{Zm0)bcGbh!e7cTG_DK%jh!E7bY!?YwGMrpGlW-QH|_AF+3i$NtJ) zt{~^}{EIpS?8%$#y@XT(DFspsq!^C28b~>idLRWsDuR>*sR>dPM_U!7EJ$6D!XTAF zN`uq}DGpK{q&!G{kOCnULP~_x2q}`ItrAiuM_VVPP)MbaQX#cMiiK1QDHl>Nq+m$J zkdh%aLyCq}4JjK^H%D7Iq;g2ksUuQI zM_Wmxlt?X+Vj|T<%8AqyDJW7=q@+kqk)k41MaqiQ6)7xISw~x1q_#+Lk?JDlMe2(b z7^yH)Vx-1Mk&!ARWk%}kXbX*0+R>I8sWnn;q}oWik$NKqM=Fk#9H}`{bfoG?*^#;< zg-0syXiJaO9w|OjeWd(I{gDMgRsdN7WDSr-Kvn@+24o!^?Lr_c;b@lvSqn$I7|3cM z%Ym#1vLMKcAWMR*39=~2svygPtc#;v7-VG}?b0A?<7gKLSsi3~ko7?p2w5RyiI6oy z771A;WSNk4LKX^HDM!0h$XYqt#X?rg(JmLVUdVzWD~2o?vS!GlA*+Tg8?tW5!XYc? zXqOIIJ4d^C$m%)TA5;gMUCATqHt^7hF5K z5s4sImBW-o-ctz1OIfDJyk9wlE5VNMb9AR0SH8o0K8Ime^L)c~(HBK>;#@M{a5=^1 z@}BkTp#6HRuUB^_((Lz*Rqls^2hPW`Lbp%db>g{K-MAZa5?2bW#P?n2({6_KIet0v zwK?4#sNZr1Yc}1X`|Xk8!U=ceX0J1vy6h7SJ!;nJl3)J^^zSb%GB@9?|GbIW^Zl)Qq0P3PSX3`Y zpWA<5KGsVQOYP-n`FiEfEqk^6ky^_rk@eeoYW-iXY^}O#duCF0hLh?-;M7k_>ZxBJ z{rIBibu5c`-rKG~s(IIv?!Slpr{XD@6_sJBEH$^*+^6PNho!{4a{|ZD@EQJm&m00E z5s(l_3?v8=1qp-1@il>vNWLZ%5(^22L_@+M@sNN>L?k2<6A9{Tq9S3DxJY1M6B!AO z#72T6(UI^-d}IK=W(3F(kTD>GKt_QK0~rT05M(6CP>``8gF!}v3O6*LRG7d!-P)%6Mh literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Yukon b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Yukon new file mode 100644 index 0000000000000000000000000000000000000000..9ee229c0eb82c6aea7359e0b38677264f3cad8ab GIT binary patch literal 1614 zcmdthNk~;u0Eh9XIix5Y$T_v+lv8S%vo@I`np62SpJ@|PC`Hm>n-T>HGQvYrE;2hx zn`onm5m-V&LAa=V(IP`42qTcnf-J??`7X3-6}0L;&ix(l%EkY)H?$l{xBc<>m@gcj zCUdyQb(+`Uy{VC#6ERvp_Zt}+p6;Bwm@qOO^Q~?AP=@@T)~*&4hQ(6E0kNj#qzrJ> ziojC449d+G!HHQiB)Ue0`h>_Z_e>SGkfGPU3s&LNK|12$4;4AOsMih6DA}GYqq-ib z=sJHH)B0M(W`2@!W%tGUz!x$;X;8$k%pNdtROHRv-8ZVU@UnjHDKd5Z)9GMgDDRSn*WbV?O$a}IZ^Jkul zf{_rtW#W$5+WS*)yM9@0Kk-KI=)SEAt0wi%=1Zz5P3z*KE>bXZ8r18-2JS#aJgQ7K}bbNNk~mdQAkxtSx8+-VMt|2 zX-I9BrZ}WJOH&?FpQR}fsSqgsS+s@sS_y_sT3&{snyaHi&SfA%0=q6GzB9S XBPAm>BSj-sBW2_NRkyE+KHK*fniI0_ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Chile/Continental b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Chile/Continental new file mode 100644 index 0000000000000000000000000000000000000000..816a0428188d99f437004312ee73c3860ee0f54f GIT binary patch literal 2529 zcmd_rZA{fw0LStF``6Q16DwjdDa7DQQf;@WRtZuwbh!8o-9po=lfs0>Q(RB`rrM}=kC6|+wXfy z%c?3et$#eB<`-U`m(0ue*xlx67fTlJ_ndbhZ2orOkhMdr@}_~Vraalb(DI>dUtn zbh+Qoc~!pStn~K8kLaFr``x`)J-Tl&!96s+S`Kah&ilpLcKzkF(`q<#l^$;FkXL=V z@><7b?r8S>4T3cVI1uRG;aVWYpw z@WU5HME{74Z1aliU+j~UwsecACx>P{$(D7Z_YTD->IelNensGc|-cUOuR1_q6Fbt&gkJ=eO##jhmF%y+@`O z6sn93RWdVgM7ZQKIX8Tfm>1bAvx0|Jwlzs+e-bKkzE9EfkNzO;JRPZXpBfT*hsSjO z)?;Epn@`J?AFG91PUwQnH`QHBpVNzCo>7JA-LmlKTD2s)Q!W_`5KG4!WzoqRakp=+ zT-Ix;8QA`MrqHHO0~YeS(ooEQumjZ>kU;Y>H(M38;c^Qwny>lM*b5+z&w ze!nBY;dBHBOnjUH&LHy!hx|uA!G3@LyOw32fqs9VvO@j-L2X5FI?Orjbwo{^{Jy-n z)LLoYIbyDPUFMxwqQhaPW*^k3}L{6+q%Ju?Q7og!OB_KIv4*)6hNWWUIUksTvj zM)r(s+ScqE**3CoWaGAG=g8KPy(62qHM>W)kM{ogLIZeA2Y?nJJwTd(bOC7t(g&mw zwx$zEE0A6w%|N<=v;*k}(h#I0NK25OAWcEKg0uzc3(^={(;1{Swx%~obCB*J?Lqp3 zGzjSs(jufsNRyB*A#FnXgfz<5bP8z|(krA{NVkx7A^k!chI9;R8PYSPX-LD%!kv<}gL^_GI($@46X{N2|Celu% zpGZTIjv_5ZdWtj^=_=Azq_0S0k&h)kv>xO|y}1Bke}|jWitTIMQ;Y=Sb6$t|M(n`i?Xn={(YUr1!R_`AGMX z_9OjA?f~Q-K<)zMK0xjS GE$lDZUi%6F literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Chile/EasterIsland b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Chile/EasterIsland new file mode 100644 index 0000000000000000000000000000000000000000..cae3744096402e8a452336544edf96ca9ae5ad8d GIT binary patch literal 2233 zcmdtiT};(=9LMqh;W^+W2$|3mS{MbwkLQQ*_=_YVJxF=dBs5cpfF(pgrWD3jVzpF8 zYi_!%R{7BM3tcFi%-?#l2P@BoBU`MSbgMNPJy}}*`@R3wRqLXgF8ZJI`@jA>7w6*a zeBPmkmZn1IZ&$4Sgv0f$Jv^swwzrYvy8pLurM@(9LEIA`8>iz7@paXk2wf|YcNdtb zjBJSxEYdNKUt$xE>ew$QB<@m*zU)|7;>Ul~3470}#L+SB??0(7-#wzIG!Lt!r%svV znn5+S>99%3>Q(n4;#JsL%Fs2O;c6)hTK;3yqTBs zoK)uz>+0{@Wq$IYo<9+xY9_mN?a?-MNBADS;D{p&hbnaNy;xOO-)9!>Iw4h&J

rD5BGI`|PpxN+wx;*-7 zp4s?zsoL~pvgvsxO+B_gS3ll&QT5g(>0Z}$eNhpS|M-fI`7d8FuDf%C<9PQd*FCVu z7w5XWw>yb{-4E<>>?b4QOIjEVIo0;eRwee7+EZ-*_dXx*KM4Jc&Dfv8ZP`*~zuSJh z-43!J^ftr;JL0li0``P#3fUF1Eo5KF#*m$P+N~jbLpF!(4%r^EKV*Z*4v{S)dqg&g z>=M}~vQK2A$WA@&R*}7W+RY-nMYfCV7uhhfV`R(7o{>!>yGFK+>>JrQvU5+nb!6|z z=8@ea+eh|~Gyv%U(gLIhNE47QAZ<YUfHVT>1kwtm7f3UZZg|>uApJlZf^-CF3DOg! zDM(k4wjg~$8iRBOX${gFPum=%JD#>ZNPmz9Ass?mg!Bk$64E84O-P@RMj@R-T7~oq zX_lw$7Sb+H+b^VHNXL+tAw5HyhI9>S8`3wVaY*No)_L0AA<gr&-9y@k^bctu(m|w! zNDq-FB3(q<i1ZO@B+^Nwl}Im<W_sFgBJD)_i8K`HDAH1-r$|$gt|Dzk`s!)Z@qcY> ee5LJgpv2yb13AI+-2B{<yn=$9V9}pX@xKE%a7T*( literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Cuba b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Cuba new file mode 100644 index 0000000000000000000000000000000000000000..b69ac4510784f23ee794cd6d11e62315a7318e5e GIT binary patch literal 2416 zcmdtiUrbhY9LMp8zcJLJ6#qmLCJ7b)9_Vot3TG2VL*Pq1n({9)1c3-M69XaFN}{#V zMQJAEqB7=IVPpfV(OH5rNAnxxu+f--ana`1az;e*^n0Jx)<rk1uKJyw^ZM=Ff8O50 zs)}US-=5$<{<a&rhaEJZ_jY`7@WYYUq<e3PHCR-kgCqIY`LvCC{<B(pD0-(1wddJi z_0N;xwCncB+gIi5h*5jGEJ&w)P1elXOr4o5uzwv()7j2L)^7tR^hV1rYp&O&zRpS8 zb!0;QS_W+Y`hE@AJz)iweJ4SlMRu@tMs8ZX(F%z=E+Ny6cBrdGLVv8b=3TCm`QIF} z7ueZy^XXmoE!}TPSkp1<*8Cszwu&Bmp?gRdZ8&O&7d@|wS2fy8(#mydaEZMvVuLQ5 z%CK*rjn#+?#nv5Tp}M>)-HL1|kUQI=tf)edtf=$1?pl|xD|4?{(JNE*?u4_}s_>UJ zX32ydGuJ7x)5Chtc&pqydP?u>tC6^#!y4a_BMC?LYhrVvB-IzHyE0poA6cU*S@C+m zwOu^RFUsoVld}3okEBKnY3kI7J}~=%K6v(HO&fbv*K`fb+E4drdfO?<IObKWqDa?g zdSv~zS2QbniDZ3yLN*1=$fl1(ADSGK?DksOJT$F2FScs#=ee3!e_7@ApCy0ILV5U^ zOHvSVUA$X95%27%Z1uFu)+^U^TV$_p>%XYm=ib!9cY3sF{D2m}a8yhBO0~4SQ6KHF zv@GWhd90;GcEmTx<CPgwzMxokX04E&SJS03CO|5`jFPJ0@1^Q}f2p22CpCv7^@$6U zTD#AsPj(Gx-IfX6-PWm3dHQuvU8_DF{;uxLtI@r4XJlXMOR{hLxa?nAE&Kag<k?>~ zOG8JMG+s)O1I^je)Eg$vrSbCIk)Omb!2jPqf&PDaf&%}$$LH%Fbh*seb_M!;=WM?a zpYQZZ*Ze=f{Mnr2b!{~7x=iyHc+GlTE<Zo-KUkd4oT`@CUSxU5`j7=8D|9qVMAqnN z7KyCV(JT{LC$dmvrN~l|wK|%`BCB;Y%SG0UEEriavSf7D%!NgB%&LK9BkM*Mj;tJ6 zI<j_T@yO~O&GM1;JDLI@6+lXW)Bq_0QU#<8NF9(uAeBH$fz$#i22u^A97sJJO+k=~ zASFR+f)oX*3Q`uNE=XaJ${?jdYJ(I9sSZ*eM^hi9KuCp<5+OB0iiA`NDHBpBq)<qu zkWwMFLW+e{3n`bQsTWc(M^iDRWJt}Bq9Ij7%7)YpDI8Kcq;!s^c1ZCYP4$rSIhy(* z1w<-{ln|*QQbeSRNEwkjB85aMiImdO)DkJCqp2oRPDfKuq@YMek&+@cMT&}46)7uH zSER5=Ws%Y%wMB~SXsU~p*U{7$DX^odFj8Wq#z>KoDkEh^>WmZ`sWeh*q}E8W9Zj{7 zayy!OBL#Of6-P>r)Ep@~Qgx*4NZs-OTli2Ddyk2JTuw?tazavKQe2MPo!~Y%cj)ib CX!a@q literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/EET b/venv/lib/python3.8/site-packages/pytz/zoneinfo/EET new file mode 100644 index 0000000000000000000000000000000000000000..cbdb71ddd38be8f4a23e57bdb4b86e52195e9f89 GIT binary patch literal 1908 zcmdVaYfO~|9LMp8DKlB=AB;-^ViJOMfWy^GkQyAA3Yc;-;u0xWjZl#on97{Yxn%6; z#%!*fIvI1#$QPt9@G`s27O^(R9F=R!Rd$(cGe?)P`Fx*x*Q;JRpR;p5XXnLv_5c2Y zRa={~oc}yC-Cua~>~`OLpZ(Ziz2+RAZ*zMCvW`53HzX?}7^8V*MfQ01Uy4lpMN#v< zQS^*26n*!yVs5>!C$68={Ev<(_TnXrJ3DOg@0_p&eX@i-`)y%syFFP`Z;MKUmY5%~ zr+j&q6qjs^AC0l(&_X5O%TdbrNm?=yrPNPm>FJR_<Qx1+X#-y=z4vovbX=6b;XP&6 zPFhy`h-DXyTF%C!mK%TE^0K-tZ@R~p#SUoM&CRy_?@q0_RA|q9U8($`Iu(qr(6a|u zYvtQ<TGf=O)xFE@x#Cb2HpE&{(vJ!hPFr#4XDUhj)=KXDU~6VvwKe0{Z0)Vnwr==c zD;>L{vi?3RKYL2++uH2;z609u;+xvo+Ng@9tqPWw=!NKVZSpPArYXNFBa5x_Muc9v zmts}te^>QHnAMyNx7v|k?d6`kRyQziuhdQ0=Dj~_%gPH@UpuCTgk#oNFs!CWK2USK z)O`CbwM@5b>$PreyBXB0XR6iu=}vp?P=VTpDr|d8f_5CtwVfOCt-UGQc4aQGj=-Px zdbneq8IkJz?K|t5Go`LCKep~WliGc5$le$q)t+M?YVYuI?du*?Pk)a>oCo!CoVbNf zsN<yiL)?S==aXLofr_9L2n3ywf1lw0I9vCh98MQGU*v?5Ge%AsIcMagk+Vil8#!;} z#68_JM@}6%cjV-evqw%JIe#PpBm*P`BnKo3Bnu=BBo8DJBoj|J6(koV86+Dd9V8zl zAtWOtB_t;#DI_Z-EhH}_F(fljH#H<TPd7OvJ0v|MKO{jULnK8cM<hukOC(JsPb5(! zQzTU+S5G%tBwJ56T_j&5VI*TDWh7@LX(VeTZ6t3baU^pjbtHFBH+dv`Pd9xee`ErX z89=50nFC}JkXb;c0htG6B9NItrUID@WHON1@N}mGnGa+_kQqUy1ep_LQjl3erUjW7 zWMYt+L8b<o8)R~j+3|Fz2bmvFcY=@^LZ%3rBV>}0Swf}>ACh?rbGIrji`DX#WvAz+ P`!lkAWto2OTTa-0+xVLQ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/EST b/venv/lib/python3.8/site-packages/pytz/zoneinfo/EST new file mode 100644 index 0000000000000000000000000000000000000000..21ebc00b3fc096035b9810519d778d04a3562a44 GIT binary patch literal 114 lcmWHE%1kq2AP5+NDp>yi-?@Q-!8JI9A%rYlTtKa+TmXY14MYF{ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/EST5EDT b/venv/lib/python3.8/site-packages/pytz/zoneinfo/EST5EDT new file mode 100644 index 0000000000000000000000000000000000000000..9bce5007d4dbb871974a69cb0f68151c1ee22556 GIT binary patch literal 2310 zcmdtiZ%oxy9LMnsqUZ$@Dhd@Tp<*Ea4Mn8Fgb~^m(u*OPel_q8p*X4CpbTrFq+4@N zgZ}N7WoB)T%xqeXsX23NX3A>zXLxLjwTe1M51iz^o%iu!k9yWRcjvr*yU#ywe?#-? zBF{h0So;r`^Mbv6Cx-T<sn<UGMPA?RQM+C~C7(ZM)Y*(b)ma(UmoL?u(Vyn%zs{AK zD<`Mw@S#)_c{`##y<rp8eL+V*uFV(~mKeFB#@1>XSAJf_795k<=O?KNiMwUOzMaNv zHcOn|q~gDMLnj;wsA~>)>51<=YZ6~tt&_GinQJ@l(bqLsnd_Hk>*VSzbHnU-ePdRf zNlDL=N#lpj<mfn={D)UfxiBoLXMR;vkDiva{a>h?cI}s&gB~;OnH`c|_k+n;)2DAK zK5lNEzg^#!yvJl_uhW^~PgRz;PG=3irLupXrKk6ItDFJ9<c6A6-hr8t-?=~)>`0Nq zK)@8Oy(}}Ts?F_-zL(<6>1Jk8zs!nFFeOvI)g?o}o7tnE=+YBs%$)B+x~%Uvb;rj~ z>pQo7sqT7Zl`e04U(M~>D0kQFRP!2FN=1H9RaVTC%8|XMDtCph8rW*86Xxpb1FdHM zaE4y+>K1kH*X82d(4rQ8m@YNTe5$r5M(!)iSBoASlEtY>%3pU<{G%gkN%6a~<j0Ao zKJA3AKYr0H4e!+ry9dkzgIo2ou7l>m{#L!bvDd5!E!5)sK&|X<kyW`p>Y;#78WY-8 zQ&qk+4L7JjW|9O>m8s@&BhtJtO|2RFN?LkKP3!54`r%-zd8BVZx7CG>+ICPsTCC05 zwqCt1`IuQ>)1lXg&#Pcbj|2ygs`iw2Y43kibzEwYCqkRlljq80LuWuebtp|bmshKe zFM1@(6Xl5>W1s)hFA_QYo+l;}`RquP$Gzj-8-Mlx$_l@ya<RSl+gs~rB2iZ#|GyYh z#2yBPj0zbRGA?9b$jF>_Xvo-*!6BnVhKFu^d@w+c9U(A8WQ@olkx?SUM8=5>)M-bG z4Ap7JiVPMREiznWyvTr&5hFuJ#*7Ra88tF&WZcNWk&z=qN5+l}-f2gV3?CUk5&$Fu zNC=P^AVEN)fP?{w0}==%5=bbVHWo-QoHiOrIFNWC0YM^yganBR5)>pVNLY}#Ab~+5 zgM<c&4H6uujSdnXBtA%hkO(0mLSlpj35gOCCL~TsppZx*p>o<-A;EImXd&Tp+IS%W zLn4NR42c;MG$d+B*pRp(fkPsPgwAPWhXl`QqlbjgY2$|k5Q!iXLL`Pr5RoV%VMOAH z1QLlP5=tbNNHCo?nn*aEHl9d8oi?IKNRgN#K}Dj9gcXS^5?Ca%NNADRBEfaq=px~D y+V~;?cG?IdAx2`11R04k5@saM_`eIZ*LJ(u_B+QnBd;j0Ajel&m{*ur;Qbp6U$$!i literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Egypt b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Egypt new file mode 100644 index 0000000000000000000000000000000000000000..d3f819623fc9ef90d327380fad15341ec1a0e202 GIT binary patch literal 1955 zcmdVaZ)nw39LMo<r_Onu>Ge-G^V-ra*L3BUZ7pvu|6G|i=@<8oQbzt(p;QznmXNO4 zL87pXustvmRJ5YhGPA6O3K`U#)lS9~6!a`2m)ShcP1()0&imNI2zt<iz8ChoY!CM2 zyg%vXkFG2ee|tm!`fZbw@1vCa(c1ixY0Wh1BUdh%wy(PM(WCE&U!S>If3v&OeEVgu zZhv*9(eJL&-#s6iV=uiIbd^6GcJ-D7=SH@K=Q=|D%lV8w|M3&z*Y+mcy{SiB_+X#3 zYYNqG8-KDr%a@6Z4U=T=oDHh4cB{NJC8jQyAG4PSlcN8+Y}w!0CNlk%_V>dB>dL7@ zcHpgb>W>3Ga`1)yLTo9tkySsdtfpmh$l|ydT7Oy&o3UMFFNoRUxg9E}ASrXYM~LXK zXKb`Rp+=q^u(^9bSEG)U%4=Th6Qg%NV#hpPq+&0>F2~l^iE&TH<@kzDG2!08UYj>w zP2AROCuXWep4?&cPBp4Yy$O5$A)zLBNEzQcTTI!%!``4)sr*eR<c;;4#niQRa@xXt zQSi`oSy-4-HzmH1)3aX`Me$3v=<H{zSTx$=wkkEFbB~<4t3i|;{=wd|;ca#6wsB_G z<GH%Dsn3)x>DITcIALZNYkhlFiz$zOs4I$&hZPswgUXyw!^-dX26uM75zg7y93)zw z4ex4R9n5{_!LX{~{^0J7Yt6j620j0&I<p{As~6rk*CfXd1dB@Z%_8$yP#w!M)t|)l zV*8_6@=8l^&&fzwQ-4s`tbf4NyqO77tM4$W-RpJg<bg0<urA1o{70W5S^xaG`hSIp z*Sgmyif2XKQ=FVHMqK?~votM|$rL}*{5_KX7w>t{-E#+*?n2(R*S&4zeIsuidFRMm zN8UT~=8<=gynW>TBMl%OcwGxf4_?;<(go56(g)HA(h1TE(hJfI(hbrM(ht%Q(vjD- zg!JTfO(9(&Z6SRjjiK+1FSN$F-hk$i?vVC4`a>Gz=n!cU>Cx+&<ml4t+C=(98bvxq zTIJ{!X%^`gX_up4q+yPZk(QC3y{>7FuDz~pq;I5gq;sToj^2^xk?xW9Ir>L7fMW-c zEkO1F*#wSV@Vae4_QC5m0@(><D>(K7*$iYiknKSB1KAK{N02Q+_5|4!WLLayTabP6 zx{X102H6^9Z;;JFb_dxWWPgwiLUst*B4m${O+t3b>$VBmC$HNmWT%j=LiP&TEU()w auiGwUzr1e4yl%(v|FmUMH)<ti(LVwBTA^S7 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Eire b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Eire new file mode 100644 index 0000000000000000000000000000000000000000..1d994902db21814a626e42639d7a96b18ee73756 GIT binary patch literal 3492 zcmeI!Sx}W_9LMpO5Cz;G%`H)R3^xq%fJ;gexe|)xa#GR^Ek#W-Bx6J~aw<#5asD=z znVOGFN-ntJisl;XWG*Q#xbNb=CN5~t_r2(*tEMix=sk1zoB^(w;rIP}dks#GbpG-L z*zfS>IcMK|uJnohGOgZ<Nz)FNt}uO%$IO_!)qFpFhM75~x-p-x)3eeao7n@V>p7!# zn7IjS%nvb-^t`%#_5AvII;&xr&bm@$7C8IOg8a&QVc|`^XnTrYyz@7mJwHJ&F&Sp* z7aqOrtG#A<YP?yIw%p`&2{$X_dg)ajWmZR~n>FQco3#}a&Dt9W%(_BH=N`VL*B|Yv zH>}yOe_Hm$Z2Wem-ZU*pZyqs4Zy8yvw<c!jZC&S@pIh|Sc~P77_QZo`dqIFX5O+%F z*Q#v}CM?p2!W!tq;S=@Y2Vd)ga;duD%2j>zd{uMom)-jKwg=`!&Si5lyNW(Fd6zkz z_NqBEWVk-tt)V&R6>~najJXiKSYHeZ)t4%H&80`Bbz$)^eYxP8zH+>~zPfIYzP93_ zx&GZUePhf(b93fseXC!bxt*D$?{rMocavJ{d$r4&-(y1bedmTL3ii`Qr}mi#PcG_* zn^u@dmwe6RQ43A+_S{t8)I41xG*SC?$<ieQqI4<GcwMTnh7M3EI$*~W9e6WAmtJ1o zl-cXiWhXs0<(5{|<%gXxYHGNt&~=lkn4!$G5wlID#M`EF$Q7y5B2TLN{wmd~Wl6QO zOXRtt@lt*3Bndh_U)5NYt!i!_r)o_Q6+CN*(kW@G_L$D<`FO7i>DO4*32UzEcI+he z%2ZSJ8#a>q_nJy*V0j76uObZ#Z^;WeMH04izciX$AmKl*l*Yr?i)Y*viRg1gMW*Gb zCegX7X}51wvzjwh^T-jZd2yy{5j0s^9Pg)EK1!FU4Q<s+M-!#hyd;Uvjgptgww9P_ zHRP4#5NZ8cOVy@>pS0~Cq}tWJDDB%8s}6oUB{t-wioJe8#rbYlal3b@j%VknPT31o z{H~4CdEx|>uxOUNHgu@!GT~F{+H<^gOBo>DUrZ5ie5|})H9>lWg-Vb69!ad+K_wol zC~w?rpn9#kE4}jr)tjb*>XUO-y_I=KB~9L~`X=S8exonT+cB%vJAHOZ|KO==Ky<bw z`>&LNHAMzqnj(XW(`4|D40-psSB7NumXy3<>b)<cW$3)_>it2%k~+4T8rHRyN=vS) zK8UELhPQv9KCIxV^v0DX{pJ}pqTGEMv3HxwxPC-NE}f@F?aq~trf!kZ*)!zhjJc9I zF;je=DdGF)%df=0{PHhZ>Ob&$`t)HP$FX0_J0%>)KiJ3Lamp#5GIoj_N4cNvcO1vZ z{p`3ub^PNyd!2Un9oOCKw6X74``P}E`|#WL@$qrIe`EWe+NbBfz+=b;y4oE?wh-Av zWD}8HM79yxM`R<BokX@0*-K<Ik=;bL)79=LvZ1baN0BW>_7vGvWLJ@GMfMfhSY&6B ztwr`0*<56Ik?lqH7ujG}yTiy9BYTW&GP29aHY59tY&5dd$W|kJjchiu+sJk!`|WBs z9NBSX%aJ`tHXYe@SG(=VzPs9uM|K|BdSvgB%|~`0*?wgIkp>_gKw5zG0BHi!1*8qG zwhu@nkWL`2Kze~R1L+3R4x}GQLy(RjEkSyMGzIAj(iWsIuC_5qXOPw)y+N9TbccTx z+Jp25X%NyOq(!c_M@W-gZI_TXA$>v`g>(vO71ArDSxC2#b|L*j8isTXX&KTpq-n0U zYe?IWz9Ef6I)}6l=^fHMq<cvFkp3YJL^_DH5a}V(L|5BIq>Zk&k4PhtP9m*DdWkd> z=_b-nq@PGbk&YrQMS6-f)zx+tX{)R4E7Dk`vq)=^-XhIKx{I_I=`Ye?q{B#yksc#W zM!Jl&+12(LX|${DG}3CM*GRLGZX@kR`i(Rk={VAIq~}P}k**_cceQ;-8t-a5kF*}? zJ<@!n`$+qd{v$U4at9!{0CEo?Hvw`NAh!W>A0Rh^tGyGDTLHNjkedOy8<5)pxgU@l z0=XlQTLQT!kedRzE0Eg)xi63#!`0py$gSaO?+xVUK<*CY_CW3r<OV_R5d8lZv3~^h d&u)=Gd#W^wuy=|ltaF4Xyji%l2{euf`~${g?PmZ0 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT new file mode 100644 index 0000000000000000000000000000000000000000..c63474664a289aa3c3c0d8b2ce06d484679754c0 GIT binary patch literal 114 hcmWHE%1kq2AP5+NDp(+@+<ikBLdep^1=MQ51psD724w&M literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+0 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+0 new file mode 100644 index 0000000000000000000000000000000000000000..c63474664a289aa3c3c0d8b2ce06d484679754c0 GIT binary patch literal 114 hcmWHE%1kq2AP5+NDp(+@+<ikBLdep^1=MQ51psD724w&M literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+1 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+1 new file mode 100644 index 0000000000000000000000000000000000000000..4dab6f9005bea50a065c685ec8260b0da2bff921 GIT binary patch literal 116 ncmWHE%1kq2AP5+NDp>yi|M-D{LD#^LA%rYlTsA<xc7|L4sK^bF literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+10 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+10 new file mode 100644 index 0000000000000000000000000000000000000000..c749290af2f6b5fe22770c34eb1e8fc87cd85aff GIT binary patch literal 117 ocmWHE%1kq2AP5+NDp>yiFHT@!&^0t*2q8-smkm&_ouL6209yeIqyPW_ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+11 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+11 new file mode 100644 index 0000000000000000000000000000000000000000..d969982309e5ca7d32979a7dad814ca307d2cd8d GIT binary patch literal 117 ocmWHE%1kq2AP5+NDp>yiPYqyT&^0t<2q8-smkm&_ouMHY08u0hYybcN literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+12 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+12 new file mode 100644 index 0000000000000000000000000000000000000000..cdeec90973be28ee4075eadd22b8b574db2d7a5f GIT binary patch literal 117 ocmWHE%1kq2AP5+NDp>yi4|iZ-&^0t-2q8-smkm&_ouLsI07pj)Gynhq literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+2 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+2 new file mode 100644 index 0000000000000000000000000000000000000000..fbd2a941fda996f4abc1f0e09cdf99c271f5a1e2 GIT binary patch literal 116 ncmWHE%1kq2AP5+NDp>yifBb-fLD#^DA%rYlTsA<xc1BzPpCk=f literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+3 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+3 new file mode 100644 index 0000000000000000000000000000000000000000..ee246ef56f18de61105af0c14d201fd090f74905 GIT binary patch literal 116 ncmWHE%1kq2AP5+NDp>yizj}dzLD#^TA%rYlTsA<xcE(%)m4FQ( literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+4 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+4 new file mode 100644 index 0000000000000000000000000000000000000000..5a25ff2a6afda2cb09b9e147ad20610bc1923444 GIT binary patch literal 116 ncmWHE%1kq2AP5+NDp>yiKYoCLLD#^9A%rYlTsA<xb|zc^i`)$8 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+5 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+5 new file mode 100644 index 0000000000000000000000000000000000000000..c0b745f1cc44d03a00f8bdf127c154392e3baf27 GIT binary patch literal 116 ncmWHE%1kq2AP5+NDp>yi-?@Q-LD#^PA%rYlTsA<xcBWhaf;bGY literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+6 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+6 new file mode 100644 index 0000000000000000000000000000000000000000..06e777d57e0267a0635b6b284729fddcfe6221dd GIT binary patch literal 116 ncmWHE%1kq2AP5+NDp>yiU%h~VLD#^HA%rYlTsA<xc4k}vc$5ry literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+7 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+7 new file mode 100644 index 0000000000000000000000000000000000000000..4e0b53a082f11f9b9debf5e110b97b1b0473c9a6 GIT binary patch literal 116 ncmWHE%1kq2AP5+NDp>yipF4qpLD#^XA%rYlTsA<xcII3FZtx61 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+8 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+8 new file mode 100644 index 0000000000000000000000000000000000000000..714b0c562889a8a774d9aa27810d8400164d00e6 GIT binary patch literal 116 ncmWHE%1kq2AP5+NDp>yi?{8pW&^54N2q8-smkm&_odp*FWlRhR literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+9 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+9 new file mode 100644 index 0000000000000000000000000000000000000000..78b9daa373d2aa2856eafcc92ebc6d899cafde5c GIT binary patch literal 116 ncmWHE%1kq2AP5+NDp>yiZ!BP7&^54R2q8-smkm&_oh26lTc``r literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-0 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-0 new file mode 100644 index 0000000000000000000000000000000000000000..c63474664a289aa3c3c0d8b2ce06d484679754c0 GIT binary patch literal 114 hcmWHE%1kq2AP5+NDp(+@+<ikBLdep^1=MQ51psD724w&M literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-1 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-1 new file mode 100644 index 0000000000000000000000000000000000000000..a838bebf5e7bac3e1257eeb0a61c1b83feb1324c GIT binary patch literal 117 ocmWHE%1kq2AP5+NDp(j8_yiajv<(ayLdep^Wdqb}r)$Us0B2POH2?qr literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-10 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-10 new file mode 100644 index 0000000000000000000000000000000000000000..68ff77db0d95c7d054ef33c05e05ba71bcbbbdd8 GIT binary patch literal 118 pcmWHE%1kq2AP5+NDp(j8dKNG+Xd4<Zgpj3+%Lb^|PS?<Y3joWn2!Q|q literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-11 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-11 new file mode 100644 index 0000000000000000000000000000000000000000..66af5a42be440f1fb8fec3b915afb49b356f63a5 GIT binary patch literal 118 pcmWHE%1kq2AP5+NDp(j8W^G_#&^9z=2q8-smkm&_ovxuF7Xa3A2*CgV literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-12 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-12 new file mode 100644 index 0000000000000000000000000000000000000000..17ba5057727dd73bd5f6234cc5b239b71a861945 GIT binary patch literal 118 pcmWHE%1kq2AP5+NDp(j8Rvchp&^9z;2q8-smkm&_ovxt~7XaZi2>}2A literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-13 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-13 new file mode 100644 index 0000000000000000000000000000000000000000..5f3706ce64cadf081a6c56abd7ba423575a4abb2 GIT binary patch literal 118 pcmWHE%1kq2AP5+NDp(j8wq0Og&^9z?2q8-smkm&_ovxuV7Xa(^2|)k= literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-14 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-14 new file mode 100644 index 0000000000000000000000000000000000000000..7e9f9c465ce6211c65d617f60472c9b55b5052c5 GIT binary patch literal 118 pcmWHE%1kq2AP5+NDp(j8jyzys&^9z-2q8-smkm&_ovxt?7XbFR34s6r literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-2 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-2 new file mode 100644 index 0000000000000000000000000000000000000000..fcef6d9acb247deb539fcc4b30149802572ea642 GIT binary patch literal 117 ocmWHE%1kq2AP5+NDp(j8WE2<}v<-|HLdep^Wdqb}r)$Io0CCs`bpQYW literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-3 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-3 new file mode 100644 index 0000000000000000000000000000000000000000..27973bc857b4e618218ca2790acacb81f7c7bb82 GIT binary patch literal 117 ocmWHE%1kq2AP5+NDp(j8v<w&+v<-|ILdep^Wdqb}r)$gw0DM~pwEzGB literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-4 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-4 new file mode 100644 index 0000000000000000000000000000000000000000..1efd841261a977ae218d408f9cc308c3e312a5e8 GIT binary patch literal 117 ocmWHE%1kq2AP5+NDp(j8EF2gZv<*xcLdep^Wdqb}r)$Cm0EXTM^#A|> literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-5 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-5 new file mode 100644 index 0000000000000000000000000000000000000000..1f761844fc44f8228bb748235bfd30be6c389cd1 GIT binary patch literal 117 ocmWHE%1kq2AP5+NDp(j8+yWRFv<*xdLdep^Wdqb}r)$au0Fhw_H2?qr literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-6 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-6 new file mode 100644 index 0000000000000000000000000000000000000000..952681ed46cb60e59baf76a2c43b49d5f67255d1 GIT binary patch literal 117 ocmWHE%1kq2AP5+NDp(j8LJ}Alv<=J{Ldep^Wdqb}r)$Oq0Gs3obpQYW literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-7 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-7 new file mode 100644 index 0000000000000000000000000000000000000000..cefc9126c691060225ff2eee1241b1e5e9825fcd GIT binary patch literal 117 ocmWHE%1kq2AP5+NDp(j8k_s3Yv<=J|Ldep^Wdqb}r)$my0H$XLwEzGB literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-8 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-8 new file mode 100644 index 0000000000000000000000000000000000000000..afb093da00685297cb11347c4840acf3a8e2e2bf GIT binary patch literal 117 ocmWHE%1kq2AP5+NDp(j83K|#~v<)m6Ldep^Wdqb}r)$9l0I=!@^#A|> literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-9 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-9 new file mode 100644 index 0000000000000000000000000000000000000000..9265fb7c2071ec0e66c657ad2ae42d5dd525fe97 GIT binary patch literal 117 ocmWHE%1kq2AP5+NDp(j8>LxHSXd75Egpj3+%Lb^|PS=tP0K07nH2?qr literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT0 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT0 new file mode 100644 index 0000000000000000000000000000000000000000..c63474664a289aa3c3c0d8b2ce06d484679754c0 GIT binary patch literal 114 hcmWHE%1kq2AP5+NDp(+@+<ikBLdep^1=MQ51psD724w&M literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/Greenwich b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/Greenwich new file mode 100644 index 0000000000000000000000000000000000000000..c63474664a289aa3c3c0d8b2ce06d484679754c0 GIT binary patch literal 114 hcmWHE%1kq2AP5+NDp(+@+<ikBLdep^1=MQ51psD724w&M literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/UCT b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/UCT new file mode 100644 index 0000000000000000000000000000000000000000..91558be0c2bf903b2364215ba26d5227d6126508 GIT binary patch literal 114 hcmWHE%1kq2AP5+NDp(+@LPMMxLdep^1=MQ51psH$25|rY literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/UTC b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/UTC new file mode 100644 index 0000000000000000000000000000000000000000..91558be0c2bf903b2364215ba26d5227d6126508 GIT binary patch literal 114 hcmWHE%1kq2AP5+NDp(+@LPMMxLdep^1=MQ51psH$25|rY literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/Universal b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/Universal new file mode 100644 index 0000000000000000000000000000000000000000..91558be0c2bf903b2364215ba26d5227d6126508 GIT binary patch literal 114 hcmWHE%1kq2AP5+NDp(+@LPMMxLdep^1=MQ51psH$25|rY literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/Zulu b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/Zulu new file mode 100644 index 0000000000000000000000000000000000000000..91558be0c2bf903b2364215ba26d5227d6126508 GIT binary patch literal 114 hcmWHE%1kq2AP5+NDp(+@LPMMxLdep^1=MQ51psH$25|rY literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Amsterdam b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Amsterdam new file mode 100644 index 0000000000000000000000000000000000000000..c3ff07b436aedf662eae60f50668f5abcdb172b6 GIT binary patch literal 2910 zcmeIzdrVe!9LMqJQAndBe#Hb*yhVf;#0OAPlavt61VVixQt*<9T4adCur#`;wffC{ zb1ZXe-VoFwqTy|T_ghoRYLuF;O;>g?ax<saT>ai>Yt8jftv~vwb2z`(+2LP!fBX|> z<;Q#ea<#Kxc)059!+XzH?Xkj%y|SYD^PH7ucRQ;p_BkI^MLDaNg*t0A*{m(O>8vY^ zH0!g@ITe|KW<z3wQyDeUR7D>!8z)^do7${5n_4C~n=dai)zKH7>SHs^mLKz-nyS%e zYtwR5`(|IWZCf|9z3?&T!=>Y#y39V#j=77>PM_oK^6znWw{LOw3@<f%emd>chtDzf zXRerrTN|9l-A!iixie<p`?Y3&W3D++y3`!3I$;i;&&@fMU0is$>~P_cL0N@Ir`))D ztY^{H<0H0bp1eFpPHhU)rgbUu@zMcu`t>OJq$pHA%^0rjDyC`hJDsKd!c>*wMD36l zts(w!?U+77?oIebJ4ODWp&id_SnE?7c5SbQU)rkoeYQqBA9`22G&D*?b&Yggxmvmz zmG1LjlO6>{(lck8+@I!`$f2q7Kun@UMMTSkPPjw|rfBr_0ov>9DDB-Gs(p^M(Y|#z zHKyV_?N@$IV;7##{>2UI%iE%Hxo0K5s7?}+>Se&V_hew#RgxHADv7ttWKfrK9du!; z4F0u5hcu?h!(V3W(8|f0R6j%?S)8oHRz&FV{76k+I9MJX8K^0FU1UVmWlc@FEh7Uz z(ovCL$*7iZWOVBTGP>!wJbr1tjH%fyX(#t-`Vu1<)ob;M*|R0nyrE;CdRxa8OxN)b z6{tULls*}jp;<A#HS2~?vpbEH>@Py}>Fd2@!p@&{Vsnt>tmz=Rbys9k*)^G5-Xv2d zH_Oxo-|I8OcFDBdlbY9kxlB*0(fqbMbVgUz8Q(6`nYW8{*714z>;=C*w{fBt9GxT2 zzm=r3E62+VGrMcy;(;<}>`*Dn50klZ-K046mb}=(BPIPiY01@#QW|_iOHUt`c`ax4 zrP@k)xv5^~FF&XYYF6nh^D4A#Ntw3twrU;lH}5uqciB6r?cMHukMm#M9#25I{WtW4 zRCoj2_qKPw2h@5T`(?j3<c~90JmDTsL=SJoohRSZ(*2%{@qSOTwXe??@3Uu|JyTNs z_OZXPm)BnQ;OEcF>-GPGaQtSkRv}{xkbt<_h#(<BVuAz(i3$=HBrZr`kjNmRL1Kdh z2Z;_69wa`lHb6*(kPx}r7$HGIqJ)GAi4zhiBvMGIkXRwXLZXF)3yBvJFjpHfBxJ5O zW=PPGs3BoP;)Vnci5wC-R~tJdcu4e+@FDR-0*FKq2_X_gB#1~9kuV~0L;}g*0g*&P ziNq2KCK62~oJc&8fFcn^LW;!H)dm%bDiT&Cu1H{!$ReRdVv7V9i7paeB)&+1kq9Fp zMq-Qv+0{lF2{RIBB+y8tkx(PCMuLq*8wocOZzSMI#F3CAF-L;#YNL*X-POh&2|N;c zB=kt^k>DfIN5YT99~l5-1dt&>#sC=vWE7BLaJA!r41}v431ldcu|Ng`84YAOknunU z1Q`)zNRTl>1_c=vWLRA7xF7@LYDWec8f0vc!9hj`86ISOkO4wQ2pJ+|jF3S>MhO`v zWSo$Ja<wCc3>7j~$Y3F(g$x%mUdVtUBZdqaGG@r2A)|&28!~Rlz`5FyLx#@PjvX?1 t$mk)%hm0RGfXE2q|3eu3?}jkQj%B|%)-onNA$DM_FD5<Chy4?Reh2>ZkT3uM literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Andorra b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Andorra new file mode 100644 index 0000000000000000000000000000000000000000..5962550392fa78514061582e9371c32b9f1d929b GIT binary patch literal 1742 zcmdVaU1*H~9LMqJm=i7OKjo!thM5`1UTtPJ%yG7`jqN;aUS?kA*f_?HS(~>*){@rx zUo2WIL`&kN3>PC2B3dpi&5|OoNs5KEc)pKIS8kMNJ?C>;=koXcn=7k)DaId<)A|oD zkKcOv9<ks0c%0K`M4k^x)bSHCu305|&jA_l56Fbo8)Ra>DKS|dndC~B*vL4UJZy}_ zIo%r9KSQUyiq-g@Q9AX`5S`ZfO<iZ+>Gam8n$Y+_6Kk(&QpE*LF6)()K&PZ;cgc+6 zBa#-?F6k-tl0FcWjIphn@ob&U`cbEu*WEI^uT---$~C(yQ|C10=-gwGI?orQIgPVq zey&s96=P*V>>KsC2PD^dU-M#~OWw!VvM}tXEbP7~i(a0V#i4VO|L}$uv@}cM`BS>2 zx>}YtAJn3f!&>a$sNR`=HS_ay+2}%D?uystUz4<SWUiDx8KEosr^w1HUvyPZxU4=I zA!VH(WKHn1l(%-v+VUP*xA(oSpL<m{ls(jn=r-Ay9a7)W%epB_b<^9US~(EVs(TH( z`I)I(&aP7b-5S|?C|j#Lyt1t_TDLc)Nlj6f1bm}qNAftS^?a9|5r)(yj?}tOFQk6> zSFL|^TN*z0>aL3&vb(!W_q5&8y`gs9*KkIIEkSh*3LE^d{tUyxPIv|z#&9u)8b;)J z$FSeu^9xL)#A6z6`}Laq%;B&<%)c1mPwUy2eyJ51A`fFk28oOk874ALWT41Mk)a}E zMFxwE78$OsHC|-E$cT|4BV$Gejf@%@HZpEx;K<04p(A5Q29Jy$8NRJGek1@}D*_}0 zBnBi1Bnl)9Bn~7HBoZVPBo-tXBpM_fBpxInTPq?YBwH&cBq$^*BrGH@Brqg0Bs3&8 zBse5GBs?TOBtTm$LL@|6D@G(pBuXSqBu*qyBvK?)BvvF?Bw8d~Bwi$7Bw{3FTPtQH zXe4SRY$R?Za3pdhbR>2pcqDoxd?bG403b&IIRv)WF+dK2t#uTT!+;zI<Uk-t0yz}O hvB3Z4V1!#oWO}mO<279csR?NbNv?wABuq>V{{?7%e9iy> literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Astrakhan b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Astrakhan new file mode 100644 index 0000000000000000000000000000000000000000..73a4d013fcb82c2beb6f885f359b9ca20da054e7 GIT binary patch literal 1165 zcmd7QO-R#m9LMqBa&xwI=uo+Ivj>~Qht-;!teQ5Pb6683h6gK<9)uw1OYBe(7-XI* zD1wM0f<}j)4|U37gqKJ?b+h0Hoq8aCmk5$tzxQ9e1<|elpY8SM#~5RucX8zCSX}+_ zTE2AJYvp<6-9WDNwCo>R9l2In6PSzD*Ue_?zq=j>KB~&v`DCnN=3J$5>aq^rKdVDG zO1kO%5xws8uwH*GuQ%*Z>5YX}-JEXFn>zeD9Q2tM|AL8lA`<x;kk&V!N86@9N&Azx z(ovq3=#>|;dE$|5DczFT;Y+ghz?6xfxN17PZ<@s3QzjWYW4hw|OxKTtCe?USQt$fA zwuKSd{=CKPm`_XkPFA{~HA&B8Sax1lk{R<#??lk-%6*XRp`WHN{91BZZTdYAB;Wkf z<iET!12ttcFn7=Fem`mUJiK5EGq+{%;&D?fghq$It&;I-wd$%_ws^ZeOLwie*6Zf& z@3-6Qb}JQK!5`ZeQ}(%k$W^CQDx>V#;`{Ftmpxhh4CjTxqH2$I+E>!P5`2MjaTWhz zKl}5mY>4d0m#`(WC$g!d-4)pu*%#Ru*%{dy*&Ep$*&W#)*&k^D=>TZ~=>cg1>B7;r zf%Jhif^>qkg7ktkgLH$mgY<(mgmi?og!F_o<!HM?+H$mgA&nuOA*~_3A<ZG(A?+dk zAq^rOA}u04B26M)B5gX_K9NQpZKp`9NUun<NViD4NWVC4xBuT7_N8soJ<){k7jTRa A6aWAK literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Athens b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Athens new file mode 100644 index 0000000000000000000000000000000000000000..9f3a0678d766881389e129c93def7fffd74f14f1 GIT binary patch literal 2262 zcmd_qUrd#C9LMqJ2qYerzDWE@Kr|xMj&S(vpCF>+ftd$GI2x%42BH{|5-~`OV=>np zbKe%LoS9aPIcCQ$DCdw`R!$4Zt+8h1V7W5OIhHzW#p?HdYHO{lZo27r_B^lWJmZ3k z^LhK%)z@WO|2R(bhKsY;Ts+SXnA?HCyugX}%i||bA3JyU$C~kv<w)t!rIj+==bIRL zJ#PHd7wWf<MZH=*cHCJy?aIdL>2cSqrw<3M8H0zcnLTR)5nYvmTRRsAWZSP2S-W#$ zR$1RfRM9ilw`H9wjZXeSW1_y&*pOk3z4orgT|B0@e|A`BfAGA<pB$8gqd`f0<&ezj zQb}sxEpr>1WZs4vxx?p|<UFt3>B^OqgjBg}Mx3OEc{KG#w$A@1MHh_5=)#Yt>fQZ6 zsjKI*F6#b5(>g!V^yZW5u6<K8D$h%1Q@>>84@h>|i;|OgP;xU{C3mtzmc)1Kk_($; z=`St1Y|tb3d|9D+y;Yh&uuSjWQ>X<867;^hWG(DmD)$$Ksi!txmZw}&uV+$<!p>@O z@|YA~{Z>|lye}(8&d387-;kBTKJg8`rzQKkWYy8v^ufkPDeZbzS3k5@%NjOo`Qirk z`-*i<>?&RBTA*uhy0s#@NGd*`r4QejFYDg9uIopgvf*%~RQ6wyjUCsds(VDLt43wh zuJ84cg5y$CIi$5o`(<-}Q0v0q)-8#uTfTcqw@x-`{h2o1cEPWY9$Bvqr+3I>&*f`l zZ@E0aHA%Pc$&nqa^Q5URR-VY1BhB8Q<;h4(TGFGnW#VgTjku|;=RTCStLOEpw|Zsg z$bh!*Kc%~Z2leT;9_`rIp^lI#AydLa!$OU>Otn9}2??L}Uw<qsCeQq6xrbWTLboH_ zvJ&Q6Gc7AZtVo_6(SLvc*WdU`{8pj4yxwwde#>KD=F1<)Va}hAmc!xy7d!gRoaTa; zmm_;ZHf3veg=`Di7qT&AXUNu&y&;>kHM`@#VtdH`Y|REa?2yA2kv$@tM0Sa66WJ%S zQDmpcR*}6To3%B&MYfCV7uhhfV`R(7o{>!>yGFK+>>JrQvU6nX$lj67BfGaX+eh|~ zGyv%U(gLIhNE47QAZ<YUfHVT>1kwtm7f3UZZrGZ3ApNj44M94Bv;^r1(iEgCNL!G; zAdNvfgR}<e4bmK>J4kzw{@9uZAsw<cEkb&PGzsYv(k7%&NTZNWA+17sg)|H47Sb-H zU$&-UNXKkV%aEQSO+&hdv<>MS(m14ZNb8W^A<aX&hqMprAJRaigSMuHNDq-FB3(q< zi1ZO@B+^Nwl}Im<W+L50+KKcNX(-ZBThmgcr?#f4NLP`zB7H>~i*y!gE&gA7>oi4P Ylu4UiC0S`XY3}qaS4oE3e#&<K4n&?MSpWb4 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Belfast b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Belfast new file mode 100644 index 0000000000000000000000000000000000000000..ac02a81440f47a67b9f01d3fbcdb085266d20894 GIT binary patch literal 3648 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 Nbd8QojP~#<@K40&SY`kK literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Belgrade b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Belgrade new file mode 100644 index 0000000000000000000000000000000000000000..27de456f16ab549627b284a39e2265cbdb4ad8e9 GIT binary patch literal 1920 zcmdVaYfQ~?9LMqhL0H4S7@-o9T#oJ~DdMPHDwhrt$t4vMLdq?-nOU<hYs@g$HH>%= z9>mObA-Sy?W{kPcS{sI0<M;k=Hk(JD*!)lDyjrdG<oo`(Gv?)lS${mO%ujgptT1oB zZ@bQX+-w&4y!OplxqZw_>khf(&W;GVyCFdC9W0aksqxz7<tgp@;DC0!vR%E;Ul5-Y zmEya1zjQBC@msxKdgK>M&*^idSF&6DV-uveGfDz{0;NxzE)wYB(!kFV+V@p}_N(u# z{jass0aahsdE}iAEPt#)n{H|Fvhx~}eNsa+A4ynYm4wGtOT@&T66w27qQZ(Ls;N|> zy~{QF=`0!iy+~s&xMawabd9aZ(zxmv9lCkA4%_3S@j3oFeA8eVk?5hWY;PGE@J16{ zO_JzwLzDcUNm9dW8QuJnjIOJZF)t6x*vjLQTzgSdwv|chiGw<>pg_i#ZPW=<w(7+E zxtca8U){+`I>{?lCp-J;<S!wb-YHSiA9m2GpZiM2*-tvH-czO@XfK&nA7n=9N69L$ zlbKodGHcCyojvTF%*m|PY`@(yH?C51TA$HeU)9{VyELz<Q0LW@==`T{U2t@o=3ieT z3%A5+K}DJ@%Jb93n<Hh(gjgxe@sg#X-DO$AH(B1^lA_>FTGaSLiranB;=5O+q~VdS zJY6BH>Z*11?#sHSa-Xg(IijW8O4ZS#S#$g4(ehuuEURO*xhkujSS@~i`t)$LwyfVj z`E7EF+j1rFPIH?-a5(tlaX8$6al=2%Gb6Tf6mrYRJtH@b+%<CB$bBO>j@&u_nOjHh z9l3er?vdL^?jLCY=>TZ~=>cg1=>lm3=>us5>BQEwg7ktkgLH$mgY<(mgmi?og!F_o zg>;3qh4h6qhID3YT0?rXHO(R2A?+dkAq^rOA}u04B26M)B5fjlB8?)QBCR65+L~sO zZf#AwNWVzKNXJOaNY6;qNY_Z)NZ&}~NaslFNbk0$d8B(=(>~HavH{2rAX|X!0kR3m zE+E^0>;tk9$W9<zf$Rmc8OUzfn(aXL1KAK{N02Q+_5|4!WLJ=FLG}gN7-VOVtwHt% z*&JkdY|Zu{`(tZ12-zWIi;z7+HVN4!WSj7R-zQJATLVKGE@w)3P-IYuGbJ<xgTp<4 E0<)*Xw*UYD literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Berlin b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Berlin new file mode 100644 index 0000000000000000000000000000000000000000..7f6d958f8630cba512d8e58ca8edfbd516291522 GIT binary patch literal 2298 zcmd_qe@xVM9LMqR@gs$id#k~jfKV49cEa&9G05x$W^kHv8L5N>f)-(%#-KDTnRAWV zyT))1$saLh&944HTSIO3YqXF=yX-92mMgNFb2F#aSbd(~wrcCI{^_4Sci->hd-vz< zUQhqZ^$j`JKTeGKhKuupxp<zo)!cgHoNIbR=PvIF2eq&Nu)h4Z>fX*>IvmrYBje?A z@>Qpf9`MR1FXhRp=h9>>kRW46daTn`$G4u|zf{iDCF-Z;E)5lqrG^^EHFR*J^;yQC zoOREX&trNd9C1R!7u#gIZ;{-T`-{fAe$a&JU#c_mq&lx0*BKYy(3{Wf)0ywRsEJ39 zNz$R9B=6ZPv$|ALHa{z=O#!)Ob)DQ=;TKm?iQMKckhG+9xjk-%q(^%-{c4`h{w7T` zLJ2zOgGqYF;B|HPU(~tX=QOkPW6j!hR6X^tYj$;5asq>rTRbFr%X=h0xlamm+N5Bj zL*^xR>%8-|Quu4D&OhdryS}K>qJbJM9-6OrZ(pbjdXw~?2A3}EER=goqt#oVD2vj@ zwZuCirO_X0nd>VlyY#IrjyxfYM~CIU3$I9d@HMFzc}IOayJX3s{kpWdS?=%Jrpq3D zUY9qm)yg}Y)L&7i4>*_T3U`LCxaQHS_)@7lJ53+DI$KsA`AJuWVrBKdsZu@oqdeSk zMQXZ7Wlc>;YPWo^k1Tjg>Z(VyK4rJ8Ee>kK<ipyStlIe9E?qYf(DlRZ`sjJTK6Y@G zHhtJ4kMAhf=7CDtur5WP*q$#f%Zen>;FOKovt(1r&+_C{OIowywe|AX(l+Iqww-!k z+AoFmsW%7Y>CqwGy!&0<6717w+WWO*XNN{OA|j*yd__BWzQMjnO`81Qzbq?mhxs>K zNvVz~%bFtm!T<g|$K$xsvi`XL^?ilUZ+S~9xpA3K<~SVY?cm8Ahr|Cb2KAdc8xGW7 zM}}o<#)S+F85uG(WNgUbkkKK-L&k>;5E&sdL|ZdPWRSLIl*llVaUuh?H6yh(Lq*1l z3>FzJGF)3TUVaG%jEoo=GBRdl(6(mO$gq)dBLhc9jtm_cJ2H4=^vLj$@go61B7lSd zi2)J>Bnq}B3`iW1Kp>GoLV?5r2?i1kBpgUQkboc&K|+GW1PKZf6<ZS)BrdilFi2#O z&>*ovf`dc{2@et<BtS@nkPsm;LV|=u2?-MtCtDLJBvQ5}R7k9lU?I^$!iB^O2^bPF zBxFd;kf0$^L&Ao{&DI1CiJYwo9TGbvcu4e+@FDR-0*FKq2_X_gB#1~9kuV~0L;{IK z($<6$i6s(DB$`M#k$55jMIwrX6p1MkR3xfMSdq9Qfkh%~YeI{}*46|Ui7paeB)&+1 hkq9Fp#{X4}V@;^%W|M5UFE=wk)8qDKdoU|E_IIABaYO(B literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Bratislava b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Bratislava new file mode 100644 index 0000000000000000000000000000000000000000..ce8f433ece44f0b96b18d3b5780730e7f9cad9f5 GIT binary patch literal 2301 zcmc)Me@xVM9LMqRfyj?3d!GhJ^0SDLI{6KuL1rf~k~5XdNG1G%sCAKC#-KDTnRAWV zJ7YSBq!nY;jQRs>4XyQav=B|b>@3%oE7O{DGpE&9eV*T_(ei&kU+x~?@3FD5@p=y5 zl68&w*8fhF`GgnedGq4lx!JsRPjW5q4xYNWC)BS!y$AHA_f+?G?9!p=W*t5|PY%EC z(vep@a%4xL9DO!Jz6`|6v6Yc>d~=eXs5&MmUK~gZh6U1s)g|&()_|OJPm`~scS^{y zUP9+u#o3UlQ+x?J)jL;iDEM9D(tp<Yso$zA{II$%y{`#p-qIV7@6%}?zo3Z+4@uJg zeo5Z5S5i7vQa3&$Y5suRv}~2!T<w$e(sH@QT`U<%nR4r-1j&r>Xy)ZYo&H0HW(DK* zwofDV_JOPF?mee7x=v|!#}}Hj;h^R=ys3G0A;}L6NI}`46fW8+Maex<oZl+NqwP|X z*rg?>SIEpiT6ESSkKFl9t(NxHYuVr|y=&_no!y<JcQ>Z%oQ|1tPep`!8WLr0##t@* zj7mks=USQmom5`<QL4f}l&X;-x%bSgGOzy)sUH47z1urw{{ENszNRKw(78nyKJc6_ z@~_sKJN)XauGITo^L4R1OBY|s)!MiUsXaMGAG|zWmb~+;E)B-WvVBge8~8;YYQH4) zT_du*J}4_To!6DK-<4H$!`hI#TUM9#Yh%;_U6ZW3=BHh{b~K>thT8Pu(>{IVwWaF+ ztXUr2R;EpTHS*ZnR9(NdNSYUxN}$mtkLRVxhVtL!38y73IdR%@@q1~Fy`rs0KasWz zA${`gK6z?nP&e-WNH_KO=+kYz+P=MA!yIAZ6UJW=W6u*Kug7Isled|_W-BSpF~PE8 z#ftv#y=6HjkN>3F>$5!NHN5$(O7mcj!@-w*91h>LcVvDnKiWPzb|3erIVn{;uA=|Q zd0TeHGuuM;g=`Gj8L~BGZ^-75-67jU_J?c`*&(t;WRJ)uZOtx`ZQ7cBA{#|^ifk3x ztF75Aza6_pwu|f+*)XzWWXs5&ZOx{UT_f8@_Kj>D**UUxWber4k=-NPNA{020O<hI z0;C5>6KqWvkTxKFKpKH`0%--(3#1uHH;{H9{XiOmbOdP$(i5a9wx%mcTWn2Vkj5aL zL0W_K25An`9i%--e~<<t9YR`!^ayDZ(j}x#wx&-=qijv5kX9kRLYjqi3uzb9FQj2e z$B>pGJwuv?bPZ{nt?3)mI9t;>q;*K|kme!XL)wS*4{0FML8OI950NG!T}0Z5^bu*K zt?4AvN~D)aGm&m0?L_*CG!*G5(o&?SNK=unB5g(biZs^NbQWo?t?4b&T%@~5dy)Pk z4MsYQwAc}D+8Z(cnmG0x8Ff9be`0KsY+`JZZ2sGb73=Q+|9fwO>m2`GlDyy=SsveI bb01@hJtL2HyS)Y3McKJ-Z(c6u6vX@mfqZ3V literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Brussels b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Brussels new file mode 100644 index 0000000000000000000000000000000000000000..40d7124e5346af056c75e2f7012a51d94e8154b7 GIT binary patch literal 2933 zcmc)LdrXye9LMoPfFK%v(EtV1Q$(mCcSue0g6L52N=n|)MASq=G6v>#G1GMJYjdeX z<EV(26wN>}yyP91lBH-`&P|uvW%iUgt>*0aewcI9+WgPw;W@8!*pKlKygwNur{u&s z9=n>E@9=Qdn1}ZP^UTZ2KB@Ccn}_9>He9q;U#QeI<<<Jh9@Vmv6<St*H`+CBgSB=} zZT`B*me%^2X;yi{d~3tl(EN(91Z!h>skNz-o3+_%wzc_YeEyc}S=OiL2U}Z@_p-K~ z*l1O547Ikq2IcSgz|;C{(Nt?^ewyp^f}O6a!I7@&)RE3z(c;=2Tj;83@rSGC{#DnW z-_E+eIJekY``z!(y>(Zd`)bZO_m?el9avfI{IWFId9Y}O^U&ml&cm6-&LcgdTt~Z% zavtk;(0M%boa^|-rmnjFZJZ~s50F!v1GRo#vV8qfyqwM(tKSp^$hQM~>X~Id<?Mh^ zeYSjp`YsNV79}YvGZNJ=J6v04wANPXedM{gztunV7Y%6jg9f^v(!g8$we{8Q+UAT) zgAOm#;Jy1KWNW3gU0o*amZ-F!HD8>$1@ipp3GzZ(hJ<!ckryKpB`hRdUTWT2!ab8U z{C2!{_%Td7HUwy=qh9)Q)m@D!|4BP9zo?NVUuo2gy&9dpO=HGfkl2DMiA$=L_@N(5 zLfbWx7+WNX_vT8M;N{xo(s=3mPoZ|(mn^S-pQ+s|vNWl-o4&T7m-Z+P(VjV>+N-3i z^zQ4a$=SiuC+xbWB;S+1o+q?l=w<15^O~f(AC%PkI_ZCPy$q<_B55ZNX!_D6GH~l! z9h8?RgO|LoLq>e4LvttUuvc<5Bdwpl9ym~kM|9NTccL}ZzprGTZ>ewG?jR#~{i&lG zd}OrCPsUXJDr4u~lC0(RGA^q@#?Ss)-|VqlCX6|$+3i=!#H32i@vhcMZB-}TSfP{e z73h?@VtwmUhEClyN^_4*muU-=G_PWqygj+S<}XN)=|j3pK~A8&6Vpy+r2HlC`Z=U9 z%3lkuD^lcpM~hA$k>Z;dbmoo<d9S`!XRSJ<vn$u=oZ@nwyL7I)J>&U|yNA1ncN4EC zzB%7`H}!d1x5MEPWd1d|JRA;Rad<l%Ax^jEkG^;FdvK=l<ij&*=^2g@DH)Dr`x(Xu z^I|SHH}hpK`v>jMZW;ew4D;I@JY0Ls!~3B7<{G~1@->`xqt1a81gVIvDG5>&q$o&L zkh0jCx*&x?Dua{;sSQ#bq&i4>koq76LMmiyN`%x1DH2j8q)bSikU}AqLP~|y3Mm#+ zEu>sXy^w+-6|*%ZLu!T;4XGMZHl%Jy;gHH9r9*0m6c4E$Qa+@9NCA-w+L{s~HAISt zR1qm7Qb(kaNF|X{BDF+{$sYmLM9PWO6DcTCQKY0uO_8D^RYl5*)YaA$7O5;!TBNo} zagpjG<wfd?6d0*6QevdWNRg2$BV|VFj1=0|R2nHYQfs8xNVSo2BlSiKj#L~eIZ|_^ z=t$L(vLkgz3U6yFkCfil)E+55QhlWSNd1uoKvn=*0%Q%4ML<>oSq5YskcB{20$B=M zvlhr=*qYTqmIGN2WI>P>L6!tr6J$}4RY8^oSr=qskd;A}#@4J2vN*P8b&%yj)(2T2 zWQC9=Le>abBxIG4WkS{oStw+skflP_3Rx^$vs%b<A?t-K7_wr>k|Aq`EE=+E$g&~p zhAbSia>&vlYlkeJtyw)}`E1SlAq$ACAhLwW8X}8`tRglpqk9u~4^I!zre5Apd~?3> z_G$LC?g!Io2GUHUxy&^B3gcwPPab{m=KtVK<H?6-7|7oLH<FL7B%A4DwzP9hvf0sy S^ti}`$modlm}rcO^Z6GUA-G)t literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Bucharest b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Bucharest new file mode 100644 index 0000000000000000000000000000000000000000..4303b903e5e007484c0d8e1eea43a35e9b53f38b GIT binary patch literal 2184 zcmdtie@xVM9LMqR1y}6)u{RQd0iu$LcESOoXy7jbvN%OKja1}oA!41BsO(6TTRO*z z+&g2HrJF9ttQql#Wrjv78Ex*QAFj2={4QIy=B$mJYmU|D`R$L^Tz|CnSMS^1<HoOz z?OxB&iuDco)(w|nzQU91Fi+kmM$OBy-p><`&l$0g|Gdxs;NlB*-}&wKiNQCWlkdOg ze0cbIr~lP9=cA4d&Z)?1=XB#@=S<B!XW+p+=i{P@&e`lF=abZUC-Lpi>@n3&RZ{TQ zp*stP?BuNB=v_&%Xi8jvG-aeWntJJAbnF*<qIaL!5luVsj+K7ofR(ZDMQdE=vsPx? zCTo1S-kPv#nKiMp+{!ARY2D+`wkD;IweG#mXHE7NMkinO+1cM+x2Jr0*`7KuY~Ob@ zX8RBI+ta#w?VO!2RpoBpV+ZQDROQw7IQh+6hYCviWct#Vr7&Z^%*c<(jL~)}O6$_1 z;WaYrdW+6JSt|E`Q=`S*bz0IlTj%VWuXA5d*Le+DI)CRZSy1lP()u)cVA2m-Ryr!> z-cPk6>!MU#`Cb;rosxyIL3!xX8}e|^TT*$hUxT|lWzms?y11!HsycV*l1HA?rQx+& zJu|GK$_ibUvPhTvr|9x)0j)_cmzuA}=%ZJ&WyO2H>dFf~S#=;$YL8x))$Jov*A)}H z?t-k@_LDv~_n16hdrs>!_sZIm9&Jc?SJ!2zuKV#7Z5(aZ^@FYY#BfNTJiJoFXE(}* zjuLI^u9l}7Gxh0Rg|cx;u{1ZN$fmq;vbpRx*^+2UOK!5Z{PL|t?zpCrp#f>V^0hwG z+bvsTecHD7v~KI!uiIM>Y5VSW^>}ZJ`}-r_8-K&s{`v{N8}GgOmjC);S*a28QROw> zvZe++=F^)#-n#vt-d6@g)&lb^E34)uWPa7-`SZ!2@pwZ2VkEzt3!irqkg*_xaW$hs zhJ%a;84xleWJt)EkU=4%LWYHm3mF(PGGu7T*!T|^95Om&c*yvW0U{$rhUjX>hzt@L zB{EE8oE!t?7%9h4ImXH{SdP(h43}fP90TSUF~^WO#_Vbajf@%@HZpEx;K<04p(A5Q z29Jy$89p+8BmhVRkPsj-a5X_dqTp)6fW!d_1QH1(6i6(PU?9;z!hysC2?!DqBqT^o zkf0z@aW!E<;^JxogG2@i4H6q9I7oDm@F4L)0)#{e2@w(_BuGe<TuqpeIJufYA(28t zg~SR877{HaTu8i-fFTh>LWaZ)2^tbLBy33BTutDR$RVLaVuu6|i5?O@Bz{N$kq9Co zL}G{p5s4xaMkJ1|CXh%ZT}>#FSR%nhqKSkPi6;_J{9i}ZXUaM)pT_!w1v!N|f!qRr LFfZV~o9_DqL0CBH literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Budapest b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Budapest new file mode 100644 index 0000000000000000000000000000000000000000..b76c873d9256e1d73c2ea672140b813f15657bc7 GIT binary patch literal 2368 zcmdtie@xVM9LMqFS0*#}Cc{$!v51gD;P{moWOe~FI1{;yR00!GljtO3M`@Tc*Bo<i zi@^v;MIvi<s|{)mUHPLXi_kJMY!(w0Y|T;RtTn99^K1XL{^+0n==<G$AK&}l?w{Me zp6(SJ%93n<J0_VYyf~W7i~C!)noG+Rdr8Z{*|F9^pSE>$>+2t??x}0iy{{dYeWf+p z?wKX~U5(N^-d)l+k}IFTW!L_8r<{BxMNVytmM@yULtpOf^_*VXsbA%WZXHNJCSS*P z$(fmN$TyQ4WzheK4qo=k`St^2!}&j#T-f%eTy$L5OI6opBxFcO-9s|^(@~w~iW$2t z`8!W&)Jf0uX&-y+0q=S2<L#aq!>@W~p04xEI<{NG4jq>8gFcC9-6ON>RU$XPBy-9u z<@Qx;<c>VIL}g^jopEUr9UdchO_?DvK~9ainxb<rMr-WAbiMnNNqSG$uNv2JS?4vJ z)%d#4G@<H{CYHXVj-o+Hs_c^F%pOTu)+nhFZIYJcm9&XknIG1m^Utl8^xvy>!C|M| z_idqObQWu7&jP)F$0A+W60Q%FMd_ltba^m4NS&o&@=)}MW;rJ$JE&K4qP~}$E0<(( zz!6#8e?lG}-Y>bnw<WLdBX#Ynmn8@H=_3^tvb27?=0CPmmzA&8f_ux=otLAJ+L!3^ zxL93&El~?Yv!(FNt@`-Yxw7K@Uv%X_u&mk}B1K(4$`iHYQryrlCB*}>ddm;`<iZbR zO;MkgMmEdZOrMtB+^y>(RM(9*>H3LE-Eg8tpE~E(jR#h0`KO!Y>6bILqO(ArSs$sM z9jUS@KSL_Z?DDK*wp3;PCeMY~q&gu~tH;iZcj`6uo;ofyR|fU@cRS^U{vO@jd{npi z+VsVm4z1l)tNwoe0fBzzYR<p_bDH<&$&I_ep5OS?Kj^0a?zGuLE|`D4Eqsn&pv^W_ zY?J@#KF{U0IkO75xcP>kIndm=|Ha1sFvmvw?p9=LmS%6r=8)YX+e7w;Y!KNYvPEQ% z$R?3pBHKjviEI?vDY8{$ugGSR-6GpX_KR#7*)g(ZOS5NW)5xxoZ6o_eHjeBZ*}A3K zJHI5GM|O{FAK5?B087&Wqy<P1kR~8qK-z%x0cix%38WQBFOX&+-9Xxb^aE)K(h*D3 z5~L?cQ;@D8Z9)2iGzRGm(i)^UNOO?xAnif=gER=~kfmu6(j!aLB&177n~**sjY2ww zv<m4J(k!G~NV|}JAq_)1hO`XnnWbqO(ltxdHl%Mz<B-lFtwVZ;G!N+>(mterNCS}$ zA}vIEXla^=bkWkZ5$Pk+NTicUE0JCz%|yD1v=iwk(om$MNK28PB27iQYH8Yv^c86= z(pjXnNN<tmBHcyWi}V+1Fw$Y9#Ym5lCL>+8G;K!uY-t*ebQ)<j(rcvINVk!8<Nv+i Z!6xbR9K=1&l^mZMpBU$IBw|8x@Sl-7wT}P* literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Busingen b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Busingen new file mode 100644 index 0000000000000000000000000000000000000000..ad6cf59281a1046d9dcd045fda521585e3e33e06 GIT binary patch literal 1909 zcmciCX-L$09LMqhq+=x|UkjT`&1!PZnmp6((5_jPcE=8#Ej!E(waeVJGVQV`Btqi5 zAVpMc%Z5ah^}y<Z9c&jJCJUQH7eUcw5kZ9=Nd4abC5WxZ{r}9ohV0?@{qfIST%2Tm z^*GJH@Zni)KK$;!(R^KTEwQfLFSD+;`>f`(xmK9_nfB^=M_mEe)b;AL_I_|g`~164 z`=0w<!%v=)h(iq$x#th*SE~}WZj<ycDVG7W7sx=LU)*UKGRTuE(GfB7L$}@%<Me9G zo8db6VYJ4!_R=92I_uEJx9ZvdREO2w(zq>GHGbtuO(;C9iTO7rsk~8=)0<>?&JIb5 z+$*U`m6F;~EhEC~bj00xGV()(jymO)(YNz7t-e6hn?~uFn(;bzcZ7~BcI)^pBV|IS zQ@w@Z@>BF<&G2?ert`99x$jBVi$^js;BT4Oa!G!E@R$73a8P{BXEb|ztxP)fr%o;{ zl_|BGb?WqOnp0Awxj&Yu-<PGox+du~PpnRBPtd%uOv$^^Lub4hEHjV4)>*B=GJ9XB z<TpN-In}SEpsq#c7PQK|^=&$T><L+r->ijEyQC<+L5sT_(}j_$3!m)NMIGh3_)?WF zx$D=Z2WDx>#WGp8HC;>VbLF>1QM$Y)Marh8NqMnLRwVY5l^O43Rj4Hu@nKr=^1f7t zv}@%*=cVe!O<i-eUe>lW>AGEKb$!EL-B7h(tG8EcCx>|h0>AfbSzXLgSyn`UN1$be zh}HGW-@a_W<;}?D%g_IEIP5R~w{JGc{E-h&rTOqX^rLwOy=>cvW!HmhkQ=r&cZ}RJ za?d>6G;-I-ZQGjrMs6IrbL7^Mdq-{_xqIaHk^4s)KsrELKzcx$K)OKMK>DyXjUb&M ztsuQ1%^=+%?I8Ui4Iv#NEg?N2O(9(&Z6STxn#PdMY)xxOZ%A`UcSw6ke@KH!he(S^ zk4Te9mq?pPpGc!fr?#e5q*q(hEYdB~F48a3Fw!y7GSV~BG}1NFHqtlJIMTVTX&vd^ z)-;cFkF<~Uk8A+41IQL2dw^^LvJ1#IAp3x91hNyzRv>#}Yc>Pf4P-lz{XjMZ*%4$* zkUc>*1=$s3TabN0HU`-lWNVPUu{E26?2fJ39%O%z4MKJZ*&<|*kWE5%$q~@Wyn)W| z{eB*%p!b#;CNocFr$WT){^f7xX~O>|>c5RL-@#_Hh9$CIp6ukfl(+;>c47j?CkKB5 Dj=i{v literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Chisinau b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Chisinau new file mode 100644 index 0000000000000000000000000000000000000000..5ee23fe0e59f044598675db44d53c20590b88934 GIT binary patch literal 2390 zcmeIye@xVM9LMqZ#jg{Q&Nbq<8YYmQ{1n9!J;lQm&_fW(1g|7SK?@bb1pUl8M)PN4 z&59LkO=VMti%|+1l_@KNtFcu>>$^4kJ^ik7w#?P%`6brc`lJ5nzh1YyCwzBv&iQ^6 zty*7^CVxA}A5Zt|@^ie>A1_tC9P)a{NA@#wfApTY-r_y``F?Nr;7)H(Uz>66jTemb zC-xd|9<4Wen>HG6)s-1<S1vQ&DRCJW9!xdf&5ScHCf;RSitso3dYZlOJ=x&t|0>t< zL0kBtfmgB}gNJ80d`k~`!xE1B?vA+Z3bzk?!hgB5H{#n+U*vGME2_WQ7v0lp#+-b{ zjBVL%PT04_oLFCOPO4sE-m^N#jLVy4PM(u!-s_Asr^E!C@ndh9@!5GsLO_N}xDl@s zuZFAphQ9Ysy)fvR);ZvHzIxg-{YZy5X-~5!dFx?sN_nj(wY1$x+q}b<o^?uQEN_yG z*n=`NZG+6bT_c&%jVkj>q0GKjsqR0QArA~MQFD$JsH|?Mn%kJJ=DirIToqwz{+?;F zz<pC?myeT$Q$AJh?CX*f(5)6t{!kWO`$QJ|y(WtX&dQQ6o|WA87Rl>Bt@01-l%*$| z)v`@q@$9Qr1uN^-^6HhUa8{Wr%A2iLgu7I+Gg=kjj8i3HnNsqxzk29Kl&tFdQawEM ztE_JIlhV%5q-@t!S#zXUylXDWBMq0;qx0HiZRvScK5?%+mer~%?8nu**xhQ~*H5d; z+vRF~UzOT$B}Y}A$XC@D*UHAGWVPv-TOO|*ubya3keY%d*<3M3wxl{_tNS~tb^IXP zl7rMXb4cn!zfpC*F4=zVef3nwQQ0wYO4UE#sT$f3s-4@PQ@ak-DBB$Ye*S-b1&#@_ z2ieC4kGw+0{rL*i-wX`+?_MI&cKv@?qJ9#8k%&6czfDcCg^0vVlJTRTBTqsd62=o- z<mhLn%Qk`UOWf$^=#$YuAuqp3vh{m`e!Ja;eCP+(TmO<@xKO`y`3u-=BX8@6qJMFM zzv&fs_5DmaManr+PSUDAOUh|d&XaPYlryEAD&<@$Crde7%IQ+hmvX|CGp3v}<(w%e zO*w1IX;aRda^jRTr<^+f7@Rxh<SA!wRi8fP{3!%b7@$x<;ebK{g#`)?6dou<P?(@l zLE(Zz289i)nhpvdRy83MMktg}IH8b2VTD2qg%=7j6lN&YP`IIx!(fL&4}%}8nji*4 zRy9QojwmECSfbEG;fX>Ng((VE6s{O#QP^V8Md6D<7=<ybnlc7wRyAo1))=%gc%u-< zV2(l^gF6a&6!s|eQTU?}NMX>brjWv+RZSv=MFx!&9vMV3m}F4N;F3WmgG~yZ3_dA@ zG8m;$O5xP1CY8b}g;ol$6k;jNGN`3+%OID+E`weMzYKyI3^OQZaBNkR%wXB7rkTMr qg=hxT6sjp)Q^=<Ov;B|Q4%XkAo(A*I{Pd)Zq!ed<Y6?wG5B?oV8;IQi literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Copenhagen b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Copenhagen new file mode 100644 index 0000000000000000000000000000000000000000..776be6e4a6d5a054152135a1ad149576052f49a1 GIT binary patch literal 2137 zcmciCeN0t#9LMo<xm+<)_9caD@nj*PcI6rJ0W`Y;Q@NIMReV4+5ygn)rVL7@Oj&Ep zeRVA7&}rpZHKG1M{R4%m<!~WVcE_xoEm!t5b2DcTWA%F<$8go({?5*MogK!;AAH{a z<&_l~)_+cz`NGZFWp3U_ziJ*W@lC5+f?fSR-ldy*ug{kY@4L0{9j{#6n<f1_lH{{M zw0u56^iusU`68xGgR9ykc=a0@C_JwN-DhNsZ;p)3{8OV6f7a+RU#r`BLEX2yblkNM z_2Em0^^voCH0I<fi9OmbaR&}be3MGT*4JcwRX`qHxmF%4@=IcFzD)4sNK$OFJU(ii zB)hztd^<}gewU<^g3&tplQ4av<9GEO`BA4df2k=uKh@ODCpE3SP18#+OGcnWGV?km zYtdVh9d}T2GU_B}utBEAH0#tWYh>DAwL1NjS7v-wqPeYQn%6m9XEx5(SuL^pR7IlB z-Z@R4E^w*0JVxduUDtf?pcJ^yYhmJ5DZKH$%ypiYxqUq{@7lXEzx@L#>g`tF?j~7q z^lg2nx>}xXdR-STeNz`zt<&NstJGgqsEgeTbctt@F1eGYB~b-ZGVqWtyFF2sAOB5P z1jA+J;Yca%_(fJV+>)~9K3QEBlr`Ia(&uKKkhP_~TAr|9*5$Qp#mHm2K2CN05Bqe( zU_dK->UHB4zdrxo3avU<BQLy>r`4^+^5TXB-PD*ZH4AekP~n!B(&J@w{vWa>(vsTL zD6PHut<*)_(YpSRrT)fcefgtSd8MyYx9&fq+u9H6_WC2*u)9G+93c*8=slNf#Qnc4 z>%m_0ziGvecZ6D2gjf#@J@0-Q{$AwsTi*O)9)5nqVGf!X|Nk#xr1>E?r_tQJNB(V2 zW#h#TtQqxd7P1Umvkqh-$V!l<AZtMugRBNw4zeC(LCA`bCE1!aA&as#tKyGiS;)GO zg&`|LmS$_#hAa+Q9kM)ReaHfl6(UPS)`%<;StYVeWSz)Dk(DA#Mb>I-7K^MFSuV0( zWWmUaktHK*Miz~%8d)~7Ze-!e%8{ibYqvFvM^<lZmXE9-DF9Ldqy$I}kRl*eK+1sB z0VxDh38WNAEs$a$)vz_?K<Z&@3W8JwDG5>&q$o&Lkg_0kK?;LZ1}P0v8>Bc$b!<&} zkowq~0wEPbN`%x1DH2j8q)bSikU}AqLP~|y3Mm#+Eu>sXy=+avkcuHCLu!T;4XGMZ zHl%Jy;gHH9r9*0m6c4E$Qa+@9wx)nc1#L|Uks2aJM5>6C5ve0mNTiYuXNWT-)OF7_ zBJBQOLzy(OG?_F}G%bq|YxL0b?w8^3b}auD%;931w{TO@De3go<I7CRPD%6l($g?C GGyET=z$0G( literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Dublin b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Dublin new file mode 100644 index 0000000000000000000000000000000000000000..1d994902db21814a626e42639d7a96b18ee73756 GIT binary patch literal 3492 zcmeI!Sx}W_9LMpO5Cz;G%`H)R3^xq%fJ;gexe|)xa#GR^Ek#W-Bx6J~aw<#5asD=z znVOGFN-ntJisl;XWG*Q#xbNb=CN5~t_r2(*tEMix=sk1zoB^(w;rIP}dks#GbpG-L z*zfS>IcMK|uJnohGOgZ<Nz)FNt}uO%$IO_!)qFpFhM75~x-p-x)3eeao7n@V>p7!# zn7IjS%nvb-^t`%#_5AvII;&xr&bm@$7C8IOg8a&QVc|`^XnTrYyz@7mJwHJ&F&Sp* z7aqOrtG#A<YP?yIw%p`&2{$X_dg)ajWmZR~n>FQco3#}a&Dt9W%(_BH=N`VL*B|Yv zH>}yOe_Hm$Z2Wem-ZU*pZyqs4Zy8yvw<c!jZC&S@pIh|Sc~P77_QZo`dqIFX5O+%F z*Q#v}CM?p2!W!tq;S=@Y2Vd)ga;duD%2j>zd{uMom)-jKwg=`!&Si5lyNW(Fd6zkz z_NqBEWVk-tt)V&R6>~najJXiKSYHeZ)t4%H&80`Bbz$)^eYxP8zH+>~zPfIYzP93_ zx&GZUePhf(b93fseXC!bxt*D$?{rMocavJ{d$r4&-(y1bedmTL3ii`Qr}mi#PcG_* zn^u@dmwe6RQ43A+_S{t8)I41xG*SC?$<ieQqI4<GcwMTnh7M3EI$*~W9e6WAmtJ1o zl-cXiWhXs0<(5{|<%gXxYHGNt&~=lkn4!$G5wlID#M`EF$Q7y5B2TLN{wmd~Wl6QO zOXRtt@lt*3Bndh_U)5NYt!i!_r)o_Q6+CN*(kW@G_L$D<`FO7i>DO4*32UzEcI+he z%2ZSJ8#a>q_nJy*V0j76uObZ#Z^;WeMH04izciX$AmKl*l*Yr?i)Y*viRg1gMW*Gb zCegX7X}51wvzjwh^T-jZd2yy{5j0s^9Pg)EK1!FU4Q<s+M-!#hyd;Uvjgptgww9P_ zHRP4#5NZ8cOVy@>pS0~Cq}tWJDDB%8s}6oUB{t-wioJe8#rbYlal3b@j%VknPT31o z{H~4CdEx|>uxOUNHgu@!GT~F{+H<^gOBo>DUrZ5ie5|})H9>lWg-Vb69!ad+K_wol zC~w?rpn9#kE4}jr)tjb*>XUO-y_I=KB~9L~`X=S8exonT+cB%vJAHOZ|KO==Ky<bw z`>&LNHAMzqnj(XW(`4|D40-psSB7NumXy3<>b)<cW$3)_>it2%k~+4T8rHRyN=vS) zK8UELhPQv9KCIxV^v0DX{pJ}pqTGEMv3HxwxPC-NE}f@F?aq~trf!kZ*)!zhjJc9I zF;je=DdGF)%df=0{PHhZ>Ob&$`t)HP$FX0_J0%>)KiJ3Lamp#5GIoj_N4cNvcO1vZ z{p`3ub^PNyd!2Un9oOCKw6X74``P}E`|#WL@$qrIe`EWe+NbBfz+=b;y4oE?wh-Av zWD}8HM79yxM`R<BokX@0*-K<Ik=;bL)79=LvZ1baN0BW>_7vGvWLJ@GMfMfhSY&6B ztwr`0*<56Ik?lqH7ujG}yTiy9BYTW&GP29aHY59tY&5dd$W|kJjchiu+sJk!`|WBs z9NBSX%aJ`tHXYe@SG(=VzPs9uM|K|BdSvgB%|~`0*?wgIkp>_gKw5zG0BHi!1*8qG zwhu@nkWL`2Kze~R1L+3R4x}GQLy(RjEkSyMGzIAj(iWsIuC_5qXOPw)y+N9TbccTx z+Jp25X%NyOq(!c_M@W-gZI_TXA$>v`g>(vO71ArDSxC2#b|L*j8isTXX&KTpq-n0U zYe?IWz9Ef6I)}6l=^fHMq<cvFkp3YJL^_DH5a}V(L|5BIq>Zk&k4PhtP9m*DdWkd> z=_b-nq@PGbk&YrQMS6-f)zx+tX{)R4E7Dk`vq)=^-XhIKx{I_I=`Ye?q{B#yksc#W zM!Jl&+12(LX|${DG}3CM*GRLGZX@kR`i(Rk={VAIq~}P}k**_cceQ;-8t-a5kF*}? zJ<@!n`$+qd{v$U4at9!{0CEo?Hvw`NAh!W>A0Rh^tGyGDTLHNjkedOy8<5)pxgU@l z0=XlQTLQT!kedRzE0Eg)xi63#!`0py$gSaO?+xVUK<*CY_CW3r<OV_R5d8lZv3~^h d&u)=Gd#W^wuy=|ltaF4Xyji%l2{euf`~${g?PmZ0 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Gibraltar b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Gibraltar new file mode 100644 index 0000000000000000000000000000000000000000..117aadb8364cd7901388098503f4538c7b445aeb GIT binary patch literal 3052 zcmeIzSx}W_9LMo<Ledz=9-ROa#K#N~Lj+uMBTGc0fLu<ByQZQhk&+R(WKCvG<2e5s ziX0#xlh851C0udI4L3v)A;nD7+#R#bQB$<%`!-!w7v6N$`_6kl&zza}?ws$>Gi-87 zl<RL-L;DR6SGj#Sw|K{X<hCs~xwYOp?_h+<FW6ze$jdj2a#|Sk{zknx<F5H~LY`hS zbB`%VT5rDUeMc7tkI_p*%Js7LVS3r+TV}bd+AOc})n8w{ri*r`>f*hJb;;5sy~1Rf zl^;atRi7L(tEVQIZ_-zr(*EIQP5dyuHbR+oQ5k0aqraLB&63TApO2W07hSsS=r4NH z@gaKi`f9yp)jhNI^ELY0+yK2TGe>WqQLlF-XX%{-3e2u<!*zL&ZF+Zdt=V1oh}q}Y zR`%r#mHkygQt?(#Ik3tlm1C0CK{+jl(nd*Dx}U1L6QvGMzNf3lg_<Mrr*utFYg5yw zUTRLBQng7%y7r!zIU2q|AHDslu4^(?*ImA%kDv87-|w%~CwAU8Ka^fFCrkYFsq6~# zWBT*v^pxrP%)s{MCy$u3QH{;H=wf|7AXHy?%wzn$4v7EtEz<nV3VFQRNQ)gGOTebh zDzK<Twai<jg64~AHS1laQ`1%J5#!Vo2_Ds^SFCz6tg8wR3{h<xH&-FvF%oj4v$Q)K zETJ`i(tcM%d8+i5gcV$r4%u}QK6k%#oW4mS#urQE$YUxhy;OCIE>oQcex|y#%vW8b zGF8|5IjUPgwsbo&R&~FVAw4$7sGi4@rB~r-i7x9Q&&+#Hdglhpvng%lxw+j{pMKsF zGd@7|4L&ciG4-mS_g;x>b5g}!J*VQmwyF5aJ?e!sOVo=c%T+?fR!LkiUnLbSmY34f zRR8(!$$%jr$-vYJGU(}4@g&5_%l=6+I4o2K-;9uC-+n6jyJj-<MmsfZ?Qb%?#z&1X zP1VTKD{9o7>uPj%r5ZE3Mva|)NnYu_PK_H`A>&&uR1>00B&E?Bnb=Zf;)NWURG%)B z_hiYdCp<D`*>FiMpQc{>Fj~?I2dUR5wUVjxx~ORbda3jjfAvOWkeVKQTfN!Tr7}AD zO2)O*DznK=$vm`EWnDccGgcO=nU!TSYvFd8U6L<vXBEht1#{#f_k-SE?!Ru{^!lgw z8+bqb-`@A{|9;p0!Cg(1y8*fyxm<zT-I#A&O`WsvpXY=`kE_ohk1G!Q+Cxk%k3G2D zZnu4$*WGT<1GMG7y@pizG(Z~TXgh<n2I&pb9Hcu)dyxJh4MIAEv<T@D(j=ryNShpO zpO8j5+D;*@LVATX3+WcpE~H;b!;p?4Ekk;SG!5w*(l(@TNaGxB=aAMRy+fLZbPs7C z(m$kuNC%M?B0WT!h;$KYBhp7l+eoC7j<%IZFOg;<-9*}n^b=_)(osj-QlzIyQ<1JB zZFRJLb+nB|I_qd#i}cpfHW%rxqirwJU!=iEhmjT|Jw}?0bQx(g(r2X6NT-ojBfUnN z%}<<eJKA<5{YDy&bR20p(sQKgNY|0JBYj62k8~bsJ<@xm`AGMX_B-1CBO8G10I~(h z9w3{5>;ke4$UYz&f$Rjb706y7n}O^GvK@|gKadS^v^#=q39={1rXah5Yzwk4$i^T$ zgKQ15H^}B7yMt^GvOmZMIocgUw#d=$5wc0hE+N~5>=Uw4$W9?!h3plwS;%f7+lA~G zvSE&P$B->^w0nkZ8nSE1wjuk5Y#g$4$kriyhio3Qd&u@7`-f~GvV+JLI@&!%HWArH zWE+uvL^cxHNn|ULy+k$>*-d0Sk^MwA6xmT^OC9Z=BAe=HcNN)IWM7euMRpe1T4ZnW g|IPjP&GoTc+#!-N4omD5-X%ODEHN?yJ9hH<16u-G00000 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Guernsey b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Guernsey new file mode 100644 index 0000000000000000000000000000000000000000..ac02a81440f47a67b9f01d3fbcdb085266d20894 GIT binary patch literal 3648 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 Nbd8QojP~#<@K40&SY`kK literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Helsinki b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Helsinki new file mode 100644 index 0000000000000000000000000000000000000000..b4f8f9cbb57450549933f83ac90dd56a2ca75344 GIT binary patch literal 1900 zcmdVaYiP}J9LMqh%+NyL(Hv|u%xpNev#Z<YHfM9$FguvbY}n>D!>~5Db3~GszG{&W zvX;c`!B9r-BI~5Igq9-LB!!R`zxUr0<&h`KIi3IOv`%~UeSbXjSCl4Nf4n-GzwqHz zX+C@p@tH^6`ZZzq{JBLfS6>u`Mz#5R_4NB3fmeKvkBz?G&(CU~2gkJUjeQz+>9T~M zZjgw>N2OnlO5~R9(!Z=i1}t1E1G7C6mFAW~&QysGkCDM$drM4EhQ@qO*4P)(I;6Fi z4!zY`hc$gwXWbheUi(<%cHYzY4VTnad`1%r9!X+FlO&}#OY*G!k`i%5QWL8rwcRTt z!)kS8+hQ5@y;4VC&X6%r@-?l#P}7@7>)2frbljnE9bX!y6LyZ0iJ3u~Q5+_dqF<>y zqg^tC?rK)lQ^|V&Ql<o6lPUf?GWGchnbvShvRkfb&fXfCe)_o1C@+_pH9ItS?jD_0 zR-$<$%G8scrL!H=b&hk0&iUff{LoCvf7nCkeU6p+=RfI!)?it9EJO;L-pL~GM=7lJ zOHpB~EZ+K7myEk0OAA`GIP##Bq&H}3mvg!-LUq~e1G>DuLRZ|W)|G7@U3GGSmfc<_ zt9Pesd3~O&SstltccsX>+%%~ub;$aJezL*+O*V#DQW+nrl^>o-RrfDib^oSRzkj5g z8tY}Vzgf2&ysldtj_9`PI`!`LYCvEI``t0<U%oBNQDP2?XGhB#>I&#$S>gSyZohxe z&hc22&ByJ|<Kf}=RzSe7r{^zD_lJ4qT^xJ}Ibr0CkyGYBa?Z#}BWG=EP8&II<iwFP zM@}6%cjV-evqw%JIe#PpBm*P`BnKo3Bnu=BTayQp2$Bhs3X%(w43Z6!4w4U&5Rws+ z5|R^=6p|H^maWMPNzB${hNOn%h9rk%hopz(ha`w(h@^<*h$M+*iKL0-i6m-kGDT9g zHMt_mBH1G8BKaZ-BN-zpBRL~UBUvM9BY7i<+nUUg)NM`fNb*SbNcu?r$OIrWfJ^~0 z2goEKvw%zkG7rc^ATxnXg{_$jWHON1K&Atk4`f1+89}B5nG<AEkXb>d1(_FQVvw0Z zrpDIH4Kg{lW_FP2LFNaUAY_J+DMIE5|KmvtHXAiOk+pK>B*mq~x#E+YISDTNTXOJE D35>6g literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Isle_of_Man b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Isle_of_Man new file mode 100644 index 0000000000000000000000000000000000000000..ac02a81440f47a67b9f01d3fbcdb085266d20894 GIT binary patch literal 3648 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 Nbd8QojP~#<@K40&SY`kK literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Istanbul b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Istanbul new file mode 100644 index 0000000000000000000000000000000000000000..508446bb6aee2841ab88e82607a6ad6e748e7db7 GIT binary patch literal 1947 zcmd_qZ%9>V0LSs?`nP+{bz_9Pc+<9~_m<WCx4Je{%S>!HcdDyFf5t&8ib5V%gGPe4 zDT7wf8GBJA#8%G0%Gwr#Q7fV`boS>^w&_xK##j)+d<I!_QucgLuUc=`>z&KFpX24? zi_7!<#nx`!TqvHq()1_XTs!s6b0DtYtbL=0+9zk2?YA!2M>jP($98{cbkxSpFUrr_ zojD=rc&Nqh3Wv?E-yYc~#`ZcVFBcd+d&-?&&&x*d@=^20YjLBmuiLz_&1>8|T4MHB zCK$J(>CR8HcH2MajW`3|4fbHdL38kKx&6z%ubtaB)*D0pwmJM&neo^CZ_WD+BgW{K z6!SrL#7=4YRHl|3mZ{_K3vZxVdhI^p8+%u#efc;(d9XsJchtpS>O3W<v@M8F`FpAn z*n36>hR!&dcWf2>VMI-DFOXULcc|><jcUgBI`!)MW$Lx)0yVQVtX`iJP&q-L%1s+r zq2!PZjlLqoe|Y7r{(t1`@9)XHvqN%D$5lCZU#ptec3Qr%^D~*h@e^6F;k+t*@1QDL zbVL=e`ar!oJ+9^#u2b_LHK<7DE*TkKs!GP!%7x$Ms<&>J%F@nCx#(P$Ec+-&mbVL8 zu{l*PZVRd<Rd;1&<72fnr%zT@I%-*RuT?$sSAX@Ncl<Spm;5!?di=|OKjweCyUQQF za?x6GVA!fX`MLE@Q<LA=-)gN~^RcyR`zC93<bppIt+whiYOVURBUb&xd~411c}B~` z#Dpg?;YD6a$w`SRssH^o$@|<ZDM^UTus%j2bBoZ=v-3TZgb2<M={$?6LPRP&)BgSW zv)_rXh>03~S5>X%Ehh5vi}YR0f7O>qUr(RhKSb;W4!HhJChEWG89)v?a@bw<fkzHK za`2JEj|6~3fP{d=;HrZ_qCmnx;y?m%)sY~fAh969AkiS<An_mpArT=VAu+k?ppdAL zu#mWrz>vt0(2&@W;P_pM4hhdy$Hzs0t~x?4LPTOjf<&T3!bIY9)qx_By6RAoSdn0n zXpwM{c#(jSh>?(yn3157sFARdxLtMNNaRT9NbE@PNc2efNc_kEAR~Yb0Wt>2ARwcF z3<EL_u6iJlk#N;Rfs6$*7|3WK!-0$kG9bu^AVY$T2{I_is360Fj0-X_$jG?rp+UyR zRSym_I>_)K<AV$kGD64@A!CFL5;982Fd^fF3=}d_u6n4DvBDO82LBg><tx>LRyMcD F_XJx;ZRG#} literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Jersey b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Jersey new file mode 100644 index 0000000000000000000000000000000000000000..ac02a81440f47a67b9f01d3fbcdb085266d20894 GIT binary patch literal 3648 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 Nbd8QojP~#<@K40&SY`kK literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Kaliningrad b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Kaliningrad new file mode 100644 index 0000000000000000000000000000000000000000..cc99beabe4ffc5107c4719d1201d6583b9ead03a GIT binary patch literal 1493 zcmds$TS${(9Ebn&l-kr$=sahdhn$wpL#wo`In5JTu8U6Kg-AtETF{Neiwuc~S_kPu z%MdYw6rux^30-s%WabJXTY(S}cv0U?L`Bs5d}<MNQMdg*_C6oq24n1byu0?dIpvRw zn}6D*$$h5MN3Yf1(mVCi=$jt#UmCpazkJv4@AqBwKZ<JikH4$8J-KH0PYk$iPtTRu zCcCn2fsO=Qp!3*FpvTwp?BsCM^PP8Q;&ZP~CM3S9v_}S;>|f#@B+kZ8CI#J<$>ZlI zQ|@0eQm>yi()zlL^ixNSWu2`?#=#xN@;%i?X2V(|t31zGQIKS0rzS~`HCl4ROI7a2 z9F_Ohu2xP(s{DtamE+c|Di{o^!VBYSm2XU~K02a`TKm<Sy^qD&F(kzm!&0*Sgp{V8 zkuv82Df`wgu9R-&dfhDRzV1`&$4X^Guuhc^ZBrGa1!`k=vD(xdt18>#)n=bVws<}% zcWaDPWlt-Q`-4=6kE)uifYiKyA+@15rFP<;)V=AE`jI|q7{8$!PahX=gX3_BB_uTL z=M@ni5xHpYii)1U7F+-Rim{3;b?LuEQZp=JBC$4!`u#q?$P&X7St8=9v?Pe+7fJHM zx$xxIXY{-2bDwW$^orZl%;6OeHy(Y{*j%Mw_2MWh=4&mMxznQO{RfS{>m3@{y%nO9 zNv#w_D~MVUy&#G~G=r!H(G8*;L_3Ij5dBPQ1x;!VAu2+2<X501L`#U8CbgarMIo9( zRE6jYQ5K>tL|ur!5QQNcLsW+73{e`QHA8KN-X^u;5X~W~Lv)8I578c?K16>=0+0+K zDKK(iB*Dmnkp?3VlR6PbCMI<%j9eheFtUN91IY)H5F{f=N|2lwNkOt=qy@=~kr*U1 elR7m<ZYFhdjO-ZcG4g{X$o}&Tqjjc*&gdTt^LtAG literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Kiev b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Kiev new file mode 100644 index 0000000000000000000000000000000000000000..9337c9ea27c0a61b1082f4be37cfb0f9484cf5e2 GIT binary patch literal 2088 zcmeIye@xVM9LMqRSD@%LeCwj~0)!+L?SunF(IBz&U<RkBoJ1;d)`?m~ipHQcTshYo zxwn()T)J5?G^flqv_G)*W3H^hb${fVBUh`H%{lkos=0EkKF_bC{^+m%=)b<-eZP+{ zU&d~`@p?wrZfPm8{&C!G-f(ernTzKcyUp#S?|A%dpD*_LNMUmLYORdC<JH7lK}n39 z*qS-}c=Fz9Usrk4M<d?fCx1BYT1L`08mzi+_&_r2{4po{)P5)D$ji?3p6yQV&bX7; zy2iPGeYG>AZlRN3QQ$n__c=4OJ<hC&x13q8=Y3o7gLn6wFR#buUic#N;9w%=?|U~g zulG!>aL<8A(T?*Ph@aNtrpr>&J}9M?Lo$E$K`F~QDho<FWx-gtlxOv7`IQZ_=vId= zem^J=jW%jUf3sE&E!KzkF4ZM(WNTGRzAoLfNFJ$9(_lPHmd(7Xq2QQQr+ub1`QJ#* zjUQ!s%15$1aZw)q{%xrpI4O0*A82@AkE}TLrmk#jlSt1iy6Umlbam@StzX!x(YhL4 z<6WT*{yExkGoX!`)zbLYRDJx{0$F?R7hQMBBkPY%k*2}x@<jK~(%hSnSo0;>u<M#W zx#T^0s%co`xrb$A<$$)NpVdt{s+)c~q?^aub<4#refmmNpE<EkTR+(*&%RozZT<D~ z+~!=}y0=WWt*Vgr7O!kCo-R8=zsd7cEa@o9)DGu6>CCvPoyiN*b>p(WaHd~gObqGH z!yoIefus6TSD$w8>sEV0${nd`sVR5fKGW~|`}9n>eNLS8U!0beeZ>5KaZfe(JS*L@ z<_4@umX#rv@W#Gp{9ayV`^JAe{%q&)hC6>-7mixB<_d+PR=B>_3L1l<dVW}DUYZ9E z+jcMb>#*(UznH`y=4d$gX&jjbG7n@T$V`x_Aaijwli_2T4Kf{MKCWg$$c&IFA#*|| zh0F?>7BVknV#v&psUdSiCWp)pnI1AfS2ICmhR76=IU<upW{FG_nI|$)WTwbek+~w1 zMP`dk7n!fCnJ_YAS2JZ~&d8*ZStHX%=8a4onK?3bWbVl1k=Y~DN9K<t0Lg%>Ndb}r zSCa%J3rHG}JRpfcGJ&K5$pw-OBpXONkbEEsK{DcMQi9~f)g%SU3X&EiFGymL%pj>j za)TrX$qtepBtJ-kkPIOyLUQD4l7wUlNfVMMBvDAFkW?YLLXw4K3rQD}FC<||#*maD zIde5hL$c;-(uU*>NgR?nBy~vckmTY2*)v~)ZF@{B=atY#f4H=;tT0ei>JJwO+^6}T FKLL|r@~!{? literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Kirov b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Kirov new file mode 100644 index 0000000000000000000000000000000000000000..a3b5320a0bd139c07b8642c4efd7b98f57c6e8dd GIT binary patch literal 1153 zcmd7QJ7`l;9LMn!oAj2%!9^R}q&{jI`t+JKCDpV>(>AoGP$W21h2o<i2>y`{3PKCk zPAVvZiXw`^#pj@tRf4#PZ6~)X9B}f1oW;eW@qDj#au7G~&Ap#+Ng(9+Esh=;PpChR z8vBHcBWo|-ueznWr=FBTBdg<A%WJ|5Zf(tcw)UIvQTU@OuU$;Jb#rIR^|Kds<lbo= zy*{BE&K}n5PVLd_kLLA;eQCY1(5xFXb$U}<NXH^U(-c}V@jzVSU&GS;=JQy~%TLn! z_^q^+=B548bLp6VD4Qp4ihJmSY}r3+62~u_WX}!Lx%;F^MW;+xVz24?e!!&bPe}S* zpXpv2m95X3%(lghWbWjo=V^oV&ctN<H6__`M|Mm{%+CG~k~{dr^u=CFe@>f$z<tR# zzA*VOugqXo$qX*sHAC-b%&rILOkwV}44*${iiPOdWTjH^Rjv4S`UAhuYNy)qbNl=0 zcO0cUuGs%kwYbW!)WC?({;TP%TDg2*e&VxF_)KBAs9N2my;An-RLW;x_CSu}KWt}z zeue#z4f#GhB3mMRdfH8qU6E~(eUXikosq4Py^+n4-I48){gDQc4v-d*9*`zHZ5K!z zNFPWeNGC`uNH0h;NH<73NIytJNJmIZNKc-&DWoe;+ZNIn(iqYi(i+km(j3wq(jL+u w(jd|y(jw9$(j?NQr)?AI)6+JJbc(c!^olf#bc>UA^Z%{gV8)i++nx;m1PZbYN&o-= literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Lisbon b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Lisbon new file mode 100644 index 0000000000000000000000000000000000000000..355817b52b1b05680bbb57e4dc8de358eff27a39 GIT binary patch literal 3469 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 Y{v0ZPotiXi*2uqcfM2Hof8Le;4LU9nuK)l5 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Ljubljana b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Ljubljana new file mode 100644 index 0000000000000000000000000000000000000000..27de456f16ab549627b284a39e2265cbdb4ad8e9 GIT binary patch literal 1920 zcmdVaYfQ~?9LMqhL0H4S7@-o9T#oJ~DdMPHDwhrt$t4vMLdq?-nOU<hYs@g$HH>%= z9>mObA-Sy?W{kPcS{sI0<M;k=Hk(JD*!)lDyjrdG<oo`(Gv?)lS${mO%ujgptT1oB zZ@bQX+-w&4y!OplxqZw_>khf(&W;GVyCFdC9W0aksqxz7<tgp@;DC0!vR%E;Ul5-Y zmEya1zjQBC@msxKdgK>M&*^idSF&6DV-uveGfDz{0;NxzE)wYB(!kFV+V@p}_N(u# z{jass0aahsdE}iAEPt#)n{H|Fvhx~}eNsa+A4ynYm4wGtOT@&T66w27qQZ(Ls;N|> zy~{QF=`0!iy+~s&xMawabd9aZ(zxmv9lCkA4%_3S@j3oFeA8eVk?5hWY;PGE@J16{ zO_JzwLzDcUNm9dW8QuJnjIOJZF)t6x*vjLQTzgSdwv|chiGw<>pg_i#ZPW=<w(7+E zxtca8U){+`I>{?lCp-J;<S!wb-YHSiA9m2GpZiM2*-tvH-czO@XfK&nA7n=9N69L$ zlbKodGHcCyojvTF%*m|PY`@(yH?C51TA$HeU)9{VyELz<Q0LW@==`T{U2t@o=3ieT z3%A5+K}DJ@%Jb93n<Hh(gjgxe@sg#X-DO$AH(B1^lA_>FTGaSLiranB;=5O+q~VdS zJY6BH>Z*11?#sHSa-Xg(IijW8O4ZS#S#$g4(ehuuEURO*xhkujSS@~i`t)$LwyfVj z`E7EF+j1rFPIH?-a5(tlaX8$6al=2%Gb6Tf6mrYRJtH@b+%<CB$bBO>j@&u_nOjHh z9l3er?vdL^?jLCY=>TZ~=>cg1=>lm3=>us5>BQEwg7ktkgLH$mgY<(mgmi?og!F_o zg>;3qh4h6qhID3YT0?rXHO(R2A?+dkAq^rOA}u04B26M)B5fjlB8?)QBCR65+L~sO zZf#AwNWVzKNXJOaNY6;qNY_Z)NZ&}~NaslFNbk0$d8B(=(>~HavH{2rAX|X!0kR3m zE+E^0>;tk9$W9<zf$Rmc8OUzfn(aXL1KAK{N02Q+_5|4!WLJ=FLG}gN7-VOVtwHt% z*&JkdY|Zu{`(tZ12-zWIi;z7+HVN4!WSj7R-zQJATLVKGE@w)3P-IYuGbJ<xgTp<4 E0<)*Xw*UYD literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/London b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/London new file mode 100644 index 0000000000000000000000000000000000000000..ac02a81440f47a67b9f01d3fbcdb085266d20894 GIT binary patch literal 3648 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 Nbd8QojP~#<@K40&SY`kK literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Luxembourg b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Luxembourg new file mode 100644 index 0000000000000000000000000000000000000000..c4ca733f5345df24e5286b70464a6c0498353372 GIT binary patch literal 2946 zcmeIze{{`t9LMo{o5dFMHf*xtTWbx?es3Xbm~mwD^TzU9X2{}N+S!EVv?H?Pymg$U z(XN>dF{=61hA_;DrI=7o4o6BI-IAjp$I<8c)sNH3KlM-l^!=Xi_whaV$Nt)VzFecH zXU94Ib_AGLxHxv2i|3%CvMseG9g8QHG@kRWzFK)<P5CPKo4Zv@i&kpsg*vxq;(G7e z1(!W#QGwodbEivr;zIBG@hMsnp6IQN*yPyI)#=^X^bOf~Ey2C%%1p;wXUg20j|_Ee zIa=whs*H1N^$c-ud%2C{?Ikn3@3>=Ld^dNoyLxDpXZyg>){YqQ?2OCv>}vVFXV>jZ zp55P`^1OF?sa134JFB+-qP1t&No#NE63@QZw_ER*gjoCYS6T<AEw&D37FcyD(Vj!y z$5@AZ?zfI)p7tC$=jW;K8)F^2GDwbZ4AzFSRQd4L1UWHln|zcTBp(m%ttXfFmQ#bm zv_<)34OrS<S{9|L%t_K#SrHoOYNxF;`bnGkpS5k+*BaFNGY$4RuEE#$YP(BY_5PC{ zZGUjNhSctn(9KoSVRfl=ELQ0>Z=qN@x$?l+$?{;jOTv1k$wQGz5*`{M4>xZo5x%J! zaU(%HUk=wUjX~P=P*Z)R`bUi{|4O^9IHyrXA87QPT8+utqOs%7N?dNW#3$EC!tmE5 zvBMfkip!UzTZPg+WQBG=KS_H0lBYfQq{?HTW@@jB37TBfQy*W{M^j2dwRd)y_9^Ni zef#@rYF3E!3%{aiskfxR?@=8P_PGqW_Js`e*)Ibd>g9<`>ts;XCP_cGPcxPk%izsx zb;!(_GPL+59X9F}9iB5qM?9LNuJi%=Wbj}e8QDcg-i*=Aw*4jZlR$myMrRql;|Cqn z=r3bEtz=yFH!{BPx=dKnAQLAv%B1;M_34zIGI`uF&FZvDrX*KscC+m|wS(%^FIVcc zTe&*DzCfQj@6s6?#%Rvr+4Ah-WSv<tLS{|tr0zwDGJ9Ar$;}Ry=VCj`oV1_h`Bo0e zi*BoV-iwkSa8vV7)Jeg$vpRQMg}l&Eqw`iB(D_wsbU{J67A`B)dz|L<X>zac-Oi@X z?snei=kMolzT?xRd5iz*bU1wL_>G2I&L-wpDh|KDJ_m@i1@Aiof4|>(#eCAdV!mbG z{p0@IUr5hzIa1R`aC13E@i59fn8WGhGIt*SJe*F~KZwX}a}W|FCblLhNK}xpAaOwg zV{0OVga(NX5*#EtNO+L=AOS)mgoFr*k*x_55+x)|NSu&BA(28tg~SR877{HaTu8i- zfFTh>LWac5)&vcS8WJ`nZb;ye$RVLaVuu6|i5?O@Bz{N$kq9CoL}F-bf`~*B2_q6m zB#=lXkx(MBM1qM#6A35(AH)+0C=yX5q)1GWpdwL4!ivNd2`my>TN7F&wn%W1=px}o z;)?_ri7*mkB*sXPktic!M&gVF8i_O#YFiU)B-lu_k#HmNMgopR90@rRb0p|U)RC|w zaYq7=L>>vft%*Gnd|MNJB>YJHkpVzP02u;g43I%UMgbWHWE_xzKt=)?3S=yh!LT)> zfeeSO84qMYkP$(K1Q`=#P>@kUh6NcHWMGhyL52ny8)R^7&FCP*V{66-86aeYkRd|G z2pJ?~l#pRU#t9iHWTcRxLdFUiEM&Bh;j%U3g$x)nV#tsoV}=YGGHS@MA>)P&95Qmq z&>>@o3?4Fi$ne>k@k0jC){G!Bgvb~ogNTeGGK|PL;{OAAXD0vkK>C|0?H0?ZMrOoE PB}T<WX2ix|biDts=f9={ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Madrid b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Madrid new file mode 100644 index 0000000000000000000000000000000000000000..16f6420ab7efc7ceac3b0e42fe37836185cfc463 GIT binary patch literal 2614 zcmeIzZA?{l9Ki8|NFqM{KoRSrXhdl7jF6awhF~W6cvBLIt0HP4U5T9d1Wu;r82i<% z#>&KG*hs+&a|^8{kTQWRWsS;WxiZV_Hf8q2=>I*vY2}+<^`>)n?&q9yxBKF5zwghv zbZvf|^^aqSdBer=s=2s#l$noL-f8vhuTHY6)!{j?y`Zel=SO$l<wEO7+aXW=p*X9d zdY=2}u2I$-&up^ZbjOsvRkYjPI6t85RNGZgb5@Sk@=%JWWu2p^HL2KjdO~*D>E24u z+1@W)?a#0GbTrR#byjz|KRg)eI#+hw{n3sQu8&<+?(-{ta$T6d+1))Zy{G$1w#Ro^ zN00A~=iGyTXz1~~Q0yMk6x=iPb%$qIO_FQ)o<7fr@-&s=MD@=L*8t}j9ho^(M#cZC zfuY~)=#igmkavd$U4K`{Tx!tU&sXam&Cjai#7PN0TrXo^-Y?@SR6@3Fm+=KfGGW<D zxiiBlq0`dju82el3l5jNhmMhOpHvO+ovahT4%10pqxGKFL3(fF&l*v4MI-lqs!`=< zHM;nO#^fE**qm;OD{7SZ<R+QC@C8X2yH671HcDb&sZ4R~)hQR3OVV!}bn3}ex&N~) zomQKx$xT!Bft@on<)vVqo*$|+%9G^5bRSL4bI8oF%bJ$jC+R+IIxF-`nRV?OneF|) z%<eoR4_`VcbL#6Pqy0V2tgMi^hY#qy!a|u}u|pRu*`o^!R_UVq3e=e~OCJfEtBWHh z>EfF)niZHXS)T;xqrDSl>DxCnyUS0ORr^a$<5hXA^t$Bk?G#sTmn`4<ovuhZE-Q1| zH7}$}RwdVKzV9(zJyvz~w=e3Nz9L<FrbHjV=+q}(%hrMq*2}ux$y!*uNS<61qVAmu zvVOrdDasF$r((xRaoR8Pw7(@Aq62k<=PTJb{HAU^*CHj?x^>ghTG`y$q+6;^>DKyv zx~-%}ODjutpx1!Eo!(vpZu7atImmag-+yuT_y1mDhQ%5#UIWn@Y+1qMy@vheK7enn zAp89-?lUr-){?YEd~lhkRGw1JlVy4FJ6`6nfA7x+=f4=_esgR~JZ2#SjSMw1*vN1r z18!@E92s<E*pY!ph8`JwWcZN)AQ3=9fW!a^f~|=H5(Xp=wk8lrB#=-bu|R@>L<0#2 z5)ULGNJNm3AThBuLE#@HDz+vpNL-M>Adx{rgTw|24iX(CJV<<y03i`VLWIN!2@(<| zTN5TEPDr4TNFkv@Vub_?i53zrBwk3skcc56Lt=&m4T%~OHd_-nBydRNkkBEqLxP7y z4+$R<KO}%i1d$LTF+_rhL=g$2t%)NNNLv$0B$P-jkzgXxM8b*06A361Q6!{DOp%}> zQANUv#1#pwt%)oWT3ZuaB)CX)k?<n%MFNaO7zr^FV<gB(l#wtaaYh1dYa)$=+SbGx z2{saKB-}{6k$@u+M?#Lo90@uSbtLRa+>yW|kw-#rYhsTCABjE^ekA_L0zj4kvIvl6 zfGh-LDIkjhSq{j8K$ZluC~VELKo*9rSsKXVK$ZuxK#(PZED~gy;QtH7{0X;OD1K(w XM8>jpA~NHn5~5-vGGk*fI^ORO@U!br literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Malta b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Malta new file mode 100644 index 0000000000000000000000000000000000000000..bf2452da40314be196f61e6a7cdd48eaf5c426f3 GIT binary patch literal 2620 zcmd_rZA_JQ7{~F$lLDz-_yDE{wa^en9z^gV(Uj1c2TM7bsVFL<7SSykL8%<eTs7vd zmf{$g_z=sc)D(4v)-q`{kr2bwaygw@+3eoTkSW^#dpqq#uX@v)?laEkaFmzV_vf9x zEO)r;A5UlV4L>|P%@3cu`pjF!sOwfmYvZ}f`lI&d1Fr1%-nwONsdAsI%6{M8x_Wo^ zwz(s%?Vdi_4SC6S<E5!`Y-fZvZA+7H^t?9b&(q@t;nL!1u}_Rk)NiM>NNZ%9buwm? zee$wTPlc38d(u9;{q&J@H{31OjZbRrn>TB%j`A}5*2QM~_G^1BSN$H_Z{bGEzjC$} zF!5z8@Qp${Xz06kr#?wm=g@&xa74Hjd}f3d($-T$4|nz5ck)l|vh{ag*Zrro+nVFP z`^!F6S+Lg^R#>UsCv5cfNS`A;hwO3nin^@fJ$}%LfMXhQ^)u~#;Uj(EM3wgW@*VAa z@Q}E7)ktLJ7U@^2(tqU|8IV^X56)dA4|%*2H8x!a#-_+1ceFg*rME-}rD^oF5jyzd zAdP7a*CF+tb!hE%jotB!4%=`><JKP4_!S2=A!oNHW}TMd1+|itS|=lBlu2^rW=R=d zBq<#wGOF(e9d&krjJ{E*V-BUsBj3-`vDNc6wQh`#TQ@<+SGe`j+$f!}cC<{K6r^c6 zedV!1moz=CLnZ}%t&^jEl*w0qk|_aS$dslAdHlk5nOgIqcp5*~jP<25ZP!+PB0pcA zEPY+4KmE4O$Xl$LBlFbjnXFGmOw*aMF*>s?L1*=vB(uKjuFqT>EVK9jp>tY8Wo}iN zWYzvA^GdGD{0&W#J-<~Jtol_Kjz1uavKlp~f4MA9t<l`zeYzx4b;-}0bZJL{E^8>( zXU}@|xew-O-dD@z`8QKFzdBQ1SlVB$b;+`P`dBH*jgS`;`^k#*c6lkxC57?5w9q~; zMcvx8sQHK#UpcL>d|WNBHr46M^255SX0xs?-k~MyOEkdG|K2Mg(7gQoc{i`S-ucb> zmwW%yKd94x{WAAdY3|A89^e<~a&;3|$ldol-~9c(C&TMXOV8xZ%U}4J2h9iXzqsDp z=CKZ)$U&~y(Ofce&B#R~SB+dYa^1*<BUg@GI&$sE#UodbTt0IBNCA)vASFO*fD{3# z0#XJ?QwO9FNF^LiDUez?nqnZ;K+1tmJ@`ODcuYlrk{~rfih@)HDGO2;q%cTj98GDE z+91V2s)LjVsSi>hq(VrEkQyOHLaKz6iHABNg+eOjXiA0D3Mm#+Eu>sXy^w+-6+=pf z)C?&aQZ=M(NZpXaA(cZ)=V)q&6c4E$Qa+@9NCA-wA|*s>h!hd2B2q@Ajz}SqN+P9n zG_^#E>1e8nloP2ZQc$F#NJ){JB1J{2ij)<pD^ggbvPfx>+9JhuG}T4Q>uBnW6d0*6 zQevdWNRg2$BV|VFj1(HFG*W7$)=04(O|_A7JDPeU1xG55lpLu!Qgo#1NZFCPBZWsQ zkCYy%JyLw6`bha5P5qGtKvn=*0%Q%4ML<>oSq5YskcB{20$B=VEs(`PRs&fMN3$Nt wf;gHLL6!tr6J$}4RY8^oSr`2OElj8xoneX0Pi#g~Tyk7OY(`=N#wUgT1<GOd9smFU literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Mariehamn b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Mariehamn new file mode 100644 index 0000000000000000000000000000000000000000..b4f8f9cbb57450549933f83ac90dd56a2ca75344 GIT binary patch literal 1900 zcmdVaYiP}J9LMqh%+NyL(Hv|u%xpNev#Z<YHfM9$FguvbY}n>D!>~5Db3~GszG{&W zvX;c`!B9r-BI~5Igq9-LB!!R`zxUr0<&h`KIi3IOv`%~UeSbXjSCl4Nf4n-GzwqHz zX+C@p@tH^6`ZZzq{JBLfS6>u`Mz#5R_4NB3fmeKvkBz?G&(CU~2gkJUjeQz+>9T~M zZjgw>N2OnlO5~R9(!Z=i1}t1E1G7C6mFAW~&QysGkCDM$drM4EhQ@qO*4P)(I;6Fi z4!zY`hc$gwXWbheUi(<%cHYzY4VTnad`1%r9!X+FlO&}#OY*G!k`i%5QWL8rwcRTt z!)kS8+hQ5@y;4VC&X6%r@-?l#P}7@7>)2frbljnE9bX!y6LyZ0iJ3u~Q5+_dqF<>y zqg^tC?rK)lQ^|V&Ql<o6lPUf?GWGchnbvShvRkfb&fXfCe)_o1C@+_pH9ItS?jD_0 zR-$<$%G8scrL!H=b&hk0&iUff{LoCvf7nCkeU6p+=RfI!)?it9EJO;L-pL~GM=7lJ zOHpB~EZ+K7myEk0OAA`GIP##Bq&H}3mvg!-LUq~e1G>DuLRZ|W)|G7@U3GGSmfc<_ zt9Pesd3~O&SstltccsX>+%%~ub;$aJezL*+O*V#DQW+nrl^>o-RrfDib^oSRzkj5g z8tY}Vzgf2&ysldtj_9`PI`!`LYCvEI``t0<U%oBNQDP2?XGhB#>I&#$S>gSyZohxe z&hc22&ByJ|<Kf}=RzSe7r{^zD_lJ4qT^xJ}Ibr0CkyGYBa?Z#}BWG=EP8&II<iwFP zM@}6%cjV-evqw%JIe#PpBm*P`BnKo3Bnu=BTayQp2$Bhs3X%(w43Z6!4w4U&5Rws+ z5|R^=6p|H^maWMPNzB${hNOn%h9rk%hopz(ha`w(h@^<*h$M+*iKL0-i6m-kGDT9g zHMt_mBH1G8BKaZ-BN-zpBRL~UBUvM9BY7i<+nUUg)NM`fNb*SbNcu?r$OIrWfJ^~0 z2goEKvw%zkG7rc^ATxnXg{_$jWHON1K&Atk4`f1+89}B5nG<AEkXb>d1(_FQVvw0Z zrpDIH4Kg{lW_FP2LFNaUAY_J+DMIE5|KmvtHXAiOk+pK>B*mq~x#E+YISDTNTXOJE D35>6g literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Minsk b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Minsk new file mode 100644 index 0000000000000000000000000000000000000000..453306c07566a94c0c391024fb16ee36245a0a40 GIT binary patch literal 1321 zcmdthPe_w-9LMqRbk<sGJ7n|8txPk`&9Y5x)wI=|qMJ}{b%+WNLn=DhpJU{Y5a|&8 z@03u47)c4ypF<{e=n%GS9Rg!@iU>T^bBU;k^?R=t9Xiyt&%^e9d_?^B`XzSm>+{JU zSMu{|M3?&&O23U6V}ZLPM(@;~{&ebH)baGX^UU<su;baeCP&&{&|6k}ExoAxRmf?} zY;k^B@UVQgG;L(Up~b25>52zeOxKOGrhE9fx#Z+wbLr8fS$SZ)xolU5SruDrRtM|M z<zB<AaoNq<kLCS!Z=Gu83!AEc^jUfC%qs6lMm1bWsa1oMYW0zE)tJ1j*6e;FzC)wp zZ@no^+fGQc`?R$9_DjpRgA%A1Qi0cTS@(6XT0hw=8#3K0IJ#A}PIy(@kY8=QRH{OK zWopx)M>a=3sc^DH+G}2_Nce+v6iukk>gUq=enz?qZ%fzoed&I4QKI9+5=-4uJ*SSz zKsKAT6co;}7Fml5=l-~C^L}0S`G0p67mFA(`fn@7W3h_3D#a#J-zfTdsY4t*u`JBL z2SOGj|JnS##r@k?RmFM|(xYFIh;BS8Vcl>f&Ij%Kp}z4n`uTQZvGCGM{DT7hOJ{f7 zo2sK|popNTpva);pa`KTp-ABeKnq0-MNO_+4n+?|5JeG15=9e56h#$97DX3D7)2RH z8bupL97P>P9z`ETAVncXB1I!bBt<1fCPgPhC_^bjDnlznY_3`@LvF5GFGDazF+(y% zGetB-HAOZ>H$^x@IYl}{J4HN0Jw<-5T0i3i<f=~r<0LRn1LH(cP6Zp#|KtDTWY~lH Ku(UP!?cV`C@iFcI literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Monaco b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Monaco new file mode 100644 index 0000000000000000000000000000000000000000..adbe45d1c1db7287345b1826a356732075a38c51 GIT binary patch literal 2944 zcmeIzYfu$+7{~EFDvEe}&;%0{lMprJ4yj3Mh-3nyo|IHX6H$|BC3Da;baG71aUL7S zGBi*TZ-`cS3%uX(Mpk2{<<#h;T^##2=GbM-_PdkQi(dJvH|@@z&+fiBug>}Yykn;2 z#ajP5S~zdGIQBXh_aXD0j}=8NhLxrknbHdp_UgJ7_L_rFoA;LdX_uAvH02XEn6>j; znst$F&H6cMrXpd1*)TrTt_({s8^cS@rmSxE=4SKE=9}^Mmg_lY>xE2Hbz-2|c5<Vs z-WY1Omk+adyy0WsUozc%V0X1YEL?2YWHzyP4v8|mqORGyW7F(CZR+hk_x9R*f7)Vy z^!Wr+`^9lnSHIir+q22+FUzqHytC9CeAk#mMfv9N)NFGkE5jV^?_(e99c_;HU1?5a zRoN#lH7`FEIM$rH;{E3IwrS?f^`UZhbD%b?OO}t{ikEXsem0*J2FRxw1GGhLAFJio zAk(U1lD2-cqqJF=qB1j4{d2>$t+#`=OCKZ;#r>}BLx0qOc3){=<FgugYrl55x?Las ztXw-DS)oC7`y{xkS~{&Rlg`UjLgp@zF8PJ>$hb+;HO(ub{Zi!7h(rks4wr5%J4m=s zvWDM|*Y4kjX^-;(+Vfa5eXQnJji~rudzD<$$c3jhYG$2A=Wf%O?28gxSR-*swGuyK zr6hD(BZ;v^l6bdRdIyzg@5>XV&mXh2@4jSt;>#@USDB+pwSD!;MFX{eX|N8+3)O)O z`^Zy+eKa{YNCt&n*OcVDGT7&&riOkksW-35kj95(NJG6mb9KE8t==MOXAWrk@@0}y zwN{4}6iDW>*LC>lr8**ivW|Q_U%hFm`fOl^j*94^qwYj&R{Oz{b)l_3ce}fc+4YN# zJ?|&u%Kas~=7x+fz9l&&4Kg9;yiA<;gFfGXw@k`Dqq!lgWO7oq=K1c_DV<cOeD}6a zy<4c$>SyZ<m%TcD(^$<vK0{tyoTLSnBju&3A!;v5kQu}KNnu`~yd2Y6W~TfmulQRs zE2_QDGFPOi^&KrbcT{HIyr^?_RLZLjwK{jzVVzgKMqis<p~cIK)zh?5;|DvN_}o8z zoB1~P`>#&RYI?)@e_D-VtR|M#T0FiyS*`Bh2Y2!K-+$xW2k_nsvaEmZ)6%_GrgM!> z8OaBi^OVd}vh!qF9*_G4f5W}U<9&dB+;ffs|FROKBS=eJot_{~LArvp1?daY7^E{u zYmnX`%|W_@v<K-A(jcTmu1<@P9wALax`ea|=@Zf@q*F+%kX|9pLb`>t3+WfqFr;Iy zPRo#<Ax%TNhO`ao8`3zWb4cru-XYCHx`(t6=^xTSq=T+b3y~hWI!#2nh_n&uBhpBu zlSnI(ULwupmq9l<XeZK7q@hShk(MGoMVg9q6=^HdSER8>XI-7vBE3bLi*y%hFVbJ6 z!AOUZ79%}Inv8TAX*1Giq|r#Hkyg7py+)dibQ@_m(r={UNXL<uBRxl&j&vPqJJNTg z@kr;9*1I~rN1E^IbRTIy(tl(FkR3p_0NDd%6Odg%wgK4(WFwHBK(+$e3uH4~o!vmT z!`0ajWJ8c0LAC_h6J%46T|u@5*%xGEkexxc2H6{Ab6lO>LAJ-$*&k$skR3v{2-zcK zlaO6Pwh7rMWTTLsLbeLoD`c~f-9om@)!8p(!;l?AwhY-bWYdscL$(dsH)P|GokO+` z**j$OkljPJ&(+yKWCLBD9YnSe*+XO#kzGW#5!pxle<L4!BmJED>=nb1Mx@6@CPYR@ Lq{l>KRGi;m_j$vq literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Moscow b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Moscow new file mode 100644 index 0000000000000000000000000000000000000000..ddb3f4e99a1030f33b56fad986c8d9c16e59eb32 GIT binary patch literal 1535 zcmd_pOGs2v0Eh8&eK(rb!qglm&2)U$sA*0)IyEzjsUbNPSW%Qng3+OZ6j}@+wy8i0 zTv(<w>Y|s6YLnFvfkYNAS_B#d(ZT{b1Q9Ad&UZz$TD9&D_x_Go1;Ov{Z)$BR5`SH5 z^c!xj-TLO770{2~!?v;O6<<2~a%X1yzByZObnc(+f7>=aAe@1L@*#I{^@&i>RWve~ zaC~IY6&@P4`5GPslaD0WhbPu1O}P_eCL0pxR)vy2#ZM$pdfe;AuS}$j_ABe{Zk2lN zys}+9t=6AwR%vZ}Rr<jywV`gS$|%oP8}pM@rq!adV&|1T(k|^^lVtYC#6V8_(?HIf zIhp(Xv&_3cCG&%?WWm)Za#QC$x%o`LbToI%!b78~=v0p?cJ-+(dpcA}YCx419Z;p; zkE*hic3Jk$tDN&qa@*r9wSBT&mJfNP>yb@XbY;rQULoBr(Q-$pRqgamOV6<%%A5I8 z`aJJdRpcF6o$*Xn&%97I;XzgN`j*=Dp-a`?y`<{KZ_4`1CzZc0^@tH379J565g8R7 z6CJf8Dth5#iCy-ITe<9u<=^=89B&aK!>RufJR^iCykNxW^I6W7Jw}`mWo|?Nw{jgK zVewqmU?dA+O%tiVzt43T>5K2n+)F>t@7C4(MLl<;zP&sez51>dd5#j{^ZE6yUz(S} z(^$BcUYI8#{QuC`Pkrrs7#c%5Ls~<6Gu6!@-68EE{h8_pkq%9Di%5^Ax=Ex<q)q-* z`a~K<IyKd;BE2HbBHbeGBK;x_BON0xBRwNcBV8kHBYh){Bb_6yo9f<?=8^7Ab^A#F z$Oe!dAX`B8fNTQU1+oofAIL_KogiC5_F}3xgY3psZwJ{AvLR$g$d-^jA)7*Wg=`Di s7qT&AXUNu&y&;=Jc4w-$hwRT(ZxGobvPEQ%$R_cB-=#%wxuDqc3lb5KyZ`_I literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Nicosia b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Nicosia new file mode 100644 index 0000000000000000000000000000000000000000..f7f10ab7665e94ca44fd8cd98a362cd4b304eff1 GIT binary patch literal 2002 zcmdVaZAeuI9LMqNOjy@ye{0UQ>qF(rhpu|nY}s_Jnc9QbPV-i-GEb#fYtAi8r(5m5 z$Yg}XzY-#9P-GGju7RsTPxL@E2zOwMF+w`6v5iOxDx!vL=X;=6dll@>&gI_E<)ZKY z-(P6e#&DkJUr&tl3vZr?^XB{bW1l8}H+J}I+dH(^ihWjRkGpWq7~flHPS|zFdZp86 zO6yW9Zo{ZKvC1|k1t;6D=3h4AQ!kmXP3kogqK}#h54()l@9s1w|JZ1}aiziZo$Is` zPwudj4u!4c?s_|A+d^wfQ@K5LO{O)iBEwEC8fU%fkF}@!MywgJ!**IstdaKEYo`A; zY-Id&-^{%FgE4bp(De6yV`TN5GP67P897_`nt{4jBe$mC&I|6b@{84;m9@nxNNTZX z=e5i1(TL3P_2`_TbyE0Oo6bF7B5&WS)}p>zEj~L}-|3pK^A0BJyWv!w-&rW{mBnaD zolh1_|3gblMx`v~do54BE#)J>%cAH@vS{$SEWUeGmh_*HiW?U-xVu{_Pae^w&COzT z@6cr{cj^00^;-2-lZGnFb$LRiuJC8*iYEcBjxUqypC{@EkJDw<=|{TyrdQS+j+2^! z`?5CjP-=Sy#jL$4>$cz1_4CfihMF5%mvTVri~BYF^0(TMq}uT3er+6W(T&$Tbkk5s zKRmu#o33q^kG?F{=DsTVxG_aP=_-)T%Zj8WoFH3rlVxk^Q)!L!NLx<4wmtY&+9y2G zcI&EijQpaXo$8a%2hZxZ1DADs|5y4&N3TY9NA#tr7kfpI`A=USPs&1WF*6V~#^Xtx z;u-t=lV2)=Ax~*(6(1q~Dk{qT2))2<|Lr{7H~-F!BX^G6I&$yG%_Db@+&*&uNCQX* zNDD|0NE1jGNE@zBA4nreCrB$uFGw>;H%L23KS)DJM@UOZPe@ZpS4dk(U#?DLNM}fE zNN-4UNOwqkNPkF!NQX#^NRLR9NS8>PNT04wqe!Q&POC_-NV7<{NV`bCNW)0SNXtmi zNYhByNZUx?NaIN7u1@Pn@2*bsNcTwlNdL$NAUl9;0kQ|kCLp_jYy+|n$VMPL;p%J! zvKOw-W+1zPYzML*$c7+0f@}%0C&;ECyMk;BvM<QSAUlI>4YD_`&gLMygKQ77Kgb3l zJA`ZzvPZ}!A-jZZ6S7apMj<<eY!$LsuFhs5yXER^7qVZ-h9NtKY#Fj=$fn`{b=SPk a%w^><c>Z91c0qO^C*L2;4Y=QCdH(?jq|NOB literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Oslo b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Oslo new file mode 100644 index 0000000000000000000000000000000000000000..15a34c3cedb7c9ca519c195f5ec0ce9d8d1885a5 GIT binary patch literal 2228 zcmdtiUrd#C9LMp4h!iXLF@<9RLLs4r{0IL8nH_<d97{PFsRSw_7EzvzL26Vw=Nh?h zja80ZR*qRS?1J(Ft@X!73&~8@tXx~HtTZB#=+9XF-cM^?)J->C^m}%m*Ry9k7iT-4 zcWA|i+8p2CPPBW&hx3^G@O<e*?$(|*;A=m*xw_|2u)6omVjX+YZ+*`P^uZH(I{rwi zJ`Bg{#F}WGJ(z6g_Lu3qr;9YWGeh4uC26Qm`k^91=S$CPc=muUq@C1=|EPY{kd0<e z(CE+!n;cxIDY?H`Y|2@SoBWyiBafMX_;s5)aL_LQXs=!I_Tv_R_=pk?bSm+gXEm+W zl(gkxCD(^_<*K#1sw||G!eUKNFHmYiny$WNs?wqYmNt@SGrml<nf-Bg&CzJPw(BQL z-}jBpYWu`8w!d$gn+{u6&C8Zuc}h9qF69<=D{tA8%1_**f}AE5jJ0S^e4EWVy;^gB zZM1nu0=n+g3M=fWvZC&JcKwb8HorZ=Zm3PM1>5K9#*!!t)WmCH>KQ8zjHx8*Ju6N5 zT&06wX;I{xTGZF0n+9Ic;?9>;*87G9ceQHCf#>Yzh6dfzy3Ll}_NXnZUuWgB>n&7P zYPb5A*z)w5wtO_pDq>4i@$qGL`^XHfc<q9%?2pl^y^~bgbxwD*46CZGPt{fZTD|pK zTQmQV)>igfP10_yE9$h`i(a+$iDv7+e#+{`!nUEO+3q|Yvb*-LwEA~9>h7II*3eO| zd+L(x-W~bcxU^8=TEFhgo~BL3KkNQUJ~d{>TI0|cYMMA|O~>C+^WZ6a;FS(-?(4QK zyWg^{oqO!T=6%+(tHs7ejEjgI{|{Hxg#Z5X`C_KH|FAD1IbyueH&MQe|GfY4=CAi< z!H_RdT+S`THzM3Y_YnFQi}}r+@Zj`%WI3L0J;;KP6(LJP)`TnySrxJ@WL?O@kd+}z zL)L~Y4p|+tJY;>y0+AIWOGMU)EYj1hl3&g;k#!;qMOKO|)zhsNSuC<zWVy(Ckp&|w zMwX1M8Cf*4YGm2Sx{-w=D@T@&tliTs9$7uId}RGd0gwtHB|vI`6alFMQU;_BNFk6) zAf-TR;pvKjRKwGi1E~j65TqhVNsyW#MM0{9lm)2^QW&H%NNJGTAjLtd<LSzS)W_2m z2&oWKBBVx0k&r4OWkTwN6bh*nQYxfYNU@M=dAf2T_40HDLn?-p45=AXG^A=s*^s&+ zg+nTbln$vKQaq%3NcoWZdAb536+}vi)DS5mQbnYUNF9+vB9%l+iPRD)CQ?nLoJc)A xT|tqGdb*M#HARYwR23;JQdgv~`2VbIj0^9qY!aLv%+1Kp$Vv}pXJKY;%<s!{R2~2T literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Paris b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Paris new file mode 100644 index 0000000000000000000000000000000000000000..7d366c6098c49ecd546e1cc1538919e1414a3aee GIT binary patch literal 2962 zcmeIze{{`t9LMoHHk+Awk7lwlSu-^Iy@f1v&654XjfL4{hAe$8IU^c}Bjh-59Y<+o znE5rM8m7(fUvpwqN1~jR6a6~+bmZvAk-pDwe^jTxoc`#azW02;kMI4Sd(Qpm-sj6R zdP-4(>mNsJ`w1sUoqcj2KF_|aD9Fh!PcJp)7ox2-4J)j*haNX?F8R$`SJBf{6l^l< z=LMJzF>TGp*%_uXdA`{+F2bscOg5XN%FUMCZq`=cxn}E)Bx~FCe6#&Rj;TI5(Cj$1 z+0<-~Fgq)<tz9qsn75WpHE&y8t#?WmTeUgf*6ty(W>4%jYi~k^RoAA`s=K?-+V}l7 z>)nqEO#R0vOhe;dv%hYOIj}C@I{5lhbLb6Y4wn|2Ba`#Y(cCO^tiO+Symy>A(RY<O znOkk0ywtLyu{i3=>FYz~%+?TX+TfP6uO`X4?9Z>9Tk?Z>zofl<kTpPC)%S4)Y!5Z9 zD<^2+D;=fH!Zei`DH>E5rENVOv|Z*Pxi9e-4UYI$+qe5vLz<t_kedgz!_}R7|A!UY z@#qQ-ZP+hi)iu&-%{uA4OeK8IeCbkLA`gt6AYC&&645VB9*j<r$gn8s7SKVWeB2s! zD@nV58L2(ax7VJ>ef6Q*pESDiYwfl2lEy52Ph)2^Xk6hAjnBI%2_?0Xm|8DM!&gai zr?rxjP%0^R%A|MbO6`4ly!82XruN<MmPbCx)qYj^np)piA6+z1`<I95fT9Q;xUi2r zHrPkqg`qMi^17zE@5o@EQ<@&}nWW#iCPSJZmLW}z^2F7RGPGu!WSl;znah_+R`q(# zo;FQ#mMzd>qn7IM;)y!q;bQe<r0bI*SvoShhmO1*r@6s{CHF#Ged<<s8NKI69dq7a z##RJLUhQ`>uI#4duWXWn{PQw??l<~$|GhFH@3a<%ua=3aHCp7iTPJl=o%GdfI{8kC zPHCK_&s_HC)GcGQ_{4O1c5$jss~RECO%7LUQL;=Q)=x@`Lge}Q&N3tIXL%vWB{O4# zb*A}3N&|0e>A7Pv>&8W$y{k%IY^v8etB>g1nzj1UtV%6gUZ!3?&6?la%iFJoZwud+ z-Yxz8{96V5S1*^VS-kz%<m&Bm1&Ws+@A%LD{oWPia)ovA3jWKrBcJ*6IrkZv9#@Wi zj!GNB#p7~2r}M^s>~eW|{c$=s&Np%K^77n6O77an)KleWk)$A5akSHd<ON9#k{Kj5 zNN$kiAlX6EgX9NE5RxGzMM#d2BstnyLehlf2}u-^DI`@$u8?FQ*+SBV<O@j{k})J@ zNY0R?Ioer6(uU*>NgR?nBy~vckmMoRL(+%j4@n@BK_rDp4v{1}+F3->h~yDTB$7!a zl}Iif?PMa^MAFGGf_!q2P$Z*BN|Br*Nky`Xq!r04l2|0ONNSPXI@-xavWuh_$uE*% zB*RFGksKpQMzV~g8Obw}Xe84}s*zkH$#%4}jiejNH<EB9<4DSpoFhp`vW}!3$vcvG zB=bn>k=!H6ceJyQq~FobKQaNx3?Ng0%mFe9$Sfe!fXo9j5y(s+Q-RC{G8xEhAk*P! z&j&Igj`oZoQ-aJ1GAYQcAk%`(3o<dt%pg;P%ndR*$m}4~<7m$hGC_{^3?Wm5%n>q4 z$Sfh#gv=8%QOHaoQ-#bGGFixMA=8D-7cyav_KYD@hRhi<X~?W0(}v6&GI7YvAybFU z9Wr^y>><;K%pWp=j`j>9Q|M^VAu@@`EF#m0%p)?9$V}q@Q^|w|{+p@vw>Py{yxU&b T=*+~J<e0eV%=kErP4xdAFa5mr literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Podgorica b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Podgorica new file mode 100644 index 0000000000000000000000000000000000000000..27de456f16ab549627b284a39e2265cbdb4ad8e9 GIT binary patch literal 1920 zcmdVaYfQ~?9LMqhL0H4S7@-o9T#oJ~DdMPHDwhrt$t4vMLdq?-nOU<hYs@g$HH>%= z9>mObA-Sy?W{kPcS{sI0<M;k=Hk(JD*!)lDyjrdG<oo`(Gv?)lS${mO%ujgptT1oB zZ@bQX+-w&4y!OplxqZw_>khf(&W;GVyCFdC9W0aksqxz7<tgp@;DC0!vR%E;Ul5-Y zmEya1zjQBC@msxKdgK>M&*^idSF&6DV-uveGfDz{0;NxzE)wYB(!kFV+V@p}_N(u# z{jass0aahsdE}iAEPt#)n{H|Fvhx~}eNsa+A4ynYm4wGtOT@&T66w27qQZ(Ls;N|> zy~{QF=`0!iy+~s&xMawabd9aZ(zxmv9lCkA4%_3S@j3oFeA8eVk?5hWY;PGE@J16{ zO_JzwLzDcUNm9dW8QuJnjIOJZF)t6x*vjLQTzgSdwv|chiGw<>pg_i#ZPW=<w(7+E zxtca8U){+`I>{?lCp-J;<S!wb-YHSiA9m2GpZiM2*-tvH-czO@XfK&nA7n=9N69L$ zlbKodGHcCyojvTF%*m|PY`@(yH?C51TA$HeU)9{VyELz<Q0LW@==`T{U2t@o=3ieT z3%A5+K}DJ@%Jb93n<Hh(gjgxe@sg#X-DO$AH(B1^lA_>FTGaSLiranB;=5O+q~VdS zJY6BH>Z*11?#sHSa-Xg(IijW8O4ZS#S#$g4(ehuuEURO*xhkujSS@~i`t)$LwyfVj z`E7EF+j1rFPIH?-a5(tlaX8$6al=2%Gb6Tf6mrYRJtH@b+%<CB$bBO>j@&u_nOjHh z9l3er?vdL^?jLCY=>TZ~=>cg1=>lm3=>us5>BQEwg7ktkgLH$mgY<(mgmi?og!F_o zg>;3qh4h6qhID3YT0?rXHO(R2A?+dkAq^rOA}u04B26M)B5fjlB8?)QBCR65+L~sO zZf#AwNWVzKNXJOaNY6;qNY_Z)NZ&}~NaslFNbk0$d8B(=(>~HavH{2rAX|X!0kR3m zE+E^0>;tk9$W9<zf$Rmc8OUzfn(aXL1KAK{N02Q+_5|4!WLJ=FLG}gN7-VOVtwHt% z*&JkdY|Zu{`(tZ12-zWIi;z7+HVN4!WSj7R-zQJATLVKGE@w)3P-IYuGbJ<xgTp<4 E0<)*Xw*UYD literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Prague b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Prague new file mode 100644 index 0000000000000000000000000000000000000000..ce8f433ece44f0b96b18d3b5780730e7f9cad9f5 GIT binary patch literal 2301 zcmc)Me@xVM9LMqRfyj?3d!GhJ^0SDLI{6KuL1rf~k~5XdNG1G%sCAKC#-KDTnRAWV zJ7YSBq!nY;jQRs>4XyQav=B|b>@3%oE7O{DGpE&9eV*T_(ei&kU+x~?@3FD5@p=y5 zl68&w*8fhF`GgnedGq4lx!JsRPjW5q4xYNWC)BS!y$AHA_f+?G?9!p=W*t5|PY%EC z(vep@a%4xL9DO!Jz6`|6v6Yc>d~=eXs5&MmUK~gZh6U1s)g|&()_|OJPm`~scS^{y zUP9+u#o3UlQ+x?J)jL;iDEM9D(tp<Yso$zA{II$%y{`#p-qIV7@6%}?zo3Z+4@uJg zeo5Z5S5i7vQa3&$Y5suRv}~2!T<w$e(sH@QT`U<%nR4r-1j&r>Xy)ZYo&H0HW(DK* zwofDV_JOPF?mee7x=v|!#}}Hj;h^R=ys3G0A;}L6NI}`46fW8+Maex<oZl+NqwP|X z*rg?>SIEpiT6ESSkKFl9t(NxHYuVr|y=&_no!y<JcQ>Z%oQ|1tPep`!8WLr0##t@* zj7mks=USQmom5`<QL4f}l&X;-x%bSgGOzy)sUH47z1urw{{ENszNRKw(78nyKJc6_ z@~_sKJN)XauGITo^L4R1OBY|s)!MiUsXaMGAG|zWmb~+;E)B-WvVBge8~8;YYQH4) zT_du*J}4_To!6DK-<4H$!`hI#TUM9#Yh%;_U6ZW3=BHh{b~K>thT8Pu(>{IVwWaF+ ztXUr2R;EpTHS*ZnR9(NdNSYUxN}$mtkLRVxhVtL!38y73IdR%@@q1~Fy`rs0KasWz zA${`gK6z?nP&e-WNH_KO=+kYz+P=MA!yIAZ6UJW=W6u*Kug7Isled|_W-BSpF~PE8 z#ftv#y=6HjkN>3F>$5!NHN5$(O7mcj!@-w*91h>LcVvDnKiWPzb|3erIVn{;uA=|Q zd0TeHGuuM;g=`Gj8L~BGZ^-75-67jU_J?c`*&(t;WRJ)uZOtx`ZQ7cBA{#|^ifk3x ztF75Aza6_pwu|f+*)XzWWXs5&ZOx{UT_f8@_Kj>D**UUxWber4k=-NPNA{020O<hI z0;C5>6KqWvkTxKFKpKH`0%--(3#1uHH;{H9{XiOmbOdP$(i5a9wx%mcTWn2Vkj5aL zL0W_K25An`9i%--e~<<t9YR`!^ayDZ(j}x#wx&-=qijv5kX9kRLYjqi3uzb9FQj2e z$B>pGJwuv?bPZ{nt?3)mI9t;>q;*K|kme!XL)wS*4{0FML8OI950NG!T}0Z5^bu*K zt?4AvN~D)aGm&m0?L_*CG!*G5(o&?SNK=unB5g(biZs^NbQWo?t?4b&T%@~5dy)Pk z4MsYQwAc}D+8Z(cnmG0x8Ff9be`0KsY+`JZZ2sGb73=Q+|9fwO>m2`GlDyy=SsveI bb01@hJtL2HyS)Y3McKJ-Z(c6u6vX@mfqZ3V literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Riga b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Riga new file mode 100644 index 0000000000000000000000000000000000000000..8db477d01736445cafce8af7a7085d226d81f546 GIT binary patch literal 2198 zcmeIydrXye9LMqBNhl)1uPr<fAS!avkUMGyi5-C%978w~sfZb%7Lm6cl)^J&W{t6L z#%iuiGDnvgwPv=4uFG7bL^}Vl*66a;ipH8dt(>zB>i2$>wbuHhtv~xcJJ0LkVQh@? zc?Z^SZ^|`)J2UMYKAd*@;W^c@w-?`gV(MsD&s5*R()PY{ol|d&|NQmPn+=;k-O^Y& zJYFv6U-Rn7F`s;PC|`n|DH7Btcf_Q<5}Y0TWwAG6tkV12%nxEGqJwc`zT#Vkp9#jF z?h7THcsi8$LT6}B_wG>AzJ}1;=5?WY8%sm;E0%_m3)4djGU7rh32`PhD$=Bd7dUAb zQ=Rnhz0ShX2xrmR%g(JQC!CDqW6t8<VJEZejFYuzz{zen>g3d&Gr9iLCa-8v@~fVe zg2W@TB)3(TOm@h!_+DLp#wWLr)oNjXy%r5F*E<fZ)D_PsXmL}ruI#!^?ko*gUqigC zN*UJ@-=vg=f1+i{-$>boA7u564`ubpklgj%%Thk@x>O9mul}BHS##ngy}PAFD!U)o zwf8)wRn3iBy|h^a6=k~4yGCm=7HZ9<Y^{wcmD<m5(t9ta%lcEl>W0xs+1NKr>Q4S7 zn>v1x`rZ-QTt6!J?Vr#sE8dm+>xQ)<>98~w4QNxuJGwPdb?cAM>9)yTx_zikANVSu z55BrVn?K$u4;?Jhmi}sacw3V0I8Y!v*A~jICa>(ynIn5jF3TgcjO@*d(Y>K>r8WAJ zwg%5i+l4Rm(YN~Lv5`UDclaaSKX63b+m35TPltN0vDb{S>%y<KS6IZA>-xy6*9}pB zy>5*DZ!cqJAG7~>+{27n@U|zyn1s0|%9usjMvRFTb2D!|vD5cu#h%3J?@m8^=Kc9o z)6W(DfT^;dit2zVDG3;Vb-D3beI@pVzj~E@X&>C<@fhQA&y}yQ-aVeczu3?3_SBp@ zzX{n9vL$3su69$%u8?gZ`$9H`><rl&vNvRNu6B3)l57vzAF@GLyF+A)$R3eRBD+Mk ziR=^ED6&&ztH@rF%_6%+wu|hS!-hHR*wt<s*)y_fWY@^Hk$oc@M|O^E9oajwc@Deh zuzh6zNCS`#xY`yVJwTd(bOC7t(g&mwNGFh1AiY4Efpi0D2htCuAxKADZA*}zxZ0*5 zT|wG{^aW`Q(ix;RNN<qlAl*UQgY*Y!5Yi!6+ajb#uC_@?myk9geL@<AbP8z|(krA{ zNVkx7A^k!chI9;R8PYRX+cczWNZXLUA&o;ihqMmq9nw6cdr13`{vi!SI*7Co>7lD_ zBGN@y+eW01NF$L>BCSMvi8K@c?<Ri*+suFHW~2@7;#>lo;m^w~$jr{l%kbx9yHEL% Fe*o7aBb5LE literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Rome b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Rome new file mode 100644 index 0000000000000000000000000000000000000000..ac4c16342b5bbfa4c58a26f57db33b95f5b3e533 GIT binary patch literal 2641 zcmciDdrVe!9LMp8n;;^6(G=q%7MYlcAfRBPDFP!OEa6Gb8+b!4q9ZA3sc4xi$K1Cx zokJ5ZxiqC#m}_dS(nbTxFf1x3%S?;r&Sp*t(SGm47_<7@bM~Cq;W+>Ny+5AmiwlRl z{&V@8FZ{Unn;-8z*O*5|$_=Zcv95Xh$y$5I5m&+6uivtERz@^e7QAEcT79Ts_so&j z9(PzlO;NI4cWI)W+8?U*yVK>HH<RRa@ofFJq^~r%8|*V<67;+525F4EZk-*x)jr#@ zMt|tOMOqUN+pSF}n%g28thP_8?VC5Nt@dqO>{}O4+qYl-$a0<h(Ds`9mgT*Dy5%$e z1<Uu<QrmCHCc9hlCd<FaGCLq+lpWAA)eelCY6aG&+CjmoR?vIlcF$j%?cfdV_C2TC zEm<07g&aC>^~$?x_0E|f_a^?WeWF{mZ||Qq)aR6jUj0=2U3g#bJ5#A)U%sK?$Bs+H z!77Q|zEk>_t3<6_D+7v3<o=oS<N>!wqDN=QgRvuIV8kGKD5#$d@=Mo2*OD~m;y@kT z*jFDu>90eoZ)oh^-*xEbA2n`WtqxmyOylPt(u7$}GQ6Z(64Q=KQtlQ>j@%(5hA)>9 z?PZb@zFAYw&5_i$QXO?XT^{*qnvUL=uW3g|>6rE7bZkY0K3W*9<JP6h_)I@dpC2w0 z242#P^mfVg`&zT2&r8;o-z3}TbIGo+k;g9Vk%?6Y#9jB9=4>pNNe6f7<Hg1DMENT^ zdFlquEn1*?Ba77I&eA7CC+U>f!8+x7yiV(rDbv31rB7Xpk?9}*r861>WoBiF%&PuV zW|v)+{LS@Jkl!eCR{f!K#~zV+v+8ty)HYd=R;7gjhjn43>cY!gby0hXF0NUjPoMMX zGw;sOqOX?7v#+IT@xDBHZc&t4>yu^4<k3=67%I;v^p~X>t+Fh{C8fjqXsP{+EDye} z%TJ$>6<3<{#Siw$OZ7)}<+d+$Rn-n%y<)GHZ7fr7uddt2*W6y-Jk8x{$6t3m{kq-# z+vVy}ZO)S`Vt|*g%M~oH?w!w$FJ0f=IUZMfMjj6j|HI2%XkI-3e|iJVKl0-`V1B%Z z+&0&kn9FXoj;*zj)9h$YG;*qulZ~8i<b)%q969O8X-7^xa_W(jkDPv_07wOp5+F4| zihxuBDFadmq!5m#5=beKS~!|wAk}a*<v{9z6a<}$@IpzrOih5IAXP!ig46{m3{n}S zG)Qe6O>vOwIGXYx^>H)>LMnum2&oZLB&146nUFdmg+eNYlnSYpqbU|rEu>sXy^w+- z6+=pf)C?&aQZ=M(NZpXaA(cZ)htv)!o};NAQa+@9NCA-wA|*s>h!hd2B2q@Ajz}Sq zN+P91YKaun(Nq&Dr=zJSQc$F#NJ){JB1J{2ij)<pD^ggbvPfx>+9Jh8s*9A@(bN|y zu%oFkQevdWNRg2$BV|VFj1(HFG*W7$)=06DY9r-#H1$Rb?r18GlpLu!Qgo#1NZFCP zBZWsQkCYy%JyLw6`bhba`XdYAXjTAO0%Q%4ML<>oSq5YskcB{20$B=VEs(`PRs&fM zWId1taWpG}EQzC86J$}4RY8^oSr=qskd;A}#>>aM>-P0Cx3>>Zb9dVD*B#Gp{&)ZG zoEkGYW@^l^m^}y<SI^F8$Cs|}3{LL9MyG3a%v+#YqM-?FQfy9QTyk7|Y)(Qv4oeLD E2jBk!N&o-= literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Samara b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Samara new file mode 100644 index 0000000000000000000000000000000000000000..97d5dd9e6ed7fc924c9bcb514f991cc8b52061b3 GIT binary patch literal 1215 zcmdVYPe_wt9Ki8sx_@jDUTVuf{WDvey4KvrtZ6gTVQnBWIz+((WzZjJh=&fr1T6?6 zLLw-Nkfc+H2RoUxL(s)`kZwcxL3D|T5p^hu^?cvir6B0o^X}pE?B(T!?f1=}x^O<K z{#agfhs_!=n{(5w>YaQ(=N;V=xL?}pFGqatH)-E@+k*dtDs8L8Bh4$<OD!*Er1ja9 zv^|`V?YG8c$F-BP^KwRZoleT`Y*5-$&9bM<D;=$#>R#`9HQ)#o0$=@weeZpfLG@Y% z-+t7gS8KX+v8=o1Uh3|<3pzYKtM^aL=*YP#ec;TzM8|JRPv0Ghowy|NwsA>BbCURx zmt@ODom@*u?|N1rT=vVMN?50!#&zFPlkUIa(}y2?*6FctdSH6992u(U!LwC4+Oe#M z23KX+@mOct7bWv)Nk$s)$w>K;9D8?Fj?Wh*yYi%vyM3ivtkr6^hQ|73cWhivm(%5T zHT?SeH=QoKU8(RF^Jl71M459kt=vitkJ>i<ezuwW^=Cp6oAo4jcs`rUtIkM|*)g-@ zO4-b(zBq2I{67rV{H_|qMFz|(7&0<wWZ0Hw;K<OC!6U;*0ze`_LO^0bf<U4`!a(9c z0zo1{LP26dg0VEwAmJeKSek&4h>(zwn2?~5sF1LbxD1NGkjRkGkl2vmkmxK;cu0Jf zCO{-YBt#@eBuFGmBupeuBv2$$Bvd3;Bv>R`BwQq3OA{~>v84$ai5UqRi5dwTi)Qx! OP28T8iNC))=J^Tns}05g literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/San_Marino b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/San_Marino new file mode 100644 index 0000000000000000000000000000000000000000..ac4c16342b5bbfa4c58a26f57db33b95f5b3e533 GIT binary patch literal 2641 zcmciDdrVe!9LMp8n;;^6(G=q%7MYlcAfRBPDFP!OEa6Gb8+b!4q9ZA3sc4xi$K1Cx zokJ5ZxiqC#m}_dS(nbTxFf1x3%S?;r&Sp*t(SGm47_<7@bM~Cq;W+>Ny+5AmiwlRl z{&V@8FZ{Unn;-8z*O*5|$_=Zcv95Xh$y$5I5m&+6uivtERz@^e7QAEcT79Ts_so&j z9(PzlO;NI4cWI)W+8?U*yVK>HH<RRa@ofFJq^~r%8|*V<67;+525F4EZk-*x)jr#@ zMt|tOMOqUN+pSF}n%g28thP_8?VC5Nt@dqO>{}O4+qYl-$a0<h(Ds`9mgT*Dy5%$e z1<Uu<QrmCHCc9hlCd<FaGCLq+lpWAA)eelCY6aG&+CjmoR?vIlcF$j%?cfdV_C2TC zEm<07g&aC>^~$?x_0E|f_a^?WeWF{mZ||Qq)aR6jUj0=2U3g#bJ5#A)U%sK?$Bs+H z!77Q|zEk>_t3<6_D+7v3<o=oS<N>!wqDN=QgRvuIV8kGKD5#$d@=Mo2*OD~m;y@kT z*jFDu>90eoZ)oh^-*xEbA2n`WtqxmyOylPt(u7$}GQ6Z(64Q=KQtlQ>j@%(5hA)>9 z?PZb@zFAYw&5_i$QXO?XT^{*qnvUL=uW3g|>6rE7bZkY0K3W*9<JP6h_)I@dpC2w0 z242#P^mfVg`&zT2&r8;o-z3}TbIGo+k;g9Vk%?6Y#9jB9=4>pNNe6f7<Hg1DMENT^ zdFlquEn1*?Ba77I&eA7CC+U>f!8+x7yiV(rDbv31rB7Xpk?9}*r861>WoBiF%&PuV zW|v)+{LS@Jkl!eCR{f!K#~zV+v+8ty)HYd=R;7gjhjn43>cY!gby0hXF0NUjPoMMX zGw;sOqOX?7v#+IT@xDBHZc&t4>yu^4<k3=67%I;v^p~X>t+Fh{C8fjqXsP{+EDye} z%TJ$>6<3<{#Siw$OZ7)}<+d+$Rn-n%y<)GHZ7fr7uddt2*W6y-Jk8x{$6t3m{kq-# z+vVy}ZO)S`Vt|*g%M~oH?w!w$FJ0f=IUZMfMjj6j|HI2%XkI-3e|iJVKl0-`V1B%Z z+&0&kn9FXoj;*zj)9h$YG;*qulZ~8i<b)%q969O8X-7^xa_W(jkDPv_07wOp5+F4| zihxuBDFadmq!5m#5=beKS~!|wAk}a*<v{9z6a<}$@IpzrOih5IAXP!ig46{m3{n}S zG)Qe6O>vOwIGXYx^>H)>LMnum2&oZLB&146nUFdmg+eNYlnSYpqbU|rEu>sXy^w+- z6+=pf)C?&aQZ=M(NZpXaA(cZ)htv)!o};NAQa+@9NCA-wA|*s>h!hd2B2q@Ajz}Sq zN+P91YKaun(Nq&Dr=zJSQc$F#NJ){JB1J{2ij)<pD^ggbvPfx>+9Jh8s*9A@(bN|y zu%oFkQevdWNRg2$BV|VFj1(HFG*W7$)=06DY9r-#H1$Rb?r18GlpLu!Qgo#1NZFCP zBZWsQkCYy%JyLw6`bhba`XdYAXjTAO0%Q%4ML<>oSq5YskcB{20$B=VEs(`PRs&fM zWId1taWpG}EQzC86J$}4RY8^oSr=qskd;A}#>>aM>-P0Cx3>>Zb9dVD*B#Gp{&)ZG zoEkGYW@^l^m^}y<SI^F8$Cs|}3{LL9MyG3a%v+#YqM-?FQfy9QTyk7|Y)(Qv4oeLD E2jBk!N&o-= literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Sarajevo b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Sarajevo new file mode 100644 index 0000000000000000000000000000000000000000..27de456f16ab549627b284a39e2265cbdb4ad8e9 GIT binary patch literal 1920 zcmdVaYfQ~?9LMqhL0H4S7@-o9T#oJ~DdMPHDwhrt$t4vMLdq?-nOU<hYs@g$HH>%= z9>mObA-Sy?W{kPcS{sI0<M;k=Hk(JD*!)lDyjrdG<oo`(Gv?)lS${mO%ujgptT1oB zZ@bQX+-w&4y!OplxqZw_>khf(&W;GVyCFdC9W0aksqxz7<tgp@;DC0!vR%E;Ul5-Y zmEya1zjQBC@msxKdgK>M&*^idSF&6DV-uveGfDz{0;NxzE)wYB(!kFV+V@p}_N(u# z{jass0aahsdE}iAEPt#)n{H|Fvhx~}eNsa+A4ynYm4wGtOT@&T66w27qQZ(Ls;N|> zy~{QF=`0!iy+~s&xMawabd9aZ(zxmv9lCkA4%_3S@j3oFeA8eVk?5hWY;PGE@J16{ zO_JzwLzDcUNm9dW8QuJnjIOJZF)t6x*vjLQTzgSdwv|chiGw<>pg_i#ZPW=<w(7+E zxtca8U){+`I>{?lCp-J;<S!wb-YHSiA9m2GpZiM2*-tvH-czO@XfK&nA7n=9N69L$ zlbKodGHcCyojvTF%*m|PY`@(yH?C51TA$HeU)9{VyELz<Q0LW@==`T{U2t@o=3ieT z3%A5+K}DJ@%Jb93n<Hh(gjgxe@sg#X-DO$AH(B1^lA_>FTGaSLiranB;=5O+q~VdS zJY6BH>Z*11?#sHSa-Xg(IijW8O4ZS#S#$g4(ehuuEURO*xhkujSS@~i`t)$LwyfVj z`E7EF+j1rFPIH?-a5(tlaX8$6al=2%Gb6Tf6mrYRJtH@b+%<CB$bBO>j@&u_nOjHh z9l3er?vdL^?jLCY=>TZ~=>cg1=>lm3=>us5>BQEwg7ktkgLH$mgY<(mgmi?og!F_o zg>;3qh4h6qhID3YT0?rXHO(R2A?+dkAq^rOA}u04B26M)B5fjlB8?)QBCR65+L~sO zZf#AwNWVzKNXJOaNY6;qNY_Z)NZ&}~NaslFNbk0$d8B(=(>~HavH{2rAX|X!0kR3m zE+E^0>;tk9$W9<zf$Rmc8OUzfn(aXL1KAK{N02Q+_5|4!WLJ=FLG}gN7-VOVtwHt% z*&JkdY|Zu{`(tZ12-zWIi;z7+HVN4!WSj7R-zQJATLVKGE@w)3P-IYuGbJ<xgTp<4 E0<)*Xw*UYD literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Saratov b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Saratov new file mode 100644 index 0000000000000000000000000000000000000000..8fd5f6d4b881457d13fdcdd35abb6fc5429d7084 GIT binary patch literal 1183 zcmd7QO-R#W9Ki8sxiy;|x|B0Fd$GB6T5E1HYuaqSV9k&i5mq3*2tm+~@K6vaWS%N0 zf`}rDMwea>b;@K!mq<Nzv)~V%dLe$7E=jHD`xj3gqFc{@&;Rr1*%)lUZ(-=fNW%QF zR@f6ZtIKYlSKT%3<Ijs#gR7%AN^631@#@OiZ1oS%)8J=Qs+mv4*Unrh)lOY?LJ!Y7 z;aj6l-Nob1x^w%T^(XtB4TsXs#(bkwpV_RNnrk!?3TQ*sf<}E&iGB}C<GZiJO|QR5 z?Ad#1F3w8JwQ1Qh@kF+c-jVpRE3)nIlqODJ*Vc~Pn%s9*Q{i!KOB~d;pGP!Zdq&b9 zy0v{_NVdOh&>iy`$=uIL$BR1YoQ%lMn?|xDe(9PB>8_qnk~{iKyCZL<C+BFd?~(M? zztX;MZ?wOnsQq&fboa+e-Sha8=4bB7z~xg~$cKjy<o3!~xm@;CEL*(1KKEMg=khM{ zx4YNx^%@g%|L>-_vCqAOo=RiVS+jEKzI5WTCySrq-TXko#Nw@Xr|eD|<FPLm5AG`b z!yxVNC^JlCpnL&CMFxuu*VPUf88R|xWZ1~Sk)b1lM~06CfJA_VfW&|Vfkc6Xfy99X z;%Xy7LP26df<dA|!a?Fe0zx7}LPBCff<mG~!b0M5wSgg#x!TZ>*pT3m=#cP`_>cgR z2$2wx7?B{6D3LIcIFUe+NL_8HNUW|lSR`5`TqIs3U?gHBWE``z|8HXsWNhS}Ey=)d D1dR{C literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Simferopol b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Simferopol new file mode 100644 index 0000000000000000000000000000000000000000..432e8315bc9dfa74080467f9e08073d9fdcc833a GIT binary patch literal 1453 zcmd_pOGs2v0Eh82I#c6hdKQ&V&ZKGfFf~)t(X_6Oqu7i!In#saF@YI@xTuI0K~mNt zG)^ULD$)`oktnD(7Cn$CGMz;`i-aH{BJMH@sq<aYO^ayVz1;a-k0>JFKf3#HOR@Ol zO4TPkTtWTtp53lL2HbsF5BuD)H}<ah$YfByy_2R!Z~EofrBXR|!#A;T#qIc_^!G-Z zb3B~(BlTJOmz21B+;1!%xg5`U++%tMFPh$Kr_CjuN6pNW&1P2Xc5~^TIx{;|Zst_2 zG?(SO&0LSmT;5e^u6p-1mNz^WUj1M+mfv?jT+n?lR`B9wys+b}vF2DuxTyJ%v374y zy!c4JD5)NjrA=4lI`4H^R(wL1O`VdyjBe%oa6nf4JgzFA_~rWXU8<^ozp5UpR2$CK zsEt=W%4o?^H60alQ=LQkn=@o>?xYI%r(~VuwW`ngDC@s{mJNx|Wy9zzx%tyA8N53n zLnBXB<AqMSWw2LmZEKU^&NFJ;&hx6N^`MHB?`w~SyfIrs;vBof?ns<FeLIt8?*tb& z=Sj|a$$z`&JB7&nuK)8Qb3)jK@MH;nl2;^>g-DS?a$;LB^XW5e?wRk-yxY8-@Hzdn zK7*g-H-s9aBBGx_ASxOoLE+c>0};Nc)rb0p%Vx74jeeQEIF0^8Jiqj{<I%7ai3kY^ zi3te`i3$k|iOW(4#vedrNN7lGmO3~jIwU+KJ|sXSLL@{aMkGiiN+e7qP9#tyQY2I) zRwP&?S|nT~UL;^k9WfFz5;GDs5;YPw7jYwjBatJaTk6=6;4O9ZNcc$n$N-QLAVWaL zfD8f|1u_g|9LPYBksw1s#)1sSQjZ21j-?(CG9Y9`$dHgRA%j9jg$xTB7cwwpWcc3< L&862_P~!RxK#57i literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Skopje b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Skopje new file mode 100644 index 0000000000000000000000000000000000000000..27de456f16ab549627b284a39e2265cbdb4ad8e9 GIT binary patch literal 1920 zcmdVaYfQ~?9LMqhL0H4S7@-o9T#oJ~DdMPHDwhrt$t4vMLdq?-nOU<hYs@g$HH>%= z9>mObA-Sy?W{kPcS{sI0<M;k=Hk(JD*!)lDyjrdG<oo`(Gv?)lS${mO%ujgptT1oB zZ@bQX+-w&4y!OplxqZw_>khf(&W;GVyCFdC9W0aksqxz7<tgp@;DC0!vR%E;Ul5-Y zmEya1zjQBC@msxKdgK>M&*^idSF&6DV-uveGfDz{0;NxzE)wYB(!kFV+V@p}_N(u# z{jass0aahsdE}iAEPt#)n{H|Fvhx~}eNsa+A4ynYm4wGtOT@&T66w27qQZ(Ls;N|> zy~{QF=`0!iy+~s&xMawabd9aZ(zxmv9lCkA4%_3S@j3oFeA8eVk?5hWY;PGE@J16{ zO_JzwLzDcUNm9dW8QuJnjIOJZF)t6x*vjLQTzgSdwv|chiGw<>pg_i#ZPW=<w(7+E zxtca8U){+`I>{?lCp-J;<S!wb-YHSiA9m2GpZiM2*-tvH-czO@XfK&nA7n=9N69L$ zlbKodGHcCyojvTF%*m|PY`@(yH?C51TA$HeU)9{VyELz<Q0LW@==`T{U2t@o=3ieT z3%A5+K}DJ@%Jb93n<Hh(gjgxe@sg#X-DO$AH(B1^lA_>FTGaSLiranB;=5O+q~VdS zJY6BH>Z*11?#sHSa-Xg(IijW8O4ZS#S#$g4(ehuuEURO*xhkujSS@~i`t)$LwyfVj z`E7EF+j1rFPIH?-a5(tlaX8$6al=2%Gb6Tf6mrYRJtH@b+%<CB$bBO>j@&u_nOjHh z9l3er?vdL^?jLCY=>TZ~=>cg1=>lm3=>us5>BQEwg7ktkgLH$mgY<(mgmi?og!F_o zg>;3qh4h6qhID3YT0?rXHO(R2A?+dkAq^rOA}u04B26M)B5fjlB8?)QBCR65+L~sO zZf#AwNWVzKNXJOaNY6;qNY_Z)NZ&}~NaslFNbk0$d8B(=(>~HavH{2rAX|X!0kR3m zE+E^0>;tk9$W9<zf$Rmc8OUzfn(aXL1KAK{N02Q+_5|4!WLJ=FLG}gN7-VOVtwHt% z*&JkdY|Zu{`(tZ12-zWIi;z7+HVN4!WSj7R-zQJATLVKGE@w)3P-IYuGbJ<xgTp<4 E0<)*Xw*UYD literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Sofia b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Sofia new file mode 100644 index 0000000000000000000000000000000000000000..0e4d879332d21c93c229fc25587205020eeb3127 GIT binary patch literal 2077 zcmb`He@xV69Dv^wP`nuXpdl(C7?5ZuzwuWP837}~PC1BF;!H#=B0ZHsirmyW*O>c6 ztmev1%du*XXfykRT0eBnHaf1AYpq-?TDGRvX3n+7>V3Yz+Nl2X^YVV5_ulV~zwUW_ zn|3zmnSae}d&6eB?B+Z#XdlB@*U9H^CTQrjQW@zjkno`l`67^>8n^9N@0{9_(Ye)k zh3_t0JR0x09-cS%qg@FxBjJRbgTeV@r-KW=><uowa5$Lw{@W($>?xD{>I-I3&mog? zV2?>{Z8D3u)S7#$%1v6)N|Wx%G#N<?%)K#gvm~l8xa5}GpZVi;@6xZX`IlWB@!oeX z<oBF;$Gg05(4TeWMQ`@rUVl#0K5uTrz-V4ze>lH*ND4N-B!$T*Wkp_xtQhZ>Rf&DN z>dIDG{b#$b`Jhzp|F&L>`Wv-)XpKH_bgh=WlB5qdr|H@wtL35cC@pPDl!r5}YFX*H zlt+E06=~l~#f_h&GU8*Y3|*2(#$K0o18+&y@P}G`yhqlbJ*|(nwTZXqux@zldEMB$ zU29ghs;{a-YZKOMooA`m-Okba_;RWLdX7GRD^oU||6Mm<cFUGianf+^nmo~cQyTk1 z;%~exTf2VICrjRwZ4JZPlyXA07Y}H2^t-wvS#`(HFKf$qKzCm1)Tgfa^yxP?YwM@G z<(Xr}+SXqq&$guKuA_yrdqa@~niFJC?jqS+_J{0?Gt!<NukFA6ARV!{wIh5{I&XZV z&kgp={?L#fIPr;g4V=`2ooBTBc(=M{MA+quoLEsar>)6*=k2WMJH3pF|IYsAOj4?e zG$vL|G-p?gG0SpXaZ~pb=YMXhs(q%c%x6lSUBd_aFvjJwfA%pkE|>4WfBJ6wp3NMz zoAbiI?9`nPrNh95vH1`cAUZ&lfM@|x1EPoh9|lDrnm|;6=mJp&q76hHhgKhmLJ*B0 zDnWE&P>Mk-2DKRUVo;1hGX~WdbYoDCK|2QZ81!>!6@+LAQ4yjeL`jI25H%rsLKKB) z3Q-lJD@0j{wh(n8`Z}}<Lo{}1RfgycQ5vE(L~V%P5XB*yLsW<84pAPWJw$zo{*VMf zGT_jr0FncTHVKd{K+*uo10)fUOh8fr$ps`CkZeHG0m%m>A&`tXv?+n)#Gy?JBrA}# zK=J}f3?ws<)If3rNe(1Ckn}+E14$4hLy#0fa^%n^36dp9njm?CBnpx#NU9*Yf+P!) zEl9c``GO=2k}*iiAUShrlLpC}Lz^~8-XMvCWDb%#NbVrXgOk~djEIbw5jC-9&YHF+ z@13{Nv+wkp>Rw_C-Lv(x-HR1tyJzbsPW|Gi?rrz%dE&`8sbA&)6mVJs?MJr_<?=iN V>8Z}oD$L5s&i7R3<~XMU_umlP+nN9X literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Stockholm b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Stockholm new file mode 100644 index 0000000000000000000000000000000000000000..f3e0c7f0f25f0a7290e56281c91190e3611498a7 GIT binary patch literal 1909 zcmciCYfQ~?9LMqhQ3q?ZZ%F8dB$uPBax1r^8ai$r<dR&HTS7<?G0n`HeQk|d3}elV zcn}`sGS@LQo1K~4Y|P!vhPkcrd;c3A@Yrep|EryP_<eu8(-##aT7P|<<{KV9Ys|y% zZ8w@%O+?k~8sGi*?LDKUL((@5j(VdV+dtG0zgrse;hc7QdR#l-*{@wL?a<IOXC>@t zorLe%ClOUDk>#7DYhkf;n>kOqXL%(mHC=kRQY1PoMtZjCBr#66#(e6py`DvDZ(m34 zbETE`t^cB~L$9=7^?i-4yrFTc&S-r8F-^$5CyB-Nl9bjU{U_~|<nX<cl2|G!O%*aQ zv|0x~nj?e0m+0WLZW;0*M^kI_G_7H<4&5?Bht-7X@Pa5EQ8`FPW;oTIA1b4wUue3! zNiv+*H8bk5WWIYYqx~+(=*DX@=IKEhTX#gVZk|`q_9_{7^ni{pDv}9Rn|0#UZ91uN zzGe?7RBu+MP7WETQ(V1u%IA2^3C@t5yX|z^r(QDs)JL7+3y_)ngCw{9t<0+UAbHh| zGCR*FbJoAsxx-G&yxg0bAGurRr`2ge>yx@5Ty??AUAnNTSQlL@)5VXxy5#T-Exfuy zmTpbcqS|a(wlGqcZ%LLF6H}$QAVgLsM98Z2ud+JGl9IS!EqVV$N&`P@>Fvu>_U@jp zJy9#`8XL5H_eEV_w^uim9ny;J73yf=@bmxwKb9qL%~e@}V)<KESXW2uUvIw2@^~$G zI#0Hj|8h9&m-pW{+tU1zhfk?__&w-{`FMT%s<C|X%DKo5+nPJ(pSfk^o{^hI?i#sm zTXWyYjU#uC+&Xga$ju{nkK8_T|40K!2S^J@4@eV87f2gOAGW3uq!XkSq!*+aq#L9i zq#vXqq$8vyq$i{)q${K?q%T|37}A-oX$|QOX%6WQX%FcSX%OiUX%XoWX%guYX%p!a zX%y+y*0hTBYHONBx<%SW`b8Q>I!0PXdPbT?x<=YY`bHW@I=3~gBfZ<2=8^7^_L2UP z4M27P*#cw_kWD~#0oev*ACQeeb^_T7WG`&ZW+1zPYzML*$c7+0f@}%0C&;ECyMk;B zvM<QSAUlI>4YD`3W^<6;u{GO+><_X*$POV}gzOQrN!Ywgel7f+|NrOrFhwv-fnqfe sQyY7p%$skRr)+zk{!CQ!Mwxej8LoZ_ESJlZ6q_6y@A4$XV_Z_ePe)m?eE<Le literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Tallinn b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Tallinn new file mode 100644 index 0000000000000000000000000000000000000000..b5acca3cf51e7f7b3176965748688ff41720246f GIT binary patch literal 2148 zcmeIye@xVM9LMp`foInx=Z7{ri8~=lK|SF3rPd(P6PR&lC@1-g=m(+}p#nKbjqi#% z*O<L4Hs&gS6r&$A<{xTn*7`B$C@;EySZmaBwX(71zFRqG8>`RrTlbgikGB5o^WFFR z`0kDk{^0eDZ`sverfxcO%_rQP{pRL<fn^@YHWww1y)SZnU|3G7rF%xYcSpxhpS}F~ z#o@-pl?MIA+kTmNJ)*ySsX`}vE?v$lcr$s&yl-m!o~cIv?{hz%H|<MiPep3(OuU@T z`QU^dIQ60(eDzs-{$RJAd!WtE>)2@DwXM!x5M6HPR~6cKhqCR3fo!#Cj#m}9E3JZS zi>$&Q{np}1kG15&4QuI{X)81`Wfcu2tm1(Wt&*NGE8KS6Ds8!>%DP5XdG))hV#8ro z8GJ!4E9=$EX8QGtoFS<iZI$Zt_sV^TR>{g&0#ehSFRKRb(W~p+5^2lPYZhLS+Q^Kq zbAKlF`QPdKt3T<r>7VGe6XW{+AKuUnWAEr_;v<P28Pw}eos<VUJ9XpWbF%)y=Ve33 zc4=DPA@OLvZ1k^_=Fnnkz8;oMS#^5TSGUXNYlV8tx!+{#q*re{k*QnG{GuP~|5djR zP3VVPC-ox-r{&R=@9D={64I7?RBx{ylXlNp*%1`k@$<0koavHX<9+h@w{dymt*z2= zaj$;zaJ6)fHtF3vb7jw=O1*b|mF{Zy>+aI|x~KMrekxPxeI;44&;DNb`mRfF@`CQW z`n5cLdQ|V9I4=i|ekupYUXy3~Mx_5pzqn?lrMuj-Z%I!}Pn+%e>$=tZ_jTKxo30F> z+n4d*TuS*X%zqlsSxN=+Tpp!-T4ki3fjpI|)RM5uN`1Sc#+9A=B=znJ@-07^`gvC{ z8jGvAxg)hrJmRX>+_9zxbFVS)=0l}iE`GOx<GiLGE?4|tjO7n=n$IN?$Y>nRaFFpJ z142fG3<((%GALwJ$gq%cAp_&DV`RwCkg++M!6BnVhKGy~86Yx3WQfQZkwGG(M23ls z6B#HnQe>zc#>!!^j%KvTaFOvM14c%S3>g_SGH7Jf$gq)da~L>>k#iV2hp}@QyrUUC zGJItGNC1!sAR$0vfCK@F0ulx!4oD!7NFbqbG_gQ};b@|Pgae5O5)dRJNJx;FAVEQ* zf`kQ$3lbP4GDv6~O>B_hIGX4n;X&eq1PF-`5+Wo<NRW^yAz?z|gaitS6cQ>VR!FcM zO|+13A@M>2hC~br84@!jXh_tMupx0n0*6En2^|tUBzTS{dPw*jP5h7mA`wJFh{O;H kA`(UXKaBqnMz0BJQ5gjd#mb8-i^C=5p;&3yd8_dL31K4)Bme*a literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Tirane b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Tirane new file mode 100644 index 0000000000000000000000000000000000000000..0b86017d243f1b7bbb41d6b4feefcb2b7edfc7d8 GIT binary patch literal 2084 zcmdVaZ%kEn9LMoPdKbGQeZlZ%fLMs2U4hF#MM1M0pb46CRs4e-6A=^XK*Yd5v6fkD z%zYo+S+1PA98;&{8vSwTtfmepGS|kMI?L6{XpQbx&YZIRz0V^z*Mpw4b<WOxo!#Bt zN59WIv}#jbj`h&xG2ifTy=5NW$L=|rSKqhgZKwa{Lb-Irr<cAM(&&uBNc8V>Y_F#+ z;=SB-W6aQEC#Gk<J@%W;k=XDw`>_-E9BGNM<McZxzH-<e=X~irKKrDdF#n`8e%vRv zFEAMK-5a<u!3sMQuGQF2_J15nJat-<j&)1&hx=t>r%KB9H)K*nvpltCy*ynWlGLIS znd~o+w4`*I67z(ldxDyND^D|iO4F%><8|7(NA;PWztn$dNT-LdYUa+1n$>bjvulrQ zp!$mBH1|kuaj)bp-6Q$Q`=lVJO$tUjWM*PmXI@_?g?C$Z*6E<kzE-70T{T+VJ4@&6 znx}I=NYZEPQgz<WLV2##qruulc|Pr?mIOzn)N?`0Qoon7;h$x}sIO$fK%czu<43Zv z`>2%npV5llowDfIL0#O~C@*%tsY_P8t4kX;XyuFs4V9PaGT$Oy?w_j5Z)a;&La9`J z8?P&GWyq?}{?yfjURiS>PO5u;leHaxNKJS^?3zJYx8qlRY3}E;zPev)Q})V+;%=>r z{!}+6t8V<|J*^*U)=how`ttRVZa%zP8_qY$mUoJ^v8z&EsZUX7SH3hYDU#+opS&8F zC@m#-<h3|UTC)<gHS&YB#opGo%V(v1_=;{l(IwjkdUgBWuXRWFK7GCYkaq0u(5OfL z=^i!uKf5g}{(VkrtXQKhD``?x^n>r^6(K8F!c!UIS5Z;!N9bRi{J+h`=|>iTtN>Yp zt62ko&mvsSDv)Kknsp!xK~{n+1z8KS7-Tiba**{P3qn?eED2c?vM5)xDr8x%W?jg_ zkd+}zL)L~Y4p|+tJY;>y0+AIWOGMU)ED~9zt63(pPGq6TN|B`^Yeg1|tQJ`=vR-7t z$cm9ABWp$$jjY<$EE`$3t64a*a%Abq+L6U0t4EfPtRE==QURm{NDYu8AXPxhfYia& z6auM)t0@Ii3#1rGHIQ;3^*{=OR0JsrQWK;oNL7%sAa!vyg+VIgYD$CD1}P3w9i%)+ zeUJhn6+%jc)CegOQYEBJNS%;EA(e79r9x_j6bq>qQZA%kNWqYbAtgg<h7=8{8d5f- zZb;#f%DI}-A+>Wg#Y3uxln<#NQb44FND1-(T|=)a<n#cE^jG9&=4WR6D+1Y=mFv9^ D;y&Xi literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Tiraspol b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Tiraspol new file mode 100644 index 0000000000000000000000000000000000000000..5ee23fe0e59f044598675db44d53c20590b88934 GIT binary patch literal 2390 zcmeIye@xVM9LMqZ#jg{Q&Nbq<8YYmQ{1n9!J;lQm&_fW(1g|7SK?@bb1pUl8M)PN4 z&59LkO=VMti%|+1l_@KNtFcu>>$^4kJ^ik7w#?P%`6brc`lJ5nzh1YyCwzBv&iQ^6 zty*7^CVxA}A5Zt|@^ie>A1_tC9P)a{NA@#wfApTY-r_y``F?Nr;7)H(Uz>66jTemb zC-xd|9<4Wen>HG6)s-1<S1vQ&DRCJW9!xdf&5ScHCf;RSitso3dYZlOJ=x&t|0>t< zL0kBtfmgB}gNJ80d`k~`!xE1B?vA+Z3bzk?!hgB5H{#n+U*vGME2_WQ7v0lp#+-b{ zjBVL%PT04_oLFCOPO4sE-m^N#jLVy4PM(u!-s_Asr^E!C@ndh9@!5GsLO_N}xDl@s zuZFAphQ9Ysy)fvR);ZvHzIxg-{YZy5X-~5!dFx?sN_nj(wY1$x+q}b<o^?uQEN_yG z*n=`NZG+6bT_c&%jVkj>q0GKjsqR0QArA~MQFD$JsH|?Mn%kJJ=DirIToqwz{+?;F zz<pC?myeT$Q$AJh?CX*f(5)6t{!kWO`$QJ|y(WtX&dQQ6o|WA87Rl>Bt@01-l%*$| z)v`@q@$9Qr1uN^-^6HhUa8{Wr%A2iLgu7I+Gg=kjj8i3HnNsqxzk29Kl&tFdQawEM ztE_JIlhV%5q-@t!S#zXUylXDWBMq0;qx0HiZRvScK5?%+mer~%?8nu**xhQ~*H5d; z+vRF~UzOT$B}Y}A$XC@D*UHAGWVPv-TOO|*ubya3keY%d*<3M3wxl{_tNS~tb^IXP zl7rMXb4cn!zfpC*F4=zVef3nwQQ0wYO4UE#sT$f3s-4@PQ@ak-DBB$Ye*S-b1&#@_ z2ieC4kGw+0{rL*i-wX`+?_MI&cKv@?qJ9#8k%&6czfDcCg^0vVlJTRTBTqsd62=o- z<mhLn%Qk`UOWf$^=#$YuAuqp3vh{m`e!Ja;eCP+(TmO<@xKO`y`3u-=BX8@6qJMFM zzv&fs_5DmaManr+PSUDAOUh|d&XaPYlryEAD&<@$Crde7%IQ+hmvX|CGp3v}<(w%e zO*w1IX;aRda^jRTr<^+f7@Rxh<SA!wRi8fP{3!%b7@$x<;ebK{g#`)?6dou<P?(@l zLE(Zz289i)nhpvdRy83MMktg}IH8b2VTD2qg%=7j6lN&YP`IIx!(fL&4}%}8nji*4 zRy9QojwmECSfbEG;fX>Ng((VE6s{O#QP^V8Md6D<7=<ybnlc7wRyAo1))=%gc%u-< zV2(l^gF6a&6!s|eQTU?}NMX>brjWv+RZSv=MFx!&9vMV3m}F4N;F3WmgG~yZ3_dA@ zG8m;$O5xP1CY8b}g;ol$6k;jNGN`3+%OID+E`weMzYKyI3^OQZaBNkR%wXB7rkTMr qg=hxT6sjp)Q^=<Ov;B|Q4%XkAo(A*I{Pd)Zq!ed<Y6?wG5B?oV8;IQi literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Ulyanovsk b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Ulyanovsk new file mode 100644 index 0000000000000000000000000000000000000000..7b61bdc522b5b7f4397fdb9246185f4d972f4b6c GIT binary patch literal 1267 zcmdVZPe{{I0KoD0%gwE=LkDY1H?wT6O;^9>CbOokrVeX@#PDDR(jOrRdV~jqz(MAz zf+C10qG)vK@1agvj_4Apr*0PfAUaeK?-GGh>wSOIQ<pmSetW;qkH=%M-}|mGd}1^% z{upcY3X_r5ljpiSqO<s{<Q-fWzFuDMpErH(xr}eoc;f#e${QAvX8r8>a>Mi$EAZf) z6}&lSHC{MwZ9F?<HJ!{^n+~O{&H0GcoUXUFw0W&iz@u8cODgOP%kX!<-1^B^jEv6| zBkvYv^z~QS`t-eQE6vH+)t7SH<YT#g?6x$IU6wlzPpkOpYpT8LmP#Brqmsd*>WCjy z9Y2q#RKvJTedtl0OT%*Kix#zOAuZGQva;)WqwJmv$=x@E%#6C^p2>jP+xuB&kN#3U zp|`R(YpFixLz!!SrE=fisQ#Lg>Yu-__I;dE`yX9Y`PsX2;L<5o$OlJ;e$>f{N~L1d ztg2oP=kitSs&%<n>)YR44wu6rL~KOARuMIYe(oDI+(M)>yz1(GWyR1d)jd(u&^rT7 zVl8`EXJ>w(AX?3KJ(GGS^wbAx=+E-td1Vy-;kfm$tZ?MWvGW}qJ#zd=0=7B>Bn2b~ zBnc!7Bn>1FBoQPNBo!nVBpD<dBpoClBq1atTb&Y;6Oxpz&I(Bj$qPvg$qY#i$qh*k z$qq>m$qz{o$q-4=R_BN$X{)nD(nRt^5=AmaQblq_l0~vb(naz`5=JscQbuw{lD5@Z kBWc^}yphC_%#qZQ+>zvw>~TW3@SmpdN$WpHcP!!g4SK2@ng9R* literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Uzhgorod b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Uzhgorod new file mode 100644 index 0000000000000000000000000000000000000000..66ae8d69e3f86cfdd8d90a9b1d094d807f75f27a GIT binary patch literal 2050 zcmd_qZ%kEn9LMqBNh!P)eQD8!xcn(H|8#}RKShH?uNP);?J8FzmB2#$6H%ZsD2-Om zwMOn+vYIO!mZLv2MjO=wZ2g&Qw9)mp<(eZ`tCh|<cD8b^8mr&?IO;)<deEcJ**UMX z-;?{~zCZDeJK9RjKdx)+2@h9~efZ9O(!R#$bn3*}I{D%)zb0M_%gGnYBzff3@4ozT z+Rd2vM)JnYZ>s&NlQI8q*L|FMJ}sFw8Lqx*;$SlS_@Em&_Pm?(%2RG`|1LLgPpg~X zzTUlgbB%jT{SvpJa=v?OFw31A@VU1=SLn{WxN>m8R~K3qo;Vr1eKgS$Jo;{I(ZEPc z;l6{hqTR<e)cTGVH=UM}u2Cti8k4ehFG_jNVOd<#Ba5f|q#}DjE6!|@rN4LUvJb;@ z$7G{c4mE4l*fPCy{|a6HazLxw3UtN3rLwXnMZ>MxvTE*GjfAJACgpRjE%;Vyr+$*v zvp$j4iE+8>hu5WU_-(15_(-D%`en_rBYJm7hs64y*0uLMtLxggYQvItjn~)edjA^T z5L}=eE`_u)qedFPzFzOWIA1ot|BG%q<&({W>C!ZMLGJ7OS(*nD($aiNw(LEx_b>lI z9%!1-*1SWqwQ5+~Qs2{UIjY;vy`<ZxyL88RukJh(*9YI+r0t(|%0tgoX~$55JiI+m zAK70noog$ltIaRFigRUm<X3q#-AH#)hIYH(OHbM*?Ma@H-l^02*vODPo*2_Thd$N4 z!-w^W-lN)gpiiAEX4%_GnSJ@b@~XdXCv}c@`>y^kZewmZXa8CzP0Va#0{Kqr%y&h# zbFDE8LneLZefcDiZ!$P>vS!|#)JNkc9N}q*n`px-`_!3;J&15%jN|<M@Oxa26aN<l z{9&)1QzMy32}lh{5l9tC8Au&SA^akhAf+I+c-mr+YLIe}dXR#Uijb0!nvkN9s*tjf zx{$(<%8=5K+K}Rq>X7n~`j7&V3Xu|#8j&KADv>ggI*~$=N|91MZLLVLp0-+~T%=y4 zV5DNCWTa-KXryYSY@}|aaHMjibfk8qcu!kBQog6HA6Woo1&}2`)&N-qWEGHQK-K|S z2xKLYr9jpKSqx9R8pv{Z+Vwyd1X&SeNsu)`76n-qWLc1PK^6vC8DwdYwLumKSsi3~ zJni}*3xuo?vP8%lA&Z2p60%IlIw1>%tQ4|T$XX$bg{&5`T%LBlkOlL!D~2o?vS!Gl mA*+Tg8?tWr|6Mqr-M~d9j9@TYT3B8fDk=>|i$mU5neR{PPwhhh literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Vaduz b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Vaduz new file mode 100644 index 0000000000000000000000000000000000000000..ad6cf59281a1046d9dcd045fda521585e3e33e06 GIT binary patch literal 1909 zcmciCX-L$09LMqhq+=x|UkjT`&1!PZnmp6((5_jPcE=8#Ej!E(waeVJGVQV`Btqi5 zAVpMc%Z5ah^}y<Z9c&jJCJUQH7eUcw5kZ9=Nd4abC5WxZ{r}9ohV0?@{qfIST%2Tm z^*GJH@Zni)KK$;!(R^KTEwQfLFSD+;`>f`(xmK9_nfB^=M_mEe)b;AL_I_|g`~164 z`=0w<!%v=)h(iq$x#th*SE~}WZj<ycDVG7W7sx=LU)*UKGRTuE(GfB7L$}@%<Me9G zo8db6VYJ4!_R=92I_uEJx9ZvdREO2w(zq>GHGbtuO(;C9iTO7rsk~8=)0<>?&JIb5 z+$*U`m6F;~EhEC~bj00xGV()(jymO)(YNz7t-e6hn?~uFn(;bzcZ7~BcI)^pBV|IS zQ@w@Z@>BF<&G2?ert`99x$jBVi$^js;BT4Oa!G!E@R$73a8P{BXEb|ztxP)fr%o;{ zl_|BGb?WqOnp0Awxj&Yu-<PGox+du~PpnRBPtd%uOv$^^Lub4hEHjV4)>*B=GJ9XB z<TpN-In}SEpsq#c7PQK|^=&$T><L+r->ijEyQC<+L5sT_(}j_$3!m)NMIGh3_)?WF zx$D=Z2WDx>#WGp8HC;>VbLF>1QM$Y)Marh8NqMnLRwVY5l^O43Rj4Hu@nKr=^1f7t zv}@%*=cVe!O<i-eUe>lW>AGEKb$!EL-B7h(tG8EcCx>|h0>AfbSzXLgSyn`UN1$be zh}HGW-@a_W<;}?D%g_IEIP5R~w{JGc{E-h&rTOqX^rLwOy=>cvW!HmhkQ=r&cZ}RJ za?d>6G;-I-ZQGjrMs6IrbL7^Mdq-{_xqIaHk^4s)KsrELKzcx$K)OKMK>DyXjUb&M ztsuQ1%^=+%?I8Ui4Iv#NEg?N2O(9(&Z6STxn#PdMY)xxOZ%A`UcSw6ke@KH!he(S^ zk4Te9mq?pPpGc!fr?#e5q*q(hEYdB~F48a3Fw!y7GSV~BG}1NFHqtlJIMTVTX&vd^ z)-;cFkF<~Uk8A+41IQL2dw^^LvJ1#IAp3x91hNyzRv>#}Yc>Pf4P-lz{XjMZ*%4$* zkUc>*1=$s3TabN0HU`-lWNVPUu{E26?2fJ39%O%z4MKJZ*&<|*kWE5%$q~@Wyn)W| z{eB*%p!b#;CNocFr$WT){^f7xX~O>|>c5RL-@#_Hh9$CIp6ukfl(+;>c47j?CkKB5 Dj=i{v literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Vatican b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Vatican new file mode 100644 index 0000000000000000000000000000000000000000..ac4c16342b5bbfa4c58a26f57db33b95f5b3e533 GIT binary patch literal 2641 zcmciDdrVe!9LMp8n;;^6(G=q%7MYlcAfRBPDFP!OEa6Gb8+b!4q9ZA3sc4xi$K1Cx zokJ5ZxiqC#m}_dS(nbTxFf1x3%S?;r&Sp*t(SGm47_<7@bM~Cq;W+>Ny+5AmiwlRl z{&V@8FZ{Unn;-8z*O*5|$_=Zcv95Xh$y$5I5m&+6uivtERz@^e7QAEcT79Ts_so&j z9(PzlO;NI4cWI)W+8?U*yVK>HH<RRa@ofFJq^~r%8|*V<67;+525F4EZk-*x)jr#@ zMt|tOMOqUN+pSF}n%g28thP_8?VC5Nt@dqO>{}O4+qYl-$a0<h(Ds`9mgT*Dy5%$e z1<Uu<QrmCHCc9hlCd<FaGCLq+lpWAA)eelCY6aG&+CjmoR?vIlcF$j%?cfdV_C2TC zEm<07g&aC>^~$?x_0E|f_a^?WeWF{mZ||Qq)aR6jUj0=2U3g#bJ5#A)U%sK?$Bs+H z!77Q|zEk>_t3<6_D+7v3<o=oS<N>!wqDN=QgRvuIV8kGKD5#$d@=Mo2*OD~m;y@kT z*jFDu>90eoZ)oh^-*xEbA2n`WtqxmyOylPt(u7$}GQ6Z(64Q=KQtlQ>j@%(5hA)>9 z?PZb@zFAYw&5_i$QXO?XT^{*qnvUL=uW3g|>6rE7bZkY0K3W*9<JP6h_)I@dpC2w0 z242#P^mfVg`&zT2&r8;o-z3}TbIGo+k;g9Vk%?6Y#9jB9=4>pNNe6f7<Hg1DMENT^ zdFlquEn1*?Ba77I&eA7CC+U>f!8+x7yiV(rDbv31rB7Xpk?9}*r861>WoBiF%&PuV zW|v)+{LS@Jkl!eCR{f!K#~zV+v+8ty)HYd=R;7gjhjn43>cY!gby0hXF0NUjPoMMX zGw;sOqOX?7v#+IT@xDBHZc&t4>yu^4<k3=67%I;v^p~X>t+Fh{C8fjqXsP{+EDye} z%TJ$>6<3<{#Siw$OZ7)}<+d+$Rn-n%y<)GHZ7fr7uddt2*W6y-Jk8x{$6t3m{kq-# z+vVy}ZO)S`Vt|*g%M~oH?w!w$FJ0f=IUZMfMjj6j|HI2%XkI-3e|iJVKl0-`V1B%Z z+&0&kn9FXoj;*zj)9h$YG;*qulZ~8i<b)%q969O8X-7^xa_W(jkDPv_07wOp5+F4| zihxuBDFadmq!5m#5=beKS~!|wAk}a*<v{9z6a<}$@IpzrOih5IAXP!ig46{m3{n}S zG)Qe6O>vOwIGXYx^>H)>LMnum2&oZLB&146nUFdmg+eNYlnSYpqbU|rEu>sXy^w+- z6+=pf)C?&aQZ=M(NZpXaA(cZ)htv)!o};NAQa+@9NCA-wA|*s>h!hd2B2q@Ajz}Sq zN+P91YKaun(Nq&Dr=zJSQc$F#NJ){JB1J{2ij)<pD^ggbvPfx>+9Jh8s*9A@(bN|y zu%oFkQevdWNRg2$BV|VFj1(HFG*W7$)=06DY9r-#H1$Rb?r18GlpLu!Qgo#1NZFCP zBZWsQkCYy%JyLw6`bhba`XdYAXjTAO0%Q%4ML<>oSq5YskcB{20$B=VEs(`PRs&fM zWId1taWpG}EQzC86J$}4RY8^oSr=qskd;A}#>>aM>-P0Cx3>>Zb9dVD*B#Gp{&)ZG zoEkGYW@^l^m^}y<SI^F8$Cs|}3{LL9MyG3a%v+#YqM-?FQfy9QTyk7|Y)(Qv4oeLD E2jBk!N&o-= literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Vienna b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Vienna new file mode 100644 index 0000000000000000000000000000000000000000..3582bb15cd7322088839b0134987ad10e717b6b5 GIT binary patch literal 2200 zcmdtie@xVM9LMo5ASul3Z3buj5bY$SPJTmTklJ}Lg;SBsNF*>2wFu=h2Bn=pm~+Y8 zTgP+`Nkhh}>FFO>YiO;kMhgjNmtncKoWH6$Hgnb*tIzZMuj`Ng>5o3&eZP<IZo5Bj zyVujVa(#W4b<Y`ZKH=u<HaGA0Z#9q3iH@4i(52BsBSG!zIi+uXsCu~VfOc<;lcNhO zbs(xq2d|gNxpy5p)a{n9_vOg&_GCHlkCpQQk6fsY*KbOk8p=N_-=_A-MOU1B7qwre zcvD6n${wzXasHyQQ+`lK#5r}`{z#`@IiU|<IHGZ9_iFs<Gm>yDD2ay-%d~ctq|Mu8 zdV^nPtg4kqN`2xi@W@P8o+Kxv$fFadN=l?#Q|{#GtgFeI8j97&J|C}-_x-M}o|`(m z<C3PeeWmG}PHRTpam}n6kt~0oWEb{J&hq_|o7g3JSuK(`7LYmd9XjXoYRUhzS?8W{ z%ah+%XhCna7WU88r*<yTd7TM5zuu_}+VbV;qDXbu#mmCv>*{fjNm1mNTI~E$if>($ zMG>FKqM-p<eC4Q=1mBa=!H?Cur(KpDds~+_Hp;U09a{G6o4UMVjg~*rpuW;#ea5jw zSGZDj#oY|8h$)haix28^cV@}T_kYvMP_(Q%GFhtnewF6~x23vcNNTD>vU<zU`og>q zq_%2M>yi%2n!=#gPdKG(6IIvVIH2ps{JMUiRbRa9)0f_<)P^sb<mFw3+Spqz8`dT1 z#+|v+R8}DVdWXD{IZZZs{*YHEThg2!qs^l~Nz0_W+A{o^wB8!g*G~4z>qGsz`QWFz zCD^5JwDxFVPe8-N!Xw7rdxeEZ-uGW$mi0iH`R7^*)5FGD)+Di_{^`Bc>$BXRavnau z5oQjW7vI0w$zSGd=&nvj_F`)`gX{*`4zeF)L&%PhEg^eCHihg8*%q=dWMjzAY|Yk? zy&;=Jc86>a*&nh&eknUdwutNz*(9<{TeD4MpU6g$og!OB_KIv4*)6hNWWUIUksTvj zM)r(s8re0nZCkT%WaG%rk*y<pM>db_9@##!f209O2apyZJwTd(bOC9Dt?2{O2wT$$ zq!mankY*s=K-z)y18E4-5u_zZPmrb{T|wG{^aW{*t?3NX8e7vFq&Y};koF+`K^lZ~ z2x$@0Bcw@4myk9geL@;#YdVFr%GUG>X%^Bgq+LkAkcJ^0Lt2LP3~3tDHKc7w-;l;3 zokLn@YkG$?59uD#KBRw01Cb6QEkt^VG!f|{(nh3@NF$L>BCWJFy+oR6Yr2WF6X_?? kP^6<sOOc-9|FNmjCbP3M39ieVotB%H;qqo?V0w1+--?$-F#rGn literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Vilnius b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Vilnius new file mode 100644 index 0000000000000000000000000000000000000000..7abd63fa608e0186b9f154d9fcc32472c28f6759 GIT binary patch literal 2162 zcmeIyZ%kEn9LMqB4bdCX^^1iU0z@JK3E}cjZIi_KHw6^sihoHfL@Xjjb5I&*rOq|x zz7<=!bop=eXT*G9_8?n-<{H%v?-SM<wOXxgthv+5IonwM-Up~vkKB6L@9gk8I~N!a z_`Jg#ceECnf1O$O4L7ID-aKbH_RFzV=?y0ju6XIx&ms48YuDDHflE6-*^nEJT&|VR zUJvT<sS3IDe2GLuW#1%bzZ#vL^ksR_KiUxdZRYz)V}WS$Xhr!Qkr$#V7f!gT1JAi> z$DVfQ^zL@k_qDil+t<1oo2%VB>lV40OLE-1@{-+osmUfQKF(yvmO9y2vz(mogU<XB zzmt3Mx^wrrF(>cLsI#Ci;^ZHA*D2UD=!9BcaSEG1HAS8Mrnu})Q?ll;DNQ>r3yZpB z;dqZMPU+Ko4=vNBFQ;mGYo;zcaF5(q9jg^BDN;G_vQ|}$OLgqWT9f&;)Li*NmdAV` z%ZG<##doKrcJK|Ui@c}xM|x%Dz)4-z(IE}J&*<uP&+3}?ZQ8h~UBh)Xx;D5{oATys z)3uPUPpp>ppU=__S94_J`CoO@NStgwks!_Iev<opevvJG!?JbDh&-@=OdnkOwmj4v z(U$b1vaM`TTm5h8_B7S)Kfb7K<DI%=s9PWYDy)yZwn^JR+9i)3F4K<wMtQ6)U3VTT zm0hcsNM~zMb{Ec(JyqA`@dP7#3lep&`>k{Zu4z~FqI6&RLZ3L>FHa7?qx+72sQU+x z>r>rlwC6~V`fiGu78C2AK4bcf*qbM=xLYQ#_*?&Z1!e{$;Xk>I30|=OTIRO1W|}dx z+l=3sfS7n=Qs){mCO2em|Lct}iT8Y6T<%Mo`gH2qmofEI6W{aq-{Z@us}GxX_O7*e zMOD~T*}J~6);>4#P-$P-hl%6!8RMHgldt~##ODj&z;b@Kr|Ep85?K(kB4kO(nvg{y zt3sBAtP5EfvNB|8{8_9GSsb!DPrE#1eaHfl6(UPS)`%<;StYVeWSz)Dk(DA#Mb?Te zmcwc}EZ5Vn7g;c}Vr0q4nvq2#t45ZMtQ%Q4vT_bf=dgATi|4R<Wci+U{YU|j3Lqsw zYJe00sRB|4qz*_SkV+t>@U*o+is5Oifs_NO2T~BEB1lP)njl3%s)CdSsS8pVq%ufp zJZ)`|;&|HXAmu^ogA@p<5K<zfMo5v6Dj{V;>Vy;usT5Kwq*h3=JZ-g*av}9X3Wih+ zDH&2Tq-aRhkg_3lLkfpf4k;Z{JEVA?wt7hUJZ=4u0wNVeN{G}DDI!uu{J)GhTE;jV a)dfX_G_SrmzcfEoP@Gp^81kM<;{E^_i2_Uj literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Volgograd b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Volgograd new file mode 100644 index 0000000000000000000000000000000000000000..11739ac271da2b623bef49ea64908820b7ca05fd GIT binary patch literal 1165 zcmd7QPe_w-9LMozxiy&`x|B0F`(ty>KeaX|tEMfd8`cDg(Lswwe}o|DOL!;<3^Gp@ z6hTB0MWai9i8^I5qD!QnylL=2hv+Zgi<hL<@BP>*g6P)s@a*;Qu#K_LyD)fUIA;Cv zsQ&e|+sOU$Tl3kur=^;K72&JpmHz2yZS_>T_M7XG|D#o|n@vPlO`a{+Ph7GC_s-bC z>mzo<xx@DAQ+w<+M|1Yty-9mrK4LefHt71+It>MU+ElZkVNY1X^L~lUd@eS>`Xnt+ z=A^YWC2f~q$i}gUvT5X|L=Rn*&HE-acKnLQJ8x+F?vt7bp4N`okam1Opvn3Zl6>2v zTNVao>+>evHk*>vos4uoYmlz-kZiwZNqX2TJH`Uq-TOf@2Y+Z!=#BJdY|VP^ORn*y z=DxnxzN(V;P2bg>@5Xi4gY%l7ye<6~j%gtuEDp_l(f#iq7e_0Vifc*L;_3D{=Ta}H zdy&7ry1j0%*Rmod{@v!N<+iM3n*TRD;9B<ky~{l3J^B8E)e?=HtKD1)K5DtlQTT`T z%nz@yAhIIg!IH?D$fAyBRb*LYU1VWoWn^h&ZDes|b!2&DeWU=S0;B|_2BZk23P)20 zQU_89QVCKDQVUWHQVmiLQV&uPQV~)TQWH{?qp1oh%hA+@6oyoWl!nxX6o*uYl!w%Z z6o^!al!(-b6p2)cl<8>dL<)5@l_I4gwIanL)gt90^&$o1sA=H;so0k?ZFjZBeLn&7 C+!|T{ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Warsaw b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Warsaw new file mode 100644 index 0000000000000000000000000000000000000000..e33cf67171da78aa9e6eb02e50f9b9603da4c3f4 GIT binary patch literal 2654 zcmeIzYfP499LMnskW^Coqaw;dEFzImK@b%oGeT#8sXQv;2@Oz-3=a{S#64xMnREXf z;t(k<WagCELR+G9cA70CJdk0dR<1mZOhdBPm|fr7wboi&z35%nv*-TYJmc;4{dsbh z7mPN4Id|J%_;U8zFYm#QeN^p>ZmI4Qlv~|;;rgz&dabEFq_4cA`fB+O-M#a$*^__F z)RnH!Jz4yvoVt`QpS%&I&99}(r`r;wrTmCFy?tBJnaxePXP4YAI+q@ytqTvzXTuxi zd`z%>-n&xTyiaJ`l@ht^Ib$y0XmqZ8z1O*Vy3*+wP-!}jyk)-MUu&-I+-`n2mt(H4 zd(PZwOg2B}%r%`AL(I*j38t$w$@wWb%=E3D<@mqU$J|ps){!+)PC(vZr=Q2q>7SWs z2E=zbff4P_!2Zonkk4@^sI$Qtba9U}`0O?(_`Quz$k8`V=z-lPY}d<X$d(NzeEn)O zv@p-yJAanBFT*1d$!T(bOrk`F4wDD^43c5KsXDAHL8HEn)ZwiIHTr{|`e5VF8dG~k zM^s$Uk>wxjs5M75Ht(RuEohU`s~ROfrAZQIR?3*L8c7^oB8lB)GA^V-$F(n(@xK;p z(y>&T@I|&J*DcbNrX+o6(<Gf(9jXr(MChdQ@$$%IUro&mkw+shX<BNxO!oaqr$l@u zQ?7j{Q+-az)aH}&*u~c+y?(!BoI0+VTerxx1AFxG6)R-=mW?`N&Ssrin6Fu53)Pb` zMP~&~)7de@b@r`T%?_L_+2{M|+^#6eIeb&+wff2Y-2t+ou|pP?b;_cOX31UDDvL|6 z>XM0X%M%MuX<m4h<fqhYL9au)G)#5r<sG`LdzCIfxmKTS_vlmm=4s)FE9L1IQ*=dL zmOQg8T#Gi1k(D!&WmQ3ttd1KZYtnv^X9J8Bj|$Y{>)%L;|1B+Pd0*CEYtwZNb@F_3 zldi9NS4-<_^o6yxTDG-Jy?nfVdieI}byrUxZ(sXz=TF}L;itFXfB!M2e}la{JbM@u zI@GI|G5%uu{`oyR)+>Nt%)mdMzyD`OrpL^&-_*1$9v+j%OPYP*c-dng?)#m;J^$ib z-?nG=;g;#h^+v9^tG(vPRY$Hna^;b0k6eA^`XdQIGJvE2$pMlCBnwCykUSuXKr(@( z0?7rE3?v&!I*@$0+Jqn(akVKya)KlU$%?B@3z8QkF-T^R)F8P*l7nOiNe_}ABtaZ9 zgrtZ=j*uiFSwhl;<cUL~kW3+|LUQG5lZ9jpNf(kYBw-vf#vx@Ka>gNP9J0nCZ5;B3 zBo4_Ok~$=JNb+25_K@@;`9l(jWDrRql0zhkNEVSaB6&m-iDVK<C6Y@dnXWdQNIG3@ zK9PhX8AVcx<P=FNl2s(FNM4b|BAG=}i{utbE|Og&y{<ODNP=B$hLIE_IYyF<WEn{_ zl4m5*NT!igBe_PBjbs~1x2w%Jl5kg>aU|tP&XJ@eSx3^2<Q+*ol6fTcNbZs3BiTpN zkK`Yj09QK$$P^%RfJ_213&=De^MFhQG84#DAaj9C1~MDSbRhGAOo*$U5oAhS?VKQ! tg3JmsEy%ne6NAhQ{y#N;J2ifGjz+{WOfi}9Bgc%4jmeCQ#ZmEozX3dW2`vBs literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Zagreb b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Zagreb new file mode 100644 index 0000000000000000000000000000000000000000..27de456f16ab549627b284a39e2265cbdb4ad8e9 GIT binary patch literal 1920 zcmdVaYfQ~?9LMqhL0H4S7@-o9T#oJ~DdMPHDwhrt$t4vMLdq?-nOU<hYs@g$HH>%= z9>mObA-Sy?W{kPcS{sI0<M;k=Hk(JD*!)lDyjrdG<oo`(Gv?)lS${mO%ujgptT1oB zZ@bQX+-w&4y!OplxqZw_>khf(&W;GVyCFdC9W0aksqxz7<tgp@;DC0!vR%E;Ul5-Y zmEya1zjQBC@msxKdgK>M&*^idSF&6DV-uveGfDz{0;NxzE)wYB(!kFV+V@p}_N(u# z{jass0aahsdE}iAEPt#)n{H|Fvhx~}eNsa+A4ynYm4wGtOT@&T66w27qQZ(Ls;N|> zy~{QF=`0!iy+~s&xMawabd9aZ(zxmv9lCkA4%_3S@j3oFeA8eVk?5hWY;PGE@J16{ zO_JzwLzDcUNm9dW8QuJnjIOJZF)t6x*vjLQTzgSdwv|chiGw<>pg_i#ZPW=<w(7+E zxtca8U){+`I>{?lCp-J;<S!wb-YHSiA9m2GpZiM2*-tvH-czO@XfK&nA7n=9N69L$ zlbKodGHcCyojvTF%*m|PY`@(yH?C51TA$HeU)9{VyELz<Q0LW@==`T{U2t@o=3ieT z3%A5+K}DJ@%Jb93n<Hh(gjgxe@sg#X-DO$AH(B1^lA_>FTGaSLiranB;=5O+q~VdS zJY6BH>Z*11?#sHSa-Xg(IijW8O4ZS#S#$g4(ehuuEURO*xhkujSS@~i`t)$LwyfVj z`E7EF+j1rFPIH?-a5(tlaX8$6al=2%Gb6Tf6mrYRJtH@b+%<CB$bBO>j@&u_nOjHh z9l3er?vdL^?jLCY=>TZ~=>cg1=>lm3=>us5>BQEwg7ktkgLH$mgY<(mgmi?og!F_o zg>;3qh4h6qhID3YT0?rXHO(R2A?+dkAq^rOA}u04B26M)B5fjlB8?)QBCR65+L~sO zZf#AwNWVzKNXJOaNY6;qNY_Z)NZ&}~NaslFNbk0$d8B(=(>~HavH{2rAX|X!0kR3m zE+E^0>;tk9$W9<zf$Rmc8OUzfn(aXL1KAK{N02Q+_5|4!WLJ=FLG}gN7-VOVtwHt% z*&JkdY|Zu{`(tZ12-zWIi;z7+HVN4!WSj7R-zQJATLVKGE@w)3P-IYuGbJ<xgTp<4 E0<)*Xw*UYD literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Zaporozhye b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Zaporozhye new file mode 100644 index 0000000000000000000000000000000000000000..e42edfc8506b9b99362b36d90c8b8c4db67d50d8 GIT binary patch literal 2106 zcmeIye@xVM9LMp`2^5`$Z{6@9Ku9!D5spI?4H7#KW`Lb?5~;*lh+0I5#=taMIp-R4 z?<T9ca<gPq%$RLxf1vA^Yu4zxKeFb?wN;De%zd|VR*u!@`E|6m{_2nZ>-*jJ`}p!@ z?6w=PXJq4!)`0oPaff}w#j(d;JkNX9-iFeT`%ev|M?W2!h>uOw$Y*c)H1>K>VrReX zNX>gAK0EE}N?-DL*!TO4_tP$?#M8%vm3NLEj%S=X=476D(aC!CIcHAaE+>0$i<8r~ z!MSU5l{2??nUh<d@60Pmcjjk$ox7*saPpG!I`Xcib>x5lQ+UA_SE38geI8yk5{niL zyc1sBe==IQ|8Tfy_ZjuKysgDe7bVa+A|(~0vSj^BQkr#CmIk_I>13~zW%O&=r7g1j zMwhNQ8<cy-8?}6}St~|Y=)DJ4>B?6!wX!u=SM6Ue_f;inuq8uQ&!5mxa8jz0KGEvj zZ>0L_53(lV16dP0FZX|UTxy1gq;~8*tvl2wYfrqU545*SxbJyg_uvb<zHO`4FKg3C zZMAOjt<{Et1=?`kuZ^iy()iUZedt=gY&`voZo1%=&Bta+)5sNhxc6si?vF{d`GRcO zcUd1<`K~<LG^Q=tM`UZou(l?j(rsC)+kSjmw@-HJj`KbG*rkX*{^lla`*^23aj-($ z2kYg@?b+IKpj39QE0@kzpX@50BfCSt$x}0pbQPs)m-DT3r(D<W_&MphdQtbB9F(VH zqq_IVhq`b0s6Nv(puLBB)iW*Omc*pQgj;W($+!LO^iI2ZPQU%XIE~5q)&7&2oVZCe zCNsx)jale7DaNFTnZ+B=?5TTMr6*(Rw^PraY~FC^Z)@u!W|2P-@S9L5V(RK^Owbw( z)$_w@`_evecs%X}e;poA<X<e~4|_D6{wNt)2(l7nDacxo#UQJ3waejSSr4)xWJRua zNywUzMIoy~mW8YfSs1c1WNFCSki{XZLzaiE4_P3xLS%`qc8$m)kyRqgMAnHc6j>>< zRAjBlVv*G%%SG0UEEriavSe4gW@OQ>cGbwTk#!>rM^=t39a%fFcx3g+@{#o;1wbl* zlmMv#QUq691*8nFwhl-kkV+t>Kx%;$1E~g54x}DPL6C|dB|&O}6vfq61u2WGtqW2Z zq%ufpklG-{L8^n42dNKIAf!S_iI5s0MMA2Cl*!fB2`Lm(DWp_Lt&n0N)k4aJ)C(yX zQZb}tNX?L<Ayq@l=4$JP6wcLF4k;Z{JEV9>^^o!*^~3)Q$hSZdy*8VR17xzGuB5QE Q&|g$iP*?1CpO$$41Tp&eZ~y=R literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Zurich b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Zurich new file mode 100644 index 0000000000000000000000000000000000000000..ad6cf59281a1046d9dcd045fda521585e3e33e06 GIT binary patch literal 1909 zcmciCX-L$09LMqhq+=x|UkjT`&1!PZnmp6((5_jPcE=8#Ej!E(waeVJGVQV`Btqi5 zAVpMc%Z5ah^}y<Z9c&jJCJUQH7eUcw5kZ9=Nd4abC5WxZ{r}9ohV0?@{qfIST%2Tm z^*GJH@Zni)KK$;!(R^KTEwQfLFSD+;`>f`(xmK9_nfB^=M_mEe)b;AL_I_|g`~164 z`=0w<!%v=)h(iq$x#th*SE~}WZj<ycDVG7W7sx=LU)*UKGRTuE(GfB7L$}@%<Me9G zo8db6VYJ4!_R=92I_uEJx9ZvdREO2w(zq>GHGbtuO(;C9iTO7rsk~8=)0<>?&JIb5 z+$*U`m6F;~EhEC~bj00xGV()(jymO)(YNz7t-e6hn?~uFn(;bzcZ7~BcI)^pBV|IS zQ@w@Z@>BF<&G2?ert`99x$jBVi$^js;BT4Oa!G!E@R$73a8P{BXEb|ztxP)fr%o;{ zl_|BGb?WqOnp0Awxj&Yu-<PGox+du~PpnRBPtd%uOv$^^Lub4hEHjV4)>*B=GJ9XB z<TpN-In}SEpsq#c7PQK|^=&$T><L+r->ijEyQC<+L5sT_(}j_$3!m)NMIGh3_)?WF zx$D=Z2WDx>#WGp8HC;>VbLF>1QM$Y)Marh8NqMnLRwVY5l^O43Rj4Hu@nKr=^1f7t zv}@%*=cVe!O<i-eUe>lW>AGEKb$!EL-B7h(tG8EcCx>|h0>AfbSzXLgSyn`UN1$be zh}HGW-@a_W<;}?D%g_IEIP5R~w{JGc{E-h&rTOqX^rLwOy=>cvW!HmhkQ=r&cZ}RJ za?d>6G;-I-ZQGjrMs6IrbL7^Mdq-{_xqIaHk^4s)KsrELKzcx$K)OKMK>DyXjUb&M ztsuQ1%^=+%?I8Ui4Iv#NEg?N2O(9(&Z6STxn#PdMY)xxOZ%A`UcSw6ke@KH!he(S^ zk4Te9mq?pPpGc!fr?#e5q*q(hEYdB~F48a3Fw!y7GSV~BG}1NFHqtlJIMTVTX&vd^ z)-;cFkF<~Uk8A+41IQL2dw^^LvJ1#IAp3x91hNyzRv>#}Yc>Pf4P-lz{XjMZ*%4$* zkUc>*1=$s3TabN0HU`-lWNVPUu{E26?2fJ39%O%z4MKJZ*&<|*kWE5%$q~@Wyn)W| z{eB*%p!b#;CNocFr$WT){^f7xX~O>|>c5RL-@#_Hh9$CIp6ukfl(+;>c47j?CkKB5 Dj=i{v literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Factory b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Factory new file mode 100644 index 0000000000000000000000000000000000000000..60aa2a0d695ba577ff87624d479f1eb25c8f1caf GIT binary patch literal 116 jcmWHE%1kq2AP5+NDp(+@bPWs`Ldep^Wdqb}XTSvjS7imx literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/GB b/venv/lib/python3.8/site-packages/pytz/zoneinfo/GB new file mode 100644 index 0000000000000000000000000000000000000000..ac02a81440f47a67b9f01d3fbcdb085266d20894 GIT binary patch literal 3648 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 Nbd8QojP~#<@K40&SY`kK literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/GB-Eire b/venv/lib/python3.8/site-packages/pytz/zoneinfo/GB-Eire new file mode 100644 index 0000000000000000000000000000000000000000..ac02a81440f47a67b9f01d3fbcdb085266d20894 GIT binary patch literal 3648 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 Nbd8QojP~#<@K40&SY`kK literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/GMT b/venv/lib/python3.8/site-packages/pytz/zoneinfo/GMT new file mode 100644 index 0000000000000000000000000000000000000000..c63474664a289aa3c3c0d8b2ce06d484679754c0 GIT binary patch literal 114 hcmWHE%1kq2AP5+NDp(+@+<ikBLdep^1=MQ51psD724w&M literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/GMT+0 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/GMT+0 new file mode 100644 index 0000000000000000000000000000000000000000..c63474664a289aa3c3c0d8b2ce06d484679754c0 GIT binary patch literal 114 hcmWHE%1kq2AP5+NDp(+@+<ikBLdep^1=MQ51psD724w&M literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/GMT-0 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/GMT-0 new file mode 100644 index 0000000000000000000000000000000000000000..c63474664a289aa3c3c0d8b2ce06d484679754c0 GIT binary patch literal 114 hcmWHE%1kq2AP5+NDp(+@+<ikBLdep^1=MQ51psD724w&M literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/GMT0 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/GMT0 new file mode 100644 index 0000000000000000000000000000000000000000..c63474664a289aa3c3c0d8b2ce06d484679754c0 GIT binary patch literal 114 hcmWHE%1kq2AP5+NDp(+@+<ikBLdep^1=MQ51psD724w&M literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Greenwich b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Greenwich new file mode 100644 index 0000000000000000000000000000000000000000..c63474664a289aa3c3c0d8b2ce06d484679754c0 GIT binary patch literal 114 hcmWHE%1kq2AP5+NDp(+@+<ikBLdep^1=MQ51psD724w&M literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/HST b/venv/lib/python3.8/site-packages/pytz/zoneinfo/HST new file mode 100644 index 0000000000000000000000000000000000000000..cccd45eb8cb2f56b6a1b75e2d7b9530cb5abf2e1 GIT binary patch literal 115 mcmWHE%1kq2AP5+NDp>yiFHT@!@CXiJ2q8-s7f`FA0T%#a4Gc{H literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Hongkong b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Hongkong new file mode 100644 index 0000000000000000000000000000000000000000..23d0375fba3377a3d513d849c0d29c82ad2add64 GIT binary patch literal 1203 zcmd7QU1-f=0LSs?e_rh{a>4}{MD&!#u^Z16wn@Wr?82!@F;a5cyrs<5X_8uzPOZ35 zlB;KwMCrM5X)}@6?btZ;wsRV0UUrThHplb*N4apbJI}v!K2QJ4|L+^$p4eL{{&|AG z->$cEpK~&?C)FKW5$W!4kKBzOKKAHhCiS?fxAjT;HuJRhn(8^S%Ji<OG3jNMCS9yD zebZ-|zGw4H|8T)PHxuT?y|l?(nyUtG=GDvN<LcGfJMwjXLcKY9MZR4gRfCP4Iy<96 z<<@rS+}K7lH2;(yN-s6<O8fPDQ*J&C)a&7MBj#gQvm9x8Xg=vJ@^ixt^QA2!zg9m` zqx-@#zu>wm)Q!q-i<4?>_HJ49?^4D5I{AIDR{h8{>hb$K&BU!5{qt(IDP35k#hHc1 zN&2<tfX{e$<g_oAHU2uE46O93;F7Eio>;BQ0$sAK(5XV%%W`T@hnjZ#w48aqN`((L zYscgDIUaw&KAu01<C)|mL{o^5eW+FVgh-~GDMGZgIpy3%`0w|dV{x$|%5N)w4RNu_ zUfkn2@kwl1vWGp9O<nD-$hOG7$i~Rd$kxc-$mYoIu6BE5e^=W8(gD%}(gV^2(go56 z(g)HA(h1TE(hJfI(v7Qa2kFPvHiUG9w1o78G=+49w1xDAG=_ABw1)JCG>3GDw1@PE zH0WwOL|R08M4CjpM7K>Y^vSV}0-YkQBE2HbBHbeGBK^ABhLMh4ZOcf{NYhByNZa_o L^&PV1SE$f0t#TGS literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Iceland b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Iceland new file mode 100644 index 0000000000000000000000000000000000000000..10e0fc8190a401f67b861ced3b8b16401432a565 GIT binary patch literal 1162 zcmc)IO-K}R7{~FMc3s3G76L_sdZN@of-OT3ifGF^)E;6NqAo5`K~YdqbStrh=!Nu9 zr>&mEQ}hObVC*3X5;d*O)NM6;HCOFLvurJE`hUluOP9Jdf0)lObDQ5cvUS(aW!4`r z-><i8jXe8LMUQE$Zk}}^aiaF(flXDHx;%aj*I1Vu%W4}|6jwDg9rWJ|6<EzHi={c0 zceABvjkeq^k~UwVwp|VC{l0c-KfOph;y2{M9-lsp)k$JQS|8P1)6SAseZ1qWc9kcj zyJElg<lmBHVOW!s=Oi_IpQN4~mfnFp?Q7a1Pdk=NfBhkSc0E^~S8vuAXEO3~Te-g4 zo08YTxjGPv%bNw?b+9a{>6ryGlzUr;hNonBBBmp){qnZ^h`zgWN8UF^^~1?}89g7= zvE9ez<IzeP537EvTrHnVt94@4LisXhyJqHRNoIVVPW~8_ubqqaTiT;j@d}w?|2`h? zKb<Vc8HrB+XWQ#IW208~^qqIM*ZneUV<=*k1OnEQz*1|ydFGRCNB&|t$6Tz3EQqX# zEQzd%EQ+j(EbD64MHWU@b~Q^QYrC4ok=0$z^2qu~0Z0W%2}lh{5l9tC8Au&SAxI@i zDM&4@rWm9eS5ppB4^j|P5mFLT6H*jX6;c*b7g88f8B!Wj8&VunovSGisSha-sSqg< rsSzm>sS+s@sS_y_sT3&{sTC;}sn*q$i`0u0j8u&OzvLVfbs*;_NO)Hd literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Antananarivo b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Antananarivo new file mode 100644 index 0000000000000000000000000000000000000000..9dcfc19c56e62b12b730f4335b34479695f273f5 GIT binary patch literal 265 zcmWHE%1kq2zzbM`vLGzd{r}>hjqh$nY&rhm!ojy|BhKVhU14NmWM*PuP-+1gp{&8c z!oZ+qz`(`8ptgpA55o5G4PnqWFfuk^aCHQ;OiUR<NU-)l5P+-((ID$VG{^}c8srQR OO@ULmfUeRt<^llo>q3(N literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Chagos b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Chagos new file mode 100644 index 0000000000000000000000000000000000000000..93d6dda50f579093f25617c77081ae99c8631ea5 GIT binary patch literal 199 zcmWHE%1kq2zzdjxvLMXUS@(U8!Lz#?>i_@$&&b5Yz~KA@q|q&afrWt~B!Pj$$2WvQ k+rSiv%@{&RFc@gwe~{rI(?Ax0Xre6PvH@CUr)$Oq0G>%BlK=n! literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Christmas b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Christmas new file mode 100644 index 0000000000000000000000000000000000000000..d18c3810d97bbd424dc3c8fa98de46bfa08c3fa8 GIT binary patch literal 165 zcmWHE%1kq2zzdjwvLMXS03_=F|Nqa($iR>+1LQCy6)>>)_=YfO8<;bMkYEzfkpIPE TE1!VOz-=Oz4bWUWU2`q~S7aD5 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Cocos b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Cocos new file mode 100644 index 0000000000000000000000000000000000000000..f8116e7025cadc709bbd995905e88c92ed03642a GIT binary patch literal 174 zcmWHE%1kq2zzdjwvLMXW03_=F|Nqa($iNVF2gqTF&R}5i@eN_nHZU_bU<e_>ETA#} YYeLnQfK0(>CYKG^Y&%^uD`NvL0F6i*%m4rY literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Comoro b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Comoro new file mode 100644 index 0000000000000000000000000000000000000000..9dcfc19c56e62b12b730f4335b34479695f273f5 GIT binary patch literal 265 zcmWHE%1kq2zzbM`vLGzd{r}>hjqh$nY&rhm!ojy|BhKVhU14NmWM*PuP-+1gp{&8c z!oZ+qz`(`8ptgpA55o5G4PnqWFfuk^aCHQ;OiUR<NU-)l5P+-((ID$VG{^}c8srQR OO@ULmfUeRt<^llo>q3(N literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Kerguelen b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Kerguelen new file mode 100644 index 0000000000000000000000000000000000000000..cde4cf7ea7086a3fa3609566ff03e9425b096f36 GIT binary patch literal 165 zcmWHE%1kq2zzdjwvLMWHD>12|{{R2~jEpe#ZUGD|x&{Ue+6JZ!AtaatG~_?XG>|#C OP2{oxnro+P$^`(9>=%~+ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Mahe b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Mahe new file mode 100644 index 0000000000000000000000000000000000000000..208f9386bdad172305a48f6ab7e70ac3e1ca0e1e GIT binary patch literal 165 zcmWHE%1kq2zzdjwvLMXSS<l{5|NsAgMn(n(<3Auh77h$7KE5Fg+6E>JAtaatG~_?X SG>{p%P2{oxnro+P!UX{Gdl_K> literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Maldives b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Maldives new file mode 100644 index 0000000000000000000000000000000000000000..7c839cfa9bd62842cf23f01d5195b239bc5a437c GIT binary patch literal 199 zcmWHE%1kq2zzdjxvLMXU03_b(AD&VF|NnnRCME_3mlr@05Xr*8;1<BZ;o}>^;0wgs l2Br)lBp3`d?|;~~`4S)+WC6(3dLWyiC0sT@tL$`5xd3Z|CHMdU literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Mauritius b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Mauritius new file mode 100644 index 0000000000000000000000000000000000000000..17f26169904928e4061e4ee58bdf7a6c62001524 GIT binary patch literal 241 zcmWHE%1kq2zzf)bvdlot(^=0tLxT0KgT(D315f5@4?NHHU#S28|34EW5Hc|^n7#m+ z;}*ck!oXnRz`)_-8^WM%U<$-03?U@g12pnK$S#m+Ap5{H&`uByvKLGP?FP}r+RtSJ KbcLO+2^Rpsttt-y literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Mayotte b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Mayotte new file mode 100644 index 0000000000000000000000000000000000000000..9dcfc19c56e62b12b730f4335b34479695f273f5 GIT binary patch literal 265 zcmWHE%1kq2zzbM`vLGzd{r}>hjqh$nY&rhm!ojy|BhKVhU14NmWM*PuP-+1gp{&8c z!oZ+qz`(`8ptgpA55o5G4PnqWFfuk^aCHQ;OiUR<NU-)l5P+-((ID$VG{^}c8srQR OO@ULmfUeRt<^llo>q3(N literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Reunion b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Reunion new file mode 100644 index 0000000000000000000000000000000000000000..dfe08313dffde345044d5053e3359f92163d3e38 GIT binary patch literal 165 zcmWHE%1kq2zzdjwvLMVc@r-3d{r~^}85tQEOu$+!92i)9d_x$t4NMq9NH7U#$bXP& RAVYAQ$YldG*G|`j3jo2r7;yjq literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Iran b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Iran new file mode 100644 index 0000000000000000000000000000000000000000..8cec5ad7de2f2c14dd4b0a6c375d7198ef7429b6 GIT binary patch literal 2582 zcmchYYfP499L66Mg&7_KDr+uXW>A2@`>OBl2?$bdK?RXRc}!GL6DS2rJfewdKnY<& ziidzg(ZV2aQb-f(1|iY#6i{Yv;wHmQ+)Ul*xi06|`jWw(_s5^>8hp8adm?8ojk6g4 z__fGP9n5D)!Sc2GT&uGlaBROEnCulWC_BJsQ0KUSC!^xE^P~{vV!Nqby`EC;!&0?- z>u&Y(>0SDjnirHuS+n%q6D_>5d+U)Kwkq!=oAg;wEque5X-nWOWwmtaQ6o~+XxHI# zOy5#5=1#P>U2jw3!Zta!evlYfHBgQ}m?tI_1nP;ITKTO`mHr72M8KR<{c4!E3iKbT zgM2Gg@YQ-L&xeUAb<<_Y(H0R}lCG!bJE&<}D&_RF@gi(VhYp{esAhyF=!l88)lAQQ zGIFS!i0a>>qm5ZAy30|<{E;nQKbs}rsC5yuj-1f5izll&x!rPZMw*zH;-=@vA5w3| zl<5T_78NV5$b}wpV$pLhda+Z!T6{lP#&tG{`1VG*q&Y$?t?ALr$~UXG_FCogoGOu! z9;Xvm-c(7k1@i5vVd9-hL*)uvu~_+1giaoONu@Ys$dr3dBDJGRzuW4s-aGB5S5?=l zw6Ya)b>UsHCaYMl-Qc0tC0>^67t9xSz3hA2_v-UlzYW7jU>)YCy<zwY!_hD%huaM> z3=v>B8-~BMd-~z;r%sDBBF)Fc$7=O4KS!I-C_LsB`R^-hc(k$}^9xG@u{Qj7EDpr# zKrD|m*9T&OAXW%si6GVpVv(e|N)XEgu}%;R1+h{PO9io35Q_z|S`f<xv0e}h2C-rg zO9ruK(p)r%RfAYIh;@TlIEa;lSUQNcgIGL>)q_|*i1mXo0E7h~OaNg62qQpP0m2Lr zc7QMhge4$M0bvUWV?bB~!W<CxfG`MzMWksG2%A6{1;Q#2W`VE^gkc~o17R8n+dvox z!a5M<fv^vRfgmg-O%p-b2*OAZR)R1Sgq<J^1z{-&Q$g4Y!dMX2f-o0^y&wz*VKE4k zNz-N!MuV^#gxMhM24Oe|%R!h9!gdhGgRmalFk>F?^q_0JH(Iu{ziGrX?7#0)$9!|& zQ0AMv?=sK0zK;2pi)(p*(9oOrR#ndawu3hIKg_?zJTr3{^Q_f_nP(>yGXH4qZr&e< z59htzubKTE-)Q!8huJg##CaR@JUbinyxY~xcl>#r_oo*EdGD;f#eV+LRQ3x>hBN<c zXDRbtTVj~+Ue(ULaA_OwJ#%7t?+qQu{=SKM?C<vsV*dH_^~{U<KlHz-=K=HLuKVnl zTutZw#aVCmzdTjRe(8}|<_C&8m><mD!MrSE2=hb9^~?{)hcW*uW;*Y$r?l`c7aQ3> z;^D~tH_uiwuW%aAyyD&s=9QgE%)f0<<bCu^H*Zz5kNv80H}=2VbDsIJoY~Ber#mvQ zUYX6jW?>fZ@1tFKpLp#g`zLL|?Ef&LoB651Y0PUK+?m(@b(neGjYGVDY_szIso@Iy zx;l>i`Z8DM4TS~FPiF-)Z(QHRyeX-X_s_8rywA)q*l!NXVE?Se%KY4mRm^{JiD%x@ zr;~ZhotwPRcdX!j;o?yCFV+{ce@V?`e)+&<=D+4=FmKItV&1mq3Eu6A+j;*s*Ps30 y!|MK*x8&n}2S57j|INF&-vqv){k*K>tUl(?=KI;tGsHI5+cL^C#4^Tevftk%?{cC5 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Israel b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Israel new file mode 100644 index 0000000000000000000000000000000000000000..1ebd0664aa29c0abd722661f761031ec0304631c GIT binary patch literal 2388 zcmd_qZ%kEn9LMqRO}t*foJ^@^$e%I_#mnWdRFaCKU?8`+F@%6)1ZE)}lgJeEm)c)U zw-&XgqFcm9rNg4O=Au^9Xd}28i&V_hACLmvX$1;P?Yz(0SnE+wdeZmq+}GLVDWA8m za6?6+{Nn<xUwF6%>)}0ASznEwjORPnc1y=ZvwV@dUv>5msW0ETB3++HNcY~I;%{k^ zuXfeR$rpRo*X6CMr!rW23q7j$T!DNW_nA5sUM8n!UX;^AemT>YBz+&I$ywti`L3-? zooo778TB>teSV$%&|aZ_OevM08Z%Y@b<1R++LZGlC)Hr|VKq3oRa~|8hU;>xKXB|9 zEvPxsKkMf|wAoQb+MJ0K+Kqdvw6OL|#@r`r{o$QgwFvEXZ{&`nT2$8i{+mh~jhiEj zz4Hn^+AXrg8y!4iM1M2jzjdhFxb2fE-k6?YZGKCHf5EYGBlZP{f8oAWhP$-I8@DaS z@MIqM$7jB3BrLA-CdR*~CC$0wPY!9&l7DUXE(&m|McocPb*xm~-ZyUC;UCfOJW`}B ze&djycIaL0uAMvdCA9~QrJGaqW!@$&J$tV#&&<_V#BP#|@G*1c^gLNPTxPBsPL|B` zqk2~7^|HEszj^oD<C48Q(9CHFRcoHxr{`8*RNj(w^B&(Rb#G;so|kk?`LY-2_su?_ z@?)>n^MBv23PNMdf}VA1?P#!B*tT31^^BPJAJC+@t=lZAOPA7Dj+$EWJXu%Qr9Y77 zl(OPh{lTz7DNlP@uW$ya^>eHB_5B0tq09ODhT|RT;j^jwBX7Q?Do^;#jnC{>Rm~~p zqvcgffA$7*)0%pDtbD@U?A|EV8GYvCGjgTIJ+9YWh?gxh&gfgZX33KmKGL@y9+hof z2ld+5LR8(6r}d|5epB1`l<5xVHB%-(0h6zjZ&RI9ozq;?T=?I7M53J5|GGq8k^qtU z9*0XLEK;V6q%L*L{QEDHf6dPE$!hD#T46nTXuXIy91gzzdJ*yci^W~FF8_m1Cy?bK z>$9~Mh^!D<BC<wgk;p2MWg_cD7K*GCSt_ztTWhh%YLVq4>$SBOjI0=0GO}i5(a5Ti zWh3iG7LKeOSvs<IWbw%Ak>%T3>*pwdtyKY}1V{~#A|O>j%7D}XDFjjpq!dUkkYXU! zK+1vC11Shn5u_xxR!xwiAXP!ig46{m3{n}SG)Qfb;vm&Q%7fGgDG*X2q(rt>jgTVQ zT2(^IgwzQs6jCXqR7kCmVj<N+%7xSmDHun^kdkrK3@MteRW+n+9Cbqq$5A<?bR4xq ziicDWDIZclq<}~TkrE;`M2d)1(bg&>Qb${>kVqwwQX;iPipfz;q?{b}L<-7LQKY0C zHARZbQB|a@NL_8M!XlMLN{iGMDK1i7q`XLdkpd$XMoP?4W2DF&RYuCpQD<AL&>WSv ywMxxVYoyp5)keyV)Eg-{{y!@oWEFm4f|dH%oJ4n$J1H(9B{nDC<4$&ag8l@yuiuRT literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Jamaica b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Jamaica new file mode 100644 index 0000000000000000000000000000000000000000..2a9b7fd52d37a1ffe9fc589daa04d88c6c71a6e0 GIT binary patch literal 482 zcmbu*F;Buk9ES0uk_c^)3WDIMQyobh+%-Uyi7q;I5!0=!3o!vT4otAP8W#r=1_s#J z{0waO1x)S}c>W(|V`9AK?l*LL-sn2%HPo-CDu1(bgL`?##rfCvsGjD7w>UqY7}q?; zo_<LE^{XzdZquFRP#50^CV1)T-RB!qx@+lj(lmQl$GXxEP4(2*`=MuQhhbdLeVPNu zi!;vF51+LQN2$%5wRSmEIcq;w8UL~qsSCO1UAbqGivCbw<s?r>eWXN!6g5cEMyW!| okUFFgsYFVVTBI1MM#_<TWC3IaWC>&qWD#T){QokpOmyOY16WpdI{*Lx literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Japan b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Japan new file mode 100644 index 0000000000000000000000000000000000000000..26f4d34d67b46513491f26c2e661c6e653cc130d GIT binary patch literal 309 zcmWHE%1kq2zyK^j5fBCeP9O%cc^ZJkbvvel>u)1J-1zaU;O1HD54YJFKHOd_`{B;B zM<4F?{Qtnr$OM5549(0y^$a}=7=fDWCNOY7NFU!21}_&N4h{iHGlFmk36A&=1gVFX r6o6=uW56`fK_D9BC=d;D7>EWr4om|b2%<rb1kq$Wlndx;T}v(iZ^UHp literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Kwajalein b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Kwajalein new file mode 100644 index 0000000000000000000000000000000000000000..1a7975fad7f7e96f7101eb3c64c9b420eeebb621 GIT binary patch literal 316 zcmWHE%1kq2zzf)cvTQ&s(Eub4zBRpY@)cLYdAG(7|J$SkbjtV~>i_@$&&b5g$im9X zz%b_lP!+?h4Gb&{3_S}NI2ah}CNS{){~zwaAi%(|;sAq)k8cQrwxJ;q8!%`aSTg7u z8Ufix3?U>q1!&{{Ix`6c5Djt?hz2<eM1!3MVgQ{7atp|bAi5qXL<MJZ*#I4D2Xr(S E0Dm)39RL6T literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Libya b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Libya new file mode 100644 index 0000000000000000000000000000000000000000..07b393bb7db14cef1e906ebe63cfbbe8cddc79d5 GIT binary patch literal 625 zcmb`@&nrYh0KoCtT?f{Wo{Q(l;<399B=szg#O_6Gtap+!4%F^xj&jiEPvGPrIXXyc z%Rvq<PFu=NqS>-3N{@?jVZM*EQs%vx@B49?`FM-@HCOyP9P_uv%;tl)i^Sd8iFF@8 zl9lyqtMa(2t3%_edRW%a*-O7=ds5o9@5=rd(5+AXe%tM`Y%d@C9p?`+R@(48_if#^ zQ?I(WUZkU@RnN+%?#*4PcsimJsj#0+j>*1>Q{T<L%Hi~=N{tls+}^I3_il>0e5n`? z1y|&!-*2qu3%3vrOPnO;gv@@MEK$d^Xq=h##8hU1#S<Aby+0iK(+mzyIXne`f)La| zP%wfT5DE$#0)~PU)BsVCC{PqE3K#{A0!P8408$VskQ7V`C<T=QOTnc8Q;;dp6l@0I N^k31VMt;zZegQ-UsTu$P literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/MET b/venv/lib/python3.8/site-packages/pytz/zoneinfo/MET new file mode 100644 index 0000000000000000000000000000000000000000..4a826bb185531c34eb37959037c68fbf08c23f71 GIT binary patch literal 2094 zcmdVaUrd#C9LMp8h?UIfiw1`T#3DlL$bU!;Qac`)$)S{!kxFPFY7xbW7?j2;=3FuN zsj-|x(u%QaMqOa7p|$>w7LwIi!*Xr8vVU`K=IqZ{{oYSqcGF!wXM0{}zpLls_jyOx zZEG&_{_(l+@6%mQ{?F*28Q9oAdHl@2sbLKa9?~;!Nc(&CXlzEC#!s!Xqb~+D@m$D0 zeyYTdJ(^>m#8U0knq|6Vuu(}*%&|**!m{=<B{$`2Ry0ksBP;B(;@^~#{i9N6f2lzH zQ3cMvskD=?=<?4FXwJJ&D*f;g%Q!e}nfvzJ++JDM_D5`9OU$m=&}dgyM=iTNY*z)# zEGHw^uAZ4@xd|cVo-5J(Z*sI?GF8{Sf03>o`9;CO@3pY+xbk{FQhxhk6*Rr9!ulyI zij7!t#i*66dD==d2du29)5@m1ZBcrk7M<8+i+}IXk|QCz{);-54>hP_bct@*xm-*8 zGqkKZTg!VE+l`e83N@wMikwplho-GE;X_qre`QstzqOU|Z`;a=F}vyH^R{aEC958P zOOf5ZR&(%K-Q3!0xAZ=y)weyaH7%P}dtHm7)m6GRP@}cM1zLN)Ky@jVR`>ZV-F|Mq zt$Xcft)EP^4F{5~e&i>+qx-Bi^i9~thDqDB;|JZj^mS{jA6HY>UfWzTtmcakX-lTG z<-0xFIvvxtu`b<pBC5MzSg)23+U%ZP6>1%-wR^W_>Asz%*0#FbV$A`&zi_U#hkvyP zl0EClPf^F2udOrbygHA)XI-bK^x&&Q_Rz$rw(osMJBA1JaMz%^cXun!yCD9*@bkPR z^AbESV_uxQwtu}jiG*vTUL+iKhjDSye{u2ua1WQ?*9`y}0Wt(+49FmmQ6R%W#(@k3 z83{5JWGu*F+y{D$1{n@A9%Mksh>#&6V?qXnj0zbRGA>^?Fl1!N(2%hqgF{A#3=bI} zGC*X6$Pke+B7;Omi3}4NCo)i9H&SG%$XJoVBBMoyi;Nc;Ffw9f$jF$HK_jC^hK-CH z8Mv<-IWlx#H+E$3$mo&bBjZN`fJ6WZ0TKfw2uKu=Fd%V20)a#V35BnV1riKj7Y!sF zNIZ~$AQ3@Ag2V&~3KA70EJ$3Cz#x%9LgVXVg9OLdMF$BF5+5W$NQ96OAu&RNghUAm z6A~vRP)MYZP$98Gg5~R?g@g-<7ZNZeVo1o4m?1$!qK1SGi5n6)ByvdTkk}!?^L5cf u!sqMahXfFbAQD0(hDZ>RDB}MvjESz03kzvwFjAaXnpY5v6c%89apIpo*$oZ= literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/MST b/venv/lib/python3.8/site-packages/pytz/zoneinfo/MST new file mode 100644 index 0000000000000000000000000000000000000000..c93a58eee8b32f672fd3a96ca3e6ada5b0a0e168 GIT binary patch literal 114 lcmWHE%1kq2AP5+NDp>yipF4qp!8bUBA%rYlTtKbnTmW*V4CVj; literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/MST7MDT b/venv/lib/python3.8/site-packages/pytz/zoneinfo/MST7MDT new file mode 100644 index 0000000000000000000000000000000000000000..4506a6e150dfd73884811c8c0f5a0e21dc76a756 GIT binary patch literal 2310 zcmdtiYfRO39LMn=s39jVzb+U8nrTT8AfP9K%*Y@@Ize~@G{PwG>}UmEI%y&P42to< z`CS>aOoDFKnt5Hbv7xTv+REl|Yg!AtUo0D4wpd(FzxU6FJ?dHOd-ngo{yWb<Z~w~R z>Rk1Yn_~ar;hwh--@5ya0(rSF%Je*wBE2vEXg=(Wk-<5CG!ND%s=r1a)1yDssIjxv zdi;X|HE}dwhu=(5YFDz3=$KHEkB{p~>ypgm`sp&IV$57tI4V)uLndmwSEBWC6TR=C z_6)ybF8`ueV$K~?vB%pa?!8_W|5lIIFSMyEI-k;4Zf;ap1sn9$D@s&C>79C7eww-_ z?M9tAyVy*R_UNR@RFm}ETuJ^a+N2Cll^G{~GBXcekZXHSnOUJ3`nqlV&Ftl2J!j2F z>U!^&`i7<NsJRL6>(q2nsT1cV&9h#m4V{qm3x0J||ErR5rrBh6KP_2@E6u#tfMh?n zz~ltlb?$~~W`4<Py`XZ$cvJ7vH|Kt87DlD(yyQPs-uE#&fApLxIQfgd<+DDu=zvFV z?c1Xk@Az46+r3p4HhnC&x9>Jf$`8mL4O>jnyl17jXq74ceL$CFwy2Ubdv$4Sohm)t zsh3_XRAn!{E_Z)YYkVyoa?iVqO?holD!OKwdl!{SWhl}tOUV@f@^6fPEMBU-Cr#D2 z8M<cX*Q#b9POq34P%B>>*7ptVRkiJd`u_e-Ro8Gtuj*c_9`K!(`i>6sVCErtC=fIa zu{)))q|7v43`rn0(*#b{NH8ki1osuln(ux!YrCrT!>8laBcXi#=>B2VRF$locMPg^ z-f_LY>4@5pa9(dL?@}8lMkSPY$b^PImraQ~&8GfivUwzAp6KqCC(qWHmew}ea<ss- z)-}r3T`49)MX1P0_Vr)-g~NM9O%8|O?uk(DJ=MKqF8%K-@+;pm`&8Sf!p}q^F1`H! zVoYIs3<?<)GAv|V$iR@1IqlGpu_1#)Mu!X!-T3%mfSes6Fhq_qB7;Omi3}4NCo)i{ z9Vs$YryVOYSY))wa5=_{447lY$dEb4j0~D%)X1<o#*GY|W8}!tk+CC#ciPb-!$-!C z1OSNu5&|R!NDz=HAYtH$0}=?1NFbqb+E^gLaN1}f;oyh|5)dRJNJx;FAVEQ*f`kQ$ z3lbP4GDv8U*dW1i+UOwR;fN0sAdUzjA>xP;5+sf&Az?z|gaitS6cQ?@jTI6sr;Qd8 zE~kwb5-^U4At6Izh6D|X8WJ`nZb;ye$RVL~+Snn%bK2-3;d9#fApzuwAQD237$QOB zh$0e3jyNKLL?VfV5{V@eOs9<|5>BU$ClXMnjVKaQB&JAEIiiY$l_Rc5U^ya-gq9<= zNN}Atx=47PHoi!Joi@Tqh>;j0K}MpCgc*r5{_g_qvE5#1`<>yNpOu@Ho#D&L$;!#f G_WTVQwMumW literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Mexico/BajaNorte b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Mexico/BajaNorte new file mode 100644 index 0000000000000000000000000000000000000000..ada6bf78b2815d3d99c97d521ab9a6b35c8af8c3 GIT binary patch literal 2342 zcmdtiUrg0y9LMn=gpw%wq@u(hds2#laOA%z_Rpvz$O)7qi5Z#kXHW)-p%f81w$_^C ziw?_G^yKV<wIXJb{bS^oTWhSsR+x=3Q(zcHtQD2x^t^vvcGX?$clJE5-_G6d;`8?J zsIE+N{_)JU|8RIZ?BPA~wccM_x*7}Xx~H3_dMnH8-i=ny>9Fak&n6DH46gd6Zt(c~ zb>BpnIz#PmPhD)@EZ^sCl}lyGaycPGM!orJZ1EN~9-pMfr_<F$=t4Cy7@@9=PN^Sy zep8cY2i1@5=hgg?ZnNP0fC}$#Hw)kER*Smc)arP<y6#!giyQ0JlIp#BY3Vi<k>}UT z)~!{`6S8#V%3`^GUZjo+&XlO>3=@5Exx@@EGqE54E-QLw%nh$z5Z$m^-+1sNSy>XU zSJiy0;xd2IH|2k*ZjSg;$0v5G_}NL55Z0m+hCern6T8*wz8;fwu33^hj~dUZU9zV6 zag%a%qoh_H(P{N@lJ4E7Gm7U*W_*dxN*kB8q1ie+W{%1pi_+`<98>GhUe!4lK2;mu ziZr);@VdIS?GJO?i-*<iwcnXLTDxRpVV}9P{5i>8W6WK-d*tp#hm1F_P`op*=)90r z$s0PT^Dixt%`crY1z*>Quc^b_(_0{gJNKKSV;<SEq10?`P*NO|WBl8u#eX%{lw^J- zC70Lh?JIs(+dqlXrL*VMj+3+czTtP&&ejoqf8X<}to)3AptDi!@(r5@pXrd@$^GV` zs{K+Pe!^6EOQmA6)l|jjNYy~4sSb^m>Nhr-n$dtfe5^u0@<oi=)8N&QcF(HXk_27X zHliNOny>fPo>BD?lX_p_NwqI9&opHBOT+LLb0G4B9OxS`jWezCL}#~oa;Q?8n%m7& zr#DG+S-pAsg+vJo4hp^|IAo5!{yV=w;7Ebv1OhLM6A}otwK&)E9<;!{m3uEO@cA8I zvEM1;<l1wuJw<*7<2XTo-~N9wu7G_Q7&0<sXvo-*!6BnVhKG#L)eaCDAu>c{jL0C7 zQ6j@c#)%9R8L6usDl%4AJ6L42$Z(PIA_L~j88I?sWX#B*kx?VVM#hZ{92q$>bY$$v z;E~ZI!$-!C1i;ls00{vS10)DY6p%0=aX<orL;?u~5(^|4NHmaexY~Fi0dchvK|+GW z1PKZf6(lT3T#&#ZkwHR(#0Cit5*;KwNPLh0x!MRJAwpt=1PO@}5+)>0NT85NA)!KI zg#-(U77{KbUP!=PZN!j}x!RZ^K|`X3gbj%s5;!DsNa&E*A;CkUhlJ17#t#XgtBoKM zLRT9@B#1~9kuV~0L;{IK5(y;|OC*>`G?8#3@k9dZY9oq-)YZlm3974&DiT&Cu1H{! z$ReRdVv7V9i7paeB)&+1U2TMs5WCtKBSChxQAWay#2E=R5@{sVNUZUHAM7w&^K4u5 UBwxBG&6ASkOHK8pdQ!sv0^LWd&Hw-a literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Mexico/BajaSur b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Mexico/BajaSur new file mode 100644 index 0000000000000000000000000000000000000000..e4a785743d75f939c3e4798ebe7c79d38e4cfd08 GIT binary patch literal 1526 zcmd6mduUH#9EZPSF0IvGatV=GiPmn+W@hYSGxpoYew!J#-)4R@cC}d>w!LL3a(Smj z%}^pNZHZYf<uAE}keW#?$(EEgEko-#&+)(Vhw^!Q&vQEG-{*1XmUzSEkK1bh9dF+$ z7rO>3JBG^py1dz*TL~{c-Tq5G-J=HwpM0wF^t9X<6sgo<#my?bdYWFG>{UxPjOd63 zYt+*4UL84Mk&2r2O``h!)v}*&BzkzVS>E+RVmkfIiaTu*d;GIm+1ezlDxR6R=2jh_ z-f0qw8gydF39~veUnd3BnB>4XojlT_Qhev@l%8s}_QN>6t~*PmKAk77(~&Ceny;kS z%}^OfKFa!n2(zK|p=8EQH}2G{k~R0c$qqUq8|AIZnR;30^xZR?h7ar9`{&H&*QI*P zmAh)|%`}~N=&Z^=8LB-cS`{?9q%fsWZOaRhqJ@cSd+a3fPWG7M*<Yo2DBkQCeJv#~ z1I^BNw`AA#@uu{_D_zzyV9GDu)D=~aP36H;x+=F{?e^B|>gY$RCTX+YGqYXQhSW*z zkE5zCAXn;oD^&fL7}<M!z1sJDj_kisW*Ry~8V{tKrep8LXN+^k`uP5XV_9cnL@cY# zh_7X}pO=Z2bzF--?>_4H_f(f#T$yf3uy2NaU5RdS|AjP`J;Z^?0}%)!5kw@1woDMA z;BTprvr_X!E{I?d$snRZWP=C?kq#oBLt8$GfD8#CA~Ixz2+5EVA|^vlh@cQjA)-QL zg$N6g79y@gTV9C34sD4cB12?`2+fchA~r*Ah~Ny#A)+&6hX~J*9wI(Nen<cg?Fb+t zKw^Ld0f_<<1|$whAdpBPp)g{B1jC315)LCCNI(wlh#(;`VuA$4hzb%GBrZr`kjNmR zL1Kdh2Z;_69wa_UfDY{lAt5@nV}u0Bh!PSeBTh)5j7Z^s8>*jOZlqmokZVbBSa4{N MD=aiPA~@9V7s`x}c>n+a literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Mexico/General b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Mexico/General new file mode 100644 index 0000000000000000000000000000000000000000..e7fb6f2953d123efbc2550f450decd794b017d4f GIT binary patch literal 1584 zcmd6m*-Mo{07pkNDie&#9$G*m5W&p7va(E5OmA-2B`dv}Ub9R`EwQp3Pz0e&AEHHs zDB38p9x}}yBv3FC!-&dAE)*g4&=g40_BH4G1A?H3e#6Z9;CnsCSy17Q5Pw{W`8(U( z#aDW#WY3o>Pp>=Ibw6R;)#n%E>igNMhbHg1hR;T2jO2XwjC^>LG3Gt&8M~jGF>yY? z^SZwIX?S_Ph^U(@Ba`z*RMrO>9TY2KBA&>#bC!#B%ck_Y_rJvY?~irtw2#`*`$%u> z`JpxqwClLjlWKF9)LW_tReZ}Sxi$TgN+_+CiECQaw!}=C<nLC=t0HCcOtVPw36Lo- z%f$A#Uu9}vvPc_Uq#fsi#g1FkI=x}O$T;~zXBG#ktjd0!9Y0Sw)4Fs{;764ka$M($ zQI#KXLFRjU)XwQfSuohCc0DhYyKmeUd+u$Kg>4<8=*&v#s;CvkC*pKTic{<@4AiB; zF`_KaTe}x#sqz)?borMkweRP!t{7jU_P@EV58RzmmBT~wVCRIYx_V7k*F03RwN2I( zyb`tU1F|l5KpaYP$iqv!Mg5uzUH`2~H2A0LhKXWv<kM<>^g)6+Hs-GzFBhrfw?FF> z&GD+K{h9Xi=FBq3$A0<xx5u(B`w3xL-5tWmvTj}!b1kd?j+dYPE=Y4Yg(KT361a)x z<~fD)FFdl$a0%iQ#3_hZ5Vvd^zaWl5JcGDq)A$B)&ZhAW;vU35?8ZTchY%MTK0=&i zcnNWn;ipaGD8o~Ts}Nry&O*F}xC`+Y;xNQxh|3V4Ax=ZQhPVy!+oo}x;kixYI>UE} z^9=7H?lb&{G{EQp(gLIhNE47QAZ<YUfHVT>#HMKl(hH;+NH>sn82vyRVsr#)iP00J zDMnY2witau8iRCZ)3gTZ4bmK>J4kzw{vZuPI)t<c=@HT-qf1Dej6NZaGCH+sT4nTV t(=^NI7Sb-GUr57{jv+0>|Fvgd6L*Y>JH!zc8Xg)J;s_55jSda-{SB~`;=}*| literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/NZ b/venv/lib/python3.8/site-packages/pytz/zoneinfo/NZ new file mode 100644 index 0000000000000000000000000000000000000000..6575fdce31183d8238b18f2f30ab5b9227c7071c GIT binary patch literal 2437 zcmd_rdrXye9LMqJpwhVKWemws!@O`gTvUW2LIninl6fRN8GVz42MwVlp$lXgnPXVf zmaRD|$pO<6kpwLTF@#zdvNfreebbp|D>PSA%fg=bv;M3<`l~;Bp6&Pg?QG|tvwhyj z<t{CbH~#jy;jd43T5=!1(K^~X+CBT1ZZ2rAK4%_ScuqPB`ptL3`{iI_tJyiKRk}jz z&8{E&^w8BZ^YBN_`tDGk`QBNN9(nt+=jibdwR`K3r>AMJ9$R<V)4OS_9?#wBdB3Pa z`<%6&6WI;YA1I!IsB#&&Qe&R{>eW=AkU!LC?{4+IxLf=he^>vZV;WF<S_8Y9G^nsg zZ+xXr$ENJkan&U{KI~bYP>`h)Mv65!F;auiZ<3IynG({!T0$KW656~-Zu-t&CT*T2 zH}_nSuo6F+{Q96w$rzTY8{6fUSRV~9{Y0k){h+rx9Wvc(fzAjxD>Kea)0xA4GOO2H zBR+1H$UWf__0|@Nt{)@LhP4v2=Dfs~<w)G(4<tUnRA)!*kvR!VbgplMBm_rm!q2Tb z?{bhPeqOIhUtH4L4wUKb-GP$4Jx}jw{7F*Q$LXE5Cna@duFNm&kOj%HvM}XkNt-lI z(!;7H{n{^*G2)g*SL!tLbh2cfD$&J9!(>TkmS#5^lCvXHb8F5>UR8kJRXn0gB|`4b zP+gYlFRtmmx_t5l$@hL!^RExeJ>Ng41>d&IiW8=~yI+!f_tnYDmNvcbg%T-zew*H3 zo+V;d>H~R^vMMuQi(&%g!I_D=I`E<tk6kXsSN*i)(mXLw4QuIV6J<^3r@FT7nmn{) zzm~oDjjXHMuH_ZoQXy^f@QSbXk<@LnKIw>7PN|efC%&c|jC|Sf>(g4LiBkP#kv`TF zDvuvZ*C$#N^vPYTq-INq);^OaPno}|m&0q+KfT_g$NZ<SVKfa{b1?P|I7S=B8(oHv zVYKvcKRD<J<Zf7Z&g>kQk?UT@Vc*hRe9v$=4A;Nd-gWDl-<jQlY!KNYvPEQ%$R?3p zBHKjviEPx?+9|SCWUt6(k=-KOMfQtq7}+thWn|CDrjcDE+eY?{Y#iCSt+jPz@BB1u z-qzYZvVCO#NCS`#AT2<8fHVQ=0@4Pg4@e_ytxh1Vu(f)DG{e^F2GR~&s~<>1kd7cN zL3)BT1?dXX7NjpoW01}utwDN&G{@HJ4$>Z^KS+a+4k0Z<dW19y=@QZ=q)$krkWL}3 zLVATX%hu`^(k`T5NW+khAuU6ChBOW78qzkTZ%E^i&LOQsdWSU6*6JS8KBRw01Cb6Q zEkt^VG!f|{(nh3@NF$L>BCSMvi8K@GCelt@tDi_ik&YrQMS6-f73nI{R-~^;W0B4x ztwnl^G#BYE(q5#$wpN3Y4kIl_dW<v~=`zx0q|ZpBkxnD6MtY4j8|gOEZlvEx!)>jO zBP~aIjx-(VI?{He??~g3&g1`~^}hTCM90PFy3<@yIZ4jB&e*7&InFp|Y|L!mKLIzD B3|asH literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/NZ-CHAT b/venv/lib/python3.8/site-packages/pytz/zoneinfo/NZ-CHAT new file mode 100644 index 0000000000000000000000000000000000000000..c00410988272dec2ae70ede88720b4a46146a4d1 GIT binary patch literal 2068 zcmdVaYfRO39LMqhA$8-f<`|Nprg`CTJBN#4L}-AZAYJgJMD$7X9MDKh61s?HQaR^p z+O$X1EN2c|q;1qzfo|1$P?@dSW!X2|@<Bs$wQd@x-}_$=d(xxUIot2`Kj+EW*?ymQ zb4y1w?ET|w{NLYhck-OE%^jz{*!N~)<{y@L<e(*8IH=_Q%a-!laZBwzV`;CyVCiim zHu2d$n^bwgCileb%IqCBWo5lh8H-v*S<o`hJ*Lc=b;^8it+E0+$~v?}SACPBX-~}8 z)g$MX9ZS~q=TB-z?WksMJF0666Kz(<hc-L?d%HG2pg9SPZEotfntOJ(%^Q73^G{5$ zoDU8uI511OFYi>|uJOv>y<P?D&Z)4oQK6;pD;(*tqMQL0moBrCq}?jb$g|QP58HyD z)2-~2T~_|-MO%2R)2<s%Q^npUyT1PiRc;E|4ZWvS)w*1Z+FsM*ibCC3xlh&8CaWg9 zM>UszQteoami*FZb!RG6e>!GM-_F*up?YiR_tdyQXv?>pRa1AW-4q?Oo0X$mYRzt~ zN>THi6SiXdc||6?Xp#6y-S*w%w({$vTJ>(bwG2O_+h6HZ>q~=n$5S!2J-Ns3+)yvI zciCM{L9MQf*qVY=-94|&)}~!hbkYh%e@(X7#RY0VJ!%~vPu04ik8J(mCEc_CRqK5E zE8W|@*EVb%)<zBLzExk^{Z)Iksr)VLn$e{Praotzy@)pd_NaARnR-57V-JpG>7h4j z?BT<u_Q-+N+Ojj#dbd|=Yy0oEH6D)##wA?wpS}}3Z{V`KjNXxIZ=B~HZw(}Q-mwO6 z;$LS&W3v|wg+nFoEGp&<yVLUm0k8RATzB_R<BNu>cOciEALQ!$y6cZj0GR<Y1!NA$ zB#>Dk(?I5dOaz$;G8JDp7i2QNZZ^nteBFGI3HiDiAyY!;giH#V6*4VkUdY6dnITg{ z=7vlTnH@4cUpGHwg2)V!DI#-3CW*`vnI<w%WTMDSk*OkcMJ9{P7MZTEn=dk9WX8yp zkvSuiMrMsn8<{sUab)Jm)RDO(lSgKcOyAedA4vd`0VD-T4v-`uSwPZ&<N-+pk_jXg zNG_0MAlX3Df#d^8h_A~Ck`g2*NK%ljAZbDJf+PmX43ZioH%M}j>>%ku@`EG@$&jy0 z5t1V$Nl2EEG$DCH5`|<6NfnYSBw0wdkaQvWLK22#3`v=<%Nde1Bx^|8kh~#@Lo$b? z4#^#oJYUy<|8e$`D*Ogk=7quwi%Z-Gm&MB5#`64<{K5jh%55yp54q<e_nh=6i{2Jl literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Navajo b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Navajo new file mode 100644 index 0000000000000000000000000000000000000000..5fbe26b1d93d1acb2561c390c1e097d07f1a262e GIT binary patch literal 2444 zcmdtjeN5F=9LMnkqQH%ZQ;8v<nU)CgtR#>b6-0<P2(NH8!YHnHS1a(Ln-=0RD8?U+ zvtrCL36!+fOng|gv7xTv+REl|Yg!BKxhxw!Y?8peo%dPwPk;4STVM9OuOIjS&-=Po z`_|@&f812_4G-6C9^R)b{@GWcUmFNlJ<liU-dDa?dprTXw{@E6E54}vI`*j#+N1RF zyx$s!>*B?gOursm&?$b8b?d7UesOi|Njd(VTTGm*mXq%nh`_OY8GIv2h@FWtq%9yq zpPH0YHYBL9x|w=v#e|wxIIhF9MpXC<xjIswP>}}?Nyq3Ob<M?I9d-V=h(6JxW8Uo* zv2XTB`ErZ6w*6Uo-Bypd-d8WDuPPC7rT5Ai`6=Rtlm#+=Zn2sf>5vJb$tvNO`8x57 zNR>1kp=X`^LCrpNN#EFeTFvp#k~i%*sOGK=%6aQP6gTI7E^k@(wwNFHo=i^FA~|qD zr#Lo>l#!D<^^!~6I=EM-oo!U<-OuTaBb6$%*{ic&TBNeQtuklR47IRitz1+&rgD?- zlegu3q85jz%DluYBJbNMnLmDB6rB1=-u~%;Skmv%cMR+nOFMqlckbFQ3L8GsceU<P zcbE6;d+N8TqRba{anTx8{Ogb`NpBJ*XZOp}=vq;Fq+Kq%Tqw$3eO)jAxJEgf+VuVJ zELG(-K3&l@M?J8lOjr6t)rzEa?OOSja!thQs@zkm>gzP=p8ch855>q;fg!QFZ&W@w zvR~A+4$FrI+eK~tQMsmjy?EGpM%T5qsYlWe>qoslRUh4{JtbwzbJ?%G$?3{_+O2)z zvC4O#K(G7eXSKeoT0V9rMm+A%mrooV6%AF1vaw@WY{;FI8yk*_O>r0G=JGDFIWVsM zd54vM<TJe`zEf=(Jg&En`PI|iz51DRZq?M>qPHC@P|dX-y?tkr3Jv-5Z%WwTuYY~@ z-y00>?i3;ze5)rU%)Dz6Vc(<dr(EuI31^XcR+y*SJQXgpA|XQThwERgFKDhdEUF(_ zA+khdjmRRARU*qo)@d~hMOKO|)oRv?EEZWUvRq`nR<mGa#mJJ8HKScLFRYp~%LdlX zv2bMN$kLIuBa25?Z#BzD)^9ZhKq`Qg0I2~-5s)fylmV#&M<I|(aFhb61xGQEYH*YT zsRvRJq#{;R5~L<bQIM)2WkKqK6b7jbQW~T-9K}JZ!%-fjK2}p8q(W9xBBVwfMMA2C zlnJR5QYfTSNU4xoA;m(fg_H}a7g8{!VpdZ!q-GpNL#oD6Hl%JGg+nUGQ97h{Nb!*B zA>~8rXEg;xDrhw&L~3X?MMSE|QAVVWNFk9*BBexXi4+s5CQ?qMo>o&(q@q?+QlzF< zQ&gm?9A!o7%28OPvK*yFYRgevq`F9Xk@_M9Mk;JIB}Qs&HAP0MY&B&@>WmZ`sWeBa zky>*U8>u!&xsiHv6db9z)s!5mxz!XMsk+sa9jQA~c%<@3>5<wa#mE15^&RHNV6pj8 VNOLaC$jQh`b7p5}WM^bK{s0D?lEVN1 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/PRC b/venv/lib/python3.8/site-packages/pytz/zoneinfo/PRC new file mode 100644 index 0000000000000000000000000000000000000000..91f6f8bc2e234bafd484146986bdb289082c3588 GIT binary patch literal 561 zcmbu*zb^w}9LMo*sb7uZVlR)P+QDKF36WCLNNV90hMH8mol%_2lQ6N|X0Wt&|A0ig zYPz+k{ufWWnRwpMAJ9ZRm*-x?E%$l*C$;LT3_WT4b=2NzZC~|=C*8PAnz!SMZcTj$ zt?sL|$L>r!EJ$Z#%XIIr^!v`U`Pj?IXSr#5n@#x|uLk|}K=-#pGy8I==4y|zif-%k z``2;iyrCBIr}1LxMlH>RUUvCRWd{{6H&If#PQe>V40%K@diI|riW5nZK+9zLz?b5# zy+^+If0*`TPqbFdBNLIC$W&ym(@sWaJMDC2K9T^*fTTcjAW4ucNE)Zj!x|DHnUGXS cE+iR}4M~UOLlQb|MkJ;4e>qdO>B@TQ7g9&Lh5!Hn literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/PST8PDT b/venv/lib/python3.8/site-packages/pytz/zoneinfo/PST8PDT new file mode 100644 index 0000000000000000000000000000000000000000..99d246baa35cb9c6f56d50adbec163452e2a47fa GIT binary patch literal 2310 zcmdtieN5F=9LMnsio{c$9#A5%lbUo9u7H9l_MqY}m<Y!8CT1qa!ypY6LMS6!tg_}f z<WPIMeRZzonxSJhn?>YSt2KIn)+`%iZKbPNWo?nty`A^*&;IJa*17wg*KfbS?mwS* zU|mC9p64GY#(v@9^w@`Y6?(NqUOAO)<jG7q_`)CN<K3w;H1qeZL)Ej@#qlTfrSo-a z;!Lgn>%$TiKIzwy*D{sofLBL7ov5PQ67-~Px0uP*84|NP-b`5%C$Tv{nb<wcBu;%| z;*P$n<9|735=MI^@vA|VG|(+qzSXO)I`W2A&v&b<cN=|8d$YQ>VY|MrYK=-R4d|&0 z7pQ680-Z9W(p(>xqEn;uP3ndDa>KXNOxn;?Nq_H8GyV9u+<5S;(XDgzO^?50W(1S; z%*L<Pto)z#%`4tkvy(s98JQuK5grq7{4V7k`BXB0*rew4AD67*4wD_)E55#sW^Ttr zlCyWI$*q4*=QYnV^ZYG(e&rOCpApmrdFRc7*g{>H7NZK!rRs&3&Z$KoOz5JsAF0L1 zQsmZCudCa-F3RmM?ooF%eIrXckC>(9{j#j)SyMb$WO?xxv;4PV?azKj`G-&F(xlC* zv~Ry&F}6zG`BI;({Ib!M?d*|NZ>}`u>vu@SKA%~=xJvG7Ri-knNCImvn7~B31oOWz z!S5F7wbOr9Yu``PRpDW^?r>P&Gjc+$?;O?l_U~64YEJ9>LhWi}*@#p>)nhhg56J!X zJ4{W|A*uCOncA^Vsm~}f^@DZN5Swlqj+RK{_Yw2JzFNKcvoy7()vq7y4XdW0S8wea zRoe;@^!BFHsyTT~x0D}NEs;2BEgUedBR@)8$|2L%KPc_vo#x?CuRL<5&g|^ymPb#P zn2rt2^4Nh)6Xl8WL{GBUf9V&AbnWs?jznIzf6v`lxI6Lk_ln|xr=rq6ciX2Tz(k@h zUx9xyrieWZ3K<nLEM#2Bz>twS?a+|1A%jCkhYSzh_;_J}96Lf_h{za`K_a6>hKY<5 z8K~2a6d9`1juja!GFoJ~$as+fBO^wJjEor>G%{*r*vPn%fg>YFhK`IK8NAbu9vMC| zek1@$1dtFQF+hTVL;(o{5(gv@NF<O@IBhJDU^s0wkZ>UJKmvk91PKWe6C@}|RFJSB zaX|uuL<R{B5*s8qP8%I0JV<<y03i`VLWIN!2@(<|Buq%0kU$}kLPF)Vu|k67w9!Js z<+Sla0)|8k2^kVIBxp#~kgy?fLjs3H4hfyp#tsRd(?$;opVP(<2_O<dB!ox|ksu;b zM8b%~5eXy`NhFj=ERkS3Z8VW^I&D0WfI4kNk&q%WMS_Y%6$vX6S0u1VWRcJ!u|<OG zw9!Sv>$LGj0_?OAMna6l7zr{GWhBf<obi7b=y==hLfh}GvU$EdUrtt8ZmuuamlOXt D9#L8< literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Apia b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Apia new file mode 100644 index 0000000000000000000000000000000000000000..dab1f3f602b297cff53222906fe7c20230587395 GIT binary patch literal 1097 zcmc)I&u`0d9LMobt*fML35UgY;e_bc?W;wX%(4SA$+`_)*|5EJ)^&btW3~D<LqdoH zMzZ5X960%MAPzDSkvMHmf{1q<+z>avKR(a?0TM3Se7=t+J$%3UzMiSBf$U22$4`U% zcdk2CC*9?8=@0WN6HK&BE%TF;5p5lNC#^p(Tx%<oX?ymUZju$Ud4uYfrumXu`dB*_ zf0T6ShNkVTY<+)Lx4pe9olkSxHGNgK-##NdZu+|OV!w2so6w%2jUu_c?rMujra7&> zwPmt<c|!ZjKS_2$hh)FZ)BewEB=_Qj4m_`vJ@;pHum4^4P2SP{m)^)=;ff9oPs_0Q za-j3I9&DPBk@|<4Uy_$Yl~X!u(lYw>lom80hhO&Ukw;Z>^uc;Pc5AgBzn+n?^NaMv z>2)%m`=;a8+Q6J(Nw6eT`VZfbF}{0U*7mq}W^H$~30gZMfv~lG?WWwAd$VStF;6s5 z(UMG=8qbT>xhuyr5ijOW+@$_u8~3<&aP2d9FKgKd*~#7BuobcwvRP5L8?qg;AF?5` zBeEs3C$cHBYf-l?vM;hRvNN(ZvNy6hvOBUpvOm%Q(gD%}(gV^2(go5+QP&632+|4C z3epSG4AKqK4$=?O5YiFS64DdW6w(#a7SdNy*BH_n(i+km(j3wq(jL+u(jd}dQMcv) hZZX{8s%)(BV$OJDb+SIXDq2??t4_wFp8F9G{{{?RF~k4> literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Auckland b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Auckland new file mode 100644 index 0000000000000000000000000000000000000000..6575fdce31183d8238b18f2f30ab5b9227c7071c GIT binary patch literal 2437 zcmd_rdrXye9LMqJpwhVKWemws!@O`gTvUW2LIninl6fRN8GVz42MwVlp$lXgnPXVf zmaRD|$pO<6kpwLTF@#zdvNfreebbp|D>PSA%fg=bv;M3<`l~;Bp6&Pg?QG|tvwhyj z<t{CbH~#jy;jd43T5=!1(K^~X+CBT1ZZ2rAK4%_ScuqPB`ptL3`{iI_tJyiKRk}jz z&8{E&^w8BZ^YBN_`tDGk`QBNN9(nt+=jibdwR`K3r>AMJ9$R<V)4OS_9?#wBdB3Pa z`<%6&6WI;YA1I!IsB#&&Qe&R{>eW=AkU!LC?{4+IxLf=he^>vZV;WF<S_8Y9G^nsg zZ+xXr$ENJkan&U{KI~bYP>`h)Mv65!F;auiZ<3IynG({!T0$KW656~-Zu-t&CT*T2 zH}_nSuo6F+{Q96w$rzTY8{6fUSRV~9{Y0k){h+rx9Wvc(fzAjxD>Kea)0xA4GOO2H zBR+1H$UWf__0|@Nt{)@LhP4v2=Dfs~<w)G(4<tUnRA)!*kvR!VbgplMBm_rm!q2Tb z?{bhPeqOIhUtH4L4wUKb-GP$4Jx}jw{7F*Q$LXE5Cna@duFNm&kOj%HvM}XkNt-lI z(!;7H{n{^*G2)g*SL!tLbh2cfD$&J9!(>TkmS#5^lCvXHb8F5>UR8kJRXn0gB|`4b zP+gYlFRtmmx_t5l$@hL!^RExeJ>Ng41>d&IiW8=~yI+!f_tnYDmNvcbg%T-zew*H3 zo+V;d>H~R^vMMuQi(&%g!I_D=I`E<tk6kXsSN*i)(mXLw4QuIV6J<^3r@FT7nmn{) zzm~oDjjXHMuH_ZoQXy^f@QSbXk<@LnKIw>7PN|efC%&c|jC|Sf>(g4LiBkP#kv`TF zDvuvZ*C$#N^vPYTq-INq);^OaPno}|m&0q+KfT_g$NZ<SVKfa{b1?P|I7S=B8(oHv zVYKvcKRD<J<Zf7Z&g>kQk?UT@Vc*hRe9v$=4A;Nd-gWDl-<jQlY!KNYvPEQ%$R?3p zBHKjviEPx?+9|SCWUt6(k=-KOMfQtq7}+thWn|CDrjcDE+eY?{Y#iCSt+jPz@BB1u z-qzYZvVCO#NCS`#AT2<8fHVQ=0@4Pg4@e_ytxh1Vu(f)DG{e^F2GR~&s~<>1kd7cN zL3)BT1?dXX7NjpoW01}utwDN&G{@HJ4$>Z^KS+a+4k0Z<dW19y=@QZ=q)$krkWL}3 zLVATX%hu`^(k`T5NW+khAuU6ChBOW78qzkTZ%E^i&LOQsdWSU6*6JS8KBRw01Cb6Q zEkt^VG!f|{(nh3@NF$L>BCSMvi8K@GCelt@tDi_ik&YrQMS6-f73nI{R-~^;W0B4x ztwnl^G#BYE(q5#$wpN3Y4kIl_dW<v~=`zx0q|ZpBkxnD6MtY4j8|gOEZlvEx!)>jO zBP~aIjx-(VI?{He??~g3&g1`~^}hTCM90PFy3<@yIZ4jB&e*7&InFp|Y|L!mKLIzD B3|asH literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Bougainville b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Bougainville new file mode 100644 index 0000000000000000000000000000000000000000..2892d268094ea785b045e53cb441a551672aabd0 GIT binary patch literal 268 zcmWHE%1kq2zzbM`vMfL>&;TUPIGZJ0($4u1GVgjr{r~^}8JQTFnHd-+-T=xm^eg}= ztee2V!N4$U0|SqbZwQ07p#g)ofhCYOWC$T_85__TkcFZ^v;T)}3(^45MQ@i(0MQ`J zK{Ut#Ap1a$0MYe8F-9h4CKjOW5SMg*0J#L{9!{`(c){)w1i2@`7tK*zHbAG@=^7ex F0RVS6KXU*8 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Chatham b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Chatham new file mode 100644 index 0000000000000000000000000000000000000000..c00410988272dec2ae70ede88720b4a46146a4d1 GIT binary patch literal 2068 zcmdVaYfRO39LMqhA$8-f<`|Nprg`CTJBN#4L}-AZAYJgJMD$7X9MDKh61s?HQaR^p z+O$X1EN2c|q;1qzfo|1$P?@dSW!X2|@<Bs$wQd@x-}_$=d(xxUIot2`Kj+EW*?ymQ zb4y1w?ET|w{NLYhck-OE%^jz{*!N~)<{y@L<e(*8IH=_Q%a-!laZBwzV`;CyVCiim zHu2d$n^bwgCileb%IqCBWo5lh8H-v*S<o`hJ*Lc=b;^8it+E0+$~v?}SACPBX-~}8 z)g$MX9ZS~q=TB-z?WksMJF0666Kz(<hc-L?d%HG2pg9SPZEotfntOJ(%^Q73^G{5$ zoDU8uI511OFYi>|uJOv>y<P?D&Z)4oQK6;pD;(*tqMQL0moBrCq}?jb$g|QP58HyD z)2-~2T~_|-MO%2R)2<s%Q^npUyT1PiRc;E|4ZWvS)w*1Z+FsM*ibCC3xlh&8CaWg9 zM>UszQteoami*FZb!RG6e>!GM-_F*up?YiR_tdyQXv?>pRa1AW-4q?Oo0X$mYRzt~ zN>THi6SiXdc||6?Xp#6y-S*w%w({$vTJ>(bwG2O_+h6HZ>q~=n$5S!2J-Ns3+)yvI zciCM{L9MQf*qVY=-94|&)}~!hbkYh%e@(X7#RY0VJ!%~vPu04ik8J(mCEc_CRqK5E zE8W|@*EVb%)<zBLzExk^{Z)Iksr)VLn$e{Praotzy@)pd_NaARnR-57V-JpG>7h4j z?BT<u_Q-+N+Ojj#dbd|=Yy0oEH6D)##wA?wpS}}3Z{V`KjNXxIZ=B~HZw(}Q-mwO6 z;$LS&W3v|wg+nFoEGp&<yVLUm0k8RATzB_R<BNu>cOciEALQ!$y6cZj0GR<Y1!NA$ zB#>Dk(?I5dOaz$;G8JDp7i2QNZZ^nteBFGI3HiDiAyY!;giH#V6*4VkUdY6dnITg{ z=7vlTnH@4cUpGHwg2)V!DI#-3CW*`vnI<w%WTMDSk*OkcMJ9{P7MZTEn=dk9WX8yp zkvSuiMrMsn8<{sUab)Jm)RDO(lSgKcOyAedA4vd`0VD-T4v-`uSwPZ&<N-+pk_jXg zNG_0MAlX3Df#d^8h_A~Ck`g2*NK%ljAZbDJf+PmX43ZioH%M}j>>%ku@`EG@$&jy0 z5t1V$Nl2EEG$DCH5`|<6NfnYSBw0wdkaQvWLK22#3`v=<%Nde1Bx^|8kh~#@Lo$b? z4#^#oJYUy<|8e$`D*Ogk=7quwi%Z-Gm&MB5#`64<{K5jh%55yp54q<e_nh=6i{2Jl literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Chuuk b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Chuuk new file mode 100644 index 0000000000000000000000000000000000000000..07c84b7110ad9589810b916390aedc7ef498f423 GIT binary patch literal 269 zcmWHE%1kq2zzf)bvMfN%(*Pu92rhoG!1CvZldrfEE(!8|sQ>@}KO++mGXDQ>a|Wn@ zp=SX|b=?F84hY-FH-tgk(11bPz>*<^ux;!>BUpi$2Waqrk%#+DKy;m%+7=KEvK>T& qTmYg$t^m;>mw@c92eKKNn1PT9=A1qskOV$QaoGT!XQyjuzy$!|p-bif literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Easter b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Easter new file mode 100644 index 0000000000000000000000000000000000000000..cae3744096402e8a452336544edf96ca9ae5ad8d GIT binary patch literal 2233 zcmdtiT};(=9LMqh;W^+W2$|3mS{MbwkLQQ*_=_YVJxF=dBs5cpfF(pgrWD3jVzpF8 zYi_!%R{7BM3tcFi%-?#l2P@BoBU`MSbgMNPJy}}*`@R3wRqLXgF8ZJI`@jA>7w6*a zeBPmkmZn1IZ&$4Sgv0f$Jv^swwzrYvy8pLurM@(9LEIA`8>iz7@paXk2wf|YcNdtb zjBJSxEYdNKUt$xE>ew$QB<@m*zU)|7;>Ul~3470}#L+SB??0(7-#wzIG!Lt!r%svV znn5+S>99%3>Q<?@?=)8=56HAxo6NMyPMIFF+)NKIk+idOP5MxoT=i+AzIsQxTyrR( zuWkQTuG^NOGkPP{jJ60pv;3mEzV0i1L)y5?EOSieFUQoZ?|wEno_<MXoqxyN^wy}{ zJocK&e)&boIoxk%_dOxGFSMGxRjWm9-lFrXs-<9Mi!Piqri%0eU7RpamH3b7(wI|H z=1kFLAH}Kiud_|X{%_PRANWn>(<juNy%Q$TdQi>n4;#JsL%Fs2O;c6)hTK;3yqTBs zoK)uz>+0{@Wq$IYo<9+xY9_mN?a?-MNBADS;D{p&hbnaNy;xOO-)9!>Iw<v3r_G%` z+vTq8pY-C!4hbcErk9qURZ9<jYnEO4zFM~J6Vq^hzq+?gOyj<_vb?j$tk_yB_k~uN zl`YwFe~~t;YW=c0b*5R9H6d$$h%!x66IIjr483;poN6A8)GgtYs&&^Hy>4h&J<xMp zKe%I1t#90?+ct`{S3aX3Y8a4?%-7As6`j%<z14K3FOjY@>rD5BGI`|PpxN+wx;*-7 zp4s?zsoL~pvgvsxO+B_gS3ll&QT5g(>0Z}$eNhpS|M-fI`7d8FuDf%C<9PQd*FCVu z7w5XWw>yb{-4E<>>?b4QOIjEVIo0;eRwee7+EZ-*_dXx*KM4Jc&Dfv8ZP`*~zuSJh z-43!J^ftr;JL0li0``P#3fUF1Eo5KF#*m$P+N~jbLpF!(4%r^EKV*Z*4v{S)dqg&g z>=M}~vQK2A$WA@&R*}7W+RY-nMYfCV7uhhfV`R(7o{>!>yGFK+>>JrQvU5+nb!6|z z=8@ea+eh|~Gyv%U(gLIhNE47QAZ<YUfHVT>1kwtm7f3UZZg|>uApJlZf^-CF3DOg! zDM(k4wjg~$8iRBOX${gFPum=%JD#>ZNPmz9Ass?mg!Bk$64E84O-P@RMj@R-T7~oq zX_lw$7Sb+H+b^VHNXL+tAw5HyhI9>S8`3wVaY*No)_L0AA<gr&-9y@k^bctu(m|w! zNDq-FB3(q<i1ZO@B+^Nwl}Im<W_sFgBJD)_i8K`HDAH1-r$|$gt|Dzk`s!)Z@qcY> ee5LJgpv2yb13AI+-2B{<yn=$9V9}pX@xKE%a7T*( literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Efate b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Efate new file mode 100644 index 0000000000000000000000000000000000000000..d8d4093bc804be0730b5f5f530db42d55991afbf GIT binary patch literal 538 zcmb`Dy-LGS7(j1qq*8qVwQ99${Rs|fM@2qx5!%8PGU;L$L3{#HEcys;{?wt9qe!Rf z5IT1VPU`F;&MLG+{7xsKli&?E=ObLWIVafO-^-i6HK<?MtWn*}Bj=y3M)L4NlAX4U zJ$*;xt=BMp{}N5qAH&J3FFSR16K0N{?exKe%<MF6wpf$d)oVNFRb@VXVspb4$#r+_ z!pDXzz8yzPr(3f8z8QIyf>h%;cAbHQ+yA)6)Y|;WZRqHHd1r=x&!uu;JU_47H^y=F z9IxOHUV3$m8+YK>qdG!7A+8W#h%>|+;tuhLG=Ow~w1D)0G=X%1wCPd%KpH_hL0Un2 SL7Kt;?v`59j_WJFpZWoSR&+lA literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Enderbury b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Enderbury new file mode 100644 index 0000000000000000000000000000000000000000..f0b8252362b0916405ad479b9f3ac148a2527814 GIT binary patch literal 234 zcmWHE%1kq2zzbM_vLGzb03?LMSPtm3T5hQS|NlQD6EpMw|M7De82<kccVJ-o|35W= zfrEiz+XV(5AKwrLT|*-vHe}E?G-e1P!5*N||Le>{Q-Ici?E}#uJ3%z5_Hx+(ZMV}k HH0A;Td>k*g literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Fakaofo b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Fakaofo new file mode 100644 index 0000000000000000000000000000000000000000..e40307f6aab2a169bb957979f5580affb379131e GIT binary patch literal 200 zcmWHE%1kq2zzdjxvLMXU03`hW&fHM{|NnnRCZ_-Y<0}{#{{K%6U|?Zj*mi+|!^by- pLD$fbLEF%nA%p~jf#&_MGY{<mnh&-BL=$BRmkrP=J6%I#E&xI<DYF0o literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Fiji b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Fiji new file mode 100644 index 0000000000000000000000000000000000000000..e71691ee932809771920778c699c27e32ce99207 GIT binary patch literal 1077 zcmcK2&r1|>7{~E(3knOi=n#cMhi>ZH?ufV;V&~mWvBBK!*CS%GyOpwuYuk?nPu)6% z6rN%UtBVl*q|>s9k#sN&il}%9BB+DdQL62EfB%3Wq8Yxt4g<q5pLdYSp7y;zUcL5o zlb!8zyY5#zyLW5nn+@sO-yvO3-b-R<t0or0lB|7|RN;^wuDq1Ky^GpEvmpH&^E!}U z)`54Wl_2;c!LytWcD#_mxugy?f7YQ=MAJW?YbLWpkA1kO$K&7i#L|+S-1AybecU1v zT9@H#i#q&iRYu0=b)@!4M*FVnXyt~CwdZtf=7MCyNzLYGHMbVge4?ml-X`R1OIpu8 zZIkhB-8ykIEEC_FwNPA_!g5_FkFLt(!zP*PUDK)SzhrvfE1f>CQt}>X=}1j3>a1S! zZ_DLsQLi*rwR|hB<sTI-*X#9A!#~|2&%0B#|L8qlY1r&}cdOpkWGe7lqQ0G&7yQK% z_AzzV;B748v{jI0oVE_KkkeK|mO|D-7DHA;mUG&A$bwE=5n0k{Ya)v}ZB=Ahr>%=D zjI4|-jjW9<j;xL>kF1Xr;Is;m5}Z~8QiRj0K+14h9Y`Tgs{|<psRbzpsRk(rsRt>@ zX%!(QIjtt7D5q70l;yO#kiwi+8B&_lYD0=cszb^{>O%^2T7}O4USi`x>#?UT8Z-T# S)>JeaiA4^WhTk5KH~t1r+$|gc literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Funafuti b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Funafuti new file mode 100644 index 0000000000000000000000000000000000000000..ea728637ac1fa43f2d73469151c688468b34c3e3 GIT binary patch literal 166 zcmWHE%1kq2zzdjwvLMXS03_=F|Nqa($iT3I1;}Aoae#rv$2WvQ+t7$1gang-hWxKH U<M{(J1GkA>Hb8UjbPbKT0Kp&`eE<Le literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Galapagos b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Galapagos new file mode 100644 index 0000000000000000000000000000000000000000..31f0921ea04cd201675b613082fb4b0b0b91941c GIT binary patch literal 238 zcmWHE%1kq2zzbM`vMfN%vu%k_gPg>X0Bv!u2ik>S0_y+&|If(G#LWEv{~DnD|NlET zFtC6~Mj*L*0RxARZwP~~fhiE1F@%s{5zyTKAj^P;GJq@u(I88~G|*xYO_JqYHb5uX HnQ;LCaeg|i literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Gambier b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Gambier new file mode 100644 index 0000000000000000000000000000000000000000..e1fc3daa55eb2bc8c5d6a78bd77a01d193a821a7 GIT binary patch literal 164 zcmWHE%1kq2zzdjwvLMVcCBTEF{{R2~jEw*PH`XvP0LcOd79Zab23-S7h7b}=0vhrk SWE#j`+$M6_0L`_t<N^T6-XRVE literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Guadalcanal b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Guadalcanal new file mode 100644 index 0000000000000000000000000000000000000000..7e9d10a100f9cbe796d99945dd60e0430dced523 GIT binary patch literal 166 zcmWHE%1kq2zzdjwvLMVc#oxH6{{R2~jEoEnQ@?=p%-X=f;^P~_plxW#5JG}UKtuk6 TOaqyL+e9uKpt*LshK5`KtEU_P literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Guam b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Guam new file mode 100644 index 0000000000000000000000000000000000000000..66490d25dff9bcc8f710b0141f1a02e64aeb32f3 GIT binary patch literal 494 zcmWHE%1kq2zzalxvaCQX+5jX@n@@dkL9g?}8}oe(@6CRE_&u9};h(*F&woZahX1h< z9~h?VFfh867BH3bF)*uz7qAyhXJ9{b@dFRXL<XLkb{*dRQyTbE7Z+GL$0aZ_F*2h; zmjD0FOn}xf^ekXtVPL46z`()4Flz%N4_HLN$2Ww*Jvf9x+rW~+-6e#<IRnTEA?yWF zpowfiEczb^L>?YJ1ETB9bbUZH$V(s^<Sh^l@*0Q+c@IQ`ya=Mf-UKl~UIhV=cR>K? zWe@;)8$^S=4gw(WgJ@6?fN5YbfM`%qfN5ZGfM`&VfM`&#fM`h2Ff*~BK~`AUv~K|^ PBO!#iK;fioXut&kj?IX8 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Honolulu b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Honolulu new file mode 100644 index 0000000000000000000000000000000000000000..c7cd060159bd22fc5e6f10ac5a2089afb2c19c6a GIT binary patch literal 329 zcmWHE%1kq2zyNGO5fBCeb|40^MH+y_ZdPZH-HL?~r#o#=TvGm0a4FH#;%aZP2O|?B zGYcc@|Nl8m3=BXrf`R4#|Edf|4lv0BCI$ZgFHT@!@$n5|@CXKC7a$G?;(!pK!3+$H uP%?xBC;bP4k_QF*Ks3l{U>fK=5Dju7hz2<mOaq+?qN(g$E}&lw4Y&a7X=UL6 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Johnston b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Johnston new file mode 100644 index 0000000000000000000000000000000000000000..c7cd060159bd22fc5e6f10ac5a2089afb2c19c6a GIT binary patch literal 329 zcmWHE%1kq2zyNGO5fBCeb|40^MH+y_ZdPZH-HL?~r#o#=TvGm0a4FH#;%aZP2O|?B zGYcc@|Nl8m3=BXrf`R4#|Edf|4lv0BCI$ZgFHT@!@$n5|@CXKC7a$G?;(!pK!3+$H uP%?xBC;bP4k_QF*Ks3l{U>fK=5Dju7hz2<mOaq+?qN(g$E}&lw4Y&a7X=UL6 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Kiritimati b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Kiritimati new file mode 100644 index 0000000000000000000000000000000000000000..7cae0cb7562e5c0f9fa46913b71a5c3628c01bbf GIT binary patch literal 238 zcmWHE%1kq2zzbM_vLGzf03t#^G3c{uFR1_j|34!WGxPudIY8n6|FeK<{{JsdVBlh4 zIP!pj&&M}}LD$g0!~jGxXd9X^gpgnp(D46t<{lsm!8U?ukgXt^bep+sfcD$z8k%qc E08<Arwg3PC literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Kosrae b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Kosrae new file mode 100644 index 0000000000000000000000000000000000000000..a584aae5eb8187f88600e97b6d6c764245a37e65 GIT binary patch literal 351 zcmWHE%1kq2zzaBmvTQ&s(f}l82u{7Q!1CvZgKteQoP5QVa7mEw!~Ztv0JH9Nhx-5j z|1&Z%GBYu<Ff#uC@9qOs&oFBP0}BH~-2?^>28Nym3_J`BD-JLSK*W7~Lm0FT4H>iz zEP=EE5F0Us5Oxq3&{%dL76ID#U*zGIEg-tiOvVI6gB%E=L5>8`AculzkYhnK*ufwM s(9t0GfgBE^>w!XyOw3Fy%uK9IOfc8aI0KR+)el@YKwsJE8X9r|0FqT_fB*mh literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Kwajalein b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Kwajalein new file mode 100644 index 0000000000000000000000000000000000000000..1a7975fad7f7e96f7101eb3c64c9b420eeebb621 GIT binary patch literal 316 zcmWHE%1kq2zzf)cvTQ&s(Eub4zBRpY@)cLYdAG(7|J$SkbjtV~>i_@$&&b5g$im9X zz%b_lP!+?h4Gb&{3_S}NI2ah}CNS{){~zwaAi%(|;sAq)k8cQrwxJ;q8!%`aSTg7u z8Ufix3?U>q1!&{{Ix`6c5Djt?hz2<eM1!3MVgQ{7atp|bAi5qXL<MJZ*#I4D2Xr(S E0Dm)39RL6T literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Majuro b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Majuro new file mode 100644 index 0000000000000000000000000000000000000000..9ef8374de4fa73cd2a3359d3c3886b11643a7146 GIT binary patch literal 310 zcmWHE%1kq2zzaBlvaCQX(f}l82u{7Q!1CvZgKteQoP5QVaNgFv;D4KRK>h#!{~4JW znVA?_SQr=<fRr-K+Q0y0*G*smn$WX=fro)%#Q_EZAKwrLZ9_u_Z39anZ2-hZ3?U@A z0%+0yIx~?55Djt-hz7X`M1x!fqCqYL(O}ns7(f?-TvQKalJ80`8=zb5bPbKT0DetZ Aa{vGU literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Marquesas b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Marquesas new file mode 100644 index 0000000000000000000000000000000000000000..74d6792bf6fcb791bfc0af1f827737f612abef67 GIT binary patch literal 173 zcmWHE%1kq2zzdjwvLMVgCBVm{{{R2~jEw*P*IF<z{QqB-!NB6<8^WM#U}<c?5JG}k YKx6)c%mdks&rB{Gu-SH&R>lTg0Q#CDx&QzG literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Midway b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Midway new file mode 100644 index 0000000000000000000000000000000000000000..cb56709a77dedb471150f4907771bf38f1879ba4 GIT binary patch literal 175 zcmWHE%1kq2zzdjwvdlot(EubSvi{~^1d42|U|{(FKmG@ZObuXQ@$n5|2o4Tm2qD3| V|3Hvudx8T*6Ec?zXt<#v7XWnZBuoGR literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Nauru b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Nauru new file mode 100644 index 0000000000000000000000000000000000000000..acec0429f147f40279107a48cb85c3b0e9f56c94 GIT binary patch literal 252 zcmWHE%1kq2zzbM`vMfL>wD`F;%b5u;Ph4_V{~)Ni;zj-c|Nj}87@3(F80OS~j99n> zq_A!R0~Z6siUSOMKE5Fg+J=V41`OH;mOz#fLkJ1h0Zso8vJymttOd~^t3ft_tOwEc SKrs@Xz-0q;h@GyX5f=dOmpQEf literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Niue b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Niue new file mode 100644 index 0000000000000000000000000000000000000000..684b010e8b6bad56b084072403110b94e8cfe2dd GIT binary patch literal 241 zcmWHE%1kq2zzbM_vLGzd03_}>n<fa9oU*9@|NlQD6EpMw{|Q?d7=Yvg2A2Q-<2)F+ z{{K%6U=Z-}4PnqVG&C{*k;Y(>A%q0GfX4r?GY|0r(I7j4Rx^O?1=00DF;ea3vH`lo I&d`tx082zVDF6Tf literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Norfolk b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Norfolk new file mode 100644 index 0000000000000000000000000000000000000000..53c1aad4e0a541ee3c2c4c6de33a79ca93a7d244 GIT binary patch literal 880 zcmc)IJ4{ny7>Dui$i=h^ut;%W6~e8j7=*--5Tk*FE?5bYD0evZ#>>5e&=V#$#mSgp z(20d0BqWkJ=mr=EM+l1xgs{A9=u*DtL^cMPJWameNr#iu|I<W!vOi|dy{`WIw#>?X zv2TyPh7&)Ox9x@254_gAeecn`6@5Ins2!<!?eu1~t8GNP8+)~<_JQ`6+|$0uE$uJp zkpU+m1IKs8`&}c+UpM5*_lP`Q4au{`zw-Rek-YHtWKe#JBu{kc;h_#U?dnL~4;?N2 zs$)gVIv)C<<9}Z3#G$XLogsa>)vc2o_jPJ5Ew4U_Ouy}tnb{Ue58sh=CX;clWM${% zUgVQ&%tFfkGPB^DY-2utF=1m?Hl6&l`}d#CHDi{(IoF%x2~*~}Zj7@!YR_13y4>*y z$6kp`ENWjgGgDJIhb+r8SU1ovjI4|-jjW9<j;xL>kF1XrKq??5kQzvlKwAYVgVaF^ zA(fC)NG+roQVl7G)I$m)6_JuiO{8d`t%{UI>LP`a%1CLXHc}j^j+76yTmHZL;oJ7F ZQD5P@)>wUc+>KVcmC^F}O{l64p90#q=NSM1 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Noumea b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Noumea new file mode 100644 index 0000000000000000000000000000000000000000..931a1a306f70eb0c7578a65425086270c6ea2b88 GIT binary patch literal 304 zcmWHE%1kq2zzSHQq8vaP#O9gw^+*Zdvt0rFVY?3q9Gep$X#U>8Xo2?!V+ogn`v3p` zGcf`oGYbm?!yF!v-W3NJf$Uiu7=R`q*gn1?4BCc9Kx_z7#K;&zf)jwY{0BJ$q!Z*6 l5Djt;hz2<cM1!0KqCrjr(IDr6XbPOjWdn4rovxuF7XYYcI)eZJ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Pago_Pago b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Pago_Pago new file mode 100644 index 0000000000000000000000000000000000000000..cb56709a77dedb471150f4907771bf38f1879ba4 GIT binary patch literal 175 zcmWHE%1kq2zzdjwvdlot(EubSvi{~^1d42|U|{(FKmG@ZObuXQ@$n5|2o4Tm2qD3| V|3Hvudx8T*6Ec?zXt<#v7XWnZBuoGR literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Palau b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Palau new file mode 100644 index 0000000000000000000000000000000000000000..146b35152aaeffb5940d30910ba37703f4096285 GIT binary patch literal 180 zcmWHE%1kq2zzdjwvLMXS03_=F|Nqa(`2WAo6d;G8ZUO^~k8cQrwt*!>2w{_$fm%SA p18B&9k%#AVKy;m%*&C2q^*}Zw6BFEM5s)CV1za{jYwUC_xd1P4BeDPh literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Pitcairn b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Pitcairn new file mode 100644 index 0000000000000000000000000000000000000000..ef91b061bb145b2658d49fd5065ed74b1a6cf6f7 GIT binary patch literal 202 zcmWHE%1kq2zzdjxvLMXY03=LZoH*+L|Nqa(#Pt7v8xI4+|Nk8o3@rcu_ct(b`S^w~ n=o(lU8-PfL5E6_An)tuYT<;6e2Cx+%nn-K7Y=D;8S#SXWD_|-E literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Pohnpei b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Pohnpei new file mode 100644 index 0000000000000000000000000000000000000000..c298ddd4debb649220e5dfde60948591bc6a3501 GIT binary patch literal 303 zcmWHE%1kq2zzf)cvaCQX&;TT62u{7Q!1CvZgKteQoP5QVa7mEwL;e5%{~4JWnVA?F z|NnQo0#wB?YXbud14G>e1`Y;>o&^j%5D_2W5C&~SLk4XFOCW8)5JK2;pne86AQk}H z@n7WOP8|?kXQr?QM1vdyqCpM<(I7{GXpqA|G{|uv*VF^qj7-c-EX+(yFc(e<0m%^O OPA(gutL=0R4Y>eZAz3j1 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Ponape b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Ponape new file mode 100644 index 0000000000000000000000000000000000000000..c298ddd4debb649220e5dfde60948591bc6a3501 GIT binary patch literal 303 zcmWHE%1kq2zzf)cvaCQX&;TT62u{7Q!1CvZgKteQoP5QVa7mEwL;e5%{~4JWnVA?F z|NnQo0#wB?YXbud14G>e1`Y;>o&^j%5D_2W5C&~SLk4XFOCW8)5JK2;pne86AQk}H z@n7WOP8|?kXQr?QM1vdyqCpM<(I7{GXpqA|G{|uv*VF^qj7-c-EX+(yFc(e<0m%^O OPA(gutL=0R4Y>eZAz3j1 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Port_Moresby b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Port_Moresby new file mode 100644 index 0000000000000000000000000000000000000000..920ad27e629e350c1baac8537bb639a59fd19039 GIT binary patch literal 186 zcmWHE%1kq2zzdjwvLMXS03_=F|Nqa($iUF~1IS_MS-`;J;~T=DZD_y{Lf9l`pcWA3 z1sd`{Y+Douh%S1&WCF;ndLWyT31|_-=*|xeEMN;bK^6q~LT%x)0orA!YiPg)0AN8Q AvH$=8 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Rarotonga b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Rarotonga new file mode 100644 index 0000000000000000000000000000000000000000..da6b0fadea95ebd9d06a6ac997806993a4d7330d GIT binary patch literal 577 zcmb`@u}Z^G6vpw}v>;@Vs-Ya()LyHhA`}uGv{-Zy5sGdZtdk;0Ep84{2eq3oAl~u1 zIdt^}Iu%`f1aYdHPvG%<cUKTh$o&N}gzujooSrPJU$0QU=Hv-(<j4<7i&L9VG~Mg# znaVu{?PDEqj|z=#T^QdPsvcPyU6`V`Ws8q(Q+khVc)M=O!wEavDVxf}ht)f5=K3$T znuIjp9qWbs7e%dS9euu0ZE2uuuS2?K=1kW6>GqhrYf3Sn?W-K~`JwWeFFTpZ-Mv)R zlXxY@sp@e<-qJs8l;85zYHK7@-ByUb5St-(Lu_}-euxH6=>XBfDLo*XIHe0j8;Cv- njUYNfw1Vgb(F~#+L_3In5DlHu5u&A2dcyx~>NlnDMiTqqIAwb= literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Saipan b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Saipan new file mode 100644 index 0000000000000000000000000000000000000000..66490d25dff9bcc8f710b0141f1a02e64aeb32f3 GIT binary patch literal 494 zcmWHE%1kq2zzalxvaCQX+5jX@n@@dkL9g?}8}oe(@6CRE_&u9};h(*F&woZahX1h< z9~h?VFfh867BH3bF)*uz7qAyhXJ9{b@dFRXL<XLkb{*dRQyTbE7Z+GL$0aZ_F*2h; zmjD0FOn}xf^ekXtVPL46z`()4Flz%N4_HLN$2Ww*Jvf9x+rW~+-6e#<IRnTEA?yWF zpowfiEczb^L>?YJ1ETB9bbUZH$V(s^<Sh^l@*0Q+c@IQ`ya=Mf-UKl~UIhV=cR>K? zWe@;)8$^S=4gw(WgJ@6?fN5YbfM`%qfN5ZGfM`&VfM`&#fM`h2Ff*~BK~`AUv~K|^ PBO!#iK;fioXut&kj?IX8 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Samoa b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Samoa new file mode 100644 index 0000000000000000000000000000000000000000..cb56709a77dedb471150f4907771bf38f1879ba4 GIT binary patch literal 175 zcmWHE%1kq2zzdjwvdlot(EubSvi{~^1d42|U|{(FKmG@ZObuXQ@$n5|2o4Tm2qD3| V|3Hvudx8T*6Ec?zXt<#v7XWnZBuoGR literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Tahiti b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Tahiti new file mode 100644 index 0000000000000000000000000000000000000000..442b8eb5a438985092d8657ebcabe8859037482a GIT binary patch literal 165 zcmWHE%1kq2zzdjwvLMVcB_MQ1{r~^}85#foFFwJ*03;I_SbTg#7<3H{7(z%e324ZF TkZB-$ahu3x12osp(0~g7aQq_R literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Tarawa b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Tarawa new file mode 100644 index 0000000000000000000000000000000000000000..3db6c750333fa6dc1efc84b1abc24528fbc00b0b GIT binary patch literal 166 zcmWHE%1kq2zzdjwvLMXS03_=F|Nqa($iT431ju1nae#rv$2WvQ+t7$1gang-hWxKH U6FLJj1GkA>Hb8UjbPbKT0MM`*rvLx| literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Tongatapu b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Tongatapu new file mode 100644 index 0000000000000000000000000000000000000000..5553c6009acd272cae012a08b618c2fd649dceae GIT binary patch literal 372 zcmWHE%1kq2zzW!)qTE0l#1?7*5+{qDCYb+rzhH5>_JS1)M}Sq)4hQSUuL5j>W;sO2 zUcV4grEsDC|NsAtOw25-Od!a_z_8W>sFPuB0RsyI!?p_yTnr3H9x(DDvweI+7_<$I zj0}LJF%X-8G%zwUgplAopsoMw%-DB;Xpl2OMu40OqCw6D(I6*-X`r(~G|1^78svNs c4e|n*26_WT*8|O>l2^EFfL^oHH8kb|03GB`#sB~S literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Truk b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Truk new file mode 100644 index 0000000000000000000000000000000000000000..07c84b7110ad9589810b916390aedc7ef498f423 GIT binary patch literal 269 zcmWHE%1kq2zzf)bvMfN%(*Pu92rhoG!1CvZldrfEE(!8|sQ>@}KO++mGXDQ>a|Wn@ zp=SX|b=?F84hY-FH-tgk(11bPz>*<^ux;!>BUpi$2Waqrk%#+DKy;m%+7=KEvK>T& qTmYg$t^m;>mw@c92eKKNn1PT9=A1qskOV$QaoGT!XQyjuzy$!|p-bif literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Wake b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Wake new file mode 100644 index 0000000000000000000000000000000000000000..c9e310670f07e9e577791bfa19fefde61351fcdf GIT binary patch literal 166 zcmWHE%1kq2zzdjwvLMXS03_=F|Nqa($iOhi1ju1nae#rv$2WvQ+t7$1gang-hWxKH UlQ;u11GkA>Hb8UjbPbKT0M2k3p#T5? literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Wallis b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Wallis new file mode 100644 index 0000000000000000000000000000000000000000..b35344b312c6ca690c0f79a858c3995a05c71ff3 GIT binary patch literal 166 zcmWHE%1kq2zzdjwvLMXS03_=F|Nqa($iT2B0?1)lae#rv$2WvQ+t7$1gang-hWxKH U<5&SQ1GkA>Hb8UjbPbKT0O8CT)c^nh literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Yap b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Yap new file mode 100644 index 0000000000000000000000000000000000000000..07c84b7110ad9589810b916390aedc7ef498f423 GIT binary patch literal 269 zcmWHE%1kq2zzf)bvMfN%(*Pu92rhoG!1CvZldrfEE(!8|sQ>@}KO++mGXDQ>a|Wn@ zp=SX|b=?F84hY-FH-tgk(11bPz>*<^ux;!>BUpi$2Waqrk%#+DKy;m%+7=KEvK>T& qTmYg$t^m;>mw@c92eKKNn1PT9=A1qskOV$QaoGT!XQyjuzy$!|p-bif literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Poland b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Poland new file mode 100644 index 0000000000000000000000000000000000000000..e33cf67171da78aa9e6eb02e50f9b9603da4c3f4 GIT binary patch literal 2654 zcmeIzYfP499LMnskW^Coqaw;dEFzImK@b%oGeT#8sXQv;2@Oz-3=a{S#64xMnREXf z;t(k<WagCELR+G9cA70CJdk0dR<1mZOhdBPm|fr7wboi&z35%nv*-TYJmc;4{dsbh z7mPN4Id|J%_;U8zFYm#QeN^p>ZmI4Qlv~|;;rgz&dabEFq_4cA`fB+O-M#a$*^__F z)RnH!Jz4yvoVt`QpS%&I&99}(r`r;wrTmCFy?tBJnaxePXP4YAI+q@ytqTvzXTuxi zd`z%>-n&xTyiaJ`l@ht^Ib$y0XmqZ8z1O*Vy3*+wP-!}jyk)-MUu&-I+-`n2mt(H4 zd(PZwOg2B}%r%`AL(I*j38t$w$@wWb%=E3D<@mqU$J|ps){!+)PC(vZr=Q2q>7SWs z2E=zbff4P_!2Zonkk4@^sI$Qtba9U}`0O?(_`Quz$k8`V=z-lPY}d<X$d(NzeEn)O zv@p-yJAanBFT*1d$!T(bOrk`F4wDD^43c5KsXDAHL8HEn)ZwiIHTr{|`e5VF8dG~k zM^s$Uk>wxjs5M75Ht(RuEohU`s~ROfrAZQIR?3*L8c7^oB8lB)GA^V-$F(n(@xK;p z(y>&T@I|&J*DcbNrX+o6(<Gf(9jXr(MChdQ@$$%IUro&mkw+shX<BNxO!oaqr$l@u zQ?7j{Q+-az)aH}&*u~c+y?(!BoI0+VTerxx1AFxG6)R-=mW?`N&Ssrin6Fu53)Pb` zMP~&~)7de@b@r`T%?_L_+2{M|+^#6eIeb&+wff2Y-2t+ou|pP?b;_cOX31UDDvL|6 z>XM0X%M%MuX<m4h<fqhYL9au)G)#5r<sG`LdzCIfxmKTS_vlmm=4s)FE9L1IQ*=dL zmOQg8T#Gi1k(D!&WmQ3ttd1KZYtnv^X9J8Bj|$Y{>)%L;|1B+Pd0*CEYtwZNb@F_3 zldi9NS4-<_^o6yxTDG-Jy?nfVdieI}byrUxZ(sXz=TF}L;itFXfB!M2e}la{JbM@u zI@GI|G5%uu{`oyR)+>Nt%)mdMzyD`OrpL^&-_*1$9v+j%OPYP*c-dng?)#m;J^$ib z-?nG=;g;#h^+v9^tG(vPRY$Hna^;b0k6eA^`XdQIGJvE2$pMlCBnwCykUSuXKr(@( z0?7rE3?v&!I*@$0+Jqn(akVKya)KlU$%?B@3z8QkF-T^R)F8P*l7nOiNe_}ABtaZ9 zgrtZ=j*uiFSwhl;<cUL~kW3+|LUQG5lZ9jpNf(kYBw-vf#vx@Ka>gNP9J0nCZ5;B3 zBo4_Ok~$=JNb+25_K@@;`9l(jWDrRql0zhkNEVSaB6&m-iDVK<C6Y@dnXWdQNIG3@ zK9PhX8AVcx<P=FNl2s(FNM4b|BAG=}i{utbE|Og&y{<ODNP=B$hLIE_IYyF<WEn{_ zl4m5*NT!igBe_PBjbs~1x2w%Jl5kg>aU|tP&XJ@eSx3^2<Q+*ol6fTcNbZs3BiTpN zkK`Yj09QK$$P^%RfJ_213&=De^MFhQG84#DAaj9C1~MDSbRhGAOo*$U5oAhS?VKQ! tg3JmsEy%ne6NAhQ{y#N;J2ifGjz+{WOfi}9Bgc%4jmeCQ#ZmEozX3dW2`vBs literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Portugal b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Portugal new file mode 100644 index 0000000000000000000000000000000000000000..355817b52b1b05680bbb57e4dc8de358eff27a39 GIT binary patch literal 3469 zcmeI!cT|;i9LMoXh!gdvCa5?bC38dyI5Ele24>=dtKvW$hzs%YIu4o!DVeFq^V8IF z<s;%aq_}XUxEBswkz$UU=EC(DnwSy&-j9D&r$4fD>c1Wi_jSD@|M_`;9leLe2HO7e zc&bnM=DDK2dGC{?UgqAMowT^)NPY3IN0OE-xvwwHnyP=9=+u{`Z8eQ(hrWDfo}SV+ zS6>l7N>BCmG*@;>G1ELA>S>Q>o9nVxo9U~4&GkkXeZwan=EhG)n49!E`ex^JJ)>(e zeOq9dzP<cWeS6UkeaFKzeb>=#X6E)a=I&+D`kpUln0ptQ=DvhDbN|pN^FU;0^I#hf z{ZLDP^Kh#L=8?#?`jOnLdX`&bJ?oLCAG<ctJiaB|JbrJ5>qJsV*NICh=E?a@&65W@ z_Rn^vxUvuJ(NB%@GEc1?;yN9k>^i-2xqik`V4j)P!F4t;)^+ydsrtEI2hDFfY%z0! z&S>8@*sq<hx>>tWDpkAiY`&IzXPS0tM=$O2rexzv$~fcd+*rdkrKj<|^F8C*z#!v# zcthidc0R_9Ku_al?Ly<0PXq0CnQGeY=Vi1zdB13R7w>C#k6qF3eSJ#1pSD+fuxO+9 za7Kz|PW()JG(1`RanO1rKf*8`+vgZhnoKc%@*QJ5trTMvxOX=S@<R>JuNvCQF7~mN zo9SsQpWGrzjIEzkA*O0lMMo7`$^Ja))h0j7%D#7{SEWnR+x?{U&fhJoT+cMBo-<^% z19PO$u1ryVZMvwjWSOWrONv^PJ`!4-Q`GJ|NYn{)2;bHr;x)hKqHgti;&sm|qMnCc z)_c-a*1u6#Hpuak4G)!&Z)6lmztlVO&3PAPqvYeV@z`C`KW3c_h{_d#&J58cc&BI@ zzCbjqu~ak<Oc2cr6Gcm(d9vl@0V3%6c-bn`F5dbsQnp?dErWNql5bCIE88rtF5iju zm2H!QM7vNAX^-&{@7BE~L+phj)FVr__q{6GKe#D6xbG7kvX6@Qudfgt)6+!Qi9NE@ z>{+7o+U2rKe7xv7YpU$lbA}9$8!RJQ#7Re3d)eK)v+Uv5K=yd*FC#05ipcX7Wv?go zMenVTWuKhVqOVawL}lC){Sxy<^t^1*KRQPYn4BjEw%H~IMV*i_wHAuO!Ra!#<Q6%k zhLl5Ye=dg>I_0pV6XfvA4mn~?9~pOev=})(SjMl45Tl0HlKQk}Vsy9G!Wru=#st(9 zV?&;aaTRQ0eB;V;ym?I|lzS=@P9GE#9^}f28&-)AvUkc!3-`;(=}YB@6H;a3>_llR z?)Hj%v6uYvP(Sy_@0a>_CI0UBmn>y{l`j78e-#xy9i)cER!+DTLtCjozpt*jmHqv5 zTSfksSM|BqAAd5elf%|CB!U;d)t~I@jh#=_<EEY$FV^pR@!s(d#;-^{{enGfAR~wj zp`{u_WDt>2M1~O=M`R$8kwk_P8B1g^k<mnk(^8EmGN8zaB14LdDKe<Ys3OCPj4Lv* z$jDl%p+&|P8C+y^k>N$g7a3q=gpnae#uyo7WR#I%M#kAv4Ky;+mTIVxu|@{lQjIn; z+?Hy*kpZ_<BaRHYr5bZ&&@I)dBg1Z~#vK`WOEvPy&|9jpM+P4mePsBN@kauHM8Hyo z0Eqz-1SASb7?3z1fj}aGgaU~L5)337NH~yqAOW#d5kW$N!~_Wn5)~vYNL-M>Adx{r zgTw|24iX(CJV<<y03i{wR3YNO6EWf;NIXP|hcF>=LIQ<E3JDbwD<oJ*w2*LFs(2v* zLn4NR42c;MG$d+B*pRp(fkPsPgbs-v5<Db&NcfQWS*idc5kx|W#1IK05=A78NF0$s zB9TNwiNq2KCK62~oJc$^RX~x5TB?vDF-3xkL=_1u5?3U!NMw=FBC$n+i$oU*FA`rQ zz(|BGRfv%oTdE)<QAWay#2E=R5@{sVNUV`yBhf~}jl>%XI1+J76>=ozmMZ8-)RC|w zaYq7=L>>t}5_=^0Nc55LBk@NL0OSZj4gusCuv7;Daugtk0dgE52Lf^=Acq2SEFcF1 zax@@^19Chd2Ly6NAcq8UOjxRe0y!!y)nS1g7s!Eu92v-=fgBsi!GZrD9sl9cQCi(6 Y{v0ZPotiXi*2uqcfM2Hof8Le;4LU9nuK)l5 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/ROC b/venv/lib/python3.8/site-packages/pytz/zoneinfo/ROC new file mode 100644 index 0000000000000000000000000000000000000000..24c43444b6751343d2915843d03e55753d4d7359 GIT binary patch literal 761 zcmcK1KPZH89LMqR`FoCmn=A^0GKfqDQI3Jm<e?~=l<jvYiS%0xSWNzmibWa8A_Gc^ z!QVR^$KlTZUknWD{NC(h@OyfmS3S@4ygyD`S7*8Wc#7@URC{M@`&etP*Sk)u-Wwax z`!x&Zpsr93{j27va#ez9ohp>~qC>H1bDSuWlg({)8fn$xc`;|*J#xO-p(2CBaxpP! zF58!Nv~NpYRXxacS-!d{2uRF3r{YPoI{q3ox6z>79b~EdjZFQpRBayLKICa?-8_d% zwdsFX=^riPejHU9;SufGSur^$GurEfl`F}W{HseO5V!v$N=u5!(73pHy0X6C_!}MZ zH968?Z(pq=&L1)*?CISxxkxS~8Ilc2hvY*NA{mjCNX{>9QY0&q7RiewMlvI*k=#gf zBs-EG$&XBc%z#XR%<-k21epby2AKz$2$>0)3YiO;jM~h`VLD_!WI|*{{KqLhcGr>$ F&nGsEUL61c literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/ROK b/venv/lib/python3.8/site-packages/pytz/zoneinfo/ROK new file mode 100644 index 0000000000000000000000000000000000000000..96199e73e73aafacd89e48cb2855a96d7a134e1d GIT binary patch literal 617 zcmcK0&npB`0KoA#c14?7Qk#qN;~<AkiGwRH?4p>H)21*|8mE0H7m3)~$w^8n2PbF# z11Bj5<7Z79v(sWd<uJMMzLSHKa`0ZS@0<57^FHSE!d$QTb+qc+I=vdVTqU>tRCqDe zrQF$~?N;}4SK)_!eU|oa+)Z_Rl=SZWlDaRvd8LVN^{{vxJ~p>l{!C1ko3cUBW6PlY zZdH<#vT}N9J-znH=fe~0<vb;;>${ffUzTkLIj4PT-sxB!bUMdJ9HS;4`<_Paj~Sf_ zk+0|1^BW>A#EK*IS7G01i1zwqZHGN4*)daOrc5!aS7z80<{zH@sRvJ|JfA{9VTh_J zC>#_L3JZmX!b2gVFj1%|Tof`28-*^a=A#fs)r=HM3MYk>!b+h<3SJ5^g_-^%bwazR G2NGX5oeD|- literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Singapore b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Singapore new file mode 100644 index 0000000000000000000000000000000000000000..2364b2178b03853b1771cb3f34b964fdb82e2e91 GIT binary patch literal 383 zcmWHE%1kq2zzaBmvK&CH&;TUbnp+p|O81*^fa^)Zsm)IlPEU;Ixa5)hL2Tkzj{5)q z|1&Z%v#_$Uva>TVB*p^OgGd$zhNJ?J5$OtyJRp(*NM=?r2r)3!O<<5<U?^x{kn!;i zVF(6dZ3A-<HZlN_#vsxXh%FdGNN_079sldhf)|5mkb^-q$k8Ag<ZuuTay*Czc>qL% aJOOeq$Ri-S9w<gL&v4lQy=13r!36*{S756E literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Turkey b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Turkey new file mode 100644 index 0000000000000000000000000000000000000000..508446bb6aee2841ab88e82607a6ad6e748e7db7 GIT binary patch literal 1947 zcmd_qZ%9>V0LSs?`nP+{bz_9Pc+<9~_m<WCx4Je{%S>!HcdDyFf5t&8ib5V%gGPe4 zDT7wf8GBJA#8%G0%Gwr#Q7fV`boS>^w&_xK##j)+d<I!_QucgLuUc=`>z&KFpX24? zi_7!<#nx`!TqvHq()1_XTs!s6b0DtYtbL=0+9zk2?YA!2M>jP($98{cbkxSpFUrr_ zojD=rc&Nqh3Wv?E-yYc~#`ZcVFBcd+d&-?&&&x*d@=^20YjLBmuiLz_&1>8|T4MHB zCK$J(>CR8HcH2MajW`3|4fbHdL38kKx&6z%ubtaB)*D0pwmJM&neo^CZ_WD+BgW{K z6!SrL#7=4YRHl|3mZ{_K3vZxVdhI^p8+%u#efc;(d9XsJchtpS>O3W<v@M8F`FpAn z*n36>hR!&dcWf2>VMI-DFOXULcc|><jcUgBI`!)MW$Lx)0yVQVtX`iJP&q-L%1s+r zq2!PZjlLqoe|Y7r{(t1`@9)XHvqN%D$5lCZU#ptec3Qr%^D~*h@e^6F;k+t*@1QDL zbVL=e`ar!oJ+9^#u2b_LHK<7DE*TkKs!GP!%7x$Ms<&>J%F@nCx#(P$Ec+-&mbVL8 zu{l*PZVRd<Rd;1&<72fnr%zT@I%-*RuT?$sSAX@Ncl<Spm;5!?di=|OKjweCyUQQF za?x6GVA!fX`MLE@Q<LA=-)gN~^RcyR`zC93<bppIt+whiYOVURBUb&xd~411c}B~` z#Dpg?;YD6a$w`SRssH^o$@|<ZDM^UTus%j2bBoZ=v-3TZgb2<M={$?6LPRP&)BgSW zv)_rXh>03~S5>X%Ehh5vi}YR0f7O>qUr(RhKSb;W4!HhJChEWG89)v?a@bw<fkzHK za`2JEj|6~3fP{d=;HrZ_qCmnx;y?m%)sY~fAh969AkiS<An_mpArT=VAu+k?ppdAL zu#mWrz>vt0(2&@W;P_pM4hhdy$Hzs0t~x?4LPTOjf<&T3!bIY9)qx_By6RAoSdn0n zXpwM{c#(jSh>?(yn3157sFARdxLtMNNaRT9NbE@PNc2efNc_kEAR~Yb0Wt>2ARwcF z3<EL_u6iJlk#N;Rfs6$*7|3WK!-0$kG9bu^AVY$T2{I_is360Fj0-X_$jG?rp+UyR zRSym_I>_)K<AV$kGD64@A!CFL5;982Fd^fF3=}d_u6n4DvBDO82LBg><tx>LRyMcD F_XJx;ZRG#} literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/UCT b/venv/lib/python3.8/site-packages/pytz/zoneinfo/UCT new file mode 100644 index 0000000000000000000000000000000000000000..91558be0c2bf903b2364215ba26d5227d6126508 GIT binary patch literal 114 hcmWHE%1kq2AP5+NDp(+@LPMMxLdep^1=MQ51psH$25|rY literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Alaska b/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Alaska new file mode 100644 index 0000000000000000000000000000000000000000..9bbb2fd3b361ea8aa4c126d14df5fa370343a63f GIT binary patch literal 2371 zcmciCZA{fw0LSqQ0v8C15>k=qB=Y>=0R^EbF9-r60dl(ukxF8BSP2AU_(W1Vaw{?0 z9L`3^IkwuQo#|G(7TvVgCgupY9>$_{YbHzAdYVOYJKvM57d7AI|G)G99PW7g`??!i zp3HIl>j^WzaCr8a!#!oE`Hb$#^NlC`+&11+EPo#_Q!^(vxcqOdkdA>;SHO!YGO#<@ zHLJZu2Q@AC1=l9&kfKDNGdol}UtZ@6i<;75!xOIXAI|FAz8UpJe0f<$`i6bCpB$BU zym`hIb#PeTx#y_st}Xp?cFSH@bbY&wsc3WET~H_Iq^@?&UC^rMg)MQ#2G;7>^ysMA zAB*+;i-{_3e4)PQlvBkY3(@x;zN|!7fxNGGR4wq#mkFD`6AN>%%fyvuL{iMxGCA$2 zNS>M2so{G?>f~2CZK_SAkG!ul&cCEG2M_D4<D1o@o)@%ywMJ!omCWhLQH#r-mrLrR zRc>;#%***zEp@Jt`Ej#F{-qRIF#U_T|Ko7^z{KaGP$%gJ-#sZF+83&q9Xcdjty8*a z*E_1X`mA2wd{C7vdP|p<Y*VE_U65s&1ETEwX;~4uRa6`wk}Iz?iptkM(5pV{R#n@N z=!f5KP}PmQb<Kf7Ra@xQtGnV=U0j8BdmPIBN4oapUR0iM%jKGQzgY88nyjC>AR2}u z<YSYkMdPlk^6`-&v9@_kt{dzV>#M%kO?^ky6Pf4q2Jddw9I5rjGOyZrWxw_&S19i% zow~)Du3CmYdefyy_0)k5`Se(tc&6(SxmibuR?kw|)_+yB=gpJPwvLI8m}%KreN1%v z=jg8dbE<3dH{Cr~tL~8rz2(||wRP}4z3q!mwY}$cz2k&O^{nmH&kf|OfWTP+LBThB zLqeUm@O3yoyykHD{T=HaL4JR4TR^D&M%Z7X>^+9BBi8Tl-x&~Z?+L4_+>W9;a~?IP z#+-8gC@*n4>bX>!OHrk{nJ0h`&tDh!e{U_^`~!#Q6?3?!_|3EI)b&qsM_*AnvOQ#f zR<l85hiJFRg+20^O#-__wu$T$*(kD8WUI(tt!A^xZmnj!$bOLxBRfX6jO-cNG_q@C z+sM9=jUzipwvOx_**vm)Wc$eet)>B1(*dLfNDq)EAYDM(fb;=r1kwql6-Y0TW+2@_ z+F>>QKpJ8-9YI=x^aN=N(iNmFNMDe~Ae}*4gY*Vz4$>W@JxG6$23bvqkQO05LYjnh z32773C!|qGr;t`5y+WFWbPH*h)$|K#nALO)X_?jZ3~3tDHKc7w-;l;3okLoO^bTnr z(mkYoR?|PEfmYK&q=i<~L!^mF7m+q1eMB0GbP{PL(o3Y7NH>voBK<@fYBe22T52^t zMVe|gT}9f8^c86=(pjXnNN<tmBHcyWi}V+1u+?-JX|dJx7-_QAbQx(g(r2X6NT-oj zBfZ8O%?=6-4!POu3=6%5@88kx{$JDmPrGm2!ijnTdC#a?oRyO$Gpe$)v$C^f_@5Pu BZASnA literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Aleutian b/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Aleutian new file mode 100644 index 0000000000000000000000000000000000000000..43236498f681cc06f64ca2afa613880331fe6fbb GIT binary patch literal 2356 zcmciCZ%ma{0LSsm-|Iy&Dj-Bm!Hl7RhrdBt9tc86<UwwrWC#iolmVg)3ox8hdC|nN zoE0&9(I3~SV{FZ&u`@U43+KAv*1#M!H|MM|UA1J6yq)jK){C0&@;rN<&)MC5`}=yU zn_f<L{p)zlFT9+7^Ky@W%Y4rF75FBW|JFKD=g8X=FQ_}G+8qC<Ug<hk;RGDYmVupF zPEgxM9b8xL3n|akp?MiTcUrV|zrDlfiI~-%;p<M=%}aXzk5j${Q@3Qe9`!B!dP+WU zV$z9tcT_&uciMSq&j<41ra>oi^IjQM+~Y*&*2zbbYMq#bZoSBp@5Baf)v>D*mc{<! z=*3quRNO?mUUDW%J^E#&Ui#rJwXCB^#`jLCgvunjy!m(WSoVCmqGVD$9yKEqSDqG$ zeveKH8x%>?KkJo0^@vqt7j*K)_f*Qz7dmyMORerXqQyXsN^AUFrngI#QPeLpD-u*z z;!c^J5v-nYdu2{syvVthEpz9B#FOV@<Wt{Y6>C(cetPtrc&0yEuYLc7kS()1Z~s}9 zUv^19TmOkFSpAJIEa+2(zuu5VDIbfXi{r95{E#Rf8IdJ3&EomNZ}s}`4ye+ulX}Bf zuc)#u1KK%SqRQ9o)*CyLRYhEt_Es)b-nm>|nRQcDUagdymWGQ>XLID{J2yo2N3rt7 z>2a}T|D1ejY(&)5Ps^=C?}*yc+q&-HNwqEIvfkb}pz6cNbVJc@)i85hHzro8#tZv& zlRH;64cF`DYm3#ZM|<UKz8tZmW4nA^#fp~7LfLwFPPAnw%AGCKqCMIpca>?e%fCW* z<Xl!AKe%;g%$VvNyRP@l9#?M+o!4(p?o(Yo!@B!az3QnstoI&!P6Y%81q6rO>j|Cb zzK@T~_1P7d%kOV+T)}>Sdu_lx`(0pviLm!bzOER*zqd7DiM=mcU+Q&js4#Dpc^$7S z-`w*Hyso@;=CaOQ%n9Jb`Rn5S?~#R>Kk#ynn3sFJ-<-8){usyZgVi<2=#b%A&G?W3 zq8%X@hR88v1O|zW5*a2kPGq3SNRgph%~+AaTFq#Y;UeQj28@gt88R|vWYEZ{kzpg_ zMh1?I92q(?c4Y9#=#k-D&G@Y*07wLo5Fjx?f`CK;2?G)bBoIg>kWe78K!Slp!)n5T z#KUR=f<y!f2@(?|C`eS0upn_k0)s>b2@Mh(BsfTPknkY!v6=uO5kf+Q#0Uuz5+x)| zNSu&BA(28tg~SR877{J12^SJCs|gqqF{=p~5;G)dNYs$9A#p<jheQqu9TGbvcu4fD zCVWWztR{d+1g$27NDPr6B2h%bh{O>IBoav^lt?U*U?R~(!imJwY66Nx)M`SC#MEkn zibNF&D-u^Eut;Q)&?2!#f{R2K2`>^~s|hd?VXFx-5@V|gG7@DZ%t)M(KqHYxLXCH0 z9UK@EdauXrnRg$bziVB+?f+@^KheH>3o}7a6Q=0Nr5UN|sUo>FEiE-IRfPQs4Q6_I literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Arizona b/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Arizona new file mode 100644 index 0000000000000000000000000000000000000000..ac6bb0c78291f1e341f42c34639458fb385bf8ed GIT binary patch literal 328 zcmWHE%1kq2zzev6vMfL>&;TUnEwh?1e>Z!>f;O263unD-INixJ;k@{Lne+Wm*Ia0n zlKJ(cRN(iE2nHrbAY=wYMyCJ&r@dof`2T<P0!Ehq|L0C%-~h9Ee0)O~d|iMz7>L6| z7(z&J%6}k;W8v8VqCrjq(I97mXpqxDG{|`%8stO}4RR)!209f)gPaSZK~4tIWICG* I=zeo90HHg7VgLXD literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Central b/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Central new file mode 100644 index 0000000000000000000000000000000000000000..a5b1617c7f70bfc77b7d504aaa3f23603082c3cb GIT binary patch literal 3576 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/East-Indiana b/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/East-Indiana new file mode 100644 index 0000000000000000000000000000000000000000..09511ccdcf97a5baa8e1b0eb75e040eee6b6e0c4 GIT binary patch literal 1666 zcmdVaT};kV0LStFL*AOuCUenZx^UBrvdmhxOs$2dygYfS)X7^*(Gj&G`CoXy!A)V7 zj1gwph`4Am!&tLPDN)B;GiE#Fg4v$G^F7?Tvbk}do&V?GbJNZ5`vh`JHYPfMoH6Db zE@z#&yhpm`(ReP#J$385Y}z-$J$<5IK3qA&eb}2J9~}s~PolrdCq?6QSLLwtH1(tI z&gph~rg!RRNjIEcr$zTg9C!NEQT;sF>h^bR(=P@Z+?N-Q$bt46ckp0^RE>G=tCE0x zT{q8tlQ~DeEtuxM|1w2?F#kQ+7OB1So^l$3+PD9eN{g?O>1hi@`f#((h%HnZU59jL z*nE|FwM;Mk6s;DWJSZ3UqzZp+sm!`QLuBXs<&ydku{0%KE~^|8%Ok^OAm@Py{1}!i zk}irB?<VS1QTNoUyPx&yV6)0S+okgc4ypV-t$Iy+nJQS{pbHzbl<;4ZMf*#|+Sq!z zuGlZuhgHiB8S!Gnr(9V)Gh7sRrpS`f!=mJJl-xAbElTT?b=l+3YI9Yj-qO;g%5#ER z9&S}zla#I~Z&2GJ?&$5=HEMfsP*%;Y7gYndW%bl*QQdw<)_ltqI~w=OoxLfdwys$2 zYKsze1(|a9F-MH>+0V$3-!H%Z{Pi3)V$|q=@bSEsWXJKmn^$}xo_DFq8EfCi+vg;n z&ScNK-{G6O*dK5fq?x<i+?D1o2{`HIJ>7iA@!2N?{$g&PIRztwO~~w!=^^t&CWy?? zYNm+H5t*db%o3R<GEZcp$V`!`B6CG1Yc;b)ri;uMnJ_YAWXi~#kx3)7My8F-8<{vV zb7bmh=gte0=a|_8(?{lyBw#feASqZ)4oDJKlLe9nk_VCqk_nOuk_(ayk`0m$k`I!Q z)ntUEWHmV<Nm)%+NLol<NMcB4NNPxKNODMaNP0+qNP<X)NQzdIBa)=mWQn9{HF+Y5 zBAFtoBDo^TBH1G8BKaZ-BN-zpTTRYL(pHl-lD5_4jU<j_j--y{jwFv{kN<J{q2?DM Y$^0V3_-Dr@#?6ZHCnUrr#LWu*39tolUH||9 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Eastern b/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Eastern new file mode 100644 index 0000000000000000000000000000000000000000..2f75480e069b60b6c58a9137c7eebd4796f74226 GIT binary patch literal 3536 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 EZ-WKA#Q*>R literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Hawaii b/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Hawaii new file mode 100644 index 0000000000000000000000000000000000000000..c7cd060159bd22fc5e6f10ac5a2089afb2c19c6a GIT binary patch literal 329 zcmWHE%1kq2zyNGO5fBCeb|40^MH+y_ZdPZH-HL?~r#o#=TvGm0a4FH#;%aZP2O|?B zGYcc@|Nl8m3=BXrf`R4#|Edf|4lv0BCI$ZgFHT@!@$n5|@CXKC7a$G?;(!pK!3+$H uP%?xBC;bP4k_QF*Ks3l{U>fK=5Dju7hz2<mOaq+?qN(g$E}&lw4Y&a7X=UL6 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Indiana-Starke b/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Indiana-Starke new file mode 100644 index 0000000000000000000000000000000000000000..fcd408d74df43310a9a85c475f83d545f6d75911 GIT binary patch literal 2428 zcmd_rQB2ik7{~Dkfe-{G6GJjEt(buXHk3Bl+S0K@BA5qIA&k@z%Y0QJQKQ$bL0&XV zn~G})i(IZ5T2rwtG^N&R&d?-CCBP(SA+N>-DV@{%eY?zBUH7p6`TTcudiDF_T~hY^ zO!>=&*l&2aJ@(-}THBBMeTjPSC%>tNnz6cZ&jt1M>pp#U+K@V15^B!potKU&r_Fb% zN2ODmO;=Q%boIPtzV{v07f!4<7rS@qOZ(qc-K|ynhpp>WPko{8E%U0r>I{9^GfVwg z9H*}oq?`WCbops^thpK=D_3t$G}r9^eyx4j{M_FszjU;jfiK$R`te>h*xaMd-c#zv zwv&2jX|1|7Tq?J(ddx_tM}Ge@!T4Gd#Q%PTk=+pzP&;Twy*wy^Yr|Dg$rv4+dtKf2 z#DES-{ziqo5wAldKT@Fw-jy)(wi?s3Lx*=AG!Z8%^w?wD&A9#BC9<yE+`YA2##iN= zd&=@<!s0X&<w=u?kH?sMr^iV2)Y)p%=n;t-HA%(XjMn${-d2;_Z|VC#yQE?dUDR=n z$JLa|aq_^HMm06>hD=-asd+H<oII4Z*E}3`SmGbqV&Z-6dV1J0Gw0DtHFwSeHTTz} zk~w3w$vjslo`@Xd`FN9L4WyW--r1$+b<9`Uo2&HvBgrbKs8Hwb9IqCnXXvLZhSb8z zaoU^Lp}ZpjIzP2V<zI=FMX}$SMW2f-_8l=xn);-$d$%citxcY3-DrxJ?~|qVMdsP; zle(m~N<BBDNiQocRLdi3^oq<3wPIkUE{%^<rKhuWSxA5?JCLYX^<P#m?DWWsXZ&V$ zWrDoa+-uh4M~K>X%B)Qtlyz&~GwY+;r97wBl=}vBWm=P}>^`G6MAxVdt%r2g@Jh9@ zeuv)FnWZ*YSLjz-5><6^fqr%OST!oZ{saa&c)jya@ZWrY=fCZ~4gQBe`&a*(-~ZuP zB7Xm|g8@N){|5~++P#On&qzLH!k^#I%l68XbL_LwJ_Yv4^~zlP&IPzn@cxJO`Rx@4 z`WlcGB1=Tph%6FWC9+JXT_>_oWTnVbk+mX=b=uV;%SG0UEEriavSeh<$fA)|Bg;nC zjVv5lIkI$Q?a1PtcJ;{eop$|50gwtHB|vI`6alFMQU;_BNFk6)Af-TRfvy<5Pz}zO zgQFfuK{zUclmw{>QWT^rPFohFE>2q*j>;gVL282(2dNHH9*+7T1>&d>QX-BTAw}Y- z5>h6PIw6JPsFc%|3aJ%RETmdUxsZAx1>>j~QZkO3Aw}b;8d5fnx;bs(kjf#YLu%)= z#p9@+)0U5;eok9JjtU|rL~4i>5vd|lMx>5NA(2WVr9^7!w8ccK>9pnKsHf8wl%t|Z zNjYkY6qTc@NLe}RiWC;9EK*vewn%Z2>N;(Ck@`AqfsqP3ZHbW@BSq$@GE!!aIwOVV zs5DY)j#?wd=BT#QmK&+J(-s`5xYL##sX0<~r0Pi7k-8&=$NyL5!|X4CS@xGfV)kQ6 RGn0}Nvr|%%Qj(Ix{s3RXO|k$0 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Michigan b/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Michigan new file mode 100644 index 0000000000000000000000000000000000000000..e104faa46545ee873295cde34e1d46bccad8647c GIT binary patch literal 2230 zcmdtie@xV60LSq!L|_Lbm=r2fLCOx{_|+-mRT!}A)DzRg6ipuuyq!=ysokIqYk{WA zS<_*z#xkvuu92E8S1~nbZmmpNML&j5ZL!v(9-}{6S6t8gS^xD{|Fxdm^So~N*ZuQ( zhZ-Xr%AJ3lWb+G`v)f$0XLrAsx9WgzpY!3<T3*ioRbCb`^|`lC4><=_tm4^cV&BhG ze+*UWKQByI$<<e6O6ggVvU`fWF5|FpIftZ6Zx^YmTc&;SvPwT4me-%^QWIZ$N@pC{ zpfYzh>q#B=s2d`FJ$YrJ$_lvkjdRn~P3}~ko#z%)CXDK-iK$}hFD^Oln^BQ-=|?&J z%teuV>|=TJ!DHf<sH1Ova<9m1_*Um{>{qvW&*>Qpo>MckUeyJKn^nR1`_k=dQ10PZ zWZ@5U)U1IWvS=_QihCo{b7HnA>0BsF_hyT-a9Edb`dw7`1N!!*Ukh)+EIqq?K+H)= z*Ok-0RFxw?>$$OaRn_@Rdfr#P%GdvsyyKlG)SY`ik$1hYURAdpm-D-}iM#9f$(p8h zqP8R|>uPI6-B_RY7q3<R!Cg9#K3@e+wCV+;`D)>dJLRI!szq>Xi(LFxo~U0PluLS& z#J#=}x%80{u`DN3h8ix2P;5*t_Z|_;zniF6<epb6&Rx|j$NN;{;X%D>c$Zq;byD9y z(5lun?bmC27b_8bQ?A?5BGwo8$Opnf(UjgUoBbuCd9+c63o=FcBcF^UkBP|ZxpL#k zr=q2&O1ECTsveBy=!g0TRa?WjmU~XBhrLQ~YTK_iXPwns>O0hy@hdV~*(0LEXJmVJ zyJ#OcBs+d<6p!|H%g2U%VryquKK^#D=v)(!+n#qsLgF<^iP!!|KJobR8IBW=AAQM5 zipNjA;Y^6fKRBI`X5S3^PF@rYIW@~dP966?bC;M~8)67f!ryP`UyLSh4#PplgA526 zk<|<d851%nWK>o&EM#2B!1ybS3>li$j13taGCHdn9x^^;fXE1uAtGZ$28oOk874AL zWT41Mk)a}EMFxwE78$P9j29U&GGb)N$e58qBcn!!jf@)^I5Ki%=*ZZS!CTGfk>Oj- z_>ll05kNwK!~h8b5(Oj-NF0zrAdx^qfy4p{1`-V<999z#Bp^sckdPoTL4txr1qllh z7bGx9WRTDxu|a}kHPJ!BV>R(X0%SE2LPCVZ2niArB_vEpoRB~vkwQX+#0m+P)kF&k zm(|1z37FMH3<(($GbCt8)R3?taYF)!L=FiZ5<4V#Nc52KSxx+q09s81kq}x<43Qur zQAEOs#1RQ35=kVKNGy?HBGE*`X*Kag0%|o8MM7#dF-3xkL=_1u5?3U!NM!MU8(NpC Xu-DYLC|Kbs_mma|%gQ`uo>JFeUM!I( literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Mountain b/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Mountain new file mode 100644 index 0000000000000000000000000000000000000000..5fbe26b1d93d1acb2561c390c1e097d07f1a262e GIT binary patch literal 2444 zcmdtjeN5F=9LMnkqQH%ZQ;8v<nU)CgtR#>b6-0<P2(NH8!YHnHS1a(Ln-=0RD8?U+ zvtrCL36!+fOng|gv7xTv+REl|Yg!BKxhxw!Y?8peo%dPwPk;4STVM9OuOIjS&-=Po z`_|@&f812_4G-6C9^R)b{@GWcUmFNlJ<liU-dDa?dprTXw{@E6E54}vI`*j#+N1RF zyx$s!>*B?gOursm&?$b8b?d7UesOi|Njd(VTTGm*mXq%nh`_OY8GIv2h@FWtq%9yq zpPH0YHYBL9x|w=v#e|wxIIhF9MpXC<xjIswP>}}?Nyq3Ob<M?I9d-V=h(6JxW8Uo* zv2XTB`ErZ6w*6Uo-Bypd-d8WDuPPC7rT5Ai`6=Rtlm#+=Zn2sf>5vJb$tvNO`8x57 zNR>1kp=X`^LCrpNN#EFeTFvp#k~i%*sOGK=%6aQP6gTI7E^k@(wwNFHo=i^FA~|qD zr#Lo>l#!D<^^!~6I=EM-oo!U<-OuTaBb6$%*{ic&TBNeQtuklR47IRitz1+&rgD?- zlegu3q85jz%DluYBJbNMnLmDB6rB1=-u~%;Skmv%cMR+nOFMqlckbFQ3L8GsceU<P zcbE6;d+N8TqRba{anTx8{Ogb`NpBJ*XZOp}=vq;Fq+Kq%Tqw$3eO)jAxJEgf+VuVJ zELG(-K3&l@M?J8lOjr6t)rzEa?OOSja!thQs@zkm>gzP=p8ch855>q;fg!QFZ&W@w zvR~A+4$FrI+eK~tQMsmjy?EGpM%T5qsYlWe>qoslRUh4{JtbwzbJ?%G$?3{_+O2)z zvC4O#K(G7eXSKeoT0V9rMm+A%mrooV6%AF1vaw@WY{;FI8yk*_O>r0G=JGDFIWVsM zd54vM<TJe`zEf=(Jg&En`PI|iz51DRZq?M>qPHC@P|dX-y?tkr3Jv-5Z%WwTuYY~@ z-y00>?i3;ze5)rU%)Dz6Vc(<dr(EuI31^XcR+y*SJQXgpA|XQThwERgFKDhdEUF(_ zA+khdjmRRARU*qo)@d~hMOKO|)oRv?EEZWUvRq`nR<mGa#mJJ8HKScLFRYp~%LdlX zv2bMN$kLIuBa25?Z#BzD)^9ZhKq`Qg0I2~-5s)fylmV#&M<I|(aFhb61xGQEYH*YT zsRvRJq#{;R5~L<bQIM)2WkKqK6b7jbQW~T-9K}JZ!%-fjK2}p8q(W9xBBVwfMMA2C zlnJR5QYfTSNU4xoA;m(fg_H}a7g8{!VpdZ!q-GpNL#oD6Hl%JGg+nUGQ97h{Nb!*B zA>~8rXEg;xDrhw&L~3X?MMSE|QAVVWNFk9*BBexXi4+s5CQ?qMo>o&(q@q?+QlzF< zQ&gm?9A!o7%28OPvK*yFYRgevq`F9Xk@_M9Mk;JIB}Qs&HAP0MY&B&@>WmZ`sWeBa zky>*U8>u!&xsiHv6db9z)s!5mxz!XMsk+sa9jQA~c%<@3>5<wa#mE15^&RHNV6pj8 VNOLaC$jQh`b7p5}WM^bK{s0D?lEVN1 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Pacific b/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Pacific new file mode 100644 index 0000000000000000000000000000000000000000..9dad4f4c75b373635ccbe634798f8d9e587e36c1 GIT binary patch literal 2836 zcmd_rX;76_9LMpCq6mtfOq2-iq$YxZfTFmRxecHqDoA36O9F#ws1Rxy(nOgx#-Gfk zjgDqbP8phGV_AeYIW>)C&^T@pSt6t2f|j^+Z|8g7_Ntdn&ok%woVoAs_m?@lATPo5 zkEetEg~RiiJ=}Yg*-zDbDdz3{A!447GFxB2F5j&SGj;v0Ev=hBKppiK&pB4MQ%-ol zl9RQfPBpwMKkxWZ8fw<cFY8{G#;OAOwP2~7E}bmDrOuGwb7JI7<WOl!o}|uppRSrC zqE&P25Opq~t2$Q~qRuy6Ru^_(S1pI?)Wyo<>QePZxx8$@x>9jOTGt$qtA!uSwYl%e zAL*~kpJSer>w`<AZQwR_quVUG*{NLJY<pJUYR*%)kLBvWzDZHueaYJQew6ZTiPU~C zbW!bAcGm5e4HW<R5vIfRAn7<Z&;-O?kbw2$O`!T-0(X9?gD&rq&W+Wk%kjf1xVF-C z{j^$j+wqZBuT`o$)`{-Esz}{guw3`Zo~c4oGj-1q!&R@yVLG&LhTIhxs>9kPN?7Yq zbNA_95?<HS^geJy`s{8q_iQ~Wx@3^P_n9xGZ&tAGx9EiGpLj{%H|cXVAmm3K5mluk zye%d&s7ysR{9vNaEl`7McAMz>Qi-YBU}E>olfk7=n79q&BtHKYolw+Yh9np3p&1<| zF(OM3OK6ti0ZBS3yn{+Q8>UCxI;%z=x~)f@{8o+L6>9F^|ABg-;-(q%#(MQ&;VCn= ze20unuQB5nz9bU{8#8gj5}A0lUMI)AsFLgV>eS%HDs|6hJ*j1?n*8P-Gv(+aNn5?q zO#Nhvq|aGlrfrIq>7%pFj1nao;iF9E%vQ;~-P>d({v=svM(SC8uBcgGhwE%_y_&t< zs~>LItLBt9>PKoetDJ=g_1vmeYF=7{nZI_UEQqN!kLItCg~8iQZgRHdwv?Ovh*6S% zIL{OW^p=91DP~cVPafNps}~;$S4&Eg_2boERhSj2msT{YWy3n_<%I`TQAmp}PT#JI zeSxMVsa8rF&YP8?+hk?UVY8~OT%N3|HcuVPlhvh_=IMPYQkqj_)@+HAc7FD4@9*IH z-+6t$$^jma&-a%2`TKkoWu8v%-o<^@l(bCGv<dcP*z=G*(=zQp+T-zapUi(z0-t?y z{KIOIA|O>j%7D}XDFjjpr!56i3#1rGHIQ;3^*{=OR0JsrQWK;oNL7%sAay|sgH#47 z4N@DYEe=v0r!5asAEZD?g^&^<HA0GnR0$~)QYWNPNTrZcA+<t^g;WbEm($h@DHu{Q zq-5x7#)YEs*s1|#L+XYU4yhbcI;3_;@tn4LNco($en<h43L+&$YKRmOsUlKFq>e}- zkxC+^L~4l?6R9RrPNbelL7lduNJ){JB1J{2ij)<pD^ggbvPfx>+9Jh8s*9A@Y3qv= z*l8<_lo+WoQe>pcNSTp3BZWpPjg%UxHBxM(+DN&PdLspQ+KMA3M{14~9jQ7}cBJk| z;gQNCrAKOy6d$QRQhukcKe7N$y8_4(IPDrBi-4>GvJA*NAPa%41hN#!S|E#otOl|i zPP-n+f;jDpAWP!3Yl18avMR{3AnSrG46-uF(jaStEDo|d$nqfTgDjBKt`M?BPP<0P zB023UA<KlU6S7dqN+C;ytQE3Y$Z8?Wg{&8{U{1SY$dWnjnjwqkw5x_J8?tW5!XYb% jEFH3T`2StJAUlLfb`Yb}hQubs#zm*a$H&IU#s&Qiukn{d literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Samoa b/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Samoa new file mode 100644 index 0000000000000000000000000000000000000000..cb56709a77dedb471150f4907771bf38f1879ba4 GIT binary patch literal 175 zcmWHE%1kq2zzdjwvdlot(EubSvi{~^1d42|U|{(FKmG@ZObuXQ@$n5|2o4Tm2qD3| V|3Hvudx8T*6Ec?zXt<#v7XWnZBuoGR literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/UTC b/venv/lib/python3.8/site-packages/pytz/zoneinfo/UTC new file mode 100644 index 0000000000000000000000000000000000000000..91558be0c2bf903b2364215ba26d5227d6126508 GIT binary patch literal 114 hcmWHE%1kq2AP5+NDp(+@LPMMxLdep^1=MQ51psH$25|rY literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Universal b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Universal new file mode 100644 index 0000000000000000000000000000000000000000..91558be0c2bf903b2364215ba26d5227d6126508 GIT binary patch literal 114 hcmWHE%1kq2AP5+NDp(+@LPMMxLdep^1=MQ51psH$25|rY literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/W-SU b/venv/lib/python3.8/site-packages/pytz/zoneinfo/W-SU new file mode 100644 index 0000000000000000000000000000000000000000..ddb3f4e99a1030f33b56fad986c8d9c16e59eb32 GIT binary patch literal 1535 zcmd_pOGs2v0Eh8&eK(rb!qglm&2)U$sA*0)IyEzjsUbNPSW%Qng3+OZ6j}@+wy8i0 zTv(<w>Y|s6YLnFvfkYNAS_B#d(ZT{b1Q9Ad&UZz$TD9&D_x_Go1;Ov{Z)$BR5`SH5 z^c!xj-TLO770{2~!?v;O6<<2~a%X1yzByZObnc(+f7>=aAe@1L@*#I{^@&i>RWve~ zaC~IY6&@P4`5GPslaD0WhbPu1O}P_eCL0pxR)vy2#ZM$pdfe;AuS}$j_ABe{Zk2lN zys}+9t=6AwR%vZ}Rr<jywV`gS$|%oP8}pM@rq!adV&|1T(k|^^lVtYC#6V8_(?HIf zIhp(Xv&_3cCG&%?WWm)Za#QC$x%o`LbToI%!b78~=v0p?cJ-+(dpcA}YCx419Z;p; zkE*hic3Jk$tDN&qa@*r9wSBT&mJfNP>yb@XbY;rQULoBr(Q-$pRqgamOV6<%%A5I8 z`aJJdRpcF6o$*Xn&%97I;XzgN`j*=Dp-a`?y`<{KZ_4`1CzZc0^@tH379J565g8R7 z6CJf8Dth5#iCy-ITe<9u<=^=89B&aK!>RufJR^iCykNxW^I6W7Jw}`mWo|?Nw{jgK zVewqmU?dA+O%tiVzt43T>5K2n+)F>t@7C4(MLl<;zP&sez51>dd5#j{^ZE6yUz(S} z(^$BcUYI8#{QuC`Pkrrs7#c%5Ls~<6Gu6!@-68EE{h8_pkq%9Di%5^Ax=Ex<q)q-* z`a~K<IyKd;BE2HbBHbeGBK;x_BON0xBRwNcBV8kHBYh){Bb_6yo9f<?=8^7Ab^A#F z$Oe!dAX`B8fNTQU1+oofAIL_KogiC5_F}3xgY3psZwJ{AvLR$g$d-^jA)7*Wg=`Di s7qT&AXUNu&y&;=Jc4w-$hwRT(ZxGobvPEQ%$R_cB-=#%wxuDqc3lb5KyZ`_I literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/WET b/venv/lib/python3.8/site-packages/pytz/zoneinfo/WET new file mode 100644 index 0000000000000000000000000000000000000000..c27390b5b638399057d5f5c6d09ef8c81d5f01c1 GIT binary patch literal 1905 zcmdVaT}+h)9LMp)h-J*^4~n3?Wkf(7;qa;uM>9My3RK`Iq#`NEiy{RP1HxE~F;~p} z+?b6O%NAqJDSCl*f!5S?wv4qk)~uXcuJ`8J)cMlbdcKd|b=6h#VTaGNb8)Wz-(PT3 zYg4x8U(W;1H+*>doDc60Jv`o^h_{#6BZC21SH2<}Qxz4A)q;vOwlL?8qLcs7q6I%F zCiE-CT>Dh9SB`4&HwU%k%znk4IBD^RCoSQ<_bqW)mel`-J=)f3OSd%GW930hE(+M= z-h4}mPqioJ$69Jwu~Kj3D($BfrOz(XlV=~)Q&YF(9sf<sM!r+V;FrqmIw4=<5oOg~ zwCv6)%kfWJZq)(HOBl2K>>kUX8?Y5|BU*83n-%=st-_PV_Vo9)Dw?R5f4WdBhgNIV zyYYIaDOsxr3+&mFFcmk(*_xDJ6eymvlCUpSnta(xul{Uhp{J~D=Da<3<wJXZ@{pBZ z_)Hc1hHdTP545hm-PRAksmhwSRMoaa)yvxyEHBlDn6=vIP1nYoKGjB-Snan_df`Tz zZTk4SHqVCJmV=R2H}$7&9k^!oBQy45{j6=<^SidM`otRQE~qhS)OPqM)im$8niHhv zU*A#7T&G&k_iE>*pmu$<S#9S!Z1-Nj+9#^*rIsYUJd|f0l||Os6l1SsC0bYDw!IqZ zvF^-hb^rCF^+eoM&)1(@@70UyJ2qjj%}lF*^tAR&j_LK@aSiMnP>ARM`s3U@VIEI} zg*Y#F|MN{vpgQQO2?RYM_nzQ?I9q;`(?!k~Ibr0CkyA#_898a>tdY}3&Ko&#SLe); zQ%BAnIeFylk<&-cA4veo07(JK0Z9VM0!ahO14#tQ#MMa!$puLU$p%RW$p=XY$p}da z$q7jc$qGpe$qPvg$;{PB4av>bNe;;lNe{^nNf5~pNfF5rNfOBtNfXHvNfgNxNfpV} z)kzk~*40TD$rni&$rwo)$r(u+$r?!;$s0)=$s9=?$=%gS9?9O-Ngv4{nE+%4kSRds z0GR}27LaK`<^h=qWG0ZQK;{CO3}iN3o#{a41DOzHMvy5%<^-7(WLA)ALFNUS7-VLU zsX^ujnH*$xT%GAb=Ev2UAY_J+DMIE5nIvSEkZHpEWS+vEt@1Hi-in-zybNDvmbW6y H$6NS60s5Ht literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Zulu b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Zulu new file mode 100644 index 0000000000000000000000000000000000000000..91558be0c2bf903b2364215ba26d5227d6126508 GIT binary patch literal 114 hcmWHE%1kq2AP5+NDp(+@LPMMxLdep^1=MQ51psH$25|rY literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/iso3166.tab b/venv/lib/python3.8/site-packages/pytz/zoneinfo/iso3166.tab new file mode 100644 index 0000000..a4ff61a --- /dev/null +++ b/venv/lib/python3.8/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 (2015-05-02): +# 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 N976 (2018-11-06). 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 Southern & Antarctic Lands +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/venv/lib/python3.8/site-packages/pytz/zoneinfo/leapseconds b/venv/lib/python3.8/site-packages/pytz/zoneinfo/leapseconds new file mode 100644 index 0000000..cf0df04 --- /dev/null +++ b/venv/lib/python3.8/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 2021 Dec 28 00:00:00 + +# POSIX timestamps for the data in this file: +#updated 1467936000 (2016-07-08 00:00:00 UTC) +#expires 1640649600 (2021-12-28 00:00:00 UTC) + +# Updated through IERS Bulletin C61 +# File expires on: 28 December 2021 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/tzdata.zi b/venv/lib/python3.8/site-packages/pytz/zoneinfo/tzdata.zi new file mode 100644 index 0000000..aaf67f0 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pytz/zoneinfo/tzdata.zi @@ -0,0 +1,4459 @@ +# 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 +L Africa/Abidjan Africa/Bamako +L Africa/Abidjan Africa/Banjul +L Africa/Abidjan Africa/Conakry +L Africa/Abidjan Africa/Dakar +L Africa/Abidjan Africa/Freetown +L Africa/Abidjan Africa/Lome +L Africa/Abidjan Africa/Nouakchott +L Africa/Abidjan Africa/Ouagadougou +L Africa/Abidjan Atlantic/St_Helena +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 - +Z Africa/Cairo 2:5:9 - LMT 1900 O +2 K EE%sT +R GH 1919 o - N 24 0 0:20 +0020 +R GH 1920 1942 - Ja 1 2 0 GMT +R GH 1920 1939 - S 1 2 0:20 +0020 +R GH 1940 1941 - May 1 2 0:20 +0020 +R GH 1950 1955 - S 1 2 0:30 +0030 +R GH 1951 1956 - Ja 1 2 0 GMT +Z Africa/Accra -0:0:52 - LMT 1915 N 2 +0 GH %s 1942 F 8 +0:30 - +0030 1946 Ja 6 +0 GH %s +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 +L Africa/Nairobi Africa/Addis_Ababa +L Africa/Nairobi Africa/Asmara +L Africa/Nairobi Africa/Dar_es_Salaam +L Africa/Nairobi Africa/Djibouti +L Africa/Nairobi Africa/Kampala +L Africa/Nairobi Africa/Mogadishu +L Africa/Nairobi Indian/Antananarivo +L Africa/Nairobi Indian/Comoro +L Africa/Nairobi Indian/Mayotte +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 30 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 - F 2 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 - N 7 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 12 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 17 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 19 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 24 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 29 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 - Jul 5 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 - Jun 3 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 +L Africa/Maputo Africa/Blantyre +L Africa/Maputo Africa/Bujumbura +L Africa/Maputo Africa/Gaborone +L Africa/Maputo Africa/Harare +L Africa/Maputo Africa/Kigali +L Africa/Maputo Africa/Lubumbashi +L Africa/Maputo Africa/Lusaka +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 +L Africa/Lagos Africa/Bangui +L Africa/Lagos Africa/Brazzaville +L Africa/Lagos Africa/Douala +L Africa/Lagos Africa/Kinshasa +L Africa/Lagos Africa/Libreville +L Africa/Lagos Africa/Luanda +L Africa/Lagos Africa/Malabo +L Africa/Lagos Africa/Niamey +L Africa/Lagos Africa/Porto-Novo +Z Indian/Reunion 3:41:52 - LMT 1911 Jun +4 - +04 +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 +Z Indian/Mahe 3:41:48 - LMT 1907 +4 - +04 +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 +L Africa/Johannesburg Africa/Maseru +L Africa/Johannesburg Africa/Mbabane +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 +Z Indian/Kerguelen 0 - -00 1950 +5 - +05 +Z Antarctica/DumontDUrville 0 - -00 1947 +10 - +10 1952 Ja 14 +0 - -00 1956 N +10 - +10 +Z Antarctica/Syowa 0 - -00 1957 Ja 29 +3 - +03 +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/Vostok 0 - -00 1957 D 16 +6 - +06 +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/Brunei 7:39:40 - LMT 1926 Mar +7:30 - +0730 1933 +8 - +08 +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 30 0:36:42 +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 +L Asia/Nicosia Europe/Nicosia +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 23:47:12 +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 1978 1980 - Mar 20 24 1 - +R i 1978 o - O 20 24 0 - +R i 1979 o - S 18 24 0 - +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 2023 - Mar 21 24 1 - +R i 2021 2023 - S 21 24 0 - +R i 2024 o - Mar 20 24 1 - +R i 2024 o - S 20 24 0 - +R i 2025 2027 - Mar 21 24 1 - +R i 2025 2027 - S 21 24 0 - +R i 2028 2029 - Mar 20 24 1 - +R i 2028 2029 - S 20 24 0 - +R i 2030 2031 - Mar 21 24 1 - +R i 2030 2031 - S 21 24 0 - +R i 2032 2033 - Mar 20 24 1 - +R i 2032 2033 - S 20 24 0 - +R i 2034 2035 - Mar 21 24 1 - +R i 2034 2035 - S 21 24 0 - +R i 2036 2037 - Mar 20 24 1 - +R i 2036 2037 - S 20 24 0 - +R i 2038 2039 - Mar 21 24 1 - +R i 2038 2039 - S 21 24 0 - +R i 2040 2041 - Mar 20 24 1 - +R i 2040 2041 - S 20 24 0 - +R i 2042 2043 - Mar 21 24 1 - +R i 2042 2043 - S 21 24 0 - +R i 2044 2045 - Mar 20 24 1 - +R i 2044 2045 - S 20 24 0 - +R i 2046 2047 - Mar 21 24 1 - +R i 2046 2047 - S 21 24 0 - +R i 2048 2049 - Mar 20 24 1 - +R i 2048 2049 - S 20 24 0 - +R i 2050 2051 - Mar 21 24 1 - +R i 2050 2051 - S 21 24 0 - +R i 2052 2053 - Mar 20 24 1 - +R i 2052 2053 - S 20 24 0 - +R i 2054 2055 - Mar 21 24 1 - +R i 2054 2055 - S 21 24 0 - +R i 2056 2057 - Mar 20 24 1 - +R i 2056 2057 - S 20 24 0 - +R i 2058 2059 - Mar 21 24 1 - +R i 2058 2059 - S 21 24 0 - +R i 2060 2062 - Mar 20 24 1 - +R i 2060 2062 - S 20 24 0 - +R i 2063 o - Mar 21 24 1 - +R i 2063 o - S 21 24 0 - +R i 2064 2066 - Mar 20 24 1 - +R i 2064 2066 - S 20 24 0 - +R i 2067 o - Mar 21 24 1 - +R i 2067 o - S 21 24 0 - +R i 2068 2070 - Mar 20 24 1 - +R i 2068 2070 - S 20 24 0 - +R i 2071 o - Mar 21 24 1 - +R i 2071 o - S 21 24 0 - +R i 2072 2074 - Mar 20 24 1 - +R i 2072 2074 - S 20 24 0 - +R i 2075 o - Mar 21 24 1 - +R i 2075 o - S 21 24 0 - +R i 2076 2078 - Mar 20 24 1 - +R i 2076 2078 - S 20 24 0 - +R i 2079 o - Mar 21 24 1 - +R i 2079 o - S 21 24 0 - +R i 2080 2082 - Mar 20 24 1 - +R i 2080 2082 - S 20 24 0 - +R i 2083 o - Mar 21 24 1 - +R i 2083 o - S 21 24 0 - +R i 2084 2086 - Mar 20 24 1 - +R i 2084 2086 - S 20 24 0 - +R i 2087 o - Mar 21 24 1 - +R i 2087 o - S 21 24 0 - +R i 2088 ma - Mar 20 24 1 - +R i 2088 ma - S 20 24 0 - +Z Asia/Tehran 3:25:44 - LMT 1916 +3:25:44 - TMT 1946 +3:30 - +0330 1977 N +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 ma - Mar lastTh 24 1 S +R J 2014 ma - O lastF 0s 0 - +Z Asia/Amman 2:23:44 - LMT 1931 +2 J EE%sT +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 ma - Mar lastSu 0 1 S +R l 1993 1998 - S lastSu 0 0 - +R l 1999 ma - O lastSu 0 0 - +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/Kuala_Lumpur 6:46:46 - 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 1982 +8 - +08 +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>=24 1 1 S +R P 2016 2018 - O Sa>=24 1 0 - +R P 2019 o - Mar 29 0 1 S +R P 2019 o - O Sa>=24 0 0 - +R P 2020 ma - Mar Sa>=24 0 1 S +R P 2020 ma - O Sa>=24 1 0 - +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 +L Asia/Qatar Asia/Bahrain +Z Asia/Riyadh 3:6:52 - LMT 1947 Mar 14 +3 - +03 +L Asia/Riyadh Asia/Aden +L Asia/Riyadh Asia/Kuwait +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 1982 +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 ma - Mar lastF 0 1 S +R S 2009 ma - O lastF 0 0 - +Z Asia/Damascus 2:25:12 - LMT 1920 +2 S EE%sT +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 +05/+06 1991 S 9 2s +5 - +05 +Z Asia/Bangkok 6:42:4 - LMT 1880 +6:42:4 - BMT 1920 Ap +7 - +07 +L Asia/Bangkok Asia/Phnom_Penh +L Asia/Bangkok Asia/Vientiane +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 +L Asia/Dubai Asia/Muscat +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:40 - 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 +Z Indian/Christmas 7:2:52 - LMT 1895 F +7 - +07 +Z Indian/Cocos 6:27:40 - LMT 1900 +6:30 - +0630 +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 ma - Ja Su>=12 3 0 - +R FJ 2019 o - N Su>=8 2 1 - +R FJ 2020 o - D 20 2 1 - +R FJ 2021 ma - N Su>=8 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 +L Pacific/Guam Pacific/Saipan +Z Pacific/Tarawa 11:32:4 - LMT 1901 +12 - +12 +Z Pacific/Enderbury -11:24:20 - LMT 1901 +-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/Majuro 11:24:48 - LMT 1901 +11 - +11 1914 O +9 - +09 1919 F +11 - +11 1937 +10 - +10 1941 Ap +9 - +09 1944 Ja 30 +11 - +11 1969 O +12 - +12 +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/Chuuk -13:52:52 - LMT 1844 D 31 +10:7:8 - LMT 1901 +10 - +10 1914 O +9 - +09 1919 F +10 - +10 1941 Ap +9 - +09 1945 Au +10 - +10 +Z Pacific/Pohnpei -13:27:8 - LMT 1844 D 31 +10:32:52 - LMT 1901 +11 - +11 1914 O +9 - +09 1919 F +11 - +11 1937 +10 - +10 1941 Ap +9 - +09 1945 Au +11 - +11 +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 +L Pacific/Auckland Antarctica/McMurdo +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 -10:39:4 - LMT 1901 +-10:30 - -1030 1978 N 12 +-10 CK -10/-0930 +Z Pacific/Niue -11:19:40 - LMT 1901 +-11:20 - -1120 1951 +-11:30 - -1130 1978 O +-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 +L Pacific/Pago_Pago Pacific/Midway +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 ma - Ap Su>=1 4 0 - +R WS 2012 ma - 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:20 - LMT 1901 +12:20 - +1220 1941 +13 - +13 1999 +13 TO +13/+14 +Z Pacific/Funafuti 11:56:52 - LMT 1901 +12 - +12 +Z Pacific/Wake 11:6:28 - LMT 1901 +12 - +12 +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 +Z Pacific/Wallis 12:15:20 - LMT 1901 +12 - +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 1 0s +0 G %s 1968 O 27 +1 - BST 1971 O 31 2u +0 G %s 1996 +0 E GMT/BST +L Europe/London Europe/Jersey +L Europe/London Europe/Guernsey +L Europe/London Europe/Isle_of_Man +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 - 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 +R D 1916 o - May 14 23 1 S +R D 1916 o - S 30 23 0 - +R D 1940 o - May 15 0 1 S +R D 1945 o - Ap 2 2s 1 S +R D 1945 o - Au 15 2s 0 - +R D 1946 o - May 1 2s 1 S +R D 1946 o - S 1 2s 0 - +R D 1947 o - May 4 2s 1 S +R D 1947 o - Au 10 2s 0 - +R D 1948 o - May 9 2s 1 S +R D 1948 o - Au 8 2s 0 - +Z Europe/Copenhagen 0:50:20 - LMT 1890 +0:50:20 - CMT 1894 +1 D CE%sT 1942 N 2 2s +1 c CE%sT 1945 Ap 2 2 +1 D CE%sT 1980 +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 +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 +L Europe/Helsinki Europe/Mariehamn +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 +L Europe/Zurich Europe/Busingen +Z Europe/Gibraltar -0:21:24 - LMT 1880 Au 2 0s +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 w 1917 1919 - F 19 23 1 - +R w 1917 o - O 21 1 0 - +R w 1918 1919 - N 16 1 0 - +R w 1921 o - Mar 19 23 1 - +R w 1921 o - Jun 23 1 0 - +R w 1939 o - Ap 29 23 1 - +R w 1939 o - O 29 2 0 - +R w 1940 o - F 25 2 1 - +R w 1940 1941 - N Su>=2 1s 0 - +R w 1941 1942 - Mar Su>=2 1s 1 - +R w 1943 1946 - Mar Su>=1 1s 1 - +R w 1942 1948 - O Su>=22 1s 0 - +R w 1947 1967 - Ap Su>=1 1s 1 - +R w 1949 o - O 30 1s 0 - +R w 1950 1966 - O Su>=22 1s 0 - +R w 1967 o - O 29 1s 0 - +Z Atlantic/Reykjavik -1:28 - LMT 1908 +-1 w -01/+00 1968 Ap 7 1s +0 - GMT +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 23:49:56 +1 I CE%sT 1943 S 10 +1 c CE%sT 1944 Jun 4 +1 I CE%sT 1980 +1 E CE%sT +L Europe/Rome Europe/Vatican +L Europe/Rome Europe/San_Marino +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 +L Europe/Zurich Europe/Vaduz +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 LX 1916 o - May 14 23 1 S +R LX 1916 o - O 1 1 0 - +R LX 1917 o - Ap 28 23 1 S +R LX 1917 o - S 17 1 0 - +R LX 1918 o - Ap M>=15 2s 1 S +R LX 1918 o - S M>=15 2s 0 - +R LX 1919 o - Mar 1 23 1 S +R LX 1919 o - O 5 3 0 - +R LX 1920 o - F 14 23 1 S +R LX 1920 o - O 24 2 0 - +R LX 1921 o - Mar 14 23 1 S +R LX 1921 o - O 26 2 0 - +R LX 1922 o - Mar 25 23 1 S +R LX 1922 o - O Su>=2 1 0 - +R LX 1923 o - Ap 21 23 1 S +R LX 1923 o - O Su>=2 2 0 - +R LX 1924 o - Mar 29 23 1 S +R LX 1924 1928 - O Su>=2 1 0 - +R LX 1925 o - Ap 5 23 1 S +R LX 1926 o - Ap 17 23 1 S +R LX 1927 o - Ap 9 23 1 S +R LX 1928 o - Ap 14 23 1 S +R LX 1929 o - Ap 20 23 1 S +Z Europe/Luxembourg 0:24:36 - LMT 1904 Jun +1 LX CE%sT 1918 N 25 +0 LX WE%sT 1929 O 6 2s +0 b WE%sT 1940 May 14 3 +1 c WE%sT 1944 S 18 3 +1 b CE%sT 1977 +1 E CE%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 0s +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 +Z Europe/Monaco 0:29:32 - LMT 1892 Jun +0:9:21 - PMT 1911 Mar 29 +0 F WE%sT 1945 S 16 3 +1 F CE%sT 1977 +1 E CE%sT +R N 1916 o - May 1 0 1 NST +R N 1916 o - O 1 0 0 AMT +R N 1917 o - Ap 16 2s 1 NST +R N 1917 o - S 17 2s 0 AMT +R N 1918 1921 - Ap M>=1 2s 1 NST +R N 1918 1921 - S lastM 2s 0 AMT +R N 1922 o - Mar lastSu 2s 1 NST +R N 1922 1936 - O Su>=2 2s 0 AMT +R N 1923 o - Jun F>=1 2s 1 NST +R N 1924 o - Mar lastSu 2s 1 NST +R N 1925 o - Jun F>=1 2s 1 NST +R N 1926 1931 - May 15 2s 1 NST +R N 1932 o - May 22 2s 1 NST +R N 1933 1936 - May 15 2s 1 NST +R N 1937 o - May 22 2s 1 NST +R N 1937 o - Jul 1 0 1 S +R N 1937 1939 - O Su>=2 2s 0 - +R N 1938 1939 - May 15 2s 1 S +R N 1945 o - Ap 2 2s 1 S +R N 1945 o - S 16 2s 0 - +Z Europe/Amsterdam 0:19:32 - LMT 1835 +0:19:32 N %s 1937 Jul +0:20 N +0020/+0120 1940 May 16 +1 c CE%sT 1945 Ap 2 2 +1 N CE%sT 1977 +1 E CE%sT +R NO 1916 o - May 22 1 1 S +R NO 1916 o - S 30 0 0 - +R NO 1945 o - Ap 2 2s 1 S +R NO 1945 o - O 1 2s 0 - +R NO 1959 1964 - Mar Su>=15 2s 1 S +R NO 1959 1965 - S Su>=15 2s 0 - +R NO 1965 o - Ap 25 2s 1 S +Z Europe/Oslo 0:43 - LMT 1895 +1 NO CE%sT 1940 Au 10 23 +1 c CE%sT 1945 Ap 2 2 +1 NO CE%sT 1980 +1 E CE%sT +L Europe/Oslo Arctic/Longyearbyen +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 1949 - Ap Su>=1 2s 1 S +R p 1947 1949 - O Su>=1 2s 0 - +R p 1951 1965 - Ap Su>=1 2s 1 S +R p 1951 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 +2 e EE%sT 1994 May +3 e MSK/MSD 1996 Mar 31 0s +3 1 MSD 1996 O 27 3s +3 R MSK/MSD 1997 +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 +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 2018 O 28 2s +4 - +04 2020 D 27 2s +3 - +03 +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 +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 +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 +L Europe/Belgrade Europe/Ljubljana +L Europe/Belgrade Europe/Podgorica +L Europe/Belgrade Europe/Sarajevo +L Europe/Belgrade Europe/Skopje +L Europe/Belgrade Europe/Zagreb +L Europe/Prague Europe/Bratislava +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 1900 D 31 23:45:16 +0 s WE%sT 1940 Mar 16 23 +1 s CE%sT 1979 +1 E CE%sT +Z Africa/Ceuta -0:21:16 - LMT 1900 D 31 23:38:44 +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 +Z Europe/Stockholm 1:12:12 - LMT 1879 +1:0:14 - SET 1900 +1 - CET 1916 May 14 23 +1 1 CEST 1916 O 1 1 +1 - CET 1980 +1 E CE%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 +L Europe/Istanbul Asia/Istanbul +Z Europe/Kiev 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 e EE%sT 1995 +2 E EE%sT +Z Europe/Uzhgorod 1:29:12 - LMT 1890 O +1 - CET 1940 +1 c CE%sT 1944 O +1 1 CEST 1944 O 26 +1 - CET 1945 Jun 29 +3 R MSK/MSD 1990 +3 - MSK 1990 Jul 1 2 +1 - CET 1991 Mar 31 3 +2 - EET 1992 +2 e EE%sT 1995 +2 E EE%sT +Z Europe/Zaporozhye 2:20:40 - LMT 1880 +2:20 - +0220 1924 May 2 +2 - EET 1930 Jun 21 +3 - MSK 1941 Au 25 +1 c CE%sT 1943 O 25 +3 R MSK/MSD 1991 Mar 31 2 +2 e EE%sT 1995 +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 12:3:58 +-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 12:9:24 +-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 12:14:48 +-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 12:14:21 +-7 u M%sT 2003 O 26 2 +-6 u C%sT +Z America/North_Dakota/Beulah -6:47:7 - LMT 1883 N 18 12:12:53 +-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 12:0:4 +-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 12:7:2 +-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 11:31:42 +-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 12:15:11 +-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 12:15:22 +-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 12:14:37 +-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 12:9:53 +-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 12:12:57 +-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 12:10:53 +-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 12:13:30 +-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 12:13:35 +-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 12:19:44 +-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 12:16:58 +-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 12:20:36 +-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 +Z America/Blanc-Sablon -3:48:28 - LMT 1884 +-4 C A%sT 1970 +-4 - AST +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 +Z America/Thunder_Bay -5:57 - LMT 1895 +-6 - CST 1910 +-5 - EST 1942 +-5 C E%sT 1970 +-5 t E%sT 1973 +-5 - EST 1974 +-5 C E%sT +Z America/Nipigon -5:53:4 - LMT 1895 +-5 C E%sT 1940 S 29 +-5 1 EDT 1942 F 9 2s +-5 C E%sT +Z America/Rainy_River -6:18:16 - LMT 1895 +-6 C C%sT 1940 S 29 +-6 1 CDT 1942 F 9 2s +-6 C C%sT +Z America/Atikokan -6:6:28 - LMT 1895 +-6 C C%sT 1940 S 29 +-6 1 CDT 1942 F 9 2s +-6 C C%sT 1945 S 30 2 +-5 - EST +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 +Z America/Creston -7:46:4 - LMT 1884 +-7 - MST 1916 O +-8 - PST 1918 Jun 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 1965 o - Ap lastSu 0 2 DD +R Y 1965 o - O lastSu 2 0 S +R Y 1980 1986 - Ap lastSu 2 1 D +R Y 1980 2006 - O lastSu 2 0 S +R Y 1987 2006 - Ap Su>=1 2 1 D +Z America/Pangnirtung 0 - -00 1921 +-4 Y A%sT 1995 Ap Su>=1 2 +-5 C E%sT 1999 O 31 2 +-6 C C%sT 2000 O 29 2 +-5 C E%sT +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/Yellowknife 0 - -00 1935 +-7 Y M%sT 1980 +-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 1967 May 28 +-8 Y P%sT 1980 +-8 C P%sT 2020 N +-7 - MST +Z America/Dawson -9:17:40 - LMT 1900 Au 20 +-9 Y Y%sT 1973 O 28 +-8 Y P%sT 1980 +-8 C P%sT 2020 N +-7 - MST +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 ma - Ap Su>=1 2 1 D +R m 2002 ma - O lastSu 2 0 S +Z America/Cancun -5:47:4 - LMT 1922 Ja 1 0:12:56 +-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 0:1:32 +-6 - CST 1981 D 23 +-5 - EST 1982 D 2 +-6 m C%sT +Z America/Matamoros -6:40 - LMT 1921 D 31 23:20 +-6 - CST 1988 +-6 u C%sT 1989 +-6 m C%sT 2010 +-6 u C%sT +Z America/Monterrey -6:41:16 - LMT 1921 D 31 23:18:44 +-6 - CST 1988 +-6 u C%sT 1989 +-6 m C%sT +Z America/Mexico_City -6:36:36 - LMT 1922 Ja 1 0:23:24 +-7 - MST 1927 Jun 10 23 +-6 - CST 1930 N 15 +-7 - MST 1931 May 1 23 +-6 - CST 1931 O +-7 - MST 1932 Ap +-6 m C%sT 2001 S 30 2 +-6 - CST 2002 F 20 +-6 m C%sT +Z America/Ojinaga -6:57:40 - LMT 1922 Ja 1 0:2:20 +-7 - MST 1927 Jun 10 23 +-6 - CST 1930 N 15 +-7 - MST 1931 May 1 23 +-6 - CST 1931 O +-7 - MST 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 +Z America/Chihuahua -7:4:20 - LMT 1921 D 31 23:55:40 +-7 - MST 1927 Jun 10 23 +-6 - CST 1930 N 15 +-7 - MST 1931 May 1 23 +-6 - CST 1931 O +-7 - MST 1932 Ap +-6 - CST 1996 +-6 m C%sT 1998 +-6 - CST 1998 Ap Su>=1 3 +-7 m M%sT +Z America/Hermosillo -7:23:52 - LMT 1921 D 31 23:36:8 +-7 - MST 1927 Jun 10 23 +-6 - CST 1930 N 15 +-7 - MST 1931 May 1 23 +-6 - CST 1931 O +-7 - MST 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 1921 D 31 23:54:20 +-7 - MST 1927 Jun 10 23 +-6 - CST 1930 N 15 +-7 - MST 1931 May 1 23 +-6 - CST 1931 O +-7 - MST 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 1921 D 31 23:59 +-7 - MST 1927 Jun 10 23 +-6 - CST 1930 N 15 +-7 - MST 1931 May 1 23 +-6 - CST 1931 O +-7 - MST 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 0:11:56 +-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 BS 1942 o - May 1 24 1 W +R BS 1944 o - D 31 24 0 S +R BS 1945 o - F 1 0 1 W +R BS 1945 o - Au 14 23u 1 P +R BS 1945 o - O 17 24 0 S +R BS 1964 1975 - O lastSu 2 0 S +R BS 1964 1975 - Ap lastSu 2 1 D +Z America/Nassau -5:9:30 - LMT 1912 Mar 2 +-5 BS E%sT 1976 +-5 u E%sT +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 1924 +-3:58:29 - BMT 1932 +-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 +L America/Panama America/Cayman +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 +L America/Curacao America/Aruba +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 ma - S Su>=2 4u 1 - +Z America/Santiago -4:42:46 - LMT 1890 +-4:42:46 - SMT 1910 Ja 10 +-5 - -05 1916 Jul +-4:42:46 - SMT 1918 S 10 +-4 - -04 1919 Jul +-4:42:46 - SMT 1927 S +-5 x -05/-04 1932 S +-4 - -04 1942 Jun +-5 - -05 1942 Au +-4 - -04 1946 Jul 15 +-4 1 -03 1946 S +-4 - -04 1947 Ap +-5 - -05 1947 May 21 23 +-4 x -04/-03 +Z America/Punta_Arenas -4:43:40 - LMT 1890 +-4:42:46 - SMT 1910 Ja 10 +-5 - -05 1916 Jul +-4:42:46 - SMT 1918 S 10 +-4 - -04 1919 Jul +-4:42:46 - SMT 1927 S +-5 x -05/-04 1932 S +-4 - -04 1942 Jun +-5 - -05 1942 Au +-4 - -04 1947 Ap +-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 - Ap 4 0 0 - +Z America/Bogota -4:56:16 - LMT 1884 Mar 13 +-4:56:16 - BMT 1914 N 23 +-5 CO -05/-04 +Z America/Curacao -4:35:47 - LMT 1912 F 12 +-4:30 - -0430 1965 +-4 - AST +L America/Curacao America/Lower_Princes +L America/Curacao America/Kralendijk +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:40 - LMT 1915 Mar +-3:45 - -0345 1975 Jul 31 +-3 - -03 1991 +-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 +Z America/Port_of_Spain -4:6:4 - LMT 1912 Mar 2 +-4 - AST +L America/Port_of_Spain America/Anguilla +L America/Port_of_Spain America/Antigua +L America/Port_of_Spain America/Dominica +L America/Port_of_Spain America/Grenada +L America/Port_of_Spain America/Guadeloupe +L America/Port_of_Spain America/Marigot +L America/Port_of_Spain America/Montserrat +L America/Port_of_Spain America/St_Barthelemy +L America/Port_of_Spain America/St_Kitts +L America/Port_of_Spain America/St_Lucia +L America/Port_of_Spain America/St_Thomas +L America/Port_of_Spain America/St_Vincent +L America/Port_of_Spain America/Tortola +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/GMT 0 - GMT +Z Etc/UTC 0 - UTC +L Etc/GMT GMT +L Etc/UTC Etc/Universal +L Etc/UTC Etc/Zulu +L Etc/GMT Etc/Greenwich +L Etc/GMT Etc/GMT-0 +L Etc/GMT Etc/GMT+0 +L Etc/GMT Etc/GMT0 +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 Africa/Nairobi Africa/Asmera +L Africa/Abidjan Africa/Timbuktu +L America/Argentina/Catamarca America/Argentina/ComodRivadavia +L America/Adak America/Atka +L America/Argentina/Buenos_Aires America/Buenos_Aires +L America/Argentina/Catamarca America/Catamarca +L America/Atikokan America/Coral_Harbour +L America/Argentina/Cordoba America/Cordoba +L America/Tijuana America/Ensenada +L America/Indiana/Indianapolis America/Fort_Wayne +L America/Nuuk America/Godthab +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/Toronto America/Montreal +L America/Rio_Branco America/Porto_Acre +L America/Argentina/Cordoba America/Rosario +L America/Tijuana America/Santa_Isabel +L America/Denver America/Shiprock +L America/Port_of_Spain America/Virgin +L Pacific/Auckland Antarctica/South_Pole +L Asia/Ashgabat Asia/Ashkhabad +L Asia/Kolkata Asia/Calcutta +L Asia/Shanghai Asia/Chongqing +L Asia/Shanghai Asia/Chungking +L Asia/Dhaka Asia/Dacca +L Asia/Shanghai Asia/Harbin +L Asia/Urumqi Asia/Kashgar +L Asia/Kathmandu Asia/Katmandu +L Asia/Macau Asia/Macao +L Asia/Yangon Asia/Rangoon +L Asia/Ho_Chi_Minh Asia/Saigon +L Asia/Jerusalem Asia/Tel_Aviv +L Asia/Thimphu Asia/Thimbu +L Asia/Makassar Asia/Ujung_Pandang +L Asia/Ulaanbaatar Asia/Ulan_Bator +L Atlantic/Faroe Atlantic/Faeroe +L Europe/Oslo Atlantic/Jan_Mayen +L Australia/Sydney Australia/ACT +L Australia/Sydney Australia/Canberra +L Australia/Hobart Australia/Currie +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/UTC Etc/UCT +L Europe/London Europe/Belfast +L Europe/Chisinau Europe/Tiraspol +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 Atlantic/Reykjavik 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 Pacific/Honolulu Pacific/Johnston +L Pacific/Pohnpei Pacific/Ponape +L Pacific/Pago_Pago Pacific/Samoa +L Pacific/Chuuk Pacific/Truk +L Pacific/Chuuk Pacific/Yap +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 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/zone.tab b/venv/lib/python3.8/site-packages/pytz/zoneinfo/zone.tab new file mode 100644 index 0000000..1f0128f --- /dev/null +++ b/venv/lib/python3.8/site-packages/pytz/zoneinfo/zone.tab @@ -0,0 +1,451 @@ +# 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 (2018-06-27): +# 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. +# +# 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 +4901-08816 America/Nipigon Eastern - ON, QC (no DST 1967-73) +CA +4823-08915 America/Thunder_Bay Eastern - ON (Thunder Bay) +CA +6344-06828 America/Iqaluit Eastern - NU (most east areas) +CA +6608-06544 America/Pangnirtung Eastern - NU (Pangnirtung) +CA +484531-0913718 America/Atikokan EST - ON (Atikokan); NU (Coral H) +CA +4953-09709 America/Winnipeg Central - ON (west); Manitoba +CA +4843-09434 America/Rainy_River Central - ON (Rainy R, Ft Frances) +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); SK (W) +CA +690650-1050310 America/Cambridge_Bay Mountain - NU (west) +CA +6227-11421 America/Yellowknife Mountain - NT (central) +CA +682059-1334300 America/Inuvik Mountain - NT (west) +CA +4906-11631 America/Creston MST - BC (Creston) +CA +5946-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 Chile (most areas) +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 Cyprus (most areas) +CY +3507+03357 Asia/Famagusta Northern Cyprus +CZ +5005+01426 Europe/Prague +DE +5230+01322 Europe/Berlin Germany (most areas) +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 Greenland (most areas) +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 -0308-17105 Pacific/Enderbury 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 Kazakhstan (most areas) +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 Marshall Islands (most areas) +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 Mongolia (most areas) +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 Time +MX +2105-08646 America/Cancun Eastern Standard Time - Quintana Roo +MX +2058-08937 America/Merida Central Time - Campeche, Yucatan +MX +2540-10019 America/Monterrey Central Time - Durango; Coahuila, Nuevo Leon, Tamaulipas (most areas) +MX +2550-09730 America/Matamoros Central Time US - Coahuila, Nuevo Leon, Tamaulipas (US border) +MX +2313-10625 America/Mazatlan Mountain Time - Baja California Sur, Nayarit, Sinaloa +MX +2838-10605 America/Chihuahua Mountain Time - Chihuahua (most areas) +MX +2934-10425 America/Ojinaga Mountain Time US - Chihuahua (US border) +MX +2904-11058 America/Hermosillo Mountain Standard Time - Sonora +MX +3232-11701 America/Tijuana Pacific Time US - Baja California +MX +2048-10515 America/Bahia_Banderas Central Time - Bahia de Banderas +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 New Zealand (most areas) +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 Papua New Guinea (most areas) +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); North 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 -2110-17510 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/Kiev Ukraine (most areas) +UA +4837+02218 Europe/Uzhgorod Transcarpathia +UA +4750+03510 Europe/Zaporozhye Zaporozhye and east Lugansk +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 - Arizona (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 Aleutian Islands +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/venv/lib/python3.8/site-packages/pytz/zoneinfo/zone1970.tab b/venv/lib/python3.8/site-packages/pytz/zoneinfo/zone1970.tab new file mode 100644 index 0000000..396e4d3 --- /dev/null +++ b/venv/lib/python3.8/site-packages/pytz/zoneinfo/zone1970.tab @@ -0,0 +1,383 @@ +# 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 a country has multiple 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 +2518+05518 Asia/Dubai +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 -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 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 Samoa, 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 +5050+00420 Europe/Brussels +BG +4241+02319 Europe/Sofia +BM +3217-06446 Atlantic/Bermuda +BN +0456+11455 Asia/Brunei +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 +BS +2505-07721 America/Nassau +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 +5125-05707 America/Blanc-Sablon AST - QC (Lower North Shore) +CA +4339-07923 America/Toronto Eastern - ON, QC (most areas) +CA +4901-08816 America/Nipigon Eastern - ON, QC (no DST 1967-73) +CA +4823-08915 America/Thunder_Bay Eastern - ON (Thunder Bay) +CA +6344-06828 America/Iqaluit Eastern - NU (most east areas) +CA +6608-06544 America/Pangnirtung Eastern - NU (Pangnirtung) +CA +484531-0913718 America/Atikokan EST - ON (Atikokan); NU (Coral H) +CA +4953-09709 America/Winnipeg Central - ON (west); Manitoba +CA +4843-09434 America/Rainy_River Central - ON (Rainy R, Ft Frances) +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); SK (W) +CA +690650-1050310 America/Cambridge_Bay Mountain - NU (west) +CA +6227-11421 America/Yellowknife Mountain - NT (central) +CA +682059-1334300 America/Inuvik Mountain - NT (west) +CA +4906-11631 America/Creston MST - BC (Creston) +CA +5946-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 +CH,DE,LI +4723+00832 Europe/Zurich Swiss time +CI,BF,GM,GN,ML,MR,SH,SL,SN,TG +0519-00402 Africa/Abidjan +CK -2114-15946 Pacific/Rarotonga +CL -3327-07040 America/Santiago Chile (most areas) +CL -5309-07055 America/Punta_Arenas Region of Magallanes +CL -2709-10926 Pacific/Easter Easter Island +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,AW,BQ,SX +1211-06900 America/Curacao +CX -1025+10543 Indian/Christmas +CY +3510+03322 Asia/Nicosia Cyprus (most areas) +CY +3507+03357 Asia/Famagusta Northern Cyprus +CZ,SK +5005+01426 Europe/Prague +DE +5230+01322 Europe/Berlin Germany (most areas) +DK +5540+01235 Europe/Copenhagen +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 +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 +GB,GG,IM,JE +513030-0000731 Europe/London +GE +4143+04449 Asia/Tbilisi +GF +0456-05220 America/Cayenne +GH +0533-00013 Africa/Accra +GI +3608-00521 Europe/Gibraltar +GL +6411-05144 America/Nuuk Greenland (most areas) +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 +IS +6409-02151 Atlantic/Reykjavik +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 +0125+17300 Pacific/Tarawa Gilbert Islands +KI -0308-17105 Pacific/Enderbury Phoenix Islands +KI +0152-15720 Pacific/Kiritimati Line Islands +KP +3901+12545 Asia/Pyongyang +KR +3733+12658 Asia/Seoul +KZ +4315+07657 Asia/Almaty Kazakhstan (most areas) +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 +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 +MH +0709+17112 Pacific/Majuro Marshall Islands (most areas) +MH +0905+16720 Pacific/Kwajalein Kwajalein +MM +1647+09610 Asia/Yangon +MN +4755+10653 Asia/Ulaanbaatar Mongolia (most areas) +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 +0410+07330 Indian/Maldives +MX +1924-09909 America/Mexico_City Central Time +MX +2105-08646 America/Cancun Eastern Standard Time - Quintana Roo +MX +2058-08937 America/Merida Central Time - Campeche, Yucatán +MX +2540-10019 America/Monterrey Central Time - Durango; Coahuila, Nuevo León, Tamaulipas (most areas) +MX +2550-09730 America/Matamoros Central Time US - Coahuila, Nuevo León, Tamaulipas (US border) +MX +2313-10625 America/Mazatlan Mountain Time - Baja California Sur, Nayarit, Sinaloa +MX +2838-10605 America/Chihuahua Mountain Time - Chihuahua (most areas) +MX +2934-10425 America/Ojinaga Mountain Time US - Chihuahua (US border) +MX +2904-11058 America/Hermosillo Mountain Standard Time - Sonora +MX +3232-11701 America/Tijuana Pacific Time US - Baja California +MX +2048-10515 America/Bahia_Banderas Central Time - Bahía de Banderas +MY +0310+10142 Asia/Kuala_Lumpur Malaysia (peninsula) +MY +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 +NL +5222+00454 Europe/Amsterdam +NO,SJ +5955+01045 Europe/Oslo +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,KY +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 Papua New Guinea (most areas) +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,BH +2517+05132 Asia/Qatar +RE,TF -2052+05528 Indian/Reunion Réunion, Crozet, Scattered Islands +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); North Kuril Is +RU +5301+15839 Asia/Kamchatka MSK+09 - Kamchatka +RU +6445+17729 Asia/Anadyr MSK+09 - Bering Sea +SA,KW,YE +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 +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 +TF -492110+0701303 Indian/Kerguelen Kerguelen, St Paul Island, Amsterdam Island +TH,KH,LA,VN +1345+10031 Asia/Bangkok Indochina (most areas) +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 -2110-17510 Pacific/Tongatapu +TR +4101+02858 Europe/Istanbul +TT,AG,AI,BL,DM,GD,GP,KN,LC,MF,MS,VC,VG,VI +1039-06131 America/Port_of_Spain +TV -0831+17913 Pacific/Funafuti +TW +2503+12130 Asia/Taipei +UA +5026+03031 Europe/Kiev Ukraine (most areas) +UA +4837+02218 Europe/Uzhgorod Transcarpathia +UA +4750+03510 Europe/Zaporozhye Zaporozhye and east Lugansk +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 - Arizona (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 Aleutian Islands +US,UM +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 Vietnam (south) +VU -1740+16825 Pacific/Efate +WF -1318-17610 Pacific/Wallis +WS -1350-17144 Pacific/Apia +ZA,LS,SZ -2615+02800 Africa/Johannesburg diff --git a/venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/INSTALLER b/venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/LICENSE b/venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/LICENSE new file mode 100644 index 0000000..67db858 --- /dev/null +++ b/venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/LICENSE @@ -0,0 +1,175 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. diff --git a/venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/METADATA b/venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/METADATA new file mode 100644 index 0000000..6aaa2dd --- /dev/null +++ b/venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/METADATA @@ -0,0 +1,103 @@ +Metadata-Version: 2.1 +Name: requests +Version: 2.25.1 +Summary: Python HTTP for Humans. +Home-page: https://requests.readthedocs.io +Author: Kenneth Reitz +Author-email: me@kennethreitz.org +License: Apache 2.0 +Project-URL: Documentation, https://requests.readthedocs.io +Project-URL: Source, https://github.com/psf/requests +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: Natural Language :: English +Classifier: License :: OSI Approved :: Apache Software 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.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.*, !=3.4.* +Description-Content-Type: text/markdown +Requires-Dist: chardet (<5,>=3.0.2) +Requires-Dist: idna (<3,>=2.5) +Requires-Dist: urllib3 (<1.27,>=1.21.1) +Requires-Dist: certifi (>=2017.4.17) +Provides-Extra: security +Requires-Dist: pyOpenSSL (>=0.14) ; extra == 'security' +Requires-Dist: cryptography (>=1.3.4) ; extra == 'security' +Provides-Extra: socks +Requires-Dist: PySocks (!=1.5.7,>=1.5.6) ; extra == 'socks' +Requires-Dist: win-inet-pton ; (sys_platform == "win32" and python_version == "2.7") and extra == 'socks' + +# Requests + +**Requests** is a simple, yet elegant HTTP library. + +```python +>>> import requests +>>> r = requests.get('https://api.github.com/user', auth=('user', 'pass')) +>>> r.status_code +200 +>>> r.headers['content-type'] +'application/json; charset=utf8' +>>> r.encoding +'utf-8' +>>> r.text +'{"type":"User"...' +>>> r.json() +{'disk_usage': 368627, 'private_gists': 484, ...} +``` + +Requests allows you to send HTTP/1.1 requests extremely easily. There’s no need to manually add query strings to your URLs, or to form-encode your `PUT` & `POST` data — but nowadays, just use the `json` method! + +Requests is one of the most downloaded Python package today, pulling in around `14M downloads / week`— according to GitHub, Requests is currently [depended upon](https://github.com/psf/requests/network/dependents?package_id=UGFja2FnZS01NzA4OTExNg%3D%3D) by `500,000+` repositories. You may certainly put your trust in this code. + +[![Downloads](https://pepy.tech/badge/requests/month)](https://pepy.tech/project/requests/month) +[![Supported Versions](https://img.shields.io/pypi/pyversions/requests.svg)](https://pypi.org/project/requests) +[![Contributors](https://img.shields.io/github/contributors/psf/requests.svg)](https://github.com/psf/requests/graphs/contributors) + +## Installing Requests and Supported Versions + +Requests is available on PyPI: + +```console +$ python -m pip install requests +``` + +Requests officially supports Python 2.7 & 3.5+. + +## Supported Features & Best–Practices + +Requests is ready for the demands of building robust and reliable HTTP–speaking applications, for the needs of today. + +- Keep-Alive & Connection Pooling +- International Domains and URLs +- Sessions with Cookie Persistence +- Browser-style TLS/SSL Verification +- Basic & Digest Authentication +- Familiar `dict`–like Cookies +- Automatic Content Decompression and Decoding +- Multi-part File Uploads +- SOCKS Proxy Support +- Connection Timeouts +- Streaming Downloads +- Automatic honoring of `.netrc` +- Chunked HTTP Requests + +## API Reference and User Guide available on [Read the Docs](https://requests.readthedocs.io) + +[![Read the Docs](https://raw.githubusercontent.com/psf/requests/master/ext/ss.png)](https://requests.readthedocs.io) + +--- + +[![Kenneth Reitz](https://raw.githubusercontent.com/psf/requests/master/ext/kr.png)](https://kennethreitz.org) [![Python Software Foundation](https://raw.githubusercontent.com/psf/requests/master/ext/psf.png)](https://www.python.org/psf) + + diff --git a/venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/RECORD b/venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/RECORD new file mode 100644 index 0000000..008165f --- /dev/null +++ b/venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/RECORD @@ -0,0 +1,42 @@ +requests-2.25.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +requests-2.25.1.dist-info/LICENSE,sha256=CeipvOyAZxBGUsFoaFqwkx54aPnIKEtm9a5u2uXxEws,10142 +requests-2.25.1.dist-info/METADATA,sha256=RuNh38uN0IMsRT3OwaTNB_WyGx6RMwwQoMwujXfkUVM,4168 +requests-2.25.1.dist-info/RECORD,, +requests-2.25.1.dist-info/WHEEL,sha256=Z-nyYpwrcSqxfdux5Mbn_DQ525iP7J2DG3JgGvOYyTQ,110 +requests-2.25.1.dist-info/top_level.txt,sha256=fMSVmHfb5rbGOo6xv-O_tUX6j-WyixssE-SnwcDRxNQ,9 +requests/__init__.py,sha256=rsmg7xmbbCE_zmDcG6EDk_pyvdEfadztdBaWIkInlH8,4141 +requests/__pycache__/__init__.cpython-38.pyc,, +requests/__pycache__/__version__.cpython-38.pyc,, +requests/__pycache__/_internal_utils.cpython-38.pyc,, +requests/__pycache__/adapters.cpython-38.pyc,, +requests/__pycache__/api.cpython-38.pyc,, +requests/__pycache__/auth.cpython-38.pyc,, +requests/__pycache__/certs.cpython-38.pyc,, +requests/__pycache__/compat.cpython-38.pyc,, +requests/__pycache__/cookies.cpython-38.pyc,, +requests/__pycache__/exceptions.cpython-38.pyc,, +requests/__pycache__/help.cpython-38.pyc,, +requests/__pycache__/hooks.cpython-38.pyc,, +requests/__pycache__/models.cpython-38.pyc,, +requests/__pycache__/packages.cpython-38.pyc,, +requests/__pycache__/sessions.cpython-38.pyc,, +requests/__pycache__/status_codes.cpython-38.pyc,, +requests/__pycache__/structures.cpython-38.pyc,, +requests/__pycache__/utils.cpython-38.pyc,, +requests/__version__.py,sha256=k4J8c1yFRFzwGWwlN7miaDOclFtbcIs1GlnmT17YbXQ,441 +requests/_internal_utils.py,sha256=Zx3PnEUccyfsB-ie11nZVAW8qClJy0gx1qNME7rgT18,1096 +requests/adapters.py,sha256=WelSM1BCQXdbjEuDsBxqKDADeY8BHmxlrwbNnLN2rr4,21344 +requests/api.py,sha256=PlHM-HT3PQ5lyufoeGmV-nJxRi7UnUyGVh7OV7B9XV4,6496 +requests/auth.py,sha256=OMoJIVKyRLy9THr91y8rxysZuclwPB-K1Xg1zBomUhQ,10207 +requests/certs.py,sha256=dOB5rV2DZ13dEhq9BUa_4hd5kAqg59e_zUZB00faYz8,453 +requests/compat.py,sha256=iBRvu-X540CH4PJsuxr0vcGTnl_TZhq_75SwmeckQ7w,1782 +requests/cookies.py,sha256=Y-bKX6TvW3FnYlE6Au0SXtVVWcaNdFvuAwQxw-G0iTI,18430 +requests/exceptions.py,sha256=xXoj1rdhnxTS_DYphKZ9OvFZJQZ333A64REc9ZDZIgU,3161 +requests/help.py,sha256=lLcBtKAar8T6T78e9Tc4Zfd_EEJFhntxgib1JHNctEI,3515 +requests/hooks.py,sha256=QReGyy0bRcr5rkwCuObNakbYsc7EkiKeBwG4qHekr2Q,757 +requests/models.py,sha256=Uhb4Ra_ubNGBf-6ktHShgO5mUSCGZKa5D_wLGVCMtYk,34308 +requests/packages.py,sha256=Q2rF0L5mc3wQAvc6q_lAVtPTDOaOeFgD-7kWSQLkjEQ,542 +requests/sessions.py,sha256=BsnR-zYILgoFzJ6yq4T8ht_i0PwwPGVAxWxWaV5dcHg,30137 +requests/status_codes.py,sha256=gT79Pbs_cQjBgp-fvrUgg1dn2DQO32bDj4TInjnMPSc,4188 +requests/structures.py,sha256=msAtr9mq1JxHd-JRyiILfdFlpbJwvvFuP3rfUQT_QxE,3005 +requests/utils.py,sha256=_K9AgkN6efPe-a-zgZurXzds5PBC0CzDkyjAE2oCQFQ,30529 diff --git a/venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/WHEEL b/venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/WHEEL new file mode 100644 index 0000000..01b8fc7 --- /dev/null +++ b/venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.36.2) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/top_level.txt b/venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/top_level.txt new file mode 100644 index 0000000..f229360 --- /dev/null +++ b/venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/top_level.txt @@ -0,0 +1 @@ +requests diff --git a/venv/lib/python3.8/site-packages/requests/__init__.py b/venv/lib/python3.8/site-packages/requests/__init__.py new file mode 100644 index 0000000..f8f9429 --- /dev/null +++ b/venv/lib/python3.8/site-packages/requests/__init__.py @@ -0,0 +1,137 @@ +# -*- coding: utf-8 -*- + +# __ +# /__) _ _ _ _ _/ _ +# / ( (- (/ (/ (- _) / _) +# / + +""" +Requests HTTP Library +~~~~~~~~~~~~~~~~~~~~~ + +Requests is an HTTP library, written in Python, for human beings. +Basic GET usage: + + >>> import requests + >>> r = requests.get('https://www.python.org') + >>> r.status_code + 200 + >>> b'Python is a programming language' in r.content + True + +... or POST: + + >>> payload = dict(key1='value1', key2='value2') + >>> r = requests.post('https://httpbin.org/post', data=payload) + >>> print(r.text) + { + ... + "form": { + "key1": "value1", + "key2": "value2" + }, + ... + } + +The other HTTP methods are supported - see `requests.api`. Full documentation +is at <https://requests.readthedocs.io>. + +:copyright: (c) 2017 by Kenneth Reitz. +:license: Apache 2.0, see LICENSE for more details. +""" + +import urllib3 +import chardet +import warnings +from .exceptions import RequestsDependencyWarning + + +def check_compatibility(urllib3_version, chardet_version): + urllib3_version = urllib3_version.split('.') + assert urllib3_version != ['dev'] # Verify urllib3 isn't installed from git. + + # Sometimes, urllib3 only reports its version as 16.1. + if len(urllib3_version) == 2: + urllib3_version.append('0') + + # Check urllib3 for compatibility. + major, minor, patch = urllib3_version # noqa: F811 + major, minor, patch = int(major), int(minor), int(patch) + # urllib3 >= 1.21.1, <= 1.26 + assert major == 1 + assert minor >= 21 + assert minor <= 26 + + # Check chardet for compatibility. + major, minor, patch = chardet_version.split('.')[:3] + major, minor, patch = int(major), int(minor), int(patch) + # chardet >= 3.0.2, < 5.0.0 + assert (3, 0, 2) <= (major, minor, patch) < (5, 0, 0) + + +def _check_cryptography(cryptography_version): + # cryptography < 1.3.4 + try: + cryptography_version = list(map(int, cryptography_version.split('.'))) + except ValueError: + return + + if cryptography_version < [1, 3, 4]: + warning = 'Old version of cryptography ({}) may cause slowdown.'.format(cryptography_version) + warnings.warn(warning, RequestsDependencyWarning) + +# Check imported dependencies for compatibility. +try: + check_compatibility(urllib3.__version__, chardet.__version__) +except (AssertionError, ValueError): + warnings.warn("urllib3 ({}) or chardet ({}) doesn't match a supported " + "version!".format(urllib3.__version__, chardet.__version__), + RequestsDependencyWarning) + +# Attempt to enable urllib3's fallback for SNI support +# if the standard library doesn't support SNI or the +# 'ssl' library isn't available. +try: + try: + import ssl + except ImportError: + ssl = None + + if not getattr(ssl, "HAS_SNI", False): + from urllib3.contrib import pyopenssl + pyopenssl.inject_into_urllib3() + + # Check cryptography version + from cryptography import __version__ as cryptography_version + _check_cryptography(cryptography_version) +except ImportError: + pass + +# urllib3's DependencyWarnings should be silenced. +from urllib3.exceptions import DependencyWarning +warnings.simplefilter('ignore', DependencyWarning) + +from .__version__ import __title__, __description__, __url__, __version__ +from .__version__ import __build__, __author__, __author_email__, __license__ +from .__version__ import __copyright__, __cake__ + +from . import utils +from . import packages +from .models import Request, Response, PreparedRequest +from .api import request, get, head, post, patch, put, delete, options +from .sessions import session, Session +from .status_codes import codes +from .exceptions import ( + RequestException, Timeout, URLRequired, + TooManyRedirects, HTTPError, ConnectionError, + FileModeWarning, ConnectTimeout, ReadTimeout +) + +# Set default logging handler to avoid "No handler found" warnings. +import logging +from logging import NullHandler + +logging.getLogger(__name__).addHandler(NullHandler()) + +# FileModeWarnings go off per the default. +warnings.simplefilter('default', FileModeWarning, append=True) diff --git a/venv/lib/python3.8/site-packages/requests/__version__.py b/venv/lib/python3.8/site-packages/requests/__version__.py new file mode 100644 index 0000000..1267488 --- /dev/null +++ b/venv/lib/python3.8/site-packages/requests/__version__.py @@ -0,0 +1,14 @@ +# .-. .-. .-. . . .-. .-. .-. .-. +# |( |- |.| | | |- `-. | `-. +# ' ' `-' `-`.`-' `-' `-' ' `-' + +__title__ = 'requests' +__description__ = 'Python HTTP for Humans.' +__url__ = 'https://requests.readthedocs.io' +__version__ = '2.25.1' +__build__ = 0x022501 +__author__ = 'Kenneth Reitz' +__author_email__ = 'me@kennethreitz.org' +__license__ = 'Apache 2.0' +__copyright__ = 'Copyright 2020 Kenneth Reitz' +__cake__ = u'\u2728 \U0001f370 \u2728' diff --git a/venv/lib/python3.8/site-packages/requests/_internal_utils.py b/venv/lib/python3.8/site-packages/requests/_internal_utils.py new file mode 100644 index 0000000..759d9a5 --- /dev/null +++ b/venv/lib/python3.8/site-packages/requests/_internal_utils.py @@ -0,0 +1,42 @@ +# -*- coding: utf-8 -*- + +""" +requests._internal_utils +~~~~~~~~~~~~~~ + +Provides utility functions that are consumed internally by Requests +which depend on extremely few external helpers (such as compat) +""" + +from .compat import is_py2, builtin_str, str + + +def to_native_string(string, encoding='ascii'): + """Given a string object, regardless of type, returns a representation of + that string in the native string type, encoding and decoding where + necessary. This assumes ASCII unless told otherwise. + """ + if isinstance(string, builtin_str): + out = string + else: + if is_py2: + out = string.encode(encoding) + else: + out = string.decode(encoding) + + return out + + +def unicode_is_ascii(u_string): + """Determine if unicode string only contains ASCII characters. + + :param str u_string: unicode string to check. Must be unicode + and not Python 2 `str`. + :rtype: bool + """ + assert isinstance(u_string, str) + try: + u_string.encode('ascii') + return True + except UnicodeEncodeError: + return False diff --git a/venv/lib/python3.8/site-packages/requests/adapters.py b/venv/lib/python3.8/site-packages/requests/adapters.py new file mode 100644 index 0000000..fa4d9b3 --- /dev/null +++ b/venv/lib/python3.8/site-packages/requests/adapters.py @@ -0,0 +1,533 @@ +# -*- coding: utf-8 -*- + +""" +requests.adapters +~~~~~~~~~~~~~~~~~ + +This module contains the transport adapters that Requests uses to define +and maintain connections. +""" + +import os.path +import socket + +from urllib3.poolmanager import PoolManager, proxy_from_url +from urllib3.response import HTTPResponse +from urllib3.util import parse_url +from urllib3.util import Timeout as TimeoutSauce +from urllib3.util.retry import Retry +from urllib3.exceptions import ClosedPoolError +from urllib3.exceptions import ConnectTimeoutError +from urllib3.exceptions import HTTPError as _HTTPError +from urllib3.exceptions import MaxRetryError +from urllib3.exceptions import NewConnectionError +from urllib3.exceptions import ProxyError as _ProxyError +from urllib3.exceptions import ProtocolError +from urllib3.exceptions import ReadTimeoutError +from urllib3.exceptions import SSLError as _SSLError +from urllib3.exceptions import ResponseError +from urllib3.exceptions import LocationValueError + +from .models import Response +from .compat import urlparse, basestring +from .utils import (DEFAULT_CA_BUNDLE_PATH, extract_zipped_paths, + get_encoding_from_headers, prepend_scheme_if_needed, + get_auth_from_url, urldefragauth, select_proxy) +from .structures import CaseInsensitiveDict +from .cookies import extract_cookies_to_jar +from .exceptions import (ConnectionError, ConnectTimeout, ReadTimeout, SSLError, + ProxyError, RetryError, InvalidSchema, InvalidProxyURL, + InvalidURL) +from .auth import _basic_auth_str + +try: + from urllib3.contrib.socks import SOCKSProxyManager +except ImportError: + def SOCKSProxyManager(*args, **kwargs): + raise InvalidSchema("Missing dependencies for SOCKS support.") + +DEFAULT_POOLBLOCK = False +DEFAULT_POOLSIZE = 10 +DEFAULT_RETRIES = 0 +DEFAULT_POOL_TIMEOUT = None + + +class BaseAdapter(object): + """The Base Transport Adapter""" + + def __init__(self): + super(BaseAdapter, self).__init__() + + def send(self, request, stream=False, timeout=None, verify=True, + cert=None, proxies=None): + """Sends PreparedRequest object. Returns Response object. + + :param request: The :class:`PreparedRequest <PreparedRequest>` being sent. + :param stream: (optional) Whether to stream the request content. + :param timeout: (optional) How long to wait for the server to send + data before giving up, as a float, or a :ref:`(connect timeout, + read timeout) <timeouts>` tuple. + :type timeout: float or tuple + :param verify: (optional) Either a boolean, in which case it controls whether we verify + the server's TLS certificate, or a string, in which case it must be a path + to a CA bundle to use + :param cert: (optional) Any user-provided SSL certificate to be trusted. + :param proxies: (optional) The proxies dictionary to apply to the request. + """ + raise NotImplementedError + + def close(self): + """Cleans up adapter specific items.""" + raise NotImplementedError + + +class HTTPAdapter(BaseAdapter): + """The built-in HTTP Adapter for urllib3. + + Provides a general-case interface for Requests sessions to contact HTTP and + HTTPS urls by implementing the Transport Adapter interface. This class will + usually be created by the :class:`Session <Session>` class under the + covers. + + :param pool_connections: The number of urllib3 connection pools to cache. + :param pool_maxsize: The maximum number of connections to save in the pool. + :param max_retries: The maximum number of retries each connection + should attempt. Note, this applies only to failed DNS lookups, socket + connections and connection timeouts, never to requests where data has + made it to the server. By default, Requests does not retry failed + connections. If you need granular control over the conditions under + which we retry a request, import urllib3's ``Retry`` class and pass + that instead. + :param pool_block: Whether the connection pool should block for connections. + + Usage:: + + >>> import requests + >>> s = requests.Session() + >>> a = requests.adapters.HTTPAdapter(max_retries=3) + >>> s.mount('http://', a) + """ + __attrs__ = ['max_retries', 'config', '_pool_connections', '_pool_maxsize', + '_pool_block'] + + def __init__(self, pool_connections=DEFAULT_POOLSIZE, + pool_maxsize=DEFAULT_POOLSIZE, max_retries=DEFAULT_RETRIES, + pool_block=DEFAULT_POOLBLOCK): + if max_retries == DEFAULT_RETRIES: + self.max_retries = Retry(0, read=False) + else: + self.max_retries = Retry.from_int(max_retries) + self.config = {} + self.proxy_manager = {} + + super(HTTPAdapter, self).__init__() + + self._pool_connections = pool_connections + self._pool_maxsize = pool_maxsize + self._pool_block = pool_block + + self.init_poolmanager(pool_connections, pool_maxsize, block=pool_block) + + def __getstate__(self): + return {attr: getattr(self, attr, None) for attr in self.__attrs__} + + def __setstate__(self, state): + # Can't handle by adding 'proxy_manager' to self.__attrs__ because + # self.poolmanager uses a lambda function, which isn't pickleable. + self.proxy_manager = {} + self.config = {} + + for attr, value in state.items(): + setattr(self, attr, value) + + self.init_poolmanager(self._pool_connections, self._pool_maxsize, + block=self._pool_block) + + def init_poolmanager(self, connections, maxsize, block=DEFAULT_POOLBLOCK, **pool_kwargs): + """Initializes a urllib3 PoolManager. + + This method should not be called from user code, and is only + exposed for use when subclassing the + :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. + + :param connections: The number of urllib3 connection pools to cache. + :param maxsize: The maximum number of connections to save in the pool. + :param block: Block when no free connections are available. + :param pool_kwargs: Extra keyword arguments used to initialize the Pool Manager. + """ + # save these values for pickling + self._pool_connections = connections + self._pool_maxsize = maxsize + self._pool_block = block + + self.poolmanager = PoolManager(num_pools=connections, maxsize=maxsize, + block=block, strict=True, **pool_kwargs) + + def proxy_manager_for(self, proxy, **proxy_kwargs): + """Return urllib3 ProxyManager for the given proxy. + + This method should not be called from user code, and is only + exposed for use when subclassing the + :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. + + :param proxy: The proxy to return a urllib3 ProxyManager for. + :param proxy_kwargs: Extra keyword arguments used to configure the Proxy Manager. + :returns: ProxyManager + :rtype: urllib3.ProxyManager + """ + if proxy in self.proxy_manager: + manager = self.proxy_manager[proxy] + elif proxy.lower().startswith('socks'): + username, password = get_auth_from_url(proxy) + manager = self.proxy_manager[proxy] = SOCKSProxyManager( + proxy, + username=username, + password=password, + num_pools=self._pool_connections, + maxsize=self._pool_maxsize, + block=self._pool_block, + **proxy_kwargs + ) + else: + proxy_headers = self.proxy_headers(proxy) + manager = self.proxy_manager[proxy] = proxy_from_url( + proxy, + proxy_headers=proxy_headers, + num_pools=self._pool_connections, + maxsize=self._pool_maxsize, + block=self._pool_block, + **proxy_kwargs) + + return manager + + def cert_verify(self, conn, url, verify, cert): + """Verify a SSL certificate. This method should not be called from user + code, and is only exposed for use when subclassing the + :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. + + :param conn: The urllib3 connection object associated with the cert. + :param url: The requested URL. + :param verify: Either a boolean, in which case it controls whether we verify + the server's TLS certificate, or a string, in which case it must be a path + to a CA bundle to use + :param cert: The SSL certificate to verify. + """ + if url.lower().startswith('https') and verify: + + cert_loc = None + + # Allow self-specified cert location. + if verify is not True: + cert_loc = verify + + if not cert_loc: + cert_loc = extract_zipped_paths(DEFAULT_CA_BUNDLE_PATH) + + if not cert_loc or not os.path.exists(cert_loc): + raise IOError("Could not find a suitable TLS CA certificate bundle, " + "invalid path: {}".format(cert_loc)) + + conn.cert_reqs = 'CERT_REQUIRED' + + if not os.path.isdir(cert_loc): + conn.ca_certs = cert_loc + else: + conn.ca_cert_dir = cert_loc + else: + conn.cert_reqs = 'CERT_NONE' + conn.ca_certs = None + conn.ca_cert_dir = None + + if cert: + if not isinstance(cert, basestring): + conn.cert_file = cert[0] + conn.key_file = cert[1] + else: + conn.cert_file = cert + conn.key_file = None + if conn.cert_file and not os.path.exists(conn.cert_file): + raise IOError("Could not find the TLS certificate file, " + "invalid path: {}".format(conn.cert_file)) + if conn.key_file and not os.path.exists(conn.key_file): + raise IOError("Could not find the TLS key file, " + "invalid path: {}".format(conn.key_file)) + + def build_response(self, req, resp): + """Builds a :class:`Response <requests.Response>` object from a urllib3 + response. This should not be called from user code, and is only exposed + for use when subclassing the + :class:`HTTPAdapter <requests.adapters.HTTPAdapter>` + + :param req: The :class:`PreparedRequest <PreparedRequest>` used to generate the response. + :param resp: The urllib3 response object. + :rtype: requests.Response + """ + response = Response() + + # Fallback to None if there's no status_code, for whatever reason. + response.status_code = getattr(resp, 'status', None) + + # Make headers case-insensitive. + response.headers = CaseInsensitiveDict(getattr(resp, 'headers', {})) + + # Set encoding. + response.encoding = get_encoding_from_headers(response.headers) + response.raw = resp + response.reason = response.raw.reason + + if isinstance(req.url, bytes): + response.url = req.url.decode('utf-8') + else: + response.url = req.url + + # Add new cookies from the server. + extract_cookies_to_jar(response.cookies, req, resp) + + # Give the Response some context. + response.request = req + response.connection = self + + return response + + def get_connection(self, url, proxies=None): + """Returns a urllib3 connection for the given URL. This should not be + called from user code, and is only exposed for use when subclassing the + :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. + + :param url: The URL to connect to. + :param proxies: (optional) A Requests-style dictionary of proxies used on this request. + :rtype: urllib3.ConnectionPool + """ + proxy = select_proxy(url, proxies) + + if proxy: + proxy = prepend_scheme_if_needed(proxy, 'http') + proxy_url = parse_url(proxy) + if not proxy_url.host: + raise InvalidProxyURL("Please check proxy URL. It is malformed" + " and could be missing the host.") + proxy_manager = self.proxy_manager_for(proxy) + conn = proxy_manager.connection_from_url(url) + else: + # Only scheme should be lower case + parsed = urlparse(url) + url = parsed.geturl() + conn = self.poolmanager.connection_from_url(url) + + return conn + + def close(self): + """Disposes of any internal state. + + Currently, this closes the PoolManager and any active ProxyManager, + which closes any pooled connections. + """ + self.poolmanager.clear() + for proxy in self.proxy_manager.values(): + proxy.clear() + + def request_url(self, request, proxies): + """Obtain the url to use when making the final request. + + If the message is being sent through a HTTP proxy, the full URL has to + be used. Otherwise, we should only use the path portion of the URL. + + This should not be called from user code, and is only exposed for use + when subclassing the + :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. + + :param request: The :class:`PreparedRequest <PreparedRequest>` being sent. + :param proxies: A dictionary of schemes or schemes and hosts to proxy URLs. + :rtype: str + """ + proxy = select_proxy(request.url, proxies) + scheme = urlparse(request.url).scheme + + is_proxied_http_request = (proxy and scheme != 'https') + using_socks_proxy = False + if proxy: + proxy_scheme = urlparse(proxy).scheme.lower() + using_socks_proxy = proxy_scheme.startswith('socks') + + url = request.path_url + if is_proxied_http_request and not using_socks_proxy: + url = urldefragauth(request.url) + + return url + + def add_headers(self, request, **kwargs): + """Add any headers needed by the connection. As of v2.0 this does + nothing by default, but is left for overriding by users that subclass + the :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. + + This should not be called from user code, and is only exposed for use + when subclassing the + :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. + + :param request: The :class:`PreparedRequest <PreparedRequest>` to add headers to. + :param kwargs: The keyword arguments from the call to send(). + """ + pass + + def proxy_headers(self, proxy): + """Returns a dictionary of the headers to add to any request sent + through a proxy. This works with urllib3 magic to ensure that they are + correctly sent to the proxy, rather than in a tunnelled request if + CONNECT is being used. + + This should not be called from user code, and is only exposed for use + when subclassing the + :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. + + :param proxy: The url of the proxy being used for this request. + :rtype: dict + """ + headers = {} + username, password = get_auth_from_url(proxy) + + if username: + headers['Proxy-Authorization'] = _basic_auth_str(username, + password) + + return headers + + def send(self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None): + """Sends PreparedRequest object. Returns Response object. + + :param request: The :class:`PreparedRequest <PreparedRequest>` being sent. + :param stream: (optional) Whether to stream the request content. + :param timeout: (optional) How long to wait for the server to send + data before giving up, as a float, or a :ref:`(connect timeout, + read timeout) <timeouts>` tuple. + :type timeout: float or tuple or urllib3 Timeout object + :param verify: (optional) Either a boolean, in which case it controls whether + we verify the server's TLS certificate, or a string, in which case it + must be a path to a CA bundle to use + :param cert: (optional) Any user-provided SSL certificate to be trusted. + :param proxies: (optional) The proxies dictionary to apply to the request. + :rtype: requests.Response + """ + + try: + conn = self.get_connection(request.url, proxies) + except LocationValueError as e: + raise InvalidURL(e, request=request) + + self.cert_verify(conn, request.url, verify, cert) + url = self.request_url(request, proxies) + self.add_headers(request, stream=stream, timeout=timeout, verify=verify, cert=cert, proxies=proxies) + + chunked = not (request.body is None or 'Content-Length' in request.headers) + + if isinstance(timeout, tuple): + try: + connect, read = timeout + timeout = TimeoutSauce(connect=connect, read=read) + except ValueError as e: + # this may raise a string formatting error. + err = ("Invalid timeout {}. Pass a (connect, read) " + "timeout tuple, or a single float to set " + "both timeouts to the same value".format(timeout)) + raise ValueError(err) + elif isinstance(timeout, TimeoutSauce): + pass + else: + timeout = TimeoutSauce(connect=timeout, read=timeout) + + try: + if not chunked: + resp = conn.urlopen( + method=request.method, + url=url, + body=request.body, + headers=request.headers, + redirect=False, + assert_same_host=False, + preload_content=False, + decode_content=False, + retries=self.max_retries, + timeout=timeout + ) + + # Send the request. + else: + if hasattr(conn, 'proxy_pool'): + conn = conn.proxy_pool + + low_conn = conn._get_conn(timeout=DEFAULT_POOL_TIMEOUT) + + try: + low_conn.putrequest(request.method, + url, + skip_accept_encoding=True) + + for header, value in request.headers.items(): + low_conn.putheader(header, value) + + low_conn.endheaders() + + for i in request.body: + low_conn.send(hex(len(i))[2:].encode('utf-8')) + low_conn.send(b'\r\n') + low_conn.send(i) + low_conn.send(b'\r\n') + low_conn.send(b'0\r\n\r\n') + + # Receive the response from the server + try: + # For Python 2.7, use buffering of HTTP responses + r = low_conn.getresponse(buffering=True) + except TypeError: + # For compatibility with Python 3.3+ + r = low_conn.getresponse() + + resp = HTTPResponse.from_httplib( + r, + pool=conn, + connection=low_conn, + preload_content=False, + decode_content=False + ) + except: + # If we hit any problems here, clean up the connection. + # Then, reraise so that we can handle the actual exception. + low_conn.close() + raise + + except (ProtocolError, socket.error) as err: + raise ConnectionError(err, request=request) + + except MaxRetryError as e: + if isinstance(e.reason, ConnectTimeoutError): + # TODO: Remove this in 3.0.0: see #2811 + if not isinstance(e.reason, NewConnectionError): + raise ConnectTimeout(e, request=request) + + if isinstance(e.reason, ResponseError): + raise RetryError(e, request=request) + + if isinstance(e.reason, _ProxyError): + raise ProxyError(e, request=request) + + if isinstance(e.reason, _SSLError): + # This branch is for urllib3 v1.22 and later. + raise SSLError(e, request=request) + + raise ConnectionError(e, request=request) + + except ClosedPoolError as e: + raise ConnectionError(e, request=request) + + except _ProxyError as e: + raise ProxyError(e) + + except (_SSLError, _HTTPError) as e: + if isinstance(e, _SSLError): + # This branch is for urllib3 versions earlier than v1.22 + raise SSLError(e, request=request) + elif isinstance(e, ReadTimeoutError): + raise ReadTimeout(e, request=request) + else: + raise + + return self.build_response(request, resp) diff --git a/venv/lib/python3.8/site-packages/requests/api.py b/venv/lib/python3.8/site-packages/requests/api.py new file mode 100644 index 0000000..e978e20 --- /dev/null +++ b/venv/lib/python3.8/site-packages/requests/api.py @@ -0,0 +1,161 @@ +# -*- coding: utf-8 -*- + +""" +requests.api +~~~~~~~~~~~~ + +This module implements the Requests API. + +:copyright: (c) 2012 by Kenneth Reitz. +:license: Apache2, see LICENSE for more details. +""" + +from . import sessions + + +def request(method, url, **kwargs): + """Constructs and sends a :class:`Request <Request>`. + + :param method: method for the new :class:`Request` object: ``GET``, ``OPTIONS``, ``HEAD``, ``POST``, ``PUT``, ``PATCH``, or ``DELETE``. + :param url: URL for the new :class:`Request` object. + :param params: (optional) Dictionary, list of tuples or bytes to send + in the query string for the :class:`Request`. + :param data: (optional) Dictionary, list of tuples, bytes, or file-like + object to send in the body of the :class:`Request`. + :param json: (optional) A JSON serializable Python object to send in the body of the :class:`Request`. + :param headers: (optional) Dictionary of HTTP Headers to send with the :class:`Request`. + :param cookies: (optional) Dict or CookieJar object to send with the :class:`Request`. + :param files: (optional) Dictionary of ``'name': file-like-objects`` (or ``{'name': file-tuple}``) for multipart encoding upload. + ``file-tuple`` can be a 2-tuple ``('filename', fileobj)``, 3-tuple ``('filename', fileobj, 'content_type')`` + or a 4-tuple ``('filename', fileobj, 'content_type', custom_headers)``, where ``'content-type'`` is a string + defining the content type of the given file and ``custom_headers`` a dict-like object containing additional headers + to add for the file. + :param auth: (optional) Auth tuple to enable Basic/Digest/Custom HTTP Auth. + :param timeout: (optional) How many seconds to wait for the server to send data + before giving up, as a float, or a :ref:`(connect timeout, read + timeout) <timeouts>` tuple. + :type timeout: float or tuple + :param allow_redirects: (optional) Boolean. Enable/disable GET/OPTIONS/POST/PUT/PATCH/DELETE/HEAD redirection. Defaults to ``True``. + :type allow_redirects: bool + :param proxies: (optional) Dictionary mapping protocol to the URL of the proxy. + :param verify: (optional) Either a boolean, in which case it controls whether we verify + the server's TLS certificate, or a string, in which case it must be a path + to a CA bundle to use. Defaults to ``True``. + :param stream: (optional) if ``False``, the response content will be immediately downloaded. + :param cert: (optional) if String, path to ssl client cert file (.pem). If Tuple, ('cert', 'key') pair. + :return: :class:`Response <Response>` object + :rtype: requests.Response + + Usage:: + + >>> import requests + >>> req = requests.request('GET', 'https://httpbin.org/get') + >>> req + <Response [200]> + """ + + # By using the 'with' statement we are sure the session is closed, thus we + # avoid leaving sockets open which can trigger a ResourceWarning in some + # cases, and look like a memory leak in others. + with sessions.Session() as session: + return session.request(method=method, url=url, **kwargs) + + +def get(url, params=None, **kwargs): + r"""Sends a GET request. + + :param url: URL for the new :class:`Request` object. + :param params: (optional) Dictionary, list of tuples or bytes to send + in the query string for the :class:`Request`. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :return: :class:`Response <Response>` object + :rtype: requests.Response + """ + + kwargs.setdefault('allow_redirects', True) + return request('get', url, params=params, **kwargs) + + +def options(url, **kwargs): + r"""Sends an OPTIONS request. + + :param url: URL for the new :class:`Request` object. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :return: :class:`Response <Response>` object + :rtype: requests.Response + """ + + kwargs.setdefault('allow_redirects', True) + return request('options', url, **kwargs) + + +def head(url, **kwargs): + r"""Sends a HEAD request. + + :param url: URL for the new :class:`Request` object. + :param \*\*kwargs: Optional arguments that ``request`` takes. If + `allow_redirects` is not provided, it will be set to `False` (as + opposed to the default :meth:`request` behavior). + :return: :class:`Response <Response>` object + :rtype: requests.Response + """ + + kwargs.setdefault('allow_redirects', False) + return request('head', url, **kwargs) + + +def post(url, data=None, json=None, **kwargs): + r"""Sends a POST request. + + :param url: URL for the new :class:`Request` object. + :param data: (optional) Dictionary, list of tuples, bytes, or file-like + object to send in the body of the :class:`Request`. + :param json: (optional) json data to send in the body of the :class:`Request`. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :return: :class:`Response <Response>` object + :rtype: requests.Response + """ + + return request('post', url, data=data, json=json, **kwargs) + + +def put(url, data=None, **kwargs): + r"""Sends a PUT request. + + :param url: URL for the new :class:`Request` object. + :param data: (optional) Dictionary, list of tuples, bytes, or file-like + object to send in the body of the :class:`Request`. + :param json: (optional) json data to send in the body of the :class:`Request`. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :return: :class:`Response <Response>` object + :rtype: requests.Response + """ + + return request('put', url, data=data, **kwargs) + + +def patch(url, data=None, **kwargs): + r"""Sends a PATCH request. + + :param url: URL for the new :class:`Request` object. + :param data: (optional) Dictionary, list of tuples, bytes, or file-like + object to send in the body of the :class:`Request`. + :param json: (optional) json data to send in the body of the :class:`Request`. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :return: :class:`Response <Response>` object + :rtype: requests.Response + """ + + return request('patch', url, data=data, **kwargs) + + +def delete(url, **kwargs): + r"""Sends a DELETE request. + + :param url: URL for the new :class:`Request` object. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :return: :class:`Response <Response>` object + :rtype: requests.Response + """ + + return request('delete', url, **kwargs) diff --git a/venv/lib/python3.8/site-packages/requests/auth.py b/venv/lib/python3.8/site-packages/requests/auth.py new file mode 100644 index 0000000..eeface3 --- /dev/null +++ b/venv/lib/python3.8/site-packages/requests/auth.py @@ -0,0 +1,305 @@ +# -*- coding: utf-8 -*- + +""" +requests.auth +~~~~~~~~~~~~~ + +This module contains the authentication handlers for Requests. +""" + +import os +import re +import time +import hashlib +import threading +import warnings + +from base64 import b64encode + +from .compat import urlparse, str, basestring +from .cookies import extract_cookies_to_jar +from ._internal_utils import to_native_string +from .utils import parse_dict_header + +CONTENT_TYPE_FORM_URLENCODED = 'application/x-www-form-urlencoded' +CONTENT_TYPE_MULTI_PART = 'multipart/form-data' + + +def _basic_auth_str(username, password): + """Returns a Basic Auth string.""" + + # "I want us to put a big-ol' comment on top of it that + # says that this behaviour is dumb but we need to preserve + # it because people are relying on it." + # - Lukasa + # + # These are here solely to maintain backwards compatibility + # for things like ints. This will be removed in 3.0.0. + if not isinstance(username, basestring): + warnings.warn( + "Non-string usernames will no longer be supported in Requests " + "3.0.0. Please convert the object you've passed in ({!r}) to " + "a string or bytes object in the near future to avoid " + "problems.".format(username), + category=DeprecationWarning, + ) + username = str(username) + + if not isinstance(password, basestring): + warnings.warn( + "Non-string passwords will no longer be supported in Requests " + "3.0.0. Please convert the object you've passed in ({!r}) to " + "a string or bytes object in the near future to avoid " + "problems.".format(type(password)), + category=DeprecationWarning, + ) + password = str(password) + # -- End Removal -- + + if isinstance(username, str): + username = username.encode('latin1') + + if isinstance(password, str): + password = password.encode('latin1') + + authstr = 'Basic ' + to_native_string( + b64encode(b':'.join((username, password))).strip() + ) + + return authstr + + +class AuthBase(object): + """Base class that all auth implementations derive from""" + + def __call__(self, r): + raise NotImplementedError('Auth hooks must be callable.') + + +class HTTPBasicAuth(AuthBase): + """Attaches HTTP Basic Authentication to the given Request object.""" + + def __init__(self, username, password): + self.username = username + self.password = password + + def __eq__(self, other): + return all([ + self.username == getattr(other, 'username', None), + self.password == getattr(other, 'password', None) + ]) + + def __ne__(self, other): + return not self == other + + def __call__(self, r): + r.headers['Authorization'] = _basic_auth_str(self.username, self.password) + return r + + +class HTTPProxyAuth(HTTPBasicAuth): + """Attaches HTTP Proxy Authentication to a given Request object.""" + + def __call__(self, r): + r.headers['Proxy-Authorization'] = _basic_auth_str(self.username, self.password) + return r + + +class HTTPDigestAuth(AuthBase): + """Attaches HTTP Digest Authentication to the given Request object.""" + + def __init__(self, username, password): + self.username = username + self.password = password + # Keep state in per-thread local storage + self._thread_local = threading.local() + + def init_per_thread_state(self): + # Ensure state is initialized just once per-thread + if not hasattr(self._thread_local, 'init'): + self._thread_local.init = True + self._thread_local.last_nonce = '' + self._thread_local.nonce_count = 0 + self._thread_local.chal = {} + self._thread_local.pos = None + self._thread_local.num_401_calls = None + + def build_digest_header(self, method, url): + """ + :rtype: str + """ + + realm = self._thread_local.chal['realm'] + nonce = self._thread_local.chal['nonce'] + qop = self._thread_local.chal.get('qop') + algorithm = self._thread_local.chal.get('algorithm') + opaque = self._thread_local.chal.get('opaque') + hash_utf8 = None + + if algorithm is None: + _algorithm = 'MD5' + else: + _algorithm = algorithm.upper() + # lambdas assume digest modules are imported at the top level + if _algorithm == 'MD5' or _algorithm == 'MD5-SESS': + def md5_utf8(x): + if isinstance(x, str): + x = x.encode('utf-8') + return hashlib.md5(x).hexdigest() + hash_utf8 = md5_utf8 + elif _algorithm == 'SHA': + def sha_utf8(x): + if isinstance(x, str): + x = x.encode('utf-8') + return hashlib.sha1(x).hexdigest() + hash_utf8 = sha_utf8 + elif _algorithm == 'SHA-256': + def sha256_utf8(x): + if isinstance(x, str): + x = x.encode('utf-8') + return hashlib.sha256(x).hexdigest() + hash_utf8 = sha256_utf8 + elif _algorithm == 'SHA-512': + def sha512_utf8(x): + if isinstance(x, str): + x = x.encode('utf-8') + return hashlib.sha512(x).hexdigest() + hash_utf8 = sha512_utf8 + + KD = lambda s, d: hash_utf8("%s:%s" % (s, d)) + + if hash_utf8 is None: + return None + + # XXX not implemented yet + entdig = None + p_parsed = urlparse(url) + #: path is request-uri defined in RFC 2616 which should not be empty + path = p_parsed.path or "/" + if p_parsed.query: + path += '?' + p_parsed.query + + A1 = '%s:%s:%s' % (self.username, realm, self.password) + A2 = '%s:%s' % (method, path) + + HA1 = hash_utf8(A1) + HA2 = hash_utf8(A2) + + if nonce == self._thread_local.last_nonce: + self._thread_local.nonce_count += 1 + else: + self._thread_local.nonce_count = 1 + ncvalue = '%08x' % self._thread_local.nonce_count + s = str(self._thread_local.nonce_count).encode('utf-8') + s += nonce.encode('utf-8') + s += time.ctime().encode('utf-8') + s += os.urandom(8) + + cnonce = (hashlib.sha1(s).hexdigest()[:16]) + if _algorithm == 'MD5-SESS': + HA1 = hash_utf8('%s:%s:%s' % (HA1, nonce, cnonce)) + + if not qop: + respdig = KD(HA1, "%s:%s" % (nonce, HA2)) + elif qop == 'auth' or 'auth' in qop.split(','): + noncebit = "%s:%s:%s:%s:%s" % ( + nonce, ncvalue, cnonce, 'auth', HA2 + ) + respdig = KD(HA1, noncebit) + else: + # XXX handle auth-int. + return None + + self._thread_local.last_nonce = nonce + + # XXX should the partial digests be encoded too? + base = 'username="%s", realm="%s", nonce="%s", uri="%s", ' \ + 'response="%s"' % (self.username, realm, nonce, path, respdig) + if opaque: + base += ', opaque="%s"' % opaque + if algorithm: + base += ', algorithm="%s"' % algorithm + if entdig: + base += ', digest="%s"' % entdig + if qop: + base += ', qop="auth", nc=%s, cnonce="%s"' % (ncvalue, cnonce) + + return 'Digest %s' % (base) + + def handle_redirect(self, r, **kwargs): + """Reset num_401_calls counter on redirects.""" + if r.is_redirect: + self._thread_local.num_401_calls = 1 + + def handle_401(self, r, **kwargs): + """ + Takes the given response and tries digest-auth, if needed. + + :rtype: requests.Response + """ + + # If response is not 4xx, do not auth + # See https://github.com/psf/requests/issues/3772 + if not 400 <= r.status_code < 500: + self._thread_local.num_401_calls = 1 + return r + + if self._thread_local.pos is not None: + # Rewind the file position indicator of the body to where + # it was to resend the request. + r.request.body.seek(self._thread_local.pos) + s_auth = r.headers.get('www-authenticate', '') + + if 'digest' in s_auth.lower() and self._thread_local.num_401_calls < 2: + + self._thread_local.num_401_calls += 1 + pat = re.compile(r'digest ', flags=re.IGNORECASE) + self._thread_local.chal = parse_dict_header(pat.sub('', s_auth, count=1)) + + # Consume content and release the original connection + # to allow our new request to reuse the same one. + r.content + r.close() + prep = r.request.copy() + extract_cookies_to_jar(prep._cookies, r.request, r.raw) + prep.prepare_cookies(prep._cookies) + + prep.headers['Authorization'] = self.build_digest_header( + prep.method, prep.url) + _r = r.connection.send(prep, **kwargs) + _r.history.append(r) + _r.request = prep + + return _r + + self._thread_local.num_401_calls = 1 + return r + + def __call__(self, r): + # Initialize per-thread state, if needed + self.init_per_thread_state() + # If we have a saved nonce, skip the 401 + if self._thread_local.last_nonce: + r.headers['Authorization'] = self.build_digest_header(r.method, r.url) + try: + self._thread_local.pos = r.body.tell() + except AttributeError: + # In the case of HTTPDigestAuth being reused and the body of + # the previous request was a file-like object, pos has the + # file position of the previous body. Ensure it's set to + # None. + self._thread_local.pos = None + r.register_hook('response', self.handle_401) + r.register_hook('response', self.handle_redirect) + self._thread_local.num_401_calls = 1 + + return r + + def __eq__(self, other): + return all([ + self.username == getattr(other, 'username', None), + self.password == getattr(other, 'password', None) + ]) + + def __ne__(self, other): + return not self == other diff --git a/venv/lib/python3.8/site-packages/requests/certs.py b/venv/lib/python3.8/site-packages/requests/certs.py new file mode 100644 index 0000000..d1a378d --- /dev/null +++ b/venv/lib/python3.8/site-packages/requests/certs.py @@ -0,0 +1,18 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +""" +requests.certs +~~~~~~~~~~~~~~ + +This module returns the preferred default CA certificate bundle. There is +only one — the one from the certifi package. + +If you are packaging Requests, e.g., for a Linux distribution or a managed +environment, you can change the definition of where() to return a separately +packaged CA bundle. +""" +from certifi import where + +if __name__ == '__main__': + print(where()) diff --git a/venv/lib/python3.8/site-packages/requests/compat.py b/venv/lib/python3.8/site-packages/requests/compat.py new file mode 100644 index 0000000..5de0769 --- /dev/null +++ b/venv/lib/python3.8/site-packages/requests/compat.py @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- + +""" +requests.compat +~~~~~~~~~~~~~~~ + +This module handles import compatibility issues between Python 2 and +Python 3. +""" + +import chardet + +import sys + +# ------- +# Pythons +# ------- + +# Syntax sugar. +_ver = sys.version_info + +#: Python 2.x? +is_py2 = (_ver[0] == 2) + +#: Python 3.x? +is_py3 = (_ver[0] == 3) + +try: + import simplejson as json +except ImportError: + import json + +# --------- +# Specifics +# --------- + +if is_py2: + from urllib import ( + quote, unquote, quote_plus, unquote_plus, urlencode, getproxies, + proxy_bypass, proxy_bypass_environment, getproxies_environment) + from urlparse import urlparse, urlunparse, urljoin, urlsplit, urldefrag + from urllib2 import parse_http_list + import cookielib + from Cookie import Morsel + from StringIO import StringIO + # Keep OrderedDict for backwards compatibility. + from collections import Callable, Mapping, MutableMapping, OrderedDict + + + builtin_str = str + bytes = str + str = unicode + basestring = basestring + numeric_types = (int, long, float) + integer_types = (int, long) + +elif is_py3: + from urllib.parse import urlparse, urlunparse, urljoin, urlsplit, urlencode, quote, unquote, quote_plus, unquote_plus, urldefrag + from urllib.request import parse_http_list, getproxies, proxy_bypass, proxy_bypass_environment, getproxies_environment + from http import cookiejar as cookielib + from http.cookies import Morsel + from io import StringIO + # Keep OrderedDict for backwards compatibility. + from collections import OrderedDict + from collections.abc import Callable, Mapping, MutableMapping + + builtin_str = str + str = str + bytes = bytes + basestring = (str, bytes) + numeric_types = (int, float) + integer_types = (int,) diff --git a/venv/lib/python3.8/site-packages/requests/cookies.py b/venv/lib/python3.8/site-packages/requests/cookies.py new file mode 100644 index 0000000..56fccd9 --- /dev/null +++ b/venv/lib/python3.8/site-packages/requests/cookies.py @@ -0,0 +1,549 @@ +# -*- coding: utf-8 -*- + +""" +requests.cookies +~~~~~~~~~~~~~~~~ + +Compatibility code to be able to use `cookielib.CookieJar` with requests. + +requests.utils imports from here, so be careful with imports. +""" + +import copy +import time +import calendar + +from ._internal_utils import to_native_string +from .compat import cookielib, urlparse, urlunparse, Morsel, MutableMapping + +try: + import threading +except ImportError: + import dummy_threading as threading + + +class MockRequest(object): + """Wraps a `requests.Request` to mimic a `urllib2.Request`. + + The code in `cookielib.CookieJar` expects this interface in order to correctly + manage cookie policies, i.e., determine whether a cookie can be set, given the + domains of the request and the cookie. + + The original request object is read-only. The client is responsible for collecting + the new headers via `get_new_headers()` and interpreting them appropriately. You + probably want `get_cookie_header`, defined below. + """ + + def __init__(self, request): + self._r = request + self._new_headers = {} + self.type = urlparse(self._r.url).scheme + + def get_type(self): + return self.type + + def get_host(self): + return urlparse(self._r.url).netloc + + def get_origin_req_host(self): + return self.get_host() + + def get_full_url(self): + # Only return the response's URL if the user hadn't set the Host + # header + if not self._r.headers.get('Host'): + return self._r.url + # If they did set it, retrieve it and reconstruct the expected domain + host = to_native_string(self._r.headers['Host'], encoding='utf-8') + parsed = urlparse(self._r.url) + # Reconstruct the URL as we expect it + return urlunparse([ + parsed.scheme, host, parsed.path, parsed.params, parsed.query, + parsed.fragment + ]) + + def is_unverifiable(self): + return True + + def has_header(self, name): + return name in self._r.headers or name in self._new_headers + + def get_header(self, name, default=None): + return self._r.headers.get(name, self._new_headers.get(name, default)) + + def add_header(self, key, val): + """cookielib has no legitimate use for this method; add it back if you find one.""" + raise NotImplementedError("Cookie headers should be added with add_unredirected_header()") + + def add_unredirected_header(self, name, value): + self._new_headers[name] = value + + def get_new_headers(self): + return self._new_headers + + @property + def unverifiable(self): + return self.is_unverifiable() + + @property + def origin_req_host(self): + return self.get_origin_req_host() + + @property + def host(self): + return self.get_host() + + +class MockResponse(object): + """Wraps a `httplib.HTTPMessage` to mimic a `urllib.addinfourl`. + + ...what? Basically, expose the parsed HTTP headers from the server response + the way `cookielib` expects to see them. + """ + + def __init__(self, headers): + """Make a MockResponse for `cookielib` to read. + + :param headers: a httplib.HTTPMessage or analogous carrying the headers + """ + self._headers = headers + + def info(self): + return self._headers + + def getheaders(self, name): + self._headers.getheaders(name) + + +def extract_cookies_to_jar(jar, request, response): + """Extract the cookies from the response into a CookieJar. + + :param jar: cookielib.CookieJar (not necessarily a RequestsCookieJar) + :param request: our own requests.Request object + :param response: urllib3.HTTPResponse object + """ + if not (hasattr(response, '_original_response') and + response._original_response): + return + # the _original_response field is the wrapped httplib.HTTPResponse object, + req = MockRequest(request) + # pull out the HTTPMessage with the headers and put it in the mock: + res = MockResponse(response._original_response.msg) + jar.extract_cookies(res, req) + + +def get_cookie_header(jar, request): + """ + Produce an appropriate Cookie header string to be sent with `request`, or None. + + :rtype: str + """ + r = MockRequest(request) + jar.add_cookie_header(r) + return r.get_new_headers().get('Cookie') + + +def remove_cookie_by_name(cookiejar, name, domain=None, path=None): + """Unsets a cookie by name, by default over all domains and paths. + + Wraps CookieJar.clear(), is O(n). + """ + clearables = [] + for cookie in cookiejar: + if cookie.name != name: + continue + if domain is not None and domain != cookie.domain: + continue + if path is not None and path != cookie.path: + continue + clearables.append((cookie.domain, cookie.path, cookie.name)) + + for domain, path, name in clearables: + cookiejar.clear(domain, path, name) + + +class CookieConflictError(RuntimeError): + """There are two cookies that meet the criteria specified in the cookie jar. + Use .get and .set and include domain and path args in order to be more specific. + """ + + +class RequestsCookieJar(cookielib.CookieJar, MutableMapping): + """Compatibility class; is a cookielib.CookieJar, but exposes a dict + interface. + + This is the CookieJar we create by default for requests and sessions that + don't specify one, since some clients may expect response.cookies and + session.cookies to support dict operations. + + Requests does not use the dict interface internally; it's just for + compatibility with external client code. All requests code should work + out of the box with externally provided instances of ``CookieJar``, e.g. + ``LWPCookieJar`` and ``FileCookieJar``. + + Unlike a regular CookieJar, this class is pickleable. + + .. warning:: dictionary operations that are normally O(1) may be O(n). + """ + + def get(self, name, default=None, domain=None, path=None): + """Dict-like get() that also supports optional domain and path args in + order to resolve naming collisions from using one cookie jar over + multiple domains. + + .. warning:: operation is O(n), not O(1). + """ + try: + return self._find_no_duplicates(name, domain, path) + except KeyError: + return default + + def set(self, name, value, **kwargs): + """Dict-like set() that also supports optional domain and path args in + order to resolve naming collisions from using one cookie jar over + multiple domains. + """ + # support client code that unsets cookies by assignment of a None value: + if value is None: + remove_cookie_by_name(self, name, domain=kwargs.get('domain'), path=kwargs.get('path')) + return + + if isinstance(value, Morsel): + c = morsel_to_cookie(value) + else: + c = create_cookie(name, value, **kwargs) + self.set_cookie(c) + return c + + def iterkeys(self): + """Dict-like iterkeys() that returns an iterator of names of cookies + from the jar. + + .. seealso:: itervalues() and iteritems(). + """ + for cookie in iter(self): + yield cookie.name + + def keys(self): + """Dict-like keys() that returns a list of names of cookies from the + jar. + + .. seealso:: values() and items(). + """ + return list(self.iterkeys()) + + def itervalues(self): + """Dict-like itervalues() that returns an iterator of values of cookies + from the jar. + + .. seealso:: iterkeys() and iteritems(). + """ + for cookie in iter(self): + yield cookie.value + + def values(self): + """Dict-like values() that returns a list of values of cookies from the + jar. + + .. seealso:: keys() and items(). + """ + return list(self.itervalues()) + + def iteritems(self): + """Dict-like iteritems() that returns an iterator of name-value tuples + from the jar. + + .. seealso:: iterkeys() and itervalues(). + """ + for cookie in iter(self): + yield cookie.name, cookie.value + + def items(self): + """Dict-like items() that returns a list of name-value tuples from the + jar. Allows client-code to call ``dict(RequestsCookieJar)`` and get a + vanilla python dict of key value pairs. + + .. seealso:: keys() and values(). + """ + return list(self.iteritems()) + + def list_domains(self): + """Utility method to list all the domains in the jar.""" + domains = [] + for cookie in iter(self): + if cookie.domain not in domains: + domains.append(cookie.domain) + return domains + + def list_paths(self): + """Utility method to list all the paths in the jar.""" + paths = [] + for cookie in iter(self): + if cookie.path not in paths: + paths.append(cookie.path) + return paths + + def multiple_domains(self): + """Returns True if there are multiple domains in the jar. + Returns False otherwise. + + :rtype: bool + """ + domains = [] + for cookie in iter(self): + if cookie.domain is not None and cookie.domain in domains: + return True + domains.append(cookie.domain) + return False # there is only one domain in jar + + def get_dict(self, domain=None, path=None): + """Takes as an argument an optional domain and path and returns a plain + old Python dict of name-value pairs of cookies that meet the + requirements. + + :rtype: dict + """ + dictionary = {} + for cookie in iter(self): + if ( + (domain is None or cookie.domain == domain) and + (path is None or cookie.path == path) + ): + dictionary[cookie.name] = cookie.value + return dictionary + + def __contains__(self, name): + try: + return super(RequestsCookieJar, self).__contains__(name) + except CookieConflictError: + return True + + def __getitem__(self, name): + """Dict-like __getitem__() for compatibility with client code. Throws + exception if there are more than one cookie with name. In that case, + use the more explicit get() method instead. + + .. warning:: operation is O(n), not O(1). + """ + return self._find_no_duplicates(name) + + def __setitem__(self, name, value): + """Dict-like __setitem__ for compatibility with client code. Throws + exception if there is already a cookie of that name in the jar. In that + case, use the more explicit set() method instead. + """ + self.set(name, value) + + def __delitem__(self, name): + """Deletes a cookie given a name. Wraps ``cookielib.CookieJar``'s + ``remove_cookie_by_name()``. + """ + remove_cookie_by_name(self, name) + + def set_cookie(self, cookie, *args, **kwargs): + if hasattr(cookie.value, 'startswith') and cookie.value.startswith('"') and cookie.value.endswith('"'): + cookie.value = cookie.value.replace('\\"', '') + return super(RequestsCookieJar, self).set_cookie(cookie, *args, **kwargs) + + def update(self, other): + """Updates this jar with cookies from another CookieJar or dict-like""" + if isinstance(other, cookielib.CookieJar): + for cookie in other: + self.set_cookie(copy.copy(cookie)) + else: + super(RequestsCookieJar, self).update(other) + + def _find(self, name, domain=None, path=None): + """Requests uses this method internally to get cookie values. + + If there are conflicting cookies, _find arbitrarily chooses one. + See _find_no_duplicates if you want an exception thrown if there are + conflicting cookies. + + :param name: a string containing name of cookie + :param domain: (optional) string containing domain of cookie + :param path: (optional) string containing path of cookie + :return: cookie.value + """ + for cookie in iter(self): + if cookie.name == name: + if domain is None or cookie.domain == domain: + if path is None or cookie.path == path: + return cookie.value + + raise KeyError('name=%r, domain=%r, path=%r' % (name, domain, path)) + + def _find_no_duplicates(self, name, domain=None, path=None): + """Both ``__get_item__`` and ``get`` call this function: it's never + used elsewhere in Requests. + + :param name: a string containing name of cookie + :param domain: (optional) string containing domain of cookie + :param path: (optional) string containing path of cookie + :raises KeyError: if cookie is not found + :raises CookieConflictError: if there are multiple cookies + that match name and optionally domain and path + :return: cookie.value + """ + toReturn = None + for cookie in iter(self): + if cookie.name == name: + if domain is None or cookie.domain == domain: + if path is None or cookie.path == path: + if toReturn is not None: # if there are multiple cookies that meet passed in criteria + raise CookieConflictError('There are multiple cookies with name, %r' % (name)) + toReturn = cookie.value # we will eventually return this as long as no cookie conflict + + if toReturn: + return toReturn + raise KeyError('name=%r, domain=%r, path=%r' % (name, domain, path)) + + def __getstate__(self): + """Unlike a normal CookieJar, this class is pickleable.""" + state = self.__dict__.copy() + # remove the unpickleable RLock object + state.pop('_cookies_lock') + return state + + def __setstate__(self, state): + """Unlike a normal CookieJar, this class is pickleable.""" + self.__dict__.update(state) + if '_cookies_lock' not in self.__dict__: + self._cookies_lock = threading.RLock() + + def copy(self): + """Return a copy of this RequestsCookieJar.""" + new_cj = RequestsCookieJar() + new_cj.set_policy(self.get_policy()) + new_cj.update(self) + return new_cj + + def get_policy(self): + """Return the CookiePolicy instance used.""" + return self._policy + + +def _copy_cookie_jar(jar): + if jar is None: + return None + + if hasattr(jar, 'copy'): + # We're dealing with an instance of RequestsCookieJar + return jar.copy() + # We're dealing with a generic CookieJar instance + new_jar = copy.copy(jar) + new_jar.clear() + for cookie in jar: + new_jar.set_cookie(copy.copy(cookie)) + return new_jar + + +def create_cookie(name, value, **kwargs): + """Make a cookie from underspecified parameters. + + By default, the pair of `name` and `value` will be set for the domain '' + and sent on every request (this is sometimes called a "supercookie"). + """ + result = { + 'version': 0, + 'name': name, + 'value': value, + 'port': None, + 'domain': '', + 'path': '/', + 'secure': False, + 'expires': None, + 'discard': True, + 'comment': None, + 'comment_url': None, + 'rest': {'HttpOnly': None}, + 'rfc2109': False, + } + + badargs = set(kwargs) - set(result) + if badargs: + err = 'create_cookie() got unexpected keyword arguments: %s' + raise TypeError(err % list(badargs)) + + result.update(kwargs) + result['port_specified'] = bool(result['port']) + result['domain_specified'] = bool(result['domain']) + result['domain_initial_dot'] = result['domain'].startswith('.') + result['path_specified'] = bool(result['path']) + + return cookielib.Cookie(**result) + + +def morsel_to_cookie(morsel): + """Convert a Morsel object into a Cookie containing the one k/v pair.""" + + expires = None + if morsel['max-age']: + try: + expires = int(time.time() + int(morsel['max-age'])) + except ValueError: + raise TypeError('max-age: %s must be integer' % morsel['max-age']) + elif morsel['expires']: + time_template = '%a, %d-%b-%Y %H:%M:%S GMT' + expires = calendar.timegm( + time.strptime(morsel['expires'], time_template) + ) + return create_cookie( + comment=morsel['comment'], + comment_url=bool(morsel['comment']), + discard=False, + domain=morsel['domain'], + expires=expires, + name=morsel.key, + path=morsel['path'], + port=None, + rest={'HttpOnly': morsel['httponly']}, + rfc2109=False, + secure=bool(morsel['secure']), + value=morsel.value, + version=morsel['version'] or 0, + ) + + +def cookiejar_from_dict(cookie_dict, cookiejar=None, overwrite=True): + """Returns a CookieJar from a key/value dictionary. + + :param cookie_dict: Dict of key/values to insert into CookieJar. + :param cookiejar: (optional) A cookiejar to add the cookies to. + :param overwrite: (optional) If False, will not replace cookies + already in the jar with new ones. + :rtype: CookieJar + """ + if cookiejar is None: + cookiejar = RequestsCookieJar() + + if cookie_dict is not None: + names_from_jar = [cookie.name for cookie in cookiejar] + for name in cookie_dict: + if overwrite or (name not in names_from_jar): + cookiejar.set_cookie(create_cookie(name, cookie_dict[name])) + + return cookiejar + + +def merge_cookies(cookiejar, cookies): + """Add cookies to cookiejar and returns a merged CookieJar. + + :param cookiejar: CookieJar object to add the cookies to. + :param cookies: Dictionary or CookieJar object to be added. + :rtype: CookieJar + """ + if not isinstance(cookiejar, cookielib.CookieJar): + raise ValueError('You can only merge into CookieJar') + + if isinstance(cookies, dict): + cookiejar = cookiejar_from_dict( + cookies, cookiejar=cookiejar, overwrite=False) + elif isinstance(cookies, cookielib.CookieJar): + try: + cookiejar.update(cookies) + except AttributeError: + for cookie_in_jar in cookies: + cookiejar.set_cookie(cookie_in_jar) + + return cookiejar diff --git a/venv/lib/python3.8/site-packages/requests/exceptions.py b/venv/lib/python3.8/site-packages/requests/exceptions.py new file mode 100644 index 0000000..0e9c820 --- /dev/null +++ b/venv/lib/python3.8/site-packages/requests/exceptions.py @@ -0,0 +1,123 @@ +# -*- coding: utf-8 -*- + +""" +requests.exceptions +~~~~~~~~~~~~~~~~~~~ + +This module contains the set of Requests' exceptions. +""" +from urllib3.exceptions import HTTPError as BaseHTTPError + + +class RequestException(IOError): + """There was an ambiguous exception that occurred while handling your + request. + """ + + def __init__(self, *args, **kwargs): + """Initialize RequestException with `request` and `response` objects.""" + response = kwargs.pop('response', None) + self.response = response + self.request = kwargs.pop('request', None) + if (response is not None and not self.request and + hasattr(response, 'request')): + self.request = self.response.request + super(RequestException, self).__init__(*args, **kwargs) + + +class HTTPError(RequestException): + """An HTTP error occurred.""" + + +class ConnectionError(RequestException): + """A Connection error occurred.""" + + +class ProxyError(ConnectionError): + """A proxy error occurred.""" + + +class SSLError(ConnectionError): + """An SSL error occurred.""" + + +class Timeout(RequestException): + """The request timed out. + + Catching this error will catch both + :exc:`~requests.exceptions.ConnectTimeout` and + :exc:`~requests.exceptions.ReadTimeout` errors. + """ + + +class ConnectTimeout(ConnectionError, Timeout): + """The request timed out while trying to connect to the remote server. + + Requests that produced this error are safe to retry. + """ + + +class ReadTimeout(Timeout): + """The server did not send any data in the allotted amount of time.""" + + +class URLRequired(RequestException): + """A valid URL is required to make a request.""" + + +class TooManyRedirects(RequestException): + """Too many redirects.""" + + +class MissingSchema(RequestException, ValueError): + """The URL schema (e.g. http or https) is missing.""" + + +class InvalidSchema(RequestException, ValueError): + """See defaults.py for valid schemas.""" + + +class InvalidURL(RequestException, ValueError): + """The URL provided was somehow invalid.""" + + +class InvalidHeader(RequestException, ValueError): + """The header value provided was somehow invalid.""" + + +class InvalidProxyURL(InvalidURL): + """The proxy URL provided is invalid.""" + + +class ChunkedEncodingError(RequestException): + """The server declared chunked encoding but sent an invalid chunk.""" + + +class ContentDecodingError(RequestException, BaseHTTPError): + """Failed to decode response content.""" + + +class StreamConsumedError(RequestException, TypeError): + """The content for this response was already consumed.""" + + +class RetryError(RequestException): + """Custom retries logic failed""" + + +class UnrewindableBodyError(RequestException): + """Requests encountered an error when trying to rewind a body.""" + +# Warnings + + +class RequestsWarning(Warning): + """Base warning for Requests.""" + + +class FileModeWarning(RequestsWarning, DeprecationWarning): + """A file was opened in text mode, but Requests determined its binary length.""" + + +class RequestsDependencyWarning(RequestsWarning): + """An imported dependency doesn't match the expected version range.""" diff --git a/venv/lib/python3.8/site-packages/requests/help.py b/venv/lib/python3.8/site-packages/requests/help.py new file mode 100644 index 0000000..e53d35e --- /dev/null +++ b/venv/lib/python3.8/site-packages/requests/help.py @@ -0,0 +1,119 @@ +"""Module containing bug report helper(s).""" +from __future__ import print_function + +import json +import platform +import sys +import ssl + +import idna +import urllib3 +import chardet + +from . import __version__ as requests_version + +try: + from urllib3.contrib import pyopenssl +except ImportError: + pyopenssl = None + OpenSSL = None + cryptography = None +else: + import OpenSSL + import cryptography + + +def _implementation(): + """Return a dict with the Python implementation and version. + + Provide both the name and the version of the Python implementation + currently running. For example, on CPython 2.7.5 it will return + {'name': 'CPython', 'version': '2.7.5'}. + + This function works best on CPython and PyPy: in particular, it probably + doesn't work for Jython or IronPython. Future investigation should be done + to work out the correct shape of the code for those platforms. + """ + implementation = platform.python_implementation() + + if implementation == 'CPython': + implementation_version = platform.python_version() + elif implementation == 'PyPy': + implementation_version = '%s.%s.%s' % (sys.pypy_version_info.major, + sys.pypy_version_info.minor, + sys.pypy_version_info.micro) + if sys.pypy_version_info.releaselevel != 'final': + implementation_version = ''.join([ + implementation_version, sys.pypy_version_info.releaselevel + ]) + elif implementation == 'Jython': + implementation_version = platform.python_version() # Complete Guess + elif implementation == 'IronPython': + implementation_version = platform.python_version() # Complete Guess + else: + implementation_version = 'Unknown' + + return {'name': implementation, 'version': implementation_version} + + +def info(): + """Generate information for a bug report.""" + try: + platform_info = { + 'system': platform.system(), + 'release': platform.release(), + } + except IOError: + platform_info = { + 'system': 'Unknown', + 'release': 'Unknown', + } + + implementation_info = _implementation() + urllib3_info = {'version': urllib3.__version__} + chardet_info = {'version': chardet.__version__} + + pyopenssl_info = { + 'version': None, + 'openssl_version': '', + } + if OpenSSL: + pyopenssl_info = { + 'version': OpenSSL.__version__, + 'openssl_version': '%x' % OpenSSL.SSL.OPENSSL_VERSION_NUMBER, + } + cryptography_info = { + 'version': getattr(cryptography, '__version__', ''), + } + idna_info = { + 'version': getattr(idna, '__version__', ''), + } + + system_ssl = ssl.OPENSSL_VERSION_NUMBER + system_ssl_info = { + 'version': '%x' % system_ssl if system_ssl is not None else '' + } + + return { + 'platform': platform_info, + 'implementation': implementation_info, + 'system_ssl': system_ssl_info, + 'using_pyopenssl': pyopenssl is not None, + 'pyOpenSSL': pyopenssl_info, + 'urllib3': urllib3_info, + 'chardet': chardet_info, + 'cryptography': cryptography_info, + 'idna': idna_info, + 'requests': { + 'version': requests_version, + }, + } + + +def main(): + """Pretty-print the bug information as JSON.""" + print(json.dumps(info(), sort_keys=True, indent=2)) + + +if __name__ == '__main__': + main() diff --git a/venv/lib/python3.8/site-packages/requests/hooks.py b/venv/lib/python3.8/site-packages/requests/hooks.py new file mode 100644 index 0000000..7a51f21 --- /dev/null +++ b/venv/lib/python3.8/site-packages/requests/hooks.py @@ -0,0 +1,34 @@ +# -*- coding: utf-8 -*- + +""" +requests.hooks +~~~~~~~~~~~~~~ + +This module provides the capabilities for the Requests hooks system. + +Available hooks: + +``response``: + The response generated from a Request. +""" +HOOKS = ['response'] + + +def default_hooks(): + return {event: [] for event in HOOKS} + +# TODO: response is the only one + + +def dispatch_hook(key, hooks, hook_data, **kwargs): + """Dispatches a hook dictionary on a given piece of data.""" + hooks = hooks or {} + hooks = hooks.get(key) + if hooks: + if hasattr(hooks, '__call__'): + hooks = [hooks] + for hook in hooks: + _hook_data = hook(hook_data, **kwargs) + if _hook_data is not None: + hook_data = _hook_data + return hook_data diff --git a/venv/lib/python3.8/site-packages/requests/models.py b/venv/lib/python3.8/site-packages/requests/models.py new file mode 100644 index 0000000..ec2edc2 --- /dev/null +++ b/venv/lib/python3.8/site-packages/requests/models.py @@ -0,0 +1,956 @@ +# -*- coding: utf-8 -*- + +""" +requests.models +~~~~~~~~~~~~~~~ + +This module contains the primary objects that power Requests. +""" + +import datetime +import sys + +# Import encoding now, to avoid implicit import later. +# Implicit import within threads may cause LookupError when standard library is in a ZIP, +# such as in Embedded Python. See https://github.com/psf/requests/issues/3578. +import encodings.idna + +from urllib3.fields import RequestField +from urllib3.filepost import encode_multipart_formdata +from urllib3.util import parse_url +from urllib3.exceptions import ( + DecodeError, ReadTimeoutError, ProtocolError, LocationParseError) + +from io import UnsupportedOperation +from .hooks import default_hooks +from .structures import CaseInsensitiveDict + +from .auth import HTTPBasicAuth +from .cookies import cookiejar_from_dict, get_cookie_header, _copy_cookie_jar +from .exceptions import ( + HTTPError, MissingSchema, InvalidURL, ChunkedEncodingError, + ContentDecodingError, ConnectionError, StreamConsumedError) +from ._internal_utils import to_native_string, unicode_is_ascii +from .utils import ( + guess_filename, get_auth_from_url, requote_uri, + stream_decode_response_unicode, to_key_val_list, parse_header_links, + iter_slices, guess_json_utf, super_len, check_header_validity) +from .compat import ( + Callable, Mapping, + cookielib, urlunparse, urlsplit, urlencode, str, bytes, + is_py2, chardet, builtin_str, basestring) +from .compat import json as complexjson +from .status_codes import codes + +#: The set of HTTP status codes that indicate an automatically +#: processable redirect. +REDIRECT_STATI = ( + codes.moved, # 301 + codes.found, # 302 + codes.other, # 303 + codes.temporary_redirect, # 307 + codes.permanent_redirect, # 308 +) + +DEFAULT_REDIRECT_LIMIT = 30 +CONTENT_CHUNK_SIZE = 10 * 1024 +ITER_CHUNK_SIZE = 512 + + +class RequestEncodingMixin(object): + @property + def path_url(self): + """Build the path URL to use.""" + + url = [] + + p = urlsplit(self.url) + + path = p.path + if not path: + path = '/' + + url.append(path) + + query = p.query + if query: + url.append('?') + url.append(query) + + return ''.join(url) + + @staticmethod + def _encode_params(data): + """Encode parameters in a piece of data. + + Will successfully encode parameters when passed as a dict or a list of + 2-tuples. Order is retained if data is a list of 2-tuples but arbitrary + if parameters are supplied as a dict. + """ + + if isinstance(data, (str, bytes)): + return data + elif hasattr(data, 'read'): + return data + elif hasattr(data, '__iter__'): + result = [] + for k, vs in to_key_val_list(data): + if isinstance(vs, basestring) or not hasattr(vs, '__iter__'): + vs = [vs] + for v in vs: + if v is not None: + result.append( + (k.encode('utf-8') if isinstance(k, str) else k, + v.encode('utf-8') if isinstance(v, str) else v)) + return urlencode(result, doseq=True) + else: + return data + + @staticmethod + def _encode_files(files, data): + """Build the body for a multipart/form-data request. + + Will successfully encode files when passed as a dict or a list of + tuples. Order is retained if data is a list of tuples but arbitrary + if parameters are supplied as a dict. + The tuples may be 2-tuples (filename, fileobj), 3-tuples (filename, fileobj, contentype) + or 4-tuples (filename, fileobj, contentype, custom_headers). + """ + if (not files): + raise ValueError("Files must be provided.") + elif isinstance(data, basestring): + raise ValueError("Data must not be a string.") + + new_fields = [] + fields = to_key_val_list(data or {}) + files = to_key_val_list(files or {}) + + for field, val in fields: + if isinstance(val, basestring) or not hasattr(val, '__iter__'): + val = [val] + for v in val: + if v is not None: + # Don't call str() on bytestrings: in Py3 it all goes wrong. + if not isinstance(v, bytes): + v = str(v) + + new_fields.append( + (field.decode('utf-8') if isinstance(field, bytes) else field, + v.encode('utf-8') if isinstance(v, str) else v)) + + for (k, v) in files: + # support for explicit filename + ft = None + fh = None + if isinstance(v, (tuple, list)): + if len(v) == 2: + fn, fp = v + elif len(v) == 3: + fn, fp, ft = v + else: + fn, fp, ft, fh = v + else: + fn = guess_filename(v) or k + fp = v + + if isinstance(fp, (str, bytes, bytearray)): + fdata = fp + elif hasattr(fp, 'read'): + fdata = fp.read() + elif fp is None: + continue + else: + fdata = fp + + rf = RequestField(name=k, data=fdata, filename=fn, headers=fh) + rf.make_multipart(content_type=ft) + new_fields.append(rf) + + body, content_type = encode_multipart_formdata(new_fields) + + return body, content_type + + +class RequestHooksMixin(object): + def register_hook(self, event, hook): + """Properly register a hook.""" + + if event not in self.hooks: + raise ValueError('Unsupported event specified, with event name "%s"' % (event)) + + if isinstance(hook, Callable): + self.hooks[event].append(hook) + elif hasattr(hook, '__iter__'): + self.hooks[event].extend(h for h in hook if isinstance(h, Callable)) + + def deregister_hook(self, event, hook): + """Deregister a previously registered hook. + Returns True if the hook existed, False if not. + """ + + try: + self.hooks[event].remove(hook) + return True + except ValueError: + return False + + +class Request(RequestHooksMixin): + """A user-created :class:`Request <Request>` object. + + Used to prepare a :class:`PreparedRequest <PreparedRequest>`, which is sent to the server. + + :param method: HTTP method to use. + :param url: URL to send. + :param headers: dictionary of headers to send. + :param files: dictionary of {filename: fileobject} files to multipart upload. + :param data: the body to attach to the request. If a dictionary or + list of tuples ``[(key, value)]`` is provided, form-encoding will + take place. + :param json: json for the body to attach to the request (if files or data is not specified). + :param params: URL parameters to append to the URL. If a dictionary or + list of tuples ``[(key, value)]`` is provided, form-encoding will + take place. + :param auth: Auth handler or (user, pass) tuple. + :param cookies: dictionary or CookieJar of cookies to attach to this request. + :param hooks: dictionary of callback hooks, for internal usage. + + Usage:: + + >>> import requests + >>> req = requests.Request('GET', 'https://httpbin.org/get') + >>> req.prepare() + <PreparedRequest [GET]> + """ + + def __init__(self, + method=None, url=None, headers=None, files=None, data=None, + params=None, auth=None, cookies=None, hooks=None, json=None): + + # Default empty dicts for dict params. + data = [] if data is None else data + files = [] if files is None else files + headers = {} if headers is None else headers + params = {} if params is None else params + hooks = {} if hooks is None else hooks + + self.hooks = default_hooks() + for (k, v) in list(hooks.items()): + self.register_hook(event=k, hook=v) + + self.method = method + self.url = url + self.headers = headers + self.files = files + self.data = data + self.json = json + self.params = params + self.auth = auth + self.cookies = cookies + + def __repr__(self): + return '<Request [%s]>' % (self.method) + + def prepare(self): + """Constructs a :class:`PreparedRequest <PreparedRequest>` for transmission and returns it.""" + p = PreparedRequest() + p.prepare( + method=self.method, + url=self.url, + headers=self.headers, + files=self.files, + data=self.data, + json=self.json, + params=self.params, + auth=self.auth, + cookies=self.cookies, + hooks=self.hooks, + ) + return p + + +class PreparedRequest(RequestEncodingMixin, RequestHooksMixin): + """The fully mutable :class:`PreparedRequest <PreparedRequest>` object, + containing the exact bytes that will be sent to the server. + + Instances are generated from a :class:`Request <Request>` object, and + should not be instantiated manually; doing so may produce undesirable + effects. + + Usage:: + + >>> import requests + >>> req = requests.Request('GET', 'https://httpbin.org/get') + >>> r = req.prepare() + >>> r + <PreparedRequest [GET]> + + >>> s = requests.Session() + >>> s.send(r) + <Response [200]> + """ + + def __init__(self): + #: HTTP verb to send to the server. + self.method = None + #: HTTP URL to send the request to. + self.url = None + #: dictionary of HTTP headers. + self.headers = None + # The `CookieJar` used to create the Cookie header will be stored here + # after prepare_cookies is called + self._cookies = None + #: request body to send to the server. + self.body = None + #: dictionary of callback hooks, for internal usage. + self.hooks = default_hooks() + #: integer denoting starting position of a readable file-like body. + self._body_position = None + + def prepare(self, + method=None, url=None, headers=None, files=None, data=None, + params=None, auth=None, cookies=None, hooks=None, json=None): + """Prepares the entire request with the given parameters.""" + + self.prepare_method(method) + self.prepare_url(url, params) + self.prepare_headers(headers) + self.prepare_cookies(cookies) + self.prepare_body(data, files, json) + self.prepare_auth(auth, url) + + # Note that prepare_auth must be last to enable authentication schemes + # such as OAuth to work on a fully prepared request. + + # This MUST go after prepare_auth. Authenticators could add a hook + self.prepare_hooks(hooks) + + def __repr__(self): + return '<PreparedRequest [%s]>' % (self.method) + + def copy(self): + p = PreparedRequest() + p.method = self.method + p.url = self.url + p.headers = self.headers.copy() if self.headers is not None else None + p._cookies = _copy_cookie_jar(self._cookies) + p.body = self.body + p.hooks = self.hooks + p._body_position = self._body_position + return p + + def prepare_method(self, method): + """Prepares the given HTTP method.""" + self.method = method + if self.method is not None: + self.method = to_native_string(self.method.upper()) + + @staticmethod + def _get_idna_encoded_host(host): + import idna + + try: + host = idna.encode(host, uts46=True).decode('utf-8') + except idna.IDNAError: + raise UnicodeError + return host + + def prepare_url(self, url, params): + """Prepares the given HTTP URL.""" + #: Accept objects that have string representations. + #: We're unable to blindly call unicode/str functions + #: as this will include the bytestring indicator (b'') + #: on python 3.x. + #: https://github.com/psf/requests/pull/2238 + if isinstance(url, bytes): + url = url.decode('utf8') + else: + url = unicode(url) if is_py2 else str(url) + + # Remove leading whitespaces from url + url = url.lstrip() + + # Don't do any URL preparation for non-HTTP schemes like `mailto`, + # `data` etc to work around exceptions from `url_parse`, which + # handles RFC 3986 only. + if ':' in url and not url.lower().startswith('http'): + self.url = url + return + + # Support for unicode domain names and paths. + try: + scheme, auth, host, port, path, query, fragment = parse_url(url) + except LocationParseError as e: + raise InvalidURL(*e.args) + + if not scheme: + error = ("Invalid URL {0!r}: No schema supplied. Perhaps you meant http://{0}?") + error = error.format(to_native_string(url, 'utf8')) + + raise MissingSchema(error) + + if not host: + raise InvalidURL("Invalid URL %r: No host supplied" % url) + + # In general, we want to try IDNA encoding the hostname if the string contains + # non-ASCII characters. This allows users to automatically get the correct IDNA + # behaviour. For strings containing only ASCII characters, we need to also verify + # it doesn't start with a wildcard (*), before allowing the unencoded hostname. + if not unicode_is_ascii(host): + try: + host = self._get_idna_encoded_host(host) + except UnicodeError: + raise InvalidURL('URL has an invalid label.') + elif host.startswith(u'*'): + raise InvalidURL('URL has an invalid label.') + + # Carefully reconstruct the network location + netloc = auth or '' + if netloc: + netloc += '@' + netloc += host + if port: + netloc += ':' + str(port) + + # Bare domains aren't valid URLs. + if not path: + path = '/' + + if is_py2: + if isinstance(scheme, str): + scheme = scheme.encode('utf-8') + if isinstance(netloc, str): + netloc = netloc.encode('utf-8') + if isinstance(path, str): + path = path.encode('utf-8') + if isinstance(query, str): + query = query.encode('utf-8') + if isinstance(fragment, str): + fragment = fragment.encode('utf-8') + + if isinstance(params, (str, bytes)): + params = to_native_string(params) + + enc_params = self._encode_params(params) + if enc_params: + if query: + query = '%s&%s' % (query, enc_params) + else: + query = enc_params + + url = requote_uri(urlunparse([scheme, netloc, path, None, query, fragment])) + self.url = url + + def prepare_headers(self, headers): + """Prepares the given HTTP headers.""" + + self.headers = CaseInsensitiveDict() + if headers: + for header in headers.items(): + # Raise exception on invalid header value. + check_header_validity(header) + name, value = header + self.headers[to_native_string(name)] = value + + def prepare_body(self, data, files, json=None): + """Prepares the given HTTP body data.""" + + # Check if file, fo, generator, iterator. + # If not, run through normal process. + + # Nottin' on you. + body = None + content_type = None + + if not data and json is not None: + # urllib3 requires a bytes-like body. Python 2's json.dumps + # provides this natively, but Python 3 gives a Unicode string. + content_type = 'application/json' + body = complexjson.dumps(json) + if not isinstance(body, bytes): + body = body.encode('utf-8') + + is_stream = all([ + hasattr(data, '__iter__'), + not isinstance(data, (basestring, list, tuple, Mapping)) + ]) + + if is_stream: + try: + length = super_len(data) + except (TypeError, AttributeError, UnsupportedOperation): + length = None + + body = data + + if getattr(body, 'tell', None) is not None: + # Record the current file position before reading. + # This will allow us to rewind a file in the event + # of a redirect. + try: + self._body_position = body.tell() + except (IOError, OSError): + # This differentiates from None, allowing us to catch + # a failed `tell()` later when trying to rewind the body + self._body_position = object() + + if files: + raise NotImplementedError('Streamed bodies and files are mutually exclusive.') + + if length: + self.headers['Content-Length'] = builtin_str(length) + else: + self.headers['Transfer-Encoding'] = 'chunked' + else: + # Multi-part file uploads. + if files: + (body, content_type) = self._encode_files(files, data) + else: + if data: + body = self._encode_params(data) + if isinstance(data, basestring) or hasattr(data, 'read'): + content_type = None + else: + content_type = 'application/x-www-form-urlencoded' + + self.prepare_content_length(body) + + # Add content-type if it wasn't explicitly provided. + if content_type and ('content-type' not in self.headers): + self.headers['Content-Type'] = content_type + + self.body = body + + def prepare_content_length(self, body): + """Prepare Content-Length header based on request method and body""" + if body is not None: + length = super_len(body) + if length: + # If length exists, set it. Otherwise, we fallback + # to Transfer-Encoding: chunked. + self.headers['Content-Length'] = builtin_str(length) + elif self.method not in ('GET', 'HEAD') and self.headers.get('Content-Length') is None: + # Set Content-Length to 0 for methods that can have a body + # but don't provide one. (i.e. not GET or HEAD) + self.headers['Content-Length'] = '0' + + def prepare_auth(self, auth, url=''): + """Prepares the given HTTP auth data.""" + + # If no Auth is explicitly provided, extract it from the URL first. + if auth is None: + url_auth = get_auth_from_url(self.url) + auth = url_auth if any(url_auth) else None + + if auth: + if isinstance(auth, tuple) and len(auth) == 2: + # special-case basic HTTP auth + auth = HTTPBasicAuth(*auth) + + # Allow auth to make its changes. + r = auth(self) + + # Update self to reflect the auth changes. + self.__dict__.update(r.__dict__) + + # Recompute Content-Length + self.prepare_content_length(self.body) + + def prepare_cookies(self, cookies): + """Prepares the given HTTP cookie data. + + This function eventually generates a ``Cookie`` header from the + given cookies using cookielib. Due to cookielib's design, the header + will not be regenerated if it already exists, meaning this function + can only be called once for the life of the + :class:`PreparedRequest <PreparedRequest>` object. Any subsequent calls + to ``prepare_cookies`` will have no actual effect, unless the "Cookie" + header is removed beforehand. + """ + if isinstance(cookies, cookielib.CookieJar): + self._cookies = cookies + else: + self._cookies = cookiejar_from_dict(cookies) + + cookie_header = get_cookie_header(self._cookies, self) + if cookie_header is not None: + self.headers['Cookie'] = cookie_header + + def prepare_hooks(self, hooks): + """Prepares the given hooks.""" + # hooks can be passed as None to the prepare method and to this + # method. To prevent iterating over None, simply use an empty list + # if hooks is False-y + hooks = hooks or [] + for event in hooks: + self.register_hook(event, hooks[event]) + + +class Response(object): + """The :class:`Response <Response>` object, which contains a + server's response to an HTTP request. + """ + + __attrs__ = [ + '_content', 'status_code', 'headers', 'url', 'history', + 'encoding', 'reason', 'cookies', 'elapsed', 'request' + ] + + def __init__(self): + self._content = False + self._content_consumed = False + self._next = None + + #: Integer Code of responded HTTP Status, e.g. 404 or 200. + self.status_code = None + + #: Case-insensitive Dictionary of Response Headers. + #: For example, ``headers['content-encoding']`` will return the + #: value of a ``'Content-Encoding'`` response header. + self.headers = CaseInsensitiveDict() + + #: File-like object representation of response (for advanced usage). + #: Use of ``raw`` requires that ``stream=True`` be set on the request. + #: This requirement does not apply for use internally to Requests. + self.raw = None + + #: Final URL location of Response. + self.url = None + + #: Encoding to decode with when accessing r.text. + self.encoding = None + + #: A list of :class:`Response <Response>` objects from + #: the history of the Request. Any redirect responses will end + #: up here. The list is sorted from the oldest to the most recent request. + self.history = [] + + #: Textual reason of responded HTTP Status, e.g. "Not Found" or "OK". + self.reason = None + + #: A CookieJar of Cookies the server sent back. + self.cookies = cookiejar_from_dict({}) + + #: The amount of time elapsed between sending the request + #: and the arrival of the response (as a timedelta). + #: This property specifically measures the time taken between sending + #: the first byte of the request and finishing parsing the headers. It + #: is therefore unaffected by consuming the response content or the + #: value of the ``stream`` keyword argument. + self.elapsed = datetime.timedelta(0) + + #: The :class:`PreparedRequest <PreparedRequest>` object to which this + #: is a response. + self.request = None + + def __enter__(self): + return self + + def __exit__(self, *args): + self.close() + + def __getstate__(self): + # Consume everything; accessing the content attribute makes + # sure the content has been fully read. + if not self._content_consumed: + self.content + + return {attr: getattr(self, attr, None) for attr in self.__attrs__} + + def __setstate__(self, state): + for name, value in state.items(): + setattr(self, name, value) + + # pickled objects do not have .raw + setattr(self, '_content_consumed', True) + setattr(self, 'raw', None) + + def __repr__(self): + return '<Response [%s]>' % (self.status_code) + + def __bool__(self): + """Returns True if :attr:`status_code` is less than 400. + + This attribute checks if the status code of the response is between + 400 and 600 to see if there was a client error or a server error. If + the status code, is between 200 and 400, this will return True. This + is **not** a check to see if the response code is ``200 OK``. + """ + return self.ok + + def __nonzero__(self): + """Returns True if :attr:`status_code` is less than 400. + + This attribute checks if the status code of the response is between + 400 and 600 to see if there was a client error or a server error. If + the status code, is between 200 and 400, this will return True. This + is **not** a check to see if the response code is ``200 OK``. + """ + return self.ok + + def __iter__(self): + """Allows you to use a response as an iterator.""" + return self.iter_content(128) + + @property + def ok(self): + """Returns True if :attr:`status_code` is less than 400, False if not. + + This attribute checks if the status code of the response is between + 400 and 600 to see if there was a client error or a server error. If + the status code is between 200 and 400, this will return True. This + is **not** a check to see if the response code is ``200 OK``. + """ + try: + self.raise_for_status() + except HTTPError: + return False + return True + + @property + def is_redirect(self): + """True if this Response is a well-formed HTTP redirect that could have + been processed automatically (by :meth:`Session.resolve_redirects`). + """ + return ('location' in self.headers and self.status_code in REDIRECT_STATI) + + @property + def is_permanent_redirect(self): + """True if this Response one of the permanent versions of redirect.""" + return ('location' in self.headers and self.status_code in (codes.moved_permanently, codes.permanent_redirect)) + + @property + def next(self): + """Returns a PreparedRequest for the next request in a redirect chain, if there is one.""" + return self._next + + @property + def apparent_encoding(self): + """The apparent encoding, provided by the chardet library.""" + return chardet.detect(self.content)['encoding'] + + def iter_content(self, chunk_size=1, decode_unicode=False): + """Iterates over the response data. When stream=True is set on the + request, this avoids reading the content at once into memory for + large responses. The chunk size is the number of bytes it should + read into memory. This is not necessarily the length of each item + returned as decoding can take place. + + chunk_size must be of type int or None. A value of None will + function differently depending on the value of `stream`. + stream=True will read data as it arrives in whatever size the + chunks are received. If stream=False, data is returned as + a single chunk. + + If decode_unicode is True, content will be decoded using the best + available encoding based on the response. + """ + + def generate(): + # Special case for urllib3. + if hasattr(self.raw, 'stream'): + try: + for chunk in self.raw.stream(chunk_size, decode_content=True): + yield chunk + except ProtocolError as e: + raise ChunkedEncodingError(e) + except DecodeError as e: + raise ContentDecodingError(e) + except ReadTimeoutError as e: + raise ConnectionError(e) + else: + # Standard file-like object. + while True: + chunk = self.raw.read(chunk_size) + if not chunk: + break + yield chunk + + self._content_consumed = True + + if self._content_consumed and isinstance(self._content, bool): + raise StreamConsumedError() + elif chunk_size is not None and not isinstance(chunk_size, int): + raise TypeError("chunk_size must be an int, it is instead a %s." % type(chunk_size)) + # simulate reading small chunks of the content + reused_chunks = iter_slices(self._content, chunk_size) + + stream_chunks = generate() + + chunks = reused_chunks if self._content_consumed else stream_chunks + + if decode_unicode: + chunks = stream_decode_response_unicode(chunks, self) + + return chunks + + def iter_lines(self, chunk_size=ITER_CHUNK_SIZE, decode_unicode=False, delimiter=None): + """Iterates over the response data, one line at a time. When + stream=True is set on the request, this avoids reading the + content at once into memory for large responses. + + .. note:: This method is not reentrant safe. + """ + + pending = None + + for chunk in self.iter_content(chunk_size=chunk_size, decode_unicode=decode_unicode): + + if pending is not None: + chunk = pending + chunk + + if delimiter: + lines = chunk.split(delimiter) + else: + lines = chunk.splitlines() + + if lines and lines[-1] and chunk and lines[-1][-1] == chunk[-1]: + pending = lines.pop() + else: + pending = None + + for line in lines: + yield line + + if pending is not None: + yield pending + + @property + def content(self): + """Content of the response, in bytes.""" + + if self._content is False: + # Read the contents. + if self._content_consumed: + raise RuntimeError( + 'The content for this response was already consumed') + + if self.status_code == 0 or self.raw is None: + self._content = None + else: + self._content = b''.join(self.iter_content(CONTENT_CHUNK_SIZE)) or b'' + + self._content_consumed = True + # don't need to release the connection; that's been handled by urllib3 + # since we exhausted the data. + return self._content + + @property + def text(self): + """Content of the response, in unicode. + + If Response.encoding is None, encoding will be guessed using + ``chardet``. + + The encoding of the response content is determined based solely on HTTP + headers, following RFC 2616 to the letter. If you can take advantage of + non-HTTP knowledge to make a better guess at the encoding, you should + set ``r.encoding`` appropriately before accessing this property. + """ + + # Try charset from content-type + content = None + encoding = self.encoding + + if not self.content: + return str('') + + # Fallback to auto-detected encoding. + if self.encoding is None: + encoding = self.apparent_encoding + + # Decode unicode from given encoding. + try: + content = str(self.content, encoding, errors='replace') + except (LookupError, TypeError): + # A LookupError is raised if the encoding was not found which could + # indicate a misspelling or similar mistake. + # + # A TypeError can be raised if encoding is None + # + # So we try blindly encoding. + content = str(self.content, errors='replace') + + return content + + def json(self, **kwargs): + r"""Returns the json-encoded content of a response, if any. + + :param \*\*kwargs: Optional arguments that ``json.loads`` takes. + :raises ValueError: If the response body does not contain valid json. + """ + + if not self.encoding and self.content and len(self.content) > 3: + # No encoding set. JSON RFC 4627 section 3 states we should expect + # UTF-8, -16 or -32. Detect which one to use; If the detection or + # decoding fails, fall back to `self.text` (using chardet to make + # a best guess). + encoding = guess_json_utf(self.content) + if encoding is not None: + try: + return complexjson.loads( + self.content.decode(encoding), **kwargs + ) + except UnicodeDecodeError: + # Wrong UTF codec detected; usually because it's not UTF-8 + # but some other 8-bit codec. This is an RFC violation, + # and the server didn't bother to tell us what codec *was* + # used. + pass + return complexjson.loads(self.text, **kwargs) + + @property + def links(self): + """Returns the parsed header links of the response, if any.""" + + header = self.headers.get('link') + + # l = MultiDict() + l = {} + + if header: + links = parse_header_links(header) + + for link in links: + key = link.get('rel') or link.get('url') + l[key] = link + + return l + + def raise_for_status(self): + """Raises :class:`HTTPError`, if one occurred.""" + + http_error_msg = '' + if isinstance(self.reason, bytes): + # We attempt to decode utf-8 first because some servers + # choose to localize their reason strings. If the string + # isn't utf-8, we fall back to iso-8859-1 for all other + # encodings. (See PR #3538) + try: + reason = self.reason.decode('utf-8') + except UnicodeDecodeError: + reason = self.reason.decode('iso-8859-1') + else: + reason = self.reason + + if 400 <= self.status_code < 500: + http_error_msg = u'%s Client Error: %s for url: %s' % (self.status_code, reason, self.url) + + elif 500 <= self.status_code < 600: + http_error_msg = u'%s Server Error: %s for url: %s' % (self.status_code, reason, self.url) + + if http_error_msg: + raise HTTPError(http_error_msg, response=self) + + def close(self): + """Releases the connection back to the pool. Once this method has been + called the underlying ``raw`` object must not be accessed again. + + *Note: Should not normally need to be called explicitly.* + """ + if not self._content_consumed: + self.raw.close() + + release_conn = getattr(self.raw, 'release_conn', None) + if release_conn is not None: + release_conn() diff --git a/venv/lib/python3.8/site-packages/requests/packages.py b/venv/lib/python3.8/site-packages/requests/packages.py new file mode 100644 index 0000000..7232fe0 --- /dev/null +++ b/venv/lib/python3.8/site-packages/requests/packages.py @@ -0,0 +1,14 @@ +import sys + +# This code exists for backwards compatibility reasons. +# I don't like it either. Just look the other way. :) + +for package in ('urllib3', 'idna', 'chardet'): + locals()[package] = __import__(package) + # This traversal is apparently necessary such that the identities are + # preserved (requests.packages.urllib3.* is urllib3.*) + for mod in list(sys.modules): + if mod == package or mod.startswith(package + '.'): + sys.modules['requests.packages.' + mod] = sys.modules[mod] + +# Kinda cool, though, right? diff --git a/venv/lib/python3.8/site-packages/requests/sessions.py b/venv/lib/python3.8/site-packages/requests/sessions.py new file mode 100644 index 0000000..45ab8a5 --- /dev/null +++ b/venv/lib/python3.8/site-packages/requests/sessions.py @@ -0,0 +1,781 @@ +# -*- coding: utf-8 -*- + +""" +requests.sessions +~~~~~~~~~~~~~~~~~ + +This module provides a Session object to manage and persist settings across +requests (cookies, auth, proxies). +""" +import os +import sys +import time +from datetime import timedelta +from collections import OrderedDict + +from .auth import _basic_auth_str +from .compat import cookielib, is_py3, urljoin, urlparse, Mapping +from .cookies import ( + cookiejar_from_dict, extract_cookies_to_jar, RequestsCookieJar, merge_cookies) +from .models import Request, PreparedRequest, DEFAULT_REDIRECT_LIMIT +from .hooks import default_hooks, dispatch_hook +from ._internal_utils import to_native_string +from .utils import to_key_val_list, default_headers, DEFAULT_PORTS +from .exceptions import ( + TooManyRedirects, InvalidSchema, ChunkedEncodingError, ContentDecodingError) + +from .structures import CaseInsensitiveDict +from .adapters import HTTPAdapter + +from .utils import ( + requote_uri, get_environ_proxies, get_netrc_auth, should_bypass_proxies, + get_auth_from_url, rewind_body +) + +from .status_codes import codes + +# formerly defined here, reexposed here for backward compatibility +from .models import REDIRECT_STATI + +# Preferred clock, based on which one is more accurate on a given system. +if sys.platform == 'win32': + try: # Python 3.4+ + preferred_clock = time.perf_counter + except AttributeError: # Earlier than Python 3. + preferred_clock = time.clock +else: + preferred_clock = time.time + + +def merge_setting(request_setting, session_setting, dict_class=OrderedDict): + """Determines appropriate setting for a given request, taking into account + the explicit setting on that request, and the setting in the session. If a + setting is a dictionary, they will be merged together using `dict_class` + """ + + if session_setting is None: + return request_setting + + if request_setting is None: + return session_setting + + # Bypass if not a dictionary (e.g. verify) + if not ( + isinstance(session_setting, Mapping) and + isinstance(request_setting, Mapping) + ): + return request_setting + + merged_setting = dict_class(to_key_val_list(session_setting)) + merged_setting.update(to_key_val_list(request_setting)) + + # Remove keys that are set to None. Extract keys first to avoid altering + # the dictionary during iteration. + none_keys = [k for (k, v) in merged_setting.items() if v is None] + for key in none_keys: + del merged_setting[key] + + return merged_setting + + +def merge_hooks(request_hooks, session_hooks, dict_class=OrderedDict): + """Properly merges both requests and session hooks. + + This is necessary because when request_hooks == {'response': []}, the + merge breaks Session hooks entirely. + """ + if session_hooks is None or session_hooks.get('response') == []: + return request_hooks + + if request_hooks is None or request_hooks.get('response') == []: + return session_hooks + + return merge_setting(request_hooks, session_hooks, dict_class) + + +class SessionRedirectMixin(object): + + def get_redirect_target(self, resp): + """Receives a Response. Returns a redirect URI or ``None``""" + # Due to the nature of how requests processes redirects this method will + # be called at least once upon the original response and at least twice + # on each subsequent redirect response (if any). + # If a custom mixin is used to handle this logic, it may be advantageous + # to cache the redirect location onto the response object as a private + # attribute. + if resp.is_redirect: + location = resp.headers['location'] + # Currently the underlying http module on py3 decode headers + # in latin1, but empirical evidence suggests that latin1 is very + # rarely used with non-ASCII characters in HTTP headers. + # It is more likely to get UTF8 header rather than latin1. + # This causes incorrect handling of UTF8 encoded location headers. + # To solve this, we re-encode the location in latin1. + if is_py3: + location = location.encode('latin1') + return to_native_string(location, 'utf8') + return None + + def should_strip_auth(self, old_url, new_url): + """Decide whether Authorization header should be removed when redirecting""" + old_parsed = urlparse(old_url) + new_parsed = urlparse(new_url) + if old_parsed.hostname != new_parsed.hostname: + return True + # Special case: allow http -> https redirect when using the standard + # ports. This isn't specified by RFC 7235, but is kept to avoid + # breaking backwards compatibility with older versions of requests + # that allowed any redirects on the same host. + if (old_parsed.scheme == 'http' and old_parsed.port in (80, None) + and new_parsed.scheme == 'https' and new_parsed.port in (443, None)): + return False + + # Handle default port usage corresponding to scheme. + changed_port = old_parsed.port != new_parsed.port + changed_scheme = old_parsed.scheme != new_parsed.scheme + default_port = (DEFAULT_PORTS.get(old_parsed.scheme, None), None) + if (not changed_scheme and old_parsed.port in default_port + and new_parsed.port in default_port): + return False + + # Standard case: root URI must match + return changed_port or changed_scheme + + def resolve_redirects(self, resp, req, stream=False, timeout=None, + verify=True, cert=None, proxies=None, yield_requests=False, **adapter_kwargs): + """Receives a Response. Returns a generator of Responses or Requests.""" + + hist = [] # keep track of history + + url = self.get_redirect_target(resp) + previous_fragment = urlparse(req.url).fragment + while url: + prepared_request = req.copy() + + # Update history and keep track of redirects. + # resp.history must ignore the original request in this loop + hist.append(resp) + resp.history = hist[1:] + + try: + resp.content # Consume socket so it can be released + except (ChunkedEncodingError, ContentDecodingError, RuntimeError): + resp.raw.read(decode_content=False) + + if len(resp.history) >= self.max_redirects: + raise TooManyRedirects('Exceeded {} redirects.'.format(self.max_redirects), response=resp) + + # Release the connection back into the pool. + resp.close() + + # Handle redirection without scheme (see: RFC 1808 Section 4) + if url.startswith('//'): + parsed_rurl = urlparse(resp.url) + url = ':'.join([to_native_string(parsed_rurl.scheme), url]) + + # Normalize url case and attach previous fragment if needed (RFC 7231 7.1.2) + parsed = urlparse(url) + if parsed.fragment == '' and previous_fragment: + parsed = parsed._replace(fragment=previous_fragment) + elif parsed.fragment: + previous_fragment = parsed.fragment + url = parsed.geturl() + + # Facilitate relative 'location' headers, as allowed by RFC 7231. + # (e.g. '/path/to/resource' instead of 'http://domain.tld/path/to/resource') + # Compliant with RFC3986, we percent encode the url. + if not parsed.netloc: + url = urljoin(resp.url, requote_uri(url)) + else: + url = requote_uri(url) + + prepared_request.url = to_native_string(url) + + self.rebuild_method(prepared_request, resp) + + # https://github.com/psf/requests/issues/1084 + if resp.status_code not in (codes.temporary_redirect, codes.permanent_redirect): + # https://github.com/psf/requests/issues/3490 + purged_headers = ('Content-Length', 'Content-Type', 'Transfer-Encoding') + for header in purged_headers: + prepared_request.headers.pop(header, None) + prepared_request.body = None + + headers = prepared_request.headers + headers.pop('Cookie', None) + + # Extract any cookies sent on the response to the cookiejar + # in the new request. Because we've mutated our copied prepared + # request, use the old one that we haven't yet touched. + extract_cookies_to_jar(prepared_request._cookies, req, resp.raw) + merge_cookies(prepared_request._cookies, self.cookies) + prepared_request.prepare_cookies(prepared_request._cookies) + + # Rebuild auth and proxy information. + proxies = self.rebuild_proxies(prepared_request, proxies) + self.rebuild_auth(prepared_request, resp) + + # A failed tell() sets `_body_position` to `object()`. This non-None + # value ensures `rewindable` will be True, allowing us to raise an + # UnrewindableBodyError, instead of hanging the connection. + rewindable = ( + prepared_request._body_position is not None and + ('Content-Length' in headers or 'Transfer-Encoding' in headers) + ) + + # Attempt to rewind consumed file-like object. + if rewindable: + rewind_body(prepared_request) + + # Override the original request. + req = prepared_request + + if yield_requests: + yield req + else: + + resp = self.send( + req, + stream=stream, + timeout=timeout, + verify=verify, + cert=cert, + proxies=proxies, + allow_redirects=False, + **adapter_kwargs + ) + + extract_cookies_to_jar(self.cookies, prepared_request, resp.raw) + + # extract redirect url, if any, for the next loop + url = self.get_redirect_target(resp) + yield resp + + def rebuild_auth(self, prepared_request, response): + """When being redirected we may want to strip authentication from the + request to avoid leaking credentials. This method intelligently removes + and reapplies authentication where possible to avoid credential loss. + """ + headers = prepared_request.headers + url = prepared_request.url + + if 'Authorization' in headers and self.should_strip_auth(response.request.url, url): + # If we get redirected to a new host, we should strip out any + # authentication headers. + del headers['Authorization'] + + # .netrc might have more auth for us on our new host. + new_auth = get_netrc_auth(url) if self.trust_env else None + if new_auth is not None: + prepared_request.prepare_auth(new_auth) + + + def rebuild_proxies(self, prepared_request, proxies): + """This method re-evaluates the proxy configuration by considering the + environment variables. If we are redirected to a URL covered by + NO_PROXY, we strip the proxy configuration. Otherwise, we set missing + proxy keys for this URL (in case they were stripped by a previous + redirect). + + This method also replaces the Proxy-Authorization header where + necessary. + + :rtype: dict + """ + proxies = proxies if proxies is not None else {} + headers = prepared_request.headers + url = prepared_request.url + scheme = urlparse(url).scheme + new_proxies = proxies.copy() + no_proxy = proxies.get('no_proxy') + + bypass_proxy = should_bypass_proxies(url, no_proxy=no_proxy) + if self.trust_env and not bypass_proxy: + environ_proxies = get_environ_proxies(url, no_proxy=no_proxy) + + proxy = environ_proxies.get(scheme, environ_proxies.get('all')) + + if proxy: + new_proxies.setdefault(scheme, proxy) + + if 'Proxy-Authorization' in headers: + del headers['Proxy-Authorization'] + + try: + username, password = get_auth_from_url(new_proxies[scheme]) + except KeyError: + username, password = None, None + + if username and password: + headers['Proxy-Authorization'] = _basic_auth_str(username, password) + + return new_proxies + + def rebuild_method(self, prepared_request, response): + """When being redirected we may want to change the method of the request + based on certain specs or browser behavior. + """ + method = prepared_request.method + + # https://tools.ietf.org/html/rfc7231#section-6.4.4 + if response.status_code == codes.see_other and method != 'HEAD': + method = 'GET' + + # Do what the browsers do, despite standards... + # First, turn 302s into GETs. + if response.status_code == codes.found and method != 'HEAD': + method = 'GET' + + # Second, if a POST is responded to with a 301, turn it into a GET. + # This bizarre behaviour is explained in Issue 1704. + if response.status_code == codes.moved and method == 'POST': + method = 'GET' + + prepared_request.method = method + + +class Session(SessionRedirectMixin): + """A Requests session. + + Provides cookie persistence, connection-pooling, and configuration. + + Basic Usage:: + + >>> import requests + >>> s = requests.Session() + >>> s.get('https://httpbin.org/get') + <Response [200]> + + Or as a context manager:: + + >>> with requests.Session() as s: + ... s.get('https://httpbin.org/get') + <Response [200]> + """ + + __attrs__ = [ + 'headers', 'cookies', 'auth', 'proxies', 'hooks', 'params', 'verify', + 'cert', 'adapters', 'stream', 'trust_env', + 'max_redirects', + ] + + def __init__(self): + + #: A case-insensitive dictionary of headers to be sent on each + #: :class:`Request <Request>` sent from this + #: :class:`Session <Session>`. + self.headers = default_headers() + + #: Default Authentication tuple or object to attach to + #: :class:`Request <Request>`. + self.auth = None + + #: Dictionary mapping protocol or protocol and host to the URL of the proxy + #: (e.g. {'http': 'foo.bar:3128', 'http://host.name': 'foo.bar:4012'}) to + #: be used on each :class:`Request <Request>`. + self.proxies = {} + + #: Event-handling hooks. + self.hooks = default_hooks() + + #: Dictionary of querystring data to attach to each + #: :class:`Request <Request>`. The dictionary values may be lists for + #: representing multivalued query parameters. + self.params = {} + + #: Stream response content default. + self.stream = False + + #: SSL Verification default. + #: Defaults to `True`, requiring requests to verify the TLS certificate at the + #: remote end. + #: If verify is set to `False`, requests will accept any TLS certificate + #: presented by the server, and will ignore hostname mismatches and/or + #: expired certificates, which will make your application vulnerable to + #: man-in-the-middle (MitM) attacks. + #: Only set this to `False` for testing. + self.verify = True + + #: SSL client certificate default, if String, path to ssl client + #: cert file (.pem). If Tuple, ('cert', 'key') pair. + self.cert = None + + #: Maximum number of redirects allowed. If the request exceeds this + #: limit, a :class:`TooManyRedirects` exception is raised. + #: This defaults to requests.models.DEFAULT_REDIRECT_LIMIT, which is + #: 30. + self.max_redirects = DEFAULT_REDIRECT_LIMIT + + #: Trust environment settings for proxy configuration, default + #: authentication and similar. + self.trust_env = True + + #: A CookieJar containing all currently outstanding cookies set on this + #: session. By default it is a + #: :class:`RequestsCookieJar <requests.cookies.RequestsCookieJar>`, but + #: may be any other ``cookielib.CookieJar`` compatible object. + self.cookies = cookiejar_from_dict({}) + + # Default connection adapters. + self.adapters = OrderedDict() + self.mount('https://', HTTPAdapter()) + self.mount('http://', HTTPAdapter()) + + def __enter__(self): + return self + + def __exit__(self, *args): + self.close() + + def prepare_request(self, request): + """Constructs a :class:`PreparedRequest <PreparedRequest>` for + transmission and returns it. The :class:`PreparedRequest` has settings + merged from the :class:`Request <Request>` instance and those of the + :class:`Session`. + + :param request: :class:`Request` instance to prepare with this + session's settings. + :rtype: requests.PreparedRequest + """ + cookies = request.cookies or {} + + # Bootstrap CookieJar. + if not isinstance(cookies, cookielib.CookieJar): + cookies = cookiejar_from_dict(cookies) + + # Merge with session cookies + merged_cookies = merge_cookies( + merge_cookies(RequestsCookieJar(), self.cookies), cookies) + + # Set environment's basic authentication if not explicitly set. + auth = request.auth + if self.trust_env and not auth and not self.auth: + auth = get_netrc_auth(request.url) + + p = PreparedRequest() + p.prepare( + method=request.method.upper(), + url=request.url, + files=request.files, + data=request.data, + json=request.json, + headers=merge_setting(request.headers, self.headers, dict_class=CaseInsensitiveDict), + params=merge_setting(request.params, self.params), + auth=merge_setting(auth, self.auth), + cookies=merged_cookies, + hooks=merge_hooks(request.hooks, self.hooks), + ) + return p + + def request(self, method, url, + params=None, data=None, headers=None, cookies=None, files=None, + auth=None, timeout=None, allow_redirects=True, proxies=None, + hooks=None, stream=None, verify=None, cert=None, json=None): + """Constructs a :class:`Request <Request>`, prepares it and sends it. + Returns :class:`Response <Response>` object. + + :param method: method for the new :class:`Request` object. + :param url: URL for the new :class:`Request` object. + :param params: (optional) Dictionary or bytes to be sent in the query + string for the :class:`Request`. + :param data: (optional) Dictionary, list of tuples, bytes, or file-like + object to send in the body of the :class:`Request`. + :param json: (optional) json to send in the body of the + :class:`Request`. + :param headers: (optional) Dictionary of HTTP Headers to send with the + :class:`Request`. + :param cookies: (optional) Dict or CookieJar object to send with the + :class:`Request`. + :param files: (optional) Dictionary of ``'filename': file-like-objects`` + for multipart encoding upload. + :param auth: (optional) Auth tuple or callable to enable + Basic/Digest/Custom HTTP Auth. + :param timeout: (optional) How long to wait for the server to send + data before giving up, as a float, or a :ref:`(connect timeout, + read timeout) <timeouts>` tuple. + :type timeout: float or tuple + :param allow_redirects: (optional) Set to True by default. + :type allow_redirects: bool + :param proxies: (optional) Dictionary mapping protocol or protocol and + hostname to the URL of the proxy. + :param stream: (optional) whether to immediately download the response + content. Defaults to ``False``. + :param verify: (optional) Either a boolean, in which case it controls whether we verify + the server's TLS certificate, or a string, in which case it must be a path + to a CA bundle to use. Defaults to ``True``. When set to + ``False``, requests will accept any TLS certificate presented by + the server, and will ignore hostname mismatches and/or expired + certificates, which will make your application vulnerable to + man-in-the-middle (MitM) attacks. Setting verify to ``False`` + may be useful during local development or testing. + :param cert: (optional) if String, path to ssl client cert file (.pem). + If Tuple, ('cert', 'key') pair. + :rtype: requests.Response + """ + # Create the Request. + req = Request( + method=method.upper(), + url=url, + headers=headers, + files=files, + data=data or {}, + json=json, + params=params or {}, + auth=auth, + cookies=cookies, + hooks=hooks, + ) + prep = self.prepare_request(req) + + proxies = proxies or {} + + settings = self.merge_environment_settings( + prep.url, proxies, stream, verify, cert + ) + + # Send the request. + send_kwargs = { + 'timeout': timeout, + 'allow_redirects': allow_redirects, + } + send_kwargs.update(settings) + resp = self.send(prep, **send_kwargs) + + return resp + + def get(self, url, **kwargs): + r"""Sends a GET request. Returns :class:`Response` object. + + :param url: URL for the new :class:`Request` object. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :rtype: requests.Response + """ + + kwargs.setdefault('allow_redirects', True) + return self.request('GET', url, **kwargs) + + def options(self, url, **kwargs): + r"""Sends a OPTIONS request. Returns :class:`Response` object. + + :param url: URL for the new :class:`Request` object. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :rtype: requests.Response + """ + + kwargs.setdefault('allow_redirects', True) + return self.request('OPTIONS', url, **kwargs) + + def head(self, url, **kwargs): + r"""Sends a HEAD request. Returns :class:`Response` object. + + :param url: URL for the new :class:`Request` object. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :rtype: requests.Response + """ + + kwargs.setdefault('allow_redirects', False) + return self.request('HEAD', url, **kwargs) + + def post(self, url, data=None, json=None, **kwargs): + r"""Sends a POST request. Returns :class:`Response` object. + + :param url: URL for the new :class:`Request` object. + :param data: (optional) Dictionary, list of tuples, bytes, or file-like + object to send in the body of the :class:`Request`. + :param json: (optional) json to send in the body of the :class:`Request`. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :rtype: requests.Response + """ + + return self.request('POST', url, data=data, json=json, **kwargs) + + def put(self, url, data=None, **kwargs): + r"""Sends a PUT request. Returns :class:`Response` object. + + :param url: URL for the new :class:`Request` object. + :param data: (optional) Dictionary, list of tuples, bytes, or file-like + object to send in the body of the :class:`Request`. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :rtype: requests.Response + """ + + return self.request('PUT', url, data=data, **kwargs) + + def patch(self, url, data=None, **kwargs): + r"""Sends a PATCH request. Returns :class:`Response` object. + + :param url: URL for the new :class:`Request` object. + :param data: (optional) Dictionary, list of tuples, bytes, or file-like + object to send in the body of the :class:`Request`. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :rtype: requests.Response + """ + + return self.request('PATCH', url, data=data, **kwargs) + + def delete(self, url, **kwargs): + r"""Sends a DELETE request. Returns :class:`Response` object. + + :param url: URL for the new :class:`Request` object. + :param \*\*kwargs: Optional arguments that ``request`` takes. + :rtype: requests.Response + """ + + return self.request('DELETE', url, **kwargs) + + def send(self, request, **kwargs): + """Send a given PreparedRequest. + + :rtype: requests.Response + """ + # Set defaults that the hooks can utilize to ensure they always have + # the correct parameters to reproduce the previous request. + kwargs.setdefault('stream', self.stream) + kwargs.setdefault('verify', self.verify) + kwargs.setdefault('cert', self.cert) + kwargs.setdefault('proxies', self.proxies) + + # It's possible that users might accidentally send a Request object. + # Guard against that specific failure case. + if isinstance(request, Request): + raise ValueError('You can only send PreparedRequests.') + + # Set up variables needed for resolve_redirects and dispatching of hooks + allow_redirects = kwargs.pop('allow_redirects', True) + stream = kwargs.get('stream') + hooks = request.hooks + + # Get the appropriate adapter to use + adapter = self.get_adapter(url=request.url) + + # Start time (approximately) of the request + start = preferred_clock() + + # Send the request + r = adapter.send(request, **kwargs) + + # Total elapsed time of the request (approximately) + elapsed = preferred_clock() - start + r.elapsed = timedelta(seconds=elapsed) + + # Response manipulation hooks + r = dispatch_hook('response', hooks, r, **kwargs) + + # Persist cookies + if r.history: + + # If the hooks create history then we want those cookies too + for resp in r.history: + extract_cookies_to_jar(self.cookies, resp.request, resp.raw) + + extract_cookies_to_jar(self.cookies, request, r.raw) + + # Resolve redirects if allowed. + if allow_redirects: + # Redirect resolving generator. + gen = self.resolve_redirects(r, request, **kwargs) + history = [resp for resp in gen] + else: + history = [] + + # Shuffle things around if there's history. + if history: + # Insert the first (original) request at the start + history.insert(0, r) + # Get the last request made + r = history.pop() + r.history = history + + # If redirects aren't being followed, store the response on the Request for Response.next(). + if not allow_redirects: + try: + r._next = next(self.resolve_redirects(r, request, yield_requests=True, **kwargs)) + except StopIteration: + pass + + if not stream: + r.content + + return r + + def merge_environment_settings(self, url, proxies, stream, verify, cert): + """ + Check the environment and merge it with some settings. + + :rtype: dict + """ + # Gather clues from the surrounding environment. + if self.trust_env: + # Set environment's proxies. + no_proxy = proxies.get('no_proxy') if proxies is not None else None + env_proxies = get_environ_proxies(url, no_proxy=no_proxy) + for (k, v) in env_proxies.items(): + proxies.setdefault(k, v) + + # Look for requests environment configuration and be compatible + # with cURL. + if verify is True or verify is None: + verify = (os.environ.get('REQUESTS_CA_BUNDLE') or + os.environ.get('CURL_CA_BUNDLE')) + + # Merge all the kwargs. + proxies = merge_setting(proxies, self.proxies) + stream = merge_setting(stream, self.stream) + verify = merge_setting(verify, self.verify) + cert = merge_setting(cert, self.cert) + + return {'verify': verify, 'proxies': proxies, 'stream': stream, + 'cert': cert} + + def get_adapter(self, url): + """ + Returns the appropriate connection adapter for the given URL. + + :rtype: requests.adapters.BaseAdapter + """ + for (prefix, adapter) in self.adapters.items(): + + if url.lower().startswith(prefix.lower()): + return adapter + + # Nothing matches :-/ + raise InvalidSchema("No connection adapters were found for {!r}".format(url)) + + def close(self): + """Closes all adapters and as such the session""" + for v in self.adapters.values(): + v.close() + + def mount(self, prefix, adapter): + """Registers a connection adapter to a prefix. + + Adapters are sorted in descending order by prefix length. + """ + self.adapters[prefix] = adapter + keys_to_move = [k for k in self.adapters if len(k) < len(prefix)] + + for key in keys_to_move: + self.adapters[key] = self.adapters.pop(key) + + def __getstate__(self): + state = {attr: getattr(self, attr, None) for attr in self.__attrs__} + return state + + def __setstate__(self, state): + for attr, value in state.items(): + setattr(self, attr, value) + + +def session(): + """ + Returns a :class:`Session` for context-management. + + .. deprecated:: 1.0.0 + + This method has been deprecated since version 1.0.0 and is only kept for + backwards compatibility. New code should use :class:`~requests.sessions.Session` + to create a session. This may be removed at a future date. + + :rtype: Session + """ + return Session() diff --git a/venv/lib/python3.8/site-packages/requests/status_codes.py b/venv/lib/python3.8/site-packages/requests/status_codes.py new file mode 100644 index 0000000..d80a7cd --- /dev/null +++ b/venv/lib/python3.8/site-packages/requests/status_codes.py @@ -0,0 +1,123 @@ +# -*- coding: utf-8 -*- + +r""" +The ``codes`` object defines a mapping from common names for HTTP statuses +to their numerical codes, accessible either as attributes or as dictionary +items. + +Example:: + + >>> import requests + >>> requests.codes['temporary_redirect'] + 307 + >>> requests.codes.teapot + 418 + >>> requests.codes['\o/'] + 200 + +Some codes have multiple names, and both upper- and lower-case versions of +the names are allowed. For example, ``codes.ok``, ``codes.OK``, and +``codes.okay`` all correspond to the HTTP status code 200. +""" + +from .structures import LookupDict + +_codes = { + + # Informational. + 100: ('continue',), + 101: ('switching_protocols',), + 102: ('processing',), + 103: ('checkpoint',), + 122: ('uri_too_long', 'request_uri_too_long'), + 200: ('ok', 'okay', 'all_ok', 'all_okay', 'all_good', '\\o/', '✓'), + 201: ('created',), + 202: ('accepted',), + 203: ('non_authoritative_info', 'non_authoritative_information'), + 204: ('no_content',), + 205: ('reset_content', 'reset'), + 206: ('partial_content', 'partial'), + 207: ('multi_status', 'multiple_status', 'multi_stati', 'multiple_stati'), + 208: ('already_reported',), + 226: ('im_used',), + + # Redirection. + 300: ('multiple_choices',), + 301: ('moved_permanently', 'moved', '\\o-'), + 302: ('found',), + 303: ('see_other', 'other'), + 304: ('not_modified',), + 305: ('use_proxy',), + 306: ('switch_proxy',), + 307: ('temporary_redirect', 'temporary_moved', 'temporary'), + 308: ('permanent_redirect', + 'resume_incomplete', 'resume',), # These 2 to be removed in 3.0 + + # Client Error. + 400: ('bad_request', 'bad'), + 401: ('unauthorized',), + 402: ('payment_required', 'payment'), + 403: ('forbidden',), + 404: ('not_found', '-o-'), + 405: ('method_not_allowed', 'not_allowed'), + 406: ('not_acceptable',), + 407: ('proxy_authentication_required', 'proxy_auth', 'proxy_authentication'), + 408: ('request_timeout', 'timeout'), + 409: ('conflict',), + 410: ('gone',), + 411: ('length_required',), + 412: ('precondition_failed', 'precondition'), + 413: ('request_entity_too_large',), + 414: ('request_uri_too_large',), + 415: ('unsupported_media_type', 'unsupported_media', 'media_type'), + 416: ('requested_range_not_satisfiable', 'requested_range', 'range_not_satisfiable'), + 417: ('expectation_failed',), + 418: ('im_a_teapot', 'teapot', 'i_am_a_teapot'), + 421: ('misdirected_request',), + 422: ('unprocessable_entity', 'unprocessable'), + 423: ('locked',), + 424: ('failed_dependency', 'dependency'), + 425: ('unordered_collection', 'unordered'), + 426: ('upgrade_required', 'upgrade'), + 428: ('precondition_required', 'precondition'), + 429: ('too_many_requests', 'too_many'), + 431: ('header_fields_too_large', 'fields_too_large'), + 444: ('no_response', 'none'), + 449: ('retry_with', 'retry'), + 450: ('blocked_by_windows_parental_controls', 'parental_controls'), + 451: ('unavailable_for_legal_reasons', 'legal_reasons'), + 499: ('client_closed_request',), + + # Server Error. + 500: ('internal_server_error', 'server_error', '/o\\', '✗'), + 501: ('not_implemented',), + 502: ('bad_gateway',), + 503: ('service_unavailable', 'unavailable'), + 504: ('gateway_timeout',), + 505: ('http_version_not_supported', 'http_version'), + 506: ('variant_also_negotiates',), + 507: ('insufficient_storage',), + 509: ('bandwidth_limit_exceeded', 'bandwidth'), + 510: ('not_extended',), + 511: ('network_authentication_required', 'network_auth', 'network_authentication'), +} + +codes = LookupDict(name='status_codes') + +def _init(): + for code, titles in _codes.items(): + for title in titles: + setattr(codes, title, code) + if not title.startswith(('\\', '/')): + setattr(codes, title.upper(), code) + + def doc(code): + names = ', '.join('``%s``' % n for n in _codes[code]) + return '* %d: %s' % (code, names) + + global __doc__ + __doc__ = (__doc__ + '\n' + + '\n'.join(doc(code) for code in sorted(_codes)) + if __doc__ is not None else None) + +_init() diff --git a/venv/lib/python3.8/site-packages/requests/structures.py b/venv/lib/python3.8/site-packages/requests/structures.py new file mode 100644 index 0000000..8ee0ba7 --- /dev/null +++ b/venv/lib/python3.8/site-packages/requests/structures.py @@ -0,0 +1,105 @@ +# -*- coding: utf-8 -*- + +""" +requests.structures +~~~~~~~~~~~~~~~~~~~ + +Data structures that power Requests. +""" + +from collections import OrderedDict + +from .compat import Mapping, MutableMapping + + +class CaseInsensitiveDict(MutableMapping): + """A case-insensitive ``dict``-like object. + + Implements all methods and operations of + ``MutableMapping`` as well as dict's ``copy``. Also + provides ``lower_items``. + + All keys are expected to be strings. The structure remembers the + case of the last key to be set, and ``iter(instance)``, + ``keys()``, ``items()``, ``iterkeys()``, and ``iteritems()`` + will contain case-sensitive keys. However, querying and contains + testing is case insensitive:: + + cid = CaseInsensitiveDict() + cid['Accept'] = 'application/json' + cid['aCCEPT'] == 'application/json' # True + list(cid) == ['Accept'] # True + + For example, ``headers['content-encoding']`` will return the + value of a ``'Content-Encoding'`` response header, regardless + of how the header name was originally stored. + + If the constructor, ``.update``, or equality comparison + operations are given keys that have equal ``.lower()``s, the + behavior is undefined. + """ + + def __init__(self, data=None, **kwargs): + self._store = OrderedDict() + if data is None: + data = {} + self.update(data, **kwargs) + + def __setitem__(self, key, value): + # Use the lowercased key for lookups, but store the actual + # key alongside the value. + self._store[key.lower()] = (key, value) + + def __getitem__(self, key): + return self._store[key.lower()][1] + + def __delitem__(self, key): + del self._store[key.lower()] + + def __iter__(self): + return (casedkey for casedkey, mappedvalue in self._store.values()) + + def __len__(self): + return len(self._store) + + def lower_items(self): + """Like iteritems(), but with all lowercase keys.""" + return ( + (lowerkey, keyval[1]) + for (lowerkey, keyval) + in self._store.items() + ) + + def __eq__(self, other): + if isinstance(other, Mapping): + other = CaseInsensitiveDict(other) + else: + return NotImplemented + # Compare insensitively + return dict(self.lower_items()) == dict(other.lower_items()) + + # Copy is required + def copy(self): + return CaseInsensitiveDict(self._store.values()) + + def __repr__(self): + return str(dict(self.items())) + + +class LookupDict(dict): + """Dictionary lookup object.""" + + def __init__(self, name=None): + self.name = name + super(LookupDict, self).__init__() + + def __repr__(self): + return '<lookup \'%s\'>' % (self.name) + + def __getitem__(self, key): + # We allow fall-through here, so values default to None + + return self.__dict__.get(key, None) + + def get(self, key, default=None): + return self.__dict__.get(key, default) diff --git a/venv/lib/python3.8/site-packages/requests/utils.py b/venv/lib/python3.8/site-packages/requests/utils.py new file mode 100644 index 0000000..db67938 --- /dev/null +++ b/venv/lib/python3.8/site-packages/requests/utils.py @@ -0,0 +1,992 @@ +# -*- coding: utf-8 -*- + +""" +requests.utils +~~~~~~~~~~~~~~ + +This module provides utility functions that are used within Requests +that are also useful for external consumption. +""" + +import codecs +import contextlib +import io +import os +import re +import socket +import struct +import sys +import tempfile +import warnings +import zipfile +from collections import OrderedDict + +from .__version__ import __version__ +from . import certs +# to_native_string is unused here, but imported here for backwards compatibility +from ._internal_utils import to_native_string +from .compat import parse_http_list as _parse_list_header +from .compat import ( + quote, urlparse, bytes, str, unquote, getproxies, + proxy_bypass, urlunparse, basestring, integer_types, is_py3, + proxy_bypass_environment, getproxies_environment, Mapping) +from .cookies import cookiejar_from_dict +from .structures import CaseInsensitiveDict +from .exceptions import ( + InvalidURL, InvalidHeader, FileModeWarning, UnrewindableBodyError) + +NETRC_FILES = ('.netrc', '_netrc') + +DEFAULT_CA_BUNDLE_PATH = certs.where() + +DEFAULT_PORTS = {'http': 80, 'https': 443} + + +if sys.platform == 'win32': + # provide a proxy_bypass version on Windows without DNS lookups + + def proxy_bypass_registry(host): + try: + if is_py3: + import winreg + else: + import _winreg as winreg + except ImportError: + return False + + try: + internetSettings = winreg.OpenKey(winreg.HKEY_CURRENT_USER, + r'Software\Microsoft\Windows\CurrentVersion\Internet Settings') + # ProxyEnable could be REG_SZ or REG_DWORD, normalizing it + proxyEnable = int(winreg.QueryValueEx(internetSettings, + 'ProxyEnable')[0]) + # ProxyOverride is almost always a string + proxyOverride = winreg.QueryValueEx(internetSettings, + 'ProxyOverride')[0] + except OSError: + return False + if not proxyEnable or not proxyOverride: + return False + + # make a check value list from the registry entry: replace the + # '<local>' string by the localhost entry and the corresponding + # canonical entry. + proxyOverride = proxyOverride.split(';') + # now check if we match one of the registry values. + for test in proxyOverride: + if test == '<local>': + if '.' not in host: + return True + test = test.replace(".", r"\.") # mask dots + test = test.replace("*", r".*") # change glob sequence + test = test.replace("?", r".") # change glob char + if re.match(test, host, re.I): + return True + return False + + def proxy_bypass(host): # noqa + """Return True, if the host should be bypassed. + + Checks proxy settings gathered from the environment, if specified, + or the registry. + """ + if getproxies_environment(): + return proxy_bypass_environment(host) + else: + return proxy_bypass_registry(host) + + +def dict_to_sequence(d): + """Returns an internal sequence dictionary update.""" + + if hasattr(d, 'items'): + d = d.items() + + return d + + +def super_len(o): + total_length = None + current_position = 0 + + if hasattr(o, '__len__'): + total_length = len(o) + + elif hasattr(o, 'len'): + total_length = o.len + + elif hasattr(o, 'fileno'): + try: + fileno = o.fileno() + except io.UnsupportedOperation: + pass + else: + total_length = os.fstat(fileno).st_size + + # Having used fstat to determine the file length, we need to + # confirm that this file was opened up in binary mode. + if 'b' not in o.mode: + warnings.warn(( + "Requests has determined the content-length for this " + "request using the binary size of the file: however, the " + "file has been opened in text mode (i.e. without the 'b' " + "flag in the mode). This may lead to an incorrect " + "content-length. In Requests 3.0, support will be removed " + "for files in text mode."), + FileModeWarning + ) + + if hasattr(o, 'tell'): + try: + current_position = o.tell() + except (OSError, IOError): + # This can happen in some weird situations, such as when the file + # is actually a special file descriptor like stdin. In this + # instance, we don't know what the length is, so set it to zero and + # let requests chunk it instead. + if total_length is not None: + current_position = total_length + else: + if hasattr(o, 'seek') and total_length is None: + # StringIO and BytesIO have seek but no useable fileno + try: + # seek to end of file + o.seek(0, 2) + total_length = o.tell() + + # seek back to current position to support + # partially read file-like objects + o.seek(current_position or 0) + except (OSError, IOError): + total_length = 0 + + if total_length is None: + total_length = 0 + + return max(0, total_length - current_position) + + +def get_netrc_auth(url, raise_errors=False): + """Returns the Requests tuple auth for a given url from netrc.""" + + netrc_file = os.environ.get('NETRC') + if netrc_file is not None: + netrc_locations = (netrc_file,) + else: + netrc_locations = ('~/{}'.format(f) for f in NETRC_FILES) + + try: + from netrc import netrc, NetrcParseError + + netrc_path = None + + for f in netrc_locations: + try: + loc = os.path.expanduser(f) + except KeyError: + # os.path.expanduser can fail when $HOME is undefined and + # getpwuid fails. See https://bugs.python.org/issue20164 & + # https://github.com/psf/requests/issues/1846 + return + + if os.path.exists(loc): + netrc_path = loc + break + + # Abort early if there isn't one. + if netrc_path is None: + return + + ri = urlparse(url) + + # Strip port numbers from netloc. This weird `if...encode`` dance is + # used for Python 3.2, which doesn't support unicode literals. + splitstr = b':' + if isinstance(url, str): + splitstr = splitstr.decode('ascii') + host = ri.netloc.split(splitstr)[0] + + try: + _netrc = netrc(netrc_path).authenticators(host) + if _netrc: + # Return with login / password + login_i = (0 if _netrc[0] else 1) + return (_netrc[login_i], _netrc[2]) + except (NetrcParseError, IOError): + # If there was a parsing error or a permissions issue reading the file, + # we'll just skip netrc auth unless explicitly asked to raise errors. + if raise_errors: + raise + + # App Engine hackiness. + except (ImportError, AttributeError): + pass + + +def guess_filename(obj): + """Tries to guess the filename of the given object.""" + name = getattr(obj, 'name', None) + if (name and isinstance(name, basestring) and name[0] != '<' and + name[-1] != '>'): + return os.path.basename(name) + + +def extract_zipped_paths(path): + """Replace nonexistent paths that look like they refer to a member of a zip + archive with the location of an extracted copy of the target, or else + just return the provided path unchanged. + """ + if os.path.exists(path): + # this is already a valid path, no need to do anything further + return path + + # find the first valid part of the provided path and treat that as a zip archive + # assume the rest of the path is the name of a member in the archive + archive, member = os.path.split(path) + while archive and not os.path.exists(archive): + archive, prefix = os.path.split(archive) + member = '/'.join([prefix, member]) + + if not zipfile.is_zipfile(archive): + return path + + zip_file = zipfile.ZipFile(archive) + if member not in zip_file.namelist(): + return path + + # we have a valid zip archive and a valid member of that archive + tmp = tempfile.gettempdir() + extracted_path = os.path.join(tmp, *member.split('/')) + if not os.path.exists(extracted_path): + extracted_path = zip_file.extract(member, path=tmp) + + return extracted_path + + +def from_key_val_list(value): + """Take an object and test to see if it can be represented as a + dictionary. Unless it can not be represented as such, return an + OrderedDict, e.g., + + :: + + >>> from_key_val_list([('key', 'val')]) + OrderedDict([('key', 'val')]) + >>> from_key_val_list('string') + Traceback (most recent call last): + ... + ValueError: cannot encode objects that are not 2-tuples + >>> from_key_val_list({'key': 'val'}) + OrderedDict([('key', 'val')]) + + :rtype: OrderedDict + """ + if value is None: + return None + + if isinstance(value, (str, bytes, bool, int)): + raise ValueError('cannot encode objects that are not 2-tuples') + + return OrderedDict(value) + + +def to_key_val_list(value): + """Take an object and test to see if it can be represented as a + dictionary. If it can be, return a list of tuples, e.g., + + :: + + >>> to_key_val_list([('key', 'val')]) + [('key', 'val')] + >>> to_key_val_list({'key': 'val'}) + [('key', 'val')] + >>> to_key_val_list('string') + Traceback (most recent call last): + ... + ValueError: cannot encode objects that are not 2-tuples + + :rtype: list + """ + if value is None: + return None + + if isinstance(value, (str, bytes, bool, int)): + raise ValueError('cannot encode objects that are not 2-tuples') + + if isinstance(value, Mapping): + value = value.items() + + return list(value) + + +# From mitsuhiko/werkzeug (used with permission). +def parse_list_header(value): + """Parse lists as described by RFC 2068 Section 2. + + In particular, parse comma-separated lists where the elements of + the list may include quoted-strings. A quoted-string could + contain a comma. A non-quoted string could have quotes in the + middle. Quotes are removed automatically after parsing. + + It basically works like :func:`parse_set_header` just that items + may appear multiple times and case sensitivity is preserved. + + The return value is a standard :class:`list`: + + >>> parse_list_header('token, "quoted value"') + ['token', 'quoted value'] + + To create a header from the :class:`list` again, use the + :func:`dump_header` function. + + :param value: a string with a list header. + :return: :class:`list` + :rtype: list + """ + result = [] + for item in _parse_list_header(value): + if item[:1] == item[-1:] == '"': + item = unquote_header_value(item[1:-1]) + result.append(item) + return result + + +# From mitsuhiko/werkzeug (used with permission). +def parse_dict_header(value): + """Parse lists of key, value pairs as described by RFC 2068 Section 2 and + convert them into a python dict: + + >>> d = parse_dict_header('foo="is a fish", bar="as well"') + >>> type(d) is dict + True + >>> sorted(d.items()) + [('bar', 'as well'), ('foo', 'is a fish')] + + If there is no value for a key it will be `None`: + + >>> parse_dict_header('key_without_value') + {'key_without_value': None} + + To create a header from the :class:`dict` again, use the + :func:`dump_header` function. + + :param value: a string with a dict header. + :return: :class:`dict` + :rtype: dict + """ + result = {} + for item in _parse_list_header(value): + if '=' not in item: + result[item] = None + continue + name, value = item.split('=', 1) + if value[:1] == value[-1:] == '"': + value = unquote_header_value(value[1:-1]) + result[name] = value + return result + + +# From mitsuhiko/werkzeug (used with permission). +def unquote_header_value(value, is_filename=False): + r"""Unquotes a header value. (Reversal of :func:`quote_header_value`). + This does not use the real unquoting but what browsers are actually + using for quoting. + + :param value: the header value to unquote. + :rtype: str + """ + if value and value[0] == value[-1] == '"': + # this is not the real unquoting, but fixing this so that the + # RFC is met will result in bugs with internet explorer and + # probably some other browsers as well. IE for example is + # uploading files with "C:\foo\bar.txt" as filename + value = value[1:-1] + + # if this is a filename and the starting characters look like + # a UNC path, then just return the value without quotes. Using the + # replace sequence below on a UNC path has the effect of turning + # the leading double slash into a single slash and then + # _fix_ie_filename() doesn't work correctly. See #458. + if not is_filename or value[:2] != '\\\\': + return value.replace('\\\\', '\\').replace('\\"', '"') + return value + + +def dict_from_cookiejar(cj): + """Returns a key/value dictionary from a CookieJar. + + :param cj: CookieJar object to extract cookies from. + :rtype: dict + """ + + cookie_dict = {} + + for cookie in cj: + cookie_dict[cookie.name] = cookie.value + + return cookie_dict + + +def add_dict_to_cookiejar(cj, cookie_dict): + """Returns a CookieJar from a key/value dictionary. + + :param cj: CookieJar to insert cookies into. + :param cookie_dict: Dict of key/values to insert into CookieJar. + :rtype: CookieJar + """ + + return cookiejar_from_dict(cookie_dict, cj) + + +def get_encodings_from_content(content): + """Returns encodings from given content string. + + :param content: bytestring to extract encodings from. + """ + warnings.warn(( + 'In requests 3.0, get_encodings_from_content will be removed. For ' + 'more information, please see the discussion on issue #2266. (This' + ' warning should only appear once.)'), + DeprecationWarning) + + charset_re = re.compile(r'<meta.*?charset=["\']*(.+?)["\'>]', flags=re.I) + pragma_re = re.compile(r'<meta.*?content=["\']*;?charset=(.+?)["\'>]', flags=re.I) + xml_re = re.compile(r'^<\?xml.*?encoding=["\']*(.+?)["\'>]') + + return (charset_re.findall(content) + + pragma_re.findall(content) + + xml_re.findall(content)) + + +def _parse_content_type_header(header): + """Returns content type and parameters from given header + + :param header: string + :return: tuple containing content type and dictionary of + parameters + """ + + tokens = header.split(';') + content_type, params = tokens[0].strip(), tokens[1:] + params_dict = {} + items_to_strip = "\"' " + + for param in params: + param = param.strip() + if param: + key, value = param, True + index_of_equals = param.find("=") + if index_of_equals != -1: + key = param[:index_of_equals].strip(items_to_strip) + value = param[index_of_equals + 1:].strip(items_to_strip) + params_dict[key.lower()] = value + return content_type, params_dict + + +def get_encoding_from_headers(headers): + """Returns encodings from given HTTP Header Dict. + + :param headers: dictionary to extract encoding from. + :rtype: str + """ + + content_type = headers.get('content-type') + + if not content_type: + return None + + content_type, params = _parse_content_type_header(content_type) + + if 'charset' in params: + return params['charset'].strip("'\"") + + if 'text' in content_type: + return 'ISO-8859-1' + + if 'application/json' in content_type: + # Assume UTF-8 based on RFC 4627: https://www.ietf.org/rfc/rfc4627.txt since the charset was unset + return 'utf-8' + + +def stream_decode_response_unicode(iterator, r): + """Stream decodes a iterator.""" + + if r.encoding is None: + for item in iterator: + yield item + return + + decoder = codecs.getincrementaldecoder(r.encoding)(errors='replace') + for chunk in iterator: + rv = decoder.decode(chunk) + if rv: + yield rv + rv = decoder.decode(b'', final=True) + if rv: + yield rv + + +def iter_slices(string, slice_length): + """Iterate over slices of a string.""" + pos = 0 + if slice_length is None or slice_length <= 0: + slice_length = len(string) + while pos < len(string): + yield string[pos:pos + slice_length] + pos += slice_length + + +def get_unicode_from_response(r): + """Returns the requested content back in unicode. + + :param r: Response object to get unicode content from. + + Tried: + + 1. charset from content-type + 2. fall back and replace all unicode characters + + :rtype: str + """ + warnings.warn(( + 'In requests 3.0, get_unicode_from_response will be removed. For ' + 'more information, please see the discussion on issue #2266. (This' + ' warning should only appear once.)'), + DeprecationWarning) + + tried_encodings = [] + + # Try charset from content-type + encoding = get_encoding_from_headers(r.headers) + + if encoding: + try: + return str(r.content, encoding) + except UnicodeError: + tried_encodings.append(encoding) + + # Fall back: + try: + return str(r.content, encoding, errors='replace') + except TypeError: + return r.content + + +# The unreserved URI characters (RFC 3986) +UNRESERVED_SET = frozenset( + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + "0123456789-._~") + + +def unquote_unreserved(uri): + """Un-escape any percent-escape sequences in a URI that are unreserved + characters. This leaves all reserved, illegal and non-ASCII bytes encoded. + + :rtype: str + """ + parts = uri.split('%') + for i in range(1, len(parts)): + h = parts[i][0:2] + if len(h) == 2 and h.isalnum(): + try: + c = chr(int(h, 16)) + except ValueError: + raise InvalidURL("Invalid percent-escape sequence: '%s'" % h) + + if c in UNRESERVED_SET: + parts[i] = c + parts[i][2:] + else: + parts[i] = '%' + parts[i] + else: + parts[i] = '%' + parts[i] + return ''.join(parts) + + +def requote_uri(uri): + """Re-quote the given URI. + + This function passes the given URI through an unquote/quote cycle to + ensure that it is fully and consistently quoted. + + :rtype: str + """ + safe_with_percent = "!#$%&'()*+,/:;=?@[]~" + safe_without_percent = "!#$&'()*+,/:;=?@[]~" + try: + # Unquote only the unreserved characters + # Then quote only illegal characters (do not quote reserved, + # unreserved, or '%') + return quote(unquote_unreserved(uri), safe=safe_with_percent) + except InvalidURL: + # We couldn't unquote the given URI, so let's try quoting it, but + # there may be unquoted '%'s in the URI. We need to make sure they're + # properly quoted so they do not cause issues elsewhere. + return quote(uri, safe=safe_without_percent) + + +def address_in_network(ip, net): + """This function allows you to check if an IP belongs to a network subnet + + Example: returns True if ip = 192.168.1.1 and net = 192.168.1.0/24 + returns False if ip = 192.168.1.1 and net = 192.168.100.0/24 + + :rtype: bool + """ + ipaddr = struct.unpack('=L', socket.inet_aton(ip))[0] + netaddr, bits = net.split('/') + netmask = struct.unpack('=L', socket.inet_aton(dotted_netmask(int(bits))))[0] + network = struct.unpack('=L', socket.inet_aton(netaddr))[0] & netmask + return (ipaddr & netmask) == (network & netmask) + + +def dotted_netmask(mask): + """Converts mask from /xx format to xxx.xxx.xxx.xxx + + Example: if mask is 24 function returns 255.255.255.0 + + :rtype: str + """ + bits = 0xffffffff ^ (1 << 32 - mask) - 1 + return socket.inet_ntoa(struct.pack('>I', bits)) + + +def is_ipv4_address(string_ip): + """ + :rtype: bool + """ + try: + socket.inet_aton(string_ip) + except socket.error: + return False + return True + + +def is_valid_cidr(string_network): + """ + Very simple check of the cidr format in no_proxy variable. + + :rtype: bool + """ + if string_network.count('/') == 1: + try: + mask = int(string_network.split('/')[1]) + except ValueError: + return False + + if mask < 1 or mask > 32: + return False + + try: + socket.inet_aton(string_network.split('/')[0]) + except socket.error: + return False + else: + return False + return True + + +@contextlib.contextmanager +def set_environ(env_name, value): + """Set the environment variable 'env_name' to 'value' + + Save previous value, yield, and then restore the previous value stored in + the environment variable 'env_name'. + + If 'value' is None, do nothing""" + value_changed = value is not None + if value_changed: + old_value = os.environ.get(env_name) + os.environ[env_name] = value + try: + yield + finally: + if value_changed: + if old_value is None: + del os.environ[env_name] + else: + os.environ[env_name] = old_value + + +def should_bypass_proxies(url, no_proxy): + """ + Returns whether we should bypass proxies or not. + + :rtype: bool + """ + # Prioritize lowercase environment variables over uppercase + # to keep a consistent behaviour with other http projects (curl, wget). + get_proxy = lambda k: os.environ.get(k) or os.environ.get(k.upper()) + + # First check whether no_proxy is defined. If it is, check that the URL + # we're getting isn't in the no_proxy list. + no_proxy_arg = no_proxy + if no_proxy is None: + no_proxy = get_proxy('no_proxy') + parsed = urlparse(url) + + if parsed.hostname is None: + # URLs don't always have hostnames, e.g. file:/// urls. + return True + + if no_proxy: + # We need to check whether we match here. We need to see if we match + # the end of the hostname, both with and without the port. + no_proxy = ( + host for host in no_proxy.replace(' ', '').split(',') if host + ) + + if is_ipv4_address(parsed.hostname): + for proxy_ip in no_proxy: + if is_valid_cidr(proxy_ip): + if address_in_network(parsed.hostname, proxy_ip): + return True + elif parsed.hostname == proxy_ip: + # If no_proxy ip was defined in plain IP notation instead of cidr notation & + # matches the IP of the index + return True + else: + host_with_port = parsed.hostname + if parsed.port: + host_with_port += ':{}'.format(parsed.port) + + for host in no_proxy: + if parsed.hostname.endswith(host) or host_with_port.endswith(host): + # The URL does match something in no_proxy, so we don't want + # to apply the proxies on this URL. + return True + + with set_environ('no_proxy', no_proxy_arg): + # parsed.hostname can be `None` in cases such as a file URI. + try: + bypass = proxy_bypass(parsed.hostname) + except (TypeError, socket.gaierror): + bypass = False + + if bypass: + return True + + return False + + +def get_environ_proxies(url, no_proxy=None): + """ + Return a dict of environment proxies. + + :rtype: dict + """ + if should_bypass_proxies(url, no_proxy=no_proxy): + return {} + else: + return getproxies() + + +def select_proxy(url, proxies): + """Select a proxy for the url, if applicable. + + :param url: The url being for the request + :param proxies: A dictionary of schemes or schemes and hosts to proxy URLs + """ + proxies = proxies or {} + urlparts = urlparse(url) + if urlparts.hostname is None: + return proxies.get(urlparts.scheme, proxies.get('all')) + + proxy_keys = [ + urlparts.scheme + '://' + urlparts.hostname, + urlparts.scheme, + 'all://' + urlparts.hostname, + 'all', + ] + proxy = None + for proxy_key in proxy_keys: + if proxy_key in proxies: + proxy = proxies[proxy_key] + break + + return proxy + + +def default_user_agent(name="python-requests"): + """ + Return a string representing the default user agent. + + :rtype: str + """ + return '%s/%s' % (name, __version__) + + +def default_headers(): + """ + :rtype: requests.structures.CaseInsensitiveDict + """ + return CaseInsensitiveDict({ + 'User-Agent': default_user_agent(), + 'Accept-Encoding': ', '.join(('gzip', 'deflate')), + 'Accept': '*/*', + 'Connection': 'keep-alive', + }) + + +def parse_header_links(value): + """Return a list of parsed link headers proxies. + + i.e. Link: <http:/.../front.jpeg>; rel=front; type="image/jpeg",<http://.../back.jpeg>; rel=back;type="image/jpeg" + + :rtype: list + """ + + links = [] + + replace_chars = ' \'"' + + value = value.strip(replace_chars) + if not value: + return links + + for val in re.split(', *<', value): + try: + url, params = val.split(';', 1) + except ValueError: + url, params = val, '' + + link = {'url': url.strip('<> \'"')} + + for param in params.split(';'): + try: + key, value = param.split('=') + except ValueError: + break + + link[key.strip(replace_chars)] = value.strip(replace_chars) + + links.append(link) + + return links + + +# Null bytes; no need to recreate these on each call to guess_json_utf +_null = '\x00'.encode('ascii') # encoding to ASCII for Python 3 +_null2 = _null * 2 +_null3 = _null * 3 + + +def guess_json_utf(data): + """ + :rtype: str + """ + # JSON always starts with two ASCII characters, so detection is as + # easy as counting the nulls and from their location and count + # determine the encoding. Also detect a BOM, if present. + sample = data[:4] + if sample in (codecs.BOM_UTF32_LE, codecs.BOM_UTF32_BE): + return 'utf-32' # BOM included + if sample[:3] == codecs.BOM_UTF8: + return 'utf-8-sig' # BOM included, MS style (discouraged) + if sample[:2] in (codecs.BOM_UTF16_LE, codecs.BOM_UTF16_BE): + return 'utf-16' # BOM included + nullcount = sample.count(_null) + if nullcount == 0: + return 'utf-8' + if nullcount == 2: + if sample[::2] == _null2: # 1st and 3rd are null + return 'utf-16-be' + if sample[1::2] == _null2: # 2nd and 4th are null + return 'utf-16-le' + # Did not detect 2 valid UTF-16 ascii-range characters + if nullcount == 3: + if sample[:3] == _null3: + return 'utf-32-be' + if sample[1:] == _null3: + return 'utf-32-le' + # Did not detect a valid UTF-32 ascii-range character + return None + + +def prepend_scheme_if_needed(url, new_scheme): + """Given a URL that may or may not have a scheme, prepend the given scheme. + Does not replace a present scheme with the one provided as an argument. + + :rtype: str + """ + scheme, netloc, path, params, query, fragment = urlparse(url, new_scheme) + + # urlparse is a finicky beast, and sometimes decides that there isn't a + # netloc present. Assume that it's being over-cautious, and switch netloc + # and path if urlparse decided there was no netloc. + if not netloc: + netloc, path = path, netloc + + return urlunparse((scheme, netloc, path, params, query, fragment)) + + +def get_auth_from_url(url): + """Given a url with authentication components, extract them into a tuple of + username,password. + + :rtype: (str,str) + """ + parsed = urlparse(url) + + try: + auth = (unquote(parsed.username), unquote(parsed.password)) + except (AttributeError, TypeError): + auth = ('', '') + + return auth + + +# Moved outside of function to avoid recompile every call +_CLEAN_HEADER_REGEX_BYTE = re.compile(b'^\\S[^\\r\\n]*$|^$') +_CLEAN_HEADER_REGEX_STR = re.compile(r'^\S[^\r\n]*$|^$') + + +def check_header_validity(header): + """Verifies that header value is a string which doesn't contain + leading whitespace or return characters. This prevents unintended + header injection. + + :param header: tuple, in the format (name, value). + """ + name, value = header + + if isinstance(value, bytes): + pat = _CLEAN_HEADER_REGEX_BYTE + else: + pat = _CLEAN_HEADER_REGEX_STR + try: + if not pat.match(value): + raise InvalidHeader("Invalid return character or leading space in header: %s" % name) + except TypeError: + raise InvalidHeader("Value for header {%s: %s} must be of type str or " + "bytes, not %s" % (name, value, type(value))) + + +def urldefragauth(url): + """ + Given a url remove the fragment and the authentication part. + + :rtype: str + """ + scheme, netloc, path, params, query, fragment = urlparse(url) + + # see func:`prepend_scheme_if_needed` + if not netloc: + netloc, path = path, netloc + + netloc = netloc.rsplit('@', 1)[-1] + + return urlunparse((scheme, netloc, path, params, query, '')) + + +def rewind_body(prepared_request): + """Move file pointer back to its recorded starting position + so it can be read again on redirect. + """ + body_seek = getattr(prepared_request.body, 'seek', None) + if body_seek is not None and isinstance(prepared_request._body_position, integer_types): + try: + body_seek(prepared_request._body_position) + except (IOError, OSError): + raise UnrewindableBodyError("An error occurred when rewinding request " + "body for redirect.") + else: + raise UnrewindableBodyError("Unable to rewind request body for redirect.") diff --git a/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/AUTHORS.txt b/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/AUTHORS.txt new file mode 100644 index 0000000..04c42fc --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/AUTHORS.txt @@ -0,0 +1,566 @@ +@Switch01 +A_Rog +Aakanksha Agrawal +Abhinav Sagar +ABHYUDAY PRATAP SINGH +abs51295 +AceGentile +Adam Chainz +Adam Tse +Adam Wentz +admin +Adrien Morison +ahayrapetyan +Ahilya +AinsworthK +Akash Srivastava +Alan Yee +Albert Tugushev +Albert-Guan +albertg +Aleks Bunin +Alethea Flowers +Alex Gaynor +Alex Grönholm +Alex Loosley +Alex Morega +Alex Stachowiak +Alexander Shtyrov +Alexandre Conrad +Alexey Popravka +Alli +Ami Fischman +Ananya Maiti +Anatoly Techtonik +Anders Kaseorg +Andre Aguiar +Andreas Lutro +Andrei Geacar +Andrew Gaul +Andrey Bulgakov +Andrés Delfino +Andy Freeland +Andy Kluger +Ani Hayrapetyan +Aniruddha Basak +Anish Tambe +Anrs Hu +Anthony Sottile +Antoine Musso +Anton Ovchinnikov +Anton Patrushev +Antonio Alvarado Hernandez +Antony Lee +Antti Kaihola +Anubhav Patel +Anudit Nagar +Anuj Godase +AQNOUCH Mohammed +AraHaan +Arindam Choudhury +Armin Ronacher +Artem +Ashley Manton +Ashwin Ramaswami +atse +Atsushi Odagiri +Avner Cohen +Baptiste Mispelon +Barney Gale +barneygale +Bartek Ogryczak +Bastian Venthur +Ben Darnell +Ben Hoyt +Ben Rosser +Bence Nagy +Benjamin Peterson +Benjamin VanEvery +Benoit Pierre +Berker Peksag +Bernardo B. Marques +Bernhard M. Wiedemann +Bertil Hatt +Bhavam Vidyarthi +Bogdan Opanchuk +BorisZZZ +Brad Erickson +Bradley Ayers +Brandon L. Reiss +Brandt Bucher +Brett Randall +Brian Cristante +Brian Rosner +BrownTruck +Bruno Oliveira +Bruno Renié +Bstrdsmkr +Buck Golemon +burrows +Bussonnier Matthias +c22 +Caleb Martinez +Calvin Smith +Carl Meyer +Carlos Liam +Carol Willing +Carter Thayer +Cass +Chandrasekhar Atina +Chih-Hsuan Yen +Chris Brinker +Chris Hunt +Chris Jerdonek +Chris McDonough +Chris Wolfe +Christian Clauss +Christian Heimes +Christian Oudard +Christoph Reiter +Christopher Hunt +Christopher Snyder +cjc7373 +Clark Boylan +Clay McClure +Cody +Cody Soyland +Colin Watson +Connor Osborn +Cooper Lees +Cooper Ry Lees +Cory Benfield +Cory Wright +Craig Kerstiens +Cristian Sorinel +Curtis Doty +cytolentino +Damian Quiroga +Dan Black +Dan Savilonis +Dan Sully +daniel +Daniel Collins +Daniel Hahler +Daniel Holth +Daniel Jost +Daniel Shaulov +Daniele Esposti +Daniele Procida +Danny Hermes +Danny McClanahan +Dav Clark +Dave Abrahams +Dave Jones +David Aguilar +David Black +David Bordeynik +David Caro +David Evans +David Linke +David Pursehouse +David Tucker +David Wales +Davidovich +Deepak Sharma +derwolfe +Desetude +Devesh Kumar Singh +Diego Caraballo +DiegoCaraballo +Dmitry Gladkov +Domen Kožar +Donald Stufft +Dongweiming +Douglas Thor +DrFeathers +Dustin Ingram +Dwayne Bailey +Ed Morley +Eitan Adler +ekristina +elainechan +Eli Schwartz +Ellen Marie Dash +Emil Burzo +Emil Styrke +Endoh Takanao +enoch +Erdinc Mutlu +Eric Gillingham +Eric Hanchrow +Eric Hopper +Erik M. Bray +Erik Rose +Ernest W Durbin III +Ernest W. Durbin III +Erwin Janssen +Eugene Vereshchagin +everdimension +Felix Yan +fiber-space +Filip Kokosiński +Florian Briand +Florian Rathgeber +Francesco +Francesco Montesano +Frost Ming +Gabriel Curio +Gabriel de Perthuis +Garry Polley +gdanielson +Geoffrey Lehée +Geoffrey Sneddon +George Song +Georgi Valkov +ghost +Giftlin Rajaiah +gizmoguy1 +gkdoc +Gopinath M +GOTO Hayato +gpiks +Guilherme Espada +gutsytechster +Guy Rozendorn +gzpan123 +Hanjun Kim +Hari Charan +Harsh Vardhan +Herbert Pfennig +Hsiaoming Yang +Hugo +Hugo Lopes Tavares +Hugo van Kemenade +hugovk +Hynek Schlawack +Ian Bicking +Ian Cordasco +Ian Lee +Ian Stapleton Cordasco +Ian Wienand +Igor Kuzmitshov +Igor Sobreira +Ilan Schnell +Ilya Baryshev +INADA Naoki +Ionel Cristian Mărieș +Ionel Maries Cristian +Ivan Pozdeev +Jacob Kim +jakirkham +Jakub Stasiak +Jakub Vysoky +Jakub Wilk +James Cleveland +James Firth +James Polley +Jan Pokorný +Jannis Leidel +jarondl +Jason R. Coombs +Jay Graves +Jean-Christophe Fillion-Robin +Jeff Barber +Jeff Dairiki +Jelmer Vernooij +jenix21 +Jeremy Stanley +Jeremy Zafran +Jiashuo Li +Jim Garrison +Jivan Amara +John Paton +John T. Wodder II +John-Scott Atlakson +johnthagen +Jon Banafato +Jon Dufresne +Jon Parise +Jonas Nockert +Jonathan Herbert +Joost Molenaar +Jorge Niedbalski +Joseph Long +Josh Bronson +Josh Hansen +Josh Schneier +Juanjo Bazán +Julian Berman +Julian Gethmann +Julien Demoor +jwg4 +Jyrki Pulliainen +Kai Chen +Kamal Bin Mustafa +kaustav haldar +keanemind +Keith Maxwell +Kelsey Hightower +Kenneth Belitzky +Kenneth Reitz +Kevin Burke +Kevin Carter +Kevin Frommelt +Kevin R Patterson +Kexuan Sun +Kit Randel +KOLANICH +kpinc +Krishna Oza +Kumar McMillan +Kyle Persohn +lakshmanaram +Laszlo Kiss-Kollar +Laurent Bristiel +Laurie Opperman +Leon Sasson +Lev Givon +Lincoln de Sousa +Lipis +Loren Carvalho +Lucas Cimon +Ludovic Gasc +Luke Macken +Luo Jiebin +luojiebin +luz.paz +László Kiss Kollár +Marc Abramowitz +Marc Tamlyn +Marcus Smith +Mariatta +Mark Kohler +Mark Williams +Markus Hametner +Masaki +Masklinn +Matej Stuchlik +Mathew Jennings +Mathieu Bridon +Matt Good +Matt Maker +Matt Robenolt +matthew +Matthew Einhorn +Matthew Gilliard +Matthew Iversen +Matthew Trumbell +Matthew Willson +Matthias Bussonnier +mattip +Maxim Kurnikov +Maxime Rouyrre +mayeut +mbaluna +mdebi +memoselyk +Michael +Michael Aquilina +Michael E. Karpeles +Michael Klich +Michael Williamson +michaelpacer +Mickaël Schoentgen +Miguel Araujo Perez +Mihir Singh +Mike +Mike Hendricks +Min RK +MinRK +Miro Hrončok +Monica Baluna +montefra +Monty Taylor +Nate Coraor +Nathaniel J. Smith +Nehal J Wani +Neil Botelho +Nguyễn Gia Phong +Nick Coghlan +Nick Stenning +Nick Timkovich +Nicolas Bock +Nikhil Benesch +Nikolay Korolev +Nitesh Sharma +Noah Gorny +Nowell Strite +NtaleGrey +nvdv +Ofekmeister +ofrinevo +Oliver Jeeves +Oliver Tonnhofer +Olivier Girardot +Olivier Grisel +Ollie Rutherfurd +OMOTO Kenji +Omry Yadan +onlinejudge95 +Oren Held +Oscar Benjamin +Oz N Tiram +Pachwenko +Patrick Dubroy +Patrick Jenkins +Patrick Lawson +patricktokeeffe +Patrik Kopkan +Paul Kehrer +Paul Moore +Paul Nasrat +Paul Oswald +Paul van der Linden +Paulus Schoutsen +Pavithra Eswaramoorthy +Pawel Jasinski +Pekka Klärck +Peter Lisák +Peter Waller +petr-tik +Phaneendra Chiruvella +Phil Freo +Phil Pennock +Phil Whelan +Philip Jägenstedt +Philip Molloy +Philippe Ombredanne +Pi Delport +Pierre-Yves Rofes +pip +Prabakaran Kumaresshan +Prabhjyotsing Surjit Singh Sodhi +Prabhu Marappan +Pradyun Gedam +Prashant Sharma +Pratik Mallya +Preet Thakkar +Preston Holmes +Przemek Wrzos +Pulkit Goyal +Qiangning Hong +Quentin Pradet +R. David Murray +Rafael Caricio +Ralf Schmitt +Razzi Abuissa +rdb +Reece Dunham +Remi Rampin +Rene Dudfield +Riccardo Magliocchetti +Richard Jones +Ricky Ng-Adam +RobberPhex +Robert Collins +Robert McGibbon +Robert T. McGibbon +robin elisha robinson +Roey Berman +Rohan Jain +Roman Bogorodskiy +Romuald Brunet +Ronny Pfannschmidt +Rory McCann +Ross Brattain +Roy Wellington Ⅳ +Ryan Wooden +ryneeverett +Sachi King +Salvatore Rinchiera +Savio Jomton +schlamar +Scott Kitterman +Sean +seanj +Sebastian Jordan +Sebastian Schaetz +Segev Finer +SeongSoo Cho +Sergey Vasilyev +Seth Woodworth +Shlomi Fish +Shovan Maity +Simeon Visser +Simon Cross +Simon Pichugin +sinoroc +sinscary +Sorin Sbarnea +Stavros Korokithakis +Stefan Scherfke +Stefano Rivera +Stephan Erb +stepshal +Steve (Gadget) Barnes +Steve Barnes +Steve Dower +Steve Kowalik +Steven Myint +stonebig +Stéphane Bidoul +Stéphane Bidoul (ACSONE) +Stéphane Klein +Sumana Harihareswara +Sviatoslav Sydorenko +Swat009 +Takayuki SHIMIZUKAWA +tbeswick +Thijs Triemstra +Thomas Fenzl +Thomas Grainger +Thomas Guettler +Thomas Johansson +Thomas Kluyver +Thomas Smith +Tim D. Smith +Tim Gates +Tim Harder +Tim Heap +tim smith +tinruufu +Tom Forbes +Tom Freudenheim +Tom V +Tomas Hrnciar +Tomas Orsava +Tomer Chachamu +Tony Beswick +Tony Zhaocheng Tan +TonyBeswick +toonarmycaptain +Toshio Kuratomi +Travis Swicegood +Tzu-ping Chung +Valentin Haenel +Victor Stinner +victorvpaulo +Viktor Szépe +Ville Skyttä +Vinay Sajip +Vincent Philippon +Vinicyus Macedo +Vitaly Babiy +Vladimir Rutsky +W. Trevor King +Wil Tan +Wilfred Hughes +William ML Leslie +William T Olson +Wilson Mo +wim glenn +Wolfgang Maier +Xavier Fernandez +xoviat +xtreak +YAMAMOTO Takashi +Yen Chi Hsuan +Yeray Diaz Diaz +Yoval P +Yu Jian +Yuan Jing Vincent Yan +Zearin +Zhiping Deng +Zvezdan Petkovic +Łukasz Langa +Семён Марьясин diff --git a/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/INSTALLER b/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/LICENSE.txt b/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/LICENSE.txt new file mode 100644 index 0000000..737fec5 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/LICENSE.txt @@ -0,0 +1,20 @@ +Copyright (c) 2008-2019 The pip developers (see AUTHORS.txt file) + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/METADATA b/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/METADATA new file mode 100644 index 0000000..4adf953 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/METADATA @@ -0,0 +1,82 @@ +Metadata-Version: 2.1 +Name: setuptools +Version: 44.0.0 +Summary: Easily download, build, install, upgrade, and uninstall Python packages +Home-page: https://github.com/pypa/setuptools +Author: Python Packaging Authority +Author-email: distutils-sig@python.org +License: UNKNOWN +Project-URL: Documentation, https://setuptools.readthedocs.io/ +Keywords: CPAN PyPI distutils eggs package management +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: OS Independent +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: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: System :: Archiving :: Packaging +Classifier: Topic :: System :: Systems Administration +Classifier: Topic :: Utilities +Requires-Python: !=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7 +Description-Content-Type: text/x-rst; charset=UTF-8 + +.. image:: https://img.shields.io/pypi/v/setuptools.svg + :target: https://pypi.org/project/setuptools + +.. image:: https://img.shields.io/readthedocs/setuptools/latest.svg + :target: https://setuptools.readthedocs.io + +.. image:: https://img.shields.io/travis/pypa/setuptools/master.svg?label=Linux%20CI&logo=travis&logoColor=white + :target: https://travis-ci.org/pypa/setuptools + +.. image:: https://img.shields.io/appveyor/ci/pypa/setuptools/master.svg?label=Windows%20CI&logo=appveyor&logoColor=white + :target: https://ci.appveyor.com/project/pypa/setuptools/branch/master + +.. image:: https://img.shields.io/codecov/c/github/pypa/setuptools/master.svg?logo=codecov&logoColor=white + :target: https://codecov.io/gh/pypa/setuptools + +.. image:: https://tidelift.com/badges/github/pypa/setuptools?style=flat + :target: https://tidelift.com/subscription/pkg/pypi-setuptools?utm_source=pypi-setuptools&utm_medium=readme + +.. image:: https://img.shields.io/pypi/pyversions/setuptools.svg + +See the `Installation Instructions +<https://packaging.python.org/installing/>`_ in the Python Packaging +User's Guide for instructions on installing, upgrading, and uninstalling +Setuptools. + +Questions and comments should be directed to the `distutils-sig +mailing list <http://mail.python.org/pipermail/distutils-sig/>`_. +Bug reports and especially tested patches may be +submitted directly to the `bug tracker +<https://github.com/pypa/setuptools/issues>`_. + +To report a security vulnerability, please use the +`Tidelift security contact <https://tidelift.com/security>`_. +Tidelift will coordinate the fix and disclosure. + + +For Enterprise +============== + +Available as part of the Tidelift Subscription. + +Setuptools and the maintainers of thousands of other packages are working with Tidelift to deliver one enterprise subscription that covers all of the open source you use. + +`Learn more <https://tidelift.com/subscription/pkg/pypi-setuptools?utm_source=pypi-setuptools&utm_medium=referral&utm_campaign=github>`_. + +Code of Conduct +=============== + +Everyone interacting in the setuptools project's codebases, issue trackers, +chat rooms, and mailing lists is expected to follow the +`PyPA Code of Conduct <https://www.pypa.io/en/latest/code-of-conduct/>`_. + + diff --git a/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/RECORD b/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/RECORD new file mode 100644 index 0000000..a6481a6 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/RECORD @@ -0,0 +1,163 @@ +../../../bin/easy_install,sha256=puwYb_NPnvgDcyg3O3bcAxp2mlT87hLdEghB1kCJCJ8,265 +../../../bin/easy_install-3.8,sha256=puwYb_NPnvgDcyg3O3bcAxp2mlT87hLdEghB1kCJCJ8,265 +__pycache__/easy_install.cpython-38.pyc,, +easy_install.py,sha256=MDC9vt5AxDsXX5qcKlBz2TnW6Tpuv_AobnfhCJ9X3PM,126 +setuptools-44.0.0.dist-info/AUTHORS.txt,sha256=RnTFYKrTgbpfWnZMizLRq0u31iGDJMbs-iqvafo1CcA,7734 +setuptools-44.0.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +setuptools-44.0.0.dist-info/LICENSE.txt,sha256=W6Ifuwlk-TatfRU2LR7W1JMcyMj5_y1NkRkOEJvnRDE,1090 +setuptools-44.0.0.dist-info/METADATA,sha256=L93fcafgVw4xoJUNG0lehyy0prVj-jU_JFxRh0ZUtos,3523 +setuptools-44.0.0.dist-info/RECORD,, +setuptools-44.0.0.dist-info/WHEEL,sha256=kGT74LWyRUZrL4VgLh6_g12IeVl_9u9ZVhadrgXZUEY,110 +setuptools-44.0.0.dist-info/dependency_links.txt,sha256=HlkCFkoK5TbZ5EMLbLKYhLcY_E31kBWD8TqW2EgmatQ,239 +setuptools-44.0.0.dist-info/entry_points.txt,sha256=ZmIqlp-SBdsBS2cuetmU2NdSOs4DG0kxctUR9UJ8Xk0,3150 +setuptools-44.0.0.dist-info/top_level.txt,sha256=2HUXVVwA4Pff1xgTFr3GsTXXKaPaO6vlG6oNJ_4u4Tg,38 +setuptools-44.0.0.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1 +setuptools/__init__.py,sha256=WBpCcn2lvdckotabeae1TTYonPOcgCIF3raD2zRWzBc,7283 +setuptools/__pycache__/__init__.cpython-38.pyc,, +setuptools/__pycache__/_deprecation_warning.cpython-38.pyc,, +setuptools/__pycache__/_imp.cpython-38.pyc,, +setuptools/__pycache__/archive_util.cpython-38.pyc,, +setuptools/__pycache__/build_meta.cpython-38.pyc,, +setuptools/__pycache__/config.cpython-38.pyc,, +setuptools/__pycache__/dep_util.cpython-38.pyc,, +setuptools/__pycache__/depends.cpython-38.pyc,, +setuptools/__pycache__/dist.cpython-38.pyc,, +setuptools/__pycache__/errors.cpython-38.pyc,, +setuptools/__pycache__/extension.cpython-38.pyc,, +setuptools/__pycache__/glob.cpython-38.pyc,, +setuptools/__pycache__/installer.cpython-38.pyc,, +setuptools/__pycache__/launch.cpython-38.pyc,, +setuptools/__pycache__/lib2to3_ex.cpython-38.pyc,, +setuptools/__pycache__/monkey.cpython-38.pyc,, +setuptools/__pycache__/msvc.cpython-38.pyc,, +setuptools/__pycache__/namespaces.cpython-38.pyc,, +setuptools/__pycache__/package_index.cpython-38.pyc,, +setuptools/__pycache__/py27compat.cpython-38.pyc,, +setuptools/__pycache__/py31compat.cpython-38.pyc,, +setuptools/__pycache__/py33compat.cpython-38.pyc,, +setuptools/__pycache__/py34compat.cpython-38.pyc,, +setuptools/__pycache__/sandbox.cpython-38.pyc,, +setuptools/__pycache__/site-patch.cpython-38.pyc,, +setuptools/__pycache__/ssl_support.cpython-38.pyc,, +setuptools/__pycache__/unicode_utils.cpython-38.pyc,, +setuptools/__pycache__/version.cpython-38.pyc,, +setuptools/__pycache__/wheel.cpython-38.pyc,, +setuptools/__pycache__/windows_support.cpython-38.pyc,, +setuptools/_deprecation_warning.py,sha256=jU9-dtfv6cKmtQJOXN8nP1mm7gONw5kKEtiPtbwnZyI,218 +setuptools/_imp.py,sha256=jloslOkxrTKbobgemfP94YII0nhqiJzE1bRmCTZ1a5I,2223 +setuptools/_vendor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +setuptools/_vendor/__pycache__/__init__.cpython-38.pyc,, +setuptools/_vendor/__pycache__/ordered_set.cpython-38.pyc,, +setuptools/_vendor/__pycache__/pyparsing.cpython-38.pyc,, +setuptools/_vendor/__pycache__/six.cpython-38.pyc,, +setuptools/_vendor/ordered_set.py,sha256=dbaCcs27dyN9gnMWGF5nA_BrVn6Q-NrjKYJpV9_fgBs,15130 +setuptools/_vendor/packaging/__about__.py,sha256=CpuMSyh1V7adw8QMjWKkY3LtdqRUkRX4MgJ6nF4stM0,744 +setuptools/_vendor/packaging/__init__.py,sha256=6enbp5XgRfjBjsI9-bn00HjHf5TH21PDMOKkJW8xw-w,562 +setuptools/_vendor/packaging/__pycache__/__about__.cpython-38.pyc,, +setuptools/_vendor/packaging/__pycache__/__init__.cpython-38.pyc,, +setuptools/_vendor/packaging/__pycache__/_compat.cpython-38.pyc,, +setuptools/_vendor/packaging/__pycache__/_structures.cpython-38.pyc,, +setuptools/_vendor/packaging/__pycache__/markers.cpython-38.pyc,, +setuptools/_vendor/packaging/__pycache__/requirements.cpython-38.pyc,, +setuptools/_vendor/packaging/__pycache__/specifiers.cpython-38.pyc,, +setuptools/_vendor/packaging/__pycache__/tags.cpython-38.pyc,, +setuptools/_vendor/packaging/__pycache__/utils.cpython-38.pyc,, +setuptools/_vendor/packaging/__pycache__/version.cpython-38.pyc,, +setuptools/_vendor/packaging/_compat.py,sha256=Ugdm-qcneSchW25JrtMIKgUxfEEBcCAz6WrEeXeqz9o,865 +setuptools/_vendor/packaging/_structures.py,sha256=pVd90XcXRGwpZRB_qdFuVEibhCHpX_bL5zYr9-N0mc8,1416 +setuptools/_vendor/packaging/markers.py,sha256=-meFl9Fr9V8rF5Rduzgett5EHK9wBYRUqssAV2pj0lw,8268 +setuptools/_vendor/packaging/requirements.py,sha256=3dwIJekt8RRGCUbgxX8reeAbgmZYjb0wcCRtmH63kxI,4742 +setuptools/_vendor/packaging/specifiers.py,sha256=0ZzQpcUnvrQ6LjR-mQRLzMr8G6hdRv-mY0VSf_amFtI,27778 +setuptools/_vendor/packaging/tags.py,sha256=EPLXhO6GTD7_oiWEO1U0l0PkfR8R_xivpMDHXnsTlts,12933 +setuptools/_vendor/packaging/utils.py,sha256=VaTC0Ei7zO2xl9ARiWmz2YFLFt89PuuhLbAlXMyAGms,1520 +setuptools/_vendor/packaging/version.py,sha256=Npdwnb8OHedj_2L86yiUqscujb7w_i5gmSK1PhOAFzg,11978 +setuptools/_vendor/pyparsing.py,sha256=tmrp-lu-qO1i75ZzIN5A12nKRRD1Cm4Vpk-5LR9rims,232055 +setuptools/_vendor/six.py,sha256=A6hdJZVjI3t_geebZ9BzUvwRrIXo0lfwzQlM2LcKyas,30098 +setuptools/archive_util.py,sha256=kw8Ib_lKjCcnPKNbS7h8HztRVK0d5RacU3r_KRdVnmM,6592 +setuptools/build_meta.py,sha256=-9Nmj9YdbW4zX3TssPJZhsENrTa4fw3k86Jm1cdKMik,9597 +setuptools/cli-32.exe,sha256=dfEuovMNnA2HLa3jRfMPVi5tk4R7alCbpTvuxtCyw0Y,65536 +setuptools/cli-64.exe,sha256=KLABu5pyrnokJCv6skjXZ6GsXeyYHGcqOUT3oHI3Xpo,74752 +setuptools/cli.exe,sha256=dfEuovMNnA2HLa3jRfMPVi5tk4R7alCbpTvuxtCyw0Y,65536 +setuptools/command/__init__.py,sha256=QCAuA9whnq8Bnoc0bBaS6Lw_KAUO0DiHYZQXEMNn5hg,568 +setuptools/command/__pycache__/__init__.cpython-38.pyc,, +setuptools/command/__pycache__/alias.cpython-38.pyc,, +setuptools/command/__pycache__/bdist_egg.cpython-38.pyc,, +setuptools/command/__pycache__/bdist_rpm.cpython-38.pyc,, +setuptools/command/__pycache__/bdist_wininst.cpython-38.pyc,, +setuptools/command/__pycache__/build_clib.cpython-38.pyc,, +setuptools/command/__pycache__/build_ext.cpython-38.pyc,, +setuptools/command/__pycache__/build_py.cpython-38.pyc,, +setuptools/command/__pycache__/develop.cpython-38.pyc,, +setuptools/command/__pycache__/dist_info.cpython-38.pyc,, +setuptools/command/__pycache__/easy_install.cpython-38.pyc,, +setuptools/command/__pycache__/egg_info.cpython-38.pyc,, +setuptools/command/__pycache__/install.cpython-38.pyc,, +setuptools/command/__pycache__/install_egg_info.cpython-38.pyc,, +setuptools/command/__pycache__/install_lib.cpython-38.pyc,, +setuptools/command/__pycache__/install_scripts.cpython-38.pyc,, +setuptools/command/__pycache__/py36compat.cpython-38.pyc,, +setuptools/command/__pycache__/register.cpython-38.pyc,, +setuptools/command/__pycache__/rotate.cpython-38.pyc,, +setuptools/command/__pycache__/saveopts.cpython-38.pyc,, +setuptools/command/__pycache__/sdist.cpython-38.pyc,, +setuptools/command/__pycache__/setopt.cpython-38.pyc,, +setuptools/command/__pycache__/test.cpython-38.pyc,, +setuptools/command/__pycache__/upload.cpython-38.pyc,, +setuptools/command/__pycache__/upload_docs.cpython-38.pyc,, +setuptools/command/alias.py,sha256=KjpE0sz_SDIHv3fpZcIQK-sCkJz-SrC6Gmug6b9Nkc8,2426 +setuptools/command/bdist_egg.py,sha256=nnfV8Ah8IRC_Ifv5Loa9FdxL66MVbyDXwy-foP810zM,18185 +setuptools/command/bdist_rpm.py,sha256=B7l0TnzCGb-0nLlm6rS00jWLkojASwVmdhW2w5Qz_Ak,1508 +setuptools/command/bdist_wininst.py,sha256=_6dz3lpB1tY200LxKPLM7qgwTCceOMgaWFF-jW2-pm0,637 +setuptools/command/build_clib.py,sha256=bQ9aBr-5ZSO-9fGsGsDLz0mnnFteHUZnftVLkhvHDq0,4484 +setuptools/command/build_ext.py,sha256=Ib42YUGksBswm2mL5xmQPF6NeTA6HcqrvAtEgFCv32A,13019 +setuptools/command/build_py.py,sha256=yWyYaaS9F3o9JbIczn064A5g1C5_UiKRDxGaTqYbtLE,9596 +setuptools/command/develop.py,sha256=MQlnGS6uP19erK2JCNOyQYoYyquk3PADrqrrinqqLtA,8184 +setuptools/command/dist_info.py,sha256=5t6kOfrdgALT-P3ogss6PF9k-Leyesueycuk3dUyZnI,960 +setuptools/command/easy_install.py,sha256=0lY8Agxe-7IgMtxgxFuOY1NrDlBzOUlpCKsvayXlTYY,89903 +setuptools/command/egg_info.py,sha256=0e_TXrMfpa8nGTO7GmJcmpPCMWzliZi6zt9aMchlumc,25578 +setuptools/command/install.py,sha256=8doMxeQEDoK4Eco0mO2WlXXzzp9QnsGJQ7Z7yWkZPG8,4705 +setuptools/command/install_egg_info.py,sha256=4zq_Ad3jE-EffParuyDEnvxU6efB-Xhrzdr8aB6Ln_8,3195 +setuptools/command/install_lib.py,sha256=9zdc-H5h6RPxjySRhOwi30E_WfcVva7gpfhZ5ata60w,5023 +setuptools/command/install_scripts.py,sha256=UD0rEZ6861mTYhIdzcsqKnUl8PozocXWl9VBQ1VTWnc,2439 +setuptools/command/launcher manifest.xml,sha256=xlLbjWrB01tKC0-hlVkOKkiSPbzMml2eOPtJ_ucCnbE,628 +setuptools/command/py36compat.py,sha256=SzjZcOxF7zdFUT47Zv2n7AM3H8koDys_0OpS-n9gIfc,4986 +setuptools/command/register.py,sha256=kk3DxXCb5lXTvqnhfwx2g6q7iwbUmgTyXUCaBooBOUk,468 +setuptools/command/rotate.py,sha256=co5C1EkI7P0GGT6Tqz-T2SIj2LBJTZXYELpmao6d4KQ,2164 +setuptools/command/saveopts.py,sha256=za7QCBcQimKKriWcoCcbhxPjUz30gSB74zuTL47xpP4,658 +setuptools/command/sdist.py,sha256=IL1LepD2h8qGKOFJ3rrQVbjNH_Q6ViD40l0QADr4MEU,8088 +setuptools/command/setopt.py,sha256=NTWDyx-gjDF-txf4dO577s7LOzHVoKR0Mq33rFxaRr8,5085 +setuptools/command/test.py,sha256=u2kXngIIdSYqtvwFlHiN6Iye1IB4TU6uadB2uiV1szw,9602 +setuptools/command/upload.py,sha256=XT3YFVfYPAmA5qhGg0euluU98ftxRUW-PzKcODMLxUs,462 +setuptools/command/upload_docs.py,sha256=oXiGplM_cUKLwE4CWWw98RzCufAu8tBhMC97GegFcms,7311 +setuptools/config.py,sha256=6SB2OY3qcooOJmG_rsK_s0pKBsorBlDpfMJUyzjQIGk,20575 +setuptools/dep_util.py,sha256=fgixvC1R7sH3r13ktyf7N0FALoqEXL1cBarmNpSEoWg,935 +setuptools/depends.py,sha256=qt2RWllArRvhnm8lxsyRpcthEZYp4GHQgREl1q0LkFw,5517 +setuptools/dist.py,sha256=xtXaNsOsE32MwwQqErzgXJF7jsTQz9GYFRrwnPFQ0J0,49865 +setuptools/errors.py,sha256=MVOcv381HNSajDgEUWzOQ4J6B5BHCBMSjHfaWcEwA1o,524 +setuptools/extension.py,sha256=uc6nHI-MxwmNCNPbUiBnybSyqhpJqjbhvOQ-emdvt_E,1729 +setuptools/extern/__init__.py,sha256=4q9gtShB1XFP6CisltsyPqtcfTO6ZM9Lu1QBl3l-qmo,2514 +setuptools/extern/__pycache__/__init__.cpython-38.pyc,, +setuptools/glob.py,sha256=o75cHrOxYsvn854thSxE0x9k8JrKDuhP_rRXlVB00Q4,5084 +setuptools/gui-32.exe,sha256=XBr0bHMA6Hpz2s9s9Bzjl-PwXfa9nH4ie0rFn4V2kWA,65536 +setuptools/gui-64.exe,sha256=aYKMhX1IJLn4ULHgWX0sE0yREUt6B3TEHf_jOw6yNyE,75264 +setuptools/gui.exe,sha256=XBr0bHMA6Hpz2s9s9Bzjl-PwXfa9nH4ie0rFn4V2kWA,65536 +setuptools/installer.py,sha256=TCFRonRo01I79zo-ucf3Ymhj8TenPlmhMijN916aaJs,5337 +setuptools/launch.py,sha256=sd7ejwhBocCDx_wG9rIs0OaZ8HtmmFU8ZC6IR_S0Lvg,787 +setuptools/lib2to3_ex.py,sha256=t5e12hbR2pi9V4ezWDTB4JM-AISUnGOkmcnYHek3xjg,2013 +setuptools/monkey.py,sha256=FGc9fffh7gAxMLFmJs2DW_OYWpBjkdbNS2n14UAK4NA,5264 +setuptools/msvc.py,sha256=8baJ6aYgCA4TRdWQQi185qB9dnU8FaP4wgpbmd7VODs,46751 +setuptools/namespaces.py,sha256=F0Nrbv8KCT2OrO7rwa03om4N4GZKAlnce-rr-cgDQa8,3199 +setuptools/package_index.py,sha256=6pb-B1POtHyLycAbkDETk4fO-Qv8_sY-rjTXhUOoh6k,40605 +setuptools/py27compat.py,sha256=tvmer0Tn-wk_JummCkoM22UIjpjL-AQ8uUiOaqTs8sI,1496 +setuptools/py31compat.py,sha256=h2rtZghOfwoGYd8sQ0-auaKiF3TcL3qX0bX3VessqcE,838 +setuptools/py33compat.py,sha256=SMF9Z8wnGicTOkU1uRNwZ_kz5Z_bj29PUBbqdqeeNsc,1330 +setuptools/py34compat.py,sha256=KYOd6ybRxjBW8NJmYD8t_UyyVmysppFXqHpFLdslGXU,245 +setuptools/sandbox.py,sha256=9UbwfEL5QY436oMI1LtFWohhoZ-UzwHvGyZjUH_qhkw,14276 +setuptools/script (dev).tmpl,sha256=RUzQzCQUaXtwdLtYHWYbIQmOaES5Brqq1FvUA_tu-5I,218 +setuptools/script.tmpl,sha256=WGTt5piezO27c-Dbx6l5Q4T3Ff20A5z7872hv3aAhYY,138 +setuptools/site-patch.py,sha256=OumkIHMuoSenRSW1382kKWI1VAwxNE86E5W8iDd34FY,2302 +setuptools/ssl_support.py,sha256=nLjPUBBw7RTTx6O4RJZ5eAMGgjJG8beiDbkFXDZpLuM,8493 +setuptools/unicode_utils.py,sha256=NOiZ_5hD72A6w-4wVj8awHFM3n51Kmw1Ic_vx15XFqw,996 +setuptools/version.py,sha256=og_cuZQb0QI6ukKZFfZWPlr1HgJBPPn2vO2m_bI9ZTE,144 +setuptools/wheel.py,sha256=zct-SEj5_LoHg6XELt2cVRdulsUENenCdS1ekM7TlZA,8455 +setuptools/windows_support.py,sha256=5GrfqSP2-dLGJoZTq2g6dCKkyQxxa2n5IQiXlJCoYEE,714 diff --git a/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/WHEEL b/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/WHEEL new file mode 100644 index 0000000..ef99c6c --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools-44.0.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/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/dependency_links.txt b/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/dependency_links.txt new file mode 100644 index 0000000..e87d021 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/dependency_links.txt @@ -0,0 +1,2 @@ +https://files.pythonhosted.org/packages/source/c/certifi/certifi-2016.9.26.tar.gz#md5=baa81e951a29958563689d868ef1064d +https://files.pythonhosted.org/packages/source/w/wincertstore/wincertstore-0.2.zip#md5=ae728f2f007185648d0c7a8679b361e2 diff --git a/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/entry_points.txt b/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/entry_points.txt new file mode 100644 index 0000000..0fed3f1 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/entry_points.txt @@ -0,0 +1,68 @@ +[console_scripts] +easy_install = setuptools.command.easy_install:main + +[distutils.commands] +alias = setuptools.command.alias:alias +bdist_egg = setuptools.command.bdist_egg:bdist_egg +bdist_rpm = setuptools.command.bdist_rpm:bdist_rpm +bdist_wininst = setuptools.command.bdist_wininst:bdist_wininst +build_clib = setuptools.command.build_clib:build_clib +build_ext = setuptools.command.build_ext:build_ext +build_py = setuptools.command.build_py:build_py +develop = setuptools.command.develop:develop +dist_info = setuptools.command.dist_info:dist_info +easy_install = setuptools.command.easy_install:easy_install +egg_info = setuptools.command.egg_info:egg_info +install = setuptools.command.install:install +install_egg_info = setuptools.command.install_egg_info:install_egg_info +install_lib = setuptools.command.install_lib:install_lib +install_scripts = setuptools.command.install_scripts:install_scripts +rotate = setuptools.command.rotate:rotate +saveopts = setuptools.command.saveopts:saveopts +sdist = setuptools.command.sdist:sdist +setopt = setuptools.command.setopt:setopt +test = setuptools.command.test:test +upload_docs = setuptools.command.upload_docs:upload_docs + +[distutils.setup_keywords] +convert_2to3_doctests = setuptools.dist:assert_string_list +dependency_links = setuptools.dist:assert_string_list +eager_resources = setuptools.dist:assert_string_list +entry_points = setuptools.dist:check_entry_points +exclude_package_data = setuptools.dist:check_package_data +extras_require = setuptools.dist:check_extras +include_package_data = setuptools.dist:assert_bool +install_requires = setuptools.dist:check_requirements +namespace_packages = setuptools.dist:check_nsp +package_data = setuptools.dist:check_package_data +packages = setuptools.dist:check_packages +python_requires = setuptools.dist:check_specifier +setup_requires = setuptools.dist:check_requirements +test_loader = setuptools.dist:check_importable +test_runner = setuptools.dist:check_importable +test_suite = setuptools.dist:check_test_suite +tests_require = setuptools.dist:check_requirements +use_2to3 = setuptools.dist:assert_bool +use_2to3_exclude_fixers = setuptools.dist:assert_string_list +use_2to3_fixers = setuptools.dist:assert_string_list +zip_safe = setuptools.dist:assert_bool + +[egg_info.writers] +PKG-INFO = setuptools.command.egg_info:write_pkg_info +dependency_links.txt = setuptools.command.egg_info:overwrite_arg +depends.txt = setuptools.command.egg_info:warn_depends_obsolete +eager_resources.txt = setuptools.command.egg_info:overwrite_arg +entry_points.txt = setuptools.command.egg_info:write_entries +namespace_packages.txt = setuptools.command.egg_info:overwrite_arg +requires.txt = setuptools.command.egg_info:write_requirements +top_level.txt = setuptools.command.egg_info:write_toplevel_names + +[setuptools.finalize_distribution_options] +2to3_doctests = setuptools.dist:Distribution._finalize_2to3_doctests +features = setuptools.dist:Distribution._finalize_feature_opts +keywords = setuptools.dist:Distribution._finalize_setup_keywords +parent_finalize = setuptools.dist:_Distribution.finalize_options + +[setuptools.installation] +eggsecutable = setuptools.command.easy_install:bootstrap + diff --git a/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/top_level.txt b/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/top_level.txt new file mode 100644 index 0000000..4577c6a --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/top_level.txt @@ -0,0 +1,3 @@ +easy_install +pkg_resources +setuptools diff --git a/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/zip-safe b/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/zip-safe new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/zip-safe @@ -0,0 +1 @@ + diff --git a/venv/lib/python3.8/site-packages/setuptools/__init__.py b/venv/lib/python3.8/site-packages/setuptools/__init__.py new file mode 100644 index 0000000..a71b2bb --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/__init__.py @@ -0,0 +1,228 @@ +"""Extensions to the 'distutils' for large or complex distributions""" + +import os +import sys +import functools +import distutils.core +import distutils.filelist +import re +from distutils.errors import DistutilsOptionError +from distutils.util import convert_path +from fnmatch import fnmatchcase + +from ._deprecation_warning import SetuptoolsDeprecationWarning + +from setuptools.extern.six import PY3, string_types +from setuptools.extern.six.moves import filter, map + +import setuptools.version +from setuptools.extension import Extension +from setuptools.dist import Distribution, Feature +from setuptools.depends import Require +from . import monkey + +__metaclass__ = type + + +__all__ = [ + 'setup', 'Distribution', 'Feature', 'Command', 'Extension', 'Require', + 'SetuptoolsDeprecationWarning', + 'find_packages' +] + +if PY3: + __all__.append('find_namespace_packages') + +__version__ = setuptools.version.__version__ + +bootstrap_install_from = None + +# If we run 2to3 on .py files, should we also convert docstrings? +# Default: yes; assume that we can detect doctests reliably +run_2to3_on_doctests = True +# Standard package names for fixer packages +lib2to3_fixer_packages = ['lib2to3.fixes'] + + +class PackageFinder: + """ + Generate a list of all Python packages found within a directory + """ + + @classmethod + def find(cls, where='.', exclude=(), include=('*',)): + """Return a list all Python packages found within directory 'where' + + 'where' is the root directory which will be searched for packages. It + should be supplied as a "cross-platform" (i.e. URL-style) path; it will + be converted to the appropriate local path syntax. + + 'exclude' is a sequence of package names to exclude; '*' can be used + as a wildcard in the names, such that 'foo.*' will exclude all + subpackages of 'foo' (but not 'foo' itself). + + 'include' is a sequence of package names to include. If it's + specified, only the named packages will be included. If it's not + specified, all found packages will be included. 'include' can contain + shell style wildcard patterns just like 'exclude'. + """ + + return list(cls._find_packages_iter( + convert_path(where), + cls._build_filter('ez_setup', '*__pycache__', *exclude), + cls._build_filter(*include))) + + @classmethod + def _find_packages_iter(cls, where, exclude, include): + """ + All the packages found in 'where' that pass the 'include' filter, but + not the 'exclude' filter. + """ + for root, dirs, files in os.walk(where, followlinks=True): + # Copy dirs to iterate over it, then empty dirs. + all_dirs = dirs[:] + dirs[:] = [] + + for dir in all_dirs: + full_path = os.path.join(root, dir) + rel_path = os.path.relpath(full_path, where) + package = rel_path.replace(os.path.sep, '.') + + # Skip directory trees that are not valid packages + if ('.' in dir or not cls._looks_like_package(full_path)): + continue + + # Should this package be included? + if include(package) and not exclude(package): + yield package + + # Keep searching subdirectories, as there may be more packages + # down there, even if the parent was excluded. + dirs.append(dir) + + @staticmethod + def _looks_like_package(path): + """Does a directory look like a package?""" + return os.path.isfile(os.path.join(path, '__init__.py')) + + @staticmethod + def _build_filter(*patterns): + """ + Given a list of patterns, return a callable that will be true only if + the input matches at least one of the patterns. + """ + return lambda name: any(fnmatchcase(name, pat=pat) for pat in patterns) + + +class PEP420PackageFinder(PackageFinder): + @staticmethod + def _looks_like_package(path): + return True + + +find_packages = PackageFinder.find + +if PY3: + find_namespace_packages = PEP420PackageFinder.find + + +def _install_setup_requires(attrs): + # Note: do not use `setuptools.Distribution` directly, as + # our PEP 517 backend patch `distutils.core.Distribution`. + dist = distutils.core.Distribution(dict( + (k, v) for k, v in attrs.items() + if k in ('dependency_links', 'setup_requires') + )) + # Honor setup.cfg's options. + dist.parse_config_files(ignore_option_errors=True) + if dist.setup_requires: + dist.fetch_build_eggs(dist.setup_requires) + + +def setup(**attrs): + # Make sure we have any requirements needed to interpret 'attrs'. + _install_setup_requires(attrs) + return distutils.core.setup(**attrs) + +setup.__doc__ = distutils.core.setup.__doc__ + + +_Command = monkey.get_unpatched(distutils.core.Command) + + +class Command(_Command): + __doc__ = _Command.__doc__ + + command_consumes_arguments = False + + def __init__(self, dist, **kw): + """ + Construct the command for dist, updating + vars(self) with any keyword parameters. + """ + _Command.__init__(self, dist) + vars(self).update(kw) + + def _ensure_stringlike(self, option, what, default=None): + val = getattr(self, option) + if val is None: + setattr(self, option, default) + return default + elif not isinstance(val, string_types): + raise DistutilsOptionError("'%s' must be a %s (got `%s`)" + % (option, what, val)) + return val + + def ensure_string_list(self, option): + r"""Ensure that 'option' is a list of strings. If 'option' is + currently a string, we split it either on /,\s*/ or /\s+/, so + "foo bar baz", "foo,bar,baz", and "foo, bar baz" all become + ["foo", "bar", "baz"]. + """ + val = getattr(self, option) + if val is None: + return + elif isinstance(val, string_types): + setattr(self, option, re.split(r',\s*|\s+', val)) + else: + if isinstance(val, list): + ok = all(isinstance(v, string_types) for v in val) + else: + ok = False + if not ok: + raise DistutilsOptionError( + "'%s' must be a list of strings (got %r)" + % (option, val)) + + def reinitialize_command(self, command, reinit_subcommands=0, **kw): + cmd = _Command.reinitialize_command(self, command, reinit_subcommands) + vars(cmd).update(kw) + return cmd + + +def _find_all_simple(path): + """ + Find all files under 'path' + """ + results = ( + os.path.join(base, file) + for base, dirs, files in os.walk(path, followlinks=True) + for file in files + ) + return filter(os.path.isfile, results) + + +def findall(dir=os.curdir): + """ + Find all files under 'dir' and return the list of full filenames. + Unless dir is '.', return full filenames with dir prepended. + """ + files = _find_all_simple(dir) + if dir == os.curdir: + make_rel = functools.partial(os.path.relpath, start=dir) + files = map(make_rel, files) + return list(files) + + +# Apply monkey patches +monkey.patch_all() diff --git a/venv/lib/python3.8/site-packages/setuptools/_deprecation_warning.py b/venv/lib/python3.8/site-packages/setuptools/_deprecation_warning.py new file mode 100644 index 0000000..086b64d --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/_deprecation_warning.py @@ -0,0 +1,7 @@ +class SetuptoolsDeprecationWarning(Warning): + """ + Base class for warning deprecations in ``setuptools`` + + This class is not derived from ``DeprecationWarning``, and as such is + visible by default. + """ diff --git a/venv/lib/python3.8/site-packages/setuptools/_imp.py b/venv/lib/python3.8/site-packages/setuptools/_imp.py new file mode 100644 index 0000000..a3cce9b --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/_imp.py @@ -0,0 +1,73 @@ +""" +Re-implementation of find_module and get_frozen_object +from the deprecated imp module. +""" + +import os +import importlib.util +import importlib.machinery + +from .py34compat import module_from_spec + + +PY_SOURCE = 1 +PY_COMPILED = 2 +C_EXTENSION = 3 +C_BUILTIN = 6 +PY_FROZEN = 7 + + +def find_module(module, paths=None): + """Just like 'imp.find_module()', but with package support""" + spec = importlib.util.find_spec(module, paths) + if spec is None: + raise ImportError("Can't find %s" % module) + if not spec.has_location and hasattr(spec, 'submodule_search_locations'): + spec = importlib.util.spec_from_loader('__init__.py', spec.loader) + + kind = -1 + file = None + static = isinstance(spec.loader, type) + if spec.origin == 'frozen' or static and issubclass( + spec.loader, importlib.machinery.FrozenImporter): + kind = PY_FROZEN + path = None # imp compabilty + suffix = mode = '' # imp compability + elif spec.origin == 'built-in' or static and issubclass( + spec.loader, importlib.machinery.BuiltinImporter): + kind = C_BUILTIN + path = None # imp compabilty + suffix = mode = '' # imp compability + elif spec.has_location: + path = spec.origin + suffix = os.path.splitext(path)[1] + mode = 'r' if suffix in importlib.machinery.SOURCE_SUFFIXES else 'rb' + + if suffix in importlib.machinery.SOURCE_SUFFIXES: + kind = PY_SOURCE + elif suffix in importlib.machinery.BYTECODE_SUFFIXES: + kind = PY_COMPILED + elif suffix in importlib.machinery.EXTENSION_SUFFIXES: + kind = C_EXTENSION + + if kind in {PY_SOURCE, PY_COMPILED}: + file = open(path, mode) + else: + path = None + suffix = mode = '' + + return file, path, (suffix, mode, kind) + + +def get_frozen_object(module, paths=None): + spec = importlib.util.find_spec(module, paths) + if not spec: + raise ImportError("Can't find %s" % module) + return spec.loader.get_code(module) + + +def get_module(module, paths, info): + spec = importlib.util.find_spec(module, paths) + if not spec: + raise ImportError("Can't find %s" % module) + return module_from_spec(spec) diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/__init__.py b/venv/lib/python3.8/site-packages/setuptools/_vendor/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/ordered_set.py b/venv/lib/python3.8/site-packages/setuptools/_vendor/ordered_set.py new file mode 100644 index 0000000..1487600 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/_vendor/ordered_set.py @@ -0,0 +1,488 @@ +""" +An OrderedSet is a custom MutableSet that remembers its order, so that every +entry has an index that can be looked up. + +Based on a recipe originally posted to ActiveState Recipes by Raymond Hettiger, +and released under the MIT license. +""" +import itertools as it +from collections import deque + +try: + # Python 3 + from collections.abc import MutableSet, Sequence +except ImportError: + # Python 2.7 + from collections import MutableSet, Sequence + +SLICE_ALL = slice(None) +__version__ = "3.1" + + +def is_iterable(obj): + """ + Are we being asked to look up a list of things, instead of a single thing? + We check for the `__iter__` attribute so that this can cover types that + don't have to be known by this module, such as NumPy arrays. + + Strings, however, should be considered as atomic values to look up, not + iterables. The same goes for tuples, since they are immutable and therefore + valid entries. + + We don't need to check for the Python 2 `unicode` type, because it doesn't + have an `__iter__` attribute anyway. + """ + return ( + hasattr(obj, "__iter__") + and not isinstance(obj, str) + and not isinstance(obj, tuple) + ) + + +class OrderedSet(MutableSet, Sequence): + """ + An OrderedSet is a custom MutableSet that remembers its order, so that + every entry has an index that can be looked up. + + Example: + >>> OrderedSet([1, 1, 2, 3, 2]) + OrderedSet([1, 2, 3]) + """ + + def __init__(self, iterable=None): + self.items = [] + self.map = {} + if iterable is not None: + self |= iterable + + def __len__(self): + """ + Returns the number of unique elements in the ordered set + + Example: + >>> len(OrderedSet([])) + 0 + >>> len(OrderedSet([1, 2])) + 2 + """ + return len(self.items) + + def __getitem__(self, index): + """ + Get the item at a given index. + + If `index` is a slice, you will get back that slice of items, as a + new OrderedSet. + + If `index` is a list or a similar iterable, you'll get a list of + items corresponding to those indices. This is similar to NumPy's + "fancy indexing". The result is not an OrderedSet because you may ask + for duplicate indices, and the number of elements returned should be + the number of elements asked for. + + Example: + >>> oset = OrderedSet([1, 2, 3]) + >>> oset[1] + 2 + """ + if isinstance(index, slice) and index == SLICE_ALL: + return self.copy() + elif is_iterable(index): + return [self.items[i] for i in index] + elif hasattr(index, "__index__") or isinstance(index, slice): + result = self.items[index] + if isinstance(result, list): + return self.__class__(result) + else: + return result + else: + raise TypeError("Don't know how to index an OrderedSet by %r" % index) + + def copy(self): + """ + Return a shallow copy of this object. + + Example: + >>> this = OrderedSet([1, 2, 3]) + >>> other = this.copy() + >>> this == other + True + >>> this is other + False + """ + return self.__class__(self) + + def __getstate__(self): + if len(self) == 0: + # The state can't be an empty list. + # We need to return a truthy value, or else __setstate__ won't be run. + # + # This could have been done more gracefully by always putting the state + # in a tuple, but this way is backwards- and forwards- compatible with + # previous versions of OrderedSet. + return (None,) + else: + return list(self) + + def __setstate__(self, state): + if state == (None,): + self.__init__([]) + else: + self.__init__(state) + + def __contains__(self, key): + """ + Test if the item is in this ordered set + + Example: + >>> 1 in OrderedSet([1, 3, 2]) + True + >>> 5 in OrderedSet([1, 3, 2]) + False + """ + return key in self.map + + def add(self, key): + """ + Add `key` as an item to this OrderedSet, then return its index. + + If `key` is already in the OrderedSet, return the index it already + had. + + Example: + >>> oset = OrderedSet() + >>> oset.append(3) + 0 + >>> print(oset) + OrderedSet([3]) + """ + if key not in self.map: + self.map[key] = len(self.items) + self.items.append(key) + return self.map[key] + + append = add + + def update(self, sequence): + """ + Update the set with the given iterable sequence, then return the index + of the last element inserted. + + Example: + >>> oset = OrderedSet([1, 2, 3]) + >>> oset.update([3, 1, 5, 1, 4]) + 4 + >>> print(oset) + OrderedSet([1, 2, 3, 5, 4]) + """ + item_index = None + try: + for item in sequence: + item_index = self.add(item) + except TypeError: + raise ValueError( + "Argument needs to be an iterable, got %s" % type(sequence) + ) + return item_index + + def index(self, key): + """ + Get the index of a given entry, raising an IndexError if it's not + present. + + `key` can be an iterable of entries that is not a string, in which case + this returns a list of indices. + + Example: + >>> oset = OrderedSet([1, 2, 3]) + >>> oset.index(2) + 1 + """ + if is_iterable(key): + return [self.index(subkey) for subkey in key] + return self.map[key] + + # Provide some compatibility with pd.Index + get_loc = index + get_indexer = index + + def pop(self): + """ + Remove and return the last element from the set. + + Raises KeyError if the set is empty. + + Example: + >>> oset = OrderedSet([1, 2, 3]) + >>> oset.pop() + 3 + """ + if not self.items: + raise KeyError("Set is empty") + + elem = self.items[-1] + del self.items[-1] + del self.map[elem] + return elem + + def discard(self, key): + """ + Remove an element. Do not raise an exception if absent. + + The MutableSet mixin uses this to implement the .remove() method, which + *does* raise an error when asked to remove a non-existent item. + + Example: + >>> oset = OrderedSet([1, 2, 3]) + >>> oset.discard(2) + >>> print(oset) + OrderedSet([1, 3]) + >>> oset.discard(2) + >>> print(oset) + OrderedSet([1, 3]) + """ + if key in self: + i = self.map[key] + del self.items[i] + del self.map[key] + for k, v in self.map.items(): + if v >= i: + self.map[k] = v - 1 + + def clear(self): + """ + Remove all items from this OrderedSet. + """ + del self.items[:] + self.map.clear() + + def __iter__(self): + """ + Example: + >>> list(iter(OrderedSet([1, 2, 3]))) + [1, 2, 3] + """ + return iter(self.items) + + def __reversed__(self): + """ + Example: + >>> list(reversed(OrderedSet([1, 2, 3]))) + [3, 2, 1] + """ + return reversed(self.items) + + def __repr__(self): + if not self: + return "%s()" % (self.__class__.__name__,) + return "%s(%r)" % (self.__class__.__name__, list(self)) + + def __eq__(self, other): + """ + Returns true if the containers have the same items. If `other` is a + Sequence, then order is checked, otherwise it is ignored. + + Example: + >>> oset = OrderedSet([1, 3, 2]) + >>> oset == [1, 3, 2] + True + >>> oset == [1, 2, 3] + False + >>> oset == [2, 3] + False + >>> oset == OrderedSet([3, 2, 1]) + False + """ + # In Python 2 deque is not a Sequence, so treat it as one for + # consistent behavior with Python 3. + if isinstance(other, (Sequence, deque)): + # Check that this OrderedSet contains the same elements, in the + # same order, as the other object. + return list(self) == list(other) + try: + other_as_set = set(other) + except TypeError: + # If `other` can't be converted into a set, it's not equal. + return False + else: + return set(self) == other_as_set + + def union(self, *sets): + """ + Combines all unique items. + Each items order is defined by its first appearance. + + Example: + >>> oset = OrderedSet.union(OrderedSet([3, 1, 4, 1, 5]), [1, 3], [2, 0]) + >>> print(oset) + OrderedSet([3, 1, 4, 5, 2, 0]) + >>> oset.union([8, 9]) + OrderedSet([3, 1, 4, 5, 2, 0, 8, 9]) + >>> oset | {10} + OrderedSet([3, 1, 4, 5, 2, 0, 10]) + """ + cls = self.__class__ if isinstance(self, OrderedSet) else OrderedSet + containers = map(list, it.chain([self], sets)) + items = it.chain.from_iterable(containers) + return cls(items) + + def __and__(self, other): + # the parent implementation of this is backwards + return self.intersection(other) + + def intersection(self, *sets): + """ + Returns elements in common between all sets. Order is defined only + by the first set. + + Example: + >>> oset = OrderedSet.intersection(OrderedSet([0, 1, 2, 3]), [1, 2, 3]) + >>> print(oset) + OrderedSet([1, 2, 3]) + >>> oset.intersection([2, 4, 5], [1, 2, 3, 4]) + OrderedSet([2]) + >>> oset.intersection() + OrderedSet([1, 2, 3]) + """ + cls = self.__class__ if isinstance(self, OrderedSet) else OrderedSet + if sets: + common = set.intersection(*map(set, sets)) + items = (item for item in self if item in common) + else: + items = self + return cls(items) + + def difference(self, *sets): + """ + Returns all elements that are in this set but not the others. + + Example: + >>> OrderedSet([1, 2, 3]).difference(OrderedSet([2])) + OrderedSet([1, 3]) + >>> OrderedSet([1, 2, 3]).difference(OrderedSet([2]), OrderedSet([3])) + OrderedSet([1]) + >>> OrderedSet([1, 2, 3]) - OrderedSet([2]) + OrderedSet([1, 3]) + >>> OrderedSet([1, 2, 3]).difference() + OrderedSet([1, 2, 3]) + """ + cls = self.__class__ + if sets: + other = set.union(*map(set, sets)) + items = (item for item in self if item not in other) + else: + items = self + return cls(items) + + def issubset(self, other): + """ + Report whether another set contains this set. + + Example: + >>> OrderedSet([1, 2, 3]).issubset({1, 2}) + False + >>> OrderedSet([1, 2, 3]).issubset({1, 2, 3, 4}) + True + >>> OrderedSet([1, 2, 3]).issubset({1, 4, 3, 5}) + False + """ + if len(self) > len(other): # Fast check for obvious cases + return False + return all(item in other for item in self) + + def issuperset(self, other): + """ + Report whether this set contains another set. + + Example: + >>> OrderedSet([1, 2]).issuperset([1, 2, 3]) + False + >>> OrderedSet([1, 2, 3, 4]).issuperset({1, 2, 3}) + True + >>> OrderedSet([1, 4, 3, 5]).issuperset({1, 2, 3}) + False + """ + if len(self) < len(other): # Fast check for obvious cases + return False + return all(item in self for item in other) + + def symmetric_difference(self, other): + """ + Return the symmetric difference of two OrderedSets as a new set. + That is, the new set will contain all elements that are in exactly + one of the sets. + + Their order will be preserved, with elements from `self` preceding + elements from `other`. + + Example: + >>> this = OrderedSet([1, 4, 3, 5, 7]) + >>> other = OrderedSet([9, 7, 1, 3, 2]) + >>> this.symmetric_difference(other) + OrderedSet([4, 5, 9, 2]) + """ + cls = self.__class__ if isinstance(self, OrderedSet) else OrderedSet + diff1 = cls(self).difference(other) + diff2 = cls(other).difference(self) + return diff1.union(diff2) + + def _update_items(self, items): + """ + Replace the 'items' list of this OrderedSet with a new one, updating + self.map accordingly. + """ + self.items = items + self.map = {item: idx for (idx, item) in enumerate(items)} + + def difference_update(self, *sets): + """ + Update this OrderedSet to remove items from one or more other sets. + + Example: + >>> this = OrderedSet([1, 2, 3]) + >>> this.difference_update(OrderedSet([2, 4])) + >>> print(this) + OrderedSet([1, 3]) + + >>> this = OrderedSet([1, 2, 3, 4, 5]) + >>> this.difference_update(OrderedSet([2, 4]), OrderedSet([1, 4, 6])) + >>> print(this) + OrderedSet([3, 5]) + """ + items_to_remove = set() + for other in sets: + items_to_remove |= set(other) + self._update_items([item for item in self.items if item not in items_to_remove]) + + def intersection_update(self, other): + """ + Update this OrderedSet to keep only items in another set, preserving + their order in this set. + + Example: + >>> this = OrderedSet([1, 4, 3, 5, 7]) + >>> other = OrderedSet([9, 7, 1, 3, 2]) + >>> this.intersection_update(other) + >>> print(this) + OrderedSet([1, 3, 7]) + """ + other = set(other) + self._update_items([item for item in self.items if item in other]) + + def symmetric_difference_update(self, other): + """ + Update this OrderedSet to remove items from another set, then + add items from the other set that were not present in this set. + + Example: + >>> this = OrderedSet([1, 4, 3, 5, 7]) + >>> other = OrderedSet([9, 7, 1, 3, 2]) + >>> this.symmetric_difference_update(other) + >>> print(this) + OrderedSet([4, 5, 9, 2]) + """ + items_to_add = [item for item in other if item not in self] + items_to_remove = set(other) + self._update_items( + [item for item in self.items if item not in items_to_remove] + items_to_add + ) diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__about__.py b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__about__.py new file mode 100644 index 0000000..dc95138 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__about__.py @@ -0,0 +1,27 @@ +# 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 __future__ import absolute_import, division, print_function + +__all__ = [ + "__title__", + "__summary__", + "__uri__", + "__version__", + "__author__", + "__email__", + "__license__", + "__copyright__", +] + +__title__ = "packaging" +__summary__ = "Core utilities for Python packages" +__uri__ = "https://github.com/pypa/packaging" + +__version__ = "19.2" + +__author__ = "Donald Stufft and individual contributors" +__email__ = "donald@stufft.io" + +__license__ = "BSD or Apache License, Version 2.0" +__copyright__ = "Copyright 2014-2019 %s" % __author__ diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__init__.py b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__init__.py new file mode 100644 index 0000000..a0cf67d --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__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 __future__ import absolute_import, division, print_function + +from .__about__ import ( + __author__, + __copyright__, + __email__, + __license__, + __summary__, + __title__, + __uri__, + __version__, +) + +__all__ = [ + "__title__", + "__summary__", + "__uri__", + "__version__", + "__author__", + "__email__", + "__license__", + "__copyright__", +] diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/_compat.py b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/_compat.py new file mode 100644 index 0000000..25da473 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/_compat.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 __future__ import absolute_import, division, print_function + +import sys + + +PY2 = sys.version_info[0] == 2 +PY3 = sys.version_info[0] == 3 + +# flake8: noqa + +if PY3: + string_types = (str,) +else: + string_types = (basestring,) + + +def with_metaclass(meta, *bases): + """ + Create a base class with a metaclass. + """ + # This requires a bit of explanation: the basic idea is to make a dummy + # metaclass for one level of class instantiation that replaces itself with + # the actual metaclass. + class metaclass(meta): + def __new__(cls, name, this_bases, d): + return meta(name, bases, d) + + return type.__new__(metaclass, "temporary_class", (), {}) diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/_structures.py b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/_structures.py new file mode 100644 index 0000000..68dcca6 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/_structures.py @@ -0,0 +1,68 @@ +# 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 __future__ import absolute_import, division, print_function + + +class Infinity(object): + def __repr__(self): + return "Infinity" + + def __hash__(self): + return hash(repr(self)) + + def __lt__(self, other): + return False + + def __le__(self, other): + return False + + def __eq__(self, other): + return isinstance(other, self.__class__) + + def __ne__(self, other): + return not isinstance(other, self.__class__) + + def __gt__(self, other): + return True + + def __ge__(self, other): + return True + + def __neg__(self): + return NegativeInfinity + + +Infinity = Infinity() + + +class NegativeInfinity(object): + def __repr__(self): + return "-Infinity" + + def __hash__(self): + return hash(repr(self)) + + def __lt__(self, other): + return True + + def __le__(self, other): + return True + + def __eq__(self, other): + return isinstance(other, self.__class__) + + def __ne__(self, other): + return not isinstance(other, self.__class__) + + def __gt__(self, other): + return False + + def __ge__(self, other): + return False + + def __neg__(self): + return Infinity + + +NegativeInfinity = NegativeInfinity() diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/markers.py b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/markers.py new file mode 100644 index 0000000..4bdfdb2 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/markers.py @@ -0,0 +1,296 @@ +# 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 __future__ import absolute_import, division, print_function + +import operator +import os +import platform +import sys + +from setuptools.extern.pyparsing import ParseException, ParseResults, stringStart, stringEnd +from setuptools.extern.pyparsing import ZeroOrMore, Group, Forward, QuotedString +from setuptools.extern.pyparsing import Literal as L # noqa + +from ._compat import string_types +from .specifiers import Specifier, InvalidSpecifier + + +__all__ = [ + "InvalidMarker", + "UndefinedComparison", + "UndefinedEnvironmentName", + "Marker", + "default_environment", +] + + +class InvalidMarker(ValueError): + """ + An invalid marker was found, users should refer to PEP 508. + """ + + +class UndefinedComparison(ValueError): + """ + An invalid operation was attempted on a value that doesn't support it. + """ + + +class UndefinedEnvironmentName(ValueError): + """ + A name was attempted to be used that does not exist inside of the + environment. + """ + + +class Node(object): + def __init__(self, value): + self.value = value + + def __str__(self): + return str(self.value) + + def __repr__(self): + return "<{0}({1!r})>".format(self.__class__.__name__, str(self)) + + def serialize(self): + raise NotImplementedError + + +class Variable(Node): + def serialize(self): + return str(self) + + +class Value(Node): + def serialize(self): + return '"{0}"'.format(self) + + +class Op(Node): + def serialize(self): + return str(self) + + +VARIABLE = ( + L("implementation_version") + | L("platform_python_implementation") + | L("implementation_name") + | L("python_full_version") + | L("platform_release") + | L("platform_version") + | L("platform_machine") + | L("platform_system") + | L("python_version") + | L("sys_platform") + | L("os_name") + | L("os.name") + | L("sys.platform") # PEP-345 + | L("platform.version") # PEP-345 + | L("platform.machine") # PEP-345 + | L("platform.python_implementation") # PEP-345 + | L("python_implementation") # PEP-345 + | L("extra") # undocumented setuptools legacy +) +ALIASES = { + "os.name": "os_name", + "sys.platform": "sys_platform", + "platform.version": "platform_version", + "platform.machine": "platform_machine", + "platform.python_implementation": "platform_python_implementation", + "python_implementation": "platform_python_implementation", +} +VARIABLE.setParseAction(lambda s, l, t: Variable(ALIASES.get(t[0], t[0]))) + +VERSION_CMP = ( + L("===") | L("==") | L(">=") | L("<=") | L("!=") | L("~=") | L(">") | L("<") +) + +MARKER_OP = VERSION_CMP | L("not in") | L("in") +MARKER_OP.setParseAction(lambda s, l, t: Op(t[0])) + +MARKER_VALUE = QuotedString("'") | QuotedString('"') +MARKER_VALUE.setParseAction(lambda s, l, t: Value(t[0])) + +BOOLOP = L("and") | L("or") + +MARKER_VAR = VARIABLE | MARKER_VALUE + +MARKER_ITEM = Group(MARKER_VAR + MARKER_OP + MARKER_VAR) +MARKER_ITEM.setParseAction(lambda s, l, t: tuple(t[0])) + +LPAREN = L("(").suppress() +RPAREN = L(")").suppress() + +MARKER_EXPR = Forward() +MARKER_ATOM = MARKER_ITEM | Group(LPAREN + MARKER_EXPR + RPAREN) +MARKER_EXPR << MARKER_ATOM + ZeroOrMore(BOOLOP + MARKER_EXPR) + +MARKER = stringStart + MARKER_EXPR + stringEnd + + +def _coerce_parse_result(results): + if isinstance(results, ParseResults): + return [_coerce_parse_result(i) for i in results] + else: + return results + + +def _format_marker(marker, first=True): + assert isinstance(marker, (list, tuple, string_types)) + + # Sometimes we have a structure like [[...]] which is a single item list + # where the single item is itself it's own list. In that case we want skip + # the rest of this function so that we don't get extraneous () on the + # outside. + if ( + isinstance(marker, list) + and len(marker) == 1 + and isinstance(marker[0], (list, tuple)) + ): + return _format_marker(marker[0]) + + if isinstance(marker, list): + inner = (_format_marker(m, first=False) for m in marker) + if first: + return " ".join(inner) + else: + return "(" + " ".join(inner) + ")" + elif isinstance(marker, tuple): + return " ".join([m.serialize() for m in marker]) + else: + return marker + + +_operators = { + "in": lambda lhs, rhs: lhs in rhs, + "not in": lambda lhs, rhs: lhs not in rhs, + "<": operator.lt, + "<=": operator.le, + "==": operator.eq, + "!=": operator.ne, + ">=": operator.ge, + ">": operator.gt, +} + + +def _eval_op(lhs, op, rhs): + try: + spec = Specifier("".join([op.serialize(), rhs])) + except InvalidSpecifier: + pass + else: + return spec.contains(lhs) + + oper = _operators.get(op.serialize()) + if oper is None: + raise UndefinedComparison( + "Undefined {0!r} on {1!r} and {2!r}.".format(op, lhs, rhs) + ) + + return oper(lhs, rhs) + + +_undefined = object() + + +def _get_env(environment, name): + value = environment.get(name, _undefined) + + if value is _undefined: + raise UndefinedEnvironmentName( + "{0!r} does not exist in evaluation environment.".format(name) + ) + + return value + + +def _evaluate_markers(markers, environment): + groups = [[]] + + for marker in markers: + assert isinstance(marker, (list, tuple, string_types)) + + if isinstance(marker, list): + groups[-1].append(_evaluate_markers(marker, environment)) + elif isinstance(marker, tuple): + lhs, op, rhs = marker + + if isinstance(lhs, Variable): + lhs_value = _get_env(environment, lhs.value) + rhs_value = rhs.value + else: + lhs_value = lhs.value + rhs_value = _get_env(environment, rhs.value) + + groups[-1].append(_eval_op(lhs_value, op, rhs_value)) + else: + assert marker in ["and", "or"] + if marker == "or": + groups.append([]) + + return any(all(item) for item in groups) + + +def format_full_version(info): + version = "{0.major}.{0.minor}.{0.micro}".format(info) + kind = info.releaselevel + if kind != "final": + version += kind[0] + str(info.serial) + return version + + +def default_environment(): + if hasattr(sys, "implementation"): + iver = format_full_version(sys.implementation.version) + implementation_name = sys.implementation.name + else: + iver = "0" + implementation_name = "" + + return { + "implementation_name": implementation_name, + "implementation_version": iver, + "os_name": os.name, + "platform_machine": platform.machine(), + "platform_release": platform.release(), + "platform_system": platform.system(), + "platform_version": platform.version(), + "python_full_version": platform.python_version(), + "platform_python_implementation": platform.python_implementation(), + "python_version": ".".join(platform.python_version_tuple()[:2]), + "sys_platform": sys.platform, + } + + +class Marker(object): + def __init__(self, marker): + try: + self._markers = _coerce_parse_result(MARKER.parseString(marker)) + except ParseException as e: + err_str = "Invalid marker: {0!r}, parse error at {1!r}".format( + marker, marker[e.loc : e.loc + 8] + ) + raise InvalidMarker(err_str) + + def __str__(self): + return _format_marker(self._markers) + + def __repr__(self): + return "<Marker({0!r})>".format(str(self)) + + def evaluate(self, environment=None): + """Evaluate a marker. + + Return the boolean from evaluating the given marker against the + environment. environment is an optional argument to override all or + part of the determined environment. + + The environment is determined from the current Python process. + """ + current_environment = default_environment() + if environment is not None: + current_environment.update(environment) + + return _evaluate_markers(self._markers, current_environment) diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/requirements.py b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/requirements.py new file mode 100644 index 0000000..8a0c2cb --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/requirements.py @@ -0,0 +1,138 @@ +# 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 __future__ import absolute_import, division, print_function + +import string +import re + +from setuptools.extern.pyparsing import stringStart, stringEnd, originalTextFor, ParseException +from setuptools.extern.pyparsing import ZeroOrMore, Word, Optional, Regex, Combine +from setuptools.extern.pyparsing import Literal as L # noqa +from setuptools.extern.six.moves.urllib import parse as urlparse + +from .markers import MARKER_EXPR, Marker +from .specifiers import LegacySpecifier, Specifier, SpecifierSet + + +class InvalidRequirement(ValueError): + """ + An invalid requirement was found, users should refer to PEP 508. + """ + + +ALPHANUM = Word(string.ascii_letters + string.digits) + +LBRACKET = L("[").suppress() +RBRACKET = L("]").suppress() +LPAREN = L("(").suppress() +RPAREN = L(")").suppress() +COMMA = L(",").suppress() +SEMICOLON = L(";").suppress() +AT = L("@").suppress() + +PUNCTUATION = Word("-_.") +IDENTIFIER_END = ALPHANUM | (ZeroOrMore(PUNCTUATION) + ALPHANUM) +IDENTIFIER = Combine(ALPHANUM + ZeroOrMore(IDENTIFIER_END)) + +NAME = IDENTIFIER("name") +EXTRA = IDENTIFIER + +URI = Regex(r"[^ ]+")("url") +URL = AT + URI + +EXTRAS_LIST = EXTRA + ZeroOrMore(COMMA + EXTRA) +EXTRAS = (LBRACKET + Optional(EXTRAS_LIST) + RBRACKET)("extras") + +VERSION_PEP440 = Regex(Specifier._regex_str, re.VERBOSE | re.IGNORECASE) +VERSION_LEGACY = Regex(LegacySpecifier._regex_str, re.VERBOSE | re.IGNORECASE) + +VERSION_ONE = VERSION_PEP440 ^ VERSION_LEGACY +VERSION_MANY = Combine( + VERSION_ONE + ZeroOrMore(COMMA + VERSION_ONE), joinString=",", adjacent=False +)("_raw_spec") +_VERSION_SPEC = Optional(((LPAREN + VERSION_MANY + RPAREN) | VERSION_MANY)) +_VERSION_SPEC.setParseAction(lambda s, l, t: t._raw_spec or "") + +VERSION_SPEC = originalTextFor(_VERSION_SPEC)("specifier") +VERSION_SPEC.setParseAction(lambda s, l, t: t[1]) + +MARKER_EXPR = originalTextFor(MARKER_EXPR())("marker") +MARKER_EXPR.setParseAction( + lambda s, l, t: Marker(s[t._original_start : t._original_end]) +) +MARKER_SEPARATOR = SEMICOLON +MARKER = MARKER_SEPARATOR + MARKER_EXPR + +VERSION_AND_MARKER = VERSION_SPEC + Optional(MARKER) +URL_AND_MARKER = URL + Optional(MARKER) + +NAMED_REQUIREMENT = NAME + Optional(EXTRAS) + (URL_AND_MARKER | VERSION_AND_MARKER) + +REQUIREMENT = stringStart + NAMED_REQUIREMENT + stringEnd +# setuptools.extern.pyparsing isn't thread safe during initialization, so we do it eagerly, see +# issue #104 +REQUIREMENT.parseString("x[]") + + +class Requirement(object): + """Parse a requirement. + + Parse a given requirement string into its parts, such as name, specifier, + URL, and extras. Raises InvalidRequirement on a badly-formed requirement + string. + """ + + # TODO: Can we test whether something is contained within a requirement? + # If so how do we do that? Do we need to test against the _name_ of + # the thing as well as the version? What about the markers? + # TODO: Can we normalize the name and extra name? + + def __init__(self, requirement_string): + try: + req = REQUIREMENT.parseString(requirement_string) + except ParseException as e: + raise InvalidRequirement( + 'Parse error at "{0!r}": {1}'.format( + requirement_string[e.loc : e.loc + 8], e.msg + ) + ) + + self.name = req.name + if req.url: + parsed_url = urlparse.urlparse(req.url) + if parsed_url.scheme == "file": + if urlparse.urlunparse(parsed_url) != req.url: + raise InvalidRequirement("Invalid URL given") + elif not (parsed_url.scheme and parsed_url.netloc) or ( + not parsed_url.scheme and not parsed_url.netloc + ): + raise InvalidRequirement("Invalid URL: {0}".format(req.url)) + self.url = req.url + else: + self.url = None + self.extras = set(req.extras.asList() if req.extras else []) + self.specifier = SpecifierSet(req.specifier) + self.marker = req.marker if req.marker else None + + def __str__(self): + parts = [self.name] + + if self.extras: + parts.append("[{0}]".format(",".join(sorted(self.extras)))) + + if self.specifier: + parts.append(str(self.specifier)) + + if self.url: + parts.append("@ {0}".format(self.url)) + if self.marker: + parts.append(" ") + + if self.marker: + parts.append("; {0}".format(self.marker)) + + return "".join(parts) + + def __repr__(self): + return "<Requirement({0!r})>".format(str(self)) diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/specifiers.py b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/specifiers.py new file mode 100644 index 0000000..743576a --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/specifiers.py @@ -0,0 +1,749 @@ +# 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 __future__ import absolute_import, division, print_function + +import abc +import functools +import itertools +import re + +from ._compat import string_types, with_metaclass +from .version import Version, LegacyVersion, parse + + +class InvalidSpecifier(ValueError): + """ + An invalid specifier was found, users should refer to PEP 440. + """ + + +class BaseSpecifier(with_metaclass(abc.ABCMeta, object)): + @abc.abstractmethod + def __str__(self): + """ + Returns the str representation of this Specifier like object. This + should be representative of the Specifier itself. + """ + + @abc.abstractmethod + def __hash__(self): + """ + Returns a hash value for this Specifier like object. + """ + + @abc.abstractmethod + def __eq__(self, other): + """ + Returns a boolean representing whether or not the two Specifier like + objects are equal. + """ + + @abc.abstractmethod + def __ne__(self, other): + """ + Returns a boolean representing whether or not the two Specifier like + objects are not equal. + """ + + @abc.abstractproperty + def prereleases(self): + """ + Returns whether or not pre-releases as a whole are allowed by this + specifier. + """ + + @prereleases.setter + def prereleases(self, value): + """ + Sets whether or not pre-releases as a whole are allowed by this + specifier. + """ + + @abc.abstractmethod + def contains(self, item, prereleases=None): + """ + Determines if the given item is contained within this specifier. + """ + + @abc.abstractmethod + def filter(self, iterable, prereleases=None): + """ + Takes an iterable of items and filters them so that only items which + are contained within this specifier are allowed in it. + """ + + +class _IndividualSpecifier(BaseSpecifier): + + _operators = {} + + def __init__(self, spec="", prereleases=None): + match = self._regex.search(spec) + if not match: + raise InvalidSpecifier("Invalid specifier: '{0}'".format(spec)) + + self._spec = (match.group("operator").strip(), match.group("version").strip()) + + # Store whether or not this Specifier should accept prereleases + self._prereleases = prereleases + + def __repr__(self): + pre = ( + ", prereleases={0!r}".format(self.prereleases) + if self._prereleases is not None + else "" + ) + + return "<{0}({1!r}{2})>".format(self.__class__.__name__, str(self), pre) + + def __str__(self): + return "{0}{1}".format(*self._spec) + + def __hash__(self): + return hash(self._spec) + + def __eq__(self, other): + if isinstance(other, string_types): + try: + other = self.__class__(other) + except InvalidSpecifier: + return NotImplemented + elif not isinstance(other, self.__class__): + return NotImplemented + + return self._spec == other._spec + + def __ne__(self, other): + if isinstance(other, string_types): + try: + other = self.__class__(other) + except InvalidSpecifier: + return NotImplemented + elif not isinstance(other, self.__class__): + return NotImplemented + + return self._spec != other._spec + + def _get_operator(self, op): + return getattr(self, "_compare_{0}".format(self._operators[op])) + + def _coerce_version(self, version): + if not isinstance(version, (LegacyVersion, Version)): + version = parse(version) + return version + + @property + def operator(self): + return self._spec[0] + + @property + def version(self): + return self._spec[1] + + @property + def prereleases(self): + return self._prereleases + + @prereleases.setter + def prereleases(self, value): + self._prereleases = value + + def __contains__(self, item): + return self.contains(item) + + def contains(self, item, prereleases=None): + # Determine if prereleases are to be allowed or not. + if prereleases is None: + prereleases = self.prereleases + + # Normalize item to a Version or LegacyVersion, this allows us to have + # a shortcut for ``"2.0" in Specifier(">=2") + item = self._coerce_version(item) + + # Determine if we should be supporting prereleases in this specifier + # or not, if we do not support prereleases than we can short circuit + # logic if this version is a prereleases. + if item.is_prerelease and not prereleases: + return False + + # Actually do the comparison to determine if this item is contained + # within this Specifier or not. + return self._get_operator(self.operator)(item, self.version) + + def filter(self, iterable, prereleases=None): + yielded = False + found_prereleases = [] + + kw = {"prereleases": prereleases if prereleases is not None else True} + + # Attempt to iterate over all the values in the iterable and if any of + # them match, yield them. + for version in iterable: + parsed_version = self._coerce_version(version) + + if self.contains(parsed_version, **kw): + # If our version is a prerelease, and we were not set to allow + # prereleases, then we'll store it for later incase nothing + # else matches this specifier. + if parsed_version.is_prerelease and not ( + prereleases or self.prereleases + ): + found_prereleases.append(version) + # Either this is not a prerelease, or we should have been + # accepting prereleases from the beginning. + else: + yielded = True + yield version + + # Now that we've iterated over everything, determine if we've yielded + # any values, and if we have not and we have any prereleases stored up + # then we will go ahead and yield the prereleases. + if not yielded and found_prereleases: + for version in found_prereleases: + yield version + + +class LegacySpecifier(_IndividualSpecifier): + + _regex_str = r""" + (?P<operator>(==|!=|<=|>=|<|>)) + \s* + (?P<version> + [^,;\s)]* # Since this is a "legacy" specifier, and the version + # string can be just about anything, we match everything + # except for whitespace, a semi-colon for marker support, + # a closing paren since versions can be enclosed in + # them, and a comma since it's a version separator. + ) + """ + + _regex = re.compile(r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE) + + _operators = { + "==": "equal", + "!=": "not_equal", + "<=": "less_than_equal", + ">=": "greater_than_equal", + "<": "less_than", + ">": "greater_than", + } + + def _coerce_version(self, version): + if not isinstance(version, LegacyVersion): + version = LegacyVersion(str(version)) + return version + + def _compare_equal(self, prospective, spec): + return prospective == self._coerce_version(spec) + + def _compare_not_equal(self, prospective, spec): + return prospective != self._coerce_version(spec) + + def _compare_less_than_equal(self, prospective, spec): + return prospective <= self._coerce_version(spec) + + def _compare_greater_than_equal(self, prospective, spec): + return prospective >= self._coerce_version(spec) + + def _compare_less_than(self, prospective, spec): + return prospective < self._coerce_version(spec) + + def _compare_greater_than(self, prospective, spec): + return prospective > self._coerce_version(spec) + + +def _require_version_compare(fn): + @functools.wraps(fn) + def wrapped(self, prospective, spec): + if not isinstance(prospective, Version): + return False + return fn(self, prospective, spec) + + return wrapped + + +class Specifier(_IndividualSpecifier): + + _regex_str = r""" + (?P<operator>(~=|==|!=|<=|>=|<|>|===)) + (?P<version> + (?: + # The identity operators allow for an escape hatch that will + # do an exact string match of the version you wish to install. + # This will not be parsed by PEP 440 and we cannot determine + # any semantic meaning from it. This operator is discouraged + # but included entirely as an escape hatch. + (?<====) # Only match for the identity operator + \s* + [^\s]* # We just match everything, except for whitespace + # since we are only testing for strict identity. + ) + | + (?: + # The (non)equality operators allow for wild card and local + # versions to be specified so we have to define these two + # operators separately to enable that. + (?<===|!=) # Only match for equals and not equals + + \s* + v? + (?:[0-9]+!)? # epoch + [0-9]+(?:\.[0-9]+)* # release + (?: # pre release + [-_\.]? + (a|b|c|rc|alpha|beta|pre|preview) + [-_\.]? + [0-9]* + )? + (?: # post release + (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*) + )? + + # You cannot use a wild card and a dev or local version + # together so group them with a | and make them optional. + (?: + (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release + (?:\+[a-z0-9]+(?:[-_\.][a-z0-9]+)*)? # local + | + \.\* # Wild card syntax of .* + )? + ) + | + (?: + # The compatible operator requires at least two digits in the + # release segment. + (?<=~=) # Only match for the compatible operator + + \s* + v? + (?:[0-9]+!)? # epoch + [0-9]+(?:\.[0-9]+)+ # release (We have a + instead of a *) + (?: # pre release + [-_\.]? + (a|b|c|rc|alpha|beta|pre|preview) + [-_\.]? + [0-9]* + )? + (?: # post release + (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*) + )? + (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release + ) + | + (?: + # All other operators only allow a sub set of what the + # (non)equality operators do. Specifically they do not allow + # local versions to be specified nor do they allow the prefix + # matching wild cards. + (?<!==|!=|~=) # We have special cases for these + # operators so we want to make sure they + # don't match here. + + \s* + v? + (?:[0-9]+!)? # epoch + [0-9]+(?:\.[0-9]+)* # release + (?: # pre release + [-_\.]? + (a|b|c|rc|alpha|beta|pre|preview) + [-_\.]? + [0-9]* + )? + (?: # post release + (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*) + )? + (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release + ) + ) + """ + + _regex = re.compile(r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE) + + _operators = { + "~=": "compatible", + "==": "equal", + "!=": "not_equal", + "<=": "less_than_equal", + ">=": "greater_than_equal", + "<": "less_than", + ">": "greater_than", + "===": "arbitrary", + } + + @_require_version_compare + def _compare_compatible(self, prospective, spec): + # Compatible releases have an equivalent combination of >= and ==. That + # is that ~=2.2 is equivalent to >=2.2,==2.*. This allows us to + # implement this in terms of the other specifiers instead of + # implementing it ourselves. The only thing we need to do is construct + # the other specifiers. + + # We want everything but the last item in the version, but we want to + # ignore post and dev releases and we want to treat the pre-release as + # it's own separate segment. + prefix = ".".join( + list( + itertools.takewhile( + lambda x: (not x.startswith("post") and not x.startswith("dev")), + _version_split(spec), + ) + )[:-1] + ) + + # Add the prefix notation to the end of our string + prefix += ".*" + + return self._get_operator(">=")(prospective, spec) and self._get_operator("==")( + prospective, prefix + ) + + @_require_version_compare + def _compare_equal(self, prospective, spec): + # We need special logic to handle prefix matching + if spec.endswith(".*"): + # In the case of prefix matching we want to ignore local segment. + prospective = Version(prospective.public) + # Split the spec out by dots, and pretend that there is an implicit + # dot in between a release segment and a pre-release segment. + spec = _version_split(spec[:-2]) # Remove the trailing .* + + # Split the prospective version out by dots, and pretend that there + # is an implicit dot in between a release segment and a pre-release + # segment. + prospective = _version_split(str(prospective)) + + # Shorten the prospective version to be the same length as the spec + # so that we can determine if the specifier is a prefix of the + # prospective version or not. + prospective = prospective[: len(spec)] + + # Pad out our two sides with zeros so that they both equal the same + # length. + spec, prospective = _pad_version(spec, prospective) + else: + # Convert our spec string into a Version + spec = Version(spec) + + # If the specifier does not have a local segment, then we want to + # act as if the prospective version also does not have a local + # segment. + if not spec.local: + prospective = Version(prospective.public) + + return prospective == spec + + @_require_version_compare + def _compare_not_equal(self, prospective, spec): + return not self._compare_equal(prospective, spec) + + @_require_version_compare + def _compare_less_than_equal(self, prospective, spec): + return prospective <= Version(spec) + + @_require_version_compare + def _compare_greater_than_equal(self, prospective, spec): + return prospective >= Version(spec) + + @_require_version_compare + def _compare_less_than(self, prospective, spec): + # Convert our spec to a Version instance, since we'll want to work with + # it as a version. + spec = Version(spec) + + # Check to see if the prospective version is less than the spec + # version. If it's not we can short circuit and just return False now + # instead of doing extra unneeded work. + if not prospective < spec: + return False + + # This special case is here so that, unless the specifier itself + # includes is a pre-release version, that we do not accept pre-release + # versions for the version mentioned in the specifier (e.g. <3.1 should + # not match 3.1.dev0, but should match 3.0.dev0). + if not spec.is_prerelease and prospective.is_prerelease: + if Version(prospective.base_version) == Version(spec.base_version): + return False + + # If we've gotten to here, it means that prospective version is both + # less than the spec version *and* it's not a pre-release of the same + # version in the spec. + return True + + @_require_version_compare + def _compare_greater_than(self, prospective, spec): + # Convert our spec to a Version instance, since we'll want to work with + # it as a version. + spec = Version(spec) + + # Check to see if the prospective version is greater than the spec + # version. If it's not we can short circuit and just return False now + # instead of doing extra unneeded work. + if not prospective > spec: + return False + + # This special case is here so that, unless the specifier itself + # includes is a post-release version, that we do not accept + # post-release versions for the version mentioned in the specifier + # (e.g. >3.1 should not match 3.0.post0, but should match 3.2.post0). + if not spec.is_postrelease and prospective.is_postrelease: + if Version(prospective.base_version) == Version(spec.base_version): + return False + + # Ensure that we do not allow a local version of the version mentioned + # in the specifier, which is technically greater than, to match. + if prospective.local is not None: + if Version(prospective.base_version) == Version(spec.base_version): + return False + + # If we've gotten to here, it means that prospective version is both + # greater than the spec version *and* it's not a pre-release of the + # same version in the spec. + return True + + def _compare_arbitrary(self, prospective, spec): + return str(prospective).lower() == str(spec).lower() + + @property + def prereleases(self): + # If there is an explicit prereleases set for this, then we'll just + # blindly use that. + if self._prereleases is not None: + return self._prereleases + + # Look at all of our specifiers and determine if they are inclusive + # operators, and if they are if they are including an explicit + # prerelease. + operator, version = self._spec + if operator in ["==", ">=", "<=", "~=", "==="]: + # The == specifier can include a trailing .*, if it does we + # want to remove before parsing. + if operator == "==" and version.endswith(".*"): + version = version[:-2] + + # Parse the version, and if it is a pre-release than this + # specifier allows pre-releases. + if parse(version).is_prerelease: + return True + + return False + + @prereleases.setter + def prereleases(self, value): + self._prereleases = value + + +_prefix_regex = re.compile(r"^([0-9]+)((?:a|b|c|rc)[0-9]+)$") + + +def _version_split(version): + result = [] + for item in version.split("."): + match = _prefix_regex.search(item) + if match: + result.extend(match.groups()) + else: + result.append(item) + return result + + +def _pad_version(left, right): + left_split, right_split = [], [] + + # Get the release segment of our versions + left_split.append(list(itertools.takewhile(lambda x: x.isdigit(), left))) + right_split.append(list(itertools.takewhile(lambda x: x.isdigit(), right))) + + # Get the rest of our versions + left_split.append(left[len(left_split[0]) :]) + right_split.append(right[len(right_split[0]) :]) + + # Insert our padding + left_split.insert(1, ["0"] * max(0, len(right_split[0]) - len(left_split[0]))) + right_split.insert(1, ["0"] * max(0, len(left_split[0]) - len(right_split[0]))) + + return (list(itertools.chain(*left_split)), list(itertools.chain(*right_split))) + + +class SpecifierSet(BaseSpecifier): + def __init__(self, specifiers="", prereleases=None): + # Split on , to break each indidivual specifier into it's own item, and + # strip each item to remove leading/trailing whitespace. + specifiers = [s.strip() for s in specifiers.split(",") if s.strip()] + + # Parsed each individual specifier, attempting first to make it a + # Specifier and falling back to a LegacySpecifier. + parsed = set() + for specifier in specifiers: + try: + parsed.add(Specifier(specifier)) + except InvalidSpecifier: + parsed.add(LegacySpecifier(specifier)) + + # Turn our parsed specifiers into a frozen set and save them for later. + self._specs = frozenset(parsed) + + # Store our prereleases value so we can use it later to determine if + # we accept prereleases or not. + self._prereleases = prereleases + + def __repr__(self): + pre = ( + ", prereleases={0!r}".format(self.prereleases) + if self._prereleases is not None + else "" + ) + + return "<SpecifierSet({0!r}{1})>".format(str(self), pre) + + def __str__(self): + return ",".join(sorted(str(s) for s in self._specs)) + + def __hash__(self): + return hash(self._specs) + + def __and__(self, other): + if isinstance(other, string_types): + other = SpecifierSet(other) + elif not isinstance(other, SpecifierSet): + return NotImplemented + + specifier = SpecifierSet() + specifier._specs = frozenset(self._specs | other._specs) + + if self._prereleases is None and other._prereleases is not None: + specifier._prereleases = other._prereleases + elif self._prereleases is not None and other._prereleases is None: + specifier._prereleases = self._prereleases + elif self._prereleases == other._prereleases: + specifier._prereleases = self._prereleases + else: + raise ValueError( + "Cannot combine SpecifierSets with True and False prerelease " + "overrides." + ) + + return specifier + + def __eq__(self, other): + if isinstance(other, string_types): + other = SpecifierSet(other) + elif isinstance(other, _IndividualSpecifier): + other = SpecifierSet(str(other)) + elif not isinstance(other, SpecifierSet): + return NotImplemented + + return self._specs == other._specs + + def __ne__(self, other): + if isinstance(other, string_types): + other = SpecifierSet(other) + elif isinstance(other, _IndividualSpecifier): + other = SpecifierSet(str(other)) + elif not isinstance(other, SpecifierSet): + return NotImplemented + + return self._specs != other._specs + + def __len__(self): + return len(self._specs) + + def __iter__(self): + return iter(self._specs) + + @property + def prereleases(self): + # If we have been given an explicit prerelease modifier, then we'll + # pass that through here. + if self._prereleases is not None: + return self._prereleases + + # If we don't have any specifiers, and we don't have a forced value, + # then we'll just return None since we don't know if this should have + # pre-releases or not. + if not self._specs: + return None + + # Otherwise we'll see if any of the given specifiers accept + # prereleases, if any of them do we'll return True, otherwise False. + return any(s.prereleases for s in self._specs) + + @prereleases.setter + def prereleases(self, value): + self._prereleases = value + + def __contains__(self, item): + return self.contains(item) + + def contains(self, item, prereleases=None): + # Ensure that our item is a Version or LegacyVersion instance. + if not isinstance(item, (LegacyVersion, Version)): + item = parse(item) + + # Determine if we're forcing a prerelease or not, if we're not forcing + # one for this particular filter call, then we'll use whatever the + # SpecifierSet thinks for whether or not we should support prereleases. + if prereleases is None: + prereleases = self.prereleases + + # We can determine if we're going to allow pre-releases by looking to + # see if any of the underlying items supports them. If none of them do + # and this item is a pre-release then we do not allow it and we can + # short circuit that here. + # Note: This means that 1.0.dev1 would not be contained in something + # like >=1.0.devabc however it would be in >=1.0.debabc,>0.0.dev0 + if not prereleases and item.is_prerelease: + return False + + # We simply dispatch to the underlying specs here to make sure that the + # given version is contained within all of them. + # Note: This use of all() here means that an empty set of specifiers + # will always return True, this is an explicit design decision. + return all(s.contains(item, prereleases=prereleases) for s in self._specs) + + def filter(self, iterable, prereleases=None): + # Determine if we're forcing a prerelease or not, if we're not forcing + # one for this particular filter call, then we'll use whatever the + # SpecifierSet thinks for whether or not we should support prereleases. + if prereleases is None: + prereleases = self.prereleases + + # If we have any specifiers, then we want to wrap our iterable in the + # filter method for each one, this will act as a logical AND amongst + # each specifier. + if self._specs: + for spec in self._specs: + iterable = spec.filter(iterable, prereleases=bool(prereleases)) + return iterable + # If we do not have any specifiers, then we need to have a rough filter + # which will filter out any pre-releases, unless there are no final + # releases, and which will filter out LegacyVersion in general. + else: + filtered = [] + found_prereleases = [] + + for item in iterable: + # Ensure that we some kind of Version class for this item. + if not isinstance(item, (LegacyVersion, Version)): + parsed_version = parse(item) + else: + parsed_version = item + + # Filter out any item which is parsed as a LegacyVersion + if isinstance(parsed_version, LegacyVersion): + continue + + # Store any item which is a pre-release for later unless we've + # already found a final version or we are accepting prereleases + if parsed_version.is_prerelease and not prereleases: + if not filtered: + found_prereleases.append(item) + else: + filtered.append(item) + + # If we've found no items except for pre-releases, then we'll go + # ahead and use the pre-releases + if not filtered and found_prereleases and prereleases is None: + return found_prereleases + + return filtered diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/tags.py b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/tags.py new file mode 100644 index 0000000..ec9942f --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/tags.py @@ -0,0 +1,404 @@ +# 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 __future__ import absolute_import + +import distutils.util + +try: + from importlib.machinery import EXTENSION_SUFFIXES +except ImportError: # pragma: no cover + import imp + + EXTENSION_SUFFIXES = [x[0] for x in imp.get_suffixes()] + del imp +import platform +import re +import sys +import sysconfig +import warnings + + +INTERPRETER_SHORT_NAMES = { + "python": "py", # Generic. + "cpython": "cp", + "pypy": "pp", + "ironpython": "ip", + "jython": "jy", +} + + +_32_BIT_INTERPRETER = sys.maxsize <= 2 ** 32 + + +class Tag(object): + + __slots__ = ["_interpreter", "_abi", "_platform"] + + def __init__(self, interpreter, abi, platform): + self._interpreter = interpreter.lower() + self._abi = abi.lower() + self._platform = platform.lower() + + @property + def interpreter(self): + return self._interpreter + + @property + def abi(self): + return self._abi + + @property + def platform(self): + return self._platform + + def __eq__(self, other): + return ( + (self.platform == other.platform) + and (self.abi == other.abi) + and (self.interpreter == other.interpreter) + ) + + def __hash__(self): + return hash((self._interpreter, self._abi, self._platform)) + + def __str__(self): + return "{}-{}-{}".format(self._interpreter, self._abi, self._platform) + + def __repr__(self): + return "<{self} @ {self_id}>".format(self=self, self_id=id(self)) + + +def parse_tag(tag): + tags = set() + interpreters, abis, platforms = tag.split("-") + for interpreter in interpreters.split("."): + for abi in abis.split("."): + for platform_ in platforms.split("."): + tags.add(Tag(interpreter, abi, platform_)) + return frozenset(tags) + + +def _normalize_string(string): + return string.replace(".", "_").replace("-", "_") + + +def _cpython_interpreter(py_version): + # TODO: Is using py_version_nodot for interpreter version critical? + return "cp{major}{minor}".format(major=py_version[0], minor=py_version[1]) + + +def _cpython_abis(py_version): + abis = [] + version = "{}{}".format(*py_version[:2]) + debug = pymalloc = ucs4 = "" + with_debug = sysconfig.get_config_var("Py_DEBUG") + has_refcount = hasattr(sys, "gettotalrefcount") + # Windows doesn't set Py_DEBUG, so checking for support of debug-compiled + # extension modules is the best option. + # https://github.com/pypa/pip/issues/3383#issuecomment-173267692 + has_ext = "_d.pyd" in EXTENSION_SUFFIXES + if with_debug or (with_debug is None and (has_refcount or has_ext)): + debug = "d" + if py_version < (3, 8): + with_pymalloc = sysconfig.get_config_var("WITH_PYMALLOC") + if with_pymalloc or with_pymalloc is None: + pymalloc = "m" + if py_version < (3, 3): + unicode_size = sysconfig.get_config_var("Py_UNICODE_SIZE") + if unicode_size == 4 or ( + unicode_size is None and sys.maxunicode == 0x10FFFF + ): + ucs4 = "u" + elif debug: + # Debug builds can also load "normal" extension modules. + # We can also assume no UCS-4 or pymalloc requirement. + abis.append("cp{version}".format(version=version)) + abis.insert( + 0, + "cp{version}{debug}{pymalloc}{ucs4}".format( + version=version, debug=debug, pymalloc=pymalloc, ucs4=ucs4 + ), + ) + return abis + + +def _cpython_tags(py_version, interpreter, abis, platforms): + for abi in abis: + for platform_ in platforms: + yield Tag(interpreter, abi, platform_) + for tag in (Tag(interpreter, "abi3", platform_) for platform_ in platforms): + yield tag + for tag in (Tag(interpreter, "none", platform_) for platform_ in platforms): + yield tag + # PEP 384 was first implemented in Python 3.2. + for minor_version in range(py_version[1] - 1, 1, -1): + for platform_ in platforms: + interpreter = "cp{major}{minor}".format( + major=py_version[0], minor=minor_version + ) + yield Tag(interpreter, "abi3", platform_) + + +def _pypy_interpreter(): + return "pp{py_major}{pypy_major}{pypy_minor}".format( + py_major=sys.version_info[0], + pypy_major=sys.pypy_version_info.major, + pypy_minor=sys.pypy_version_info.minor, + ) + + +def _generic_abi(): + abi = sysconfig.get_config_var("SOABI") + if abi: + return _normalize_string(abi) + else: + return "none" + + +def _pypy_tags(py_version, interpreter, abi, platforms): + for tag in (Tag(interpreter, abi, platform) for platform in platforms): + yield tag + for tag in (Tag(interpreter, "none", platform) for platform in platforms): + yield tag + + +def _generic_tags(interpreter, py_version, abi, platforms): + for tag in (Tag(interpreter, abi, platform) for platform in platforms): + yield tag + if abi != "none": + tags = (Tag(interpreter, "none", platform_) for platform_ in platforms) + for tag in tags: + yield tag + + +def _py_interpreter_range(py_version): + """ + Yield Python versions in descending order. + + After the latest version, the major-only version will be yielded, and then + all following versions up to 'end'. + """ + yield "py{major}{minor}".format(major=py_version[0], minor=py_version[1]) + yield "py{major}".format(major=py_version[0]) + for minor in range(py_version[1] - 1, -1, -1): + yield "py{major}{minor}".format(major=py_version[0], minor=minor) + + +def _independent_tags(interpreter, py_version, platforms): + """ + Return the sequence of tags that are consistent across implementations. + + The tags consist of: + - py*-none-<platform> + - <interpreter>-none-any + - py*-none-any + """ + for version in _py_interpreter_range(py_version): + for platform_ in platforms: + yield Tag(version, "none", platform_) + yield Tag(interpreter, "none", "any") + for version in _py_interpreter_range(py_version): + yield Tag(version, "none", "any") + + +def _mac_arch(arch, is_32bit=_32_BIT_INTERPRETER): + if not is_32bit: + return arch + + if arch.startswith("ppc"): + return "ppc" + + return "i386" + + +def _mac_binary_formats(version, cpu_arch): + formats = [cpu_arch] + if cpu_arch == "x86_64": + if version < (10, 4): + return [] + formats.extend(["intel", "fat64", "fat32"]) + + elif cpu_arch == "i386": + if version < (10, 4): + return [] + formats.extend(["intel", "fat32", "fat"]) + + elif cpu_arch == "ppc64": + # TODO: Need to care about 32-bit PPC for ppc64 through 10.2? + if version > (10, 5) or version < (10, 4): + return [] + formats.append("fat64") + + elif cpu_arch == "ppc": + if version > (10, 6): + return [] + formats.extend(["fat32", "fat"]) + + formats.append("universal") + return formats + + +def _mac_platforms(version=None, arch=None): + version_str, _, cpu_arch = platform.mac_ver() + if version is None: + version = tuple(map(int, version_str.split(".")[:2])) + if arch is None: + arch = _mac_arch(cpu_arch) + platforms = [] + for minor_version in range(version[1], -1, -1): + compat_version = version[0], minor_version + binary_formats = _mac_binary_formats(compat_version, arch) + for binary_format in binary_formats: + platforms.append( + "macosx_{major}_{minor}_{binary_format}".format( + major=compat_version[0], + minor=compat_version[1], + binary_format=binary_format, + ) + ) + return platforms + + +# From PEP 513. +def _is_manylinux_compatible(name, glibc_version): + # Check for presence of _manylinux module. + try: + import _manylinux + + return bool(getattr(_manylinux, name + "_compatible")) + except (ImportError, AttributeError): + # Fall through to heuristic check below. + pass + + return _have_compatible_glibc(*glibc_version) + + +def _glibc_version_string(): + # Returns glibc version string, or None if not using glibc. + import ctypes + + # ctypes.CDLL(None) internally calls dlopen(NULL), and as the dlopen + # manpage says, "If filename is NULL, then the returned handle is for the + # main program". This way we can let the linker do the work to figure out + # which libc our process is actually using. + process_namespace = ctypes.CDLL(None) + try: + gnu_get_libc_version = process_namespace.gnu_get_libc_version + except AttributeError: + # Symbol doesn't exist -> therefore, we are not linked to + # glibc. + return None + + # Call gnu_get_libc_version, which returns a string like "2.5" + gnu_get_libc_version.restype = ctypes.c_char_p + version_str = gnu_get_libc_version() + # py2 / py3 compatibility: + if not isinstance(version_str, str): + version_str = version_str.decode("ascii") + + return version_str + + +# Separated out from have_compatible_glibc for easier unit testing. +def _check_glibc_version(version_str, required_major, minimum_minor): + # Parse string and check against requested version. + # + # We use a regexp instead of str.split because we want to discard any + # random junk that might come after the minor version -- this might happen + # in patched/forked versions of glibc (e.g. Linaro's version of glibc + # uses version strings like "2.20-2014.11"). See gh-3588. + m = re.match(r"(?P<major>[0-9]+)\.(?P<minor>[0-9]+)", version_str) + if not m: + warnings.warn( + "Expected glibc version with 2 components major.minor," + " got: %s" % version_str, + RuntimeWarning, + ) + return False + return ( + int(m.group("major")) == required_major + and int(m.group("minor")) >= minimum_minor + ) + + +def _have_compatible_glibc(required_major, minimum_minor): + version_str = _glibc_version_string() + if version_str is None: + return False + return _check_glibc_version(version_str, required_major, minimum_minor) + + +def _linux_platforms(is_32bit=_32_BIT_INTERPRETER): + linux = _normalize_string(distutils.util.get_platform()) + if linux == "linux_x86_64" and is_32bit: + linux = "linux_i686" + manylinux_support = ( + ("manylinux2014", (2, 17)), # CentOS 7 w/ glibc 2.17 (PEP 599) + ("manylinux2010", (2, 12)), # CentOS 6 w/ glibc 2.12 (PEP 571) + ("manylinux1", (2, 5)), # CentOS 5 w/ glibc 2.5 (PEP 513) + ) + manylinux_support_iter = iter(manylinux_support) + for name, glibc_version in manylinux_support_iter: + if _is_manylinux_compatible(name, glibc_version): + platforms = [linux.replace("linux", name)] + break + else: + platforms = [] + # Support for a later manylinux implies support for an earlier version. + platforms += [linux.replace("linux", name) for name, _ in manylinux_support_iter] + platforms.append(linux) + return platforms + + +def _generic_platforms(): + platform = _normalize_string(distutils.util.get_platform()) + return [platform] + + +def _interpreter_name(): + name = platform.python_implementation().lower() + return INTERPRETER_SHORT_NAMES.get(name) or name + + +def _generic_interpreter(name, py_version): + version = sysconfig.get_config_var("py_version_nodot") + if not version: + version = "".join(map(str, py_version[:2])) + return "{name}{version}".format(name=name, version=version) + + +def sys_tags(): + """ + Returns the sequence of tag triples for the running interpreter. + + The order of the sequence corresponds to priority order for the + interpreter, from most to least important. + """ + py_version = sys.version_info[:2] + interpreter_name = _interpreter_name() + if platform.system() == "Darwin": + platforms = _mac_platforms() + elif platform.system() == "Linux": + platforms = _linux_platforms() + else: + platforms = _generic_platforms() + + if interpreter_name == "cp": + interpreter = _cpython_interpreter(py_version) + abis = _cpython_abis(py_version) + for tag in _cpython_tags(py_version, interpreter, abis, platforms): + yield tag + elif interpreter_name == "pp": + interpreter = _pypy_interpreter() + abi = _generic_abi() + for tag in _pypy_tags(py_version, interpreter, abi, platforms): + yield tag + else: + interpreter = _generic_interpreter(interpreter_name, py_version) + abi = _generic_abi() + for tag in _generic_tags(interpreter, py_version, abi, platforms): + yield tag + for tag in _independent_tags(interpreter, py_version, platforms): + yield tag diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/utils.py b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/utils.py new file mode 100644 index 0000000..8841878 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/utils.py @@ -0,0 +1,57 @@ +# 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 __future__ import absolute_import, division, print_function + +import re + +from .version import InvalidVersion, Version + + +_canonicalize_regex = re.compile(r"[-_.]+") + + +def canonicalize_name(name): + # This is taken from PEP 503. + return _canonicalize_regex.sub("-", name).lower() + + +def canonicalize_version(version): + """ + This is very similar to Version.__str__, but has one subtle differences + with the way it handles the release segment. + """ + + try: + version = Version(version) + except InvalidVersion: + # Legacy versions cannot be normalized + return version + + parts = [] + + # Epoch + if version.epoch != 0: + parts.append("{0}!".format(version.epoch)) + + # Release segment + # NB: This strips trailing '.0's to normalize + parts.append(re.sub(r"(\.0)+$", "", ".".join(str(x) for x in version.release))) + + # Pre-release + if version.pre is not None: + parts.append("".join(str(x) for x in version.pre)) + + # Post-release + if version.post is not None: + parts.append(".post{0}".format(version.post)) + + # Development release + if version.dev is not None: + parts.append(".dev{0}".format(version.dev)) + + # Local version segment + if version.local is not None: + parts.append("+{0}".format(version.local)) + + return "".join(parts) diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/version.py b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/version.py new file mode 100644 index 0000000..95157a1 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/version.py @@ -0,0 +1,420 @@ +# 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 __future__ import absolute_import, division, print_function + +import collections +import itertools +import re + +from ._structures import Infinity + + +__all__ = ["parse", "Version", "LegacyVersion", "InvalidVersion", "VERSION_PATTERN"] + + +_Version = collections.namedtuple( + "_Version", ["epoch", "release", "dev", "pre", "post", "local"] +) + + +def parse(version): + """ + Parse the given version string and return either a :class:`Version` object + or a :class:`LegacyVersion` object depending on if the given version is + a valid PEP 440 version or a legacy version. + """ + try: + return Version(version) + except InvalidVersion: + return LegacyVersion(version) + + +class InvalidVersion(ValueError): + """ + An invalid version was found, users should refer to PEP 440. + """ + + +class _BaseVersion(object): + def __hash__(self): + return hash(self._key) + + def __lt__(self, other): + return self._compare(other, lambda s, o: s < o) + + def __le__(self, other): + return self._compare(other, lambda s, o: s <= o) + + def __eq__(self, other): + return self._compare(other, lambda s, o: s == o) + + def __ge__(self, other): + return self._compare(other, lambda s, o: s >= o) + + def __gt__(self, other): + return self._compare(other, lambda s, o: s > o) + + def __ne__(self, other): + return self._compare(other, lambda s, o: s != o) + + def _compare(self, other, method): + if not isinstance(other, _BaseVersion): + return NotImplemented + + return method(self._key, other._key) + + +class LegacyVersion(_BaseVersion): + def __init__(self, version): + self._version = str(version) + self._key = _legacy_cmpkey(self._version) + + def __str__(self): + return self._version + + def __repr__(self): + return "<LegacyVersion({0})>".format(repr(str(self))) + + @property + def public(self): + return self._version + + @property + def base_version(self): + return self._version + + @property + def epoch(self): + return -1 + + @property + def release(self): + return None + + @property + def pre(self): + return None + + @property + def post(self): + return None + + @property + def dev(self): + return None + + @property + def local(self): + return None + + @property + def is_prerelease(self): + return False + + @property + def is_postrelease(self): + return False + + @property + def is_devrelease(self): + return False + + +_legacy_version_component_re = re.compile(r"(\d+ | [a-z]+ | \.| -)", re.VERBOSE) + +_legacy_version_replacement_map = { + "pre": "c", + "preview": "c", + "-": "final-", + "rc": "c", + "dev": "@", +} + + +def _parse_version_parts(s): + for part in _legacy_version_component_re.split(s): + part = _legacy_version_replacement_map.get(part, part) + + if not part or part == ".": + continue + + if part[:1] in "0123456789": + # pad for numeric comparison + yield part.zfill(8) + else: + yield "*" + part + + # ensure that alpha/beta/candidate are before final + yield "*final" + + +def _legacy_cmpkey(version): + # We hardcode an epoch of -1 here. A PEP 440 version can only have a epoch + # greater than or equal to 0. This will effectively put the LegacyVersion, + # which uses the defacto standard originally implemented by setuptools, + # as before all PEP 440 versions. + epoch = -1 + + # This scheme is taken from pkg_resources.parse_version setuptools prior to + # it's adoption of the packaging library. + parts = [] + for part in _parse_version_parts(version.lower()): + if part.startswith("*"): + # remove "-" before a prerelease tag + if part < "*final": + while parts and parts[-1] == "*final-": + parts.pop() + + # remove trailing zeros from each series of numeric parts + while parts and parts[-1] == "00000000": + parts.pop() + + parts.append(part) + parts = tuple(parts) + + return epoch, parts + + +# Deliberately not anchored to the start and end of the string, to make it +# easier for 3rd party code to reuse +VERSION_PATTERN = r""" + v? + (?: + (?:(?P<epoch>[0-9]+)!)? # epoch + (?P<release>[0-9]+(?:\.[0-9]+)*) # release segment + (?P<pre> # pre-release + [-_\.]? + (?P<pre_l>(a|b|c|rc|alpha|beta|pre|preview)) + [-_\.]? + (?P<pre_n>[0-9]+)? + )? + (?P<post> # post release + (?:-(?P<post_n1>[0-9]+)) + | + (?: + [-_\.]? + (?P<post_l>post|rev|r) + [-_\.]? + (?P<post_n2>[0-9]+)? + ) + )? + (?P<dev> # dev release + [-_\.]? + (?P<dev_l>dev) + [-_\.]? + (?P<dev_n>[0-9]+)? + )? + ) + (?:\+(?P<local>[a-z0-9]+(?:[-_\.][a-z0-9]+)*))? # local version +""" + + +class Version(_BaseVersion): + + _regex = re.compile(r"^\s*" + VERSION_PATTERN + r"\s*$", re.VERBOSE | re.IGNORECASE) + + def __init__(self, version): + # Validate the version and parse it into pieces + match = self._regex.search(version) + if not match: + raise InvalidVersion("Invalid version: '{0}'".format(version)) + + # Store the parsed out pieces of the version + self._version = _Version( + epoch=int(match.group("epoch")) if match.group("epoch") else 0, + release=tuple(int(i) for i in match.group("release").split(".")), + pre=_parse_letter_version(match.group("pre_l"), match.group("pre_n")), + post=_parse_letter_version( + match.group("post_l"), match.group("post_n1") or match.group("post_n2") + ), + dev=_parse_letter_version(match.group("dev_l"), match.group("dev_n")), + local=_parse_local_version(match.group("local")), + ) + + # Generate a key which will be used for sorting + self._key = _cmpkey( + self._version.epoch, + self._version.release, + self._version.pre, + self._version.post, + self._version.dev, + self._version.local, + ) + + def __repr__(self): + return "<Version({0})>".format(repr(str(self))) + + def __str__(self): + parts = [] + + # Epoch + if self.epoch != 0: + parts.append("{0}!".format(self.epoch)) + + # Release segment + parts.append(".".join(str(x) for x in self.release)) + + # Pre-release + if self.pre is not None: + parts.append("".join(str(x) for x in self.pre)) + + # Post-release + if self.post is not None: + parts.append(".post{0}".format(self.post)) + + # Development release + if self.dev is not None: + parts.append(".dev{0}".format(self.dev)) + + # Local version segment + if self.local is not None: + parts.append("+{0}".format(self.local)) + + return "".join(parts) + + @property + def epoch(self): + return self._version.epoch + + @property + def release(self): + return self._version.release + + @property + def pre(self): + return self._version.pre + + @property + def post(self): + return self._version.post[1] if self._version.post else None + + @property + def dev(self): + return self._version.dev[1] if self._version.dev else None + + @property + def local(self): + if self._version.local: + return ".".join(str(x) for x in self._version.local) + else: + return None + + @property + def public(self): + return str(self).split("+", 1)[0] + + @property + def base_version(self): + parts = [] + + # Epoch + if self.epoch != 0: + parts.append("{0}!".format(self.epoch)) + + # Release segment + parts.append(".".join(str(x) for x in self.release)) + + return "".join(parts) + + @property + def is_prerelease(self): + return self.dev is not None or self.pre is not None + + @property + def is_postrelease(self): + return self.post is not None + + @property + def is_devrelease(self): + return self.dev is not None + + +def _parse_letter_version(letter, number): + if letter: + # We consider there to be an implicit 0 in a pre-release if there is + # not a numeral associated with it. + if number is None: + number = 0 + + # We normalize any letters to their lower case form + letter = letter.lower() + + # We consider some words to be alternate spellings of other words and + # in those cases we want to normalize the spellings to our preferred + # spelling. + if letter == "alpha": + letter = "a" + elif letter == "beta": + letter = "b" + elif letter in ["c", "pre", "preview"]: + letter = "rc" + elif letter in ["rev", "r"]: + letter = "post" + + return letter, int(number) + if not letter and number: + # We assume if we are given a number, but we are not given a letter + # then this is using the implicit post release syntax (e.g. 1.0-1) + letter = "post" + + return letter, int(number) + + +_local_version_separators = re.compile(r"[\._-]") + + +def _parse_local_version(local): + """ + Takes a string like abc.1.twelve and turns it into ("abc", 1, "twelve"). + """ + if local is not None: + return tuple( + part.lower() if not part.isdigit() else int(part) + for part in _local_version_separators.split(local) + ) + + +def _cmpkey(epoch, release, pre, post, dev, local): + # When we compare a release version, we want to compare it with all of the + # trailing zeros removed. So we'll use a reverse the list, drop all the now + # leading zeros until we come to something non zero, then take the rest + # re-reverse it back into the correct order and make it a tuple and use + # that for our sorting key. + release = tuple( + reversed(list(itertools.dropwhile(lambda x: x == 0, reversed(release)))) + ) + + # We need to "trick" the sorting algorithm to put 1.0.dev0 before 1.0a0. + # We'll do this by abusing the pre segment, but we _only_ want to do this + # if there is not a pre or a post segment. If we have one of those then + # the normal sorting rules will handle this case correctly. + if pre is None and post is None and dev is not None: + pre = -Infinity + # Versions without a pre-release (except as noted above) should sort after + # those with one. + elif pre is None: + pre = Infinity + + # Versions without a post segment should sort before those with one. + if post is None: + post = -Infinity + + # Versions without a development segment should sort after those with one. + if dev is None: + dev = Infinity + + if local is None: + # Versions without a local segment should sort before those with one. + local = -Infinity + else: + # Versions with a local segment need that segment parsed to implement + # the sorting rules in PEP440. + # - Alpha numeric segments sort before numeric segments + # - Alpha numeric segments sort lexicographically + # - Numeric segments sort numerically + # - Shorter versions sort before longer versions when the prefixes + # match exactly + local = tuple((i, "") if isinstance(i, int) else (-Infinity, i) for i in local) + + return epoch, release, pre, post, dev, local diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/pyparsing.py b/venv/lib/python3.8/site-packages/setuptools/_vendor/pyparsing.py new file mode 100644 index 0000000..cf75e1e --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/_vendor/pyparsing.py @@ -0,0 +1,5742 @@ +# module pyparsing.py +# +# Copyright (c) 2003-2018 Paul T. McGuire +# +# 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. +# + +__doc__ = \ +""" +pyparsing module - Classes and methods to define and execute parsing grammars +============================================================================= + +The pyparsing module is an alternative approach to creating and executing simple grammars, +vs. the traditional lex/yacc approach, or the use of regular expressions. With pyparsing, you +don't need to learn a new syntax for defining grammars or matching expressions - the parsing module +provides a library of classes that you use to construct the grammar directly in Python. + +Here is a program to parse "Hello, World!" (or any greeting of the form +C{"<salutation>, <addressee>!"}), built up using L{Word}, L{Literal}, and L{And} elements +(L{'+'<ParserElement.__add__>} operator gives L{And} expressions, strings are auto-converted to +L{Literal} expressions):: + + from pyparsing import Word, alphas + + # define grammar of a greeting + greet = Word(alphas) + "," + Word(alphas) + "!" + + hello = "Hello, World!" + print (hello, "->", greet.parseString(hello)) + +The program outputs the following:: + + Hello, World! -> ['Hello', ',', 'World', '!'] + +The Python representation of the grammar is quite readable, owing to the self-explanatory +class names, and the use of '+', '|' and '^' operators. + +The L{ParseResults} object returned from L{ParserElement.parseString<ParserElement.parseString>} can be accessed as a nested list, a dictionary, or an +object with named attributes. + +The pyparsing module handles some of the problems that are typically vexing when writing text parsers: + - extra or missing whitespace (the above program will also handle "Hello,World!", "Hello , World !", etc.) + - quoted strings + - embedded comments + + +Getting Started - +----------------- +Visit the classes L{ParserElement} and L{ParseResults} to see the base classes that most other pyparsing +classes inherit from. Use the docstrings for examples of how to: + - construct literal match expressions from L{Literal} and L{CaselessLiteral} classes + - construct character word-group expressions using the L{Word} class + - see how to create repetitive expressions using L{ZeroOrMore} and L{OneOrMore} classes + - use L{'+'<And>}, L{'|'<MatchFirst>}, L{'^'<Or>}, and L{'&'<Each>} operators to combine simple expressions into more complex ones + - associate names with your parsed results using L{ParserElement.setResultsName} + - find some helpful expression short-cuts like L{delimitedList} and L{oneOf} + - find more useful common expressions in the L{pyparsing_common} namespace class +""" + +__version__ = "2.2.1" +__versionTime__ = "18 Sep 2018 00:49 UTC" +__author__ = "Paul McGuire <ptmcg@users.sourceforge.net>" + +import string +from weakref import ref as wkref +import copy +import sys +import warnings +import re +import sre_constants +import collections +import pprint +import traceback +import types +from datetime import datetime + +try: + from _thread import RLock +except ImportError: + from threading import RLock + +try: + # Python 3 + from collections.abc import Iterable + from collections.abc import MutableMapping +except ImportError: + # Python 2.7 + from collections import Iterable + from collections import MutableMapping + +try: + from collections import OrderedDict as _OrderedDict +except ImportError: + try: + from ordereddict import OrderedDict as _OrderedDict + except ImportError: + _OrderedDict = None + +#~ sys.stderr.write( "testing pyparsing module, version %s, %s\n" % (__version__,__versionTime__ ) ) + +__all__ = [ +'And', 'CaselessKeyword', 'CaselessLiteral', 'CharsNotIn', 'Combine', 'Dict', 'Each', 'Empty', +'FollowedBy', 'Forward', 'GoToColumn', 'Group', 'Keyword', 'LineEnd', 'LineStart', 'Literal', +'MatchFirst', 'NoMatch', 'NotAny', 'OneOrMore', 'OnlyOnce', 'Optional', 'Or', +'ParseBaseException', 'ParseElementEnhance', 'ParseException', 'ParseExpression', 'ParseFatalException', +'ParseResults', 'ParseSyntaxException', 'ParserElement', 'QuotedString', 'RecursiveGrammarException', +'Regex', 'SkipTo', 'StringEnd', 'StringStart', 'Suppress', 'Token', 'TokenConverter', +'White', 'Word', 'WordEnd', 'WordStart', 'ZeroOrMore', +'alphanums', 'alphas', 'alphas8bit', 'anyCloseTag', 'anyOpenTag', 'cStyleComment', 'col', +'commaSeparatedList', 'commonHTMLEntity', 'countedArray', 'cppStyleComment', 'dblQuotedString', +'dblSlashComment', 'delimitedList', 'dictOf', 'downcaseTokens', 'empty', 'hexnums', +'htmlComment', 'javaStyleComment', 'line', 'lineEnd', 'lineStart', 'lineno', +'makeHTMLTags', 'makeXMLTags', 'matchOnlyAtCol', 'matchPreviousExpr', 'matchPreviousLiteral', +'nestedExpr', 'nullDebugAction', 'nums', 'oneOf', 'opAssoc', 'operatorPrecedence', 'printables', +'punc8bit', 'pythonStyleComment', 'quotedString', 'removeQuotes', 'replaceHTMLEntity', +'replaceWith', 'restOfLine', 'sglQuotedString', 'srange', 'stringEnd', +'stringStart', 'traceParseAction', 'unicodeString', 'upcaseTokens', 'withAttribute', +'indentedBlock', 'originalTextFor', 'ungroup', 'infixNotation','locatedExpr', 'withClass', +'CloseMatch', 'tokenMap', 'pyparsing_common', +] + +system_version = tuple(sys.version_info)[:3] +PY_3 = system_version[0] == 3 +if PY_3: + _MAX_INT = sys.maxsize + basestring = str + unichr = chr + _ustr = str + + # build list of single arg builtins, that can be used as parse actions + singleArgBuiltins = [sum, len, sorted, reversed, list, tuple, set, any, all, min, max] + +else: + _MAX_INT = sys.maxint + range = xrange + + def _ustr(obj): + """Drop-in replacement for str(obj) that tries to be Unicode friendly. It first tries + str(obj). If that fails with a UnicodeEncodeError, then it tries unicode(obj). It + then < returns the unicode object | encodes it with the default encoding | ... >. + """ + if isinstance(obj,unicode): + return obj + + try: + # If this works, then _ustr(obj) has the same behaviour as str(obj), so + # it won't break any existing code. + return str(obj) + + except UnicodeEncodeError: + # Else encode it + ret = unicode(obj).encode(sys.getdefaultencoding(), 'xmlcharrefreplace') + xmlcharref = Regex(r'&#\d+;') + xmlcharref.setParseAction(lambda t: '\\u' + hex(int(t[0][2:-1]))[2:]) + return xmlcharref.transformString(ret) + + # build list of single arg builtins, tolerant of Python version, that can be used as parse actions + singleArgBuiltins = [] + import __builtin__ + for fname in "sum len sorted reversed list tuple set any all min max".split(): + try: + singleArgBuiltins.append(getattr(__builtin__,fname)) + except AttributeError: + continue + +_generatorType = type((y for y in range(1))) + +def _xml_escape(data): + """Escape &, <, >, ", ', etc. in a string of data.""" + + # ampersand must be replaced first + from_symbols = '&><"\'' + to_symbols = ('&'+s+';' for s in "amp gt lt quot apos".split()) + for from_,to_ in zip(from_symbols, to_symbols): + data = data.replace(from_, to_) + return data + +class _Constants(object): + pass + +alphas = string.ascii_uppercase + string.ascii_lowercase +nums = "0123456789" +hexnums = nums + "ABCDEFabcdef" +alphanums = alphas + nums +_bslash = chr(92) +printables = "".join(c for c in string.printable if c not in string.whitespace) + +class ParseBaseException(Exception): + """base exception class for all parsing runtime exceptions""" + # Performance tuning: we construct a *lot* of these, so keep this + # constructor as small and fast as possible + def __init__( self, pstr, loc=0, msg=None, elem=None ): + self.loc = loc + if msg is None: + self.msg = pstr + self.pstr = "" + else: + self.msg = msg + self.pstr = pstr + self.parserElement = elem + self.args = (pstr, loc, msg) + + @classmethod + def _from_exception(cls, pe): + """ + internal factory method to simplify creating one type of ParseException + from another - avoids having __init__ signature conflicts among subclasses + """ + return cls(pe.pstr, pe.loc, pe.msg, pe.parserElement) + + def __getattr__( self, aname ): + """supported attributes by name are: + - lineno - returns the line number of the exception text + - col - returns the column number of the exception text + - line - returns the line containing the exception text + """ + if( aname == "lineno" ): + return lineno( self.loc, self.pstr ) + elif( aname in ("col", "column") ): + return col( self.loc, self.pstr ) + elif( aname == "line" ): + return line( self.loc, self.pstr ) + else: + raise AttributeError(aname) + + def __str__( self ): + return "%s (at char %d), (line:%d, col:%d)" % \ + ( self.msg, self.loc, self.lineno, self.column ) + def __repr__( self ): + return _ustr(self) + def markInputline( self, markerString = ">!<" ): + """Extracts the exception line from the input string, and marks + the location of the exception with a special symbol. + """ + line_str = self.line + line_column = self.column - 1 + if markerString: + line_str = "".join((line_str[:line_column], + markerString, line_str[line_column:])) + return line_str.strip() + def __dir__(self): + return "lineno col line".split() + dir(type(self)) + +class ParseException(ParseBaseException): + """ + Exception thrown when parse expressions don't match class; + supported attributes by name are: + - lineno - returns the line number of the exception text + - col - returns the column number of the exception text + - line - returns the line containing the exception text + + Example:: + try: + Word(nums).setName("integer").parseString("ABC") + except ParseException as pe: + print(pe) + print("column: {}".format(pe.col)) + + prints:: + Expected integer (at char 0), (line:1, col:1) + column: 1 + """ + pass + +class ParseFatalException(ParseBaseException): + """user-throwable exception thrown when inconsistent parse content + is found; stops all parsing immediately""" + pass + +class ParseSyntaxException(ParseFatalException): + """just like L{ParseFatalException}, but thrown internally when an + L{ErrorStop<And._ErrorStop>} ('-' operator) indicates that parsing is to stop + immediately because an unbacktrackable syntax error has been found""" + pass + +#~ class ReparseException(ParseBaseException): + #~ """Experimental class - parse actions can raise this exception to cause + #~ pyparsing to reparse the input string: + #~ - with a modified input string, and/or + #~ - with a modified start location + #~ Set the values of the ReparseException in the constructor, and raise the + #~ exception in a parse action to cause pyparsing to use the new string/location. + #~ Setting the values as None causes no change to be made. + #~ """ + #~ def __init_( self, newstring, restartLoc ): + #~ self.newParseText = newstring + #~ self.reparseLoc = restartLoc + +class RecursiveGrammarException(Exception): + """exception thrown by L{ParserElement.validate} if the grammar could be improperly recursive""" + def __init__( self, parseElementList ): + self.parseElementTrace = parseElementList + + def __str__( self ): + return "RecursiveGrammarException: %s" % self.parseElementTrace + +class _ParseResultsWithOffset(object): + def __init__(self,p1,p2): + self.tup = (p1,p2) + def __getitem__(self,i): + return self.tup[i] + def __repr__(self): + return repr(self.tup[0]) + def setOffset(self,i): + self.tup = (self.tup[0],i) + +class ParseResults(object): + """ + Structured parse results, to provide multiple means of access to the parsed data: + - as a list (C{len(results)}) + - by list index (C{results[0], results[1]}, etc.) + - by attribute (C{results.<resultsName>} - see L{ParserElement.setResultsName}) + + Example:: + integer = Word(nums) + date_str = (integer.setResultsName("year") + '/' + + integer.setResultsName("month") + '/' + + integer.setResultsName("day")) + # equivalent form: + # date_str = integer("year") + '/' + integer("month") + '/' + integer("day") + + # parseString returns a ParseResults object + result = date_str.parseString("1999/12/31") + + def test(s, fn=repr): + print("%s -> %s" % (s, fn(eval(s)))) + test("list(result)") + test("result[0]") + test("result['month']") + test("result.day") + test("'month' in result") + test("'minutes' in result") + test("result.dump()", str) + prints:: + list(result) -> ['1999', '/', '12', '/', '31'] + result[0] -> '1999' + result['month'] -> '12' + result.day -> '31' + 'month' in result -> True + 'minutes' in result -> False + result.dump() -> ['1999', '/', '12', '/', '31'] + - day: 31 + - month: 12 + - year: 1999 + """ + def __new__(cls, toklist=None, name=None, asList=True, modal=True ): + if isinstance(toklist, cls): + return toklist + retobj = object.__new__(cls) + retobj.__doinit = True + return retobj + + # Performance tuning: we construct a *lot* of these, so keep this + # constructor as small and fast as possible + def __init__( self, toklist=None, name=None, asList=True, modal=True, isinstance=isinstance ): + if self.__doinit: + self.__doinit = False + self.__name = None + self.__parent = None + self.__accumNames = {} + self.__asList = asList + self.__modal = modal + if toklist is None: + toklist = [] + if isinstance(toklist, list): + self.__toklist = toklist[:] + elif isinstance(toklist, _generatorType): + self.__toklist = list(toklist) + else: + self.__toklist = [toklist] + self.__tokdict = dict() + + if name is not None and name: + if not modal: + self.__accumNames[name] = 0 + if isinstance(name,int): + name = _ustr(name) # will always return a str, but use _ustr for consistency + self.__name = name + if not (isinstance(toklist, (type(None), basestring, list)) and toklist in (None,'',[])): + if isinstance(toklist,basestring): + toklist = [ toklist ] + if asList: + if isinstance(toklist,ParseResults): + self[name] = _ParseResultsWithOffset(toklist.copy(),0) + else: + self[name] = _ParseResultsWithOffset(ParseResults(toklist[0]),0) + self[name].__name = name + else: + try: + self[name] = toklist[0] + except (KeyError,TypeError,IndexError): + self[name] = toklist + + def __getitem__( self, i ): + if isinstance( i, (int,slice) ): + return self.__toklist[i] + else: + if i not in self.__accumNames: + return self.__tokdict[i][-1][0] + else: + return ParseResults([ v[0] for v in self.__tokdict[i] ]) + + def __setitem__( self, k, v, isinstance=isinstance ): + if isinstance(v,_ParseResultsWithOffset): + self.__tokdict[k] = self.__tokdict.get(k,list()) + [v] + sub = v[0] + elif isinstance(k,(int,slice)): + self.__toklist[k] = v + sub = v + else: + self.__tokdict[k] = self.__tokdict.get(k,list()) + [_ParseResultsWithOffset(v,0)] + sub = v + if isinstance(sub,ParseResults): + sub.__parent = wkref(self) + + def __delitem__( self, i ): + if isinstance(i,(int,slice)): + mylen = len( self.__toklist ) + del self.__toklist[i] + + # convert int to slice + if isinstance(i, int): + if i < 0: + i += mylen + i = slice(i, i+1) + # get removed indices + removed = list(range(*i.indices(mylen))) + removed.reverse() + # fixup indices in token dictionary + for name,occurrences in self.__tokdict.items(): + for j in removed: + for k, (value, position) in enumerate(occurrences): + occurrences[k] = _ParseResultsWithOffset(value, position - (position > j)) + else: + del self.__tokdict[i] + + def __contains__( self, k ): + return k in self.__tokdict + + def __len__( self ): return len( self.__toklist ) + def __bool__(self): return ( not not self.__toklist ) + __nonzero__ = __bool__ + def __iter__( self ): return iter( self.__toklist ) + def __reversed__( self ): return iter( self.__toklist[::-1] ) + def _iterkeys( self ): + if hasattr(self.__tokdict, "iterkeys"): + return self.__tokdict.iterkeys() + else: + return iter(self.__tokdict) + + def _itervalues( self ): + return (self[k] for k in self._iterkeys()) + + def _iteritems( self ): + return ((k, self[k]) for k in self._iterkeys()) + + if PY_3: + keys = _iterkeys + """Returns an iterator of all named result keys (Python 3.x only).""" + + values = _itervalues + """Returns an iterator of all named result values (Python 3.x only).""" + + items = _iteritems + """Returns an iterator of all named result key-value tuples (Python 3.x only).""" + + else: + iterkeys = _iterkeys + """Returns an iterator of all named result keys (Python 2.x only).""" + + itervalues = _itervalues + """Returns an iterator of all named result values (Python 2.x only).""" + + iteritems = _iteritems + """Returns an iterator of all named result key-value tuples (Python 2.x only).""" + + def keys( self ): + """Returns all named result keys (as a list in Python 2.x, as an iterator in Python 3.x).""" + return list(self.iterkeys()) + + def values( self ): + """Returns all named result values (as a list in Python 2.x, as an iterator in Python 3.x).""" + return list(self.itervalues()) + + def items( self ): + """Returns all named result key-values (as a list of tuples in Python 2.x, as an iterator in Python 3.x).""" + return list(self.iteritems()) + + def haskeys( self ): + """Since keys() returns an iterator, this method is helpful in bypassing + code that looks for the existence of any defined results names.""" + return bool(self.__tokdict) + + def pop( self, *args, **kwargs): + """ + Removes and returns item at specified index (default=C{last}). + Supports both C{list} and C{dict} semantics for C{pop()}. If passed no + argument or an integer argument, it will use C{list} semantics + and pop tokens from the list of parsed tokens. If passed a + non-integer argument (most likely a string), it will use C{dict} + semantics and pop the corresponding value from any defined + results names. A second default return value argument is + supported, just as in C{dict.pop()}. + + Example:: + def remove_first(tokens): + tokens.pop(0) + print(OneOrMore(Word(nums)).parseString("0 123 321")) # -> ['0', '123', '321'] + print(OneOrMore(Word(nums)).addParseAction(remove_first).parseString("0 123 321")) # -> ['123', '321'] + + label = Word(alphas) + patt = label("LABEL") + OneOrMore(Word(nums)) + print(patt.parseString("AAB 123 321").dump()) + + # Use pop() in a parse action to remove named result (note that corresponding value is not + # removed from list form of results) + def remove_LABEL(tokens): + tokens.pop("LABEL") + return tokens + patt.addParseAction(remove_LABEL) + print(patt.parseString("AAB 123 321").dump()) + prints:: + ['AAB', '123', '321'] + - LABEL: AAB + + ['AAB', '123', '321'] + """ + if not args: + args = [-1] + for k,v in kwargs.items(): + if k == 'default': + args = (args[0], v) + else: + raise TypeError("pop() got an unexpected keyword argument '%s'" % k) + if (isinstance(args[0], int) or + len(args) == 1 or + args[0] in self): + index = args[0] + ret = self[index] + del self[index] + return ret + else: + defaultvalue = args[1] + return defaultvalue + + def get(self, key, defaultValue=None): + """ + Returns named result matching the given key, or if there is no + such name, then returns the given C{defaultValue} or C{None} if no + C{defaultValue} is specified. + + Similar to C{dict.get()}. + + Example:: + integer = Word(nums) + date_str = integer("year") + '/' + integer("month") + '/' + integer("day") + + result = date_str.parseString("1999/12/31") + print(result.get("year")) # -> '1999' + print(result.get("hour", "not specified")) # -> 'not specified' + print(result.get("hour")) # -> None + """ + if key in self: + return self[key] + else: + return defaultValue + + def insert( self, index, insStr ): + """ + Inserts new element at location index in the list of parsed tokens. + + Similar to C{list.insert()}. + + Example:: + print(OneOrMore(Word(nums)).parseString("0 123 321")) # -> ['0', '123', '321'] + + # use a parse action to insert the parse location in the front of the parsed results + def insert_locn(locn, tokens): + tokens.insert(0, locn) + print(OneOrMore(Word(nums)).addParseAction(insert_locn).parseString("0 123 321")) # -> [0, '0', '123', '321'] + """ + self.__toklist.insert(index, insStr) + # fixup indices in token dictionary + for name,occurrences in self.__tokdict.items(): + for k, (value, position) in enumerate(occurrences): + occurrences[k] = _ParseResultsWithOffset(value, position + (position > index)) + + def append( self, item ): + """ + Add single element to end of ParseResults list of elements. + + Example:: + print(OneOrMore(Word(nums)).parseString("0 123 321")) # -> ['0', '123', '321'] + + # use a parse action to compute the sum of the parsed integers, and add it to the end + def append_sum(tokens): + tokens.append(sum(map(int, tokens))) + print(OneOrMore(Word(nums)).addParseAction(append_sum).parseString("0 123 321")) # -> ['0', '123', '321', 444] + """ + self.__toklist.append(item) + + def extend( self, itemseq ): + """ + Add sequence of elements to end of ParseResults list of elements. + + Example:: + patt = OneOrMore(Word(alphas)) + + # use a parse action to append the reverse of the matched strings, to make a palindrome + def make_palindrome(tokens): + tokens.extend(reversed([t[::-1] for t in tokens])) + return ''.join(tokens) + print(patt.addParseAction(make_palindrome).parseString("lskdj sdlkjf lksd")) # -> 'lskdjsdlkjflksddsklfjkldsjdksl' + """ + if isinstance(itemseq, ParseResults): + self += itemseq + else: + self.__toklist.extend(itemseq) + + def clear( self ): + """ + Clear all elements and results names. + """ + del self.__toklist[:] + self.__tokdict.clear() + + def __getattr__( self, name ): + try: + return self[name] + except KeyError: + return "" + + if name in self.__tokdict: + if name not in self.__accumNames: + return self.__tokdict[name][-1][0] + else: + return ParseResults([ v[0] for v in self.__tokdict[name] ]) + else: + return "" + + def __add__( self, other ): + ret = self.copy() + ret += other + return ret + + def __iadd__( self, other ): + if other.__tokdict: + offset = len(self.__toklist) + addoffset = lambda a: offset if a<0 else a+offset + otheritems = other.__tokdict.items() + otherdictitems = [(k, _ParseResultsWithOffset(v[0],addoffset(v[1])) ) + for (k,vlist) in otheritems for v in vlist] + for k,v in otherdictitems: + self[k] = v + if isinstance(v[0],ParseResults): + v[0].__parent = wkref(self) + + self.__toklist += other.__toklist + self.__accumNames.update( other.__accumNames ) + return self + + def __radd__(self, other): + if isinstance(other,int) and other == 0: + # useful for merging many ParseResults using sum() builtin + return self.copy() + else: + # this may raise a TypeError - so be it + return other + self + + def __repr__( self ): + return "(%s, %s)" % ( repr( self.__toklist ), repr( self.__tokdict ) ) + + def __str__( self ): + return '[' + ', '.join(_ustr(i) if isinstance(i, ParseResults) else repr(i) for i in self.__toklist) + ']' + + def _asStringList( self, sep='' ): + out = [] + for item in self.__toklist: + if out and sep: + out.append(sep) + if isinstance( item, ParseResults ): + out += item._asStringList() + else: + out.append( _ustr(item) ) + return out + + def asList( self ): + """ + Returns the parse results as a nested list of matching tokens, all converted to strings. + + Example:: + patt = OneOrMore(Word(alphas)) + result = patt.parseString("sldkj lsdkj sldkj") + # even though the result prints in string-like form, it is actually a pyparsing ParseResults + print(type(result), result) # -> <class 'pyparsing.ParseResults'> ['sldkj', 'lsdkj', 'sldkj'] + + # Use asList() to create an actual list + result_list = result.asList() + print(type(result_list), result_list) # -> <class 'list'> ['sldkj', 'lsdkj', 'sldkj'] + """ + return [res.asList() if isinstance(res,ParseResults) else res for res in self.__toklist] + + def asDict( self ): + """ + Returns the named parse results as a nested dictionary. + + Example:: + integer = Word(nums) + date_str = integer("year") + '/' + integer("month") + '/' + integer("day") + + result = date_str.parseString('12/31/1999') + print(type(result), repr(result)) # -> <class 'pyparsing.ParseResults'> (['12', '/', '31', '/', '1999'], {'day': [('1999', 4)], 'year': [('12', 0)], 'month': [('31', 2)]}) + + result_dict = result.asDict() + print(type(result_dict), repr(result_dict)) # -> <class 'dict'> {'day': '1999', 'year': '12', 'month': '31'} + + # even though a ParseResults supports dict-like access, sometime you just need to have a dict + import json + print(json.dumps(result)) # -> Exception: TypeError: ... is not JSON serializable + print(json.dumps(result.asDict())) # -> {"month": "31", "day": "1999", "year": "12"} + """ + if PY_3: + item_fn = self.items + else: + item_fn = self.iteritems + + def toItem(obj): + if isinstance(obj, ParseResults): + if obj.haskeys(): + return obj.asDict() + else: + return [toItem(v) for v in obj] + else: + return obj + + return dict((k,toItem(v)) for k,v in item_fn()) + + def copy( self ): + """ + Returns a new copy of a C{ParseResults} object. + """ + ret = ParseResults( self.__toklist ) + ret.__tokdict = self.__tokdict.copy() + ret.__parent = self.__parent + ret.__accumNames.update( self.__accumNames ) + ret.__name = self.__name + return ret + + def asXML( self, doctag=None, namedItemsOnly=False, indent="", formatted=True ): + """ + (Deprecated) Returns the parse results as XML. Tags are created for tokens and lists that have defined results names. + """ + nl = "\n" + out = [] + namedItems = dict((v[1],k) for (k,vlist) in self.__tokdict.items() + for v in vlist) + nextLevelIndent = indent + " " + + # collapse out indents if formatting is not desired + if not formatted: + indent = "" + nextLevelIndent = "" + nl = "" + + selfTag = None + if doctag is not None: + selfTag = doctag + else: + if self.__name: + selfTag = self.__name + + if not selfTag: + if namedItemsOnly: + return "" + else: + selfTag = "ITEM" + + out += [ nl, indent, "<", selfTag, ">" ] + + for i,res in enumerate(self.__toklist): + if isinstance(res,ParseResults): + if i in namedItems: + out += [ res.asXML(namedItems[i], + namedItemsOnly and doctag is None, + nextLevelIndent, + formatted)] + else: + out += [ res.asXML(None, + namedItemsOnly and doctag is None, + nextLevelIndent, + formatted)] + else: + # individual token, see if there is a name for it + resTag = None + if i in namedItems: + resTag = namedItems[i] + if not resTag: + if namedItemsOnly: + continue + else: + resTag = "ITEM" + xmlBodyText = _xml_escape(_ustr(res)) + out += [ nl, nextLevelIndent, "<", resTag, ">", + xmlBodyText, + "</", resTag, ">" ] + + out += [ nl, indent, "</", selfTag, ">" ] + return "".join(out) + + def __lookup(self,sub): + for k,vlist in self.__tokdict.items(): + for v,loc in vlist: + if sub is v: + return k + return None + + def getName(self): + r""" + Returns the results name for this token expression. Useful when several + different expressions might match at a particular location. + + Example:: + integer = Word(nums) + ssn_expr = Regex(r"\d\d\d-\d\d-\d\d\d\d") + house_number_expr = Suppress('#') + Word(nums, alphanums) + user_data = (Group(house_number_expr)("house_number") + | Group(ssn_expr)("ssn") + | Group(integer)("age")) + user_info = OneOrMore(user_data) + + result = user_info.parseString("22 111-22-3333 #221B") + for item in result: + print(item.getName(), ':', item[0]) + prints:: + age : 22 + ssn : 111-22-3333 + house_number : 221B + """ + if self.__name: + return self.__name + elif self.__parent: + par = self.__parent() + if par: + return par.__lookup(self) + else: + return None + elif (len(self) == 1 and + len(self.__tokdict) == 1 and + next(iter(self.__tokdict.values()))[0][1] in (0,-1)): + return next(iter(self.__tokdict.keys())) + else: + return None + + def dump(self, indent='', depth=0, full=True): + """ + Diagnostic method for listing out the contents of a C{ParseResults}. + Accepts an optional C{indent} argument so that this string can be embedded + in a nested display of other data. + + Example:: + integer = Word(nums) + date_str = integer("year") + '/' + integer("month") + '/' + integer("day") + + result = date_str.parseString('12/31/1999') + print(result.dump()) + prints:: + ['12', '/', '31', '/', '1999'] + - day: 1999 + - month: 31 + - year: 12 + """ + out = [] + NL = '\n' + out.append( indent+_ustr(self.asList()) ) + if full: + if self.haskeys(): + items = sorted((str(k), v) for k,v in self.items()) + for k,v in items: + if out: + out.append(NL) + out.append( "%s%s- %s: " % (indent,(' '*depth), k) ) + if isinstance(v,ParseResults): + if v: + out.append( v.dump(indent,depth+1) ) + else: + out.append(_ustr(v)) + else: + out.append(repr(v)) + elif any(isinstance(vv,ParseResults) for vv in self): + v = self + for i,vv in enumerate(v): + if isinstance(vv,ParseResults): + out.append("\n%s%s[%d]:\n%s%s%s" % (indent,(' '*(depth)),i,indent,(' '*(depth+1)),vv.dump(indent,depth+1) )) + else: + out.append("\n%s%s[%d]:\n%s%s%s" % (indent,(' '*(depth)),i,indent,(' '*(depth+1)),_ustr(vv))) + + return "".join(out) + + def pprint(self, *args, **kwargs): + """ + Pretty-printer for parsed results as a list, using the C{pprint} module. + Accepts additional positional or keyword args as defined for the + C{pprint.pprint} method. (U{http://docs.python.org/3/library/pprint.html#pprint.pprint}) + + Example:: + ident = Word(alphas, alphanums) + num = Word(nums) + func = Forward() + term = ident | num | Group('(' + func + ')') + func <<= ident + Group(Optional(delimitedList(term))) + result = func.parseString("fna a,b,(fnb c,d,200),100") + result.pprint(width=40) + prints:: + ['fna', + ['a', + 'b', + ['(', 'fnb', ['c', 'd', '200'], ')'], + '100']] + """ + pprint.pprint(self.asList(), *args, **kwargs) + + # add support for pickle protocol + def __getstate__(self): + return ( self.__toklist, + ( self.__tokdict.copy(), + self.__parent is not None and self.__parent() or None, + self.__accumNames, + self.__name ) ) + + def __setstate__(self,state): + self.__toklist = state[0] + (self.__tokdict, + par, + inAccumNames, + self.__name) = state[1] + self.__accumNames = {} + self.__accumNames.update(inAccumNames) + if par is not None: + self.__parent = wkref(par) + else: + self.__parent = None + + def __getnewargs__(self): + return self.__toklist, self.__name, self.__asList, self.__modal + + def __dir__(self): + return (dir(type(self)) + list(self.keys())) + +MutableMapping.register(ParseResults) + +def col (loc,strg): + """Returns current column within a string, counting newlines as line separators. + The first column is number 1. + + Note: the default parsing behavior is to expand tabs in the input string + before starting the parsing process. See L{I{ParserElement.parseString}<ParserElement.parseString>} for more information + on parsing strings containing C{<TAB>}s, and suggested methods to maintain a + consistent view of the parsed string, the parse location, and line and column + positions within the parsed string. + """ + s = strg + return 1 if 0<loc<len(s) and s[loc-1] == '\n' else loc - s.rfind("\n", 0, loc) + +def lineno(loc,strg): + """Returns current line number within a string, counting newlines as line separators. + The first line is number 1. + + Note: the default parsing behavior is to expand tabs in the input string + before starting the parsing process. See L{I{ParserElement.parseString}<ParserElement.parseString>} for more information + on parsing strings containing C{<TAB>}s, and suggested methods to maintain a + consistent view of the parsed string, the parse location, and line and column + positions within the parsed string. + """ + return strg.count("\n",0,loc) + 1 + +def line( loc, strg ): + """Returns the line of text containing loc within a string, counting newlines as line separators. + """ + lastCR = strg.rfind("\n", 0, loc) + nextCR = strg.find("\n", loc) + if nextCR >= 0: + return strg[lastCR+1:nextCR] + else: + return strg[lastCR+1:] + +def _defaultStartDebugAction( instring, loc, expr ): + print (("Match " + _ustr(expr) + " at loc " + _ustr(loc) + "(%d,%d)" % ( lineno(loc,instring), col(loc,instring) ))) + +def _defaultSuccessDebugAction( instring, startloc, endloc, expr, toks ): + print ("Matched " + _ustr(expr) + " -> " + str(toks.asList())) + +def _defaultExceptionDebugAction( instring, loc, expr, exc ): + print ("Exception raised:" + _ustr(exc)) + +def nullDebugAction(*args): + """'Do-nothing' debug action, to suppress debugging output during parsing.""" + pass + +# Only works on Python 3.x - nonlocal is toxic to Python 2 installs +#~ 'decorator to trim function calls to match the arity of the target' +#~ def _trim_arity(func, maxargs=3): + #~ if func in singleArgBuiltins: + #~ return lambda s,l,t: func(t) + #~ limit = 0 + #~ foundArity = False + #~ def wrapper(*args): + #~ nonlocal limit,foundArity + #~ while 1: + #~ try: + #~ ret = func(*args[limit:]) + #~ foundArity = True + #~ return ret + #~ except TypeError: + #~ if limit == maxargs or foundArity: + #~ raise + #~ limit += 1 + #~ continue + #~ return wrapper + +# this version is Python 2.x-3.x cross-compatible +'decorator to trim function calls to match the arity of the target' +def _trim_arity(func, maxargs=2): + if func in singleArgBuiltins: + return lambda s,l,t: func(t) + limit = [0] + foundArity = [False] + + # traceback return data structure changed in Py3.5 - normalize back to plain tuples + if system_version[:2] >= (3,5): + def extract_stack(limit=0): + # special handling for Python 3.5.0 - extra deep call stack by 1 + offset = -3 if system_version == (3,5,0) else -2 + frame_summary = traceback.extract_stack(limit=-offset+limit-1)[offset] + return [frame_summary[:2]] + def extract_tb(tb, limit=0): + frames = traceback.extract_tb(tb, limit=limit) + frame_summary = frames[-1] + return [frame_summary[:2]] + else: + extract_stack = traceback.extract_stack + extract_tb = traceback.extract_tb + + # synthesize what would be returned by traceback.extract_stack at the call to + # user's parse action 'func', so that we don't incur call penalty at parse time + + LINE_DIFF = 6 + # IF ANY CODE CHANGES, EVEN JUST COMMENTS OR BLANK LINES, BETWEEN THE NEXT LINE AND + # THE CALL TO FUNC INSIDE WRAPPER, LINE_DIFF MUST BE MODIFIED!!!! + this_line = extract_stack(limit=2)[-1] + pa_call_line_synth = (this_line[0], this_line[1]+LINE_DIFF) + + def wrapper(*args): + while 1: + try: + ret = func(*args[limit[0]:]) + foundArity[0] = True + return ret + except TypeError: + # re-raise TypeErrors if they did not come from our arity testing + if foundArity[0]: + raise + else: + try: + tb = sys.exc_info()[-1] + if not extract_tb(tb, limit=2)[-1][:2] == pa_call_line_synth: + raise + finally: + del tb + + if limit[0] <= maxargs: + limit[0] += 1 + continue + raise + + # copy func name to wrapper for sensible debug output + func_name = "<parse action>" + try: + func_name = getattr(func, '__name__', + getattr(func, '__class__').__name__) + except Exception: + func_name = str(func) + wrapper.__name__ = func_name + + return wrapper + +class ParserElement(object): + """Abstract base level parser element class.""" + DEFAULT_WHITE_CHARS = " \n\t\r" + verbose_stacktrace = False + + @staticmethod + def setDefaultWhitespaceChars( chars ): + r""" + Overrides the default whitespace chars + + Example:: + # default whitespace chars are space, <TAB> and newline + OneOrMore(Word(alphas)).parseString("abc def\nghi jkl") # -> ['abc', 'def', 'ghi', 'jkl'] + + # change to just treat newline as significant + ParserElement.setDefaultWhitespaceChars(" \t") + OneOrMore(Word(alphas)).parseString("abc def\nghi jkl") # -> ['abc', 'def'] + """ + ParserElement.DEFAULT_WHITE_CHARS = chars + + @staticmethod + def inlineLiteralsUsing(cls): + """ + Set class to be used for inclusion of string literals into a parser. + + Example:: + # default literal class used is Literal + integer = Word(nums) + date_str = integer("year") + '/' + integer("month") + '/' + integer("day") + + date_str.parseString("1999/12/31") # -> ['1999', '/', '12', '/', '31'] + + + # change to Suppress + ParserElement.inlineLiteralsUsing(Suppress) + date_str = integer("year") + '/' + integer("month") + '/' + integer("day") + + date_str.parseString("1999/12/31") # -> ['1999', '12', '31'] + """ + ParserElement._literalStringClass = cls + + def __init__( self, savelist=False ): + self.parseAction = list() + self.failAction = None + #~ self.name = "<unknown>" # don't define self.name, let subclasses try/except upcall + self.strRepr = None + self.resultsName = None + self.saveAsList = savelist + self.skipWhitespace = True + self.whiteChars = ParserElement.DEFAULT_WHITE_CHARS + self.copyDefaultWhiteChars = True + self.mayReturnEmpty = False # used when checking for left-recursion + self.keepTabs = False + self.ignoreExprs = list() + self.debug = False + self.streamlined = False + self.mayIndexError = True # used to optimize exception handling for subclasses that don't advance parse index + self.errmsg = "" + self.modalResults = True # used to mark results names as modal (report only last) or cumulative (list all) + self.debugActions = ( None, None, None ) #custom debug actions + self.re = None + self.callPreparse = True # used to avoid redundant calls to preParse + self.callDuringTry = False + + def copy( self ): + """ + Make a copy of this C{ParserElement}. Useful for defining different parse actions + for the same parsing pattern, using copies of the original parse element. + + Example:: + integer = Word(nums).setParseAction(lambda toks: int(toks[0])) + integerK = integer.copy().addParseAction(lambda toks: toks[0]*1024) + Suppress("K") + integerM = integer.copy().addParseAction(lambda toks: toks[0]*1024*1024) + Suppress("M") + + print(OneOrMore(integerK | integerM | integer).parseString("5K 100 640K 256M")) + prints:: + [5120, 100, 655360, 268435456] + Equivalent form of C{expr.copy()} is just C{expr()}:: + integerM = integer().addParseAction(lambda toks: toks[0]*1024*1024) + Suppress("M") + """ + cpy = copy.copy( self ) + cpy.parseAction = self.parseAction[:] + cpy.ignoreExprs = self.ignoreExprs[:] + if self.copyDefaultWhiteChars: + cpy.whiteChars = ParserElement.DEFAULT_WHITE_CHARS + return cpy + + def setName( self, name ): + """ + Define name for this expression, makes debugging and exception messages clearer. + + Example:: + Word(nums).parseString("ABC") # -> Exception: Expected W:(0123...) (at char 0), (line:1, col:1) + Word(nums).setName("integer").parseString("ABC") # -> Exception: Expected integer (at char 0), (line:1, col:1) + """ + self.name = name + self.errmsg = "Expected " + self.name + if hasattr(self,"exception"): + self.exception.msg = self.errmsg + return self + + def setResultsName( self, name, listAllMatches=False ): + """ + Define name for referencing matching tokens as a nested attribute + of the returned parse results. + NOTE: this returns a *copy* of the original C{ParserElement} object; + this is so that the client can define a basic element, such as an + integer, and reference it in multiple places with different names. + + You can also set results names using the abbreviated syntax, + C{expr("name")} in place of C{expr.setResultsName("name")} - + see L{I{__call__}<__call__>}. + + Example:: + date_str = (integer.setResultsName("year") + '/' + + integer.setResultsName("month") + '/' + + integer.setResultsName("day")) + + # equivalent form: + date_str = integer("year") + '/' + integer("month") + '/' + integer("day") + """ + newself = self.copy() + if name.endswith("*"): + name = name[:-1] + listAllMatches=True + newself.resultsName = name + newself.modalResults = not listAllMatches + return newself + + def setBreak(self,breakFlag = True): + """Method to invoke the Python pdb debugger when this element is + about to be parsed. Set C{breakFlag} to True to enable, False to + disable. + """ + if breakFlag: + _parseMethod = self._parse + def breaker(instring, loc, doActions=True, callPreParse=True): + import pdb + pdb.set_trace() + return _parseMethod( instring, loc, doActions, callPreParse ) + breaker._originalParseMethod = _parseMethod + self._parse = breaker + else: + if hasattr(self._parse,"_originalParseMethod"): + self._parse = self._parse._originalParseMethod + return self + + def setParseAction( self, *fns, **kwargs ): + """ + Define one or more actions to perform when successfully matching parse element definition. + Parse action fn is a callable method with 0-3 arguments, called as C{fn(s,loc,toks)}, + C{fn(loc,toks)}, C{fn(toks)}, or just C{fn()}, where: + - s = the original string being parsed (see note below) + - loc = the location of the matching substring + - toks = a list of the matched tokens, packaged as a C{L{ParseResults}} object + If the functions in fns modify the tokens, they can return them as the return + value from fn, and the modified list of tokens will replace the original. + Otherwise, fn does not need to return any value. + + Optional keyword arguments: + - callDuringTry = (default=C{False}) indicate if parse action should be run during lookaheads and alternate testing + + Note: the default parsing behavior is to expand tabs in the input string + before starting the parsing process. See L{I{parseString}<parseString>} for more information + on parsing strings containing C{<TAB>}s, and suggested methods to maintain a + consistent view of the parsed string, the parse location, and line and column + positions within the parsed string. + + Example:: + integer = Word(nums) + date_str = integer + '/' + integer + '/' + integer + + date_str.parseString("1999/12/31") # -> ['1999', '/', '12', '/', '31'] + + # use parse action to convert to ints at parse time + integer = Word(nums).setParseAction(lambda toks: int(toks[0])) + date_str = integer + '/' + integer + '/' + integer + + # note that integer fields are now ints, not strings + date_str.parseString("1999/12/31") # -> [1999, '/', 12, '/', 31] + """ + self.parseAction = list(map(_trim_arity, list(fns))) + self.callDuringTry = kwargs.get("callDuringTry", False) + return self + + def addParseAction( self, *fns, **kwargs ): + """ + Add one or more parse actions to expression's list of parse actions. See L{I{setParseAction}<setParseAction>}. + + See examples in L{I{copy}<copy>}. + """ + self.parseAction += list(map(_trim_arity, list(fns))) + self.callDuringTry = self.callDuringTry or kwargs.get("callDuringTry", False) + return self + + def addCondition(self, *fns, **kwargs): + """Add a boolean predicate function to expression's list of parse actions. See + L{I{setParseAction}<setParseAction>} for function call signatures. Unlike C{setParseAction}, + functions passed to C{addCondition} need to return boolean success/fail of the condition. + + Optional keyword arguments: + - message = define a custom message to be used in the raised exception + - fatal = if True, will raise ParseFatalException to stop parsing immediately; otherwise will raise ParseException + + Example:: + integer = Word(nums).setParseAction(lambda toks: int(toks[0])) + year_int = integer.copy() + year_int.addCondition(lambda toks: toks[0] >= 2000, message="Only support years 2000 and later") + date_str = year_int + '/' + integer + '/' + integer + + result = date_str.parseString("1999/12/31") # -> Exception: Only support years 2000 and later (at char 0), (line:1, col:1) + """ + msg = kwargs.get("message", "failed user-defined condition") + exc_type = ParseFatalException if kwargs.get("fatal", False) else ParseException + for fn in fns: + def pa(s,l,t): + if not bool(_trim_arity(fn)(s,l,t)): + raise exc_type(s,l,msg) + self.parseAction.append(pa) + self.callDuringTry = self.callDuringTry or kwargs.get("callDuringTry", False) + return self + + def setFailAction( self, fn ): + """Define action to perform if parsing fails at this expression. + Fail acton fn is a callable function that takes the arguments + C{fn(s,loc,expr,err)} where: + - s = string being parsed + - loc = location where expression match was attempted and failed + - expr = the parse expression that failed + - err = the exception thrown + The function returns no value. It may throw C{L{ParseFatalException}} + if it is desired to stop parsing immediately.""" + self.failAction = fn + return self + + def _skipIgnorables( self, instring, loc ): + exprsFound = True + while exprsFound: + exprsFound = False + for e in self.ignoreExprs: + try: + while 1: + loc,dummy = e._parse( instring, loc ) + exprsFound = True + except ParseException: + pass + return loc + + def preParse( self, instring, loc ): + if self.ignoreExprs: + loc = self._skipIgnorables( instring, loc ) + + if self.skipWhitespace: + wt = self.whiteChars + instrlen = len(instring) + while loc < instrlen and instring[loc] in wt: + loc += 1 + + return loc + + def parseImpl( self, instring, loc, doActions=True ): + return loc, [] + + def postParse( self, instring, loc, tokenlist ): + return tokenlist + + #~ @profile + def _parseNoCache( self, instring, loc, doActions=True, callPreParse=True ): + debugging = ( self.debug ) #and doActions ) + + if debugging or self.failAction: + #~ print ("Match",self,"at loc",loc,"(%d,%d)" % ( lineno(loc,instring), col(loc,instring) )) + if (self.debugActions[0] ): + self.debugActions[0]( instring, loc, self ) + if callPreParse and self.callPreparse: + preloc = self.preParse( instring, loc ) + else: + preloc = loc + tokensStart = preloc + try: + try: + loc,tokens = self.parseImpl( instring, preloc, doActions ) + except IndexError: + raise ParseException( instring, len(instring), self.errmsg, self ) + except ParseBaseException as err: + #~ print ("Exception raised:", err) + if self.debugActions[2]: + self.debugActions[2]( instring, tokensStart, self, err ) + if self.failAction: + self.failAction( instring, tokensStart, self, err ) + raise + else: + if callPreParse and self.callPreparse: + preloc = self.preParse( instring, loc ) + else: + preloc = loc + tokensStart = preloc + if self.mayIndexError or preloc >= len(instring): + try: + loc,tokens = self.parseImpl( instring, preloc, doActions ) + except IndexError: + raise ParseException( instring, len(instring), self.errmsg, self ) + else: + loc,tokens = self.parseImpl( instring, preloc, doActions ) + + tokens = self.postParse( instring, loc, tokens ) + + retTokens = ParseResults( tokens, self.resultsName, asList=self.saveAsList, modal=self.modalResults ) + if self.parseAction and (doActions or self.callDuringTry): + if debugging: + try: + for fn in self.parseAction: + tokens = fn( instring, tokensStart, retTokens ) + if tokens is not None: + retTokens = ParseResults( tokens, + self.resultsName, + asList=self.saveAsList and isinstance(tokens,(ParseResults,list)), + modal=self.modalResults ) + except ParseBaseException as err: + #~ print "Exception raised in user parse action:", err + if (self.debugActions[2] ): + self.debugActions[2]( instring, tokensStart, self, err ) + raise + else: + for fn in self.parseAction: + tokens = fn( instring, tokensStart, retTokens ) + if tokens is not None: + retTokens = ParseResults( tokens, + self.resultsName, + asList=self.saveAsList and isinstance(tokens,(ParseResults,list)), + modal=self.modalResults ) + if debugging: + #~ print ("Matched",self,"->",retTokens.asList()) + if (self.debugActions[1] ): + self.debugActions[1]( instring, tokensStart, loc, self, retTokens ) + + return loc, retTokens + + def tryParse( self, instring, loc ): + try: + return self._parse( instring, loc, doActions=False )[0] + except ParseFatalException: + raise ParseException( instring, loc, self.errmsg, self) + + def canParseNext(self, instring, loc): + try: + self.tryParse(instring, loc) + except (ParseException, IndexError): + return False + else: + return True + + class _UnboundedCache(object): + def __init__(self): + cache = {} + self.not_in_cache = not_in_cache = object() + + def get(self, key): + return cache.get(key, not_in_cache) + + def set(self, key, value): + cache[key] = value + + def clear(self): + cache.clear() + + def cache_len(self): + return len(cache) + + self.get = types.MethodType(get, self) + self.set = types.MethodType(set, self) + self.clear = types.MethodType(clear, self) + self.__len__ = types.MethodType(cache_len, self) + + if _OrderedDict is not None: + class _FifoCache(object): + def __init__(self, size): + self.not_in_cache = not_in_cache = object() + + cache = _OrderedDict() + + def get(self, key): + return cache.get(key, not_in_cache) + + def set(self, key, value): + cache[key] = value + while len(cache) > size: + try: + cache.popitem(False) + except KeyError: + pass + + def clear(self): + cache.clear() + + def cache_len(self): + return len(cache) + + self.get = types.MethodType(get, self) + self.set = types.MethodType(set, self) + self.clear = types.MethodType(clear, self) + self.__len__ = types.MethodType(cache_len, self) + + else: + class _FifoCache(object): + def __init__(self, size): + self.not_in_cache = not_in_cache = object() + + cache = {} + key_fifo = collections.deque([], size) + + def get(self, key): + return cache.get(key, not_in_cache) + + def set(self, key, value): + cache[key] = value + while len(key_fifo) > size: + cache.pop(key_fifo.popleft(), None) + key_fifo.append(key) + + def clear(self): + cache.clear() + key_fifo.clear() + + def cache_len(self): + return len(cache) + + self.get = types.MethodType(get, self) + self.set = types.MethodType(set, self) + self.clear = types.MethodType(clear, self) + self.__len__ = types.MethodType(cache_len, self) + + # argument cache for optimizing repeated calls when backtracking through recursive expressions + packrat_cache = {} # this is set later by enabledPackrat(); this is here so that resetCache() doesn't fail + packrat_cache_lock = RLock() + packrat_cache_stats = [0, 0] + + # this method gets repeatedly called during backtracking with the same arguments - + # we can cache these arguments and save ourselves the trouble of re-parsing the contained expression + def _parseCache( self, instring, loc, doActions=True, callPreParse=True ): + HIT, MISS = 0, 1 + lookup = (self, instring, loc, callPreParse, doActions) + with ParserElement.packrat_cache_lock: + cache = ParserElement.packrat_cache + value = cache.get(lookup) + if value is cache.not_in_cache: + ParserElement.packrat_cache_stats[MISS] += 1 + try: + value = self._parseNoCache(instring, loc, doActions, callPreParse) + except ParseBaseException as pe: + # cache a copy of the exception, without the traceback + cache.set(lookup, pe.__class__(*pe.args)) + raise + else: + cache.set(lookup, (value[0], value[1].copy())) + return value + else: + ParserElement.packrat_cache_stats[HIT] += 1 + if isinstance(value, Exception): + raise value + return (value[0], value[1].copy()) + + _parse = _parseNoCache + + @staticmethod + def resetCache(): + ParserElement.packrat_cache.clear() + ParserElement.packrat_cache_stats[:] = [0] * len(ParserElement.packrat_cache_stats) + + _packratEnabled = False + @staticmethod + def enablePackrat(cache_size_limit=128): + """Enables "packrat" parsing, which adds memoizing to the parsing logic. + Repeated parse attempts at the same string location (which happens + often in many complex grammars) can immediately return a cached value, + instead of re-executing parsing/validating code. Memoizing is done of + both valid results and parsing exceptions. + + Parameters: + - cache_size_limit - (default=C{128}) - if an integer value is provided + will limit the size of the packrat cache; if None is passed, then + the cache size will be unbounded; if 0 is passed, the cache will + be effectively disabled. + + This speedup may break existing programs that use parse actions that + have side-effects. For this reason, packrat parsing is disabled when + you first import pyparsing. To activate the packrat feature, your + program must call the class method C{ParserElement.enablePackrat()}. If + your program uses C{psyco} to "compile as you go", you must call + C{enablePackrat} before calling C{psyco.full()}. If you do not do this, + Python will crash. For best results, call C{enablePackrat()} immediately + after importing pyparsing. + + Example:: + import pyparsing + pyparsing.ParserElement.enablePackrat() + """ + if not ParserElement._packratEnabled: + ParserElement._packratEnabled = True + if cache_size_limit is None: + ParserElement.packrat_cache = ParserElement._UnboundedCache() + else: + ParserElement.packrat_cache = ParserElement._FifoCache(cache_size_limit) + ParserElement._parse = ParserElement._parseCache + + def parseString( self, instring, parseAll=False ): + """ + Execute the parse expression with the given string. + This is the main interface to the client code, once the complete + expression has been built. + + If you want the grammar to require that the entire input string be + successfully parsed, then set C{parseAll} to True (equivalent to ending + the grammar with C{L{StringEnd()}}). + + Note: C{parseString} implicitly calls C{expandtabs()} on the input string, + in order to report proper column numbers in parse actions. + If the input string contains tabs and + the grammar uses parse actions that use the C{loc} argument to index into the + string being parsed, you can ensure you have a consistent view of the input + string by: + - calling C{parseWithTabs} on your grammar before calling C{parseString} + (see L{I{parseWithTabs}<parseWithTabs>}) + - define your parse action using the full C{(s,loc,toks)} signature, and + reference the input string using the parse action's C{s} argument + - explictly expand the tabs in your input string before calling + C{parseString} + + Example:: + Word('a').parseString('aaaaabaaa') # -> ['aaaaa'] + Word('a').parseString('aaaaabaaa', parseAll=True) # -> Exception: Expected end of text + """ + ParserElement.resetCache() + if not self.streamlined: + self.streamline() + #~ self.saveAsList = True + for e in self.ignoreExprs: + e.streamline() + if not self.keepTabs: + instring = instring.expandtabs() + try: + loc, tokens = self._parse( instring, 0 ) + if parseAll: + loc = self.preParse( instring, loc ) + se = Empty() + StringEnd() + se._parse( instring, loc ) + except ParseBaseException as exc: + if ParserElement.verbose_stacktrace: + raise + else: + # catch and re-raise exception from here, clears out pyparsing internal stack trace + raise exc + else: + return tokens + + def scanString( self, instring, maxMatches=_MAX_INT, overlap=False ): + """ + Scan the input string for expression matches. Each match will return the + matching tokens, start location, and end location. May be called with optional + C{maxMatches} argument, to clip scanning after 'n' matches are found. If + C{overlap} is specified, then overlapping matches will be reported. + + Note that the start and end locations are reported relative to the string + being parsed. See L{I{parseString}<parseString>} for more information on parsing + strings with embedded tabs. + + Example:: + source = "sldjf123lsdjjkf345sldkjf879lkjsfd987" + print(source) + for tokens,start,end in Word(alphas).scanString(source): + print(' '*start + '^'*(end-start)) + print(' '*start + tokens[0]) + + prints:: + + sldjf123lsdjjkf345sldkjf879lkjsfd987 + ^^^^^ + sldjf + ^^^^^^^ + lsdjjkf + ^^^^^^ + sldkjf + ^^^^^^ + lkjsfd + """ + if not self.streamlined: + self.streamline() + for e in self.ignoreExprs: + e.streamline() + + if not self.keepTabs: + instring = _ustr(instring).expandtabs() + instrlen = len(instring) + loc = 0 + preparseFn = self.preParse + parseFn = self._parse + ParserElement.resetCache() + matches = 0 + try: + while loc <= instrlen and matches < maxMatches: + try: + preloc = preparseFn( instring, loc ) + nextLoc,tokens = parseFn( instring, preloc, callPreParse=False ) + except ParseException: + loc = preloc+1 + else: + if nextLoc > loc: + matches += 1 + yield tokens, preloc, nextLoc + if overlap: + nextloc = preparseFn( instring, loc ) + if nextloc > loc: + loc = nextLoc + else: + loc += 1 + else: + loc = nextLoc + else: + loc = preloc+1 + except ParseBaseException as exc: + if ParserElement.verbose_stacktrace: + raise + else: + # catch and re-raise exception from here, clears out pyparsing internal stack trace + raise exc + + def transformString( self, instring ): + """ + Extension to C{L{scanString}}, to modify matching text with modified tokens that may + be returned from a parse action. To use C{transformString}, define a grammar and + attach a parse action to it that modifies the returned token list. + Invoking C{transformString()} on a target string will then scan for matches, + and replace the matched text patterns according to the logic in the parse + action. C{transformString()} returns the resulting transformed string. + + Example:: + wd = Word(alphas) + wd.setParseAction(lambda toks: toks[0].title()) + + print(wd.transformString("now is the winter of our discontent made glorious summer by this sun of york.")) + Prints:: + Now Is The Winter Of Our Discontent Made Glorious Summer By This Sun Of York. + """ + out = [] + lastE = 0 + # force preservation of <TAB>s, to minimize unwanted transformation of string, and to + # keep string locs straight between transformString and scanString + self.keepTabs = True + try: + for t,s,e in self.scanString( instring ): + out.append( instring[lastE:s] ) + if t: + if isinstance(t,ParseResults): + out += t.asList() + elif isinstance(t,list): + out += t + else: + out.append(t) + lastE = e + out.append(instring[lastE:]) + out = [o for o in out if o] + return "".join(map(_ustr,_flatten(out))) + except ParseBaseException as exc: + if ParserElement.verbose_stacktrace: + raise + else: + # catch and re-raise exception from here, clears out pyparsing internal stack trace + raise exc + + def searchString( self, instring, maxMatches=_MAX_INT ): + """ + Another extension to C{L{scanString}}, simplifying the access to the tokens found + to match the given parse expression. May be called with optional + C{maxMatches} argument, to clip searching after 'n' matches are found. + + Example:: + # a capitalized word starts with an uppercase letter, followed by zero or more lowercase letters + cap_word = Word(alphas.upper(), alphas.lower()) + + print(cap_word.searchString("More than Iron, more than Lead, more than Gold I need Electricity")) + + # the sum() builtin can be used to merge results into a single ParseResults object + print(sum(cap_word.searchString("More than Iron, more than Lead, more than Gold I need Electricity"))) + prints:: + [['More'], ['Iron'], ['Lead'], ['Gold'], ['I'], ['Electricity']] + ['More', 'Iron', 'Lead', 'Gold', 'I', 'Electricity'] + """ + try: + return ParseResults([ t for t,s,e in self.scanString( instring, maxMatches ) ]) + except ParseBaseException as exc: + if ParserElement.verbose_stacktrace: + raise + else: + # catch and re-raise exception from here, clears out pyparsing internal stack trace + raise exc + + def split(self, instring, maxsplit=_MAX_INT, includeSeparators=False): + """ + Generator method to split a string using the given expression as a separator. + May be called with optional C{maxsplit} argument, to limit the number of splits; + and the optional C{includeSeparators} argument (default=C{False}), if the separating + matching text should be included in the split results. + + Example:: + punc = oneOf(list(".,;:/-!?")) + print(list(punc.split("This, this?, this sentence, is badly punctuated!"))) + prints:: + ['This', ' this', '', ' this sentence', ' is badly punctuated', ''] + """ + splits = 0 + last = 0 + for t,s,e in self.scanString(instring, maxMatches=maxsplit): + yield instring[last:s] + if includeSeparators: + yield t[0] + last = e + yield instring[last:] + + def __add__(self, other ): + """ + Implementation of + operator - returns C{L{And}}. Adding strings to a ParserElement + converts them to L{Literal}s by default. + + Example:: + greet = Word(alphas) + "," + Word(alphas) + "!" + hello = "Hello, World!" + print (hello, "->", greet.parseString(hello)) + Prints:: + Hello, World! -> ['Hello', ',', 'World', '!'] + """ + if isinstance( other, basestring ): + other = ParserElement._literalStringClass( other ) + if not isinstance( other, ParserElement ): + warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, stacklevel=2) + return None + return And( [ self, other ] ) + + def __radd__(self, other ): + """ + Implementation of + operator when left operand is not a C{L{ParserElement}} + """ + if isinstance( other, basestring ): + other = ParserElement._literalStringClass( other ) + if not isinstance( other, ParserElement ): + warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, stacklevel=2) + return None + return other + self + + def __sub__(self, other): + """ + Implementation of - operator, returns C{L{And}} with error stop + """ + if isinstance( other, basestring ): + other = ParserElement._literalStringClass( other ) + if not isinstance( other, ParserElement ): + warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, stacklevel=2) + return None + return self + And._ErrorStop() + other + + def __rsub__(self, other ): + """ + Implementation of - operator when left operand is not a C{L{ParserElement}} + """ + if isinstance( other, basestring ): + other = ParserElement._literalStringClass( other ) + if not isinstance( other, ParserElement ): + warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, stacklevel=2) + return None + return other - self + + def __mul__(self,other): + """ + Implementation of * operator, allows use of C{expr * 3} in place of + C{expr + expr + expr}. Expressions may also me multiplied by a 2-integer + tuple, similar to C{{min,max}} multipliers in regular expressions. Tuples + may also include C{None} as in: + - C{expr*(n,None)} or C{expr*(n,)} is equivalent + to C{expr*n + L{ZeroOrMore}(expr)} + (read as "at least n instances of C{expr}") + - C{expr*(None,n)} is equivalent to C{expr*(0,n)} + (read as "0 to n instances of C{expr}") + - C{expr*(None,None)} is equivalent to C{L{ZeroOrMore}(expr)} + - C{expr*(1,None)} is equivalent to C{L{OneOrMore}(expr)} + + Note that C{expr*(None,n)} does not raise an exception if + more than n exprs exist in the input stream; that is, + C{expr*(None,n)} does not enforce a maximum number of expr + occurrences. If this behavior is desired, then write + C{expr*(None,n) + ~expr} + """ + if isinstance(other,int): + minElements, optElements = other,0 + elif isinstance(other,tuple): + other = (other + (None, None))[:2] + if other[0] is None: + other = (0, other[1]) + if isinstance(other[0],int) and other[1] is None: + if other[0] == 0: + return ZeroOrMore(self) + if other[0] == 1: + return OneOrMore(self) + else: + return self*other[0] + ZeroOrMore(self) + elif isinstance(other[0],int) and isinstance(other[1],int): + minElements, optElements = other + optElements -= minElements + else: + raise TypeError("cannot multiply 'ParserElement' and ('%s','%s') objects", type(other[0]),type(other[1])) + else: + raise TypeError("cannot multiply 'ParserElement' and '%s' objects", type(other)) + + if minElements < 0: + raise ValueError("cannot multiply ParserElement by negative value") + if optElements < 0: + raise ValueError("second tuple value must be greater or equal to first tuple value") + if minElements == optElements == 0: + raise ValueError("cannot multiply ParserElement by 0 or (0,0)") + + if (optElements): + def makeOptionalList(n): + if n>1: + return Optional(self + makeOptionalList(n-1)) + else: + return Optional(self) + if minElements: + if minElements == 1: + ret = self + makeOptionalList(optElements) + else: + ret = And([self]*minElements) + makeOptionalList(optElements) + else: + ret = makeOptionalList(optElements) + else: + if minElements == 1: + ret = self + else: + ret = And([self]*minElements) + return ret + + def __rmul__(self, other): + return self.__mul__(other) + + def __or__(self, other ): + """ + Implementation of | operator - returns C{L{MatchFirst}} + """ + if isinstance( other, basestring ): + other = ParserElement._literalStringClass( other ) + if not isinstance( other, ParserElement ): + warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, stacklevel=2) + return None + return MatchFirst( [ self, other ] ) + + def __ror__(self, other ): + """ + Implementation of | operator when left operand is not a C{L{ParserElement}} + """ + if isinstance( other, basestring ): + other = ParserElement._literalStringClass( other ) + if not isinstance( other, ParserElement ): + warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, stacklevel=2) + return None + return other | self + + def __xor__(self, other ): + """ + Implementation of ^ operator - returns C{L{Or}} + """ + if isinstance( other, basestring ): + other = ParserElement._literalStringClass( other ) + if not isinstance( other, ParserElement ): + warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, stacklevel=2) + return None + return Or( [ self, other ] ) + + def __rxor__(self, other ): + """ + Implementation of ^ operator when left operand is not a C{L{ParserElement}} + """ + if isinstance( other, basestring ): + other = ParserElement._literalStringClass( other ) + if not isinstance( other, ParserElement ): + warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, stacklevel=2) + return None + return other ^ self + + def __and__(self, other ): + """ + Implementation of & operator - returns C{L{Each}} + """ + if isinstance( other, basestring ): + other = ParserElement._literalStringClass( other ) + if not isinstance( other, ParserElement ): + warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, stacklevel=2) + return None + return Each( [ self, other ] ) + + def __rand__(self, other ): + """ + Implementation of & operator when left operand is not a C{L{ParserElement}} + """ + if isinstance( other, basestring ): + other = ParserElement._literalStringClass( other ) + if not isinstance( other, ParserElement ): + warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), + SyntaxWarning, stacklevel=2) + return None + return other & self + + def __invert__( self ): + """ + Implementation of ~ operator - returns C{L{NotAny}} + """ + return NotAny( self ) + + def __call__(self, name=None): + """ + Shortcut for C{L{setResultsName}}, with C{listAllMatches=False}. + + If C{name} is given with a trailing C{'*'} character, then C{listAllMatches} will be + passed as C{True}. + + If C{name} is omitted, same as calling C{L{copy}}. + + Example:: + # these are equivalent + userdata = Word(alphas).setResultsName("name") + Word(nums+"-").setResultsName("socsecno") + userdata = Word(alphas)("name") + Word(nums+"-")("socsecno") + """ + if name is not None: + return self.setResultsName(name) + else: + return self.copy() + + def suppress( self ): + """ + Suppresses the output of this C{ParserElement}; useful to keep punctuation from + cluttering up returned output. + """ + return Suppress( self ) + + def leaveWhitespace( self ): + """ + Disables the skipping of whitespace before matching the characters in the + C{ParserElement}'s defined pattern. This is normally only used internally by + the pyparsing module, but may be needed in some whitespace-sensitive grammars. + """ + self.skipWhitespace = False + return self + + def setWhitespaceChars( self, chars ): + """ + Overrides the default whitespace chars + """ + self.skipWhitespace = True + self.whiteChars = chars + self.copyDefaultWhiteChars = False + return self + + def parseWithTabs( self ): + """ + Overrides default behavior to expand C{<TAB>}s to spaces before parsing the input string. + Must be called before C{parseString} when the input grammar contains elements that + match C{<TAB>} characters. + """ + self.keepTabs = True + return self + + def ignore( self, other ): + """ + Define expression to be ignored (e.g., comments) while doing pattern + matching; may be called repeatedly, to define multiple comment or other + ignorable patterns. + + Example:: + patt = OneOrMore(Word(alphas)) + patt.parseString('ablaj /* comment */ lskjd') # -> ['ablaj'] + + patt.ignore(cStyleComment) + patt.parseString('ablaj /* comment */ lskjd') # -> ['ablaj', 'lskjd'] + """ + if isinstance(other, basestring): + other = Suppress(other) + + if isinstance( other, Suppress ): + if other not in self.ignoreExprs: + self.ignoreExprs.append(other) + else: + self.ignoreExprs.append( Suppress( other.copy() ) ) + return self + + def setDebugActions( self, startAction, successAction, exceptionAction ): + """ + Enable display of debugging messages while doing pattern matching. + """ + self.debugActions = (startAction or _defaultStartDebugAction, + successAction or _defaultSuccessDebugAction, + exceptionAction or _defaultExceptionDebugAction) + self.debug = True + return self + + def setDebug( self, flag=True ): + """ + Enable display of debugging messages while doing pattern matching. + Set C{flag} to True to enable, False to disable. + + Example:: + wd = Word(alphas).setName("alphaword") + integer = Word(nums).setName("numword") + term = wd | integer + + # turn on debugging for wd + wd.setDebug() + + OneOrMore(term).parseString("abc 123 xyz 890") + + prints:: + Match alphaword at loc 0(1,1) + Matched alphaword -> ['abc'] + Match alphaword at loc 3(1,4) + Exception raised:Expected alphaword (at char 4), (line:1, col:5) + Match alphaword at loc 7(1,8) + Matched alphaword -> ['xyz'] + Match alphaword at loc 11(1,12) + Exception raised:Expected alphaword (at char 12), (line:1, col:13) + Match alphaword at loc 15(1,16) + Exception raised:Expected alphaword (at char 15), (line:1, col:16) + + The output shown is that produced by the default debug actions - custom debug actions can be + specified using L{setDebugActions}. Prior to attempting + to match the C{wd} expression, the debugging message C{"Match <exprname> at loc <n>(<line>,<col>)"} + is shown. Then if the parse succeeds, a C{"Matched"} message is shown, or an C{"Exception raised"} + message is shown. Also note the use of L{setName} to assign a human-readable name to the expression, + which makes debugging and exception messages easier to understand - for instance, the default + name created for the C{Word} expression without calling C{setName} is C{"W:(ABCD...)"}. + """ + if flag: + self.setDebugActions( _defaultStartDebugAction, _defaultSuccessDebugAction, _defaultExceptionDebugAction ) + else: + self.debug = False + return self + + def __str__( self ): + return self.name + + def __repr__( self ): + return _ustr(self) + + def streamline( self ): + self.streamlined = True + self.strRepr = None + return self + + def checkRecursion( self, parseElementList ): + pass + + def validate( self, validateTrace=[] ): + """ + Check defined expressions for valid structure, check for infinite recursive definitions. + """ + self.checkRecursion( [] ) + + def parseFile( self, file_or_filename, parseAll=False ): + """ + Execute the parse expression on the given file or filename. + If a filename is specified (instead of a file object), + the entire file is opened, read, and closed before parsing. + """ + try: + file_contents = file_or_filename.read() + except AttributeError: + with open(file_or_filename, "r") as f: + file_contents = f.read() + try: + return self.parseString(file_contents, parseAll) + except ParseBaseException as exc: + if ParserElement.verbose_stacktrace: + raise + else: + # catch and re-raise exception from here, clears out pyparsing internal stack trace + raise exc + + def __eq__(self,other): + if isinstance(other, ParserElement): + return self is other or vars(self) == vars(other) + elif isinstance(other, basestring): + return self.matches(other) + else: + return super(ParserElement,self)==other + + def __ne__(self,other): + return not (self == other) + + def __hash__(self): + return hash(id(self)) + + def __req__(self,other): + return self == other + + def __rne__(self,other): + return not (self == other) + + def matches(self, testString, parseAll=True): + """ + Method for quick testing of a parser against a test string. Good for simple + inline microtests of sub expressions while building up larger parser. + + Parameters: + - testString - to test against this expression for a match + - parseAll - (default=C{True}) - flag to pass to C{L{parseString}} when running tests + + Example:: + expr = Word(nums) + assert expr.matches("100") + """ + try: + self.parseString(_ustr(testString), parseAll=parseAll) + return True + except ParseBaseException: + return False + + def runTests(self, tests, parseAll=True, comment='#', fullDump=True, printResults=True, failureTests=False): + """ + Execute the parse expression on a series of test strings, showing each + test, the parsed results or where the parse failed. Quick and easy way to + run a parse expression against a list of sample strings. + + Parameters: + - tests - a list of separate test strings, or a multiline string of test strings + - parseAll - (default=C{True}) - flag to pass to C{L{parseString}} when running tests + - comment - (default=C{'#'}) - expression for indicating embedded comments in the test + string; pass None to disable comment filtering + - fullDump - (default=C{True}) - dump results as list followed by results names in nested outline; + if False, only dump nested list + - printResults - (default=C{True}) prints test output to stdout + - failureTests - (default=C{False}) indicates if these tests are expected to fail parsing + + Returns: a (success, results) tuple, where success indicates that all tests succeeded + (or failed if C{failureTests} is True), and the results contain a list of lines of each + test's output + + Example:: + number_expr = pyparsing_common.number.copy() + + result = number_expr.runTests(''' + # unsigned integer + 100 + # negative integer + -100 + # float with scientific notation + 6.02e23 + # integer with scientific notation + 1e-12 + ''') + print("Success" if result[0] else "Failed!") + + result = number_expr.runTests(''' + # stray character + 100Z + # missing leading digit before '.' + -.100 + # too many '.' + 3.14.159 + ''', failureTests=True) + print("Success" if result[0] else "Failed!") + prints:: + # unsigned integer + 100 + [100] + + # negative integer + -100 + [-100] + + # float with scientific notation + 6.02e23 + [6.02e+23] + + # integer with scientific notation + 1e-12 + [1e-12] + + Success + + # stray character + 100Z + ^ + FAIL: Expected end of text (at char 3), (line:1, col:4) + + # missing leading digit before '.' + -.100 + ^ + FAIL: Expected {real number with scientific notation | real number | signed integer} (at char 0), (line:1, col:1) + + # too many '.' + 3.14.159 + ^ + FAIL: Expected end of text (at char 4), (line:1, col:5) + + Success + + Each test string must be on a single line. If you want to test a string that spans multiple + lines, create a test like this:: + + expr.runTest(r"this is a test\\n of strings that spans \\n 3 lines") + + (Note that this is a raw string literal, you must include the leading 'r'.) + """ + if isinstance(tests, basestring): + tests = list(map(str.strip, tests.rstrip().splitlines())) + if isinstance(comment, basestring): + comment = Literal(comment) + allResults = [] + comments = [] + success = True + for t in tests: + if comment is not None and comment.matches(t, False) or comments and not t: + comments.append(t) + continue + if not t: + continue + out = ['\n'.join(comments), t] + comments = [] + try: + t = t.replace(r'\n','\n') + result = self.parseString(t, parseAll=parseAll) + out.append(result.dump(full=fullDump)) + success = success and not failureTests + except ParseBaseException as pe: + fatal = "(FATAL)" if isinstance(pe, ParseFatalException) else "" + if '\n' in t: + out.append(line(pe.loc, t)) + out.append(' '*(col(pe.loc,t)-1) + '^' + fatal) + else: + out.append(' '*pe.loc + '^' + fatal) + out.append("FAIL: " + str(pe)) + success = success and failureTests + result = pe + except Exception as exc: + out.append("FAIL-EXCEPTION: " + str(exc)) + success = success and failureTests + result = exc + + if printResults: + if fullDump: + out.append('') + print('\n'.join(out)) + + allResults.append((t, result)) + + return success, allResults + + +class Token(ParserElement): + """ + Abstract C{ParserElement} subclass, for defining atomic matching patterns. + """ + def __init__( self ): + super(Token,self).__init__( savelist=False ) + + +class Empty(Token): + """ + An empty token, will always match. + """ + def __init__( self ): + super(Empty,self).__init__() + self.name = "Empty" + self.mayReturnEmpty = True + self.mayIndexError = False + + +class NoMatch(Token): + """ + A token that will never match. + """ + def __init__( self ): + super(NoMatch,self).__init__() + self.name = "NoMatch" + self.mayReturnEmpty = True + self.mayIndexError = False + self.errmsg = "Unmatchable token" + + def parseImpl( self, instring, loc, doActions=True ): + raise ParseException(instring, loc, self.errmsg, self) + + +class Literal(Token): + """ + Token to exactly match a specified string. + + Example:: + Literal('blah').parseString('blah') # -> ['blah'] + Literal('blah').parseString('blahfooblah') # -> ['blah'] + Literal('blah').parseString('bla') # -> Exception: Expected "blah" + + For case-insensitive matching, use L{CaselessLiteral}. + + For keyword matching (force word break before and after the matched string), + use L{Keyword} or L{CaselessKeyword}. + """ + def __init__( self, matchString ): + super(Literal,self).__init__() + self.match = matchString + self.matchLen = len(matchString) + try: + self.firstMatchChar = matchString[0] + except IndexError: + warnings.warn("null string passed to Literal; use Empty() instead", + SyntaxWarning, stacklevel=2) + self.__class__ = Empty + self.name = '"%s"' % _ustr(self.match) + self.errmsg = "Expected " + self.name + self.mayReturnEmpty = False + self.mayIndexError = False + + # Performance tuning: this routine gets called a *lot* + # if this is a single character match string and the first character matches, + # short-circuit as quickly as possible, and avoid calling startswith + #~ @profile + def parseImpl( self, instring, loc, doActions=True ): + if (instring[loc] == self.firstMatchChar and + (self.matchLen==1 or instring.startswith(self.match,loc)) ): + return loc+self.matchLen, self.match + raise ParseException(instring, loc, self.errmsg, self) +_L = Literal +ParserElement._literalStringClass = Literal + +class Keyword(Token): + """ + Token to exactly match a specified string as a keyword, that is, it must be + immediately followed by a non-keyword character. Compare with C{L{Literal}}: + - C{Literal("if")} will match the leading C{'if'} in C{'ifAndOnlyIf'}. + - C{Keyword("if")} will not; it will only match the leading C{'if'} in C{'if x=1'}, or C{'if(y==2)'} + Accepts two optional constructor arguments in addition to the keyword string: + - C{identChars} is a string of characters that would be valid identifier characters, + defaulting to all alphanumerics + "_" and "$" + - C{caseless} allows case-insensitive matching, default is C{False}. + + Example:: + Keyword("start").parseString("start") # -> ['start'] + Keyword("start").parseString("starting") # -> Exception + + For case-insensitive matching, use L{CaselessKeyword}. + """ + DEFAULT_KEYWORD_CHARS = alphanums+"_$" + + def __init__( self, matchString, identChars=None, caseless=False ): + super(Keyword,self).__init__() + if identChars is None: + identChars = Keyword.DEFAULT_KEYWORD_CHARS + self.match = matchString + self.matchLen = len(matchString) + try: + self.firstMatchChar = matchString[0] + except IndexError: + warnings.warn("null string passed to Keyword; use Empty() instead", + SyntaxWarning, stacklevel=2) + self.name = '"%s"' % self.match + self.errmsg = "Expected " + self.name + self.mayReturnEmpty = False + self.mayIndexError = False + self.caseless = caseless + if caseless: + self.caselessmatch = matchString.upper() + identChars = identChars.upper() + self.identChars = set(identChars) + + def parseImpl( self, instring, loc, doActions=True ): + if self.caseless: + if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and + (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) and + (loc == 0 or instring[loc-1].upper() not in self.identChars) ): + return loc+self.matchLen, self.match + else: + if (instring[loc] == self.firstMatchChar and + (self.matchLen==1 or instring.startswith(self.match,loc)) and + (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen] not in self.identChars) and + (loc == 0 or instring[loc-1] not in self.identChars) ): + return loc+self.matchLen, self.match + raise ParseException(instring, loc, self.errmsg, self) + + def copy(self): + c = super(Keyword,self).copy() + c.identChars = Keyword.DEFAULT_KEYWORD_CHARS + return c + + @staticmethod + def setDefaultKeywordChars( chars ): + """Overrides the default Keyword chars + """ + Keyword.DEFAULT_KEYWORD_CHARS = chars + +class CaselessLiteral(Literal): + """ + Token to match a specified string, ignoring case of letters. + Note: the matched results will always be in the case of the given + match string, NOT the case of the input text. + + Example:: + OneOrMore(CaselessLiteral("CMD")).parseString("cmd CMD Cmd10") # -> ['CMD', 'CMD', 'CMD'] + + (Contrast with example for L{CaselessKeyword}.) + """ + def __init__( self, matchString ): + super(CaselessLiteral,self).__init__( matchString.upper() ) + # Preserve the defining literal. + self.returnString = matchString + self.name = "'%s'" % self.returnString + self.errmsg = "Expected " + self.name + + def parseImpl( self, instring, loc, doActions=True ): + if instring[ loc:loc+self.matchLen ].upper() == self.match: + return loc+self.matchLen, self.returnString + raise ParseException(instring, loc, self.errmsg, self) + +class CaselessKeyword(Keyword): + """ + Caseless version of L{Keyword}. + + Example:: + OneOrMore(CaselessKeyword("CMD")).parseString("cmd CMD Cmd10") # -> ['CMD', 'CMD'] + + (Contrast with example for L{CaselessLiteral}.) + """ + def __init__( self, matchString, identChars=None ): + super(CaselessKeyword,self).__init__( matchString, identChars, caseless=True ) + + def parseImpl( self, instring, loc, doActions=True ): + if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and + (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) ): + return loc+self.matchLen, self.match + raise ParseException(instring, loc, self.errmsg, self) + +class CloseMatch(Token): + """ + A variation on L{Literal} which matches "close" matches, that is, + strings with at most 'n' mismatching characters. C{CloseMatch} takes parameters: + - C{match_string} - string to be matched + - C{maxMismatches} - (C{default=1}) maximum number of mismatches allowed to count as a match + + The results from a successful parse will contain the matched text from the input string and the following named results: + - C{mismatches} - a list of the positions within the match_string where mismatches were found + - C{original} - the original match_string used to compare against the input string + + If C{mismatches} is an empty list, then the match was an exact match. + + Example:: + patt = CloseMatch("ATCATCGAATGGA") + patt.parseString("ATCATCGAAXGGA") # -> (['ATCATCGAAXGGA'], {'mismatches': [[9]], 'original': ['ATCATCGAATGGA']}) + patt.parseString("ATCAXCGAAXGGA") # -> Exception: Expected 'ATCATCGAATGGA' (with up to 1 mismatches) (at char 0), (line:1, col:1) + + # exact match + patt.parseString("ATCATCGAATGGA") # -> (['ATCATCGAATGGA'], {'mismatches': [[]], 'original': ['ATCATCGAATGGA']}) + + # close match allowing up to 2 mismatches + patt = CloseMatch("ATCATCGAATGGA", maxMismatches=2) + patt.parseString("ATCAXCGAAXGGA") # -> (['ATCAXCGAAXGGA'], {'mismatches': [[4, 9]], 'original': ['ATCATCGAATGGA']}) + """ + def __init__(self, match_string, maxMismatches=1): + super(CloseMatch,self).__init__() + self.name = match_string + self.match_string = match_string + self.maxMismatches = maxMismatches + self.errmsg = "Expected %r (with up to %d mismatches)" % (self.match_string, self.maxMismatches) + self.mayIndexError = False + self.mayReturnEmpty = False + + def parseImpl( self, instring, loc, doActions=True ): + start = loc + instrlen = len(instring) + maxloc = start + len(self.match_string) + + if maxloc <= instrlen: + match_string = self.match_string + match_stringloc = 0 + mismatches = [] + maxMismatches = self.maxMismatches + + for match_stringloc,s_m in enumerate(zip(instring[loc:maxloc], self.match_string)): + src,mat = s_m + if src != mat: + mismatches.append(match_stringloc) + if len(mismatches) > maxMismatches: + break + else: + loc = match_stringloc + 1 + results = ParseResults([instring[start:loc]]) + results['original'] = self.match_string + results['mismatches'] = mismatches + return loc, results + + raise ParseException(instring, loc, self.errmsg, self) + + +class Word(Token): + """ + Token for matching words composed of allowed character sets. + Defined with string containing all allowed initial characters, + an optional string containing allowed body characters (if omitted, + defaults to the initial character set), and an optional minimum, + maximum, and/or exact length. The default value for C{min} is 1 (a + minimum value < 1 is not valid); the default values for C{max} and C{exact} + are 0, meaning no maximum or exact length restriction. An optional + C{excludeChars} parameter can list characters that might be found in + the input C{bodyChars} string; useful to define a word of all printables + except for one or two characters, for instance. + + L{srange} is useful for defining custom character set strings for defining + C{Word} expressions, using range notation from regular expression character sets. + + A common mistake is to use C{Word} to match a specific literal string, as in + C{Word("Address")}. Remember that C{Word} uses the string argument to define + I{sets} of matchable characters. This expression would match "Add", "AAA", + "dAred", or any other word made up of the characters 'A', 'd', 'r', 'e', and 's'. + To match an exact literal string, use L{Literal} or L{Keyword}. + + pyparsing includes helper strings for building Words: + - L{alphas} + - L{nums} + - L{alphanums} + - L{hexnums} + - L{alphas8bit} (alphabetic characters in ASCII range 128-255 - accented, tilded, umlauted, etc.) + - L{punc8bit} (non-alphabetic characters in ASCII range 128-255 - currency, symbols, superscripts, diacriticals, etc.) + - L{printables} (any non-whitespace character) + + Example:: + # a word composed of digits + integer = Word(nums) # equivalent to Word("0123456789") or Word(srange("0-9")) + + # a word with a leading capital, and zero or more lowercase + capital_word = Word(alphas.upper(), alphas.lower()) + + # hostnames are alphanumeric, with leading alpha, and '-' + hostname = Word(alphas, alphanums+'-') + + # roman numeral (not a strict parser, accepts invalid mix of characters) + roman = Word("IVXLCDM") + + # any string of non-whitespace characters, except for ',' + csv_value = Word(printables, excludeChars=",") + """ + def __init__( self, initChars, bodyChars=None, min=1, max=0, exact=0, asKeyword=False, excludeChars=None ): + super(Word,self).__init__() + if excludeChars: + initChars = ''.join(c for c in initChars if c not in excludeChars) + if bodyChars: + bodyChars = ''.join(c for c in bodyChars if c not in excludeChars) + self.initCharsOrig = initChars + self.initChars = set(initChars) + if bodyChars : + self.bodyCharsOrig = bodyChars + self.bodyChars = set(bodyChars) + else: + self.bodyCharsOrig = initChars + self.bodyChars = set(initChars) + + self.maxSpecified = max > 0 + + if min < 1: + raise ValueError("cannot specify a minimum length < 1; use Optional(Word()) if zero-length word is permitted") + + self.minLen = min + + if max > 0: + self.maxLen = max + else: + self.maxLen = _MAX_INT + + if exact > 0: + self.maxLen = exact + self.minLen = exact + + self.name = _ustr(self) + self.errmsg = "Expected " + self.name + self.mayIndexError = False + self.asKeyword = asKeyword + + if ' ' not in self.initCharsOrig+self.bodyCharsOrig and (min==1 and max==0 and exact==0): + if self.bodyCharsOrig == self.initCharsOrig: + self.reString = "[%s]+" % _escapeRegexRangeChars(self.initCharsOrig) + elif len(self.initCharsOrig) == 1: + self.reString = "%s[%s]*" % \ + (re.escape(self.initCharsOrig), + _escapeRegexRangeChars(self.bodyCharsOrig),) + else: + self.reString = "[%s][%s]*" % \ + (_escapeRegexRangeChars(self.initCharsOrig), + _escapeRegexRangeChars(self.bodyCharsOrig),) + if self.asKeyword: + self.reString = r"\b"+self.reString+r"\b" + try: + self.re = re.compile( self.reString ) + except Exception: + self.re = None + + def parseImpl( self, instring, loc, doActions=True ): + if self.re: + result = self.re.match(instring,loc) + if not result: + raise ParseException(instring, loc, self.errmsg, self) + + loc = result.end() + return loc, result.group() + + if not(instring[ loc ] in self.initChars): + raise ParseException(instring, loc, self.errmsg, self) + + start = loc + loc += 1 + instrlen = len(instring) + bodychars = self.bodyChars + maxloc = start + self.maxLen + maxloc = min( maxloc, instrlen ) + while loc < maxloc and instring[loc] in bodychars: + loc += 1 + + throwException = False + if loc - start < self.minLen: + throwException = True + if self.maxSpecified and loc < instrlen and instring[loc] in bodychars: + throwException = True + if self.asKeyword: + if (start>0 and instring[start-1] in bodychars) or (loc<instrlen and instring[loc] in bodychars): + throwException = True + + if throwException: + raise ParseException(instring, loc, self.errmsg, self) + + return loc, instring[start:loc] + + def __str__( self ): + try: + return super(Word,self).__str__() + except Exception: + pass + + + if self.strRepr is None: + + def charsAsStr(s): + if len(s)>4: + return s[:4]+"..." + else: + return s + + if ( self.initCharsOrig != self.bodyCharsOrig ): + self.strRepr = "W:(%s,%s)" % ( charsAsStr(self.initCharsOrig), charsAsStr(self.bodyCharsOrig) ) + else: + self.strRepr = "W:(%s)" % charsAsStr(self.initCharsOrig) + + return self.strRepr + + +class Regex(Token): + r""" + Token for matching strings that match a given regular expression. + Defined with string specifying the regular expression in a form recognized by the inbuilt Python re module. + If the given regex contains named groups (defined using C{(?P<name>...)}), these will be preserved as + named parse results. + + Example:: + realnum = Regex(r"[+-]?\d+\.\d*") + date = Regex(r'(?P<year>\d{4})-(?P<month>\d\d?)-(?P<day>\d\d?)') + # ref: http://stackoverflow.com/questions/267399/how-do-you-match-only-valid-roman-numerals-with-a-regular-expression + roman = Regex(r"M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})") + """ + compiledREtype = type(re.compile("[A-Z]")) + def __init__( self, pattern, flags=0): + """The parameters C{pattern} and C{flags} are passed to the C{re.compile()} function as-is. See the Python C{re} module for an explanation of the acceptable patterns and flags.""" + super(Regex,self).__init__() + + if isinstance(pattern, basestring): + if not pattern: + warnings.warn("null string passed to Regex; use Empty() instead", + SyntaxWarning, stacklevel=2) + + self.pattern = pattern + self.flags = flags + + try: + self.re = re.compile(self.pattern, self.flags) + self.reString = self.pattern + except sre_constants.error: + warnings.warn("invalid pattern (%s) passed to Regex" % pattern, + SyntaxWarning, stacklevel=2) + raise + + elif isinstance(pattern, Regex.compiledREtype): + self.re = pattern + self.pattern = \ + self.reString = str(pattern) + self.flags = flags + + else: + raise ValueError("Regex may only be constructed with a string or a compiled RE object") + + self.name = _ustr(self) + self.errmsg = "Expected " + self.name + self.mayIndexError = False + self.mayReturnEmpty = True + + def parseImpl( self, instring, loc, doActions=True ): + result = self.re.match(instring,loc) + if not result: + raise ParseException(instring, loc, self.errmsg, self) + + loc = result.end() + d = result.groupdict() + ret = ParseResults(result.group()) + if d: + for k in d: + ret[k] = d[k] + return loc,ret + + def __str__( self ): + try: + return super(Regex,self).__str__() + except Exception: + pass + + if self.strRepr is None: + self.strRepr = "Re:(%s)" % repr(self.pattern) + + return self.strRepr + + +class QuotedString(Token): + r""" + Token for matching strings that are delimited by quoting characters. + + Defined with the following parameters: + - quoteChar - string of one or more characters defining the quote delimiting string + - escChar - character to escape quotes, typically backslash (default=C{None}) + - escQuote - special quote sequence to escape an embedded quote string (such as SQL's "" to escape an embedded ") (default=C{None}) + - multiline - boolean indicating whether quotes can span multiple lines (default=C{False}) + - unquoteResults - boolean indicating whether the matched text should be unquoted (default=C{True}) + - endQuoteChar - string of one or more characters defining the end of the quote delimited string (default=C{None} => same as quoteChar) + - convertWhitespaceEscapes - convert escaped whitespace (C{'\t'}, C{'\n'}, etc.) to actual whitespace (default=C{True}) + + Example:: + qs = QuotedString('"') + print(qs.searchString('lsjdf "This is the quote" sldjf')) + complex_qs = QuotedString('{{', endQuoteChar='}}') + print(complex_qs.searchString('lsjdf {{This is the "quote"}} sldjf')) + sql_qs = QuotedString('"', escQuote='""') + print(sql_qs.searchString('lsjdf "This is the quote with ""embedded"" quotes" sldjf')) + prints:: + [['This is the quote']] + [['This is the "quote"']] + [['This is the quote with "embedded" quotes']] + """ + def __init__( self, quoteChar, escChar=None, escQuote=None, multiline=False, unquoteResults=True, endQuoteChar=None, convertWhitespaceEscapes=True): + super(QuotedString,self).__init__() + + # remove white space from quote chars - wont work anyway + quoteChar = quoteChar.strip() + if not quoteChar: + warnings.warn("quoteChar cannot be the empty string",SyntaxWarning,stacklevel=2) + raise SyntaxError() + + if endQuoteChar is None: + endQuoteChar = quoteChar + else: + endQuoteChar = endQuoteChar.strip() + if not endQuoteChar: + warnings.warn("endQuoteChar cannot be the empty string",SyntaxWarning,stacklevel=2) + raise SyntaxError() + + self.quoteChar = quoteChar + self.quoteCharLen = len(quoteChar) + self.firstQuoteChar = quoteChar[0] + self.endQuoteChar = endQuoteChar + self.endQuoteCharLen = len(endQuoteChar) + self.escChar = escChar + self.escQuote = escQuote + self.unquoteResults = unquoteResults + self.convertWhitespaceEscapes = convertWhitespaceEscapes + + if multiline: + self.flags = re.MULTILINE | re.DOTALL + self.pattern = r'%s(?:[^%s%s]' % \ + ( re.escape(self.quoteChar), + _escapeRegexRangeChars(self.endQuoteChar[0]), + (escChar is not None and _escapeRegexRangeChars(escChar) or '') ) + else: + self.flags = 0 + self.pattern = r'%s(?:[^%s\n\r%s]' % \ + ( re.escape(self.quoteChar), + _escapeRegexRangeChars(self.endQuoteChar[0]), + (escChar is not None and _escapeRegexRangeChars(escChar) or '') ) + if len(self.endQuoteChar) > 1: + self.pattern += ( + '|(?:' + ')|(?:'.join("%s[^%s]" % (re.escape(self.endQuoteChar[:i]), + _escapeRegexRangeChars(self.endQuoteChar[i])) + for i in range(len(self.endQuoteChar)-1,0,-1)) + ')' + ) + if escQuote: + self.pattern += (r'|(?:%s)' % re.escape(escQuote)) + if escChar: + self.pattern += (r'|(?:%s.)' % re.escape(escChar)) + self.escCharReplacePattern = re.escape(self.escChar)+"(.)" + self.pattern += (r')*%s' % re.escape(self.endQuoteChar)) + + try: + self.re = re.compile(self.pattern, self.flags) + self.reString = self.pattern + except sre_constants.error: + warnings.warn("invalid pattern (%s) passed to Regex" % self.pattern, + SyntaxWarning, stacklevel=2) + raise + + self.name = _ustr(self) + self.errmsg = "Expected " + self.name + self.mayIndexError = False + self.mayReturnEmpty = True + + def parseImpl( self, instring, loc, doActions=True ): + result = instring[loc] == self.firstQuoteChar and self.re.match(instring,loc) or None + if not result: + raise ParseException(instring, loc, self.errmsg, self) + + loc = result.end() + ret = result.group() + + if self.unquoteResults: + + # strip off quotes + ret = ret[self.quoteCharLen:-self.endQuoteCharLen] + + if isinstance(ret,basestring): + # replace escaped whitespace + if '\\' in ret and self.convertWhitespaceEscapes: + ws_map = { + r'\t' : '\t', + r'\n' : '\n', + r'\f' : '\f', + r'\r' : '\r', + } + for wslit,wschar in ws_map.items(): + ret = ret.replace(wslit, wschar) + + # replace escaped characters + if self.escChar: + ret = re.sub(self.escCharReplacePattern, r"\g<1>", ret) + + # replace escaped quotes + if self.escQuote: + ret = ret.replace(self.escQuote, self.endQuoteChar) + + return loc, ret + + def __str__( self ): + try: + return super(QuotedString,self).__str__() + except Exception: + pass + + if self.strRepr is None: + self.strRepr = "quoted string, starting with %s ending with %s" % (self.quoteChar, self.endQuoteChar) + + return self.strRepr + + +class CharsNotIn(Token): + """ + Token for matching words composed of characters I{not} in a given set (will + include whitespace in matched characters if not listed in the provided exclusion set - see example). + Defined with string containing all disallowed characters, and an optional + minimum, maximum, and/or exact length. The default value for C{min} is 1 (a + minimum value < 1 is not valid); the default values for C{max} and C{exact} + are 0, meaning no maximum or exact length restriction. + + Example:: + # define a comma-separated-value as anything that is not a ',' + csv_value = CharsNotIn(',') + print(delimitedList(csv_value).parseString("dkls,lsdkjf,s12 34,@!#,213")) + prints:: + ['dkls', 'lsdkjf', 's12 34', '@!#', '213'] + """ + def __init__( self, notChars, min=1, max=0, exact=0 ): + super(CharsNotIn,self).__init__() + self.skipWhitespace = False + self.notChars = notChars + + if min < 1: + raise ValueError("cannot specify a minimum length < 1; use Optional(CharsNotIn()) if zero-length char group is permitted") + + self.minLen = min + + if max > 0: + self.maxLen = max + else: + self.maxLen = _MAX_INT + + if exact > 0: + self.maxLen = exact + self.minLen = exact + + self.name = _ustr(self) + self.errmsg = "Expected " + self.name + self.mayReturnEmpty = ( self.minLen == 0 ) + self.mayIndexError = False + + def parseImpl( self, instring, loc, doActions=True ): + if instring[loc] in self.notChars: + raise ParseException(instring, loc, self.errmsg, self) + + start = loc + loc += 1 + notchars = self.notChars + maxlen = min( start+self.maxLen, len(instring) ) + while loc < maxlen and \ + (instring[loc] not in notchars): + loc += 1 + + if loc - start < self.minLen: + raise ParseException(instring, loc, self.errmsg, self) + + return loc, instring[start:loc] + + def __str__( self ): + try: + return super(CharsNotIn, self).__str__() + except Exception: + pass + + if self.strRepr is None: + if len(self.notChars) > 4: + self.strRepr = "!W:(%s...)" % self.notChars[:4] + else: + self.strRepr = "!W:(%s)" % self.notChars + + return self.strRepr + +class White(Token): + """ + Special matching class for matching whitespace. Normally, whitespace is ignored + by pyparsing grammars. This class is included when some whitespace structures + are significant. Define with a string containing the whitespace characters to be + matched; default is C{" \\t\\r\\n"}. Also takes optional C{min}, C{max}, and C{exact} arguments, + as defined for the C{L{Word}} class. + """ + whiteStrs = { + " " : "<SPC>", + "\t": "<TAB>", + "\n": "<LF>", + "\r": "<CR>", + "\f": "<FF>", + } + def __init__(self, ws=" \t\r\n", min=1, max=0, exact=0): + super(White,self).__init__() + self.matchWhite = ws + self.setWhitespaceChars( "".join(c for c in self.whiteChars if c not in self.matchWhite) ) + #~ self.leaveWhitespace() + self.name = ("".join(White.whiteStrs[c] for c in self.matchWhite)) + self.mayReturnEmpty = True + self.errmsg = "Expected " + self.name + + self.minLen = min + + if max > 0: + self.maxLen = max + else: + self.maxLen = _MAX_INT + + if exact > 0: + self.maxLen = exact + self.minLen = exact + + def parseImpl( self, instring, loc, doActions=True ): + if not(instring[ loc ] in self.matchWhite): + raise ParseException(instring, loc, self.errmsg, self) + start = loc + loc += 1 + maxloc = start + self.maxLen + maxloc = min( maxloc, len(instring) ) + while loc < maxloc and instring[loc] in self.matchWhite: + loc += 1 + + if loc - start < self.minLen: + raise ParseException(instring, loc, self.errmsg, self) + + return loc, instring[start:loc] + + +class _PositionToken(Token): + def __init__( self ): + super(_PositionToken,self).__init__() + self.name=self.__class__.__name__ + self.mayReturnEmpty = True + self.mayIndexError = False + +class GoToColumn(_PositionToken): + """ + Token to advance to a specific column of input text; useful for tabular report scraping. + """ + def __init__( self, colno ): + super(GoToColumn,self).__init__() + self.col = colno + + def preParse( self, instring, loc ): + if col(loc,instring) != self.col: + instrlen = len(instring) + if self.ignoreExprs: + loc = self._skipIgnorables( instring, loc ) + while loc < instrlen and instring[loc].isspace() and col( loc, instring ) != self.col : + loc += 1 + return loc + + def parseImpl( self, instring, loc, doActions=True ): + thiscol = col( loc, instring ) + if thiscol > self.col: + raise ParseException( instring, loc, "Text not in expected column", self ) + newloc = loc + self.col - thiscol + ret = instring[ loc: newloc ] + return newloc, ret + + +class LineStart(_PositionToken): + """ + Matches if current position is at the beginning of a line within the parse string + + Example:: + + test = '''\ + AAA this line + AAA and this line + AAA but not this one + B AAA and definitely not this one + ''' + + for t in (LineStart() + 'AAA' + restOfLine).searchString(test): + print(t) + + Prints:: + ['AAA', ' this line'] + ['AAA', ' and this line'] + + """ + def __init__( self ): + super(LineStart,self).__init__() + self.errmsg = "Expected start of line" + + def parseImpl( self, instring, loc, doActions=True ): + if col(loc, instring) == 1: + return loc, [] + raise ParseException(instring, loc, self.errmsg, self) + +class LineEnd(_PositionToken): + """ + Matches if current position is at the end of a line within the parse string + """ + def __init__( self ): + super(LineEnd,self).__init__() + self.setWhitespaceChars( ParserElement.DEFAULT_WHITE_CHARS.replace("\n","") ) + self.errmsg = "Expected end of line" + + def parseImpl( self, instring, loc, doActions=True ): + if loc<len(instring): + if instring[loc] == "\n": + return loc+1, "\n" + else: + raise ParseException(instring, loc, self.errmsg, self) + elif loc == len(instring): + return loc+1, [] + else: + raise ParseException(instring, loc, self.errmsg, self) + +class StringStart(_PositionToken): + """ + Matches if current position is at the beginning of the parse string + """ + def __init__( self ): + super(StringStart,self).__init__() + self.errmsg = "Expected start of text" + + def parseImpl( self, instring, loc, doActions=True ): + if loc != 0: + # see if entire string up to here is just whitespace and ignoreables + if loc != self.preParse( instring, 0 ): + raise ParseException(instring, loc, self.errmsg, self) + return loc, [] + +class StringEnd(_PositionToken): + """ + Matches if current position is at the end of the parse string + """ + def __init__( self ): + super(StringEnd,self).__init__() + self.errmsg = "Expected end of text" + + def parseImpl( self, instring, loc, doActions=True ): + if loc < len(instring): + raise ParseException(instring, loc, self.errmsg, self) + elif loc == len(instring): + return loc+1, [] + elif loc > len(instring): + return loc, [] + else: + raise ParseException(instring, loc, self.errmsg, self) + +class WordStart(_PositionToken): + """ + Matches if the current position is at the beginning of a Word, and + is not preceded by any character in a given set of C{wordChars} + (default=C{printables}). To emulate the C{\b} behavior of regular expressions, + use C{WordStart(alphanums)}. C{WordStart} will also match at the beginning of + the string being parsed, or at the beginning of a line. + """ + def __init__(self, wordChars = printables): + super(WordStart,self).__init__() + self.wordChars = set(wordChars) + self.errmsg = "Not at the start of a word" + + def parseImpl(self, instring, loc, doActions=True ): + if loc != 0: + if (instring[loc-1] in self.wordChars or + instring[loc] not in self.wordChars): + raise ParseException(instring, loc, self.errmsg, self) + return loc, [] + +class WordEnd(_PositionToken): + """ + Matches if the current position is at the end of a Word, and + is not followed by any character in a given set of C{wordChars} + (default=C{printables}). To emulate the C{\b} behavior of regular expressions, + use C{WordEnd(alphanums)}. C{WordEnd} will also match at the end of + the string being parsed, or at the end of a line. + """ + def __init__(self, wordChars = printables): + super(WordEnd,self).__init__() + self.wordChars = set(wordChars) + self.skipWhitespace = False + self.errmsg = "Not at the end of a word" + + def parseImpl(self, instring, loc, doActions=True ): + instrlen = len(instring) + if instrlen>0 and loc<instrlen: + if (instring[loc] in self.wordChars or + instring[loc-1] not in self.wordChars): + raise ParseException(instring, loc, self.errmsg, self) + return loc, [] + + +class ParseExpression(ParserElement): + """ + Abstract subclass of ParserElement, for combining and post-processing parsed tokens. + """ + def __init__( self, exprs, savelist = False ): + super(ParseExpression,self).__init__(savelist) + if isinstance( exprs, _generatorType ): + exprs = list(exprs) + + if isinstance( exprs, basestring ): + self.exprs = [ ParserElement._literalStringClass( exprs ) ] + elif isinstance( exprs, Iterable ): + exprs = list(exprs) + # if sequence of strings provided, wrap with Literal + if all(isinstance(expr, basestring) for expr in exprs): + exprs = map(ParserElement._literalStringClass, exprs) + self.exprs = list(exprs) + else: + try: + self.exprs = list( exprs ) + except TypeError: + self.exprs = [ exprs ] + self.callPreparse = False + + def __getitem__( self, i ): + return self.exprs[i] + + def append( self, other ): + self.exprs.append( other ) + self.strRepr = None + return self + + def leaveWhitespace( self ): + """Extends C{leaveWhitespace} defined in base class, and also invokes C{leaveWhitespace} on + all contained expressions.""" + self.skipWhitespace = False + self.exprs = [ e.copy() for e in self.exprs ] + for e in self.exprs: + e.leaveWhitespace() + return self + + def ignore( self, other ): + if isinstance( other, Suppress ): + if other not in self.ignoreExprs: + super( ParseExpression, self).ignore( other ) + for e in self.exprs: + e.ignore( self.ignoreExprs[-1] ) + else: + super( ParseExpression, self).ignore( other ) + for e in self.exprs: + e.ignore( self.ignoreExprs[-1] ) + return self + + def __str__( self ): + try: + return super(ParseExpression,self).__str__() + except Exception: + pass + + if self.strRepr is None: + self.strRepr = "%s:(%s)" % ( self.__class__.__name__, _ustr(self.exprs) ) + return self.strRepr + + def streamline( self ): + super(ParseExpression,self).streamline() + + for e in self.exprs: + e.streamline() + + # collapse nested And's of the form And( And( And( a,b), c), d) to And( a,b,c,d ) + # but only if there are no parse actions or resultsNames on the nested And's + # (likewise for Or's and MatchFirst's) + if ( len(self.exprs) == 2 ): + other = self.exprs[0] + if ( isinstance( other, self.__class__ ) and + not(other.parseAction) and + other.resultsName is None and + not other.debug ): + self.exprs = other.exprs[:] + [ self.exprs[1] ] + self.strRepr = None + self.mayReturnEmpty |= other.mayReturnEmpty + self.mayIndexError |= other.mayIndexError + + other = self.exprs[-1] + if ( isinstance( other, self.__class__ ) and + not(other.parseAction) and + other.resultsName is None and + not other.debug ): + self.exprs = self.exprs[:-1] + other.exprs[:] + self.strRepr = None + self.mayReturnEmpty |= other.mayReturnEmpty + self.mayIndexError |= other.mayIndexError + + self.errmsg = "Expected " + _ustr(self) + + return self + + def setResultsName( self, name, listAllMatches=False ): + ret = super(ParseExpression,self).setResultsName(name,listAllMatches) + return ret + + def validate( self, validateTrace=[] ): + tmp = validateTrace[:]+[self] + for e in self.exprs: + e.validate(tmp) + self.checkRecursion( [] ) + + def copy(self): + ret = super(ParseExpression,self).copy() + ret.exprs = [e.copy() for e in self.exprs] + return ret + +class And(ParseExpression): + """ + Requires all given C{ParseExpression}s to be found in the given order. + Expressions may be separated by whitespace. + May be constructed using the C{'+'} operator. + May also be constructed using the C{'-'} operator, which will suppress backtracking. + + Example:: + integer = Word(nums) + name_expr = OneOrMore(Word(alphas)) + + expr = And([integer("id"),name_expr("name"),integer("age")]) + # more easily written as: + expr = integer("id") + name_expr("name") + integer("age") + """ + + class _ErrorStop(Empty): + def __init__(self, *args, **kwargs): + super(And._ErrorStop,self).__init__(*args, **kwargs) + self.name = '-' + self.leaveWhitespace() + + def __init__( self, exprs, savelist = True ): + super(And,self).__init__(exprs, savelist) + self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs) + self.setWhitespaceChars( self.exprs[0].whiteChars ) + self.skipWhitespace = self.exprs[0].skipWhitespace + self.callPreparse = True + + def parseImpl( self, instring, loc, doActions=True ): + # pass False as last arg to _parse for first element, since we already + # pre-parsed the string as part of our And pre-parsing + loc, resultlist = self.exprs[0]._parse( instring, loc, doActions, callPreParse=False ) + errorStop = False + for e in self.exprs[1:]: + if isinstance(e, And._ErrorStop): + errorStop = True + continue + if errorStop: + try: + loc, exprtokens = e._parse( instring, loc, doActions ) + except ParseSyntaxException: + raise + except ParseBaseException as pe: + pe.__traceback__ = None + raise ParseSyntaxException._from_exception(pe) + except IndexError: + raise ParseSyntaxException(instring, len(instring), self.errmsg, self) + else: + loc, exprtokens = e._parse( instring, loc, doActions ) + if exprtokens or exprtokens.haskeys(): + resultlist += exprtokens + return loc, resultlist + + def __iadd__(self, other ): + if isinstance( other, basestring ): + other = ParserElement._literalStringClass( other ) + return self.append( other ) #And( [ self, other ] ) + + def checkRecursion( self, parseElementList ): + subRecCheckList = parseElementList[:] + [ self ] + for e in self.exprs: + e.checkRecursion( subRecCheckList ) + if not e.mayReturnEmpty: + break + + def __str__( self ): + if hasattr(self,"name"): + return self.name + + if self.strRepr is None: + self.strRepr = "{" + " ".join(_ustr(e) for e in self.exprs) + "}" + + return self.strRepr + + +class Or(ParseExpression): + """ + Requires that at least one C{ParseExpression} is found. + If two expressions match, the expression that matches the longest string will be used. + May be constructed using the C{'^'} operator. + + Example:: + # construct Or using '^' operator + + number = Word(nums) ^ Combine(Word(nums) + '.' + Word(nums)) + print(number.searchString("123 3.1416 789")) + prints:: + [['123'], ['3.1416'], ['789']] + """ + def __init__( self, exprs, savelist = False ): + super(Or,self).__init__(exprs, savelist) + if self.exprs: + self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs) + else: + self.mayReturnEmpty = True + + def parseImpl( self, instring, loc, doActions=True ): + maxExcLoc = -1 + maxException = None + matches = [] + for e in self.exprs: + try: + loc2 = e.tryParse( instring, loc ) + except ParseException as err: + err.__traceback__ = None + if err.loc > maxExcLoc: + maxException = err + maxExcLoc = err.loc + except IndexError: + if len(instring) > maxExcLoc: + maxException = ParseException(instring,len(instring),e.errmsg,self) + maxExcLoc = len(instring) + else: + # save match among all matches, to retry longest to shortest + matches.append((loc2, e)) + + if matches: + matches.sort(key=lambda x: -x[0]) + for _,e in matches: + try: + return e._parse( instring, loc, doActions ) + except ParseException as err: + err.__traceback__ = None + if err.loc > maxExcLoc: + maxException = err + maxExcLoc = err.loc + + if maxException is not None: + maxException.msg = self.errmsg + raise maxException + else: + raise ParseException(instring, loc, "no defined alternatives to match", self) + + + def __ixor__(self, other ): + if isinstance( other, basestring ): + other = ParserElement._literalStringClass( other ) + return self.append( other ) #Or( [ self, other ] ) + + def __str__( self ): + if hasattr(self,"name"): + return self.name + + if self.strRepr is None: + self.strRepr = "{" + " ^ ".join(_ustr(e) for e in self.exprs) + "}" + + return self.strRepr + + def checkRecursion( self, parseElementList ): + subRecCheckList = parseElementList[:] + [ self ] + for e in self.exprs: + e.checkRecursion( subRecCheckList ) + + +class MatchFirst(ParseExpression): + """ + Requires that at least one C{ParseExpression} is found. + If two expressions match, the first one listed is the one that will match. + May be constructed using the C{'|'} operator. + + Example:: + # construct MatchFirst using '|' operator + + # watch the order of expressions to match + number = Word(nums) | Combine(Word(nums) + '.' + Word(nums)) + print(number.searchString("123 3.1416 789")) # Fail! -> [['123'], ['3'], ['1416'], ['789']] + + # put more selective expression first + number = Combine(Word(nums) + '.' + Word(nums)) | Word(nums) + print(number.searchString("123 3.1416 789")) # Better -> [['123'], ['3.1416'], ['789']] + """ + def __init__( self, exprs, savelist = False ): + super(MatchFirst,self).__init__(exprs, savelist) + if self.exprs: + self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs) + else: + self.mayReturnEmpty = True + + def parseImpl( self, instring, loc, doActions=True ): + maxExcLoc = -1 + maxException = None + for e in self.exprs: + try: + ret = e._parse( instring, loc, doActions ) + return ret + except ParseException as err: + if err.loc > maxExcLoc: + maxException = err + maxExcLoc = err.loc + except IndexError: + if len(instring) > maxExcLoc: + maxException = ParseException(instring,len(instring),e.errmsg,self) + maxExcLoc = len(instring) + + # only got here if no expression matched, raise exception for match that made it the furthest + else: + if maxException is not None: + maxException.msg = self.errmsg + raise maxException + else: + raise ParseException(instring, loc, "no defined alternatives to match", self) + + def __ior__(self, other ): + if isinstance( other, basestring ): + other = ParserElement._literalStringClass( other ) + return self.append( other ) #MatchFirst( [ self, other ] ) + + def __str__( self ): + if hasattr(self,"name"): + return self.name + + if self.strRepr is None: + self.strRepr = "{" + " | ".join(_ustr(e) for e in self.exprs) + "}" + + return self.strRepr + + def checkRecursion( self, parseElementList ): + subRecCheckList = parseElementList[:] + [ self ] + for e in self.exprs: + e.checkRecursion( subRecCheckList ) + + +class Each(ParseExpression): + """ + Requires all given C{ParseExpression}s to be found, but in any order. + Expressions may be separated by whitespace. + May be constructed using the C{'&'} operator. + + Example:: + color = oneOf("RED ORANGE YELLOW GREEN BLUE PURPLE BLACK WHITE BROWN") + shape_type = oneOf("SQUARE CIRCLE TRIANGLE STAR HEXAGON OCTAGON") + integer = Word(nums) + shape_attr = "shape:" + shape_type("shape") + posn_attr = "posn:" + Group(integer("x") + ',' + integer("y"))("posn") + color_attr = "color:" + color("color") + size_attr = "size:" + integer("size") + + # use Each (using operator '&') to accept attributes in any order + # (shape and posn are required, color and size are optional) + shape_spec = shape_attr & posn_attr & Optional(color_attr) & Optional(size_attr) + + shape_spec.runTests(''' + shape: SQUARE color: BLACK posn: 100, 120 + shape: CIRCLE size: 50 color: BLUE posn: 50,80 + color:GREEN size:20 shape:TRIANGLE posn:20,40 + ''' + ) + prints:: + shape: SQUARE color: BLACK posn: 100, 120 + ['shape:', 'SQUARE', 'color:', 'BLACK', 'posn:', ['100', ',', '120']] + - color: BLACK + - posn: ['100', ',', '120'] + - x: 100 + - y: 120 + - shape: SQUARE + + + shape: CIRCLE size: 50 color: BLUE posn: 50,80 + ['shape:', 'CIRCLE', 'size:', '50', 'color:', 'BLUE', 'posn:', ['50', ',', '80']] + - color: BLUE + - posn: ['50', ',', '80'] + - x: 50 + - y: 80 + - shape: CIRCLE + - size: 50 + + + color: GREEN size: 20 shape: TRIANGLE posn: 20,40 + ['color:', 'GREEN', 'size:', '20', 'shape:', 'TRIANGLE', 'posn:', ['20', ',', '40']] + - color: GREEN + - posn: ['20', ',', '40'] + - x: 20 + - y: 40 + - shape: TRIANGLE + - size: 20 + """ + def __init__( self, exprs, savelist = True ): + super(Each,self).__init__(exprs, savelist) + self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs) + self.skipWhitespace = True + self.initExprGroups = True + + def parseImpl( self, instring, loc, doActions=True ): + if self.initExprGroups: + self.opt1map = dict((id(e.expr),e) for e in self.exprs if isinstance(e,Optional)) + opt1 = [ e.expr for e in self.exprs if isinstance(e,Optional) ] + opt2 = [ e for e in self.exprs if e.mayReturnEmpty and not isinstance(e,Optional)] + self.optionals = opt1 + opt2 + self.multioptionals = [ e.expr for e in self.exprs if isinstance(e,ZeroOrMore) ] + self.multirequired = [ e.expr for e in self.exprs if isinstance(e,OneOrMore) ] + self.required = [ e for e in self.exprs if not isinstance(e,(Optional,ZeroOrMore,OneOrMore)) ] + self.required += self.multirequired + self.initExprGroups = False + tmpLoc = loc + tmpReqd = self.required[:] + tmpOpt = self.optionals[:] + matchOrder = [] + + keepMatching = True + while keepMatching: + tmpExprs = tmpReqd + tmpOpt + self.multioptionals + self.multirequired + failed = [] + for e in tmpExprs: + try: + tmpLoc = e.tryParse( instring, tmpLoc ) + except ParseException: + failed.append(e) + else: + matchOrder.append(self.opt1map.get(id(e),e)) + if e in tmpReqd: + tmpReqd.remove(e) + elif e in tmpOpt: + tmpOpt.remove(e) + if len(failed) == len(tmpExprs): + keepMatching = False + + if tmpReqd: + missing = ", ".join(_ustr(e) for e in tmpReqd) + raise ParseException(instring,loc,"Missing one or more required elements (%s)" % missing ) + + # add any unmatched Optionals, in case they have default values defined + matchOrder += [e for e in self.exprs if isinstance(e,Optional) and e.expr in tmpOpt] + + resultlist = [] + for e in matchOrder: + loc,results = e._parse(instring,loc,doActions) + resultlist.append(results) + + finalResults = sum(resultlist, ParseResults([])) + return loc, finalResults + + def __str__( self ): + if hasattr(self,"name"): + return self.name + + if self.strRepr is None: + self.strRepr = "{" + " & ".join(_ustr(e) for e in self.exprs) + "}" + + return self.strRepr + + def checkRecursion( self, parseElementList ): + subRecCheckList = parseElementList[:] + [ self ] + for e in self.exprs: + e.checkRecursion( subRecCheckList ) + + +class ParseElementEnhance(ParserElement): + """ + Abstract subclass of C{ParserElement}, for combining and post-processing parsed tokens. + """ + def __init__( self, expr, savelist=False ): + super(ParseElementEnhance,self).__init__(savelist) + if isinstance( expr, basestring ): + if issubclass(ParserElement._literalStringClass, Token): + expr = ParserElement._literalStringClass(expr) + else: + expr = ParserElement._literalStringClass(Literal(expr)) + self.expr = expr + self.strRepr = None + if expr is not None: + self.mayIndexError = expr.mayIndexError + self.mayReturnEmpty = expr.mayReturnEmpty + self.setWhitespaceChars( expr.whiteChars ) + self.skipWhitespace = expr.skipWhitespace + self.saveAsList = expr.saveAsList + self.callPreparse = expr.callPreparse + self.ignoreExprs.extend(expr.ignoreExprs) + + def parseImpl( self, instring, loc, doActions=True ): + if self.expr is not None: + return self.expr._parse( instring, loc, doActions, callPreParse=False ) + else: + raise ParseException("",loc,self.errmsg,self) + + def leaveWhitespace( self ): + self.skipWhitespace = False + self.expr = self.expr.copy() + if self.expr is not None: + self.expr.leaveWhitespace() + return self + + def ignore( self, other ): + if isinstance( other, Suppress ): + if other not in self.ignoreExprs: + super( ParseElementEnhance, self).ignore( other ) + if self.expr is not None: + self.expr.ignore( self.ignoreExprs[-1] ) + else: + super( ParseElementEnhance, self).ignore( other ) + if self.expr is not None: + self.expr.ignore( self.ignoreExprs[-1] ) + return self + + def streamline( self ): + super(ParseElementEnhance,self).streamline() + if self.expr is not None: + self.expr.streamline() + return self + + def checkRecursion( self, parseElementList ): + if self in parseElementList: + raise RecursiveGrammarException( parseElementList+[self] ) + subRecCheckList = parseElementList[:] + [ self ] + if self.expr is not None: + self.expr.checkRecursion( subRecCheckList ) + + def validate( self, validateTrace=[] ): + tmp = validateTrace[:]+[self] + if self.expr is not None: + self.expr.validate(tmp) + self.checkRecursion( [] ) + + def __str__( self ): + try: + return super(ParseElementEnhance,self).__str__() + except Exception: + pass + + if self.strRepr is None and self.expr is not None: + self.strRepr = "%s:(%s)" % ( self.__class__.__name__, _ustr(self.expr) ) + return self.strRepr + + +class FollowedBy(ParseElementEnhance): + """ + Lookahead matching of the given parse expression. C{FollowedBy} + does I{not} advance the parsing position within the input string, it only + verifies that the specified parse expression matches at the current + position. C{FollowedBy} always returns a null token list. + + Example:: + # use FollowedBy to match a label only if it is followed by a ':' + data_word = Word(alphas) + label = data_word + FollowedBy(':') + attr_expr = Group(label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join)) + + OneOrMore(attr_expr).parseString("shape: SQUARE color: BLACK posn: upper left").pprint() + prints:: + [['shape', 'SQUARE'], ['color', 'BLACK'], ['posn', 'upper left']] + """ + def __init__( self, expr ): + super(FollowedBy,self).__init__(expr) + self.mayReturnEmpty = True + + def parseImpl( self, instring, loc, doActions=True ): + self.expr.tryParse( instring, loc ) + return loc, [] + + +class NotAny(ParseElementEnhance): + """ + Lookahead to disallow matching with the given parse expression. C{NotAny} + does I{not} advance the parsing position within the input string, it only + verifies that the specified parse expression does I{not} match at the current + position. Also, C{NotAny} does I{not} skip over leading whitespace. C{NotAny} + always returns a null token list. May be constructed using the '~' operator. + + Example:: + + """ + def __init__( self, expr ): + super(NotAny,self).__init__(expr) + #~ self.leaveWhitespace() + self.skipWhitespace = False # do NOT use self.leaveWhitespace(), don't want to propagate to exprs + self.mayReturnEmpty = True + self.errmsg = "Found unwanted token, "+_ustr(self.expr) + + def parseImpl( self, instring, loc, doActions=True ): + if self.expr.canParseNext(instring, loc): + raise ParseException(instring, loc, self.errmsg, self) + return loc, [] + + def __str__( self ): + if hasattr(self,"name"): + return self.name + + if self.strRepr is None: + self.strRepr = "~{" + _ustr(self.expr) + "}" + + return self.strRepr + +class _MultipleMatch(ParseElementEnhance): + def __init__( self, expr, stopOn=None): + super(_MultipleMatch, self).__init__(expr) + self.saveAsList = True + ender = stopOn + if isinstance(ender, basestring): + ender = ParserElement._literalStringClass(ender) + self.not_ender = ~ender if ender is not None else None + + def parseImpl( self, instring, loc, doActions=True ): + self_expr_parse = self.expr._parse + self_skip_ignorables = self._skipIgnorables + check_ender = self.not_ender is not None + if check_ender: + try_not_ender = self.not_ender.tryParse + + # must be at least one (but first see if we are the stopOn sentinel; + # if so, fail) + if check_ender: + try_not_ender(instring, loc) + loc, tokens = self_expr_parse( instring, loc, doActions, callPreParse=False ) + try: + hasIgnoreExprs = (not not self.ignoreExprs) + while 1: + if check_ender: + try_not_ender(instring, loc) + if hasIgnoreExprs: + preloc = self_skip_ignorables( instring, loc ) + else: + preloc = loc + loc, tmptokens = self_expr_parse( instring, preloc, doActions ) + if tmptokens or tmptokens.haskeys(): + tokens += tmptokens + except (ParseException,IndexError): + pass + + return loc, tokens + +class OneOrMore(_MultipleMatch): + """ + Repetition of one or more of the given expression. + + Parameters: + - expr - expression that must match one or more times + - stopOn - (default=C{None}) - expression for a terminating sentinel + (only required if the sentinel would ordinarily match the repetition + expression) + + Example:: + data_word = Word(alphas) + label = data_word + FollowedBy(':') + attr_expr = Group(label + Suppress(':') + OneOrMore(data_word).setParseAction(' '.join)) + + text = "shape: SQUARE posn: upper left color: BLACK" + OneOrMore(attr_expr).parseString(text).pprint() # Fail! read 'color' as data instead of next label -> [['shape', 'SQUARE color']] + + # use stopOn attribute for OneOrMore to avoid reading label string as part of the data + attr_expr = Group(label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join)) + OneOrMore(attr_expr).parseString(text).pprint() # Better -> [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'BLACK']] + + # could also be written as + (attr_expr * (1,)).parseString(text).pprint() + """ + + def __str__( self ): + if hasattr(self,"name"): + return self.name + + if self.strRepr is None: + self.strRepr = "{" + _ustr(self.expr) + "}..." + + return self.strRepr + +class ZeroOrMore(_MultipleMatch): + """ + Optional repetition of zero or more of the given expression. + + Parameters: + - expr - expression that must match zero or more times + - stopOn - (default=C{None}) - expression for a terminating sentinel + (only required if the sentinel would ordinarily match the repetition + expression) + + Example: similar to L{OneOrMore} + """ + def __init__( self, expr, stopOn=None): + super(ZeroOrMore,self).__init__(expr, stopOn=stopOn) + self.mayReturnEmpty = True + + def parseImpl( self, instring, loc, doActions=True ): + try: + return super(ZeroOrMore, self).parseImpl(instring, loc, doActions) + except (ParseException,IndexError): + return loc, [] + + def __str__( self ): + if hasattr(self,"name"): + return self.name + + if self.strRepr is None: + self.strRepr = "[" + _ustr(self.expr) + "]..." + + return self.strRepr + +class _NullToken(object): + def __bool__(self): + return False + __nonzero__ = __bool__ + def __str__(self): + return "" + +_optionalNotMatched = _NullToken() +class Optional(ParseElementEnhance): + """ + Optional matching of the given expression. + + Parameters: + - expr - expression that must match zero or more times + - default (optional) - value to be returned if the optional expression is not found. + + Example:: + # US postal code can be a 5-digit zip, plus optional 4-digit qualifier + zip = Combine(Word(nums, exact=5) + Optional('-' + Word(nums, exact=4))) + zip.runTests(''' + # traditional ZIP code + 12345 + + # ZIP+4 form + 12101-0001 + + # invalid ZIP + 98765- + ''') + prints:: + # traditional ZIP code + 12345 + ['12345'] + + # ZIP+4 form + 12101-0001 + ['12101-0001'] + + # invalid ZIP + 98765- + ^ + FAIL: Expected end of text (at char 5), (line:1, col:6) + """ + def __init__( self, expr, default=_optionalNotMatched ): + super(Optional,self).__init__( expr, savelist=False ) + self.saveAsList = self.expr.saveAsList + self.defaultValue = default + self.mayReturnEmpty = True + + def parseImpl( self, instring, loc, doActions=True ): + try: + loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False ) + except (ParseException,IndexError): + if self.defaultValue is not _optionalNotMatched: + if self.expr.resultsName: + tokens = ParseResults([ self.defaultValue ]) + tokens[self.expr.resultsName] = self.defaultValue + else: + tokens = [ self.defaultValue ] + else: + tokens = [] + return loc, tokens + + def __str__( self ): + if hasattr(self,"name"): + return self.name + + if self.strRepr is None: + self.strRepr = "[" + _ustr(self.expr) + "]" + + return self.strRepr + +class SkipTo(ParseElementEnhance): + """ + Token for skipping over all undefined text until the matched expression is found. + + Parameters: + - expr - target expression marking the end of the data to be skipped + - include - (default=C{False}) if True, the target expression is also parsed + (the skipped text and target expression are returned as a 2-element list). + - ignore - (default=C{None}) used to define grammars (typically quoted strings and + comments) that might contain false matches to the target expression + - failOn - (default=C{None}) define expressions that are not allowed to be + included in the skipped test; if found before the target expression is found, + the SkipTo is not a match + + Example:: + report = ''' + Outstanding Issues Report - 1 Jan 2000 + + # | Severity | Description | Days Open + -----+----------+-------------------------------------------+----------- + 101 | Critical | Intermittent system crash | 6 + 94 | Cosmetic | Spelling error on Login ('log|n') | 14 + 79 | Minor | System slow when running too many reports | 47 + ''' + integer = Word(nums) + SEP = Suppress('|') + # use SkipTo to simply match everything up until the next SEP + # - ignore quoted strings, so that a '|' character inside a quoted string does not match + # - parse action will call token.strip() for each matched token, i.e., the description body + string_data = SkipTo(SEP, ignore=quotedString) + string_data.setParseAction(tokenMap(str.strip)) + ticket_expr = (integer("issue_num") + SEP + + string_data("sev") + SEP + + string_data("desc") + SEP + + integer("days_open")) + + for tkt in ticket_expr.searchString(report): + print tkt.dump() + prints:: + ['101', 'Critical', 'Intermittent system crash', '6'] + - days_open: 6 + - desc: Intermittent system crash + - issue_num: 101 + - sev: Critical + ['94', 'Cosmetic', "Spelling error on Login ('log|n')", '14'] + - days_open: 14 + - desc: Spelling error on Login ('log|n') + - issue_num: 94 + - sev: Cosmetic + ['79', 'Minor', 'System slow when running too many reports', '47'] + - days_open: 47 + - desc: System slow when running too many reports + - issue_num: 79 + - sev: Minor + """ + def __init__( self, other, include=False, ignore=None, failOn=None ): + super( SkipTo, self ).__init__( other ) + self.ignoreExpr = ignore + self.mayReturnEmpty = True + self.mayIndexError = False + self.includeMatch = include + self.asList = False + if isinstance(failOn, basestring): + self.failOn = ParserElement._literalStringClass(failOn) + else: + self.failOn = failOn + self.errmsg = "No match found for "+_ustr(self.expr) + + def parseImpl( self, instring, loc, doActions=True ): + startloc = loc + instrlen = len(instring) + expr = self.expr + expr_parse = self.expr._parse + self_failOn_canParseNext = self.failOn.canParseNext if self.failOn is not None else None + self_ignoreExpr_tryParse = self.ignoreExpr.tryParse if self.ignoreExpr is not None else None + + tmploc = loc + while tmploc <= instrlen: + if self_failOn_canParseNext is not None: + # break if failOn expression matches + if self_failOn_canParseNext(instring, tmploc): + break + + if self_ignoreExpr_tryParse is not None: + # advance past ignore expressions + while 1: + try: + tmploc = self_ignoreExpr_tryParse(instring, tmploc) + except ParseBaseException: + break + + try: + expr_parse(instring, tmploc, doActions=False, callPreParse=False) + except (ParseException, IndexError): + # no match, advance loc in string + tmploc += 1 + else: + # matched skipto expr, done + break + + else: + # ran off the end of the input string without matching skipto expr, fail + raise ParseException(instring, loc, self.errmsg, self) + + # build up return values + loc = tmploc + skiptext = instring[startloc:loc] + skipresult = ParseResults(skiptext) + + if self.includeMatch: + loc, mat = expr_parse(instring,loc,doActions,callPreParse=False) + skipresult += mat + + return loc, skipresult + +class Forward(ParseElementEnhance): + """ + Forward declaration of an expression to be defined later - + used for recursive grammars, such as algebraic infix notation. + When the expression is known, it is assigned to the C{Forward} variable using the '<<' operator. + + Note: take care when assigning to C{Forward} not to overlook precedence of operators. + Specifically, '|' has a lower precedence than '<<', so that:: + fwdExpr << a | b | c + will actually be evaluated as:: + (fwdExpr << a) | b | c + thereby leaving b and c out as parseable alternatives. It is recommended that you + explicitly group the values inserted into the C{Forward}:: + fwdExpr << (a | b | c) + Converting to use the '<<=' operator instead will avoid this problem. + + See L{ParseResults.pprint} for an example of a recursive parser created using + C{Forward}. + """ + def __init__( self, other=None ): + super(Forward,self).__init__( other, savelist=False ) + + def __lshift__( self, other ): + if isinstance( other, basestring ): + other = ParserElement._literalStringClass(other) + self.expr = other + self.strRepr = None + self.mayIndexError = self.expr.mayIndexError + self.mayReturnEmpty = self.expr.mayReturnEmpty + self.setWhitespaceChars( self.expr.whiteChars ) + self.skipWhitespace = self.expr.skipWhitespace + self.saveAsList = self.expr.saveAsList + self.ignoreExprs.extend(self.expr.ignoreExprs) + return self + + def __ilshift__(self, other): + return self << other + + def leaveWhitespace( self ): + self.skipWhitespace = False + return self + + def streamline( self ): + if not self.streamlined: + self.streamlined = True + if self.expr is not None: + self.expr.streamline() + return self + + def validate( self, validateTrace=[] ): + if self not in validateTrace: + tmp = validateTrace[:]+[self] + if self.expr is not None: + self.expr.validate(tmp) + self.checkRecursion([]) + + def __str__( self ): + if hasattr(self,"name"): + return self.name + return self.__class__.__name__ + ": ..." + + # stubbed out for now - creates awful memory and perf issues + self._revertClass = self.__class__ + self.__class__ = _ForwardNoRecurse + try: + if self.expr is not None: + retString = _ustr(self.expr) + else: + retString = "None" + finally: + self.__class__ = self._revertClass + return self.__class__.__name__ + ": " + retString + + def copy(self): + if self.expr is not None: + return super(Forward,self).copy() + else: + ret = Forward() + ret <<= self + return ret + +class _ForwardNoRecurse(Forward): + def __str__( self ): + return "..." + +class TokenConverter(ParseElementEnhance): + """ + Abstract subclass of C{ParseExpression}, for converting parsed results. + """ + def __init__( self, expr, savelist=False ): + super(TokenConverter,self).__init__( expr )#, savelist ) + self.saveAsList = False + +class Combine(TokenConverter): + """ + Converter to concatenate all matching tokens to a single string. + By default, the matching patterns must also be contiguous in the input string; + this can be disabled by specifying C{'adjacent=False'} in the constructor. + + Example:: + real = Word(nums) + '.' + Word(nums) + print(real.parseString('3.1416')) # -> ['3', '.', '1416'] + # will also erroneously match the following + print(real.parseString('3. 1416')) # -> ['3', '.', '1416'] + + real = Combine(Word(nums) + '.' + Word(nums)) + print(real.parseString('3.1416')) # -> ['3.1416'] + # no match when there are internal spaces + print(real.parseString('3. 1416')) # -> Exception: Expected W:(0123...) + """ + def __init__( self, expr, joinString="", adjacent=True ): + super(Combine,self).__init__( expr ) + # suppress whitespace-stripping in contained parse expressions, but re-enable it on the Combine itself + if adjacent: + self.leaveWhitespace() + self.adjacent = adjacent + self.skipWhitespace = True + self.joinString = joinString + self.callPreparse = True + + def ignore( self, other ): + if self.adjacent: + ParserElement.ignore(self, other) + else: + super( Combine, self).ignore( other ) + return self + + def postParse( self, instring, loc, tokenlist ): + retToks = tokenlist.copy() + del retToks[:] + retToks += ParseResults([ "".join(tokenlist._asStringList(self.joinString)) ], modal=self.modalResults) + + if self.resultsName and retToks.haskeys(): + return [ retToks ] + else: + return retToks + +class Group(TokenConverter): + """ + Converter to return the matched tokens as a list - useful for returning tokens of C{L{ZeroOrMore}} and C{L{OneOrMore}} expressions. + + Example:: + ident = Word(alphas) + num = Word(nums) + term = ident | num + func = ident + Optional(delimitedList(term)) + print(func.parseString("fn a,b,100")) # -> ['fn', 'a', 'b', '100'] + + func = ident + Group(Optional(delimitedList(term))) + print(func.parseString("fn a,b,100")) # -> ['fn', ['a', 'b', '100']] + """ + def __init__( self, expr ): + super(Group,self).__init__( expr ) + self.saveAsList = True + + def postParse( self, instring, loc, tokenlist ): + return [ tokenlist ] + +class Dict(TokenConverter): + """ + Converter to return a repetitive expression as a list, but also as a dictionary. + Each element can also be referenced using the first token in the expression as its key. + Useful for tabular report scraping when the first column can be used as a item key. + + Example:: + data_word = Word(alphas) + label = data_word + FollowedBy(':') + attr_expr = Group(label + Suppress(':') + OneOrMore(data_word).setParseAction(' '.join)) + + text = "shape: SQUARE posn: upper left color: light blue texture: burlap" + attr_expr = (label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join)) + + # print attributes as plain groups + print(OneOrMore(attr_expr).parseString(text).dump()) + + # instead of OneOrMore(expr), parse using Dict(OneOrMore(Group(expr))) - Dict will auto-assign names + result = Dict(OneOrMore(Group(attr_expr))).parseString(text) + print(result.dump()) + + # access named fields as dict entries, or output as dict + print(result['shape']) + print(result.asDict()) + prints:: + ['shape', 'SQUARE', 'posn', 'upper left', 'color', 'light blue', 'texture', 'burlap'] + + [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'light blue'], ['texture', 'burlap']] + - color: light blue + - posn: upper left + - shape: SQUARE + - texture: burlap + SQUARE + {'color': 'light blue', 'posn': 'upper left', 'texture': 'burlap', 'shape': 'SQUARE'} + See more examples at L{ParseResults} of accessing fields by results name. + """ + def __init__( self, expr ): + super(Dict,self).__init__( expr ) + self.saveAsList = True + + def postParse( self, instring, loc, tokenlist ): + for i,tok in enumerate(tokenlist): + if len(tok) == 0: + continue + ikey = tok[0] + if isinstance(ikey,int): + ikey = _ustr(tok[0]).strip() + if len(tok)==1: + tokenlist[ikey] = _ParseResultsWithOffset("",i) + elif len(tok)==2 and not isinstance(tok[1],ParseResults): + tokenlist[ikey] = _ParseResultsWithOffset(tok[1],i) + else: + dictvalue = tok.copy() #ParseResults(i) + del dictvalue[0] + if len(dictvalue)!= 1 or (isinstance(dictvalue,ParseResults) and dictvalue.haskeys()): + tokenlist[ikey] = _ParseResultsWithOffset(dictvalue,i) + else: + tokenlist[ikey] = _ParseResultsWithOffset(dictvalue[0],i) + + if self.resultsName: + return [ tokenlist ] + else: + return tokenlist + + +class Suppress(TokenConverter): + """ + Converter for ignoring the results of a parsed expression. + + Example:: + source = "a, b, c,d" + wd = Word(alphas) + wd_list1 = wd + ZeroOrMore(',' + wd) + print(wd_list1.parseString(source)) + + # often, delimiters that are useful during parsing are just in the + # way afterward - use Suppress to keep them out of the parsed output + wd_list2 = wd + ZeroOrMore(Suppress(',') + wd) + print(wd_list2.parseString(source)) + prints:: + ['a', ',', 'b', ',', 'c', ',', 'd'] + ['a', 'b', 'c', 'd'] + (See also L{delimitedList}.) + """ + def postParse( self, instring, loc, tokenlist ): + return [] + + def suppress( self ): + return self + + +class OnlyOnce(object): + """ + Wrapper for parse actions, to ensure they are only called once. + """ + def __init__(self, methodCall): + self.callable = _trim_arity(methodCall) + self.called = False + def __call__(self,s,l,t): + if not self.called: + results = self.callable(s,l,t) + self.called = True + return results + raise ParseException(s,l,"") + def reset(self): + self.called = False + +def traceParseAction(f): + """ + Decorator for debugging parse actions. + + When the parse action is called, this decorator will print C{">> entering I{method-name}(line:I{current_source_line}, I{parse_location}, I{matched_tokens})".} + When the parse action completes, the decorator will print C{"<<"} followed by the returned value, or any exception that the parse action raised. + + Example:: + wd = Word(alphas) + + @traceParseAction + def remove_duplicate_chars(tokens): + return ''.join(sorted(set(''.join(tokens)))) + + wds = OneOrMore(wd).setParseAction(remove_duplicate_chars) + print(wds.parseString("slkdjs sld sldd sdlf sdljf")) + prints:: + >>entering remove_duplicate_chars(line: 'slkdjs sld sldd sdlf sdljf', 0, (['slkdjs', 'sld', 'sldd', 'sdlf', 'sdljf'], {})) + <<leaving remove_duplicate_chars (ret: 'dfjkls') + ['dfjkls'] + """ + f = _trim_arity(f) + def z(*paArgs): + thisFunc = f.__name__ + s,l,t = paArgs[-3:] + if len(paArgs)>3: + thisFunc = paArgs[0].__class__.__name__ + '.' + thisFunc + sys.stderr.write( ">>entering %s(line: '%s', %d, %r)\n" % (thisFunc,line(l,s),l,t) ) + try: + ret = f(*paArgs) + except Exception as exc: + sys.stderr.write( "<<leaving %s (exception: %s)\n" % (thisFunc,exc) ) + raise + sys.stderr.write( "<<leaving %s (ret: %r)\n" % (thisFunc,ret) ) + return ret + try: + z.__name__ = f.__name__ + except AttributeError: + pass + return z + +# +# global helpers +# +def delimitedList( expr, delim=",", combine=False ): + """ + Helper to define a delimited list of expressions - the delimiter defaults to ','. + By default, the list elements and delimiters can have intervening whitespace, and + comments, but this can be overridden by passing C{combine=True} in the constructor. + If C{combine} is set to C{True}, the matching tokens are returned as a single token + string, with the delimiters included; otherwise, the matching tokens are returned + as a list of tokens, with the delimiters suppressed. + + Example:: + delimitedList(Word(alphas)).parseString("aa,bb,cc") # -> ['aa', 'bb', 'cc'] + delimitedList(Word(hexnums), delim=':', combine=True).parseString("AA:BB:CC:DD:EE") # -> ['AA:BB:CC:DD:EE'] + """ + dlName = _ustr(expr)+" ["+_ustr(delim)+" "+_ustr(expr)+"]..." + if combine: + return Combine( expr + ZeroOrMore( delim + expr ) ).setName(dlName) + else: + return ( expr + ZeroOrMore( Suppress( delim ) + expr ) ).setName(dlName) + +def countedArray( expr, intExpr=None ): + """ + Helper to define a counted list of expressions. + This helper defines a pattern of the form:: + integer expr expr expr... + where the leading integer tells how many expr expressions follow. + The matched tokens returns the array of expr tokens as a list - the leading count token is suppressed. + + If C{intExpr} is specified, it should be a pyparsing expression that produces an integer value. + + Example:: + countedArray(Word(alphas)).parseString('2 ab cd ef') # -> ['ab', 'cd'] + + # in this parser, the leading integer value is given in binary, + # '10' indicating that 2 values are in the array + binaryConstant = Word('01').setParseAction(lambda t: int(t[0], 2)) + countedArray(Word(alphas), intExpr=binaryConstant).parseString('10 ab cd ef') # -> ['ab', 'cd'] + """ + arrayExpr = Forward() + def countFieldParseAction(s,l,t): + n = t[0] + arrayExpr << (n and Group(And([expr]*n)) or Group(empty)) + return [] + if intExpr is None: + intExpr = Word(nums).setParseAction(lambda t:int(t[0])) + else: + intExpr = intExpr.copy() + intExpr.setName("arrayLen") + intExpr.addParseAction(countFieldParseAction, callDuringTry=True) + return ( intExpr + arrayExpr ).setName('(len) ' + _ustr(expr) + '...') + +def _flatten(L): + ret = [] + for i in L: + if isinstance(i,list): + ret.extend(_flatten(i)) + else: + ret.append(i) + return ret + +def matchPreviousLiteral(expr): + """ + Helper to define an expression that is indirectly defined from + the tokens matched in a previous expression, that is, it looks + for a 'repeat' of a previous expression. For example:: + first = Word(nums) + second = matchPreviousLiteral(first) + matchExpr = first + ":" + second + will match C{"1:1"}, but not C{"1:2"}. Because this matches a + previous literal, will also match the leading C{"1:1"} in C{"1:10"}. + If this is not desired, use C{matchPreviousExpr}. + Do I{not} use with packrat parsing enabled. + """ + rep = Forward() + def copyTokenToRepeater(s,l,t): + if t: + if len(t) == 1: + rep << t[0] + else: + # flatten t tokens + tflat = _flatten(t.asList()) + rep << And(Literal(tt) for tt in tflat) + else: + rep << Empty() + expr.addParseAction(copyTokenToRepeater, callDuringTry=True) + rep.setName('(prev) ' + _ustr(expr)) + return rep + +def matchPreviousExpr(expr): + """ + Helper to define an expression that is indirectly defined from + the tokens matched in a previous expression, that is, it looks + for a 'repeat' of a previous expression. For example:: + first = Word(nums) + second = matchPreviousExpr(first) + matchExpr = first + ":" + second + will match C{"1:1"}, but not C{"1:2"}. Because this matches by + expressions, will I{not} match the leading C{"1:1"} in C{"1:10"}; + the expressions are evaluated first, and then compared, so + C{"1"} is compared with C{"10"}. + Do I{not} use with packrat parsing enabled. + """ + rep = Forward() + e2 = expr.copy() + rep <<= e2 + def copyTokenToRepeater(s,l,t): + matchTokens = _flatten(t.asList()) + def mustMatchTheseTokens(s,l,t): + theseTokens = _flatten(t.asList()) + if theseTokens != matchTokens: + raise ParseException("",0,"") + rep.setParseAction( mustMatchTheseTokens, callDuringTry=True ) + expr.addParseAction(copyTokenToRepeater, callDuringTry=True) + rep.setName('(prev) ' + _ustr(expr)) + return rep + +def _escapeRegexRangeChars(s): + #~ escape these chars: ^-] + for c in r"\^-]": + s = s.replace(c,_bslash+c) + s = s.replace("\n",r"\n") + s = s.replace("\t",r"\t") + return _ustr(s) + +def oneOf( strs, caseless=False, useRegex=True ): + """ + Helper to quickly define a set of alternative Literals, and makes sure to do + longest-first testing when there is a conflict, regardless of the input order, + but returns a C{L{MatchFirst}} for best performance. + + Parameters: + - strs - a string of space-delimited literals, or a collection of string literals + - caseless - (default=C{False}) - treat all literals as caseless + - useRegex - (default=C{True}) - as an optimization, will generate a Regex + object; otherwise, will generate a C{MatchFirst} object (if C{caseless=True}, or + if creating a C{Regex} raises an exception) + + Example:: + comp_oper = oneOf("< = > <= >= !=") + var = Word(alphas) + number = Word(nums) + term = var | number + comparison_expr = term + comp_oper + term + print(comparison_expr.searchString("B = 12 AA=23 B<=AA AA>12")) + prints:: + [['B', '=', '12'], ['AA', '=', '23'], ['B', '<=', 'AA'], ['AA', '>', '12']] + """ + if caseless: + isequal = ( lambda a,b: a.upper() == b.upper() ) + masks = ( lambda a,b: b.upper().startswith(a.upper()) ) + parseElementClass = CaselessLiteral + else: + isequal = ( lambda a,b: a == b ) + masks = ( lambda a,b: b.startswith(a) ) + parseElementClass = Literal + + symbols = [] + if isinstance(strs,basestring): + symbols = strs.split() + elif isinstance(strs, Iterable): + symbols = list(strs) + else: + warnings.warn("Invalid argument to oneOf, expected string or iterable", + SyntaxWarning, stacklevel=2) + if not symbols: + return NoMatch() + + i = 0 + while i < len(symbols)-1: + cur = symbols[i] + for j,other in enumerate(symbols[i+1:]): + if ( isequal(other, cur) ): + del symbols[i+j+1] + break + elif ( masks(cur, other) ): + del symbols[i+j+1] + symbols.insert(i,other) + cur = other + break + else: + i += 1 + + if not caseless and useRegex: + #~ print (strs,"->", "|".join( [ _escapeRegexChars(sym) for sym in symbols] )) + try: + if len(symbols)==len("".join(symbols)): + return Regex( "[%s]" % "".join(_escapeRegexRangeChars(sym) for sym in symbols) ).setName(' | '.join(symbols)) + else: + return Regex( "|".join(re.escape(sym) for sym in symbols) ).setName(' | '.join(symbols)) + except Exception: + warnings.warn("Exception creating Regex for oneOf, building MatchFirst", + SyntaxWarning, stacklevel=2) + + + # last resort, just use MatchFirst + return MatchFirst(parseElementClass(sym) for sym in symbols).setName(' | '.join(symbols)) + +def dictOf( key, value ): + """ + Helper to easily and clearly define a dictionary by specifying the respective patterns + for the key and value. Takes care of defining the C{L{Dict}}, C{L{ZeroOrMore}}, and C{L{Group}} tokens + in the proper order. The key pattern can include delimiting markers or punctuation, + as long as they are suppressed, thereby leaving the significant key text. The value + pattern can include named results, so that the C{Dict} results can include named token + fields. + + Example:: + text = "shape: SQUARE posn: upper left color: light blue texture: burlap" + attr_expr = (label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join)) + print(OneOrMore(attr_expr).parseString(text).dump()) + + attr_label = label + attr_value = Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join) + + # similar to Dict, but simpler call format + result = dictOf(attr_label, attr_value).parseString(text) + print(result.dump()) + print(result['shape']) + print(result.shape) # object attribute access works too + print(result.asDict()) + prints:: + [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'light blue'], ['texture', 'burlap']] + - color: light blue + - posn: upper left + - shape: SQUARE + - texture: burlap + SQUARE + SQUARE + {'color': 'light blue', 'shape': 'SQUARE', 'posn': 'upper left', 'texture': 'burlap'} + """ + return Dict( ZeroOrMore( Group ( key + value ) ) ) + +def originalTextFor(expr, asString=True): + """ + Helper to return the original, untokenized text for a given expression. Useful to + restore the parsed fields of an HTML start tag into the raw tag text itself, or to + revert separate tokens with intervening whitespace back to the original matching + input text. By default, returns astring containing the original parsed text. + + If the optional C{asString} argument is passed as C{False}, then the return value is a + C{L{ParseResults}} containing any results names that were originally matched, and a + single token containing the original matched text from the input string. So if + the expression passed to C{L{originalTextFor}} contains expressions with defined + results names, you must set C{asString} to C{False} if you want to preserve those + results name values. + + Example:: + src = "this is test <b> bold <i>text</i> </b> normal text " + for tag in ("b","i"): + opener,closer = makeHTMLTags(tag) + patt = originalTextFor(opener + SkipTo(closer) + closer) + print(patt.searchString(src)[0]) + prints:: + ['<b> bold <i>text</i> </b>'] + ['<i>text</i>'] + """ + locMarker = Empty().setParseAction(lambda s,loc,t: loc) + endlocMarker = locMarker.copy() + endlocMarker.callPreparse = False + matchExpr = locMarker("_original_start") + expr + endlocMarker("_original_end") + if asString: + extractText = lambda s,l,t: s[t._original_start:t._original_end] + else: + def extractText(s,l,t): + t[:] = [s[t.pop('_original_start'):t.pop('_original_end')]] + matchExpr.setParseAction(extractText) + matchExpr.ignoreExprs = expr.ignoreExprs + return matchExpr + +def ungroup(expr): + """ + Helper to undo pyparsing's default grouping of And expressions, even + if all but one are non-empty. + """ + return TokenConverter(expr).setParseAction(lambda t:t[0]) + +def locatedExpr(expr): + """ + Helper to decorate a returned token with its starting and ending locations in the input string. + This helper adds the following results names: + - locn_start = location where matched expression begins + - locn_end = location where matched expression ends + - value = the actual parsed results + + Be careful if the input text contains C{<TAB>} characters, you may want to call + C{L{ParserElement.parseWithTabs}} + + Example:: + wd = Word(alphas) + for match in locatedExpr(wd).searchString("ljsdf123lksdjjf123lkkjj1222"): + print(match) + prints:: + [[0, 'ljsdf', 5]] + [[8, 'lksdjjf', 15]] + [[18, 'lkkjj', 23]] + """ + locator = Empty().setParseAction(lambda s,l,t: l) + return Group(locator("locn_start") + expr("value") + locator.copy().leaveWhitespace()("locn_end")) + + +# convenience constants for positional expressions +empty = Empty().setName("empty") +lineStart = LineStart().setName("lineStart") +lineEnd = LineEnd().setName("lineEnd") +stringStart = StringStart().setName("stringStart") +stringEnd = StringEnd().setName("stringEnd") + +_escapedPunc = Word( _bslash, r"\[]-*.$+^?()~ ", exact=2 ).setParseAction(lambda s,l,t:t[0][1]) +_escapedHexChar = Regex(r"\\0?[xX][0-9a-fA-F]+").setParseAction(lambda s,l,t:unichr(int(t[0].lstrip(r'\0x'),16))) +_escapedOctChar = Regex(r"\\0[0-7]+").setParseAction(lambda s,l,t:unichr(int(t[0][1:],8))) +_singleChar = _escapedPunc | _escapedHexChar | _escapedOctChar | CharsNotIn(r'\]', exact=1) +_charRange = Group(_singleChar + Suppress("-") + _singleChar) +_reBracketExpr = Literal("[") + Optional("^").setResultsName("negate") + Group( OneOrMore( _charRange | _singleChar ) ).setResultsName("body") + "]" + +def srange(s): + r""" + Helper to easily define string ranges for use in Word construction. Borrows + syntax from regexp '[]' string range definitions:: + srange("[0-9]") -> "0123456789" + srange("[a-z]") -> "abcdefghijklmnopqrstuvwxyz" + srange("[a-z$_]") -> "abcdefghijklmnopqrstuvwxyz$_" + The input string must be enclosed in []'s, and the returned string is the expanded + character set joined into a single string. + The values enclosed in the []'s may be: + - a single character + - an escaped character with a leading backslash (such as C{\-} or C{\]}) + - an escaped hex character with a leading C{'\x'} (C{\x21}, which is a C{'!'} character) + (C{\0x##} is also supported for backwards compatibility) + - an escaped octal character with a leading C{'\0'} (C{\041}, which is a C{'!'} character) + - a range of any of the above, separated by a dash (C{'a-z'}, etc.) + - any combination of the above (C{'aeiouy'}, C{'a-zA-Z0-9_$'}, etc.) + """ + _expanded = lambda p: p if not isinstance(p,ParseResults) else ''.join(unichr(c) for c in range(ord(p[0]),ord(p[1])+1)) + try: + return "".join(_expanded(part) for part in _reBracketExpr.parseString(s).body) + except Exception: + return "" + +def matchOnlyAtCol(n): + """ + Helper method for defining parse actions that require matching at a specific + column in the input text. + """ + def verifyCol(strg,locn,toks): + if col(locn,strg) != n: + raise ParseException(strg,locn,"matched token not at column %d" % n) + return verifyCol + +def replaceWith(replStr): + """ + Helper method for common parse actions that simply return a literal value. Especially + useful when used with C{L{transformString<ParserElement.transformString>}()}. + + Example:: + num = Word(nums).setParseAction(lambda toks: int(toks[0])) + na = oneOf("N/A NA").setParseAction(replaceWith(math.nan)) + term = na | num + + OneOrMore(term).parseString("324 234 N/A 234") # -> [324, 234, nan, 234] + """ + return lambda s,l,t: [replStr] + +def removeQuotes(s,l,t): + """ + Helper parse action for removing quotation marks from parsed quoted strings. + + Example:: + # by default, quotation marks are included in parsed results + quotedString.parseString("'Now is the Winter of our Discontent'") # -> ["'Now is the Winter of our Discontent'"] + + # use removeQuotes to strip quotation marks from parsed results + quotedString.setParseAction(removeQuotes) + quotedString.parseString("'Now is the Winter of our Discontent'") # -> ["Now is the Winter of our Discontent"] + """ + return t[0][1:-1] + +def tokenMap(func, *args): + """ + Helper to define a parse action by mapping a function to all elements of a ParseResults list.If any additional + args are passed, they are forwarded to the given function as additional arguments after + the token, as in C{hex_integer = Word(hexnums).setParseAction(tokenMap(int, 16))}, which will convert the + parsed data to an integer using base 16. + + Example (compare the last to example in L{ParserElement.transformString}:: + hex_ints = OneOrMore(Word(hexnums)).setParseAction(tokenMap(int, 16)) + hex_ints.runTests(''' + 00 11 22 aa FF 0a 0d 1a + ''') + + upperword = Word(alphas).setParseAction(tokenMap(str.upper)) + OneOrMore(upperword).runTests(''' + my kingdom for a horse + ''') + + wd = Word(alphas).setParseAction(tokenMap(str.title)) + OneOrMore(wd).setParseAction(' '.join).runTests(''' + now is the winter of our discontent made glorious summer by this sun of york + ''') + prints:: + 00 11 22 aa FF 0a 0d 1a + [0, 17, 34, 170, 255, 10, 13, 26] + + my kingdom for a horse + ['MY', 'KINGDOM', 'FOR', 'A', 'HORSE'] + + now is the winter of our discontent made glorious summer by this sun of york + ['Now Is The Winter Of Our Discontent Made Glorious Summer By This Sun Of York'] + """ + def pa(s,l,t): + return [func(tokn, *args) for tokn in t] + + try: + func_name = getattr(func, '__name__', + getattr(func, '__class__').__name__) + except Exception: + func_name = str(func) + pa.__name__ = func_name + + return pa + +upcaseTokens = tokenMap(lambda t: _ustr(t).upper()) +"""(Deprecated) Helper parse action to convert tokens to upper case. Deprecated in favor of L{pyparsing_common.upcaseTokens}""" + +downcaseTokens = tokenMap(lambda t: _ustr(t).lower()) +"""(Deprecated) Helper parse action to convert tokens to lower case. Deprecated in favor of L{pyparsing_common.downcaseTokens}""" + +def _makeTags(tagStr, xml): + """Internal helper to construct opening and closing tag expressions, given a tag name""" + if isinstance(tagStr,basestring): + resname = tagStr + tagStr = Keyword(tagStr, caseless=not xml) + else: + resname = tagStr.name + + tagAttrName = Word(alphas,alphanums+"_-:") + if (xml): + tagAttrValue = dblQuotedString.copy().setParseAction( removeQuotes ) + openTag = Suppress("<") + tagStr("tag") + \ + Dict(ZeroOrMore(Group( tagAttrName + Suppress("=") + tagAttrValue ))) + \ + Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">") + else: + printablesLessRAbrack = "".join(c for c in printables if c not in ">") + tagAttrValue = quotedString.copy().setParseAction( removeQuotes ) | Word(printablesLessRAbrack) + openTag = Suppress("<") + tagStr("tag") + \ + Dict(ZeroOrMore(Group( tagAttrName.setParseAction(downcaseTokens) + \ + Optional( Suppress("=") + tagAttrValue ) ))) + \ + Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">") + closeTag = Combine(_L("</") + tagStr + ">") + + openTag = openTag.setResultsName("start"+"".join(resname.replace(":"," ").title().split())).setName("<%s>" % resname) + closeTag = closeTag.setResultsName("end"+"".join(resname.replace(":"," ").title().split())).setName("</%s>" % resname) + openTag.tag = resname + closeTag.tag = resname + return openTag, closeTag + +def makeHTMLTags(tagStr): + """ + Helper to construct opening and closing tag expressions for HTML, given a tag name. Matches + tags in either upper or lower case, attributes with namespaces and with quoted or unquoted values. + + Example:: + text = '<td>More info at the <a href="http://pyparsing.wikispaces.com">pyparsing</a> wiki page</td>' + # makeHTMLTags returns pyparsing expressions for the opening and closing tags as a 2-tuple + a,a_end = makeHTMLTags("A") + link_expr = a + SkipTo(a_end)("link_text") + a_end + + for link in link_expr.searchString(text): + # attributes in the <A> tag (like "href" shown here) are also accessible as named results + print(link.link_text, '->', link.href) + prints:: + pyparsing -> http://pyparsing.wikispaces.com + """ + return _makeTags( tagStr, False ) + +def makeXMLTags(tagStr): + """ + Helper to construct opening and closing tag expressions for XML, given a tag name. Matches + tags only in the given upper/lower case. + + Example: similar to L{makeHTMLTags} + """ + return _makeTags( tagStr, True ) + +def withAttribute(*args,**attrDict): + """ + Helper to create a validating parse action to be used with start tags created + with C{L{makeXMLTags}} or C{L{makeHTMLTags}}. Use C{withAttribute} to qualify a starting tag + with a required attribute value, to avoid false matches on common tags such as + C{<TD>} or C{<DIV>}. + + Call C{withAttribute} with a series of attribute names and values. Specify the list + of filter attributes names and values as: + - keyword arguments, as in C{(align="right")}, or + - as an explicit dict with C{**} operator, when an attribute name is also a Python + reserved word, as in C{**{"class":"Customer", "align":"right"}} + - a list of name-value tuples, as in ( ("ns1:class", "Customer"), ("ns2:align","right") ) + For attribute names with a namespace prefix, you must use the second form. Attribute + names are matched insensitive to upper/lower case. + + If just testing for C{class} (with or without a namespace), use C{L{withClass}}. + + To verify that the attribute exists, but without specifying a value, pass + C{withAttribute.ANY_VALUE} as the value. + + Example:: + html = ''' + <div> + Some text + <div type="grid">1 4 0 1 0</div> + <div type="graph">1,3 2,3 1,1</div> + <div>this has no type</div> + </div> + + ''' + div,div_end = makeHTMLTags("div") + + # only match div tag having a type attribute with value "grid" + div_grid = div().setParseAction(withAttribute(type="grid")) + grid_expr = div_grid + SkipTo(div | div_end)("body") + for grid_header in grid_expr.searchString(html): + print(grid_header.body) + + # construct a match with any div tag having a type attribute, regardless of the value + div_any_type = div().setParseAction(withAttribute(type=withAttribute.ANY_VALUE)) + div_expr = div_any_type + SkipTo(div | div_end)("body") + for div_header in div_expr.searchString(html): + print(div_header.body) + prints:: + 1 4 0 1 0 + + 1 4 0 1 0 + 1,3 2,3 1,1 + """ + if args: + attrs = args[:] + else: + attrs = attrDict.items() + attrs = [(k,v) for k,v in attrs] + def pa(s,l,tokens): + for attrName,attrValue in attrs: + if attrName not in tokens: + raise ParseException(s,l,"no matching attribute " + attrName) + if attrValue != withAttribute.ANY_VALUE and tokens[attrName] != attrValue: + raise ParseException(s,l,"attribute '%s' has value '%s', must be '%s'" % + (attrName, tokens[attrName], attrValue)) + return pa +withAttribute.ANY_VALUE = object() + +def withClass(classname, namespace=''): + """ + Simplified version of C{L{withAttribute}} when matching on a div class - made + difficult because C{class} is a reserved word in Python. + + Example:: + html = ''' + <div> + Some text + <div class="grid">1 4 0 1 0</div> + <div class="graph">1,3 2,3 1,1</div> + <div>this &lt;div&gt; has no class</div> + </div> + + ''' + div,div_end = makeHTMLTags("div") + div_grid = div().setParseAction(withClass("grid")) + + grid_expr = div_grid + SkipTo(div | div_end)("body") + for grid_header in grid_expr.searchString(html): + print(grid_header.body) + + div_any_type = div().setParseAction(withClass(withAttribute.ANY_VALUE)) + div_expr = div_any_type + SkipTo(div | div_end)("body") + for div_header in div_expr.searchString(html): + print(div_header.body) + prints:: + 1 4 0 1 0 + + 1 4 0 1 0 + 1,3 2,3 1,1 + """ + classattr = "%s:class" % namespace if namespace else "class" + return withAttribute(**{classattr : classname}) + +opAssoc = _Constants() +opAssoc.LEFT = object() +opAssoc.RIGHT = object() + +def infixNotation( baseExpr, opList, lpar=Suppress('('), rpar=Suppress(')') ): + """ + Helper method for constructing grammars of expressions made up of + operators working in a precedence hierarchy. Operators may be unary or + binary, left- or right-associative. Parse actions can also be attached + to operator expressions. The generated parser will also recognize the use + of parentheses to override operator precedences (see example below). + + Note: if you define a deep operator list, you may see performance issues + when using infixNotation. See L{ParserElement.enablePackrat} for a + mechanism to potentially improve your parser performance. + + Parameters: + - baseExpr - expression representing the most basic element for the nested + - opList - list of tuples, one for each operator precedence level in the + expression grammar; each tuple is of the form + (opExpr, numTerms, rightLeftAssoc, parseAction), where: + - opExpr is the pyparsing expression for the operator; + may also be a string, which will be converted to a Literal; + if numTerms is 3, opExpr is a tuple of two expressions, for the + two operators separating the 3 terms + - numTerms is the number of terms for this operator (must + be 1, 2, or 3) + - rightLeftAssoc is the indicator whether the operator is + right or left associative, using the pyparsing-defined + constants C{opAssoc.RIGHT} and C{opAssoc.LEFT}. + - parseAction is the parse action to be associated with + expressions matching this operator expression (the + parse action tuple member may be omitted); if the parse action + is passed a tuple or list of functions, this is equivalent to + calling C{setParseAction(*fn)} (L{ParserElement.setParseAction}) + - lpar - expression for matching left-parentheses (default=C{Suppress('(')}) + - rpar - expression for matching right-parentheses (default=C{Suppress(')')}) + + Example:: + # simple example of four-function arithmetic with ints and variable names + integer = pyparsing_common.signed_integer + varname = pyparsing_common.identifier + + arith_expr = infixNotation(integer | varname, + [ + ('-', 1, opAssoc.RIGHT), + (oneOf('* /'), 2, opAssoc.LEFT), + (oneOf('+ -'), 2, opAssoc.LEFT), + ]) + + arith_expr.runTests(''' + 5+3*6 + (5+3)*6 + -2--11 + ''', fullDump=False) + prints:: + 5+3*6 + [[5, '+', [3, '*', 6]]] + + (5+3)*6 + [[[5, '+', 3], '*', 6]] + + -2--11 + [[['-', 2], '-', ['-', 11]]] + """ + ret = Forward() + lastExpr = baseExpr | ( lpar + ret + rpar ) + for i,operDef in enumerate(opList): + opExpr,arity,rightLeftAssoc,pa = (operDef + (None,))[:4] + termName = "%s term" % opExpr if arity < 3 else "%s%s term" % opExpr + if arity == 3: + if opExpr is None or len(opExpr) != 2: + raise ValueError("if numterms=3, opExpr must be a tuple or list of two expressions") + opExpr1, opExpr2 = opExpr + thisExpr = Forward().setName(termName) + if rightLeftAssoc == opAssoc.LEFT: + if arity == 1: + matchExpr = FollowedBy(lastExpr + opExpr) + Group( lastExpr + OneOrMore( opExpr ) ) + elif arity == 2: + if opExpr is not None: + matchExpr = FollowedBy(lastExpr + opExpr + lastExpr) + Group( lastExpr + OneOrMore( opExpr + lastExpr ) ) + else: + matchExpr = FollowedBy(lastExpr+lastExpr) + Group( lastExpr + OneOrMore(lastExpr) ) + elif arity == 3: + matchExpr = FollowedBy(lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr) + \ + Group( lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr ) + else: + raise ValueError("operator must be unary (1), binary (2), or ternary (3)") + elif rightLeftAssoc == opAssoc.RIGHT: + if arity == 1: + # try to avoid LR with this extra test + if not isinstance(opExpr, Optional): + opExpr = Optional(opExpr) + matchExpr = FollowedBy(opExpr.expr + thisExpr) + Group( opExpr + thisExpr ) + elif arity == 2: + if opExpr is not None: + matchExpr = FollowedBy(lastExpr + opExpr + thisExpr) + Group( lastExpr + OneOrMore( opExpr + thisExpr ) ) + else: + matchExpr = FollowedBy(lastExpr + thisExpr) + Group( lastExpr + OneOrMore( thisExpr ) ) + elif arity == 3: + matchExpr = FollowedBy(lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr) + \ + Group( lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr ) + else: + raise ValueError("operator must be unary (1), binary (2), or ternary (3)") + else: + raise ValueError("operator must indicate right or left associativity") + if pa: + if isinstance(pa, (tuple, list)): + matchExpr.setParseAction(*pa) + else: + matchExpr.setParseAction(pa) + thisExpr <<= ( matchExpr.setName(termName) | lastExpr ) + lastExpr = thisExpr + ret <<= lastExpr + return ret + +operatorPrecedence = infixNotation +"""(Deprecated) Former name of C{L{infixNotation}}, will be dropped in a future release.""" + +dblQuotedString = Combine(Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*')+'"').setName("string enclosed in double quotes") +sglQuotedString = Combine(Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*")+"'").setName("string enclosed in single quotes") +quotedString = Combine(Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*')+'"'| + Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*")+"'").setName("quotedString using single or double quotes") +unicodeString = Combine(_L('u') + quotedString.copy()).setName("unicode string literal") + +def nestedExpr(opener="(", closer=")", content=None, ignoreExpr=quotedString.copy()): + """ + Helper method for defining nested lists enclosed in opening and closing + delimiters ("(" and ")" are the default). + + Parameters: + - opener - opening character for a nested list (default=C{"("}); can also be a pyparsing expression + - closer - closing character for a nested list (default=C{")"}); can also be a pyparsing expression + - content - expression for items within the nested lists (default=C{None}) + - ignoreExpr - expression for ignoring opening and closing delimiters (default=C{quotedString}) + + If an expression is not provided for the content argument, the nested + expression will capture all whitespace-delimited content between delimiters + as a list of separate values. + + Use the C{ignoreExpr} argument to define expressions that may contain + opening or closing characters that should not be treated as opening + or closing characters for nesting, such as quotedString or a comment + expression. Specify multiple expressions using an C{L{Or}} or C{L{MatchFirst}}. + The default is L{quotedString}, but if no expressions are to be ignored, + then pass C{None} for this argument. + + Example:: + data_type = oneOf("void int short long char float double") + decl_data_type = Combine(data_type + Optional(Word('*'))) + ident = Word(alphas+'_', alphanums+'_') + number = pyparsing_common.number + arg = Group(decl_data_type + ident) + LPAR,RPAR = map(Suppress, "()") + + code_body = nestedExpr('{', '}', ignoreExpr=(quotedString | cStyleComment)) + + c_function = (decl_data_type("type") + + ident("name") + + LPAR + Optional(delimitedList(arg), [])("args") + RPAR + + code_body("body")) + c_function.ignore(cStyleComment) + + source_code = ''' + int is_odd(int x) { + return (x%2); + } + + int dec_to_hex(char hchar) { + if (hchar >= '0' && hchar <= '9') { + return (ord(hchar)-ord('0')); + } else { + return (10+ord(hchar)-ord('A')); + } + } + ''' + for func in c_function.searchString(source_code): + print("%(name)s (%(type)s) args: %(args)s" % func) + + prints:: + is_odd (int) args: [['int', 'x']] + dec_to_hex (int) args: [['char', 'hchar']] + """ + if opener == closer: + raise ValueError("opening and closing strings cannot be the same") + if content is None: + if isinstance(opener,basestring) and isinstance(closer,basestring): + if len(opener) == 1 and len(closer)==1: + if ignoreExpr is not None: + content = (Combine(OneOrMore(~ignoreExpr + + CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS,exact=1)) + ).setParseAction(lambda t:t[0].strip())) + else: + content = (empty.copy()+CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS + ).setParseAction(lambda t:t[0].strip())) + else: + if ignoreExpr is not None: + content = (Combine(OneOrMore(~ignoreExpr + + ~Literal(opener) + ~Literal(closer) + + CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1)) + ).setParseAction(lambda t:t[0].strip())) + else: + content = (Combine(OneOrMore(~Literal(opener) + ~Literal(closer) + + CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1)) + ).setParseAction(lambda t:t[0].strip())) + else: + raise ValueError("opening and closing arguments must be strings if no content expression is given") + ret = Forward() + if ignoreExpr is not None: + ret <<= Group( Suppress(opener) + ZeroOrMore( ignoreExpr | ret | content ) + Suppress(closer) ) + else: + ret <<= Group( Suppress(opener) + ZeroOrMore( ret | content ) + Suppress(closer) ) + ret.setName('nested %s%s expression' % (opener,closer)) + return ret + +def indentedBlock(blockStatementExpr, indentStack, indent=True): + """ + Helper method for defining space-delimited indentation blocks, such as + those used to define block statements in Python source code. + + Parameters: + - blockStatementExpr - expression defining syntax of statement that + is repeated within the indented block + - indentStack - list created by caller to manage indentation stack + (multiple statementWithIndentedBlock expressions within a single grammar + should share a common indentStack) + - indent - boolean indicating whether block must be indented beyond the + the current level; set to False for block of left-most statements + (default=C{True}) + + A valid block must contain at least one C{blockStatement}. + + Example:: + data = ''' + def A(z): + A1 + B = 100 + G = A2 + A2 + A3 + B + def BB(a,b,c): + BB1 + def BBA(): + bba1 + bba2 + bba3 + C + D + def spam(x,y): + def eggs(z): + pass + ''' + + + indentStack = [1] + stmt = Forward() + + identifier = Word(alphas, alphanums) + funcDecl = ("def" + identifier + Group( "(" + Optional( delimitedList(identifier) ) + ")" ) + ":") + func_body = indentedBlock(stmt, indentStack) + funcDef = Group( funcDecl + func_body ) + + rvalue = Forward() + funcCall = Group(identifier + "(" + Optional(delimitedList(rvalue)) + ")") + rvalue << (funcCall | identifier | Word(nums)) + assignment = Group(identifier + "=" + rvalue) + stmt << ( funcDef | assignment | identifier ) + + module_body = OneOrMore(stmt) + + parseTree = module_body.parseString(data) + parseTree.pprint() + prints:: + [['def', + 'A', + ['(', 'z', ')'], + ':', + [['A1'], [['B', '=', '100']], [['G', '=', 'A2']], ['A2'], ['A3']]], + 'B', + ['def', + 'BB', + ['(', 'a', 'b', 'c', ')'], + ':', + [['BB1'], [['def', 'BBA', ['(', ')'], ':', [['bba1'], ['bba2'], ['bba3']]]]]], + 'C', + 'D', + ['def', + 'spam', + ['(', 'x', 'y', ')'], + ':', + [[['def', 'eggs', ['(', 'z', ')'], ':', [['pass']]]]]]] + """ + def checkPeerIndent(s,l,t): + if l >= len(s): return + curCol = col(l,s) + if curCol != indentStack[-1]: + if curCol > indentStack[-1]: + raise ParseFatalException(s,l,"illegal nesting") + raise ParseException(s,l,"not a peer entry") + + def checkSubIndent(s,l,t): + curCol = col(l,s) + if curCol > indentStack[-1]: + indentStack.append( curCol ) + else: + raise ParseException(s,l,"not a subentry") + + def checkUnindent(s,l,t): + if l >= len(s): return + curCol = col(l,s) + if not(indentStack and curCol < indentStack[-1] and curCol <= indentStack[-2]): + raise ParseException(s,l,"not an unindent") + indentStack.pop() + + NL = OneOrMore(LineEnd().setWhitespaceChars("\t ").suppress()) + INDENT = (Empty() + Empty().setParseAction(checkSubIndent)).setName('INDENT') + PEER = Empty().setParseAction(checkPeerIndent).setName('') + UNDENT = Empty().setParseAction(checkUnindent).setName('UNINDENT') + if indent: + smExpr = Group( Optional(NL) + + #~ FollowedBy(blockStatementExpr) + + INDENT + (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) + UNDENT) + else: + smExpr = Group( Optional(NL) + + (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) ) + blockStatementExpr.ignore(_bslash + LineEnd()) + return smExpr.setName('indented block') + +alphas8bit = srange(r"[\0xc0-\0xd6\0xd8-\0xf6\0xf8-\0xff]") +punc8bit = srange(r"[\0xa1-\0xbf\0xd7\0xf7]") + +anyOpenTag,anyCloseTag = makeHTMLTags(Word(alphas,alphanums+"_:").setName('any tag')) +_htmlEntityMap = dict(zip("gt lt amp nbsp quot apos".split(),'><& "\'')) +commonHTMLEntity = Regex('&(?P<entity>' + '|'.join(_htmlEntityMap.keys()) +");").setName("common HTML entity") +def replaceHTMLEntity(t): + """Helper parser action to replace common HTML entities with their special characters""" + return _htmlEntityMap.get(t.entity) + +# it's easy to get these comment structures wrong - they're very common, so may as well make them available +cStyleComment = Combine(Regex(r"/\*(?:[^*]|\*(?!/))*") + '*/').setName("C style comment") +"Comment of the form C{/* ... */}" + +htmlComment = Regex(r"<!--[\s\S]*?-->").setName("HTML comment") +"Comment of the form C{<!-- ... -->}" + +restOfLine = Regex(r".*").leaveWhitespace().setName("rest of line") +dblSlashComment = Regex(r"//(?:\\\n|[^\n])*").setName("// comment") +"Comment of the form C{// ... (to end of line)}" + +cppStyleComment = Combine(Regex(r"/\*(?:[^*]|\*(?!/))*") + '*/'| dblSlashComment).setName("C++ style comment") +"Comment of either form C{L{cStyleComment}} or C{L{dblSlashComment}}" + +javaStyleComment = cppStyleComment +"Same as C{L{cppStyleComment}}" + +pythonStyleComment = Regex(r"#.*").setName("Python style comment") +"Comment of the form C{# ... (to end of line)}" + +_commasepitem = Combine(OneOrMore(Word(printables, excludeChars=',') + + Optional( Word(" \t") + + ~Literal(",") + ~LineEnd() ) ) ).streamline().setName("commaItem") +commaSeparatedList = delimitedList( Optional( quotedString.copy() | _commasepitem, default="") ).setName("commaSeparatedList") +"""(Deprecated) Predefined expression of 1 or more printable words or quoted strings, separated by commas. + This expression is deprecated in favor of L{pyparsing_common.comma_separated_list}.""" + +# some other useful expressions - using lower-case class name since we are really using this as a namespace +class pyparsing_common: + """ + Here are some common low-level expressions that may be useful in jump-starting parser development: + - numeric forms (L{integers<integer>}, L{reals<real>}, L{scientific notation<sci_real>}) + - common L{programming identifiers<identifier>} + - network addresses (L{MAC<mac_address>}, L{IPv4<ipv4_address>}, L{IPv6<ipv6_address>}) + - ISO8601 L{dates<iso8601_date>} and L{datetime<iso8601_datetime>} + - L{UUID<uuid>} + - L{comma-separated list<comma_separated_list>} + Parse actions: + - C{L{convertToInteger}} + - C{L{convertToFloat}} + - C{L{convertToDate}} + - C{L{convertToDatetime}} + - C{L{stripHTMLTags}} + - C{L{upcaseTokens}} + - C{L{downcaseTokens}} + + Example:: + pyparsing_common.number.runTests(''' + # any int or real number, returned as the appropriate type + 100 + -100 + +100 + 3.14159 + 6.02e23 + 1e-12 + ''') + + pyparsing_common.fnumber.runTests(''' + # any int or real number, returned as float + 100 + -100 + +100 + 3.14159 + 6.02e23 + 1e-12 + ''') + + pyparsing_common.hex_integer.runTests(''' + # hex numbers + 100 + FF + ''') + + pyparsing_common.fraction.runTests(''' + # fractions + 1/2 + -3/4 + ''') + + pyparsing_common.mixed_integer.runTests(''' + # mixed fractions + 1 + 1/2 + -3/4 + 1-3/4 + ''') + + import uuid + pyparsing_common.uuid.setParseAction(tokenMap(uuid.UUID)) + pyparsing_common.uuid.runTests(''' + # uuid + 12345678-1234-5678-1234-567812345678 + ''') + prints:: + # any int or real number, returned as the appropriate type + 100 + [100] + + -100 + [-100] + + +100 + [100] + + 3.14159 + [3.14159] + + 6.02e23 + [6.02e+23] + + 1e-12 + [1e-12] + + # any int or real number, returned as float + 100 + [100.0] + + -100 + [-100.0] + + +100 + [100.0] + + 3.14159 + [3.14159] + + 6.02e23 + [6.02e+23] + + 1e-12 + [1e-12] + + # hex numbers + 100 + [256] + + FF + [255] + + # fractions + 1/2 + [0.5] + + -3/4 + [-0.75] + + # mixed fractions + 1 + [1] + + 1/2 + [0.5] + + -3/4 + [-0.75] + + 1-3/4 + [1.75] + + # uuid + 12345678-1234-5678-1234-567812345678 + [UUID('12345678-1234-5678-1234-567812345678')] + """ + + convertToInteger = tokenMap(int) + """ + Parse action for converting parsed integers to Python int + """ + + convertToFloat = tokenMap(float) + """ + Parse action for converting parsed numbers to Python float + """ + + integer = Word(nums).setName("integer").setParseAction(convertToInteger) + """expression that parses an unsigned integer, returns an int""" + + hex_integer = Word(hexnums).setName("hex integer").setParseAction(tokenMap(int,16)) + """expression that parses a hexadecimal integer, returns an int""" + + signed_integer = Regex(r'[+-]?\d+').setName("signed integer").setParseAction(convertToInteger) + """expression that parses an integer with optional leading sign, returns an int""" + + fraction = (signed_integer().setParseAction(convertToFloat) + '/' + signed_integer().setParseAction(convertToFloat)).setName("fraction") + """fractional expression of an integer divided by an integer, returns a float""" + fraction.addParseAction(lambda t: t[0]/t[-1]) + + mixed_integer = (fraction | signed_integer + Optional(Optional('-').suppress() + fraction)).setName("fraction or mixed integer-fraction") + """mixed integer of the form 'integer - fraction', with optional leading integer, returns float""" + mixed_integer.addParseAction(sum) + + real = Regex(r'[+-]?\d+\.\d*').setName("real number").setParseAction(convertToFloat) + """expression that parses a floating point number and returns a float""" + + sci_real = Regex(r'[+-]?\d+([eE][+-]?\d+|\.\d*([eE][+-]?\d+)?)').setName("real number with scientific notation").setParseAction(convertToFloat) + """expression that parses a floating point number with optional scientific notation and returns a float""" + + # streamlining this expression makes the docs nicer-looking + number = (sci_real | real | signed_integer).streamline() + """any numeric expression, returns the corresponding Python type""" + + fnumber = Regex(r'[+-]?\d+\.?\d*([eE][+-]?\d+)?').setName("fnumber").setParseAction(convertToFloat) + """any int or real number, returned as float""" + + identifier = Word(alphas+'_', alphanums+'_').setName("identifier") + """typical code identifier (leading alpha or '_', followed by 0 or more alphas, nums, or '_')""" + + ipv4_address = Regex(r'(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})(\.(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})){3}').setName("IPv4 address") + "IPv4 address (C{0.0.0.0 - 255.255.255.255})" + + _ipv6_part = Regex(r'[0-9a-fA-F]{1,4}').setName("hex_integer") + _full_ipv6_address = (_ipv6_part + (':' + _ipv6_part)*7).setName("full IPv6 address") + _short_ipv6_address = (Optional(_ipv6_part + (':' + _ipv6_part)*(0,6)) + "::" + Optional(_ipv6_part + (':' + _ipv6_part)*(0,6))).setName("short IPv6 address") + _short_ipv6_address.addCondition(lambda t: sum(1 for tt in t if pyparsing_common._ipv6_part.matches(tt)) < 8) + _mixed_ipv6_address = ("::ffff:" + ipv4_address).setName("mixed IPv6 address") + ipv6_address = Combine((_full_ipv6_address | _mixed_ipv6_address | _short_ipv6_address).setName("IPv6 address")).setName("IPv6 address") + "IPv6 address (long, short, or mixed form)" + + mac_address = Regex(r'[0-9a-fA-F]{2}([:.-])[0-9a-fA-F]{2}(?:\1[0-9a-fA-F]{2}){4}').setName("MAC address") + "MAC address xx:xx:xx:xx:xx (may also have '-' or '.' delimiters)" + + @staticmethod + def convertToDate(fmt="%Y-%m-%d"): + """ + Helper to create a parse action for converting parsed date string to Python datetime.date + + Params - + - fmt - format to be passed to datetime.strptime (default=C{"%Y-%m-%d"}) + + Example:: + date_expr = pyparsing_common.iso8601_date.copy() + date_expr.setParseAction(pyparsing_common.convertToDate()) + print(date_expr.parseString("1999-12-31")) + prints:: + [datetime.date(1999, 12, 31)] + """ + def cvt_fn(s,l,t): + try: + return datetime.strptime(t[0], fmt).date() + except ValueError as ve: + raise ParseException(s, l, str(ve)) + return cvt_fn + + @staticmethod + def convertToDatetime(fmt="%Y-%m-%dT%H:%M:%S.%f"): + """ + Helper to create a parse action for converting parsed datetime string to Python datetime.datetime + + Params - + - fmt - format to be passed to datetime.strptime (default=C{"%Y-%m-%dT%H:%M:%S.%f"}) + + Example:: + dt_expr = pyparsing_common.iso8601_datetime.copy() + dt_expr.setParseAction(pyparsing_common.convertToDatetime()) + print(dt_expr.parseString("1999-12-31T23:59:59.999")) + prints:: + [datetime.datetime(1999, 12, 31, 23, 59, 59, 999000)] + """ + def cvt_fn(s,l,t): + try: + return datetime.strptime(t[0], fmt) + except ValueError as ve: + raise ParseException(s, l, str(ve)) + return cvt_fn + + iso8601_date = Regex(r'(?P<year>\d{4})(?:-(?P<month>\d\d)(?:-(?P<day>\d\d))?)?').setName("ISO8601 date") + "ISO8601 date (C{yyyy-mm-dd})" + + iso8601_datetime = Regex(r'(?P<year>\d{4})-(?P<month>\d\d)-(?P<day>\d\d)[T ](?P<hour>\d\d):(?P<minute>\d\d)(:(?P<second>\d\d(\.\d*)?)?)?(?P<tz>Z|[+-]\d\d:?\d\d)?').setName("ISO8601 datetime") + "ISO8601 datetime (C{yyyy-mm-ddThh:mm:ss.s(Z|+-00:00)}) - trailing seconds, milliseconds, and timezone optional; accepts separating C{'T'} or C{' '}" + + uuid = Regex(r'[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}').setName("UUID") + "UUID (C{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx})" + + _html_stripper = anyOpenTag.suppress() | anyCloseTag.suppress() + @staticmethod + def stripHTMLTags(s, l, tokens): + """ + Parse action to remove HTML tags from web page HTML source + + Example:: + # strip HTML links from normal text + text = '<td>More info at the <a href="http://pyparsing.wikispaces.com">pyparsing</a> wiki page</td>' + td,td_end = makeHTMLTags("TD") + table_text = td + SkipTo(td_end).setParseAction(pyparsing_common.stripHTMLTags)("body") + td_end + + print(table_text.parseString(text).body) # -> 'More info at the pyparsing wiki page' + """ + return pyparsing_common._html_stripper.transformString(tokens[0]) + + _commasepitem = Combine(OneOrMore(~Literal(",") + ~LineEnd() + Word(printables, excludeChars=',') + + Optional( White(" \t") ) ) ).streamline().setName("commaItem") + comma_separated_list = delimitedList( Optional( quotedString.copy() | _commasepitem, default="") ).setName("comma separated list") + """Predefined expression of 1 or more printable words or quoted strings, separated by commas.""" + + upcaseTokens = staticmethod(tokenMap(lambda t: _ustr(t).upper())) + """Parse action to convert tokens to upper case.""" + + downcaseTokens = staticmethod(tokenMap(lambda t: _ustr(t).lower())) + """Parse action to convert tokens to lower case.""" + + +if __name__ == "__main__": + + selectToken = CaselessLiteral("select") + fromToken = CaselessLiteral("from") + + ident = Word(alphas, alphanums + "_$") + + columnName = delimitedList(ident, ".", combine=True).setParseAction(upcaseTokens) + columnNameList = Group(delimitedList(columnName)).setName("columns") + columnSpec = ('*' | columnNameList) + + tableName = delimitedList(ident, ".", combine=True).setParseAction(upcaseTokens) + tableNameList = Group(delimitedList(tableName)).setName("tables") + + simpleSQL = selectToken("command") + columnSpec("columns") + fromToken + tableNameList("tables") + + # demo runTests method, including embedded comments in test string + simpleSQL.runTests(""" + # '*' as column list and dotted table name + select * from SYS.XYZZY + + # caseless match on "SELECT", and casts back to "select" + SELECT * from XYZZY, ABC + + # list of column names, and mixed case SELECT keyword + Select AA,BB,CC from Sys.dual + + # multiple tables + Select A, B, C from Sys.dual, Table2 + + # invalid SELECT keyword - should fail + Xelect A, B, C from Sys.dual + + # incomplete command - should fail + Select + + # invalid column name - should fail + Select ^^^ frox Sys.dual + + """) + + pyparsing_common.number.runTests(""" + 100 + -100 + +100 + 3.14159 + 6.02e23 + 1e-12 + """) + + # any int or real number, returned as float + pyparsing_common.fnumber.runTests(""" + 100 + -100 + +100 + 3.14159 + 6.02e23 + 1e-12 + """) + + pyparsing_common.hex_integer.runTests(""" + 100 + FF + """) + + import uuid + pyparsing_common.uuid.setParseAction(tokenMap(uuid.UUID)) + pyparsing_common.uuid.runTests(""" + 12345678-1234-5678-1234-567812345678 + """) diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/six.py b/venv/lib/python3.8/site-packages/setuptools/_vendor/six.py new file mode 100644 index 0000000..190c023 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/_vendor/six.py @@ -0,0 +1,868 @@ +"""Utilities for writing code that runs on Python 2 and 3""" + +# Copyright (c) 2010-2015 Benjamin Peterson +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from __future__ import absolute_import + +import functools +import itertools +import operator +import sys +import types + +__author__ = "Benjamin Peterson <benjamin@python.org>" +__version__ = "1.10.0" + + +# Useful for very coarse version differentiation. +PY2 = sys.version_info[0] == 2 +PY3 = sys.version_info[0] == 3 +PY34 = sys.version_info[0:2] >= (3, 4) + +if PY3: + string_types = str, + integer_types = int, + class_types = type, + text_type = str + binary_type = bytes + + MAXSIZE = sys.maxsize +else: + string_types = basestring, + integer_types = (int, long) + class_types = (type, types.ClassType) + text_type = unicode + binary_type = str + + if sys.platform.startswith("java"): + # Jython always uses 32 bits. + MAXSIZE = int((1 << 31) - 1) + else: + # It's possible to have sizeof(long) != sizeof(Py_ssize_t). + class X(object): + + def __len__(self): + return 1 << 31 + try: + len(X()) + except OverflowError: + # 32-bit + MAXSIZE = int((1 << 31) - 1) + else: + # 64-bit + MAXSIZE = int((1 << 63) - 1) + del X + + +def _add_doc(func, doc): + """Add documentation to a function.""" + func.__doc__ = doc + + +def _import_module(name): + """Import module, returning the module after the last dot.""" + __import__(name) + return sys.modules[name] + + +class _LazyDescr(object): + + def __init__(self, name): + self.name = name + + def __get__(self, obj, tp): + result = self._resolve() + setattr(obj, self.name, result) # Invokes __set__. + try: + # This is a bit ugly, but it avoids running this again by + # removing this descriptor. + delattr(obj.__class__, self.name) + except AttributeError: + pass + return result + + +class MovedModule(_LazyDescr): + + def __init__(self, name, old, new=None): + super(MovedModule, self).__init__(name) + if PY3: + if new is None: + new = name + self.mod = new + else: + self.mod = old + + def _resolve(self): + return _import_module(self.mod) + + def __getattr__(self, attr): + _module = self._resolve() + value = getattr(_module, attr) + setattr(self, attr, value) + return value + + +class _LazyModule(types.ModuleType): + + def __init__(self, name): + super(_LazyModule, self).__init__(name) + self.__doc__ = self.__class__.__doc__ + + def __dir__(self): + attrs = ["__doc__", "__name__"] + attrs += [attr.name for attr in self._moved_attributes] + return attrs + + # Subclasses should override this + _moved_attributes = [] + + +class MovedAttribute(_LazyDescr): + + def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None): + super(MovedAttribute, self).__init__(name) + if PY3: + if new_mod is None: + new_mod = name + self.mod = new_mod + if new_attr is None: + if old_attr is None: + new_attr = name + else: + new_attr = old_attr + self.attr = new_attr + else: + self.mod = old_mod + if old_attr is None: + old_attr = name + self.attr = old_attr + + def _resolve(self): + module = _import_module(self.mod) + return getattr(module, self.attr) + + +class _SixMetaPathImporter(object): + + """ + A meta path importer to import six.moves and its submodules. + + This class implements a PEP302 finder and loader. It should be compatible + with Python 2.5 and all existing versions of Python3 + """ + + def __init__(self, six_module_name): + self.name = six_module_name + self.known_modules = {} + + def _add_module(self, mod, *fullnames): + for fullname in fullnames: + self.known_modules[self.name + "." + fullname] = mod + + def _get_module(self, fullname): + return self.known_modules[self.name + "." + fullname] + + def find_module(self, fullname, path=None): + if fullname in self.known_modules: + return self + return None + + def __get_module(self, fullname): + try: + return self.known_modules[fullname] + except KeyError: + raise ImportError("This loader does not know module " + fullname) + + def load_module(self, fullname): + try: + # in case of a reload + return sys.modules[fullname] + except KeyError: + pass + mod = self.__get_module(fullname) + if isinstance(mod, MovedModule): + mod = mod._resolve() + else: + mod.__loader__ = self + sys.modules[fullname] = mod + return mod + + def is_package(self, fullname): + """ + Return true, if the named module is a package. + + We need this method to get correct spec objects with + Python 3.4 (see PEP451) + """ + return hasattr(self.__get_module(fullname), "__path__") + + def get_code(self, fullname): + """Return None + + Required, if is_package is implemented""" + self.__get_module(fullname) # eventually raises ImportError + return None + get_source = get_code # same as get_code + +_importer = _SixMetaPathImporter(__name__) + + +class _MovedItems(_LazyModule): + + """Lazy loading of moved objects""" + __path__ = [] # mark as package + + +_moved_attributes = [ + MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"), + MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"), + MovedAttribute("filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"), + MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"), + MovedAttribute("intern", "__builtin__", "sys"), + MovedAttribute("map", "itertools", "builtins", "imap", "map"), + MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"), + MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"), + MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"), + MovedAttribute("reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload"), + MovedAttribute("reduce", "__builtin__", "functools"), + MovedAttribute("shlex_quote", "pipes", "shlex", "quote"), + MovedAttribute("StringIO", "StringIO", "io"), + MovedAttribute("UserDict", "UserDict", "collections"), + MovedAttribute("UserList", "UserList", "collections"), + MovedAttribute("UserString", "UserString", "collections"), + MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"), + MovedAttribute("zip", "itertools", "builtins", "izip", "zip"), + MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"), + MovedModule("builtins", "__builtin__"), + MovedModule("configparser", "ConfigParser"), + MovedModule("copyreg", "copy_reg"), + MovedModule("dbm_gnu", "gdbm", "dbm.gnu"), + MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread"), + MovedModule("http_cookiejar", "cookielib", "http.cookiejar"), + MovedModule("http_cookies", "Cookie", "http.cookies"), + MovedModule("html_entities", "htmlentitydefs", "html.entities"), + MovedModule("html_parser", "HTMLParser", "html.parser"), + MovedModule("http_client", "httplib", "http.client"), + MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"), + MovedModule("email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart"), + MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"), + MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"), + MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"), + MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"), + MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"), + MovedModule("cPickle", "cPickle", "pickle"), + MovedModule("queue", "Queue"), + MovedModule("reprlib", "repr"), + MovedModule("socketserver", "SocketServer"), + MovedModule("_thread", "thread", "_thread"), + MovedModule("tkinter", "Tkinter"), + MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"), + MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"), + MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"), + MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"), + MovedModule("tkinter_tix", "Tix", "tkinter.tix"), + MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"), + MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"), + MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"), + MovedModule("tkinter_colorchooser", "tkColorChooser", + "tkinter.colorchooser"), + MovedModule("tkinter_commondialog", "tkCommonDialog", + "tkinter.commondialog"), + MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"), + MovedModule("tkinter_font", "tkFont", "tkinter.font"), + MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"), + MovedModule("tkinter_tksimpledialog", "tkSimpleDialog", + "tkinter.simpledialog"), + MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"), + MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"), + MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"), + MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"), + MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"), + MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"), +] +# Add windows specific modules. +if sys.platform == "win32": + _moved_attributes += [ + MovedModule("winreg", "_winreg"), + ] + +for attr in _moved_attributes: + setattr(_MovedItems, attr.name, attr) + if isinstance(attr, MovedModule): + _importer._add_module(attr, "moves." + attr.name) +del attr + +_MovedItems._moved_attributes = _moved_attributes + +moves = _MovedItems(__name__ + ".moves") +_importer._add_module(moves, "moves") + + +class Module_six_moves_urllib_parse(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_parse""" + + +_urllib_parse_moved_attributes = [ + MovedAttribute("ParseResult", "urlparse", "urllib.parse"), + MovedAttribute("SplitResult", "urlparse", "urllib.parse"), + MovedAttribute("parse_qs", "urlparse", "urllib.parse"), + MovedAttribute("parse_qsl", "urlparse", "urllib.parse"), + MovedAttribute("urldefrag", "urlparse", "urllib.parse"), + MovedAttribute("urljoin", "urlparse", "urllib.parse"), + MovedAttribute("urlparse", "urlparse", "urllib.parse"), + MovedAttribute("urlsplit", "urlparse", "urllib.parse"), + MovedAttribute("urlunparse", "urlparse", "urllib.parse"), + MovedAttribute("urlunsplit", "urlparse", "urllib.parse"), + MovedAttribute("quote", "urllib", "urllib.parse"), + MovedAttribute("quote_plus", "urllib", "urllib.parse"), + MovedAttribute("unquote", "urllib", "urllib.parse"), + MovedAttribute("unquote_plus", "urllib", "urllib.parse"), + MovedAttribute("urlencode", "urllib", "urllib.parse"), + MovedAttribute("splitquery", "urllib", "urllib.parse"), + MovedAttribute("splittag", "urllib", "urllib.parse"), + MovedAttribute("splituser", "urllib", "urllib.parse"), + MovedAttribute("uses_fragment", "urlparse", "urllib.parse"), + MovedAttribute("uses_netloc", "urlparse", "urllib.parse"), + MovedAttribute("uses_params", "urlparse", "urllib.parse"), + MovedAttribute("uses_query", "urlparse", "urllib.parse"), + MovedAttribute("uses_relative", "urlparse", "urllib.parse"), +] +for attr in _urllib_parse_moved_attributes: + setattr(Module_six_moves_urllib_parse, attr.name, attr) +del attr + +Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes + +_importer._add_module(Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"), + "moves.urllib_parse", "moves.urllib.parse") + + +class Module_six_moves_urllib_error(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_error""" + + +_urllib_error_moved_attributes = [ + MovedAttribute("URLError", "urllib2", "urllib.error"), + MovedAttribute("HTTPError", "urllib2", "urllib.error"), + MovedAttribute("ContentTooShortError", "urllib", "urllib.error"), +] +for attr in _urllib_error_moved_attributes: + setattr(Module_six_moves_urllib_error, attr.name, attr) +del attr + +Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes + +_importer._add_module(Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"), + "moves.urllib_error", "moves.urllib.error") + + +class Module_six_moves_urllib_request(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_request""" + + +_urllib_request_moved_attributes = [ + MovedAttribute("urlopen", "urllib2", "urllib.request"), + MovedAttribute("install_opener", "urllib2", "urllib.request"), + MovedAttribute("build_opener", "urllib2", "urllib.request"), + MovedAttribute("pathname2url", "urllib", "urllib.request"), + MovedAttribute("url2pathname", "urllib", "urllib.request"), + MovedAttribute("getproxies", "urllib", "urllib.request"), + MovedAttribute("Request", "urllib2", "urllib.request"), + MovedAttribute("OpenerDirector", "urllib2", "urllib.request"), + MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"), + MovedAttribute("ProxyHandler", "urllib2", "urllib.request"), + MovedAttribute("BaseHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"), + MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"), + MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"), + MovedAttribute("FileHandler", "urllib2", "urllib.request"), + MovedAttribute("FTPHandler", "urllib2", "urllib.request"), + MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"), + MovedAttribute("UnknownHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"), + MovedAttribute("urlretrieve", "urllib", "urllib.request"), + MovedAttribute("urlcleanup", "urllib", "urllib.request"), + MovedAttribute("URLopener", "urllib", "urllib.request"), + MovedAttribute("FancyURLopener", "urllib", "urllib.request"), + MovedAttribute("proxy_bypass", "urllib", "urllib.request"), +] +for attr in _urllib_request_moved_attributes: + setattr(Module_six_moves_urllib_request, attr.name, attr) +del attr + +Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes + +_importer._add_module(Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"), + "moves.urllib_request", "moves.urllib.request") + + +class Module_six_moves_urllib_response(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_response""" + + +_urllib_response_moved_attributes = [ + MovedAttribute("addbase", "urllib", "urllib.response"), + MovedAttribute("addclosehook", "urllib", "urllib.response"), + MovedAttribute("addinfo", "urllib", "urllib.response"), + MovedAttribute("addinfourl", "urllib", "urllib.response"), +] +for attr in _urllib_response_moved_attributes: + setattr(Module_six_moves_urllib_response, attr.name, attr) +del attr + +Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes + +_importer._add_module(Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"), + "moves.urllib_response", "moves.urllib.response") + + +class Module_six_moves_urllib_robotparser(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_robotparser""" + + +_urllib_robotparser_moved_attributes = [ + MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"), +] +for attr in _urllib_robotparser_moved_attributes: + setattr(Module_six_moves_urllib_robotparser, attr.name, attr) +del attr + +Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes + +_importer._add_module(Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"), + "moves.urllib_robotparser", "moves.urllib.robotparser") + + +class Module_six_moves_urllib(types.ModuleType): + + """Create a six.moves.urllib namespace that resembles the Python 3 namespace""" + __path__ = [] # mark as package + parse = _importer._get_module("moves.urllib_parse") + error = _importer._get_module("moves.urllib_error") + request = _importer._get_module("moves.urllib_request") + response = _importer._get_module("moves.urllib_response") + robotparser = _importer._get_module("moves.urllib_robotparser") + + def __dir__(self): + return ['parse', 'error', 'request', 'response', 'robotparser'] + +_importer._add_module(Module_six_moves_urllib(__name__ + ".moves.urllib"), + "moves.urllib") + + +def add_move(move): + """Add an item to six.moves.""" + setattr(_MovedItems, move.name, move) + + +def remove_move(name): + """Remove item from six.moves.""" + try: + delattr(_MovedItems, name) + except AttributeError: + try: + del moves.__dict__[name] + except KeyError: + raise AttributeError("no such move, %r" % (name,)) + + +if PY3: + _meth_func = "__func__" + _meth_self = "__self__" + + _func_closure = "__closure__" + _func_code = "__code__" + _func_defaults = "__defaults__" + _func_globals = "__globals__" +else: + _meth_func = "im_func" + _meth_self = "im_self" + + _func_closure = "func_closure" + _func_code = "func_code" + _func_defaults = "func_defaults" + _func_globals = "func_globals" + + +try: + advance_iterator = next +except NameError: + def advance_iterator(it): + return it.next() +next = advance_iterator + + +try: + callable = callable +except NameError: + def callable(obj): + return any("__call__" in klass.__dict__ for klass in type(obj).__mro__) + + +if PY3: + def get_unbound_function(unbound): + return unbound + + create_bound_method = types.MethodType + + def create_unbound_method(func, cls): + return func + + Iterator = object +else: + def get_unbound_function(unbound): + return unbound.im_func + + def create_bound_method(func, obj): + return types.MethodType(func, obj, obj.__class__) + + def create_unbound_method(func, cls): + return types.MethodType(func, None, cls) + + class Iterator(object): + + def next(self): + return type(self).__next__(self) + + callable = callable +_add_doc(get_unbound_function, + """Get the function out of a possibly unbound function""") + + +get_method_function = operator.attrgetter(_meth_func) +get_method_self = operator.attrgetter(_meth_self) +get_function_closure = operator.attrgetter(_func_closure) +get_function_code = operator.attrgetter(_func_code) +get_function_defaults = operator.attrgetter(_func_defaults) +get_function_globals = operator.attrgetter(_func_globals) + + +if PY3: + def iterkeys(d, **kw): + return iter(d.keys(**kw)) + + def itervalues(d, **kw): + return iter(d.values(**kw)) + + def iteritems(d, **kw): + return iter(d.items(**kw)) + + def iterlists(d, **kw): + return iter(d.lists(**kw)) + + viewkeys = operator.methodcaller("keys") + + viewvalues = operator.methodcaller("values") + + viewitems = operator.methodcaller("items") +else: + def iterkeys(d, **kw): + return d.iterkeys(**kw) + + def itervalues(d, **kw): + return d.itervalues(**kw) + + def iteritems(d, **kw): + return d.iteritems(**kw) + + def iterlists(d, **kw): + return d.iterlists(**kw) + + viewkeys = operator.methodcaller("viewkeys") + + viewvalues = operator.methodcaller("viewvalues") + + viewitems = operator.methodcaller("viewitems") + +_add_doc(iterkeys, "Return an iterator over the keys of a dictionary.") +_add_doc(itervalues, "Return an iterator over the values of a dictionary.") +_add_doc(iteritems, + "Return an iterator over the (key, value) pairs of a dictionary.") +_add_doc(iterlists, + "Return an iterator over the (key, [values]) pairs of a dictionary.") + + +if PY3: + def b(s): + return s.encode("latin-1") + + def u(s): + return s + unichr = chr + import struct + int2byte = struct.Struct(">B").pack + del struct + byte2int = operator.itemgetter(0) + indexbytes = operator.getitem + iterbytes = iter + import io + StringIO = io.StringIO + BytesIO = io.BytesIO + _assertCountEqual = "assertCountEqual" + if sys.version_info[1] <= 1: + _assertRaisesRegex = "assertRaisesRegexp" + _assertRegex = "assertRegexpMatches" + else: + _assertRaisesRegex = "assertRaisesRegex" + _assertRegex = "assertRegex" +else: + def b(s): + return s + # Workaround for standalone backslash + + def u(s): + return unicode(s.replace(r'\\', r'\\\\'), "unicode_escape") + unichr = unichr + int2byte = chr + + def byte2int(bs): + return ord(bs[0]) + + def indexbytes(buf, i): + return ord(buf[i]) + iterbytes = functools.partial(itertools.imap, ord) + import StringIO + StringIO = BytesIO = StringIO.StringIO + _assertCountEqual = "assertItemsEqual" + _assertRaisesRegex = "assertRaisesRegexp" + _assertRegex = "assertRegexpMatches" +_add_doc(b, """Byte literal""") +_add_doc(u, """Text literal""") + + +def assertCountEqual(self, *args, **kwargs): + return getattr(self, _assertCountEqual)(*args, **kwargs) + + +def assertRaisesRegex(self, *args, **kwargs): + return getattr(self, _assertRaisesRegex)(*args, **kwargs) + + +def assertRegex(self, *args, **kwargs): + return getattr(self, _assertRegex)(*args, **kwargs) + + +if PY3: + exec_ = getattr(moves.builtins, "exec") + + def reraise(tp, value, tb=None): + if value is None: + value = tp() + if value.__traceback__ is not tb: + raise value.with_traceback(tb) + raise value + +else: + def exec_(_code_, _globs_=None, _locs_=None): + """Execute code in a namespace.""" + if _globs_ is None: + frame = sys._getframe(1) + _globs_ = frame.f_globals + if _locs_ is None: + _locs_ = frame.f_locals + del frame + elif _locs_ is None: + _locs_ = _globs_ + exec("""exec _code_ in _globs_, _locs_""") + + exec_("""def reraise(tp, value, tb=None): + raise tp, value, tb +""") + + +if sys.version_info[:2] == (3, 2): + exec_("""def raise_from(value, from_value): + if from_value is None: + raise value + raise value from from_value +""") +elif sys.version_info[:2] > (3, 2): + exec_("""def raise_from(value, from_value): + raise value from from_value +""") +else: + def raise_from(value, from_value): + raise value + + +print_ = getattr(moves.builtins, "print", None) +if print_ is None: + def print_(*args, **kwargs): + """The new-style print function for Python 2.4 and 2.5.""" + fp = kwargs.pop("file", sys.stdout) + if fp is None: + return + + def write(data): + if not isinstance(data, basestring): + data = str(data) + # If the file has an encoding, encode unicode with it. + if (isinstance(fp, file) and + isinstance(data, unicode) and + fp.encoding is not None): + errors = getattr(fp, "errors", None) + if errors is None: + errors = "strict" + data = data.encode(fp.encoding, errors) + fp.write(data) + want_unicode = False + sep = kwargs.pop("sep", None) + if sep is not None: + if isinstance(sep, unicode): + want_unicode = True + elif not isinstance(sep, str): + raise TypeError("sep must be None or a string") + end = kwargs.pop("end", None) + if end is not None: + if isinstance(end, unicode): + want_unicode = True + elif not isinstance(end, str): + raise TypeError("end must be None or a string") + if kwargs: + raise TypeError("invalid keyword arguments to print()") + if not want_unicode: + for arg in args: + if isinstance(arg, unicode): + want_unicode = True + break + if want_unicode: + newline = unicode("\n") + space = unicode(" ") + else: + newline = "\n" + space = " " + if sep is None: + sep = space + if end is None: + end = newline + for i, arg in enumerate(args): + if i: + write(sep) + write(arg) + write(end) +if sys.version_info[:2] < (3, 3): + _print = print_ + + def print_(*args, **kwargs): + fp = kwargs.get("file", sys.stdout) + flush = kwargs.pop("flush", False) + _print(*args, **kwargs) + if flush and fp is not None: + fp.flush() + +_add_doc(reraise, """Reraise an exception.""") + +if sys.version_info[0:2] < (3, 4): + def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS, + updated=functools.WRAPPER_UPDATES): + def wrapper(f): + f = functools.wraps(wrapped, assigned, updated)(f) + f.__wrapped__ = wrapped + return f + return wrapper +else: + wraps = functools.wraps + + +def with_metaclass(meta, *bases): + """Create a base class with a metaclass.""" + # This requires a bit of explanation: the basic idea is to make a dummy + # metaclass for one level of class instantiation that replaces itself with + # the actual metaclass. + class metaclass(meta): + + def __new__(cls, name, this_bases, d): + return meta(name, bases, d) + return type.__new__(metaclass, 'temporary_class', (), {}) + + +def add_metaclass(metaclass): + """Class decorator for creating a class with a metaclass.""" + def wrapper(cls): + orig_vars = cls.__dict__.copy() + slots = orig_vars.get('__slots__') + if slots is not None: + if isinstance(slots, str): + slots = [slots] + for slots_var in slots: + orig_vars.pop(slots_var) + orig_vars.pop('__dict__', None) + orig_vars.pop('__weakref__', None) + return metaclass(cls.__name__, cls.__bases__, orig_vars) + return wrapper + + +def python_2_unicode_compatible(klass): + """ + A decorator that defines __unicode__ and __str__ methods under Python 2. + Under Python 3 it does nothing. + + To support Python 2 and 3 with a single code base, define a __str__ method + returning text and apply this decorator to the class. + """ + if PY2: + if '__str__' not in klass.__dict__: + raise ValueError("@python_2_unicode_compatible cannot be applied " + "to %s because it doesn't define __str__()." % + klass.__name__) + klass.__unicode__ = klass.__str__ + klass.__str__ = lambda self: self.__unicode__().encode('utf-8') + return klass + + +# Complete the moves implementation. +# This code is at the end of this module to speed up module loading. +# Turn this module into a package. +__path__ = [] # required for PEP 302 and PEP 451 +__package__ = __name__ # see PEP 366 @ReservedAssignment +if globals().get("__spec__") is not None: + __spec__.submodule_search_locations = [] # PEP 451 @UndefinedVariable +# Remove other six meta path importers, since they cause problems. This can +# happen if six is removed from sys.modules and then reloaded. (Setuptools does +# this for some reason.) +if sys.meta_path: + for i, importer in enumerate(sys.meta_path): + # Here's some real nastiness: Another "instance" of the six module might + # be floating around. Therefore, we can't use isinstance() to check for + # the six meta path importer, since the other six instance will have + # inserted an importer with different class. + if (type(importer).__name__ == "_SixMetaPathImporter" and + importer.name == __name__): + del sys.meta_path[i] + break + del i, importer +# Finally, add the importer to the meta path import hook. +sys.meta_path.append(_importer) diff --git a/venv/lib/python3.8/site-packages/setuptools/archive_util.py b/venv/lib/python3.8/site-packages/setuptools/archive_util.py new file mode 100644 index 0000000..8143604 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/archive_util.py @@ -0,0 +1,173 @@ +"""Utilities for extracting common archive formats""" + +import zipfile +import tarfile +import os +import shutil +import posixpath +import contextlib +from distutils.errors import DistutilsError + +from pkg_resources import ensure_directory + +__all__ = [ + "unpack_archive", "unpack_zipfile", "unpack_tarfile", "default_filter", + "UnrecognizedFormat", "extraction_drivers", "unpack_directory", +] + + +class UnrecognizedFormat(DistutilsError): + """Couldn't recognize the archive type""" + + +def default_filter(src, dst): + """The default progress/filter callback; returns True for all files""" + return dst + + +def unpack_archive(filename, extract_dir, progress_filter=default_filter, + drivers=None): + """Unpack `filename` to `extract_dir`, or raise ``UnrecognizedFormat`` + + `progress_filter` is a function taking two arguments: a source path + internal to the archive ('/'-separated), and a filesystem path where it + will be extracted. The callback must return the desired extract path + (which may be the same as the one passed in), or else ``None`` to skip + that file or directory. The callback can thus be used to report on the + progress of the extraction, as well as to filter the items extracted or + alter their extraction paths. + + `drivers`, if supplied, must be a non-empty sequence of functions with the + same signature as this function (minus the `drivers` argument), that raise + ``UnrecognizedFormat`` if they do not support extracting the designated + archive type. The `drivers` are tried in sequence until one is found that + does not raise an error, or until all are exhausted (in which case + ``UnrecognizedFormat`` is raised). If you do not supply a sequence of + drivers, the module's ``extraction_drivers`` constant will be used, which + means that ``unpack_zipfile`` and ``unpack_tarfile`` will be tried, in that + order. + """ + for driver in drivers or extraction_drivers: + try: + driver(filename, extract_dir, progress_filter) + except UnrecognizedFormat: + continue + else: + return + else: + raise UnrecognizedFormat( + "Not a recognized archive type: %s" % filename + ) + + +def unpack_directory(filename, extract_dir, progress_filter=default_filter): + """"Unpack" a directory, using the same interface as for archives + + Raises ``UnrecognizedFormat`` if `filename` is not a directory + """ + if not os.path.isdir(filename): + raise UnrecognizedFormat("%s is not a directory" % filename) + + paths = { + filename: ('', extract_dir), + } + for base, dirs, files in os.walk(filename): + src, dst = paths[base] + for d in dirs: + paths[os.path.join(base, d)] = src + d + '/', os.path.join(dst, d) + for f in files: + target = os.path.join(dst, f) + target = progress_filter(src + f, target) + if not target: + # skip non-files + continue + ensure_directory(target) + f = os.path.join(base, f) + shutil.copyfile(f, target) + shutil.copystat(f, target) + + +def unpack_zipfile(filename, extract_dir, progress_filter=default_filter): + """Unpack zip `filename` to `extract_dir` + + Raises ``UnrecognizedFormat`` if `filename` is not a zipfile (as determined + by ``zipfile.is_zipfile()``). See ``unpack_archive()`` for an explanation + of the `progress_filter` argument. + """ + + if not zipfile.is_zipfile(filename): + raise UnrecognizedFormat("%s is not a zip file" % (filename,)) + + with zipfile.ZipFile(filename) as z: + for info in z.infolist(): + name = info.filename + + # don't extract absolute paths or ones with .. in them + if name.startswith('/') or '..' in name.split('/'): + continue + + target = os.path.join(extract_dir, *name.split('/')) + target = progress_filter(name, target) + if not target: + continue + if name.endswith('/'): + # directory + ensure_directory(target) + else: + # file + ensure_directory(target) + data = z.read(info.filename) + with open(target, 'wb') as f: + f.write(data) + unix_attributes = info.external_attr >> 16 + if unix_attributes: + os.chmod(target, unix_attributes) + + +def unpack_tarfile(filename, extract_dir, progress_filter=default_filter): + """Unpack tar/tar.gz/tar.bz2 `filename` to `extract_dir` + + Raises ``UnrecognizedFormat`` if `filename` is not a tarfile (as determined + by ``tarfile.open()``). See ``unpack_archive()`` for an explanation + of the `progress_filter` argument. + """ + try: + tarobj = tarfile.open(filename) + except tarfile.TarError: + raise UnrecognizedFormat( + "%s is not a compressed or uncompressed tar file" % (filename,) + ) + with contextlib.closing(tarobj): + # don't do any chowning! + tarobj.chown = lambda *args: None + for member in tarobj: + name = member.name + # don't extract absolute paths or ones with .. in them + if not name.startswith('/') and '..' not in name.split('/'): + prelim_dst = os.path.join(extract_dir, *name.split('/')) + + # resolve any links and to extract the link targets as normal + # files + while member is not None and (member.islnk() or member.issym()): + linkpath = member.linkname + if member.issym(): + base = posixpath.dirname(member.name) + linkpath = posixpath.join(base, linkpath) + linkpath = posixpath.normpath(linkpath) + member = tarobj._getmember(linkpath) + + if member is not None and (member.isfile() or member.isdir()): + final_dst = progress_filter(name, prelim_dst) + if final_dst: + if final_dst.endswith(os.sep): + final_dst = final_dst[:-1] + try: + # XXX Ugh + tarobj._extract_member(member, final_dst) + except tarfile.ExtractError: + # chown/chmod/mkfifo/mknode/makedev failed + pass + return True + + +extraction_drivers = unpack_directory, unpack_zipfile, unpack_tarfile diff --git a/venv/lib/python3.8/site-packages/setuptools/build_meta.py b/venv/lib/python3.8/site-packages/setuptools/build_meta.py new file mode 100644 index 0000000..10c4b52 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/build_meta.py @@ -0,0 +1,257 @@ +"""A PEP 517 interface to setuptools + +Previously, when a user or a command line tool (let's call it a "frontend") +needed to make a request of setuptools to take a certain action, for +example, generating a list of installation requirements, the frontend would +would call "setup.py egg_info" or "setup.py bdist_wheel" on the command line. + +PEP 517 defines a different method of interfacing with setuptools. Rather +than calling "setup.py" directly, the frontend should: + + 1. Set the current directory to the directory with a setup.py file + 2. Import this module into a safe python interpreter (one in which + setuptools can potentially set global variables or crash hard). + 3. Call one of the functions defined in PEP 517. + +What each function does is defined in PEP 517. However, here is a "casual" +definition of the functions (this definition should not be relied on for +bug reports or API stability): + + - `build_wheel`: build a wheel in the folder and return the basename + - `get_requires_for_build_wheel`: get the `setup_requires` to build + - `prepare_metadata_for_build_wheel`: get the `install_requires` + - `build_sdist`: build an sdist in the folder and return the basename + - `get_requires_for_build_sdist`: get the `setup_requires` to build + +Again, this is not a formal definition! Just a "taste" of the module. +""" + +import io +import os +import sys +import tokenize +import shutil +import contextlib + +import setuptools +import distutils +from setuptools.py31compat import TemporaryDirectory + +from pkg_resources import parse_requirements +from pkg_resources.py31compat import makedirs + +__all__ = ['get_requires_for_build_sdist', + 'get_requires_for_build_wheel', + 'prepare_metadata_for_build_wheel', + 'build_wheel', + 'build_sdist', + '__legacy__', + 'SetupRequirementsError'] + +class SetupRequirementsError(BaseException): + def __init__(self, specifiers): + self.specifiers = specifiers + + +class Distribution(setuptools.dist.Distribution): + def fetch_build_eggs(self, specifiers): + specifier_list = list(map(str, parse_requirements(specifiers))) + + raise SetupRequirementsError(specifier_list) + + @classmethod + @contextlib.contextmanager + def patch(cls): + """ + Replace + distutils.dist.Distribution with this class + for the duration of this context. + """ + orig = distutils.core.Distribution + distutils.core.Distribution = cls + try: + yield + finally: + distutils.core.Distribution = orig + + +def _to_str(s): + """ + Convert a filename to a string (on Python 2, explicitly + a byte string, not Unicode) as distutils checks for the + exact type str. + """ + if sys.version_info[0] == 2 and not isinstance(s, str): + # Assume it's Unicode, as that's what the PEP says + # should be provided. + return s.encode(sys.getfilesystemencoding()) + return s + + +def _get_immediate_subdirectories(a_dir): + return [name for name in os.listdir(a_dir) + if os.path.isdir(os.path.join(a_dir, name))] + + +def _file_with_extension(directory, extension): + matching = ( + f for f in os.listdir(directory) + if f.endswith(extension) + ) + file, = matching + return file + + +def _open_setup_script(setup_script): + if not os.path.exists(setup_script): + # Supply a default setup.py + return io.StringIO(u"from setuptools import setup; setup()") + + return getattr(tokenize, 'open', open)(setup_script) + + +class _BuildMetaBackend(object): + + def _fix_config(self, config_settings): + config_settings = config_settings or {} + config_settings.setdefault('--global-option', []) + return config_settings + + def _get_build_requires(self, config_settings, requirements): + config_settings = self._fix_config(config_settings) + + sys.argv = sys.argv[:1] + ['egg_info'] + \ + config_settings["--global-option"] + try: + with Distribution.patch(): + self.run_setup() + except SetupRequirementsError as e: + requirements += e.specifiers + + return requirements + + def run_setup(self, setup_script='setup.py'): + # Note that we can reuse our build directory between calls + # Correctness comes first, then optimization later + __file__ = setup_script + __name__ = '__main__' + + with _open_setup_script(__file__) as f: + code = f.read().replace(r'\r\n', r'\n') + + exec(compile(code, __file__, 'exec'), locals()) + + def get_requires_for_build_wheel(self, config_settings=None): + config_settings = self._fix_config(config_settings) + return self._get_build_requires(config_settings, requirements=['wheel']) + + def get_requires_for_build_sdist(self, config_settings=None): + config_settings = self._fix_config(config_settings) + return self._get_build_requires(config_settings, requirements=[]) + + def prepare_metadata_for_build_wheel(self, metadata_directory, + config_settings=None): + sys.argv = sys.argv[:1] + ['dist_info', '--egg-base', + _to_str(metadata_directory)] + self.run_setup() + + dist_info_directory = metadata_directory + while True: + dist_infos = [f for f in os.listdir(dist_info_directory) + if f.endswith('.dist-info')] + + if (len(dist_infos) == 0 and + len(_get_immediate_subdirectories(dist_info_directory)) == 1): + + dist_info_directory = os.path.join( + dist_info_directory, os.listdir(dist_info_directory)[0]) + continue + + assert len(dist_infos) == 1 + break + + # PEP 517 requires that the .dist-info directory be placed in the + # metadata_directory. To comply, we MUST copy the directory to the root + if dist_info_directory != metadata_directory: + shutil.move( + os.path.join(dist_info_directory, dist_infos[0]), + metadata_directory) + shutil.rmtree(dist_info_directory, ignore_errors=True) + + return dist_infos[0] + + def _build_with_temp_dir(self, setup_command, result_extension, + result_directory, config_settings): + config_settings = self._fix_config(config_settings) + result_directory = os.path.abspath(result_directory) + + # Build in a temporary directory, then copy to the target. + makedirs(result_directory, exist_ok=True) + with TemporaryDirectory(dir=result_directory) as tmp_dist_dir: + sys.argv = (sys.argv[:1] + setup_command + + ['--dist-dir', tmp_dist_dir] + + config_settings["--global-option"]) + self.run_setup() + + result_basename = _file_with_extension(tmp_dist_dir, result_extension) + result_path = os.path.join(result_directory, result_basename) + if os.path.exists(result_path): + # os.rename will fail overwriting on non-Unix. + os.remove(result_path) + os.rename(os.path.join(tmp_dist_dir, result_basename), result_path) + + return result_basename + + + def build_wheel(self, wheel_directory, config_settings=None, + metadata_directory=None): + return self._build_with_temp_dir(['bdist_wheel'], '.whl', + wheel_directory, config_settings) + + def build_sdist(self, sdist_directory, config_settings=None): + return self._build_with_temp_dir(['sdist', '--formats', 'gztar'], + '.tar.gz', sdist_directory, + config_settings) + + +class _BuildMetaLegacyBackend(_BuildMetaBackend): + """Compatibility backend for setuptools + + This is a version of setuptools.build_meta that endeavors to maintain backwards + compatibility with pre-PEP 517 modes of invocation. It exists as a temporary + bridge between the old packaging mechanism and the new packaging mechanism, + and will eventually be removed. + """ + def run_setup(self, setup_script='setup.py'): + # In order to maintain compatibility with scripts assuming that + # the setup.py script is in a directory on the PYTHONPATH, inject + # '' into sys.path. (pypa/setuptools#1642) + sys_path = list(sys.path) # Save the original path + + script_dir = os.path.dirname(os.path.abspath(setup_script)) + if script_dir not in sys.path: + sys.path.insert(0, script_dir) + + try: + super(_BuildMetaLegacyBackend, + self).run_setup(setup_script=setup_script) + finally: + # While PEP 517 frontends should be calling each hook in a fresh + # subprocess according to the standard (and thus it should not be + # strictly necessary to restore the old sys.path), we'll restore + # the original path so that the path manipulation does not persist + # within the hook after run_setup is called. + sys.path[:] = sys_path + +# The primary backend +_BACKEND = _BuildMetaBackend() + +get_requires_for_build_wheel = _BACKEND.get_requires_for_build_wheel +get_requires_for_build_sdist = _BACKEND.get_requires_for_build_sdist +prepare_metadata_for_build_wheel = _BACKEND.prepare_metadata_for_build_wheel +build_wheel = _BACKEND.build_wheel +build_sdist = _BACKEND.build_sdist + + +# The legacy backend +__legacy__ = _BuildMetaLegacyBackend() diff --git a/venv/lib/python3.8/site-packages/setuptools/cli-32.exe b/venv/lib/python3.8/site-packages/setuptools/cli-32.exe new file mode 100644 index 0000000000000000000000000000000000000000..b1487b7819e7286577a043c7726fbe0ca1543083 GIT binary patch literal 65536 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/setuptools/cli-64.exe b/venv/lib/python3.8/site-packages/setuptools/cli-64.exe new file mode 100644 index 0000000000000000000000000000000000000000..675e6bf3743f3d3011c238657e7128ee9960ef7f GIT binary patch literal 74752 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/setuptools/cli.exe b/venv/lib/python3.8/site-packages/setuptools/cli.exe new file mode 100644 index 0000000000000000000000000000000000000000..b1487b7819e7286577a043c7726fbe0ca1543083 GIT binary patch literal 65536 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/setuptools/command/__init__.py b/venv/lib/python3.8/site-packages/setuptools/command/__init__.py new file mode 100644 index 0000000..743f558 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/command/__init__.py @@ -0,0 +1,17 @@ +__all__ = [ + 'alias', 'bdist_egg', 'bdist_rpm', 'build_ext', 'build_py', 'develop', + 'easy_install', 'egg_info', 'install', 'install_lib', 'rotate', 'saveopts', + 'sdist', 'setopt', 'test', 'install_egg_info', 'install_scripts', + 'bdist_wininst', 'upload_docs', 'build_clib', 'dist_info', +] + +from distutils.command.bdist import bdist +import sys + +from setuptools.command import install_scripts + +if 'egg' not in bdist.format_commands: + bdist.format_command['egg'] = ('bdist_egg', "Python .egg file") + bdist.format_commands.append('egg') + +del bdist, sys diff --git a/venv/lib/python3.8/site-packages/setuptools/command/alias.py b/venv/lib/python3.8/site-packages/setuptools/command/alias.py new file mode 100644 index 0000000..4532b1c --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/command/alias.py @@ -0,0 +1,80 @@ +from distutils.errors import DistutilsOptionError + +from setuptools.extern.six.moves import map + +from setuptools.command.setopt import edit_config, option_base, config_file + + +def shquote(arg): + """Quote an argument for later parsing by shlex.split()""" + for c in '"', "'", "\\", "#": + if c in arg: + return repr(arg) + if arg.split() != [arg]: + return repr(arg) + return arg + + +class alias(option_base): + """Define a shortcut that invokes one or more commands""" + + description = "define a shortcut to invoke one or more commands" + command_consumes_arguments = True + + user_options = [ + ('remove', 'r', 'remove (unset) the alias'), + ] + option_base.user_options + + boolean_options = option_base.boolean_options + ['remove'] + + def initialize_options(self): + option_base.initialize_options(self) + self.args = None + self.remove = None + + def finalize_options(self): + option_base.finalize_options(self) + if self.remove and len(self.args) != 1: + raise DistutilsOptionError( + "Must specify exactly one argument (the alias name) when " + "using --remove" + ) + + def run(self): + aliases = self.distribution.get_option_dict('aliases') + + if not self.args: + print("Command Aliases") + print("---------------") + for alias in aliases: + print("setup.py alias", format_alias(alias, aliases)) + return + + elif len(self.args) == 1: + alias, = self.args + if self.remove: + command = None + elif alias in aliases: + print("setup.py alias", format_alias(alias, aliases)) + return + else: + print("No alias definition found for %r" % alias) + return + else: + alias = self.args[0] + command = ' '.join(map(shquote, self.args[1:])) + + edit_config(self.filename, {'aliases': {alias: command}}, self.dry_run) + + +def format_alias(name, aliases): + source, command = aliases[name] + if source == config_file('global'): + source = '--global-config ' + elif source == config_file('user'): + source = '--user-config ' + elif source == config_file('local'): + source = '' + else: + source = '--filename=%r' % source + return source + name + ' ' + command diff --git a/venv/lib/python3.8/site-packages/setuptools/command/bdist_egg.py b/venv/lib/python3.8/site-packages/setuptools/command/bdist_egg.py new file mode 100644 index 0000000..98470f1 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/command/bdist_egg.py @@ -0,0 +1,502 @@ +"""setuptools.command.bdist_egg + +Build .egg distributions""" + +from distutils.errors import DistutilsSetupError +from distutils.dir_util import remove_tree, mkpath +from distutils import log +from types import CodeType +import sys +import os +import re +import textwrap +import marshal + +from setuptools.extern import six + +from pkg_resources import get_build_platform, Distribution, ensure_directory +from pkg_resources import EntryPoint +from setuptools.extension import Library +from setuptools import Command + +try: + # Python 2.7 or >=3.2 + from sysconfig import get_path, get_python_version + + def _get_purelib(): + return get_path("purelib") +except ImportError: + from distutils.sysconfig import get_python_lib, get_python_version + + def _get_purelib(): + return get_python_lib(False) + + +def strip_module(filename): + if '.' in filename: + filename = os.path.splitext(filename)[0] + if filename.endswith('module'): + filename = filename[:-6] + return filename + + +def sorted_walk(dir): + """Do os.walk in a reproducible way, + independent of indeterministic filesystem readdir order + """ + for base, dirs, files in os.walk(dir): + dirs.sort() + files.sort() + yield base, dirs, files + + +def write_stub(resource, pyfile): + _stub_template = textwrap.dedent(""" + def __bootstrap__(): + global __bootstrap__, __loader__, __file__ + import sys, pkg_resources, imp + __file__ = pkg_resources.resource_filename(__name__, %r) + __loader__ = None; del __bootstrap__, __loader__ + imp.load_dynamic(__name__,__file__) + __bootstrap__() + """).lstrip() + with open(pyfile, 'w') as f: + f.write(_stub_template % resource) + + +class bdist_egg(Command): + description = "create an \"egg\" distribution" + + user_options = [ + ('bdist-dir=', 'b', + "temporary directory for creating the distribution"), + ('plat-name=', 'p', "platform name to embed in generated filenames " + "(default: %s)" % get_build_platform()), + ('exclude-source-files', None, + "remove all .py files from the generated egg"), + ('keep-temp', 'k', + "keep the pseudo-installation tree around after " + + "creating the distribution archive"), + ('dist-dir=', 'd', + "directory to put final built distributions in"), + ('skip-build', None, + "skip rebuilding everything (for testing/debugging)"), + ] + + boolean_options = [ + 'keep-temp', 'skip-build', 'exclude-source-files' + ] + + def initialize_options(self): + self.bdist_dir = None + self.plat_name = None + self.keep_temp = 0 + self.dist_dir = None + self.skip_build = 0 + self.egg_output = None + self.exclude_source_files = None + + def finalize_options(self): + ei_cmd = self.ei_cmd = self.get_finalized_command("egg_info") + self.egg_info = ei_cmd.egg_info + + if self.bdist_dir is None: + bdist_base = self.get_finalized_command('bdist').bdist_base + self.bdist_dir = os.path.join(bdist_base, 'egg') + + if self.plat_name is None: + self.plat_name = get_build_platform() + + self.set_undefined_options('bdist', ('dist_dir', 'dist_dir')) + + if self.egg_output is None: + + # Compute filename of the output egg + basename = Distribution( + None, None, ei_cmd.egg_name, ei_cmd.egg_version, + get_python_version(), + self.distribution.has_ext_modules() and self.plat_name + ).egg_name() + + self.egg_output = os.path.join(self.dist_dir, basename + '.egg') + + def do_install_data(self): + # Hack for packages that install data to install's --install-lib + self.get_finalized_command('install').install_lib = self.bdist_dir + + site_packages = os.path.normcase(os.path.realpath(_get_purelib())) + old, self.distribution.data_files = self.distribution.data_files, [] + + for item in old: + if isinstance(item, tuple) and len(item) == 2: + if os.path.isabs(item[0]): + realpath = os.path.realpath(item[0]) + normalized = os.path.normcase(realpath) + if normalized == site_packages or normalized.startswith( + site_packages + os.sep + ): + item = realpath[len(site_packages) + 1:], item[1] + # XXX else: raise ??? + self.distribution.data_files.append(item) + + try: + log.info("installing package data to %s", self.bdist_dir) + self.call_command('install_data', force=0, root=None) + finally: + self.distribution.data_files = old + + def get_outputs(self): + return [self.egg_output] + + def call_command(self, cmdname, **kw): + """Invoke reinitialized command `cmdname` with keyword args""" + for dirname in INSTALL_DIRECTORY_ATTRS: + kw.setdefault(dirname, self.bdist_dir) + kw.setdefault('skip_build', self.skip_build) + kw.setdefault('dry_run', self.dry_run) + cmd = self.reinitialize_command(cmdname, **kw) + self.run_command(cmdname) + return cmd + + def run(self): + # Generate metadata first + self.run_command("egg_info") + # We run install_lib before install_data, because some data hacks + # pull their data path from the install_lib command. + log.info("installing library code to %s", self.bdist_dir) + instcmd = self.get_finalized_command('install') + old_root = instcmd.root + instcmd.root = None + if self.distribution.has_c_libraries() and not self.skip_build: + self.run_command('build_clib') + cmd = self.call_command('install_lib', warn_dir=0) + instcmd.root = old_root + + all_outputs, ext_outputs = self.get_ext_outputs() + self.stubs = [] + to_compile = [] + for (p, ext_name) in enumerate(ext_outputs): + filename, ext = os.path.splitext(ext_name) + pyfile = os.path.join(self.bdist_dir, strip_module(filename) + + '.py') + self.stubs.append(pyfile) + log.info("creating stub loader for %s", ext_name) + if not self.dry_run: + write_stub(os.path.basename(ext_name), pyfile) + to_compile.append(pyfile) + ext_outputs[p] = ext_name.replace(os.sep, '/') + + if to_compile: + cmd.byte_compile(to_compile) + if self.distribution.data_files: + self.do_install_data() + + # Make the EGG-INFO directory + archive_root = self.bdist_dir + egg_info = os.path.join(archive_root, 'EGG-INFO') + self.mkpath(egg_info) + if self.distribution.scripts: + script_dir = os.path.join(egg_info, 'scripts') + log.info("installing scripts to %s", script_dir) + self.call_command('install_scripts', install_dir=script_dir, + no_ep=1) + + self.copy_metadata_to(egg_info) + native_libs = os.path.join(egg_info, "native_libs.txt") + if all_outputs: + log.info("writing %s", native_libs) + if not self.dry_run: + ensure_directory(native_libs) + libs_file = open(native_libs, 'wt') + libs_file.write('\n'.join(all_outputs)) + libs_file.write('\n') + libs_file.close() + elif os.path.isfile(native_libs): + log.info("removing %s", native_libs) + if not self.dry_run: + os.unlink(native_libs) + + write_safety_flag( + os.path.join(archive_root, 'EGG-INFO'), self.zip_safe() + ) + + if os.path.exists(os.path.join(self.egg_info, 'depends.txt')): + log.warn( + "WARNING: 'depends.txt' will not be used by setuptools 0.6!\n" + "Use the install_requires/extras_require setup() args instead." + ) + + if self.exclude_source_files: + self.zap_pyfiles() + + # Make the archive + make_zipfile(self.egg_output, archive_root, verbose=self.verbose, + dry_run=self.dry_run, mode=self.gen_header()) + if not self.keep_temp: + remove_tree(self.bdist_dir, dry_run=self.dry_run) + + # Add to 'Distribution.dist_files' so that the "upload" command works + getattr(self.distribution, 'dist_files', []).append( + ('bdist_egg', get_python_version(), self.egg_output)) + + def zap_pyfiles(self): + log.info("Removing .py files from temporary directory") + for base, dirs, files in walk_egg(self.bdist_dir): + for name in files: + path = os.path.join(base, name) + + if name.endswith('.py'): + log.debug("Deleting %s", path) + os.unlink(path) + + if base.endswith('__pycache__'): + path_old = path + + pattern = r'(?P<name>.+)\.(?P<magic>[^.]+)\.pyc' + m = re.match(pattern, name) + path_new = os.path.join( + base, os.pardir, m.group('name') + '.pyc') + log.info( + "Renaming file from [%s] to [%s]" + % (path_old, path_new)) + try: + os.remove(path_new) + except OSError: + pass + os.rename(path_old, path_new) + + def zip_safe(self): + safe = getattr(self.distribution, 'zip_safe', None) + if safe is not None: + return safe + log.warn("zip_safe flag not set; analyzing archive contents...") + return analyze_egg(self.bdist_dir, self.stubs) + + def gen_header(self): + epm = EntryPoint.parse_map(self.distribution.entry_points or '') + ep = epm.get('setuptools.installation', {}).get('eggsecutable') + if ep is None: + return 'w' # not an eggsecutable, do it the usual way. + + if not ep.attrs or ep.extras: + raise DistutilsSetupError( + "eggsecutable entry point (%r) cannot have 'extras' " + "or refer to a module" % (ep,) + ) + + pyver = '{}.{}'.format(*sys.version_info) + pkg = ep.module_name + full = '.'.join(ep.attrs) + base = ep.attrs[0] + basename = os.path.basename(self.egg_output) + + header = ( + "#!/bin/sh\n" + 'if [ `basename $0` = "%(basename)s" ]\n' + 'then exec python%(pyver)s -c "' + "import sys, os; sys.path.insert(0, os.path.abspath('$0')); " + "from %(pkg)s import %(base)s; sys.exit(%(full)s())" + '" "$@"\n' + 'else\n' + ' echo $0 is not the correct name for this egg file.\n' + ' echo Please rename it back to %(basename)s and try again.\n' + ' exec false\n' + 'fi\n' + ) % locals() + + if not self.dry_run: + mkpath(os.path.dirname(self.egg_output), dry_run=self.dry_run) + f = open(self.egg_output, 'w') + f.write(header) + f.close() + return 'a' + + def copy_metadata_to(self, target_dir): + "Copy metadata (egg info) to the target_dir" + # normalize the path (so that a forward-slash in egg_info will + # match using startswith below) + norm_egg_info = os.path.normpath(self.egg_info) + prefix = os.path.join(norm_egg_info, '') + for path in self.ei_cmd.filelist.files: + if path.startswith(prefix): + target = os.path.join(target_dir, path[len(prefix):]) + ensure_directory(target) + self.copy_file(path, target) + + def get_ext_outputs(self): + """Get a list of relative paths to C extensions in the output distro""" + + all_outputs = [] + ext_outputs = [] + + paths = {self.bdist_dir: ''} + for base, dirs, files in sorted_walk(self.bdist_dir): + for filename in files: + if os.path.splitext(filename)[1].lower() in NATIVE_EXTENSIONS: + all_outputs.append(paths[base] + filename) + for filename in dirs: + paths[os.path.join(base, filename)] = (paths[base] + + filename + '/') + + if self.distribution.has_ext_modules(): + build_cmd = self.get_finalized_command('build_ext') + for ext in build_cmd.extensions: + if isinstance(ext, Library): + continue + fullname = build_cmd.get_ext_fullname(ext.name) + filename = build_cmd.get_ext_filename(fullname) + if not os.path.basename(filename).startswith('dl-'): + if os.path.exists(os.path.join(self.bdist_dir, filename)): + ext_outputs.append(filename) + + return all_outputs, ext_outputs + + +NATIVE_EXTENSIONS = dict.fromkeys('.dll .so .dylib .pyd'.split()) + + +def walk_egg(egg_dir): + """Walk an unpacked egg's contents, skipping the metadata directory""" + walker = sorted_walk(egg_dir) + base, dirs, files = next(walker) + if 'EGG-INFO' in dirs: + dirs.remove('EGG-INFO') + yield base, dirs, files + for bdf in walker: + yield bdf + + +def analyze_egg(egg_dir, stubs): + # check for existing flag in EGG-INFO + for flag, fn in safety_flags.items(): + if os.path.exists(os.path.join(egg_dir, 'EGG-INFO', fn)): + return flag + if not can_scan(): + return False + safe = True + for base, dirs, files in walk_egg(egg_dir): + for name in files: + if name.endswith('.py') or name.endswith('.pyw'): + continue + elif name.endswith('.pyc') or name.endswith('.pyo'): + # always scan, even if we already know we're not safe + safe = scan_module(egg_dir, base, name, stubs) and safe + return safe + + +def write_safety_flag(egg_dir, safe): + # Write or remove zip safety flag file(s) + for flag, fn in safety_flags.items(): + fn = os.path.join(egg_dir, fn) + if os.path.exists(fn): + if safe is None or bool(safe) != flag: + os.unlink(fn) + elif safe is not None and bool(safe) == flag: + f = open(fn, 'wt') + f.write('\n') + f.close() + + +safety_flags = { + True: 'zip-safe', + False: 'not-zip-safe', +} + + +def scan_module(egg_dir, base, name, stubs): + """Check whether module possibly uses unsafe-for-zipfile stuff""" + + filename = os.path.join(base, name) + if filename[:-1] in stubs: + return True # Extension module + pkg = base[len(egg_dir) + 1:].replace(os.sep, '.') + module = pkg + (pkg and '.' or '') + os.path.splitext(name)[0] + if six.PY2: + skip = 8 # skip magic & date + elif sys.version_info < (3, 7): + skip = 12 # skip magic & date & file size + else: + skip = 16 # skip magic & reserved? & date & file size + f = open(filename, 'rb') + f.read(skip) + code = marshal.load(f) + f.close() + safe = True + symbols = dict.fromkeys(iter_symbols(code)) + for bad in ['__file__', '__path__']: + if bad in symbols: + log.warn("%s: module references %s", module, bad) + safe = False + if 'inspect' in symbols: + for bad in [ + 'getsource', 'getabsfile', 'getsourcefile', 'getfile' + 'getsourcelines', 'findsource', 'getcomments', 'getframeinfo', + 'getinnerframes', 'getouterframes', 'stack', 'trace' + ]: + if bad in symbols: + log.warn("%s: module MAY be using inspect.%s", module, bad) + safe = False + return safe + + +def iter_symbols(code): + """Yield names and strings used by `code` and its nested code objects""" + for name in code.co_names: + yield name + for const in code.co_consts: + if isinstance(const, six.string_types): + yield const + elif isinstance(const, CodeType): + for name in iter_symbols(const): + yield name + + +def can_scan(): + if not sys.platform.startswith('java') and sys.platform != 'cli': + # CPython, PyPy, etc. + return True + log.warn("Unable to analyze compiled code on this platform.") + log.warn("Please ask the author to include a 'zip_safe'" + " setting (either True or False) in the package's setup.py") + + +# Attribute names of options for commands that might need to be convinced to +# install to the egg build directory + +INSTALL_DIRECTORY_ATTRS = [ + 'install_lib', 'install_dir', 'install_data', 'install_base' +] + + +def make_zipfile(zip_filename, base_dir, verbose=0, dry_run=0, compress=True, + mode='w'): + """Create a zip file from all the files under 'base_dir'. The output + zip file will be named 'base_dir' + ".zip". Uses either the "zipfile" + Python module (if available) or the InfoZIP "zip" utility (if installed + and found on the default search path). If neither tool is available, + raises DistutilsExecError. Returns the name of the output zip file. + """ + import zipfile + + mkpath(os.path.dirname(zip_filename), dry_run=dry_run) + log.info("creating '%s' and adding '%s' to it", zip_filename, base_dir) + + def visit(z, dirname, names): + for name in names: + path = os.path.normpath(os.path.join(dirname, name)) + if os.path.isfile(path): + p = path[len(base_dir) + 1:] + if not dry_run: + z.write(path, p) + log.debug("adding '%s'", p) + + compression = zipfile.ZIP_DEFLATED if compress else zipfile.ZIP_STORED + if not dry_run: + z = zipfile.ZipFile(zip_filename, mode, compression=compression) + for dirname, dirs, files in sorted_walk(base_dir): + visit(z, dirname, files) + z.close() + else: + for dirname, dirs, files in sorted_walk(base_dir): + visit(None, dirname, files) + return zip_filename diff --git a/venv/lib/python3.8/site-packages/setuptools/command/bdist_rpm.py b/venv/lib/python3.8/site-packages/setuptools/command/bdist_rpm.py new file mode 100644 index 0000000..7073092 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/command/bdist_rpm.py @@ -0,0 +1,43 @@ +import distutils.command.bdist_rpm as orig + + +class bdist_rpm(orig.bdist_rpm): + """ + Override the default bdist_rpm behavior to do the following: + + 1. Run egg_info to ensure the name and version are properly calculated. + 2. Always run 'install' using --single-version-externally-managed to + disable eggs in RPM distributions. + 3. Replace dash with underscore in the version numbers for better RPM + compatibility. + """ + + def run(self): + # ensure distro name is up-to-date + self.run_command('egg_info') + + orig.bdist_rpm.run(self) + + def _make_spec_file(self): + version = self.distribution.get_version() + rpmversion = version.replace('-', '_') + spec = orig.bdist_rpm._make_spec_file(self) + line23 = '%define version ' + version + line24 = '%define version ' + rpmversion + spec = [ + line.replace( + "Source0: %{name}-%{version}.tar", + "Source0: %{name}-%{unmangled_version}.tar" + ).replace( + "setup.py install ", + "setup.py install --single-version-externally-managed " + ).replace( + "%setup", + "%setup -n %{name}-%{unmangled_version}" + ).replace(line23, line24) + for line in spec + ] + insert_loc = spec.index(line24) + 1 + unmangled_version = "%define unmangled_version " + version + spec.insert(insert_loc, unmangled_version) + return spec diff --git a/venv/lib/python3.8/site-packages/setuptools/command/bdist_wininst.py b/venv/lib/python3.8/site-packages/setuptools/command/bdist_wininst.py new file mode 100644 index 0000000..073de97 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/command/bdist_wininst.py @@ -0,0 +1,21 @@ +import distutils.command.bdist_wininst as orig + + +class bdist_wininst(orig.bdist_wininst): + def reinitialize_command(self, command, reinit_subcommands=0): + """ + Supplement reinitialize_command to work around + http://bugs.python.org/issue20819 + """ + cmd = self.distribution.reinitialize_command( + command, reinit_subcommands) + if command in ('install', 'install_lib'): + cmd.install_lib = None + return cmd + + def run(self): + self._is_running = True + try: + orig.bdist_wininst.run(self) + finally: + self._is_running = False diff --git a/venv/lib/python3.8/site-packages/setuptools/command/build_clib.py b/venv/lib/python3.8/site-packages/setuptools/command/build_clib.py new file mode 100644 index 0000000..09caff6 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/command/build_clib.py @@ -0,0 +1,98 @@ +import distutils.command.build_clib as orig +from distutils.errors import DistutilsSetupError +from distutils import log +from setuptools.dep_util import newer_pairwise_group + + +class build_clib(orig.build_clib): + """ + Override the default build_clib behaviour to do the following: + + 1. Implement a rudimentary timestamp-based dependency system + so 'compile()' doesn't run every time. + 2. Add more keys to the 'build_info' dictionary: + * obj_deps - specify dependencies for each object compiled. + this should be a dictionary mapping a key + with the source filename to a list of + dependencies. Use an empty string for global + dependencies. + * cflags - specify a list of additional flags to pass to + the compiler. + """ + + def build_libraries(self, libraries): + for (lib_name, build_info) in libraries: + sources = build_info.get('sources') + if sources is None or not isinstance(sources, (list, tuple)): + raise DistutilsSetupError( + "in 'libraries' option (library '%s'), " + "'sources' must be present and must be " + "a list of source filenames" % lib_name) + sources = list(sources) + + log.info("building '%s' library", lib_name) + + # Make sure everything is the correct type. + # obj_deps should be a dictionary of keys as sources + # and a list/tuple of files that are its dependencies. + obj_deps = build_info.get('obj_deps', dict()) + if not isinstance(obj_deps, dict): + raise DistutilsSetupError( + "in 'libraries' option (library '%s'), " + "'obj_deps' must be a dictionary of " + "type 'source: list'" % lib_name) + dependencies = [] + + # Get the global dependencies that are specified by the '' key. + # These will go into every source's dependency list. + global_deps = obj_deps.get('', list()) + if not isinstance(global_deps, (list, tuple)): + raise DistutilsSetupError( + "in 'libraries' option (library '%s'), " + "'obj_deps' must be a dictionary of " + "type 'source: list'" % lib_name) + + # Build the list to be used by newer_pairwise_group + # each source will be auto-added to its dependencies. + for source in sources: + src_deps = [source] + src_deps.extend(global_deps) + extra_deps = obj_deps.get(source, list()) + if not isinstance(extra_deps, (list, tuple)): + raise DistutilsSetupError( + "in 'libraries' option (library '%s'), " + "'obj_deps' must be a dictionary of " + "type 'source: list'" % lib_name) + src_deps.extend(extra_deps) + dependencies.append(src_deps) + + expected_objects = self.compiler.object_filenames( + sources, + output_dir=self.build_temp + ) + + if newer_pairwise_group(dependencies, expected_objects) != ([], []): + # First, compile the source code to object files in the library + # directory. (This should probably change to putting object + # files in a temporary build directory.) + macros = build_info.get('macros') + include_dirs = build_info.get('include_dirs') + cflags = build_info.get('cflags') + objects = self.compiler.compile( + sources, + output_dir=self.build_temp, + macros=macros, + include_dirs=include_dirs, + extra_postargs=cflags, + debug=self.debug + ) + + # Now "link" the object files together into a static library. + # (On Unix at least, this isn't really linking -- it just + # builds an archive. Whatever.) + self.compiler.create_static_lib( + expected_objects, + lib_name, + output_dir=self.build_clib, + debug=self.debug + ) diff --git a/venv/lib/python3.8/site-packages/setuptools/command/build_ext.py b/venv/lib/python3.8/site-packages/setuptools/command/build_ext.py new file mode 100644 index 0000000..daa8e4f --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/command/build_ext.py @@ -0,0 +1,327 @@ +import os +import sys +import itertools +from distutils.command.build_ext import build_ext as _du_build_ext +from distutils.file_util import copy_file +from distutils.ccompiler import new_compiler +from distutils.sysconfig import customize_compiler, get_config_var +from distutils.errors import DistutilsError +from distutils import log + +from setuptools.extension import Library +from setuptools.extern import six + +if six.PY2: + import imp + + EXTENSION_SUFFIXES = [s for s, _, tp in imp.get_suffixes() if tp == imp.C_EXTENSION] +else: + from importlib.machinery import EXTENSION_SUFFIXES + +try: + # Attempt to use Cython for building extensions, if available + from Cython.Distutils.build_ext import build_ext as _build_ext + # Additionally, assert that the compiler module will load + # also. Ref #1229. + __import__('Cython.Compiler.Main') +except ImportError: + _build_ext = _du_build_ext + +# make sure _config_vars is initialized +get_config_var("LDSHARED") +from distutils.sysconfig import _config_vars as _CONFIG_VARS + + +def _customize_compiler_for_shlib(compiler): + if sys.platform == "darwin": + # building .dylib requires additional compiler flags on OSX; here we + # temporarily substitute the pyconfig.h variables so that distutils' + # 'customize_compiler' uses them before we build the shared libraries. + tmp = _CONFIG_VARS.copy() + try: + # XXX Help! I don't have any idea whether these are right... + _CONFIG_VARS['LDSHARED'] = ( + "gcc -Wl,-x -dynamiclib -undefined dynamic_lookup") + _CONFIG_VARS['CCSHARED'] = " -dynamiclib" + _CONFIG_VARS['SO'] = ".dylib" + customize_compiler(compiler) + finally: + _CONFIG_VARS.clear() + _CONFIG_VARS.update(tmp) + else: + customize_compiler(compiler) + + +have_rtld = False +use_stubs = False +libtype = 'shared' + +if sys.platform == "darwin": + use_stubs = True +elif os.name != 'nt': + try: + import dl + use_stubs = have_rtld = hasattr(dl, 'RTLD_NOW') + except ImportError: + pass + +if_dl = lambda s: s if have_rtld else '' + + +def get_abi3_suffix(): + """Return the file extension for an abi3-compliant Extension()""" + for suffix in EXTENSION_SUFFIXES: + if '.abi3' in suffix: # Unix + return suffix + elif suffix == '.pyd': # Windows + return suffix + + +class build_ext(_build_ext): + def run(self): + """Build extensions in build directory, then copy if --inplace""" + old_inplace, self.inplace = self.inplace, 0 + _build_ext.run(self) + self.inplace = old_inplace + if old_inplace: + self.copy_extensions_to_source() + + def copy_extensions_to_source(self): + build_py = self.get_finalized_command('build_py') + for ext in self.extensions: + fullname = self.get_ext_fullname(ext.name) + filename = self.get_ext_filename(fullname) + modpath = fullname.split('.') + package = '.'.join(modpath[:-1]) + package_dir = build_py.get_package_dir(package) + dest_filename = os.path.join(package_dir, + os.path.basename(filename)) + src_filename = os.path.join(self.build_lib, filename) + + # Always copy, even if source is older than destination, to ensure + # that the right extensions for the current Python/platform are + # used. + copy_file( + src_filename, dest_filename, verbose=self.verbose, + dry_run=self.dry_run + ) + if ext._needs_stub: + self.write_stub(package_dir or os.curdir, ext, True) + + def get_ext_filename(self, fullname): + filename = _build_ext.get_ext_filename(self, fullname) + if fullname in self.ext_map: + ext = self.ext_map[fullname] + use_abi3 = ( + six.PY3 + and getattr(ext, 'py_limited_api') + and get_abi3_suffix() + ) + if use_abi3: + so_ext = get_config_var('EXT_SUFFIX') + filename = filename[:-len(so_ext)] + filename = filename + get_abi3_suffix() + if isinstance(ext, Library): + fn, ext = os.path.splitext(filename) + return self.shlib_compiler.library_filename(fn, libtype) + elif use_stubs and ext._links_to_dynamic: + d, fn = os.path.split(filename) + return os.path.join(d, 'dl-' + fn) + return filename + + def initialize_options(self): + _build_ext.initialize_options(self) + self.shlib_compiler = None + self.shlibs = [] + self.ext_map = {} + + def finalize_options(self): + _build_ext.finalize_options(self) + self.extensions = self.extensions or [] + self.check_extensions_list(self.extensions) + self.shlibs = [ext for ext in self.extensions + if isinstance(ext, Library)] + if self.shlibs: + self.setup_shlib_compiler() + for ext in self.extensions: + ext._full_name = self.get_ext_fullname(ext.name) + for ext in self.extensions: + fullname = ext._full_name + self.ext_map[fullname] = ext + + # distutils 3.1 will also ask for module names + # XXX what to do with conflicts? + self.ext_map[fullname.split('.')[-1]] = ext + + ltd = self.shlibs and self.links_to_dynamic(ext) or False + ns = ltd and use_stubs and not isinstance(ext, Library) + ext._links_to_dynamic = ltd + ext._needs_stub = ns + filename = ext._file_name = self.get_ext_filename(fullname) + libdir = os.path.dirname(os.path.join(self.build_lib, filename)) + if ltd and libdir not in ext.library_dirs: + ext.library_dirs.append(libdir) + if ltd and use_stubs and os.curdir not in ext.runtime_library_dirs: + ext.runtime_library_dirs.append(os.curdir) + + def setup_shlib_compiler(self): + compiler = self.shlib_compiler = new_compiler( + compiler=self.compiler, dry_run=self.dry_run, force=self.force + ) + _customize_compiler_for_shlib(compiler) + + if self.include_dirs is not None: + compiler.set_include_dirs(self.include_dirs) + if self.define is not None: + # 'define' option is a list of (name,value) tuples + for (name, value) in self.define: + compiler.define_macro(name, value) + if self.undef is not None: + for macro in self.undef: + compiler.undefine_macro(macro) + if self.libraries is not None: + compiler.set_libraries(self.libraries) + if self.library_dirs is not None: + compiler.set_library_dirs(self.library_dirs) + if self.rpath is not None: + compiler.set_runtime_library_dirs(self.rpath) + if self.link_objects is not None: + compiler.set_link_objects(self.link_objects) + + # hack so distutils' build_extension() builds a library instead + compiler.link_shared_object = link_shared_object.__get__(compiler) + + def get_export_symbols(self, ext): + if isinstance(ext, Library): + return ext.export_symbols + return _build_ext.get_export_symbols(self, ext) + + def build_extension(self, ext): + ext._convert_pyx_sources_to_lang() + _compiler = self.compiler + try: + if isinstance(ext, Library): + self.compiler = self.shlib_compiler + _build_ext.build_extension(self, ext) + if ext._needs_stub: + cmd = self.get_finalized_command('build_py').build_lib + self.write_stub(cmd, ext) + finally: + self.compiler = _compiler + + def links_to_dynamic(self, ext): + """Return true if 'ext' links to a dynamic lib in the same package""" + # XXX this should check to ensure the lib is actually being built + # XXX as dynamic, and not just using a locally-found version or a + # XXX static-compiled version + libnames = dict.fromkeys([lib._full_name for lib in self.shlibs]) + pkg = '.'.join(ext._full_name.split('.')[:-1] + ['']) + return any(pkg + libname in libnames for libname in ext.libraries) + + def get_outputs(self): + return _build_ext.get_outputs(self) + self.__get_stubs_outputs() + + def __get_stubs_outputs(self): + # assemble the base name for each extension that needs a stub + ns_ext_bases = ( + os.path.join(self.build_lib, *ext._full_name.split('.')) + for ext in self.extensions + if ext._needs_stub + ) + # pair each base with the extension + pairs = itertools.product(ns_ext_bases, self.__get_output_extensions()) + return list(base + fnext for base, fnext in pairs) + + def __get_output_extensions(self): + yield '.py' + yield '.pyc' + if self.get_finalized_command('build_py').optimize: + yield '.pyo' + + def write_stub(self, output_dir, ext, compile=False): + log.info("writing stub loader for %s to %s", ext._full_name, + output_dir) + stub_file = (os.path.join(output_dir, *ext._full_name.split('.')) + + '.py') + if compile and os.path.exists(stub_file): + raise DistutilsError(stub_file + " already exists! Please delete.") + if not self.dry_run: + f = open(stub_file, 'w') + f.write( + '\n'.join([ + "def __bootstrap__():", + " global __bootstrap__, __file__, __loader__", + " import sys, os, pkg_resources, imp" + if_dl(", dl"), + " __file__ = pkg_resources.resource_filename" + "(__name__,%r)" + % os.path.basename(ext._file_name), + " del __bootstrap__", + " if '__loader__' in globals():", + " del __loader__", + if_dl(" old_flags = sys.getdlopenflags()"), + " old_dir = os.getcwd()", + " try:", + " os.chdir(os.path.dirname(__file__))", + if_dl(" sys.setdlopenflags(dl.RTLD_NOW)"), + " imp.load_dynamic(__name__,__file__)", + " finally:", + if_dl(" sys.setdlopenflags(old_flags)"), + " os.chdir(old_dir)", + "__bootstrap__()", + "" # terminal \n + ]) + ) + f.close() + if compile: + from distutils.util import byte_compile + + byte_compile([stub_file], optimize=0, + force=True, dry_run=self.dry_run) + optimize = self.get_finalized_command('install_lib').optimize + if optimize > 0: + byte_compile([stub_file], optimize=optimize, + force=True, dry_run=self.dry_run) + if os.path.exists(stub_file) and not self.dry_run: + os.unlink(stub_file) + + +if use_stubs or os.name == 'nt': + # Build shared libraries + # + def link_shared_object( + self, objects, output_libname, output_dir=None, libraries=None, + library_dirs=None, runtime_library_dirs=None, export_symbols=None, + debug=0, extra_preargs=None, extra_postargs=None, build_temp=None, + target_lang=None): + self.link( + self.SHARED_LIBRARY, objects, output_libname, + output_dir, libraries, library_dirs, runtime_library_dirs, + export_symbols, debug, extra_preargs, extra_postargs, + build_temp, target_lang + ) +else: + # Build static libraries everywhere else + libtype = 'static' + + def link_shared_object( + self, objects, output_libname, output_dir=None, libraries=None, + library_dirs=None, runtime_library_dirs=None, export_symbols=None, + debug=0, extra_preargs=None, extra_postargs=None, build_temp=None, + target_lang=None): + # XXX we need to either disallow these attrs on Library instances, + # or warn/abort here if set, or something... + # libraries=None, library_dirs=None, runtime_library_dirs=None, + # export_symbols=None, extra_preargs=None, extra_postargs=None, + # build_temp=None + + assert output_dir is None # distutils build_ext doesn't pass this + output_dir, filename = os.path.split(output_libname) + basename, ext = os.path.splitext(filename) + if self.library_filename("x").startswith('lib'): + # strip 'lib' prefix; this is kludgy if some platform uses + # a different prefix + basename = basename[3:] + + self.create_static_lib( + objects, basename, output_dir, debug, target_lang + ) diff --git a/venv/lib/python3.8/site-packages/setuptools/command/build_py.py b/venv/lib/python3.8/site-packages/setuptools/command/build_py.py new file mode 100644 index 0000000..b0314fd --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/command/build_py.py @@ -0,0 +1,270 @@ +from glob import glob +from distutils.util import convert_path +import distutils.command.build_py as orig +import os +import fnmatch +import textwrap +import io +import distutils.errors +import itertools + +from setuptools.extern import six +from setuptools.extern.six.moves import map, filter, filterfalse + +try: + from setuptools.lib2to3_ex import Mixin2to3 +except ImportError: + + class Mixin2to3: + def run_2to3(self, files, doctests=True): + "do nothing" + + +class build_py(orig.build_py, Mixin2to3): + """Enhanced 'build_py' command that includes data files with packages + + The data files are specified via a 'package_data' argument to 'setup()'. + See 'setuptools.dist.Distribution' for more details. + + Also, this version of the 'build_py' command allows you to specify both + 'py_modules' and 'packages' in the same setup operation. + """ + + def finalize_options(self): + orig.build_py.finalize_options(self) + self.package_data = self.distribution.package_data + self.exclude_package_data = (self.distribution.exclude_package_data or + {}) + if 'data_files' in self.__dict__: + del self.__dict__['data_files'] + self.__updated_files = [] + self.__doctests_2to3 = [] + + def run(self): + """Build modules, packages, and copy data files to build directory""" + if not self.py_modules and not self.packages: + return + + if self.py_modules: + self.build_modules() + + if self.packages: + self.build_packages() + self.build_package_data() + + self.run_2to3(self.__updated_files, False) + self.run_2to3(self.__updated_files, True) + self.run_2to3(self.__doctests_2to3, True) + + # Only compile actual .py files, using our base class' idea of what our + # output files are. + self.byte_compile(orig.build_py.get_outputs(self, include_bytecode=0)) + + def __getattr__(self, attr): + "lazily compute data files" + if attr == 'data_files': + self.data_files = self._get_data_files() + return self.data_files + return orig.build_py.__getattr__(self, attr) + + def build_module(self, module, module_file, package): + if six.PY2 and isinstance(package, six.string_types): + # avoid errors on Python 2 when unicode is passed (#190) + package = package.split('.') + outfile, copied = orig.build_py.build_module(self, module, module_file, + package) + if copied: + self.__updated_files.append(outfile) + return outfile, copied + + def _get_data_files(self): + """Generate list of '(package,src_dir,build_dir,filenames)' tuples""" + self.analyze_manifest() + return list(map(self._get_pkg_data_files, self.packages or ())) + + def _get_pkg_data_files(self, package): + # Locate package source directory + src_dir = self.get_package_dir(package) + + # Compute package build directory + build_dir = os.path.join(*([self.build_lib] + package.split('.'))) + + # Strip directory from globbed filenames + filenames = [ + os.path.relpath(file, src_dir) + for file in self.find_data_files(package, src_dir) + ] + return package, src_dir, build_dir, filenames + + def find_data_files(self, package, src_dir): + """Return filenames for package's data files in 'src_dir'""" + patterns = self._get_platform_patterns( + self.package_data, + package, + src_dir, + ) + globs_expanded = map(glob, patterns) + # flatten the expanded globs into an iterable of matches + globs_matches = itertools.chain.from_iterable(globs_expanded) + glob_files = filter(os.path.isfile, globs_matches) + files = itertools.chain( + self.manifest_files.get(package, []), + glob_files, + ) + return self.exclude_data_files(package, src_dir, files) + + def build_package_data(self): + """Copy data files into build directory""" + for package, src_dir, build_dir, filenames in self.data_files: + for filename in filenames: + target = os.path.join(build_dir, filename) + self.mkpath(os.path.dirname(target)) + srcfile = os.path.join(src_dir, filename) + outf, copied = self.copy_file(srcfile, target) + srcfile = os.path.abspath(srcfile) + if (copied and + srcfile in self.distribution.convert_2to3_doctests): + self.__doctests_2to3.append(outf) + + def analyze_manifest(self): + self.manifest_files = mf = {} + if not self.distribution.include_package_data: + return + src_dirs = {} + for package in self.packages or (): + # Locate package source directory + src_dirs[assert_relative(self.get_package_dir(package))] = package + + self.run_command('egg_info') + ei_cmd = self.get_finalized_command('egg_info') + for path in ei_cmd.filelist.files: + d, f = os.path.split(assert_relative(path)) + prev = None + oldf = f + while d and d != prev and d not in src_dirs: + prev = d + d, df = os.path.split(d) + f = os.path.join(df, f) + if d in src_dirs: + if path.endswith('.py') and f == oldf: + continue # it's a module, not data + mf.setdefault(src_dirs[d], []).append(path) + + def get_data_files(self): + pass # Lazily compute data files in _get_data_files() function. + + def check_package(self, package, package_dir): + """Check namespace packages' __init__ for declare_namespace""" + try: + return self.packages_checked[package] + except KeyError: + pass + + init_py = orig.build_py.check_package(self, package, package_dir) + self.packages_checked[package] = init_py + + if not init_py or not self.distribution.namespace_packages: + return init_py + + for pkg in self.distribution.namespace_packages: + if pkg == package or pkg.startswith(package + '.'): + break + else: + return init_py + + with io.open(init_py, 'rb') as f: + contents = f.read() + if b'declare_namespace' not in contents: + raise distutils.errors.DistutilsError( + "Namespace package problem: %s is a namespace package, but " + "its\n__init__.py does not call declare_namespace()! Please " + 'fix it.\n(See the setuptools manual under ' + '"Namespace Packages" for details.)\n"' % (package,) + ) + return init_py + + def initialize_options(self): + self.packages_checked = {} + orig.build_py.initialize_options(self) + + def get_package_dir(self, package): + res = orig.build_py.get_package_dir(self, package) + if self.distribution.src_root is not None: + return os.path.join(self.distribution.src_root, res) + return res + + def exclude_data_files(self, package, src_dir, files): + """Filter filenames for package's data files in 'src_dir'""" + files = list(files) + patterns = self._get_platform_patterns( + self.exclude_package_data, + package, + src_dir, + ) + match_groups = ( + fnmatch.filter(files, pattern) + for pattern in patterns + ) + # flatten the groups of matches into an iterable of matches + matches = itertools.chain.from_iterable(match_groups) + bad = set(matches) + keepers = ( + fn + for fn in files + if fn not in bad + ) + # ditch dupes + return list(_unique_everseen(keepers)) + + @staticmethod + def _get_platform_patterns(spec, package, src_dir): + """ + yield platform-specific path patterns (suitable for glob + or fn_match) from a glob-based spec (such as + self.package_data or self.exclude_package_data) + matching package in src_dir. + """ + raw_patterns = itertools.chain( + spec.get('', []), + spec.get(package, []), + ) + return ( + # Each pattern has to be converted to a platform-specific path + os.path.join(src_dir, convert_path(pattern)) + for pattern in raw_patterns + ) + + +# from Python docs +def _unique_everseen(iterable, key=None): + "List unique elements, preserving order. Remember all elements ever seen." + # unique_everseen('AAAABBBCCDAABBB') --> A B C D + # unique_everseen('ABBCcAD', str.lower) --> A B C D + seen = set() + seen_add = seen.add + if key is None: + for element in filterfalse(seen.__contains__, iterable): + seen_add(element) + yield element + else: + for element in iterable: + k = key(element) + if k not in seen: + seen_add(k) + yield element + + +def assert_relative(path): + if not os.path.isabs(path): + return path + from distutils.errors import DistutilsSetupError + + msg = textwrap.dedent(""" + Error: setup script specifies an absolute path: + + %s + + setup() arguments must *always* be /-separated paths relative to the + setup.py directory, *never* absolute paths. + """).lstrip() % path + raise DistutilsSetupError(msg) diff --git a/venv/lib/python3.8/site-packages/setuptools/command/develop.py b/venv/lib/python3.8/site-packages/setuptools/command/develop.py new file mode 100644 index 0000000..009e4f9 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/command/develop.py @@ -0,0 +1,221 @@ +from distutils.util import convert_path +from distutils import log +from distutils.errors import DistutilsError, DistutilsOptionError +import os +import glob +import io + +from setuptools.extern import six + +import pkg_resources +from setuptools.command.easy_install import easy_install +from setuptools import namespaces +import setuptools + +__metaclass__ = type + + +class develop(namespaces.DevelopInstaller, easy_install): + """Set up package for development""" + + description = "install package in 'development mode'" + + user_options = easy_install.user_options + [ + ("uninstall", "u", "Uninstall this source package"), + ("egg-path=", None, "Set the path to be used in the .egg-link file"), + ] + + boolean_options = easy_install.boolean_options + ['uninstall'] + + command_consumes_arguments = False # override base + + def run(self): + if self.uninstall: + self.multi_version = True + self.uninstall_link() + self.uninstall_namespaces() + else: + self.install_for_development() + self.warn_deprecated_options() + + def initialize_options(self): + self.uninstall = None + self.egg_path = None + easy_install.initialize_options(self) + self.setup_path = None + self.always_copy_from = '.' # always copy eggs installed in curdir + + def finalize_options(self): + ei = self.get_finalized_command("egg_info") + if ei.broken_egg_info: + template = "Please rename %r to %r before using 'develop'" + args = ei.egg_info, ei.broken_egg_info + raise DistutilsError(template % args) + self.args = [ei.egg_name] + + easy_install.finalize_options(self) + self.expand_basedirs() + self.expand_dirs() + # pick up setup-dir .egg files only: no .egg-info + self.package_index.scan(glob.glob('*.egg')) + + egg_link_fn = ei.egg_name + '.egg-link' + self.egg_link = os.path.join(self.install_dir, egg_link_fn) + self.egg_base = ei.egg_base + if self.egg_path is None: + self.egg_path = os.path.abspath(ei.egg_base) + + target = pkg_resources.normalize_path(self.egg_base) + egg_path = pkg_resources.normalize_path( + os.path.join(self.install_dir, self.egg_path)) + if egg_path != target: + raise DistutilsOptionError( + "--egg-path must be a relative path from the install" + " directory to " + target + ) + + # Make a distribution for the package's source + self.dist = pkg_resources.Distribution( + target, + pkg_resources.PathMetadata(target, os.path.abspath(ei.egg_info)), + project_name=ei.egg_name + ) + + self.setup_path = self._resolve_setup_path( + self.egg_base, + self.install_dir, + self.egg_path, + ) + + @staticmethod + def _resolve_setup_path(egg_base, install_dir, egg_path): + """ + Generate a path from egg_base back to '.' where the + setup script resides and ensure that path points to the + setup path from $install_dir/$egg_path. + """ + path_to_setup = egg_base.replace(os.sep, '/').rstrip('/') + if path_to_setup != os.curdir: + path_to_setup = '../' * (path_to_setup.count('/') + 1) + resolved = pkg_resources.normalize_path( + os.path.join(install_dir, egg_path, path_to_setup) + ) + if resolved != pkg_resources.normalize_path(os.curdir): + raise DistutilsOptionError( + "Can't get a consistent path to setup script from" + " installation directory", resolved, + pkg_resources.normalize_path(os.curdir)) + return path_to_setup + + def install_for_development(self): + if six.PY3 and getattr(self.distribution, 'use_2to3', False): + # If we run 2to3 we can not do this inplace: + + # Ensure metadata is up-to-date + self.reinitialize_command('build_py', inplace=0) + self.run_command('build_py') + bpy_cmd = self.get_finalized_command("build_py") + build_path = pkg_resources.normalize_path(bpy_cmd.build_lib) + + # Build extensions + self.reinitialize_command('egg_info', egg_base=build_path) + self.run_command('egg_info') + + self.reinitialize_command('build_ext', inplace=0) + self.run_command('build_ext') + + # Fixup egg-link and easy-install.pth + ei_cmd = self.get_finalized_command("egg_info") + self.egg_path = build_path + self.dist.location = build_path + # XXX + self.dist._provider = pkg_resources.PathMetadata( + build_path, ei_cmd.egg_info) + else: + # Without 2to3 inplace works fine: + self.run_command('egg_info') + + # Build extensions in-place + self.reinitialize_command('build_ext', inplace=1) + self.run_command('build_ext') + + self.install_site_py() # ensure that target dir is site-safe + if setuptools.bootstrap_install_from: + self.easy_install(setuptools.bootstrap_install_from) + setuptools.bootstrap_install_from = None + + self.install_namespaces() + + # create an .egg-link in the installation dir, pointing to our egg + log.info("Creating %s (link to %s)", self.egg_link, self.egg_base) + if not self.dry_run: + with open(self.egg_link, "w") as f: + f.write(self.egg_path + "\n" + self.setup_path) + # postprocess the installed distro, fixing up .pth, installing scripts, + # and handling requirements + self.process_distribution(None, self.dist, not self.no_deps) + + def uninstall_link(self): + if os.path.exists(self.egg_link): + log.info("Removing %s (link to %s)", self.egg_link, self.egg_base) + egg_link_file = open(self.egg_link) + contents = [line.rstrip() for line in egg_link_file] + egg_link_file.close() + if contents not in ([self.egg_path], + [self.egg_path, self.setup_path]): + log.warn("Link points to %s: uninstall aborted", contents) + return + if not self.dry_run: + os.unlink(self.egg_link) + if not self.dry_run: + self.update_pth(self.dist) # remove any .pth link to us + if self.distribution.scripts: + # XXX should also check for entry point scripts! + log.warn("Note: you must uninstall or replace scripts manually!") + + def install_egg_scripts(self, dist): + if dist is not self.dist: + # Installing a dependency, so fall back to normal behavior + return easy_install.install_egg_scripts(self, dist) + + # create wrapper scripts in the script dir, pointing to dist.scripts + + # new-style... + self.install_wrapper_scripts(dist) + + # ...and old-style + for script_name in self.distribution.scripts or []: + script_path = os.path.abspath(convert_path(script_name)) + script_name = os.path.basename(script_path) + with io.open(script_path) as strm: + script_text = strm.read() + self.install_script(dist, script_name, script_text, script_path) + + def install_wrapper_scripts(self, dist): + dist = VersionlessRequirement(dist) + return easy_install.install_wrapper_scripts(self, dist) + + +class VersionlessRequirement: + """ + Adapt a pkg_resources.Distribution to simply return the project + name as the 'requirement' so that scripts will work across + multiple versions. + + >>> from pkg_resources import Distribution + >>> dist = Distribution(project_name='foo', version='1.0') + >>> str(dist.as_requirement()) + 'foo==1.0' + >>> adapted_dist = VersionlessRequirement(dist) + >>> str(adapted_dist.as_requirement()) + 'foo' + """ + + def __init__(self, dist): + self.__dist = dist + + def __getattr__(self, name): + return getattr(self.__dist, name) + + def as_requirement(self): + return self.project_name diff --git a/venv/lib/python3.8/site-packages/setuptools/command/dist_info.py b/venv/lib/python3.8/site-packages/setuptools/command/dist_info.py new file mode 100644 index 0000000..c45258f --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/command/dist_info.py @@ -0,0 +1,36 @@ +""" +Create a dist_info directory +As defined in the wheel specification +""" + +import os + +from distutils.core import Command +from distutils import log + + +class dist_info(Command): + + description = 'create a .dist-info directory' + + user_options = [ + ('egg-base=', 'e', "directory containing .egg-info directories" + " (default: top of the source tree)"), + ] + + def initialize_options(self): + self.egg_base = None + + def finalize_options(self): + pass + + def run(self): + egg_info = self.get_finalized_command('egg_info') + egg_info.egg_base = self.egg_base + egg_info.finalize_options() + egg_info.run() + dist_info_dir = egg_info.egg_info[:-len('.egg-info')] + '.dist-info' + log.info("creating '{}'".format(os.path.abspath(dist_info_dir))) + + bdist_wheel = self.get_finalized_command('bdist_wheel') + bdist_wheel.egg2dist(egg_info.egg_info, dist_info_dir) diff --git a/venv/lib/python3.8/site-packages/setuptools/command/easy_install.py b/venv/lib/python3.8/site-packages/setuptools/command/easy_install.py new file mode 100644 index 0000000..1f6839c --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/command/easy_install.py @@ -0,0 +1,2402 @@ +#!/usr/bin/env python +""" +Easy Install +------------ + +A tool for doing automatic download/extract/build of distutils-based Python +packages. For detailed documentation, see the accompanying EasyInstall.txt +file, or visit the `EasyInstall home page`__. + +__ https://setuptools.readthedocs.io/en/latest/easy_install.html + +""" + +from glob import glob +from distutils.util import get_platform +from distutils.util import convert_path, subst_vars +from distutils.errors import ( + DistutilsArgError, DistutilsOptionError, + DistutilsError, DistutilsPlatformError, +) +from distutils.command.install import INSTALL_SCHEMES, SCHEME_KEYS +from distutils import log, dir_util +from distutils.command.build_scripts import first_line_re +from distutils.spawn import find_executable +import sys +import os +import zipimport +import shutil +import tempfile +import zipfile +import re +import stat +import random +import textwrap +import warnings +import site +import struct +import contextlib +import subprocess +import shlex +import io + + +from sysconfig import get_config_vars, get_path + +from setuptools import SetuptoolsDeprecationWarning + +from setuptools.extern import six +from setuptools.extern.six.moves import configparser, map + +from setuptools import Command +from setuptools.sandbox import run_setup +from setuptools.py27compat import rmtree_safe +from setuptools.command import setopt +from setuptools.archive_util import unpack_archive +from setuptools.package_index import ( + PackageIndex, parse_requirement_arg, URL_SCHEME, +) +from setuptools.command import bdist_egg, egg_info +from setuptools.wheel import Wheel +from pkg_resources import ( + yield_lines, normalize_path, resource_string, ensure_directory, + get_distribution, find_distributions, Environment, Requirement, + Distribution, PathMetadata, EggMetadata, WorkingSet, DistributionNotFound, + VersionConflict, DEVELOP_DIST, +) +import pkg_resources.py31compat + +__metaclass__ = type + +# Turn on PEP440Warnings +warnings.filterwarnings("default", category=pkg_resources.PEP440Warning) + +__all__ = [ + 'samefile', 'easy_install', 'PthDistributions', 'extract_wininst_cfg', + 'main', 'get_exe_prefixes', +] + + +def is_64bit(): + return struct.calcsize("P") == 8 + + +def samefile(p1, p2): + """ + Determine if two paths reference the same file. + + Augments os.path.samefile to work on Windows and + suppresses errors if the path doesn't exist. + """ + both_exist = os.path.exists(p1) and os.path.exists(p2) + use_samefile = hasattr(os.path, 'samefile') and both_exist + if use_samefile: + return os.path.samefile(p1, p2) + norm_p1 = os.path.normpath(os.path.normcase(p1)) + norm_p2 = os.path.normpath(os.path.normcase(p2)) + return norm_p1 == norm_p2 + + +if six.PY2: + + def _to_bytes(s): + return s + + def isascii(s): + try: + six.text_type(s, 'ascii') + return True + except UnicodeError: + return False +else: + + def _to_bytes(s): + return s.encode('utf8') + + def isascii(s): + try: + s.encode('ascii') + return True + except UnicodeError: + return False + + +_one_liner = lambda text: textwrap.dedent(text).strip().replace('\n', '; ') + + +class easy_install(Command): + """Manage a download/build/install process""" + description = "Find/get/install Python packages" + command_consumes_arguments = True + + user_options = [ + ('prefix=', None, "installation prefix"), + ("zip-ok", "z", "install package as a zipfile"), + ("multi-version", "m", "make apps have to require() a version"), + ("upgrade", "U", "force upgrade (searches PyPI for latest versions)"), + ("install-dir=", "d", "install package to DIR"), + ("script-dir=", "s", "install scripts to DIR"), + ("exclude-scripts", "x", "Don't install scripts"), + ("always-copy", "a", "Copy all needed packages to install dir"), + ("index-url=", "i", "base URL of Python Package Index"), + ("find-links=", "f", "additional URL(s) to search for packages"), + ("build-directory=", "b", + "download/extract/build in DIR; keep the results"), + ('optimize=', 'O', + "also compile with optimization: -O1 for \"python -O\", " + "-O2 for \"python -OO\", and -O0 to disable [default: -O0]"), + ('record=', None, + "filename in which to record list of installed files"), + ('always-unzip', 'Z', "don't install as a zipfile, no matter what"), + ('site-dirs=', 'S', "list of directories where .pth files work"), + ('editable', 'e', "Install specified packages in editable form"), + ('no-deps', 'N', "don't install dependencies"), + ('allow-hosts=', 'H', "pattern(s) that hostnames must match"), + ('local-snapshots-ok', 'l', + "allow building eggs from local checkouts"), + ('version', None, "print version information and exit"), + ('install-layout=', None, "installation layout to choose (known values: deb)"), + ('force-installation-into-system-dir', '0', "force installation into /usr"), + ('no-find-links', None, + "Don't load find-links defined in packages being installed") + ] + boolean_options = [ + 'zip-ok', 'multi-version', 'exclude-scripts', 'upgrade', 'always-copy', + 'editable', + 'no-deps', 'local-snapshots-ok', 'version', 'force-installation-into-system-dir' + ] + + if site.ENABLE_USER_SITE: + help_msg = "install in user site-package '%s'" % site.USER_SITE + user_options.append(('user', None, help_msg)) + boolean_options.append('user') + + negative_opt = {'always-unzip': 'zip-ok'} + create_index = PackageIndex + + def initialize_options(self): + # the --user option seems to be an opt-in one, + # so the default should be False. + self.user = 0 + self.zip_ok = self.local_snapshots_ok = None + self.install_dir = self.script_dir = self.exclude_scripts = None + self.index_url = None + self.find_links = None + self.build_directory = None + self.args = None + self.optimize = self.record = None + self.upgrade = self.always_copy = self.multi_version = None + self.editable = self.no_deps = self.allow_hosts = None + self.root = self.prefix = self.no_report = None + self.version = None + self.install_purelib = None # for pure module distributions + self.install_platlib = None # non-pure (dists w/ extensions) + self.install_headers = None # for C/C++ headers + self.install_lib = None # set to either purelib or platlib + self.install_scripts = None + self.install_data = None + self.install_base = None + self.install_platbase = None + if site.ENABLE_USER_SITE: + self.install_userbase = site.USER_BASE + self.install_usersite = site.USER_SITE + else: + self.install_userbase = None + self.install_usersite = None + self.no_find_links = None + + # Options not specifiable via command line + self.package_index = None + self.pth_file = self.always_copy_from = None + self.site_dirs = None + self.installed_projects = {} + self.sitepy_installed = False + # enable custom installation, known values: deb + self.install_layout = None + self.force_installation_into_system_dir = None + self.multiarch = None + + # Always read easy_install options, even if we are subclassed, or have + # an independent instance created. This ensures that defaults will + # always come from the standard configuration file(s)' "easy_install" + # section, even if this is a "develop" or "install" command, or some + # other embedding. + self._dry_run = None + self.verbose = self.distribution.verbose + self.distribution._set_command_options( + self, self.distribution.get_option_dict('easy_install') + ) + + def delete_blockers(self, blockers): + extant_blockers = ( + filename for filename in blockers + if os.path.exists(filename) or os.path.islink(filename) + ) + list(map(self._delete_path, extant_blockers)) + + def _delete_path(self, path): + log.info("Deleting %s", path) + if self.dry_run: + return + + is_tree = os.path.isdir(path) and not os.path.islink(path) + remover = rmtree if is_tree else os.unlink + remover(path) + + @staticmethod + def _render_version(): + """ + Render the Setuptools version and installation details, then exit. + """ + ver = '{}.{}'.format(*sys.version_info) + dist = get_distribution('setuptools') + tmpl = 'setuptools {dist.version} from {dist.location} (Python {ver})' + print(tmpl.format(**locals())) + raise SystemExit() + + def finalize_options(self): + self.version and self._render_version() + + py_version = sys.version.split()[0] + prefix, exec_prefix = get_config_vars('prefix', 'exec_prefix') + + self.config_vars = { + 'dist_name': self.distribution.get_name(), + 'dist_version': self.distribution.get_version(), + 'dist_fullname': self.distribution.get_fullname(), + 'py_version': py_version, + 'py_version_short': py_version[0:3], + 'py_version_nodot': py_version[0] + py_version[2], + 'sys_prefix': prefix, + 'prefix': prefix, + 'sys_exec_prefix': exec_prefix, + 'exec_prefix': exec_prefix, + # Only python 3.2+ has abiflags + 'abiflags': getattr(sys, 'abiflags', ''), + } + + if site.ENABLE_USER_SITE: + self.config_vars['userbase'] = self.install_userbase + self.config_vars['usersite'] = self.install_usersite + + self._fix_install_dir_for_user_site() + + self.expand_basedirs() + self.expand_dirs() + + if self.install_layout: + if not self.install_layout.lower() in ['deb']: + raise DistutilsOptionError("unknown value for --install-layout") + self.install_layout = self.install_layout.lower() + + import sysconfig + if sys.version_info[:2] >= (3, 3): + self.multiarch = sysconfig.get_config_var('MULTIARCH') + + self._expand( + 'install_dir', 'script_dir', 'build_directory', + 'site_dirs', + ) + # If a non-default installation directory was specified, default the + # script directory to match it. + if self.script_dir is None: + self.script_dir = self.install_dir + + if self.no_find_links is None: + self.no_find_links = False + + # Let install_dir get set by install_lib command, which in turn + # gets its info from the install command, and takes into account + # --prefix and --home and all that other crud. + self.set_undefined_options( + 'install_lib', ('install_dir', 'install_dir') + ) + # Likewise, set default script_dir from 'install_scripts.install_dir' + self.set_undefined_options( + 'install_scripts', ('install_dir', 'script_dir') + ) + + if self.user and self.install_purelib: + self.install_dir = self.install_purelib + self.script_dir = self.install_scripts + + if self.prefix == '/usr' and not self.force_installation_into_system_dir: + raise DistutilsOptionError("""installation into /usr + +Trying to install into the system managed parts of the file system. Please +consider to install to another location, or use the option +--force-installation-into-system-dir to overwrite this warning. +""") + + # default --record from the install command + self.set_undefined_options('install', ('record', 'record')) + # Should this be moved to the if statement below? It's not used + # elsewhere + normpath = map(normalize_path, sys.path) + self.all_site_dirs = get_site_dirs() + if self.site_dirs is not None: + site_dirs = [ + os.path.expanduser(s.strip()) for s in + self.site_dirs.split(',') + ] + for d in site_dirs: + if not os.path.isdir(d): + log.warn("%s (in --site-dirs) does not exist", d) + elif normalize_path(d) not in normpath: + raise DistutilsOptionError( + d + " (in --site-dirs) is not on sys.path" + ) + else: + self.all_site_dirs.append(normalize_path(d)) + if not self.editable: + self.check_site_dir() + self.index_url = self.index_url or "https://pypi.org/simple/" + self.shadow_path = self.all_site_dirs[:] + for path_item in self.install_dir, normalize_path(self.script_dir): + if path_item not in self.shadow_path: + self.shadow_path.insert(0, path_item) + + if self.allow_hosts is not None: + hosts = [s.strip() for s in self.allow_hosts.split(',')] + else: + hosts = ['*'] + if self.package_index is None: + self.package_index = self.create_index( + self.index_url, search_path=self.shadow_path, hosts=hosts, + ) + self.local_index = Environment(self.shadow_path + sys.path) + + if self.find_links is not None: + if isinstance(self.find_links, six.string_types): + self.find_links = self.find_links.split() + else: + self.find_links = [] + if self.local_snapshots_ok: + self.package_index.scan_egg_links(self.shadow_path + sys.path) + if not self.no_find_links: + self.package_index.add_find_links(self.find_links) + self.set_undefined_options('install_lib', ('optimize', 'optimize')) + if not isinstance(self.optimize, int): + try: + self.optimize = int(self.optimize) + if not (0 <= self.optimize <= 2): + raise ValueError + except ValueError: + raise DistutilsOptionError("--optimize must be 0, 1, or 2") + + if self.editable and not self.build_directory: + raise DistutilsArgError( + "Must specify a build directory (-b) when using --editable" + ) + if not self.args: + raise DistutilsArgError( + "No urls, filenames, or requirements specified (see --help)") + + self.outputs = [] + + def _fix_install_dir_for_user_site(self): + """ + Fix the install_dir if "--user" was used. + """ + if not self.user or not site.ENABLE_USER_SITE: + return + + self.create_home_path() + if self.install_userbase is None: + msg = "User base directory is not specified" + raise DistutilsPlatformError(msg) + self.install_base = self.install_platbase = self.install_userbase + scheme_name = os.name.replace('posix', 'unix') + '_user' + self.select_scheme(scheme_name) + + def _expand_attrs(self, attrs): + for attr in attrs: + val = getattr(self, attr) + if val is not None: + if os.name == 'posix' or os.name == 'nt': + val = os.path.expanduser(val) + val = subst_vars(val, self.config_vars) + setattr(self, attr, val) + + def expand_basedirs(self): + """Calls `os.path.expanduser` on install_base, install_platbase and + root.""" + self._expand_attrs(['install_base', 'install_platbase', 'root']) + + def expand_dirs(self): + """Calls `os.path.expanduser` on install dirs.""" + dirs = [ + 'install_purelib', + 'install_platlib', + 'install_lib', + 'install_headers', + 'install_scripts', + 'install_data', + ] + self._expand_attrs(dirs) + + def run(self, show_deprecation=True): + if show_deprecation: + self.announce( + "WARNING: The easy_install command is deprecated " + "and will be removed in a future version." + , log.WARN, + ) + if self.verbose != self.distribution.verbose: + log.set_verbosity(self.verbose) + try: + for spec in self.args: + self.easy_install(spec, not self.no_deps) + if self.record: + outputs = list(sorted(self.outputs)) + if self.root: # strip any package prefix + root_len = len(self.root) + for counter in range(len(outputs)): + outputs[counter] = outputs[counter][root_len:] + from distutils import file_util + + self.execute( + file_util.write_file, (self.record, outputs), + "writing list of installed files to '%s'" % + self.record + ) + self.warn_deprecated_options() + finally: + log.set_verbosity(self.distribution.verbose) + + def pseudo_tempname(self): + """Return a pseudo-tempname base in the install directory. + This code is intentionally naive; if a malicious party can write to + the target directory you're already in deep doodoo. + """ + try: + pid = os.getpid() + except Exception: + pid = random.randint(0, sys.maxsize) + return os.path.join(self.install_dir, "test-easy-install-%s" % pid) + + def warn_deprecated_options(self): + pass + + def check_site_dir(self): + """Verify that self.install_dir is .pth-capable dir, if needed""" + + instdir = normalize_path(self.install_dir) + pth_file = os.path.join(instdir, 'easy-install.pth') + + # Is it a configured, PYTHONPATH, implicit, or explicit site dir? + is_site_dir = instdir in self.all_site_dirs + + if not is_site_dir and not self.multi_version: + # No? Then directly test whether it does .pth file processing + is_site_dir = self.check_pth_processing() + else: + # make sure we can write to target dir + testfile = self.pseudo_tempname() + '.write-test' + test_exists = os.path.exists(testfile) + try: + if test_exists: + os.unlink(testfile) + open(testfile, 'w').close() + os.unlink(testfile) + except (OSError, IOError): + self.cant_write_to_target() + + if not is_site_dir and not self.multi_version: + # Can't install non-multi to non-site dir + raise DistutilsError(self.no_default_version_msg()) + + if is_site_dir: + if self.pth_file is None: + self.pth_file = PthDistributions(pth_file, self.all_site_dirs) + else: + self.pth_file = None + + if instdir not in map(normalize_path, _pythonpath()): + # only PYTHONPATH dirs need a site.py, so pretend it's there + self.sitepy_installed = True + elif self.multi_version and not os.path.exists(pth_file): + self.sitepy_installed = True # don't need site.py in this case + self.pth_file = None # and don't create a .pth file + self.install_dir = instdir + + __cant_write_msg = textwrap.dedent(""" + can't create or remove files in install directory + + The following error occurred while trying to add or remove files in the + installation directory: + + %s + + The installation directory you specified (via --install-dir, --prefix, or + the distutils default setting) was: + + %s + """).lstrip() + + __not_exists_id = textwrap.dedent(""" + This directory does not currently exist. Please create it and try again, or + choose a different installation directory (using the -d or --install-dir + option). + """).lstrip() + + __access_msg = textwrap.dedent(""" + Perhaps your account does not have write access to this directory? If the + installation directory is a system-owned directory, you may need to sign in + as the administrator or "root" account. If you do not have administrative + access to this machine, you may wish to choose a different installation + directory, preferably one that is listed in your PYTHONPATH environment + variable. + + For information on other options, you may wish to consult the + documentation at: + + https://setuptools.readthedocs.io/en/latest/easy_install.html + + Please make the appropriate changes for your system and try again. + """).lstrip() + + def cant_write_to_target(self): + msg = self.__cant_write_msg % (sys.exc_info()[1], self.install_dir,) + + if not os.path.exists(self.install_dir): + msg += '\n' + self.__not_exists_id + else: + msg += '\n' + self.__access_msg + raise DistutilsError(msg) + + def check_pth_processing(self): + """Empirically verify whether .pth files are supported in inst. dir""" + instdir = self.install_dir + log.info("Checking .pth file support in %s", instdir) + pth_file = self.pseudo_tempname() + ".pth" + ok_file = pth_file + '.ok' + ok_exists = os.path.exists(ok_file) + tmpl = _one_liner(""" + import os + f = open({ok_file!r}, 'w') + f.write('OK') + f.close() + """) + '\n' + try: + if ok_exists: + os.unlink(ok_file) + dirname = os.path.dirname(ok_file) + pkg_resources.py31compat.makedirs(dirname, exist_ok=True) + f = open(pth_file, 'w') + except (OSError, IOError): + self.cant_write_to_target() + else: + try: + f.write(tmpl.format(**locals())) + f.close() + f = None + executable = sys.executable + if os.name == 'nt': + dirname, basename = os.path.split(executable) + alt = os.path.join(dirname, 'pythonw.exe') + use_alt = ( + basename.lower() == 'python.exe' and + os.path.exists(alt) + ) + if use_alt: + # use pythonw.exe to avoid opening a console window + executable = alt + + from distutils.spawn import spawn + + spawn([executable, '-E', '-c', 'pass'], 0) + + if os.path.exists(ok_file): + log.info( + "TEST PASSED: %s appears to support .pth files", + instdir + ) + return True + finally: + if f: + f.close() + if os.path.exists(ok_file): + os.unlink(ok_file) + if os.path.exists(pth_file): + os.unlink(pth_file) + if not self.multi_version: + log.warn("TEST FAILED: %s does NOT support .pth files", instdir) + return False + + def install_egg_scripts(self, dist): + """Write all the scripts for `dist`, unless scripts are excluded""" + if not self.exclude_scripts and dist.metadata_isdir('scripts'): + for script_name in dist.metadata_listdir('scripts'): + if dist.metadata_isdir('scripts/' + script_name): + # The "script" is a directory, likely a Python 3 + # __pycache__ directory, so skip it. + continue + self.install_script( + dist, script_name, + dist.get_metadata('scripts/' + script_name) + ) + self.install_wrapper_scripts(dist) + + def add_output(self, path): + if os.path.isdir(path): + for base, dirs, files in os.walk(path): + for filename in files: + self.outputs.append(os.path.join(base, filename)) + else: + self.outputs.append(path) + + def not_editable(self, spec): + if self.editable: + raise DistutilsArgError( + "Invalid argument %r: you can't use filenames or URLs " + "with --editable (except via the --find-links option)." + % (spec,) + ) + + def check_editable(self, spec): + if not self.editable: + return + + if os.path.exists(os.path.join(self.build_directory, spec.key)): + raise DistutilsArgError( + "%r already exists in %s; can't do a checkout there" % + (spec.key, self.build_directory) + ) + + @contextlib.contextmanager + def _tmpdir(self): + tmpdir = tempfile.mkdtemp(prefix=u"easy_install-") + try: + # cast to str as workaround for #709 and #710 and #712 + yield str(tmpdir) + finally: + os.path.exists(tmpdir) and rmtree(rmtree_safe(tmpdir)) + + def easy_install(self, spec, deps=False): + if not self.editable: + self.install_site_py() + + with self._tmpdir() as tmpdir: + if not isinstance(spec, Requirement): + if URL_SCHEME(spec): + # It's a url, download it to tmpdir and process + self.not_editable(spec) + dl = self.package_index.download(spec, tmpdir) + return self.install_item(None, dl, tmpdir, deps, True) + + elif os.path.exists(spec): + # Existing file or directory, just process it directly + self.not_editable(spec) + return self.install_item(None, spec, tmpdir, deps, True) + else: + spec = parse_requirement_arg(spec) + + self.check_editable(spec) + dist = self.package_index.fetch_distribution( + spec, tmpdir, self.upgrade, self.editable, + not self.always_copy, self.local_index + ) + if dist is None: + msg = "Could not find suitable distribution for %r" % spec + if self.always_copy: + msg += " (--always-copy skips system and development eggs)" + raise DistutilsError(msg) + elif dist.precedence == DEVELOP_DIST: + # .egg-info dists don't need installing, just process deps + self.process_distribution(spec, dist, deps, "Using") + return dist + else: + return self.install_item(spec, dist.location, tmpdir, deps) + + def install_item(self, spec, download, tmpdir, deps, install_needed=False): + + # Installation is also needed if file in tmpdir or is not an egg + install_needed = install_needed or self.always_copy + install_needed = install_needed or os.path.dirname(download) == tmpdir + install_needed = install_needed or not download.endswith('.egg') + install_needed = install_needed or ( + self.always_copy_from is not None and + os.path.dirname(normalize_path(download)) == + normalize_path(self.always_copy_from) + ) + + if spec and not install_needed: + # at this point, we know it's a local .egg, we just don't know if + # it's already installed. + for dist in self.local_index[spec.project_name]: + if dist.location == download: + break + else: + install_needed = True # it's not in the local index + + log.info("Processing %s", os.path.basename(download)) + + if install_needed: + dists = self.install_eggs(spec, download, tmpdir) + for dist in dists: + self.process_distribution(spec, dist, deps) + else: + dists = [self.egg_distribution(download)] + self.process_distribution(spec, dists[0], deps, "Using") + + if spec is not None: + for dist in dists: + if dist in spec: + return dist + + def select_scheme(self, name): + """Sets the install directories by applying the install schemes.""" + # it's the caller's problem if they supply a bad name! + scheme = INSTALL_SCHEMES[name] + for key in SCHEME_KEYS: + attrname = 'install_' + key + if getattr(self, attrname) is None: + setattr(self, attrname, scheme[key]) + + def process_distribution(self, requirement, dist, deps=True, *info): + self.update_pth(dist) + self.package_index.add(dist) + if dist in self.local_index[dist.key]: + self.local_index.remove(dist) + self.local_index.add(dist) + self.install_egg_scripts(dist) + self.installed_projects[dist.key] = dist + log.info(self.installation_report(requirement, dist, *info)) + if (dist.has_metadata('dependency_links.txt') and + not self.no_find_links): + self.package_index.add_find_links( + dist.get_metadata_lines('dependency_links.txt') + ) + if not deps and not self.always_copy: + return + elif requirement is not None and dist.key != requirement.key: + log.warn("Skipping dependencies for %s", dist) + return # XXX this is not the distribution we were looking for + elif requirement is None or dist not in requirement: + # if we wound up with a different version, resolve what we've got + distreq = dist.as_requirement() + requirement = Requirement(str(distreq)) + log.info("Processing dependencies for %s", requirement) + try: + distros = WorkingSet([]).resolve( + [requirement], self.local_index, self.easy_install + ) + except DistributionNotFound as e: + raise DistutilsError(str(e)) + except VersionConflict as e: + raise DistutilsError(e.report()) + if self.always_copy or self.always_copy_from: + # Force all the relevant distros to be copied or activated + for dist in distros: + if dist.key not in self.installed_projects: + self.easy_install(dist.as_requirement()) + log.info("Finished processing dependencies for %s", requirement) + + def should_unzip(self, dist): + if self.zip_ok is not None: + return not self.zip_ok + if dist.has_metadata('not-zip-safe'): + return True + if not dist.has_metadata('zip-safe'): + return True + return False + + def maybe_move(self, spec, dist_filename, setup_base): + dst = os.path.join(self.build_directory, spec.key) + if os.path.exists(dst): + msg = ( + "%r already exists in %s; build directory %s will not be kept" + ) + log.warn(msg, spec.key, self.build_directory, setup_base) + return setup_base + if os.path.isdir(dist_filename): + setup_base = dist_filename + else: + if os.path.dirname(dist_filename) == setup_base: + os.unlink(dist_filename) # get it out of the tmp dir + contents = os.listdir(setup_base) + if len(contents) == 1: + dist_filename = os.path.join(setup_base, contents[0]) + if os.path.isdir(dist_filename): + # if the only thing there is a directory, move it instead + setup_base = dist_filename + ensure_directory(dst) + shutil.move(setup_base, dst) + return dst + + def install_wrapper_scripts(self, dist): + if self.exclude_scripts: + return + for args in ScriptWriter.best().get_args(dist): + self.write_script(*args) + + def install_script(self, dist, script_name, script_text, dev_path=None): + """Generate a legacy script wrapper and install it""" + spec = str(dist.as_requirement()) + is_script = is_python_script(script_text, script_name) + + if is_script: + body = self._load_template(dev_path) % locals() + script_text = ScriptWriter.get_header(script_text) + body + self.write_script(script_name, _to_bytes(script_text), 'b') + + @staticmethod + def _load_template(dev_path): + """ + There are a couple of template scripts in the package. This + function loads one of them and prepares it for use. + """ + # See https://github.com/pypa/setuptools/issues/134 for info + # on script file naming and downstream issues with SVR4 + name = 'script.tmpl' + if dev_path: + name = name.replace('.tmpl', ' (dev).tmpl') + + raw_bytes = resource_string('setuptools', name) + return raw_bytes.decode('utf-8') + + def write_script(self, script_name, contents, mode="t", blockers=()): + """Write an executable file to the scripts directory""" + self.delete_blockers( # clean up old .py/.pyw w/o a script + [os.path.join(self.script_dir, x) for x in blockers] + ) + log.info("Installing %s script to %s", script_name, self.script_dir) + target = os.path.join(self.script_dir, script_name) + self.add_output(target) + + if self.dry_run: + return + + mask = current_umask() + ensure_directory(target) + if os.path.exists(target): + os.unlink(target) + with open(target, "w" + mode) as f: + f.write(contents) + chmod(target, 0o777 - mask) + + def install_eggs(self, spec, dist_filename, tmpdir): + # .egg dirs or files are already built, so just return them + if dist_filename.lower().endswith('.egg'): + return [self.install_egg(dist_filename, tmpdir)] + elif dist_filename.lower().endswith('.exe'): + return [self.install_exe(dist_filename, tmpdir)] + elif dist_filename.lower().endswith('.whl'): + return [self.install_wheel(dist_filename, tmpdir)] + + # Anything else, try to extract and build + setup_base = tmpdir + if os.path.isfile(dist_filename) and not dist_filename.endswith('.py'): + unpack_archive(dist_filename, tmpdir, self.unpack_progress) + elif os.path.isdir(dist_filename): + setup_base = os.path.abspath(dist_filename) + + if (setup_base.startswith(tmpdir) # something we downloaded + and self.build_directory and spec is not None): + setup_base = self.maybe_move(spec, dist_filename, setup_base) + + # Find the setup.py file + setup_script = os.path.join(setup_base, 'setup.py') + + if not os.path.exists(setup_script): + setups = glob(os.path.join(setup_base, '*', 'setup.py')) + if not setups: + raise DistutilsError( + "Couldn't find a setup script in %s" % + os.path.abspath(dist_filename) + ) + if len(setups) > 1: + raise DistutilsError( + "Multiple setup scripts in %s" % + os.path.abspath(dist_filename) + ) + setup_script = setups[0] + + # Now run it, and return the result + if self.editable: + log.info(self.report_editable(spec, setup_script)) + return [] + else: + return self.build_and_install(setup_script, setup_base) + + def egg_distribution(self, egg_path): + if os.path.isdir(egg_path): + metadata = PathMetadata(egg_path, os.path.join(egg_path, + 'EGG-INFO')) + else: + metadata = EggMetadata(zipimport.zipimporter(egg_path)) + return Distribution.from_filename(egg_path, metadata=metadata) + + def install_egg(self, egg_path, tmpdir): + destination = os.path.join( + self.install_dir, + os.path.basename(egg_path), + ) + destination = os.path.abspath(destination) + if not self.dry_run: + ensure_directory(destination) + + dist = self.egg_distribution(egg_path) + if not samefile(egg_path, destination): + if os.path.isdir(destination) and not os.path.islink(destination): + dir_util.remove_tree(destination, dry_run=self.dry_run) + elif os.path.exists(destination): + self.execute( + os.unlink, + (destination,), + "Removing " + destination, + ) + try: + new_dist_is_zipped = False + if os.path.isdir(egg_path): + if egg_path.startswith(tmpdir): + f, m = shutil.move, "Moving" + else: + f, m = shutil.copytree, "Copying" + elif self.should_unzip(dist): + self.mkpath(destination) + f, m = self.unpack_and_compile, "Extracting" + else: + new_dist_is_zipped = True + if egg_path.startswith(tmpdir): + f, m = shutil.move, "Moving" + else: + f, m = shutil.copy2, "Copying" + self.execute( + f, + (egg_path, destination), + (m + " %s to %s") % ( + os.path.basename(egg_path), + os.path.dirname(destination) + ), + ) + update_dist_caches( + destination, + fix_zipimporter_caches=new_dist_is_zipped, + ) + except Exception: + update_dist_caches(destination, fix_zipimporter_caches=False) + raise + + self.add_output(destination) + return self.egg_distribution(destination) + + def install_exe(self, dist_filename, tmpdir): + # See if it's valid, get data + cfg = extract_wininst_cfg(dist_filename) + if cfg is None: + raise DistutilsError( + "%s is not a valid distutils Windows .exe" % dist_filename + ) + # Create a dummy distribution object until we build the real distro + dist = Distribution( + None, + project_name=cfg.get('metadata', 'name'), + version=cfg.get('metadata', 'version'), platform=get_platform(), + ) + + # Convert the .exe to an unpacked egg + egg_path = os.path.join(tmpdir, dist.egg_name() + '.egg') + dist.location = egg_path + egg_tmp = egg_path + '.tmp' + _egg_info = os.path.join(egg_tmp, 'EGG-INFO') + pkg_inf = os.path.join(_egg_info, 'PKG-INFO') + ensure_directory(pkg_inf) # make sure EGG-INFO dir exists + dist._provider = PathMetadata(egg_tmp, _egg_info) # XXX + self.exe_to_egg(dist_filename, egg_tmp) + + # Write EGG-INFO/PKG-INFO + if not os.path.exists(pkg_inf): + f = open(pkg_inf, 'w') + f.write('Metadata-Version: 1.0\n') + for k, v in cfg.items('metadata'): + if k != 'target_version': + f.write('%s: %s\n' % (k.replace('_', '-').title(), v)) + f.close() + script_dir = os.path.join(_egg_info, 'scripts') + # delete entry-point scripts to avoid duping + self.delete_blockers([ + os.path.join(script_dir, args[0]) + for args in ScriptWriter.get_args(dist) + ]) + # Build .egg file from tmpdir + bdist_egg.make_zipfile( + egg_path, egg_tmp, verbose=self.verbose, dry_run=self.dry_run, + ) + # install the .egg + return self.install_egg(egg_path, tmpdir) + + def exe_to_egg(self, dist_filename, egg_tmp): + """Extract a bdist_wininst to the directories an egg would use""" + # Check for .pth file and set up prefix translations + prefixes = get_exe_prefixes(dist_filename) + to_compile = [] + native_libs = [] + top_level = {} + + def process(src, dst): + s = src.lower() + for old, new in prefixes: + if s.startswith(old): + src = new + src[len(old):] + parts = src.split('/') + dst = os.path.join(egg_tmp, *parts) + dl = dst.lower() + if dl.endswith('.pyd') or dl.endswith('.dll'): + parts[-1] = bdist_egg.strip_module(parts[-1]) + top_level[os.path.splitext(parts[0])[0]] = 1 + native_libs.append(src) + elif dl.endswith('.py') and old != 'SCRIPTS/': + top_level[os.path.splitext(parts[0])[0]] = 1 + to_compile.append(dst) + return dst + if not src.endswith('.pth'): + log.warn("WARNING: can't process %s", src) + return None + + # extract, tracking .pyd/.dll->native_libs and .py -> to_compile + unpack_archive(dist_filename, egg_tmp, process) + stubs = [] + for res in native_libs: + if res.lower().endswith('.pyd'): # create stubs for .pyd's + parts = res.split('/') + resource = parts[-1] + parts[-1] = bdist_egg.strip_module(parts[-1]) + '.py' + pyfile = os.path.join(egg_tmp, *parts) + to_compile.append(pyfile) + stubs.append(pyfile) + bdist_egg.write_stub(resource, pyfile) + self.byte_compile(to_compile) # compile .py's + bdist_egg.write_safety_flag( + os.path.join(egg_tmp, 'EGG-INFO'), + bdist_egg.analyze_egg(egg_tmp, stubs)) # write zip-safety flag + + for name in 'top_level', 'native_libs': + if locals()[name]: + txt = os.path.join(egg_tmp, 'EGG-INFO', name + '.txt') + if not os.path.exists(txt): + f = open(txt, 'w') + f.write('\n'.join(locals()[name]) + '\n') + f.close() + + def install_wheel(self, wheel_path, tmpdir): + wheel = Wheel(wheel_path) + assert wheel.is_compatible() + destination = os.path.join(self.install_dir, wheel.egg_name()) + destination = os.path.abspath(destination) + if not self.dry_run: + ensure_directory(destination) + if os.path.isdir(destination) and not os.path.islink(destination): + dir_util.remove_tree(destination, dry_run=self.dry_run) + elif os.path.exists(destination): + self.execute( + os.unlink, + (destination,), + "Removing " + destination, + ) + try: + self.execute( + wheel.install_as_egg, + (destination,), + ("Installing %s to %s") % ( + os.path.basename(wheel_path), + os.path.dirname(destination) + ), + ) + finally: + update_dist_caches(destination, fix_zipimporter_caches=False) + self.add_output(destination) + return self.egg_distribution(destination) + + __mv_warning = textwrap.dedent(""" + Because this distribution was installed --multi-version, before you can + import modules from this package in an application, you will need to + 'import pkg_resources' and then use a 'require()' call similar to one of + these examples, in order to select the desired version: + + pkg_resources.require("%(name)s") # latest installed version + pkg_resources.require("%(name)s==%(version)s") # this exact version + pkg_resources.require("%(name)s>=%(version)s") # this version or higher + """).lstrip() + + __id_warning = textwrap.dedent(""" + Note also that the installation directory must be on sys.path at runtime for + this to work. (e.g. by being the application's script directory, by being on + PYTHONPATH, or by being added to sys.path by your code.) + """) + + def installation_report(self, req, dist, what="Installed"): + """Helpful installation message for display to package users""" + msg = "\n%(what)s %(eggloc)s%(extras)s" + if self.multi_version and not self.no_report: + msg += '\n' + self.__mv_warning + if self.install_dir not in map(normalize_path, sys.path): + msg += '\n' + self.__id_warning + + eggloc = dist.location + name = dist.project_name + version = dist.version + extras = '' # TODO: self.report_extras(req, dist) + return msg % locals() + + __editable_msg = textwrap.dedent(""" + Extracted editable version of %(spec)s to %(dirname)s + + If it uses setuptools in its setup script, you can activate it in + "development" mode by going to that directory and running:: + + %(python)s setup.py develop + + See the setuptools documentation for the "develop" command for more info. + """).lstrip() + + def report_editable(self, spec, setup_script): + dirname = os.path.dirname(setup_script) + python = sys.executable + return '\n' + self.__editable_msg % locals() + + def run_setup(self, setup_script, setup_base, args): + sys.modules.setdefault('distutils.command.bdist_egg', bdist_egg) + sys.modules.setdefault('distutils.command.egg_info', egg_info) + + args = list(args) + if self.verbose > 2: + v = 'v' * (self.verbose - 1) + args.insert(0, '-' + v) + elif self.verbose < 2: + args.insert(0, '-q') + if self.dry_run: + args.insert(0, '-n') + log.info( + "Running %s %s", setup_script[len(setup_base) + 1:], ' '.join(args) + ) + try: + run_setup(setup_script, args) + except SystemExit as v: + raise DistutilsError("Setup script exited with %s" % (v.args[0],)) + + def build_and_install(self, setup_script, setup_base): + args = ['bdist_egg', '--dist-dir'] + + dist_dir = tempfile.mkdtemp( + prefix='egg-dist-tmp-', dir=os.path.dirname(setup_script) + ) + try: + self._set_fetcher_options(os.path.dirname(setup_script)) + args.append(dist_dir) + + self.run_setup(setup_script, setup_base, args) + all_eggs = Environment([dist_dir]) + eggs = [] + for key in all_eggs: + for dist in all_eggs[key]: + eggs.append(self.install_egg(dist.location, setup_base)) + if not eggs and not self.dry_run: + log.warn("No eggs found in %s (setup script problem?)", + dist_dir) + return eggs + finally: + rmtree(dist_dir) + log.set_verbosity(self.verbose) # restore our log verbosity + + def _set_fetcher_options(self, base): + """ + When easy_install is about to run bdist_egg on a source dist, that + source dist might have 'setup_requires' directives, requiring + additional fetching. Ensure the fetcher options given to easy_install + are available to that command as well. + """ + # find the fetch options from easy_install and write them out + # to the setup.cfg file. + ei_opts = self.distribution.get_option_dict('easy_install').copy() + fetch_directives = ( + 'find_links', 'site_dirs', 'index_url', 'optimize', 'allow_hosts', + ) + fetch_options = {} + for key, val in ei_opts.items(): + if key not in fetch_directives: + continue + fetch_options[key.replace('_', '-')] = val[1] + # create a settings dictionary suitable for `edit_config` + settings = dict(easy_install=fetch_options) + cfg_filename = os.path.join(base, 'setup.cfg') + setopt.edit_config(cfg_filename, settings) + + def update_pth(self, dist): + if self.pth_file is None: + return + + for d in self.pth_file[dist.key]: # drop old entries + if self.multi_version or d.location != dist.location: + log.info("Removing %s from easy-install.pth file", d) + self.pth_file.remove(d) + if d.location in self.shadow_path: + self.shadow_path.remove(d.location) + + if not self.multi_version: + if dist.location in self.pth_file.paths: + log.info( + "%s is already the active version in easy-install.pth", + dist, + ) + else: + log.info("Adding %s to easy-install.pth file", dist) + self.pth_file.add(dist) # add new entry + if dist.location not in self.shadow_path: + self.shadow_path.append(dist.location) + + if not self.dry_run: + + self.pth_file.save() + + if dist.key == 'setuptools': + # Ensure that setuptools itself never becomes unavailable! + # XXX should this check for latest version? + filename = os.path.join(self.install_dir, 'setuptools.pth') + if os.path.islink(filename): + os.unlink(filename) + f = open(filename, 'wt') + f.write(self.pth_file.make_relative(dist.location) + '\n') + f.close() + + def unpack_progress(self, src, dst): + # Progress filter for unpacking + log.debug("Unpacking %s to %s", src, dst) + return dst # only unpack-and-compile skips files for dry run + + def unpack_and_compile(self, egg_path, destination): + to_compile = [] + to_chmod = [] + + def pf(src, dst): + if dst.endswith('.py') and not src.startswith('EGG-INFO/'): + to_compile.append(dst) + elif dst.endswith('.dll') or dst.endswith('.so'): + to_chmod.append(dst) + self.unpack_progress(src, dst) + return not self.dry_run and dst or None + + unpack_archive(egg_path, destination, pf) + self.byte_compile(to_compile) + if not self.dry_run: + for f in to_chmod: + mode = ((os.stat(f)[stat.ST_MODE]) | 0o555) & 0o7755 + chmod(f, mode) + + def byte_compile(self, to_compile): + if sys.dont_write_bytecode: + return + + from distutils.util import byte_compile + + try: + # try to make the byte compile messages quieter + log.set_verbosity(self.verbose - 1) + + byte_compile(to_compile, optimize=0, force=1, dry_run=self.dry_run) + if self.optimize: + byte_compile( + to_compile, optimize=self.optimize, force=1, + dry_run=self.dry_run, + ) + finally: + log.set_verbosity(self.verbose) # restore original verbosity + + __no_default_msg = textwrap.dedent(""" + bad install directory or PYTHONPATH + + You are attempting to install a package to a directory that is not + on PYTHONPATH and which Python does not read ".pth" files from. The + installation directory you specified (via --install-dir, --prefix, or + the distutils default setting) was: + + %s + + and your PYTHONPATH environment variable currently contains: + + %r + + Here are some of your options for correcting the problem: + + * You can choose a different installation directory, i.e., one that is + on PYTHONPATH or supports .pth files + + * You can add the installation directory to the PYTHONPATH environment + variable. (It must then also be on PYTHONPATH whenever you run + Python and want to use the package(s) you are installing.) + + * You can set up the installation directory to support ".pth" files by + using one of the approaches described here: + + https://setuptools.readthedocs.io/en/latest/easy_install.html#custom-installation-locations + + + Please make the appropriate changes for your system and try again.""").lstrip() + + def no_default_version_msg(self): + template = self.__no_default_msg + return template % (self.install_dir, os.environ.get('PYTHONPATH', '')) + + def install_site_py(self): + """Make sure there's a site.py in the target dir, if needed""" + + if self.sitepy_installed: + return # already did it, or don't need to + + sitepy = os.path.join(self.install_dir, "site.py") + source = resource_string("setuptools", "site-patch.py") + source = source.decode('utf-8') + current = "" + + if os.path.exists(sitepy): + log.debug("Checking existing site.py in %s", self.install_dir) + with io.open(sitepy) as strm: + current = strm.read() + + if not current.startswith('def __boot():'): + raise DistutilsError( + "%s is not a setuptools-generated site.py; please" + " remove it." % sitepy + ) + + if current != source: + log.info("Creating %s", sitepy) + if not self.dry_run: + ensure_directory(sitepy) + with io.open(sitepy, 'w', encoding='utf-8') as strm: + strm.write(source) + self.byte_compile([sitepy]) + + self.sitepy_installed = True + + def create_home_path(self): + """Create directories under ~.""" + if not self.user: + return + home = convert_path(os.path.expanduser("~")) + for name, path in six.iteritems(self.config_vars): + if path.startswith(home) and not os.path.isdir(path): + self.debug_print("os.makedirs('%s', 0o700)" % path) + os.makedirs(path, 0o700) + + if sys.version[:3] in ('2.3', '2.4', '2.5') or 'real_prefix' in sys.__dict__: + sitedir_name = 'site-packages' + else: + sitedir_name = 'dist-packages' + + INSTALL_SCHEMES = dict( + posix=dict( + install_dir='$base/lib/python$py_version_short/site-packages', + script_dir='$base/bin', + ), + unix_local = dict( + install_dir = '$base/local/lib/python$py_version_short/%s' % sitedir_name, + script_dir = '$base/local/bin', + ), + posix_local = dict( + install_dir = '$base/local/lib/python$py_version_short/%s' % sitedir_name, + script_dir = '$base/local/bin', + ), + deb_system = dict( + install_dir = '$base/lib/python3/%s' % sitedir_name, + script_dir = '$base/bin', + ), + ) + + DEFAULT_SCHEME = dict( + install_dir='$base/Lib/site-packages', + script_dir='$base/Scripts', + ) + + def _expand(self, *attrs): + config_vars = self.get_finalized_command('install').config_vars + + if self.prefix or self.install_layout: + if self.install_layout and self.install_layout in ['deb']: + scheme_name = "deb_system" + self.prefix = '/usr' + elif self.prefix or 'real_prefix' in sys.__dict__: + scheme_name = os.name + else: + scheme_name = "posix_local" + # Set default install_dir/scripts from --prefix + config_vars = config_vars.copy() + config_vars['base'] = self.prefix + scheme = self.INSTALL_SCHEMES.get(scheme_name,self.DEFAULT_SCHEME) + for attr, val in scheme.items(): + if getattr(self, attr, None) is None: + setattr(self, attr, val) + + from distutils.util import subst_vars + + for attr in attrs: + val = getattr(self, attr) + if val is not None: + val = subst_vars(val, config_vars) + if os.name == 'posix': + val = os.path.expanduser(val) + setattr(self, attr, val) + + +def _pythonpath(): + items = os.environ.get('PYTHONPATH', '').split(os.pathsep) + return filter(None, items) + + +def get_site_dirs(): + """ + Return a list of 'site' dirs + """ + + sitedirs = [] + + # start with PYTHONPATH + sitedirs.extend(_pythonpath()) + + prefixes = [sys.prefix] + if sys.exec_prefix != sys.prefix: + prefixes.append(sys.exec_prefix) + for prefix in prefixes: + if prefix: + if sys.platform in ('os2emx', 'riscos'): + sitedirs.append(os.path.join(prefix, "Lib", "site-packages")) + elif os.sep == '/': + sitedirs.extend([ + os.path.join( + prefix, + "local/lib", + "python" + sys.version[:3], + "dist-packages", + ), + os.path.join( + prefix, + "lib", + "python{}.{}".format(*sys.version_info), + "dist-packages", + ), + os.path.join(prefix, "lib", "site-python"), + ]) + else: + sitedirs.extend([ + prefix, + os.path.join(prefix, "lib", "site-packages"), + ]) + if sys.platform == 'darwin': + # for framework builds *only* we add the standard Apple + # locations. Currently only per-user, but /Library and + # /Network/Library could be added too + if 'Python.framework' in prefix: + home = os.environ.get('HOME') + if home: + home_sp = os.path.join( + home, + 'Library', + 'Python', + '{}.{}'.format(*sys.version_info), + 'site-packages', + ) + sitedirs.append(home_sp) + lib_paths = get_path('purelib'), get_path('platlib') + for site_lib in lib_paths: + if site_lib not in sitedirs: + sitedirs.append(site_lib) + + if site.ENABLE_USER_SITE: + sitedirs.append(site.USER_SITE) + + try: + sitedirs.extend(site.getsitepackages()) + except AttributeError: + pass + + sitedirs = list(map(normalize_path, sitedirs)) + + return sitedirs + + +def expand_paths(inputs): + """Yield sys.path directories that might contain "old-style" packages""" + + seen = {} + + for dirname in inputs: + dirname = normalize_path(dirname) + if dirname in seen: + continue + + seen[dirname] = 1 + if not os.path.isdir(dirname): + continue + + files = os.listdir(dirname) + yield dirname, files + + for name in files: + if not name.endswith('.pth'): + # We only care about the .pth files + continue + if name in ('easy-install.pth', 'setuptools.pth'): + # Ignore .pth files that we control + continue + + # Read the .pth file + f = open(os.path.join(dirname, name)) + lines = list(yield_lines(f)) + f.close() + + # Yield existing non-dupe, non-import directory lines from it + for line in lines: + if not line.startswith("import"): + line = normalize_path(line.rstrip()) + if line not in seen: + seen[line] = 1 + if not os.path.isdir(line): + continue + yield line, os.listdir(line) + + +def extract_wininst_cfg(dist_filename): + """Extract configuration data from a bdist_wininst .exe + + Returns a configparser.RawConfigParser, or None + """ + f = open(dist_filename, 'rb') + try: + endrec = zipfile._EndRecData(f) + if endrec is None: + return None + + prepended = (endrec[9] - endrec[5]) - endrec[6] + if prepended < 12: # no wininst data here + return None + f.seek(prepended - 12) + + tag, cfglen, bmlen = struct.unpack("<iii", f.read(12)) + if tag not in (0x1234567A, 0x1234567B): + return None # not a valid tag + + f.seek(prepended - (12 + cfglen)) + init = {'version': '', 'target_version': ''} + cfg = configparser.RawConfigParser(init) + try: + part = f.read(cfglen) + # Read up to the first null byte. + config = part.split(b'\0', 1)[0] + # Now the config is in bytes, but for RawConfigParser, it should + # be text, so decode it. + config = config.decode(sys.getfilesystemencoding()) + cfg.readfp(six.StringIO(config)) + except configparser.Error: + return None + if not cfg.has_section('metadata') or not cfg.has_section('Setup'): + return None + return cfg + + finally: + f.close() + + +def get_exe_prefixes(exe_filename): + """Get exe->egg path translations for a given .exe file""" + + prefixes = [ + ('PURELIB/', ''), + ('PLATLIB/pywin32_system32', ''), + ('PLATLIB/', ''), + ('SCRIPTS/', 'EGG-INFO/scripts/'), + ('DATA/lib/site-packages', ''), + ] + z = zipfile.ZipFile(exe_filename) + try: + for info in z.infolist(): + name = info.filename + parts = name.split('/') + if len(parts) == 3 and parts[2] == 'PKG-INFO': + if parts[1].endswith('.egg-info'): + prefixes.insert(0, ('/'.join(parts[:2]), 'EGG-INFO/')) + break + if len(parts) != 2 or not name.endswith('.pth'): + continue + if name.endswith('-nspkg.pth'): + continue + if parts[0].upper() in ('PURELIB', 'PLATLIB'): + contents = z.read(name) + if six.PY3: + contents = contents.decode() + for pth in yield_lines(contents): + pth = pth.strip().replace('\\', '/') + if not pth.startswith('import'): + prefixes.append((('%s/%s/' % (parts[0], pth)), '')) + finally: + z.close() + prefixes = [(x.lower(), y) for x, y in prefixes] + prefixes.sort() + prefixes.reverse() + return prefixes + + +class PthDistributions(Environment): + """A .pth file with Distribution paths in it""" + + dirty = False + + def __init__(self, filename, sitedirs=()): + self.filename = filename + self.sitedirs = list(map(normalize_path, sitedirs)) + self.basedir = normalize_path(os.path.dirname(self.filename)) + self._load() + Environment.__init__(self, [], None, None) + for path in yield_lines(self.paths): + list(map(self.add, find_distributions(path, True))) + + def _load(self): + self.paths = [] + saw_import = False + seen = dict.fromkeys(self.sitedirs) + if os.path.isfile(self.filename): + f = open(self.filename, 'rt') + for line in f: + if line.startswith('import'): + saw_import = True + continue + path = line.rstrip() + self.paths.append(path) + if not path.strip() or path.strip().startswith('#'): + continue + # skip non-existent paths, in case somebody deleted a package + # manually, and duplicate paths as well + path = self.paths[-1] = normalize_path( + os.path.join(self.basedir, path) + ) + if not os.path.exists(path) or path in seen: + self.paths.pop() # skip it + self.dirty = True # we cleaned up, so we're dirty now :) + continue + seen[path] = 1 + f.close() + + if self.paths and not saw_import: + self.dirty = True # ensure anything we touch has import wrappers + while self.paths and not self.paths[-1].strip(): + self.paths.pop() + + def save(self): + """Write changed .pth file back to disk""" + if not self.dirty: + return + + rel_paths = list(map(self.make_relative, self.paths)) + if rel_paths: + log.debug("Saving %s", self.filename) + lines = self._wrap_lines(rel_paths) + data = '\n'.join(lines) + '\n' + + if os.path.islink(self.filename): + os.unlink(self.filename) + with open(self.filename, 'wt') as f: + f.write(data) + + elif os.path.exists(self.filename): + log.debug("Deleting empty %s", self.filename) + os.unlink(self.filename) + + self.dirty = False + + @staticmethod + def _wrap_lines(lines): + return lines + + def add(self, dist): + """Add `dist` to the distribution map""" + new_path = ( + dist.location not in self.paths and ( + dist.location not in self.sitedirs or + # account for '.' being in PYTHONPATH + dist.location == os.getcwd() + ) + ) + if new_path: + self.paths.append(dist.location) + self.dirty = True + Environment.add(self, dist) + + def remove(self, dist): + """Remove `dist` from the distribution map""" + while dist.location in self.paths: + self.paths.remove(dist.location) + self.dirty = True + Environment.remove(self, dist) + + def make_relative(self, path): + npath, last = os.path.split(normalize_path(path)) + baselen = len(self.basedir) + parts = [last] + sep = os.altsep == '/' and '/' or os.sep + while len(npath) >= baselen: + if npath == self.basedir: + parts.append(os.curdir) + parts.reverse() + return sep.join(parts) + npath, last = os.path.split(npath) + parts.append(last) + else: + return path + + +class RewritePthDistributions(PthDistributions): + @classmethod + def _wrap_lines(cls, lines): + yield cls.prelude + for line in lines: + yield line + yield cls.postlude + + prelude = _one_liner(""" + import sys + sys.__plen = len(sys.path) + """) + postlude = _one_liner(""" + import sys + new = sys.path[sys.__plen:] + del sys.path[sys.__plen:] + p = getattr(sys, '__egginsert', 0) + sys.path[p:p] = new + sys.__egginsert = p + len(new) + """) + + +if os.environ.get('SETUPTOOLS_SYS_PATH_TECHNIQUE', 'raw') == 'rewrite': + PthDistributions = RewritePthDistributions + + +def _first_line_re(): + """ + Return a regular expression based on first_line_re suitable for matching + strings. + """ + if isinstance(first_line_re.pattern, str): + return first_line_re + + # first_line_re in Python >=3.1.4 and >=3.2.1 is a bytes pattern. + return re.compile(first_line_re.pattern.decode()) + + +def auto_chmod(func, arg, exc): + if func in [os.unlink, os.remove] and os.name == 'nt': + chmod(arg, stat.S_IWRITE) + return func(arg) + et, ev, _ = sys.exc_info() + six.reraise(et, (ev[0], ev[1] + (" %s %s" % (func, arg)))) + + +def update_dist_caches(dist_path, fix_zipimporter_caches): + """ + Fix any globally cached `dist_path` related data + + `dist_path` should be a path of a newly installed egg distribution (zipped + or unzipped). + + sys.path_importer_cache contains finder objects that have been cached when + importing data from the original distribution. Any such finders need to be + cleared since the replacement distribution might be packaged differently, + e.g. a zipped egg distribution might get replaced with an unzipped egg + folder or vice versa. Having the old finders cached may then cause Python + to attempt loading modules from the replacement distribution using an + incorrect loader. + + zipimport.zipimporter objects are Python loaders charged with importing + data packaged inside zip archives. If stale loaders referencing the + original distribution, are left behind, they can fail to load modules from + the replacement distribution. E.g. if an old zipimport.zipimporter instance + is used to load data from a new zipped egg archive, it may cause the + operation to attempt to locate the requested data in the wrong location - + one indicated by the original distribution's zip archive directory + information. Such an operation may then fail outright, e.g. report having + read a 'bad local file header', or even worse, it may fail silently & + return invalid data. + + zipimport._zip_directory_cache contains cached zip archive directory + information for all existing zipimport.zipimporter instances and all such + instances connected to the same archive share the same cached directory + information. + + If asked, and the underlying Python implementation allows it, we can fix + all existing zipimport.zipimporter instances instead of having to track + them down and remove them one by one, by updating their shared cached zip + archive directory information. This, of course, assumes that the + replacement distribution is packaged as a zipped egg. + + If not asked to fix existing zipimport.zipimporter instances, we still do + our best to clear any remaining zipimport.zipimporter related cached data + that might somehow later get used when attempting to load data from the new + distribution and thus cause such load operations to fail. Note that when + tracking down such remaining stale data, we can not catch every conceivable + usage from here, and we clear only those that we know of and have found to + cause problems if left alive. Any remaining caches should be updated by + whomever is in charge of maintaining them, i.e. they should be ready to + handle us replacing their zip archives with new distributions at runtime. + + """ + # There are several other known sources of stale zipimport.zipimporter + # instances that we do not clear here, but might if ever given a reason to + # do so: + # * Global setuptools pkg_resources.working_set (a.k.a. 'master working + # set') may contain distributions which may in turn contain their + # zipimport.zipimporter loaders. + # * Several zipimport.zipimporter loaders held by local variables further + # up the function call stack when running the setuptools installation. + # * Already loaded modules may have their __loader__ attribute set to the + # exact loader instance used when importing them. Python 3.4 docs state + # that this information is intended mostly for introspection and so is + # not expected to cause us problems. + normalized_path = normalize_path(dist_path) + _uncache(normalized_path, sys.path_importer_cache) + if fix_zipimporter_caches: + _replace_zip_directory_cache_data(normalized_path) + else: + # Here, even though we do not want to fix existing and now stale + # zipimporter cache information, we still want to remove it. Related to + # Python's zip archive directory information cache, we clear each of + # its stale entries in two phases: + # 1. Clear the entry so attempting to access zip archive information + # via any existing stale zipimport.zipimporter instances fails. + # 2. Remove the entry from the cache so any newly constructed + # zipimport.zipimporter instances do not end up using old stale + # zip archive directory information. + # This whole stale data removal step does not seem strictly necessary, + # but has been left in because it was done before we started replacing + # the zip archive directory information cache content if possible, and + # there are no relevant unit tests that we can depend on to tell us if + # this is really needed. + _remove_and_clear_zip_directory_cache_data(normalized_path) + + +def _collect_zipimporter_cache_entries(normalized_path, cache): + """ + Return zipimporter cache entry keys related to a given normalized path. + + Alternative path spellings (e.g. those using different character case or + those using alternative path separators) related to the same path are + included. Any sub-path entries are included as well, i.e. those + corresponding to zip archives embedded in other zip archives. + + """ + result = [] + prefix_len = len(normalized_path) + for p in cache: + np = normalize_path(p) + if (np.startswith(normalized_path) and + np[prefix_len:prefix_len + 1] in (os.sep, '')): + result.append(p) + return result + + +def _update_zipimporter_cache(normalized_path, cache, updater=None): + """ + Update zipimporter cache data for a given normalized path. + + Any sub-path entries are processed as well, i.e. those corresponding to zip + archives embedded in other zip archives. + + Given updater is a callable taking a cache entry key and the original entry + (after already removing the entry from the cache), and expected to update + the entry and possibly return a new one to be inserted in its place. + Returning None indicates that the entry should not be replaced with a new + one. If no updater is given, the cache entries are simply removed without + any additional processing, the same as if the updater simply returned None. + + """ + for p in _collect_zipimporter_cache_entries(normalized_path, cache): + # N.B. pypy's custom zipimport._zip_directory_cache implementation does + # not support the complete dict interface: + # * Does not support item assignment, thus not allowing this function + # to be used only for removing existing cache entries. + # * Does not support the dict.pop() method, forcing us to use the + # get/del patterns instead. For more detailed information see the + # following links: + # https://github.com/pypa/setuptools/issues/202#issuecomment-202913420 + # http://bit.ly/2h9itJX + old_entry = cache[p] + del cache[p] + new_entry = updater and updater(p, old_entry) + if new_entry is not None: + cache[p] = new_entry + + +def _uncache(normalized_path, cache): + _update_zipimporter_cache(normalized_path, cache) + + +def _remove_and_clear_zip_directory_cache_data(normalized_path): + def clear_and_remove_cached_zip_archive_directory_data(path, old_entry): + old_entry.clear() + + _update_zipimporter_cache( + normalized_path, zipimport._zip_directory_cache, + updater=clear_and_remove_cached_zip_archive_directory_data) + + +# PyPy Python implementation does not allow directly writing to the +# zipimport._zip_directory_cache and so prevents us from attempting to correct +# its content. The best we can do there is clear the problematic cache content +# and have PyPy repopulate it as needed. The downside is that if there are any +# stale zipimport.zipimporter instances laying around, attempting to use them +# will fail due to not having its zip archive directory information available +# instead of being automatically corrected to use the new correct zip archive +# directory information. +if '__pypy__' in sys.builtin_module_names: + _replace_zip_directory_cache_data = \ + _remove_and_clear_zip_directory_cache_data +else: + + def _replace_zip_directory_cache_data(normalized_path): + def replace_cached_zip_archive_directory_data(path, old_entry): + # N.B. In theory, we could load the zip directory information just + # once for all updated path spellings, and then copy it locally and + # update its contained path strings to contain the correct + # spelling, but that seems like a way too invasive move (this cache + # structure is not officially documented anywhere and could in + # theory change with new Python releases) for no significant + # benefit. + old_entry.clear() + zipimport.zipimporter(path) + old_entry.update(zipimport._zip_directory_cache[path]) + return old_entry + + _update_zipimporter_cache( + normalized_path, zipimport._zip_directory_cache, + updater=replace_cached_zip_archive_directory_data) + + +def is_python(text, filename='<string>'): + "Is this string a valid Python script?" + try: + compile(text, filename, 'exec') + except (SyntaxError, TypeError): + return False + else: + return True + + +def is_sh(executable): + """Determine if the specified executable is a .sh (contains a #! line)""" + try: + with io.open(executable, encoding='latin-1') as fp: + magic = fp.read(2) + except (OSError, IOError): + return executable + return magic == '#!' + + +def nt_quote_arg(arg): + """Quote a command line argument according to Windows parsing rules""" + return subprocess.list2cmdline([arg]) + + +def is_python_script(script_text, filename): + """Is this text, as a whole, a Python script? (as opposed to shell/bat/etc. + """ + if filename.endswith('.py') or filename.endswith('.pyw'): + return True # extension says it's Python + if is_python(script_text, filename): + return True # it's syntactically valid Python + if script_text.startswith('#!'): + # It begins with a '#!' line, so check if 'python' is in it somewhere + return 'python' in script_text.splitlines()[0].lower() + + return False # Not any Python I can recognize + + +try: + from os import chmod as _chmod +except ImportError: + # Jython compatibility + def _chmod(*args): + pass + + +def chmod(path, mode): + log.debug("changing mode of %s to %o", path, mode) + try: + _chmod(path, mode) + except os.error as e: + log.debug("chmod failed: %s", e) + + +class CommandSpec(list): + """ + A command spec for a #! header, specified as a list of arguments akin to + those passed to Popen. + """ + + options = [] + split_args = dict() + + @classmethod + def best(cls): + """ + Choose the best CommandSpec class based on environmental conditions. + """ + return cls + + @classmethod + def _sys_executable(cls): + _default = os.path.normpath(sys.executable) + return os.environ.get('__PYVENV_LAUNCHER__', _default) + + @classmethod + def from_param(cls, param): + """ + Construct a CommandSpec from a parameter to build_scripts, which may + be None. + """ + if isinstance(param, cls): + return param + if isinstance(param, list): + return cls(param) + if param is None: + return cls.from_environment() + # otherwise, assume it's a string. + return cls.from_string(param) + + @classmethod + def from_environment(cls): + return cls([cls._sys_executable()]) + + @classmethod + def from_string(cls, string): + """ + Construct a command spec from a simple string representing a command + line parseable by shlex.split. + """ + items = shlex.split(string, **cls.split_args) + return cls(items) + + def install_options(self, script_text): + self.options = shlex.split(self._extract_options(script_text)) + cmdline = subprocess.list2cmdline(self) + if not isascii(cmdline): + self.options[:0] = ['-x'] + + @staticmethod + def _extract_options(orig_script): + """ + Extract any options from the first line of the script. + """ + first = (orig_script + '\n').splitlines()[0] + match = _first_line_re().match(first) + options = match.group(1) or '' if match else '' + return options.strip() + + def as_header(self): + return self._render(self + list(self.options)) + + @staticmethod + def _strip_quotes(item): + _QUOTES = '"\'' + for q in _QUOTES: + if item.startswith(q) and item.endswith(q): + return item[1:-1] + return item + + @staticmethod + def _render(items): + cmdline = subprocess.list2cmdline( + CommandSpec._strip_quotes(item.strip()) for item in items) + return '#!' + cmdline + '\n' + + +# For pbr compat; will be removed in a future version. +sys_executable = CommandSpec._sys_executable() + + +class WindowsCommandSpec(CommandSpec): + split_args = dict(posix=False) + + +class ScriptWriter: + """ + Encapsulates behavior around writing entry point scripts for console and + gui apps. + """ + + template = textwrap.dedent(r""" + # EASY-INSTALL-ENTRY-SCRIPT: %(spec)r,%(group)r,%(name)r + __requires__ = %(spec)r + import re + import sys + from pkg_resources import load_entry_point + + if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit( + load_entry_point(%(spec)r, %(group)r, %(name)r)() + ) + """).lstrip() + + command_spec_class = CommandSpec + + @classmethod + def get_script_args(cls, dist, executable=None, wininst=False): + # for backward compatibility + warnings.warn("Use get_args", EasyInstallDeprecationWarning) + writer = (WindowsScriptWriter if wininst else ScriptWriter).best() + header = cls.get_script_header("", executable, wininst) + return writer.get_args(dist, header) + + @classmethod + def get_script_header(cls, script_text, executable=None, wininst=False): + # for backward compatibility + warnings.warn("Use get_header", EasyInstallDeprecationWarning, stacklevel=2) + if wininst: + executable = "python.exe" + return cls.get_header(script_text, executable) + + @classmethod + def get_args(cls, dist, header=None): + """ + Yield write_script() argument tuples for a distribution's + console_scripts and gui_scripts entry points. + """ + if header is None: + header = cls.get_header() + spec = str(dist.as_requirement()) + for type_ in 'console', 'gui': + group = type_ + '_scripts' + for name, ep in dist.get_entry_map(group).items(): + cls._ensure_safe_name(name) + script_text = cls.template % locals() + args = cls._get_script_args(type_, name, header, script_text) + for res in args: + yield res + + @staticmethod + def _ensure_safe_name(name): + """ + Prevent paths in *_scripts entry point names. + """ + has_path_sep = re.search(r'[\\/]', name) + if has_path_sep: + raise ValueError("Path separators not allowed in script names") + + @classmethod + def get_writer(cls, force_windows): + # for backward compatibility + warnings.warn("Use best", EasyInstallDeprecationWarning) + return WindowsScriptWriter.best() if force_windows else cls.best() + + @classmethod + def best(cls): + """ + Select the best ScriptWriter for this environment. + """ + if sys.platform == 'win32' or (os.name == 'java' and os._name == 'nt'): + return WindowsScriptWriter.best() + else: + return cls + + @classmethod + def _get_script_args(cls, type_, name, header, script_text): + # Simply write the stub with no extension. + yield (name, header + script_text) + + @classmethod + def get_header(cls, script_text="", executable=None): + """Create a #! line, getting options (if any) from script_text""" + cmd = cls.command_spec_class.best().from_param(executable) + cmd.install_options(script_text) + return cmd.as_header() + + +class WindowsScriptWriter(ScriptWriter): + command_spec_class = WindowsCommandSpec + + @classmethod + def get_writer(cls): + # for backward compatibility + warnings.warn("Use best", EasyInstallDeprecationWarning) + return cls.best() + + @classmethod + def best(cls): + """ + Select the best ScriptWriter suitable for Windows + """ + writer_lookup = dict( + executable=WindowsExecutableLauncherWriter, + natural=cls, + ) + # for compatibility, use the executable launcher by default + launcher = os.environ.get('SETUPTOOLS_LAUNCHER', 'executable') + return writer_lookup[launcher] + + @classmethod + def _get_script_args(cls, type_, name, header, script_text): + "For Windows, add a .py extension" + ext = dict(console='.pya', gui='.pyw')[type_] + if ext not in os.environ['PATHEXT'].lower().split(';'): + msg = ( + "{ext} not listed in PATHEXT; scripts will not be " + "recognized as executables." + ).format(**locals()) + warnings.warn(msg, UserWarning) + old = ['.pya', '.py', '-script.py', '.pyc', '.pyo', '.pyw', '.exe'] + old.remove(ext) + header = cls._adjust_header(type_, header) + blockers = [name + x for x in old] + yield name + ext, header + script_text, 't', blockers + + @classmethod + def _adjust_header(cls, type_, orig_header): + """ + Make sure 'pythonw' is used for gui and and 'python' is used for + console (regardless of what sys.executable is). + """ + pattern = 'pythonw.exe' + repl = 'python.exe' + if type_ == 'gui': + pattern, repl = repl, pattern + pattern_ob = re.compile(re.escape(pattern), re.IGNORECASE) + new_header = pattern_ob.sub(string=orig_header, repl=repl) + return new_header if cls._use_header(new_header) else orig_header + + @staticmethod + def _use_header(new_header): + """ + Should _adjust_header use the replaced header? + + On non-windows systems, always use. On + Windows systems, only use the replaced header if it resolves + to an executable on the system. + """ + clean_header = new_header[2:-1].strip('"') + return sys.platform != 'win32' or find_executable(clean_header) + + +class WindowsExecutableLauncherWriter(WindowsScriptWriter): + @classmethod + def _get_script_args(cls, type_, name, header, script_text): + """ + For Windows, add a .py extension and an .exe launcher + """ + if type_ == 'gui': + launcher_type = 'gui' + ext = '-script.pyw' + old = ['.pyw'] + else: + launcher_type = 'cli' + ext = '-script.py' + old = ['.py', '.pyc', '.pyo'] + hdr = cls._adjust_header(type_, header) + blockers = [name + x for x in old] + yield (name + ext, hdr + script_text, 't', blockers) + yield ( + name + '.exe', get_win_launcher(launcher_type), + 'b' # write in binary mode + ) + if not is_64bit(): + # install a manifest for the launcher to prevent Windows + # from detecting it as an installer (which it will for + # launchers like easy_install.exe). Consider only + # adding a manifest for launchers detected as installers. + # See Distribute #143 for details. + m_name = name + '.exe.manifest' + yield (m_name, load_launcher_manifest(name), 't') + + +# for backward-compatibility +get_script_args = ScriptWriter.get_script_args +get_script_header = ScriptWriter.get_script_header + + +def get_win_launcher(type): + """ + Load the Windows launcher (executable) suitable for launching a script. + + `type` should be either 'cli' or 'gui' + + Returns the executable as a byte string. + """ + launcher_fn = '%s.exe' % type + if is_64bit(): + launcher_fn = launcher_fn.replace(".", "-64.") + else: + launcher_fn = launcher_fn.replace(".", "-32.") + return resource_string('setuptools', launcher_fn) + + +def load_launcher_manifest(name): + manifest = pkg_resources.resource_string(__name__, 'launcher manifest.xml') + if six.PY2: + return manifest % vars() + else: + return manifest.decode('utf-8') % vars() + + +def rmtree(path, ignore_errors=False, onerror=auto_chmod): + return shutil.rmtree(path, ignore_errors, onerror) + + +def current_umask(): + tmp = os.umask(0o022) + os.umask(tmp) + return tmp + + +def bootstrap(): + # This function is called when setuptools*.egg is run using /bin/sh + import setuptools + + argv0 = os.path.dirname(setuptools.__path__[0]) + sys.argv[0] = argv0 + sys.argv.append(argv0) + main() + + +def main(argv=None, **kw): + from setuptools import setup + from setuptools.dist import Distribution + + class DistributionWithoutHelpCommands(Distribution): + common_usage = "" + + def _show_help(self, *args, **kw): + with _patch_usage(): + Distribution._show_help(self, *args, **kw) + + if argv is None: + argv = sys.argv[1:] + + with _patch_usage(): + setup( + script_args=['-q', 'easy_install', '-v'] + argv, + script_name=sys.argv[0] or 'easy_install', + distclass=DistributionWithoutHelpCommands, + **kw + ) + + +@contextlib.contextmanager +def _patch_usage(): + import distutils.core + USAGE = textwrap.dedent(""" + usage: %(script)s [options] requirement_or_url ... + or: %(script)s --help + """).lstrip() + + def gen_usage(script_name): + return USAGE % dict( + script=os.path.basename(script_name), + ) + + saved = distutils.core.gen_usage + distutils.core.gen_usage = gen_usage + try: + yield + finally: + distutils.core.gen_usage = saved + +class EasyInstallDeprecationWarning(SetuptoolsDeprecationWarning): + """Class for warning about deprecations in EasyInstall in SetupTools. Not ignored by default, unlike DeprecationWarning.""" + diff --git a/venv/lib/python3.8/site-packages/setuptools/command/egg_info.py b/venv/lib/python3.8/site-packages/setuptools/command/egg_info.py new file mode 100644 index 0000000..b767ef3 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/command/egg_info.py @@ -0,0 +1,717 @@ +"""setuptools.command.egg_info + +Create a distribution's .egg-info directory and contents""" + +from distutils.filelist import FileList as _FileList +from distutils.errors import DistutilsInternalError +from distutils.util import convert_path +from distutils import log +import distutils.errors +import distutils.filelist +import os +import re +import sys +import io +import warnings +import time +import collections + +from setuptools.extern import six +from setuptools.extern.six.moves import map + +from setuptools import Command +from setuptools.command.sdist import sdist +from setuptools.command.sdist import walk_revctrl +from setuptools.command.setopt import edit_config +from setuptools.command import bdist_egg +from pkg_resources import ( + parse_requirements, safe_name, parse_version, + safe_version, yield_lines, EntryPoint, iter_entry_points, to_filename) +import setuptools.unicode_utils as unicode_utils +from setuptools.glob import glob + +from setuptools.extern import packaging +from setuptools import SetuptoolsDeprecationWarning + +def translate_pattern(glob): + """ + Translate a file path glob like '*.txt' in to a regular expression. + This differs from fnmatch.translate which allows wildcards to match + directory separators. It also knows about '**/' which matches any number of + directories. + """ + pat = '' + + # This will split on '/' within [character classes]. This is deliberate. + chunks = glob.split(os.path.sep) + + sep = re.escape(os.sep) + valid_char = '[^%s]' % (sep,) + + for c, chunk in enumerate(chunks): + last_chunk = c == len(chunks) - 1 + + # Chunks that are a literal ** are globstars. They match anything. + if chunk == '**': + if last_chunk: + # Match anything if this is the last component + pat += '.*' + else: + # Match '(name/)*' + pat += '(?:%s+%s)*' % (valid_char, sep) + continue # Break here as the whole path component has been handled + + # Find any special characters in the remainder + i = 0 + chunk_len = len(chunk) + while i < chunk_len: + char = chunk[i] + if char == '*': + # Match any number of name characters + pat += valid_char + '*' + elif char == '?': + # Match a name character + pat += valid_char + elif char == '[': + # Character class + inner_i = i + 1 + # Skip initial !/] chars + if inner_i < chunk_len and chunk[inner_i] == '!': + inner_i = inner_i + 1 + if inner_i < chunk_len and chunk[inner_i] == ']': + inner_i = inner_i + 1 + + # Loop till the closing ] is found + while inner_i < chunk_len and chunk[inner_i] != ']': + inner_i = inner_i + 1 + + if inner_i >= chunk_len: + # Got to the end of the string without finding a closing ] + # Do not treat this as a matching group, but as a literal [ + pat += re.escape(char) + else: + # Grab the insides of the [brackets] + inner = chunk[i + 1:inner_i] + char_class = '' + + # Class negation + if inner[0] == '!': + char_class = '^' + inner = inner[1:] + + char_class += re.escape(inner) + pat += '[%s]' % (char_class,) + + # Skip to the end ] + i = inner_i + else: + pat += re.escape(char) + i += 1 + + # Join each chunk with the dir separator + if not last_chunk: + pat += sep + + pat += r'\Z' + return re.compile(pat, flags=re.MULTILINE|re.DOTALL) + + +class InfoCommon: + tag_build = None + tag_date = None + + @property + def name(self): + return safe_name(self.distribution.get_name()) + + def tagged_version(self): + version = self.distribution.get_version() + # egg_info may be called more than once for a distribution, + # in which case the version string already contains all tags. + if self.vtags and version.endswith(self.vtags): + return safe_version(version) + return safe_version(version + self.vtags) + + def tags(self): + version = '' + if self.tag_build: + version += self.tag_build + if self.tag_date: + version += time.strftime("-%Y%m%d") + return version + vtags = property(tags) + + +class egg_info(InfoCommon, Command): + description = "create a distribution's .egg-info directory" + + user_options = [ + ('egg-base=', 'e', "directory containing .egg-info directories" + " (default: top of the source tree)"), + ('tag-date', 'd', "Add date stamp (e.g. 20050528) to version number"), + ('tag-build=', 'b', "Specify explicit tag to add to version number"), + ('no-date', 'D', "Don't include date stamp [default]"), + ] + + boolean_options = ['tag-date'] + negative_opt = { + 'no-date': 'tag-date', + } + + def initialize_options(self): + self.egg_base = None + self.egg_name = None + self.egg_info = None + self.egg_version = None + self.broken_egg_info = False + + #################################### + # allow the 'tag_svn_revision' to be detected and + # set, supporting sdists built on older Setuptools. + @property + def tag_svn_revision(self): + pass + + @tag_svn_revision.setter + def tag_svn_revision(self, value): + pass + #################################### + + def save_version_info(self, filename): + """ + Materialize the value of date into the + build tag. Install build keys in a deterministic order + to avoid arbitrary reordering on subsequent builds. + """ + egg_info = collections.OrderedDict() + # follow the order these keys would have been added + # when PYTHONHASHSEED=0 + egg_info['tag_build'] = self.tags() + egg_info['tag_date'] = 0 + edit_config(filename, dict(egg_info=egg_info)) + + def finalize_options(self): + # Note: we need to capture the current value returned + # by `self.tagged_version()`, so we can later update + # `self.distribution.metadata.version` without + # repercussions. + self.egg_name = self.name + self.egg_version = self.tagged_version() + parsed_version = parse_version(self.egg_version) + + try: + is_version = isinstance(parsed_version, packaging.version.Version) + spec = ( + "%s==%s" if is_version else "%s===%s" + ) + list( + parse_requirements(spec % (self.egg_name, self.egg_version)) + ) + except ValueError: + raise distutils.errors.DistutilsOptionError( + "Invalid distribution name or version syntax: %s-%s" % + (self.egg_name, self.egg_version) + ) + + if self.egg_base is None: + dirs = self.distribution.package_dir + self.egg_base = (dirs or {}).get('', os.curdir) + + self.ensure_dirname('egg_base') + self.egg_info = to_filename(self.egg_name) + '.egg-info' + if self.egg_base != os.curdir: + self.egg_info = os.path.join(self.egg_base, self.egg_info) + if '-' in self.egg_name: + self.check_broken_egg_info() + + # Set package version for the benefit of dumber commands + # (e.g. sdist, bdist_wininst, etc.) + # + self.distribution.metadata.version = self.egg_version + + # If we bootstrapped around the lack of a PKG-INFO, as might be the + # case in a fresh checkout, make sure that any special tags get added + # to the version info + # + pd = self.distribution._patched_dist + if pd is not None and pd.key == self.egg_name.lower(): + pd._version = self.egg_version + pd._parsed_version = parse_version(self.egg_version) + self.distribution._patched_dist = None + + def write_or_delete_file(self, what, filename, data, force=False): + """Write `data` to `filename` or delete if empty + + If `data` is non-empty, this routine is the same as ``write_file()``. + If `data` is empty but not ``None``, this is the same as calling + ``delete_file(filename)`. If `data` is ``None``, then this is a no-op + unless `filename` exists, in which case a warning is issued about the + orphaned file (if `force` is false), or deleted (if `force` is true). + """ + if data: + self.write_file(what, filename, data) + elif os.path.exists(filename): + if data is None and not force: + log.warn( + "%s not set in setup(), but %s exists", what, filename + ) + return + else: + self.delete_file(filename) + + def write_file(self, what, filename, data): + """Write `data` to `filename` (if not a dry run) after announcing it + + `what` is used in a log message to identify what is being written + to the file. + """ + log.info("writing %s to %s", what, filename) + if six.PY3: + data = data.encode("utf-8") + if not self.dry_run: + f = open(filename, 'wb') + f.write(data) + f.close() + + def delete_file(self, filename): + """Delete `filename` (if not a dry run) after announcing it""" + log.info("deleting %s", filename) + if not self.dry_run: + os.unlink(filename) + + def run(self): + self.mkpath(self.egg_info) + os.utime(self.egg_info, None) + installer = self.distribution.fetch_build_egg + for ep in iter_entry_points('egg_info.writers'): + ep.require(installer=installer) + writer = ep.resolve() + writer(self, ep.name, os.path.join(self.egg_info, ep.name)) + + # Get rid of native_libs.txt if it was put there by older bdist_egg + nl = os.path.join(self.egg_info, "native_libs.txt") + if os.path.exists(nl): + self.delete_file(nl) + + self.find_sources() + + def find_sources(self): + """Generate SOURCES.txt manifest file""" + manifest_filename = os.path.join(self.egg_info, "SOURCES.txt") + mm = manifest_maker(self.distribution) + mm.manifest = manifest_filename + mm.run() + self.filelist = mm.filelist + + def check_broken_egg_info(self): + bei = self.egg_name + '.egg-info' + if self.egg_base != os.curdir: + bei = os.path.join(self.egg_base, bei) + if os.path.exists(bei): + log.warn( + "-" * 78 + '\n' + "Note: Your current .egg-info directory has a '-' in its name;" + '\nthis will not work correctly with "setup.py develop".\n\n' + 'Please rename %s to %s to correct this problem.\n' + '-' * 78, + bei, self.egg_info + ) + self.broken_egg_info = self.egg_info + self.egg_info = bei # make it work for now + + +class FileList(_FileList): + # Implementations of the various MANIFEST.in commands + + def process_template_line(self, line): + # Parse the line: split it up, make sure the right number of words + # is there, and return the relevant words. 'action' is always + # defined: it's the first word of the line. Which of the other + # three are defined depends on the action; it'll be either + # patterns, (dir and patterns), or (dir_pattern). + (action, patterns, dir, dir_pattern) = self._parse_template_line(line) + + # OK, now we know that the action is valid and we have the + # right number of words on the line for that action -- so we + # can proceed with minimal error-checking. + if action == 'include': + self.debug_print("include " + ' '.join(patterns)) + for pattern in patterns: + if not self.include(pattern): + log.warn("warning: no files found matching '%s'", pattern) + + elif action == 'exclude': + self.debug_print("exclude " + ' '.join(patterns)) + for pattern in patterns: + if not self.exclude(pattern): + log.warn(("warning: no previously-included files " + "found matching '%s'"), pattern) + + elif action == 'global-include': + self.debug_print("global-include " + ' '.join(patterns)) + for pattern in patterns: + if not self.global_include(pattern): + log.warn(("warning: no files found matching '%s' " + "anywhere in distribution"), pattern) + + elif action == 'global-exclude': + self.debug_print("global-exclude " + ' '.join(patterns)) + for pattern in patterns: + if not self.global_exclude(pattern): + log.warn(("warning: no previously-included files matching " + "'%s' found anywhere in distribution"), + pattern) + + elif action == 'recursive-include': + self.debug_print("recursive-include %s %s" % + (dir, ' '.join(patterns))) + for pattern in patterns: + if not self.recursive_include(dir, pattern): + log.warn(("warning: no files found matching '%s' " + "under directory '%s'"), + pattern, dir) + + elif action == 'recursive-exclude': + self.debug_print("recursive-exclude %s %s" % + (dir, ' '.join(patterns))) + for pattern in patterns: + if not self.recursive_exclude(dir, pattern): + log.warn(("warning: no previously-included files matching " + "'%s' found under directory '%s'"), + pattern, dir) + + elif action == 'graft': + self.debug_print("graft " + dir_pattern) + if not self.graft(dir_pattern): + log.warn("warning: no directories found matching '%s'", + dir_pattern) + + elif action == 'prune': + self.debug_print("prune " + dir_pattern) + if not self.prune(dir_pattern): + log.warn(("no previously-included directories found " + "matching '%s'"), dir_pattern) + + else: + raise DistutilsInternalError( + "this cannot happen: invalid action '%s'" % action) + + def _remove_files(self, predicate): + """ + Remove all files from the file list that match the predicate. + Return True if any matching files were removed + """ + found = False + for i in range(len(self.files) - 1, -1, -1): + if predicate(self.files[i]): + self.debug_print(" removing " + self.files[i]) + del self.files[i] + found = True + return found + + def include(self, pattern): + """Include files that match 'pattern'.""" + found = [f for f in glob(pattern) if not os.path.isdir(f)] + self.extend(found) + return bool(found) + + def exclude(self, pattern): + """Exclude files that match 'pattern'.""" + match = translate_pattern(pattern) + return self._remove_files(match.match) + + def recursive_include(self, dir, pattern): + """ + Include all files anywhere in 'dir/' that match the pattern. + """ + full_pattern = os.path.join(dir, '**', pattern) + found = [f for f in glob(full_pattern, recursive=True) + if not os.path.isdir(f)] + self.extend(found) + return bool(found) + + def recursive_exclude(self, dir, pattern): + """ + Exclude any file anywhere in 'dir/' that match the pattern. + """ + match = translate_pattern(os.path.join(dir, '**', pattern)) + return self._remove_files(match.match) + + def graft(self, dir): + """Include all files from 'dir/'.""" + found = [ + item + for match_dir in glob(dir) + for item in distutils.filelist.findall(match_dir) + ] + self.extend(found) + return bool(found) + + def prune(self, dir): + """Filter out files from 'dir/'.""" + match = translate_pattern(os.path.join(dir, '**')) + return self._remove_files(match.match) + + def global_include(self, pattern): + """ + Include all files anywhere in the current directory that match the + pattern. This is very inefficient on large file trees. + """ + if self.allfiles is None: + self.findall() + match = translate_pattern(os.path.join('**', pattern)) + found = [f for f in self.allfiles if match.match(f)] + self.extend(found) + return bool(found) + + def global_exclude(self, pattern): + """ + Exclude all files anywhere that match the pattern. + """ + match = translate_pattern(os.path.join('**', pattern)) + return self._remove_files(match.match) + + def append(self, item): + if item.endswith('\r'): # Fix older sdists built on Windows + item = item[:-1] + path = convert_path(item) + + if self._safe_path(path): + self.files.append(path) + + def extend(self, paths): + self.files.extend(filter(self._safe_path, paths)) + + def _repair(self): + """ + Replace self.files with only safe paths + + Because some owners of FileList manipulate the underlying + ``files`` attribute directly, this method must be called to + repair those paths. + """ + self.files = list(filter(self._safe_path, self.files)) + + def _safe_path(self, path): + enc_warn = "'%s' not %s encodable -- skipping" + + # To avoid accidental trans-codings errors, first to unicode + u_path = unicode_utils.filesys_decode(path) + if u_path is None: + log.warn("'%s' in unexpected encoding -- skipping" % path) + return False + + # Must ensure utf-8 encodability + utf8_path = unicode_utils.try_encode(u_path, "utf-8") + if utf8_path is None: + log.warn(enc_warn, path, 'utf-8') + return False + + try: + # accept is either way checks out + if os.path.exists(u_path) or os.path.exists(utf8_path): + return True + # this will catch any encode errors decoding u_path + except UnicodeEncodeError: + log.warn(enc_warn, path, sys.getfilesystemencoding()) + + +class manifest_maker(sdist): + template = "MANIFEST.in" + + def initialize_options(self): + self.use_defaults = 1 + self.prune = 1 + self.manifest_only = 1 + self.force_manifest = 1 + + def finalize_options(self): + pass + + def run(self): + self.filelist = FileList() + if not os.path.exists(self.manifest): + self.write_manifest() # it must exist so it'll get in the list + self.add_defaults() + if os.path.exists(self.template): + self.read_template() + self.prune_file_list() + self.filelist.sort() + self.filelist.remove_duplicates() + self.write_manifest() + + def _manifest_normalize(self, path): + path = unicode_utils.filesys_decode(path) + return path.replace(os.sep, '/') + + def write_manifest(self): + """ + Write the file list in 'self.filelist' to the manifest file + named by 'self.manifest'. + """ + self.filelist._repair() + + # Now _repairs should encodability, but not unicode + files = [self._manifest_normalize(f) for f in self.filelist.files] + msg = "writing manifest file '%s'" % self.manifest + self.execute(write_file, (self.manifest, files), msg) + + def warn(self, msg): + if not self._should_suppress_warning(msg): + sdist.warn(self, msg) + + @staticmethod + def _should_suppress_warning(msg): + """ + suppress missing-file warnings from sdist + """ + return re.match(r"standard file .*not found", msg) + + def add_defaults(self): + sdist.add_defaults(self) + self.check_license() + self.filelist.append(self.template) + self.filelist.append(self.manifest) + rcfiles = list(walk_revctrl()) + if rcfiles: + self.filelist.extend(rcfiles) + elif os.path.exists(self.manifest): + self.read_manifest() + + if os.path.exists("setup.py"): + # setup.py should be included by default, even if it's not + # the script called to create the sdist + self.filelist.append("setup.py") + + ei_cmd = self.get_finalized_command('egg_info') + self.filelist.graft(ei_cmd.egg_info) + + def prune_file_list(self): + build = self.get_finalized_command('build') + base_dir = self.distribution.get_fullname() + self.filelist.prune(build.build_base) + self.filelist.prune(base_dir) + sep = re.escape(os.sep) + self.filelist.exclude_pattern(r'(^|' + sep + r')(RCS|CVS|\.svn)' + sep, + is_regex=1) + + +def write_file(filename, contents): + """Create a file with the specified name and write 'contents' (a + sequence of strings without line terminators) to it. + """ + contents = "\n".join(contents) + + # assuming the contents has been vetted for utf-8 encoding + contents = contents.encode("utf-8") + + with open(filename, "wb") as f: # always write POSIX-style manifest + f.write(contents) + + +def write_pkg_info(cmd, basename, filename): + log.info("writing %s", filename) + if not cmd.dry_run: + metadata = cmd.distribution.metadata + metadata.version, oldver = cmd.egg_version, metadata.version + metadata.name, oldname = cmd.egg_name, metadata.name + + try: + # write unescaped data to PKG-INFO, so older pkg_resources + # can still parse it + metadata.write_pkg_info(cmd.egg_info) + finally: + metadata.name, metadata.version = oldname, oldver + + safe = getattr(cmd.distribution, 'zip_safe', None) + + bdist_egg.write_safety_flag(cmd.egg_info, safe) + + +def warn_depends_obsolete(cmd, basename, filename): + if os.path.exists(filename): + log.warn( + "WARNING: 'depends.txt' is not used by setuptools 0.6!\n" + "Use the install_requires/extras_require setup() args instead." + ) + + +def _write_requirements(stream, reqs): + lines = yield_lines(reqs or ()) + append_cr = lambda line: line + '\n' + lines = map(append_cr, sorted(lines)) + stream.writelines(lines) + + +def write_requirements(cmd, basename, filename): + dist = cmd.distribution + data = six.StringIO() + _write_requirements(data, dist.install_requires) + extras_require = dist.extras_require or {} + for extra in sorted(extras_require): + data.write('\n[{extra}]\n'.format(**vars())) + _write_requirements(data, extras_require[extra]) + cmd.write_or_delete_file("requirements", filename, data.getvalue()) + + +def write_setup_requirements(cmd, basename, filename): + data = io.StringIO() + _write_requirements(data, cmd.distribution.setup_requires) + cmd.write_or_delete_file("setup-requirements", filename, data.getvalue()) + + +def write_toplevel_names(cmd, basename, filename): + pkgs = dict.fromkeys( + [ + k.split('.', 1)[0] + for k in cmd.distribution.iter_distribution_names() + ] + ) + cmd.write_file("top-level names", filename, '\n'.join(sorted(pkgs)) + '\n') + + +def overwrite_arg(cmd, basename, filename): + write_arg(cmd, basename, filename, True) + + +def write_arg(cmd, basename, filename, force=False): + argname = os.path.splitext(basename)[0] + value = getattr(cmd.distribution, argname, None) + if value is not None: + value = '\n'.join(value) + '\n' + cmd.write_or_delete_file(argname, filename, value, force) + + +def write_entries(cmd, basename, filename): + ep = cmd.distribution.entry_points + + if isinstance(ep, six.string_types) or ep is None: + data = ep + elif ep is not None: + data = [] + for section, contents in sorted(ep.items()): + if not isinstance(contents, six.string_types): + contents = EntryPoint.parse_group(section, contents) + contents = '\n'.join(sorted(map(str, contents.values()))) + data.append('[%s]\n%s\n\n' % (section, contents)) + data = ''.join(data) + + cmd.write_or_delete_file('entry points', filename, data, True) + + +def get_pkg_info_revision(): + """ + Get a -r### off of PKG-INFO Version in case this is an sdist of + a subversion revision. + """ + warnings.warn("get_pkg_info_revision is deprecated.", EggInfoDeprecationWarning) + if os.path.exists('PKG-INFO'): + with io.open('PKG-INFO') as f: + for line in f: + match = re.match(r"Version:.*-r(\d+)\s*$", line) + if match: + return int(match.group(1)) + return 0 + + +class EggInfoDeprecationWarning(SetuptoolsDeprecationWarning): + """Class for warning about deprecations in eggInfo in setupTools. Not ignored by default, unlike DeprecationWarning.""" diff --git a/venv/lib/python3.8/site-packages/setuptools/command/install.py b/venv/lib/python3.8/site-packages/setuptools/command/install.py new file mode 100644 index 0000000..72b9a3e --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/command/install.py @@ -0,0 +1,125 @@ +from distutils.errors import DistutilsArgError +import inspect +import glob +import warnings +import platform +import distutils.command.install as orig + +import setuptools + +# Prior to numpy 1.9, NumPy relies on the '_install' name, so provide it for +# now. See https://github.com/pypa/setuptools/issues/199/ +_install = orig.install + + +class install(orig.install): + """Use easy_install to install the package, w/dependencies""" + + user_options = orig.install.user_options + [ + ('old-and-unmanageable', None, "Try not to use this!"), + ('single-version-externally-managed', None, + "used by system package builders to create 'flat' eggs"), + ] + boolean_options = orig.install.boolean_options + [ + 'old-and-unmanageable', 'single-version-externally-managed', + ] + new_commands = [ + ('install_egg_info', lambda self: True), + ('install_scripts', lambda self: True), + ] + _nc = dict(new_commands) + + def initialize_options(self): + orig.install.initialize_options(self) + self.old_and_unmanageable = None + self.single_version_externally_managed = None + + def finalize_options(self): + orig.install.finalize_options(self) + if self.root: + self.single_version_externally_managed = True + elif self.single_version_externally_managed: + if not self.root and not self.record: + raise DistutilsArgError( + "You must specify --record or --root when building system" + " packages" + ) + + def handle_extra_path(self): + if self.root or self.single_version_externally_managed: + # explicit backward-compatibility mode, allow extra_path to work + return orig.install.handle_extra_path(self) + + # Ignore extra_path when installing an egg (or being run by another + # command without --root or --single-version-externally-managed + self.path_file = None + self.extra_dirs = '' + + def run(self): + # Explicit request for old-style install? Just do it + if self.old_and_unmanageable or self.single_version_externally_managed: + return orig.install.run(self) + + if not self._called_from_setup(inspect.currentframe()): + # Run in backward-compatibility mode to support bdist_* commands. + orig.install.run(self) + else: + self.do_egg_install() + + @staticmethod + def _called_from_setup(run_frame): + """ + Attempt to detect whether run() was called from setup() or by another + command. If called by setup(), the parent caller will be the + 'run_command' method in 'distutils.dist', and *its* caller will be + the 'run_commands' method. If called any other way, the + immediate caller *might* be 'run_command', but it won't have been + called by 'run_commands'. Return True in that case or if a call stack + is unavailable. Return False otherwise. + """ + if run_frame is None: + msg = "Call stack not available. bdist_* commands may fail." + warnings.warn(msg) + if platform.python_implementation() == 'IronPython': + msg = "For best results, pass -X:Frames to enable call stack." + warnings.warn(msg) + return True + res = inspect.getouterframes(run_frame)[2] + caller, = res[:1] + info = inspect.getframeinfo(caller) + caller_module = caller.f_globals.get('__name__', '') + return ( + caller_module == 'distutils.dist' + and info.function == 'run_commands' + ) + + def do_egg_install(self): + + easy_install = self.distribution.get_command_class('easy_install') + + cmd = easy_install( + self.distribution, args="x", root=self.root, record=self.record, + ) + cmd.ensure_finalized() # finalize before bdist_egg munges install cmd + cmd.always_copy_from = '.' # make sure local-dir eggs get installed + + # pick up setup-dir .egg files only: no .egg-info + cmd.package_index.scan(glob.glob('*.egg')) + + self.run_command('bdist_egg') + args = [self.distribution.get_command_obj('bdist_egg').egg_output] + + if setuptools.bootstrap_install_from: + # Bootstrap self-installation of setuptools + args.insert(0, setuptools.bootstrap_install_from) + + cmd.args = args + cmd.run(show_deprecation=False) + setuptools.bootstrap_install_from = None + + +# XXX Python 3.1 doesn't see _nc if this is inside the class +install.sub_commands = ( + [cmd for cmd in orig.install.sub_commands if cmd[0] not in install._nc] + + install.new_commands +) diff --git a/venv/lib/python3.8/site-packages/setuptools/command/install_egg_info.py b/venv/lib/python3.8/site-packages/setuptools/command/install_egg_info.py new file mode 100644 index 0000000..5f405bc --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/command/install_egg_info.py @@ -0,0 +1,82 @@ +from distutils import log, dir_util +import os, sys + +from setuptools import Command +from setuptools import namespaces +from setuptools.archive_util import unpack_archive +import pkg_resources + + +class install_egg_info(namespaces.Installer, Command): + """Install an .egg-info directory for the package""" + + description = "Install an .egg-info directory for the package" + + user_options = [ + ('install-dir=', 'd', "directory to install to"), + ] + + def initialize_options(self): + self.install_dir = None + self.install_layout = None + self.prefix_option = None + + def finalize_options(self): + self.set_undefined_options('install_lib', + ('install_dir', 'install_dir')) + self.set_undefined_options('install',('install_layout','install_layout')) + if sys.hexversion > 0x2060000: + self.set_undefined_options('install',('prefix_option','prefix_option')) + ei_cmd = self.get_finalized_command("egg_info") + basename = pkg_resources.Distribution( + None, None, ei_cmd.egg_name, ei_cmd.egg_version + ).egg_name() + '.egg-info' + + if self.install_layout: + if not self.install_layout.lower() in ['deb']: + raise DistutilsOptionError("unknown value for --install-layout") + self.install_layout = self.install_layout.lower() + basename = basename.replace('-py%s' % pkg_resources.PY_MAJOR, '') + elif self.prefix_option or 'real_prefix' in sys.__dict__: + # don't modify for virtualenv + pass + else: + basename = basename.replace('-py%s' % pkg_resources.PY_MAJOR, '') + + self.source = ei_cmd.egg_info + self.target = os.path.join(self.install_dir, basename) + self.outputs = [] + + def run(self): + self.run_command('egg_info') + if os.path.isdir(self.target) and not os.path.islink(self.target): + dir_util.remove_tree(self.target, dry_run=self.dry_run) + elif os.path.exists(self.target): + self.execute(os.unlink, (self.target,), "Removing " + self.target) + if not self.dry_run: + pkg_resources.ensure_directory(self.target) + self.execute( + self.copytree, (), "Copying %s to %s" % (self.source, self.target) + ) + self.install_namespaces() + + def get_outputs(self): + return self.outputs + + def copytree(self): + # Copy the .egg-info tree to site-packages + def skimmer(src, dst): + # filter out source-control directories; note that 'src' is always + # a '/'-separated path, regardless of platform. 'dst' is a + # platform-specific path. + for skip in '.svn/', 'CVS/': + if src.startswith(skip) or '/' + skip in src: + return None + if self.install_layout and self.install_layout in ['deb'] and src.startswith('SOURCES.txt'): + log.info("Skipping SOURCES.txt") + return None + self.outputs.append(dst) + log.debug("Copying %s to %s", src, dst) + return dst + + unpack_archive(self.source, self.target, skimmer) diff --git a/venv/lib/python3.8/site-packages/setuptools/command/install_lib.py b/venv/lib/python3.8/site-packages/setuptools/command/install_lib.py new file mode 100644 index 0000000..bf81519 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/command/install_lib.py @@ -0,0 +1,147 @@ +import os +import sys +from itertools import product, starmap +import distutils.command.install_lib as orig + + +class install_lib(orig.install_lib): + """Don't add compiled flags to filenames of non-Python files""" + + def initialize_options(self): + orig.install_lib.initialize_options(self) + self.multiarch = None + self.install_layout = None + + def finalize_options(self): + orig.install_lib.finalize_options(self) + self.set_undefined_options('install',('install_layout','install_layout')) + if self.install_layout == 'deb' and sys.version_info[:2] >= (3, 3): + import sysconfig + self.multiarch = sysconfig.get_config_var('MULTIARCH') + + def run(self): + self.build() + outfiles = self.install() + if outfiles is not None: + # always compile, in case we have any extension stubs to deal with + self.byte_compile(outfiles) + + def get_exclusions(self): + """ + Return a collections.Sized collections.Container of paths to be + excluded for single_version_externally_managed installations. + """ + all_packages = ( + pkg + for ns_pkg in self._get_SVEM_NSPs() + for pkg in self._all_packages(ns_pkg) + ) + + excl_specs = product(all_packages, self._gen_exclusion_paths()) + return set(starmap(self._exclude_pkg_path, excl_specs)) + + def _exclude_pkg_path(self, pkg, exclusion_path): + """ + Given a package name and exclusion path within that package, + compute the full exclusion path. + """ + parts = pkg.split('.') + [exclusion_path] + return os.path.join(self.install_dir, *parts) + + @staticmethod + def _all_packages(pkg_name): + """ + >>> list(install_lib._all_packages('foo.bar.baz')) + ['foo.bar.baz', 'foo.bar', 'foo'] + """ + while pkg_name: + yield pkg_name + pkg_name, sep, child = pkg_name.rpartition('.') + + def _get_SVEM_NSPs(self): + """ + Get namespace packages (list) but only for + single_version_externally_managed installations and empty otherwise. + """ + # TODO: is it necessary to short-circuit here? i.e. what's the cost + # if get_finalized_command is called even when namespace_packages is + # False? + if not self.distribution.namespace_packages: + return [] + + install_cmd = self.get_finalized_command('install') + svem = install_cmd.single_version_externally_managed + + return self.distribution.namespace_packages if svem else [] + + @staticmethod + def _gen_exclusion_paths(): + """ + Generate file paths to be excluded for namespace packages (bytecode + cache files). + """ + # always exclude the package module itself + yield '__init__.py' + + yield '__init__.pyc' + yield '__init__.pyo' + + if not hasattr(sys, 'implementation'): + return + + base = os.path.join('__pycache__', '__init__.' + sys.implementation.cache_tag) + yield base + '.pyc' + yield base + '.pyo' + yield base + '.opt-1.pyc' + yield base + '.opt-2.pyc' + + def copy_tree( + self, infile, outfile, + preserve_mode=1, preserve_times=1, preserve_symlinks=0, level=1 + ): + assert preserve_mode and preserve_times and not preserve_symlinks + exclude = self.get_exclusions() + + if not exclude: + import distutils.dir_util + distutils.dir_util._multiarch = self.multiarch + return orig.install_lib.copy_tree(self, infile, outfile) + + # Exclude namespace package __init__.py* files from the output + + from setuptools.archive_util import unpack_directory + from distutils import log + + outfiles = [] + + if self.multiarch: + import sysconfig + ext_suffix = sysconfig.get_config_var ('EXT_SUFFIX') + if ext_suffix.endswith(self.multiarch + ext_suffix[-3:]): + new_suffix = None + else: + new_suffix = "%s-%s%s" % (ext_suffix[:-3], self.multiarch, ext_suffix[-3:]) + + def pf(src, dst): + if dst in exclude: + log.warn("Skipping installation of %s (namespace package)", + dst) + return False + + if self.multiarch and new_suffix and dst.endswith(ext_suffix) and not dst.endswith(new_suffix): + dst = dst.replace(ext_suffix, new_suffix) + log.info("renaming extension to %s", os.path.basename(dst)) + + log.info("copying %s -> %s", src, os.path.dirname(dst)) + outfiles.append(dst) + return dst + + unpack_directory(infile, outfile, pf) + return outfiles + + def get_outputs(self): + outputs = orig.install_lib.get_outputs(self) + exclude = self.get_exclusions() + if exclude: + return [f for f in outputs if f not in exclude] + return outputs diff --git a/venv/lib/python3.8/site-packages/setuptools/command/install_scripts.py b/venv/lib/python3.8/site-packages/setuptools/command/install_scripts.py new file mode 100644 index 0000000..1623427 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/command/install_scripts.py @@ -0,0 +1,65 @@ +from distutils import log +import distutils.command.install_scripts as orig +import os +import sys + +from pkg_resources import Distribution, PathMetadata, ensure_directory + + +class install_scripts(orig.install_scripts): + """Do normal script install, plus any egg_info wrapper scripts""" + + def initialize_options(self): + orig.install_scripts.initialize_options(self) + self.no_ep = False + + def run(self): + import setuptools.command.easy_install as ei + + self.run_command("egg_info") + if self.distribution.scripts: + orig.install_scripts.run(self) # run first to set up self.outfiles + else: + self.outfiles = [] + if self.no_ep: + # don't install entry point scripts into .egg file! + return + + ei_cmd = self.get_finalized_command("egg_info") + dist = Distribution( + ei_cmd.egg_base, PathMetadata(ei_cmd.egg_base, ei_cmd.egg_info), + ei_cmd.egg_name, ei_cmd.egg_version, + ) + bs_cmd = self.get_finalized_command('build_scripts') + exec_param = getattr(bs_cmd, 'executable', None) + bw_cmd = self.get_finalized_command("bdist_wininst") + is_wininst = getattr(bw_cmd, '_is_running', False) + writer = ei.ScriptWriter + if is_wininst: + exec_param = "python.exe" + writer = ei.WindowsScriptWriter + if exec_param == sys.executable: + # In case the path to the Python executable contains a space, wrap + # it so it's not split up. + exec_param = [exec_param] + # resolve the writer to the environment + writer = writer.best() + cmd = writer.command_spec_class.best().from_param(exec_param) + for args in writer.get_args(dist, cmd.as_header()): + self.write_script(*args) + + def write_script(self, script_name, contents, mode="t", *ignored): + """Write an executable file to the scripts directory""" + from setuptools.command.easy_install import chmod, current_umask + + log.info("Installing %s script to %s", script_name, self.install_dir) + target = os.path.join(self.install_dir, script_name) + self.outfiles.append(target) + + mask = current_umask() + if not self.dry_run: + ensure_directory(target) + f = open(target, "w" + mode) + f.write(contents) + f.close() + chmod(target, 0o777 - mask) diff --git a/venv/lib/python3.8/site-packages/setuptools/command/launcher manifest.xml b/venv/lib/python3.8/site-packages/setuptools/command/launcher manifest.xml new file mode 100644 index 0000000..5972a96 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/command/launcher manifest.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> + <assemblyIdentity version="1.0.0.0" + processorArchitecture="X86" + name="%(name)s" + type="win32"/> + <!-- Identify the application security requirements. --> + <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> + <security> + <requestedPrivileges> + <requestedExecutionLevel level="asInvoker" uiAccess="false"/> + </requestedPrivileges> + </security> + </trustInfo> +</assembly> diff --git a/venv/lib/python3.8/site-packages/setuptools/command/py36compat.py b/venv/lib/python3.8/site-packages/setuptools/command/py36compat.py new file mode 100644 index 0000000..61063e7 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/command/py36compat.py @@ -0,0 +1,136 @@ +import os +from glob import glob +from distutils.util import convert_path +from distutils.command import sdist + +from setuptools.extern.six.moves import filter + + +class sdist_add_defaults: + """ + Mix-in providing forward-compatibility for functionality as found in + distutils on Python 3.7. + + Do not edit the code in this class except to update functionality + as implemented in distutils. Instead, override in the subclass. + """ + + def add_defaults(self): + """Add all the default files to self.filelist: + - README or README.txt + - setup.py + - test/test*.py + - all pure Python modules mentioned in setup script + - all files pointed by package_data (build_py) + - all files defined in data_files. + - all files defined as scripts. + - all C sources listed as part of extensions or C libraries + in the setup script (doesn't catch C headers!) + Warns if (README or README.txt) or setup.py are missing; everything + else is optional. + """ + self._add_defaults_standards() + self._add_defaults_optional() + self._add_defaults_python() + self._add_defaults_data_files() + self._add_defaults_ext() + self._add_defaults_c_libs() + self._add_defaults_scripts() + + @staticmethod + def _cs_path_exists(fspath): + """ + Case-sensitive path existence check + + >>> sdist_add_defaults._cs_path_exists(__file__) + True + >>> sdist_add_defaults._cs_path_exists(__file__.upper()) + False + """ + if not os.path.exists(fspath): + return False + # make absolute so we always have a directory + abspath = os.path.abspath(fspath) + directory, filename = os.path.split(abspath) + return filename in os.listdir(directory) + + def _add_defaults_standards(self): + standards = [self.READMES, self.distribution.script_name] + for fn in standards: + if isinstance(fn, tuple): + alts = fn + got_it = False + for fn in alts: + if self._cs_path_exists(fn): + got_it = True + self.filelist.append(fn) + break + + if not got_it: + self.warn("standard file not found: should have one of " + + ', '.join(alts)) + else: + if self._cs_path_exists(fn): + self.filelist.append(fn) + else: + self.warn("standard file '%s' not found" % fn) + + def _add_defaults_optional(self): + optional = ['test/test*.py', 'setup.cfg'] + for pattern in optional: + files = filter(os.path.isfile, glob(pattern)) + self.filelist.extend(files) + + def _add_defaults_python(self): + # build_py is used to get: + # - python modules + # - files defined in package_data + build_py = self.get_finalized_command('build_py') + + # getting python files + if self.distribution.has_pure_modules(): + self.filelist.extend(build_py.get_source_files()) + + # getting package_data files + # (computed in build_py.data_files by build_py.finalize_options) + for pkg, src_dir, build_dir, filenames in build_py.data_files: + for filename in filenames: + self.filelist.append(os.path.join(src_dir, filename)) + + def _add_defaults_data_files(self): + # getting distribution.data_files + if self.distribution.has_data_files(): + for item in self.distribution.data_files: + if isinstance(item, str): + # plain file + item = convert_path(item) + if os.path.isfile(item): + self.filelist.append(item) + else: + # a (dirname, filenames) tuple + dirname, filenames = item + for f in filenames: + f = convert_path(f) + if os.path.isfile(f): + self.filelist.append(f) + + def _add_defaults_ext(self): + if self.distribution.has_ext_modules(): + build_ext = self.get_finalized_command('build_ext') + self.filelist.extend(build_ext.get_source_files()) + + def _add_defaults_c_libs(self): + if self.distribution.has_c_libraries(): + build_clib = self.get_finalized_command('build_clib') + self.filelist.extend(build_clib.get_source_files()) + + def _add_defaults_scripts(self): + if self.distribution.has_scripts(): + build_scripts = self.get_finalized_command('build_scripts') + self.filelist.extend(build_scripts.get_source_files()) + + +if hasattr(sdist.sdist, '_add_defaults_standards'): + # disable the functionality already available upstream + class sdist_add_defaults: + pass diff --git a/venv/lib/python3.8/site-packages/setuptools/command/register.py b/venv/lib/python3.8/site-packages/setuptools/command/register.py new file mode 100644 index 0000000..b8266b9 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/command/register.py @@ -0,0 +1,18 @@ +from distutils import log +import distutils.command.register as orig + +from setuptools.errors import RemovedCommandError + + +class register(orig.register): + """Formerly used to register packages on PyPI.""" + + def run(self): + msg = ( + "The register command has been removed, use twine to upload " + + "instead (https://pypi.org/p/twine)" + ) + + self.announce("ERROR: " + msg, log.ERROR) + + raise RemovedCommandError(msg) diff --git a/venv/lib/python3.8/site-packages/setuptools/command/rotate.py b/venv/lib/python3.8/site-packages/setuptools/command/rotate.py new file mode 100644 index 0000000..b89353f --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/command/rotate.py @@ -0,0 +1,66 @@ +from distutils.util import convert_path +from distutils import log +from distutils.errors import DistutilsOptionError +import os +import shutil + +from setuptools.extern import six + +from setuptools import Command + + +class rotate(Command): + """Delete older distributions""" + + description = "delete older distributions, keeping N newest files" + user_options = [ + ('match=', 'm', "patterns to match (required)"), + ('dist-dir=', 'd', "directory where the distributions are"), + ('keep=', 'k', "number of matching distributions to keep"), + ] + + boolean_options = [] + + def initialize_options(self): + self.match = None + self.dist_dir = None + self.keep = None + + def finalize_options(self): + if self.match is None: + raise DistutilsOptionError( + "Must specify one or more (comma-separated) match patterns " + "(e.g. '.zip' or '.egg')" + ) + if self.keep is None: + raise DistutilsOptionError("Must specify number of files to keep") + try: + self.keep = int(self.keep) + except ValueError: + raise DistutilsOptionError("--keep must be an integer") + if isinstance(self.match, six.string_types): + self.match = [ + convert_path(p.strip()) for p in self.match.split(',') + ] + self.set_undefined_options('bdist', ('dist_dir', 'dist_dir')) + + def run(self): + self.run_command("egg_info") + from glob import glob + + for pattern in self.match: + pattern = self.distribution.get_name() + '*' + pattern + files = glob(os.path.join(self.dist_dir, pattern)) + files = [(os.path.getmtime(f), f) for f in files] + files.sort() + files.reverse() + + log.info("%d file(s) matching %s", len(files), pattern) + files = files[self.keep:] + for (t, f) in files: + log.info("Deleting %s", f) + if not self.dry_run: + if os.path.isdir(f): + shutil.rmtree(f) + else: + os.unlink(f) diff --git a/venv/lib/python3.8/site-packages/setuptools/command/saveopts.py b/venv/lib/python3.8/site-packages/setuptools/command/saveopts.py new file mode 100644 index 0000000..611cec5 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/command/saveopts.py @@ -0,0 +1,22 @@ +from setuptools.command.setopt import edit_config, option_base + + +class saveopts(option_base): + """Save command-line options to a file""" + + description = "save supplied options to setup.cfg or other config file" + + def run(self): + dist = self.distribution + settings = {} + + for cmd in dist.command_options: + + if cmd == 'saveopts': + continue # don't save our own options! + + for opt, (src, val) in dist.get_option_dict(cmd).items(): + if src == "command line": + settings.setdefault(cmd, {})[opt] = val + + edit_config(self.filename, settings, self.dry_run) diff --git a/venv/lib/python3.8/site-packages/setuptools/command/sdist.py b/venv/lib/python3.8/site-packages/setuptools/command/sdist.py new file mode 100644 index 0000000..a851453 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/command/sdist.py @@ -0,0 +1,252 @@ +from distutils import log +import distutils.command.sdist as orig +import os +import sys +import io +import contextlib + +from setuptools.extern import six, ordered_set + +from .py36compat import sdist_add_defaults + +import pkg_resources + +_default_revctrl = list + + +def walk_revctrl(dirname=''): + """Find all files under revision control""" + for ep in pkg_resources.iter_entry_points('setuptools.file_finders'): + for item in ep.load()(dirname): + yield item + + +class sdist(sdist_add_defaults, orig.sdist): + """Smart sdist that finds anything supported by revision control""" + + user_options = [ + ('formats=', None, + "formats for source distribution (comma-separated list)"), + ('keep-temp', 'k', + "keep the distribution tree around after creating " + + "archive file(s)"), + ('dist-dir=', 'd', + "directory to put the source distribution archive(s) in " + "[default: dist]"), + ] + + negative_opt = {} + + README_EXTENSIONS = ['', '.rst', '.txt', '.md'] + READMES = tuple('README{0}'.format(ext) for ext in README_EXTENSIONS) + + def run(self): + self.run_command('egg_info') + ei_cmd = self.get_finalized_command('egg_info') + self.filelist = ei_cmd.filelist + self.filelist.append(os.path.join(ei_cmd.egg_info, 'SOURCES.txt')) + self.check_readme() + + # Run sub commands + for cmd_name in self.get_sub_commands(): + self.run_command(cmd_name) + + self.make_distribution() + + dist_files = getattr(self.distribution, 'dist_files', []) + for file in self.archive_files: + data = ('sdist', '', file) + if data not in dist_files: + dist_files.append(data) + + def initialize_options(self): + orig.sdist.initialize_options(self) + + self._default_to_gztar() + + def _default_to_gztar(self): + # only needed on Python prior to 3.6. + if sys.version_info >= (3, 6, 0, 'beta', 1): + return + self.formats = ['gztar'] + + def make_distribution(self): + """ + Workaround for #516 + """ + with self._remove_os_link(): + orig.sdist.make_distribution(self) + + @staticmethod + @contextlib.contextmanager + def _remove_os_link(): + """ + In a context, remove and restore os.link if it exists + """ + + class NoValue: + pass + + orig_val = getattr(os, 'link', NoValue) + try: + del os.link + except Exception: + pass + try: + yield + finally: + if orig_val is not NoValue: + setattr(os, 'link', orig_val) + + def __read_template_hack(self): + # This grody hack closes the template file (MANIFEST.in) if an + # exception occurs during read_template. + # Doing so prevents an error when easy_install attempts to delete the + # file. + try: + orig.sdist.read_template(self) + except Exception: + _, _, tb = sys.exc_info() + tb.tb_next.tb_frame.f_locals['template'].close() + raise + + # Beginning with Python 2.7.2, 3.1.4, and 3.2.1, this leaky file handle + # has been fixed, so only override the method if we're using an earlier + # Python. + has_leaky_handle = ( + sys.version_info < (2, 7, 2) + or (3, 0) <= sys.version_info < (3, 1, 4) + or (3, 2) <= sys.version_info < (3, 2, 1) + ) + if has_leaky_handle: + read_template = __read_template_hack + + def _add_defaults_optional(self): + if six.PY2: + sdist_add_defaults._add_defaults_optional(self) + else: + super()._add_defaults_optional() + if os.path.isfile('pyproject.toml'): + self.filelist.append('pyproject.toml') + + def _add_defaults_python(self): + """getting python files""" + if self.distribution.has_pure_modules(): + build_py = self.get_finalized_command('build_py') + self.filelist.extend(build_py.get_source_files()) + self._add_data_files(self._safe_data_files(build_py)) + + def _safe_data_files(self, build_py): + """ + Extracting data_files from build_py is known to cause + infinite recursion errors when `include_package_data` + is enabled, so suppress it in that case. + """ + if self.distribution.include_package_data: + return () + return build_py.data_files + + def _add_data_files(self, data_files): + """ + Add data files as found in build_py.data_files. + """ + self.filelist.extend( + os.path.join(src_dir, name) + for _, src_dir, _, filenames in data_files + for name in filenames + ) + + def _add_defaults_data_files(self): + try: + if six.PY2: + sdist_add_defaults._add_defaults_data_files(self) + else: + super()._add_defaults_data_files() + except TypeError: + log.warn("data_files contains unexpected objects") + + def check_readme(self): + for f in self.READMES: + if os.path.exists(f): + return + else: + self.warn( + "standard file not found: should have one of " + + ', '.join(self.READMES) + ) + + def make_release_tree(self, base_dir, files): + orig.sdist.make_release_tree(self, base_dir, files) + + # Save any egg_info command line options used to create this sdist + dest = os.path.join(base_dir, 'setup.cfg') + if hasattr(os, 'link') and os.path.exists(dest): + # unlink and re-copy, since it might be hard-linked, and + # we don't want to change the source version + os.unlink(dest) + self.copy_file('setup.cfg', dest) + + self.get_finalized_command('egg_info').save_version_info(dest) + + def _manifest_is_not_generated(self): + # check for special comment used in 2.7.1 and higher + if not os.path.isfile(self.manifest): + return False + + with io.open(self.manifest, 'rb') as fp: + first_line = fp.readline() + return (first_line != + '# file GENERATED by distutils, do NOT edit\n'.encode()) + + def read_manifest(self): + """Read the manifest file (named by 'self.manifest') and use it to + fill in 'self.filelist', the list of files to include in the source + distribution. + """ + log.info("reading manifest file '%s'", self.manifest) + manifest = open(self.manifest, 'rb') + for line in manifest: + # The manifest must contain UTF-8. See #303. + if six.PY3: + try: + line = line.decode('UTF-8') + except UnicodeDecodeError: + log.warn("%r not UTF-8 decodable -- skipping" % line) + continue + # ignore comments and blank lines + line = line.strip() + if line.startswith('#') or not line: + continue + self.filelist.append(line) + manifest.close() + + def check_license(self): + """Checks if license_file' or 'license_files' is configured and adds any + valid paths to 'self.filelist'. + """ + + files = ordered_set.OrderedSet() + + opts = self.distribution.get_option_dict('metadata') + + # ignore the source of the value + _, license_file = opts.get('license_file', (None, None)) + + if license_file is None: + log.debug("'license_file' option was not specified") + else: + files.add(license_file) + + try: + files.update(self.distribution.metadata.license_files) + except TypeError: + log.warn("warning: 'license_files' option is malformed") + + for f in files: + if not os.path.exists(f): + log.warn( + "warning: Failed to find the configured license file '%s'", + f) + files.remove(f) + + self.filelist.extend(files) diff --git a/venv/lib/python3.8/site-packages/setuptools/command/setopt.py b/venv/lib/python3.8/site-packages/setuptools/command/setopt.py new file mode 100644 index 0000000..7e57cc0 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/command/setopt.py @@ -0,0 +1,149 @@ +from distutils.util import convert_path +from distutils import log +from distutils.errors import DistutilsOptionError +import distutils +import os + +from setuptools.extern.six.moves import configparser + +from setuptools import Command + +__all__ = ['config_file', 'edit_config', 'option_base', 'setopt'] + + +def config_file(kind="local"): + """Get the filename of the distutils, local, global, or per-user config + + `kind` must be one of "local", "global", or "user" + """ + if kind == 'local': + return 'setup.cfg' + if kind == 'global': + return os.path.join( + os.path.dirname(distutils.__file__), 'distutils.cfg' + ) + if kind == 'user': + dot = os.name == 'posix' and '.' or '' + return os.path.expanduser(convert_path("~/%spydistutils.cfg" % dot)) + raise ValueError( + "config_file() type must be 'local', 'global', or 'user'", kind + ) + + +def edit_config(filename, settings, dry_run=False): + """Edit a configuration file to include `settings` + + `settings` is a dictionary of dictionaries or ``None`` values, keyed by + command/section name. A ``None`` value means to delete the entire section, + while a dictionary lists settings to be changed or deleted in that section. + A setting of ``None`` means to delete that setting. + """ + log.debug("Reading configuration from %s", filename) + opts = configparser.RawConfigParser() + opts.read([filename]) + for section, options in settings.items(): + if options is None: + log.info("Deleting section [%s] from %s", section, filename) + opts.remove_section(section) + else: + if not opts.has_section(section): + log.debug("Adding new section [%s] to %s", section, filename) + opts.add_section(section) + for option, value in options.items(): + if value is None: + log.debug( + "Deleting %s.%s from %s", + section, option, filename + ) + opts.remove_option(section, option) + if not opts.options(section): + log.info("Deleting empty [%s] section from %s", + section, filename) + opts.remove_section(section) + else: + log.debug( + "Setting %s.%s to %r in %s", + section, option, value, filename + ) + opts.set(section, option, value) + + log.info("Writing %s", filename) + if not dry_run: + with open(filename, 'w') as f: + opts.write(f) + + +class option_base(Command): + """Abstract base class for commands that mess with config files""" + + user_options = [ + ('global-config', 'g', + "save options to the site-wide distutils.cfg file"), + ('user-config', 'u', + "save options to the current user's pydistutils.cfg file"), + ('filename=', 'f', + "configuration file to use (default=setup.cfg)"), + ] + + boolean_options = [ + 'global-config', 'user-config', + ] + + def initialize_options(self): + self.global_config = None + self.user_config = None + self.filename = None + + def finalize_options(self): + filenames = [] + if self.global_config: + filenames.append(config_file('global')) + if self.user_config: + filenames.append(config_file('user')) + if self.filename is not None: + filenames.append(self.filename) + if not filenames: + filenames.append(config_file('local')) + if len(filenames) > 1: + raise DistutilsOptionError( + "Must specify only one configuration file option", + filenames + ) + self.filename, = filenames + + +class setopt(option_base): + """Save command-line options to a file""" + + description = "set an option in setup.cfg or another config file" + + user_options = [ + ('command=', 'c', 'command to set an option for'), + ('option=', 'o', 'option to set'), + ('set-value=', 's', 'value of the option'), + ('remove', 'r', 'remove (unset) the value'), + ] + option_base.user_options + + boolean_options = option_base.boolean_options + ['remove'] + + def initialize_options(self): + option_base.initialize_options(self) + self.command = None + self.option = None + self.set_value = None + self.remove = None + + def finalize_options(self): + option_base.finalize_options(self) + if self.command is None or self.option is None: + raise DistutilsOptionError("Must specify --command *and* --option") + if self.set_value is None and not self.remove: + raise DistutilsOptionError("Must specify --set-value or --remove") + + def run(self): + edit_config( + self.filename, { + self.command: {self.option.replace('-', '_'): self.set_value} + }, + self.dry_run + ) diff --git a/venv/lib/python3.8/site-packages/setuptools/command/test.py b/venv/lib/python3.8/site-packages/setuptools/command/test.py new file mode 100644 index 0000000..c148b38 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/command/test.py @@ -0,0 +1,279 @@ +import os +import operator +import sys +import contextlib +import itertools +import unittest +from distutils.errors import DistutilsError, DistutilsOptionError +from distutils import log +from unittest import TestLoader + +from setuptools.extern import six +from setuptools.extern.six.moves import map, filter + +from pkg_resources import (resource_listdir, resource_exists, normalize_path, + working_set, _namespace_packages, evaluate_marker, + add_activation_listener, require, EntryPoint) +from setuptools import Command +from .build_py import _unique_everseen + +__metaclass__ = type + + +class ScanningLoader(TestLoader): + + def __init__(self): + TestLoader.__init__(self) + self._visited = set() + + def loadTestsFromModule(self, module, pattern=None): + """Return a suite of all tests cases contained in the given module + + If the module is a package, load tests from all the modules in it. + If the module has an ``additional_tests`` function, call it and add + the return value to the tests. + """ + if module in self._visited: + return None + self._visited.add(module) + + tests = [] + tests.append(TestLoader.loadTestsFromModule(self, module)) + + if hasattr(module, "additional_tests"): + tests.append(module.additional_tests()) + + if hasattr(module, '__path__'): + for file in resource_listdir(module.__name__, ''): + if file.endswith('.py') and file != '__init__.py': + submodule = module.__name__ + '.' + file[:-3] + else: + if resource_exists(module.__name__, file + '/__init__.py'): + submodule = module.__name__ + '.' + file + else: + continue + tests.append(self.loadTestsFromName(submodule)) + + if len(tests) != 1: + return self.suiteClass(tests) + else: + return tests[0] # don't create a nested suite for only one return + + +# adapted from jaraco.classes.properties:NonDataProperty +class NonDataProperty: + def __init__(self, fget): + self.fget = fget + + def __get__(self, obj, objtype=None): + if obj is None: + return self + return self.fget(obj) + + +class test(Command): + """Command to run unit tests after in-place build""" + + description = "run unit tests after in-place build (deprecated)" + + user_options = [ + ('test-module=', 'm', "Run 'test_suite' in specified module"), + ('test-suite=', 's', + "Run single test, case or suite (e.g. 'module.test_suite')"), + ('test-runner=', 'r', "Test runner to use"), + ] + + def initialize_options(self): + self.test_suite = None + self.test_module = None + self.test_loader = None + self.test_runner = None + + def finalize_options(self): + + if self.test_suite and self.test_module: + msg = "You may specify a module or a suite, but not both" + raise DistutilsOptionError(msg) + + if self.test_suite is None: + if self.test_module is None: + self.test_suite = self.distribution.test_suite + else: + self.test_suite = self.test_module + ".test_suite" + + if self.test_loader is None: + self.test_loader = getattr(self.distribution, 'test_loader', None) + if self.test_loader is None: + self.test_loader = "setuptools.command.test:ScanningLoader" + if self.test_runner is None: + self.test_runner = getattr(self.distribution, 'test_runner', None) + + @NonDataProperty + def test_args(self): + return list(self._test_args()) + + def _test_args(self): + if not self.test_suite and sys.version_info >= (2, 7): + yield 'discover' + if self.verbose: + yield '--verbose' + if self.test_suite: + yield self.test_suite + + def with_project_on_sys_path(self, func): + """ + Backward compatibility for project_on_sys_path context. + """ + with self.project_on_sys_path(): + func() + + @contextlib.contextmanager + def project_on_sys_path(self, include_dists=[]): + with_2to3 = six.PY3 and getattr(self.distribution, 'use_2to3', False) + + if with_2to3: + # If we run 2to3 we can not do this inplace: + + # Ensure metadata is up-to-date + self.reinitialize_command('build_py', inplace=0) + self.run_command('build_py') + bpy_cmd = self.get_finalized_command("build_py") + build_path = normalize_path(bpy_cmd.build_lib) + + # Build extensions + self.reinitialize_command('egg_info', egg_base=build_path) + self.run_command('egg_info') + + self.reinitialize_command('build_ext', inplace=0) + self.run_command('build_ext') + else: + # Without 2to3 inplace works fine: + self.run_command('egg_info') + + # Build extensions in-place + self.reinitialize_command('build_ext', inplace=1) + self.run_command('build_ext') + + ei_cmd = self.get_finalized_command("egg_info") + + old_path = sys.path[:] + old_modules = sys.modules.copy() + + try: + project_path = normalize_path(ei_cmd.egg_base) + sys.path.insert(0, project_path) + working_set.__init__() + add_activation_listener(lambda dist: dist.activate()) + require('%s==%s' % (ei_cmd.egg_name, ei_cmd.egg_version)) + with self.paths_on_pythonpath([project_path]): + yield + finally: + sys.path[:] = old_path + sys.modules.clear() + sys.modules.update(old_modules) + working_set.__init__() + + @staticmethod + @contextlib.contextmanager + def paths_on_pythonpath(paths): + """ + Add the indicated paths to the head of the PYTHONPATH environment + variable so that subprocesses will also see the packages at + these paths. + + Do this in a context that restores the value on exit. + """ + nothing = object() + orig_pythonpath = os.environ.get('PYTHONPATH', nothing) + current_pythonpath = os.environ.get('PYTHONPATH', '') + try: + prefix = os.pathsep.join(_unique_everseen(paths)) + to_join = filter(None, [prefix, current_pythonpath]) + new_path = os.pathsep.join(to_join) + if new_path: + os.environ['PYTHONPATH'] = new_path + yield + finally: + if orig_pythonpath is nothing: + os.environ.pop('PYTHONPATH', None) + else: + os.environ['PYTHONPATH'] = orig_pythonpath + + @staticmethod + def install_dists(dist): + """ + Install the requirements indicated by self.distribution and + return an iterable of the dists that were built. + """ + ir_d = dist.fetch_build_eggs(dist.install_requires) + tr_d = dist.fetch_build_eggs(dist.tests_require or []) + er_d = dist.fetch_build_eggs( + v for k, v in dist.extras_require.items() + if k.startswith(':') and evaluate_marker(k[1:]) + ) + return itertools.chain(ir_d, tr_d, er_d) + + def run(self): + self.announce( + "WARNING: Testing via this command is deprecated and will be " + "removed in a future version. Users looking for a generic test " + "entry point independent of test runner are encouraged to use " + "tox.", + log.WARN, + ) + + installed_dists = self.install_dists(self.distribution) + + cmd = ' '.join(self._argv) + if self.dry_run: + self.announce('skipping "%s" (dry run)' % cmd) + return + + self.announce('running "%s"' % cmd) + + paths = map(operator.attrgetter('location'), installed_dists) + with self.paths_on_pythonpath(paths): + with self.project_on_sys_path(): + self.run_tests() + + def run_tests(self): + # Purge modules under test from sys.modules. The test loader will + # re-import them from the build location. Required when 2to3 is used + # with namespace packages. + if six.PY3 and getattr(self.distribution, 'use_2to3', False): + module = self.test_suite.split('.')[0] + if module in _namespace_packages: + del_modules = [] + if module in sys.modules: + del_modules.append(module) + module += '.' + for name in sys.modules: + if name.startswith(module): + del_modules.append(name) + list(map(sys.modules.__delitem__, del_modules)) + + test = unittest.main( + None, None, self._argv, + testLoader=self._resolve_as_ep(self.test_loader), + testRunner=self._resolve_as_ep(self.test_runner), + exit=False, + ) + if not test.result.wasSuccessful(): + msg = 'Test failed: %s' % test.result + self.announce(msg, log.ERROR) + raise DistutilsError(msg) + + @property + def _argv(self): + return ['unittest'] + self.test_args + + @staticmethod + def _resolve_as_ep(val): + """ + Load the indicated attribute value, called, as a as if it were + specified as an entry point. + """ + if val is None: + return + parsed = EntryPoint.parse("x=" + val) + return parsed.resolve()() diff --git a/venv/lib/python3.8/site-packages/setuptools/command/upload.py b/venv/lib/python3.8/site-packages/setuptools/command/upload.py new file mode 100644 index 0000000..ec7f81e --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/command/upload.py @@ -0,0 +1,17 @@ +from distutils import log +from distutils.command import upload as orig + +from setuptools.errors import RemovedCommandError + + +class upload(orig.upload): + """Formerly used to upload packages to PyPI.""" + + def run(self): + msg = ( + "The upload command has been removed, use twine to upload " + + "instead (https://pypi.org/p/twine)" + ) + + self.announce("ERROR: " + msg, log.ERROR) + raise RemovedCommandError(msg) diff --git a/venv/lib/python3.8/site-packages/setuptools/command/upload_docs.py b/venv/lib/python3.8/site-packages/setuptools/command/upload_docs.py new file mode 100644 index 0000000..07aa564 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/command/upload_docs.py @@ -0,0 +1,206 @@ +# -*- coding: utf-8 -*- +"""upload_docs + +Implements a Distutils 'upload_docs' subcommand (upload documentation to +PyPI's pythonhosted.org). +""" + +from base64 import standard_b64encode +from distutils import log +from distutils.errors import DistutilsOptionError +import os +import socket +import zipfile +import tempfile +import shutil +import itertools +import functools + +from setuptools.extern import six +from setuptools.extern.six.moves import http_client, urllib + +from pkg_resources import iter_entry_points +from .upload import upload + + +def _encode(s): + errors = 'surrogateescape' if six.PY3 else 'strict' + return s.encode('utf-8', errors) + + +class upload_docs(upload): + # override the default repository as upload_docs isn't + # supported by Warehouse (and won't be). + DEFAULT_REPOSITORY = 'https://pypi.python.org/pypi/' + + description = 'Upload documentation to PyPI' + + user_options = [ + ('repository=', 'r', + "url of repository [default: %s]" % upload.DEFAULT_REPOSITORY), + ('show-response', None, + 'display full response text from server'), + ('upload-dir=', None, 'directory to upload'), + ] + boolean_options = upload.boolean_options + + def has_sphinx(self): + if self.upload_dir is None: + for ep in iter_entry_points('distutils.commands', 'build_sphinx'): + return True + + sub_commands = [('build_sphinx', has_sphinx)] + + def initialize_options(self): + upload.initialize_options(self) + self.upload_dir = None + self.target_dir = None + + def finalize_options(self): + upload.finalize_options(self) + if self.upload_dir is None: + if self.has_sphinx(): + build_sphinx = self.get_finalized_command('build_sphinx') + self.target_dir = build_sphinx.builder_target_dir + else: + build = self.get_finalized_command('build') + self.target_dir = os.path.join(build.build_base, 'docs') + else: + self.ensure_dirname('upload_dir') + self.target_dir = self.upload_dir + if 'pypi.python.org' in self.repository: + log.warn("Upload_docs command is deprecated. Use RTD instead.") + self.announce('Using upload directory %s' % self.target_dir) + + def create_zipfile(self, filename): + zip_file = zipfile.ZipFile(filename, "w") + try: + self.mkpath(self.target_dir) # just in case + for root, dirs, files in os.walk(self.target_dir): + if root == self.target_dir and not files: + tmpl = "no files found in upload directory '%s'" + raise DistutilsOptionError(tmpl % self.target_dir) + for name in files: + full = os.path.join(root, name) + relative = root[len(self.target_dir):].lstrip(os.path.sep) + dest = os.path.join(relative, name) + zip_file.write(full, dest) + finally: + zip_file.close() + + def run(self): + # Run sub commands + for cmd_name in self.get_sub_commands(): + self.run_command(cmd_name) + + tmp_dir = tempfile.mkdtemp() + name = self.distribution.metadata.get_name() + zip_file = os.path.join(tmp_dir, "%s.zip" % name) + try: + self.create_zipfile(zip_file) + self.upload_file(zip_file) + finally: + shutil.rmtree(tmp_dir) + + @staticmethod + def _build_part(item, sep_boundary): + key, values = item + title = '\nContent-Disposition: form-data; name="%s"' % key + # handle multiple entries for the same name + if not isinstance(values, list): + values = [values] + for value in values: + if isinstance(value, tuple): + title += '; filename="%s"' % value[0] + value = value[1] + else: + value = _encode(value) + yield sep_boundary + yield _encode(title) + yield b"\n\n" + yield value + if value and value[-1:] == b'\r': + yield b'\n' # write an extra newline (lurve Macs) + + @classmethod + def _build_multipart(cls, data): + """ + Build up the MIME payload for the POST data + """ + boundary = b'--------------GHSKFJDLGDS7543FJKLFHRE75642756743254' + sep_boundary = b'\n--' + boundary + end_boundary = sep_boundary + b'--' + end_items = end_boundary, b"\n", + builder = functools.partial( + cls._build_part, + sep_boundary=sep_boundary, + ) + part_groups = map(builder, data.items()) + parts = itertools.chain.from_iterable(part_groups) + body_items = itertools.chain(parts, end_items) + content_type = 'multipart/form-data; boundary=%s' % boundary.decode('ascii') + return b''.join(body_items), content_type + + def upload_file(self, filename): + with open(filename, 'rb') as f: + content = f.read() + meta = self.distribution.metadata + data = { + ':action': 'doc_upload', + 'name': meta.get_name(), + 'content': (os.path.basename(filename), content), + } + # set up the authentication + credentials = _encode(self.username + ':' + self.password) + credentials = standard_b64encode(credentials) + if six.PY3: + credentials = credentials.decode('ascii') + auth = "Basic " + credentials + + body, ct = self._build_multipart(data) + + msg = "Submitting documentation to %s" % (self.repository) + self.announce(msg, log.INFO) + + # build the Request + # We can't use urllib2 since we need to send the Basic + # auth right with the first request + schema, netloc, url, params, query, fragments = \ + urllib.parse.urlparse(self.repository) + assert not params and not query and not fragments + if schema == 'http': + conn = http_client.HTTPConnection(netloc) + elif schema == 'https': + conn = http_client.HTTPSConnection(netloc) + else: + raise AssertionError("unsupported schema " + schema) + + data = '' + try: + conn.connect() + conn.putrequest("POST", url) + content_type = ct + conn.putheader('Content-type', content_type) + conn.putheader('Content-length', str(len(body))) + conn.putheader('Authorization', auth) + conn.endheaders() + conn.send(body) + except socket.error as e: + self.announce(str(e), log.ERROR) + return + + r = conn.getresponse() + if r.status == 200: + msg = 'Server response (%s): %s' % (r.status, r.reason) + self.announce(msg, log.INFO) + elif r.status == 301: + location = r.getheader('Location') + if location is None: + location = 'https://pythonhosted.org/%s/' % meta.get_name() + msg = 'Upload successful. Visit %s' % location + self.announce(msg, log.INFO) + else: + msg = 'Upload failed (%s): %s' % (r.status, r.reason) + self.announce(msg, log.ERROR) + if self.show_response: + print('-' * 75, r.read(), '-' * 75) diff --git a/venv/lib/python3.8/site-packages/setuptools/config.py b/venv/lib/python3.8/site-packages/setuptools/config.py new file mode 100644 index 0000000..9b9a0c4 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/config.py @@ -0,0 +1,659 @@ +from __future__ import absolute_import, unicode_literals +import io +import os +import sys + +import warnings +import functools +from collections import defaultdict +from functools import partial +from functools import wraps +from importlib import import_module + +from distutils.errors import DistutilsOptionError, DistutilsFileError +from setuptools.extern.packaging.version import LegacyVersion, parse +from setuptools.extern.packaging.specifiers import SpecifierSet +from setuptools.extern.six import string_types, PY3 + + +__metaclass__ = type + + +def read_configuration( + filepath, find_others=False, ignore_option_errors=False): + """Read given configuration file and returns options from it as a dict. + + :param str|unicode filepath: Path to configuration file + to get options from. + + :param bool find_others: Whether to search for other configuration files + which could be on in various places. + + :param bool ignore_option_errors: Whether to silently ignore + options, values of which could not be resolved (e.g. due to exceptions + in directives such as file:, attr:, etc.). + If False exceptions are propagated as expected. + + :rtype: dict + """ + from setuptools.dist import Distribution, _Distribution + + filepath = os.path.abspath(filepath) + + if not os.path.isfile(filepath): + raise DistutilsFileError( + 'Configuration file %s does not exist.' % filepath) + + current_directory = os.getcwd() + os.chdir(os.path.dirname(filepath)) + + try: + dist = Distribution() + + filenames = dist.find_config_files() if find_others else [] + if filepath not in filenames: + filenames.append(filepath) + + _Distribution.parse_config_files(dist, filenames=filenames) + + handlers = parse_configuration( + dist, dist.command_options, + ignore_option_errors=ignore_option_errors) + + finally: + os.chdir(current_directory) + + return configuration_to_dict(handlers) + + +def _get_option(target_obj, key): + """ + Given a target object and option key, get that option from + the target object, either through a get_{key} method or + from an attribute directly. + """ + getter_name = 'get_{key}'.format(**locals()) + by_attribute = functools.partial(getattr, target_obj, key) + getter = getattr(target_obj, getter_name, by_attribute) + return getter() + + +def configuration_to_dict(handlers): + """Returns configuration data gathered by given handlers as a dict. + + :param list[ConfigHandler] handlers: Handlers list, + usually from parse_configuration() + + :rtype: dict + """ + config_dict = defaultdict(dict) + + for handler in handlers: + for option in handler.set_options: + value = _get_option(handler.target_obj, option) + config_dict[handler.section_prefix][option] = value + + return config_dict + + +def parse_configuration( + distribution, command_options, ignore_option_errors=False): + """Performs additional parsing of configuration options + for a distribution. + + Returns a list of used option handlers. + + :param Distribution distribution: + :param dict command_options: + :param bool ignore_option_errors: Whether to silently ignore + options, values of which could not be resolved (e.g. due to exceptions + in directives such as file:, attr:, etc.). + If False exceptions are propagated as expected. + :rtype: list + """ + options = ConfigOptionsHandler( + distribution, command_options, ignore_option_errors) + options.parse() + + meta = ConfigMetadataHandler( + distribution.metadata, command_options, ignore_option_errors, + distribution.package_dir) + meta.parse() + + return meta, options + + +class ConfigHandler: + """Handles metadata supplied in configuration files.""" + + section_prefix = None + """Prefix for config sections handled by this handler. + Must be provided by class heirs. + + """ + + aliases = {} + """Options aliases. + For compatibility with various packages. E.g.: d2to1 and pbr. + Note: `-` in keys is replaced with `_` by config parser. + + """ + + def __init__(self, target_obj, options, ignore_option_errors=False): + sections = {} + + section_prefix = self.section_prefix + for section_name, section_options in options.items(): + if not section_name.startswith(section_prefix): + continue + + section_name = section_name.replace(section_prefix, '').strip('.') + sections[section_name] = section_options + + self.ignore_option_errors = ignore_option_errors + self.target_obj = target_obj + self.sections = sections + self.set_options = [] + + @property + def parsers(self): + """Metadata item name to parser function mapping.""" + raise NotImplementedError( + '%s must provide .parsers property' % self.__class__.__name__) + + def __setitem__(self, option_name, value): + unknown = tuple() + target_obj = self.target_obj + + # Translate alias into real name. + option_name = self.aliases.get(option_name, option_name) + + current_value = getattr(target_obj, option_name, unknown) + + if current_value is unknown: + raise KeyError(option_name) + + if current_value: + # Already inhabited. Skipping. + return + + skip_option = False + parser = self.parsers.get(option_name) + if parser: + try: + value = parser(value) + + except Exception: + skip_option = True + if not self.ignore_option_errors: + raise + + if skip_option: + return + + setter = getattr(target_obj, 'set_%s' % option_name, None) + if setter is None: + setattr(target_obj, option_name, value) + else: + setter(value) + + self.set_options.append(option_name) + + @classmethod + def _parse_list(cls, value, separator=','): + """Represents value as a list. + + Value is split either by separator (defaults to comma) or by lines. + + :param value: + :param separator: List items separator character. + :rtype: list + """ + if isinstance(value, list): # _get_parser_compound case + return value + + if '\n' in value: + value = value.splitlines() + else: + value = value.split(separator) + + return [chunk.strip() for chunk in value if chunk.strip()] + + @classmethod + def _parse_dict(cls, value): + """Represents value as a dict. + + :param value: + :rtype: dict + """ + separator = '=' + result = {} + for line in cls._parse_list(value): + key, sep, val = line.partition(separator) + if sep != separator: + raise DistutilsOptionError( + 'Unable to parse option value to dict: %s' % value) + result[key.strip()] = val.strip() + + return result + + @classmethod + def _parse_bool(cls, value): + """Represents value as boolean. + + :param value: + :rtype: bool + """ + value = value.lower() + return value in ('1', 'true', 'yes') + + @classmethod + def _exclude_files_parser(cls, key): + """Returns a parser function to make sure field inputs + are not files. + + Parses a value after getting the key so error messages are + more informative. + + :param key: + :rtype: callable + """ + def parser(value): + exclude_directive = 'file:' + if value.startswith(exclude_directive): + raise ValueError( + 'Only strings are accepted for the {0} field, ' + 'files are not accepted'.format(key)) + return value + return parser + + @classmethod + def _parse_file(cls, value): + """Represents value as a string, allowing including text + from nearest files using `file:` directive. + + Directive is sandboxed and won't reach anything outside + directory with setup.py. + + Examples: + file: README.rst, CHANGELOG.md, src/file.txt + + :param str value: + :rtype: str + """ + include_directive = 'file:' + + if not isinstance(value, string_types): + return value + + if not value.startswith(include_directive): + return value + + spec = value[len(include_directive):] + filepaths = (os.path.abspath(path.strip()) for path in spec.split(',')) + return '\n'.join( + cls._read_file(path) + for path in filepaths + if (cls._assert_local(path) or True) + and os.path.isfile(path) + ) + + @staticmethod + def _assert_local(filepath): + if not filepath.startswith(os.getcwd()): + raise DistutilsOptionError( + '`file:` directive can not access %s' % filepath) + + @staticmethod + def _read_file(filepath): + with io.open(filepath, encoding='utf-8') as f: + return f.read() + + @classmethod + def _parse_attr(cls, value, package_dir=None): + """Represents value as a module attribute. + + Examples: + attr: package.attr + attr: package.module.attr + + :param str value: + :rtype: str + """ + attr_directive = 'attr:' + if not value.startswith(attr_directive): + return value + + attrs_path = value.replace(attr_directive, '').strip().split('.') + attr_name = attrs_path.pop() + + module_name = '.'.join(attrs_path) + module_name = module_name or '__init__' + + parent_path = os.getcwd() + if package_dir: + if attrs_path[0] in package_dir: + # A custom path was specified for the module we want to import + custom_path = package_dir[attrs_path[0]] + parts = custom_path.rsplit('/', 1) + if len(parts) > 1: + parent_path = os.path.join(os.getcwd(), parts[0]) + module_name = parts[1] + else: + module_name = custom_path + elif '' in package_dir: + # A custom parent directory was specified for all root modules + parent_path = os.path.join(os.getcwd(), package_dir['']) + sys.path.insert(0, parent_path) + try: + module = import_module(module_name) + value = getattr(module, attr_name) + + finally: + sys.path = sys.path[1:] + + return value + + @classmethod + def _get_parser_compound(cls, *parse_methods): + """Returns parser function to represents value as a list. + + Parses a value applying given methods one after another. + + :param parse_methods: + :rtype: callable + """ + def parse(value): + parsed = value + + for method in parse_methods: + parsed = method(parsed) + + return parsed + + return parse + + @classmethod + def _parse_section_to_dict(cls, section_options, values_parser=None): + """Parses section options into a dictionary. + + Optionally applies a given parser to values. + + :param dict section_options: + :param callable values_parser: + :rtype: dict + """ + value = {} + values_parser = values_parser or (lambda val: val) + for key, (_, val) in section_options.items(): + value[key] = values_parser(val) + return value + + def parse_section(self, section_options): + """Parses configuration file section. + + :param dict section_options: + """ + for (name, (_, value)) in section_options.items(): + try: + self[name] = value + + except KeyError: + pass # Keep silent for a new option may appear anytime. + + def parse(self): + """Parses configuration file items from one + or more related sections. + + """ + for section_name, section_options in self.sections.items(): + + method_postfix = '' + if section_name: # [section.option] variant + method_postfix = '_%s' % section_name + + section_parser_method = getattr( + self, + # Dots in section names are translated into dunderscores. + ('parse_section%s' % method_postfix).replace('.', '__'), + None) + + if section_parser_method is None: + raise DistutilsOptionError( + 'Unsupported distribution option section: [%s.%s]' % ( + self.section_prefix, section_name)) + + section_parser_method(section_options) + + def _deprecated_config_handler(self, func, msg, warning_class): + """ this function will wrap around parameters that are deprecated + + :param msg: deprecation message + :param warning_class: class of warning exception to be raised + :param func: function to be wrapped around + """ + @wraps(func) + def config_handler(*args, **kwargs): + warnings.warn(msg, warning_class) + return func(*args, **kwargs) + + return config_handler + + +class ConfigMetadataHandler(ConfigHandler): + + section_prefix = 'metadata' + + aliases = { + 'home_page': 'url', + 'summary': 'description', + 'classifier': 'classifiers', + 'platform': 'platforms', + } + + strict_mode = False + """We need to keep it loose, to be partially compatible with + `pbr` and `d2to1` packages which also uses `metadata` section. + + """ + + def __init__(self, target_obj, options, ignore_option_errors=False, + package_dir=None): + super(ConfigMetadataHandler, self).__init__(target_obj, options, + ignore_option_errors) + self.package_dir = package_dir + + @property + def parsers(self): + """Metadata item name to parser function mapping.""" + parse_list = self._parse_list + parse_file = self._parse_file + parse_dict = self._parse_dict + exclude_files_parser = self._exclude_files_parser + + return { + 'platforms': parse_list, + 'keywords': parse_list, + 'provides': parse_list, + 'requires': self._deprecated_config_handler( + parse_list, + "The requires parameter is deprecated, please use " + "install_requires for runtime dependencies.", + DeprecationWarning), + 'obsoletes': parse_list, + 'classifiers': self._get_parser_compound(parse_file, parse_list), + 'license': exclude_files_parser('license'), + 'license_files': parse_list, + 'description': parse_file, + 'long_description': parse_file, + 'version': self._parse_version, + 'project_urls': parse_dict, + } + + def _parse_version(self, value): + """Parses `version` option value. + + :param value: + :rtype: str + + """ + version = self._parse_file(value) + + if version != value: + version = version.strip() + # Be strict about versions loaded from file because it's easy to + # accidentally include newlines and other unintended content + if isinstance(parse(version), LegacyVersion): + tmpl = ( + 'Version loaded from {value} does not ' + 'comply with PEP 440: {version}' + ) + raise DistutilsOptionError(tmpl.format(**locals())) + + return version + + version = self._parse_attr(value, self.package_dir) + + if callable(version): + version = version() + + if not isinstance(version, string_types): + if hasattr(version, '__iter__'): + version = '.'.join(map(str, version)) + else: + version = '%s' % version + + return version + + +class ConfigOptionsHandler(ConfigHandler): + + section_prefix = 'options' + + @property + def parsers(self): + """Metadata item name to parser function mapping.""" + parse_list = self._parse_list + parse_list_semicolon = partial(self._parse_list, separator=';') + parse_bool = self._parse_bool + parse_dict = self._parse_dict + + return { + 'zip_safe': parse_bool, + 'use_2to3': parse_bool, + 'include_package_data': parse_bool, + 'package_dir': parse_dict, + 'use_2to3_fixers': parse_list, + 'use_2to3_exclude_fixers': parse_list, + 'convert_2to3_doctests': parse_list, + 'scripts': parse_list, + 'eager_resources': parse_list, + 'dependency_links': parse_list, + 'namespace_packages': parse_list, + 'install_requires': parse_list_semicolon, + 'setup_requires': parse_list_semicolon, + 'tests_require': parse_list_semicolon, + 'packages': self._parse_packages, + 'entry_points': self._parse_file, + 'py_modules': parse_list, + 'python_requires': SpecifierSet, + } + + def _parse_packages(self, value): + """Parses `packages` option value. + + :param value: + :rtype: list + """ + find_directives = ['find:', 'find_namespace:'] + trimmed_value = value.strip() + + if trimmed_value not in find_directives: + return self._parse_list(value) + + findns = trimmed_value == find_directives[1] + if findns and not PY3: + raise DistutilsOptionError( + 'find_namespace: directive is unsupported on Python < 3.3') + + # Read function arguments from a dedicated section. + find_kwargs = self.parse_section_packages__find( + self.sections.get('packages.find', {})) + + if findns: + from setuptools import find_namespace_packages as find_packages + else: + from setuptools import find_packages + + return find_packages(**find_kwargs) + + def parse_section_packages__find(self, section_options): + """Parses `packages.find` configuration file section. + + To be used in conjunction with _parse_packages(). + + :param dict section_options: + """ + section_data = self._parse_section_to_dict( + section_options, self._parse_list) + + valid_keys = ['where', 'include', 'exclude'] + + find_kwargs = dict( + [(k, v) for k, v in section_data.items() if k in valid_keys and v]) + + where = find_kwargs.get('where') + if where is not None: + find_kwargs['where'] = where[0] # cast list to single val + + return find_kwargs + + def parse_section_entry_points(self, section_options): + """Parses `entry_points` configuration file section. + + :param dict section_options: + """ + parsed = self._parse_section_to_dict(section_options, self._parse_list) + self['entry_points'] = parsed + + def _parse_package_data(self, section_options): + parsed = self._parse_section_to_dict(section_options, self._parse_list) + + root = parsed.get('*') + if root: + parsed[''] = root + del parsed['*'] + + return parsed + + def parse_section_package_data(self, section_options): + """Parses `package_data` configuration file section. + + :param dict section_options: + """ + self['package_data'] = self._parse_package_data(section_options) + + def parse_section_exclude_package_data(self, section_options): + """Parses `exclude_package_data` configuration file section. + + :param dict section_options: + """ + self['exclude_package_data'] = self._parse_package_data( + section_options) + + def parse_section_extras_require(self, section_options): + """Parses `extras_require` configuration file section. + + :param dict section_options: + """ + parse_list = partial(self._parse_list, separator=';') + self['extras_require'] = self._parse_section_to_dict( + section_options, parse_list) + + def parse_section_data_files(self, section_options): + """Parses `data_files` configuration file section. + + :param dict section_options: + """ + parsed = self._parse_section_to_dict(section_options, self._parse_list) + self['data_files'] = [(k, v) for k, v in parsed.items()] diff --git a/venv/lib/python3.8/site-packages/setuptools/dep_util.py b/venv/lib/python3.8/site-packages/setuptools/dep_util.py new file mode 100644 index 0000000..2931c13 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/dep_util.py @@ -0,0 +1,23 @@ +from distutils.dep_util import newer_group + +# yes, this is was almost entirely copy-pasted from +# 'newer_pairwise()', this is just another convenience +# function. +def newer_pairwise_group(sources_groups, targets): + """Walk both arguments in parallel, testing if each source group is newer + than its corresponding target. Returns a pair of lists (sources_groups, + targets) where sources is newer than target, according to the semantics + of 'newer_group()'. + """ + if len(sources_groups) != len(targets): + raise ValueError("'sources_group' and 'targets' must be the same length") + + # build a pair of lists (sources_groups, targets) where source is newer + n_sources = [] + n_targets = [] + for i in range(len(sources_groups)): + if newer_group(sources_groups[i], targets[i]): + n_sources.append(sources_groups[i]) + n_targets.append(targets[i]) + + return n_sources, n_targets diff --git a/venv/lib/python3.8/site-packages/setuptools/depends.py b/venv/lib/python3.8/site-packages/setuptools/depends.py new file mode 100644 index 0000000..a37675c --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/depends.py @@ -0,0 +1,176 @@ +import sys +import marshal +import contextlib +from distutils.version import StrictVersion + +from .py33compat import Bytecode + +from .py27compat import find_module, PY_COMPILED, PY_FROZEN, PY_SOURCE +from . import py27compat + + +__all__ = [ + 'Require', 'find_module', 'get_module_constant', 'extract_constant' +] + + +class Require: + """A prerequisite to building or installing a distribution""" + + def __init__( + self, name, requested_version, module, homepage='', + attribute=None, format=None): + + if format is None and requested_version is not None: + format = StrictVersion + + if format is not None: + requested_version = format(requested_version) + if attribute is None: + attribute = '__version__' + + self.__dict__.update(locals()) + del self.self + + def full_name(self): + """Return full package/distribution name, w/version""" + if self.requested_version is not None: + return '%s-%s' % (self.name, self.requested_version) + return self.name + + def version_ok(self, version): + """Is 'version' sufficiently up-to-date?""" + return self.attribute is None or self.format is None or \ + str(version) != "unknown" and version >= self.requested_version + + def get_version(self, paths=None, default="unknown"): + """Get version number of installed module, 'None', or 'default' + + Search 'paths' for module. If not found, return 'None'. If found, + return the extracted version attribute, or 'default' if no version + attribute was specified, or the value cannot be determined without + importing the module. The version is formatted according to the + requirement's version format (if any), unless it is 'None' or the + supplied 'default'. + """ + + if self.attribute is None: + try: + f, p, i = find_module(self.module, paths) + if f: + f.close() + return default + except ImportError: + return None + + v = get_module_constant(self.module, self.attribute, default, paths) + + if v is not None and v is not default and self.format is not None: + return self.format(v) + + return v + + def is_present(self, paths=None): + """Return true if dependency is present on 'paths'""" + return self.get_version(paths) is not None + + def is_current(self, paths=None): + """Return true if dependency is present and up-to-date on 'paths'""" + version = self.get_version(paths) + if version is None: + return False + return self.version_ok(version) + + +def maybe_close(f): + @contextlib.contextmanager + def empty(): + yield + return + if not f: + return empty() + + return contextlib.closing(f) + + +def get_module_constant(module, symbol, default=-1, paths=None): + """Find 'module' by searching 'paths', and extract 'symbol' + + Return 'None' if 'module' does not exist on 'paths', or it does not define + 'symbol'. If the module defines 'symbol' as a constant, return the + constant. Otherwise, return 'default'.""" + + try: + f, path, (suffix, mode, kind) = info = find_module(module, paths) + except ImportError: + # Module doesn't exist + return None + + with maybe_close(f): + if kind == PY_COMPILED: + f.read(8) # skip magic & date + code = marshal.load(f) + elif kind == PY_FROZEN: + code = py27compat.get_frozen_object(module, paths) + elif kind == PY_SOURCE: + code = compile(f.read(), path, 'exec') + else: + # Not something we can parse; we'll have to import it. :( + imported = py27compat.get_module(module, paths, info) + return getattr(imported, symbol, None) + + return extract_constant(code, symbol, default) + + +def extract_constant(code, symbol, default=-1): + """Extract the constant value of 'symbol' from 'code' + + If the name 'symbol' is bound to a constant value by the Python code + object 'code', return that value. If 'symbol' is bound to an expression, + return 'default'. Otherwise, return 'None'. + + Return value is based on the first assignment to 'symbol'. 'symbol' must + be a global, or at least a non-"fast" local in the code block. That is, + only 'STORE_NAME' and 'STORE_GLOBAL' opcodes are checked, and 'symbol' + must be present in 'code.co_names'. + """ + if symbol not in code.co_names: + # name's not there, can't possibly be an assignment + return None + + name_idx = list(code.co_names).index(symbol) + + STORE_NAME = 90 + STORE_GLOBAL = 97 + LOAD_CONST = 100 + + const = default + + for byte_code in Bytecode(code): + op = byte_code.opcode + arg = byte_code.arg + + if op == LOAD_CONST: + const = code.co_consts[arg] + elif arg == name_idx and (op == STORE_NAME or op == STORE_GLOBAL): + return const + else: + const = default + + +def _update_globals(): + """ + Patch the globals to remove the objects not available on some platforms. + + XXX it'd be better to test assertions about bytecode instead. + """ + + if not sys.platform.startswith('java') and sys.platform != 'cli': + return + incompatible = 'extract_constant', 'get_module_constant' + for name in incompatible: + del globals()[name] + __all__.remove(name) + + +_update_globals() diff --git a/venv/lib/python3.8/site-packages/setuptools/dist.py b/venv/lib/python3.8/site-packages/setuptools/dist.py new file mode 100644 index 0000000..f22429e --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/dist.py @@ -0,0 +1,1274 @@ +# -*- coding: utf-8 -*- +__all__ = ['Distribution'] + +import io +import sys +import re +import os +import warnings +import numbers +import distutils.log +import distutils.core +import distutils.cmd +import distutils.dist +from distutils.util import strtobool +from distutils.debug import DEBUG +from distutils.fancy_getopt import translate_longopt +import itertools + +from collections import defaultdict +from email import message_from_file + +from distutils.errors import ( + DistutilsOptionError, DistutilsPlatformError, DistutilsSetupError, +) +from distutils.util import rfc822_escape +from distutils.version import StrictVersion + +from setuptools.extern import six +from setuptools.extern import packaging +from setuptools.extern import ordered_set +from setuptools.extern.six.moves import map, filter, filterfalse + +from . import SetuptoolsDeprecationWarning + +from setuptools.depends import Require +from setuptools import windows_support +from setuptools.monkey import get_unpatched +from setuptools.config import parse_configuration +import pkg_resources + +__import__('setuptools.extern.packaging.specifiers') +__import__('setuptools.extern.packaging.version') + + +def _get_unpatched(cls): + warnings.warn("Do not call this function", DistDeprecationWarning) + return get_unpatched(cls) + + +def get_metadata_version(self): + mv = getattr(self, 'metadata_version', None) + + if mv is None: + if self.long_description_content_type or self.provides_extras: + mv = StrictVersion('2.1') + elif (self.maintainer is not None or + self.maintainer_email is not None or + getattr(self, 'python_requires', None) is not None or + self.project_urls): + mv = StrictVersion('1.2') + elif (self.provides or self.requires or self.obsoletes or + self.classifiers or self.download_url): + mv = StrictVersion('1.1') + else: + mv = StrictVersion('1.0') + + self.metadata_version = mv + + return mv + + +def read_pkg_file(self, file): + """Reads the metadata values from a file object.""" + msg = message_from_file(file) + + def _read_field(name): + value = msg[name] + if value == 'UNKNOWN': + return None + return value + + def _read_list(name): + values = msg.get_all(name, None) + if values == []: + return None + return values + + self.metadata_version = StrictVersion(msg['metadata-version']) + self.name = _read_field('name') + self.version = _read_field('version') + self.description = _read_field('summary') + # we are filling author only. + self.author = _read_field('author') + self.maintainer = None + self.author_email = _read_field('author-email') + self.maintainer_email = None + self.url = _read_field('home-page') + self.license = _read_field('license') + + if 'download-url' in msg: + self.download_url = _read_field('download-url') + else: + self.download_url = None + + self.long_description = _read_field('description') + self.description = _read_field('summary') + + if 'keywords' in msg: + self.keywords = _read_field('keywords').split(',') + + self.platforms = _read_list('platform') + self.classifiers = _read_list('classifier') + + # PEP 314 - these fields only exist in 1.1 + if self.metadata_version == StrictVersion('1.1'): + self.requires = _read_list('requires') + self.provides = _read_list('provides') + self.obsoletes = _read_list('obsoletes') + else: + self.requires = None + self.provides = None + self.obsoletes = None + + +# Based on Python 3.5 version +def write_pkg_file(self, file): + """Write the PKG-INFO format data to a file object. + """ + version = self.get_metadata_version() + + if six.PY2: + def write_field(key, value): + file.write("%s: %s\n" % (key, self._encode_field(value))) + else: + def write_field(key, value): + file.write("%s: %s\n" % (key, value)) + + write_field('Metadata-Version', str(version)) + write_field('Name', self.get_name()) + write_field('Version', self.get_version()) + write_field('Summary', self.get_description()) + write_field('Home-page', self.get_url()) + + if version < StrictVersion('1.2'): + write_field('Author', self.get_contact()) + write_field('Author-email', self.get_contact_email()) + else: + optional_fields = ( + ('Author', 'author'), + ('Author-email', 'author_email'), + ('Maintainer', 'maintainer'), + ('Maintainer-email', 'maintainer_email'), + ) + + for field, attr in optional_fields: + attr_val = getattr(self, attr) + + if attr_val is not None: + write_field(field, attr_val) + + write_field('License', self.get_license()) + if self.download_url: + write_field('Download-URL', self.download_url) + for project_url in self.project_urls.items(): + write_field('Project-URL', '%s, %s' % project_url) + + long_desc = rfc822_escape(self.get_long_description()) + write_field('Description', long_desc) + + keywords = ','.join(self.get_keywords()) + if keywords: + write_field('Keywords', keywords) + + if version >= StrictVersion('1.2'): + for platform in self.get_platforms(): + write_field('Platform', platform) + else: + self._write_list(file, 'Platform', self.get_platforms()) + + self._write_list(file, 'Classifier', self.get_classifiers()) + + # PEP 314 + self._write_list(file, 'Requires', self.get_requires()) + self._write_list(file, 'Provides', self.get_provides()) + self._write_list(file, 'Obsoletes', self.get_obsoletes()) + + # Setuptools specific for PEP 345 + if hasattr(self, 'python_requires'): + write_field('Requires-Python', self.python_requires) + + # PEP 566 + if self.long_description_content_type: + write_field( + 'Description-Content-Type', + self.long_description_content_type + ) + if self.provides_extras: + for extra in sorted(self.provides_extras): + write_field('Provides-Extra', extra) + + +sequence = tuple, list + + +def check_importable(dist, attr, value): + try: + ep = pkg_resources.EntryPoint.parse('x=' + value) + assert not ep.extras + except (TypeError, ValueError, AttributeError, AssertionError): + raise DistutilsSetupError( + "%r must be importable 'module:attrs' string (got %r)" + % (attr, value) + ) + + +def assert_string_list(dist, attr, value): + """Verify that value is a string list""" + try: + # verify that value is a list or tuple to exclude unordered + # or single-use iterables + assert isinstance(value, (list, tuple)) + # verify that elements of value are strings + assert ''.join(value) != value + except (TypeError, ValueError, AttributeError, AssertionError): + raise DistutilsSetupError( + "%r must be a list of strings (got %r)" % (attr, value) + ) + + +def check_nsp(dist, attr, value): + """Verify that namespace packages are valid""" + ns_packages = value + assert_string_list(dist, attr, ns_packages) + for nsp in ns_packages: + if not dist.has_contents_for(nsp): + raise DistutilsSetupError( + "Distribution contains no modules or packages for " + + "namespace package %r" % nsp + ) + parent, sep, child = nsp.rpartition('.') + if parent and parent not in ns_packages: + distutils.log.warn( + "WARNING: %r is declared as a package namespace, but %r" + " is not: please correct this in setup.py", nsp, parent + ) + + +def check_extras(dist, attr, value): + """Verify that extras_require mapping is valid""" + try: + list(itertools.starmap(_check_extra, value.items())) + except (TypeError, ValueError, AttributeError): + raise DistutilsSetupError( + "'extras_require' must be a dictionary whose values are " + "strings or lists of strings containing valid project/version " + "requirement specifiers." + ) + + +def _check_extra(extra, reqs): + name, sep, marker = extra.partition(':') + if marker and pkg_resources.invalid_marker(marker): + raise DistutilsSetupError("Invalid environment marker: " + marker) + list(pkg_resources.parse_requirements(reqs)) + + +def assert_bool(dist, attr, value): + """Verify that value is True, False, 0, or 1""" + if bool(value) != value: + tmpl = "{attr!r} must be a boolean value (got {value!r})" + raise DistutilsSetupError(tmpl.format(attr=attr, value=value)) + + +def check_requirements(dist, attr, value): + """Verify that install_requires is a valid requirements list""" + try: + list(pkg_resources.parse_requirements(value)) + if isinstance(value, (dict, set)): + raise TypeError("Unordered types are not allowed") + except (TypeError, ValueError) as error: + tmpl = ( + "{attr!r} must be a string or list of strings " + "containing valid project/version requirement specifiers; {error}" + ) + raise DistutilsSetupError(tmpl.format(attr=attr, error=error)) + + +def check_specifier(dist, attr, value): + """Verify that value is a valid version specifier""" + try: + packaging.specifiers.SpecifierSet(value) + except packaging.specifiers.InvalidSpecifier as error: + tmpl = ( + "{attr!r} must be a string " + "containing valid version specifiers; {error}" + ) + raise DistutilsSetupError(tmpl.format(attr=attr, error=error)) + + +def check_entry_points(dist, attr, value): + """Verify that entry_points map is parseable""" + try: + pkg_resources.EntryPoint.parse_map(value) + except ValueError as e: + raise DistutilsSetupError(e) + + +def check_test_suite(dist, attr, value): + if not isinstance(value, six.string_types): + raise DistutilsSetupError("test_suite must be a string") + + +def check_package_data(dist, attr, value): + """Verify that value is a dictionary of package names to glob lists""" + if not isinstance(value, dict): + raise DistutilsSetupError( + "{!r} must be a dictionary mapping package names to lists of " + "string wildcard patterns".format(attr)) + for k, v in value.items(): + if not isinstance(k, six.string_types): + raise DistutilsSetupError( + "keys of {!r} dict must be strings (got {!r})" + .format(attr, k) + ) + assert_string_list(dist, 'values of {!r} dict'.format(attr), v) + + +def check_packages(dist, attr, value): + for pkgname in value: + if not re.match(r'\w+(\.\w+)*', pkgname): + distutils.log.warn( + "WARNING: %r not a valid package name; please use only " + ".-separated package names in setup.py", pkgname + ) + + +_Distribution = get_unpatched(distutils.core.Distribution) + + +class Distribution(_Distribution): + """Distribution with support for features, tests, and package data + + This is an enhanced version of 'distutils.dist.Distribution' that + effectively adds the following new optional keyword arguments to 'setup()': + + 'install_requires' -- a string or sequence of strings specifying project + versions that the distribution requires when installed, in the format + used by 'pkg_resources.require()'. They will be installed + automatically when the package is installed. If you wish to use + packages that are not available in PyPI, or want to give your users an + alternate download location, you can add a 'find_links' option to the + '[easy_install]' section of your project's 'setup.cfg' file, and then + setuptools will scan the listed web pages for links that satisfy the + requirements. + + 'extras_require' -- a dictionary mapping names of optional "extras" to the + additional requirement(s) that using those extras incurs. For example, + this:: + + extras_require = dict(reST = ["docutils>=0.3", "reSTedit"]) + + indicates that the distribution can optionally provide an extra + capability called "reST", but it can only be used if docutils and + reSTedit are installed. If the user installs your package using + EasyInstall and requests one of your extras, the corresponding + additional requirements will be installed if needed. + + 'features' **deprecated** -- a dictionary mapping option names to + 'setuptools.Feature' + objects. Features are a portion of the distribution that can be + included or excluded based on user options, inter-feature dependencies, + and availability on the current system. Excluded features are omitted + from all setup commands, including source and binary distributions, so + you can create multiple distributions from the same source tree. + Feature names should be valid Python identifiers, except that they may + contain the '-' (minus) sign. Features can be included or excluded + via the command line options '--with-X' and '--without-X', where 'X' is + the name of the feature. Whether a feature is included by default, and + whether you are allowed to control this from the command line, is + determined by the Feature object. See the 'Feature' class for more + information. + + 'test_suite' -- the name of a test suite to run for the 'test' command. + If the user runs 'python setup.py test', the package will be installed, + and the named test suite will be run. The format is the same as + would be used on a 'unittest.py' command line. That is, it is the + dotted name of an object to import and call to generate a test suite. + + 'package_data' -- a dictionary mapping package names to lists of filenames + or globs to use to find data files contained in the named packages. + If the dictionary has filenames or globs listed under '""' (the empty + string), those names will be searched for in every package, in addition + to any names for the specific package. Data files found using these + names/globs will be installed along with the package, in the same + location as the package. Note that globs are allowed to reference + the contents of non-package subdirectories, as long as you use '/' as + a path separator. (Globs are automatically converted to + platform-specific paths at runtime.) + + In addition to these new keywords, this class also has several new methods + for manipulating the distribution's contents. For example, the 'include()' + and 'exclude()' methods can be thought of as in-place add and subtract + commands that add or remove packages, modules, extensions, and so on from + the distribution. They are used by the feature subsystem to configure the + distribution for the included and excluded features. + """ + + _DISTUTILS_UNSUPPORTED_METADATA = { + 'long_description_content_type': None, + 'project_urls': dict, + 'provides_extras': ordered_set.OrderedSet, + 'license_files': ordered_set.OrderedSet, + } + + _patched_dist = None + + def patch_missing_pkg_info(self, attrs): + # Fake up a replacement for the data that would normally come from + # PKG-INFO, but which might not yet be built if this is a fresh + # checkout. + # + if not attrs or 'name' not in attrs or 'version' not in attrs: + return + key = pkg_resources.safe_name(str(attrs['name'])).lower() + dist = pkg_resources.working_set.by_key.get(key) + if dist is not None and not dist.has_metadata('PKG-INFO'): + dist._version = pkg_resources.safe_version(str(attrs['version'])) + self._patched_dist = dist + + def __init__(self, attrs=None): + have_package_data = hasattr(self, "package_data") + if not have_package_data: + self.package_data = {} + attrs = attrs or {} + if 'features' in attrs or 'require_features' in attrs: + Feature.warn_deprecated() + self.require_features = [] + self.features = {} + self.dist_files = [] + # Filter-out setuptools' specific options. + self.src_root = attrs.pop("src_root", None) + self.patch_missing_pkg_info(attrs) + self.dependency_links = attrs.pop('dependency_links', []) + self.setup_requires = attrs.pop('setup_requires', []) + for ep in pkg_resources.iter_entry_points('distutils.setup_keywords'): + vars(self).setdefault(ep.name, None) + _Distribution.__init__(self, { + k: v for k, v in attrs.items() + if k not in self._DISTUTILS_UNSUPPORTED_METADATA + }) + + # Fill-in missing metadata fields not supported by distutils. + # Note some fields may have been set by other tools (e.g. pbr) + # above; they are taken preferrentially to setup() arguments + for option, default in self._DISTUTILS_UNSUPPORTED_METADATA.items(): + for source in self.metadata.__dict__, attrs: + if option in source: + value = source[option] + break + else: + value = default() if default else None + setattr(self.metadata, option, value) + + if isinstance(self.metadata.version, numbers.Number): + # Some people apparently take "version number" too literally :) + self.metadata.version = str(self.metadata.version) + + if self.metadata.version is not None: + try: + ver = packaging.version.Version(self.metadata.version) + normalized_version = str(ver) + if self.metadata.version != normalized_version: + warnings.warn( + "Normalizing '%s' to '%s'" % ( + self.metadata.version, + normalized_version, + ) + ) + self.metadata.version = normalized_version + except (packaging.version.InvalidVersion, TypeError): + warnings.warn( + "The version specified (%r) is an invalid version, this " + "may not work as expected with newer versions of " + "setuptools, pip, and PyPI. Please see PEP 440 for more " + "details." % self.metadata.version + ) + self._finalize_requires() + + def _finalize_requires(self): + """ + Set `metadata.python_requires` and fix environment markers + in `install_requires` and `extras_require`. + """ + if getattr(self, 'python_requires', None): + self.metadata.python_requires = self.python_requires + + if getattr(self, 'extras_require', None): + for extra in self.extras_require.keys(): + # Since this gets called multiple times at points where the + # keys have become 'converted' extras, ensure that we are only + # truly adding extras we haven't seen before here. + extra = extra.split(':')[0] + if extra: + self.metadata.provides_extras.add(extra) + + self._convert_extras_requirements() + self._move_install_requirements_markers() + + def _convert_extras_requirements(self): + """ + Convert requirements in `extras_require` of the form + `"extra": ["barbazquux; {marker}"]` to + `"extra:{marker}": ["barbazquux"]`. + """ + spec_ext_reqs = getattr(self, 'extras_require', None) or {} + self._tmp_extras_require = defaultdict(list) + for section, v in spec_ext_reqs.items(): + # Do not strip empty sections. + self._tmp_extras_require[section] + for r in pkg_resources.parse_requirements(v): + suffix = self._suffix_for(r) + self._tmp_extras_require[section + suffix].append(r) + + @staticmethod + def _suffix_for(req): + """ + For a requirement, return the 'extras_require' suffix for + that requirement. + """ + return ':' + str(req.marker) if req.marker else '' + + def _move_install_requirements_markers(self): + """ + Move requirements in `install_requires` that are using environment + markers `extras_require`. + """ + + # divide the install_requires into two sets, simple ones still + # handled by install_requires and more complex ones handled + # by extras_require. + + def is_simple_req(req): + return not req.marker + + spec_inst_reqs = getattr(self, 'install_requires', None) or () + inst_reqs = list(pkg_resources.parse_requirements(spec_inst_reqs)) + simple_reqs = filter(is_simple_req, inst_reqs) + complex_reqs = filterfalse(is_simple_req, inst_reqs) + self.install_requires = list(map(str, simple_reqs)) + + for r in complex_reqs: + self._tmp_extras_require[':' + str(r.marker)].append(r) + self.extras_require = dict( + (k, [str(r) for r in map(self._clean_req, v)]) + for k, v in self._tmp_extras_require.items() + ) + + def _clean_req(self, req): + """ + Given a Requirement, remove environment markers and return it. + """ + req.marker = None + return req + + def _parse_config_files(self, filenames=None): + """ + Adapted from distutils.dist.Distribution.parse_config_files, + this method provides the same functionality in subtly-improved + ways. + """ + from setuptools.extern.six.moves.configparser import ConfigParser + + # Ignore install directory options if we have a venv + if six.PY3 and sys.prefix != sys.base_prefix: + ignore_options = [ + 'install-base', 'install-platbase', 'install-lib', + 'install-platlib', 'install-purelib', 'install-headers', + 'install-scripts', 'install-data', 'prefix', 'exec-prefix', + 'home', 'user', 'root'] + else: + ignore_options = [] + + ignore_options = frozenset(ignore_options) + + if filenames is None: + filenames = self.find_config_files() + + if DEBUG: + self.announce("Distribution.parse_config_files():") + + parser = ConfigParser() + for filename in filenames: + with io.open(filename, encoding='utf-8') as reader: + if DEBUG: + self.announce(" reading {filename}".format(**locals())) + (parser.read_file if six.PY3 else parser.readfp)(reader) + for section in parser.sections(): + options = parser.options(section) + opt_dict = self.get_option_dict(section) + + for opt in options: + if opt != '__name__' and opt not in ignore_options: + val = self._try_str(parser.get(section, opt)) + opt = opt.replace('-', '_') + opt_dict[opt] = (filename, val) + + # Make the ConfigParser forget everything (so we retain + # the original filenames that options come from) + parser.__init__() + + # If there was a "global" section in the config file, use it + # to set Distribution options. + + if 'global' in self.command_options: + for (opt, (src, val)) in self.command_options['global'].items(): + alias = self.negative_opt.get(opt) + try: + if alias: + setattr(self, alias, not strtobool(val)) + elif opt in ('verbose', 'dry_run'): # ugh! + setattr(self, opt, strtobool(val)) + else: + setattr(self, opt, val) + except ValueError as msg: + raise DistutilsOptionError(msg) + + @staticmethod + def _try_str(val): + """ + On Python 2, much of distutils relies on string values being of + type 'str' (bytes) and not unicode text. If the value can be safely + encoded to bytes using the default encoding, prefer that. + + Why the default encoding? Because that value can be implicitly + decoded back to text if needed. + + Ref #1653 + """ + if six.PY3: + return val + try: + return val.encode() + except UnicodeEncodeError: + pass + return val + + def _set_command_options(self, command_obj, option_dict=None): + """ + Set the options for 'command_obj' from 'option_dict'. Basically + this means copying elements of a dictionary ('option_dict') to + attributes of an instance ('command'). + + 'command_obj' must be a Command instance. If 'option_dict' is not + supplied, uses the standard option dictionary for this command + (from 'self.command_options'). + + (Adopted from distutils.dist.Distribution._set_command_options) + """ + command_name = command_obj.get_command_name() + if option_dict is None: + option_dict = self.get_option_dict(command_name) + + if DEBUG: + self.announce(" setting options for '%s' command:" % command_name) + for (option, (source, value)) in option_dict.items(): + if DEBUG: + self.announce(" %s = %s (from %s)" % (option, value, + source)) + try: + bool_opts = [translate_longopt(o) + for o in command_obj.boolean_options] + except AttributeError: + bool_opts = [] + try: + neg_opt = command_obj.negative_opt + except AttributeError: + neg_opt = {} + + try: + is_string = isinstance(value, six.string_types) + if option in neg_opt and is_string: + setattr(command_obj, neg_opt[option], not strtobool(value)) + elif option in bool_opts and is_string: + setattr(command_obj, option, strtobool(value)) + elif hasattr(command_obj, option): + setattr(command_obj, option, value) + else: + raise DistutilsOptionError( + "error in %s: command '%s' has no such option '%s'" + % (source, command_name, option)) + except ValueError as msg: + raise DistutilsOptionError(msg) + + def parse_config_files(self, filenames=None, ignore_option_errors=False): + """Parses configuration files from various levels + and loads configuration. + + """ + self._parse_config_files(filenames=filenames) + + parse_configuration(self, self.command_options, + ignore_option_errors=ignore_option_errors) + self._finalize_requires() + + def parse_command_line(self): + """Process features after parsing command line options""" + result = _Distribution.parse_command_line(self) + if self.features: + self._finalize_features() + return result + + def _feature_attrname(self, name): + """Convert feature name to corresponding option attribute name""" + return 'with_' + name.replace('-', '_') + + def fetch_build_eggs(self, requires): + """Resolve pre-setup requirements""" + resolved_dists = pkg_resources.working_set.resolve( + pkg_resources.parse_requirements(requires), + installer=self.fetch_build_egg, + replace_conflicting=True, + ) + for dist in resolved_dists: + pkg_resources.working_set.add(dist, replace=True) + return resolved_dists + + def finalize_options(self): + """ + Allow plugins to apply arbitrary operations to the + distribution. Each hook may optionally define a 'order' + to influence the order of execution. Smaller numbers + go first and the default is 0. + """ + hook_key = 'setuptools.finalize_distribution_options' + + def by_order(hook): + return getattr(hook, 'order', 0) + eps = pkg_resources.iter_entry_points(hook_key) + for ep in sorted(eps, key=by_order): + ep.load()(self) + + def _finalize_setup_keywords(self): + for ep in pkg_resources.iter_entry_points('distutils.setup_keywords'): + value = getattr(self, ep.name, None) + if value is not None: + ep.require(installer=self.fetch_build_egg) + ep.load()(self, ep.name, value) + + def _finalize_2to3_doctests(self): + if getattr(self, 'convert_2to3_doctests', None): + # XXX may convert to set here when we can rely on set being builtin + self.convert_2to3_doctests = [ + os.path.abspath(p) + for p in self.convert_2to3_doctests + ] + else: + self.convert_2to3_doctests = [] + + def get_egg_cache_dir(self): + egg_cache_dir = os.path.join(os.curdir, '.eggs') + if not os.path.exists(egg_cache_dir): + os.mkdir(egg_cache_dir) + windows_support.hide_file(egg_cache_dir) + readme_txt_filename = os.path.join(egg_cache_dir, 'README.txt') + with open(readme_txt_filename, 'w') as f: + f.write('This directory contains eggs that were downloaded ' + 'by setuptools to build, test, and run plug-ins.\n\n') + f.write('This directory caches those eggs to prevent ' + 'repeated downloads.\n\n') + f.write('However, it is safe to delete this directory.\n\n') + + return egg_cache_dir + + def fetch_build_egg(self, req): + """Fetch an egg needed for building""" + from setuptools.installer import fetch_build_egg + return fetch_build_egg(self, req) + + def _finalize_feature_opts(self): + """Add --with-X/--without-X options based on optional features""" + + if not self.features: + return + + go = [] + no = self.negative_opt.copy() + + for name, feature in self.features.items(): + self._set_feature(name, None) + feature.validate(self) + + if feature.optional: + descr = feature.description + incdef = ' (default)' + excdef = '' + if not feature.include_by_default(): + excdef, incdef = incdef, excdef + + new = ( + ('with-' + name, None, 'include ' + descr + incdef), + ('without-' + name, None, 'exclude ' + descr + excdef), + ) + go.extend(new) + no['without-' + name] = 'with-' + name + + self.global_options = self.feature_options = go + self.global_options + self.negative_opt = self.feature_negopt = no + + def _finalize_features(self): + """Add/remove features and resolve dependencies between them""" + + # First, flag all the enabled items (and thus their dependencies) + for name, feature in self.features.items(): + enabled = self.feature_is_included(name) + if enabled or (enabled is None and feature.include_by_default()): + feature.include_in(self) + self._set_feature(name, 1) + + # Then disable the rest, so that off-by-default features don't + # get flagged as errors when they're required by an enabled feature + for name, feature in self.features.items(): + if not self.feature_is_included(name): + feature.exclude_from(self) + self._set_feature(name, 0) + + def get_command_class(self, command): + """Pluggable version of get_command_class()""" + if command in self.cmdclass: + return self.cmdclass[command] + + eps = pkg_resources.iter_entry_points('distutils.commands', command) + for ep in eps: + ep.require(installer=self.fetch_build_egg) + self.cmdclass[command] = cmdclass = ep.load() + return cmdclass + else: + return _Distribution.get_command_class(self, command) + + def print_commands(self): + for ep in pkg_resources.iter_entry_points('distutils.commands'): + if ep.name not in self.cmdclass: + # don't require extras as the commands won't be invoked + cmdclass = ep.resolve() + self.cmdclass[ep.name] = cmdclass + return _Distribution.print_commands(self) + + def get_command_list(self): + for ep in pkg_resources.iter_entry_points('distutils.commands'): + if ep.name not in self.cmdclass: + # don't require extras as the commands won't be invoked + cmdclass = ep.resolve() + self.cmdclass[ep.name] = cmdclass + return _Distribution.get_command_list(self) + + def _set_feature(self, name, status): + """Set feature's inclusion status""" + setattr(self, self._feature_attrname(name), status) + + def feature_is_included(self, name): + """Return 1 if feature is included, 0 if excluded, 'None' if unknown""" + return getattr(self, self._feature_attrname(name)) + + def include_feature(self, name): + """Request inclusion of feature named 'name'""" + + if self.feature_is_included(name) == 0: + descr = self.features[name].description + raise DistutilsOptionError( + descr + " is required, but was excluded or is not available" + ) + self.features[name].include_in(self) + self._set_feature(name, 1) + + def include(self, **attrs): + """Add items to distribution that are named in keyword arguments + + For example, 'dist.include(py_modules=["x"])' would add 'x' to + the distribution's 'py_modules' attribute, if it was not already + there. + + Currently, this method only supports inclusion for attributes that are + lists or tuples. If you need to add support for adding to other + attributes in this or a subclass, you can add an '_include_X' method, + where 'X' is the name of the attribute. The method will be called with + the value passed to 'include()'. So, 'dist.include(foo={"bar":"baz"})' + will try to call 'dist._include_foo({"bar":"baz"})', which can then + handle whatever special inclusion logic is needed. + """ + for k, v in attrs.items(): + include = getattr(self, '_include_' + k, None) + if include: + include(v) + else: + self._include_misc(k, v) + + def exclude_package(self, package): + """Remove packages, modules, and extensions in named package""" + + pfx = package + '.' + if self.packages: + self.packages = [ + p for p in self.packages + if p != package and not p.startswith(pfx) + ] + + if self.py_modules: + self.py_modules = [ + p for p in self.py_modules + if p != package and not p.startswith(pfx) + ] + + if self.ext_modules: + self.ext_modules = [ + p for p in self.ext_modules + if p.name != package and not p.name.startswith(pfx) + ] + + def has_contents_for(self, package): + """Return true if 'exclude_package(package)' would do something""" + + pfx = package + '.' + + for p in self.iter_distribution_names(): + if p == package or p.startswith(pfx): + return True + + def _exclude_misc(self, name, value): + """Handle 'exclude()' for list/tuple attrs without a special handler""" + if not isinstance(value, sequence): + raise DistutilsSetupError( + "%s: setting must be a list or tuple (%r)" % (name, value) + ) + try: + old = getattr(self, name) + except AttributeError: + raise DistutilsSetupError( + "%s: No such distribution setting" % name + ) + if old is not None and not isinstance(old, sequence): + raise DistutilsSetupError( + name + ": this setting cannot be changed via include/exclude" + ) + elif old: + setattr(self, name, [item for item in old if item not in value]) + + def _include_misc(self, name, value): + """Handle 'include()' for list/tuple attrs without a special handler""" + + if not isinstance(value, sequence): + raise DistutilsSetupError( + "%s: setting must be a list (%r)" % (name, value) + ) + try: + old = getattr(self, name) + except AttributeError: + raise DistutilsSetupError( + "%s: No such distribution setting" % name + ) + if old is None: + setattr(self, name, value) + elif not isinstance(old, sequence): + raise DistutilsSetupError( + name + ": this setting cannot be changed via include/exclude" + ) + else: + new = [item for item in value if item not in old] + setattr(self, name, old + new) + + def exclude(self, **attrs): + """Remove items from distribution that are named in keyword arguments + + For example, 'dist.exclude(py_modules=["x"])' would remove 'x' from + the distribution's 'py_modules' attribute. Excluding packages uses + the 'exclude_package()' method, so all of the package's contained + packages, modules, and extensions are also excluded. + + Currently, this method only supports exclusion from attributes that are + lists or tuples. If you need to add support for excluding from other + attributes in this or a subclass, you can add an '_exclude_X' method, + where 'X' is the name of the attribute. The method will be called with + the value passed to 'exclude()'. So, 'dist.exclude(foo={"bar":"baz"})' + will try to call 'dist._exclude_foo({"bar":"baz"})', which can then + handle whatever special exclusion logic is needed. + """ + for k, v in attrs.items(): + exclude = getattr(self, '_exclude_' + k, None) + if exclude: + exclude(v) + else: + self._exclude_misc(k, v) + + def _exclude_packages(self, packages): + if not isinstance(packages, sequence): + raise DistutilsSetupError( + "packages: setting must be a list or tuple (%r)" % (packages,) + ) + list(map(self.exclude_package, packages)) + + def _parse_command_opts(self, parser, args): + # Remove --with-X/--without-X options when processing command args + self.global_options = self.__class__.global_options + self.negative_opt = self.__class__.negative_opt + + # First, expand any aliases + command = args[0] + aliases = self.get_option_dict('aliases') + while command in aliases: + src, alias = aliases[command] + del aliases[command] # ensure each alias can expand only once! + import shlex + args[:1] = shlex.split(alias, True) + command = args[0] + + nargs = _Distribution._parse_command_opts(self, parser, args) + + # Handle commands that want to consume all remaining arguments + cmd_class = self.get_command_class(command) + if getattr(cmd_class, 'command_consumes_arguments', None): + self.get_option_dict(command)['args'] = ("command line", nargs) + if nargs is not None: + return [] + + return nargs + + def get_cmdline_options(self): + """Return a '{cmd: {opt:val}}' map of all command-line options + + Option names are all long, but do not include the leading '--', and + contain dashes rather than underscores. If the option doesn't take + an argument (e.g. '--quiet'), the 'val' is 'None'. + + Note that options provided by config files are intentionally excluded. + """ + + d = {} + + for cmd, opts in self.command_options.items(): + + for opt, (src, val) in opts.items(): + + if src != "command line": + continue + + opt = opt.replace('_', '-') + + if val == 0: + cmdobj = self.get_command_obj(cmd) + neg_opt = self.negative_opt.copy() + neg_opt.update(getattr(cmdobj, 'negative_opt', {})) + for neg, pos in neg_opt.items(): + if pos == opt: + opt = neg + val = None + break + else: + raise AssertionError("Shouldn't be able to get here") + + elif val == 1: + val = None + + d.setdefault(cmd, {})[opt] = val + + return d + + def iter_distribution_names(self): + """Yield all packages, modules, and extension names in distribution""" + + for pkg in self.packages or (): + yield pkg + + for module in self.py_modules or (): + yield module + + for ext in self.ext_modules or (): + if isinstance(ext, tuple): + name, buildinfo = ext + else: + name = ext.name + if name.endswith('module'): + name = name[:-6] + yield name + + def handle_display_options(self, option_order): + """If there were any non-global "display-only" options + (--help-commands or the metadata display options) on the command + line, display the requested info and return true; else return + false. + """ + import sys + + if six.PY2 or self.help_commands: + return _Distribution.handle_display_options(self, option_order) + + # Stdout may be StringIO (e.g. in tests) + if not isinstance(sys.stdout, io.TextIOWrapper): + return _Distribution.handle_display_options(self, option_order) + + # Don't wrap stdout if utf-8 is already the encoding. Provides + # workaround for #334. + if sys.stdout.encoding.lower() in ('utf-8', 'utf8'): + return _Distribution.handle_display_options(self, option_order) + + # Print metadata in UTF-8 no matter the platform + encoding = sys.stdout.encoding + errors = sys.stdout.errors + newline = sys.platform != 'win32' and '\n' or None + line_buffering = sys.stdout.line_buffering + + sys.stdout = io.TextIOWrapper( + sys.stdout.detach(), 'utf-8', errors, newline, line_buffering) + try: + return _Distribution.handle_display_options(self, option_order) + finally: + sys.stdout = io.TextIOWrapper( + sys.stdout.detach(), encoding, errors, newline, line_buffering) + + +class Feature: + """ + **deprecated** -- The `Feature` facility was never completely implemented + or supported, `has reported issues + <https://github.com/pypa/setuptools/issues/58>`_ and will be removed in + a future version. + + A subset of the distribution that can be excluded if unneeded/wanted + + Features are created using these keyword arguments: + + 'description' -- a short, human readable description of the feature, to + be used in error messages, and option help messages. + + 'standard' -- if true, the feature is included by default if it is + available on the current system. Otherwise, the feature is only + included if requested via a command line '--with-X' option, or if + another included feature requires it. The default setting is 'False'. + + 'available' -- if true, the feature is available for installation on the + current system. The default setting is 'True'. + + 'optional' -- if true, the feature's inclusion can be controlled from the + command line, using the '--with-X' or '--without-X' options. If + false, the feature's inclusion status is determined automatically, + based on 'availabile', 'standard', and whether any other feature + requires it. The default setting is 'True'. + + 'require_features' -- a string or sequence of strings naming features + that should also be included if this feature is included. Defaults to + empty list. May also contain 'Require' objects that should be + added/removed from the distribution. + + 'remove' -- a string or list of strings naming packages to be removed + from the distribution if this feature is *not* included. If the + feature *is* included, this argument is ignored. This argument exists + to support removing features that "crosscut" a distribution, such as + defining a 'tests' feature that removes all the 'tests' subpackages + provided by other features. The default for this argument is an empty + list. (Note: the named package(s) or modules must exist in the base + distribution when the 'setup()' function is initially called.) + + other keywords -- any other keyword arguments are saved, and passed to + the distribution's 'include()' and 'exclude()' methods when the + feature is included or excluded, respectively. So, for example, you + could pass 'packages=["a","b"]' to cause packages 'a' and 'b' to be + added or removed from the distribution as appropriate. + + A feature must include at least one 'requires', 'remove', or other + keyword argument. Otherwise, it can't affect the distribution in any way. + Note also that you can subclass 'Feature' to create your own specialized + feature types that modify the distribution in other ways when included or + excluded. See the docstrings for the various methods here for more detail. + Aside from the methods, the only feature attributes that distributions look + at are 'description' and 'optional'. + """ + + @staticmethod + def warn_deprecated(): + msg = ( + "Features are deprecated and will be removed in a future " + "version. See https://github.com/pypa/setuptools/issues/65." + ) + warnings.warn(msg, DistDeprecationWarning, stacklevel=3) + + def __init__( + self, description, standard=False, available=True, + optional=True, require_features=(), remove=(), **extras): + self.warn_deprecated() + + self.description = description + self.standard = standard + self.available = available + self.optional = optional + if isinstance(require_features, (str, Require)): + require_features = require_features, + + self.require_features = [ + r for r in require_features if isinstance(r, str) + ] + er = [r for r in require_features if not isinstance(r, str)] + if er: + extras['require_features'] = er + + if isinstance(remove, str): + remove = remove, + self.remove = remove + self.extras = extras + + if not remove and not require_features and not extras: + raise DistutilsSetupError( + "Feature %s: must define 'require_features', 'remove', or " + "at least one of 'packages', 'py_modules', etc." + ) + + def include_by_default(self): + """Should this feature be included by default?""" + return self.available and self.standard + + def include_in(self, dist): + """Ensure feature and its requirements are included in distribution + + You may override this in a subclass to perform additional operations on + the distribution. Note that this method may be called more than once + per feature, and so should be idempotent. + + """ + + if not self.available: + raise DistutilsPlatformError( + self.description + " is required, " + "but is not available on this platform" + ) + + dist.include(**self.extras) + + for f in self.require_features: + dist.include_feature(f) + + def exclude_from(self, dist): + """Ensure feature is excluded from distribution + + You may override this in a subclass to perform additional operations on + the distribution. This method will be called at most once per + feature, and only after all included features have been asked to + include themselves. + """ + + dist.exclude(**self.extras) + + if self.remove: + for item in self.remove: + dist.exclude_package(item) + + def validate(self, dist): + """Verify that feature makes sense in context of distribution + + This method is called by the distribution just before it parses its + command line. It checks to ensure that the 'remove' attribute, if any, + contains only valid package/module names that are present in the base + distribution when 'setup()' is called. You may override it in a + subclass to perform any other required validation of the feature + against a target distribution. + """ + + for item in self.remove: + if not dist.has_contents_for(item): + raise DistutilsSetupError( + "%s wants to be able to remove %s, but the distribution" + " doesn't contain any packages or modules under %s" + % (self.description, item, item) + ) + + +class DistDeprecationWarning(SetuptoolsDeprecationWarning): + """Class for warning about deprecations in dist in + setuptools. Not ignored by default, unlike DeprecationWarning.""" diff --git a/venv/lib/python3.8/site-packages/setuptools/errors.py b/venv/lib/python3.8/site-packages/setuptools/errors.py new file mode 100644 index 0000000..2701747 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/errors.py @@ -0,0 +1,16 @@ +"""setuptools.errors + +Provides exceptions used by setuptools modules. +""" + +from distutils.errors import DistutilsError + + +class RemovedCommandError(DistutilsError, RuntimeError): + """Error used for commands that have been removed in setuptools. + + Since ``setuptools`` is built on ``distutils``, simply removing a command + from ``setuptools`` will make the behavior fall back to ``distutils``; this + error is raised if a command exists in ``distutils`` but has been actively + removed in ``setuptools``. + """ diff --git a/venv/lib/python3.8/site-packages/setuptools/extension.py b/venv/lib/python3.8/site-packages/setuptools/extension.py new file mode 100644 index 0000000..2946889 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/extension.py @@ -0,0 +1,57 @@ +import re +import functools +import distutils.core +import distutils.errors +import distutils.extension + +from setuptools.extern.six.moves import map + +from .monkey import get_unpatched + + +def _have_cython(): + """ + Return True if Cython can be imported. + """ + cython_impl = 'Cython.Distutils.build_ext' + try: + # from (cython_impl) import build_ext + __import__(cython_impl, fromlist=['build_ext']).build_ext + return True + except Exception: + pass + return False + + +# for compatibility +have_pyrex = _have_cython + +_Extension = get_unpatched(distutils.core.Extension) + + +class Extension(_Extension): + """Extension that uses '.c' files in place of '.pyx' files""" + + def __init__(self, name, sources, *args, **kw): + # The *args is needed for compatibility as calls may use positional + # arguments. py_limited_api may be set only via keyword. + self.py_limited_api = kw.pop("py_limited_api", False) + _Extension.__init__(self, name, sources, *args, **kw) + + def _convert_pyx_sources_to_lang(self): + """ + Replace sources with .pyx extensions to sources with the target + language extension. This mechanism allows language authors to supply + pre-converted sources but to prefer the .pyx sources. + """ + if _have_cython(): + # the build has Cython, so allow it to compile the .pyx files + return + lang = self.language or '' + target_ext = '.cpp' if lang.lower() == 'c++' else '.c' + sub = functools.partial(re.sub, '.pyx$', target_ext) + self.sources = list(map(sub, self.sources)) + + +class Library(Extension): + """Just like a regular Extension, but built as a library instead""" diff --git a/venv/lib/python3.8/site-packages/setuptools/extern/__init__.py b/venv/lib/python3.8/site-packages/setuptools/extern/__init__.py new file mode 100644 index 0000000..e8c616f --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/extern/__init__.py @@ -0,0 +1,73 @@ +import sys + + +class VendorImporter: + """ + A PEP 302 meta path importer for finding optionally-vendored + or otherwise naturally-installed packages from root_name. + """ + + def __init__(self, root_name, vendored_names=(), vendor_pkg=None): + self.root_name = root_name + self.vendored_names = set(vendored_names) + self.vendor_pkg = vendor_pkg or root_name.replace('extern', '_vendor') + + @property + def search_path(self): + """ + Search first the vendor package then as a natural package. + """ + yield self.vendor_pkg + '.' + yield '' + + def find_module(self, fullname, path=None): + """ + Return self when fullname starts with root_name and the + target module is one vendored through this importer. + """ + root, base, target = fullname.partition(self.root_name + '.') + if root: + return + if not any(map(target.startswith, self.vendored_names)): + return + return self + + def load_module(self, fullname): + """ + Iterate over the search path to locate and load fullname. + """ + root, base, target = fullname.partition(self.root_name + '.') + for prefix in self.search_path: + try: + extant = prefix + target + __import__(extant) + mod = sys.modules[extant] + sys.modules[fullname] = mod + # mysterious hack: + # Remove the reference to the extant package/module + # on later Python versions to cause relative imports + # in the vendor package to resolve the same modules + # as those going through this importer. + if sys.version_info >= (3, ): + del sys.modules[extant] + return mod + except ImportError: + pass + else: + raise ImportError( + "The '{target}' package is required; " + "normally this is bundled with this package so if you get " + "this warning, consult the packager of your " + "distribution.".format(**locals()) + ) + + def install(self): + """ + Install this importer into sys.meta_path if not already present. + """ + if self not in sys.meta_path: + sys.meta_path.append(self) + + +names = 'six', 'packaging', 'pyparsing', 'ordered_set', +VendorImporter(__name__, names, 'setuptools._vendor').install() diff --git a/venv/lib/python3.8/site-packages/setuptools/glob.py b/venv/lib/python3.8/site-packages/setuptools/glob.py new file mode 100644 index 0000000..9d7cbc5 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/glob.py @@ -0,0 +1,174 @@ +""" +Filename globbing utility. Mostly a copy of `glob` from Python 3.5. + +Changes include: + * `yield from` and PEP3102 `*` removed. + * Hidden files are not ignored. +""" + +import os +import re +import fnmatch + +__all__ = ["glob", "iglob", "escape"] + + +def glob(pathname, recursive=False): + """Return a list of paths matching a pathname pattern. + + The pattern may contain simple shell-style wildcards a la + fnmatch. However, unlike fnmatch, filenames starting with a + dot are special cases that are not matched by '*' and '?' + patterns. + + If recursive is true, the pattern '**' will match any files and + zero or more directories and subdirectories. + """ + return list(iglob(pathname, recursive=recursive)) + + +def iglob(pathname, recursive=False): + """Return an iterator which yields the paths matching a pathname pattern. + + The pattern may contain simple shell-style wildcards a la + fnmatch. However, unlike fnmatch, filenames starting with a + dot are special cases that are not matched by '*' and '?' + patterns. + + If recursive is true, the pattern '**' will match any files and + zero or more directories and subdirectories. + """ + it = _iglob(pathname, recursive) + if recursive and _isrecursive(pathname): + s = next(it) # skip empty string + assert not s + return it + + +def _iglob(pathname, recursive): + dirname, basename = os.path.split(pathname) + if not has_magic(pathname): + if basename: + if os.path.lexists(pathname): + yield pathname + else: + # Patterns ending with a slash should match only directories + if os.path.isdir(dirname): + yield pathname + return + if not dirname: + if recursive and _isrecursive(basename): + for x in glob2(dirname, basename): + yield x + else: + for x in glob1(dirname, basename): + yield x + return + # `os.path.split()` returns the argument itself as a dirname if it is a + # drive or UNC path. Prevent an infinite recursion if a drive or UNC path + # contains magic characters (i.e. r'\\?\C:'). + if dirname != pathname and has_magic(dirname): + dirs = _iglob(dirname, recursive) + else: + dirs = [dirname] + if has_magic(basename): + if recursive and _isrecursive(basename): + glob_in_dir = glob2 + else: + glob_in_dir = glob1 + else: + glob_in_dir = glob0 + for dirname in dirs: + for name in glob_in_dir(dirname, basename): + yield os.path.join(dirname, name) + + +# These 2 helper functions non-recursively glob inside a literal directory. +# They return a list of basenames. `glob1` accepts a pattern while `glob0` +# takes a literal basename (so it only has to check for its existence). + + +def glob1(dirname, pattern): + if not dirname: + if isinstance(pattern, bytes): + dirname = os.curdir.encode('ASCII') + else: + dirname = os.curdir + try: + names = os.listdir(dirname) + except OSError: + return [] + return fnmatch.filter(names, pattern) + + +def glob0(dirname, basename): + if not basename: + # `os.path.split()` returns an empty basename for paths ending with a + # directory separator. 'q*x/' should match only directories. + if os.path.isdir(dirname): + return [basename] + else: + if os.path.lexists(os.path.join(dirname, basename)): + return [basename] + return [] + + +# This helper function recursively yields relative pathnames inside a literal +# directory. + + +def glob2(dirname, pattern): + assert _isrecursive(pattern) + yield pattern[:0] + for x in _rlistdir(dirname): + yield x + + +# Recursively yields relative pathnames inside a literal directory. +def _rlistdir(dirname): + if not dirname: + if isinstance(dirname, bytes): + dirname = os.curdir.encode('ASCII') + else: + dirname = os.curdir + try: + names = os.listdir(dirname) + except os.error: + return + for x in names: + yield x + path = os.path.join(dirname, x) if dirname else x + for y in _rlistdir(path): + yield os.path.join(x, y) + + +magic_check = re.compile('([*?[])') +magic_check_bytes = re.compile(b'([*?[])') + + +def has_magic(s): + if isinstance(s, bytes): + match = magic_check_bytes.search(s) + else: + match = magic_check.search(s) + return match is not None + + +def _isrecursive(pattern): + if isinstance(pattern, bytes): + return pattern == b'**' + else: + return pattern == '**' + + +def escape(pathname): + """Escape all special characters. + """ + # Escaping is done by wrapping any of "*?[" between square brackets. + # Metacharacters do not work in the drive part and shouldn't be escaped. + drive, pathname = os.path.splitdrive(pathname) + if isinstance(pathname, bytes): + pathname = magic_check_bytes.sub(br'[\1]', pathname) + else: + pathname = magic_check.sub(r'[\1]', pathname) + return drive + pathname diff --git a/venv/lib/python3.8/site-packages/setuptools/gui-32.exe b/venv/lib/python3.8/site-packages/setuptools/gui-32.exe new file mode 100644 index 0000000000000000000000000000000000000000..f8d3509653ba8f80ca7f3aa7f95616142ba83a94 GIT binary patch literal 65536 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/setuptools/gui-64.exe b/venv/lib/python3.8/site-packages/setuptools/gui-64.exe new file mode 100644 index 0000000000000000000000000000000000000000..330c51a5dde15a0bb610a48cd0ca11770c914dae GIT binary patch literal 75264 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/setuptools/gui.exe b/venv/lib/python3.8/site-packages/setuptools/gui.exe new file mode 100644 index 0000000000000000000000000000000000000000..f8d3509653ba8f80ca7f3aa7f95616142ba83a94 GIT binary patch literal 65536 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/setuptools/installer.py b/venv/lib/python3.8/site-packages/setuptools/installer.py new file mode 100644 index 0000000..9f8be2e --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/installer.py @@ -0,0 +1,150 @@ +import glob +import os +import subprocess +import sys +from distutils import log +from distutils.errors import DistutilsError + +import pkg_resources +from setuptools.command.easy_install import easy_install +from setuptools.extern import six +from setuptools.wheel import Wheel + +from .py31compat import TemporaryDirectory + + +def _fixup_find_links(find_links): + """Ensure find-links option end-up being a list of strings.""" + if isinstance(find_links, six.string_types): + return find_links.split() + assert isinstance(find_links, (tuple, list)) + return find_links + + +def _legacy_fetch_build_egg(dist, req): + """Fetch an egg needed for building. + + Legacy path using EasyInstall. + """ + tmp_dist = dist.__class__({'script_args': ['easy_install']}) + opts = tmp_dist.get_option_dict('easy_install') + opts.clear() + opts.update( + (k, v) + for k, v in dist.get_option_dict('easy_install').items() + if k in ( + # don't use any other settings + 'find_links', 'site_dirs', 'index_url', + 'optimize', 'site_dirs', 'allow_hosts', + )) + if dist.dependency_links: + links = dist.dependency_links[:] + if 'find_links' in opts: + links = _fixup_find_links(opts['find_links'][1]) + links + opts['find_links'] = ('setup', links) + install_dir = dist.get_egg_cache_dir() + cmd = easy_install( + tmp_dist, args=["x"], install_dir=install_dir, + exclude_scripts=True, + always_copy=False, build_directory=None, editable=False, + upgrade=False, multi_version=True, no_report=True, user=False + ) + cmd.ensure_finalized() + return cmd.easy_install(req) + + +def fetch_build_egg(dist, req): + """Fetch an egg needed for building. + + Use pip/wheel to fetch/build a wheel.""" + # Check pip is available. + try: + pkg_resources.get_distribution('pip') + except pkg_resources.DistributionNotFound: + dist.announce( + 'WARNING: The pip package is not available, falling back ' + 'to EasyInstall for handling setup_requires/test_requires; ' + 'this is deprecated and will be removed in a future version.' + , log.WARN + ) + return _legacy_fetch_build_egg(dist, req) + # Warn if wheel is not. + try: + pkg_resources.get_distribution('wheel') + except pkg_resources.DistributionNotFound: + dist.announce('WARNING: The wheel package is not available.', log.WARN) + # Ignore environment markers; if supplied, it is required. + req = strip_marker(req) + # Take easy_install options into account, but do not override relevant + # pip environment variables (like PIP_INDEX_URL or PIP_QUIET); they'll + # take precedence. + opts = dist.get_option_dict('easy_install') + if 'allow_hosts' in opts: + raise DistutilsError('the `allow-hosts` option is not supported ' + 'when using pip to install requirements.') + if 'PIP_QUIET' in os.environ or 'PIP_VERBOSE' in os.environ: + quiet = False + else: + quiet = True + if 'PIP_INDEX_URL' in os.environ: + index_url = None + elif 'index_url' in opts: + index_url = opts['index_url'][1] + else: + index_url = None + if 'find_links' in opts: + find_links = _fixup_find_links(opts['find_links'][1])[:] + else: + find_links = [] + if dist.dependency_links: + find_links.extend(dist.dependency_links) + eggs_dir = os.path.realpath(dist.get_egg_cache_dir()) + environment = pkg_resources.Environment() + for egg_dist in pkg_resources.find_distributions(eggs_dir): + if egg_dist in req and environment.can_add(egg_dist): + return egg_dist + with TemporaryDirectory() as tmpdir: + cmd = [ + sys.executable, '-m', 'pip', + '--disable-pip-version-check', + 'wheel', '--no-deps', + '-w', tmpdir, + ] + if quiet: + cmd.append('--quiet') + if index_url is not None: + cmd.extend(('--index-url', index_url)) + if find_links is not None: + for link in find_links: + cmd.extend(('--find-links', link)) + # If requirement is a PEP 508 direct URL, directly pass + # the URL to pip, as `req @ url` does not work on the + # command line. + if req.url: + cmd.append(req.url) + else: + cmd.append(str(req)) + try: + subprocess.check_call(cmd) + except subprocess.CalledProcessError as e: + raise DistutilsError(str(e)) + wheel = Wheel(glob.glob(os.path.join(tmpdir, '*.whl'))[0]) + dist_location = os.path.join(eggs_dir, wheel.egg_name()) + wheel.install_as_egg(dist_location) + dist_metadata = pkg_resources.PathMetadata( + dist_location, os.path.join(dist_location, 'EGG-INFO')) + dist = pkg_resources.Distribution.from_filename( + dist_location, metadata=dist_metadata) + return dist + + +def strip_marker(req): + """ + Return a new requirement without the environment marker to avoid + calling pip with something like `babel; extra == "i18n"`, which + would always be ignored. + """ + # create a copy to avoid mutating the input + req = pkg_resources.Requirement.parse(str(req)) + req.marker = None + return req diff --git a/venv/lib/python3.8/site-packages/setuptools/launch.py b/venv/lib/python3.8/site-packages/setuptools/launch.py new file mode 100644 index 0000000..308283e --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/launch.py @@ -0,0 +1,35 @@ +""" +Launch the Python script on the command line after +setuptools is bootstrapped via import. +""" + +# Note that setuptools gets imported implicitly by the +# invocation of this script using python -m setuptools.launch + +import tokenize +import sys + + +def run(): + """ + Run the script in sys.argv[1] as if it had + been invoked naturally. + """ + __builtins__ + script_name = sys.argv[1] + namespace = dict( + __file__=script_name, + __name__='__main__', + __doc__=None, + ) + sys.argv[:] = sys.argv[1:] + + open_ = getattr(tokenize, 'open', open) + script = open_(script_name).read() + norm_script = script.replace('\\r\\n', '\\n') + code = compile(norm_script, script_name, 'exec') + exec(code, namespace) + + +if __name__ == '__main__': + run() diff --git a/venv/lib/python3.8/site-packages/setuptools/lib2to3_ex.py b/venv/lib/python3.8/site-packages/setuptools/lib2to3_ex.py new file mode 100644 index 0000000..4b1a73f --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/lib2to3_ex.py @@ -0,0 +1,62 @@ +""" +Customized Mixin2to3 support: + + - adds support for converting doctests + + +This module raises an ImportError on Python 2. +""" + +from distutils.util import Mixin2to3 as _Mixin2to3 +from distutils import log +from lib2to3.refactor import RefactoringTool, get_fixers_from_package + +import setuptools + + +class DistutilsRefactoringTool(RefactoringTool): + def log_error(self, msg, *args, **kw): + log.error(msg, *args) + + def log_message(self, msg, *args): + log.info(msg, *args) + + def log_debug(self, msg, *args): + log.debug(msg, *args) + + +class Mixin2to3(_Mixin2to3): + def run_2to3(self, files, doctests=False): + # See of the distribution option has been set, otherwise check the + # setuptools default. + if self.distribution.use_2to3 is not True: + return + if not files: + return + log.info("Fixing " + " ".join(files)) + self.__build_fixer_names() + self.__exclude_fixers() + if doctests: + if setuptools.run_2to3_on_doctests: + r = DistutilsRefactoringTool(self.fixer_names) + r.refactor(files, write=True, doctests_only=True) + else: + _Mixin2to3.run_2to3(self, files) + + def __build_fixer_names(self): + if self.fixer_names: + return + self.fixer_names = [] + for p in setuptools.lib2to3_fixer_packages: + self.fixer_names.extend(get_fixers_from_package(p)) + if self.distribution.use_2to3_fixers is not None: + for p in self.distribution.use_2to3_fixers: + self.fixer_names.extend(get_fixers_from_package(p)) + + def __exclude_fixers(self): + excluded_fixers = getattr(self, 'exclude_fixers', []) + if self.distribution.use_2to3_exclude_fixers is not None: + excluded_fixers.extend(self.distribution.use_2to3_exclude_fixers) + for fixer_name in excluded_fixers: + if fixer_name in self.fixer_names: + self.fixer_names.remove(fixer_name) diff --git a/venv/lib/python3.8/site-packages/setuptools/monkey.py b/venv/lib/python3.8/site-packages/setuptools/monkey.py new file mode 100644 index 0000000..3c77f8c --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/monkey.py @@ -0,0 +1,179 @@ +""" +Monkey patching of distutils. +""" + +import sys +import distutils.filelist +import platform +import types +import functools +from importlib import import_module +import inspect + +from setuptools.extern import six + +import setuptools + +__all__ = [] +""" +Everything is private. Contact the project team +if you think you need this functionality. +""" + + +def _get_mro(cls): + """ + Returns the bases classes for cls sorted by the MRO. + + Works around an issue on Jython where inspect.getmro will not return all + base classes if multiple classes share the same name. Instead, this + function will return a tuple containing the class itself, and the contents + of cls.__bases__. See https://github.com/pypa/setuptools/issues/1024. + """ + if platform.python_implementation() == "Jython": + return (cls,) + cls.__bases__ + return inspect.getmro(cls) + + +def get_unpatched(item): + lookup = ( + get_unpatched_class if isinstance(item, six.class_types) else + get_unpatched_function if isinstance(item, types.FunctionType) else + lambda item: None + ) + return lookup(item) + + +def get_unpatched_class(cls): + """Protect against re-patching the distutils if reloaded + + Also ensures that no other distutils extension monkeypatched the distutils + first. + """ + external_bases = ( + cls + for cls in _get_mro(cls) + if not cls.__module__.startswith('setuptools') + ) + base = next(external_bases) + if not base.__module__.startswith('distutils'): + msg = "distutils has already been patched by %r" % cls + raise AssertionError(msg) + return base + + +def patch_all(): + # we can't patch distutils.cmd, alas + distutils.core.Command = setuptools.Command + + has_issue_12885 = sys.version_info <= (3, 5, 3) + + if has_issue_12885: + # fix findall bug in distutils (http://bugs.python.org/issue12885) + distutils.filelist.findall = setuptools.findall + + needs_warehouse = ( + sys.version_info < (2, 7, 13) + or + (3, 4) < sys.version_info < (3, 4, 6) + or + (3, 5) < sys.version_info <= (3, 5, 3) + ) + + if needs_warehouse: + warehouse = 'https://upload.pypi.org/legacy/' + distutils.config.PyPIRCCommand.DEFAULT_REPOSITORY = warehouse + + _patch_distribution_metadata() + + # Install Distribution throughout the distutils + for module in distutils.dist, distutils.core, distutils.cmd: + module.Distribution = setuptools.dist.Distribution + + # Install the patched Extension + distutils.core.Extension = setuptools.extension.Extension + distutils.extension.Extension = setuptools.extension.Extension + if 'distutils.command.build_ext' in sys.modules: + sys.modules['distutils.command.build_ext'].Extension = ( + setuptools.extension.Extension + ) + + patch_for_msvc_specialized_compiler() + + +def _patch_distribution_metadata(): + """Patch write_pkg_file and read_pkg_file for higher metadata standards""" + for attr in ('write_pkg_file', 'read_pkg_file', 'get_metadata_version'): + new_val = getattr(setuptools.dist, attr) + setattr(distutils.dist.DistributionMetadata, attr, new_val) + + +def patch_func(replacement, target_mod, func_name): + """ + Patch func_name in target_mod with replacement + + Important - original must be resolved by name to avoid + patching an already patched function. + """ + original = getattr(target_mod, func_name) + + # set the 'unpatched' attribute on the replacement to + # point to the original. + vars(replacement).setdefault('unpatched', original) + + # replace the function in the original module + setattr(target_mod, func_name, replacement) + + +def get_unpatched_function(candidate): + return getattr(candidate, 'unpatched') + + +def patch_for_msvc_specialized_compiler(): + """ + Patch functions in distutils to use standalone Microsoft Visual C++ + compilers. + """ + # import late to avoid circular imports on Python < 3.5 + msvc = import_module('setuptools.msvc') + + if platform.system() != 'Windows': + # Compilers only availables on Microsoft Windows + return + + def patch_params(mod_name, func_name): + """ + Prepare the parameters for patch_func to patch indicated function. + """ + repl_prefix = 'msvc9_' if 'msvc9' in mod_name else 'msvc14_' + repl_name = repl_prefix + func_name.lstrip('_') + repl = getattr(msvc, repl_name) + mod = import_module(mod_name) + if not hasattr(mod, func_name): + raise ImportError(func_name) + return repl, mod, func_name + + # Python 2.7 to 3.4 + msvc9 = functools.partial(patch_params, 'distutils.msvc9compiler') + + # Python 3.5+ + msvc14 = functools.partial(patch_params, 'distutils._msvccompiler') + + try: + # Patch distutils.msvc9compiler + patch_func(*msvc9('find_vcvarsall')) + patch_func(*msvc9('query_vcvarsall')) + except ImportError: + pass + + try: + # Patch distutils._msvccompiler._get_vc_env + patch_func(*msvc14('_get_vc_env')) + except ImportError: + pass + + try: + # Patch distutils._msvccompiler.gen_lib_options for Numpy + patch_func(*msvc14('gen_lib_options')) + except ImportError: + pass diff --git a/venv/lib/python3.8/site-packages/setuptools/msvc.py b/venv/lib/python3.8/site-packages/setuptools/msvc.py new file mode 100644 index 0000000..2ffe1c8 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/msvc.py @@ -0,0 +1,1679 @@ +""" +Improved support for Microsoft Visual C++ compilers. + +Known supported compilers: +-------------------------- +Microsoft Visual C++ 9.0: + Microsoft Visual C++ Compiler for Python 2.7 (x86, amd64) + Microsoft Windows SDK 6.1 (x86, x64, ia64) + Microsoft Windows SDK 7.0 (x86, x64, ia64) + +Microsoft Visual C++ 10.0: + Microsoft Windows SDK 7.1 (x86, x64, ia64) + +Microsoft Visual C++ 14.X: + Microsoft Visual C++ Build Tools 2015 (x86, x64, arm) + Microsoft Visual Studio Build Tools 2017 (x86, x64, arm, arm64) + Microsoft Visual Studio Build Tools 2019 (x86, x64, arm, arm64) + +This may also support compilers shipped with compatible Visual Studio versions. +""" + +import json +from io import open +from os import listdir, pathsep +from os.path import join, isfile, isdir, dirname +import sys +import platform +import itertools +import distutils.errors +from setuptools.extern.packaging.version import LegacyVersion + +from setuptools.extern.six.moves import filterfalse + +from .monkey import get_unpatched + +if platform.system() == 'Windows': + from setuptools.extern.six.moves import winreg + from os import environ +else: + # Mock winreg and environ so the module can be imported on this platform. + + class winreg: + HKEY_USERS = None + HKEY_CURRENT_USER = None + HKEY_LOCAL_MACHINE = None + HKEY_CLASSES_ROOT = None + + environ = dict() + +_msvc9_suppress_errors = ( + # msvc9compiler isn't available on some platforms + ImportError, + + # msvc9compiler raises DistutilsPlatformError in some + # environments. See #1118. + distutils.errors.DistutilsPlatformError, +) + +try: + from distutils.msvc9compiler import Reg +except _msvc9_suppress_errors: + pass + + +def msvc9_find_vcvarsall(version): + """ + Patched "distutils.msvc9compiler.find_vcvarsall" to use the standalone + compiler build for Python + (VCForPython / Microsoft Visual C++ Compiler for Python 2.7). + + Fall back to original behavior when the standalone compiler is not + available. + + Redirect the path of "vcvarsall.bat". + + Parameters + ---------- + version: float + Required Microsoft Visual C++ version. + + Return + ------ + str + vcvarsall.bat path + """ + vc_base = r'Software\%sMicrosoft\DevDiv\VCForPython\%0.1f' + key = vc_base % ('', version) + try: + # Per-user installs register the compiler path here + productdir = Reg.get_value(key, "installdir") + except KeyError: + try: + # All-user installs on a 64-bit system register here + key = vc_base % ('Wow6432Node\\', version) + productdir = Reg.get_value(key, "installdir") + except KeyError: + productdir = None + + if productdir: + vcvarsall = join(productdir, "vcvarsall.bat") + if isfile(vcvarsall): + return vcvarsall + + return get_unpatched(msvc9_find_vcvarsall)(version) + + +def msvc9_query_vcvarsall(ver, arch='x86', *args, **kwargs): + """ + Patched "distutils.msvc9compiler.query_vcvarsall" for support extra + Microsoft Visual C++ 9.0 and 10.0 compilers. + + Set environment without use of "vcvarsall.bat". + + Parameters + ---------- + ver: float + Required Microsoft Visual C++ version. + arch: str + Target architecture. + + Return + ------ + dict + environment + """ + # Try to get environment from vcvarsall.bat (Classical way) + try: + orig = get_unpatched(msvc9_query_vcvarsall) + return orig(ver, arch, *args, **kwargs) + except distutils.errors.DistutilsPlatformError: + # Pass error if Vcvarsall.bat is missing + pass + except ValueError: + # Pass error if environment not set after executing vcvarsall.bat + pass + + # If error, try to set environment directly + try: + return EnvironmentInfo(arch, ver).return_env() + except distutils.errors.DistutilsPlatformError as exc: + _augment_exception(exc, ver, arch) + raise + + +def msvc14_get_vc_env(plat_spec): + """ + Patched "distutils._msvccompiler._get_vc_env" for support extra + Microsoft Visual C++ 14.X compilers. + + Set environment without use of "vcvarsall.bat". + + Parameters + ---------- + plat_spec: str + Target architecture. + + Return + ------ + dict + environment + """ + # Try to get environment from vcvarsall.bat (Classical way) + try: + return get_unpatched(msvc14_get_vc_env)(plat_spec) + except distutils.errors.DistutilsPlatformError: + # Pass error Vcvarsall.bat is missing + pass + + # If error, try to set environment directly + try: + return EnvironmentInfo(plat_spec, vc_min_ver=14.0).return_env() + except distutils.errors.DistutilsPlatformError as exc: + _augment_exception(exc, 14.0) + raise + + +def msvc14_gen_lib_options(*args, **kwargs): + """ + Patched "distutils._msvccompiler.gen_lib_options" for fix + compatibility between "numpy.distutils" and "distutils._msvccompiler" + (for Numpy < 1.11.2) + """ + if "numpy.distutils" in sys.modules: + import numpy as np + if LegacyVersion(np.__version__) < LegacyVersion('1.11.2'): + return np.distutils.ccompiler.gen_lib_options(*args, **kwargs) + return get_unpatched(msvc14_gen_lib_options)(*args, **kwargs) + + +def _augment_exception(exc, version, arch=''): + """ + Add details to the exception message to help guide the user + as to what action will resolve it. + """ + # Error if MSVC++ directory not found or environment not set + message = exc.args[0] + + if "vcvarsall" in message.lower() or "visual c" in message.lower(): + # Special error message if MSVC++ not installed + tmpl = 'Microsoft Visual C++ {version:0.1f} is required.' + message = tmpl.format(**locals()) + msdownload = 'www.microsoft.com/download/details.aspx?id=%d' + if version == 9.0: + if arch.lower().find('ia64') > -1: + # For VC++ 9.0, if IA64 support is needed, redirect user + # to Windows SDK 7.0. + # Note: No download link available from Microsoft. + message += ' Get it with "Microsoft Windows SDK 7.0"' + else: + # For VC++ 9.0 redirect user to Vc++ for Python 2.7 : + # This redirection link is maintained by Microsoft. + # Contact vspython@microsoft.com if it needs updating. + message += ' Get it from http://aka.ms/vcpython27' + elif version == 10.0: + # For VC++ 10.0 Redirect user to Windows SDK 7.1 + message += ' Get it with "Microsoft Windows SDK 7.1": ' + message += msdownload % 8279 + elif version >= 14.0: + # For VC++ 14.X Redirect user to latest Visual C++ Build Tools + message += (' Get it with "Build Tools for Visual Studio": ' + r'https://visualstudio.microsoft.com/downloads/') + + exc.args = (message, ) + + +class PlatformInfo: + """ + Current and Target Architectures information. + + Parameters + ---------- + arch: str + Target architecture. + """ + current_cpu = environ.get('processor_architecture', '').lower() + + def __init__(self, arch): + self.arch = arch.lower().replace('x64', 'amd64') + + @property + def target_cpu(self): + """ + Return Target CPU architecture. + + Return + ------ + str + Target CPU + """ + return self.arch[self.arch.find('_') + 1:] + + def target_is_x86(self): + """ + Return True if target CPU is x86 32 bits.. + + Return + ------ + bool + CPU is x86 32 bits + """ + return self.target_cpu == 'x86' + + def current_is_x86(self): + """ + Return True if current CPU is x86 32 bits.. + + Return + ------ + bool + CPU is x86 32 bits + """ + return self.current_cpu == 'x86' + + def current_dir(self, hidex86=False, x64=False): + """ + Current platform specific subfolder. + + Parameters + ---------- + hidex86: bool + return '' and not '\x86' if architecture is x86. + x64: bool + return '\x64' and not '\amd64' if architecture is amd64. + + Return + ------ + str + subfolder: '\target', or '' (see hidex86 parameter) + """ + return ( + '' if (self.current_cpu == 'x86' and hidex86) else + r'\x64' if (self.current_cpu == 'amd64' and x64) else + r'\%s' % self.current_cpu + ) + + def target_dir(self, hidex86=False, x64=False): + r""" + Target platform specific subfolder. + + Parameters + ---------- + hidex86: bool + return '' and not '\x86' if architecture is x86. + x64: bool + return '\x64' and not '\amd64' if architecture is amd64. + + Return + ------ + str + subfolder: '\current', or '' (see hidex86 parameter) + """ + return ( + '' if (self.target_cpu == 'x86' and hidex86) else + r'\x64' if (self.target_cpu == 'amd64' and x64) else + r'\%s' % self.target_cpu + ) + + def cross_dir(self, forcex86=False): + r""" + Cross platform specific subfolder. + + Parameters + ---------- + forcex86: bool + Use 'x86' as current architecture even if current architecture is + not x86. + + Return + ------ + str + subfolder: '' if target architecture is current architecture, + '\current_target' if not. + """ + current = 'x86' if forcex86 else self.current_cpu + return ( + '' if self.target_cpu == current else + self.target_dir().replace('\\', '\\%s_' % current) + ) + + +class RegistryInfo: + """ + Microsoft Visual Studio related registry information. + + Parameters + ---------- + platform_info: PlatformInfo + "PlatformInfo" instance. + """ + HKEYS = (winreg.HKEY_USERS, + winreg.HKEY_CURRENT_USER, + winreg.HKEY_LOCAL_MACHINE, + winreg.HKEY_CLASSES_ROOT) + + def __init__(self, platform_info): + self.pi = platform_info + + @property + def visualstudio(self): + """ + Microsoft Visual Studio root registry key. + + Return + ------ + str + Registry key + """ + return 'VisualStudio' + + @property + def sxs(self): + """ + Microsoft Visual Studio SxS registry key. + + Return + ------ + str + Registry key + """ + return join(self.visualstudio, 'SxS') + + @property + def vc(self): + """ + Microsoft Visual C++ VC7 registry key. + + Return + ------ + str + Registry key + """ + return join(self.sxs, 'VC7') + + @property + def vs(self): + """ + Microsoft Visual Studio VS7 registry key. + + Return + ------ + str + Registry key + """ + return join(self.sxs, 'VS7') + + @property + def vc_for_python(self): + """ + Microsoft Visual C++ for Python registry key. + + Return + ------ + str + Registry key + """ + return r'DevDiv\VCForPython' + + @property + def microsoft_sdk(self): + """ + Microsoft SDK registry key. + + Return + ------ + str + Registry key + """ + return 'Microsoft SDKs' + + @property + def windows_sdk(self): + """ + Microsoft Windows/Platform SDK registry key. + + Return + ------ + str + Registry key + """ + return join(self.microsoft_sdk, 'Windows') + + @property + def netfx_sdk(self): + """ + Microsoft .NET Framework SDK registry key. + + Return + ------ + str + Registry key + """ + return join(self.microsoft_sdk, 'NETFXSDK') + + @property + def windows_kits_roots(self): + """ + Microsoft Windows Kits Roots registry key. + + Return + ------ + str + Registry key + """ + return r'Windows Kits\Installed Roots' + + def microsoft(self, key, x86=False): + """ + Return key in Microsoft software registry. + + Parameters + ---------- + key: str + Registry key path where look. + x86: str + Force x86 software registry. + + Return + ------ + str + Registry key + """ + node64 = '' if self.pi.current_is_x86() or x86 else 'Wow6432Node' + return join('Software', node64, 'Microsoft', key) + + def lookup(self, key, name): + """ + Look for values in registry in Microsoft software registry. + + Parameters + ---------- + key: str + Registry key path where look. + name: str + Value name to find. + + Return + ------ + str + value + """ + key_read = winreg.KEY_READ + openkey = winreg.OpenKey + ms = self.microsoft + for hkey in self.HKEYS: + try: + bkey = openkey(hkey, ms(key), 0, key_read) + except (OSError, IOError): + if not self.pi.current_is_x86(): + try: + bkey = openkey(hkey, ms(key, True), 0, key_read) + except (OSError, IOError): + continue + else: + continue + try: + return winreg.QueryValueEx(bkey, name)[0] + except (OSError, IOError): + pass + + +class SystemInfo: + """ + Microsoft Windows and Visual Studio related system information. + + Parameters + ---------- + registry_info: RegistryInfo + "RegistryInfo" instance. + vc_ver: float + Required Microsoft Visual C++ version. + """ + + # Variables and properties in this class use originals CamelCase variables + # names from Microsoft source files for more easy comparison. + WinDir = environ.get('WinDir', '') + ProgramFiles = environ.get('ProgramFiles', '') + ProgramFilesx86 = environ.get('ProgramFiles(x86)', ProgramFiles) + + def __init__(self, registry_info, vc_ver=None): + self.ri = registry_info + self.pi = self.ri.pi + + self.known_vs_paths = self.find_programdata_vs_vers() + + # Except for VS15+, VC version is aligned with VS version + self.vs_ver = self.vc_ver = ( + vc_ver or self._find_latest_available_vs_ver()) + + def _find_latest_available_vs_ver(self): + """ + Find the latest VC version + + Return + ------ + float + version + """ + reg_vc_vers = self.find_reg_vs_vers() + + if not (reg_vc_vers or self.known_vs_paths): + raise distutils.errors.DistutilsPlatformError( + 'No Microsoft Visual C++ version found') + + vc_vers = set(reg_vc_vers) + vc_vers.update(self.known_vs_paths) + return sorted(vc_vers)[-1] + + def find_reg_vs_vers(self): + """ + Find Microsoft Visual Studio versions available in registry. + + Return + ------ + list of float + Versions + """ + ms = self.ri.microsoft + vckeys = (self.ri.vc, self.ri.vc_for_python, self.ri.vs) + vs_vers = [] + for hkey in self.ri.HKEYS: + for key in vckeys: + try: + bkey = winreg.OpenKey(hkey, ms(key), 0, winreg.KEY_READ) + except (OSError, IOError): + continue + subkeys, values, _ = winreg.QueryInfoKey(bkey) + for i in range(values): + try: + ver = float(winreg.EnumValue(bkey, i)[0]) + if ver not in vs_vers: + vs_vers.append(ver) + except ValueError: + pass + for i in range(subkeys): + try: + ver = float(winreg.EnumKey(bkey, i)) + if ver not in vs_vers: + vs_vers.append(ver) + except ValueError: + pass + return sorted(vs_vers) + + def find_programdata_vs_vers(self): + r""" + Find Visual studio 2017+ versions from information in + "C:\ProgramData\Microsoft\VisualStudio\Packages\_Instances". + + Return + ------ + dict + float version as key, path as value. + """ + vs_versions = {} + instances_dir = \ + r'C:\ProgramData\Microsoft\VisualStudio\Packages\_Instances' + + try: + hashed_names = listdir(instances_dir) + + except (OSError, IOError): + # Directory not exists with all Visual Studio versions + return vs_versions + + for name in hashed_names: + try: + # Get VS installation path from "state.json" file + state_path = join(instances_dir, name, 'state.json') + with open(state_path, 'rt', encoding='utf-8') as state_file: + state = json.load(state_file) + vs_path = state['installationPath'] + + # Raises OSError if this VS installation does not contain VC + listdir(join(vs_path, r'VC\Tools\MSVC')) + + # Store version and path + vs_versions[self._as_float_version( + state['installationVersion'])] = vs_path + + except (OSError, IOError, KeyError): + # Skip if "state.json" file is missing or bad format + continue + + return vs_versions + + @staticmethod + def _as_float_version(version): + """ + Return a string version as a simplified float version (major.minor) + + Parameters + ---------- + version: str + Version. + + Return + ------ + float + version + """ + return float('.'.join(version.split('.')[:2])) + + @property + def VSInstallDir(self): + """ + Microsoft Visual Studio directory. + + Return + ------ + str + path + """ + # Default path + default = join(self.ProgramFilesx86, + 'Microsoft Visual Studio %0.1f' % self.vs_ver) + + # Try to get path from registry, if fail use default path + return self.ri.lookup(self.ri.vs, '%0.1f' % self.vs_ver) or default + + @property + def VCInstallDir(self): + """ + Microsoft Visual C++ directory. + + Return + ------ + str + path + """ + path = self._guess_vc() or self._guess_vc_legacy() + + if not isdir(path): + msg = 'Microsoft Visual C++ directory not found' + raise distutils.errors.DistutilsPlatformError(msg) + + return path + + def _guess_vc(self): + """ + Locate Visual C++ for VS2017+. + + Return + ------ + str + path + """ + if self.vs_ver <= 14.0: + return '' + + try: + # First search in known VS paths + vs_dir = self.known_vs_paths[self.vs_ver] + except KeyError: + # Else, search with path from registry + vs_dir = self.VSInstallDir + + guess_vc = join(vs_dir, r'VC\Tools\MSVC') + + # Subdir with VC exact version as name + try: + # Update the VC version with real one instead of VS version + vc_ver = listdir(guess_vc)[-1] + self.vc_ver = self._as_float_version(vc_ver) + return join(guess_vc, vc_ver) + except (OSError, IOError, IndexError): + return '' + + def _guess_vc_legacy(self): + """ + Locate Visual C++ for versions prior to 2017. + + Return + ------ + str + path + """ + default = join(self.ProgramFilesx86, + r'Microsoft Visual Studio %0.1f\VC' % self.vs_ver) + + # Try to get "VC++ for Python" path from registry as default path + reg_path = join(self.ri.vc_for_python, '%0.1f' % self.vs_ver) + python_vc = self.ri.lookup(reg_path, 'installdir') + default_vc = join(python_vc, 'VC') if python_vc else default + + # Try to get path from registry, if fail use default path + return self.ri.lookup(self.ri.vc, '%0.1f' % self.vs_ver) or default_vc + + @property + def WindowsSdkVersion(self): + """ + Microsoft Windows SDK versions for specified MSVC++ version. + + Return + ------ + tuple of str + versions + """ + if self.vs_ver <= 9.0: + return '7.0', '6.1', '6.0a' + elif self.vs_ver == 10.0: + return '7.1', '7.0a' + elif self.vs_ver == 11.0: + return '8.0', '8.0a' + elif self.vs_ver == 12.0: + return '8.1', '8.1a' + elif self.vs_ver >= 14.0: + return '10.0', '8.1' + + @property + def WindowsSdkLastVersion(self): + """ + Microsoft Windows SDK last version. + + Return + ------ + str + version + """ + return self._use_last_dir_name(join(self.WindowsSdkDir, 'lib')) + + @property + def WindowsSdkDir(self): + """ + Microsoft Windows SDK directory. + + Return + ------ + str + path + """ + sdkdir = '' + for ver in self.WindowsSdkVersion: + # Try to get it from registry + loc = join(self.ri.windows_sdk, 'v%s' % ver) + sdkdir = self.ri.lookup(loc, 'installationfolder') + if sdkdir: + break + if not sdkdir or not isdir(sdkdir): + # Try to get "VC++ for Python" version from registry + path = join(self.ri.vc_for_python, '%0.1f' % self.vc_ver) + install_base = self.ri.lookup(path, 'installdir') + if install_base: + sdkdir = join(install_base, 'WinSDK') + if not sdkdir or not isdir(sdkdir): + # If fail, use default new path + for ver in self.WindowsSdkVersion: + intver = ver[:ver.rfind('.')] + path = r'Microsoft SDKs\Windows Kits\%s' % intver + d = join(self.ProgramFiles, path) + if isdir(d): + sdkdir = d + if not sdkdir or not isdir(sdkdir): + # If fail, use default old path + for ver in self.WindowsSdkVersion: + path = r'Microsoft SDKs\Windows\v%s' % ver + d = join(self.ProgramFiles, path) + if isdir(d): + sdkdir = d + if not sdkdir: + # If fail, use Platform SDK + sdkdir = join(self.VCInstallDir, 'PlatformSDK') + return sdkdir + + @property + def WindowsSDKExecutablePath(self): + """ + Microsoft Windows SDK executable directory. + + Return + ------ + str + path + """ + # Find WinSDK NetFx Tools registry dir name + if self.vs_ver <= 11.0: + netfxver = 35 + arch = '' + else: + netfxver = 40 + hidex86 = True if self.vs_ver <= 12.0 else False + arch = self.pi.current_dir(x64=True, hidex86=hidex86) + fx = 'WinSDK-NetFx%dTools%s' % (netfxver, arch.replace('\\', '-')) + + # list all possibles registry paths + regpaths = [] + if self.vs_ver >= 14.0: + for ver in self.NetFxSdkVersion: + regpaths += [join(self.ri.netfx_sdk, ver, fx)] + + for ver in self.WindowsSdkVersion: + regpaths += [join(self.ri.windows_sdk, 'v%sA' % ver, fx)] + + # Return installation folder from the more recent path + for path in regpaths: + execpath = self.ri.lookup(path, 'installationfolder') + if execpath: + return execpath + + @property + def FSharpInstallDir(self): + """ + Microsoft Visual F# directory. + + Return + ------ + str + path + """ + path = join(self.ri.visualstudio, r'%0.1f\Setup\F#' % self.vs_ver) + return self.ri.lookup(path, 'productdir') or '' + + @property + def UniversalCRTSdkDir(self): + """ + Microsoft Universal CRT SDK directory. + + Return + ------ + str + path + """ + # Set Kit Roots versions for specified MSVC++ version + vers = ('10', '81') if self.vs_ver >= 14.0 else () + + # Find path of the more recent Kit + for ver in vers: + sdkdir = self.ri.lookup(self.ri.windows_kits_roots, + 'kitsroot%s' % ver) + if sdkdir: + return sdkdir or '' + + @property + def UniversalCRTSdkLastVersion(self): + """ + Microsoft Universal C Runtime SDK last version. + + Return + ------ + str + version + """ + return self._use_last_dir_name(join(self.UniversalCRTSdkDir, 'lib')) + + @property + def NetFxSdkVersion(self): + """ + Microsoft .NET Framework SDK versions. + + Return + ------ + tuple of str + versions + """ + # Set FxSdk versions for specified VS version + return (('4.7.2', '4.7.1', '4.7', + '4.6.2', '4.6.1', '4.6', + '4.5.2', '4.5.1', '4.5') + if self.vs_ver >= 14.0 else ()) + + @property + def NetFxSdkDir(self): + """ + Microsoft .NET Framework SDK directory. + + Return + ------ + str + path + """ + sdkdir = '' + for ver in self.NetFxSdkVersion: + loc = join(self.ri.netfx_sdk, ver) + sdkdir = self.ri.lookup(loc, 'kitsinstallationfolder') + if sdkdir: + break + return sdkdir + + @property + def FrameworkDir32(self): + """ + Microsoft .NET Framework 32bit directory. + + Return + ------ + str + path + """ + # Default path + guess_fw = join(self.WinDir, r'Microsoft.NET\Framework') + + # Try to get path from registry, if fail use default path + return self.ri.lookup(self.ri.vc, 'frameworkdir32') or guess_fw + + @property + def FrameworkDir64(self): + """ + Microsoft .NET Framework 64bit directory. + + Return + ------ + str + path + """ + # Default path + guess_fw = join(self.WinDir, r'Microsoft.NET\Framework64') + + # Try to get path from registry, if fail use default path + return self.ri.lookup(self.ri.vc, 'frameworkdir64') or guess_fw + + @property + def FrameworkVersion32(self): + """ + Microsoft .NET Framework 32bit versions. + + Return + ------ + tuple of str + versions + """ + return self._find_dot_net_versions(32) + + @property + def FrameworkVersion64(self): + """ + Microsoft .NET Framework 64bit versions. + + Return + ------ + tuple of str + versions + """ + return self._find_dot_net_versions(64) + + def _find_dot_net_versions(self, bits): + """ + Find Microsoft .NET Framework versions. + + Parameters + ---------- + bits: int + Platform number of bits: 32 or 64. + + Return + ------ + tuple of str + versions + """ + # Find actual .NET version in registry + reg_ver = self.ri.lookup(self.ri.vc, 'frameworkver%d' % bits) + dot_net_dir = getattr(self, 'FrameworkDir%d' % bits) + ver = reg_ver or self._use_last_dir_name(dot_net_dir, 'v') or '' + + # Set .NET versions for specified MSVC++ version + if self.vs_ver >= 12.0: + return ver, 'v4.0' + elif self.vs_ver >= 10.0: + return 'v4.0.30319' if ver.lower()[:2] != 'v4' else ver, 'v3.5' + elif self.vs_ver == 9.0: + return 'v3.5', 'v2.0.50727' + elif self.vs_ver == 8.0: + return 'v3.0', 'v2.0.50727' + + @staticmethod + def _use_last_dir_name(path, prefix=''): + """ + Return name of the last dir in path or '' if no dir found. + + Parameters + ---------- + path: str + Use dirs in this path + prefix: str + Use only dirs starting by this prefix + + Return + ------ + str + name + """ + matching_dirs = ( + dir_name + for dir_name in reversed(listdir(path)) + if isdir(join(path, dir_name)) and + dir_name.startswith(prefix) + ) + return next(matching_dirs, None) or '' + + +class EnvironmentInfo: + """ + Return environment variables for specified Microsoft Visual C++ version + and platform : Lib, Include, Path and libpath. + + This function is compatible with Microsoft Visual C++ 9.0 to 14.X. + + Script created by analysing Microsoft environment configuration files like + "vcvars[...].bat", "SetEnv.Cmd", "vcbuildtools.bat", ... + + Parameters + ---------- + arch: str + Target architecture. + vc_ver: float + Required Microsoft Visual C++ version. If not set, autodetect the last + version. + vc_min_ver: float + Minimum Microsoft Visual C++ version. + """ + + # Variables and properties in this class use originals CamelCase variables + # names from Microsoft source files for more easy comparison. + + def __init__(self, arch, vc_ver=None, vc_min_ver=0): + self.pi = PlatformInfo(arch) + self.ri = RegistryInfo(self.pi) + self.si = SystemInfo(self.ri, vc_ver) + + if self.vc_ver < vc_min_ver: + err = 'No suitable Microsoft Visual C++ version found' + raise distutils.errors.DistutilsPlatformError(err) + + @property + def vs_ver(self): + """ + Microsoft Visual Studio. + + Return + ------ + float + version + """ + return self.si.vs_ver + + @property + def vc_ver(self): + """ + Microsoft Visual C++ version. + + Return + ------ + float + version + """ + return self.si.vc_ver + + @property + def VSTools(self): + """ + Microsoft Visual Studio Tools. + + Return + ------ + list of str + paths + """ + paths = [r'Common7\IDE', r'Common7\Tools'] + + if self.vs_ver >= 14.0: + arch_subdir = self.pi.current_dir(hidex86=True, x64=True) + paths += [r'Common7\IDE\CommonExtensions\Microsoft\TestWindow'] + paths += [r'Team Tools\Performance Tools'] + paths += [r'Team Tools\Performance Tools%s' % arch_subdir] + + return [join(self.si.VSInstallDir, path) for path in paths] + + @property + def VCIncludes(self): + """ + Microsoft Visual C++ & Microsoft Foundation Class Includes. + + Return + ------ + list of str + paths + """ + return [join(self.si.VCInstallDir, 'Include'), + join(self.si.VCInstallDir, r'ATLMFC\Include')] + + @property + def VCLibraries(self): + """ + Microsoft Visual C++ & Microsoft Foundation Class Libraries. + + Return + ------ + list of str + paths + """ + if self.vs_ver >= 15.0: + arch_subdir = self.pi.target_dir(x64=True) + else: + arch_subdir = self.pi.target_dir(hidex86=True) + paths = ['Lib%s' % arch_subdir, r'ATLMFC\Lib%s' % arch_subdir] + + if self.vs_ver >= 14.0: + paths += [r'Lib\store%s' % arch_subdir] + + return [join(self.si.VCInstallDir, path) for path in paths] + + @property + def VCStoreRefs(self): + """ + Microsoft Visual C++ store references Libraries. + + Return + ------ + list of str + paths + """ + if self.vs_ver < 14.0: + return [] + return [join(self.si.VCInstallDir, r'Lib\store\references')] + + @property + def VCTools(self): + """ + Microsoft Visual C++ Tools. + + Return + ------ + list of str + paths + """ + si = self.si + tools = [join(si.VCInstallDir, 'VCPackages')] + + forcex86 = True if self.vs_ver <= 10.0 else False + arch_subdir = self.pi.cross_dir(forcex86) + if arch_subdir: + tools += [join(si.VCInstallDir, 'Bin%s' % arch_subdir)] + + if self.vs_ver == 14.0: + path = 'Bin%s' % self.pi.current_dir(hidex86=True) + tools += [join(si.VCInstallDir, path)] + + elif self.vs_ver >= 15.0: + host_dir = (r'bin\HostX86%s' if self.pi.current_is_x86() else + r'bin\HostX64%s') + tools += [join( + si.VCInstallDir, host_dir % self.pi.target_dir(x64=True))] + + if self.pi.current_cpu != self.pi.target_cpu: + tools += [join( + si.VCInstallDir, host_dir % self.pi.current_dir(x64=True))] + + else: + tools += [join(si.VCInstallDir, 'Bin')] + + return tools + + @property + def OSLibraries(self): + """ + Microsoft Windows SDK Libraries. + + Return + ------ + list of str + paths + """ + if self.vs_ver <= 10.0: + arch_subdir = self.pi.target_dir(hidex86=True, x64=True) + return [join(self.si.WindowsSdkDir, 'Lib%s' % arch_subdir)] + + else: + arch_subdir = self.pi.target_dir(x64=True) + lib = join(self.si.WindowsSdkDir, 'lib') + libver = self._sdk_subdir + return [join(lib, '%sum%s' % (libver , arch_subdir))] + + @property + def OSIncludes(self): + """ + Microsoft Windows SDK Include. + + Return + ------ + list of str + paths + """ + include = join(self.si.WindowsSdkDir, 'include') + + if self.vs_ver <= 10.0: + return [include, join(include, 'gl')] + + else: + if self.vs_ver >= 14.0: + sdkver = self._sdk_subdir + else: + sdkver = '' + return [join(include, '%sshared' % sdkver), + join(include, '%sum' % sdkver), + join(include, '%swinrt' % sdkver)] + + @property + def OSLibpath(self): + """ + Microsoft Windows SDK Libraries Paths. + + Return + ------ + list of str + paths + """ + ref = join(self.si.WindowsSdkDir, 'References') + libpath = [] + + if self.vs_ver <= 9.0: + libpath += self.OSLibraries + + if self.vs_ver >= 11.0: + libpath += [join(ref, r'CommonConfiguration\Neutral')] + + if self.vs_ver >= 14.0: + libpath += [ + ref, + join(self.si.WindowsSdkDir, 'UnionMetadata'), + join(ref, 'Windows.Foundation.UniversalApiContract', '1.0.0.0'), + join(ref, 'Windows.Foundation.FoundationContract', '1.0.0.0'), + join(ref,'Windows.Networking.Connectivity.WwanContract', + '1.0.0.0'), + join(self.si.WindowsSdkDir, 'ExtensionSDKs', 'Microsoft.VCLibs', + '%0.1f' % self.vs_ver, 'References', 'CommonConfiguration', + 'neutral'), + ] + return libpath + + @property + def SdkTools(self): + """ + Microsoft Windows SDK Tools. + + Return + ------ + list of str + paths + """ + return list(self._sdk_tools()) + + def _sdk_tools(self): + """ + Microsoft Windows SDK Tools paths generator. + + Return + ------ + generator of str + paths + """ + if self.vs_ver < 15.0: + bin_dir = 'Bin' if self.vs_ver <= 11.0 else r'Bin\x86' + yield join(self.si.WindowsSdkDir, bin_dir) + + if not self.pi.current_is_x86(): + arch_subdir = self.pi.current_dir(x64=True) + path = 'Bin%s' % arch_subdir + yield join(self.si.WindowsSdkDir, path) + + if self.vs_ver in (10.0, 11.0): + if self.pi.target_is_x86(): + arch_subdir = '' + else: + arch_subdir = self.pi.current_dir(hidex86=True, x64=True) + path = r'Bin\NETFX 4.0 Tools%s' % arch_subdir + yield join(self.si.WindowsSdkDir, path) + + elif self.vs_ver >= 15.0: + path = join(self.si.WindowsSdkDir, 'Bin') + arch_subdir = self.pi.current_dir(x64=True) + sdkver = self.si.WindowsSdkLastVersion + yield join(path, '%s%s' % (sdkver, arch_subdir)) + + if self.si.WindowsSDKExecutablePath: + yield self.si.WindowsSDKExecutablePath + + @property + def _sdk_subdir(self): + """ + Microsoft Windows SDK version subdir. + + Return + ------ + str + subdir + """ + ucrtver = self.si.WindowsSdkLastVersion + return ('%s\\' % ucrtver) if ucrtver else '' + + @property + def SdkSetup(self): + """ + Microsoft Windows SDK Setup. + + Return + ------ + list of str + paths + """ + if self.vs_ver > 9.0: + return [] + + return [join(self.si.WindowsSdkDir, 'Setup')] + + @property + def FxTools(self): + """ + Microsoft .NET Framework Tools. + + Return + ------ + list of str + paths + """ + pi = self.pi + si = self.si + + if self.vs_ver <= 10.0: + include32 = True + include64 = not pi.target_is_x86() and not pi.current_is_x86() + else: + include32 = pi.target_is_x86() or pi.current_is_x86() + include64 = pi.current_cpu == 'amd64' or pi.target_cpu == 'amd64' + + tools = [] + if include32: + tools += [join(si.FrameworkDir32, ver) + for ver in si.FrameworkVersion32] + if include64: + tools += [join(si.FrameworkDir64, ver) + for ver in si.FrameworkVersion64] + return tools + + @property + def NetFxSDKLibraries(self): + """ + Microsoft .Net Framework SDK Libraries. + + Return + ------ + list of str + paths + """ + if self.vs_ver < 14.0 or not self.si.NetFxSdkDir: + return [] + + arch_subdir = self.pi.target_dir(x64=True) + return [join(self.si.NetFxSdkDir, r'lib\um%s' % arch_subdir)] + + @property + def NetFxSDKIncludes(self): + """ + Microsoft .Net Framework SDK Includes. + + Return + ------ + list of str + paths + """ + if self.vs_ver < 14.0 or not self.si.NetFxSdkDir: + return [] + + return [join(self.si.NetFxSdkDir, r'include\um')] + + @property + def VsTDb(self): + """ + Microsoft Visual Studio Team System Database. + + Return + ------ + list of str + paths + """ + return [join(self.si.VSInstallDir, r'VSTSDB\Deploy')] + + @property + def MSBuild(self): + """ + Microsoft Build Engine. + + Return + ------ + list of str + paths + """ + if self.vs_ver < 12.0: + return [] + elif self.vs_ver < 15.0: + base_path = self.si.ProgramFilesx86 + arch_subdir = self.pi.current_dir(hidex86=True) + else: + base_path = self.si.VSInstallDir + arch_subdir = '' + + path = r'MSBuild\%0.1f\bin%s' % (self.vs_ver, arch_subdir) + build = [join(base_path, path)] + + if self.vs_ver >= 15.0: + # Add Roslyn C# & Visual Basic Compiler + build += [join(base_path, path, 'Roslyn')] + + return build + + @property + def HTMLHelpWorkshop(self): + """ + Microsoft HTML Help Workshop. + + Return + ------ + list of str + paths + """ + if self.vs_ver < 11.0: + return [] + + return [join(self.si.ProgramFilesx86, 'HTML Help Workshop')] + + @property + def UCRTLibraries(self): + """ + Microsoft Universal C Runtime SDK Libraries. + + Return + ------ + list of str + paths + """ + if self.vs_ver < 14.0: + return [] + + arch_subdir = self.pi.target_dir(x64=True) + lib = join(self.si.UniversalCRTSdkDir, 'lib') + ucrtver = self._ucrt_subdir + return [join(lib, '%sucrt%s' % (ucrtver, arch_subdir))] + + @property + def UCRTIncludes(self): + """ + Microsoft Universal C Runtime SDK Include. + + Return + ------ + list of str + paths + """ + if self.vs_ver < 14.0: + return [] + + include = join(self.si.UniversalCRTSdkDir, 'include') + return [join(include, '%sucrt' % self._ucrt_subdir)] + + @property + def _ucrt_subdir(self): + """ + Microsoft Universal C Runtime SDK version subdir. + + Return + ------ + str + subdir + """ + ucrtver = self.si.UniversalCRTSdkLastVersion + return ('%s\\' % ucrtver) if ucrtver else '' + + @property + def FSharp(self): + """ + Microsoft Visual F#. + + Return + ------ + list of str + paths + """ + if 11.0 > self.vs_ver > 12.0: + return [] + + return [self.si.FSharpInstallDir] + + @property + def VCRuntimeRedist(self): + """ + Microsoft Visual C++ runtime redistributable dll. + + Return + ------ + str + path + """ + vcruntime = 'vcruntime%d0.dll' % self.vc_ver + arch_subdir = self.pi.target_dir(x64=True).strip('\\') + + # Installation prefixes candidates + prefixes = [] + tools_path = self.si.VCInstallDir + redist_path = dirname(tools_path.replace(r'\Tools', r'\Redist')) + if isdir(redist_path): + # Redist version may not be exactly the same as tools + redist_path = join(redist_path, listdir(redist_path)[-1]) + prefixes += [redist_path, join(redist_path, 'onecore')] + + prefixes += [join(tools_path, 'redist')] # VS14 legacy path + + # CRT directory + crt_dirs = ('Microsoft.VC%d.CRT' % (self.vc_ver * 10), + # Sometime store in directory with VS version instead of VC + 'Microsoft.VC%d.CRT' % (int(self.vs_ver) * 10)) + + # vcruntime path + for prefix, crt_dir in itertools.product(prefixes, crt_dirs): + path = join(prefix, arch_subdir, crt_dir, vcruntime) + if isfile(path): + return path + + def return_env(self, exists=True): + """ + Return environment dict. + + Parameters + ---------- + exists: bool + It True, only return existing paths. + + Return + ------ + dict + environment + """ + env = dict( + include=self._build_paths('include', + [self.VCIncludes, + self.OSIncludes, + self.UCRTIncludes, + self.NetFxSDKIncludes], + exists), + lib=self._build_paths('lib', + [self.VCLibraries, + self.OSLibraries, + self.FxTools, + self.UCRTLibraries, + self.NetFxSDKLibraries], + exists), + libpath=self._build_paths('libpath', + [self.VCLibraries, + self.FxTools, + self.VCStoreRefs, + self.OSLibpath], + exists), + path=self._build_paths('path', + [self.VCTools, + self.VSTools, + self.VsTDb, + self.SdkTools, + self.SdkSetup, + self.FxTools, + self.MSBuild, + self.HTMLHelpWorkshop, + self.FSharp], + exists), + ) + if self.vs_ver >= 14 and isfile(self.VCRuntimeRedist): + env['py_vcruntime_redist'] = self.VCRuntimeRedist + return env + + def _build_paths(self, name, spec_path_lists, exists): + """ + Given an environment variable name and specified paths, + return a pathsep-separated string of paths containing + unique, extant, directories from those paths and from + the environment variable. Raise an error if no paths + are resolved. + + Parameters + ---------- + name: str + Environment variable name + spec_path_lists: list of str + Paths + exists: bool + It True, only return existing paths. + + Return + ------ + str + Pathsep-separated paths + """ + # flatten spec_path_lists + spec_paths = itertools.chain.from_iterable(spec_path_lists) + env_paths = environ.get(name, '').split(pathsep) + paths = itertools.chain(spec_paths, env_paths) + extant_paths = list(filter(isdir, paths)) if exists else paths + if not extant_paths: + msg = "%s environment variable is empty" % name.upper() + raise distutils.errors.DistutilsPlatformError(msg) + unique_paths = self._unique_everseen(extant_paths) + return pathsep.join(unique_paths) + + # from Python docs + @staticmethod + def _unique_everseen(iterable, key=None): + """ + List unique elements, preserving order. + Remember all elements ever seen. + + _unique_everseen('AAAABBBCCDAABBB') --> A B C D + + _unique_everseen('ABBCcAD', str.lower) --> A B C D + """ + seen = set() + seen_add = seen.add + if key is None: + for element in filterfalse(seen.__contains__, iterable): + seen_add(element) + yield element + else: + for element in iterable: + k = key(element) + if k not in seen: + seen_add(k) + yield element diff --git a/venv/lib/python3.8/site-packages/setuptools/namespaces.py b/venv/lib/python3.8/site-packages/setuptools/namespaces.py new file mode 100644 index 0000000..dc16106 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/namespaces.py @@ -0,0 +1,107 @@ +import os +from distutils import log +import itertools + +from setuptools.extern.six.moves import map + + +flatten = itertools.chain.from_iterable + + +class Installer: + + nspkg_ext = '-nspkg.pth' + + def install_namespaces(self): + nsp = self._get_all_ns_packages() + if not nsp: + return + filename, ext = os.path.splitext(self._get_target()) + filename += self.nspkg_ext + self.outputs.append(filename) + log.info("Installing %s", filename) + lines = map(self._gen_nspkg_line, nsp) + + if self.dry_run: + # always generate the lines, even in dry run + list(lines) + return + + with open(filename, 'wt') as f: + f.writelines(lines) + + def uninstall_namespaces(self): + filename, ext = os.path.splitext(self._get_target()) + filename += self.nspkg_ext + if not os.path.exists(filename): + return + log.info("Removing %s", filename) + os.remove(filename) + + def _get_target(self): + return self.target + + _nspkg_tmpl = ( + "import sys, types, os", + "has_mfs = sys.version_info > (3, 5)", + "p = os.path.join(%(root)s, *%(pth)r)", + "importlib = has_mfs and __import__('importlib.util')", + "has_mfs and __import__('importlib.machinery')", + "m = has_mfs and " + "sys.modules.setdefault(%(pkg)r, " + "importlib.util.module_from_spec(" + "importlib.machinery.PathFinder.find_spec(%(pkg)r, " + "[os.path.dirname(p)])))", + "m = m or " + "sys.modules.setdefault(%(pkg)r, types.ModuleType(%(pkg)r))", + "mp = (m or []) and m.__dict__.setdefault('__path__',[])", + "(p not in mp) and mp.append(p)", + ) + "lines for the namespace installer" + + _nspkg_tmpl_multi = ( + 'm and setattr(sys.modules[%(parent)r], %(child)r, m)', + ) + "additional line(s) when a parent package is indicated" + + def _get_root(self): + return "sys._getframe(1).f_locals['sitedir']" + + def _gen_nspkg_line(self, pkg): + # ensure pkg is not a unicode string under Python 2.7 + pkg = str(pkg) + pth = tuple(pkg.split('.')) + root = self._get_root() + tmpl_lines = self._nspkg_tmpl + parent, sep, child = pkg.rpartition('.') + if parent: + tmpl_lines += self._nspkg_tmpl_multi + return ';'.join(tmpl_lines) % locals() + '\n' + + def _get_all_ns_packages(self): + """Return sorted list of all package namespaces""" + pkgs = self.distribution.namespace_packages or [] + return sorted(flatten(map(self._pkg_names, pkgs))) + + @staticmethod + def _pkg_names(pkg): + """ + Given a namespace package, yield the components of that + package. + + >>> names = Installer._pkg_names('a.b.c') + >>> set(names) == set(['a', 'a.b', 'a.b.c']) + True + """ + parts = pkg.split('.') + while parts: + yield '.'.join(parts) + parts.pop() + + +class DevelopInstaller(Installer): + def _get_root(self): + return repr(str(self.egg_path)) + + def _get_target(self): + return self.egg_link diff --git a/venv/lib/python3.8/site-packages/setuptools/package_index.py b/venv/lib/python3.8/site-packages/setuptools/package_index.py new file mode 100644 index 0000000..f419d47 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/package_index.py @@ -0,0 +1,1136 @@ +"""PyPI and direct package downloading""" +import sys +import os +import re +import shutil +import socket +import base64 +import hashlib +import itertools +import warnings +from functools import wraps + +from setuptools.extern import six +from setuptools.extern.six.moves import urllib, http_client, configparser, map + +import setuptools +from pkg_resources import ( + CHECKOUT_DIST, Distribution, BINARY_DIST, normalize_path, SOURCE_DIST, + Environment, find_distributions, safe_name, safe_version, + to_filename, Requirement, DEVELOP_DIST, EGG_DIST, +) +from setuptools import ssl_support +from distutils import log +from distutils.errors import DistutilsError +from fnmatch import translate +from setuptools.py27compat import get_all_headers +from setuptools.py33compat import unescape +from setuptools.wheel import Wheel + +__metaclass__ = type + +EGG_FRAGMENT = re.compile(r'^egg=([-A-Za-z0-9_.+!]+)$') +HREF = re.compile(r"""href\s*=\s*['"]?([^'"> ]+)""", re.I) +PYPI_MD5 = re.compile( + r'<a href="([^"#]+)">([^<]+)</a>\n\s+\(<a (?:title="MD5 hash"\n\s+)' + r'href="[^?]+\?:action=show_md5&amp;digest=([0-9a-f]{32})">md5</a>\)' +) +URL_SCHEME = re.compile('([-+.a-z0-9]{2,}):', re.I).match +EXTENSIONS = ".tar.gz .tar.bz2 .tar .zip .tgz".split() + +__all__ = [ + 'PackageIndex', 'distros_for_url', 'parse_bdist_wininst', + 'interpret_distro_name', +] + +_SOCKET_TIMEOUT = 15 + +_tmpl = "setuptools/{setuptools.__version__} Python-urllib/{py_major}" +user_agent = _tmpl.format(py_major='{}.{}'.format(*sys.version_info), setuptools=setuptools) + + +def parse_requirement_arg(spec): + try: + return Requirement.parse(spec) + except ValueError: + raise DistutilsError( + "Not a URL, existing file, or requirement spec: %r" % (spec,) + ) + + +def parse_bdist_wininst(name): + """Return (base,pyversion) or (None,None) for possible .exe name""" + + lower = name.lower() + base, py_ver, plat = None, None, None + + if lower.endswith('.exe'): + if lower.endswith('.win32.exe'): + base = name[:-10] + plat = 'win32' + elif lower.startswith('.win32-py', -16): + py_ver = name[-7:-4] + base = name[:-16] + plat = 'win32' + elif lower.endswith('.win-amd64.exe'): + base = name[:-14] + plat = 'win-amd64' + elif lower.startswith('.win-amd64-py', -20): + py_ver = name[-7:-4] + base = name[:-20] + plat = 'win-amd64' + return base, py_ver, plat + + +def egg_info_for_url(url): + parts = urllib.parse.urlparse(url) + scheme, server, path, parameters, query, fragment = parts + base = urllib.parse.unquote(path.split('/')[-1]) + if server == 'sourceforge.net' and base == 'download': # XXX Yuck + base = urllib.parse.unquote(path.split('/')[-2]) + if '#' in base: + base, fragment = base.split('#', 1) + return base, fragment + + +def distros_for_url(url, metadata=None): + """Yield egg or source distribution objects that might be found at a URL""" + base, fragment = egg_info_for_url(url) + for dist in distros_for_location(url, base, metadata): + yield dist + if fragment: + match = EGG_FRAGMENT.match(fragment) + if match: + for dist in interpret_distro_name( + url, match.group(1), metadata, precedence=CHECKOUT_DIST + ): + yield dist + + +def distros_for_location(location, basename, metadata=None): + """Yield egg or source distribution objects based on basename""" + if basename.endswith('.egg.zip'): + basename = basename[:-4] # strip the .zip + if basename.endswith('.egg') and '-' in basename: + # only one, unambiguous interpretation + return [Distribution.from_location(location, basename, metadata)] + if basename.endswith('.whl') and '-' in basename: + wheel = Wheel(basename) + if not wheel.is_compatible(): + return [] + return [Distribution( + location=location, + project_name=wheel.project_name, + version=wheel.version, + # Increase priority over eggs. + precedence=EGG_DIST + 1, + )] + if basename.endswith('.exe'): + win_base, py_ver, platform = parse_bdist_wininst(basename) + if win_base is not None: + return interpret_distro_name( + location, win_base, metadata, py_ver, BINARY_DIST, platform + ) + # Try source distro extensions (.zip, .tgz, etc.) + # + for ext in EXTENSIONS: + if basename.endswith(ext): + basename = basename[:-len(ext)] + return interpret_distro_name(location, basename, metadata) + return [] # no extension matched + + +def distros_for_filename(filename, metadata=None): + """Yield possible egg or source distribution objects based on a filename""" + return distros_for_location( + normalize_path(filename), os.path.basename(filename), metadata + ) + + +def interpret_distro_name( + location, basename, metadata, py_version=None, precedence=SOURCE_DIST, + platform=None +): + """Generate alternative interpretations of a source distro name + + Note: if `location` is a filesystem filename, you should call + ``pkg_resources.normalize_path()`` on it before passing it to this + routine! + """ + # Generate alternative interpretations of a source distro name + # Because some packages are ambiguous as to name/versions split + # e.g. "adns-python-1.1.0", "egenix-mx-commercial", etc. + # So, we generate each possible interepretation (e.g. "adns, python-1.1.0" + # "adns-python, 1.1.0", and "adns-python-1.1.0, no version"). In practice, + # the spurious interpretations should be ignored, because in the event + # there's also an "adns" package, the spurious "python-1.1.0" version will + # compare lower than any numeric version number, and is therefore unlikely + # to match a request for it. It's still a potential problem, though, and + # in the long run PyPI and the distutils should go for "safe" names and + # versions in distribution archive names (sdist and bdist). + + parts = basename.split('-') + if not py_version and any(re.match(r'py\d\.\d$', p) for p in parts[2:]): + # it is a bdist_dumb, not an sdist -- bail out + return + + for p in range(1, len(parts) + 1): + yield Distribution( + location, metadata, '-'.join(parts[:p]), '-'.join(parts[p:]), + py_version=py_version, precedence=precedence, + platform=platform + ) + + +# From Python 2.7 docs +def unique_everseen(iterable, key=None): + "List unique elements, preserving order. Remember all elements ever seen." + # unique_everseen('AAAABBBCCDAABBB') --> A B C D + # unique_everseen('ABBCcAD', str.lower) --> A B C D + seen = set() + seen_add = seen.add + if key is None: + for element in six.moves.filterfalse(seen.__contains__, iterable): + seen_add(element) + yield element + else: + for element in iterable: + k = key(element) + if k not in seen: + seen_add(k) + yield element + + +def unique_values(func): + """ + Wrap a function returning an iterable such that the resulting iterable + only ever yields unique items. + """ + + @wraps(func) + def wrapper(*args, **kwargs): + return unique_everseen(func(*args, **kwargs)) + + return wrapper + + +REL = re.compile(r"""<([^>]*\srel\s*=\s*['"]?([^'">]+)[^>]*)>""", re.I) +# this line is here to fix emacs' cruddy broken syntax highlighting + + +@unique_values +def find_external_links(url, page): + """Find rel="homepage" and rel="download" links in `page`, yielding URLs""" + + for match in REL.finditer(page): + tag, rel = match.groups() + rels = set(map(str.strip, rel.lower().split(','))) + if 'homepage' in rels or 'download' in rels: + for match in HREF.finditer(tag): + yield urllib.parse.urljoin(url, htmldecode(match.group(1))) + + for tag in ("<th>Home Page", "<th>Download URL"): + pos = page.find(tag) + if pos != -1: + match = HREF.search(page, pos) + if match: + yield urllib.parse.urljoin(url, htmldecode(match.group(1))) + + +class ContentChecker: + """ + A null content checker that defines the interface for checking content + """ + + def feed(self, block): + """ + Feed a block of data to the hash. + """ + return + + def is_valid(self): + """ + Check the hash. Return False if validation fails. + """ + return True + + def report(self, reporter, template): + """ + Call reporter with information about the checker (hash name) + substituted into the template. + """ + return + + +class HashChecker(ContentChecker): + pattern = re.compile( + r'(?P<hash_name>sha1|sha224|sha384|sha256|sha512|md5)=' + r'(?P<expected>[a-f0-9]+)' + ) + + def __init__(self, hash_name, expected): + self.hash_name = hash_name + self.hash = hashlib.new(hash_name) + self.expected = expected + + @classmethod + def from_url(cls, url): + "Construct a (possibly null) ContentChecker from a URL" + fragment = urllib.parse.urlparse(url)[-1] + if not fragment: + return ContentChecker() + match = cls.pattern.search(fragment) + if not match: + return ContentChecker() + return cls(**match.groupdict()) + + def feed(self, block): + self.hash.update(block) + + def is_valid(self): + return self.hash.hexdigest() == self.expected + + def report(self, reporter, template): + msg = template % self.hash_name + return reporter(msg) + + +class PackageIndex(Environment): + """A distribution index that scans web pages for download URLs""" + + def __init__( + self, index_url="https://pypi.org/simple/", hosts=('*',), + ca_bundle=None, verify_ssl=True, *args, **kw + ): + Environment.__init__(self, *args, **kw) + self.index_url = index_url + "/" [:not index_url.endswith('/')] + self.scanned_urls = {} + self.fetched_urls = {} + self.package_pages = {} + self.allows = re.compile('|'.join(map(translate, hosts))).match + self.to_scan = [] + use_ssl = ( + verify_ssl + and ssl_support.is_available + and (ca_bundle or ssl_support.find_ca_bundle()) + ) + if use_ssl: + self.opener = ssl_support.opener_for(ca_bundle) + else: + self.opener = urllib.request.urlopen + + def process_url(self, url, retrieve=False): + """Evaluate a URL as a possible download, and maybe retrieve it""" + if url in self.scanned_urls and not retrieve: + return + self.scanned_urls[url] = True + if not URL_SCHEME(url): + self.process_filename(url) + return + else: + dists = list(distros_for_url(url)) + if dists: + if not self.url_ok(url): + return + self.debug("Found link: %s", url) + + if dists or not retrieve or url in self.fetched_urls: + list(map(self.add, dists)) + return # don't need the actual page + + if not self.url_ok(url): + self.fetched_urls[url] = True + return + + self.info("Reading %s", url) + self.fetched_urls[url] = True # prevent multiple fetch attempts + tmpl = "Download error on %s: %%s -- Some packages may not be found!" + f = self.open_url(url, tmpl % url) + if f is None: + return + self.fetched_urls[f.url] = True + if 'html' not in f.headers.get('content-type', '').lower(): + f.close() # not html, we can't process it + return + + base = f.url # handle redirects + page = f.read() + if not isinstance(page, str): + # In Python 3 and got bytes but want str. + if isinstance(f, urllib.error.HTTPError): + # Errors have no charset, assume latin1: + charset = 'latin-1' + else: + charset = f.headers.get_param('charset') or 'latin-1' + page = page.decode(charset, "ignore") + f.close() + for match in HREF.finditer(page): + link = urllib.parse.urljoin(base, htmldecode(match.group(1))) + self.process_url(link) + if url.startswith(self.index_url) and getattr(f, 'code', None) != 404: + page = self.process_index(url, page) + + def process_filename(self, fn, nested=False): + # process filenames or directories + if not os.path.exists(fn): + self.warn("Not found: %s", fn) + return + + if os.path.isdir(fn) and not nested: + path = os.path.realpath(fn) + for item in os.listdir(path): + self.process_filename(os.path.join(path, item), True) + + dists = distros_for_filename(fn) + if dists: + self.debug("Found: %s", fn) + list(map(self.add, dists)) + + def url_ok(self, url, fatal=False): + s = URL_SCHEME(url) + is_file = s and s.group(1).lower() == 'file' + if is_file or self.allows(urllib.parse.urlparse(url)[1]): + return True + msg = ( + "\nNote: Bypassing %s (disallowed host; see " + "http://bit.ly/2hrImnY for details).\n") + if fatal: + raise DistutilsError(msg % url) + else: + self.warn(msg, url) + + def scan_egg_links(self, search_path): + dirs = filter(os.path.isdir, search_path) + egg_links = ( + (path, entry) + for path in dirs + for entry in os.listdir(path) + if entry.endswith('.egg-link') + ) + list(itertools.starmap(self.scan_egg_link, egg_links)) + + def scan_egg_link(self, path, entry): + with open(os.path.join(path, entry)) as raw_lines: + # filter non-empty lines + lines = list(filter(None, map(str.strip, raw_lines))) + + if len(lines) != 2: + # format is not recognized; punt + return + + egg_path, setup_path = lines + + for dist in find_distributions(os.path.join(path, egg_path)): + dist.location = os.path.join(path, *lines) + dist.precedence = SOURCE_DIST + self.add(dist) + + def process_index(self, url, page): + """Process the contents of a PyPI page""" + + def scan(link): + # Process a URL to see if it's for a package page + if link.startswith(self.index_url): + parts = list(map( + urllib.parse.unquote, link[len(self.index_url):].split('/') + )) + if len(parts) == 2 and '#' not in parts[1]: + # it's a package page, sanitize and index it + pkg = safe_name(parts[0]) + ver = safe_version(parts[1]) + self.package_pages.setdefault(pkg.lower(), {})[link] = True + return to_filename(pkg), to_filename(ver) + return None, None + + # process an index page into the package-page index + for match in HREF.finditer(page): + try: + scan(urllib.parse.urljoin(url, htmldecode(match.group(1)))) + except ValueError: + pass + + pkg, ver = scan(url) # ensure this page is in the page index + if pkg: + # process individual package page + for new_url in find_external_links(url, page): + # Process the found URL + base, frag = egg_info_for_url(new_url) + if base.endswith('.py') and not frag: + if ver: + new_url += '#egg=%s-%s' % (pkg, ver) + else: + self.need_version_info(url) + self.scan_url(new_url) + + return PYPI_MD5.sub( + lambda m: '<a href="%s#md5=%s">%s</a>' % m.group(1, 3, 2), page + ) + else: + return "" # no sense double-scanning non-package pages + + def need_version_info(self, url): + self.scan_all( + "Page at %s links to .py file(s) without version info; an index " + "scan is required.", url + ) + + def scan_all(self, msg=None, *args): + if self.index_url not in self.fetched_urls: + if msg: + self.warn(msg, *args) + self.info( + "Scanning index of all packages (this may take a while)" + ) + self.scan_url(self.index_url) + + def find_packages(self, requirement): + self.scan_url(self.index_url + requirement.unsafe_name + '/') + + if not self.package_pages.get(requirement.key): + # Fall back to safe version of the name + self.scan_url(self.index_url + requirement.project_name + '/') + + if not self.package_pages.get(requirement.key): + # We couldn't find the target package, so search the index page too + self.not_found_in_index(requirement) + + for url in list(self.package_pages.get(requirement.key, ())): + # scan each page that might be related to the desired package + self.scan_url(url) + + def obtain(self, requirement, installer=None): + self.prescan() + self.find_packages(requirement) + for dist in self[requirement.key]: + if dist in requirement: + return dist + self.debug("%s does not match %s", requirement, dist) + return super(PackageIndex, self).obtain(requirement, installer) + + def check_hash(self, checker, filename, tfp): + """ + checker is a ContentChecker + """ + checker.report( + self.debug, + "Validating %%s checksum for %s" % filename) + if not checker.is_valid(): + tfp.close() + os.unlink(filename) + raise DistutilsError( + "%s validation failed for %s; " + "possible download problem?" + % (checker.hash.name, os.path.basename(filename)) + ) + + def add_find_links(self, urls): + """Add `urls` to the list that will be prescanned for searches""" + for url in urls: + if ( + self.to_scan is None # if we have already "gone online" + or not URL_SCHEME(url) # or it's a local file/directory + or url.startswith('file:') + or list(distros_for_url(url)) # or a direct package link + ): + # then go ahead and process it now + self.scan_url(url) + else: + # otherwise, defer retrieval till later + self.to_scan.append(url) + + def prescan(self): + """Scan urls scheduled for prescanning (e.g. --find-links)""" + if self.to_scan: + list(map(self.scan_url, self.to_scan)) + self.to_scan = None # from now on, go ahead and process immediately + + def not_found_in_index(self, requirement): + if self[requirement.key]: # we've seen at least one distro + meth, msg = self.info, "Couldn't retrieve index page for %r" + else: # no distros seen for this name, might be misspelled + meth, msg = ( + self.warn, + "Couldn't find index page for %r (maybe misspelled?)") + meth(msg, requirement.unsafe_name) + self.scan_all() + + def download(self, spec, tmpdir): + """Locate and/or download `spec` to `tmpdir`, returning a local path + + `spec` may be a ``Requirement`` object, or a string containing a URL, + an existing local filename, or a project/version requirement spec + (i.e. the string form of a ``Requirement`` object). If it is the URL + of a .py file with an unambiguous ``#egg=name-version`` tag (i.e., one + that escapes ``-`` as ``_`` throughout), a trivial ``setup.py`` is + automatically created alongside the downloaded file. + + If `spec` is a ``Requirement`` object or a string containing a + project/version requirement spec, this method returns the location of + a matching distribution (possibly after downloading it to `tmpdir`). + If `spec` is a locally existing file or directory name, it is simply + returned unchanged. If `spec` is a URL, it is downloaded to a subpath + of `tmpdir`, and the local filename is returned. Various errors may be + raised if a problem occurs during downloading. + """ + if not isinstance(spec, Requirement): + scheme = URL_SCHEME(spec) + if scheme: + # It's a url, download it to tmpdir + found = self._download_url(scheme.group(1), spec, tmpdir) + base, fragment = egg_info_for_url(spec) + if base.endswith('.py'): + found = self.gen_setup(found, fragment, tmpdir) + return found + elif os.path.exists(spec): + # Existing file or directory, just return it + return spec + else: + spec = parse_requirement_arg(spec) + return getattr(self.fetch_distribution(spec, tmpdir), 'location', None) + + def fetch_distribution( + self, requirement, tmpdir, force_scan=False, source=False, + develop_ok=False, local_index=None): + """Obtain a distribution suitable for fulfilling `requirement` + + `requirement` must be a ``pkg_resources.Requirement`` instance. + If necessary, or if the `force_scan` flag is set, the requirement is + searched for in the (online) package index as well as the locally + installed packages. If a distribution matching `requirement` is found, + the returned distribution's ``location`` is the value you would have + gotten from calling the ``download()`` method with the matching + distribution's URL or filename. If no matching distribution is found, + ``None`` is returned. + + If the `source` flag is set, only source distributions and source + checkout links will be considered. Unless the `develop_ok` flag is + set, development and system eggs (i.e., those using the ``.egg-info`` + format) will be ignored. + """ + # process a Requirement + self.info("Searching for %s", requirement) + skipped = {} + dist = None + + def find(req, env=None): + if env is None: + env = self + # Find a matching distribution; may be called more than once + + for dist in env[req.key]: + + if dist.precedence == DEVELOP_DIST and not develop_ok: + if dist not in skipped: + self.warn( + "Skipping development or system egg: %s", dist, + ) + skipped[dist] = 1 + continue + + test = ( + dist in req + and (dist.precedence <= SOURCE_DIST or not source) + ) + if test: + loc = self.download(dist.location, tmpdir) + dist.download_location = loc + if os.path.exists(dist.download_location): + return dist + + if force_scan: + self.prescan() + self.find_packages(requirement) + dist = find(requirement) + + if not dist and local_index is not None: + dist = find(requirement, local_index) + + if dist is None: + if self.to_scan is not None: + self.prescan() + dist = find(requirement) + + if dist is None and not force_scan: + self.find_packages(requirement) + dist = find(requirement) + + if dist is None: + self.warn( + "No local packages or working download links found for %s%s", + (source and "a source distribution of " or ""), + requirement, + ) + else: + self.info("Best match: %s", dist) + return dist.clone(location=dist.download_location) + + def fetch(self, requirement, tmpdir, force_scan=False, source=False): + """Obtain a file suitable for fulfilling `requirement` + + DEPRECATED; use the ``fetch_distribution()`` method now instead. For + backward compatibility, this routine is identical but returns the + ``location`` of the downloaded distribution instead of a distribution + object. + """ + dist = self.fetch_distribution(requirement, tmpdir, force_scan, source) + if dist is not None: + return dist.location + return None + + def gen_setup(self, filename, fragment, tmpdir): + match = EGG_FRAGMENT.match(fragment) + dists = match and [ + d for d in + interpret_distro_name(filename, match.group(1), None) if d.version + ] or [] + + if len(dists) == 1: # unambiguous ``#egg`` fragment + basename = os.path.basename(filename) + + # Make sure the file has been downloaded to the temp dir. + if os.path.dirname(filename) != tmpdir: + dst = os.path.join(tmpdir, basename) + from setuptools.command.easy_install import samefile + if not samefile(filename, dst): + shutil.copy2(filename, dst) + filename = dst + + with open(os.path.join(tmpdir, 'setup.py'), 'w') as file: + file.write( + "from setuptools import setup\n" + "setup(name=%r, version=%r, py_modules=[%r])\n" + % ( + dists[0].project_name, dists[0].version, + os.path.splitext(basename)[0] + ) + ) + return filename + + elif match: + raise DistutilsError( + "Can't unambiguously interpret project/version identifier %r; " + "any dashes in the name or version should be escaped using " + "underscores. %r" % (fragment, dists) + ) + else: + raise DistutilsError( + "Can't process plain .py files without an '#egg=name-version'" + " suffix to enable automatic setup script generation." + ) + + dl_blocksize = 8192 + + def _download_to(self, url, filename): + self.info("Downloading %s", url) + # Download the file + fp = None + try: + checker = HashChecker.from_url(url) + fp = self.open_url(url) + if isinstance(fp, urllib.error.HTTPError): + raise DistutilsError( + "Can't download %s: %s %s" % (url, fp.code, fp.msg) + ) + headers = fp.info() + blocknum = 0 + bs = self.dl_blocksize + size = -1 + if "content-length" in headers: + # Some servers return multiple Content-Length headers :( + sizes = get_all_headers(headers, 'Content-Length') + size = max(map(int, sizes)) + self.reporthook(url, filename, blocknum, bs, size) + with open(filename, 'wb') as tfp: + while True: + block = fp.read(bs) + if block: + checker.feed(block) + tfp.write(block) + blocknum += 1 + self.reporthook(url, filename, blocknum, bs, size) + else: + break + self.check_hash(checker, filename, tfp) + return headers + finally: + if fp: + fp.close() + + def reporthook(self, url, filename, blocknum, blksize, size): + pass # no-op + + def open_url(self, url, warning=None): + if url.startswith('file:'): + return local_open(url) + try: + return open_with_auth(url, self.opener) + except (ValueError, http_client.InvalidURL) as v: + msg = ' '.join([str(arg) for arg in v.args]) + if warning: + self.warn(warning, msg) + else: + raise DistutilsError('%s %s' % (url, msg)) + except urllib.error.HTTPError as v: + return v + except urllib.error.URLError as v: + if warning: + self.warn(warning, v.reason) + else: + raise DistutilsError("Download error for %s: %s" + % (url, v.reason)) + except http_client.BadStatusLine as v: + if warning: + self.warn(warning, v.line) + else: + raise DistutilsError( + '%s returned a bad status line. The server might be ' + 'down, %s' % + (url, v.line) + ) + except (http_client.HTTPException, socket.error) as v: + if warning: + self.warn(warning, v) + else: + raise DistutilsError("Download error for %s: %s" + % (url, v)) + + def _download_url(self, scheme, url, tmpdir): + # Determine download filename + # + name, fragment = egg_info_for_url(url) + if name: + while '..' in name: + name = name.replace('..', '.').replace('\\', '_') + else: + name = "__downloaded__" # default if URL has no path contents + + if name.endswith('.egg.zip'): + name = name[:-4] # strip the extra .zip before download + + filename = os.path.join(tmpdir, name) + + # Download the file + # + if scheme == 'svn' or scheme.startswith('svn+'): + return self._download_svn(url, filename) + elif scheme == 'git' or scheme.startswith('git+'): + return self._download_git(url, filename) + elif scheme.startswith('hg+'): + return self._download_hg(url, filename) + elif scheme == 'file': + return urllib.request.url2pathname(urllib.parse.urlparse(url)[2]) + else: + self.url_ok(url, True) # raises error if not allowed + return self._attempt_download(url, filename) + + def scan_url(self, url): + self.process_url(url, True) + + def _attempt_download(self, url, filename): + headers = self._download_to(url, filename) + if 'html' in headers.get('content-type', '').lower(): + return self._download_html(url, headers, filename) + else: + return filename + + def _download_html(self, url, headers, filename): + file = open(filename) + for line in file: + if line.strip(): + # Check for a subversion index page + if re.search(r'<title>([^- ]+ - )?Revision \d+:', line): + # it's a subversion index page: + file.close() + os.unlink(filename) + return self._download_svn(url, filename) + break # not an index page + file.close() + os.unlink(filename) + raise DistutilsError("Unexpected HTML page found at " + url) + + def _download_svn(self, url, filename): + warnings.warn("SVN download support is deprecated", UserWarning) + url = url.split('#', 1)[0] # remove any fragment for svn's sake + creds = '' + if url.lower().startswith('svn:') and '@' in url: + scheme, netloc, path, p, q, f = urllib.parse.urlparse(url) + if not netloc and path.startswith('//') and '/' in path[2:]: + netloc, path = path[2:].split('/', 1) + auth, host = _splituser(netloc) + if auth: + if ':' in auth: + user, pw = auth.split(':', 1) + creds = " --username=%s --password=%s" % (user, pw) + else: + creds = " --username=" + auth + netloc = host + parts = scheme, netloc, url, p, q, f + url = urllib.parse.urlunparse(parts) + self.info("Doing subversion checkout from %s to %s", url, filename) + os.system("svn checkout%s -q %s %s" % (creds, url, filename)) + return filename + + @staticmethod + def _vcs_split_rev_from_url(url, pop_prefix=False): + scheme, netloc, path, query, frag = urllib.parse.urlsplit(url) + + scheme = scheme.split('+', 1)[-1] + + # Some fragment identification fails + path = path.split('#', 1)[0] + + rev = None + if '@' in path: + path, rev = path.rsplit('@', 1) + + # Also, discard fragment + url = urllib.parse.urlunsplit((scheme, netloc, path, query, '')) + + return url, rev + + def _download_git(self, url, filename): + filename = filename.split('#', 1)[0] + url, rev = self._vcs_split_rev_from_url(url, pop_prefix=True) + + self.info("Doing git clone from %s to %s", url, filename) + os.system("git clone --quiet %s %s" % (url, filename)) + + if rev is not None: + self.info("Checking out %s", rev) + os.system("git -C %s checkout --quiet %s" % ( + filename, + rev, + )) + + return filename + + def _download_hg(self, url, filename): + filename = filename.split('#', 1)[0] + url, rev = self._vcs_split_rev_from_url(url, pop_prefix=True) + + self.info("Doing hg clone from %s to %s", url, filename) + os.system("hg clone --quiet %s %s" % (url, filename)) + + if rev is not None: + self.info("Updating to %s", rev) + os.system("hg --cwd %s up -C -r %s -q" % ( + filename, + rev, + )) + + return filename + + def debug(self, msg, *args): + log.debug(msg, *args) + + def info(self, msg, *args): + log.info(msg, *args) + + def warn(self, msg, *args): + log.warn(msg, *args) + + +# This pattern matches a character entity reference (a decimal numeric +# references, a hexadecimal numeric reference, or a named reference). +entity_sub = re.compile(r'&(#(\d+|x[\da-fA-F]+)|[\w.:-]+);?').sub + + +def decode_entity(match): + what = match.group(0) + return unescape(what) + + +def htmldecode(text): + """ + Decode HTML entities in the given text. + + >>> htmldecode( + ... 'https://../package_name-0.1.2.tar.gz' + ... '?tokena=A&amp;tokenb=B">package_name-0.1.2.tar.gz') + 'https://../package_name-0.1.2.tar.gz?tokena=A&tokenb=B">package_name-0.1.2.tar.gz' + """ + return entity_sub(decode_entity, text) + + +def socket_timeout(timeout=15): + def _socket_timeout(func): + def _socket_timeout(*args, **kwargs): + old_timeout = socket.getdefaulttimeout() + socket.setdefaulttimeout(timeout) + try: + return func(*args, **kwargs) + finally: + socket.setdefaulttimeout(old_timeout) + + return _socket_timeout + + return _socket_timeout + + +def _encode_auth(auth): + """ + A function compatible with Python 2.3-3.3 that will encode + auth from a URL suitable for an HTTP header. + >>> str(_encode_auth('username%3Apassword')) + 'dXNlcm5hbWU6cGFzc3dvcmQ=' + + Long auth strings should not cause a newline to be inserted. + >>> long_auth = 'username:' + 'password'*10 + >>> chr(10) in str(_encode_auth(long_auth)) + False + """ + auth_s = urllib.parse.unquote(auth) + # convert to bytes + auth_bytes = auth_s.encode() + encoded_bytes = base64.b64encode(auth_bytes) + # convert back to a string + encoded = encoded_bytes.decode() + # strip the trailing carriage return + return encoded.replace('\n', '') + + +class Credential: + """ + A username/password pair. Use like a namedtuple. + """ + + def __init__(self, username, password): + self.username = username + self.password = password + + def __iter__(self): + yield self.username + yield self.password + + def __str__(self): + return '%(username)s:%(password)s' % vars(self) + + +class PyPIConfig(configparser.RawConfigParser): + def __init__(self): + """ + Load from ~/.pypirc + """ + defaults = dict.fromkeys(['username', 'password', 'repository'], '') + configparser.RawConfigParser.__init__(self, defaults) + + rc = os.path.join(os.path.expanduser('~'), '.pypirc') + if os.path.exists(rc): + self.read(rc) + + @property + def creds_by_repository(self): + sections_with_repositories = [ + section for section in self.sections() + if self.get(section, 'repository').strip() + ] + + return dict(map(self._get_repo_cred, sections_with_repositories)) + + def _get_repo_cred(self, section): + repo = self.get(section, 'repository').strip() + return repo, Credential( + self.get(section, 'username').strip(), + self.get(section, 'password').strip(), + ) + + def find_credential(self, url): + """ + If the URL indicated appears to be a repository defined in this + config, return the credential for that repository. + """ + for repository, cred in self.creds_by_repository.items(): + if url.startswith(repository): + return cred + + +def open_with_auth(url, opener=urllib.request.urlopen): + """Open a urllib2 request, handling HTTP authentication""" + + parsed = urllib.parse.urlparse(url) + scheme, netloc, path, params, query, frag = parsed + + # Double scheme does not raise on Mac OS X as revealed by a + # failing test. We would expect "nonnumeric port". Refs #20. + if netloc.endswith(':'): + raise http_client.InvalidURL("nonnumeric port: ''") + + if scheme in ('http', 'https'): + auth, address = _splituser(netloc) + else: + auth = None + + if not auth: + cred = PyPIConfig().find_credential(url) + if cred: + auth = str(cred) + info = cred.username, url + log.info('Authenticating as %s for %s (from .pypirc)', *info) + + if auth: + auth = "Basic " + _encode_auth(auth) + parts = scheme, address, path, params, query, frag + new_url = urllib.parse.urlunparse(parts) + request = urllib.request.Request(new_url) + request.add_header("Authorization", auth) + else: + request = urllib.request.Request(url) + + request.add_header('User-Agent', user_agent) + fp = opener(request) + + if auth: + # Put authentication info back into request URL if same host, + # so that links found on the page will work + s2, h2, path2, param2, query2, frag2 = urllib.parse.urlparse(fp.url) + if s2 == scheme and h2 == address: + parts = s2, netloc, path2, param2, query2, frag2 + fp.url = urllib.parse.urlunparse(parts) + + return fp + + +# copy of urllib.parse._splituser from Python 3.8 +def _splituser(host): + """splituser('user[:passwd]@host[:port]') --> 'user[:passwd]', 'host[:port]'.""" + user, delim, host = host.rpartition('@') + return (user if delim else None), host + + +# adding a timeout to avoid freezing package_index +open_with_auth = socket_timeout(_SOCKET_TIMEOUT)(open_with_auth) + + +def fix_sf_url(url): + return url # backward compatibility + + +def local_open(url): + """Read a local path, with special support for directories""" + scheme, server, path, param, query, frag = urllib.parse.urlparse(url) + filename = urllib.request.url2pathname(path) + if os.path.isfile(filename): + return urllib.request.urlopen(url) + elif path.endswith('/') and os.path.isdir(filename): + files = [] + for f in os.listdir(filename): + filepath = os.path.join(filename, f) + if f == 'index.html': + with open(filepath, 'r') as fp: + body = fp.read() + break + elif os.path.isdir(filepath): + f += '/' + files.append('<a href="{name}">{name}</a>'.format(name=f)) + else: + tmpl = ( + "<html><head><title>{url}</title>" + "</head><body>{files}</body></html>") + body = tmpl.format(url=url, files='\n'.join(files)) + status, message = 200, "OK" + else: + status, message, body = 404, "Path not found", "Not found" + + headers = {'content-type': 'text/html'} + body_stream = six.StringIO(body) + return urllib.error.HTTPError(url, status, message, headers, body_stream) diff --git a/venv/lib/python3.8/site-packages/setuptools/py27compat.py b/venv/lib/python3.8/site-packages/setuptools/py27compat.py new file mode 100644 index 0000000..1d57360 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/py27compat.py @@ -0,0 +1,60 @@ +""" +Compatibility Support for Python 2.7 and earlier +""" + +import sys +import platform + +from setuptools.extern import six + + +def get_all_headers(message, key): + """ + Given an HTTPMessage, return all headers matching a given key. + """ + return message.get_all(key) + + +if six.PY2: + def get_all_headers(message, key): + return message.getheaders(key) + + +linux_py2_ascii = ( + platform.system() == 'Linux' and + six.PY2 +) + +rmtree_safe = str if linux_py2_ascii else lambda x: x +"""Workaround for http://bugs.python.org/issue24672""" + + +try: + from ._imp import find_module, PY_COMPILED, PY_FROZEN, PY_SOURCE + from ._imp import get_frozen_object, get_module +except ImportError: + import imp + from imp import PY_COMPILED, PY_FROZEN, PY_SOURCE # noqa + + def find_module(module, paths=None): + """Just like 'imp.find_module()', but with package support""" + parts = module.split('.') + while parts: + part = parts.pop(0) + f, path, (suffix, mode, kind) = info = imp.find_module(part, paths) + + if kind == imp.PKG_DIRECTORY: + parts = parts or ['__init__'] + paths = [path] + + elif parts: + raise ImportError("Can't find %r in %s" % (parts, module)) + + return info + + def get_frozen_object(module, paths): + return imp.get_frozen_object(module) + + def get_module(module, paths, info): + imp.load_module(module, *info) + return sys.modules[module] diff --git a/venv/lib/python3.8/site-packages/setuptools/py31compat.py b/venv/lib/python3.8/site-packages/setuptools/py31compat.py new file mode 100644 index 0000000..e1da7ee --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/py31compat.py @@ -0,0 +1,32 @@ +__all__ = [] + +__metaclass__ = type + + +try: + # Python >=3.2 + from tempfile import TemporaryDirectory +except ImportError: + import shutil + import tempfile + + class TemporaryDirectory: + """ + Very simple temporary directory context manager. + Will try to delete afterward, but will also ignore OS and similar + errors on deletion. + """ + + def __init__(self, **kwargs): + self.name = None # Handle mkdtemp raising an exception + self.name = tempfile.mkdtemp(**kwargs) + + def __enter__(self): + return self.name + + def __exit__(self, exctype, excvalue, exctrace): + try: + shutil.rmtree(self.name, True) + except OSError: # removal errors are not the only possible + pass + self.name = None diff --git a/venv/lib/python3.8/site-packages/setuptools/py33compat.py b/venv/lib/python3.8/site-packages/setuptools/py33compat.py new file mode 100644 index 0000000..cb69443 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/py33compat.py @@ -0,0 +1,59 @@ +import dis +import array +import collections + +try: + import html +except ImportError: + html = None + +from setuptools.extern import six +from setuptools.extern.six.moves import html_parser + +__metaclass__ = type + +OpArg = collections.namedtuple('OpArg', 'opcode arg') + + +class Bytecode_compat: + def __init__(self, code): + self.code = code + + def __iter__(self): + """Yield '(op,arg)' pair for each operation in code object 'code'""" + + bytes = array.array('b', self.code.co_code) + eof = len(self.code.co_code) + + ptr = 0 + extended_arg = 0 + + while ptr < eof: + + op = bytes[ptr] + + if op >= dis.HAVE_ARGUMENT: + + arg = bytes[ptr + 1] + bytes[ptr + 2] * 256 + extended_arg + ptr += 3 + + if op == dis.EXTENDED_ARG: + long_type = six.integer_types[-1] + extended_arg = arg * long_type(65536) + continue + + else: + arg = None + ptr += 1 + + yield OpArg(op, arg) + + +Bytecode = getattr(dis, 'Bytecode', Bytecode_compat) + + +unescape = getattr(html, 'unescape', None) +if unescape is None: + # HTMLParser.unescape is deprecated since Python 3.4, and will be removed + # from 3.9. + unescape = html_parser.HTMLParser().unescape diff --git a/venv/lib/python3.8/site-packages/setuptools/py34compat.py b/venv/lib/python3.8/site-packages/setuptools/py34compat.py new file mode 100644 index 0000000..3ad9172 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/py34compat.py @@ -0,0 +1,13 @@ +import importlib + +try: + import importlib.util +except ImportError: + pass + + +try: + module_from_spec = importlib.util.module_from_spec +except AttributeError: + def module_from_spec(spec): + return spec.loader.load_module(spec.name) diff --git a/venv/lib/python3.8/site-packages/setuptools/sandbox.py b/venv/lib/python3.8/site-packages/setuptools/sandbox.py new file mode 100644 index 0000000..685f3f7 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/sandbox.py @@ -0,0 +1,491 @@ +import os +import sys +import tempfile +import operator +import functools +import itertools +import re +import contextlib +import pickle +import textwrap + +from setuptools.extern import six +from setuptools.extern.six.moves import builtins, map + +import pkg_resources.py31compat + +if sys.platform.startswith('java'): + import org.python.modules.posix.PosixModule as _os +else: + _os = sys.modules[os.name] +try: + _file = file +except NameError: + _file = None +_open = open +from distutils.errors import DistutilsError +from pkg_resources import working_set + + +__all__ = [ + "AbstractSandbox", "DirectorySandbox", "SandboxViolation", "run_setup", +] + + +def _execfile(filename, globals, locals=None): + """ + Python 3 implementation of execfile. + """ + mode = 'rb' + with open(filename, mode) as stream: + script = stream.read() + if locals is None: + locals = globals + code = compile(script, filename, 'exec') + exec(code, globals, locals) + + +@contextlib.contextmanager +def save_argv(repl=None): + saved = sys.argv[:] + if repl is not None: + sys.argv[:] = repl + try: + yield saved + finally: + sys.argv[:] = saved + + +@contextlib.contextmanager +def save_path(): + saved = sys.path[:] + try: + yield saved + finally: + sys.path[:] = saved + + +@contextlib.contextmanager +def override_temp(replacement): + """ + Monkey-patch tempfile.tempdir with replacement, ensuring it exists + """ + pkg_resources.py31compat.makedirs(replacement, exist_ok=True) + + saved = tempfile.tempdir + + tempfile.tempdir = replacement + + try: + yield + finally: + tempfile.tempdir = saved + + +@contextlib.contextmanager +def pushd(target): + saved = os.getcwd() + os.chdir(target) + try: + yield saved + finally: + os.chdir(saved) + + +class UnpickleableException(Exception): + """ + An exception representing another Exception that could not be pickled. + """ + + @staticmethod + def dump(type, exc): + """ + Always return a dumped (pickled) type and exc. If exc can't be pickled, + wrap it in UnpickleableException first. + """ + try: + return pickle.dumps(type), pickle.dumps(exc) + except Exception: + # get UnpickleableException inside the sandbox + from setuptools.sandbox import UnpickleableException as cls + return cls.dump(cls, cls(repr(exc))) + + +class ExceptionSaver: + """ + A Context Manager that will save an exception, serialized, and restore it + later. + """ + + def __enter__(self): + return self + + def __exit__(self, type, exc, tb): + if not exc: + return + + # dump the exception + self._saved = UnpickleableException.dump(type, exc) + self._tb = tb + + # suppress the exception + return True + + def resume(self): + "restore and re-raise any exception" + + if '_saved' not in vars(self): + return + + type, exc = map(pickle.loads, self._saved) + six.reraise(type, exc, self._tb) + + +@contextlib.contextmanager +def save_modules(): + """ + Context in which imported modules are saved. + + Translates exceptions internal to the context into the equivalent exception + outside the context. + """ + saved = sys.modules.copy() + with ExceptionSaver() as saved_exc: + yield saved + + sys.modules.update(saved) + # remove any modules imported since + del_modules = ( + mod_name for mod_name in sys.modules + if mod_name not in saved + # exclude any encodings modules. See #285 + and not mod_name.startswith('encodings.') + ) + _clear_modules(del_modules) + + saved_exc.resume() + + +def _clear_modules(module_names): + for mod_name in list(module_names): + del sys.modules[mod_name] + + +@contextlib.contextmanager +def save_pkg_resources_state(): + saved = pkg_resources.__getstate__() + try: + yield saved + finally: + pkg_resources.__setstate__(saved) + + +@contextlib.contextmanager +def setup_context(setup_dir): + temp_dir = os.path.join(setup_dir, 'temp') + with save_pkg_resources_state(): + with save_modules(): + hide_setuptools() + with save_path(): + with save_argv(): + with override_temp(temp_dir): + with pushd(setup_dir): + # ensure setuptools commands are available + __import__('setuptools') + yield + + +def _needs_hiding(mod_name): + """ + >>> _needs_hiding('setuptools') + True + >>> _needs_hiding('pkg_resources') + True + >>> _needs_hiding('setuptools_plugin') + False + >>> _needs_hiding('setuptools.__init__') + True + >>> _needs_hiding('distutils') + True + >>> _needs_hiding('os') + False + >>> _needs_hiding('Cython') + True + """ + pattern = re.compile(r'(setuptools|pkg_resources|distutils|Cython)(\.|$)') + return bool(pattern.match(mod_name)) + + +def hide_setuptools(): + """ + Remove references to setuptools' modules from sys.modules to allow the + invocation to import the most appropriate setuptools. This technique is + necessary to avoid issues such as #315 where setuptools upgrading itself + would fail to find a function declared in the metadata. + """ + modules = filter(_needs_hiding, sys.modules) + _clear_modules(modules) + + +def run_setup(setup_script, args): + """Run a distutils setup script, sandboxed in its directory""" + setup_dir = os.path.abspath(os.path.dirname(setup_script)) + with setup_context(setup_dir): + try: + sys.argv[:] = [setup_script] + list(args) + sys.path.insert(0, setup_dir) + # reset to include setup dir, w/clean callback list + working_set.__init__() + working_set.callbacks.append(lambda dist: dist.activate()) + + # __file__ should be a byte string on Python 2 (#712) + dunder_file = ( + setup_script + if isinstance(setup_script, str) else + setup_script.encode(sys.getfilesystemencoding()) + ) + + with DirectorySandbox(setup_dir): + ns = dict(__file__=dunder_file, __name__='__main__') + _execfile(setup_script, ns) + except SystemExit as v: + if v.args and v.args[0]: + raise + # Normal exit, just return + + +class AbstractSandbox: + """Wrap 'os' module and 'open()' builtin for virtualizing setup scripts""" + + _active = False + + def __init__(self): + self._attrs = [ + name for name in dir(_os) + if not name.startswith('_') and hasattr(self, name) + ] + + def _copy(self, source): + for name in self._attrs: + setattr(os, name, getattr(source, name)) + + def __enter__(self): + self._copy(self) + if _file: + builtins.file = self._file + builtins.open = self._open + self._active = True + + def __exit__(self, exc_type, exc_value, traceback): + self._active = False + if _file: + builtins.file = _file + builtins.open = _open + self._copy(_os) + + def run(self, func): + """Run 'func' under os sandboxing""" + with self: + return func() + + def _mk_dual_path_wrapper(name): + original = getattr(_os, name) + + def wrap(self, src, dst, *args, **kw): + if self._active: + src, dst = self._remap_pair(name, src, dst, *args, **kw) + return original(src, dst, *args, **kw) + + return wrap + + for name in ["rename", "link", "symlink"]: + if hasattr(_os, name): + locals()[name] = _mk_dual_path_wrapper(name) + + def _mk_single_path_wrapper(name, original=None): + original = original or getattr(_os, name) + + def wrap(self, path, *args, **kw): + if self._active: + path = self._remap_input(name, path, *args, **kw) + return original(path, *args, **kw) + + return wrap + + if _file: + _file = _mk_single_path_wrapper('file', _file) + _open = _mk_single_path_wrapper('open', _open) + for name in [ + "stat", "listdir", "chdir", "open", "chmod", "chown", "mkdir", + "remove", "unlink", "rmdir", "utime", "lchown", "chroot", "lstat", + "startfile", "mkfifo", "mknod", "pathconf", "access" + ]: + if hasattr(_os, name): + locals()[name] = _mk_single_path_wrapper(name) + + def _mk_single_with_return(name): + original = getattr(_os, name) + + def wrap(self, path, *args, **kw): + if self._active: + path = self._remap_input(name, path, *args, **kw) + return self._remap_output(name, original(path, *args, **kw)) + return original(path, *args, **kw) + + return wrap + + for name in ['readlink', 'tempnam']: + if hasattr(_os, name): + locals()[name] = _mk_single_with_return(name) + + def _mk_query(name): + original = getattr(_os, name) + + def wrap(self, *args, **kw): + retval = original(*args, **kw) + if self._active: + return self._remap_output(name, retval) + return retval + + return wrap + + for name in ['getcwd', 'tmpnam']: + if hasattr(_os, name): + locals()[name] = _mk_query(name) + + def _validate_path(self, path): + """Called to remap or validate any path, whether input or output""" + return path + + def _remap_input(self, operation, path, *args, **kw): + """Called for path inputs""" + return self._validate_path(path) + + def _remap_output(self, operation, path): + """Called for path outputs""" + return self._validate_path(path) + + def _remap_pair(self, operation, src, dst, *args, **kw): + """Called for path pairs like rename, link, and symlink operations""" + return ( + self._remap_input(operation + '-from', src, *args, **kw), + self._remap_input(operation + '-to', dst, *args, **kw) + ) + + +if hasattr(os, 'devnull'): + _EXCEPTIONS = [os.devnull,] +else: + _EXCEPTIONS = [] + + +class DirectorySandbox(AbstractSandbox): + """Restrict operations to a single subdirectory - pseudo-chroot""" + + write_ops = dict.fromkeys([ + "open", "chmod", "chown", "mkdir", "remove", "unlink", "rmdir", + "utime", "lchown", "chroot", "mkfifo", "mknod", "tempnam", + ]) + + _exception_patterns = [ + # Allow lib2to3 to attempt to save a pickled grammar object (#121) + r'.*lib2to3.*\.pickle$', + ] + "exempt writing to paths that match the pattern" + + def __init__(self, sandbox, exceptions=_EXCEPTIONS): + self._sandbox = os.path.normcase(os.path.realpath(sandbox)) + self._prefix = os.path.join(self._sandbox, '') + self._exceptions = [ + os.path.normcase(os.path.realpath(path)) + for path in exceptions + ] + AbstractSandbox.__init__(self) + + def _violation(self, operation, *args, **kw): + from setuptools.sandbox import SandboxViolation + raise SandboxViolation(operation, args, kw) + + if _file: + + def _file(self, path, mode='r', *args, **kw): + if mode not in ('r', 'rt', 'rb', 'rU', 'U') and not self._ok(path): + self._violation("file", path, mode, *args, **kw) + return _file(path, mode, *args, **kw) + + def _open(self, path, mode='r', *args, **kw): + if mode not in ('r', 'rt', 'rb', 'rU', 'U') and not self._ok(path): + self._violation("open", path, mode, *args, **kw) + return _open(path, mode, *args, **kw) + + def tmpnam(self): + self._violation("tmpnam") + + def _ok(self, path): + active = self._active + try: + self._active = False + realpath = os.path.normcase(os.path.realpath(path)) + return ( + self._exempted(realpath) + or realpath == self._sandbox + or realpath.startswith(self._prefix) + ) + finally: + self._active = active + + def _exempted(self, filepath): + start_matches = ( + filepath.startswith(exception) + for exception in self._exceptions + ) + pattern_matches = ( + re.match(pattern, filepath) + for pattern in self._exception_patterns + ) + candidates = itertools.chain(start_matches, pattern_matches) + return any(candidates) + + def _remap_input(self, operation, path, *args, **kw): + """Called for path inputs""" + if operation in self.write_ops and not self._ok(path): + self._violation(operation, os.path.realpath(path), *args, **kw) + return path + + def _remap_pair(self, operation, src, dst, *args, **kw): + """Called for path pairs like rename, link, and symlink operations""" + if not self._ok(src) or not self._ok(dst): + self._violation(operation, src, dst, *args, **kw) + return (src, dst) + + def open(self, file, flags, mode=0o777, *args, **kw): + """Called for low-level os.open()""" + if flags & WRITE_FLAGS and not self._ok(file): + self._violation("os.open", file, flags, mode, *args, **kw) + return _os.open(file, flags, mode, *args, **kw) + + +WRITE_FLAGS = functools.reduce( + operator.or_, [getattr(_os, a, 0) for a in + "O_WRONLY O_RDWR O_APPEND O_CREAT O_TRUNC O_TEMPORARY".split()] +) + + +class SandboxViolation(DistutilsError): + """A setup script attempted to modify the filesystem outside the sandbox""" + + tmpl = textwrap.dedent(""" + SandboxViolation: {cmd}{args!r} {kwargs} + + The package setup script has attempted to modify files on your system + that are not within the EasyInstall build area, and has been aborted. + + This package cannot be safely installed by EasyInstall, and may not + support alternate installation locations even if you run its setup + script by hand. Please inform the package's author and the EasyInstall + maintainers to find out if a fix or workaround is available. + """).lstrip() + + def __str__(self): + cmd, args, kwargs = self.args + return self.tmpl.format(**locals()) diff --git a/venv/lib/python3.8/site-packages/setuptools/script (dev).tmpl b/venv/lib/python3.8/site-packages/setuptools/script (dev).tmpl new file mode 100644 index 0000000..39a24b0 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/script (dev).tmpl @@ -0,0 +1,6 @@ +# EASY-INSTALL-DEV-SCRIPT: %(spec)r,%(script_name)r +__requires__ = %(spec)r +__import__('pkg_resources').require(%(spec)r) +__file__ = %(dev_path)r +with open(__file__) as f: + exec(compile(f.read(), __file__, 'exec')) diff --git a/venv/lib/python3.8/site-packages/setuptools/script.tmpl b/venv/lib/python3.8/site-packages/setuptools/script.tmpl new file mode 100644 index 0000000..ff5efbc --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/script.tmpl @@ -0,0 +1,3 @@ +# EASY-INSTALL-SCRIPT: %(spec)r,%(script_name)r +__requires__ = %(spec)r +__import__('pkg_resources').run_script(%(spec)r, %(script_name)r) diff --git a/venv/lib/python3.8/site-packages/setuptools/site-patch.py b/venv/lib/python3.8/site-packages/setuptools/site-patch.py new file mode 100644 index 0000000..40b00de --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/site-patch.py @@ -0,0 +1,74 @@ +def __boot(): + import sys + import os + PYTHONPATH = os.environ.get('PYTHONPATH') + if PYTHONPATH is None or (sys.platform == 'win32' and not PYTHONPATH): + PYTHONPATH = [] + else: + PYTHONPATH = PYTHONPATH.split(os.pathsep) + + pic = getattr(sys, 'path_importer_cache', {}) + stdpath = sys.path[len(PYTHONPATH):] + mydir = os.path.dirname(__file__) + + for item in stdpath: + if item == mydir or not item: + continue # skip if current dir. on Windows, or my own directory + importer = pic.get(item) + if importer is not None: + loader = importer.find_module('site') + if loader is not None: + # This should actually reload the current module + loader.load_module('site') + break + else: + try: + import imp # Avoid import loop in Python 3 + stream, path, descr = imp.find_module('site', [item]) + except ImportError: + continue + if stream is None: + continue + try: + # This should actually reload the current module + imp.load_module('site', stream, path, descr) + finally: + stream.close() + break + else: + raise ImportError("Couldn't find the real 'site' module") + + known_paths = dict([(makepath(item)[1], 1) for item in sys.path]) # 2.2 comp + + oldpos = getattr(sys, '__egginsert', 0) # save old insertion position + sys.__egginsert = 0 # and reset the current one + + for item in PYTHONPATH: + addsitedir(item) + + sys.__egginsert += oldpos # restore effective old position + + d, nd = makepath(stdpath[0]) + insert_at = None + new_path = [] + + for item in sys.path: + p, np = makepath(item) + + if np == nd and insert_at is None: + # We've hit the first 'system' path entry, so added entries go here + insert_at = len(new_path) + + if np in known_paths or insert_at is None: + new_path.append(item) + else: + # new path after the insert point, back-insert it + new_path.insert(insert_at, item) + insert_at += 1 + + sys.path[:] = new_path + + +if __name__ == 'site': + __boot() + del __boot diff --git a/venv/lib/python3.8/site-packages/setuptools/ssl_support.py b/venv/lib/python3.8/site-packages/setuptools/ssl_support.py new file mode 100644 index 0000000..226db69 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/ssl_support.py @@ -0,0 +1,260 @@ +import os +import socket +import atexit +import re +import functools + +from setuptools.extern.six.moves import urllib, http_client, map, filter + +from pkg_resources import ResolutionError, ExtractionError + +try: + import ssl +except ImportError: + ssl = None + +__all__ = [ + 'VerifyingHTTPSHandler', 'find_ca_bundle', 'is_available', 'cert_paths', + 'opener_for' +] + +cert_paths = """ +/etc/pki/tls/certs/ca-bundle.crt +/etc/ssl/certs/ca-certificates.crt +/usr/share/ssl/certs/ca-bundle.crt +/usr/local/share/certs/ca-root.crt +/etc/ssl/cert.pem +/System/Library/OpenSSL/certs/cert.pem +/usr/local/share/certs/ca-root-nss.crt +/etc/ssl/ca-bundle.pem +""".strip().split() + +try: + HTTPSHandler = urllib.request.HTTPSHandler + HTTPSConnection = http_client.HTTPSConnection +except AttributeError: + HTTPSHandler = HTTPSConnection = object + +is_available = ssl is not None and object not in (HTTPSHandler, HTTPSConnection) + + +try: + from ssl import CertificateError, match_hostname +except ImportError: + try: + from backports.ssl_match_hostname import CertificateError + from backports.ssl_match_hostname import match_hostname + except ImportError: + CertificateError = None + match_hostname = None + +if not CertificateError: + + class CertificateError(ValueError): + pass + + +if not match_hostname: + + def _dnsname_match(dn, hostname, max_wildcards=1): + """Matching according to RFC 6125, section 6.4.3 + + https://tools.ietf.org/html/rfc6125#section-6.4.3 + """ + pats = [] + if not dn: + return False + + # Ported from python3-syntax: + # leftmost, *remainder = dn.split(r'.') + parts = dn.split(r'.') + leftmost = parts[0] + remainder = parts[1:] + + wildcards = leftmost.count('*') + if wildcards > max_wildcards: + # Issue #17980: avoid denials of service by refusing more + # than one wildcard per fragment. A survey of established + # policy among SSL implementations showed it to be a + # reasonable choice. + raise CertificateError( + "too many wildcards in certificate DNS name: " + repr(dn)) + + # speed up common case w/o wildcards + if not wildcards: + return dn.lower() == hostname.lower() + + # RFC 6125, section 6.4.3, subitem 1. + # The client SHOULD NOT attempt to match a presented identifier in which + # the wildcard character comprises a label other than the left-most label. + if leftmost == '*': + # When '*' is a fragment by itself, it matches a non-empty dotless + # fragment. + pats.append('[^.]+') + elif leftmost.startswith('xn--') or hostname.startswith('xn--'): + # RFC 6125, section 6.4.3, subitem 3. + # The client SHOULD NOT attempt to match a presented identifier + # where the wildcard character is embedded within an A-label or + # U-label of an internationalized domain name. + pats.append(re.escape(leftmost)) + else: + # Otherwise, '*' matches any dotless string, e.g. www* + pats.append(re.escape(leftmost).replace(r'\*', '[^.]*')) + + # add the remaining fragments, ignore any wildcards + for frag in remainder: + pats.append(re.escape(frag)) + + pat = re.compile(r'\A' + r'\.'.join(pats) + r'\Z', re.IGNORECASE) + return pat.match(hostname) + + def match_hostname(cert, hostname): + """Verify that *cert* (in decoded format as returned by + SSLSocket.getpeercert()) matches the *hostname*. RFC 2818 and RFC 6125 + rules are followed, but IP addresses are not accepted for *hostname*. + + CertificateError is raised on failure. On success, the function + returns nothing. + """ + if not cert: + raise ValueError("empty or no certificate") + dnsnames = [] + san = cert.get('subjectAltName', ()) + for key, value in san: + if key == 'DNS': + if _dnsname_match(value, hostname): + return + dnsnames.append(value) + if not dnsnames: + # The subject is only checked when there is no dNSName entry + # in subjectAltName + for sub in cert.get('subject', ()): + for key, value in sub: + # XXX according to RFC 2818, the most specific Common Name + # must be used. + if key == 'commonName': + if _dnsname_match(value, hostname): + return + dnsnames.append(value) + if len(dnsnames) > 1: + raise CertificateError("hostname %r " + "doesn't match either of %s" + % (hostname, ', '.join(map(repr, dnsnames)))) + elif len(dnsnames) == 1: + raise CertificateError("hostname %r " + "doesn't match %r" + % (hostname, dnsnames[0])) + else: + raise CertificateError("no appropriate commonName or " + "subjectAltName fields were found") + + +class VerifyingHTTPSHandler(HTTPSHandler): + """Simple verifying handler: no auth, subclasses, timeouts, etc.""" + + def __init__(self, ca_bundle): + self.ca_bundle = ca_bundle + HTTPSHandler.__init__(self) + + def https_open(self, req): + return self.do_open( + lambda host, **kw: VerifyingHTTPSConn(host, self.ca_bundle, **kw), req + ) + + +class VerifyingHTTPSConn(HTTPSConnection): + """Simple verifying connection: no auth, subclasses, timeouts, etc.""" + + def __init__(self, host, ca_bundle, **kw): + HTTPSConnection.__init__(self, host, **kw) + self.ca_bundle = ca_bundle + + def connect(self): + sock = socket.create_connection( + (self.host, self.port), getattr(self, 'source_address', None) + ) + + # Handle the socket if a (proxy) tunnel is present + if hasattr(self, '_tunnel') and getattr(self, '_tunnel_host', None): + self.sock = sock + self._tunnel() + # http://bugs.python.org/issue7776: Python>=3.4.1 and >=2.7.7 + # change self.host to mean the proxy server host when tunneling is + # being used. Adapt, since we are interested in the destination + # host for the match_hostname() comparison. + actual_host = self._tunnel_host + else: + actual_host = self.host + + if hasattr(ssl, 'create_default_context'): + ctx = ssl.create_default_context(cafile=self.ca_bundle) + self.sock = ctx.wrap_socket(sock, server_hostname=actual_host) + else: + # This is for python < 2.7.9 and < 3.4? + self.sock = ssl.wrap_socket( + sock, cert_reqs=ssl.CERT_REQUIRED, ca_certs=self.ca_bundle + ) + try: + match_hostname(self.sock.getpeercert(), actual_host) + except CertificateError: + self.sock.shutdown(socket.SHUT_RDWR) + self.sock.close() + raise + + +def opener_for(ca_bundle=None): + """Get a urlopen() replacement that uses ca_bundle for verification""" + return urllib.request.build_opener( + VerifyingHTTPSHandler(ca_bundle or find_ca_bundle()) + ).open + + +# from jaraco.functools +def once(func): + @functools.wraps(func) + def wrapper(*args, **kwargs): + if not hasattr(func, 'always_returns'): + func.always_returns = func(*args, **kwargs) + return func.always_returns + return wrapper + + +@once +def get_win_certfile(): + try: + import wincertstore + except ImportError: + return None + + class CertFile(wincertstore.CertFile): + def __init__(self): + super(CertFile, self).__init__() + atexit.register(self.close) + + def close(self): + try: + super(CertFile, self).close() + except OSError: + pass + + _wincerts = CertFile() + _wincerts.addstore('CA') + _wincerts.addstore('ROOT') + return _wincerts.name + + +def find_ca_bundle(): + """Return an existing CA bundle path, or None""" + extant_cert_paths = filter(os.path.isfile, cert_paths) + return ( + get_win_certfile() + or next(extant_cert_paths, None) + or _certifi_where() + ) + + +def _certifi_where(): + try: + return __import__('certifi').where() + except (ImportError, ResolutionError, ExtractionError): + pass diff --git a/venv/lib/python3.8/site-packages/setuptools/unicode_utils.py b/venv/lib/python3.8/site-packages/setuptools/unicode_utils.py new file mode 100644 index 0000000..7c63efd --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/unicode_utils.py @@ -0,0 +1,44 @@ +import unicodedata +import sys + +from setuptools.extern import six + + +# HFS Plus uses decomposed UTF-8 +def decompose(path): + if isinstance(path, six.text_type): + return unicodedata.normalize('NFD', path) + try: + path = path.decode('utf-8') + path = unicodedata.normalize('NFD', path) + path = path.encode('utf-8') + except UnicodeError: + pass # Not UTF-8 + return path + + +def filesys_decode(path): + """ + Ensure that the given path is decoded, + NONE when no expected encoding works + """ + + if isinstance(path, six.text_type): + return path + + fs_enc = sys.getfilesystemencoding() or 'utf-8' + candidates = fs_enc, 'utf-8' + + for enc in candidates: + try: + return path.decode(enc) + except UnicodeDecodeError: + continue + + +def try_encode(string, enc): + "turn unicode encoding into a functional routine" + try: + return string.encode(enc) + except UnicodeEncodeError: + return None diff --git a/venv/lib/python3.8/site-packages/setuptools/version.py b/venv/lib/python3.8/site-packages/setuptools/version.py new file mode 100644 index 0000000..95e1869 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/version.py @@ -0,0 +1,6 @@ +import pkg_resources + +try: + __version__ = pkg_resources.get_distribution('setuptools').version +except Exception: + __version__ = 'unknown' diff --git a/venv/lib/python3.8/site-packages/setuptools/wheel.py b/venv/lib/python3.8/site-packages/setuptools/wheel.py new file mode 100644 index 0000000..025aaa8 --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/wheel.py @@ -0,0 +1,220 @@ +"""Wheels support.""" + +from distutils.util import get_platform +from distutils import log +import email +import itertools +import os +import posixpath +import re +import zipfile + +import pkg_resources +import setuptools +from pkg_resources import parse_version +from setuptools.extern.packaging.tags import sys_tags +from setuptools.extern.packaging.utils import canonicalize_name +from setuptools.extern.six import PY3 +from setuptools.command.egg_info import write_requirements + + +__metaclass__ = type + + +WHEEL_NAME = re.compile( + r"""^(?P<project_name>.+?)-(?P<version>\d.*?) + ((-(?P<build>\d.*?))?-(?P<py_version>.+?)-(?P<abi>.+?)-(?P<platform>.+?) + )\.whl$""", + re.VERBOSE).match + +NAMESPACE_PACKAGE_INIT = '''\ +try: + __import__('pkg_resources').declare_namespace(__name__) +except ImportError: + __path__ = __import__('pkgutil').extend_path(__path__, __name__) +''' + + +def unpack(src_dir, dst_dir): + '''Move everything under `src_dir` to `dst_dir`, and delete the former.''' + for dirpath, dirnames, filenames in os.walk(src_dir): + subdir = os.path.relpath(dirpath, src_dir) + for f in filenames: + src = os.path.join(dirpath, f) + dst = os.path.join(dst_dir, subdir, f) + os.renames(src, dst) + for n, d in reversed(list(enumerate(dirnames))): + src = os.path.join(dirpath, d) + dst = os.path.join(dst_dir, subdir, d) + if not os.path.exists(dst): + # Directory does not exist in destination, + # rename it and prune it from os.walk list. + os.renames(src, dst) + del dirnames[n] + # Cleanup. + for dirpath, dirnames, filenames in os.walk(src_dir, topdown=True): + assert not filenames + os.rmdir(dirpath) + + +class Wheel: + + def __init__(self, filename): + match = WHEEL_NAME(os.path.basename(filename)) + if match is None: + raise ValueError('invalid wheel name: %r' % filename) + self.filename = filename + for k, v in match.groupdict().items(): + setattr(self, k, v) + + def tags(self): + '''List tags (py_version, abi, platform) supported by this wheel.''' + return itertools.product( + self.py_version.split('.'), + self.abi.split('.'), + self.platform.split('.'), + ) + + def is_compatible(self): + '''Is the wheel is compatible with the current platform?''' + supported_tags = set((t.interpreter, t.abi, t.platform) for t in sys_tags()) + return next((True for t in self.tags() if t in supported_tags), False) + + def egg_name(self): + return pkg_resources.Distribution( + project_name=self.project_name, version=self.version, + platform=(None if self.platform == 'any' else get_platform()), + ).egg_name() + '.egg' + + def get_dist_info(self, zf): + # find the correct name of the .dist-info dir in the wheel file + for member in zf.namelist(): + dirname = posixpath.dirname(member) + if (dirname.endswith('.dist-info') and + canonicalize_name(dirname).startswith( + canonicalize_name(self.project_name))): + return dirname + raise ValueError("unsupported wheel format. .dist-info not found") + + def install_as_egg(self, destination_eggdir): + '''Install wheel as an egg directory.''' + with zipfile.ZipFile(self.filename) as zf: + self._install_as_egg(destination_eggdir, zf) + + def _install_as_egg(self, destination_eggdir, zf): + dist_basename = '%s-%s' % (self.project_name, self.version) + dist_info = self.get_dist_info(zf) + dist_data = '%s.data' % dist_basename + egg_info = os.path.join(destination_eggdir, 'EGG-INFO') + + self._convert_metadata(zf, destination_eggdir, dist_info, egg_info) + self._move_data_entries(destination_eggdir, dist_data) + self._fix_namespace_packages(egg_info, destination_eggdir) + + @staticmethod + def _convert_metadata(zf, destination_eggdir, dist_info, egg_info): + def get_metadata(name): + with zf.open(posixpath.join(dist_info, name)) as fp: + value = fp.read().decode('utf-8') if PY3 else fp.read() + return email.parser.Parser().parsestr(value) + + wheel_metadata = get_metadata('WHEEL') + # Check wheel format version is supported. + wheel_version = parse_version(wheel_metadata.get('Wheel-Version')) + wheel_v1 = ( + parse_version('1.0') <= wheel_version < parse_version('2.0dev0') + ) + if not wheel_v1: + raise ValueError( + 'unsupported wheel format version: %s' % wheel_version) + # Extract to target directory. + os.mkdir(destination_eggdir) + zf.extractall(destination_eggdir) + # Convert metadata. + dist_info = os.path.join(destination_eggdir, dist_info) + dist = pkg_resources.Distribution.from_location( + destination_eggdir, dist_info, + metadata=pkg_resources.PathMetadata(destination_eggdir, dist_info), + ) + + # Note: Evaluate and strip markers now, + # as it's difficult to convert back from the syntax: + # foobar; "linux" in sys_platform and extra == 'test' + def raw_req(req): + req.marker = None + return str(req) + install_requires = list(sorted(map(raw_req, dist.requires()))) + extras_require = { + extra: sorted( + req + for req in map(raw_req, dist.requires((extra,))) + if req not in install_requires + ) + for extra in dist.extras + } + os.rename(dist_info, egg_info) + os.rename( + os.path.join(egg_info, 'METADATA'), + os.path.join(egg_info, 'PKG-INFO'), + ) + setup_dist = setuptools.Distribution( + attrs=dict( + install_requires=install_requires, + extras_require=extras_require, + ), + ) + # Temporarily disable info traces. + log_threshold = log._global_log.threshold + log.set_threshold(log.WARN) + try: + write_requirements( + setup_dist.get_command_obj('egg_info'), + None, + os.path.join(egg_info, 'requires.txt'), + ) + finally: + log.set_threshold(log_threshold) + + @staticmethod + def _move_data_entries(destination_eggdir, dist_data): + """Move data entries to their correct location.""" + dist_data = os.path.join(destination_eggdir, dist_data) + dist_data_scripts = os.path.join(dist_data, 'scripts') + if os.path.exists(dist_data_scripts): + egg_info_scripts = os.path.join( + destination_eggdir, 'EGG-INFO', 'scripts') + os.mkdir(egg_info_scripts) + for entry in os.listdir(dist_data_scripts): + # Remove bytecode, as it's not properly handled + # during easy_install scripts install phase. + if entry.endswith('.pyc'): + os.unlink(os.path.join(dist_data_scripts, entry)) + else: + os.rename( + os.path.join(dist_data_scripts, entry), + os.path.join(egg_info_scripts, entry), + ) + os.rmdir(dist_data_scripts) + for subdir in filter(os.path.exists, ( + os.path.join(dist_data, d) + for d in ('data', 'headers', 'purelib', 'platlib') + )): + unpack(subdir, destination_eggdir) + if os.path.exists(dist_data): + os.rmdir(dist_data) + + @staticmethod + def _fix_namespace_packages(egg_info, destination_eggdir): + namespace_packages = os.path.join( + egg_info, 'namespace_packages.txt') + if os.path.exists(namespace_packages): + with open(namespace_packages) as fp: + namespace_packages = fp.read().split() + for mod in namespace_packages: + mod_dir = os.path.join(destination_eggdir, *mod.split('.')) + mod_init = os.path.join(mod_dir, '__init__.py') + if not os.path.exists(mod_dir): + os.mkdir(mod_dir) + if not os.path.exists(mod_init): + with open(mod_init, 'w') as fp: + fp.write(NAMESPACE_PACKAGE_INIT) diff --git a/venv/lib/python3.8/site-packages/setuptools/windows_support.py b/venv/lib/python3.8/site-packages/setuptools/windows_support.py new file mode 100644 index 0000000..cb977cf --- /dev/null +++ b/venv/lib/python3.8/site-packages/setuptools/windows_support.py @@ -0,0 +1,29 @@ +import platform +import ctypes + + +def windows_only(func): + if platform.system() != 'Windows': + return lambda *args, **kwargs: None + return func + + +@windows_only +def hide_file(path): + """ + Set the hidden attribute on a file or directory. + + From http://stackoverflow.com/questions/19622133/ + + `path` must be text. + """ + __import__('ctypes.wintypes') + SetFileAttributes = ctypes.windll.kernel32.SetFileAttributesW + SetFileAttributes.argtypes = ctypes.wintypes.LPWSTR, ctypes.wintypes.DWORD + SetFileAttributes.restype = ctypes.wintypes.BOOL + + FILE_ATTRIBUTE_HIDDEN = 0x02 + + ret = SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN) + if not ret: + raise ctypes.WinError() diff --git a/venv/lib/python3.8/site-packages/six-1.16.0.dist-info/INSTALLER b/venv/lib/python3.8/site-packages/six-1.16.0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python3.8/site-packages/six-1.16.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.8/site-packages/six-1.16.0.dist-info/LICENSE b/venv/lib/python3.8/site-packages/six-1.16.0.dist-info/LICENSE new file mode 100644 index 0000000..de66331 --- /dev/null +++ b/venv/lib/python3.8/site-packages/six-1.16.0.dist-info/LICENSE @@ -0,0 +1,18 @@ +Copyright (c) 2010-2020 Benjamin Peterson + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/venv/lib/python3.8/site-packages/six-1.16.0.dist-info/METADATA b/venv/lib/python3.8/site-packages/six-1.16.0.dist-info/METADATA new file mode 100644 index 0000000..6d7525c --- /dev/null +++ b/venv/lib/python3.8/site-packages/six-1.16.0.dist-info/METADATA @@ -0,0 +1,49 @@ +Metadata-Version: 2.1 +Name: six +Version: 1.16.0 +Summary: Python 2 and 3 compatibility utilities +Home-page: https://github.com/benjaminp/six +Author: Benjamin Peterson +Author-email: benjamin@python.org +License: MIT +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 3 +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Topic :: Software Development :: Libraries +Classifier: Topic :: Utilities +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.* + +.. image:: https://img.shields.io/pypi/v/six.svg + :target: https://pypi.org/project/six/ + :alt: six on PyPI + +.. image:: https://travis-ci.org/benjaminp/six.svg?branch=master + :target: https://travis-ci.org/benjaminp/six + :alt: six on TravisCI + +.. image:: https://readthedocs.org/projects/six/badge/?version=latest + :target: https://six.readthedocs.io/ + :alt: six's documentation on Read the Docs + +.. image:: https://img.shields.io/badge/license-MIT-green.svg + :target: https://github.com/benjaminp/six/blob/master/LICENSE + :alt: MIT License badge + +Six is a Python 2 and 3 compatibility library. It provides utility functions +for smoothing over the differences between the Python versions with the goal of +writing Python code that is compatible on both Python versions. See the +documentation for more information on what is provided. + +Six supports Python 2.7 and 3.3+. It is contained in only one Python +file, so it can be easily copied into your project. (The copyright and license +notice must be retained.) + +Online documentation is at https://six.readthedocs.io/. + +Bugs can be reported to https://github.com/benjaminp/six. The code can also +be found there. + + diff --git a/venv/lib/python3.8/site-packages/six-1.16.0.dist-info/RECORD b/venv/lib/python3.8/site-packages/six-1.16.0.dist-info/RECORD new file mode 100644 index 0000000..4de46ba --- /dev/null +++ b/venv/lib/python3.8/site-packages/six-1.16.0.dist-info/RECORD @@ -0,0 +1,8 @@ +__pycache__/six.cpython-38.pyc,, +six-1.16.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +six-1.16.0.dist-info/LICENSE,sha256=i7hQxWWqOJ_cFvOkaWWtI9gq3_YPI5P8J2K2MYXo5sk,1066 +six-1.16.0.dist-info/METADATA,sha256=VQcGIFCAEmfZcl77E5riPCN4v2TIsc_qtacnjxKHJoI,1795 +six-1.16.0.dist-info/RECORD,, +six-1.16.0.dist-info/WHEEL,sha256=Z-nyYpwrcSqxfdux5Mbn_DQ525iP7J2DG3JgGvOYyTQ,110 +six-1.16.0.dist-info/top_level.txt,sha256=_iVH_iYEtEXnD8nYGQYpYFUvkUW9sEO1GYbkeKSAais,4 +six.py,sha256=TOOfQi7nFGfMrIvtdr6wX4wyHH8M7aknmuLfo2cBBrM,34549 diff --git a/venv/lib/python3.8/site-packages/six-1.16.0.dist-info/WHEEL b/venv/lib/python3.8/site-packages/six-1.16.0.dist-info/WHEEL new file mode 100644 index 0000000..01b8fc7 --- /dev/null +++ b/venv/lib/python3.8/site-packages/six-1.16.0.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.36.2) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/venv/lib/python3.8/site-packages/six-1.16.0.dist-info/top_level.txt b/venv/lib/python3.8/site-packages/six-1.16.0.dist-info/top_level.txt new file mode 100644 index 0000000..ffe2fce --- /dev/null +++ b/venv/lib/python3.8/site-packages/six-1.16.0.dist-info/top_level.txt @@ -0,0 +1 @@ +six diff --git a/venv/lib/python3.8/site-packages/six.py b/venv/lib/python3.8/site-packages/six.py new file mode 100644 index 0000000..4e15675 --- /dev/null +++ b/venv/lib/python3.8/site-packages/six.py @@ -0,0 +1,998 @@ +# Copyright (c) 2010-2020 Benjamin Peterson +# +# 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. + +"""Utilities for writing code that runs on Python 2 and 3""" + +from __future__ import absolute_import + +import functools +import itertools +import operator +import sys +import types + +__author__ = "Benjamin Peterson <benjamin@python.org>" +__version__ = "1.16.0" + + +# Useful for very coarse version differentiation. +PY2 = sys.version_info[0] == 2 +PY3 = sys.version_info[0] == 3 +PY34 = sys.version_info[0:2] >= (3, 4) + +if PY3: + string_types = str, + integer_types = int, + class_types = type, + text_type = str + binary_type = bytes + + MAXSIZE = sys.maxsize +else: + string_types = basestring, + integer_types = (int, long) + class_types = (type, types.ClassType) + text_type = unicode + binary_type = str + + if sys.platform.startswith("java"): + # Jython always uses 32 bits. + MAXSIZE = int((1 << 31) - 1) + else: + # It's possible to have sizeof(long) != sizeof(Py_ssize_t). + class X(object): + + def __len__(self): + return 1 << 31 + try: + len(X()) + except OverflowError: + # 32-bit + MAXSIZE = int((1 << 31) - 1) + else: + # 64-bit + MAXSIZE = int((1 << 63) - 1) + del X + +if PY34: + from importlib.util import spec_from_loader +else: + spec_from_loader = None + + +def _add_doc(func, doc): + """Add documentation to a function.""" + func.__doc__ = doc + + +def _import_module(name): + """Import module, returning the module after the last dot.""" + __import__(name) + return sys.modules[name] + + +class _LazyDescr(object): + + def __init__(self, name): + self.name = name + + def __get__(self, obj, tp): + result = self._resolve() + setattr(obj, self.name, result) # Invokes __set__. + try: + # This is a bit ugly, but it avoids running this again by + # removing this descriptor. + delattr(obj.__class__, self.name) + except AttributeError: + pass + return result + + +class MovedModule(_LazyDescr): + + def __init__(self, name, old, new=None): + super(MovedModule, self).__init__(name) + if PY3: + if new is None: + new = name + self.mod = new + else: + self.mod = old + + def _resolve(self): + return _import_module(self.mod) + + def __getattr__(self, attr): + _module = self._resolve() + value = getattr(_module, attr) + setattr(self, attr, value) + return value + + +class _LazyModule(types.ModuleType): + + def __init__(self, name): + super(_LazyModule, self).__init__(name) + self.__doc__ = self.__class__.__doc__ + + def __dir__(self): + attrs = ["__doc__", "__name__"] + attrs += [attr.name for attr in self._moved_attributes] + return attrs + + # Subclasses should override this + _moved_attributes = [] + + +class MovedAttribute(_LazyDescr): + + def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None): + super(MovedAttribute, self).__init__(name) + if PY3: + if new_mod is None: + new_mod = name + self.mod = new_mod + if new_attr is None: + if old_attr is None: + new_attr = name + else: + new_attr = old_attr + self.attr = new_attr + else: + self.mod = old_mod + if old_attr is None: + old_attr = name + self.attr = old_attr + + def _resolve(self): + module = _import_module(self.mod) + return getattr(module, self.attr) + + +class _SixMetaPathImporter(object): + + """ + A meta path importer to import six.moves and its submodules. + + This class implements a PEP302 finder and loader. It should be compatible + with Python 2.5 and all existing versions of Python3 + """ + + def __init__(self, six_module_name): + self.name = six_module_name + self.known_modules = {} + + def _add_module(self, mod, *fullnames): + for fullname in fullnames: + self.known_modules[self.name + "." + fullname] = mod + + def _get_module(self, fullname): + return self.known_modules[self.name + "." + fullname] + + def find_module(self, fullname, path=None): + if fullname in self.known_modules: + return self + return None + + def find_spec(self, fullname, path, target=None): + if fullname in self.known_modules: + return spec_from_loader(fullname, self) + return None + + def __get_module(self, fullname): + try: + return self.known_modules[fullname] + except KeyError: + raise ImportError("This loader does not know module " + fullname) + + def load_module(self, fullname): + try: + # in case of a reload + return sys.modules[fullname] + except KeyError: + pass + mod = self.__get_module(fullname) + if isinstance(mod, MovedModule): + mod = mod._resolve() + else: + mod.__loader__ = self + sys.modules[fullname] = mod + return mod + + def is_package(self, fullname): + """ + Return true, if the named module is a package. + + We need this method to get correct spec objects with + Python 3.4 (see PEP451) + """ + return hasattr(self.__get_module(fullname), "__path__") + + def get_code(self, fullname): + """Return None + + Required, if is_package is implemented""" + self.__get_module(fullname) # eventually raises ImportError + return None + get_source = get_code # same as get_code + + def create_module(self, spec): + return self.load_module(spec.name) + + def exec_module(self, module): + pass + +_importer = _SixMetaPathImporter(__name__) + + +class _MovedItems(_LazyModule): + + """Lazy loading of moved objects""" + __path__ = [] # mark as package + + +_moved_attributes = [ + MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"), + MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"), + MovedAttribute("filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"), + MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"), + MovedAttribute("intern", "__builtin__", "sys"), + MovedAttribute("map", "itertools", "builtins", "imap", "map"), + MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"), + MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"), + MovedAttribute("getoutput", "commands", "subprocess"), + MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"), + MovedAttribute("reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload"), + MovedAttribute("reduce", "__builtin__", "functools"), + MovedAttribute("shlex_quote", "pipes", "shlex", "quote"), + MovedAttribute("StringIO", "StringIO", "io"), + MovedAttribute("UserDict", "UserDict", "collections"), + MovedAttribute("UserList", "UserList", "collections"), + MovedAttribute("UserString", "UserString", "collections"), + MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"), + MovedAttribute("zip", "itertools", "builtins", "izip", "zip"), + MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"), + MovedModule("builtins", "__builtin__"), + MovedModule("configparser", "ConfigParser"), + MovedModule("collections_abc", "collections", "collections.abc" if sys.version_info >= (3, 3) else "collections"), + MovedModule("copyreg", "copy_reg"), + MovedModule("dbm_gnu", "gdbm", "dbm.gnu"), + MovedModule("dbm_ndbm", "dbm", "dbm.ndbm"), + MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread" if sys.version_info < (3, 9) else "_thread"), + MovedModule("http_cookiejar", "cookielib", "http.cookiejar"), + MovedModule("http_cookies", "Cookie", "http.cookies"), + MovedModule("html_entities", "htmlentitydefs", "html.entities"), + MovedModule("html_parser", "HTMLParser", "html.parser"), + MovedModule("http_client", "httplib", "http.client"), + MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"), + MovedModule("email_mime_image", "email.MIMEImage", "email.mime.image"), + MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"), + MovedModule("email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart"), + MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"), + MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"), + MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"), + MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"), + MovedModule("cPickle", "cPickle", "pickle"), + MovedModule("queue", "Queue"), + MovedModule("reprlib", "repr"), + MovedModule("socketserver", "SocketServer"), + MovedModule("_thread", "thread", "_thread"), + MovedModule("tkinter", "Tkinter"), + MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"), + MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"), + MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"), + MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"), + MovedModule("tkinter_tix", "Tix", "tkinter.tix"), + MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"), + MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"), + MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"), + MovedModule("tkinter_colorchooser", "tkColorChooser", + "tkinter.colorchooser"), + MovedModule("tkinter_commondialog", "tkCommonDialog", + "tkinter.commondialog"), + MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"), + MovedModule("tkinter_font", "tkFont", "tkinter.font"), + MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"), + MovedModule("tkinter_tksimpledialog", "tkSimpleDialog", + "tkinter.simpledialog"), + MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"), + MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"), + MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"), + MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"), + MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"), + MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"), +] +# Add windows specific modules. +if sys.platform == "win32": + _moved_attributes += [ + MovedModule("winreg", "_winreg"), + ] + +for attr in _moved_attributes: + setattr(_MovedItems, attr.name, attr) + if isinstance(attr, MovedModule): + _importer._add_module(attr, "moves." + attr.name) +del attr + +_MovedItems._moved_attributes = _moved_attributes + +moves = _MovedItems(__name__ + ".moves") +_importer._add_module(moves, "moves") + + +class Module_six_moves_urllib_parse(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_parse""" + + +_urllib_parse_moved_attributes = [ + MovedAttribute("ParseResult", "urlparse", "urllib.parse"), + MovedAttribute("SplitResult", "urlparse", "urllib.parse"), + MovedAttribute("parse_qs", "urlparse", "urllib.parse"), + MovedAttribute("parse_qsl", "urlparse", "urllib.parse"), + MovedAttribute("urldefrag", "urlparse", "urllib.parse"), + MovedAttribute("urljoin", "urlparse", "urllib.parse"), + MovedAttribute("urlparse", "urlparse", "urllib.parse"), + MovedAttribute("urlsplit", "urlparse", "urllib.parse"), + MovedAttribute("urlunparse", "urlparse", "urllib.parse"), + MovedAttribute("urlunsplit", "urlparse", "urllib.parse"), + MovedAttribute("quote", "urllib", "urllib.parse"), + MovedAttribute("quote_plus", "urllib", "urllib.parse"), + MovedAttribute("unquote", "urllib", "urllib.parse"), + MovedAttribute("unquote_plus", "urllib", "urllib.parse"), + MovedAttribute("unquote_to_bytes", "urllib", "urllib.parse", "unquote", "unquote_to_bytes"), + MovedAttribute("urlencode", "urllib", "urllib.parse"), + MovedAttribute("splitquery", "urllib", "urllib.parse"), + MovedAttribute("splittag", "urllib", "urllib.parse"), + MovedAttribute("splituser", "urllib", "urllib.parse"), + MovedAttribute("splitvalue", "urllib", "urllib.parse"), + MovedAttribute("uses_fragment", "urlparse", "urllib.parse"), + MovedAttribute("uses_netloc", "urlparse", "urllib.parse"), + MovedAttribute("uses_params", "urlparse", "urllib.parse"), + MovedAttribute("uses_query", "urlparse", "urllib.parse"), + MovedAttribute("uses_relative", "urlparse", "urllib.parse"), +] +for attr in _urllib_parse_moved_attributes: + setattr(Module_six_moves_urllib_parse, attr.name, attr) +del attr + +Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes + +_importer._add_module(Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"), + "moves.urllib_parse", "moves.urllib.parse") + + +class Module_six_moves_urllib_error(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_error""" + + +_urllib_error_moved_attributes = [ + MovedAttribute("URLError", "urllib2", "urllib.error"), + MovedAttribute("HTTPError", "urllib2", "urllib.error"), + MovedAttribute("ContentTooShortError", "urllib", "urllib.error"), +] +for attr in _urllib_error_moved_attributes: + setattr(Module_six_moves_urllib_error, attr.name, attr) +del attr + +Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes + +_importer._add_module(Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"), + "moves.urllib_error", "moves.urllib.error") + + +class Module_six_moves_urllib_request(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_request""" + + +_urllib_request_moved_attributes = [ + MovedAttribute("urlopen", "urllib2", "urllib.request"), + MovedAttribute("install_opener", "urllib2", "urllib.request"), + MovedAttribute("build_opener", "urllib2", "urllib.request"), + MovedAttribute("pathname2url", "urllib", "urllib.request"), + MovedAttribute("url2pathname", "urllib", "urllib.request"), + MovedAttribute("getproxies", "urllib", "urllib.request"), + MovedAttribute("Request", "urllib2", "urllib.request"), + MovedAttribute("OpenerDirector", "urllib2", "urllib.request"), + MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"), + MovedAttribute("ProxyHandler", "urllib2", "urllib.request"), + MovedAttribute("BaseHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"), + MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"), + MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"), + MovedAttribute("FileHandler", "urllib2", "urllib.request"), + MovedAttribute("FTPHandler", "urllib2", "urllib.request"), + MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"), + MovedAttribute("UnknownHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"), + MovedAttribute("urlretrieve", "urllib", "urllib.request"), + MovedAttribute("urlcleanup", "urllib", "urllib.request"), + MovedAttribute("URLopener", "urllib", "urllib.request"), + MovedAttribute("FancyURLopener", "urllib", "urllib.request"), + MovedAttribute("proxy_bypass", "urllib", "urllib.request"), + MovedAttribute("parse_http_list", "urllib2", "urllib.request"), + MovedAttribute("parse_keqv_list", "urllib2", "urllib.request"), +] +for attr in _urllib_request_moved_attributes: + setattr(Module_six_moves_urllib_request, attr.name, attr) +del attr + +Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes + +_importer._add_module(Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"), + "moves.urllib_request", "moves.urllib.request") + + +class Module_six_moves_urllib_response(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_response""" + + +_urllib_response_moved_attributes = [ + MovedAttribute("addbase", "urllib", "urllib.response"), + MovedAttribute("addclosehook", "urllib", "urllib.response"), + MovedAttribute("addinfo", "urllib", "urllib.response"), + MovedAttribute("addinfourl", "urllib", "urllib.response"), +] +for attr in _urllib_response_moved_attributes: + setattr(Module_six_moves_urllib_response, attr.name, attr) +del attr + +Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes + +_importer._add_module(Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"), + "moves.urllib_response", "moves.urllib.response") + + +class Module_six_moves_urllib_robotparser(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_robotparser""" + + +_urllib_robotparser_moved_attributes = [ + MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"), +] +for attr in _urllib_robotparser_moved_attributes: + setattr(Module_six_moves_urllib_robotparser, attr.name, attr) +del attr + +Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes + +_importer._add_module(Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"), + "moves.urllib_robotparser", "moves.urllib.robotparser") + + +class Module_six_moves_urllib(types.ModuleType): + + """Create a six.moves.urllib namespace that resembles the Python 3 namespace""" + __path__ = [] # mark as package + parse = _importer._get_module("moves.urllib_parse") + error = _importer._get_module("moves.urllib_error") + request = _importer._get_module("moves.urllib_request") + response = _importer._get_module("moves.urllib_response") + robotparser = _importer._get_module("moves.urllib_robotparser") + + def __dir__(self): + return ['parse', 'error', 'request', 'response', 'robotparser'] + +_importer._add_module(Module_six_moves_urllib(__name__ + ".moves.urllib"), + "moves.urllib") + + +def add_move(move): + """Add an item to six.moves.""" + setattr(_MovedItems, move.name, move) + + +def remove_move(name): + """Remove item from six.moves.""" + try: + delattr(_MovedItems, name) + except AttributeError: + try: + del moves.__dict__[name] + except KeyError: + raise AttributeError("no such move, %r" % (name,)) + + +if PY3: + _meth_func = "__func__" + _meth_self = "__self__" + + _func_closure = "__closure__" + _func_code = "__code__" + _func_defaults = "__defaults__" + _func_globals = "__globals__" +else: + _meth_func = "im_func" + _meth_self = "im_self" + + _func_closure = "func_closure" + _func_code = "func_code" + _func_defaults = "func_defaults" + _func_globals = "func_globals" + + +try: + advance_iterator = next +except NameError: + def advance_iterator(it): + return it.next() +next = advance_iterator + + +try: + callable = callable +except NameError: + def callable(obj): + return any("__call__" in klass.__dict__ for klass in type(obj).__mro__) + + +if PY3: + def get_unbound_function(unbound): + return unbound + + create_bound_method = types.MethodType + + def create_unbound_method(func, cls): + return func + + Iterator = object +else: + def get_unbound_function(unbound): + return unbound.im_func + + def create_bound_method(func, obj): + return types.MethodType(func, obj, obj.__class__) + + def create_unbound_method(func, cls): + return types.MethodType(func, None, cls) + + class Iterator(object): + + def next(self): + return type(self).__next__(self) + + callable = callable +_add_doc(get_unbound_function, + """Get the function out of a possibly unbound function""") + + +get_method_function = operator.attrgetter(_meth_func) +get_method_self = operator.attrgetter(_meth_self) +get_function_closure = operator.attrgetter(_func_closure) +get_function_code = operator.attrgetter(_func_code) +get_function_defaults = operator.attrgetter(_func_defaults) +get_function_globals = operator.attrgetter(_func_globals) + + +if PY3: + def iterkeys(d, **kw): + return iter(d.keys(**kw)) + + def itervalues(d, **kw): + return iter(d.values(**kw)) + + def iteritems(d, **kw): + return iter(d.items(**kw)) + + def iterlists(d, **kw): + return iter(d.lists(**kw)) + + viewkeys = operator.methodcaller("keys") + + viewvalues = operator.methodcaller("values") + + viewitems = operator.methodcaller("items") +else: + def iterkeys(d, **kw): + return d.iterkeys(**kw) + + def itervalues(d, **kw): + return d.itervalues(**kw) + + def iteritems(d, **kw): + return d.iteritems(**kw) + + def iterlists(d, **kw): + return d.iterlists(**kw) + + viewkeys = operator.methodcaller("viewkeys") + + viewvalues = operator.methodcaller("viewvalues") + + viewitems = operator.methodcaller("viewitems") + +_add_doc(iterkeys, "Return an iterator over the keys of a dictionary.") +_add_doc(itervalues, "Return an iterator over the values of a dictionary.") +_add_doc(iteritems, + "Return an iterator over the (key, value) pairs of a dictionary.") +_add_doc(iterlists, + "Return an iterator over the (key, [values]) pairs of a dictionary.") + + +if PY3: + def b(s): + return s.encode("latin-1") + + def u(s): + return s + unichr = chr + import struct + int2byte = struct.Struct(">B").pack + del struct + byte2int = operator.itemgetter(0) + indexbytes = operator.getitem + iterbytes = iter + import io + StringIO = io.StringIO + BytesIO = io.BytesIO + del io + _assertCountEqual = "assertCountEqual" + if sys.version_info[1] <= 1: + _assertRaisesRegex = "assertRaisesRegexp" + _assertRegex = "assertRegexpMatches" + _assertNotRegex = "assertNotRegexpMatches" + else: + _assertRaisesRegex = "assertRaisesRegex" + _assertRegex = "assertRegex" + _assertNotRegex = "assertNotRegex" +else: + def b(s): + return s + # Workaround for standalone backslash + + def u(s): + return unicode(s.replace(r'\\', r'\\\\'), "unicode_escape") + unichr = unichr + int2byte = chr + + def byte2int(bs): + return ord(bs[0]) + + def indexbytes(buf, i): + return ord(buf[i]) + iterbytes = functools.partial(itertools.imap, ord) + import StringIO + StringIO = BytesIO = StringIO.StringIO + _assertCountEqual = "assertItemsEqual" + _assertRaisesRegex = "assertRaisesRegexp" + _assertRegex = "assertRegexpMatches" + _assertNotRegex = "assertNotRegexpMatches" +_add_doc(b, """Byte literal""") +_add_doc(u, """Text literal""") + + +def assertCountEqual(self, *args, **kwargs): + return getattr(self, _assertCountEqual)(*args, **kwargs) + + +def assertRaisesRegex(self, *args, **kwargs): + return getattr(self, _assertRaisesRegex)(*args, **kwargs) + + +def assertRegex(self, *args, **kwargs): + return getattr(self, _assertRegex)(*args, **kwargs) + + +def assertNotRegex(self, *args, **kwargs): + return getattr(self, _assertNotRegex)(*args, **kwargs) + + +if PY3: + exec_ = getattr(moves.builtins, "exec") + + def reraise(tp, value, tb=None): + try: + if value is None: + value = tp() + if value.__traceback__ is not tb: + raise value.with_traceback(tb) + raise value + finally: + value = None + tb = None + +else: + def exec_(_code_, _globs_=None, _locs_=None): + """Execute code in a namespace.""" + if _globs_ is None: + frame = sys._getframe(1) + _globs_ = frame.f_globals + if _locs_ is None: + _locs_ = frame.f_locals + del frame + elif _locs_ is None: + _locs_ = _globs_ + exec("""exec _code_ in _globs_, _locs_""") + + exec_("""def reraise(tp, value, tb=None): + try: + raise tp, value, tb + finally: + tb = None +""") + + +if sys.version_info[:2] > (3,): + exec_("""def raise_from(value, from_value): + try: + raise value from from_value + finally: + value = None +""") +else: + def raise_from(value, from_value): + raise value + + +print_ = getattr(moves.builtins, "print", None) +if print_ is None: + def print_(*args, **kwargs): + """The new-style print function for Python 2.4 and 2.5.""" + fp = kwargs.pop("file", sys.stdout) + if fp is None: + return + + def write(data): + if not isinstance(data, basestring): + data = str(data) + # If the file has an encoding, encode unicode with it. + if (isinstance(fp, file) and + isinstance(data, unicode) and + fp.encoding is not None): + errors = getattr(fp, "errors", None) + if errors is None: + errors = "strict" + data = data.encode(fp.encoding, errors) + fp.write(data) + want_unicode = False + sep = kwargs.pop("sep", None) + if sep is not None: + if isinstance(sep, unicode): + want_unicode = True + elif not isinstance(sep, str): + raise TypeError("sep must be None or a string") + end = kwargs.pop("end", None) + if end is not None: + if isinstance(end, unicode): + want_unicode = True + elif not isinstance(end, str): + raise TypeError("end must be None or a string") + if kwargs: + raise TypeError("invalid keyword arguments to print()") + if not want_unicode: + for arg in args: + if isinstance(arg, unicode): + want_unicode = True + break + if want_unicode: + newline = unicode("\n") + space = unicode(" ") + else: + newline = "\n" + space = " " + if sep is None: + sep = space + if end is None: + end = newline + for i, arg in enumerate(args): + if i: + write(sep) + write(arg) + write(end) +if sys.version_info[:2] < (3, 3): + _print = print_ + + def print_(*args, **kwargs): + fp = kwargs.get("file", sys.stdout) + flush = kwargs.pop("flush", False) + _print(*args, **kwargs) + if flush and fp is not None: + fp.flush() + +_add_doc(reraise, """Reraise an exception.""") + +if sys.version_info[0:2] < (3, 4): + # This does exactly the same what the :func:`py3:functools.update_wrapper` + # function does on Python versions after 3.2. It sets the ``__wrapped__`` + # attribute on ``wrapper`` object and it doesn't raise an error if any of + # the attributes mentioned in ``assigned`` and ``updated`` are missing on + # ``wrapped`` object. + def _update_wrapper(wrapper, wrapped, + assigned=functools.WRAPPER_ASSIGNMENTS, + updated=functools.WRAPPER_UPDATES): + for attr in assigned: + try: + value = getattr(wrapped, attr) + except AttributeError: + continue + else: + setattr(wrapper, attr, value) + for attr in updated: + getattr(wrapper, attr).update(getattr(wrapped, attr, {})) + wrapper.__wrapped__ = wrapped + return wrapper + _update_wrapper.__doc__ = functools.update_wrapper.__doc__ + + def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS, + updated=functools.WRAPPER_UPDATES): + return functools.partial(_update_wrapper, wrapped=wrapped, + assigned=assigned, updated=updated) + wraps.__doc__ = functools.wraps.__doc__ + +else: + wraps = functools.wraps + + +def with_metaclass(meta, *bases): + """Create a base class with a metaclass.""" + # This requires a bit of explanation: the basic idea is to make a dummy + # metaclass for one level of class instantiation that replaces itself with + # the actual metaclass. + class metaclass(type): + + def __new__(cls, name, this_bases, d): + if sys.version_info[:2] >= (3, 7): + # This version introduced PEP 560 that requires a bit + # of extra care (we mimic what is done by __build_class__). + resolved_bases = types.resolve_bases(bases) + if resolved_bases is not bases: + d['__orig_bases__'] = bases + else: + resolved_bases = bases + return meta(name, resolved_bases, d) + + @classmethod + def __prepare__(cls, name, this_bases): + return meta.__prepare__(name, bases) + return type.__new__(metaclass, 'temporary_class', (), {}) + + +def add_metaclass(metaclass): + """Class decorator for creating a class with a metaclass.""" + def wrapper(cls): + orig_vars = cls.__dict__.copy() + slots = orig_vars.get('__slots__') + if slots is not None: + if isinstance(slots, str): + slots = [slots] + for slots_var in slots: + orig_vars.pop(slots_var) + orig_vars.pop('__dict__', None) + orig_vars.pop('__weakref__', None) + if hasattr(cls, '__qualname__'): + orig_vars['__qualname__'] = cls.__qualname__ + return metaclass(cls.__name__, cls.__bases__, orig_vars) + return wrapper + + +def ensure_binary(s, encoding='utf-8', errors='strict'): + """Coerce **s** to six.binary_type. + + For Python 2: + - `unicode` -> encoded to `str` + - `str` -> `str` + + For Python 3: + - `str` -> encoded to `bytes` + - `bytes` -> `bytes` + """ + if isinstance(s, binary_type): + return s + if isinstance(s, text_type): + return s.encode(encoding, errors) + raise TypeError("not expecting type '%s'" % type(s)) + + +def ensure_str(s, encoding='utf-8', errors='strict'): + """Coerce *s* to `str`. + + For Python 2: + - `unicode` -> encoded to `str` + - `str` -> `str` + + For Python 3: + - `str` -> `str` + - `bytes` -> decoded to `str` + """ + # Optimization: Fast return for the common case. + if type(s) is str: + return s + if PY2 and isinstance(s, text_type): + return s.encode(encoding, errors) + elif PY3 and isinstance(s, binary_type): + return s.decode(encoding, errors) + elif not isinstance(s, (text_type, binary_type)): + raise TypeError("not expecting type '%s'" % type(s)) + return s + + +def ensure_text(s, encoding='utf-8', errors='strict'): + """Coerce *s* to six.text_type. + + For Python 2: + - `unicode` -> `unicode` + - `str` -> `unicode` + + For Python 3: + - `str` -> `str` + - `bytes` -> decoded to `str` + """ + if isinstance(s, binary_type): + return s.decode(encoding, errors) + elif isinstance(s, text_type): + return s + else: + raise TypeError("not expecting type '%s'" % type(s)) + + +def python_2_unicode_compatible(klass): + """ + A class decorator that defines __unicode__ and __str__ methods under Python 2. + Under Python 3 it does nothing. + + To support Python 2 and 3 with a single code base, define a __str__ method + returning text and apply this decorator to the class. + """ + if PY2: + if '__str__' not in klass.__dict__: + raise ValueError("@python_2_unicode_compatible cannot be applied " + "to %s because it doesn't define __str__()." % + klass.__name__) + klass.__unicode__ = klass.__str__ + klass.__str__ = lambda self: self.__unicode__().encode('utf-8') + return klass + + +# Complete the moves implementation. +# This code is at the end of this module to speed up module loading. +# Turn this module into a package. +__path__ = [] # required for PEP 302 and PEP 451 +__package__ = __name__ # see PEP 366 @ReservedAssignment +if globals().get("__spec__") is not None: + __spec__.submodule_search_locations = [] # PEP 451 @UndefinedVariable +# Remove other six meta path importers, since they cause problems. This can +# happen if six is removed from sys.modules and then reloaded. (Setuptools does +# this for some reason.) +if sys.meta_path: + for i, importer in enumerate(sys.meta_path): + # Here's some real nastiness: Another "instance" of the six module might + # be floating around. Therefore, we can't use isinstance() to check for + # the six meta path importer, since the other six instance will have + # inserted an importer with different class. + if (type(importer).__name__ == "_SixMetaPathImporter" and + importer.name == __name__): + del sys.meta_path[i] + break + del i, importer +# Finally, add the importer to the meta path import hook. +sys.meta_path.append(_importer) diff --git a/venv/lib/python3.8/site-packages/telegram/__init__.py b/venv/lib/python3.8/site-packages/telegram/__init__.py new file mode 100644 index 0000000..c71d3fd --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/__init__.py @@ -0,0 +1,294 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""A library that provides a Python interface to the Telegram Bot API""" + +from .base import TelegramObject +from .botcommand import BotCommand +from .user import User +from .files.chatphoto import ChatPhoto +from .chat import Chat +from .chatlocation import ChatLocation +from .chatinvitelink import ChatInviteLink +from .chatmember import ChatMember +from .chatmemberupdated import ChatMemberUpdated +from .chatpermissions import ChatPermissions +from .files.photosize import PhotoSize +from .files.audio import Audio +from .files.voice import Voice +from .files.document import Document +from .files.animation import Animation +from .files.sticker import Sticker, StickerSet, MaskPosition +from .files.video import Video +from .files.contact import Contact +from .files.location import Location +from .files.venue import Venue +from .files.videonote import VideoNote +from .chataction import ChatAction +from .dice import Dice +from .userprofilephotos import UserProfilePhotos +from .keyboardbuttonpolltype import KeyboardButtonPollType +from .keyboardbutton import KeyboardButton +from .replymarkup import ReplyMarkup +from .replykeyboardmarkup import ReplyKeyboardMarkup +from .replykeyboardremove import ReplyKeyboardRemove +from .forcereply import ForceReply +from .error import TelegramError +from .files.inputfile import InputFile +from .files.file import File +from .parsemode import ParseMode +from .messageentity import MessageEntity +from .messageid import MessageId +from .games.game import Game +from .poll import Poll, PollOption, PollAnswer +from .voicechat import ( + VoiceChatStarted, + VoiceChatEnded, + VoiceChatParticipantsInvited, + VoiceChatScheduled, +) +from .loginurl import LoginUrl +from .proximityalerttriggered import ProximityAlertTriggered +from .games.callbackgame import CallbackGame +from .payment.shippingaddress import ShippingAddress +from .payment.orderinfo import OrderInfo +from .payment.successfulpayment import SuccessfulPayment +from .payment.invoice import Invoice +from .passport.credentials import EncryptedCredentials +from .passport.passportfile import PassportFile +from .passport.data import IdDocumentData, PersonalDetails, ResidentialAddress +from .passport.encryptedpassportelement import EncryptedPassportElement +from .passport.passportdata import PassportData +from .inline.inlinekeyboardbutton import InlineKeyboardButton +from .inline.inlinekeyboardmarkup import InlineKeyboardMarkup +from .messageautodeletetimerchanged import MessageAutoDeleteTimerChanged +from .message import Message +from .callbackquery import CallbackQuery +from .choseninlineresult import ChosenInlineResult +from .inline.inputmessagecontent import InputMessageContent +from .inline.inlinequery import InlineQuery +from .inline.inlinequeryresult import InlineQueryResult +from .inline.inlinequeryresultarticle import InlineQueryResultArticle +from .inline.inlinequeryresultaudio import InlineQueryResultAudio +from .inline.inlinequeryresultcachedaudio import InlineQueryResultCachedAudio +from .inline.inlinequeryresultcacheddocument import InlineQueryResultCachedDocument +from .inline.inlinequeryresultcachedgif import InlineQueryResultCachedGif +from .inline.inlinequeryresultcachedmpeg4gif import InlineQueryResultCachedMpeg4Gif +from .inline.inlinequeryresultcachedphoto import InlineQueryResultCachedPhoto +from .inline.inlinequeryresultcachedsticker import InlineQueryResultCachedSticker +from .inline.inlinequeryresultcachedvideo import InlineQueryResultCachedVideo +from .inline.inlinequeryresultcachedvoice import InlineQueryResultCachedVoice +from .inline.inlinequeryresultcontact import InlineQueryResultContact +from .inline.inlinequeryresultdocument import InlineQueryResultDocument +from .inline.inlinequeryresultgif import InlineQueryResultGif +from .inline.inlinequeryresultlocation import InlineQueryResultLocation +from .inline.inlinequeryresultmpeg4gif import InlineQueryResultMpeg4Gif +from .inline.inlinequeryresultphoto import InlineQueryResultPhoto +from .inline.inlinequeryresultvenue import InlineQueryResultVenue +from .inline.inlinequeryresultvideo import InlineQueryResultVideo +from .inline.inlinequeryresultvoice import InlineQueryResultVoice +from .inline.inlinequeryresultgame import InlineQueryResultGame +from .inline.inputtextmessagecontent import InputTextMessageContent +from .inline.inputlocationmessagecontent import InputLocationMessageContent +from .inline.inputvenuemessagecontent import InputVenueMessageContent +from .payment.labeledprice import LabeledPrice +from .inline.inputinvoicemessagecontent import InputInvoiceMessageContent +from .inline.inputcontactmessagecontent import InputContactMessageContent +from .payment.shippingoption import ShippingOption +from .payment.precheckoutquery import PreCheckoutQuery +from .payment.shippingquery import ShippingQuery +from .webhookinfo import WebhookInfo +from .games.gamehighscore import GameHighScore +from .update import Update +from .files.inputmedia import ( + InputMedia, + InputMediaVideo, + InputMediaPhoto, + InputMediaAnimation, + InputMediaAudio, + InputMediaDocument, +) +from .constants import ( + MAX_MESSAGE_LENGTH, + MAX_CAPTION_LENGTH, + SUPPORTED_WEBHOOK_PORTS, + MAX_FILESIZE_DOWNLOAD, + MAX_FILESIZE_UPLOAD, + MAX_MESSAGES_PER_SECOND_PER_CHAT, + MAX_MESSAGES_PER_SECOND, + MAX_MESSAGES_PER_MINUTE_PER_GROUP, +) +from .passport.passportelementerrors import ( + PassportElementError, + PassportElementErrorDataField, + PassportElementErrorFile, + PassportElementErrorFiles, + PassportElementErrorFrontSide, + PassportElementErrorReverseSide, + PassportElementErrorSelfie, + PassportElementErrorTranslationFile, + PassportElementErrorTranslationFiles, + PassportElementErrorUnspecified, +) +from .passport.credentials import ( + Credentials, + DataCredentials, + SecureData, + SecureValue, + FileCredentials, + TelegramDecryptionError, +) +from .bot import Bot +from .version import __version__, bot_api_version # noqa: F401 + +__author__ = 'devs@python-telegram-bot.org' + +__all__ = ( # Keep this alphabetically ordered + 'Animation', + 'Audio', + 'Bot', + 'BotCommand', + 'CallbackGame', + 'CallbackQuery', + 'Chat', + 'ChatAction', + 'ChatInviteLink', + 'ChatLocation', + 'ChatMember', + 'ChatMemberUpdated', + 'ChatPermissions', + 'ChatPhoto', + 'ChosenInlineResult', + 'Contact', + 'Credentials', + 'DataCredentials', + 'Dice', + 'Document', + 'EncryptedCredentials', + 'EncryptedPassportElement', + 'File', + 'FileCredentials', + 'ForceReply', + 'Game', + 'GameHighScore', + 'IdDocumentData', + 'InlineKeyboardButton', + 'InlineKeyboardMarkup', + 'InlineQuery', + 'InlineQueryResult', + 'InlineQueryResultArticle', + 'InlineQueryResultAudio', + 'InlineQueryResultCachedAudio', + 'InlineQueryResultCachedDocument', + 'InlineQueryResultCachedGif', + 'InlineQueryResultCachedMpeg4Gif', + 'InlineQueryResultCachedPhoto', + 'InlineQueryResultCachedSticker', + 'InlineQueryResultCachedVideo', + 'InlineQueryResultCachedVoice', + 'InlineQueryResultContact', + 'InlineQueryResultDocument', + 'InlineQueryResultGame', + 'InlineQueryResultGif', + 'InlineQueryResultLocation', + 'InlineQueryResultMpeg4Gif', + 'InlineQueryResultPhoto', + 'InlineQueryResultVenue', + 'InlineQueryResultVideo', + 'InlineQueryResultVoice', + 'InputContactMessageContent', + 'InputFile', + 'InputInvoiceMessageContent', + 'InputLocationMessageContent', + 'InputMedia', + 'InputMediaAnimation', + 'InputMediaAudio', + 'InputMediaDocument', + 'InputMediaPhoto', + 'InputMediaVideo', + 'InputMessageContent', + 'InputTextMessageContent', + 'InputVenueMessageContent', + 'Invoice', + 'KeyboardButton', + 'KeyboardButtonPollType', + 'LabeledPrice', + 'Location', + 'LoginUrl', + 'MAX_CAPTION_LENGTH', + 'MAX_FILESIZE_DOWNLOAD', + 'MAX_FILESIZE_UPLOAD', + 'MAX_MESSAGES_PER_MINUTE_PER_GROUP', + 'MAX_MESSAGES_PER_SECOND', + 'MAX_MESSAGES_PER_SECOND_PER_CHAT', + 'MAX_MESSAGE_LENGTH', + 'MaskPosition', + 'Message', + 'MessageAutoDeleteTimerChanged', + 'MessageEntity', + 'MessageId', + 'OrderInfo', + 'ParseMode', + 'PassportData', + 'PassportElementError', + 'PassportElementErrorDataField', + 'PassportElementErrorFile', + 'PassportElementErrorFiles', + 'PassportElementErrorFrontSide', + 'PassportElementErrorReverseSide', + 'PassportElementErrorSelfie', + 'PassportElementErrorTranslationFile', + 'PassportElementErrorTranslationFiles', + 'PassportElementErrorUnspecified', + 'PassportFile', + 'PersonalDetails', + 'PhotoSize', + 'Poll', + 'PollAnswer', + 'PollOption', + 'PreCheckoutQuery', + 'ProximityAlertTriggered', + 'ReplyKeyboardMarkup', + 'ReplyKeyboardRemove', + 'ReplyMarkup', + 'ResidentialAddress', + 'SUPPORTED_WEBHOOK_PORTS', + 'SecureData', + 'SecureValue', + 'ShippingAddress', + 'ShippingOption', + 'ShippingQuery', + 'Sticker', + 'StickerSet', + 'SuccessfulPayment', + 'TelegramDecryptionError', + 'TelegramError', + 'TelegramObject', + 'Update', + 'User', + 'UserProfilePhotos', + 'Venue', + 'Video', + 'VideoNote', + 'Voice', + 'VoiceChatStarted', + 'VoiceChatEnded', + 'VoiceChatScheduled', + 'VoiceChatParticipantsInvited', + 'WebhookInfo', +) diff --git a/venv/lib/python3.8/site-packages/telegram/__main__.py b/venv/lib/python3.8/site-packages/telegram/__main__.py new file mode 100644 index 0000000..0e8db82 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/__main__.py @@ -0,0 +1,54 @@ +# !/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +# pylint: disable=C0114 +import subprocess +import sys +from typing import Optional + +import certifi + +from . import __version__ as telegram_ver +from .constants import BOT_API_VERSION + + +def _git_revision() -> Optional[str]: + try: + output = subprocess.check_output( # skipcq: BAN-B607 + ["git", "describe", "--long", "--tags"], stderr=subprocess.STDOUT + ) + except (subprocess.SubprocessError, OSError): + return None + return output.decode().strip() + + +def print_ver_info() -> None: # skipcq: PY-D0003 + git_revision = _git_revision() + print(f'python-telegram-bot {telegram_ver}' + (f' ({git_revision})' if git_revision else '')) + print(f'Bot API {BOT_API_VERSION}') + print(f'certifi {certifi.__version__}') # type: ignore[attr-defined] + sys_version = sys.version.replace('\n', ' ') + print(f'Python {sys_version}') + + +def main() -> None: # skipcq: PY-D0003 + print_ver_info() + + +if __name__ == '__main__': + main() diff --git a/venv/lib/python3.8/site-packages/telegram/base.py b/venv/lib/python3.8/site-packages/telegram/base.py new file mode 100644 index 0000000..0f906e9 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/base.py @@ -0,0 +1,152 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""Base class for Telegram Objects.""" +try: + import ujson as json +except ImportError: + import json # type: ignore[no-redef] + +import warnings +from typing import TYPE_CHECKING, List, Optional, Tuple, Type, TypeVar + +from telegram.utils.types import JSONDict +from telegram.utils.deprecate import set_new_attribute_deprecated + +if TYPE_CHECKING: + from telegram import Bot + +TO = TypeVar('TO', bound='TelegramObject', covariant=True) + + +class TelegramObject: + """Base class for most Telegram objects.""" + + _id_attrs: Tuple[object, ...] = () + + # Adding slots reduces memory usage & allows for faster attribute access. + # Only instance variables should be added to __slots__. + # We add __dict__ here for backward compatibility & also to avoid repetition for subclasses. + __slots__ = ('__dict__',) + + def __str__(self) -> str: + return str(self.to_dict()) + + def __getitem__(self, item: str) -> object: + return getattr(self, item, None) + + def __setattr__(self, key: str, value: object) -> None: + set_new_attribute_deprecated(self, key, value) + + @staticmethod + def _parse_data(data: Optional[JSONDict]) -> Optional[JSONDict]: + return None if data is None else data.copy() + + @classmethod + def de_json(cls: Type[TO], data: Optional[JSONDict], bot: 'Bot') -> Optional[TO]: + """Converts JSON data to a Telegram object. + + Args: + data (Dict[:obj:`str`, ...]): The JSON data. + bot (:class:`telegram.Bot`): The bot associated with this object. + + Returns: + The Telegram object. + + """ + data = cls._parse_data(data) + + if data is None: + return None + + if cls == TelegramObject: + return cls() + return cls(bot=bot, **data) # type: ignore[call-arg] + + @classmethod + def de_list(cls: Type[TO], data: Optional[List[JSONDict]], bot: 'Bot') -> List[Optional[TO]]: + """Converts JSON data to a list of Telegram objects. + + Args: + data (Dict[:obj:`str`, ...]): The JSON data. + bot (:class:`telegram.Bot`): The bot associated with these objects. + + Returns: + A list of Telegram objects. + + """ + if not data: + return [] + + return [cls.de_json(d, bot) for d in data] + + def to_json(self) -> str: + """Gives a JSON representation of object. + + Returns: + :obj:`str` + """ + return json.dumps(self.to_dict()) + + def to_dict(self) -> JSONDict: + """Gives representation of object as :obj:`dict`. + + Returns: + :obj:`dict` + """ + data = {} + + # We want to get all attributes for the class, using self.__slots__ only includes the + # attributes used by that class itself, and not its superclass(es). Hence we get its MRO + # and then get their attributes. The `[:-2]` slice excludes the `object` class & the + # TelegramObject class itself. + attrs = {attr for cls in self.__class__.__mro__[:-2] for attr in cls.__slots__} + for key in attrs: + if key == 'bot' or key.startswith('_'): + continue + + value = getattr(self, key, None) + if value is not None: + if hasattr(value, 'to_dict'): + data[key] = value.to_dict() + else: + data[key] = value + + if data.get('from_user'): + data['from'] = data.pop('from_user', None) + return data + + def __eq__(self, other: object) -> bool: + if isinstance(other, self.__class__): + if self._id_attrs == (): + warnings.warn( + f"Objects of type {self.__class__.__name__} can not be meaningfully tested for" + " equivalence." + ) + if other._id_attrs == (): + warnings.warn( + f"Objects of type {other.__class__.__name__} can not be meaningfully tested" + " for equivalence." + ) + return self._id_attrs == other._id_attrs + return super().__eq__(other) # pylint: disable=no-member + + def __hash__(self) -> int: + if self._id_attrs: + return hash((self.__class__, self._id_attrs)) # pylint: disable=no-member + return super().__hash__() diff --git a/venv/lib/python3.8/site-packages/telegram/bot.py b/venv/lib/python3.8/site-packages/telegram/bot.py new file mode 100644 index 0000000..db81a1d --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/bot.py @@ -0,0 +1,5318 @@ +#!/usr/bin/env python +# pylint: disable=E0611,E0213,E1102,E1101,R0913,R0904 +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram Bot.""" + +import functools +import logging +import warnings +from datetime import datetime + +from typing import ( + TYPE_CHECKING, + Callable, + List, + Optional, + Tuple, + TypeVar, + Union, + no_type_check, + Dict, + cast, + Sequence, +) + +try: + import ujson as json +except ImportError: + import json # type: ignore[no-redef] # noqa: F723 + +try: + from cryptography.hazmat.backends import default_backend + from cryptography.hazmat.primitives import serialization + + CRYPTO_INSTALLED = True +except ImportError: + default_backend = None # type: ignore[assignment] + serialization = None # type: ignore[assignment] + CRYPTO_INSTALLED = False + +from telegram import ( + Animation, + Audio, + BotCommand, + Chat, + ChatMember, + ChatPermissions, + ChatPhoto, + Contact, + Document, + File, + GameHighScore, + Location, + MaskPosition, + Message, + MessageId, + PassportElementError, + PhotoSize, + Poll, + ReplyMarkup, + ShippingOption, + Sticker, + StickerSet, + TelegramObject, + Update, + User, + UserProfilePhotos, + Venue, + Video, + VideoNote, + Voice, + WebhookInfo, + InlineKeyboardMarkup, + ChatInviteLink, +) +from telegram.constants import MAX_INLINE_QUERY_RESULTS +from telegram.error import InvalidToken, TelegramError +from telegram.utils.deprecate import TelegramDeprecationWarning +from telegram.utils.helpers import ( + DEFAULT_NONE, + DefaultValue, + to_timestamp, + is_local_file, + parse_file_input, + DEFAULT_20, +) +from telegram.utils.request import Request +from telegram.utils.types import FileInput, JSONDict, ODVInput, DVInput + +if TYPE_CHECKING: + from telegram.ext import Defaults + from telegram import ( + InputMediaAudio, + InputMediaDocument, + InputMediaPhoto, + InputMediaVideo, + InputMedia, + InlineQueryResult, + LabeledPrice, + MessageEntity, + ) + +RT = TypeVar('RT') + + +def log( # skipcq: PY-D0003 + func: Callable[..., RT], *args: object, **kwargs: object # pylint: disable=W0613 +) -> Callable[..., RT]: + logger = logging.getLogger(func.__module__) + + @functools.wraps(func) + def decorator(*args: object, **kwargs: object) -> RT: # pylint: disable=W0613 + logger.debug('Entering: %s', func.__name__) + result = func(*args, **kwargs) + logger.debug(result) + logger.debug('Exiting: %s', func.__name__) + return result + + return decorator + + +class Bot(TelegramObject): + """This object represents a Telegram Bot. + + .. versionadded:: 13.2 + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`bot` is equal. + + Note: + Most bot methods have the argument ``api_kwargs`` which allows to pass arbitrary keywords + to the Telegram API. This can be used to access new features of the API before they were + incorporated into PTB. However, this is not guaranteed to work, i.e. it will fail for + passing files. + + Args: + token (:obj:`str`): Bot's unique authentication. + base_url (:obj:`str`, optional): Telegram Bot API service URL. + base_file_url (:obj:`str`, optional): Telegram Bot API file URL. + request (:obj:`telegram.utils.request.Request`, optional): Pre initialized + :obj:`telegram.utils.request.Request`. + private_key (:obj:`bytes`, optional): Private key for decryption of telegram passport data. + private_key_password (:obj:`bytes`, optional): Password for above private key. + defaults (:class:`telegram.ext.Defaults`, optional): An object containing default values to + be used if not set explicitly in the bot methods. + + .. deprecated:: 13.6 + Passing :class:`telegram.ext.Defaults` to :class:`telegram.Bot` is deprecated. If + you want to use :class:`telegram.ext.Defaults`, please use + :class:`telegram.ext.ExtBot` instead. + + """ + + __slots__ = ( + 'token', + 'base_url', + 'base_file_url', + 'private_key', + 'defaults', + '_bot', + '_commands', + '_request', + 'logger', + ) + + def __init__( + self, + token: str, + base_url: str = None, + base_file_url: str = None, + request: 'Request' = None, + private_key: bytes = None, + private_key_password: bytes = None, + defaults: 'Defaults' = None, + ): + self.token = self._validate_token(token) + + # Gather default + self.defaults = defaults + + if self.defaults: + warnings.warn( + 'Passing Defaults to telegram.Bot is deprecated. Use telegram.ext.ExtBot instead.', + TelegramDeprecationWarning, + stacklevel=3, + ) + + if base_url is None: + base_url = 'https://api.telegram.org/bot' + + if base_file_url is None: + base_file_url = 'https://api.telegram.org/file/bot' + + self.base_url = str(base_url) + str(self.token) + self.base_file_url = str(base_file_url) + str(self.token) + self._bot: Optional[User] = None + self._commands: Optional[List[BotCommand]] = None + self._request = request or Request() + self.private_key = None + self.logger = logging.getLogger(__name__) + + if private_key: + if not CRYPTO_INSTALLED: + raise RuntimeError( + 'To use Telegram Passports, PTB must be installed via `pip install ' + 'python-telegram-bot[passport]`.' + ) + self.private_key = serialization.load_pem_private_key( + private_key, password=private_key_password, backend=default_backend() + ) + + # The ext_bot argument is a little hack to get warnings handled correctly. + # It's not very clean, but the warnings will be dropped at some point anyway. + def __setattr__(self, key: str, value: object, ext_bot: bool = False) -> None: + if issubclass(self.__class__, Bot) and self.__class__ is not Bot and not ext_bot: + object.__setattr__(self, key, value) + return + super().__setattr__(key, value) + + def _insert_defaults( + self, data: Dict[str, object], timeout: ODVInput[float] + ) -> Optional[float]: + """ + Inserts the defaults values for optional kwargs for which tg.ext.Defaults provides + convenience functionality, i.e. the kwargs with a tg.utils.helpers.DefaultValue default + + data is edited in-place. As timeout is not passed via the kwargs, it needs to be passed + separately and gets returned. + + This can only work, if all kwargs that may have defaults are passed in data! + """ + effective_timeout = DefaultValue.get_value(timeout) + + # If we have no Defaults, we just need to replace DefaultValue instances + # with the actual value + if not self.defaults: + data.update((key, DefaultValue.get_value(value)) for key, value in data.items()) + return effective_timeout + + # if we have Defaults, we replace all DefaultValue instances with the relevant + # Defaults value. If there is none, we fall back to the default value of the bot method + for key, val in data.items(): + if isinstance(val, DefaultValue): + data[key] = self.defaults.api_defaults.get(key, val.value) + + if isinstance(timeout, DefaultValue): + # If we get here, we use Defaults.timeout, unless that's not set, which is the + # case if isinstance(self.defaults.timeout, DefaultValue) + return ( + self.defaults.timeout + if not isinstance(self.defaults.timeout, DefaultValue) + else effective_timeout + ) + return effective_timeout + + def _post( + self, + endpoint: str, + data: JSONDict = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> Union[bool, JSONDict, None]: + if data is None: + data = {} + + if api_kwargs: + if data: + data.update(api_kwargs) + else: + data = api_kwargs + + # Insert is in-place, so no return value for data + if endpoint != 'getUpdates': + effective_timeout = self._insert_defaults(data, timeout) + else: + effective_timeout = cast(float, timeout) + # Drop any None values because Telegram doesn't handle them well + data = {key: value for key, value in data.items() if value is not None} + + return self.request.post( + f'{self.base_url}/{endpoint}', data=data, timeout=effective_timeout + ) + + def _message( + self, + endpoint: str, + data: JSONDict, + reply_to_message_id: int = None, + disable_notification: ODVInput[bool] = DEFAULT_NONE, + reply_markup: ReplyMarkup = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> Union[bool, Message]: + if reply_to_message_id is not None: + data['reply_to_message_id'] = reply_to_message_id + + # We don't check if (DEFAULT_)None here, so that _put is able to insert the defaults + # correctly, if necessary + data['disable_notification'] = disable_notification + data['allow_sending_without_reply'] = allow_sending_without_reply + + if reply_markup is not None: + if isinstance(reply_markup, ReplyMarkup): + # We need to_json() instead of to_dict() here, because reply_markups may be + # attached to media messages, which aren't json dumped by utils.request + data['reply_markup'] = reply_markup.to_json() + else: + data['reply_markup'] = reply_markup + + if data.get('media') and (data['media'].parse_mode == DEFAULT_NONE): + if self.defaults: + data['media'].parse_mode = DefaultValue.get_value(self.defaults.parse_mode) + else: + data['media'].parse_mode = None + + result = self._post(endpoint, data, timeout=timeout, api_kwargs=api_kwargs) + + if result is True: + return result + + return Message.de_json(result, self) # type: ignore[return-value, arg-type] + + @property + def request(self) -> Request: # skip-cq: PY-D0003 + return self._request + + @staticmethod + def _validate_token(token: str) -> str: + """A very basic validation on token.""" + if any(x.isspace() for x in token): + raise InvalidToken() + + left, sep, _right = token.partition(':') + if (not sep) or (not left.isdigit()) or (len(left) < 3): + raise InvalidToken() + + return token + + @property + def bot(self) -> User: + """:class:`telegram.User`: User instance for the bot as returned by :meth:`get_me`.""" + if self._bot is None: + self._bot = self.get_me() + return self._bot + + @property + def id(self) -> int: # pylint: disable=C0103 + """:obj:`int`: Unique identifier for this bot.""" + return self.bot.id + + @property + def first_name(self) -> str: + """:obj:`str`: Bot's first name.""" + return self.bot.first_name + + @property + def last_name(self) -> str: + """:obj:`str`: Optional. Bot's last name.""" + return self.bot.last_name # type: ignore + + @property + def username(self) -> str: + """:obj:`str`: Bot's username.""" + return self.bot.username # type: ignore + + @property + def link(self) -> str: + """:obj:`str`: Convenience property. Returns the t.me link of the bot.""" + return f"https://t.me/{self.username}" + + @property + def can_join_groups(self) -> bool: + """:obj:`bool`: Bot's :attr:`telegram.User.can_join_groups` attribute.""" + return self.bot.can_join_groups # type: ignore + + @property + def can_read_all_group_messages(self) -> bool: + """:obj:`bool`: Bot's :attr:`telegram.User.can_read_all_group_messages` attribute.""" + return self.bot.can_read_all_group_messages # type: ignore + + @property + def supports_inline_queries(self) -> bool: + """:obj:`bool`: Bot's :attr:`telegram.User.supports_inline_queries` attribute.""" + return self.bot.supports_inline_queries # type: ignore + + @property + def commands(self) -> List[BotCommand]: + """List[:class:`BotCommand`]: Bot's commands.""" + if self._commands is None: + self._commands = self.get_my_commands() + return self._commands + + @property + def name(self) -> str: + """:obj:`str`: Bot's @username.""" + return f'@{self.username}' + + @log + def get_me(self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None) -> User: + """A simple method for testing your bot's auth token. Requires no parameters. + + Args: + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :class:`telegram.User`: A :class:`telegram.User` instance representing that bot if the + credentials are valid, :obj:`None` otherwise. + + Raises: + :class:`telegram.error.TelegramError` + + """ + result = self._post('getMe', timeout=timeout, api_kwargs=api_kwargs) + + self._bot = User.de_json(result, self) # type: ignore[return-value, arg-type] + + return self._bot # type: ignore[return-value] + + @log + def send_message( + self, + chat_id: Union[int, str], + text: str, + parse_mode: ODVInput[str] = DEFAULT_NONE, + disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: ReplyMarkup = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + ) -> Message: + """Use this method to send text messages. + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target channel (in the format ``@channelusername``). + text (:obj:`str`): Text of the message to be sent. Max 4096 characters after entities + parsing. Also found as :attr:`telegram.constants.MAX_MESSAGE_LENGTH`. + parse_mode (:obj:`str`): Send Markdown or HTML, if you want Telegram apps to show bold, + italic, fixed-width text or inline URLs in your bot's message. See the constants in + :class:`telegram.ParseMode` for the available modes. + entities (List[:class:`telegram.MessageEntity`], optional): List of special entities + that appear in message text, which can be specified instead of :attr:`parse_mode`. + disable_web_page_preview (:obj:`bool`, optional): Disables link previews for links in + this message. + disable_notification (:obj:`bool`, optional): Sends the message silently. Users will + receive a notification with no sound. + reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the + original message. + allow_sending_without_reply (:obj:`bool`, optional): Pass :obj:`True`, if the message + should be sent even if the specified replied-to message is not found. + reply_markup (:class:`telegram.ReplyMarkup`, optional): Additional interface options. + A JSON-serialized object for an inline keyboard, custom reply keyboard, + instructions to remove reply keyboard or to force a reply from the user. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :class:`telegram.Message`: On success, the sent message is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = { + 'chat_id': chat_id, + 'text': text, + 'parse_mode': parse_mode, + 'disable_web_page_preview': disable_web_page_preview, + } + + if entities: + data['entities'] = [me.to_dict() for me in entities] + + return self._message( # type: ignore[return-value] + 'sendMessage', + data, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + allow_sending_without_reply=allow_sending_without_reply, + timeout=timeout, + api_kwargs=api_kwargs, + ) + + @log + def delete_message( + self, + chat_id: Union[str, int], + message_id: int, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> bool: + """ + Use this method to delete a message, including service messages, with the following + limitations: + + - A message can only be deleted if it was sent less than 48 hours ago. + - A dice message in a private chat can only be deleted if it was sent more than 24 + hours ago. + - Bots can delete outgoing messages in private chats, groups, and supergroups. + - Bots can delete incoming messages in private chats. + - Bots granted :attr:`telegram.ChatMember.can_post_messages` permissions can delete + outgoing messages in channels. + - If the bot is an administrator of a group, it can delete any message there. + - If the bot has :attr:`telegram.ChatMember.can_delete_messages` permission in a + supergroup or a channel, it can delete any message there. + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target channel (in the format ``@channelusername``). + message_id (:obj:`int`): Identifier of the message to delete. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = {'chat_id': chat_id, 'message_id': message_id} + + result = self._post('deleteMessage', data, timeout=timeout, api_kwargs=api_kwargs) + + return result # type: ignore[return-value] + + @log + def forward_message( + self, + chat_id: Union[int, str], + from_chat_id: Union[str, int], + message_id: int, + disable_notification: DVInput[bool] = DEFAULT_NONE, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> Message: + """Use this method to forward messages of any kind. Service messages can't be forwarded. + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target channel (in the format ``@channelusername``). + from_chat_id (:obj:`int` | :obj:`str`): Unique identifier for the chat where the + original message was sent (or channel username in the format ``@channelusername``). + message_id (:obj:`int`): Message identifier in the chat specified in from_chat_id. + disable_notification (:obj:`bool`, optional): Sends the message silently. Users will + receive a notification with no sound. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :class:`telegram.Message`: On success, the sent Message is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = {} + + if chat_id: + data['chat_id'] = chat_id + if from_chat_id: + data['from_chat_id'] = from_chat_id + if message_id: + data['message_id'] = message_id + + return self._message( # type: ignore[return-value] + 'forwardMessage', + data, + disable_notification=disable_notification, + timeout=timeout, + api_kwargs=api_kwargs, + ) + + @log + def send_photo( + self, + chat_id: Union[int, str], + photo: Union[FileInput, 'PhotoSize'], + caption: str = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: ReplyMarkup = None, + timeout: DVInput[float] = DEFAULT_20, + parse_mode: ODVInput[str] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + filename: str = None, + ) -> Message: + """Use this method to send photos. + + Note: + The photo argument can be either a file_id, an URL or a file from disk + ``open(filename, 'rb')`` + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target channel (in the format ``@channelusername``). + photo (:obj:`str` | `filelike object` | :obj:`bytes` | :class:`pathlib.Path` | \ + :class:`telegram.PhotoSize`): Photo to send. + Pass a file_id as String to send a photo that exists on the Telegram servers + (recommended), pass an HTTP URL as a String for Telegram to get a photo from the + Internet, or upload a new photo using multipart/form-data. Lastly you can pass + an existing :class:`telegram.PhotoSize` object to send. + + .. versionchanged:: 13.2 + Accept :obj:`bytes` as input. + filename (:obj:`str`, optional): Custom file name for the photo, when uploading a + new file. Convenience parameter, useful e.g. when sending files generated by the + :obj:`tempfile` module. + + .. versionadded:: 13.1 + caption (:obj:`str`, optional): Photo caption (may also be used when resending photos + by file_id), 0-1024 characters after entities parsing. + parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to + show bold, italic, fixed-width text or inline URLs in the media caption. See the + constants in :class:`telegram.ParseMode` for the available modes. + caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special + entities that appear in message text, which can be specified instead of + :attr:`parse_mode`. + disable_notification (:obj:`bool`, optional): Sends the message silently. Users will + receive a notification with no sound. + reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the + original message. + allow_sending_without_reply (:obj:`bool`, optional): Pass :obj:`True`, if the message + should be sent even if the specified replied-to message is not found. + reply_markup (:class:`telegram.ReplyMarkup`, optional): Additional interface options. A + JSON-serialized object for an inline keyboard, custom reply keyboard, instructions + to remove reply keyboard or to force a reply from the user. + timeout (:obj:`int` | :obj:`float`, optional): Send file timeout (default: 20 seconds). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :class:`telegram.Message`: On success, the sent Message is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = { + 'chat_id': chat_id, + 'photo': parse_file_input(photo, PhotoSize, filename=filename), + 'parse_mode': parse_mode, + } + + if caption: + data['caption'] = caption + + if caption_entities: + data['caption_entities'] = [me.to_dict() for me in caption_entities] + + return self._message( # type: ignore[return-value] + 'sendPhoto', + data, + timeout=timeout, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + allow_sending_without_reply=allow_sending_without_reply, + api_kwargs=api_kwargs, + ) + + @log + def send_audio( + self, + chat_id: Union[int, str], + audio: Union[FileInput, 'Audio'], + duration: int = None, + performer: str = None, + title: str = None, + caption: str = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: ReplyMarkup = None, + timeout: DVInput[float] = DEFAULT_20, + parse_mode: ODVInput[str] = DEFAULT_NONE, + thumb: FileInput = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + filename: str = None, + ) -> Message: + """ + Use this method to send audio files, if you want Telegram clients to display them in the + music player. Your audio must be in the .mp3 or .m4a format. + + Bots can currently send audio files of up to 50 MB in size, this limit may be changed in + the future. + + For sending voice messages, use the :meth:`send_voice` method instead. + + Note: + The audio argument can be either a file_id, an URL or a file from disk + ``open(filename, 'rb')`` + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target channel (in the format ``@channelusername``). + audio (:obj:`str` | `filelike object` | :obj:`bytes` | :class:`pathlib.Path` | \ + :class:`telegram.Audio`): Audio file to send. + Pass a file_id as String to send an audio file that exists on the Telegram servers + (recommended), pass an HTTP URL as a String for Telegram to get an audio file from + the Internet, or upload a new one using multipart/form-data. Lastly you can pass + an existing :class:`telegram.Audio` object to send. + + .. versionchanged:: 13.2 + Accept :obj:`bytes` as input. + filename (:obj:`str`, optional): Custom file name for the audio, when uploading a + new file. Convenience parameter, useful e.g. when sending files generated by the + :obj:`tempfile` module. + + .. versionadded:: 13.1 + caption (:obj:`str`, optional): Audio caption, 0-1024 characters after entities + parsing. + parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to + show bold, italic, fixed-width text or inline URLs in the media caption. See the + constants in :class:`telegram.ParseMode` for the available modes. + caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special + entities that appear in message text, which can be specified instead of + :attr:`parse_mode`. + duration (:obj:`int`, optional): Duration of sent audio in seconds. + performer (:obj:`str`, optional): Performer. + title (:obj:`str`, optional): Track name. + disable_notification (:obj:`bool`, optional): Sends the message silently. Users will + receive a notification with no sound. + reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the + original message. + allow_sending_without_reply (:obj:`bool`, optional): Pass :obj:`True`, if the message + should be sent even if the specified replied-to message is not found. + reply_markup (:class:`telegram.ReplyMarkup`, optional): Additional interface options. A + JSON-serialized object for an inline keyboard, custom reply keyboard, instructions + to remove reply keyboard or to force a reply from the user. + thumb (`filelike object` | :obj:`bytes` | :class:`pathlib.Path`, optional): Thumbnail + of the file sent; can be ignored if + thumbnail generation for the file is supported server-side. The thumbnail should be + in JPEG format and less than 200 kB in size. A thumbnail's width and height should + not exceed 320. Ignored if the file is not uploaded using multipart/form-data. + Thumbnails can't be reused and can be only uploaded as a new file. + + .. versionchanged:: 13.2 + Accept :obj:`bytes` as input. + timeout (:obj:`int` | :obj:`float`, optional): Send file timeout (default: 20 seconds). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :class:`telegram.Message`: On success, the sent Message is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = { + 'chat_id': chat_id, + 'audio': parse_file_input(audio, Audio, filename=filename), + 'parse_mode': parse_mode, + } + + if duration: + data['duration'] = duration + if performer: + data['performer'] = performer + if title: + data['title'] = title + if caption: + data['caption'] = caption + + if caption_entities: + data['caption_entities'] = [me.to_dict() for me in caption_entities] + if thumb: + data['thumb'] = parse_file_input(thumb, attach=True) + + return self._message( # type: ignore[return-value] + 'sendAudio', + data, + timeout=timeout, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + allow_sending_without_reply=allow_sending_without_reply, + api_kwargs=api_kwargs, + ) + + @log + def send_document( + self, + chat_id: Union[int, str], + document: Union[FileInput, 'Document'], + filename: str = None, + caption: str = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: ReplyMarkup = None, + timeout: DVInput[float] = DEFAULT_20, + parse_mode: ODVInput[str] = DEFAULT_NONE, + thumb: FileInput = None, + api_kwargs: JSONDict = None, + disable_content_type_detection: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + ) -> Message: + """ + Use this method to send general files. + + Bots can currently send files of any type of up to 50 MB in size, this limit may be + changed in the future. + + Note: + The document argument can be either a file_id, an URL or a file from disk + ``open(filename, 'rb')`` + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target channel (in the format ``@channelusername``). + document (:obj:`str` | `filelike object` | :obj:`bytes` | :class:`pathlib.Path` | \ + :class:`telegram.Document`): File to send. + Pass a file_id as String to send a file that exists on the Telegram servers + (recommended), pass an HTTP URL as a String for Telegram to get a file from the + Internet, or upload a new one using multipart/form-data. Lastly you can pass + an existing :class:`telegram.Document` object to send. + + .. versionchanged:: 13.2 + Accept :obj:`bytes` as input. + filename (:obj:`str`, optional): Custom file name for the document, when uploading a + new file. Convenience parameter, useful e.g. when sending files generated by the + :obj:`tempfile` module. + caption (:obj:`str`, optional): Document caption (may also be used when resending + documents by file_id), 0-1024 characters after entities parsing. + disable_content_type_detection (:obj:`bool`, optional): Disables automatic server-side + content type detection for files uploaded using multipart/form-data. + parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to + show bold, italic, fixed-width text or inline URLs in the media caption. See the + constants in :class:`telegram.ParseMode` for the available modes. + caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special + entities that appear in message text, which can be specified instead of + :attr:`parse_mode`. + disable_notification (:obj:`bool`, optional): Sends the message silently. Users will + receive a notification with no sound. + reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the + original message. + allow_sending_without_reply (:obj:`bool`, optional): Pass :obj:`True`, if the message + should be sent even if the specified replied-to message is not found. + reply_markup (:class:`telegram.ReplyMarkup`, optional): Additional interface options. A + JSON-serialized object for an inline keyboard, custom reply keyboard, instructions + to remove reply keyboard or to force a reply from the user. + thumb (`filelike object` | :obj:`bytes` | :class:`pathlib.Path`, optional): Thumbnail + of the file sent; can be ignored if + thumbnail generation for the file is supported server-side. The thumbnail should be + in JPEG format and less than 200 kB in size. A thumbnail's width and height should + not exceed 320. Ignored if the file is not uploaded using multipart/form-data. + Thumbnails can't be reused and can be only uploaded as a new file. + + .. versionchanged:: 13.2 + Accept :obj:`bytes` as input. + timeout (:obj:`int` | :obj:`float`, optional): Send file timeout (default: 20 seconds). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :class:`telegram.Message`: On success, the sent Message is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = { + 'chat_id': chat_id, + 'document': parse_file_input(document, Document, filename=filename), + 'parse_mode': parse_mode, + } + + if caption: + data['caption'] = caption + + if caption_entities: + data['caption_entities'] = [me.to_dict() for me in caption_entities] + if disable_content_type_detection is not None: + data['disable_content_type_detection'] = disable_content_type_detection + if thumb: + data['thumb'] = parse_file_input(thumb, attach=True) + + return self._message( # type: ignore[return-value] + 'sendDocument', + data, + timeout=timeout, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + allow_sending_without_reply=allow_sending_without_reply, + api_kwargs=api_kwargs, + ) + + @log + def send_sticker( + self, + chat_id: Union[int, str], + sticker: Union[FileInput, 'Sticker'], + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: ReplyMarkup = None, + timeout: DVInput[float] = DEFAULT_20, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + ) -> Message: + """ + Use this method to send static .WEBP or animated .TGS stickers. + + Note: + The sticker argument can be either a file_id, an URL or a file from disk + ``open(filename, 'rb')`` + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target channel (in the format ``@channelusername``). + sticker (:obj:`str` | `filelike object` | :obj:`bytes` | :class:`pathlib.Path` | \ + :class:`telegram.Sticker`): Sticker to send. + Pass a file_id as String to send a file that exists on the Telegram servers + (recommended), pass an HTTP URL as a String for Telegram to get a .webp file from + the Internet, or upload a new one using multipart/form-data. Lastly you can pass + an existing :class:`telegram.Sticker` object to send. + + .. versionchanged:: 13.2 + Accept :obj:`bytes` as input. + disable_notification (:obj:`bool`, optional): Sends the message silently. Users will + receive a notification with no sound. + reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the + original message. + allow_sending_without_reply (:obj:`bool`, optional): Pass :obj:`True`, if the message + should be sent even if the specified replied-to message is not found. + reply_markup (:class:`telegram.ReplyMarkup`, optional): Additional interface options. A + JSON-serialized object for an inline keyboard, custom reply keyboard, instructions + to remove reply keyboard or to force a reply from the user. + timeout (:obj:`int` | :obj:`float`, optional): Send file timeout (default: 20 seconds). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :class:`telegram.Message`: On success, the sent Message is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = {'chat_id': chat_id, 'sticker': parse_file_input(sticker, Sticker)} + + return self._message( # type: ignore[return-value] + 'sendSticker', + data, + timeout=timeout, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + allow_sending_without_reply=allow_sending_without_reply, + api_kwargs=api_kwargs, + ) + + @log + def send_video( + self, + chat_id: Union[int, str], + video: Union[FileInput, 'Video'], + duration: int = None, + caption: str = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: ReplyMarkup = None, + timeout: DVInput[float] = DEFAULT_20, + width: int = None, + height: int = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + supports_streaming: bool = None, + thumb: FileInput = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + filename: str = None, + ) -> Message: + """ + Use this method to send video files, Telegram clients support mp4 videos + (other formats may be sent as Document). + + Bots can currently send video files of up to 50 MB in size, this limit may be changed in + the future. + + Note: + * The video argument can be either a file_id, an URL or a file from disk + ``open(filename, 'rb')`` + * ``thumb`` will be ignored for small video files, for which Telegram can easily + generate thumb nails. However, this behaviour is undocumented and might be changed + by Telegram. + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target channel (in the format ``@channelusername``). + video (:obj:`str` | `filelike object` | :obj:`bytes` | :class:`pathlib.Path` | \ + :class:`telegram.Video`): Video file to send. + Pass a file_id as String to send an video file that exists on the Telegram servers + (recommended), pass an HTTP URL as a String for Telegram to get an video file from + the Internet, or upload a new one using multipart/form-data. Lastly you can pass + an existing :class:`telegram.Video` object to send. + + .. versionchanged:: 13.2 + Accept :obj:`bytes` as input. + filename (:obj:`str`, optional): Custom file name for the video, when uploading a + new file. Convenience parameter, useful e.g. when sending files generated by the + :obj:`tempfile` module. + + .. versionadded:: 13.1 + duration (:obj:`int`, optional): Duration of sent video in seconds. + width (:obj:`int`, optional): Video width. + height (:obj:`int`, optional): Video height. + caption (:obj:`str`, optional): Video caption (may also be used when resending videos + by file_id), 0-1024 characters after entities parsing. + parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to + show bold, italic, fixed-width text or inline URLs in the media caption. See the + constants in :class:`telegram.ParseMode` for the available modes. + caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special + entities that appear in message text, which can be specified instead of + :attr:`parse_mode`. + supports_streaming (:obj:`bool`, optional): Pass :obj:`True`, if the uploaded video is + suitable for streaming. + disable_notification (:obj:`bool`, optional): Sends the message silently. Users will + receive a notification with no sound. + reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the + original message. + allow_sending_without_reply (:obj:`bool`, optional): Pass :obj:`True`, if the message + should be sent even if the specified replied-to message is not found. + reply_markup (:class:`telegram.ReplyMarkup`, optional): Additional interface options. A + JSON-serialized object for an inline keyboard, custom reply keyboard, instructions + to remove reply keyboard or to force a reply from the user. + thumb (`filelike object` | :obj:`bytes` | :class:`pathlib.Path`, optional): Thumbnail + of the file sent; can be ignored if + thumbnail generation for the file is supported server-side. The thumbnail should be + in JPEG format and less than 200 kB in size. A thumbnail's width and height should + not exceed 320. Ignored if the file is not uploaded using multipart/form-data. + Thumbnails can't be reused and can be only uploaded as a new file. + + .. versionchanged:: 13.2 + Accept :obj:`bytes` as input. + timeout (:obj:`int` | :obj:`float`, optional): Send file timeout (default: 20 seconds). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :class:`telegram.Message`: On success, the sent Message is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = { + 'chat_id': chat_id, + 'video': parse_file_input(video, Video, filename=filename), + 'parse_mode': parse_mode, + } + + if duration: + data['duration'] = duration + if caption: + data['caption'] = caption + if caption_entities: + data['caption_entities'] = [me.to_dict() for me in caption_entities] + if supports_streaming: + data['supports_streaming'] = supports_streaming + if width: + data['width'] = width + if height: + data['height'] = height + if thumb: + data['thumb'] = parse_file_input(thumb, attach=True) + + return self._message( # type: ignore[return-value] + 'sendVideo', + data, + timeout=timeout, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + allow_sending_without_reply=allow_sending_without_reply, + api_kwargs=api_kwargs, + ) + + @log + def send_video_note( + self, + chat_id: Union[int, str], + video_note: Union[FileInput, 'VideoNote'], + duration: int = None, + length: int = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: ReplyMarkup = None, + timeout: DVInput[float] = DEFAULT_20, + thumb: FileInput = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + filename: str = None, + ) -> Message: + """ + As of v.4.0, Telegram clients support rounded square mp4 videos of up to 1 minute long. + Use this method to send video messages. + + Note: + * The video_note argument can be either a file_id or a file from disk + ``open(filename, 'rb')`` + * ``thumb`` will be ignored for small video files, for which Telegram can easily + generate thumb nails. However, this behaviour is undocumented and might be changed + by Telegram. + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target channel (in the format ``@channelusername``). + video_note (:obj:`str` | `filelike object` | :obj:`bytes` | :class:`pathlib.Path` | \ + :class:`telegram.VideoNote`): Video note + to send. Pass a file_id as String to send a video note that exists on the Telegram + servers (recommended) or upload a new video using multipart/form-data. Or you can + pass an existing :class:`telegram.VideoNote` object to send. Sending video notes by + a URL is currently unsupported. + + .. versionchanged:: 13.2 + Accept :obj:`bytes` as input. + filename (:obj:`str`, optional): Custom file name for the video note, when uploading a + new file. Convenience parameter, useful e.g. when sending files generated by the + :obj:`tempfile` module. + + .. versionadded:: 13.1 + duration (:obj:`int`, optional): Duration of sent video in seconds. + length (:obj:`int`, optional): Video width and height, i.e. diameter of the video + message. + disable_notification (:obj:`bool`, optional): Sends the message silently. Users will + receive a notification with no sound. + reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the + original message. + allow_sending_without_reply (:obj:`bool`, optional): Pass :obj:`True`, if the message + should be sent even if the specified replied-to message is not found. + reply_markup (:class:`telegram.ReplyMarkup`, optional): Additional interface options. A + JSON-serialized object for an inline keyboard, custom reply keyboard, + instructions to remove reply keyboard or to force a reply from the user. + thumb (`filelike object` | :obj:`bytes` | :class:`pathlib.Path`, optional): Thumbnail + of the file sent; can be ignored if + thumbnail generation for the file is supported server-side. The thumbnail should be + in JPEG format and less than 200 kB in size. A thumbnail's width and height should + not exceed 320. Ignored if the file is not uploaded using multipart/form-data. + Thumbnails can't be reused and can be only uploaded as a new file. + + .. versionchanged:: 13.2 + Accept :obj:`bytes` as input. + timeout (:obj:`int` | :obj:`float`, optional): Send file timeout (default: 20 seconds). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :class:`telegram.Message`: On success, the sent Message is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = { + 'chat_id': chat_id, + 'video_note': parse_file_input(video_note, VideoNote, filename=filename), + } + + if duration is not None: + data['duration'] = duration + if length is not None: + data['length'] = length + if thumb: + data['thumb'] = parse_file_input(thumb, attach=True) + + return self._message( # type: ignore[return-value] + 'sendVideoNote', + data, + timeout=timeout, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + allow_sending_without_reply=allow_sending_without_reply, + api_kwargs=api_kwargs, + ) + + @log + def send_animation( + self, + chat_id: Union[int, str], + animation: Union[FileInput, 'Animation'], + duration: int = None, + width: int = None, + height: int = None, + thumb: FileInput = None, + caption: str = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: ReplyMarkup = None, + timeout: DVInput[float] = DEFAULT_20, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + filename: str = None, + ) -> Message: + """ + Use this method to send animation files (GIF or H.264/MPEG-4 AVC video without sound). + Bots can currently send animation files of up to 50 MB in size, this limit may be changed + in the future. + + Note: + ``thumb`` will be ignored for small files, for which Telegram can easily + generate thumb nails. However, this behaviour is undocumented and might be changed + by Telegram. + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target channel (in the format ``@channelusername``). + animation (:obj:`str` | `filelike object` | :obj:`bytes` | :class:`pathlib.Path` | \ + :class:`telegram.Animation`): Animation to + send. Pass a file_id as String to send an animation that exists on the Telegram + servers (recommended), pass an HTTP URL as a String for Telegram to get an + animation from the Internet, or upload a new animation using multipart/form-data. + Lastly you can pass an existing :class:`telegram.Animation` object to send. + + .. versionchanged:: 13.2 + Accept :obj:`bytes` as input. + filename (:obj:`str`, optional): Custom file name for the animation, when uploading a + new file. Convenience parameter, useful e.g. when sending files generated by the + :obj:`tempfile` module. + + .. versionadded:: 13.1 + duration (:obj:`int`, optional): Duration of sent animation in seconds. + width (:obj:`int`, optional): Animation width. + height (:obj:`int`, optional): Animation height. + thumb (`filelike object` | :obj:`bytes` | :class:`pathlib.Path`, optional): Thumbnail + of the file sent; can be ignored if + thumbnail generation for the file is supported server-side. The thumbnail should be + in JPEG format and less than 200 kB in size. A thumbnail's width and height should + not exceed 320. Ignored if the file is not uploaded using multipart/form-data. + Thumbnails can't be reused and can be only uploaded as a new file. + + .. versionchanged:: 13.2 + Accept :obj:`bytes` as input. + caption (:obj:`str`, optional): Animation caption (may also be used when resending + animations by file_id), 0-1024 characters after entities parsing. + parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to + show bold, italic, fixed-width text or inline URLs in the media caption. See the + constants in :class:`telegram.ParseMode` for the available modes. + caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special + entities that appear in message text, which can be specified instead of + :attr:`parse_mode`. + disable_notification (:obj:`bool`, optional): Sends the message silently. Users will + receive a notification with no sound. + reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the + original message. + allow_sending_without_reply (:obj:`bool`, optional): Pass :obj:`True`, if the message + should be sent even if the specified replied-to message is not found. + reply_markup (:class:`telegram.ReplyMarkup`, optional): Additional interface options. A + JSON-serialized object for an inline keyboard, custom reply keyboard, instructions + to remove reply keyboard or to force a reply from the user. + timeout (:obj:`int` | :obj:`float`, optional): Send file timeout (default: 20 seconds). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :class:`telegram.Message`: On success, the sent Message is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = { + 'chat_id': chat_id, + 'animation': parse_file_input(animation, Animation, filename=filename), + 'parse_mode': parse_mode, + } + + if duration: + data['duration'] = duration + if width: + data['width'] = width + if height: + data['height'] = height + if thumb: + data['thumb'] = parse_file_input(thumb, attach=True) + if caption: + data['caption'] = caption + if caption_entities: + data['caption_entities'] = [me.to_dict() for me in caption_entities] + + return self._message( # type: ignore[return-value] + 'sendAnimation', + data, + timeout=timeout, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + allow_sending_without_reply=allow_sending_without_reply, + api_kwargs=api_kwargs, + ) + + @log + def send_voice( + self, + chat_id: Union[int, str], + voice: Union[FileInput, 'Voice'], + duration: int = None, + caption: str = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: ReplyMarkup = None, + timeout: DVInput[float] = DEFAULT_20, + parse_mode: ODVInput[str] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + filename: str = None, + ) -> Message: + """ + Use this method to send audio files, if you want Telegram clients to display the file + as a playable voice message. For this to work, your audio must be in an .ogg file + encoded with OPUS (other formats may be sent as Audio or Document). Bots can currently + send voice messages of up to 50 MB in size, this limit may be changed in the future. + + Note: + The voice argument can be either a file_id, an URL or a file from disk + ``open(filename, 'rb')`` + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target channel (in the format ``@channelusername``). + voice (:obj:`str` | `filelike object` | :obj:`bytes` | :class:`pathlib.Path` | \ + :class:`telegram.Voice`): Voice file to send. + Pass a file_id as String to send an voice file that exists on the Telegram servers + (recommended), pass an HTTP URL as a String for Telegram to get an voice file from + the Internet, or upload a new one using multipart/form-data. Lastly you can pass + an existing :class:`telegram.Voice` object to send. + + .. versionchanged:: 13.2 + Accept :obj:`bytes` as input. + filename (:obj:`str`, optional): Custom file name for the voice, when uploading a + new file. Convenience parameter, useful e.g. when sending files generated by the + :obj:`tempfile` module. + + .. versionadded:: 13.1 + caption (:obj:`str`, optional): Voice message caption, 0-1024 characters after entities + parsing. + parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to + show bold, italic, fixed-width text or inline URLs in the media caption. See the + constants in :class:`telegram.ParseMode` for the available modes. + caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special + entities that appear in message text, which can be specified instead of + :attr:`parse_mode`. + duration (:obj:`int`, optional): Duration of the voice message in seconds. + disable_notification (:obj:`bool`, optional): Sends the message silently. Users will + receive a notification with no sound. + reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the + original message. + allow_sending_without_reply (:obj:`bool`, optional): Pass :obj:`True`, if the message + should be sent even if the specified replied-to message is not found. + reply_markup (:class:`telegram.ReplyMarkup`, optional): Additional interface options. A + JSON-serialized object for an inline keyboard, custom reply keyboard, + instructions to remove reply keyboard or to force a reply from the user. + timeout (:obj:`int` | :obj:`float`, optional): Send file timeout (default: 20 seconds). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :class:`telegram.Message`: On success, the sent Message is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = { + 'chat_id': chat_id, + 'voice': parse_file_input(voice, Voice, filename=filename), + 'parse_mode': parse_mode, + } + + if duration: + data['duration'] = duration + if caption: + data['caption'] = caption + + if caption_entities: + data['caption_entities'] = [me.to_dict() for me in caption_entities] + + return self._message( # type: ignore[return-value] + 'sendVoice', + data, + timeout=timeout, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + allow_sending_without_reply=allow_sending_without_reply, + api_kwargs=api_kwargs, + ) + + @log + def send_media_group( + self, + chat_id: Union[int, str], + media: List[ + Union['InputMediaAudio', 'InputMediaDocument', 'InputMediaPhoto', 'InputMediaVideo'] + ], + disable_notification: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + timeout: DVInput[float] = DEFAULT_20, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + ) -> List[Message]: + """Use this method to send a group of photos or videos as an album. + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target channel (in the format ``@channelusername``). + media (List[:class:`telegram.InputMediaAudio`, :class:`telegram.InputMediaDocument`, \ + :class:`telegram.InputMediaPhoto`, :class:`telegram.InputMediaVideo`]): An array + describing messages to be sent, must include 2–10 items. + disable_notification (:obj:`bool`, optional): Sends the message silently. Users will + receive a notification with no sound. + reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the + original message. + allow_sending_without_reply (:obj:`bool`, optional): Pass :obj:`True`, if the message + should be sent even if the specified replied-to message is not found. + timeout (:obj:`int` | :obj:`float`, optional): Send file timeout (default: 20 seconds). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + List[:class:`telegram.Message`]: An array of the sent Messages. + + Raises: + :class:`telegram.error.TelegramError` + """ + data: JSONDict = { + 'chat_id': chat_id, + 'media': media, + 'disable_notification': disable_notification, + 'allow_sending_without_reply': allow_sending_without_reply, + } + + for med in data['media']: + if med.parse_mode == DEFAULT_NONE: + if self.defaults: + med.parse_mode = DefaultValue.get_value(self.defaults.parse_mode) + else: + med.parse_mode = None + + if reply_to_message_id: + data['reply_to_message_id'] = reply_to_message_id + + result = self._post('sendMediaGroup', data, timeout=timeout, api_kwargs=api_kwargs) + + return Message.de_list(result, self) # type: ignore + + @log + def send_location( + self, + chat_id: Union[int, str], + latitude: float = None, + longitude: float = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: ReplyMarkup = None, + timeout: ODVInput[float] = DEFAULT_NONE, + location: Location = None, + live_period: int = None, + api_kwargs: JSONDict = None, + horizontal_accuracy: float = None, + heading: int = None, + proximity_alert_radius: int = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + ) -> Message: + """Use this method to send point on the map. + + Note: + You can either supply a :obj:`latitude` and :obj:`longitude` or a :obj:`location`. + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target channel (in the format ``@channelusername``). + latitude (:obj:`float`, optional): Latitude of location. + longitude (:obj:`float`, optional): Longitude of location. + location (:class:`telegram.Location`, optional): The location to send. + horizontal_accuracy (:obj:`int`, optional): The radius of uncertainty for the location, + measured in meters; 0-1500. + live_period (:obj:`int`, optional): Period in seconds for which the location will be + updated, should be between 60 and 86400. + heading (:obj:`int`, optional): For live locations, a direction in which the user is + moving, in degrees. Must be between 1 and 360 if specified. + proximity_alert_radius (:obj:`int`, optional): For live locations, a maximum distance + for proximity alerts about approaching another chat member, in meters. Must be + between 1 and 100000 if specified. + disable_notification (:obj:`bool`, optional): Sends the message silently. Users will + receive a notification with no sound. + reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the + original message. + allow_sending_without_reply (:obj:`bool`, optional): Pass :obj:`True`, if the message + should be sent even if the specified replied-to message is not found. + reply_markup (:class:`telegram.ReplyMarkup`, optional): Additional interface options. A + JSON-serialized object for an inline keyboard, custom reply keyboard, + instructions to remove reply keyboard or to force a reply from the user. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :class:`telegram.Message`: On success, the sent Message is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + if not ((latitude is not None and longitude is not None) or location): + raise ValueError( + "Either location or latitude and longitude must be passed as argument." + ) + + if not (latitude is not None or longitude is not None) ^ bool(location): + raise ValueError( + "Either location or latitude and longitude must be passed as argument. Not both." + ) + + if isinstance(location, Location): + latitude = location.latitude + longitude = location.longitude + + data: JSONDict = {'chat_id': chat_id, 'latitude': latitude, 'longitude': longitude} + + if live_period: + data['live_period'] = live_period + if horizontal_accuracy: + data['horizontal_accuracy'] = horizontal_accuracy + if heading: + data['heading'] = heading + if proximity_alert_radius: + data['proximity_alert_radius'] = proximity_alert_radius + + return self._message( # type: ignore[return-value] + 'sendLocation', + data, + timeout=timeout, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + allow_sending_without_reply=allow_sending_without_reply, + api_kwargs=api_kwargs, + ) + + @log + def edit_message_live_location( + self, + chat_id: Union[str, int] = None, + message_id: int = None, + inline_message_id: int = None, + latitude: float = None, + longitude: float = None, + location: Location = None, + reply_markup: InlineKeyboardMarkup = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + horizontal_accuracy: float = None, + heading: int = None, + proximity_alert_radius: int = None, + ) -> Union[Message, bool]: + """Use this method to edit live location messages sent by the bot or via the bot + (for inline bots). A location can be edited until its :attr:`telegram.Location.live_period` + expires or editing is explicitly disabled by a call to :meth:`stop_message_live_location`. + + Note: + You can either supply a :obj:`latitude` and :obj:`longitude` or a :obj:`location`. + + Args: + chat_id (:obj:`int` | :obj:`str`, optional): Required if inline_message_id is not + specified. Unique identifier for the target chat or username of the target channel + (in the format ``@channelusername``). + message_id (:obj:`int`, optional): Required if inline_message_id is not specified. + Identifier of the message to edit. + inline_message_id (:obj:`str`, optional): Required if chat_id and message_id are not + specified. Identifier of the inline message. + latitude (:obj:`float`, optional): Latitude of location. + longitude (:obj:`float`, optional): Longitude of location. + location (:class:`telegram.Location`, optional): The location to send. + horizontal_accuracy (:obj:`float`, optional): The radius of uncertainty for the + location, measured in meters; 0-1500. + heading (:obj:`int`, optional): Direction in which the user is moving, in degrees. Must + be between 1 and 360 if specified. + proximity_alert_radius (:obj:`int`, optional): Maximum distance for proximity alerts + about approaching another chat member, in meters. Must be between 1 and 100000 if + specified. + reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): A JSON-serialized + object for a new inline keyboard. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :class:`telegram.Message`: On success, if edited message is not an inline message, the + edited message is returned, otherwise :obj:`True` is returned. + """ + if not (all([latitude, longitude]) or location): + raise ValueError( + "Either location or latitude and longitude must be passed as argument." + ) + if not (latitude is not None or longitude is not None) ^ bool(location): + raise ValueError( + "Either location or latitude and longitude must be passed as argument. Not both." + ) + + if isinstance(location, Location): + latitude = location.latitude + longitude = location.longitude + + data: JSONDict = {'latitude': latitude, 'longitude': longitude} + + if chat_id: + data['chat_id'] = chat_id + if message_id: + data['message_id'] = message_id + if inline_message_id: + data['inline_message_id'] = inline_message_id + if horizontal_accuracy: + data['horizontal_accuracy'] = horizontal_accuracy + if heading: + data['heading'] = heading + if proximity_alert_radius: + data['proximity_alert_radius'] = proximity_alert_radius + + return self._message( + 'editMessageLiveLocation', + data, + timeout=timeout, + reply_markup=reply_markup, + api_kwargs=api_kwargs, + ) + + @log + def stop_message_live_location( + self, + chat_id: Union[str, int] = None, + message_id: int = None, + inline_message_id: int = None, + reply_markup: InlineKeyboardMarkup = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> Union[Message, bool]: + """Use this method to stop updating a live location message sent by the bot or via the bot + (for inline bots) before live_period expires. + + Args: + chat_id (:obj:`int` | :obj:`str`): Required if inline_message_id is not specified. + Unique identifier for the target chat or username of the target channel + (in the format ``@channelusername``). + message_id (:obj:`int`, optional): Required if inline_message_id is not specified. + Identifier of the sent message with live location to stop. + inline_message_id (:obj:`str`, optional): Required if chat_id and message_id are not + specified. Identifier of the inline message. + reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): A JSON-serialized + object for a new inline keyboard. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :class:`telegram.Message`: On success, if edited message is sent by the bot, the + sent Message is returned, otherwise :obj:`True` is returned. + """ + data: JSONDict = {} + + if chat_id: + data['chat_id'] = chat_id + if message_id: + data['message_id'] = message_id + if inline_message_id: + data['inline_message_id'] = inline_message_id + + return self._message( + 'stopMessageLiveLocation', + data, + timeout=timeout, + reply_markup=reply_markup, + api_kwargs=api_kwargs, + ) + + @log + def send_venue( + self, + chat_id: Union[int, str], + latitude: float = None, + longitude: float = None, + title: str = None, + address: str = None, + foursquare_id: str = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: ReplyMarkup = None, + timeout: ODVInput[float] = DEFAULT_NONE, + venue: Venue = None, + foursquare_type: str = None, + api_kwargs: JSONDict = None, + google_place_id: str = None, + google_place_type: str = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + ) -> Message: + """Use this method to send information about a venue. + + Note: + * You can either supply :obj:`venue`, or :obj:`latitude`, :obj:`longitude`, + :obj:`title` and :obj:`address` and optionally :obj:`foursquare_id` and + :obj:`foursquare_type` or optionally :obj:`google_place_id` and + :obj:`google_place_type`. + * Foursquare details and Google Pace details are mutually exclusive. However, this + behaviour is undocumented and might be changed by Telegram. + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target channel (in the format ``@channelusername``). + latitude (:obj:`float`, optional): Latitude of venue. + longitude (:obj:`float`, optional): Longitude of venue. + title (:obj:`str`, optional): Name of the venue. + address (:obj:`str`, optional): Address of the venue. + foursquare_id (:obj:`str`, optional): Foursquare identifier of the venue. + foursquare_type (:obj:`str`, optional): Foursquare type of the venue, if known. + (For example, "arts_entertainment/default", "arts_entertainment/aquarium" or + "food/icecream".) + google_place_id (:obj:`str`, optional): Google Places identifier of the venue. + google_place_type (:obj:`str`, optional): Google Places type of the venue. (See + `supported types \ + <https://developers.google.com/places/web-service/supported_types>`_.) + venue (:class:`telegram.Venue`, optional): The venue to send. + disable_notification (:obj:`bool`, optional): Sends the message silently. Users will + receive a notification with no sound. + reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the + original message. + allow_sending_without_reply (:obj:`bool`, optional): Pass :obj:`True`, if the message + should be sent even if the specified replied-to message is not found. + reply_markup (:class:`telegram.ReplyMarkup`, optional): Additional interface options. A + JSON-serialized object for an inline keyboard, custom reply keyboard, instructions + to remove reply keyboard or to force a reply from the user. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :class:`telegram.Message`: On success, the sent Message is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + if not (venue or all([latitude, longitude, address, title])): + raise ValueError( + "Either venue or latitude, longitude, address and title must be" + "passed as arguments." + ) + + if isinstance(venue, Venue): + latitude = venue.location.latitude + longitude = venue.location.longitude + address = venue.address + title = venue.title + foursquare_id = venue.foursquare_id + foursquare_type = venue.foursquare_type + google_place_id = venue.google_place_id + google_place_type = venue.google_place_type + + data: JSONDict = { + 'chat_id': chat_id, + 'latitude': latitude, + 'longitude': longitude, + 'address': address, + 'title': title, + } + + if foursquare_id: + data['foursquare_id'] = foursquare_id + if foursquare_type: + data['foursquare_type'] = foursquare_type + if google_place_id: + data['google_place_id'] = google_place_id + if google_place_type: + data['google_place_type'] = google_place_type + + return self._message( # type: ignore[return-value] + 'sendVenue', + data, + timeout=timeout, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + allow_sending_without_reply=allow_sending_without_reply, + api_kwargs=api_kwargs, + ) + + @log + def send_contact( + self, + chat_id: Union[int, str], + phone_number: str = None, + first_name: str = None, + last_name: str = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: ReplyMarkup = None, + timeout: ODVInput[float] = DEFAULT_NONE, + contact: Contact = None, + vcard: str = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + ) -> Message: + """Use this method to send phone contacts. + + Note: + You can either supply :obj:`contact` or :obj:`phone_number` and :obj:`first_name` + with optionally :obj:`last_name` and optionally :obj:`vcard`. + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target channel (in the format ``@channelusername``). + phone_number (:obj:`str`, optional): Contact's phone number. + first_name (:obj:`str`, optional): Contact's first name. + last_name (:obj:`str`, optional): Contact's last name. + vcard (:obj:`str`, optional): Additional data about the contact in the form of a vCard, + 0-2048 bytes. + contact (:class:`telegram.Contact`, optional): The contact to send. + disable_notification (:obj:`bool`, optional): Sends the message silently. Users will + receive a notification with no sound. + reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the + original message. + allow_sending_without_reply (:obj:`bool`, optional): Pass :obj:`True`, if the message + should be sent even if the specified replied-to message is not found. + reply_markup (:class:`telegram.ReplyMarkup`, optional): Additional interface options. A + JSON-serialized object for an inline keyboard, custom reply keyboard, instructions + to remove reply keyboard or to force a reply from the user. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :class:`telegram.Message`: On success, the sent Message is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + if (not contact) and (not all([phone_number, first_name])): + raise ValueError( + "Either contact or phone_number and first_name must be passed as arguments." + ) + + if isinstance(contact, Contact): + phone_number = contact.phone_number + first_name = contact.first_name + last_name = contact.last_name + vcard = contact.vcard + + data: JSONDict = { + 'chat_id': chat_id, + 'phone_number': phone_number, + 'first_name': first_name, + } + + if last_name: + data['last_name'] = last_name + if vcard: + data['vcard'] = vcard + + return self._message( # type: ignore[return-value] + 'sendContact', + data, + timeout=timeout, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + allow_sending_without_reply=allow_sending_without_reply, + api_kwargs=api_kwargs, + ) + + @log + def send_game( + self, + chat_id: Union[int, str], + game_short_name: str, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: InlineKeyboardMarkup = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + ) -> Message: + """Use this method to send a game. + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat. + game_short_name (:obj:`str`): Short name of the game, serves as the unique identifier + for the game. Set up your games via `@BotFather <https://t.me/BotFather>`_. + disable_notification (:obj:`bool`, optional): Sends the message silently. Users will + receive a notification with no sound. + reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the + original message. + allow_sending_without_reply (:obj:`bool`, optional): Pass :obj:`True`, if the message + should be sent even if the specified replied-to message is not found. + reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): A JSON-serialized + object for a new inline keyboard. If empty, one ‘Play game_title’ button will be + shown. If not empty, the first button must launch the game. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :class:`telegram.Message`: On success, the sent Message is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = {'chat_id': chat_id, 'game_short_name': game_short_name} + + return self._message( # type: ignore[return-value] + 'sendGame', + data, + timeout=timeout, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + allow_sending_without_reply=allow_sending_without_reply, + api_kwargs=api_kwargs, + ) + + @log + def send_chat_action( + self, + chat_id: Union[str, int], + action: str, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> bool: + """ + Use this method when you need to tell the user that something is happening on the bot's + side. The status is set for 5 seconds or less (when a message arrives from your bot, + Telegram clients clear its typing status). Telegram only recommends using this method when + a response from the bot will take a noticeable amount of time to arrive. + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target channel (in the format ``@channelusername``). + action(:class:`telegram.ChatAction` | :obj:`str`): Type of action to broadcast. Choose + one, depending on what the user is about to receive. For convenience look at the + constants in :class:`telegram.ChatAction` + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = {'chat_id': chat_id, 'action': action} + + result = self._post('sendChatAction', data, timeout=timeout, api_kwargs=api_kwargs) + + return result # type: ignore[return-value] + + def _effective_inline_results( # pylint: disable=R0201 + self, + results: Union[ + Sequence['InlineQueryResult'], Callable[[int], Optional[Sequence['InlineQueryResult']]] + ], + next_offset: str = None, + current_offset: str = None, + ) -> Tuple[Sequence['InlineQueryResult'], Optional[str]]: + """ + Builds the effective results from the results input. + We make this a stand-alone method so tg.ext.ExtBot can wrap it. + + Returns: + Tuple of 1. the effective results and 2. correct the next_offset + + """ + if current_offset is not None and next_offset is not None: + raise ValueError('`current_offset` and `next_offset` are mutually exclusive!') + + if current_offset is not None: + # Convert the string input to integer + if current_offset == '': + current_offset_int = 0 + else: + current_offset_int = int(current_offset) + + # for now set to empty string, stating that there are no more results + # might change later + next_offset = '' + + if callable(results): + callable_output = results(current_offset_int) + if not callable_output: + effective_results: Sequence['InlineQueryResult'] = [] + else: + effective_results = callable_output + # the callback *might* return more results on the next call, so we increment + # the page count + next_offset = str(current_offset_int + 1) + else: + if len(results) > (current_offset_int + 1) * MAX_INLINE_QUERY_RESULTS: + # we expect more results for the next page + next_offset_int = current_offset_int + 1 + next_offset = str(next_offset_int) + effective_results = results[ + current_offset_int + * MAX_INLINE_QUERY_RESULTS : next_offset_int + * MAX_INLINE_QUERY_RESULTS + ] + else: + effective_results = results[current_offset_int * MAX_INLINE_QUERY_RESULTS :] + else: + effective_results = results # type: ignore[assignment] + + return effective_results, next_offset + + @log + def answer_inline_query( + self, + inline_query_id: str, + results: Union[ + Sequence['InlineQueryResult'], Callable[[int], Optional[Sequence['InlineQueryResult']]] + ], + cache_time: int = 300, + is_personal: bool = None, + next_offset: str = None, + switch_pm_text: str = None, + switch_pm_parameter: str = None, + timeout: ODVInput[float] = DEFAULT_NONE, + current_offset: str = None, + api_kwargs: JSONDict = None, + ) -> bool: + """ + Use this method to send answers to an inline query. No more than 50 results per query are + allowed. + + Warning: + In most use cases :attr:`current_offset` should not be passed manually. Instead of + calling this method directly, use the shortcut :meth:`telegram.InlineQuery.answer` with + ``auto_pagination=True``, which will take care of passing the correct value. + + Args: + inline_query_id (:obj:`str`): Unique identifier for the answered query. + results (List[:class:`telegram.InlineQueryResult`] | Callable): A list of results for + the inline query. In case :attr:`current_offset` is passed, ``results`` may also be + a callable that accepts the current page index starting from 0. It must return + either a list of :class:`telegram.InlineQueryResult` instances or :obj:`None` if + there are no more results. + cache_time (:obj:`int`, optional): The maximum amount of time in seconds that the + result of the inline query may be cached on the server. Defaults to ``300``. + is_personal (:obj:`bool`, optional): Pass :obj:`True`, if results may be cached on + the server side only for the user that sent the query. By default, + results may be returned to any user who sends the same query. + next_offset (:obj:`str`, optional): Pass the offset that a client should send in the + next query with the same text to receive more results. Pass an empty string if + there are no more results or if you don't support pagination. Offset length can't + exceed 64 bytes. + switch_pm_text (:obj:`str`, optional): If passed, clients will display a button with + specified text that switches the user to a private chat with the bot and sends the + bot a start message with the parameter ``switch_pm_parameter``. + switch_pm_parameter (:obj:`str`, optional): Deep-linking parameter for the /start + message sent to the bot when user presses the switch button. 1-64 characters, + only A-Z, a-z, 0-9, _ and - are allowed. + current_offset (:obj:`str`, optional): The :attr:`telegram.InlineQuery.offset` of + the inline query to answer. If passed, PTB will automatically take care of + the pagination for you, i.e. pass the correct ``next_offset`` and truncate the + results list/get the results from the callable you passed. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Example: + An inline bot that sends YouTube videos can ask the user to connect the bot to their + YouTube account to adapt search results accordingly. To do this, it displays a + 'Connect your YouTube account' button above the results, or even before showing any. + The user presses the button, switches to a private chat with the bot and, in doing so, + passes a start parameter that instructs the bot to return an oauth link. Once done, the + bot can offer a switch_inline button so that the user can easily return to the chat + where they wanted to use the bot's inline capabilities. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + + @no_type_check + def _set_defaults(res): + # pylint: disable=W0212 + if hasattr(res, 'parse_mode') and res.parse_mode == DEFAULT_NONE: + if self.defaults: + res.parse_mode = self.defaults.parse_mode + else: + res.parse_mode = None + if hasattr(res, 'input_message_content') and res.input_message_content: + if ( + hasattr(res.input_message_content, 'parse_mode') + and res.input_message_content.parse_mode == DEFAULT_NONE + ): + if self.defaults: + res.input_message_content.parse_mode = DefaultValue.get_value( + self.defaults.parse_mode + ) + else: + res.input_message_content.parse_mode = None + if ( + hasattr(res.input_message_content, 'disable_web_page_preview') + and res.input_message_content.disable_web_page_preview == DEFAULT_NONE + ): + if self.defaults: + res.input_message_content.disable_web_page_preview = ( + DefaultValue.get_value(self.defaults.disable_web_page_preview) + ) + else: + res.input_message_content.disable_web_page_preview = None + + effective_results, next_offset = self._effective_inline_results( + results=results, next_offset=next_offset, current_offset=current_offset + ) + + # Apply defaults + for result in effective_results: + _set_defaults(result) + + results_dicts = [res.to_dict() for res in effective_results] + + data: JSONDict = {'inline_query_id': inline_query_id, 'results': results_dicts} + + if cache_time or cache_time == 0: + data['cache_time'] = cache_time + if is_personal: + data['is_personal'] = is_personal + if next_offset is not None: + data['next_offset'] = next_offset + if switch_pm_text: + data['switch_pm_text'] = switch_pm_text + if switch_pm_parameter: + data['switch_pm_parameter'] = switch_pm_parameter + + return self._post( # type: ignore[return-value] + 'answerInlineQuery', + data, + timeout=timeout, + api_kwargs=api_kwargs, + ) + + @log + def get_user_profile_photos( + self, + user_id: Union[str, int], + offset: int = None, + limit: int = 100, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> Optional[UserProfilePhotos]: + """Use this method to get a list of profile pictures for a user. + + Args: + user_id (:obj:`int`): Unique identifier of the target user. + offset (:obj:`int`, optional): Sequential number of the first photo to be returned. + By default, all photos are returned. + limit (:obj:`int`, optional): Limits the number of photos to be retrieved. Values + between 1-100 are accepted. Defaults to ``100``. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :class:`telegram.UserProfilePhotos` + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = {'user_id': user_id} + + if offset is not None: + data['offset'] = offset + if limit: + data['limit'] = limit + + result = self._post('getUserProfilePhotos', data, timeout=timeout, api_kwargs=api_kwargs) + + return UserProfilePhotos.de_json(result, self) # type: ignore[return-value, arg-type] + + @log + def get_file( + self, + file_id: Union[ + str, Animation, Audio, ChatPhoto, Document, PhotoSize, Sticker, Video, VideoNote, Voice + ], + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> File: + """ + Use this method to get basic info about a file and prepare it for downloading. For the + moment, bots can download files of up to 20MB in size. The file can then be downloaded + with :meth:`telegram.File.download`. It is guaranteed that the link will be + valid for at least 1 hour. When the link expires, a new one can be requested by + calling get_file again. + + Note: + This function may not preserve the original file name and MIME type. + You should save the file's MIME type and name (if available) when the File object + is received. + + Args: + file_id (:obj:`str` | :class:`telegram.Animation` | :class:`telegram.Audio` | \ + :class:`telegram.ChatPhoto` | :class:`telegram.Document` | \ + :class:`telegram.PhotoSize` | :class:`telegram.Sticker` | \ + :class:`telegram.Video` | :class:`telegram.VideoNote` | \ + :class:`telegram.Voice`): + Either the file identifier or an object that has a file_id attribute + to get file information about. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :class:`telegram.File` + + Raises: + :class:`telegram.error.TelegramError` + + """ + try: + file_id = file_id.file_id # type: ignore[union-attr] + except AttributeError: + pass + + data: JSONDict = {'file_id': file_id} + + result = self._post('getFile', data, timeout=timeout, api_kwargs=api_kwargs) + + if result.get('file_path') and not is_local_file( # type: ignore[union-attr] + result['file_path'] # type: ignore[index] + ): + result['file_path'] = '{}/{}'.format( # type: ignore[index] + self.base_file_url, result['file_path'] # type: ignore[index] + ) + + return File.de_json(result, self) # type: ignore[return-value, arg-type] + + @log + def kick_chat_member( + self, + chat_id: Union[str, int], + user_id: Union[str, int], + timeout: ODVInput[float] = DEFAULT_NONE, + until_date: Union[int, datetime] = None, + api_kwargs: JSONDict = None, + revoke_messages: bool = None, + ) -> bool: + """ + Use this method to kick a user from a group, supergroup or a channel. In the case of + supergroups and channels, the user will not be able to return to the group on their own + using invite links, etc., unless unbanned first. The bot must be an administrator in the + chat for this to work and must have the appropriate admin rights. + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target group or username + of the target supergroup or channel (in the format ``@channelusername``). + user_id (:obj:`int`): Unique identifier of the target user. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + until_date (:obj:`int` | :obj:`datetime.datetime`, optional): Date when the user will + be unbanned, unix time. If user is banned for more than 366 days or less than 30 + seconds from the current time they are considered to be banned forever. Applied + for supergroups and channels only. + For timezone naive :obj:`datetime.datetime` objects, the default timezone of the + bot will be used. + revoke_messages (:obj:`bool`, optional): Pass :obj:`True` to delete all messages from + the chat for the user that is being removed. If :obj:`False`, the user will be able + to see messages in the group that were sent before the user was removed. + Always :obj:`True` for supergroups and channels. + + .. versionadded:: 13.4 + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = {'chat_id': chat_id, 'user_id': user_id} + + if until_date is not None: + if isinstance(until_date, datetime): + until_date = to_timestamp( + until_date, tzinfo=self.defaults.tzinfo if self.defaults else None + ) + data['until_date'] = until_date + + if revoke_messages is not None: + data['revoke_messages'] = revoke_messages + + result = self._post('kickChatMember', data, timeout=timeout, api_kwargs=api_kwargs) + + return result # type: ignore[return-value] + + @log + def unban_chat_member( + self, + chat_id: Union[str, int], + user_id: Union[str, int], + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + only_if_banned: bool = None, + ) -> bool: + """Use this method to unban a previously kicked user in a supergroup or channel. + + The user will *not* return to the group or channel automatically, but will be able to join + via link, etc. The bot must be an administrator for this to work. By default, this method + guarantees that after the call the user is not a member of the chat, but will be able to + join it. So if the user is a member of the chat they will also be *removed* from the chat. + If you don't want this, use the parameter :attr:`only_if_banned`. + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target supergroup or channel (in the format ``@channelusername``). + user_id (:obj:`int`): Unique identifier of the target user. + only_if_banned (:obj:`bool`, optional): Do nothing if the user is not banned. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :obj:`bool` On success, :obj:`True` is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = {'chat_id': chat_id, 'user_id': user_id} + + if only_if_banned is not None: + data['only_if_banned'] = only_if_banned + + result = self._post('unbanChatMember', data, timeout=timeout, api_kwargs=api_kwargs) + + return result # type: ignore[return-value] + + @log + def answer_callback_query( + self, + callback_query_id: str, + text: str = None, + show_alert: bool = False, + url: str = None, + cache_time: int = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> bool: + """ + Use this method to send answers to callback queries sent from inline keyboards. The answer + will be displayed to the user as a notification at the top of the chat screen or as an + alert. + Alternatively, the user can be redirected to the specified Game URL. For this option to + work, you must first create a game for your bot via `@BotFather <https://t.me/BotFather>`_ + and accept the terms. Otherwise, you may use links like t.me/your_bot?start=XXXX that open + your bot with a parameter. + + Args: + callback_query_id (:obj:`str`): Unique identifier for the query to be answered. + text (:obj:`str`, optional): Text of the notification. If not specified, nothing will + be shown to the user, 0-200 characters. + show_alert (:obj:`bool`, optional): If :obj:`True`, an alert will be shown by the + client instead of a notification at the top of the chat screen. Defaults to + :obj:`False`. + url (:obj:`str`, optional): URL that will be opened by the user's client. If you have + created a Game and accepted the conditions via + `@BotFather <https://t.me/BotFather>`_, specify the URL that + opens your game - note that this will only work if the query comes from a callback + game button. Otherwise, you may use links like t.me/your_bot?start=XXXX that open + your bot with a parameter. + cache_time (:obj:`int`, optional): The maximum amount of time in seconds that the + result of the callback query may be cached client-side. Defaults to 0. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :obj:`bool` On success, :obj:`True` is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = {'callback_query_id': callback_query_id} + + if text: + data['text'] = text + if show_alert: + data['show_alert'] = show_alert + if url: + data['url'] = url + if cache_time is not None: + data['cache_time'] = cache_time + + result = self._post('answerCallbackQuery', data, timeout=timeout, api_kwargs=api_kwargs) + + return result # type: ignore[return-value] + + @log + def edit_message_text( + self, + text: str, + chat_id: Union[str, int] = None, + message_id: int = None, + inline_message_id: int = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, + reply_markup: InlineKeyboardMarkup = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + ) -> Union[Message, bool]: + """ + Use this method to edit text and game messages. + + Args: + chat_id (:obj:`int` | :obj:`str`, optional): Required if inline_message_id is not + specified. Unique identifier for the target chat or username of the target channel + (in the format ``@channelusername``) + message_id (:obj:`int`, optional): Required if inline_message_id is not specified. + Identifier of the message to edit. + inline_message_id (:obj:`str`, optional): Required if chat_id and message_id are not + specified. Identifier of the inline message. + text (:obj:`str`): New text of the message, 1-4096 characters after entities parsing. + parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to + show bold, italic, fixed-width text or inline URLs in your bot's message. See the + constants in :class:`telegram.ParseMode` for the available modes. + entities (List[:class:`telegram.MessageEntity`], optional): List of special entities + that appear in message text, which can be specified instead of :attr:`parse_mode`. + disable_web_page_preview (:obj:`bool`, optional): Disables link previews for links in + this message. + reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): A JSON-serialized + object for an inline keyboard. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :class:`telegram.Message`: On success, if edited message is not an inline message, the + edited message is returned, otherwise :obj:`True` is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = { + 'text': text, + 'parse_mode': parse_mode, + 'disable_web_page_preview': disable_web_page_preview, + } + + if chat_id: + data['chat_id'] = chat_id + if message_id: + data['message_id'] = message_id + if inline_message_id: + data['inline_message_id'] = inline_message_id + if entities: + data['entities'] = [me.to_dict() for me in entities] + + return self._message( + 'editMessageText', + data, + timeout=timeout, + reply_markup=reply_markup, + api_kwargs=api_kwargs, + ) + + @log + def edit_message_caption( + self, + chat_id: Union[str, int] = None, + message_id: int = None, + inline_message_id: int = None, + caption: str = None, + reply_markup: InlineKeyboardMarkup = None, + timeout: ODVInput[float] = DEFAULT_NONE, + parse_mode: ODVInput[str] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + ) -> Union[Message, bool]: + """ + Use this method to edit captions of messages. + + Args: + chat_id (:obj:`int` | :obj:`str`, optional): Required if inline_message_id is not + specified. Unique identifier for the target chat or username of the target channel + (in the format ``@channelusername``) + message_id (:obj:`int`, optional): Required if inline_message_id is not specified. + Identifier of the message to edit. + inline_message_id (:obj:`str`, optional): Required if chat_id and message_id are not + specified. Identifier of the inline message. + caption (:obj:`str`, optional): New caption of the message, 0-1024 characters after + entities parsing. + parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to + show bold, italic, fixed-width text or inline URLs in the media caption. See the + constants in :class:`telegram.ParseMode` for the available modes. + caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special + entities that appear in message text, which can be specified instead of + :attr:`parse_mode`. + reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): A JSON-serialized + object for an inline keyboard. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :class:`telegram.Message`: On success, if edited message is not an inline message, the + edited message is returned, otherwise :obj:`True` is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + if inline_message_id is None and (chat_id is None or message_id is None): + raise ValueError( + 'edit_message_caption: Both chat_id and message_id are required when ' + 'inline_message_id is not specified' + ) + + data: JSONDict = {'parse_mode': parse_mode} + + if caption: + data['caption'] = caption + if caption_entities: + data['caption_entities'] = [me.to_dict() for me in caption_entities] + if chat_id: + data['chat_id'] = chat_id + if message_id: + data['message_id'] = message_id + if inline_message_id: + data['inline_message_id'] = inline_message_id + + return self._message( + 'editMessageCaption', + data, + timeout=timeout, + reply_markup=reply_markup, + api_kwargs=api_kwargs, + ) + + @log + def edit_message_media( + self, + chat_id: Union[str, int] = None, + message_id: int = None, + inline_message_id: int = None, + media: 'InputMedia' = None, + reply_markup: InlineKeyboardMarkup = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> Union[Message, bool]: + """ + Use this method to edit animation, audio, document, photo, or video messages. If a message + is part of a message album, then it can be edited only to an audio for audio albums, only + to a document for document albums and to a photo or a video otherwise. When an inline + message is edited, a new file can't be uploaded. Use a previously uploaded file via its + ``file_id`` or specify a URL. + + Args: + chat_id (:obj:`int` | :obj:`str`, optional): Required if inline_message_id is not + specified. Unique identifier for the target chat or username of the target channel + (in the format ``@channelusername``). + message_id (:obj:`int`, optional): Required if inline_message_id is not specified. + Identifier of the message to edit. + inline_message_id (:obj:`str`, optional): Required if chat_id and message_id are not + specified. Identifier of the inline message. + media (:class:`telegram.InputMedia`): An object for a new media content + of the message. + reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): A JSON-serialized + object for an inline keyboard. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :class:`telegram.Message`: On success, if edited message is sent by the bot, the + edited Message is returned, otherwise :obj:`True` is returned. + + Raises: + :class:`telegram.error.TelegramError` + """ + if inline_message_id is None and (chat_id is None or message_id is None): + raise ValueError( + 'edit_message_media: Both chat_id and message_id are required when ' + 'inline_message_id is not specified' + ) + + data: JSONDict = {'media': media} + + if chat_id: + data['chat_id'] = chat_id + if message_id: + data['message_id'] = message_id + if inline_message_id: + data['inline_message_id'] = inline_message_id + + return self._message( + 'editMessageMedia', + data, + timeout=timeout, + reply_markup=reply_markup, + api_kwargs=api_kwargs, + ) + + @log + def edit_message_reply_markup( + self, + chat_id: Union[str, int] = None, + message_id: int = None, + inline_message_id: int = None, + reply_markup: Optional['InlineKeyboardMarkup'] = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> Union[Message, bool]: + """ + Use this method to edit only the reply markup of messages sent by the bot or via the bot + (for inline bots). + + Args: + chat_id (:obj:`int` | :obj:`str`, optional): Required if inline_message_id is not + specified. Unique identifier for the target chat or username of the target channel + (in the format ``@channelusername``). + message_id (:obj:`int`, optional): Required if inline_message_id is not specified. + Identifier of the message to edit. + inline_message_id (:obj:`str`, optional): Required if chat_id and message_id are not + specified. Identifier of the inline message. + reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): A JSON-serialized + object for an inline keyboard. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :class:`telegram.Message`: On success, if edited message is not an inline message, the + edited message is returned, otherwise :obj:`True` is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + if inline_message_id is None and (chat_id is None or message_id is None): + raise ValueError( + 'edit_message_reply_markup: Both chat_id and message_id are required when ' + 'inline_message_id is not specified' + ) + + data: JSONDict = {} + + if chat_id: + data['chat_id'] = chat_id + if message_id: + data['message_id'] = message_id + if inline_message_id: + data['inline_message_id'] = inline_message_id + + return self._message( + 'editMessageReplyMarkup', + data, + timeout=timeout, + reply_markup=reply_markup, + api_kwargs=api_kwargs, + ) + + @log + def get_updates( + self, + offset: int = None, + limit: int = 100, + timeout: float = 0, + read_latency: float = 2.0, + allowed_updates: List[str] = None, + api_kwargs: JSONDict = None, + ) -> List[Update]: + """Use this method to receive incoming updates using long polling. + + Args: + offset (:obj:`int`, optional): Identifier of the first update to be returned. Must be + greater by one than the highest among the identifiers of previously received + updates. By default, updates starting with the earliest unconfirmed update are + returned. An update is considered confirmed as soon as getUpdates is called with an + offset higher than its :attr:`telegram.Update.update_id`. The negative offset can + be specified to retrieve updates starting from -offset update from the end of the + updates queue. All previous updates will forgotten. + limit (:obj:`int`, optional): Limits the number of updates to be retrieved. Values + between 1-100 are accepted. Defaults to ``100``. + timeout (:obj:`int`, optional): Timeout in seconds for long polling. Defaults to ``0``, + i.e. usual short polling. Should be positive, short polling should be used for + testing purposes only. + read_latency (:obj:`float` | :obj:`int`, optional): Grace time in seconds for receiving + the reply from server. Will be added to the ``timeout`` value and used as the read + timeout from server. Defaults to ``2``. + allowed_updates (List[:obj:`str`]), optional): A JSON-serialized list the types of + updates you want your bot to receive. For example, specify ["message", + "edited_channel_post", "callback_query"] to only receive updates of these types. + See :class:`telegram.Update` for a complete list of available update types. + Specify an empty list to receive all updates except + :attr:`telegram.Update.chat_member` (default). If not specified, the previous + setting will be used. Please note that this parameter doesn't affect updates + created before the call to the get_updates, so unwanted updates may be received for + a short period of time. + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Note: + 1. This method will not work if an outgoing webhook is set up. + 2. In order to avoid getting duplicate updates, recalculate offset after each + server response. + 3. To take full advantage of this library take a look at :class:`telegram.ext.Updater` + + Returns: + List[:class:`telegram.Update`] + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = {'timeout': timeout} + + if offset: + data['offset'] = offset + if limit: + data['limit'] = limit + if allowed_updates is not None: + data['allowed_updates'] = allowed_updates + + # Ideally we'd use an aggressive read timeout for the polling. However, + # * Short polling should return within 2 seconds. + # * Long polling poses a different problem: the connection might have been dropped while + # waiting for the server to return and there's no way of knowing the connection had been + # dropped in real time. + result = cast( + List[JSONDict], + self._post( + 'getUpdates', + data, + timeout=float(read_latency) + float(timeout), + api_kwargs=api_kwargs, + ), + ) + + if result: + self.logger.debug('Getting updates: %s', [u['update_id'] for u in result]) + else: + self.logger.debug('No new updates found.') + + return Update.de_list(result, self) # type: ignore[return-value] + + @log + def set_webhook( + self, + url: str = None, + certificate: FileInput = None, + timeout: ODVInput[float] = DEFAULT_NONE, + max_connections: int = 40, + allowed_updates: List[str] = None, + api_kwargs: JSONDict = None, + ip_address: str = None, + drop_pending_updates: bool = None, + ) -> bool: + """ + Use this method to specify a url and receive incoming updates via an outgoing webhook. + Whenever there is an update for the bot, Telegram will send an HTTPS POST request to the + specified url, containing a JSON-serialized Update. In case of an unsuccessful request, + Telegram will give up after a reasonable amount of attempts. + + If you'd like to make sure that the Webhook request comes from Telegram, Telegram + recommends using a secret path in the URL, e.g. https://www.example.com/<token>. Since + nobody else knows your bot's token, you can be pretty sure it's us. + + Note: + The certificate argument should be a file from disk ``open(filename, 'rb')``. + + Args: + url (:obj:`str`): HTTPS url to send updates to. Use an empty string to remove webhook + integration. + certificate (:obj:`filelike`): Upload your public key certificate so that the root + certificate in use can be checked. See our self-signed guide for details. + (https://goo.gl/rw7w6Y) + ip_address (:obj:`str`, optional): The fixed IP address which will be used to send + webhook requests instead of the IP address resolved through DNS. + max_connections (:obj:`int`, optional): Maximum allowed number of simultaneous HTTPS + connections to the webhook for update delivery, 1-100. Defaults to ``40``. Use + lower values to limit the load on your bot's server, and higher values to increase + your bot's throughput. + allowed_updates (List[:obj:`str`], optional): A JSON-serialized list the types of + updates you want your bot to receive. For example, specify ["message", + "edited_channel_post", "callback_query"] to only receive updates of these types. + See :class:`telegram.Update` for a complete list of available update types. + Specify an empty list to receive all updates except + :attr:`telegram.Update.chat_member` (default). If not specified, the previous + setting will be used. Please note that this parameter doesn't affect updates + created before the call to the set_webhook, so unwanted updates may be received for + a short period of time. + drop_pending_updates (:obj:`bool`, optional): Pass :obj:`True` to drop all pending + updates. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Note: + 1. You will not be able to receive updates using :meth:`get_updates` for long as an + outgoing webhook is set up. + 2. To use a self-signed certificate, you need to upload your public key certificate + using certificate parameter. Please upload as InputFile, sending a String will not + work. + 3. Ports currently supported for Webhooks: ``443``, ``80``, ``88``, ``8443``. + + If you're having any trouble setting up webhooks, please check out this `guide to + Webhooks`_. + + Returns: + :obj:`bool` On success, :obj:`True` is returned. + + Raises: + :class:`telegram.error.TelegramError` + + .. _`guide to Webhooks`: https://core.telegram.org/bots/webhooks + + """ + data: JSONDict = {} + + if url is not None: + data['url'] = url + if certificate: + data['certificate'] = parse_file_input(certificate) + if max_connections is not None: + data['max_connections'] = max_connections + if allowed_updates is not None: + data['allowed_updates'] = allowed_updates + if ip_address: + data['ip_address'] = ip_address + if drop_pending_updates: + data['drop_pending_updates'] = drop_pending_updates + + result = self._post('setWebhook', data, timeout=timeout, api_kwargs=api_kwargs) + + return result # type: ignore[return-value] + + @log + def delete_webhook( + self, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + drop_pending_updates: bool = None, + ) -> bool: + """ + Use this method to remove webhook integration if you decide to switch back to + :meth:`get_updates()`. + + Args: + drop_pending_updates (:obj:`bool`, optional): Pass :obj:`True` to drop all pending + updates. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data = {} + + if drop_pending_updates: + data['drop_pending_updates'] = drop_pending_updates + + result = self._post('deleteWebhook', data, timeout=timeout, api_kwargs=api_kwargs) + + return result # type: ignore[return-value] + + @log + def leave_chat( + self, + chat_id: Union[str, int], + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> bool: + """Use this method for your bot to leave a group, supergroup or channel. + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target supergroup or channel (in the format ``@channelusername``). + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = {'chat_id': chat_id} + + result = self._post('leaveChat', data, timeout=timeout, api_kwargs=api_kwargs) + + return result # type: ignore[return-value] + + @log + def get_chat( + self, + chat_id: Union[str, int], + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> Chat: + """ + Use this method to get up to date information about the chat (current name of the user for + one-on-one conversations, current username of a user, group or channel, etc.). + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target supergroup or channel (in the format ``@channelusername``). + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :class:`telegram.Chat` + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = {'chat_id': chat_id} + + result = self._post('getChat', data, timeout=timeout, api_kwargs=api_kwargs) + + return Chat.de_json(result, self) # type: ignore[return-value, arg-type] + + @log + def get_chat_administrators( + self, + chat_id: Union[str, int], + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> List[ChatMember]: + """ + Use this method to get a list of administrators in a chat. + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target supergroup or channel (in the format ``@channelusername``). + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + List[:class:`telegram.ChatMember`]: On success, returns a list of ``ChatMember`` + objects that contains information about all chat administrators except + other bots. If the chat is a group or a supergroup and no administrators were + appointed, only the creator will be returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = {'chat_id': chat_id} + + result = self._post('getChatAdministrators', data, timeout=timeout, api_kwargs=api_kwargs) + + return ChatMember.de_list(result, self) # type: ignore + + @log + def get_chat_members_count( + self, + chat_id: Union[str, int], + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> int: + """Use this method to get the number of members in a chat. + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target supergroup or channel (in the format ``@channelusername``). + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :obj:`int`: Number of members in the chat. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = {'chat_id': chat_id} + + result = self._post('getChatMembersCount', data, timeout=timeout, api_kwargs=api_kwargs) + + return result # type: ignore[return-value] + + @log + def get_chat_member( + self, + chat_id: Union[str, int], + user_id: Union[str, int], + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> ChatMember: + """Use this method to get information about a member of a chat. + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target supergroup or channel (in the format ``@channelusername``). + user_id (:obj:`int`): Unique identifier of the target user. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :class:`telegram.ChatMember` + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = {'chat_id': chat_id, 'user_id': user_id} + + result = self._post('getChatMember', data, timeout=timeout, api_kwargs=api_kwargs) + + return ChatMember.de_json(result, self) # type: ignore[return-value, arg-type] + + @log + def set_chat_sticker_set( + self, + chat_id: Union[str, int], + sticker_set_name: str, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> bool: + """Use this method to set a new group sticker set for a supergroup. + The bot must be an administrator in the chat for this to work and must have the appropriate + admin rights. Use the field :attr:`telegram.Chat.can_set_sticker_set` optionally returned + in :meth:`get_chat` requests to check if the bot can use this method. + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target supergroup (in the format @supergroupusername). + sticker_set_name (:obj:`str`): Name of the sticker set to be set as the group + sticker set. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + """ + data: JSONDict = {'chat_id': chat_id, 'sticker_set_name': sticker_set_name} + + result = self._post('setChatStickerSet', data, timeout=timeout, api_kwargs=api_kwargs) + + return result # type: ignore[return-value] + + @log + def delete_chat_sticker_set( + self, + chat_id: Union[str, int], + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> bool: + """Use this method to delete a group sticker set from a supergroup. The bot must be an + administrator in the chat for this to work and must have the appropriate admin rights. + Use the field :attr:`telegram.Chat.can_set_sticker_set` optionally returned in + :meth:`get_chat` requests to check if the bot can use this method. + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target supergroup (in the format @supergroupusername). + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + """ + data: JSONDict = {'chat_id': chat_id} + + result = self._post('deleteChatStickerSet', data, timeout=timeout, api_kwargs=api_kwargs) + + return result # type: ignore[return-value] + + def get_webhook_info( + self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None + ) -> WebhookInfo: + """Use this method to get current webhook status. Requires no parameters. + + If the bot is using :meth:`get_updates`, will return an object with the + :attr:`telegram.WebhookInfo.url` field empty. + + Args: + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :class:`telegram.WebhookInfo` + + """ + result = self._post('getWebhookInfo', None, timeout=timeout, api_kwargs=api_kwargs) + + return WebhookInfo.de_json(result, self) # type: ignore[return-value, arg-type] + + @log + def set_game_score( + self, + user_id: Union[int, str], + score: int, + chat_id: Union[str, int] = None, + message_id: int = None, + inline_message_id: int = None, + force: bool = None, + disable_edit_message: bool = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> Union[Message, bool]: + """ + Use this method to set the score of the specified user in a game. + + Args: + user_id (:obj:`int`): User identifier. + score (:obj:`int`): New score, must be non-negative. + force (:obj:`bool`, optional): Pass :obj:`True`, if the high score is allowed to + decrease. This can be useful when fixing mistakes or banning cheaters. + disable_edit_message (:obj:`bool`, optional): Pass :obj:`True`, if the game message + should not be automatically edited to include the current scoreboard. + chat_id (:obj:`int` | :obj:`str`, optional): Required if inline_message_id is not + specified. Unique identifier for the target chat. + message_id (:obj:`int`, optional): Required if inline_message_id is not specified. + Identifier of the sent message. + inline_message_id (:obj:`str`, optional): Required if chat_id and message_id are not + specified. Identifier of the inline message. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :class:`telegram.Message`: The edited message, or if the message wasn't sent by the bot + , :obj:`True`. + + Raises: + :class:`telegram.error.TelegramError`: If the new score is not greater than the user's + current score in the chat and force is :obj:`False`. + + """ + data: JSONDict = {'user_id': user_id, 'score': score} + + if chat_id: + data['chat_id'] = chat_id + if message_id: + data['message_id'] = message_id + if inline_message_id: + data['inline_message_id'] = inline_message_id + if force is not None: + data['force'] = force + if disable_edit_message is not None: + data['disable_edit_message'] = disable_edit_message + + return self._message( + 'setGameScore', + data, + timeout=timeout, + api_kwargs=api_kwargs, + ) + + @log + def get_game_high_scores( + self, + user_id: Union[int, str], + chat_id: Union[str, int] = None, + message_id: int = None, + inline_message_id: int = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> List[GameHighScore]: + """ + Use this method to get data for high score tables. Will return the score of the specified + user and several of their neighbors in a game. + + Note: + This method will currently return scores for the target user, plus two of their + closest neighbors on each side. Will also return the top three users if the user and + his neighbors are not among them. Please note that this behavior is subject to change. + + Args: + user_id (:obj:`int`): Target user id. + chat_id (:obj:`int` | :obj:`str`, optional): Required if inline_message_id is not + specified. Unique identifier for the target chat. + message_id (:obj:`int`, optional): Required if inline_message_id is not specified. + Identifier of the sent message. + inline_message_id (:obj:`str`, optional): Required if chat_id and message_id are not + specified. Identifier of the inline message. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + List[:class:`telegram.GameHighScore`] + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = {'user_id': user_id} + + if chat_id: + data['chat_id'] = chat_id + if message_id: + data['message_id'] = message_id + if inline_message_id: + data['inline_message_id'] = inline_message_id + + result = self._post('getGameHighScores', data, timeout=timeout, api_kwargs=api_kwargs) + + return GameHighScore.de_list(result, self) # type: ignore + + @log + def send_invoice( + self, + chat_id: Union[int, str], + title: str, + description: str, + payload: str, + provider_token: str, + currency: str, + prices: List['LabeledPrice'], + start_parameter: str = None, + photo_url: str = None, + photo_size: int = None, + photo_width: int = None, + photo_height: int = None, + need_name: bool = None, + need_phone_number: bool = None, + need_email: bool = None, + need_shipping_address: bool = None, + is_flexible: bool = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: InlineKeyboardMarkup = None, + provider_data: Union[str, object] = None, + send_phone_number_to_provider: bool = None, + send_email_to_provider: bool = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + max_tip_amount: int = None, + suggested_tip_amounts: List[int] = None, + ) -> Message: + """Use this method to send invoices. + + Warning: + As of API 5.2 :attr:`start_parameter` is an optional argument and therefore the order + of the arguments had to be changed. Use keyword arguments to make sure that the + arguments are passed correctly. + + .. versionchanged:: 13.5 + As of Bot API 5.2, the parameter :attr:`start_parameter` is optional. + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target channel (in the format ``@channelusername``). + title (:obj:`str`): Product name, 1-32 characters. + description (:obj:`str`): Product description, 1-255 characters. + payload (:obj:`str`): Bot-defined invoice payload, 1-128 bytes. This will not be + displayed to the user, use for your internal processes. + provider_token (:obj:`str`): Payments provider token, obtained via + `@BotFather <https://t.me/BotFather>`_. + currency (:obj:`str`): Three-letter ISO 4217 currency code. + prices (List[:class:`telegram.LabeledPrice`)]: Price breakdown, a JSON-serialized list + of components (e.g. product price, tax, discount, delivery cost, delivery tax, + bonus, etc.). + max_tip_amount (:obj:`int`, optional): The maximum accepted amount for tips in the + smallest units of the currency (integer, not float/double). For example, for a + maximum tip of US$ 1.45 pass ``max_tip_amount = 145``. See the exp parameter in + `currencies.json <https://core.telegram.org/bots/payments/currencies.json>`_, it + shows the number of digits past the decimal point for each currency (2 for the + majority of currencies). Defaults to ``0``. + + .. versionadded:: 13.5 + suggested_tip_amounts (List[:obj:`int`], optional): A JSON-serialized array of + suggested amounts of tips in the smallest units of the currency (integer, not + float/double). At most 4 suggested tip amounts can be specified. The suggested tip + amounts must be positive, passed in a strictly increased order and must not exceed + ``max_tip_amount``. + + .. versionadded:: 13.5 + start_parameter (:obj:`str`, optional): Unique deep-linking parameter. If left empty, + *forwarded copies* of the sent message will have a *Pay* button, allowing + multiple users to pay directly from the forwarded message, using the same invoice. + If non-empty, forwarded copies of the sent message will have a *URL* button with a + deep link to the bot (instead of a *Pay* button), with the value used as the + start parameter. + + .. versionchanged:: 13.5 + As of Bot API 5.2, this parameter is optional. + provider_data (:obj:`str` | :obj:`object`, optional): JSON-serialized data about the + invoice, which will be shared with the payment provider. A detailed description of + required fields should be provided by the payment provider. When an object is + passed, it will be encoded as JSON. + photo_url (:obj:`str`, optional): URL of the product photo for the invoice. Can be a + photo of the goods or a marketing image for a service. People like it better when + they see what they are paying for. + photo_size (:obj:`str`, optional): Photo size. + photo_width (:obj:`int`, optional): Photo width. + photo_height (:obj:`int`, optional): Photo height. + need_name (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's full + name to complete the order. + need_phone_number (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's + phone number to complete the order. + need_email (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's email + to complete the order. + need_shipping_address (:obj:`bool`, optional): Pass :obj:`True`, if you require the + user's shipping address to complete the order. + send_phone_number_to_provider (:obj:`bool`, optional): Pass :obj:`True`, if user's + phone number should be sent to provider. + send_email_to_provider (:obj:`bool`, optional): Pass :obj:`True`, if user's email + address should be sent to provider. + is_flexible (:obj:`bool`, optional): Pass :obj:`True`, if the final price depends on + the shipping method. + disable_notification (:obj:`bool`, optional): Sends the message silently. Users will + receive a notification with no sound. + reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the + original message. + allow_sending_without_reply (:obj:`bool`, optional): Pass :obj:`True`, if the message + should be sent even if the specified replied-to message is not found. + reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): A JSON-serialized + object for an inline keyboard. If empty, one 'Pay total price' button will be + shown. If not empty, the first button must be a Pay button. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :class:`telegram.Message`: On success, the sent Message is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = { + 'chat_id': chat_id, + 'title': title, + 'description': description, + 'payload': payload, + 'provider_token': provider_token, + 'currency': currency, + 'prices': [p.to_dict() for p in prices], + } + if max_tip_amount is not None: + data['max_tip_amount'] = max_tip_amount + if suggested_tip_amounts is not None: + data['suggested_tip_amounts'] = suggested_tip_amounts + if start_parameter is not None: + data['start_parameter'] = start_parameter + if provider_data is not None: + if isinstance(provider_data, str): + data['provider_data'] = provider_data + else: + data['provider_data'] = json.dumps(provider_data) + if photo_url is not None: + data['photo_url'] = photo_url + if photo_size is not None: + data['photo_size'] = photo_size + if photo_width is not None: + data['photo_width'] = photo_width + if photo_height is not None: + data['photo_height'] = photo_height + if need_name is not None: + data['need_name'] = need_name + if need_phone_number is not None: + data['need_phone_number'] = need_phone_number + if need_email is not None: + data['need_email'] = need_email + if need_shipping_address is not None: + data['need_shipping_address'] = need_shipping_address + if is_flexible is not None: + data['is_flexible'] = is_flexible + if send_phone_number_to_provider is not None: + data['send_phone_number_to_provider'] = send_phone_number_to_provider + if send_email_to_provider is not None: + data['send_email_to_provider'] = send_email_to_provider + + return self._message( # type: ignore[return-value] + 'sendInvoice', + data, + timeout=timeout, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + allow_sending_without_reply=allow_sending_without_reply, + api_kwargs=api_kwargs, + ) + + @log + def answer_shipping_query( # pylint: disable=C0103 + self, + shipping_query_id: str, + ok: bool, + shipping_options: List[ShippingOption] = None, + error_message: str = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> bool: + """ + If you sent an invoice requesting a shipping address and the parameter ``is_flexible`` was + specified, the Bot API will send an :class:`telegram.Update` with a + :attr:`Update.shipping_query` field to the bot. Use this method to reply to shipping + queries. + + Args: + shipping_query_id (:obj:`str`): Unique identifier for the query to be answered. + ok (:obj:`bool`): Specify :obj:`True` if delivery to the specified address is possible + and :obj:`False` if there are any problems (for example, if delivery to the + specified address is not possible). + shipping_options (List[:class:`telegram.ShippingOption`]), optional]: Required if ok is + :obj:`True`. A JSON-serialized array of available shipping options. + error_message (:obj:`str`, optional): Required if ok is :obj:`False`. Error message in + human readable form that explains why it is impossible to complete the order (e.g. + "Sorry, delivery to your desired address is unavailable"). Telegram will display + this message to the user. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + ok = bool(ok) + + if ok and (shipping_options is None or error_message is not None): + raise TelegramError( + 'answerShippingQuery: If ok is True, shipping_options ' + 'should not be empty and there should not be error_message' + ) + + if not ok and (shipping_options is not None or error_message is None): + raise TelegramError( + 'answerShippingQuery: If ok is False, error_message ' + 'should not be empty and there should not be shipping_options' + ) + + data: JSONDict = {'shipping_query_id': shipping_query_id, 'ok': ok} + + if ok: + if not shipping_options: + # not using an assert statement directly here since they are removed in + # the optimized bytecode + raise AssertionError + data['shipping_options'] = [option.to_dict() for option in shipping_options] + if error_message is not None: + data['error_message'] = error_message + + result = self._post('answerShippingQuery', data, timeout=timeout, api_kwargs=api_kwargs) + + return result # type: ignore[return-value] + + @log + def answer_pre_checkout_query( # pylint: disable=C0103 + self, + pre_checkout_query_id: str, + ok: bool, + error_message: str = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> bool: + """ + Once the user has confirmed their payment and shipping details, the Bot API sends the final + confirmation in the form of an :class:`telegram.Update` with the field + :attr:`Update.pre_checkout_query`. Use this method to respond to such pre-checkout queries. + + Note: + The Bot API must receive an answer within 10 seconds after the pre-checkout + query was sent. + + Args: + pre_checkout_query_id (:obj:`str`): Unique identifier for the query to be answered. + ok (:obj:`bool`): Specify :obj:`True` if everything is alright + (goods are available, etc.) and the bot is ready to proceed with the order. Use + :obj:`False` if there are any problems. + error_message (:obj:`str`, optional): Required if ok is :obj:`False`. Error message + in human readable form that explains the reason for failure to proceed with + the checkout (e.g. "Sorry, somebody just bought the last of our amazing black + T-shirts while you were busy filling out your payment details. Please choose a + different color or garment!"). Telegram will display this message to the user. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + ok = bool(ok) + + if not (ok ^ (error_message is not None)): # pylint: disable=C0325 + raise TelegramError( + 'answerPreCheckoutQuery: If ok is True, there should ' + 'not be error_message; if ok is False, error_message ' + 'should not be empty' + ) + + data: JSONDict = {'pre_checkout_query_id': pre_checkout_query_id, 'ok': ok} + + if error_message is not None: + data['error_message'] = error_message + + result = self._post('answerPreCheckoutQuery', data, timeout=timeout, api_kwargs=api_kwargs) + + return result # type: ignore[return-value] + + @log + def restrict_chat_member( + self, + chat_id: Union[str, int], + user_id: Union[str, int], + permissions: ChatPermissions, + until_date: Union[int, datetime] = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> bool: + """ + Use this method to restrict a user in a supergroup. The bot must be an administrator in + the supergroup for this to work and must have the appropriate admin rights. Pass + :obj:`True` for all boolean parameters to lift restrictions from a user. + + Note: + Since Bot API 4.4, :meth:`restrict_chat_member` takes the new user permissions in a + single argument of type :class:`telegram.ChatPermissions`. The old way of passing + parameters will not keep working forever. + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target supergroup (in the format @supergroupusername). + user_id (:obj:`int`): Unique identifier of the target user. + until_date (:obj:`int` | :obj:`datetime.datetime`, optional): Date when restrictions + will be lifted for the user, unix time. If user is restricted for more than 366 + days or less than 30 seconds from the current time, they are considered to be + restricted forever. + For timezone naive :obj:`datetime.datetime` objects, the default timezone of the + bot will be used. + permissions (:class:`telegram.ChatPermissions`): A JSON-serialized object for new user + permissions. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + + Raises: + :class:`telegram.error.TelegramError` + """ + data: JSONDict = { + 'chat_id': chat_id, + 'user_id': user_id, + 'permissions': permissions.to_dict(), + } + + if until_date is not None: + if isinstance(until_date, datetime): + until_date = to_timestamp( + until_date, tzinfo=self.defaults.tzinfo if self.defaults else None + ) + data['until_date'] = until_date + + result = self._post('restrictChatMember', data, timeout=timeout, api_kwargs=api_kwargs) + + return result # type: ignore[return-value] + + @log + def promote_chat_member( + self, + chat_id: Union[str, int], + user_id: Union[str, int], + can_change_info: bool = None, + can_post_messages: bool = None, + can_edit_messages: bool = None, + can_delete_messages: bool = None, + can_invite_users: bool = None, + can_restrict_members: bool = None, + can_pin_messages: bool = None, + can_promote_members: bool = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + is_anonymous: bool = None, + can_manage_chat: bool = None, + can_manage_voice_chats: bool = None, + ) -> bool: + """ + Use this method to promote or demote a user in a supergroup or a channel. The bot must be + an administrator in the chat for this to work and must have the appropriate admin rights. + Pass :obj:`False` for all boolean parameters to demote a user. + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target channel (in the format ``@channelusername``). + user_id (:obj:`int`): Unique identifier of the target user. + is_anonymous (:obj:`bool`, optional): Pass :obj:`True`, if the administrator's presence + in the chat is hidden. + can_manage_chat (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can + access the chat event log, chat statistics, message statistics in channels, see + channel members, see anonymous administrators in supergroups and ignore slow mode. + Implied by any other administrator privilege. + + .. versionadded:: 13.4 + + can_manage_voice_chats (:obj:`bool`, optional): Pass :obj:`True`, if the administrator + can manage voice chats. + + .. versionadded:: 13.4 + + can_change_info (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can + change chat title, photo and other settings. + can_post_messages (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can + create channel posts, channels only. + can_edit_messages (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can + edit messages of other users and can pin messages, channels only. + can_delete_messages (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can + delete messages of other users. + can_invite_users (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can + invite new users to the chat. + can_restrict_members (:obj:`bool`, optional): Pass :obj:`True`, if the administrator + can restrict, ban or unban chat members. + can_pin_messages (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can + pin messages, supergroups only. + can_promote_members (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can + add new administrators with a subset of his own privileges or demote administrators + that he has promoted, directly or indirectly (promoted by administrators that were + appointed by him). + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = {'chat_id': chat_id, 'user_id': user_id} + + if is_anonymous is not None: + data['is_anonymous'] = is_anonymous + if can_change_info is not None: + data['can_change_info'] = can_change_info + if can_post_messages is not None: + data['can_post_messages'] = can_post_messages + if can_edit_messages is not None: + data['can_edit_messages'] = can_edit_messages + if can_delete_messages is not None: + data['can_delete_messages'] = can_delete_messages + if can_invite_users is not None: + data['can_invite_users'] = can_invite_users + if can_restrict_members is not None: + data['can_restrict_members'] = can_restrict_members + if can_pin_messages is not None: + data['can_pin_messages'] = can_pin_messages + if can_promote_members is not None: + data['can_promote_members'] = can_promote_members + if can_manage_chat is not None: + data['can_manage_chat'] = can_manage_chat + if can_manage_voice_chats is not None: + data['can_manage_voice_chats'] = can_manage_voice_chats + + result = self._post('promoteChatMember', data, timeout=timeout, api_kwargs=api_kwargs) + + return result # type: ignore[return-value] + + @log + def set_chat_permissions( + self, + chat_id: Union[str, int], + permissions: ChatPermissions, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> bool: + """ + Use this method to set default chat permissions for all members. The bot must be an + administrator in the group or a supergroup for this to work and must have the + :attr:`telegram.ChatMember.can_restrict_members` admin rights. + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username of + the target supergroup (in the format `@supergroupusername`). + permissions (:class:`telegram.ChatPermissions`): New default chat permissions. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = {'chat_id': chat_id, 'permissions': permissions.to_dict()} + + result = self._post('setChatPermissions', data, timeout=timeout, api_kwargs=api_kwargs) + + return result # type: ignore[return-value] + + @log + def set_chat_administrator_custom_title( + self, + chat_id: Union[int, str], + user_id: Union[int, str], + custom_title: str, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> bool: + """ + Use this method to set a custom title for administrators promoted by the bot in a + supergroup. The bot must be an administrator for this to work. + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username of + the target supergroup (in the format `@supergroupusername`). + user_id (:obj:`int`): Unique identifier of the target administrator. + custom_title (:obj:`str`): New custom title for the administrator; 0-16 characters, + emoji are not allowed. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = {'chat_id': chat_id, 'user_id': user_id, 'custom_title': custom_title} + + result = self._post( + 'setChatAdministratorCustomTitle', data, timeout=timeout, api_kwargs=api_kwargs + ) + + return result # type: ignore[return-value] + + @log + def export_chat_invite_link( + self, + chat_id: Union[str, int], + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> str: + """ + Use this method to generate a new primary invite link for a chat; any previously generated + link is revoked. The bot must be an administrator in the chat for this to work and must + have the appropriate admin rights. + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target channel (in the format ``@channelusername``). + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Note: + Each administrator in a chat generates their own invite links. Bots can't use invite + links generated by other administrators. If you want your bot to work with invite + links, it will need to generate its own link using :meth:`export_chat_invite_link` or + by calling the :meth:`get_chat` method. If your bot needs to generate a new primary + invite link replacing its previous one, use :attr:`export_chat_invite_link` again. + + Returns: + :obj:`str`: New invite link on success. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = {'chat_id': chat_id} + + result = self._post('exportChatInviteLink', data, timeout=timeout, api_kwargs=api_kwargs) + + return result # type: ignore[return-value] + + @log + def create_chat_invite_link( + self, + chat_id: Union[str, int], + expire_date: Union[int, datetime] = None, + member_limit: int = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> ChatInviteLink: + """ + Use this method to create an additional invite link for a chat. The bot must be an + administrator in the chat for this to work and must have the appropriate admin rights. + The link can be revoked using the method :meth:`revoke_chat_invite_link`. + + .. versionadded:: 13.4 + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target channel (in the format ``@channelusername``). + expire_date (:obj:`int` | :obj:`datetime.datetime`, optional): Date when the link will + expire. Integer input will be interpreted as Unix timestamp. + For timezone naive :obj:`datetime.datetime` objects, the default timezone of the + bot will be used. + member_limit (:obj:`int`, optional): Maximum number of users that can be members of + the chat simultaneously after joining the chat via this invite link; 1-99999. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :class:`telegram.ChatInviteLink` + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = { + 'chat_id': chat_id, + } + + if expire_date is not None: + if isinstance(expire_date, datetime): + expire_date = to_timestamp( + expire_date, tzinfo=self.defaults.tzinfo if self.defaults else None + ) + data['expire_date'] = expire_date + + if member_limit is not None: + data['member_limit'] = member_limit + + result = self._post('createChatInviteLink', data, timeout=timeout, api_kwargs=api_kwargs) + + return ChatInviteLink.de_json(result, self) # type: ignore[return-value, arg-type] + + @log + def edit_chat_invite_link( + self, + chat_id: Union[str, int], + invite_link: str, + expire_date: Union[int, datetime] = None, + member_limit: int = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> ChatInviteLink: + """ + Use this method to edit a non-primary invite link created by the bot. The bot must be an + administrator in the chat for this to work and must have the appropriate admin rights. + + .. versionadded:: 13.4 + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target channel (in the format ``@channelusername``). + invite_link (:obj:`str`): The invite link to edit. + expire_date (:obj:`int` | :obj:`datetime.datetime`, optional): Date when the link will + expire. + For timezone naive :obj:`datetime.datetime` objects, the default timezone of the + bot will be used. + member_limit (:obj:`int`, optional): Maximum number of users that can be members of + the chat simultaneously after joining the chat via this invite link; 1-99999. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :class:`telegram.ChatInviteLink` + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = {'chat_id': chat_id, 'invite_link': invite_link} + + if expire_date is not None: + if isinstance(expire_date, datetime): + expire_date = to_timestamp( + expire_date, tzinfo=self.defaults.tzinfo if self.defaults else None + ) + data['expire_date'] = expire_date + + if member_limit is not None: + data['member_limit'] = member_limit + + result = self._post('editChatInviteLink', data, timeout=timeout, api_kwargs=api_kwargs) + + return ChatInviteLink.de_json(result, self) # type: ignore[return-value, arg-type] + + @log + def revoke_chat_invite_link( + self, + chat_id: Union[str, int], + invite_link: str, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> ChatInviteLink: + """ + Use this method to revoke an invite link created by the bot. If the primary link is + revoked, a new link is automatically generated. The bot must be an administrator in the + chat for this to work and must have the appropriate admin rights. + + .. versionadded:: 13.4 + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target channel (in the format ``@channelusername``). + invite_link (:obj:`str`): The invite link to edit. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :class:`telegram.ChatInviteLink` + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = {'chat_id': chat_id, 'invite_link': invite_link} + + result = self._post('revokeChatInviteLink', data, timeout=timeout, api_kwargs=api_kwargs) + + return ChatInviteLink.de_json(result, self) # type: ignore[return-value, arg-type] + + @log + def set_chat_photo( + self, + chat_id: Union[str, int], + photo: FileInput, + timeout: DVInput[float] = DEFAULT_20, + api_kwargs: JSONDict = None, + ) -> bool: + """Use this method to set a new profile photo for the chat. + + Photos can't be changed for private chats. The bot must be an administrator in the chat + for this to work and must have the appropriate admin rights. + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target channel (in the format ``@channelusername``). + photo (`filelike object` | :obj:`bytes` | :class:`pathlib.Path`): New chat photo. + + .. versionchanged:: 13.2 + Accept :obj:`bytes` as input. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = {'chat_id': chat_id, 'photo': parse_file_input(photo)} + + result = self._post('setChatPhoto', data, timeout=timeout, api_kwargs=api_kwargs) + + return result # type: ignore[return-value] + + @log + def delete_chat_photo( + self, + chat_id: Union[str, int], + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> bool: + """ + Use this method to delete a chat photo. Photos can't be changed for private chats. The bot + must be an administrator in the chat for this to work and must have the appropriate admin + rights. + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target channel (in the format ``@channelusername``). + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = {'chat_id': chat_id} + + result = self._post('deleteChatPhoto', data, timeout=timeout, api_kwargs=api_kwargs) + + return result # type: ignore[return-value] + + @log + def set_chat_title( + self, + chat_id: Union[str, int], + title: str, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> bool: + """ + Use this method to change the title of a chat. Titles can't be changed for private chats. + The bot must be an administrator in the chat for this to work and must have the appropriate + admin rights. + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target channel (in the format ``@channelusername``). + title (:obj:`str`): New chat title, 1-255 characters. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = {'chat_id': chat_id, 'title': title} + + result = self._post('setChatTitle', data, timeout=timeout, api_kwargs=api_kwargs) + + return result # type: ignore[return-value] + + @log + def set_chat_description( + self, + chat_id: Union[str, int], + description: str, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> bool: + """ + Use this method to change the description of a group, a supergroup or a channel. The bot + must be an administrator in the chat for this to work and must have the appropriate admin + rights. + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target channel (in the format ``@channelusername``). + description (:obj:`str`): New chat description, 0-255 characters. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = {'chat_id': chat_id, 'description': description} + + result = self._post('setChatDescription', data, timeout=timeout, api_kwargs=api_kwargs) + + return result # type: ignore[return-value] + + @log + def pin_chat_message( + self, + chat_id: Union[str, int], + message_id: int, + disable_notification: ODVInput[bool] = DEFAULT_NONE, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> bool: + """ + Use this method to add a message to the list of pinned messages in a chat. If the + chat is not a private chat, the bot must be an administrator in the chat for this to work + and must have the :attr:`telegram.ChatMember.can_pin_messages` admin right in a supergroup + or :attr:`telegram.ChatMember.can_edit_messages` admin right in a channel. + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target channel (in the format ``@channelusername``). + message_id (:obj:`int`): Identifier of a message to pin. + disable_notification (:obj:`bool`, optional): Pass :obj:`True`, if it is not necessary + to send a notification to all chat members about the new pinned message. + Notifications are always disabled in channels and private chats. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = { + 'chat_id': chat_id, + 'message_id': message_id, + 'disable_notification': disable_notification, + } + + return self._post( # type: ignore[return-value] + 'pinChatMessage', data, timeout=timeout, api_kwargs=api_kwargs + ) + + @log + def unpin_chat_message( + self, + chat_id: Union[str, int], + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + message_id: int = None, + ) -> bool: + """ + Use this method to remove a message from the list of pinned messages in a chat. If the + chat is not a private chat, the bot must be an administrator in the chat for this to work + and must have the :attr:`telegram.ChatMember.can_pin_messages` admin right in a + supergroup or :attr:`telegram.ChatMember.can_edit_messages` admin right in a channel. + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target channel (in the format ``@channelusername``). + message_id (:obj:`int`, optional): Identifier of a message to unpin. If not specified, + the most recent pinned message (by sending date) will be unpinned. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = {'chat_id': chat_id} + + if message_id is not None: + data['message_id'] = message_id + + return self._post( # type: ignore[return-value] + 'unpinChatMessage', data, timeout=timeout, api_kwargs=api_kwargs + ) + + @log + def unpin_all_chat_messages( + self, + chat_id: Union[str, int], + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> bool: + """ + Use this method to clear the list of pinned messages in a chat. If the + chat is not a private chat, the bot must be an administrator in the chat for this + to work and must have the :attr:`telegram.ChatMember.can_pin_messages` admin right in a + supergroup or :attr:`telegram.ChatMember.can_edit_messages` admin right in a channel. + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target channel (in the format ``@channelusername``). + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = {'chat_id': chat_id} + + return self._post( # type: ignore[return-value] + 'unpinAllChatMessages', data, timeout=timeout, api_kwargs=api_kwargs + ) + + @log + def get_sticker_set( + self, + name: str, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> StickerSet: + """Use this method to get a sticker set. + + Args: + name (:obj:`str`): Name of the sticker set. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during + creation of the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :class:`telegram.StickerSet` + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = {'name': name} + + result = self._post('getStickerSet', data, timeout=timeout, api_kwargs=api_kwargs) + + return StickerSet.de_json(result, self) # type: ignore[return-value, arg-type] + + @log + def upload_sticker_file( + self, + user_id: Union[str, int], + png_sticker: FileInput, + timeout: DVInput[float] = DEFAULT_20, + api_kwargs: JSONDict = None, + ) -> File: + """ + Use this method to upload a .png file with a sticker for later use in + :meth:`create_new_sticker_set` and :meth:`add_sticker_to_set` methods (can be used multiple + times). + + Note: + The png_sticker argument can be either a file_id, an URL or a file from disk + ``open(filename, 'rb')`` + + Args: + user_id (:obj:`int`): User identifier of sticker file owner. + png_sticker (:obj:`str` | `filelike object` | :obj:`bytes` | :class:`pathlib.Path`): + Png image with the sticker, + must be up to 512 kilobytes in size, dimensions must not exceed 512px, + and either width or height must be exactly 512px. + + .. versionchanged:: 13.2 + Accept :obj:`bytes` as input. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during + creation of the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :class:`telegram.File`: On success, the uploaded File is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = {'user_id': user_id, 'png_sticker': parse_file_input(png_sticker)} + + result = self._post('uploadStickerFile', data, timeout=timeout, api_kwargs=api_kwargs) + + return File.de_json(result, self) # type: ignore[return-value, arg-type] + + @log + def create_new_sticker_set( + self, + user_id: Union[str, int], + name: str, + title: str, + emojis: str, + png_sticker: FileInput = None, + contains_masks: bool = None, + mask_position: MaskPosition = None, + timeout: DVInput[float] = DEFAULT_20, + tgs_sticker: FileInput = None, + api_kwargs: JSONDict = None, + ) -> bool: + """ + Use this method to create new sticker set owned by a user. + The bot will be able to edit the created sticker set. + You must use exactly one of the fields ``png_sticker`` or ``tgs_sticker``. + + Warning: + As of API 4.7 ``png_sticker`` is an optional argument and therefore the order of the + arguments had to be changed. Use keyword arguments to make sure that the arguments are + passed correctly. + + Note: + The png_sticker and tgs_sticker argument can be either a file_id, an URL or a file from + disk ``open(filename, 'rb')`` + + Args: + user_id (:obj:`int`): User identifier of created sticker set owner. + name (:obj:`str`): Short name of sticker set, to be used in t.me/addstickers/ URLs + (e.g., animals). Can contain only english letters, digits and underscores. + Must begin with a letter, can't contain consecutive underscores and + must end in "_by_<bot username>". <bot_username> is case insensitive. + 1-64 characters. + title (:obj:`str`): Sticker set title, 1-64 characters. + png_sticker (:obj:`str` | `filelike object` | :obj:`bytes` | :class:`pathlib.Path`, \ + optional): Png image with the sticker, + must be up to 512 kilobytes in size, dimensions must not exceed 512px, + and either width or height must be exactly 512px. Pass a file_id as a String to + send a file that already exists on the Telegram servers, pass an HTTP URL as a + String for Telegram to get a file from the Internet, or upload a new one + using multipart/form-data. + + .. versionchanged:: 13.2 + Accept :obj:`bytes` as input. + tgs_sticker (:obj:`str` | `filelike object` | :obj:`bytes` | :class:`pathlib.Path`, \ + optional): TGS animation with the sticker, + uploaded using multipart/form-data. See + https://core.telegram.org/animated_stickers#technical-requirements for technical + requirements. + + .. versionchanged:: 13.2 + Accept :obj:`bytes` as input. + emojis (:obj:`str`): One or more emoji corresponding to the sticker. + contains_masks (:obj:`bool`, optional): Pass :obj:`True`, if a set of mask stickers + should be created. + mask_position (:class:`telegram.MaskPosition`, optional): Position where the mask + should be placed on faces. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during + creation of the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = {'user_id': user_id, 'name': name, 'title': title, 'emojis': emojis} + + if png_sticker is not None: + data['png_sticker'] = parse_file_input(png_sticker) + if tgs_sticker is not None: + data['tgs_sticker'] = parse_file_input(tgs_sticker) + if contains_masks is not None: + data['contains_masks'] = contains_masks + if mask_position is not None: + # We need to_json() instead of to_dict() here, because we're sending a media + # message here, which isn't json dumped by utils.request + data['mask_position'] = mask_position.to_json() + + result = self._post('createNewStickerSet', data, timeout=timeout, api_kwargs=api_kwargs) + + return result # type: ignore[return-value] + + @log + def add_sticker_to_set( + self, + user_id: Union[str, int], + name: str, + emojis: str, + png_sticker: FileInput = None, + mask_position: MaskPosition = None, + timeout: DVInput[float] = DEFAULT_20, + tgs_sticker: FileInput = None, + api_kwargs: JSONDict = None, + ) -> bool: + """ + Use this method to add a new sticker to a set created by the bot. + You must use exactly one of the fields ``png_sticker`` or ``tgs_sticker``. Animated + stickers can be added to animated sticker sets and only to them. Animated sticker sets can + have up to 50 stickers. Static sticker sets can have up to 120 stickers. + + Warning: + As of API 4.7 ``png_sticker`` is an optional argument and therefore the order of the + arguments had to be changed. Use keyword arguments to make sure that the arguments are + passed correctly. + + Note: + The png_sticker and tgs_sticker argument can be either a file_id, an URL or a file from + disk ``open(filename, 'rb')`` + + Args: + user_id (:obj:`int`): User identifier of created sticker set owner. + + name (:obj:`str`): Sticker set name. + png_sticker (:obj:`str` | `filelike object` | :obj:`bytes` | :class:`pathlib.Path`, \ + optional): PNG image with the sticker, + must be up to 512 kilobytes in size, dimensions must not exceed 512px, + and either width or height must be exactly 512px. Pass a file_id as a String to + send a file that already exists on the Telegram servers, pass an HTTP URL as a + String for Telegram to get a file from the Internet, or upload a new one + using multipart/form-data. + + .. versionchanged:: 13.2 + Accept :obj:`bytes` as input. + tgs_sticker (:obj:`str` | `filelike object` | :obj:`bytes` | :class:`pathlib.Path`, \ + optional): TGS animation with the sticker, + uploaded using multipart/form-data. See + https://core.telegram.org/animated_stickers#technical-requirements for technical + requirements. + + .. versionchanged:: 13.2 + Accept :obj:`bytes` as input. + emojis (:obj:`str`): One or more emoji corresponding to the sticker. + mask_position (:class:`telegram.MaskPosition`, optional): Position where the mask + should be placed on faces. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during + creation of the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = {'user_id': user_id, 'name': name, 'emojis': emojis} + + if png_sticker is not None: + data['png_sticker'] = parse_file_input(png_sticker) + if tgs_sticker is not None: + data['tgs_sticker'] = parse_file_input(tgs_sticker) + if mask_position is not None: + # We need to_json() instead of to_dict() here, because we're sending a media + # message here, which isn't json dumped by utils.request + data['mask_position'] = mask_position.to_json() + + result = self._post('addStickerToSet', data, timeout=timeout, api_kwargs=api_kwargs) + + return result # type: ignore[return-value] + + @log + def set_sticker_position_in_set( + self, + sticker: str, + position: int, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> bool: + """Use this method to move a sticker in a set created by the bot to a specific position. + + Args: + sticker (:obj:`str`): File identifier of the sticker. + position (:obj:`int`): New sticker position in the set, zero-based. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during + creation of the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = {'sticker': sticker, 'position': position} + + result = self._post( + 'setStickerPositionInSet', data, timeout=timeout, api_kwargs=api_kwargs + ) + + return result # type: ignore[return-value] + + @log + def delete_sticker_from_set( + self, + sticker: str, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> bool: + """Use this method to delete a sticker from a set created by the bot. + + Args: + sticker (:obj:`str`): File identifier of the sticker. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during + creation of the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = {'sticker': sticker} + + result = self._post('deleteStickerFromSet', data, timeout=timeout, api_kwargs=api_kwargs) + + return result # type: ignore[return-value] + + @log + def set_sticker_set_thumb( + self, + name: str, + user_id: Union[str, int], + thumb: FileInput = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> bool: + """Use this method to set the thumbnail of a sticker set. Animated thumbnails can be set + for animated sticker sets only. + + Note: + The thumb can be either a file_id, an URL or a file from disk ``open(filename, 'rb')`` + + Args: + name (:obj:`str`): Sticker set name + user_id (:obj:`int`): User identifier of created sticker set owner. + thumb (:obj:`str` | `filelike object` | :obj:`bytes` | :class:`pathlib.Path`, \ + optional): A PNG image with the thumbnail, must + be up to 128 kilobytes in size and have width and height exactly 100px, or a TGS + animation with the thumbnail up to 32 kilobytes in size; see + https://core.telegram.org/animated_stickers#technical-requirements for animated + sticker technical requirements. Pass a file_id as a String to send a file that + already exists on the Telegram servers, pass an HTTP URL as a String for Telegram + to get a file from the Internet, or upload a new one using multipart/form-data. + Animated sticker set thumbnail can't be uploaded via HTTP URL. + + .. versionchanged:: 13.2 + Accept :obj:`bytes` as input. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during + creation of the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = {'name': name, 'user_id': user_id} + + if thumb is not None: + data['thumb'] = parse_file_input(thumb) + + result = self._post('setStickerSetThumb', data, timeout=timeout, api_kwargs=api_kwargs) + + return result # type: ignore[return-value] + + @log + def set_passport_data_errors( + self, + user_id: Union[str, int], + errors: List[PassportElementError], + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> bool: + """ + Informs a user that some of the Telegram Passport elements they provided contains errors. + The user will not be able to re-submit their Passport to you until the errors are fixed + (the contents of the field for which you returned the error must change). + + Use this if the data submitted by the user doesn't satisfy the standards your service + requires for any reason. For example, if a birthday date seems invalid, a submitted + document is blurry, a scan shows evidence of tampering, etc. Supply some details in the + error message to make sure the user knows how to correct the issues. + + Args: + user_id (:obj:`int`): User identifier + errors (List[:class:`PassportElementError`]): A JSON-serialized array describing the + errors. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during + creation of the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = {'user_id': user_id, 'errors': [error.to_dict() for error in errors]} + + result = self._post('setPassportDataErrors', data, timeout=timeout, api_kwargs=api_kwargs) + + return result # type: ignore[return-value] + + @log + def send_poll( + self, + chat_id: Union[int, str], + question: str, + options: List[str], + is_anonymous: bool = True, + type: str = Poll.REGULAR, # pylint: disable=W0622 + allows_multiple_answers: bool = False, + correct_option_id: int = None, + is_closed: bool = None, + disable_notification: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: ReplyMarkup = None, + timeout: ODVInput[float] = DEFAULT_NONE, + explanation: str = None, + explanation_parse_mode: ODVInput[str] = DEFAULT_NONE, + open_period: int = None, + close_date: Union[int, datetime] = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + explanation_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + ) -> Message: + """ + Use this method to send a native poll. + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target channel (in the format ``@channelusername``). + question (:obj:`str`): Poll question, 1-300 characters. + options (List[:obj:`str`]): List of answer options, 2-10 strings 1-100 characters each. + is_anonymous (:obj:`bool`, optional): :obj:`True`, if the poll needs to be anonymous, + defaults to :obj:`True`. + type (:obj:`str`, optional): Poll type, :attr:`telegram.Poll.QUIZ` or + :attr:`telegram.Poll.REGULAR`, defaults to :attr:`telegram.Poll.REGULAR`. + allows_multiple_answers (:obj:`bool`, optional): :obj:`True`, if the poll allows + multiple answers, ignored for polls in quiz mode, defaults to :obj:`False`. + correct_option_id (:obj:`int`, optional): 0-based identifier of the correct answer + option, required for polls in quiz mode. + explanation (:obj:`str`, optional): Text that is shown when a user chooses an incorrect + answer or taps on the lamp icon in a quiz-style poll, 0-200 characters with at most + 2 line feeds after entities parsing. + explanation_parse_mode (:obj:`str`, optional): Mode for parsing entities in the + explanation. See the constants in :class:`telegram.ParseMode` for the available + modes. + explanation_entities (List[:class:`telegram.MessageEntity`], optional): List of special + entities that appear in message text, which can be specified instead of + :attr:`parse_mode`. + open_period (:obj:`int`, optional): Amount of time in seconds the poll will be active + after creation, 5-600. Can't be used together with :attr:`close_date`. + close_date (:obj:`int` | :obj:`datetime.datetime`, optional): Point in time (Unix + timestamp) when the poll will be automatically closed. Must be at least 5 and no + more than 600 seconds in the future. Can't be used together with + :attr:`open_period`. + For timezone naive :obj:`datetime.datetime` objects, the default timezone of the + bot will be used. + is_closed (:obj:`bool`, optional): Pass :obj:`True`, if the poll needs to be + immediately closed. This can be useful for poll preview. + disable_notification (:obj:`bool`, optional): Sends the message silently. Users will + receive a notification with no sound. + reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the + original message. + allow_sending_without_reply (:obj:`bool`, optional): Pass :obj:`True`, if the message + should be sent even if the specified replied-to message is not found. + reply_markup (:class:`telegram.ReplyMarkup`, optional): Additional interface options. A + JSON-serialized object for an inline keyboard, custom reply keyboard, instructions + to remove reply keyboard or to force a reply from the user. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :class:`telegram.Message`: On success, the sent Message is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = { + 'chat_id': chat_id, + 'question': question, + 'options': options, + 'explanation_parse_mode': explanation_parse_mode, + } + + if not is_anonymous: + data['is_anonymous'] = is_anonymous + if type: + data['type'] = type + if allows_multiple_answers: + data['allows_multiple_answers'] = allows_multiple_answers + if correct_option_id is not None: + data['correct_option_id'] = correct_option_id + if is_closed: + data['is_closed'] = is_closed + if explanation: + data['explanation'] = explanation + if explanation_entities: + data['explanation_entities'] = [me.to_dict() for me in explanation_entities] + if open_period: + data['open_period'] = open_period + if close_date: + if isinstance(close_date, datetime): + close_date = to_timestamp( + close_date, tzinfo=self.defaults.tzinfo if self.defaults else None + ) + data['close_date'] = close_date + + return self._message( # type: ignore[return-value] + 'sendPoll', + data, + timeout=timeout, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + allow_sending_without_reply=allow_sending_without_reply, + api_kwargs=api_kwargs, + ) + + @log + def stop_poll( + self, + chat_id: Union[int, str], + message_id: int, + reply_markup: InlineKeyboardMarkup = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> Poll: + """ + Use this method to stop a poll which was sent by the bot. + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target channel (in the format ``@channelusername``). + message_id (:obj:`int`): Identifier of the original message with the poll. + reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): A JSON-serialized + object for a new message inline keyboard. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :class:`telegram.Poll`: On success, the stopped Poll with the final results is + returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = {'chat_id': chat_id, 'message_id': message_id} + + if reply_markup: + if isinstance(reply_markup, ReplyMarkup): + # We need to_json() instead of to_dict() here, because reply_markups may be + # attached to media messages, which aren't json dumped by utils.request + data['reply_markup'] = reply_markup.to_json() + else: + data['reply_markup'] = reply_markup + + result = self._post('stopPoll', data, timeout=timeout, api_kwargs=api_kwargs) + + return Poll.de_json(result, self) # type: ignore[return-value, arg-type] + + @log + def send_dice( + self, + chat_id: Union[int, str], + disable_notification: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: ReplyMarkup = None, + timeout: ODVInput[float] = DEFAULT_NONE, + emoji: str = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + ) -> Message: + """ + Use this method to send an animated emoji that will display a random value. + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target channel (in the format ``@channelusername``). + emoji (:obj:`str`, optional): Emoji on which the dice throw animation is based. + Currently, must be one of “🎲”, “🎯”, “🏀”, “⚽”, "🎳", or “🎰”. Dice can have + values 1-6 for “🎲”, “🎯” and "🎳", values 1-5 for “🏀” and “⚽”, and values 1-64 + for “🎰”. Defaults to “🎲”. + + .. versionchanged:: 13.4 + Added the "🎳" emoji. + disable_notification (:obj:`bool`, optional): Sends the message silently. Users will + receive a notification with no sound. + reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the + original message. + allow_sending_without_reply (:obj:`bool`, optional): Pass :obj:`True`, if the message + should be sent even if the specified replied-to message is not found. + reply_markup (:class:`telegram.ReplyMarkup`, optional): Additional interface options. A + JSON-serialized object for an inline keyboard, custom reply keyboard, instructions + to remove reply keyboard or to force a reply from the user. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :class:`telegram.Message`: On success, the sent Message is returned. + + Raises: + :class:`telegram.error.TelegramError` + + """ + data: JSONDict = { + 'chat_id': chat_id, + } + + if emoji: + data['emoji'] = emoji + + return self._message( # type: ignore[return-value] + 'sendDice', + data, + timeout=timeout, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + allow_sending_without_reply=allow_sending_without_reply, + api_kwargs=api_kwargs, + ) + + @log + def get_my_commands( + self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None + ) -> List[BotCommand]: + """ + Use this method to get the current list of the bot's commands. + + Args: + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + List[:class:`telegram.BotCommand]`: On success, the commands set for the bot + + Raises: + :class:`telegram.error.TelegramError` + + """ + result = self._post('getMyCommands', timeout=timeout, api_kwargs=api_kwargs) + + self._commands = BotCommand.de_list(result, self) # type: ignore[assignment,arg-type] + + return self._commands # type: ignore[return-value] + + @log + def set_my_commands( + self, + commands: List[Union[BotCommand, Tuple[str, str]]], + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> bool: + """ + Use this method to change the list of the bot's commands. + + Args: + commands (List[:class:`BotCommand` | (:obj:`str`, :obj:`str`)]): A JSON-serialized list + of bot commands to be set as the list of the bot's commands. At most 100 commands + can be specified. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :obj:`True`: On success + + Raises: + :class:`telegram.error.TelegramError` + + """ + cmds = [c if isinstance(c, BotCommand) else BotCommand(c[0], c[1]) for c in commands] + + data: JSONDict = {'commands': [c.to_dict() for c in cmds]} + + result = self._post('setMyCommands', data, timeout=timeout, api_kwargs=api_kwargs) + + # Set commands. No need to check for outcome. + # If request failed, we won't come this far + self._commands = cmds + + return result # type: ignore[return-value] + + @log + def log_out(self, timeout: ODVInput[float] = DEFAULT_NONE) -> bool: + """ + Use this method to log out from the cloud Bot API server before launching the bot locally. + You *must* log out the bot before running it locally, otherwise there is no guarantee that + the bot will receive updates. After a successful call, you can immediately log in on a + local server, but will not be able to log in back to the cloud Bot API server for 10 + minutes. + + Args: + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + + Returns: + :obj:`True`: On success + + Raises: + :class:`telegram.error.TelegramError` + + """ + return self._post('logOut', timeout=timeout) # type: ignore[return-value] + + @log + def close(self, timeout: ODVInput[float] = DEFAULT_NONE) -> bool: + """ + Use this method to close the bot instance before moving it from one local server to + another. You need to delete the webhook before calling this method to ensure that the bot + isn't launched again after server restart. The method will return error 429 in the first + 10 minutes after the bot is launched. + + Args: + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + + Returns: + :obj:`True`: On success + + Raises: + :class:`telegram.error.TelegramError` + + """ + return self._post('close', timeout=timeout) # type: ignore[return-value] + + @log + def copy_message( + self, + chat_id: Union[int, str], + from_chat_id: Union[str, int], + message_id: int, + caption: str = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + caption_entities: Union[Tuple['MessageEntity', ...], List['MessageEntity']] = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE, + reply_markup: ReplyMarkup = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> MessageId: + """ + Use this method to copy messages of any kind. Service messages and invoice messages can't + be copied. The method is analogous to the method :meth:`forward_message`, but the copied + message doesn't have a link to the original message. + + Args: + chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username + of the target channel (in the format ``@channelusername``). + from_chat_id (:obj:`int` | :obj:`str`): Unique identifier for the chat where the + original message was sent (or channel username in the format ``@channelusername``). + message_id (:obj:`int`): Message identifier in the chat specified in from_chat_id. + caption (:obj:`str`, optional): New caption for media, 0-1024 characters after + entities parsing. If not specified, the original caption is kept. + parse_mode (:obj:`str`, optional): Mode for parsing entities in the new caption. See + the constants in :class:`telegram.ParseMode` for the available modes. + caption_entities (:class:`telegram.utils.types.SLT[MessageEntity]`): List of special + entities that appear in the new caption, which can be specified instead of + parse_mode + disable_notification (:obj:`bool`, optional): Sends the message silently. Users will + receive a notification with no sound. + reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the + original message. + allow_sending_without_reply (:obj:`bool`, optional): Pass :obj:`True`, if the message + should be sent even if the specified replied-to message is not found. + reply_markup (:class:`telegram.ReplyMarkup`, optional): Additional interface options. + A JSON-serialized object for an inline keyboard, custom reply keyboard, + instructions to remove reply keyboard or to force a reply from the user. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the + Telegram API. + + Returns: + :class:`telegram.MessageId`: On success + + Raises: + :class:`telegram.error.TelegramError` + """ + data: JSONDict = { + 'chat_id': chat_id, + 'from_chat_id': from_chat_id, + 'message_id': message_id, + 'parse_mode': parse_mode, + 'disable_notification': disable_notification, + 'allow_sending_without_reply': allow_sending_without_reply, + } + if caption: + data['caption'] = caption + if caption_entities: + data['caption_entities'] = caption_entities + if reply_to_message_id: + data['reply_to_message_id'] = reply_to_message_id + if reply_markup: + if isinstance(reply_markup, ReplyMarkup): + # We need to_json() instead of to_dict() here, because reply_markups may be + # attached to media messages, which aren't json dumped by utils.request + data['reply_markup'] = reply_markup.to_json() + else: + data['reply_markup'] = reply_markup + + result = self._post('copyMessage', data, timeout=timeout, api_kwargs=api_kwargs) + return MessageId.de_json(result, self) # type: ignore[return-value, arg-type] + + def to_dict(self) -> JSONDict: + """See :meth:`telegram.TelegramObject.to_dict`.""" + data: JSONDict = {'id': self.id, 'username': self.username, 'first_name': self.first_name} + + if self.last_name: + data['last_name'] = self.last_name + + return data + + def __eq__(self, other: object) -> bool: + return self.bot == other + + def __hash__(self) -> int: + return hash(self.bot) + + # camelCase aliases + getMe = get_me + """Alias for :meth:`get_me`""" + sendMessage = send_message + """Alias for :meth:`send_message`""" + deleteMessage = delete_message + """Alias for :meth:`delete_message`""" + forwardMessage = forward_message + """Alias for :meth:`forward_message`""" + sendPhoto = send_photo + """Alias for :meth:`send_photo`""" + sendAudio = send_audio + """Alias for :meth:`send_audio`""" + sendDocument = send_document + """Alias for :meth:`send_document`""" + sendSticker = send_sticker + """Alias for :meth:`send_sticker`""" + sendVideo = send_video + """Alias for :meth:`send_video`""" + sendAnimation = send_animation + """Alias for :meth:`send_animation`""" + sendVoice = send_voice + """Alias for :meth:`send_voice`""" + sendVideoNote = send_video_note + """Alias for :meth:`send_video_note`""" + sendMediaGroup = send_media_group + """Alias for :meth:`send_media_group`""" + sendLocation = send_location + """Alias for :meth:`send_location`""" + editMessageLiveLocation = edit_message_live_location + """Alias for :meth:`edit_message_live_location`""" + stopMessageLiveLocation = stop_message_live_location + """Alias for :meth:`stop_message_live_location`""" + sendVenue = send_venue + """Alias for :meth:`send_venue`""" + sendContact = send_contact + """Alias for :meth:`send_contact`""" + sendGame = send_game + """Alias for :meth:`send_game`""" + sendChatAction = send_chat_action + """Alias for :meth:`send_chat_action`""" + answerInlineQuery = answer_inline_query + """Alias for :meth:`answer_inline_query`""" + getUserProfilePhotos = get_user_profile_photos + """Alias for :meth:`get_user_profile_photos`""" + getFile = get_file + """Alias for :meth:`get_file`""" + kickChatMember = kick_chat_member + """Alias for :meth:`kick_chat_member`""" + unbanChatMember = unban_chat_member + """Alias for :meth:`unban_chat_member`""" + answerCallbackQuery = answer_callback_query + """Alias for :meth:`answer_callback_query`""" + editMessageText = edit_message_text + """Alias for :meth:`edit_message_text`""" + editMessageCaption = edit_message_caption + """Alias for :meth:`edit_message_caption`""" + editMessageMedia = edit_message_media + """Alias for :meth:`edit_message_media`""" + editMessageReplyMarkup = edit_message_reply_markup + """Alias for :meth:`edit_message_reply_markup`""" + getUpdates = get_updates + """Alias for :meth:`get_updates`""" + setWebhook = set_webhook + """Alias for :meth:`set_webhook`""" + deleteWebhook = delete_webhook + """Alias for :meth:`delete_webhook`""" + leaveChat = leave_chat + """Alias for :meth:`leave_chat`""" + getChat = get_chat + """Alias for :meth:`get_chat`""" + getChatAdministrators = get_chat_administrators + """Alias for :meth:`get_chat_administrators`""" + getChatMember = get_chat_member + """Alias for :meth:`get_chat_member`""" + setChatStickerSet = set_chat_sticker_set + """Alias for :meth:`set_chat_sticker_set`""" + deleteChatStickerSet = delete_chat_sticker_set + """Alias for :meth:`delete_chat_sticker_set`""" + getChatMembersCount = get_chat_members_count + """Alias for :meth:`get_chat_members_count`""" + getWebhookInfo = get_webhook_info + """Alias for :meth:`get_webhook_info`""" + setGameScore = set_game_score + """Alias for :meth:`set_game_score`""" + getGameHighScores = get_game_high_scores + """Alias for :meth:`get_game_high_scores`""" + sendInvoice = send_invoice + """Alias for :meth:`send_invoice`""" + answerShippingQuery = answer_shipping_query + """Alias for :meth:`answer_shipping_query`""" + answerPreCheckoutQuery = answer_pre_checkout_query + """Alias for :meth:`answer_pre_checkout_query`""" + restrictChatMember = restrict_chat_member + """Alias for :meth:`restrict_chat_member`""" + promoteChatMember = promote_chat_member + """Alias for :meth:`promote_chat_member`""" + setChatPermissions = set_chat_permissions + """Alias for :meth:`set_chat_permissions`""" + setChatAdministratorCustomTitle = set_chat_administrator_custom_title + """Alias for :meth:`set_chat_administrator_custom_title`""" + exportChatInviteLink = export_chat_invite_link + """Alias for :meth:`export_chat_invite_link`""" + createChatInviteLink = create_chat_invite_link + """Alias for :attr:`create_chat_invite_link`""" + editChatInviteLink = edit_chat_invite_link + """Alias for :attr:`edit_chat_invite_link`""" + revokeChatInviteLink = revoke_chat_invite_link + """Alias for :attr:`revoke_chat_invite_link`""" + setChatPhoto = set_chat_photo + """Alias for :meth:`set_chat_photo`""" + deleteChatPhoto = delete_chat_photo + """Alias for :meth:`delete_chat_photo`""" + setChatTitle = set_chat_title + """Alias for :meth:`set_chat_title`""" + setChatDescription = set_chat_description + """Alias for :meth:`set_chat_description`""" + pinChatMessage = pin_chat_message + """Alias for :meth:`pin_chat_message`""" + unpinChatMessage = unpin_chat_message + """Alias for :meth:`unpin_chat_message`""" + unpinAllChatMessages = unpin_all_chat_messages + """Alias for :meth:`unpin_all_chat_messages`""" + getStickerSet = get_sticker_set + """Alias for :meth:`get_sticker_set`""" + uploadStickerFile = upload_sticker_file + """Alias for :meth:`upload_sticker_file`""" + createNewStickerSet = create_new_sticker_set + """Alias for :meth:`create_new_sticker_set`""" + addStickerToSet = add_sticker_to_set + """Alias for :meth:`add_sticker_to_set`""" + setStickerPositionInSet = set_sticker_position_in_set + """Alias for :meth:`set_sticker_position_in_set`""" + deleteStickerFromSet = delete_sticker_from_set + """Alias for :meth:`delete_sticker_from_set`""" + setStickerSetThumb = set_sticker_set_thumb + """Alias for :meth:`set_sticker_set_thumb`""" + setPassportDataErrors = set_passport_data_errors + """Alias for :meth:`set_passport_data_errors`""" + sendPoll = send_poll + """Alias for :meth:`send_poll`""" + stopPoll = stop_poll + """Alias for :meth:`stop_poll`""" + sendDice = send_dice + """Alias for :meth:`send_dice`""" + getMyCommands = get_my_commands + """Alias for :meth:`get_my_commands`""" + setMyCommands = set_my_commands + """Alias for :meth:`set_my_commands`""" + logOut = log_out + """Alias for :meth:`log_out`""" + copyMessage = copy_message + """Alias for :meth:`copy_message`""" diff --git a/venv/lib/python3.8/site-packages/telegram/botcommand.py b/venv/lib/python3.8/site-packages/telegram/botcommand.py new file mode 100644 index 0000000..8b36e3e --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/botcommand.py @@ -0,0 +1,50 @@ +#!/usr/bin/env python +# pylint: disable=R0903 +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram Bot Command.""" +from typing import Any + +from telegram import TelegramObject + + +class BotCommand(TelegramObject): + """ + This object represents a bot command. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`command` and :attr:`description` are equal. + + Args: + command (:obj:`str`): Text of the command, 1-32 characters. Can contain only lowercase + English letters, digits and underscores. + description (:obj:`str`): Description of the command, 3-256 characters. + + Attributes: + command (:obj:`str`): Text of the command. + description (:obj:`str`): Description of the command. + + """ + + __slots__ = ('description', '_id_attrs', 'command') + + def __init__(self, command: str, description: str, **_kwargs: Any): + self.command = command + self.description = description + + self._id_attrs = (self.command, self.description) diff --git a/venv/lib/python3.8/site-packages/telegram/callbackquery.py b/venv/lib/python3.8/site-packages/telegram/callbackquery.py new file mode 100644 index 0000000..47b05b9 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/callbackquery.py @@ -0,0 +1,658 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +# pylint: disable=W0622 +"""This module contains an object that represents a Telegram CallbackQuery""" +from typing import TYPE_CHECKING, Any, List, Optional, Union, Tuple, ClassVar + +from telegram import Message, TelegramObject, User, Location, ReplyMarkup, constants +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import JSONDict, ODVInput, DVInput + +if TYPE_CHECKING: + from telegram import ( + Bot, + GameHighScore, + InlineKeyboardMarkup, + MessageId, + InputMedia, + MessageEntity, + ) + + +class CallbackQuery(TelegramObject): + """ + This object represents an incoming callback query from a callback button in an inline keyboard. + + If the button that originated the query was attached to a message sent by the bot, the field + :attr:`message` will be present. If the button was attached to a message sent via the bot (in + inline mode), the field :attr:`inline_message_id` will be present. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`id` is equal. + + Note: + * In Python ``from`` is a reserved word, use ``from_user`` instead. + * Exactly one of the fields :attr:`data` or :attr:`game_short_name` will be present. + * After the user presses an inline button, Telegram clients will display a progress bar + until you call :attr:`answer`. It is, therefore, necessary to react + by calling :attr:`telegram.Bot.answer_callback_query` even if no notification to the user + is needed (e.g., without specifying any of the optional parameters). + * If you're using :attr:`Bot.arbitrary_callback_data`, :attr:`data` may be an instance + of :class:`telegram.ext.InvalidCallbackData`. This will be the case, if the data + associated with the button triggering the :class:`telegram.CallbackQuery` was already + deleted or if :attr:`data` was manipulated by a malicious client. + + .. versionadded:: 13.6 + + + Args: + id (:obj:`str`): Unique identifier for this query. + from_user (:class:`telegram.User`): Sender. + chat_instance (:obj:`str`): Global identifier, uniquely corresponding to the chat to which + the message with the callback button was sent. Useful for high scores in games. + message (:class:`telegram.Message`, optional): Message with the callback button that + originated the query. Note that message content and message date will not be available + if the message is too old. + data (:obj:`str`, optional): Data associated with the callback button. Be aware that a bad + client can send arbitrary data in this field. + inline_message_id (:obj:`str`, optional): Identifier of the message sent via the bot in + inline mode, that originated the query. + game_short_name (:obj:`str`, optional): Short name of a Game to be returned, serves as + the unique identifier for the game + bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods. + + Attributes: + id (:obj:`str`): Unique identifier for this query. + from_user (:class:`telegram.User`): Sender. + chat_instance (:obj:`str`): Global identifier, uniquely corresponding to the chat to which + the message with the callback button was sent. + message (:class:`telegram.Message`): Optional. Message with the callback button that + originated the query. + data (:obj:`str` | :obj:`object`): Optional. Data associated with the callback button. + inline_message_id (:obj:`str`): Optional. Identifier of the message sent via the bot in + inline mode, that originated the query. + game_short_name (:obj:`str`): Optional. Short name of a Game to be returned. + bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods. + + """ + + __slots__ = ( + 'bot', + 'game_short_name', + 'message', + 'chat_instance', + 'id', + 'from_user', + 'inline_message_id', + 'data', + '_id_attrs', + ) + + def __init__( + self, + id: str, # pylint: disable=W0622 + from_user: User, + chat_instance: str, + message: Message = None, + data: str = None, + inline_message_id: str = None, + game_short_name: str = None, + bot: 'Bot' = None, + **_kwargs: Any, + ): + # Required + self.id = id # pylint: disable=C0103 + self.from_user = from_user + self.chat_instance = chat_instance + # Optionals + self.message = message + self.data = data + self.inline_message_id = inline_message_id + self.game_short_name = game_short_name + + self.bot = bot + + self._id_attrs = (self.id,) + + @classmethod + def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['CallbackQuery']: + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + if not data: + return None + + data['from_user'] = User.de_json(data.get('from'), bot) + data['message'] = Message.de_json(data.get('message'), bot) + + return cls(bot=bot, **data) + + def answer( + self, + text: str = None, + show_alert: bool = False, + url: str = None, + cache_time: int = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> bool: + """Shortcut for:: + + bot.answer_callback_query(update.callback_query.id, *args, **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Bot.answer_callback_query`. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + + """ + return self.bot.answer_callback_query( + callback_query_id=self.id, + text=text, + show_alert=show_alert, + url=url, + cache_time=cache_time, + timeout=timeout, + api_kwargs=api_kwargs, + ) + + def edit_message_text( + self, + text: str, + parse_mode: ODVInput[str] = DEFAULT_NONE, + disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, + reply_markup: 'InlineKeyboardMarkup' = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + ) -> Union[Message, bool]: + """Shortcut for either:: + + update.callback_query.message.edit_text(text, *args, **kwargs) + + or:: + + bot.edit_message_text(text, inline_message_id=update.callback_query.inline_message_id, + *args, **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Bot.edit_message_text` and :meth:`telegram.Message.edit_text`. + + Returns: + :class:`telegram.Message`: On success, if edited message is sent by the bot, the + edited Message is returned, otherwise :obj:`True` is returned. + + """ + if self.inline_message_id: + return self.bot.edit_message_text( + inline_message_id=self.inline_message_id, + text=text, + parse_mode=parse_mode, + disable_web_page_preview=disable_web_page_preview, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + entities=entities, + chat_id=None, + message_id=None, + ) + return self.message.edit_text( + text=text, + parse_mode=parse_mode, + disable_web_page_preview=disable_web_page_preview, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + entities=entities, + ) + + def edit_message_caption( + self, + caption: str = None, + reply_markup: 'InlineKeyboardMarkup' = None, + timeout: ODVInput[float] = DEFAULT_NONE, + parse_mode: ODVInput[str] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + ) -> Union[Message, bool]: + """Shortcut for either:: + + update.callback_query.message.edit_caption(caption, *args, **kwargs) + + or:: + + bot.edit_message_caption(caption=caption + inline_message_id=update.callback_query.inline_message_id, + *args, **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Bot.edit_message_caption` and :meth:`telegram.Message.edit_caption`. + + Returns: + :class:`telegram.Message`: On success, if edited message is sent by the bot, the + edited Message is returned, otherwise :obj:`True` is returned. + + """ + if self.inline_message_id: + return self.bot.edit_message_caption( + caption=caption, + inline_message_id=self.inline_message_id, + reply_markup=reply_markup, + timeout=timeout, + parse_mode=parse_mode, + api_kwargs=api_kwargs, + caption_entities=caption_entities, + chat_id=None, + message_id=None, + ) + return self.message.edit_caption( + caption=caption, + reply_markup=reply_markup, + timeout=timeout, + parse_mode=parse_mode, + api_kwargs=api_kwargs, + caption_entities=caption_entities, + ) + + def edit_message_reply_markup( + self, + reply_markup: Optional['InlineKeyboardMarkup'] = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> Union[Message, bool]: + """Shortcut for either:: + + update.callback_query.message.edit_reply_markup( + reply_markup=reply_markup, + *args, + **kwargs + ) + + or:: + + bot.edit_message_reply_markup + inline_message_id=update.callback_query.inline_message_id, + reply_markup=reply_markup, + *args, + **kwargs + ) + + For the documentation of the arguments, please see + :meth:`telegram.Bot.edit_message_reply_markup` and + :meth:`telegram.Message.edit_reply_markup`. + + Returns: + :class:`telegram.Message`: On success, if edited message is sent by the bot, the + edited Message is returned, otherwise :obj:`True` is returned. + + """ + if self.inline_message_id: + return self.bot.edit_message_reply_markup( + reply_markup=reply_markup, + inline_message_id=self.inline_message_id, + timeout=timeout, + api_kwargs=api_kwargs, + chat_id=None, + message_id=None, + ) + return self.message.edit_reply_markup( + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + ) + + def edit_message_media( + self, + media: 'InputMedia' = None, + reply_markup: 'InlineKeyboardMarkup' = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> Union[Message, bool]: + """Shortcut for either:: + + update.callback_query.message.edit_media(*args, **kwargs) + + or:: + + bot.edit_message_media(inline_message_id=update.callback_query.inline_message_id, + *args, **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Bot.edit_message_media` and :meth:`telegram.Message.edit_media`. + + Returns: + :class:`telegram.Message`: On success, if edited message is sent by the bot, the + edited Message is returned, otherwise :obj:`True` is returned. + + """ + if self.inline_message_id: + return self.bot.edit_message_media( + inline_message_id=self.inline_message_id, + media=media, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + chat_id=None, + message_id=None, + ) + return self.message.edit_media( + media=media, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + ) + + def edit_message_live_location( + self, + latitude: float = None, + longitude: float = None, + location: Location = None, + reply_markup: 'InlineKeyboardMarkup' = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + horizontal_accuracy: float = None, + heading: int = None, + proximity_alert_radius: int = None, + ) -> Union[Message, bool]: + """Shortcut for either:: + + update.callback_query.message.edit_live_location(*args, **kwargs) + + or:: + + bot.edit_message_live_location( + inline_message_id=update.callback_query.inline_message_id, + *args, **kwargs + ) + + For the documentation of the arguments, please see + :meth:`telegram.Bot.edit_message_live_location` and + :meth:`telegram.Message.edit_live_location`. + + Returns: + :class:`telegram.Message`: On success, if edited message is sent by the bot, the + edited Message is returned, otherwise :obj:`True` is returned. + + """ + if self.inline_message_id: + return self.bot.edit_message_live_location( + inline_message_id=self.inline_message_id, + latitude=latitude, + longitude=longitude, + location=location, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + horizontal_accuracy=horizontal_accuracy, + heading=heading, + proximity_alert_radius=proximity_alert_radius, + chat_id=None, + message_id=None, + ) + return self.message.edit_live_location( + latitude=latitude, + longitude=longitude, + location=location, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + horizontal_accuracy=horizontal_accuracy, + heading=heading, + proximity_alert_radius=proximity_alert_radius, + ) + + def stop_message_live_location( + self, + reply_markup: 'InlineKeyboardMarkup' = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> Union[Message, bool]: + """Shortcut for either:: + + update.callback_query.message.stop_live_location(*args, **kwargs) + + or:: + + bot.stop_message_live_location( + inline_message_id=update.callback_query.inline_message_id, + *args, **kwargs + ) + + For the documentation of the arguments, please see + :meth:`telegram.Bot.stop_message_live_location` and + :meth:`telegram.Message.stop_live_location`. + + Returns: + :class:`telegram.Message`: On success, if edited message is sent by the bot, the + edited Message is returned, otherwise :obj:`True` is returned. + + """ + if self.inline_message_id: + return self.bot.stop_message_live_location( + inline_message_id=self.inline_message_id, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + chat_id=None, + message_id=None, + ) + return self.message.stop_live_location( + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + ) + + def set_game_score( + self, + user_id: Union[int, str], + score: int, + force: bool = None, + disable_edit_message: bool = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> Union[Message, bool]: + """Shortcut for either:: + + update.callback_query.message.set_game_score(*args, **kwargs) + + or:: + + bot.set_game_score(inline_message_id=update.callback_query.inline_message_id, + *args, **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Bot.set_game_score` and :meth:`telegram.Message.set_game_score`. + + Returns: + :class:`telegram.Message`: On success, if edited message is sent by the bot, the + edited Message is returned, otherwise :obj:`True` is returned. + + """ + if self.inline_message_id: + return self.bot.set_game_score( + inline_message_id=self.inline_message_id, + user_id=user_id, + score=score, + force=force, + disable_edit_message=disable_edit_message, + timeout=timeout, + api_kwargs=api_kwargs, + chat_id=None, + message_id=None, + ) + return self.message.set_game_score( + user_id=user_id, + score=score, + force=force, + disable_edit_message=disable_edit_message, + timeout=timeout, + api_kwargs=api_kwargs, + ) + + def get_game_high_scores( + self, + user_id: Union[int, str], + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> List['GameHighScore']: + """Shortcut for either:: + + update.callback_query.message.get_game_high_score(*args, **kwargs) + + or:: + + bot.get_game_high_scores(inline_message_id=update.callback_query.inline_message_id, + *args, **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Bot.get_game_high_scores` and :meth:`telegram.Message.get_game_high_score`. + + Returns: + List[:class:`telegram.GameHighScore`] + + """ + if self.inline_message_id: + return self.bot.get_game_high_scores( + inline_message_id=self.inline_message_id, + user_id=user_id, + timeout=timeout, + api_kwargs=api_kwargs, + chat_id=None, + message_id=None, + ) + return self.message.get_game_high_scores( + user_id=user_id, + timeout=timeout, + api_kwargs=api_kwargs, + ) + + def delete_message( + self, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> bool: + """Shortcut for:: + + update.callback_query.message.delete(*args, **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Message.delete`. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + + """ + return self.message.delete( + timeout=timeout, + api_kwargs=api_kwargs, + ) + + def pin_message( + self, + disable_notification: ODVInput[bool] = DEFAULT_NONE, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> bool: + """Shortcut for:: + + update.callback_query.message.pin(*args, **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Message.pin`. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + + """ + return self.message.pin( + disable_notification=disable_notification, + timeout=timeout, + api_kwargs=api_kwargs, + ) + + def unpin_message( + self, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> bool: + """Shortcut for:: + + update.callback_query.message.unpin(*args, **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Message.unpin`. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + + """ + return self.message.unpin( + timeout=timeout, + api_kwargs=api_kwargs, + ) + + def copy_message( + self, + chat_id: Union[int, str], + caption: str = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + caption_entities: Union[Tuple['MessageEntity', ...], List['MessageEntity']] = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE, + reply_markup: ReplyMarkup = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> 'MessageId': + """Shortcut for:: + + update.callback_query.message.copy( + chat_id, + from_chat_id=update.message.chat_id, + message_id=update.message.message_id, + *args, + **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Message.copy`. + + Returns: + :class:`telegram.MessageId`: On success, returns the MessageId of the sent message. + + """ + return self.message.copy( + chat_id=chat_id, + caption=caption, + parse_mode=parse_mode, + caption_entities=caption_entities, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + allow_sending_without_reply=allow_sending_without_reply, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + ) + + MAX_ANSWER_TEXT_LENGTH: ClassVar[int] = constants.MAX_ANSWER_CALLBACK_QUERY_TEXT_LENGTH + """ + :const:`telegram.constants.MAX_ANSWER_CALLBACK_QUERY_TEXT_LENGTH` + + .. versionadded:: 13.2 + """ diff --git a/venv/lib/python3.8/site-packages/telegram/chat.py b/venv/lib/python3.8/site-packages/telegram/chat.py new file mode 100644 index 0000000..95ed61d --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/chat.py @@ -0,0 +1,1559 @@ +#!/usr/bin/env python +# pylint: disable=W0622 +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram Chat.""" +from datetime import datetime +from typing import TYPE_CHECKING, List, Optional, ClassVar, Union, Tuple, Any + +from telegram import ChatPhoto, TelegramObject, constants +from telegram.utils.types import JSONDict, FileInput, ODVInput, DVInput + +from .chatpermissions import ChatPermissions +from .chatlocation import ChatLocation +from .utils.helpers import DEFAULT_NONE, DEFAULT_20 + +if TYPE_CHECKING: + from telegram import ( + Bot, + ChatMember, + ChatInviteLink, + Message, + MessageId, + ReplyMarkup, + Contact, + InlineKeyboardMarkup, + Location, + Venue, + MessageEntity, + InputMediaAudio, + InputMediaDocument, + InputMediaPhoto, + InputMediaVideo, + PhotoSize, + Audio, + Document, + Animation, + LabeledPrice, + Sticker, + Video, + VideoNote, + Voice, + ) + + +class Chat(TelegramObject): + """This object represents a chat. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`id` is equal. + + Args: + id (:obj:`int`): Unique identifier for this chat. This number may be greater than 32 bits + and some programming languages may have difficulty/silent defects in interpreting it. + But it is smaller than 52 bits, so a signed 64 bit integer or double-precision float + type are safe for storing this identifier. + type (:obj:`str`): Type of chat, can be either 'private', 'group', 'supergroup' or + 'channel'. + title (:obj:`str`, optional): Title, for supergroups, channels and group chats. + username(:obj:`str`, optional): Username, for private chats, supergroups and channels if + available. + first_name(:obj:`str`, optional): First name of the other party in a private chat. + last_name(:obj:`str`, optional): Last name of the other party in a private chat. + photo (:class:`telegram.ChatPhoto`, optional): Chat photo. + Returned only in :meth:`telegram.Bot.get_chat`. + bio (:obj:`str`, optional): Bio of the other party in a private chat. Returned only in + :meth:`telegram.Bot.get_chat`. + description (:obj:`str`, optional): Description, for groups, supergroups and channel chats. + Returned only in :meth:`telegram.Bot.get_chat`. + invite_link (:obj:`str`, optional): Primary invite link, for groups, supergroups and + channel. Returned only in :meth:`telegram.Bot.get_chat`. + pinned_message (:class:`telegram.Message`, optional): The most recent pinned message + (by sending date). Returned only in :meth:`telegram.Bot.get_chat`. + permissions (:class:`telegram.ChatPermissions`): Optional. Default chat member permissions, + for groups and supergroups. Returned only in :meth:`telegram.Bot.get_chat`. + slow_mode_delay (:obj:`int`, optional): For supergroups, the minimum allowed delay between + consecutive messages sent by each unprivileged user. + Returned only in :meth:`telegram.Bot.get_chat`. + message_auto_delete_time (:obj:`int`, optional): The time after which all messages sent to + the chat will be automatically deleted; in seconds. Returned only in + :meth:`telegram.Bot.get_chat`. + + .. versionadded:: 13.4 + bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods. + sticker_set_name (:obj:`str`, optional): For supergroups, name of group sticker set. + Returned only in :meth:`telegram.Bot.get_chat`. + can_set_sticker_set (:obj:`bool`, optional): :obj:`True`, if the bot can change group the + sticker set. Returned only in :meth:`telegram.Bot.get_chat`. + linked_chat_id (:obj:`int`, optional): Unique identifier for the linked chat, i.e. the + discussion group identifier for a channel and vice versa; for supergroups and channel + chats. Returned only in :meth:`telegram.Bot.get_chat`. + location (:class:`telegram.ChatLocation`, optional): For supergroups, the location to which + the supergroup is connected. Returned only in :meth:`telegram.Bot.get_chat`. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + id (:obj:`int`): Unique identifier for this chat. + type (:obj:`str`): Type of chat. + title (:obj:`str`): Optional. Title, for supergroups, channels and group chats. + username (:obj:`str`): Optional. Username. + first_name (:obj:`str`): Optional. First name of the other party in a private chat. + last_name (:obj:`str`): Optional. Last name of the other party in a private chat. + photo (:class:`telegram.ChatPhoto`): Optional. Chat photo. + bio (:obj:`str`): Optional. Bio of the other party in a private chat. Returned only in + :meth:`telegram.Bot.get_chat`. + description (:obj:`str`): Optional. Description, for groups, supergroups and channel chats. + invite_link (:obj:`str`): Optional. Primary invite link, for groups, supergroups and + channel. Returned only in :meth:`telegram.Bot.get_chat`. + pinned_message (:class:`telegram.Message`): Optional. The most recent pinned message + (by sending date). Returned only in :meth:`telegram.Bot.get_chat`. + permissions (:class:`telegram.ChatPermissions`): Optional. Default chat member permissions, + for groups and supergroups. Returned only in :meth:`telegram.Bot.get_chat`. + slow_mode_delay (:obj:`int`): Optional. For supergroups, the minimum allowed delay between + consecutive messages sent by each unprivileged user. Returned only in + :meth:`telegram.Bot.get_chat`. + message_auto_delete_time (:obj:`int`): Optional. The time after which all messages sent to + the chat will be automatically deleted; in seconds. Returned only in + :meth:`telegram.Bot.get_chat`. + + .. versionadded:: 13.4 + sticker_set_name (:obj:`str`): Optional. For supergroups, name of Group sticker set. + can_set_sticker_set (:obj:`bool`): Optional. :obj:`True`, if the bot can change group the + sticker set. + linked_chat_id (:obj:`int`): Optional. Unique identifier for the linked chat, i.e. the + discussion group identifier for a channel and vice versa; for supergroups and channel + chats. Returned only in :meth:`telegram.Bot.get_chat`. + location (:class:`telegram.ChatLocation`): Optional. For supergroups, the location to which + the supergroup is connected. Returned only in :meth:`telegram.Bot.get_chat`. + + """ + + __slots__ = ( + 'bio', + 'id', + 'type', + 'last_name', + 'bot', + 'sticker_set_name', + 'slow_mode_delay', + 'location', + 'first_name', + 'permissions', + 'invite_link', + 'pinned_message', + 'description', + 'can_set_sticker_set', + 'username', + 'title', + 'photo', + 'linked_chat_id', + 'all_members_are_administrators', + 'message_auto_delete_time', + '_id_attrs', + ) + + SENDER: ClassVar[str] = constants.CHAT_SENDER + """:const:`telegram.constants.CHAT_SENDER` + + .. versionadded:: 13.5 + """ + PRIVATE: ClassVar[str] = constants.CHAT_PRIVATE + """:const:`telegram.constants.CHAT_PRIVATE`""" + GROUP: ClassVar[str] = constants.CHAT_GROUP + """:const:`telegram.constants.CHAT_GROUP`""" + SUPERGROUP: ClassVar[str] = constants.CHAT_SUPERGROUP + """:const:`telegram.constants.CHAT_SUPERGROUP`""" + CHANNEL: ClassVar[str] = constants.CHAT_CHANNEL + """:const:`telegram.constants.CHAT_CHANNEL`""" + + def __init__( + self, + id: int, + type: str, + title: str = None, + username: str = None, + first_name: str = None, + last_name: str = None, + bot: 'Bot' = None, + photo: ChatPhoto = None, + description: str = None, + invite_link: str = None, + pinned_message: 'Message' = None, + permissions: ChatPermissions = None, + sticker_set_name: str = None, + can_set_sticker_set: bool = None, + slow_mode_delay: int = None, + bio: str = None, + linked_chat_id: int = None, + location: ChatLocation = None, + message_auto_delete_time: int = None, + **_kwargs: Any, + ): + # Required + self.id = int(id) # pylint: disable=C0103 + self.type = type + # Optionals + self.title = title + self.username = username + self.first_name = first_name + self.last_name = last_name + # TODO: Remove (also from tests), when Telegram drops this completely + self.all_members_are_administrators = _kwargs.get('all_members_are_administrators') + self.photo = photo + self.bio = bio + self.description = description + self.invite_link = invite_link + self.pinned_message = pinned_message + self.permissions = permissions + self.slow_mode_delay = slow_mode_delay + self.message_auto_delete_time = ( + int(message_auto_delete_time) if message_auto_delete_time is not None else None + ) + self.sticker_set_name = sticker_set_name + self.can_set_sticker_set = can_set_sticker_set + self.linked_chat_id = linked_chat_id + self.location = location + + self.bot = bot + self._id_attrs = (self.id,) + + @property + def full_name(self) -> Optional[str]: + """ + :obj:`str`: Convenience property. If :attr:`first_name` is not :obj:`None` gives, + :attr:`first_name` followed by (if available) :attr:`last_name`. + + Note: + :attr:`full_name` will always be :obj:`None`, if the chat is a (super)group or + channel. + + .. versionadded:: 13.2 + """ + if not self.first_name: + return None + if self.last_name: + return f'{self.first_name} {self.last_name}' + return self.first_name + + @property + def link(self) -> Optional[str]: + """:obj:`str`: Convenience property. If the chat has a :attr:`username`, returns a t.me + link of the chat. + """ + if self.username: + return f"https://t.me/{self.username}" + return None + + @classmethod + def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Chat']: + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + if not data: + return None + + data['photo'] = ChatPhoto.de_json(data.get('photo'), bot) + from telegram import Message # pylint: disable=C0415 + + data['pinned_message'] = Message.de_json(data.get('pinned_message'), bot) + data['permissions'] = ChatPermissions.de_json(data.get('permissions'), bot) + data['location'] = ChatLocation.de_json(data.get('location'), bot) + + return cls(bot=bot, **data) + + def leave(self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None) -> bool: + """Shortcut for:: + + bot.leave_chat(update.effective_chat.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.leave_chat`. + + Returns: + :obj:`bool` If the action was sent successfully. + + """ + return self.bot.leave_chat( + chat_id=self.id, + timeout=timeout, + api_kwargs=api_kwargs, + ) + + def get_administrators( + self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None + ) -> List['ChatMember']: + """Shortcut for:: + + bot.get_chat_administrators(update.effective_chat.id, *args, **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Bot.get_chat_administrators`. + + Returns: + List[:class:`telegram.ChatMember`]: A list of administrators in a chat. An Array of + :class:`telegram.ChatMember` objects that contains information about all + chat administrators except other bots. If the chat is a group or a supergroup + and no administrators were appointed, only the creator will be returned. + + """ + return self.bot.get_chat_administrators( + chat_id=self.id, + timeout=timeout, + api_kwargs=api_kwargs, + ) + + def get_members_count( + self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None + ) -> int: + """Shortcut for:: + + bot.get_chat_members_count(update.effective_chat.id, *args, **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Bot.get_chat_members_count`. + + Returns: + :obj:`int` + + """ + return self.bot.get_chat_members_count( + chat_id=self.id, + timeout=timeout, + api_kwargs=api_kwargs, + ) + + def get_member( + self, + user_id: Union[str, int], + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> 'ChatMember': + """Shortcut for:: + + bot.get_chat_member(update.effective_chat.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.get_chat_member`. + + Returns: + :class:`telegram.ChatMember` + + """ + return self.bot.get_chat_member( + chat_id=self.id, + user_id=user_id, + timeout=timeout, + api_kwargs=api_kwargs, + ) + + def kick_member( + self, + user_id: Union[str, int], + timeout: ODVInput[float] = DEFAULT_NONE, + until_date: Union[int, datetime] = None, + api_kwargs: JSONDict = None, + revoke_messages: bool = None, + ) -> bool: + """Shortcut for:: + + bot.kick_chat_member(update.effective_chat.id, *args, **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Bot.kick_chat_member`. + + Returns: + :obj:`bool`: If the action was sent successfully. + + Note: + This method will only work if the `All Members Are Admins` setting is off in the + target group. Otherwise members may only be removed by the group's creator or by the + member that added them. + + """ + return self.bot.kick_chat_member( + chat_id=self.id, + user_id=user_id, + timeout=timeout, + until_date=until_date, + api_kwargs=api_kwargs, + revoke_messages=revoke_messages, + ) + + def unban_member( + self, + user_id: Union[str, int], + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + only_if_banned: bool = None, + ) -> bool: + """Shortcut for:: + + bot.unban_chat_member(update.effective_chat.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.unban_chat_member`. + + Returns: + :obj:`bool`: If the action was sent successfully. + + """ + return self.bot.unban_chat_member( + chat_id=self.id, + user_id=user_id, + timeout=timeout, + api_kwargs=api_kwargs, + only_if_banned=only_if_banned, + ) + + def promote_member( + self, + user_id: Union[str, int], + can_change_info: bool = None, + can_post_messages: bool = None, + can_edit_messages: bool = None, + can_delete_messages: bool = None, + can_invite_users: bool = None, + can_restrict_members: bool = None, + can_pin_messages: bool = None, + can_promote_members: bool = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + is_anonymous: bool = None, + can_manage_chat: bool = None, + can_manage_voice_chats: bool = None, + ) -> bool: + """Shortcut for:: + + bot.promote_chat_member(update.effective_chat.id, *args, **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Bot.promote_chat_member`. + + .. versionadded:: 13.2 + + Returns: + :obj:`bool`: If the action was sent successfully. + + """ + return self.bot.promote_chat_member( + chat_id=self.id, + user_id=user_id, + can_change_info=can_change_info, + can_post_messages=can_post_messages, + can_edit_messages=can_edit_messages, + can_delete_messages=can_delete_messages, + can_invite_users=can_invite_users, + can_restrict_members=can_restrict_members, + can_pin_messages=can_pin_messages, + can_promote_members=can_promote_members, + timeout=timeout, + api_kwargs=api_kwargs, + is_anonymous=is_anonymous, + can_manage_chat=can_manage_chat, + can_manage_voice_chats=can_manage_voice_chats, + ) + + def restrict_member( + self, + user_id: Union[str, int], + permissions: ChatPermissions, + until_date: Union[int, datetime] = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> bool: + """Shortcut for:: + + bot.restrict_chat_member(update.effective_chat.id, *args, **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Bot.restrict_chat_member`. + + .. versionadded:: 13.2 + + Returns: + :obj:`bool`: If the action was sent successfully. + + """ + return self.bot.restrict_chat_member( + chat_id=self.id, + user_id=user_id, + permissions=permissions, + until_date=until_date, + timeout=timeout, + api_kwargs=api_kwargs, + ) + + def set_permissions( + self, + permissions: ChatPermissions, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> bool: + """Shortcut for:: + + bot.set_chat_permissions(update.effective_chat.id, *args, **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Bot.set_chat_permissions`. + + Returns: + :obj:`bool`: If the action was sent successfully. + + """ + return self.bot.set_chat_permissions( + chat_id=self.id, + permissions=permissions, + timeout=timeout, + api_kwargs=api_kwargs, + ) + + def set_administrator_custom_title( + self, + user_id: Union[int, str], + custom_title: str, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> bool: + """Shortcut for:: + + bot.set_chat_administrator_custom_title(update.effective_chat.id, *args, **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Bot.set_chat_administrator_custom_title`. + + Returns: + :obj:`bool`: If the action was sent successfully. + + """ + return self.bot.set_chat_administrator_custom_title( + chat_id=self.id, + user_id=user_id, + custom_title=custom_title, + timeout=timeout, + api_kwargs=api_kwargs, + ) + + def pin_message( + self, + message_id: int, + disable_notification: ODVInput[bool] = DEFAULT_NONE, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> bool: + """Shortcut for:: + + bot.pin_chat_message(chat_id=update.effective_chat.id, + *args, + **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Bot.pin_chat_message`. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + + """ + return self.bot.pin_chat_message( + chat_id=self.id, + message_id=message_id, + disable_notification=disable_notification, + timeout=timeout, + api_kwargs=api_kwargs, + ) + + def unpin_message( + self, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + message_id: int = None, + ) -> bool: + """Shortcut for:: + + bot.unpin_chat_message(chat_id=update.effective_chat.id, + *args, + **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Bot.unpin_chat_message`. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + + """ + return self.bot.unpin_chat_message( + chat_id=self.id, + timeout=timeout, + api_kwargs=api_kwargs, + message_id=message_id, + ) + + def unpin_all_messages( + self, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> bool: + """Shortcut for:: + + bot.unpin_all_chat_messages(chat_id=update.effective_chat.id, + *args, + **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Bot.unpin_all_chat_messages`. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + + """ + return self.bot.unpin_all_chat_messages( + chat_id=self.id, + timeout=timeout, + api_kwargs=api_kwargs, + ) + + def send_message( + self, + text: str, + parse_mode: ODVInput[str] = DEFAULT_NONE, + disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: 'ReplyMarkup' = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + ) -> 'Message': + """Shortcut for:: + + bot.send_message(update.effective_chat.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_message`. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + return self.bot.send_message( + chat_id=self.id, + text=text, + parse_mode=parse_mode, + disable_web_page_preview=disable_web_page_preview, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + entities=entities, + ) + + def send_media_group( + self, + media: List[ + Union['InputMediaAudio', 'InputMediaDocument', 'InputMediaPhoto', 'InputMediaVideo'] + ], + disable_notification: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + timeout: DVInput[float] = DEFAULT_20, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + ) -> List['Message']: + """Shortcut for:: + + bot.send_media_group(update.effective_chat.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_media_group`. + + Returns: + List[:class:`telegram.Message`:] On success, instance representing the message posted. + + """ + return self.bot.send_media_group( + chat_id=self.id, + media=media, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + timeout=timeout, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + ) + + def send_chat_action( + self, + action: str, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> bool: + """Shortcut for:: + + bot.send_chat_action(update.effective_chat.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_chat_action`. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + + """ + return self.bot.send_chat_action( + chat_id=self.id, + action=action, + timeout=timeout, + api_kwargs=api_kwargs, + ) + + send_action = send_chat_action + """Alias for :attr:`send_chat_action`""" + + def send_photo( + self, + photo: Union[FileInput, 'PhotoSize'], + caption: str = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: 'ReplyMarkup' = None, + timeout: DVInput[float] = DEFAULT_20, + parse_mode: ODVInput[str] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + filename: str = None, + ) -> 'Message': + """Shortcut for:: + + bot.send_photo(update.effective_chat.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_photo`. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + return self.bot.send_photo( + chat_id=self.id, + photo=photo, + caption=caption, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + parse_mode=parse_mode, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + caption_entities=caption_entities, + filename=filename, + ) + + def send_contact( + self, + phone_number: str = None, + first_name: str = None, + last_name: str = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: 'ReplyMarkup' = None, + timeout: ODVInput[float] = DEFAULT_NONE, + contact: 'Contact' = None, + vcard: str = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + ) -> 'Message': + """Shortcut for:: + + bot.send_contact(update.effective_chat.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_contact`. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + return self.bot.send_contact( + chat_id=self.id, + phone_number=phone_number, + first_name=first_name, + last_name=last_name, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + contact=contact, + vcard=vcard, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + ) + + def send_audio( + self, + audio: Union[FileInput, 'Audio'], + duration: int = None, + performer: str = None, + title: str = None, + caption: str = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: 'ReplyMarkup' = None, + timeout: DVInput[float] = DEFAULT_20, + parse_mode: ODVInput[str] = DEFAULT_NONE, + thumb: FileInput = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + filename: str = None, + ) -> 'Message': + """Shortcut for:: + + bot.send_audio(update.effective_chat.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_audio`. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + return self.bot.send_audio( + chat_id=self.id, + audio=audio, + duration=duration, + performer=performer, + title=title, + caption=caption, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + parse_mode=parse_mode, + thumb=thumb, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + caption_entities=caption_entities, + filename=filename, + ) + + def send_document( + self, + document: Union[FileInput, 'Document'], + filename: str = None, + caption: str = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: 'ReplyMarkup' = None, + timeout: DVInput[float] = DEFAULT_20, + parse_mode: ODVInput[str] = DEFAULT_NONE, + thumb: FileInput = None, + api_kwargs: JSONDict = None, + disable_content_type_detection: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + ) -> 'Message': + """Shortcut for:: + + bot.send_document(update.effective_chat.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_document`. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + return self.bot.send_document( + chat_id=self.id, + document=document, + filename=filename, + caption=caption, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + parse_mode=parse_mode, + thumb=thumb, + api_kwargs=api_kwargs, + disable_content_type_detection=disable_content_type_detection, + allow_sending_without_reply=allow_sending_without_reply, + caption_entities=caption_entities, + ) + + def send_dice( + self, + disable_notification: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: 'ReplyMarkup' = None, + timeout: ODVInput[float] = DEFAULT_NONE, + emoji: str = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + ) -> 'Message': + """Shortcut for:: + + bot.send_dice(update.effective_chat.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_dice`. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + return self.bot.send_dice( + chat_id=self.id, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + emoji=emoji, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + ) + + def send_game( + self, + game_short_name: str, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: 'InlineKeyboardMarkup' = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + ) -> 'Message': + """Shortcut for:: + + bot.send_game(update.effective_chat.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_game`. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + return self.bot.send_game( + chat_id=self.id, + game_short_name=game_short_name, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + ) + + def send_invoice( + self, + title: str, + description: str, + payload: str, + provider_token: str, + currency: str, + prices: List['LabeledPrice'], + start_parameter: str = None, + photo_url: str = None, + photo_size: int = None, + photo_width: int = None, + photo_height: int = None, + need_name: bool = None, + need_phone_number: bool = None, + need_email: bool = None, + need_shipping_address: bool = None, + is_flexible: bool = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: 'InlineKeyboardMarkup' = None, + provider_data: Union[str, object] = None, + send_phone_number_to_provider: bool = None, + send_email_to_provider: bool = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + max_tip_amount: int = None, + suggested_tip_amounts: List[int] = None, + ) -> 'Message': + """Shortcut for:: + + bot.send_invoice(update.effective_chat.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_invoice`. + + Warning: + As of API 5.2 :attr:`start_parameter` is an optional argument and therefore the order + of the arguments had to be changed. Use keyword arguments to make sure that the + arguments are passed correctly. + + .. versionchanged:: 13.5 + As of Bot API 5.2, the parameter :attr:`start_parameter` is optional. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + return self.bot.send_invoice( + chat_id=self.id, + title=title, + description=description, + payload=payload, + provider_token=provider_token, + currency=currency, + prices=prices, + start_parameter=start_parameter, + photo_url=photo_url, + photo_size=photo_size, + photo_width=photo_width, + photo_height=photo_height, + need_name=need_name, + need_phone_number=need_phone_number, + need_email=need_email, + need_shipping_address=need_shipping_address, + is_flexible=is_flexible, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + provider_data=provider_data, + send_phone_number_to_provider=send_phone_number_to_provider, + send_email_to_provider=send_email_to_provider, + timeout=timeout, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + max_tip_amount=max_tip_amount, + suggested_tip_amounts=suggested_tip_amounts, + ) + + def send_location( + self, + latitude: float = None, + longitude: float = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: 'ReplyMarkup' = None, + timeout: ODVInput[float] = DEFAULT_NONE, + location: 'Location' = None, + live_period: int = None, + api_kwargs: JSONDict = None, + horizontal_accuracy: float = None, + heading: int = None, + proximity_alert_radius: int = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + ) -> 'Message': + """Shortcut for:: + + bot.send_location(update.effective_chat.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_location`. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + return self.bot.send_location( + chat_id=self.id, + latitude=latitude, + longitude=longitude, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + location=location, + live_period=live_period, + api_kwargs=api_kwargs, + horizontal_accuracy=horizontal_accuracy, + heading=heading, + proximity_alert_radius=proximity_alert_radius, + allow_sending_without_reply=allow_sending_without_reply, + ) + + def send_animation( + self, + animation: Union[FileInput, 'Animation'], + duration: int = None, + width: int = None, + height: int = None, + thumb: FileInput = None, + caption: str = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: 'ReplyMarkup' = None, + timeout: DVInput[float] = DEFAULT_20, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + filename: str = None, + ) -> 'Message': + """Shortcut for:: + + bot.send_animation(update.effective_chat.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_animation`. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + return self.bot.send_animation( + chat_id=self.id, + animation=animation, + duration=duration, + width=width, + height=height, + thumb=thumb, + caption=caption, + parse_mode=parse_mode, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + caption_entities=caption_entities, + filename=filename, + ) + + def send_sticker( + self, + sticker: Union[FileInput, 'Sticker'], + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: 'ReplyMarkup' = None, + timeout: DVInput[float] = DEFAULT_20, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + ) -> 'Message': + """Shortcut for:: + + bot.send_sticker(update.effective_chat.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_sticker`. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + return self.bot.send_sticker( + chat_id=self.id, + sticker=sticker, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + ) + + def send_venue( + self, + latitude: float = None, + longitude: float = None, + title: str = None, + address: str = None, + foursquare_id: str = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: 'ReplyMarkup' = None, + timeout: ODVInput[float] = DEFAULT_NONE, + venue: 'Venue' = None, + foursquare_type: str = None, + api_kwargs: JSONDict = None, + google_place_id: str = None, + google_place_type: str = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + ) -> 'Message': + """Shortcut for:: + + bot.send_venue(update.effective_chat.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_venue`. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + return self.bot.send_venue( + chat_id=self.id, + latitude=latitude, + longitude=longitude, + title=title, + address=address, + foursquare_id=foursquare_id, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + venue=venue, + foursquare_type=foursquare_type, + api_kwargs=api_kwargs, + google_place_id=google_place_id, + google_place_type=google_place_type, + allow_sending_without_reply=allow_sending_without_reply, + ) + + def send_video( + self, + video: Union[FileInput, 'Video'], + duration: int = None, + caption: str = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: 'ReplyMarkup' = None, + timeout: DVInput[float] = DEFAULT_20, + width: int = None, + height: int = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + supports_streaming: bool = None, + thumb: FileInput = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + filename: str = None, + ) -> 'Message': + """Shortcut for:: + + bot.send_video(update.effective_chat.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_video`. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + return self.bot.send_video( + chat_id=self.id, + video=video, + duration=duration, + caption=caption, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + width=width, + height=height, + parse_mode=parse_mode, + supports_streaming=supports_streaming, + thumb=thumb, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + caption_entities=caption_entities, + filename=filename, + ) + + def send_video_note( + self, + video_note: Union[FileInput, 'VideoNote'], + duration: int = None, + length: int = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: 'ReplyMarkup' = None, + timeout: DVInput[float] = DEFAULT_20, + thumb: FileInput = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + filename: str = None, + ) -> 'Message': + """Shortcut for:: + + bot.send_video_note(update.effective_chat.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_video_note`. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + return self.bot.send_video_note( + chat_id=self.id, + video_note=video_note, + duration=duration, + length=length, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + thumb=thumb, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + filename=filename, + ) + + def send_voice( + self, + voice: Union[FileInput, 'Voice'], + duration: int = None, + caption: str = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: 'ReplyMarkup' = None, + timeout: DVInput[float] = DEFAULT_20, + parse_mode: ODVInput[str] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + filename: str = None, + ) -> 'Message': + """Shortcut for:: + + bot.send_voice(update.effective_chat.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_voice`. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + return self.bot.send_voice( + chat_id=self.id, + voice=voice, + duration=duration, + caption=caption, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + parse_mode=parse_mode, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + caption_entities=caption_entities, + filename=filename, + ) + + def send_poll( + self, + question: str, + options: List[str], + is_anonymous: bool = True, + # We use constant.POLL_REGULAR instead of Poll.REGULAR here to avoid circular imports + type: str = constants.POLL_REGULAR, # pylint: disable=W0622 + allows_multiple_answers: bool = False, + correct_option_id: int = None, + is_closed: bool = None, + disable_notification: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: 'ReplyMarkup' = None, + timeout: ODVInput[float] = DEFAULT_NONE, + explanation: str = None, + explanation_parse_mode: ODVInput[str] = DEFAULT_NONE, + open_period: int = None, + close_date: Union[int, datetime] = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + explanation_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + ) -> 'Message': + """Shortcut for:: + + bot.send_poll(update.effective_chat.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_poll`. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + return self.bot.send_poll( + chat_id=self.id, + question=question, + options=options, + is_anonymous=is_anonymous, + type=type, # pylint=pylint, + allows_multiple_answers=allows_multiple_answers, + correct_option_id=correct_option_id, + is_closed=is_closed, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + explanation=explanation, + explanation_parse_mode=explanation_parse_mode, + open_period=open_period, + close_date=close_date, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + explanation_entities=explanation_entities, + ) + + def send_copy( + self, + from_chat_id: Union[str, int], + message_id: int, + caption: str = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + caption_entities: Union[Tuple['MessageEntity', ...], List['MessageEntity']] = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE, + reply_markup: 'ReplyMarkup' = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> 'MessageId': + """Shortcut for:: + + bot.copy_message(chat_id=update.effective_chat.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.copy_message`. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + return self.bot.copy_message( + chat_id=self.id, + from_chat_id=from_chat_id, + message_id=message_id, + caption=caption, + parse_mode=parse_mode, + caption_entities=caption_entities, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + allow_sending_without_reply=allow_sending_without_reply, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + ) + + def copy_message( + self, + chat_id: Union[int, str], + message_id: int, + caption: str = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + caption_entities: Union[Tuple['MessageEntity', ...], List['MessageEntity']] = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE, + reply_markup: 'ReplyMarkup' = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> 'MessageId': + """Shortcut for:: + + bot.copy_message(from_chat_id=update.effective_chat.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.copy_message`. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + return self.bot.copy_message( + from_chat_id=self.id, + chat_id=chat_id, + message_id=message_id, + caption=caption, + parse_mode=parse_mode, + caption_entities=caption_entities, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + allow_sending_without_reply=allow_sending_without_reply, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + ) + + def export_invite_link( + self, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> str: + """Shortcut for:: + + bot.export_chat_invite_link(chat_id=update.effective_chat.id, *args, **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Bot.export_chat_invite_link`. + + .. versionadded:: 13.4 + + Returns: + :obj:`str`: New invite link on success. + + """ + return self.bot.export_chat_invite_link( + chat_id=self.id, timeout=timeout, api_kwargs=api_kwargs + ) + + def create_invite_link( + self, + expire_date: Union[int, datetime] = None, + member_limit: int = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> 'ChatInviteLink': + """Shortcut for:: + + bot.create_chat_invite_link(chat_id=update.effective_chat.id, *args, **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Bot.create_chat_invite_link`. + + .. versionadded:: 13.4 + + Returns: + :class:`telegram.ChatInviteLink` + + """ + return self.bot.create_chat_invite_link( + chat_id=self.id, + expire_date=expire_date, + member_limit=member_limit, + timeout=timeout, + api_kwargs=api_kwargs, + ) + + def edit_invite_link( + self, + invite_link: str, + expire_date: Union[int, datetime] = None, + member_limit: int = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> 'ChatInviteLink': + """Shortcut for:: + + bot.edit_chat_invite_link(chat_id=update.effective_chat.id, *args, **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Bot.edit_chat_invite_link`. + + .. versionadded:: 13.4 + + Returns: + :class:`telegram.ChatInviteLink` + + """ + return self.bot.edit_chat_invite_link( + chat_id=self.id, + invite_link=invite_link, + expire_date=expire_date, + member_limit=member_limit, + timeout=timeout, + api_kwargs=api_kwargs, + ) + + def revoke_invite_link( + self, + invite_link: str, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> 'ChatInviteLink': + """Shortcut for:: + + bot.revoke_chat_invite_link(chat_id=update.effective_chat.id, *args, **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Bot.revoke_chat_invite_link`. + + .. versionadded:: 13.4 + + Returns: + :class:`telegram.ChatInviteLink` + + """ + return self.bot.revoke_chat_invite_link( + chat_id=self.id, invite_link=invite_link, timeout=timeout, api_kwargs=api_kwargs + ) diff --git a/venv/lib/python3.8/site-packages/telegram/chataction.py b/venv/lib/python3.8/site-packages/telegram/chataction.py new file mode 100644 index 0000000..c737b81 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/chataction.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python +# pylint: disable=R0903 +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram ChatAction.""" +from typing import ClassVar +from telegram import constants +from telegram.utils.deprecate import set_new_attribute_deprecated + + +class ChatAction: + """Helper class to provide constants for different chat actions.""" + + __slots__ = ('__dict__',) # Adding __dict__ here since it doesn't subclass TGObject + FIND_LOCATION: ClassVar[str] = constants.CHATACTION_FIND_LOCATION + """:const:`telegram.constants.CHATACTION_FIND_LOCATION`""" + RECORD_AUDIO: ClassVar[str] = constants.CHATACTION_RECORD_AUDIO + """:const:`telegram.constants.CHATACTION_RECORD_AUDIO` + + .. deprecated:: 13.5 + Deprecated by Telegram. Use :attr:`RECORD_VOICE` instead. + """ + RECORD_VOICE: ClassVar[str] = constants.CHATACTION_RECORD_VOICE + """:const:`telegram.constants.CHATACTION_RECORD_VOICE` + + .. versionadded:: 13.5 + """ + RECORD_VIDEO: ClassVar[str] = constants.CHATACTION_RECORD_VIDEO + """:const:`telegram.constants.CHATACTION_RECORD_VIDEO`""" + RECORD_VIDEO_NOTE: ClassVar[str] = constants.CHATACTION_RECORD_VIDEO_NOTE + """:const:`telegram.constants.CHATACTION_RECORD_VIDEO_NOTE`""" + TYPING: ClassVar[str] = constants.CHATACTION_TYPING + """:const:`telegram.constants.CHATACTION_TYPING`""" + UPLOAD_AUDIO: ClassVar[str] = constants.CHATACTION_UPLOAD_AUDIO + """:const:`telegram.constants.CHATACTION_UPLOAD_AUDIO` + + .. deprecated:: 13.5 + Deprecated by Telegram. Use :attr:`UPLOAD_VOICE` instead. + """ + UPLOAD_VOICE: ClassVar[str] = constants.CHATACTION_UPLOAD_VOICE + """:const:`telegram.constants.CHATACTION_UPLOAD_VOICE` + + .. versionadded:: 13.5 + """ + UPLOAD_DOCUMENT: ClassVar[str] = constants.CHATACTION_UPLOAD_DOCUMENT + """:const:`telegram.constants.CHATACTION_UPLOAD_DOCUMENT`""" + UPLOAD_PHOTO: ClassVar[str] = constants.CHATACTION_UPLOAD_PHOTO + """:const:`telegram.constants.CHATACTION_UPLOAD_PHOTO`""" + UPLOAD_VIDEO: ClassVar[str] = constants.CHATACTION_UPLOAD_VIDEO + """:const:`telegram.constants.CHATACTION_UPLOAD_VIDEO`""" + UPLOAD_VIDEO_NOTE: ClassVar[str] = constants.CHATACTION_UPLOAD_VIDEO_NOTE + """:const:`telegram.constants.CHATACTION_UPLOAD_VIDEO_NOTE`""" + + def __setattr__(self, key: str, value: object) -> None: + set_new_attribute_deprecated(self, key, value) diff --git a/venv/lib/python3.8/site-packages/telegram/chatinvitelink.py b/venv/lib/python3.8/site-packages/telegram/chatinvitelink.py new file mode 100644 index 0000000..0755853 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/chatinvitelink.py @@ -0,0 +1,114 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents an invite link for a chat.""" +import datetime +from typing import TYPE_CHECKING, Any, Optional + +from telegram import TelegramObject, User +from telegram.utils.helpers import from_timestamp, to_timestamp +from telegram.utils.types import JSONDict + +if TYPE_CHECKING: + from telegram import Bot + + +class ChatInviteLink(TelegramObject): + """This object represents an invite link for a chat. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`invite_link`, :attr:`creator`, :attr:`is_primary` and + :attr:`is_revoked` are equal. + + .. versionadded:: 13.4 + + Args: + invite_link (:obj:`str`): The invite link. + creator (:class:`telegram.User`): Creator of the link. + is_primary (:obj:`bool`): :obj:`True`, if the link is primary. + is_revoked (:obj:`bool`): :obj:`True`, if the link is revoked. + expire_date (:class:`datetime.datetime`, optional): Date when the link will expire or + has been expired. + member_limit (:obj:`int`, optional): Maximum number of users that can be members of the + chat simultaneously after joining the chat via this invite link; 1-99999. + + Attributes: + invite_link (:obj:`str`): The invite link. If the link was created by another chat + administrator, then the second part of the link will be replaced with ``'…'``. + creator (:class:`telegram.User`): Creator of the link. + is_primary (:obj:`bool`): :obj:`True`, if the link is primary. + is_revoked (:obj:`bool`): :obj:`True`, if the link is revoked. + expire_date (:class:`datetime.datetime`): Optional. Date when the link will expire or + has been expired. + member_limit (:obj:`int`): Optional. Maximum number of users that can be members + of the chat simultaneously after joining the chat via this invite link; 1-99999. + + """ + + __slots__ = ( + 'invite_link', + 'creator', + 'is_primary', + 'is_revoked', + 'expire_date', + 'member_limit', + '_id_attrs', + ) + + def __init__( + self, + invite_link: str, + creator: User, + is_primary: bool, + is_revoked: bool, + expire_date: datetime.datetime = None, + member_limit: int = None, + **_kwargs: Any, + ): + # Required + self.invite_link = invite_link + self.creator = creator + self.is_primary = is_primary + self.is_revoked = is_revoked + + # Optionals + self.expire_date = expire_date + self.member_limit = int(member_limit) if member_limit is not None else None + + self._id_attrs = (self.invite_link, self.creator, self.is_primary, self.is_revoked) + + @classmethod + def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['ChatInviteLink']: + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + if not data: + return None + + data['creator'] = User.de_json(data.get('creator'), bot) + data['expire_date'] = from_timestamp(data.get('expire_date', None)) + + return cls(**data) + + def to_dict(self) -> JSONDict: + """See :meth:`telegram.TelegramObject.to_dict`.""" + data = super().to_dict() + + data['expire_date'] = to_timestamp(self.expire_date) + + return data diff --git a/venv/lib/python3.8/site-packages/telegram/chatlocation.py b/venv/lib/python3.8/site-packages/telegram/chatlocation.py new file mode 100644 index 0000000..dcdbb6f --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/chatlocation.py @@ -0,0 +1,73 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a location to which a chat is connected.""" + +from typing import TYPE_CHECKING, Any, Optional + +from telegram import TelegramObject +from telegram.utils.types import JSONDict + +from .files.location import Location + +if TYPE_CHECKING: + from telegram import Bot + + +class ChatLocation(TelegramObject): + """This object represents a location to which a chat is connected. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`location` is equal. + + Args: + location (:class:`telegram.Location`): The location to which the supergroup is connected. + Can't be a live location. + address (:obj:`str`): Location address; 1-64 characters, as defined by the chat owner + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + location (:class:`telegram.Location`): The location to which the supergroup is connected. + address (:obj:`str`): Location address, as defined by the chat owner + + """ + + __slots__ = ('location', '_id_attrs', 'address') + + def __init__( + self, + location: Location, + address: str, + **_kwargs: Any, + ): + self.location = location + self.address = address + + self._id_attrs = (self.location,) + + @classmethod + def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['ChatLocation']: + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + if not data: + return None + + data['location'] = Location.de_json(data.get('location'), bot) + + return cls(bot=bot, **data) diff --git a/venv/lib/python3.8/site-packages/telegram/chatmember.py b/venv/lib/python3.8/site-packages/telegram/chatmember.py new file mode 100644 index 0000000..3246c4b --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/chatmember.py @@ -0,0 +1,253 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram ChatMember.""" +import datetime +from typing import TYPE_CHECKING, Any, Optional, ClassVar + +from telegram import TelegramObject, User, constants +from telegram.utils.helpers import from_timestamp, to_timestamp +from telegram.utils.types import JSONDict + +if TYPE_CHECKING: + from telegram import Bot + + +class ChatMember(TelegramObject): + """This object contains information about one member of a chat. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`user` and :attr:`status` are equal. + + Args: + user (:class:`telegram.User`): Information about the user. + status (:obj:`str`): The member's status in the chat. Can be 'creator', 'administrator', + 'member', 'restricted', 'left' or 'kicked'. + custom_title (:obj:`str`, optional): Owner and administrators only. + Custom title for this user. + is_anonymous (:obj:`bool`, optional): Owner and administrators only. :obj:`True`, if the + user's presence in the chat is hidden. + until_date (:class:`datetime.datetime`, optional): Restricted and kicked only. Date when + restrictions will be lifted for this user. + can_be_edited (:obj:`bool`, optional): Administrators only. :obj:`True`, if the bot is + allowed to edit administrator privileges of that user. + can_manage_chat (:obj:`bool`, optional): Administrators only. :obj:`True`, if the + administrator can access the chat event log, chat statistics, message statistics in + channels, see channel members, see anonymous administrators in supergroups and ignore + slow mode. Implied by any other administrator privilege. + + .. versionadded:: 13.4 + + can_manage_voice_chats (:obj:`bool`, optional): Administrators only. :obj:`True`, if the + administrator can manage voice chats. + + .. versionadded:: 13.4 + + can_change_info (:obj:`bool`, optional): Administrators and restricted only. :obj:`True`, + if the user can change the chat title, photo and other settings. + can_post_messages (:obj:`bool`, optional): Administrators only. :obj:`True`, if the + administrator can post in the channel, channels only. + can_edit_messages (:obj:`bool`, optional): Administrators only. :obj:`True`, if the + administrator can edit messages of other users and can pin messages; channels only. + can_delete_messages (:obj:`bool`, optional): Administrators only. :obj:`True`, if the + administrator can delete messages of other users. + can_invite_users (:obj:`bool`, optional): Administrators and restricted only. :obj:`True`, + if the user can invite new users to the chat. + can_restrict_members (:obj:`bool`, optional): Administrators only. :obj:`True`, if the + administrator can restrict, ban or unban chat members. + can_pin_messages (:obj:`bool`, optional): Administrators and restricted only. :obj:`True`, + if the user can pin messages, groups and supergroups only. + can_promote_members (:obj:`bool`, optional): Administrators only. :obj:`True`, if the + administrator can add new administrators with a subset of his own privileges or demote + administrators that he has promoted, directly or indirectly (promoted by administrators + that were appointed by the user). + is_member (:obj:`bool`, optional): Restricted only. :obj:`True`, if the user is a member of + the chat at the moment of the request. + can_send_messages (:obj:`bool`, optional): Restricted only. :obj:`True`, if the user can + send text messages, contacts, locations and venues. + can_send_media_messages (:obj:`bool`, optional): Restricted only. :obj:`True`, if the user + can send audios, documents, photos, videos, video notes and voice notes. + can_send_polls (:obj:`bool`, optional): Restricted only. :obj:`True`, if the user is + allowed to send polls. + can_send_other_messages (:obj:`bool`, optional): Restricted only. :obj:`True`, if the user + can send animations, games, stickers and use inline bots. + can_add_web_page_previews (:obj:`bool`, optional): Restricted only. :obj:`True`, if user + may add web page previews to his messages. + + Attributes: + user (:class:`telegram.User`): Information about the user. + status (:obj:`str`): The member's status in the chat. + custom_title (:obj:`str`): Optional. Custom title for owner and administrators. + is_anonymous (:obj:`bool`): Optional. :obj:`True`, if the user's presence in the chat is + hidden. + until_date (:class:`datetime.datetime`): Optional. Date when restrictions will be lifted + for this user. + can_be_edited (:obj:`bool`): Optional. If the bot is allowed to edit administrator + privileges of that user. + can_manage_chat (:obj:`bool`): Optional. If the administrator can access the chat event + log, chat statistics, message statistics in channels, see channel members, see + anonymous administrators in supergroups and ignore slow mode. + + .. versionadded:: 13.4 + + can_manage_voice_chats (:obj:`bool`): Optional. if the administrator can manage + voice chats. + + .. versionadded:: 13.4 + + can_change_info (:obj:`bool`): Optional. If the user can change the chat title, photo and + other settings. + can_post_messages (:obj:`bool`): Optional. If the administrator can post in the channel. + can_edit_messages (:obj:`bool`): Optional. If the administrator can edit messages of other + users. + can_delete_messages (:obj:`bool`): Optional. If the administrator can delete messages of + other users. + can_invite_users (:obj:`bool`): Optional. If the user can invite new users to the chat. + can_restrict_members (:obj:`bool`): Optional. If the administrator can restrict, ban or + unban chat members. + can_pin_messages (:obj:`bool`): Optional. If the user can pin messages. + can_promote_members (:obj:`bool`): Optional. If the administrator can add new + administrators. + is_member (:obj:`bool`): Optional. Restricted only. :obj:`True`, if the user is a member of + the chat at the moment of the request. + can_send_messages (:obj:`bool`): Optional. If the user can send text messages, contacts, + locations and venues. + can_send_media_messages (:obj:`bool`): Optional. If the user can send media messages, + implies can_send_messages. + can_send_polls (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to + send polls. + can_send_other_messages (:obj:`bool`): Optional. If the user can send animations, games, + stickers and use inline bots, implies can_send_media_messages. + can_add_web_page_previews (:obj:`bool`): Optional. If user may add web page previews to his + messages, implies can_send_media_messages + + """ + + __slots__ = ( + 'is_member', + 'can_restrict_members', + 'can_delete_messages', + 'custom_title', + 'can_be_edited', + 'can_post_messages', + 'can_send_messages', + 'can_edit_messages', + 'can_send_media_messages', + 'is_anonymous', + 'can_add_web_page_previews', + 'can_send_other_messages', + 'can_invite_users', + 'can_send_polls', + 'user', + 'can_promote_members', + 'status', + 'can_change_info', + 'can_pin_messages', + 'can_manage_chat', + 'can_manage_voice_chats', + 'until_date', + '_id_attrs', + ) + + ADMINISTRATOR: ClassVar[str] = constants.CHATMEMBER_ADMINISTRATOR + """:const:`telegram.constants.CHATMEMBER_ADMINISTRATOR`""" + CREATOR: ClassVar[str] = constants.CHATMEMBER_CREATOR + """:const:`telegram.constants.CHATMEMBER_CREATOR`""" + KICKED: ClassVar[str] = constants.CHATMEMBER_KICKED + """:const:`telegram.constants.CHATMEMBER_KICKED`""" + LEFT: ClassVar[str] = constants.CHATMEMBER_LEFT + """:const:`telegram.constants.CHATMEMBER_LEFT`""" + MEMBER: ClassVar[str] = constants.CHATMEMBER_MEMBER + """:const:`telegram.constants.CHATMEMBER_MEMBER`""" + RESTRICTED: ClassVar[str] = constants.CHATMEMBER_RESTRICTED + """:const:`telegram.constants.CHATMEMBER_RESTRICTED`""" + + def __init__( + self, + user: User, + status: str, + until_date: datetime.datetime = None, + can_be_edited: bool = None, + can_change_info: bool = None, + can_post_messages: bool = None, + can_edit_messages: bool = None, + can_delete_messages: bool = None, + can_invite_users: bool = None, + can_restrict_members: bool = None, + can_pin_messages: bool = None, + can_promote_members: bool = None, + can_send_messages: bool = None, + can_send_media_messages: bool = None, + can_send_polls: bool = None, + can_send_other_messages: bool = None, + can_add_web_page_previews: bool = None, + is_member: bool = None, + custom_title: str = None, + is_anonymous: bool = None, + can_manage_chat: bool = None, + can_manage_voice_chats: bool = None, + **_kwargs: Any, + ): + # Required + self.user = user + self.status = status + + # Optionals + self.custom_title = custom_title + self.is_anonymous = is_anonymous + self.until_date = until_date + self.can_be_edited = can_be_edited + self.can_change_info = can_change_info + self.can_post_messages = can_post_messages + self.can_edit_messages = can_edit_messages + self.can_delete_messages = can_delete_messages + self.can_invite_users = can_invite_users + self.can_restrict_members = can_restrict_members + self.can_pin_messages = can_pin_messages + self.can_promote_members = can_promote_members + self.can_send_messages = can_send_messages + self.can_send_media_messages = can_send_media_messages + self.can_send_polls = can_send_polls + self.can_send_other_messages = can_send_other_messages + self.can_add_web_page_previews = can_add_web_page_previews + self.is_member = is_member + self.can_manage_chat = can_manage_chat + self.can_manage_voice_chats = can_manage_voice_chats + + self._id_attrs = (self.user, self.status) + + @classmethod + def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['ChatMember']: + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + if not data: + return None + + data['user'] = User.de_json(data.get('user'), bot) + data['until_date'] = from_timestamp(data.get('until_date', None)) + + return cls(**data) + + def to_dict(self) -> JSONDict: + """See :meth:`telegram.TelegramObject.to_dict`.""" + data = super().to_dict() + + data['until_date'] = to_timestamp(self.until_date) + + return data diff --git a/venv/lib/python3.8/site-packages/telegram/chatmemberupdated.py b/venv/lib/python3.8/site-packages/telegram/chatmemberupdated.py new file mode 100644 index 0000000..4d49a6c --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/chatmemberupdated.py @@ -0,0 +1,173 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram ChatMemberUpdated.""" +import datetime +from typing import TYPE_CHECKING, Any, Optional, Dict, Tuple, Union + +from telegram import TelegramObject, User, Chat, ChatMember, ChatInviteLink +from telegram.utils.helpers import from_timestamp, to_timestamp +from telegram.utils.types import JSONDict + +if TYPE_CHECKING: + from telegram import Bot + + +class ChatMemberUpdated(TelegramObject): + """This object represents changes in the status of a chat member. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`chat`, :attr:`from_user`, :attr:`date`, + :attr:`old_chat_member` and :attr:`new_chat_member` are equal. + + .. versionadded:: 13.4 + + Note: + In Python ``from`` is a reserved word, use ``from_user`` instead. + + Args: + chat (:class:`telegram.Chat`): Chat the user belongs to. + from_user (:class:`telegram.User`): Performer of the action, which resulted in the change. + date (:class:`datetime.datetime`): Date the change was done in Unix time. Converted to + :class:`datetime.datetime`. + old_chat_member (:class:`telegram.ChatMember`): Previous information about the chat member. + new_chat_member (:class:`telegram.ChatMember`): New information about the chat member. + invite_link (:class:`telegram.ChatInviteLink`, optional): Chat invite link, which was used + by the user to join the chat. For joining by invite link events only. + + Attributes: + chat (:class:`telegram.Chat`): Chat the user belongs to. + from_user (:class:`telegram.User`): Performer of the action, which resulted in the change. + date (:class:`datetime.datetime`): Date the change was done in Unix time. Converted to + :class:`datetime.datetime`. + old_chat_member (:class:`telegram.ChatMember`): Previous information about the chat member. + new_chat_member (:class:`telegram.ChatMember`): New information about the chat member. + invite_link (:class:`telegram.ChatInviteLink`): Optional. Chat invite link, which was used + by the user to join the chat. + + """ + + __slots__ = ( + 'chat', + 'from_user', + 'date', + 'old_chat_member', + 'new_chat_member', + 'invite_link', + '_id_attrs', + ) + + def __init__( + self, + chat: Chat, + from_user: User, + date: datetime.datetime, + old_chat_member: ChatMember, + new_chat_member: ChatMember, + invite_link: ChatInviteLink = None, + **_kwargs: Any, + ): + # Required + self.chat = chat + self.from_user = from_user + self.date = date + self.old_chat_member = old_chat_member + self.new_chat_member = new_chat_member + + # Optionals + self.invite_link = invite_link + + self._id_attrs = ( + self.chat, + self.from_user, + self.date, + self.old_chat_member, + self.new_chat_member, + ) + + @classmethod + def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['ChatMemberUpdated']: + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + if not data: + return None + + data['chat'] = Chat.de_json(data.get('chat'), bot) + data['from_user'] = User.de_json(data.get('from'), bot) + data['date'] = from_timestamp(data.get('date')) + data['old_chat_member'] = ChatMember.de_json(data.get('old_chat_member'), bot) + data['new_chat_member'] = ChatMember.de_json(data.get('new_chat_member'), bot) + data['invite_link'] = ChatInviteLink.de_json(data.get('invite_link'), bot) + + return cls(**data) + + def to_dict(self) -> JSONDict: + """See :meth:`telegram.TelegramObject.to_dict`.""" + data = super().to_dict() + + # Required + data['date'] = to_timestamp(self.date) + + return data + + def difference( + self, + ) -> Dict[ + str, + Tuple[ + Union[str, bool, datetime.datetime, User], Union[str, bool, datetime.datetime, User] + ], + ]: + """Computes the difference between :attr:`old_chat_member` and :attr:`new_chat_member`. + + Example: + .. code:: python + + >>> chat_member_updated.difference() + {'custom_title': ('old title', 'new title')} + + Note: + To determine, if the :attr:`telegram.ChatMember.user` attribute has changed, *every* + attribute of the user will be checked. + + .. versionadded:: 13.5 + + Returns: + Dict[:obj:`str`, Tuple[:obj:`obj`, :obj:`obj`]]: A dictionary mapping attribute names + to tuples of the form ``(old_value, new_value)`` + """ + # we first get the names of the attributes that have changed + # user.to_dict() is unhashable, so that needs some special casing further down + old_dict = self.old_chat_member.to_dict() + old_user_dict = old_dict.pop('user') + new_dict = self.new_chat_member.to_dict() + new_user_dict = new_dict.pop('user') + + # Generator for speed: we only need to iterate over it once + # we can't directly use the values from old_dict ^ new_dict b/c that set is unordered + attributes = (entry[0] for entry in set(old_dict.items()) ^ set(new_dict.items())) + + result = { + attribute: (self.old_chat_member[attribute], self.new_chat_member[attribute]) + for attribute in attributes + } + if old_user_dict != new_user_dict: + result['user'] = (self.old_chat_member.user, self.new_chat_member.user) + + return result # type: ignore[return-value] diff --git a/venv/lib/python3.8/site-packages/telegram/chatpermissions.py b/venv/lib/python3.8/site-packages/telegram/chatpermissions.py new file mode 100644 index 0000000..0b5a7b9 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/chatpermissions.py @@ -0,0 +1,124 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram ChatPermission.""" + +from typing import Any + +from telegram import TelegramObject + + +class ChatPermissions(TelegramObject): + """Describes actions that a non-administrator user is allowed to take in a chat. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`can_send_messages`, :attr:`can_send_media_messages`, + :attr:`can_send_polls`, :attr:`can_send_other_messages`, :attr:`can_add_web_page_previews`, + :attr:`can_change_info`, :attr:`can_invite_users` and :attr:`can_pin_messages` are equal. + + Note: + Though not stated explicitly in the official docs, Telegram changes not only the + permissions that are set, but also sets all the others to :obj:`False`. However, since not + documented, this behaviour may change unbeknown to PTB. + + Args: + can_send_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed to send text + messages, contacts, locations and venues. + can_send_media_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed to + send audios, documents, photos, videos, video notes and voice notes, implies + :attr:`can_send_messages`. + can_send_polls (:obj:`bool`, optional): :obj:`True`, if the user is allowed to send polls, + implies :attr:`can_send_messages`. + can_send_other_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed to + send animations, games, stickers and use inline bots, implies + :attr:`can_send_media_messages`. + can_add_web_page_previews (:obj:`bool`, optional): :obj:`True`, if the user is allowed to + add web page previews to their messages, implies :attr:`can_send_media_messages`. + can_change_info (:obj:`bool`, optional): :obj:`True`, if the user is allowed to change the + chat title, photo and other settings. Ignored in public supergroups. + can_invite_users (:obj:`bool`, optional): :obj:`True`, if the user is allowed to invite new + users to the chat. + can_pin_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed to pin + messages. Ignored in public supergroups. + + Attributes: + can_send_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to send text + messages, contacts, locations and venues. + can_send_media_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to + send audios, documents, photos, videos, video notes and voice notes, implies + :attr:`can_send_messages`. + can_send_polls (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to send polls, + implies :attr:`can_send_messages`. + can_send_other_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to + send animations, games, stickers and use inline bots, implies + :attr:`can_send_media_messages`. + can_add_web_page_previews (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to + add web page previews to their messages, implies :attr:`can_send_media_messages`. + can_change_info (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to change the + chat title, photo and other settings. Ignored in public supergroups. + can_invite_users (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to invite + new users to the chat. + can_pin_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to pin + messages. Ignored in public supergroups. + + """ + + __slots__ = ( + 'can_send_other_messages', + 'can_invite_users', + 'can_send_polls', + '_id_attrs', + 'can_send_messages', + 'can_send_media_messages', + 'can_change_info', + 'can_pin_messages', + 'can_add_web_page_previews', + ) + + def __init__( + self, + can_send_messages: bool = None, + can_send_media_messages: bool = None, + can_send_polls: bool = None, + can_send_other_messages: bool = None, + can_add_web_page_previews: bool = None, + can_change_info: bool = None, + can_invite_users: bool = None, + can_pin_messages: bool = None, + **_kwargs: Any, + ): + # Required + self.can_send_messages = can_send_messages + self.can_send_media_messages = can_send_media_messages + self.can_send_polls = can_send_polls + self.can_send_other_messages = can_send_other_messages + self.can_add_web_page_previews = can_add_web_page_previews + self.can_change_info = can_change_info + self.can_invite_users = can_invite_users + self.can_pin_messages = can_pin_messages + + self._id_attrs = ( + self.can_send_messages, + self.can_send_media_messages, + self.can_send_polls, + self.can_send_other_messages, + self.can_add_web_page_previews, + self.can_change_info, + self.can_invite_users, + self.can_pin_messages, + ) diff --git a/venv/lib/python3.8/site-packages/telegram/choseninlineresult.py b/venv/lib/python3.8/site-packages/telegram/choseninlineresult.py new file mode 100644 index 0000000..384d57e --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/choseninlineresult.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python +# pylint: disable=R0902,R0913 +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram ChosenInlineResult.""" + +from typing import TYPE_CHECKING, Any, Optional + +from telegram import Location, TelegramObject, User +from telegram.utils.types import JSONDict + +if TYPE_CHECKING: + from telegram import Bot + + +class ChosenInlineResult(TelegramObject): + """ + Represents a result of an inline query that was chosen by the user and sent to their chat + partner. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`result_id` is equal. + + Note: + * In Python ``from`` is a reserved word, use ``from_user`` instead. + * It is necessary to enable inline feedback via `@Botfather <https://t.me/BotFather>`_ in + order to receive these objects in updates. + + Args: + result_id (:obj:`str`): The unique identifier for the result that was chosen. + from_user (:class:`telegram.User`): The user that chose the result. + location (:class:`telegram.Location`, optional): Sender location, only for bots that + require user location. + inline_message_id (:obj:`str`, optional): Identifier of the sent inline message. Available + only if there is an inline keyboard attached to the message. Will be also received in + callback queries and can be used to edit the message. + query (:obj:`str`): The query that was used to obtain the result. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + result_id (:obj:`str`): The unique identifier for the result that was chosen. + from_user (:class:`telegram.User`): The user that chose the result. + location (:class:`telegram.Location`): Optional. Sender location. + inline_message_id (:obj:`str`): Optional. Identifier of the sent inline message. + query (:obj:`str`): The query that was used to obtain the result. + + """ + + __slots__ = ('location', 'result_id', 'from_user', 'inline_message_id', '_id_attrs', 'query') + + def __init__( + self, + result_id: str, + from_user: User, + query: str, + location: Location = None, + inline_message_id: str = None, + **_kwargs: Any, + ): + # Required + self.result_id = result_id + self.from_user = from_user + self.query = query + # Optionals + self.location = location + self.inline_message_id = inline_message_id + + self._id_attrs = (self.result_id,) + + @classmethod + def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['ChosenInlineResult']: + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + if not data: + return None + + # Required + data['from_user'] = User.de_json(data.pop('from'), bot) + # Optionals + data['location'] = Location.de_json(data.get('location'), bot) + + return cls(**data) diff --git a/venv/lib/python3.8/site-packages/telegram/constants.py b/venv/lib/python3.8/site-packages/telegram/constants.py new file mode 100644 index 0000000..02cb2d2 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/constants.py @@ -0,0 +1,345 @@ +# python-telegram-bot - a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# by the python-telegram-bot contributors <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""Constants in the Telegram network. + +The following constants were extracted from the +`Telegram Bots FAQ <https://core.telegram.org/bots/faq>`_ and +`Telegram Bots API <https://core.telegram.org/bots/api>`_. + +Attributes: + BOT_API_VERSION (:obj:`str`): `5.2`. Telegram Bot API version supported by this + version of `python-telegram-bot`. Also available as ``telegram.bot_api_version``. + + .. versionadded:: 13.4 + MAX_MESSAGE_LENGTH (:obj:`int`): 4096 + MAX_CAPTION_LENGTH (:obj:`int`): 1024 + SUPPORTED_WEBHOOK_PORTS (List[:obj:`int`]): [443, 80, 88, 8443] + MAX_FILESIZE_DOWNLOAD (:obj:`int`): In bytes (20MB) + MAX_FILESIZE_UPLOAD (:obj:`int`): In bytes (50MB) + MAX_PHOTOSIZE_UPLOAD (:obj:`int`): In bytes (10MB) + MAX_MESSAGES_PER_SECOND_PER_CHAT (:obj:`int`): `1`. Telegram may allow short bursts that go + over this limit, but eventually you'll begin receiving 429 errors. + MAX_MESSAGES_PER_SECOND (:obj:`int`): 30 + MAX_MESSAGES_PER_MINUTE_PER_GROUP (:obj:`int`): 20 + MAX_INLINE_QUERY_RESULTS (:obj:`int`): 50 + MAX_ANSWER_CALLBACK_QUERY_TEXT_LENGTH (:obj:`int`): 200 + + .. versionadded:: 13.2 + +The following constant have been found by experimentation: + +Attributes: + MAX_MESSAGE_ENTITIES (:obj:`int`): 100 (Beyond this cap telegram will simply ignore further + formatting styles) + ANONYMOUS_ADMIN_ID (:obj:`int`): ``1087968824`` (User id in groups for anonymous admin) + SERVICE_CHAT_ID (:obj:`int`): ``777000`` (Telegram service chat, that also acts as sender of + channel posts forwarded to discussion groups) + +The following constants are related to specific classes and are also available +as attributes of those classes: + +:class:`telegram.Chat`: + +Attributes: + CHAT_PRIVATE (:obj:`str`): ``'private'`` + CHAT_GROUP (:obj:`str`): ``'group'`` + CHAT_SUPERGROUP (:obj:`str`): ``'supergroup'`` + CHAT_CHANNEL (:obj:`str`): ``'channel'`` + CHAT_SENDER (:obj:`str`): ``'sender'``. Only relevant for + :attr:`telegram.InlineQuery.chat_type`. + + .. versionadded:: 13.5 + +:class:`telegram.ChatAction`: + +Attributes: + CHATACTION_FIND_LOCATION (:obj:`str`): ``'find_location'`` + CHATACTION_RECORD_AUDIO (:obj:`str`): ``'record_audio'`` + + .. deprecated:: 13.5 + Deprecated by Telegram. Use :const:`CHATACTION_RECORD_VOICE` instead. + CHATACTION_RECORD_VOICE (:obj:`str`): ``'record_voice'`` + + .. versionadded:: 13.5 + CHATACTION_RECORD_VIDEO (:obj:`str`): ``'record_video'`` + CHATACTION_RECORD_VIDEO_NOTE (:obj:`str`): ``'record_video_note'`` + CHATACTION_TYPING (:obj:`str`): ``'typing'`` + CHATACTION_UPLOAD_AUDIO (:obj:`str`): ``'upload_audio'`` + + .. deprecated:: 13.5 + Deprecated by Telegram. Use :const:`CHATACTION_UPLOAD_VOICE` instead. + CHATACTION_UPLOAD_VOICE (:obj:`str`): ``'upload_voice'`` + + .. versionadded:: 13.5 + CHATACTION_UPLOAD_DOCUMENT (:obj:`str`): ``'upload_document'`` + CHATACTION_UPLOAD_PHOTO (:obj:`str`): ``'upload_photo'`` + CHATACTION_UPLOAD_VIDEO (:obj:`str`): ``'upload_video'`` + CHATACTION_UPLOAD_VIDEO_NOTE (:obj:`str`): ``'upload_video_note'`` + +:class:`telegram.ChatMember`: + +Attributes: + CHATMEMBER_ADMINISTRATOR (:obj:`str`): ``'administrator'`` + CHATMEMBER_CREATOR (:obj:`str`): ``'creator'`` + CHATMEMBER_KICKED (:obj:`str`): ``'kicked'`` + CHATMEMBER_LEFT (:obj:`str`): ``'left'`` + CHATMEMBER_MEMBER (:obj:`str`): ``'member'`` + CHATMEMBER_RESTRICTED (:obj:`str`): ``'restricted'`` + +:class:`telegram.Dice`: + +Attributes: + DICE_DICE (:obj:`str`): ``'🎲'`` + DICE_DARTS (:obj:`str`): ``'🎯'`` + DICE_BASKETBALL (:obj:`str`): ``'🏀'`` + DICE_FOOTBALL (:obj:`str`): ``'⚽'`` + DICE_SLOT_MACHINE (:obj:`str`): ``'🎰'`` + DICE_BOWLING (:obj:`str`): ``'🎳'`` + + .. versionadded:: 13.4 + DICE_ALL_EMOJI (List[:obj:`str`]): List of all supported base emoji. + + .. versionchanged:: 13.4 + Added :attr:`DICE_BOWLING` + +:class:`telegram.MessageEntity`: + +Attributes: + MESSAGEENTITY_MENTION (:obj:`str`): ``'mention'`` + MESSAGEENTITY_HASHTAG (:obj:`str`): ``'hashtag'`` + MESSAGEENTITY_CASHTAG (:obj:`str`): ``'cashtag'`` + MESSAGEENTITY_PHONE_NUMBER (:obj:`str`): ``'phone_number'`` + MESSAGEENTITY_BOT_COMMAND (:obj:`str`): ``'bot_command'`` + MESSAGEENTITY_URL (:obj:`str`): ``'url'`` + MESSAGEENTITY_EMAIL (:obj:`str`): ``'email'`` + MESSAGEENTITY_BOLD (:obj:`str`): ``'bold'`` + MESSAGEENTITY_ITALIC (:obj:`str`): ``'italic'`` + MESSAGEENTITY_CODE (:obj:`str`): ``'code'`` + MESSAGEENTITY_PRE (:obj:`str`): ``'pre'`` + MESSAGEENTITY_TEXT_LINK (:obj:`str`): ``'text_link'`` + MESSAGEENTITY_TEXT_MENTION (:obj:`str`): ``'text_mention'`` + MESSAGEENTITY_UNDERLINE (:obj:`str`): ``'underline'`` + MESSAGEENTITY_STRIKETHROUGH (:obj:`str`): ``'strikethrough'`` + MESSAGEENTITY_ALL_TYPES (List[:obj:`str`]): List of all the types of message entity. + +:class:`telegram.ParseMode`: + +Attributes: + PARSEMODE_MARKDOWN (:obj:`str`): ``'Markdown'`` + PARSEMODE_MARKDOWN_V2 (:obj:`str`): ``'MarkdownV2'`` + PARSEMODE_HTML (:obj:`str`): ``'HTML'`` + +:class:`telegram.Poll`: + +Attributes: + POLL_REGULAR (:obj:`str`): ``'regular'`` + POLL_QUIZ (:obj:`str`): ``'quiz'`` + MAX_POLL_QUESTION_LENGTH (:obj:`int`): 300 + MAX_POLL_OPTION_LENGTH (:obj:`int`): 100 + +:class:`telegram.MaskPosition`: + +Attributes: + STICKER_FOREHEAD (:obj:`str`): ``'forehead'`` + STICKER_EYES (:obj:`str`): ``'eyes'`` + STICKER_MOUTH (:obj:`str`): ``'mouth'`` + STICKER_CHIN (:obj:`str`): ``'chin'`` + +:class:`telegram.Update`: + +Attributes: + UPDATE_MESSAGE (:obj:`str`): ``'message'`` + + .. versionadded:: 13.5 + UPDATE_EDITED_MESSAGE (:obj:`str`): ``'edited_message'`` + + .. versionadded:: 13.5 + UPDATE_CHANNEL_POST (:obj:`str`): ``'channel_post'`` + + .. versionadded:: 13.5 + UPDATE_EDITED_CHANNEL_POST (:obj:`str`): ``'edited_channel_post'`` + + .. versionadded:: 13.5 + UPDATE_INLINE_QUERY (:obj:`str`): ``'inline_query'`` + + .. versionadded:: 13.5 + UPDATE_CHOSEN_INLINE_RESULT (:obj:`str`): ``'chosen_inline_result'`` + + .. versionadded:: 13.5 + UPDATE_CALLBACK_QUERY (:obj:`str`): ``'callback_query'`` + + .. versionadded:: 13.5 + UPDATE_SHIPPING_QUERY (:obj:`str`): ``'shipping_query'`` + + .. versionadded:: 13.5 + UPDATE_PRE_CHECKOUT_QUERY (:obj:`str`): ``'pre_checkout_query'`` + + .. versionadded:: 13.5 + UPDATE_POLL (:obj:`str`): ``'poll'`` + + .. versionadded:: 13.5 + UPDATE_POLL_ANSWER (:obj:`str`): ``'poll_answer'`` + + .. versionadded:: 13.5 + UPDATE_MY_CHAT_MEMBER (:obj:`str`): ``'my_chat_member'`` + + .. versionadded:: 13.5 + UPDATE_CHAT_MEMBER (:obj:`str`): ``'chat_member'`` + + .. versionadded:: 13.5 + UPDATE_ALL_TYPES (List[:obj:`str`]): List of all update types. + + .. versionadded:: 13.5 + +""" +from typing import List + +BOT_API_VERSION: str = '5.2' +MAX_MESSAGE_LENGTH: int = 4096 +MAX_CAPTION_LENGTH: int = 1024 +ANONYMOUS_ADMIN_ID: int = 1087968824 +SERVICE_CHAT_ID: int = 777000 + +# constants above this line are tested + +SUPPORTED_WEBHOOK_PORTS: List[int] = [443, 80, 88, 8443] +MAX_FILESIZE_DOWNLOAD: int = int(20e6) # (20MB) +MAX_FILESIZE_UPLOAD: int = int(50e6) # (50MB) +MAX_PHOTOSIZE_UPLOAD: int = int(10e6) # (10MB) +MAX_MESSAGES_PER_SECOND_PER_CHAT: int = 1 +MAX_MESSAGES_PER_SECOND: int = 30 +MAX_MESSAGES_PER_MINUTE_PER_GROUP: int = 20 +MAX_MESSAGE_ENTITIES: int = 100 +MAX_INLINE_QUERY_RESULTS: int = 50 +MAX_ANSWER_CALLBACK_QUERY_TEXT_LENGTH: int = 200 + +CHAT_SENDER: str = 'sender' +CHAT_PRIVATE: str = 'private' +CHAT_GROUP: str = 'group' +CHAT_SUPERGROUP: str = 'supergroup' +CHAT_CHANNEL: str = 'channel' + +CHATACTION_FIND_LOCATION: str = 'find_location' +CHATACTION_RECORD_AUDIO: str = 'record_audio' +CHATACTION_RECORD_VOICE: str = 'record_voice' +CHATACTION_RECORD_VIDEO: str = 'record_video' +CHATACTION_RECORD_VIDEO_NOTE: str = 'record_video_note' +CHATACTION_TYPING: str = 'typing' +CHATACTION_UPLOAD_AUDIO: str = 'upload_audio' +CHATACTION_UPLOAD_VOICE: str = 'upload_voice' +CHATACTION_UPLOAD_DOCUMENT: str = 'upload_document' +CHATACTION_UPLOAD_PHOTO: str = 'upload_photo' +CHATACTION_UPLOAD_VIDEO: str = 'upload_video' +CHATACTION_UPLOAD_VIDEO_NOTE: str = 'upload_video_note' + +CHATMEMBER_ADMINISTRATOR: str = 'administrator' +CHATMEMBER_CREATOR: str = 'creator' +CHATMEMBER_KICKED: str = 'kicked' +CHATMEMBER_LEFT: str = 'left' +CHATMEMBER_MEMBER: str = 'member' +CHATMEMBER_RESTRICTED: str = 'restricted' + +DICE_DICE: str = '🎲' +DICE_DARTS: str = '🎯' +DICE_BASKETBALL: str = '🏀' +DICE_FOOTBALL: str = '⚽' +DICE_SLOT_MACHINE: str = '🎰' +DICE_BOWLING: str = '🎳' +DICE_ALL_EMOJI: List[str] = [ + DICE_DICE, + DICE_DARTS, + DICE_BASKETBALL, + DICE_FOOTBALL, + DICE_SLOT_MACHINE, + DICE_BOWLING, +] + +MESSAGEENTITY_MENTION: str = 'mention' +MESSAGEENTITY_HASHTAG: str = 'hashtag' +MESSAGEENTITY_CASHTAG: str = 'cashtag' +MESSAGEENTITY_PHONE_NUMBER: str = 'phone_number' +MESSAGEENTITY_BOT_COMMAND: str = 'bot_command' +MESSAGEENTITY_URL: str = 'url' +MESSAGEENTITY_EMAIL: str = 'email' +MESSAGEENTITY_BOLD: str = 'bold' +MESSAGEENTITY_ITALIC: str = 'italic' +MESSAGEENTITY_CODE: str = 'code' +MESSAGEENTITY_PRE: str = 'pre' +MESSAGEENTITY_TEXT_LINK: str = 'text_link' +MESSAGEENTITY_TEXT_MENTION: str = 'text_mention' +MESSAGEENTITY_UNDERLINE: str = 'underline' +MESSAGEENTITY_STRIKETHROUGH: str = 'strikethrough' +MESSAGEENTITY_ALL_TYPES: List[str] = [ + MESSAGEENTITY_MENTION, + MESSAGEENTITY_HASHTAG, + MESSAGEENTITY_CASHTAG, + MESSAGEENTITY_PHONE_NUMBER, + MESSAGEENTITY_BOT_COMMAND, + MESSAGEENTITY_URL, + MESSAGEENTITY_EMAIL, + MESSAGEENTITY_BOLD, + MESSAGEENTITY_ITALIC, + MESSAGEENTITY_CODE, + MESSAGEENTITY_PRE, + MESSAGEENTITY_TEXT_LINK, + MESSAGEENTITY_TEXT_MENTION, + MESSAGEENTITY_UNDERLINE, + MESSAGEENTITY_STRIKETHROUGH, +] + +PARSEMODE_MARKDOWN: str = 'Markdown' +PARSEMODE_MARKDOWN_V2: str = 'MarkdownV2' +PARSEMODE_HTML: str = 'HTML' + +POLL_REGULAR: str = 'regular' +POLL_QUIZ: str = 'quiz' +MAX_POLL_QUESTION_LENGTH: int = 300 +MAX_POLL_OPTION_LENGTH: int = 100 + +STICKER_FOREHEAD: str = 'forehead' +STICKER_EYES: str = 'eyes' +STICKER_MOUTH: str = 'mouth' +STICKER_CHIN: str = 'chin' + +UPDATE_MESSAGE = 'message' +UPDATE_EDITED_MESSAGE = 'edited_message' +UPDATE_CHANNEL_POST = 'channel_post' +UPDATE_EDITED_CHANNEL_POST = 'edited_channel_post' +UPDATE_INLINE_QUERY = 'inline_query' +UPDATE_CHOSEN_INLINE_RESULT = 'chosen_inline_result' +UPDATE_CALLBACK_QUERY = 'callback_query' +UPDATE_SHIPPING_QUERY = 'shipping_query' +UPDATE_PRE_CHECKOUT_QUERY = 'pre_checkout_query' +UPDATE_POLL = 'poll' +UPDATE_POLL_ANSWER = 'poll_answer' +UPDATE_MY_CHAT_MEMBER = 'my_chat_member' +UPDATE_CHAT_MEMBER = 'chat_member' +UPDATE_ALL_TYPES = [ + UPDATE_MESSAGE, + UPDATE_EDITED_MESSAGE, + UPDATE_CHANNEL_POST, + UPDATE_EDITED_CHANNEL_POST, + UPDATE_INLINE_QUERY, + UPDATE_CHOSEN_INLINE_RESULT, + UPDATE_CALLBACK_QUERY, + UPDATE_SHIPPING_QUERY, + UPDATE_PRE_CHECKOUT_QUERY, + UPDATE_POLL, + UPDATE_POLL_ANSWER, + UPDATE_MY_CHAT_MEMBER, + UPDATE_CHAT_MEMBER, +] diff --git a/venv/lib/python3.8/site-packages/telegram/dice.py b/venv/lib/python3.8/site-packages/telegram/dice.py new file mode 100644 index 0000000..3406cee --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/dice.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python +# pylint: disable=R0903 +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram Dice.""" +from typing import Any, List, ClassVar + +from telegram import TelegramObject, constants + + +class Dice(TelegramObject): + """ + This object represents an animated emoji with a random value for currently supported base + emoji. (The singular form of "dice" is "die". However, PTB mimics the Telegram API, which uses + the term "dice".) + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`value` and :attr:`emoji` are equal. + + Note: + If :attr:`emoji` is "🎯", a value of 6 currently represents a bullseye, while a value of 1 + indicates that the dartboard was missed. However, this behaviour is undocumented and might + be changed by Telegram. + + If :attr:`emoji` is "🏀", a value of 4 or 5 currently score a basket, while a value of 1 to + 3 indicates that the basket was missed. However, this behaviour is undocumented and might + be changed by Telegram. + + If :attr:`emoji` is "⚽", a value of 4 to 5 currently scores a goal, while a value of 1 to + 3 indicates that the goal was missed. However, this behaviour is undocumented and might + be changed by Telegram. + + If :attr:`emoji` is "🎳", a value of 6 knocks all the pins, while a value of 1 means all + the pins were missed. However, this behaviour is undocumented and might be changed by + Telegram. + + If :attr:`emoji` is "🎰", each value corresponds to a unique combination of symbols, which + can be found at our `wiki <https://git.io/JkeC6>`_. However, this behaviour is undocumented + and might be changed by Telegram. + + Args: + value (:obj:`int`): Value of the dice. 1-6 for dice, darts and bowling balls, 1-5 for + basketball and football/soccer ball, 1-64 for slot machine. + emoji (:obj:`str`): Emoji on which the dice throw animation is based. + + Attributes: + value (:obj:`int`): Value of the dice. + emoji (:obj:`str`): Emoji on which the dice throw animation is based. + + """ + + __slots__ = ('emoji', 'value', '_id_attrs') + + def __init__(self, value: int, emoji: str, **_kwargs: Any): + self.value = value + self.emoji = emoji + + self._id_attrs = (self.value, self.emoji) + + DICE: ClassVar[str] = constants.DICE_DICE # skipcq: PTC-W0052 + """:const:`telegram.constants.DICE_DICE`""" + DARTS: ClassVar[str] = constants.DICE_DARTS + """:const:`telegram.constants.DICE_DARTS`""" + BASKETBALL: ClassVar[str] = constants.DICE_BASKETBALL + """:const:`telegram.constants.DICE_BASKETBALL`""" + FOOTBALL: ClassVar[str] = constants.DICE_FOOTBALL + """:const:`telegram.constants.DICE_FOOTBALL`""" + SLOT_MACHINE: ClassVar[str] = constants.DICE_SLOT_MACHINE + """:const:`telegram.constants.DICE_SLOT_MACHINE`""" + BOWLING: ClassVar[str] = constants.DICE_BOWLING + """ + :const:`telegram.constants.DICE_BOWLING` + + .. versionadded:: 13.4 + """ + ALL_EMOJI: ClassVar[List[str]] = constants.DICE_ALL_EMOJI + """:const:`telegram.constants.DICE_ALL_EMOJI`""" diff --git a/venv/lib/python3.8/site-packages/telegram/error.py b/venv/lib/python3.8/site-packages/telegram/error.py new file mode 100644 index 0000000..5e597cd --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/error.py @@ -0,0 +1,151 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +# pylint: disable=C0115 +"""This module contains an object that represents Telegram errors.""" +from typing import Tuple + + +def _lstrip_str(in_s: str, lstr: str) -> str: + """ + Args: + in_s (:obj:`str`): in string + lstr (:obj:`str`): substr to strip from left side + + Returns: + :obj:`str`: The stripped string. + + """ + if in_s.startswith(lstr): + res = in_s[len(lstr) :] + else: + res = in_s + return res + + +class TelegramError(Exception): + """Base class for Telegram errors.""" + + # Apparently the base class Exception already has __dict__ in it, so its not included here + __slots__ = ('message',) + + def __init__(self, message: str): + super().__init__() + + msg = _lstrip_str(message, 'Error: ') + msg = _lstrip_str(msg, '[Error]: ') + msg = _lstrip_str(msg, 'Bad Request: ') + if msg != message: + # api_error - capitalize the msg... + msg = msg.capitalize() + self.message = msg + + def __str__(self) -> str: + return '%s' % self.message + + def __reduce__(self) -> Tuple[type, Tuple[str]]: + return self.__class__, (self.message,) + + +class Unauthorized(TelegramError): + """Raised when the bot has not enough rights to perform the requested action.""" + + __slots__ = () + + +class InvalidToken(TelegramError): + """Raised when the token is invalid.""" + + __slots__ = () + + def __init__(self) -> None: + super().__init__('Invalid token') + + def __reduce__(self) -> Tuple[type, Tuple]: # type: ignore[override] + return self.__class__, () + + +class NetworkError(TelegramError): + """Base class for exceptions due to networking errors.""" + + __slots__ = () + + +class BadRequest(NetworkError): + """Raised when Telegram could not process the request correctly.""" + + __slots__ = () + + +class TimedOut(NetworkError): + """Raised when a request took too long to finish.""" + + __slots__ = () + + def __init__(self) -> None: + super().__init__('Timed out') + + def __reduce__(self) -> Tuple[type, Tuple]: # type: ignore[override] + return self.__class__, () + + +class ChatMigrated(TelegramError): + """ + Raised when the requested group chat migrated to supergroup and has a new chat id. + + Args: + new_chat_id (:obj:`int`): The new chat id of the group. + + """ + + __slots__ = ('new_chat_id',) + + def __init__(self, new_chat_id: int): + super().__init__(f'Group migrated to supergroup. New chat id: {new_chat_id}') + self.new_chat_id = new_chat_id + + def __reduce__(self) -> Tuple[type, Tuple[int]]: # type: ignore[override] + return self.__class__, (self.new_chat_id,) + + +class RetryAfter(TelegramError): + """ + Raised when flood limits where exceeded. + + Args: + retry_after (:obj:`int`): Time in seconds, after which the bot can retry the request. + + """ + + __slots__ = ('retry_after',) + + def __init__(self, retry_after: int): + super().__init__(f'Flood control exceeded. Retry in {float(retry_after)} seconds') + self.retry_after = float(retry_after) + + def __reduce__(self) -> Tuple[type, Tuple[float]]: # type: ignore[override] + return self.__class__, (self.retry_after,) + + +class Conflict(TelegramError): + """Raised when a long poll or webhook conflicts with another one.""" + + __slots__ = () + + def __reduce__(self) -> Tuple[type, Tuple[str]]: + return self.__class__, (self.message,) diff --git a/venv/lib/python3.8/site-packages/telegram/ext/__init__.py b/venv/lib/python3.8/site-packages/telegram/ext/__init__.py new file mode 100644 index 0000000..b4b4cc5 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/ext/__init__.py @@ -0,0 +1,104 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +# pylint: disable=C0413 +"""Extensions over the Telegram Bot API to facilitate bot making""" + +from .extbot import ExtBot +from .basepersistence import BasePersistence +from .picklepersistence import PicklePersistence +from .dictpersistence import DictPersistence +from .handler import Handler +from .callbackcontext import CallbackContext +from .contexttypes import ContextTypes +from .dispatcher import Dispatcher, DispatcherHandlerStop, run_async + +# https://bugs.python.org/issue41451, fixed on 3.7+, doesn't actually remove slots +# try-except is just here in case the __init__ is called twice (like in the tests) +# this block is also the reason for the pylint-ignore at the top of the file +try: + del Dispatcher.__slots__ # type: ignore[has-type] +except AttributeError as exc: + if str(exc) == '__slots__': + pass + else: + raise exc + +from .jobqueue import JobQueue, Job +from .updater import Updater +from .callbackqueryhandler import CallbackQueryHandler +from .choseninlineresulthandler import ChosenInlineResultHandler +from .inlinequeryhandler import InlineQueryHandler +from .filters import BaseFilter, MessageFilter, UpdateFilter, Filters +from .messagehandler import MessageHandler +from .commandhandler import CommandHandler, PrefixHandler +from .regexhandler import RegexHandler +from .stringcommandhandler import StringCommandHandler +from .stringregexhandler import StringRegexHandler +from .typehandler import TypeHandler +from .conversationhandler import ConversationHandler +from .precheckoutqueryhandler import PreCheckoutQueryHandler +from .shippingqueryhandler import ShippingQueryHandler +from .messagequeue import MessageQueue +from .messagequeue import DelayQueue +from .pollanswerhandler import PollAnswerHandler +from .pollhandler import PollHandler +from .chatmemberhandler import ChatMemberHandler +from .defaults import Defaults +from .callbackdatacache import CallbackDataCache, InvalidCallbackData + +__all__ = ( + 'BaseFilter', + 'BasePersistence', + 'CallbackContext', + 'CallbackDataCache', + 'CallbackQueryHandler', + 'ChatMemberHandler', + 'ChosenInlineResultHandler', + 'CommandHandler', + 'ContextTypes', + 'ConversationHandler', + 'Defaults', + 'DelayQueue', + 'DictPersistence', + 'Dispatcher', + 'DispatcherHandlerStop', + 'ExtBot', + 'Filters', + 'Handler', + 'InlineQueryHandler', + 'InvalidCallbackData', + 'Job', + 'JobQueue', + 'MessageFilter', + 'MessageHandler', + 'MessageQueue', + 'PicklePersistence', + 'PollAnswerHandler', + 'PollHandler', + 'PreCheckoutQueryHandler', + 'PrefixHandler', + 'RegexHandler', + 'ShippingQueryHandler', + 'StringCommandHandler', + 'StringRegexHandler', + 'TypeHandler', + 'UpdateFilter', + 'Updater', + 'run_async', +) diff --git a/venv/lib/python3.8/site-packages/telegram/ext/basepersistence.py b/venv/lib/python3.8/site-packages/telegram/ext/basepersistence.py new file mode 100644 index 0000000..8833733 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/ext/basepersistence.py @@ -0,0 +1,538 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the BasePersistence class.""" +import warnings +from sys import version_info as py_ver +from abc import ABC, abstractmethod +from copy import copy +from typing import Dict, Optional, Tuple, cast, ClassVar, Generic, DefaultDict + +from telegram.utils.deprecate import set_new_attribute_deprecated + +from telegram import Bot +import telegram.ext.extbot + +from telegram.ext.utils.types import UD, CD, BD, ConversationDict, CDCData + + +class BasePersistence(Generic[UD, CD, BD], ABC): + """Interface class for adding persistence to your bot. + Subclass this object for different implementations of a persistent bot. + + All relevant methods must be overwritten. This includes: + + * :meth:`get_bot_data` + * :meth:`update_bot_data` + * :meth:`refresh_bot_data` + * :meth:`get_chat_data` + * :meth:`update_chat_data` + * :meth:`refresh_chat_data` + * :meth:`get_user_data` + * :meth:`update_user_data` + * :meth:`refresh_user_data` + * :meth:`get_callback_data` + * :meth:`update_callback_data` + * :meth:`get_conversations` + * :meth:`update_conversation` + * :meth:`flush` + + If you don't actually need one of those methods, a simple ``pass`` is enough. For example, if + ``store_bot_data=False``, you don't need :meth:`get_bot_data`, :meth:`update_bot_data` or + :meth:`refresh_bot_data`. + + Warning: + Persistence will try to replace :class:`telegram.Bot` instances by :attr:`REPLACED_BOT` and + insert the bot set with :meth:`set_bot` upon loading of the data. This is to ensure that + changes to the bot apply to the saved objects, too. If you change the bots token, this may + lead to e.g. ``Chat not found`` errors. For the limitations on replacing bots see + :meth:`replace_bot` and :meth:`insert_bot`. + + Note: + :meth:`replace_bot` and :meth:`insert_bot` are used *independently* of the implementation + of the :meth:`update/get_*` methods, i.e. you don't need to worry about it while + implementing a custom persistence subclass. + + Args: + store_user_data (:obj:`bool`, optional): Whether user_data should be saved by this + persistence class. Default is :obj:`True`. + store_chat_data (:obj:`bool`, optional): Whether chat_data should be saved by this + persistence class. Default is :obj:`True` . + store_bot_data (:obj:`bool`, optional): Whether bot_data should be saved by this + persistence class. Default is :obj:`True`. + store_callback_data (:obj:`bool`, optional): Whether callback_data should be saved by this + persistence class. Default is :obj:`False`. + + .. versionadded:: 13.6 + + Attributes: + store_user_data (:obj:`bool`): Optional, Whether user_data should be saved by this + persistence class. + store_chat_data (:obj:`bool`): Optional. Whether chat_data should be saved by this + persistence class. + store_bot_data (:obj:`bool`): Optional. Whether bot_data should be saved by this + persistence class. + store_callback_data (:obj:`bool`): Optional. Whether callback_data should be saved by this + persistence class. + + .. versionadded:: 13.6 + """ + + # Apparently Py 3.7 and below have '__dict__' in ABC + if py_ver < (3, 7): + __slots__ = ( + 'store_user_data', + 'store_chat_data', + 'store_bot_data', + 'store_callback_data', + 'bot', + ) + else: + __slots__ = ( + 'store_user_data', # type: ignore[assignment] + 'store_chat_data', + 'store_bot_data', + 'store_callback_data', + 'bot', + '__dict__', + ) + + def __new__( + cls, *args: object, **kwargs: object # pylint: disable=W0613 + ) -> 'BasePersistence': + """This overrides the get_* and update_* methods to use insert/replace_bot. + That has the side effect that we always pass deepcopied data to those methods, so in + Pickle/DictPersistence we don't have to worry about copying the data again. + + Note: This doesn't hold for second tuple-entry of callback_data. That's a Dict[str, str], + so no bots to replace anyway. + """ + instance = super().__new__(cls) + get_user_data = instance.get_user_data + get_chat_data = instance.get_chat_data + get_bot_data = instance.get_bot_data + get_callback_data = instance.get_callback_data + update_user_data = instance.update_user_data + update_chat_data = instance.update_chat_data + update_bot_data = instance.update_bot_data + update_callback_data = instance.update_callback_data + + def get_user_data_insert_bot() -> DefaultDict[int, UD]: + return instance.insert_bot(get_user_data()) + + def get_chat_data_insert_bot() -> DefaultDict[int, CD]: + return instance.insert_bot(get_chat_data()) + + def get_bot_data_insert_bot() -> BD: + return instance.insert_bot(get_bot_data()) + + def get_callback_data_insert_bot() -> Optional[CDCData]: + cdc_data = get_callback_data() + if cdc_data is None: + return None + return instance.insert_bot(cdc_data[0]), cdc_data[1] + + def update_user_data_replace_bot(user_id: int, data: UD) -> None: + return update_user_data(user_id, instance.replace_bot(data)) + + def update_chat_data_replace_bot(chat_id: int, data: CD) -> None: + return update_chat_data(chat_id, instance.replace_bot(data)) + + def update_bot_data_replace_bot(data: BD) -> None: + return update_bot_data(instance.replace_bot(data)) + + def update_callback_data_replace_bot(data: CDCData) -> None: + obj_data, queue = data + return update_callback_data((instance.replace_bot(obj_data), queue)) + + # We want to ignore TGDeprecation warnings so we use obj.__setattr__. Adds to __dict__ + object.__setattr__(instance, 'get_user_data', get_user_data_insert_bot) + object.__setattr__(instance, 'get_chat_data', get_chat_data_insert_bot) + object.__setattr__(instance, 'get_bot_data', get_bot_data_insert_bot) + object.__setattr__(instance, 'get_callback_data', get_callback_data_insert_bot) + object.__setattr__(instance, 'update_user_data', update_user_data_replace_bot) + object.__setattr__(instance, 'update_chat_data', update_chat_data_replace_bot) + object.__setattr__(instance, 'update_bot_data', update_bot_data_replace_bot) + object.__setattr__(instance, 'update_callback_data', update_callback_data_replace_bot) + return instance + + def __init__( + self, + store_user_data: bool = True, + store_chat_data: bool = True, + store_bot_data: bool = True, + store_callback_data: bool = False, + ): + self.store_user_data = store_user_data + self.store_chat_data = store_chat_data + self.store_bot_data = store_bot_data + self.store_callback_data = store_callback_data + self.bot: Bot = None # type: ignore[assignment] + + def __setattr__(self, key: str, value: object) -> None: + # Allow user defined subclasses to have custom attributes. + if issubclass(self.__class__, BasePersistence) and self.__class__.__name__ not in { + 'DictPersistence', + 'PicklePersistence', + }: + object.__setattr__(self, key, value) + return + set_new_attribute_deprecated(self, key, value) + + def set_bot(self, bot: Bot) -> None: + """Set the Bot to be used by this persistence instance. + + Args: + bot (:class:`telegram.Bot`): The bot. + """ + if self.store_callback_data and not isinstance(bot, telegram.ext.extbot.ExtBot): + raise TypeError('store_callback_data can only be used with telegram.ext.ExtBot.') + + self.bot = bot + + @classmethod + def replace_bot(cls, obj: object) -> object: + """ + Replaces all instances of :class:`telegram.Bot` that occur within the passed object with + :attr:`REPLACED_BOT`. Currently, this handles objects of type ``list``, ``tuple``, ``set``, + ``frozenset``, ``dict``, ``defaultdict`` and objects that have a ``__dict__`` or + ``__slots__`` attribute, excluding classes and objects that can't be copied with + ``copy.copy``. + + Args: + obj (:obj:`object`): The object + + Returns: + :obj:`obj`: Copy of the object with Bot instances replaced. + """ + return cls._replace_bot(obj, {}) + + @classmethod + def _replace_bot(cls, obj: object, memo: Dict[int, object]) -> object: # pylint: disable=R0911 + obj_id = id(obj) + if obj_id in memo: + return memo[obj_id] + + if isinstance(obj, Bot): + memo[obj_id] = cls.REPLACED_BOT + return cls.REPLACED_BOT + if isinstance(obj, (list, set)): + # We copy the iterable here for thread safety, i.e. make sure the object we iterate + # over doesn't change its length during the iteration + temp_iterable = obj.copy() + new_iterable = obj.__class__(cls._replace_bot(item, memo) for item in temp_iterable) + memo[obj_id] = new_iterable + return new_iterable + if isinstance(obj, (tuple, frozenset)): + # tuples and frozensets are immutable so we don't need to worry about thread safety + new_immutable = obj.__class__(cls._replace_bot(item, memo) for item in obj) + memo[obj_id] = new_immutable + return new_immutable + if isinstance(obj, type): + # classes usually do have a __dict__, but it's not writable + warnings.warn( + 'BasePersistence.replace_bot does not handle classes. See ' + 'the docs of BasePersistence.replace_bot for more information.', + RuntimeWarning, + ) + return obj + + try: + new_obj = copy(obj) + memo[obj_id] = new_obj + except Exception: + warnings.warn( + 'BasePersistence.replace_bot does not handle objects that can not be copied. See ' + 'the docs of BasePersistence.replace_bot for more information.', + RuntimeWarning, + ) + memo[obj_id] = obj + return obj + + if isinstance(obj, dict): + # We handle dicts via copy(obj) so we don't have to make a + # difference between dict and defaultdict + new_obj = cast(dict, new_obj) + # We can't iterate over obj.items() due to thread safety, i.e. the dicts length may + # change during the iteration + temp_dict = new_obj.copy() + new_obj.clear() + for k, val in temp_dict.items(): + new_obj[cls._replace_bot(k, memo)] = cls._replace_bot(val, memo) + memo[obj_id] = new_obj + return new_obj + if hasattr(obj, '__dict__'): + for attr_name, attr in new_obj.__dict__.items(): + setattr(new_obj, attr_name, cls._replace_bot(attr, memo)) + memo[obj_id] = new_obj + return new_obj + if hasattr(obj, '__slots__'): + for attr_name in new_obj.__slots__: + setattr( + new_obj, + attr_name, + cls._replace_bot(cls._replace_bot(getattr(new_obj, attr_name), memo), memo), + ) + memo[obj_id] = new_obj + return new_obj + + return obj + + def insert_bot(self, obj: object) -> object: + """ + Replaces all instances of :attr:`REPLACED_BOT` that occur within the passed object with + :attr:`bot`. Currently, this handles objects of type ``list``, ``tuple``, ``set``, + ``frozenset``, ``dict``, ``defaultdict`` and objects that have a ``__dict__`` or + ``__slots__`` attribute, excluding classes and objects that can't be copied with + ``copy.copy``. + + Args: + obj (:obj:`object`): The object + + Returns: + :obj:`obj`: Copy of the object with Bot instances inserted. + """ + return self._insert_bot(obj, {}) + + def _insert_bot(self, obj: object, memo: Dict[int, object]) -> object: # pylint: disable=R0911 + obj_id = id(obj) + if obj_id in memo: + return memo[obj_id] + + if isinstance(obj, Bot): + memo[obj_id] = self.bot + return self.bot + if isinstance(obj, str) and obj == self.REPLACED_BOT: + memo[obj_id] = self.bot + return self.bot + if isinstance(obj, (list, set)): + # We copy the iterable here for thread safety, i.e. make sure the object we iterate + # over doesn't change its length during the iteration + temp_iterable = obj.copy() + new_iterable = obj.__class__(self._insert_bot(item, memo) for item in temp_iterable) + memo[obj_id] = new_iterable + return new_iterable + if isinstance(obj, (tuple, frozenset)): + # tuples and frozensets are immutable so we don't need to worry about thread safety + new_immutable = obj.__class__(self._insert_bot(item, memo) for item in obj) + memo[obj_id] = new_immutable + return new_immutable + if isinstance(obj, type): + # classes usually do have a __dict__, but it's not writable + warnings.warn( + 'BasePersistence.insert_bot does not handle classes. See ' + 'the docs of BasePersistence.insert_bot for more information.', + RuntimeWarning, + ) + return obj + + try: + new_obj = copy(obj) + except Exception: + warnings.warn( + 'BasePersistence.insert_bot does not handle objects that can not be copied. See ' + 'the docs of BasePersistence.insert_bot for more information.', + RuntimeWarning, + ) + memo[obj_id] = obj + return obj + + if isinstance(obj, dict): + # We handle dicts via copy(obj) so we don't have to make a + # difference between dict and defaultdict + new_obj = cast(dict, new_obj) + # We can't iterate over obj.items() due to thread safety, i.e. the dicts length may + # change during the iteration + temp_dict = new_obj.copy() + new_obj.clear() + for k, val in temp_dict.items(): + new_obj[self._insert_bot(k, memo)] = self._insert_bot(val, memo) + memo[obj_id] = new_obj + return new_obj + if hasattr(obj, '__dict__'): + for attr_name, attr in new_obj.__dict__.items(): + setattr(new_obj, attr_name, self._insert_bot(attr, memo)) + memo[obj_id] = new_obj + return new_obj + if hasattr(obj, '__slots__'): + for attr_name in obj.__slots__: + setattr( + new_obj, + attr_name, + self._insert_bot(self._insert_bot(getattr(new_obj, attr_name), memo), memo), + ) + memo[obj_id] = new_obj + return new_obj + + return obj + + @abstractmethod + def get_user_data(self) -> DefaultDict[int, UD]: + """Will be called by :class:`telegram.ext.Dispatcher` upon creation with a + persistence object. It should return the ``user_data`` if stored, or an empty + :obj:`defaultdict(telegram.ext.utils.types.UD)` with integer keys. + + Returns: + DefaultDict[:obj:`int`, :class:`telegram.ext.utils.types.UD`]: The restored user data. + """ + + @abstractmethod + def get_chat_data(self) -> DefaultDict[int, CD]: + """Will be called by :class:`telegram.ext.Dispatcher` upon creation with a + persistence object. It should return the ``chat_data`` if stored, or an empty + :obj:`defaultdict(telegram.ext.utils.types.CD)` with integer keys. + + Returns: + DefaultDict[:obj:`int`, :class:`telegram.ext.utils.types.CD`]: The restored chat data. + """ + + @abstractmethod + def get_bot_data(self) -> BD: + """Will be called by :class:`telegram.ext.Dispatcher` upon creation with a + persistence object. It should return the ``bot_data`` if stored, or an empty + :class:`telegram.ext.utils.types.BD`. + + Returns: + :class:`telegram.ext.utils.types.BD`: The restored bot data. + """ + + def get_callback_data(self) -> Optional[CDCData]: + """Will be called by :class:`telegram.ext.Dispatcher` upon creation with a + persistence object. If callback data was stored, it should be returned. + + .. versionadded:: 13.6 + + Returns: + Optional[:class:`telegram.ext.utils.types.CDCData`]: The restored meta data or + :obj:`None`, if no data was stored. + """ + raise NotImplementedError + + @abstractmethod + def get_conversations(self, name: str) -> ConversationDict: + """Will be called by :class:`telegram.ext.Dispatcher` when a + :class:`telegram.ext.ConversationHandler` is added if + :attr:`telegram.ext.ConversationHandler.persistent` is :obj:`True`. + It should return the conversations for the handler with `name` or an empty :obj:`dict` + + Args: + name (:obj:`str`): The handlers name. + + Returns: + :obj:`dict`: The restored conversations for the handler. + """ + + @abstractmethod + def update_conversation( + self, name: str, key: Tuple[int, ...], new_state: Optional[object] + ) -> None: + """Will be called when a :attr:`telegram.ext.ConversationHandler.update_state` + is called. This allows the storage of the new state in the persistence. + + Args: + name (:obj:`str`): The handler's name. + key (:obj:`tuple`): The key the state is changed for. + new_state (:obj:`tuple` | :obj:`any`): The new state for the given key. + """ + + @abstractmethod + def update_user_data(self, user_id: int, data: UD) -> None: + """Will be called by the :class:`telegram.ext.Dispatcher` after a handler has + handled an update. + + Args: + user_id (:obj:`int`): The user the data might have been changed for. + data (:class:`telegram.ext.utils.types.UD`): The + :attr:`telegram.ext.dispatcher.user_data` ``[user_id]``. + """ + + @abstractmethod + def update_chat_data(self, chat_id: int, data: CD) -> None: + """Will be called by the :class:`telegram.ext.Dispatcher` after a handler has + handled an update. + + Args: + chat_id (:obj:`int`): The chat the data might have been changed for. + data (:class:`telegram.ext.utils.types.CD`): The + :attr:`telegram.ext.dispatcher.chat_data` ``[chat_id]``. + """ + + @abstractmethod + def update_bot_data(self, data: BD) -> None: + """Will be called by the :class:`telegram.ext.Dispatcher` after a handler has + handled an update. + + Args: + data (:class:`telegram.ext.utils.types.BD`): The + :attr:`telegram.ext.dispatcher.bot_data`. + """ + + def refresh_user_data(self, user_id: int, user_data: UD) -> None: + """Will be called by the :class:`telegram.ext.Dispatcher` before passing the + :attr:`user_data` to a callback. Can be used to update data stored in :attr:`user_data` + from an external source. + + .. versionadded:: 13.6 + + Args: + user_id (:obj:`int`): The user ID this :attr:`user_data` is associated with. + user_data (:class:`telegram.ext.utils.types.UD`): The ``user_data`` of a single user. + """ + + def refresh_chat_data(self, chat_id: int, chat_data: CD) -> None: + """Will be called by the :class:`telegram.ext.Dispatcher` before passing the + :attr:`chat_data` to a callback. Can be used to update data stored in :attr:`chat_data` + from an external source. + + .. versionadded:: 13.6 + + Args: + chat_id (:obj:`int`): The chat ID this :attr:`chat_data` is associated with. + chat_data (:class:`telegram.ext.utils.types.CD`): The ``chat_data`` of a single chat. + """ + + def refresh_bot_data(self, bot_data: BD) -> None: + """Will be called by the :class:`telegram.ext.Dispatcher` before passing the + :attr:`bot_data` to a callback. Can be used to update data stored in :attr:`bot_data` + from an external source. + + .. versionadded:: 13.6 + + Args: + bot_data (:class:`telegram.ext.utils.types.BD`): The ``bot_data``. + """ + + def update_callback_data(self, data: CDCData) -> None: + """Will be called by the :class:`telegram.ext.Dispatcher` after a handler has + handled an update. + + .. versionadded:: 13.6 + + Args: + data (:class:`telegram.ext.utils.types.CDCData`:): The relevant data to restore + :attr:`telegram.ext.dispatcher.bot.callback_data_cache`. + """ + raise NotImplementedError + + def flush(self) -> None: + """Will be called by :class:`telegram.ext.Updater` upon receiving a stop signal. Gives the + persistence a chance to finish up saving or close a database connection gracefully. + """ + + REPLACED_BOT: ClassVar[str] = 'bot_instance_replaced_by_ptb_persistence' + """:obj:`str`: Placeholder for :class:`telegram.Bot` instances replaced in saved data.""" diff --git a/venv/lib/python3.8/site-packages/telegram/ext/callbackcontext.py b/venv/lib/python3.8/site-packages/telegram/ext/callbackcontext.py new file mode 100644 index 0000000..5c5e9be --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/ext/callbackcontext.py @@ -0,0 +1,361 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +# pylint: disable=R0201 +"""This module contains the CallbackContext class.""" +from queue import Queue +from typing import ( + TYPE_CHECKING, + Dict, + List, + Match, + NoReturn, + Optional, + Tuple, + Union, + Generic, + Type, + TypeVar, +) + +from telegram import Update, CallbackQuery +from telegram.ext import ExtBot +from telegram.ext.utils.types import UD, CD, BD + +if TYPE_CHECKING: + from telegram import Bot + from telegram.ext import Dispatcher, Job, JobQueue + +CC = TypeVar('CC', bound='CallbackContext') + + +class CallbackContext(Generic[UD, CD, BD]): + """ + This is a context object passed to the callback called by :class:`telegram.ext.Handler` + or by the :class:`telegram.ext.Dispatcher` in an error handler added by + :attr:`telegram.ext.Dispatcher.add_error_handler` or to the callback of a + :class:`telegram.ext.Job`. + + Note: + :class:`telegram.ext.Dispatcher` will create a single context for an entire update. This + means that if you got 2 handlers in different groups and they both get called, they will + get passed the same `CallbackContext` object (of course with proper attributes like + `.matches` differing). This allows you to add custom attributes in a lower handler group + callback, and then subsequently access those attributes in a higher handler group callback. + Note that the attributes on `CallbackContext` might change in the future, so make sure to + use a fairly unique name for the attributes. + + Warning: + Do not combine custom attributes and ``@run_async``/ + :meth:`telegram.ext.Disptacher.run_async`. Due to how ``run_async`` works, it will + almost certainly execute the callbacks for an update out of order, and the attributes + that you think you added will not be present. + + Args: + dispatcher (:class:`telegram.ext.Dispatcher`): The dispatcher associated with this context. + + Attributes: + matches (List[:obj:`re match object`]): Optional. If the associated update originated from + a regex-supported handler or had a :class:`Filters.regex`, this will contain a list of + match objects for every pattern where ``re.search(pattern, string)`` returned a match. + Note that filters short circuit, so combined regex filters will not always + be evaluated. + args (List[:obj:`str`]): Optional. Arguments passed to a command if the associated update + is handled by :class:`telegram.ext.CommandHandler`, :class:`telegram.ext.PrefixHandler` + or :class:`telegram.ext.StringCommandHandler`. It contains a list of the words in the + text after the command, using any whitespace string as a delimiter. + error (:obj:`Exception`): Optional. The error that was raised. Only present when passed + to a error handler registered with :attr:`telegram.ext.Dispatcher.add_error_handler`. + async_args (List[:obj:`object`]): Optional. Positional arguments of the function that + raised the error. Only present when the raising function was run asynchronously using + :meth:`telegram.ext.Dispatcher.run_async`. + async_kwargs (Dict[:obj:`str`, :obj:`object`]): Optional. Keyword arguments of the function + that raised the error. Only present when the raising function was run asynchronously + using :meth:`telegram.ext.Dispatcher.run_async`. + job (:class:`telegram.ext.Job`): Optional. The job which originated this callback. + Only present when passed to the callback of :class:`telegram.ext.Job`. + + """ + + __slots__ = ( + '_dispatcher', + '_chat_id_and_data', + '_user_id_and_data', + 'args', + 'matches', + 'error', + 'job', + 'async_args', + 'async_kwargs', + '__dict__', + ) + + def __init__(self, dispatcher: 'Dispatcher'): + """ + Args: + dispatcher (:class:`telegram.ext.Dispatcher`): + """ + if not dispatcher.use_context: + raise ValueError( + 'CallbackContext should not be used with a non context aware ' 'dispatcher!' + ) + self._dispatcher = dispatcher + self._chat_id_and_data: Optional[Tuple[int, CD]] = None + self._user_id_and_data: Optional[Tuple[int, UD]] = None + self.args: Optional[List[str]] = None + self.matches: Optional[List[Match]] = None + self.error: Optional[Exception] = None + self.job: Optional['Job'] = None + self.async_args: Optional[Union[List, Tuple]] = None + self.async_kwargs: Optional[Dict[str, object]] = None + + @property + def dispatcher(self) -> 'Dispatcher': + """:class:`telegram.ext.Dispatcher`: The dispatcher associated with this context.""" + return self._dispatcher + + @property + def bot_data(self) -> BD: + """:obj:`dict`: Optional. A dict that can be used to keep any data in. For each + update it will be the same ``dict``. + """ + return self.dispatcher.bot_data + + @bot_data.setter + def bot_data(self, value: object) -> NoReturn: + raise AttributeError( + "You can not assign a new value to bot_data, see https://git.io/Jt6ic" + ) + + @property + def chat_data(self) -> Optional[CD]: + """:obj:`dict`: Optional. A dict that can be used to keep any data in. For each + update from the same chat id it will be the same ``dict``. + + Warning: + When a group chat migrates to a supergroup, its chat id will change and the + ``chat_data`` needs to be transferred. For details see our `wiki page + <https://github.com/python-telegram-bot/python-telegram-bot/wiki/ + Storing-bot,-user-and-chat-related-data#chat-migration>`_. + """ + if self._chat_id_and_data: + return self._chat_id_and_data[1] + return None + + @chat_data.setter + def chat_data(self, value: object) -> NoReturn: + raise AttributeError( + "You can not assign a new value to chat_data, see https://git.io/Jt6ic" + ) + + @property + def user_data(self) -> Optional[UD]: + """:obj:`dict`: Optional. A dict that can be used to keep any data in. For each + update from the same user it will be the same ``dict``. + """ + if self._user_id_and_data: + return self._user_id_and_data[1] + return None + + @user_data.setter + def user_data(self, value: object) -> NoReturn: + raise AttributeError( + "You can not assign a new value to user_data, see https://git.io/Jt6ic" + ) + + def refresh_data(self) -> None: + """If :attr:`dispatcher` uses persistence, calls + :meth:`telegram.ext.BasePersistence.refresh_bot_data` on :attr:`bot_data`, + :meth:`telegram.ext.BasePersistence.refresh_chat_data` on :attr:`chat_data` and + :meth:`telegram.ext.BasePersistence.refresh_user_data` on :attr:`user_data`, if + appropriate. + + .. versionadded:: 13.6 + """ + if self.dispatcher.persistence: + if self.dispatcher.persistence.store_bot_data: + self.dispatcher.persistence.refresh_bot_data(self.bot_data) + if self.dispatcher.persistence.store_chat_data and self._chat_id_and_data is not None: + self.dispatcher.persistence.refresh_chat_data(*self._chat_id_and_data) + if self.dispatcher.persistence.store_user_data and self._user_id_and_data is not None: + self.dispatcher.persistence.refresh_user_data(*self._user_id_and_data) + + def drop_callback_data(self, callback_query: CallbackQuery) -> None: + """ + Deletes the cached data for the specified callback query. + + .. versionadded:: 13.6 + + Note: + Will *not* raise exceptions in case the data is not found in the cache. + *Will* raise :class:`KeyError` in case the callback query can not be found in the + cache. + + Args: + callback_query (:class:`telegram.CallbackQuery`): The callback query. + + Raises: + KeyError | RuntimeError: :class:`KeyError`, if the callback query can not be found in + the cache and :class:`RuntimeError`, if the bot doesn't allow for arbitrary + callback data. + """ + if isinstance(self.bot, ExtBot): + if not self.bot.arbitrary_callback_data: + raise RuntimeError( + 'This telegram.ext.ExtBot instance does not use arbitrary callback data.' + ) + self.bot.callback_data_cache.drop_data(callback_query) + else: + raise RuntimeError('telegram.Bot does not allow for arbitrary callback data.') + + @classmethod + def from_error( + cls: Type[CC], + update: object, + error: Exception, + dispatcher: 'Dispatcher', + async_args: Union[List, Tuple] = None, + async_kwargs: Dict[str, object] = None, + ) -> CC: + """ + Constructs an instance of :class:`telegram.ext.CallbackContext` to be passed to the error + handlers. + + .. seealso:: :meth:`telegram.ext.Dispatcher.add_error_handler` + + Args: + update (:obj:`object` | :class:`telegram.Update`): The update associated with the + error. May be :obj:`None`, e.g. for errors in job callbacks. + error (:obj:`Exception`): The error. + dispatcher (:class:`telegram.ext.Dispatcher`): The dispatcher associated with this + context. + async_args (List[:obj:`object`]): Optional. Positional arguments of the function that + raised the error. Pass only when the raising function was run asynchronously using + :meth:`telegram.ext.Dispatcher.run_async`. + async_kwargs (Dict[:obj:`str`, :obj:`object`]): Optional. Keyword arguments of the + function that raised the error. Pass only when the raising function was run + asynchronously using :meth:`telegram.ext.Dispatcher.run_async`. + + Returns: + :class:`telegram.ext.CallbackContext` + """ + self = cls.from_update(update, dispatcher) + self.error = error + self.async_args = async_args + self.async_kwargs = async_kwargs + return self + + @classmethod + def from_update(cls: Type[CC], update: object, dispatcher: 'Dispatcher') -> CC: + """ + Constructs an instance of :class:`telegram.ext.CallbackContext` to be passed to the + handlers. + + .. seealso:: :meth:`telegram.ext.Dispatcher.add_handler` + + Args: + update (:obj:`object` | :class:`telegram.Update`): The update. + dispatcher (:class:`telegram.ext.Dispatcher`): The dispatcher associated with this + context. + + Returns: + :class:`telegram.ext.CallbackContext` + """ + self = cls(dispatcher) + + if update is not None and isinstance(update, Update): + chat = update.effective_chat + user = update.effective_user + + if chat: + self._chat_id_and_data = ( + chat.id, + dispatcher.chat_data[chat.id], # pylint: disable=W0212 + ) + if user: + self._user_id_and_data = ( + user.id, + dispatcher.user_data[user.id], # pylint: disable=W0212 + ) + return self + + @classmethod + def from_job(cls: Type[CC], job: 'Job', dispatcher: 'Dispatcher') -> CC: + """ + Constructs an instance of :class:`telegram.ext.CallbackContext` to be passed to a + job callback. + + .. seealso:: :meth:`telegram.ext.JobQueue` + + Args: + job (:class:`telegram.ext.Job`): The job. + dispatcher (:class:`telegram.ext.Dispatcher`): The dispatcher associated with this + context. + + Returns: + :class:`telegram.ext.CallbackContext` + """ + self = cls(dispatcher) + self.job = job + return self + + def update(self, data: Dict[str, object]) -> None: + """Updates ``self.__slots__`` with the passed data. + + Args: + data (Dict[:obj:`str`, :obj:`object`]): The data. + """ + for key, value in data.items(): + setattr(self, key, value) + + @property + def bot(self) -> 'Bot': + """:class:`telegram.Bot`: The bot associated with this context.""" + return self._dispatcher.bot + + @property + def job_queue(self) -> Optional['JobQueue']: + """ + :class:`telegram.ext.JobQueue`: The ``JobQueue`` used by the + :class:`telegram.ext.Dispatcher` and (usually) the :class:`telegram.ext.Updater` + associated with this context. + + """ + return self._dispatcher.job_queue + + @property + def update_queue(self) -> Queue: + """ + :class:`queue.Queue`: The ``Queue`` instance used by the + :class:`telegram.ext.Dispatcher` and (usually) the :class:`telegram.ext.Updater` + associated with this context. + + """ + return self._dispatcher.update_queue + + @property + def match(self) -> Optional[Match[str]]: + """ + `Regex match type`: The first match from :attr:`matches`. + Useful if you are only filtering using a single regex filter. + Returns `None` if :attr:`matches` is empty. + """ + try: + return self.matches[0] # type: ignore[index] # pylint: disable=unsubscriptable-object + except (IndexError, TypeError): + return None diff --git a/venv/lib/python3.8/site-packages/telegram/ext/callbackdatacache.py b/venv/lib/python3.8/site-packages/telegram/ext/callbackdatacache.py new file mode 100644 index 0000000..ac60e47 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/ext/callbackdatacache.py @@ -0,0 +1,427 @@ +#!/usr/bin/env python + +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. + +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the CallbackDataCache class.""" +import logging +import time +from datetime import datetime +from threading import Lock +from typing import Dict, Tuple, Union, Optional, MutableMapping, TYPE_CHECKING, cast +from uuid import uuid4 + +from cachetools import LRUCache # pylint: disable=E0401 + +from telegram import ( + InlineKeyboardMarkup, + InlineKeyboardButton, + TelegramError, + CallbackQuery, + Message, + User, +) +from telegram.utils.helpers import to_float_timestamp +from telegram.ext.utils.types import CDCData + +if TYPE_CHECKING: + from telegram.ext import ExtBot + + +class InvalidCallbackData(TelegramError): + """ + Raised when the received callback data has been tempered with or deleted from cache. + + .. versionadded:: 13.6 + + Args: + callback_data (:obj:`int`, optional): The button data of which the callback data could not + be found. + + Attributes: + callback_data (:obj:`int`): Optional. The button data of which the callback data could not + be found. + """ + + __slots__ = ('callback_data',) + + def __init__(self, callback_data: str = None) -> None: + super().__init__( + 'The object belonging to this callback_data was deleted or the callback_data was ' + 'manipulated.' + ) + self.callback_data = callback_data + + def __reduce__(self) -> Tuple[type, Tuple[Optional[str]]]: # type: ignore[override] + return self.__class__, (self.callback_data,) + + +class _KeyboardData: + __slots__ = ('keyboard_uuid', 'button_data', 'access_time') + + def __init__( + self, keyboard_uuid: str, access_time: float = None, button_data: Dict[str, object] = None + ): + self.keyboard_uuid = keyboard_uuid + self.button_data = button_data or {} + self.access_time = access_time or time.time() + + def update_access_time(self) -> None: + """Updates the access time with the current time.""" + self.access_time = time.time() + + def to_tuple(self) -> Tuple[str, float, Dict[str, object]]: + """Gives a tuple representation consisting of the keyboard uuid, the access time and the + button data. + """ + return self.keyboard_uuid, self.access_time, self.button_data + + +class CallbackDataCache: + """A custom cache for storing the callback data of a :class:`telegram.ext.ExtBot`. Internally, + it keeps two mappings with fixed maximum size: + + * One for mapping the data received in callback queries to the cached objects + * One for mapping the IDs of received callback queries to the cached objects + + The second mapping allows to manually drop data that has been cached for keyboards of messages + sent via inline mode. + If necessary, will drop the least recently used items. + + .. versionadded:: 13.6 + + Args: + bot (:class:`telegram.ext.ExtBot`): The bot this cache is for. + maxsize (:obj:`int`, optional): Maximum number of items in each of the internal mappings. + Defaults to 1024. + persistent_data (:obj:`telegram.ext.utils.types.CDCData`, optional): Data to initialize + the cache with, as returned by :meth:`telegram.ext.BasePersistence.get_callback_data`. + + Attributes: + bot (:class:`telegram.ext.ExtBot`): The bot this cache is for. + maxsize (:obj:`int`): maximum size of the cache. + + """ + + __slots__ = ('bot', 'maxsize', '_keyboard_data', '_callback_queries', '__lock', 'logger') + + def __init__( + self, + bot: 'ExtBot', + maxsize: int = 1024, + persistent_data: CDCData = None, + ): + self.logger = logging.getLogger(__name__) + + self.bot = bot + self.maxsize = maxsize + self._keyboard_data: MutableMapping[str, _KeyboardData] = LRUCache(maxsize=maxsize) + self._callback_queries: MutableMapping[str, str] = LRUCache(maxsize=maxsize) + self.__lock = Lock() + + if persistent_data: + keyboard_data, callback_queries = persistent_data + for key, value in callback_queries.items(): + self._callback_queries[key] = value + for uuid, access_time, data in keyboard_data: + self._keyboard_data[uuid] = _KeyboardData( + keyboard_uuid=uuid, access_time=access_time, button_data=data + ) + + @property + def persistence_data(self) -> CDCData: + """:obj:`telegram.ext.utils.types.CDCData`: The data that needs to be persisted to allow + caching callback data across bot reboots. + """ + # While building a list/dict from the LRUCaches has linear runtime (in the number of + # entries), the runtime is bounded by maxsize and it has the big upside of not throwing a + # highly customized data structure at users trying to implement a custom persistence class + with self.__lock: + return [data.to_tuple() for data in self._keyboard_data.values()], dict( + self._callback_queries.items() + ) + + def process_keyboard(self, reply_markup: InlineKeyboardMarkup) -> InlineKeyboardMarkup: + """Registers the reply markup to the cache. If any of the buttons have + :attr:`callback_data`, stores that data and builds a new keyboard with the correspondingly + replaced buttons. Otherwise does nothing and returns the original reply markup. + + Args: + reply_markup (:class:`telegram.InlineKeyboardMarkup`): The keyboard. + + Returns: + :class:`telegram.InlineKeyboardMarkup`: The keyboard to be passed to Telegram. + + """ + with self.__lock: + return self.__process_keyboard(reply_markup) + + def __process_keyboard(self, reply_markup: InlineKeyboardMarkup) -> InlineKeyboardMarkup: + keyboard_uuid = uuid4().hex + keyboard_data = _KeyboardData(keyboard_uuid) + + # Built a new nested list of buttons by replacing the callback data if needed + buttons = [ + [ + # We create a new button instead of replacing callback_data in case the + # same object is used elsewhere + InlineKeyboardButton( + btn.text, + callback_data=self.__put_button(btn.callback_data, keyboard_data), + ) + if btn.callback_data + else btn + for btn in column + ] + for column in reply_markup.inline_keyboard + ] + + if not keyboard_data.button_data: + # If we arrive here, no data had to be replaced and we can return the input + return reply_markup + + self._keyboard_data[keyboard_uuid] = keyboard_data + return InlineKeyboardMarkup(buttons) + + @staticmethod + def __put_button(callback_data: object, keyboard_data: _KeyboardData) -> str: + """Stores the data for a single button in :attr:`keyboard_data`. + Returns the string that should be passed instead of the callback_data, which is + ``keyboard_uuid + button_uuids``. + """ + uuid = uuid4().hex + keyboard_data.button_data[uuid] = callback_data + return f'{keyboard_data.keyboard_uuid}{uuid}' + + def __get_keyboard_uuid_and_button_data( + self, callback_data: str + ) -> Union[Tuple[str, object], Tuple[None, InvalidCallbackData]]: + keyboard, button = self.extract_uuids(callback_data) + try: + # we get the values before calling update() in case KeyErrors are raised + # we don't want to update in that case + keyboard_data = self._keyboard_data[keyboard] + button_data = keyboard_data.button_data[button] + # Update the timestamp for the LRU + keyboard_data.update_access_time() + return keyboard, button_data + except KeyError: + return None, InvalidCallbackData(callback_data) + + @staticmethod + def extract_uuids(callback_data: str) -> Tuple[str, str]: + """Extracts the keyboard uuid and the button uuid from the given ``callback_data``. + + Args: + callback_data (:obj:`str`): The ``callback_data`` as present in the button. + + Returns: + (:obj:`str`, :obj:`str`): Tuple of keyboard and button uuid + + """ + # Extract the uuids as put in __put_button + return callback_data[:32], callback_data[32:] + + def process_message(self, message: Message) -> None: + """Replaces the data in the inline keyboard attached to the message with the cached + objects, if necessary. If the data could not be found, + :class:`telegram.ext.InvalidCallbackData` will be inserted. + + Note: + Checks :attr:`telegram.Message.via_bot` and :attr:`telegram.Message.from_user` to check + if the reply markup (if any) was actually sent by this caches bot. If it was not, the + message will be returned unchanged. + + Note that this will fail for channel posts, as :attr:`telegram.Message.from_user` is + :obj:`None` for those! In the corresponding reply markups the callback data will be + replaced by :class:`telegram.ext.InvalidCallbackData`. + + Warning: + * Does *not* consider :attr:`telegram.Message.reply_to_message` and + :attr:`telegram.Message.pinned_message`. Pass them to these method separately. + * *In place*, i.e. the passed :class:`telegram.Message` will be changed! + + Args: + message (:class:`telegram.Message`): The message. + + """ + with self.__lock: + self.__process_message(message) + + def __process_message(self, message: Message) -> Optional[str]: + """As documented in process_message, but returns the uuid of the attached keyboard, if any, + which is relevant for process_callback_query. + + **IN PLACE** + """ + if not message.reply_markup: + return None + + if message.via_bot: + sender: Optional[User] = message.via_bot + elif message.from_user: + sender = message.from_user + else: + sender = None + + if sender is not None and sender != self.bot.bot: + return None + + keyboard_uuid = None + + for row in message.reply_markup.inline_keyboard: + for button in row: + if button.callback_data: + button_data = cast(str, button.callback_data) + keyboard_id, callback_data = self.__get_keyboard_uuid_and_button_data( + button_data + ) + # update_callback_data makes sure that the _id_attrs are updated + button.update_callback_data(callback_data) + + # This is lazy loaded. The firsts time we find a button + # we load the associated keyboard - afterwards, there is + if not keyboard_uuid and not isinstance(callback_data, InvalidCallbackData): + keyboard_uuid = keyboard_id + + return keyboard_uuid + + def process_callback_query(self, callback_query: CallbackQuery) -> None: + """Replaces the data in the callback query and the attached messages keyboard with the + cached objects, if necessary. If the data could not be found, + :class:`telegram.ext.InvalidCallbackData` will be inserted. + If :attr:`callback_query.data` or :attr:`callback_query.message` is present, this also + saves the callback queries ID in order to be able to resolve it to the stored data. + + Note: + Also considers inserts data into the buttons of + :attr:`telegram.Message.reply_to_message` and :attr:`telegram.Message.pinned_message` + if necessary. + + Warning: + *In place*, i.e. the passed :class:`telegram.CallbackQuery` will be changed! + + Args: + callback_query (:class:`telegram.CallbackQuery`): The callback query. + + """ + with self.__lock: + mapped = False + + if callback_query.data: + data = callback_query.data + + # Get the cached callback data for the CallbackQuery + keyboard_uuid, button_data = self.__get_keyboard_uuid_and_button_data(data) + callback_query.data = button_data # type: ignore[assignment] + + # Map the callback queries ID to the keyboards UUID for later use + if not mapped and not isinstance(button_data, InvalidCallbackData): + self._callback_queries[callback_query.id] = keyboard_uuid # type: ignore + mapped = True + + # Get the cached callback data for the inline keyboard attached to the + # CallbackQuery. + if callback_query.message: + self.__process_message(callback_query.message) + for message in ( + callback_query.message.pinned_message, + callback_query.message.reply_to_message, + ): + if message: + self.__process_message(message) + + def drop_data(self, callback_query: CallbackQuery) -> None: + """Deletes the data for the specified callback query. + + Note: + Will *not* raise exceptions in case the callback data is not found in the cache. + *Will* raise :class:`KeyError` in case the callback query can not be found in the + cache. + + Args: + callback_query (:class:`telegram.CallbackQuery`): The callback query. + + Raises: + KeyError: If the callback query can not be found in the cache + """ + with self.__lock: + try: + keyboard_uuid = self._callback_queries.pop(callback_query.id) + self.__drop_keyboard(keyboard_uuid) + except KeyError as exc: + raise KeyError('CallbackQuery was not found in cache.') from exc + + def __drop_keyboard(self, keyboard_uuid: str) -> None: + try: + self._keyboard_data.pop(keyboard_uuid) + except KeyError: + return + + def clear_callback_data(self, time_cutoff: Union[float, datetime] = None) -> None: + """Clears the stored callback data. + + Args: + time_cutoff (:obj:`float` | :obj:`datetime.datetime`, optional): Pass a UNIX timestamp + or a :obj:`datetime.datetime` to clear only entries which are older. + For timezone naive :obj:`datetime.datetime` objects, the default timezone of the + bot will be used. + + """ + with self.__lock: + self.__clear(self._keyboard_data, time_cutoff=time_cutoff) + + def clear_callback_queries(self) -> None: + """Clears the stored callback query IDs.""" + with self.__lock: + self.__clear(self._callback_queries) + + def __clear(self, mapping: MutableMapping, time_cutoff: Union[float, datetime] = None) -> None: + if not time_cutoff: + mapping.clear() + return + + if isinstance(time_cutoff, datetime): + effective_cutoff = to_float_timestamp( + time_cutoff, tzinfo=self.bot.defaults.tzinfo if self.bot.defaults else None + ) + else: + effective_cutoff = time_cutoff + + # We need a list instead of a generator here, as the list doesn't change it's size + # during the iteration + to_drop = [key for key, data in mapping.items() if data.access_time < effective_cutoff] + for key in to_drop: + mapping.pop(key) diff --git a/venv/lib/python3.8/site-packages/telegram/ext/callbackqueryhandler.py b/venv/lib/python3.8/site-packages/telegram/ext/callbackqueryhandler.py new file mode 100644 index 0000000..beea75f --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/ext/callbackqueryhandler.py @@ -0,0 +1,236 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the CallbackQueryHandler class.""" + +import re +from typing import ( + TYPE_CHECKING, + Callable, + Dict, + Match, + Optional, + Pattern, + TypeVar, + Union, + cast, +) + +from telegram import Update +from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE + +from .handler import Handler +from .utils.types import CCT + +if TYPE_CHECKING: + from telegram.ext import Dispatcher + +RT = TypeVar('RT') + + +class CallbackQueryHandler(Handler[Update, CCT]): + """Handler class to handle Telegram callback queries. Optionally based on a regex. + + Read the documentation of the ``re`` module for more information. + + Note: + * :attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you + can use to keep any data in will be sent to the :attr:`callback` function. Related to + either the user or the chat that the update was sent in. For each update from the same + user or in the same chat, it will be the same ``dict``. + + Note that this is DEPRECATED, and you should use context based callbacks. See + https://git.io/fxJuV for more info. + * If your bot allows arbitrary objects as ``callback_data``, it may happen that the + original ``callback_data`` for the incoming :class:`telegram.CallbackQuery`` can not be + found. This is the case when either a malicious client tempered with the + ``callback_data`` or the data was simply dropped from cache or not persisted. In these + cases, an instance of :class:`telegram.ext.InvalidCallbackData` will be set as + ``callback_data``. + + .. versionadded:: 13.6 + + Warning: + When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom + attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. + + Args: + callback (:obj:`callable`): The callback function for this handler. Will be called when + :attr:`check_update` has determined that an update should be processed by this handler. + Callback signature for context based API: + + ``def callback(update: Update, context: CallbackContext)`` + + The return value of the callback is usually ignored except for the special case of + :class:`telegram.ext.ConversationHandler`. + pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``update_queue`` will be passed to the callback function. It will be the ``Queue`` + instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher` + that contains new updates which can be used to insert updates. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``job_queue`` will be passed to the callback function. It will be a + :class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater` + which can be used to schedule new jobs. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + pattern (:obj:`str` | `Pattern` | :obj:`callable` | :obj:`type`, optional): + Pattern to test :attr:`telegram.CallbackQuery.data` against. If a string or a regex + pattern is passed, :meth:`re.match` is used on :attr:`telegram.CallbackQuery.data` to + determine if an update should be handled by this handler. If your bot allows arbitrary + objects as ``callback_data``, non-strings will be accepted. To filter arbitrary + objects you may pass + + * a callable, accepting exactly one argument, namely the + :attr:`telegram.CallbackQuery.data`. It must return :obj:`True` or + :obj:`False`/:obj:`None` to indicate, whether the update should be handled. + * a :obj:`type`. If :attr:`telegram.CallbackQuery.data` is an instance of that type + (or a subclass), the update will be handled. + + If :attr:`telegram.CallbackQuery.data` is :obj:`None`, the + :class:`telegram.CallbackQuery` update will not be handled. + + .. versionchanged:: 13.6 + Added support for arbitrary callback data. + pass_groups (:obj:`bool`, optional): If the callback should be passed the result of + ``re.match(pattern, data).groups()`` as a keyword argument called ``groups``. + Default is :obj:`False` + DEPRECATED: Please switch to context based callbacks. + pass_groupdict (:obj:`bool`, optional): If the callback should be passed the result of + ``re.match(pattern, data).groupdict()`` as a keyword argument called ``groupdict``. + Default is :obj:`False` + DEPRECATED: Please switch to context based callbacks. + pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``user_data`` will be passed to the callback function. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``chat_data`` will be passed to the callback function. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + run_async (:obj:`bool`): Determines whether the callback will run asynchronously. + Defaults to :obj:`False`. + + Attributes: + callback (:obj:`callable`): The callback function for this handler. + pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be + passed to the callback function. + pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to + the callback function. + pattern (`Pattern` | :obj:`callable` | :obj:`type`): Optional. Regex pattern, callback or + type to test :attr:`telegram.CallbackQuery.data` against. + + .. versionchanged:: 13.6 + Added support for arbitrary callback data. + pass_groups (:obj:`bool`): Determines whether ``groups`` will be passed to the + callback function. + pass_groupdict (:obj:`bool`): Determines whether ``groupdict``. will be passed to + the callback function. + pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to + the callback function. + pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to + the callback function. + run_async (:obj:`bool`): Determines whether the callback will run asynchronously. + + """ + + __slots__ = ('pattern', 'pass_groups', 'pass_groupdict') + + def __init__( + self, + callback: Callable[[Update, CCT], RT], + pass_update_queue: bool = False, + pass_job_queue: bool = False, + pattern: Union[str, Pattern, type, Callable[[object], Optional[bool]]] = None, + pass_groups: bool = False, + pass_groupdict: bool = False, + pass_user_data: bool = False, + pass_chat_data: bool = False, + run_async: Union[bool, DefaultValue] = DEFAULT_FALSE, + ): + super().__init__( + callback, + pass_update_queue=pass_update_queue, + pass_job_queue=pass_job_queue, + pass_user_data=pass_user_data, + pass_chat_data=pass_chat_data, + run_async=run_async, + ) + + if isinstance(pattern, str): + pattern = re.compile(pattern) + + self.pattern = pattern + self.pass_groups = pass_groups + self.pass_groupdict = pass_groupdict + + def check_update(self, update: object) -> Optional[Union[bool, object]]: + """Determines whether an update should be passed to this handlers :attr:`callback`. + + Args: + update (:class:`telegram.Update` | :obj:`object`): Incoming update. + + Returns: + :obj:`bool` + + """ + if isinstance(update, Update) and update.callback_query: + callback_data = update.callback_query.data + if self.pattern: + if callback_data is None: + return False + if isinstance(self.pattern, type): + return isinstance(callback_data, self.pattern) + if callable(self.pattern): + return self.pattern(callback_data) + match = re.match(self.pattern, callback_data) + if match: + return match + else: + return True + return None + + def collect_optional_args( + self, + dispatcher: 'Dispatcher', + update: Update = None, + check_result: Union[bool, Match] = None, + ) -> Dict[str, object]: + """Pass the results of ``re.match(pattern, data).{groups(), groupdict()}`` to the + callback as a keyword arguments called ``groups`` and ``groupdict``, respectively, if + needed. + """ + optional_args = super().collect_optional_args(dispatcher, update, check_result) + if self.pattern and not callable(self.pattern): + check_result = cast(Match, check_result) + if self.pass_groups: + optional_args['groups'] = check_result.groups() + if self.pass_groupdict: + optional_args['groupdict'] = check_result.groupdict() + return optional_args + + def collect_additional_context( + self, + context: CCT, + update: Update, + dispatcher: 'Dispatcher', + check_result: Union[bool, Match], + ) -> None: + """Add the result of ``re.match(pattern, update.callback_query.data)`` to + :attr:`CallbackContext.matches` as list with one element. + """ + if self.pattern: + check_result = cast(Match, check_result) + context.matches = [check_result] diff --git a/venv/lib/python3.8/site-packages/telegram/ext/chatmemberhandler.py b/venv/lib/python3.8/site-packages/telegram/ext/chatmemberhandler.py new file mode 100644 index 0000000..9499cfd --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/ext/chatmemberhandler.py @@ -0,0 +1,145 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2019-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the ChatMemberHandler classes.""" +from typing import ClassVar, TypeVar, Union, Callable + +from telegram import Update +from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE +from .handler import Handler +from .utils.types import CCT + +RT = TypeVar('RT') + + +class ChatMemberHandler(Handler[Update, CCT]): + """Handler class to handle Telegram updates that contain a chat member update. + + .. versionadded:: 13.4 + + Note: + :attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you + can use to keep any data in will be sent to the :attr:`callback` function. Related to + either the user or the chat that the update was sent in. For each update from the same user + or in the same chat, it will be the same ``dict``. + + Note that this is DEPRECATED, and you should use context based callbacks. See + https://git.io/fxJuV for more info. + + Warning: + When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom + attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. + + Args: + callback (:obj:`callable`): The callback function for this handler. Will be called when + :attr:`check_update` has determined that an update should be processed by this handler. + Callback signature for context based API: + + ``def callback(update: Update, context: CallbackContext)`` + + The return value of the callback is usually ignored except for the special case of + :class:`telegram.ext.ConversationHandler`. + chat_member_types (:obj:`int`, optional): Pass one of :attr:`MY_CHAT_MEMBER`, + :attr:`CHAT_MEMBER` or :attr:`ANY_CHAT_MEMBER` to specify if this handler should handle + only updates with :attr:`telegram.Update.my_chat_member`, + :attr:`telegram.Update.chat_member` or both. Defaults to :attr:`MY_CHAT_MEMBER`. + pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``update_queue`` will be passed to the callback function. It will be the ``Queue`` + instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher` + that contains new updates which can be used to insert updates. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``job_queue`` will be passed to the callback function. It will be a + :class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater` + which can be used to schedule new jobs. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``user_data`` will be passed to the callback function. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``chat_data`` will be passed to the callback function. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + run_async (:obj:`bool`): Determines whether the callback will run asynchronously. + Defaults to :obj:`False`. + + Attributes: + callback (:obj:`callable`): The callback function for this handler. + chat_member_types (:obj:`int`, optional): Specifies if this handler should handle + only updates with :attr:`telegram.Update.my_chat_member`, + :attr:`telegram.Update.chat_member` or both. + pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be + passed to the callback function. + pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to + the callback function. + pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to + the callback function. + pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to + the callback function. + run_async (:obj:`bool`): Determines whether the callback will run asynchronously. + + """ + + __slots__ = ('chat_member_types',) + MY_CHAT_MEMBER: ClassVar[int] = -1 + """:obj:`int`: Used as a constant to handle only :attr:`telegram.Update.my_chat_member`.""" + CHAT_MEMBER: ClassVar[int] = 0 + """:obj:`int`: Used as a constant to handle only :attr:`telegram.Update.chat_member`.""" + ANY_CHAT_MEMBER: ClassVar[int] = 1 + """:obj:`int`: Used as a constant to handle bot :attr:`telegram.Update.my_chat_member` + and :attr:`telegram.Update.chat_member`.""" + + def __init__( + self, + callback: Callable[[Update, CCT], RT], + chat_member_types: int = MY_CHAT_MEMBER, + pass_update_queue: bool = False, + pass_job_queue: bool = False, + pass_user_data: bool = False, + pass_chat_data: bool = False, + run_async: Union[bool, DefaultValue] = DEFAULT_FALSE, + ): + super().__init__( + callback, + pass_update_queue=pass_update_queue, + pass_job_queue=pass_job_queue, + pass_user_data=pass_user_data, + pass_chat_data=pass_chat_data, + run_async=run_async, + ) + + self.chat_member_types = chat_member_types + + def check_update(self, update: object) -> bool: + """Determines whether an update should be passed to this handlers :attr:`callback`. + + Args: + update (:class:`telegram.Update` | :obj:`object`): Incoming update. + + Returns: + :obj:`bool` + + """ + if isinstance(update, Update): + if not (update.my_chat_member or update.chat_member): + return False + if self.chat_member_types == self.ANY_CHAT_MEMBER: + return True + if self.chat_member_types == self.CHAT_MEMBER: + return bool(update.chat_member) + return bool(update.my_chat_member) + return False diff --git a/venv/lib/python3.8/site-packages/telegram/ext/choseninlineresulthandler.py b/venv/lib/python3.8/site-packages/telegram/ext/choseninlineresulthandler.py new file mode 100644 index 0000000..ec35289 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/ext/choseninlineresulthandler.py @@ -0,0 +1,160 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the ChosenInlineResultHandler class.""" +import re +from typing import Optional, TypeVar, Union, Callable, TYPE_CHECKING, Pattern, Match, cast + +from telegram import Update + +from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE +from .handler import Handler +from .utils.types import CCT + +RT = TypeVar('RT') + +if TYPE_CHECKING: + from telegram.ext import CallbackContext, Dispatcher + + +class ChosenInlineResultHandler(Handler[Update, CCT]): + """Handler class to handle Telegram updates that contain a chosen inline result. + + Note: + :attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you + can use to keep any data in will be sent to the :attr:`callback` function. Related to + either the user or the chat that the update was sent in. For each update from the same user + or in the same chat, it will be the same ``dict``. + + Note that this is DEPRECATED, and you should use context based callbacks. See + https://git.io/fxJuV for more info. + + Warning: + When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom + attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. + + Args: + callback (:obj:`callable`): The callback function for this handler. Will be called when + :attr:`check_update` has determined that an update should be processed by this handler. + Callback signature for context based API: + + ``def callback(update: Update, context: CallbackContext)`` + + The return value of the callback is usually ignored except for the special case of + :class:`telegram.ext.ConversationHandler`. + pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``update_queue`` will be passed to the callback function. It will be the ``Queue`` + instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher` + that contains new updates which can be used to insert updates. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``job_queue`` will be passed to the callback function. It will be a + :class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater` + which can be used to schedule new jobs. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``user_data`` will be passed to the callback function. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``chat_data`` will be passed to the callback function. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + run_async (:obj:`bool`): Determines whether the callback will run asynchronously. + Defaults to :obj:`False`. + pattern (:obj:`str` | `Pattern`, optional): Regex pattern. If not :obj:`None`, ``re.match`` + is used on :attr:`telegram.ChosenInlineResult.result_id` to determine if an update + should be handled by this handler. This is accessible in the callback as + :attr:`telegram.ext.CallbackContext.matches`. + + .. versionadded:: 13.6 + + Attributes: + callback (:obj:`callable`): The callback function for this handler. + pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be + passed to the callback function. + pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to + the callback function. + pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to + the callback function. + pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to + the callback function. + run_async (:obj:`bool`): Determines whether the callback will run asynchronously. + pattern (`Pattern`): Optional. Regex pattern to test + :attr:`telegram.ChosenInlineResult.result_id` against. + + .. versionadded:: 13.6 + + """ + + __slots__ = ('pattern',) + + def __init__( + self, + callback: Callable[[Update, 'CallbackContext'], RT], + pass_update_queue: bool = False, + pass_job_queue: bool = False, + pass_user_data: bool = False, + pass_chat_data: bool = False, + run_async: Union[bool, DefaultValue] = DEFAULT_FALSE, + pattern: Union[str, Pattern] = None, + ): + super().__init__( + callback, + pass_update_queue=pass_update_queue, + pass_job_queue=pass_job_queue, + pass_user_data=pass_user_data, + pass_chat_data=pass_chat_data, + run_async=run_async, + ) + + if isinstance(pattern, str): + pattern = re.compile(pattern) + + self.pattern = pattern + + def check_update(self, update: object) -> Optional[Union[bool, object]]: + """Determines whether an update should be passed to this handlers :attr:`callback`. + + Args: + update (:class:`telegram.Update` | :obj:`object`): Incoming update. + + Returns: + :obj:`bool` + + """ + if isinstance(update, Update) and update.chosen_inline_result: + if self.pattern: + match = re.match(self.pattern, update.chosen_inline_result.result_id) + if match: + return match + else: + return True + return None + + def collect_additional_context( + self, + context: 'CallbackContext', + update: Update, + dispatcher: 'Dispatcher', + check_result: Union[bool, Match], + ) -> None: + """This function adds the matched regex pattern result to + :attr:`telegram.ext.CallbackContext.matches`. + """ + if self.pattern: + check_result = cast(Match, check_result) + context.matches = [check_result] diff --git a/venv/lib/python3.8/site-packages/telegram/ext/commandhandler.py b/venv/lib/python3.8/site-packages/telegram/ext/commandhandler.py new file mode 100644 index 0000000..1f0a321 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/ext/commandhandler.py @@ -0,0 +1,456 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the CommandHandler and PrefixHandler classes.""" +import re +import warnings +from typing import TYPE_CHECKING, Callable, Dict, List, Optional, Tuple, TypeVar, Union + +from telegram import MessageEntity, Update +from telegram.ext import BaseFilter, Filters +from telegram.utils.deprecate import TelegramDeprecationWarning +from telegram.utils.types import SLT +from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE + +from .utils.types import CCT +from .handler import Handler + +if TYPE_CHECKING: + from telegram.ext import Dispatcher + +RT = TypeVar('RT') + + +class CommandHandler(Handler[Update, CCT]): + """Handler class to handle Telegram commands. + + Commands are Telegram messages that start with ``/``, optionally followed by an ``@`` and the + bot's name and/or some additional text. The handler will add a ``list`` to the + :class:`CallbackContext` named :attr:`CallbackContext.args`. It will contain a list of strings, + which is the text following the command split on single or consecutive whitespace characters. + + By default the handler listens to messages as well as edited messages. To change this behavior + use ``~Filters.update.edited_message`` in the filter argument. + + Note: + * :class:`CommandHandler` does *not* handle (edited) channel posts. + * :attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a :obj:`dict` you + can use to keep any data in will be sent to the :attr:`callback` function. Related to + either the user or the chat that the update was sent in. For each update from the same + user or in the same chat, it will be the same :obj:`dict`. + + Note that this is DEPRECATED, and you should use context based callbacks. See + https://git.io/fxJuV for more info. + + Warning: + When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom + attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. + + Args: + command (:class:`telegram.utils.types.SLT[str]`): + The command or list of commands this handler should listen for. + Limitations are the same as described here https://core.telegram.org/bots#commands + callback (:obj:`callable`): The callback function for this handler. Will be called when + :attr:`check_update` has determined that an update should be processed by this handler. + Callback signature for context based API: + + ``def callback(update: Update, context: CallbackContext)`` + + The return value of the callback is usually ignored except for the special case of + :class:`telegram.ext.ConversationHandler`. + filters (:class:`telegram.ext.BaseFilter`, optional): A filter inheriting from + :class:`telegram.ext.filters.BaseFilter`. Standard filters can be found in + :class:`telegram.ext.filters.Filters`. Filters can be combined using bitwise + operators (& for and, | for or, ~ for not). + allow_edited (:obj:`bool`, optional): Determines whether the handler should also accept + edited messages. Default is :obj:`False`. + DEPRECATED: Edited is allowed by default. To change this behavior use + ``~Filters.update.edited_message``. + pass_args (:obj:`bool`, optional): Determines whether the handler should be passed the + arguments passed to the command as a keyword argument called ``args``. It will contain + a list of strings, which is the text following the command split on single or + consecutive whitespace characters. Default is :obj:`False` + DEPRECATED: Please switch to context based callbacks. + pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``update_queue`` will be passed to the callback function. It will be the ``Queue`` + instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher` + that contains new updates which can be used to insert updates. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``job_queue`` will be passed to the callback function. It will be a + :class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater` + which can be used to schedule new jobs. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``user_data`` will be passed to the callback function. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``chat_data`` will be passed to the callback function. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + run_async (:obj:`bool`): Determines whether the callback will run asynchronously. + Defaults to :obj:`False`. + + Raises: + ValueError: when command is too long or has illegal chars. + + Attributes: + command (:class:`telegram.utils.types.SLT[str]`): + The command or list of commands this handler should listen for. + Limitations are the same as described here https://core.telegram.org/bots#commands + callback (:obj:`callable`): The callback function for this handler. + filters (:class:`telegram.ext.BaseFilter`): Optional. Only allow updates with these + Filters. + allow_edited (:obj:`bool`): Determines whether the handler should also accept + edited messages. + pass_args (:obj:`bool`): Determines whether the handler should be passed + ``args``. + pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be + passed to the callback function. + pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to + the callback function. + pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to + the callback function. + pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to + the callback function. + run_async (:obj:`bool`): Determines whether the callback will run asynchronously. + """ + + __slots__ = ('command', 'filters', 'pass_args') + + def __init__( + self, + command: SLT[str], + callback: Callable[[Update, CCT], RT], + filters: BaseFilter = None, + allow_edited: bool = None, + pass_args: bool = False, + pass_update_queue: bool = False, + pass_job_queue: bool = False, + pass_user_data: bool = False, + pass_chat_data: bool = False, + run_async: Union[bool, DefaultValue] = DEFAULT_FALSE, + ): + super().__init__( + callback, + pass_update_queue=pass_update_queue, + pass_job_queue=pass_job_queue, + pass_user_data=pass_user_data, + pass_chat_data=pass_chat_data, + run_async=run_async, + ) + + if isinstance(command, str): + self.command = [command.lower()] + else: + self.command = [x.lower() for x in command] + for comm in self.command: + if not re.match(r'^[\da-z_]{1,32}$', comm): + raise ValueError('Command is not a valid bot command') + + if filters: + self.filters = Filters.update.messages & filters + else: + self.filters = Filters.update.messages + + if allow_edited is not None: + warnings.warn( + 'allow_edited is deprecated. See https://git.io/fxJuV for more info', + TelegramDeprecationWarning, + stacklevel=2, + ) + if not allow_edited: + self.filters &= ~Filters.update.edited_message + self.pass_args = pass_args + + def check_update( + self, update: object + ) -> Optional[Union[bool, Tuple[List[str], Optional[Union[bool, Dict]]]]]: + """Determines whether an update should be passed to this handlers :attr:`callback`. + + Args: + update (:class:`telegram.Update` | :obj:`object`): Incoming update. + + Returns: + :obj:`list`: The list of args for the handler. + + """ + if isinstance(update, Update) and update.effective_message: + message = update.effective_message + + if ( + message.entities + and message.entities[0].type == MessageEntity.BOT_COMMAND + and message.entities[0].offset == 0 + and message.text + and message.bot + ): + command = message.text[1 : message.entities[0].length] + args = message.text.split()[1:] + command_parts = command.split('@') + command_parts.append(message.bot.username) + + if not ( + command_parts[0].lower() in self.command + and command_parts[1].lower() == message.bot.username.lower() + ): + return None + + filter_result = self.filters(update) + if filter_result: + return args, filter_result + return False + return None + + def collect_optional_args( + self, + dispatcher: 'Dispatcher', + update: Update = None, + check_result: Optional[Union[bool, Tuple[List[str], Optional[bool]]]] = None, + ) -> Dict[str, object]: + """Provide text after the command to the callback the ``args`` argument as list, split on + single whitespaces. + """ + optional_args = super().collect_optional_args(dispatcher, update) + if self.pass_args and isinstance(check_result, tuple): + optional_args['args'] = check_result[0] + return optional_args + + def collect_additional_context( + self, + context: CCT, + update: Update, + dispatcher: 'Dispatcher', + check_result: Optional[Union[bool, Tuple[List[str], Optional[bool]]]], + ) -> None: + """Add text after the command to :attr:`CallbackContext.args` as list, split on single + whitespaces and add output of data filters to :attr:`CallbackContext` as well. + """ + if isinstance(check_result, tuple): + context.args = check_result[0] + if isinstance(check_result[1], dict): + context.update(check_result[1]) + + +class PrefixHandler(CommandHandler): + """Handler class to handle custom prefix commands. + + This is a intermediate handler between :class:`MessageHandler` and :class:`CommandHandler`. + It supports configurable commands with the same options as CommandHandler. It will respond to + every combination of :attr:`prefix` and :attr:`command`. It will add a ``list`` to the + :class:`CallbackContext` named :attr:`CallbackContext.args`. It will contain a list of strings, + which is the text following the command split on single or consecutive whitespace characters. + + Examples: + + Single prefix and command: + + .. code:: python + + PrefixHandler('!', 'test', callback) # will respond to '!test'. + + Multiple prefixes, single command: + + .. code:: python + + PrefixHandler(['!', '#'], 'test', callback) # will respond to '!test' and '#test'. + + Multiple prefixes and commands: + + .. code:: python + + PrefixHandler(['!', '#'], ['test', 'help'], callback) # will respond to '!test', \ + '#test', '!help' and '#help'. + + + By default the handler listens to messages as well as edited messages. To change this behavior + use ``~Filters.update.edited_message``. + + Note: + * :class:`PrefixHandler` does *not* handle (edited) channel posts. + * :attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a :obj:`dict` you + can use to keep any data in will be sent to the :attr:`callback` function. Related to + either the user or the chat that the update was sent in. For each update from the same + user or in the same chat, it will be the same :obj:`dict`. + + Note that this is DEPRECATED, and you should use context based callbacks. See + https://git.io/fxJuV for more info. + + Warning: + When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom + attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. + + Args: + prefix (:class:`telegram.utils.types.SLT[str]`): + The prefix(es) that will precede :attr:`command`. + command (:class:`telegram.utils.types.SLT[str]`): + The command or list of commands this handler should listen for. + callback (:obj:`callable`): The callback function for this handler. Will be called when + :attr:`check_update` has determined that an update should be processed by this handler. + Callback signature for context based API: + + ``def callback(update: Update, context: CallbackContext)`` + + The return value of the callback is usually ignored except for the special case of + :class:`telegram.ext.ConversationHandler`. + filters (:class:`telegram.ext.BaseFilter`, optional): A filter inheriting from + :class:`telegram.ext.filters.BaseFilter`. Standard filters can be found in + :class:`telegram.ext.filters.Filters`. Filters can be combined using bitwise + operators (& for and, | for or, ~ for not). + pass_args (:obj:`bool`, optional): Determines whether the handler should be passed the + arguments passed to the command as a keyword argument called ``args``. It will contain + a list of strings, which is the text following the command split on single or + consecutive whitespace characters. Default is :obj:`False` + DEPRECATED: Please switch to context based callbacks. + pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``update_queue`` will be passed to the callback function. It will be the ``Queue`` + instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher` + that contains new updates which can be used to insert updates. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``job_queue`` will be passed to the callback function. It will be a + :class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater` + which can be used to schedule new jobs. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``user_data`` will be passed to the callback function. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``chat_data`` will be passed to the callback function. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + run_async (:obj:`bool`): Determines whether the callback will run asynchronously. + Defaults to :obj:`False`. + + Attributes: + callback (:obj:`callable`): The callback function for this handler. + filters (:class:`telegram.ext.BaseFilter`): Optional. Only allow updates with these + Filters. + pass_args (:obj:`bool`): Determines whether the handler should be passed + ``args``. + pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be + passed to the callback function. + pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to + the callback function. + pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to + the callback function. + pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to + the callback function. + run_async (:obj:`bool`): Determines whether the callback will run asynchronously. + + """ + + # 'prefix' is a class property, & 'command' is included in the superclass, so they're left out. + __slots__ = ('_prefix', '_command', '_commands') + + def __init__( + self, + prefix: SLT[str], + command: SLT[str], + callback: Callable[[Update, CCT], RT], + filters: BaseFilter = None, + pass_args: bool = False, + pass_update_queue: bool = False, + pass_job_queue: bool = False, + pass_user_data: bool = False, + pass_chat_data: bool = False, + run_async: Union[bool, DefaultValue] = DEFAULT_FALSE, + ): + + self._prefix: List[str] = [] + self._command: List[str] = [] + self._commands: List[str] = [] + + super().__init__( + 'nocommand', + callback, + filters=filters, + allow_edited=None, + pass_args=pass_args, + pass_update_queue=pass_update_queue, + pass_job_queue=pass_job_queue, + pass_user_data=pass_user_data, + pass_chat_data=pass_chat_data, + run_async=run_async, + ) + + self.prefix = prefix # type: ignore[assignment] + self.command = command # type: ignore[assignment] + self._build_commands() + + @property + def prefix(self) -> List[str]: + """ + The prefixes that will precede :attr:`command`. + + Returns: + List[:obj:`str`] + """ + return self._prefix + + @prefix.setter + def prefix(self, prefix: Union[str, List[str]]) -> None: + if isinstance(prefix, str): + self._prefix = [prefix.lower()] + else: + self._prefix = prefix + self._build_commands() + + @property # type: ignore[override] + def command(self) -> List[str]: # type: ignore[override] + """ + The list of commands this handler should listen for. + + Returns: + List[:obj:`str`] + """ + return self._command + + @command.setter + def command(self, command: Union[str, List[str]]) -> None: + if isinstance(command, str): + self._command = [command.lower()] + else: + self._command = command + self._build_commands() + + def _build_commands(self) -> None: + self._commands = [x.lower() + y.lower() for x in self.prefix for y in self.command] + + def check_update( + self, update: object + ) -> Optional[Union[bool, Tuple[List[str], Optional[Union[bool, Dict]]]]]: + """Determines whether an update should be passed to this handlers :attr:`callback`. + + Args: + update (:class:`telegram.Update` | :obj:`object`): Incoming update. + + Returns: + :obj:`list`: The list of args for the handler. + + """ + if isinstance(update, Update) and update.effective_message: + message = update.effective_message + + if message.text: + text_list = message.text.split() + if text_list[0].lower() not in self._commands: + return None + filter_result = self.filters(update) + if filter_result: + return text_list[1:], filter_result + return False + return None diff --git a/venv/lib/python3.8/site-packages/telegram/ext/contexttypes.py b/venv/lib/python3.8/site-packages/telegram/ext/contexttypes.py new file mode 100644 index 0000000..2156e7f --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/ext/contexttypes.py @@ -0,0 +1,194 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2020 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +# pylint: disable=R0201 +"""This module contains the auxiliary class ContextTypes.""" +from typing import Type, Generic, overload, Dict # pylint: disable=W0611 + +from telegram.ext.callbackcontext import CallbackContext +from telegram.ext.utils.types import CCT, UD, CD, BD + + +class ContextTypes(Generic[CCT, UD, CD, BD]): + """ + Convenience class to gather customizable types of the :class:`telegram.ext.CallbackContext` + interface. + + .. versionadded:: 13.6 + + Args: + context (:obj:`type`, optional): Determines the type of the ``context`` argument of all + (error-)handler callbacks and job callbacks. Must be a subclass of + :class:`telegram.ext.CallbackContext`. Defaults to + :class:`telegram.ext.CallbackContext`. + bot_data (:obj:`type`, optional): Determines the type of ``context.bot_data`` of all + (error-)handler callbacks and job callbacks. Defaults to :obj:`dict`. Must support + instantiating without arguments. + chat_data (:obj:`type`, optional): Determines the type of ``context.chat_data`` of all + (error-)handler callbacks and job callbacks. Defaults to :obj:`dict`. Must support + instantiating without arguments. + user_data (:obj:`type`, optional): Determines the type of ``context.user_data`` of all + (error-)handler callbacks and job callbacks. Defaults to :obj:`dict`. Must support + instantiating without arguments. + + """ + + __slots__ = ('_context', '_bot_data', '_chat_data', '_user_data') + + @overload + def __init__( + self: 'ContextTypes[CallbackContext, Dict, Dict, Dict]', + ): + ... + + @overload + def __init__(self: 'ContextTypes[CCT, Dict, Dict, Dict]', context: Type[CCT]): + ... + + @overload + def __init__(self: 'ContextTypes[CallbackContext, UD, Dict, Dict]', bot_data: Type[UD]): + ... + + @overload + def __init__(self: 'ContextTypes[CallbackContext, Dict, CD, Dict]', chat_data: Type[CD]): + ... + + @overload + def __init__(self: 'ContextTypes[CallbackContext, Dict, Dict, BD]', user_data: Type[BD]): + ... + + @overload + def __init__( + self: 'ContextTypes[CCT, UD, Dict, Dict]', context: Type[CCT], bot_data: Type[UD] + ): + ... + + @overload + def __init__( + self: 'ContextTypes[CCT, Dict, CD, Dict]', context: Type[CCT], chat_data: Type[CD] + ): + ... + + @overload + def __init__( + self: 'ContextTypes[CCT, Dict, Dict, BD]', context: Type[CCT], user_data: Type[BD] + ): + ... + + @overload + def __init__( + self: 'ContextTypes[CallbackContext, UD, CD, Dict]', + bot_data: Type[UD], + chat_data: Type[CD], + ): + ... + + @overload + def __init__( + self: 'ContextTypes[CallbackContext, UD, Dict, BD]', + bot_data: Type[UD], + user_data: Type[BD], + ): + ... + + @overload + def __init__( + self: 'ContextTypes[CallbackContext, Dict, CD, BD]', + chat_data: Type[CD], + user_data: Type[BD], + ): + ... + + @overload + def __init__( + self: 'ContextTypes[CCT, UD, CD, Dict]', + context: Type[CCT], + bot_data: Type[UD], + chat_data: Type[CD], + ): + ... + + @overload + def __init__( + self: 'ContextTypes[CCT, UD, Dict, BD]', + context: Type[CCT], + bot_data: Type[UD], + user_data: Type[BD], + ): + ... + + @overload + def __init__( + self: 'ContextTypes[CCT, Dict, CD, BD]', + context: Type[CCT], + chat_data: Type[CD], + user_data: Type[BD], + ): + ... + + @overload + def __init__( + self: 'ContextTypes[CallbackContext, UD, CD, BD]', + bot_data: Type[UD], + chat_data: Type[CD], + user_data: Type[BD], + ): + ... + + @overload + def __init__( + self: 'ContextTypes[CCT, UD, CD, BD]', + context: Type[CCT], + bot_data: Type[UD], + chat_data: Type[CD], + user_data: Type[BD], + ): + ... + + def __init__( # type: ignore[no-untyped-def] + self, + context=CallbackContext, + bot_data=dict, + chat_data=dict, + user_data=dict, + ): + if not issubclass(context, CallbackContext): + raise ValueError('context must be a subclass of CallbackContext.') + + # We make all those only accessible via properties because we don't currently support + # changing this at runtime, so overriding the attributes doesn't make sense + self._context = context + self._bot_data = bot_data + self._chat_data = chat_data + self._user_data = user_data + + @property + def context(self) -> Type[CCT]: + return self._context + + @property + def bot_data(self) -> Type[BD]: + return self._bot_data + + @property + def chat_data(self) -> Type[CD]: + return self._chat_data + + @property + def user_data(self) -> Type[UD]: + return self._user_data diff --git a/venv/lib/python3.8/site-packages/telegram/ext/conversationhandler.py b/venv/lib/python3.8/site-packages/telegram/ext/conversationhandler.py new file mode 100644 index 0000000..df94f9b --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/ext/conversationhandler.py @@ -0,0 +1,725 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +# pylint: disable=R0201 +"""This module contains the ConversationHandler.""" + +import logging +import warnings +import functools +import datetime +from threading import Lock +from typing import TYPE_CHECKING, Dict, List, NoReturn, Optional, Union, Tuple, cast, ClassVar + +from telegram import Update +from telegram.ext import ( + BasePersistence, + CallbackContext, + CallbackQueryHandler, + ChosenInlineResultHandler, + DispatcherHandlerStop, + Handler, + InlineQueryHandler, +) +from telegram.ext.utils.promise import Promise +from telegram.ext.utils.types import ConversationDict +from telegram.ext.utils.types import CCT + +if TYPE_CHECKING: + from telegram.ext import Dispatcher, Job +CheckUpdateType = Optional[Tuple[Tuple[int, ...], Handler, object]] + + +class _ConversationTimeoutContext: + # '__dict__' is not included since this a private class + __slots__ = ('conversation_key', 'update', 'dispatcher', 'callback_context') + + def __init__( + self, + conversation_key: Tuple[int, ...], + update: Update, + dispatcher: 'Dispatcher', + callback_context: Optional[CallbackContext], + ): + self.conversation_key = conversation_key + self.update = update + self.dispatcher = dispatcher + self.callback_context = callback_context + + +class ConversationHandler(Handler[Update, CCT]): + """ + A handler to hold a conversation with a single or multiple users through Telegram updates by + managing four collections of other handlers. + + Note: + ``ConversationHandler`` will only accept updates that are (subclass-)instances of + :class:`telegram.Update`. This is, because depending on the :attr:`per_user` and + :attr:`per_chat` ``ConversationHandler`` relies on + :attr:`telegram.Update.effective_user` and/or :attr:`telegram.Update.effective_chat` in + order to determine which conversation an update should belong to. For ``per_message=True``, + ``ConversationHandler`` uses ``update.callback_query.message.message_id`` when + ``per_chat=True`` and ``update.callback_query.inline_message_id`` when ``per_chat=False``. + For a more detailed explanation, please see our `FAQ`_. + + Finally, ``ConversationHandler``, does *not* handle (edited) channel posts. + + .. _`FAQ`: https://git.io/JtcyU + + The first collection, a ``list`` named :attr:`entry_points`, is used to initiate the + conversation, for example with a :class:`telegram.ext.CommandHandler` or + :class:`telegram.ext.MessageHandler`. + + The second collection, a ``dict`` named :attr:`states`, contains the different conversation + steps and one or more associated handlers that should be used if the user sends a message when + the conversation with them is currently in that state. Here you can also define a state for + :attr:`TIMEOUT` to define the behavior when :attr:`conversation_timeout` is exceeded, and a + state for :attr:`WAITING` to define behavior when a new update is received while the previous + ``@run_async`` decorated handler is not finished. + + The third collection, a ``list`` named :attr:`fallbacks`, is used if the user is currently in a + conversation but the state has either no associated handler or the handler that is associated + to the state is inappropriate for the update, for example if the update contains a command, but + a regular text message is expected. You could use this for a ``/cancel`` command or to let the + user know their message was not recognized. + + To change the state of conversation, the callback function of a handler must return the new + state after responding to the user. If it does not return anything (returning :obj:`None` by + default), the state will not change. If an entry point callback function returns :obj:`None`, + the conversation ends immediately after the execution of this callback function. + To end the conversation, the callback function must return :attr:`END` or ``-1``. To + handle the conversation timeout, use handler :attr:`TIMEOUT` or ``-2``. + Finally, :class:`telegram.ext.DispatcherHandlerStop` can be used in conversations as described + in the corresponding documentation. + + Note: + In each of the described collections of handlers, a handler may in turn be a + :class:`ConversationHandler`. In that case, the nested :class:`ConversationHandler` should + have the attribute :attr:`map_to_parent` which allows to return to the parent conversation + at specified states within the nested conversation. + + Note that the keys in :attr:`map_to_parent` must not appear as keys in :attr:`states` + attribute or else the latter will be ignored. You may map :attr:`END` to one of the parents + states to continue the parent conversation after this has ended or even map a state to + :attr:`END` to end the *parent* conversation from within the nested one. For an example on + nested :class:`ConversationHandler` s, see our `examples`_. + + .. _`examples`: https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples + + Args: + entry_points (List[:class:`telegram.ext.Handler`]): A list of ``Handler`` objects that can + trigger the start of the conversation. The first handler which :attr:`check_update` + method returns :obj:`True` will be used. If all return :obj:`False`, the update is not + handled. + states (Dict[:obj:`object`, List[:class:`telegram.ext.Handler`]]): A :obj:`dict` that + defines the different states of conversation a user can be in and one or more + associated ``Handler`` objects that should be used in that state. The first handler + which :attr:`check_update` method returns :obj:`True` will be used. + fallbacks (List[:class:`telegram.ext.Handler`]): A list of handlers that might be used if + the user is in a conversation, but every handler for their current state returned + :obj:`False` on :attr:`check_update`. The first handler which :attr:`check_update` + method returns :obj:`True` will be used. If all return :obj:`False`, the update is not + handled. + allow_reentry (:obj:`bool`, optional): If set to :obj:`True`, a user that is currently in a + conversation can restart the conversation by triggering one of the entry points. + per_chat (:obj:`bool`, optional): If the conversationkey should contain the Chat's ID. + Default is :obj:`True`. + per_user (:obj:`bool`, optional): If the conversationkey should contain the User's ID. + Default is :obj:`True`. + per_message (:obj:`bool`, optional): If the conversationkey should contain the Message's + ID. Default is :obj:`False`. + conversation_timeout (:obj:`float` | :obj:`datetime.timedelta`, optional): When this + handler is inactive more than this timeout (in seconds), it will be automatically + ended. If this value is 0 or :obj:`None` (default), there will be no timeout. The last + received update and the corresponding ``context`` will be handled by ALL the handler's + who's :attr:`check_update` method returns :obj:`True` that are in the state + :attr:`ConversationHandler.TIMEOUT`. + + Note: + Using `conversation_timeout` with nested conversations is currently not + supported. You can still try to use it, but it will likely behave differently + from what you expect. + + + name (:obj:`str`, optional): The name for this conversationhandler. Required for + persistence. + persistent (:obj:`bool`, optional): If the conversations dict for this handler should be + saved. Name is required and persistence has to be set in :class:`telegram.ext.Updater` + map_to_parent (Dict[:obj:`object`, :obj:`object`], optional): A :obj:`dict` that can be + used to instruct a nested conversationhandler to transition into a mapped state on + its parent conversationhandler in place of a specified nested state. + run_async (:obj:`bool`, optional): Pass :obj:`True` to *override* the + :attr:`Handler.run_async` setting of all handlers (in :attr:`entry_points`, + :attr:`states` and :attr:`fallbacks`). + + Note: + If set to :obj:`True`, you should not pass a handler instance, that needs to be + run synchronously in another context. + + .. versionadded:: 13.2 + + Raises: + ValueError + + Attributes: + persistent (:obj:`bool`): Optional. If the conversations dict for this handler should be + saved. Name is required and persistence has to be set in :class:`telegram.ext.Updater` + run_async (:obj:`bool`): If :obj:`True`, will override the + :attr:`Handler.run_async` setting of all internal handlers on initialization. + + .. versionadded:: 13.2 + + """ + + __slots__ = ( + '_entry_points', + '_states', + '_fallbacks', + '_allow_reentry', + '_per_user', + '_per_chat', + '_per_message', + '_conversation_timeout', + '_name', + 'persistent', + '_persistence', + '_map_to_parent', + 'timeout_jobs', + '_timeout_jobs_lock', + '_conversations', + '_conversations_lock', + 'logger', + ) + + END: ClassVar[int] = -1 + """:obj:`int`: Used as a constant to return when a conversation is ended.""" + TIMEOUT: ClassVar[int] = -2 + """:obj:`int`: Used as a constant to handle state when a conversation is timed out.""" + WAITING: ClassVar[int] = -3 + """:obj:`int`: Used as a constant to handle state when a conversation is still waiting on the + previous ``@run_sync`` decorated running handler to finish.""" + # pylint: disable=W0231 + def __init__( + self, + entry_points: List[Handler[Update, CCT]], + states: Dict[object, List[Handler[Update, CCT]]], + fallbacks: List[Handler[Update, CCT]], + allow_reentry: bool = False, + per_chat: bool = True, + per_user: bool = True, + per_message: bool = False, + conversation_timeout: Union[float, datetime.timedelta] = None, + name: str = None, + persistent: bool = False, + map_to_parent: Dict[object, object] = None, + run_async: bool = False, + ): + self.run_async = run_async + + self._entry_points = entry_points + self._states = states + self._fallbacks = fallbacks + + self._allow_reentry = allow_reentry + self._per_user = per_user + self._per_chat = per_chat + self._per_message = per_message + self._conversation_timeout = conversation_timeout + self._name = name + if persistent and not self.name: + raise ValueError("Conversations can't be persistent when handler is unnamed.") + self.persistent: bool = persistent + self._persistence: Optional[BasePersistence] = None + """:obj:`telegram.ext.BasePersistence`: The persistence used to store conversations. + Set by dispatcher""" + self._map_to_parent = map_to_parent + + self.timeout_jobs: Dict[Tuple[int, ...], 'Job'] = {} + self._timeout_jobs_lock = Lock() + self._conversations: ConversationDict = {} + self._conversations_lock = Lock() + + self.logger = logging.getLogger(__name__) + + if not any((self.per_user, self.per_chat, self.per_message)): + raise ValueError("'per_user', 'per_chat' and 'per_message' can't all be 'False'") + + if self.per_message and not self.per_chat: + warnings.warn( + "If 'per_message=True' is used, 'per_chat=True' should also be used, " + "since message IDs are not globally unique." + ) + + all_handlers: List[Handler] = [] + all_handlers.extend(entry_points) + all_handlers.extend(fallbacks) + + for state_handlers in states.values(): + all_handlers.extend(state_handlers) + + if self.per_message: + for handler in all_handlers: + if not isinstance(handler, CallbackQueryHandler): + warnings.warn( + "If 'per_message=True', all entry points and state handlers" + " must be 'CallbackQueryHandler', since no other handlers " + "have a message context." + ) + break + else: + for handler in all_handlers: + if isinstance(handler, CallbackQueryHandler): + warnings.warn( + "If 'per_message=False', 'CallbackQueryHandler' will not be " + "tracked for every message." + ) + break + + if self.per_chat: + for handler in all_handlers: + if isinstance(handler, (InlineQueryHandler, ChosenInlineResultHandler)): + warnings.warn( + "If 'per_chat=True', 'InlineQueryHandler' can not be used, " + "since inline queries have no chat context." + ) + break + + if self.conversation_timeout: + for handler in all_handlers: + if isinstance(handler, self.__class__): + warnings.warn( + "Using `conversation_timeout` with nested conversations is currently not " + "supported. You can still try to use it, but it will likely behave " + "differently from what you expect." + ) + break + + if self.run_async: + for handler in all_handlers: + handler.run_async = True + + @property + def entry_points(self) -> List[Handler]: + """List[:class:`telegram.ext.Handler`]: A list of ``Handler`` objects that can trigger the + start of the conversation. + """ + return self._entry_points + + @entry_points.setter + def entry_points(self, value: object) -> NoReturn: + raise ValueError('You can not assign a new value to entry_points after initialization.') + + @property + def states(self) -> Dict[object, List[Handler]]: + """Dict[:obj:`object`, List[:class:`telegram.ext.Handler`]]: A :obj:`dict` that + defines the different states of conversation a user can be in and one or more + associated ``Handler`` objects that should be used in that state. + """ + return self._states + + @states.setter + def states(self, value: object) -> NoReturn: + raise ValueError('You can not assign a new value to states after initialization.') + + @property + def fallbacks(self) -> List[Handler]: + """List[:class:`telegram.ext.Handler`]: A list of handlers that might be used if + the user is in a conversation, but every handler for their current state returned + :obj:`False` on :attr:`check_update`. + """ + return self._fallbacks + + @fallbacks.setter + def fallbacks(self, value: object) -> NoReturn: + raise ValueError('You can not assign a new value to fallbacks after initialization.') + + @property + def allow_reentry(self) -> bool: + return self._allow_reentry + + @allow_reentry.setter + def allow_reentry(self, value: object) -> NoReturn: + """:obj:`bool`: Determines if a user can restart a conversation with an entry point.""" + raise ValueError('You can not assign a new value to allow_reentry after initialization.') + + @property + def per_user(self) -> bool: + """:obj:`bool`: If the conversation key should contain the User's ID.""" + return self._per_user + + @per_user.setter + def per_user(self, value: object) -> NoReturn: + raise ValueError('You can not assign a new value to per_user after initialization.') + + @property + def per_chat(self) -> bool: + """:obj:`bool`: If the conversation key should contain the Chat's ID.""" + return self._per_chat + + @per_chat.setter + def per_chat(self, value: object) -> NoReturn: + raise ValueError('You can not assign a new value to per_chat after initialization.') + + @property + def per_message(self) -> bool: + """:obj:`bool`: If the conversation key should contain the message's ID.""" + return self._per_message + + @per_message.setter + def per_message(self, value: object) -> NoReturn: + raise ValueError('You can not assign a new value to per_message after initialization.') + + @property + def conversation_timeout( + self, + ) -> Optional[Union[float, datetime.timedelta]]: + """:obj:`float` | :obj:`datetime.timedelta`: Optional. When this + handler is inactive more than this timeout (in seconds), it will be automatically + ended. + """ + return self._conversation_timeout + + @conversation_timeout.setter + def conversation_timeout(self, value: object) -> NoReturn: + raise ValueError( + 'You can not assign a new value to conversation_timeout after initialization.' + ) + + @property + def name(self) -> Optional[str]: + """:obj:`str`: Optional. The name for this :class:`ConversationHandler`.""" + return self._name + + @name.setter + def name(self, value: object) -> NoReturn: + raise ValueError('You can not assign a new value to name after initialization.') + + @property + def map_to_parent(self) -> Optional[Dict[object, object]]: + """Dict[:obj:`object`, :obj:`object`]: Optional. A :obj:`dict` that can be + used to instruct a nested :class:`ConversationHandler` to transition into a mapped state on + its parent :class:`ConversationHandler` in place of a specified nested state. + """ + return self._map_to_parent + + @map_to_parent.setter + def map_to_parent(self, value: object) -> NoReturn: + raise ValueError('You can not assign a new value to map_to_parent after initialization.') + + @property + def persistence(self) -> Optional[BasePersistence]: + """The persistence class as provided by the :class:`Dispatcher`.""" + return self._persistence + + @persistence.setter + def persistence(self, persistence: BasePersistence) -> None: + self._persistence = persistence + # Set persistence for nested conversations + for handlers in self.states.values(): + for handler in handlers: + if isinstance(handler, ConversationHandler): + handler.persistence = self.persistence + + @property + def conversations(self) -> ConversationDict: # skipcq: PY-D0003 + return self._conversations + + @conversations.setter + def conversations(self, value: ConversationDict) -> None: + self._conversations = value + # Set conversations for nested conversations + for handlers in self.states.values(): + for handler in handlers: + if isinstance(handler, ConversationHandler) and self.persistence and handler.name: + handler.conversations = self.persistence.get_conversations(handler.name) + + def _get_key(self, update: Update) -> Tuple[int, ...]: + chat = update.effective_chat + user = update.effective_user + + key = [] + + if self.per_chat: + key.append(chat.id) # type: ignore[union-attr] + + if self.per_user and user is not None: + key.append(user.id) + + if self.per_message: + key.append( + update.callback_query.inline_message_id # type: ignore[union-attr] + or update.callback_query.message.message_id # type: ignore[union-attr] + ) + + return tuple(key) + + def _resolve_promise(self, state: Tuple) -> object: + old_state, new_state = state + try: + res = new_state.result(0) + res = res if res is not None else old_state + except Exception as exc: + self.logger.exception("Promise function raised exception") + self.logger.exception("%s", exc) + res = old_state + finally: + if res is None and old_state is None: + res = self.END + return res + + def _schedule_job( + self, + new_state: object, + dispatcher: 'Dispatcher', + update: Update, + context: Optional[CallbackContext], + conversation_key: Tuple[int, ...], + ) -> None: + if new_state != self.END: + try: + # both job_queue & conversation_timeout are checked before calling _schedule_job + j_queue = dispatcher.job_queue + self.timeout_jobs[conversation_key] = j_queue.run_once( # type: ignore[union-attr] + self._trigger_timeout, + self.conversation_timeout, # type: ignore[arg-type] + context=_ConversationTimeoutContext( + conversation_key, update, dispatcher, context + ), + ) + except Exception as exc: + self.logger.exception( + "Failed to schedule timeout job due to the following exception:" + ) + self.logger.exception("%s", exc) + + def check_update(self, update: object) -> CheckUpdateType: # pylint: disable=R0911 + """ + Determines whether an update should be handled by this conversationhandler, and if so in + which state the conversation currently is. + + Args: + update (:class:`telegram.Update` | :obj:`object`): Incoming update. + + Returns: + :obj:`bool` + + """ + if not isinstance(update, Update): + return None + # Ignore messages in channels + if update.channel_post or update.edited_channel_post: + return None + if self.per_chat and not update.effective_chat: + return None + if self.per_message and not update.callback_query: + return None + if update.callback_query and self.per_chat and not update.callback_query.message: + return None + + key = self._get_key(update) + with self._conversations_lock: + state = self.conversations.get(key) + + # Resolve promises + if isinstance(state, tuple) and len(state) == 2 and isinstance(state[1], Promise): + self.logger.debug('waiting for promise...') + + # check if promise is finished or not + if state[1].done.wait(0): + res = self._resolve_promise(state) + self._update_state(res, key) + with self._conversations_lock: + state = self.conversations.get(key) + + # if not then handle WAITING state instead + else: + hdlrs = self.states.get(self.WAITING, []) + for hdlr in hdlrs: + check = hdlr.check_update(update) + if check is not None and check is not False: + return key, hdlr, check + return None + + self.logger.debug('selecting conversation %s with state %s', str(key), str(state)) + + handler = None + + # Search entry points for a match + if state is None or self.allow_reentry: + for entry_point in self.entry_points: + check = entry_point.check_update(update) + if check is not None and check is not False: + handler = entry_point + break + + else: + if state is None: + return None + + # Get the handler list for current state, if we didn't find one yet and we're still here + if state is not None and not handler: + handlers = self.states.get(state) + + for candidate in handlers or []: + check = candidate.check_update(update) + if check is not None and check is not False: + handler = candidate + break + + # Find a fallback handler if all other handlers fail + else: + for fallback in self.fallbacks: + check = fallback.check_update(update) + if check is not None and check is not False: + handler = fallback + break + + else: + return None + + return key, handler, check # type: ignore[return-value] + + def handle_update( # type: ignore[override] + self, + update: Update, + dispatcher: 'Dispatcher', + check_result: CheckUpdateType, + context: CallbackContext = None, + ) -> Optional[object]: + """Send the update to the callback for the current state and Handler + + Args: + check_result: The result from check_update. For this handler it's a tuple of key, + handler, and the handler's check result. + update (:class:`telegram.Update`): Incoming telegram update. + dispatcher (:class:`telegram.ext.Dispatcher`): Dispatcher that originated the Update. + context (:class:`telegram.ext.CallbackContext`, optional): The context as provided by + the dispatcher. + + """ + update = cast(Update, update) # for mypy + conversation_key, handler, check_result = check_result # type: ignore[assignment,misc] + raise_dp_handler_stop = False + + with self._timeout_jobs_lock: + # Remove the old timeout job (if present) + timeout_job = self.timeout_jobs.pop(conversation_key, None) + + if timeout_job is not None: + timeout_job.schedule_removal() + try: + new_state = handler.handle_update(update, dispatcher, check_result, context) + except DispatcherHandlerStop as exception: + new_state = exception.state + raise_dp_handler_stop = True + with self._timeout_jobs_lock: + if self.conversation_timeout: + if dispatcher.job_queue is not None: + # Add the new timeout job + if isinstance(new_state, Promise): + new_state.add_done_callback( + functools.partial( + self._schedule_job, + dispatcher=dispatcher, + update=update, + context=context, + conversation_key=conversation_key, + ) + ) + elif new_state != self.END: + self._schedule_job( + new_state, dispatcher, update, context, conversation_key + ) + else: + self.logger.warning( + "Ignoring `conversation_timeout` because the Dispatcher has no JobQueue." + ) + + if isinstance(self.map_to_parent, dict) and new_state in self.map_to_parent: + self._update_state(self.END, conversation_key) + if raise_dp_handler_stop: + raise DispatcherHandlerStop(self.map_to_parent.get(new_state)) + return self.map_to_parent.get(new_state) + + self._update_state(new_state, conversation_key) + if raise_dp_handler_stop: + # Don't pass the new state here. If we're in a nested conversation, the parent is + # expecting None as return value. + raise DispatcherHandlerStop() + return None + + def _update_state(self, new_state: object, key: Tuple[int, ...]) -> None: + if new_state == self.END: + with self._conversations_lock: + if key in self.conversations: + # If there is no key in conversations, nothing is done. + del self.conversations[key] + if self.persistent and self.persistence and self.name: + self.persistence.update_conversation(self.name, key, None) + + elif isinstance(new_state, Promise): + with self._conversations_lock: + self.conversations[key] = (self.conversations.get(key), new_state) + if self.persistent and self.persistence and self.name: + self.persistence.update_conversation( + self.name, key, (self.conversations.get(key), new_state) + ) + + elif new_state is not None: + if new_state not in self.states: + warnings.warn( + f"Handler returned state {new_state} which is unknown to the " + f"ConversationHandler{' ' + self.name if self.name is not None else ''}." + ) + with self._conversations_lock: + self.conversations[key] = new_state + if self.persistent and self.persistence and self.name: + self.persistence.update_conversation(self.name, key, new_state) + + def _trigger_timeout(self, context: CallbackContext, job: 'Job' = None) -> None: + self.logger.debug('conversation timeout was triggered!') + + # Backward compatibility with bots that do not use CallbackContext + if isinstance(context, CallbackContext): + job = context.job + ctxt = cast(_ConversationTimeoutContext, job.context) # type: ignore[union-attr] + else: + ctxt = cast(_ConversationTimeoutContext, job.context) + + callback_context = ctxt.callback_context + + with self._timeout_jobs_lock: + found_job = self.timeout_jobs[ctxt.conversation_key] + if found_job is not job: + # The timeout has been cancelled in handle_update + return + del self.timeout_jobs[ctxt.conversation_key] + + handlers = self.states.get(self.TIMEOUT, []) + for handler in handlers: + check = handler.check_update(ctxt.update) + if check is not None and check is not False: + try: + handler.handle_update(ctxt.update, ctxt.dispatcher, check, callback_context) + except DispatcherHandlerStop: + self.logger.warning( + 'DispatcherHandlerStop in TIMEOUT state of ' + 'ConversationHandler has no effect. Ignoring.' + ) + + self._update_state(self.END, ctxt.conversation_key) diff --git a/venv/lib/python3.8/site-packages/telegram/ext/defaults.py b/venv/lib/python3.8/site-packages/telegram/ext/defaults.py new file mode 100644 index 0000000..8546f71 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/ext/defaults.py @@ -0,0 +1,267 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2020-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +# pylint: disable=R0201 +"""This module contains the class Defaults, which allows to pass default values to Updater.""" +from typing import NoReturn, Optional, Dict, Any + +import pytz + +from telegram.utils.deprecate import set_new_attribute_deprecated +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import ODVInput + + +class Defaults: + """Convenience Class to gather all parameters with a (user defined) default value + + Parameters: + parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show + bold, italic, fixed-width text or URLs in your bot's message. + disable_notification (:obj:`bool`, optional): Sends the message silently. Users will + receive a notification with no sound. + disable_web_page_preview (:obj:`bool`, optional): Disables link previews for links in this + message. + allow_sending_without_reply (:obj:`bool`, optional): Pass :obj:`True`, if the message + should be sent even if the specified replied-to message is not found. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as the + read timeout from the server (instead of the one specified during creation of the + connection pool). + + Note: + Will *not* be used for :meth:`telegram.Bot.get_updates`! + quote (:obj:`bool`, optional): If set to :obj:`True`, the reply is sent as an actual reply + to the message. If ``reply_to_message_id`` is passed in ``kwargs``, this parameter will + be ignored. Default: :obj:`True` in group chats and :obj:`False` in private chats. + tzinfo (:obj:`tzinfo`, optional): A timezone to be used for all date(time) inputs + appearing throughout PTB, i.e. if a timezone naive date(time) object is passed + somewhere, it will be assumed to be in ``tzinfo``. Must be a timezone provided by the + ``pytz`` module. Defaults to UTC. + run_async (:obj:`bool`, optional): Default setting for the ``run_async`` parameter of + handlers and error handlers registered through :meth:`Dispatcher.add_handler` and + :meth:`Dispatcher.add_error_handler`. Defaults to :obj:`False`. + """ + + __slots__ = ( + '_timeout', + '_tzinfo', + '_disable_web_page_preview', + '_run_async', + '_quote', + '_disable_notification', + '_allow_sending_without_reply', + '_parse_mode', + '_api_defaults', + '__dict__', + ) + + def __init__( + self, + parse_mode: str = None, + disable_notification: bool = None, + disable_web_page_preview: bool = None, + # Timeout needs special treatment, since the bot methods have two different + # default values for timeout (None and 20s) + timeout: ODVInput[float] = DEFAULT_NONE, + quote: bool = None, + tzinfo: pytz.BaseTzInfo = pytz.utc, + run_async: bool = False, + allow_sending_without_reply: bool = None, + ): + self._parse_mode = parse_mode + self._disable_notification = disable_notification + self._disable_web_page_preview = disable_web_page_preview + self._allow_sending_without_reply = allow_sending_without_reply + self._timeout = timeout + self._quote = quote + self._tzinfo = tzinfo + self._run_async = run_async + + # Gather all defaults that actually have a default value + self._api_defaults = {} + for kwarg in ( + 'parse_mode', + 'explanation_parse_mode', + 'disable_notification', + 'disable_web_page_preview', + 'allow_sending_without_reply', + ): + value = getattr(self, kwarg) + if value not in [None, DEFAULT_NONE]: + self._api_defaults[kwarg] = value + # Special casing, as None is a valid default value + if self._timeout != DEFAULT_NONE: + self._api_defaults['timeout'] = self._timeout + + def __setattr__(self, key: str, value: object) -> None: + set_new_attribute_deprecated(self, key, value) + + @property + def api_defaults(self) -> Dict[str, Any]: # skip-cq: PY-D0003 + return self._api_defaults + + @property + def parse_mode(self) -> Optional[str]: + """:obj:`str`: Optional. Send Markdown or HTML, if you want Telegram apps to show + bold, italic, fixed-width text or URLs in your bot's message. + """ + return self._parse_mode + + @parse_mode.setter + def parse_mode(self, value: object) -> NoReturn: + raise AttributeError( + "You can not assign a new value to defaults after because it would " + "not have any effect." + ) + + @property + def explanation_parse_mode(self) -> Optional[str]: + """:obj:`str`: Optional. Alias for :attr:`parse_mode`, used for + the corresponding parameter of :meth:`telegram.Bot.send_poll`. + """ + return self._parse_mode + + @explanation_parse_mode.setter + def explanation_parse_mode(self, value: object) -> NoReturn: + raise AttributeError( + "You can not assign a new value to defaults after because it would " + "not have any effect." + ) + + @property + def disable_notification(self) -> Optional[bool]: + """:obj:`bool`: Optional. Sends the message silently. Users will + receive a notification with no sound. + """ + return self._disable_notification + + @disable_notification.setter + def disable_notification(self, value: object) -> NoReturn: + raise AttributeError( + "You can not assign a new value to defaults after because it would " + "not have any effect." + ) + + @property + def disable_web_page_preview(self) -> Optional[bool]: + """:obj:`bool`: Optional. Disables link previews for links in this + message. + """ + return self._disable_web_page_preview + + @disable_web_page_preview.setter + def disable_web_page_preview(self, value: object) -> NoReturn: + raise AttributeError( + "You can not assign a new value to defaults after because it would " + "not have any effect." + ) + + @property + def allow_sending_without_reply(self) -> Optional[bool]: + """:obj:`bool`: Optional. Pass :obj:`True`, if the message + should be sent even if the specified replied-to message is not found. + """ + return self._allow_sending_without_reply + + @allow_sending_without_reply.setter + def allow_sending_without_reply(self, value: object) -> NoReturn: + raise AttributeError( + "You can not assign a new value to defaults after because it would " + "not have any effect." + ) + + @property + def timeout(self) -> ODVInput[float]: + """:obj:`int` | :obj:`float`: Optional. If this value is specified, use it as the + read timeout from the server (instead of the one specified during creation of the + connection pool). + """ + return self._timeout + + @timeout.setter + def timeout(self, value: object) -> NoReturn: + raise AttributeError( + "You can not assign a new value to defaults after because it would " + "not have any effect." + ) + + @property + def quote(self) -> Optional[bool]: + """:obj:`bool`: Optional. If set to :obj:`True`, the reply is sent as an actual reply + to the message. If ``reply_to_message_id`` is passed in ``kwargs``, this parameter will + be ignored. Default: :obj:`True` in group chats and :obj:`False` in private chats. + """ + return self._quote + + @quote.setter + def quote(self, value: object) -> NoReturn: + raise AttributeError( + "You can not assign a new value to defaults after because it would " + "not have any effect." + ) + + @property + def tzinfo(self) -> pytz.BaseTzInfo: + """:obj:`tzinfo`: A timezone to be used for all date(time) objects appearing + throughout PTB. + """ + return self._tzinfo + + @tzinfo.setter + def tzinfo(self, value: object) -> NoReturn: + raise AttributeError( + "You can not assign a new value to defaults after because it would " + "not have any effect." + ) + + @property + def run_async(self) -> bool: + """:obj:`bool`: Optional. Default setting for the ``run_async`` parameter of + handlers and error handlers registered through :meth:`Dispatcher.add_handler` and + :meth:`Dispatcher.add_error_handler`. + """ + return self._run_async + + @run_async.setter + def run_async(self, value: object) -> NoReturn: + raise AttributeError( + "You can not assign a new value to defaults after because it would " + "not have any effect." + ) + + def __hash__(self) -> int: + return hash( + ( + self._parse_mode, + self._disable_notification, + self._disable_web_page_preview, + self._allow_sending_without_reply, + self._timeout, + self._quote, + self._tzinfo, + self._run_async, + ) + ) + + def __eq__(self, other: object) -> bool: + if isinstance(other, Defaults): + return all(getattr(self, attr) == getattr(other, attr) for attr in self.__slots__) + return False + + def __ne__(self, other: object) -> bool: + return not self == other diff --git a/venv/lib/python3.8/site-packages/telegram/ext/dictpersistence.py b/venv/lib/python3.8/site-packages/telegram/ext/dictpersistence.py new file mode 100644 index 0000000..044fc65 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/ext/dictpersistence.py @@ -0,0 +1,404 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the DictPersistence class.""" + +from typing import DefaultDict, Dict, Optional, Tuple, cast +from collections import defaultdict + +from telegram.utils.helpers import ( + decode_conversations_from_json, + decode_user_chat_data_from_json, + encode_conversations_to_json, +) +from telegram.ext import BasePersistence +from telegram.ext.utils.types import ConversationDict, CDCData + +try: + import ujson as json +except ImportError: + import json # type: ignore[no-redef] + + +class DictPersistence(BasePersistence): + """Using Python's :obj:`dict` and ``json`` for making your bot persistent. + + Note: + This class does *not* implement a :meth:`flush` method, meaning that data managed by + ``DictPersistence`` is in-memory only and will be lost when the bot shuts down. This is, + because ``DictPersistence`` is mainly intended as starting point for custom persistence + classes that need to JSON-serialize the stored data before writing them to file/database. + + Warning: + :class:`DictPersistence` will try to replace :class:`telegram.Bot` instances by + :attr:`REPLACED_BOT` and insert the bot set with + :meth:`telegram.ext.BasePersistence.set_bot` upon loading of the data. This is to ensure + that changes to the bot apply to the saved objects, too. If you change the bots token, this + may lead to e.g. ``Chat not found`` errors. For the limitations on replacing bots see + :meth:`telegram.ext.BasePersistence.replace_bot` and + :meth:`telegram.ext.BasePersistence.insert_bot`. + + Args: + store_user_data (:obj:`bool`, optional): Whether user_data should be saved by this + persistence class. Default is :obj:`True`. + store_chat_data (:obj:`bool`, optional): Whether chat_data should be saved by this + persistence class. Default is :obj:`True`. + store_bot_data (:obj:`bool`, optional): Whether bot_data should be saved by this + persistence class. Default is :obj:`True`. + store_callback_data (:obj:`bool`, optional): Whether callback_data should be saved by this + persistence class. Default is :obj:`False`. + + .. versionadded:: 13.6 + user_data_json (:obj:`str`, optional): JSON string that will be used to reconstruct + user_data on creating this persistence. Default is ``""``. + chat_data_json (:obj:`str`, optional): JSON string that will be used to reconstruct + chat_data on creating this persistence. Default is ``""``. + bot_data_json (:obj:`str`, optional): JSON string that will be used to reconstruct + bot_data on creating this persistence. Default is ``""``. + callback_data_json (:obj:`str`, optional): Json string that will be used to reconstruct + callback_data on creating this persistence. Default is ``""``. + + .. versionadded:: 13.6 + conversations_json (:obj:`str`, optional): JSON string that will be used to reconstruct + conversation on creating this persistence. Default is ``""``. + + Attributes: + store_user_data (:obj:`bool`): Whether user_data should be saved by this + persistence class. + store_chat_data (:obj:`bool`): Whether chat_data should be saved by this + persistence class. + store_bot_data (:obj:`bool`): Whether bot_data should be saved by this + persistence class. + store_callback_data (:obj:`bool`): Whether callback_data be saved by this + persistence class. + + .. versionadded:: 13.6 + """ + + __slots__ = ( + '_user_data', + '_chat_data', + '_bot_data', + '_callback_data', + '_conversations', + '_user_data_json', + '_chat_data_json', + '_bot_data_json', + '_callback_data_json', + '_conversations_json', + ) + + def __init__( + self, + store_user_data: bool = True, + store_chat_data: bool = True, + store_bot_data: bool = True, + user_data_json: str = '', + chat_data_json: str = '', + bot_data_json: str = '', + conversations_json: str = '', + store_callback_data: bool = False, + callback_data_json: str = '', + ): + super().__init__( + store_user_data=store_user_data, + store_chat_data=store_chat_data, + store_bot_data=store_bot_data, + store_callback_data=store_callback_data, + ) + self._user_data = None + self._chat_data = None + self._bot_data = None + self._callback_data = None + self._conversations = None + self._user_data_json = None + self._chat_data_json = None + self._bot_data_json = None + self._callback_data_json = None + self._conversations_json = None + if user_data_json: + try: + self._user_data = decode_user_chat_data_from_json(user_data_json) + self._user_data_json = user_data_json + except (ValueError, AttributeError) as exc: + raise TypeError("Unable to deserialize user_data_json. Not valid JSON") from exc + if chat_data_json: + try: + self._chat_data = decode_user_chat_data_from_json(chat_data_json) + self._chat_data_json = chat_data_json + except (ValueError, AttributeError) as exc: + raise TypeError("Unable to deserialize chat_data_json. Not valid JSON") from exc + if bot_data_json: + try: + self._bot_data = json.loads(bot_data_json) + self._bot_data_json = bot_data_json + except (ValueError, AttributeError) as exc: + raise TypeError("Unable to deserialize bot_data_json. Not valid JSON") from exc + if not isinstance(self._bot_data, dict): + raise TypeError("bot_data_json must be serialized dict") + if callback_data_json: + try: + data = json.loads(callback_data_json) + except (ValueError, AttributeError) as exc: + raise TypeError( + "Unable to deserialize callback_data_json. Not valid JSON" + ) from exc + # We are a bit more thorough with the checking of the format here, because it's + # more complicated than for the other things + try: + if data is None: + self._callback_data = None + else: + self._callback_data = cast( + CDCData, + ([(one, float(two), three) for one, two, three in data[0]], data[1]), + ) + self._callback_data_json = callback_data_json + except (ValueError, IndexError) as exc: + raise TypeError("callback_data_json is not in the required format") from exc + if self._callback_data is not None and ( + not all( + isinstance(entry[2], dict) and isinstance(entry[0], str) + for entry in self._callback_data[0] + ) + or not isinstance(self._callback_data[1], dict) + ): + raise TypeError("callback_data_json is not in the required format") + + if conversations_json: + try: + self._conversations = decode_conversations_from_json(conversations_json) + self._conversations_json = conversations_json + except (ValueError, AttributeError) as exc: + raise TypeError( + "Unable to deserialize conversations_json. Not valid JSON" + ) from exc + + @property + def user_data(self) -> Optional[DefaultDict[int, Dict]]: + """:obj:`dict`: The user_data as a dict.""" + return self._user_data + + @property + def user_data_json(self) -> str: + """:obj:`str`: The user_data serialized as a JSON-string.""" + if self._user_data_json: + return self._user_data_json + return json.dumps(self.user_data) + + @property + def chat_data(self) -> Optional[DefaultDict[int, Dict]]: + """:obj:`dict`: The chat_data as a dict.""" + return self._chat_data + + @property + def chat_data_json(self) -> str: + """:obj:`str`: The chat_data serialized as a JSON-string.""" + if self._chat_data_json: + return self._chat_data_json + return json.dumps(self.chat_data) + + @property + def bot_data(self) -> Optional[Dict]: + """:obj:`dict`: The bot_data as a dict.""" + return self._bot_data + + @property + def bot_data_json(self) -> str: + """:obj:`str`: The bot_data serialized as a JSON-string.""" + if self._bot_data_json: + return self._bot_data_json + return json.dumps(self.bot_data) + + @property + def callback_data(self) -> Optional[CDCData]: + """:class:`telegram.ext.utils.types.CDCData`: The meta data on the stored callback data. + + .. versionadded:: 13.6 + """ + return self._callback_data + + @property + def callback_data_json(self) -> str: + """:obj:`str`: The meta data on the stored callback data as a JSON-string. + + .. versionadded:: 13.6 + """ + if self._callback_data_json: + return self._callback_data_json + return json.dumps(self.callback_data) + + @property + def conversations(self) -> Optional[Dict[str, ConversationDict]]: + """:obj:`dict`: The conversations as a dict.""" + return self._conversations + + @property + def conversations_json(self) -> str: + """:obj:`str`: The conversations serialized as a JSON-string.""" + if self._conversations_json: + return self._conversations_json + return encode_conversations_to_json(self.conversations) # type: ignore[arg-type] + + def get_user_data(self) -> DefaultDict[int, Dict[object, object]]: + """Returns the user_data created from the ``user_data_json`` or an empty + :obj:`defaultdict`. + + Returns: + :obj:`defaultdict`: The restored user data. + """ + if self.user_data is None: + self._user_data = defaultdict(dict) + return self.user_data # type: ignore[return-value] + + def get_chat_data(self) -> DefaultDict[int, Dict[object, object]]: + """Returns the chat_data created from the ``chat_data_json`` or an empty + :obj:`defaultdict`. + + Returns: + :obj:`defaultdict`: The restored chat data. + """ + if self.chat_data is None: + self._chat_data = defaultdict(dict) + return self.chat_data # type: ignore[return-value] + + def get_bot_data(self) -> Dict[object, object]: + """Returns the bot_data created from the ``bot_data_json`` or an empty :obj:`dict`. + + Returns: + :obj:`dict`: The restored bot data. + """ + if self.bot_data is None: + self._bot_data = {} + return self.bot_data # type: ignore[return-value] + + def get_callback_data(self) -> Optional[CDCData]: + """Returns the callback_data created from the ``callback_data_json`` or :obj:`None`. + + .. versionadded:: 13.6 + + Returns: + Optional[:class:`telegram.ext.utils.types.CDCData`]: The restored meta data or + :obj:`None`, if no data was stored. + """ + if self.callback_data is None: + self._callback_data = None + return None + return self.callback_data[0], self.callback_data[1].copy() + + def get_conversations(self, name: str) -> ConversationDict: + """Returns the conversations created from the ``conversations_json`` or an empty + :obj:`dict`. + + Returns: + :obj:`dict`: The restored conversations data. + """ + if self.conversations is None: + self._conversations = {} + return self.conversations.get(name, {}).copy() # type: ignore[union-attr] + + def update_conversation( + self, name: str, key: Tuple[int, ...], new_state: Optional[object] + ) -> None: + """Will update the conversations for the given handler. + + Args: + name (:obj:`str`): The handler's name. + key (:obj:`tuple`): The key the state is changed for. + new_state (:obj:`tuple` | :obj:`any`): The new state for the given key. + """ + if not self._conversations: + self._conversations = {} + if self._conversations.setdefault(name, {}).get(key) == new_state: + return + self._conversations[name][key] = new_state + self._conversations_json = None + + def update_user_data(self, user_id: int, data: Dict) -> None: + """Will update the user_data (if changed). + + Args: + user_id (:obj:`int`): The user the data might have been changed for. + data (:obj:`dict`): The :attr:`telegram.ext.dispatcher.user_data` ``[user_id]``. + """ + if self._user_data is None: + self._user_data = defaultdict(dict) + if self._user_data.get(user_id) == data: + return + self._user_data[user_id] = data + self._user_data_json = None + + def update_chat_data(self, chat_id: int, data: Dict) -> None: + """Will update the chat_data (if changed). + + Args: + chat_id (:obj:`int`): The chat the data might have been changed for. + data (:obj:`dict`): The :attr:`telegram.ext.dispatcher.chat_data` ``[chat_id]``. + """ + if self._chat_data is None: + self._chat_data = defaultdict(dict) + if self._chat_data.get(chat_id) == data: + return + self._chat_data[chat_id] = data + self._chat_data_json = None + + def update_bot_data(self, data: Dict) -> None: + """Will update the bot_data (if changed). + + Args: + data (:obj:`dict`): The :attr:`telegram.ext.dispatcher.bot_data`. + """ + if self._bot_data == data: + return + self._bot_data = data + self._bot_data_json = None + + def update_callback_data(self, data: CDCData) -> None: + """Will update the callback_data (if changed). + + .. versionadded:: 13.6 + + Args: + data (:class:`telegram.ext.utils.types.CDCData`:): The relevant data to restore + :attr:`telegram.ext.dispatcher.bot.callback_data_cache`. + """ + if self._callback_data == data: + return + self._callback_data = (data[0], data[1].copy()) + self._callback_data_json = None + + def refresh_user_data(self, user_id: int, user_data: Dict) -> None: + """Does nothing. + + .. versionadded:: 13.6 + .. seealso:: :meth:`telegram.ext.BasePersistence.refresh_user_data` + """ + + def refresh_chat_data(self, chat_id: int, chat_data: Dict) -> None: + """Does nothing. + + .. versionadded:: 13.6 + .. seealso:: :meth:`telegram.ext.BasePersistence.refresh_chat_data` + """ + + def refresh_bot_data(self, bot_data: Dict) -> None: + """Does nothing. + + .. versionadded:: 13.6 + .. seealso:: :meth:`telegram.ext.BasePersistence.refresh_bot_data` + """ diff --git a/venv/lib/python3.8/site-packages/telegram/ext/dispatcher.py b/venv/lib/python3.8/site-packages/telegram/ext/dispatcher.py new file mode 100644 index 0000000..3322acf --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/ext/dispatcher.py @@ -0,0 +1,820 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the Dispatcher class.""" + +import logging +import warnings +import weakref +from collections import defaultdict +from functools import wraps +from queue import Empty, Queue +from threading import BoundedSemaphore, Event, Lock, Thread, current_thread +from time import sleep +from typing import ( + TYPE_CHECKING, + Callable, + DefaultDict, + Dict, + List, + Optional, + Set, + Union, + Generic, + TypeVar, + overload, + cast, +) +from uuid import uuid4 + +from telegram import TelegramError, Update +from telegram.ext import BasePersistence, ContextTypes +from telegram.ext.callbackcontext import CallbackContext +from telegram.ext.handler import Handler +import telegram.ext.extbot +from telegram.ext.callbackdatacache import CallbackDataCache +from telegram.utils.deprecate import TelegramDeprecationWarning, set_new_attribute_deprecated +from telegram.ext.utils.promise import Promise +from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE +from telegram.ext.utils.types import CCT, UD, CD, BD + +if TYPE_CHECKING: + from telegram import Bot + from telegram.ext import JobQueue + +DEFAULT_GROUP: int = 0 + +UT = TypeVar('UT') + + +def run_async( + func: Callable[[Update, CallbackContext], object] +) -> Callable[[Update, CallbackContext], object]: + """ + Function decorator that will run the function in a new thread. + + Will run :attr:`telegram.ext.Dispatcher.run_async`. + + Using this decorator is only possible when only a single Dispatcher exist in the system. + + Note: + DEPRECATED. Use :attr:`telegram.ext.Dispatcher.run_async` directly instead or the + :attr:`Handler.run_async` parameter. + + Warning: + If you're using ``@run_async`` you cannot rely on adding custom attributes to + :class:`telegram.ext.CallbackContext`. See its docs for more info. + """ + + @wraps(func) + def async_func(*args: object, **kwargs: object) -> object: + warnings.warn( + 'The @run_async decorator is deprecated. Use the `run_async` parameter of ' + 'your Handler or `Dispatcher.run_async` instead.', + TelegramDeprecationWarning, + stacklevel=2, + ) + return Dispatcher.get_instance()._run_async( # pylint: disable=W0212 + func, *args, update=None, error_handling=False, **kwargs + ) + + return async_func + + +class DispatcherHandlerStop(Exception): + """ + Raise this in handler to prevent execution of any other handler (even in different group). + + In order to use this exception in a :class:`telegram.ext.ConversationHandler`, pass the + optional ``state`` parameter instead of returning the next state: + + .. code-block:: python + + def callback(update, context): + ... + raise DispatcherHandlerStop(next_state) + + Attributes: + state (:obj:`object`): Optional. The next state of the conversation. + + Args: + state (:obj:`object`, optional): The next state of the conversation. + """ + + __slots__ = ('state',) + + def __init__(self, state: object = None) -> None: + super().__init__() + self.state = state + + +class Dispatcher(Generic[CCT, UD, CD, BD]): + """This class dispatches all kinds of updates to its registered handlers. + + Args: + bot (:class:`telegram.Bot`): The bot object that should be passed to the handlers. + update_queue (:obj:`Queue`): The synchronized queue that will contain the updates. + job_queue (:class:`telegram.ext.JobQueue`, optional): The :class:`telegram.ext.JobQueue` + instance to pass onto handler callbacks. + workers (:obj:`int`, optional): Number of maximum concurrent worker threads for the + ``@run_async`` decorator and :meth:`run_async`. Defaults to 4. + persistence (:class:`telegram.ext.BasePersistence`, optional): The persistence class to + store data that should be persistent over restarts. + use_context (:obj:`bool`, optional): If set to :obj:`True` uses the context based callback + API (ignored if `dispatcher` argument is used). Defaults to :obj:`True`. + **New users**: set this to :obj:`True`. + context_types (:class:`telegram.ext.ContextTypes`, optional): Pass an instance + of :class:`telegram.ext.ContextTypes` to customize the types used in the + ``context`` interface. If not passed, the defaults documented in + :class:`telegram.ext.ContextTypes` will be used. + + .. versionadded:: 13.6 + + Attributes: + bot (:class:`telegram.Bot`): The bot object that should be passed to the handlers. + update_queue (:obj:`Queue`): The synchronized queue that will contain the updates. + job_queue (:class:`telegram.ext.JobQueue`): Optional. The :class:`telegram.ext.JobQueue` + instance to pass onto handler callbacks. + workers (:obj:`int`, optional): Number of maximum concurrent worker threads for the + ``@run_async`` decorator and :meth:`run_async`. + user_data (:obj:`defaultdict`): A dictionary handlers can use to store data for the user. + chat_data (:obj:`defaultdict`): A dictionary handlers can use to store data for the chat. + bot_data (:obj:`dict`): A dictionary handlers can use to store data for the bot. + persistence (:class:`telegram.ext.BasePersistence`): Optional. The persistence class to + store data that should be persistent over restarts. + context_types (:class:`telegram.ext.ContextTypes`): Container for the types used + in the ``context`` interface. + + .. versionadded:: 13.6 + + """ + + # Allowing '__weakref__' creation here since we need it for the singleton + __slots__ = ( + 'workers', + 'persistence', + 'use_context', + 'update_queue', + 'job_queue', + 'user_data', + 'chat_data', + 'bot_data', + '_update_persistence_lock', + 'handlers', + 'groups', + 'error_handlers', + 'running', + '__stop_event', + '__exception_event', + '__async_queue', + '__async_threads', + 'bot', + '__dict__', + '__weakref__', + 'context_types', + ) + + __singleton_lock = Lock() + __singleton_semaphore = BoundedSemaphore() + __singleton = None + logger = logging.getLogger(__name__) + + @overload + def __init__( + self: 'Dispatcher[CallbackContext[Dict, Dict, Dict], Dict, Dict, Dict]', + bot: 'Bot', + update_queue: Queue, + workers: int = 4, + exception_event: Event = None, + job_queue: 'JobQueue' = None, + persistence: BasePersistence = None, + use_context: bool = True, + ): + ... + + @overload + def __init__( + self: 'Dispatcher[CCT, UD, CD, BD]', + bot: 'Bot', + update_queue: Queue, + workers: int = 4, + exception_event: Event = None, + job_queue: 'JobQueue' = None, + persistence: BasePersistence = None, + use_context: bool = True, + context_types: ContextTypes[CCT, UD, CD, BD] = None, + ): + ... + + def __init__( + self, + bot: 'Bot', + update_queue: Queue, + workers: int = 4, + exception_event: Event = None, + job_queue: 'JobQueue' = None, + persistence: BasePersistence = None, + use_context: bool = True, + context_types: ContextTypes[CCT, UD, CD, BD] = None, + ): + self.bot = bot + self.update_queue = update_queue + self.job_queue = job_queue + self.workers = workers + self.use_context = use_context + self.context_types = cast(ContextTypes[CCT, UD, CD, BD], context_types or ContextTypes()) + + if not use_context: + warnings.warn( + 'Old Handler API is deprecated - see https://git.io/fxJuV for details', + TelegramDeprecationWarning, + stacklevel=3, + ) + + if self.workers < 1: + warnings.warn( + 'Asynchronous callbacks can not be processed without at least one worker thread.' + ) + + self.user_data: DefaultDict[int, UD] = defaultdict(self.context_types.user_data) + self.chat_data: DefaultDict[int, CD] = defaultdict(self.context_types.chat_data) + self.bot_data = self.context_types.bot_data() + self.persistence: Optional[BasePersistence] = None + self._update_persistence_lock = Lock() + if persistence: + if not isinstance(persistence, BasePersistence): + raise TypeError("persistence must be based on telegram.ext.BasePersistence") + self.persistence = persistence + self.persistence.set_bot(self.bot) + if self.persistence.store_user_data: + self.user_data = self.persistence.get_user_data() + if not isinstance(self.user_data, defaultdict): + raise ValueError("user_data must be of type defaultdict") + if self.persistence.store_chat_data: + self.chat_data = self.persistence.get_chat_data() + if not isinstance(self.chat_data, defaultdict): + raise ValueError("chat_data must be of type defaultdict") + if self.persistence.store_bot_data: + self.bot_data = self.persistence.get_bot_data() + if not isinstance(self.bot_data, self.context_types.bot_data): + raise ValueError( + f"bot_data must be of type {self.context_types.bot_data.__name__}" + ) + if self.persistence.store_callback_data: + self.bot = cast(telegram.ext.extbot.ExtBot, self.bot) + persistent_data = self.persistence.get_callback_data() + if persistent_data is not None: + if not isinstance(persistent_data, tuple) and len(persistent_data) != 2: + raise ValueError('callback_data must be a 2-tuple') + self.bot.callback_data_cache = CallbackDataCache( + self.bot, + self.bot.callback_data_cache.maxsize, + persistent_data=persistent_data, + ) + else: + self.persistence = None + + self.handlers: Dict[int, List[Handler]] = {} + """Dict[:obj:`int`, List[:class:`telegram.ext.Handler`]]: Holds the handlers per group.""" + self.groups: List[int] = [] + """List[:obj:`int`]: A list with all groups.""" + self.error_handlers: Dict[Callable, Union[bool, DefaultValue]] = {} + """Dict[:obj:`callable`, :obj:`bool`]: A dict, where the keys are error handlers and the + values indicate whether they are to be run asynchronously.""" + + self.running = False + """:obj:`bool`: Indicates if this dispatcher is running.""" + self.__stop_event = Event() + self.__exception_event = exception_event or Event() + self.__async_queue: Queue = Queue() + self.__async_threads: Set[Thread] = set() + + # For backward compatibility, we allow a "singleton" mode for the dispatcher. When there's + # only one instance of Dispatcher, it will be possible to use the `run_async` decorator. + with self.__singleton_lock: + if self.__singleton_semaphore.acquire(blocking=False): # pylint: disable=R1732 + self._set_singleton(self) + else: + self._set_singleton(None) + + def __setattr__(self, key: str, value: object) -> None: + # Mangled names don't automatically apply in __setattr__ (see + # https://docs.python.org/3/tutorial/classes.html#private-variables), so we have to make + # it mangled so they don't raise TelegramDeprecationWarning unnecessarily + if key.startswith('__'): + key = f"_{self.__class__.__name__}{key}" + if issubclass(self.__class__, Dispatcher) and self.__class__ is not Dispatcher: + object.__setattr__(self, key, value) + return + set_new_attribute_deprecated(self, key, value) + + @property + def exception_event(self) -> Event: # skipcq: PY-D0003 + return self.__exception_event + + def _init_async_threads(self, base_name: str, workers: int) -> None: + base_name = f'{base_name}_' if base_name else '' + + for i in range(workers): + thread = Thread(target=self._pooled, name=f'Bot:{self.bot.id}:worker:{base_name}{i}') + self.__async_threads.add(thread) + thread.start() + + @classmethod + def _set_singleton(cls, val: Optional['Dispatcher']) -> None: + cls.logger.debug('Setting singleton dispatcher as %s', val) + cls.__singleton = weakref.ref(val) if val else None + + @classmethod + def get_instance(cls) -> 'Dispatcher': + """Get the singleton instance of this class. + + Returns: + :class:`telegram.ext.Dispatcher` + + Raises: + RuntimeError + + """ + if cls.__singleton is not None: + return cls.__singleton() # type: ignore[return-value] # pylint: disable=not-callable + raise RuntimeError(f'{cls.__name__} not initialized or multiple instances exist') + + def _pooled(self) -> None: + thr_name = current_thread().getName() + while 1: + promise = self.__async_queue.get() + + # If unpacking fails, the thread pool is being closed from Updater._join_async_threads + if not isinstance(promise, Promise): + self.logger.debug( + "Closing run_async thread %s/%d", thr_name, len(self.__async_threads) + ) + break + + promise.run() + + if not promise.exception: + self.update_persistence(update=promise.update) + continue + + if isinstance(promise.exception, DispatcherHandlerStop): + self.logger.warning( + 'DispatcherHandlerStop is not supported with async functions; func: %s', + promise.pooled_function.__name__, + ) + continue + + # Avoid infinite recursion of error handlers. + if promise.pooled_function in self.error_handlers: + self.logger.error('An uncaught error was raised while handling the error.') + continue + + # Don't perform error handling for a `Promise` with deactivated error handling. This + # should happen only via the deprecated `@run_async` decorator or `Promises` created + # within error handlers + if not promise.error_handling: + self.logger.error('A promise with deactivated error handling raised an error.') + continue + + # If we arrive here, an exception happened in the promise and was neither + # DispatcherHandlerStop nor raised by an error handler. So we can and must handle it + try: + self.dispatch_error(promise.update, promise.exception, promise=promise) + except Exception: + self.logger.exception('An uncaught error was raised while handling the error.') + + def run_async( + self, func: Callable[..., object], *args: object, update: object = None, **kwargs: object + ) -> Promise: + """ + Queue a function (with given args/kwargs) to be run asynchronously. Exceptions raised + by the function will be handled by the error handlers registered with + :meth:`add_error_handler`. + + Warning: + * If you're using ``@run_async``/:meth:`run_async` you cannot rely on adding custom + attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. + * Calling a function through :meth:`run_async` from within an error handler can lead to + an infinite error handling loop. + + Args: + func (:obj:`callable`): The function to run in the thread. + *args (:obj:`tuple`, optional): Arguments to ``func``. + update (:class:`telegram.Update` | :obj:`object`, optional): The update associated with + the functions call. If passed, it will be available in the error handlers, in case + an exception is raised by :attr:`func`. + **kwargs (:obj:`dict`, optional): Keyword arguments to ``func``. + + Returns: + Promise + + """ + return self._run_async(func, *args, update=update, error_handling=True, **kwargs) + + def _run_async( + self, + func: Callable[..., object], + *args: object, + update: object = None, + error_handling: bool = True, + **kwargs: object, + ) -> Promise: + # TODO: Remove error_handling parameter once we drop the @run_async decorator + promise = Promise(func, args, kwargs, update=update, error_handling=error_handling) + self.__async_queue.put(promise) + return promise + + def start(self, ready: Event = None) -> None: + """Thread target of thread 'dispatcher'. + + Runs in background and processes the update queue. + + Args: + ready (:obj:`threading.Event`, optional): If specified, the event will be set once the + dispatcher is ready. + + """ + if self.running: + self.logger.warning('already running') + if ready is not None: + ready.set() + return + + if self.__exception_event.is_set(): + msg = 'reusing dispatcher after exception event is forbidden' + self.logger.error(msg) + raise TelegramError(msg) + + self._init_async_threads(str(uuid4()), self.workers) + self.running = True + self.logger.debug('Dispatcher started') + + if ready is not None: + ready.set() + + while 1: + try: + # Pop update from update queue. + update = self.update_queue.get(True, 1) + except Empty: + if self.__stop_event.is_set(): + self.logger.debug('orderly stopping') + break + if self.__exception_event.is_set(): + self.logger.critical('stopping due to exception in another thread') + break + continue + + self.logger.debug('Processing Update: %s', update) + self.process_update(update) + self.update_queue.task_done() + + self.running = False + self.logger.debug('Dispatcher thread stopped') + + def stop(self) -> None: + """Stops the thread.""" + if self.running: + self.__stop_event.set() + while self.running: + sleep(0.1) + self.__stop_event.clear() + + # async threads must be join()ed only after the dispatcher thread was joined, + # otherwise we can still have new async threads dispatched + threads = list(self.__async_threads) + total = len(threads) + + # Stop all threads in the thread pool by put()ting one non-tuple per thread + for i in range(total): + self.__async_queue.put(None) + + for i, thr in enumerate(threads): + self.logger.debug('Waiting for async thread %s/%s to end', i + 1, total) + thr.join() + self.__async_threads.remove(thr) + self.logger.debug('async thread %s/%s has ended', i + 1, total) + + @property + def has_running_threads(self) -> bool: # skipcq: PY-D0003 + return self.running or bool(self.__async_threads) + + def process_update(self, update: object) -> None: + """Processes a single update and updates the persistence. + + Note: + If the update is handled by least one synchronously running handlers (i.e. + ``run_async=False``), :meth:`update_persistence` is called *once* after all handlers + synchronous handlers are done. Each asynchronously running handler will trigger + :meth:`update_persistence` on its own. + + Args: + update (:class:`telegram.Update` | :obj:`object` | \ + :class:`telegram.error.TelegramError`): + The update to process. + + """ + # An error happened while polling + if isinstance(update, TelegramError): + try: + self.dispatch_error(None, update) + except Exception: + self.logger.exception('An uncaught error was raised while handling the error.') + return + + context = None + handled = False + sync_modes = [] + + for group in self.groups: + try: + for handler in self.handlers[group]: + check = handler.check_update(update) + if check is not None and check is not False: + if not context and self.use_context: + context = self.context_types.context.from_update(update, self) + context.refresh_data() + handled = True + sync_modes.append(handler.run_async) + handler.handle_update(update, self, check, context) + break + + # Stop processing with any other handler. + except DispatcherHandlerStop: + self.logger.debug('Stopping further handlers due to DispatcherHandlerStop') + self.update_persistence(update=update) + break + + # Dispatch any error. + except Exception as exc: + try: + self.dispatch_error(update, exc) + except DispatcherHandlerStop: + self.logger.debug('Error handler stopped further handlers') + break + # Errors should not stop the thread. + except Exception: + self.logger.exception('An uncaught error was raised while handling the error.') + + # Update persistence, if handled + handled_only_async = all(sync_modes) + if handled: + # Respect default settings + if all(mode is DEFAULT_FALSE for mode in sync_modes) and self.bot.defaults: + handled_only_async = self.bot.defaults.run_async + # If update was only handled by async handlers, we don't need to update here + if not handled_only_async: + self.update_persistence(update=update) + + def add_handler(self, handler: Handler[UT, CCT], group: int = DEFAULT_GROUP) -> None: + """Register a handler. + + TL;DR: Order and priority counts. 0 or 1 handlers per group will be used. End handling of + update with :class:`telegram.ext.DispatcherHandlerStop`. + + A handler must be an instance of a subclass of :class:`telegram.ext.Handler`. All handlers + are organized in groups with a numeric value. The default group is 0. All groups will be + evaluated for handling an update, but only 0 or 1 handler per group will be used. If + :class:`telegram.ext.DispatcherHandlerStop` is raised from one of the handlers, no further + handlers (regardless of the group) will be called. + + The priority/order of handlers is determined as follows: + + * Priority of the group (lower group number == higher priority) + * The first handler in a group which should handle an update (see + :attr:`telegram.ext.Handler.check_update`) will be used. Other handlers from the + group will not be used. The order in which handlers were added to the group defines the + priority. + + Args: + handler (:class:`telegram.ext.Handler`): A Handler instance. + group (:obj:`int`, optional): The group identifier. Default is 0. + + """ + # Unfortunately due to circular imports this has to be here + from .conversationhandler import ConversationHandler # pylint: disable=C0415 + + if not isinstance(handler, Handler): + raise TypeError(f'handler is not an instance of {Handler.__name__}') + if not isinstance(group, int): + raise TypeError('group is not int') + # For some reason MyPy infers the type of handler is <nothing> here, + # so for now we just ignore all the errors + if ( + isinstance(handler, ConversationHandler) + and handler.persistent # type: ignore[attr-defined] + and handler.name # type: ignore[attr-defined] + ): + if not self.persistence: + raise ValueError( + f"ConversationHandler {handler.name} " # type: ignore[attr-defined] + f"can not be persistent if dispatcher has no persistence" + ) + handler.persistence = self.persistence # type: ignore[attr-defined] + handler.conversations = ( # type: ignore[attr-defined] + self.persistence.get_conversations(handler.name) # type: ignore[attr-defined] + ) + + if group not in self.handlers: + self.handlers[group] = [] + self.groups.append(group) + self.groups = sorted(self.groups) + + self.handlers[group].append(handler) + + def remove_handler(self, handler: Handler, group: int = DEFAULT_GROUP) -> None: + """Remove a handler from the specified group. + + Args: + handler (:class:`telegram.ext.Handler`): A Handler instance. + group (:obj:`object`, optional): The group identifier. Default is 0. + + """ + if handler in self.handlers[group]: + self.handlers[group].remove(handler) + if not self.handlers[group]: + del self.handlers[group] + self.groups.remove(group) + + def update_persistence(self, update: object = None) -> None: + """Update :attr:`user_data`, :attr:`chat_data` and :attr:`bot_data` in :attr:`persistence`. + + Args: + update (:class:`telegram.Update`, optional): The update to process. If passed, only the + corresponding ``user_data`` and ``chat_data`` will be updated. + """ + with self._update_persistence_lock: + self.__update_persistence(update) + + def __update_persistence(self, update: object = None) -> None: + if self.persistence: + # We use list() here in order to decouple chat_ids from self.chat_data, as dict view + # objects will change, when the dict does and we want to loop over chat_ids + chat_ids = list(self.chat_data.keys()) + user_ids = list(self.user_data.keys()) + + if isinstance(update, Update): + if update.effective_chat: + chat_ids = [update.effective_chat.id] + else: + chat_ids = [] + if update.effective_user: + user_ids = [update.effective_user.id] + else: + user_ids = [] + + if self.persistence.store_callback_data: + self.bot = cast(telegram.ext.extbot.ExtBot, self.bot) + try: + self.persistence.update_callback_data( + self.bot.callback_data_cache.persistence_data + ) + except Exception as exc: + try: + self.dispatch_error(update, exc) + except Exception: + message = ( + 'Saving callback data raised an error and an ' + 'uncaught error was raised while handling ' + 'the error with an error_handler' + ) + self.logger.exception(message) + if self.persistence.store_bot_data: + try: + self.persistence.update_bot_data(self.bot_data) + except Exception as exc: + try: + self.dispatch_error(update, exc) + except Exception: + message = ( + 'Saving bot data raised an error and an ' + 'uncaught error was raised while handling ' + 'the error with an error_handler' + ) + self.logger.exception(message) + if self.persistence.store_chat_data: + for chat_id in chat_ids: + try: + self.persistence.update_chat_data(chat_id, self.chat_data[chat_id]) + except Exception as exc: + try: + self.dispatch_error(update, exc) + except Exception: + message = ( + 'Saving chat data raised an error and an ' + 'uncaught error was raised while handling ' + 'the error with an error_handler' + ) + self.logger.exception(message) + if self.persistence.store_user_data: + for user_id in user_ids: + try: + self.persistence.update_user_data(user_id, self.user_data[user_id]) + except Exception as exc: + try: + self.dispatch_error(update, exc) + except Exception: + message = ( + 'Saving user data raised an error and an ' + 'uncaught error was raised while handling ' + 'the error with an error_handler' + ) + self.logger.exception(message) + + def add_error_handler( + self, + callback: Callable[[object, CCT], None], + run_async: Union[bool, DefaultValue] = DEFAULT_FALSE, # pylint: disable=W0621 + ) -> None: + """Registers an error handler in the Dispatcher. This handler will receive every error + which happens in your bot. + + Note: + Attempts to add the same callback multiple times will be ignored. + + Warning: + The errors handled within these handlers won't show up in the logger, so you + need to make sure that you reraise the error. + + Args: + callback (:obj:`callable`): The callback function for this error handler. Will be + called when an error is raised. Callback signature for context based API: + + ``def callback(update: object, context: CallbackContext)`` + + The error that happened will be present in context.error. + run_async (:obj:`bool`, optional): Whether this handlers callback should be run + asynchronously using :meth:`run_async`. Defaults to :obj:`False`. + + Note: + See https://git.io/fxJuV for more info about switching to context based API. + """ + if callback in self.error_handlers: + self.logger.debug('The callback is already registered as an error handler. Ignoring.') + return + + if run_async is DEFAULT_FALSE and self.bot.defaults and self.bot.defaults.run_async: + run_async = True + + self.error_handlers[callback] = run_async + + def remove_error_handler(self, callback: Callable[[object, CCT], None]) -> None: + """Removes an error handler. + + Args: + callback (:obj:`callable`): The error handler to remove. + + """ + self.error_handlers.pop(callback, None) + + def dispatch_error( + self, update: Optional[object], error: Exception, promise: Promise = None + ) -> None: + """Dispatches an error. + + Args: + update (:obj:`object` | :class:`telegram.Update`): The update that caused the error. + error (:obj:`Exception`): The error that was raised. + promise (:class:`telegram.utils.Promise`, optional): The promise whose pooled function + raised the error. + + """ + async_args = None if not promise else promise.args + async_kwargs = None if not promise else promise.kwargs + + if self.error_handlers: + for callback, run_async in self.error_handlers.items(): # pylint: disable=W0621 + if self.use_context: + context = self.context_types.context.from_error( + update, error, self, async_args=async_args, async_kwargs=async_kwargs + ) + if run_async: + self.run_async(callback, update, context, update=update) + else: + callback(update, context) + else: + if run_async: + self.run_async(callback, self.bot, update, error, update=update) + else: + callback(self.bot, update, error) + + else: + self.logger.exception( + 'No error handlers are registered, logging exception.', exc_info=error + ) diff --git a/venv/lib/python3.8/site-packages/telegram/ext/extbot.py b/venv/lib/python3.8/site-packages/telegram/ext/extbot.py new file mode 100644 index 0000000..a718bce --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/ext/extbot.py @@ -0,0 +1,326 @@ +#!/usr/bin/env python +# pylint: disable=E0611,E0213,E1102,C0103,E1101,R0913,R0904 +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram Bot with convenience extensions.""" +from copy import copy +from typing import Union, cast, List, Callable, Optional, Tuple, TypeVar, TYPE_CHECKING, Sequence + +import telegram.bot +from telegram import ( + ReplyMarkup, + Message, + InlineKeyboardMarkup, + Poll, + MessageId, + Update, + Chat, + CallbackQuery, +) + +from telegram.ext.callbackdatacache import CallbackDataCache +from telegram.utils.types import JSONDict, ODVInput, DVInput +from ..utils.helpers import DEFAULT_NONE + +if TYPE_CHECKING: + from telegram import InlineQueryResult, MessageEntity + from telegram.utils.request import Request + from .defaults import Defaults + +HandledTypes = TypeVar('HandledTypes', bound=Union[Message, CallbackQuery, Chat]) + + +class ExtBot(telegram.bot.Bot): + """This object represents a Telegram Bot with convenience extensions. + + Warning: + Not to be confused with :class:`telegram.Bot`. + + For the documentation of the arguments, methods and attributes, please see + :class:`telegram.Bot`. + + .. versionadded:: 13.6 + + Args: + defaults (:class:`telegram.ext.Defaults`, optional): An object containing default values to + be used if not set explicitly in the bot methods. + arbitrary_callback_data (:obj:`bool` | :obj:`int`, optional): Whether to + allow arbitrary objects as callback data for :class:`telegram.InlineKeyboardButton`. + Pass an integer to specify the maximum number of objects cached in memory. For more + details, please see our `wiki <https://git.io/JGBDI>`_. Defaults to :obj:`False`. + + Attributes: + arbitrary_callback_data (:obj:`bool` | :obj:`int`): Whether this bot instance + allows to use arbitrary objects as callback data for + :class:`telegram.InlineKeyboardButton`. + callback_data_cache (:class:`telegram.ext.CallbackDataCache`): The cache for objects passed + as callback data for :class:`telegram.InlineKeyboardButton`. + + """ + + __slots__ = ('arbitrary_callback_data', 'callback_data_cache') + + # The ext_bot argument is a little hack to get warnings handled correctly. + # It's not very clean, but the warnings will be dropped at some point anyway. + def __setattr__(self, key: str, value: object, ext_bot: bool = True) -> None: + if issubclass(self.__class__, ExtBot) and self.__class__ is not ExtBot: + object.__setattr__(self, key, value) + return + super().__setattr__(key, value, ext_bot=ext_bot) # type: ignore[call-arg] + + def __init__( + self, + token: str, + base_url: str = None, + base_file_url: str = None, + request: 'Request' = None, + private_key: bytes = None, + private_key_password: bytes = None, + defaults: 'Defaults' = None, + arbitrary_callback_data: Union[bool, int] = False, + ): + super().__init__( + token=token, + base_url=base_url, + base_file_url=base_file_url, + request=request, + private_key=private_key, + private_key_password=private_key_password, + defaults=defaults, + ) + + # set up callback_data + if not isinstance(arbitrary_callback_data, bool): + maxsize = cast(int, arbitrary_callback_data) + self.arbitrary_callback_data = True + else: + maxsize = 1024 + self.arbitrary_callback_data = arbitrary_callback_data + self.callback_data_cache: CallbackDataCache = CallbackDataCache(bot=self, maxsize=maxsize) + + def _replace_keyboard(self, reply_markup: Optional[ReplyMarkup]) -> Optional[ReplyMarkup]: + # If the reply_markup is an inline keyboard and we allow arbitrary callback data, let the + # CallbackDataCache build a new keyboard with the data replaced. Otherwise return the input + if isinstance(reply_markup, InlineKeyboardMarkup) and self.arbitrary_callback_data: + return self.callback_data_cache.process_keyboard(reply_markup) + + return reply_markup + + def insert_callback_data(self, update: Update) -> None: + """If this bot allows for arbitrary callback data, this inserts the cached data into all + corresponding buttons within this update. + + Note: + Checks :attr:`telegram.Message.via_bot` and :attr:`telegram.Message.from_user` to check + if the reply markup (if any) was actually sent by this caches bot. If it was not, the + message will be returned unchanged. + + Note that this will fail for channel posts, as :attr:`telegram.Message.from_user` is + :obj:`None` for those! In the corresponding reply markups the callback data will be + replaced by :class:`telegram.ext.InvalidCallbackData`. + + Warning: + *In place*, i.e. the passed :class:`telegram.Message` will be changed! + + Args: + update (:class`telegram.Update`): The update. + + """ + # The only incoming updates that can directly contain a message sent by the bot itself are: + # * CallbackQueries + # * Messages where the pinned_message is sent by the bot + # * Messages where the reply_to_message is sent by the bot + # * Messages where via_bot is the bot + # Finally there is effective_chat.pinned message, but that's only returned in get_chat + if update.callback_query: + self._insert_callback_data(update.callback_query) + # elif instead of if, as effective_message includes callback_query.message + # and that has already been processed + elif update.effective_message: + self._insert_callback_data(update.effective_message) + + def _insert_callback_data(self, obj: HandledTypes) -> HandledTypes: + if not self.arbitrary_callback_data: + return obj + + if isinstance(obj, CallbackQuery): + self.callback_data_cache.process_callback_query(obj) + return obj # type: ignore[return-value] + + if isinstance(obj, Message): + if obj.reply_to_message: + # reply_to_message can't contain further reply_to_messages, so no need to check + self.callback_data_cache.process_message(obj.reply_to_message) + if obj.reply_to_message.pinned_message: + # pinned messages can't contain reply_to_message, no need to check + self.callback_data_cache.process_message(obj.reply_to_message.pinned_message) + if obj.pinned_message: + # pinned messages can't contain reply_to_message, no need to check + self.callback_data_cache.process_message(obj.pinned_message) + + # Finally, handle the message itself + self.callback_data_cache.process_message(message=obj) + return obj # type: ignore[return-value] + + if isinstance(obj, Chat) and obj.pinned_message: + self.callback_data_cache.process_message(obj.pinned_message) + + return obj + + def _message( + self, + endpoint: str, + data: JSONDict, + reply_to_message_id: int = None, + disable_notification: ODVInput[bool] = DEFAULT_NONE, + reply_markup: ReplyMarkup = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> Union[bool, Message]: + # We override this method to call self._replace_keyboard and self._insert_callback_data. + # This covers most methods that have a reply_markup + result = super()._message( + endpoint=endpoint, + data=data, + reply_to_message_id=reply_to_message_id, + disable_notification=disable_notification, + reply_markup=self._replace_keyboard(reply_markup), + allow_sending_without_reply=allow_sending_without_reply, + timeout=timeout, + api_kwargs=api_kwargs, + ) + if isinstance(result, Message): + self._insert_callback_data(result) + return result + + def get_updates( + self, + offset: int = None, + limit: int = 100, + timeout: float = 0, + read_latency: float = 2.0, + allowed_updates: List[str] = None, + api_kwargs: JSONDict = None, + ) -> List[Update]: + updates = super().get_updates( + offset=offset, + limit=limit, + timeout=timeout, + read_latency=read_latency, + allowed_updates=allowed_updates, + api_kwargs=api_kwargs, + ) + + for update in updates: + self.insert_callback_data(update) + + return updates + + def _effective_inline_results( # pylint: disable=R0201 + self, + results: Union[ + Sequence['InlineQueryResult'], Callable[[int], Optional[Sequence['InlineQueryResult']]] + ], + next_offset: str = None, + current_offset: str = None, + ) -> Tuple[Sequence['InlineQueryResult'], Optional[str]]: + """ + This method is called by Bot.answer_inline_query to build the actual results list. + Overriding this to call self._replace_keyboard suffices + """ + effective_results, next_offset = super()._effective_inline_results( + results=results, next_offset=next_offset, current_offset=current_offset + ) + + # Process arbitrary callback + if not self.arbitrary_callback_data: + return effective_results, next_offset + results = [] + for result in effective_results: + # All currently existingInlineQueryResults have a reply_markup, but future ones + # might not have. Better be save than sorry + if not hasattr(result, 'reply_markup'): + results.append(result) + else: + # We build a new result in case the user wants to use the same object in + # different places + new_result = copy(result) + markup = self._replace_keyboard(result.reply_markup) # type: ignore[attr-defined] + new_result.reply_markup = markup + results.append(new_result) + + return results, next_offset + + def stop_poll( + self, + chat_id: Union[int, str], + message_id: int, + reply_markup: InlineKeyboardMarkup = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> Poll: + # We override this method to call self._replace_keyboard + return super().stop_poll( + chat_id=chat_id, + message_id=message_id, + reply_markup=self._replace_keyboard(reply_markup), + timeout=timeout, + api_kwargs=api_kwargs, + ) + + def copy_message( + self, + chat_id: Union[int, str], + from_chat_id: Union[str, int], + message_id: int, + caption: str = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + caption_entities: Union[Tuple['MessageEntity', ...], List['MessageEntity']] = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE, + reply_markup: ReplyMarkup = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> MessageId: + # We override this method to call self._replace_keyboard + return super().copy_message( + chat_id=chat_id, + from_chat_id=from_chat_id, + message_id=message_id, + caption=caption, + parse_mode=parse_mode, + caption_entities=caption_entities, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + allow_sending_without_reply=allow_sending_without_reply, + reply_markup=self._replace_keyboard(reply_markup), + timeout=timeout, + api_kwargs=api_kwargs, + ) + + def get_chat( + self, + chat_id: Union[str, int], + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> Chat: + # We override this method to call self._insert_callback_data + result = super().get_chat(chat_id=chat_id, timeout=timeout, api_kwargs=api_kwargs) + return self._insert_callback_data(result) diff --git a/venv/lib/python3.8/site-packages/telegram/ext/filters.py b/venv/lib/python3.8/site-packages/telegram/ext/filters.py new file mode 100644 index 0000000..72a4b30 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/ext/filters.py @@ -0,0 +1,2313 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +# pylint: disable=C0112, C0103, W0221 +"""This module contains the Filters for use with the MessageHandler class.""" + +import re +import warnings + +from abc import ABC, abstractmethod +from sys import version_info as py_ver +from threading import Lock +from typing import ( + Dict, + FrozenSet, + List, + Match, + Optional, + Pattern, + Set, + Tuple, + Union, + cast, + NoReturn, +) + +from telegram import Chat, Message, MessageEntity, Update, User + +__all__ = [ + 'Filters', + 'BaseFilter', + 'MessageFilter', + 'UpdateFilter', + 'InvertedFilter', + 'MergedFilter', + 'XORFilter', +] + +from telegram.utils.deprecate import TelegramDeprecationWarning, set_new_attribute_deprecated +from telegram.utils.types import SLT + +DataDict = Dict[str, list] + + +class BaseFilter(ABC): + """Base class for all Filters. + + Filters subclassing from this class can combined using bitwise operators: + + And: + + >>> (Filters.text & Filters.entity(MENTION)) + + Or: + + >>> (Filters.audio | Filters.video) + + Exclusive Or: + + >>> (Filters.regex('To Be') ^ Filters.regex('Not 2B')) + + Not: + + >>> ~ Filters.command + + Also works with more than two filters: + + >>> (Filters.text & (Filters.entity(URL) | Filters.entity(TEXT_LINK))) + >>> Filters.text & (~ Filters.forwarded) + + Note: + Filters use the same short circuiting logic as python's `and`, `or` and `not`. + This means that for example: + + >>> Filters.regex(r'(a?x)') | Filters.regex(r'(b?x)') + + With ``message.text == x``, will only ever return the matches for the first filter, + since the second one is never evaluated. + + + If you want to create your own filters create a class inheriting from either + :class:`MessageFilter` or :class:`UpdateFilter` and implement a :meth:`filter` method that + returns a boolean: :obj:`True` if the message should be + handled, :obj:`False` otherwise. + Note that the filters work only as class instances, not + actual class objects (so remember to + initialize your filter classes). + + By default the filters name (what will get printed when converted to a string for display) + will be the class name. If you want to overwrite this assign a better name to the :attr:`name` + class variable. + + Attributes: + name (:obj:`str`): Name for this filter. Defaults to the type of filter. + data_filter (:obj:`bool`): Whether this filter is a data filter. A data filter should + return a dict with lists. The dict will be merged with + :class:`telegram.ext.CallbackContext`'s internal dict in most cases + (depends on the handler). + """ + + if py_ver < (3, 7): + __slots__ = ('_name', '_data_filter') + else: + __slots__ = ('_name', '_data_filter', '__dict__') # type: ignore[assignment] + + def __new__(cls, *args: object, **kwargs: object) -> 'BaseFilter': # pylint: disable=W0613 + instance = super().__new__(cls) + instance._name = None + instance._data_filter = False + + return instance + + @abstractmethod + def __call__(self, update: Update) -> Optional[Union[bool, DataDict]]: + ... + + def __and__(self, other: 'BaseFilter') -> 'BaseFilter': + return MergedFilter(self, and_filter=other) + + def __or__(self, other: 'BaseFilter') -> 'BaseFilter': + return MergedFilter(self, or_filter=other) + + def __xor__(self, other: 'BaseFilter') -> 'BaseFilter': + return XORFilter(self, other) + + def __invert__(self) -> 'BaseFilter': + return InvertedFilter(self) + + def __setattr__(self, key: str, value: object) -> None: + # Allow setting custom attributes w/o warning for user defined custom filters. + # To differentiate between a custom and a PTB filter, we use this hacky but + # simple way of checking the module name where the class is defined from. + if ( + issubclass(self.__class__, (UpdateFilter, MessageFilter)) + and self.__class__.__module__ != __name__ + ): # __name__ is telegram.ext.filters + object.__setattr__(self, key, value) + return + set_new_attribute_deprecated(self, key, value) + + @property + def data_filter(self) -> bool: + return self._data_filter + + @data_filter.setter + def data_filter(self, value: bool) -> None: + self._data_filter = value + + @property + def name(self) -> Optional[str]: + return self._name + + @name.setter + def name(self, name: Optional[str]) -> None: + self._name = name # pylint: disable=E0237 + + def __repr__(self) -> str: + # We do this here instead of in a __init__ so filter don't have to call __init__ or super() + if self.name is None: + self.name = self.__class__.__name__ + return self.name + + +class MessageFilter(BaseFilter): + """Base class for all Message Filters. In contrast to :class:`UpdateFilter`, the object passed + to :meth:`filter` is ``update.effective_message``. + + Please see :class:`telegram.ext.filters.BaseFilter` for details on how to create custom + filters. + + Attributes: + name (:obj:`str`): Name for this filter. Defaults to the type of filter. + data_filter (:obj:`bool`): Whether this filter is a data filter. A data filter should + return a dict with lists. The dict will be merged with + :class:`telegram.ext.CallbackContext`'s internal dict in most cases + (depends on the handler). + + """ + + __slots__ = () + + def __call__(self, update: Update) -> Optional[Union[bool, DataDict]]: + return self.filter(update.effective_message) + + @abstractmethod + def filter(self, message: Message) -> Optional[Union[bool, DataDict]]: + """This method must be overwritten. + + Args: + message (:class:`telegram.Message`): The message that is tested. + + Returns: + :obj:`dict` or :obj:`bool` + + """ + + +class UpdateFilter(BaseFilter): + """Base class for all Update Filters. In contrast to :class:`MessageFilter`, the object + passed to :meth:`filter` is ``update``, which allows to create filters like + :attr:`Filters.update.edited_message`. + + Please see :class:`telegram.ext.filters.BaseFilter` for details on how to create custom + filters. + + Attributes: + name (:obj:`str`): Name for this filter. Defaults to the type of filter. + data_filter (:obj:`bool`): Whether this filter is a data filter. A data filter should + return a dict with lists. The dict will be merged with + :class:`telegram.ext.CallbackContext`'s internal dict in most cases + (depends on the handler). + + """ + + __slots__ = () + + def __call__(self, update: Update) -> Optional[Union[bool, DataDict]]: + return self.filter(update) + + @abstractmethod + def filter(self, update: Update) -> Optional[Union[bool, DataDict]]: + """This method must be overwritten. + + Args: + update (:class:`telegram.Update`): The update that is tested. + + Returns: + :obj:`dict` or :obj:`bool`. + + """ + + +class InvertedFilter(UpdateFilter): + """Represents a filter that has been inverted. + + Args: + f: The filter to invert. + + """ + + __slots__ = ('f',) + + def __init__(self, f: BaseFilter): + self.f = f + + def filter(self, update: Update) -> bool: + return not bool(self.f(update)) + + @property + def name(self) -> str: + return f"<inverted {self.f}>" + + @name.setter + def name(self, name: str) -> NoReturn: + raise RuntimeError('Cannot set name for InvertedFilter') + + +class MergedFilter(UpdateFilter): + """Represents a filter consisting of two other filters. + + Args: + base_filter: Filter 1 of the merged filter. + and_filter: Optional filter to "and" with base_filter. Mutually exclusive with or_filter. + or_filter: Optional filter to "or" with base_filter. Mutually exclusive with and_filter. + + """ + + __slots__ = ('base_filter', 'and_filter', 'or_filter') + + def __init__( + self, base_filter: BaseFilter, and_filter: BaseFilter = None, or_filter: BaseFilter = None + ): + self.base_filter = base_filter + if self.base_filter.data_filter: + self.data_filter = True + self.and_filter = and_filter + if ( + self.and_filter + and not isinstance(self.and_filter, bool) + and self.and_filter.data_filter + ): + self.data_filter = True + self.or_filter = or_filter + if self.or_filter and not isinstance(self.and_filter, bool) and self.or_filter.data_filter: + self.data_filter = True + + @staticmethod + def _merge(base_output: Union[bool, Dict], comp_output: Union[bool, Dict]) -> DataDict: + base = base_output if isinstance(base_output, dict) else {} + comp = comp_output if isinstance(comp_output, dict) else {} + for k in comp.keys(): + # Make sure comp values are lists + comp_value = comp[k] if isinstance(comp[k], list) else [] + try: + # If base is a list then merge + if isinstance(base[k], list): + base[k] += comp_value + else: + base[k] = [base[k]] + comp_value + except KeyError: + base[k] = comp_value + return base + + def filter(self, update: Update) -> Union[bool, DataDict]: # pylint: disable=R0911 + base_output = self.base_filter(update) + # We need to check if the filters are data filters and if so return the merged data. + # If it's not a data filter or an or_filter but no matches return bool + if self.and_filter: + # And filter needs to short circuit if base is falsey + if base_output: + comp_output = self.and_filter(update) + if comp_output: + if self.data_filter: + merged = self._merge(base_output, comp_output) + if merged: + return merged + return True + elif self.or_filter: + # Or filter needs to short circuit if base is truthey + if base_output: + if self.data_filter: + return base_output + return True + + comp_output = self.or_filter(update) + if comp_output: + if self.data_filter: + return comp_output + return True + return False + + @property + def name(self) -> str: + return ( + f"<{self.base_filter} {'and' if self.and_filter else 'or'} " + f"{self.and_filter or self.or_filter}>" + ) + + @name.setter + def name(self, name: str) -> NoReturn: + raise RuntimeError('Cannot set name for MergedFilter') + + +class XORFilter(UpdateFilter): + """Convenience filter acting as wrapper for :class:`MergedFilter` representing the an XOR gate + for two filters. + + Args: + base_filter: Filter 1 of the merged filter. + xor_filter: Filter 2 of the merged filter. + + """ + + __slots__ = ('base_filter', 'xor_filter', 'merged_filter') + + def __init__(self, base_filter: BaseFilter, xor_filter: BaseFilter): + self.base_filter = base_filter + self.xor_filter = xor_filter + self.merged_filter = (base_filter & ~xor_filter) | (~base_filter & xor_filter) + + def filter(self, update: Update) -> Optional[Union[bool, DataDict]]: + return self.merged_filter(update) + + @property + def name(self) -> str: + return f'<{self.base_filter} xor {self.xor_filter}>' + + @name.setter + def name(self, name: str) -> NoReturn: + raise RuntimeError('Cannot set name for XORFilter') + + +class _DiceEmoji(MessageFilter): + __slots__ = ('emoji',) + + def __init__(self, emoji: str = None, name: str = None): + self.name = f'Filters.dice.{name}' if name else 'Filters.dice' + self.emoji = emoji + + class _DiceValues(MessageFilter): + __slots__ = ('values', 'emoji') + + def __init__( + self, + values: SLT[int], + name: str, + emoji: str = None, + ): + self.values = [values] if isinstance(values, int) else values + self.emoji = emoji + self.name = f'{name}({values})' + + def filter(self, message: Message) -> bool: + if message.dice and message.dice.value in self.values: + if self.emoji: + return message.dice.emoji == self.emoji + return True + return False + + def __call__( # type: ignore[override] + self, update: Union[Update, List[int], Tuple[int]] + ) -> Union[bool, '_DiceValues']: + if isinstance(update, Update): + return self.filter(update.effective_message) + return self._DiceValues(update, self.name, emoji=self.emoji) + + def filter(self, message: Message) -> bool: + if bool(message.dice): + if self.emoji: + return message.dice.emoji == self.emoji + return True + return False + + +class Filters: + """Predefined filters for use as the ``filter`` argument of + :class:`telegram.ext.MessageHandler`. + + Examples: + Use ``MessageHandler(Filters.video, callback_method)`` to filter all video + messages. Use ``MessageHandler(Filters.contact, callback_method)`` for all contacts. etc. + + """ + + __slots__ = ('__dict__',) + + def __setattr__(self, key: str, value: object) -> None: + set_new_attribute_deprecated(self, key, value) + + class _All(MessageFilter): + __slots__ = () + name = 'Filters.all' + + def filter(self, message: Message) -> bool: + return True + + all = _All() + """All Messages.""" + + class _Text(MessageFilter): + __slots__ = () + name = 'Filters.text' + + class _TextStrings(MessageFilter): + __slots__ = ('strings',) + + def __init__(self, strings: Union[List[str], Tuple[str]]): + self.strings = strings + self.name = f'Filters.text({strings})' + + def filter(self, message: Message) -> bool: + if message.text: + return message.text in self.strings + return False + + def __call__( # type: ignore[override] + self, update: Union[Update, List[str], Tuple[str]] + ) -> Union[bool, '_TextStrings']: + if isinstance(update, Update): + return self.filter(update.effective_message) + return self._TextStrings(update) + + def filter(self, message: Message) -> bool: + return bool(message.text) + + text = _Text() + """Text Messages. If a list of strings is passed, it filters messages to only allow those + whose text is appearing in the given list. + + Examples: + To allow any text message, simply use + ``MessageHandler(Filters.text, callback_method)``. + + A simple use case for passing a list is to allow only messages that were sent by a + custom :class:`telegram.ReplyKeyboardMarkup`:: + + buttons = ['Start', 'Settings', 'Back'] + markup = ReplyKeyboardMarkup.from_column(buttons) + ... + MessageHandler(Filters.text(buttons), callback_method) + + Note: + * Dice messages don't have text. If you want to filter either text or dice messages, use + ``Filters.text | Filters.dice``. + * Messages containing a command are accepted by this filter. Use + ``Filters.text & (~Filters.command)``, if you want to filter only text messages without + commands. + + Args: + update (List[:obj:`str`] | Tuple[:obj:`str`], optional): Which messages to allow. Only + exact matches are allowed. If not specified, will allow any text message. + """ + + class _Caption(MessageFilter): + __slots__ = () + name = 'Filters.caption' + + class _CaptionStrings(MessageFilter): + __slots__ = ('strings',) + + def __init__(self, strings: Union[List[str], Tuple[str]]): + self.strings = strings + self.name = f'Filters.caption({strings})' + + def filter(self, message: Message) -> bool: + if message.caption: + return message.caption in self.strings + return False + + def __call__( # type: ignore[override] + self, update: Union[Update, List[str], Tuple[str]] + ) -> Union[bool, '_CaptionStrings']: + if isinstance(update, Update): + return self.filter(update.effective_message) + return self._CaptionStrings(update) + + def filter(self, message: Message) -> bool: + return bool(message.caption) + + caption = _Caption() + """Messages with a caption. If a list of strings is passed, it filters messages to only + allow those whose caption is appearing in the given list. + + Examples: + ``MessageHandler(Filters.caption, callback_method)`` + + Args: + update (List[:obj:`str`] | Tuple[:obj:`str`], optional): Which captions to allow. Only + exact matches are allowed. If not specified, will allow any message with a caption. + """ + + class _Command(MessageFilter): + __slots__ = () + name = 'Filters.command' + + class _CommandOnlyStart(MessageFilter): + __slots__ = ('only_start',) + + def __init__(self, only_start: bool): + self.only_start = only_start + self.name = f'Filters.command({only_start})' + + def filter(self, message: Message) -> bool: + return bool( + message.entities + and any(e.type == MessageEntity.BOT_COMMAND for e in message.entities) + ) + + def __call__( # type: ignore[override] + self, update: Union[bool, Update] + ) -> Union[bool, '_CommandOnlyStart']: + if isinstance(update, Update): + return self.filter(update.effective_message) + return self._CommandOnlyStart(update) + + def filter(self, message: Message) -> bool: + return bool( + message.entities + and message.entities[0].type == MessageEntity.BOT_COMMAND + and message.entities[0].offset == 0 + ) + + command = _Command() + """ + Messages with a :attr:`telegram.MessageEntity.BOT_COMMAND`. By default only allows + messages `starting` with a bot command. Pass :obj:`False` to also allow messages that contain a + bot command `anywhere` in the text. + + Examples:: + + MessageHandler(Filters.command, command_at_start_callback) + MessageHandler(Filters.command(False), command_anywhere_callback) + + Note: + ``Filters.text`` also accepts messages containing a command. + + Args: + update (:obj:`bool`, optional): Whether to only allow messages that `start` with a bot + command. Defaults to :obj:`True`. + """ + + class regex(MessageFilter): + """ + Filters updates by searching for an occurrence of ``pattern`` in the message text. + The ``re.search()`` function is used to determine whether an update should be filtered. + + Refer to the documentation of the ``re`` module for more information. + + To get the groups and groupdict matched, see :attr:`telegram.ext.CallbackContext.matches`. + + Examples: + Use ``MessageHandler(Filters.regex(r'help'), callback)`` to capture all messages that + contain the word 'help'. You can also use + ``MessageHandler(Filters.regex(re.compile(r'help', re.IGNORECASE)), callback)`` if + you want your pattern to be case insensitive. This approach is recommended + if you need to specify flags on your pattern. + + Note: + Filters use the same short circuiting logic as python's `and`, `or` and `not`. + This means that for example: + + >>> Filters.regex(r'(a?x)') | Filters.regex(r'(b?x)') + + With a message.text of `x`, will only ever return the matches for the first filter, + since the second one is never evaluated. + + Args: + pattern (:obj:`str` | :obj:`Pattern`): The regex pattern. + """ + + __slots__ = ('pattern',) + data_filter = True + + def __init__(self, pattern: Union[str, Pattern]): + if isinstance(pattern, str): + pattern = re.compile(pattern) + pattern = cast(Pattern, pattern) + self.pattern: Pattern = pattern + self.name = f'Filters.regex({self.pattern})' + + def filter(self, message: Message) -> Optional[Dict[str, List[Match]]]: + """""" # remove method from docs + if message.text: + match = self.pattern.search(message.text) + if match: + return {'matches': [match]} + return {} + + class caption_regex(MessageFilter): + """ + Filters updates by searching for an occurrence of ``pattern`` in the message caption. + + This filter works similarly to :class:`Filters.regex`, with the only exception being that + it applies to the message caption instead of the text. + + Examples: + Use ``MessageHandler(Filters.photo & Filters.caption_regex(r'help'), callback)`` + to capture all photos with caption containing the word 'help'. + + Note: + This filter will not work on simple text messages, but only on media with caption. + + Args: + pattern (:obj:`str` | :obj:`Pattern`): The regex pattern. + """ + + __slots__ = ('pattern',) + data_filter = True + + def __init__(self, pattern: Union[str, Pattern]): + if isinstance(pattern, str): + pattern = re.compile(pattern) + pattern = cast(Pattern, pattern) + self.pattern: Pattern = pattern + self.name = f'Filters.caption_regex({self.pattern})' + + def filter(self, message: Message) -> Optional[Dict[str, List[Match]]]: + """""" # remove method from docs + if message.caption: + match = self.pattern.search(message.caption) + if match: + return {'matches': [match]} + return {} + + class _Reply(MessageFilter): + __slots__ = () + name = 'Filters.reply' + + def filter(self, message: Message) -> bool: + return bool(message.reply_to_message) + + reply = _Reply() + """Messages that are a reply to another message.""" + + class _Audio(MessageFilter): + __slots__ = () + name = 'Filters.audio' + + def filter(self, message: Message) -> bool: + return bool(message.audio) + + audio = _Audio() + """Messages that contain :class:`telegram.Audio`.""" + + class _Document(MessageFilter): + __slots__ = () + name = 'Filters.document' + + class category(MessageFilter): + """Filters documents by their category in the mime-type attribute. + + Note: + This Filter only filters by the mime_type of the document, + it doesn't check the validity of the document. + The user can manipulate the mime-type of a message and + send media with wrong types that don't fit to this handler. + + Example: + Filters.document.category('audio/') returns :obj:`True` for all types + of audio sent as file, for example 'audio/mpeg' or 'audio/x-wav'. + """ + + __slots__ = ('_category',) + + def __init__(self, category: Optional[str]): + """Initialize the category you want to filter + + Args: + category (str, optional): category of the media you want to filter + """ + self._category = category + self.name = f"Filters.document.category('{self._category}')" + + def filter(self, message: Message) -> bool: + """""" # remove method from docs + if message.document: + return message.document.mime_type.startswith(self._category) + return False + + application = category('application/') + audio = category('audio/') + image = category('image/') + video = category('video/') + text = category('text/') + + class mime_type(MessageFilter): + """This Filter filters documents by their mime-type attribute + + Note: + This Filter only filters by the mime_type of the document, + it doesn't check the validity of document. + The user can manipulate the mime-type of a message and + send media with wrong types that don't fit to this handler. + + Example: + ``Filters.document.mime_type('audio/mpeg')`` filters all audio in mp3 format. + """ + + __slots__ = ('mimetype',) + + def __init__(self, mimetype: Optional[str]): + self.mimetype = mimetype + self.name = f"Filters.document.mime_type('{self.mimetype}')" + + def filter(self, message: Message) -> bool: + """""" # remove method from docs + if message.document: + return message.document.mime_type == self.mimetype + return False + + apk = mime_type('application/vnd.android.package-archive') + doc = mime_type('application/msword') + docx = mime_type('application/vnd.openxmlformats-officedocument.wordprocessingml.document') + exe = mime_type('application/x-ms-dos-executable') + gif = mime_type('video/mp4') + jpg = mime_type('image/jpeg') + mp3 = mime_type('audio/mpeg') + pdf = mime_type('application/pdf') + py = mime_type('text/x-python') + svg = mime_type('image/svg+xml') + txt = mime_type('text/plain') + targz = mime_type('application/x-compressed-tar') + wav = mime_type('audio/x-wav') + xml = mime_type('application/xml') + zip = mime_type('application/zip') + + class file_extension(MessageFilter): + """This filter filters documents by their file ending/extension. + + Note: + * This Filter only filters by the file ending/extension of the document, + it doesn't check the validity of document. + * The user can manipulate the file extension of a document and + send media with wrong types that don't fit to this handler. + * Case insensitive by default, + you may change this with the flag ``case_sensitive=True``. + * Extension should be passed without leading dot + unless it's a part of the extension. + * Pass :obj:`None` to filter files with no extension, + i.e. without a dot in the filename. + + Example: + * ``Filters.document.file_extension("jpg")`` + filters files with extension ``".jpg"``. + * ``Filters.document.file_extension(".jpg")`` + filters files with extension ``"..jpg"``. + * ``Filters.document.file_extension("Dockerfile", case_sensitive=True)`` + filters files with extension ``".Dockerfile"`` minding the case. + * ``Filters.document.file_extension(None)`` + filters files without a dot in the filename. + """ + + __slots__ = ('_file_extension', 'is_case_sensitive') + + def __init__(self, file_extension: Optional[str], case_sensitive: bool = False): + """Initialize the extension you want to filter. + + Args: + file_extension (:obj:`str` | :obj:`None`): + media file extension you want to filter. + case_sensitive (:obj:bool, optional): + pass :obj:`True` to make the filter case sensitive. + Default: :obj:`False`. + """ + self.is_case_sensitive = case_sensitive + if file_extension is None: + self._file_extension = None + self.name = "Filters.document.file_extension(None)" + elif self.is_case_sensitive: + self._file_extension = f".{file_extension}" + self.name = ( + f"Filters.document.file_extension({file_extension!r}," + " case_sensitive=True)" + ) + else: + self._file_extension = f".{file_extension}".lower() + self.name = f"Filters.document.file_extension({file_extension.lower()!r})" + + def filter(self, message: Message) -> bool: + """""" # remove method from docs + if message.document is None: + return False + if self._file_extension is None: + return "." not in message.document.file_name + if self.is_case_sensitive: + filename = message.document.file_name + else: + filename = message.document.file_name.lower() + return filename.endswith(self._file_extension) + + def filter(self, message: Message) -> bool: + return bool(message.document) + + document = _Document() + """ + Subset for messages containing a document/file. + + Examples: + Use these filters like: ``Filters.document.mp3``, + ``Filters.document.mime_type("text/plain")`` etc. Or use just + ``Filters.document`` for all document messages. + + Attributes: + category: Filters documents by their category in the mime-type attribute + + Note: + This Filter only filters by the mime_type of the document, + it doesn't check the validity of the document. + The user can manipulate the mime-type of a message and + send media with wrong types that don't fit to this handler. + + Example: + ``Filters.document.category('audio/')`` filters all types + of audio sent as file, for example 'audio/mpeg' or 'audio/x-wav'. + application: Same as ``Filters.document.category("application")``. + audio: Same as ``Filters.document.category("audio")``. + image: Same as ``Filters.document.category("image")``. + video: Same as ``Filters.document.category("video")``. + text: Same as ``Filters.document.category("text")``. + mime_type: Filters documents by their mime-type attribute + + Note: + This Filter only filters by the mime_type of the document, + it doesn't check the validity of document. + + The user can manipulate the mime-type of a message and + send media with wrong types that don't fit to this handler. + + Example: + ``Filters.document.mime_type('audio/mpeg')`` filters all audio in mp3 format. + apk: Same as ``Filters.document.mime_type("application/vnd.android.package-archive")``. + doc: Same as ``Filters.document.mime_type("application/msword")``. + docx: Same as ``Filters.document.mime_type("application/vnd.openxmlformats-\ +officedocument.wordprocessingml.document")``. + exe: Same as ``Filters.document.mime_type("application/x-ms-dos-executable")``. + gif: Same as ``Filters.document.mime_type("video/mp4")``. + jpg: Same as ``Filters.document.mime_type("image/jpeg")``. + mp3: Same as ``Filters.document.mime_type("audio/mpeg")``. + pdf: Same as ``Filters.document.mime_type("application/pdf")``. + py: Same as ``Filters.document.mime_type("text/x-python")``. + svg: Same as ``Filters.document.mime_type("image/svg+xml")``. + txt: Same as ``Filters.document.mime_type("text/plain")``. + targz: Same as ``Filters.document.mime_type("application/x-compressed-tar")``. + wav: Same as ``Filters.document.mime_type("audio/x-wav")``. + xml: Same as ``Filters.document.mime_type("application/xml")``. + zip: Same as ``Filters.document.mime_type("application/zip")``. + file_extension: This filter filters documents by their file ending/extension. + + Note: + * This Filter only filters by the file ending/extension of the document, + it doesn't check the validity of document. + * The user can manipulate the file extension of a document and + send media with wrong types that don't fit to this handler. + * Case insensitive by default, + you may change this with the flag ``case_sensitive=True``. + * Extension should be passed without leading dot + unless it's a part of the extension. + * Pass :obj:`None` to filter files with no extension, + i.e. without a dot in the filename. + + Example: + * ``Filters.document.file_extension("jpg")`` + filters files with extension ``".jpg"``. + * ``Filters.document.file_extension(".jpg")`` + filters files with extension ``"..jpg"``. + * ``Filters.document.file_extension("Dockerfile", case_sensitive=True)`` + filters files with extension ``".Dockerfile"`` minding the case. + * ``Filters.document.file_extension(None)`` + filters files without a dot in the filename. + """ + + class _Animation(MessageFilter): + __slots__ = () + name = 'Filters.animation' + + def filter(self, message: Message) -> bool: + return bool(message.animation) + + animation = _Animation() + """Messages that contain :class:`telegram.Animation`.""" + + class _Photo(MessageFilter): + __slots__ = () + name = 'Filters.photo' + + def filter(self, message: Message) -> bool: + return bool(message.photo) + + photo = _Photo() + """Messages that contain :class:`telegram.PhotoSize`.""" + + class _Sticker(MessageFilter): + __slots__ = () + name = 'Filters.sticker' + + def filter(self, message: Message) -> bool: + return bool(message.sticker) + + sticker = _Sticker() + """Messages that contain :class:`telegram.Sticker`.""" + + class _Video(MessageFilter): + __slots__ = () + name = 'Filters.video' + + def filter(self, message: Message) -> bool: + return bool(message.video) + + video = _Video() + """Messages that contain :class:`telegram.Video`.""" + + class _Voice(MessageFilter): + __slots__ = () + name = 'Filters.voice' + + def filter(self, message: Message) -> bool: + return bool(message.voice) + + voice = _Voice() + """Messages that contain :class:`telegram.Voice`.""" + + class _VideoNote(MessageFilter): + __slots__ = () + name = 'Filters.video_note' + + def filter(self, message: Message) -> bool: + return bool(message.video_note) + + video_note = _VideoNote() + """Messages that contain :class:`telegram.VideoNote`.""" + + class _Contact(MessageFilter): + __slots__ = () + name = 'Filters.contact' + + def filter(self, message: Message) -> bool: + return bool(message.contact) + + contact = _Contact() + """Messages that contain :class:`telegram.Contact`.""" + + class _Location(MessageFilter): + __slots__ = () + name = 'Filters.location' + + def filter(self, message: Message) -> bool: + return bool(message.location) + + location = _Location() + """Messages that contain :class:`telegram.Location`.""" + + class _Venue(MessageFilter): + __slots__ = () + name = 'Filters.venue' + + def filter(self, message: Message) -> bool: + return bool(message.venue) + + venue = _Venue() + """Messages that contain :class:`telegram.Venue`.""" + + class _StatusUpdate(UpdateFilter): + """Subset for messages containing a status update. + + Examples: + Use these filters like: ``Filters.status_update.new_chat_members`` etc. Or use just + ``Filters.status_update`` for all status update messages. + + """ + + __slots__ = () + + class _NewChatMembers(MessageFilter): + __slots__ = () + name = 'Filters.status_update.new_chat_members' + + def filter(self, message: Message) -> bool: + return bool(message.new_chat_members) + + new_chat_members = _NewChatMembers() + """Messages that contain :attr:`telegram.Message.new_chat_members`.""" + + class _LeftChatMember(MessageFilter): + __slots__ = () + name = 'Filters.status_update.left_chat_member' + + def filter(self, message: Message) -> bool: + return bool(message.left_chat_member) + + left_chat_member = _LeftChatMember() + """Messages that contain :attr:`telegram.Message.left_chat_member`.""" + + class _NewChatTitle(MessageFilter): + __slots__ = () + name = 'Filters.status_update.new_chat_title' + + def filter(self, message: Message) -> bool: + return bool(message.new_chat_title) + + new_chat_title = _NewChatTitle() + """Messages that contain :attr:`telegram.Message.new_chat_title`.""" + + class _NewChatPhoto(MessageFilter): + __slots__ = () + name = 'Filters.status_update.new_chat_photo' + + def filter(self, message: Message) -> bool: + return bool(message.new_chat_photo) + + new_chat_photo = _NewChatPhoto() + """Messages that contain :attr:`telegram.Message.new_chat_photo`.""" + + class _DeleteChatPhoto(MessageFilter): + __slots__ = () + name = 'Filters.status_update.delete_chat_photo' + + def filter(self, message: Message) -> bool: + return bool(message.delete_chat_photo) + + delete_chat_photo = _DeleteChatPhoto() + """Messages that contain :attr:`telegram.Message.delete_chat_photo`.""" + + class _ChatCreated(MessageFilter): + __slots__ = () + name = 'Filters.status_update.chat_created' + + def filter(self, message: Message) -> bool: + return bool( + message.group_chat_created + or message.supergroup_chat_created + or message.channel_chat_created + ) + + chat_created = _ChatCreated() + """Messages that contain :attr:`telegram.Message.group_chat_created`, + :attr: `telegram.Message.supergroup_chat_created` or + :attr: `telegram.Message.channel_chat_created`.""" + + class _MessageAutoDeleteTimerChanged(MessageFilter): + __slots__ = () + name = 'MessageAutoDeleteTimerChanged' + + def filter(self, message: Message) -> bool: + return bool(message.message_auto_delete_timer_changed) + + message_auto_delete_timer_changed = _MessageAutoDeleteTimerChanged() + """Messages that contain :attr:`message_auto_delete_timer_changed`""" + + class _Migrate(MessageFilter): + __slots__ = () + name = 'Filters.status_update.migrate' + + def filter(self, message: Message) -> bool: + return bool(message.migrate_from_chat_id or message.migrate_to_chat_id) + + migrate = _Migrate() + """Messages that contain :attr:`telegram.Message.migrate_from_chat_id` or + :attr:`telegram.Message.migrate_to_chat_id`.""" + + class _PinnedMessage(MessageFilter): + __slots__ = () + name = 'Filters.status_update.pinned_message' + + def filter(self, message: Message) -> bool: + return bool(message.pinned_message) + + pinned_message = _PinnedMessage() + """Messages that contain :attr:`telegram.Message.pinned_message`.""" + + class _ConnectedWebsite(MessageFilter): + __slots__ = () + name = 'Filters.status_update.connected_website' + + def filter(self, message: Message) -> bool: + return bool(message.connected_website) + + connected_website = _ConnectedWebsite() + """Messages that contain :attr:`telegram.Message.connected_website`.""" + + class _ProximityAlertTriggered(MessageFilter): + __slots__ = () + name = 'Filters.status_update.proximity_alert_triggered' + + def filter(self, message: Message) -> bool: + return bool(message.proximity_alert_triggered) + + proximity_alert_triggered = _ProximityAlertTriggered() + """Messages that contain :attr:`telegram.Message.proximity_alert_triggered`.""" + + class _VoiceChatScheduled(MessageFilter): + __slots__ = () + name = 'Filters.status_update.voice_chat_scheduled' + + def filter(self, message: Message) -> bool: + return bool(message.voice_chat_scheduled) + + voice_chat_scheduled = _VoiceChatScheduled() + """Messages that contain :attr:`telegram.Message.voice_chat_scheduled`.""" + + class _VoiceChatStarted(MessageFilter): + __slots__ = () + name = 'Filters.status_update.voice_chat_started' + + def filter(self, message: Message) -> bool: + return bool(message.voice_chat_started) + + voice_chat_started = _VoiceChatStarted() + """Messages that contain :attr:`telegram.Message.voice_chat_started`.""" + + class _VoiceChatEnded(MessageFilter): + __slots__ = () + name = 'Filters.status_update.voice_chat_ended' + + def filter(self, message: Message) -> bool: + return bool(message.voice_chat_ended) + + voice_chat_ended = _VoiceChatEnded() + """Messages that contain :attr:`telegram.Message.voice_chat_ended`.""" + + class _VoiceChatParticipantsInvited(MessageFilter): + __slots__ = () + name = 'Filters.status_update.voice_chat_participants_invited' + + def filter(self, message: Message) -> bool: + return bool(message.voice_chat_participants_invited) + + voice_chat_participants_invited = _VoiceChatParticipantsInvited() + """Messages that contain :attr:`telegram.Message.voice_chat_participants_invited`.""" + + name = 'Filters.status_update' + + def filter(self, message: Update) -> bool: + return bool( + self.new_chat_members(message) + or self.left_chat_member(message) + or self.new_chat_title(message) + or self.new_chat_photo(message) + or self.delete_chat_photo(message) + or self.chat_created(message) + or self.message_auto_delete_timer_changed(message) + or self.migrate(message) + or self.pinned_message(message) + or self.connected_website(message) + or self.proximity_alert_triggered(message) + or self.voice_chat_scheduled(message) + or self.voice_chat_started(message) + or self.voice_chat_ended(message) + or self.voice_chat_participants_invited(message) + ) + + status_update = _StatusUpdate() + """Subset for messages containing a status update. + + Examples: + Use these filters like: ``Filters.status_update.new_chat_members`` etc. Or use just + ``Filters.status_update`` for all status update messages. + + Attributes: + chat_created: Messages that contain + :attr:`telegram.Message.group_chat_created`, + :attr:`telegram.Message.supergroup_chat_created` or + :attr:`telegram.Message.channel_chat_created`. + connected_website: Messages that contain + :attr:`telegram.Message.connected_website`. + delete_chat_photo: Messages that contain + :attr:`telegram.Message.delete_chat_photo`. + left_chat_member: Messages that contain + :attr:`telegram.Message.left_chat_member`. + migrate: Messages that contain + :attr:`telegram.Message.migrate_to_chat_id` or + :attr:`telegram.Message.migrate_from_chat_id`. + new_chat_members: Messages that contain + :attr:`telegram.Message.new_chat_members`. + new_chat_photo: Messages that contain + :attr:`telegram.Message.new_chat_photo`. + new_chat_title: Messages that contain + :attr:`telegram.Message.new_chat_title`. + message_auto_delete_timer_changed: Messages that contain + :attr:`message_auto_delete_timer_changed`. + + .. versionadded:: 13.4 + pinned_message: Messages that contain + :attr:`telegram.Message.pinned_message`. + proximity_alert_triggered: Messages that contain + :attr:`telegram.Message.proximity_alert_triggered`. + voice_chat_scheduled: Messages that contain + :attr:`telegram.Message.voice_chat_scheduled`. + + .. versionadded:: 13.5 + voice_chat_started: Messages that contain + :attr:`telegram.Message.voice_chat_started`. + + .. versionadded:: 13.4 + voice_chat_ended: Messages that contain + :attr:`telegram.Message.voice_chat_ended`. + + .. versionadded:: 13.4 + voice_chat_participants_invited: Messages that contain + :attr:`telegram.Message.voice_chat_participants_invited`. + + .. versionadded:: 13.4 + + """ + + class _Forwarded(MessageFilter): + __slots__ = () + name = 'Filters.forwarded' + + def filter(self, message: Message) -> bool: + return bool(message.forward_date) + + forwarded = _Forwarded() + """Messages that are forwarded.""" + + class _Game(MessageFilter): + __slots__ = () + name = 'Filters.game' + + def filter(self, message: Message) -> bool: + return bool(message.game) + + game = _Game() + """Messages that contain :class:`telegram.Game`.""" + + class entity(MessageFilter): + """ + Filters messages to only allow those which have a :class:`telegram.MessageEntity` + where their `type` matches `entity_type`. + + Examples: + Example ``MessageHandler(Filters.entity("hashtag"), callback_method)`` + + Args: + entity_type: Entity type to check for. All types can be found as constants + in :class:`telegram.MessageEntity`. + + """ + + __slots__ = ('entity_type',) + + def __init__(self, entity_type: str): + self.entity_type = entity_type + self.name = f'Filters.entity({self.entity_type})' + + def filter(self, message: Message) -> bool: + """""" # remove method from docs + return any(entity.type == self.entity_type for entity in message.entities) + + class caption_entity(MessageFilter): + """ + Filters media messages to only allow those which have a :class:`telegram.MessageEntity` + where their `type` matches `entity_type`. + + Examples: + Example ``MessageHandler(Filters.caption_entity("hashtag"), callback_method)`` + + Args: + entity_type: Caption Entity type to check for. All types can be found as constants + in :class:`telegram.MessageEntity`. + + """ + + __slots__ = ('entity_type',) + + def __init__(self, entity_type: str): + self.entity_type = entity_type + self.name = f'Filters.caption_entity({self.entity_type})' + + def filter(self, message: Message) -> bool: + """""" # remove method from docs + return any(entity.type == self.entity_type for entity in message.caption_entities) + + class _Private(MessageFilter): + __slots__ = () + name = 'Filters.private' + + def filter(self, message: Message) -> bool: + warnings.warn( + 'Filters.private is deprecated. Use Filters.chat_type.private instead.', + TelegramDeprecationWarning, + stacklevel=2, + ) + return message.chat.type == Chat.PRIVATE + + private = _Private() + """ + Messages sent in a private chat. + + Note: + DEPRECATED. Use + :attr:`telegram.ext.Filters.chat_type.private` instead. + """ + + class _Group(MessageFilter): + __slots__ = () + name = 'Filters.group' + + def filter(self, message: Message) -> bool: + warnings.warn( + 'Filters.group is deprecated. Use Filters.chat_type.groups instead.', + TelegramDeprecationWarning, + stacklevel=2, + ) + return message.chat.type in [Chat.GROUP, Chat.SUPERGROUP] + + group = _Group() + """ + Messages sent in a group or a supergroup chat. + + Note: + DEPRECATED. Use + :attr:`telegram.ext.Filters.chat_type.groups` instead. + """ + + class _ChatType(MessageFilter): + __slots__ = () + name = 'Filters.chat_type' + + class _Channel(MessageFilter): + __slots__ = () + name = 'Filters.chat_type.channel' + + def filter(self, message: Message) -> bool: + return message.chat.type == Chat.CHANNEL + + channel = _Channel() + + class _Group(MessageFilter): + __slots__ = () + name = 'Filters.chat_type.group' + + def filter(self, message: Message) -> bool: + return message.chat.type == Chat.GROUP + + group = _Group() + + class _SuperGroup(MessageFilter): + __slots__ = () + name = 'Filters.chat_type.supergroup' + + def filter(self, message: Message) -> bool: + return message.chat.type == Chat.SUPERGROUP + + supergroup = _SuperGroup() + + class _Groups(MessageFilter): + __slots__ = () + name = 'Filters.chat_type.groups' + + def filter(self, message: Message) -> bool: + return message.chat.type in [Chat.GROUP, Chat.SUPERGROUP] + + groups = _Groups() + + class _Private(MessageFilter): + __slots__ = () + name = 'Filters.chat_type.private' + + def filter(self, message: Message) -> bool: + return message.chat.type == Chat.PRIVATE + + private = _Private() + + def filter(self, message: Message) -> bool: + return bool(message.chat.type) + + chat_type = _ChatType() + """Subset for filtering the type of chat. + + Examples: + Use these filters like: ``Filters.chat_type.channel`` or + ``Filters.chat_type.supergroup`` etc. Or use just ``Filters.chat_type`` for all + chat types. + + Attributes: + channel: Updates from channel + group: Updates from group + supergroup: Updates from supergroup + groups: Updates from group *or* supergroup + private: Updates sent in private chat + """ + + class _ChatUserBaseFilter(MessageFilter, ABC): + __slots__ = ( + 'chat_id_name', + 'username_name', + 'allow_empty', + '__lock', + '_chat_ids', + '_usernames', + ) + + def __init__( + self, + chat_id: SLT[int] = None, + username: SLT[str] = None, + allow_empty: bool = False, + ): + self.chat_id_name = 'chat_id' + self.username_name = 'username' + self.allow_empty = allow_empty + self.__lock = Lock() + + self._chat_ids: Set[int] = set() + self._usernames: Set[str] = set() + + self._set_chat_ids(chat_id) + self._set_usernames(username) + + @abstractmethod + def get_chat_or_user(self, message: Message) -> Union[Chat, User, None]: + ... + + @staticmethod + def _parse_chat_id(chat_id: SLT[int]) -> Set[int]: + if chat_id is None: + return set() + if isinstance(chat_id, int): + return {chat_id} + return set(chat_id) + + @staticmethod + def _parse_username(username: SLT[str]) -> Set[str]: + if username is None: + return set() + if isinstance(username, str): + return {username[1:] if username.startswith('@') else username} + return {chat[1:] if chat.startswith('@') else chat for chat in username} + + def _set_chat_ids(self, chat_id: SLT[int]) -> None: + with self.__lock: + if chat_id and self._usernames: + raise RuntimeError( + f"Can't set {self.chat_id_name} in conjunction with (already set) " + f"{self.username_name}s." + ) + self._chat_ids = self._parse_chat_id(chat_id) + + def _set_usernames(self, username: SLT[str]) -> None: + with self.__lock: + if username and self._chat_ids: + raise RuntimeError( + f"Can't set {self.username_name} in conjunction with (already set) " + f"{self.chat_id_name}s." + ) + self._usernames = self._parse_username(username) + + @property + def chat_ids(self) -> FrozenSet[int]: + with self.__lock: + return frozenset(self._chat_ids) + + @chat_ids.setter + def chat_ids(self, chat_id: SLT[int]) -> None: + self._set_chat_ids(chat_id) + + @property + def usernames(self) -> FrozenSet[str]: + with self.__lock: + return frozenset(self._usernames) + + @usernames.setter + def usernames(self, username: SLT[str]) -> None: + self._set_usernames(username) + + def add_usernames(self, username: SLT[str]) -> None: + with self.__lock: + if self._chat_ids: + raise RuntimeError( + f"Can't set {self.username_name} in conjunction with (already set) " + f"{self.chat_id_name}s." + ) + + parsed_username = self._parse_username(username) + self._usernames |= parsed_username + + def add_chat_ids(self, chat_id: SLT[int]) -> None: + with self.__lock: + if self._usernames: + raise RuntimeError( + f"Can't set {self.chat_id_name} in conjunction with (already set) " + f"{self.username_name}s." + ) + + parsed_chat_id = self._parse_chat_id(chat_id) + + self._chat_ids |= parsed_chat_id + + def remove_usernames(self, username: SLT[str]) -> None: + with self.__lock: + if self._chat_ids: + raise RuntimeError( + f"Can't set {self.username_name} in conjunction with (already set) " + f"{self.chat_id_name}s." + ) + + parsed_username = self._parse_username(username) + self._usernames -= parsed_username + + def remove_chat_ids(self, chat_id: SLT[int]) -> None: + with self.__lock: + if self._usernames: + raise RuntimeError( + f"Can't set {self.chat_id_name} in conjunction with (already set) " + f"{self.username_name}s." + ) + parsed_chat_id = self._parse_chat_id(chat_id) + self._chat_ids -= parsed_chat_id + + def filter(self, message: Message) -> bool: + """""" # remove method from docs + chat_or_user = self.get_chat_or_user(message) + if chat_or_user: + if self.chat_ids: + return chat_or_user.id in self.chat_ids + if self.usernames: + return bool(chat_or_user.username and chat_or_user.username in self.usernames) + return self.allow_empty + return False + + @property + def name(self) -> str: + return ( + f'Filters.{self.__class__.__name__}(' + f'{", ".join(str(s) for s in (self.usernames or self.chat_ids))})' + ) + + @name.setter + def name(self, name: str) -> NoReturn: + raise RuntimeError(f'Cannot set name for Filters.{self.__class__.__name__}') + + class user(_ChatUserBaseFilter): + # pylint: disable=W0235 + """Filters messages to allow only those which are from specified user ID(s) or + username(s). + + Examples: + ``MessageHandler(Filters.user(1234), callback_method)`` + + Warning: + :attr:`user_ids` will give a *copy* of the saved user ids as :class:`frozenset`. This + is to ensure thread safety. To add/remove a user, you should use :meth:`add_usernames`, + :meth:`add_user_ids`, :meth:`remove_usernames` and :meth:`remove_user_ids`. Only update + the entire set by ``filter.user_ids/usernames = new_set``, if you are entirely sure + that it is not causing race conditions, as this will complete replace the current set + of allowed users. + + Args: + user_id(:class:`telegram.utils.types.SLT[int]`, optional): + Which user ID(s) to allow through. + username(:class:`telegram.utils.types.SLT[str]`, optional): + Which username(s) to allow through. Leading ``'@'`` s in usernames will be + discarded. + allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no user + is specified in :attr:`user_ids` and :attr:`usernames`. Defaults to :obj:`False` + + Raises: + RuntimeError: If user_id and username are both present. + + Attributes: + user_ids(set(:obj:`int`), optional): Which user ID(s) to allow through. + usernames(set(:obj:`str`), optional): Which username(s) (without leading ``'@'``) to + allow through. + allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no user + is specified in :attr:`user_ids` and :attr:`usernames`. + + """ + + __slots__ = () + + def __init__( + self, + user_id: SLT[int] = None, + username: SLT[str] = None, + allow_empty: bool = False, + ): + super().__init__(chat_id=user_id, username=username, allow_empty=allow_empty) + self.chat_id_name = 'user_id' + + def get_chat_or_user(self, message: Message) -> Optional[User]: + return message.from_user + + @property + def user_ids(self) -> FrozenSet[int]: + return self.chat_ids + + @user_ids.setter + def user_ids(self, user_id: SLT[int]) -> None: + self.chat_ids = user_id # type: ignore[assignment] + + def add_usernames(self, username: SLT[str]) -> None: + """ + Add one or more users to the allowed usernames. + + Args: + username(:class:`telegram.utils.types.SLT[str]`, optional): + Which username(s) to allow through. + Leading ``'@'`` s in usernames will be discarded. + """ + return super().add_usernames(username) + + def add_user_ids(self, user_id: SLT[int]) -> None: + """ + Add one or more users to the allowed user ids. + + Args: + user_id(:class:`telegram.utils.types.SLT[int]`, optional): + Which user ID(s) to allow through. + """ + return super().add_chat_ids(user_id) + + def remove_usernames(self, username: SLT[str]) -> None: + """ + Remove one or more users from allowed usernames. + + Args: + username(:class:`telegram.utils.types.SLT[str]`, optional): + Which username(s) to disallow through. + Leading ``'@'`` s in usernames will be discarded. + """ + return super().remove_usernames(username) + + def remove_user_ids(self, user_id: SLT[int]) -> None: + """ + Remove one or more users from allowed user ids. + + Args: + user_id(:class:`telegram.utils.types.SLT[int]`, optional): + Which user ID(s) to disallow through. + """ + return super().remove_chat_ids(user_id) + + class via_bot(_ChatUserBaseFilter): + # pylint: disable=W0235 + """Filters messages to allow only those which are from specified via_bot ID(s) or + username(s). + + Examples: + ``MessageHandler(Filters.via_bot(1234), callback_method)`` + + Warning: + :attr:`bot_ids` will give a *copy* of the saved bot ids as :class:`frozenset`. This + is to ensure thread safety. To add/remove a bot, you should use :meth:`add_usernames`, + :meth:`add_bot_ids`, :meth:`remove_usernames` and :meth:`remove_bot_ids`. Only update + the entire set by ``filter.bot_ids/usernames = new_set``, if you are entirely sure + that it is not causing race conditions, as this will complete replace the current set + of allowed bots. + + Args: + bot_id(:class:`telegram.utils.types.SLT[int]`, optional): + Which bot ID(s) to allow through. + username(:class:`telegram.utils.types.SLT[str]`, optional): + Which username(s) to allow through. Leading ``'@'`` s in usernames will be + discarded. + allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no user + is specified in :attr:`bot_ids` and :attr:`usernames`. Defaults to :obj:`False` + + Raises: + RuntimeError: If bot_id and username are both present. + + Attributes: + bot_ids(set(:obj:`int`), optional): Which bot ID(s) to allow through. + usernames(set(:obj:`str`), optional): Which username(s) (without leading ``'@'``) to + allow through. + allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no bot + is specified in :attr:`bot_ids` and :attr:`usernames`. + + """ + + __slots__ = () + + def __init__( + self, + bot_id: SLT[int] = None, + username: SLT[str] = None, + allow_empty: bool = False, + ): + super().__init__(chat_id=bot_id, username=username, allow_empty=allow_empty) + self.chat_id_name = 'bot_id' + + def get_chat_or_user(self, message: Message) -> Optional[User]: + return message.via_bot + + @property + def bot_ids(self) -> FrozenSet[int]: + return self.chat_ids + + @bot_ids.setter + def bot_ids(self, bot_id: SLT[int]) -> None: + self.chat_ids = bot_id # type: ignore[assignment] + + def add_usernames(self, username: SLT[str]) -> None: + """ + Add one or more users to the allowed usernames. + + Args: + username(:class:`telegram.utils.types.SLT[str]`, optional): + Which username(s) to allow through. + Leading ``'@'`` s in usernames will be discarded. + """ + return super().add_usernames(username) + + def add_bot_ids(self, bot_id: SLT[int]) -> None: + """ + + Add one or more users to the allowed user ids. + + Args: + bot_id(:class:`telegram.utils.types.SLT[int]`, optional): + Which bot ID(s) to allow through. + """ + return super().add_chat_ids(bot_id) + + def remove_usernames(self, username: SLT[str]) -> None: + """ + Remove one or more users from allowed usernames. + + Args: + username(:class:`telegram.utils.types.SLT[str]`, optional): + Which username(s) to disallow through. + Leading ``'@'`` s in usernames will be discarded. + """ + return super().remove_usernames(username) + + def remove_bot_ids(self, bot_id: SLT[int]) -> None: + """ + Remove one or more users from allowed user ids. + + Args: + bot_id(:class:`telegram.utils.types.SLT[int]`, optional): + Which bot ID(s) to disallow through. + """ + return super().remove_chat_ids(bot_id) + + class chat(_ChatUserBaseFilter): + # pylint: disable=W0235 + """Filters messages to allow only those which are from a specified chat ID or username. + + Examples: + ``MessageHandler(Filters.chat(-1234), callback_method)`` + + Warning: + :attr:`chat_ids` will give a *copy* of the saved chat ids as :class:`frozenset`. This + is to ensure thread safety. To add/remove a chat, you should use :meth:`add_usernames`, + :meth:`add_chat_ids`, :meth:`remove_usernames` and :meth:`remove_chat_ids`. Only update + the entire set by ``filter.chat_ids/usernames = new_set``, if you are entirely sure + that it is not causing race conditions, as this will complete replace the current set + of allowed chats. + + Args: + chat_id(:class:`telegram.utils.types.SLT[int]`, optional): + Which chat ID(s) to allow through. + username(:class:`telegram.utils.types.SLT[str]`, optional): + Which username(s) to allow through. + Leading ``'@'`` s in usernames will be discarded. + allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no chat + is specified in :attr:`chat_ids` and :attr:`usernames`. Defaults to :obj:`False` + + Raises: + RuntimeError: If chat_id and username are both present. + + Attributes: + chat_ids(set(:obj:`int`), optional): Which chat ID(s) to allow through. + usernames(set(:obj:`str`), optional): Which username(s) (without leading ``'@'``) to + allow through. + allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no chat + is specified in :attr:`chat_ids` and :attr:`usernames`. + + """ + + __slots__ = () + + def get_chat_or_user(self, message: Message) -> Optional[Chat]: + return message.chat + + def add_usernames(self, username: SLT[str]) -> None: + """ + Add one or more chats to the allowed usernames. + + Args: + username(:class:`telegram.utils.types.SLT[str]`, optional): + Which username(s) to allow through. + Leading ``'@'`` s in usernames will be discarded. + """ + return super().add_usernames(username) + + def add_chat_ids(self, chat_id: SLT[int]) -> None: + """ + Add one or more chats to the allowed chat ids. + + Args: + chat_id(:class:`telegram.utils.types.SLT[int]`, optional): + Which chat ID(s) to allow through. + """ + return super().add_chat_ids(chat_id) + + def remove_usernames(self, username: SLT[str]) -> None: + """ + Remove one or more chats from allowed usernames. + + Args: + username(:class:`telegram.utils.types.SLT[str]`, optional): + Which username(s) to disallow through. + Leading ``'@'`` s in usernames will be discarded. + """ + return super().remove_usernames(username) + + def remove_chat_ids(self, chat_id: SLT[int]) -> None: + """ + Remove one or more chats from allowed chat ids. + + Args: + chat_id(:class:`telegram.utils.types.SLT[int]`, optional): + Which chat ID(s) to disallow through. + """ + return super().remove_chat_ids(chat_id) + + class forwarded_from(_ChatUserBaseFilter): + # pylint: disable=W0235 + """Filters messages to allow only those which are forwarded from the specified chat ID(s) + or username(s) based on :attr:`telegram.Message.forward_from` and + :attr:`telegram.Message.forward_from_chat`. + + .. versionadded:: 13.5 + + Examples: + ``MessageHandler(Filters.forwarded_from(chat_id=1234), callback_method)`` + + Note: + When a user has disallowed adding a link to their account while forwarding their + messages, this filter will *not* work since both + :attr:`telegram.Message.forwarded_from` and + :attr:`telegram.Message.forwarded_from_chat` are :obj:`None`. However, this behaviour + is undocumented and might be changed by Telegram. + + Warning: + :attr:`chat_ids` will give a *copy* of the saved chat ids as :class:`frozenset`. This + is to ensure thread safety. To add/remove a chat, you should use :meth:`add_usernames`, + :meth:`add_chat_ids`, :meth:`remove_usernames` and :meth:`remove_chat_ids`. Only update + the entire set by ``filter.chat_ids/usernames = new_set``, if you are entirely sure + that it is not causing race conditions, as this will complete replace the current set + of allowed chats. + + Args: + chat_id(:class:`telegram.utils.types.SLT[int]`, optional): + Which chat/user ID(s) to allow through. + username(:class:`telegram.utils.types.SLT[str]`, optional): + Which username(s) to allow through. Leading ``'@'`` s in usernames will be + discarded. + allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no chat + is specified in :attr:`chat_ids` and :attr:`usernames`. Defaults to :obj:`False`. + + Raises: + RuntimeError: If both chat_id and username are present. + + Attributes: + chat_ids(set(:obj:`int`), optional): Which chat/user ID(s) to allow through. + usernames(set(:obj:`str`), optional): Which username(s) (without leading ``'@'``) to + allow through. + allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no chat + is specified in :attr:`chat_ids` and :attr:`usernames`. + """ + + __slots__ = () + + def get_chat_or_user(self, message: Message) -> Union[User, Chat, None]: + return message.forward_from or message.forward_from_chat + + def add_usernames(self, username: SLT[str]) -> None: + """ + Add one or more chats to the allowed usernames. + + Args: + username(:class:`telegram.utils.types.SLT[str]`, optional): + Which username(s) to allow through. + Leading ``'@'`` s in usernames will be discarded. + """ + return super().add_usernames(username) + + def add_chat_ids(self, chat_id: SLT[int]) -> None: + """ + Add one or more chats to the allowed chat ids. + + Args: + chat_id(:class:`telegram.utils.types.SLT[int]`, optional): + Which chat/user ID(s) to allow through. + """ + return super().add_chat_ids(chat_id) + + def remove_usernames(self, username: SLT[str]) -> None: + """ + Remove one or more chats from allowed usernames. + + Args: + username(:class:`telegram.utils.types.SLT[str]`, optional): + Which username(s) to disallow through. + Leading ``'@'`` s in usernames will be discarded. + """ + return super().remove_usernames(username) + + def remove_chat_ids(self, chat_id: SLT[int]) -> None: + """ + Remove one or more chats from allowed chat ids. + + Args: + chat_id(:class:`telegram.utils.types.SLT[int]`, optional): + Which chat/user ID(s) to disallow through. + """ + return super().remove_chat_ids(chat_id) + + class sender_chat(_ChatUserBaseFilter): + # pylint: disable=W0235 + """Filters messages to allow only those which are from a specified sender chats chat ID or + username. + + Examples: + * To filter for messages forwarded to a discussion group from a channel with ID + ``-1234``, use ``MessageHandler(Filters.sender_chat(-1234), callback_method)``. + * To filter for messages of anonymous admins in a super group with username + ``@anonymous``, use + ``MessageHandler(Filters.sender_chat(username='anonymous'), callback_method)``. + * To filter for messages forwarded to a discussion group from *any* channel, use + ``MessageHandler(Filters.sender_chat.channel, callback_method)``. + * To filter for messages of anonymous admins in *any* super group, use + ``MessageHandler(Filters.sender_chat.super_group, callback_method)``. + + Note: + Remember, ``sender_chat`` is also set for messages in a channel as the channel itself, + so when your bot is an admin in a channel and the linked discussion group, you would + receive the message twice (once from inside the channel, once inside the discussion + group). + + Warning: + :attr:`chat_ids` will return a *copy* of the saved chat ids as :class:`frozenset`. This + is to ensure thread safety. To add/remove a chat, you should use :meth:`add_usernames`, + :meth:`add_chat_ids`, :meth:`remove_usernames` and :meth:`remove_chat_ids`. Only update + the entire set by ``filter.chat_ids/usernames = new_set``, if you are entirely sure + that it is not causing race conditions, as this will complete replace the current set + of allowed chats. + + Args: + chat_id(:class:`telegram.utils.types.SLT[int]`, optional): + Which sender chat chat ID(s) to allow through. + username(:class:`telegram.utils.types.SLT[str]`, optional): + Which sender chat username(s) to allow through. + Leading ``'@'`` s in usernames will be discarded. + allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no sender + chat is specified in :attr:`chat_ids` and :attr:`usernames`. Defaults to + :obj:`False` + + Raises: + RuntimeError: If both chat_id and username are present. + + Attributes: + chat_ids(set(:obj:`int`), optional): Which sender chat chat ID(s) to allow through. + usernames(set(:obj:`str`), optional): Which sender chat username(s) (without leading + ``'@'``) to allow through. + allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no sender + chat is specified in :attr:`chat_ids` and :attr:`usernames`. + super_group: Messages whose sender chat is a super group. + + Examples: + ``Filters.sender_chat.supergroup`` + channel: Messages whose sender chat is a channel. + + Examples: + ``Filters.sender_chat.channel`` + + """ + + __slots__ = () + + def get_chat_or_user(self, message: Message) -> Optional[Chat]: + return message.sender_chat + + def add_usernames(self, username: SLT[str]) -> None: + """ + Add one or more sender chats to the allowed usernames. + + Args: + username(:class:`telegram.utils.types.SLT[str]`, optional): + Which sender chat username(s) to allow through. + Leading ``'@'`` s in usernames will be discarded. + """ + return super().add_usernames(username) + + def add_chat_ids(self, chat_id: SLT[int]) -> None: + """ + Add one or more sender chats to the allowed chat ids. + + Args: + chat_id(:class:`telegram.utils.types.SLT[int]`, optional): + Which sender chat ID(s) to allow through. + """ + return super().add_chat_ids(chat_id) + + def remove_usernames(self, username: SLT[str]) -> None: + """ + Remove one or more sender chats from allowed usernames. + + Args: + username(:class:`telegram.utils.types.SLT[str]`, optional): + Which sender chat username(s) to disallow through. + Leading ``'@'`` s in usernames will be discarded. + """ + return super().remove_usernames(username) + + def remove_chat_ids(self, chat_id: SLT[int]) -> None: + """ + Remove one or more sender chats from allowed chat ids. + + Args: + chat_id(:class:`telegram.utils.types.SLT[int]`, optional): + Which sender chat ID(s) to disallow through. + """ + return super().remove_chat_ids(chat_id) + + class _SuperGroup(MessageFilter): + __slots__ = () + + def filter(self, message: Message) -> bool: + if message.sender_chat: + return message.sender_chat.type == Chat.SUPERGROUP + return False + + class _Channel(MessageFilter): + __slots__ = () + + def filter(self, message: Message) -> bool: + if message.sender_chat: + return message.sender_chat.type == Chat.CHANNEL + return False + + super_group = _SuperGroup() + channel = _Channel() + + class _Invoice(MessageFilter): + __slots__ = () + name = 'Filters.invoice' + + def filter(self, message: Message) -> bool: + return bool(message.invoice) + + invoice = _Invoice() + """Messages that contain :class:`telegram.Invoice`.""" + + class _SuccessfulPayment(MessageFilter): + __slots__ = () + name = 'Filters.successful_payment' + + def filter(self, message: Message) -> bool: + return bool(message.successful_payment) + + successful_payment = _SuccessfulPayment() + """Messages that confirm a :class:`telegram.SuccessfulPayment`.""" + + class _PassportData(MessageFilter): + __slots__ = () + name = 'Filters.passport_data' + + def filter(self, message: Message) -> bool: + return bool(message.passport_data) + + passport_data = _PassportData() + """Messages that contain a :class:`telegram.PassportData`""" + + class _Poll(MessageFilter): + __slots__ = () + name = 'Filters.poll' + + def filter(self, message: Message) -> bool: + return bool(message.poll) + + poll = _Poll() + """Messages that contain a :class:`telegram.Poll`.""" + + class _Dice(_DiceEmoji): + __slots__ = () + dice = _DiceEmoji('🎲', 'dice') + darts = _DiceEmoji('🎯', 'darts') + basketball = _DiceEmoji('🏀', 'basketball') + football = _DiceEmoji('⚽') + slot_machine = _DiceEmoji('🎰') + bowling = _DiceEmoji('🎳', 'bowling') + + dice = _Dice() + """Dice Messages. If an integer or a list of integers is passed, it filters messages to only + allow those whose dice value is appearing in the given list. + + Examples: + To allow any dice message, simply use + ``MessageHandler(Filters.dice, callback_method)``. + + To allow only dice messages with the emoji 🎲, but any value, use + ``MessageHandler(Filters.dice.dice, callback_method)``. + + To allow only dice messages with the emoji 🎯 and with value 6, use + ``MessageHandler(Filters.dice.darts(6), callback_method)``. + + To allow only dice messages with the emoji ⚽ and with value 5 `or` 6, use + ``MessageHandler(Filters.dice.football([5, 6]), callback_method)``. + + Note: + Dice messages don't have text. If you want to filter either text or dice messages, use + ``Filters.text | Filters.dice``. + + Args: + update (:class:`telegram.utils.types.SLT[int]`, optional): + Which values to allow. If not specified, will allow any dice message. + + Attributes: + dice: Dice messages with the emoji 🎲. Passing a list of integers is supported just as for + :attr:`Filters.dice`. + darts: Dice messages with the emoji 🎯. Passing a list of integers is supported just as for + :attr:`Filters.dice`. + basketball: Dice messages with the emoji 🏀. Passing a list of integers is supported just + as for :attr:`Filters.dice`. + football: Dice messages with the emoji ⚽. Passing a list of integers is supported just + as for :attr:`Filters.dice`. + slot_machine: Dice messages with the emoji 🎰. Passing a list of integers is supported just + as for :attr:`Filters.dice`. + bowling: Dice messages with the emoji 🎳. Passing a list of integers is supported just + as for :attr:`Filters.dice`. + + .. versionadded:: 13.4 + + """ + + class language(MessageFilter): + """Filters messages to only allow those which are from users with a certain language code. + + Note: + According to official Telegram API documentation, not every single user has the + `language_code` attribute. Do not count on this filter working on all users. + + Examples: + ``MessageHandler(Filters.language("en"), callback_method)`` + + Args: + lang (:class:`telegram.utils.types.SLT[str]`): + Which language code(s) to allow through. + This will be matched using ``.startswith`` meaning that + 'en' will match both 'en_US' and 'en_GB'. + + """ + + __slots__ = ('lang',) + + def __init__(self, lang: SLT[str]): + if isinstance(lang, str): + lang = cast(str, lang) + self.lang = [lang] + else: + lang = cast(List[str], lang) + self.lang = lang + self.name = f'Filters.language({self.lang})' + + def filter(self, message: Message) -> bool: + """""" # remove method from docs + return bool( + message.from_user.language_code + and any(message.from_user.language_code.startswith(x) for x in self.lang) + ) + + class _Attachment(MessageFilter): + __slots__ = () + + name = 'Filters.attachment' + + def filter(self, message: Message) -> bool: + return bool(message.effective_attachment) + + attachment = _Attachment() + """Messages that contain :meth:`telegram.Message.effective_attachment`. + + + .. versionadded:: 13.6""" + + class _UpdateType(UpdateFilter): + __slots__ = () + name = 'Filters.update' + + class _Message(UpdateFilter): + __slots__ = () + name = 'Filters.update.message' + + def filter(self, update: Update) -> bool: + return update.message is not None + + message = _Message() + + class _EditedMessage(UpdateFilter): + __slots__ = () + name = 'Filters.update.edited_message' + + def filter(self, update: Update) -> bool: + return update.edited_message is not None + + edited_message = _EditedMessage() + + class _Messages(UpdateFilter): + __slots__ = () + name = 'Filters.update.messages' + + def filter(self, update: Update) -> bool: + return update.message is not None or update.edited_message is not None + + messages = _Messages() + + class _ChannelPost(UpdateFilter): + __slots__ = () + name = 'Filters.update.channel_post' + + def filter(self, update: Update) -> bool: + return update.channel_post is not None + + channel_post = _ChannelPost() + + class _EditedChannelPost(UpdateFilter): + __slots__ = () + name = 'Filters.update.edited_channel_post' + + def filter(self, update: Update) -> bool: + return update.edited_channel_post is not None + + edited_channel_post = _EditedChannelPost() + + class _ChannelPosts(UpdateFilter): + __slots__ = () + name = 'Filters.update.channel_posts' + + def filter(self, update: Update) -> bool: + return update.channel_post is not None or update.edited_channel_post is not None + + channel_posts = _ChannelPosts() + + def filter(self, update: Update) -> bool: + return bool(self.messages(update) or self.channel_posts(update)) + + update = _UpdateType() + """Subset for filtering the type of update. + + Examples: + Use these filters like: ``Filters.update.message`` or + ``Filters.update.channel_posts`` etc. Or use just ``Filters.update`` for all + types. + + Attributes: + message: Updates with :attr:`telegram.Update.message` + edited_message: Updates with :attr:`telegram.Update.edited_message` + messages: Updates with either :attr:`telegram.Update.message` or + :attr:`telegram.Update.edited_message` + channel_post: Updates with :attr:`telegram.Update.channel_post` + edited_channel_post: Updates with + :attr:`telegram.Update.edited_channel_post` + channel_posts: Updates with either :attr:`telegram.Update.channel_post` or + :attr:`telegram.Update.edited_channel_post` + """ diff --git a/venv/lib/python3.8/site-packages/telegram/ext/handler.py b/venv/lib/python3.8/site-packages/telegram/ext/handler.py new file mode 100644 index 0000000..befaf41 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/ext/handler.py @@ -0,0 +1,260 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the base class for handlers as used by the Dispatcher.""" +from abc import ABC, abstractmethod +from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, TypeVar, Union, Generic +from sys import version_info as py_ver + +from telegram.utils.deprecate import set_new_attribute_deprecated + +from telegram import Update +from telegram.ext.utils.promise import Promise +from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE +from telegram.ext.utils.types import CCT + +if TYPE_CHECKING: + from telegram.ext import Dispatcher + +RT = TypeVar('RT') +UT = TypeVar('UT') + + +class Handler(Generic[UT, CCT], ABC): + """The base class for all update handlers. Create custom handlers by inheriting from it. + + Note: + :attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you + can use to keep any data in will be sent to the :attr:`callback` function. Related to + either the user or the chat that the update was sent in. For each update from the same user + or in the same chat, it will be the same ``dict``. + + Note that this is DEPRECATED, and you should use context based callbacks. See + https://git.io/fxJuV for more info. + + Warning: + When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom + attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. + + Args: + callback (:obj:`callable`): The callback function for this handler. Will be called when + :attr:`check_update` has determined that an update should be processed by this handler. + Callback signature for context based API: + + ``def callback(update: Update, context: CallbackContext)`` + + The return value of the callback is usually ignored except for the special case of + :class:`telegram.ext.ConversationHandler`. + pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``update_queue`` will be passed to the callback function. It will be the ``Queue`` + instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher` + that contains new updates which can be used to insert updates. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``job_queue`` will be passed to the callback function. It will be a + :class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater` + which can be used to schedule new jobs. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``user_data`` will be passed to the callback function. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``chat_data`` will be passed to the callback function. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + run_async (:obj:`bool`): Determines whether the callback will run asynchronously. + Defaults to :obj:`False`. + + Attributes: + callback (:obj:`callable`): The callback function for this handler. + pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be + passed to the callback function. + pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to + the callback function. + pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to + the callback function. + pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to + the callback function. + run_async (:obj:`bool`): Determines whether the callback will run asynchronously. + + """ + + # Apparently Py 3.7 and below have '__dict__' in ABC + if py_ver < (3, 7): + __slots__ = ( + 'callback', + 'pass_update_queue', + 'pass_job_queue', + 'pass_user_data', + 'pass_chat_data', + 'run_async', + ) + else: + __slots__ = ( + 'callback', # type: ignore[assignment] + 'pass_update_queue', + 'pass_job_queue', + 'pass_user_data', + 'pass_chat_data', + 'run_async', + '__dict__', + ) + + def __init__( + self, + callback: Callable[[UT, CCT], RT], + pass_update_queue: bool = False, + pass_job_queue: bool = False, + pass_user_data: bool = False, + pass_chat_data: bool = False, + run_async: Union[bool, DefaultValue] = DEFAULT_FALSE, + ): + self.callback = callback + self.pass_update_queue = pass_update_queue + self.pass_job_queue = pass_job_queue + self.pass_user_data = pass_user_data + self.pass_chat_data = pass_chat_data + self.run_async = run_async + + def __setattr__(self, key: str, value: object) -> None: + # See comment on BaseFilter to know why this was done. + if key.startswith('__'): + key = f"_{self.__class__.__name__}{key}" + if issubclass(self.__class__, Handler) and not self.__class__.__module__.startswith( + 'telegram.ext.' + ): + object.__setattr__(self, key, value) + return + set_new_attribute_deprecated(self, key, value) + + @abstractmethod + def check_update(self, update: object) -> Optional[Union[bool, object]]: + """ + This method is called to determine if an update should be handled by + this handler instance. It should always be overridden. + + Note: + Custom updates types can be handled by the dispatcher. Therefore, an implementation of + this method should always check the type of :attr:`update`. + + Args: + update (:obj:`str` | :class:`telegram.Update`): The update to be tested. + + Returns: + Either :obj:`None` or :obj:`False` if the update should not be handled. Otherwise an + object that will be passed to :meth:`handle_update` and + :meth:`collect_additional_context` when the update gets handled. + + """ + + def handle_update( + self, + update: UT, + dispatcher: 'Dispatcher', + check_result: object, + context: CCT = None, + ) -> Union[RT, Promise]: + """ + This method is called if it was determined that an update should indeed + be handled by this instance. Calls :attr:`callback` along with its respectful + arguments. To work with the :class:`telegram.ext.ConversationHandler`, this method + returns the value returned from :attr:`callback`. + Note that it can be overridden if needed by the subclassing handler. + + Args: + update (:obj:`str` | :class:`telegram.Update`): The update to be handled. + dispatcher (:class:`telegram.ext.Dispatcher`): The calling dispatcher. + check_result (:obj:`obj`): The result from :attr:`check_update`. + context (:class:`telegram.ext.CallbackContext`, optional): The context as provided by + the dispatcher. + + """ + run_async = self.run_async + if ( + self.run_async is DEFAULT_FALSE + and dispatcher.bot.defaults + and dispatcher.bot.defaults.run_async + ): + run_async = True + + if context: + self.collect_additional_context(context, update, dispatcher, check_result) + if run_async: + return dispatcher.run_async(self.callback, update, context, update=update) + return self.callback(update, context) + + optional_args = self.collect_optional_args(dispatcher, update, check_result) + if run_async: + return dispatcher.run_async( + self.callback, dispatcher.bot, update, update=update, **optional_args + ) + return self.callback(dispatcher.bot, update, **optional_args) # type: ignore + + def collect_additional_context( + self, + context: CCT, + update: UT, + dispatcher: 'Dispatcher', + check_result: Any, + ) -> None: + """Prepares additional arguments for the context. Override if needed. + + Args: + context (:class:`telegram.ext.CallbackContext`): The context object. + update (:class:`telegram.Update`): The update to gather chat/user id from. + dispatcher (:class:`telegram.ext.Dispatcher`): The calling dispatcher. + check_result: The result (return value) from :attr:`check_update`. + + """ + + def collect_optional_args( + self, + dispatcher: 'Dispatcher', + update: UT = None, + check_result: Any = None, # pylint: disable=W0613 + ) -> Dict[str, object]: + """ + Prepares the optional arguments. If the handler has additional optional args, + it should subclass this method, but remember to call this super method. + + DEPRECATED: This method is being replaced by new context based callbacks. Please see + https://git.io/fxJuV for more info. + + Args: + dispatcher (:class:`telegram.ext.Dispatcher`): The dispatcher. + update (:class:`telegram.Update`): The update to gather chat/user id from. + check_result: The result from check_update + + """ + optional_args: Dict[str, object] = {} + + if self.pass_update_queue: + optional_args['update_queue'] = dispatcher.update_queue + if self.pass_job_queue: + optional_args['job_queue'] = dispatcher.job_queue + if self.pass_user_data and isinstance(update, Update): + user = update.effective_user + optional_args['user_data'] = dispatcher.user_data[ + user.id if user else None # type: ignore[index] + ] + if self.pass_chat_data and isinstance(update, Update): + chat = update.effective_chat + optional_args['chat_data'] = dispatcher.chat_data[ + chat.id if chat else None # type: ignore[index] + ] + + return optional_args diff --git a/venv/lib/python3.8/site-packages/telegram/ext/inlinequeryhandler.py b/venv/lib/python3.8/site-packages/telegram/ext/inlinequeryhandler.py new file mode 100644 index 0000000..11103e7 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/ext/inlinequeryhandler.py @@ -0,0 +1,221 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the InlineQueryHandler class.""" +import re +from typing import ( + TYPE_CHECKING, + Callable, + Dict, + Match, + Optional, + Pattern, + TypeVar, + Union, + cast, + List, +) + +from telegram import Update +from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE + +from .handler import Handler +from .utils.types import CCT + +if TYPE_CHECKING: + from telegram.ext import Dispatcher + +RT = TypeVar('RT') + + +class InlineQueryHandler(Handler[Update, CCT]): + """ + Handler class to handle Telegram inline queries. Optionally based on a regex. Read the + documentation of the ``re`` module for more information. + + Note: + :attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you + can use to keep any data in will be sent to the :attr:`callback` function. Related to + either the user or the chat that the update was sent in. For each update from the same user + or in the same chat, it will be the same ``dict``. + + Note that this is DEPRECATED, and you should use context based callbacks. See + https://git.io/fxJuV for more info. + + Warning: + * When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom + attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. + * :attr:`telegram.InlineQuery.chat_type` will not be set for inline queries from secret + chats and may not be set for inline queries coming from third-party clients. These + updates won't be handled, if :attr:`chat_types` is passed. + + Args: + callback (:obj:`callable`): The callback function for this handler. Will be called when + :attr:`check_update` has determined that an update should be processed by this handler. + Callback signature for context based API: + + ``def callback(update: Update, context: CallbackContext)`` + + The return value of the callback is usually ignored except for the special case of + :class:`telegram.ext.ConversationHandler`. + pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``update_queue`` will be passed to the callback function. It will be the ``Queue`` + instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher` + that contains new updates which can be used to insert updates. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``job_queue`` will be passed to the callback function. It will be a + :class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater` + which can be used to schedule new jobs. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + pattern (:obj:`str` | :obj:`Pattern`, optional): Regex pattern. If not :obj:`None`, + ``re.match`` is used on :attr:`telegram.InlineQuery.query` to determine if an update + should be handled by this handler. + chat_types (List[:obj:`str`], optional): List of allowed chat types. If passed, will only + handle inline queries with the appropriate :attr:`telegram.InlineQuery.chat_type`. + + .. versionadded:: 13.5 + pass_groups (:obj:`bool`, optional): If the callback should be passed the result of + ``re.match(pattern, data).groups()`` as a keyword argument called ``groups``. + Default is :obj:`False` + DEPRECATED: Please switch to context based callbacks. + pass_groupdict (:obj:`bool`, optional): If the callback should be passed the result of + ``re.match(pattern, data).groupdict()`` as a keyword argument called ``groupdict``. + Default is :obj:`False` + DEPRECATED: Please switch to context based callbacks. + pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``user_data`` will be passed to the callback function. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``chat_data`` will be passed to the callback function. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + run_async (:obj:`bool`): Determines whether the callback will run asynchronously. + Defaults to :obj:`False`. + + Attributes: + callback (:obj:`callable`): The callback function for this handler. + pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be + passed to the callback function. + pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to + the callback function. + pattern (:obj:`str` | :obj:`Pattern`): Optional. Regex pattern to test + :attr:`telegram.InlineQuery.query` against. + chat_types (List[:obj:`str`], optional): List of allowed chat types. + + .. versionadded:: 13.5 + pass_groups (:obj:`bool`): Determines whether ``groups`` will be passed to the + callback function. + pass_groupdict (:obj:`bool`): Determines whether ``groupdict``. will be passed to + the callback function. + pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to + the callback function. + pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to + the callback function. + run_async (:obj:`bool`): Determines whether the callback will run asynchronously. + + """ + + __slots__ = ('pattern', 'chat_types', 'pass_groups', 'pass_groupdict') + + def __init__( + self, + callback: Callable[[Update, CCT], RT], + pass_update_queue: bool = False, + pass_job_queue: bool = False, + pattern: Union[str, Pattern] = None, + pass_groups: bool = False, + pass_groupdict: bool = False, + pass_user_data: bool = False, + pass_chat_data: bool = False, + run_async: Union[bool, DefaultValue] = DEFAULT_FALSE, + chat_types: List[str] = None, + ): + super().__init__( + callback, + pass_update_queue=pass_update_queue, + pass_job_queue=pass_job_queue, + pass_user_data=pass_user_data, + pass_chat_data=pass_chat_data, + run_async=run_async, + ) + + if isinstance(pattern, str): + pattern = re.compile(pattern) + + self.pattern = pattern + self.chat_types = chat_types + self.pass_groups = pass_groups + self.pass_groupdict = pass_groupdict + + def check_update(self, update: object) -> Optional[Union[bool, Match]]: + """ + Determines whether an update should be passed to this handlers :attr:`callback`. + + Args: + update (:class:`telegram.Update` | :obj:`object`): Incoming update. + + Returns: + :obj:`bool` + + """ + if isinstance(update, Update) and update.inline_query: + if (self.chat_types is not None) and ( + update.inline_query.chat_type not in self.chat_types + ): + return False + if self.pattern: + if update.inline_query.query: + match = re.match(self.pattern, update.inline_query.query) + if match: + return match + else: + return True + return None + + def collect_optional_args( + self, + dispatcher: 'Dispatcher', + update: Update = None, + check_result: Optional[Union[bool, Match]] = None, + ) -> Dict[str, object]: + """Pass the results of ``re.match(pattern, query).{groups(), groupdict()}`` to the + callback as a keyword arguments called ``groups`` and ``groupdict``, respectively, if + needed. + """ + optional_args = super().collect_optional_args(dispatcher, update, check_result) + if self.pattern: + check_result = cast(Match, check_result) + if self.pass_groups: + optional_args['groups'] = check_result.groups() + if self.pass_groupdict: + optional_args['groupdict'] = check_result.groupdict() + return optional_args + + def collect_additional_context( + self, + context: CCT, + update: Update, + dispatcher: 'Dispatcher', + check_result: Optional[Union[bool, Match]], + ) -> None: + """Add the result of ``re.match(pattern, update.inline_query.query)`` to + :attr:`CallbackContext.matches` as list with one element. + """ + if self.pattern: + check_result = cast(Match, check_result) + context.matches = [check_result] diff --git a/venv/lib/python3.8/site-packages/telegram/ext/jobqueue.py b/venv/lib/python3.8/site-packages/telegram/ext/jobqueue.py new file mode 100644 index 0000000..a6e8e1a --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/ext/jobqueue.py @@ -0,0 +1,656 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the classes JobQueue and Job.""" + +import datetime +import logging +from typing import TYPE_CHECKING, Callable, List, Optional, Tuple, Union, cast, overload + +import pytz +from apscheduler.events import EVENT_JOB_ERROR, EVENT_JOB_EXECUTED, JobEvent +from apscheduler.schedulers.background import BackgroundScheduler +from apscheduler.triggers.combining import OrTrigger +from apscheduler.triggers.cron import CronTrigger +from apscheduler.job import Job as APSJob + +from telegram.ext.callbackcontext import CallbackContext +from telegram.utils.types import JSONDict +from telegram.utils.deprecate import set_new_attribute_deprecated + +if TYPE_CHECKING: + from telegram import Bot + from telegram.ext import Dispatcher + import apscheduler.job # noqa: F401 + + +class JobQueue: + """This class allows you to periodically perform tasks with the bot. It is a convenience + wrapper for the APScheduler library. + + Attributes: + scheduler (:class:`apscheduler.schedulers.background.BackgroundScheduler`): The APScheduler + bot (:class:`telegram.Bot`): The bot instance that should be passed to the jobs. + DEPRECATED: Use :attr:`set_dispatcher` instead. + + """ + + __slots__ = ('_dispatcher', 'logger', 'scheduler', '__dict__') + + def __init__(self) -> None: + self._dispatcher: 'Dispatcher' = None # type: ignore[assignment] + self.logger = logging.getLogger(self.__class__.__name__) + self.scheduler = BackgroundScheduler(timezone=pytz.utc) + self.scheduler.add_listener( + self._update_persistence, mask=EVENT_JOB_EXECUTED | EVENT_JOB_ERROR + ) + + # Dispatch errors and don't log them in the APS logger + def aps_log_filter(record): # type: ignore + return 'raised an exception' not in record.msg + + logging.getLogger('apscheduler.executors.default').addFilter(aps_log_filter) + self.scheduler.add_listener(self._dispatch_error, EVENT_JOB_ERROR) + + def __setattr__(self, key: str, value: object) -> None: + set_new_attribute_deprecated(self, key, value) + + def _build_args(self, job: 'Job') -> List[Union[CallbackContext, 'Bot', 'Job']]: + if self._dispatcher.use_context: + return [self._dispatcher.context_types.context.from_job(job, self._dispatcher)] + return [self._dispatcher.bot, job] + + def _tz_now(self) -> datetime.datetime: + return datetime.datetime.now(self.scheduler.timezone) + + def _update_persistence(self, _: JobEvent) -> None: + self._dispatcher.update_persistence() + + def _dispatch_error(self, event: JobEvent) -> None: + try: + self._dispatcher.dispatch_error(None, event.exception) + # Errors should not stop the thread. + except Exception: + self.logger.exception( + 'An error was raised while processing the job and an ' + 'uncaught error was raised while handling the error ' + 'with an error_handler.' + ) + + @overload + def _parse_time_input(self, time: None, shift_day: bool = False) -> None: + ... + + @overload + def _parse_time_input( + self, + time: Union[float, int, datetime.timedelta, datetime.datetime, datetime.time], + shift_day: bool = False, + ) -> datetime.datetime: + ... + + def _parse_time_input( + self, + time: Union[float, int, datetime.timedelta, datetime.datetime, datetime.time, None], + shift_day: bool = False, + ) -> Optional[datetime.datetime]: + if time is None: + return None + if isinstance(time, (int, float)): + return self._tz_now() + datetime.timedelta(seconds=time) + if isinstance(time, datetime.timedelta): + return self._tz_now() + time + if isinstance(time, datetime.time): + date_time = datetime.datetime.combine( + datetime.datetime.now(tz=time.tzinfo or self.scheduler.timezone).date(), time + ) + if date_time.tzinfo is None: + date_time = self.scheduler.timezone.localize(date_time) + if shift_day and date_time <= datetime.datetime.now(pytz.utc): + date_time += datetime.timedelta(days=1) + return date_time + # isinstance(time, datetime.datetime): + return time + + def set_dispatcher(self, dispatcher: 'Dispatcher') -> None: + """Set the dispatcher to be used by this JobQueue. Use this instead of passing a + :class:`telegram.Bot` to the JobQueue, which is deprecated. + + Args: + dispatcher (:class:`telegram.ext.Dispatcher`): The dispatcher. + + """ + self._dispatcher = dispatcher + if dispatcher.bot.defaults: + self.scheduler.configure(timezone=dispatcher.bot.defaults.tzinfo or pytz.utc) + + def run_once( + self, + callback: Callable[['CallbackContext'], None], + when: Union[float, datetime.timedelta, datetime.datetime, datetime.time], + context: object = None, + name: str = None, + job_kwargs: JSONDict = None, + ) -> 'Job': + """Creates a new ``Job`` that runs once and adds it to the queue. + + Args: + callback (:obj:`callable`): The callback function that should be executed by the new + job. Callback signature for context based API: + + ``def callback(CallbackContext)`` + + ``context.job`` is the :class:`telegram.ext.Job` instance. It can be used to access + its ``job.context`` or change it to a repeating job. + when (:obj:`int` | :obj:`float` | :obj:`datetime.timedelta` | \ + :obj:`datetime.datetime` | :obj:`datetime.time`): + Time in or at which the job should run. This parameter will be interpreted + depending on its type. + + * :obj:`int` or :obj:`float` will be interpreted as "seconds from now" in which the + job should run. + * :obj:`datetime.timedelta` will be interpreted as "time from now" in which the + job should run. + * :obj:`datetime.datetime` will be interpreted as a specific date and time at + which the job should run. If the timezone (``datetime.tzinfo``) is :obj:`None`, + the default timezone of the bot will be used. + * :obj:`datetime.time` will be interpreted as a specific time of day at which the + job should run. This could be either today or, if the time has already passed, + tomorrow. If the timezone (``time.tzinfo``) is :obj:`None`, the + default timezone of the bot will be used. + + context (:obj:`object`, optional): Additional data needed for the callback function. + Can be accessed through ``job.context`` in the callback. Defaults to :obj:`None`. + name (:obj:`str`, optional): The name of the new job. Defaults to + ``callback.__name__``. + job_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to pass to the + ``scheduler.add_job()``. + + Returns: + :class:`telegram.ext.Job`: The new ``Job`` instance that has been added to the job + queue. + + """ + if not job_kwargs: + job_kwargs = {} + + name = name or callback.__name__ + job = Job(callback, context, name, self) + date_time = self._parse_time_input(when, shift_day=True) + + j = self.scheduler.add_job( + callback, + name=name, + trigger='date', + run_date=date_time, + args=self._build_args(job), + timezone=date_time.tzinfo or self.scheduler.timezone, + **job_kwargs, + ) + + job.job = j + return job + + def run_repeating( + self, + callback: Callable[['CallbackContext'], None], + interval: Union[float, datetime.timedelta], + first: Union[float, datetime.timedelta, datetime.datetime, datetime.time] = None, + last: Union[float, datetime.timedelta, datetime.datetime, datetime.time] = None, + context: object = None, + name: str = None, + job_kwargs: JSONDict = None, + ) -> 'Job': + """Creates a new ``Job`` that runs at specified intervals and adds it to the queue. + + Note: + For a note about DST, please see the documentation of `APScheduler`_. + + .. _`APScheduler`: https://apscheduler.readthedocs.io/en/stable/modules/triggers/cron.html + #daylight-saving-time-behavior + + Args: + callback (:obj:`callable`): The callback function that should be executed by the new + job. Callback signature for context based API: + + ``def callback(CallbackContext)`` + + ``context.job`` is the :class:`telegram.ext.Job` instance. It can be used to access + its ``job.context`` or change it to a repeating job. + interval (:obj:`int` | :obj:`float` | :obj:`datetime.timedelta`): The interval in which + the job will run. If it is an :obj:`int` or a :obj:`float`, it will be interpreted + as seconds. + first (:obj:`int` | :obj:`float` | :obj:`datetime.timedelta` | \ + :obj:`datetime.datetime` | :obj:`datetime.time`, optional): + Time in or at which the job should run. This parameter will be interpreted + depending on its type. + + * :obj:`int` or :obj:`float` will be interpreted as "seconds from now" in which the + job should run. + * :obj:`datetime.timedelta` will be interpreted as "time from now" in which the + job should run. + * :obj:`datetime.datetime` will be interpreted as a specific date and time at + which the job should run. If the timezone (``datetime.tzinfo``) is :obj:`None`, + the default timezone of the bot will be used. + * :obj:`datetime.time` will be interpreted as a specific time of day at which the + job should run. This could be either today or, if the time has already passed, + tomorrow. If the timezone (``time.tzinfo``) is :obj:`None`, the + default timezone of the bot will be used. + + Defaults to ``interval`` + last (:obj:`int` | :obj:`float` | :obj:`datetime.timedelta` | \ + :obj:`datetime.datetime` | :obj:`datetime.time`, optional): + Latest possible time for the job to run. This parameter will be interpreted + depending on its type. See ``first`` for details. + + If ``last`` is :obj:`datetime.datetime` or :obj:`datetime.time` type + and ``last.tzinfo`` is :obj:`None`, the default timezone of the bot will be + assumed. + + Defaults to :obj:`None`. + context (:obj:`object`, optional): Additional data needed for the callback function. + Can be accessed through ``job.context`` in the callback. Defaults to :obj:`None`. + name (:obj:`str`, optional): The name of the new job. Defaults to + ``callback.__name__``. + job_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to pass to the + ``scheduler.add_job()``. + + Returns: + :class:`telegram.ext.Job`: The new ``Job`` instance that has been added to the job + queue. + + """ + if not job_kwargs: + job_kwargs = {} + + name = name or callback.__name__ + job = Job(callback, context, name, self) + + dt_first = self._parse_time_input(first) + dt_last = self._parse_time_input(last) + + if dt_last and dt_first and dt_last < dt_first: + raise ValueError("'last' must not be before 'first'!") + + if isinstance(interval, datetime.timedelta): + interval = interval.total_seconds() + + j = self.scheduler.add_job( + callback, + trigger='interval', + args=self._build_args(job), + start_date=dt_first, + end_date=dt_last, + seconds=interval, + name=name, + **job_kwargs, + ) + + job.job = j + return job + + def run_monthly( + self, + callback: Callable[['CallbackContext'], None], + when: datetime.time, + day: int, + context: object = None, + name: str = None, + day_is_strict: bool = True, + job_kwargs: JSONDict = None, + ) -> 'Job': + """Creates a new ``Job`` that runs on a monthly basis and adds it to the queue. + + Args: + callback (:obj:`callable`): The callback function that should be executed by the new + job. Callback signature for context based API: + + ``def callback(CallbackContext)`` + + ``context.job`` is the :class:`telegram.ext.Job` instance. It can be used to access + its ``job.context`` or change it to a repeating job. + when (:obj:`datetime.time`): Time of day at which the job should run. If the timezone + (``when.tzinfo``) is :obj:`None`, the default timezone of the bot will be used. + day (:obj:`int`): Defines the day of the month whereby the job would run. It should + be within the range of 1 and 31, inclusive. + context (:obj:`object`, optional): Additional data needed for the callback function. + Can be accessed through ``job.context`` in the callback. Defaults to :obj:`None`. + name (:obj:`str`, optional): The name of the new job. Defaults to + ``callback.__name__``. + day_is_strict (:obj:`bool`, optional): If :obj:`False` and day > month.days, will pick + the last day in the month. Defaults to :obj:`True`. + job_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to pass to the + ``scheduler.add_job()``. + + Returns: + :class:`telegram.ext.Job`: The new ``Job`` instance that has been added to the job + queue. + + """ + if not job_kwargs: + job_kwargs = {} + + name = name or callback.__name__ + job = Job(callback, context, name, self) + + if day_is_strict: + j = self.scheduler.add_job( + callback, + trigger='cron', + args=self._build_args(job), + name=name, + day=day, + hour=when.hour, + minute=when.minute, + second=when.second, + timezone=when.tzinfo or self.scheduler.timezone, + **job_kwargs, + ) + else: + trigger = OrTrigger( + [ + CronTrigger( + day=day, + hour=when.hour, + minute=when.minute, + second=when.second, + timezone=when.tzinfo, + **job_kwargs, + ), + CronTrigger( + day='last', + hour=when.hour, + minute=when.minute, + second=when.second, + timezone=when.tzinfo or self.scheduler.timezone, + **job_kwargs, + ), + ] + ) + j = self.scheduler.add_job( + callback, trigger=trigger, args=self._build_args(job), name=name, **job_kwargs + ) + + job.job = j + return job + + def run_daily( + self, + callback: Callable[['CallbackContext'], None], + time: datetime.time, + days: Tuple[int, ...] = tuple(range(7)), + context: object = None, + name: str = None, + job_kwargs: JSONDict = None, + ) -> 'Job': + """Creates a new ``Job`` that runs on a daily basis and adds it to the queue. + + Note: + For a note about DST, please see the documentation of `APScheduler`_. + + .. _`APScheduler`: https://apscheduler.readthedocs.io/en/stable/modules/triggers/cron.html + #daylight-saving-time-behavior + + Args: + callback (:obj:`callable`): The callback function that should be executed by the new + job. Callback signature for context based API: + + ``def callback(CallbackContext)`` + + ``context.job`` is the :class:`telegram.ext.Job` instance. It can be used to access + its ``job.context`` or change it to a repeating job. + time (:obj:`datetime.time`): Time of day at which the job should run. If the timezone + (``time.tzinfo``) is :obj:`None`, the default timezone of the bot will be used. + days (Tuple[:obj:`int`], optional): Defines on which days of the week the job should + run (where ``0-6`` correspond to monday - sunday). Defaults to ``EVERY_DAY`` + context (:obj:`object`, optional): Additional data needed for the callback function. + Can be accessed through ``job.context`` in the callback. Defaults to :obj:`None`. + name (:obj:`str`, optional): The name of the new job. Defaults to + ``callback.__name__``. + job_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to pass to the + ``scheduler.add_job()``. + + Returns: + :class:`telegram.ext.Job`: The new ``Job`` instance that has been added to the job + queue. + + """ + if not job_kwargs: + job_kwargs = {} + + name = name or callback.__name__ + job = Job(callback, context, name, self) + + j = self.scheduler.add_job( + callback, + name=name, + args=self._build_args(job), + trigger='cron', + day_of_week=','.join([str(d) for d in days]), + hour=time.hour, + minute=time.minute, + second=time.second, + timezone=time.tzinfo or self.scheduler.timezone, + **job_kwargs, + ) + + job.job = j + return job + + def run_custom( + self, + callback: Callable[['CallbackContext'], None], + job_kwargs: JSONDict, + context: object = None, + name: str = None, + ) -> 'Job': + """Creates a new customly defined ``Job``. + + Args: + callback (:obj:`callable`): The callback function that should be executed by the new + job. Callback signature for context based API: + + ``def callback(CallbackContext)`` + + ``context.job`` is the :class:`telegram.ext.Job` instance. It can be used to access + its ``job.context`` or change it to a repeating job. + job_kwargs (:obj:`dict`): Arbitrary keyword arguments. Used as arguments for + ``scheduler.add_job``. + context (:obj:`object`, optional): Additional data needed for the callback function. + Can be accessed through ``job.context`` in the callback. Defaults to ``None``. + name (:obj:`str`, optional): The name of the new job. Defaults to + ``callback.__name__``. + + Returns: + :class:`telegram.ext.Job`: The new ``Job`` instance that has been added to the job + queue. + + """ + name = name or callback.__name__ + job = Job(callback, context, name, self) + + j = self.scheduler.add_job(callback, args=self._build_args(job), name=name, **job_kwargs) + + job.job = j + return job + + def start(self) -> None: + """Starts the job_queue thread.""" + if not self.scheduler.running: + self.scheduler.start() + + def stop(self) -> None: + """Stops the thread.""" + if self.scheduler.running: + self.scheduler.shutdown() + + def jobs(self) -> Tuple['Job', ...]: + """Returns a tuple of all *scheduled* jobs that are currently in the ``JobQueue``.""" + return tuple( + Job._from_aps_job(job, self) # pylint: disable=W0212 + for job in self.scheduler.get_jobs() + ) + + def get_jobs_by_name(self, name: str) -> Tuple['Job', ...]: + """Returns a tuple of all *pending/scheduled* jobs with the given name that are currently + in the ``JobQueue``. + """ + return tuple(job for job in self.jobs() if job.name == name) + + +class Job: + """This class is a convenience wrapper for the jobs held in a :class:`telegram.ext.JobQueue`. + With the current backend APScheduler, :attr:`job` holds a :class:`apscheduler.job.Job` + instance. + + Note: + * All attributes and instance methods of :attr:`job` are also directly available as + attributes/methods of the corresponding :class:`telegram.ext.Job` object. + * Two instances of :class:`telegram.ext.Job` are considered equal, if their corresponding + ``job`` attributes have the same ``id``. + * If :attr:`job` isn't passed on initialization, it must be set manually afterwards for + this :class:`telegram.ext.Job` to be useful. + + Args: + callback (:obj:`callable`): The callback function that should be executed by the new job. + Callback signature for context based API: + + ``def callback(CallbackContext)`` + + a ``context.job`` is the :class:`telegram.ext.Job` instance. It can be used to access + its ``job.context`` or change it to a repeating job. + context (:obj:`object`, optional): Additional data needed for the callback function. Can be + accessed through ``job.context`` in the callback. Defaults to :obj:`None`. + name (:obj:`str`, optional): The name of the new job. Defaults to ``callback.__name__``. + job_queue (:class:`telegram.ext.JobQueue`, optional): The ``JobQueue`` this job belongs to. + Only optional for backward compatibility with ``JobQueue.put()``. + job (:class:`apscheduler.job.Job`, optional): The APS Job this job is a wrapper for. + + Attributes: + callback (:obj:`callable`): The callback function that should be executed by the new job. + context (:obj:`object`): Optional. Additional data needed for the callback function. + name (:obj:`str`): Optional. The name of the new job. + job_queue (:class:`telegram.ext.JobQueue`): Optional. The ``JobQueue`` this job belongs to. + job (:class:`apscheduler.job.Job`): Optional. The APS Job this job is a wrapper for. + """ + + __slots__ = ( + 'callback', + 'context', + 'name', + 'job_queue', + '_removed', + '_enabled', + 'job', + '__dict__', + ) + + def __init__( + self, + callback: Callable[['CallbackContext'], None], + context: object = None, + name: str = None, + job_queue: JobQueue = None, + job: APSJob = None, + ): + + self.callback = callback + self.context = context + self.name = name or callback.__name__ + self.job_queue = job_queue + + self._removed = False + self._enabled = False + + self.job = cast(APSJob, job) # skipcq: PTC-W0052 + + def __setattr__(self, key: str, value: object) -> None: + set_new_attribute_deprecated(self, key, value) + + def run(self, dispatcher: 'Dispatcher') -> None: + """Executes the callback function independently of the jobs schedule.""" + try: + if dispatcher.use_context: + self.callback(dispatcher.context_types.context.from_job(self, dispatcher)) + else: + self.callback(dispatcher.bot, self) # type: ignore[arg-type,call-arg] + except Exception as exc: + try: + dispatcher.dispatch_error(None, exc) + # Errors should not stop the thread. + except Exception: + dispatcher.logger.exception( + 'An error was raised while processing the job and an ' + 'uncaught error was raised while handling the error ' + 'with an error_handler.' + ) + + def schedule_removal(self) -> None: + """ + Schedules this job for removal from the ``JobQueue``. It will be removed without executing + its callback function again. + """ + self.job.remove() + self._removed = True + + @property + def removed(self) -> bool: + """:obj:`bool`: Whether this job is due to be removed.""" + return self._removed + + @property + def enabled(self) -> bool: + """:obj:`bool`: Whether this job is enabled.""" + return self._enabled + + @enabled.setter + def enabled(self, status: bool) -> None: + if status: + self.job.resume() + else: + self.job.pause() + self._enabled = status + + @property + def next_t(self) -> Optional[datetime.datetime]: + """ + :obj:`datetime.datetime`: Datetime for the next job execution. + Datetime is localized according to :attr:`tzinfo`. + If job is removed or already ran it equals to :obj:`None`. + """ + return self.job.next_run_time + + @classmethod + def _from_aps_job(cls, job: APSJob, job_queue: JobQueue) -> 'Job': + # context based callbacks + if len(job.args) == 1: + context = job.args[0].job.context + else: + context = job.args[1].context + return cls(job.func, context=context, name=job.name, job_queue=job_queue, job=job) + + def __getattr__(self, item: str) -> object: + return getattr(self.job, item) + + def __lt__(self, other: object) -> bool: + return False + + def __eq__(self, other: object) -> bool: + if isinstance(other, self.__class__): + return self.id == other.id + return False diff --git a/venv/lib/python3.8/site-packages/telegram/ext/messagehandler.py b/venv/lib/python3.8/site-packages/telegram/ext/messagehandler.py new file mode 100644 index 0000000..c3f0c01 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/ext/messagehandler.py @@ -0,0 +1,208 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +# TODO: Remove allow_edited +"""This module contains the MessageHandler class.""" +import warnings +from typing import TYPE_CHECKING, Callable, Dict, Optional, TypeVar, Union + +from telegram import Update +from telegram.ext import BaseFilter, Filters +from telegram.utils.deprecate import TelegramDeprecationWarning +from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE + +from .handler import Handler +from .utils.types import CCT + +if TYPE_CHECKING: + from telegram.ext import Dispatcher + +RT = TypeVar('RT') + + +class MessageHandler(Handler[Update, CCT]): + """Handler class to handle telegram messages. They might contain text, media or status updates. + + Note: + :attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you + can use to keep any data in will be sent to the :attr:`callback` function. Related to + either the user or the chat that the update was sent in. For each update from the same user + or in the same chat, it will be the same ``dict``. + + Note that this is DEPRECATED, and you should use context based callbacks. See + https://git.io/fxJuV for more info. + + Warning: + When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom + attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. + + Args: + filters (:class:`telegram.ext.BaseFilter`, optional): A filter inheriting from + :class:`telegram.ext.filters.BaseFilter`. Standard filters can be found in + :class:`telegram.ext.filters.Filters`. Filters can be combined using bitwise + operators (& for and, | for or, ~ for not). Default is + :attr:`telegram.ext.filters.Filters.update`. This defaults to all message_type updates + being: ``message``, ``edited_message``, ``channel_post`` and ``edited_channel_post``. + If you don't want or need any of those pass ``~Filters.update.*`` in the filter + argument. + callback (:obj:`callable`): The callback function for this handler. Will be called when + :attr:`check_update` has determined that an update should be processed by this handler. + Callback signature for context based API: + + ``def callback(update: Update, context: CallbackContext)`` + + The return value of the callback is usually ignored except for the special case of + :class:`telegram.ext.ConversationHandler`. + pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``update_queue`` will be passed to the callback function. It will be the ``Queue`` + instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher` + that contains new updates which can be used to insert updates. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``job_queue`` will be passed to the callback function. It will be a + :class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater` + which can be used to schedule new jobs. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``user_data`` will be passed to the callback function. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``chat_data`` will be passed to the callback function. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + message_updates (:obj:`bool`, optional): Should "normal" message updates be handled? + Default is :obj:`None`. + DEPRECATED: Please switch to filters for update filtering. + channel_post_updates (:obj:`bool`, optional): Should channel posts updates be handled? + Default is :obj:`None`. + DEPRECATED: Please switch to filters for update filtering. + edited_updates (:obj:`bool`, optional): Should "edited" message updates be handled? Default + is :obj:`None`. + DEPRECATED: Please switch to filters for update filtering. + run_async (:obj:`bool`): Determines whether the callback will run asynchronously. + Defaults to :obj:`False`. + + Raises: + ValueError + + Attributes: + filters (:obj:`Filter`): Only allow updates with these Filters. See + :mod:`telegram.ext.filters` for a full list of all available filters. + callback (:obj:`callable`): The callback function for this handler. + pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be + passed to the callback function. + pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to + the callback function. + pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to + the callback function. + pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to + the callback function. + message_updates (:obj:`bool`): Should "normal" message updates be handled? + Default is :obj:`None`. + channel_post_updates (:obj:`bool`): Should channel posts updates be handled? + Default is :obj:`None`. + edited_updates (:obj:`bool`): Should "edited" message updates be handled? + Default is :obj:`None`. + run_async (:obj:`bool`): Determines whether the callback will run asynchronously. + + """ + + __slots__ = ('filters',) + + def __init__( + self, + filters: BaseFilter, + callback: Callable[[Update, CCT], RT], + pass_update_queue: bool = False, + pass_job_queue: bool = False, + pass_user_data: bool = False, + pass_chat_data: bool = False, + message_updates: bool = None, + channel_post_updates: bool = None, + edited_updates: bool = None, + run_async: Union[bool, DefaultValue] = DEFAULT_FALSE, + ): + + super().__init__( + callback, + pass_update_queue=pass_update_queue, + pass_job_queue=pass_job_queue, + pass_user_data=pass_user_data, + pass_chat_data=pass_chat_data, + run_async=run_async, + ) + if message_updates is False and channel_post_updates is False and edited_updates is False: + raise ValueError( + 'message_updates, channel_post_updates and edited_updates are all False' + ) + if filters is not None: + self.filters = Filters.update & filters + else: + self.filters = Filters.update + if message_updates is not None: + warnings.warn( + 'message_updates is deprecated. See https://git.io/fxJuV for more info', + TelegramDeprecationWarning, + stacklevel=2, + ) + if message_updates is False: + self.filters &= ~Filters.update.message + + if channel_post_updates is not None: + warnings.warn( + 'channel_post_updates is deprecated. See https://git.io/fxJuV ' 'for more info', + TelegramDeprecationWarning, + stacklevel=2, + ) + if channel_post_updates is False: + self.filters &= ~Filters.update.channel_post + + if edited_updates is not None: + warnings.warn( + 'edited_updates is deprecated. See https://git.io/fxJuV for more info', + TelegramDeprecationWarning, + stacklevel=2, + ) + if edited_updates is False: + self.filters &= ~( + Filters.update.edited_message | Filters.update.edited_channel_post + ) + + def check_update(self, update: object) -> Optional[Union[bool, Dict[str, list]]]: + """Determines whether an update should be passed to this handlers :attr:`callback`. + + Args: + update (:class:`telegram.Update` | :obj:`object`): Incoming update. + + Returns: + :obj:`bool` + + """ + if isinstance(update, Update) and update.effective_message: + return self.filters(update) + return None + + def collect_additional_context( + self, + context: CCT, + update: Update, + dispatcher: 'Dispatcher', + check_result: Optional[Union[bool, Dict[str, object]]], + ) -> None: + """Adds possible output of data filters to the :class:`CallbackContext`.""" + if isinstance(check_result, dict): + context.update(check_result) diff --git a/venv/lib/python3.8/site-packages/telegram/ext/messagequeue.py b/venv/lib/python3.8/site-packages/telegram/ext/messagequeue.py new file mode 100644 index 0000000..ece0bc3 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/ext/messagequeue.py @@ -0,0 +1,334 @@ +#!/usr/bin/env python +# +# Module author: +# Tymofii A. Khodniev (thodnev) <thodnev@mail.ru> +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/] +"""A throughput-limiting message processor for Telegram bots.""" +import functools +import queue as q +import threading +import time +import warnings +from typing import TYPE_CHECKING, Callable, List, NoReturn + +from telegram.ext.utils.promise import Promise +from telegram.utils.deprecate import TelegramDeprecationWarning + +if TYPE_CHECKING: + from telegram import Bot + +# We need to count < 1s intervals, so the most accurate timer is needed +curtime = time.perf_counter + + +class DelayQueueError(RuntimeError): + """Indicates processing errors.""" + + __slots__ = () + + +class DelayQueue(threading.Thread): + """ + Processes callbacks from queue with specified throughput limits. Creates a separate thread to + process callbacks with delays. + + .. deprecated:: 13.3 + :class:`telegram.ext.DelayQueue` in its current form is deprecated and will be reinvented + in a future release. See `this thread <https://git.io/JtDbF>`_ for a list of known bugs. + + Args: + queue (:obj:`Queue`, optional): Used to pass callbacks to thread. Creates ``Queue`` + implicitly if not provided. + burst_limit (:obj:`int`, optional): Number of maximum callbacks to process per time-window + defined by :attr:`time_limit_ms`. Defaults to 30. + time_limit_ms (:obj:`int`, optional): Defines width of time-window used when each + processing limit is calculated. Defaults to 1000. + exc_route (:obj:`callable`, optional): A callable, accepting 1 positional argument; used to + route exceptions from processor thread to main thread; is called on `Exception` + subclass exceptions. If not provided, exceptions are routed through dummy handler, + which re-raises them. + autostart (:obj:`bool`, optional): If :obj:`True`, processor is started immediately after + object's creation; if :obj:`False`, should be started manually by `start` method. + Defaults to :obj:`True`. + name (:obj:`str`, optional): Thread's name. Defaults to ``'DelayQueue-N'``, where N is + sequential number of object created. + + Attributes: + burst_limit (:obj:`int`): Number of maximum callbacks to process per time-window. + time_limit (:obj:`int`): Defines width of time-window used when each processing limit is + calculated. + exc_route (:obj:`callable`): A callable, accepting 1 positional argument; used to route + exceptions from processor thread to main thread; + name (:obj:`str`): Thread's name. + + """ + + _instcnt = 0 # instance counter + + def __init__( + self, + queue: q.Queue = None, + burst_limit: int = 30, + time_limit_ms: int = 1000, + exc_route: Callable[[Exception], None] = None, + autostart: bool = True, + name: str = None, + ): + warnings.warn( + 'DelayQueue in its current form is deprecated and will be reinvented in a future ' + 'release. See https://git.io/JtDbF for a list of known bugs.', + category=TelegramDeprecationWarning, + ) + + self._queue = queue if queue is not None else q.Queue() + self.burst_limit = burst_limit + self.time_limit = time_limit_ms / 1000 + self.exc_route = exc_route if exc_route is not None else self._default_exception_handler + self.__exit_req = False # flag to gently exit thread + self.__class__._instcnt += 1 + if name is None: + name = f'{self.__class__.__name__}-{self.__class__._instcnt}' + super().__init__(name=name) + self.daemon = False + if autostart: # immediately start processing + super().start() + + def run(self) -> None: + """ + Do not use the method except for unthreaded testing purposes, the method normally is + automatically called by autostart argument. + + """ + times: List[float] = [] # used to store each callable processing time + while True: + item = self._queue.get() + if self.__exit_req: + return # shutdown thread + # delay routine + now = time.perf_counter() + t_delta = now - self.time_limit # calculate early to improve perf. + if times and t_delta > times[-1]: + # if last call was before the limit time-window + # used to impr. perf. in long-interval calls case + times = [now] + else: + # collect last in current limit time-window + times = [t for t in times if t >= t_delta] + times.append(now) + if len(times) >= self.burst_limit: # if throughput limit was hit + time.sleep(times[1] - t_delta) + # finally process one + try: + func, args, kwargs = item + func(*args, **kwargs) + except Exception as exc: # re-route any exceptions + self.exc_route(exc) # to prevent thread exit + + def stop(self, timeout: float = None) -> None: + """Used to gently stop processor and shutdown its thread. + + Args: + timeout (:obj:`float`): Indicates maximum time to wait for processor to stop and its + thread to exit. If timeout exceeds and processor has not stopped, method silently + returns. :attr:`is_alive` could be used afterwards to check the actual status. + ``timeout`` set to :obj:`None`, blocks until processor is shut down. + Defaults to :obj:`None`. + + """ + self.__exit_req = True # gently request + self._queue.put(None) # put something to unfreeze if frozen + super().join(timeout=timeout) + + @staticmethod + def _default_exception_handler(exc: Exception) -> NoReturn: + """ + Dummy exception handler which re-raises exception in thread. Could be possibly overwritten + by subclasses. + + """ + raise exc + + def __call__(self, func: Callable, *args: object, **kwargs: object) -> None: + """Used to process callbacks in throughput-limiting thread through queue. + + Args: + func (:obj:`callable`): The actual function (or any callable) that is processed through + queue. + *args (:obj:`list`): Variable-length `func` arguments. + **kwargs (:obj:`dict`): Arbitrary keyword-arguments to `func`. + + """ + if not self.is_alive() or self.__exit_req: + raise DelayQueueError('Could not process callback in stopped thread') + self._queue.put((func, args, kwargs)) + + +# The most straightforward way to implement this is to use 2 sequential delay +# queues, like on classic delay chain schematics in electronics. +# So, message path is: +# msg --> group delay if group msg, else no delay --> normal msg delay --> out +# This way OS threading scheduler cares of timings accuracy. +# (see time.time, time.clock, time.perf_counter, time.sleep @ docs.python.org) +class MessageQueue: + """ + Implements callback processing with proper delays to avoid hitting Telegram's message limits. + Contains two ``DelayQueue``, for group and for all messages, interconnected in delay chain. + Callables are processed through *group* ``DelayQueue``, then through *all* ``DelayQueue`` for + group-type messages. For non-group messages, only the *all* ``DelayQueue`` is used. + + .. deprecated:: 13.3 + :class:`telegram.ext.MessageQueue` in its current form is deprecated and will be reinvented + in a future release. See `this thread <https://git.io/JtDbF>`_ for a list of known bugs. + + Args: + all_burst_limit (:obj:`int`, optional): Number of maximum *all-type* callbacks to process + per time-window defined by :attr:`all_time_limit_ms`. Defaults to 30. + all_time_limit_ms (:obj:`int`, optional): Defines width of *all-type* time-window used when + each processing limit is calculated. Defaults to 1000 ms. + group_burst_limit (:obj:`int`, optional): Number of maximum *group-type* callbacks to + process per time-window defined by :attr:`group_time_limit_ms`. Defaults to 20. + group_time_limit_ms (:obj:`int`, optional): Defines width of *group-type* time-window used + when each processing limit is calculated. Defaults to 60000 ms. + exc_route (:obj:`callable`, optional): A callable, accepting one positional argument; used + to route exceptions from processor threads to main thread; is called on ``Exception`` + subclass exceptions. If not provided, exceptions are routed through dummy handler, + which re-raises them. + autostart (:obj:`bool`, optional): If :obj:`True`, processors are started immediately after + object's creation; if :obj:`False`, should be started manually by :attr:`start` method. + Defaults to :obj:`True`. + + """ + + def __init__( + self, + all_burst_limit: int = 30, + all_time_limit_ms: int = 1000, + group_burst_limit: int = 20, + group_time_limit_ms: int = 60000, + exc_route: Callable[[Exception], None] = None, + autostart: bool = True, + ): + warnings.warn( + 'MessageQueue in its current form is deprecated and will be reinvented in a future ' + 'release. See https://git.io/JtDbF for a list of known bugs.', + category=TelegramDeprecationWarning, + ) + + # create according delay queues, use composition + self._all_delayq = DelayQueue( + burst_limit=all_burst_limit, + time_limit_ms=all_time_limit_ms, + exc_route=exc_route, + autostart=autostart, + ) + self._group_delayq = DelayQueue( + burst_limit=group_burst_limit, + time_limit_ms=group_time_limit_ms, + exc_route=exc_route, + autostart=autostart, + ) + + def start(self) -> None: + """Method is used to manually start the ``MessageQueue`` processing.""" + self._all_delayq.start() + self._group_delayq.start() + + def stop(self, timeout: float = None) -> None: + """Stops the ``MessageQueue``.""" + self._group_delayq.stop(timeout=timeout) + self._all_delayq.stop(timeout=timeout) + + stop.__doc__ = DelayQueue.stop.__doc__ or '' # reuse docstring if any + + def __call__(self, promise: Callable, is_group_msg: bool = False) -> Callable: + """ + Processes callables in throughput-limiting queues to avoid hitting limits (specified with + :attr:`burst_limit` and :attr:`time_limit`. + + Args: + promise (:obj:`callable`): Mainly the ``telegram.utils.promise.Promise`` (see Notes for + other callables), that is processed in delay queues. + is_group_msg (:obj:`bool`, optional): Defines whether ``promise`` would be processed in + group*+*all* ``DelayQueue``s (if set to :obj:`True`), or only through *all* + ``DelayQueue`` (if set to :obj:`False`), resulting in needed delays to avoid + hitting specified limits. Defaults to :obj:`False`. + + Note: + Method is designed to accept ``telegram.utils.promise.Promise`` as ``promise`` + argument, but other callables could be used too. For example, lambdas or simple + functions could be used to wrap original func to be called with needed args. In that + case, be sure that either wrapper func does not raise outside exceptions or the proper + :attr:`exc_route` handler is provided. + + Returns: + :obj:`callable`: Used as ``promise`` argument. + + """ + if not is_group_msg: # ignore middle group delay + self._all_delayq(promise) + else: # use middle group delay + self._group_delayq(self._all_delayq, promise) + return promise + + +def queuedmessage(method: Callable) -> Callable: + """A decorator to be used with :attr:`telegram.Bot` send* methods. + + Note: + As it probably wouldn't be a good idea to make this decorator a property, it has been coded + as decorator function, so it implies that first positional argument to wrapped MUST be + self. + + The next object attributes are used by decorator: + + Attributes: + self._is_messages_queued_default (:obj:`bool`): Value to provide class-defaults to + ``queued`` kwarg if not provided during wrapped method call. + self._msg_queue (:class:`telegram.ext.messagequeue.MessageQueue`): The actual + ``MessageQueue`` used to delay outbound messages according to specified time-limits. + + Wrapped method starts accepting the next kwargs: + + Args: + queued (:obj:`bool`, optional): If set to :obj:`True`, the ``MessageQueue`` is used to + process output messages. Defaults to `self._is_queued_out`. + isgroup (:obj:`bool`, optional): If set to :obj:`True`, the message is meant to be + group-type(as there's no obvious way to determine its type in other way at the moment). + Group-type messages could have additional processing delay according to limits set + in `self._out_queue`. Defaults to :obj:`False`. + + Returns: + ``telegram.utils.promise.Promise``: In case call is queued or original method's return + value if it's not. + + """ + + @functools.wraps(method) + def wrapped(self: 'Bot', *args: object, **kwargs: object) -> object: + # pylint: disable=W0212 + queued = kwargs.pop( + 'queued', self._is_messages_queued_default # type: ignore[attr-defined] + ) + isgroup = kwargs.pop('isgroup', False) + if queued: + prom = Promise(method, (self,) + args, kwargs) + return self._msg_queue(prom, isgroup) # type: ignore[attr-defined] + return method(self, *args, **kwargs) + + return wrapped diff --git a/venv/lib/python3.8/site-packages/telegram/ext/picklepersistence.py b/venv/lib/python3.8/site-packages/telegram/ext/picklepersistence.py new file mode 100644 index 0000000..3870d41 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/ext/picklepersistence.py @@ -0,0 +1,463 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the PicklePersistence class.""" +import pickle +from collections import defaultdict +from typing import ( + Any, + Dict, + Optional, + Tuple, + overload, + cast, + DefaultDict, +) + +from telegram.ext import BasePersistence +from .utils.types import UD, CD, BD, ConversationDict, CDCData +from .contexttypes import ContextTypes + + +class PicklePersistence(BasePersistence[UD, CD, BD]): + """Using python's builtin pickle for making your bot persistent. + + Warning: + :class:`PicklePersistence` will try to replace :class:`telegram.Bot` instances by + :attr:`REPLACED_BOT` and insert the bot set with + :meth:`telegram.ext.BasePersistence.set_bot` upon loading of the data. This is to ensure + that changes to the bot apply to the saved objects, too. If you change the bots token, this + may lead to e.g. ``Chat not found`` errors. For the limitations on replacing bots see + :meth:`telegram.ext.BasePersistence.replace_bot` and + :meth:`telegram.ext.BasePersistence.insert_bot`. + + Args: + filename (:obj:`str`): The filename for storing the pickle files. When :attr:`single_file` + is :obj:`False` this will be used as a prefix. + store_user_data (:obj:`bool`, optional): Whether user_data should be saved by this + persistence class. Default is :obj:`True`. + store_chat_data (:obj:`bool`, optional): Whether chat_data should be saved by this + persistence class. Default is :obj:`True`. + store_bot_data (:obj:`bool`, optional): Whether bot_data should be saved by this + persistence class. Default is :obj:`True`. + store_callback_data (:obj:`bool`, optional): Whether callback_data should be saved by this + persistence class. Default is :obj:`False`. + + .. versionadded:: 13.6 + single_file (:obj:`bool`, optional): When :obj:`False` will store 5 separate files of + `filename_user_data`, `filename_chat_data`, `filename_bot_data`, `filename_chat_data`, + `filename_callback_data` and `filename_conversations`. Default is :obj:`True`. + on_flush (:obj:`bool`, optional): When :obj:`True` will only save to file when + :meth:`flush` is called and keep data in memory until that happens. When + :obj:`False` will store data on any transaction *and* on call to :meth:`flush`. + Default is :obj:`False`. + context_types (:class:`telegram.ext.ContextTypes`, optional): Pass an instance + of :class:`telegram.ext.ContextTypes` to customize the types used in the + ``context`` interface. If not passed, the defaults documented in + :class:`telegram.ext.ContextTypes` will be used. + + .. versionadded:: 13.6 + + Attributes: + filename (:obj:`str`): The filename for storing the pickle files. When :attr:`single_file` + is :obj:`False` this will be used as a prefix. + store_user_data (:obj:`bool`): Optional. Whether user_data should be saved by this + persistence class. + store_chat_data (:obj:`bool`): Optional. Whether chat_data should be saved by this + persistence class. + store_bot_data (:obj:`bool`): Optional. Whether bot_data should be saved by this + persistence class. + store_callback_data (:obj:`bool`): Optional. Whether callback_data be saved by this + persistence class. + + .. versionadded:: 13.6 + single_file (:obj:`bool`): Optional. When :obj:`False` will store 5 separate files of + `filename_user_data`, `filename_chat_data`, `filename_bot_data`, `filename_chat_data`, + `filename_callback_data` and `filename_conversations`. Default is :obj:`True`. + on_flush (:obj:`bool`, optional): When :obj:`True` will only save to file when + :meth:`flush` is called and keep data in memory until that happens. When + :obj:`False` will store data on any transaction *and* on call to :meth:`flush`. + Default is :obj:`False`. + context_types (:class:`telegram.ext.ContextTypes`): Container for the types used + in the ``context`` interface. + + .. versionadded:: 13.6 + """ + + __slots__ = ( + 'filename', + 'single_file', + 'on_flush', + 'user_data', + 'chat_data', + 'bot_data', + 'callback_data', + 'conversations', + 'context_types', + ) + + @overload + def __init__( + self: 'PicklePersistence[Dict, Dict, Dict]', + filename: str, + store_user_data: bool = True, + store_chat_data: bool = True, + store_bot_data: bool = True, + single_file: bool = True, + on_flush: bool = False, + store_callback_data: bool = False, + ): + ... + + @overload + def __init__( + self: 'PicklePersistence[UD, CD, BD]', + filename: str, + store_user_data: bool = True, + store_chat_data: bool = True, + store_bot_data: bool = True, + single_file: bool = True, + on_flush: bool = False, + store_callback_data: bool = False, + context_types: ContextTypes[Any, UD, CD, BD] = None, + ): + ... + + def __init__( + self, + filename: str, + store_user_data: bool = True, + store_chat_data: bool = True, + store_bot_data: bool = True, + single_file: bool = True, + on_flush: bool = False, + store_callback_data: bool = False, + context_types: ContextTypes[Any, UD, CD, BD] = None, + ): + super().__init__( + store_user_data=store_user_data, + store_chat_data=store_chat_data, + store_bot_data=store_bot_data, + store_callback_data=store_callback_data, + ) + self.filename = filename + self.single_file = single_file + self.on_flush = on_flush + self.user_data: Optional[DefaultDict[int, UD]] = None + self.chat_data: Optional[DefaultDict[int, CD]] = None + self.bot_data: Optional[BD] = None + self.callback_data: Optional[CDCData] = None + self.conversations: Optional[Dict[str, Dict[Tuple, object]]] = None + self.context_types = cast(ContextTypes[Any, UD, CD, BD], context_types or ContextTypes()) + + def _load_singlefile(self) -> None: + try: + filename = self.filename + with open(self.filename, "rb") as file: + data = pickle.load(file) + self.user_data = defaultdict(self.context_types.user_data, data['user_data']) + self.chat_data = defaultdict(self.context_types.chat_data, data['chat_data']) + # For backwards compatibility with files not containing bot data + self.bot_data = data.get('bot_data', self.context_types.bot_data()) + self.callback_data = data.get('callback_data', {}) + self.conversations = data['conversations'] + except OSError: + self.conversations = {} + self.user_data = defaultdict(self.context_types.user_data) + self.chat_data = defaultdict(self.context_types.chat_data) + self.bot_data = self.context_types.bot_data() + self.callback_data = None + except pickle.UnpicklingError as exc: + raise TypeError(f"File {filename} does not contain valid pickle data") from exc + except Exception as exc: + raise TypeError(f"Something went wrong unpickling {filename}") from exc + + @staticmethod + def _load_file(filename: str) -> Any: + try: + with open(filename, "rb") as file: + return pickle.load(file) + except OSError: + return None + except pickle.UnpicklingError as exc: + raise TypeError(f"File {filename} does not contain valid pickle data") from exc + except Exception as exc: + raise TypeError(f"Something went wrong unpickling {filename}") from exc + + def _dump_singlefile(self) -> None: + with open(self.filename, "wb") as file: + data = { + 'conversations': self.conversations, + 'user_data': self.user_data, + 'chat_data': self.chat_data, + 'bot_data': self.bot_data, + 'callback_data': self.callback_data, + } + pickle.dump(data, file) + + @staticmethod + def _dump_file(filename: str, data: object) -> None: + with open(filename, "wb") as file: + pickle.dump(data, file) + + def get_user_data(self) -> DefaultDict[int, UD]: + """Returns the user_data from the pickle file if it exists or an empty :obj:`defaultdict`. + + Returns: + DefaultDict[:obj:`int`, :class:`telegram.ext.utils.types.UD`]: The restored user data. + """ + if self.user_data: + pass + elif not self.single_file: + filename = f"{self.filename}_user_data" + data = self._load_file(filename) + if not data: + data = defaultdict(self.context_types.user_data) + else: + data = defaultdict(self.context_types.user_data, data) + self.user_data = data + else: + self._load_singlefile() + return self.user_data # type: ignore[return-value] + + def get_chat_data(self) -> DefaultDict[int, CD]: + """Returns the chat_data from the pickle file if it exists or an empty :obj:`defaultdict`. + + Returns: + DefaultDict[:obj:`int`, :class:`telegram.ext.utils.types.CD`]: The restored chat data. + """ + if self.chat_data: + pass + elif not self.single_file: + filename = f"{self.filename}_chat_data" + data = self._load_file(filename) + if not data: + data = defaultdict(self.context_types.chat_data) + else: + data = defaultdict(self.context_types.chat_data, data) + self.chat_data = data + else: + self._load_singlefile() + return self.chat_data # type: ignore[return-value] + + def get_bot_data(self) -> BD: + """Returns the bot_data from the pickle file if it exists or an empty object of type + :class:`telegram.ext.utils.types.BD`. + + Returns: + :class:`telegram.ext.utils.types.BD`: The restored bot data. + """ + if self.bot_data: + pass + elif not self.single_file: + filename = f"{self.filename}_bot_data" + data = self._load_file(filename) + if not data: + data = self.context_types.bot_data() + self.bot_data = data + else: + self._load_singlefile() + return self.bot_data # type: ignore[return-value] + + def get_callback_data(self) -> Optional[CDCData]: + """Returns the callback data from the pickle file if it exists or :obj:`None`. + + .. versionadded:: 13.6 + + Returns: + Optional[:class:`telegram.ext.utils.types.CDCData`]: The restored meta data or + :obj:`None`, if no data was stored. + """ + if self.callback_data: + pass + elif not self.single_file: + filename = f"{self.filename}_callback_data" + data = self._load_file(filename) + if not data: + data = None + self.callback_data = data + else: + self._load_singlefile() + if self.callback_data is None: + return None + return self.callback_data[0], self.callback_data[1].copy() + + def get_conversations(self, name: str) -> ConversationDict: + """Returns the conversations from the pickle file if it exists or an empty dict. + + Args: + name (:obj:`str`): The handlers name. + + Returns: + :obj:`dict`: The restored conversations for the handler. + """ + if self.conversations: + pass + elif not self.single_file: + filename = f"{self.filename}_conversations" + data = self._load_file(filename) + if not data: + data = {name: {}} + self.conversations = data + else: + self._load_singlefile() + return self.conversations.get(name, {}).copy() # type: ignore[union-attr] + + def update_conversation( + self, name: str, key: Tuple[int, ...], new_state: Optional[object] + ) -> None: + """Will update the conversations for the given handler and depending on :attr:`on_flush` + save the pickle file. + + Args: + name (:obj:`str`): The handler's name. + key (:obj:`tuple`): The key the state is changed for. + new_state (:obj:`tuple` | :obj:`any`): The new state for the given key. + """ + if not self.conversations: + self.conversations = {} + if self.conversations.setdefault(name, {}).get(key) == new_state: + return + self.conversations[name][key] = new_state + if not self.on_flush: + if not self.single_file: + filename = f"{self.filename}_conversations" + self._dump_file(filename, self.conversations) + else: + self._dump_singlefile() + + def update_user_data(self, user_id: int, data: UD) -> None: + """Will update the user_data and depending on :attr:`on_flush` save the pickle file. + + Args: + user_id (:obj:`int`): The user the data might have been changed for. + data (:class:`telegram.ext.utils.types.UD`): The + :attr:`telegram.ext.dispatcher.user_data` ``[user_id]``. + """ + if self.user_data is None: + self.user_data = defaultdict(self.context_types.user_data) + if self.user_data.get(user_id) == data: + return + self.user_data[user_id] = data + if not self.on_flush: + if not self.single_file: + filename = f"{self.filename}_user_data" + self._dump_file(filename, self.user_data) + else: + self._dump_singlefile() + + def update_chat_data(self, chat_id: int, data: CD) -> None: + """Will update the chat_data and depending on :attr:`on_flush` save the pickle file. + + Args: + chat_id (:obj:`int`): The chat the data might have been changed for. + data (:class:`telegram.ext.utils.types.CD`): The + :attr:`telegram.ext.dispatcher.chat_data` ``[chat_id]``. + """ + if self.chat_data is None: + self.chat_data = defaultdict(self.context_types.chat_data) + if self.chat_data.get(chat_id) == data: + return + self.chat_data[chat_id] = data + if not self.on_flush: + if not self.single_file: + filename = f"{self.filename}_chat_data" + self._dump_file(filename, self.chat_data) + else: + self._dump_singlefile() + + def update_bot_data(self, data: BD) -> None: + """Will update the bot_data and depending on :attr:`on_flush` save the pickle file. + + Args: + data (:class:`telegram.ext.utils.types.BD`): The + :attr:`telegram.ext.dispatcher.bot_data`. + """ + if self.bot_data == data: + return + self.bot_data = data + if not self.on_flush: + if not self.single_file: + filename = f"{self.filename}_bot_data" + self._dump_file(filename, self.bot_data) + else: + self._dump_singlefile() + + def update_callback_data(self, data: CDCData) -> None: + """Will update the callback_data (if changed) and depending on :attr:`on_flush` save the + pickle file. + + .. versionadded:: 13.6 + + Args: + data (:class:`telegram.ext.utils.types.CDCData`:): The relevant data to restore + :attr:`telegram.ext.dispatcher.bot.callback_data`. + """ + if self.callback_data == data: + return + self.callback_data = (data[0], data[1].copy()) + if not self.on_flush: + if not self.single_file: + filename = f"{self.filename}_callback_data" + self._dump_file(filename, self.callback_data) + else: + self._dump_singlefile() + + def refresh_user_data(self, user_id: int, user_data: UD) -> None: + """Does nothing. + + .. versionadded:: 13.6 + .. seealso:: :meth:`telegram.ext.BasePersistence.refresh_user_data` + """ + + def refresh_chat_data(self, chat_id: int, chat_data: CD) -> None: + """Does nothing. + + .. versionadded:: 13.6 + .. seealso:: :meth:`telegram.ext.BasePersistence.refresh_chat_data` + """ + + def refresh_bot_data(self, bot_data: BD) -> None: + """Does nothing. + + .. versionadded:: 13.6 + .. seealso:: :meth:`telegram.ext.BasePersistence.refresh_bot_data` + """ + + def flush(self) -> None: + """Will save all data in memory to pickle file(s).""" + if self.single_file: + if ( + self.user_data + or self.chat_data + or self.bot_data + or self.callback_data + or self.conversations + ): + self._dump_singlefile() + else: + if self.user_data: + self._dump_file(f"{self.filename}_user_data", self.user_data) + if self.chat_data: + self._dump_file(f"{self.filename}_chat_data", self.chat_data) + if self.bot_data: + self._dump_file(f"{self.filename}_bot_data", self.bot_data) + if self.callback_data: + self._dump_file(f"{self.filename}_callback_data", self.callback_data) + if self.conversations: + self._dump_file(f"{self.filename}_conversations", self.conversations) diff --git a/venv/lib/python3.8/site-packages/telegram/ext/pollanswerhandler.py b/venv/lib/python3.8/site-packages/telegram/ext/pollanswerhandler.py new file mode 100644 index 0000000..199bcb3 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/ext/pollanswerhandler.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2019-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the PollAnswerHandler class.""" + + +from telegram import Update + +from .handler import Handler +from .utils.types import CCT + + +class PollAnswerHandler(Handler[Update, CCT]): + """Handler class to handle Telegram updates that contain a poll answer. + + Note: + :attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you + can use to keep any data in will be sent to the :attr:`callback` function. Related to + either the user or the chat that the update was sent in. For each update from the same user + or in the same chat, it will be the same ``dict``. + + Note that this is DEPRECATED, and you should use context based callbacks. See + https://git.io/fxJuV for more info. + + Warning: + When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom + attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. + + Args: + callback (:obj:`callable`): The callback function for this handler. Will be called when + :attr:`check_update` has determined that an update should be processed by this handler. + Callback signature for context based API: + + ``def callback(update: Update, context: CallbackContext)`` + + The return value of the callback is usually ignored except for the special case of + :class:`telegram.ext.ConversationHandler`. + pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``update_queue`` will be passed to the callback function. It will be the ``Queue`` + instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher` + that contains new updates which can be used to insert updates. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``job_queue`` will be passed to the callback function. It will be a + :class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater` + which can be used to schedule new jobs. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``user_data`` will be passed to the callback function. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``chat_data`` will be passed to the callback function. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + run_async (:obj:`bool`): Determines whether the callback will run asynchronously. + Defaults to :obj:`False`. + + Attributes: + callback (:obj:`callable`): The callback function for this handler. + pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be + passed to the callback function. + pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to + the callback function. + pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to + the callback function. + pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to + the callback function. + run_async (:obj:`bool`): Determines whether the callback will run asynchronously. + + """ + + __slots__ = () + + def check_update(self, update: object) -> bool: + """Determines whether an update should be passed to this handlers :attr:`callback`. + + Args: + update (:class:`telegram.Update` | :obj:`object`): Incoming update. + + Returns: + :obj:`bool` + + """ + return isinstance(update, Update) and bool(update.poll_answer) diff --git a/venv/lib/python3.8/site-packages/telegram/ext/pollhandler.py b/venv/lib/python3.8/site-packages/telegram/ext/pollhandler.py new file mode 100644 index 0000000..7b67e76 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/ext/pollhandler.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2019-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the PollHandler classes.""" + + +from telegram import Update + +from .handler import Handler +from .utils.types import CCT + + +class PollHandler(Handler[Update, CCT]): + """Handler class to handle Telegram updates that contain a poll. + + Note: + :attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you + can use to keep any data in will be sent to the :attr:`callback` function. Related to + either the user or the chat that the update was sent in. For each update from the same user + or in the same chat, it will be the same ``dict``. + + Note that this is DEPRECATED, and you should use context based callbacks. See + https://git.io/fxJuV for more info. + + Warning: + When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom + attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. + + Args: + callback (:obj:`callable`): The callback function for this handler. Will be called when + :attr:`check_update` has determined that an update should be processed by this handler. + Callback signature for context based API: + + ``def callback(update: Update, context: CallbackContext)`` + + The return value of the callback is usually ignored except for the special case of + :class:`telegram.ext.ConversationHandler`. + pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``update_queue`` will be passed to the callback function. It will be the ``Queue`` + instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher` + that contains new updates which can be used to insert updates. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``job_queue`` will be passed to the callback function. It will be a + :class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater` + which can be used to schedule new jobs. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``user_data`` will be passed to the callback function. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``chat_data`` will be passed to the callback function. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + run_async (:obj:`bool`): Determines whether the callback will run asynchronously. + Defaults to :obj:`False`. + + Attributes: + callback (:obj:`callable`): The callback function for this handler. + pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be + passed to the callback function. + pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to + the callback function. + pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to + the callback function. + pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to + the callback function. + run_async (:obj:`bool`): Determines whether the callback will run asynchronously. + + """ + + __slots__ = () + + def check_update(self, update: object) -> bool: + """Determines whether an update should be passed to this handlers :attr:`callback`. + + Args: + update (:class:`telegram.Update` | :obj:`object`): Incoming update. + + Returns: + :obj:`bool` + + """ + return isinstance(update, Update) and bool(update.poll) diff --git a/venv/lib/python3.8/site-packages/telegram/ext/precheckoutqueryhandler.py b/venv/lib/python3.8/site-packages/telegram/ext/precheckoutqueryhandler.py new file mode 100644 index 0000000..3a2eee3 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/ext/precheckoutqueryhandler.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the PreCheckoutQueryHandler class.""" + + +from telegram import Update + +from .handler import Handler +from .utils.types import CCT + + +class PreCheckoutQueryHandler(Handler[Update, CCT]): + """Handler class to handle Telegram PreCheckout callback queries. + + Note: + :attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you + can use to keep any data in will be sent to the :attr:`callback` function. Related to + either the user or the chat that the update was sent in. For each update from the same user + or in the same chat, it will be the same ``dict``. + + Note that this is DEPRECATED, and you should use context based callbacks. See + https://git.io/fxJuV for more info. + + Warning: + When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom + attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. + + Args: + callback (:obj:`callable`): The callback function for this handler. Will be called when + :attr:`check_update` has determined that an update should be processed by this handler. + Callback signature for context based API: + + ``def callback(update: Update, context: CallbackContext)`` + + The return value of the callback is usually ignored except for the special case of + :class:`telegram.ext.ConversationHandler`. + pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``update_queue`` will be passed to the callback function. It will be the ``Queue`` + DEPRECATED: Please switch to context based callbacks. + instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher` + that contains new updates which can be used to insert updates. Default is :obj:`False`. + pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``job_queue`` will be passed to the callback function. It will be a + :class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater` + which can be used to schedule new jobs. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``user_data`` will be passed to the callback function. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``chat_data`` will be passed to the callback function. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + run_async (:obj:`bool`): Determines whether the callback will run asynchronously. + Defaults to :obj:`False`. + + Attributes: + callback (:obj:`callable`): The callback function for this handler. + pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be + passed to the callback function. + pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to + the callback function. + pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to + the callback function. + pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to + the callback function. + run_async (:obj:`bool`): Determines whether the callback will run asynchronously. + + """ + + __slots__ = () + + def check_update(self, update: object) -> bool: + """Determines whether an update should be passed to this handlers :attr:`callback`. + + Args: + update (:class:`telegram.Update` | :obj:`object`): Incoming update. + + Returns: + :obj:`bool` + + """ + return isinstance(update, Update) and bool(update.pre_checkout_query) diff --git a/venv/lib/python3.8/site-packages/telegram/ext/regexhandler.py b/venv/lib/python3.8/site-packages/telegram/ext/regexhandler.py new file mode 100644 index 0000000..399e4df --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/ext/regexhandler.py @@ -0,0 +1,166 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +# TODO: Remove allow_edited +"""This module contains the RegexHandler class.""" + +import warnings +from typing import TYPE_CHECKING, Callable, Dict, Optional, Pattern, TypeVar, Union, Any + +from telegram import Update +from telegram.ext import Filters, MessageHandler +from telegram.utils.deprecate import TelegramDeprecationWarning +from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE +from telegram.ext.utils.types import CCT + +if TYPE_CHECKING: + from telegram.ext import Dispatcher + +RT = TypeVar('RT') + + +class RegexHandler(MessageHandler): + """Handler class to handle Telegram updates based on a regex. + + It uses a regular expression to check text messages. Read the documentation of the ``re`` + module for more information. The ``re.match`` function is used to determine if an update should + be handled by this handler. + + Note: + This handler is being deprecated. For the same use case use: + ``MessageHandler(Filters.regex(r'pattern'), callback)`` + + Warning: + When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom + attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. + + + Args: + pattern (:obj:`str` | :obj:`Pattern`): The regex pattern. + callback (:obj:`callable`): The callback function for this handler. Will be called when + :attr:`check_update` has determined that an update should be processed by this handler. + Callback signature for context based API: + + ``def callback(update: Update, context: CallbackContext)`` + + The return value of the callback is usually ignored except for the special case of + :class:`telegram.ext.ConversationHandler`. + pass_groups (:obj:`bool`, optional): If the callback should be passed the result of + ``re.match(pattern, data).groups()`` as a keyword argument called ``groups``. + Default is :obj:`False` + pass_groupdict (:obj:`bool`, optional): If the callback should be passed the result of + ``re.match(pattern, data).groupdict()`` as a keyword argument called ``groupdict``. + Default is :obj:`False` + pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``update_queue`` will be passed to the callback function. It will be the ``Queue`` + instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher` + that contains new updates which can be used to insert updates. Default is :obj:`False`. + pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``job_queue`` will be passed to the callback function. It will be a + :class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater` + which can be used to schedule new jobs. Default is :obj:`False`. + pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``user_data`` will be passed to the callback function. Default is :obj:`False`. + pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``chat_data`` will be passed to the callback function. Default is :obj:`False`. + message_updates (:obj:`bool`, optional): Should "normal" message updates be handled? + Default is :obj:`True`. + channel_post_updates (:obj:`bool`, optional): Should channel posts updates be handled? + Default is :obj:`True`. + edited_updates (:obj:`bool`, optional): Should "edited" message updates be handled? Default + is :obj:`False`. + run_async (:obj:`bool`): Determines whether the callback will run asynchronously. + Defaults to :obj:`False`. + + Raises: + ValueError + + Attributes: + pattern (:obj:`str` | :obj:`Pattern`): The regex pattern. + callback (:obj:`callable`): The callback function for this handler. + pass_groups (:obj:`bool`): Determines whether ``groups`` will be passed to the + callback function. + pass_groupdict (:obj:`bool`): Determines whether ``groupdict``. will be passed to + the callback function. + pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be + passed to the callback function. + pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to + the callback function. + pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to + the callback function. + pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to + the callback function. + run_async (:obj:`bool`): Determines whether the callback will run asynchronously. + + """ + + __slots__ = ('pass_groups', 'pass_groupdict') + + def __init__( + self, + pattern: Union[str, Pattern], + callback: Callable[[Update, CCT], RT], + pass_groups: bool = False, + pass_groupdict: bool = False, + pass_update_queue: bool = False, + pass_job_queue: bool = False, + pass_user_data: bool = False, + pass_chat_data: bool = False, + allow_edited: bool = False, # pylint: disable=W0613 + message_updates: bool = True, + channel_post_updates: bool = False, + edited_updates: bool = False, + run_async: Union[bool, DefaultValue] = DEFAULT_FALSE, + ): + warnings.warn( + 'RegexHandler is deprecated. See https://git.io/fxJuV for more info', + TelegramDeprecationWarning, + stacklevel=2, + ) + super().__init__( + Filters.regex(pattern), + callback, + pass_update_queue=pass_update_queue, + pass_job_queue=pass_job_queue, + pass_user_data=pass_user_data, + pass_chat_data=pass_chat_data, + message_updates=message_updates, + channel_post_updates=channel_post_updates, + edited_updates=edited_updates, + run_async=run_async, + ) + self.pass_groups = pass_groups + self.pass_groupdict = pass_groupdict + + def collect_optional_args( + self, + dispatcher: 'Dispatcher', + update: Update = None, + check_result: Optional[Union[bool, Dict[str, Any]]] = None, + ) -> Dict[str, object]: + """Pass the results of ``re.match(pattern, text).{groups(), groupdict()}`` to the + callback as a keyword arguments called ``groups`` and ``groupdict``, respectively, if + needed. + """ + optional_args = super().collect_optional_args(dispatcher, update, check_result) + if isinstance(check_result, dict): + if self.pass_groups: + optional_args['groups'] = check_result['matches'][0].groups() + if self.pass_groupdict: + optional_args['groupdict'] = check_result['matches'][0].groupdict() + return optional_args diff --git a/venv/lib/python3.8/site-packages/telegram/ext/shippingqueryhandler.py b/venv/lib/python3.8/site-packages/telegram/ext/shippingqueryhandler.py new file mode 100644 index 0000000..e4229ce --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/ext/shippingqueryhandler.py @@ -0,0 +1,97 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the ShippingQueryHandler class.""" + + +from telegram import Update +from .handler import Handler +from .utils.types import CCT + + +class ShippingQueryHandler(Handler[Update, CCT]): + """Handler class to handle Telegram shipping callback queries. + + Note: + :attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you + can use to keep any data in will be sent to the :attr:`callback` function. Related to + either the user or the chat that the update was sent in. For each update from the same user + or in the same chat, it will be the same ``dict``. + + Note that this is DEPRECATED, and you should use context based callbacks. See + https://git.io/fxJuV for more info. + + Warning: + When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom + attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. + + Args: + callback (:obj:`callable`): The callback function for this handler. Will be called when + :attr:`check_update` has determined that an update should be processed by this handler. + Callback signature for context based API: + + ``def callback(update: Update, context: CallbackContext)`` + + The return value of the callback is usually ignored except for the special case of + :class:`telegram.ext.ConversationHandler`. + pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``update_queue`` will be passed to the callback function. It will be the ``Queue`` + instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher` + that contains new updates which can be used to insert updates. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``job_queue`` will be passed to the callback function. It will be a + :class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater` + which can be used to schedule new jobs. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``user_data`` will be passed to the callback function. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``chat_data`` will be passed to the callback function. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + run_async (:obj:`bool`): Determines whether the callback will run asynchronously. + Defaults to :obj:`False`. + + Attributes: + callback (:obj:`callable`): The callback function for this handler. + pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be + passed to the callback function. + pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to + the callback function. + pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to + the callback function. + pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to + the callback function. + run_async (:obj:`bool`): Determines whether the callback will run asynchronously. + + """ + + __slots__ = () + + def check_update(self, update: object) -> bool: + """Determines whether an update should be passed to this handlers :attr:`callback`. + + Args: + update (:class:`telegram.Update` | :obj:`object`): Incoming update. + + Returns: + :obj:`bool` + + """ + return isinstance(update, Update) and bool(update.shipping_query) diff --git a/venv/lib/python3.8/site-packages/telegram/ext/stringcommandhandler.py b/venv/lib/python3.8/site-packages/telegram/ext/stringcommandhandler.py new file mode 100644 index 0000000..1d84892 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/ext/stringcommandhandler.py @@ -0,0 +1,149 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the StringCommandHandler class.""" + +from typing import TYPE_CHECKING, Callable, Dict, List, Optional, TypeVar, Union + +from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE + +from .handler import Handler +from .utils.types import CCT + +if TYPE_CHECKING: + from telegram.ext import Dispatcher + +RT = TypeVar('RT') + + +class StringCommandHandler(Handler[str, CCT]): + """Handler class to handle string commands. Commands are string updates that start with ``/``. + The handler will add a ``list`` to the + :class:`CallbackContext` named :attr:`CallbackContext.args`. It will contain a list of strings, + which is the text following the command split on single whitespace characters. + + Note: + This handler is not used to handle Telegram :attr:`telegram.Update`, but strings manually + put in the queue. For example to send messages with the bot using command line or API. + + Warning: + When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom + attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. + + Args: + command (:obj:`str`): The command this handler should listen for. + callback (:obj:`callable`): The callback function for this handler. Will be called when + :attr:`check_update` has determined that an update should be processed by this handler. + Callback signature for context based API: + + ``def callback(update: Update, context: CallbackContext)`` + + The return value of the callback is usually ignored except for the special case of + :class:`telegram.ext.ConversationHandler`. + pass_args (:obj:`bool`, optional): Determines whether the handler should be passed the + arguments passed to the command as a keyword argument called ``args``. It will contain + a list of strings, which is the text following the command split on single or + consecutive whitespace characters. Default is :obj:`False` + DEPRECATED: Please switch to context based callbacks. + pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``update_queue`` will be passed to the callback function. It will be the ``Queue`` + instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher` + that contains new updates which can be used to insert updates. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``job_queue`` will be passed to the callback function. It will be a + class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater` + which can be used to schedule new jobs. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + run_async (:obj:`bool`): Determines whether the callback will run asynchronously. + Defaults to :obj:`False`. + + Attributes: + command (:obj:`str`): The command this handler should listen for. + callback (:obj:`callable`): The callback function for this handler. + pass_args (:obj:`bool`): Determines whether the handler should be passed + ``args``. + pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be + passed to the callback function. + pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to + the callback function. + run_async (:obj:`bool`): Determines whether the callback will run asynchronously. + + """ + + __slots__ = ('command', 'pass_args') + + def __init__( + self, + command: str, + callback: Callable[[str, CCT], RT], + pass_args: bool = False, + pass_update_queue: bool = False, + pass_job_queue: bool = False, + run_async: Union[bool, DefaultValue] = DEFAULT_FALSE, + ): + super().__init__( + callback, + pass_update_queue=pass_update_queue, + pass_job_queue=pass_job_queue, + run_async=run_async, + ) + self.command = command + self.pass_args = pass_args + + def check_update(self, update: object) -> Optional[List[str]]: + """Determines whether an update should be passed to this handlers :attr:`callback`. + + Args: + update (:obj:`object`): The incoming update. + + Returns: + :obj:`bool` + + """ + if isinstance(update, str) and update.startswith('/'): + args = update[1:].split(' ') + if args[0] == self.command: + return args[1:] + return None + + def collect_optional_args( + self, + dispatcher: 'Dispatcher', + update: str = None, + check_result: Optional[List[str]] = None, + ) -> Dict[str, object]: + """Provide text after the command to the callback the ``args`` argument as list, split on + single whitespaces. + """ + optional_args = super().collect_optional_args(dispatcher, update, check_result) + if self.pass_args: + optional_args['args'] = check_result + return optional_args + + def collect_additional_context( + self, + context: CCT, + update: str, + dispatcher: 'Dispatcher', + check_result: Optional[List[str]], + ) -> None: + """Add text after the command to :attr:`CallbackContext.args` as list, split on single + whitespaces. + """ + context.args = check_result diff --git a/venv/lib/python3.8/site-packages/telegram/ext/stringregexhandler.py b/venv/lib/python3.8/site-packages/telegram/ext/stringregexhandler.py new file mode 100644 index 0000000..282c48a --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/ext/stringregexhandler.py @@ -0,0 +1,166 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the StringRegexHandler class.""" + +import re +from typing import TYPE_CHECKING, Callable, Dict, Match, Optional, Pattern, TypeVar, Union + +from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE + +from .handler import Handler +from .utils.types import CCT + +if TYPE_CHECKING: + from telegram.ext import Dispatcher + +RT = TypeVar('RT') + + +class StringRegexHandler(Handler[str, CCT]): + """Handler class to handle string updates based on a regex which checks the update content. + + Read the documentation of the ``re`` module for more information. The ``re.match`` function is + used to determine if an update should be handled by this handler. + + Note: + This handler is not used to handle Telegram :attr:`telegram.Update`, but strings manually + put in the queue. For example to send messages with the bot using command line or API. + + Warning: + When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom + attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. + + Args: + pattern (:obj:`str` | :obj:`Pattern`): The regex pattern. + callback (:obj:`callable`): The callback function for this handler. Will be called when + :attr:`check_update` has determined that an update should be processed by this handler. + Callback signature for context based API: + + ``def callback(update: Update, context: CallbackContext)`` + + The return value of the callback is usually ignored except for the special case of + :class:`telegram.ext.ConversationHandler`. + pass_groups (:obj:`bool`, optional): If the callback should be passed the result of + ``re.match(pattern, data).groups()`` as a keyword argument called ``groups``. + Default is :obj:`False` + DEPRECATED: Please switch to context based callbacks. + pass_groupdict (:obj:`bool`, optional): If the callback should be passed the result of + ``re.match(pattern, data).groupdict()`` as a keyword argument called ``groupdict``. + Default is :obj:`False` + DEPRECATED: Please switch to context based callbacks. + pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``update_queue`` will be passed to the callback function. It will be the ``Queue`` + instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher` + that contains new updates which can be used to insert updates. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``job_queue`` will be passed to the callback function. It will be a + :class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater` + which can be used to schedule new jobs. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + run_async (:obj:`bool`): Determines whether the callback will run asynchronously. + Defaults to :obj:`False`. + + Attributes: + pattern (:obj:`str` | :obj:`Pattern`): The regex pattern. + callback (:obj:`callable`): The callback function for this handler. + pass_groups (:obj:`bool`): Determines whether ``groups`` will be passed to the + callback function. + pass_groupdict (:obj:`bool`): Determines whether ``groupdict``. will be passed to + the callback function. + pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be + passed to the callback function. + pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to + the callback function. + run_async (:obj:`bool`): Determines whether the callback will run asynchronously. + + """ + + __slots__ = ('pass_groups', 'pass_groupdict', 'pattern') + + def __init__( + self, + pattern: Union[str, Pattern], + callback: Callable[[str, CCT], RT], + pass_groups: bool = False, + pass_groupdict: bool = False, + pass_update_queue: bool = False, + pass_job_queue: bool = False, + run_async: Union[bool, DefaultValue] = DEFAULT_FALSE, + ): + super().__init__( + callback, + pass_update_queue=pass_update_queue, + pass_job_queue=pass_job_queue, + run_async=run_async, + ) + + if isinstance(pattern, str): + pattern = re.compile(pattern) + + self.pattern = pattern + self.pass_groups = pass_groups + self.pass_groupdict = pass_groupdict + + def check_update(self, update: object) -> Optional[Match]: + """Determines whether an update should be passed to this handlers :attr:`callback`. + + Args: + update (:obj:`object`): The incoming update. + + Returns: + :obj:`bool` + + """ + if isinstance(update, str): + match = re.match(self.pattern, update) + if match: + return match + return None + + def collect_optional_args( + self, + dispatcher: 'Dispatcher', + update: str = None, + check_result: Optional[Match] = None, + ) -> Dict[str, object]: + """Pass the results of ``re.match(pattern, update).{groups(), groupdict()}`` to the + callback as a keyword arguments called ``groups`` and ``groupdict``, respectively, if + needed. + """ + optional_args = super().collect_optional_args(dispatcher, update, check_result) + if self.pattern: + if self.pass_groups and check_result: + optional_args['groups'] = check_result.groups() + if self.pass_groupdict and check_result: + optional_args['groupdict'] = check_result.groupdict() + return optional_args + + def collect_additional_context( + self, + context: CCT, + update: str, + dispatcher: 'Dispatcher', + check_result: Optional[Match], + ) -> None: + """Add the result of ``re.match(pattern, update)`` to :attr:`CallbackContext.matches` as + list with one element. + """ + if self.pattern and check_result: + context.matches = [check_result] diff --git a/venv/lib/python3.8/site-packages/telegram/ext/typehandler.py b/venv/lib/python3.8/site-packages/telegram/ext/typehandler.py new file mode 100644 index 0000000..531d10c --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/ext/typehandler.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the TypeHandler class.""" + +from typing import Callable, Type, TypeVar, Union +from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE + +from .handler import Handler +from .utils.types import CCT + +RT = TypeVar('RT') +UT = TypeVar('UT') + + +class TypeHandler(Handler[UT, CCT]): + """Handler class to handle updates of custom types. + + Warning: + When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom + attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. + + Args: + type (:obj:`type`): The ``type`` of updates this handler should process, as + determined by ``isinstance`` + callback (:obj:`callable`): The callback function for this handler. Will be called when + :attr:`check_update` has determined that an update should be processed by this handler. + Callback signature for context based API: + + ``def callback(update: Update, context: CallbackContext)`` + + The return value of the callback is usually ignored except for the special case of + :class:`telegram.ext.ConversationHandler`. + strict (:obj:`bool`, optional): Use ``type`` instead of ``isinstance``. + Default is :obj:`False` + pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``update_queue`` will be passed to the callback function. It will be the ``Queue`` + instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher` + that contains new updates which can be used to insert updates. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called + ``job_queue`` will be passed to the callback function. It will be a + :class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater` + which can be used to schedule new jobs. Default is :obj:`False`. + DEPRECATED: Please switch to context based callbacks. + run_async (:obj:`bool`): Determines whether the callback will run asynchronously. + Defaults to :obj:`False`. + + Attributes: + type (:obj:`type`): The ``type`` of updates this handler should process. + callback (:obj:`callable`): The callback function for this handler. + strict (:obj:`bool`): Use ``type`` instead of ``isinstance``. Default is :obj:`False`. + pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be + passed to the callback function. + pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to + the callback function. + run_async (:obj:`bool`): Determines whether the callback will run asynchronously. + + """ + + __slots__ = ('type', 'strict') + + def __init__( + self, + type: Type[UT], # pylint: disable=W0622 + callback: Callable[[UT, CCT], RT], + strict: bool = False, + pass_update_queue: bool = False, + pass_job_queue: bool = False, + run_async: Union[bool, DefaultValue] = DEFAULT_FALSE, + ): + super().__init__( + callback, + pass_update_queue=pass_update_queue, + pass_job_queue=pass_job_queue, + run_async=run_async, + ) + self.type = type # pylint: disable=E0237 + self.strict = strict # pylint: disable=E0237 + + def check_update(self, update: object) -> bool: + """Determines whether an update should be passed to this handlers :attr:`callback`. + + Args: + update (:obj:`object`): Incoming update. + + Returns: + :obj:`bool` + + """ + if not self.strict: + return isinstance(update, self.type) + return type(update) is self.type # pylint: disable=C0123 diff --git a/venv/lib/python3.8/site-packages/telegram/ext/updater.py b/venv/lib/python3.8/site-packages/telegram/ext/updater.py new file mode 100644 index 0000000..37a2e7e --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/ext/updater.py @@ -0,0 +1,890 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the class Updater, which tries to make creating Telegram bots intuitive.""" + +import logging +import ssl +import warnings +from queue import Queue +from signal import SIGABRT, SIGINT, SIGTERM, signal +from threading import Event, Lock, Thread, current_thread +from time import sleep +from typing import ( + TYPE_CHECKING, + Any, + Callable, + Dict, + List, + Optional, + Tuple, + Union, + no_type_check, + Generic, + overload, +) + +from telegram import Bot, TelegramError +from telegram.error import InvalidToken, RetryAfter, TimedOut, Unauthorized +from telegram.ext import Dispatcher, JobQueue, ContextTypes, ExtBot +from telegram.utils.deprecate import TelegramDeprecationWarning, set_new_attribute_deprecated +from telegram.utils.helpers import get_signal_name, DEFAULT_FALSE, DefaultValue +from telegram.utils.request import Request +from telegram.ext.utils.types import CCT, UD, CD, BD +from telegram.ext.utils.webhookhandler import WebhookAppClass, WebhookServer + +if TYPE_CHECKING: + from telegram.ext import BasePersistence, Defaults, CallbackContext + + +class Updater(Generic[CCT, UD, CD, BD]): + """ + This class, which employs the :class:`telegram.ext.Dispatcher`, provides a frontend to + :class:`telegram.Bot` to the programmer, so they can focus on coding the bot. Its purpose is to + receive the updates from Telegram and to deliver them to said dispatcher. It also runs in a + separate thread, so the user can interact with the bot, for example on the command line. The + dispatcher supports handlers for different kinds of data: Updates from Telegram, basic text + commands and even arbitrary types. The updater can be started as a polling service or, for + production, use a webhook to receive updates. This is achieved using the WebhookServer and + WebhookHandler classes. + + Note: + * You must supply either a :attr:`bot` or a :attr:`token` argument. + * If you supply a :attr:`bot`, you will need to pass :attr:`arbitrary_callback_data`, + and :attr:`defaults` to the bot instead of the :class:`telegram.ext.Updater`. In this + case, you'll have to use the class :class:`telegram.ext.ExtBot`. + + .. versionchanged:: 13.6 + + Args: + token (:obj:`str`, optional): The bot's token given by the @BotFather. + base_url (:obj:`str`, optional): Base_url for the bot. + base_file_url (:obj:`str`, optional): Base_file_url for the bot. + workers (:obj:`int`, optional): Amount of threads in the thread pool for functions + decorated with ``@run_async`` (ignored if `dispatcher` argument is used). + bot (:class:`telegram.Bot`, optional): A pre-initialized bot instance (ignored if + `dispatcher` argument is used). If a pre-initialized bot is used, it is the user's + responsibility to create it using a `Request` instance with a large enough connection + pool. + dispatcher (:class:`telegram.ext.Dispatcher`, optional): A pre-initialized dispatcher + instance. If a pre-initialized dispatcher is used, it is the user's responsibility to + create it with proper arguments. + private_key (:obj:`bytes`, optional): Private key for decryption of telegram passport data. + private_key_password (:obj:`bytes`, optional): Password for above private key. + user_sig_handler (:obj:`function`, optional): Takes ``signum, frame`` as positional + arguments. This will be called when a signal is received, defaults are (SIGINT, + SIGTERM, SIGABRT) settable with :attr:`idle`. + request_kwargs (:obj:`dict`, optional): Keyword args to control the creation of a + `telegram.utils.request.Request` object (ignored if `bot` or `dispatcher` argument is + used). The request_kwargs are very useful for the advanced users who would like to + control the default timeouts and/or control the proxy used for http communication. + use_context (:obj:`bool`, optional): If set to :obj:`True` uses the context based callback + API (ignored if `dispatcher` argument is used). Defaults to :obj:`True`. + **New users**: set this to :obj:`True`. + persistence (:class:`telegram.ext.BasePersistence`, optional): The persistence class to + store data that should be persistent over restarts (ignored if `dispatcher` argument is + used). + defaults (:class:`telegram.ext.Defaults`, optional): An object containing default values to + be used if not set explicitly in the bot methods. + arbitrary_callback_data (:obj:`bool` | :obj:`int` | :obj:`None`, optional): Whether to + allow arbitrary objects as callback data for :class:`telegram.InlineKeyboardButton`. + Pass an integer to specify the maximum number of cached objects. For more details, + please see our wiki. Defaults to :obj:`False`. + + .. versionadded:: 13.6 + context_types (:class:`telegram.ext.ContextTypes`, optional): Pass an instance + of :class:`telegram.ext.ContextTypes` to customize the types used in the + ``context`` interface. If not passed, the defaults documented in + :class:`telegram.ext.ContextTypes` will be used. + + .. versionadded:: 13.6 + + Raises: + ValueError: If both :attr:`token` and :attr:`bot` are passed or none of them. + + + Attributes: + bot (:class:`telegram.Bot`): The bot used with this Updater. + user_sig_handler (:obj:`function`): Optional. Function to be called when a signal is + received. + update_queue (:obj:`Queue`): Queue for the updates. + job_queue (:class:`telegram.ext.JobQueue`): Jobqueue for the updater. + dispatcher (:class:`telegram.ext.Dispatcher`): Dispatcher that handles the updates and + dispatches them to the handlers. + running (:obj:`bool`): Indicates if the updater is running. + persistence (:class:`telegram.ext.BasePersistence`): Optional. The persistence class to + store data that should be persistent over restarts. + use_context (:obj:`bool`): Optional. :obj:`True` if using context based callbacks. + + """ + + __slots__ = ( + 'persistence', + 'dispatcher', + 'user_sig_handler', + 'bot', + 'logger', + 'update_queue', + 'job_queue', + '__exception_event', + 'last_update_id', + 'running', + '_request', + 'is_idle', + 'httpd', + '__lock', + '__threads', + '__dict__', + ) + + @overload + def __init__( + self: 'Updater[CallbackContext, dict, dict, dict]', + token: str = None, + base_url: str = None, + workers: int = 4, + bot: Bot = None, + private_key: bytes = None, + private_key_password: bytes = None, + user_sig_handler: Callable = None, + request_kwargs: Dict[str, Any] = None, + persistence: 'BasePersistence' = None, # pylint: disable=E0601 + defaults: 'Defaults' = None, + use_context: bool = True, + base_file_url: str = None, + arbitrary_callback_data: Union[DefaultValue, bool, int, None] = DEFAULT_FALSE, + ): + ... + + @overload + def __init__( + self: 'Updater[CCT, UD, CD, BD]', + token: str = None, + base_url: str = None, + workers: int = 4, + bot: Bot = None, + private_key: bytes = None, + private_key_password: bytes = None, + user_sig_handler: Callable = None, + request_kwargs: Dict[str, Any] = None, + persistence: 'BasePersistence' = None, + defaults: 'Defaults' = None, + use_context: bool = True, + base_file_url: str = None, + arbitrary_callback_data: Union[DefaultValue, bool, int, None] = DEFAULT_FALSE, + context_types: ContextTypes[CCT, UD, CD, BD] = None, + ): + ... + + @overload + def __init__( + self: 'Updater[CCT, UD, CD, BD]', + user_sig_handler: Callable = None, + dispatcher: Dispatcher[CCT, UD, CD, BD] = None, + ): + ... + + def __init__( # type: ignore[no-untyped-def,misc] + self, + token: str = None, + base_url: str = None, + workers: int = 4, + bot: Bot = None, + private_key: bytes = None, + private_key_password: bytes = None, + user_sig_handler: Callable = None, + request_kwargs: Dict[str, Any] = None, + persistence: 'BasePersistence' = None, + defaults: 'Defaults' = None, + use_context: bool = True, + dispatcher=None, + base_file_url: str = None, + arbitrary_callback_data: Union[DefaultValue, bool, int, None] = DEFAULT_FALSE, + context_types: ContextTypes[CCT, UD, CD, BD] = None, + ): + + if defaults and bot: + warnings.warn( + 'Passing defaults to an Updater has no effect when a Bot is passed ' + 'as well. Pass them to the Bot instead.', + TelegramDeprecationWarning, + stacklevel=2, + ) + if arbitrary_callback_data is not DEFAULT_FALSE and bot: + warnings.warn( + 'Passing arbitrary_callback_data to an Updater has no ' + 'effect when a Bot is passed as well. Pass them to the Bot instead.', + stacklevel=2, + ) + + if dispatcher is None: + if (token is None) and (bot is None): + raise ValueError('`token` or `bot` must be passed') + if (token is not None) and (bot is not None): + raise ValueError('`token` and `bot` are mutually exclusive') + if (private_key is not None) and (bot is not None): + raise ValueError('`bot` and `private_key` are mutually exclusive') + else: + if bot is not None: + raise ValueError('`dispatcher` and `bot` are mutually exclusive') + if persistence is not None: + raise ValueError('`dispatcher` and `persistence` are mutually exclusive') + if use_context != dispatcher.use_context: + raise ValueError('`dispatcher` and `use_context` are mutually exclusive') + if context_types is not None: + raise ValueError('`dispatcher` and `context_types` are mutually exclusive') + if workers is not None: + raise ValueError('`dispatcher` and `workers` are mutually exclusive') + + self.logger = logging.getLogger(__name__) + self._request = None + + if dispatcher is None: + con_pool_size = workers + 4 + + if bot is not None: + self.bot = bot + if bot.request.con_pool_size < con_pool_size: + self.logger.warning( + 'Connection pool of Request object is smaller than optimal value (%s)', + con_pool_size, + ) + else: + # we need a connection pool the size of: + # * for each of the workers + # * 1 for Dispatcher + # * 1 for polling Updater (even if webhook is used, we can spare a connection) + # * 1 for JobQueue + # * 1 for main thread + if request_kwargs is None: + request_kwargs = {} + if 'con_pool_size' not in request_kwargs: + request_kwargs['con_pool_size'] = con_pool_size + self._request = Request(**request_kwargs) + self.bot = ExtBot( + token, # type: ignore[arg-type] + base_url, + base_file_url=base_file_url, + request=self._request, + private_key=private_key, + private_key_password=private_key_password, + defaults=defaults, + arbitrary_callback_data=( + False # type: ignore[arg-type] + if arbitrary_callback_data is DEFAULT_FALSE + else arbitrary_callback_data + ), + ) + self.update_queue: Queue = Queue() + self.job_queue = JobQueue() + self.__exception_event = Event() + self.persistence = persistence + self.dispatcher = Dispatcher( + self.bot, + self.update_queue, + job_queue=self.job_queue, + workers=workers, + exception_event=self.__exception_event, + persistence=persistence, + use_context=use_context, + context_types=context_types, + ) + self.job_queue.set_dispatcher(self.dispatcher) + else: + con_pool_size = dispatcher.workers + 4 + + self.bot = dispatcher.bot + if self.bot.request.con_pool_size < con_pool_size: + self.logger.warning( + 'Connection pool of Request object is smaller than optimal value (%s)', + con_pool_size, + ) + self.update_queue = dispatcher.update_queue + self.__exception_event = dispatcher.exception_event + self.persistence = dispatcher.persistence + self.job_queue = dispatcher.job_queue + self.dispatcher = dispatcher + + self.user_sig_handler = user_sig_handler + self.last_update_id = 0 + self.running = False + self.is_idle = False + self.httpd = None + self.__lock = Lock() + self.__threads: List[Thread] = [] + + def __setattr__(self, key: str, value: object) -> None: + if key.startswith('__'): + key = f"_{self.__class__.__name__}{key}" + if issubclass(self.__class__, Updater) and self.__class__ is not Updater: + object.__setattr__(self, key, value) + return + set_new_attribute_deprecated(self, key, value) + + def _init_thread(self, target: Callable, name: str, *args: object, **kwargs: object) -> None: + thr = Thread( + target=self._thread_wrapper, + name=f"Bot:{self.bot.id}:{name}", + args=(target,) + args, + kwargs=kwargs, + ) + thr.start() + self.__threads.append(thr) + + def _thread_wrapper(self, target: Callable, *args: object, **kwargs: object) -> None: + thr_name = current_thread().name + self.logger.debug('%s - started', thr_name) + try: + target(*args, **kwargs) + except Exception: + self.__exception_event.set() + self.logger.exception('unhandled exception in %s', thr_name) + raise + self.logger.debug('%s - ended', thr_name) + + def start_polling( + self, + poll_interval: float = 0.0, + timeout: float = 10, + clean: bool = None, + bootstrap_retries: int = -1, + read_latency: float = 2.0, + allowed_updates: List[str] = None, + drop_pending_updates: bool = None, + ) -> Optional[Queue]: + """Starts polling updates from Telegram. + + Args: + poll_interval (:obj:`float`, optional): Time to wait between polling updates from + Telegram in seconds. Default is ``0.0``. + timeout (:obj:`float`, optional): Passed to :meth:`telegram.Bot.get_updates`. + drop_pending_updates (:obj:`bool`, optional): Whether to clean any pending updates on + Telegram servers before actually starting to poll. Default is :obj:`False`. + + .. versionadded :: 13.4 + clean (:obj:`bool`, optional): Alias for ``drop_pending_updates``. + + .. deprecated:: 13.4 + Use ``drop_pending_updates`` instead. + bootstrap_retries (:obj:`int`, optional): Whether the bootstrapping phase of the + :class:`telegram.ext.Updater` will retry on failures on the Telegram server. + + * < 0 - retry indefinitely (default) + * 0 - no retries + * > 0 - retry up to X times + + allowed_updates (List[:obj:`str`], optional): Passed to + :meth:`telegram.Bot.get_updates`. + read_latency (:obj:`float` | :obj:`int`, optional): Grace time in seconds for receiving + the reply from server. Will be added to the ``timeout`` value and used as the read + timeout from server (Default: ``2``). + + Returns: + :obj:`Queue`: The update queue that can be filled from the main thread. + + """ + if (clean is not None) and (drop_pending_updates is not None): + raise TypeError('`clean` and `drop_pending_updates` are mutually exclusive.') + + if clean is not None: + warnings.warn( + 'The argument `clean` of `start_polling` is deprecated. Please use ' + '`drop_pending_updates` instead.', + category=TelegramDeprecationWarning, + stacklevel=2, + ) + + drop_pending_updates = drop_pending_updates if drop_pending_updates is not None else clean + + with self.__lock: + if not self.running: + self.running = True + + # Create & start threads + self.job_queue.start() + dispatcher_ready = Event() + polling_ready = Event() + self._init_thread(self.dispatcher.start, "dispatcher", ready=dispatcher_ready) + self._init_thread( + self._start_polling, + "updater", + poll_interval, + timeout, + read_latency, + bootstrap_retries, + drop_pending_updates, + allowed_updates, + ready=polling_ready, + ) + + self.logger.debug('Waiting for Dispatcher and polling to start') + dispatcher_ready.wait() + polling_ready.wait() + + # Return the update queue so the main thread can insert updates + return self.update_queue + return None + + def start_webhook( + self, + listen: str = '127.0.0.1', + port: int = 80, + url_path: str = '', + cert: str = None, + key: str = None, + clean: bool = None, + bootstrap_retries: int = 0, + webhook_url: str = None, + allowed_updates: List[str] = None, + force_event_loop: bool = None, + drop_pending_updates: bool = None, + ip_address: str = None, + max_connections: int = 40, + ) -> Optional[Queue]: + """ + Starts a small http server to listen for updates via webhook. If :attr:`cert` + and :attr:`key` are not provided, the webhook will be started directly on + http://listen:port/url_path, so SSL can be handled by another + application. Else, the webhook will be started on + https://listen:port/url_path. Also calls :meth:`telegram.Bot.set_webhook` as required. + + .. versionchanged:: 13.4 + :meth:`start_webhook` now *always* calls :meth:`telegram.Bot.set_webhook`, so pass + ``webhook_url`` instead of calling ``updater.bot.set_webhook(webhook_url)`` manually. + + Args: + listen (:obj:`str`, optional): IP-Address to listen on. Default ``127.0.0.1``. + port (:obj:`int`, optional): Port the bot should be listening on. Default ``80``. + url_path (:obj:`str`, optional): Path inside url. + cert (:obj:`str`, optional): Path to the SSL certificate file. + key (:obj:`str`, optional): Path to the SSL key file. + drop_pending_updates (:obj:`bool`, optional): Whether to clean any pending updates on + Telegram servers before actually starting to poll. Default is :obj:`False`. + + .. versionadded :: 13.4 + clean (:obj:`bool`, optional): Alias for ``drop_pending_updates``. + + .. deprecated:: 13.4 + Use ``drop_pending_updates`` instead. + bootstrap_retries (:obj:`int`, optional): Whether the bootstrapping phase of the + :class:`telegram.ext.Updater` will retry on failures on the Telegram server. + + * < 0 - retry indefinitely (default) + * 0 - no retries + * > 0 - retry up to X times + + webhook_url (:obj:`str`, optional): Explicitly specify the webhook url. Useful behind + NAT, reverse proxy, etc. Default is derived from ``listen``, ``port`` & + ``url_path``. + ip_address (:obj:`str`, optional): Passed to :meth:`telegram.Bot.set_webhook`. + + .. versionadded :: 13.4 + allowed_updates (List[:obj:`str`], optional): Passed to + :meth:`telegram.Bot.set_webhook`. + force_event_loop (:obj:`bool`, optional): Legacy parameter formerly used for a + workaround on Windows + Python 3.8+. No longer has any effect. + + .. deprecated:: 13.6 + Since version 13.6, ``tornade>=6.1`` is required, which resolves the former + issue. + + max_connections (:obj:`int`, optional): Passed to + :meth:`telegram.Bot.set_webhook`. + + .. versionadded:: 13.6 + + Returns: + :obj:`Queue`: The update queue that can be filled from the main thread. + + """ + if (clean is not None) and (drop_pending_updates is not None): + raise TypeError('`clean` and `drop_pending_updates` are mutually exclusive.') + + if clean is not None: + warnings.warn( + 'The argument `clean` of `start_webhook` is deprecated. Please use ' + '`drop_pending_updates` instead.', + category=TelegramDeprecationWarning, + stacklevel=2, + ) + + if force_event_loop is not None: + warnings.warn( + 'The argument `force_event_loop` of `start_webhook` is deprecated and no longer ' + 'has any effect.', + category=TelegramDeprecationWarning, + stacklevel=2, + ) + + drop_pending_updates = drop_pending_updates if drop_pending_updates is not None else clean + + with self.__lock: + if not self.running: + self.running = True + + # Create & start threads + webhook_ready = Event() + dispatcher_ready = Event() + self.job_queue.start() + self._init_thread(self.dispatcher.start, "dispatcher", dispatcher_ready) + self._init_thread( + self._start_webhook, + "updater", + listen, + port, + url_path, + cert, + key, + bootstrap_retries, + drop_pending_updates, + webhook_url, + allowed_updates, + ready=webhook_ready, + ip_address=ip_address, + max_connections=max_connections, + ) + + self.logger.debug('Waiting for Dispatcher and Webhook to start') + webhook_ready.wait() + dispatcher_ready.wait() + + # Return the update queue so the main thread can insert updates + return self.update_queue + return None + + @no_type_check + def _start_polling( + self, + poll_interval, + timeout, + read_latency, + bootstrap_retries, + drop_pending_updates, + allowed_updates, + ready=None, + ): # pragma: no cover + # Thread target of thread 'updater'. Runs in background, pulls + # updates from Telegram and inserts them in the update queue of the + # Dispatcher. + + self.logger.debug('Updater thread started (polling)') + + self._bootstrap( + bootstrap_retries, + drop_pending_updates=drop_pending_updates, + webhook_url='', + allowed_updates=None, + ) + + self.logger.debug('Bootstrap done') + + def polling_action_cb(): + updates = self.bot.get_updates( + self.last_update_id, + timeout=timeout, + read_latency=read_latency, + allowed_updates=allowed_updates, + ) + + if updates: + if not self.running: + self.logger.debug('Updates ignored and will be pulled again on restart') + else: + for update in updates: + self.update_queue.put(update) + self.last_update_id = updates[-1].update_id + 1 + + return True + + def polling_onerr_cb(exc): + # Put the error into the update queue and let the Dispatcher + # broadcast it + self.update_queue.put(exc) + + if ready is not None: + ready.set() + + self._network_loop_retry( + polling_action_cb, polling_onerr_cb, 'getting Updates', poll_interval + ) + + @no_type_check + def _network_loop_retry(self, action_cb, onerr_cb, description, interval): + """Perform a loop calling `action_cb`, retrying after network errors. + + Stop condition for loop: `self.running` evaluates :obj:`False` or return value of + `action_cb` evaluates :obj:`False`. + + Args: + action_cb (:obj:`callable`): Network oriented callback function to call. + onerr_cb (:obj:`callable`): Callback to call when TelegramError is caught. Receives the + exception object as a parameter. + description (:obj:`str`): Description text to use for logs and exception raised. + interval (:obj:`float` | :obj:`int`): Interval to sleep between each call to + `action_cb`. + + """ + self.logger.debug('Start network loop retry %s', description) + cur_interval = interval + while self.running: + try: + if not action_cb(): + break + except RetryAfter as exc: + self.logger.info('%s', exc) + cur_interval = 0.5 + exc.retry_after + except TimedOut as toe: + self.logger.debug('Timed out %s: %s', description, toe) + # If failure is due to timeout, we should retry asap. + cur_interval = 0 + except InvalidToken as pex: + self.logger.error('Invalid token; aborting') + raise pex + except TelegramError as telegram_exc: + self.logger.error('Error while %s: %s', description, telegram_exc) + onerr_cb(telegram_exc) + cur_interval = self._increase_poll_interval(cur_interval) + else: + cur_interval = interval + + if cur_interval: + sleep(cur_interval) + + @staticmethod + def _increase_poll_interval(current_interval: float) -> float: + # increase waiting times on subsequent errors up to 30secs + if current_interval == 0: + current_interval = 1 + elif current_interval < 30: + current_interval *= 1.5 + else: + current_interval = min(30.0, current_interval) + return current_interval + + @no_type_check + def _start_webhook( + self, + listen, + port, + url_path, + cert, + key, + bootstrap_retries, + drop_pending_updates, + webhook_url, + allowed_updates, + ready=None, + ip_address=None, + max_connections: int = 40, + ): + self.logger.debug('Updater thread started (webhook)') + + # Note that we only use the SSL certificate for the WebhookServer, if the key is also + # present. This is because the WebhookServer may not actually be in charge of performing + # the SSL handshake, e.g. in case a reverse proxy is used + use_ssl = cert is not None and key is not None + + if not url_path.startswith('/'): + url_path = f'/{url_path}' + + # Create Tornado app instance + app = WebhookAppClass(url_path, self.bot, self.update_queue) + + # Form SSL Context + # An SSLError is raised if the private key does not match with the certificate + if use_ssl: + try: + ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) + ssl_ctx.load_cert_chain(cert, key) + except ssl.SSLError as exc: + raise TelegramError('Invalid SSL Certificate') from exc + else: + ssl_ctx = None + + # Create and start server + self.httpd = WebhookServer(listen, port, app, ssl_ctx) + + if not webhook_url: + webhook_url = self._gen_webhook_url(listen, port, url_path) + + # We pass along the cert to the webhook if present. + cert_file = open(cert, 'rb') if cert is not None else None + self._bootstrap( + max_retries=bootstrap_retries, + drop_pending_updates=drop_pending_updates, + webhook_url=webhook_url, + allowed_updates=allowed_updates, + cert=cert_file, + ip_address=ip_address, + max_connections=max_connections, + ) + if cert_file is not None: + cert_file.close() + + self.httpd.serve_forever(ready=ready) + + @staticmethod + def _gen_webhook_url(listen: str, port: int, url_path: str) -> str: + return f'https://{listen}:{port}{url_path}' + + @no_type_check + def _bootstrap( + self, + max_retries, + drop_pending_updates, + webhook_url, + allowed_updates, + cert=None, + bootstrap_interval=5, + ip_address=None, + max_connections: int = 40, + ): + retries = [0] + + def bootstrap_del_webhook(): + self.logger.debug('Deleting webhook') + if drop_pending_updates: + self.logger.debug('Dropping pending updates from Telegram server') + self.bot.delete_webhook(drop_pending_updates=drop_pending_updates) + return False + + def bootstrap_set_webhook(): + self.logger.debug('Setting webhook') + if drop_pending_updates: + self.logger.debug('Dropping pending updates from Telegram server') + self.bot.set_webhook( + url=webhook_url, + certificate=cert, + allowed_updates=allowed_updates, + ip_address=ip_address, + drop_pending_updates=drop_pending_updates, + max_connections=max_connections, + ) + return False + + def bootstrap_onerr_cb(exc): + if not isinstance(exc, Unauthorized) and (max_retries < 0 or retries[0] < max_retries): + retries[0] += 1 + self.logger.warning( + 'Failed bootstrap phase; try=%s max_retries=%s', retries[0], max_retries + ) + else: + self.logger.error('Failed bootstrap phase after %s retries (%s)', retries[0], exc) + raise exc + + # Dropping pending updates from TG can be efficiently done with the drop_pending_updates + # parameter of delete/start_webhook, even in the case of polling. Also we want to make + # sure that no webhook is configured in case of polling, so we just always call + # delete_webhook for polling + if drop_pending_updates or not webhook_url: + self._network_loop_retry( + bootstrap_del_webhook, + bootstrap_onerr_cb, + 'bootstrap del webhook', + bootstrap_interval, + ) + retries[0] = 0 + + # Restore/set webhook settings, if needed. Again, we don't know ahead if a webhook is set, + # so we set it anyhow. + if webhook_url: + self._network_loop_retry( + bootstrap_set_webhook, + bootstrap_onerr_cb, + 'bootstrap set webhook', + bootstrap_interval, + ) + + def stop(self) -> None: + """Stops the polling/webhook thread, the dispatcher and the job queue.""" + self.job_queue.stop() + with self.__lock: + if self.running or self.dispatcher.has_running_threads: + self.logger.debug('Stopping Updater and Dispatcher...') + + self.running = False + + self._stop_httpd() + self._stop_dispatcher() + self._join_threads() + + # Stop the Request instance only if it was created by the Updater + if self._request: + self._request.stop() + + @no_type_check + def _stop_httpd(self) -> None: + if self.httpd: + self.logger.debug( + 'Waiting for current webhook connection to be ' + 'closed... Send a Telegram message to the bot to exit ' + 'immediately.' + ) + self.httpd.shutdown() + self.httpd = None + + @no_type_check + def _stop_dispatcher(self) -> None: + self.logger.debug('Requesting Dispatcher to stop...') + self.dispatcher.stop() + + @no_type_check + def _join_threads(self) -> None: + for thr in self.__threads: + self.logger.debug('Waiting for %s thread to end', thr.name) + thr.join() + self.logger.debug('%s thread has ended', thr.name) + self.__threads = [] + + @no_type_check + def _signal_handler(self, signum, frame) -> None: + self.is_idle = False + if self.running: + self.logger.info( + 'Received signal %s (%s), stopping...', signum, get_signal_name(signum) + ) + if self.persistence: + # Update user_data, chat_data and bot_data before flushing + self.dispatcher.update_persistence() + self.persistence.flush() + self.stop() + if self.user_sig_handler: + self.user_sig_handler(signum, frame) + else: + self.logger.warning('Exiting immediately!') + # pylint: disable=C0415,W0212 + import os + + os._exit(1) + + def idle(self, stop_signals: Union[List, Tuple] = (SIGINT, SIGTERM, SIGABRT)) -> None: + """Blocks until one of the signals are received and stops the updater. + + Args: + stop_signals (:obj:`list` | :obj:`tuple`): List containing signals from the signal + module that should be subscribed to. :meth:`Updater.stop()` will be called on + receiving one of those signals. Defaults to (``SIGINT``, ``SIGTERM``, ``SIGABRT``). + + """ + for sig in stop_signals: + signal(sig, self._signal_handler) + + self.is_idle = True + + while self.is_idle: + sleep(1) diff --git a/venv/lib/python3.8/site-packages/telegram/ext/utils/__init__.py b/venv/lib/python3.8/site-packages/telegram/ext/utils/__init__.py new file mode 100644 index 0000000..85c96bc --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/ext/utils/__init__.py @@ -0,0 +1,17 @@ +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. diff --git a/venv/lib/python3.8/site-packages/telegram/ext/utils/promise.py b/venv/lib/python3.8/site-packages/telegram/ext/utils/promise.py new file mode 100644 index 0000000..6b54824 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/ext/utils/promise.py @@ -0,0 +1,158 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the Promise class.""" + +import logging +from threading import Event +from typing import Callable, List, Optional, Tuple, TypeVar, Union + +from telegram.utils.deprecate import set_new_attribute_deprecated +from telegram.utils.types import JSONDict + +RT = TypeVar('RT') + + +logger = logging.getLogger(__name__) + + +class Promise: + """A simple Promise implementation for use with the run_async decorator, DelayQueue etc. + + Args: + pooled_function (:obj:`callable`): The callable that will be called concurrently. + args (:obj:`list` | :obj:`tuple`): Positional arguments for :attr:`pooled_function`. + kwargs (:obj:`dict`): Keyword arguments for :attr:`pooled_function`. + update (:class:`telegram.Update` | :obj:`object`, optional): The update this promise is + associated with. + error_handling (:obj:`bool`, optional): Whether exceptions raised by :attr:`func` + may be handled by error handlers. Defaults to :obj:`True`. + + Attributes: + pooled_function (:obj:`callable`): The callable that will be called concurrently. + args (:obj:`list` | :obj:`tuple`): Positional arguments for :attr:`pooled_function`. + kwargs (:obj:`dict`): Keyword arguments for :attr:`pooled_function`. + done (:obj:`threading.Event`): Is set when the result is available. + update (:class:`telegram.Update` | :obj:`object`): Optional. The update this promise is + associated with. + error_handling (:obj:`bool`): Optional. Whether exceptions raised by :attr:`func` + may be handled by error handlers. Defaults to :obj:`True`. + + """ + + __slots__ = ( + 'pooled_function', + 'args', + 'kwargs', + 'update', + 'error_handling', + 'done', + '_done_callback', + '_result', + '_exception', + '__dict__', + ) + + # TODO: Remove error_handling parameter once we drop the @run_async decorator + def __init__( + self, + pooled_function: Callable[..., RT], + args: Union[List, Tuple], + kwargs: JSONDict, + update: object = None, + error_handling: bool = True, + ): + self.pooled_function = pooled_function + self.args = args + self.kwargs = kwargs + self.update = update + self.error_handling = error_handling + self.done = Event() + self._done_callback: Optional[Callable] = None + self._result: Optional[RT] = None + self._exception: Optional[Exception] = None + + def __setattr__(self, key: str, value: object) -> None: + set_new_attribute_deprecated(self, key, value) + + def run(self) -> None: + """Calls the :attr:`pooled_function` callable.""" + try: + self._result = self.pooled_function(*self.args, **self.kwargs) + + except Exception as exc: + self._exception = exc + + finally: + self.done.set() + if self._exception is None and self._done_callback: + try: + self._done_callback(self.result()) + except Exception as exc: + logger.warning( + "`done_callback` of a Promise raised the following exception." + " The exception won't be handled by error handlers." + ) + logger.warning("Full traceback:", exc_info=exc) + + def __call__(self) -> None: + self.run() + + def result(self, timeout: float = None) -> Optional[RT]: + """Return the result of the ``Promise``. + + Args: + timeout (:obj:`float`, optional): Maximum time in seconds to wait for the result to be + calculated. ``None`` means indefinite. Default is ``None``. + + Returns: + Returns the return value of :attr:`pooled_function` or ``None`` if the ``timeout`` + expires. + + Raises: + object exception raised by :attr:`pooled_function`. + """ + self.done.wait(timeout=timeout) + if self._exception is not None: + raise self._exception # pylint: disable=raising-bad-type + return self._result + + def add_done_callback(self, callback: Callable) -> None: + """ + Callback to be run when :class:`telegram.ext.utils.promise.Promise` becomes done. + + Note: + Callback won't be called if :attr:`pooled_function` + raises an exception. + + Args: + callback (:obj:`callable`): The callable that will be called when promise is done. + callback will be called by passing ``Promise.result()`` as only positional argument. + + """ + if self.done.wait(0): + callback(self.result()) + else: + self._done_callback = callback + + @property + def exception(self) -> Optional[Exception]: + """The exception raised by :attr:`pooled_function` or ``None`` if no exception has been + raised (yet). + """ + return self._exception diff --git a/venv/lib/python3.8/site-packages/telegram/ext/utils/types.py b/venv/lib/python3.8/site-packages/telegram/ext/utils/types.py new file mode 100644 index 0000000..b7152f6 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/ext/utils/types.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains custom typing aliases. + +.. versionadded:: 13.6 +""" +from typing import TypeVar, TYPE_CHECKING, Tuple, List, Dict, Any, Optional + +if TYPE_CHECKING: + from telegram.ext import CallbackContext # noqa: F401 + + +ConversationDict = Dict[Tuple[int, ...], Optional[object]] +"""Dicts as maintained by the :class:`telegram.ext.ConversationHandler`. + + .. versionadded:: 13.6 +""" + +CDCData = Tuple[List[Tuple[str, float, Dict[str, Any]]], Dict[str, str]] +"""Tuple[List[Tuple[:obj:`str`, :obj:`float`, Dict[:obj:`str`, :obj:`any`]]], \ + Dict[:obj:`str`, :obj:`str`]]: Data returned by + :attr:`telegram.ext.CallbackDataCache.persistence_data`. + + .. versionadded:: 13.6 +""" + +CCT = TypeVar('CCT', bound='CallbackContext') +"""An instance of :class:`telegram.ext.CallbackContext` or a custom subclass. + +.. versionadded:: 13.6 +""" +UD = TypeVar('UD') +"""Type of the user data for a single user. + +.. versionadded:: 13.6 +""" +CD = TypeVar('CD') +"""Type of the chat data for a single user. + +.. versionadded:: 13.6 +""" +BD = TypeVar('BD') +"""Type of the bot data. + +.. versionadded:: 13.6 +""" diff --git a/venv/lib/python3.8/site-packages/telegram/ext/utils/webhookhandler.py b/venv/lib/python3.8/site-packages/telegram/ext/utils/webhookhandler.py new file mode 100644 index 0000000..ddf5e69 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/ext/utils/webhookhandler.py @@ -0,0 +1,177 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +# pylint: disable=C0114 + +import logging +from queue import Queue +from ssl import SSLContext +from threading import Event, Lock +from typing import TYPE_CHECKING, Any, Optional + +import tornado.web +from tornado import httputil +from tornado.httpserver import HTTPServer +from tornado.ioloop import IOLoop + +from telegram import Update +from telegram.ext import ExtBot +from telegram.utils.deprecate import set_new_attribute_deprecated +from telegram.utils.types import JSONDict + +if TYPE_CHECKING: + from telegram import Bot + +try: + import ujson as json +except ImportError: + import json # type: ignore[no-redef] + + +class WebhookServer: + __slots__ = ( + 'http_server', + 'listen', + 'port', + 'loop', + 'logger', + 'is_running', + 'server_lock', + 'shutdown_lock', + '__dict__', + ) + + def __init__( + self, listen: str, port: int, webhook_app: 'WebhookAppClass', ssl_ctx: SSLContext + ): + self.http_server = HTTPServer(webhook_app, ssl_options=ssl_ctx) + self.listen = listen + self.port = port + self.loop: Optional[IOLoop] = None + self.logger = logging.getLogger(__name__) + self.is_running = False + self.server_lock = Lock() + self.shutdown_lock = Lock() + + def __setattr__(self, key: str, value: object) -> None: + set_new_attribute_deprecated(self, key, value) + + def serve_forever(self, ready: Event = None) -> None: + with self.server_lock: + IOLoop().make_current() + self.is_running = True + self.logger.debug('Webhook Server started.') + self.loop = IOLoop.current() + self.http_server.listen(self.port, address=self.listen) + + if ready is not None: + ready.set() + + self.loop.start() + self.logger.debug('Webhook Server stopped.') + self.is_running = False + + def shutdown(self) -> None: + with self.shutdown_lock: + if not self.is_running: + self.logger.warning('Webhook Server already stopped.') + return + self.loop.add_callback(self.loop.stop) # type: ignore + + def handle_error(self, request: object, client_address: str) -> None: # pylint: disable=W0613 + """Handle an error gracefully.""" + self.logger.debug( + 'Exception happened during processing of request from %s', + client_address, + exc_info=True, + ) + + +class WebhookAppClass(tornado.web.Application): + def __init__(self, webhook_path: str, bot: 'Bot', update_queue: Queue): + self.shared_objects = {"bot": bot, "update_queue": update_queue} + handlers = [(rf"{webhook_path}/?", WebhookHandler, self.shared_objects)] # noqa + tornado.web.Application.__init__(self, handlers) # type: ignore + + def log_request(self, handler: tornado.web.RequestHandler) -> None: # skipcq: PTC-W0049 + pass + + +# WebhookHandler, process webhook calls +# pylint: disable=W0223 +class WebhookHandler(tornado.web.RequestHandler): + SUPPORTED_METHODS = ["POST"] # type: ignore + + def __init__( + self, + application: tornado.web.Application, + request: httputil.HTTPServerRequest, + **kwargs: JSONDict, + ): + super().__init__(application, request, **kwargs) + self.logger = logging.getLogger(__name__) + + def initialize(self, bot: 'Bot', update_queue: Queue) -> None: + # pylint: disable=W0201 + self.bot = bot + self.update_queue = update_queue + + def set_default_headers(self) -> None: + self.set_header("Content-Type", 'application/json; charset="utf-8"') + + def post(self) -> None: + self.logger.debug('Webhook triggered') + self._validate_post() + json_string = self.request.body.decode() + data = json.loads(json_string) + self.set_status(200) + self.logger.debug('Webhook received data: %s', json_string) + update = Update.de_json(data, self.bot) + if update: + self.logger.debug('Received Update with ID %d on Webhook', update.update_id) + # handle arbitrary callback data, if necessary + if isinstance(self.bot, ExtBot): + self.bot.insert_callback_data(update) + self.update_queue.put(update) + + def _validate_post(self) -> None: + ct_header = self.request.headers.get("Content-Type", None) + if ct_header != 'application/json': + raise tornado.web.HTTPError(403) + + def write_error(self, status_code: int, **kwargs: Any) -> None: + """Log an arbitrary message. + + This is used by all other logging functions. + + It overrides ``BaseHTTPRequestHandler.log_message``, which logs to ``sys.stderr``. + + The first argument, FORMAT, is a format string for the message to be logged. If the format + string contains any % escapes requiring parameters, they should be specified as subsequent + arguments (it's just like printf!). + + The client ip is prefixed to every message. + + """ + super().write_error(status_code, **kwargs) + self.logger.debug( + "%s - - %s", + self.request.remote_ip, + "Exception in WebhookHandler", + exc_info=kwargs['exc_info'], + ) diff --git a/venv/lib/python3.8/site-packages/telegram/files/__init__.py b/venv/lib/python3.8/site-packages/telegram/files/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.8/site-packages/telegram/files/animation.py b/venv/lib/python3.8/site-packages/telegram/files/animation.py new file mode 100644 index 0000000..199cf33 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/files/animation.py @@ -0,0 +1,137 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram Animation.""" +from typing import TYPE_CHECKING, Any, Optional + +from telegram import PhotoSize, TelegramObject +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import JSONDict, ODVInput + +if TYPE_CHECKING: + from telegram import Bot, File + + +class Animation(TelegramObject): + """This object represents an animation file (GIF or H.264/MPEG-4 AVC video without sound). + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`file_unique_id` is equal. + + Args: + file_id (:obj:`str`): Identifier for this file, which can be used to download + or reuse the file. + file_unique_id (:obj:`str`): Unique identifier for this file, which + is supposed to be the same over time and for different bots. + Can't be used to download or reuse the file. + width (:obj:`int`): Video width as defined by sender. + height (:obj:`int`): Video height as defined by sender. + duration (:obj:`int`): Duration of the video in seconds as defined by sender. + thumb (:class:`telegram.PhotoSize`, optional): Animation thumbnail as defined by sender. + file_name (:obj:`str`, optional): Original animation filename as defined by sender. + mime_type (:obj:`str`, optional): MIME type of the file as defined by sender. + file_size (:obj:`int`, optional): File size. + bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + file_id (:obj:`str`): File identifier. + file_unique_id (:obj:`str`): Unique identifier for this file, which + is supposed to be the same over time and for different bots. + Can't be used to download or reuse the file. + width (:obj:`int`): Video width as defined by sender. + height (:obj:`int`): Video height as defined by sender. + duration (:obj:`int`): Duration of the video in seconds as defined by sender. + thumb (:class:`telegram.PhotoSize`): Optional. Animation thumbnail as defined by sender. + file_name (:obj:`str`): Optional. Original animation filename as defined by sender. + mime_type (:obj:`str`): Optional. MIME type of the file as defined by sender. + file_size (:obj:`int`): Optional. File size. + bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods. + + """ + + __slots__ = ( + 'bot', + 'width', + 'file_id', + 'file_size', + 'file_name', + 'thumb', + 'duration', + 'mime_type', + 'height', + 'file_unique_id', + '_id_attrs', + ) + + def __init__( + self, + file_id: str, + file_unique_id: str, + width: int, + height: int, + duration: int, + thumb: PhotoSize = None, + file_name: str = None, + mime_type: str = None, + file_size: int = None, + bot: 'Bot' = None, + **_kwargs: Any, + ): + # Required + self.file_id = str(file_id) + self.file_unique_id = str(file_unique_id) + self.width = int(width) + self.height = int(height) + self.duration = duration + # Optionals + self.thumb = thumb + self.file_name = file_name + self.mime_type = mime_type + self.file_size = file_size + self.bot = bot + + self._id_attrs = (self.file_unique_id,) + + @classmethod + def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Animation']: + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + if not data: + return None + + data['thumb'] = PhotoSize.de_json(data.get('thumb'), bot) + + return cls(bot=bot, **data) + + def get_file( + self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None + ) -> 'File': + """Convenience wrapper over :attr:`telegram.Bot.get_file` + + For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. + + Returns: + :class:`telegram.File` + + Raises: + :class:`telegram.error.TelegramError` + + """ + return self.bot.get_file(file_id=self.file_id, timeout=timeout, api_kwargs=api_kwargs) diff --git a/venv/lib/python3.8/site-packages/telegram/files/audio.py b/venv/lib/python3.8/site-packages/telegram/files/audio.py new file mode 100644 index 0000000..d95711a --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/files/audio.py @@ -0,0 +1,141 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram Audio.""" + +from typing import TYPE_CHECKING, Any, Optional + +from telegram import PhotoSize, TelegramObject +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import JSONDict, ODVInput + +if TYPE_CHECKING: + from telegram import Bot, File + + +class Audio(TelegramObject): + """This object represents an audio file to be treated as music by the Telegram clients. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`file_unique_id` is equal. + + Args: + file_id (:obj:`str`): Identifier for this file, which can be used to download + or reuse the file. + file_unique_id (:obj:`str`): Unique identifier for this file, which is supposed to be + the same over time and for different bots. Can't be used to download or reuse the file. + duration (:obj:`int`): Duration of the audio in seconds as defined by sender. + performer (:obj:`str`, optional): Performer of the audio as defined by sender or by audio + tags. + title (:obj:`str`, optional): Title of the audio as defined by sender or by audio tags. + file_name (:obj:`str`, optional): Original filename as defined by sender. + mime_type (:obj:`str`, optional): MIME type of the file as defined by sender. + file_size (:obj:`int`, optional): File size. + thumb (:class:`telegram.PhotoSize`, optional): Thumbnail of the album cover to + which the music file belongs. + bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + file_id (:obj:`str`): Identifier for this file. + file_unique_id (:obj:`str`): Unique identifier for this file, which + is supposed to be the same over time and for different bots. + Can't be used to download or reuse the file. + duration (:obj:`int`): Duration of the audio in seconds. + performer (:obj:`str`): Optional. Performer of the audio as defined by sender or by audio + tags. + title (:obj:`str`): Optional. Title of the audio as defined by sender or by audio tags. + file_name (:obj:`str`): Optional. Original filename as defined by sender. + mime_type (:obj:`str`): Optional. MIME type of the file as defined by sender. + file_size (:obj:`int`): Optional. File size. + thumb (:class:`telegram.PhotoSize`): Optional. Thumbnail of the album cover to + which the music file belongs. + bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods. + + """ + + __slots__ = ( + 'file_id', + 'bot', + 'file_size', + 'file_name', + 'thumb', + 'title', + 'duration', + 'performer', + 'mime_type', + 'file_unique_id', + '_id_attrs', + ) + + def __init__( + self, + file_id: str, + file_unique_id: str, + duration: int, + performer: str = None, + title: str = None, + mime_type: str = None, + file_size: int = None, + thumb: PhotoSize = None, + bot: 'Bot' = None, + file_name: str = None, + **_kwargs: Any, + ): + # Required + self.file_id = str(file_id) + self.file_unique_id = str(file_unique_id) + self.duration = int(duration) + # Optionals + self.performer = performer + self.title = title + self.file_name = file_name + self.mime_type = mime_type + self.file_size = file_size + self.thumb = thumb + self.bot = bot + + self._id_attrs = (self.file_unique_id,) + + @classmethod + def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Audio']: + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + if not data: + return None + + data['thumb'] = PhotoSize.de_json(data.get('thumb'), bot) + + return cls(bot=bot, **data) + + def get_file( + self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None + ) -> 'File': + """Convenience wrapper over :attr:`telegram.Bot.get_file` + + For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. + + Returns: + :class:`telegram.File` + + Raises: + :class:`telegram.error.TelegramError` + + """ + return self.bot.get_file(file_id=self.file_id, timeout=timeout, api_kwargs=api_kwargs) diff --git a/venv/lib/python3.8/site-packages/telegram/files/chatphoto.py b/venv/lib/python3.8/site-packages/telegram/files/chatphoto.py new file mode 100644 index 0000000..5302c7e --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/files/chatphoto.py @@ -0,0 +1,132 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram ChatPhoto.""" +from typing import TYPE_CHECKING, Any + +from telegram import TelegramObject +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import JSONDict, ODVInput + +if TYPE_CHECKING: + from telegram import Bot, File + + +class ChatPhoto(TelegramObject): + """This object represents a chat photo. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`small_file_unique_id` and :attr:`big_file_unique_id` are + equal. + + Args: + small_file_id (:obj:`str`): Unique file identifier of small (160x160) chat photo. This + file_id can be used only for photo download and only for as long + as the photo is not changed. + small_file_unique_id (:obj:`str`): Unique file identifier of small (160x160) chat photo, + which is supposed to be the same over time and for different bots. + Can't be used to download or reuse the file. + big_file_id (:obj:`str`): Unique file identifier of big (640x640) chat photo. This file_id + can be used only for photo download and only for as long as the photo is not changed. + big_file_unique_id (:obj:`str`): Unique file identifier of big (640x640) chat photo, + which is supposed to be the same over time and for different bots. + Can't be used to download or reuse the file. + bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + small_file_id (:obj:`str`): File identifier of small (160x160) chat photo. + This file_id can be used only for photo download and only for as long + as the photo is not changed. + small_file_unique_id (:obj:`str`): Unique file identifier of small (160x160) chat photo, + which is supposed to be the same over time and for different bots. + Can't be used to download or reuse the file. + big_file_id (:obj:`str`): File identifier of big (640x640) chat photo. + This file_id can be used only for photo download and only for as long as + the photo is not changed. + big_file_unique_id (:obj:`str`): Unique file identifier of big (640x640) chat photo, + which is supposed to be the same over time and for different bots. + Can't be used to download or reuse the file. + + """ + + __slots__ = ( + 'big_file_unique_id', + 'bot', + 'small_file_id', + 'small_file_unique_id', + 'big_file_id', + '_id_attrs', + ) + + def __init__( + self, + small_file_id: str, + small_file_unique_id: str, + big_file_id: str, + big_file_unique_id: str, + bot: 'Bot' = None, + **_kwargs: Any, + ): + self.small_file_id = small_file_id + self.small_file_unique_id = small_file_unique_id + self.big_file_id = big_file_id + self.big_file_unique_id = big_file_unique_id + + self.bot = bot + + self._id_attrs = ( + self.small_file_unique_id, + self.big_file_unique_id, + ) + + def get_small_file( + self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None + ) -> 'File': + """Convenience wrapper over :attr:`telegram.Bot.get_file` for getting the + small (160x160) chat photo + + For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. + + Returns: + :class:`telegram.File` + + Raises: + :class:`telegram.error.TelegramError` + + """ + return self.bot.get_file( + file_id=self.small_file_id, timeout=timeout, api_kwargs=api_kwargs + ) + + def get_big_file( + self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None + ) -> 'File': + """Convenience wrapper over :attr:`telegram.Bot.get_file` for getting the + big (640x640) chat photo + + For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. + + Returns: + :class:`telegram.File` + + Raises: + :class:`telegram.error.TelegramError` + + """ + return self.bot.get_file(file_id=self.big_file_id, timeout=timeout, api_kwargs=api_kwargs) diff --git a/venv/lib/python3.8/site-packages/telegram/files/contact.py b/venv/lib/python3.8/site-packages/telegram/files/contact.py new file mode 100644 index 0000000..257fdf4 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/files/contact.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram Contact.""" + +from typing import Any + +from telegram import TelegramObject + + +class Contact(TelegramObject): + """This object represents a phone contact. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`phone_number` is equal. + + Args: + phone_number (:obj:`str`): Contact's phone number. + first_name (:obj:`str`): Contact's first name. + last_name (:obj:`str`, optional): Contact's last name. + user_id (:obj:`int`, optional): Contact's user identifier in Telegram. + vcard (:obj:`str`, optional): Additional data about the contact in the form of a vCard. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + phone_number (:obj:`str`): Contact's phone number. + first_name (:obj:`str`): Contact's first name. + last_name (:obj:`str`): Optional. Contact's last name. + user_id (:obj:`int`): Optional. Contact's user identifier in Telegram. + vcard (:obj:`str`): Optional. Additional data about the contact in the form of a vCard. + + """ + + __slots__ = ('vcard', 'user_id', 'first_name', 'last_name', 'phone_number', '_id_attrs') + + def __init__( + self, + phone_number: str, + first_name: str, + last_name: str = None, + user_id: int = None, + vcard: str = None, + **_kwargs: Any, + ): + # Required + self.phone_number = str(phone_number) + self.first_name = first_name + # Optionals + self.last_name = last_name + self.user_id = user_id + self.vcard = vcard + + self._id_attrs = (self.phone_number,) diff --git a/venv/lib/python3.8/site-packages/telegram/files/document.py b/venv/lib/python3.8/site-packages/telegram/files/document.py new file mode 100644 index 0000000..dad9f9b --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/files/document.py @@ -0,0 +1,125 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram Document.""" + +from typing import TYPE_CHECKING, Any, Optional + +from telegram import PhotoSize, TelegramObject +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import JSONDict, ODVInput + +if TYPE_CHECKING: + from telegram import Bot, File + + +class Document(TelegramObject): + """This object represents a general file + (as opposed to photos, voice messages and audio files). + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`file_unique_id` is equal. + + Args: + file_id (:obj:`str`): Identifier for this file, which can be used to download + or reuse the file. + file_unique_id (:obj:`str`): Unique identifier for this file, which is supposed to be + the same over time and for different bots. Can't be used to download or reuse the file. + thumb (:class:`telegram.PhotoSize`, optional): Document thumbnail as defined by sender. + file_name (:obj:`str`, optional): Original filename as defined by sender. + mime_type (:obj:`str`, optional): MIME type of the file as defined by sender. + file_size (:obj:`int`, optional): File size. + bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + file_id (:obj:`str`): File identifier. + file_unique_id (:obj:`str`): Unique identifier for this file, which + is supposed to be the same over time and for different bots. + Can't be used to download or reuse the file. + thumb (:class:`telegram.PhotoSize`): Optional. Document thumbnail. + file_name (:obj:`str`): Original filename. + mime_type (:obj:`str`): Optional. MIME type of the file. + file_size (:obj:`int`): Optional. File size. + bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods. + + """ + + __slots__ = ( + 'bot', + 'file_id', + 'file_size', + 'file_name', + 'thumb', + 'mime_type', + 'file_unique_id', + '_id_attrs', + ) + + _id_keys = ('file_id',) + + def __init__( + self, + file_id: str, + file_unique_id: str, + thumb: PhotoSize = None, + file_name: str = None, + mime_type: str = None, + file_size: int = None, + bot: 'Bot' = None, + **_kwargs: Any, + ): + # Required + self.file_id = str(file_id) + self.file_unique_id = str(file_unique_id) + # Optionals + self.thumb = thumb + self.file_name = file_name + self.mime_type = mime_type + self.file_size = file_size + self.bot = bot + + self._id_attrs = (self.file_unique_id,) + + @classmethod + def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Document']: + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + if not data: + return None + + data['thumb'] = PhotoSize.de_json(data.get('thumb'), bot) + + return cls(bot=bot, **data) + + def get_file( + self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None + ) -> 'File': + """Convenience wrapper over :attr:`telegram.Bot.get_file` + + For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. + + Returns: + :class:`telegram.File` + + Raises: + :class:`telegram.error.TelegramError` + + """ + return self.bot.get_file(file_id=self.file_id, timeout=timeout, api_kwargs=api_kwargs) diff --git a/venv/lib/python3.8/site-packages/telegram/files/file.py b/venv/lib/python3.8/site-packages/telegram/files/file.py new file mode 100644 index 0000000..c3391bd --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/files/file.py @@ -0,0 +1,213 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram File.""" +import os +import shutil +import urllib.parse as urllib_parse +from base64 import b64decode +from os.path import basename +from typing import IO, TYPE_CHECKING, Any, Optional, Union + +from telegram import TelegramObject +from telegram.passport.credentials import decrypt +from telegram.utils.helpers import is_local_file + +if TYPE_CHECKING: + from telegram import Bot, FileCredentials + + +class File(TelegramObject): + """ + This object represents a file ready to be downloaded. The file can be downloaded with + :attr:`download`. It is guaranteed that the link will be valid for at least 1 hour. When the + link expires, a new one can be requested by calling :meth:`telegram.Bot.get_file`. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`file_unique_id` is equal. + + Note: + * Maximum file size to download is 20 MB. + * If you obtain an instance of this class from :attr:`telegram.PassportFile.get_file`, + then it will automatically be decrypted as it downloads when you call :attr:`download()`. + + Args: + file_id (:obj:`str`): Identifier for this file, which can be used to download + or reuse the file. + file_unique_id (:obj:`str`): Unique identifier for this file, which + is supposed to be the same over time and for different bots. + Can't be used to download or reuse the file. + file_size (:obj:`int`, optional): Optional. File size, if known. + file_path (:obj:`str`, optional): File path. Use :attr:`download` to get the file. + bot (:obj:`telegram.Bot`, optional): Bot to use with shortcut method. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + file_id (:obj:`str`): Identifier for this file. + file_unique_id (:obj:`str`): Unique identifier for this file, which + is supposed to be the same over time and for different bots. + Can't be used to download or reuse the file. + file_size (:obj:`str`): Optional. File size. + file_path (:obj:`str`): Optional. File path. Use :attr:`download` to get the file. + + """ + + __slots__ = ( + 'bot', + 'file_id', + 'file_size', + 'file_unique_id', + 'file_path', + '_credentials', + '_id_attrs', + ) + + def __init__( + self, + file_id: str, + file_unique_id: str, + bot: 'Bot' = None, + file_size: int = None, + file_path: str = None, + **_kwargs: Any, + ): + # Required + self.file_id = str(file_id) + self.file_unique_id = str(file_unique_id) + # Optionals + self.file_size = file_size + self.file_path = file_path + self.bot = bot + self._credentials: Optional['FileCredentials'] = None + + self._id_attrs = (self.file_unique_id,) + + def download( + self, custom_path: str = None, out: IO = None, timeout: int = None + ) -> Union[str, IO]: + """ + Download this file. By default, the file is saved in the current working directory with its + original filename as reported by Telegram. If the file has no filename, it the file ID will + be used as filename. If a :attr:`custom_path` is supplied, it will be saved to that path + instead. If :attr:`out` is defined, the file contents will be saved to that object using + the ``out.write`` method. + + Note: + * :attr:`custom_path` and :attr:`out` are mutually exclusive. + * If neither :attr:`custom_path` nor :attr:`out` is provided and :attr:`file_path` is + the path of a local file (which is the case when a Bot API Server is running in + local mode), this method will just return the path. + + Args: + custom_path (:obj:`str`, optional): Custom path. + out (:obj:`io.BufferedWriter`, optional): A file-like object. Must be opened for + writing in binary mode, if applicable. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + + Returns: + :obj:`str` | :obj:`io.BufferedWriter`: The same object as :attr:`out` if specified. + Otherwise, returns the filename downloaded to or the file path of the local file. + + Raises: + ValueError: If both :attr:`custom_path` and :attr:`out` are passed. + + """ + if custom_path is not None and out is not None: + raise ValueError('custom_path and out are mutually exclusive') + + local_file = is_local_file(self.file_path) + + if local_file: + url = self.file_path + else: + # Convert any UTF-8 char into a url encoded ASCII string. + url = self._get_encoded_url() + + if out: + if local_file: + with open(url, 'rb') as file: + buf = file.read() + else: + buf = self.bot.request.retrieve(url) + if self._credentials: + buf = decrypt( + b64decode(self._credentials.secret), b64decode(self._credentials.hash), buf + ) + out.write(buf) + return out + + if custom_path and local_file: + shutil.copyfile(self.file_path, custom_path) + return custom_path + + if custom_path: + filename = custom_path + elif local_file: + return self.file_path + elif self.file_path: + filename = basename(self.file_path) + else: + filename = os.path.join(os.getcwd(), self.file_id) + + buf = self.bot.request.retrieve(url, timeout=timeout) + if self._credentials: + buf = decrypt( + b64decode(self._credentials.secret), b64decode(self._credentials.hash), buf + ) + with open(filename, 'wb') as fobj: + fobj.write(buf) + return filename + + def _get_encoded_url(self) -> str: + """Convert any UTF-8 char in :obj:`File.file_path` into a url encoded ASCII string.""" + sres = urllib_parse.urlsplit(self.file_path) + return urllib_parse.urlunsplit( + urllib_parse.SplitResult( + sres.scheme, sres.netloc, urllib_parse.quote(sres.path), sres.query, sres.fragment + ) + ) + + def download_as_bytearray(self, buf: bytearray = None) -> bytes: + """Download this file and return it as a bytearray. + + Args: + buf (:obj:`bytearray`, optional): Extend the given bytearray with the downloaded data. + + Returns: + :obj:`bytearray`: The same object as :attr:`buf` if it was specified. Otherwise a newly + allocated :obj:`bytearray`. + + """ + if buf is None: + buf = bytearray() + if is_local_file(self.file_path): + with open(self.file_path, "rb") as file: + buf.extend(file.read()) + else: + buf.extend(self.bot.request.retrieve(self._get_encoded_url())) + return buf + + def set_credentials(self, credentials: 'FileCredentials') -> None: + """Sets the passport credentials for the file. + + Args: + credentials (:class:`telegram.FileCredentials`): The credentials. + """ + self._credentials = credentials diff --git a/venv/lib/python3.8/site-packages/telegram/files/inputfile.py b/venv/lib/python3.8/site-packages/telegram/files/inputfile.py new file mode 100644 index 0000000..583f4a6 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/files/inputfile.py @@ -0,0 +1,119 @@ +#!/usr/bin/env python +# pylint: disable=W0622,E0611 +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram InputFile.""" + +import imghdr +import logging +import mimetypes +import os +from typing import IO, Optional, Tuple, Union +from uuid import uuid4 + +from telegram.utils.deprecate import set_new_attribute_deprecated + +DEFAULT_MIME_TYPE = 'application/octet-stream' +logger = logging.getLogger(__name__) + + +class InputFile: + """This object represents a Telegram InputFile. + + Args: + obj (:obj:`File handler` | :obj:`bytes`): An open file descriptor or the files content as + bytes. + filename (:obj:`str`, optional): Filename for this InputFile. + attach (:obj:`bool`, optional): Whether this should be send as one file or is part of a + collection of files. + + Raises: + TelegramError + + Attributes: + input_file_content (:obj:`bytes`): The binary content of the file to send. + filename (:obj:`str`): Optional. Filename for the file to be sent. + attach (:obj:`str`): Optional. Attach id for sending multiple files. + + """ + + __slots__ = ('filename', 'attach', 'input_file_content', 'mimetype', '__dict__') + + def __init__(self, obj: Union[IO, bytes], filename: str = None, attach: bool = None): + self.filename = None + if isinstance(obj, bytes): + self.input_file_content = obj + else: + self.input_file_content = obj.read() + self.attach = 'attached' + uuid4().hex if attach else None + + if filename: + self.filename = filename + elif hasattr(obj, 'name') and not isinstance(obj.name, int): # type: ignore[union-attr] + self.filename = os.path.basename(obj.name) # type: ignore[union-attr] + + image_mime_type = self.is_image(self.input_file_content) + if image_mime_type: + self.mimetype = image_mime_type + elif self.filename: + self.mimetype = mimetypes.guess_type(self.filename)[0] or DEFAULT_MIME_TYPE + else: + self.mimetype = DEFAULT_MIME_TYPE + + if not self.filename: + self.filename = self.mimetype.replace('/', '.') + + def __setattr__(self, key: str, value: object) -> None: + set_new_attribute_deprecated(self, key, value) + + @property + def field_tuple(self) -> Tuple[str, bytes, str]: # skipcq: PY-D0003 + return self.filename, self.input_file_content, self.mimetype + + @staticmethod + def is_image(stream: bytes) -> Optional[str]: + """Check if the content file is an image by analyzing its headers. + + Args: + stream (:obj:`bytes`): A byte stream representing the content of a file. + + Returns: + :obj:`str` | :obj:`None`: The mime-type of an image, if the input is an image, or + :obj:`None` else. + + """ + try: + image = imghdr.what(None, stream) + if image: + return f'image/{image}' + return None + except Exception: + logger.debug( + "Could not parse file content. Assuming that file is not an image.", exc_info=True + ) + return None + + @staticmethod + def is_file(obj: object) -> bool: # skipcq: PY-D0003 + return hasattr(obj, 'read') + + def to_dict(self) -> Optional[str]: + """See :meth:`telegram.TelegramObject.to_dict`.""" + if self.attach: + return 'attach://' + self.attach + return None diff --git a/venv/lib/python3.8/site-packages/telegram/files/inputmedia.py b/venv/lib/python3.8/site-packages/telegram/files/inputmedia.py new file mode 100644 index 0000000..f59cf4d --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/files/inputmedia.py @@ -0,0 +1,525 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""Base class for Telegram InputMedia Objects.""" + +from typing import Union, List, Tuple + +from telegram import ( + Animation, + Audio, + Document, + InputFile, + PhotoSize, + TelegramObject, + Video, + MessageEntity, +) +from telegram.utils.helpers import DEFAULT_NONE, parse_file_input +from telegram.utils.types import FileInput, JSONDict, ODVInput + + +class InputMedia(TelegramObject): + """Base class for Telegram InputMedia Objects. + + See :class:`telegram.InputMediaAnimation`, :class:`telegram.InputMediaAudio`, + :class:`telegram.InputMediaDocument`, :class:`telegram.InputMediaPhoto` and + :class:`telegram.InputMediaVideo` for detailed use. + + """ + + __slots__ = () + caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...], None] = None + + def to_dict(self) -> JSONDict: + """See :meth:`telegram.TelegramObject.to_dict`.""" + data = super().to_dict() + + if self.caption_entities: + data['caption_entities'] = [ + ce.to_dict() for ce in self.caption_entities # pylint: disable=E1133 + ] + + return data + + +class InputMediaAnimation(InputMedia): + """Represents an animation file (GIF or H.264/MPEG-4 AVC video without sound) to be sent. + + Note: + When using a :class:`telegram.Animation` for the :attr:`media` attribute. It will take the + width, height and duration from that video, unless otherwise specified with the optional + arguments. + + Args: + media (:obj:`str` | `filelike object` | :obj:`bytes` | :class:`pathlib.Path` | \ + :class:`telegram.Animation`): File to send. Pass a + file_id to send a file that exists on the Telegram servers (recommended), pass an HTTP + URL for Telegram to get a file from the Internet. Lastly you can pass an existing + :class:`telegram.Animation` object to send. + + .. versionchanged:: 13.2 + Accept :obj:`bytes` as input. + filename (:obj:`str`, optional): Custom file name for the animation, when uploading a + new file. Convenience parameter, useful e.g. when sending files generated by the + :obj:`tempfile` module. + + .. versionadded:: 13.1 + thumb (`filelike object` | :obj:`bytes` | :class:`pathlib.Path`, optional): Thumbnail of + the file sent; can be ignored if + thumbnail generation for the file is supported server-side. The thumbnail should be + in JPEG format and less than 200 kB in size. A thumbnail's width and height should + not exceed 320. Ignored if the file is not uploaded using multipart/form-data. + Thumbnails can't be reused and can be only uploaded as a new file. + + .. versionchanged:: 13.2 + Accept :obj:`bytes` as input. + caption (:obj:`str`, optional): Caption of the animation to be sent, 0-1024 characters + after entities parsing. + parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show + bold, italic, fixed-width text or inline URLs in the media caption. See the constants + in :class:`telegram.ParseMode` for the available modes. + caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special + entities that appear in the caption, which can be specified instead of parse_mode. + width (:obj:`int`, optional): Animation width. + height (:obj:`int`, optional): Animation height. + duration (:obj:`int`, optional): Animation duration. + + Attributes: + type (:obj:`str`): ``animation``. + media (:obj:`str` | :class:`telegram.InputFile`): Animation to send. + caption (:obj:`str`): Optional. Caption of the document to be sent. + parse_mode (:obj:`str`): Optional. The parse mode to use for text formatting. + caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special + entities that appear in the caption. + thumb (:class:`telegram.InputFile`): Optional. Thumbnail of the file to send. + width (:obj:`int`): Optional. Animation width. + height (:obj:`int`): Optional. Animation height. + duration (:obj:`int`): Optional. Animation duration. + + """ + + __slots__ = ( + 'caption_entities', + 'width', + 'media', + 'thumb', + 'caption', + 'duration', + 'parse_mode', + 'height', + 'type', + ) + + def __init__( + self, + media: Union[FileInput, Animation], + thumb: FileInput = None, + caption: str = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + width: int = None, + height: int = None, + duration: int = None, + caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None, + filename: str = None, + ): + self.type = 'animation' + + if isinstance(media, Animation): + self.media: Union[str, InputFile] = media.file_id + self.width = media.width + self.height = media.height + self.duration = media.duration + else: + self.media = parse_file_input(media, attach=True, filename=filename) + + if thumb: + self.thumb = parse_file_input(thumb, attach=True) + + if caption: + self.caption = caption + self.parse_mode = parse_mode + self.caption_entities = caption_entities + if width: + self.width = width + if height: + self.height = height + if duration: + self.duration = duration + + +class InputMediaPhoto(InputMedia): + """Represents a photo to be sent. + + Args: + media (:obj:`str` | `filelike object` | :obj:`bytes` | :class:`pathlib.Path` | \ + :class:`telegram.PhotoSize`): File to send. Pass a + file_id to send a file that exists on the Telegram servers (recommended), pass an HTTP + URL for Telegram to get a file from the Internet. Lastly you can pass an existing + :class:`telegram.PhotoSize` object to send. + + .. versionchanged:: 13.2 + Accept :obj:`bytes` as input. + filename (:obj:`str`, optional): Custom file name for the photo, when uploading a + new file. Convenience parameter, useful e.g. when sending files generated by the + :obj:`tempfile` module. + + .. versionadded:: 13.1 + caption (:obj:`str`, optional ): Caption of the photo to be sent, 0-1024 characters after + entities parsing. + parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show + bold, italic, fixed-width text or inline URLs in the media caption. See the constants + in :class:`telegram.ParseMode` for the available modes. + caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special + entities that appear in the caption, which can be specified instead of parse_mode. + + Attributes: + type (:obj:`str`): ``photo``. + media (:obj:`str` | :class:`telegram.InputFile`): Photo to send. + caption (:obj:`str`): Optional. Caption of the document to be sent. + parse_mode (:obj:`str`): Optional. The parse mode to use for text formatting. + caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special + entities that appear in the caption. + + """ + + __slots__ = ('caption_entities', 'media', 'caption', 'parse_mode', 'type') + + def __init__( + self, + media: Union[FileInput, PhotoSize], + caption: str = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None, + filename: str = None, + ): + self.type = 'photo' + self.media = parse_file_input(media, PhotoSize, attach=True, filename=filename) + + if caption: + self.caption = caption + self.parse_mode = parse_mode + self.caption_entities = caption_entities + + +class InputMediaVideo(InputMedia): + """Represents a video to be sent. + + Note: + * When using a :class:`telegram.Video` for the :attr:`media` attribute. It will take the + width, height and duration from that video, unless otherwise specified with the optional + arguments. + * ``thumb`` will be ignored for small video files, for which Telegram can easily + generate thumb nails. However, this behaviour is undocumented and might be changed + by Telegram. + + Args: + media (:obj:`str` | `filelike object` | :obj:`bytes` | :class:`pathlib.Path` | \ + :class:`telegram.Video`): File to send. Pass a + file_id to send a file that exists on the Telegram servers (recommended), pass an HTTP + URL for Telegram to get a file from the Internet. Lastly you can pass an existing + :class:`telegram.Video` object to send. + + .. versionchanged:: 13.2 + Accept :obj:`bytes` as input. + filename (:obj:`str`, optional): Custom file name for the video, when uploading a + new file. Convenience parameter, useful e.g. when sending files generated by the + :obj:`tempfile` module. + + .. versionadded:: 13.1 + caption (:obj:`str`, optional): Caption of the video to be sent, 0-1024 characters after + entities parsing. + parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show + bold, italic, fixed-width text or inline URLs in the media caption. See the constants + in :class:`telegram.ParseMode` for the available modes. + caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special + entities that appear in the caption, which can be specified instead of parse_mode. + width (:obj:`int`, optional): Video width. + height (:obj:`int`, optional): Video height. + duration (:obj:`int`, optional): Video duration. + supports_streaming (:obj:`bool`, optional): Pass :obj:`True`, if the uploaded video is + suitable for streaming. + thumb (`filelike object` | :obj:`bytes` | :class:`pathlib.Path`, optional): Thumbnail of + the file sent; can be ignored if + thumbnail generation for the file is supported server-side. The thumbnail should be + in JPEG format and less than 200 kB in size. A thumbnail's width and height should + not exceed 320. Ignored if the file is not uploaded using multipart/form-data. + Thumbnails can't be reused and can be only uploaded as a new file. + + .. versionchanged:: 13.2 + Accept :obj:`bytes` as input. + + Attributes: + type (:obj:`str`): ``video``. + media (:obj:`str` | :class:`telegram.InputFile`): Video file to send. + caption (:obj:`str`): Optional. Caption of the document to be sent. + parse_mode (:obj:`str`): Optional. The parse mode to use for text formatting. + caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special + entities that appear in the caption. + width (:obj:`int`): Optional. Video width. + height (:obj:`int`): Optional. Video height. + duration (:obj:`int`): Optional. Video duration. + supports_streaming (:obj:`bool`): Optional. Pass :obj:`True`, if the uploaded video is + suitable for streaming. + thumb (:class:`telegram.InputFile`): Optional. Thumbnail of the file to send. + + """ + + __slots__ = ( + 'caption_entities', + 'width', + 'media', + 'thumb', + 'supports_streaming', + 'caption', + 'duration', + 'parse_mode', + 'height', + 'type', + ) + + def __init__( + self, + media: Union[FileInput, Video], + caption: str = None, + width: int = None, + height: int = None, + duration: int = None, + supports_streaming: bool = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + thumb: FileInput = None, + caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None, + filename: str = None, + ): + self.type = 'video' + + if isinstance(media, Video): + self.media: Union[str, InputFile] = media.file_id + self.width = media.width + self.height = media.height + self.duration = media.duration + else: + self.media = parse_file_input(media, attach=True, filename=filename) + + if thumb: + self.thumb = parse_file_input(thumb, attach=True) + + if caption: + self.caption = caption + self.parse_mode = parse_mode + self.caption_entities = caption_entities + if width: + self.width = width + if height: + self.height = height + if duration: + self.duration = duration + if supports_streaming: + self.supports_streaming = supports_streaming + + +class InputMediaAudio(InputMedia): + """Represents an audio file to be treated as music to be sent. + + Note: + When using a :class:`telegram.Audio` for the :attr:`media` attribute. It will take the + duration, performer and title from that video, unless otherwise specified with the + optional arguments. + + Args: + media (:obj:`str` | `filelike object` | :obj:`bytes` | :class:`pathlib.Path` | \ + :class:`telegram.Audio`): + File to send. Pass a + file_id to send a file that exists on the Telegram servers (recommended), pass an HTTP + URL for Telegram to get a file from the Internet. Lastly you can pass an existing + :class:`telegram.Audio` object to send. + + .. versionchanged:: 13.2 + Accept :obj:`bytes` as input. + filename (:obj:`str`, optional): Custom file name for the audio, when uploading a + new file. Convenience parameter, useful e.g. when sending files generated by the + :obj:`tempfile` module. + + .. versionadded:: 13.1 + caption (:obj:`str`, optional): Caption of the audio to be sent, 0-1024 characters after + entities parsing. + parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show + bold, italic, fixed-width text or inline URLs in the media caption. See the constants + in :class:`telegram.ParseMode` for the available modes. + caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special + entities that appear in the caption, which can be specified instead of parse_mode. + duration (:obj:`int`): Duration of the audio in seconds as defined by sender. + performer (:obj:`str`, optional): Performer of the audio as defined by sender or by audio + tags. + title (:obj:`str`, optional): Title of the audio as defined by sender or by audio tags. + thumb (`filelike object` | :obj:`bytes` | :class:`pathlib.Path`, optional): Thumbnail of + the file sent; can be ignored if + thumbnail generation for the file is supported server-side. The thumbnail should be + in JPEG format and less than 200 kB in size. A thumbnail's width and height should + not exceed 320. Ignored if the file is not uploaded using multipart/form-data. + Thumbnails can't be reused and can be only uploaded as a new file. + + .. versionchanged:: 13.2 + Accept :obj:`bytes` as input. + + Attributes: + type (:obj:`str`): ``audio``. + media (:obj:`str` | :class:`telegram.InputFile`): Audio file to send. + caption (:obj:`str`): Optional. Caption of the document to be sent. + parse_mode (:obj:`str`): Optional. The parse mode to use for text formatting. + caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special + entities that appear in the caption. + duration (:obj:`int`): Duration of the audio in seconds. + performer (:obj:`str`): Optional. Performer of the audio as defined by sender or by audio + tags. + title (:obj:`str`): Optional. Title of the audio as defined by sender or by audio tags. + thumb (:class:`telegram.InputFile`): Optional. Thumbnail of the file to send. + + """ + + __slots__ = ( + 'caption_entities', + 'media', + 'thumb', + 'caption', + 'title', + 'duration', + 'type', + 'parse_mode', + 'performer', + ) + + def __init__( + self, + media: Union[FileInput, Audio], + thumb: FileInput = None, + caption: str = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + duration: int = None, + performer: str = None, + title: str = None, + caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None, + filename: str = None, + ): + self.type = 'audio' + + if isinstance(media, Audio): + self.media: Union[str, InputFile] = media.file_id + self.duration = media.duration + self.performer = media.performer + self.title = media.title + else: + self.media = parse_file_input(media, attach=True, filename=filename) + + if thumb: + self.thumb = parse_file_input(thumb, attach=True) + + if caption: + self.caption = caption + self.parse_mode = parse_mode + self.caption_entities = caption_entities + if duration: + self.duration = duration + if performer: + self.performer = performer + if title: + self.title = title + + +class InputMediaDocument(InputMedia): + """Represents a general file to be sent. + + Args: + media (:obj:`str` | `filelike object` | :obj:`bytes` | :class:`pathlib.Path` | \ + :class:`telegram.Document`): File to send. Pass a + file_id to send a file that exists on the Telegram servers (recommended), pass an HTTP + URL for Telegram to get a file from the Internet. Lastly you can pass an existing + :class:`telegram.Document` object to send. + + .. versionchanged:: 13.2 + Accept :obj:`bytes` as input. + filename (:obj:`str`, optional): Custom file name for the document, when uploading a + new file. Convenience parameter, useful e.g. when sending files generated by the + :obj:`tempfile` module. + + .. versionadded:: 13.1 + caption (:obj:`str`, optional): Caption of the document to be sent, 0-1024 characters after + entities parsing. + parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show + bold, italic, fixed-width text or inline URLs in the media caption. See the constants + in :class:`telegram.ParseMode` for the available modes. + caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special + entities that appear in the caption, which can be specified instead of parse_mode. + thumb (`filelike object` | :obj:`bytes` | :class:`pathlib.Path`, optional): Thumbnail of + the file sent; can be ignored if + thumbnail generation for the file is supported server-side. The thumbnail should be + in JPEG format and less than 200 kB in size. A thumbnail's width and height should + not exceed 320. Ignored if the file is not uploaded using multipart/form-data. + Thumbnails can't be reused and can be only uploaded as a new file. + + .. versionchanged:: 13.2 + Accept :obj:`bytes` as input. + disable_content_type_detection (:obj:`bool`, optional): Disables automatic server-side + content type detection for files uploaded using multipart/form-data. Always true, if + the document is sent as part of an album. + + Attributes: + type (:obj:`str`): ``document``. + media (:obj:`str` | :class:`telegram.InputFile`): File to send. + caption (:obj:`str`): Optional. Caption of the document to be sent. + parse_mode (:obj:`str`): Optional. The parse mode to use for text formatting. + caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special + entities that appear in the caption. + thumb (:class:`telegram.InputFile`): Optional. Thumbnail of the file to send. + disable_content_type_detection (:obj:`bool`): Optional. Disables automatic server-side + content type detection for files uploaded using multipart/form-data. Always true, if + the document is sent as part of an album. + + """ + + __slots__ = ( + 'caption_entities', + 'media', + 'thumb', + 'caption', + 'parse_mode', + 'type', + 'disable_content_type_detection', + ) + + def __init__( + self, + media: Union[FileInput, Document], + thumb: FileInput = None, + caption: str = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + disable_content_type_detection: bool = None, + caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None, + filename: str = None, + ): + self.type = 'document' + self.media = parse_file_input(media, Document, attach=True, filename=filename) + + if thumb: + self.thumb = parse_file_input(thumb, attach=True) + + if caption: + self.caption = caption + self.parse_mode = parse_mode + self.caption_entities = caption_entities + self.disable_content_type_detection = disable_content_type_detection diff --git a/venv/lib/python3.8/site-packages/telegram/files/location.py b/venv/lib/python3.8/site-packages/telegram/files/location.py new file mode 100644 index 0000000..8f5c1c6 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/files/location.py @@ -0,0 +1,91 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram Location.""" + +from typing import Any + +from telegram import TelegramObject + + +class Location(TelegramObject): + """This object represents a point on the map. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`longitute` and :attr:`latitude` are equal. + + Args: + longitude (:obj:`float`): Longitude as defined by sender. + latitude (:obj:`float`): Latitude as defined by sender. + horizontal_accuracy (:obj:`float`, optional): The radius of uncertainty for the location, + measured in meters; 0-1500. + live_period (:obj:`int`, optional): Time relative to the message sending date, during which + the location can be updated, in seconds. For active live locations only. + heading (:obj:`int`, optional): The direction in which user is moving, in degrees; 1-360. + For active live locations only. + proximity_alert_radius (:obj:`int`, optional): Maximum distance for proximity alerts about + approaching another chat member, in meters. For sent live locations only. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + longitude (:obj:`float`): Longitude as defined by sender. + latitude (:obj:`float`): Latitude as defined by sender. + horizontal_accuracy (:obj:`float`): Optional. The radius of uncertainty for the location, + measured in meters. + live_period (:obj:`int`): Optional. Time relative to the message sending date, during which + the location can be updated, in seconds. For active live locations only. + heading (:obj:`int`): Optional. The direction in which user is moving, in degrees. + For active live locations only. + proximity_alert_radius (:obj:`int`): Optional. Maximum distance for proximity alerts about + approaching another chat member, in meters. For sent live locations only. + + """ + + __slots__ = ( + 'longitude', + 'horizontal_accuracy', + 'proximity_alert_radius', + 'live_period', + 'latitude', + 'heading', + '_id_attrs', + ) + + def __init__( + self, + longitude: float, + latitude: float, + horizontal_accuracy: float = None, + live_period: int = None, + heading: int = None, + proximity_alert_radius: int = None, + **_kwargs: Any, + ): + # Required + self.longitude = float(longitude) + self.latitude = float(latitude) + + # Optionals + self.horizontal_accuracy = float(horizontal_accuracy) if horizontal_accuracy else None + self.live_period = int(live_period) if live_period else None + self.heading = int(heading) if heading else None + self.proximity_alert_radius = ( + int(proximity_alert_radius) if proximity_alert_radius else None + ) + + self._id_attrs = (self.longitude, self.latitude) diff --git a/venv/lib/python3.8/site-packages/telegram/files/photosize.py b/venv/lib/python3.8/site-packages/telegram/files/photosize.py new file mode 100644 index 0000000..831a7c0 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/files/photosize.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram PhotoSize.""" + +from typing import TYPE_CHECKING, Any + +from telegram import TelegramObject +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import JSONDict, ODVInput + +if TYPE_CHECKING: + from telegram import Bot, File + + +class PhotoSize(TelegramObject): + """This object represents one size of a photo or a file/sticker thumbnail. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`file_unique_id` is equal. + + Args: + file_id (:obj:`str`): Identifier for this file, which can be used to download + or reuse the file. + file_unique_id (:obj:`str`): Unique identifier for this file, which + is supposed to be the same over time and for different bots. + Can't be used to download or reuse the file. + width (:obj:`int`): Photo width. + height (:obj:`int`): Photo height. + file_size (:obj:`int`, optional): File size. + bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + file_id (:obj:`str`): Identifier for this file. + file_unique_id (:obj:`str`): Unique identifier for this file, which + is supposed to be the same over time and for different bots. + Can't be used to download or reuse the file. + width (:obj:`int`): Photo width. + height (:obj:`int`): Photo height. + file_size (:obj:`int`): Optional. File size. + bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods. + + """ + + __slots__ = ('bot', 'width', 'file_id', 'file_size', 'height', 'file_unique_id', '_id_attrs') + + def __init__( + self, + file_id: str, + file_unique_id: str, + width: int, + height: int, + file_size: int = None, + bot: 'Bot' = None, + **_kwargs: Any, + ): + # Required + self.file_id = str(file_id) + self.file_unique_id = str(file_unique_id) + self.width = int(width) + self.height = int(height) + # Optionals + self.file_size = file_size + self.bot = bot + + self._id_attrs = (self.file_unique_id,) + + def get_file( + self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None + ) -> 'File': + """Convenience wrapper over :attr:`telegram.Bot.get_file` + + For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. + + Returns: + :class:`telegram.File` + + Raises: + :class:`telegram.error.TelegramError` + + """ + return self.bot.get_file(file_id=self.file_id, timeout=timeout, api_kwargs=api_kwargs) diff --git a/venv/lib/python3.8/site-packages/telegram/files/sticker.py b/venv/lib/python3.8/site-packages/telegram/files/sticker.py new file mode 100644 index 0000000..681c708 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/files/sticker.py @@ -0,0 +1,288 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains objects that represents stickers.""" + +from typing import TYPE_CHECKING, Any, List, Optional, ClassVar + +from telegram import PhotoSize, TelegramObject, constants +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import JSONDict, ODVInput + +if TYPE_CHECKING: + from telegram import Bot, File + + +class Sticker(TelegramObject): + """This object represents a sticker. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`file_unique_id` is equal. + + Args: + file_id (:obj:`str`): Identifier for this file, which can be used to download + or reuse the file. + file_unique_id (:obj:`str`): Unique identifier for this file, which + is supposed to be the same over time and for different bots. + Can't be used to download or reuse the file. + width (:obj:`int`): Sticker width. + height (:obj:`int`): Sticker height. + is_animated (:obj:`bool`): :obj:`True`, if the sticker is animated. + thumb (:class:`telegram.PhotoSize`, optional): Sticker thumbnail in the .WEBP or .JPG + format. + emoji (:obj:`str`, optional): Emoji associated with the sticker + set_name (:obj:`str`, optional): Name of the sticker set to which the sticker + belongs. + mask_position (:class:`telegram.MaskPosition`, optional): For mask stickers, the + position where the mask should be placed. + file_size (:obj:`int`, optional): File size. + bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods. + **kwargs (obj:`dict`): Arbitrary keyword arguments. + + Attributes: + file_id (:obj:`str`): Identifier for this file. + file_unique_id (:obj:`str`): Unique identifier for this file, which + is supposed to be the same over time and for different bots. + Can't be used to download or reuse the file. + width (:obj:`int`): Sticker width. + height (:obj:`int`): Sticker height. + is_animated (:obj:`bool`): :obj:`True`, if the sticker is animated. + thumb (:class:`telegram.PhotoSize`): Optional. Sticker thumbnail in the .webp or .jpg + format. + emoji (:obj:`str`): Optional. Emoji associated with the sticker. + set_name (:obj:`str`): Optional. Name of the sticker set to which the sticker belongs. + mask_position (:class:`telegram.MaskPosition`): Optional. For mask stickers, the position + where the mask should be placed. + file_size (:obj:`int`): Optional. File size. + bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods. + + """ + + __slots__ = ( + 'bot', + 'width', + 'file_id', + 'is_animated', + 'file_size', + 'thumb', + 'set_name', + 'mask_position', + 'height', + 'file_unique_id', + 'emoji', + '_id_attrs', + ) + + def __init__( + self, + file_id: str, + file_unique_id: str, + width: int, + height: int, + is_animated: bool, + thumb: PhotoSize = None, + emoji: str = None, + file_size: int = None, + set_name: str = None, + mask_position: 'MaskPosition' = None, + bot: 'Bot' = None, + **_kwargs: Any, + ): + # Required + self.file_id = str(file_id) + self.file_unique_id = str(file_unique_id) + self.width = int(width) + self.height = int(height) + self.is_animated = is_animated + # Optionals + self.thumb = thumb + self.emoji = emoji + self.file_size = file_size + self.set_name = set_name + self.mask_position = mask_position + self.bot = bot + + self._id_attrs = (self.file_unique_id,) + + @classmethod + def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Sticker']: + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + if not data: + return None + + data['thumb'] = PhotoSize.de_json(data.get('thumb'), bot) + data['mask_position'] = MaskPosition.de_json(data.get('mask_position'), bot) + + return cls(bot=bot, **data) + + def get_file( + self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None + ) -> 'File': + """Convenience wrapper over :attr:`telegram.Bot.get_file` + + For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. + + Returns: + :class:`telegram.File` + + Raises: + :class:`telegram.error.TelegramError` + + """ + return self.bot.get_file(file_id=self.file_id, timeout=timeout, api_kwargs=api_kwargs) + + +class StickerSet(TelegramObject): + """This object represents a sticker set. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`name` is equal. + + Attributes: + name (:obj:`str`): Sticker set name. + title (:obj:`str`): Sticker set title. + is_animated (:obj:`bool`): :obj:`True`, if the sticker set contains animated stickers. + contains_masks (:obj:`bool`): :obj:`True`, if the sticker set contains masks. + stickers (List[:class:`telegram.Sticker`]): List of all set stickers. + thumb (:class:`telegram.PhotoSize`): Optional. Sticker set thumbnail in the .WEBP or .TGS + format. + + Args: + name (:obj:`str`): Sticker set name. + title (:obj:`str`): Sticker set title. + is_animated (:obj:`bool`): :obj:`True`, if the sticker set contains animated stickers. + contains_masks (:obj:`bool`): :obj:`True`, if the sticker set contains masks. + stickers (List[:class:`telegram.Sticker`]): List of all set stickers. + thumb (:class:`telegram.PhotoSize`, optional): Sticker set thumbnail in the .WEBP or .TGS + format. + + """ + + __slots__ = ( + 'is_animated', + 'contains_masks', + 'thumb', + 'title', + 'stickers', + 'name', + '_id_attrs', + ) + + def __init__( + self, + name: str, + title: str, + is_animated: bool, + contains_masks: bool, + stickers: List[Sticker], + thumb: PhotoSize = None, + **_kwargs: Any, + ): + self.name = name + self.title = title + self.is_animated = is_animated + self.contains_masks = contains_masks + self.stickers = stickers + # Optionals + self.thumb = thumb + + self._id_attrs = (self.name,) + + @classmethod + def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['StickerSet']: + """See :meth:`telegram.TelegramObject.de_json`.""" + if not data: + return None + + data['thumb'] = PhotoSize.de_json(data.get('thumb'), bot) + data['stickers'] = Sticker.de_list(data.get('stickers'), bot) + + return cls(bot=bot, **data) + + def to_dict(self) -> JSONDict: + """See :meth:`telegram.TelegramObject.to_dict`.""" + data = super().to_dict() + + data['stickers'] = [s.to_dict() for s in data.get('stickers')] + + return data + + +class MaskPosition(TelegramObject): + """This object describes the position on faces where a mask should be placed by default. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`point`, :attr:`x_shift`, :attr:`y_shift` and, :attr:`scale` + are equal. + + Attributes: + point (:obj:`str`): The part of the face relative to which the mask should be placed. + One of ``'forehead'``, ``'eyes'``, ``'mouth'``, or ``'chin'``. + x_shift (:obj:`float`): Shift by X-axis measured in widths of the mask scaled to the face + size, from left to right. + y_shift (:obj:`float`): Shift by Y-axis measured in heights of the mask scaled to the face + size, from top to bottom. + scale (:obj:`float`): Mask scaling coefficient. For example, 2.0 means double size. + + Note: + :attr:`type` should be one of the following: `forehead`, `eyes`, `mouth` or `chin`. You can + use the class constants for those. + + Args: + point (:obj:`str`): The part of the face relative to which the mask should be placed. + One of ``'forehead'``, ``'eyes'``, ``'mouth'``, or ``'chin'``. + x_shift (:obj:`float`): Shift by X-axis measured in widths of the mask scaled to the face + size, from left to right. For example, choosing -1.0 will place mask just to the left + of the default mask position. + y_shift (:obj:`float`): Shift by Y-axis measured in heights of the mask scaled to the face + size, from top to bottom. For example, 1.0 will place the mask just below the default + mask position. + scale (:obj:`float`): Mask scaling coefficient. For example, 2.0 means double size. + + """ + + __slots__ = ('point', 'scale', 'x_shift', 'y_shift', '_id_attrs') + + FOREHEAD: ClassVar[str] = constants.STICKER_FOREHEAD + """:const:`telegram.constants.STICKER_FOREHEAD`""" + EYES: ClassVar[str] = constants.STICKER_EYES + """:const:`telegram.constants.STICKER_EYES`""" + MOUTH: ClassVar[str] = constants.STICKER_MOUTH + """:const:`telegram.constants.STICKER_MOUTH`""" + CHIN: ClassVar[str] = constants.STICKER_CHIN + """:const:`telegram.constants.STICKER_CHIN`""" + + def __init__(self, point: str, x_shift: float, y_shift: float, scale: float, **_kwargs: Any): + self.point = point + self.x_shift = x_shift + self.y_shift = y_shift + self.scale = scale + + self._id_attrs = (self.point, self.x_shift, self.y_shift, self.scale) + + @classmethod + def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['MaskPosition']: + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + if data is None: + return None + + return cls(**data) diff --git a/venv/lib/python3.8/site-packages/telegram/files/venue.py b/venv/lib/python3.8/site-packages/telegram/files/venue.py new file mode 100644 index 0000000..3ba2c53 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/files/venue.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram Venue.""" + +from typing import TYPE_CHECKING, Any, Optional + +from telegram import Location, TelegramObject +from telegram.utils.types import JSONDict + +if TYPE_CHECKING: + from telegram import Bot + + +class Venue(TelegramObject): + """This object represents a venue. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`location` and :attr:`title` are equal. + + Note: + Foursquare details and Google Pace details are mutually exclusive. However, this + behaviour is undocumented and might be changed by Telegram. + + Args: + location (:class:`telegram.Location`): Venue location. + title (:obj:`str`): Name of the venue. + address (:obj:`str`): Address of the venue. + foursquare_id (:obj:`str`, optional): Foursquare identifier of the venue. + foursquare_type (:obj:`str`, optional): Foursquare type of the venue. (For example, + "arts_entertainment/default", "arts_entertainment/aquarium" or "food/icecream".) + google_place_id (:obj:`str`, optional): Google Places identifier of the venue. + google_place_type (:obj:`str`, optional): Google Places type of the venue. (See + `supported types <https://developers.google.com/places/web-service/supported_types>`_.) + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + location (:class:`telegram.Location`): Venue location. + title (:obj:`str`): Name of the venue. + address (:obj:`str`): Address of the venue. + foursquare_id (:obj:`str`): Optional. Foursquare identifier of the venue. + foursquare_type (:obj:`str`): Optional. Foursquare type of the venue. + google_place_id (:obj:`str`): Optional. Google Places identifier of the venue. + google_place_type (:obj:`str`): Optional. Google Places type of the venue. + + """ + + __slots__ = ( + 'google_place_type', + 'location', + 'title', + 'address', + 'foursquare_type', + 'foursquare_id', + 'google_place_id', + '_id_attrs', + ) + + def __init__( + self, + location: Location, + title: str, + address: str, + foursquare_id: str = None, + foursquare_type: str = None, + google_place_id: str = None, + google_place_type: str = None, + **_kwargs: Any, + ): + # Required + self.location = location + self.title = title + self.address = address + # Optionals + self.foursquare_id = foursquare_id + self.foursquare_type = foursquare_type + self.google_place_id = google_place_id + self.google_place_type = google_place_type + + self._id_attrs = (self.location, self.title) + + @classmethod + def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Venue']: + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + if not data: + return None + + data['location'] = Location.de_json(data.get('location'), bot) + + return cls(**data) diff --git a/venv/lib/python3.8/site-packages/telegram/files/video.py b/venv/lib/python3.8/site-packages/telegram/files/video.py new file mode 100644 index 0000000..76bb07c --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/files/video.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram Video.""" + +from typing import TYPE_CHECKING, Any, Optional + +from telegram import PhotoSize, TelegramObject +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import JSONDict, ODVInput + +if TYPE_CHECKING: + from telegram import Bot, File + + +class Video(TelegramObject): + """This object represents a video file. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`file_unique_id` is equal. + + Args: + file_id (:obj:`str`): Identifier for this file, which can be used to download + or reuse the file. + file_unique_id (:obj:`str`): Unique identifier for this file, which + is supposed to be the same over time and for different bots. + Can't be used to download or reuse the file. + width (:obj:`int`): Video width as defined by sender. + height (:obj:`int`): Video height as defined by sender. + duration (:obj:`int`): Duration of the video in seconds as defined by sender. + thumb (:class:`telegram.PhotoSize`, optional): Video thumbnail. + file_name (:obj:`str`, optional): Original filename as defined by sender. + mime_type (:obj:`str`, optional): Mime type of a file as defined by sender. + file_size (:obj:`int`, optional): File size. + bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + file_id (:obj:`str`): Identifier for this file. + file_unique_id (:obj:`str`): Unique identifier for this file, which + is supposed to be the same over time and for different bots. + Can't be used to download or reuse the file. + width (:obj:`int`): Video width as defined by sender. + height (:obj:`int`): Video height as defined by sender. + duration (:obj:`int`): Duration of the video in seconds as defined by sender. + thumb (:class:`telegram.PhotoSize`): Optional. Video thumbnail. + file_name (:obj:`str`): Optional. Original filename as defined by sender. + mime_type (:obj:`str`): Optional. Mime type of a file as defined by sender. + file_size (:obj:`int`): Optional. File size. + bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods. + + """ + + __slots__ = ( + 'bot', + 'width', + 'file_id', + 'file_size', + 'file_name', + 'thumb', + 'duration', + 'mime_type', + 'height', + 'file_unique_id', + '_id_attrs', + ) + + def __init__( + self, + file_id: str, + file_unique_id: str, + width: int, + height: int, + duration: int, + thumb: PhotoSize = None, + mime_type: str = None, + file_size: int = None, + bot: 'Bot' = None, + file_name: str = None, + **_kwargs: Any, + ): + # Required + self.file_id = str(file_id) + self.file_unique_id = str(file_unique_id) + self.width = int(width) + self.height = int(height) + self.duration = int(duration) + # Optionals + self.thumb = thumb + self.file_name = file_name + self.mime_type = mime_type + self.file_size = file_size + self.bot = bot + + self._id_attrs = (self.file_unique_id,) + + @classmethod + def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Video']: + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + if not data: + return None + + data['thumb'] = PhotoSize.de_json(data.get('thumb'), bot) + + return cls(bot=bot, **data) + + def get_file( + self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None + ) -> 'File': + """Convenience wrapper over :attr:`telegram.Bot.get_file` + + For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. + + Returns: + :class:`telegram.File` + + Raises: + :class:`telegram.error.TelegramError` + + """ + return self.bot.get_file(file_id=self.file_id, timeout=timeout, api_kwargs=api_kwargs) diff --git a/venv/lib/python3.8/site-packages/telegram/files/videonote.py b/venv/lib/python3.8/site-packages/telegram/files/videonote.py new file mode 100644 index 0000000..8c70406 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/files/videonote.py @@ -0,0 +1,124 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram VideoNote.""" + +from typing import TYPE_CHECKING, Optional, Any + +from telegram import PhotoSize, TelegramObject +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import JSONDict, ODVInput + +if TYPE_CHECKING: + from telegram import Bot, File + + +class VideoNote(TelegramObject): + """This object represents a video message (available in Telegram apps as of v.4.0). + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`file_unique_id` is equal. + + Args: + file_id (:obj:`str`): Identifier for this file, which can be used to download + or reuse the file. + file_unique_id (:obj:`str`): Unique identifier for this file, which + is supposed to be the same over time and for different bots. + Can't be used to download or reuse the file. + length (:obj:`int`): Video width and height (diameter of the video message) as defined + by sender. + duration (:obj:`int`): Duration of the video in seconds as defined by sender. + thumb (:class:`telegram.PhotoSize`, optional): Video thumbnail. + file_size (:obj:`int`, optional): File size. + bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + file_id (:obj:`str`): Identifier for this file. + file_unique_id (:obj:`str`): Unique identifier for this file, which + is supposed to be the same over time and for different bots. + Can't be used to download or reuse the file. + length (:obj:`int`): Video width and height as defined by sender. + duration (:obj:`int`): Duration of the video in seconds as defined by sender. + thumb (:class:`telegram.PhotoSize`): Optional. Video thumbnail. + file_size (:obj:`int`): Optional. File size. + bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods. + + """ + + __slots__ = ( + 'bot', + 'length', + 'file_id', + 'file_size', + 'thumb', + 'duration', + 'file_unique_id', + '_id_attrs', + ) + + def __init__( + self, + file_id: str, + file_unique_id: str, + length: int, + duration: int, + thumb: PhotoSize = None, + file_size: int = None, + bot: 'Bot' = None, + **_kwargs: Any, + ): + # Required + self.file_id = str(file_id) + self.file_unique_id = str(file_unique_id) + self.length = int(length) + self.duration = int(duration) + # Optionals + self.thumb = thumb + self.file_size = file_size + self.bot = bot + + self._id_attrs = (self.file_unique_id,) + + @classmethod + def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['VideoNote']: + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + if not data: + return None + + data['thumb'] = PhotoSize.de_json(data.get('thumb'), bot) + + return cls(bot=bot, **data) + + def get_file( + self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None + ) -> 'File': + """Convenience wrapper over :attr:`telegram.Bot.get_file` + + For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. + + Returns: + :class:`telegram.File` + + Raises: + :class:`telegram.error.TelegramError` + + """ + return self.bot.get_file(file_id=self.file_id, timeout=timeout, api_kwargs=api_kwargs) diff --git a/venv/lib/python3.8/site-packages/telegram/files/voice.py b/venv/lib/python3.8/site-packages/telegram/files/voice.py new file mode 100644 index 0000000..f65c5c5 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/files/voice.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram Voice.""" + +from typing import TYPE_CHECKING, Any + +from telegram import TelegramObject +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import JSONDict, ODVInput + +if TYPE_CHECKING: + from telegram import Bot, File + + +class Voice(TelegramObject): + """This object represents a voice note. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`file_unique_id` is equal. + + Args: + file_id (:obj:`str`): Identifier for this file, which can be used to download + or reuse the file. + file_unique_id (:obj:`str`): Unique identifier for this file, which + is supposed to be the same over time and for different bots. + Can't be used to download or reuse the file. + duration (:obj:`int`, optional): Duration of the audio in seconds as defined by sender. + mime_type (:obj:`str`, optional): MIME type of the file as defined by sender. + file_size (:obj:`int`, optional): File size. + bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + file_id (:obj:`str`): Identifier for this file. + file_unique_id (:obj:`str`): Unique identifier for this file, which + is supposed to be the same over time and for different bots. + Can't be used to download or reuse the file. + duration (:obj:`int`): Duration of the audio in seconds as defined by sender. + mime_type (:obj:`str`): Optional. MIME type of the file as defined by sender. + file_size (:obj:`int`): Optional. File size. + bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods. + + """ + + __slots__ = ( + 'bot', + 'file_id', + 'file_size', + 'duration', + 'mime_type', + 'file_unique_id', + '_id_attrs', + ) + + def __init__( + self, + file_id: str, + file_unique_id: str, + duration: int, + mime_type: str = None, + file_size: int = None, + bot: 'Bot' = None, + **_kwargs: Any, + ): + # Required + self.file_id = str(file_id) + self.file_unique_id = str(file_unique_id) + self.duration = int(duration) + # Optionals + self.mime_type = mime_type + self.file_size = file_size + self.bot = bot + + self._id_attrs = (self.file_unique_id,) + + def get_file( + self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None + ) -> 'File': + """Convenience wrapper over :attr:`telegram.Bot.get_file` + + For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. + + Returns: + :class:`telegram.File` + + Raises: + :class:`telegram.error.TelegramError` + + """ + return self.bot.get_file(file_id=self.file_id, timeout=timeout, api_kwargs=api_kwargs) diff --git a/venv/lib/python3.8/site-packages/telegram/forcereply.py b/venv/lib/python3.8/site-packages/telegram/forcereply.py new file mode 100644 index 0000000..aaf7c73 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/forcereply.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram ForceReply.""" + +from typing import Any + +from telegram import ReplyMarkup + + +class ForceReply(ReplyMarkup): + """ + Upon receiving a message with this object, Telegram clients will display a reply interface to + the user (act as if the user has selected the bot's message and tapped 'Reply'). This can be + extremely useful if you want to create user-friendly step-by-step interfaces without having + to sacrifice privacy mode. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`selective` is equal. + + Args: + selective (:obj:`bool`, optional): Use this parameter if you want to force reply from + specific users only. Targets: + + 1) Users that are @mentioned in the text of the Message object. + 2) If the bot's message is a reply (has reply_to_message_id), sender of the + original message. + + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + force_reply (:obj:`True`): Shows reply interface to the user, as if they manually selected + the bots message and tapped 'Reply'. + selective (:obj:`bool`): Optional. Force reply from specific users only. + + """ + + __slots__ = ('selective', 'force_reply', '_id_attrs') + + def __init__(self, force_reply: bool = True, selective: bool = False, **_kwargs: Any): + # Required + self.force_reply = bool(force_reply) + # Optionals + self.selective = bool(selective) + + self._id_attrs = (self.selective,) diff --git a/venv/lib/python3.8/site-packages/telegram/games/__init__.py b/venv/lib/python3.8/site-packages/telegram/games/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.8/site-packages/telegram/games/callbackgame.py b/venv/lib/python3.8/site-packages/telegram/games/callbackgame.py new file mode 100644 index 0000000..8a116da --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/games/callbackgame.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram CallbackGame.""" + +from telegram import TelegramObject + + +class CallbackGame(TelegramObject): + """A placeholder, currently holds no information. Use BotFather to set up your game.""" + + __slots__ = () diff --git a/venv/lib/python3.8/site-packages/telegram/games/game.py b/venv/lib/python3.8/site-packages/telegram/games/game.py new file mode 100644 index 0000000..d56bebe --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/games/game.py @@ -0,0 +1,186 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram Game.""" + +import sys +from typing import TYPE_CHECKING, Any, Dict, List, Optional + +from telegram import Animation, MessageEntity, PhotoSize, TelegramObject +from telegram.utils.types import JSONDict + +if TYPE_CHECKING: + from telegram import Bot + + +class Game(TelegramObject): + """ + This object represents a game. Use `BotFather <https://t.me/BotFather>`_ to create and edit + games, their short names will act as unique identifiers. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`title`, :attr:`description` and :attr:`photo` are equal. + + Args: + title (:obj:`str`): Title of the game. + description (:obj:`str`): Description of the game. + photo (List[:class:`telegram.PhotoSize`]): Photo that will be displayed in the game message + in chats. + text (:obj:`str`, optional): Brief description of the game or high scores included in the + game message. Can be automatically edited to include current high scores for the game + when the bot calls :meth:`telegram.Bot.set_game_score`, or manually edited + using :meth:`telegram.Bot.edit_message_text`. + 0-4096 characters. Also found as ``telegram.constants.MAX_MESSAGE_LENGTH``. + text_entities (List[:class:`telegram.MessageEntity`], optional): Special entities that + appear in text, such as usernames, URLs, bot commands, etc. + animation (:class:`telegram.Animation`, optional): Animation that will be displayed in the + game message in chats. Upload via `BotFather <https://t.me/BotFather>`_. + + Attributes: + title (:obj:`str`): Title of the game. + description (:obj:`str`): Description of the game. + photo (List[:class:`telegram.PhotoSize`]): Photo that will be displayed in the game message + in chats. + text (:obj:`str`): Optional. Brief description of the game or high scores included in the + game message. Can be automatically edited to include current high scores for the game + when the bot calls :meth:`telegram.Bot.set_game_score`, or manually edited + using :meth:`telegram.Bot.edit_message_text`. + text_entities (List[:class:`telegram.MessageEntity`]): Optional. Special entities that + appear in text, such as usernames, URLs, bot commands, etc. + animation (:class:`telegram.Animation`): Optional. Animation that will be displayed in the + game message in chats. Upload via `BotFather <https://t.me/BotFather>`_. + + """ + + __slots__ = ( + 'title', + 'photo', + 'description', + 'text_entities', + 'text', + 'animation', + '_id_attrs', + ) + + def __init__( + self, + title: str, + description: str, + photo: List[PhotoSize], + text: str = None, + text_entities: List[MessageEntity] = None, + animation: Animation = None, + **_kwargs: Any, + ): + # Required + self.title = title + self.description = description + self.photo = photo + # Optionals + self.text = text + self.text_entities = text_entities or [] + self.animation = animation + + self._id_attrs = (self.title, self.description, self.photo) + + @classmethod + def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Game']: + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + if not data: + return None + + data['photo'] = PhotoSize.de_list(data.get('photo'), bot) + data['text_entities'] = MessageEntity.de_list(data.get('text_entities'), bot) + data['animation'] = Animation.de_json(data.get('animation'), bot) + + return cls(**data) + + def to_dict(self) -> JSONDict: + """See :meth:`telegram.TelegramObject.to_dict`.""" + data = super().to_dict() + + data['photo'] = [p.to_dict() for p in self.photo] + if self.text_entities: + data['text_entities'] = [x.to_dict() for x in self.text_entities] + + return data + + def parse_text_entity(self, entity: MessageEntity) -> str: + """Returns the text from a given :class:`telegram.MessageEntity`. + + Note: + This method is present because Telegram calculates the offset and length in + UTF-16 codepoint pairs, which some versions of Python don't handle automatically. + (That is, you can't just slice ``Message.text`` with the offset and length.) + + Args: + entity (:class:`telegram.MessageEntity`): The entity to extract the text from. It must + be an entity that belongs to this message. + + Returns: + :obj:`str`: The text of the given entity. + + Raises: + RuntimeError: If this game has no text. + + """ + if not self.text: + raise RuntimeError("This Game has no 'text'.") + + # Is it a narrow build, if so we don't need to convert + if sys.maxunicode == 0xFFFF: + return self.text[entity.offset : entity.offset + entity.length] + entity_text = self.text.encode('utf-16-le') + entity_text = entity_text[entity.offset * 2 : (entity.offset + entity.length) * 2] + + return entity_text.decode('utf-16-le') + + def parse_text_entities(self, types: List[str] = None) -> Dict[MessageEntity, str]: + """ + Returns a :obj:`dict` that maps :class:`telegram.MessageEntity` to :obj:`str`. + It contains entities from this message filtered by their ``type`` attribute as the key, and + the text that each entity belongs to as the value of the :obj:`dict`. + + Note: + This method should always be used instead of the :attr:`text_entities` attribute, since + it calculates the correct substring from the message text based on UTF-16 codepoints. + See :attr:`parse_text_entity` for more info. + + Args: + types (List[:obj:`str`], optional): List of ``MessageEntity`` types as strings. If the + ``type`` attribute of an entity is contained in this list, it will be returned. + Defaults to :attr:`telegram.MessageEntity.ALL_TYPES`. + + Returns: + Dict[:class:`telegram.MessageEntity`, :obj:`str`]: A dictionary of entities mapped to + the text that belongs to them, calculated based on UTF-16 codepoints. + + """ + if types is None: + types = MessageEntity.ALL_TYPES + + return { + entity: self.parse_text_entity(entity) + for entity in (self.text_entities or []) + if entity.type in types + } + + def __hash__(self) -> int: + return hash((self.title, self.description, tuple(p for p in self.photo))) diff --git a/venv/lib/python3.8/site-packages/telegram/games/gamehighscore.py b/venv/lib/python3.8/site-packages/telegram/games/gamehighscore.py new file mode 100644 index 0000000..bfa7cbf --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/games/gamehighscore.py @@ -0,0 +1,67 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram GameHighScore.""" + +from typing import TYPE_CHECKING, Optional + +from telegram import TelegramObject, User +from telegram.utils.types import JSONDict + +if TYPE_CHECKING: + from telegram import Bot + + +class GameHighScore(TelegramObject): + """This object represents one row of the high scores table for a game. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`position`, :attr:`user` and :attr:`score` are equal. + + Args: + position (:obj:`int`): Position in high score table for the game. + user (:class:`telegram.User`): User. + score (:obj:`int`): Score. + + Attributes: + position (:obj:`int`): Position in high score table for the game. + user (:class:`telegram.User`): User. + score (:obj:`int`): Score. + + """ + + __slots__ = ('position', 'user', 'score', '_id_attrs') + + def __init__(self, position: int, user: User, score: int): + self.position = position + self.user = user + self.score = score + + self._id_attrs = (self.position, self.user, self.score) + + @classmethod + def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['GameHighScore']: + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + if not data: + return None + + data['user'] = User.de_json(data.get('user'), bot) + + return cls(**data) diff --git a/venv/lib/python3.8/site-packages/telegram/inline/__init__.py b/venv/lib/python3.8/site-packages/telegram/inline/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinekeyboardbutton.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinekeyboardbutton.py new file mode 100644 index 0000000..b9d0c32 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/inline/inlinekeyboardbutton.py @@ -0,0 +1,162 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram InlineKeyboardButton.""" + +from typing import TYPE_CHECKING, Any + +from telegram import TelegramObject + +if TYPE_CHECKING: + from telegram import CallbackGame, LoginUrl + + +class InlineKeyboardButton(TelegramObject): + """This object represents one button of an inline keyboard. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`text`, :attr:`url`, :attr:`login_url`, :attr:`callback_data`, + :attr:`switch_inline_query`, :attr:`switch_inline_query_current_chat`, :attr:`callback_game` + and :attr:`pay` are equal. + + Note: + * You must use exactly one of the optional fields. Mind that :attr:`callback_game` is not + working as expected. Putting a game short name in it might, but is not guaranteed to + work. + * If your bot allows for arbitrary callback data, in keyboards returned in a response + from telegram, :attr:`callback_data` maybe be an instance of + :class:`telegram.ext.InvalidCallbackData`. This will be the case, if the data + associated with the button was already deleted. + + .. versionadded:: 13.6 + + Warning: + If your bot allows your arbitrary callback data, buttons whose callback data is a + non-hashable object will be come unhashable. Trying to evaluate ``hash(button)`` will + result in a :class:`TypeError`. + + .. versionchanged:: 13.6 + + Args: + text (:obj:`str`): Label text on the button. + url (:obj:`str`, optional): HTTP or tg:// url to be opened when button is pressed. + login_url (:class:`telegram.LoginUrl`, optional): An HTTP URL used to automatically + authorize the user. Can be used as a replacement for the Telegram Login Widget. + callback_data (:obj:`str` | :obj:`Any`, optional): Data to be sent in a callback query to + the bot when button is pressed, UTF-8 1-64 bytes. If the bot instance allows arbitrary + callback data, anything can be passed. + switch_inline_query (:obj:`str`, optional): If set, pressing the button will prompt the + user to select one of their chats, open that chat and insert the bot's username and the + specified inline query in the input field. Can be empty, in which case just the bot's + username will be inserted. This offers an easy way for users to start using your bot + in inline mode when they are currently in a private chat with it. Especially useful + when combined with switch_pm* actions - in this case the user will be automatically + returned to the chat they switched from, skipping the chat selection screen. + switch_inline_query_current_chat (:obj:`str`, optional): If set, pressing the button will + insert the bot's username and the specified inline query in the current chat's input + field. Can be empty, in which case only the bot's username will be inserted. This + offers a quick way for the user to open your bot in inline mode in the same chat - good + for selecting something from multiple options. + callback_game (:class:`telegram.CallbackGame`, optional): Description of the game that will + be launched when the user presses the button. This type of button must always be + the ``first`` button in the first row. + pay (:obj:`bool`, optional): Specify :obj:`True`, to send a Pay button. This type of button + must always be the ``first`` button in the first row. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + text (:obj:`str`): Label text on the button. + url (:obj:`str`): Optional. HTTP or tg:// url to be opened when button is pressed. + login_url (:class:`telegram.LoginUrl`): Optional. An HTTP URL used to automatically + authorize the user. Can be used as a replacement for the Telegram Login Widget. + callback_data (:obj:`str` | :obj:`object`): Optional. Data to be sent in a callback query + to the bot when button is pressed, UTF-8 1-64 bytes. + switch_inline_query (:obj:`str`): Optional. Will prompt the user to select one of their + chats, open that chat and insert the bot's username and the specified inline query in + the input field. Can be empty, in which case just the bot’s username will be inserted. + switch_inline_query_current_chat (:obj:`str`): Optional. Will insert the bot's username and + the specified inline query in the current chat's input field. Can be empty, in which + case just the bot’s username will be inserted. + callback_game (:class:`telegram.CallbackGame`): Optional. Description of the game that will + be launched when the user presses the button. + pay (:obj:`bool`): Optional. Specify :obj:`True`, to send a Pay button. + + """ + + __slots__ = ( + 'callback_game', + 'url', + 'switch_inline_query_current_chat', + 'callback_data', + 'pay', + 'switch_inline_query', + 'text', + '_id_attrs', + 'login_url', + ) + + def __init__( + self, + text: str, + url: str = None, + callback_data: object = None, + switch_inline_query: str = None, + switch_inline_query_current_chat: str = None, + callback_game: 'CallbackGame' = None, + pay: bool = None, + login_url: 'LoginUrl' = None, + **_kwargs: Any, + ): + # Required + self.text = text + + # Optionals + self.url = url + self.login_url = login_url + self.callback_data = callback_data + self.switch_inline_query = switch_inline_query + self.switch_inline_query_current_chat = switch_inline_query_current_chat + self.callback_game = callback_game + self.pay = pay + self._id_attrs = () + self._set_id_attrs() + + def _set_id_attrs(self) -> None: + self._id_attrs = ( + self.text, + self.url, + self.login_url, + self.callback_data, + self.switch_inline_query, + self.switch_inline_query_current_chat, + self.callback_game, + self.pay, + ) + + def update_callback_data(self, callback_data: object) -> None: + """ + Sets :attr:`callback_data` to the passed object. Intended to be used by + :class:`telegram.ext.CallbackDataCache`. + + .. versionadded:: 13.6 + + Args: + callback_data (:obj:`obj`): The new callback data. + """ + self.callback_data = callback_data + self._set_id_attrs() diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinekeyboardmarkup.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinekeyboardmarkup.py new file mode 100644 index 0000000..a917d96 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/inline/inlinekeyboardmarkup.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram InlineKeyboardMarkup.""" + +from typing import TYPE_CHECKING, Any, List, Optional + +from telegram import InlineKeyboardButton, ReplyMarkup +from telegram.utils.types import JSONDict + +if TYPE_CHECKING: + from telegram import Bot + + +class InlineKeyboardMarkup(ReplyMarkup): + """ + This object represents an inline keyboard that appears right next to the message it belongs to. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their the size of :attr:`inline_keyboard` and all the buttons are equal. + + Args: + inline_keyboard (List[List[:class:`telegram.InlineKeyboardButton`]]): List of button rows, + each represented by a list of InlineKeyboardButton objects. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + inline_keyboard (List[List[:class:`telegram.InlineKeyboardButton`]]): List of button rows, + each represented by a list of InlineKeyboardButton objects. + + """ + + __slots__ = ('inline_keyboard', '_id_attrs') + + def __init__(self, inline_keyboard: List[List[InlineKeyboardButton]], **_kwargs: Any): + # Required + self.inline_keyboard = inline_keyboard + + self._id_attrs = (self.inline_keyboard,) + + def to_dict(self) -> JSONDict: + """See :meth:`telegram.TelegramObject.to_dict`.""" + data = super().to_dict() + + data['inline_keyboard'] = [] + for inline_keyboard in self.inline_keyboard: + data['inline_keyboard'].append([x.to_dict() for x in inline_keyboard]) + + return data + + @classmethod + def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['InlineKeyboardMarkup']: + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + if not data: + return None + + keyboard = [] + for row in data['inline_keyboard']: + tmp = [] + for col in row: + btn = InlineKeyboardButton.de_json(col, bot) + if btn: + tmp.append(btn) + keyboard.append(tmp) + + return cls(keyboard) + + @classmethod + def from_button(cls, button: InlineKeyboardButton, **kwargs: object) -> 'InlineKeyboardMarkup': + """Shortcut for:: + + InlineKeyboardMarkup([[button]], **kwargs) + + Return an InlineKeyboardMarkup from a single InlineKeyboardButton + + Args: + button (:class:`telegram.InlineKeyboardButton`): The button to use in the markup + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + """ + return cls([[button]], **kwargs) + + @classmethod + def from_row( + cls, button_row: List[InlineKeyboardButton], **kwargs: object + ) -> 'InlineKeyboardMarkup': + """Shortcut for:: + + InlineKeyboardMarkup([button_row], **kwargs) + + Return an InlineKeyboardMarkup from a single row of InlineKeyboardButtons + + Args: + button_row (List[:class:`telegram.InlineKeyboardButton`]): The button to use in the + markup + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + """ + return cls([button_row], **kwargs) + + @classmethod + def from_column( + cls, button_column: List[InlineKeyboardButton], **kwargs: object + ) -> 'InlineKeyboardMarkup': + """Shortcut for:: + + InlineKeyboardMarkup([[button] for button in button_column], **kwargs) + + Return an InlineKeyboardMarkup from a single column of InlineKeyboardButtons + + Args: + button_column (List[:class:`telegram.InlineKeyboardButton`]): The button to use in the + markup + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + """ + button_grid = [[button] for button in button_column] + return cls(button_grid, **kwargs) + + def __hash__(self) -> int: + return hash(tuple(tuple(button for button in row) for row in self.inline_keyboard)) diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequery.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequery.py new file mode 100644 index 0000000..412188d --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/inline/inlinequery.py @@ -0,0 +1,168 @@ +#!/usr/bin/env python +# pylint: disable=R0902,R0913 +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram InlineQuery.""" + +from typing import TYPE_CHECKING, Any, Optional, Union, Callable, ClassVar, Sequence + +from telegram import Location, TelegramObject, User, constants +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import JSONDict, ODVInput + +if TYPE_CHECKING: + from telegram import Bot, InlineQueryResult + + +class InlineQuery(TelegramObject): + """ + This object represents an incoming inline query. When the user sends an empty query, your bot + could return some default or trending results. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`id` is equal. + + Note: + In Python ``from`` is a reserved word, use ``from_user`` instead. + + Args: + id (:obj:`str`): Unique identifier for this query. + from_user (:class:`telegram.User`): Sender. + query (:obj:`str`): Text of the query (up to 256 characters). + offset (:obj:`str`): Offset of the results to be returned, can be controlled by the bot. + chat_type (:obj:`str`, optional): Type of the chat, from which the inline query was sent. + Can be either :attr:`telegram.Chat.SENDER` for a private chat with the inline query + sender, :attr:`telegram.Chat.PRIVATE`, :attr:`telegram.Chat.GROUP`, + :attr:`telegram.Chat.SUPERGROUP` or :attr:`telegram.Chat.CHANNEL`. The chat type should + be always known for requests sent from official clients and most third-party clients, + unless the request was sent from a secret chat. + + .. versionadded:: 13.5 + location (:class:`telegram.Location`, optional): Sender location, only for bots that + request user location. + bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + id (:obj:`str`): Unique identifier for this query. + from_user (:class:`telegram.User`): Sender. + query (:obj:`str`): Text of the query (up to 256 characters). + offset (:obj:`str`): Offset of the results to be returned, can be controlled by the bot. + location (:class:`telegram.Location`): Optional. Sender location, only for bots that + request user location. + chat_type (:obj:`str`, optional): Type of the chat, from which the inline query was sent. + + .. versionadded:: 13.5 + + """ + + __slots__ = ('bot', 'location', 'chat_type', 'id', 'offset', 'from_user', 'query', '_id_attrs') + + def __init__( + self, + id: str, # pylint: disable=W0622 + from_user: User, + query: str, + offset: str, + location: Location = None, + bot: 'Bot' = None, + chat_type: str = None, + **_kwargs: Any, + ): + # Required + self.id = id # pylint: disable=C0103 + self.from_user = from_user + self.query = query + self.offset = offset + + # Optional + self.location = location + self.chat_type = chat_type + + self.bot = bot + self._id_attrs = (self.id,) + + @classmethod + def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['InlineQuery']: + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + if not data: + return None + + data['from_user'] = User.de_json(data.get('from'), bot) + data['location'] = Location.de_json(data.get('location'), bot) + + return cls(bot=bot, **data) + + def answer( + self, + results: Union[ + Sequence['InlineQueryResult'], Callable[[int], Optional[Sequence['InlineQueryResult']]] + ], + cache_time: int = 300, + is_personal: bool = None, + next_offset: str = None, + switch_pm_text: str = None, + switch_pm_parameter: str = None, + timeout: ODVInput[float] = DEFAULT_NONE, + current_offset: str = None, + api_kwargs: JSONDict = None, + auto_pagination: bool = False, + ) -> bool: + """Shortcut for:: + + bot.answer_inline_query(update.inline_query.id, + *args, + current_offset=self.offset if auto_pagination else None, + **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Bot.answer_inline_query`. + + Args: + auto_pagination (:obj:`bool`, optional): If set to :obj:`True`, :attr:`offset` will be + passed as :attr:`current_offset` to :meth:`telegram.Bot.answer_inline_query`. + Defaults to :obj:`False`. + + Raises: + TypeError: If both :attr:`current_offset` and :attr:`auto_pagination` are supplied. + """ + if current_offset and auto_pagination: + # We raise TypeError instead of ValueError for backwards compatibility with versions + # which didn't check this here but let Python do the checking + raise TypeError('current_offset and auto_pagination are mutually exclusive!') + return self.bot.answer_inline_query( + inline_query_id=self.id, + current_offset=self.offset if auto_pagination else current_offset, + results=results, + cache_time=cache_time, + is_personal=is_personal, + next_offset=next_offset, + switch_pm_text=switch_pm_text, + switch_pm_parameter=switch_pm_parameter, + timeout=timeout, + api_kwargs=api_kwargs, + ) + + MAX_RESULTS: ClassVar[int] = constants.MAX_INLINE_QUERY_RESULTS + """ + :const:`telegram.constants.MAX_INLINE_QUERY_RESULTS` + + .. versionadded:: 13.2 + """ diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresult.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresult.py new file mode 100644 index 0000000..756e2fb --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresult.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +# pylint: disable=W0622 +"""This module contains the classes that represent Telegram InlineQueryResult.""" + +from typing import Any + +from telegram import TelegramObject +from telegram.utils.types import JSONDict + + +class InlineQueryResult(TelegramObject): + """Baseclass for the InlineQueryResult* classes. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`id` is equal. + + Note: + All URLs passed in inline query results will be available to end users and therefore must + be assumed to be *public*. + + Args: + type (:obj:`str`): Type of the result. + id (:obj:`str`): Unique identifier for this result, 1-64 Bytes. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + type (:obj:`str`): Type of the result. + id (:obj:`str`): Unique identifier for this result, 1-64 Bytes. + + """ + + __slots__ = ('type', 'id', '_id_attrs') + + def __init__(self, type: str, id: str, **_kwargs: Any): + # Required + self.type = str(type) + self.id = str(id) # pylint: disable=C0103 + + self._id_attrs = (self.id,) + + def to_dict(self) -> JSONDict: + """See :meth:`telegram.TelegramObject.to_dict`.""" + data = super().to_dict() + + # pylint: disable=E1101 + if ( + hasattr(self, 'caption_entities') + and self.caption_entities # type: ignore[attr-defined] + ): + data['caption_entities'] = [ + ce.to_dict() for ce in self.caption_entities # type: ignore[attr-defined] + ] + + return data diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultarticle.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultarticle.py new file mode 100644 index 0000000..3827ae3 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultarticle.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the classes that represent Telegram InlineQueryResultArticle.""" + +from typing import TYPE_CHECKING, Any + +from telegram import InlineQueryResult + +if TYPE_CHECKING: + from telegram import InputMessageContent, ReplyMarkup + + +class InlineQueryResultArticle(InlineQueryResult): + """This object represents a Telegram InlineQueryResultArticle. + + Args: + id (:obj:`str`): Unique identifier for this result, 1-64 Bytes. + title (:obj:`str`): Title of the result. + input_message_content (:class:`telegram.InputMessageContent`): Content of the message to + be sent. + reply_markup (:class:`telegram.ReplyMarkup`, optional): Inline keyboard attached to + the message + url (:obj:`str`, optional): URL of the result. + hide_url (:obj:`bool`, optional): Pass :obj:`True`, if you don't want the URL to be shown + in the message. + description (:obj:`str`, optional): Short description of the result. + thumb_url (:obj:`str`, optional): Url of the thumbnail for the result. + thumb_width (:obj:`int`, optional): Thumbnail width. + thumb_height (:obj:`int`, optional): Thumbnail height. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + type (:obj:`str`): 'article'. + id (:obj:`str`): Unique identifier for this result, 1-64 Bytes. + title (:obj:`str`): Title of the result. + input_message_content (:class:`telegram.InputMessageContent`): Content of the message to + be sent. + reply_markup (:class:`telegram.ReplyMarkup`): Optional. Inline keyboard attached to + the message. + url (:obj:`str`): Optional. URL of the result. + hide_url (:obj:`bool`): Optional. Pass :obj:`True`, if you don't want the URL to be shown + in the message. + description (:obj:`str`): Optional. Short description of the result. + thumb_url (:obj:`str`): Optional. Url of the thumbnail for the result. + thumb_width (:obj:`int`): Optional. Thumbnail width. + thumb_height (:obj:`int`): Optional. Thumbnail height. + + """ + + __slots__ = ( + 'reply_markup', + 'thumb_width', + 'thumb_height', + 'hide_url', + 'url', + 'title', + 'description', + 'input_message_content', + 'thumb_url', + ) + + def __init__( + self, + id: str, # pylint: disable=W0622 + title: str, + input_message_content: 'InputMessageContent', + reply_markup: 'ReplyMarkup' = None, + url: str = None, + hide_url: bool = None, + description: str = None, + thumb_url: str = None, + thumb_width: int = None, + thumb_height: int = None, + **_kwargs: Any, + ): + + # Required + super().__init__('article', id) + self.title = title + self.input_message_content = input_message_content + + # Optional + self.reply_markup = reply_markup + self.url = url + self.hide_url = hide_url + self.description = description + self.thumb_url = thumb_url + self.thumb_width = thumb_width + self.thumb_height = thumb_height diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultaudio.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultaudio.py new file mode 100644 index 0000000..93eaa16 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultaudio.py @@ -0,0 +1,116 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the classes that represent Telegram InlineQueryResultAudio.""" + +from typing import TYPE_CHECKING, Any, Union, Tuple, List + +from telegram import InlineQueryResult, MessageEntity +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import ODVInput + +if TYPE_CHECKING: + from telegram import InputMessageContent, ReplyMarkup + + +class InlineQueryResultAudio(InlineQueryResult): + """ + Represents a link to an mp3 audio file. By default, this audio file will be sent by the user. + Alternatively, you can use :attr:`input_message_content` to send a message with the specified + content instead of the audio. + + Args: + id (:obj:`str`): Unique identifier for this result, 1-64 bytes. + audio_url (:obj:`str`): A valid URL for the audio file. + title (:obj:`str`): Title. + performer (:obj:`str`, optional): Performer. + audio_duration (:obj:`str`, optional): Audio duration in seconds. + caption (:obj:`str`, optional): Caption, 0-1024 characters after entities parsing. + parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show + bold, italic, fixed-width text or inline URLs in the media caption. See the constants + in :class:`telegram.ParseMode` for the available modes. + caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special + entities that appear in the caption, which can be specified instead of + :attr:`parse_mode`. + reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached + to the message. + input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the + message to be sent instead of the audio. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + type (:obj:`str`): 'audio'. + id (:obj:`str`): Unique identifier for this result, 1-64 bytes. + audio_url (:obj:`str`): A valid URL for the audio file. + title (:obj:`str`): Title. + performer (:obj:`str`): Optional. Performer. + audio_duration (:obj:`str`): Optional. Audio duration in seconds. + caption (:obj:`str`): Optional. Caption, 0-1024 characters after entities parsing. + parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show + bold, italic, fixed-width text or inline URLs in the media caption. See the constants + in :class:`telegram.ParseMode` for the available modes. + caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special + entities that appear in the caption, which can be specified instead of + :attr:`parse_mode`. + reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached + to the message. + input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the + message to be sent instead of the audio. + + """ + + __slots__ = ( + 'reply_markup', + 'caption_entities', + 'caption', + 'title', + 'parse_mode', + 'audio_url', + 'performer', + 'input_message_content', + 'audio_duration', + ) + + def __init__( + self, + id: str, # pylint: disable=W0622 + audio_url: str, + title: str, + performer: str = None, + audio_duration: int = None, + caption: str = None, + reply_markup: 'ReplyMarkup' = None, + input_message_content: 'InputMessageContent' = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, + **_kwargs: Any, + ): + + # Required + super().__init__('audio', id) + self.audio_url = audio_url + self.title = title + + # Optionals + self.performer = performer + self.audio_duration = audio_duration + self.caption = caption + self.parse_mode = parse_mode + self.caption_entities = caption_entities + self.reply_markup = reply_markup + self.input_message_content = input_message_content diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedaudio.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedaudio.py new file mode 100644 index 0000000..41222bb --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedaudio.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the classes that represent Telegram InlineQueryResultCachedAudio.""" + +from typing import TYPE_CHECKING, Any, Union, Tuple, List + +from telegram import InlineQueryResult, MessageEntity +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import ODVInput + +if TYPE_CHECKING: + from telegram import InputMessageContent, ReplyMarkup + + +class InlineQueryResultCachedAudio(InlineQueryResult): + """ + Represents a link to an mp3 audio file stored on the Telegram servers. By default, this audio + file will be sent by the user. Alternatively, you can use :attr:`input_message_content` to + send a message with the specified content instead of the audio. + + Args: + id (:obj:`str`): Unique identifier for this result, 1-64 bytes. + audio_file_id (:obj:`str`): A valid file identifier for the audio file. + caption (:obj:`str`, optional): Caption, 0-1024 characters after entities parsing. + parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show + bold, italic, fixed-width text or inline URLs in the media caption. See the constants + in :class:`telegram.ParseMode` for the available modes. + caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special + entities that appear in the caption, which can be specified instead of + :attr:`parse_mode`. + reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached + to the message. + input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the + message to be sent instead of the audio. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + type (:obj:`str`): 'audio'. + id (:obj:`str`): Unique identifier for this result, 1-64 bytes. + audio_file_id (:obj:`str`): A valid file identifier for the audio file. + caption (:obj:`str`): Optional. Caption, 0-1024 characters after entities parsing. + parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show + bold, italic, fixed-width text or inline URLs in the media caption. See the constants + in :class:`telegram.ParseMode` for the available modes. + caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special + entities that appear in the caption, which can be specified instead of + :attr:`parse_mode`. + reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached + to the message. + input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the + message to be sent instead of the audio. + + """ + + __slots__ = ( + 'reply_markup', + 'caption_entities', + 'caption', + 'parse_mode', + 'audio_file_id', + 'input_message_content', + ) + + def __init__( + self, + id: str, # pylint: disable=W0622 + audio_file_id: str, + caption: str = None, + reply_markup: 'ReplyMarkup' = None, + input_message_content: 'InputMessageContent' = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, + **_kwargs: Any, + ): + # Required + super().__init__('audio', id) + self.audio_file_id = audio_file_id + + # Optionals + self.caption = caption + self.parse_mode = parse_mode + self.caption_entities = caption_entities + self.reply_markup = reply_markup + self.input_message_content = input_message_content diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcacheddocument.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcacheddocument.py new file mode 100644 index 0000000..784ccaf --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcacheddocument.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +# pylint: disable=W0622 +"""This module contains the classes that represent Telegram InlineQueryResultCachedDocument.""" + +from typing import TYPE_CHECKING, Any, Union, Tuple, List + +from telegram import InlineQueryResult, MessageEntity +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import ODVInput + +if TYPE_CHECKING: + from telegram import InputMessageContent, ReplyMarkup + + +class InlineQueryResultCachedDocument(InlineQueryResult): + """ + Represents a link to a file stored on the Telegram servers. By default, this file will be sent + by the user with an optional caption. Alternatively, you can use :attr:`input_message_content` + to send a message with the specified content instead of the file. + + Args: + id (:obj:`str`): Unique identifier for this result, 1-64 bytes. + title (:obj:`str`): Title for the result. + document_file_id (:obj:`str`): A valid file identifier for the file. + description (:obj:`str`, optional): Short description of the result. + caption (:obj:`str`, optional): Caption of the document to be sent, 0-1024 characters + after entities parsing. + parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show + bold, italic, fixed-width text or inline URLs in the media caption.. See the constants + in :class:`telegram.ParseMode` for the available modes. + caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special + entities that appear in the caption, which can be specified instead of + :attr:`parse_mode`. + reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached + to the message. + input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the + message to be sent instead of the file. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + type (:obj:`str`): 'document'. + id (:obj:`str`): Unique identifier for this result, 1-64 bytes. + title (:obj:`str`): Title for the result. + document_file_id (:obj:`str`): A valid file identifier for the file. + description (:obj:`str`): Optional. Short description of the result. + caption (:obj:`str`): Optional. Caption of the document to be sent, 0-1024 characters + after entities parsing. + parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show + bold, italic, fixed-width text or inline URLs in the media caption.. See the constants + in :class:`telegram.ParseMode` for the available modes. + caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special + entities that appear in the caption, which can be specified instead of + :attr:`parse_mode`. + reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached + to the message. + input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the + message to be sent instead of the file. + + """ + + __slots__ = ( + 'reply_markup', + 'caption_entities', + 'document_file_id', + 'caption', + 'title', + 'description', + 'parse_mode', + 'input_message_content', + ) + + def __init__( + self, + id: str, # pylint: disable=W0622 + title: str, + document_file_id: str, + description: str = None, + caption: str = None, + reply_markup: 'ReplyMarkup' = None, + input_message_content: 'InputMessageContent' = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, + **_kwargs: Any, + ): + # Required + super().__init__('document', id) + self.title = title + self.document_file_id = document_file_id + + # Optionals + self.description = description + self.caption = caption + self.parse_mode = parse_mode + self.caption_entities = caption_entities + self.reply_markup = reply_markup + self.input_message_content = input_message_content diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedgif.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedgif.py new file mode 100644 index 0000000..ca2fc42 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedgif.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the classes that represent Telegram InlineQueryResultCachedGif.""" + +from typing import TYPE_CHECKING, Any, Union, Tuple, List + +from telegram import InlineQueryResult, MessageEntity +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import ODVInput + +if TYPE_CHECKING: + from telegram import InputMessageContent, ReplyMarkup + + +class InlineQueryResultCachedGif(InlineQueryResult): + """ + Represents a link to an animated GIF file stored on the Telegram servers. By default, this + animated GIF file will be sent by the user with an optional caption. Alternatively, you can + use :attr:`input_message_content` to send a message with specified content instead of + the animation. + + Args: + id (:obj:`str`): Unique identifier for this result, 1-64 bytes. + gif_file_id (:obj:`str`): A valid file identifier for the GIF file. + title (:obj:`str`, optional): Title for the result.caption (:obj:`str`, optional): + caption (:obj:`str`, optional): Caption of the GIF file to be sent, 0-1024 characters + after entities parsing. + parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show + bold, italic, fixed-width text or inline URLs in the media caption. See the constants + in :class:`telegram.ParseMode` for the available modes. + caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special + entities that appear in the caption, which can be specified instead of + :attr:`parse_mode`. + reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached + to the message. + input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the + message to be sent instead of the gif. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + type (:obj:`str`): 'gif'. + id (:obj:`str`): Unique identifier for this result, 1-64 bytes. + gif_file_id (:obj:`str`): A valid file identifier for the GIF file. + title (:obj:`str`): Optional. Title for the result. + caption (:obj:`str`): Optional. Caption of the GIF file to be sent, 0-1024 characters + after entities parsing. + parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show + bold, italic, fixed-width text or inline URLs in the media caption. See the constants + in :class:`telegram.ParseMode` for the available modes. + caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special + entities that appear in the caption, which can be specified instead of + :attr:`parse_mode`. + reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached + to the message. + input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the + message to be sent instead of the gif. + + """ + + __slots__ = ( + 'reply_markup', + 'caption_entities', + 'caption', + 'title', + 'input_message_content', + 'parse_mode', + 'gif_file_id', + ) + + def __init__( + self, + id: str, # pylint: disable=W0622 + gif_file_id: str, + title: str = None, + caption: str = None, + reply_markup: 'ReplyMarkup' = None, + input_message_content: 'InputMessageContent' = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, + **_kwargs: Any, + ): + # Required + super().__init__('gif', id) + self.gif_file_id = gif_file_id + + # Optionals + self.title = title + self.caption = caption + self.parse_mode = parse_mode + self.caption_entities = caption_entities + self.reply_markup = reply_markup + self.input_message_content = input_message_content diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedmpeg4gif.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedmpeg4gif.py new file mode 100644 index 0000000..4f0f85c --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedmpeg4gif.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the classes that represent Telegram InlineQueryResultMpeg4Gif.""" + +from typing import TYPE_CHECKING, Any, Union, Tuple, List + +from telegram import InlineQueryResult, MessageEntity +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import ODVInput + +if TYPE_CHECKING: + from telegram import InputMessageContent, ReplyMarkup + + +class InlineQueryResultCachedMpeg4Gif(InlineQueryResult): + """ + Represents a link to a video animation (H.264/MPEG-4 AVC video without sound) stored on the + Telegram servers. By default, this animated MPEG-4 file will be sent by the user with an + optional caption. Alternatively, you can use :attr:`input_message_content` to send a message + with the specified content instead of the animation. + + Args: + id (:obj:`str`): Unique identifier for this result, 1-64 bytes. + mpeg4_file_id (:obj:`str`): A valid file identifier for the MP4 file. + title (:obj:`str`, optional): Title for the result. + caption (:obj:`str`, optional): Caption of the MPEG-4 file to be sent, 0-1024 characters + after entities parsing. + parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show + bold, italic, fixed-width text or inline URLs in the media caption. See the constants + in :class:`telegram.ParseMode` for the available modes. + caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special + entities that appear in the caption, which can be specified instead of + :attr:`parse_mode`. + reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached + to the message. + input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the + message to be sent instead of the MPEG-4 file. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + type (:obj:`str`): 'mpeg4_gif'. + id (:obj:`str`): Unique identifier for this result, 1-64 bytes. + mpeg4_file_id (:obj:`str`): A valid file identifier for the MP4 file. + title (:obj:`str`): Optional. Title for the result. + caption (:obj:`str`): Optional. Caption of the MPEG-4 file to be sent, 0-1024 characters + after entities parsing. + parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show + bold, italic, fixed-width text or inline URLs in the media caption. See the constants + in :class:`telegram.ParseMode` for the available modes. + caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special + entities that appear in the caption, which can be specified instead of + :attr:`parse_mode`. + reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached + to the message. + input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the + message to be sent instead of the MPEG-4 file. + + """ + + __slots__ = ( + 'reply_markup', + 'caption_entities', + 'mpeg4_file_id', + 'caption', + 'title', + 'parse_mode', + 'input_message_content', + ) + + def __init__( + self, + id: str, # pylint: disable=W0622 + mpeg4_file_id: str, + title: str = None, + caption: str = None, + reply_markup: 'ReplyMarkup' = None, + input_message_content: 'InputMessageContent' = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, + **_kwargs: Any, + ): + # Required + super().__init__('mpeg4_gif', id) + self.mpeg4_file_id = mpeg4_file_id + + # Optionals + self.title = title + self.caption = caption + self.parse_mode = parse_mode + self.caption_entities = caption_entities + self.reply_markup = reply_markup + self.input_message_content = input_message_content diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedphoto.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedphoto.py new file mode 100644 index 0000000..4a929dd --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedphoto.py @@ -0,0 +1,114 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +# pylint: disable=W0622 +"""This module contains the classes that represent Telegram InlineQueryResultPhoto""" + +from typing import TYPE_CHECKING, Any, Union, Tuple, List + +from telegram import InlineQueryResult, MessageEntity +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import ODVInput + +if TYPE_CHECKING: + from telegram import InputMessageContent, ReplyMarkup + + +class InlineQueryResultCachedPhoto(InlineQueryResult): + """ + Represents a link to a photo stored on the Telegram servers. By default, this photo will be + sent by the user with an optional caption. Alternatively, you can use + :attr:`input_message_content` to send a message with the specified content instead + of the photo. + + Args: + id (:obj:`str`): Unique identifier for this result, 1-64 bytes. + photo_file_id (:obj:`str`): A valid file identifier of the photo. + title (:obj:`str`, optional): Title for the result. + description (:obj:`str`, optional): Short description of the result. + caption (:obj:`str`, optional): Caption of the photo to be sent, 0-1024 characters after + entities parsing. + parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show + bold, italic, fixed-width text or inline URLs in the media caption. See the constants + in :class:`telegram.ParseMode` for the available modes. + caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special + entities that appear in the caption, which can be specified instead of + :attr:`parse_mode`. + reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached + to the message. + input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the + message to be sent instead of the photo. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + type (:obj:`str`): 'photo'. + id (:obj:`str`): Unique identifier for this result, 1-64 bytes. + photo_file_id (:obj:`str`): A valid file identifier of the photo. + title (:obj:`str`): Optional. Title for the result. + description (:obj:`str`): Optional. Short description of the result. + caption (:obj:`str`): Optional. Caption of the photo to be sent, 0-1024 characters after + entities parsing. + parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show + bold, italic, fixed-width text or inline URLs in the media caption. See the constants + in :class:`telegram.ParseMode` for the available modes. + caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special + entities that appear in the caption, which can be specified instead of + :attr:`parse_mode`. + reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached + to the message. + input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the + message to be sent instead of the photo. + + """ + + __slots__ = ( + 'reply_markup', + 'caption_entities', + 'caption', + 'title', + 'description', + 'parse_mode', + 'photo_file_id', + 'input_message_content', + ) + + def __init__( + self, + id: str, # pylint: disable=W0622 + photo_file_id: str, + title: str = None, + description: str = None, + caption: str = None, + reply_markup: 'ReplyMarkup' = None, + input_message_content: 'InputMessageContent' = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, + **_kwargs: Any, + ): + # Required + super().__init__('photo', id) + self.photo_file_id = photo_file_id + + # Optionals + self.title = title + self.description = description + self.caption = caption + self.parse_mode = parse_mode + self.caption_entities = caption_entities + self.reply_markup = reply_markup + self.input_message_content = input_message_content diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedsticker.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedsticker.py new file mode 100644 index 0000000..f369bdd --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedsticker.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the classes that represent Telegram InlineQueryResultCachedSticker.""" + +from typing import TYPE_CHECKING, Any + +from telegram import InlineQueryResult + +if TYPE_CHECKING: + from telegram import InputMessageContent, ReplyMarkup + + +class InlineQueryResultCachedSticker(InlineQueryResult): + """ + Represents a link to a sticker stored on the Telegram servers. By default, this sticker will + be sent by the user. Alternatively, you can use :attr:`input_message_content` to send a + message with the specified content instead of the sticker. + + Args: + id (:obj:`str`): Unique identifier for this result, 1-64 bytes. + sticker_file_id (:obj:`str`): A valid file identifier of the sticker. + reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached + to the message. + input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the + message to be sent instead of the sticker. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + type (:obj:`str`): 'sticker`. + id (:obj:`str`): Unique identifier for this result, 1-64 bytes. + sticker_file_id (:obj:`str`): A valid file identifier of the sticker. + reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached + to the message. + input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the + message to be sent instead of the sticker. + + """ + + __slots__ = ('reply_markup', 'input_message_content', 'sticker_file_id') + + def __init__( + self, + id: str, # pylint: disable=W0622 + sticker_file_id: str, + reply_markup: 'ReplyMarkup' = None, + input_message_content: 'InputMessageContent' = None, + **_kwargs: Any, + ): + # Required + super().__init__('sticker', id) + self.sticker_file_id = sticker_file_id + + # Optionals + self.reply_markup = reply_markup + self.input_message_content = input_message_content diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedvideo.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedvideo.py new file mode 100644 index 0000000..ee91515 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedvideo.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the classes that represent Telegram InlineQueryResultCachedVideo.""" + +from typing import TYPE_CHECKING, Any, Union, Tuple, List + +from telegram import InlineQueryResult, MessageEntity +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import ODVInput + +if TYPE_CHECKING: + from telegram import InputMessageContent, ReplyMarkup + + +class InlineQueryResultCachedVideo(InlineQueryResult): + """ + Represents a link to a video file stored on the Telegram servers. By default, this video file + will be sent by the user with an optional caption. Alternatively, you can use + :attr:`input_message_content` to send a message with the specified content instead + of the video. + + Args: + id (:obj:`str`): Unique identifier for this result, 1-64 bytes. + video_file_id (:obj:`str`): A valid file identifier for the video file. + title (:obj:`str`): Title for the result. + description (:obj:`str`, optional): Short description of the result. + caption (:obj:`str`, optional): Caption of the video to be sent, 0-1024 characters after + entities parsing. + parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show + bold, italic, fixed-width text or inline URLs in the media caption. See the constants + in :class:`telegram.ParseMode` for the available modes. + caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special + entities that appear in the caption, which can be specified instead of + :attr:`parse_mode`. + reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached + to the message. + input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the + message to be sent instead of the video. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + type (:obj:`str`): 'video'. + id (:obj:`str`): Unique identifier for this result, 1-64 bytes. + video_file_id (:obj:`str`): A valid file identifier for the video file. + title (:obj:`str`): Title for the result. + description (:obj:`str`): Optional. Short description of the result. + caption (:obj:`str`): Optional. Caption of the video to be sent, 0-1024 characters after + entities parsing. + parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show + bold, italic, fixed-width text or inline URLs in the media caption. See the constants + in :class:`telegram.ParseMode` for the available modes. + caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special + entities that appear in the caption, which can be specified instead of + :attr:`parse_mode`. + reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached + to the message. + input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the + message to be sent instead of the video. + + """ + + __slots__ = ( + 'reply_markup', + 'caption_entities', + 'caption', + 'title', + 'description', + 'parse_mode', + 'input_message_content', + 'video_file_id', + ) + + def __init__( + self, + id: str, # pylint: disable=W0622 + video_file_id: str, + title: str, + description: str = None, + caption: str = None, + reply_markup: 'ReplyMarkup' = None, + input_message_content: 'InputMessageContent' = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, + **_kwargs: Any, + ): + # Required + super().__init__('video', id) + self.video_file_id = video_file_id + self.title = title + + # Optionals + self.description = description + self.caption = caption + self.parse_mode = parse_mode + self.caption_entities = caption_entities + self.reply_markup = reply_markup + self.input_message_content = input_message_content diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedvoice.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedvoice.py new file mode 100644 index 0000000..ff2ef22 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedvoice.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the classes that represent Telegram InlineQueryResultCachedVoice.""" + +from typing import TYPE_CHECKING, Any, Union, Tuple, List + +from telegram import InlineQueryResult, MessageEntity +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import ODVInput + +if TYPE_CHECKING: + from telegram import InputMessageContent, ReplyMarkup + + +class InlineQueryResultCachedVoice(InlineQueryResult): + """ + Represents a link to a voice message stored on the Telegram servers. By default, this voice + message will be sent by the user. Alternatively, you can use :attr:`input_message_content` to + send a message with the specified content instead of the voice message. + + Args: + id (:obj:`str`): Unique identifier for this result, 1-64 bytes. + voice_file_id (:obj:`str`): A valid file identifier for the voice message. + title (:obj:`str`): Voice message title. + caption (:obj:`str`, optional): Caption, 0-1024 characters after entities parsing. + parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show + bold, italic, fixed-width text or inline URLs in the media caption. See the constants + in :class:`telegram.ParseMode` for the available modes. + caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special + entities that appear in the caption, which can be specified instead of + :attr:`parse_mode`. + reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached + to the message. + input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the + message to be sent instead of the voice message. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + type (:obj:`str`): 'voice'. + id (:obj:`str`): Unique identifier for this result, 1-64 bytes. + voice_file_id (:obj:`str`): A valid file identifier for the voice message. + title (:obj:`str`): Voice message title. + caption (:obj:`str`): Optional. Caption, 0-1024 characters after entities parsing. + parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show + bold, italic, fixed-width text or inline URLs in the media caption. See the constants + in :class:`telegram.ParseMode` for the available modes. + caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special + entities that appear in the caption, which can be specified instead of + :attr:`parse_mode`. + reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached + to the message. + input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the + message to be sent instead of the voice message. + + """ + + __slots__ = ( + 'reply_markup', + 'caption_entities', + 'caption', + 'title', + 'parse_mode', + 'voice_file_id', + 'input_message_content', + ) + + def __init__( + self, + id: str, # pylint: disable=W0622 + voice_file_id: str, + title: str, + caption: str = None, + reply_markup: 'ReplyMarkup' = None, + input_message_content: 'InputMessageContent' = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, + **_kwargs: Any, + ): + # Required + super().__init__('voice', id) + self.voice_file_id = voice_file_id + self.title = title + + # Optionals + self.caption = caption + self.parse_mode = parse_mode + self.caption_entities = caption_entities + self.reply_markup = reply_markup + self.input_message_content = input_message_content diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcontact.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcontact.py new file mode 100644 index 0000000..42dd75d --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcontact.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the classes that represent Telegram InlineQueryResultContact.""" + +from typing import TYPE_CHECKING, Any + +from telegram import InlineQueryResult + +if TYPE_CHECKING: + from telegram import InputMessageContent, ReplyMarkup + + +class InlineQueryResultContact(InlineQueryResult): + """ + Represents a contact with a phone number. By default, this contact will be sent by the user. + Alternatively, you can use :attr:`input_message_content` to send a message with the specified + content instead of the contact. + + Args: + id (:obj:`str`): Unique identifier for this result, 1-64 bytes. + phone_number (:obj:`str`): Contact's phone number. + first_name (:obj:`str`): Contact's first name. + last_name (:obj:`str`, optional): Contact's last name. + vcard (:obj:`str`, optional): Additional data about the contact in the form of a vCard, + 0-2048 bytes. + reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached + to the message. + input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the + message to be sent instead of the contact. + thumb_url (:obj:`str`, optional): Url of the thumbnail for the result. + thumb_width (:obj:`int`, optional): Thumbnail width. + thumb_height (:obj:`int`, optional): Thumbnail height. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + type (:obj:`str`): 'contact'. + id (:obj:`str`): Unique identifier for this result, 1-64 bytes. + phone_number (:obj:`str`): Contact's phone number. + first_name (:obj:`str`): Contact's first name. + last_name (:obj:`str`): Optional. Contact's last name. + vcard (:obj:`str`): Optional. Additional data about the contact in the form of a vCard, + 0-2048 bytes. + reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached + to the message. + input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the + message to be sent instead of the contact. + thumb_url (:obj:`str`): Optional. Url of the thumbnail for the result. + thumb_width (:obj:`int`): Optional. Thumbnail width. + thumb_height (:obj:`int`): Optional. Thumbnail height. + + """ + + __slots__ = ( + 'reply_markup', + 'thumb_width', + 'thumb_height', + 'vcard', + 'first_name', + 'last_name', + 'phone_number', + 'input_message_content', + 'thumb_url', + ) + + def __init__( + self, + id: str, # pylint: disable=W0622 + phone_number: str, + first_name: str, + last_name: str = None, + reply_markup: 'ReplyMarkup' = None, + input_message_content: 'InputMessageContent' = None, + thumb_url: str = None, + thumb_width: int = None, + thumb_height: int = None, + vcard: str = None, + **_kwargs: Any, + ): + # Required + super().__init__('contact', id) + self.phone_number = phone_number + self.first_name = first_name + + # Optionals + self.last_name = last_name + self.vcard = vcard + self.reply_markup = reply_markup + self.input_message_content = input_message_content + self.thumb_url = thumb_url + self.thumb_width = thumb_width + self.thumb_height = thumb_height diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultdocument.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultdocument.py new file mode 100644 index 0000000..4e3c0b0 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultdocument.py @@ -0,0 +1,135 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the classes that represent Telegram InlineQueryResultDocument""" + +from typing import TYPE_CHECKING, Any, Union, Tuple, List + +from telegram import InlineQueryResult, MessageEntity +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import ODVInput + +if TYPE_CHECKING: + from telegram import InputMessageContent, ReplyMarkup + + +class InlineQueryResultDocument(InlineQueryResult): + """ + Represents a link to a file. By default, this file will be sent by the user with an optional + caption. Alternatively, you can use :attr:`input_message_content` to send a message with the + specified content instead of the file. Currently, only .PDF and .ZIP files can be sent + using this method. + + Args: + id (:obj:`str`): Unique identifier for this result, 1-64 bytes. + title (:obj:`str`): Title for the result. + caption (:obj:`str`, optional): Caption of the document to be sent, 0-1024 characters + after entities parsing. + parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show + bold, italic, fixed-width text or inline URLs in the media caption. See the constants + in :class:`telegram.ParseMode` for the available modes. + caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special + entities that appear in the caption, which can be specified instead of + :attr:`parse_mode`. + document_url (:obj:`str`): A valid URL for the file. + mime_type (:obj:`str`): Mime type of the content of the file, either "application/pdf" + or "application/zip". + description (:obj:`str`, optional): Short description of the result. + reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached + to the message. + input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the + message to be sent instead of the file. + thumb_url (:obj:`str`, optional): URL of the thumbnail (jpeg only) for the file. + thumb_width (:obj:`int`, optional): Thumbnail width. + thumb_height (:obj:`int`, optional): Thumbnail height. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + type (:obj:`str`): 'document'. + id (:obj:`str`): Unique identifier for this result, 1-64 bytes. + title (:obj:`str`): Title for the result. + caption (:obj:`str`): Optional. Caption of the document to be sent, 0-1024 characters + after entities parsing. + parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show + bold, italic, fixed-width text or inline URLs in the media caption. See the constants + in :class:`telegram.ParseMode` for the available modes. + caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special + entities that appear in the caption, which can be specified instead of + :attr:`parse_mode`. + document_url (:obj:`str`): A valid URL for the file. + mime_type (:obj:`str`): Mime type of the content of the file, either "application/pdf" + or "application/zip". + description (:obj:`str`): Optional. Short description of the result. + reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached + to the message. + input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the + message to be sent instead of the file. + thumb_url (:obj:`str`): Optional. URL of the thumbnail (jpeg only) for the file. + thumb_width (:obj:`int`): Optional. Thumbnail width. + thumb_height (:obj:`int`): Optional. Thumbnail height. + + """ + + __slots__ = ( + 'reply_markup', + 'caption_entities', + 'document_url', + 'thumb_width', + 'thumb_height', + 'caption', + 'title', + 'description', + 'parse_mode', + 'mime_type', + 'thumb_url', + 'input_message_content', + ) + + def __init__( + self, + id: str, # pylint: disable=W0622 + document_url: str, + title: str, + mime_type: str, + caption: str = None, + description: str = None, + reply_markup: 'ReplyMarkup' = None, + input_message_content: 'InputMessageContent' = None, + thumb_url: str = None, + thumb_width: int = None, + thumb_height: int = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, + **_kwargs: Any, + ): + # Required + super().__init__('document', id) + self.document_url = document_url + self.title = title + self.mime_type = mime_type + + # Optionals + self.caption = caption + self.parse_mode = parse_mode + self.caption_entities = caption_entities + self.description = description + self.reply_markup = reply_markup + self.input_message_content = input_message_content + self.thumb_url = thumb_url + self.thumb_width = thumb_width + self.thumb_height = thumb_height diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultgame.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultgame.py new file mode 100644 index 0000000..f8535b4 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultgame.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the classes that represent Telegram InlineQueryResultGame.""" + +from typing import TYPE_CHECKING, Any + +from telegram import InlineQueryResult + +if TYPE_CHECKING: + from telegram import ReplyMarkup + + +class InlineQueryResultGame(InlineQueryResult): + """Represents a :class:`telegram.Game`. + + Args: + id (:obj:`str`): Unique identifier for this result, 1-64 bytes. + game_short_name (:obj:`str`): Short name of the game. + reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached + to the message. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + type (:obj:`str`): 'game'. + id (:obj:`str`): Unique identifier for this result, 1-64 bytes. + game_short_name (:obj:`str`): Short name of the game. + reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached + to the message. + + """ + + __slots__ = ('reply_markup', 'game_short_name') + + def __init__( + self, + id: str, # pylint: disable=W0622 + game_short_name: str, + reply_markup: 'ReplyMarkup' = None, + **_kwargs: Any, + ): + # Required + super().__init__('game', id) + self.id = id # pylint: disable=W0622 + self.game_short_name = game_short_name + + self.reply_markup = reply_markup diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultgif.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultgif.py new file mode 100644 index 0000000..619af45 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultgif.py @@ -0,0 +1,137 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +# pylint: disable=W0622 +"""This module contains the classes that represent Telegram InlineQueryResultGif.""" + +from typing import TYPE_CHECKING, Any, Union, Tuple, List + +from telegram import InlineQueryResult, MessageEntity +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import ODVInput + +if TYPE_CHECKING: + from telegram import InputMessageContent, ReplyMarkup + + +class InlineQueryResultGif(InlineQueryResult): + """ + Represents a link to an animated GIF file. By default, this animated GIF file will be sent by + the user with optional caption. Alternatively, you can use :attr:`input_message_content` to + send a message with the specified content instead of the animation. + + Args: + id (:obj:`str`): Unique identifier for this result, 1-64 bytes. + gif_url (:obj:`str`): A valid URL for the GIF file. File size must not exceed 1MB. + gif_width (:obj:`int`, optional): Width of the GIF. + gif_height (:obj:`int`, optional): Height of the GIF. + gif_duration (:obj:`int`, optional): Duration of the GIF + thumb_url (:obj:`str`): URL of the static (JPEG or GIF) or animated (MPEG4) thumbnail for + the result. + thumb_mime_type (:obj:`str`, optional): MIME type of the thumbnail, must be one of + ``'image/jpeg'``, ``'image/gif'``, or ``'video/mp4'``. Defaults to ``'image/jpeg'``. + title (:obj:`str`, optional): Title for the result. + caption (:obj:`str`, optional): Caption of the GIF file to be sent, 0-1024 characters + after entities parsing. + parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show + bold, italic, fixed-width text or inline URLs in the media caption. See the constants + in :class:`telegram.ParseMode` for the available modes. + caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special + entities that appear in the caption, which can be specified instead of + :attr:`parse_mode`. + reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached + to the message. + input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the + message to be sent instead of the GIF animation. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + type (:obj:`str`): 'gif'. + id (:obj:`str`): Unique identifier for this result, 1-64 bytes. + gif_url (:obj:`str`): A valid URL for the GIF file. File size must not exceed 1MB. + gif_width (:obj:`int`): Optional. Width of the GIF. + gif_height (:obj:`int`): Optional. Height of the GIF. + gif_duration (:obj:`int`): Optional. Duration of the GIF. + thumb_url (:obj:`str`): URL of the static (JPEG or GIF) or animated (MPEG4) thumbnail for + the result. + thumb_mime_type (:obj:`str`): Optional. MIME type of the thumbnail. + title (:obj:`str`): Optional. Title for the result. + caption (:obj:`str`): Optional. Caption of the GIF file to be sent, 0-1024 characters + after entities parsing. + parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show + bold, italic, fixed-width text or inline URLs in the media caption. See the constants + in :class:`telegram.ParseMode` for the available modes. + caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special + entities that appear in the caption, which can be specified instead of + :attr:`parse_mode`. + reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached + to the message. + input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the + message to be sent instead of the GIF animation. + + """ + + __slots__ = ( + 'reply_markup', + 'gif_height', + 'thumb_mime_type', + 'caption_entities', + 'gif_width', + 'title', + 'caption', + 'parse_mode', + 'gif_duration', + 'input_message_content', + 'gif_url', + 'thumb_url', + ) + + def __init__( + self, + id: str, # pylint: disable=W0622 + gif_url: str, + thumb_url: str, + gif_width: int = None, + gif_height: int = None, + title: str = None, + caption: str = None, + reply_markup: 'ReplyMarkup' = None, + input_message_content: 'InputMessageContent' = None, + gif_duration: int = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + thumb_mime_type: str = None, + caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, + **_kwargs: Any, + ): + + # Required + super().__init__('gif', id) + self.gif_url = gif_url + self.thumb_url = thumb_url + + # Optionals + self.gif_width = gif_width + self.gif_height = gif_height + self.gif_duration = gif_duration + self.title = title + self.caption = caption + self.parse_mode = parse_mode + self.caption_entities = caption_entities + self.reply_markup = reply_markup + self.input_message_content = input_message_content + self.thumb_mime_type = thumb_mime_type diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultlocation.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultlocation.py new file mode 100644 index 0000000..2591b63 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultlocation.py @@ -0,0 +1,131 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the classes that represent Telegram InlineQueryResultLocation.""" + +from typing import TYPE_CHECKING, Any + +from telegram import InlineQueryResult + +if TYPE_CHECKING: + from telegram import InputMessageContent, ReplyMarkup + + +class InlineQueryResultLocation(InlineQueryResult): + """ + Represents a location on a map. By default, the location will be sent by the user. + Alternatively, you can use :attr:`input_message_content` to send a message with the specified + content instead of the location. + + Args: + id (:obj:`str`): Unique identifier for this result, 1-64 bytes. + latitude (:obj:`float`): Location latitude in degrees. + longitude (:obj:`float`): Location longitude in degrees. + title (:obj:`str`): Location title. + horizontal_accuracy (:obj:`float`, optional): The radius of uncertainty for the location, + measured in meters; 0-1500. + live_period (:obj:`int`, optional): Period in seconds for which the location can be + updated, should be between 60 and 86400. + heading (:obj:`int`, optional): For live locations, a direction in which the user is + moving, in degrees. Must be between 1 and 360 if specified. + proximity_alert_radius (:obj:`int`, optional): For live locations, a maximum distance for + proximity alerts about approaching another chat member, in meters. Must be between 1 + and 100000 if specified. + reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached + to the message. + input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the + message to be sent instead of the location. + thumb_url (:obj:`str`, optional): Url of the thumbnail for the result. + thumb_width (:obj:`int`, optional): Thumbnail width. + thumb_height (:obj:`int`, optional): Thumbnail height. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + type (:obj:`str`): 'location'. + id (:obj:`str`): Unique identifier for this result, 1-64 bytes. + latitude (:obj:`float`): Location latitude in degrees. + longitude (:obj:`float`): Location longitude in degrees. + title (:obj:`str`): Location title. + horizontal_accuracy (:obj:`float`): Optional. The radius of uncertainty for the location, + measured in meters. + live_period (:obj:`int`): Optional. Period in seconds for which the location can be + updated, should be between 60 and 86400. + heading (:obj:`int`): Optional. For live locations, a direction in which the user is + moving, in degrees. + proximity_alert_radius (:obj:`int`): Optional. For live locations, a maximum distance for + proximity alerts about approaching another chat member, in meters. + reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached + to the message. + input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the + message to be sent instead of the location. + thumb_url (:obj:`str`): Optional. Url of the thumbnail for the result. + thumb_width (:obj:`int`): Optional. Thumbnail width. + thumb_height (:obj:`int`): Optional. Thumbnail height. + + """ + + __slots__ = ( + 'longitude', + 'reply_markup', + 'thumb_width', + 'thumb_height', + 'heading', + 'title', + 'live_period', + 'proximity_alert_radius', + 'input_message_content', + 'latitude', + 'horizontal_accuracy', + 'thumb_url', + ) + + def __init__( + self, + id: str, # pylint: disable=W0622 + latitude: float, + longitude: float, + title: str, + live_period: int = None, + reply_markup: 'ReplyMarkup' = None, + input_message_content: 'InputMessageContent' = None, + thumb_url: str = None, + thumb_width: int = None, + thumb_height: int = None, + horizontal_accuracy: float = None, + heading: int = None, + proximity_alert_radius: int = None, + **_kwargs: Any, + ): + # Required + super().__init__('location', id) + self.latitude = float(latitude) + self.longitude = float(longitude) + self.title = title + + # Optionals + self.live_period = live_period + self.reply_markup = reply_markup + self.input_message_content = input_message_content + self.thumb_url = thumb_url + self.thumb_width = thumb_width + self.thumb_height = thumb_height + self.horizontal_accuracy = float(horizontal_accuracy) if horizontal_accuracy else None + self.heading = int(heading) if heading else None + self.proximity_alert_radius = ( + int(proximity_alert_radius) if proximity_alert_radius else None + ) diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultmpeg4gif.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultmpeg4gif.py new file mode 100644 index 0000000..3eb1c21 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultmpeg4gif.py @@ -0,0 +1,136 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the classes that represent Telegram InlineQueryResultMpeg4Gif.""" + +from typing import TYPE_CHECKING, Any, Union, Tuple, List + +from telegram import InlineQueryResult, MessageEntity +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import ODVInput + +if TYPE_CHECKING: + from telegram import InputMessageContent, ReplyMarkup + + +class InlineQueryResultMpeg4Gif(InlineQueryResult): + """ + Represents a link to a video animation (H.264/MPEG-4 AVC video without sound). By default, this + animated MPEG-4 file will be sent by the user with optional caption. Alternatively, you can + use :attr:`input_message_content` to send a message with the specified content instead of the + animation. + + Args: + id (:obj:`str`): Unique identifier for this result, 1-64 bytes. + mpeg4_url (:obj:`str`): A valid URL for the MP4 file. File size must not exceed 1MB. + mpeg4_width (:obj:`int`, optional): Video width. + mpeg4_height (:obj:`int`, optional): Video height. + mpeg4_duration (:obj:`int`, optional): Video duration. + thumb_url (:obj:`str`): URL of the static thumbnail (jpeg or gif) for the result. + thumb_mime_type (:obj:`str`): Optional. MIME type of the thumbnail, must be one of + ``'image/jpeg'``, ``'image/gif'``, or ``'video/mp4'``. Defaults to ``'image/jpeg'``. + title (:obj:`str`, optional): Title for the result. + caption (:obj:`str`, optional): Caption of the MPEG-4 file to be sent, 0-1024 characters + after entities parsing. + parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show + bold, italic, fixed-width text or inline URLs in the media caption. See the constants + in :class:`telegram.ParseMode` for the available modes. + caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special + entities that appear in the caption, which can be specified instead of + :attr:`parse_mode`. + reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached + to the message. + input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the + message to be sent instead of the video animation. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + type (:obj:`str`): 'mpeg4_gif'. + id (:obj:`str`): Unique identifier for this result, 1-64 bytes. + mpeg4_url (:obj:`str`): A valid URL for the MP4 file. File size must not exceed 1MB. + mpeg4_width (:obj:`int`): Optional. Video width. + mpeg4_height (:obj:`int`): Optional. Video height. + mpeg4_duration (:obj:`int`): Optional. Video duration. + thumb_url (:obj:`str`): URL of the static (JPEG or GIF) or animated (MPEG4) thumbnail for + the result. + thumb_mime_type (:obj:`str`): Optional. MIME type of the thumbnail. + title (:obj:`str`): Optional. Title for the result. + caption (:obj:`str`): Optional. Caption of the MPEG-4 file to be sent, 0-1024 characters + after entities parsing. + parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show + bold, italic, fixed-width text or inline URLs in the media caption. See the constants + in :class:`telegram.ParseMode` for the available modes. + caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special + entities that appear in the caption, which can be specified instead of + :attr:`parse_mode`. + reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached + to the message. + input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the + message to be sent instead of the video animation. + + """ + + __slots__ = ( + 'reply_markup', + 'thumb_mime_type', + 'caption_entities', + 'mpeg4_duration', + 'mpeg4_width', + 'title', + 'caption', + 'parse_mode', + 'input_message_content', + 'mpeg4_url', + 'mpeg4_height', + 'thumb_url', + ) + + def __init__( + self, + id: str, # pylint: disable=W0622 + mpeg4_url: str, + thumb_url: str, + mpeg4_width: int = None, + mpeg4_height: int = None, + title: str = None, + caption: str = None, + reply_markup: 'ReplyMarkup' = None, + input_message_content: 'InputMessageContent' = None, + mpeg4_duration: int = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + thumb_mime_type: str = None, + caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, + **_kwargs: Any, + ): + + # Required + super().__init__('mpeg4_gif', id) + self.mpeg4_url = mpeg4_url + self.thumb_url = thumb_url + + # Optional + self.mpeg4_width = mpeg4_width + self.mpeg4_height = mpeg4_height + self.mpeg4_duration = mpeg4_duration + self.title = title + self.caption = caption + self.parse_mode = parse_mode + self.caption_entities = caption_entities + self.reply_markup = reply_markup + self.input_message_content = input_message_content + self.thumb_mime_type = thumb_mime_type diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultphoto.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultphoto.py new file mode 100644 index 0000000..98f7185 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultphoto.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the classes that represent Telegram InlineQueryResultPhoto.""" + +from typing import TYPE_CHECKING, Any, Union, Tuple, List + +from telegram import InlineQueryResult, MessageEntity +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import ODVInput + +if TYPE_CHECKING: + from telegram import InputMessageContent, ReplyMarkup + + +class InlineQueryResultPhoto(InlineQueryResult): + """ + Represents a link to a photo. By default, this photo will be sent by the user with optional + caption. Alternatively, you can use :attr:`input_message_content` to send a message with the + specified content instead of the photo. + + Args: + id (:obj:`str`): Unique identifier for this result, 1-64 bytes. + photo_url (:obj:`str`): A valid URL of the photo. Photo must be in jpeg format. Photo size + must not exceed 5MB. + thumb_url (:obj:`str`): URL of the thumbnail for the photo. + photo_width (:obj:`int`, optional): Width of the photo. + photo_height (:obj:`int`, optional): Height of the photo. + title (:obj:`str`, optional): Title for the result. + description (:obj:`str`, optional): Short description of the result. + caption (:obj:`str`, optional): Caption of the photo to be sent, 0-1024 characters after + entities parsing. + parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show + bold, italic, fixed-width text or inline URLs in the media caption. See the constants + in :class:`telegram.ParseMode` for the available modes. + caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special + entities that appear in the caption, which can be specified instead of + :attr:`parse_mode`. + reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached + to the message. + input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the + message to be sent instead of the photo. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + type (:obj:`str`): 'photo'. + id (:obj:`str`): Unique identifier for this result, 1-64 bytes. + photo_url (:obj:`str`): A valid URL of the photo. Photo must be in jpeg format. Photo size + must not exceed 5MB. + thumb_url (:obj:`str`): URL of the thumbnail for the photo. + photo_width (:obj:`int`): Optional. Width of the photo. + photo_height (:obj:`int`): Optional. Height of the photo. + title (:obj:`str`): Optional. Title for the result. + description (:obj:`str`): Optional. Short description of the result. + caption (:obj:`str`): Optional. Caption of the photo to be sent, 0-1024 characters after + entities parsing. + parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show + bold, italic, fixed-width text or inline URLs in the media caption. See the constants + in :class:`telegram.ParseMode` for the available modes. + caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special + entities that appear in the caption, which can be specified instead of + :attr:`parse_mode`. + reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached + to the message. + input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the + message to be sent instead of the photo. + + """ + + __slots__ = ( + 'photo_url', + 'reply_markup', + 'caption_entities', + 'photo_width', + 'caption', + 'title', + 'description', + 'parse_mode', + 'input_message_content', + 'photo_height', + 'thumb_url', + ) + + def __init__( + self, + id: str, # pylint: disable=W0622 + photo_url: str, + thumb_url: str, + photo_width: int = None, + photo_height: int = None, + title: str = None, + description: str = None, + caption: str = None, + reply_markup: 'ReplyMarkup' = None, + input_message_content: 'InputMessageContent' = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, + **_kwargs: Any, + ): + # Required + super().__init__('photo', id) + self.photo_url = photo_url + self.thumb_url = thumb_url + + # Optionals + self.photo_width = int(photo_width) if photo_width is not None else None + self.photo_height = int(photo_height) if photo_height is not None else None + self.title = title + self.description = description + self.caption = caption + self.parse_mode = parse_mode + self.caption_entities = caption_entities + self.reply_markup = reply_markup + self.input_message_content = input_message_content diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultvenue.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultvenue.py new file mode 100644 index 0000000..9930f7a --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultvenue.py @@ -0,0 +1,133 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the classes that represent Telegram InlineQueryResultVenue.""" + +from typing import TYPE_CHECKING, Any + +from telegram import InlineQueryResult + +if TYPE_CHECKING: + from telegram import InputMessageContent, ReplyMarkup + + +class InlineQueryResultVenue(InlineQueryResult): + """ + Represents a venue. By default, the venue will be sent by the user. Alternatively, you can + use :attr:`input_message_content` to send a message with the specified content instead of the + venue. + + Note: + Foursquare details and Google Pace details are mutually exclusive. However, this + behaviour is undocumented and might be changed by Telegram. + + Args: + id (:obj:`str`): Unique identifier for this result, 1-64 Bytes. + latitude (:obj:`float`): Latitude of the venue location in degrees. + longitude (:obj:`float`): Longitude of the venue location in degrees. + title (:obj:`str`): Title of the venue. + address (:obj:`str`): Address of the venue. + foursquare_id (:obj:`str`, optional): Foursquare identifier of the venue if known. + foursquare_type (:obj:`str`, optional): Foursquare type of the venue, if known. + (For example, "arts_entertainment/default", "arts_entertainment/aquarium" or + "food/icecream".) + google_place_id (:obj:`str`, optional): Google Places identifier of the venue. + google_place_type (:obj:`str`, optional): Google Places type of the venue. (See + `supported types <https://developers.google.com/places/web-service/supported_types>`_.) + reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached + to the message. + input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the + message to be sent instead of the location. + thumb_url (:obj:`str`, optional): Url of the thumbnail for the result. + thumb_width (:obj:`int`, optional): Thumbnail width. + thumb_height (:obj:`int`, optional): Thumbnail height. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + type (:obj:`str`): 'venue'. + id (:obj:`str`): Unique identifier for this result, 1-64 Bytes. + latitude (:obj:`float`): Latitude of the venue location in degrees. + longitude (:obj:`float`): Longitude of the venue location in degrees. + title (:obj:`str`): Title of the venue. + address (:obj:`str`): Address of the venue. + foursquare_id (:obj:`str`): Optional. Foursquare identifier of the venue if known. + foursquare_type (:obj:`str`): Optional. Foursquare type of the venue, if known. + google_place_id (:obj:`str`): Optional. Google Places identifier of the venue. + google_place_type (:obj:`str`): Optional. Google Places type of the venue. + reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached + to the message. + input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the + message to be sent instead of the venue. + thumb_url (:obj:`str`): Optional. Url of the thumbnail for the result. + thumb_width (:obj:`int`): Optional. Thumbnail width. + thumb_height (:obj:`int`): Optional. Thumbnail height. + + """ + + __slots__ = ( + 'longitude', + 'reply_markup', + 'google_place_type', + 'thumb_width', + 'thumb_height', + 'title', + 'address', + 'foursquare_id', + 'foursquare_type', + 'google_place_id', + 'input_message_content', + 'latitude', + 'thumb_url', + ) + + def __init__( + self, + id: str, # pylint: disable=W0622 + latitude: float, + longitude: float, + title: str, + address: str, + foursquare_id: str = None, + foursquare_type: str = None, + reply_markup: 'ReplyMarkup' = None, + input_message_content: 'InputMessageContent' = None, + thumb_url: str = None, + thumb_width: int = None, + thumb_height: int = None, + google_place_id: str = None, + google_place_type: str = None, + **_kwargs: Any, + ): + + # Required + super().__init__('venue', id) + self.latitude = latitude + self.longitude = longitude + self.title = title + self.address = address + + # Optional + self.foursquare_id = foursquare_id + self.foursquare_type = foursquare_type + self.google_place_id = google_place_id + self.google_place_type = google_place_type + self.reply_markup = reply_markup + self.input_message_content = input_message_content + self.thumb_url = thumb_url + self.thumb_width = thumb_width + self.thumb_height = thumb_height diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultvideo.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultvideo.py new file mode 100644 index 0000000..b84a3f2 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultvideo.py @@ -0,0 +1,146 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the classes that represent Telegram InlineQueryResultVideo.""" + +from typing import TYPE_CHECKING, Any, Union, Tuple, List + +from telegram import InlineQueryResult, MessageEntity +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import ODVInput + +if TYPE_CHECKING: + from telegram import InputMessageContent, ReplyMarkup + + +class InlineQueryResultVideo(InlineQueryResult): + """ + Represents a link to a page containing an embedded video player or a video file. By default, + this video file will be sent by the user with an optional caption. Alternatively, you can use + :attr:`input_message_content` to send a message with the specified content instead of + the video. + + Note: + If an InlineQueryResultVideo message contains an embedded video (e.g., YouTube), you must + replace its content using :attr:`input_message_content`. + + Args: + id (:obj:`str`): Unique identifier for this result, 1-64 bytes. + video_url (:obj:`str`): A valid URL for the embedded video player or video file. + mime_type (:obj:`str`): Mime type of the content of video url, "text/html" or "video/mp4". + thumb_url (:obj:`str`): URL of the thumbnail (jpeg only) for the video. + title (:obj:`str`): Title for the result. + caption (:obj:`str`, optional): Caption, 0-1024 characters after entities parsing. + parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show + bold, italic, fixed-width text or inline URLs in the media caption. See the constants + in :class:`telegram.ParseMode` for the available modes. + caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special + entities that appear in the caption, which can be specified instead of + :attr:`parse_mode`. + video_width (:obj:`int`, optional): Video width. + video_height (:obj:`int`, optional): Video height. + video_duration (:obj:`int`, optional): Video duration in seconds. + description (:obj:`str`, optional): Short description of the result. + reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached + to the message. + input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the + message to be sent instead of the video. This field is required if + InlineQueryResultVideo is used to send an HTML-page as a result + (e.g., a YouTube video). + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + type (:obj:`str`): 'video'. + id (:obj:`str`): Unique identifier for this result, 1-64 bytes. + video_url (:obj:`str`): A valid URL for the embedded video player or video file. + mime_type (:obj:`str`): Mime type of the content of video url, "text/html" or "video/mp4". + thumb_url (:obj:`str`): URL of the thumbnail (jpeg only) for the video. + title (:obj:`str`): Title for the result. + caption (:obj:`str`): Optional. Caption of the video to be sent, 0-1024 characters after + entities parsing. + parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show + bold, italic, fixed-width text or inline URLs in the media caption. See the constants + in :class:`telegram.ParseMode` for the available modes. + caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special + entities that appear in the caption, which can be specified instead of + :attr:`parse_mode`. + video_width (:obj:`int`): Optional. Video width. + video_height (:obj:`int`): Optional. Video height. + video_duration (:obj:`int`): Optional. Video duration in seconds. + description (:obj:`str`): Optional. Short description of the result. + reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached + to the message. + input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the + message to be sent instead of the video. This field is required if + InlineQueryResultVideo is used to send an HTML-page as a result + (e.g., a YouTube video). + + """ + + __slots__ = ( + 'video_url', + 'reply_markup', + 'caption_entities', + 'caption', + 'title', + 'description', + 'video_duration', + 'parse_mode', + 'mime_type', + 'input_message_content', + 'video_height', + 'video_width', + 'thumb_url', + ) + + def __init__( + self, + id: str, # pylint: disable=W0622 + video_url: str, + mime_type: str, + thumb_url: str, + title: str, + caption: str = None, + video_width: int = None, + video_height: int = None, + video_duration: int = None, + description: str = None, + reply_markup: 'ReplyMarkup' = None, + input_message_content: 'InputMessageContent' = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, + **_kwargs: Any, + ): + + # Required + super().__init__('video', id) + self.video_url = video_url + self.mime_type = mime_type + self.thumb_url = thumb_url + self.title = title + + # Optional + self.caption = caption + self.parse_mode = parse_mode + self.caption_entities = caption_entities + self.video_width = video_width + self.video_height = video_height + self.video_duration = video_duration + self.description = description + self.reply_markup = reply_markup + self.input_message_content = input_message_content diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultvoice.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultvoice.py new file mode 100644 index 0000000..531f04b --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultvoice.py @@ -0,0 +1,112 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the classes that represent Telegram InlineQueryResultVoice.""" + +from typing import TYPE_CHECKING, Any, Union, Tuple, List + +from telegram import InlineQueryResult, MessageEntity +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import ODVInput + +if TYPE_CHECKING: + from telegram import InputMessageContent, ReplyMarkup + + +class InlineQueryResultVoice(InlineQueryResult): + """ + Represents a link to a voice recording in an .ogg container encoded with OPUS. By default, + this voice recording will be sent by the user. Alternatively, you can use + :attr:`input_message_content` to send a message with the specified content instead of the + the voice message. + + Args: + id (:obj:`str`): Unique identifier for this result, 1-64 bytes. + voice_url (:obj:`str`): A valid URL for the voice recording. + title (:obj:`str`): Recording title. + caption (:obj:`str`, optional): Caption, 0-1024 characters after entities parsing. + parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show + bold, italic, fixed-width text or inline URLs in the media caption. See the constants + in :class:`telegram.ParseMode` for the available modes. + caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special + entities that appear in the caption, which can be specified instead of + :attr:`parse_mode`. + voice_duration (:obj:`int`, optional): Recording duration in seconds. + reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached + to the message. + input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the + message to be sent instead of the voice recording. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + type (:obj:`str`): 'voice'. + id (:obj:`str`): Unique identifier for this result, 1-64 bytes. + voice_url (:obj:`str`): A valid URL for the voice recording. + title (:obj:`str`): Recording title. + caption (:obj:`str`): Optional. Caption, 0-1024 characters after entities parsing. + parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show + bold, italic, fixed-width text or inline URLs in the media caption. See the constants + in :class:`telegram.ParseMode` for the available modes. + caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special + entities that appear in the caption, which can be specified instead of + :attr:`parse_mode`. + voice_duration (:obj:`int`): Optional. Recording duration in seconds. + reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached + to the message. + input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the + message to be sent instead of the voice recording. + + """ + + __slots__ = ( + 'reply_markup', + 'caption_entities', + 'voice_duration', + 'caption', + 'title', + 'voice_url', + 'parse_mode', + 'input_message_content', + ) + + def __init__( + self, + id: str, # pylint: disable=W0622 + voice_url: str, + title: str, + voice_duration: int = None, + caption: str = None, + reply_markup: 'ReplyMarkup' = None, + input_message_content: 'InputMessageContent' = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, + **_kwargs: Any, + ): + + # Required + super().__init__('voice', id) + self.voice_url = voice_url + self.title = title + + # Optional + self.voice_duration = voice_duration + self.caption = caption + self.parse_mode = parse_mode + self.caption_entities = caption_entities + self.reply_markup = reply_markup + self.input_message_content = input_message_content diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inputcontactmessagecontent.py b/venv/lib/python3.8/site-packages/telegram/inline/inputcontactmessagecontent.py new file mode 100644 index 0000000..22e9460 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/inline/inputcontactmessagecontent.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the classes that represent Telegram InputContactMessageContent.""" + +from typing import Any + +from telegram import InputMessageContent + + +class InputContactMessageContent(InputMessageContent): + """Represents the content of a contact message to be sent as the result of an inline query. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`phone_number` is equal. + + Args: + phone_number (:obj:`str`): Contact's phone number. + first_name (:obj:`str`): Contact's first name. + last_name (:obj:`str`, optional): Contact's last name. + vcard (:obj:`str`, optional): Additional data about the contact in the form of a vCard, + 0-2048 bytes. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + phone_number (:obj:`str`): Contact's phone number. + first_name (:obj:`str`): Contact's first name. + last_name (:obj:`str`): Optional. Contact's last name. + vcard (:obj:`str`): Optional. Additional data about the contact in the form of a vCard, + 0-2048 bytes. + + """ + + __slots__ = ('vcard', 'first_name', 'last_name', 'phone_number', '_id_attrs') + + def __init__( + self, + phone_number: str, + first_name: str, + last_name: str = None, + vcard: str = None, + **_kwargs: Any, + ): + # Required + self.phone_number = phone_number + self.first_name = first_name + # Optionals + self.last_name = last_name + self.vcard = vcard + + self._id_attrs = (self.phone_number,) diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inputinvoicemessagecontent.py b/venv/lib/python3.8/site-packages/telegram/inline/inputinvoicemessagecontent.py new file mode 100644 index 0000000..2cbbcb8 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/inline/inputinvoicemessagecontent.py @@ -0,0 +1,242 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains a class that represents a Telegram InputInvoiceMessageContent.""" + +from typing import Any, List, Optional, TYPE_CHECKING + +from telegram import InputMessageContent, LabeledPrice +from telegram.utils.types import JSONDict + +if TYPE_CHECKING: + from telegram import Bot + + +class InputInvoiceMessageContent(InputMessageContent): + """ + Represents the content of a invoice message to be sent as the result of an inline query. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`title`, :attr:`description`, :attr:`payload`, + :attr:`provider_token`, :attr:`currency` and :attr:`prices` are equal. + + .. versionadded:: 13.5 + + Args: + title (:obj:`str`): Product name, 1-32 characters + description (:obj:`str`): Product description, 1-255 characters + payload (:obj:`str`):Bot-defined invoice payload, 1-128 bytes. This will not be displayed + to the user, use for your internal processes. + provider_token (:obj:`str`): Payment provider token, obtained via + `@Botfather <https://t.me/Botfather>`_. + currency (:obj:`str`): Three-letter ISO 4217 currency code, see more on + `currencies <https://core.telegram.org/bots/payments#supported-currencies>`_ + prices (List[:class:`telegram.LabeledPrice`]): Price breakdown, a JSON-serialized list of + components (e.g. product price, tax, discount, delivery cost, delivery tax, bonus, + etc.) + max_tip_amount (:obj:`int`, optional): The maximum accepted amount for tips in the smallest + units of the currency (integer, not float/double). For example, for a maximum tip of + US$ 1.45 pass ``max_tip_amount = 145``. See the ``exp`` parameter in + `currencies.json <https://core.telegram.org/bots/payments/currencies.json>`_, it + shows the number of digits past the decimal point for each currency (2 for the majority + of currencies). Defaults to ``0``. + suggested_tip_amounts (List[:obj:`int`], optional): A JSON-serialized array of suggested + amounts of tip in the smallest units of the currency (integer, not float/double). At + most 4 suggested tip amounts can be specified. The suggested tip amounts must be + positive, passed in a strictly increased order and must not exceed + :attr:`max_tip_amount`. + provider_data (:obj:`str`, optional): A JSON-serialized object for data about the invoice, + which will be shared with the payment provider. A detailed description of the required + fields should be provided by the payment provider. + photo_url (:obj:`str`, optional): URL of the product photo for the invoice. Can be a photo + of the goods or a marketing image for a service. People like it better when they see + what they are paying for. + photo_size (:obj:`int`, optional): Photo size. + photo_width (:obj:`int`, optional): Photo width. + photo_height (:obj:`int`, optional): Photo height. + need_name (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's full name to + complete the order. + need_phone_number (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's + phone number to complete the order + need_email (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's email + address to complete the order. + need_shipping_address (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's + shipping address to complete the order + send_phone_number_to_provider (:obj:`bool`, optional): Pass :obj:`True`, if user's phone + number should be sent to provider. + send_email_to_provider (:obj:`bool`, optional): Pass :obj:`True`, if user's email address + should be sent to provider. + is_flexible (:obj:`bool`, optional): Pass :obj:`True`, if the final price depends on the + shipping method. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + title (:obj:`str`): Product name, 1-32 characters + description (:obj:`str`): Product description, 1-255 characters + payload (:obj:`str`):Bot-defined invoice payload, 1-128 bytes. This will not be displayed + to the user, use for your internal processes. + provider_token (:obj:`str`): Payment provider token, obtained via + `@Botfather <https://t.me/Botfather>`_. + currency (:obj:`str`): Three-letter ISO 4217 currency code, see more on + `currencies <https://core.telegram.org/bots/payments#supported-currencies>`_ + prices (List[:class:`telegram.LabeledPrice`]): Price breakdown, a JSON-serialized list of + components. + max_tip_amount (:obj:`int`): Optional. The maximum accepted amount for tips in the smallest + units of the currency (integer, not float/double). + suggested_tip_amounts (List[:obj:`int`]): Optional. A JSON-serialized array of suggested + amounts of tip in the smallest units of the currency (integer, not float/double). + provider_data (:obj:`str`): Optional. A JSON-serialized object for data about the invoice, + which will be shared with the payment provider. + photo_url (:obj:`str`): Optional. URL of the product photo for the invoice. + photo_size (:obj:`int`): Optional. Photo size. + photo_width (:obj:`int`): Optional. Photo width. + photo_height (:obj:`int`): Optional. Photo height. + need_name (:obj:`bool`): Optional. Pass :obj:`True`, if you require the user's full name to + complete the order. + need_phone_number (:obj:`bool`): Optional. Pass :obj:`True`, if you require the user's + phone number to complete the order + need_email (:obj:`bool`): Optional. Pass :obj:`True`, if you require the user's email + address to complete the order. + need_shipping_address (:obj:`bool`): Optional. Pass :obj:`True`, if you require the user's + shipping address to complete the order + send_phone_number_to_provider (:obj:`bool`): Optional. Pass :obj:`True`, if user's phone + number should be sent to provider. + send_email_to_provider (:obj:`bool`): Optional. Pass :obj:`True`, if user's email address + should be sent to provider. + is_flexible (:obj:`bool`): Optional. Pass :obj:`True`, if the final price depends on the + shipping method. + + """ + + __slots__ = ( + 'title', + 'description', + 'payload', + 'provider_token', + 'currency', + 'prices', + 'max_tip_amount', + 'suggested_tip_amounts', + 'provider_data', + 'photo_url', + 'photo_size', + 'photo_width', + 'photo_height', + 'need_name', + 'need_phone_number', + 'need_email', + 'need_shipping_address', + 'send_phone_number_to_provider', + 'send_email_to_provider', + 'is_flexible', + '_id_attrs', + ) + + def __init__( + self, + title: str, + description: str, + payload: str, + provider_token: str, + currency: str, + prices: List[LabeledPrice], + max_tip_amount: int = None, + suggested_tip_amounts: List[int] = None, + provider_data: str = None, + photo_url: str = None, + photo_size: int = None, + photo_width: int = None, + photo_height: int = None, + need_name: bool = None, + need_phone_number: bool = None, + need_email: bool = None, + need_shipping_address: bool = None, + send_phone_number_to_provider: bool = None, + send_email_to_provider: bool = None, + is_flexible: bool = None, + **_kwargs: Any, + ): + # Required + self.title = title + self.description = description + self.payload = payload + self.provider_token = provider_token + self.currency = currency + self.prices = prices + # Optionals + self.max_tip_amount = int(max_tip_amount) if max_tip_amount else None + self.suggested_tip_amounts = ( + [int(sta) for sta in suggested_tip_amounts] if suggested_tip_amounts else None + ) + self.provider_data = provider_data + self.photo_url = photo_url + self.photo_size = int(photo_size) if photo_size else None + self.photo_width = int(photo_width) if photo_width else None + self.photo_height = int(photo_height) if photo_height else None + self.need_name = need_name + self.need_phone_number = need_phone_number + self.need_email = need_email + self.need_shipping_address = need_shipping_address + self.send_phone_number_to_provider = send_phone_number_to_provider + self.send_email_to_provider = send_email_to_provider + self.is_flexible = is_flexible + + self._id_attrs = ( + self.title, + self.description, + self.payload, + self.provider_token, + self.currency, + self.prices, + ) + + def __hash__(self) -> int: + # we override this as self.prices is a list and not hashable + prices = tuple(self.prices) + return hash( + ( + self.title, + self.description, + self.payload, + self.provider_token, + self.currency, + prices, + ) + ) + + def to_dict(self) -> JSONDict: + """See :meth:`telegram.TelegramObject.to_dict`.""" + data = super().to_dict() + + data['prices'] = [price.to_dict() for price in self.prices] + + return data + + @classmethod + def de_json( + cls, data: Optional[JSONDict], bot: 'Bot' + ) -> Optional['InputInvoiceMessageContent']: + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + if not data: + return None + + data['prices'] = LabeledPrice.de_list(data.get('prices'), bot) + + return cls(**data, bot=bot) diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inputlocationmessagecontent.py b/venv/lib/python3.8/site-packages/telegram/inline/inputlocationmessagecontent.py new file mode 100644 index 0000000..fe86628 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/inline/inputlocationmessagecontent.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the classes that represent Telegram InputLocationMessageContent.""" + +from typing import Any + +from telegram import InputMessageContent + + +class InputLocationMessageContent(InputMessageContent): + # fmt: off + """ + Represents the content of a location message to be sent as the result of an inline query. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`latitude` and :attr:`longitude` are equal. + + Args: + latitude (:obj:`float`): Latitude of the location in degrees. + longitude (:obj:`float`): Longitude of the location in degrees. + horizontal_accuracy (:obj:`float`, optional): The radius of uncertainty for the location, + measured in meters; 0-1500. + live_period (:obj:`int`, optional): Period in seconds for which the location can be + updated, should be between 60 and 86400. + heading (:obj:`int`, optional): For live locations, a direction in which the user is + moving, in degrees. Must be between 1 and 360 if specified. + proximity_alert_radius (:obj:`int`, optional): For live locations, a maximum distance for + proximity alerts about approaching another chat member, in meters. Must be between 1 + and 100000 if specified. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + latitude (:obj:`float`): Latitude of the location in degrees. + longitude (:obj:`float`): Longitude of the location in degrees. + horizontal_accuracy (:obj:`float`): Optional. The radius of uncertainty for the location, + measured in meters. + live_period (:obj:`int`): Optional. Period in seconds for which the location can be + updated. + heading (:obj:`int`): Optional. For live locations, a direction in which the user is + moving, in degrees. + proximity_alert_radius (:obj:`int`): Optional. For live locations, a maximum distance for + proximity alerts about approaching another chat member, in meters. + + """ + + __slots__ = ('longitude', 'horizontal_accuracy', 'proximity_alert_radius', 'live_period', + 'latitude', 'heading', '_id_attrs') + # fmt: on + + def __init__( + self, + latitude: float, + longitude: float, + live_period: int = None, + horizontal_accuracy: float = None, + heading: int = None, + proximity_alert_radius: int = None, + **_kwargs: Any, + ): + # Required + self.latitude = latitude + self.longitude = longitude + + # Optionals + self.live_period = int(live_period) if live_period else None + self.horizontal_accuracy = float(horizontal_accuracy) if horizontal_accuracy else None + self.heading = int(heading) if heading else None + self.proximity_alert_radius = ( + int(proximity_alert_radius) if proximity_alert_radius else None + ) + + self._id_attrs = (self.latitude, self.longitude) diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inputmessagecontent.py b/venv/lib/python3.8/site-packages/telegram/inline/inputmessagecontent.py new file mode 100644 index 0000000..44fd681 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/inline/inputmessagecontent.py @@ -0,0 +1,34 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the classes that represent Telegram InputMessageContent.""" + +from telegram import TelegramObject + + +class InputMessageContent(TelegramObject): + """Base class for Telegram InputMessageContent Objects. + + See: :class:`telegram.InputContactMessageContent`, + :class:`telegram.InputInvoiceMessageContent`, + :class:`telegram.InputLocationMessageContent`, :class:`telegram.InputTextMessageContent` and + :class:`telegram.InputVenueMessageContent` for more details. + + """ + + __slots__ = () diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inputtextmessagecontent.py b/venv/lib/python3.8/site-packages/telegram/inline/inputtextmessagecontent.py new file mode 100644 index 0000000..3d60f45 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/inline/inputtextmessagecontent.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the classes that represent Telegram InputTextMessageContent.""" + +from typing import Any, Union, Tuple, List + +from telegram import InputMessageContent, MessageEntity +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import JSONDict, ODVInput + + +class InputTextMessageContent(InputMessageContent): + """ + Represents the content of a text message to be sent as the result of an inline query. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`message_text` is equal. + + Args: + message_text (:obj:`str`): Text of the message to be sent, 1-4096 characters after entities + parsing. Also found as :attr:`telegram.constants.MAX_MESSAGE_LENGTH`. + parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show + bold, italic, fixed-width text or inline URLs in your bot's message. See the constants + in :class:`telegram.ParseMode` for the available modes. + entities (List[:class:`telegram.MessageEntity`], optional): List of special + entities that appear in the caption, which can be specified instead of + :attr:`parse_mode`. + disable_web_page_preview (:obj:`bool`, optional): Disables link previews for links in the + sent message. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + message_text (:obj:`str`): Text of the message to be sent, 1-4096 characters after entities + parsing. + parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show + bold, italic, fixed-width text or inline URLs in your bot's message. See the constants + in :class:`telegram.ParseMode` for the available modes. + entities (List[:class:`telegram.MessageEntity`]): Optional. List of special + entities that appear in the caption, which can be specified instead of + :attr:`parse_mode`. + disable_web_page_preview (:obj:`bool`): Optional. Disables link previews for links in the + sent message. + + """ + + __slots__ = ('disable_web_page_preview', 'parse_mode', 'entities', 'message_text', '_id_attrs') + + def __init__( + self, + message_text: str, + parse_mode: ODVInput[str] = DEFAULT_NONE, + disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, + entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, + **_kwargs: Any, + ): + # Required + self.message_text = message_text + # Optionals + self.parse_mode = parse_mode + self.entities = entities + self.disable_web_page_preview = disable_web_page_preview + + self._id_attrs = (self.message_text,) + + def to_dict(self) -> JSONDict: + """See :meth:`telegram.TelegramObject.to_dict`.""" + data = super().to_dict() + + if self.entities: + data['entities'] = [ce.to_dict() for ce in self.entities] + + return data diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inputvenuemessagecontent.py b/venv/lib/python3.8/site-packages/telegram/inline/inputvenuemessagecontent.py new file mode 100644 index 0000000..55652d2 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/inline/inputvenuemessagecontent.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the classes that represent Telegram InputVenueMessageContent.""" + +from typing import Any + +from telegram import InputMessageContent + + +class InputVenueMessageContent(InputMessageContent): + """Represents the content of a venue message to be sent as the result of an inline query. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`latitude`, :attr:`longitude` and :attr:`title` + are equal. + + Note: + Foursquare details and Google Pace details are mutually exclusive. However, this + behaviour is undocumented and might be changed by Telegram. + + Args: + latitude (:obj:`float`): Latitude of the location in degrees. + longitude (:obj:`float`): Longitude of the location in degrees. + title (:obj:`str`): Name of the venue. + address (:obj:`str`): Address of the venue. + foursquare_id (:obj:`str`, optional): Foursquare identifier of the venue, if known. + foursquare_type (:obj:`str`, optional): Foursquare type of the venue, if known. + (For example, "arts_entertainment/default", "arts_entertainment/aquarium" or + "food/icecream".) + google_place_id (:obj:`str`, optional): Google Places identifier of the venue. + google_place_type (:obj:`str`, optional): Google Places type of the venue. (See + `supported types <https://developers.google.com/places/web-service/supported_types>`_.) + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + latitude (:obj:`float`): Latitude of the location in degrees. + longitude (:obj:`float`): Longitude of the location in degrees. + title (:obj:`str`): Name of the venue. + address (:obj:`str`): Address of the venue. + foursquare_id (:obj:`str`): Optional. Foursquare identifier of the venue, if known. + foursquare_type (:obj:`str`): Optional. Foursquare type of the venue, if known. + google_place_id (:obj:`str`): Optional. Google Places identifier of the venue. + google_place_type (:obj:`str`): Optional. Google Places type of the venue. + + """ + + __slots__ = ( + 'longitude', + 'google_place_type', + 'title', + 'address', + 'foursquare_id', + 'foursquare_type', + 'google_place_id', + 'latitude', + '_id_attrs', + ) + + def __init__( + self, + latitude: float, + longitude: float, + title: str, + address: str, + foursquare_id: str = None, + foursquare_type: str = None, + google_place_id: str = None, + google_place_type: str = None, + **_kwargs: Any, + ): + # Required + self.latitude = latitude + self.longitude = longitude + self.title = title + self.address = address + # Optionals + self.foursquare_id = foursquare_id + self.foursquare_type = foursquare_type + self.google_place_id = google_place_id + self.google_place_type = google_place_type + + self._id_attrs = ( + self.latitude, + self.longitude, + self.title, + ) diff --git a/venv/lib/python3.8/site-packages/telegram/keyboardbutton.py b/venv/lib/python3.8/site-packages/telegram/keyboardbutton.py new file mode 100644 index 0000000..590801b --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/keyboardbutton.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram KeyboardButton.""" + +from typing import Any + +from telegram import TelegramObject, KeyboardButtonPollType + + +class KeyboardButton(TelegramObject): + """ + This object represents one button of the reply keyboard. For simple text buttons String can be + used instead of this object to specify text of the button. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`text`, :attr:`request_contact`, :attr:`request_location` and + :attr:`request_poll` are equal. + + Note: + * Optional fields are mutually exclusive. + * :attr:`request_contact` and :attr:`request_location` options will only work in Telegram + versions released after 9 April, 2016. Older clients will ignore them. + * :attr:`request_poll` option will only work in Telegram versions released after 23 + January, 2020. Older clients will receive unsupported message. + + Args: + text (:obj:`str`): Text of the button. If none of the optional fields are used, it will be + sent to the bot as a message when the button is pressed. + request_contact (:obj:`bool`, optional): If :obj:`True`, the user's phone number will be + sent as a contact when the button is pressed. Available in private chats only. + request_location (:obj:`bool`, optional): If :obj:`True`, the user's current location will + be sent when the button is pressed. Available in private chats only. + request_poll (:class:`KeyboardButtonPollType`, optional): If specified, the user will be + asked to create a poll and send it to the bot when the button is pressed. Available in + private chats only. + + Attributes: + text (:obj:`str`): Text of the button. + request_contact (:obj:`bool`): Optional. The user's phone number will be sent. + request_location (:obj:`bool`): Optional. The user's current location will be sent. + request_poll (:class:`KeyboardButtonPollType`): Optional. If the user should create a poll. + + """ + + __slots__ = ('request_location', 'request_contact', 'request_poll', 'text', '_id_attrs') + + def __init__( + self, + text: str, + request_contact: bool = None, + request_location: bool = None, + request_poll: KeyboardButtonPollType = None, + **_kwargs: Any, + ): + # Required + self.text = text + # Optionals + self.request_contact = request_contact + self.request_location = request_location + self.request_poll = request_poll + + self._id_attrs = ( + self.text, + self.request_contact, + self.request_location, + self.request_poll, + ) diff --git a/venv/lib/python3.8/site-packages/telegram/keyboardbuttonpolltype.py b/venv/lib/python3.8/site-packages/telegram/keyboardbuttonpolltype.py new file mode 100644 index 0000000..89be62a --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/keyboardbuttonpolltype.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python +# pylint: disable=R0903 +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2020-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a type of a Telegram Poll.""" +from typing import Any + +from telegram import TelegramObject + + +class KeyboardButtonPollType(TelegramObject): + """This object represents type of a poll, which is allowed to be created + and sent when the corresponding button is pressed. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`type` is equal. + + Attributes: + type (:obj:`str`): Optional. If :attr:`telegram.Poll.QUIZ` is passed, the user will be + allowed to create only polls in the quiz mode. If :attr:`telegram.Poll.REGULAR` is + passed, only regular polls will be allowed. Otherwise, the user will be allowed to + create a poll of any type. + """ + + __slots__ = ('type', '_id_attrs') + + def __init__(self, type: str = None, **_kwargs: Any): # pylint: disable=W0622 + self.type = type + + self._id_attrs = (self.type,) diff --git a/venv/lib/python3.8/site-packages/telegram/loginurl.py b/venv/lib/python3.8/site-packages/telegram/loginurl.py new file mode 100644 index 0000000..8179273 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/loginurl.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python +# pylint: disable=R0903 +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram LoginUrl.""" +from typing import Any + +from telegram import TelegramObject + + +class LoginUrl(TelegramObject): + """This object represents a parameter of the inline keyboard button used to automatically + authorize a user. Serves as a great replacement for the Telegram Login Widget when the user is + coming from Telegram. All the user needs to do is tap/click a button and confirm that they want + to log in. Telegram apps support these buttons as of version 5.7. + + Sample bot: `@discussbot <https://t.me/dicussbot>`_ + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`url` is equal. + + Note: + You must always check the hash of the received data to verify the authentication + and the integrity of the data as described in + `Checking authorization <https://core.telegram.org/widgets/login#checking-authorization>`_ + + Args: + url (:obj:`str`): An HTTP URL to be opened with user authorization data added to the query + string when the button is pressed. If the user refuses to provide authorization data, + the original URL without information about the user will be opened. The data added is + the same as described in + `Receiving authorization data + <https://core.telegram.org/widgets/login#receiving-authorization-data>`_ + forward_text (:obj:`str`, optional): New text of the button in forwarded messages. + bot_username (:obj:`str`, optional): Username of a bot, which will be used for user + authorization. See + `Setting up a bot <https://core.telegram.org/widgets/login#setting-up-a-bot>`_ + for more details. If not specified, the current + bot's username will be assumed. The url's domain must be the same as the domain linked + with the bot. See + `Linking your domain to the bot + <https://core.telegram.org/widgets/login#linking-your-domain-to-the-bot>`_ + for more details. + request_write_access (:obj:`bool`, optional): Pass :obj:`True` to request the permission + for your bot to send messages to the user. + + Attributes: + url (:obj:`str`): An HTTP URL to be opened with user authorization data. + forward_text (:obj:`str`): Optional. New text of the button in forwarded messages. + bot_username (:obj:`str`): Optional. Username of a bot, which will be used for user + authorization. + request_write_access (:obj:`bool`): Optional. Pass :obj:`True` to request the permission + for your bot to send messages to the user. + + """ + + __slots__ = ('bot_username', 'request_write_access', 'url', 'forward_text', '_id_attrs') + + def __init__( + self, + url: str, + forward_text: bool = None, + bot_username: str = None, + request_write_access: bool = None, + **_kwargs: Any, + ): + # Required + self.url = url + # Optional + self.forward_text = forward_text + self.bot_username = bot_username + self.request_write_access = request_write_access + + self._id_attrs = (self.url,) diff --git a/venv/lib/python3.8/site-packages/telegram/message.py b/venv/lib/python3.8/site-packages/telegram/message.py new file mode 100644 index 0000000..63e18bf --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/message.py @@ -0,0 +1,2888 @@ +#!/usr/bin/env python +# pylint: disable=R0902,R0913 +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram Message.""" +import datetime +import sys +from html import escape +from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union, ClassVar, Tuple + +from telegram import ( + Animation, + Audio, + Chat, + Contact, + Dice, + Document, + Game, + InlineKeyboardMarkup, + Invoice, + Location, + MessageEntity, + ParseMode, + PassportData, + PhotoSize, + Poll, + Sticker, + SuccessfulPayment, + TelegramObject, + User, + Venue, + Video, + VideoNote, + Voice, + VoiceChatStarted, + VoiceChatEnded, + VoiceChatParticipantsInvited, + ProximityAlertTriggered, + ReplyMarkup, + MessageAutoDeleteTimerChanged, + VoiceChatScheduled, +) +from telegram.utils.helpers import ( + escape_markdown, + from_timestamp, + to_timestamp, + DEFAULT_NONE, + DEFAULT_20, +) +from telegram.utils.types import JSONDict, FileInput, ODVInput, DVInput + +if TYPE_CHECKING: + from telegram import ( + Bot, + GameHighScore, + InputMedia, + MessageId, + InputMediaAudio, + InputMediaDocument, + InputMediaPhoto, + InputMediaVideo, + LabeledPrice, + ) + + +class Message(TelegramObject): + # fmt: off + """This object represents a message. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`message_id` and :attr:`chat` are equal. + + Note: + In Python ``from`` is a reserved word, use ``from_user`` instead. + + Args: + message_id (:obj:`int`): Unique message identifier inside this chat. + from_user (:class:`telegram.User`, optional): Sender, empty for messages sent + to channels. + sender_chat (:class:`telegram.Chat`, optional): Sender of the message, sent on behalf of a + chat. The channel itself for channel messages. The supergroup itself for messages from + anonymous group administrators. The linked channel for messages automatically forwarded + to the discussion group. + date (:class:`datetime.datetime`): Date the message was sent in Unix time. Converted to + :class:`datetime.datetime`. + chat (:class:`telegram.Chat`): Conversation the message belongs to. + forward_from (:class:`telegram.User`, optional): For forwarded messages, sender of + the original message. + forward_from_chat (:class:`telegram.Chat`, optional): For messages forwarded from channels + or from anonymous administrators, information about the original sender chat. + forward_from_message_id (:obj:`int`, optional): For forwarded channel posts, identifier of + the original message in the channel. + forward_sender_name (:obj:`str`, optional): Sender's name for messages forwarded from users + who disallow adding a link to their account in forwarded messages. + forward_date (:class:`datetime.datetime`, optional): For forwarded messages, date the + original message was sent in Unix time. Converted to :class:`datetime.datetime`. + reply_to_message (:class:`telegram.Message`, optional): For replies, the original message. + edit_date (:class:`datetime.datetime`, optional): Date the message was last edited in Unix + time. Converted to :class:`datetime.datetime`. + media_group_id (:obj:`str`, optional): The unique identifier of a media message group this + message belongs to. + text (str, optional): For text messages, the actual UTF-8 text of the message, 0-4096 + characters. Also found as :attr:`telegram.constants.MAX_MESSAGE_LENGTH`. + entities (List[:class:`telegram.MessageEntity`], optional): For text messages, special + entities like usernames, URLs, bot commands, etc. that appear in the text. See + :attr:`parse_entity` and :attr:`parse_entities` methods for how to use properly. + caption_entities (List[:class:`telegram.MessageEntity`]): Optional. For Messages with a + Caption. Special entities like usernames, URLs, bot commands, etc. that appear in the + caption. See :attr:`Message.parse_caption_entity` and :attr:`parse_caption_entities` + methods for how to use properly. + audio (:class:`telegram.Audio`, optional): Message is an audio file, information + about the file. + document (:class:`telegram.Document`, optional): Message is a general file, information + about the file. + animation (:class:`telegram.Animation`, optional): Message is an animation, information + about the animation. For backward compatibility, when this field is set, the document + field will also be set. + game (:class:`telegram.Game`, optional): Message is a game, information about the game. + photo (List[:class:`telegram.PhotoSize`], optional): Message is a photo, available + sizes of the photo. + sticker (:class:`telegram.Sticker`, optional): Message is a sticker, information + about the sticker. + video (:class:`telegram.Video`, optional): Message is a video, information about the video. + voice (:class:`telegram.Voice`, optional): Message is a voice message, information about + the file. + video_note (:class:`telegram.VideoNote`, optional): Message is a video note, information + about the video message. + new_chat_members (List[:class:`telegram.User`], optional): New members that were added to + the group or supergroup and information about them (the bot itself may be one of these + members). + caption (:obj:`str`, optional): Caption for the animation, audio, document, photo, video + or voice, 0-1024 characters. + contact (:class:`telegram.Contact`, optional): Message is a shared contact, information + about the contact. + location (:class:`telegram.Location`, optional): Message is a shared location, information + about the location. + venue (:class:`telegram.Venue`, optional): Message is a venue, information about the venue. + For backward compatibility, when this field is set, the location field will also be + set. + left_chat_member (:class:`telegram.User`, optional): A member was removed from the group, + information about them (this member may be the bot itself). + new_chat_title (:obj:`str`, optional): A chat title was changed to this value. + new_chat_photo (List[:class:`telegram.PhotoSize`], optional): A chat photo was changed to + this value. + delete_chat_photo (:obj:`bool`, optional): Service message: The chat photo was deleted. + group_chat_created (:obj:`bool`, optional): Service message: The group has been created. + supergroup_chat_created (:obj:`bool`, optional): Service message: The supergroup has been + created. This field can't be received in a message coming through updates, because bot + can't be a member of a supergroup when it is created. It can only be found in + :attr:`reply_to_message` if someone replies to a very first message in a directly + created supergroup. + channel_chat_created (:obj:`bool`, optional): Service message: The channel has been + created. This field can't be received in a message coming through updates, because bot + can't be a member of a channel when it is created. It can only be found in + :attr:`reply_to_message` if someone replies to a very first message in a channel. + message_auto_delete_timer_changed (:class:`telegram.MessageAutoDeleteTimerChanged`, \ + optional): Service message: auto-delete timer settings changed in the chat. + + .. versionadded:: 13.4 + migrate_to_chat_id (:obj:`int`, optional): The group has been migrated to a supergroup with + the specified identifier. This number may be greater than 32 bits and some programming + languages may have difficulty/silent defects in interpreting it. But it is smaller than + 52 bits, so a signed 64 bit integer or double-precision float type are safe for storing + this identifier. + migrate_from_chat_id (:obj:`int`, optional): The supergroup has been migrated from a group + with the specified identifier. This number may be greater than 32 bits and some + programming languages may have difficulty/silent defects in interpreting it. But it is + smaller than 52 bits, so a signed 64 bit integer or double-precision float type are + safe for storing this identifier. + pinned_message (:class:`telegram.Message`, optional): Specified message was pinned. Note + that the Message object in this field will not contain further :attr:`reply_to_message` + fields even if it is itself a reply. + invoice (:class:`telegram.Invoice`, optional): Message is an invoice for a payment, + information about the invoice. + successful_payment (:class:`telegram.SuccessfulPayment`, optional): Message is a service + message about a successful payment, information about the payment. + connected_website (:obj:`str`, optional): The domain name of the website on which the user + has logged in. + forward_signature (:obj:`str`, optional): For messages forwarded from channels, signature + of the post author if present. + author_signature (:obj:`str`, optional): Signature of the post author for messages in + channels, or the custom title of an anonymous group administrator. + passport_data (:class:`telegram.PassportData`, optional): Telegram Passport data. + poll (:class:`telegram.Poll`, optional): Message is a native poll, + information about the poll. + dice (:class:`telegram.Dice`, optional): Message is a dice with random value from 1 to 6. + via_bot (:class:`telegram.User`, optional): Message was sent through an inline bot. + proximity_alert_triggered (:class:`telegram.ProximityAlertTriggered`, optional): Service + message. A user in the chat triggered another user's proximity alert while sharing + Live Location. + voice_chat_scheduled (:class:`telegram.VoiceChatScheduled`, optional): Service message: + voice chat scheduled. + + .. versionadded:: 13.5 + voice_chat_started (:class:`telegram.VoiceChatStarted`, optional): Service message: voice + chat started. + + .. versionadded:: 13.4 + voice_chat_ended (:class:`telegram.VoiceChatEnded`, optional): Service message: voice chat + ended. + + .. versionadded:: 13.4 + voice_chat_participants_invited (:class:`telegram.VoiceChatParticipantsInvited` optional): + Service message: new participants invited to a voice chat. + + .. versionadded:: 13.4 + reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached + to the message. ``login_url`` buttons are represented as ordinary url buttons. + bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods. + + Attributes: + message_id (:obj:`int`): Unique message identifier inside this chat. + from_user (:class:`telegram.User`): Optional. Sender. + sender_chat (:class:`telegram.Chat`): Optional. Sender of the message, sent on behalf of a + chat. The channel itself for channel messages. The supergroup itself for messages from + anonymous group administrators. The linked channel for messages automatically forwarded + to the discussion group. + date (:class:`datetime.datetime`): Date the message was sent. + chat (:class:`telegram.Chat`): Conversation the message belongs to. + forward_from (:class:`telegram.User`): Optional. Sender of the original message. + forward_from_chat (:class:`telegram.Chat`): Optional. For messages forwarded from channels + or from anonymous administrators, information about the original sender chat. + forward_from_message_id (:obj:`int`): Optional. Identifier of the original message in the + channel. + forward_date (:class:`datetime.datetime`): Optional. Date the original message was sent. + reply_to_message (:class:`telegram.Message`): Optional. For replies, the original message. + Note that the Message object in this field will not contain further + ``reply_to_message`` fields even if it itself is a reply. + edit_date (:class:`datetime.datetime`): Optional. Date the message was last edited. + media_group_id (:obj:`str`): Optional. The unique identifier of a media message group this + message belongs to. + text (:obj:`str`): Optional. The actual UTF-8 text of the message. + entities (List[:class:`telegram.MessageEntity`]): Optional. Special entities like + usernames, URLs, bot commands, etc. that appear in the text. See + :attr:`Message.parse_entity` and :attr:`parse_entities` methods for how to use + properly. + caption_entities (List[:class:`telegram.MessageEntity`]): Optional. Special entities like + usernames, URLs, bot commands, etc. that appear in the caption. See + :attr:`Message.parse_caption_entity` and :attr:`parse_caption_entities` methods for how + to use properly. + audio (:class:`telegram.Audio`): Optional. Information about the file. + document (:class:`telegram.Document`): Optional. Information about the file. + animation (:class:`telegram.Animation`) Optional. Information about the file. + For backward compatibility, when this field is set, the document field will also be + set. + game (:class:`telegram.Game`): Optional. Information about the game. + photo (List[:class:`telegram.PhotoSize`]): Optional. Available sizes of the photo. + sticker (:class:`telegram.Sticker`): Optional. Information about the sticker. + video (:class:`telegram.Video`): Optional. Information about the video. + voice (:class:`telegram.Voice`): Optional. Information about the file. + video_note (:class:`telegram.VideoNote`): Optional. Information about the video message. + new_chat_members (List[:class:`telegram.User`]): Optional. Information about new members to + the chat. (the bot itself may be one of these members). + caption (:obj:`str`): Optional. Caption for the document, photo or video, 0-1024 + characters. + contact (:class:`telegram.Contact`): Optional. Information about the contact. + location (:class:`telegram.Location`): Optional. Information about the location. + venue (:class:`telegram.Venue`): Optional. Information about the venue. + left_chat_member (:class:`telegram.User`): Optional. Information about the user that left + the group. (this member may be the bot itself). + new_chat_title (:obj:`str`): Optional. A chat title was changed to this value. + new_chat_photo (List[:class:`telegram.PhotoSize`]): Optional. A chat photo was changed to + this value. + delete_chat_photo (:obj:`bool`): Optional. The chat photo was deleted. + group_chat_created (:obj:`bool`): Optional. The group has been created. + supergroup_chat_created (:obj:`bool`): Optional. The supergroup has been created. + channel_chat_created (:obj:`bool`): Optional. The channel has been created. + message_auto_delete_timer_changed (:class:`telegram.MessageAutoDeleteTimerChanged`): + Optional. Service message: auto-delete timer settings changed in the chat. + + .. versionadded:: 13.4 + migrate_to_chat_id (:obj:`int`): Optional. The group has been migrated to a supergroup with + the specified identifier. + migrate_from_chat_id (:obj:`int`): Optional. The supergroup has been migrated from a group + with the specified identifier. + pinned_message (:class:`telegram.message`): Optional. Specified message was pinned. + invoice (:class:`telegram.Invoice`): Optional. Information about the invoice. + successful_payment (:class:`telegram.SuccessfulPayment`): Optional. Information about the + payment. + connected_website (:obj:`str`): Optional. The domain name of the website on which the user + has logged in. + forward_signature (:obj:`str`): Optional. Signature of the post author for messages + forwarded from channels. + forward_sender_name (:obj:`str`): Optional. Sender's name for messages forwarded from users + who disallow adding a link to their account in forwarded messages. + author_signature (:obj:`str`): Optional. Signature of the post author for messages in + channels, or the custom title of an anonymous group administrator. + passport_data (:class:`telegram.PassportData`): Optional. Telegram Passport data. + poll (:class:`telegram.Poll`): Optional. Message is a native poll, + information about the poll. + dice (:class:`telegram.Dice`): Optional. Message is a dice. + via_bot (:class:`telegram.User`): Optional. Bot through which the message was sent. + proximity_alert_triggered (:class:`telegram.ProximityAlertTriggered`): Optional. Service + message. A user in the chat triggered another user's proximity alert while sharing + Live Location. + voice_chat_scheduled (:class:`telegram.VoiceChatScheduled`): Optional. Service message: + voice chat scheduled. + + .. versionadded:: 13.5 + voice_chat_started (:class:`telegram.VoiceChatStarted`): Optional. Service message: voice + chat started. + + .. versionadded:: 13.4 + voice_chat_ended (:class:`telegram.VoiceChatEnded`): Optional. Service message: voice chat + ended. + + .. versionadded:: 13.4 + voice_chat_participants_invited (:class:`telegram.VoiceChatParticipantsInvited`): Optional. + Service message: new participants invited to a voice chat. + + .. versionadded:: 13.4 + reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached + to the message. + bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods. + + """ + + # fmt: on + __slots__ = ( + 'reply_markup', + 'audio', + 'contact', + 'migrate_to_chat_id', + 'forward_signature', + 'chat', + 'successful_payment', + 'game', + 'text', + 'forward_sender_name', + 'document', + 'new_chat_title', + 'forward_date', + 'group_chat_created', + 'media_group_id', + 'caption', + 'video', + 'bot', + 'entities', + 'via_bot', + 'new_chat_members', + 'connected_website', + 'animation', + 'migrate_from_chat_id', + 'forward_from', + 'sticker', + 'location', + 'venue', + 'edit_date', + 'reply_to_message', + 'passport_data', + 'pinned_message', + 'forward_from_chat', + 'new_chat_photo', + 'message_id', + 'delete_chat_photo', + 'from_user', + 'author_signature', + 'proximity_alert_triggered', + 'sender_chat', + 'dice', + 'forward_from_message_id', + 'caption_entities', + 'voice', + 'date', + 'supergroup_chat_created', + 'poll', + 'left_chat_member', + 'photo', + 'channel_chat_created', + 'invoice', + 'video_note', + '_effective_attachment', + 'message_auto_delete_timer_changed', + 'voice_chat_ended', + 'voice_chat_participants_invited', + 'voice_chat_started', + 'voice_chat_scheduled', + '_id_attrs', + ) + + ATTACHMENT_TYPES: ClassVar[List[str]] = [ + 'audio', + 'game', + 'animation', + 'document', + 'photo', + 'sticker', + 'video', + 'voice', + 'video_note', + 'contact', + 'location', + 'venue', + 'invoice', + 'successful_payment', + ] + MESSAGE_TYPES: ClassVar[List[str]] = [ + 'text', + 'new_chat_members', + 'left_chat_member', + 'new_chat_title', + 'new_chat_photo', + 'delete_chat_photo', + 'group_chat_created', + 'supergroup_chat_created', + 'channel_chat_created', + 'message_auto_delete_timer_changed', + 'migrate_to_chat_id', + 'migrate_from_chat_id', + 'pinned_message', + 'poll', + 'dice', + 'passport_data', + 'proximity_alert_triggered', + 'voice_chat_scheduled', + 'voice_chat_started', + 'voice_chat_ended', + 'voice_chat_participants_invited', + ] + ATTACHMENT_TYPES + + def __init__( + self, + message_id: int, + date: datetime.datetime, + chat: Chat, + from_user: User = None, + forward_from: User = None, + forward_from_chat: Chat = None, + forward_from_message_id: int = None, + forward_date: datetime.datetime = None, + reply_to_message: 'Message' = None, + edit_date: datetime.datetime = None, + text: str = None, + entities: List['MessageEntity'] = None, + caption_entities: List['MessageEntity'] = None, + audio: Audio = None, + document: Document = None, + game: Game = None, + photo: List[PhotoSize] = None, + sticker: Sticker = None, + video: Video = None, + voice: Voice = None, + video_note: VideoNote = None, + new_chat_members: List[User] = None, + caption: str = None, + contact: Contact = None, + location: Location = None, + venue: Venue = None, + left_chat_member: User = None, + new_chat_title: str = None, + new_chat_photo: List[PhotoSize] = None, + delete_chat_photo: bool = False, + group_chat_created: bool = False, + supergroup_chat_created: bool = False, + channel_chat_created: bool = False, + migrate_to_chat_id: int = None, + migrate_from_chat_id: int = None, + pinned_message: 'Message' = None, + invoice: Invoice = None, + successful_payment: SuccessfulPayment = None, + forward_signature: str = None, + author_signature: str = None, + media_group_id: str = None, + connected_website: str = None, + animation: Animation = None, + passport_data: PassportData = None, + poll: Poll = None, + forward_sender_name: str = None, + reply_markup: InlineKeyboardMarkup = None, + bot: 'Bot' = None, + dice: Dice = None, + via_bot: User = None, + proximity_alert_triggered: ProximityAlertTriggered = None, + sender_chat: Chat = None, + voice_chat_started: VoiceChatStarted = None, + voice_chat_ended: VoiceChatEnded = None, + voice_chat_participants_invited: VoiceChatParticipantsInvited = None, + message_auto_delete_timer_changed: MessageAutoDeleteTimerChanged = None, + voice_chat_scheduled: VoiceChatScheduled = None, + **_kwargs: Any, + ): + # Required + self.message_id = int(message_id) + # Optionals + self.from_user = from_user + self.sender_chat = sender_chat + self.date = date + self.chat = chat + self.forward_from = forward_from + self.forward_from_chat = forward_from_chat + self.forward_date = forward_date + self.reply_to_message = reply_to_message + self.edit_date = edit_date + self.text = text + self.entities = entities or [] + self.caption_entities = caption_entities or [] + self.audio = audio + self.game = game + self.document = document + self.photo = photo or [] + self.sticker = sticker + self.video = video + self.voice = voice + self.video_note = video_note + self.caption = caption + self.contact = contact + self.location = location + self.venue = venue + self.new_chat_members = new_chat_members or [] + self.left_chat_member = left_chat_member + self.new_chat_title = new_chat_title + self.new_chat_photo = new_chat_photo or [] + self.delete_chat_photo = bool(delete_chat_photo) + self.group_chat_created = bool(group_chat_created) + self.supergroup_chat_created = bool(supergroup_chat_created) + self.migrate_to_chat_id = migrate_to_chat_id + self.migrate_from_chat_id = migrate_from_chat_id + self.channel_chat_created = bool(channel_chat_created) + self.message_auto_delete_timer_changed = message_auto_delete_timer_changed + self.pinned_message = pinned_message + self.forward_from_message_id = forward_from_message_id + self.invoice = invoice + self.successful_payment = successful_payment + self.connected_website = connected_website + self.forward_signature = forward_signature + self.forward_sender_name = forward_sender_name + self.author_signature = author_signature + self.media_group_id = media_group_id + self.animation = animation + self.passport_data = passport_data + self.poll = poll + self.dice = dice + self.via_bot = via_bot + self.proximity_alert_triggered = proximity_alert_triggered + self.voice_chat_scheduled = voice_chat_scheduled + self.voice_chat_started = voice_chat_started + self.voice_chat_ended = voice_chat_ended + self.voice_chat_participants_invited = voice_chat_participants_invited + self.reply_markup = reply_markup + self.bot = bot + + self._effective_attachment = DEFAULT_NONE + + self._id_attrs = (self.message_id, self.chat) + + @property + def chat_id(self) -> int: + """:obj:`int`: Shortcut for :attr:`telegram.Chat.id` for :attr:`chat`.""" + return self.chat.id + + @property + def link(self) -> Optional[str]: + """:obj:`str`: Convenience property. If the chat of the message is not + a private chat or normal group, returns a t.me link of the message. + """ + if self.chat.type not in [Chat.PRIVATE, Chat.GROUP]: + if self.chat.username: + to_link = self.chat.username + else: + # Get rid of leading -100 for supergroups + to_link = f"c/{str(self.chat.id)[4:]}" + return f"https://t.me/{to_link}/{self.message_id}" + return None + + @classmethod + def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Message']: + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + if not data: + return None + + data['from_user'] = User.de_json(data.get('from'), bot) + data['sender_chat'] = Chat.de_json(data.get('sender_chat'), bot) + data['date'] = from_timestamp(data['date']) + data['chat'] = Chat.de_json(data.get('chat'), bot) + data['entities'] = MessageEntity.de_list(data.get('entities'), bot) + data['caption_entities'] = MessageEntity.de_list(data.get('caption_entities'), bot) + data['forward_from'] = User.de_json(data.get('forward_from'), bot) + data['forward_from_chat'] = Chat.de_json(data.get('forward_from_chat'), bot) + data['forward_date'] = from_timestamp(data.get('forward_date')) + data['reply_to_message'] = Message.de_json(data.get('reply_to_message'), bot) + data['edit_date'] = from_timestamp(data.get('edit_date')) + data['audio'] = Audio.de_json(data.get('audio'), bot) + data['document'] = Document.de_json(data.get('document'), bot) + data['animation'] = Animation.de_json(data.get('animation'), bot) + data['game'] = Game.de_json(data.get('game'), bot) + data['photo'] = PhotoSize.de_list(data.get('photo'), bot) + data['sticker'] = Sticker.de_json(data.get('sticker'), bot) + data['video'] = Video.de_json(data.get('video'), bot) + data['voice'] = Voice.de_json(data.get('voice'), bot) + data['video_note'] = VideoNote.de_json(data.get('video_note'), bot) + data['contact'] = Contact.de_json(data.get('contact'), bot) + data['location'] = Location.de_json(data.get('location'), bot) + data['venue'] = Venue.de_json(data.get('venue'), bot) + data['new_chat_members'] = User.de_list(data.get('new_chat_members'), bot) + data['left_chat_member'] = User.de_json(data.get('left_chat_member'), bot) + data['new_chat_photo'] = PhotoSize.de_list(data.get('new_chat_photo'), bot) + data['message_auto_delete_timer_changed'] = MessageAutoDeleteTimerChanged.de_json( + data.get('message_auto_delete_timer_changed'), bot + ) + data['pinned_message'] = Message.de_json(data.get('pinned_message'), bot) + data['invoice'] = Invoice.de_json(data.get('invoice'), bot) + data['successful_payment'] = SuccessfulPayment.de_json(data.get('successful_payment'), bot) + data['passport_data'] = PassportData.de_json(data.get('passport_data'), bot) + data['poll'] = Poll.de_json(data.get('poll'), bot) + data['dice'] = Dice.de_json(data.get('dice'), bot) + data['via_bot'] = User.de_json(data.get('via_bot'), bot) + data['proximity_alert_triggered'] = ProximityAlertTriggered.de_json( + data.get('proximity_alert_triggered'), bot + ) + data['reply_markup'] = InlineKeyboardMarkup.de_json(data.get('reply_markup'), bot) + data['voice_chat_scheduled'] = VoiceChatScheduled.de_json( + data.get('voice_chat_scheduled'), bot + ) + data['voice_chat_started'] = VoiceChatStarted.de_json(data.get('voice_chat_started'), bot) + data['voice_chat_ended'] = VoiceChatEnded.de_json(data.get('voice_chat_ended'), bot) + data['voice_chat_participants_invited'] = VoiceChatParticipantsInvited.de_json( + data.get('voice_chat_participants_invited'), bot + ) + return cls(bot=bot, **data) + + @property + def effective_attachment( + self, + ) -> Union[ + Contact, + Document, + Animation, + Game, + Invoice, + Location, + List[PhotoSize], + Sticker, + SuccessfulPayment, + Venue, + Video, + VideoNote, + Voice, + None, + ]: + """ + :class:`telegram.Audio` + or :class:`telegram.Contact` + or :class:`telegram.Document` + or :class:`telegram.Animation` + or :class:`telegram.Game` + or :class:`telegram.Invoice` + or :class:`telegram.Location` + or List[:class:`telegram.PhotoSize`] + or :class:`telegram.Sticker` + or :class:`telegram.SuccessfulPayment` + or :class:`telegram.Venue` + or :class:`telegram.Video` + or :class:`telegram.VideoNote` + or :class:`telegram.Voice`: The attachment that this message was sent with. May be + :obj:`None` if no attachment was sent. + + """ + if self._effective_attachment is not DEFAULT_NONE: + return self._effective_attachment # type: ignore + + for i in Message.ATTACHMENT_TYPES: + if getattr(self, i, None): + self._effective_attachment = getattr(self, i) + break + else: + self._effective_attachment = None + + return self._effective_attachment # type: ignore + + def __getitem__(self, item: str) -> Any: # pylint: disable=R1710 + return self.chat.id if item == 'chat_id' else super().__getitem__(item) + + def to_dict(self) -> JSONDict: + """See :meth:`telegram.TelegramObject.to_dict`.""" + data = super().to_dict() + + # Required + data['date'] = to_timestamp(self.date) + # Optionals + if self.forward_date: + data['forward_date'] = to_timestamp(self.forward_date) + if self.edit_date: + data['edit_date'] = to_timestamp(self.edit_date) + if self.photo: + data['photo'] = [p.to_dict() for p in self.photo] + if self.entities: + data['entities'] = [e.to_dict() for e in self.entities] + if self.caption_entities: + data['caption_entities'] = [e.to_dict() for e in self.caption_entities] + if self.new_chat_photo: + data['new_chat_photo'] = [p.to_dict() for p in self.new_chat_photo] + if self.new_chat_members: + data['new_chat_members'] = [u.to_dict() for u in self.new_chat_members] + + return data + + def _quote(self, quote: Optional[bool], reply_to_message_id: Optional[int]) -> Optional[int]: + """Modify kwargs for replying with or without quoting.""" + if reply_to_message_id is not None: + return reply_to_message_id + + if quote is not None: + if quote: + return self.message_id + + else: + if self.bot.defaults: + default_quote = self.bot.defaults.quote + else: + default_quote = None + if (default_quote is None and self.chat.type != Chat.PRIVATE) or default_quote: + return self.message_id + + return None + + def reply_text( + self, + text: str, + parse_mode: ODVInput[str] = DEFAULT_NONE, + disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: ReplyMarkup = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + quote: bool = None, + ) -> 'Message': + """Shortcut for:: + + bot.send_message(update.effective_message.chat_id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_message`. + + Args: + quote (:obj:`bool`, optional): If set to :obj:`True`, the message is sent as an actual + reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this + parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` in + private chats. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + reply_to_message_id = self._quote(quote, reply_to_message_id) + return self.bot.send_message( + chat_id=self.chat_id, + text=text, + parse_mode=parse_mode, + disable_web_page_preview=disable_web_page_preview, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + entities=entities, + ) + + def reply_markdown( + self, + text: str, + disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: ReplyMarkup = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + quote: bool = None, + ) -> 'Message': + """Shortcut for:: + + bot.send_message( + update.effective_message.chat_id, + parse_mode=ParseMode.MARKDOWN, + *args, + **kwargs, + ) + + Sends a message with Markdown version 1 formatting. + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_message`. + + Note: + :attr:`telegram.ParseMode.MARKDOWN` is a legacy mode, retained by Telegram for + backward compatibility. You should use :meth:`reply_markdown_v2` instead. + + Args: + quote (:obj:`bool`, optional): If set to :obj:`True`, the message is sent as an actual + reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this + parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` in + private chats. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + """ + reply_to_message_id = self._quote(quote, reply_to_message_id) + return self.bot.send_message( + chat_id=self.chat_id, + text=text, + parse_mode=ParseMode.MARKDOWN, + disable_web_page_preview=disable_web_page_preview, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + entities=entities, + ) + + def reply_markdown_v2( + self, + text: str, + disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: ReplyMarkup = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + quote: bool = None, + ) -> 'Message': + """Shortcut for:: + + bot.send_message( + update.effective_message.chat_id, + parse_mode=ParseMode.MARKDOWN_V2, + *args, + **kwargs, + ) + + Sends a message with markdown version 2 formatting. + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_message`. + + Args: + quote (:obj:`bool`, optional): If set to :obj:`True`, the message is sent as an actual + reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this + parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` in + private chats. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + """ + reply_to_message_id = self._quote(quote, reply_to_message_id) + return self.bot.send_message( + chat_id=self.chat_id, + text=text, + parse_mode=ParseMode.MARKDOWN_V2, + disable_web_page_preview=disable_web_page_preview, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + entities=entities, + ) + + def reply_html( + self, + text: str, + disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: ReplyMarkup = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + quote: bool = None, + ) -> 'Message': + """Shortcut for:: + + bot.send_message( + update.effective_message.chat_id, + parse_mode=ParseMode.HTML, + *args, + **kwargs, + ) + + Sends a message with HTML formatting. + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_message`. + + Args: + quote (:obj:`bool`, optional): If set to :obj:`True`, the message is sent as an actual + reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this + parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` in + private chats. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + """ + reply_to_message_id = self._quote(quote, reply_to_message_id) + return self.bot.send_message( + chat_id=self.chat_id, + text=text, + parse_mode=ParseMode.HTML, + disable_web_page_preview=disable_web_page_preview, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + entities=entities, + ) + + def reply_media_group( + self, + media: List[ + Union['InputMediaAudio', 'InputMediaDocument', 'InputMediaPhoto', 'InputMediaVideo'] + ], + disable_notification: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + timeout: DVInput[float] = DEFAULT_20, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + quote: bool = None, + ) -> List['Message']: + """Shortcut for:: + + bot.send_media_group(update.effective_message.chat_id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_media_group`. + + Args: + quote (:obj:`bool`, optional): If set to :obj:`True`, the media group is sent as an + actual reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, + this parameter will be ignored. Default: :obj:`True` in group chats and + :obj:`False` in private chats. + + Returns: + List[:class:`telegram.Message`]: An array of the sent Messages. + + Raises: + :class:`telegram.error.TelegramError` + """ + reply_to_message_id = self._quote(quote, reply_to_message_id) + return self.bot.send_media_group( + chat_id=self.chat_id, + media=media, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + timeout=timeout, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + ) + + def reply_photo( + self, + photo: Union[FileInput, 'PhotoSize'], + caption: str = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: ReplyMarkup = None, + timeout: DVInput[float] = DEFAULT_20, + parse_mode: ODVInput[str] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + filename: str = None, + quote: bool = None, + ) -> 'Message': + """Shortcut for:: + + bot.send_photo(update.effective_message.chat_id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_photo`. + + Args: + quote (:obj:`bool`, optional): If set to :obj:`True`, the photo is sent as an actual + reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, + this parameter will be ignored. Default: :obj:`True` in group chats and + :obj:`False` in private chats. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + reply_to_message_id = self._quote(quote, reply_to_message_id) + return self.bot.send_photo( + chat_id=self.chat_id, + photo=photo, + caption=caption, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + parse_mode=parse_mode, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + caption_entities=caption_entities, + filename=filename, + ) + + def reply_audio( + self, + audio: Union[FileInput, 'Audio'], + duration: int = None, + performer: str = None, + title: str = None, + caption: str = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: ReplyMarkup = None, + timeout: DVInput[float] = DEFAULT_20, + parse_mode: ODVInput[str] = DEFAULT_NONE, + thumb: FileInput = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + filename: str = None, + quote: bool = None, + ) -> 'Message': + """Shortcut for:: + + bot.send_audio(update.effective_message.chat_id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_audio`. + + Args: + quote (:obj:`bool`, optional): If set to :obj:`True`, the audio is sent as an actual + reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, + this parameter will be ignored. Default: :obj:`True` in group chats and + :obj:`False` in private chats. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + reply_to_message_id = self._quote(quote, reply_to_message_id) + return self.bot.send_audio( + chat_id=self.chat_id, + audio=audio, + duration=duration, + performer=performer, + title=title, + caption=caption, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + parse_mode=parse_mode, + thumb=thumb, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + caption_entities=caption_entities, + filename=filename, + ) + + def reply_document( + self, + document: Union[FileInput, 'Document'], + filename: str = None, + caption: str = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: ReplyMarkup = None, + timeout: DVInput[float] = DEFAULT_20, + parse_mode: ODVInput[str] = DEFAULT_NONE, + thumb: FileInput = None, + api_kwargs: JSONDict = None, + disable_content_type_detection: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + quote: bool = None, + ) -> 'Message': + """Shortcut for:: + + bot.send_document(update.effective_message.chat_id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_document`. + + Args: + quote (:obj:`bool`, optional): If set to :obj:`True`, the document is sent as an actual + reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this + parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` in + private chats. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + reply_to_message_id = self._quote(quote, reply_to_message_id) + return self.bot.send_document( + chat_id=self.chat_id, + document=document, + filename=filename, + caption=caption, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + parse_mode=parse_mode, + thumb=thumb, + api_kwargs=api_kwargs, + disable_content_type_detection=disable_content_type_detection, + allow_sending_without_reply=allow_sending_without_reply, + caption_entities=caption_entities, + ) + + def reply_animation( + self, + animation: Union[FileInput, 'Animation'], + duration: int = None, + width: int = None, + height: int = None, + thumb: FileInput = None, + caption: str = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: ReplyMarkup = None, + timeout: DVInput[float] = DEFAULT_20, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + filename: str = None, + quote: bool = None, + ) -> 'Message': + """Shortcut for:: + + bot.send_animation(update.effective_message.chat_id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_animation`. + + Args: + quote (:obj:`bool`, optional): If set to :obj:`True`, the animation is sent as an + actual reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, + this parameter will be ignored. Default: :obj:`True` in group chats and + :obj:`False` in private chats. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + reply_to_message_id = self._quote(quote, reply_to_message_id) + return self.bot.send_animation( + chat_id=self.chat_id, + animation=animation, + duration=duration, + width=width, + height=height, + thumb=thumb, + caption=caption, + parse_mode=parse_mode, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + caption_entities=caption_entities, + filename=filename, + ) + + def reply_sticker( + self, + sticker: Union[FileInput, 'Sticker'], + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: ReplyMarkup = None, + timeout: DVInput[float] = DEFAULT_20, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + quote: bool = None, + ) -> 'Message': + """Shortcut for:: + + bot.send_sticker(update.effective_message.chat_id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_sticker`. + + Args: + quote (:obj:`bool`, optional): If set to :obj:`True`, the sticker is sent as an actual + reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this + parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` in + private chats. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + reply_to_message_id = self._quote(quote, reply_to_message_id) + return self.bot.send_sticker( + chat_id=self.chat_id, + sticker=sticker, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + ) + + def reply_video( + self, + video: Union[FileInput, 'Video'], + duration: int = None, + caption: str = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: ReplyMarkup = None, + timeout: DVInput[float] = DEFAULT_20, + width: int = None, + height: int = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + supports_streaming: bool = None, + thumb: FileInput = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + filename: str = None, + quote: bool = None, + ) -> 'Message': + """Shortcut for:: + + bot.send_video(update.effective_message.chat_id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_video`. + + Args: + quote (:obj:`bool`, optional): If set to :obj:`True`, the video is sent as an actual + reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this + parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` in + private chats. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + reply_to_message_id = self._quote(quote, reply_to_message_id) + return self.bot.send_video( + chat_id=self.chat_id, + video=video, + duration=duration, + caption=caption, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + width=width, + height=height, + parse_mode=parse_mode, + supports_streaming=supports_streaming, + thumb=thumb, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + caption_entities=caption_entities, + filename=filename, + ) + + def reply_video_note( + self, + video_note: Union[FileInput, 'VideoNote'], + duration: int = None, + length: int = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: ReplyMarkup = None, + timeout: DVInput[float] = DEFAULT_20, + thumb: FileInput = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + filename: str = None, + quote: bool = None, + ) -> 'Message': + """Shortcut for:: + + bot.send_video_note(update.effective_message.chat_id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_video_note`. + + Args: + quote (:obj:`bool`, optional): If set to :obj:`True`, the video note is sent as an + actual reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, + this parameter will be ignored. Default: :obj:`True` in group chats and + :obj:`False` in private chats. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + reply_to_message_id = self._quote(quote, reply_to_message_id) + return self.bot.send_video_note( + chat_id=self.chat_id, + video_note=video_note, + duration=duration, + length=length, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + thumb=thumb, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + filename=filename, + ) + + def reply_voice( + self, + voice: Union[FileInput, 'Voice'], + duration: int = None, + caption: str = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: ReplyMarkup = None, + timeout: DVInput[float] = DEFAULT_20, + parse_mode: ODVInput[str] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + filename: str = None, + quote: bool = None, + ) -> 'Message': + """Shortcut for:: + + bot.send_voice(update.effective_message.chat_id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_voice`. + + Args: + quote (:obj:`bool`, optional): If set to :obj:`True`, the voice note is sent as an + actual reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, + this parameter will be ignored. Default: :obj:`True` in group chats and + :obj:`False` in private chats. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + reply_to_message_id = self._quote(quote, reply_to_message_id) + return self.bot.send_voice( + chat_id=self.chat_id, + voice=voice, + duration=duration, + caption=caption, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + parse_mode=parse_mode, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + caption_entities=caption_entities, + filename=filename, + ) + + def reply_location( + self, + latitude: float = None, + longitude: float = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: ReplyMarkup = None, + timeout: ODVInput[float] = DEFAULT_NONE, + location: Location = None, + live_period: int = None, + api_kwargs: JSONDict = None, + horizontal_accuracy: float = None, + heading: int = None, + proximity_alert_radius: int = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + quote: bool = None, + ) -> 'Message': + """Shortcut for:: + + bot.send_location(update.effective_message.chat_id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_location`. + + Args: + quote (:obj:`bool`, optional): If set to :obj:`True`, the location is sent as an actual + reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this + parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` in + private chats. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + reply_to_message_id = self._quote(quote, reply_to_message_id) + return self.bot.send_location( + chat_id=self.chat_id, + latitude=latitude, + longitude=longitude, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + location=location, + live_period=live_period, + api_kwargs=api_kwargs, + horizontal_accuracy=horizontal_accuracy, + heading=heading, + proximity_alert_radius=proximity_alert_radius, + allow_sending_without_reply=allow_sending_without_reply, + ) + + def reply_venue( + self, + latitude: float = None, + longitude: float = None, + title: str = None, + address: str = None, + foursquare_id: str = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: ReplyMarkup = None, + timeout: ODVInput[float] = DEFAULT_NONE, + venue: Venue = None, + foursquare_type: str = None, + api_kwargs: JSONDict = None, + google_place_id: str = None, + google_place_type: str = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + quote: bool = None, + ) -> 'Message': + """Shortcut for:: + + bot.send_venue(update.effective_message.chat_id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_venue`. + + Args: + quote (:obj:`bool`, optional): If set to :obj:`True`, the venue is sent as an actual + reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this + parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` in + private chats. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + reply_to_message_id = self._quote(quote, reply_to_message_id) + return self.bot.send_venue( + chat_id=self.chat_id, + latitude=latitude, + longitude=longitude, + title=title, + address=address, + foursquare_id=foursquare_id, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + venue=venue, + foursquare_type=foursquare_type, + api_kwargs=api_kwargs, + google_place_id=google_place_id, + google_place_type=google_place_type, + allow_sending_without_reply=allow_sending_without_reply, + ) + + def reply_contact( + self, + phone_number: str = None, + first_name: str = None, + last_name: str = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: ReplyMarkup = None, + timeout: ODVInput[float] = DEFAULT_NONE, + contact: Contact = None, + vcard: str = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + quote: bool = None, + ) -> 'Message': + """Shortcut for:: + + bot.send_contact(update.effective_message.chat_id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_contact`. + + Args: + quote (:obj:`bool`, optional): If set to :obj:`True`, the contact is sent as an actual + reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this + parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` in + private chats. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + reply_to_message_id = self._quote(quote, reply_to_message_id) + return self.bot.send_contact( + chat_id=self.chat_id, + phone_number=phone_number, + first_name=first_name, + last_name=last_name, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + contact=contact, + vcard=vcard, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + ) + + def reply_poll( + self, + question: str, + options: List[str], + is_anonymous: bool = True, + type: str = Poll.REGULAR, # pylint: disable=W0622 + allows_multiple_answers: bool = False, + correct_option_id: int = None, + is_closed: bool = None, + disable_notification: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: ReplyMarkup = None, + timeout: ODVInput[float] = DEFAULT_NONE, + explanation: str = None, + explanation_parse_mode: ODVInput[str] = DEFAULT_NONE, + open_period: int = None, + close_date: Union[int, datetime.datetime] = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + explanation_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + quote: bool = None, + ) -> 'Message': + """Shortcut for:: + + bot.send_poll(update.effective_message.chat_id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_poll`. + + Args: + quote (:obj:`bool`, optional): If set to :obj:`True`, the poll is sent as an actual + reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, + this parameter will be ignored. Default: :obj:`True` in group chats and + :obj:`False` in private chats. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + reply_to_message_id = self._quote(quote, reply_to_message_id) + return self.bot.send_poll( + chat_id=self.chat_id, + question=question, + options=options, + is_anonymous=is_anonymous, + type=type, + allows_multiple_answers=allows_multiple_answers, + correct_option_id=correct_option_id, + is_closed=is_closed, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + explanation=explanation, + explanation_parse_mode=explanation_parse_mode, + open_period=open_period, + close_date=close_date, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + explanation_entities=explanation_entities, + ) + + def reply_dice( + self, + disable_notification: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: ReplyMarkup = None, + timeout: ODVInput[float] = DEFAULT_NONE, + emoji: str = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + quote: bool = None, + ) -> 'Message': + """Shortcut for:: + + bot.send_dice(update.effective_message.chat_id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_dice`. + + Args: + quote (:obj:`bool`, optional): If set to :obj:`True`, the dice is sent as an actual + reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this + parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` + in private chats. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + reply_to_message_id = self._quote(quote, reply_to_message_id) + return self.bot.send_dice( + chat_id=self.chat_id, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + emoji=emoji, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + ) + + def reply_chat_action( + self, + action: str, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> bool: + """Shortcut for:: + + bot.send_chat_action(update.effective_message.chat_id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_chat_action`. + + .. versionadded:: 13.2 + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + + """ + return self.bot.send_chat_action( + chat_id=self.chat_id, + action=action, + timeout=timeout, + api_kwargs=api_kwargs, + ) + + def reply_game( + self, + game_short_name: str, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: 'InlineKeyboardMarkup' = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + quote: bool = None, + ) -> 'Message': + """Shortcut for:: + + bot.send_game(update.effective_message.chat_id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_game`. + + Args: + quote (:obj:`bool`, optional): If set to :obj:`True`, the game is sent as an actual + reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this + parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` + in private chats. + + .. versionadded:: 13.2 + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + reply_to_message_id = self._quote(quote, reply_to_message_id) + return self.bot.send_game( + chat_id=self.chat_id, + game_short_name=game_short_name, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + ) + + def reply_invoice( + self, + title: str, + description: str, + payload: str, + provider_token: str, + currency: str, + prices: List['LabeledPrice'], + start_parameter: str = None, + photo_url: str = None, + photo_size: int = None, + photo_width: int = None, + photo_height: int = None, + need_name: bool = None, + need_phone_number: bool = None, + need_email: bool = None, + need_shipping_address: bool = None, + is_flexible: bool = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: 'InlineKeyboardMarkup' = None, + provider_data: Union[str, object] = None, + send_phone_number_to_provider: bool = None, + send_email_to_provider: bool = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + quote: bool = None, + max_tip_amount: int = None, + suggested_tip_amounts: List[int] = None, + ) -> 'Message': + """Shortcut for:: + + bot.send_invoice(update.effective_message.chat_id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_invoice`. + + Warning: + As of API 5.2 :attr:`start_parameter` is an optional argument and therefore the order + of the arguments had to be changed. Use keyword arguments to make sure that the + arguments are passed correctly. + + .. versionadded:: 13.2 + + .. versionchanged:: 13.5 + As of Bot API 5.2, the parameter :attr:`start_parameter` is optional. + + Args: + quote (:obj:`bool`, optional): If set to :obj:`True`, the invoice is sent as an actual + reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this + parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` + in private chats. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + reply_to_message_id = self._quote(quote, reply_to_message_id) + return self.bot.send_invoice( + chat_id=self.chat_id, + title=title, + description=description, + payload=payload, + provider_token=provider_token, + currency=currency, + prices=prices, + start_parameter=start_parameter, + photo_url=photo_url, + photo_size=photo_size, + photo_width=photo_width, + photo_height=photo_height, + need_name=need_name, + need_phone_number=need_phone_number, + need_email=need_email, + need_shipping_address=need_shipping_address, + is_flexible=is_flexible, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + provider_data=provider_data, + send_phone_number_to_provider=send_phone_number_to_provider, + send_email_to_provider=send_email_to_provider, + timeout=timeout, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + max_tip_amount=max_tip_amount, + suggested_tip_amounts=suggested_tip_amounts, + ) + + def forward( + self, + chat_id: Union[int, str], + disable_notification: DVInput[bool] = DEFAULT_NONE, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> 'Message': + """Shortcut for:: + + bot.forward_message(chat_id=chat_id, + from_chat_id=update.effective_message.chat_id, + message_id=update.effective_message.message_id, + *args, + **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.forward_message`. + + Returns: + :class:`telegram.Message`: On success, instance representing the message forwarded. + + """ + return self.bot.forward_message( + chat_id=chat_id, + from_chat_id=self.chat_id, + message_id=self.message_id, + disable_notification=disable_notification, + timeout=timeout, + api_kwargs=api_kwargs, + ) + + def copy( + self, + chat_id: Union[int, str], + caption: str = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + caption_entities: Union[Tuple['MessageEntity', ...], List['MessageEntity']] = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE, + reply_markup: ReplyMarkup = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> 'MessageId': + """Shortcut for:: + + bot.copy_message(chat_id=chat_id, + from_chat_id=update.effective_message.chat_id, + message_id=update.effective_message.message_id, + *args, + **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.copy_message`. + + Returns: + :class:`telegram.MessageId`: On success, returns the MessageId of the sent message. + + """ + return self.bot.copy_message( + chat_id=chat_id, + from_chat_id=self.chat_id, + message_id=self.message_id, + caption=caption, + parse_mode=parse_mode, + caption_entities=caption_entities, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + allow_sending_without_reply=allow_sending_without_reply, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + ) + + def reply_copy( + self, + from_chat_id: Union[str, int], + message_id: int, + caption: str = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + caption_entities: Union[Tuple['MessageEntity', ...], List['MessageEntity']] = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE, + reply_markup: ReplyMarkup = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + quote: bool = None, + ) -> 'MessageId': + """Shortcut for:: + + bot.copy_message(chat_id=message.chat.id, + from_chat_id=from_chat_id, + message_id=message_id, + *args, + **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.copy_message`. + + Args: + quote (:obj:`bool`, optional): If set to :obj:`True`, the copy is sent as an actual + reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, + this parameter will be ignored. Default: :obj:`True` in group chats and + :obj:`False` in private chats. + + .. versionadded:: 13.1 + + Returns: + :class:`telegram.MessageId`: On success, returns the MessageId of the sent message. + + """ + reply_to_message_id = self._quote(quote, reply_to_message_id) + return self.bot.copy_message( + chat_id=self.chat_id, + from_chat_id=from_chat_id, + message_id=message_id, + caption=caption, + parse_mode=parse_mode, + caption_entities=caption_entities, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + allow_sending_without_reply=allow_sending_without_reply, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + ) + + def edit_text( + self, + text: str, + parse_mode: ODVInput[str] = DEFAULT_NONE, + disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, + reply_markup: InlineKeyboardMarkup = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + ) -> Union['Message', bool]: + """Shortcut for:: + + bot.edit_message_text(chat_id=message.chat_id, + message_id=message.message_id, + *args, + **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.edit_message_text`. + + Note: + You can only edit messages that the bot sent itself (i.e. of the ``bot.send_*`` family + of methods) or channel posts, if the bot is an admin in that channel. However, this + behaviour is undocumented and might be changed by Telegram. + + Returns: + :class:`telegram.Message`: On success, if edited message is sent by the bot, the + edited Message is returned, otherwise ``True`` is returned. + + """ + return self.bot.edit_message_text( + chat_id=self.chat_id, + message_id=self.message_id, + text=text, + parse_mode=parse_mode, + disable_web_page_preview=disable_web_page_preview, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + entities=entities, + inline_message_id=None, + ) + + def edit_caption( + self, + caption: str = None, + reply_markup: InlineKeyboardMarkup = None, + timeout: ODVInput[float] = DEFAULT_NONE, + parse_mode: ODVInput[str] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + ) -> Union['Message', bool]: + """Shortcut for:: + + bot.edit_message_caption(chat_id=message.chat_id, + message_id=message.message_id, + *args, + **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Bot.edit_message_caption`. + + Note: + You can only edit messages that the bot sent itself (i.e. of the ``bot.send_*`` family + of methods) or channel posts, if the bot is an admin in that channel. However, this + behaviour is undocumented and might be changed by Telegram. + + Returns: + :class:`telegram.Message`: On success, if edited message is sent by the bot, the + edited Message is returned, otherwise ``True`` is returned. + + """ + return self.bot.edit_message_caption( + chat_id=self.chat_id, + message_id=self.message_id, + caption=caption, + reply_markup=reply_markup, + timeout=timeout, + parse_mode=parse_mode, + api_kwargs=api_kwargs, + caption_entities=caption_entities, + inline_message_id=None, + ) + + def edit_media( + self, + media: 'InputMedia' = None, + reply_markup: InlineKeyboardMarkup = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> Union['Message', bool]: + """Shortcut for:: + + bot.edit_message_media(chat_id=message.chat_id, + message_id=message.message_id, + *args, + **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Bot.edit_message_media`. + + Note: + You can only edit messages that the bot sent itself(i.e. of the ``bot.send_*`` family + of methods) or channel posts, if the bot is an admin in that channel. However, this + behaviour is undocumented and might be changed by Telegram. + + Returns: + :class:`telegram.Message`: On success, if edited message is sent by the bot, the + edited Message is returned, otherwise ``True`` is returned. + + """ + return self.bot.edit_message_media( + chat_id=self.chat_id, + message_id=self.message_id, + media=media, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + inline_message_id=None, + ) + + def edit_reply_markup( + self, + reply_markup: Optional['InlineKeyboardMarkup'] = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> Union['Message', bool]: + """Shortcut for:: + + bot.edit_message_reply_markup(chat_id=message.chat_id, + message_id=message.message_id, + *args, + **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Bot.edit_message_reply_markup`. + + Note: + You can only edit messages that the bot sent itself (i.e. of the ``bot.send_*`` family + of methods) or channel posts, if the bot is an admin in that channel. However, this + behaviour is undocumented and might be changed by Telegram. + + Returns: + :class:`telegram.Message`: On success, if edited message is sent by the bot, the + edited Message is returned, otherwise ``True`` is returned. + """ + return self.bot.edit_message_reply_markup( + chat_id=self.chat_id, + message_id=self.message_id, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + inline_message_id=None, + ) + + def edit_live_location( + self, + latitude: float = None, + longitude: float = None, + location: Location = None, + reply_markup: InlineKeyboardMarkup = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + horizontal_accuracy: float = None, + heading: int = None, + proximity_alert_radius: int = None, + ) -> Union['Message', bool]: + """Shortcut for:: + + bot.edit_message_live_location(chat_id=message.chat_id, + message_id=message.message_id, + *args, + **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Bot.edit_message_live_location`. + + Note: + You can only edit messages that the bot sent itself (i.e. of the ``bot.send_*`` family + of methods) or channel posts, if the bot is an admin in that channel. However, this + behaviour is undocumented and might be changed by Telegram. + + Returns: + :class:`telegram.Message`: On success, if edited message is sent by the bot, the + edited Message is returned, otherwise :obj:`True` is returned. + """ + return self.bot.edit_message_live_location( + chat_id=self.chat_id, + message_id=self.message_id, + latitude=latitude, + longitude=longitude, + location=location, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + horizontal_accuracy=horizontal_accuracy, + heading=heading, + proximity_alert_radius=proximity_alert_radius, + inline_message_id=None, + ) + + def stop_live_location( + self, + reply_markup: InlineKeyboardMarkup = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> Union['Message', bool]: + """Shortcut for:: + + bot.stop_message_live_location(chat_id=message.chat_id, + message_id=message.message_id, + *args, + **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Bot.stop_message_live_location`. + + Note: + You can only edit messages that the bot sent itself (i.e. of the ``bot.send_*`` family + of methods) or channel posts, if the bot is an admin in that channel. However, this + behaviour is undocumented and might be changed by Telegram. + + Returns: + :class:`telegram.Message`: On success, if edited message is sent by the bot, the + edited Message is returned, otherwise :obj:`True` is returned. + """ + return self.bot.stop_message_live_location( + chat_id=self.chat_id, + message_id=self.message_id, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + inline_message_id=None, + ) + + def set_game_score( + self, + user_id: Union[int, str], + score: int, + force: bool = None, + disable_edit_message: bool = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> Union['Message', bool]: + """Shortcut for:: + + bot.set_game_score(chat_id=message.chat_id, + message_id=message.message_id, + *args, + **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.set_game_score`. + + Note: + You can only edit messages that the bot sent itself (i.e. of the ``bot.send_*`` family + of methods) or channel posts, if the bot is an admin in that channel. However, this + behaviour is undocumented and might be changed by Telegram. + + Returns: + :class:`telegram.Message`: On success, if edited message is sent by the bot, the + edited Message is returned, otherwise :obj:`True` is returned. + """ + return self.bot.set_game_score( + chat_id=self.chat_id, + message_id=self.message_id, + user_id=user_id, + score=score, + force=force, + disable_edit_message=disable_edit_message, + timeout=timeout, + api_kwargs=api_kwargs, + inline_message_id=None, + ) + + def get_game_high_scores( + self, + user_id: Union[int, str], + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> List['GameHighScore']: + """Shortcut for:: + + bot.get_game_high_scores(chat_id=message.chat_id, + message_id=message.message_id, + *args, + **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Bot.get_game_high_scores`. + + Note: + You can only edit messages that the bot sent itself (i.e. of the ``bot.send_*`` family + of methods) or channel posts, if the bot is an admin in that channel. However, this + behaviour is undocumented and might be changed by Telegram. + + Returns: + List[:class:`telegram.GameHighScore`] + """ + return self.bot.get_game_high_scores( + chat_id=self.chat_id, + message_id=self.message_id, + user_id=user_id, + timeout=timeout, + api_kwargs=api_kwargs, + inline_message_id=None, + ) + + def delete( + self, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> bool: + """Shortcut for:: + + bot.delete_message(chat_id=message.chat_id, + message_id=message.message_id, + *args, + **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.delete_message`. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + + """ + return self.bot.delete_message( + chat_id=self.chat_id, + message_id=self.message_id, + timeout=timeout, + api_kwargs=api_kwargs, + ) + + def stop_poll( + self, + reply_markup: InlineKeyboardMarkup = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> Poll: + """Shortcut for:: + + bot.stop_poll(chat_id=message.chat_id, + message_id=message.message_id, + *args, + **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.stop_poll`. + + Returns: + :class:`telegram.Poll`: On success, the stopped Poll with the final results is + returned. + + """ + return self.bot.stop_poll( + chat_id=self.chat_id, + message_id=self.message_id, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + ) + + def pin( + self, + disable_notification: ODVInput[bool] = DEFAULT_NONE, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> bool: + """Shortcut for:: + + bot.pin_chat_message(chat_id=message.chat_id, + message_id=message.message_id, + *args, + **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.pin_chat_message`. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + + """ + return self.bot.pin_chat_message( + chat_id=self.chat_id, + message_id=self.message_id, + disable_notification=disable_notification, + timeout=timeout, + api_kwargs=api_kwargs, + ) + + def unpin( + self, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> bool: + """Shortcut for:: + + bot.unpin_chat_message(chat_id=message.chat_id, + message_id=message.message_id, + *args, + **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.unpin_chat_message`. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + + """ + return self.bot.unpin_chat_message( + chat_id=self.chat_id, + message_id=self.message_id, + timeout=timeout, + api_kwargs=api_kwargs, + ) + + def parse_entity(self, entity: MessageEntity) -> str: + """Returns the text from a given :class:`telegram.MessageEntity`. + + Note: + This method is present because Telegram calculates the offset and length in + UTF-16 codepoint pairs, which some versions of Python don't handle automatically. + (That is, you can't just slice ``Message.text`` with the offset and length.) + + Args: + entity (:class:`telegram.MessageEntity`): The entity to extract the text from. It must + be an entity that belongs to this message. + + Returns: + :obj:`str`: The text of the given entity. + + Raises: + RuntimeError: If the message has no text. + + """ + if not self.text: + raise RuntimeError("This Message has no 'text'.") + + # Is it a narrow build, if so we don't need to convert + if sys.maxunicode == 0xFFFF: + return self.text[entity.offset : entity.offset + entity.length] + + entity_text = self.text.encode('utf-16-le') + entity_text = entity_text[entity.offset * 2 : (entity.offset + entity.length) * 2] + return entity_text.decode('utf-16-le') + + def parse_caption_entity(self, entity: MessageEntity) -> str: + """Returns the text from a given :class:`telegram.MessageEntity`. + + Note: + This method is present because Telegram calculates the offset and length in + UTF-16 codepoint pairs, which some versions of Python don't handle automatically. + (That is, you can't just slice ``Message.caption`` with the offset and length.) + + Args: + entity (:class:`telegram.MessageEntity`): The entity to extract the text from. It must + be an entity that belongs to this message. + + Returns: + :obj:`str`: The text of the given entity. + + Raises: + RuntimeError: If the message has no caption. + + """ + if not self.caption: + raise RuntimeError("This Message has no 'caption'.") + + # Is it a narrow build, if so we don't need to convert + if sys.maxunicode == 0xFFFF: + return self.caption[entity.offset : entity.offset + entity.length] + + entity_text = self.caption.encode('utf-16-le') + entity_text = entity_text[entity.offset * 2 : (entity.offset + entity.length) * 2] + return entity_text.decode('utf-16-le') + + def parse_entities(self, types: List[str] = None) -> Dict[MessageEntity, str]: + """ + Returns a :obj:`dict` that maps :class:`telegram.MessageEntity` to :obj:`str`. + It contains entities from this message filtered by their + :attr:`telegram.MessageEntity.type` attribute as the key, and the text that each entity + belongs to as the value of the :obj:`dict`. + + Note: + This method should always be used instead of the :attr:`entities` attribute, since it + calculates the correct substring from the message text based on UTF-16 codepoints. + See :attr:`parse_entity` for more info. + + Args: + types (List[:obj:`str`], optional): List of :class:`telegram.MessageEntity` types as + strings. If the ``type`` attribute of an entity is contained in this list, it will + be returned. Defaults to a list of all types. All types can be found as constants + in :class:`telegram.MessageEntity`. + + Returns: + Dict[:class:`telegram.MessageEntity`, :obj:`str`]: A dictionary of entities mapped to + the text that belongs to them, calculated based on UTF-16 codepoints. + + """ + if types is None: + types = MessageEntity.ALL_TYPES + + return { + entity: self.parse_entity(entity) + for entity in (self.entities or []) + if entity.type in types + } + + def parse_caption_entities(self, types: List[str] = None) -> Dict[MessageEntity, str]: + """ + Returns a :obj:`dict` that maps :class:`telegram.MessageEntity` to :obj:`str`. + It contains entities from this message's caption filtered by their + :attr:`telegram.MessageEntity.type` attribute as the key, and the text that each entity + belongs to as the value of the :obj:`dict`. + + Note: + This method should always be used instead of the :attr:`caption_entities` attribute, + since it calculates the correct substring from the message text based on UTF-16 + codepoints. See :attr:`parse_entity` for more info. + + Args: + types (List[:obj:`str`], optional): List of :class:`telegram.MessageEntity` types as + strings. If the ``type`` attribute of an entity is contained in this list, it will + be returned. Defaults to a list of all types. All types can be found as constants + in :class:`telegram.MessageEntity`. + + Returns: + Dict[:class:`telegram.MessageEntity`, :obj:`str`]: A dictionary of entities mapped to + the text that belongs to them, calculated based on UTF-16 codepoints. + + """ + if types is None: + types = MessageEntity.ALL_TYPES + + return { + entity: self.parse_caption_entity(entity) + for entity in (self.caption_entities or []) + if entity.type in types + } + + @staticmethod + def _parse_html( + message_text: Optional[str], + entities: Dict[MessageEntity, str], + urled: bool = False, + offset: int = 0, + ) -> Optional[str]: + if message_text is None: + return None + + if sys.maxunicode != 0xFFFF: + message_text = message_text.encode('utf-16-le') # type: ignore + + html_text = '' + last_offset = 0 + + sorted_entities = sorted(entities.items(), key=(lambda item: item[0].offset)) + parsed_entities = [] + + for (entity, text) in sorted_entities: + if entity not in parsed_entities: + nested_entities = { + e: t + for (e, t) in sorted_entities + if e.offset >= entity.offset + and e.offset + e.length <= entity.offset + entity.length + and e != entity + } + parsed_entities.extend(list(nested_entities.keys())) + + orig_text = text + text = escape(text) + + if nested_entities: + text = Message._parse_html( + orig_text, nested_entities, urled=urled, offset=entity.offset + ) + + if entity.type == MessageEntity.TEXT_LINK: + insert = f'<a href="{entity.url}">{text}</a>' + elif entity.type == MessageEntity.TEXT_MENTION and entity.user: + insert = f'<a href="tg://user?id={entity.user.id}">{text}</a>' + elif entity.type == MessageEntity.URL and urled: + insert = f'<a href="{text}">{text}</a>' + elif entity.type == MessageEntity.BOLD: + insert = '<b>' + text + '</b>' + elif entity.type == MessageEntity.ITALIC: + insert = '<i>' + text + '</i>' + elif entity.type == MessageEntity.CODE: + insert = '<code>' + text + '</code>' + elif entity.type == MessageEntity.PRE: + if entity.language: + insert = f'<pre><code class="{entity.language}">{text}</code></pre>' + else: + insert = '<pre>' + text + '</pre>' + elif entity.type == MessageEntity.UNDERLINE: + insert = '<u>' + text + '</u>' + elif entity.type == MessageEntity.STRIKETHROUGH: + insert = '<s>' + text + '</s>' + else: + insert = text + + if offset == 0: + if sys.maxunicode == 0xFFFF: + html_text += ( + escape(message_text[last_offset : entity.offset - offset]) + insert + ) + else: + html_text += ( + escape( + message_text[ # type: ignore + last_offset * 2 : (entity.offset - offset) * 2 + ].decode('utf-16-le') + ) + + insert + ) + else: + if sys.maxunicode == 0xFFFF: + html_text += message_text[last_offset : entity.offset - offset] + insert + else: + html_text += ( + message_text[ # type: ignore + last_offset * 2 : (entity.offset - offset) * 2 + ].decode('utf-16-le') + + insert + ) + + last_offset = entity.offset - offset + entity.length + + if offset == 0: + if sys.maxunicode == 0xFFFF: + html_text += escape(message_text[last_offset:]) + else: + html_text += escape( + message_text[last_offset * 2 :].decode('utf-16-le') # type: ignore + ) + else: + if sys.maxunicode == 0xFFFF: + html_text += message_text[last_offset:] + else: + html_text += message_text[last_offset * 2 :].decode('utf-16-le') # type: ignore + + return html_text + + @property + def text_html(self) -> str: + """Creates an HTML-formatted string from the markup entities found in the message. + + Use this if you want to retrieve the message text with the entities formatted as HTML in + the same way the original message was formatted. + + Returns: + :obj:`str`: Message text with entities formatted as HTML. + + """ + return self._parse_html(self.text, self.parse_entities(), urled=False) + + @property + def text_html_urled(self) -> str: + """Creates an HTML-formatted string from the markup entities found in the message. + + Use this if you want to retrieve the message text with the entities formatted as HTML. + This also formats :attr:`telegram.MessageEntity.URL` as a hyperlink. + + Returns: + :obj:`str`: Message text with entities formatted as HTML. + + """ + return self._parse_html(self.text, self.parse_entities(), urled=True) + + @property + def caption_html(self) -> str: + """Creates an HTML-formatted string from the markup entities found in the message's + caption. + + Use this if you want to retrieve the message caption with the caption entities formatted as + HTML in the same way the original message was formatted. + + Returns: + :obj:`str`: Message caption with caption entities formatted as HTML. + + """ + return self._parse_html(self.caption, self.parse_caption_entities(), urled=False) + + @property + def caption_html_urled(self) -> str: + """Creates an HTML-formatted string from the markup entities found in the message's + caption. + + Use this if you want to retrieve the message caption with the caption entities formatted as + HTML. This also formats :attr:`telegram.MessageEntity.URL` as a hyperlink. + + Returns: + :obj:`str`: Message caption with caption entities formatted as HTML. + + """ + return self._parse_html(self.caption, self.parse_caption_entities(), urled=True) + + @staticmethod + def _parse_markdown( + message_text: Optional[str], + entities: Dict[MessageEntity, str], + urled: bool = False, + version: int = 1, + offset: int = 0, + ) -> Optional[str]: + version = int(version) + + if message_text is None: + return None + + if sys.maxunicode != 0xFFFF: + message_text = message_text.encode('utf-16-le') # type: ignore + + markdown_text = '' + last_offset = 0 + + sorted_entities = sorted(entities.items(), key=(lambda item: item[0].offset)) + parsed_entities = [] + + for (entity, text) in sorted_entities: + if entity not in parsed_entities: + nested_entities = { + e: t + for (e, t) in sorted_entities + if e.offset >= entity.offset + and e.offset + e.length <= entity.offset + entity.length + and e != entity + } + parsed_entities.extend(list(nested_entities.keys())) + + orig_text = text + text = escape_markdown(text, version=version) + + if nested_entities: + if version < 2: + raise ValueError( + 'Nested entities are not supported for Markdown ' 'version 1' + ) + + text = Message._parse_markdown( + orig_text, + nested_entities, + urled=urled, + offset=entity.offset, + version=version, + ) + + if entity.type == MessageEntity.TEXT_LINK: + if version == 1: + url = entity.url + else: + # Links need special escaping. Also can't have entities nested within + url = escape_markdown( + entity.url, version=version, entity_type=MessageEntity.TEXT_LINK + ) + insert = f'[{text}]({url})' + elif entity.type == MessageEntity.TEXT_MENTION and entity.user: + insert = f'[{text}](tg://user?id={entity.user.id})' + elif entity.type == MessageEntity.URL and urled: + if version == 1: + link = orig_text + else: + link = text + insert = f'[{link}]({orig_text})' + elif entity.type == MessageEntity.BOLD: + insert = '*' + text + '*' + elif entity.type == MessageEntity.ITALIC: + insert = '_' + text + '_' + elif entity.type == MessageEntity.CODE: + # Monospace needs special escaping. Also can't have entities nested within + insert = ( + '`' + + escape_markdown( + orig_text, version=version, entity_type=MessageEntity.CODE + ) + + '`' + ) + elif entity.type == MessageEntity.PRE: + # Monospace needs special escaping. Also can't have entities nested within + code = escape_markdown( + orig_text, version=version, entity_type=MessageEntity.PRE + ) + if entity.language: + prefix = '```' + entity.language + '\n' + else: + if code.startswith('\\'): + prefix = '```' + else: + prefix = '```\n' + insert = prefix + code + '```' + elif entity.type == MessageEntity.UNDERLINE: + if version == 1: + raise ValueError( + 'Underline entities are not supported for Markdown ' 'version 1' + ) + insert = '__' + text + '__' + elif entity.type == MessageEntity.STRIKETHROUGH: + if version == 1: + raise ValueError( + 'Strikethrough entities are not supported for Markdown ' 'version 1' + ) + insert = '~' + text + '~' + else: + insert = text + + if offset == 0: + if sys.maxunicode == 0xFFFF: + markdown_text += ( + escape_markdown( + message_text[last_offset : entity.offset - offset], version=version + ) + + insert + ) + else: + markdown_text += ( + escape_markdown( + message_text[ # type: ignore + last_offset * 2 : (entity.offset - offset) * 2 + ].decode('utf-16-le'), + version=version, + ) + + insert + ) + else: + if sys.maxunicode == 0xFFFF: + markdown_text += ( + message_text[last_offset : entity.offset - offset] + insert + ) + else: + markdown_text += ( + message_text[ # type: ignore + last_offset * 2 : (entity.offset - offset) * 2 + ].decode('utf-16-le') + + insert + ) + + last_offset = entity.offset - offset + entity.length + + if offset == 0: + if sys.maxunicode == 0xFFFF: + markdown_text += escape_markdown(message_text[last_offset:], version=version) + else: + markdown_text += escape_markdown( + message_text[last_offset * 2 :].decode('utf-16-le'), # type: ignore + version=version, + ) + else: + if sys.maxunicode == 0xFFFF: + markdown_text += message_text[last_offset:] + else: + markdown_text += message_text[last_offset * 2 :].decode( # type: ignore + 'utf-16-le' + ) + + return markdown_text + + @property + def text_markdown(self) -> str: + """Creates an Markdown-formatted string from the markup entities found in the message + using :class:`telegram.ParseMode.MARKDOWN`. + + Use this if you want to retrieve the message text with the entities formatted as Markdown + in the same way the original message was formatted. + + Note: + :attr:`telegram.ParseMode.MARKDOWN` is is a legacy mode, retained by Telegram for + backward compatibility. You should use :meth:`text_markdown_v2` instead. + + Returns: + :obj:`str`: Message text with entities formatted as Markdown. + + """ + return self._parse_markdown(self.text, self.parse_entities(), urled=False) + + @property + def text_markdown_v2(self) -> str: + """Creates an Markdown-formatted string from the markup entities found in the message + using :class:`telegram.ParseMode.MARKDOWN_V2`. + + Use this if you want to retrieve the message text with the entities formatted as Markdown + in the same way the original message was formatted. + + Returns: + :obj:`str`: Message text with entities formatted as Markdown. + + """ + return self._parse_markdown(self.text, self.parse_entities(), urled=False, version=2) + + @property + def text_markdown_urled(self) -> str: + """Creates an Markdown-formatted string from the markup entities found in the message + using :class:`telegram.ParseMode.MARKDOWN`. + + Use this if you want to retrieve the message text with the entities formatted as Markdown. + This also formats :attr:`telegram.MessageEntity.URL` as a hyperlink. + + Note: + :attr:`telegram.ParseMode.MARKDOWN` is is a legacy mode, retained by Telegram for + backward compatibility. You should use :meth:`text_markdown_v2_urled` instead. + + Returns: + :obj:`str`: Message text with entities formatted as Markdown. + + """ + return self._parse_markdown(self.text, self.parse_entities(), urled=True) + + @property + def text_markdown_v2_urled(self) -> str: + """Creates an Markdown-formatted string from the markup entities found in the message + using :class:`telegram.ParseMode.MARKDOWN_V2`. + + Use this if you want to retrieve the message text with the entities formatted as Markdown. + This also formats :attr:`telegram.MessageEntity.URL` as a hyperlink. + + Returns: + :obj:`str`: Message text with entities formatted as Markdown. + + """ + return self._parse_markdown(self.text, self.parse_entities(), urled=True, version=2) + + @property + def caption_markdown(self) -> str: + """Creates an Markdown-formatted string from the markup entities found in the message's + caption using :class:`telegram.ParseMode.MARKDOWN`. + + Use this if you want to retrieve the message caption with the caption entities formatted as + Markdown in the same way the original message was formatted. + + Note: + :attr:`telegram.ParseMode.MARKDOWN` is is a legacy mode, retained by Telegram for + backward compatibility. You should use :meth:`caption_markdown_v2` instead. + + Returns: + :obj:`str`: Message caption with caption entities formatted as Markdown. + + """ + return self._parse_markdown(self.caption, self.parse_caption_entities(), urled=False) + + @property + def caption_markdown_v2(self) -> str: + """Creates an Markdown-formatted string from the markup entities found in the message's + caption using :class:`telegram.ParseMode.MARKDOWN_V2`. + + Use this if you want to retrieve the message caption with the caption entities formatted as + Markdown in the same way the original message was formatted. + + Returns: + :obj:`str`: Message caption with caption entities formatted as Markdown. + + """ + return self._parse_markdown( + self.caption, self.parse_caption_entities(), urled=False, version=2 + ) + + @property + def caption_markdown_urled(self) -> str: + """Creates an Markdown-formatted string from the markup entities found in the message's + caption using :class:`telegram.ParseMode.MARKDOWN`. + + Use this if you want to retrieve the message caption with the caption entities formatted as + Markdown. This also formats :attr:`telegram.MessageEntity.URL` as a hyperlink. + + Note: + :attr:`telegram.ParseMode.MARKDOWN` is is a legacy mode, retained by Telegram for + backward compatibility. You should use :meth:`caption_markdown_v2_urled` instead. + + Returns: + :obj:`str`: Message caption with caption entities formatted as Markdown. + + """ + return self._parse_markdown(self.caption, self.parse_caption_entities(), urled=True) + + @property + def caption_markdown_v2_urled(self) -> str: + """Creates an Markdown-formatted string from the markup entities found in the message's + caption using :class:`telegram.ParseMode.MARKDOWN_V2`. + + Use this if you want to retrieve the message caption with the caption entities formatted as + Markdown. This also formats :attr:`telegram.MessageEntity.URL` as a hyperlink. + + Returns: + :obj:`str`: Message caption with caption entities formatted as Markdown. + + """ + return self._parse_markdown( + self.caption, self.parse_caption_entities(), urled=True, version=2 + ) diff --git a/venv/lib/python3.8/site-packages/telegram/messageautodeletetimerchanged.py b/venv/lib/python3.8/site-packages/telegram/messageautodeletetimerchanged.py new file mode 100644 index 0000000..3fb1ce9 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/messageautodeletetimerchanged.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a change in the Telegram message auto +deletion. +""" + +from typing import Any + +from telegram import TelegramObject + + +class MessageAutoDeleteTimerChanged(TelegramObject): + """This object represents a service message about a change in auto-delete timer settings. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`message_auto_delete_time` is equal. + + .. versionadded:: 13.4 + + Args: + message_auto_delete_time (:obj:`int`): New auto-delete time for messages in the + chat. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + message_auto_delete_time (:obj:`int`): New auto-delete time for messages in the + chat. + + """ + + __slots__ = ('message_auto_delete_time', '_id_attrs') + + def __init__( + self, + message_auto_delete_time: int, + **_kwargs: Any, + ): + self.message_auto_delete_time = int(message_auto_delete_time) + + self._id_attrs = (self.message_auto_delete_time,) diff --git a/venv/lib/python3.8/site-packages/telegram/messageentity.py b/venv/lib/python3.8/site-packages/telegram/messageentity.py new file mode 100644 index 0000000..0a0350e --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/messageentity.py @@ -0,0 +1,129 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram MessageEntity.""" + +from typing import TYPE_CHECKING, Any, List, Optional, ClassVar + +from telegram import TelegramObject, User, constants +from telegram.utils.types import JSONDict + +if TYPE_CHECKING: + from telegram import Bot + + +class MessageEntity(TelegramObject): + """ + This object represents one special entity in a text message. For example, hashtags, + usernames, URLs, etc. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`type`, :attr:`offset` and :attr:`length` are equal. + + Args: + type (:obj:`str`): Type of the entity. Can be mention (@username), hashtag, bot_command, + url, email, phone_number, bold (bold text), italic (italic text), strikethrough, + code (monowidth string), pre (monowidth block), text_link (for clickable text URLs), + text_mention (for users without usernames). + offset (:obj:`int`): Offset in UTF-16 code units to the start of the entity. + length (:obj:`int`): Length of the entity in UTF-16 code units. + url (:obj:`str`, optional): For :attr:`TEXT_LINK` only, url that will be opened after + user taps on the text. + user (:class:`telegram.User`, optional): For :attr:`TEXT_MENTION` only, the mentioned + user. + language (:obj:`str`, optional): For :attr:`PRE` only, the programming language of + the entity text. + + Attributes: + type (:obj:`str`): Type of the entity. + offset (:obj:`int`): Offset in UTF-16 code units to the start of the entity. + length (:obj:`int`): Length of the entity in UTF-16 code units. + url (:obj:`str`): Optional. Url that will be opened after user taps on the text. + user (:class:`telegram.User`): Optional. The mentioned user. + language (:obj:`str`): Optional. Programming language of the entity text. + + """ + + __slots__ = ('length', 'url', 'user', 'type', 'language', 'offset', '_id_attrs') + + def __init__( + self, + type: str, # pylint: disable=W0622 + offset: int, + length: int, + url: str = None, + user: User = None, + language: str = None, + **_kwargs: Any, + ): + # Required + self.type = type + self.offset = offset + self.length = length + # Optionals + self.url = url + self.user = user + self.language = language + + self._id_attrs = (self.type, self.offset, self.length) + + @classmethod + def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['MessageEntity']: + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + if not data: + return None + + data['user'] = User.de_json(data.get('user'), bot) + + return cls(**data) + + MENTION: ClassVar[str] = constants.MESSAGEENTITY_MENTION + """:const:`telegram.constants.MESSAGEENTITY_MENTION`""" + HASHTAG: ClassVar[str] = constants.MESSAGEENTITY_HASHTAG + """:const:`telegram.constants.MESSAGEENTITY_HASHTAG`""" + CASHTAG: ClassVar[str] = constants.MESSAGEENTITY_CASHTAG + """:const:`telegram.constants.MESSAGEENTITY_CASHTAG`""" + PHONE_NUMBER: ClassVar[str] = constants.MESSAGEENTITY_PHONE_NUMBER + """:const:`telegram.constants.MESSAGEENTITY_PHONE_NUMBER`""" + BOT_COMMAND: ClassVar[str] = constants.MESSAGEENTITY_BOT_COMMAND + """:const:`telegram.constants.MESSAGEENTITY_BOT_COMMAND`""" + URL: ClassVar[str] = constants.MESSAGEENTITY_URL + """:const:`telegram.constants.MESSAGEENTITY_URL`""" + EMAIL: ClassVar[str] = constants.MESSAGEENTITY_EMAIL + """:const:`telegram.constants.MESSAGEENTITY_EMAIL`""" + BOLD: ClassVar[str] = constants.MESSAGEENTITY_BOLD + """:const:`telegram.constants.MESSAGEENTITY_BOLD`""" + ITALIC: ClassVar[str] = constants.MESSAGEENTITY_ITALIC + """:const:`telegram.constants.MESSAGEENTITY_ITALIC`""" + CODE: ClassVar[str] = constants.MESSAGEENTITY_CODE + """:const:`telegram.constants.MESSAGEENTITY_CODE`""" + PRE: ClassVar[str] = constants.MESSAGEENTITY_PRE + """:const:`telegram.constants.MESSAGEENTITY_PRE`""" + TEXT_LINK: ClassVar[str] = constants.MESSAGEENTITY_TEXT_LINK + """:const:`telegram.constants.MESSAGEENTITY_TEXT_LINK`""" + TEXT_MENTION: ClassVar[str] = constants.MESSAGEENTITY_TEXT_MENTION + """:const:`telegram.constants.MESSAGEENTITY_TEXT_MENTION`""" + UNDERLINE: ClassVar[str] = constants.MESSAGEENTITY_UNDERLINE + """:const:`telegram.constants.MESSAGEENTITY_UNDERLINE`""" + STRIKETHROUGH: ClassVar[str] = constants.MESSAGEENTITY_STRIKETHROUGH + """:const:`telegram.constants.MESSAGEENTITY_STRIKETHROUGH`""" + ALL_TYPES: ClassVar[List[str]] = constants.MESSAGEENTITY_ALL_TYPES + """:const:`telegram.constants.MESSAGEENTITY_ALL_TYPES`\n + List of all the types""" diff --git a/venv/lib/python3.8/site-packages/telegram/messageid.py b/venv/lib/python3.8/site-packages/telegram/messageid.py new file mode 100644 index 0000000..56eca3a --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/messageid.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2020-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents an instance of a Telegram MessageId.""" +from typing import Any + +from telegram import TelegramObject + + +class MessageId(TelegramObject): + """This object represents a unique message identifier. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`message_id` is equal. + + Attributes: + message_id (:obj:`int`): Unique message identifier + """ + + __slots__ = ('message_id', '_id_attrs') + + def __init__(self, message_id: int, **_kwargs: Any): + self.message_id = int(message_id) + + self._id_attrs = (self.message_id,) diff --git a/venv/lib/python3.8/site-packages/telegram/parsemode.py b/venv/lib/python3.8/site-packages/telegram/parsemode.py new file mode 100644 index 0000000..86bc07b --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/parsemode.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python +# pylint: disable=R0903 +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram Message Parse Modes.""" +from typing import ClassVar + +from telegram import constants +from telegram.utils.deprecate import set_new_attribute_deprecated + + +class ParseMode: + """This object represents a Telegram Message Parse Modes.""" + + __slots__ = ('__dict__',) + + MARKDOWN: ClassVar[str] = constants.PARSEMODE_MARKDOWN + """:const:`telegram.constants.PARSEMODE_MARKDOWN`\n + + Note: + :attr:`MARKDOWN` is a legacy mode, retained by Telegram for backward compatibility. + You should use :attr:`MARKDOWN_V2` instead. + """ + MARKDOWN_V2: ClassVar[str] = constants.PARSEMODE_MARKDOWN_V2 + """:const:`telegram.constants.PARSEMODE_MARKDOWN_V2`""" + HTML: ClassVar[str] = constants.PARSEMODE_HTML + """:const:`telegram.constants.PARSEMODE_HTML`""" + + def __setattr__(self, key: str, value: object) -> None: + set_new_attribute_deprecated(self, key, value) diff --git a/venv/lib/python3.8/site-packages/telegram/passport/__init__.py b/venv/lib/python3.8/site-packages/telegram/passport/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.8/site-packages/telegram/passport/credentials.py b/venv/lib/python3.8/site-packages/telegram/passport/credentials.py new file mode 100644 index 0000000..156c79d --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/passport/credentials.py @@ -0,0 +1,497 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +# pylint: disable=C0114, W0622 +try: + import ujson as json +except ImportError: + import json # type: ignore[no-redef] + +from base64 import b64decode +from typing import TYPE_CHECKING, Any, List, Optional, Tuple, Union, no_type_check + +try: + from cryptography.hazmat.backends import default_backend + from cryptography.hazmat.primitives.asymmetric.padding import MGF1, OAEP + from cryptography.hazmat.primitives.ciphers import Cipher + from cryptography.hazmat.primitives.ciphers.algorithms import AES + from cryptography.hazmat.primitives.ciphers.modes import CBC + from cryptography.hazmat.primitives.hashes import SHA1, SHA256, SHA512, Hash + + CRYPTO_INSTALLED = True +except ImportError: + default_backend = None + MGF1, OAEP, Cipher, AES, CBC = (None, None, None, None, None) # type: ignore[misc] + SHA1, SHA256, SHA512, Hash = (None, None, None, None) # type: ignore[misc] + + CRYPTO_INSTALLED = False + +from telegram import TelegramError, TelegramObject +from telegram.utils.types import JSONDict + +if TYPE_CHECKING: + from telegram import Bot + + +class TelegramDecryptionError(TelegramError): + """Something went wrong with decryption.""" + + __slots__ = ('_msg',) + + def __init__(self, message: Union[str, Exception]): + super().__init__(f"TelegramDecryptionError: {message}") + self._msg = str(message) + + def __reduce__(self) -> Tuple[type, Tuple[str]]: + return self.__class__, (self._msg,) + + +@no_type_check +def decrypt(secret, hash, data): + """ + Decrypt per telegram docs at https://core.telegram.org/passport. + + Args: + secret (:obj:`str` or :obj:`bytes`): The encryption secret, either as bytes or as a + base64 encoded string. + hash (:obj:`str` or :obj:`bytes`): The hash, either as bytes or as a + base64 encoded string. + data (:obj:`str` or :obj:`bytes`): The data to decrypt, either as bytes or as a + base64 encoded string. + file (:obj:`bool`): Force data to be treated as raw data, instead of trying to + b64decode it. + + Raises: + :class:`TelegramDecryptionError`: Given hash does not match hash of decrypted data. + + Returns: + :obj:`bytes`: The decrypted data as bytes. + + """ + if not CRYPTO_INSTALLED: + raise RuntimeError( + 'To use Telegram Passports, PTB must be installed via `pip install ' + 'python-telegram-bot[passport]`.' + ) + # Make a SHA512 hash of secret + update + digest = Hash(SHA512(), backend=default_backend()) + digest.update(secret + hash) + secret_hash_hash = digest.finalize() + # First 32 chars is our key, next 16 is the initialisation vector + key, init_vector = secret_hash_hash[:32], secret_hash_hash[32 : 32 + 16] + # Init a AES-CBC cipher and decrypt the data + cipher = Cipher(AES(key), CBC(init_vector), backend=default_backend()) + decryptor = cipher.decryptor() + data = decryptor.update(data) + decryptor.finalize() + # Calculate SHA256 hash of the decrypted data + digest = Hash(SHA256(), backend=default_backend()) + digest.update(data) + data_hash = digest.finalize() + # If the newly calculated hash did not match the one telegram gave us + if data_hash != hash: + # Raise a error that is caught inside telegram.PassportData and transformed into a warning + raise TelegramDecryptionError(f"Hashes are not equal! {data_hash} != {hash}") + # Return data without padding + return data[data[0] :] + + +@no_type_check +def decrypt_json(secret, hash, data): + """Decrypts data using secret and hash and then decodes utf-8 string and loads json""" + return json.loads(decrypt(secret, hash, data).decode('utf-8')) + + +class EncryptedCredentials(TelegramObject): + """Contains data required for decrypting and authenticating EncryptedPassportElement. See the + Telegram Passport Documentation for a complete description of the data decryption and + authentication processes. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`data`, :attr:`hash` and :attr:`secret` are equal. + + Note: + This object is decrypted only when originating from + :obj:`telegram.PassportData.decrypted_credentials`. + + Args: + data (:class:`telegram.Credentials` or :obj:`str`): Decrypted data with unique user's + nonce, data hashes and secrets used for EncryptedPassportElement decryption and + authentication or base64 encrypted data. + hash (:obj:`str`): Base64-encoded data hash for data authentication. + secret (:obj:`str`): Decrypted or encrypted secret used for decryption. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + data (:class:`telegram.Credentials` or :obj:`str`): Decrypted data with unique user's + nonce, data hashes and secrets used for EncryptedPassportElement decryption and + authentication or base64 encrypted data. + hash (:obj:`str`): Base64-encoded data hash for data authentication. + secret (:obj:`str`): Decrypted or encrypted secret used for decryption. + + """ + + __slots__ = ( + 'hash', + 'secret', + 'bot', + 'data', + '_id_attrs', + '_decrypted_secret', + '_decrypted_data', + ) + + def __init__(self, data: str, hash: str, secret: str, bot: 'Bot' = None, **_kwargs: Any): + # Required + self.data = data + self.hash = hash + self.secret = secret + + self._id_attrs = (self.data, self.hash, self.secret) + + self.bot = bot + self._decrypted_secret = None + self._decrypted_data: Optional['Credentials'] = None + + @property + def decrypted_secret(self) -> str: + """ + :obj:`str`: Lazily decrypt and return secret. + + Raises: + telegram.TelegramDecryptionError: Decryption failed. Usually due to bad + private/public key but can also suggest malformed/tampered data. + """ + if self._decrypted_secret is None: + if not CRYPTO_INSTALLED: + raise RuntimeError( + 'To use Telegram Passports, PTB must be installed via `pip install ' + 'python-telegram-bot[passport]`.' + ) + # Try decrypting according to step 1 at + # https://core.telegram.org/passport#decrypting-data + # We make sure to base64 decode the secret first. + # Telegram says to use OAEP padding so we do that. The Mask Generation Function + # is the default for OAEP, the algorithm is the default for PHP which is what + # Telegram's backend servers run. + try: + self._decrypted_secret = self.bot.private_key.decrypt( + b64decode(self.secret), + OAEP(mgf=MGF1(algorithm=SHA1()), algorithm=SHA1(), label=None), # skipcq + ) + except ValueError as exception: + # If decryption fails raise exception + raise TelegramDecryptionError(exception) from exception + return self._decrypted_secret + + @property + def decrypted_data(self) -> 'Credentials': + """ + :class:`telegram.Credentials`: Lazily decrypt and return credentials data. This object + also contains the user specified nonce as + `decrypted_data.nonce`. + + Raises: + telegram.TelegramDecryptionError: Decryption failed. Usually due to bad + private/public key but can also suggest malformed/tampered data. + """ + if self._decrypted_data is None: + self._decrypted_data = Credentials.de_json( + decrypt_json(self.decrypted_secret, b64decode(self.hash), b64decode(self.data)), + self.bot, + ) + return self._decrypted_data + + +class Credentials(TelegramObject): + """ + Attributes: + secure_data (:class:`telegram.SecureData`): Credentials for encrypted data + nonce (:obj:`str`): Bot-specified nonce + """ + + __slots__ = ('bot', 'nonce', 'secure_data') + + def __init__(self, secure_data: 'SecureData', nonce: str, bot: 'Bot' = None, **_kwargs: Any): + # Required + self.secure_data = secure_data + self.nonce = nonce + + self.bot = bot + + @classmethod + def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Credentials']: + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + if not data: + return None + + data['secure_data'] = SecureData.de_json(data.get('secure_data'), bot=bot) + + return cls(bot=bot, **data) + + +class SecureData(TelegramObject): + """ + This object represents the credentials that were used to decrypt the encrypted data. + All fields are optional and depend on fields that were requested. + + Attributes: + personal_details (:class:`telegram.SecureValue`, optional): Credentials for encrypted + personal details. + passport (:class:`telegram.SecureValue`, optional): Credentials for encrypted passport. + internal_passport (:class:`telegram.SecureValue`, optional): Credentials for encrypted + internal passport. + driver_license (:class:`telegram.SecureValue`, optional): Credentials for encrypted + driver license. + identity_card (:class:`telegram.SecureValue`, optional): Credentials for encrypted ID card + address (:class:`telegram.SecureValue`, optional): Credentials for encrypted + residential address. + utility_bill (:class:`telegram.SecureValue`, optional): Credentials for encrypted + utility bill. + bank_statement (:class:`telegram.SecureValue`, optional): Credentials for encrypted + bank statement. + rental_agreement (:class:`telegram.SecureValue`, optional): Credentials for encrypted + rental agreement. + passport_registration (:class:`telegram.SecureValue`, optional): Credentials for encrypted + registration from internal passport. + temporary_registration (:class:`telegram.SecureValue`, optional): Credentials for encrypted + temporary registration. + """ + + __slots__ = ( + 'bot', + 'utility_bill', + 'personal_details', + 'temporary_registration', + 'address', + 'driver_license', + 'rental_agreement', + 'internal_passport', + 'identity_card', + 'bank_statement', + 'passport', + 'passport_registration', + ) + + def __init__( + self, + personal_details: 'SecureValue' = None, + passport: 'SecureValue' = None, + internal_passport: 'SecureValue' = None, + driver_license: 'SecureValue' = None, + identity_card: 'SecureValue' = None, + address: 'SecureValue' = None, + utility_bill: 'SecureValue' = None, + bank_statement: 'SecureValue' = None, + rental_agreement: 'SecureValue' = None, + passport_registration: 'SecureValue' = None, + temporary_registration: 'SecureValue' = None, + bot: 'Bot' = None, + **_kwargs: Any, + ): + # Optionals + self.temporary_registration = temporary_registration + self.passport_registration = passport_registration + self.rental_agreement = rental_agreement + self.bank_statement = bank_statement + self.utility_bill = utility_bill + self.address = address + self.identity_card = identity_card + self.driver_license = driver_license + self.internal_passport = internal_passport + self.passport = passport + self.personal_details = personal_details + + self.bot = bot + + @classmethod + def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['SecureData']: + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + if not data: + return None + + data['temporary_registration'] = SecureValue.de_json( + data.get('temporary_registration'), bot=bot + ) + data['passport_registration'] = SecureValue.de_json( + data.get('passport_registration'), bot=bot + ) + data['rental_agreement'] = SecureValue.de_json(data.get('rental_agreement'), bot=bot) + data['bank_statement'] = SecureValue.de_json(data.get('bank_statement'), bot=bot) + data['utility_bill'] = SecureValue.de_json(data.get('utility_bill'), bot=bot) + data['address'] = SecureValue.de_json(data.get('address'), bot=bot) + data['identity_card'] = SecureValue.de_json(data.get('identity_card'), bot=bot) + data['driver_license'] = SecureValue.de_json(data.get('driver_license'), bot=bot) + data['internal_passport'] = SecureValue.de_json(data.get('internal_passport'), bot=bot) + data['passport'] = SecureValue.de_json(data.get('passport'), bot=bot) + data['personal_details'] = SecureValue.de_json(data.get('personal_details'), bot=bot) + + return cls(bot=bot, **data) + + +class SecureValue(TelegramObject): + """ + This object represents the credentials that were used to decrypt the encrypted value. + All fields are optional and depend on the type of field. + + Attributes: + data (:class:`telegram.DataCredentials`, optional): Credentials for encrypted Telegram + Passport data. Available for "personal_details", "passport", "driver_license", + "identity_card", "identity_passport" and "address" types. + front_side (:class:`telegram.FileCredentials`, optional): Credentials for encrypted + document's front side. Available for "passport", "driver_license", "identity_card" + and "internal_passport". + reverse_side (:class:`telegram.FileCredentials`, optional): Credentials for encrypted + document's reverse side. Available for "driver_license" and "identity_card". + selfie (:class:`telegram.FileCredentials`, optional): Credentials for encrypted selfie + of the user with a document. Can be available for "passport", "driver_license", + "identity_card" and "internal_passport". + translation (List[:class:`telegram.FileCredentials`], optional): Credentials for an + encrypted translation of the document. Available for "passport", "driver_license", + "identity_card", "internal_passport", "utility_bill", "bank_statement", + "rental_agreement", "passport_registration" and "temporary_registration". + files (List[:class:`telegram.FileCredentials`], optional): Credentials for encrypted + files. Available for "utility_bill", "bank_statement", "rental_agreement", + "passport_registration" and "temporary_registration" types. + + """ + + __slots__ = ('data', 'front_side', 'reverse_side', 'selfie', 'files', 'translation', 'bot') + + def __init__( + self, + data: 'DataCredentials' = None, + front_side: 'FileCredentials' = None, + reverse_side: 'FileCredentials' = None, + selfie: 'FileCredentials' = None, + files: List['FileCredentials'] = None, + translation: List['FileCredentials'] = None, + bot: 'Bot' = None, + **_kwargs: Any, + ): + self.data = data + self.front_side = front_side + self.reverse_side = reverse_side + self.selfie = selfie + self.files = files + self.translation = translation + + self.bot = bot + + @classmethod + def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['SecureValue']: + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + if not data: + return None + + data['data'] = DataCredentials.de_json(data.get('data'), bot=bot) + data['front_side'] = FileCredentials.de_json(data.get('front_side'), bot=bot) + data['reverse_side'] = FileCredentials.de_json(data.get('reverse_side'), bot=bot) + data['selfie'] = FileCredentials.de_json(data.get('selfie'), bot=bot) + data['files'] = FileCredentials.de_list(data.get('files'), bot=bot) + data['translation'] = FileCredentials.de_list(data.get('translation'), bot=bot) + + return cls(bot=bot, **data) + + def to_dict(self) -> JSONDict: + """See :meth:`telegram.TelegramObject.to_dict`.""" + data = super().to_dict() + + data['files'] = [p.to_dict() for p in self.files] + data['translation'] = [p.to_dict() for p in self.translation] + + return data + + +class _CredentialsBase(TelegramObject): + """Base class for DataCredentials and FileCredentials.""" + + __slots__ = ('hash', 'secret', 'file_hash', 'data_hash', 'bot') + + def __init__(self, hash: str, secret: str, bot: 'Bot' = None, **_kwargs: Any): + self.hash = hash + self.secret = secret + + # Aliases just be be sure + self.file_hash = self.hash + self.data_hash = self.hash + + self.bot = bot + + +class DataCredentials(_CredentialsBase): + """ + These credentials can be used to decrypt encrypted data from the data field in + EncryptedPassportData. + + Args: + data_hash (:obj:`str`): Checksum of encrypted data + secret (:obj:`str`): Secret of encrypted data + + Attributes: + hash (:obj:`str`): Checksum of encrypted data + secret (:obj:`str`): Secret of encrypted data + """ + + __slots__ = () + + def __init__(self, data_hash: str, secret: str, **_kwargs: Any): + super().__init__(data_hash, secret, **_kwargs) + + def to_dict(self) -> JSONDict: + """See :meth:`telegram.TelegramObject.to_dict`.""" + data = super().to_dict() + + del data['file_hash'] + del data['hash'] + + return data + + +class FileCredentials(_CredentialsBase): + """ + These credentials can be used to decrypt encrypted files from the front_side, + reverse_side, selfie and files fields in EncryptedPassportData. + + Args: + file_hash (:obj:`str`): Checksum of encrypted file + secret (:obj:`str`): Secret of encrypted file + + Attributes: + hash (:obj:`str`): Checksum of encrypted file + secret (:obj:`str`): Secret of encrypted file + """ + + __slots__ = () + + def __init__(self, file_hash: str, secret: str, **_kwargs: Any): + super().__init__(file_hash, secret, **_kwargs) + + def to_dict(self) -> JSONDict: + """See :meth:`telegram.TelegramObject.to_dict`.""" + data = super().to_dict() + + del data['data_hash'] + del data['hash'] + + return data diff --git a/venv/lib/python3.8/site-packages/telegram/passport/data.py b/venv/lib/python3.8/site-packages/telegram/passport/data.py new file mode 100644 index 0000000..b17f5d8 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/passport/data.py @@ -0,0 +1,153 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +# pylint: disable=C0114 +from typing import TYPE_CHECKING, Any + +from telegram import TelegramObject + +if TYPE_CHECKING: + from telegram import Bot + + +class PersonalDetails(TelegramObject): + """ + This object represents personal details. + + Attributes: + first_name (:obj:`str`): First Name. + middle_name (:obj:`str`): Optional. First Name. + last_name (:obj:`str`): Last Name. + birth_date (:obj:`str`): Date of birth in DD.MM.YYYY format. + gender (:obj:`str`): Gender, male or female. + country_code (:obj:`str`): Citizenship (ISO 3166-1 alpha-2 country code). + residence_country_code (:obj:`str`): Country of residence (ISO 3166-1 alpha-2 country + code). + first_name_native (:obj:`str`): First Name in the language of the user's country of + residence. + middle_name_native (:obj:`str`): Optional. Middle Name in the language of the user's + country of residence. + last_name_native (:obj:`str`): Last Name in the language of the user's country of + residence. + """ + + __slots__ = ( + 'middle_name', + 'first_name_native', + 'last_name_native', + 'residence_country_code', + 'first_name', + 'last_name', + 'country_code', + 'gender', + 'bot', + 'middle_name_native', + 'birth_date', + ) + + def __init__( + self, + first_name: str, + last_name: str, + birth_date: str, + gender: str, + country_code: str, + residence_country_code: str, + first_name_native: str = None, + last_name_native: str = None, + middle_name: str = None, + middle_name_native: str = None, + bot: 'Bot' = None, + **_kwargs: Any, + ): + # Required + self.first_name = first_name + self.last_name = last_name + self.middle_name = middle_name + self.birth_date = birth_date + self.gender = gender + self.country_code = country_code + self.residence_country_code = residence_country_code + self.first_name_native = first_name_native + self.last_name_native = last_name_native + self.middle_name_native = middle_name_native + + self.bot = bot + + +class ResidentialAddress(TelegramObject): + """ + This object represents a residential address. + + Attributes: + street_line1 (:obj:`str`): First line for the address. + street_line2 (:obj:`str`): Optional. Second line for the address. + city (:obj:`str`): City. + state (:obj:`str`): Optional. State. + country_code (:obj:`str`): ISO 3166-1 alpha-2 country code. + post_code (:obj:`str`): Address post code. + """ + + __slots__ = ( + 'post_code', + 'city', + 'country_code', + 'street_line2', + 'street_line1', + 'bot', + 'state', + ) + + def __init__( + self, + street_line1: str, + street_line2: str, + city: str, + state: str, + country_code: str, + post_code: str, + bot: 'Bot' = None, + **_kwargs: Any, + ): + # Required + self.street_line1 = street_line1 + self.street_line2 = street_line2 + self.city = city + self.state = state + self.country_code = country_code + self.post_code = post_code + + self.bot = bot + + +class IdDocumentData(TelegramObject): + """ + This object represents the data of an identity document. + + Attributes: + document_no (:obj:`str`): Document number. + expiry_date (:obj:`str`): Optional. Date of expiry, in DD.MM.YYYY format. + """ + + __slots__ = ('document_no', 'bot', 'expiry_date') + + def __init__(self, document_no: str, expiry_date: str, bot: 'Bot' = None, **_kwargs: Any): + self.document_no = document_no + self.expiry_date = expiry_date + + self.bot = bot diff --git a/venv/lib/python3.8/site-packages/telegram/passport/encryptedpassportelement.py b/venv/lib/python3.8/site-packages/telegram/passport/encryptedpassportelement.py new file mode 100644 index 0000000..74e3aaf --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/passport/encryptedpassportelement.py @@ -0,0 +1,266 @@ +#!/usr/bin/env python +# flake8: noqa: E501 +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram EncryptedPassportElement.""" +from base64 import b64decode +from typing import TYPE_CHECKING, Any, List, Optional + +from telegram import ( + IdDocumentData, + PassportFile, + PersonalDetails, + ResidentialAddress, + TelegramObject, +) +from telegram.passport.credentials import decrypt_json +from telegram.utils.types import JSONDict + +if TYPE_CHECKING: + from telegram import Bot, Credentials + + +class EncryptedPassportElement(TelegramObject): + """ + Contains information about documents or other Telegram Passport elements shared with the bot + by the user. The data has been automatically decrypted by python-telegram-bot. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`type`, :attr:`data`, :attr:`phone_number`, :attr:`email`, + :attr:`files`, :attr:`front_side`, :attr:`reverse_side` and :attr:`selfie` are equal. + + Note: + This object is decrypted only when originating from + :obj:`telegram.PassportData.decrypted_data`. + + Args: + type (:obj:`str`): Element type. One of "personal_details", "passport", "driver_license", + "identity_card", "internal_passport", "address", "utility_bill", "bank_statement", + "rental_agreement", "passport_registration", "temporary_registration", "phone_number", + "email". + data (:class:`telegram.PersonalDetails` | :class:`telegram.IdDocument` | \ + :class:`telegram.ResidentialAddress` | :obj:`str`, optional): + Decrypted or encrypted data, available for "personal_details", "passport", + "driver_license", "identity_card", "identity_passport" and "address" types. + phone_number (:obj:`str`, optional): User's verified phone number, available only for + "phone_number" type. + email (:obj:`str`, optional): User's verified email address, available only for "email" + type. + files (List[:class:`telegram.PassportFile`], optional): Array of encrypted/decrypted files + with documents provided by the user, available for "utility_bill", "bank_statement", + "rental_agreement", "passport_registration" and "temporary_registration" types. + front_side (:class:`telegram.PassportFile`, optional): Encrypted/decrypted file with the + front side of the document, provided by the user. Available for "passport", + "driver_license", "identity_card" and "internal_passport". + reverse_side (:class:`telegram.PassportFile`, optional): Encrypted/decrypted file with the + reverse side of the document, provided by the user. Available for "driver_license" and + "identity_card". + selfie (:class:`telegram.PassportFile`, optional): Encrypted/decrypted file with the + selfie of the user holding a document, provided by the user; available for "passport", + "driver_license", "identity_card" and "internal_passport". + translation (List[:class:`telegram.PassportFile`], optional): Array of encrypted/decrypted + files with translated versions of documents provided by the user. Available if + requested for "passport", "driver_license", "identity_card", "internal_passport", + "utility_bill", "bank_statement", "rental_agreement", "passport_registration" and + "temporary_registration" types. + hash (:obj:`str`): Base64-encoded element hash for using in + :class:`telegram.PassportElementErrorUnspecified`. + bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + type (:obj:`str`): Element type. One of "personal_details", "passport", "driver_license", + "identity_card", "internal_passport", "address", "utility_bill", "bank_statement", + "rental_agreement", "passport_registration", "temporary_registration", "phone_number", + "email". + data (:class:`telegram.PersonalDetails` | :class:`telegram.IdDocument` | \ + :class:`telegram.ResidentialAddress` | :obj:`str`): + Optional. Decrypted or encrypted data, available for "personal_details", "passport", + "driver_license", "identity_card", "identity_passport" and "address" types. + phone_number (:obj:`str`): Optional. User's verified phone number, available only for + "phone_number" type. + email (:obj:`str`): Optional. User's verified email address, available only for "email" + type. + files (List[:class:`telegram.PassportFile`]): Optional. Array of encrypted/decrypted files + with documents provided by the user, available for "utility_bill", "bank_statement", + "rental_agreement", "passport_registration" and "temporary_registration" types. + front_side (:class:`telegram.PassportFile`): Optional. Encrypted/decrypted file with the + front side of the document, provided by the user. Available for "passport", + "driver_license", "identity_card" and "internal_passport". + reverse_side (:class:`telegram.PassportFile`): Optional. Encrypted/decrypted file with the + reverse side of the document, provided by the user. Available for "driver_license" and + "identity_card". + selfie (:class:`telegram.PassportFile`): Optional. Encrypted/decrypted file with the + selfie of the user holding a document, provided by the user; available for "passport", + "driver_license", "identity_card" and "internal_passport". + translation (List[:class:`telegram.PassportFile`]): Optional. Array of encrypted/decrypted + files with translated versions of documents provided by the user. Available if + requested for "passport", "driver_license", "identity_card", "internal_passport", + "utility_bill", "bank_statement", "rental_agreement", "passport_registration" and + "temporary_registration" types. + hash (:obj:`str`): Base64-encoded element hash for using in + :class:`telegram.PassportElementErrorUnspecified`. + bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods. + + """ + + __slots__ = ( + 'selfie', + 'files', + 'type', + 'translation', + 'email', + 'hash', + 'phone_number', + 'bot', + 'reverse_side', + 'front_side', + 'data', + '_id_attrs', + ) + + def __init__( + self, + type: str, # pylint: disable=W0622 + data: PersonalDetails = None, + phone_number: str = None, + email: str = None, + files: List[PassportFile] = None, + front_side: PassportFile = None, + reverse_side: PassportFile = None, + selfie: PassportFile = None, + translation: List[PassportFile] = None, + hash: str = None, # pylint: disable=W0622 + bot: 'Bot' = None, + credentials: 'Credentials' = None, # pylint: disable=W0613 + **_kwargs: Any, + ): + # Required + self.type = type + # Optionals + self.data = data + self.phone_number = phone_number + self.email = email + self.files = files + self.front_side = front_side + self.reverse_side = reverse_side + self.selfie = selfie + self.translation = translation + self.hash = hash + + self._id_attrs = ( + self.type, + self.data, + self.phone_number, + self.email, + self.files, + self.front_side, + self.reverse_side, + self.selfie, + ) + + self.bot = bot + + @classmethod + def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['EncryptedPassportElement']: + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + if not data: + return None + + data['files'] = PassportFile.de_list(data.get('files'), bot) or None + data['front_side'] = PassportFile.de_json(data.get('front_side'), bot) + data['reverse_side'] = PassportFile.de_json(data.get('reverse_side'), bot) + data['selfie'] = PassportFile.de_json(data.get('selfie'), bot) + data['translation'] = PassportFile.de_list(data.get('translation'), bot) or None + + return cls(bot=bot, **data) + + @classmethod + def de_json_decrypted( + cls, data: Optional[JSONDict], bot: 'Bot', credentials: 'Credentials' + ) -> Optional['EncryptedPassportElement']: + """Variant of :meth:`telegram.TelegramObject.de_json` that also takes into account + passport credentials. + + Args: + data (Dict[:obj:`str`, ...]): The JSON data. + bot (:class:`telegram.Bot`): The bot associated with this object. + credentials (:class:`telegram.FileCredentials`): The credentials + + Returns: + :class:`telegram.EncryptedPassportElement`: + + """ + if not data: + return None + + if data['type'] not in ('phone_number', 'email'): + secure_data = getattr(credentials.secure_data, data['type']) + + if secure_data.data is not None: + # If not already decrypted + if not isinstance(data['data'], dict): + data['data'] = decrypt_json( + b64decode(secure_data.data.secret), + b64decode(secure_data.data.hash), + b64decode(data['data']), + ) + if data['type'] == 'personal_details': + data['data'] = PersonalDetails.de_json(data['data'], bot=bot) + elif data['type'] in ( + 'passport', + 'internal_passport', + 'driver_license', + 'identity_card', + ): + data['data'] = IdDocumentData.de_json(data['data'], bot=bot) + elif data['type'] == 'address': + data['data'] = ResidentialAddress.de_json(data['data'], bot=bot) + + data['files'] = ( + PassportFile.de_list_decrypted(data.get('files'), bot, secure_data.files) or None + ) + data['front_side'] = PassportFile.de_json_decrypted( + data.get('front_side'), bot, secure_data.front_side + ) + data['reverse_side'] = PassportFile.de_json_decrypted( + data.get('reverse_side'), bot, secure_data.reverse_side + ) + data['selfie'] = PassportFile.de_json_decrypted( + data.get('selfie'), bot, secure_data.selfie + ) + data['translation'] = ( + PassportFile.de_list_decrypted( + data.get('translation'), bot, secure_data.translation + ) + or None + ) + + return cls(bot=bot, **data) + + def to_dict(self) -> JSONDict: + """See :meth:`telegram.TelegramObject.to_dict`.""" + data = super().to_dict() + + if self.files: + data['files'] = [p.to_dict() for p in self.files] + if self.translation: + data['translation'] = [p.to_dict() for p in self.translation] + + return data diff --git a/venv/lib/python3.8/site-packages/telegram/passport/passportdata.py b/venv/lib/python3.8/site-packages/telegram/passport/passportdata.py new file mode 100644 index 0000000..a8d1ede --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/passport/passportdata.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""Contains information about Telegram Passport data shared with the bot by the user.""" + +from typing import TYPE_CHECKING, Any, List, Optional + +from telegram import EncryptedCredentials, EncryptedPassportElement, TelegramObject +from telegram.utils.types import JSONDict + +if TYPE_CHECKING: + from telegram import Bot, Credentials + + +class PassportData(TelegramObject): + """Contains information about Telegram Passport data shared with the bot by the user. + + Note: + To be able to decrypt this object, you must pass your ``private_key`` to either + :class:`telegram.Updater` or :class:`telegram.Bot`. Decrypted data is then found in + :attr:`decrypted_data` and the payload can be found in :attr:`decrypted_credentials`'s + attribute :attr:`telegram.Credentials.payload`. + + Args: + data (List[:class:`telegram.EncryptedPassportElement`]): Array with encrypted information + about documents and other Telegram Passport elements that was shared with the bot. + credentials (:class:`telegram.EncryptedCredentials`)): Encrypted credentials. + bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + data (List[:class:`telegram.EncryptedPassportElement`]): Array with encrypted information + about documents and other Telegram Passport elements that was shared with the bot. + credentials (:class:`telegram.EncryptedCredentials`): Encrypted credentials. + bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods. + + """ + + __slots__ = ('bot', 'credentials', 'data', '_decrypted_data', '_id_attrs') + + def __init__( + self, + data: List[EncryptedPassportElement], + credentials: EncryptedCredentials, + bot: 'Bot' = None, + **_kwargs: Any, + ): + self.data = data + self.credentials = credentials + + self.bot = bot + self._decrypted_data: Optional[List[EncryptedPassportElement]] = None + self._id_attrs = tuple([x.type for x in data] + [credentials.hash]) + + @classmethod + def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['PassportData']: + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + if not data: + return None + + data['data'] = EncryptedPassportElement.de_list(data.get('data'), bot) + data['credentials'] = EncryptedCredentials.de_json(data.get('credentials'), bot) + + return cls(bot=bot, **data) + + def to_dict(self) -> JSONDict: + """See :meth:`telegram.TelegramObject.to_dict`.""" + data = super().to_dict() + + data['data'] = [e.to_dict() for e in self.data] + + return data + + @property + def decrypted_data(self) -> List[EncryptedPassportElement]: + """ + List[:class:`telegram.EncryptedPassportElement`]: Lazily decrypt and return information + about documents and other Telegram Passport elements which were shared with the bot. + + Raises: + telegram.TelegramDecryptionError: Decryption failed. Usually due to bad + private/public key but can also suggest malformed/tampered data. + """ + if self._decrypted_data is None: + self._decrypted_data = [ + EncryptedPassportElement.de_json_decrypted( + element.to_dict(), self.bot, self.decrypted_credentials + ) + for element in self.data + ] + return self._decrypted_data + + @property + def decrypted_credentials(self) -> 'Credentials': + """ + :class:`telegram.Credentials`: Lazily decrypt and return credentials that were used + to decrypt the data. This object also contains the user specified payload as + `decrypted_data.payload`. + + Raises: + telegram.TelegramDecryptionError: Decryption failed. Usually due to bad + private/public key but can also suggest malformed/tampered data. + """ + return self.credentials.decrypted_data diff --git a/venv/lib/python3.8/site-packages/telegram/passport/passportelementerrors.py b/venv/lib/python3.8/site-packages/telegram/passport/passportelementerrors.py new file mode 100644 index 0000000..4d61f96 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/passport/passportelementerrors.py @@ -0,0 +1,382 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +# pylint: disable=W0622 +"""This module contains the classes that represent Telegram PassportElementError.""" + +from typing import Any + +from telegram import TelegramObject + + +class PassportElementError(TelegramObject): + """Baseclass for the PassportElementError* classes. + + This object represents an error in the Telegram Passport element which was submitted that + should be resolved by the user. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`source` and :attr:`type` are equal. + + Args: + source (:obj:`str`): Error source. + type (:obj:`str`): The section of the user's Telegram Passport which has the error. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + source (:obj:`str`): Error source. + type (:obj:`str`): The section of the user's Telegram Passport which has the error. + message (:obj:`str`): Error message. + + """ + + # All subclasses of this class won't have _id_attrs in slots since it's added here. + __slots__ = ('message', 'source', 'type', '_id_attrs') + + def __init__(self, source: str, type: str, message: str, **_kwargs: Any): + # Required + self.source = str(source) + self.type = str(type) + self.message = str(message) + + self._id_attrs = (self.source, self.type) + + +class PassportElementErrorDataField(PassportElementError): + """ + Represents an issue in one of the data fields that was provided by the user. The error is + considered resolved when the field's value changes. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`source`, :attr:`type`, :attr:`field_name`, :attr:`data_hash` + and :attr:`message` are equal. + + Args: + type (:obj:`str`): The section of the user's Telegram Passport which has the error, one of + ``"personal_details"``, ``"passport"``, ``"driver_license"``, ``"identity_card"``, + ``"internal_passport"``, ``"address"``. + field_name (:obj:`str`): Name of the data field which has the error. + data_hash (:obj:`str`): Base64-encoded data hash. + message (:obj:`str`): Error message. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + type (:obj:`str`): The section of the user's Telegram Passport which has the error, one of + ``"personal_details"``, ``"passport"``, ``"driver_license"``, ``"identity_card"``, + ``"internal_passport"``, ``"address"``. + field_name (:obj:`str`): Name of the data field which has the error. + data_hash (:obj:`str`): Base64-encoded data hash. + message (:obj:`str`): Error message. + + """ + + __slots__ = ('data_hash', 'field_name') + + def __init__(self, type: str, field_name: str, data_hash: str, message: str, **_kwargs: Any): + # Required + super().__init__('data', type, message) + self.field_name = field_name + self.data_hash = data_hash + + self._id_attrs = (self.source, self.type, self.field_name, self.data_hash, self.message) + + +class PassportElementErrorFile(PassportElementError): + """ + Represents an issue with a document scan. The error is considered resolved when the file with + the document scan changes. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`source`, :attr:`type`, :attr:`file_hash`, and + :attr:`message` are equal. + + Args: + type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of + ``"utility_bill"``, ``"bank_statement"``, ``"rental_agreement"``, + ``"passport_registration"``, ``"temporary_registration"``. + file_hash (:obj:`str`): Base64-encoded file hash. + message (:obj:`str`): Error message. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of + ``"utility_bill"``, ``"bank_statement"``, ``"rental_agreement"``, + ``"passport_registration"``, ``"temporary_registration"``. + file_hash (:obj:`str`): Base64-encoded file hash. + message (:obj:`str`): Error message. + + """ + + __slots__ = ('file_hash',) + + def __init__(self, type: str, file_hash: str, message: str, **_kwargs: Any): + # Required + super().__init__('file', type, message) + self.file_hash = file_hash + + self._id_attrs = (self.source, self.type, self.file_hash, self.message) + + +class PassportElementErrorFiles(PassportElementError): + """ + Represents an issue with a list of scans. The error is considered resolved when the list of + files with the document scans changes. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`source`, :attr:`type`, :attr:`file_hashes`, and + :attr:`message` are equal. + + Args: + type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of + ``"utility_bill"``, ``"bank_statement"``, ``"rental_agreement"``, + ``"passport_registration"``, ``"temporary_registration"``. + file_hashes (List[:obj:`str`]): List of base64-encoded file hashes. + message (:obj:`str`): Error message. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of + ``"utility_bill"``, ``"bank_statement"``, ``"rental_agreement"``, + ``"passport_registration"``, ``"temporary_registration"``. + file_hashes (List[:obj:`str`]): List of base64-encoded file hashes. + message (:obj:`str`): Error message. + + """ + + __slots__ = ('file_hashes',) + + def __init__(self, type: str, file_hashes: str, message: str, **_kwargs: Any): + # Required + super().__init__('files', type, message) + self.file_hashes = file_hashes + + self._id_attrs = (self.source, self.type, self.message) + tuple(file_hashes) + + +class PassportElementErrorFrontSide(PassportElementError): + """ + Represents an issue with the front side of a document. The error is considered resolved when + the file with the front side of the document changes. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`source`, :attr:`type`, :attr:`file_hash`, and + :attr:`message` are equal. + + Args: + type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of + ``"passport"``, ``"driver_license"``, ``"identity_card"``, ``"internal_passport"``. + file_hash (:obj:`str`): Base64-encoded hash of the file with the front side of the + document. + message (:obj:`str`): Error message. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of + ``"passport"``, ``"driver_license"``, ``"identity_card"``, ``"internal_passport"``. + file_hash (:obj:`str`): Base64-encoded hash of the file with the front side of the + document. + message (:obj:`str`): Error message. + + """ + + __slots__ = ('file_hash',) + + def __init__(self, type: str, file_hash: str, message: str, **_kwargs: Any): + # Required + super().__init__('front_side', type, message) + self.file_hash = file_hash + + self._id_attrs = (self.source, self.type, self.file_hash, self.message) + + +class PassportElementErrorReverseSide(PassportElementError): + """ + Represents an issue with the reverse side of a document. The error is considered resolved when + the file with the reverse side of the document changes. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`source`, :attr:`type`, :attr:`file_hash`, and + :attr:`message` are equal. + + Args: + type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of + ``"driver_license"``, ``"identity_card"``. + file_hash (:obj:`str`): Base64-encoded hash of the file with the reverse side of the + document. + message (:obj:`str`): Error message. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of + ``"driver_license"``, ``"identity_card"``. + file_hash (:obj:`str`): Base64-encoded hash of the file with the reverse side of the + document. + message (:obj:`str`): Error message. + + """ + + __slots__ = ('file_hash',) + + def __init__(self, type: str, file_hash: str, message: str, **_kwargs: Any): + # Required + super().__init__('reverse_side', type, message) + self.file_hash = file_hash + + self._id_attrs = (self.source, self.type, self.file_hash, self.message) + + +class PassportElementErrorSelfie(PassportElementError): + """ + Represents an issue with the selfie with a document. The error is considered resolved when + the file with the selfie changes. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`source`, :attr:`type`, :attr:`file_hash`, and + :attr:`message` are equal. + + Args: + type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of + ``"passport"``, ``"driver_license"``, ``"identity_card"``, ``"internal_passport"``. + file_hash (:obj:`str`): Base64-encoded hash of the file with the selfie. + message (:obj:`str`): Error message. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of + ``"passport"``, ``"driver_license"``, ``"identity_card"``, ``"internal_passport"``. + file_hash (:obj:`str`): Base64-encoded hash of the file with the selfie. + message (:obj:`str`): Error message. + + """ + + __slots__ = ('file_hash',) + + def __init__(self, type: str, file_hash: str, message: str, **_kwargs: Any): + # Required + super().__init__('selfie', type, message) + self.file_hash = file_hash + + self._id_attrs = (self.source, self.type, self.file_hash, self.message) + + +class PassportElementErrorTranslationFile(PassportElementError): + """ + Represents an issue with one of the files that constitute the translation of a document. + The error is considered resolved when the file changes. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`source`, :attr:`type`, :attr:`file_hash`, and + :attr:`message` are equal. + + Args: + type (:obj:`str`): Type of element of the user's Telegram Passport which has the issue, + one of ``"passport"``, ``"driver_license"``, ``"identity_card"``, + ``"internal_passport"``, ``"utility_bill"``, ``"bank_statement"``, + ``"rental_agreement"``, ``"passport_registration"``, ``"temporary_registration"``. + file_hash (:obj:`str`): Base64-encoded hash of the file. + message (:obj:`str`): Error message. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + type (:obj:`str`): Type of element of the user's Telegram Passport which has the issue, + one of ``"passport"``, ``"driver_license"``, ``"identity_card"``, + ``"internal_passport"``, ``"utility_bill"``, ``"bank_statement"``, + ``"rental_agreement"``, ``"passport_registration"``, ``"temporary_registration"``. + file_hash (:obj:`str`): Base64-encoded hash of the file. + message (:obj:`str`): Error message. + + """ + + __slots__ = ('file_hash',) + + def __init__(self, type: str, file_hash: str, message: str, **_kwargs: Any): + # Required + super().__init__('translation_file', type, message) + self.file_hash = file_hash + + self._id_attrs = (self.source, self.type, self.file_hash, self.message) + + +class PassportElementErrorTranslationFiles(PassportElementError): + """ + Represents an issue with the translated version of a document. The error is considered + resolved when a file with the document translation changes. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`source`, :attr:`type`, :attr:`file_hashes`, and + :attr:`message` are equal. + + Args: + type (:obj:`str`): Type of element of the user's Telegram Passport which has the issue, + one of ``"passport"``, ``"driver_license"``, ``"identity_card"``, + ``"internal_passport"``, ``"utility_bill"``, ``"bank_statement"``, + ``"rental_agreement"``, ``"passport_registration"``, ``"temporary_registration"``. + file_hashes (List[:obj:`str`]): List of base64-encoded file hashes. + message (:obj:`str`): Error message. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + type (:obj:`str`): Type of element of the user's Telegram Passport which has the issue, + one of ``"passport"``, ``"driver_license"``, ``"identity_card"``, + ``"internal_passport"``, ``"utility_bill"``, ``"bank_statement"``, + ``"rental_agreement"``, ``"passport_registration"``, ``"temporary_registration"``. + file_hashes (List[:obj:`str`]): List of base64-encoded file hashes. + message (:obj:`str`): Error message. + + """ + + __slots__ = ('file_hashes',) + + def __init__(self, type: str, file_hashes: str, message: str, **_kwargs: Any): + # Required + super().__init__('translation_files', type, message) + self.file_hashes = file_hashes + + self._id_attrs = (self.source, self.type, self.message) + tuple(file_hashes) + + +class PassportElementErrorUnspecified(PassportElementError): + """ + Represents an issue in an unspecified place. The error is considered resolved when new + data is added. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`source`, :attr:`type`, :attr:`element_hash`, + and :attr:`message` are equal. + + Args: + type (:obj:`str`): Type of element of the user's Telegram Passport which has the issue. + element_hash (:obj:`str`): Base64-encoded element hash. + message (:obj:`str`): Error message. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + type (:obj:`str`): Type of element of the user's Telegram Passport which has the issue. + element_hash (:obj:`str`): Base64-encoded element hash. + message (:obj:`str`): Error message. + + """ + + __slots__ = ('element_hash',) + + def __init__(self, type: str, element_hash: str, message: str, **_kwargs: Any): + # Required + super().__init__('unspecified', type, message) + self.element_hash = element_hash + + self._id_attrs = (self.source, self.type, self.element_hash, self.message) diff --git a/venv/lib/python3.8/site-packages/telegram/passport/passportfile.py b/venv/lib/python3.8/site-packages/telegram/passport/passportfile.py new file mode 100644 index 0000000..b5f2122 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/passport/passportfile.py @@ -0,0 +1,160 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Encrypted PassportFile.""" + +from typing import TYPE_CHECKING, Any, List, Optional + +from telegram import TelegramObject +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import JSONDict, ODVInput + +if TYPE_CHECKING: + from telegram import Bot, File, FileCredentials + + +class PassportFile(TelegramObject): + """ + This object represents a file uploaded to Telegram Passport. Currently all Telegram Passport + files are in JPEG format when decrypted and don't exceed 10MB. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`file_unique_id` is equal. + + Args: + file_id (:obj:`str`): Identifier for this file, which can be used to download + or reuse the file. + file_unique_id (:obj:`str`): Unique identifier for this file, which + is supposed to be the same over time and for different bots. + Can't be used to download or reuse the file. + file_size (:obj:`int`): File size. + file_date (:obj:`int`): Unix time when the file was uploaded. + bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + file_id (:obj:`str`): Identifier for this file. + file_unique_id (:obj:`str`): Unique identifier for this file, which + is supposed to be the same over time and for different bots. + Can't be used to download or reuse the file. + file_size (:obj:`int`): File size. + file_date (:obj:`int`): Unix time when the file was uploaded. + bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods. + + """ + + __slots__ = ( + 'file_date', + 'bot', + 'file_id', + 'file_size', + '_credentials', + 'file_unique_id', + '_id_attrs', + ) + + def __init__( + self, + file_id: str, + file_unique_id: str, + file_date: int, + file_size: int = None, + bot: 'Bot' = None, + credentials: 'FileCredentials' = None, + **_kwargs: Any, + ): + # Required + self.file_id = file_id + self.file_unique_id = file_unique_id + self.file_size = file_size + self.file_date = file_date + # Optionals + self.bot = bot + self._credentials = credentials + + self._id_attrs = (self.file_unique_id,) + + @classmethod + def de_json_decrypted( + cls, data: Optional[JSONDict], bot: 'Bot', credentials: 'FileCredentials' + ) -> Optional['PassportFile']: + """Variant of :meth:`telegram.TelegramObject.de_json` that also takes into account + passport credentials. + + Args: + data (Dict[:obj:`str`, ...]): The JSON data. + bot (:class:`telegram.Bot`): The bot associated with this object. + credentials (:class:`telegram.FileCredentials`): The credentials + + Returns: + :class:`telegram.PassportFile`: + + """ + data = cls._parse_data(data) + + if not data: + return None + + data['credentials'] = credentials + + return cls(bot=bot, **data) + + @classmethod + def de_list_decrypted( + cls, data: Optional[List[JSONDict]], bot: 'Bot', credentials: List['FileCredentials'] + ) -> List[Optional['PassportFile']]: + """Variant of :meth:`telegram.TelegramObject.de_list` that also takes into account + passport credentials. + + Args: + data (Dict[:obj:`str`, ...]): The JSON data. + bot (:class:`telegram.Bot`): The bot associated with these objects. + credentials (:class:`telegram.FileCredentials`): The credentials + + Returns: + List[:class:`telegram.PassportFile`]: + + """ + if not data: + return [] + + return [ + cls.de_json_decrypted(passport_file, bot, credentials[i]) + for i, passport_file in enumerate(data) + ] + + def get_file( + self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None + ) -> 'File': + """ + Wrapper over :attr:`telegram.Bot.get_file`. Will automatically assign the correct + credentials to the returned :class:`telegram.File` if originating from + :obj:`telegram.PassportData.decrypted_data`. + + For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. + + Returns: + :class:`telegram.File` + + Raises: + :class:`telegram.error.TelegramError` + + """ + file = self.bot.get_file(file_id=self.file_id, timeout=timeout, api_kwargs=api_kwargs) + file.set_credentials(self._credentials) + return file diff --git a/venv/lib/python3.8/site-packages/telegram/payment/__init__.py b/venv/lib/python3.8/site-packages/telegram/payment/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.8/site-packages/telegram/payment/invoice.py b/venv/lib/python3.8/site-packages/telegram/payment/invoice.py new file mode 100644 index 0000000..dea2740 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/payment/invoice.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram Invoice.""" + +from typing import Any + +from telegram import TelegramObject + + +class Invoice(TelegramObject): + """This object contains basic information about an invoice. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`title`, :attr:`description`, :attr:`start_parameter`, + :attr:`currency` and :attr:`total_amount` are equal. + + Args: + title (:obj:`str`): Product name. + description (:obj:`str`): Product description. + start_parameter (:obj:`str`): Unique bot deep-linking parameter that can be used to + generate this invoice. + currency (:obj:`str`): Three-letter ISO 4217 currency code. + total_amount (:obj:`int`): Total price in the smallest units of the currency (integer, not + float/double). For example, for a price of US$ 1.45 pass ``amount = 145``. See the + :obj:`exp` parameter in + `currencies.json <https://core.telegram.org/bots/payments/currencies.json>`_, + it shows the number of digits past the decimal point for each currency + (2 for the majority of currencies). + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + title (:obj:`str`): Product name. + description (:obj:`str`): Product description. + start_parameter (:obj:`str`): Unique bot deep-linking parameter. + currency (:obj:`str`): Three-letter ISO 4217 currency code. + total_amount (:obj:`int`): Total price in the smallest units of the currency. + + """ + + __slots__ = ( + 'currency', + 'start_parameter', + 'title', + 'description', + 'total_amount', + '_id_attrs', + ) + + def __init__( + self, + title: str, + description: str, + start_parameter: str, + currency: str, + total_amount: int, + **_kwargs: Any, + ): + self.title = title + self.description = description + self.start_parameter = start_parameter + self.currency = currency + self.total_amount = total_amount + + self._id_attrs = ( + self.title, + self.description, + self.start_parameter, + self.currency, + self.total_amount, + ) diff --git a/venv/lib/python3.8/site-packages/telegram/payment/labeledprice.py b/venv/lib/python3.8/site-packages/telegram/payment/labeledprice.py new file mode 100644 index 0000000..221c62d --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/payment/labeledprice.py @@ -0,0 +1,54 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram LabeledPrice.""" + +from typing import Any + +from telegram import TelegramObject + + +class LabeledPrice(TelegramObject): + """This object represents a portion of the price for goods or services. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`label` and :attr:`amount` are equal. + + Args: + label (:obj:`str`): Portion label. + amount (:obj:`int`): Price of the product in the smallest units of the currency (integer, + not float/double). For example, for a price of US$ 1.45 pass ``amount = 145``. + See the :obj:`exp` parameter in + `currencies.json <https://core.telegram.org/bots/payments/currencies.json>`_, + it shows the number of digits past the decimal point for each currency + (2 for the majority of currencies). + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + label (:obj:`str`): Portion label. + amount (:obj:`int`): Price of the product in the smallest units of the currency. + + """ + + __slots__ = ('label', '_id_attrs', 'amount') + + def __init__(self, label: str, amount: int, **_kwargs: Any): + self.label = label + self.amount = amount + + self._id_attrs = (self.label, self.amount) diff --git a/venv/lib/python3.8/site-packages/telegram/payment/orderinfo.py b/venv/lib/python3.8/site-packages/telegram/payment/orderinfo.py new file mode 100644 index 0000000..7ebe358 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/payment/orderinfo.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram OrderInfo.""" + +from typing import TYPE_CHECKING, Any, Optional + +from telegram import ShippingAddress, TelegramObject +from telegram.utils.types import JSONDict + +if TYPE_CHECKING: + from telegram import Bot + + +class OrderInfo(TelegramObject): + """This object represents information about an order. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`name`, :attr:`phone_number`, :attr:`email` and + :attr:`shipping_address` are equal. + + Args: + name (:obj:`str`, optional): User name. + phone_number (:obj:`str`, optional): User's phone number. + email (:obj:`str`, optional): User email. + shipping_address (:class:`telegram.ShippingAddress`, optional): User shipping address. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + name (:obj:`str`): Optional. User name. + phone_number (:obj:`str`): Optional. User's phone number. + email (:obj:`str`): Optional. User email. + shipping_address (:class:`telegram.ShippingAddress`): Optional. User shipping address. + + """ + + __slots__ = ('email', 'shipping_address', 'phone_number', 'name', '_id_attrs') + + def __init__( + self, + name: str = None, + phone_number: str = None, + email: str = None, + shipping_address: str = None, + **_kwargs: Any, + ): + self.name = name + self.phone_number = phone_number + self.email = email + self.shipping_address = shipping_address + + self._id_attrs = (self.name, self.phone_number, self.email, self.shipping_address) + + @classmethod + def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['OrderInfo']: + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + if not data: + return cls() + + data['shipping_address'] = ShippingAddress.de_json(data.get('shipping_address'), bot) + + return cls(**data) diff --git a/venv/lib/python3.8/site-packages/telegram/payment/precheckoutquery.py b/venv/lib/python3.8/site-packages/telegram/payment/precheckoutquery.py new file mode 100644 index 0000000..a8f2eb2 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/payment/precheckoutquery.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram PreCheckoutQuery.""" + +from typing import TYPE_CHECKING, Any, Optional + +from telegram import OrderInfo, TelegramObject, User +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import JSONDict, ODVInput + +if TYPE_CHECKING: + from telegram import Bot + + +class PreCheckoutQuery(TelegramObject): + """This object contains information about an incoming pre-checkout query. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`id` is equal. + + Note: + In Python ``from`` is a reserved word, use ``from_user`` instead. + + Args: + id (:obj:`str`): Unique query identifier. + from_user (:class:`telegram.User`): User who sent the query. + currency (:obj:`str`): Three-letter ISO 4217 currency code. + total_amount (:obj:`int`): Total price in the smallest units of the currency (integer, not + float/double). For example, for a price of US$ 1.45 pass ``amount = 145``. + See the :obj:`exp` parameter in + `currencies.json <https://core.telegram.org/bots/payments/currencies.json>`_, + it shows the number of digits past the decimal point for each currency + (2 for the majority of currencies). + invoice_payload (:obj:`str`): Bot specified invoice payload. + shipping_option_id (:obj:`str`, optional): Identifier of the shipping option chosen by the + user. + order_info (:class:`telegram.OrderInfo`, optional): Order info provided by the user. + bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + id (:obj:`str`): Unique query identifier. + from_user (:class:`telegram.User`): User who sent the query. + currency (:obj:`str`): Three-letter ISO 4217 currency code. + total_amount (:obj:`int`): Total price in the smallest units of the currency. + invoice_payload (:obj:`str`): Bot specified invoice payload. + shipping_option_id (:obj:`str`): Optional. Identifier of the shipping option chosen by the + user. + order_info (:class:`telegram.OrderInfo`): Optional. Order info provided by the user. + bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods. + + """ + + __slots__ = ( + 'bot', + 'invoice_payload', + 'shipping_option_id', + 'currency', + 'order_info', + 'total_amount', + 'id', + 'from_user', + '_id_attrs', + ) + + def __init__( + self, + id: str, # pylint: disable=W0622 + from_user: User, + currency: str, + total_amount: int, + invoice_payload: str, + shipping_option_id: str = None, + order_info: OrderInfo = None, + bot: 'Bot' = None, + **_kwargs: Any, + ): + self.id = id # pylint: disable=C0103 + self.from_user = from_user + self.currency = currency + self.total_amount = total_amount + self.invoice_payload = invoice_payload + self.shipping_option_id = shipping_option_id + self.order_info = order_info + + self.bot = bot + + self._id_attrs = (self.id,) + + @classmethod + def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['PreCheckoutQuery']: + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + if not data: + return None + + data['from_user'] = User.de_json(data.pop('from'), bot) + data['order_info'] = OrderInfo.de_json(data.get('order_info'), bot) + + return cls(bot=bot, **data) + + def answer( # pylint: disable=C0103 + self, + ok: bool, + error_message: str = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> bool: + """Shortcut for:: + + bot.answer_pre_checkout_query(update.pre_checkout_query.id, *args, **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Bot.answer_pre_checkout_query`. + + """ + return self.bot.answer_pre_checkout_query( + pre_checkout_query_id=self.id, + ok=ok, + error_message=error_message, + timeout=timeout, + api_kwargs=api_kwargs, + ) diff --git a/venv/lib/python3.8/site-packages/telegram/payment/shippingaddress.py b/venv/lib/python3.8/site-packages/telegram/payment/shippingaddress.py new file mode 100644 index 0000000..2ea5a45 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/payment/shippingaddress.py @@ -0,0 +1,86 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram ShippingAddress.""" + +from typing import Any + +from telegram import TelegramObject + + +class ShippingAddress(TelegramObject): + """This object represents a Telegram ShippingAddress. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`country_code`, :attr:`state`, :attr:`city`, + :attr:`street_line1`, :attr:`street_line2` and :attr:`post_cod` are equal. + + Args: + country_code (:obj:`str`): ISO 3166-1 alpha-2 country code. + state (:obj:`str`): State, if applicable. + city (:obj:`str`): City. + street_line1 (:obj:`str`): First line for the address. + street_line2 (:obj:`str`): Second line for the address. + post_code (:obj:`str`): Address post code. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + country_code (:obj:`str`): ISO 3166-1 alpha-2 country code. + state (:obj:`str`): State, if applicable. + city (:obj:`str`): City. + street_line1 (:obj:`str`): First line for the address. + street_line2 (:obj:`str`): Second line for the address. + post_code (:obj:`str`): Address post code. + + """ + + __slots__ = ( + 'post_code', + 'city', + '_id_attrs', + 'country_code', + 'street_line2', + 'street_line1', + 'state', + ) + + def __init__( + self, + country_code: str, + state: str, + city: str, + street_line1: str, + street_line2: str, + post_code: str, + **_kwargs: Any, + ): + self.country_code = country_code + self.state = state + self.city = city + self.street_line1 = street_line1 + self.street_line2 = street_line2 + self.post_code = post_code + + self._id_attrs = ( + self.country_code, + self.state, + self.city, + self.street_line1, + self.street_line2, + self.post_code, + ) diff --git a/venv/lib/python3.8/site-packages/telegram/payment/shippingoption.py b/venv/lib/python3.8/site-packages/telegram/payment/shippingoption.py new file mode 100644 index 0000000..6ddbb0b --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/payment/shippingoption.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram ShippingOption.""" + +from typing import TYPE_CHECKING, Any, List + +from telegram import TelegramObject +from telegram.utils.types import JSONDict + +if TYPE_CHECKING: + from telegram import LabeledPrice # noqa + + +class ShippingOption(TelegramObject): + """This object represents one shipping option. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`id` is equal. + + Args: + id (:obj:`str`): Shipping option identifier. + title (:obj:`str`): Option title. + prices (List[:class:`telegram.LabeledPrice`]): List of price portions. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + id (:obj:`str`): Shipping option identifier. + title (:obj:`str`): Option title. + prices (List[:class:`telegram.LabeledPrice`]): List of price portions. + + """ + + __slots__ = ('prices', 'title', 'id', '_id_attrs') + + def __init__( + self, + id: str, # pylint: disable=W0622 + title: str, + prices: List['LabeledPrice'], + **_kwargs: Any, + ): + self.id = id # pylint: disable=C0103 + self.title = title + self.prices = prices + + self._id_attrs = (self.id,) + + def to_dict(self) -> JSONDict: + """See :meth:`telegram.TelegramObject.to_dict`.""" + data = super().to_dict() + + data['prices'] = [p.to_dict() for p in self.prices] + + return data diff --git a/venv/lib/python3.8/site-packages/telegram/payment/shippingquery.py b/venv/lib/python3.8/site-packages/telegram/payment/shippingquery.py new file mode 100644 index 0000000..bcde858 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/payment/shippingquery.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram ShippingQuery.""" + +from typing import TYPE_CHECKING, Any, Optional, List + +from telegram import ShippingAddress, TelegramObject, User, ShippingOption +from telegram.utils.helpers import DEFAULT_NONE +from telegram.utils.types import JSONDict, ODVInput + +if TYPE_CHECKING: + from telegram import Bot + + +class ShippingQuery(TelegramObject): + """This object contains information about an incoming shipping query. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`id` is equal. + + Note: + In Python ``from`` is a reserved word, use ``from_user`` instead. + + Args: + id (:obj:`str`): Unique query identifier. + from_user (:class:`telegram.User`): User who sent the query. + invoice_payload (:obj:`str`): Bot specified invoice payload. + shipping_address (:class:`telegram.ShippingAddress`): User specified shipping address. + bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + id (:obj:`str`): Unique query identifier. + from_user (:class:`telegram.User`): User who sent the query. + invoice_payload (:obj:`str`): Bot specified invoice payload. + shipping_address (:class:`telegram.ShippingAddress`): User specified shipping address. + bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods. + + """ + + __slots__ = ('bot', 'invoice_payload', 'shipping_address', 'id', 'from_user', '_id_attrs') + + def __init__( + self, + id: str, # pylint: disable=W0622 + from_user: User, + invoice_payload: str, + shipping_address: ShippingAddress, + bot: 'Bot' = None, + **_kwargs: Any, + ): + self.id = id # pylint: disable=C0103 + self.from_user = from_user + self.invoice_payload = invoice_payload + self.shipping_address = shipping_address + + self.bot = bot + + self._id_attrs = (self.id,) + + @classmethod + def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['ShippingQuery']: + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + if not data: + return None + + data['from_user'] = User.de_json(data.pop('from'), bot) + data['shipping_address'] = ShippingAddress.de_json(data.get('shipping_address'), bot) + + return cls(bot=bot, **data) + + def answer( # pylint: disable=C0103 + self, + ok: bool, + shipping_options: List[ShippingOption] = None, + error_message: str = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> bool: + """Shortcut for:: + + bot.answer_shipping_query(update.shipping_query.id, *args, **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Bot.answer_shipping_query`. + + """ + return self.bot.answer_shipping_query( + shipping_query_id=self.id, + ok=ok, + shipping_options=shipping_options, + error_message=error_message, + timeout=timeout, + api_kwargs=api_kwargs, + ) diff --git a/venv/lib/python3.8/site-packages/telegram/payment/successfulpayment.py b/venv/lib/python3.8/site-packages/telegram/payment/successfulpayment.py new file mode 100644 index 0000000..6997ca7 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/payment/successfulpayment.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram SuccessfulPayment.""" + +from typing import TYPE_CHECKING, Any, Optional + +from telegram import OrderInfo, TelegramObject +from telegram.utils.types import JSONDict + +if TYPE_CHECKING: + from telegram import Bot + + +class SuccessfulPayment(TelegramObject): + """This object contains basic information about a successful payment. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`telegram_payment_charge_id` and + :attr:`provider_payment_charge_id` are equal. + + Args: + currency (:obj:`str`): Three-letter ISO 4217 currency code. + total_amount (:obj:`int`): Total price in the smallest units of the currency (integer, not + float/double). For example, for a price of US$ 1.45 pass ``amount = 145``. + See the :obj:`exp` parameter in + `currencies.json <https://core.telegram.org/bots/payments/currencies.json>`_, + it shows the number of digits past the decimal point for each currency + (2 for the majority of currencies). + invoice_payload (:obj:`str`): Bot specified invoice payload. + shipping_option_id (:obj:`str`, optional): Identifier of the shipping option chosen by the + user. + order_info (:class:`telegram.OrderInfo`, optional): Order info provided by the user. + telegram_payment_charge_id (:obj:`str`): Telegram payment identifier. + provider_payment_charge_id (:obj:`str`): Provider payment identifier. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + currency (:obj:`str`): Three-letter ISO 4217 currency code. + total_amount (:obj:`int`): Total price in the smallest units of the currency. + invoice_payload (:obj:`str`): Bot specified invoice payload. + shipping_option_id (:obj:`str`): Optional. Identifier of the shipping option chosen by the + user. + order_info (:class:`telegram.OrderInfo`): Optional. Order info provided by the user. + telegram_payment_charge_id (:obj:`str`): Telegram payment identifier. + provider_payment_charge_id (:obj:`str`): Provider payment identifier. + + """ + + __slots__ = ( + 'invoice_payload', + 'shipping_option_id', + 'currency', + 'order_info', + 'telegram_payment_charge_id', + 'provider_payment_charge_id', + 'total_amount', + '_id_attrs', + ) + + def __init__( + self, + currency: str, + total_amount: int, + invoice_payload: str, + telegram_payment_charge_id: str, + provider_payment_charge_id: str, + shipping_option_id: str = None, + order_info: OrderInfo = None, + **_kwargs: Any, + ): + self.currency = currency + self.total_amount = total_amount + self.invoice_payload = invoice_payload + self.shipping_option_id = shipping_option_id + self.order_info = order_info + self.telegram_payment_charge_id = telegram_payment_charge_id + self.provider_payment_charge_id = provider_payment_charge_id + + self._id_attrs = (self.telegram_payment_charge_id, self.provider_payment_charge_id) + + @classmethod + def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['SuccessfulPayment']: + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + if not data: + return None + + data['order_info'] = OrderInfo.de_json(data.get('order_info'), bot) + + return cls(**data) diff --git a/venv/lib/python3.8/site-packages/telegram/poll.py b/venv/lib/python3.8/site-packages/telegram/poll.py new file mode 100644 index 0000000..9c28ce5 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/poll.py @@ -0,0 +1,295 @@ +#!/usr/bin/env python +# pylint: disable=R0903 +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram Poll.""" + +import datetime +import sys +from typing import TYPE_CHECKING, Any, Dict, List, Optional, ClassVar + +from telegram import MessageEntity, TelegramObject, User, constants +from telegram.utils.helpers import from_timestamp, to_timestamp +from telegram.utils.types import JSONDict + +if TYPE_CHECKING: + from telegram import Bot + + +class PollOption(TelegramObject): + """ + This object contains information about one answer option in a poll. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`text` and :attr:`voter_count` are equal. + + Args: + text (:obj:`str`): Option text, 1-100 characters. + voter_count (:obj:`int`): Number of users that voted for this option. + + Attributes: + text (:obj:`str`): Option text, 1-100 characters. + voter_count (:obj:`int`): Number of users that voted for this option. + + """ + + __slots__ = ('voter_count', 'text', '_id_attrs') + + def __init__(self, text: str, voter_count: int, **_kwargs: Any): + self.text = text + self.voter_count = voter_count + + self._id_attrs = (self.text, self.voter_count) + + MAX_LENGTH: ClassVar[int] = constants.MAX_POLL_OPTION_LENGTH + """:const:`telegram.constants.MAX_POLL_OPTION_LENGTH`""" + + +class PollAnswer(TelegramObject): + """ + This object represents an answer of a user in a non-anonymous poll. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`poll_id`, :attr:`user` and :attr:`options_ids` are equal. + + Attributes: + poll_id (:obj:`str`): Unique poll identifier. + user (:class:`telegram.User`): The user, who changed the answer to the poll. + option_ids (List[:obj:`int`]): Identifiers of answer options, chosen by the user. + + Args: + poll_id (:obj:`str`): Unique poll identifier. + user (:class:`telegram.User`): The user, who changed the answer to the poll. + option_ids (List[:obj:`int`]): 0-based identifiers of answer options, chosen by the user. + May be empty if the user retracted their vote. + + """ + + __slots__ = ('option_ids', 'user', 'poll_id', '_id_attrs') + + def __init__(self, poll_id: str, user: User, option_ids: List[int], **_kwargs: Any): + self.poll_id = poll_id + self.user = user + self.option_ids = option_ids + + self._id_attrs = (self.poll_id, self.user, tuple(self.option_ids)) + + @classmethod + def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['PollAnswer']: + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + if not data: + return None + + data['user'] = User.de_json(data.get('user'), bot) + + return cls(**data) + + +class Poll(TelegramObject): + """ + This object contains information about a poll. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`id` is equal. + + Attributes: + id (:obj:`str`): Unique poll identifier. + question (:obj:`str`): Poll question, 1-300 characters. + options (List[:class:`PollOption`]): List of poll options. + total_voter_count (:obj:`int`): Total number of users that voted in the poll. + is_closed (:obj:`bool`): :obj:`True`, if the poll is closed. + is_anonymous (:obj:`bool`): :obj:`True`, if the poll is anonymous. + type (:obj:`str`): Poll type, currently can be :attr:`REGULAR` or :attr:`QUIZ`. + allows_multiple_answers (:obj:`bool`): :obj:`True`, if the poll allows multiple answers. + correct_option_id (:obj:`int`): Optional. Identifier of the correct answer option. + explanation (:obj:`str`): Optional. Text that is shown when a user chooses an incorrect + answer or taps on the lamp icon in a quiz-style poll. + explanation_entities (List[:class:`telegram.MessageEntity`]): Optional. Special entities + like usernames, URLs, bot commands, etc. that appear in the :attr:`explanation`. + open_period (:obj:`int`): Optional. Amount of time in seconds the poll will be active + after creation. + close_date (:obj:`datetime.datetime`): Optional. Point in time when the poll will be + automatically closed. + + Args: + id (:obj:`str`): Unique poll identifier. + question (:obj:`str`): Poll question, 1-300 characters. + options (List[:class:`PollOption`]): List of poll options. + is_closed (:obj:`bool`): :obj:`True`, if the poll is closed. + is_anonymous (:obj:`bool`): :obj:`True`, if the poll is anonymous. + type (:obj:`str`): Poll type, currently can be :attr:`REGULAR` or :attr:`QUIZ`. + allows_multiple_answers (:obj:`bool`): :obj:`True`, if the poll allows multiple answers. + correct_option_id (:obj:`int`, optional): 0-based identifier of the correct answer option. + Available only for polls in the quiz mode, which are closed, or was sent (not + forwarded) by the bot or to the private chat with the bot. + explanation (:obj:`str`, optional): Text that is shown when a user chooses an incorrect + answer or taps on the lamp icon in a quiz-style poll, 0-200 characters. + explanation_entities (List[:class:`telegram.MessageEntity`], optional): Special entities + like usernames, URLs, bot commands, etc. that appear in the :attr:`explanation`. + open_period (:obj:`int`, optional): Amount of time in seconds the poll will be active + after creation. + close_date (:obj:`datetime.datetime`, optional): Point in time (Unix timestamp) when the + poll will be automatically closed. Converted to :obj:`datetime.datetime`. + + """ + + __slots__ = ( + 'total_voter_count', + 'allows_multiple_answers', + 'open_period', + 'options', + 'type', + 'explanation_entities', + 'is_anonymous', + 'close_date', + 'is_closed', + 'id', + 'explanation', + 'question', + 'correct_option_id', + '_id_attrs', + ) + + def __init__( + self, + id: str, # pylint: disable=W0622 + question: str, + options: List[PollOption], + total_voter_count: int, + is_closed: bool, + is_anonymous: bool, + type: str, # pylint: disable=W0622 + allows_multiple_answers: bool, + correct_option_id: int = None, + explanation: str = None, + explanation_entities: List[MessageEntity] = None, + open_period: int = None, + close_date: datetime.datetime = None, + **_kwargs: Any, + ): + self.id = id # pylint: disable=C0103 + self.question = question + self.options = options + self.total_voter_count = total_voter_count + self.is_closed = is_closed + self.is_anonymous = is_anonymous + self.type = type + self.allows_multiple_answers = allows_multiple_answers + self.correct_option_id = correct_option_id + self.explanation = explanation + self.explanation_entities = explanation_entities + self.open_period = open_period + self.close_date = close_date + + self._id_attrs = (self.id,) + + @classmethod + def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Poll']: + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + if not data: + return None + + data['options'] = [PollOption.de_json(option, bot) for option in data['options']] + data['explanation_entities'] = MessageEntity.de_list(data.get('explanation_entities'), bot) + data['close_date'] = from_timestamp(data.get('close_date')) + + return cls(**data) + + def to_dict(self) -> JSONDict: + """See :meth:`telegram.TelegramObject.to_dict`.""" + data = super().to_dict() + + data['options'] = [x.to_dict() for x in self.options] + if self.explanation_entities: + data['explanation_entities'] = [e.to_dict() for e in self.explanation_entities] + data['close_date'] = to_timestamp(data.get('close_date')) + + return data + + def parse_explanation_entity(self, entity: MessageEntity) -> str: + """Returns the text from a given :class:`telegram.MessageEntity`. + + Note: + This method is present because Telegram calculates the offset and length in + UTF-16 codepoint pairs, which some versions of Python don't handle automatically. + (That is, you can't just slice ``Message.text`` with the offset and length.) + + Args: + entity (:class:`telegram.MessageEntity`): The entity to extract the text from. It must + be an entity that belongs to this message. + + Returns: + :obj:`str`: The text of the given entity. + + Raises: + RuntimeError: If the poll has no explanation. + + """ + if not self.explanation: + raise RuntimeError("This Poll has no 'explanation'.") + + # Is it a narrow build, if so we don't need to convert + if sys.maxunicode == 0xFFFF: + return self.explanation[entity.offset : entity.offset + entity.length] + entity_text = self.explanation.encode('utf-16-le') + entity_text = entity_text[entity.offset * 2 : (entity.offset + entity.length) * 2] + + return entity_text.decode('utf-16-le') + + def parse_explanation_entities(self, types: List[str] = None) -> Dict[MessageEntity, str]: + """ + Returns a :obj:`dict` that maps :class:`telegram.MessageEntity` to :obj:`str`. + It contains entities from this polls explanation filtered by their ``type`` attribute as + the key, and the text that each entity belongs to as the value of the :obj:`dict`. + + Note: + This method should always be used instead of the :attr:`explanation_entities` + attribute, since it calculates the correct substring from the message text based on + UTF-16 codepoints. See :attr:`parse_explanation_entity` for more info. + + Args: + types (List[:obj:`str`], optional): List of ``MessageEntity`` types as strings. If the + ``type`` attribute of an entity is contained in this list, it will be returned. + Defaults to :attr:`telegram.MessageEntity.ALL_TYPES`. + + Returns: + Dict[:class:`telegram.MessageEntity`, :obj:`str`]: A dictionary of entities mapped to + the text that belongs to them, calculated based on UTF-16 codepoints. + + """ + if types is None: + types = MessageEntity.ALL_TYPES + + return { + entity: self.parse_explanation_entity(entity) + for entity in (self.explanation_entities or []) + if entity.type in types + } + + REGULAR: ClassVar[str] = constants.POLL_REGULAR + """:const:`telegram.constants.POLL_REGULAR`""" + QUIZ: ClassVar[str] = constants.POLL_QUIZ + """:const:`telegram.constants.POLL_QUIZ`""" + MAX_QUESTION_LENGTH: ClassVar[int] = constants.MAX_POLL_QUESTION_LENGTH + """:const:`telegram.constants.MAX_POLL_QUESTION_LENGTH`""" + MAX_OPTION_LENGTH: ClassVar[int] = constants.MAX_POLL_OPTION_LENGTH + """:const:`telegram.constants.MAX_POLL_OPTION_LENGTH`""" diff --git a/venv/lib/python3.8/site-packages/telegram/proximityalerttriggered.py b/venv/lib/python3.8/site-packages/telegram/proximityalerttriggered.py new file mode 100644 index 0000000..507fb77 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/proximityalerttriggered.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram Proximity Alert.""" +from typing import Any, Optional, TYPE_CHECKING + +from telegram import TelegramObject, User +from telegram.utils.types import JSONDict + +if TYPE_CHECKING: + from telegram import Bot + + +class ProximityAlertTriggered(TelegramObject): + """ + This object represents the content of a service message, sent whenever a user in the chat + triggers a proximity alert set by another user. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`traveler`, :attr:`watcher` and :attr:`distance` are equal. + + Args: + traveler (:class:`telegram.User`): User that triggered the alert + watcher (:class:`telegram.User`): User that set the alert + distance (:obj:`int`): The distance between the users + + Attributes: + traveler (:class:`telegram.User`): User that triggered the alert + watcher (:class:`telegram.User`): User that set the alert + distance (:obj:`int`): The distance between the users + + """ + + __slots__ = ('traveler', 'distance', 'watcher', '_id_attrs') + + def __init__(self, traveler: User, watcher: User, distance: int, **_kwargs: Any): + self.traveler = traveler + self.watcher = watcher + self.distance = distance + + self._id_attrs = (self.traveler, self.watcher, self.distance) + + @classmethod + def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['ProximityAlertTriggered']: + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + if not data: + return None + + data['traveler'] = User.de_json(data.get('traveler'), bot) + data['watcher'] = User.de_json(data.get('watcher'), bot) + + return cls(bot=bot, **data) diff --git a/venv/lib/python3.8/site-packages/telegram/py.typed b/venv/lib/python3.8/site-packages/telegram/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.8/site-packages/telegram/replykeyboardmarkup.py b/venv/lib/python3.8/site-packages/telegram/replykeyboardmarkup.py new file mode 100644 index 0000000..490ce33 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/replykeyboardmarkup.py @@ -0,0 +1,251 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram ReplyKeyboardMarkup.""" + +from typing import Any, List, Union, Sequence + +from telegram import KeyboardButton, ReplyMarkup +from telegram.utils.types import JSONDict + + +class ReplyKeyboardMarkup(ReplyMarkup): + """This object represents a custom keyboard with reply options. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their the size of :attr:`keyboard` and all the buttons are equal. + + Example: + A user requests to change the bot's language, bot replies to the request with a keyboard + to select the new language. Other users in the group don't see the keyboard. + + Args: + keyboard (List[List[:obj:`str` | :class:`telegram.KeyboardButton`]]): Array of button rows, + each represented by an Array of :class:`telegram.KeyboardButton` objects. + resize_keyboard (:obj:`bool`, optional): Requests clients to resize the keyboard vertically + for optimal fit (e.g., make the keyboard smaller if there are just two rows of + buttons). Defaults to :obj:`False`, in which case the custom keyboard is always of the + same height as the app's standard keyboard. + one_time_keyboard (:obj:`bool`, optional): Requests clients to hide the keyboard as soon as + it's been used. The keyboard will still be available, but clients will automatically + display the usual letter-keyboard in the chat - the user can press a special button in + the input field to see the custom keyboard again. Defaults to :obj:`False`. + selective (:obj:`bool`, optional): Use this parameter if you want to show the keyboard to + specific users only. Targets: + + 1) Users that are @mentioned in the text of the Message object. + 2) If the bot's message is a reply (has ``reply_to_message_id``), sender of the + original message. + + Defaults to :obj:`False`. + + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + keyboard (List[List[:class:`telegram.KeyboardButton` | :obj:`str`]]): Array of button rows. + resize_keyboard (:obj:`bool`): Optional. Requests clients to resize the keyboard. + one_time_keyboard (:obj:`bool`): Optional. Requests clients to hide the keyboard as soon as + it's been used. + selective (:obj:`bool`): Optional. Show the keyboard to specific users only. + + """ + + __slots__ = ('selective', 'keyboard', 'resize_keyboard', 'one_time_keyboard', '_id_attrs') + + def __init__( + self, + keyboard: Sequence[Sequence[Union[str, KeyboardButton]]], + resize_keyboard: bool = False, + one_time_keyboard: bool = False, + selective: bool = False, + **_kwargs: Any, + ): + # Required + self.keyboard = [] + for row in keyboard: + button_row = [] + for button in row: + if isinstance(button, KeyboardButton): + button_row.append(button) # telegram.KeyboardButton + else: + button_row.append(KeyboardButton(button)) # str + self.keyboard.append(button_row) + + # Optionals + self.resize_keyboard = bool(resize_keyboard) + self.one_time_keyboard = bool(one_time_keyboard) + self.selective = bool(selective) + + self._id_attrs = (self.keyboard,) + + def to_dict(self) -> JSONDict: + """See :meth:`telegram.TelegramObject.to_dict`.""" + data = super().to_dict() + + data['keyboard'] = [] + for row in self.keyboard: + data['keyboard'].append([button.to_dict() for button in row]) + return data + + @classmethod + def from_button( + cls, + button: Union[KeyboardButton, str], + resize_keyboard: bool = False, + one_time_keyboard: bool = False, + selective: bool = False, + **kwargs: object, + ) -> 'ReplyKeyboardMarkup': + """Shortcut for:: + + ReplyKeyboardMarkup([[button]], **kwargs) + + Return a ReplyKeyboardMarkup from a single KeyboardButton. + + Args: + button (:class:`telegram.KeyboardButton` | :obj:`str`): The button to use in + the markup. + resize_keyboard (:obj:`bool`, optional): Requests clients to resize the keyboard + vertically for optimal fit (e.g., make the keyboard smaller if there are just two + rows of buttons). Defaults to :obj:`False`, in which case the custom keyboard is + always of the same height as the app's standard keyboard. + one_time_keyboard (:obj:`bool`, optional): Requests clients to hide the keyboard as + soon as it's been used. The keyboard will still be available, but clients will + automatically display the usual letter-keyboard in the chat - the user can press + a special button in the input field to see the custom keyboard again. + Defaults to :obj:`False`. + selective (:obj:`bool`, optional): Use this parameter if you want to show the keyboard + to specific users only. Targets: + + 1) Users that are @mentioned in the text of the Message object. + 2) If the bot's message is a reply (has reply_to_message_id), sender of the + original message. + + Defaults to :obj:`False`. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + """ + return cls( + [[button]], + resize_keyboard=resize_keyboard, + one_time_keyboard=one_time_keyboard, + selective=selective, + **kwargs, + ) + + @classmethod + def from_row( + cls, + button_row: List[Union[str, KeyboardButton]], + resize_keyboard: bool = False, + one_time_keyboard: bool = False, + selective: bool = False, + **kwargs: object, + ) -> 'ReplyKeyboardMarkup': + """Shortcut for:: + + ReplyKeyboardMarkup([button_row], **kwargs) + + Return a ReplyKeyboardMarkup from a single row of KeyboardButtons. + + Args: + button_row (List[:class:`telegram.KeyboardButton` | :obj:`str`]): The button to use in + the markup. + resize_keyboard (:obj:`bool`, optional): Requests clients to resize the keyboard + vertically for optimal fit (e.g., make the keyboard smaller if there are just two + rows of buttons). Defaults to :obj:`False`, in which case the custom keyboard is + always of the same height as the app's standard keyboard. + one_time_keyboard (:obj:`bool`, optional): Requests clients to hide the keyboard as + soon as it's been used. The keyboard will still be available, but clients will + automatically display the usual letter-keyboard in the chat - the user can press + a special button in the input field to see the custom keyboard again. + Defaults to :obj:`False`. + selective (:obj:`bool`, optional): Use this parameter if you want to show the keyboard + to specific users only. Targets: + + 1) Users that are @mentioned in the text of the Message object. + 2) If the bot's message is a reply (has reply_to_message_id), sender of the + original message. + + Defaults to :obj:`False`. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + """ + return cls( + [button_row], + resize_keyboard=resize_keyboard, + one_time_keyboard=one_time_keyboard, + selective=selective, + **kwargs, + ) + + @classmethod + def from_column( + cls, + button_column: List[Union[str, KeyboardButton]], + resize_keyboard: bool = False, + one_time_keyboard: bool = False, + selective: bool = False, + **kwargs: object, + ) -> 'ReplyKeyboardMarkup': + """Shortcut for:: + + ReplyKeyboardMarkup([[button] for button in button_column], **kwargs) + + Return a ReplyKeyboardMarkup from a single column of KeyboardButtons. + + Args: + button_column (List[:class:`telegram.KeyboardButton` | :obj:`str`]): The button to use + in the markup. + resize_keyboard (:obj:`bool`, optional): Requests clients to resize the keyboard + vertically for optimal fit (e.g., make the keyboard smaller if there are just two + rows of buttons). Defaults to :obj:`False`, in which case the custom keyboard is + always of the same height as the app's standard keyboard. + one_time_keyboard (:obj:`bool`, optional): Requests clients to hide the keyboard as + soon as it's been used. The keyboard will still be available, but clients will + automatically display the usual letter-keyboard in the chat - the user can press + a special button in the input field to see the custom keyboard again. + Defaults to :obj:`False`. + selective (:obj:`bool`, optional): Use this parameter if you want to show the keyboard + to specific users only. Targets: + + 1) Users that are @mentioned in the text of the Message object. + 2) If the bot's message is a reply (has reply_to_message_id), sender of the + original message. + + Defaults to :obj:`False`. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + """ + button_grid = [[button] for button in button_column] + return cls( + button_grid, + resize_keyboard=resize_keyboard, + one_time_keyboard=one_time_keyboard, + selective=selective, + **kwargs, + ) + + def __hash__(self) -> int: + return hash( + ( + tuple(tuple(button for button in row) for row in self.keyboard), + self.resize_keyboard, + self.one_time_keyboard, + self.selective, + ) + ) diff --git a/venv/lib/python3.8/site-packages/telegram/replykeyboardremove.py b/venv/lib/python3.8/site-packages/telegram/replykeyboardremove.py new file mode 100644 index 0000000..5f3c255 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/replykeyboardremove.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram ReplyKeyboardRemove.""" +from typing import Any + +from telegram import ReplyMarkup + + +class ReplyKeyboardRemove(ReplyMarkup): + """ + Upon receiving a message with this object, Telegram clients will remove the current custom + keyboard and display the default letter-keyboard. By default, custom keyboards are displayed + until a new keyboard is sent by a bot. An exception is made for one-time keyboards that are + hidden immediately after the user presses a button (see :class:`telegram.ReplyKeyboardMarkup`). + + Example: + A user votes in a poll, bot returns confirmation message in reply to the vote and removes + the keyboard for that user, while still showing the keyboard with poll options to users who + haven't voted yet. + + Note: + User will not be able to summon this keyboard; if you want to hide the keyboard from + sight but keep it accessible, use :attr:`telegram.ReplyKeyboardMarkup.one_time_keyboard`. + + Args: + selective (:obj:`bool`, optional): Use this parameter if you want to remove the keyboard + for specific users only. Targets: + + 1) Users that are @mentioned in the text of the :class:`telegram.Message` object. + 2) If the bot's message is a reply (has `reply_to_message_id`), sender of the original + message. + + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + remove_keyboard (:obj:`True`): Requests clients to remove the custom keyboard. + selective (:obj:`bool`): Optional. Use this parameter if you want to remove the keyboard + for specific users only. + + """ + + __slots__ = ('selective', 'remove_keyboard') + + def __init__(self, selective: bool = False, **_kwargs: Any): + # Required + self.remove_keyboard = True + # Optionals + self.selective = bool(selective) diff --git a/venv/lib/python3.8/site-packages/telegram/replymarkup.py b/venv/lib/python3.8/site-packages/telegram/replymarkup.py new file mode 100644 index 0000000..4f2c01d --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/replymarkup.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""Base class for Telegram ReplyMarkup Objects.""" + +from telegram import TelegramObject + + +class ReplyMarkup(TelegramObject): + """Base class for Telegram ReplyMarkup Objects. + + See :class:`telegram.InlineKeyboardMarkup`, :class:`telegram.ReplyKeyboardMarkup`, + :class:`telegram.ReplyKeyboardRemove` and :class:`telegram.ForceReply` for + detailed use. + + """ + + __slots__ = () diff --git a/venv/lib/python3.8/site-packages/telegram/update.py b/venv/lib/python3.8/site-packages/telegram/update.py new file mode 100644 index 0000000..b610b35 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/update.py @@ -0,0 +1,388 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram Update.""" + +from typing import TYPE_CHECKING, Any, Optional + +from telegram import ( + CallbackQuery, + ChosenInlineResult, + InlineQuery, + Message, + Poll, + PreCheckoutQuery, + ShippingQuery, + TelegramObject, + ChatMemberUpdated, + constants, +) +from telegram.poll import PollAnswer +from telegram.utils.types import JSONDict + +if TYPE_CHECKING: + from telegram import Bot, Chat, User # noqa + + +class Update(TelegramObject): + """This object represents an incoming update. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`update_id` is equal. + + Note: + At most one of the optional parameters can be present in any given update. + + Args: + update_id (:obj:`int`): The update's unique identifier. Update identifiers start from a + certain positive number and increase sequentially. This ID becomes especially handy if + you're using Webhooks, since it allows you to ignore repeated updates or to restore the + correct update sequence, should they get out of order. If there are no new updates for + at least a week, then identifier of the next update will be chosen randomly instead of + sequentially. + message (:class:`telegram.Message`, optional): New incoming message of any kind - text, + photo, sticker, etc. + edited_message (:class:`telegram.Message`, optional): New version of a message that is + known to the bot and was edited. + channel_post (:class:`telegram.Message`, optional): New incoming channel post of any kind + - text, photo, sticker, etc. + edited_channel_post (:class:`telegram.Message`, optional): New version of a channel post + that is known to the bot and was edited. + inline_query (:class:`telegram.InlineQuery`, optional): New incoming inline query. + chosen_inline_result (:class:`telegram.ChosenInlineResult`, optional): The result of an + inline query that was chosen by a user and sent to their chat partner. + callback_query (:class:`telegram.CallbackQuery`, optional): New incoming callback query. + shipping_query (:class:`telegram.ShippingQuery`, optional): New incoming shipping query. + Only for invoices with flexible price. + pre_checkout_query (:class:`telegram.PreCheckoutQuery`, optional): New incoming + pre-checkout query. Contains full information about checkout. + poll (:class:`telegram.Poll`, optional): New poll state. Bots receive only updates about + stopped polls and polls, which are sent by the bot. + poll_answer (:class:`telegram.PollAnswer`, optional): A user changed their answer + in a non-anonymous poll. Bots receive new votes only in polls that were sent + by the bot itself. + my_chat_member (:class:`telegram.ChatMemberUpdated`, optional): The bot's chat member + status was updated in a chat. For private chats, this update is received only when the + bot is blocked or unblocked by the user. + + .. versionadded:: 13.4 + chat_member (:class:`telegram.ChatMemberUpdated`, optional): A chat member's status was + updated in a chat. The bot must be an administrator in the chat and must explicitly + specify ``'chat_member'`` in the list of ``'allowed_updates'`` to receive these + updates (see :meth:`telegram.Bot.get_updates`, :meth:`telegram.Bot.set_webhook`, + :meth:`telegram.ext.Updater.start_polling` and + :meth:`telegram.ext.Updater.start_webhook`). + + .. versionadded:: 13.4 + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + update_id (:obj:`int`): The update's unique identifier. + message (:class:`telegram.Message`): Optional. New incoming message. + edited_message (:class:`telegram.Message`): Optional. New version of a message. + channel_post (:class:`telegram.Message`): Optional. New incoming channel post. + edited_channel_post (:class:`telegram.Message`): Optional. New version of a channel post. + inline_query (:class:`telegram.InlineQuery`): Optional. New incoming inline query. + chosen_inline_result (:class:`telegram.ChosenInlineResult`): Optional. The result of an + inline query that was chosen by a user. + callback_query (:class:`telegram.CallbackQuery`): Optional. New incoming callback query. + shipping_query (:class:`telegram.ShippingQuery`): Optional. New incoming shipping query. + pre_checkout_query (:class:`telegram.PreCheckoutQuery`): Optional. New incoming + pre-checkout query. + poll (:class:`telegram.Poll`): Optional. New poll state. Bots receive only updates + about stopped polls and polls, which are sent by the bot. + poll_answer (:class:`telegram.PollAnswer`): Optional. A user changed their answer + in a non-anonymous poll. Bots receive new votes only in polls that were sent + by the bot itself. + my_chat_member (:class:`telegram.ChatMemberUpdated`): Optional. The bot's chat member + status was updated in a chat. For private chats, this update is received only when the + bot is blocked or unblocked by the user. + + .. versionadded:: 13.4 + chat_member (:class:`telegram.ChatMemberUpdated`): Optional. A chat member's status was + updated in a chat. The bot must be an administrator in the chat and must explicitly + specify ``'chat_member'`` in the list of ``'allowed_updates'`` to receive these + updates (see :meth:`telegram.Bot.get_updates`, :meth:`telegram.Bot.set_webhook`, + :meth:`telegram.ext.Updater.start_polling` and + :meth:`telegram.ext.Updater.start_webhook`). + + .. versionadded:: 13.4 + + """ + + __slots__ = ( + 'callback_query', + 'chosen_inline_result', + 'pre_checkout_query', + 'inline_query', + 'update_id', + 'message', + 'shipping_query', + 'poll', + 'poll_answer', + 'channel_post', + 'edited_channel_post', + 'edited_message', + '_effective_user', + '_effective_chat', + '_effective_message', + 'my_chat_member', + 'chat_member', + '_id_attrs', + ) + + MESSAGE = constants.UPDATE_MESSAGE + """:const:`telegram.constants.UPDATE_MESSAGE` + + .. versionadded:: 13.5""" + EDITED_MESSAGE = constants.UPDATE_EDITED_MESSAGE + """:const:`telegram.constants.UPDATE_EDITED_MESSAGE` + + .. versionadded:: 13.5""" + CHANNEL_POST = constants.UPDATE_CHANNEL_POST + """:const:`telegram.constants.UPDATE_CHANNEL_POST` + + .. versionadded:: 13.5""" + EDITED_CHANNEL_POST = constants.UPDATE_EDITED_CHANNEL_POST + """:const:`telegram.constants.UPDATE_EDITED_CHANNEL_POST` + + .. versionadded:: 13.5""" + INLINE_QUERY = constants.UPDATE_INLINE_QUERY + """:const:`telegram.constants.UPDATE_INLINE_QUERY` + + .. versionadded:: 13.5""" + CHOSEN_INLINE_RESULT = constants.UPDATE_CHOSEN_INLINE_RESULT + """:const:`telegram.constants.UPDATE_CHOSEN_INLINE_RESULT` + + .. versionadded:: 13.5""" + CALLBACK_QUERY = constants.UPDATE_CALLBACK_QUERY + """:const:`telegram.constants.UPDATE_CALLBACK_QUERY` + + .. versionadded:: 13.5""" + SHIPPING_QUERY = constants.UPDATE_SHIPPING_QUERY + """:const:`telegram.constants.UPDATE_SHIPPING_QUERY` + + .. versionadded:: 13.5""" + PRE_CHECKOUT_QUERY = constants.UPDATE_PRE_CHECKOUT_QUERY + """:const:`telegram.constants.UPDATE_PRE_CHECKOUT_QUERY` + + .. versionadded:: 13.5""" + POLL = constants.UPDATE_POLL + """:const:`telegram.constants.UPDATE_POLL` + + .. versionadded:: 13.5""" + POLL_ANSWER = constants.UPDATE_POLL_ANSWER + """:const:`telegram.constants.UPDATE_POLL_ANSWER` + + .. versionadded:: 13.5""" + MY_CHAT_MEMBER = constants.UPDATE_MY_CHAT_MEMBER + """:const:`telegram.constants.UPDATE_MY_CHAT_MEMBER` + + .. versionadded:: 13.5""" + CHAT_MEMBER = constants.UPDATE_CHAT_MEMBER + """:const:`telegram.constants.UPDATE_CHAT_MEMBER` + + .. versionadded:: 13.5""" + ALL_TYPES = constants.UPDATE_ALL_TYPES + """:const:`telegram.constants.UPDATE_ALL_TYPES` + + .. versionadded:: 13.5""" + + def __init__( + self, + update_id: int, + message: Message = None, + edited_message: Message = None, + channel_post: Message = None, + edited_channel_post: Message = None, + inline_query: InlineQuery = None, + chosen_inline_result: ChosenInlineResult = None, + callback_query: CallbackQuery = None, + shipping_query: ShippingQuery = None, + pre_checkout_query: PreCheckoutQuery = None, + poll: Poll = None, + poll_answer: PollAnswer = None, + my_chat_member: ChatMemberUpdated = None, + chat_member: ChatMemberUpdated = None, + **_kwargs: Any, + ): + # Required + self.update_id = int(update_id) + # Optionals + self.message = message + self.edited_message = edited_message + self.inline_query = inline_query + self.chosen_inline_result = chosen_inline_result + self.callback_query = callback_query + self.shipping_query = shipping_query + self.pre_checkout_query = pre_checkout_query + self.channel_post = channel_post + self.edited_channel_post = edited_channel_post + self.poll = poll + self.poll_answer = poll_answer + self.my_chat_member = my_chat_member + self.chat_member = chat_member + + self._effective_user: Optional['User'] = None + self._effective_chat: Optional['Chat'] = None + self._effective_message: Optional[Message] = None + + self._id_attrs = (self.update_id,) + + @property + def effective_user(self) -> Optional['User']: + """ + :class:`telegram.User`: The user that sent this update, no matter what kind of update this + is. Will be :obj:`None` for :attr:`channel_post` and :attr:`poll`. + + """ + if self._effective_user: + return self._effective_user + + user = None + + if self.message: + user = self.message.from_user + + elif self.edited_message: + user = self.edited_message.from_user + + elif self.inline_query: + user = self.inline_query.from_user + + elif self.chosen_inline_result: + user = self.chosen_inline_result.from_user + + elif self.callback_query: + user = self.callback_query.from_user + + elif self.shipping_query: + user = self.shipping_query.from_user + + elif self.pre_checkout_query: + user = self.pre_checkout_query.from_user + + elif self.poll_answer: + user = self.poll_answer.user + + elif self.my_chat_member: + user = self.my_chat_member.from_user + + elif self.chat_member: + user = self.chat_member.from_user + + self._effective_user = user + return user + + @property + def effective_chat(self) -> Optional['Chat']: + """ + :class:`telegram.Chat`: The chat that this update was sent in, no matter what kind of + update this is. Will be :obj:`None` for :attr:`inline_query`, + :attr:`chosen_inline_result`, :attr:`callback_query` from inline messages, + :attr:`shipping_query`, :attr:`pre_checkout_query`, :attr:`poll` and + :attr:`poll_answer`. + + """ + if self._effective_chat: + return self._effective_chat + + chat = None + + if self.message: + chat = self.message.chat + + elif self.edited_message: + chat = self.edited_message.chat + + elif self.callback_query and self.callback_query.message: + chat = self.callback_query.message.chat + + elif self.channel_post: + chat = self.channel_post.chat + + elif self.edited_channel_post: + chat = self.edited_channel_post.chat + + elif self.my_chat_member: + chat = self.my_chat_member.chat + + elif self.chat_member: + chat = self.chat_member.chat + + self._effective_chat = chat + return chat + + @property + def effective_message(self) -> Optional[Message]: + """ + :class:`telegram.Message`: The message included in this update, no matter what kind of + update this is. Will be :obj:`None` for :attr:`inline_query`, + :attr:`chosen_inline_result`, :attr:`callback_query` from inline messages, + :attr:`shipping_query`, :attr:`pre_checkout_query`, :attr:`poll` and + :attr:`poll_answer`. + + """ + if self._effective_message: + return self._effective_message + + message = None + + if self.message: + message = self.message + + elif self.edited_message: + message = self.edited_message + + elif self.callback_query: + message = self.callback_query.message + + elif self.channel_post: + message = self.channel_post + + elif self.edited_channel_post: + message = self.edited_channel_post + + self._effective_message = message + return message + + @classmethod + def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Update']: + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + if not data: + return None + + data['message'] = Message.de_json(data.get('message'), bot) + data['edited_message'] = Message.de_json(data.get('edited_message'), bot) + data['inline_query'] = InlineQuery.de_json(data.get('inline_query'), bot) + data['chosen_inline_result'] = ChosenInlineResult.de_json( + data.get('chosen_inline_result'), bot + ) + data['callback_query'] = CallbackQuery.de_json(data.get('callback_query'), bot) + data['shipping_query'] = ShippingQuery.de_json(data.get('shipping_query'), bot) + data['pre_checkout_query'] = PreCheckoutQuery.de_json(data.get('pre_checkout_query'), bot) + data['channel_post'] = Message.de_json(data.get('channel_post'), bot) + data['edited_channel_post'] = Message.de_json(data.get('edited_channel_post'), bot) + data['poll'] = Poll.de_json(data.get('poll'), bot) + data['poll_answer'] = PollAnswer.de_json(data.get('poll_answer'), bot) + data['my_chat_member'] = ChatMemberUpdated.de_json(data.get('my_chat_member'), bot) + data['chat_member'] = ChatMemberUpdated.de_json(data.get('chat_member'), bot) + + return cls(**data) diff --git a/venv/lib/python3.8/site-packages/telegram/user.py b/venv/lib/python3.8/site-packages/telegram/user.py new file mode 100644 index 0000000..ecb4a3c --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/user.py @@ -0,0 +1,1142 @@ +#!/usr/bin/env python +# pylint: disable=W0622 +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram User.""" +from datetime import datetime +from typing import TYPE_CHECKING, Any, List, Optional, Union, Tuple + +from telegram import TelegramObject, constants +from telegram.utils.helpers import ( + mention_html as util_mention_html, + DEFAULT_NONE, + DEFAULT_20, +) +from telegram.utils.helpers import mention_markdown as util_mention_markdown +from telegram.utils.types import JSONDict, FileInput, ODVInput, DVInput + +if TYPE_CHECKING: + from telegram import ( + Bot, + Message, + UserProfilePhotos, + MessageId, + InputMediaAudio, + InputMediaDocument, + InputMediaPhoto, + InputMediaVideo, + MessageEntity, + ReplyMarkup, + PhotoSize, + Audio, + Contact, + Document, + InlineKeyboardMarkup, + LabeledPrice, + Location, + Animation, + Sticker, + Video, + Venue, + VideoNote, + Voice, + ) + + +class User(TelegramObject): + """This object represents a Telegram user or bot. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`id` is equal. + + Args: + id (:obj:`int`): Unique identifier for this user or bot. + is_bot (:obj:`bool`): :obj:`True`, if this user is a bot. + first_name (:obj:`str`): User's or bots first name. + last_name (:obj:`str`, optional): User's or bots last name. + username (:obj:`str`, optional): User's or bots username. + language_code (:obj:`str`, optional): IETF language tag of the user's language. + can_join_groups (:obj:`str`, optional): :obj:`True`, if the bot can be invited to groups. + Returned only in :attr:`telegram.Bot.get_me` requests. + can_read_all_group_messages (:obj:`str`, optional): :obj:`True`, if privacy mode is + disabled for the bot. Returned only in :attr:`telegram.Bot.get_me` requests. + supports_inline_queries (:obj:`str`, optional): :obj:`True`, if the bot supports inline + queries. Returned only in :attr:`telegram.Bot.get_me` requests. + bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods. + + Attributes: + id (:obj:`int`): Unique identifier for this user or bot. + is_bot (:obj:`bool`): :obj:`True`, if this user is a bot. + first_name (:obj:`str`): User's or bot's first name. + last_name (:obj:`str`): Optional. User's or bot's last name. + username (:obj:`str`): Optional. User's or bot's username. + language_code (:obj:`str`): Optional. IETF language tag of the user's language. + can_join_groups (:obj:`str`): Optional. :obj:`True`, if the bot can be invited to groups. + Returned only in :attr:`telegram.Bot.get_me` requests. + can_read_all_group_messages (:obj:`str`): Optional. :obj:`True`, if privacy mode is + disabled for the bot. Returned only in :attr:`telegram.Bot.get_me` requests. + supports_inline_queries (:obj:`str`): Optional. :obj:`True`, if the bot supports inline + queries. Returned only in :attr:`telegram.Bot.get_me` requests. + bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods. + + """ + + __slots__ = ( + 'is_bot', + 'can_read_all_group_messages', + 'username', + 'first_name', + 'last_name', + 'can_join_groups', + 'supports_inline_queries', + 'id', + 'bot', + 'language_code', + '_id_attrs', + ) + + def __init__( + self, + id: int, + first_name: str, + is_bot: bool, + last_name: str = None, + username: str = None, + language_code: str = None, + can_join_groups: bool = None, + can_read_all_group_messages: bool = None, + supports_inline_queries: bool = None, + bot: 'Bot' = None, + **_kwargs: Any, + ): + # Required + self.id = int(id) # pylint: disable=C0103 + self.first_name = first_name + self.is_bot = is_bot + # Optionals + self.last_name = last_name + self.username = username + self.language_code = language_code + self.can_join_groups = can_join_groups + self.can_read_all_group_messages = can_read_all_group_messages + self.supports_inline_queries = supports_inline_queries + self.bot = bot + + self._id_attrs = (self.id,) + + @property + def name(self) -> str: + """:obj:`str`: Convenience property. If available, returns the user's :attr:`username` + prefixed with "@". If :attr:`username` is not available, returns :attr:`full_name`. + """ + if self.username: + return f'@{self.username}' + return self.full_name + + @property + def full_name(self) -> str: + """:obj:`str`: Convenience property. The user's :attr:`first_name`, followed by (if + available) :attr:`last_name`. + """ + if self.last_name: + return f'{self.first_name} {self.last_name}' + return self.first_name + + @property + def link(self) -> Optional[str]: + """:obj:`str`: Convenience property. If :attr:`username` is available, returns a t.me link + of the user. + """ + if self.username: + return f"https://t.me/{self.username}" + return None + + def get_profile_photos( + self, + offset: int = None, + limit: int = 100, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> Optional['UserProfilePhotos']: + """ + Shortcut for:: + + bot.get_user_profile_photos(update.effective_user.id, *args, **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Bot.get_user_profile_photos`. + + """ + return self.bot.get_user_profile_photos( + user_id=self.id, + offset=offset, + limit=limit, + timeout=timeout, + api_kwargs=api_kwargs, + ) + + def mention_markdown(self, name: str = None) -> str: + """ + Note: + :attr:`telegram.ParseMode.MARKDOWN` is is a legacy mode, retained by Telegram for + backward compatibility. You should use :meth:`mention_markdown_v2` instead. + + Args: + name (:obj:`str`): The name used as a link for the user. Defaults to :attr:`full_name`. + + Returns: + :obj:`str`: The inline mention for the user as markdown (version 1). + + """ + if name: + return util_mention_markdown(self.id, name) + return util_mention_markdown(self.id, self.full_name) + + def mention_markdown_v2(self, name: str = None) -> str: + """ + Args: + name (:obj:`str`): The name used as a link for the user. Defaults to :attr:`full_name`. + + Returns: + :obj:`str`: The inline mention for the user as markdown (version 2). + + """ + if name: + return util_mention_markdown(self.id, name, version=2) + return util_mention_markdown(self.id, self.full_name, version=2) + + def mention_html(self, name: str = None) -> str: + """ + Args: + name (:obj:`str`): The name used as a link for the user. Defaults to :attr:`full_name`. + + Returns: + :obj:`str`: The inline mention for the user as HTML. + + """ + if name: + return util_mention_html(self.id, name) + return util_mention_html(self.id, self.full_name) + + def pin_message( + self, + message_id: int, + disable_notification: ODVInput[bool] = DEFAULT_NONE, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> bool: + """Shortcut for:: + + bot.pin_chat_message(chat_id=update.effective_user.id, + *args, + **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.pin_chat_message`. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + + """ + return self.bot.pin_chat_message( + chat_id=self.id, + message_id=message_id, + disable_notification=disable_notification, + timeout=timeout, + api_kwargs=api_kwargs, + ) + + def unpin_message( + self, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + message_id: int = None, + ) -> bool: + """Shortcut for:: + + bot.unpin_chat_message(chat_id=update.effective_user.id, + *args, + **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.unpin_chat_message`. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + + """ + return self.bot.unpin_chat_message( + chat_id=self.id, + timeout=timeout, + api_kwargs=api_kwargs, + message_id=message_id, + ) + + def unpin_all_messages( + self, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> bool: + """Shortcut for:: + + bot.unpin_all_chat_messages(chat_id=update.effective_user.id, + *args, + **kwargs) + + For the documentation of the arguments, please see + :meth:`telegram.Bot.unpin_all_chat_messages`. + + Returns: + :obj:`bool`: On success, :obj:`True` is returned. + + """ + return self.bot.unpin_all_chat_messages( + chat_id=self.id, + timeout=timeout, + api_kwargs=api_kwargs, + ) + + def send_message( + self, + text: str, + parse_mode: ODVInput[str] = DEFAULT_NONE, + disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: 'ReplyMarkup' = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + ) -> 'Message': + """Shortcut for:: + + bot.send_message(update.effective_user.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_message`. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + return self.bot.send_message( + chat_id=self.id, + text=text, + parse_mode=parse_mode, + disable_web_page_preview=disable_web_page_preview, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + entities=entities, + ) + + def send_photo( + self, + photo: Union[FileInput, 'PhotoSize'], + caption: str = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: 'ReplyMarkup' = None, + timeout: DVInput[float] = DEFAULT_20, + parse_mode: ODVInput[str] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + filename: str = None, + ) -> 'Message': + """Shortcut for:: + + bot.send_message(update.effective_user.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_photo`. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + return self.bot.send_photo( + chat_id=self.id, + photo=photo, + caption=caption, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + parse_mode=parse_mode, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + caption_entities=caption_entities, + filename=filename, + ) + + def send_media_group( + self, + media: List[ + Union['InputMediaAudio', 'InputMediaDocument', 'InputMediaPhoto', 'InputMediaVideo'] + ], + disable_notification: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + timeout: DVInput[float] = DEFAULT_20, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + ) -> List['Message']: + """Shortcut for:: + + bot.send_message(update.effective_user.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_media_group`. + + Returns: + List[:class:`telegram.Message`:] On success, instance representing the message posted. + + """ + return self.bot.send_media_group( + chat_id=self.id, + media=media, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + timeout=timeout, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + ) + + def send_audio( + self, + audio: Union[FileInput, 'Audio'], + duration: int = None, + performer: str = None, + title: str = None, + caption: str = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: 'ReplyMarkup' = None, + timeout: DVInput[float] = DEFAULT_20, + parse_mode: ODVInput[str] = DEFAULT_NONE, + thumb: FileInput = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + filename: str = None, + ) -> 'Message': + """Shortcut for:: + + bot.send_message(update.effective_user.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_audio`. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + return self.bot.send_audio( + chat_id=self.id, + audio=audio, + duration=duration, + performer=performer, + title=title, + caption=caption, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + parse_mode=parse_mode, + thumb=thumb, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + caption_entities=caption_entities, + filename=filename, + ) + + def send_chat_action( + self, + action: str, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> bool: + """Shortcut for:: + + bot.send_message(update.effective_user.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_chat_action`. + + Returns: + :obj:`True`: On success. + + """ + return self.bot.send_chat_action( + chat_id=self.id, + action=action, + timeout=timeout, + api_kwargs=api_kwargs, + ) + + send_action = send_chat_action + """Alias for :attr:`send_chat_action`""" + + def send_contact( + self, + phone_number: str = None, + first_name: str = None, + last_name: str = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: 'ReplyMarkup' = None, + timeout: ODVInput[float] = DEFAULT_NONE, + contact: 'Contact' = None, + vcard: str = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + ) -> 'Message': + """Shortcut for:: + + bot.send_message(update.effective_user.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_contact`. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + return self.bot.send_contact( + chat_id=self.id, + phone_number=phone_number, + first_name=first_name, + last_name=last_name, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + contact=contact, + vcard=vcard, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + ) + + def send_dice( + self, + disable_notification: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: 'ReplyMarkup' = None, + timeout: ODVInput[float] = DEFAULT_NONE, + emoji: str = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + ) -> 'Message': + """Shortcut for:: + + bot.send_message(update.effective_user.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_dice`. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + return self.bot.send_dice( + chat_id=self.id, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + emoji=emoji, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + ) + + def send_document( + self, + document: Union[FileInput, 'Document'], + filename: str = None, + caption: str = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: 'ReplyMarkup' = None, + timeout: DVInput[float] = DEFAULT_20, + parse_mode: ODVInput[str] = DEFAULT_NONE, + thumb: FileInput = None, + api_kwargs: JSONDict = None, + disable_content_type_detection: bool = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + ) -> 'Message': + """Shortcut for:: + + bot.send_message(update.effective_user.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_document`. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + return self.bot.send_document( + chat_id=self.id, + document=document, + filename=filename, + caption=caption, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + parse_mode=parse_mode, + thumb=thumb, + api_kwargs=api_kwargs, + disable_content_type_detection=disable_content_type_detection, + allow_sending_without_reply=allow_sending_without_reply, + caption_entities=caption_entities, + ) + + def send_game( + self, + game_short_name: str, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: 'InlineKeyboardMarkup' = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + ) -> 'Message': + """Shortcut for:: + + bot.send_message(update.effective_user.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_game`. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + return self.bot.send_game( + chat_id=self.id, + game_short_name=game_short_name, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + ) + + def send_invoice( + self, + title: str, + description: str, + payload: str, + provider_token: str, + currency: str, + prices: List['LabeledPrice'], + start_parameter: str = None, + photo_url: str = None, + photo_size: int = None, + photo_width: int = None, + photo_height: int = None, + need_name: bool = None, + need_phone_number: bool = None, + need_email: bool = None, + need_shipping_address: bool = None, + is_flexible: bool = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: 'InlineKeyboardMarkup' = None, + provider_data: Union[str, object] = None, + send_phone_number_to_provider: bool = None, + send_email_to_provider: bool = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + max_tip_amount: int = None, + suggested_tip_amounts: List[int] = None, + ) -> 'Message': + """Shortcut for:: + + bot.send_message(update.effective_user.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_invoice`. + + Warning: + As of API 5.2 :attr:`start_parameter` is an optional argument and therefore the order + of the arguments had to be changed. Use keyword arguments to make sure that the + arguments are passed correctly. + + .. versionchanged:: 13.5 + As of Bot API 5.2, the parameter :attr:`start_parameter` is optional. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + return self.bot.send_invoice( + chat_id=self.id, + title=title, + description=description, + payload=payload, + provider_token=provider_token, + currency=currency, + prices=prices, + start_parameter=start_parameter, + photo_url=photo_url, + photo_size=photo_size, + photo_width=photo_width, + photo_height=photo_height, + need_name=need_name, + need_phone_number=need_phone_number, + need_email=need_email, + need_shipping_address=need_shipping_address, + is_flexible=is_flexible, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + provider_data=provider_data, + send_phone_number_to_provider=send_phone_number_to_provider, + send_email_to_provider=send_email_to_provider, + timeout=timeout, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + max_tip_amount=max_tip_amount, + suggested_tip_amounts=suggested_tip_amounts, + ) + + def send_location( + self, + latitude: float = None, + longitude: float = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: 'ReplyMarkup' = None, + timeout: ODVInput[float] = DEFAULT_NONE, + location: 'Location' = None, + live_period: int = None, + api_kwargs: JSONDict = None, + horizontal_accuracy: float = None, + heading: int = None, + proximity_alert_radius: int = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + ) -> 'Message': + """Shortcut for:: + + bot.send_message(update.effective_user.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_location`. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + return self.bot.send_location( + chat_id=self.id, + latitude=latitude, + longitude=longitude, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + location=location, + live_period=live_period, + api_kwargs=api_kwargs, + horizontal_accuracy=horizontal_accuracy, + heading=heading, + proximity_alert_radius=proximity_alert_radius, + allow_sending_without_reply=allow_sending_without_reply, + ) + + def send_animation( + self, + animation: Union[FileInput, 'Animation'], + duration: int = None, + width: int = None, + height: int = None, + thumb: FileInput = None, + caption: str = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: 'ReplyMarkup' = None, + timeout: DVInput[float] = DEFAULT_20, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + filename: str = None, + ) -> 'Message': + """Shortcut for:: + + bot.send_message(update.effective_user.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_animation`. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + return self.bot.send_animation( + chat_id=self.id, + animation=animation, + duration=duration, + width=width, + height=height, + thumb=thumb, + caption=caption, + parse_mode=parse_mode, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + caption_entities=caption_entities, + filename=filename, + ) + + def send_sticker( + self, + sticker: Union[FileInput, 'Sticker'], + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: 'ReplyMarkup' = None, + timeout: DVInput[float] = DEFAULT_20, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + ) -> 'Message': + """Shortcut for:: + + bot.send_message(update.effective_user.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_sticker`. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + return self.bot.send_sticker( + chat_id=self.id, + sticker=sticker, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + ) + + def send_video( + self, + video: Union[FileInput, 'Video'], + duration: int = None, + caption: str = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: 'ReplyMarkup' = None, + timeout: DVInput[float] = DEFAULT_20, + width: int = None, + height: int = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + supports_streaming: bool = None, + thumb: FileInput = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + filename: str = None, + ) -> 'Message': + """Shortcut for:: + + bot.send_message(update.effective_user.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_video`. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + return self.bot.send_video( + chat_id=self.id, + video=video, + duration=duration, + caption=caption, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + width=width, + height=height, + parse_mode=parse_mode, + supports_streaming=supports_streaming, + thumb=thumb, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + caption_entities=caption_entities, + filename=filename, + ) + + def send_venue( + self, + latitude: float = None, + longitude: float = None, + title: str = None, + address: str = None, + foursquare_id: str = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: 'ReplyMarkup' = None, + timeout: ODVInput[float] = DEFAULT_NONE, + venue: 'Venue' = None, + foursquare_type: str = None, + api_kwargs: JSONDict = None, + google_place_id: str = None, + google_place_type: str = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + ) -> 'Message': + """Shortcut for:: + + bot.send_message(update.effective_user.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_venue`. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + return self.bot.send_venue( + chat_id=self.id, + latitude=latitude, + longitude=longitude, + title=title, + address=address, + foursquare_id=foursquare_id, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + venue=venue, + foursquare_type=foursquare_type, + api_kwargs=api_kwargs, + google_place_id=google_place_id, + google_place_type=google_place_type, + allow_sending_without_reply=allow_sending_without_reply, + ) + + def send_video_note( + self, + video_note: Union[FileInput, 'VideoNote'], + duration: int = None, + length: int = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: 'ReplyMarkup' = None, + timeout: DVInput[float] = DEFAULT_20, + thumb: FileInput = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + filename: str = None, + ) -> 'Message': + """Shortcut for:: + + bot.send_message(update.effective_user.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_video_note`. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + return self.bot.send_video_note( + chat_id=self.id, + video_note=video_note, + duration=duration, + length=length, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + thumb=thumb, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + filename=filename, + ) + + def send_voice( + self, + voice: Union[FileInput, 'Voice'], + duration: int = None, + caption: str = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: 'ReplyMarkup' = None, + timeout: DVInput[float] = DEFAULT_20, + parse_mode: ODVInput[str] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + filename: str = None, + ) -> 'Message': + """Shortcut for:: + + bot.send_message(update.effective_user.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_voice`. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + return self.bot.send_voice( + chat_id=self.id, + voice=voice, + duration=duration, + caption=caption, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + parse_mode=parse_mode, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + caption_entities=caption_entities, + filename=filename, + ) + + def send_poll( + self, + question: str, + options: List[str], + is_anonymous: bool = True, + # We use constant.POLL_REGULAR instead of Poll.REGULAR here to avoid circular imports + type: str = constants.POLL_REGULAR, # pylint: disable=W0622 + allows_multiple_answers: bool = False, + correct_option_id: int = None, + is_closed: bool = None, + disable_notification: ODVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + reply_markup: 'ReplyMarkup' = None, + timeout: ODVInput[float] = DEFAULT_NONE, + explanation: str = None, + explanation_parse_mode: ODVInput[str] = DEFAULT_NONE, + open_period: int = None, + close_date: Union[int, datetime] = None, + api_kwargs: JSONDict = None, + allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, + explanation_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, + ) -> 'Message': + """Shortcut for:: + + bot.send_message(update.effective_user.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.send_poll`. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + return self.bot.send_poll( + chat_id=self.id, + question=question, + options=options, + is_anonymous=is_anonymous, + type=type, # pylint=pylint, + allows_multiple_answers=allows_multiple_answers, + correct_option_id=correct_option_id, + is_closed=is_closed, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + reply_markup=reply_markup, + timeout=timeout, + explanation=explanation, + explanation_parse_mode=explanation_parse_mode, + open_period=open_period, + close_date=close_date, + api_kwargs=api_kwargs, + allow_sending_without_reply=allow_sending_without_reply, + explanation_entities=explanation_entities, + ) + + def send_copy( + self, + from_chat_id: Union[str, int], + message_id: int, + caption: str = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + caption_entities: Union[Tuple['MessageEntity', ...], List['MessageEntity']] = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE, + reply_markup: 'ReplyMarkup' = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> 'MessageId': + """Shortcut for:: + + bot.copy_message(chat_id=update.effective_user.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.copy_message`. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + return self.bot.copy_message( + chat_id=self.id, + from_chat_id=from_chat_id, + message_id=message_id, + caption=caption, + parse_mode=parse_mode, + caption_entities=caption_entities, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + allow_sending_without_reply=allow_sending_without_reply, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + ) + + def copy_message( + self, + chat_id: Union[int, str], + message_id: int, + caption: str = None, + parse_mode: ODVInput[str] = DEFAULT_NONE, + caption_entities: Union[Tuple['MessageEntity', ...], List['MessageEntity']] = None, + disable_notification: DVInput[bool] = DEFAULT_NONE, + reply_to_message_id: int = None, + allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE, + reply_markup: 'ReplyMarkup' = None, + timeout: ODVInput[float] = DEFAULT_NONE, + api_kwargs: JSONDict = None, + ) -> 'MessageId': + """Shortcut for:: + + bot.copy_message(from_chat_id=update.effective_user.id, *args, **kwargs) + + For the documentation of the arguments, please see :meth:`telegram.Bot.copy_message`. + + Returns: + :class:`telegram.Message`: On success, instance representing the message posted. + + """ + return self.bot.copy_message( + from_chat_id=self.id, + chat_id=chat_id, + message_id=message_id, + caption=caption, + parse_mode=parse_mode, + caption_entities=caption_entities, + disable_notification=disable_notification, + reply_to_message_id=reply_to_message_id, + allow_sending_without_reply=allow_sending_without_reply, + reply_markup=reply_markup, + timeout=timeout, + api_kwargs=api_kwargs, + ) diff --git a/venv/lib/python3.8/site-packages/telegram/userprofilephotos.py b/venv/lib/python3.8/site-packages/telegram/userprofilephotos.py new file mode 100644 index 0000000..bd277bf --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/userprofilephotos.py @@ -0,0 +1,79 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram UserProfilePhotos.""" + +from typing import TYPE_CHECKING, Any, List, Optional + +from telegram import PhotoSize, TelegramObject +from telegram.utils.types import JSONDict + +if TYPE_CHECKING: + from telegram import Bot + + +class UserProfilePhotos(TelegramObject): + """This object represent a user's profile pictures. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`total_count` and :attr:`photos` are equal. + + Args: + total_count (:obj:`int`): Total number of profile pictures the target user has. + photos (List[List[:class:`telegram.PhotoSize`]]): Requested profile pictures (in up to 4 + sizes each). + + Attributes: + total_count (:obj:`int`): Total number of profile pictures. + photos (List[List[:class:`telegram.PhotoSize`]]): Requested profile pictures. + + """ + + __slots__ = ('photos', 'total_count', '_id_attrs') + + def __init__(self, total_count: int, photos: List[List[PhotoSize]], **_kwargs: Any): + # Required + self.total_count = int(total_count) + self.photos = photos + + self._id_attrs = (self.total_count, self.photos) + + @classmethod + def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['UserProfilePhotos']: + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + if not data: + return None + + data['photos'] = [PhotoSize.de_list(photo, bot) for photo in data['photos']] + + return cls(**data) + + def to_dict(self) -> JSONDict: + """See :meth:`telegram.TelegramObject.to_dict`.""" + data = super().to_dict() + + data['photos'] = [] + for photo in self.photos: + data['photos'].append([x.to_dict() for x in photo]) + + return data + + def __hash__(self) -> int: + return hash(tuple(tuple(p for p in photo) for photo in self.photos)) diff --git a/venv/lib/python3.8/site-packages/telegram/utils/__init__.py b/venv/lib/python3.8/site-packages/telegram/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.8/site-packages/telegram/utils/deprecate.py b/venv/lib/python3.8/site-packages/telegram/utils/deprecate.py new file mode 100644 index 0000000..fbf6042 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/utils/deprecate.py @@ -0,0 +1,45 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module facilitates the deprecation of functions.""" + +import warnings + + +# We use our own DeprecationWarning since they are muted by default and "UserWarning" makes it +# seem like it's the user that issued the warning +# We name it something else so that you don't get confused when you attempt to suppress it +class TelegramDeprecationWarning(Warning): + """Custom warning class for deprecations in this library.""" + + __slots__ = () + + +# Function to warn users that setting custom attributes is deprecated (Use only in __setattr__!) +# Checks if a custom attribute is added by checking length of dictionary before & after +# assigning attribute. This is the fastest way to do it (I hope!). +def set_new_attribute_deprecated(self: object, key: str, value: object) -> None: + """Warns the user if they set custom attributes on PTB objects.""" + org = len(self.__dict__) + object.__setattr__(self, key, value) + new = len(self.__dict__) + if new > org: + warnings.warn( + "Setting custom attributes on objects of the PTB library is deprecated.", + TelegramDeprecationWarning, + ) diff --git a/venv/lib/python3.8/site-packages/telegram/utils/helpers.py b/venv/lib/python3.8/site-packages/telegram/utils/helpers.py new file mode 100644 index 0000000..6705cc9 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/utils/helpers.py @@ -0,0 +1,596 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains helper functions.""" + +import datetime as dtm # dtm = "DateTime Module" +import re +import signal +import time + +from collections import defaultdict +from html import escape +from pathlib import Path + +from typing import ( + TYPE_CHECKING, + Any, + DefaultDict, + Dict, + Optional, + Tuple, + Union, + Type, + cast, + IO, + TypeVar, + Generic, + overload, +) + +from telegram.utils.types import JSONDict, FileInput + +if TYPE_CHECKING: + from telegram import Message, Update, TelegramObject, InputFile + +# in PTB-Raw we don't have pytz, so we make a little workaround here +DTM_UTC = dtm.timezone.utc +try: + import pytz + + UTC = pytz.utc +except ImportError: + UTC = DTM_UTC # type: ignore[assignment] + +try: + import ujson as json +except ImportError: + import json # type: ignore[no-redef] + + +# From https://stackoverflow.com/questions/2549939/get-signal-names-from-numbers-in-python +_signames = { + v: k + for k, v in reversed(sorted(vars(signal).items())) + if k.startswith('SIG') and not k.startswith('SIG_') +} + + +def get_signal_name(signum: int) -> str: + """Returns the signal name of the given signal number.""" + return _signames[signum] + + +def is_local_file(obj: Optional[Union[str, Path]]) -> bool: + """ + Checks if a given string is a file on local system. + + Args: + obj (:obj:`str`): The string to check. + """ + if obj is None: + return False + + path = Path(obj) + try: + return path.is_file() + except Exception: + return False + + +def parse_file_input( + file_input: Union[FileInput, 'TelegramObject'], + tg_type: Type['TelegramObject'] = None, + attach: bool = None, + filename: str = None, +) -> Union[str, 'InputFile', Any]: + """ + Parses input for sending files: + + * For string input, if the input is an absolute path of a local file, + adds the ``file://`` prefix. If the input is a relative path of a local file, computes the + absolute path and adds the ``file://`` prefix. Returns the input unchanged, otherwise. + * :class:`pathlib.Path` objects are treated the same way as strings. + * For IO and bytes input, returns an :class:`telegram.InputFile`. + * If :attr:`tg_type` is specified and the input is of that type, returns the ``file_id`` + attribute. + + Args: + file_input (:obj:`str` | :obj:`bytes` | `filelike object` | Telegram media object): The + input to parse. + tg_type (:obj:`type`, optional): The Telegram media type the input can be. E.g. + :class:`telegram.Animation`. + attach (:obj:`bool`, optional): Whether this file should be send as one file or is part of + a collection of files. Only relevant in case an :class:`telegram.InputFile` is + returned. + filename (:obj:`str`, optional): The filename. Only relevant in case an + :class:`telegram.InputFile` is returned. + + Returns: + :obj:`str` | :class:`telegram.InputFile` | :obj:`object`: The parsed input or the untouched + :attr:`file_input`, in case it's no valid file input. + """ + # Importing on file-level yields cyclic Import Errors + from telegram import InputFile # pylint: disable=C0415 + + if isinstance(file_input, str) and file_input.startswith('file://'): + return file_input + if isinstance(file_input, (str, Path)): + if is_local_file(file_input): + out = Path(file_input).absolute().as_uri() + else: + out = file_input # type: ignore[assignment] + return out + if isinstance(file_input, bytes): + return InputFile(file_input, attach=attach, filename=filename) + if InputFile.is_file(file_input): + file_input = cast(IO, file_input) + return InputFile(file_input, attach=attach, filename=filename) + if tg_type and isinstance(file_input, tg_type): + return file_input.file_id # type: ignore[attr-defined] + return file_input + + +def escape_markdown(text: str, version: int = 1, entity_type: str = None) -> str: + """ + Helper function to escape telegram markup symbols. + + Args: + text (:obj:`str`): The text. + version (:obj:`int` | :obj:`str`): Use to specify the version of telegrams Markdown. + Either ``1`` or ``2``. Defaults to ``1``. + entity_type (:obj:`str`, optional): For the entity types ``PRE``, ``CODE`` and the link + part of ``TEXT_LINKS``, only certain characters need to be escaped in ``MarkdownV2``. + See the official API documentation for details. Only valid in combination with + ``version=2``, will be ignored else. + """ + if int(version) == 1: + escape_chars = r'_*`[' + elif int(version) == 2: + if entity_type in ['pre', 'code']: + escape_chars = r'\`' + elif entity_type == 'text_link': + escape_chars = r'\)' + else: + escape_chars = r'_*[]()~`>#+-=|{}.!' + else: + raise ValueError('Markdown version must be either 1 or 2!') + + return re.sub(f'([{re.escape(escape_chars)}])', r'\\\1', text) + + +# -------- date/time related helpers -------- +def _datetime_to_float_timestamp(dt_obj: dtm.datetime) -> float: + """ + Converts a datetime object to a float timestamp (with sub-second precision). + If the datetime object is timezone-naive, it is assumed to be in UTC. + """ + if dt_obj.tzinfo is None: + dt_obj = dt_obj.replace(tzinfo=dtm.timezone.utc) + return dt_obj.timestamp() + + +def _localize(datetime: dtm.datetime, tzinfo: dtm.tzinfo) -> dtm.datetime: + """Localize the datetime, where UTC is handled depending on whether pytz is available or not""" + if tzinfo is DTM_UTC: + return datetime.replace(tzinfo=DTM_UTC) + return tzinfo.localize(datetime) # type: ignore[attr-defined] + + +def to_float_timestamp( + time_object: Union[int, float, dtm.timedelta, dtm.datetime, dtm.time], + reference_timestamp: float = None, + tzinfo: dtm.tzinfo = None, +) -> float: + """ + Converts a given time object to a float POSIX timestamp. + Used to convert different time specifications to a common format. The time object + can be relative (i.e. indicate a time increment, or a time of day) or absolute. + object objects from the :class:`datetime` module that are timezone-naive will be assumed + to be in UTC, if ``bot`` is not passed or ``bot.defaults`` is :obj:`None`. + + Args: + time_object (:obj:`int` | :obj:`float` | :obj:`datetime.timedelta` | \ + :obj:`datetime.datetime` | :obj:`datetime.time`): + Time value to convert. The semantics of this parameter will depend on its type: + + * :obj:`int` or :obj:`float` will be interpreted as "seconds from ``reference_t``" + * :obj:`datetime.timedelta` will be interpreted as + "time increment from ``reference_t``" + * :obj:`datetime.datetime` will be interpreted as an absolute date/time value + * :obj:`datetime.time` will be interpreted as a specific time of day + + reference_timestamp (:obj:`float`, optional): POSIX timestamp that indicates the absolute + time from which relative calculations are to be performed (e.g. when ``t`` is given as + an :obj:`int`, indicating "seconds from ``reference_t``"). Defaults to now (the time at + which this function is called). + + If ``t`` is given as an absolute representation of date & time (i.e. a + :obj:`datetime.datetime` object), ``reference_timestamp`` is not relevant and so its + value should be :obj:`None`. If this is not the case, a ``ValueError`` will be raised. + tzinfo (:obj:`pytz.BaseTzInfo`, optional): If ``t`` is a naive object from the + :class:`datetime` module, it will be interpreted as this timezone. Defaults to + ``pytz.utc``. + + Note: + Only to be used by ``telegram.ext``. + + + Returns: + :obj:`float` | :obj:`None`: + The return value depends on the type of argument ``t``. + If ``t`` is given as a time increment (i.e. as a :obj:`int`, :obj:`float` or + :obj:`datetime.timedelta`), then the return value will be ``reference_t`` + ``t``. + + Else if it is given as an absolute date/time value (i.e. a :obj:`datetime.datetime` + object), the equivalent value as a POSIX timestamp will be returned. + + Finally, if it is a time of the day without date (i.e. a :obj:`datetime.time` + object), the return value is the nearest future occurrence of that time of day. + + Raises: + TypeError: If ``t``'s type is not one of those described above. + ValueError: If ``t`` is a :obj:`datetime.datetime` and :obj:`reference_timestamp` is not + :obj:`None`. + """ + if reference_timestamp is None: + reference_timestamp = time.time() + elif isinstance(time_object, dtm.datetime): + raise ValueError('t is an (absolute) datetime while reference_timestamp is not None') + + if isinstance(time_object, dtm.timedelta): + return reference_timestamp + time_object.total_seconds() + if isinstance(time_object, (int, float)): + return reference_timestamp + time_object + + if tzinfo is None: + tzinfo = UTC + + if isinstance(time_object, dtm.time): + reference_dt = dtm.datetime.fromtimestamp( + reference_timestamp, tz=time_object.tzinfo or tzinfo + ) + reference_date = reference_dt.date() + reference_time = reference_dt.timetz() + + aware_datetime = dtm.datetime.combine(reference_date, time_object) + if aware_datetime.tzinfo is None: + aware_datetime = _localize(aware_datetime, tzinfo) + + # if the time of day has passed today, use tomorrow + if reference_time > aware_datetime.timetz(): + aware_datetime += dtm.timedelta(days=1) + return _datetime_to_float_timestamp(aware_datetime) + if isinstance(time_object, dtm.datetime): + if time_object.tzinfo is None: + time_object = _localize(time_object, tzinfo) + return _datetime_to_float_timestamp(time_object) + + raise TypeError(f'Unable to convert {type(time_object).__name__} object to timestamp') + + +def to_timestamp( + dt_obj: Union[int, float, dtm.timedelta, dtm.datetime, dtm.time, None], + reference_timestamp: float = None, + tzinfo: dtm.tzinfo = None, +) -> Optional[int]: + """ + Wrapper over :func:`to_float_timestamp` which returns an integer (the float value truncated + down to the nearest integer). + + See the documentation for :func:`to_float_timestamp` for more details. + """ + return ( + int(to_float_timestamp(dt_obj, reference_timestamp, tzinfo)) + if dt_obj is not None + else None + ) + + +def from_timestamp(unixtime: Optional[int], tzinfo: dtm.tzinfo = UTC) -> Optional[dtm.datetime]: + """ + Converts an (integer) unix timestamp to a timezone aware datetime object. + :obj:`None` s are left alone (i.e. ``from_timestamp(None)`` is :obj:`None`). + + Args: + unixtime (:obj:`int`): Integer POSIX timestamp. + tzinfo (:obj:`datetime.tzinfo`, optional): The timezone to which the timestamp is to be + converted to. Defaults to UTC. + + Returns: + Timezone aware equivalent :obj:`datetime.datetime` value if ``unixtime`` is not + :obj:`None`; else :obj:`None`. + """ + if unixtime is None: + return None + + if tzinfo is not None: + return dtm.datetime.fromtimestamp(unixtime, tz=tzinfo) + return dtm.datetime.utcfromtimestamp(unixtime) + + +# -------- end -------- + + +def mention_html(user_id: Union[int, str], name: str) -> str: + """ + Args: + user_id (:obj:`int`): The user's id which you want to mention. + name (:obj:`str`): The name the mention is showing. + + Returns: + :obj:`str`: The inline mention for the user as HTML. + """ + return f'<a href="tg://user?id={user_id}">{escape(name)}</a>' + + +def mention_markdown(user_id: Union[int, str], name: str, version: int = 1) -> str: + """ + Args: + user_id (:obj:`int`): The user's id which you want to mention. + name (:obj:`str`): The name the mention is showing. + version (:obj:`int` | :obj:`str`): Use to specify the version of Telegram's Markdown. + Either ``1`` or ``2``. Defaults to ``1``. + + Returns: + :obj:`str`: The inline mention for the user as Markdown. + """ + return f'[{escape_markdown(name, version=version)}](tg://user?id={user_id})' + + +def effective_message_type(entity: Union['Message', 'Update']) -> Optional[str]: + """ + Extracts the type of message as a string identifier from a :class:`telegram.Message` or a + :class:`telegram.Update`. + + Args: + entity (:class:`telegram.Update` | :class:`telegram.Message`): The ``update`` or + ``message`` to extract from. + + Returns: + :obj:`str`: One of ``Message.MESSAGE_TYPES`` + + """ + # Importing on file-level yields cyclic Import Errors + from telegram import Message, Update # pylint: disable=C0415 + + if isinstance(entity, Message): + message = entity + elif isinstance(entity, Update): + message = entity.effective_message # type: ignore[assignment] + else: + raise TypeError(f"entity is not Message or Update (got: {type(entity)})") + + for i in Message.MESSAGE_TYPES: + if getattr(message, i, None): + return i + + return None + + +def create_deep_linked_url(bot_username: str, payload: str = None, group: bool = False) -> str: + """ + Creates a deep-linked URL for this ``bot_username`` with the specified ``payload``. + See https://core.telegram.org/bots#deep-linking to learn more. + + The ``payload`` may consist of the following characters: ``A-Z, a-z, 0-9, _, -`` + + Note: + Works well in conjunction with + ``CommandHandler("start", callback, filters = Filters.regex('payload'))`` + + Examples: + ``create_deep_linked_url(bot.get_me().username, "some-params")`` + + Args: + bot_username (:obj:`str`): The username to link to + payload (:obj:`str`, optional): Parameters to encode in the created URL + group (:obj:`bool`, optional): If :obj:`True` the user is prompted to select a group to + add the bot to. If :obj:`False`, opens a one-on-one conversation with the bot. + Defaults to :obj:`False`. + + Returns: + :obj:`str`: An URL to start the bot with specific parameters + """ + if bot_username is None or len(bot_username) <= 3: + raise ValueError("You must provide a valid bot_username.") + + base_url = f'https://t.me/{bot_username}' + if not payload: + return base_url + + if len(payload) > 64: + raise ValueError("The deep-linking payload must not exceed 64 characters.") + + if not re.match(r'^[A-Za-z0-9_-]+$', payload): + raise ValueError( + "Only the following characters are allowed for deep-linked " + "URLs: A-Z, a-z, 0-9, _ and -" + ) + + if group: + key = 'startgroup' + else: + key = 'start' + + return f'{base_url}?{key}={payload}' + + +def encode_conversations_to_json(conversations: Dict[str, Dict[Tuple, object]]) -> str: + """Helper method to encode a conversations dict (that uses tuples as keys) to a + JSON-serializable way. Use :meth:`decode_conversations_from_json` to decode. + + Args: + conversations (:obj:`dict`): The conversations dict to transform to JSON. + + Returns: + :obj:`str`: The JSON-serialized conversations dict + """ + tmp: Dict[str, JSONDict] = {} + for handler, states in conversations.items(): + tmp[handler] = {} + for key, state in states.items(): + tmp[handler][json.dumps(key)] = state + return json.dumps(tmp) + + +def decode_conversations_from_json(json_string: str) -> Dict[str, Dict[Tuple, object]]: + """Helper method to decode a conversations dict (that uses tuples as keys) from a + JSON-string created with :meth:`encode_conversations_to_json`. + + Args: + json_string (:obj:`str`): The conversations dict as JSON string. + + Returns: + :obj:`dict`: The conversations dict after decoding + """ + tmp = json.loads(json_string) + conversations: Dict[str, Dict[Tuple, object]] = {} + for handler, states in tmp.items(): + conversations[handler] = {} + for key, state in states.items(): + conversations[handler][tuple(json.loads(key))] = state + return conversations + + +def decode_user_chat_data_from_json(data: str) -> DefaultDict[int, Dict[object, object]]: + """Helper method to decode chat or user data (that uses ints as keys) from a + JSON-string. + + Args: + data (:obj:`str`): The user/chat_data dict as JSON string. + + Returns: + :obj:`dict`: The user/chat_data defaultdict after decoding + """ + tmp: DefaultDict[int, Dict[object, object]] = defaultdict(dict) + decoded_data = json.loads(data) + for user, user_data in decoded_data.items(): + user = int(user) + tmp[user] = {} + for key, value in user_data.items(): + try: + key = int(key) + except ValueError: + pass + tmp[user][key] = value + return tmp + + +DVType = TypeVar('DVType', bound=object) +OT = TypeVar('OT', bound=object) + + +class DefaultValue(Generic[DVType]): + """Wrapper for immutable default arguments that allows to check, if the default value was set + explicitly. Usage:: + + DefaultOne = DefaultValue(1) + def f(arg=DefaultOne): + if arg is DefaultOne: + print('`arg` is the default') + arg = arg.value + else: + print('`arg` was set explicitly') + print(f'`arg` = {str(arg)}') + + This yields:: + + >>> f() + `arg` is the default + `arg` = 1 + >>> f(1) + `arg` was set explicitly + `arg` = 1 + >>> f(2) + `arg` was set explicitly + `arg` = 2 + + Also allows to evaluate truthiness:: + + default = DefaultValue(value) + if default: + ... + + is equivalent to:: + + default = DefaultValue(value) + if value: + ... + + ``repr(DefaultValue(value))`` returns ``repr(value)`` and ``str(DefaultValue(value))`` returns + ``f'DefaultValue({value})'``. + + Args: + value (:obj:`obj`): The value of the default argument + + Attributes: + value (:obj:`obj`): The value of the default argument + + """ + + __slots__ = ('value', '__dict__') + + def __init__(self, value: DVType = None): + self.value = value + + def __bool__(self) -> bool: + return bool(self.value) + + @overload + @staticmethod + def get_value(obj: 'DefaultValue[OT]') -> OT: + ... + + @overload + @staticmethod + def get_value(obj: OT) -> OT: + ... + + @staticmethod + def get_value(obj: Union[OT, 'DefaultValue[OT]']) -> OT: + """ + Shortcut for:: + + return obj.value if isinstance(obj, DefaultValue) else obj + + Args: + obj (:obj:`object`): The object to process + + Returns: + Same type as input, or the value of the input: The value + """ + return obj.value if isinstance(obj, DefaultValue) else obj # type: ignore[return-value] + + # This is mostly here for readability during debugging + def __str__(self) -> str: + return f'DefaultValue({self.value})' + + # This is here to have the default instances nicely rendered in the docs + def __repr__(self) -> str: + return repr(self.value) + + +DEFAULT_NONE: DefaultValue = DefaultValue(None) +""":class:`DefaultValue`: Default :obj:`None`""" + +DEFAULT_FALSE: DefaultValue = DefaultValue(False) +""":class:`DefaultValue`: Default :obj:`False`""" + +DEFAULT_20: DefaultValue = DefaultValue(20) +""":class:`DefaultValue`: Default :obj:`20`""" diff --git a/venv/lib/python3.8/site-packages/telegram/utils/promise.py b/venv/lib/python3.8/site-packages/telegram/utils/promise.py new file mode 100644 index 0000000..c25d56d --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/utils/promise.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the :class:`telegram.ext.utils.promise.Promise` class for backwards +compatibility. +""" +import warnings + +import telegram.ext.utils.promise as promise +from telegram.utils.deprecate import TelegramDeprecationWarning + +warnings.warn( + 'telegram.utils.promise is deprecated. Please use telegram.ext.utils.promise instead.', + TelegramDeprecationWarning, +) + +Promise = promise.Promise +""" +:class:`telegram.ext.utils.promise.Promise` + +.. deprecated:: v13.2 + Use :class:`telegram.ext.utils.promise.Promise` instead. +""" diff --git a/venv/lib/python3.8/site-packages/telegram/utils/request.py b/venv/lib/python3.8/site-packages/telegram/utils/request.py new file mode 100644 index 0000000..f2c35bf --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/utils/request.py @@ -0,0 +1,395 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains methods to make POST and GET requests.""" +import logging +import os +import socket +import sys +import warnings + +try: + import ujson as json +except ImportError: + import json # type: ignore[no-redef] + +from typing import Any, Union + +import certifi + +try: + import telegram.vendor.ptb_urllib3.urllib3 as urllib3 + import telegram.vendor.ptb_urllib3.urllib3.contrib.appengine as appengine + from telegram.vendor.ptb_urllib3.urllib3.connection import HTTPConnection + from telegram.vendor.ptb_urllib3.urllib3.fields import RequestField + from telegram.vendor.ptb_urllib3.urllib3.util.timeout import Timeout +except ImportError: # pragma: no cover + try: + import urllib3 # type: ignore[no-redef] + import urllib3.contrib.appengine as appengine # type: ignore[no-redef] + from urllib3.connection import HTTPConnection # type: ignore[no-redef] + from urllib3.fields import RequestField # type: ignore[no-redef] + from urllib3.util.timeout import Timeout # type: ignore[no-redef] + + warnings.warn( + 'python-telegram-bot is using upstream urllib3. This is allowed but not ' + 'supported by python-telegram-bot maintainers.' + ) + except ImportError: + warnings.warn( + "python-telegram-bot wasn't properly installed. Please refer to README.rst on " + "how to properly install." + ) + raise + +# pylint: disable=C0412 +from telegram import InputFile, InputMedia, TelegramError +from telegram.error import ( + BadRequest, + ChatMigrated, + Conflict, + InvalidToken, + NetworkError, + RetryAfter, + TimedOut, + Unauthorized, +) +from telegram.utils.types import JSONDict +from telegram.utils.deprecate import set_new_attribute_deprecated + + +def _render_part(self: RequestField, name: str, value: str) -> str: # pylint: disable=W0613 + r""" + Monkey patch urllib3.urllib3.fields.RequestField to make it *not* support RFC2231 compliant + Content-Disposition headers since telegram servers don't understand it. Instead just escape + \\ and " and replace any \n and \r with a space. + """ + value = value.replace('\\', '\\\\').replace('"', '\\"') + value = value.replace('\r', ' ').replace('\n', ' ') + return f'{name}="{value}"' + + +RequestField._render_part = _render_part # type: ignore # pylint: disable=W0212 + +logging.getLogger('telegram.vendor.ptb_urllib3.urllib3').setLevel(logging.WARNING) + +USER_AGENT = 'Python Telegram Bot (https://github.com/python-telegram-bot/python-telegram-bot)' + + +class Request: + """ + Helper class for python-telegram-bot which provides methods to perform POST & GET towards + Telegram servers. + + Args: + con_pool_size (:obj:`int`): Number of connections to keep in the connection pool. + proxy_url (:obj:`str`): The URL to the proxy server. For example: `http://127.0.0.1:3128`. + urllib3_proxy_kwargs (:obj:`dict`): Arbitrary arguments passed as-is to + :obj:`urllib3.ProxyManager`. This value will be ignored if :attr:`proxy_url` is not + set. + connect_timeout (:obj:`int` | :obj:`float`): The maximum amount of time (in seconds) to + wait for a connection attempt to a server to succeed. :obj:`None` will set an + infinite timeout for connection attempts. Defaults to ``5.0``. + read_timeout (:obj:`int` | :obj:`float`): The maximum amount of time (in seconds) to wait + between consecutive read operations for a response from the server. :obj:`None` will + set an infinite timeout. This value is usually overridden by the various + :class:`telegram.Bot` methods. Defaults to ``5.0``. + + """ + + __slots__ = ('_connect_timeout', '_con_pool_size', '_con_pool', '__dict__') + + def __init__( + self, + con_pool_size: int = 1, + proxy_url: str = None, + urllib3_proxy_kwargs: JSONDict = None, + connect_timeout: float = 5.0, + read_timeout: float = 5.0, + ): + if urllib3_proxy_kwargs is None: + urllib3_proxy_kwargs = {} + + self._connect_timeout = connect_timeout + + sockopts = HTTPConnection.default_socket_options + [ + (socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) + ] + + # TODO: Support other platforms like mac and windows. + if 'linux' in sys.platform: + sockopts.append( + (socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 120) # pylint: disable=no-member + ) + sockopts.append( + (socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 30) # pylint: disable=no-member + ) + sockopts.append( + (socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 8) # pylint: disable=no-member + ) + + self._con_pool_size = con_pool_size + + kwargs = dict( + maxsize=con_pool_size, + cert_reqs='CERT_REQUIRED', + ca_certs=certifi.where(), + socket_options=sockopts, + timeout=urllib3.Timeout(connect=self._connect_timeout, read=read_timeout, total=None), + ) + + # Set a proxy according to the following order: + # * proxy defined in proxy_url (+ urllib3_proxy_kwargs) + # * proxy set in `HTTPS_PROXY` env. var. + # * proxy set in `https_proxy` env. var. + # * None (if no proxy is configured) + + if not proxy_url: + proxy_url = os.environ.get('HTTPS_PROXY') or os.environ.get('https_proxy') + + self._con_pool: Union[ + urllib3.PoolManager, + appengine.AppEngineManager, + 'SOCKSProxyManager', # noqa: F821 + urllib3.ProxyManager, + ] = None # type: ignore + if not proxy_url: + if appengine.is_appengine_sandbox(): + # Use URLFetch service if running in App Engine + self._con_pool = appengine.AppEngineManager() + else: + self._con_pool = urllib3.PoolManager(**kwargs) + else: + kwargs.update(urllib3_proxy_kwargs) + if proxy_url.startswith('socks'): + try: + # pylint: disable=C0415 + from telegram.vendor.ptb_urllib3.urllib3.contrib.socks import SOCKSProxyManager + except ImportError as exc: + raise RuntimeError('PySocks is missing') from exc + self._con_pool = SOCKSProxyManager(proxy_url, **kwargs) + else: + mgr = urllib3.proxy_from_url(proxy_url, **kwargs) + if mgr.proxy.auth: + # TODO: what about other auth types? + auth_hdrs = urllib3.make_headers(proxy_basic_auth=mgr.proxy.auth) + mgr.proxy_headers.update(auth_hdrs) + + self._con_pool = mgr + + def __setattr__(self, key: str, value: object) -> None: + set_new_attribute_deprecated(self, key, value) + + @property + def con_pool_size(self) -> int: + """The size of the connection pool used.""" + return self._con_pool_size + + def stop(self) -> None: + """Performs cleanup on shutdown.""" + self._con_pool.clear() # type: ignore + + @staticmethod + def _parse(json_data: bytes) -> Union[JSONDict, bool]: + """Try and parse the JSON returned from Telegram. + + Returns: + dict: A JSON parsed as Python dict with results - on error this dict will be empty. + + """ + decoded_s = json_data.decode('utf-8', 'replace') + try: + data = json.loads(decoded_s) + except ValueError as exc: + raise TelegramError('Invalid server response') from exc + + if not data.get('ok'): # pragma: no cover + description = data.get('description') + parameters = data.get('parameters') + if parameters: + migrate_to_chat_id = parameters.get('migrate_to_chat_id') + if migrate_to_chat_id: + raise ChatMigrated(migrate_to_chat_id) + retry_after = parameters.get('retry_after') + if retry_after: + raise RetryAfter(retry_after) + if description: + return description + + return data['result'] + + def _request_wrapper(self, *args: object, **kwargs: Any) -> bytes: + """Wraps urllib3 request for handling known exceptions. + + Args: + args: unnamed arguments, passed to urllib3 request. + kwargs: keyword arguments, passed to urllib3 request. + + Returns: + bytes: A non-parsed JSON text. + + Raises: + TelegramError + + """ + # Make sure to hint Telegram servers that we reuse connections by sending + # "Connection: keep-alive" in the HTTP headers. + if 'headers' not in kwargs: + kwargs['headers'] = {} + kwargs['headers']['connection'] = 'keep-alive' + # Also set our user agent + kwargs['headers']['user-agent'] = USER_AGENT + + try: + resp = self._con_pool.request(*args, **kwargs) + except urllib3.exceptions.TimeoutError as error: + raise TimedOut() from error + except urllib3.exceptions.HTTPError as error: + # HTTPError must come last as its the base urllib3 exception class + # TODO: do something smart here; for now just raise NetworkError + raise NetworkError(f'urllib3 HTTPError {error}') from error + + if 200 <= resp.status <= 299: + # 200-299 range are HTTP success statuses + return resp.data + + try: + message = str(self._parse(resp.data)) + except ValueError: + message = 'Unknown HTTPError' + + if resp.status in (401, 403): + raise Unauthorized(message) + if resp.status == 400: + raise BadRequest(message) + if resp.status == 404: + raise InvalidToken() + if resp.status == 409: + raise Conflict(message) + if resp.status == 413: + raise NetworkError( + 'File too large. Check telegram api limits ' + 'https://core.telegram.org/bots/api#senddocument' + ) + if resp.status == 502: + raise NetworkError('Bad Gateway') + raise NetworkError(f'{message} ({resp.status})') + + def post(self, url: str, data: JSONDict, timeout: float = None) -> Union[JSONDict, bool]: + """Request an URL. + + Args: + url (:obj:`str`): The web location we want to retrieve. + data (Dict[:obj:`str`, :obj:`str` | :obj:`int`], optional): A dict of key/value pairs. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + + Returns: + A JSON object. + + """ + urlopen_kwargs = {} + + if timeout is not None: + urlopen_kwargs['timeout'] = Timeout(read=timeout, connect=self._connect_timeout) + + if data is None: + data = {} + + # Are we uploading files? + files = False + + # pylint: disable=R1702 + for key, val in data.copy().items(): + if isinstance(val, InputFile): + # Convert the InputFile to urllib3 field format + data[key] = val.field_tuple + files = True + elif isinstance(val, (float, int)): + # Urllib3 doesn't like floats it seems + data[key] = str(val) + elif key == 'media': + # One media or multiple + if isinstance(val, InputMedia): + # Attach and set val to attached name + data[key] = val.to_json() + if isinstance(val.media, InputFile): # type: ignore + data[val.media.attach] = val.media.field_tuple # type: ignore + else: + # Attach and set val to attached name for all + media = [] + for med in val: + media_dict = med.to_dict() + media.append(media_dict) + if isinstance(med.media, InputFile): + data[med.media.attach] = med.media.field_tuple + # if the file has a thumb, we also need to attach it to the data + if "thumb" in media_dict: + data[med.thumb.attach] = med.thumb.field_tuple + data[key] = json.dumps(media) + files = True + elif isinstance(val, list): + # In case we're sending files, we need to json-dump lists manually + # As we can't know if that's the case, we just json-dump here + data[key] = json.dumps(val) + + # Use multipart upload if we're uploading files, otherwise use JSON + if files: + result = self._request_wrapper('POST', url, fields=data, **urlopen_kwargs) + else: + result = self._request_wrapper( + 'POST', + url, + body=json.dumps(data).encode('utf-8'), + headers={'Content-Type': 'application/json'}, + **urlopen_kwargs, + ) + + return self._parse(result) + + def retrieve(self, url: str, timeout: float = None) -> bytes: + """Retrieve the contents of a file by its URL. + + Args: + url (:obj:`str`): The web location we want to retrieve. + timeout (:obj:`int` | :obj:`float`): If this value is specified, use it as the read + timeout from the server (instead of the one specified during creation of the + connection pool). + + """ + urlopen_kwargs = {} + if timeout is not None: + urlopen_kwargs['timeout'] = Timeout(read=timeout, connect=self._connect_timeout) + + return self._request_wrapper('GET', url, **urlopen_kwargs) + + def download(self, url: str, filename: str, timeout: float = None) -> None: + """Download a file by its URL. + + Args: + url (:obj:`str`): The web location we want to retrieve. + timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as + the read timeout from the server (instead of the one specified during creation of + the connection pool). + filename (:obj:`str`): The filename within the path to download the file. + + """ + buf = self.retrieve(url, timeout=timeout) + with open(filename, 'wb') as fobj: + fobj.write(buf) diff --git a/venv/lib/python3.8/site-packages/telegram/utils/types.py b/venv/lib/python3.8/site-packages/telegram/utils/types.py new file mode 100644 index 0000000..2f9ff8f --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/utils/types.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains custom typing aliases.""" +from pathlib import Path +from typing import ( + IO, + TYPE_CHECKING, + Any, + Dict, + List, + Optional, + Tuple, + TypeVar, + Union, +) + +if TYPE_CHECKING: + from telegram import InputFile # noqa: F401 + from telegram.utils.helpers import DefaultValue # noqa: F401 + +FileLike = Union[IO, 'InputFile'] +"""Either an open file handler or a :class:`telegram.InputFile`.""" + +FileInput = Union[str, bytes, FileLike, Path] +"""Valid input for passing files to Telegram. Either a file id as string, a file like object, +a local file path as string, :class:`pathlib.Path` or the file contents as :obj:`bytes`.""" + +JSONDict = Dict[str, Any] +"""Dictionary containing response from Telegram or data to send to the API.""" + +DVType = TypeVar('DVType') +ODVInput = Optional[Union['DefaultValue[DVType]', DVType]] +"""Generic type for bot method parameters which can have defaults. ``ODVInput[type]`` is the same +as ``Optional[Union[DefaultValue, type]]``.""" +DVInput = Union['DefaultValue[DVType]', DVType] +"""Generic type for bot method parameters which can have defaults. ``DVInput[type]`` is the same +as ``Union[DefaultValue, type]``.""" + +RT = TypeVar("RT") +SLT = Union[RT, List[RT], Tuple[RT, ...]] +"""Single instance or list/tuple of instances.""" diff --git a/venv/lib/python3.8/site-packages/telegram/utils/webhookhandler.py b/venv/lib/python3.8/site-packages/telegram/utils/webhookhandler.py new file mode 100644 index 0000000..727eecb --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/utils/webhookhandler.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains the :class:`telegram.ext.utils.webhookhandler.WebhookHandler` class for +backwards compatibility. +""" +import warnings + +import telegram.ext.utils.webhookhandler as webhook_handler +from telegram.utils.deprecate import TelegramDeprecationWarning + +warnings.warn( + 'telegram.utils.webhookhandler is deprecated. Please use telegram.ext.utils.webhookhandler ' + 'instead.', + TelegramDeprecationWarning, +) + +WebhookHandler = webhook_handler.WebhookHandler +WebhookServer = webhook_handler.WebhookServer +WebhookAppClass = webhook_handler.WebhookAppClass diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/__init__.py b/venv/lib/python3.8/site-packages/telegram/vendor/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/__init__.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/__init__.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/__init__.py new file mode 100644 index 0000000..0cd5e34 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/__init__.py @@ -0,0 +1,96 @@ +""" +urllib3 - Thread-safe connection pooling and re-using. +""" +from __future__ import absolute_import +import warnings + +from .connectionpool import ( + HTTPConnectionPool, + HTTPSConnectionPool, + connection_from_url +) + +from . import exceptions +from .filepost import encode_multipart_formdata +from .poolmanager import PoolManager, ProxyManager, proxy_from_url +from .response import HTTPResponse +from .util.request import make_headers +from .util.url import get_host +from .util.timeout import Timeout +from .util.retry import Retry + + +# Set default logging handler to avoid "No handler found" warnings. +import logging +try: # Python 2.7+ + from logging import NullHandler +except ImportError: + class NullHandler(logging.Handler): + def emit(self, record): + pass + +__author__ = 'Andrey Petrov (andrey.petrov@shazow.net)' +__license__ = 'MIT' +__version__ = 'dev' + +__all__ = ( + 'HTTPConnectionPool', + 'HTTPSConnectionPool', + 'PoolManager', + 'ProxyManager', + 'HTTPResponse', + 'Retry', + 'Timeout', + 'add_stderr_logger', + 'connection_from_url', + 'disable_warnings', + 'encode_multipart_formdata', + 'get_host', + 'make_headers', + 'proxy_from_url', +) + +logging.getLogger(__name__).addHandler(NullHandler()) + + +def add_stderr_logger(level=logging.DEBUG): + """ + Helper for quickly adding a StreamHandler to the logger. Useful for + debugging. + + Returns the handler after adding it. + """ + # This method needs to be in this __init__.py to get the __name__ correct + # even if urllib3 is vendored within another package. + logger = logging.getLogger(__name__) + handler = logging.StreamHandler() + handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s %(message)s')) + logger.addHandler(handler) + logger.setLevel(level) + logger.debug('Added a stderr logging handler to logger: %s', __name__) + return handler + + +# ... Clean up. +del NullHandler + + +# All warning filters *must* be appended unless you're really certain that they +# shouldn't be: otherwise, it's very hard for users to use most Python +# mechanisms to silence them. +# SecurityWarning's always go off by default. +warnings.simplefilter('always', exceptions.SecurityWarning, append=True) +# SubjectAltNameWarning's should go off once per host +warnings.simplefilter('default', exceptions.SubjectAltNameWarning, append=True) +# InsecurePlatformWarning's don't vary between requests, so we keep it default. +warnings.simplefilter('default', exceptions.InsecurePlatformWarning, + append=True) +# SNIMissingWarnings should go off only once. +warnings.simplefilter('default', exceptions.SNIMissingWarning, append=True) + + +def disable_warnings(category=exceptions.HTTPWarning): + """ + Helper for quickly disabling all urllib3 warnings. + """ + warnings.simplefilter('ignore', category) diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/_collections.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/_collections.py new file mode 100644 index 0000000..4fcd2ab --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/_collections.py @@ -0,0 +1,327 @@ +from __future__ import absolute_import +try: + from collections.abc import Mapping, MutableMapping +except ImportError: + from collections import Mapping, MutableMapping +try: + from threading import RLock +except ImportError: # Platform-specific: No threads available + class RLock: + def __enter__(self): + pass + + def __exit__(self, exc_type, exc_value, traceback): + pass + + +try: # Python 2.7+ + from collections import OrderedDict +except ImportError: + from .packages.ordered_dict import OrderedDict +from .packages.six import iterkeys, itervalues, PY3 + + +__all__ = ['RecentlyUsedContainer', 'HTTPHeaderDict'] + + +_Null = object() + + +class RecentlyUsedContainer(MutableMapping): + """ + Provides a thread-safe dict-like container which maintains up to + ``maxsize`` keys while throwing away the least-recently-used keys beyond + ``maxsize``. + + :param maxsize: + Maximum number of recent elements to retain. + + :param dispose_func: + Every time an item is evicted from the container, + ``dispose_func(value)`` is called. Callback which will get called + """ + + ContainerCls = OrderedDict + + def __init__(self, maxsize=10, dispose_func=None): + self._maxsize = maxsize + self.dispose_func = dispose_func + + self._container = self.ContainerCls() + self.lock = RLock() + + def __getitem__(self, key): + # Re-insert the item, moving it to the end of the eviction line. + with self.lock: + item = self._container.pop(key) + self._container[key] = item + return item + + def __setitem__(self, key, value): + evicted_value = _Null + with self.lock: + # Possibly evict the existing value of 'key' + evicted_value = self._container.get(key, _Null) + self._container[key] = value + + # If we didn't evict an existing value, we might have to evict the + # least recently used item from the beginning of the container. + if len(self._container) > self._maxsize: + _key, evicted_value = self._container.popitem(last=False) + + if self.dispose_func and evicted_value is not _Null: + self.dispose_func(evicted_value) + + def __delitem__(self, key): + with self.lock: + value = self._container.pop(key) + + if self.dispose_func: + self.dispose_func(value) + + def __len__(self): + with self.lock: + return len(self._container) + + def __iter__(self): + raise NotImplementedError('Iteration over this class is unlikely to be threadsafe.') + + def clear(self): + with self.lock: + # Copy pointers to all values, then wipe the mapping + values = list(itervalues(self._container)) + self._container.clear() + + if self.dispose_func: + for value in values: + self.dispose_func(value) + + def keys(self): + with self.lock: + return list(iterkeys(self._container)) + + +class HTTPHeaderDict(MutableMapping): + """ + :param headers: + An iterable of field-value pairs. Must not contain multiple field names + when compared case-insensitively. + + :param kwargs: + Additional field-value pairs to pass in to ``dict.update``. + + A ``dict`` like container for storing HTTP Headers. + + Field names are stored and compared case-insensitively in compliance with + RFC 7230. Iteration provides the first case-sensitive key seen for each + case-insensitive pair. + + Using ``__setitem__`` syntax overwrites fields that compare equal + case-insensitively in order to maintain ``dict``'s api. For fields that + compare equal, instead create a new ``HTTPHeaderDict`` and use ``.add`` + in a loop. + + If multiple fields that are equal case-insensitively are passed to the + constructor or ``.update``, the behavior is undefined and some will be + lost. + + >>> headers = HTTPHeaderDict() + >>> headers.add('Set-Cookie', 'foo=bar') + >>> headers.add('set-cookie', 'baz=quxx') + >>> headers['content-length'] = '7' + >>> headers['SET-cookie'] + 'foo=bar, baz=quxx' + >>> headers['Content-Length'] + '7' + """ + + def __init__(self, headers=None, **kwargs): + super(HTTPHeaderDict, self).__init__() + self._container = OrderedDict() + if headers is not None: + if isinstance(headers, HTTPHeaderDict): + self._copy_from(headers) + else: + self.extend(headers) + if kwargs: + self.extend(kwargs) + + def __setitem__(self, key, val): + self._container[key.lower()] = (key, val) + return self._container[key.lower()] + + def __getitem__(self, key): + val = self._container[key.lower()] + return ', '.join(val[1:]) + + def __delitem__(self, key): + del self._container[key.lower()] + + def __contains__(self, key): + return key.lower() in self._container + + def __eq__(self, other): + if not isinstance(other, Mapping) and not hasattr(other, 'keys'): + return False + if not isinstance(other, type(self)): + other = type(self)(other) + return (dict((k.lower(), v) for k, v in self.itermerged()) == + dict((k.lower(), v) for k, v in other.itermerged())) + + def __ne__(self, other): + return not self.__eq__(other) + + if not PY3: # Python 2 + iterkeys = MutableMapping.iterkeys + itervalues = MutableMapping.itervalues + + __marker = object() + + def __len__(self): + return len(self._container) + + def __iter__(self): + # Only provide the originally cased names + for vals in self._container.values(): + yield vals[0] + + def pop(self, key, default=__marker): + '''D.pop(k[,d]) -> v, remove specified key and return the corresponding value. + If key is not found, d is returned if given, otherwise KeyError is raised. + ''' + # Using the MutableMapping function directly fails due to the private marker. + # Using ordinary dict.pop would expose the internal structures. + # So let's reinvent the wheel. + try: + value = self[key] + except KeyError: + if default is self.__marker: + raise + return default + else: + del self[key] + return value + + def discard(self, key): + try: + del self[key] + except KeyError: + pass + + def add(self, key, val): + """Adds a (name, value) pair, doesn't overwrite the value if it already + exists. + + >>> headers = HTTPHeaderDict(foo='bar') + >>> headers.add('Foo', 'baz') + >>> headers['foo'] + 'bar, baz' + """ + key_lower = key.lower() + new_vals = key, val + # Keep the common case aka no item present as fast as possible + vals = self._container.setdefault(key_lower, new_vals) + if new_vals is not vals: + # new_vals was not inserted, as there was a previous one + if isinstance(vals, list): + # If already several items got inserted, we have a list + vals.append(val) + else: + # vals should be a tuple then, i.e. only one item so far + # Need to convert the tuple to list for further extension + self._container[key_lower] = [vals[0], vals[1], val] + + def extend(self, *args, **kwargs): + """Generic import function for any type of header-like object. + Adapted version of MutableMapping.update in order to insert items + with self.add instead of self.__setitem__ + """ + if len(args) > 1: + raise TypeError("extend() takes at most 1 positional " + "arguments ({0} given)".format(len(args))) + other = args[0] if len(args) >= 1 else () + + if isinstance(other, HTTPHeaderDict): + for key, val in other.iteritems(): + self.add(key, val) + elif isinstance(other, Mapping): + for key in other: + self.add(key, other[key]) + elif hasattr(other, "keys"): + for key in other.keys(): + self.add(key, other[key]) + else: + for key, value in other: + self.add(key, value) + + for key, value in kwargs.items(): + self.add(key, value) + + def getlist(self, key): + """Returns a list of all the values for the named field. Returns an + empty list if the key doesn't exist.""" + try: + vals = self._container[key.lower()] + except KeyError: + return [] + else: + if isinstance(vals, tuple): + return [vals[1]] + else: + return vals[1:] + + # Backwards compatibility for httplib + getheaders = getlist + getallmatchingheaders = getlist + iget = getlist + + def __repr__(self): + return "%s(%s)" % (type(self).__name__, dict(self.itermerged())) + + def _copy_from(self, other): + for key in other: + val = other.getlist(key) + if isinstance(val, list): + # Don't need to convert tuples + val = list(val) + self._container[key.lower()] = [key] + val + + def copy(self): + clone = type(self)() + clone._copy_from(self) + return clone + + def iteritems(self): + """Iterate over all header lines, including duplicate ones.""" + for key in self: + vals = self._container[key.lower()] + for val in vals[1:]: + yield vals[0], val + + def itermerged(self): + """Iterate over all headers, merging duplicate ones together.""" + for key in self: + val = self._container[key.lower()] + yield val[0], ', '.join(val[1:]) + + def items(self): + return list(self.iteritems()) + + @classmethod + def from_httplib(cls, message): # Python 2 + """Read headers from a Python 2 httplib message object.""" + # python2.7 does not expose a proper API for exporting multiheaders + # efficiently. This function re-reads raw lines from the message + # object and extracts the multiheaders properly. + headers = [] + + for line in message.headers: + if line.startswith((' ', '\t')): + key, value = headers[-1] + headers[-1] = (key, value + '\r\n' + line.rstrip()) + continue + + key, value = line.split(':', 1) + headers.append((key, value.strip())) + + return cls(headers) diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/connection.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/connection.py new file mode 100644 index 0000000..9f06c39 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/connection.py @@ -0,0 +1,369 @@ +from __future__ import absolute_import +import datetime +import logging +import os +import sys +import socket +from socket import error as SocketError, timeout as SocketTimeout +import warnings +from .packages import six +from .packages.six.moves.http_client import HTTPConnection as _HTTPConnection +from .packages.six.moves.http_client import HTTPException # noqa: F401 + +try: # Compiled with SSL? + import ssl + BaseSSLError = ssl.SSLError +except (ImportError, AttributeError): # Platform-specific: No SSL. + ssl = None + + class BaseSSLError(BaseException): + pass + + +try: # Python 3: + # Not a no-op, we're adding this to the namespace so it can be imported. + ConnectionError = ConnectionError +except NameError: # Python 2: + class ConnectionError(Exception): + pass + + +from .exceptions import ( + NewConnectionError, + ConnectTimeoutError, + SubjectAltNameWarning, + SystemTimeWarning, +) +from .packages.ssl_match_hostname import match_hostname, CertificateError + +from .util.ssl_ import ( + resolve_cert_reqs, + resolve_ssl_version, + assert_fingerprint, + create_urllib3_context, + ssl_wrap_socket +) + + +from .util import connection + +from ._collections import HTTPHeaderDict + +log = logging.getLogger(__name__) + +port_by_scheme = { + 'http': 80, + 'https': 443, +} + +# When updating RECENT_DATE, move it to +# within two years of the current date, and no +# earlier than 6 months ago. +RECENT_DATE = datetime.date(2016, 1, 1) + + +class DummyConnection(object): + """Used to detect a failed ConnectionCls import.""" + pass + + +class HTTPConnection(_HTTPConnection, object): + """ + Based on httplib.HTTPConnection but provides an extra constructor + backwards-compatibility layer between older and newer Pythons. + + Additional keyword parameters are used to configure attributes of the connection. + Accepted parameters include: + + - ``strict``: See the documentation on :class:`urllib3.connectionpool.HTTPConnectionPool` + - ``source_address``: Set the source address for the current connection. + + .. note:: This is ignored for Python 2.6. It is only applied for 2.7 and 3.x + + - ``socket_options``: Set specific options on the underlying socket. If not specified, then + defaults are loaded from ``HTTPConnection.default_socket_options`` which includes disabling + Nagle's algorithm (sets TCP_NODELAY to 1) unless the connection is behind a proxy. + + For example, if you wish to enable TCP Keep Alive in addition to the defaults, + you might pass:: + + HTTPConnection.default_socket_options + [ + (socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1), + ] + + Or you may want to disable the defaults by passing an empty list (e.g., ``[]``). + """ + + default_port = port_by_scheme['http'] + + #: Disable Nagle's algorithm by default. + #: ``[(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)]`` + default_socket_options = [(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)] + + #: Whether this connection verifies the host's certificate. + is_verified = False + + def __init__(self, *args, **kw): + if six.PY3: # Python 3 + kw.pop('strict', None) + + # Pre-set source_address in case we have an older Python like 2.6. + self.source_address = kw.get('source_address') + + if sys.version_info < (2, 7): # Python 2.6 + # _HTTPConnection on Python 2.6 will balk at this keyword arg, but + # not newer versions. We can still use it when creating a + # connection though, so we pop it *after* we have saved it as + # self.source_address. + kw.pop('source_address', None) + + #: The socket options provided by the user. If no options are + #: provided, we use the default options. + self.socket_options = kw.pop('socket_options', self.default_socket_options) + + # Superclass also sets self.source_address in Python 2.7+. + _HTTPConnection.__init__(self, *args, **kw) + + def _new_conn(self): + """ Establish a socket connection and set nodelay settings on it. + + :return: New socket connection. + """ + extra_kw = {} + if self.source_address: + extra_kw['source_address'] = self.source_address + + if self.socket_options: + extra_kw['socket_options'] = self.socket_options + + try: + conn = connection.create_connection( + (self.host, self.port), self.timeout, **extra_kw) + + except SocketTimeout as e: + raise ConnectTimeoutError( + self, "Connection to %s timed out. (connect timeout=%s)" % + (self.host, self.timeout)) + + except SocketError as e: + raise NewConnectionError( + self, "Failed to establish a new connection: %s" % e) + + return conn + + def _prepare_conn(self, conn): + self.sock = conn + # the _tunnel_host attribute was added in python 2.6.3 (via + # http://hg.python.org/cpython/rev/0f57b30a152f) so pythons 2.6(0-2) do + # not have them. + if getattr(self, '_tunnel_host', None): + # TODO: Fix tunnel so it doesn't depend on self.sock state. + self._tunnel() + # Mark this connection as not reusable + self.auto_open = 0 + + def connect(self): + conn = self._new_conn() + self._prepare_conn(conn) + + def request_chunked(self, method, url, body=None, headers=None): + """ + Alternative to the common request method, which sends the + body with chunked encoding and not as one block + """ + headers = HTTPHeaderDict(headers if headers is not None else {}) + skip_accept_encoding = 'accept-encoding' in headers + skip_host = 'host' in headers + self.putrequest( + method, + url, + skip_accept_encoding=skip_accept_encoding, + skip_host=skip_host + ) + for header, value in headers.items(): + self.putheader(header, value) + if 'transfer-encoding' not in headers: + self.putheader('Transfer-Encoding', 'chunked') + self.endheaders() + + if body is not None: + stringish_types = six.string_types + (six.binary_type,) + if isinstance(body, stringish_types): + body = (body,) + for chunk in body: + if not chunk: + continue + if not isinstance(chunk, six.binary_type): + chunk = chunk.encode('utf8') + len_str = hex(len(chunk))[2:] + self.send(len_str.encode('utf-8')) + self.send(b'\r\n') + self.send(chunk) + self.send(b'\r\n') + + # After the if clause, to always have a closed body + self.send(b'0\r\n\r\n') + + +class HTTPSConnection(HTTPConnection): + default_port = port_by_scheme['https'] + + ssl_version = None + + def __init__(self, host, port=None, key_file=None, cert_file=None, + strict=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, + ssl_context=None, **kw): + + HTTPConnection.__init__(self, host, port, strict=strict, + timeout=timeout, **kw) + + self.key_file = key_file + self.cert_file = cert_file + self.ssl_context = ssl_context + + # Required property for Google AppEngine 1.9.0 which otherwise causes + # HTTPS requests to go out as HTTP. (See Issue #356) + self._protocol = 'https' + + def connect(self): + conn = self._new_conn() + self._prepare_conn(conn) + + if self.ssl_context is None: + self.ssl_context = create_urllib3_context( + ssl_version=resolve_ssl_version(None), + cert_reqs=resolve_cert_reqs(None), + ) + + self.sock = ssl_wrap_socket( + sock=conn, + keyfile=self.key_file, + certfile=self.cert_file, + ssl_context=self.ssl_context, + ) + + +class VerifiedHTTPSConnection(HTTPSConnection): + """ + Based on httplib.HTTPSConnection but wraps the socket with + SSL certification. + """ + cert_reqs = None + ca_certs = None + ca_cert_dir = None + ssl_version = None + assert_fingerprint = None + + def set_cert(self, key_file=None, cert_file=None, + cert_reqs=None, ca_certs=None, + assert_hostname=None, assert_fingerprint=None, + ca_cert_dir=None): + """ + This method should only be called once, before the connection is used. + """ + # If cert_reqs is not provided, we can try to guess. If the user gave + # us a cert database, we assume they want to use it: otherwise, if + # they gave us an SSL Context object we should use whatever is set for + # it. + if cert_reqs is None: + if ca_certs or ca_cert_dir: + cert_reqs = 'CERT_REQUIRED' + elif self.ssl_context is not None: + cert_reqs = self.ssl_context.verify_mode + + self.key_file = key_file + self.cert_file = cert_file + self.cert_reqs = cert_reqs + self.assert_hostname = assert_hostname + self.assert_fingerprint = assert_fingerprint + self.ca_certs = ca_certs and os.path.expanduser(ca_certs) + self.ca_cert_dir = ca_cert_dir and os.path.expanduser(ca_cert_dir) + + def connect(self): + # Add certificate verification + conn = self._new_conn() + + hostname = self.host + if getattr(self, '_tunnel_host', None): + # _tunnel_host was added in Python 2.6.3 + # (See: http://hg.python.org/cpython/rev/0f57b30a152f) + + self.sock = conn + # Calls self._set_hostport(), so self.host is + # self._tunnel_host below. + self._tunnel() + # Mark this connection as not reusable + self.auto_open = 0 + + # Override the host with the one we're requesting data from. + hostname = self._tunnel_host + + is_time_off = datetime.date.today() < RECENT_DATE + if is_time_off: + warnings.warn(( + 'System time is way off (before {0}). This will probably ' + 'lead to SSL verification errors').format(RECENT_DATE), + SystemTimeWarning + ) + + # Wrap socket using verification with the root certs in + # trusted_root_certs + if self.ssl_context is None: + self.ssl_context = create_urllib3_context( + ssl_version=resolve_ssl_version(self.ssl_version), + cert_reqs=resolve_cert_reqs(self.cert_reqs), + ) + + context = self.ssl_context + context.verify_mode = resolve_cert_reqs(self.cert_reqs) + self.sock = ssl_wrap_socket( + sock=conn, + keyfile=self.key_file, + certfile=self.cert_file, + ca_certs=self.ca_certs, + ca_cert_dir=self.ca_cert_dir, + server_hostname=hostname, + ssl_context=context) + + if self.assert_fingerprint: + assert_fingerprint(self.sock.getpeercert(binary_form=True), + self.assert_fingerprint) + elif context.verify_mode != ssl.CERT_NONE \ + and self.assert_hostname is not False: + cert = self.sock.getpeercert() + if not cert.get('subjectAltName', ()): + warnings.warn(( + 'Certificate for {0} has no `subjectAltName`, falling back to check for a ' + '`commonName` for now. This feature is being removed by major browsers and ' + 'deprecated by RFC 2818. (See https://github.com/shazow/urllib3/issues/497 ' + 'for details.)'.format(hostname)), + SubjectAltNameWarning + ) + _match_hostname(cert, self.assert_hostname or hostname) + + self.is_verified = ( + context.verify_mode == ssl.CERT_REQUIRED or + self.assert_fingerprint is not None + ) + + +def _match_hostname(cert, asserted_hostname): + try: + match_hostname(cert, asserted_hostname) + except CertificateError as e: + log.error( + 'Certificate did not match expected hostname: %s. ' + 'Certificate: %s', asserted_hostname, cert + ) + # Add cert to exception and reraise so client code can inspect + # the cert when catching the exception, if they want to + e._peer_cert = cert + raise + + +if ssl: + # Make a copy for testing. + UnverifiedHTTPSConnection = HTTPSConnection + HTTPSConnection = VerifiedHTTPSConnection +else: + HTTPSConnection = DummyConnection diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/connectionpool.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/connectionpool.py new file mode 100644 index 0000000..a958f99 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/connectionpool.py @@ -0,0 +1,912 @@ +from __future__ import absolute_import +import errno +import logging +import sys +import warnings + +from socket import error as SocketError, timeout as SocketTimeout +import socket + + +from .exceptions import ( + ClosedPoolError, + ProtocolError, + EmptyPoolError, + HeaderParsingError, + HostChangedError, + LocationValueError, + MaxRetryError, + ProxyError, + ReadTimeoutError, + SSLError, + TimeoutError, + InsecureRequestWarning, + NewConnectionError, + ConnectTimeoutError, +) +from .packages.ssl_match_hostname import CertificateError +from .packages import six +from .packages.six.moves import queue +from .connection import ( + port_by_scheme, + DummyConnection, + HTTPConnection, HTTPSConnection, VerifiedHTTPSConnection, + HTTPException, BaseSSLError, +) +from .request import RequestMethods +from .response import HTTPResponse + +from .util.connection import is_connection_dropped +from .util.request import set_file_position +from .util.response import assert_header_parsing +from .util.retry import Retry +from .util.timeout import Timeout +from .util.url import get_host, Url + + +if six.PY2: + # Queue is imported for side effects on MS Windows + import Queue as _unused_module_Queue # noqa: F401 + +xrange = six.moves.xrange + +log = logging.getLogger(__name__) + +_Default = object() + + +# Pool objects +class ConnectionPool(object): + """ + Base class for all connection pools, such as + :class:`.HTTPConnectionPool` and :class:`.HTTPSConnectionPool`. + """ + + scheme = None + QueueCls = queue.LifoQueue + + def __init__(self, host, port=None): + if not host: + raise LocationValueError("No host specified.") + + self.host = _ipv6_host(host).lower() + self.port = port + + def __str__(self): + return '%s(host=%r, port=%r)' % (type(self).__name__, + self.host, self.port) + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.close() + # Return False to re-raise any potential exceptions + return False + + def close(self): + """ + Close all pooled connections and disable the pool. + """ + pass + + +# This is taken from http://hg.python.org/cpython/file/7aaba721ebc0/Lib/socket.py#l252 +_blocking_errnos = set([errno.EAGAIN, errno.EWOULDBLOCK]) + + +class HTTPConnectionPool(ConnectionPool, RequestMethods): + """ + Thread-safe connection pool for one host. + + :param host: + Host used for this HTTP Connection (e.g. "localhost"), passed into + :class:`httplib.HTTPConnection`. + + :param port: + Port used for this HTTP Connection (None is equivalent to 80), passed + into :class:`httplib.HTTPConnection`. + + :param strict: + Causes BadStatusLine to be raised if the status line can't be parsed + as a valid HTTP/1.0 or 1.1 status line, passed into + :class:`httplib.HTTPConnection`. + + .. note:: + Only works in Python 2. This parameter is ignored in Python 3. + + :param timeout: + Socket timeout in seconds for each individual connection. This can + be a float or integer, which sets the timeout for the HTTP request, + or an instance of :class:`urllib3.util.Timeout` which gives you more + fine-grained control over request timeouts. After the constructor has + been parsed, this is always a `urllib3.util.Timeout` object. + + :param maxsize: + Number of connections to save that can be reused. More than 1 is useful + in multithreaded situations. If ``block`` is set to False, more + connections will be created but they will not be saved once they've + been used. + + :param block: + If set to True, no more than ``maxsize`` connections will be used at + a time. When no free connections are available, the call will block + until a connection has been released. This is a useful side effect for + particular multithreaded situations where one does not want to use more + than maxsize connections per host to prevent flooding. + + :param headers: + Headers to include with all requests, unless other headers are given + explicitly. + + :param retries: + Retry configuration to use by default with requests in this pool. + + :param _proxy: + Parsed proxy URL, should not be used directly, instead, see + :class:`urllib3.connectionpool.ProxyManager`" + + :param _proxy_headers: + A dictionary with proxy headers, should not be used directly, + instead, see :class:`urllib3.connectionpool.ProxyManager`" + + :param \\**conn_kw: + Additional parameters are used to create fresh :class:`urllib3.connection.HTTPConnection`, + :class:`urllib3.connection.HTTPSConnection` instances. + """ + + scheme = 'http' + ConnectionCls = HTTPConnection + ResponseCls = HTTPResponse + + def __init__(self, host, port=None, strict=False, + timeout=Timeout.DEFAULT_TIMEOUT, maxsize=1, block=False, + headers=None, retries=None, + _proxy=None, _proxy_headers=None, + **conn_kw): + ConnectionPool.__init__(self, host, port) + RequestMethods.__init__(self, headers) + + self.strict = strict + + if not isinstance(timeout, Timeout): + timeout = Timeout.from_float(timeout) + + if retries is None: + retries = Retry.DEFAULT + + self.timeout = timeout + self.retries = retries + + self.pool = self.QueueCls(maxsize) + self.block = block + + self.proxy = _proxy + self.proxy_headers = _proxy_headers or {} + + # Fill the queue up so that doing get() on it will block properly + for _ in xrange(maxsize): + self.pool.put(None) + + # These are mostly for testing and debugging purposes. + self.num_connections = 0 + self.num_requests = 0 + self.conn_kw = conn_kw + + if self.proxy: + # Enable Nagle's algorithm for proxies, to avoid packet fragmentation. + # We cannot know if the user has added default socket options, so we cannot replace the + # list. + self.conn_kw.setdefault('socket_options', []) + + def _new_conn(self): + """ + Return a fresh :class:`HTTPConnection`. + """ + self.num_connections += 1 + log.debug("Starting new HTTP connection (%d): %s", + self.num_connections, self.host) + + conn = self.ConnectionCls(host=self.host, port=self.port, + timeout=self.timeout.connect_timeout, + strict=self.strict, **self.conn_kw) + return conn + + def _get_conn(self, timeout=None): + """ + Get a connection. Will return a pooled connection if one is available. + + If no connections are available and :prop:`.block` is ``False``, then a + fresh connection is returned. + + :param timeout: + Seconds to wait before giving up and raising + :class:`urllib3.exceptions.EmptyPoolError` if the pool is empty and + :prop:`.block` is ``True``. + """ + conn = None + try: + conn = self.pool.get(block=self.block, timeout=timeout) + + except AttributeError: # self.pool is None + raise ClosedPoolError(self, "Pool is closed.") + + except queue.Empty: + if self.block: + raise EmptyPoolError(self, + "Pool reached maximum size and no more " + "connections are allowed.") + pass # Oh well, we'll create a new connection then + + # If this is a persistent connection, check if it got disconnected + if conn and is_connection_dropped(conn): + log.debug("Resetting dropped connection: %s", self.host) + conn.close() + if getattr(conn, 'auto_open', 1) == 0: + # This is a proxied connection that has been mutated by + # httplib._tunnel() and cannot be reused (since it would + # attempt to bypass the proxy) + conn = None + + return conn or self._new_conn() + + def _put_conn(self, conn): + """ + Put a connection back into the pool. + + :param conn: + Connection object for the current host and port as returned by + :meth:`._new_conn` or :meth:`._get_conn`. + + If the pool is already full, the connection is closed and discarded + because we exceeded maxsize. If connections are discarded frequently, + then maxsize should be increased. + + If the pool is closed, then the connection will be closed and discarded. + """ + try: + self.pool.put(conn, block=False) + return # Everything is dandy, done. + except AttributeError: + # self.pool is None. + pass + except queue.Full: + # This should never happen if self.block == True + log.warning( + "Connection pool is full, discarding connection: %s", + self.host) + + # Connection never got put back into the pool, close it. + if conn: + conn.close() + + def _validate_conn(self, conn): + """ + Called right before a request is made, after the socket is created. + """ + # Force connect early to allow us to set read timeout in time + if not getattr(conn, 'sock', None): # AppEngine might not have `.sock` + conn.connect() + + def _prepare_proxy(self, conn): + # Nothing to do for HTTP connections. + pass + + def _get_timeout(self, timeout): + """ Helper that always returns a :class:`urllib3.util.Timeout` """ + if timeout is _Default: + return self.timeout.clone() + + if isinstance(timeout, Timeout): + return timeout.clone() + else: + # User passed us an int/float. This is for backwards compatibility, + # can be removed later + return Timeout.from_float(timeout) + + def _raise_timeout(self, err, url, timeout_value, exc_cls): + """Is the error actually a timeout? Will raise a ReadTimeout or pass""" + + # exc_cls is either ReadTimeoutError or ConnectTimeoutError + # Only ReadTimeoutError requires the url (preserving old behaviour) + args = [self] + if exc_cls is ReadTimeoutError: + args.append(url) + desc = 'Read' + else: + desc = 'Connect' + + if isinstance(err, SocketTimeout): + args.append("%s timed out. (%s timeout=%s)" % (desc, desc.lower(), timeout_value)) + raise exc_cls(*args) + + # See the above comment about EAGAIN in Python 3. In Python 2 we have + # to specifically catch it and throw the timeout error + elif hasattr(err, 'errno') and err.errno in _blocking_errnos: + args.append("%s timed out. (%s timeout=%s)" % (desc, desc.lower(), timeout_value)) + raise exc_cls(*args) + + # Catch possible read timeouts thrown as SSL errors. If not the + # case, rethrow the original. We need to do this because of: + # http://bugs.python.org/issue10272 + elif 'timed out' in str(err) or 'did not complete (read)' in str(err): # Python 2.6 + args.append("%s timed out. (%s timeout=%s)" % (desc, desc.lower(), timeout_value)) + raise exc_cls(*args) + + def _make_request(self, conn, method, url, timeout=_Default, chunked=False, + **httplib_request_kw): + """ + Perform a request on a given urllib connection object taken from our + pool. + + :param conn: + a connection from one of our connection pools + + :param timeout: + Socket timeout in seconds for the request. This can be a + float or integer, which will set the same timeout value for + the socket connect and the socket read, or an instance of + :class:`urllib3.util.Timeout`, which gives you more fine-grained + control over your timeouts. + """ + self.num_requests += 1 + + timeout_obj = self._get_timeout(timeout) + timeout_obj.start_connect() + conn.timeout = timeout_obj.connect_timeout + + # Trigger any extra validation we need to do. + try: + self._validate_conn(conn) + except (SocketTimeout, BaseSSLError) as e: + # Py2 raises this as a BaseSSLError, Py3 raises it as socket timeout. + self._raise_timeout(err=e, url=url, timeout_value=conn.timeout, + exc_cls=ConnectTimeoutError) + raise + + # Reset the timeout for the recv() on the socket + read_timeout = timeout_obj.read_timeout + + # App Engine doesn't have a sock attr + if getattr(conn, 'sock', None): + # In Python 3 socket.py will catch EAGAIN and return None when you + # try and read into the file pointer created by http.client, which + # instead raises a BadStatusLine exception. Instead of catching + # the exception and assuming all BadStatusLine exceptions are read + # timeouts, check for a zero timeout before making the request. + if read_timeout == 0: + raise ReadTimeoutError( + self, url, "Read timed out. (read timeout=%s)" % read_timeout) + if read_timeout is Timeout.DEFAULT_TIMEOUT: + conn.sock.settimeout(socket.getdefaulttimeout()) + else: # None or a value + conn.sock.settimeout(read_timeout) + + # conn.request() calls httplib.*.request, not the method in + # urllib3.request. It also calls makefile (recv) on the socket. + if chunked: + conn.request_chunked(method, url, **httplib_request_kw) + else: + conn.request(method, url, **httplib_request_kw) + + # Receive the response from the server + try: + try: # Python 2.7, use buffering of HTTP responses + httplib_response = conn.getresponse(buffering=True) + except TypeError: # Python 2.6 and older, Python 3 + try: + httplib_response = conn.getresponse() + except Exception as e: + # Remove the TypeError from the exception chain in Python 3; + # otherwise it looks like a programming error was the cause. + six.raise_from(e, None) + except (SocketTimeout, BaseSSLError, SocketError) as e: + self._raise_timeout(err=e, url=url, timeout_value=read_timeout, + exc_cls=ReadTimeoutError) + raise + + # AppEngine doesn't have a version attr. + http_version = getattr(conn, '_http_vsn_str', 'HTTP/?') + log.debug("%s://%s:%s \"%s %s %s\" %s %s", self.scheme, self.host, self.port, + method, url, http_version, httplib_response.status, + httplib_response.length) + + try: + assert_header_parsing(httplib_response.msg) + except HeaderParsingError as hpe: # Platform-specific: Python 3 + log.warning( + 'Failed to parse headers (url=%s): %s', + self._absolute_url(url), hpe, exc_info=True) + + return httplib_response + + def _absolute_url(self, path): + return Url(scheme=self.scheme, host=self.host, port=self.port, path=path).url + + def close(self): + """ + Close all pooled connections and disable the pool. + """ + # Disable access to the pool + old_pool, self.pool = self.pool, None + + try: + while True: + conn = old_pool.get(block=False) + if conn: + conn.close() + + except queue.Empty: + pass # Done. + + def is_same_host(self, url): + """ + Check if the given ``url`` is a member of the same host as this + connection pool. + """ + if url.startswith('/'): + return True + + # TODO: Add optional support for socket.gethostbyname checking. + scheme, host, port = get_host(url) + + host = _ipv6_host(host).lower() + + # Use explicit default port for comparison when none is given + if self.port and not port: + port = port_by_scheme.get(scheme) + elif not self.port and port == port_by_scheme.get(scheme): + port = None + + return (scheme, host, port) == (self.scheme, self.host, self.port) + + def urlopen(self, method, url, body=None, headers=None, retries=None, + redirect=True, assert_same_host=True, timeout=_Default, + pool_timeout=None, release_conn=None, chunked=False, + body_pos=None, **response_kw): + """ + Get a connection from the pool and perform an HTTP request. This is the + lowest level call for making a request, so you'll need to specify all + the raw details. + + .. note:: + + More commonly, it's appropriate to use a convenience method provided + by :class:`.RequestMethods`, such as :meth:`request`. + + .. note:: + + `release_conn` will only behave as expected if + `preload_content=False` because we want to make + `preload_content=False` the default behaviour someday soon without + breaking backwards compatibility. + + :param method: + HTTP request method (such as GET, POST, PUT, etc.) + + :param body: + Data to send in the request body (useful for creating + POST requests, see HTTPConnectionPool.post_url for + more convenience). + + :param headers: + Dictionary of custom headers to send, such as User-Agent, + If-None-Match, etc. If None, pool headers are used. If provided, + these headers completely replace any pool-specific headers. + + :param retries: + Configure the number of retries to allow before raising a + :class:`~urllib3.exceptions.MaxRetryError` exception. + + Pass ``None`` to retry until you receive a response. Pass a + :class:`~urllib3.util.retry.Retry` object for fine-grained control + over different types of retries. + Pass an integer number to retry connection errors that many times, + but no other types of errors. Pass zero to never retry. + + If ``False``, then retries are disabled and any exception is raised + immediately. Also, instead of raising a MaxRetryError on redirects, + the redirect response will be returned. + + :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int. + + :param redirect: + If True, automatically handle redirects (status codes 301, 302, + 303, 307, 308). Each redirect counts as a retry. Disabling retries + will disable redirect, too. + + :param assert_same_host: + If ``True``, will make sure that the host of the pool requests is + consistent else will raise HostChangedError. When False, you can + use the pool on an HTTP proxy and request foreign hosts. + + :param timeout: + If specified, overrides the default timeout for this one + request. It may be a float (in seconds) or an instance of + :class:`urllib3.util.Timeout`. + + :param pool_timeout: + If set and the pool is set to block=True, then this method will + block for ``pool_timeout`` seconds and raise EmptyPoolError if no + connection is available within the time period. + + :param release_conn: + If False, then the urlopen call will not release the connection + back into the pool once a response is received (but will release if + you read the entire contents of the response such as when + `preload_content=True`). This is useful if you're not preloading + the response's content immediately. You will need to call + ``r.release_conn()`` on the response ``r`` to return the connection + back into the pool. If None, it takes the value of + ``response_kw.get('preload_content', True)``. + + :param chunked: + If True, urllib3 will send the body using chunked transfer + encoding. Otherwise, urllib3 will send the body using the standard + content-length form. Defaults to False. + + :param int body_pos: + Position to seek to in file-like body in the event of a retry or + redirect. Typically this won't need to be set because urllib3 will + auto-populate the value when needed. + + :param \\**response_kw: + Additional parameters are passed to + :meth:`urllib3.response.HTTPResponse.from_httplib` + """ + if headers is None: + headers = self.headers + + if not isinstance(retries, Retry): + retries = Retry.from_int(retries, redirect=redirect, default=self.retries) + + if release_conn is None: + release_conn = response_kw.get('preload_content', True) + + # Check host + if assert_same_host and not self.is_same_host(url): + raise HostChangedError(self, url, retries) + + conn = None + + # Track whether `conn` needs to be released before + # returning/raising/recursing. Update this variable if necessary, and + # leave `release_conn` constant throughout the function. That way, if + # the function recurses, the original value of `release_conn` will be + # passed down into the recursive call, and its value will be respected. + # + # See issue #651 [1] for details. + # + # [1] <https://github.com/shazow/urllib3/issues/651> + release_this_conn = release_conn + + # Merge the proxy headers. Only do this in HTTP. We have to copy the + # headers dict so we can safely change it without those changes being + # reflected in anyone else's copy. + if self.scheme == 'http': + headers = headers.copy() + headers.update(self.proxy_headers) + + # Must keep the exception bound to a separate variable or else Python 3 + # complains about UnboundLocalError. + err = None + + # Keep track of whether we cleanly exited the except block. This + # ensures we do proper cleanup in finally. + clean_exit = False + + # Rewind body position, if needed. Record current position + # for future rewinds in the event of a redirect/retry. + body_pos = set_file_position(body, body_pos) + + try: + # Request a connection from the queue. + timeout_obj = self._get_timeout(timeout) + conn = self._get_conn(timeout=pool_timeout) + + conn.timeout = timeout_obj.connect_timeout + + is_new_proxy_conn = self.proxy is not None and not getattr(conn, 'sock', None) + if is_new_proxy_conn: + self._prepare_proxy(conn) + + # Make the request on the httplib connection object. + httplib_response = self._make_request(conn, method, url, + timeout=timeout_obj, + body=body, headers=headers, + chunked=chunked) + + # If we're going to release the connection in ``finally:``, then + # the response doesn't need to know about the connection. Otherwise + # it will also try to release it and we'll have a double-release + # mess. + response_conn = conn if not release_conn else None + + # Pass method to Response for length checking + response_kw['request_method'] = method + + # Import httplib's response into our own wrapper object + response = self.ResponseCls.from_httplib(httplib_response, + pool=self, + connection=response_conn, + retries=retries, + **response_kw) + + # Everything went great! + clean_exit = True + + except queue.Empty: + # Timed out by queue. + raise EmptyPoolError(self, "No pool connections are available.") + + except (BaseSSLError, CertificateError) as e: + # Close the connection. If a connection is reused on which there + # was a Certificate error, the next request will certainly raise + # another Certificate error. + clean_exit = False + raise SSLError(e) + + except SSLError: + # Treat SSLError separately from BaseSSLError to preserve + # traceback. + clean_exit = False + raise + + except (TimeoutError, HTTPException, SocketError, ProtocolError) as e: + # Discard the connection for these exceptions. It will be + # be replaced during the next _get_conn() call. + clean_exit = False + + if isinstance(e, (SocketError, NewConnectionError)) and self.proxy: + e = ProxyError('Cannot connect to proxy.', e) + elif isinstance(e, (SocketError, HTTPException)): + e = ProtocolError('Connection aborted.', e) + + retries = retries.increment(method, url, error=e, _pool=self, + _stacktrace=sys.exc_info()[2]) + retries.sleep() + + # Keep track of the error for the retry warning. + err = e + + finally: + if not clean_exit: + # We hit some kind of exception, handled or otherwise. We need + # to throw the connection away unless explicitly told not to. + # Close the connection, set the variable to None, and make sure + # we put the None back in the pool to avoid leaking it. + conn = conn and conn.close() + release_this_conn = True + + if release_this_conn: + # Put the connection back to be reused. If the connection is + # expired then it will be None, which will get replaced with a + # fresh connection during _get_conn. + self._put_conn(conn) + + if not conn: + # Try again + log.warning("Retrying (%r) after connection " + "broken by '%r': %s", retries, err, url) + return self.urlopen(method, url, body, headers, retries, + redirect, assert_same_host, + timeout=timeout, pool_timeout=pool_timeout, + release_conn=release_conn, body_pos=body_pos, + **response_kw) + + # Handle redirect? + redirect_location = redirect and response.get_redirect_location() + if redirect_location: + if response.status == 303: + method = 'GET' + + try: + retries = retries.increment(method, url, response=response, _pool=self) + except MaxRetryError: + if retries.raise_on_redirect: + # Release the connection for this response, since we're not + # returning it to be released manually. + response.release_conn() + raise + return response + + retries.sleep_for_retry(response) + log.debug("Redirecting %s -> %s", url, redirect_location) + return self.urlopen( + method, redirect_location, body, headers, + retries=retries, redirect=redirect, + assert_same_host=assert_same_host, + timeout=timeout, pool_timeout=pool_timeout, + release_conn=release_conn, body_pos=body_pos, + **response_kw) + + # Check if we should retry the HTTP response. + has_retry_after = bool(response.getheader('Retry-After')) + if retries.is_retry(method, response.status, has_retry_after): + try: + retries = retries.increment(method, url, response=response, _pool=self) + except MaxRetryError: + if retries.raise_on_status: + # Release the connection for this response, since we're not + # returning it to be released manually. + response.release_conn() + raise + return response + retries.sleep(response) + log.debug("Retry: %s", url) + return self.urlopen( + method, url, body, headers, + retries=retries, redirect=redirect, + assert_same_host=assert_same_host, + timeout=timeout, pool_timeout=pool_timeout, + release_conn=release_conn, + body_pos=body_pos, **response_kw) + + return response + + +class HTTPSConnectionPool(HTTPConnectionPool): + """ + Same as :class:`.HTTPConnectionPool`, but HTTPS. + + When Python is compiled with the :mod:`ssl` module, then + :class:`.VerifiedHTTPSConnection` is used, which *can* verify certificates, + instead of :class:`.HTTPSConnection`. + + :class:`.VerifiedHTTPSConnection` uses one of ``assert_fingerprint``, + ``assert_hostname`` and ``host`` in this order to verify connections. + If ``assert_hostname`` is False, no verification is done. + + The ``key_file``, ``cert_file``, ``cert_reqs``, ``ca_certs``, + ``ca_cert_dir``, and ``ssl_version`` are only used if :mod:`ssl` is + available and are fed into :meth:`urllib3.util.ssl_wrap_socket` to upgrade + the connection socket into an SSL socket. + """ + + scheme = 'https' + ConnectionCls = HTTPSConnection + + def __init__(self, host, port=None, + strict=False, timeout=Timeout.DEFAULT_TIMEOUT, maxsize=1, + block=False, headers=None, retries=None, + _proxy=None, _proxy_headers=None, + key_file=None, cert_file=None, cert_reqs=None, + ca_certs=None, ssl_version=None, + assert_hostname=None, assert_fingerprint=None, + ca_cert_dir=None, **conn_kw): + + HTTPConnectionPool.__init__(self, host, port, strict, timeout, maxsize, + block, headers, retries, _proxy, _proxy_headers, + **conn_kw) + + if ca_certs and cert_reqs is None: + cert_reqs = 'CERT_REQUIRED' + + self.key_file = key_file + self.cert_file = cert_file + self.cert_reqs = cert_reqs + self.ca_certs = ca_certs + self.ca_cert_dir = ca_cert_dir + self.ssl_version = ssl_version + self.assert_hostname = assert_hostname + self.assert_fingerprint = assert_fingerprint + + def _prepare_conn(self, conn): + """ + Prepare the ``connection`` for :meth:`urllib3.util.ssl_wrap_socket` + and establish the tunnel if proxy is used. + """ + + if isinstance(conn, VerifiedHTTPSConnection): + conn.set_cert(key_file=self.key_file, + cert_file=self.cert_file, + cert_reqs=self.cert_reqs, + ca_certs=self.ca_certs, + ca_cert_dir=self.ca_cert_dir, + assert_hostname=self.assert_hostname, + assert_fingerprint=self.assert_fingerprint) + conn.ssl_version = self.ssl_version + return conn + + def _prepare_proxy(self, conn): + """ + Establish tunnel connection early, because otherwise httplib + would improperly set Host: header to proxy's IP:port. + """ + # Python 2.7+ + try: + set_tunnel = conn.set_tunnel + except AttributeError: # Platform-specific: Python 2.6 + set_tunnel = conn._set_tunnel + + if sys.version_info <= (2, 6, 4) and not self.proxy_headers: # Python 2.6.4 and older + set_tunnel(self.host, self.port) + else: + set_tunnel(self.host, self.port, self.proxy_headers) + + conn.connect() + + def _new_conn(self): + """ + Return a fresh :class:`httplib.HTTPSConnection`. + """ + self.num_connections += 1 + log.debug("Starting new HTTPS connection (%d): %s", + self.num_connections, self.host) + + if not self.ConnectionCls or self.ConnectionCls is DummyConnection: + raise SSLError("Can't connect to HTTPS URL because the SSL " + "module is not available.") + + actual_host = self.host + actual_port = self.port + if self.proxy is not None: + actual_host = self.proxy.host + actual_port = self.proxy.port + + conn = self.ConnectionCls(host=actual_host, port=actual_port, + timeout=self.timeout.connect_timeout, + strict=self.strict, **self.conn_kw) + + return self._prepare_conn(conn) + + def _validate_conn(self, conn): + """ + Called right before a request is made, after the socket is created. + """ + super(HTTPSConnectionPool, self)._validate_conn(conn) + + if not conn.is_verified: + warnings.warn(( + 'Unverified HTTPS request is being made. ' + 'Adding certificate verification is strongly advised. See: ' + 'https://urllib3.readthedocs.io/en/latest/advanced-usage.html' + '#ssl-warnings'), + InsecureRequestWarning) + + +def connection_from_url(url, **kw): + """ + Given a url, return an :class:`.ConnectionPool` instance of its host. + + This is a shortcut for not having to parse out the scheme, host, and port + of the url before creating an :class:`.ConnectionPool` instance. + + :param url: + Absolute URL string that must include the scheme. Port is optional. + + :param \\**kw: + Passes additional parameters to the constructor of the appropriate + :class:`.ConnectionPool`. Useful for specifying things like + timeout, maxsize, headers, etc. + + Example:: + + >>> conn = connection_from_url('http://google.com/') + >>> r = conn.request('GET', '/') + """ + scheme, host, port = get_host(url) + port = port or port_by_scheme.get(scheme, 80) + if scheme == 'https': + return HTTPSConnectionPool(host, port=port, **kw) + else: + return HTTPConnectionPool(host, port=port, **kw) + + +def _ipv6_host(host): + """ + Process IPv6 address literals + """ + + # httplib doesn't like it when we include brackets in IPv6 addresses + # Specifically, if we include brackets but also pass the port then + # httplib crazily doubles up the square brackets on the Host header. + # Instead, we need to make sure we never pass ``None`` as the port. + # However, for backward compatibility reasons we can't actually + # *assert* that. See http://bugs.python.org/issue28539 + # + # Also if an IPv6 address literal has a zone identifier, the + # percent sign might be URIencoded, convert it back into ASCII + if host.startswith('[') and host.endswith(']'): + host = host.replace('%25', '%').strip('[]') + return host diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/contrib/__init__.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/contrib/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/contrib/appengine.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/contrib/appengine.py new file mode 100644 index 0000000..814b022 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/contrib/appengine.py @@ -0,0 +1,296 @@ +""" +This module provides a pool manager that uses Google App Engine's +`URLFetch Service <https://cloud.google.com/appengine/docs/python/urlfetch>`_. + +Example usage:: + + from urllib3 import PoolManager + from urllib3.contrib.appengine import AppEngineManager, is_appengine_sandbox + + if is_appengine_sandbox(): + # AppEngineManager uses AppEngine's URLFetch API behind the scenes + http = AppEngineManager() + else: + # PoolManager uses a socket-level API behind the scenes + http = PoolManager() + + r = http.request('GET', 'https://google.com/') + +There are `limitations <https://cloud.google.com/appengine/docs/python/\ +urlfetch/#Python_Quotas_and_limits>`_ to the URLFetch service and it may not be +the best choice for your application. There are three options for using +urllib3 on Google App Engine: + +1. You can use :class:`AppEngineManager` with URLFetch. URLFetch is + cost-effective in many circumstances as long as your usage is within the + limitations. +2. You can use a normal :class:`~urllib3.PoolManager` by enabling sockets. + Sockets also have `limitations and restrictions + <https://cloud.google.com/appengine/docs/python/sockets/\ + #limitations-and-restrictions>`_ and have a lower free quota than URLFetch. + To use sockets, be sure to specify the following in your ``app.yaml``:: + + env_variables: + GAE_USE_SOCKETS_HTTPLIB : 'true' + +3. If you are using `App Engine Flexible +<https://cloud.google.com/appengine/docs/flexible/>`_, you can use the standard +:class:`PoolManager` without any configuration or special environment variables. +""" + +from __future__ import absolute_import +import logging +import os +import warnings +from ..packages.six.moves.urllib.parse import urljoin + +from ..exceptions import ( + HTTPError, + HTTPWarning, + MaxRetryError, + ProtocolError, + TimeoutError, + SSLError +) + +from ..packages.six import BytesIO +from ..request import RequestMethods +from ..response import HTTPResponse +from ..util.timeout import Timeout +from ..util.retry import Retry + +try: + from google.appengine.api import urlfetch +except ImportError: + urlfetch = None + + +log = logging.getLogger(__name__) + + +class AppEnginePlatformWarning(HTTPWarning): + pass + + +class AppEnginePlatformError(HTTPError): + pass + + +class AppEngineManager(RequestMethods): + """ + Connection manager for Google App Engine sandbox applications. + + This manager uses the URLFetch service directly instead of using the + emulated httplib, and is subject to URLFetch limitations as described in + the App Engine documentation `here + <https://cloud.google.com/appengine/docs/python/urlfetch>`_. + + Notably it will raise an :class:`AppEnginePlatformError` if: + * URLFetch is not available. + * If you attempt to use this on App Engine Flexible, as full socket + support is available. + * If a request size is more than 10 megabytes. + * If a response size is more than 32 megabtyes. + * If you use an unsupported request method such as OPTIONS. + + Beyond those cases, it will raise normal urllib3 errors. + """ + + def __init__(self, headers=None, retries=None, validate_certificate=True, + urlfetch_retries=True): + if not urlfetch: + raise AppEnginePlatformError( + "URLFetch is not available in this environment.") + + if is_prod_appengine_mvms(): + raise AppEnginePlatformError( + "Use normal urllib3.PoolManager instead of AppEngineManager" + "on Managed VMs, as using URLFetch is not necessary in " + "this environment.") + + warnings.warn( + "urllib3 is using URLFetch on Google App Engine sandbox instead " + "of sockets. To use sockets directly instead of URLFetch see " + "https://urllib3.readthedocs.io/en/latest/reference/urllib3.contrib.html.", + AppEnginePlatformWarning) + + RequestMethods.__init__(self, headers) + self.validate_certificate = validate_certificate + self.urlfetch_retries = urlfetch_retries + + self.retries = retries or Retry.DEFAULT + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + # Return False to re-raise any potential exceptions + return False + + def urlopen(self, method, url, body=None, headers=None, + retries=None, redirect=True, timeout=Timeout.DEFAULT_TIMEOUT, + **response_kw): + + retries = self._get_retries(retries, redirect) + + try: + follow_redirects = ( + redirect and + retries.redirect != 0 and + retries.total) + response = urlfetch.fetch( + url, + payload=body, + method=method, + headers=headers or {}, + allow_truncated=False, + follow_redirects=self.urlfetch_retries and follow_redirects, + deadline=self._get_absolute_timeout(timeout), + validate_certificate=self.validate_certificate, + ) + except urlfetch.DeadlineExceededError as e: + raise TimeoutError(self, e) + + except urlfetch.InvalidURLError as e: + if 'too large' in str(e): + raise AppEnginePlatformError( + "URLFetch request too large, URLFetch only " + "supports requests up to 10mb in size.", e) + raise ProtocolError(e) + + except urlfetch.DownloadError as e: + if 'Too many redirects' in str(e): + raise MaxRetryError(self, url, reason=e) + raise ProtocolError(e) + + except urlfetch.ResponseTooLargeError as e: + raise AppEnginePlatformError( + "URLFetch response too large, URLFetch only supports" + "responses up to 32mb in size.", e) + + except urlfetch.SSLCertificateError as e: + raise SSLError(e) + + except urlfetch.InvalidMethodError as e: + raise AppEnginePlatformError( + "URLFetch does not support method: %s" % method, e) + + http_response = self._urlfetch_response_to_http_response( + response, retries=retries, **response_kw) + + # Handle redirect? + redirect_location = redirect and http_response.get_redirect_location() + if redirect_location: + # Check for redirect response + if (self.urlfetch_retries and retries.raise_on_redirect): + raise MaxRetryError(self, url, "too many redirects") + else: + if http_response.status == 303: + method = 'GET' + + try: + retries = retries.increment(method, url, response=http_response, _pool=self) + except MaxRetryError: + if retries.raise_on_redirect: + raise MaxRetryError(self, url, "too many redirects") + return http_response + + retries.sleep_for_retry(http_response) + log.debug("Redirecting %s -> %s", url, redirect_location) + redirect_url = urljoin(url, redirect_location) + return self.urlopen( + method, redirect_url, body, headers, + retries=retries, redirect=redirect, + timeout=timeout, **response_kw) + + # Check if we should retry the HTTP response. + has_retry_after = bool(http_response.getheader('Retry-After')) + if retries.is_retry(method, http_response.status, has_retry_after): + retries = retries.increment( + method, url, response=http_response, _pool=self) + log.debug("Retry: %s", url) + retries.sleep(http_response) + return self.urlopen( + method, url, + body=body, headers=headers, + retries=retries, redirect=redirect, + timeout=timeout, **response_kw) + + return http_response + + def _urlfetch_response_to_http_response(self, urlfetch_resp, **response_kw): + + if is_prod_appengine(): + # Production GAE handles deflate encoding automatically, but does + # not remove the encoding header. + content_encoding = urlfetch_resp.headers.get('content-encoding') + + if content_encoding == 'deflate': + del urlfetch_resp.headers['content-encoding'] + + transfer_encoding = urlfetch_resp.headers.get('transfer-encoding') + # We have a full response's content, + # so let's make sure we don't report ourselves as chunked data. + if transfer_encoding == 'chunked': + encodings = transfer_encoding.split(",") + encodings.remove('chunked') + urlfetch_resp.headers['transfer-encoding'] = ','.join(encodings) + + return HTTPResponse( + # In order for decoding to work, we must present the content as + # a file-like object. + body=BytesIO(urlfetch_resp.content), + headers=urlfetch_resp.headers, + status=urlfetch_resp.status_code, + **response_kw + ) + + def _get_absolute_timeout(self, timeout): + if timeout is Timeout.DEFAULT_TIMEOUT: + return None # Defer to URLFetch's default. + if isinstance(timeout, Timeout): + if timeout._read is not None or timeout._connect is not None: + warnings.warn( + "URLFetch does not support granular timeout settings, " + "reverting to total or default URLFetch timeout.", + AppEnginePlatformWarning) + return timeout.total + return timeout + + def _get_retries(self, retries, redirect): + if not isinstance(retries, Retry): + retries = Retry.from_int( + retries, redirect=redirect, default=self.retries) + + if retries.connect or retries.read or retries.redirect: + warnings.warn( + "URLFetch only supports total retries and does not " + "recognize connect, read, or redirect retry parameters.", + AppEnginePlatformWarning) + + return retries + + +def is_appengine(): + return (is_local_appengine() or + is_prod_appengine() or + is_prod_appengine_mvms()) + + +def is_appengine_sandbox(): + return is_appengine() and not is_prod_appengine_mvms() + + +def is_local_appengine(): + return ('APPENGINE_RUNTIME' in os.environ and + 'Development/' in os.environ['SERVER_SOFTWARE']) + + +def is_prod_appengine(): + return ('APPENGINE_RUNTIME' in os.environ and + 'Google App Engine/' in os.environ['SERVER_SOFTWARE'] and + not is_prod_appengine_mvms()) + + +def is_prod_appengine_mvms(): + return os.environ.get('GAE_VM', False) == 'true' diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/contrib/ntlmpool.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/contrib/ntlmpool.py new file mode 100644 index 0000000..642e99e --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/contrib/ntlmpool.py @@ -0,0 +1,112 @@ +""" +NTLM authenticating pool, contributed by erikcederstran + +Issue #10, see: http://code.google.com/p/urllib3/issues/detail?id=10 +""" +from __future__ import absolute_import + +from logging import getLogger +from ntlm import ntlm + +from .. import HTTPSConnectionPool +from ..packages.six.moves.http_client import HTTPSConnection + + +log = getLogger(__name__) + + +class NTLMConnectionPool(HTTPSConnectionPool): + """ + Implements an NTLM authentication version of an urllib3 connection pool + """ + + scheme = 'https' + + def __init__(self, user, pw, authurl, *args, **kwargs): + """ + authurl is a random URL on the server that is protected by NTLM. + user is the Windows user, probably in the DOMAIN\\username format. + pw is the password for the user. + """ + super(NTLMConnectionPool, self).__init__(*args, **kwargs) + self.authurl = authurl + self.rawuser = user + user_parts = user.split('\\', 1) + self.domain = user_parts[0].upper() + self.user = user_parts[1] + self.pw = pw + + def _new_conn(self): + # Performs the NTLM handshake that secures the connection. The socket + # must be kept open while requests are performed. + self.num_connections += 1 + log.debug('Starting NTLM HTTPS connection no. %d: https://%s%s', + self.num_connections, self.host, self.authurl) + + headers = {} + headers['Connection'] = 'Keep-Alive' + req_header = 'Authorization' + resp_header = 'www-authenticate' + + conn = HTTPSConnection(host=self.host, port=self.port) + + # Send negotiation message + headers[req_header] = ( + 'NTLM %s' % ntlm.create_NTLM_NEGOTIATE_MESSAGE(self.rawuser)) + log.debug('Request headers: %s', headers) + conn.request('GET', self.authurl, None, headers) + res = conn.getresponse() + reshdr = dict(res.getheaders()) + log.debug('Response status: %s %s', res.status, res.reason) + log.debug('Response headers: %s', reshdr) + log.debug('Response data: %s [...]', res.read(100)) + + # Remove the reference to the socket, so that it can not be closed by + # the response object (we want to keep the socket open) + res.fp = None + + # Server should respond with a challenge message + auth_header_values = reshdr[resp_header].split(', ') + auth_header_value = None + for s in auth_header_values: + if s[:5] == 'NTLM ': + auth_header_value = s[5:] + if auth_header_value is None: + raise Exception('Unexpected %s response header: %s' % + (resp_header, reshdr[resp_header])) + + # Send authentication message + ServerChallenge, NegotiateFlags = \ + ntlm.parse_NTLM_CHALLENGE_MESSAGE(auth_header_value) + auth_msg = ntlm.create_NTLM_AUTHENTICATE_MESSAGE(ServerChallenge, + self.user, + self.domain, + self.pw, + NegotiateFlags) + headers[req_header] = 'NTLM %s' % auth_msg + log.debug('Request headers: %s', headers) + conn.request('GET', self.authurl, None, headers) + res = conn.getresponse() + log.debug('Response status: %s %s', res.status, res.reason) + log.debug('Response headers: %s', dict(res.getheaders())) + log.debug('Response data: %s [...]', res.read()[:100]) + if res.status != 200: + if res.status == 401: + raise Exception('Server rejected request: wrong ' + 'username or password') + raise Exception('Wrong server response: %s %s' % + (res.status, res.reason)) + + res.fp = None + log.debug('Connection established') + return conn + + def urlopen(self, method, url, body=None, headers=None, retries=3, + redirect=True, assert_same_host=True): + if headers is None: + headers = {} + headers['Connection'] = 'Keep-Alive' + return super(NTLMConnectionPool, self).urlopen(method, url, body, + headers, retries, + redirect, + assert_same_host) diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/contrib/pyopenssl.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/contrib/pyopenssl.py new file mode 100644 index 0000000..eb4d476 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/contrib/pyopenssl.py @@ -0,0 +1,450 @@ +""" +SSL with SNI_-support for Python 2. Follow these instructions if you would +like to verify SSL certificates in Python 2. Note, the default libraries do +*not* do certificate checking; you need to do additional work to validate +certificates yourself. + +This needs the following packages installed: + +* pyOpenSSL (tested with 16.0.0) +* cryptography (minimum 1.3.4, from pyopenssl) +* idna (minimum 2.0, from cryptography) + +However, pyopenssl depends on cryptography, which depends on idna, so while we +use all three directly here we end up having relatively few packages required. + +You can install them with the following command: + + pip install pyopenssl cryptography idna + +To activate certificate checking, call +:func:`~urllib3.contrib.pyopenssl.inject_into_urllib3` from your Python code +before you begin making HTTP requests. This can be done in a ``sitecustomize`` +module, or at any other time before your application begins using ``urllib3``, +like this:: + + try: + import urllib3.contrib.pyopenssl + urllib3.contrib.pyopenssl.inject_into_urllib3() + except ImportError: + pass + +Now you can use :mod:`urllib3` as you normally would, and it will support SNI +when the required modules are installed. + +Activating this module also has the positive side effect of disabling SSL/TLS +compression in Python 2 (see `CRIME attack`_). + +If you want to configure the default list of supported cipher suites, you can +set the ``urllib3.contrib.pyopenssl.DEFAULT_SSL_CIPHER_LIST`` variable. + +.. _sni: https://en.wikipedia.org/wiki/Server_Name_Indication +.. _crime attack: https://en.wikipedia.org/wiki/CRIME_(security_exploit) +""" +from __future__ import absolute_import + +import OpenSSL.SSL +from cryptography import x509 +from cryptography.hazmat.backends.openssl import backend as openssl_backend +from cryptography.hazmat.backends.openssl.x509 import _Certificate + +from socket import timeout, error as SocketError +from io import BytesIO + +try: # Platform-specific: Python 2 + from socket import _fileobject +except ImportError: # Platform-specific: Python 3 + _fileobject = None + from ..packages.backports.makefile import backport_makefile + +import logging +import ssl +import six +import sys + +from .. import util + +__all__ = ['inject_into_urllib3', 'extract_from_urllib3'] + +# SNI always works. +HAS_SNI = True + +# Map from urllib3 to PyOpenSSL compatible parameter-values. +_openssl_versions = { + ssl.PROTOCOL_SSLv23: OpenSSL.SSL.SSLv23_METHOD, + ssl.PROTOCOL_TLSv1: OpenSSL.SSL.TLSv1_METHOD, +} + +if hasattr(ssl, 'PROTOCOL_TLSv1_1') and hasattr(OpenSSL.SSL, 'TLSv1_1_METHOD'): + _openssl_versions[ssl.PROTOCOL_TLSv1_1] = OpenSSL.SSL.TLSv1_1_METHOD + +if hasattr(ssl, 'PROTOCOL_TLSv1_2') and hasattr(OpenSSL.SSL, 'TLSv1_2_METHOD'): + _openssl_versions[ssl.PROTOCOL_TLSv1_2] = OpenSSL.SSL.TLSv1_2_METHOD + +try: + _openssl_versions.update({ssl.PROTOCOL_SSLv3: OpenSSL.SSL.SSLv3_METHOD}) +except AttributeError: + pass + +_stdlib_to_openssl_verify = { + ssl.CERT_NONE: OpenSSL.SSL.VERIFY_NONE, + ssl.CERT_OPTIONAL: OpenSSL.SSL.VERIFY_PEER, + ssl.CERT_REQUIRED: + OpenSSL.SSL.VERIFY_PEER + OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT, +} +_openssl_to_stdlib_verify = dict( + (v, k) for k, v in _stdlib_to_openssl_verify.items() +) + +# OpenSSL will only write 16K at a time +SSL_WRITE_BLOCKSIZE = 16384 + +orig_util_HAS_SNI = util.HAS_SNI +orig_util_SSLContext = util.ssl_.SSLContext + + +log = logging.getLogger(__name__) + + +def inject_into_urllib3(): + 'Monkey-patch urllib3 with PyOpenSSL-backed SSL-support.' + + _validate_dependencies_met() + + util.ssl_.SSLContext = PyOpenSSLContext + util.HAS_SNI = HAS_SNI + util.ssl_.HAS_SNI = HAS_SNI + util.IS_PYOPENSSL = True + util.ssl_.IS_PYOPENSSL = True + + +def extract_from_urllib3(): + 'Undo monkey-patching by :func:`inject_into_urllib3`.' + + util.ssl_.SSLContext = orig_util_SSLContext + util.HAS_SNI = orig_util_HAS_SNI + util.ssl_.HAS_SNI = orig_util_HAS_SNI + util.IS_PYOPENSSL = False + util.ssl_.IS_PYOPENSSL = False + + +def _validate_dependencies_met(): + """ + Verifies that PyOpenSSL's package-level dependencies have been met. + Throws `ImportError` if they are not met. + """ + # Method added in `cryptography==1.1`; not available in older versions + from cryptography.x509.extensions import Extensions + if getattr(Extensions, "get_extension_for_class", None) is None: + raise ImportError("'cryptography' module missing required functionality. " + "Try upgrading to v1.3.4 or newer.") + + # pyOpenSSL 0.14 and above use cryptography for OpenSSL bindings. The _x509 + # attribute is only present on those versions. + from OpenSSL.crypto import X509 + x509 = X509() + if getattr(x509, "_x509", None) is None: + raise ImportError("'pyOpenSSL' module missing required functionality. " + "Try upgrading to v0.14 or newer.") + + +def _dnsname_to_stdlib(name): + """ + Converts a dNSName SubjectAlternativeName field to the form used by the + standard library on the given Python version. + + Cryptography produces a dNSName as a unicode string that was idna-decoded + from ASCII bytes. We need to idna-encode that string to get it back, and + then on Python 3 we also need to convert to unicode via UTF-8 (the stdlib + uses PyUnicode_FromStringAndSize on it, which decodes via UTF-8). + """ + def idna_encode(name): + """ + Borrowed wholesale from the Python Cryptography Project. It turns out + that we can't just safely call `idna.encode`: it can explode for + wildcard names. This avoids that problem. + """ + import idna + + for prefix in [u'*.', u'.']: + if name.startswith(prefix): + name = name[len(prefix):] + return prefix.encode('ascii') + idna.encode(name) + return idna.encode(name) + + name = idna_encode(name) + if sys.version_info >= (3, 0): + name = name.decode('utf-8') + return name + + +def get_subj_alt_name(peer_cert): + """ + Given an PyOpenSSL certificate, provides all the subject alternative names. + """ + # Pass the cert to cryptography, which has much better APIs for this. + # This is technically using private APIs, but should work across all + # relevant versions until PyOpenSSL gets something proper for this. + cert = _Certificate(openssl_backend, peer_cert._x509) + + # We want to find the SAN extension. Ask Cryptography to locate it (it's + # faster than looping in Python) + try: + ext = cert.extensions.get_extension_for_class( + x509.SubjectAlternativeName + ).value + except x509.ExtensionNotFound: + # No such extension, return the empty list. + return [] + except (x509.DuplicateExtension, x509.UnsupportedExtension, + x509.UnsupportedGeneralNameType, UnicodeError) as e: + # A problem has been found with the quality of the certificate. Assume + # no SAN field is present. + log.warning( + "A problem was encountered with the certificate that prevented " + "urllib3 from finding the SubjectAlternativeName field. This can " + "affect certificate validation. The error was %s", + e, + ) + return [] + + # We want to return dNSName and iPAddress fields. We need to cast the IPs + # back to strings because the match_hostname function wants them as + # strings. + # Sadly the DNS names need to be idna encoded and then, on Python 3, UTF-8 + # decoded. This is pretty frustrating, but that's what the standard library + # does with certificates, and so we need to attempt to do the same. + names = [ + ('DNS', _dnsname_to_stdlib(name)) + for name in ext.get_values_for_type(x509.DNSName) + ] + names.extend( + ('IP Address', str(name)) + for name in ext.get_values_for_type(x509.IPAddress) + ) + + return names + + +class WrappedSocket(object): + '''API-compatibility wrapper for Python OpenSSL's Connection-class. + + Note: _makefile_refs, _drop() and _reuse() are needed for the garbage + collector of pypy. + ''' + + def __init__(self, connection, socket, suppress_ragged_eofs=True): + self.connection = connection + self.socket = socket + self.suppress_ragged_eofs = suppress_ragged_eofs + self._makefile_refs = 0 + self._closed = False + + def fileno(self): + return self.socket.fileno() + + # Copy-pasted from Python 3.5 source code + def _decref_socketios(self): + if self._makefile_refs > 0: + self._makefile_refs -= 1 + if self._closed: + self.close() + + def recv(self, *args, **kwargs): + try: + data = self.connection.recv(*args, **kwargs) + except OpenSSL.SSL.SysCallError as e: + if self.suppress_ragged_eofs and e.args == (-1, 'Unexpected EOF'): + return b'' + else: + raise SocketError(str(e)) + except OpenSSL.SSL.ZeroReturnError as e: + if self.connection.get_shutdown() == OpenSSL.SSL.RECEIVED_SHUTDOWN: + return b'' + else: + raise + except OpenSSL.SSL.WantReadError: + rd = util.wait_for_read(self.socket, self.socket.gettimeout()) + if not rd: + raise timeout('The read operation timed out') + else: + return self.recv(*args, **kwargs) + else: + return data + + def recv_into(self, *args, **kwargs): + try: + return self.connection.recv_into(*args, **kwargs) + except OpenSSL.SSL.SysCallError as e: + if self.suppress_ragged_eofs and e.args == (-1, 'Unexpected EOF'): + return 0 + else: + raise SocketError(str(e)) + except OpenSSL.SSL.ZeroReturnError as e: + if self.connection.get_shutdown() == OpenSSL.SSL.RECEIVED_SHUTDOWN: + return 0 + else: + raise + except OpenSSL.SSL.WantReadError: + rd = util.wait_for_read(self.socket, self.socket.gettimeout()) + if not rd: + raise timeout('The read operation timed out') + else: + return self.recv_into(*args, **kwargs) + + def settimeout(self, timeout): + return self.socket.settimeout(timeout) + + def _send_until_done(self, data): + while True: + try: + return self.connection.send(data) + except OpenSSL.SSL.WantWriteError: + wr = util.wait_for_write(self.socket, self.socket.gettimeout()) + if not wr: + raise timeout() + continue + + def sendall(self, data): + total_sent = 0 + while total_sent < len(data): + sent = self._send_until_done(data[total_sent:total_sent + SSL_WRITE_BLOCKSIZE]) + total_sent += sent + + def shutdown(self): + # FIXME rethrow compatible exceptions should we ever use this + self.connection.shutdown() + + def close(self): + if self._makefile_refs < 1: + try: + self._closed = True + return self.connection.close() + except OpenSSL.SSL.Error: + return + else: + self._makefile_refs -= 1 + + def getpeercert(self, binary_form=False): + x509 = self.connection.get_peer_certificate() + + if not x509: + return x509 + + if binary_form: + return OpenSSL.crypto.dump_certificate( + OpenSSL.crypto.FILETYPE_ASN1, + x509) + + return { + 'subject': ( + (('commonName', x509.get_subject().CN),), + ), + 'subjectAltName': get_subj_alt_name(x509) + } + + def _reuse(self): + self._makefile_refs += 1 + + def _drop(self): + if self._makefile_refs < 1: + self.close() + else: + self._makefile_refs -= 1 + + +if _fileobject: # Platform-specific: Python 2 + def makefile(self, mode, bufsize=-1): + self._makefile_refs += 1 + return _fileobject(self, mode, bufsize, close=True) +else: # Platform-specific: Python 3 + makefile = backport_makefile + +WrappedSocket.makefile = makefile + + +class PyOpenSSLContext(object): + """ + I am a wrapper class for the PyOpenSSL ``Context`` object. I am responsible + for translating the interface of the standard library ``SSLContext`` object + to calls into PyOpenSSL. + """ + def __init__(self, protocol): + self.protocol = _openssl_versions[protocol] + self._ctx = OpenSSL.SSL.Context(self.protocol) + self._options = 0 + self.check_hostname = False + + @property + def options(self): + return self._options + + @options.setter + def options(self, value): + self._options = value + self._ctx.set_options(value) + + @property + def verify_mode(self): + return _openssl_to_stdlib_verify[self._ctx.get_verify_mode()] + + @verify_mode.setter + def verify_mode(self, value): + self._ctx.set_verify( + _stdlib_to_openssl_verify[value], + _verify_callback + ) + + def set_default_verify_paths(self): + self._ctx.set_default_verify_paths() + + def set_ciphers(self, ciphers): + if isinstance(ciphers, six.text_type): + ciphers = ciphers.encode('utf-8') + self._ctx.set_cipher_list(ciphers) + + def load_verify_locations(self, cafile=None, capath=None, cadata=None): + if cafile is not None: + cafile = cafile.encode('utf-8') + if capath is not None: + capath = capath.encode('utf-8') + self._ctx.load_verify_locations(cafile, capath) + if cadata is not None: + self._ctx.load_verify_locations(BytesIO(cadata)) + + def load_cert_chain(self, certfile, keyfile=None, password=None): + self._ctx.use_certificate_file(certfile) + if password is not None: + self._ctx.set_passwd_cb(lambda max_length, prompt_twice, userdata: password) + self._ctx.use_privatekey_file(keyfile or certfile) + + def wrap_socket(self, sock, server_side=False, + do_handshake_on_connect=True, suppress_ragged_eofs=True, + server_hostname=None): + cnx = OpenSSL.SSL.Connection(self._ctx, sock) + + if isinstance(server_hostname, six.text_type): # Platform-specific: Python 3 + server_hostname = server_hostname.encode('utf-8') + + if server_hostname is not None: + cnx.set_tlsext_host_name(server_hostname) + + cnx.set_connect_state() + + while True: + try: + cnx.do_handshake() + except OpenSSL.SSL.WantReadError: + rd = util.wait_for_read(sock, sock.gettimeout()) + if not rd: + raise timeout('select timed out') + continue + except OpenSSL.SSL.Error as e: + raise ssl.SSLError('bad handshake: %r' % e) + break + + return WrappedSocket(cnx, sock) + + +def _verify_callback(cnx, x509, err_no, err_depth, return_code): + return err_no == 0 diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/contrib/socks.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/contrib/socks.py new file mode 100644 index 0000000..811e312 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/contrib/socks.py @@ -0,0 +1,192 @@ +# -*- coding: utf-8 -*- +""" +This module contains provisional support for SOCKS proxies from within +urllib3. This module supports SOCKS4 (specifically the SOCKS4A variant) and +SOCKS5. To enable its functionality, either install PySocks or install this +module with the ``socks`` extra. + +The SOCKS implementation supports the full range of urllib3 features. It also +supports the following SOCKS features: + +- SOCKS4 +- SOCKS4a +- SOCKS5 +- Usernames and passwords for the SOCKS proxy + +Known Limitations: + +- Currently PySocks does not support contacting remote websites via literal + IPv6 addresses. Any such connection attempt will fail. You must use a domain + name. +- Currently PySocks does not support IPv6 connections to the SOCKS proxy. Any + such connection attempt will fail. +""" +from __future__ import absolute_import + +try: + import socks +except ImportError: + import warnings + from ..exceptions import DependencyWarning + + warnings.warn(( + 'SOCKS support in urllib3 requires the installation of optional ' + 'dependencies: specifically, PySocks. For more information, see ' + 'https://urllib3.readthedocs.io/en/latest/contrib.html#socks-proxies' + ), + DependencyWarning + ) + raise + +from socket import error as SocketError, timeout as SocketTimeout + +from ..connection import ( + HTTPConnection, HTTPSConnection +) +from ..connectionpool import ( + HTTPConnectionPool, HTTPSConnectionPool +) +from ..exceptions import ConnectTimeoutError, NewConnectionError +from ..poolmanager import PoolManager +from ..util.url import parse_url + +try: + import ssl +except ImportError: + ssl = None + + +class SOCKSConnection(HTTPConnection): + """ + A plain-text HTTP connection that connects via a SOCKS proxy. + """ + def __init__(self, *args, **kwargs): + self._socks_options = kwargs.pop('_socks_options') + super(SOCKSConnection, self).__init__(*args, **kwargs) + + def _new_conn(self): + """ + Establish a new connection via the SOCKS proxy. + """ + extra_kw = {} + if self.source_address: + extra_kw['source_address'] = self.source_address + + if self.socket_options: + extra_kw['socket_options'] = self.socket_options + + try: + conn = socks.create_connection( + (self.host, self.port), + proxy_type=self._socks_options['socks_version'], + proxy_addr=self._socks_options['proxy_host'], + proxy_port=self._socks_options['proxy_port'], + proxy_username=self._socks_options['username'], + proxy_password=self._socks_options['password'], + proxy_rdns=self._socks_options['rdns'], + timeout=self.timeout, + **extra_kw + ) + + except SocketTimeout as e: + raise ConnectTimeoutError( + self, "Connection to %s timed out. (connect timeout=%s)" % + (self.host, self.timeout)) + + except socks.ProxyError as e: + # This is fragile as hell, but it seems to be the only way to raise + # useful errors here. + if e.socket_err: + error = e.socket_err + if isinstance(error, SocketTimeout): + raise ConnectTimeoutError( + self, + "Connection to %s timed out. (connect timeout=%s)" % + (self.host, self.timeout) + ) + else: + raise NewConnectionError( + self, + "Failed to establish a new connection: %s" % error + ) + else: + raise NewConnectionError( + self, + "Failed to establish a new connection: %s" % e + ) + + except SocketError as e: # Defensive: PySocks should catch all these. + raise NewConnectionError( + self, "Failed to establish a new connection: %s" % e) + + return conn + + +# We don't need to duplicate the Verified/Unverified distinction from +# urllib3/connection.py here because the HTTPSConnection will already have been +# correctly set to either the Verified or Unverified form by that module. This +# means the SOCKSHTTPSConnection will automatically be the correct type. +class SOCKSHTTPSConnection(SOCKSConnection, HTTPSConnection): + pass + + +class SOCKSHTTPConnectionPool(HTTPConnectionPool): + ConnectionCls = SOCKSConnection + + +class SOCKSHTTPSConnectionPool(HTTPSConnectionPool): + ConnectionCls = SOCKSHTTPSConnection + + +class SOCKSProxyManager(PoolManager): + """ + A version of the urllib3 ProxyManager that routes connections via the + defined SOCKS proxy. + """ + pool_classes_by_scheme = { + 'http': SOCKSHTTPConnectionPool, + 'https': SOCKSHTTPSConnectionPool, + } + + def __init__(self, proxy_url, username=None, password=None, + num_pools=10, headers=None, **connection_pool_kw): + parsed = parse_url(proxy_url) + + if username is None and password is None and parsed.auth is not None: + split = parsed.auth.split(':') + if len(split) == 2: + username, password = split + if parsed.scheme == 'socks5': + socks_version = socks.PROXY_TYPE_SOCKS5 + rdns = False + elif parsed.scheme == 'socks5h': + socks_version = socks.PROXY_TYPE_SOCKS5 + rdns = True + elif parsed.scheme == 'socks4': + socks_version = socks.PROXY_TYPE_SOCKS4 + rdns = False + elif parsed.scheme == 'socks4a': + socks_version = socks.PROXY_TYPE_SOCKS4 + rdns = True + else: + raise ValueError( + "Unable to determine SOCKS version from %s" % proxy_url + ) + + self.proxy_url = proxy_url + + socks_options = { + 'socks_version': socks_version, + 'proxy_host': parsed.host, + 'proxy_port': parsed.port, + 'username': username, + 'password': password, + 'rdns': rdns + } + connection_pool_kw['_socks_options'] = socks_options + + super(SOCKSProxyManager, self).__init__( + num_pools, headers, **connection_pool_kw + ) + + self.pool_classes_by_scheme = SOCKSProxyManager.pool_classes_by_scheme diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/exceptions.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/exceptions.py new file mode 100644 index 0000000..6c4be58 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/exceptions.py @@ -0,0 +1,246 @@ +from __future__ import absolute_import +from .packages.six.moves.http_client import ( + IncompleteRead as httplib_IncompleteRead +) +# Base Exceptions + + +class HTTPError(Exception): + "Base exception used by this module." + pass + + +class HTTPWarning(Warning): + "Base warning used by this module." + pass + + +class PoolError(HTTPError): + "Base exception for errors caused within a pool." + def __init__(self, pool, message): + self.pool = pool + HTTPError.__init__(self, "%s: %s" % (pool, message)) + + def __reduce__(self): + # For pickling purposes. + return self.__class__, (None, None) + + +class RequestError(PoolError): + "Base exception for PoolErrors that have associated URLs." + def __init__(self, pool, url, message): + self.url = url + PoolError.__init__(self, pool, message) + + def __reduce__(self): + # For pickling purposes. + return self.__class__, (None, self.url, None) + + +class SSLError(HTTPError): + "Raised when SSL certificate fails in an HTTPS connection." + pass + + +class ProxyError(HTTPError): + "Raised when the connection to a proxy fails." + pass + + +class DecodeError(HTTPError): + "Raised when automatic decoding based on Content-Type fails." + pass + + +class ProtocolError(HTTPError): + "Raised when something unexpected happens mid-request/response." + pass + + +#: Renamed to ProtocolError but aliased for backwards compatibility. +ConnectionError = ProtocolError + + +# Leaf Exceptions + +class MaxRetryError(RequestError): + """Raised when the maximum number of retries is exceeded. + + :param pool: The connection pool + :type pool: :class:`~urllib3.connectionpool.HTTPConnectionPool` + :param string url: The requested Url + :param exceptions.Exception reason: The underlying error + + """ + + def __init__(self, pool, url, reason=None): + self.reason = reason + + message = "Max retries exceeded with url: %s (Caused by %r)" % ( + url, reason) + + RequestError.__init__(self, pool, url, message) + + +class HostChangedError(RequestError): + "Raised when an existing pool gets a request for a foreign host." + + def __init__(self, pool, url, retries=3): + message = "Tried to open a foreign host with url: %s" % url + RequestError.__init__(self, pool, url, message) + self.retries = retries + + +class TimeoutStateError(HTTPError): + """ Raised when passing an invalid state to a timeout """ + pass + + +class TimeoutError(HTTPError): + """ Raised when a socket timeout error occurs. + + Catching this error will catch both :exc:`ReadTimeoutErrors + <ReadTimeoutError>` and :exc:`ConnectTimeoutErrors <ConnectTimeoutError>`. + """ + pass + + +class ReadTimeoutError(TimeoutError, RequestError): + "Raised when a socket timeout occurs while receiving data from a server" + pass + + +# This timeout error does not have a URL attached and needs to inherit from the +# base HTTPError +class ConnectTimeoutError(TimeoutError): + "Raised when a socket timeout occurs while connecting to a server" + pass + + +class NewConnectionError(ConnectTimeoutError, PoolError): + "Raised when we fail to establish a new connection. Usually ECONNREFUSED." + pass + + +class EmptyPoolError(PoolError): + "Raised when a pool runs out of connections and no more are allowed." + pass + + +class ClosedPoolError(PoolError): + "Raised when a request enters a pool after the pool has been closed." + pass + + +class LocationValueError(ValueError, HTTPError): + "Raised when there is something wrong with a given URL input." + pass + + +class LocationParseError(LocationValueError): + "Raised when get_host or similar fails to parse the URL input." + + def __init__(self, location): + message = "Failed to parse: %s" % location + HTTPError.__init__(self, message) + + self.location = location + + +class ResponseError(HTTPError): + "Used as a container for an error reason supplied in a MaxRetryError." + GENERIC_ERROR = 'too many error responses' + SPECIFIC_ERROR = 'too many {status_code} error responses' + + +class SecurityWarning(HTTPWarning): + "Warned when perfoming security reducing actions" + pass + + +class SubjectAltNameWarning(SecurityWarning): + "Warned when connecting to a host with a certificate missing a SAN." + pass + + +class InsecureRequestWarning(SecurityWarning): + "Warned when making an unverified HTTPS request." + pass + + +class SystemTimeWarning(SecurityWarning): + "Warned when system time is suspected to be wrong" + pass + + +class InsecurePlatformWarning(SecurityWarning): + "Warned when certain SSL configuration is not available on a platform." + pass + + +class SNIMissingWarning(HTTPWarning): + "Warned when making a HTTPS request without SNI available." + pass + + +class DependencyWarning(HTTPWarning): + """ + Warned when an attempt is made to import a module with missing optional + dependencies. + """ + pass + + +class ResponseNotChunked(ProtocolError, ValueError): + "Response needs to be chunked in order to read it as chunks." + pass + + +class BodyNotHttplibCompatible(HTTPError): + """ + Body should be httplib.HTTPResponse like (have an fp attribute which + returns raw chunks) for read_chunked(). + """ + pass + + +class IncompleteRead(HTTPError, httplib_IncompleteRead): + """ + Response length doesn't match expected Content-Length + + Subclass of http_client.IncompleteRead to allow int value + for `partial` to avoid creating large objects on streamed + reads. + """ + def __init__(self, partial, expected): + super(IncompleteRead, self).__init__(partial, expected) + + def __repr__(self): + return ('IncompleteRead(%i bytes read, ' + '%i more expected)' % (self.partial, self.expected)) + + +class InvalidHeader(HTTPError): + "The header provided was somehow invalid." + pass + + +class ProxySchemeUnknown(AssertionError, ValueError): + "ProxyManager does not support the supplied scheme" + # TODO(t-8ch): Stop inheriting from AssertionError in v2.0. + + def __init__(self, scheme): + message = "Not supported proxy scheme %s" % scheme + super(ProxySchemeUnknown, self).__init__(message) + + +class HeaderParsingError(HTTPError): + "Raised by assert_header_parsing, but we convert it to a log.warning statement." + def __init__(self, defects, unparsed_data): + message = '%s, unparsed data: %r' % (defects or 'Unknown', unparsed_data) + super(HeaderParsingError, self).__init__(message) + + +class UnrewindableBodyError(HTTPError): + "urllib3 encountered an error when trying to rewind a body" + pass diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/fields.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/fields.py new file mode 100644 index 0000000..19b0ae0 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/fields.py @@ -0,0 +1,178 @@ +from __future__ import absolute_import +import email.utils +import mimetypes + +from .packages import six + + +def guess_content_type(filename, default='application/octet-stream'): + """ + Guess the "Content-Type" of a file. + + :param filename: + The filename to guess the "Content-Type" of using :mod:`mimetypes`. + :param default: + If no "Content-Type" can be guessed, default to `default`. + """ + if filename: + return mimetypes.guess_type(filename)[0] or default + return default + + +def format_header_param(name, value): + """ + Helper function to format and quote a single header parameter. + + Particularly useful for header parameters which might contain + non-ASCII values, like file names. This follows RFC 2231, as + suggested by RFC 2388 Section 4.4. + + :param name: + The name of the parameter, a string expected to be ASCII only. + :param value: + The value of the parameter, provided as a unicode string. + """ + if not any(ch in value for ch in '"\\\r\n'): + result = '%s="%s"' % (name, value) + try: + result.encode('ascii') + except (UnicodeEncodeError, UnicodeDecodeError): + pass + else: + return result + if not six.PY3 and isinstance(value, six.text_type): # Python 2: + value = value.encode('utf-8') + value = email.utils.encode_rfc2231(value, 'utf-8') + value = '%s*=%s' % (name, value) + return value + + +class RequestField(object): + """ + A data container for request body parameters. + + :param name: + The name of this request field. + :param data: + The data/value body. + :param filename: + An optional filename of the request field. + :param headers: + An optional dict-like object of headers to initially use for the field. + """ + def __init__(self, name, data, filename=None, headers=None): + self._name = name + self._filename = filename + self.data = data + self.headers = {} + if headers: + self.headers = dict(headers) + + @classmethod + def from_tuples(cls, fieldname, value): + """ + A :class:`~urllib3.fields.RequestField` factory from old-style tuple parameters. + + Supports constructing :class:`~urllib3.fields.RequestField` from + parameter of key/value strings AND key/filetuple. A filetuple is a + (filename, data, MIME type) tuple where the MIME type is optional. + For example:: + + 'foo': 'bar', + 'fakefile': ('foofile.txt', 'contents of foofile'), + 'realfile': ('barfile.txt', open('realfile').read()), + 'typedfile': ('bazfile.bin', open('bazfile').read(), 'image/jpeg'), + 'nonamefile': 'contents of nonamefile field', + + Field names and filenames must be unicode. + """ + if isinstance(value, tuple): + if len(value) == 3: + filename, data, content_type = value + else: + filename, data = value + content_type = guess_content_type(filename) + else: + filename = None + content_type = None + data = value + + request_param = cls(fieldname, data, filename=filename) + request_param.make_multipart(content_type=content_type) + + return request_param + + def _render_part(self, name, value): + """ + Overridable helper function to format a single header parameter. + + :param name: + The name of the parameter, a string expected to be ASCII only. + :param value: + The value of the parameter, provided as a unicode string. + """ + return format_header_param(name, value) + + def _render_parts(self, header_parts): + """ + Helper function to format and quote a single header. + + Useful for single headers that are composed of multiple items. E.g., + 'Content-Disposition' fields. + + :param header_parts: + A sequence of (k, v) typles or a :class:`dict` of (k, v) to format + as `k1="v1"; k2="v2"; ...`. + """ + parts = [] + iterable = header_parts + if isinstance(header_parts, dict): + iterable = header_parts.items() + + for name, value in iterable: + if value is not None: + parts.append(self._render_part(name, value)) + + return '; '.join(parts) + + def render_headers(self): + """ + Renders the headers for this request field. + """ + lines = [] + + sort_keys = ['Content-Disposition', 'Content-Type', 'Content-Location'] + for sort_key in sort_keys: + if self.headers.get(sort_key, False): + lines.append('%s: %s' % (sort_key, self.headers[sort_key])) + + for header_name, header_value in self.headers.items(): + if header_name not in sort_keys: + if header_value: + lines.append('%s: %s' % (header_name, header_value)) + + lines.append('\r\n') + return '\r\n'.join(lines) + + def make_multipart(self, content_disposition=None, content_type=None, + content_location=None): + """ + Makes this request field into a multipart request field. + + This method overrides "Content-Disposition", "Content-Type" and + "Content-Location" headers to the request parameter. + + :param content_type: + The 'Content-Type' of the request body. + :param content_location: + The 'Content-Location' of the request body. + + """ + self.headers['Content-Disposition'] = content_disposition or 'form-data' + self.headers['Content-Disposition'] += '; '.join([ + '', self._render_parts( + (('name', self._name), ('filename', self._filename)) + ) + ]) + self.headers['Content-Type'] = content_type + self.headers['Content-Location'] = content_location diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/filepost.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/filepost.py new file mode 100644 index 0000000..cd11cee --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/filepost.py @@ -0,0 +1,94 @@ +from __future__ import absolute_import +import codecs + +from uuid import uuid4 +from io import BytesIO + +from .packages import six +from .packages.six import b +from .fields import RequestField + +writer = codecs.lookup('utf-8')[3] + + +def choose_boundary(): + """ + Our embarrassingly-simple replacement for mimetools.choose_boundary. + """ + return uuid4().hex + + +def iter_field_objects(fields): + """ + Iterate over fields. + + Supports list of (k, v) tuples and dicts, and lists of + :class:`~urllib3.fields.RequestField`. + + """ + if isinstance(fields, dict): + i = six.iteritems(fields) + else: + i = iter(fields) + + for field in i: + if isinstance(field, RequestField): + yield field + else: + yield RequestField.from_tuples(*field) + + +def iter_fields(fields): + """ + .. deprecated:: 1.6 + + Iterate over fields. + + The addition of :class:`~urllib3.fields.RequestField` makes this function + obsolete. Instead, use :func:`iter_field_objects`, which returns + :class:`~urllib3.fields.RequestField` objects. + + Supports list of (k, v) tuples and dicts. + """ + if isinstance(fields, dict): + return ((k, v) for k, v in six.iteritems(fields)) + + return ((k, v) for k, v in fields) + + +def encode_multipart_formdata(fields, boundary=None): + """ + Encode a dictionary of ``fields`` using the multipart/form-data MIME format. + + :param fields: + Dictionary of fields or list of (key, :class:`~urllib3.fields.RequestField`). + + :param boundary: + If not specified, then a random boundary will be generated using + :func:`mimetools.choose_boundary`. + """ + body = BytesIO() + if boundary is None: + boundary = choose_boundary() + + for field in iter_field_objects(fields): + body.write(b('--%s\r\n' % (boundary))) + + writer(body).write(field.render_headers()) + data = field.data + + if isinstance(data, int): + data = str(data) # Backwards compatibility + + if isinstance(data, six.text_type): + writer(body).write(data) + else: + body.write(data) + + body.write(b'\r\n') + + body.write(b('--%s--\r\n' % (boundary))) + + content_type = str('multipart/form-data; boundary=%s' % boundary) + + return body.getvalue(), content_type diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/__init__.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/__init__.py new file mode 100644 index 0000000..170e974 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/__init__.py @@ -0,0 +1,5 @@ +from __future__ import absolute_import + +from . import ssl_match_hostname + +__all__ = ('ssl_match_hostname', ) diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/backports/__init__.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/backports/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/backports/makefile.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/backports/makefile.py new file mode 100644 index 0000000..75b80dc --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/backports/makefile.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- +""" +backports.makefile +~~~~~~~~~~~~~~~~~~ + +Backports the Python 3 ``socket.makefile`` method for use with anything that +wants to create a "fake" socket object. +""" +import io + +from socket import SocketIO + + +def backport_makefile(self, mode="r", buffering=None, encoding=None, + errors=None, newline=None): + """ + Backport of ``socket.makefile`` from Python 3.5. + """ + if not set(mode) <= set(["r", "w", "b"]): + raise ValueError( + "invalid mode %r (only r, w, b allowed)" % (mode,) + ) + writing = "w" in mode + reading = "r" in mode or not writing + assert reading or writing + binary = "b" in mode + rawmode = "" + if reading: + rawmode += "r" + if writing: + rawmode += "w" + raw = SocketIO(self, rawmode) + self._makefile_refs += 1 + if buffering is None: + buffering = -1 + if buffering < 0: + buffering = io.DEFAULT_BUFFER_SIZE + if buffering == 0: + if not binary: + raise ValueError("unbuffered streams must be binary") + return raw + if reading and writing: + buffer = io.BufferedRWPair(raw, raw, buffering) + elif reading: + buffer = io.BufferedReader(raw, buffering) + else: + assert writing + buffer = io.BufferedWriter(raw, buffering) + if binary: + return buffer + text = io.TextIOWrapper(buffer, encoding, errors, newline) + text.mode = mode + return text diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/ordered_dict.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/ordered_dict.py new file mode 100644 index 0000000..4479363 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/ordered_dict.py @@ -0,0 +1,259 @@ +# Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy. +# Passes Python2.7's test suite and incorporates all the latest updates. +# Copyright 2009 Raymond Hettinger, released under the MIT License. +# http://code.activestate.com/recipes/576693/ +try: + from thread import get_ident as _get_ident +except ImportError: + from dummy_thread import get_ident as _get_ident + +try: + from _abcoll import KeysView, ValuesView, ItemsView +except ImportError: + pass + + +class OrderedDict(dict): + 'Dictionary that remembers insertion order' + # An inherited dict maps keys to values. + # The inherited dict provides __getitem__, __len__, __contains__, and get. + # The remaining methods are order-aware. + # Big-O running times for all methods are the same as for regular dictionaries. + + # 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). + # Each link is stored as a list of length three: [PREV, NEXT, KEY]. + + def __init__(self, *args, **kwds): + '''Initialize an ordered dictionary. Signature is the same as for + regular dictionaries, but keyword arguments are not recommended + because their insertion order is arbitrary. + + ''' + if len(args) > 1: + raise TypeError('expected at most 1 arguments, got %d' % len(args)) + try: + self.__root + except AttributeError: + self.__root = root = [] # sentinel node + root[:] = [root, root, None] + self.__map = {} + self.__update(*args, **kwds) + + def __setitem__(self, key, value, dict_setitem=dict.__setitem__): + 'od.__setitem__(i, y) <==> od[i]=y' + # Setting a new item creates a new link which goes at the end of the linked + # list, and the inherited dictionary is updated with the new key/value pair. + if key not in self: + root = self.__root + last = root[0] + last[1] = root[0] = self.__map[key] = [last, root, key] + dict_setitem(self, key, value) + + def __delitem__(self, key, dict_delitem=dict.__delitem__): + 'od.__delitem__(y) <==> del od[y]' + # Deleting an existing item uses self.__map to find the link which is + # then removed by updating the links in the predecessor and successor nodes. + dict_delitem(self, key) + link_prev, link_next, key = self.__map.pop(key) + link_prev[1] = link_next + link_next[0] = link_prev + + def __iter__(self): + 'od.__iter__() <==> iter(od)' + root = self.__root + curr = root[1] + while curr is not root: + yield curr[2] + curr = curr[1] + + def __reversed__(self): + 'od.__reversed__() <==> reversed(od)' + root = self.__root + curr = root[0] + while curr is not root: + yield curr[2] + curr = curr[0] + + def clear(self): + 'od.clear() -> None. Remove all items from od.' + try: + for node in self.__map.itervalues(): + del node[:] + root = self.__root + root[:] = [root, root, None] + self.__map.clear() + except AttributeError: + pass + dict.clear(self) + + def popitem(self, last=True): + '''od.popitem() -> (k, v), return and remove a (key, value) pair. + Pairs are returned in LIFO order if last is true or FIFO order if false. + + ''' + if not self: + raise KeyError('dictionary is empty') + root = self.__root + if last: + link = root[0] + link_prev = link[0] + link_prev[1] = root + root[0] = link_prev + else: + link = root[1] + link_next = link[1] + root[1] = link_next + link_next[0] = root + key = link[2] + del self.__map[key] + value = dict.pop(self, key) + return key, value + + # -- the following methods do not depend on the internal structure -- + + def keys(self): + 'od.keys() -> list of keys in od' + return list(self) + + def values(self): + 'od.values() -> list of values in od' + return [self[key] for key in self] + + def items(self): + 'od.items() -> list of (key, value) pairs in od' + return [(key, self[key]) for key in self] + + def iterkeys(self): + 'od.iterkeys() -> an iterator over the keys in od' + return iter(self) + + def itervalues(self): + 'od.itervalues -> an iterator over the values in od' + for k in self: + yield self[k] + + def iteritems(self): + 'od.iteritems -> an iterator over the (key, value) items in od' + for k in self: + yield (k, self[k]) + + def update(*args, **kwds): + '''od.update(E, **F) -> None. Update od from dict/iterable E and F. + + If E is a dict instance, does: for k in E: od[k] = E[k] + If E has a .keys() method, does: for k in E.keys(): od[k] = E[k] + Or if E is an iterable of items, does: for k, v in E: od[k] = v + In either case, this is followed by: for k, v in F.items(): od[k] = v + + ''' + if len(args) > 2: + raise TypeError('update() takes at most 2 positional ' + 'arguments (%d given)' % (len(args),)) + elif not args: + raise TypeError('update() takes at least 1 argument (0 given)') + self = args[0] + # Make progressively weaker assumptions about "other" + other = () + if len(args) == 2: + other = args[1] + if isinstance(other, dict): + for key in other: + self[key] = other[key] + elif hasattr(other, 'keys'): + for key in other.keys(): + self[key] = other[key] + else: + for key, value in other: + self[key] = value + for key, value in kwds.items(): + self[key] = value + + __update = update # let subclasses override update without breaking __init__ + + __marker = object() + + def pop(self, key, default=__marker): + '''od.pop(k[,d]) -> v, remove specified key and return the corresponding value. + If key is not found, d is returned if given, otherwise KeyError is raised. + + ''' + if key in self: + result = self[key] + del self[key] + return result + if default is self.__marker: + raise KeyError(key) + return default + + def setdefault(self, key, default=None): + 'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od' + if key in self: + return self[key] + self[key] = default + return default + + def __repr__(self, _repr_running={}): + 'od.__repr__() <==> repr(od)' + call_key = id(self), _get_ident() + if call_key in _repr_running: + return '...' + _repr_running[call_key] = 1 + try: + if not self: + return '%s()' % (self.__class__.__name__,) + return '%s(%r)' % (self.__class__.__name__, self.items()) + finally: + del _repr_running[call_key] + + def __reduce__(self): + 'Return state information for pickling' + items = [[k, self[k]] for k in self] + inst_dict = vars(self).copy() + for k in vars(OrderedDict()): + inst_dict.pop(k, None) + if inst_dict: + return (self.__class__, (items,), inst_dict) + return self.__class__, (items,) + + def copy(self): + 'od.copy() -> a shallow copy of od' + return self.__class__(self) + + @classmethod + def fromkeys(cls, iterable, value=None): + '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S + and values equal to v (which defaults to None). + + ''' + d = cls() + for key in iterable: + d[key] = value + return d + + def __eq__(self, other): + '''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive + while comparison to a regular mapping is order-insensitive. + + ''' + if isinstance(other, OrderedDict): + return len(self)==len(other) and self.items() == other.items() + return dict.__eq__(self, other) + + def __ne__(self, other): + return not self == other + + # -- the following methods are only used in Python 2.7 -- + + def viewkeys(self): + "od.viewkeys() -> a set-like object providing a view on od's keys" + return KeysView(self) + + def viewvalues(self): + "od.viewvalues() -> an object providing a view on od's values" + return ValuesView(self) + + def viewitems(self): + "od.viewitems() -> a set-like object providing a view on od's items" + return ItemsView(self) diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/six.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/six.py new file mode 100644 index 0000000..190c023 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/six.py @@ -0,0 +1,868 @@ +"""Utilities for writing code that runs on Python 2 and 3""" + +# Copyright (c) 2010-2015 Benjamin Peterson +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +from __future__ import absolute_import + +import functools +import itertools +import operator +import sys +import types + +__author__ = "Benjamin Peterson <benjamin@python.org>" +__version__ = "1.10.0" + + +# Useful for very coarse version differentiation. +PY2 = sys.version_info[0] == 2 +PY3 = sys.version_info[0] == 3 +PY34 = sys.version_info[0:2] >= (3, 4) + +if PY3: + string_types = str, + integer_types = int, + class_types = type, + text_type = str + binary_type = bytes + + MAXSIZE = sys.maxsize +else: + string_types = basestring, + integer_types = (int, long) + class_types = (type, types.ClassType) + text_type = unicode + binary_type = str + + if sys.platform.startswith("java"): + # Jython always uses 32 bits. + MAXSIZE = int((1 << 31) - 1) + else: + # It's possible to have sizeof(long) != sizeof(Py_ssize_t). + class X(object): + + def __len__(self): + return 1 << 31 + try: + len(X()) + except OverflowError: + # 32-bit + MAXSIZE = int((1 << 31) - 1) + else: + # 64-bit + MAXSIZE = int((1 << 63) - 1) + del X + + +def _add_doc(func, doc): + """Add documentation to a function.""" + func.__doc__ = doc + + +def _import_module(name): + """Import module, returning the module after the last dot.""" + __import__(name) + return sys.modules[name] + + +class _LazyDescr(object): + + def __init__(self, name): + self.name = name + + def __get__(self, obj, tp): + result = self._resolve() + setattr(obj, self.name, result) # Invokes __set__. + try: + # This is a bit ugly, but it avoids running this again by + # removing this descriptor. + delattr(obj.__class__, self.name) + except AttributeError: + pass + return result + + +class MovedModule(_LazyDescr): + + def __init__(self, name, old, new=None): + super(MovedModule, self).__init__(name) + if PY3: + if new is None: + new = name + self.mod = new + else: + self.mod = old + + def _resolve(self): + return _import_module(self.mod) + + def __getattr__(self, attr): + _module = self._resolve() + value = getattr(_module, attr) + setattr(self, attr, value) + return value + + +class _LazyModule(types.ModuleType): + + def __init__(self, name): + super(_LazyModule, self).__init__(name) + self.__doc__ = self.__class__.__doc__ + + def __dir__(self): + attrs = ["__doc__", "__name__"] + attrs += [attr.name for attr in self._moved_attributes] + return attrs + + # Subclasses should override this + _moved_attributes = [] + + +class MovedAttribute(_LazyDescr): + + def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None): + super(MovedAttribute, self).__init__(name) + if PY3: + if new_mod is None: + new_mod = name + self.mod = new_mod + if new_attr is None: + if old_attr is None: + new_attr = name + else: + new_attr = old_attr + self.attr = new_attr + else: + self.mod = old_mod + if old_attr is None: + old_attr = name + self.attr = old_attr + + def _resolve(self): + module = _import_module(self.mod) + return getattr(module, self.attr) + + +class _SixMetaPathImporter(object): + + """ + A meta path importer to import six.moves and its submodules. + + This class implements a PEP302 finder and loader. It should be compatible + with Python 2.5 and all existing versions of Python3 + """ + + def __init__(self, six_module_name): + self.name = six_module_name + self.known_modules = {} + + def _add_module(self, mod, *fullnames): + for fullname in fullnames: + self.known_modules[self.name + "." + fullname] = mod + + def _get_module(self, fullname): + return self.known_modules[self.name + "." + fullname] + + def find_module(self, fullname, path=None): + if fullname in self.known_modules: + return self + return None + + def __get_module(self, fullname): + try: + return self.known_modules[fullname] + except KeyError: + raise ImportError("This loader does not know module " + fullname) + + def load_module(self, fullname): + try: + # in case of a reload + return sys.modules[fullname] + except KeyError: + pass + mod = self.__get_module(fullname) + if isinstance(mod, MovedModule): + mod = mod._resolve() + else: + mod.__loader__ = self + sys.modules[fullname] = mod + return mod + + def is_package(self, fullname): + """ + Return true, if the named module is a package. + + We need this method to get correct spec objects with + Python 3.4 (see PEP451) + """ + return hasattr(self.__get_module(fullname), "__path__") + + def get_code(self, fullname): + """Return None + + Required, if is_package is implemented""" + self.__get_module(fullname) # eventually raises ImportError + return None + get_source = get_code # same as get_code + +_importer = _SixMetaPathImporter(__name__) + + +class _MovedItems(_LazyModule): + + """Lazy loading of moved objects""" + __path__ = [] # mark as package + + +_moved_attributes = [ + MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"), + MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"), + MovedAttribute("filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"), + MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"), + MovedAttribute("intern", "__builtin__", "sys"), + MovedAttribute("map", "itertools", "builtins", "imap", "map"), + MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"), + MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"), + MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"), + MovedAttribute("reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload"), + MovedAttribute("reduce", "__builtin__", "functools"), + MovedAttribute("shlex_quote", "pipes", "shlex", "quote"), + MovedAttribute("StringIO", "StringIO", "io"), + MovedAttribute("UserDict", "UserDict", "collections"), + MovedAttribute("UserList", "UserList", "collections"), + MovedAttribute("UserString", "UserString", "collections"), + MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"), + MovedAttribute("zip", "itertools", "builtins", "izip", "zip"), + MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"), + MovedModule("builtins", "__builtin__"), + MovedModule("configparser", "ConfigParser"), + MovedModule("copyreg", "copy_reg"), + MovedModule("dbm_gnu", "gdbm", "dbm.gnu"), + MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread"), + MovedModule("http_cookiejar", "cookielib", "http.cookiejar"), + MovedModule("http_cookies", "Cookie", "http.cookies"), + MovedModule("html_entities", "htmlentitydefs", "html.entities"), + MovedModule("html_parser", "HTMLParser", "html.parser"), + MovedModule("http_client", "httplib", "http.client"), + MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"), + MovedModule("email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart"), + MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"), + MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"), + MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"), + MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"), + MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"), + MovedModule("cPickle", "cPickle", "pickle"), + MovedModule("queue", "Queue"), + MovedModule("reprlib", "repr"), + MovedModule("socketserver", "SocketServer"), + MovedModule("_thread", "thread", "_thread"), + MovedModule("tkinter", "Tkinter"), + MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"), + MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"), + MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"), + MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"), + MovedModule("tkinter_tix", "Tix", "tkinter.tix"), + MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"), + MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"), + MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"), + MovedModule("tkinter_colorchooser", "tkColorChooser", + "tkinter.colorchooser"), + MovedModule("tkinter_commondialog", "tkCommonDialog", + "tkinter.commondialog"), + MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"), + MovedModule("tkinter_font", "tkFont", "tkinter.font"), + MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"), + MovedModule("tkinter_tksimpledialog", "tkSimpleDialog", + "tkinter.simpledialog"), + MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"), + MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"), + MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"), + MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"), + MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"), + MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"), +] +# Add windows specific modules. +if sys.platform == "win32": + _moved_attributes += [ + MovedModule("winreg", "_winreg"), + ] + +for attr in _moved_attributes: + setattr(_MovedItems, attr.name, attr) + if isinstance(attr, MovedModule): + _importer._add_module(attr, "moves." + attr.name) +del attr + +_MovedItems._moved_attributes = _moved_attributes + +moves = _MovedItems(__name__ + ".moves") +_importer._add_module(moves, "moves") + + +class Module_six_moves_urllib_parse(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_parse""" + + +_urllib_parse_moved_attributes = [ + MovedAttribute("ParseResult", "urlparse", "urllib.parse"), + MovedAttribute("SplitResult", "urlparse", "urllib.parse"), + MovedAttribute("parse_qs", "urlparse", "urllib.parse"), + MovedAttribute("parse_qsl", "urlparse", "urllib.parse"), + MovedAttribute("urldefrag", "urlparse", "urllib.parse"), + MovedAttribute("urljoin", "urlparse", "urllib.parse"), + MovedAttribute("urlparse", "urlparse", "urllib.parse"), + MovedAttribute("urlsplit", "urlparse", "urllib.parse"), + MovedAttribute("urlunparse", "urlparse", "urllib.parse"), + MovedAttribute("urlunsplit", "urlparse", "urllib.parse"), + MovedAttribute("quote", "urllib", "urllib.parse"), + MovedAttribute("quote_plus", "urllib", "urllib.parse"), + MovedAttribute("unquote", "urllib", "urllib.parse"), + MovedAttribute("unquote_plus", "urllib", "urllib.parse"), + MovedAttribute("urlencode", "urllib", "urllib.parse"), + MovedAttribute("splitquery", "urllib", "urllib.parse"), + MovedAttribute("splittag", "urllib", "urllib.parse"), + MovedAttribute("splituser", "urllib", "urllib.parse"), + MovedAttribute("uses_fragment", "urlparse", "urllib.parse"), + MovedAttribute("uses_netloc", "urlparse", "urllib.parse"), + MovedAttribute("uses_params", "urlparse", "urllib.parse"), + MovedAttribute("uses_query", "urlparse", "urllib.parse"), + MovedAttribute("uses_relative", "urlparse", "urllib.parse"), +] +for attr in _urllib_parse_moved_attributes: + setattr(Module_six_moves_urllib_parse, attr.name, attr) +del attr + +Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes + +_importer._add_module(Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"), + "moves.urllib_parse", "moves.urllib.parse") + + +class Module_six_moves_urllib_error(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_error""" + + +_urllib_error_moved_attributes = [ + MovedAttribute("URLError", "urllib2", "urllib.error"), + MovedAttribute("HTTPError", "urllib2", "urllib.error"), + MovedAttribute("ContentTooShortError", "urllib", "urllib.error"), +] +for attr in _urllib_error_moved_attributes: + setattr(Module_six_moves_urllib_error, attr.name, attr) +del attr + +Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes + +_importer._add_module(Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"), + "moves.urllib_error", "moves.urllib.error") + + +class Module_six_moves_urllib_request(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_request""" + + +_urllib_request_moved_attributes = [ + MovedAttribute("urlopen", "urllib2", "urllib.request"), + MovedAttribute("install_opener", "urllib2", "urllib.request"), + MovedAttribute("build_opener", "urllib2", "urllib.request"), + MovedAttribute("pathname2url", "urllib", "urllib.request"), + MovedAttribute("url2pathname", "urllib", "urllib.request"), + MovedAttribute("getproxies", "urllib", "urllib.request"), + MovedAttribute("Request", "urllib2", "urllib.request"), + MovedAttribute("OpenerDirector", "urllib2", "urllib.request"), + MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"), + MovedAttribute("ProxyHandler", "urllib2", "urllib.request"), + MovedAttribute("BaseHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"), + MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"), + MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"), + MovedAttribute("FileHandler", "urllib2", "urllib.request"), + MovedAttribute("FTPHandler", "urllib2", "urllib.request"), + MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"), + MovedAttribute("UnknownHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"), + MovedAttribute("urlretrieve", "urllib", "urllib.request"), + MovedAttribute("urlcleanup", "urllib", "urllib.request"), + MovedAttribute("URLopener", "urllib", "urllib.request"), + MovedAttribute("FancyURLopener", "urllib", "urllib.request"), + MovedAttribute("proxy_bypass", "urllib", "urllib.request"), +] +for attr in _urllib_request_moved_attributes: + setattr(Module_six_moves_urllib_request, attr.name, attr) +del attr + +Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes + +_importer._add_module(Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"), + "moves.urllib_request", "moves.urllib.request") + + +class Module_six_moves_urllib_response(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_response""" + + +_urllib_response_moved_attributes = [ + MovedAttribute("addbase", "urllib", "urllib.response"), + MovedAttribute("addclosehook", "urllib", "urllib.response"), + MovedAttribute("addinfo", "urllib", "urllib.response"), + MovedAttribute("addinfourl", "urllib", "urllib.response"), +] +for attr in _urllib_response_moved_attributes: + setattr(Module_six_moves_urllib_response, attr.name, attr) +del attr + +Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes + +_importer._add_module(Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"), + "moves.urllib_response", "moves.urllib.response") + + +class Module_six_moves_urllib_robotparser(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_robotparser""" + + +_urllib_robotparser_moved_attributes = [ + MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"), +] +for attr in _urllib_robotparser_moved_attributes: + setattr(Module_six_moves_urllib_robotparser, attr.name, attr) +del attr + +Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes + +_importer._add_module(Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"), + "moves.urllib_robotparser", "moves.urllib.robotparser") + + +class Module_six_moves_urllib(types.ModuleType): + + """Create a six.moves.urllib namespace that resembles the Python 3 namespace""" + __path__ = [] # mark as package + parse = _importer._get_module("moves.urllib_parse") + error = _importer._get_module("moves.urllib_error") + request = _importer._get_module("moves.urllib_request") + response = _importer._get_module("moves.urllib_response") + robotparser = _importer._get_module("moves.urllib_robotparser") + + def __dir__(self): + return ['parse', 'error', 'request', 'response', 'robotparser'] + +_importer._add_module(Module_six_moves_urllib(__name__ + ".moves.urllib"), + "moves.urllib") + + +def add_move(move): + """Add an item to six.moves.""" + setattr(_MovedItems, move.name, move) + + +def remove_move(name): + """Remove item from six.moves.""" + try: + delattr(_MovedItems, name) + except AttributeError: + try: + del moves.__dict__[name] + except KeyError: + raise AttributeError("no such move, %r" % (name,)) + + +if PY3: + _meth_func = "__func__" + _meth_self = "__self__" + + _func_closure = "__closure__" + _func_code = "__code__" + _func_defaults = "__defaults__" + _func_globals = "__globals__" +else: + _meth_func = "im_func" + _meth_self = "im_self" + + _func_closure = "func_closure" + _func_code = "func_code" + _func_defaults = "func_defaults" + _func_globals = "func_globals" + + +try: + advance_iterator = next +except NameError: + def advance_iterator(it): + return it.next() +next = advance_iterator + + +try: + callable = callable +except NameError: + def callable(obj): + return any("__call__" in klass.__dict__ for klass in type(obj).__mro__) + + +if PY3: + def get_unbound_function(unbound): + return unbound + + create_bound_method = types.MethodType + + def create_unbound_method(func, cls): + return func + + Iterator = object +else: + def get_unbound_function(unbound): + return unbound.im_func + + def create_bound_method(func, obj): + return types.MethodType(func, obj, obj.__class__) + + def create_unbound_method(func, cls): + return types.MethodType(func, None, cls) + + class Iterator(object): + + def next(self): + return type(self).__next__(self) + + callable = callable +_add_doc(get_unbound_function, + """Get the function out of a possibly unbound function""") + + +get_method_function = operator.attrgetter(_meth_func) +get_method_self = operator.attrgetter(_meth_self) +get_function_closure = operator.attrgetter(_func_closure) +get_function_code = operator.attrgetter(_func_code) +get_function_defaults = operator.attrgetter(_func_defaults) +get_function_globals = operator.attrgetter(_func_globals) + + +if PY3: + def iterkeys(d, **kw): + return iter(d.keys(**kw)) + + def itervalues(d, **kw): + return iter(d.values(**kw)) + + def iteritems(d, **kw): + return iter(d.items(**kw)) + + def iterlists(d, **kw): + return iter(d.lists(**kw)) + + viewkeys = operator.methodcaller("keys") + + viewvalues = operator.methodcaller("values") + + viewitems = operator.methodcaller("items") +else: + def iterkeys(d, **kw): + return d.iterkeys(**kw) + + def itervalues(d, **kw): + return d.itervalues(**kw) + + def iteritems(d, **kw): + return d.iteritems(**kw) + + def iterlists(d, **kw): + return d.iterlists(**kw) + + viewkeys = operator.methodcaller("viewkeys") + + viewvalues = operator.methodcaller("viewvalues") + + viewitems = operator.methodcaller("viewitems") + +_add_doc(iterkeys, "Return an iterator over the keys of a dictionary.") +_add_doc(itervalues, "Return an iterator over the values of a dictionary.") +_add_doc(iteritems, + "Return an iterator over the (key, value) pairs of a dictionary.") +_add_doc(iterlists, + "Return an iterator over the (key, [values]) pairs of a dictionary.") + + +if PY3: + def b(s): + return s.encode("latin-1") + + def u(s): + return s + unichr = chr + import struct + int2byte = struct.Struct(">B").pack + del struct + byte2int = operator.itemgetter(0) + indexbytes = operator.getitem + iterbytes = iter + import io + StringIO = io.StringIO + BytesIO = io.BytesIO + _assertCountEqual = "assertCountEqual" + if sys.version_info[1] <= 1: + _assertRaisesRegex = "assertRaisesRegexp" + _assertRegex = "assertRegexpMatches" + else: + _assertRaisesRegex = "assertRaisesRegex" + _assertRegex = "assertRegex" +else: + def b(s): + return s + # Workaround for standalone backslash + + def u(s): + return unicode(s.replace(r'\\', r'\\\\'), "unicode_escape") + unichr = unichr + int2byte = chr + + def byte2int(bs): + return ord(bs[0]) + + def indexbytes(buf, i): + return ord(buf[i]) + iterbytes = functools.partial(itertools.imap, ord) + import StringIO + StringIO = BytesIO = StringIO.StringIO + _assertCountEqual = "assertItemsEqual" + _assertRaisesRegex = "assertRaisesRegexp" + _assertRegex = "assertRegexpMatches" +_add_doc(b, """Byte literal""") +_add_doc(u, """Text literal""") + + +def assertCountEqual(self, *args, **kwargs): + return getattr(self, _assertCountEqual)(*args, **kwargs) + + +def assertRaisesRegex(self, *args, **kwargs): + return getattr(self, _assertRaisesRegex)(*args, **kwargs) + + +def assertRegex(self, *args, **kwargs): + return getattr(self, _assertRegex)(*args, **kwargs) + + +if PY3: + exec_ = getattr(moves.builtins, "exec") + + def reraise(tp, value, tb=None): + if value is None: + value = tp() + if value.__traceback__ is not tb: + raise value.with_traceback(tb) + raise value + +else: + def exec_(_code_, _globs_=None, _locs_=None): + """Execute code in a namespace.""" + if _globs_ is None: + frame = sys._getframe(1) + _globs_ = frame.f_globals + if _locs_ is None: + _locs_ = frame.f_locals + del frame + elif _locs_ is None: + _locs_ = _globs_ + exec("""exec _code_ in _globs_, _locs_""") + + exec_("""def reraise(tp, value, tb=None): + raise tp, value, tb +""") + + +if sys.version_info[:2] == (3, 2): + exec_("""def raise_from(value, from_value): + if from_value is None: + raise value + raise value from from_value +""") +elif sys.version_info[:2] > (3, 2): + exec_("""def raise_from(value, from_value): + raise value from from_value +""") +else: + def raise_from(value, from_value): + raise value + + +print_ = getattr(moves.builtins, "print", None) +if print_ is None: + def print_(*args, **kwargs): + """The new-style print function for Python 2.4 and 2.5.""" + fp = kwargs.pop("file", sys.stdout) + if fp is None: + return + + def write(data): + if not isinstance(data, basestring): + data = str(data) + # If the file has an encoding, encode unicode with it. + if (isinstance(fp, file) and + isinstance(data, unicode) and + fp.encoding is not None): + errors = getattr(fp, "errors", None) + if errors is None: + errors = "strict" + data = data.encode(fp.encoding, errors) + fp.write(data) + want_unicode = False + sep = kwargs.pop("sep", None) + if sep is not None: + if isinstance(sep, unicode): + want_unicode = True + elif not isinstance(sep, str): + raise TypeError("sep must be None or a string") + end = kwargs.pop("end", None) + if end is not None: + if isinstance(end, unicode): + want_unicode = True + elif not isinstance(end, str): + raise TypeError("end must be None or a string") + if kwargs: + raise TypeError("invalid keyword arguments to print()") + if not want_unicode: + for arg in args: + if isinstance(arg, unicode): + want_unicode = True + break + if want_unicode: + newline = unicode("\n") + space = unicode(" ") + else: + newline = "\n" + space = " " + if sep is None: + sep = space + if end is None: + end = newline + for i, arg in enumerate(args): + if i: + write(sep) + write(arg) + write(end) +if sys.version_info[:2] < (3, 3): + _print = print_ + + def print_(*args, **kwargs): + fp = kwargs.get("file", sys.stdout) + flush = kwargs.pop("flush", False) + _print(*args, **kwargs) + if flush and fp is not None: + fp.flush() + +_add_doc(reraise, """Reraise an exception.""") + +if sys.version_info[0:2] < (3, 4): + def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS, + updated=functools.WRAPPER_UPDATES): + def wrapper(f): + f = functools.wraps(wrapped, assigned, updated)(f) + f.__wrapped__ = wrapped + return f + return wrapper +else: + wraps = functools.wraps + + +def with_metaclass(meta, *bases): + """Create a base class with a metaclass.""" + # This requires a bit of explanation: the basic idea is to make a dummy + # metaclass for one level of class instantiation that replaces itself with + # the actual metaclass. + class metaclass(meta): + + def __new__(cls, name, this_bases, d): + return meta(name, bases, d) + return type.__new__(metaclass, 'temporary_class', (), {}) + + +def add_metaclass(metaclass): + """Class decorator for creating a class with a metaclass.""" + def wrapper(cls): + orig_vars = cls.__dict__.copy() + slots = orig_vars.get('__slots__') + if slots is not None: + if isinstance(slots, str): + slots = [slots] + for slots_var in slots: + orig_vars.pop(slots_var) + orig_vars.pop('__dict__', None) + orig_vars.pop('__weakref__', None) + return metaclass(cls.__name__, cls.__bases__, orig_vars) + return wrapper + + +def python_2_unicode_compatible(klass): + """ + A decorator that defines __unicode__ and __str__ methods under Python 2. + Under Python 3 it does nothing. + + To support Python 2 and 3 with a single code base, define a __str__ method + returning text and apply this decorator to the class. + """ + if PY2: + if '__str__' not in klass.__dict__: + raise ValueError("@python_2_unicode_compatible cannot be applied " + "to %s because it doesn't define __str__()." % + klass.__name__) + klass.__unicode__ = klass.__str__ + klass.__str__ = lambda self: self.__unicode__().encode('utf-8') + return klass + + +# Complete the moves implementation. +# This code is at the end of this module to speed up module loading. +# Turn this module into a package. +__path__ = [] # required for PEP 302 and PEP 451 +__package__ = __name__ # see PEP 366 @ReservedAssignment +if globals().get("__spec__") is not None: + __spec__.submodule_search_locations = [] # PEP 451 @UndefinedVariable +# Remove other six meta path importers, since they cause problems. This can +# happen if six is removed from sys.modules and then reloaded. (Setuptools does +# this for some reason.) +if sys.meta_path: + for i, importer in enumerate(sys.meta_path): + # Here's some real nastiness: Another "instance" of the six module might + # be floating around. Therefore, we can't use isinstance() to check for + # the six meta path importer, since the other six instance will have + # inserted an importer with different class. + if (type(importer).__name__ == "_SixMetaPathImporter" and + importer.name == __name__): + del sys.meta_path[i] + break + del i, importer +# Finally, add the importer to the meta path import hook. +sys.meta_path.append(_importer) diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/ssl_match_hostname/__init__.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/ssl_match_hostname/__init__.py new file mode 100644 index 0000000..d6594eb --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/ssl_match_hostname/__init__.py @@ -0,0 +1,19 @@ +import sys + +try: + # Our match_hostname function is the same as 3.5's, so we only want to + # import the match_hostname function if it's at least that good. + if sys.version_info < (3, 5): + raise ImportError("Fallback to vendored code") + + from ssl import CertificateError, match_hostname +except ImportError: + try: + # Backport of the function from a pypi module + from backports.ssl_match_hostname import CertificateError, match_hostname + except ImportError: + # Our vendored copy + from ._implementation import CertificateError, match_hostname + +# Not needed, but documenting what we provide. +__all__ = ('CertificateError', 'match_hostname') diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/ssl_match_hostname/_implementation.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/ssl_match_hostname/_implementation.py new file mode 100644 index 0000000..1fd42f3 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/ssl_match_hostname/_implementation.py @@ -0,0 +1,157 @@ +"""The match_hostname() function from Python 3.3.3, essential when using SSL.""" + +# Note: This file is under the PSF license as the code comes from the python +# stdlib. http://docs.python.org/3/license.html + +import re +import sys + +# ipaddress has been backported to 2.6+ in pypi. If it is installed on the +# system, use it to handle IPAddress ServerAltnames (this was added in +# python-3.5) otherwise only do DNS matching. This allows +# backports.ssl_match_hostname to continue to be used all the way back to +# python-2.4. +try: + import ipaddress +except ImportError: + ipaddress = None + +__version__ = '3.5.0.1' + + +class CertificateError(ValueError): + pass + + +def _dnsname_match(dn, hostname, max_wildcards=1): + """Matching according to RFC 6125, section 6.4.3 + + http://tools.ietf.org/html/rfc6125#section-6.4.3 + """ + pats = [] + if not dn: + return False + + # Ported from python3-syntax: + # leftmost, *remainder = dn.split(r'.') + parts = dn.split(r'.') + leftmost = parts[0] + remainder = parts[1:] + + wildcards = leftmost.count('*') + if wildcards > max_wildcards: + # Issue #17980: avoid denials of service by refusing more + # than one wildcard per fragment. A survey of established + # policy among SSL implementations showed it to be a + # reasonable choice. + raise CertificateError( + "too many wildcards in certificate DNS name: " + repr(dn)) + + # speed up common case w/o wildcards + if not wildcards: + return dn.lower() == hostname.lower() + + # RFC 6125, section 6.4.3, subitem 1. + # The client SHOULD NOT attempt to match a presented identifier in which + # the wildcard character comprises a label other than the left-most label. + if leftmost == '*': + # When '*' is a fragment by itself, it matches a non-empty dotless + # fragment. + pats.append('[^.]+') + elif leftmost.startswith('xn--') or hostname.startswith('xn--'): + # RFC 6125, section 6.4.3, subitem 3. + # The client SHOULD NOT attempt to match a presented identifier + # where the wildcard character is embedded within an A-label or + # U-label of an internationalized domain name. + pats.append(re.escape(leftmost)) + else: + # Otherwise, '*' matches any dotless string, e.g. www* + pats.append(re.escape(leftmost).replace(r'\*', '[^.]*')) + + # add the remaining fragments, ignore any wildcards + for frag in remainder: + pats.append(re.escape(frag)) + + pat = re.compile(r'\A' + r'\.'.join(pats) + r'\Z', re.IGNORECASE) + return pat.match(hostname) + + +def _to_unicode(obj): + if isinstance(obj, str) and sys.version_info < (3,): + obj = unicode(obj, encoding='ascii', errors='strict') + return obj + +def _ipaddress_match(ipname, host_ip): + """Exact matching of IP addresses. + + RFC 6125 explicitly doesn't define an algorithm for this + (section 1.7.2 - "Out of Scope"). + """ + # OpenSSL may add a trailing newline to a subjectAltName's IP address + # Divergence from upstream: ipaddress can't handle byte str + ip = ipaddress.ip_address(_to_unicode(ipname).rstrip()) + return ip == host_ip + + +def match_hostname(cert, hostname): + """Verify that *cert* (in decoded format as returned by + SSLSocket.getpeercert()) matches the *hostname*. RFC 2818 and RFC 6125 + rules are followed, but IP addresses are not accepted for *hostname*. + + CertificateError is raised on failure. On success, the function + returns nothing. + """ + if not cert: + raise ValueError("empty or no certificate, match_hostname needs a " + "SSL socket or SSL context with either " + "CERT_OPTIONAL or CERT_REQUIRED") + try: + # Divergence from upstream: ipaddress can't handle byte str + host_ip = ipaddress.ip_address(_to_unicode(hostname)) + except ValueError: + # Not an IP address (common case) + host_ip = None + except UnicodeError: + # Divergence from upstream: Have to deal with ipaddress not taking + # byte strings. addresses should be all ascii, so we consider it not + # an ipaddress in this case + host_ip = None + except AttributeError: + # Divergence from upstream: Make ipaddress library optional + if ipaddress is None: + host_ip = None + else: + raise + dnsnames = [] + san = cert.get('subjectAltName', ()) + for key, value in san: + if key == 'DNS': + if host_ip is None and _dnsname_match(value, hostname): + return + dnsnames.append(value) + elif key == 'IP Address': + if host_ip is not None and _ipaddress_match(value, host_ip): + return + dnsnames.append(value) + if not dnsnames: + # The subject is only checked when there is no dNSName entry + # in subjectAltName + for sub in cert.get('subject', ()): + for key, value in sub: + # XXX according to RFC 2818, the most specific Common Name + # must be used. + if key == 'commonName': + if _dnsname_match(value, hostname): + return + dnsnames.append(value) + if len(dnsnames) > 1: + raise CertificateError("hostname %r " + "doesn't match either of %s" + % (hostname, ', '.join(map(repr, dnsnames)))) + elif len(dnsnames) == 1: + raise CertificateError("hostname %r " + "doesn't match %r" + % (hostname, dnsnames[0])) + else: + raise CertificateError("no appropriate commonName or " + "subjectAltName fields were found") diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/poolmanager.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/poolmanager.py new file mode 100644 index 0000000..cc5a00e --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/poolmanager.py @@ -0,0 +1,363 @@ +from __future__ import absolute_import +import collections +import functools +import logging + +from ._collections import RecentlyUsedContainer +from .connectionpool import HTTPConnectionPool, HTTPSConnectionPool +from .connectionpool import port_by_scheme +from .exceptions import LocationValueError, MaxRetryError, ProxySchemeUnknown +from .packages.six.moves.urllib.parse import urljoin +from .request import RequestMethods +from .util.url import parse_url +from .util.retry import Retry + + +__all__ = ['PoolManager', 'ProxyManager', 'proxy_from_url'] + + +log = logging.getLogger(__name__) + +SSL_KEYWORDS = ('key_file', 'cert_file', 'cert_reqs', 'ca_certs', + 'ssl_version', 'ca_cert_dir', 'ssl_context') + +# The base fields to use when determining what pool to get a connection from; +# these do not rely on the ``connection_pool_kw`` and can be determined by the +# URL and potentially the ``urllib3.connection.port_by_scheme`` dictionary. +# +# All custom key schemes should include the fields in this key at a minimum. +BasePoolKey = collections.namedtuple('BasePoolKey', ('scheme', 'host', 'port')) + +# The fields to use when determining what pool to get a HTTP and HTTPS +# connection from. All additional fields must be present in the PoolManager's +# ``connection_pool_kw`` instance variable. +HTTPPoolKey = collections.namedtuple( + 'HTTPPoolKey', BasePoolKey._fields + ('timeout', 'retries', 'strict', + 'block', 'source_address') +) +HTTPSPoolKey = collections.namedtuple( + 'HTTPSPoolKey', HTTPPoolKey._fields + SSL_KEYWORDS +) + + +def _default_key_normalizer(key_class, request_context): + """ + Create a pool key of type ``key_class`` for a request. + + According to RFC 3986, both the scheme and host are case-insensitive. + Therefore, this function normalizes both before constructing the pool + key for an HTTPS request. If you wish to change this behaviour, provide + alternate callables to ``key_fn_by_scheme``. + + :param key_class: + The class to use when constructing the key. This should be a namedtuple + with the ``scheme`` and ``host`` keys at a minimum. + + :param request_context: + A dictionary-like object that contain the context for a request. + It should contain a key for each field in the :class:`HTTPPoolKey` + """ + context = {} + for key in key_class._fields: + context[key] = request_context.get(key) + context['scheme'] = context['scheme'].lower() + context['host'] = context['host'].lower() + return key_class(**context) + + +# A dictionary that maps a scheme to a callable that creates a pool key. +# This can be used to alter the way pool keys are constructed, if desired. +# Each PoolManager makes a copy of this dictionary so they can be configured +# globally here, or individually on the instance. +key_fn_by_scheme = { + 'http': functools.partial(_default_key_normalizer, HTTPPoolKey), + 'https': functools.partial(_default_key_normalizer, HTTPSPoolKey), +} + +pool_classes_by_scheme = { + 'http': HTTPConnectionPool, + 'https': HTTPSConnectionPool, +} + + +class PoolManager(RequestMethods): + """ + Allows for arbitrary requests while transparently keeping track of + necessary connection pools for you. + + :param num_pools: + Number of connection pools to cache before discarding the least + recently used pool. + + :param headers: + Headers to include with all requests, unless other headers are given + explicitly. + + :param \\**connection_pool_kw: + Additional parameters are used to create fresh + :class:`urllib3.connectionpool.ConnectionPool` instances. + + Example:: + + >>> manager = PoolManager(num_pools=2) + >>> r = manager.request('GET', 'http://google.com/') + >>> r = manager.request('GET', 'http://google.com/mail') + >>> r = manager.request('GET', 'http://yahoo.com/') + >>> len(manager.pools) + 2 + + """ + + proxy = None + + def __init__(self, num_pools=10, headers=None, **connection_pool_kw): + RequestMethods.__init__(self, headers) + self.connection_pool_kw = connection_pool_kw + self.pools = RecentlyUsedContainer(num_pools, + dispose_func=lambda p: p.close()) + + # Locally set the pool classes and keys so other PoolManagers can + # override them. + self.pool_classes_by_scheme = pool_classes_by_scheme + self.key_fn_by_scheme = key_fn_by_scheme.copy() + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.clear() + # Return False to re-raise any potential exceptions + return False + + def _new_pool(self, scheme, host, port): + """ + Create a new :class:`ConnectionPool` based on host, port and scheme. + + This method is used to actually create the connection pools handed out + by :meth:`connection_from_url` and companion methods. It is intended + to be overridden for customization. + """ + pool_cls = self.pool_classes_by_scheme[scheme] + kwargs = self.connection_pool_kw + if scheme == 'http': + kwargs = self.connection_pool_kw.copy() + for kw in SSL_KEYWORDS: + kwargs.pop(kw, None) + + return pool_cls(host, port, **kwargs) + + def clear(self): + """ + Empty our store of pools and direct them all to close. + + This will not affect in-flight connections, but they will not be + re-used after completion. + """ + self.pools.clear() + + def connection_from_host(self, host, port=None, scheme='http'): + """ + Get a :class:`ConnectionPool` based on the host, port, and scheme. + + If ``port`` isn't given, it will be derived from the ``scheme`` using + ``urllib3.connectionpool.port_by_scheme``. + """ + + if not host: + raise LocationValueError("No host specified.") + + request_context = self.connection_pool_kw.copy() + request_context['scheme'] = scheme or 'http' + if not port: + port = port_by_scheme.get(request_context['scheme'].lower(), 80) + request_context['port'] = port + request_context['host'] = host + + return self.connection_from_context(request_context) + + def connection_from_context(self, request_context): + """ + Get a :class:`ConnectionPool` based on the request context. + + ``request_context`` must at least contain the ``scheme`` key and its + value must be a key in ``key_fn_by_scheme`` instance variable. + """ + scheme = request_context['scheme'].lower() + pool_key_constructor = self.key_fn_by_scheme[scheme] + pool_key = pool_key_constructor(request_context) + + return self.connection_from_pool_key(pool_key) + + def connection_from_pool_key(self, pool_key): + """ + Get a :class:`ConnectionPool` based on the provided pool key. + + ``pool_key`` should be a namedtuple that only contains immutable + objects. At a minimum it must have the ``scheme``, ``host``, and + ``port`` fields. + """ + with self.pools.lock: + # If the scheme, host, or port doesn't match existing open + # connections, open a new ConnectionPool. + pool = self.pools.get(pool_key) + if pool: + return pool + + # Make a fresh ConnectionPool of the desired type + pool = self._new_pool(pool_key.scheme, pool_key.host, pool_key.port) + self.pools[pool_key] = pool + + return pool + + def connection_from_url(self, url): + """ + Similar to :func:`urllib3.connectionpool.connection_from_url` but + doesn't pass any additional parameters to the + :class:`urllib3.connectionpool.ConnectionPool` constructor. + + Additional parameters are taken from the :class:`.PoolManager` + constructor. + """ + u = parse_url(url) + return self.connection_from_host(u.host, port=u.port, scheme=u.scheme) + + def urlopen(self, method, url, redirect=True, **kw): + """ + Same as :meth:`urllib3.connectionpool.HTTPConnectionPool.urlopen` + with custom cross-host redirect logic and only sends the request-uri + portion of the ``url``. + + The given ``url`` parameter must be absolute, such that an appropriate + :class:`urllib3.connectionpool.ConnectionPool` can be chosen for it. + """ + u = parse_url(url) + conn = self.connection_from_host(u.host, port=u.port, scheme=u.scheme) + + kw['assert_same_host'] = False + kw['redirect'] = False + if 'headers' not in kw: + kw['headers'] = self.headers + + if self.proxy is not None and u.scheme == "http": + response = conn.urlopen(method, url, **kw) + else: + response = conn.urlopen(method, u.request_uri, **kw) + + redirect_location = redirect and response.get_redirect_location() + if not redirect_location: + return response + + # Support relative URLs for redirecting. + redirect_location = urljoin(url, redirect_location) + + # RFC 7231, Section 6.4.4 + if response.status == 303: + method = 'GET' + + retries = kw.get('retries') + if not isinstance(retries, Retry): + retries = Retry.from_int(retries, redirect=redirect) + + try: + retries = retries.increment(method, url, response=response, _pool=conn) + except MaxRetryError: + if retries.raise_on_redirect: + raise + return response + + kw['retries'] = retries + kw['redirect'] = redirect + + log.info("Redirecting %s -> %s", url, redirect_location) + return self.urlopen(method, redirect_location, **kw) + + +class ProxyManager(PoolManager): + """ + Behaves just like :class:`PoolManager`, but sends all requests through + the defined proxy, using the CONNECT method for HTTPS URLs. + + :param proxy_url: + The URL of the proxy to be used. + + :param proxy_headers: + A dictionary contaning headers that will be sent to the proxy. In case + of HTTP they are being sent with each request, while in the + HTTPS/CONNECT case they are sent only once. Could be used for proxy + authentication. + + Example: + >>> proxy = urllib3.ProxyManager('http://localhost:3128/') + >>> r1 = proxy.request('GET', 'http://google.com/') + >>> r2 = proxy.request('GET', 'http://httpbin.org/') + >>> len(proxy.pools) + 1 + >>> r3 = proxy.request('GET', 'https://httpbin.org/') + >>> r4 = proxy.request('GET', 'https://twitter.com/') + >>> len(proxy.pools) + 3 + + """ + + def __init__(self, proxy_url, num_pools=10, headers=None, + proxy_headers=None, **connection_pool_kw): + + if isinstance(proxy_url, HTTPConnectionPool): + proxy_url = '%s://%s:%i' % (proxy_url.scheme, proxy_url.host, + proxy_url.port) + proxy = parse_url(proxy_url) + if not proxy.port: + port = port_by_scheme.get(proxy.scheme, 80) + proxy = proxy._replace(port=port) + + if proxy.scheme not in ("http", "https"): + raise ProxySchemeUnknown(proxy.scheme) + + self.proxy = proxy + self.proxy_headers = proxy_headers or {} + + connection_pool_kw['_proxy'] = self.proxy + connection_pool_kw['_proxy_headers'] = self.proxy_headers + + super(ProxyManager, self).__init__( + num_pools, headers, **connection_pool_kw) + + def connection_from_host(self, host, port=None, scheme='http'): + if scheme == "https": + return super(ProxyManager, self).connection_from_host( + host, port, scheme) + + return super(ProxyManager, self).connection_from_host( + self.proxy.host, self.proxy.port, self.proxy.scheme) + + def _set_proxy_headers(self, url, headers=None): + """ + Sets headers needed by proxies: specifically, the Accept and Host + headers. Only sets headers not provided by the user. + """ + headers_ = {'Accept': '*/*'} + + netloc = parse_url(url).netloc + if netloc: + headers_['Host'] = netloc + + if headers: + headers_.update(headers) + return headers_ + + def urlopen(self, method, url, redirect=True, **kw): + "Same as HTTP(S)ConnectionPool.urlopen, ``url`` must be absolute." + u = parse_url(url) + + if u.scheme == "http": + # For proxied HTTPS requests, httplib sets the necessary headers + # on the CONNECT to the proxy. For HTTP, we'll definitely + # need to set 'Host' at the very least. + headers = kw.get('headers', self.headers) + kw['headers'] = self._set_proxy_headers(url, headers) + + return super(ProxyManager, self).urlopen(method, url, redirect=redirect, **kw) + + +def proxy_from_url(url, **kw): + return ProxyManager(proxy_url=url, **kw) diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/request.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/request.py new file mode 100644 index 0000000..c0fddff --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/request.py @@ -0,0 +1,148 @@ +from __future__ import absolute_import + +from .filepost import encode_multipart_formdata +from .packages.six.moves.urllib.parse import urlencode + + +__all__ = ['RequestMethods'] + + +class RequestMethods(object): + """ + Convenience mixin for classes who implement a :meth:`urlopen` method, such + as :class:`~urllib3.connectionpool.HTTPConnectionPool` and + :class:`~urllib3.poolmanager.PoolManager`. + + Provides behavior for making common types of HTTP request methods and + decides which type of request field encoding to use. + + Specifically, + + :meth:`.request_encode_url` is for sending requests whose fields are + encoded in the URL (such as GET, HEAD, DELETE). + + :meth:`.request_encode_body` is for sending requests whose fields are + encoded in the *body* of the request using multipart or www-form-urlencoded + (such as for POST, PUT, PATCH). + + :meth:`.request` is for making any kind of request, it will look up the + appropriate encoding format and use one of the above two methods to make + the request. + + Initializer parameters: + + :param headers: + Headers to include with all requests, unless other headers are given + explicitly. + """ + + _encode_url_methods = set(['DELETE', 'GET', 'HEAD', 'OPTIONS']) + + def __init__(self, headers=None): + self.headers = headers or {} + + def urlopen(self, method, url, body=None, headers=None, + encode_multipart=True, multipart_boundary=None, + **kw): # Abstract + raise NotImplemented("Classes extending RequestMethods must implement " + "their own ``urlopen`` method.") + + def request(self, method, url, fields=None, headers=None, **urlopen_kw): + """ + Make a request using :meth:`urlopen` with the appropriate encoding of + ``fields`` based on the ``method`` used. + + This is a convenience method that requires the least amount of manual + effort. It can be used in most situations, while still having the + option to drop down to more specific methods when necessary, such as + :meth:`request_encode_url`, :meth:`request_encode_body`, + or even the lowest level :meth:`urlopen`. + """ + method = method.upper() + + if method in self._encode_url_methods: + return self.request_encode_url(method, url, fields=fields, + headers=headers, + **urlopen_kw) + else: + return self.request_encode_body(method, url, fields=fields, + headers=headers, + **urlopen_kw) + + def request_encode_url(self, method, url, fields=None, headers=None, + **urlopen_kw): + """ + Make a request using :meth:`urlopen` with the ``fields`` encoded in + the url. This is useful for request methods like GET, HEAD, DELETE, etc. + """ + if headers is None: + headers = self.headers + + extra_kw = {'headers': headers} + extra_kw.update(urlopen_kw) + + if fields: + url += '?' + urlencode(fields) + + return self.urlopen(method, url, **extra_kw) + + def request_encode_body(self, method, url, fields=None, headers=None, + encode_multipart=True, multipart_boundary=None, + **urlopen_kw): + """ + Make a request using :meth:`urlopen` with the ``fields`` encoded in + the body. This is useful for request methods like POST, PUT, PATCH, etc. + + When ``encode_multipart=True`` (default), then + :meth:`urllib3.filepost.encode_multipart_formdata` is used to encode + the payload with the appropriate content type. Otherwise + :meth:`urllib.urlencode` is used with the + 'application/x-www-form-urlencoded' content type. + + Multipart encoding must be used when posting files, and it's reasonably + safe to use it in other times too. However, it may break request + signing, such as with OAuth. + + Supports an optional ``fields`` parameter of key/value strings AND + key/filetuple. A filetuple is a (filename, data, MIME type) tuple where + the MIME type is optional. For example:: + + fields = { + 'foo': 'bar', + 'fakefile': ('foofile.txt', 'contents of foofile'), + 'realfile': ('barfile.txt', open('realfile').read()), + 'typedfile': ('bazfile.bin', open('bazfile').read(), + 'image/jpeg'), + 'nonamefile': 'contents of nonamefile field', + } + + When uploading a file, providing a filename (the first parameter of the + tuple) is optional but recommended to best mimick behavior of browsers. + + Note that if ``headers`` are supplied, the 'Content-Type' header will + be overwritten because it depends on the dynamic random boundary string + which is used to compose the body of the request. The random boundary + string can be explicitly set with the ``multipart_boundary`` parameter. + """ + if headers is None: + headers = self.headers + + extra_kw = {'headers': {}} + + if fields: + if 'body' in urlopen_kw: + raise TypeError( + "request got values for both 'fields' and 'body', can only specify one.") + + if encode_multipart: + body, content_type = encode_multipart_formdata(fields, boundary=multipart_boundary) + else: + body, content_type = urlencode(fields), 'application/x-www-form-urlencoded' + + extra_kw['body'] = body + extra_kw['headers'] = {'Content-Type': content_type} + + extra_kw['headers'].update(headers) + extra_kw.update(urlopen_kw) + + return self.urlopen(method, url, **extra_kw) diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/response.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/response.py new file mode 100644 index 0000000..6f1b63c --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/response.py @@ -0,0 +1,618 @@ +from __future__ import absolute_import +from contextlib import contextmanager +import zlib +import io +import logging +from socket import timeout as SocketTimeout +from socket import error as SocketError + +from ._collections import HTTPHeaderDict +from .exceptions import ( + BodyNotHttplibCompatible, ProtocolError, DecodeError, ReadTimeoutError, + ResponseNotChunked, IncompleteRead, InvalidHeader +) +from .packages.six import string_types as basestring, binary_type, PY3 +from .packages.six.moves import http_client as httplib +from .connection import HTTPException, BaseSSLError +from .util.response import is_fp_closed, is_response_to_head + +log = logging.getLogger(__name__) + + +class DeflateDecoder(object): + + def __init__(self): + self._first_try = True + self._data = binary_type() + self._obj = zlib.decompressobj() + + def __getattr__(self, name): + return getattr(self._obj, name) + + def decompress(self, data): + if not data: + return data + + if not self._first_try: + return self._obj.decompress(data) + + self._data += data + try: + return self._obj.decompress(data) + except zlib.error: + self._first_try = False + self._obj = zlib.decompressobj(-zlib.MAX_WBITS) + try: + return self.decompress(self._data) + finally: + self._data = None + + +class GzipDecoder(object): + + def __init__(self): + self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS) + + def __getattr__(self, name): + return getattr(self._obj, name) + + def decompress(self, data): + if not data: + return data + return self._obj.decompress(data) + + +def _get_decoder(mode): + if mode == 'gzip': + return GzipDecoder() + + return DeflateDecoder() + + +class HTTPResponse(io.IOBase): + """ + HTTP Response container. + + Backwards-compatible to httplib's HTTPResponse but the response ``body`` is + loaded and decoded on-demand when the ``data`` property is accessed. This + class is also compatible with the Python standard library's :mod:`io` + module, and can hence be treated as a readable object in the context of that + framework. + + Extra parameters for behaviour not present in httplib.HTTPResponse: + + :param preload_content: + If True, the response's body will be preloaded during construction. + + :param decode_content: + If True, attempts to decode specific content-encoding's based on headers + (like 'gzip' and 'deflate') will be skipped and raw data will be used + instead. + + :param original_response: + When this HTTPResponse wrapper is generated from an httplib.HTTPResponse + object, it's convenient to include the original for debug purposes. It's + otherwise unused. + + :param retries: + The retries contains the last :class:`~urllib3.util.retry.Retry` that + was used during the request. + + :param enforce_content_length: + Enforce content length checking. Body returned by server must match + value of Content-Length header, if present. Otherwise, raise error. + """ + + CONTENT_DECODERS = ['gzip', 'deflate'] + REDIRECT_STATUSES = [301, 302, 303, 307, 308] + + def __init__(self, body='', headers=None, status=0, version=0, reason=None, + strict=0, preload_content=True, decode_content=True, + original_response=None, pool=None, connection=None, + retries=None, enforce_content_length=False, request_method=None): + + if isinstance(headers, HTTPHeaderDict): + self.headers = headers + else: + self.headers = HTTPHeaderDict(headers) + self.status = status + self.version = version + self.reason = reason + self.strict = strict + self.decode_content = decode_content + self.retries = retries + self.enforce_content_length = enforce_content_length + + self._decoder = None + self._body = None + self._fp = None + self._original_response = original_response + self._fp_bytes_read = 0 + + if body and isinstance(body, (basestring, binary_type)): + self._body = body + + self._pool = pool + self._connection = connection + + if hasattr(body, 'read'): + self._fp = body + + # Are we using the chunked-style of transfer encoding? + self.chunked = False + self.chunk_left = None + tr_enc = self.headers.get('transfer-encoding', '').lower() + # Don't incur the penalty of creating a list and then discarding it + encodings = (enc.strip() for enc in tr_enc.split(",")) + if "chunked" in encodings: + self.chunked = True + + # Determine length of response + self.length_remaining = self._init_length(request_method) + + # If requested, preload the body. + if preload_content and not self._body: + self._body = self.read(decode_content=decode_content) + + def get_redirect_location(self): + """ + Should we redirect and where to? + + :returns: Truthy redirect location string if we got a redirect status + code and valid location. ``None`` if redirect status and no + location. ``False`` if not a redirect status code. + """ + if self.status in self.REDIRECT_STATUSES: + return self.headers.get('location') + + return False + + def release_conn(self): + if not self._pool or not self._connection: + return + + self._pool._put_conn(self._connection) + self._connection = None + + @property + def data(self): + # For backwords-compat with earlier urllib3 0.4 and earlier. + if self._body: + return self._body + + if self._fp: + return self.read(cache_content=True) + + @property + def connection(self): + return self._connection + + def tell(self): + """ + Obtain the number of bytes pulled over the wire so far. May differ from + the amount of content returned by :meth:``HTTPResponse.read`` if bytes + are encoded on the wire (e.g, compressed). + """ + return self._fp_bytes_read + + def _init_length(self, request_method): + """ + Set initial length value for Response content if available. + """ + length = self.headers.get('content-length') + + if length is not None and self.chunked: + # This Response will fail with an IncompleteRead if it can't be + # received as chunked. This method falls back to attempt reading + # the response before raising an exception. + log.warning("Received response with both Content-Length and " + "Transfer-Encoding set. This is expressly forbidden " + "by RFC 7230 sec 3.3.2. Ignoring Content-Length and " + "attempting to process response as Transfer-Encoding: " + "chunked.") + return None + + elif length is not None: + try: + # RFC 7230 section 3.3.2 specifies multiple content lengths can + # be sent in a single Content-Length header + # (e.g. Content-Length: 42, 42). This line ensures the values + # are all valid ints and that as long as the `set` length is 1, + # all values are the same. Otherwise, the header is invalid. + lengths = set([int(val) for val in length.split(',')]) + if len(lengths) > 1: + raise InvalidHeader("Content-Length contained multiple " + "unmatching values (%s)" % length) + length = lengths.pop() + except ValueError: + length = None + else: + if length < 0: + length = None + + # Convert status to int for comparison + # In some cases, httplib returns a status of "_UNKNOWN" + try: + status = int(self.status) + except ValueError: + status = 0 + + # Check for responses that shouldn't include a body + if status in (204, 304) or 100 <= status < 200 or request_method == 'HEAD': + length = 0 + + return length + + def _init_decoder(self): + """ + Set-up the _decoder attribute if necessary. + """ + # Note: content-encoding value should be case-insensitive, per RFC 7230 + # Section 3.2 + content_encoding = self.headers.get('content-encoding', '').lower() + if self._decoder is None and content_encoding in self.CONTENT_DECODERS: + self._decoder = _get_decoder(content_encoding) + + def _decode(self, data, decode_content, flush_decoder): + """ + Decode the data passed in and potentially flush the decoder. + """ + try: + if decode_content and self._decoder: + data = self._decoder.decompress(data) + except (IOError, zlib.error) as e: + content_encoding = self.headers.get('content-encoding', '').lower() + raise DecodeError( + "Received response with content-encoding: %s, but " + "failed to decode it." % content_encoding, e) + + if flush_decoder and decode_content: + data += self._flush_decoder() + + return data + + def _flush_decoder(self): + """ + Flushes the decoder. Should only be called if the decoder is actually + being used. + """ + if self._decoder: + buf = self._decoder.decompress(b'') + return buf + self._decoder.flush() + + return b'' + + @contextmanager + def _error_catcher(self): + """ + Catch low-level python exceptions, instead re-raising urllib3 + variants, so that low-level exceptions are not leaked in the + high-level api. + + On exit, release the connection back to the pool. + """ + clean_exit = False + + try: + try: + yield + + except SocketTimeout: + # FIXME: Ideally we'd like to include the url in the ReadTimeoutError but + # there is yet no clean way to get at it from this context. + raise ReadTimeoutError(self._pool, None, 'Read timed out.') + + except BaseSSLError as e: + # FIXME: Is there a better way to differentiate between SSLErrors? + if 'read operation timed out' not in str(e): # Defensive: + # This shouldn't happen but just in case we're missing an edge + # case, let's avoid swallowing SSL errors. + raise + + raise ReadTimeoutError(self._pool, None, 'Read timed out.') + + except (HTTPException, SocketError) as e: + # This includes IncompleteRead. + raise ProtocolError('Connection broken: %r' % e, e) + + # If no exception is thrown, we should avoid cleaning up + # unnecessarily. + clean_exit = True + finally: + # If we didn't terminate cleanly, we need to throw away our + # connection. + if not clean_exit: + # The response may not be closed but we're not going to use it + # anymore so close it now to ensure that the connection is + # released back to the pool. + if self._original_response: + self._original_response.close() + + # Closing the response may not actually be sufficient to close + # everything, so if we have a hold of the connection close that + # too. + if self._connection: + self._connection.close() + + # If we hold the original response but it's closed now, we should + # return the connection back to the pool. + if self._original_response and self._original_response.isclosed(): + self.release_conn() + + def read(self, amt=None, decode_content=None, cache_content=False): + """ + Similar to :meth:`httplib.HTTPResponse.read`, but with two additional + parameters: ``decode_content`` and ``cache_content``. + + :param amt: + How much of the content to read. If specified, caching is skipped + because it doesn't make sense to cache partial content as the full + response. + + :param decode_content: + If True, will attempt to decode the body based on the + 'content-encoding' header. + + :param cache_content: + If True, will save the returned data such that the same result is + returned despite of the state of the underlying file object. This + is useful if you want the ``.data`` property to continue working + after having ``.read()`` the file object. (Overridden if ``amt`` is + set.) + """ + self._init_decoder() + if decode_content is None: + decode_content = self.decode_content + + if self._fp is None: + return + + flush_decoder = False + data = None + + with self._error_catcher(): + if amt is None: + # cStringIO doesn't like amt=None + data = self._fp.read() + flush_decoder = True + else: + cache_content = False + data = self._fp.read(amt) + if amt != 0 and not data: # Platform-specific: Buggy versions of Python. + # Close the connection when no data is returned + # + # This is redundant to what httplib/http.client _should_ + # already do. However, versions of python released before + # December 15, 2012 (http://bugs.python.org/issue16298) do + # not properly close the connection in all cases. There is + # no harm in redundantly calling close. + self._fp.close() + flush_decoder = True + if self.enforce_content_length and self.length_remaining not in (0, None): + # This is an edge case that httplib failed to cover due + # to concerns of backward compatibility. We're + # addressing it here to make sure IncompleteRead is + # raised during streaming, so all calls with incorrect + # Content-Length are caught. + raise IncompleteRead(self._fp_bytes_read, self.length_remaining) + + if data: + self._fp_bytes_read += len(data) + if self.length_remaining is not None: + self.length_remaining -= len(data) + + data = self._decode(data, decode_content, flush_decoder) + + if cache_content: + self._body = data + + return data + + def stream(self, amt=2**16, decode_content=None): + """ + A generator wrapper for the read() method. A call will block until + ``amt`` bytes have been read from the connection or until the + connection is closed. + + :param amt: + How much of the content to read. The generator will return up to + much data per iteration, but may return less. This is particularly + likely when using compressed data. However, the empty string will + never be returned. + + :param decode_content: + If True, will attempt to decode the body based on the + 'content-encoding' header. + """ + if self.chunked and self.supports_chunked_reads(): + for line in self.read_chunked(amt, decode_content=decode_content): + yield line + else: + while not is_fp_closed(self._fp): + data = self.read(amt=amt, decode_content=decode_content) + + if data: + yield data + + @classmethod + def from_httplib(ResponseCls, r, **response_kw): + """ + Given an :class:`httplib.HTTPResponse` instance ``r``, return a + corresponding :class:`urllib3.response.HTTPResponse` object. + + Remaining parameters are passed to the HTTPResponse constructor, along + with ``original_response=r``. + """ + headers = r.msg + + if not isinstance(headers, HTTPHeaderDict): + if PY3: # Python 3 + headers = HTTPHeaderDict(headers.items()) + else: # Python 2 + headers = HTTPHeaderDict.from_httplib(headers) + + # HTTPResponse objects in Python 3 don't have a .strict attribute + strict = getattr(r, 'strict', 0) + resp = ResponseCls(body=r, + headers=headers, + status=r.status, + version=r.version, + reason=r.reason, + strict=strict, + original_response=r, + **response_kw) + return resp + + # Backwards-compatibility methods for httplib.HTTPResponse + def getheaders(self): + return self.headers + + def getheader(self, name, default=None): + return self.headers.get(name, default) + + # Overrides from io.IOBase + def close(self): + if not self.closed: + self._fp.close() + + if self._connection: + self._connection.close() + + @property + def closed(self): + if self._fp is None: + return True + elif hasattr(self._fp, 'isclosed'): + return self._fp.isclosed() + elif hasattr(self._fp, 'closed'): + return self._fp.closed + else: + return True + + def fileno(self): + if self._fp is None: + raise IOError("HTTPResponse has no file to get a fileno from") + elif hasattr(self._fp, "fileno"): + return self._fp.fileno() + else: + raise IOError("The file-like object this HTTPResponse is wrapped " + "around has no file descriptor") + + def flush(self): + if self._fp is not None and hasattr(self._fp, 'flush'): + return self._fp.flush() + + def readable(self): + # This method is required for `io` module compatibility. + return True + + def readinto(self, b): + # This method is required for `io` module compatibility. + temp = self.read(len(b)) + if len(temp) == 0: + return 0 + else: + b[:len(temp)] = temp + return len(temp) + + def supports_chunked_reads(self): + """ + Checks if the underlying file-like object looks like a + httplib.HTTPResponse object. We do this by testing for the fp + attribute. If it is present we assume it returns raw chunks as + processed by read_chunked(). + """ + return hasattr(self._fp, 'fp') + + def _update_chunk_length(self): + # First, we'll figure out length of a chunk and then + # we'll try to read it from socket. + if self.chunk_left is not None: + return + line = self._fp.fp.readline() + line = line.split(b';', 1)[0] + try: + self.chunk_left = int(line, 16) + except ValueError: + # Invalid chunked protocol response, abort. + self.close() + raise httplib.IncompleteRead(line) + + def _handle_chunk(self, amt): + returned_chunk = None + if amt is None: + chunk = self._fp._safe_read(self.chunk_left) + returned_chunk = chunk + self._fp._safe_read(2) # Toss the CRLF at the end of the chunk. + self.chunk_left = None + elif amt < self.chunk_left: + value = self._fp._safe_read(amt) + self.chunk_left = self.chunk_left - amt + returned_chunk = value + elif amt == self.chunk_left: + value = self._fp._safe_read(amt) + self._fp._safe_read(2) # Toss the CRLF at the end of the chunk. + self.chunk_left = None + returned_chunk = value + else: # amt > self.chunk_left + returned_chunk = self._fp._safe_read(self.chunk_left) + self._fp._safe_read(2) # Toss the CRLF at the end of the chunk. + self.chunk_left = None + return returned_chunk + + def read_chunked(self, amt=None, decode_content=None): + """ + Similar to :meth:`HTTPResponse.read`, but with an additional + parameter: ``decode_content``. + + :param decode_content: + If True, will attempt to decode the body based on the + 'content-encoding' header. + """ + self._init_decoder() + # FIXME: Rewrite this method and make it a class with a better structured logic. + if not self.chunked: + raise ResponseNotChunked( + "Response is not chunked. " + "Header 'transfer-encoding: chunked' is missing.") + if not self.supports_chunked_reads(): + raise BodyNotHttplibCompatible( + "Body should be httplib.HTTPResponse like. " + "It should have have an fp attribute which returns raw chunks.") + + # Don't bother reading the body of a HEAD request. + if self._original_response and is_response_to_head(self._original_response): + self._original_response.close() + return + + with self._error_catcher(): + while True: + self._update_chunk_length() + if self.chunk_left == 0: + break + chunk = self._handle_chunk(amt) + decoded = self._decode(chunk, decode_content=decode_content, + flush_decoder=False) + if decoded: + yield decoded + + if decode_content: + # On CPython and PyPy, we should never need to flush the + # decoder. However, on Jython we *might* need to, so + # lets defensively do it anyway. + decoded = self._flush_decoder() + if decoded: # Platform-specific: Jython. + yield decoded + + # Chunk content ends with \r\n: discard it. + while True: + line = self._fp.fp.readline() + if not line: + # Some sites may not end with '\r\n'. + break + if line == b'\r\n': + break + + # We read everything; close the "file". + if self._original_response: + self._original_response.close() diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/__init__.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/__init__.py new file mode 100644 index 0000000..5ced5a4 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/__init__.py @@ -0,0 +1,52 @@ +from __future__ import absolute_import +# For backwards compatibility, provide imports that used to be here. +from .connection import is_connection_dropped +from .request import make_headers +from .response import is_fp_closed +from .ssl_ import ( + SSLContext, + HAS_SNI, + IS_PYOPENSSL, + assert_fingerprint, + resolve_cert_reqs, + resolve_ssl_version, + ssl_wrap_socket, +) +from .timeout import ( + current_time, + Timeout, +) + +from .retry import Retry +from .url import ( + get_host, + parse_url, + split_first, + Url, +) +from .wait import ( + wait_for_read, + wait_for_write +) + +__all__ = ( + 'HAS_SNI', + 'IS_PYOPENSSL', + 'SSLContext', + 'Retry', + 'Timeout', + 'Url', + 'assert_fingerprint', + 'current_time', + 'is_connection_dropped', + 'is_fp_closed', + 'get_host', + 'parse_url', + 'make_headers', + 'resolve_cert_reqs', + 'resolve_ssl_version', + 'split_first', + 'ssl_wrap_socket', + 'wait_for_read', + 'wait_for_write' +) diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/connection.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/connection.py new file mode 100644 index 0000000..bf699cf --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/connection.py @@ -0,0 +1,130 @@ +from __future__ import absolute_import +import socket +from .wait import wait_for_read +from .selectors import HAS_SELECT, SelectorError + + +def is_connection_dropped(conn): # Platform-specific + """ + Returns True if the connection is dropped and should be closed. + + :param conn: + :class:`httplib.HTTPConnection` object. + + Note: For platforms like AppEngine, this will always return ``False`` to + let the platform handle connection recycling transparently for us. + """ + sock = getattr(conn, 'sock', False) + if sock is False: # Platform-specific: AppEngine + return False + if sock is None: # Connection already closed (such as by httplib). + return True + + if not HAS_SELECT: + return False + + try: + return bool(wait_for_read(sock, timeout=0.0)) + except SelectorError: + return True + + +# This function is copied from socket.py in the Python 2.7 standard +# library test suite. Added to its signature is only `socket_options`. +# One additional modification is that we avoid binding to IPv6 servers +# discovered in DNS if the system doesn't have IPv6 functionality. +def create_connection(address, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, + source_address=None, socket_options=None): + """Connect to *address* and return the socket object. + + Convenience function. Connect to *address* (a 2-tuple ``(host, + port)``) and return the socket object. Passing the optional + *timeout* parameter will set the timeout on the socket instance + before attempting to connect. If no *timeout* is supplied, the + global default timeout setting returned by :func:`getdefaulttimeout` + is used. If *source_address* is set it must be a tuple of (host, port) + for the socket to bind as a source address before making the connection. + An host of '' or port 0 tells the OS to use the default. + """ + + host, port = address + if host.startswith('['): + host = host.strip('[]') + err = None + + # Using the value from allowed_gai_family() in the context of getaddrinfo lets + # us select whether to work with IPv4 DNS records, IPv6 records, or both. + # The original create_connection function always returns all records. + family = allowed_gai_family() + + for res in socket.getaddrinfo(host, port, family, socket.SOCK_STREAM): + af, socktype, proto, canonname, sa = res + sock = None + try: + sock = socket.socket(af, socktype, proto) + + # If provided, set socket level options before connecting. + _set_socket_options(sock, socket_options) + + if timeout is not socket._GLOBAL_DEFAULT_TIMEOUT: + sock.settimeout(timeout) + if source_address: + sock.bind(source_address) + sock.connect(sa) + return sock + + except socket.error as e: + err = e + if sock is not None: + sock.close() + sock = None + + if err is not None: + raise err + + raise socket.error("getaddrinfo returns an empty list") + + +def _set_socket_options(sock, options): + if options is None: + return + + for opt in options: + sock.setsockopt(*opt) + + +def allowed_gai_family(): + """This function is designed to work in the context of + getaddrinfo, where family=socket.AF_UNSPEC is the default and + will perform a DNS search for both IPv6 and IPv4 records.""" + + family = socket.AF_INET + if HAS_IPV6: + family = socket.AF_UNSPEC + return family + + +def _has_ipv6(host): + """ Returns True if the system can bind an IPv6 address. """ + sock = None + has_ipv6 = False + + if socket.has_ipv6: + # has_ipv6 returns true if cPython was compiled with IPv6 support. + # It does not tell us if the system has IPv6 support enabled. To + # determine that we must bind to an IPv6 address. + # https://github.com/shazow/urllib3/pull/611 + # https://bugs.python.org/issue658327 + try: + sock = socket.socket(socket.AF_INET6) + sock.bind((host, 0)) + has_ipv6 = True + except Exception: + pass + + if sock: + sock.close() + return has_ipv6 + + +HAS_IPV6 = _has_ipv6('::1') diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/request.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/request.py new file mode 100644 index 0000000..974fc40 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/request.py @@ -0,0 +1,118 @@ +from __future__ import absolute_import +from base64 import b64encode + +from ..packages.six import b, integer_types +from ..exceptions import UnrewindableBodyError + +ACCEPT_ENCODING = 'gzip,deflate' +_FAILEDTELL = object() + + +def make_headers(keep_alive=None, accept_encoding=None, user_agent=None, + basic_auth=None, proxy_basic_auth=None, disable_cache=None): + """ + Shortcuts for generating request headers. + + :param keep_alive: + If ``True``, adds 'connection: keep-alive' header. + + :param accept_encoding: + Can be a boolean, list, or string. + ``True`` translates to 'gzip,deflate'. + List will get joined by comma. + String will be used as provided. + + :param user_agent: + String representing the user-agent you want, such as + "python-urllib3/0.6" + + :param basic_auth: + Colon-separated username:password string for 'authorization: basic ...' + auth header. + + :param proxy_basic_auth: + Colon-separated username:password string for 'proxy-authorization: basic ...' + auth header. + + :param disable_cache: + If ``True``, adds 'cache-control: no-cache' header. + + Example:: + + >>> make_headers(keep_alive=True, user_agent="Batman/1.0") + {'connection': 'keep-alive', 'user-agent': 'Batman/1.0'} + >>> make_headers(accept_encoding=True) + {'accept-encoding': 'gzip,deflate'} + """ + headers = {} + if accept_encoding: + if isinstance(accept_encoding, str): + pass + elif isinstance(accept_encoding, list): + accept_encoding = ','.join(accept_encoding) + else: + accept_encoding = ACCEPT_ENCODING + headers['accept-encoding'] = accept_encoding + + if user_agent: + headers['user-agent'] = user_agent + + if keep_alive: + headers['connection'] = 'keep-alive' + + if basic_auth: + headers['authorization'] = 'Basic ' + \ + b64encode(b(basic_auth)).decode('utf-8') + + if proxy_basic_auth: + headers['proxy-authorization'] = 'Basic ' + \ + b64encode(b(proxy_basic_auth)).decode('utf-8') + + if disable_cache: + headers['cache-control'] = 'no-cache' + + return headers + + +def set_file_position(body, pos): + """ + If a position is provided, move file to that point. + Otherwise, we'll attempt to record a position for future use. + """ + if pos is not None: + rewind_body(body, pos) + elif getattr(body, 'tell', None) is not None: + try: + pos = body.tell() + except (IOError, OSError): + # This differentiates from None, allowing us to catch + # a failed `tell()` later when trying to rewind the body. + pos = _FAILEDTELL + + return pos + + +def rewind_body(body, body_pos): + """ + Attempt to rewind body to a certain position. + Primarily used for request redirects and retries. + + :param body: + File-like object that supports seek. + + :param int pos: + Position to seek to in file. + """ + body_seek = getattr(body, 'seek', None) + if body_seek is not None and isinstance(body_pos, integer_types): + try: + body_seek(body_pos) + except (IOError, OSError): + raise UnrewindableBodyError("An error occured when rewinding request " + "body for redirect/retry.") + elif body_pos is _FAILEDTELL: + raise UnrewindableBodyError("Unable to record file position for rewinding " + "request body during a redirect/retry.") + else: + raise ValueError("body_pos must be of type integer, " + "instead it was %s." % type(body_pos)) diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/response.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/response.py new file mode 100644 index 0000000..67cf730 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/response.py @@ -0,0 +1,81 @@ +from __future__ import absolute_import +from ..packages.six.moves import http_client as httplib + +from ..exceptions import HeaderParsingError + + +def is_fp_closed(obj): + """ + Checks whether a given file-like object is closed. + + :param obj: + The file-like object to check. + """ + + try: + # Check `isclosed()` first, in case Python3 doesn't set `closed`. + # GH Issue #928 + return obj.isclosed() + except AttributeError: + pass + + try: + # Check via the official file-like-object way. + return obj.closed + except AttributeError: + pass + + try: + # Check if the object is a container for another file-like object that + # gets released on exhaustion (e.g. HTTPResponse). + return obj.fp is None + except AttributeError: + pass + + raise ValueError("Unable to determine whether fp is closed.") + + +def assert_header_parsing(headers): + """ + Asserts whether all headers have been successfully parsed. + Extracts encountered errors from the result of parsing headers. + + Only works on Python 3. + + :param headers: Headers to verify. + :type headers: `httplib.HTTPMessage`. + + :raises urllib3.exceptions.HeaderParsingError: + If parsing errors are found. + """ + + # This will fail silently if we pass in the wrong kind of parameter. + # To make debugging easier add an explicit check. + if not isinstance(headers, httplib.HTTPMessage): + raise TypeError('expected httplib.Message, got {0}.'.format( + type(headers))) + + defects = getattr(headers, 'defects', None) + get_payload = getattr(headers, 'get_payload', None) + + unparsed_data = None + if get_payload: # Platform-specific: Python 3. + unparsed_data = get_payload() + + if defects or unparsed_data: + raise HeaderParsingError(defects=defects, unparsed_data=unparsed_data) + + +def is_response_to_head(response): + """ + Checks whether the request of a response has been a HEAD-request. + Handles the quirks of AppEngine. + + :param conn: + :type conn: :class:`httplib.HTTPResponse` + """ + # FIXME: Can we do this somehow without accessing private httplib _method? + method = response._method + if isinstance(method, int): # Platform-specific: Appengine + return method == 3 + return method.upper() == 'HEAD' diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/retry.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/retry.py new file mode 100644 index 0000000..c9e7d28 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/retry.py @@ -0,0 +1,389 @@ +from __future__ import absolute_import +import time +import logging +from collections import namedtuple +from itertools import takewhile +import email +import re + +from ..exceptions import ( + ConnectTimeoutError, + MaxRetryError, + ProtocolError, + ReadTimeoutError, + ResponseError, + InvalidHeader, +) +from ..packages import six + + +log = logging.getLogger(__name__) + +# Data structure for representing the metadata of requests that result in a retry. +RequestHistory = namedtuple('RequestHistory', ["method", "url", "error", + "status", "redirect_location"]) + + +class Retry(object): + """ Retry configuration. + + Each retry attempt will create a new Retry object with updated values, so + they can be safely reused. + + Retries can be defined as a default for a pool:: + + retries = Retry(connect=5, read=2, redirect=5) + http = PoolManager(retries=retries) + response = http.request('GET', 'http://example.com/') + + Or per-request (which overrides the default for the pool):: + + response = http.request('GET', 'http://example.com/', retries=Retry(10)) + + Retries can be disabled by passing ``False``:: + + response = http.request('GET', 'http://example.com/', retries=False) + + Errors will be wrapped in :class:`~urllib3.exceptions.MaxRetryError` unless + retries are disabled, in which case the causing exception will be raised. + + :param int total: + Total number of retries to allow. Takes precedence over other counts. + + Set to ``None`` to remove this constraint and fall back on other + counts. It's a good idea to set this to some sensibly-high value to + account for unexpected edge cases and avoid infinite retry loops. + + Set to ``0`` to fail on the first retry. + + Set to ``False`` to disable and imply ``raise_on_redirect=False``. + + :param int connect: + How many connection-related errors to retry on. + + These are errors raised before the request is sent to the remote server, + which we assume has not triggered the server to process the request. + + Set to ``0`` to fail on the first retry of this type. + + :param int read: + How many times to retry on read errors. + + These errors are raised after the request was sent to the server, so the + request may have side-effects. + + Set to ``0`` to fail on the first retry of this type. + + :param int redirect: + How many redirects to perform. Limit this to avoid infinite redirect + loops. + + A redirect is a HTTP response with a status code 301, 302, 303, 307 or + 308. + + Set to ``0`` to fail on the first retry of this type. + + Set to ``False`` to disable and imply ``raise_on_redirect=False``. + + :param iterable method_whitelist: + Set of uppercased HTTP method verbs that we should retry on. + + By default, we only retry on methods which are considered to be + idempotent (multiple requests with the same parameters end with the + same state). See :attr:`Retry.DEFAULT_METHOD_WHITELIST`. + + Set to a ``False`` value to retry on any verb. + + :param iterable status_forcelist: + A set of integer HTTP status codes that we should force a retry on. + A retry is initiated if the request method is in ``method_whitelist`` + and the response status code is in ``status_forcelist``. + + By default, this is disabled with ``None``. + + :param float backoff_factor: + A backoff factor to apply between attempts after the second try + (most errors are resolved immediately by a second try without a + delay). urllib3 will sleep for:: + + {backoff factor} * (2 ^ ({number of total retries} - 1)) + + seconds. If the backoff_factor is 0.1, then :func:`.sleep` will sleep + for [0.0s, 0.2s, 0.4s, ...] between retries. It will never be longer + than :attr:`Retry.BACKOFF_MAX`. + + By default, backoff is disabled (set to 0). + + :param bool raise_on_redirect: Whether, if the number of redirects is + exhausted, to raise a MaxRetryError, or to return a response with a + response code in the 3xx range. + + :param bool raise_on_status: Similar meaning to ``raise_on_redirect``: + whether we should raise an exception, or return a response, + if status falls in ``status_forcelist`` range and retries have + been exhausted. + + :param tuple history: The history of the request encountered during + each call to :meth:`~Retry.increment`. The list is in the order + the requests occurred. Each list item is of class :class:`RequestHistory`. + + :param bool respect_retry_after_header: + Whether to respect Retry-After header on status codes defined as + :attr:`Retry.RETRY_AFTER_STATUS_CODES` or not. + + """ + + DEFAULT_METHOD_WHITELIST = frozenset([ + 'HEAD', 'GET', 'PUT', 'DELETE', 'OPTIONS', 'TRACE']) + + RETRY_AFTER_STATUS_CODES = frozenset([413, 429, 503]) + + #: Maximum backoff time. + BACKOFF_MAX = 120 + + def __init__(self, total=10, connect=None, read=None, redirect=None, + method_whitelist=DEFAULT_METHOD_WHITELIST, status_forcelist=None, + backoff_factor=0, raise_on_redirect=True, raise_on_status=True, + history=None, respect_retry_after_header=True): + + self.total = total + self.connect = connect + self.read = read + + if redirect is False or total is False: + redirect = 0 + raise_on_redirect = False + + self.redirect = redirect + self.status_forcelist = status_forcelist or set() + self.method_whitelist = method_whitelist + self.backoff_factor = backoff_factor + self.raise_on_redirect = raise_on_redirect + self.raise_on_status = raise_on_status + self.history = history or tuple() + self.respect_retry_after_header = respect_retry_after_header + + def new(self, **kw): + params = dict( + total=self.total, + connect=self.connect, read=self.read, redirect=self.redirect, + method_whitelist=self.method_whitelist, + status_forcelist=self.status_forcelist, + backoff_factor=self.backoff_factor, + raise_on_redirect=self.raise_on_redirect, + raise_on_status=self.raise_on_status, + history=self.history, + ) + params.update(kw) + return type(self)(**params) + + @classmethod + def from_int(cls, retries, redirect=True, default=None): + """ Backwards-compatibility for the old retries format.""" + if retries is None: + retries = default if default is not None else cls.DEFAULT + + if isinstance(retries, Retry): + return retries + + redirect = bool(redirect) and None + new_retries = cls(retries, redirect=redirect) + log.debug("Converted retries value: %r -> %r", retries, new_retries) + return new_retries + + def get_backoff_time(self): + """ Formula for computing the current backoff + + :rtype: float + """ + # We want to consider only the last consecutive errors sequence (Ignore redirects). + consecutive_errors_len = len(list(takewhile(lambda x: x.redirect_location is None, + reversed(self.history)))) + if consecutive_errors_len <= 1: + return 0 + + backoff_value = self.backoff_factor * (2 ** (consecutive_errors_len - 1)) + return min(self.BACKOFF_MAX, backoff_value) + + def parse_retry_after(self, retry_after): + # Whitespace: https://tools.ietf.org/html/rfc7230#section-3.2.4 + if re.match(r"^\s*[0-9]+\s*$", retry_after): + seconds = int(retry_after) + else: + retry_date_tuple = email.utils.parsedate(retry_after) + if retry_date_tuple is None: + raise InvalidHeader("Invalid Retry-After header: %s" % retry_after) + retry_date = time.mktime(retry_date_tuple) + seconds = retry_date - time.time() + + if seconds < 0: + seconds = 0 + + return seconds + + def get_retry_after(self, response): + """ Get the value of Retry-After in seconds. """ + + retry_after = response.getheader("Retry-After") + + if retry_after is None: + return None + + return self.parse_retry_after(retry_after) + + def sleep_for_retry(self, response=None): + retry_after = self.get_retry_after(response) + if retry_after: + time.sleep(retry_after) + return True + + return False + + def _sleep_backoff(self): + backoff = self.get_backoff_time() + if backoff <= 0: + return + time.sleep(backoff) + + def sleep(self, response=None): + """ Sleep between retry attempts. + + This method will respect a server's ``Retry-After`` response header + and sleep the duration of the time requested. If that is not present, it + will use an exponential backoff. By default, the backoff factor is 0 and + this method will return immediately. + """ + + if response: + slept = self.sleep_for_retry(response) + if slept: + return + + self._sleep_backoff() + + def _is_connection_error(self, err): + """ Errors when we're fairly sure that the server did not receive the + request, so it should be safe to retry. + """ + return isinstance(err, ConnectTimeoutError) + + def _is_read_error(self, err): + """ Errors that occur after the request has been started, so we should + assume that the server began processing it. + """ + return isinstance(err, (ReadTimeoutError, ProtocolError)) + + def _is_method_retryable(self, method): + """ Checks if a given HTTP method should be retried upon, depending if + it is included on the method whitelist. + """ + if self.method_whitelist and method.upper() not in self.method_whitelist: + return False + + return True + + def is_retry(self, method, status_code, has_retry_after=False): + """ Is this method/status code retryable? (Based on whitelists and control + variables such as the number of total retries to allow, whether to + respect the Retry-After header, whether this header is present, and + whether the returned status code is on the list of status codes to + be retried upon on the presence of the aforementioned header) + """ + if not self._is_method_retryable(method): + return False + + if self.status_forcelist and status_code in self.status_forcelist: + return True + + return (self.total and self.respect_retry_after_header and + has_retry_after and (status_code in self.RETRY_AFTER_STATUS_CODES)) + + def is_exhausted(self): + """ Are we out of retries? """ + retry_counts = (self.total, self.connect, self.read, self.redirect) + retry_counts = list(filter(None, retry_counts)) + if not retry_counts: + return False + + return min(retry_counts) < 0 + + def increment(self, method=None, url=None, response=None, error=None, + _pool=None, _stacktrace=None): + """ Return a new Retry object with incremented retry counters. + + :param response: A response object, or None, if the server did not + return a response. + :type response: :class:`~urllib3.response.HTTPResponse` + :param Exception error: An error encountered during the request, or + None if the response was received successfully. + + :return: A new ``Retry`` object. + """ + if self.total is False and error: + # Disabled, indicate to re-raise the error. + raise six.reraise(type(error), error, _stacktrace) + + total = self.total + if total is not None: + total -= 1 + + connect = self.connect + read = self.read + redirect = self.redirect + cause = 'unknown' + status = None + redirect_location = None + + if error and self._is_connection_error(error): + # Connect retry? + if connect is False: + raise six.reraise(type(error), error, _stacktrace) + elif connect is not None: + connect -= 1 + + elif error and self._is_read_error(error): + # Read retry? + if read is False or not self._is_method_retryable(method): + raise six.reraise(type(error), error, _stacktrace) + elif read is not None: + read -= 1 + + elif response and response.get_redirect_location(): + # Redirect retry? + if redirect is not None: + redirect -= 1 + cause = 'too many redirects' + redirect_location = response.get_redirect_location() + status = response.status + + else: + # Incrementing because of a server error like a 500 in + # status_forcelist and a the given method is in the whitelist + cause = ResponseError.GENERIC_ERROR + if response and response.status: + cause = ResponseError.SPECIFIC_ERROR.format( + status_code=response.status) + status = response.status + + history = self.history + (RequestHistory(method, url, error, status, redirect_location),) + + new_retry = self.new( + total=total, + connect=connect, read=read, redirect=redirect, + history=history) + + if new_retry.is_exhausted(): + raise MaxRetryError(_pool, url, error or ResponseError(cause)) + + log.debug("Incremented Retry for (url='%s'): %r", url, new_retry) + + return new_retry + + def __repr__(self): + return ('{cls.__name__}(total={self.total}, connect={self.connect}, ' + 'read={self.read}, redirect={self.redirect})').format( + cls=type(self), self=self) + + +# For backwards compatibility (equivalent to pre-v1.9): +Retry.DEFAULT = Retry(3) diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/selectors.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/selectors.py new file mode 100644 index 0000000..b381450 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/selectors.py @@ -0,0 +1,529 @@ +# Backport of selectors.py from Python 3.5+ to support Python < 3.4 +# Also has the behavior specified in PEP 475 which is to retry syscalls +# in the case of an EINTR error. This module is required because selectors34 +# does not follow this behavior and instead returns that no dile descriptor +# events have occurred rather than retry the syscall. The decision to drop +# support for select.devpoll is made to maintain 100% test coverage. + +import errno +import math +import select +from collections import namedtuple + +try: + from collections.abc import Mapping +except ImportError: + from collections import Mapping + +import time +try: + monotonic = time.monotonic +except (AttributeError, ImportError): # Python 3.3< + monotonic = time.time + +EVENT_READ = (1 << 0) +EVENT_WRITE = (1 << 1) + +HAS_SELECT = True # Variable that shows whether the platform has a selector. +_SYSCALL_SENTINEL = object() # Sentinel in case a system call returns None. + + +class SelectorError(Exception): + def __init__(self, errcode): + super(SelectorError, self).__init__() + self.errno = errcode + + def __repr__(self): + return "<SelectorError errno={0}>".format(self.errno) + + def __str__(self): + return self.__repr__() + + +def _fileobj_to_fd(fileobj): + """ Return a file descriptor from a file object. If + given an integer will simply return that integer back. """ + if isinstance(fileobj, int): + fd = fileobj + else: + try: + fd = int(fileobj.fileno()) + except (AttributeError, TypeError, ValueError): + raise ValueError("Invalid file object: {0!r}".format(fileobj)) + if fd < 0: + raise ValueError("Invalid file descriptor: {0}".format(fd)) + return fd + + +def _syscall_wrapper(func, recalc_timeout, *args, **kwargs): + """ Wrapper function for syscalls that could fail due to EINTR. + All functions should be retried if there is time left in the timeout + in accordance with PEP 475. """ + timeout = kwargs.get("timeout", None) + if timeout is None: + expires = None + recalc_timeout = False + else: + timeout = float(timeout) + if timeout < 0.0: # Timeout less than 0 treated as no timeout. + expires = None + else: + expires = monotonic() + timeout + + args = list(args) + if recalc_timeout and "timeout" not in kwargs: + raise ValueError( + "Timeout must be in args or kwargs to be recalculated") + + result = _SYSCALL_SENTINEL + while result is _SYSCALL_SENTINEL: + try: + result = func(*args, **kwargs) + # OSError is thrown by select.select + # IOError is thrown by select.epoll.poll + # select.error is thrown by select.poll.poll + # Aren't we thankful for Python 3.x rework for exceptions? + except (OSError, IOError, select.error) as e: + # select.error wasn't a subclass of OSError in the past. + errcode = None + if hasattr(e, "errno"): + errcode = e.errno + elif hasattr(e, "args"): + errcode = e.args[0] + + # Also test for the Windows equivalent of EINTR. + is_interrupt = (errcode == errno.EINTR or (hasattr(errno, "WSAEINTR") and + errcode == errno.WSAEINTR)) + + if is_interrupt: + if expires is not None: + current_time = monotonic() + if current_time > expires: + raise OSError(errno=errno.ETIMEDOUT) + if recalc_timeout: + if "timeout" in kwargs: + kwargs["timeout"] = expires - current_time + continue + if errcode: + raise SelectorError(errcode) + else: + raise + return result + + +SelectorKey = namedtuple('SelectorKey', ['fileobj', 'fd', 'events', 'data']) + + +class _SelectorMapping(Mapping): + """ Mapping of file objects to selector keys """ + + def __init__(self, selector): + self._selector = selector + + def __len__(self): + return len(self._selector._fd_to_key) + + def __getitem__(self, fileobj): + try: + fd = self._selector._fileobj_lookup(fileobj) + return self._selector._fd_to_key[fd] + except KeyError: + raise KeyError("{0!r} is not registered.".format(fileobj)) + + def __iter__(self): + return iter(self._selector._fd_to_key) + + +class BaseSelector(object): + """ Abstract Selector class + + A selector supports registering file objects to be monitored + for specific I/O events. + + A file object is a file descriptor or any object with a + `fileno()` method. An arbitrary object can be attached to the + file object which can be used for example to store context info, + a callback, etc. + + A selector can use various implementations (select(), poll(), epoll(), + and kqueue()) depending on the platform. The 'DefaultSelector' class uses + the most efficient implementation for the current platform. + """ + def __init__(self): + # Maps file descriptors to keys. + self._fd_to_key = {} + + # Read-only mapping returned by get_map() + self._map = _SelectorMapping(self) + + def _fileobj_lookup(self, fileobj): + """ Return a file descriptor from a file object. + This wraps _fileobj_to_fd() to do an exhaustive + search in case the object is invalid but we still + have it in our map. Used by unregister() so we can + unregister an object that was previously registered + even if it is closed. It is also used by _SelectorMapping + """ + try: + return _fileobj_to_fd(fileobj) + except ValueError: + + # Search through all our mapped keys. + for key in self._fd_to_key.values(): + if key.fileobj is fileobj: + return key.fd + + # Raise ValueError after all. + raise + + def register(self, fileobj, events, data=None): + """ Register a file object for a set of events to monitor. """ + if (not events) or (events & ~(EVENT_READ | EVENT_WRITE)): + raise ValueError("Invalid events: {0!r}".format(events)) + + key = SelectorKey(fileobj, self._fileobj_lookup(fileobj), events, data) + + if key.fd in self._fd_to_key: + raise KeyError("{0!r} (FD {1}) is already registered" + .format(fileobj, key.fd)) + + self._fd_to_key[key.fd] = key + return key + + def unregister(self, fileobj): + """ Unregister a file object from being monitored. """ + try: + key = self._fd_to_key.pop(self._fileobj_lookup(fileobj)) + except KeyError: + raise KeyError("{0!r} is not registered".format(fileobj)) + return key + + def modify(self, fileobj, events, data=None): + """ Change a registered file object monitored events and data. """ + # NOTE: Some subclasses optimize this operation even further. + try: + key = self._fd_to_key[self._fileobj_lookup(fileobj)] + except KeyError: + raise KeyError("{0!r} is not registered".format(fileobj)) + + if events != key.events: + self.unregister(fileobj) + key = self.register(fileobj, events, data) + + elif data != key.data: + # Use a shortcut to update the data. + key = key._replace(data=data) + self._fd_to_key[key.fd] = key + + return key + + def select(self, timeout=None): + """ Perform the actual selection until some monitored file objects + are ready or the timeout expires. """ + raise NotImplementedError() + + def close(self): + """ Close the selector. This must be called to ensure that all + underlying resources are freed. """ + self._fd_to_key.clear() + self._map = None + + def get_key(self, fileobj): + """ Return the key associated with a registered file object. """ + mapping = self.get_map() + if mapping is None: + raise RuntimeError("Selector is closed") + try: + return mapping[fileobj] + except KeyError: + raise KeyError("{0!r} is not registered".format(fileobj)) + + def get_map(self): + """ Return a mapping of file objects to selector keys """ + return self._map + + def _key_from_fd(self, fd): + """ Return the key associated to a given file descriptor + Return None if it is not found. """ + try: + return self._fd_to_key[fd] + except KeyError: + return None + + def __enter__(self): + return self + + def __exit__(self, *args): + self.close() + + +# Almost all platforms have select.select() +if hasattr(select, "select"): + class SelectSelector(BaseSelector): + """ Select-based selector. """ + def __init__(self): + super(SelectSelector, self).__init__() + self._readers = set() + self._writers = set() + + def register(self, fileobj, events, data=None): + key = super(SelectSelector, self).register(fileobj, events, data) + if events & EVENT_READ: + self._readers.add(key.fd) + if events & EVENT_WRITE: + self._writers.add(key.fd) + return key + + def unregister(self, fileobj): + key = super(SelectSelector, self).unregister(fileobj) + self._readers.discard(key.fd) + self._writers.discard(key.fd) + return key + + def _select(self, r, w, timeout=None): + """ Wrapper for select.select because timeout is a positional arg """ + return select.select(r, w, [], timeout) + + def select(self, timeout=None): + # Selecting on empty lists on Windows errors out. + if not len(self._readers) and not len(self._writers): + return [] + + timeout = None if timeout is None else max(timeout, 0.0) + ready = [] + r, w, _ = _syscall_wrapper(self._select, True, self._readers, + self._writers, timeout) + r = set(r) + w = set(w) + for fd in r | w: + events = 0 + if fd in r: + events |= EVENT_READ + if fd in w: + events |= EVENT_WRITE + + key = self._key_from_fd(fd) + if key: + ready.append((key, events & key.events)) + return ready + + +if hasattr(select, "poll"): + class PollSelector(BaseSelector): + """ Poll-based selector """ + def __init__(self): + super(PollSelector, self).__init__() + self._poll = select.poll() + + def register(self, fileobj, events, data=None): + key = super(PollSelector, self).register(fileobj, events, data) + event_mask = 0 + if events & EVENT_READ: + event_mask |= select.POLLIN + if events & EVENT_WRITE: + event_mask |= select.POLLOUT + self._poll.register(key.fd, event_mask) + return key + + def unregister(self, fileobj): + key = super(PollSelector, self).unregister(fileobj) + self._poll.unregister(key.fd) + return key + + def _wrap_poll(self, timeout=None): + """ Wrapper function for select.poll.poll() so that + _syscall_wrapper can work with only seconds. """ + if timeout is not None: + if timeout <= 0: + timeout = 0 + else: + # select.poll.poll() has a resolution of 1 millisecond, + # round away from zero to wait *at least* timeout seconds. + timeout = math.ceil(timeout * 1e3) + + result = self._poll.poll(timeout) + return result + + def select(self, timeout=None): + ready = [] + fd_events = _syscall_wrapper(self._wrap_poll, True, timeout=timeout) + for fd, event_mask in fd_events: + events = 0 + if event_mask & ~select.POLLIN: + events |= EVENT_WRITE + if event_mask & ~select.POLLOUT: + events |= EVENT_READ + + key = self._key_from_fd(fd) + if key: + ready.append((key, events & key.events)) + + return ready + + +if hasattr(select, "epoll"): + class EpollSelector(BaseSelector): + """ Epoll-based selector """ + def __init__(self): + super(EpollSelector, self).__init__() + self._epoll = select.epoll() + + def fileno(self): + return self._epoll.fileno() + + def register(self, fileobj, events, data=None): + key = super(EpollSelector, self).register(fileobj, events, data) + events_mask = 0 + if events & EVENT_READ: + events_mask |= select.EPOLLIN + if events & EVENT_WRITE: + events_mask |= select.EPOLLOUT + _syscall_wrapper(self._epoll.register, False, key.fd, events_mask) + return key + + def unregister(self, fileobj): + key = super(EpollSelector, self).unregister(fileobj) + try: + _syscall_wrapper(self._epoll.unregister, False, key.fd) + except SelectorError: + # This can occur when the fd was closed since registry. + pass + return key + + def select(self, timeout=None): + if timeout is not None: + if timeout <= 0: + timeout = 0.0 + else: + # select.epoll.poll() has a resolution of 1 millisecond + # but luckily takes seconds so we don't need a wrapper + # like PollSelector. Just for better rounding. + timeout = math.ceil(timeout * 1e3) * 1e-3 + timeout = float(timeout) + else: + timeout = -1.0 # epoll.poll() must have a float. + + # We always want at least 1 to ensure that select can be called + # with no file descriptors registered. Otherwise will fail. + max_events = max(len(self._fd_to_key), 1) + + ready = [] + fd_events = _syscall_wrapper(self._epoll.poll, True, + timeout=timeout, + maxevents=max_events) + for fd, event_mask in fd_events: + events = 0 + if event_mask & ~select.EPOLLIN: + events |= EVENT_WRITE + if event_mask & ~select.EPOLLOUT: + events |= EVENT_READ + + key = self._key_from_fd(fd) + if key: + ready.append((key, events & key.events)) + return ready + + def close(self): + self._epoll.close() + super(EpollSelector, self).close() + + +if hasattr(select, "kqueue"): + class KqueueSelector(BaseSelector): + """ Kqueue / Kevent-based selector """ + def __init__(self): + super(KqueueSelector, self).__init__() + self._kqueue = select.kqueue() + + def fileno(self): + return self._kqueue.fileno() + + def register(self, fileobj, events, data=None): + key = super(KqueueSelector, self).register(fileobj, events, data) + if events & EVENT_READ: + kevent = select.kevent(key.fd, + select.KQ_FILTER_READ, + select.KQ_EV_ADD) + + _syscall_wrapper(self._kqueue.control, False, [kevent], 0, 0) + + if events & EVENT_WRITE: + kevent = select.kevent(key.fd, + select.KQ_FILTER_WRITE, + select.KQ_EV_ADD) + + _syscall_wrapper(self._kqueue.control, False, [kevent], 0, 0) + + return key + + def unregister(self, fileobj): + key = super(KqueueSelector, self).unregister(fileobj) + if key.events & EVENT_READ: + kevent = select.kevent(key.fd, + select.KQ_FILTER_READ, + select.KQ_EV_DELETE) + try: + _syscall_wrapper(self._kqueue.control, False, [kevent], 0, 0) + except SelectorError: + pass + if key.events & EVENT_WRITE: + kevent = select.kevent(key.fd, + select.KQ_FILTER_WRITE, + select.KQ_EV_DELETE) + try: + _syscall_wrapper(self._kqueue.control, False, [kevent], 0, 0) + except SelectorError: + pass + + return key + + def select(self, timeout=None): + if timeout is not None: + timeout = max(timeout, 0) + + max_events = len(self._fd_to_key) * 2 + ready_fds = {} + + kevent_list = _syscall_wrapper(self._kqueue.control, True, + None, max_events, timeout) + + for kevent in kevent_list: + fd = kevent.ident + event_mask = kevent.filter + events = 0 + if event_mask == select.KQ_FILTER_READ: + events |= EVENT_READ + if event_mask == select.KQ_FILTER_WRITE: + events |= EVENT_WRITE + + key = self._key_from_fd(fd) + if key: + if key.fd not in ready_fds: + ready_fds[key.fd] = (key, events & key.events) + else: + old_events = ready_fds[key.fd][1] + ready_fds[key.fd] = (key, (events | old_events) & key.events) + + return list(ready_fds.values()) + + def close(self): + self._kqueue.close() + super(KqueueSelector, self).close() + + +# Choose the best implementation, roughly: +# kqueue == epoll > poll > select. Devpoll not supported. (See above) +# select() also can't accept a FD > FD_SETSIZE (usually around 1024) +if 'KqueueSelector' in globals(): # Platform-specific: Mac OS and BSD + DefaultSelector = KqueueSelector +elif 'EpollSelector' in globals(): # Platform-specific: Linux + DefaultSelector = EpollSelector +elif 'PollSelector' in globals(): # Platform-specific: Linux + DefaultSelector = PollSelector +elif 'SelectSelector' in globals(): # Platform-specific: Windows + DefaultSelector = SelectSelector +else: # Platform-specific: AppEngine + def no_selector(_): + raise ValueError("Platform does not have a selector") + DefaultSelector = no_selector + HAS_SELECT = False diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/ssl_.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/ssl_.py new file mode 100644 index 0000000..c4c55df --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/ssl_.py @@ -0,0 +1,336 @@ +from __future__ import absolute_import +import errno +import warnings +import hmac + +from binascii import hexlify, unhexlify +from hashlib import md5, sha1, sha256 + +from ..exceptions import SSLError, InsecurePlatformWarning, SNIMissingWarning + + +SSLContext = None +HAS_SNI = False +IS_PYOPENSSL = False + +# Maps the length of a digest to a possible hash function producing this digest +HASHFUNC_MAP = { + 32: md5, + 40: sha1, + 64: sha256, +} + + +def _const_compare_digest_backport(a, b): + """ + Compare two digests of equal length in constant time. + + The digests must be of type str/bytes. + Returns True if the digests match, and False otherwise. + """ + result = abs(len(a) - len(b)) + for l, r in zip(bytearray(a), bytearray(b)): + result |= l ^ r + return result == 0 + + +_const_compare_digest = getattr(hmac, 'compare_digest', + _const_compare_digest_backport) + + +try: # Test for SSL features + import ssl + from ssl import wrap_socket, CERT_NONE, PROTOCOL_SSLv23 + from ssl import HAS_SNI # Has SNI? +except ImportError: + pass + + +try: + from ssl import OP_NO_SSLv2, OP_NO_SSLv3, OP_NO_COMPRESSION +except ImportError: + OP_NO_SSLv2, OP_NO_SSLv3 = 0x1000000, 0x2000000 + OP_NO_COMPRESSION = 0x20000 + +# A secure default. +# Sources for more information on TLS ciphers: +# +# - https://wiki.mozilla.org/Security/Server_Side_TLS +# - https://www.ssllabs.com/projects/best-practices/index.html +# - https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/ +# +# The general intent is: +# - Prefer cipher suites that offer perfect forward secrecy (DHE/ECDHE), +# - prefer ECDHE over DHE for better performance, +# - prefer any AES-GCM and ChaCha20 over any AES-CBC for better performance and +# security, +# - prefer AES-GCM over ChaCha20 because hardware-accelerated AES is common, +# - disable NULL authentication, MD5 MACs and DSS for security reasons. +DEFAULT_CIPHERS = ':'.join([ + 'ECDH+AESGCM', + 'ECDH+CHACHA20', + 'DH+AESGCM', + 'DH+CHACHA20', + 'ECDH+AES256', + 'DH+AES256', + 'ECDH+AES128', + 'DH+AES', + 'RSA+AESGCM', + 'RSA+AES', + '!aNULL', + '!eNULL', + '!MD5', +]) + +try: + from ssl import SSLContext # Modern SSL? +except ImportError: + import sys + + class SSLContext(object): # Platform-specific: Python 2 & 3.1 + supports_set_ciphers = ((2, 7) <= sys.version_info < (3,) or + (3, 2) <= sys.version_info) + + def __init__(self, protocol_version): + self.protocol = protocol_version + # Use default values from a real SSLContext + self.check_hostname = False + self.verify_mode = ssl.CERT_NONE + self.ca_certs = None + self.options = 0 + self.certfile = None + self.keyfile = None + self.ciphers = None + + def load_cert_chain(self, certfile, keyfile): + self.certfile = certfile + self.keyfile = keyfile + + def load_verify_locations(self, cafile=None, capath=None): + self.ca_certs = cafile + + if capath is not None: + raise SSLError("CA directories not supported in older Pythons") + + def set_ciphers(self, cipher_suite): + if not self.supports_set_ciphers: + raise TypeError( + 'Your version of Python does not support setting ' + 'a custom cipher suite. Please upgrade to Python ' + '2.7, 3.2, or later if you need this functionality.' + ) + self.ciphers = cipher_suite + + def wrap_socket(self, socket, server_hostname=None, server_side=False): + warnings.warn( + 'A true SSLContext object is not available. This prevents ' + 'urllib3 from configuring SSL appropriately and may cause ' + 'certain SSL connections to fail. You can upgrade to a newer ' + 'version of Python to solve this. For more information, see ' + 'https://urllib3.readthedocs.io/en/latest/advanced-usage.html' + '#ssl-warnings', + InsecurePlatformWarning + ) + kwargs = { + 'keyfile': self.keyfile, + 'certfile': self.certfile, + 'ca_certs': self.ca_certs, + 'cert_reqs': self.verify_mode, + 'ssl_version': self.protocol, + 'server_side': server_side, + } + if self.supports_set_ciphers: # Platform-specific: Python 2.7+ + return wrap_socket(socket, ciphers=self.ciphers, **kwargs) + else: # Platform-specific: Python 2.6 + return wrap_socket(socket, **kwargs) + + +def assert_fingerprint(cert, fingerprint): + """ + Checks if given fingerprint matches the supplied certificate. + + :param cert: + Certificate as bytes object. + :param fingerprint: + Fingerprint as string of hexdigits, can be interspersed by colons. + """ + + fingerprint = fingerprint.replace(':', '').lower() + digest_length = len(fingerprint) + hashfunc = HASHFUNC_MAP.get(digest_length) + if not hashfunc: + raise SSLError( + 'Fingerprint of invalid length: {0}'.format(fingerprint)) + + # We need encode() here for py32; works on py2 and p33. + fingerprint_bytes = unhexlify(fingerprint.encode()) + + cert_digest = hashfunc(cert).digest() + + if not _const_compare_digest(cert_digest, fingerprint_bytes): + raise SSLError('Fingerprints did not match. Expected "{0}", got "{1}".' + .format(fingerprint, hexlify(cert_digest))) + + +def resolve_cert_reqs(candidate): + """ + Resolves the argument to a numeric constant, which can be passed to + the wrap_socket function/method from the ssl module. + Defaults to :data:`ssl.CERT_NONE`. + If given a string it is assumed to be the name of the constant in the + :mod:`ssl` module or its abbrevation. + (So you can specify `REQUIRED` instead of `CERT_REQUIRED`. + If it's neither `None` nor a string we assume it is already the numeric + constant which can directly be passed to wrap_socket. + """ + if candidate is None: + return CERT_NONE + + if isinstance(candidate, str): + res = getattr(ssl, candidate, None) + if res is None: + res = getattr(ssl, 'CERT_' + candidate) + return res + + return candidate + + +def resolve_ssl_version(candidate): + """ + like resolve_cert_reqs + """ + if candidate is None: + return PROTOCOL_SSLv23 + + if isinstance(candidate, str): + res = getattr(ssl, candidate, None) + if res is None: + res = getattr(ssl, 'PROTOCOL_' + candidate) + return res + + return candidate + + +def create_urllib3_context(ssl_version=None, cert_reqs=None, + options=None, ciphers=None): + """All arguments have the same meaning as ``ssl_wrap_socket``. + + By default, this function does a lot of the same work that + ``ssl.create_default_context`` does on Python 3.4+. It: + + - Disables SSLv2, SSLv3, and compression + - Sets a restricted set of server ciphers + + If you wish to enable SSLv3, you can do:: + + from urllib3.util import ssl_ + context = ssl_.create_urllib3_context() + context.options &= ~ssl_.OP_NO_SSLv3 + + You can do the same to enable compression (substituting ``COMPRESSION`` + for ``SSLv3`` in the last line above). + + :param ssl_version: + The desired protocol version to use. This will default to + PROTOCOL_SSLv23 which will negotiate the highest protocol that both + the server and your installation of OpenSSL support. + :param cert_reqs: + Whether to require the certificate verification. This defaults to + ``ssl.CERT_REQUIRED``. + :param options: + Specific OpenSSL options. These default to ``ssl.OP_NO_SSLv2``, + ``ssl.OP_NO_SSLv3``, ``ssl.OP_NO_COMPRESSION``. + :param ciphers: + Which cipher suites to allow the server to select. + :returns: + Constructed SSLContext object with specified options + :rtype: SSLContext + """ + context = SSLContext(ssl_version or ssl.PROTOCOL_SSLv23) + + # Setting the default here, as we may have no ssl module on import + cert_reqs = ssl.CERT_REQUIRED if cert_reqs is None else cert_reqs + + if options is None: + options = 0 + # SSLv2 is easily broken and is considered harmful and dangerous + options |= OP_NO_SSLv2 + # SSLv3 has several problems and is now dangerous + options |= OP_NO_SSLv3 + # Disable compression to prevent CRIME attacks for OpenSSL 1.0+ + # (issue #309) + options |= OP_NO_COMPRESSION + + context.options |= options + + if getattr(context, 'supports_set_ciphers', True): # Platform-specific: Python 2.6 + context.set_ciphers(ciphers or DEFAULT_CIPHERS) + + context.verify_mode = cert_reqs + if getattr(context, 'check_hostname', None) is not None: # Platform-specific: Python 3.2 + # We do our own verification, including fingerprints and alternative + # hostnames. So disable it here + context.check_hostname = False + return context + + +def ssl_wrap_socket(sock, keyfile=None, certfile=None, cert_reqs=None, + ca_certs=None, server_hostname=None, + ssl_version=None, ciphers=None, ssl_context=None, + ca_cert_dir=None): + """ + All arguments except for server_hostname, ssl_context, and ca_cert_dir have + the same meaning as they do when using :func:`ssl.wrap_socket`. + + :param server_hostname: + When SNI is supported, the expected hostname of the certificate + :param ssl_context: + A pre-made :class:`SSLContext` object. If none is provided, one will + be created using :func:`create_urllib3_context`. + :param ciphers: + A string of ciphers we wish the client to support. This is not + supported on Python 2.6 as the ssl module does not support it. + :param ca_cert_dir: + A directory containing CA certificates in multiple separate files, as + supported by OpenSSL's -CApath flag or the capath argument to + SSLContext.load_verify_locations(). + """ + context = ssl_context + if context is None: + # Note: This branch of code and all the variables in it are no longer + # used by urllib3 itself. We should consider deprecating and removing + # this code. + context = create_urllib3_context(ssl_version, cert_reqs, + ciphers=ciphers) + + if ca_certs or ca_cert_dir: + try: + context.load_verify_locations(ca_certs, ca_cert_dir) + except IOError as e: # Platform-specific: Python 2.6, 2.7, 3.2 + raise SSLError(e) + # Py33 raises FileNotFoundError which subclasses OSError + # These are not equivalent unless we check the errno attribute + except OSError as e: # Platform-specific: Python 3.3 and beyond + if e.errno == errno.ENOENT: + raise SSLError(e) + raise + elif getattr(context, 'load_default_certs', None) is not None: + # try to load OS default certs; works well on Windows (require Python3.4+) + context.load_default_certs() + + if certfile: + context.load_cert_chain(certfile, keyfile) + if HAS_SNI: # Platform-specific: OpenSSL with enabled SNI + return context.wrap_socket(sock, server_hostname=server_hostname) + + warnings.warn( + 'An HTTPS request has been made, but the SNI (Subject Name ' + 'Indication) extension to TLS is not available on this platform. ' + 'This may cause the server to present an incorrect TLS ' + 'certificate, which can cause validation failures. You can upgrade to ' + 'a newer version of Python to solve this. For more information, see ' + 'https://urllib3.readthedocs.io/en/latest/advanced-usage.html' + '#ssl-warnings', + SNIMissingWarning + ) + return context.wrap_socket(sock) diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/timeout.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/timeout.py new file mode 100644 index 0000000..cec817e --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/timeout.py @@ -0,0 +1,242 @@ +from __future__ import absolute_import +# The default socket timeout, used by httplib to indicate that no timeout was +# specified by the user +from socket import _GLOBAL_DEFAULT_TIMEOUT +import time + +from ..exceptions import TimeoutStateError + +# A sentinel value to indicate that no timeout was specified by the user in +# urllib3 +_Default = object() + + +# Use time.monotonic if available. +current_time = getattr(time, "monotonic", time.time) + + +class Timeout(object): + """ Timeout configuration. + + Timeouts can be defined as a default for a pool:: + + timeout = Timeout(connect=2.0, read=7.0) + http = PoolManager(timeout=timeout) + response = http.request('GET', 'http://example.com/') + + Or per-request (which overrides the default for the pool):: + + response = http.request('GET', 'http://example.com/', timeout=Timeout(10)) + + Timeouts can be disabled by setting all the parameters to ``None``:: + + no_timeout = Timeout(connect=None, read=None) + response = http.request('GET', 'http://example.com/, timeout=no_timeout) + + + :param total: + This combines the connect and read timeouts into one; the read timeout + will be set to the time leftover from the connect attempt. In the + event that both a connect timeout and a total are specified, or a read + timeout and a total are specified, the shorter timeout will be applied. + + Defaults to None. + + :type total: integer, float, or None + + :param connect: + The maximum amount of time to wait for a connection attempt to a server + to succeed. Omitting the parameter will default the connect timeout to + the system default, probably `the global default timeout in socket.py + <http://hg.python.org/cpython/file/603b4d593758/Lib/socket.py#l535>`_. + None will set an infinite timeout for connection attempts. + + :type connect: integer, float, or None + + :param read: + The maximum amount of time to wait between consecutive + read operations for a response from the server. Omitting + the parameter will default the read timeout to the system + default, probably `the global default timeout in socket.py + <http://hg.python.org/cpython/file/603b4d593758/Lib/socket.py#l535>`_. + None will set an infinite timeout. + + :type read: integer, float, or None + + .. note:: + + Many factors can affect the total amount of time for urllib3 to return + an HTTP response. + + For example, Python's DNS resolver does not obey the timeout specified + on the socket. Other factors that can affect total request time include + high CPU load, high swap, the program running at a low priority level, + or other behaviors. + + In addition, the read and total timeouts only measure the time between + read operations on the socket connecting the client and the server, + not the total amount of time for the request to return a complete + response. For most requests, the timeout is raised because the server + has not sent the first byte in the specified time. This is not always + the case; if a server streams one byte every fifteen seconds, a timeout + of 20 seconds will not trigger, even though the request will take + several minutes to complete. + + If your goal is to cut off any request after a set amount of wall clock + time, consider having a second "watcher" thread to cut off a slow + request. + """ + + #: A sentinel object representing the default timeout value + DEFAULT_TIMEOUT = _GLOBAL_DEFAULT_TIMEOUT + + def __init__(self, total=None, connect=_Default, read=_Default): + self._connect = self._validate_timeout(connect, 'connect') + self._read = self._validate_timeout(read, 'read') + self.total = self._validate_timeout(total, 'total') + self._start_connect = None + + def __str__(self): + return '%s(connect=%r, read=%r, total=%r)' % ( + type(self).__name__, self._connect, self._read, self.total) + + @classmethod + def _validate_timeout(cls, value, name): + """ Check that a timeout attribute is valid. + + :param value: The timeout value to validate + :param name: The name of the timeout attribute to validate. This is + used to specify in error messages. + :return: The validated and casted version of the given value. + :raises ValueError: If it is a numeric value less than or equal to + zero, or the type is not an integer, float, or None. + """ + if value is _Default: + return cls.DEFAULT_TIMEOUT + + if value is None or value is cls.DEFAULT_TIMEOUT: + return value + + if isinstance(value, bool): + raise ValueError("Timeout cannot be a boolean value. It must " + "be an int, float or None.") + try: + float(value) + except (TypeError, ValueError): + raise ValueError("Timeout value %s was %s, but it must be an " + "int, float or None." % (name, value)) + + try: + if value <= 0: + raise ValueError("Attempted to set %s timeout to %s, but the " + "timeout cannot be set to a value less " + "than or equal to 0." % (name, value)) + except TypeError: # Python 3 + raise ValueError("Timeout value %s was %s, but it must be an " + "int, float or None." % (name, value)) + + return value + + @classmethod + def from_float(cls, timeout): + """ Create a new Timeout from a legacy timeout value. + + The timeout value used by httplib.py sets the same timeout on the + connect(), and recv() socket requests. This creates a :class:`Timeout` + object that sets the individual timeouts to the ``timeout`` value + passed to this function. + + :param timeout: The legacy timeout value. + :type timeout: integer, float, sentinel default object, or None + :return: Timeout object + :rtype: :class:`Timeout` + """ + return Timeout(read=timeout, connect=timeout) + + def clone(self): + """ Create a copy of the timeout object + + Timeout properties are stored per-pool but each request needs a fresh + Timeout object to ensure each one has its own start/stop configured. + + :return: a copy of the timeout object + :rtype: :class:`Timeout` + """ + # We can't use copy.deepcopy because that will also create a new object + # for _GLOBAL_DEFAULT_TIMEOUT, which socket.py uses as a sentinel to + # detect the user default. + return Timeout(connect=self._connect, read=self._read, + total=self.total) + + def start_connect(self): + """ Start the timeout clock, used during a connect() attempt + + :raises urllib3.exceptions.TimeoutStateError: if you attempt + to start a timer that has been started already. + """ + if self._start_connect is not None: + raise TimeoutStateError("Timeout timer has already been started.") + self._start_connect = current_time() + return self._start_connect + + def get_connect_duration(self): + """ Gets the time elapsed since the call to :meth:`start_connect`. + + :return: Elapsed time. + :rtype: float + :raises urllib3.exceptions.TimeoutStateError: if you attempt + to get duration for a timer that hasn't been started. + """ + if self._start_connect is None: + raise TimeoutStateError("Can't get connect duration for timer " + "that has not started.") + return current_time() - self._start_connect + + @property + def connect_timeout(self): + """ Get the value to use when setting a connection timeout. + + This will be a positive float or integer, the value None + (never timeout), or the default system timeout. + + :return: Connect timeout. + :rtype: int, float, :attr:`Timeout.DEFAULT_TIMEOUT` or None + """ + if self.total is None: + return self._connect + + if self._connect is None or self._connect is self.DEFAULT_TIMEOUT: + return self.total + + return min(self._connect, self.total) + + @property + def read_timeout(self): + """ Get the value for the read timeout. + + This assumes some time has elapsed in the connection timeout and + computes the read timeout appropriately. + + If self.total is set, the read timeout is dependent on the amount of + time taken by the connect timeout. If the connection time has not been + established, a :exc:`~urllib3.exceptions.TimeoutStateError` will be + raised. + + :return: Value to use for the read timeout. + :rtype: int, float, :attr:`Timeout.DEFAULT_TIMEOUT` or None + :raises urllib3.exceptions.TimeoutStateError: If :meth:`start_connect` + has not yet been called on this object. + """ + if (self.total is not None and + self.total is not self.DEFAULT_TIMEOUT and + self._read is not None and + self._read is not self.DEFAULT_TIMEOUT): + # In case the connect timeout has not yet been established. + if self._start_connect is None: + return self._read + return max(0, min(self.total - self.get_connect_duration(), + self._read)) + elif self.total is not None and self.total is not self.DEFAULT_TIMEOUT: + return max(0, self.total - self.get_connect_duration()) + else: + return self._read diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/url.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/url.py new file mode 100644 index 0000000..61a326e --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/url.py @@ -0,0 +1,226 @@ +from __future__ import absolute_import +from collections import namedtuple + +from ..exceptions import LocationParseError + + +url_attrs = ['scheme', 'auth', 'host', 'port', 'path', 'query', 'fragment'] + + +class Url(namedtuple('Url', url_attrs)): + """ + Datastructure for representing an HTTP URL. Used as a return value for + :func:`parse_url`. Both the scheme and host are normalized as they are + both case-insensitive according to RFC 3986. + """ + __slots__ = () + + def __new__(cls, scheme=None, auth=None, host=None, port=None, path=None, + query=None, fragment=None): + if path and not path.startswith('/'): + path = '/' + path + if scheme: + scheme = scheme.lower() + if host: + host = host.lower() + return super(Url, cls).__new__(cls, scheme, auth, host, port, path, + query, fragment) + + @property + def hostname(self): + """For backwards-compatibility with urlparse. We're nice like that.""" + return self.host + + @property + def request_uri(self): + """Absolute path including the query string.""" + uri = self.path or '/' + + if self.query is not None: + uri += '?' + self.query + + return uri + + @property + def netloc(self): + """Network location including host and port""" + if self.port: + return '%s:%d' % (self.host, self.port) + return self.host + + @property + def url(self): + """ + Convert self into a url + + This function should more or less round-trip with :func:`.parse_url`. The + returned url may not be exactly the same as the url inputted to + :func:`.parse_url`, but it should be equivalent by the RFC (e.g., urls + with a blank port will have : removed). + + Example: :: + + >>> U = parse_url('http://google.com/mail/') + >>> U.url + 'http://google.com/mail/' + >>> Url('http', 'username:password', 'host.com', 80, + ... '/path', 'query', 'fragment').url + 'http://username:password@host.com:80/path?query#fragment' + """ + scheme, auth, host, port, path, query, fragment = self + url = '' + + # We use "is not None" we want things to happen with empty strings (or 0 port) + if scheme is not None: + url += scheme + '://' + if auth is not None: + url += auth + '@' + if host is not None: + url += host + if port is not None: + url += ':' + str(port) + if path is not None: + url += path + if query is not None: + url += '?' + query + if fragment is not None: + url += '#' + fragment + + return url + + def __str__(self): + return self.url + + +def split_first(s, delims): + """ + Given a string and an iterable of delimiters, split on the first found + delimiter. Return two split parts and the matched delimiter. + + If not found, then the first part is the full input string. + + Example:: + + >>> split_first('foo/bar?baz', '?/=') + ('foo', 'bar?baz', '/') + >>> split_first('foo/bar?baz', '123') + ('foo/bar?baz', '', None) + + Scales linearly with number of delims. Not ideal for large number of delims. + """ + min_idx = None + min_delim = None + for d in delims: + idx = s.find(d) + if idx < 0: + continue + + if min_idx is None or idx < min_idx: + min_idx = idx + min_delim = d + + if min_idx is None or min_idx < 0: + return s, '', None + + return s[:min_idx], s[min_idx + 1:], min_delim + + +def parse_url(url): + """ + Given a url, return a parsed :class:`.Url` namedtuple. Best-effort is + performed to parse incomplete urls. Fields not provided will be None. + + Partly backwards-compatible with :mod:`urlparse`. + + Example:: + + >>> parse_url('http://google.com/mail/') + Url(scheme='http', host='google.com', port=None, path='/mail/', ...) + >>> parse_url('google.com:80') + Url(scheme=None, host='google.com', port=80, path=None, ...) + >>> parse_url('/foo?bar') + Url(scheme=None, host=None, port=None, path='/foo', query='bar', ...) + """ + + # While this code has overlap with stdlib's urlparse, it is much + # simplified for our needs and less annoying. + # Additionally, this implementations does silly things to be optimal + # on CPython. + + if not url: + # Empty + return Url() + + scheme = None + auth = None + host = None + port = None + path = None + fragment = None + query = None + + # Scheme + if '://' in url: + scheme, url = url.split('://', 1) + + # Find the earliest Authority Terminator + # (http://tools.ietf.org/html/rfc3986#section-3.2) + url, path_, delim = split_first(url, ['/', '?', '#']) + + if delim: + # Reassemble the path + path = delim + path_ + + # Auth + if '@' in url: + # Last '@' denotes end of auth part + auth, url = url.rsplit('@', 1) + + # IPv6 + if url and url[0] == '[': + host, url = url.split(']', 1) + host += ']' + + # Port + if ':' in url: + _host, port = url.split(':', 1) + + if not host: + host = _host + + if port: + # If given, ports must be integers. No whitespace, no plus or + # minus prefixes, no non-integer digits such as ^2 (superscript). + if not port.isdigit(): + raise LocationParseError(url) + try: + port = int(port) + except ValueError: + raise LocationParseError(url) + else: + # Blank ports are cool, too. (rfc3986#section-3.2.3) + port = None + + elif not host and url: + host = url + + if not path: + return Url(scheme, auth, host, port, path, query, fragment) + + # Fragment + if '#' in path: + path, fragment = path.split('#', 1) + + # Query + if '?' in path: + path, query = path.split('?', 1) + + return Url(scheme, auth, host, port, path, query, fragment) + + +def get_host(url): + """ + Deprecated. Use :func:`parse_url` instead. + """ + p = parse_url(url) + return p.scheme or 'http', p.hostname, p.port diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/wait.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/wait.py new file mode 100644 index 0000000..cb396e5 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/wait.py @@ -0,0 +1,40 @@ +from .selectors import ( + HAS_SELECT, + DefaultSelector, + EVENT_READ, + EVENT_WRITE +) + + +def _wait_for_io_events(socks, events, timeout=None): + """ Waits for IO events to be available from a list of sockets + or optionally a single socket if passed in. Returns a list of + sockets that can be interacted with immediately. """ + if not HAS_SELECT: + raise ValueError('Platform does not have a selector') + if not isinstance(socks, list): + # Probably just a single socket. + if hasattr(socks, "fileno"): + socks = [socks] + # Otherwise it might be a non-list iterable. + else: + socks = list(socks) + with DefaultSelector() as selector: + for sock in socks: + selector.register(sock, events) + return [key[0].fileobj for key in + selector.select(timeout) if key[1] & events] + + +def wait_for_read(socks, timeout=None): + """ Waits for reading to be available from a list of sockets + or optionally a single socket if passed in. Returns a list of + sockets that can be read from immediately. """ + return _wait_for_io_events(socks, EVENT_READ, timeout) + + +def wait_for_write(socks, timeout=None): + """ Waits for writing to be available from a list of sockets + or optionally a single socket if passed in. Returns a list of + sockets that can be written to immediately. """ + return _wait_for_io_events(socks, EVENT_WRITE, timeout) diff --git a/venv/lib/python3.8/site-packages/telegram/version.py b/venv/lib/python3.8/site-packages/telegram/version.py new file mode 100644 index 0000000..47bf17d --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/version.py @@ -0,0 +1,24 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +# pylint: disable=C0114 + +from telegram import constants + +__version__ = '13.6' +bot_api_version = constants.BOT_API_VERSION # pylint: disable=C0103 diff --git a/venv/lib/python3.8/site-packages/telegram/voicechat.py b/venv/lib/python3.8/site-packages/telegram/voicechat.py new file mode 100644 index 0000000..4fb7b53 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/voicechat.py @@ -0,0 +1,169 @@ +#!/usr/bin/env python +# pylint: disable=R0903 +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains objects related to Telegram voice chats.""" + +import datetime as dtm +from typing import TYPE_CHECKING, Any, Optional, List + +from telegram import TelegramObject, User +from telegram.utils.helpers import from_timestamp, to_timestamp +from telegram.utils.types import JSONDict + +if TYPE_CHECKING: + from telegram import Bot + + +class VoiceChatStarted(TelegramObject): + """ + This object represents a service message about a voice + chat started in the chat. Currently holds no information. + + .. versionadded:: 13.4 + """ + + __slots__ = () + + def __init__(self, **_kwargs: Any): # skipcq: PTC-W0049 + pass + + +class VoiceChatEnded(TelegramObject): + """ + This object represents a service message about a + voice chat ended in the chat. + + Objects of this class are comparable in terms of equality. + Two objects of this class are considered equal, if their + :attr:`duration` are equal. + + .. versionadded:: 13.4 + + Args: + duration (:obj:`int`): Voice chat duration in seconds. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + duration (:obj:`int`): Voice chat duration in seconds. + + """ + + __slots__ = ('duration', '_id_attrs') + + def __init__(self, duration: int, **_kwargs: Any) -> None: + self.duration = int(duration) if duration is not None else None + self._id_attrs = (self.duration,) + + +class VoiceChatParticipantsInvited(TelegramObject): + """ + This object represents a service message about + new members invited to a voice chat. + + Objects of this class are comparable in terms of equality. + Two objects of this class are considered equal, if their + :attr:`users` are equal. + + .. versionadded:: 13.4 + + Args: + users (List[:class:`telegram.User`]): New members that + were invited to the voice chat. + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + users (List[:class:`telegram.User`]): New members that + were invited to the voice chat. + + """ + + __slots__ = ('users', '_id_attrs') + + def __init__(self, users: List[User], **_kwargs: Any) -> None: + self.users = users + self._id_attrs = (self.users,) + + def __hash__(self) -> int: + return hash(tuple(self.users)) + + @classmethod + def de_json( + cls, data: Optional[JSONDict], bot: 'Bot' + ) -> Optional['VoiceChatParticipantsInvited']: + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + if not data: + return None + + data['users'] = User.de_list(data.get('users', []), bot) + return cls(**data) + + def to_dict(self) -> JSONDict: + """See :meth:`telegram.TelegramObject.to_dict`.""" + data = super().to_dict() + + data["users"] = [u.to_dict() for u in self.users] + return data + + +class VoiceChatScheduled(TelegramObject): + """This object represents a service message about a voice chat scheduled in the chat. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`start_date` are equal. + + Args: + start_date (:obj:`datetime.datetime`): Point in time (Unix timestamp) when the voice + chat is supposed to be started by a chat administrator + **kwargs (:obj:`dict`): Arbitrary keyword arguments. + + Attributes: + start_date (:obj:`datetime.datetime`): Point in time (Unix timestamp) when the voice + chat is supposed to be started by a chat administrator + + """ + + __slots__ = ('start_date', '_id_attrs') + + def __init__(self, start_date: dtm.datetime, **_kwargs: Any) -> None: + self.start_date = start_date + + self._id_attrs = (self.start_date,) + + @classmethod + def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['VoiceChatScheduled']: + """See :meth:`telegram.TelegramObject.de_json`.""" + data = cls._parse_data(data) + + if not data: + return None + + data['start_date'] = from_timestamp(data['start_date']) + + return cls(**data, bot=bot) + + def to_dict(self) -> JSONDict: + """See :meth:`telegram.TelegramObject.to_dict`.""" + data = super().to_dict() + + # Required + data['start_date'] = to_timestamp(self.start_date) + + return data diff --git a/venv/lib/python3.8/site-packages/telegram/webhookinfo.py b/venv/lib/python3.8/site-packages/telegram/webhookinfo.py new file mode 100644 index 0000000..0fc6741 --- /dev/null +++ b/venv/lib/python3.8/site-packages/telegram/webhookinfo.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python +# +# A library that provides a Python interface to the Telegram Bot API +# Copyright (C) 2015-2021 +# Leandro Toledo de Souza <devs@python-telegram-bot.org> +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser Public License for more details. +# +# You should have received a copy of the GNU Lesser Public License +# along with this program. If not, see [http://www.gnu.org/licenses/]. +"""This module contains an object that represents a Telegram WebhookInfo.""" + +from typing import Any, List + +from telegram import TelegramObject + + +class WebhookInfo(TelegramObject): + """This object represents a Telegram WebhookInfo. + + Contains information about the current status of a webhook. + + Objects of this class are comparable in terms of equality. Two objects of this class are + considered equal, if their :attr:`url`, :attr:`has_custom_certificate`, + :attr:`pending_update_count`, :attr:`ip_address`, :attr:`last_error_date`, + :attr:`last_error_message`, :attr:`max_connections` and :attr:`allowed_updates` are equal. + + Args: + url (:obj:`str`): Webhook URL, may be empty if webhook is not set up. + has_custom_certificate (:obj:`bool`): :obj:`True`, if a custom certificate was provided for + webhook certificate checks. + pending_update_count (:obj:`int`): Number of updates awaiting delivery. + ip_address (:obj:`str`, optional): Currently used webhook IP address. + last_error_date (:obj:`int`, optional): Unix time for the most recent error that happened + when trying to deliver an update via webhook. + last_error_message (:obj:`str`, optional): Error message in human-readable format for the + most recent error that happened when trying to deliver an update via webhook. + max_connections (:obj:`int`, optional): Maximum allowed number of simultaneous HTTPS + connections to the webhook for update delivery. + allowed_updates (List[:obj:`str`], optional): A list of update types the bot is subscribed + to. Defaults to all update types, except :attr:`telegram.Update.chat_member`. + + Attributes: + url (:obj:`str`): Webhook URL. + has_custom_certificate (:obj:`bool`): If a custom certificate was provided for webhook. + pending_update_count (:obj:`int`): Number of updates awaiting delivery. + ip_address (:obj:`str`): Optional. Currently used webhook IP address. + last_error_date (:obj:`int`): Optional. Unix time for the most recent error that happened. + last_error_message (:obj:`str`): Optional. Error message in human-readable format. + max_connections (:obj:`int`): Optional. Maximum allowed number of simultaneous HTTPS + connections. + allowed_updates (List[:obj:`str`]): Optional. A list of update types the bot is subscribed + to. Defaults to all update types, except :attr:`telegram.Update.chat_member`. + + """ + + __slots__ = ( + 'allowed_updates', + 'url', + 'max_connections', + 'last_error_date', + 'ip_address', + 'last_error_message', + 'pending_update_count', + 'has_custom_certificate', + '_id_attrs', + ) + + def __init__( + self, + url: str, + has_custom_certificate: bool, + pending_update_count: int, + last_error_date: int = None, + last_error_message: str = None, + max_connections: int = None, + allowed_updates: List[str] = None, + ip_address: str = None, + **_kwargs: Any, + ): + # Required + self.url = url + self.has_custom_certificate = has_custom_certificate + self.pending_update_count = pending_update_count + + # Optional + self.ip_address = ip_address + self.last_error_date = last_error_date + self.last_error_message = last_error_message + self.max_connections = max_connections + self.allowed_updates = allowed_updates + + self._id_attrs = ( + self.url, + self.has_custom_certificate, + self.pending_update_count, + self.ip_address, + self.last_error_date, + self.last_error_message, + self.max_connections, + self.allowed_updates, + ) diff --git a/venv/lib/python3.8/site-packages/tornado-6.1.dist-info/INSTALLER b/venv/lib/python3.8/site-packages/tornado-6.1.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado-6.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.8/site-packages/tornado-6.1.dist-info/LICENSE b/venv/lib/python3.8/site-packages/tornado-6.1.dist-info/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado-6.1.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/venv/lib/python3.8/site-packages/tornado-6.1.dist-info/METADATA b/venv/lib/python3.8/site-packages/tornado-6.1.dist-info/METADATA new file mode 100644 index 0000000..98ff7b2 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado-6.1.dist-info/METADATA @@ -0,0 +1,70 @@ +Metadata-Version: 2.1 +Name: tornado +Version: 6.1 +Summary: Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed. +Home-page: http://www.tornadoweb.org/ +Author: Facebook +Author-email: python-tornado@googlegroups.com +License: http://www.apache.org/licenses/LICENSE-2.0 +Platform: UNKNOWN +Classifier: License :: OSI Approved :: Apache Software License +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: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Requires-Python: >= 3.5 + +Tornado Web Server +================== + +.. image:: https://badges.gitter.im/Join%20Chat.svg + :alt: Join the chat at https://gitter.im/tornadoweb/tornado + :target: https://gitter.im/tornadoweb/tornado?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge + +`Tornado <http://www.tornadoweb.org>`_ is a Python web framework and +asynchronous networking library, originally developed at `FriendFeed +<http://friendfeed.com>`_. By using non-blocking network I/O, Tornado +can scale to tens of thousands of open connections, making it ideal for +`long polling <http://en.wikipedia.org/wiki/Push_technology#Long_Polling>`_, +`WebSockets <http://en.wikipedia.org/wiki/WebSocket>`_, and other +applications that require a long-lived connection to each user. + +Hello, world +------------ + +Here is a simple "Hello, world" example web app for Tornado: + +.. code-block:: python + + import tornado.ioloop + import tornado.web + + class MainHandler(tornado.web.RequestHandler): + def get(self): + self.write("Hello, world") + + def make_app(): + return tornado.web.Application([ + (r"/", MainHandler), + ]) + + if __name__ == "__main__": + app = make_app() + app.listen(8888) + tornado.ioloop.IOLoop.current().start() + +This example does not use any of Tornado's asynchronous features; for +that see this `simple chat room +<https://github.com/tornadoweb/tornado/tree/stable/demos/chat>`_. + +Documentation +------------- + +Documentation and links to additional resources are available at +https://www.tornadoweb.org + + diff --git a/venv/lib/python3.8/site-packages/tornado-6.1.dist-info/RECORD b/venv/lib/python3.8/site-packages/tornado-6.1.dist-info/RECORD new file mode 100644 index 0000000..1f330ba --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado-6.1.dist-info/RECORD @@ -0,0 +1,165 @@ +tornado-6.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +tornado-6.1.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358 +tornado-6.1.dist-info/METADATA,sha256=Wb23YO89rBkEgjfDwACNao8i7DcDIEBkVdV-cxmxER4,2435 +tornado-6.1.dist-info/RECORD,, +tornado-6.1.dist-info/WHEEL,sha256=3Rn77v1cOIQWUJHbJxwJJ4HycjuBQ6DIO-hbFDX-kLU,111 +tornado-6.1.dist-info/top_level.txt,sha256=5QAK1MeNpWgYdqWoU8iYlDuGB8j6NDPgx-uSUHTe0A4,8 +tornado/__init__.py,sha256=ME8HXlhSOfaX_8S2iYiSI1Nx9PMWK6HwsHfQDg20XpU,1018 +tornado/__pycache__/__init__.cpython-38.pyc,, +tornado/__pycache__/_locale_data.cpython-38.pyc,, +tornado/__pycache__/auth.cpython-38.pyc,, +tornado/__pycache__/autoreload.cpython-38.pyc,, +tornado/__pycache__/concurrent.cpython-38.pyc,, +tornado/__pycache__/curl_httpclient.cpython-38.pyc,, +tornado/__pycache__/escape.cpython-38.pyc,, +tornado/__pycache__/gen.cpython-38.pyc,, +tornado/__pycache__/http1connection.cpython-38.pyc,, +tornado/__pycache__/httpclient.cpython-38.pyc,, +tornado/__pycache__/httpserver.cpython-38.pyc,, +tornado/__pycache__/httputil.cpython-38.pyc,, +tornado/__pycache__/ioloop.cpython-38.pyc,, +tornado/__pycache__/iostream.cpython-38.pyc,, +tornado/__pycache__/locale.cpython-38.pyc,, +tornado/__pycache__/locks.cpython-38.pyc,, +tornado/__pycache__/log.cpython-38.pyc,, +tornado/__pycache__/netutil.cpython-38.pyc,, +tornado/__pycache__/options.cpython-38.pyc,, +tornado/__pycache__/process.cpython-38.pyc,, +tornado/__pycache__/queues.cpython-38.pyc,, +tornado/__pycache__/routing.cpython-38.pyc,, +tornado/__pycache__/simple_httpclient.cpython-38.pyc,, +tornado/__pycache__/tcpclient.cpython-38.pyc,, +tornado/__pycache__/tcpserver.cpython-38.pyc,, +tornado/__pycache__/template.cpython-38.pyc,, +tornado/__pycache__/testing.cpython-38.pyc,, +tornado/__pycache__/util.cpython-38.pyc,, +tornado/__pycache__/web.cpython-38.pyc,, +tornado/__pycache__/websocket.cpython-38.pyc,, +tornado/__pycache__/wsgi.cpython-38.pyc,, +tornado/_locale_data.py,sha256=BZGn0sBZeHS2kYAvFovxiimi_KqE0suPPom__qb71xU,4627 +tornado/auth.py,sha256=vbESu6SFcFgFjg7VkDcWpgWgopwPQXLtX8DDt4fmTz4,46051 +tornado/autoreload.py,sha256=sa2V25zdcZu23lweS2Scqmesnocjk6OtbF7feVu4Jgs,13652 +tornado/concurrent.py,sha256=hrlfgWnZp7Mr7ajhgxSEMA6nHHRqyYoMiUrjpK1cVIg,8108 +tornado/curl_httpclient.py,sha256=Ab09r4AykyQ_67mQa0S4lpo9WiZOiMJlS-lkDQAkXt4,24575 +tornado/escape.py,sha256=7cX6o-FkZSjzhfTNDHVU6JbsopFBT6fj3fLuwqnWAtM,13267 +tornado/gen.py,sha256=dJXReNybfnhyfTjinyFeoYTb9jYgNu9QS-3aAXgZJd0,30957 +tornado/http1connection.py,sha256=FMmXb2i4Cnv7LHBLjK13lKXARYVqFDLqHBQesmmGeos,36098 +tornado/httpclient.py,sha256=fDKLM0VLSOz4weyBOhG8w-WPfu_yjbT5mw0Q0YxR5Rs,31919 +tornado/httpserver.py,sha256=iVlUMDBkpNTQuv9X4I3felK3UNUucbbXBCfQBRtmeRo,15555 +tornado/httputil.py,sha256=USDYnppIPGpegRG9zs-qe4mI5rI8H_ZJg3G8xza6Vxs,35933 +tornado/ioloop.py,sha256=WJaCrx9ko_Z1Bzu3DDGhOfqs6Ns1uye0fAWCtMix_bs,35342 +tornado/iostream.py,sha256=H6qMORR3IbipBYPF76z61iwIqBDMSPQddtmt1SFnsWA,65451 +tornado/locale.py,sha256=YNu0cGa3LRj1AMH4Vmt5aZRG3lnoF4QvNDN95VnU4FQ,20972 +tornado/locks.py,sha256=fd6yuFK2O-hRyIms3NivsNUukhHRdPruUxiMw_LHDrQ,17414 +tornado/log.py,sha256=tC6hmAoQlncodapgPYGb_1lBlNSVnfAb5KCkIu4u0NM,12414 +tornado/netutil.py,sha256=YgFsZdMK8SfE55TU6qL_W0oivMYKnA0AfZka1sMEIUU,22912 +tornado/options.py,sha256=zvjDcUzXtzNvi3yKzyik7ZIiar_gqW4Uh2WJZrZ6pyU,25601 +tornado/platform/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +tornado/platform/__pycache__/__init__.cpython-38.pyc,, +tornado/platform/__pycache__/asyncio.cpython-38.pyc,, +tornado/platform/__pycache__/caresresolver.cpython-38.pyc,, +tornado/platform/__pycache__/twisted.cpython-38.pyc,, +tornado/platform/asyncio.py,sha256=syfpMNVTgBmdWazk7WTdGXF6Hc5BQie7aPu4GGW4mP0,23216 +tornado/platform/caresresolver.py,sha256=RXQuJsh6gyyWyKDwZRHZlNo_tM8J5IR7x46DtGnxwSI,3318 +tornado/platform/twisted.py,sha256=8bLmfn3TOQAS9wM0cGinxEITSnq2sT1pJClPkf3YR0I,5477 +tornado/process.py,sha256=wD09DPERk8-Ri2gqlMcSmkV5eKRl_c8-t8MLoTt6QK0,12789 +tornado/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +tornado/queues.py,sha256=8cL7JF7oFdlh2N1y0z6P0uwYOHOBTYOaCKWOGLY5cbY,12289 +tornado/routing.py,sha256=fEUpBPHKRd4PCp4LH1XKHspkqEG2jkIE_9hvJr3MEiA,25082 +tornado/simple_httpclient.py,sha256=Y4WSJLGV8HMaCWbKg_E1HZS2XGsse-Ln9LuAXLdl0Ys,27578 +tornado/speedups.cpython-38-x86_64-linux-gnu.so,sha256=otG3p4_6gbGdHih9HZ8EWX_OIZ7IVuNi9GiOipU34jI,29256 +tornado/tcpclient.py,sha256=SUIG3JY4a3WpSPC3eAIdSWrxUSowtHGSIjDqf3fhUko,12076 +tornado/tcpserver.py,sha256=rqyRL-d4pWRyqEa4i25dfR_0e4ts5JoTb6rN9M71TE4,13242 +tornado/template.py,sha256=32e-gIEbeaq1ucchTo1d6_gCY4J0HLqnX_lRhrFkYtA,37798 +tornado/test/__main__.py,sha256=lOtaUbVN3C_tg0kzkGGXFmhMuZjJtKnpTE8XbiDNgNQ,335 +tornado/test/__pycache__/__main__.cpython-38.pyc,, +tornado/test/__pycache__/asyncio_test.cpython-38.pyc,, +tornado/test/__pycache__/auth_test.cpython-38.pyc,, +tornado/test/__pycache__/autoreload_test.cpython-38.pyc,, +tornado/test/__pycache__/concurrent_test.cpython-38.pyc,, +tornado/test/__pycache__/curl_httpclient_test.cpython-38.pyc,, +tornado/test/__pycache__/escape_test.cpython-38.pyc,, +tornado/test/__pycache__/gen_test.cpython-38.pyc,, +tornado/test/__pycache__/http1connection_test.cpython-38.pyc,, +tornado/test/__pycache__/httpclient_test.cpython-38.pyc,, +tornado/test/__pycache__/httpserver_test.cpython-38.pyc,, +tornado/test/__pycache__/httputil_test.cpython-38.pyc,, +tornado/test/__pycache__/import_test.cpython-38.pyc,, +tornado/test/__pycache__/ioloop_test.cpython-38.pyc,, +tornado/test/__pycache__/iostream_test.cpython-38.pyc,, +tornado/test/__pycache__/locale_test.cpython-38.pyc,, +tornado/test/__pycache__/locks_test.cpython-38.pyc,, +tornado/test/__pycache__/log_test.cpython-38.pyc,, +tornado/test/__pycache__/netutil_test.cpython-38.pyc,, +tornado/test/__pycache__/options_test.cpython-38.pyc,, +tornado/test/__pycache__/process_test.cpython-38.pyc,, +tornado/test/__pycache__/queues_test.cpython-38.pyc,, +tornado/test/__pycache__/resolve_test_helper.cpython-38.pyc,, +tornado/test/__pycache__/routing_test.cpython-38.pyc,, +tornado/test/__pycache__/runtests.cpython-38.pyc,, +tornado/test/__pycache__/simple_httpclient_test.cpython-38.pyc,, +tornado/test/__pycache__/tcpclient_test.cpython-38.pyc,, +tornado/test/__pycache__/tcpserver_test.cpython-38.pyc,, +tornado/test/__pycache__/template_test.cpython-38.pyc,, +tornado/test/__pycache__/testing_test.cpython-38.pyc,, +tornado/test/__pycache__/twisted_test.cpython-38.pyc,, +tornado/test/__pycache__/util.cpython-38.pyc,, +tornado/test/__pycache__/util_test.cpython-38.pyc,, +tornado/test/__pycache__/web_test.cpython-38.pyc,, +tornado/test/__pycache__/websocket_test.cpython-38.pyc,, +tornado/test/__pycache__/wsgi_test.cpython-38.pyc,, +tornado/test/asyncio_test.py,sha256=ewtMKAwHWLWXLiX09aMPs8RZRyEG5sTNNu0sfbLsqy4,7155 +tornado/test/auth_test.py,sha256=tSgcX3PDivsrVSsPj5Cdh7WCtXOQPstHo_1P4vZ2gxk,23437 +tornado/test/autoreload_test.py,sha256=x0O26S2ZVjmRWCrF-loHyDUPkVMlHBkgviIUW6wmN6c,3948 +tornado/test/concurrent_test.py,sha256=vsggGoKCfnurb0OBQ-s69qLIg8Yws38ue5LrqoYcFaA,6051 +tornado/test/csv_translations/fr_FR.csv,sha256=0UsMzfh1cw3yQdhS7pCmRfQoAkbqWpgzzodpZqp7ttM,18 +tornado/test/curl_httpclient_test.py,sha256=hVXuIq32IdBz8_UOOuurUQGbfMgLpJb11ghF_wk7l4Q,4303 +tornado/test/escape_test.py,sha256=j81UHAlYotJHIOO1GOWoe83x1xJ8resUDt-4OkhQYLw,12372 +tornado/test/gen_test.py,sha256=AWHy4-d2khnOc3gEgl_beOWlfhAPGrxS8CtRGQ3Qz8s,33838 +tornado/test/gettext_translations/fr_FR/LC_MESSAGES/tornado_test.mo,sha256=fl0ZVZIlNwwU9lPx29pgZ4X-HfyEVYphJu7UWtll7jo,665 +tornado/test/gettext_translations/fr_FR/LC_MESSAGES/tornado_test.po,sha256=Clw6HyQUcopGV25qw3pvw3gn1ZqZRYrovsi8PQTQAnM,1049 +tornado/test/http1connection_test.py,sha256=lLav_POwDPx6NN_pMvfWWSFwKpbJ-so17UnuISWOXvQ,1950 +tornado/test/httpclient_test.py,sha256=puttXWYmGNA2SoYoPH-FAqzfZdcmXqxtNHpedENvI9c,34231 +tornado/test/httpserver_test.py,sha256=QWtPbREhgnaNVWwSeY8y7u9rH-FeiS6vKpmEnwMREds,46492 +tornado/test/httputil_test.py,sha256=6w4tQ1cSKmjxNUbTXoy-E0Ii7nhR2-y2bAUvQGnc7ZA,19053 +tornado/test/import_test.py,sha256=5oit2hRJ5QI2Wm92AZLdUn6ZwZrbzehYIuKvQl9ibAs,1980 +tornado/test/ioloop_test.py,sha256=c6JME_atMWzYjGnVF8VCRzJNuCDyvJSW_Vn8ocHXRyw,25653 +tornado/test/iostream_test.py,sha256=jP17mO8ESHRtC2-Co6vuVkYXglISyTJPvZ6wmoqgrUg,46328 +tornado/test/locale_test.py,sha256=bK7oN8SAn5eoThwR-4_Pp7IlZbxrsnzsYTbbm5g68fU,5756 +tornado/test/locks_test.py,sha256=nGyZUEW7r2FMnfLqihSzv6F_WlxZoSWyKDKa-cnqF-g,17010 +tornado/test/log_test.py,sha256=ebpF2dhhv4HNiXRTn37nLgsOZEypiuol4Pz-j5wKKqM,9504 +tornado/test/netutil_test.py,sha256=7Qz1EfJv5qaSzo9mUB-ROXOv1kXcNJfYoPsVYXL8l-s,7907 +tornado/test/options_test.cfg,sha256=SpUupk-MfXBMhLENqXmD-K5a2Mp888REqfICQupcgqc,69 +tornado/test/options_test.py,sha256=NLsVXpd1tym9GIBJoM90r3szF0MR8UGDFlSXx1v-OQ0,11821 +tornado/test/options_test_types.cfg,sha256=GeR43v-UuSfW7kkUfh6NavPrmOkdYkJr2v7-yTaqaDk,266 +tornado/test/options_test_types_str.cfg,sha256=2R1Gn7q4rt8kKvqvp2h1qC8IXZ8XrlyNVj3i7Jte-Us,150 +tornado/test/process_test.py,sha256=JXs0fVkyco-cAC7GTlCcLEkqykssfgoMk1paTSIEjso,11455 +tornado/test/queues_test.py,sha256=EGTV1_BMK3gTjlrFEyqQE1FE2WM9CPA6D7Nj20J2i7c,13981 +tornado/test/resolve_test_helper.py,sha256=bOZMi_3fgv71k-PNxKGFl2Nn4J8odfJjxtK7AdE33-8,411 +tornado/test/routing_test.py,sha256=YWZGtYp2UVj2Vf-e1KYdhXz35MgD0zwNXLy7ISYO0Q0,8827 +tornado/test/runtests.py,sha256=PdQ6jO23wDdkTmznODn7RUuQ2IEq2eJh1vmfAkuf1v4,8348 +tornado/test/simple_httpclient_test.py,sha256=PnWuu60nGJdnvkNW8mp0s1Ye_Lc8sLoZIvt90QG1708,30943 +tornado/test/static/dir/index.html,sha256=tBwBanUSjISUy0BVan_QNKkYdLau8qs__P0G9oAiP78,18 +tornado/test/static/robots.txt,sha256=Mx6pCQ2wyfb1l72YQP1bFxgw9uCzuhyyTfqR8Mla7cE,26 +tornado/test/static/sample.xml,sha256=7LeTf16BWDucipsUaZZK7oDxtKEMDH9sFtsNR1G6pME,666 +tornado/test/static/sample.xml.bz2,sha256=2Ql5ccWnaSpDdTyioino7Bw_dcGFkG_RQO5Lm5cfT6A,285 +tornado/test/static/sample.xml.gz,sha256=_App0wKpn31lZVA9P_rslytPm4ei5GvNPVKh55r7l28,264 +tornado/test/static_foo.txt,sha256=DdAKABzHb8kunGrAvUoTLnHlgdTN-6_PjH1irVmokm8,95 +tornado/test/tcpclient_test.py,sha256=n0-7_UxSS2x23nA6LmgDp-SHyX2AQhThtbvZhLYB9SU,16814 +tornado/test/tcpserver_test.py,sha256=uj4CB8VSzfNt3_t9jpblshMtTJVxPBGeYZb95rY21ns,6482 +tornado/test/template_test.py,sha256=YqgHoSxi69DMdLWNoULti5ZnH4ocI238HnEbeT0xzew,18668 +tornado/test/templates/utf8.html,sha256=9d1eiaw5KCjUTCbRRIl_RLSy0LCJXaO-bzVF2L_32fM,7 +tornado/test/test.crt,sha256=mRu1xBsBK6Z2cAh1IdwIF3tBsfOGz1kyAfWtXIEdHCI,1224 +tornado/test/test.key,sha256=Lgz56gA7gSXUbTTfiHAGFyZSXePBDPrJZlPRPu8ApeY,1704 +tornado/test/testing_test.py,sha256=_Z_fK7z8TU07TFZHFcSeD3Vk0tn-8RM72Q8_oxJgGx0,10711 +tornado/test/twisted_test.py,sha256=MD5aJ5A_Cf5UUr1fM9LLlBkf0SzPQ8z-CDjdUAE0-NM,8510 +tornado/test/util.py,sha256=LoAdDDLZai4L45le4bMSkBq2drQegm3CKdLYOkOPwYQ,3654 +tornado/test/util_test.py,sha256=-Nw4I5uIi756SFht3R9r8YjcZdTr5EC6qUX-dCuoYxc,9781 +tornado/test/web_test.py,sha256=CaRWjuRqSn4DZxY5FJA_uNoAXlB_1TJvSTbgEuiP6UU,115864 +tornado/test/websocket_test.py,sha256=LxmxrkAkALTV7_LuauJcCvoKm64szRyphWRCg14erLU,27976 +tornado/test/wsgi_test.py,sha256=fioTIRCajhhTcrCeR6jARQI7k33ajvk_a9gnI3N-Kds,657 +tornado/testing.py,sha256=Q1HL_TzcTgx8zdMTiIQSzT1uZhKDdSNqCc4dkqt4S1s,30623 +tornado/util.py,sha256=QO2_cK1kJEpf_1GfSIu-YXxYifkp-m_ArATW3pshdeY,16702 +tornado/web.py,sha256=bloqhSKzXTLflu_x2uCDzEJ7LzOJb7JZAoWCSQgQyD0,138140 +tornado/websocket.py,sha256=Dm8HScBGJSdPuo0YYnJV5UuRvRVneFgO1l1Bn1xL-t8,61476 +tornado/wsgi.py,sha256=yGtcp-400vnLKK5YyUz0a2G4cH32-NFkIWW_OSnSBYk,7807 diff --git a/venv/lib/python3.8/site-packages/tornado-6.1.dist-info/WHEEL b/venv/lib/python3.8/site-packages/tornado-6.1.dist-info/WHEEL new file mode 100644 index 0000000..3f8f773 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado-6.1.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.35.1) +Root-Is-Purelib: false +Tag: cp38-cp38-manylinux2010_x86_64 + diff --git a/venv/lib/python3.8/site-packages/tornado-6.1.dist-info/top_level.txt b/venv/lib/python3.8/site-packages/tornado-6.1.dist-info/top_level.txt new file mode 100644 index 0000000..c3368df --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado-6.1.dist-info/top_level.txt @@ -0,0 +1 @@ +tornado diff --git a/venv/lib/python3.8/site-packages/tornado/__init__.py b/venv/lib/python3.8/site-packages/tornado/__init__.py new file mode 100644 index 0000000..a5f45e5 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/__init__.py @@ -0,0 +1,26 @@ +# +# Copyright 2009 Facebook +# +# 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. + +"""The Tornado web server and tools.""" + +# version is a human-readable version number. + +# version_info is a four-tuple for programmatic comparison. The first +# three numbers are the components of the version number. The fourth +# is zero for an official release, positive for a development branch, +# or negative for a release candidate or beta (after the base version +# number has been incremented) +version = "6.1" +version_info = (6, 1, 0, 0) diff --git a/venv/lib/python3.8/site-packages/tornado/_locale_data.py b/venv/lib/python3.8/site-packages/tornado/_locale_data.py new file mode 100644 index 0000000..c706230 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/_locale_data.py @@ -0,0 +1,80 @@ +# Copyright 2012 Facebook +# +# 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. + +"""Data used by the tornado.locale module.""" + +LOCALE_NAMES = { + "af_ZA": {"name_en": u"Afrikaans", "name": u"Afrikaans"}, + "am_ET": {"name_en": u"Amharic", "name": u"አማርኛ"}, + "ar_AR": {"name_en": u"Arabic", "name": u"العربية"}, + "bg_BG": {"name_en": u"Bulgarian", "name": u"Български"}, + "bn_IN": {"name_en": u"Bengali", "name": u"বাংলা"}, + "bs_BA": {"name_en": u"Bosnian", "name": u"Bosanski"}, + "ca_ES": {"name_en": u"Catalan", "name": u"Català"}, + "cs_CZ": {"name_en": u"Czech", "name": u"Čeština"}, + "cy_GB": {"name_en": u"Welsh", "name": u"Cymraeg"}, + "da_DK": {"name_en": u"Danish", "name": u"Dansk"}, + "de_DE": {"name_en": u"German", "name": u"Deutsch"}, + "el_GR": {"name_en": u"Greek", "name": u"Ελληνικά"}, + "en_GB": {"name_en": u"English (UK)", "name": u"English (UK)"}, + "en_US": {"name_en": u"English (US)", "name": u"English (US)"}, + "es_ES": {"name_en": u"Spanish (Spain)", "name": u"Español (España)"}, + "es_LA": {"name_en": u"Spanish", "name": u"Español"}, + "et_EE": {"name_en": u"Estonian", "name": u"Eesti"}, + "eu_ES": {"name_en": u"Basque", "name": u"Euskara"}, + "fa_IR": {"name_en": u"Persian", "name": u"فارسی"}, + "fi_FI": {"name_en": u"Finnish", "name": u"Suomi"}, + "fr_CA": {"name_en": u"French (Canada)", "name": u"Français (Canada)"}, + "fr_FR": {"name_en": u"French", "name": u"Français"}, + "ga_IE": {"name_en": u"Irish", "name": u"Gaeilge"}, + "gl_ES": {"name_en": u"Galician", "name": u"Galego"}, + "he_IL": {"name_en": u"Hebrew", "name": u"עברית"}, + "hi_IN": {"name_en": u"Hindi", "name": u"हिन्दी"}, + "hr_HR": {"name_en": u"Croatian", "name": u"Hrvatski"}, + "hu_HU": {"name_en": u"Hungarian", "name": u"Magyar"}, + "id_ID": {"name_en": u"Indonesian", "name": u"Bahasa Indonesia"}, + "is_IS": {"name_en": u"Icelandic", "name": u"Íslenska"}, + "it_IT": {"name_en": u"Italian", "name": u"Italiano"}, + "ja_JP": {"name_en": u"Japanese", "name": u"日本語"}, + "ko_KR": {"name_en": u"Korean", "name": u"한국어"}, + "lt_LT": {"name_en": u"Lithuanian", "name": u"Lietuvių"}, + "lv_LV": {"name_en": u"Latvian", "name": u"Latviešu"}, + "mk_MK": {"name_en": u"Macedonian", "name": u"Македонски"}, + "ml_IN": {"name_en": u"Malayalam", "name": u"മലയാളം"}, + "ms_MY": {"name_en": u"Malay", "name": u"Bahasa Melayu"}, + "nb_NO": {"name_en": u"Norwegian (bokmal)", "name": u"Norsk (bokmål)"}, + "nl_NL": {"name_en": u"Dutch", "name": u"Nederlands"}, + "nn_NO": {"name_en": u"Norwegian (nynorsk)", "name": u"Norsk (nynorsk)"}, + "pa_IN": {"name_en": u"Punjabi", "name": u"ਪੰਜਾਬੀ"}, + "pl_PL": {"name_en": u"Polish", "name": u"Polski"}, + "pt_BR": {"name_en": u"Portuguese (Brazil)", "name": u"Português (Brasil)"}, + "pt_PT": {"name_en": u"Portuguese (Portugal)", "name": u"Português (Portugal)"}, + "ro_RO": {"name_en": u"Romanian", "name": u"Română"}, + "ru_RU": {"name_en": u"Russian", "name": u"Русский"}, + "sk_SK": {"name_en": u"Slovak", "name": u"Slovenčina"}, + "sl_SI": {"name_en": u"Slovenian", "name": u"Slovenščina"}, + "sq_AL": {"name_en": u"Albanian", "name": u"Shqip"}, + "sr_RS": {"name_en": u"Serbian", "name": u"Српски"}, + "sv_SE": {"name_en": u"Swedish", "name": u"Svenska"}, + "sw_KE": {"name_en": u"Swahili", "name": u"Kiswahili"}, + "ta_IN": {"name_en": u"Tamil", "name": u"தமிழ்"}, + "te_IN": {"name_en": u"Telugu", "name": u"తెలుగు"}, + "th_TH": {"name_en": u"Thai", "name": u"ภาษาไทย"}, + "tl_PH": {"name_en": u"Filipino", "name": u"Filipino"}, + "tr_TR": {"name_en": u"Turkish", "name": u"Türkçe"}, + "uk_UA": {"name_en": u"Ukraini ", "name": u"Українська"}, + "vi_VN": {"name_en": u"Vietnamese", "name": u"Tiếng Việt"}, + "zh_CN": {"name_en": u"Chinese (Simplified)", "name": u"中文(简体)"}, + "zh_TW": {"name_en": u"Chinese (Traditional)", "name": u"中文(繁體)"}, +} diff --git a/venv/lib/python3.8/site-packages/tornado/auth.py b/venv/lib/python3.8/site-packages/tornado/auth.py new file mode 100644 index 0000000..5f1068c --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/auth.py @@ -0,0 +1,1187 @@ +# +# Copyright 2009 Facebook +# +# 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. + +"""This module contains implementations of various third-party +authentication schemes. + +All the classes in this file are class mixins designed to be used with +the `tornado.web.RequestHandler` class. They are used in two ways: + +* On a login handler, use methods such as ``authenticate_redirect()``, + ``authorize_redirect()``, and ``get_authenticated_user()`` to + establish the user's identity and store authentication tokens to your + database and/or cookies. +* In non-login handlers, use methods such as ``facebook_request()`` + or ``twitter_request()`` to use the authentication tokens to make + requests to the respective services. + +They all take slightly different arguments due to the fact all these +services implement authentication and authorization slightly differently. +See the individual service classes below for complete documentation. + +Example usage for Google OAuth: + +.. testcode:: + + class GoogleOAuth2LoginHandler(tornado.web.RequestHandler, + tornado.auth.GoogleOAuth2Mixin): + async def get(self): + if self.get_argument('code', False): + user = await self.get_authenticated_user( + redirect_uri='http://your.site.com/auth/google', + code=self.get_argument('code')) + # Save the user with e.g. set_secure_cookie + else: + self.authorize_redirect( + redirect_uri='http://your.site.com/auth/google', + client_id=self.settings['google_oauth']['key'], + scope=['profile', 'email'], + response_type='code', + extra_params={'approval_prompt': 'auto'}) + +.. testoutput:: + :hide: + +""" + +import base64 +import binascii +import hashlib +import hmac +import time +import urllib.parse +import uuid + +from tornado import httpclient +from tornado import escape +from tornado.httputil import url_concat +from tornado.util import unicode_type +from tornado.web import RequestHandler + +from typing import List, Any, Dict, cast, Iterable, Union, Optional + + +class AuthError(Exception): + pass + + +class OpenIdMixin(object): + """Abstract implementation of OpenID and Attribute Exchange. + + Class attributes: + + * ``_OPENID_ENDPOINT``: the identity provider's URI. + """ + + def authenticate_redirect( + self, + callback_uri: Optional[str] = None, + ax_attrs: List[str] = ["name", "email", "language", "username"], + ) -> None: + """Redirects to the authentication URL for this service. + + After authentication, the service will redirect back to the given + callback URI with additional parameters including ``openid.mode``. + + We request the given attributes for the authenticated user by + default (name, email, language, and username). If you don't need + all those attributes for your app, you can request fewer with + the ax_attrs keyword argument. + + .. versionchanged:: 6.0 + + The ``callback`` argument was removed and this method no + longer returns an awaitable object. It is now an ordinary + synchronous function. + """ + handler = cast(RequestHandler, self) + callback_uri = callback_uri or handler.request.uri + assert callback_uri is not None + args = self._openid_args(callback_uri, ax_attrs=ax_attrs) + endpoint = self._OPENID_ENDPOINT # type: ignore + handler.redirect(endpoint + "?" + urllib.parse.urlencode(args)) + + async def get_authenticated_user( + self, http_client: Optional[httpclient.AsyncHTTPClient] = None + ) -> Dict[str, Any]: + """Fetches the authenticated user data upon redirect. + + This method should be called by the handler that receives the + redirect from the `authenticate_redirect()` method (which is + often the same as the one that calls it; in that case you would + call `get_authenticated_user` if the ``openid.mode`` parameter + is present and `authenticate_redirect` if it is not). + + The result of this method will generally be used to set a cookie. + + .. versionchanged:: 6.0 + + The ``callback`` argument was removed. Use the returned + awaitable object instead. + """ + handler = cast(RequestHandler, self) + # Verify the OpenID response via direct request to the OP + args = dict( + (k, v[-1]) for k, v in handler.request.arguments.items() + ) # type: Dict[str, Union[str, bytes]] + args["openid.mode"] = u"check_authentication" + url = self._OPENID_ENDPOINT # type: ignore + if http_client is None: + http_client = self.get_auth_http_client() + resp = await http_client.fetch( + url, method="POST", body=urllib.parse.urlencode(args) + ) + return self._on_authentication_verified(resp) + + def _openid_args( + self, + callback_uri: str, + ax_attrs: Iterable[str] = [], + oauth_scope: Optional[str] = None, + ) -> Dict[str, str]: + handler = cast(RequestHandler, self) + url = urllib.parse.urljoin(handler.request.full_url(), callback_uri) + args = { + "openid.ns": "http://specs.openid.net/auth/2.0", + "openid.claimed_id": "http://specs.openid.net/auth/2.0/identifier_select", + "openid.identity": "http://specs.openid.net/auth/2.0/identifier_select", + "openid.return_to": url, + "openid.realm": urllib.parse.urljoin(url, "/"), + "openid.mode": "checkid_setup", + } + if ax_attrs: + args.update( + { + "openid.ns.ax": "http://openid.net/srv/ax/1.0", + "openid.ax.mode": "fetch_request", + } + ) + ax_attrs = set(ax_attrs) + required = [] # type: List[str] + if "name" in ax_attrs: + ax_attrs -= set(["name", "firstname", "fullname", "lastname"]) + required += ["firstname", "fullname", "lastname"] + args.update( + { + "openid.ax.type.firstname": "http://axschema.org/namePerson/first", + "openid.ax.type.fullname": "http://axschema.org/namePerson", + "openid.ax.type.lastname": "http://axschema.org/namePerson/last", + } + ) + known_attrs = { + "email": "http://axschema.org/contact/email", + "language": "http://axschema.org/pref/language", + "username": "http://axschema.org/namePerson/friendly", + } + for name in ax_attrs: + args["openid.ax.type." + name] = known_attrs[name] + required.append(name) + args["openid.ax.required"] = ",".join(required) + if oauth_scope: + args.update( + { + "openid.ns.oauth": "http://specs.openid.net/extensions/oauth/1.0", + "openid.oauth.consumer": handler.request.host.split(":")[0], + "openid.oauth.scope": oauth_scope, + } + ) + return args + + def _on_authentication_verified( + self, response: httpclient.HTTPResponse + ) -> Dict[str, Any]: + handler = cast(RequestHandler, self) + if b"is_valid:true" not in response.body: + raise AuthError("Invalid OpenID response: %r" % response.body) + + # Make sure we got back at least an email from attribute exchange + ax_ns = None + for key in handler.request.arguments: + if ( + key.startswith("openid.ns.") + and handler.get_argument(key) == u"http://openid.net/srv/ax/1.0" + ): + ax_ns = key[10:] + break + + def get_ax_arg(uri: str) -> str: + if not ax_ns: + return u"" + prefix = "openid." + ax_ns + ".type." + ax_name = None + for name in handler.request.arguments.keys(): + if handler.get_argument(name) == uri and name.startswith(prefix): + part = name[len(prefix) :] + ax_name = "openid." + ax_ns + ".value." + part + break + if not ax_name: + return u"" + return handler.get_argument(ax_name, u"") + + email = get_ax_arg("http://axschema.org/contact/email") + name = get_ax_arg("http://axschema.org/namePerson") + first_name = get_ax_arg("http://axschema.org/namePerson/first") + last_name = get_ax_arg("http://axschema.org/namePerson/last") + username = get_ax_arg("http://axschema.org/namePerson/friendly") + locale = get_ax_arg("http://axschema.org/pref/language").lower() + user = dict() + name_parts = [] + if first_name: + user["first_name"] = first_name + name_parts.append(first_name) + if last_name: + user["last_name"] = last_name + name_parts.append(last_name) + if name: + user["name"] = name + elif name_parts: + user["name"] = u" ".join(name_parts) + elif email: + user["name"] = email.split("@")[0] + if email: + user["email"] = email + if locale: + user["locale"] = locale + if username: + user["username"] = username + claimed_id = handler.get_argument("openid.claimed_id", None) + if claimed_id: + user["claimed_id"] = claimed_id + return user + + def get_auth_http_client(self) -> httpclient.AsyncHTTPClient: + """Returns the `.AsyncHTTPClient` instance to be used for auth requests. + + May be overridden by subclasses to use an HTTP client other than + the default. + """ + return httpclient.AsyncHTTPClient() + + +class OAuthMixin(object): + """Abstract implementation of OAuth 1.0 and 1.0a. + + See `TwitterMixin` below for an example implementation. + + Class attributes: + + * ``_OAUTH_AUTHORIZE_URL``: The service's OAuth authorization url. + * ``_OAUTH_ACCESS_TOKEN_URL``: The service's OAuth access token url. + * ``_OAUTH_VERSION``: May be either "1.0" or "1.0a". + * ``_OAUTH_NO_CALLBACKS``: Set this to True if the service requires + advance registration of callbacks. + + Subclasses must also override the `_oauth_get_user_future` and + `_oauth_consumer_token` methods. + """ + + async def authorize_redirect( + self, + callback_uri: Optional[str] = None, + extra_params: Optional[Dict[str, Any]] = None, + http_client: Optional[httpclient.AsyncHTTPClient] = None, + ) -> None: + """Redirects the user to obtain OAuth authorization for this service. + + The ``callback_uri`` may be omitted if you have previously + registered a callback URI with the third-party service. For + some services, you must use a previously-registered callback + URI and cannot specify a callback via this method. + + This method sets a cookie called ``_oauth_request_token`` which is + subsequently used (and cleared) in `get_authenticated_user` for + security purposes. + + This method is asynchronous and must be called with ``await`` + or ``yield`` (This is different from other ``auth*_redirect`` + methods defined in this module). It calls + `.RequestHandler.finish` for you so you should not write any + other response after it returns. + + .. versionchanged:: 3.1 + Now returns a `.Future` and takes an optional callback, for + compatibility with `.gen.coroutine`. + + .. versionchanged:: 6.0 + + The ``callback`` argument was removed. Use the returned + awaitable object instead. + + """ + if callback_uri and getattr(self, "_OAUTH_NO_CALLBACKS", False): + raise Exception("This service does not support oauth_callback") + if http_client is None: + http_client = self.get_auth_http_client() + assert http_client is not None + if getattr(self, "_OAUTH_VERSION", "1.0a") == "1.0a": + response = await http_client.fetch( + self._oauth_request_token_url( + callback_uri=callback_uri, extra_params=extra_params + ) + ) + else: + response = await http_client.fetch(self._oauth_request_token_url()) + url = self._OAUTH_AUTHORIZE_URL # type: ignore + self._on_request_token(url, callback_uri, response) + + async def get_authenticated_user( + self, http_client: Optional[httpclient.AsyncHTTPClient] = None + ) -> Dict[str, Any]: + """Gets the OAuth authorized user and access token. + + This method should be called from the handler for your + OAuth callback URL to complete the registration process. We run the + callback with the authenticated user dictionary. This dictionary + will contain an ``access_key`` which can be used to make authorized + requests to this service on behalf of the user. The dictionary will + also contain other fields such as ``name``, depending on the service + used. + + .. versionchanged:: 6.0 + + The ``callback`` argument was removed. Use the returned + awaitable object instead. + """ + handler = cast(RequestHandler, self) + request_key = escape.utf8(handler.get_argument("oauth_token")) + oauth_verifier = handler.get_argument("oauth_verifier", None) + request_cookie = handler.get_cookie("_oauth_request_token") + if not request_cookie: + raise AuthError("Missing OAuth request token cookie") + handler.clear_cookie("_oauth_request_token") + cookie_key, cookie_secret = [ + base64.b64decode(escape.utf8(i)) for i in request_cookie.split("|") + ] + if cookie_key != request_key: + raise AuthError("Request token does not match cookie") + token = dict( + key=cookie_key, secret=cookie_secret + ) # type: Dict[str, Union[str, bytes]] + if oauth_verifier: + token["verifier"] = oauth_verifier + if http_client is None: + http_client = self.get_auth_http_client() + assert http_client is not None + response = await http_client.fetch(self._oauth_access_token_url(token)) + access_token = _oauth_parse_response(response.body) + user = await self._oauth_get_user_future(access_token) + if not user: + raise AuthError("Error getting user") + user["access_token"] = access_token + return user + + def _oauth_request_token_url( + self, + callback_uri: Optional[str] = None, + extra_params: Optional[Dict[str, Any]] = None, + ) -> str: + handler = cast(RequestHandler, self) + consumer_token = self._oauth_consumer_token() + url = self._OAUTH_REQUEST_TOKEN_URL # type: ignore + args = dict( + oauth_consumer_key=escape.to_basestring(consumer_token["key"]), + oauth_signature_method="HMAC-SHA1", + oauth_timestamp=str(int(time.time())), + oauth_nonce=escape.to_basestring(binascii.b2a_hex(uuid.uuid4().bytes)), + oauth_version="1.0", + ) + if getattr(self, "_OAUTH_VERSION", "1.0a") == "1.0a": + if callback_uri == "oob": + args["oauth_callback"] = "oob" + elif callback_uri: + args["oauth_callback"] = urllib.parse.urljoin( + handler.request.full_url(), callback_uri + ) + if extra_params: + args.update(extra_params) + signature = _oauth10a_signature(consumer_token, "GET", url, args) + else: + signature = _oauth_signature(consumer_token, "GET", url, args) + + args["oauth_signature"] = signature + return url + "?" + urllib.parse.urlencode(args) + + def _on_request_token( + self, + authorize_url: str, + callback_uri: Optional[str], + response: httpclient.HTTPResponse, + ) -> None: + handler = cast(RequestHandler, self) + request_token = _oauth_parse_response(response.body) + data = ( + base64.b64encode(escape.utf8(request_token["key"])) + + b"|" + + base64.b64encode(escape.utf8(request_token["secret"])) + ) + handler.set_cookie("_oauth_request_token", data) + args = dict(oauth_token=request_token["key"]) + if callback_uri == "oob": + handler.finish(authorize_url + "?" + urllib.parse.urlencode(args)) + return + elif callback_uri: + args["oauth_callback"] = urllib.parse.urljoin( + handler.request.full_url(), callback_uri + ) + handler.redirect(authorize_url + "?" + urllib.parse.urlencode(args)) + + def _oauth_access_token_url(self, request_token: Dict[str, Any]) -> str: + consumer_token = self._oauth_consumer_token() + url = self._OAUTH_ACCESS_TOKEN_URL # type: ignore + args = dict( + oauth_consumer_key=escape.to_basestring(consumer_token["key"]), + oauth_token=escape.to_basestring(request_token["key"]), + oauth_signature_method="HMAC-SHA1", + oauth_timestamp=str(int(time.time())), + oauth_nonce=escape.to_basestring(binascii.b2a_hex(uuid.uuid4().bytes)), + oauth_version="1.0", + ) + if "verifier" in request_token: + args["oauth_verifier"] = request_token["verifier"] + + if getattr(self, "_OAUTH_VERSION", "1.0a") == "1.0a": + signature = _oauth10a_signature( + consumer_token, "GET", url, args, request_token + ) + else: + signature = _oauth_signature( + consumer_token, "GET", url, args, request_token + ) + + args["oauth_signature"] = signature + return url + "?" + urllib.parse.urlencode(args) + + def _oauth_consumer_token(self) -> Dict[str, Any]: + """Subclasses must override this to return their OAuth consumer keys. + + The return value should be a `dict` with keys ``key`` and ``secret``. + """ + raise NotImplementedError() + + async def _oauth_get_user_future( + self, access_token: Dict[str, Any] + ) -> Dict[str, Any]: + """Subclasses must override this to get basic information about the + user. + + Should be a coroutine whose result is a dictionary + containing information about the user, which may have been + retrieved by using ``access_token`` to make a request to the + service. + + The access token will be added to the returned dictionary to make + the result of `get_authenticated_user`. + + .. versionchanged:: 5.1 + + Subclasses may also define this method with ``async def``. + + .. versionchanged:: 6.0 + + A synchronous fallback to ``_oauth_get_user`` was removed. + """ + raise NotImplementedError() + + def _oauth_request_parameters( + self, + url: str, + access_token: Dict[str, Any], + parameters: Dict[str, Any] = {}, + method: str = "GET", + ) -> Dict[str, Any]: + """Returns the OAuth parameters as a dict for the given request. + + parameters should include all POST arguments and query string arguments + that will be sent with the request. + """ + consumer_token = self._oauth_consumer_token() + base_args = dict( + oauth_consumer_key=escape.to_basestring(consumer_token["key"]), + oauth_token=escape.to_basestring(access_token["key"]), + oauth_signature_method="HMAC-SHA1", + oauth_timestamp=str(int(time.time())), + oauth_nonce=escape.to_basestring(binascii.b2a_hex(uuid.uuid4().bytes)), + oauth_version="1.0", + ) + args = {} + args.update(base_args) + args.update(parameters) + if getattr(self, "_OAUTH_VERSION", "1.0a") == "1.0a": + signature = _oauth10a_signature( + consumer_token, method, url, args, access_token + ) + else: + signature = _oauth_signature( + consumer_token, method, url, args, access_token + ) + base_args["oauth_signature"] = escape.to_basestring(signature) + return base_args + + def get_auth_http_client(self) -> httpclient.AsyncHTTPClient: + """Returns the `.AsyncHTTPClient` instance to be used for auth requests. + + May be overridden by subclasses to use an HTTP client other than + the default. + """ + return httpclient.AsyncHTTPClient() + + +class OAuth2Mixin(object): + """Abstract implementation of OAuth 2.0. + + See `FacebookGraphMixin` or `GoogleOAuth2Mixin` below for example + implementations. + + Class attributes: + + * ``_OAUTH_AUTHORIZE_URL``: The service's authorization url. + * ``_OAUTH_ACCESS_TOKEN_URL``: The service's access token url. + """ + + def authorize_redirect( + self, + redirect_uri: Optional[str] = None, + client_id: Optional[str] = None, + client_secret: Optional[str] = None, + extra_params: Optional[Dict[str, Any]] = None, + scope: Optional[List[str]] = None, + response_type: str = "code", + ) -> None: + """Redirects the user to obtain OAuth authorization for this service. + + Some providers require that you register a redirect URL with + your application instead of passing one via this method. You + should call this method to log the user in, and then call + ``get_authenticated_user`` in the handler for your + redirect URL to complete the authorization process. + + .. versionchanged:: 6.0 + + The ``callback`` argument and returned awaitable were removed; + this is now an ordinary synchronous function. + """ + handler = cast(RequestHandler, self) + args = {"response_type": response_type} + if redirect_uri is not None: + args["redirect_uri"] = redirect_uri + if client_id is not None: + args["client_id"] = client_id + if extra_params: + args.update(extra_params) + if scope: + args["scope"] = " ".join(scope) + url = self._OAUTH_AUTHORIZE_URL # type: ignore + handler.redirect(url_concat(url, args)) + + def _oauth_request_token_url( + self, + redirect_uri: Optional[str] = None, + client_id: Optional[str] = None, + client_secret: Optional[str] = None, + code: Optional[str] = None, + extra_params: Optional[Dict[str, Any]] = None, + ) -> str: + url = self._OAUTH_ACCESS_TOKEN_URL # type: ignore + args = {} # type: Dict[str, str] + if redirect_uri is not None: + args["redirect_uri"] = redirect_uri + if code is not None: + args["code"] = code + if client_id is not None: + args["client_id"] = client_id + if client_secret is not None: + args["client_secret"] = client_secret + if extra_params: + args.update(extra_params) + return url_concat(url, args) + + async def oauth2_request( + self, + url: str, + access_token: Optional[str] = None, + post_args: Optional[Dict[str, Any]] = None, + **args: Any + ) -> Any: + """Fetches the given URL auth an OAuth2 access token. + + If the request is a POST, ``post_args`` should be provided. Query + string arguments should be given as keyword arguments. + + Example usage: + + ..testcode:: + + class MainHandler(tornado.web.RequestHandler, + tornado.auth.FacebookGraphMixin): + @tornado.web.authenticated + async def get(self): + new_entry = await self.oauth2_request( + "https://graph.facebook.com/me/feed", + post_args={"message": "I am posting from my Tornado application!"}, + access_token=self.current_user["access_token"]) + + if not new_entry: + # Call failed; perhaps missing permission? + self.authorize_redirect() + return + self.finish("Posted a message!") + + .. testoutput:: + :hide: + + .. versionadded:: 4.3 + + .. versionchanged::: 6.0 + + The ``callback`` argument was removed. Use the returned awaitable object instead. + """ + all_args = {} + if access_token: + all_args["access_token"] = access_token + all_args.update(args) + + if all_args: + url += "?" + urllib.parse.urlencode(all_args) + http = self.get_auth_http_client() + if post_args is not None: + response = await http.fetch( + url, method="POST", body=urllib.parse.urlencode(post_args) + ) + else: + response = await http.fetch(url) + return escape.json_decode(response.body) + + def get_auth_http_client(self) -> httpclient.AsyncHTTPClient: + """Returns the `.AsyncHTTPClient` instance to be used for auth requests. + + May be overridden by subclasses to use an HTTP client other than + the default. + + .. versionadded:: 4.3 + """ + return httpclient.AsyncHTTPClient() + + +class TwitterMixin(OAuthMixin): + """Twitter OAuth authentication. + + To authenticate with Twitter, register your application with + Twitter at http://twitter.com/apps. Then copy your Consumer Key + and Consumer Secret to the application + `~tornado.web.Application.settings` ``twitter_consumer_key`` and + ``twitter_consumer_secret``. Use this mixin on the handler for the + URL you registered as your application's callback URL. + + When your application is set up, you can use this mixin like this + to authenticate the user with Twitter and get access to their stream: + + .. testcode:: + + class TwitterLoginHandler(tornado.web.RequestHandler, + tornado.auth.TwitterMixin): + async def get(self): + if self.get_argument("oauth_token", None): + user = await self.get_authenticated_user() + # Save the user using e.g. set_secure_cookie() + else: + await self.authorize_redirect() + + .. testoutput:: + :hide: + + The user object returned by `~OAuthMixin.get_authenticated_user` + includes the attributes ``username``, ``name``, ``access_token``, + and all of the custom Twitter user attributes described at + https://dev.twitter.com/docs/api/1.1/get/users/show + """ + + _OAUTH_REQUEST_TOKEN_URL = "https://api.twitter.com/oauth/request_token" + _OAUTH_ACCESS_TOKEN_URL = "https://api.twitter.com/oauth/access_token" + _OAUTH_AUTHORIZE_URL = "https://api.twitter.com/oauth/authorize" + _OAUTH_AUTHENTICATE_URL = "https://api.twitter.com/oauth/authenticate" + _OAUTH_NO_CALLBACKS = False + _TWITTER_BASE_URL = "https://api.twitter.com/1.1" + + async def authenticate_redirect(self, callback_uri: Optional[str] = None) -> None: + """Just like `~OAuthMixin.authorize_redirect`, but + auto-redirects if authorized. + + This is generally the right interface to use if you are using + Twitter for single-sign on. + + .. versionchanged:: 3.1 + Now returns a `.Future` and takes an optional callback, for + compatibility with `.gen.coroutine`. + + .. versionchanged:: 6.0 + + The ``callback`` argument was removed. Use the returned + awaitable object instead. + """ + http = self.get_auth_http_client() + response = await http.fetch( + self._oauth_request_token_url(callback_uri=callback_uri) + ) + self._on_request_token(self._OAUTH_AUTHENTICATE_URL, None, response) + + async def twitter_request( + self, + path: str, + access_token: Dict[str, Any], + post_args: Optional[Dict[str, Any]] = None, + **args: Any + ) -> Any: + """Fetches the given API path, e.g., ``statuses/user_timeline/btaylor`` + + The path should not include the format or API version number. + (we automatically use JSON format and API version 1). + + If the request is a POST, ``post_args`` should be provided. Query + string arguments should be given as keyword arguments. + + All the Twitter methods are documented at http://dev.twitter.com/ + + Many methods require an OAuth access token which you can + obtain through `~OAuthMixin.authorize_redirect` and + `~OAuthMixin.get_authenticated_user`. The user returned through that + process includes an 'access_token' attribute that can be used + to make authenticated requests via this method. Example + usage: + + .. testcode:: + + class MainHandler(tornado.web.RequestHandler, + tornado.auth.TwitterMixin): + @tornado.web.authenticated + async def get(self): + new_entry = await self.twitter_request( + "/statuses/update", + post_args={"status": "Testing Tornado Web Server"}, + access_token=self.current_user["access_token"]) + if not new_entry: + # Call failed; perhaps missing permission? + await self.authorize_redirect() + return + self.finish("Posted a message!") + + .. testoutput:: + :hide: + + .. versionchanged:: 6.0 + + The ``callback`` argument was removed. Use the returned + awaitable object instead. + """ + if path.startswith("http:") or path.startswith("https:"): + # Raw urls are useful for e.g. search which doesn't follow the + # usual pattern: http://search.twitter.com/search.json + url = path + else: + url = self._TWITTER_BASE_URL + path + ".json" + # Add the OAuth resource request signature if we have credentials + if access_token: + all_args = {} + all_args.update(args) + all_args.update(post_args or {}) + method = "POST" if post_args is not None else "GET" + oauth = self._oauth_request_parameters( + url, access_token, all_args, method=method + ) + args.update(oauth) + if args: + url += "?" + urllib.parse.urlencode(args) + http = self.get_auth_http_client() + if post_args is not None: + response = await http.fetch( + url, method="POST", body=urllib.parse.urlencode(post_args) + ) + else: + response = await http.fetch(url) + return escape.json_decode(response.body) + + def _oauth_consumer_token(self) -> Dict[str, Any]: + handler = cast(RequestHandler, self) + handler.require_setting("twitter_consumer_key", "Twitter OAuth") + handler.require_setting("twitter_consumer_secret", "Twitter OAuth") + return dict( + key=handler.settings["twitter_consumer_key"], + secret=handler.settings["twitter_consumer_secret"], + ) + + async def _oauth_get_user_future( + self, access_token: Dict[str, Any] + ) -> Dict[str, Any]: + user = await self.twitter_request( + "/account/verify_credentials", access_token=access_token + ) + if user: + user["username"] = user["screen_name"] + return user + + +class GoogleOAuth2Mixin(OAuth2Mixin): + """Google authentication using OAuth2. + + In order to use, register your application with Google and copy the + relevant parameters to your application settings. + + * Go to the Google Dev Console at http://console.developers.google.com + * Select a project, or create a new one. + * In the sidebar on the left, select APIs & Auth. + * In the list of APIs, find the Google+ API service and set it to ON. + * In the sidebar on the left, select Credentials. + * In the OAuth section of the page, select Create New Client ID. + * Set the Redirect URI to point to your auth handler + * Copy the "Client secret" and "Client ID" to the application settings as + ``{"google_oauth": {"key": CLIENT_ID, "secret": CLIENT_SECRET}}`` + + .. versionadded:: 3.2 + """ + + _OAUTH_AUTHORIZE_URL = "https://accounts.google.com/o/oauth2/v2/auth" + _OAUTH_ACCESS_TOKEN_URL = "https://www.googleapis.com/oauth2/v4/token" + _OAUTH_USERINFO_URL = "https://www.googleapis.com/oauth2/v1/userinfo" + _OAUTH_NO_CALLBACKS = False + _OAUTH_SETTINGS_KEY = "google_oauth" + + async def get_authenticated_user( + self, redirect_uri: str, code: str + ) -> Dict[str, Any]: + """Handles the login for the Google user, returning an access token. + + The result is a dictionary containing an ``access_token`` field + ([among others](https://developers.google.com/identity/protocols/OAuth2WebServer#handlingtheresponse)). + Unlike other ``get_authenticated_user`` methods in this package, + this method does not return any additional information about the user. + The returned access token can be used with `OAuth2Mixin.oauth2_request` + to request additional information (perhaps from + ``https://www.googleapis.com/oauth2/v2/userinfo``) + + Example usage: + + .. testcode:: + + class GoogleOAuth2LoginHandler(tornado.web.RequestHandler, + tornado.auth.GoogleOAuth2Mixin): + async def get(self): + if self.get_argument('code', False): + access = await self.get_authenticated_user( + redirect_uri='http://your.site.com/auth/google', + code=self.get_argument('code')) + user = await self.oauth2_request( + "https://www.googleapis.com/oauth2/v1/userinfo", + access_token=access["access_token"]) + # Save the user and access token with + # e.g. set_secure_cookie. + else: + self.authorize_redirect( + redirect_uri='http://your.site.com/auth/google', + client_id=self.settings['google_oauth']['key'], + scope=['profile', 'email'], + response_type='code', + extra_params={'approval_prompt': 'auto'}) + + .. testoutput:: + :hide: + + .. versionchanged:: 6.0 + + The ``callback`` argument was removed. Use the returned awaitable object instead. + """ # noqa: E501 + handler = cast(RequestHandler, self) + http = self.get_auth_http_client() + body = urllib.parse.urlencode( + { + "redirect_uri": redirect_uri, + "code": code, + "client_id": handler.settings[self._OAUTH_SETTINGS_KEY]["key"], + "client_secret": handler.settings[self._OAUTH_SETTINGS_KEY]["secret"], + "grant_type": "authorization_code", + } + ) + + response = await http.fetch( + self._OAUTH_ACCESS_TOKEN_URL, + method="POST", + headers={"Content-Type": "application/x-www-form-urlencoded"}, + body=body, + ) + return escape.json_decode(response.body) + + +class FacebookGraphMixin(OAuth2Mixin): + """Facebook authentication using the new Graph API and OAuth2.""" + + _OAUTH_ACCESS_TOKEN_URL = "https://graph.facebook.com/oauth/access_token?" + _OAUTH_AUTHORIZE_URL = "https://www.facebook.com/dialog/oauth?" + _OAUTH_NO_CALLBACKS = False + _FACEBOOK_BASE_URL = "https://graph.facebook.com" + + async def get_authenticated_user( + self, + redirect_uri: str, + client_id: str, + client_secret: str, + code: str, + extra_fields: Optional[Dict[str, Any]] = None, + ) -> Optional[Dict[str, Any]]: + """Handles the login for the Facebook user, returning a user object. + + Example usage: + + .. testcode:: + + class FacebookGraphLoginHandler(tornado.web.RequestHandler, + tornado.auth.FacebookGraphMixin): + async def get(self): + if self.get_argument("code", False): + user = await self.get_authenticated_user( + redirect_uri='/auth/facebookgraph/', + client_id=self.settings["facebook_api_key"], + client_secret=self.settings["facebook_secret"], + code=self.get_argument("code")) + # Save the user with e.g. set_secure_cookie + else: + self.authorize_redirect( + redirect_uri='/auth/facebookgraph/', + client_id=self.settings["facebook_api_key"], + extra_params={"scope": "read_stream,offline_access"}) + + .. testoutput:: + :hide: + + This method returns a dictionary which may contain the following fields: + + * ``access_token``, a string which may be passed to `facebook_request` + * ``session_expires``, an integer encoded as a string representing + the time until the access token expires in seconds. This field should + be used like ``int(user['session_expires'])``; in a future version of + Tornado it will change from a string to an integer. + * ``id``, ``name``, ``first_name``, ``last_name``, ``locale``, ``picture``, + ``link``, plus any fields named in the ``extra_fields`` argument. These + fields are copied from the Facebook graph API + `user object <https://developers.facebook.com/docs/graph-api/reference/user>`_ + + .. versionchanged:: 4.5 + The ``session_expires`` field was updated to support changes made to the + Facebook API in March 2017. + + .. versionchanged:: 6.0 + + The ``callback`` argument was removed. Use the returned awaitable object instead. + """ + http = self.get_auth_http_client() + args = { + "redirect_uri": redirect_uri, + "code": code, + "client_id": client_id, + "client_secret": client_secret, + } + + fields = set( + ["id", "name", "first_name", "last_name", "locale", "picture", "link"] + ) + if extra_fields: + fields.update(extra_fields) + + response = await http.fetch( + self._oauth_request_token_url(**args) # type: ignore + ) + args = escape.json_decode(response.body) + session = { + "access_token": args.get("access_token"), + "expires_in": args.get("expires_in"), + } + assert session["access_token"] is not None + + user = await self.facebook_request( + path="/me", + access_token=session["access_token"], + appsecret_proof=hmac.new( + key=client_secret.encode("utf8"), + msg=session["access_token"].encode("utf8"), + digestmod=hashlib.sha256, + ).hexdigest(), + fields=",".join(fields), + ) + + if user is None: + return None + + fieldmap = {} + for field in fields: + fieldmap[field] = user.get(field) + + # session_expires is converted to str for compatibility with + # older versions in which the server used url-encoding and + # this code simply returned the string verbatim. + # This should change in Tornado 5.0. + fieldmap.update( + { + "access_token": session["access_token"], + "session_expires": str(session.get("expires_in")), + } + ) + return fieldmap + + async def facebook_request( + self, + path: str, + access_token: Optional[str] = None, + post_args: Optional[Dict[str, Any]] = None, + **args: Any + ) -> Any: + """Fetches the given relative API path, e.g., "/btaylor/picture" + + If the request is a POST, ``post_args`` should be provided. Query + string arguments should be given as keyword arguments. + + An introduction to the Facebook Graph API can be found at + http://developers.facebook.com/docs/api + + Many methods require an OAuth access token which you can + obtain through `~OAuth2Mixin.authorize_redirect` and + `get_authenticated_user`. The user returned through that + process includes an ``access_token`` attribute that can be + used to make authenticated requests via this method. + + Example usage: + + .. testcode:: + + class MainHandler(tornado.web.RequestHandler, + tornado.auth.FacebookGraphMixin): + @tornado.web.authenticated + async def get(self): + new_entry = await self.facebook_request( + "/me/feed", + post_args={"message": "I am posting from my Tornado application!"}, + access_token=self.current_user["access_token"]) + + if not new_entry: + # Call failed; perhaps missing permission? + self.authorize_redirect() + return + self.finish("Posted a message!") + + .. testoutput:: + :hide: + + The given path is relative to ``self._FACEBOOK_BASE_URL``, + by default "https://graph.facebook.com". + + This method is a wrapper around `OAuth2Mixin.oauth2_request`; + the only difference is that this method takes a relative path, + while ``oauth2_request`` takes a complete url. + + .. versionchanged:: 3.1 + Added the ability to override ``self._FACEBOOK_BASE_URL``. + + .. versionchanged:: 6.0 + + The ``callback`` argument was removed. Use the returned awaitable object instead. + """ + url = self._FACEBOOK_BASE_URL + path + return await self.oauth2_request( + url, access_token=access_token, post_args=post_args, **args + ) + + +def _oauth_signature( + consumer_token: Dict[str, Any], + method: str, + url: str, + parameters: Dict[str, Any] = {}, + token: Optional[Dict[str, Any]] = None, +) -> bytes: + """Calculates the HMAC-SHA1 OAuth signature for the given request. + + See http://oauth.net/core/1.0/#signing_process + """ + parts = urllib.parse.urlparse(url) + scheme, netloc, path = parts[:3] + normalized_url = scheme.lower() + "://" + netloc.lower() + path + + base_elems = [] + base_elems.append(method.upper()) + base_elems.append(normalized_url) + base_elems.append( + "&".join( + "%s=%s" % (k, _oauth_escape(str(v))) for k, v in sorted(parameters.items()) + ) + ) + base_string = "&".join(_oauth_escape(e) for e in base_elems) + + key_elems = [escape.utf8(consumer_token["secret"])] + key_elems.append(escape.utf8(token["secret"] if token else "")) + key = b"&".join(key_elems) + + hash = hmac.new(key, escape.utf8(base_string), hashlib.sha1) + return binascii.b2a_base64(hash.digest())[:-1] + + +def _oauth10a_signature( + consumer_token: Dict[str, Any], + method: str, + url: str, + parameters: Dict[str, Any] = {}, + token: Optional[Dict[str, Any]] = None, +) -> bytes: + """Calculates the HMAC-SHA1 OAuth 1.0a signature for the given request. + + See http://oauth.net/core/1.0a/#signing_process + """ + parts = urllib.parse.urlparse(url) + scheme, netloc, path = parts[:3] + normalized_url = scheme.lower() + "://" + netloc.lower() + path + + base_elems = [] + base_elems.append(method.upper()) + base_elems.append(normalized_url) + base_elems.append( + "&".join( + "%s=%s" % (k, _oauth_escape(str(v))) for k, v in sorted(parameters.items()) + ) + ) + + base_string = "&".join(_oauth_escape(e) for e in base_elems) + key_elems = [escape.utf8(urllib.parse.quote(consumer_token["secret"], safe="~"))] + key_elems.append( + escape.utf8(urllib.parse.quote(token["secret"], safe="~") if token else "") + ) + key = b"&".join(key_elems) + + hash = hmac.new(key, escape.utf8(base_string), hashlib.sha1) + return binascii.b2a_base64(hash.digest())[:-1] + + +def _oauth_escape(val: Union[str, bytes]) -> str: + if isinstance(val, unicode_type): + val = val.encode("utf-8") + return urllib.parse.quote(val, safe="~") + + +def _oauth_parse_response(body: bytes) -> Dict[str, Any]: + # I can't find an officially-defined encoding for oauth responses and + # have never seen anyone use non-ascii. Leave the response in a byte + # string for python 2, and use utf8 on python 3. + body_str = escape.native_str(body) + p = urllib.parse.parse_qs(body_str, keep_blank_values=False) + token = dict(key=p["oauth_token"][0], secret=p["oauth_token_secret"][0]) + + # Add the extra parameters the Provider included to the token + special = ("oauth_token", "oauth_token_secret") + token.update((k, p[k][0]) for k in p if k not in special) + return token diff --git a/venv/lib/python3.8/site-packages/tornado/autoreload.py b/venv/lib/python3.8/site-packages/tornado/autoreload.py new file mode 100644 index 0000000..3299a3b --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/autoreload.py @@ -0,0 +1,363 @@ +# +# Copyright 2009 Facebook +# +# 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. + +"""Automatically restart the server when a source file is modified. + +Most applications should not access this module directly. Instead, +pass the keyword argument ``autoreload=True`` to the +`tornado.web.Application` constructor (or ``debug=True``, which +enables this setting and several others). This will enable autoreload +mode as well as checking for changes to templates and static +resources. Note that restarting is a destructive operation and any +requests in progress will be aborted when the process restarts. (If +you want to disable autoreload while using other debug-mode features, +pass both ``debug=True`` and ``autoreload=False``). + +This module can also be used as a command-line wrapper around scripts +such as unit test runners. See the `main` method for details. + +The command-line wrapper and Application debug modes can be used together. +This combination is encouraged as the wrapper catches syntax errors and +other import-time failures, while debug mode catches changes once +the server has started. + +This module will not work correctly when `.HTTPServer`'s multi-process +mode is used. + +Reloading loses any Python interpreter command-line arguments (e.g. ``-u``) +because it re-executes Python using ``sys.executable`` and ``sys.argv``. +Additionally, modifying these variables will cause reloading to behave +incorrectly. + +""" + +import os +import sys + +# sys.path handling +# ----------------- +# +# If a module is run with "python -m", the current directory (i.e. "") +# is automatically prepended to sys.path, but not if it is run as +# "path/to/file.py". The processing for "-m" rewrites the former to +# the latter, so subsequent executions won't have the same path as the +# original. +# +# Conversely, when run as path/to/file.py, the directory containing +# file.py gets added to the path, which can cause confusion as imports +# may become relative in spite of the future import. +# +# We address the former problem by reconstructing the original command +# line (Python >= 3.4) or by setting the $PYTHONPATH environment +# variable (Python < 3.4) before re-execution so the new process will +# see the correct path. We attempt to address the latter problem when +# tornado.autoreload is run as __main__. + +if __name__ == "__main__": + # This sys.path manipulation must come before our imports (as much + # as possible - if we introduced a tornado.sys or tornado.os + # module we'd be in trouble), or else our imports would become + # relative again despite the future import. + # + # There is a separate __main__ block at the end of the file to call main(). + if sys.path[0] == os.path.dirname(__file__): + del sys.path[0] + +import functools +import logging +import os +import pkgutil # type: ignore +import sys +import traceback +import types +import subprocess +import weakref + +from tornado import ioloop +from tornado.log import gen_log +from tornado import process +from tornado.util import exec_in + +try: + import signal +except ImportError: + signal = None # type: ignore + +import typing +from typing import Callable, Dict + +if typing.TYPE_CHECKING: + from typing import List, Optional, Union # noqa: F401 + +# os.execv is broken on Windows and can't properly parse command line +# arguments and executable name if they contain whitespaces. subprocess +# fixes that behavior. +_has_execv = sys.platform != "win32" + +_watched_files = set() +_reload_hooks = [] +_reload_attempted = False +_io_loops = weakref.WeakKeyDictionary() # type: ignore +_autoreload_is_main = False +_original_argv = None # type: Optional[List[str]] +_original_spec = None + + +def start(check_time: int = 500) -> None: + """Begins watching source files for changes. + + .. versionchanged:: 5.0 + The ``io_loop`` argument (deprecated since version 4.1) has been removed. + """ + io_loop = ioloop.IOLoop.current() + if io_loop in _io_loops: + return + _io_loops[io_loop] = True + if len(_io_loops) > 1: + gen_log.warning("tornado.autoreload started more than once in the same process") + modify_times = {} # type: Dict[str, float] + callback = functools.partial(_reload_on_update, modify_times) + scheduler = ioloop.PeriodicCallback(callback, check_time) + scheduler.start() + + +def wait() -> None: + """Wait for a watched file to change, then restart the process. + + Intended to be used at the end of scripts like unit test runners, + to run the tests again after any source file changes (but see also + the command-line interface in `main`) + """ + io_loop = ioloop.IOLoop() + io_loop.add_callback(start) + io_loop.start() + + +def watch(filename: str) -> None: + """Add a file to the watch list. + + All imported modules are watched by default. + """ + _watched_files.add(filename) + + +def add_reload_hook(fn: Callable[[], None]) -> None: + """Add a function to be called before reloading the process. + + Note that for open file and socket handles it is generally + preferable to set the ``FD_CLOEXEC`` flag (using `fcntl` or + `os.set_inheritable`) instead of using a reload hook to close them. + """ + _reload_hooks.append(fn) + + +def _reload_on_update(modify_times: Dict[str, float]) -> None: + if _reload_attempted: + # We already tried to reload and it didn't work, so don't try again. + return + if process.task_id() is not None: + # We're in a child process created by fork_processes. If child + # processes restarted themselves, they'd all restart and then + # all call fork_processes again. + return + for module in list(sys.modules.values()): + # Some modules play games with sys.modules (e.g. email/__init__.py + # in the standard library), and occasionally this can cause strange + # failures in getattr. Just ignore anything that's not an ordinary + # module. + if not isinstance(module, types.ModuleType): + continue + path = getattr(module, "__file__", None) + if not path: + continue + if path.endswith(".pyc") or path.endswith(".pyo"): + path = path[:-1] + _check_file(modify_times, path) + for path in _watched_files: + _check_file(modify_times, path) + + +def _check_file(modify_times: Dict[str, float], path: str) -> None: + try: + modified = os.stat(path).st_mtime + except Exception: + return + if path not in modify_times: + modify_times[path] = modified + return + if modify_times[path] != modified: + gen_log.info("%s modified; restarting server", path) + _reload() + + +def _reload() -> None: + global _reload_attempted + _reload_attempted = True + for fn in _reload_hooks: + fn() + if hasattr(signal, "setitimer"): + # Clear the alarm signal set by + # ioloop.set_blocking_log_threshold so it doesn't fire + # after the exec. + signal.setitimer(signal.ITIMER_REAL, 0, 0) + # sys.path fixes: see comments at top of file. If __main__.__spec__ + # exists, we were invoked with -m and the effective path is about to + # change on re-exec. Reconstruct the original command line to + # ensure that the new process sees the same path we did. If + # __spec__ is not available (Python < 3.4), check instead if + # sys.path[0] is an empty string and add the current directory to + # $PYTHONPATH. + if _autoreload_is_main: + assert _original_argv is not None + spec = _original_spec + argv = _original_argv + else: + spec = getattr(sys.modules["__main__"], "__spec__", None) + argv = sys.argv + if spec: + argv = ["-m", spec.name] + argv[1:] + else: + path_prefix = "." + os.pathsep + if sys.path[0] == "" and not os.environ.get("PYTHONPATH", "").startswith( + path_prefix + ): + os.environ["PYTHONPATH"] = path_prefix + os.environ.get("PYTHONPATH", "") + if not _has_execv: + subprocess.Popen([sys.executable] + argv) + os._exit(0) + else: + try: + os.execv(sys.executable, [sys.executable] + argv) + except OSError: + # Mac OS X versions prior to 10.6 do not support execv in + # a process that contains multiple threads. Instead of + # re-executing in the current process, start a new one + # and cause the current process to exit. This isn't + # ideal since the new process is detached from the parent + # terminal and thus cannot easily be killed with ctrl-C, + # but it's better than not being able to autoreload at + # all. + # Unfortunately the errno returned in this case does not + # appear to be consistent, so we can't easily check for + # this error specifically. + os.spawnv( + os.P_NOWAIT, sys.executable, [sys.executable] + argv # type: ignore + ) + # At this point the IOLoop has been closed and finally + # blocks will experience errors if we allow the stack to + # unwind, so just exit uncleanly. + os._exit(0) + + +_USAGE = """\ +Usage: + python -m tornado.autoreload -m module.to.run [args...] + python -m tornado.autoreload path/to/script.py [args...] +""" + + +def main() -> None: + """Command-line wrapper to re-run a script whenever its source changes. + + Scripts may be specified by filename or module name:: + + python -m tornado.autoreload -m tornado.test.runtests + python -m tornado.autoreload tornado/test/runtests.py + + Running a script with this wrapper is similar to calling + `tornado.autoreload.wait` at the end of the script, but this wrapper + can catch import-time problems like syntax errors that would otherwise + prevent the script from reaching its call to `wait`. + """ + # Remember that we were launched with autoreload as main. + # The main module can be tricky; set the variables both in our globals + # (which may be __main__) and the real importable version. + import tornado.autoreload + + global _autoreload_is_main + global _original_argv, _original_spec + tornado.autoreload._autoreload_is_main = _autoreload_is_main = True + original_argv = sys.argv + tornado.autoreload._original_argv = _original_argv = original_argv + original_spec = getattr(sys.modules["__main__"], "__spec__", None) + tornado.autoreload._original_spec = _original_spec = original_spec + sys.argv = sys.argv[:] + if len(sys.argv) >= 3 and sys.argv[1] == "-m": + mode = "module" + module = sys.argv[2] + del sys.argv[1:3] + elif len(sys.argv) >= 2: + mode = "script" + script = sys.argv[1] + sys.argv = sys.argv[1:] + else: + print(_USAGE, file=sys.stderr) + sys.exit(1) + + try: + if mode == "module": + import runpy + + runpy.run_module(module, run_name="__main__", alter_sys=True) + elif mode == "script": + with open(script) as f: + # Execute the script in our namespace instead of creating + # a new one so that something that tries to import __main__ + # (e.g. the unittest module) will see names defined in the + # script instead of just those defined in this module. + global __file__ + __file__ = script + # If __package__ is defined, imports may be incorrectly + # interpreted as relative to this module. + global __package__ + del __package__ + exec_in(f.read(), globals(), globals()) + except SystemExit as e: + logging.basicConfig() + gen_log.info("Script exited with status %s", e.code) + except Exception as e: + logging.basicConfig() + gen_log.warning("Script exited with uncaught exception", exc_info=True) + # If an exception occurred at import time, the file with the error + # never made it into sys.modules and so we won't know to watch it. + # Just to make sure we've covered everything, walk the stack trace + # from the exception and watch every file. + for (filename, lineno, name, line) in traceback.extract_tb(sys.exc_info()[2]): + watch(filename) + if isinstance(e, SyntaxError): + # SyntaxErrors are special: their innermost stack frame is fake + # so extract_tb won't see it and we have to get the filename + # from the exception object. + watch(e.filename) + else: + logging.basicConfig() + gen_log.info("Script exited normally") + # restore sys.argv so subsequent executions will include autoreload + sys.argv = original_argv + + if mode == "module": + # runpy did a fake import of the module as __main__, but now it's + # no longer in sys.modules. Figure out where it is and watch it. + loader = pkgutil.get_loader(module) + if loader is not None: + watch(loader.get_filename()) # type: ignore + + wait() + + +if __name__ == "__main__": + # See also the other __main__ block at the top of the file, which modifies + # sys.path before our imports + main() diff --git a/venv/lib/python3.8/site-packages/tornado/concurrent.py b/venv/lib/python3.8/site-packages/tornado/concurrent.py new file mode 100644 index 0000000..7638fcf --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/concurrent.py @@ -0,0 +1,263 @@ +# +# Copyright 2012 Facebook +# +# 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. +"""Utilities for working with ``Future`` objects. + +Tornado previously provided its own ``Future`` class, but now uses +`asyncio.Future`. This module contains utility functions for working +with `asyncio.Future` in a way that is backwards-compatible with +Tornado's old ``Future`` implementation. + +While this module is an important part of Tornado's internal +implementation, applications rarely need to interact with it +directly. + +""" + +import asyncio +from concurrent import futures +import functools +import sys +import types + +from tornado.log import app_log + +import typing +from typing import Any, Callable, Optional, Tuple, Union + +_T = typing.TypeVar("_T") + + +class ReturnValueIgnoredError(Exception): + # No longer used; was previously used by @return_future + pass + + +Future = asyncio.Future + +FUTURES = (futures.Future, Future) + + +def is_future(x: Any) -> bool: + return isinstance(x, FUTURES) + + +class DummyExecutor(futures.Executor): + def submit( + self, fn: Callable[..., _T], *args: Any, **kwargs: Any + ) -> "futures.Future[_T]": + future = futures.Future() # type: futures.Future[_T] + try: + future_set_result_unless_cancelled(future, fn(*args, **kwargs)) + except Exception: + future_set_exc_info(future, sys.exc_info()) + return future + + def shutdown(self, wait: bool = True) -> None: + pass + + +dummy_executor = DummyExecutor() + + +def run_on_executor(*args: Any, **kwargs: Any) -> Callable: + """Decorator to run a synchronous method asynchronously on an executor. + + Returns a future. + + The executor to be used is determined by the ``executor`` + attributes of ``self``. To use a different attribute name, pass a + keyword argument to the decorator:: + + @run_on_executor(executor='_thread_pool') + def foo(self): + pass + + This decorator should not be confused with the similarly-named + `.IOLoop.run_in_executor`. In general, using ``run_in_executor`` + when *calling* a blocking method is recommended instead of using + this decorator when *defining* a method. If compatibility with older + versions of Tornado is required, consider defining an executor + and using ``executor.submit()`` at the call site. + + .. versionchanged:: 4.2 + Added keyword arguments to use alternative attributes. + + .. versionchanged:: 5.0 + Always uses the current IOLoop instead of ``self.io_loop``. + + .. versionchanged:: 5.1 + Returns a `.Future` compatible with ``await`` instead of a + `concurrent.futures.Future`. + + .. deprecated:: 5.1 + + The ``callback`` argument is deprecated and will be removed in + 6.0. The decorator itself is discouraged in new code but will + not be removed in 6.0. + + .. versionchanged:: 6.0 + + The ``callback`` argument was removed. + """ + # Fully type-checking decorators is tricky, and this one is + # discouraged anyway so it doesn't have all the generic magic. + def run_on_executor_decorator(fn: Callable) -> Callable[..., Future]: + executor = kwargs.get("executor", "executor") + + @functools.wraps(fn) + def wrapper(self: Any, *args: Any, **kwargs: Any) -> Future: + async_future = Future() # type: Future + conc_future = getattr(self, executor).submit(fn, self, *args, **kwargs) + chain_future(conc_future, async_future) + return async_future + + return wrapper + + if args and kwargs: + raise ValueError("cannot combine positional and keyword args") + if len(args) == 1: + return run_on_executor_decorator(args[0]) + elif len(args) != 0: + raise ValueError("expected 1 argument, got %d", len(args)) + return run_on_executor_decorator + + +_NO_RESULT = object() + + +def chain_future(a: "Future[_T]", b: "Future[_T]") -> None: + """Chain two futures together so that when one completes, so does the other. + + The result (success or failure) of ``a`` will be copied to ``b``, unless + ``b`` has already been completed or cancelled by the time ``a`` finishes. + + .. versionchanged:: 5.0 + + Now accepts both Tornado/asyncio `Future` objects and + `concurrent.futures.Future`. + + """ + + def copy(future: "Future[_T]") -> None: + assert future is a + if b.done(): + return + if hasattr(a, "exc_info") and a.exc_info() is not None: # type: ignore + future_set_exc_info(b, a.exc_info()) # type: ignore + elif a.exception() is not None: + b.set_exception(a.exception()) + else: + b.set_result(a.result()) + + if isinstance(a, Future): + future_add_done_callback(a, copy) + else: + # concurrent.futures.Future + from tornado.ioloop import IOLoop + + IOLoop.current().add_future(a, copy) + + +def future_set_result_unless_cancelled( + future: "Union[futures.Future[_T], Future[_T]]", value: _T +) -> None: + """Set the given ``value`` as the `Future`'s result, if not cancelled. + + Avoids ``asyncio.InvalidStateError`` when calling ``set_result()`` on + a cancelled `asyncio.Future`. + + .. versionadded:: 5.0 + """ + if not future.cancelled(): + future.set_result(value) + + +def future_set_exception_unless_cancelled( + future: "Union[futures.Future[_T], Future[_T]]", exc: BaseException +) -> None: + """Set the given ``exc`` as the `Future`'s exception. + + If the Future is already canceled, logs the exception instead. If + this logging is not desired, the caller should explicitly check + the state of the Future and call ``Future.set_exception`` instead of + this wrapper. + + Avoids ``asyncio.InvalidStateError`` when calling ``set_exception()`` on + a cancelled `asyncio.Future`. + + .. versionadded:: 6.0 + + """ + if not future.cancelled(): + future.set_exception(exc) + else: + app_log.error("Exception after Future was cancelled", exc_info=exc) + + +def future_set_exc_info( + future: "Union[futures.Future[_T], Future[_T]]", + exc_info: Tuple[ + Optional[type], Optional[BaseException], Optional[types.TracebackType] + ], +) -> None: + """Set the given ``exc_info`` as the `Future`'s exception. + + Understands both `asyncio.Future` and the extensions in older + versions of Tornado to enable better tracebacks on Python 2. + + .. versionadded:: 5.0 + + .. versionchanged:: 6.0 + + If the future is already cancelled, this function is a no-op. + (previously ``asyncio.InvalidStateError`` would be raised) + + """ + if exc_info[1] is None: + raise Exception("future_set_exc_info called with no exception") + future_set_exception_unless_cancelled(future, exc_info[1]) + + +@typing.overload +def future_add_done_callback( + future: "futures.Future[_T]", callback: Callable[["futures.Future[_T]"], None] +) -> None: + pass + + +@typing.overload # noqa: F811 +def future_add_done_callback( + future: "Future[_T]", callback: Callable[["Future[_T]"], None] +) -> None: + pass + + +def future_add_done_callback( # noqa: F811 + future: "Union[futures.Future[_T], Future[_T]]", callback: Callable[..., None] +) -> None: + """Arrange to call ``callback`` when ``future`` is complete. + + ``callback`` is invoked with one argument, the ``future``. + + If ``future`` is already done, ``callback`` is invoked immediately. + This may differ from the behavior of ``Future.add_done_callback``, + which makes no such guarantee. + + .. versionadded:: 5.0 + """ + if future.done(): + callback(future) + else: + future.add_done_callback(callback) diff --git a/venv/lib/python3.8/site-packages/tornado/curl_httpclient.py b/venv/lib/python3.8/site-packages/tornado/curl_httpclient.py new file mode 100644 index 0000000..6553999 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/curl_httpclient.py @@ -0,0 +1,583 @@ +# +# Copyright 2009 Facebook +# +# 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. + +"""Non-blocking HTTP client implementation using pycurl.""" + +import collections +import functools +import logging +import pycurl +import threading +import time +from io import BytesIO + +from tornado import httputil +from tornado import ioloop + +from tornado.escape import utf8, native_str +from tornado.httpclient import ( + HTTPRequest, + HTTPResponse, + HTTPError, + AsyncHTTPClient, + main, +) +from tornado.log import app_log + +from typing import Dict, Any, Callable, Union, Tuple, Optional +import typing + +if typing.TYPE_CHECKING: + from typing import Deque # noqa: F401 + +curl_log = logging.getLogger("tornado.curl_httpclient") + + +class CurlAsyncHTTPClient(AsyncHTTPClient): + def initialize( # type: ignore + self, max_clients: int = 10, defaults: Optional[Dict[str, Any]] = None + ) -> None: + super().initialize(defaults=defaults) + # Typeshed is incomplete for CurlMulti, so just use Any for now. + self._multi = pycurl.CurlMulti() # type: Any + self._multi.setopt(pycurl.M_TIMERFUNCTION, self._set_timeout) + self._multi.setopt(pycurl.M_SOCKETFUNCTION, self._handle_socket) + self._curls = [self._curl_create() for i in range(max_clients)] + self._free_list = self._curls[:] + self._requests = ( + collections.deque() + ) # type: Deque[Tuple[HTTPRequest, Callable[[HTTPResponse], None], float]] + self._fds = {} # type: Dict[int, int] + self._timeout = None # type: Optional[object] + + # libcurl has bugs that sometimes cause it to not report all + # relevant file descriptors and timeouts to TIMERFUNCTION/ + # SOCKETFUNCTION. Mitigate the effects of such bugs by + # forcing a periodic scan of all active requests. + self._force_timeout_callback = ioloop.PeriodicCallback( + self._handle_force_timeout, 1000 + ) + self._force_timeout_callback.start() + + # Work around a bug in libcurl 7.29.0: Some fields in the curl + # multi object are initialized lazily, and its destructor will + # segfault if it is destroyed without having been used. Add + # and remove a dummy handle to make sure everything is + # initialized. + dummy_curl_handle = pycurl.Curl() + self._multi.add_handle(dummy_curl_handle) + self._multi.remove_handle(dummy_curl_handle) + + def close(self) -> None: + self._force_timeout_callback.stop() + if self._timeout is not None: + self.io_loop.remove_timeout(self._timeout) + for curl in self._curls: + curl.close() + self._multi.close() + super().close() + + # Set below properties to None to reduce the reference count of current + # instance, because those properties hold some methods of current + # instance that will case circular reference. + self._force_timeout_callback = None # type: ignore + self._multi = None + + def fetch_impl( + self, request: HTTPRequest, callback: Callable[[HTTPResponse], None] + ) -> None: + self._requests.append((request, callback, self.io_loop.time())) + self._process_queue() + self._set_timeout(0) + + def _handle_socket(self, event: int, fd: int, multi: Any, data: bytes) -> None: + """Called by libcurl when it wants to change the file descriptors + it cares about. + """ + event_map = { + pycurl.POLL_NONE: ioloop.IOLoop.NONE, + pycurl.POLL_IN: ioloop.IOLoop.READ, + pycurl.POLL_OUT: ioloop.IOLoop.WRITE, + pycurl.POLL_INOUT: ioloop.IOLoop.READ | ioloop.IOLoop.WRITE, + } + if event == pycurl.POLL_REMOVE: + if fd in self._fds: + self.io_loop.remove_handler(fd) + del self._fds[fd] + else: + ioloop_event = event_map[event] + # libcurl sometimes closes a socket and then opens a new + # one using the same FD without giving us a POLL_NONE in + # between. This is a problem with the epoll IOLoop, + # because the kernel can tell when a socket is closed and + # removes it from the epoll automatically, causing future + # update_handler calls to fail. Since we can't tell when + # this has happened, always use remove and re-add + # instead of update. + if fd in self._fds: + self.io_loop.remove_handler(fd) + self.io_loop.add_handler(fd, self._handle_events, ioloop_event) + self._fds[fd] = ioloop_event + + def _set_timeout(self, msecs: int) -> None: + """Called by libcurl to schedule a timeout.""" + if self._timeout is not None: + self.io_loop.remove_timeout(self._timeout) + self._timeout = self.io_loop.add_timeout( + self.io_loop.time() + msecs / 1000.0, self._handle_timeout + ) + + def _handle_events(self, fd: int, events: int) -> None: + """Called by IOLoop when there is activity on one of our + file descriptors. + """ + action = 0 + if events & ioloop.IOLoop.READ: + action |= pycurl.CSELECT_IN + if events & ioloop.IOLoop.WRITE: + action |= pycurl.CSELECT_OUT + while True: + try: + ret, num_handles = self._multi.socket_action(fd, action) + except pycurl.error as e: + ret = e.args[0] + if ret != pycurl.E_CALL_MULTI_PERFORM: + break + self._finish_pending_requests() + + def _handle_timeout(self) -> None: + """Called by IOLoop when the requested timeout has passed.""" + self._timeout = None + while True: + try: + ret, num_handles = self._multi.socket_action(pycurl.SOCKET_TIMEOUT, 0) + except pycurl.error as e: + ret = e.args[0] + if ret != pycurl.E_CALL_MULTI_PERFORM: + break + self._finish_pending_requests() + + # In theory, we shouldn't have to do this because curl will + # call _set_timeout whenever the timeout changes. However, + # sometimes after _handle_timeout we will need to reschedule + # immediately even though nothing has changed from curl's + # perspective. This is because when socket_action is + # called with SOCKET_TIMEOUT, libcurl decides internally which + # timeouts need to be processed by using a monotonic clock + # (where available) while tornado uses python's time.time() + # to decide when timeouts have occurred. When those clocks + # disagree on elapsed time (as they will whenever there is an + # NTP adjustment), tornado might call _handle_timeout before + # libcurl is ready. After each timeout, resync the scheduled + # timeout with libcurl's current state. + new_timeout = self._multi.timeout() + if new_timeout >= 0: + self._set_timeout(new_timeout) + + def _handle_force_timeout(self) -> None: + """Called by IOLoop periodically to ask libcurl to process any + events it may have forgotten about. + """ + while True: + try: + ret, num_handles = self._multi.socket_all() + except pycurl.error as e: + ret = e.args[0] + if ret != pycurl.E_CALL_MULTI_PERFORM: + break + self._finish_pending_requests() + + def _finish_pending_requests(self) -> None: + """Process any requests that were completed by the last + call to multi.socket_action. + """ + while True: + num_q, ok_list, err_list = self._multi.info_read() + for curl in ok_list: + self._finish(curl) + for curl, errnum, errmsg in err_list: + self._finish(curl, errnum, errmsg) + if num_q == 0: + break + self._process_queue() + + def _process_queue(self) -> None: + while True: + started = 0 + while self._free_list and self._requests: + started += 1 + curl = self._free_list.pop() + (request, callback, queue_start_time) = self._requests.popleft() + # TODO: Don't smuggle extra data on an attribute of the Curl object. + curl.info = { # type: ignore + "headers": httputil.HTTPHeaders(), + "buffer": BytesIO(), + "request": request, + "callback": callback, + "queue_start_time": queue_start_time, + "curl_start_time": time.time(), + "curl_start_ioloop_time": self.io_loop.current().time(), + } + try: + self._curl_setup_request( + curl, + request, + curl.info["buffer"], # type: ignore + curl.info["headers"], # type: ignore + ) + except Exception as e: + # If there was an error in setup, pass it on + # to the callback. Note that allowing the + # error to escape here will appear to work + # most of the time since we are still in the + # caller's original stack frame, but when + # _process_queue() is called from + # _finish_pending_requests the exceptions have + # nowhere to go. + self._free_list.append(curl) + callback(HTTPResponse(request=request, code=599, error=e)) + else: + self._multi.add_handle(curl) + + if not started: + break + + def _finish( + self, + curl: pycurl.Curl, + curl_error: Optional[int] = None, + curl_message: Optional[str] = None, + ) -> None: + info = curl.info # type: ignore + curl.info = None # type: ignore + self._multi.remove_handle(curl) + self._free_list.append(curl) + buffer = info["buffer"] + if curl_error: + assert curl_message is not None + error = CurlError(curl_error, curl_message) # type: Optional[CurlError] + assert error is not None + code = error.code + effective_url = None + buffer.close() + buffer = None + else: + error = None + code = curl.getinfo(pycurl.HTTP_CODE) + effective_url = curl.getinfo(pycurl.EFFECTIVE_URL) + buffer.seek(0) + # the various curl timings are documented at + # http://curl.haxx.se/libcurl/c/curl_easy_getinfo.html + time_info = dict( + queue=info["curl_start_ioloop_time"] - info["queue_start_time"], + namelookup=curl.getinfo(pycurl.NAMELOOKUP_TIME), + connect=curl.getinfo(pycurl.CONNECT_TIME), + appconnect=curl.getinfo(pycurl.APPCONNECT_TIME), + pretransfer=curl.getinfo(pycurl.PRETRANSFER_TIME), + starttransfer=curl.getinfo(pycurl.STARTTRANSFER_TIME), + total=curl.getinfo(pycurl.TOTAL_TIME), + redirect=curl.getinfo(pycurl.REDIRECT_TIME), + ) + try: + info["callback"]( + HTTPResponse( + request=info["request"], + code=code, + headers=info["headers"], + buffer=buffer, + effective_url=effective_url, + error=error, + reason=info["headers"].get("X-Http-Reason", None), + request_time=self.io_loop.time() - info["curl_start_ioloop_time"], + start_time=info["curl_start_time"], + time_info=time_info, + ) + ) + except Exception: + self.handle_callback_exception(info["callback"]) + + def handle_callback_exception(self, callback: Any) -> None: + app_log.error("Exception in callback %r", callback, exc_info=True) + + def _curl_create(self) -> pycurl.Curl: + curl = pycurl.Curl() + if curl_log.isEnabledFor(logging.DEBUG): + curl.setopt(pycurl.VERBOSE, 1) + curl.setopt(pycurl.DEBUGFUNCTION, self._curl_debug) + if hasattr( + pycurl, "PROTOCOLS" + ): # PROTOCOLS first appeared in pycurl 7.19.5 (2014-07-12) + curl.setopt(pycurl.PROTOCOLS, pycurl.PROTO_HTTP | pycurl.PROTO_HTTPS) + curl.setopt(pycurl.REDIR_PROTOCOLS, pycurl.PROTO_HTTP | pycurl.PROTO_HTTPS) + return curl + + def _curl_setup_request( + self, + curl: pycurl.Curl, + request: HTTPRequest, + buffer: BytesIO, + headers: httputil.HTTPHeaders, + ) -> None: + curl.setopt(pycurl.URL, native_str(request.url)) + + # libcurl's magic "Expect: 100-continue" behavior causes delays + # with servers that don't support it (which include, among others, + # Google's OpenID endpoint). Additionally, this behavior has + # a bug in conjunction with the curl_multi_socket_action API + # (https://sourceforge.net/tracker/?func=detail&atid=100976&aid=3039744&group_id=976), + # which increases the delays. It's more trouble than it's worth, + # so just turn off the feature (yes, setting Expect: to an empty + # value is the official way to disable this) + if "Expect" not in request.headers: + request.headers["Expect"] = "" + + # libcurl adds Pragma: no-cache by default; disable that too + if "Pragma" not in request.headers: + request.headers["Pragma"] = "" + + curl.setopt( + pycurl.HTTPHEADER, + [ + "%s: %s" % (native_str(k), native_str(v)) + for k, v in request.headers.get_all() + ], + ) + + curl.setopt( + pycurl.HEADERFUNCTION, + functools.partial( + self._curl_header_callback, headers, request.header_callback + ), + ) + if request.streaming_callback: + + def write_function(b: Union[bytes, bytearray]) -> int: + assert request.streaming_callback is not None + self.io_loop.add_callback(request.streaming_callback, b) + return len(b) + + else: + write_function = buffer.write + curl.setopt(pycurl.WRITEFUNCTION, write_function) + curl.setopt(pycurl.FOLLOWLOCATION, request.follow_redirects) + curl.setopt(pycurl.MAXREDIRS, request.max_redirects) + assert request.connect_timeout is not None + curl.setopt(pycurl.CONNECTTIMEOUT_MS, int(1000 * request.connect_timeout)) + assert request.request_timeout is not None + curl.setopt(pycurl.TIMEOUT_MS, int(1000 * request.request_timeout)) + if request.user_agent: + curl.setopt(pycurl.USERAGENT, native_str(request.user_agent)) + else: + curl.setopt(pycurl.USERAGENT, "Mozilla/5.0 (compatible; pycurl)") + if request.network_interface: + curl.setopt(pycurl.INTERFACE, request.network_interface) + if request.decompress_response: + curl.setopt(pycurl.ENCODING, "gzip,deflate") + else: + curl.setopt(pycurl.ENCODING, None) + if request.proxy_host and request.proxy_port: + curl.setopt(pycurl.PROXY, request.proxy_host) + curl.setopt(pycurl.PROXYPORT, request.proxy_port) + if request.proxy_username: + assert request.proxy_password is not None + credentials = httputil.encode_username_password( + request.proxy_username, request.proxy_password + ) + curl.setopt(pycurl.PROXYUSERPWD, credentials) + + if request.proxy_auth_mode is None or request.proxy_auth_mode == "basic": + curl.setopt(pycurl.PROXYAUTH, pycurl.HTTPAUTH_BASIC) + elif request.proxy_auth_mode == "digest": + curl.setopt(pycurl.PROXYAUTH, pycurl.HTTPAUTH_DIGEST) + else: + raise ValueError( + "Unsupported proxy_auth_mode %s" % request.proxy_auth_mode + ) + else: + try: + curl.unsetopt(pycurl.PROXY) + except TypeError: # not supported, disable proxy + curl.setopt(pycurl.PROXY, "") + curl.unsetopt(pycurl.PROXYUSERPWD) + if request.validate_cert: + curl.setopt(pycurl.SSL_VERIFYPEER, 1) + curl.setopt(pycurl.SSL_VERIFYHOST, 2) + else: + curl.setopt(pycurl.SSL_VERIFYPEER, 0) + curl.setopt(pycurl.SSL_VERIFYHOST, 0) + if request.ca_certs is not None: + curl.setopt(pycurl.CAINFO, request.ca_certs) + else: + # There is no way to restore pycurl.CAINFO to its default value + # (Using unsetopt makes it reject all certificates). + # I don't see any way to read the default value from python so it + # can be restored later. We'll have to just leave CAINFO untouched + # if no ca_certs file was specified, and require that if any + # request uses a custom ca_certs file, they all must. + pass + + if request.allow_ipv6 is False: + # Curl behaves reasonably when DNS resolution gives an ipv6 address + # that we can't reach, so allow ipv6 unless the user asks to disable. + curl.setopt(pycurl.IPRESOLVE, pycurl.IPRESOLVE_V4) + else: + curl.setopt(pycurl.IPRESOLVE, pycurl.IPRESOLVE_WHATEVER) + + # Set the request method through curl's irritating interface which makes + # up names for almost every single method + curl_options = { + "GET": pycurl.HTTPGET, + "POST": pycurl.POST, + "PUT": pycurl.UPLOAD, + "HEAD": pycurl.NOBODY, + } + custom_methods = set(["DELETE", "OPTIONS", "PATCH"]) + for o in curl_options.values(): + curl.setopt(o, False) + if request.method in curl_options: + curl.unsetopt(pycurl.CUSTOMREQUEST) + curl.setopt(curl_options[request.method], True) + elif request.allow_nonstandard_methods or request.method in custom_methods: + curl.setopt(pycurl.CUSTOMREQUEST, request.method) + else: + raise KeyError("unknown method " + request.method) + + body_expected = request.method in ("POST", "PATCH", "PUT") + body_present = request.body is not None + if not request.allow_nonstandard_methods: + # Some HTTP methods nearly always have bodies while others + # almost never do. Fail in this case unless the user has + # opted out of sanity checks with allow_nonstandard_methods. + if (body_expected and not body_present) or ( + body_present and not body_expected + ): + raise ValueError( + "Body must %sbe None for method %s (unless " + "allow_nonstandard_methods is true)" + % ("not " if body_expected else "", request.method) + ) + + if body_expected or body_present: + if request.method == "GET": + # Even with `allow_nonstandard_methods` we disallow + # GET with a body (because libcurl doesn't allow it + # unless we use CUSTOMREQUEST). While the spec doesn't + # forbid clients from sending a body, it arguably + # disallows the server from doing anything with them. + raise ValueError("Body must be None for GET request") + request_buffer = BytesIO(utf8(request.body or "")) + + def ioctl(cmd: int) -> None: + if cmd == curl.IOCMD_RESTARTREAD: # type: ignore + request_buffer.seek(0) + + curl.setopt(pycurl.READFUNCTION, request_buffer.read) + curl.setopt(pycurl.IOCTLFUNCTION, ioctl) + if request.method == "POST": + curl.setopt(pycurl.POSTFIELDSIZE, len(request.body or "")) + else: + curl.setopt(pycurl.UPLOAD, True) + curl.setopt(pycurl.INFILESIZE, len(request.body or "")) + + if request.auth_username is not None: + assert request.auth_password is not None + if request.auth_mode is None or request.auth_mode == "basic": + curl.setopt(pycurl.HTTPAUTH, pycurl.HTTPAUTH_BASIC) + elif request.auth_mode == "digest": + curl.setopt(pycurl.HTTPAUTH, pycurl.HTTPAUTH_DIGEST) + else: + raise ValueError("Unsupported auth_mode %s" % request.auth_mode) + + userpwd = httputil.encode_username_password( + request.auth_username, request.auth_password + ) + curl.setopt(pycurl.USERPWD, userpwd) + curl_log.debug( + "%s %s (username: %r)", + request.method, + request.url, + request.auth_username, + ) + else: + curl.unsetopt(pycurl.USERPWD) + curl_log.debug("%s %s", request.method, request.url) + + if request.client_cert is not None: + curl.setopt(pycurl.SSLCERT, request.client_cert) + + if request.client_key is not None: + curl.setopt(pycurl.SSLKEY, request.client_key) + + if request.ssl_options is not None: + raise ValueError("ssl_options not supported in curl_httpclient") + + if threading.active_count() > 1: + # libcurl/pycurl is not thread-safe by default. When multiple threads + # are used, signals should be disabled. This has the side effect + # of disabling DNS timeouts in some environments (when libcurl is + # not linked against ares), so we don't do it when there is only one + # thread. Applications that use many short-lived threads may need + # to set NOSIGNAL manually in a prepare_curl_callback since + # there may not be any other threads running at the time we call + # threading.activeCount. + curl.setopt(pycurl.NOSIGNAL, 1) + if request.prepare_curl_callback is not None: + request.prepare_curl_callback(curl) + + def _curl_header_callback( + self, + headers: httputil.HTTPHeaders, + header_callback: Callable[[str], None], + header_line_bytes: bytes, + ) -> None: + header_line = native_str(header_line_bytes.decode("latin1")) + if header_callback is not None: + self.io_loop.add_callback(header_callback, header_line) + # header_line as returned by curl includes the end-of-line characters. + # whitespace at the start should be preserved to allow multi-line headers + header_line = header_line.rstrip() + if header_line.startswith("HTTP/"): + headers.clear() + try: + (__, __, reason) = httputil.parse_response_start_line(header_line) + header_line = "X-Http-Reason: %s" % reason + except httputil.HTTPInputError: + return + if not header_line: + return + headers.parse_line(header_line) + + def _curl_debug(self, debug_type: int, debug_msg: str) -> None: + debug_types = ("I", "<", ">", "<", ">") + if debug_type == 0: + debug_msg = native_str(debug_msg) + curl_log.debug("%s", debug_msg.strip()) + elif debug_type in (1, 2): + debug_msg = native_str(debug_msg) + for line in debug_msg.splitlines(): + curl_log.debug("%s %s", debug_types[debug_type], line) + elif debug_type == 4: + curl_log.debug("%s %r", debug_types[debug_type], debug_msg) + + +class CurlError(HTTPError): + def __init__(self, errno: int, message: str) -> None: + HTTPError.__init__(self, 599, message) + self.errno = errno + + +if __name__ == "__main__": + AsyncHTTPClient.configure(CurlAsyncHTTPClient) + main() diff --git a/venv/lib/python3.8/site-packages/tornado/escape.py b/venv/lib/python3.8/site-packages/tornado/escape.py new file mode 100644 index 0000000..3cf7ff2 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/escape.py @@ -0,0 +1,402 @@ +# +# Copyright 2009 Facebook +# +# 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. + +"""Escaping/unescaping methods for HTML, JSON, URLs, and others. + +Also includes a few other miscellaneous string manipulation functions that +have crept in over time. +""" + +import html.entities +import json +import re +import urllib.parse + +from tornado.util import unicode_type + +import typing +from typing import Union, Any, Optional, Dict, List, Callable + + +_XHTML_ESCAPE_RE = re.compile("[&<>\"']") +_XHTML_ESCAPE_DICT = { + "&": "&amp;", + "<": "&lt;", + ">": "&gt;", + '"': "&quot;", + "'": "&#39;", +} + + +def xhtml_escape(value: Union[str, bytes]) -> str: + """Escapes a string so it is valid within HTML or XML. + + Escapes the characters ``<``, ``>``, ``"``, ``'``, and ``&``. + When used in attribute values the escaped strings must be enclosed + in quotes. + + .. versionchanged:: 3.2 + + Added the single quote to the list of escaped characters. + """ + return _XHTML_ESCAPE_RE.sub( + lambda match: _XHTML_ESCAPE_DICT[match.group(0)], to_basestring(value) + ) + + +def xhtml_unescape(value: Union[str, bytes]) -> str: + """Un-escapes an XML-escaped string.""" + return re.sub(r"&(#?)(\w+?);", _convert_entity, _unicode(value)) + + +# The fact that json_encode wraps json.dumps is an implementation detail. +# Please see https://github.com/tornadoweb/tornado/pull/706 +# before sending a pull request that adds **kwargs to this function. +def json_encode(value: Any) -> str: + """JSON-encodes the given Python object.""" + # JSON permits but does not require forward slashes to be escaped. + # This is useful when json data is emitted in a <script> tag + # in HTML, as it prevents </script> tags from prematurely terminating + # the JavaScript. Some json libraries do this escaping by default, + # although python's standard library does not, so we do it here. + # http://stackoverflow.com/questions/1580647/json-why-are-forward-slashes-escaped + return json.dumps(value).replace("</", "<\\/") + + +def json_decode(value: Union[str, bytes]) -> Any: + """Returns Python objects for the given JSON string. + + Supports both `str` and `bytes` inputs. + """ + return json.loads(to_basestring(value)) + + +def squeeze(value: str) -> str: + """Replace all sequences of whitespace chars with a single space.""" + return re.sub(r"[\x00-\x20]+", " ", value).strip() + + +def url_escape(value: Union[str, bytes], plus: bool = True) -> str: + """Returns a URL-encoded version of the given value. + + If ``plus`` is true (the default), spaces will be represented + as "+" instead of "%20". This is appropriate for query strings + but not for the path component of a URL. Note that this default + is the reverse of Python's urllib module. + + .. versionadded:: 3.1 + The ``plus`` argument + """ + quote = urllib.parse.quote_plus if plus else urllib.parse.quote + return quote(utf8(value)) + + +@typing.overload +def url_unescape(value: Union[str, bytes], encoding: None, plus: bool = True) -> bytes: + pass + + +@typing.overload # noqa: F811 +def url_unescape( + value: Union[str, bytes], encoding: str = "utf-8", plus: bool = True +) -> str: + pass + + +def url_unescape( # noqa: F811 + value: Union[str, bytes], encoding: Optional[str] = "utf-8", plus: bool = True +) -> Union[str, bytes]: + """Decodes the given value from a URL. + + The argument may be either a byte or unicode string. + + If encoding is None, the result will be a byte string. Otherwise, + the result is a unicode string in the specified encoding. + + If ``plus`` is true (the default), plus signs will be interpreted + as spaces (literal plus signs must be represented as "%2B"). This + is appropriate for query strings and form-encoded values but not + for the path component of a URL. Note that this default is the + reverse of Python's urllib module. + + .. versionadded:: 3.1 + The ``plus`` argument + """ + if encoding is None: + if plus: + # unquote_to_bytes doesn't have a _plus variant + value = to_basestring(value).replace("+", " ") + return urllib.parse.unquote_to_bytes(value) + else: + unquote = urllib.parse.unquote_plus if plus else urllib.parse.unquote + return unquote(to_basestring(value), encoding=encoding) + + +def parse_qs_bytes( + qs: Union[str, bytes], keep_blank_values: bool = False, strict_parsing: bool = False +) -> Dict[str, List[bytes]]: + """Parses a query string like urlparse.parse_qs, + but takes bytes and returns the values as byte strings. + + Keys still become type str (interpreted as latin1 in python3!) + because it's too painful to keep them as byte strings in + python3 and in practice they're nearly always ascii anyway. + """ + # This is gross, but python3 doesn't give us another way. + # Latin1 is the universal donor of character encodings. + if isinstance(qs, bytes): + qs = qs.decode("latin1") + result = urllib.parse.parse_qs( + qs, keep_blank_values, strict_parsing, encoding="latin1", errors="strict" + ) + encoded = {} + for k, v in result.items(): + encoded[k] = [i.encode("latin1") for i in v] + return encoded + + +_UTF8_TYPES = (bytes, type(None)) + + +@typing.overload +def utf8(value: bytes) -> bytes: + pass + + +@typing.overload # noqa: F811 +def utf8(value: str) -> bytes: + pass + + +@typing.overload # noqa: F811 +def utf8(value: None) -> None: + pass + + +def utf8(value: Union[None, str, bytes]) -> Optional[bytes]: # noqa: F811 + """Converts a string argument to a byte string. + + If the argument is already a byte string or None, it is returned unchanged. + Otherwise it must be a unicode string and is encoded as utf8. + """ + if isinstance(value, _UTF8_TYPES): + return value + if not isinstance(value, unicode_type): + raise TypeError("Expected bytes, unicode, or None; got %r" % type(value)) + return value.encode("utf-8") + + +_TO_UNICODE_TYPES = (unicode_type, type(None)) + + +@typing.overload +def to_unicode(value: str) -> str: + pass + + +@typing.overload # noqa: F811 +def to_unicode(value: bytes) -> str: + pass + + +@typing.overload # noqa: F811 +def to_unicode(value: None) -> None: + pass + + +def to_unicode(value: Union[None, str, bytes]) -> Optional[str]: # noqa: F811 + """Converts a string argument to a unicode string. + + If the argument is already a unicode string or None, it is returned + unchanged. Otherwise it must be a byte string and is decoded as utf8. + """ + if isinstance(value, _TO_UNICODE_TYPES): + return value + if not isinstance(value, bytes): + raise TypeError("Expected bytes, unicode, or None; got %r" % type(value)) + return value.decode("utf-8") + + +# to_unicode was previously named _unicode not because it was private, +# but to avoid conflicts with the built-in unicode() function/type +_unicode = to_unicode + +# When dealing with the standard library across python 2 and 3 it is +# sometimes useful to have a direct conversion to the native string type +native_str = to_unicode +to_basestring = to_unicode + + +def recursive_unicode(obj: Any) -> Any: + """Walks a simple data structure, converting byte strings to unicode. + + Supports lists, tuples, and dictionaries. + """ + if isinstance(obj, dict): + return dict( + (recursive_unicode(k), recursive_unicode(v)) for (k, v) in obj.items() + ) + elif isinstance(obj, list): + return list(recursive_unicode(i) for i in obj) + elif isinstance(obj, tuple): + return tuple(recursive_unicode(i) for i in obj) + elif isinstance(obj, bytes): + return to_unicode(obj) + else: + return obj + + +# I originally used the regex from +# http://daringfireball.net/2010/07/improved_regex_for_matching_urls +# but it gets all exponential on certain patterns (such as too many trailing +# dots), causing the regex matcher to never return. +# This regex should avoid those problems. +# Use to_unicode instead of tornado.util.u - we don't want backslashes getting +# processed as escapes. +_URL_RE = re.compile( + to_unicode( + r"""\b((?:([\w-]+):(/{1,3})|www[.])(?:(?:(?:[^\s&()]|&amp;|&quot;)*(?:[^!"#$%&'()*+,.:;<=>?@\[\]^`{|}~\s]))|(?:\((?:[^\s&()]|&amp;|&quot;)*\)))+)""" # noqa: E501 + ) +) + + +def linkify( + text: Union[str, bytes], + shorten: bool = False, + extra_params: Union[str, Callable[[str], str]] = "", + require_protocol: bool = False, + permitted_protocols: List[str] = ["http", "https"], +) -> str: + """Converts plain text into HTML with links. + + For example: ``linkify("Hello http://tornadoweb.org!")`` would return + ``Hello <a href="http://tornadoweb.org">http://tornadoweb.org</a>!`` + + Parameters: + + * ``shorten``: Long urls will be shortened for display. + + * ``extra_params``: Extra text to include in the link tag, or a callable + taking the link as an argument and returning the extra text + e.g. ``linkify(text, extra_params='rel="nofollow" class="external"')``, + or:: + + def extra_params_cb(url): + if url.startswith("http://example.com"): + return 'class="internal"' + else: + return 'class="external" rel="nofollow"' + linkify(text, extra_params=extra_params_cb) + + * ``require_protocol``: Only linkify urls which include a protocol. If + this is False, urls such as www.facebook.com will also be linkified. + + * ``permitted_protocols``: List (or set) of protocols which should be + linkified, e.g. ``linkify(text, permitted_protocols=["http", "ftp", + "mailto"])``. It is very unsafe to include protocols such as + ``javascript``. + """ + if extra_params and not callable(extra_params): + extra_params = " " + extra_params.strip() + + def make_link(m: typing.Match) -> str: + url = m.group(1) + proto = m.group(2) + if require_protocol and not proto: + return url # not protocol, no linkify + + if proto and proto not in permitted_protocols: + return url # bad protocol, no linkify + + href = m.group(1) + if not proto: + href = "http://" + href # no proto specified, use http + + if callable(extra_params): + params = " " + extra_params(href).strip() + else: + params = extra_params + + # clip long urls. max_len is just an approximation + max_len = 30 + if shorten and len(url) > max_len: + before_clip = url + if proto: + proto_len = len(proto) + 1 + len(m.group(3) or "") # +1 for : + else: + proto_len = 0 + + parts = url[proto_len:].split("/") + if len(parts) > 1: + # Grab the whole host part plus the first bit of the path + # The path is usually not that interesting once shortened + # (no more slug, etc), so it really just provides a little + # extra indication of shortening. + url = ( + url[:proto_len] + + parts[0] + + "/" + + parts[1][:8].split("?")[0].split(".")[0] + ) + + if len(url) > max_len * 1.5: # still too long + url = url[:max_len] + + if url != before_clip: + amp = url.rfind("&") + # avoid splitting html char entities + if amp > max_len - 5: + url = url[:amp] + url += "..." + + if len(url) >= len(before_clip): + url = before_clip + else: + # full url is visible on mouse-over (for those who don't + # have a status bar, such as Safari by default) + params += ' title="%s"' % href + + return u'<a href="%s"%s>%s</a>' % (href, params, url) + + # First HTML-escape so that our strings are all safe. + # The regex is modified to avoid character entites other than &amp; so + # that we won't pick up &quot;, etc. + text = _unicode(xhtml_escape(text)) + return _URL_RE.sub(make_link, text) + + +def _convert_entity(m: typing.Match) -> str: + if m.group(1) == "#": + try: + if m.group(2)[:1].lower() == "x": + return chr(int(m.group(2)[1:], 16)) + else: + return chr(int(m.group(2))) + except ValueError: + return "&#%s;" % m.group(2) + try: + return _HTML_UNICODE_MAP[m.group(2)] + except KeyError: + return "&%s;" % m.group(2) + + +def _build_unicode_map() -> Dict[str, str]: + unicode_map = {} + for name, value in html.entities.name2codepoint.items(): + unicode_map[name] = chr(value) + return unicode_map + + +_HTML_UNICODE_MAP = _build_unicode_map() diff --git a/venv/lib/python3.8/site-packages/tornado/gen.py b/venv/lib/python3.8/site-packages/tornado/gen.py new file mode 100644 index 0000000..cab9689 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/gen.py @@ -0,0 +1,872 @@ +"""``tornado.gen`` implements generator-based coroutines. + +.. note:: + + The "decorator and generator" approach in this module is a + precursor to native coroutines (using ``async def`` and ``await``) + which were introduced in Python 3.5. Applications that do not + require compatibility with older versions of Python should use + native coroutines instead. Some parts of this module are still + useful with native coroutines, notably `multi`, `sleep`, + `WaitIterator`, and `with_timeout`. Some of these functions have + counterparts in the `asyncio` module which may be used as well, + although the two may not necessarily be 100% compatible. + +Coroutines provide an easier way to work in an asynchronous +environment than chaining callbacks. Code using coroutines is +technically asynchronous, but it is written as a single generator +instead of a collection of separate functions. + +For example, here's a coroutine-based handler: + +.. testcode:: + + class GenAsyncHandler(RequestHandler): + @gen.coroutine + def get(self): + http_client = AsyncHTTPClient() + response = yield http_client.fetch("http://example.com") + do_something_with_response(response) + self.render("template.html") + +.. testoutput:: + :hide: + +Asynchronous functions in Tornado return an ``Awaitable`` or `.Future`; +yielding this object returns its result. + +You can also yield a list or dict of other yieldable objects, which +will be started at the same time and run in parallel; a list or dict +of results will be returned when they are all finished: + +.. testcode:: + + @gen.coroutine + def get(self): + http_client = AsyncHTTPClient() + response1, response2 = yield [http_client.fetch(url1), + http_client.fetch(url2)] + response_dict = yield dict(response3=http_client.fetch(url3), + response4=http_client.fetch(url4)) + response3 = response_dict['response3'] + response4 = response_dict['response4'] + +.. testoutput:: + :hide: + +If ``tornado.platform.twisted`` is imported, it is also possible to +yield Twisted's ``Deferred`` objects. See the `convert_yielded` +function to extend this mechanism. + +.. versionchanged:: 3.2 + Dict support added. + +.. versionchanged:: 4.1 + Support added for yielding ``asyncio`` Futures and Twisted Deferreds + via ``singledispatch``. + +""" +import asyncio +import builtins +import collections +from collections.abc import Generator +import concurrent.futures +import datetime +import functools +from functools import singledispatch +from inspect import isawaitable +import sys +import types + +from tornado.concurrent import ( + Future, + is_future, + chain_future, + future_set_exc_info, + future_add_done_callback, + future_set_result_unless_cancelled, +) +from tornado.ioloop import IOLoop +from tornado.log import app_log +from tornado.util import TimeoutError + +try: + import contextvars +except ImportError: + contextvars = None # type: ignore + +import typing +from typing import Union, Any, Callable, List, Type, Tuple, Awaitable, Dict, overload + +if typing.TYPE_CHECKING: + from typing import Sequence, Deque, Optional, Set, Iterable # noqa: F401 + +_T = typing.TypeVar("_T") + +_Yieldable = Union[ + None, Awaitable, List[Awaitable], Dict[Any, Awaitable], concurrent.futures.Future +] + + +class KeyReuseError(Exception): + pass + + +class UnknownKeyError(Exception): + pass + + +class LeakedCallbackError(Exception): + pass + + +class BadYieldError(Exception): + pass + + +class ReturnValueIgnoredError(Exception): + pass + + +def _value_from_stopiteration(e: Union[StopIteration, "Return"]) -> Any: + try: + # StopIteration has a value attribute beginning in py33. + # So does our Return class. + return e.value + except AttributeError: + pass + try: + # Cython backports coroutine functionality by putting the value in + # e.args[0]. + return e.args[0] + except (AttributeError, IndexError): + return None + + +def _create_future() -> Future: + future = Future() # type: Future + # Fixup asyncio debug info by removing extraneous stack entries + source_traceback = getattr(future, "_source_traceback", ()) + while source_traceback: + # Each traceback entry is equivalent to a + # (filename, self.lineno, self.name, self.line) tuple + filename = source_traceback[-1][0] + if filename == __file__: + del source_traceback[-1] + else: + break + return future + + +def _fake_ctx_run(f: Callable[..., _T], *args: Any, **kw: Any) -> _T: + return f(*args, **kw) + + +@overload +def coroutine( + func: Callable[..., "Generator[Any, Any, _T]"] +) -> Callable[..., "Future[_T]"]: + ... + + +@overload +def coroutine(func: Callable[..., _T]) -> Callable[..., "Future[_T]"]: + ... + + +def coroutine( + func: Union[Callable[..., "Generator[Any, Any, _T]"], Callable[..., _T]] +) -> Callable[..., "Future[_T]"]: + """Decorator for asynchronous generators. + + For compatibility with older versions of Python, coroutines may + also "return" by raising the special exception `Return(value) + <Return>`. + + Functions with this decorator return a `.Future`. + + .. warning:: + + When exceptions occur inside a coroutine, the exception + information will be stored in the `.Future` object. You must + examine the result of the `.Future` object, or the exception + may go unnoticed by your code. This means yielding the function + if called from another coroutine, using something like + `.IOLoop.run_sync` for top-level calls, or passing the `.Future` + to `.IOLoop.add_future`. + + .. versionchanged:: 6.0 + + The ``callback`` argument was removed. Use the returned + awaitable object instead. + + """ + + @functools.wraps(func) + def wrapper(*args, **kwargs): + # type: (*Any, **Any) -> Future[_T] + # This function is type-annotated with a comment to work around + # https://bitbucket.org/pypy/pypy/issues/2868/segfault-with-args-type-annotation-in + future = _create_future() + if contextvars is not None: + ctx_run = contextvars.copy_context().run # type: Callable + else: + ctx_run = _fake_ctx_run + try: + result = ctx_run(func, *args, **kwargs) + except (Return, StopIteration) as e: + result = _value_from_stopiteration(e) + except Exception: + future_set_exc_info(future, sys.exc_info()) + try: + return future + finally: + # Avoid circular references + future = None # type: ignore + else: + if isinstance(result, Generator): + # Inline the first iteration of Runner.run. This lets us + # avoid the cost of creating a Runner when the coroutine + # never actually yields, which in turn allows us to + # use "optional" coroutines in critical path code without + # performance penalty for the synchronous case. + try: + yielded = ctx_run(next, result) + except (StopIteration, Return) as e: + future_set_result_unless_cancelled( + future, _value_from_stopiteration(e) + ) + except Exception: + future_set_exc_info(future, sys.exc_info()) + else: + # Provide strong references to Runner objects as long + # as their result future objects also have strong + # references (typically from the parent coroutine's + # Runner). This keeps the coroutine's Runner alive. + # We do this by exploiting the public API + # add_done_callback() instead of putting a private + # attribute on the Future. + # (GitHub issues #1769, #2229). + runner = Runner(ctx_run, result, future, yielded) + future.add_done_callback(lambda _: runner) + yielded = None + try: + return future + finally: + # Subtle memory optimization: if next() raised an exception, + # the future's exc_info contains a traceback which + # includes this stack frame. This creates a cycle, + # which will be collected at the next full GC but has + # been shown to greatly increase memory usage of + # benchmarks (relative to the refcount-based scheme + # used in the absence of cycles). We can avoid the + # cycle by clearing the local variable after we return it. + future = None # type: ignore + future_set_result_unless_cancelled(future, result) + return future + + wrapper.__wrapped__ = func # type: ignore + wrapper.__tornado_coroutine__ = True # type: ignore + return wrapper + + +def is_coroutine_function(func: Any) -> bool: + """Return whether *func* is a coroutine function, i.e. a function + wrapped with `~.gen.coroutine`. + + .. versionadded:: 4.5 + """ + return getattr(func, "__tornado_coroutine__", False) + + +class Return(Exception): + """Special exception to return a value from a `coroutine`. + + If this exception is raised, its value argument is used as the + result of the coroutine:: + + @gen.coroutine + def fetch_json(url): + response = yield AsyncHTTPClient().fetch(url) + raise gen.Return(json_decode(response.body)) + + In Python 3.3, this exception is no longer necessary: the ``return`` + statement can be used directly to return a value (previously + ``yield`` and ``return`` with a value could not be combined in the + same function). + + By analogy with the return statement, the value argument is optional, + but it is never necessary to ``raise gen.Return()``. The ``return`` + statement can be used with no arguments instead. + """ + + def __init__(self, value: Any = None) -> None: + super().__init__() + self.value = value + # Cython recognizes subclasses of StopIteration with a .args tuple. + self.args = (value,) + + +class WaitIterator(object): + """Provides an iterator to yield the results of awaitables as they finish. + + Yielding a set of awaitables like this: + + ``results = yield [awaitable1, awaitable2]`` + + pauses the coroutine until both ``awaitable1`` and ``awaitable2`` + return, and then restarts the coroutine with the results of both + awaitables. If either awaitable raises an exception, the + expression will raise that exception and all the results will be + lost. + + If you need to get the result of each awaitable as soon as possible, + or if you need the result of some awaitables even if others produce + errors, you can use ``WaitIterator``:: + + wait_iterator = gen.WaitIterator(awaitable1, awaitable2) + while not wait_iterator.done(): + try: + result = yield wait_iterator.next() + except Exception as e: + print("Error {} from {}".format(e, wait_iterator.current_future)) + else: + print("Result {} received from {} at {}".format( + result, wait_iterator.current_future, + wait_iterator.current_index)) + + Because results are returned as soon as they are available the + output from the iterator *will not be in the same order as the + input arguments*. If you need to know which future produced the + current result, you can use the attributes + ``WaitIterator.current_future``, or ``WaitIterator.current_index`` + to get the index of the awaitable from the input list. (if keyword + arguments were used in the construction of the `WaitIterator`, + ``current_index`` will use the corresponding keyword). + + On Python 3.5, `WaitIterator` implements the async iterator + protocol, so it can be used with the ``async for`` statement (note + that in this version the entire iteration is aborted if any value + raises an exception, while the previous example can continue past + individual errors):: + + async for result in gen.WaitIterator(future1, future2): + print("Result {} received from {} at {}".format( + result, wait_iterator.current_future, + wait_iterator.current_index)) + + .. versionadded:: 4.1 + + .. versionchanged:: 4.3 + Added ``async for`` support in Python 3.5. + + """ + + _unfinished = {} # type: Dict[Future, Union[int, str]] + + def __init__(self, *args: Future, **kwargs: Future) -> None: + if args and kwargs: + raise ValueError("You must provide args or kwargs, not both") + + if kwargs: + self._unfinished = dict((f, k) for (k, f) in kwargs.items()) + futures = list(kwargs.values()) # type: Sequence[Future] + else: + self._unfinished = dict((f, i) for (i, f) in enumerate(args)) + futures = args + + self._finished = collections.deque() # type: Deque[Future] + self.current_index = None # type: Optional[Union[str, int]] + self.current_future = None # type: Optional[Future] + self._running_future = None # type: Optional[Future] + + for future in futures: + future_add_done_callback(future, self._done_callback) + + def done(self) -> bool: + """Returns True if this iterator has no more results.""" + if self._finished or self._unfinished: + return False + # Clear the 'current' values when iteration is done. + self.current_index = self.current_future = None + return True + + def next(self) -> Future: + """Returns a `.Future` that will yield the next available result. + + Note that this `.Future` will not be the same object as any of + the inputs. + """ + self._running_future = Future() + + if self._finished: + self._return_result(self._finished.popleft()) + + return self._running_future + + def _done_callback(self, done: Future) -> None: + if self._running_future and not self._running_future.done(): + self._return_result(done) + else: + self._finished.append(done) + + def _return_result(self, done: Future) -> None: + """Called set the returned future's state that of the future + we yielded, and set the current future for the iterator. + """ + if self._running_future is None: + raise Exception("no future is running") + chain_future(done, self._running_future) + + self.current_future = done + self.current_index = self._unfinished.pop(done) + + def __aiter__(self) -> typing.AsyncIterator: + return self + + def __anext__(self) -> Future: + if self.done(): + # Lookup by name to silence pyflakes on older versions. + raise getattr(builtins, "StopAsyncIteration")() + return self.next() + + +def multi( + children: Union[List[_Yieldable], Dict[Any, _Yieldable]], + quiet_exceptions: "Union[Type[Exception], Tuple[Type[Exception], ...]]" = (), +) -> "Union[Future[List], Future[Dict]]": + """Runs multiple asynchronous operations in parallel. + + ``children`` may either be a list or a dict whose values are + yieldable objects. ``multi()`` returns a new yieldable + object that resolves to a parallel structure containing their + results. If ``children`` is a list, the result is a list of + results in the same order; if it is a dict, the result is a dict + with the same keys. + + That is, ``results = yield multi(list_of_futures)`` is equivalent + to:: + + results = [] + for future in list_of_futures: + results.append(yield future) + + If any children raise exceptions, ``multi()`` will raise the first + one. All others will be logged, unless they are of types + contained in the ``quiet_exceptions`` argument. + + In a ``yield``-based coroutine, it is not normally necessary to + call this function directly, since the coroutine runner will + do it automatically when a list or dict is yielded. However, + it is necessary in ``await``-based coroutines, or to pass + the ``quiet_exceptions`` argument. + + This function is available under the names ``multi()`` and ``Multi()`` + for historical reasons. + + Cancelling a `.Future` returned by ``multi()`` does not cancel its + children. `asyncio.gather` is similar to ``multi()``, but it does + cancel its children. + + .. versionchanged:: 4.2 + If multiple yieldables fail, any exceptions after the first + (which is raised) will be logged. Added the ``quiet_exceptions`` + argument to suppress this logging for selected exception types. + + .. versionchanged:: 4.3 + Replaced the class ``Multi`` and the function ``multi_future`` + with a unified function ``multi``. Added support for yieldables + other than ``YieldPoint`` and `.Future`. + + """ + return multi_future(children, quiet_exceptions=quiet_exceptions) + + +Multi = multi + + +def multi_future( + children: Union[List[_Yieldable], Dict[Any, _Yieldable]], + quiet_exceptions: "Union[Type[Exception], Tuple[Type[Exception], ...]]" = (), +) -> "Union[Future[List], Future[Dict]]": + """Wait for multiple asynchronous futures in parallel. + + Since Tornado 6.0, this function is exactly the same as `multi`. + + .. versionadded:: 4.0 + + .. versionchanged:: 4.2 + If multiple ``Futures`` fail, any exceptions after the first (which is + raised) will be logged. Added the ``quiet_exceptions`` + argument to suppress this logging for selected exception types. + + .. deprecated:: 4.3 + Use `multi` instead. + """ + if isinstance(children, dict): + keys = list(children.keys()) # type: Optional[List] + children_seq = children.values() # type: Iterable + else: + keys = None + children_seq = children + children_futs = list(map(convert_yielded, children_seq)) + assert all(is_future(i) or isinstance(i, _NullFuture) for i in children_futs) + unfinished_children = set(children_futs) + + future = _create_future() + if not children_futs: + future_set_result_unless_cancelled(future, {} if keys is not None else []) + + def callback(fut: Future) -> None: + unfinished_children.remove(fut) + if not unfinished_children: + result_list = [] + for f in children_futs: + try: + result_list.append(f.result()) + except Exception as e: + if future.done(): + if not isinstance(e, quiet_exceptions): + app_log.error( + "Multiple exceptions in yield list", exc_info=True + ) + else: + future_set_exc_info(future, sys.exc_info()) + if not future.done(): + if keys is not None: + future_set_result_unless_cancelled( + future, dict(zip(keys, result_list)) + ) + else: + future_set_result_unless_cancelled(future, result_list) + + listening = set() # type: Set[Future] + for f in children_futs: + if f not in listening: + listening.add(f) + future_add_done_callback(f, callback) + return future + + +def maybe_future(x: Any) -> Future: + """Converts ``x`` into a `.Future`. + + If ``x`` is already a `.Future`, it is simply returned; otherwise + it is wrapped in a new `.Future`. This is suitable for use as + ``result = yield gen.maybe_future(f())`` when you don't know whether + ``f()`` returns a `.Future` or not. + + .. deprecated:: 4.3 + This function only handles ``Futures``, not other yieldable objects. + Instead of `maybe_future`, check for the non-future result types + you expect (often just ``None``), and ``yield`` anything unknown. + """ + if is_future(x): + return x + else: + fut = _create_future() + fut.set_result(x) + return fut + + +def with_timeout( + timeout: Union[float, datetime.timedelta], + future: _Yieldable, + quiet_exceptions: "Union[Type[Exception], Tuple[Type[Exception], ...]]" = (), +) -> Future: + """Wraps a `.Future` (or other yieldable object) in a timeout. + + Raises `tornado.util.TimeoutError` if the input future does not + complete before ``timeout``, which may be specified in any form + allowed by `.IOLoop.add_timeout` (i.e. a `datetime.timedelta` or + an absolute time relative to `.IOLoop.time`) + + If the wrapped `.Future` fails after it has timed out, the exception + will be logged unless it is either of a type contained in + ``quiet_exceptions`` (which may be an exception type or a sequence of + types), or an ``asyncio.CancelledError``. + + The wrapped `.Future` is not canceled when the timeout expires, + permitting it to be reused. `asyncio.wait_for` is similar to this + function but it does cancel the wrapped `.Future` on timeout. + + .. versionadded:: 4.0 + + .. versionchanged:: 4.1 + Added the ``quiet_exceptions`` argument and the logging of unhandled + exceptions. + + .. versionchanged:: 4.4 + Added support for yieldable objects other than `.Future`. + + .. versionchanged:: 6.0.3 + ``asyncio.CancelledError`` is now always considered "quiet". + + """ + # It's tempting to optimize this by cancelling the input future on timeout + # instead of creating a new one, but A) we can't know if we are the only + # one waiting on the input future, so cancelling it might disrupt other + # callers and B) concurrent futures can only be cancelled while they are + # in the queue, so cancellation cannot reliably bound our waiting time. + future_converted = convert_yielded(future) + result = _create_future() + chain_future(future_converted, result) + io_loop = IOLoop.current() + + def error_callback(future: Future) -> None: + try: + future.result() + except asyncio.CancelledError: + pass + except Exception as e: + if not isinstance(e, quiet_exceptions): + app_log.error( + "Exception in Future %r after timeout", future, exc_info=True + ) + + def timeout_callback() -> None: + if not result.done(): + result.set_exception(TimeoutError("Timeout")) + # In case the wrapped future goes on to fail, log it. + future_add_done_callback(future_converted, error_callback) + + timeout_handle = io_loop.add_timeout(timeout, timeout_callback) + if isinstance(future_converted, Future): + # We know this future will resolve on the IOLoop, so we don't + # need the extra thread-safety of IOLoop.add_future (and we also + # don't care about StackContext here. + future_add_done_callback( + future_converted, lambda future: io_loop.remove_timeout(timeout_handle) + ) + else: + # concurrent.futures.Futures may resolve on any thread, so we + # need to route them back to the IOLoop. + io_loop.add_future( + future_converted, lambda future: io_loop.remove_timeout(timeout_handle) + ) + return result + + +def sleep(duration: float) -> "Future[None]": + """Return a `.Future` that resolves after the given number of seconds. + + When used with ``yield`` in a coroutine, this is a non-blocking + analogue to `time.sleep` (which should not be used in coroutines + because it is blocking):: + + yield gen.sleep(0.5) + + Note that calling this function on its own does nothing; you must + wait on the `.Future` it returns (usually by yielding it). + + .. versionadded:: 4.1 + """ + f = _create_future() + IOLoop.current().call_later( + duration, lambda: future_set_result_unless_cancelled(f, None) + ) + return f + + +class _NullFuture(object): + """_NullFuture resembles a Future that finished with a result of None. + + It's not actually a `Future` to avoid depending on a particular event loop. + Handled as a special case in the coroutine runner. + + We lie and tell the type checker that a _NullFuture is a Future so + we don't have to leak _NullFuture into lots of public APIs. But + this means that the type checker can't warn us when we're passing + a _NullFuture into a code path that doesn't understand what to do + with it. + """ + + def result(self) -> None: + return None + + def done(self) -> bool: + return True + + +# _null_future is used as a dummy value in the coroutine runner. It differs +# from moment in that moment always adds a delay of one IOLoop iteration +# while _null_future is processed as soon as possible. +_null_future = typing.cast(Future, _NullFuture()) + +moment = typing.cast(Future, _NullFuture()) +moment.__doc__ = """A special object which may be yielded to allow the IOLoop to run for +one iteration. + +This is not needed in normal use but it can be helpful in long-running +coroutines that are likely to yield Futures that are ready instantly. + +Usage: ``yield gen.moment`` + +In native coroutines, the equivalent of ``yield gen.moment`` is +``await asyncio.sleep(0)``. + +.. versionadded:: 4.0 + +.. deprecated:: 4.5 + ``yield None`` (or ``yield`` with no argument) is now equivalent to + ``yield gen.moment``. +""" + + +class Runner(object): + """Internal implementation of `tornado.gen.coroutine`. + + Maintains information about pending callbacks and their results. + + The results of the generator are stored in ``result_future`` (a + `.Future`) + """ + + def __init__( + self, + ctx_run: Callable, + gen: "Generator[_Yieldable, Any, _T]", + result_future: "Future[_T]", + first_yielded: _Yieldable, + ) -> None: + self.ctx_run = ctx_run + self.gen = gen + self.result_future = result_future + self.future = _null_future # type: Union[None, Future] + self.running = False + self.finished = False + self.io_loop = IOLoop.current() + if self.handle_yield(first_yielded): + gen = result_future = first_yielded = None # type: ignore + self.ctx_run(self.run) + + def run(self) -> None: + """Starts or resumes the generator, running until it reaches a + yield point that is not ready. + """ + if self.running or self.finished: + return + try: + self.running = True + while True: + future = self.future + if future is None: + raise Exception("No pending future") + if not future.done(): + return + self.future = None + try: + exc_info = None + + try: + value = future.result() + except Exception: + exc_info = sys.exc_info() + future = None + + if exc_info is not None: + try: + yielded = self.gen.throw(*exc_info) # type: ignore + finally: + # Break up a reference to itself + # for faster GC on CPython. + exc_info = None + else: + yielded = self.gen.send(value) + + except (StopIteration, Return) as e: + self.finished = True + self.future = _null_future + future_set_result_unless_cancelled( + self.result_future, _value_from_stopiteration(e) + ) + self.result_future = None # type: ignore + return + except Exception: + self.finished = True + self.future = _null_future + future_set_exc_info(self.result_future, sys.exc_info()) + self.result_future = None # type: ignore + return + if not self.handle_yield(yielded): + return + yielded = None + finally: + self.running = False + + def handle_yield(self, yielded: _Yieldable) -> bool: + try: + self.future = convert_yielded(yielded) + except BadYieldError: + self.future = Future() + future_set_exc_info(self.future, sys.exc_info()) + + if self.future is moment: + self.io_loop.add_callback(self.ctx_run, self.run) + return False + elif self.future is None: + raise Exception("no pending future") + elif not self.future.done(): + + def inner(f: Any) -> None: + # Break a reference cycle to speed GC. + f = None # noqa: F841 + self.ctx_run(self.run) + + self.io_loop.add_future(self.future, inner) + return False + return True + + def handle_exception( + self, typ: Type[Exception], value: Exception, tb: types.TracebackType + ) -> bool: + if not self.running and not self.finished: + self.future = Future() + future_set_exc_info(self.future, (typ, value, tb)) + self.ctx_run(self.run) + return True + else: + return False + + +# Convert Awaitables into Futures. +try: + _wrap_awaitable = asyncio.ensure_future +except AttributeError: + # asyncio.ensure_future was introduced in Python 3.4.4, but + # Debian jessie still ships with 3.4.2 so try the old name. + _wrap_awaitable = getattr(asyncio, "async") + + +def convert_yielded(yielded: _Yieldable) -> Future: + """Convert a yielded object into a `.Future`. + + The default implementation accepts lists, dictionaries, and + Futures. This has the side effect of starting any coroutines that + did not start themselves, similar to `asyncio.ensure_future`. + + If the `~functools.singledispatch` library is available, this function + may be extended to support additional types. For example:: + + @convert_yielded.register(asyncio.Future) + def _(asyncio_future): + return tornado.platform.asyncio.to_tornado_future(asyncio_future) + + .. versionadded:: 4.1 + + """ + if yielded is None or yielded is moment: + return moment + elif yielded is _null_future: + return _null_future + elif isinstance(yielded, (list, dict)): + return multi(yielded) # type: ignore + elif is_future(yielded): + return typing.cast(Future, yielded) + elif isawaitable(yielded): + return _wrap_awaitable(yielded) # type: ignore + else: + raise BadYieldError("yielded unknown object %r" % (yielded,)) + + +convert_yielded = singledispatch(convert_yielded) diff --git a/venv/lib/python3.8/site-packages/tornado/http1connection.py b/venv/lib/python3.8/site-packages/tornado/http1connection.py new file mode 100644 index 0000000..835027b --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/http1connection.py @@ -0,0 +1,842 @@ +# +# Copyright 2014 Facebook +# +# 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. + +"""Client and server implementations of HTTP/1.x. + +.. versionadded:: 4.0 +""" + +import asyncio +import logging +import re +import types + +from tornado.concurrent import ( + Future, + future_add_done_callback, + future_set_result_unless_cancelled, +) +from tornado.escape import native_str, utf8 +from tornado import gen +from tornado import httputil +from tornado import iostream +from tornado.log import gen_log, app_log +from tornado.util import GzipDecompressor + + +from typing import cast, Optional, Type, Awaitable, Callable, Union, Tuple + + +class _QuietException(Exception): + def __init__(self) -> None: + pass + + +class _ExceptionLoggingContext(object): + """Used with the ``with`` statement when calling delegate methods to + log any exceptions with the given logger. Any exceptions caught are + converted to _QuietException + """ + + def __init__(self, logger: logging.Logger) -> None: + self.logger = logger + + def __enter__(self) -> None: + pass + + def __exit__( + self, + typ: "Optional[Type[BaseException]]", + value: Optional[BaseException], + tb: types.TracebackType, + ) -> None: + if value is not None: + assert typ is not None + self.logger.error("Uncaught exception", exc_info=(typ, value, tb)) + raise _QuietException + + +class HTTP1ConnectionParameters(object): + """Parameters for `.HTTP1Connection` and `.HTTP1ServerConnection`. + """ + + def __init__( + self, + no_keep_alive: bool = False, + chunk_size: Optional[int] = None, + max_header_size: Optional[int] = None, + header_timeout: Optional[float] = None, + max_body_size: Optional[int] = None, + body_timeout: Optional[float] = None, + decompress: bool = False, + ) -> None: + """ + :arg bool no_keep_alive: If true, always close the connection after + one request. + :arg int chunk_size: how much data to read into memory at once + :arg int max_header_size: maximum amount of data for HTTP headers + :arg float header_timeout: how long to wait for all headers (seconds) + :arg int max_body_size: maximum amount of data for body + :arg float body_timeout: how long to wait while reading body (seconds) + :arg bool decompress: if true, decode incoming + ``Content-Encoding: gzip`` + """ + self.no_keep_alive = no_keep_alive + self.chunk_size = chunk_size or 65536 + self.max_header_size = max_header_size or 65536 + self.header_timeout = header_timeout + self.max_body_size = max_body_size + self.body_timeout = body_timeout + self.decompress = decompress + + +class HTTP1Connection(httputil.HTTPConnection): + """Implements the HTTP/1.x protocol. + + This class can be on its own for clients, or via `HTTP1ServerConnection` + for servers. + """ + + def __init__( + self, + stream: iostream.IOStream, + is_client: bool, + params: Optional[HTTP1ConnectionParameters] = None, + context: Optional[object] = None, + ) -> None: + """ + :arg stream: an `.IOStream` + :arg bool is_client: client or server + :arg params: a `.HTTP1ConnectionParameters` instance or ``None`` + :arg context: an opaque application-defined object that can be accessed + as ``connection.context``. + """ + self.is_client = is_client + self.stream = stream + if params is None: + params = HTTP1ConnectionParameters() + self.params = params + self.context = context + self.no_keep_alive = params.no_keep_alive + # The body limits can be altered by the delegate, so save them + # here instead of just referencing self.params later. + self._max_body_size = self.params.max_body_size or self.stream.max_buffer_size + self._body_timeout = self.params.body_timeout + # _write_finished is set to True when finish() has been called, + # i.e. there will be no more data sent. Data may still be in the + # stream's write buffer. + self._write_finished = False + # True when we have read the entire incoming body. + self._read_finished = False + # _finish_future resolves when all data has been written and flushed + # to the IOStream. + self._finish_future = Future() # type: Future[None] + # If true, the connection should be closed after this request + # (after the response has been written in the server side, + # and after it has been read in the client) + self._disconnect_on_finish = False + self._clear_callbacks() + # Save the start lines after we read or write them; they + # affect later processing (e.g. 304 responses and HEAD methods + # have content-length but no bodies) + self._request_start_line = None # type: Optional[httputil.RequestStartLine] + self._response_start_line = None # type: Optional[httputil.ResponseStartLine] + self._request_headers = None # type: Optional[httputil.HTTPHeaders] + # True if we are writing output with chunked encoding. + self._chunking_output = False + # While reading a body with a content-length, this is the + # amount left to read. + self._expected_content_remaining = None # type: Optional[int] + # A Future for our outgoing writes, returned by IOStream.write. + self._pending_write = None # type: Optional[Future[None]] + + def read_response(self, delegate: httputil.HTTPMessageDelegate) -> Awaitable[bool]: + """Read a single HTTP response. + + Typical client-mode usage is to write a request using `write_headers`, + `write`, and `finish`, and then call ``read_response``. + + :arg delegate: a `.HTTPMessageDelegate` + + Returns a `.Future` that resolves to a bool after the full response has + been read. The result is true if the stream is still open. + """ + if self.params.decompress: + delegate = _GzipMessageDelegate(delegate, self.params.chunk_size) + return self._read_message(delegate) + + async def _read_message(self, delegate: httputil.HTTPMessageDelegate) -> bool: + need_delegate_close = False + try: + header_future = self.stream.read_until_regex( + b"\r?\n\r?\n", max_bytes=self.params.max_header_size + ) + if self.params.header_timeout is None: + header_data = await header_future + else: + try: + header_data = await gen.with_timeout( + self.stream.io_loop.time() + self.params.header_timeout, + header_future, + quiet_exceptions=iostream.StreamClosedError, + ) + except gen.TimeoutError: + self.close() + return False + start_line_str, headers = self._parse_headers(header_data) + if self.is_client: + resp_start_line = httputil.parse_response_start_line(start_line_str) + self._response_start_line = resp_start_line + start_line = ( + resp_start_line + ) # type: Union[httputil.RequestStartLine, httputil.ResponseStartLine] + # TODO: this will need to change to support client-side keepalive + self._disconnect_on_finish = False + else: + req_start_line = httputil.parse_request_start_line(start_line_str) + self._request_start_line = req_start_line + self._request_headers = headers + start_line = req_start_line + self._disconnect_on_finish = not self._can_keep_alive( + req_start_line, headers + ) + need_delegate_close = True + with _ExceptionLoggingContext(app_log): + header_recv_future = delegate.headers_received(start_line, headers) + if header_recv_future is not None: + await header_recv_future + if self.stream is None: + # We've been detached. + need_delegate_close = False + return False + skip_body = False + if self.is_client: + assert isinstance(start_line, httputil.ResponseStartLine) + if ( + self._request_start_line is not None + and self._request_start_line.method == "HEAD" + ): + skip_body = True + code = start_line.code + if code == 304: + # 304 responses may include the content-length header + # but do not actually have a body. + # http://tools.ietf.org/html/rfc7230#section-3.3 + skip_body = True + if 100 <= code < 200: + # 1xx responses should never indicate the presence of + # a body. + if "Content-Length" in headers or "Transfer-Encoding" in headers: + raise httputil.HTTPInputError( + "Response code %d cannot have body" % code + ) + # TODO: client delegates will get headers_received twice + # in the case of a 100-continue. Document or change? + await self._read_message(delegate) + else: + if headers.get("Expect") == "100-continue" and not self._write_finished: + self.stream.write(b"HTTP/1.1 100 (Continue)\r\n\r\n") + if not skip_body: + body_future = self._read_body( + resp_start_line.code if self.is_client else 0, headers, delegate + ) + if body_future is not None: + if self._body_timeout is None: + await body_future + else: + try: + await gen.with_timeout( + self.stream.io_loop.time() + self._body_timeout, + body_future, + quiet_exceptions=iostream.StreamClosedError, + ) + except gen.TimeoutError: + gen_log.info("Timeout reading body from %s", self.context) + self.stream.close() + return False + self._read_finished = True + if not self._write_finished or self.is_client: + need_delegate_close = False + with _ExceptionLoggingContext(app_log): + delegate.finish() + # If we're waiting for the application to produce an asynchronous + # response, and we're not detached, register a close callback + # on the stream (we didn't need one while we were reading) + if ( + not self._finish_future.done() + and self.stream is not None + and not self.stream.closed() + ): + self.stream.set_close_callback(self._on_connection_close) + await self._finish_future + if self.is_client and self._disconnect_on_finish: + self.close() + if self.stream is None: + return False + except httputil.HTTPInputError as e: + gen_log.info("Malformed HTTP message from %s: %s", self.context, e) + if not self.is_client: + await self.stream.write(b"HTTP/1.1 400 Bad Request\r\n\r\n") + self.close() + return False + finally: + if need_delegate_close: + with _ExceptionLoggingContext(app_log): + delegate.on_connection_close() + header_future = None # type: ignore + self._clear_callbacks() + return True + + def _clear_callbacks(self) -> None: + """Clears the callback attributes. + + This allows the request handler to be garbage collected more + quickly in CPython by breaking up reference cycles. + """ + self._write_callback = None + self._write_future = None # type: Optional[Future[None]] + self._close_callback = None # type: Optional[Callable[[], None]] + if self.stream is not None: + self.stream.set_close_callback(None) + + def set_close_callback(self, callback: Optional[Callable[[], None]]) -> None: + """Sets a callback that will be run when the connection is closed. + + Note that this callback is slightly different from + `.HTTPMessageDelegate.on_connection_close`: The + `.HTTPMessageDelegate` method is called when the connection is + closed while receiving a message. This callback is used when + there is not an active delegate (for example, on the server + side this callback is used if the client closes the connection + after sending its request but before receiving all the + response. + """ + self._close_callback = callback + + def _on_connection_close(self) -> None: + # Note that this callback is only registered on the IOStream + # when we have finished reading the request and are waiting for + # the application to produce its response. + if self._close_callback is not None: + callback = self._close_callback + self._close_callback = None + callback() + if not self._finish_future.done(): + future_set_result_unless_cancelled(self._finish_future, None) + self._clear_callbacks() + + def close(self) -> None: + if self.stream is not None: + self.stream.close() + self._clear_callbacks() + if not self._finish_future.done(): + future_set_result_unless_cancelled(self._finish_future, None) + + def detach(self) -> iostream.IOStream: + """Take control of the underlying stream. + + Returns the underlying `.IOStream` object and stops all further + HTTP processing. May only be called during + `.HTTPMessageDelegate.headers_received`. Intended for implementing + protocols like websockets that tunnel over an HTTP handshake. + """ + self._clear_callbacks() + stream = self.stream + self.stream = None # type: ignore + if not self._finish_future.done(): + future_set_result_unless_cancelled(self._finish_future, None) + return stream + + def set_body_timeout(self, timeout: float) -> None: + """Sets the body timeout for a single request. + + Overrides the value from `.HTTP1ConnectionParameters`. + """ + self._body_timeout = timeout + + def set_max_body_size(self, max_body_size: int) -> None: + """Sets the body size limit for a single request. + + Overrides the value from `.HTTP1ConnectionParameters`. + """ + self._max_body_size = max_body_size + + def write_headers( + self, + start_line: Union[httputil.RequestStartLine, httputil.ResponseStartLine], + headers: httputil.HTTPHeaders, + chunk: Optional[bytes] = None, + ) -> "Future[None]": + """Implements `.HTTPConnection.write_headers`.""" + lines = [] + if self.is_client: + assert isinstance(start_line, httputil.RequestStartLine) + self._request_start_line = start_line + lines.append(utf8("%s %s HTTP/1.1" % (start_line[0], start_line[1]))) + # Client requests with a non-empty body must have either a + # Content-Length or a Transfer-Encoding. + self._chunking_output = ( + start_line.method in ("POST", "PUT", "PATCH") + and "Content-Length" not in headers + and ( + "Transfer-Encoding" not in headers + or headers["Transfer-Encoding"] == "chunked" + ) + ) + else: + assert isinstance(start_line, httputil.ResponseStartLine) + assert self._request_start_line is not None + assert self._request_headers is not None + self._response_start_line = start_line + lines.append(utf8("HTTP/1.1 %d %s" % (start_line[1], start_line[2]))) + self._chunking_output = ( + # TODO: should this use + # self._request_start_line.version or + # start_line.version? + self._request_start_line.version == "HTTP/1.1" + # Omit payload header field for HEAD request. + and self._request_start_line.method != "HEAD" + # 1xx, 204 and 304 responses have no body (not even a zero-length + # body), and so should not have either Content-Length or + # Transfer-Encoding headers. + and start_line.code not in (204, 304) + and (start_line.code < 100 or start_line.code >= 200) + # No need to chunk the output if a Content-Length is specified. + and "Content-Length" not in headers + # Applications are discouraged from touching Transfer-Encoding, + # but if they do, leave it alone. + and "Transfer-Encoding" not in headers + ) + # If connection to a 1.1 client will be closed, inform client + if ( + self._request_start_line.version == "HTTP/1.1" + and self._disconnect_on_finish + ): + headers["Connection"] = "close" + # If a 1.0 client asked for keep-alive, add the header. + if ( + self._request_start_line.version == "HTTP/1.0" + and self._request_headers.get("Connection", "").lower() == "keep-alive" + ): + headers["Connection"] = "Keep-Alive" + if self._chunking_output: + headers["Transfer-Encoding"] = "chunked" + if not self.is_client and ( + self._request_start_line.method == "HEAD" + or cast(httputil.ResponseStartLine, start_line).code == 304 + ): + self._expected_content_remaining = 0 + elif "Content-Length" in headers: + self._expected_content_remaining = int(headers["Content-Length"]) + else: + self._expected_content_remaining = None + # TODO: headers are supposed to be of type str, but we still have some + # cases that let bytes slip through. Remove these native_str calls when those + # are fixed. + header_lines = ( + native_str(n) + ": " + native_str(v) for n, v in headers.get_all() + ) + lines.extend(line.encode("latin1") for line in header_lines) + for line in lines: + if b"\n" in line: + raise ValueError("Newline in header: " + repr(line)) + future = None + if self.stream.closed(): + future = self._write_future = Future() + future.set_exception(iostream.StreamClosedError()) + future.exception() + else: + future = self._write_future = Future() + data = b"\r\n".join(lines) + b"\r\n\r\n" + if chunk: + data += self._format_chunk(chunk) + self._pending_write = self.stream.write(data) + future_add_done_callback(self._pending_write, self._on_write_complete) + return future + + def _format_chunk(self, chunk: bytes) -> bytes: + if self._expected_content_remaining is not None: + self._expected_content_remaining -= len(chunk) + if self._expected_content_remaining < 0: + # Close the stream now to stop further framing errors. + self.stream.close() + raise httputil.HTTPOutputError( + "Tried to write more data than Content-Length" + ) + if self._chunking_output and chunk: + # Don't write out empty chunks because that means END-OF-STREAM + # with chunked encoding + return utf8("%x" % len(chunk)) + b"\r\n" + chunk + b"\r\n" + else: + return chunk + + def write(self, chunk: bytes) -> "Future[None]": + """Implements `.HTTPConnection.write`. + + For backwards compatibility it is allowed but deprecated to + skip `write_headers` and instead call `write()` with a + pre-encoded header block. + """ + future = None + if self.stream.closed(): + future = self._write_future = Future() + self._write_future.set_exception(iostream.StreamClosedError()) + self._write_future.exception() + else: + future = self._write_future = Future() + self._pending_write = self.stream.write(self._format_chunk(chunk)) + future_add_done_callback(self._pending_write, self._on_write_complete) + return future + + def finish(self) -> None: + """Implements `.HTTPConnection.finish`.""" + if ( + self._expected_content_remaining is not None + and self._expected_content_remaining != 0 + and not self.stream.closed() + ): + self.stream.close() + raise httputil.HTTPOutputError( + "Tried to write %d bytes less than Content-Length" + % self._expected_content_remaining + ) + if self._chunking_output: + if not self.stream.closed(): + self._pending_write = self.stream.write(b"0\r\n\r\n") + self._pending_write.add_done_callback(self._on_write_complete) + self._write_finished = True + # If the app finished the request while we're still reading, + # divert any remaining data away from the delegate and + # close the connection when we're done sending our response. + # Closing the connection is the only way to avoid reading the + # whole input body. + if not self._read_finished: + self._disconnect_on_finish = True + # No more data is coming, so instruct TCP to send any remaining + # data immediately instead of waiting for a full packet or ack. + self.stream.set_nodelay(True) + if self._pending_write is None: + self._finish_request(None) + else: + future_add_done_callback(self._pending_write, self._finish_request) + + def _on_write_complete(self, future: "Future[None]") -> None: + exc = future.exception() + if exc is not None and not isinstance(exc, iostream.StreamClosedError): + future.result() + if self._write_callback is not None: + callback = self._write_callback + self._write_callback = None + self.stream.io_loop.add_callback(callback) + if self._write_future is not None: + future = self._write_future + self._write_future = None + future_set_result_unless_cancelled(future, None) + + def _can_keep_alive( + self, start_line: httputil.RequestStartLine, headers: httputil.HTTPHeaders + ) -> bool: + if self.params.no_keep_alive: + return False + connection_header = headers.get("Connection") + if connection_header is not None: + connection_header = connection_header.lower() + if start_line.version == "HTTP/1.1": + return connection_header != "close" + elif ( + "Content-Length" in headers + or headers.get("Transfer-Encoding", "").lower() == "chunked" + or getattr(start_line, "method", None) in ("HEAD", "GET") + ): + # start_line may be a request or response start line; only + # the former has a method attribute. + return connection_header == "keep-alive" + return False + + def _finish_request(self, future: "Optional[Future[None]]") -> None: + self._clear_callbacks() + if not self.is_client and self._disconnect_on_finish: + self.close() + return + # Turn Nagle's algorithm back on, leaving the stream in its + # default state for the next request. + self.stream.set_nodelay(False) + if not self._finish_future.done(): + future_set_result_unless_cancelled(self._finish_future, None) + + def _parse_headers(self, data: bytes) -> Tuple[str, httputil.HTTPHeaders]: + # The lstrip removes newlines that some implementations sometimes + # insert between messages of a reused connection. Per RFC 7230, + # we SHOULD ignore at least one empty line before the request. + # http://tools.ietf.org/html/rfc7230#section-3.5 + data_str = native_str(data.decode("latin1")).lstrip("\r\n") + # RFC 7230 section allows for both CRLF and bare LF. + eol = data_str.find("\n") + start_line = data_str[:eol].rstrip("\r") + headers = httputil.HTTPHeaders.parse(data_str[eol:]) + return start_line, headers + + def _read_body( + self, + code: int, + headers: httputil.HTTPHeaders, + delegate: httputil.HTTPMessageDelegate, + ) -> Optional[Awaitable[None]]: + if "Content-Length" in headers: + if "Transfer-Encoding" in headers: + # Response cannot contain both Content-Length and + # Transfer-Encoding headers. + # http://tools.ietf.org/html/rfc7230#section-3.3.3 + raise httputil.HTTPInputError( + "Response with both Transfer-Encoding and Content-Length" + ) + if "," in headers["Content-Length"]: + # Proxies sometimes cause Content-Length headers to get + # duplicated. If all the values are identical then we can + # use them but if they differ it's an error. + pieces = re.split(r",\s*", headers["Content-Length"]) + if any(i != pieces[0] for i in pieces): + raise httputil.HTTPInputError( + "Multiple unequal Content-Lengths: %r" + % headers["Content-Length"] + ) + headers["Content-Length"] = pieces[0] + + try: + content_length = int(headers["Content-Length"]) # type: Optional[int] + except ValueError: + # Handles non-integer Content-Length value. + raise httputil.HTTPInputError( + "Only integer Content-Length is allowed: %s" + % headers["Content-Length"] + ) + + if cast(int, content_length) > self._max_body_size: + raise httputil.HTTPInputError("Content-Length too long") + else: + content_length = None + + if code == 204: + # This response code is not allowed to have a non-empty body, + # and has an implicit length of zero instead of read-until-close. + # http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.3 + if "Transfer-Encoding" in headers or content_length not in (None, 0): + raise httputil.HTTPInputError( + "Response with code %d should not have body" % code + ) + content_length = 0 + + if content_length is not None: + return self._read_fixed_body(content_length, delegate) + if headers.get("Transfer-Encoding", "").lower() == "chunked": + return self._read_chunked_body(delegate) + if self.is_client: + return self._read_body_until_close(delegate) + return None + + async def _read_fixed_body( + self, content_length: int, delegate: httputil.HTTPMessageDelegate + ) -> None: + while content_length > 0: + body = await self.stream.read_bytes( + min(self.params.chunk_size, content_length), partial=True + ) + content_length -= len(body) + if not self._write_finished or self.is_client: + with _ExceptionLoggingContext(app_log): + ret = delegate.data_received(body) + if ret is not None: + await ret + + async def _read_chunked_body(self, delegate: httputil.HTTPMessageDelegate) -> None: + # TODO: "chunk extensions" http://tools.ietf.org/html/rfc2616#section-3.6.1 + total_size = 0 + while True: + chunk_len_str = await self.stream.read_until(b"\r\n", max_bytes=64) + chunk_len = int(chunk_len_str.strip(), 16) + if chunk_len == 0: + crlf = await self.stream.read_bytes(2) + if crlf != b"\r\n": + raise httputil.HTTPInputError( + "improperly terminated chunked request" + ) + return + total_size += chunk_len + if total_size > self._max_body_size: + raise httputil.HTTPInputError("chunked body too large") + bytes_to_read = chunk_len + while bytes_to_read: + chunk = await self.stream.read_bytes( + min(bytes_to_read, self.params.chunk_size), partial=True + ) + bytes_to_read -= len(chunk) + if not self._write_finished or self.is_client: + with _ExceptionLoggingContext(app_log): + ret = delegate.data_received(chunk) + if ret is not None: + await ret + # chunk ends with \r\n + crlf = await self.stream.read_bytes(2) + assert crlf == b"\r\n" + + async def _read_body_until_close( + self, delegate: httputil.HTTPMessageDelegate + ) -> None: + body = await self.stream.read_until_close() + if not self._write_finished or self.is_client: + with _ExceptionLoggingContext(app_log): + ret = delegate.data_received(body) + if ret is not None: + await ret + + +class _GzipMessageDelegate(httputil.HTTPMessageDelegate): + """Wraps an `HTTPMessageDelegate` to decode ``Content-Encoding: gzip``. + """ + + def __init__(self, delegate: httputil.HTTPMessageDelegate, chunk_size: int) -> None: + self._delegate = delegate + self._chunk_size = chunk_size + self._decompressor = None # type: Optional[GzipDecompressor] + + def headers_received( + self, + start_line: Union[httputil.RequestStartLine, httputil.ResponseStartLine], + headers: httputil.HTTPHeaders, + ) -> Optional[Awaitable[None]]: + if headers.get("Content-Encoding") == "gzip": + self._decompressor = GzipDecompressor() + # Downstream delegates will only see uncompressed data, + # so rename the content-encoding header. + # (but note that curl_httpclient doesn't do this). + headers.add("X-Consumed-Content-Encoding", headers["Content-Encoding"]) + del headers["Content-Encoding"] + return self._delegate.headers_received(start_line, headers) + + async def data_received(self, chunk: bytes) -> None: + if self._decompressor: + compressed_data = chunk + while compressed_data: + decompressed = self._decompressor.decompress( + compressed_data, self._chunk_size + ) + if decompressed: + ret = self._delegate.data_received(decompressed) + if ret is not None: + await ret + compressed_data = self._decompressor.unconsumed_tail + if compressed_data and not decompressed: + raise httputil.HTTPInputError( + "encountered unconsumed gzip data without making progress" + ) + else: + ret = self._delegate.data_received(chunk) + if ret is not None: + await ret + + def finish(self) -> None: + if self._decompressor is not None: + tail = self._decompressor.flush() + if tail: + # The tail should always be empty: decompress returned + # all that it can in data_received and the only + # purpose of the flush call is to detect errors such + # as truncated input. If we did legitimately get a new + # chunk at this point we'd need to change the + # interface to make finish() a coroutine. + raise ValueError( + "decompressor.flush returned data; possible truncated input" + ) + return self._delegate.finish() + + def on_connection_close(self) -> None: + return self._delegate.on_connection_close() + + +class HTTP1ServerConnection(object): + """An HTTP/1.x server.""" + + def __init__( + self, + stream: iostream.IOStream, + params: Optional[HTTP1ConnectionParameters] = None, + context: Optional[object] = None, + ) -> None: + """ + :arg stream: an `.IOStream` + :arg params: a `.HTTP1ConnectionParameters` or None + :arg context: an opaque application-defined object that is accessible + as ``connection.context`` + """ + self.stream = stream + if params is None: + params = HTTP1ConnectionParameters() + self.params = params + self.context = context + self._serving_future = None # type: Optional[Future[None]] + + async def close(self) -> None: + """Closes the connection. + + Returns a `.Future` that resolves after the serving loop has exited. + """ + self.stream.close() + # Block until the serving loop is done, but ignore any exceptions + # (start_serving is already responsible for logging them). + assert self._serving_future is not None + try: + await self._serving_future + except Exception: + pass + + def start_serving(self, delegate: httputil.HTTPServerConnectionDelegate) -> None: + """Starts serving requests on this connection. + + :arg delegate: a `.HTTPServerConnectionDelegate` + """ + assert isinstance(delegate, httputil.HTTPServerConnectionDelegate) + fut = gen.convert_yielded(self._server_request_loop(delegate)) + self._serving_future = fut + # Register the future on the IOLoop so its errors get logged. + self.stream.io_loop.add_future(fut, lambda f: f.result()) + + async def _server_request_loop( + self, delegate: httputil.HTTPServerConnectionDelegate + ) -> None: + try: + while True: + conn = HTTP1Connection(self.stream, False, self.params, self.context) + request_delegate = delegate.start_request(self, conn) + try: + ret = await conn.read_response(request_delegate) + except ( + iostream.StreamClosedError, + iostream.UnsatisfiableReadError, + asyncio.CancelledError, + ): + return + except _QuietException: + # This exception was already logged. + conn.close() + return + except Exception: + gen_log.error("Uncaught exception", exc_info=True) + conn.close() + return + if not ret: + return + await asyncio.sleep(0) + finally: + delegate.on_close(self) diff --git a/venv/lib/python3.8/site-packages/tornado/httpclient.py b/venv/lib/python3.8/site-packages/tornado/httpclient.py new file mode 100644 index 0000000..3011c37 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/httpclient.py @@ -0,0 +1,790 @@ +"""Blocking and non-blocking HTTP client interfaces. + +This module defines a common interface shared by two implementations, +``simple_httpclient`` and ``curl_httpclient``. Applications may either +instantiate their chosen implementation class directly or use the +`AsyncHTTPClient` class from this module, which selects an implementation +that can be overridden with the `AsyncHTTPClient.configure` method. + +The default implementation is ``simple_httpclient``, and this is expected +to be suitable for most users' needs. However, some applications may wish +to switch to ``curl_httpclient`` for reasons such as the following: + +* ``curl_httpclient`` has some features not found in ``simple_httpclient``, + including support for HTTP proxies and the ability to use a specified + network interface. + +* ``curl_httpclient`` is more likely to be compatible with sites that are + not-quite-compliant with the HTTP spec, or sites that use little-exercised + features of HTTP. + +* ``curl_httpclient`` is faster. + +Note that if you are using ``curl_httpclient``, it is highly +recommended that you use a recent version of ``libcurl`` and +``pycurl``. Currently the minimum supported version of libcurl is +7.22.0, and the minimum version of pycurl is 7.18.2. It is highly +recommended that your ``libcurl`` installation is built with +asynchronous DNS resolver (threaded or c-ares), otherwise you may +encounter various problems with request timeouts (for more +information, see +http://curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTCONNECTTIMEOUTMS +and comments in curl_httpclient.py). + +To select ``curl_httpclient``, call `AsyncHTTPClient.configure` at startup:: + + AsyncHTTPClient.configure("tornado.curl_httpclient.CurlAsyncHTTPClient") +""" + +import datetime +import functools +from io import BytesIO +import ssl +import time +import weakref + +from tornado.concurrent import ( + Future, + future_set_result_unless_cancelled, + future_set_exception_unless_cancelled, +) +from tornado.escape import utf8, native_str +from tornado import gen, httputil +from tornado.ioloop import IOLoop +from tornado.util import Configurable + +from typing import Type, Any, Union, Dict, Callable, Optional, cast + + +class HTTPClient(object): + """A blocking HTTP client. + + This interface is provided to make it easier to share code between + synchronous and asynchronous applications. Applications that are + running an `.IOLoop` must use `AsyncHTTPClient` instead. + + Typical usage looks like this:: + + http_client = httpclient.HTTPClient() + try: + response = http_client.fetch("http://www.google.com/") + print(response.body) + except httpclient.HTTPError as e: + # HTTPError is raised for non-200 responses; the response + # can be found in e.response. + print("Error: " + str(e)) + except Exception as e: + # Other errors are possible, such as IOError. + print("Error: " + str(e)) + http_client.close() + + .. versionchanged:: 5.0 + + Due to limitations in `asyncio`, it is no longer possible to + use the synchronous ``HTTPClient`` while an `.IOLoop` is running. + Use `AsyncHTTPClient` instead. + + """ + + def __init__( + self, + async_client_class: "Optional[Type[AsyncHTTPClient]]" = None, + **kwargs: Any + ) -> None: + # Initialize self._closed at the beginning of the constructor + # so that an exception raised here doesn't lead to confusing + # failures in __del__. + self._closed = True + self._io_loop = IOLoop(make_current=False) + if async_client_class is None: + async_client_class = AsyncHTTPClient + + # Create the client while our IOLoop is "current", without + # clobbering the thread's real current IOLoop (if any). + async def make_client() -> "AsyncHTTPClient": + await gen.sleep(0) + assert async_client_class is not None + return async_client_class(**kwargs) + + self._async_client = self._io_loop.run_sync(make_client) + self._closed = False + + def __del__(self) -> None: + self.close() + + def close(self) -> None: + """Closes the HTTPClient, freeing any resources used.""" + if not self._closed: + self._async_client.close() + self._io_loop.close() + self._closed = True + + def fetch( + self, request: Union["HTTPRequest", str], **kwargs: Any + ) -> "HTTPResponse": + """Executes a request, returning an `HTTPResponse`. + + The request may be either a string URL or an `HTTPRequest` object. + If it is a string, we construct an `HTTPRequest` using any additional + kwargs: ``HTTPRequest(request, **kwargs)`` + + If an error occurs during the fetch, we raise an `HTTPError` unless + the ``raise_error`` keyword argument is set to False. + """ + response = self._io_loop.run_sync( + functools.partial(self._async_client.fetch, request, **kwargs) + ) + return response + + +class AsyncHTTPClient(Configurable): + """An non-blocking HTTP client. + + Example usage:: + + async def f(): + http_client = AsyncHTTPClient() + try: + response = await http_client.fetch("http://www.google.com") + except Exception as e: + print("Error: %s" % e) + else: + print(response.body) + + The constructor for this class is magic in several respects: It + actually creates an instance of an implementation-specific + subclass, and instances are reused as a kind of pseudo-singleton + (one per `.IOLoop`). The keyword argument ``force_instance=True`` + can be used to suppress this singleton behavior. Unless + ``force_instance=True`` is used, no arguments should be passed to + the `AsyncHTTPClient` constructor. The implementation subclass as + well as arguments to its constructor can be set with the static + method `configure()` + + All `AsyncHTTPClient` implementations support a ``defaults`` + keyword argument, which can be used to set default values for + `HTTPRequest` attributes. For example:: + + AsyncHTTPClient.configure( + None, defaults=dict(user_agent="MyUserAgent")) + # or with force_instance: + client = AsyncHTTPClient(force_instance=True, + defaults=dict(user_agent="MyUserAgent")) + + .. versionchanged:: 5.0 + The ``io_loop`` argument (deprecated since version 4.1) has been removed. + + """ + + _instance_cache = None # type: Dict[IOLoop, AsyncHTTPClient] + + @classmethod + def configurable_base(cls) -> Type[Configurable]: + return AsyncHTTPClient + + @classmethod + def configurable_default(cls) -> Type[Configurable]: + from tornado.simple_httpclient import SimpleAsyncHTTPClient + + return SimpleAsyncHTTPClient + + @classmethod + def _async_clients(cls) -> Dict[IOLoop, "AsyncHTTPClient"]: + attr_name = "_async_client_dict_" + cls.__name__ + if not hasattr(cls, attr_name): + setattr(cls, attr_name, weakref.WeakKeyDictionary()) + return getattr(cls, attr_name) + + def __new__(cls, force_instance: bool = False, **kwargs: Any) -> "AsyncHTTPClient": + io_loop = IOLoop.current() + if force_instance: + instance_cache = None + else: + instance_cache = cls._async_clients() + if instance_cache is not None and io_loop in instance_cache: + return instance_cache[io_loop] + instance = super(AsyncHTTPClient, cls).__new__(cls, **kwargs) # type: ignore + # Make sure the instance knows which cache to remove itself from. + # It can't simply call _async_clients() because we may be in + # __new__(AsyncHTTPClient) but instance.__class__ may be + # SimpleAsyncHTTPClient. + instance._instance_cache = instance_cache + if instance_cache is not None: + instance_cache[instance.io_loop] = instance + return instance + + def initialize(self, defaults: Optional[Dict[str, Any]] = None) -> None: + self.io_loop = IOLoop.current() + self.defaults = dict(HTTPRequest._DEFAULTS) + if defaults is not None: + self.defaults.update(defaults) + self._closed = False + + def close(self) -> None: + """Destroys this HTTP client, freeing any file descriptors used. + + This method is **not needed in normal use** due to the way + that `AsyncHTTPClient` objects are transparently reused. + ``close()`` is generally only necessary when either the + `.IOLoop` is also being closed, or the ``force_instance=True`` + argument was used when creating the `AsyncHTTPClient`. + + No other methods may be called on the `AsyncHTTPClient` after + ``close()``. + + """ + if self._closed: + return + self._closed = True + if self._instance_cache is not None: + cached_val = self._instance_cache.pop(self.io_loop, None) + # If there's an object other than self in the instance + # cache for our IOLoop, something has gotten mixed up. A + # value of None appears to be possible when this is called + # from a destructor (HTTPClient.__del__) as the weakref + # gets cleared before the destructor runs. + if cached_val is not None and cached_val is not self: + raise RuntimeError("inconsistent AsyncHTTPClient cache") + + def fetch( + self, + request: Union[str, "HTTPRequest"], + raise_error: bool = True, + **kwargs: Any + ) -> "Future[HTTPResponse]": + """Executes a request, asynchronously returning an `HTTPResponse`. + + The request may be either a string URL or an `HTTPRequest` object. + If it is a string, we construct an `HTTPRequest` using any additional + kwargs: ``HTTPRequest(request, **kwargs)`` + + This method returns a `.Future` whose result is an + `HTTPResponse`. By default, the ``Future`` will raise an + `HTTPError` if the request returned a non-200 response code + (other errors may also be raised if the server could not be + contacted). Instead, if ``raise_error`` is set to False, the + response will always be returned regardless of the response + code. + + If a ``callback`` is given, it will be invoked with the `HTTPResponse`. + In the callback interface, `HTTPError` is not automatically raised. + Instead, you must check the response's ``error`` attribute or + call its `~HTTPResponse.rethrow` method. + + .. versionchanged:: 6.0 + + The ``callback`` argument was removed. Use the returned + `.Future` instead. + + The ``raise_error=False`` argument only affects the + `HTTPError` raised when a non-200 response code is used, + instead of suppressing all errors. + """ + if self._closed: + raise RuntimeError("fetch() called on closed AsyncHTTPClient") + if not isinstance(request, HTTPRequest): + request = HTTPRequest(url=request, **kwargs) + else: + if kwargs: + raise ValueError( + "kwargs can't be used if request is an HTTPRequest object" + ) + # We may modify this (to add Host, Accept-Encoding, etc), + # so make sure we don't modify the caller's object. This is also + # where normal dicts get converted to HTTPHeaders objects. + request.headers = httputil.HTTPHeaders(request.headers) + request_proxy = _RequestProxy(request, self.defaults) + future = Future() # type: Future[HTTPResponse] + + def handle_response(response: "HTTPResponse") -> None: + if response.error: + if raise_error or not response._error_is_response_code: + future_set_exception_unless_cancelled(future, response.error) + return + future_set_result_unless_cancelled(future, response) + + self.fetch_impl(cast(HTTPRequest, request_proxy), handle_response) + return future + + def fetch_impl( + self, request: "HTTPRequest", callback: Callable[["HTTPResponse"], None] + ) -> None: + raise NotImplementedError() + + @classmethod + def configure( + cls, impl: "Union[None, str, Type[Configurable]]", **kwargs: Any + ) -> None: + """Configures the `AsyncHTTPClient` subclass to use. + + ``AsyncHTTPClient()`` actually creates an instance of a subclass. + This method may be called with either a class object or the + fully-qualified name of such a class (or ``None`` to use the default, + ``SimpleAsyncHTTPClient``) + + If additional keyword arguments are given, they will be passed + to the constructor of each subclass instance created. The + keyword argument ``max_clients`` determines the maximum number + of simultaneous `~AsyncHTTPClient.fetch()` operations that can + execute in parallel on each `.IOLoop`. Additional arguments + may be supported depending on the implementation class in use. + + Example:: + + AsyncHTTPClient.configure("tornado.curl_httpclient.CurlAsyncHTTPClient") + """ + super(AsyncHTTPClient, cls).configure(impl, **kwargs) + + +class HTTPRequest(object): + """HTTP client request object.""" + + _headers = None # type: Union[Dict[str, str], httputil.HTTPHeaders] + + # Default values for HTTPRequest parameters. + # Merged with the values on the request object by AsyncHTTPClient + # implementations. + _DEFAULTS = dict( + connect_timeout=20.0, + request_timeout=20.0, + follow_redirects=True, + max_redirects=5, + decompress_response=True, + proxy_password="", + allow_nonstandard_methods=False, + validate_cert=True, + ) + + def __init__( + self, + url: str, + method: str = "GET", + headers: Optional[Union[Dict[str, str], httputil.HTTPHeaders]] = None, + body: Optional[Union[bytes, str]] = None, + auth_username: Optional[str] = None, + auth_password: Optional[str] = None, + auth_mode: Optional[str] = None, + connect_timeout: Optional[float] = None, + request_timeout: Optional[float] = None, + if_modified_since: Optional[Union[float, datetime.datetime]] = None, + follow_redirects: Optional[bool] = None, + max_redirects: Optional[int] = None, + user_agent: Optional[str] = None, + use_gzip: Optional[bool] = None, + network_interface: Optional[str] = None, + streaming_callback: Optional[Callable[[bytes], None]] = None, + header_callback: Optional[Callable[[str], None]] = None, + prepare_curl_callback: Optional[Callable[[Any], None]] = None, + proxy_host: Optional[str] = None, + proxy_port: Optional[int] = None, + proxy_username: Optional[str] = None, + proxy_password: Optional[str] = None, + proxy_auth_mode: Optional[str] = None, + allow_nonstandard_methods: Optional[bool] = None, + validate_cert: Optional[bool] = None, + ca_certs: Optional[str] = None, + allow_ipv6: Optional[bool] = None, + client_key: Optional[str] = None, + client_cert: Optional[str] = None, + body_producer: Optional[ + Callable[[Callable[[bytes], None]], "Future[None]"] + ] = None, + expect_100_continue: bool = False, + decompress_response: Optional[bool] = None, + ssl_options: Optional[Union[Dict[str, Any], ssl.SSLContext]] = None, + ) -> None: + r"""All parameters except ``url`` are optional. + + :arg str url: URL to fetch + :arg str method: HTTP method, e.g. "GET" or "POST" + :arg headers: Additional HTTP headers to pass on the request + :type headers: `~tornado.httputil.HTTPHeaders` or `dict` + :arg body: HTTP request body as a string (byte or unicode; if unicode + the utf-8 encoding will be used) + :type body: `str` or `bytes` + :arg collections.abc.Callable body_producer: Callable used for + lazy/asynchronous request bodies. + It is called with one argument, a ``write`` function, and should + return a `.Future`. It should call the write function with new + data as it becomes available. The write function returns a + `.Future` which can be used for flow control. + Only one of ``body`` and ``body_producer`` may + be specified. ``body_producer`` is not supported on + ``curl_httpclient``. When using ``body_producer`` it is recommended + to pass a ``Content-Length`` in the headers as otherwise chunked + encoding will be used, and many servers do not support chunked + encoding on requests. New in Tornado 4.0 + :arg str auth_username: Username for HTTP authentication + :arg str auth_password: Password for HTTP authentication + :arg str auth_mode: Authentication mode; default is "basic". + Allowed values are implementation-defined; ``curl_httpclient`` + supports "basic" and "digest"; ``simple_httpclient`` only supports + "basic" + :arg float connect_timeout: Timeout for initial connection in seconds, + default 20 seconds (0 means no timeout) + :arg float request_timeout: Timeout for entire request in seconds, + default 20 seconds (0 means no timeout) + :arg if_modified_since: Timestamp for ``If-Modified-Since`` header + :type if_modified_since: `datetime` or `float` + :arg bool follow_redirects: Should redirects be followed automatically + or return the 3xx response? Default True. + :arg int max_redirects: Limit for ``follow_redirects``, default 5. + :arg str user_agent: String to send as ``User-Agent`` header + :arg bool decompress_response: Request a compressed response from + the server and decompress it after downloading. Default is True. + New in Tornado 4.0. + :arg bool use_gzip: Deprecated alias for ``decompress_response`` + since Tornado 4.0. + :arg str network_interface: Network interface or source IP to use for request. + See ``curl_httpclient`` note below. + :arg collections.abc.Callable streaming_callback: If set, ``streaming_callback`` will + be run with each chunk of data as it is received, and + ``HTTPResponse.body`` and ``HTTPResponse.buffer`` will be empty in + the final response. + :arg collections.abc.Callable header_callback: If set, ``header_callback`` will + be run with each header line as it is received (including the + first line, e.g. ``HTTP/1.0 200 OK\r\n``, and a final line + containing only ``\r\n``. All lines include the trailing newline + characters). ``HTTPResponse.headers`` will be empty in the final + response. This is most useful in conjunction with + ``streaming_callback``, because it's the only way to get access to + header data while the request is in progress. + :arg collections.abc.Callable prepare_curl_callback: If set, will be called with + a ``pycurl.Curl`` object to allow the application to make additional + ``setopt`` calls. + :arg str proxy_host: HTTP proxy hostname. To use proxies, + ``proxy_host`` and ``proxy_port`` must be set; ``proxy_username``, + ``proxy_pass`` and ``proxy_auth_mode`` are optional. Proxies are + currently only supported with ``curl_httpclient``. + :arg int proxy_port: HTTP proxy port + :arg str proxy_username: HTTP proxy username + :arg str proxy_password: HTTP proxy password + :arg str proxy_auth_mode: HTTP proxy Authentication mode; + default is "basic". supports "basic" and "digest" + :arg bool allow_nonstandard_methods: Allow unknown values for ``method`` + argument? Default is False. + :arg bool validate_cert: For HTTPS requests, validate the server's + certificate? Default is True. + :arg str ca_certs: filename of CA certificates in PEM format, + or None to use defaults. See note below when used with + ``curl_httpclient``. + :arg str client_key: Filename for client SSL key, if any. See + note below when used with ``curl_httpclient``. + :arg str client_cert: Filename for client SSL certificate, if any. + See note below when used with ``curl_httpclient``. + :arg ssl.SSLContext ssl_options: `ssl.SSLContext` object for use in + ``simple_httpclient`` (unsupported by ``curl_httpclient``). + Overrides ``validate_cert``, ``ca_certs``, ``client_key``, + and ``client_cert``. + :arg bool allow_ipv6: Use IPv6 when available? Default is True. + :arg bool expect_100_continue: If true, send the + ``Expect: 100-continue`` header and wait for a continue response + before sending the request body. Only supported with + ``simple_httpclient``. + + .. note:: + + When using ``curl_httpclient`` certain options may be + inherited by subsequent fetches because ``pycurl`` does + not allow them to be cleanly reset. This applies to the + ``ca_certs``, ``client_key``, ``client_cert``, and + ``network_interface`` arguments. If you use these + options, you should pass them on every request (you don't + have to always use the same values, but it's not possible + to mix requests that specify these options with ones that + use the defaults). + + .. versionadded:: 3.1 + The ``auth_mode`` argument. + + .. versionadded:: 4.0 + The ``body_producer`` and ``expect_100_continue`` arguments. + + .. versionadded:: 4.2 + The ``ssl_options`` argument. + + .. versionadded:: 4.5 + The ``proxy_auth_mode`` argument. + """ + # Note that some of these attributes go through property setters + # defined below. + self.headers = headers # type: ignore + if if_modified_since: + self.headers["If-Modified-Since"] = httputil.format_timestamp( + if_modified_since + ) + self.proxy_host = proxy_host + self.proxy_port = proxy_port + self.proxy_username = proxy_username + self.proxy_password = proxy_password + self.proxy_auth_mode = proxy_auth_mode + self.url = url + self.method = method + self.body = body # type: ignore + self.body_producer = body_producer + self.auth_username = auth_username + self.auth_password = auth_password + self.auth_mode = auth_mode + self.connect_timeout = connect_timeout + self.request_timeout = request_timeout + self.follow_redirects = follow_redirects + self.max_redirects = max_redirects + self.user_agent = user_agent + if decompress_response is not None: + self.decompress_response = decompress_response # type: Optional[bool] + else: + self.decompress_response = use_gzip + self.network_interface = network_interface + self.streaming_callback = streaming_callback + self.header_callback = header_callback + self.prepare_curl_callback = prepare_curl_callback + self.allow_nonstandard_methods = allow_nonstandard_methods + self.validate_cert = validate_cert + self.ca_certs = ca_certs + self.allow_ipv6 = allow_ipv6 + self.client_key = client_key + self.client_cert = client_cert + self.ssl_options = ssl_options + self.expect_100_continue = expect_100_continue + self.start_time = time.time() + + @property + def headers(self) -> httputil.HTTPHeaders: + # TODO: headers may actually be a plain dict until fairly late in + # the process (AsyncHTTPClient.fetch), but practically speaking, + # whenever the property is used they're already HTTPHeaders. + return self._headers # type: ignore + + @headers.setter + def headers(self, value: Union[Dict[str, str], httputil.HTTPHeaders]) -> None: + if value is None: + self._headers = httputil.HTTPHeaders() + else: + self._headers = value # type: ignore + + @property + def body(self) -> bytes: + return self._body + + @body.setter + def body(self, value: Union[bytes, str]) -> None: + self._body = utf8(value) + + +class HTTPResponse(object): + """HTTP Response object. + + Attributes: + + * ``request``: HTTPRequest object + + * ``code``: numeric HTTP status code, e.g. 200 or 404 + + * ``reason``: human-readable reason phrase describing the status code + + * ``headers``: `tornado.httputil.HTTPHeaders` object + + * ``effective_url``: final location of the resource after following any + redirects + + * ``buffer``: ``cStringIO`` object for response body + + * ``body``: response body as bytes (created on demand from ``self.buffer``) + + * ``error``: Exception object, if any + + * ``request_time``: seconds from request start to finish. Includes all + network operations from DNS resolution to receiving the last byte of + data. Does not include time spent in the queue (due to the + ``max_clients`` option). If redirects were followed, only includes + the final request. + + * ``start_time``: Time at which the HTTP operation started, based on + `time.time` (not the monotonic clock used by `.IOLoop.time`). May + be ``None`` if the request timed out while in the queue. + + * ``time_info``: dictionary of diagnostic timing information from the + request. Available data are subject to change, but currently uses timings + available from http://curl.haxx.se/libcurl/c/curl_easy_getinfo.html, + plus ``queue``, which is the delay (if any) introduced by waiting for + a slot under `AsyncHTTPClient`'s ``max_clients`` setting. + + .. versionadded:: 5.1 + + Added the ``start_time`` attribute. + + .. versionchanged:: 5.1 + + The ``request_time`` attribute previously included time spent in the queue + for ``simple_httpclient``, but not in ``curl_httpclient``. Now queueing time + is excluded in both implementations. ``request_time`` is now more accurate for + ``curl_httpclient`` because it uses a monotonic clock when available. + """ + + # I'm not sure why these don't get type-inferred from the references in __init__. + error = None # type: Optional[BaseException] + _error_is_response_code = False + request = None # type: HTTPRequest + + def __init__( + self, + request: HTTPRequest, + code: int, + headers: Optional[httputil.HTTPHeaders] = None, + buffer: Optional[BytesIO] = None, + effective_url: Optional[str] = None, + error: Optional[BaseException] = None, + request_time: Optional[float] = None, + time_info: Optional[Dict[str, float]] = None, + reason: Optional[str] = None, + start_time: Optional[float] = None, + ) -> None: + if isinstance(request, _RequestProxy): + self.request = request.request + else: + self.request = request + self.code = code + self.reason = reason or httputil.responses.get(code, "Unknown") + if headers is not None: + self.headers = headers + else: + self.headers = httputil.HTTPHeaders() + self.buffer = buffer + self._body = None # type: Optional[bytes] + if effective_url is None: + self.effective_url = request.url + else: + self.effective_url = effective_url + self._error_is_response_code = False + if error is None: + if self.code < 200 or self.code >= 300: + self._error_is_response_code = True + self.error = HTTPError(self.code, message=self.reason, response=self) + else: + self.error = None + else: + self.error = error + self.start_time = start_time + self.request_time = request_time + self.time_info = time_info or {} + + @property + def body(self) -> bytes: + if self.buffer is None: + return b"" + elif self._body is None: + self._body = self.buffer.getvalue() + + return self._body + + def rethrow(self) -> None: + """If there was an error on the request, raise an `HTTPError`.""" + if self.error: + raise self.error + + def __repr__(self) -> str: + args = ",".join("%s=%r" % i for i in sorted(self.__dict__.items())) + return "%s(%s)" % (self.__class__.__name__, args) + + +class HTTPClientError(Exception): + """Exception thrown for an unsuccessful HTTP request. + + Attributes: + + * ``code`` - HTTP error integer error code, e.g. 404. Error code 599 is + used when no HTTP response was received, e.g. for a timeout. + + * ``response`` - `HTTPResponse` object, if any. + + Note that if ``follow_redirects`` is False, redirects become HTTPErrors, + and you can look at ``error.response.headers['Location']`` to see the + destination of the redirect. + + .. versionchanged:: 5.1 + + Renamed from ``HTTPError`` to ``HTTPClientError`` to avoid collisions with + `tornado.web.HTTPError`. The name ``tornado.httpclient.HTTPError`` remains + as an alias. + """ + + def __init__( + self, + code: int, + message: Optional[str] = None, + response: Optional[HTTPResponse] = None, + ) -> None: + self.code = code + self.message = message or httputil.responses.get(code, "Unknown") + self.response = response + super().__init__(code, message, response) + + def __str__(self) -> str: + return "HTTP %d: %s" % (self.code, self.message) + + # There is a cyclic reference between self and self.response, + # which breaks the default __repr__ implementation. + # (especially on pypy, which doesn't have the same recursion + # detection as cpython). + __repr__ = __str__ + + +HTTPError = HTTPClientError + + +class _RequestProxy(object): + """Combines an object with a dictionary of defaults. + + Used internally by AsyncHTTPClient implementations. + """ + + def __init__( + self, request: HTTPRequest, defaults: Optional[Dict[str, Any]] + ) -> None: + self.request = request + self.defaults = defaults + + def __getattr__(self, name: str) -> Any: + request_attr = getattr(self.request, name) + if request_attr is not None: + return request_attr + elif self.defaults is not None: + return self.defaults.get(name, None) + else: + return None + + +def main() -> None: + from tornado.options import define, options, parse_command_line + + define("print_headers", type=bool, default=False) + define("print_body", type=bool, default=True) + define("follow_redirects", type=bool, default=True) + define("validate_cert", type=bool, default=True) + define("proxy_host", type=str) + define("proxy_port", type=int) + args = parse_command_line() + client = HTTPClient() + for arg in args: + try: + response = client.fetch( + arg, + follow_redirects=options.follow_redirects, + validate_cert=options.validate_cert, + proxy_host=options.proxy_host, + proxy_port=options.proxy_port, + ) + except HTTPError as e: + if e.response is not None: + response = e.response + else: + raise + if options.print_headers: + print(response.headers) + if options.print_body: + print(native_str(response.body)) + client.close() + + +if __name__ == "__main__": + main() diff --git a/venv/lib/python3.8/site-packages/tornado/httpserver.py b/venv/lib/python3.8/site-packages/tornado/httpserver.py new file mode 100644 index 0000000..cd4a468 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/httpserver.py @@ -0,0 +1,398 @@ +# +# Copyright 2009 Facebook +# +# 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. + +"""A non-blocking, single-threaded HTTP server. + +Typical applications have little direct interaction with the `HTTPServer` +class except to start a server at the beginning of the process +(and even that is often done indirectly via `tornado.web.Application.listen`). + +.. versionchanged:: 4.0 + + The ``HTTPRequest`` class that used to live in this module has been moved + to `tornado.httputil.HTTPServerRequest`. The old name remains as an alias. +""" + +import socket +import ssl + +from tornado.escape import native_str +from tornado.http1connection import HTTP1ServerConnection, HTTP1ConnectionParameters +from tornado import httputil +from tornado import iostream +from tornado import netutil +from tornado.tcpserver import TCPServer +from tornado.util import Configurable + +import typing +from typing import Union, Any, Dict, Callable, List, Type, Tuple, Optional, Awaitable + +if typing.TYPE_CHECKING: + from typing import Set # noqa: F401 + + +class HTTPServer(TCPServer, Configurable, httputil.HTTPServerConnectionDelegate): + r"""A non-blocking, single-threaded HTTP server. + + A server is defined by a subclass of `.HTTPServerConnectionDelegate`, + or, for backwards compatibility, a callback that takes an + `.HTTPServerRequest` as an argument. The delegate is usually a + `tornado.web.Application`. + + `HTTPServer` supports keep-alive connections by default + (automatically for HTTP/1.1, or for HTTP/1.0 when the client + requests ``Connection: keep-alive``). + + If ``xheaders`` is ``True``, we support the + ``X-Real-Ip``/``X-Forwarded-For`` and + ``X-Scheme``/``X-Forwarded-Proto`` headers, which override the + remote IP and URI scheme/protocol for all requests. These headers + are useful when running Tornado behind a reverse proxy or load + balancer. The ``protocol`` argument can also be set to ``https`` + if Tornado is run behind an SSL-decoding proxy that does not set one of + the supported ``xheaders``. + + By default, when parsing the ``X-Forwarded-For`` header, Tornado will + select the last (i.e., the closest) address on the list of hosts as the + remote host IP address. To select the next server in the chain, a list of + trusted downstream hosts may be passed as the ``trusted_downstream`` + argument. These hosts will be skipped when parsing the ``X-Forwarded-For`` + header. + + To make this server serve SSL traffic, send the ``ssl_options`` keyword + argument with an `ssl.SSLContext` object. For compatibility with older + versions of Python ``ssl_options`` may also be a dictionary of keyword + arguments for the `ssl.wrap_socket` method.:: + + ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) + ssl_ctx.load_cert_chain(os.path.join(data_dir, "mydomain.crt"), + os.path.join(data_dir, "mydomain.key")) + HTTPServer(application, ssl_options=ssl_ctx) + + `HTTPServer` initialization follows one of three patterns (the + initialization methods are defined on `tornado.tcpserver.TCPServer`): + + 1. `~tornado.tcpserver.TCPServer.listen`: simple single-process:: + + server = HTTPServer(app) + server.listen(8888) + IOLoop.current().start() + + In many cases, `tornado.web.Application.listen` can be used to avoid + the need to explicitly create the `HTTPServer`. + + 2. `~tornado.tcpserver.TCPServer.bind`/`~tornado.tcpserver.TCPServer.start`: + simple multi-process:: + + server = HTTPServer(app) + server.bind(8888) + server.start(0) # Forks multiple sub-processes + IOLoop.current().start() + + When using this interface, an `.IOLoop` must *not* be passed + to the `HTTPServer` constructor. `~.TCPServer.start` will always start + the server on the default singleton `.IOLoop`. + + 3. `~tornado.tcpserver.TCPServer.add_sockets`: advanced multi-process:: + + sockets = tornado.netutil.bind_sockets(8888) + tornado.process.fork_processes(0) + server = HTTPServer(app) + server.add_sockets(sockets) + IOLoop.current().start() + + The `~.TCPServer.add_sockets` interface is more complicated, + but it can be used with `tornado.process.fork_processes` to + give you more flexibility in when the fork happens. + `~.TCPServer.add_sockets` can also be used in single-process + servers if you want to create your listening sockets in some + way other than `tornado.netutil.bind_sockets`. + + .. versionchanged:: 4.0 + Added ``decompress_request``, ``chunk_size``, ``max_header_size``, + ``idle_connection_timeout``, ``body_timeout``, ``max_body_size`` + arguments. Added support for `.HTTPServerConnectionDelegate` + instances as ``request_callback``. + + .. versionchanged:: 4.1 + `.HTTPServerConnectionDelegate.start_request` is now called with + two arguments ``(server_conn, request_conn)`` (in accordance with the + documentation) instead of one ``(request_conn)``. + + .. versionchanged:: 4.2 + `HTTPServer` is now a subclass of `tornado.util.Configurable`. + + .. versionchanged:: 4.5 + Added the ``trusted_downstream`` argument. + + .. versionchanged:: 5.0 + The ``io_loop`` argument has been removed. + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + # Ignore args to __init__; real initialization belongs in + # initialize since we're Configurable. (there's something + # weird in initialization order between this class, + # Configurable, and TCPServer so we can't leave __init__ out + # completely) + pass + + def initialize( + self, + request_callback: Union[ + httputil.HTTPServerConnectionDelegate, + Callable[[httputil.HTTPServerRequest], None], + ], + no_keep_alive: bool = False, + xheaders: bool = False, + ssl_options: Optional[Union[Dict[str, Any], ssl.SSLContext]] = None, + protocol: Optional[str] = None, + decompress_request: bool = False, + chunk_size: Optional[int] = None, + max_header_size: Optional[int] = None, + idle_connection_timeout: Optional[float] = None, + body_timeout: Optional[float] = None, + max_body_size: Optional[int] = None, + max_buffer_size: Optional[int] = None, + trusted_downstream: Optional[List[str]] = None, + ) -> None: + # This method's signature is not extracted with autodoc + # because we want its arguments to appear on the class + # constructor. When changing this signature, also update the + # copy in httpserver.rst. + self.request_callback = request_callback + self.xheaders = xheaders + self.protocol = protocol + self.conn_params = HTTP1ConnectionParameters( + decompress=decompress_request, + chunk_size=chunk_size, + max_header_size=max_header_size, + header_timeout=idle_connection_timeout or 3600, + max_body_size=max_body_size, + body_timeout=body_timeout, + no_keep_alive=no_keep_alive, + ) + TCPServer.__init__( + self, + ssl_options=ssl_options, + max_buffer_size=max_buffer_size, + read_chunk_size=chunk_size, + ) + self._connections = set() # type: Set[HTTP1ServerConnection] + self.trusted_downstream = trusted_downstream + + @classmethod + def configurable_base(cls) -> Type[Configurable]: + return HTTPServer + + @classmethod + def configurable_default(cls) -> Type[Configurable]: + return HTTPServer + + async def close_all_connections(self) -> None: + """Close all open connections and asynchronously wait for them to finish. + + This method is used in combination with `~.TCPServer.stop` to + support clean shutdowns (especially for unittests). Typical + usage would call ``stop()`` first to stop accepting new + connections, then ``await close_all_connections()`` to wait for + existing connections to finish. + + This method does not currently close open websocket connections. + + Note that this method is a coroutine and must be called with ``await``. + + """ + while self._connections: + # Peek at an arbitrary element of the set + conn = next(iter(self._connections)) + await conn.close() + + def handle_stream(self, stream: iostream.IOStream, address: Tuple) -> None: + context = _HTTPRequestContext( + stream, address, self.protocol, self.trusted_downstream + ) + conn = HTTP1ServerConnection(stream, self.conn_params, context) + self._connections.add(conn) + conn.start_serving(self) + + def start_request( + self, server_conn: object, request_conn: httputil.HTTPConnection + ) -> httputil.HTTPMessageDelegate: + if isinstance(self.request_callback, httputil.HTTPServerConnectionDelegate): + delegate = self.request_callback.start_request(server_conn, request_conn) + else: + delegate = _CallableAdapter(self.request_callback, request_conn) + + if self.xheaders: + delegate = _ProxyAdapter(delegate, request_conn) + + return delegate + + def on_close(self, server_conn: object) -> None: + self._connections.remove(typing.cast(HTTP1ServerConnection, server_conn)) + + +class _CallableAdapter(httputil.HTTPMessageDelegate): + def __init__( + self, + request_callback: Callable[[httputil.HTTPServerRequest], None], + request_conn: httputil.HTTPConnection, + ) -> None: + self.connection = request_conn + self.request_callback = request_callback + self.request = None # type: Optional[httputil.HTTPServerRequest] + self.delegate = None + self._chunks = [] # type: List[bytes] + + def headers_received( + self, + start_line: Union[httputil.RequestStartLine, httputil.ResponseStartLine], + headers: httputil.HTTPHeaders, + ) -> Optional[Awaitable[None]]: + self.request = httputil.HTTPServerRequest( + connection=self.connection, + start_line=typing.cast(httputil.RequestStartLine, start_line), + headers=headers, + ) + return None + + def data_received(self, chunk: bytes) -> Optional[Awaitable[None]]: + self._chunks.append(chunk) + return None + + def finish(self) -> None: + assert self.request is not None + self.request.body = b"".join(self._chunks) + self.request._parse_body() + self.request_callback(self.request) + + def on_connection_close(self) -> None: + del self._chunks + + +class _HTTPRequestContext(object): + def __init__( + self, + stream: iostream.IOStream, + address: Tuple, + protocol: Optional[str], + trusted_downstream: Optional[List[str]] = None, + ) -> None: + self.address = address + # Save the socket's address family now so we know how to + # interpret self.address even after the stream is closed + # and its socket attribute replaced with None. + if stream.socket is not None: + self.address_family = stream.socket.family + else: + self.address_family = None + # In HTTPServerRequest we want an IP, not a full socket address. + if ( + self.address_family in (socket.AF_INET, socket.AF_INET6) + and address is not None + ): + self.remote_ip = address[0] + else: + # Unix (or other) socket; fake the remote address. + self.remote_ip = "0.0.0.0" + if protocol: + self.protocol = protocol + elif isinstance(stream, iostream.SSLIOStream): + self.protocol = "https" + else: + self.protocol = "http" + self._orig_remote_ip = self.remote_ip + self._orig_protocol = self.protocol + self.trusted_downstream = set(trusted_downstream or []) + + def __str__(self) -> str: + if self.address_family in (socket.AF_INET, socket.AF_INET6): + return self.remote_ip + elif isinstance(self.address, bytes): + # Python 3 with the -bb option warns about str(bytes), + # so convert it explicitly. + # Unix socket addresses are str on mac but bytes on linux. + return native_str(self.address) + else: + return str(self.address) + + def _apply_xheaders(self, headers: httputil.HTTPHeaders) -> None: + """Rewrite the ``remote_ip`` and ``protocol`` fields.""" + # Squid uses X-Forwarded-For, others use X-Real-Ip + ip = headers.get("X-Forwarded-For", self.remote_ip) + # Skip trusted downstream hosts in X-Forwarded-For list + for ip in (cand.strip() for cand in reversed(ip.split(","))): + if ip not in self.trusted_downstream: + break + ip = headers.get("X-Real-Ip", ip) + if netutil.is_valid_ip(ip): + self.remote_ip = ip + # AWS uses X-Forwarded-Proto + proto_header = headers.get( + "X-Scheme", headers.get("X-Forwarded-Proto", self.protocol) + ) + if proto_header: + # use only the last proto entry if there is more than one + # TODO: support trusting multiple layers of proxied protocol + proto_header = proto_header.split(",")[-1].strip() + if proto_header in ("http", "https"): + self.protocol = proto_header + + def _unapply_xheaders(self) -> None: + """Undo changes from `_apply_xheaders`. + + Xheaders are per-request so they should not leak to the next + request on the same connection. + """ + self.remote_ip = self._orig_remote_ip + self.protocol = self._orig_protocol + + +class _ProxyAdapter(httputil.HTTPMessageDelegate): + def __init__( + self, + delegate: httputil.HTTPMessageDelegate, + request_conn: httputil.HTTPConnection, + ) -> None: + self.connection = request_conn + self.delegate = delegate + + def headers_received( + self, + start_line: Union[httputil.RequestStartLine, httputil.ResponseStartLine], + headers: httputil.HTTPHeaders, + ) -> Optional[Awaitable[None]]: + # TODO: either make context an official part of the + # HTTPConnection interface or figure out some other way to do this. + self.connection.context._apply_xheaders(headers) # type: ignore + return self.delegate.headers_received(start_line, headers) + + def data_received(self, chunk: bytes) -> Optional[Awaitable[None]]: + return self.delegate.data_received(chunk) + + def finish(self) -> None: + self.delegate.finish() + self._cleanup() + + def on_connection_close(self) -> None: + self.delegate.on_connection_close() + self._cleanup() + + def _cleanup(self) -> None: + self.connection.context._unapply_xheaders() # type: ignore + + +HTTPRequest = httputil.HTTPServerRequest diff --git a/venv/lib/python3.8/site-packages/tornado/httputil.py b/venv/lib/python3.8/site-packages/tornado/httputil.py new file mode 100644 index 0000000..bd32cd0 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/httputil.py @@ -0,0 +1,1133 @@ +# +# Copyright 2009 Facebook +# +# 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. + +"""HTTP utility code shared by clients and servers. + +This module also defines the `HTTPServerRequest` class which is exposed +via `tornado.web.RequestHandler.request`. +""" + +import calendar +import collections +import copy +import datetime +import email.utils +from functools import lru_cache +from http.client import responses +import http.cookies +import re +from ssl import SSLError +import time +import unicodedata +from urllib.parse import urlencode, urlparse, urlunparse, parse_qsl + +from tornado.escape import native_str, parse_qs_bytes, utf8 +from tornado.log import gen_log +from tornado.util import ObjectDict, unicode_type + + +# responses is unused in this file, but we re-export it to other files. +# Reference it so pyflakes doesn't complain. +responses + +import typing +from typing import ( + Tuple, + Iterable, + List, + Mapping, + Iterator, + Dict, + Union, + Optional, + Awaitable, + Generator, + AnyStr, +) + +if typing.TYPE_CHECKING: + from typing import Deque # noqa: F401 + from asyncio import Future # noqa: F401 + import unittest # noqa: F401 + + +@lru_cache(1000) +def _normalize_header(name: str) -> str: + """Map a header name to Http-Header-Case. + + >>> _normalize_header("coNtent-TYPE") + 'Content-Type' + """ + return "-".join([w.capitalize() for w in name.split("-")]) + + +class HTTPHeaders(collections.abc.MutableMapping): + """A dictionary that maintains ``Http-Header-Case`` for all keys. + + Supports multiple values per key via a pair of new methods, + `add()` and `get_list()`. The regular dictionary interface + returns a single value per key, with multiple values joined by a + comma. + + >>> h = HTTPHeaders({"content-type": "text/html"}) + >>> list(h.keys()) + ['Content-Type'] + >>> h["Content-Type"] + 'text/html' + + >>> h.add("Set-Cookie", "A=B") + >>> h.add("Set-Cookie", "C=D") + >>> h["set-cookie"] + 'A=B,C=D' + >>> h.get_list("set-cookie") + ['A=B', 'C=D'] + + >>> for (k,v) in sorted(h.get_all()): + ... print('%s: %s' % (k,v)) + ... + Content-Type: text/html + Set-Cookie: A=B + Set-Cookie: C=D + """ + + @typing.overload + def __init__(self, __arg: Mapping[str, List[str]]) -> None: + pass + + @typing.overload # noqa: F811 + def __init__(self, __arg: Mapping[str, str]) -> None: + pass + + @typing.overload # noqa: F811 + def __init__(self, *args: Tuple[str, str]) -> None: + pass + + @typing.overload # noqa: F811 + def __init__(self, **kwargs: str) -> None: + pass + + def __init__(self, *args: typing.Any, **kwargs: str) -> None: # noqa: F811 + self._dict = {} # type: typing.Dict[str, str] + self._as_list = {} # type: typing.Dict[str, typing.List[str]] + self._last_key = None # type: Optional[str] + if len(args) == 1 and len(kwargs) == 0 and isinstance(args[0], HTTPHeaders): + # Copy constructor + for k, v in args[0].get_all(): + self.add(k, v) + else: + # Dict-style initialization + self.update(*args, **kwargs) + + # new public methods + + def add(self, name: str, value: str) -> None: + """Adds a new value for the given key.""" + norm_name = _normalize_header(name) + self._last_key = norm_name + if norm_name in self: + self._dict[norm_name] = ( + native_str(self[norm_name]) + "," + native_str(value) + ) + self._as_list[norm_name].append(value) + else: + self[norm_name] = value + + def get_list(self, name: str) -> List[str]: + """Returns all values for the given header as a list.""" + norm_name = _normalize_header(name) + return self._as_list.get(norm_name, []) + + def get_all(self) -> Iterable[Tuple[str, str]]: + """Returns an iterable of all (name, value) pairs. + + If a header has multiple values, multiple pairs will be + returned with the same name. + """ + for name, values in self._as_list.items(): + for value in values: + yield (name, value) + + def parse_line(self, line: str) -> None: + """Updates the dictionary with a single header line. + + >>> h = HTTPHeaders() + >>> h.parse_line("Content-Type: text/html") + >>> h.get('content-type') + 'text/html' + """ + if line[0].isspace(): + # continuation of a multi-line header + if self._last_key is None: + raise HTTPInputError("first header line cannot start with whitespace") + new_part = " " + line.lstrip() + self._as_list[self._last_key][-1] += new_part + self._dict[self._last_key] += new_part + else: + try: + name, value = line.split(":", 1) + except ValueError: + raise HTTPInputError("no colon in header line") + self.add(name, value.strip()) + + @classmethod + def parse(cls, headers: str) -> "HTTPHeaders": + """Returns a dictionary from HTTP header text. + + >>> h = HTTPHeaders.parse("Content-Type: text/html\\r\\nContent-Length: 42\\r\\n") + >>> sorted(h.items()) + [('Content-Length', '42'), ('Content-Type', 'text/html')] + + .. versionchanged:: 5.1 + + Raises `HTTPInputError` on malformed headers instead of a + mix of `KeyError`, and `ValueError`. + + """ + h = cls() + # RFC 7230 section 3.5: a recipient MAY recognize a single LF as a line + # terminator and ignore any preceding CR. + for line in headers.split("\n"): + if line.endswith("\r"): + line = line[:-1] + if line: + h.parse_line(line) + return h + + # MutableMapping abstract method implementations. + + def __setitem__(self, name: str, value: str) -> None: + norm_name = _normalize_header(name) + self._dict[norm_name] = value + self._as_list[norm_name] = [value] + + def __getitem__(self, name: str) -> str: + return self._dict[_normalize_header(name)] + + def __delitem__(self, name: str) -> None: + norm_name = _normalize_header(name) + del self._dict[norm_name] + del self._as_list[norm_name] + + def __len__(self) -> int: + return len(self._dict) + + def __iter__(self) -> Iterator[typing.Any]: + return iter(self._dict) + + def copy(self) -> "HTTPHeaders": + # defined in dict but not in MutableMapping. + return HTTPHeaders(self) + + # Use our overridden copy method for the copy.copy module. + # This makes shallow copies one level deeper, but preserves + # the appearance that HTTPHeaders is a single container. + __copy__ = copy + + def __str__(self) -> str: + lines = [] + for name, value in self.get_all(): + lines.append("%s: %s\n" % (name, value)) + return "".join(lines) + + __unicode__ = __str__ + + +class HTTPServerRequest(object): + """A single HTTP request. + + All attributes are type `str` unless otherwise noted. + + .. attribute:: method + + HTTP request method, e.g. "GET" or "POST" + + .. attribute:: uri + + The requested uri. + + .. attribute:: path + + The path portion of `uri` + + .. attribute:: query + + The query portion of `uri` + + .. attribute:: version + + HTTP version specified in request, e.g. "HTTP/1.1" + + .. attribute:: headers + + `.HTTPHeaders` dictionary-like object for request headers. Acts like + a case-insensitive dictionary with additional methods for repeated + headers. + + .. attribute:: body + + Request body, if present, as a byte string. + + .. attribute:: remote_ip + + Client's IP address as a string. If ``HTTPServer.xheaders`` is set, + will pass along the real IP address provided by a load balancer + in the ``X-Real-Ip`` or ``X-Forwarded-For`` header. + + .. versionchanged:: 3.1 + The list format of ``X-Forwarded-For`` is now supported. + + .. attribute:: protocol + + The protocol used, either "http" or "https". If ``HTTPServer.xheaders`` + is set, will pass along the protocol used by a load balancer if + reported via an ``X-Scheme`` header. + + .. attribute:: host + + The requested hostname, usually taken from the ``Host`` header. + + .. attribute:: arguments + + GET/POST arguments are available in the arguments property, which + maps arguments names to lists of values (to support multiple values + for individual names). Names are of type `str`, while arguments + are byte strings. Note that this is different from + `.RequestHandler.get_argument`, which returns argument values as + unicode strings. + + .. attribute:: query_arguments + + Same format as ``arguments``, but contains only arguments extracted + from the query string. + + .. versionadded:: 3.2 + + .. attribute:: body_arguments + + Same format as ``arguments``, but contains only arguments extracted + from the request body. + + .. versionadded:: 3.2 + + .. attribute:: files + + File uploads are available in the files property, which maps file + names to lists of `.HTTPFile`. + + .. attribute:: connection + + An HTTP request is attached to a single HTTP connection, which can + be accessed through the "connection" attribute. Since connections + are typically kept open in HTTP/1.1, multiple requests can be handled + sequentially on a single connection. + + .. versionchanged:: 4.0 + Moved from ``tornado.httpserver.HTTPRequest``. + """ + + path = None # type: str + query = None # type: str + + # HACK: Used for stream_request_body + _body_future = None # type: Future[None] + + def __init__( + self, + method: Optional[str] = None, + uri: Optional[str] = None, + version: str = "HTTP/1.0", + headers: Optional[HTTPHeaders] = None, + body: Optional[bytes] = None, + host: Optional[str] = None, + files: Optional[Dict[str, List["HTTPFile"]]] = None, + connection: Optional["HTTPConnection"] = None, + start_line: Optional["RequestStartLine"] = None, + server_connection: Optional[object] = None, + ) -> None: + if start_line is not None: + method, uri, version = start_line + self.method = method + self.uri = uri + self.version = version + self.headers = headers or HTTPHeaders() + self.body = body or b"" + + # set remote IP and protocol + context = getattr(connection, "context", None) + self.remote_ip = getattr(context, "remote_ip", None) + self.protocol = getattr(context, "protocol", "http") + + self.host = host or self.headers.get("Host") or "127.0.0.1" + self.host_name = split_host_and_port(self.host.lower())[0] + self.files = files or {} + self.connection = connection + self.server_connection = server_connection + self._start_time = time.time() + self._finish_time = None + + if uri is not None: + self.path, sep, self.query = uri.partition("?") + self.arguments = parse_qs_bytes(self.query, keep_blank_values=True) + self.query_arguments = copy.deepcopy(self.arguments) + self.body_arguments = {} # type: Dict[str, List[bytes]] + + @property + def cookies(self) -> Dict[str, http.cookies.Morsel]: + """A dictionary of ``http.cookies.Morsel`` objects.""" + if not hasattr(self, "_cookies"): + self._cookies = ( + http.cookies.SimpleCookie() + ) # type: http.cookies.SimpleCookie + if "Cookie" in self.headers: + try: + parsed = parse_cookie(self.headers["Cookie"]) + except Exception: + pass + else: + for k, v in parsed.items(): + try: + self._cookies[k] = v + except Exception: + # SimpleCookie imposes some restrictions on keys; + # parse_cookie does not. Discard any cookies + # with disallowed keys. + pass + return self._cookies + + def full_url(self) -> str: + """Reconstructs the full URL for this request.""" + return self.protocol + "://" + self.host + self.uri + + def request_time(self) -> float: + """Returns the amount of time it took for this request to execute.""" + if self._finish_time is None: + return time.time() - self._start_time + else: + return self._finish_time - self._start_time + + def get_ssl_certificate( + self, binary_form: bool = False + ) -> Union[None, Dict, bytes]: + """Returns the client's SSL certificate, if any. + + To use client certificates, the HTTPServer's + `ssl.SSLContext.verify_mode` field must be set, e.g.:: + + ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) + ssl_ctx.load_cert_chain("foo.crt", "foo.key") + ssl_ctx.load_verify_locations("cacerts.pem") + ssl_ctx.verify_mode = ssl.CERT_REQUIRED + server = HTTPServer(app, ssl_options=ssl_ctx) + + By default, the return value is a dictionary (or None, if no + client certificate is present). If ``binary_form`` is true, a + DER-encoded form of the certificate is returned instead. See + SSLSocket.getpeercert() in the standard library for more + details. + http://docs.python.org/library/ssl.html#sslsocket-objects + """ + try: + if self.connection is None: + return None + # TODO: add a method to HTTPConnection for this so it can work with HTTP/2 + return self.connection.stream.socket.getpeercert( # type: ignore + binary_form=binary_form + ) + except SSLError: + return None + + def _parse_body(self) -> None: + parse_body_arguments( + self.headers.get("Content-Type", ""), + self.body, + self.body_arguments, + self.files, + self.headers, + ) + + for k, v in self.body_arguments.items(): + self.arguments.setdefault(k, []).extend(v) + + def __repr__(self) -> str: + attrs = ("protocol", "host", "method", "uri", "version", "remote_ip") + args = ", ".join(["%s=%r" % (n, getattr(self, n)) for n in attrs]) + return "%s(%s)" % (self.__class__.__name__, args) + + +class HTTPInputError(Exception): + """Exception class for malformed HTTP requests or responses + from remote sources. + + .. versionadded:: 4.0 + """ + + pass + + +class HTTPOutputError(Exception): + """Exception class for errors in HTTP output. + + .. versionadded:: 4.0 + """ + + pass + + +class HTTPServerConnectionDelegate(object): + """Implement this interface to handle requests from `.HTTPServer`. + + .. versionadded:: 4.0 + """ + + def start_request( + self, server_conn: object, request_conn: "HTTPConnection" + ) -> "HTTPMessageDelegate": + """This method is called by the server when a new request has started. + + :arg server_conn: is an opaque object representing the long-lived + (e.g. tcp-level) connection. + :arg request_conn: is a `.HTTPConnection` object for a single + request/response exchange. + + This method should return a `.HTTPMessageDelegate`. + """ + raise NotImplementedError() + + def on_close(self, server_conn: object) -> None: + """This method is called when a connection has been closed. + + :arg server_conn: is a server connection that has previously been + passed to ``start_request``. + """ + pass + + +class HTTPMessageDelegate(object): + """Implement this interface to handle an HTTP request or response. + + .. versionadded:: 4.0 + """ + + # TODO: genericize this class to avoid exposing the Union. + def headers_received( + self, + start_line: Union["RequestStartLine", "ResponseStartLine"], + headers: HTTPHeaders, + ) -> Optional[Awaitable[None]]: + """Called when the HTTP headers have been received and parsed. + + :arg start_line: a `.RequestStartLine` or `.ResponseStartLine` + depending on whether this is a client or server message. + :arg headers: a `.HTTPHeaders` instance. + + Some `.HTTPConnection` methods can only be called during + ``headers_received``. + + May return a `.Future`; if it does the body will not be read + until it is done. + """ + pass + + def data_received(self, chunk: bytes) -> Optional[Awaitable[None]]: + """Called when a chunk of data has been received. + + May return a `.Future` for flow control. + """ + pass + + def finish(self) -> None: + """Called after the last chunk of data has been received.""" + pass + + def on_connection_close(self) -> None: + """Called if the connection is closed without finishing the request. + + If ``headers_received`` is called, either ``finish`` or + ``on_connection_close`` will be called, but not both. + """ + pass + + +class HTTPConnection(object): + """Applications use this interface to write their responses. + + .. versionadded:: 4.0 + """ + + def write_headers( + self, + start_line: Union["RequestStartLine", "ResponseStartLine"], + headers: HTTPHeaders, + chunk: Optional[bytes] = None, + ) -> "Future[None]": + """Write an HTTP header block. + + :arg start_line: a `.RequestStartLine` or `.ResponseStartLine`. + :arg headers: a `.HTTPHeaders` instance. + :arg chunk: the first (optional) chunk of data. This is an optimization + so that small responses can be written in the same call as their + headers. + + The ``version`` field of ``start_line`` is ignored. + + Returns a future for flow control. + + .. versionchanged:: 6.0 + + The ``callback`` argument was removed. + """ + raise NotImplementedError() + + def write(self, chunk: bytes) -> "Future[None]": + """Writes a chunk of body data. + + Returns a future for flow control. + + .. versionchanged:: 6.0 + + The ``callback`` argument was removed. + """ + raise NotImplementedError() + + def finish(self) -> None: + """Indicates that the last body data has been written. + """ + raise NotImplementedError() + + +def url_concat( + url: str, + args: Union[ + None, Dict[str, str], List[Tuple[str, str]], Tuple[Tuple[str, str], ...] + ], +) -> str: + """Concatenate url and arguments regardless of whether + url has existing query parameters. + + ``args`` may be either a dictionary or a list of key-value pairs + (the latter allows for multiple values with the same key. + + >>> url_concat("http://example.com/foo", dict(c="d")) + 'http://example.com/foo?c=d' + >>> url_concat("http://example.com/foo?a=b", dict(c="d")) + 'http://example.com/foo?a=b&c=d' + >>> url_concat("http://example.com/foo?a=b", [("c", "d"), ("c", "d2")]) + 'http://example.com/foo?a=b&c=d&c=d2' + """ + if args is None: + return url + parsed_url = urlparse(url) + if isinstance(args, dict): + parsed_query = parse_qsl(parsed_url.query, keep_blank_values=True) + parsed_query.extend(args.items()) + elif isinstance(args, list) or isinstance(args, tuple): + parsed_query = parse_qsl(parsed_url.query, keep_blank_values=True) + parsed_query.extend(args) + else: + err = "'args' parameter should be dict, list or tuple. Not {0}".format( + type(args) + ) + raise TypeError(err) + final_query = urlencode(parsed_query) + url = urlunparse( + ( + parsed_url[0], + parsed_url[1], + parsed_url[2], + parsed_url[3], + final_query, + parsed_url[5], + ) + ) + return url + + +class HTTPFile(ObjectDict): + """Represents a file uploaded via a form. + + For backwards compatibility, its instance attributes are also + accessible as dictionary keys. + + * ``filename`` + * ``body`` + * ``content_type`` + """ + + pass + + +def _parse_request_range( + range_header: str, +) -> Optional[Tuple[Optional[int], Optional[int]]]: + """Parses a Range header. + + Returns either ``None`` or tuple ``(start, end)``. + Note that while the HTTP headers use inclusive byte positions, + this method returns indexes suitable for use in slices. + + >>> start, end = _parse_request_range("bytes=1-2") + >>> start, end + (1, 3) + >>> [0, 1, 2, 3, 4][start:end] + [1, 2] + >>> _parse_request_range("bytes=6-") + (6, None) + >>> _parse_request_range("bytes=-6") + (-6, None) + >>> _parse_request_range("bytes=-0") + (None, 0) + >>> _parse_request_range("bytes=") + (None, None) + >>> _parse_request_range("foo=42") + >>> _parse_request_range("bytes=1-2,6-10") + + Note: only supports one range (ex, ``bytes=1-2,6-10`` is not allowed). + + See [0] for the details of the range header. + + [0]: http://greenbytes.de/tech/webdav/draft-ietf-httpbis-p5-range-latest.html#byte.ranges + """ + unit, _, value = range_header.partition("=") + unit, value = unit.strip(), value.strip() + if unit != "bytes": + return None + start_b, _, end_b = value.partition("-") + try: + start = _int_or_none(start_b) + end = _int_or_none(end_b) + except ValueError: + return None + if end is not None: + if start is None: + if end != 0: + start = -end + end = None + else: + end += 1 + return (start, end) + + +def _get_content_range(start: Optional[int], end: Optional[int], total: int) -> str: + """Returns a suitable Content-Range header: + + >>> print(_get_content_range(None, 1, 4)) + bytes 0-0/4 + >>> print(_get_content_range(1, 3, 4)) + bytes 1-2/4 + >>> print(_get_content_range(None, None, 4)) + bytes 0-3/4 + """ + start = start or 0 + end = (end or total) - 1 + return "bytes %s-%s/%s" % (start, end, total) + + +def _int_or_none(val: str) -> Optional[int]: + val = val.strip() + if val == "": + return None + return int(val) + + +def parse_body_arguments( + content_type: str, + body: bytes, + arguments: Dict[str, List[bytes]], + files: Dict[str, List[HTTPFile]], + headers: Optional[HTTPHeaders] = None, +) -> None: + """Parses a form request body. + + Supports ``application/x-www-form-urlencoded`` and + ``multipart/form-data``. The ``content_type`` parameter should be + a string and ``body`` should be a byte string. The ``arguments`` + and ``files`` parameters are dictionaries that will be updated + with the parsed contents. + """ + if content_type.startswith("application/x-www-form-urlencoded"): + if headers and "Content-Encoding" in headers: + gen_log.warning( + "Unsupported Content-Encoding: %s", headers["Content-Encoding"] + ) + return + try: + # real charset decoding will happen in RequestHandler.decode_argument() + uri_arguments = parse_qs_bytes(body, keep_blank_values=True) + except Exception as e: + gen_log.warning("Invalid x-www-form-urlencoded body: %s", e) + uri_arguments = {} + for name, values in uri_arguments.items(): + if values: + arguments.setdefault(name, []).extend(values) + elif content_type.startswith("multipart/form-data"): + if headers and "Content-Encoding" in headers: + gen_log.warning( + "Unsupported Content-Encoding: %s", headers["Content-Encoding"] + ) + return + try: + fields = content_type.split(";") + for field in fields: + k, sep, v = field.strip().partition("=") + if k == "boundary" and v: + parse_multipart_form_data(utf8(v), body, arguments, files) + break + else: + raise ValueError("multipart boundary not found") + except Exception as e: + gen_log.warning("Invalid multipart/form-data: %s", e) + + +def parse_multipart_form_data( + boundary: bytes, + data: bytes, + arguments: Dict[str, List[bytes]], + files: Dict[str, List[HTTPFile]], +) -> None: + """Parses a ``multipart/form-data`` body. + + The ``boundary`` and ``data`` parameters are both byte strings. + The dictionaries given in the arguments and files parameters + will be updated with the contents of the body. + + .. versionchanged:: 5.1 + + Now recognizes non-ASCII filenames in RFC 2231/5987 + (``filename*=``) format. + """ + # The standard allows for the boundary to be quoted in the header, + # although it's rare (it happens at least for google app engine + # xmpp). I think we're also supposed to handle backslash-escapes + # here but I'll save that until we see a client that uses them + # in the wild. + if boundary.startswith(b'"') and boundary.endswith(b'"'): + boundary = boundary[1:-1] + final_boundary_index = data.rfind(b"--" + boundary + b"--") + if final_boundary_index == -1: + gen_log.warning("Invalid multipart/form-data: no final boundary") + return + parts = data[:final_boundary_index].split(b"--" + boundary + b"\r\n") + for part in parts: + if not part: + continue + eoh = part.find(b"\r\n\r\n") + if eoh == -1: + gen_log.warning("multipart/form-data missing headers") + continue + headers = HTTPHeaders.parse(part[:eoh].decode("utf-8")) + disp_header = headers.get("Content-Disposition", "") + disposition, disp_params = _parse_header(disp_header) + if disposition != "form-data" or not part.endswith(b"\r\n"): + gen_log.warning("Invalid multipart/form-data") + continue + value = part[eoh + 4 : -2] + if not disp_params.get("name"): + gen_log.warning("multipart/form-data value missing name") + continue + name = disp_params["name"] + if disp_params.get("filename"): + ctype = headers.get("Content-Type", "application/unknown") + files.setdefault(name, []).append( + HTTPFile( + filename=disp_params["filename"], body=value, content_type=ctype + ) + ) + else: + arguments.setdefault(name, []).append(value) + + +def format_timestamp( + ts: Union[int, float, tuple, time.struct_time, datetime.datetime] +) -> str: + """Formats a timestamp in the format used by HTTP. + + The argument may be a numeric timestamp as returned by `time.time`, + a time tuple as returned by `time.gmtime`, or a `datetime.datetime` + object. + + >>> format_timestamp(1359312200) + 'Sun, 27 Jan 2013 18:43:20 GMT' + """ + if isinstance(ts, (int, float)): + time_num = ts + elif isinstance(ts, (tuple, time.struct_time)): + time_num = calendar.timegm(ts) + elif isinstance(ts, datetime.datetime): + time_num = calendar.timegm(ts.utctimetuple()) + else: + raise TypeError("unknown timestamp type: %r" % ts) + return email.utils.formatdate(time_num, usegmt=True) + + +RequestStartLine = collections.namedtuple( + "RequestStartLine", ["method", "path", "version"] +) + + +_http_version_re = re.compile(r"^HTTP/1\.[0-9]$") + + +def parse_request_start_line(line: str) -> RequestStartLine: + """Returns a (method, path, version) tuple for an HTTP 1.x request line. + + The response is a `collections.namedtuple`. + + >>> parse_request_start_line("GET /foo HTTP/1.1") + RequestStartLine(method='GET', path='/foo', version='HTTP/1.1') + """ + try: + method, path, version = line.split(" ") + except ValueError: + # https://tools.ietf.org/html/rfc7230#section-3.1.1 + # invalid request-line SHOULD respond with a 400 (Bad Request) + raise HTTPInputError("Malformed HTTP request line") + if not _http_version_re.match(version): + raise HTTPInputError( + "Malformed HTTP version in HTTP Request-Line: %r" % version + ) + return RequestStartLine(method, path, version) + + +ResponseStartLine = collections.namedtuple( + "ResponseStartLine", ["version", "code", "reason"] +) + + +_http_response_line_re = re.compile(r"(HTTP/1.[0-9]) ([0-9]+) ([^\r]*)") + + +def parse_response_start_line(line: str) -> ResponseStartLine: + """Returns a (version, code, reason) tuple for an HTTP 1.x response line. + + The response is a `collections.namedtuple`. + + >>> parse_response_start_line("HTTP/1.1 200 OK") + ResponseStartLine(version='HTTP/1.1', code=200, reason='OK') + """ + line = native_str(line) + match = _http_response_line_re.match(line) + if not match: + raise HTTPInputError("Error parsing response start line") + return ResponseStartLine(match.group(1), int(match.group(2)), match.group(3)) + + +# _parseparam and _parse_header are copied and modified from python2.7's cgi.py +# The original 2.7 version of this code did not correctly support some +# combinations of semicolons and double quotes. +# It has also been modified to support valueless parameters as seen in +# websocket extension negotiations, and to support non-ascii values in +# RFC 2231/5987 format. + + +def _parseparam(s: str) -> Generator[str, None, None]: + while s[:1] == ";": + s = s[1:] + end = s.find(";") + while end > 0 and (s.count('"', 0, end) - s.count('\\"', 0, end)) % 2: + end = s.find(";", end + 1) + if end < 0: + end = len(s) + f = s[:end] + yield f.strip() + s = s[end:] + + +def _parse_header(line: str) -> Tuple[str, Dict[str, str]]: + r"""Parse a Content-type like header. + + Return the main content-type and a dictionary of options. + + >>> d = "form-data; foo=\"b\\\\a\\\"r\"; file*=utf-8''T%C3%A4st" + >>> ct, d = _parse_header(d) + >>> ct + 'form-data' + >>> d['file'] == r'T\u00e4st'.encode('ascii').decode('unicode_escape') + True + >>> d['foo'] + 'b\\a"r' + """ + parts = _parseparam(";" + line) + key = next(parts) + # decode_params treats first argument special, but we already stripped key + params = [("Dummy", "value")] + for p in parts: + i = p.find("=") + if i >= 0: + name = p[:i].strip().lower() + value = p[i + 1 :].strip() + params.append((name, native_str(value))) + decoded_params = email.utils.decode_params(params) + decoded_params.pop(0) # get rid of the dummy again + pdict = {} + for name, decoded_value in decoded_params: + value = email.utils.collapse_rfc2231_value(decoded_value) + if len(value) >= 2 and value[0] == '"' and value[-1] == '"': + value = value[1:-1] + pdict[name] = value + return key, pdict + + +def _encode_header(key: str, pdict: Dict[str, str]) -> str: + """Inverse of _parse_header. + + >>> _encode_header('permessage-deflate', + ... {'client_max_window_bits': 15, 'client_no_context_takeover': None}) + 'permessage-deflate; client_max_window_bits=15; client_no_context_takeover' + """ + if not pdict: + return key + out = [key] + # Sort the parameters just to make it easy to test. + for k, v in sorted(pdict.items()): + if v is None: + out.append(k) + else: + # TODO: quote if necessary. + out.append("%s=%s" % (k, v)) + return "; ".join(out) + + +def encode_username_password( + username: Union[str, bytes], password: Union[str, bytes] +) -> bytes: + """Encodes a username/password pair in the format used by HTTP auth. + + The return value is a byte string in the form ``username:password``. + + .. versionadded:: 5.1 + """ + if isinstance(username, unicode_type): + username = unicodedata.normalize("NFC", username) + if isinstance(password, unicode_type): + password = unicodedata.normalize("NFC", password) + return utf8(username) + b":" + utf8(password) + + +def doctests(): + # type: () -> unittest.TestSuite + import doctest + + return doctest.DocTestSuite() + + +_netloc_re = re.compile(r"^(.+):(\d+)$") + + +def split_host_and_port(netloc: str) -> Tuple[str, Optional[int]]: + """Returns ``(host, port)`` tuple from ``netloc``. + + Returned ``port`` will be ``None`` if not present. + + .. versionadded:: 4.1 + """ + match = _netloc_re.match(netloc) + if match: + host = match.group(1) + port = int(match.group(2)) # type: Optional[int] + else: + host = netloc + port = None + return (host, port) + + +def qs_to_qsl(qs: Dict[str, List[AnyStr]]) -> Iterable[Tuple[str, AnyStr]]: + """Generator converting a result of ``parse_qs`` back to name-value pairs. + + .. versionadded:: 5.0 + """ + for k, vs in qs.items(): + for v in vs: + yield (k, v) + + +_OctalPatt = re.compile(r"\\[0-3][0-7][0-7]") +_QuotePatt = re.compile(r"[\\].") +_nulljoin = "".join + + +def _unquote_cookie(s: str) -> str: + """Handle double quotes and escaping in cookie values. + + This method is copied verbatim from the Python 3.5 standard + library (http.cookies._unquote) so we don't have to depend on + non-public interfaces. + """ + # If there aren't any doublequotes, + # then there can't be any special characters. See RFC 2109. + if s is None or len(s) < 2: + return s + if s[0] != '"' or s[-1] != '"': + return s + + # We have to assume that we must decode this string. + # Down to work. + + # Remove the "s + s = s[1:-1] + + # Check for special sequences. Examples: + # \012 --> \n + # \" --> " + # + i = 0 + n = len(s) + res = [] + while 0 <= i < n: + o_match = _OctalPatt.search(s, i) + q_match = _QuotePatt.search(s, i) + if not o_match and not q_match: # Neither matched + res.append(s[i:]) + break + # else: + j = k = -1 + if o_match: + j = o_match.start(0) + if q_match: + k = q_match.start(0) + if q_match and (not o_match or k < j): # QuotePatt matched + res.append(s[i:k]) + res.append(s[k + 1]) + i = k + 2 + else: # OctalPatt matched + res.append(s[i:j]) + res.append(chr(int(s[j + 1 : j + 4], 8))) + i = j + 4 + return _nulljoin(res) + + +def parse_cookie(cookie: str) -> Dict[str, str]: + """Parse a ``Cookie`` HTTP header into a dict of name/value pairs. + + This function attempts to mimic browser cookie parsing behavior; + it specifically does not follow any of the cookie-related RFCs + (because browsers don't either). + + The algorithm used is identical to that used by Django version 1.9.10. + + .. versionadded:: 4.4.2 + """ + cookiedict = {} + for chunk in cookie.split(str(";")): + if str("=") in chunk: + key, val = chunk.split(str("="), 1) + else: + # Assume an empty name per + # https://bugzilla.mozilla.org/show_bug.cgi?id=169091 + key, val = str(""), chunk + key, val = key.strip(), val.strip() + if key or val: + # unquote using Python's algorithm. + cookiedict[key] = _unquote_cookie(val) + return cookiedict diff --git a/venv/lib/python3.8/site-packages/tornado/ioloop.py b/venv/lib/python3.8/site-packages/tornado/ioloop.py new file mode 100644 index 0000000..2cf8844 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/ioloop.py @@ -0,0 +1,944 @@ +# +# Copyright 2009 Facebook +# +# 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. + +"""An I/O event loop for non-blocking sockets. + +In Tornado 6.0, `.IOLoop` is a wrapper around the `asyncio` event +loop, with a slightly different interface for historical reasons. +Applications can use either the `.IOLoop` interface or the underlying +`asyncio` event loop directly (unless compatibility with older +versions of Tornado is desired, in which case `.IOLoop` must be used). + +Typical applications will use a single `IOLoop` object, accessed via +`IOLoop.current` class method. The `IOLoop.start` method (or +equivalently, `asyncio.AbstractEventLoop.run_forever`) should usually +be called at the end of the ``main()`` function. Atypical applications +may use more than one `IOLoop`, such as one `IOLoop` per thread, or +per `unittest` case. + +""" + +import asyncio +import concurrent.futures +import datetime +import functools +import logging +import numbers +import os +import sys +import time +import math +import random + +from tornado.concurrent import ( + Future, + is_future, + chain_future, + future_set_exc_info, + future_add_done_callback, +) +from tornado.log import app_log +from tornado.util import Configurable, TimeoutError, import_object + +import typing +from typing import Union, Any, Type, Optional, Callable, TypeVar, Tuple, Awaitable + +if typing.TYPE_CHECKING: + from typing import Dict, List # noqa: F401 + + from typing_extensions import Protocol +else: + Protocol = object + + +class _Selectable(Protocol): + def fileno(self) -> int: + pass + + def close(self) -> None: + pass + + +_T = TypeVar("_T") +_S = TypeVar("_S", bound=_Selectable) + + +class IOLoop(Configurable): + """An I/O event loop. + + As of Tornado 6.0, `IOLoop` is a wrapper around the `asyncio` event + loop. + + Example usage for a simple TCP server: + + .. testcode:: + + import errno + import functools + import socket + + import tornado.ioloop + from tornado.iostream import IOStream + + async def handle_connection(connection, address): + stream = IOStream(connection) + message = await stream.read_until_close() + print("message from client:", message.decode().strip()) + + def connection_ready(sock, fd, events): + while True: + try: + connection, address = sock.accept() + except BlockingIOError: + return + connection.setblocking(0) + io_loop = tornado.ioloop.IOLoop.current() + io_loop.spawn_callback(handle_connection, connection, address) + + if __name__ == '__main__': + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + sock.setblocking(0) + sock.bind(("", 8888)) + sock.listen(128) + + io_loop = tornado.ioloop.IOLoop.current() + callback = functools.partial(connection_ready, sock) + io_loop.add_handler(sock.fileno(), callback, io_loop.READ) + io_loop.start() + + .. testoutput:: + :hide: + + By default, a newly-constructed `IOLoop` becomes the thread's current + `IOLoop`, unless there already is a current `IOLoop`. This behavior + can be controlled with the ``make_current`` argument to the `IOLoop` + constructor: if ``make_current=True``, the new `IOLoop` will always + try to become current and it raises an error if there is already a + current instance. If ``make_current=False``, the new `IOLoop` will + not try to become current. + + In general, an `IOLoop` cannot survive a fork or be shared across + processes in any way. When multiple processes are being used, each + process should create its own `IOLoop`, which also implies that + any objects which depend on the `IOLoop` (such as + `.AsyncHTTPClient`) must also be created in the child processes. + As a guideline, anything that starts processes (including the + `tornado.process` and `multiprocessing` modules) should do so as + early as possible, ideally the first thing the application does + after loading its configuration in ``main()``. + + .. versionchanged:: 4.2 + Added the ``make_current`` keyword argument to the `IOLoop` + constructor. + + .. versionchanged:: 5.0 + + Uses the `asyncio` event loop by default. The + ``IOLoop.configure`` method cannot be used on Python 3 except + to redundantly specify the `asyncio` event loop. + + """ + + # These constants were originally based on constants from the epoll module. + NONE = 0 + READ = 0x001 + WRITE = 0x004 + ERROR = 0x018 + + # In Python 3, _ioloop_for_asyncio maps from asyncio loops to IOLoops. + _ioloop_for_asyncio = dict() # type: Dict[asyncio.AbstractEventLoop, IOLoop] + + @classmethod + def configure( + cls, impl: "Union[None, str, Type[Configurable]]", **kwargs: Any + ) -> None: + if asyncio is not None: + from tornado.platform.asyncio import BaseAsyncIOLoop + + if isinstance(impl, str): + impl = import_object(impl) + if isinstance(impl, type) and not issubclass(impl, BaseAsyncIOLoop): + raise RuntimeError( + "only AsyncIOLoop is allowed when asyncio is available" + ) + super(IOLoop, cls).configure(impl, **kwargs) + + @staticmethod + def instance() -> "IOLoop": + """Deprecated alias for `IOLoop.current()`. + + .. versionchanged:: 5.0 + + Previously, this method returned a global singleton + `IOLoop`, in contrast with the per-thread `IOLoop` returned + by `current()`. In nearly all cases the two were the same + (when they differed, it was generally used from non-Tornado + threads to communicate back to the main thread's `IOLoop`). + This distinction is not present in `asyncio`, so in order + to facilitate integration with that package `instance()` + was changed to be an alias to `current()`. Applications + using the cross-thread communications aspect of + `instance()` should instead set their own global variable + to point to the `IOLoop` they want to use. + + .. deprecated:: 5.0 + """ + return IOLoop.current() + + def install(self) -> None: + """Deprecated alias for `make_current()`. + + .. versionchanged:: 5.0 + + Previously, this method would set this `IOLoop` as the + global singleton used by `IOLoop.instance()`. Now that + `instance()` is an alias for `current()`, `install()` + is an alias for `make_current()`. + + .. deprecated:: 5.0 + """ + self.make_current() + + @staticmethod + def clear_instance() -> None: + """Deprecated alias for `clear_current()`. + + .. versionchanged:: 5.0 + + Previously, this method would clear the `IOLoop` used as + the global singleton by `IOLoop.instance()`. Now that + `instance()` is an alias for `current()`, + `clear_instance()` is an alias for `clear_current()`. + + .. deprecated:: 5.0 + + """ + IOLoop.clear_current() + + @typing.overload + @staticmethod + def current() -> "IOLoop": + pass + + @typing.overload + @staticmethod + def current(instance: bool = True) -> Optional["IOLoop"]: # noqa: F811 + pass + + @staticmethod + def current(instance: bool = True) -> Optional["IOLoop"]: # noqa: F811 + """Returns the current thread's `IOLoop`. + + If an `IOLoop` is currently running or has been marked as + current by `make_current`, returns that instance. If there is + no current `IOLoop` and ``instance`` is true, creates one. + + .. versionchanged:: 4.1 + Added ``instance`` argument to control the fallback to + `IOLoop.instance()`. + .. versionchanged:: 5.0 + On Python 3, control of the current `IOLoop` is delegated + to `asyncio`, with this and other methods as pass-through accessors. + The ``instance`` argument now controls whether an `IOLoop` + is created automatically when there is none, instead of + whether we fall back to `IOLoop.instance()` (which is now + an alias for this method). ``instance=False`` is deprecated, + since even if we do not create an `IOLoop`, this method + may initialize the asyncio loop. + """ + try: + loop = asyncio.get_event_loop() + except (RuntimeError, AssertionError): + if not instance: + return None + raise + try: + return IOLoop._ioloop_for_asyncio[loop] + except KeyError: + if instance: + from tornado.platform.asyncio import AsyncIOMainLoop + + current = AsyncIOMainLoop(make_current=True) # type: Optional[IOLoop] + else: + current = None + return current + + def make_current(self) -> None: + """Makes this the `IOLoop` for the current thread. + + An `IOLoop` automatically becomes current for its thread + when it is started, but it is sometimes useful to call + `make_current` explicitly before starting the `IOLoop`, + so that code run at startup time can find the right + instance. + + .. versionchanged:: 4.1 + An `IOLoop` created while there is no current `IOLoop` + will automatically become current. + + .. versionchanged:: 5.0 + This method also sets the current `asyncio` event loop. + """ + # The asyncio event loops override this method. + raise NotImplementedError() + + @staticmethod + def clear_current() -> None: + """Clears the `IOLoop` for the current thread. + + Intended primarily for use by test frameworks in between tests. + + .. versionchanged:: 5.0 + This method also clears the current `asyncio` event loop. + """ + old = IOLoop.current(instance=False) + if old is not None: + old._clear_current_hook() + if asyncio is None: + IOLoop._current.instance = None + + def _clear_current_hook(self) -> None: + """Instance method called when an IOLoop ceases to be current. + + May be overridden by subclasses as a counterpart to make_current. + """ + pass + + @classmethod + def configurable_base(cls) -> Type[Configurable]: + return IOLoop + + @classmethod + def configurable_default(cls) -> Type[Configurable]: + from tornado.platform.asyncio import AsyncIOLoop + + return AsyncIOLoop + + def initialize(self, make_current: Optional[bool] = None) -> None: + if make_current is None: + if IOLoop.current(instance=False) is None: + self.make_current() + elif make_current: + current = IOLoop.current(instance=False) + # AsyncIO loops can already be current by this point. + if current is not None and current is not self: + raise RuntimeError("current IOLoop already exists") + self.make_current() + + def close(self, all_fds: bool = False) -> None: + """Closes the `IOLoop`, freeing any resources used. + + If ``all_fds`` is true, all file descriptors registered on the + IOLoop will be closed (not just the ones created by the + `IOLoop` itself). + + Many applications will only use a single `IOLoop` that runs for the + entire lifetime of the process. In that case closing the `IOLoop` + is not necessary since everything will be cleaned up when the + process exits. `IOLoop.close` is provided mainly for scenarios + such as unit tests, which create and destroy a large number of + ``IOLoops``. + + An `IOLoop` must be completely stopped before it can be closed. This + means that `IOLoop.stop()` must be called *and* `IOLoop.start()` must + be allowed to return before attempting to call `IOLoop.close()`. + Therefore the call to `close` will usually appear just after + the call to `start` rather than near the call to `stop`. + + .. versionchanged:: 3.1 + If the `IOLoop` implementation supports non-integer objects + for "file descriptors", those objects will have their + ``close`` method when ``all_fds`` is true. + """ + raise NotImplementedError() + + @typing.overload + def add_handler( + self, fd: int, handler: Callable[[int, int], None], events: int + ) -> None: + pass + + @typing.overload # noqa: F811 + def add_handler( + self, fd: _S, handler: Callable[[_S, int], None], events: int + ) -> None: + pass + + def add_handler( # noqa: F811 + self, fd: Union[int, _Selectable], handler: Callable[..., None], events: int + ) -> None: + """Registers the given handler to receive the given events for ``fd``. + + The ``fd`` argument may either be an integer file descriptor or + a file-like object with a ``fileno()`` and ``close()`` method. + + The ``events`` argument is a bitwise or of the constants + ``IOLoop.READ``, ``IOLoop.WRITE``, and ``IOLoop.ERROR``. + + When an event occurs, ``handler(fd, events)`` will be run. + + .. versionchanged:: 4.0 + Added the ability to pass file-like objects in addition to + raw file descriptors. + """ + raise NotImplementedError() + + def update_handler(self, fd: Union[int, _Selectable], events: int) -> None: + """Changes the events we listen for ``fd``. + + .. versionchanged:: 4.0 + Added the ability to pass file-like objects in addition to + raw file descriptors. + """ + raise NotImplementedError() + + def remove_handler(self, fd: Union[int, _Selectable]) -> None: + """Stop listening for events on ``fd``. + + .. versionchanged:: 4.0 + Added the ability to pass file-like objects in addition to + raw file descriptors. + """ + raise NotImplementedError() + + def start(self) -> None: + """Starts the I/O loop. + + The loop will run until one of the callbacks calls `stop()`, which + will make the loop stop after the current event iteration completes. + """ + raise NotImplementedError() + + def _setup_logging(self) -> None: + """The IOLoop catches and logs exceptions, so it's + important that log output be visible. However, python's + default behavior for non-root loggers (prior to python + 3.2) is to print an unhelpful "no handlers could be + found" message rather than the actual log entry, so we + must explicitly configure logging if we've made it this + far without anything. + + This method should be called from start() in subclasses. + """ + if not any( + [ + logging.getLogger().handlers, + logging.getLogger("tornado").handlers, + logging.getLogger("tornado.application").handlers, + ] + ): + logging.basicConfig() + + def stop(self) -> None: + """Stop the I/O loop. + + If the event loop is not currently running, the next call to `start()` + will return immediately. + + Note that even after `stop` has been called, the `IOLoop` is not + completely stopped until `IOLoop.start` has also returned. + Some work that was scheduled before the call to `stop` may still + be run before the `IOLoop` shuts down. + """ + raise NotImplementedError() + + def run_sync(self, func: Callable, timeout: Optional[float] = None) -> Any: + """Starts the `IOLoop`, runs the given function, and stops the loop. + + The function must return either an awaitable object or + ``None``. If the function returns an awaitable object, the + `IOLoop` will run until the awaitable is resolved (and + `run_sync()` will return the awaitable's result). If it raises + an exception, the `IOLoop` will stop and the exception will be + re-raised to the caller. + + The keyword-only argument ``timeout`` may be used to set + a maximum duration for the function. If the timeout expires, + a `tornado.util.TimeoutError` is raised. + + This method is useful to allow asynchronous calls in a + ``main()`` function:: + + async def main(): + # do stuff... + + if __name__ == '__main__': + IOLoop.current().run_sync(main) + + .. versionchanged:: 4.3 + Returning a non-``None``, non-awaitable value is now an error. + + .. versionchanged:: 5.0 + If a timeout occurs, the ``func`` coroutine will be cancelled. + + """ + future_cell = [None] # type: List[Optional[Future]] + + def run() -> None: + try: + result = func() + if result is not None: + from tornado.gen import convert_yielded + + result = convert_yielded(result) + except Exception: + fut = Future() # type: Future[Any] + future_cell[0] = fut + future_set_exc_info(fut, sys.exc_info()) + else: + if is_future(result): + future_cell[0] = result + else: + fut = Future() + future_cell[0] = fut + fut.set_result(result) + assert future_cell[0] is not None + self.add_future(future_cell[0], lambda future: self.stop()) + + self.add_callback(run) + if timeout is not None: + + def timeout_callback() -> None: + # If we can cancel the future, do so and wait on it. If not, + # Just stop the loop and return with the task still pending. + # (If we neither cancel nor wait for the task, a warning + # will be logged). + assert future_cell[0] is not None + if not future_cell[0].cancel(): + self.stop() + + timeout_handle = self.add_timeout(self.time() + timeout, timeout_callback) + self.start() + if timeout is not None: + self.remove_timeout(timeout_handle) + assert future_cell[0] is not None + if future_cell[0].cancelled() or not future_cell[0].done(): + raise TimeoutError("Operation timed out after %s seconds" % timeout) + return future_cell[0].result() + + def time(self) -> float: + """Returns the current time according to the `IOLoop`'s clock. + + The return value is a floating-point number relative to an + unspecified time in the past. + + Historically, the IOLoop could be customized to use e.g. + `time.monotonic` instead of `time.time`, but this is not + currently supported and so this method is equivalent to + `time.time`. + + """ + return time.time() + + def add_timeout( + self, + deadline: Union[float, datetime.timedelta], + callback: Callable[..., None], + *args: Any, + **kwargs: Any + ) -> object: + """Runs the ``callback`` at the time ``deadline`` from the I/O loop. + + Returns an opaque handle that may be passed to + `remove_timeout` to cancel. + + ``deadline`` may be a number denoting a time (on the same + scale as `IOLoop.time`, normally `time.time`), or a + `datetime.timedelta` object for a deadline relative to the + current time. Since Tornado 4.0, `call_later` is a more + convenient alternative for the relative case since it does not + require a timedelta object. + + Note that it is not safe to call `add_timeout` from other threads. + Instead, you must use `add_callback` to transfer control to the + `IOLoop`'s thread, and then call `add_timeout` from there. + + Subclasses of IOLoop must implement either `add_timeout` or + `call_at`; the default implementations of each will call + the other. `call_at` is usually easier to implement, but + subclasses that wish to maintain compatibility with Tornado + versions prior to 4.0 must use `add_timeout` instead. + + .. versionchanged:: 4.0 + Now passes through ``*args`` and ``**kwargs`` to the callback. + """ + if isinstance(deadline, numbers.Real): + return self.call_at(deadline, callback, *args, **kwargs) + elif isinstance(deadline, datetime.timedelta): + return self.call_at( + self.time() + deadline.total_seconds(), callback, *args, **kwargs + ) + else: + raise TypeError("Unsupported deadline %r" % deadline) + + def call_later( + self, delay: float, callback: Callable[..., None], *args: Any, **kwargs: Any + ) -> object: + """Runs the ``callback`` after ``delay`` seconds have passed. + + Returns an opaque handle that may be passed to `remove_timeout` + to cancel. Note that unlike the `asyncio` method of the same + name, the returned object does not have a ``cancel()`` method. + + See `add_timeout` for comments on thread-safety and subclassing. + + .. versionadded:: 4.0 + """ + return self.call_at(self.time() + delay, callback, *args, **kwargs) + + def call_at( + self, when: float, callback: Callable[..., None], *args: Any, **kwargs: Any + ) -> object: + """Runs the ``callback`` at the absolute time designated by ``when``. + + ``when`` must be a number using the same reference point as + `IOLoop.time`. + + Returns an opaque handle that may be passed to `remove_timeout` + to cancel. Note that unlike the `asyncio` method of the same + name, the returned object does not have a ``cancel()`` method. + + See `add_timeout` for comments on thread-safety and subclassing. + + .. versionadded:: 4.0 + """ + return self.add_timeout(when, callback, *args, **kwargs) + + def remove_timeout(self, timeout: object) -> None: + """Cancels a pending timeout. + + The argument is a handle as returned by `add_timeout`. It is + safe to call `remove_timeout` even if the callback has already + been run. + """ + raise NotImplementedError() + + def add_callback(self, callback: Callable, *args: Any, **kwargs: Any) -> None: + """Calls the given callback on the next I/O loop iteration. + + It is safe to call this method from any thread at any time, + except from a signal handler. Note that this is the **only** + method in `IOLoop` that makes this thread-safety guarantee; all + other interaction with the `IOLoop` must be done from that + `IOLoop`'s thread. `add_callback()` may be used to transfer + control from other threads to the `IOLoop`'s thread. + + To add a callback from a signal handler, see + `add_callback_from_signal`. + """ + raise NotImplementedError() + + def add_callback_from_signal( + self, callback: Callable, *args: Any, **kwargs: Any + ) -> None: + """Calls the given callback on the next I/O loop iteration. + + Safe for use from a Python signal handler; should not be used + otherwise. + """ + raise NotImplementedError() + + def spawn_callback(self, callback: Callable, *args: Any, **kwargs: Any) -> None: + """Calls the given callback on the next IOLoop iteration. + + As of Tornado 6.0, this method is equivalent to `add_callback`. + + .. versionadded:: 4.0 + """ + self.add_callback(callback, *args, **kwargs) + + def add_future( + self, + future: "Union[Future[_T], concurrent.futures.Future[_T]]", + callback: Callable[["Future[_T]"], None], + ) -> None: + """Schedules a callback on the ``IOLoop`` when the given + `.Future` is finished. + + The callback is invoked with one argument, the + `.Future`. + + This method only accepts `.Future` objects and not other + awaitables (unlike most of Tornado where the two are + interchangeable). + """ + if isinstance(future, Future): + # Note that we specifically do not want the inline behavior of + # tornado.concurrent.future_add_done_callback. We always want + # this callback scheduled on the next IOLoop iteration (which + # asyncio.Future always does). + # + # Wrap the callback in self._run_callback so we control + # the error logging (i.e. it goes to tornado.log.app_log + # instead of asyncio's log). + future.add_done_callback( + lambda f: self._run_callback(functools.partial(callback, future)) + ) + else: + assert is_future(future) + # For concurrent futures, we use self.add_callback, so + # it's fine if future_add_done_callback inlines that call. + future_add_done_callback( + future, lambda f: self.add_callback(callback, future) + ) + + def run_in_executor( + self, + executor: Optional[concurrent.futures.Executor], + func: Callable[..., _T], + *args: Any + ) -> Awaitable[_T]: + """Runs a function in a ``concurrent.futures.Executor``. If + ``executor`` is ``None``, the IO loop's default executor will be used. + + Use `functools.partial` to pass keyword arguments to ``func``. + + .. versionadded:: 5.0 + """ + if executor is None: + if not hasattr(self, "_executor"): + from tornado.process import cpu_count + + self._executor = concurrent.futures.ThreadPoolExecutor( + max_workers=(cpu_count() * 5) + ) # type: concurrent.futures.Executor + executor = self._executor + c_future = executor.submit(func, *args) + # Concurrent Futures are not usable with await. Wrap this in a + # Tornado Future instead, using self.add_future for thread-safety. + t_future = Future() # type: Future[_T] + self.add_future(c_future, lambda f: chain_future(f, t_future)) + return t_future + + def set_default_executor(self, executor: concurrent.futures.Executor) -> None: + """Sets the default executor to use with :meth:`run_in_executor`. + + .. versionadded:: 5.0 + """ + self._executor = executor + + def _run_callback(self, callback: Callable[[], Any]) -> None: + """Runs a callback with error handling. + + .. versionchanged:: 6.0 + + CancelledErrors are no longer logged. + """ + try: + ret = callback() + if ret is not None: + from tornado import gen + + # Functions that return Futures typically swallow all + # exceptions and store them in the Future. If a Future + # makes it out to the IOLoop, ensure its exception (if any) + # gets logged too. + try: + ret = gen.convert_yielded(ret) + except gen.BadYieldError: + # It's not unusual for add_callback to be used with + # methods returning a non-None and non-yieldable + # result, which should just be ignored. + pass + else: + self.add_future(ret, self._discard_future_result) + except asyncio.CancelledError: + pass + except Exception: + app_log.error("Exception in callback %r", callback, exc_info=True) + + def _discard_future_result(self, future: Future) -> None: + """Avoid unhandled-exception warnings from spawned coroutines.""" + future.result() + + def split_fd( + self, fd: Union[int, _Selectable] + ) -> Tuple[int, Union[int, _Selectable]]: + # """Returns an (fd, obj) pair from an ``fd`` parameter. + + # We accept both raw file descriptors and file-like objects as + # input to `add_handler` and related methods. When a file-like + # object is passed, we must retain the object itself so we can + # close it correctly when the `IOLoop` shuts down, but the + # poller interfaces favor file descriptors (they will accept + # file-like objects and call ``fileno()`` for you, but they + # always return the descriptor itself). + + # This method is provided for use by `IOLoop` subclasses and should + # not generally be used by application code. + + # .. versionadded:: 4.0 + # """ + if isinstance(fd, int): + return fd, fd + return fd.fileno(), fd + + def close_fd(self, fd: Union[int, _Selectable]) -> None: + # """Utility method to close an ``fd``. + + # If ``fd`` is a file-like object, we close it directly; otherwise + # we use `os.close`. + + # This method is provided for use by `IOLoop` subclasses (in + # implementations of ``IOLoop.close(all_fds=True)`` and should + # not generally be used by application code. + + # .. versionadded:: 4.0 + # """ + try: + if isinstance(fd, int): + os.close(fd) + else: + fd.close() + except OSError: + pass + + +class _Timeout(object): + """An IOLoop timeout, a UNIX timestamp and a callback""" + + # Reduce memory overhead when there are lots of pending callbacks + __slots__ = ["deadline", "callback", "tdeadline"] + + def __init__( + self, deadline: float, callback: Callable[[], None], io_loop: IOLoop + ) -> None: + if not isinstance(deadline, numbers.Real): + raise TypeError("Unsupported deadline %r" % deadline) + self.deadline = deadline + self.callback = callback + self.tdeadline = ( + deadline, + next(io_loop._timeout_counter), + ) # type: Tuple[float, int] + + # Comparison methods to sort by deadline, with object id as a tiebreaker + # to guarantee a consistent ordering. The heapq module uses __le__ + # in python2.5, and __lt__ in 2.6+ (sort() and most other comparisons + # use __lt__). + def __lt__(self, other: "_Timeout") -> bool: + return self.tdeadline < other.tdeadline + + def __le__(self, other: "_Timeout") -> bool: + return self.tdeadline <= other.tdeadline + + +class PeriodicCallback(object): + """Schedules the given callback to be called periodically. + + The callback is called every ``callback_time`` milliseconds. + Note that the timeout is given in milliseconds, while most other + time-related functions in Tornado use seconds. + + If ``jitter`` is specified, each callback time will be randomly selected + within a window of ``jitter * callback_time`` milliseconds. + Jitter can be used to reduce alignment of events with similar periods. + A jitter of 0.1 means allowing a 10% variation in callback time. + The window is centered on ``callback_time`` so the total number of calls + within a given interval should not be significantly affected by adding + jitter. + + If the callback runs for longer than ``callback_time`` milliseconds, + subsequent invocations will be skipped to get back on schedule. + + `start` must be called after the `PeriodicCallback` is created. + + .. versionchanged:: 5.0 + The ``io_loop`` argument (deprecated since version 4.1) has been removed. + + .. versionchanged:: 5.1 + The ``jitter`` argument is added. + """ + + def __init__( + self, callback: Callable[[], None], callback_time: float, jitter: float = 0 + ) -> None: + self.callback = callback + if callback_time <= 0: + raise ValueError("Periodic callback must have a positive callback_time") + self.callback_time = callback_time + self.jitter = jitter + self._running = False + self._timeout = None # type: object + + def start(self) -> None: + """Starts the timer.""" + # Looking up the IOLoop here allows to first instantiate the + # PeriodicCallback in another thread, then start it using + # IOLoop.add_callback(). + self.io_loop = IOLoop.current() + self._running = True + self._next_timeout = self.io_loop.time() + self._schedule_next() + + def stop(self) -> None: + """Stops the timer.""" + self._running = False + if self._timeout is not None: + self.io_loop.remove_timeout(self._timeout) + self._timeout = None + + def is_running(self) -> bool: + """Returns ``True`` if this `.PeriodicCallback` has been started. + + .. versionadded:: 4.1 + """ + return self._running + + def _run(self) -> None: + if not self._running: + return + try: + return self.callback() + except Exception: + app_log.error("Exception in callback %r", self.callback, exc_info=True) + finally: + self._schedule_next() + + def _schedule_next(self) -> None: + if self._running: + self._update_next(self.io_loop.time()) + self._timeout = self.io_loop.add_timeout(self._next_timeout, self._run) + + def _update_next(self, current_time: float) -> None: + callback_time_sec = self.callback_time / 1000.0 + if self.jitter: + # apply jitter fraction + callback_time_sec *= 1 + (self.jitter * (random.random() - 0.5)) + if self._next_timeout <= current_time: + # The period should be measured from the start of one call + # to the start of the next. If one call takes too long, + # skip cycles to get back to a multiple of the original + # schedule. + self._next_timeout += ( + math.floor((current_time - self._next_timeout) / callback_time_sec) + 1 + ) * callback_time_sec + else: + # If the clock moved backwards, ensure we advance the next + # timeout instead of recomputing the same value again. + # This may result in long gaps between callbacks if the + # clock jumps backwards by a lot, but the far more common + # scenario is a small NTP adjustment that should just be + # ignored. + # + # Note that on some systems if time.time() runs slower + # than time.monotonic() (most common on windows), we + # effectively experience a small backwards time jump on + # every iteration because PeriodicCallback uses + # time.time() while asyncio schedules callbacks using + # time.monotonic(). + # https://github.com/tornadoweb/tornado/issues/2333 + self._next_timeout += callback_time_sec diff --git a/venv/lib/python3.8/site-packages/tornado/iostream.py b/venv/lib/python3.8/site-packages/tornado/iostream.py new file mode 100644 index 0000000..19c5485 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/iostream.py @@ -0,0 +1,1660 @@ +# +# Copyright 2009 Facebook +# +# 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. + +"""Utility classes to write to and read from non-blocking files and sockets. + +Contents: + +* `BaseIOStream`: Generic interface for reading and writing. +* `IOStream`: Implementation of BaseIOStream using non-blocking sockets. +* `SSLIOStream`: SSL-aware version of IOStream. +* `PipeIOStream`: Pipe-based IOStream implementation. +""" + +import asyncio +import collections +import errno +import io +import numbers +import os +import socket +import ssl +import sys +import re + +from tornado.concurrent import Future, future_set_result_unless_cancelled +from tornado import ioloop +from tornado.log import gen_log +from tornado.netutil import ssl_wrap_socket, _client_ssl_defaults, _server_ssl_defaults +from tornado.util import errno_from_exception + +import typing +from typing import ( + Union, + Optional, + Awaitable, + Callable, + Pattern, + Any, + Dict, + TypeVar, + Tuple, +) +from types import TracebackType + +if typing.TYPE_CHECKING: + from typing import Deque, List, Type # noqa: F401 + +_IOStreamType = TypeVar("_IOStreamType", bound="IOStream") + +# These errnos indicate that a connection has been abruptly terminated. +# They should be caught and handled less noisily than other errors. +_ERRNO_CONNRESET = (errno.ECONNRESET, errno.ECONNABORTED, errno.EPIPE, errno.ETIMEDOUT) + +if hasattr(errno, "WSAECONNRESET"): + _ERRNO_CONNRESET += ( # type: ignore + errno.WSAECONNRESET, # type: ignore + errno.WSAECONNABORTED, # type: ignore + errno.WSAETIMEDOUT, # type: ignore + ) + +if sys.platform == "darwin": + # OSX appears to have a race condition that causes send(2) to return + # EPROTOTYPE if called while a socket is being torn down: + # http://erickt.github.io/blog/2014/11/19/adventures-in-debugging-a-potential-osx-kernel-bug/ + # Since the socket is being closed anyway, treat this as an ECONNRESET + # instead of an unexpected error. + _ERRNO_CONNRESET += (errno.EPROTOTYPE,) # type: ignore + +_WINDOWS = sys.platform.startswith("win") + + +class StreamClosedError(IOError): + """Exception raised by `IOStream` methods when the stream is closed. + + Note that the close callback is scheduled to run *after* other + callbacks on the stream (to allow for buffered data to be processed), + so you may see this error before you see the close callback. + + The ``real_error`` attribute contains the underlying error that caused + the stream to close (if any). + + .. versionchanged:: 4.3 + Added the ``real_error`` attribute. + """ + + def __init__(self, real_error: Optional[BaseException] = None) -> None: + super().__init__("Stream is closed") + self.real_error = real_error + + +class UnsatisfiableReadError(Exception): + """Exception raised when a read cannot be satisfied. + + Raised by ``read_until`` and ``read_until_regex`` with a ``max_bytes`` + argument. + """ + + pass + + +class StreamBufferFullError(Exception): + """Exception raised by `IOStream` methods when the buffer is full. + """ + + +class _StreamBuffer(object): + """ + A specialized buffer that tries to avoid copies when large pieces + of data are encountered. + """ + + def __init__(self) -> None: + # A sequence of (False, bytearray) and (True, memoryview) objects + self._buffers = ( + collections.deque() + ) # type: Deque[Tuple[bool, Union[bytearray, memoryview]]] + # Position in the first buffer + self._first_pos = 0 + self._size = 0 + + def __len__(self) -> int: + return self._size + + # Data above this size will be appended separately instead + # of extending an existing bytearray + _large_buf_threshold = 2048 + + def append(self, data: Union[bytes, bytearray, memoryview]) -> None: + """ + Append the given piece of data (should be a buffer-compatible object). + """ + size = len(data) + if size > self._large_buf_threshold: + if not isinstance(data, memoryview): + data = memoryview(data) + self._buffers.append((True, data)) + elif size > 0: + if self._buffers: + is_memview, b = self._buffers[-1] + new_buf = is_memview or len(b) >= self._large_buf_threshold + else: + new_buf = True + if new_buf: + self._buffers.append((False, bytearray(data))) + else: + b += data # type: ignore + + self._size += size + + def peek(self, size: int) -> memoryview: + """ + Get a view over at most ``size`` bytes (possibly fewer) at the + current buffer position. + """ + assert size > 0 + try: + is_memview, b = self._buffers[0] + except IndexError: + return memoryview(b"") + + pos = self._first_pos + if is_memview: + return typing.cast(memoryview, b[pos : pos + size]) + else: + return memoryview(b)[pos : pos + size] + + def advance(self, size: int) -> None: + """ + Advance the current buffer position by ``size`` bytes. + """ + assert 0 < size <= self._size + self._size -= size + pos = self._first_pos + + buffers = self._buffers + while buffers and size > 0: + is_large, b = buffers[0] + b_remain = len(b) - size - pos + if b_remain <= 0: + buffers.popleft() + size -= len(b) - pos + pos = 0 + elif is_large: + pos += size + size = 0 + else: + # Amortized O(1) shrink for Python 2 + pos += size + if len(b) <= 2 * pos: + del typing.cast(bytearray, b)[:pos] + pos = 0 + size = 0 + + assert size == 0 + self._first_pos = pos + + +class BaseIOStream(object): + """A utility class to write to and read from a non-blocking file or socket. + + We support a non-blocking ``write()`` and a family of ``read_*()`` + methods. When the operation completes, the ``Awaitable`` will resolve + with the data read (or ``None`` for ``write()``). All outstanding + ``Awaitables`` will resolve with a `StreamClosedError` when the + stream is closed; `.BaseIOStream.set_close_callback` can also be used + to be notified of a closed stream. + + When a stream is closed due to an error, the IOStream's ``error`` + attribute contains the exception object. + + Subclasses must implement `fileno`, `close_fd`, `write_to_fd`, + `read_from_fd`, and optionally `get_fd_error`. + + """ + + def __init__( + self, + max_buffer_size: Optional[int] = None, + read_chunk_size: Optional[int] = None, + max_write_buffer_size: Optional[int] = None, + ) -> None: + """`BaseIOStream` constructor. + + :arg max_buffer_size: Maximum amount of incoming data to buffer; + defaults to 100MB. + :arg read_chunk_size: Amount of data to read at one time from the + underlying transport; defaults to 64KB. + :arg max_write_buffer_size: Amount of outgoing data to buffer; + defaults to unlimited. + + .. versionchanged:: 4.0 + Add the ``max_write_buffer_size`` parameter. Changed default + ``read_chunk_size`` to 64KB. + .. versionchanged:: 5.0 + The ``io_loop`` argument (deprecated since version 4.1) has been + removed. + """ + self.io_loop = ioloop.IOLoop.current() + self.max_buffer_size = max_buffer_size or 104857600 + # A chunk size that is too close to max_buffer_size can cause + # spurious failures. + self.read_chunk_size = min(read_chunk_size or 65536, self.max_buffer_size // 2) + self.max_write_buffer_size = max_write_buffer_size + self.error = None # type: Optional[BaseException] + self._read_buffer = bytearray() + self._read_buffer_pos = 0 + self._read_buffer_size = 0 + self._user_read_buffer = False + self._after_user_read_buffer = None # type: Optional[bytearray] + self._write_buffer = _StreamBuffer() + self._total_write_index = 0 + self._total_write_done_index = 0 + self._read_delimiter = None # type: Optional[bytes] + self._read_regex = None # type: Optional[Pattern] + self._read_max_bytes = None # type: Optional[int] + self._read_bytes = None # type: Optional[int] + self._read_partial = False + self._read_until_close = False + self._read_future = None # type: Optional[Future] + self._write_futures = ( + collections.deque() + ) # type: Deque[Tuple[int, Future[None]]] + self._close_callback = None # type: Optional[Callable[[], None]] + self._connect_future = None # type: Optional[Future[IOStream]] + # _ssl_connect_future should be defined in SSLIOStream + # but it's here so we can clean it up in _signal_closed + # TODO: refactor that so subclasses can add additional futures + # to be cancelled. + self._ssl_connect_future = None # type: Optional[Future[SSLIOStream]] + self._connecting = False + self._state = None # type: Optional[int] + self._closed = False + + def fileno(self) -> Union[int, ioloop._Selectable]: + """Returns the file descriptor for this stream.""" + raise NotImplementedError() + + def close_fd(self) -> None: + """Closes the file underlying this stream. + + ``close_fd`` is called by `BaseIOStream` and should not be called + elsewhere; other users should call `close` instead. + """ + raise NotImplementedError() + + def write_to_fd(self, data: memoryview) -> int: + """Attempts to write ``data`` to the underlying file. + + Returns the number of bytes written. + """ + raise NotImplementedError() + + def read_from_fd(self, buf: Union[bytearray, memoryview]) -> Optional[int]: + """Attempts to read from the underlying file. + + Reads up to ``len(buf)`` bytes, storing them in the buffer. + Returns the number of bytes read. Returns None if there was + nothing to read (the socket returned `~errno.EWOULDBLOCK` or + equivalent), and zero on EOF. + + .. versionchanged:: 5.0 + + Interface redesigned to take a buffer and return a number + of bytes instead of a freshly-allocated object. + """ + raise NotImplementedError() + + def get_fd_error(self) -> Optional[Exception]: + """Returns information about any error on the underlying file. + + This method is called after the `.IOLoop` has signaled an error on the + file descriptor, and should return an Exception (such as `socket.error` + with additional information, or None if no such information is + available. + """ + return None + + def read_until_regex( + self, regex: bytes, max_bytes: Optional[int] = None + ) -> Awaitable[bytes]: + """Asynchronously read until we have matched the given regex. + + The result includes the data that matches the regex and anything + that came before it. + + If ``max_bytes`` is not None, the connection will be closed + if more than ``max_bytes`` bytes have been read and the regex is + not satisfied. + + .. versionchanged:: 4.0 + Added the ``max_bytes`` argument. The ``callback`` argument is + now optional and a `.Future` will be returned if it is omitted. + + .. versionchanged:: 6.0 + + The ``callback`` argument was removed. Use the returned + `.Future` instead. + + """ + future = self._start_read() + self._read_regex = re.compile(regex) + self._read_max_bytes = max_bytes + try: + self._try_inline_read() + except UnsatisfiableReadError as e: + # Handle this the same way as in _handle_events. + gen_log.info("Unsatisfiable read, closing connection: %s" % e) + self.close(exc_info=e) + return future + except: + # Ensure that the future doesn't log an error because its + # failure was never examined. + future.add_done_callback(lambda f: f.exception()) + raise + return future + + def read_until( + self, delimiter: bytes, max_bytes: Optional[int] = None + ) -> Awaitable[bytes]: + """Asynchronously read until we have found the given delimiter. + + The result includes all the data read including the delimiter. + + If ``max_bytes`` is not None, the connection will be closed + if more than ``max_bytes`` bytes have been read and the delimiter + is not found. + + .. versionchanged:: 4.0 + Added the ``max_bytes`` argument. The ``callback`` argument is + now optional and a `.Future` will be returned if it is omitted. + + .. versionchanged:: 6.0 + + The ``callback`` argument was removed. Use the returned + `.Future` instead. + """ + future = self._start_read() + self._read_delimiter = delimiter + self._read_max_bytes = max_bytes + try: + self._try_inline_read() + except UnsatisfiableReadError as e: + # Handle this the same way as in _handle_events. + gen_log.info("Unsatisfiable read, closing connection: %s" % e) + self.close(exc_info=e) + return future + except: + future.add_done_callback(lambda f: f.exception()) + raise + return future + + def read_bytes(self, num_bytes: int, partial: bool = False) -> Awaitable[bytes]: + """Asynchronously read a number of bytes. + + If ``partial`` is true, data is returned as soon as we have + any bytes to return (but never more than ``num_bytes``) + + .. versionchanged:: 4.0 + Added the ``partial`` argument. The callback argument is now + optional and a `.Future` will be returned if it is omitted. + + .. versionchanged:: 6.0 + + The ``callback`` and ``streaming_callback`` arguments have + been removed. Use the returned `.Future` (and + ``partial=True`` for ``streaming_callback``) instead. + + """ + future = self._start_read() + assert isinstance(num_bytes, numbers.Integral) + self._read_bytes = num_bytes + self._read_partial = partial + try: + self._try_inline_read() + except: + future.add_done_callback(lambda f: f.exception()) + raise + return future + + def read_into(self, buf: bytearray, partial: bool = False) -> Awaitable[int]: + """Asynchronously read a number of bytes. + + ``buf`` must be a writable buffer into which data will be read. + + If ``partial`` is true, the callback is run as soon as any bytes + have been read. Otherwise, it is run when the ``buf`` has been + entirely filled with read data. + + .. versionadded:: 5.0 + + .. versionchanged:: 6.0 + + The ``callback`` argument was removed. Use the returned + `.Future` instead. + + """ + future = self._start_read() + + # First copy data already in read buffer + available_bytes = self._read_buffer_size + n = len(buf) + if available_bytes >= n: + end = self._read_buffer_pos + n + buf[:] = memoryview(self._read_buffer)[self._read_buffer_pos : end] + del self._read_buffer[:end] + self._after_user_read_buffer = self._read_buffer + elif available_bytes > 0: + buf[:available_bytes] = memoryview(self._read_buffer)[ + self._read_buffer_pos : + ] + + # Set up the supplied buffer as our temporary read buffer. + # The original (if it had any data remaining) has been + # saved for later. + self._user_read_buffer = True + self._read_buffer = buf + self._read_buffer_pos = 0 + self._read_buffer_size = available_bytes + self._read_bytes = n + self._read_partial = partial + + try: + self._try_inline_read() + except: + future.add_done_callback(lambda f: f.exception()) + raise + return future + + def read_until_close(self) -> Awaitable[bytes]: + """Asynchronously reads all data from the socket until it is closed. + + This will buffer all available data until ``max_buffer_size`` + is reached. If flow control or cancellation are desired, use a + loop with `read_bytes(partial=True) <.read_bytes>` instead. + + .. versionchanged:: 4.0 + The callback argument is now optional and a `.Future` will + be returned if it is omitted. + + .. versionchanged:: 6.0 + + The ``callback`` and ``streaming_callback`` arguments have + been removed. Use the returned `.Future` (and `read_bytes` + with ``partial=True`` for ``streaming_callback``) instead. + + """ + future = self._start_read() + if self.closed(): + self._finish_read(self._read_buffer_size, False) + return future + self._read_until_close = True + try: + self._try_inline_read() + except: + future.add_done_callback(lambda f: f.exception()) + raise + return future + + def write(self, data: Union[bytes, memoryview]) -> "Future[None]": + """Asynchronously write the given data to this stream. + + This method returns a `.Future` that resolves (with a result + of ``None``) when the write has been completed. + + The ``data`` argument may be of type `bytes` or `memoryview`. + + .. versionchanged:: 4.0 + Now returns a `.Future` if no callback is given. + + .. versionchanged:: 4.5 + Added support for `memoryview` arguments. + + .. versionchanged:: 6.0 + + The ``callback`` argument was removed. Use the returned + `.Future` instead. + + """ + self._check_closed() + if data: + if ( + self.max_write_buffer_size is not None + and len(self._write_buffer) + len(data) > self.max_write_buffer_size + ): + raise StreamBufferFullError("Reached maximum write buffer size") + self._write_buffer.append(data) + self._total_write_index += len(data) + future = Future() # type: Future[None] + future.add_done_callback(lambda f: f.exception()) + self._write_futures.append((self._total_write_index, future)) + if not self._connecting: + self._handle_write() + if self._write_buffer: + self._add_io_state(self.io_loop.WRITE) + self._maybe_add_error_listener() + return future + + def set_close_callback(self, callback: Optional[Callable[[], None]]) -> None: + """Call the given callback when the stream is closed. + + This mostly is not necessary for applications that use the + `.Future` interface; all outstanding ``Futures`` will resolve + with a `StreamClosedError` when the stream is closed. However, + it is still useful as a way to signal that the stream has been + closed while no other read or write is in progress. + + Unlike other callback-based interfaces, ``set_close_callback`` + was not removed in Tornado 6.0. + """ + self._close_callback = callback + self._maybe_add_error_listener() + + def close( + self, + exc_info: Union[ + None, + bool, + BaseException, + Tuple[ + "Optional[Type[BaseException]]", + Optional[BaseException], + Optional[TracebackType], + ], + ] = False, + ) -> None: + """Close this stream. + + If ``exc_info`` is true, set the ``error`` attribute to the current + exception from `sys.exc_info` (or if ``exc_info`` is a tuple, + use that instead of `sys.exc_info`). + """ + if not self.closed(): + if exc_info: + if isinstance(exc_info, tuple): + self.error = exc_info[1] + elif isinstance(exc_info, BaseException): + self.error = exc_info + else: + exc_info = sys.exc_info() + if any(exc_info): + self.error = exc_info[1] + if self._read_until_close: + self._read_until_close = False + self._finish_read(self._read_buffer_size, False) + elif self._read_future is not None: + # resolve reads that are pending and ready to complete + try: + pos = self._find_read_pos() + except UnsatisfiableReadError: + pass + else: + if pos is not None: + self._read_from_buffer(pos) + if self._state is not None: + self.io_loop.remove_handler(self.fileno()) + self._state = None + self.close_fd() + self._closed = True + self._signal_closed() + + def _signal_closed(self) -> None: + futures = [] # type: List[Future] + if self._read_future is not None: + futures.append(self._read_future) + self._read_future = None + futures += [future for _, future in self._write_futures] + self._write_futures.clear() + if self._connect_future is not None: + futures.append(self._connect_future) + self._connect_future = None + for future in futures: + if not future.done(): + future.set_exception(StreamClosedError(real_error=self.error)) + # Reference the exception to silence warnings. Annoyingly, + # this raises if the future was cancelled, but just + # returns any other error. + try: + future.exception() + except asyncio.CancelledError: + pass + if self._ssl_connect_future is not None: + # _ssl_connect_future expects to see the real exception (typically + # an ssl.SSLError), not just StreamClosedError. + if not self._ssl_connect_future.done(): + if self.error is not None: + self._ssl_connect_future.set_exception(self.error) + else: + self._ssl_connect_future.set_exception(StreamClosedError()) + self._ssl_connect_future.exception() + self._ssl_connect_future = None + if self._close_callback is not None: + cb = self._close_callback + self._close_callback = None + self.io_loop.add_callback(cb) + # Clear the buffers so they can be cleared immediately even + # if the IOStream object is kept alive by a reference cycle. + # TODO: Clear the read buffer too; it currently breaks some tests. + self._write_buffer = None # type: ignore + + def reading(self) -> bool: + """Returns ``True`` if we are currently reading from the stream.""" + return self._read_future is not None + + def writing(self) -> bool: + """Returns ``True`` if we are currently writing to the stream.""" + return bool(self._write_buffer) + + def closed(self) -> bool: + """Returns ``True`` if the stream has been closed.""" + return self._closed + + def set_nodelay(self, value: bool) -> None: + """Sets the no-delay flag for this stream. + + By default, data written to TCP streams may be held for a time + to make the most efficient use of bandwidth (according to + Nagle's algorithm). The no-delay flag requests that data be + written as soon as possible, even if doing so would consume + additional bandwidth. + + This flag is currently defined only for TCP-based ``IOStreams``. + + .. versionadded:: 3.1 + """ + pass + + def _handle_connect(self) -> None: + raise NotImplementedError() + + def _handle_events(self, fd: Union[int, ioloop._Selectable], events: int) -> None: + if self.closed(): + gen_log.warning("Got events for closed stream %s", fd) + return + try: + if self._connecting: + # Most IOLoops will report a write failed connect + # with the WRITE event, but SelectIOLoop reports a + # READ as well so we must check for connecting before + # either. + self._handle_connect() + if self.closed(): + return + if events & self.io_loop.READ: + self._handle_read() + if self.closed(): + return + if events & self.io_loop.WRITE: + self._handle_write() + if self.closed(): + return + if events & self.io_loop.ERROR: + self.error = self.get_fd_error() + # We may have queued up a user callback in _handle_read or + # _handle_write, so don't close the IOStream until those + # callbacks have had a chance to run. + self.io_loop.add_callback(self.close) + return + state = self.io_loop.ERROR + if self.reading(): + state |= self.io_loop.READ + if self.writing(): + state |= self.io_loop.WRITE + if state == self.io_loop.ERROR and self._read_buffer_size == 0: + # If the connection is idle, listen for reads too so + # we can tell if the connection is closed. If there is + # data in the read buffer we won't run the close callback + # yet anyway, so we don't need to listen in this case. + state |= self.io_loop.READ + if state != self._state: + assert ( + self._state is not None + ), "shouldn't happen: _handle_events without self._state" + self._state = state + self.io_loop.update_handler(self.fileno(), self._state) + except UnsatisfiableReadError as e: + gen_log.info("Unsatisfiable read, closing connection: %s" % e) + self.close(exc_info=e) + except Exception as e: + gen_log.error("Uncaught exception, closing connection.", exc_info=True) + self.close(exc_info=e) + raise + + def _read_to_buffer_loop(self) -> Optional[int]: + # This method is called from _handle_read and _try_inline_read. + if self._read_bytes is not None: + target_bytes = self._read_bytes # type: Optional[int] + elif self._read_max_bytes is not None: + target_bytes = self._read_max_bytes + elif self.reading(): + # For read_until without max_bytes, or + # read_until_close, read as much as we can before + # scanning for the delimiter. + target_bytes = None + else: + target_bytes = 0 + next_find_pos = 0 + while not self.closed(): + # Read from the socket until we get EWOULDBLOCK or equivalent. + # SSL sockets do some internal buffering, and if the data is + # sitting in the SSL object's buffer select() and friends + # can't see it; the only way to find out if it's there is to + # try to read it. + if self._read_to_buffer() == 0: + break + + # If we've read all the bytes we can use, break out of + # this loop. + + # If we've reached target_bytes, we know we're done. + if target_bytes is not None and self._read_buffer_size >= target_bytes: + break + + # Otherwise, we need to call the more expensive find_read_pos. + # It's inefficient to do this on every read, so instead + # do it on the first read and whenever the read buffer + # size has doubled. + if self._read_buffer_size >= next_find_pos: + pos = self._find_read_pos() + if pos is not None: + return pos + next_find_pos = self._read_buffer_size * 2 + return self._find_read_pos() + + def _handle_read(self) -> None: + try: + pos = self._read_to_buffer_loop() + except UnsatisfiableReadError: + raise + except asyncio.CancelledError: + raise + except Exception as e: + gen_log.warning("error on read: %s" % e) + self.close(exc_info=e) + return + if pos is not None: + self._read_from_buffer(pos) + + def _start_read(self) -> Future: + if self._read_future is not None: + # It is an error to start a read while a prior read is unresolved. + # However, if the prior read is unresolved because the stream was + # closed without satisfying it, it's better to raise + # StreamClosedError instead of AssertionError. In particular, this + # situation occurs in harmless situations in http1connection.py and + # an AssertionError would be logged noisily. + # + # On the other hand, it is legal to start a new read while the + # stream is closed, in case the read can be satisfied from the + # read buffer. So we only want to check the closed status of the + # stream if we need to decide what kind of error to raise for + # "already reading". + # + # These conditions have proven difficult to test; we have no + # unittests that reliably verify this behavior so be careful + # when making changes here. See #2651 and #2719. + self._check_closed() + assert self._read_future is None, "Already reading" + self._read_future = Future() + return self._read_future + + def _finish_read(self, size: int, streaming: bool) -> None: + if self._user_read_buffer: + self._read_buffer = self._after_user_read_buffer or bytearray() + self._after_user_read_buffer = None + self._read_buffer_pos = 0 + self._read_buffer_size = len(self._read_buffer) + self._user_read_buffer = False + result = size # type: Union[int, bytes] + else: + result = self._consume(size) + if self._read_future is not None: + future = self._read_future + self._read_future = None + future_set_result_unless_cancelled(future, result) + self._maybe_add_error_listener() + + def _try_inline_read(self) -> None: + """Attempt to complete the current read operation from buffered data. + + If the read can be completed without blocking, schedules the + read callback on the next IOLoop iteration; otherwise starts + listening for reads on the socket. + """ + # See if we've already got the data from a previous read + pos = self._find_read_pos() + if pos is not None: + self._read_from_buffer(pos) + return + self._check_closed() + pos = self._read_to_buffer_loop() + if pos is not None: + self._read_from_buffer(pos) + return + # We couldn't satisfy the read inline, so make sure we're + # listening for new data unless the stream is closed. + if not self.closed(): + self._add_io_state(ioloop.IOLoop.READ) + + def _read_to_buffer(self) -> Optional[int]: + """Reads from the socket and appends the result to the read buffer. + + Returns the number of bytes read. Returns 0 if there is nothing + to read (i.e. the read returns EWOULDBLOCK or equivalent). On + error closes the socket and raises an exception. + """ + try: + while True: + try: + if self._user_read_buffer: + buf = memoryview(self._read_buffer)[ + self._read_buffer_size : + ] # type: Union[memoryview, bytearray] + else: + buf = bytearray(self.read_chunk_size) + bytes_read = self.read_from_fd(buf) + except (socket.error, IOError, OSError) as e: + # ssl.SSLError is a subclass of socket.error + if self._is_connreset(e): + # Treat ECONNRESET as a connection close rather than + # an error to minimize log spam (the exception will + # be available on self.error for apps that care). + self.close(exc_info=e) + return None + self.close(exc_info=e) + raise + break + if bytes_read is None: + return 0 + elif bytes_read == 0: + self.close() + return 0 + if not self._user_read_buffer: + self._read_buffer += memoryview(buf)[:bytes_read] + self._read_buffer_size += bytes_read + finally: + # Break the reference to buf so we don't waste a chunk's worth of + # memory in case an exception hangs on to our stack frame. + del buf + if self._read_buffer_size > self.max_buffer_size: + gen_log.error("Reached maximum read buffer size") + self.close() + raise StreamBufferFullError("Reached maximum read buffer size") + return bytes_read + + def _read_from_buffer(self, pos: int) -> None: + """Attempts to complete the currently-pending read from the buffer. + + The argument is either a position in the read buffer or None, + as returned by _find_read_pos. + """ + self._read_bytes = self._read_delimiter = self._read_regex = None + self._read_partial = False + self._finish_read(pos, False) + + def _find_read_pos(self) -> Optional[int]: + """Attempts to find a position in the read buffer that satisfies + the currently-pending read. + + Returns a position in the buffer if the current read can be satisfied, + or None if it cannot. + """ + if self._read_bytes is not None and ( + self._read_buffer_size >= self._read_bytes + or (self._read_partial and self._read_buffer_size > 0) + ): + num_bytes = min(self._read_bytes, self._read_buffer_size) + return num_bytes + elif self._read_delimiter is not None: + # Multi-byte delimiters (e.g. '\r\n') may straddle two + # chunks in the read buffer, so we can't easily find them + # without collapsing the buffer. However, since protocols + # using delimited reads (as opposed to reads of a known + # length) tend to be "line" oriented, the delimiter is likely + # to be in the first few chunks. Merge the buffer gradually + # since large merges are relatively expensive and get undone in + # _consume(). + if self._read_buffer: + loc = self._read_buffer.find( + self._read_delimiter, self._read_buffer_pos + ) + if loc != -1: + loc -= self._read_buffer_pos + delimiter_len = len(self._read_delimiter) + self._check_max_bytes(self._read_delimiter, loc + delimiter_len) + return loc + delimiter_len + self._check_max_bytes(self._read_delimiter, self._read_buffer_size) + elif self._read_regex is not None: + if self._read_buffer: + m = self._read_regex.search(self._read_buffer, self._read_buffer_pos) + if m is not None: + loc = m.end() - self._read_buffer_pos + self._check_max_bytes(self._read_regex, loc) + return loc + self._check_max_bytes(self._read_regex, self._read_buffer_size) + return None + + def _check_max_bytes(self, delimiter: Union[bytes, Pattern], size: int) -> None: + if self._read_max_bytes is not None and size > self._read_max_bytes: + raise UnsatisfiableReadError( + "delimiter %r not found within %d bytes" + % (delimiter, self._read_max_bytes) + ) + + def _handle_write(self) -> None: + while True: + size = len(self._write_buffer) + if not size: + break + assert size > 0 + try: + if _WINDOWS: + # On windows, socket.send blows up if given a + # write buffer that's too large, instead of just + # returning the number of bytes it was able to + # process. Therefore we must not call socket.send + # with more than 128KB at a time. + size = 128 * 1024 + + num_bytes = self.write_to_fd(self._write_buffer.peek(size)) + if num_bytes == 0: + break + self._write_buffer.advance(num_bytes) + self._total_write_done_index += num_bytes + except BlockingIOError: + break + except (socket.error, IOError, OSError) as e: + if not self._is_connreset(e): + # Broken pipe errors are usually caused by connection + # reset, and its better to not log EPIPE errors to + # minimize log spam + gen_log.warning("Write error on %s: %s", self.fileno(), e) + self.close(exc_info=e) + return + + while self._write_futures: + index, future = self._write_futures[0] + if index > self._total_write_done_index: + break + self._write_futures.popleft() + future_set_result_unless_cancelled(future, None) + + def _consume(self, loc: int) -> bytes: + # Consume loc bytes from the read buffer and return them + if loc == 0: + return b"" + assert loc <= self._read_buffer_size + # Slice the bytearray buffer into bytes, without intermediate copying + b = ( + memoryview(self._read_buffer)[ + self._read_buffer_pos : self._read_buffer_pos + loc + ] + ).tobytes() + self._read_buffer_pos += loc + self._read_buffer_size -= loc + # Amortized O(1) shrink + # (this heuristic is implemented natively in Python 3.4+ + # but is replicated here for Python 2) + if self._read_buffer_pos > self._read_buffer_size: + del self._read_buffer[: self._read_buffer_pos] + self._read_buffer_pos = 0 + return b + + def _check_closed(self) -> None: + if self.closed(): + raise StreamClosedError(real_error=self.error) + + def _maybe_add_error_listener(self) -> None: + # This method is part of an optimization: to detect a connection that + # is closed when we're not actively reading or writing, we must listen + # for read events. However, it is inefficient to do this when the + # connection is first established because we are going to read or write + # immediately anyway. Instead, we insert checks at various times to + # see if the connection is idle and add the read listener then. + if self._state is None or self._state == ioloop.IOLoop.ERROR: + if ( + not self.closed() + and self._read_buffer_size == 0 + and self._close_callback is not None + ): + self._add_io_state(ioloop.IOLoop.READ) + + def _add_io_state(self, state: int) -> None: + """Adds `state` (IOLoop.{READ,WRITE} flags) to our event handler. + + Implementation notes: Reads and writes have a fast path and a + slow path. The fast path reads synchronously from socket + buffers, while the slow path uses `_add_io_state` to schedule + an IOLoop callback. + + To detect closed connections, we must have called + `_add_io_state` at some point, but we want to delay this as + much as possible so we don't have to set an `IOLoop.ERROR` + listener that will be overwritten by the next slow-path + operation. If a sequence of fast-path ops do not end in a + slow-path op, (e.g. for an @asynchronous long-poll request), + we must add the error handler. + + TODO: reevaluate this now that callbacks are gone. + + """ + if self.closed(): + # connection has been closed, so there can be no future events + return + if self._state is None: + self._state = ioloop.IOLoop.ERROR | state + self.io_loop.add_handler(self.fileno(), self._handle_events, self._state) + elif not self._state & state: + self._state = self._state | state + self.io_loop.update_handler(self.fileno(), self._state) + + def _is_connreset(self, exc: BaseException) -> bool: + """Return ``True`` if exc is ECONNRESET or equivalent. + + May be overridden in subclasses. + """ + return ( + isinstance(exc, (socket.error, IOError)) + and errno_from_exception(exc) in _ERRNO_CONNRESET + ) + + +class IOStream(BaseIOStream): + r"""Socket-based `IOStream` implementation. + + This class supports the read and write methods from `BaseIOStream` + plus a `connect` method. + + The ``socket`` parameter may either be connected or unconnected. + For server operations the socket is the result of calling + `socket.accept <socket.socket.accept>`. For client operations the + socket is created with `socket.socket`, and may either be + connected before passing it to the `IOStream` or connected with + `IOStream.connect`. + + A very simple (and broken) HTTP client using this class: + + .. testcode:: + + import tornado.ioloop + import tornado.iostream + import socket + + async def main(): + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) + stream = tornado.iostream.IOStream(s) + await stream.connect(("friendfeed.com", 80)) + await stream.write(b"GET / HTTP/1.0\r\nHost: friendfeed.com\r\n\r\n") + header_data = await stream.read_until(b"\r\n\r\n") + headers = {} + for line in header_data.split(b"\r\n"): + parts = line.split(b":") + if len(parts) == 2: + headers[parts[0].strip()] = parts[1].strip() + body_data = await stream.read_bytes(int(headers[b"Content-Length"])) + print(body_data) + stream.close() + + if __name__ == '__main__': + tornado.ioloop.IOLoop.current().run_sync(main) + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) + stream = tornado.iostream.IOStream(s) + stream.connect(("friendfeed.com", 80), send_request) + tornado.ioloop.IOLoop.current().start() + + .. testoutput:: + :hide: + + """ + + def __init__(self, socket: socket.socket, *args: Any, **kwargs: Any) -> None: + self.socket = socket + self.socket.setblocking(False) + super().__init__(*args, **kwargs) + + def fileno(self) -> Union[int, ioloop._Selectable]: + return self.socket + + def close_fd(self) -> None: + self.socket.close() + self.socket = None # type: ignore + + def get_fd_error(self) -> Optional[Exception]: + errno = self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR) + return socket.error(errno, os.strerror(errno)) + + def read_from_fd(self, buf: Union[bytearray, memoryview]) -> Optional[int]: + try: + return self.socket.recv_into(buf, len(buf)) + except BlockingIOError: + return None + finally: + del buf + + def write_to_fd(self, data: memoryview) -> int: + try: + return self.socket.send(data) # type: ignore + finally: + # Avoid keeping to data, which can be a memoryview. + # See https://github.com/tornadoweb/tornado/pull/2008 + del data + + def connect( + self: _IOStreamType, address: Any, server_hostname: Optional[str] = None + ) -> "Future[_IOStreamType]": + """Connects the socket to a remote address without blocking. + + May only be called if the socket passed to the constructor was + not previously connected. The address parameter is in the + same format as for `socket.connect <socket.socket.connect>` for + the type of socket passed to the IOStream constructor, + e.g. an ``(ip, port)`` tuple. Hostnames are accepted here, + but will be resolved synchronously and block the IOLoop. + If you have a hostname instead of an IP address, the `.TCPClient` + class is recommended instead of calling this method directly. + `.TCPClient` will do asynchronous DNS resolution and handle + both IPv4 and IPv6. + + If ``callback`` is specified, it will be called with no + arguments when the connection is completed; if not this method + returns a `.Future` (whose result after a successful + connection will be the stream itself). + + In SSL mode, the ``server_hostname`` parameter will be used + for certificate validation (unless disabled in the + ``ssl_options``) and SNI (if supported; requires Python + 2.7.9+). + + Note that it is safe to call `IOStream.write + <BaseIOStream.write>` while the connection is pending, in + which case the data will be written as soon as the connection + is ready. Calling `IOStream` read methods before the socket is + connected works on some platforms but is non-portable. + + .. versionchanged:: 4.0 + If no callback is given, returns a `.Future`. + + .. versionchanged:: 4.2 + SSL certificates are validated by default; pass + ``ssl_options=dict(cert_reqs=ssl.CERT_NONE)`` or a + suitably-configured `ssl.SSLContext` to the + `SSLIOStream` constructor to disable. + + .. versionchanged:: 6.0 + + The ``callback`` argument was removed. Use the returned + `.Future` instead. + + """ + self._connecting = True + future = Future() # type: Future[_IOStreamType] + self._connect_future = typing.cast("Future[IOStream]", future) + try: + self.socket.connect(address) + except BlockingIOError: + # In non-blocking mode we expect connect() to raise an + # exception with EINPROGRESS or EWOULDBLOCK. + pass + except socket.error as e: + # On freebsd, other errors such as ECONNREFUSED may be + # returned immediately when attempting to connect to + # localhost, so handle them the same way as an error + # reported later in _handle_connect. + if future is None: + gen_log.warning("Connect error on fd %s: %s", self.socket.fileno(), e) + self.close(exc_info=e) + return future + self._add_io_state(self.io_loop.WRITE) + return future + + def start_tls( + self, + server_side: bool, + ssl_options: Optional[Union[Dict[str, Any], ssl.SSLContext]] = None, + server_hostname: Optional[str] = None, + ) -> Awaitable["SSLIOStream"]: + """Convert this `IOStream` to an `SSLIOStream`. + + This enables protocols that begin in clear-text mode and + switch to SSL after some initial negotiation (such as the + ``STARTTLS`` extension to SMTP and IMAP). + + This method cannot be used if there are outstanding reads + or writes on the stream, or if there is any data in the + IOStream's buffer (data in the operating system's socket + buffer is allowed). This means it must generally be used + immediately after reading or writing the last clear-text + data. It can also be used immediately after connecting, + before any reads or writes. + + The ``ssl_options`` argument may be either an `ssl.SSLContext` + object or a dictionary of keyword arguments for the + `ssl.wrap_socket` function. The ``server_hostname`` argument + will be used for certificate validation unless disabled + in the ``ssl_options``. + + This method returns a `.Future` whose result is the new + `SSLIOStream`. After this method has been called, + any other operation on the original stream is undefined. + + If a close callback is defined on this stream, it will be + transferred to the new stream. + + .. versionadded:: 4.0 + + .. versionchanged:: 4.2 + SSL certificates are validated by default; pass + ``ssl_options=dict(cert_reqs=ssl.CERT_NONE)`` or a + suitably-configured `ssl.SSLContext` to disable. + """ + if ( + self._read_future + or self._write_futures + or self._connect_future + or self._closed + or self._read_buffer + or self._write_buffer + ): + raise ValueError("IOStream is not idle; cannot convert to SSL") + if ssl_options is None: + if server_side: + ssl_options = _server_ssl_defaults + else: + ssl_options = _client_ssl_defaults + + socket = self.socket + self.io_loop.remove_handler(socket) + self.socket = None # type: ignore + socket = ssl_wrap_socket( + socket, + ssl_options, + server_hostname=server_hostname, + server_side=server_side, + do_handshake_on_connect=False, + ) + orig_close_callback = self._close_callback + self._close_callback = None + + future = Future() # type: Future[SSLIOStream] + ssl_stream = SSLIOStream(socket, ssl_options=ssl_options) + ssl_stream.set_close_callback(orig_close_callback) + ssl_stream._ssl_connect_future = future + ssl_stream.max_buffer_size = self.max_buffer_size + ssl_stream.read_chunk_size = self.read_chunk_size + return future + + def _handle_connect(self) -> None: + try: + err = self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR) + except socket.error as e: + # Hurd doesn't allow SO_ERROR for loopback sockets because all + # errors for such sockets are reported synchronously. + if errno_from_exception(e) == errno.ENOPROTOOPT: + err = 0 + if err != 0: + self.error = socket.error(err, os.strerror(err)) + # IOLoop implementations may vary: some of them return + # an error state before the socket becomes writable, so + # in that case a connection failure would be handled by the + # error path in _handle_events instead of here. + if self._connect_future is None: + gen_log.warning( + "Connect error on fd %s: %s", + self.socket.fileno(), + errno.errorcode[err], + ) + self.close() + return + if self._connect_future is not None: + future = self._connect_future + self._connect_future = None + future_set_result_unless_cancelled(future, self) + self._connecting = False + + def set_nodelay(self, value: bool) -> None: + if self.socket is not None and self.socket.family in ( + socket.AF_INET, + socket.AF_INET6, + ): + try: + self.socket.setsockopt( + socket.IPPROTO_TCP, socket.TCP_NODELAY, 1 if value else 0 + ) + except socket.error as e: + # Sometimes setsockopt will fail if the socket is closed + # at the wrong time. This can happen with HTTPServer + # resetting the value to ``False`` between requests. + if e.errno != errno.EINVAL and not self._is_connreset(e): + raise + + +class SSLIOStream(IOStream): + """A utility class to write to and read from a non-blocking SSL socket. + + If the socket passed to the constructor is already connected, + it should be wrapped with:: + + ssl.wrap_socket(sock, do_handshake_on_connect=False, **kwargs) + + before constructing the `SSLIOStream`. Unconnected sockets will be + wrapped when `IOStream.connect` is finished. + """ + + socket = None # type: ssl.SSLSocket + + def __init__(self, *args: Any, **kwargs: Any) -> None: + """The ``ssl_options`` keyword argument may either be an + `ssl.SSLContext` object or a dictionary of keywords arguments + for `ssl.wrap_socket` + """ + self._ssl_options = kwargs.pop("ssl_options", _client_ssl_defaults) + super().__init__(*args, **kwargs) + self._ssl_accepting = True + self._handshake_reading = False + self._handshake_writing = False + self._server_hostname = None # type: Optional[str] + + # If the socket is already connected, attempt to start the handshake. + try: + self.socket.getpeername() + except socket.error: + pass + else: + # Indirectly start the handshake, which will run on the next + # IOLoop iteration and then the real IO state will be set in + # _handle_events. + self._add_io_state(self.io_loop.WRITE) + + def reading(self) -> bool: + return self._handshake_reading or super().reading() + + def writing(self) -> bool: + return self._handshake_writing or super().writing() + + def _do_ssl_handshake(self) -> None: + # Based on code from test_ssl.py in the python stdlib + try: + self._handshake_reading = False + self._handshake_writing = False + self.socket.do_handshake() + except ssl.SSLError as err: + if err.args[0] == ssl.SSL_ERROR_WANT_READ: + self._handshake_reading = True + return + elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE: + self._handshake_writing = True + return + elif err.args[0] in (ssl.SSL_ERROR_EOF, ssl.SSL_ERROR_ZERO_RETURN): + return self.close(exc_info=err) + elif err.args[0] == ssl.SSL_ERROR_SSL: + try: + peer = self.socket.getpeername() + except Exception: + peer = "(not connected)" + gen_log.warning( + "SSL Error on %s %s: %s", self.socket.fileno(), peer, err + ) + return self.close(exc_info=err) + raise + except ssl.CertificateError as err: + # CertificateError can happen during handshake (hostname + # verification) and should be passed to user. Starting + # in Python 3.7, this error is a subclass of SSLError + # and will be handled by the previous block instead. + return self.close(exc_info=err) + except socket.error as err: + # Some port scans (e.g. nmap in -sT mode) have been known + # to cause do_handshake to raise EBADF and ENOTCONN, so make + # those errors quiet as well. + # https://groups.google.com/forum/?fromgroups#!topic/python-tornado/ApucKJat1_0 + # Errno 0 is also possible in some cases (nc -z). + # https://github.com/tornadoweb/tornado/issues/2504 + if self._is_connreset(err) or err.args[0] in ( + 0, + errno.EBADF, + errno.ENOTCONN, + ): + return self.close(exc_info=err) + raise + except AttributeError as err: + # On Linux, if the connection was reset before the call to + # wrap_socket, do_handshake will fail with an + # AttributeError. + return self.close(exc_info=err) + else: + self._ssl_accepting = False + if not self._verify_cert(self.socket.getpeercert()): + self.close() + return + self._finish_ssl_connect() + + def _finish_ssl_connect(self) -> None: + if self._ssl_connect_future is not None: + future = self._ssl_connect_future + self._ssl_connect_future = None + future_set_result_unless_cancelled(future, self) + + def _verify_cert(self, peercert: Any) -> bool: + """Returns ``True`` if peercert is valid according to the configured + validation mode and hostname. + + The ssl handshake already tested the certificate for a valid + CA signature; the only thing that remains is to check + the hostname. + """ + if isinstance(self._ssl_options, dict): + verify_mode = self._ssl_options.get("cert_reqs", ssl.CERT_NONE) + elif isinstance(self._ssl_options, ssl.SSLContext): + verify_mode = self._ssl_options.verify_mode + assert verify_mode in (ssl.CERT_NONE, ssl.CERT_REQUIRED, ssl.CERT_OPTIONAL) + if verify_mode == ssl.CERT_NONE or self._server_hostname is None: + return True + cert = self.socket.getpeercert() + if cert is None and verify_mode == ssl.CERT_REQUIRED: + gen_log.warning("No SSL certificate given") + return False + try: + ssl.match_hostname(peercert, self._server_hostname) + except ssl.CertificateError as e: + gen_log.warning("Invalid SSL certificate: %s" % e) + return False + else: + return True + + def _handle_read(self) -> None: + if self._ssl_accepting: + self._do_ssl_handshake() + return + super()._handle_read() + + def _handle_write(self) -> None: + if self._ssl_accepting: + self._do_ssl_handshake() + return + super()._handle_write() + + def connect( + self, address: Tuple, server_hostname: Optional[str] = None + ) -> "Future[SSLIOStream]": + self._server_hostname = server_hostname + # Ignore the result of connect(). If it fails, + # wait_for_handshake will raise an error too. This is + # necessary for the old semantics of the connect callback + # (which takes no arguments). In 6.0 this can be refactored to + # be a regular coroutine. + # TODO: This is trickier than it looks, since if write() + # is called with a connect() pending, we want the connect + # to resolve before the write. Or do we care about this? + # (There's a test for it, but I think in practice users + # either wait for the connect before performing a write or + # they don't care about the connect Future at all) + fut = super().connect(address) + fut.add_done_callback(lambda f: f.exception()) + return self.wait_for_handshake() + + def _handle_connect(self) -> None: + # Call the superclass method to check for errors. + super()._handle_connect() + if self.closed(): + return + # When the connection is complete, wrap the socket for SSL + # traffic. Note that we do this by overriding _handle_connect + # instead of by passing a callback to super().connect because + # user callbacks are enqueued asynchronously on the IOLoop, + # but since _handle_events calls _handle_connect immediately + # followed by _handle_write we need this to be synchronous. + # + # The IOLoop will get confused if we swap out self.socket while the + # fd is registered, so remove it now and re-register after + # wrap_socket(). + self.io_loop.remove_handler(self.socket) + old_state = self._state + assert old_state is not None + self._state = None + self.socket = ssl_wrap_socket( + self.socket, + self._ssl_options, + server_hostname=self._server_hostname, + do_handshake_on_connect=False, + ) + self._add_io_state(old_state) + + def wait_for_handshake(self) -> "Future[SSLIOStream]": + """Wait for the initial SSL handshake to complete. + + If a ``callback`` is given, it will be called with no + arguments once the handshake is complete; otherwise this + method returns a `.Future` which will resolve to the + stream itself after the handshake is complete. + + Once the handshake is complete, information such as + the peer's certificate and NPN/ALPN selections may be + accessed on ``self.socket``. + + This method is intended for use on server-side streams + or after using `IOStream.start_tls`; it should not be used + with `IOStream.connect` (which already waits for the + handshake to complete). It may only be called once per stream. + + .. versionadded:: 4.2 + + .. versionchanged:: 6.0 + + The ``callback`` argument was removed. Use the returned + `.Future` instead. + + """ + if self._ssl_connect_future is not None: + raise RuntimeError("Already waiting") + future = self._ssl_connect_future = Future() + if not self._ssl_accepting: + self._finish_ssl_connect() + return future + + def write_to_fd(self, data: memoryview) -> int: + try: + return self.socket.send(data) # type: ignore + except ssl.SSLError as e: + if e.args[0] == ssl.SSL_ERROR_WANT_WRITE: + # In Python 3.5+, SSLSocket.send raises a WANT_WRITE error if + # the socket is not writeable; we need to transform this into + # an EWOULDBLOCK socket.error or a zero return value, + # either of which will be recognized by the caller of this + # method. Prior to Python 3.5, an unwriteable socket would + # simply return 0 bytes written. + return 0 + raise + finally: + # Avoid keeping to data, which can be a memoryview. + # See https://github.com/tornadoweb/tornado/pull/2008 + del data + + def read_from_fd(self, buf: Union[bytearray, memoryview]) -> Optional[int]: + try: + if self._ssl_accepting: + # If the handshake hasn't finished yet, there can't be anything + # to read (attempting to read may or may not raise an exception + # depending on the SSL version) + return None + try: + return self.socket.recv_into(buf, len(buf)) + except ssl.SSLError as e: + # SSLError is a subclass of socket.error, so this except + # block must come first. + if e.args[0] == ssl.SSL_ERROR_WANT_READ: + return None + else: + raise + except BlockingIOError: + return None + finally: + del buf + + def _is_connreset(self, e: BaseException) -> bool: + if isinstance(e, ssl.SSLError) and e.args[0] == ssl.SSL_ERROR_EOF: + return True + return super()._is_connreset(e) + + +class PipeIOStream(BaseIOStream): + """Pipe-based `IOStream` implementation. + + The constructor takes an integer file descriptor (such as one returned + by `os.pipe`) rather than an open file object. Pipes are generally + one-way, so a `PipeIOStream` can be used for reading or writing but not + both. + + ``PipeIOStream`` is only available on Unix-based platforms. + """ + + def __init__(self, fd: int, *args: Any, **kwargs: Any) -> None: + self.fd = fd + self._fio = io.FileIO(self.fd, "r+") + os.set_blocking(fd, False) + super().__init__(*args, **kwargs) + + def fileno(self) -> int: + return self.fd + + def close_fd(self) -> None: + self._fio.close() + + def write_to_fd(self, data: memoryview) -> int: + try: + return os.write(self.fd, data) # type: ignore + finally: + # Avoid keeping to data, which can be a memoryview. + # See https://github.com/tornadoweb/tornado/pull/2008 + del data + + def read_from_fd(self, buf: Union[bytearray, memoryview]) -> Optional[int]: + try: + return self._fio.readinto(buf) # type: ignore + except (IOError, OSError) as e: + if errno_from_exception(e) == errno.EBADF: + # If the writing half of a pipe is closed, select will + # report it as readable but reads will fail with EBADF. + self.close(exc_info=e) + return None + else: + raise + finally: + del buf + + +def doctests() -> Any: + import doctest + + return doctest.DocTestSuite() diff --git a/venv/lib/python3.8/site-packages/tornado/locale.py b/venv/lib/python3.8/site-packages/tornado/locale.py new file mode 100644 index 0000000..adb1f77 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/locale.py @@ -0,0 +1,581 @@ +# Copyright 2009 Facebook +# +# 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. + +"""Translation methods for generating localized strings. + +To load a locale and generate a translated string:: + + user_locale = tornado.locale.get("es_LA") + print(user_locale.translate("Sign out")) + +`tornado.locale.get()` returns the closest matching locale, not necessarily the +specific locale you requested. You can support pluralization with +additional arguments to `~Locale.translate()`, e.g.:: + + people = [...] + message = user_locale.translate( + "%(list)s is online", "%(list)s are online", len(people)) + print(message % {"list": user_locale.list(people)}) + +The first string is chosen if ``len(people) == 1``, otherwise the second +string is chosen. + +Applications should call one of `load_translations` (which uses a simple +CSV format) or `load_gettext_translations` (which uses the ``.mo`` format +supported by `gettext` and related tools). If neither method is called, +the `Locale.translate` method will simply return the original string. +""" + +import codecs +import csv +import datetime +import gettext +import os +import re + +from tornado import escape +from tornado.log import gen_log + +from tornado._locale_data import LOCALE_NAMES + +from typing import Iterable, Any, Union, Dict, Optional + +_default_locale = "en_US" +_translations = {} # type: Dict[str, Any] +_supported_locales = frozenset([_default_locale]) +_use_gettext = False +CONTEXT_SEPARATOR = "\x04" + + +def get(*locale_codes: str) -> "Locale": + """Returns the closest match for the given locale codes. + + We iterate over all given locale codes in order. If we have a tight + or a loose match for the code (e.g., "en" for "en_US"), we return + the locale. Otherwise we move to the next code in the list. + + By default we return ``en_US`` if no translations are found for any of + the specified locales. You can change the default locale with + `set_default_locale()`. + """ + return Locale.get_closest(*locale_codes) + + +def set_default_locale(code: str) -> None: + """Sets the default locale. + + The default locale is assumed to be the language used for all strings + in the system. The translations loaded from disk are mappings from + the default locale to the destination locale. Consequently, you don't + need to create a translation file for the default locale. + """ + global _default_locale + global _supported_locales + _default_locale = code + _supported_locales = frozenset(list(_translations.keys()) + [_default_locale]) + + +def load_translations(directory: str, encoding: Optional[str] = None) -> None: + """Loads translations from CSV files in a directory. + + Translations are strings with optional Python-style named placeholders + (e.g., ``My name is %(name)s``) and their associated translations. + + The directory should have translation files of the form ``LOCALE.csv``, + e.g. ``es_GT.csv``. The CSV files should have two or three columns: string, + translation, and an optional plural indicator. Plural indicators should + be one of "plural" or "singular". A given string can have both singular + and plural forms. For example ``%(name)s liked this`` may have a + different verb conjugation depending on whether %(name)s is one + name or a list of names. There should be two rows in the CSV file for + that string, one with plural indicator "singular", and one "plural". + For strings with no verbs that would change on translation, simply + use "unknown" or the empty string (or don't include the column at all). + + The file is read using the `csv` module in the default "excel" dialect. + In this format there should not be spaces after the commas. + + If no ``encoding`` parameter is given, the encoding will be + detected automatically (among UTF-8 and UTF-16) if the file + contains a byte-order marker (BOM), defaulting to UTF-8 if no BOM + is present. + + Example translation ``es_LA.csv``:: + + "I love you","Te amo" + "%(name)s liked this","A %(name)s les gustó esto","plural" + "%(name)s liked this","A %(name)s le gustó esto","singular" + + .. versionchanged:: 4.3 + Added ``encoding`` parameter. Added support for BOM-based encoding + detection, UTF-16, and UTF-8-with-BOM. + """ + global _translations + global _supported_locales + _translations = {} + for path in os.listdir(directory): + if not path.endswith(".csv"): + continue + locale, extension = path.split(".") + if not re.match("[a-z]+(_[A-Z]+)?$", locale): + gen_log.error( + "Unrecognized locale %r (path: %s)", + locale, + os.path.join(directory, path), + ) + continue + full_path = os.path.join(directory, path) + if encoding is None: + # Try to autodetect encoding based on the BOM. + with open(full_path, "rb") as bf: + data = bf.read(len(codecs.BOM_UTF16_LE)) + if data in (codecs.BOM_UTF16_LE, codecs.BOM_UTF16_BE): + encoding = "utf-16" + else: + # utf-8-sig is "utf-8 with optional BOM". It's discouraged + # in most cases but is common with CSV files because Excel + # cannot read utf-8 files without a BOM. + encoding = "utf-8-sig" + # python 3: csv.reader requires a file open in text mode. + # Specify an encoding to avoid dependence on $LANG environment variable. + with open(full_path, encoding=encoding) as f: + _translations[locale] = {} + for i, row in enumerate(csv.reader(f)): + if not row or len(row) < 2: + continue + row = [escape.to_unicode(c).strip() for c in row] + english, translation = row[:2] + if len(row) > 2: + plural = row[2] or "unknown" + else: + plural = "unknown" + if plural not in ("plural", "singular", "unknown"): + gen_log.error( + "Unrecognized plural indicator %r in %s line %d", + plural, + path, + i + 1, + ) + continue + _translations[locale].setdefault(plural, {})[english] = translation + _supported_locales = frozenset(list(_translations.keys()) + [_default_locale]) + gen_log.debug("Supported locales: %s", sorted(_supported_locales)) + + +def load_gettext_translations(directory: str, domain: str) -> None: + """Loads translations from `gettext`'s locale tree + + Locale tree is similar to system's ``/usr/share/locale``, like:: + + {directory}/{lang}/LC_MESSAGES/{domain}.mo + + Three steps are required to have your app translated: + + 1. Generate POT translation file:: + + xgettext --language=Python --keyword=_:1,2 -d mydomain file1.py file2.html etc + + 2. Merge against existing POT file:: + + msgmerge old.po mydomain.po > new.po + + 3. Compile:: + + msgfmt mydomain.po -o {directory}/pt_BR/LC_MESSAGES/mydomain.mo + """ + global _translations + global _supported_locales + global _use_gettext + _translations = {} + for lang in os.listdir(directory): + if lang.startswith("."): + continue # skip .svn, etc + if os.path.isfile(os.path.join(directory, lang)): + continue + try: + os.stat(os.path.join(directory, lang, "LC_MESSAGES", domain + ".mo")) + _translations[lang] = gettext.translation( + domain, directory, languages=[lang] + ) + except Exception as e: + gen_log.error("Cannot load translation for '%s': %s", lang, str(e)) + continue + _supported_locales = frozenset(list(_translations.keys()) + [_default_locale]) + _use_gettext = True + gen_log.debug("Supported locales: %s", sorted(_supported_locales)) + + +def get_supported_locales() -> Iterable[str]: + """Returns a list of all the supported locale codes.""" + return _supported_locales + + +class Locale(object): + """Object representing a locale. + + After calling one of `load_translations` or `load_gettext_translations`, + call `get` or `get_closest` to get a Locale object. + """ + + _cache = {} # type: Dict[str, Locale] + + @classmethod + def get_closest(cls, *locale_codes: str) -> "Locale": + """Returns the closest match for the given locale code.""" + for code in locale_codes: + if not code: + continue + code = code.replace("-", "_") + parts = code.split("_") + if len(parts) > 2: + continue + elif len(parts) == 2: + code = parts[0].lower() + "_" + parts[1].upper() + if code in _supported_locales: + return cls.get(code) + if parts[0].lower() in _supported_locales: + return cls.get(parts[0].lower()) + return cls.get(_default_locale) + + @classmethod + def get(cls, code: str) -> "Locale": + """Returns the Locale for the given locale code. + + If it is not supported, we raise an exception. + """ + if code not in cls._cache: + assert code in _supported_locales + translations = _translations.get(code, None) + if translations is None: + locale = CSVLocale(code, {}) # type: Locale + elif _use_gettext: + locale = GettextLocale(code, translations) + else: + locale = CSVLocale(code, translations) + cls._cache[code] = locale + return cls._cache[code] + + def __init__(self, code: str) -> None: + self.code = code + self.name = LOCALE_NAMES.get(code, {}).get("name", u"Unknown") + self.rtl = False + for prefix in ["fa", "ar", "he"]: + if self.code.startswith(prefix): + self.rtl = True + break + + # Initialize strings for date formatting + _ = self.translate + self._months = [ + _("January"), + _("February"), + _("March"), + _("April"), + _("May"), + _("June"), + _("July"), + _("August"), + _("September"), + _("October"), + _("November"), + _("December"), + ] + self._weekdays = [ + _("Monday"), + _("Tuesday"), + _("Wednesday"), + _("Thursday"), + _("Friday"), + _("Saturday"), + _("Sunday"), + ] + + def translate( + self, + message: str, + plural_message: Optional[str] = None, + count: Optional[int] = None, + ) -> str: + """Returns the translation for the given message for this locale. + + If ``plural_message`` is given, you must also provide + ``count``. We return ``plural_message`` when ``count != 1``, + and we return the singular form for the given message when + ``count == 1``. + """ + raise NotImplementedError() + + def pgettext( + self, + context: str, + message: str, + plural_message: Optional[str] = None, + count: Optional[int] = None, + ) -> str: + raise NotImplementedError() + + def format_date( + self, + date: Union[int, float, datetime.datetime], + gmt_offset: int = 0, + relative: bool = True, + shorter: bool = False, + full_format: bool = False, + ) -> str: + """Formats the given date (which should be GMT). + + By default, we return a relative time (e.g., "2 minutes ago"). You + can return an absolute date string with ``relative=False``. + + You can force a full format date ("July 10, 1980") with + ``full_format=True``. + + This method is primarily intended for dates in the past. + For dates in the future, we fall back to full format. + """ + if isinstance(date, (int, float)): + date = datetime.datetime.utcfromtimestamp(date) + now = datetime.datetime.utcnow() + if date > now: + if relative and (date - now).seconds < 60: + # Due to click skew, things are some things slightly + # in the future. Round timestamps in the immediate + # future down to now in relative mode. + date = now + else: + # Otherwise, future dates always use the full format. + full_format = True + local_date = date - datetime.timedelta(minutes=gmt_offset) + local_now = now - datetime.timedelta(minutes=gmt_offset) + local_yesterday = local_now - datetime.timedelta(hours=24) + difference = now - date + seconds = difference.seconds + days = difference.days + + _ = self.translate + format = None + if not full_format: + if relative and days == 0: + if seconds < 50: + return _("1 second ago", "%(seconds)d seconds ago", seconds) % { + "seconds": seconds + } + + if seconds < 50 * 60: + minutes = round(seconds / 60.0) + return _("1 minute ago", "%(minutes)d minutes ago", minutes) % { + "minutes": minutes + } + + hours = round(seconds / (60.0 * 60)) + return _("1 hour ago", "%(hours)d hours ago", hours) % {"hours": hours} + + if days == 0: + format = _("%(time)s") + elif days == 1 and local_date.day == local_yesterday.day and relative: + format = _("yesterday") if shorter else _("yesterday at %(time)s") + elif days < 5: + format = _("%(weekday)s") if shorter else _("%(weekday)s at %(time)s") + elif days < 334: # 11mo, since confusing for same month last year + format = ( + _("%(month_name)s %(day)s") + if shorter + else _("%(month_name)s %(day)s at %(time)s") + ) + + if format is None: + format = ( + _("%(month_name)s %(day)s, %(year)s") + if shorter + else _("%(month_name)s %(day)s, %(year)s at %(time)s") + ) + + tfhour_clock = self.code not in ("en", "en_US", "zh_CN") + if tfhour_clock: + str_time = "%d:%02d" % (local_date.hour, local_date.minute) + elif self.code == "zh_CN": + str_time = "%s%d:%02d" % ( + (u"\u4e0a\u5348", u"\u4e0b\u5348")[local_date.hour >= 12], + local_date.hour % 12 or 12, + local_date.minute, + ) + else: + str_time = "%d:%02d %s" % ( + local_date.hour % 12 or 12, + local_date.minute, + ("am", "pm")[local_date.hour >= 12], + ) + + return format % { + "month_name": self._months[local_date.month - 1], + "weekday": self._weekdays[local_date.weekday()], + "day": str(local_date.day), + "year": str(local_date.year), + "time": str_time, + } + + def format_day( + self, date: datetime.datetime, gmt_offset: int = 0, dow: bool = True + ) -> bool: + """Formats the given date as a day of week. + + Example: "Monday, January 22". You can remove the day of week with + ``dow=False``. + """ + local_date = date - datetime.timedelta(minutes=gmt_offset) + _ = self.translate + if dow: + return _("%(weekday)s, %(month_name)s %(day)s") % { + "month_name": self._months[local_date.month - 1], + "weekday": self._weekdays[local_date.weekday()], + "day": str(local_date.day), + } + else: + return _("%(month_name)s %(day)s") % { + "month_name": self._months[local_date.month - 1], + "day": str(local_date.day), + } + + def list(self, parts: Any) -> str: + """Returns a comma-separated list for the given list of parts. + + The format is, e.g., "A, B and C", "A and B" or just "A" for lists + of size 1. + """ + _ = self.translate + if len(parts) == 0: + return "" + if len(parts) == 1: + return parts[0] + comma = u" \u0648 " if self.code.startswith("fa") else u", " + return _("%(commas)s and %(last)s") % { + "commas": comma.join(parts[:-1]), + "last": parts[len(parts) - 1], + } + + def friendly_number(self, value: int) -> str: + """Returns a comma-separated number for the given integer.""" + if self.code not in ("en", "en_US"): + return str(value) + s = str(value) + parts = [] + while s: + parts.append(s[-3:]) + s = s[:-3] + return ",".join(reversed(parts)) + + +class CSVLocale(Locale): + """Locale implementation using tornado's CSV translation format.""" + + def __init__(self, code: str, translations: Dict[str, Dict[str, str]]) -> None: + self.translations = translations + super().__init__(code) + + def translate( + self, + message: str, + plural_message: Optional[str] = None, + count: Optional[int] = None, + ) -> str: + if plural_message is not None: + assert count is not None + if count != 1: + message = plural_message + message_dict = self.translations.get("plural", {}) + else: + message_dict = self.translations.get("singular", {}) + else: + message_dict = self.translations.get("unknown", {}) + return message_dict.get(message, message) + + def pgettext( + self, + context: str, + message: str, + plural_message: Optional[str] = None, + count: Optional[int] = None, + ) -> str: + if self.translations: + gen_log.warning("pgettext is not supported by CSVLocale") + return self.translate(message, plural_message, count) + + +class GettextLocale(Locale): + """Locale implementation using the `gettext` module.""" + + def __init__(self, code: str, translations: gettext.NullTranslations) -> None: + self.ngettext = translations.ngettext + self.gettext = translations.gettext + # self.gettext must exist before __init__ is called, since it + # calls into self.translate + super().__init__(code) + + def translate( + self, + message: str, + plural_message: Optional[str] = None, + count: Optional[int] = None, + ) -> str: + if plural_message is not None: + assert count is not None + return self.ngettext(message, plural_message, count) + else: + return self.gettext(message) + + def pgettext( + self, + context: str, + message: str, + plural_message: Optional[str] = None, + count: Optional[int] = None, + ) -> str: + """Allows to set context for translation, accepts plural forms. + + Usage example:: + + pgettext("law", "right") + pgettext("good", "right") + + Plural message example:: + + pgettext("organization", "club", "clubs", len(clubs)) + pgettext("stick", "club", "clubs", len(clubs)) + + To generate POT file with context, add following options to step 1 + of `load_gettext_translations` sequence:: + + xgettext [basic options] --keyword=pgettext:1c,2 --keyword=pgettext:1c,2,3 + + .. versionadded:: 4.2 + """ + if plural_message is not None: + assert count is not None + msgs_with_ctxt = ( + "%s%s%s" % (context, CONTEXT_SEPARATOR, message), + "%s%s%s" % (context, CONTEXT_SEPARATOR, plural_message), + count, + ) + result = self.ngettext(*msgs_with_ctxt) + if CONTEXT_SEPARATOR in result: + # Translation not found + result = self.ngettext(message, plural_message, count) + return result + else: + msg_with_ctxt = "%s%s%s" % (context, CONTEXT_SEPARATOR, message) + result = self.gettext(msg_with_ctxt) + if CONTEXT_SEPARATOR in result: + # Translation not found + result = message + return result diff --git a/venv/lib/python3.8/site-packages/tornado/locks.py b/venv/lib/python3.8/site-packages/tornado/locks.py new file mode 100644 index 0000000..0898eba --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/locks.py @@ -0,0 +1,571 @@ +# Copyright 2015 The Tornado Authors +# +# 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. + +import collections +import datetime +import types + +from tornado import gen, ioloop +from tornado.concurrent import Future, future_set_result_unless_cancelled + +from typing import Union, Optional, Type, Any, Awaitable +import typing + +if typing.TYPE_CHECKING: + from typing import Deque, Set # noqa: F401 + +__all__ = ["Condition", "Event", "Semaphore", "BoundedSemaphore", "Lock"] + + +class _TimeoutGarbageCollector(object): + """Base class for objects that periodically clean up timed-out waiters. + + Avoids memory leak in a common pattern like: + + while True: + yield condition.wait(short_timeout) + print('looping....') + """ + + def __init__(self) -> None: + self._waiters = collections.deque() # type: Deque[Future] + self._timeouts = 0 + + def _garbage_collect(self) -> None: + # Occasionally clear timed-out waiters. + self._timeouts += 1 + if self._timeouts > 100: + self._timeouts = 0 + self._waiters = collections.deque(w for w in self._waiters if not w.done()) + + +class Condition(_TimeoutGarbageCollector): + """A condition allows one or more coroutines to wait until notified. + + Like a standard `threading.Condition`, but does not need an underlying lock + that is acquired and released. + + With a `Condition`, coroutines can wait to be notified by other coroutines: + + .. testcode:: + + from tornado import gen + from tornado.ioloop import IOLoop + from tornado.locks import Condition + + condition = Condition() + + async def waiter(): + print("I'll wait right here") + await condition.wait() + print("I'm done waiting") + + async def notifier(): + print("About to notify") + condition.notify() + print("Done notifying") + + async def runner(): + # Wait for waiter() and notifier() in parallel + await gen.multi([waiter(), notifier()]) + + IOLoop.current().run_sync(runner) + + .. testoutput:: + + I'll wait right here + About to notify + Done notifying + I'm done waiting + + `wait` takes an optional ``timeout`` argument, which is either an absolute + timestamp:: + + io_loop = IOLoop.current() + + # Wait up to 1 second for a notification. + await condition.wait(timeout=io_loop.time() + 1) + + ...or a `datetime.timedelta` for a timeout relative to the current time:: + + # Wait up to 1 second. + await condition.wait(timeout=datetime.timedelta(seconds=1)) + + The method returns False if there's no notification before the deadline. + + .. versionchanged:: 5.0 + Previously, waiters could be notified synchronously from within + `notify`. Now, the notification will always be received on the + next iteration of the `.IOLoop`. + """ + + def __init__(self) -> None: + super().__init__() + self.io_loop = ioloop.IOLoop.current() + + def __repr__(self) -> str: + result = "<%s" % (self.__class__.__name__,) + if self._waiters: + result += " waiters[%s]" % len(self._waiters) + return result + ">" + + def wait( + self, timeout: Optional[Union[float, datetime.timedelta]] = None + ) -> Awaitable[bool]: + """Wait for `.notify`. + + Returns a `.Future` that resolves ``True`` if the condition is notified, + or ``False`` after a timeout. + """ + waiter = Future() # type: Future[bool] + self._waiters.append(waiter) + if timeout: + + def on_timeout() -> None: + if not waiter.done(): + future_set_result_unless_cancelled(waiter, False) + self._garbage_collect() + + io_loop = ioloop.IOLoop.current() + timeout_handle = io_loop.add_timeout(timeout, on_timeout) + waiter.add_done_callback(lambda _: io_loop.remove_timeout(timeout_handle)) + return waiter + + def notify(self, n: int = 1) -> None: + """Wake ``n`` waiters.""" + waiters = [] # Waiters we plan to run right now. + while n and self._waiters: + waiter = self._waiters.popleft() + if not waiter.done(): # Might have timed out. + n -= 1 + waiters.append(waiter) + + for waiter in waiters: + future_set_result_unless_cancelled(waiter, True) + + def notify_all(self) -> None: + """Wake all waiters.""" + self.notify(len(self._waiters)) + + +class Event(object): + """An event blocks coroutines until its internal flag is set to True. + + Similar to `threading.Event`. + + A coroutine can wait for an event to be set. Once it is set, calls to + ``yield event.wait()`` will not block unless the event has been cleared: + + .. testcode:: + + from tornado import gen + from tornado.ioloop import IOLoop + from tornado.locks import Event + + event = Event() + + async def waiter(): + print("Waiting for event") + await event.wait() + print("Not waiting this time") + await event.wait() + print("Done") + + async def setter(): + print("About to set the event") + event.set() + + async def runner(): + await gen.multi([waiter(), setter()]) + + IOLoop.current().run_sync(runner) + + .. testoutput:: + + Waiting for event + About to set the event + Not waiting this time + Done + """ + + def __init__(self) -> None: + self._value = False + self._waiters = set() # type: Set[Future[None]] + + def __repr__(self) -> str: + return "<%s %s>" % ( + self.__class__.__name__, + "set" if self.is_set() else "clear", + ) + + def is_set(self) -> bool: + """Return ``True`` if the internal flag is true.""" + return self._value + + def set(self) -> None: + """Set the internal flag to ``True``. All waiters are awakened. + + Calling `.wait` once the flag is set will not block. + """ + if not self._value: + self._value = True + + for fut in self._waiters: + if not fut.done(): + fut.set_result(None) + + def clear(self) -> None: + """Reset the internal flag to ``False``. + + Calls to `.wait` will block until `.set` is called. + """ + self._value = False + + def wait( + self, timeout: Optional[Union[float, datetime.timedelta]] = None + ) -> Awaitable[None]: + """Block until the internal flag is true. + + Returns an awaitable, which raises `tornado.util.TimeoutError` after a + timeout. + """ + fut = Future() # type: Future[None] + if self._value: + fut.set_result(None) + return fut + self._waiters.add(fut) + fut.add_done_callback(lambda fut: self._waiters.remove(fut)) + if timeout is None: + return fut + else: + timeout_fut = gen.with_timeout(timeout, fut) + # This is a slightly clumsy workaround for the fact that + # gen.with_timeout doesn't cancel its futures. Cancelling + # fut will remove it from the waiters list. + timeout_fut.add_done_callback( + lambda tf: fut.cancel() if not fut.done() else None + ) + return timeout_fut + + +class _ReleasingContextManager(object): + """Releases a Lock or Semaphore at the end of a "with" statement. + + with (yield semaphore.acquire()): + pass + + # Now semaphore.release() has been called. + """ + + def __init__(self, obj: Any) -> None: + self._obj = obj + + def __enter__(self) -> None: + pass + + def __exit__( + self, + exc_type: "Optional[Type[BaseException]]", + exc_val: Optional[BaseException], + exc_tb: Optional[types.TracebackType], + ) -> None: + self._obj.release() + + +class Semaphore(_TimeoutGarbageCollector): + """A lock that can be acquired a fixed number of times before blocking. + + A Semaphore manages a counter representing the number of `.release` calls + minus the number of `.acquire` calls, plus an initial value. The `.acquire` + method blocks if necessary until it can return without making the counter + negative. + + Semaphores limit access to a shared resource. To allow access for two + workers at a time: + + .. testsetup:: semaphore + + from collections import deque + + from tornado import gen + from tornado.ioloop import IOLoop + from tornado.concurrent import Future + + # Ensure reliable doctest output: resolve Futures one at a time. + futures_q = deque([Future() for _ in range(3)]) + + async def simulator(futures): + for f in futures: + # simulate the asynchronous passage of time + await gen.sleep(0) + await gen.sleep(0) + f.set_result(None) + + IOLoop.current().add_callback(simulator, list(futures_q)) + + def use_some_resource(): + return futures_q.popleft() + + .. testcode:: semaphore + + from tornado import gen + from tornado.ioloop import IOLoop + from tornado.locks import Semaphore + + sem = Semaphore(2) + + async def worker(worker_id): + await sem.acquire() + try: + print("Worker %d is working" % worker_id) + await use_some_resource() + finally: + print("Worker %d is done" % worker_id) + sem.release() + + async def runner(): + # Join all workers. + await gen.multi([worker(i) for i in range(3)]) + + IOLoop.current().run_sync(runner) + + .. testoutput:: semaphore + + Worker 0 is working + Worker 1 is working + Worker 0 is done + Worker 2 is working + Worker 1 is done + Worker 2 is done + + Workers 0 and 1 are allowed to run concurrently, but worker 2 waits until + the semaphore has been released once, by worker 0. + + The semaphore can be used as an async context manager:: + + async def worker(worker_id): + async with sem: + print("Worker %d is working" % worker_id) + await use_some_resource() + + # Now the semaphore has been released. + print("Worker %d is done" % worker_id) + + For compatibility with older versions of Python, `.acquire` is a + context manager, so ``worker`` could also be written as:: + + @gen.coroutine + def worker(worker_id): + with (yield sem.acquire()): + print("Worker %d is working" % worker_id) + yield use_some_resource() + + # Now the semaphore has been released. + print("Worker %d is done" % worker_id) + + .. versionchanged:: 4.3 + Added ``async with`` support in Python 3.5. + + """ + + def __init__(self, value: int = 1) -> None: + super().__init__() + if value < 0: + raise ValueError("semaphore initial value must be >= 0") + + self._value = value + + def __repr__(self) -> str: + res = super().__repr__() + extra = ( + "locked" if self._value == 0 else "unlocked,value:{0}".format(self._value) + ) + if self._waiters: + extra = "{0},waiters:{1}".format(extra, len(self._waiters)) + return "<{0} [{1}]>".format(res[1:-1], extra) + + def release(self) -> None: + """Increment the counter and wake one waiter.""" + self._value += 1 + while self._waiters: + waiter = self._waiters.popleft() + if not waiter.done(): + self._value -= 1 + + # If the waiter is a coroutine paused at + # + # with (yield semaphore.acquire()): + # + # then the context manager's __exit__ calls release() at the end + # of the "with" block. + waiter.set_result(_ReleasingContextManager(self)) + break + + def acquire( + self, timeout: Optional[Union[float, datetime.timedelta]] = None + ) -> Awaitable[_ReleasingContextManager]: + """Decrement the counter. Returns an awaitable. + + Block if the counter is zero and wait for a `.release`. The awaitable + raises `.TimeoutError` after the deadline. + """ + waiter = Future() # type: Future[_ReleasingContextManager] + if self._value > 0: + self._value -= 1 + waiter.set_result(_ReleasingContextManager(self)) + else: + self._waiters.append(waiter) + if timeout: + + def on_timeout() -> None: + if not waiter.done(): + waiter.set_exception(gen.TimeoutError()) + self._garbage_collect() + + io_loop = ioloop.IOLoop.current() + timeout_handle = io_loop.add_timeout(timeout, on_timeout) + waiter.add_done_callback( + lambda _: io_loop.remove_timeout(timeout_handle) + ) + return waiter + + def __enter__(self) -> None: + raise RuntimeError("Use 'async with' instead of 'with' for Semaphore") + + def __exit__( + self, + typ: "Optional[Type[BaseException]]", + value: Optional[BaseException], + traceback: Optional[types.TracebackType], + ) -> None: + self.__enter__() + + async def __aenter__(self) -> None: + await self.acquire() + + async def __aexit__( + self, + typ: "Optional[Type[BaseException]]", + value: Optional[BaseException], + tb: Optional[types.TracebackType], + ) -> None: + self.release() + + +class BoundedSemaphore(Semaphore): + """A semaphore that prevents release() being called too many times. + + If `.release` would increment the semaphore's value past the initial + value, it raises `ValueError`. Semaphores are mostly used to guard + resources with limited capacity, so a semaphore released too many times + is a sign of a bug. + """ + + def __init__(self, value: int = 1) -> None: + super().__init__(value=value) + self._initial_value = value + + def release(self) -> None: + """Increment the counter and wake one waiter.""" + if self._value >= self._initial_value: + raise ValueError("Semaphore released too many times") + super().release() + + +class Lock(object): + """A lock for coroutines. + + A Lock begins unlocked, and `acquire` locks it immediately. While it is + locked, a coroutine that yields `acquire` waits until another coroutine + calls `release`. + + Releasing an unlocked lock raises `RuntimeError`. + + A Lock can be used as an async context manager with the ``async + with`` statement: + + >>> from tornado import locks + >>> lock = locks.Lock() + >>> + >>> async def f(): + ... async with lock: + ... # Do something holding the lock. + ... pass + ... + ... # Now the lock is released. + + For compatibility with older versions of Python, the `.acquire` + method asynchronously returns a regular context manager: + + >>> async def f2(): + ... with (yield lock.acquire()): + ... # Do something holding the lock. + ... pass + ... + ... # Now the lock is released. + + .. versionchanged:: 4.3 + Added ``async with`` support in Python 3.5. + + """ + + def __init__(self) -> None: + self._block = BoundedSemaphore(value=1) + + def __repr__(self) -> str: + return "<%s _block=%s>" % (self.__class__.__name__, self._block) + + def acquire( + self, timeout: Optional[Union[float, datetime.timedelta]] = None + ) -> Awaitable[_ReleasingContextManager]: + """Attempt to lock. Returns an awaitable. + + Returns an awaitable, which raises `tornado.util.TimeoutError` after a + timeout. + """ + return self._block.acquire(timeout) + + def release(self) -> None: + """Unlock. + + The first coroutine in line waiting for `acquire` gets the lock. + + If not locked, raise a `RuntimeError`. + """ + try: + self._block.release() + except ValueError: + raise RuntimeError("release unlocked lock") + + def __enter__(self) -> None: + raise RuntimeError("Use `async with` instead of `with` for Lock") + + def __exit__( + self, + typ: "Optional[Type[BaseException]]", + value: Optional[BaseException], + tb: Optional[types.TracebackType], + ) -> None: + self.__enter__() + + async def __aenter__(self) -> None: + await self.acquire() + + async def __aexit__( + self, + typ: "Optional[Type[BaseException]]", + value: Optional[BaseException], + tb: Optional[types.TracebackType], + ) -> None: + self.release() diff --git a/venv/lib/python3.8/site-packages/tornado/log.py b/venv/lib/python3.8/site-packages/tornado/log.py new file mode 100644 index 0000000..810a037 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/log.py @@ -0,0 +1,339 @@ +# +# Copyright 2012 Facebook +# +# 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. +"""Logging support for Tornado. + +Tornado uses three logger streams: + +* ``tornado.access``: Per-request logging for Tornado's HTTP servers (and + potentially other servers in the future) +* ``tornado.application``: Logging of errors from application code (i.e. + uncaught exceptions from callbacks) +* ``tornado.general``: General-purpose logging, including any errors + or warnings from Tornado itself. + +These streams may be configured independently using the standard library's +`logging` module. For example, you may wish to send ``tornado.access`` logs +to a separate file for analysis. +""" +import logging +import logging.handlers +import sys + +from tornado.escape import _unicode +from tornado.util import unicode_type, basestring_type + +try: + import colorama # type: ignore +except ImportError: + colorama = None + +try: + import curses +except ImportError: + curses = None # type: ignore + +from typing import Dict, Any, cast, Optional + +# Logger objects for internal tornado use +access_log = logging.getLogger("tornado.access") +app_log = logging.getLogger("tornado.application") +gen_log = logging.getLogger("tornado.general") + + +def _stderr_supports_color() -> bool: + try: + if hasattr(sys.stderr, "isatty") and sys.stderr.isatty(): + if curses: + curses.setupterm() + if curses.tigetnum("colors") > 0: + return True + elif colorama: + if sys.stderr is getattr( + colorama.initialise, "wrapped_stderr", object() + ): + return True + except Exception: + # Very broad exception handling because it's always better to + # fall back to non-colored logs than to break at startup. + pass + return False + + +def _safe_unicode(s: Any) -> str: + try: + return _unicode(s) + except UnicodeDecodeError: + return repr(s) + + +class LogFormatter(logging.Formatter): + """Log formatter used in Tornado. + + Key features of this formatter are: + + * Color support when logging to a terminal that supports it. + * Timestamps on every log line. + * Robust against str/bytes encoding problems. + + This formatter is enabled automatically by + `tornado.options.parse_command_line` or `tornado.options.parse_config_file` + (unless ``--logging=none`` is used). + + Color support on Windows versions that do not support ANSI color codes is + enabled by use of the colorama__ library. Applications that wish to use + this must first initialize colorama with a call to ``colorama.init``. + See the colorama documentation for details. + + __ https://pypi.python.org/pypi/colorama + + .. versionchanged:: 4.5 + Added support for ``colorama``. Changed the constructor + signature to be compatible with `logging.config.dictConfig`. + """ + + DEFAULT_FORMAT = "%(color)s[%(levelname)1.1s %(asctime)s %(module)s:%(lineno)d]%(end_color)s %(message)s" # noqa: E501 + DEFAULT_DATE_FORMAT = "%y%m%d %H:%M:%S" + DEFAULT_COLORS = { + logging.DEBUG: 4, # Blue + logging.INFO: 2, # Green + logging.WARNING: 3, # Yellow + logging.ERROR: 1, # Red + logging.CRITICAL: 5, # Magenta + } + + def __init__( + self, + fmt: str = DEFAULT_FORMAT, + datefmt: str = DEFAULT_DATE_FORMAT, + style: str = "%", + color: bool = True, + colors: Dict[int, int] = DEFAULT_COLORS, + ) -> None: + r""" + :arg bool color: Enables color support. + :arg str fmt: Log message format. + It will be applied to the attributes dict of log records. The + text between ``%(color)s`` and ``%(end_color)s`` will be colored + depending on the level if color support is on. + :arg dict colors: color mappings from logging level to terminal color + code + :arg str datefmt: Datetime format. + Used for formatting ``(asctime)`` placeholder in ``prefix_fmt``. + + .. versionchanged:: 3.2 + + Added ``fmt`` and ``datefmt`` arguments. + """ + logging.Formatter.__init__(self, datefmt=datefmt) + self._fmt = fmt + + self._colors = {} # type: Dict[int, str] + if color and _stderr_supports_color(): + if curses is not None: + fg_color = curses.tigetstr("setaf") or curses.tigetstr("setf") or b"" + + for levelno, code in colors.items(): + # Convert the terminal control characters from + # bytes to unicode strings for easier use with the + # logging module. + self._colors[levelno] = unicode_type( + curses.tparm(fg_color, code), "ascii" + ) + self._normal = unicode_type(curses.tigetstr("sgr0"), "ascii") + else: + # If curses is not present (currently we'll only get here for + # colorama on windows), assume hard-coded ANSI color codes. + for levelno, code in colors.items(): + self._colors[levelno] = "\033[2;3%dm" % code + self._normal = "\033[0m" + else: + self._normal = "" + + def format(self, record: Any) -> str: + try: + message = record.getMessage() + assert isinstance(message, basestring_type) # guaranteed by logging + # Encoding notes: The logging module prefers to work with character + # strings, but only enforces that log messages are instances of + # basestring. In python 2, non-ascii bytestrings will make + # their way through the logging framework until they blow up with + # an unhelpful decoding error (with this formatter it happens + # when we attach the prefix, but there are other opportunities for + # exceptions further along in the framework). + # + # If a byte string makes it this far, convert it to unicode to + # ensure it will make it out to the logs. Use repr() as a fallback + # to ensure that all byte strings can be converted successfully, + # but don't do it by default so we don't add extra quotes to ascii + # bytestrings. This is a bit of a hacky place to do this, but + # it's worth it since the encoding errors that would otherwise + # result are so useless (and tornado is fond of using utf8-encoded + # byte strings wherever possible). + record.message = _safe_unicode(message) + except Exception as e: + record.message = "Bad message (%r): %r" % (e, record.__dict__) + + record.asctime = self.formatTime(record, cast(str, self.datefmt)) + + if record.levelno in self._colors: + record.color = self._colors[record.levelno] + record.end_color = self._normal + else: + record.color = record.end_color = "" + + formatted = self._fmt % record.__dict__ + + if record.exc_info: + if not record.exc_text: + record.exc_text = self.formatException(record.exc_info) + if record.exc_text: + # exc_text contains multiple lines. We need to _safe_unicode + # each line separately so that non-utf8 bytes don't cause + # all the newlines to turn into '\n'. + lines = [formatted.rstrip()] + lines.extend(_safe_unicode(ln) for ln in record.exc_text.split("\n")) + formatted = "\n".join(lines) + return formatted.replace("\n", "\n ") + + +def enable_pretty_logging( + options: Any = None, logger: Optional[logging.Logger] = None +) -> None: + """Turns on formatted logging output as configured. + + This is called automatically by `tornado.options.parse_command_line` + and `tornado.options.parse_config_file`. + """ + if options is None: + import tornado.options + + options = tornado.options.options + if options.logging is None or options.logging.lower() == "none": + return + if logger is None: + logger = logging.getLogger() + logger.setLevel(getattr(logging, options.logging.upper())) + if options.log_file_prefix: + rotate_mode = options.log_rotate_mode + if rotate_mode == "size": + channel = logging.handlers.RotatingFileHandler( + filename=options.log_file_prefix, + maxBytes=options.log_file_max_size, + backupCount=options.log_file_num_backups, + encoding="utf-8", + ) # type: logging.Handler + elif rotate_mode == "time": + channel = logging.handlers.TimedRotatingFileHandler( + filename=options.log_file_prefix, + when=options.log_rotate_when, + interval=options.log_rotate_interval, + backupCount=options.log_file_num_backups, + encoding="utf-8", + ) + else: + error_message = ( + "The value of log_rotate_mode option should be " + + '"size" or "time", not "%s".' % rotate_mode + ) + raise ValueError(error_message) + channel.setFormatter(LogFormatter(color=False)) + logger.addHandler(channel) + + if options.log_to_stderr or (options.log_to_stderr is None and not logger.handlers): + # Set up color if we are in a tty and curses is installed + channel = logging.StreamHandler() + channel.setFormatter(LogFormatter()) + logger.addHandler(channel) + + +def define_logging_options(options: Any = None) -> None: + """Add logging-related flags to ``options``. + + These options are present automatically on the default options instance; + this method is only necessary if you have created your own `.OptionParser`. + + .. versionadded:: 4.2 + This function existed in prior versions but was broken and undocumented until 4.2. + """ + if options is None: + # late import to prevent cycle + import tornado.options + + options = tornado.options.options + options.define( + "logging", + default="info", + help=( + "Set the Python log level. If 'none', tornado won't touch the " + "logging configuration." + ), + metavar="debug|info|warning|error|none", + ) + options.define( + "log_to_stderr", + type=bool, + default=None, + help=( + "Send log output to stderr (colorized if possible). " + "By default use stderr if --log_file_prefix is not set and " + "no other logging is configured." + ), + ) + options.define( + "log_file_prefix", + type=str, + default=None, + metavar="PATH", + help=( + "Path prefix for log files. " + "Note that if you are running multiple tornado processes, " + "log_file_prefix must be different for each of them (e.g. " + "include the port number)" + ), + ) + options.define( + "log_file_max_size", + type=int, + default=100 * 1000 * 1000, + help="max size of log files before rollover", + ) + options.define( + "log_file_num_backups", type=int, default=10, help="number of log files to keep" + ) + + options.define( + "log_rotate_when", + type=str, + default="midnight", + help=( + "specify the type of TimedRotatingFileHandler interval " + "other options:('S', 'M', 'H', 'D', 'W0'-'W6')" + ), + ) + options.define( + "log_rotate_interval", + type=int, + default=1, + help="The interval value of timed rotating", + ) + + options.define( + "log_rotate_mode", + type=str, + default="size", + help="The mode of rotating files(time or size)", + ) + + options.add_parse_callback(lambda: enable_pretty_logging(options)) diff --git a/venv/lib/python3.8/site-packages/tornado/netutil.py b/venv/lib/python3.8/site-packages/tornado/netutil.py new file mode 100644 index 0000000..868d3e9 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/netutil.py @@ -0,0 +1,617 @@ +# +# Copyright 2011 Facebook +# +# 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. + +"""Miscellaneous network utility code.""" + +import concurrent.futures +import errno +import os +import sys +import socket +import ssl +import stat + +from tornado.concurrent import dummy_executor, run_on_executor +from tornado.ioloop import IOLoop +from tornado.util import Configurable, errno_from_exception + +from typing import List, Callable, Any, Type, Dict, Union, Tuple, Awaitable, Optional + +# Note that the naming of ssl.Purpose is confusing; the purpose +# of a context is to authentiate the opposite side of the connection. +_client_ssl_defaults = ssl.create_default_context(ssl.Purpose.SERVER_AUTH) +_server_ssl_defaults = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) +if hasattr(ssl, "OP_NO_COMPRESSION"): + # See netutil.ssl_options_to_context + _client_ssl_defaults.options |= ssl.OP_NO_COMPRESSION + _server_ssl_defaults.options |= ssl.OP_NO_COMPRESSION + +# ThreadedResolver runs getaddrinfo on a thread. If the hostname is unicode, +# getaddrinfo attempts to import encodings.idna. If this is done at +# module-import time, the import lock is already held by the main thread, +# leading to deadlock. Avoid it by caching the idna encoder on the main +# thread now. +u"foo".encode("idna") + +# For undiagnosed reasons, 'latin1' codec may also need to be preloaded. +u"foo".encode("latin1") + +# Default backlog used when calling sock.listen() +_DEFAULT_BACKLOG = 128 + + +def bind_sockets( + port: int, + address: Optional[str] = None, + family: socket.AddressFamily = socket.AF_UNSPEC, + backlog: int = _DEFAULT_BACKLOG, + flags: Optional[int] = None, + reuse_port: bool = False, +) -> List[socket.socket]: + """Creates listening sockets bound to the given port and address. + + Returns a list of socket objects (multiple sockets are returned if + the given address maps to multiple IP addresses, which is most common + for mixed IPv4 and IPv6 use). + + Address may be either an IP address or hostname. If it's a hostname, + the server will listen on all IP addresses associated with the + name. Address may be an empty string or None to listen on all + available interfaces. Family may be set to either `socket.AF_INET` + or `socket.AF_INET6` to restrict to IPv4 or IPv6 addresses, otherwise + both will be used if available. + + The ``backlog`` argument has the same meaning as for + `socket.listen() <socket.socket.listen>`. + + ``flags`` is a bitmask of AI_* flags to `~socket.getaddrinfo`, like + ``socket.AI_PASSIVE | socket.AI_NUMERICHOST``. + + ``reuse_port`` option sets ``SO_REUSEPORT`` option for every socket + in the list. If your platform doesn't support this option ValueError will + be raised. + """ + if reuse_port and not hasattr(socket, "SO_REUSEPORT"): + raise ValueError("the platform doesn't support SO_REUSEPORT") + + sockets = [] + if address == "": + address = None + if not socket.has_ipv6 and family == socket.AF_UNSPEC: + # Python can be compiled with --disable-ipv6, which causes + # operations on AF_INET6 sockets to fail, but does not + # automatically exclude those results from getaddrinfo + # results. + # http://bugs.python.org/issue16208 + family = socket.AF_INET + if flags is None: + flags = socket.AI_PASSIVE + bound_port = None + unique_addresses = set() # type: set + for res in sorted( + socket.getaddrinfo(address, port, family, socket.SOCK_STREAM, 0, flags), + key=lambda x: x[0], + ): + if res in unique_addresses: + continue + + unique_addresses.add(res) + + af, socktype, proto, canonname, sockaddr = res + if ( + sys.platform == "darwin" + and address == "localhost" + and af == socket.AF_INET6 + and sockaddr[3] != 0 + ): + # Mac OS X includes a link-local address fe80::1%lo0 in the + # getaddrinfo results for 'localhost'. However, the firewall + # doesn't understand that this is a local address and will + # prompt for access (often repeatedly, due to an apparent + # bug in its ability to remember granting access to an + # application). Skip these addresses. + continue + try: + sock = socket.socket(af, socktype, proto) + except socket.error as e: + if errno_from_exception(e) == errno.EAFNOSUPPORT: + continue + raise + if os.name != "nt": + try: + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + except socket.error as e: + if errno_from_exception(e) != errno.ENOPROTOOPT: + # Hurd doesn't support SO_REUSEADDR. + raise + if reuse_port: + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) + if af == socket.AF_INET6: + # On linux, ipv6 sockets accept ipv4 too by default, + # but this makes it impossible to bind to both + # 0.0.0.0 in ipv4 and :: in ipv6. On other systems, + # separate sockets *must* be used to listen for both ipv4 + # and ipv6. For consistency, always disable ipv4 on our + # ipv6 sockets and use a separate ipv4 socket when needed. + # + # Python 2.x on windows doesn't have IPPROTO_IPV6. + if hasattr(socket, "IPPROTO_IPV6"): + sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1) + + # automatic port allocation with port=None + # should bind on the same port on IPv4 and IPv6 + host, requested_port = sockaddr[:2] + if requested_port == 0 and bound_port is not None: + sockaddr = tuple([host, bound_port] + list(sockaddr[2:])) + + sock.setblocking(False) + try: + sock.bind(sockaddr) + except OSError as e: + if ( + errno_from_exception(e) == errno.EADDRNOTAVAIL + and address == "localhost" + and sockaddr[0] == "::1" + ): + # On some systems (most notably docker with default + # configurations), ipv6 is partially disabled: + # socket.has_ipv6 is true, we can create AF_INET6 + # sockets, and getaddrinfo("localhost", ..., + # AF_PASSIVE) resolves to ::1, but we get an error + # when binding. + # + # Swallow the error, but only for this specific case. + # If EADDRNOTAVAIL occurs in other situations, it + # might be a real problem like a typo in a + # configuration. + sock.close() + continue + else: + raise + bound_port = sock.getsockname()[1] + sock.listen(backlog) + sockets.append(sock) + return sockets + + +if hasattr(socket, "AF_UNIX"): + + def bind_unix_socket( + file: str, mode: int = 0o600, backlog: int = _DEFAULT_BACKLOG + ) -> socket.socket: + """Creates a listening unix socket. + + If a socket with the given name already exists, it will be deleted. + If any other file with that name exists, an exception will be + raised. + + Returns a socket object (not a list of socket objects like + `bind_sockets`) + """ + sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + try: + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + except socket.error as e: + if errno_from_exception(e) != errno.ENOPROTOOPT: + # Hurd doesn't support SO_REUSEADDR + raise + sock.setblocking(False) + try: + st = os.stat(file) + except FileNotFoundError: + pass + else: + if stat.S_ISSOCK(st.st_mode): + os.remove(file) + else: + raise ValueError("File %s exists and is not a socket", file) + sock.bind(file) + os.chmod(file, mode) + sock.listen(backlog) + return sock + + +def add_accept_handler( + sock: socket.socket, callback: Callable[[socket.socket, Any], None] +) -> Callable[[], None]: + """Adds an `.IOLoop` event handler to accept new connections on ``sock``. + + When a connection is accepted, ``callback(connection, address)`` will + be run (``connection`` is a socket object, and ``address`` is the + address of the other end of the connection). Note that this signature + is different from the ``callback(fd, events)`` signature used for + `.IOLoop` handlers. + + A callable is returned which, when called, will remove the `.IOLoop` + event handler and stop processing further incoming connections. + + .. versionchanged:: 5.0 + The ``io_loop`` argument (deprecated since version 4.1) has been removed. + + .. versionchanged:: 5.0 + A callable is returned (``None`` was returned before). + """ + io_loop = IOLoop.current() + removed = [False] + + def accept_handler(fd: socket.socket, events: int) -> None: + # More connections may come in while we're handling callbacks; + # to prevent starvation of other tasks we must limit the number + # of connections we accept at a time. Ideally we would accept + # up to the number of connections that were waiting when we + # entered this method, but this information is not available + # (and rearranging this method to call accept() as many times + # as possible before running any callbacks would have adverse + # effects on load balancing in multiprocess configurations). + # Instead, we use the (default) listen backlog as a rough + # heuristic for the number of connections we can reasonably + # accept at once. + for i in range(_DEFAULT_BACKLOG): + if removed[0]: + # The socket was probably closed + return + try: + connection, address = sock.accept() + except BlockingIOError: + # EWOULDBLOCK indicates we have accepted every + # connection that is available. + return + except ConnectionAbortedError: + # ECONNABORTED indicates that there was a connection + # but it was closed while still in the accept queue. + # (observed on FreeBSD). + continue + callback(connection, address) + + def remove_handler() -> None: + io_loop.remove_handler(sock) + removed[0] = True + + io_loop.add_handler(sock, accept_handler, IOLoop.READ) + return remove_handler + + +def is_valid_ip(ip: str) -> bool: + """Returns ``True`` if the given string is a well-formed IP address. + + Supports IPv4 and IPv6. + """ + if not ip or "\x00" in ip: + # getaddrinfo resolves empty strings to localhost, and truncates + # on zero bytes. + return False + try: + res = socket.getaddrinfo( + ip, 0, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_NUMERICHOST + ) + return bool(res) + except socket.gaierror as e: + if e.args[0] == socket.EAI_NONAME: + return False + raise + return True + + +class Resolver(Configurable): + """Configurable asynchronous DNS resolver interface. + + By default, a blocking implementation is used (which simply calls + `socket.getaddrinfo`). An alternative implementation can be + chosen with the `Resolver.configure <.Configurable.configure>` + class method:: + + Resolver.configure('tornado.netutil.ThreadedResolver') + + The implementations of this interface included with Tornado are + + * `tornado.netutil.DefaultExecutorResolver` + * `tornado.netutil.BlockingResolver` (deprecated) + * `tornado.netutil.ThreadedResolver` (deprecated) + * `tornado.netutil.OverrideResolver` + * `tornado.platform.twisted.TwistedResolver` + * `tornado.platform.caresresolver.CaresResolver` + + .. versionchanged:: 5.0 + The default implementation has changed from `BlockingResolver` to + `DefaultExecutorResolver`. + """ + + @classmethod + def configurable_base(cls) -> Type["Resolver"]: + return Resolver + + @classmethod + def configurable_default(cls) -> Type["Resolver"]: + return DefaultExecutorResolver + + def resolve( + self, host: str, port: int, family: socket.AddressFamily = socket.AF_UNSPEC + ) -> Awaitable[List[Tuple[int, Any]]]: + """Resolves an address. + + The ``host`` argument is a string which may be a hostname or a + literal IP address. + + Returns a `.Future` whose result is a list of (family, + address) pairs, where address is a tuple suitable to pass to + `socket.connect <socket.socket.connect>` (i.e. a ``(host, + port)`` pair for IPv4; additional fields may be present for + IPv6). If a ``callback`` is passed, it will be run with the + result as an argument when it is complete. + + :raises IOError: if the address cannot be resolved. + + .. versionchanged:: 4.4 + Standardized all implementations to raise `IOError`. + + .. versionchanged:: 6.0 The ``callback`` argument was removed. + Use the returned awaitable object instead. + + """ + raise NotImplementedError() + + def close(self) -> None: + """Closes the `Resolver`, freeing any resources used. + + .. versionadded:: 3.1 + + """ + pass + + +def _resolve_addr( + host: str, port: int, family: socket.AddressFamily = socket.AF_UNSPEC +) -> List[Tuple[int, Any]]: + # On Solaris, getaddrinfo fails if the given port is not found + # in /etc/services and no socket type is given, so we must pass + # one here. The socket type used here doesn't seem to actually + # matter (we discard the one we get back in the results), + # so the addresses we return should still be usable with SOCK_DGRAM. + addrinfo = socket.getaddrinfo(host, port, family, socket.SOCK_STREAM) + results = [] + for fam, socktype, proto, canonname, address in addrinfo: + results.append((fam, address)) + return results # type: ignore + + +class DefaultExecutorResolver(Resolver): + """Resolver implementation using `.IOLoop.run_in_executor`. + + .. versionadded:: 5.0 + """ + + async def resolve( + self, host: str, port: int, family: socket.AddressFamily = socket.AF_UNSPEC + ) -> List[Tuple[int, Any]]: + result = await IOLoop.current().run_in_executor( + None, _resolve_addr, host, port, family + ) + return result + + +class ExecutorResolver(Resolver): + """Resolver implementation using a `concurrent.futures.Executor`. + + Use this instead of `ThreadedResolver` when you require additional + control over the executor being used. + + The executor will be shut down when the resolver is closed unless + ``close_resolver=False``; use this if you want to reuse the same + executor elsewhere. + + .. versionchanged:: 5.0 + The ``io_loop`` argument (deprecated since version 4.1) has been removed. + + .. deprecated:: 5.0 + The default `Resolver` now uses `.IOLoop.run_in_executor`; use that instead + of this class. + """ + + def initialize( + self, + executor: Optional[concurrent.futures.Executor] = None, + close_executor: bool = True, + ) -> None: + self.io_loop = IOLoop.current() + if executor is not None: + self.executor = executor + self.close_executor = close_executor + else: + self.executor = dummy_executor + self.close_executor = False + + def close(self) -> None: + if self.close_executor: + self.executor.shutdown() + self.executor = None # type: ignore + + @run_on_executor + def resolve( + self, host: str, port: int, family: socket.AddressFamily = socket.AF_UNSPEC + ) -> List[Tuple[int, Any]]: + return _resolve_addr(host, port, family) + + +class BlockingResolver(ExecutorResolver): + """Default `Resolver` implementation, using `socket.getaddrinfo`. + + The `.IOLoop` will be blocked during the resolution, although the + callback will not be run until the next `.IOLoop` iteration. + + .. deprecated:: 5.0 + The default `Resolver` now uses `.IOLoop.run_in_executor`; use that instead + of this class. + """ + + def initialize(self) -> None: # type: ignore + super().initialize() + + +class ThreadedResolver(ExecutorResolver): + """Multithreaded non-blocking `Resolver` implementation. + + Requires the `concurrent.futures` package to be installed + (available in the standard library since Python 3.2, + installable with ``pip install futures`` in older versions). + + The thread pool size can be configured with:: + + Resolver.configure('tornado.netutil.ThreadedResolver', + num_threads=10) + + .. versionchanged:: 3.1 + All ``ThreadedResolvers`` share a single thread pool, whose + size is set by the first one to be created. + + .. deprecated:: 5.0 + The default `Resolver` now uses `.IOLoop.run_in_executor`; use that instead + of this class. + """ + + _threadpool = None # type: ignore + _threadpool_pid = None # type: int + + def initialize(self, num_threads: int = 10) -> None: # type: ignore + threadpool = ThreadedResolver._create_threadpool(num_threads) + super().initialize(executor=threadpool, close_executor=False) + + @classmethod + def _create_threadpool( + cls, num_threads: int + ) -> concurrent.futures.ThreadPoolExecutor: + pid = os.getpid() + if cls._threadpool_pid != pid: + # Threads cannot survive after a fork, so if our pid isn't what it + # was when we created the pool then delete it. + cls._threadpool = None + if cls._threadpool is None: + cls._threadpool = concurrent.futures.ThreadPoolExecutor(num_threads) + cls._threadpool_pid = pid + return cls._threadpool + + +class OverrideResolver(Resolver): + """Wraps a resolver with a mapping of overrides. + + This can be used to make local DNS changes (e.g. for testing) + without modifying system-wide settings. + + The mapping can be in three formats:: + + { + # Hostname to host or ip + "example.com": "127.0.1.1", + + # Host+port to host+port + ("login.example.com", 443): ("localhost", 1443), + + # Host+port+address family to host+port + ("login.example.com", 443, socket.AF_INET6): ("::1", 1443), + } + + .. versionchanged:: 5.0 + Added support for host-port-family triplets. + """ + + def initialize(self, resolver: Resolver, mapping: dict) -> None: + self.resolver = resolver + self.mapping = mapping + + def close(self) -> None: + self.resolver.close() + + def resolve( + self, host: str, port: int, family: socket.AddressFamily = socket.AF_UNSPEC + ) -> Awaitable[List[Tuple[int, Any]]]: + if (host, port, family) in self.mapping: + host, port = self.mapping[(host, port, family)] + elif (host, port) in self.mapping: + host, port = self.mapping[(host, port)] + elif host in self.mapping: + host = self.mapping[host] + return self.resolver.resolve(host, port, family) + + +# These are the keyword arguments to ssl.wrap_socket that must be translated +# to their SSLContext equivalents (the other arguments are still passed +# to SSLContext.wrap_socket). +_SSL_CONTEXT_KEYWORDS = frozenset( + ["ssl_version", "certfile", "keyfile", "cert_reqs", "ca_certs", "ciphers"] +) + + +def ssl_options_to_context( + ssl_options: Union[Dict[str, Any], ssl.SSLContext] +) -> ssl.SSLContext: + """Try to convert an ``ssl_options`` dictionary to an + `~ssl.SSLContext` object. + + The ``ssl_options`` dictionary contains keywords to be passed to + `ssl.wrap_socket`. In Python 2.7.9+, `ssl.SSLContext` objects can + be used instead. This function converts the dict form to its + `~ssl.SSLContext` equivalent, and may be used when a component which + accepts both forms needs to upgrade to the `~ssl.SSLContext` version + to use features like SNI or NPN. + """ + if isinstance(ssl_options, ssl.SSLContext): + return ssl_options + assert isinstance(ssl_options, dict) + assert all(k in _SSL_CONTEXT_KEYWORDS for k in ssl_options), ssl_options + # Can't use create_default_context since this interface doesn't + # tell us client vs server. + context = ssl.SSLContext(ssl_options.get("ssl_version", ssl.PROTOCOL_SSLv23)) + if "certfile" in ssl_options: + context.load_cert_chain( + ssl_options["certfile"], ssl_options.get("keyfile", None) + ) + if "cert_reqs" in ssl_options: + context.verify_mode = ssl_options["cert_reqs"] + if "ca_certs" in ssl_options: + context.load_verify_locations(ssl_options["ca_certs"]) + if "ciphers" in ssl_options: + context.set_ciphers(ssl_options["ciphers"]) + if hasattr(ssl, "OP_NO_COMPRESSION"): + # Disable TLS compression to avoid CRIME and related attacks. + # This constant depends on openssl version 1.0. + # TODO: Do we need to do this ourselves or can we trust + # the defaults? + context.options |= ssl.OP_NO_COMPRESSION + return context + + +def ssl_wrap_socket( + socket: socket.socket, + ssl_options: Union[Dict[str, Any], ssl.SSLContext], + server_hostname: Optional[str] = None, + **kwargs: Any +) -> ssl.SSLSocket: + """Returns an ``ssl.SSLSocket`` wrapping the given socket. + + ``ssl_options`` may be either an `ssl.SSLContext` object or a + dictionary (as accepted by `ssl_options_to_context`). Additional + keyword arguments are passed to ``wrap_socket`` (either the + `~ssl.SSLContext` method or the `ssl` module function as + appropriate). + """ + context = ssl_options_to_context(ssl_options) + if ssl.HAS_SNI: + # In python 3.4, wrap_socket only accepts the server_hostname + # argument if HAS_SNI is true. + # TODO: add a unittest (python added server-side SNI support in 3.4) + # In the meantime it can be manually tested with + # python3 -m tornado.httpclient https://sni.velox.ch + return context.wrap_socket(socket, server_hostname=server_hostname, **kwargs) + else: + return context.wrap_socket(socket, **kwargs) diff --git a/venv/lib/python3.8/site-packages/tornado/options.py b/venv/lib/python3.8/site-packages/tornado/options.py new file mode 100644 index 0000000..f0b89a9 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/options.py @@ -0,0 +1,735 @@ +# +# Copyright 2009 Facebook +# +# 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. + +"""A command line parsing module that lets modules define their own options. + +This module is inspired by Google's `gflags +<https://github.com/google/python-gflags>`_. The primary difference +with libraries such as `argparse` is that a global registry is used so +that options may be defined in any module (it also enables +`tornado.log` by default). The rest of Tornado does not depend on this +module, so feel free to use `argparse` or other configuration +libraries if you prefer them. + +Options must be defined with `tornado.options.define` before use, +generally at the top level of a module. The options are then +accessible as attributes of `tornado.options.options`:: + + # myapp/db.py + from tornado.options import define, options + + define("mysql_host", default="127.0.0.1:3306", help="Main user DB") + define("memcache_hosts", default="127.0.0.1:11011", multiple=True, + help="Main user memcache servers") + + def connect(): + db = database.Connection(options.mysql_host) + ... + + # myapp/server.py + from tornado.options import define, options + + define("port", default=8080, help="port to listen on") + + def start_server(): + app = make_app() + app.listen(options.port) + +The ``main()`` method of your application does not need to be aware of all of +the options used throughout your program; they are all automatically loaded +when the modules are loaded. However, all modules that define options +must have been imported before the command line is parsed. + +Your ``main()`` method can parse the command line or parse a config file with +either `parse_command_line` or `parse_config_file`:: + + import myapp.db, myapp.server + import tornado.options + + if __name__ == '__main__': + tornado.options.parse_command_line() + # or + tornado.options.parse_config_file("/etc/server.conf") + +.. note:: + + When using multiple ``parse_*`` functions, pass ``final=False`` to all + but the last one, or side effects may occur twice (in particular, + this can result in log messages being doubled). + +`tornado.options.options` is a singleton instance of `OptionParser`, and +the top-level functions in this module (`define`, `parse_command_line`, etc) +simply call methods on it. You may create additional `OptionParser` +instances to define isolated sets of options, such as for subcommands. + +.. note:: + + By default, several options are defined that will configure the + standard `logging` module when `parse_command_line` or `parse_config_file` + are called. If you want Tornado to leave the logging configuration + alone so you can manage it yourself, either pass ``--logging=none`` + on the command line or do the following to disable it in code:: + + from tornado.options import options, parse_command_line + options.logging = None + parse_command_line() + +.. versionchanged:: 4.3 + Dashes and underscores are fully interchangeable in option names; + options can be defined, set, and read with any mix of the two. + Dashes are typical for command-line usage while config files require + underscores. +""" + +import datetime +import numbers +import re +import sys +import os +import textwrap + +from tornado.escape import _unicode, native_str +from tornado.log import define_logging_options +from tornado.util import basestring_type, exec_in + +from typing import ( + Any, + Iterator, + Iterable, + Tuple, + Set, + Dict, + Callable, + List, + TextIO, + Optional, +) + + +class Error(Exception): + """Exception raised by errors in the options module.""" + + pass + + +class OptionParser(object): + """A collection of options, a dictionary with object-like access. + + Normally accessed via static functions in the `tornado.options` module, + which reference a global instance. + """ + + def __init__(self) -> None: + # we have to use self.__dict__ because we override setattr. + self.__dict__["_options"] = {} + self.__dict__["_parse_callbacks"] = [] + self.define( + "help", + type=bool, + help="show this help information", + callback=self._help_callback, + ) + + def _normalize_name(self, name: str) -> str: + return name.replace("_", "-") + + def __getattr__(self, name: str) -> Any: + name = self._normalize_name(name) + if isinstance(self._options.get(name), _Option): + return self._options[name].value() + raise AttributeError("Unrecognized option %r" % name) + + def __setattr__(self, name: str, value: Any) -> None: + name = self._normalize_name(name) + if isinstance(self._options.get(name), _Option): + return self._options[name].set(value) + raise AttributeError("Unrecognized option %r" % name) + + def __iter__(self) -> Iterator: + return (opt.name for opt in self._options.values()) + + def __contains__(self, name: str) -> bool: + name = self._normalize_name(name) + return name in self._options + + def __getitem__(self, name: str) -> Any: + return self.__getattr__(name) + + def __setitem__(self, name: str, value: Any) -> None: + return self.__setattr__(name, value) + + def items(self) -> Iterable[Tuple[str, Any]]: + """An iterable of (name, value) pairs. + + .. versionadded:: 3.1 + """ + return [(opt.name, opt.value()) for name, opt in self._options.items()] + + def groups(self) -> Set[str]: + """The set of option-groups created by ``define``. + + .. versionadded:: 3.1 + """ + return set(opt.group_name for opt in self._options.values()) + + def group_dict(self, group: str) -> Dict[str, Any]: + """The names and values of options in a group. + + Useful for copying options into Application settings:: + + from tornado.options import define, parse_command_line, options + + define('template_path', group='application') + define('static_path', group='application') + + parse_command_line() + + application = Application( + handlers, **options.group_dict('application')) + + .. versionadded:: 3.1 + """ + return dict( + (opt.name, opt.value()) + for name, opt in self._options.items() + if not group or group == opt.group_name + ) + + def as_dict(self) -> Dict[str, Any]: + """The names and values of all options. + + .. versionadded:: 3.1 + """ + return dict((opt.name, opt.value()) for name, opt in self._options.items()) + + def define( + self, + name: str, + default: Any = None, + type: Optional[type] = None, + help: Optional[str] = None, + metavar: Optional[str] = None, + multiple: bool = False, + group: Optional[str] = None, + callback: Optional[Callable[[Any], None]] = None, + ) -> None: + """Defines a new command line option. + + ``type`` can be any of `str`, `int`, `float`, `bool`, + `~datetime.datetime`, or `~datetime.timedelta`. If no ``type`` + is given but a ``default`` is, ``type`` is the type of + ``default``. Otherwise, ``type`` defaults to `str`. + + If ``multiple`` is True, the option value is a list of ``type`` + instead of an instance of ``type``. + + ``help`` and ``metavar`` are used to construct the + automatically generated command line help string. The help + message is formatted like:: + + --name=METAVAR help string + + ``group`` is used to group the defined options in logical + groups. By default, command line options are grouped by the + file in which they are defined. + + Command line option names must be unique globally. + + If a ``callback`` is given, it will be run with the new value whenever + the option is changed. This can be used to combine command-line + and file-based options:: + + define("config", type=str, help="path to config file", + callback=lambda path: parse_config_file(path, final=False)) + + With this definition, options in the file specified by ``--config`` will + override options set earlier on the command line, but can be overridden + by later flags. + + """ + normalized = self._normalize_name(name) + if normalized in self._options: + raise Error( + "Option %r already defined in %s" + % (normalized, self._options[normalized].file_name) + ) + frame = sys._getframe(0) + options_file = frame.f_code.co_filename + + # Can be called directly, or through top level define() fn, in which + # case, step up above that frame to look for real caller. + if ( + frame.f_back.f_code.co_filename == options_file + and frame.f_back.f_code.co_name == "define" + ): + frame = frame.f_back + + file_name = frame.f_back.f_code.co_filename + if file_name == options_file: + file_name = "" + if type is None: + if not multiple and default is not None: + type = default.__class__ + else: + type = str + if group: + group_name = group # type: Optional[str] + else: + group_name = file_name + option = _Option( + name, + file_name=file_name, + default=default, + type=type, + help=help, + metavar=metavar, + multiple=multiple, + group_name=group_name, + callback=callback, + ) + self._options[normalized] = option + + def parse_command_line( + self, args: Optional[List[str]] = None, final: bool = True + ) -> List[str]: + """Parses all options given on the command line (defaults to + `sys.argv`). + + Options look like ``--option=value`` and are parsed according + to their ``type``. For boolean options, ``--option`` is + equivalent to ``--option=true`` + + If the option has ``multiple=True``, comma-separated values + are accepted. For multi-value integer options, the syntax + ``x:y`` is also accepted and equivalent to ``range(x, y)``. + + Note that ``args[0]`` is ignored since it is the program name + in `sys.argv`. + + We return a list of all arguments that are not parsed as options. + + If ``final`` is ``False``, parse callbacks will not be run. + This is useful for applications that wish to combine configurations + from multiple sources. + + """ + if args is None: + args = sys.argv + remaining = [] # type: List[str] + for i in range(1, len(args)): + # All things after the last option are command line arguments + if not args[i].startswith("-"): + remaining = args[i:] + break + if args[i] == "--": + remaining = args[i + 1 :] + break + arg = args[i].lstrip("-") + name, equals, value = arg.partition("=") + name = self._normalize_name(name) + if name not in self._options: + self.print_help() + raise Error("Unrecognized command line option: %r" % name) + option = self._options[name] + if not equals: + if option.type == bool: + value = "true" + else: + raise Error("Option %r requires a value" % name) + option.parse(value) + + if final: + self.run_parse_callbacks() + + return remaining + + def parse_config_file(self, path: str, final: bool = True) -> None: + """Parses and loads the config file at the given path. + + The config file contains Python code that will be executed (so + it is **not safe** to use untrusted config files). Anything in + the global namespace that matches a defined option will be + used to set that option's value. + + Options may either be the specified type for the option or + strings (in which case they will be parsed the same way as in + `.parse_command_line`) + + Example (using the options defined in the top-level docs of + this module):: + + port = 80 + mysql_host = 'mydb.example.com:3306' + # Both lists and comma-separated strings are allowed for + # multiple=True. + memcache_hosts = ['cache1.example.com:11011', + 'cache2.example.com:11011'] + memcache_hosts = 'cache1.example.com:11011,cache2.example.com:11011' + + If ``final`` is ``False``, parse callbacks will not be run. + This is useful for applications that wish to combine configurations + from multiple sources. + + .. note:: + + `tornado.options` is primarily a command-line library. + Config file support is provided for applications that wish + to use it, but applications that prefer config files may + wish to look at other libraries instead. + + .. versionchanged:: 4.1 + Config files are now always interpreted as utf-8 instead of + the system default encoding. + + .. versionchanged:: 4.4 + The special variable ``__file__`` is available inside config + files, specifying the absolute path to the config file itself. + + .. versionchanged:: 5.1 + Added the ability to set options via strings in config files. + + """ + config = {"__file__": os.path.abspath(path)} + with open(path, "rb") as f: + exec_in(native_str(f.read()), config, config) + for name in config: + normalized = self._normalize_name(name) + if normalized in self._options: + option = self._options[normalized] + if option.multiple: + if not isinstance(config[name], (list, str)): + raise Error( + "Option %r is required to be a list of %s " + "or a comma-separated string" + % (option.name, option.type.__name__) + ) + + if type(config[name]) == str and option.type != str: + option.parse(config[name]) + else: + option.set(config[name]) + + if final: + self.run_parse_callbacks() + + def print_help(self, file: Optional[TextIO] = None) -> None: + """Prints all the command line options to stderr (or another file).""" + if file is None: + file = sys.stderr + print("Usage: %s [OPTIONS]" % sys.argv[0], file=file) + print("\nOptions:\n", file=file) + by_group = {} # type: Dict[str, List[_Option]] + for option in self._options.values(): + by_group.setdefault(option.group_name, []).append(option) + + for filename, o in sorted(by_group.items()): + if filename: + print("\n%s options:\n" % os.path.normpath(filename), file=file) + o.sort(key=lambda option: option.name) + for option in o: + # Always print names with dashes in a CLI context. + prefix = self._normalize_name(option.name) + if option.metavar: + prefix += "=" + option.metavar + description = option.help or "" + if option.default is not None and option.default != "": + description += " (default %s)" % option.default + lines = textwrap.wrap(description, 79 - 35) + if len(prefix) > 30 or len(lines) == 0: + lines.insert(0, "") + print(" --%-30s %s" % (prefix, lines[0]), file=file) + for line in lines[1:]: + print("%-34s %s" % (" ", line), file=file) + print(file=file) + + def _help_callback(self, value: bool) -> None: + if value: + self.print_help() + sys.exit(0) + + def add_parse_callback(self, callback: Callable[[], None]) -> None: + """Adds a parse callback, to be invoked when option parsing is done.""" + self._parse_callbacks.append(callback) + + def run_parse_callbacks(self) -> None: + for callback in self._parse_callbacks: + callback() + + def mockable(self) -> "_Mockable": + """Returns a wrapper around self that is compatible with + `mock.patch <unittest.mock.patch>`. + + The `mock.patch <unittest.mock.patch>` function (included in + the standard library `unittest.mock` package since Python 3.3, + or in the third-party ``mock`` package for older versions of + Python) is incompatible with objects like ``options`` that + override ``__getattr__`` and ``__setattr__``. This function + returns an object that can be used with `mock.patch.object + <unittest.mock.patch.object>` to modify option values:: + + with mock.patch.object(options.mockable(), 'name', value): + assert options.name == value + """ + return _Mockable(self) + + +class _Mockable(object): + """`mock.patch` compatible wrapper for `OptionParser`. + + As of ``mock`` version 1.0.1, when an object uses ``__getattr__`` + hooks instead of ``__dict__``, ``patch.__exit__`` tries to delete + the attribute it set instead of setting a new one (assuming that + the object does not capture ``__setattr__``, so the patch + created a new attribute in ``__dict__``). + + _Mockable's getattr and setattr pass through to the underlying + OptionParser, and delattr undoes the effect of a previous setattr. + """ + + def __init__(self, options: OptionParser) -> None: + # Modify __dict__ directly to bypass __setattr__ + self.__dict__["_options"] = options + self.__dict__["_originals"] = {} + + def __getattr__(self, name: str) -> Any: + return getattr(self._options, name) + + def __setattr__(self, name: str, value: Any) -> None: + assert name not in self._originals, "don't reuse mockable objects" + self._originals[name] = getattr(self._options, name) + setattr(self._options, name, value) + + def __delattr__(self, name: str) -> None: + setattr(self._options, name, self._originals.pop(name)) + + +class _Option(object): + # This class could almost be made generic, but the way the types + # interact with the multiple argument makes this tricky. (default + # and the callback use List[T], but type is still Type[T]). + UNSET = object() + + def __init__( + self, + name: str, + default: Any = None, + type: Optional[type] = None, + help: Optional[str] = None, + metavar: Optional[str] = None, + multiple: bool = False, + file_name: Optional[str] = None, + group_name: Optional[str] = None, + callback: Optional[Callable[[Any], None]] = None, + ) -> None: + if default is None and multiple: + default = [] + self.name = name + if type is None: + raise ValueError("type must not be None") + self.type = type + self.help = help + self.metavar = metavar + self.multiple = multiple + self.file_name = file_name + self.group_name = group_name + self.callback = callback + self.default = default + self._value = _Option.UNSET # type: Any + + def value(self) -> Any: + return self.default if self._value is _Option.UNSET else self._value + + def parse(self, value: str) -> Any: + _parse = { + datetime.datetime: self._parse_datetime, + datetime.timedelta: self._parse_timedelta, + bool: self._parse_bool, + basestring_type: self._parse_string, + }.get( + self.type, self.type + ) # type: Callable[[str], Any] + if self.multiple: + self._value = [] + for part in value.split(","): + if issubclass(self.type, numbers.Integral): + # allow ranges of the form X:Y (inclusive at both ends) + lo_str, _, hi_str = part.partition(":") + lo = _parse(lo_str) + hi = _parse(hi_str) if hi_str else lo + self._value.extend(range(lo, hi + 1)) + else: + self._value.append(_parse(part)) + else: + self._value = _parse(value) + if self.callback is not None: + self.callback(self._value) + return self.value() + + def set(self, value: Any) -> None: + if self.multiple: + if not isinstance(value, list): + raise Error( + "Option %r is required to be a list of %s" + % (self.name, self.type.__name__) + ) + for item in value: + if item is not None and not isinstance(item, self.type): + raise Error( + "Option %r is required to be a list of %s" + % (self.name, self.type.__name__) + ) + else: + if value is not None and not isinstance(value, self.type): + raise Error( + "Option %r is required to be a %s (%s given)" + % (self.name, self.type.__name__, type(value)) + ) + self._value = value + if self.callback is not None: + self.callback(self._value) + + # Supported date/time formats in our options + _DATETIME_FORMATS = [ + "%a %b %d %H:%M:%S %Y", + "%Y-%m-%d %H:%M:%S", + "%Y-%m-%d %H:%M", + "%Y-%m-%dT%H:%M", + "%Y%m%d %H:%M:%S", + "%Y%m%d %H:%M", + "%Y-%m-%d", + "%Y%m%d", + "%H:%M:%S", + "%H:%M", + ] + + def _parse_datetime(self, value: str) -> datetime.datetime: + for format in self._DATETIME_FORMATS: + try: + return datetime.datetime.strptime(value, format) + except ValueError: + pass + raise Error("Unrecognized date/time format: %r" % value) + + _TIMEDELTA_ABBREV_DICT = { + "h": "hours", + "m": "minutes", + "min": "minutes", + "s": "seconds", + "sec": "seconds", + "ms": "milliseconds", + "us": "microseconds", + "d": "days", + "w": "weeks", + } + + _FLOAT_PATTERN = r"[-+]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][-+]?\d+)?" + + _TIMEDELTA_PATTERN = re.compile( + r"\s*(%s)\s*(\w*)\s*" % _FLOAT_PATTERN, re.IGNORECASE + ) + + def _parse_timedelta(self, value: str) -> datetime.timedelta: + try: + sum = datetime.timedelta() + start = 0 + while start < len(value): + m = self._TIMEDELTA_PATTERN.match(value, start) + if not m: + raise Exception() + num = float(m.group(1)) + units = m.group(2) or "seconds" + units = self._TIMEDELTA_ABBREV_DICT.get(units, units) + sum += datetime.timedelta(**{units: num}) + start = m.end() + return sum + except Exception: + raise + + def _parse_bool(self, value: str) -> bool: + return value.lower() not in ("false", "0", "f") + + def _parse_string(self, value: str) -> str: + return _unicode(value) + + +options = OptionParser() +"""Global options object. + +All defined options are available as attributes on this object. +""" + + +def define( + name: str, + default: Any = None, + type: Optional[type] = None, + help: Optional[str] = None, + metavar: Optional[str] = None, + multiple: bool = False, + group: Optional[str] = None, + callback: Optional[Callable[[Any], None]] = None, +) -> None: + """Defines an option in the global namespace. + + See `OptionParser.define`. + """ + return options.define( + name, + default=default, + type=type, + help=help, + metavar=metavar, + multiple=multiple, + group=group, + callback=callback, + ) + + +def parse_command_line( + args: Optional[List[str]] = None, final: bool = True +) -> List[str]: + """Parses global options from the command line. + + See `OptionParser.parse_command_line`. + """ + return options.parse_command_line(args, final=final) + + +def parse_config_file(path: str, final: bool = True) -> None: + """Parses global options from a config file. + + See `OptionParser.parse_config_file`. + """ + return options.parse_config_file(path, final=final) + + +def print_help(file: Optional[TextIO] = None) -> None: + """Prints all the command line options to stderr (or another file). + + See `OptionParser.print_help`. + """ + return options.print_help(file) + + +def add_parse_callback(callback: Callable[[], None]) -> None: + """Adds a parse callback, to be invoked when option parsing is done. + + See `OptionParser.add_parse_callback` + """ + options.add_parse_callback(callback) + + +# Default options +define_logging_options(options) diff --git a/venv/lib/python3.8/site-packages/tornado/platform/__init__.py b/venv/lib/python3.8/site-packages/tornado/platform/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.8/site-packages/tornado/platform/asyncio.py b/venv/lib/python3.8/site-packages/tornado/platform/asyncio.py new file mode 100644 index 0000000..012948b --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/platform/asyncio.py @@ -0,0 +1,611 @@ +"""Bridges between the `asyncio` module and Tornado IOLoop. + +.. versionadded:: 3.2 + +This module integrates Tornado with the ``asyncio`` module introduced +in Python 3.4. This makes it possible to combine the two libraries on +the same event loop. + +.. deprecated:: 5.0 + + While the code in this module is still used, it is now enabled + automatically when `asyncio` is available, so applications should + no longer need to refer to this module directly. + +.. note:: + + Tornado is designed to use a selector-based event loop. On Windows, + where a proactor-based event loop has been the default since Python 3.8, + a selector event loop is emulated by running ``select`` on a separate thread. + Configuring ``asyncio`` to use a selector event loop may improve performance + of Tornado (but may reduce performance of other ``asyncio``-based libraries + in the same process). +""" + +import asyncio +import atexit +import concurrent.futures +import errno +import functools +import select +import socket +import sys +import threading +import typing +from tornado.gen import convert_yielded +from tornado.ioloop import IOLoop, _Selectable + +from typing import Any, TypeVar, Awaitable, Callable, Union, Optional, List, Tuple, Dict + +if typing.TYPE_CHECKING: + from typing import Set # noqa: F401 + from typing_extensions import Protocol + + class _HasFileno(Protocol): + def fileno(self) -> int: + pass + + _FileDescriptorLike = Union[int, _HasFileno] + +_T = TypeVar("_T") + + +# Collection of selector thread event loops to shut down on exit. +_selector_loops = set() # type: Set[AddThreadSelectorEventLoop] + + +def _atexit_callback() -> None: + for loop in _selector_loops: + with loop._select_cond: + loop._closing_selector = True + loop._select_cond.notify() + try: + loop._waker_w.send(b"a") + except BlockingIOError: + pass + # If we don't join our (daemon) thread here, we may get a deadlock + # during interpreter shutdown. I don't really understand why. This + # deadlock happens every time in CI (both travis and appveyor) but + # I've never been able to reproduce locally. + loop._thread.join() + _selector_loops.clear() + + +atexit.register(_atexit_callback) + + +class BaseAsyncIOLoop(IOLoop): + def initialize( # type: ignore + self, asyncio_loop: asyncio.AbstractEventLoop, **kwargs: Any + ) -> None: + # asyncio_loop is always the real underlying IOLoop. This is used in + # ioloop.py to maintain the asyncio-to-ioloop mappings. + self.asyncio_loop = asyncio_loop + # selector_loop is an event loop that implements the add_reader family of + # methods. Usually the same as asyncio_loop but differs on platforms such + # as windows where the default event loop does not implement these methods. + self.selector_loop = asyncio_loop + if hasattr(asyncio, "ProactorEventLoop") and isinstance( + asyncio_loop, asyncio.ProactorEventLoop # type: ignore + ): + # Ignore this line for mypy because the abstract method checker + # doesn't understand dynamic proxies. + self.selector_loop = AddThreadSelectorEventLoop(asyncio_loop) # type: ignore + # Maps fd to (fileobj, handler function) pair (as in IOLoop.add_handler) + self.handlers = {} # type: Dict[int, Tuple[Union[int, _Selectable], Callable]] + # Set of fds listening for reads/writes + self.readers = set() # type: Set[int] + self.writers = set() # type: Set[int] + self.closing = False + # If an asyncio loop was closed through an asyncio interface + # instead of IOLoop.close(), we'd never hear about it and may + # have left a dangling reference in our map. In case an + # application (or, more likely, a test suite) creates and + # destroys a lot of event loops in this way, check here to + # ensure that we don't have a lot of dead loops building up in + # the map. + # + # TODO(bdarnell): consider making self.asyncio_loop a weakref + # for AsyncIOMainLoop and make _ioloop_for_asyncio a + # WeakKeyDictionary. + for loop in list(IOLoop._ioloop_for_asyncio): + if loop.is_closed(): + del IOLoop._ioloop_for_asyncio[loop] + IOLoop._ioloop_for_asyncio[asyncio_loop] = self + + self._thread_identity = 0 + + super().initialize(**kwargs) + + def assign_thread_identity() -> None: + self._thread_identity = threading.get_ident() + + self.add_callback(assign_thread_identity) + + def close(self, all_fds: bool = False) -> None: + self.closing = True + for fd in list(self.handlers): + fileobj, handler_func = self.handlers[fd] + self.remove_handler(fd) + if all_fds: + self.close_fd(fileobj) + # Remove the mapping before closing the asyncio loop. If this + # happened in the other order, we could race against another + # initialize() call which would see the closed asyncio loop, + # assume it was closed from the asyncio side, and do this + # cleanup for us, leading to a KeyError. + del IOLoop._ioloop_for_asyncio[self.asyncio_loop] + if self.selector_loop is not self.asyncio_loop: + self.selector_loop.close() + self.asyncio_loop.close() + + def add_handler( + self, fd: Union[int, _Selectable], handler: Callable[..., None], events: int + ) -> None: + fd, fileobj = self.split_fd(fd) + if fd in self.handlers: + raise ValueError("fd %s added twice" % fd) + self.handlers[fd] = (fileobj, handler) + if events & IOLoop.READ: + self.selector_loop.add_reader(fd, self._handle_events, fd, IOLoop.READ) + self.readers.add(fd) + if events & IOLoop.WRITE: + self.selector_loop.add_writer(fd, self._handle_events, fd, IOLoop.WRITE) + self.writers.add(fd) + + def update_handler(self, fd: Union[int, _Selectable], events: int) -> None: + fd, fileobj = self.split_fd(fd) + if events & IOLoop.READ: + if fd not in self.readers: + self.selector_loop.add_reader(fd, self._handle_events, fd, IOLoop.READ) + self.readers.add(fd) + else: + if fd in self.readers: + self.selector_loop.remove_reader(fd) + self.readers.remove(fd) + if events & IOLoop.WRITE: + if fd not in self.writers: + self.selector_loop.add_writer(fd, self._handle_events, fd, IOLoop.WRITE) + self.writers.add(fd) + else: + if fd in self.writers: + self.selector_loop.remove_writer(fd) + self.writers.remove(fd) + + def remove_handler(self, fd: Union[int, _Selectable]) -> None: + fd, fileobj = self.split_fd(fd) + if fd not in self.handlers: + return + if fd in self.readers: + self.selector_loop.remove_reader(fd) + self.readers.remove(fd) + if fd in self.writers: + self.selector_loop.remove_writer(fd) + self.writers.remove(fd) + del self.handlers[fd] + + def _handle_events(self, fd: int, events: int) -> None: + fileobj, handler_func = self.handlers[fd] + handler_func(fileobj, events) + + def start(self) -> None: + try: + old_loop = asyncio.get_event_loop() + except (RuntimeError, AssertionError): + old_loop = None # type: ignore + try: + self._setup_logging() + asyncio.set_event_loop(self.asyncio_loop) + self.asyncio_loop.run_forever() + finally: + asyncio.set_event_loop(old_loop) + + def stop(self) -> None: + self.asyncio_loop.stop() + + def call_at( + self, when: float, callback: Callable[..., None], *args: Any, **kwargs: Any + ) -> object: + # asyncio.call_at supports *args but not **kwargs, so bind them here. + # We do not synchronize self.time and asyncio_loop.time, so + # convert from absolute to relative. + return self.asyncio_loop.call_later( + max(0, when - self.time()), + self._run_callback, + functools.partial(callback, *args, **kwargs), + ) + + def remove_timeout(self, timeout: object) -> None: + timeout.cancel() # type: ignore + + def add_callback(self, callback: Callable, *args: Any, **kwargs: Any) -> None: + if threading.get_ident() == self._thread_identity: + call_soon = self.asyncio_loop.call_soon + else: + call_soon = self.asyncio_loop.call_soon_threadsafe + try: + call_soon(self._run_callback, functools.partial(callback, *args, **kwargs)) + except RuntimeError: + # "Event loop is closed". Swallow the exception for + # consistency with PollIOLoop (and logical consistency + # with the fact that we can't guarantee that an + # add_callback that completes without error will + # eventually execute). + pass + except AttributeError: + # ProactorEventLoop may raise this instead of RuntimeError + # if call_soon_threadsafe races with a call to close(). + # Swallow it too for consistency. + pass + + def add_callback_from_signal( + self, callback: Callable, *args: Any, **kwargs: Any + ) -> None: + try: + self.asyncio_loop.call_soon_threadsafe( + self._run_callback, functools.partial(callback, *args, **kwargs) + ) + except RuntimeError: + pass + + def run_in_executor( + self, + executor: Optional[concurrent.futures.Executor], + func: Callable[..., _T], + *args: Any + ) -> Awaitable[_T]: + return self.asyncio_loop.run_in_executor(executor, func, *args) + + def set_default_executor(self, executor: concurrent.futures.Executor) -> None: + return self.asyncio_loop.set_default_executor(executor) + + +class AsyncIOMainLoop(BaseAsyncIOLoop): + """``AsyncIOMainLoop`` creates an `.IOLoop` that corresponds to the + current ``asyncio`` event loop (i.e. the one returned by + ``asyncio.get_event_loop()``). + + .. deprecated:: 5.0 + + Now used automatically when appropriate; it is no longer necessary + to refer to this class directly. + + .. versionchanged:: 5.0 + + Closing an `AsyncIOMainLoop` now closes the underlying asyncio loop. + """ + + def initialize(self, **kwargs: Any) -> None: # type: ignore + super().initialize(asyncio.get_event_loop(), **kwargs) + + def make_current(self) -> None: + # AsyncIOMainLoop already refers to the current asyncio loop so + # nothing to do here. + pass + + +class AsyncIOLoop(BaseAsyncIOLoop): + """``AsyncIOLoop`` is an `.IOLoop` that runs on an ``asyncio`` event loop. + This class follows the usual Tornado semantics for creating new + ``IOLoops``; these loops are not necessarily related to the + ``asyncio`` default event loop. + + Each ``AsyncIOLoop`` creates a new ``asyncio.EventLoop``; this object + can be accessed with the ``asyncio_loop`` attribute. + + .. versionchanged:: 5.0 + + When an ``AsyncIOLoop`` becomes the current `.IOLoop`, it also sets + the current `asyncio` event loop. + + .. deprecated:: 5.0 + + Now used automatically when appropriate; it is no longer necessary + to refer to this class directly. + """ + + def initialize(self, **kwargs: Any) -> None: # type: ignore + self.is_current = False + loop = asyncio.new_event_loop() + try: + super().initialize(loop, **kwargs) + except Exception: + # If initialize() does not succeed (taking ownership of the loop), + # we have to close it. + loop.close() + raise + + def close(self, all_fds: bool = False) -> None: + if self.is_current: + self.clear_current() + super().close(all_fds=all_fds) + + def make_current(self) -> None: + if not self.is_current: + try: + self.old_asyncio = asyncio.get_event_loop() + except (RuntimeError, AssertionError): + self.old_asyncio = None # type: ignore + self.is_current = True + asyncio.set_event_loop(self.asyncio_loop) + + def _clear_current_hook(self) -> None: + if self.is_current: + asyncio.set_event_loop(self.old_asyncio) + self.is_current = False + + +def to_tornado_future(asyncio_future: asyncio.Future) -> asyncio.Future: + """Convert an `asyncio.Future` to a `tornado.concurrent.Future`. + + .. versionadded:: 4.1 + + .. deprecated:: 5.0 + Tornado ``Futures`` have been merged with `asyncio.Future`, + so this method is now a no-op. + """ + return asyncio_future + + +def to_asyncio_future(tornado_future: asyncio.Future) -> asyncio.Future: + """Convert a Tornado yieldable object to an `asyncio.Future`. + + .. versionadded:: 4.1 + + .. versionchanged:: 4.3 + Now accepts any yieldable object, not just + `tornado.concurrent.Future`. + + .. deprecated:: 5.0 + Tornado ``Futures`` have been merged with `asyncio.Future`, + so this method is now equivalent to `tornado.gen.convert_yielded`. + """ + return convert_yielded(tornado_future) + + +if sys.platform == "win32" and hasattr(asyncio, "WindowsSelectorEventLoopPolicy"): + # "Any thread" and "selector" should be orthogonal, but there's not a clean + # interface for composing policies so pick the right base. + _BasePolicy = asyncio.WindowsSelectorEventLoopPolicy # type: ignore +else: + _BasePolicy = asyncio.DefaultEventLoopPolicy + + +class AnyThreadEventLoopPolicy(_BasePolicy): # type: ignore + """Event loop policy that allows loop creation on any thread. + + The default `asyncio` event loop policy only automatically creates + event loops in the main threads. Other threads must create event + loops explicitly or `asyncio.get_event_loop` (and therefore + `.IOLoop.current`) will fail. Installing this policy allows event + loops to be created automatically on any thread, matching the + behavior of Tornado versions prior to 5.0 (or 5.0 on Python 2). + + Usage:: + + asyncio.set_event_loop_policy(AnyThreadEventLoopPolicy()) + + .. versionadded:: 5.0 + + """ + + def get_event_loop(self) -> asyncio.AbstractEventLoop: + try: + return super().get_event_loop() + except (RuntimeError, AssertionError): + # This was an AssertionError in Python 3.4.2 (which ships with Debian Jessie) + # and changed to a RuntimeError in 3.4.3. + # "There is no current event loop in thread %r" + loop = self.new_event_loop() + self.set_event_loop(loop) + return loop + + +class AddThreadSelectorEventLoop(asyncio.AbstractEventLoop): + """Wrap an event loop to add implementations of the ``add_reader`` method family. + + Instances of this class start a second thread to run a selector. + This thread is completely hidden from the user; all callbacks are + run on the wrapped event loop's thread. + + This class is used automatically by Tornado; applications should not need + to refer to it directly. + + It is safe to wrap any event loop with this class, although it only makes sense + for event loops that do not implement the ``add_reader`` family of methods + themselves (i.e. ``WindowsProactorEventLoop``) + + Closing the ``AddThreadSelectorEventLoop`` also closes the wrapped event loop. + + """ + + # This class is a __getattribute__-based proxy. All attributes other than those + # in this set are proxied through to the underlying loop. + MY_ATTRIBUTES = { + "_consume_waker", + "_select_cond", + "_select_args", + "_closing_selector", + "_thread", + "_handle_event", + "_readers", + "_real_loop", + "_start_select", + "_run_select", + "_handle_select", + "_wake_selector", + "_waker_r", + "_waker_w", + "_writers", + "add_reader", + "add_writer", + "close", + "remove_reader", + "remove_writer", + } + + def __getattribute__(self, name: str) -> Any: + if name in AddThreadSelectorEventLoop.MY_ATTRIBUTES: + return super().__getattribute__(name) + return getattr(self._real_loop, name) + + def __init__(self, real_loop: asyncio.AbstractEventLoop) -> None: + self._real_loop = real_loop + + # Create a thread to run the select system call. We manage this thread + # manually so we can trigger a clean shutdown from an atexit hook. Note + # that due to the order of operations at shutdown, only daemon threads + # can be shut down in this way (non-daemon threads would require the + # introduction of a new hook: https://bugs.python.org/issue41962) + self._select_cond = threading.Condition() + self._select_args = ( + None + ) # type: Optional[Tuple[List[_FileDescriptorLike], List[_FileDescriptorLike]]] + self._closing_selector = False + self._thread = threading.Thread( + name="Tornado selector", daemon=True, target=self._run_select, + ) + self._thread.start() + # Start the select loop once the loop is started. + self._real_loop.call_soon(self._start_select) + + self._readers = {} # type: Dict[_FileDescriptorLike, Callable] + self._writers = {} # type: Dict[_FileDescriptorLike, Callable] + + # Writing to _waker_w will wake up the selector thread, which + # watches for _waker_r to be readable. + self._waker_r, self._waker_w = socket.socketpair() + self._waker_r.setblocking(False) + self._waker_w.setblocking(False) + _selector_loops.add(self) + self.add_reader(self._waker_r, self._consume_waker) + + def __del__(self) -> None: + # If the top-level application code uses asyncio interfaces to + # start and stop the event loop, no objects created in Tornado + # can get a clean shutdown notification. If we're just left to + # be GC'd, we must explicitly close our sockets to avoid + # logging warnings. + _selector_loops.discard(self) + self._waker_r.close() + self._waker_w.close() + + def close(self) -> None: + with self._select_cond: + self._closing_selector = True + self._select_cond.notify() + self._wake_selector() + self._thread.join() + _selector_loops.discard(self) + self._waker_r.close() + self._waker_w.close() + self._real_loop.close() + + def _wake_selector(self) -> None: + try: + self._waker_w.send(b"a") + except BlockingIOError: + pass + + def _consume_waker(self) -> None: + try: + self._waker_r.recv(1024) + except BlockingIOError: + pass + + def _start_select(self) -> None: + # Capture reader and writer sets here in the event loop + # thread to avoid any problems with concurrent + # modification while the select loop uses them. + with self._select_cond: + assert self._select_args is None + self._select_args = (list(self._readers.keys()), list(self._writers.keys())) + self._select_cond.notify() + + def _run_select(self) -> None: + while True: + with self._select_cond: + while self._select_args is None and not self._closing_selector: + self._select_cond.wait() + if self._closing_selector: + return + assert self._select_args is not None + to_read, to_write = self._select_args + self._select_args = None + + # We use the simpler interface of the select module instead of + # the more stateful interface in the selectors module because + # this class is only intended for use on windows, where + # select.select is the only option. The selector interface + # does not have well-documented thread-safety semantics that + # we can rely on so ensuring proper synchronization would be + # tricky. + try: + # On windows, selecting on a socket for write will not + # return the socket when there is an error (but selecting + # for reads works). Also select for errors when selecting + # for writes, and merge the results. + # + # This pattern is also used in + # https://github.com/python/cpython/blob/v3.8.0/Lib/selectors.py#L312-L317 + rs, ws, xs = select.select(to_read, to_write, to_write) + ws = ws + xs + except OSError as e: + # After remove_reader or remove_writer is called, the file + # descriptor may subsequently be closed on the event loop + # thread. It's possible that this select thread hasn't + # gotten into the select system call by the time that + # happens in which case (at least on macOS), select may + # raise a "bad file descriptor" error. If we get that + # error, check and see if we're also being woken up by + # polling the waker alone. If we are, just return to the + # event loop and we'll get the updated set of file + # descriptors on the next iteration. Otherwise, raise the + # original error. + if e.errno == getattr(errno, "WSAENOTSOCK", errno.EBADF): + rs, _, _ = select.select([self._waker_r.fileno()], [], [], 0) + if rs: + ws = [] + else: + raise + else: + raise + self._real_loop.call_soon_threadsafe(self._handle_select, rs, ws) + + def _handle_select( + self, rs: List["_FileDescriptorLike"], ws: List["_FileDescriptorLike"] + ) -> None: + for r in rs: + self._handle_event(r, self._readers) + for w in ws: + self._handle_event(w, self._writers) + self._start_select() + + def _handle_event( + self, fd: "_FileDescriptorLike", cb_map: Dict["_FileDescriptorLike", Callable], + ) -> None: + try: + callback = cb_map[fd] + except KeyError: + return + callback() + + def add_reader( + self, fd: "_FileDescriptorLike", callback: Callable[..., None], *args: Any + ) -> None: + self._readers[fd] = functools.partial(callback, *args) + self._wake_selector() + + def add_writer( + self, fd: "_FileDescriptorLike", callback: Callable[..., None], *args: Any + ) -> None: + self._writers[fd] = functools.partial(callback, *args) + self._wake_selector() + + def remove_reader(self, fd: "_FileDescriptorLike") -> None: + del self._readers[fd] + self._wake_selector() + + def remove_writer(self, fd: "_FileDescriptorLike") -> None: + del self._writers[fd] + self._wake_selector() diff --git a/venv/lib/python3.8/site-packages/tornado/platform/caresresolver.py b/venv/lib/python3.8/site-packages/tornado/platform/caresresolver.py new file mode 100644 index 0000000..e2c5009 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/platform/caresresolver.py @@ -0,0 +1,89 @@ +import pycares # type: ignore +import socket + +from tornado.concurrent import Future +from tornado import gen +from tornado.ioloop import IOLoop +from tornado.netutil import Resolver, is_valid_ip + +import typing + +if typing.TYPE_CHECKING: + from typing import Generator, Any, List, Tuple, Dict # noqa: F401 + + +class CaresResolver(Resolver): + """Name resolver based on the c-ares library. + + This is a non-blocking and non-threaded resolver. It may not produce + the same results as the system resolver, but can be used for non-blocking + resolution when threads cannot be used. + + c-ares fails to resolve some names when ``family`` is ``AF_UNSPEC``, + so it is only recommended for use in ``AF_INET`` (i.e. IPv4). This is + the default for ``tornado.simple_httpclient``, but other libraries + may default to ``AF_UNSPEC``. + + .. versionchanged:: 5.0 + The ``io_loop`` argument (deprecated since version 4.1) has been removed. + """ + + def initialize(self) -> None: + self.io_loop = IOLoop.current() + self.channel = pycares.Channel(sock_state_cb=self._sock_state_cb) + self.fds = {} # type: Dict[int, int] + + def _sock_state_cb(self, fd: int, readable: bool, writable: bool) -> None: + state = (IOLoop.READ if readable else 0) | (IOLoop.WRITE if writable else 0) + if not state: + self.io_loop.remove_handler(fd) + del self.fds[fd] + elif fd in self.fds: + self.io_loop.update_handler(fd, state) + self.fds[fd] = state + else: + self.io_loop.add_handler(fd, self._handle_events, state) + self.fds[fd] = state + + def _handle_events(self, fd: int, events: int) -> None: + read_fd = pycares.ARES_SOCKET_BAD + write_fd = pycares.ARES_SOCKET_BAD + if events & IOLoop.READ: + read_fd = fd + if events & IOLoop.WRITE: + write_fd = fd + self.channel.process_fd(read_fd, write_fd) + + @gen.coroutine + def resolve( + self, host: str, port: int, family: int = 0 + ) -> "Generator[Any, Any, List[Tuple[int, Any]]]": + if is_valid_ip(host): + addresses = [host] + else: + # gethostbyname doesn't take callback as a kwarg + fut = Future() # type: Future[Tuple[Any, Any]] + self.channel.gethostbyname( + host, family, lambda result, error: fut.set_result((result, error)) + ) + result, error = yield fut + if error: + raise IOError( + "C-Ares returned error %s: %s while resolving %s" + % (error, pycares.errno.strerror(error), host) + ) + addresses = result.addresses + addrinfo = [] + for address in addresses: + if "." in address: + address_family = socket.AF_INET + elif ":" in address: + address_family = socket.AF_INET6 + else: + address_family = socket.AF_UNSPEC + if family != socket.AF_UNSPEC and family != address_family: + raise IOError( + "Requested socket family %d but got %d" % (family, address_family) + ) + addrinfo.append((typing.cast(int, address_family), (address, port))) + return addrinfo diff --git a/venv/lib/python3.8/site-packages/tornado/platform/twisted.py b/venv/lib/python3.8/site-packages/tornado/platform/twisted.py new file mode 100644 index 0000000..0987a84 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/platform/twisted.py @@ -0,0 +1,146 @@ +# 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. +"""Bridges between the Twisted package and Tornado. +""" + +import socket +import sys + +import twisted.internet.abstract # type: ignore +import twisted.internet.asyncioreactor # type: ignore +from twisted.internet.defer import Deferred # type: ignore +from twisted.python import failure # type: ignore +import twisted.names.cache # type: ignore +import twisted.names.client # type: ignore +import twisted.names.hosts # type: ignore +import twisted.names.resolve # type: ignore + + +from tornado.concurrent import Future, future_set_exc_info +from tornado.escape import utf8 +from tornado import gen +from tornado.netutil import Resolver + +import typing + +if typing.TYPE_CHECKING: + from typing import Generator, Any, List, Tuple # noqa: F401 + + +class TwistedResolver(Resolver): + """Twisted-based asynchronous resolver. + + This is a non-blocking and non-threaded resolver. It is + recommended only when threads cannot be used, since it has + limitations compared to the standard ``getaddrinfo``-based + `~tornado.netutil.Resolver` and + `~tornado.netutil.DefaultExecutorResolver`. Specifically, it returns at + most one result, and arguments other than ``host`` and ``family`` + are ignored. It may fail to resolve when ``family`` is not + ``socket.AF_UNSPEC``. + + Requires Twisted 12.1 or newer. + + .. versionchanged:: 5.0 + The ``io_loop`` argument (deprecated since version 4.1) has been removed. + """ + + def initialize(self) -> None: + # partial copy of twisted.names.client.createResolver, which doesn't + # allow for a reactor to be passed in. + self.reactor = twisted.internet.asyncioreactor.AsyncioSelectorReactor() + + host_resolver = twisted.names.hosts.Resolver("/etc/hosts") + cache_resolver = twisted.names.cache.CacheResolver(reactor=self.reactor) + real_resolver = twisted.names.client.Resolver( + "/etc/resolv.conf", reactor=self.reactor + ) + self.resolver = twisted.names.resolve.ResolverChain( + [host_resolver, cache_resolver, real_resolver] + ) + + @gen.coroutine + def resolve( + self, host: str, port: int, family: int = 0 + ) -> "Generator[Any, Any, List[Tuple[int, Any]]]": + # getHostByName doesn't accept IP addresses, so if the input + # looks like an IP address just return it immediately. + if twisted.internet.abstract.isIPAddress(host): + resolved = host + resolved_family = socket.AF_INET + elif twisted.internet.abstract.isIPv6Address(host): + resolved = host + resolved_family = socket.AF_INET6 + else: + deferred = self.resolver.getHostByName(utf8(host)) + fut = Future() # type: Future[Any] + deferred.addBoth(fut.set_result) + resolved = yield fut + if isinstance(resolved, failure.Failure): + try: + resolved.raiseException() + except twisted.names.error.DomainError as e: + raise IOError(e) + elif twisted.internet.abstract.isIPAddress(resolved): + resolved_family = socket.AF_INET + elif twisted.internet.abstract.isIPv6Address(resolved): + resolved_family = socket.AF_INET6 + else: + resolved_family = socket.AF_UNSPEC + if family != socket.AF_UNSPEC and family != resolved_family: + raise Exception( + "Requested socket family %d but got %d" % (family, resolved_family) + ) + result = [(typing.cast(int, resolved_family), (resolved, port))] + return result + + +def install() -> None: + """Install ``AsyncioSelectorReactor`` as the default Twisted reactor. + + .. deprecated:: 5.1 + + This function is provided for backwards compatibility; code + that does not require compatibility with older versions of + Tornado should use + ``twisted.internet.asyncioreactor.install()`` directly. + + .. versionchanged:: 6.0.3 + + In Tornado 5.x and before, this function installed a reactor + based on the Tornado ``IOLoop``. When that reactor + implementation was removed in Tornado 6.0.0, this function was + removed as well. It was restored in Tornado 6.0.3 using the + ``asyncio`` reactor instead. + + """ + from twisted.internet.asyncioreactor import install + + install() + + +if hasattr(gen.convert_yielded, "register"): + + @gen.convert_yielded.register(Deferred) # type: ignore + def _(d: Deferred) -> Future: + f = Future() # type: Future[Any] + + def errback(failure: failure.Failure) -> None: + try: + failure.raiseException() + # Should never happen, but just in case + raise Exception("errback called without error") + except: + future_set_exc_info(f, sys.exc_info()) + + d.addCallbacks(f.set_result, errback) + return f diff --git a/venv/lib/python3.8/site-packages/tornado/process.py b/venv/lib/python3.8/site-packages/tornado/process.py new file mode 100644 index 0000000..26428fe --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/process.py @@ -0,0 +1,373 @@ +# +# Copyright 2011 Facebook +# +# 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. + +"""Utilities for working with multiple processes, including both forking +the server into multiple processes and managing subprocesses. +""" + +import os +import multiprocessing +import signal +import subprocess +import sys +import time + +from binascii import hexlify + +from tornado.concurrent import ( + Future, + future_set_result_unless_cancelled, + future_set_exception_unless_cancelled, +) +from tornado import ioloop +from tornado.iostream import PipeIOStream +from tornado.log import gen_log + +import typing +from typing import Optional, Any, Callable + +if typing.TYPE_CHECKING: + from typing import List # noqa: F401 + +# Re-export this exception for convenience. +CalledProcessError = subprocess.CalledProcessError + + +def cpu_count() -> int: + """Returns the number of processors on this machine.""" + if multiprocessing is None: + return 1 + try: + return multiprocessing.cpu_count() + except NotImplementedError: + pass + try: + return os.sysconf("SC_NPROCESSORS_CONF") # type: ignore + except (AttributeError, ValueError): + pass + gen_log.error("Could not detect number of processors; assuming 1") + return 1 + + +def _reseed_random() -> None: + if "random" not in sys.modules: + return + import random + + # If os.urandom is available, this method does the same thing as + # random.seed (at least as of python 2.6). If os.urandom is not + # available, we mix in the pid in addition to a timestamp. + try: + seed = int(hexlify(os.urandom(16)), 16) + except NotImplementedError: + seed = int(time.time() * 1000) ^ os.getpid() + random.seed(seed) + + +_task_id = None + + +def fork_processes( + num_processes: Optional[int], max_restarts: Optional[int] = None +) -> int: + """Starts multiple worker processes. + + If ``num_processes`` is None or <= 0, we detect the number of cores + available on this machine and fork that number of child + processes. If ``num_processes`` is given and > 0, we fork that + specific number of sub-processes. + + Since we use processes and not threads, there is no shared memory + between any server code. + + Note that multiple processes are not compatible with the autoreload + module (or the ``autoreload=True`` option to `tornado.web.Application` + which defaults to True when ``debug=True``). + When using multiple processes, no IOLoops can be created or + referenced until after the call to ``fork_processes``. + + In each child process, ``fork_processes`` returns its *task id*, a + number between 0 and ``num_processes``. Processes that exit + abnormally (due to a signal or non-zero exit status) are restarted + with the same id (up to ``max_restarts`` times). In the parent + process, ``fork_processes`` calls ``sys.exit(0)`` after all child + processes have exited normally. + + max_restarts defaults to 100. + + Availability: Unix + """ + if sys.platform == "win32": + # The exact form of this condition matters to mypy; it understands + # if but not assert in this context. + raise Exception("fork not available on windows") + if max_restarts is None: + max_restarts = 100 + + global _task_id + assert _task_id is None + if num_processes is None or num_processes <= 0: + num_processes = cpu_count() + gen_log.info("Starting %d processes", num_processes) + children = {} + + def start_child(i: int) -> Optional[int]: + pid = os.fork() + if pid == 0: + # child process + _reseed_random() + global _task_id + _task_id = i + return i + else: + children[pid] = i + return None + + for i in range(num_processes): + id = start_child(i) + if id is not None: + return id + num_restarts = 0 + while children: + pid, status = os.wait() + if pid not in children: + continue + id = children.pop(pid) + if os.WIFSIGNALED(status): + gen_log.warning( + "child %d (pid %d) killed by signal %d, restarting", + id, + pid, + os.WTERMSIG(status), + ) + elif os.WEXITSTATUS(status) != 0: + gen_log.warning( + "child %d (pid %d) exited with status %d, restarting", + id, + pid, + os.WEXITSTATUS(status), + ) + else: + gen_log.info("child %d (pid %d) exited normally", id, pid) + continue + num_restarts += 1 + if num_restarts > max_restarts: + raise RuntimeError("Too many child restarts, giving up") + new_id = start_child(id) + if new_id is not None: + return new_id + # All child processes exited cleanly, so exit the master process + # instead of just returning to right after the call to + # fork_processes (which will probably just start up another IOLoop + # unless the caller checks the return value). + sys.exit(0) + + +def task_id() -> Optional[int]: + """Returns the current task id, if any. + + Returns None if this process was not created by `fork_processes`. + """ + global _task_id + return _task_id + + +class Subprocess(object): + """Wraps ``subprocess.Popen`` with IOStream support. + + The constructor is the same as ``subprocess.Popen`` with the following + additions: + + * ``stdin``, ``stdout``, and ``stderr`` may have the value + ``tornado.process.Subprocess.STREAM``, which will make the corresponding + attribute of the resulting Subprocess a `.PipeIOStream`. If this option + is used, the caller is responsible for closing the streams when done + with them. + + The ``Subprocess.STREAM`` option and the ``set_exit_callback`` and + ``wait_for_exit`` methods do not work on Windows. There is + therefore no reason to use this class instead of + ``subprocess.Popen`` on that platform. + + .. versionchanged:: 5.0 + The ``io_loop`` argument (deprecated since version 4.1) has been removed. + + """ + + STREAM = object() + + _initialized = False + _waiting = {} # type: ignore + _old_sigchld = None + + def __init__(self, *args: Any, **kwargs: Any) -> None: + self.io_loop = ioloop.IOLoop.current() + # All FDs we create should be closed on error; those in to_close + # should be closed in the parent process on success. + pipe_fds = [] # type: List[int] + to_close = [] # type: List[int] + if kwargs.get("stdin") is Subprocess.STREAM: + in_r, in_w = os.pipe() + kwargs["stdin"] = in_r + pipe_fds.extend((in_r, in_w)) + to_close.append(in_r) + self.stdin = PipeIOStream(in_w) + if kwargs.get("stdout") is Subprocess.STREAM: + out_r, out_w = os.pipe() + kwargs["stdout"] = out_w + pipe_fds.extend((out_r, out_w)) + to_close.append(out_w) + self.stdout = PipeIOStream(out_r) + if kwargs.get("stderr") is Subprocess.STREAM: + err_r, err_w = os.pipe() + kwargs["stderr"] = err_w + pipe_fds.extend((err_r, err_w)) + to_close.append(err_w) + self.stderr = PipeIOStream(err_r) + try: + self.proc = subprocess.Popen(*args, **kwargs) + except: + for fd in pipe_fds: + os.close(fd) + raise + for fd in to_close: + os.close(fd) + self.pid = self.proc.pid + for attr in ["stdin", "stdout", "stderr"]: + if not hasattr(self, attr): # don't clobber streams set above + setattr(self, attr, getattr(self.proc, attr)) + self._exit_callback = None # type: Optional[Callable[[int], None]] + self.returncode = None # type: Optional[int] + + def set_exit_callback(self, callback: Callable[[int], None]) -> None: + """Runs ``callback`` when this process exits. + + The callback takes one argument, the return code of the process. + + This method uses a ``SIGCHLD`` handler, which is a global setting + and may conflict if you have other libraries trying to handle the + same signal. If you are using more than one ``IOLoop`` it may + be necessary to call `Subprocess.initialize` first to designate + one ``IOLoop`` to run the signal handlers. + + In many cases a close callback on the stdout or stderr streams + can be used as an alternative to an exit callback if the + signal handler is causing a problem. + + Availability: Unix + """ + self._exit_callback = callback + Subprocess.initialize() + Subprocess._waiting[self.pid] = self + Subprocess._try_cleanup_process(self.pid) + + def wait_for_exit(self, raise_error: bool = True) -> "Future[int]": + """Returns a `.Future` which resolves when the process exits. + + Usage:: + + ret = yield proc.wait_for_exit() + + This is a coroutine-friendly alternative to `set_exit_callback` + (and a replacement for the blocking `subprocess.Popen.wait`). + + By default, raises `subprocess.CalledProcessError` if the process + has a non-zero exit status. Use ``wait_for_exit(raise_error=False)`` + to suppress this behavior and return the exit status without raising. + + .. versionadded:: 4.2 + + Availability: Unix + """ + future = Future() # type: Future[int] + + def callback(ret: int) -> None: + if ret != 0 and raise_error: + # Unfortunately we don't have the original args any more. + future_set_exception_unless_cancelled( + future, CalledProcessError(ret, "unknown") + ) + else: + future_set_result_unless_cancelled(future, ret) + + self.set_exit_callback(callback) + return future + + @classmethod + def initialize(cls) -> None: + """Initializes the ``SIGCHLD`` handler. + + The signal handler is run on an `.IOLoop` to avoid locking issues. + Note that the `.IOLoop` used for signal handling need not be the + same one used by individual Subprocess objects (as long as the + ``IOLoops`` are each running in separate threads). + + .. versionchanged:: 5.0 + The ``io_loop`` argument (deprecated since version 4.1) has been + removed. + + Availability: Unix + """ + if cls._initialized: + return + io_loop = ioloop.IOLoop.current() + cls._old_sigchld = signal.signal( + signal.SIGCHLD, + lambda sig, frame: io_loop.add_callback_from_signal(cls._cleanup), + ) + cls._initialized = True + + @classmethod + def uninitialize(cls) -> None: + """Removes the ``SIGCHLD`` handler.""" + if not cls._initialized: + return + signal.signal(signal.SIGCHLD, cls._old_sigchld) + cls._initialized = False + + @classmethod + def _cleanup(cls) -> None: + for pid in list(cls._waiting.keys()): # make a copy + cls._try_cleanup_process(pid) + + @classmethod + def _try_cleanup_process(cls, pid: int) -> None: + try: + ret_pid, status = os.waitpid(pid, os.WNOHANG) # type: ignore + except ChildProcessError: + return + if ret_pid == 0: + return + assert ret_pid == pid + subproc = cls._waiting.pop(pid) + subproc.io_loop.add_callback_from_signal(subproc._set_returncode, status) + + def _set_returncode(self, status: int) -> None: + if sys.platform == "win32": + self.returncode = -1 + else: + if os.WIFSIGNALED(status): + self.returncode = -os.WTERMSIG(status) + else: + assert os.WIFEXITED(status) + self.returncode = os.WEXITSTATUS(status) + # We've taken over wait() duty from the subprocess.Popen + # object. If we don't inform it of the process's return code, + # it will log a warning at destruction in python 3.6+. + self.proc.returncode = self.returncode + if self._exit_callback: + callback = self._exit_callback + self._exit_callback = None + callback(self.returncode) diff --git a/venv/lib/python3.8/site-packages/tornado/py.typed b/venv/lib/python3.8/site-packages/tornado/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.8/site-packages/tornado/queues.py b/venv/lib/python3.8/site-packages/tornado/queues.py new file mode 100644 index 0000000..1e87f62 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/queues.py @@ -0,0 +1,414 @@ +# Copyright 2015 The Tornado Authors +# +# 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. + +"""Asynchronous queues for coroutines. These classes are very similar +to those provided in the standard library's `asyncio package +<https://docs.python.org/3/library/asyncio-queue.html>`_. + +.. warning:: + + Unlike the standard library's `queue` module, the classes defined here + are *not* thread-safe. To use these queues from another thread, + use `.IOLoop.add_callback` to transfer control to the `.IOLoop` thread + before calling any queue methods. + +""" + +import collections +import datetime +import heapq + +from tornado import gen, ioloop +from tornado.concurrent import Future, future_set_result_unless_cancelled +from tornado.locks import Event + +from typing import Union, TypeVar, Generic, Awaitable, Optional +import typing + +if typing.TYPE_CHECKING: + from typing import Deque, Tuple, Any # noqa: F401 + +_T = TypeVar("_T") + +__all__ = ["Queue", "PriorityQueue", "LifoQueue", "QueueFull", "QueueEmpty"] + + +class QueueEmpty(Exception): + """Raised by `.Queue.get_nowait` when the queue has no items.""" + + pass + + +class QueueFull(Exception): + """Raised by `.Queue.put_nowait` when a queue is at its maximum size.""" + + pass + + +def _set_timeout( + future: Future, timeout: Union[None, float, datetime.timedelta] +) -> None: + if timeout: + + def on_timeout() -> None: + if not future.done(): + future.set_exception(gen.TimeoutError()) + + io_loop = ioloop.IOLoop.current() + timeout_handle = io_loop.add_timeout(timeout, on_timeout) + future.add_done_callback(lambda _: io_loop.remove_timeout(timeout_handle)) + + +class _QueueIterator(Generic[_T]): + def __init__(self, q: "Queue[_T]") -> None: + self.q = q + + def __anext__(self) -> Awaitable[_T]: + return self.q.get() + + +class Queue(Generic[_T]): + """Coordinate producer and consumer coroutines. + + If maxsize is 0 (the default) the queue size is unbounded. + + .. testcode:: + + from tornado import gen + from tornado.ioloop import IOLoop + from tornado.queues import Queue + + q = Queue(maxsize=2) + + async def consumer(): + async for item in q: + try: + print('Doing work on %s' % item) + await gen.sleep(0.01) + finally: + q.task_done() + + async def producer(): + for item in range(5): + await q.put(item) + print('Put %s' % item) + + async def main(): + # Start consumer without waiting (since it never finishes). + IOLoop.current().spawn_callback(consumer) + await producer() # Wait for producer to put all tasks. + await q.join() # Wait for consumer to finish all tasks. + print('Done') + + IOLoop.current().run_sync(main) + + .. testoutput:: + + Put 0 + Put 1 + Doing work on 0 + Put 2 + Doing work on 1 + Put 3 + Doing work on 2 + Put 4 + Doing work on 3 + Doing work on 4 + Done + + + In versions of Python without native coroutines (before 3.5), + ``consumer()`` could be written as:: + + @gen.coroutine + def consumer(): + while True: + item = yield q.get() + try: + print('Doing work on %s' % item) + yield gen.sleep(0.01) + finally: + q.task_done() + + .. versionchanged:: 4.3 + Added ``async for`` support in Python 3.5. + + """ + + # Exact type depends on subclass. Could be another generic + # parameter and use protocols to be more precise here. + _queue = None # type: Any + + def __init__(self, maxsize: int = 0) -> None: + if maxsize is None: + raise TypeError("maxsize can't be None") + + if maxsize < 0: + raise ValueError("maxsize can't be negative") + + self._maxsize = maxsize + self._init() + self._getters = collections.deque([]) # type: Deque[Future[_T]] + self._putters = collections.deque([]) # type: Deque[Tuple[_T, Future[None]]] + self._unfinished_tasks = 0 + self._finished = Event() + self._finished.set() + + @property + def maxsize(self) -> int: + """Number of items allowed in the queue.""" + return self._maxsize + + def qsize(self) -> int: + """Number of items in the queue.""" + return len(self._queue) + + def empty(self) -> bool: + return not self._queue + + def full(self) -> bool: + if self.maxsize == 0: + return False + else: + return self.qsize() >= self.maxsize + + def put( + self, item: _T, timeout: Optional[Union[float, datetime.timedelta]] = None + ) -> "Future[None]": + """Put an item into the queue, perhaps waiting until there is room. + + Returns a Future, which raises `tornado.util.TimeoutError` after a + timeout. + + ``timeout`` may be a number denoting a time (on the same + scale as `tornado.ioloop.IOLoop.time`, normally `time.time`), or a + `datetime.timedelta` object for a deadline relative to the + current time. + """ + future = Future() # type: Future[None] + try: + self.put_nowait(item) + except QueueFull: + self._putters.append((item, future)) + _set_timeout(future, timeout) + else: + future.set_result(None) + return future + + def put_nowait(self, item: _T) -> None: + """Put an item into the queue without blocking. + + If no free slot is immediately available, raise `QueueFull`. + """ + self._consume_expired() + if self._getters: + assert self.empty(), "queue non-empty, why are getters waiting?" + getter = self._getters.popleft() + self.__put_internal(item) + future_set_result_unless_cancelled(getter, self._get()) + elif self.full(): + raise QueueFull + else: + self.__put_internal(item) + + def get( + self, timeout: Optional[Union[float, datetime.timedelta]] = None + ) -> Awaitable[_T]: + """Remove and return an item from the queue. + + Returns an awaitable which resolves once an item is available, or raises + `tornado.util.TimeoutError` after a timeout. + + ``timeout`` may be a number denoting a time (on the same + scale as `tornado.ioloop.IOLoop.time`, normally `time.time`), or a + `datetime.timedelta` object for a deadline relative to the + current time. + + .. note:: + + The ``timeout`` argument of this method differs from that + of the standard library's `queue.Queue.get`. That method + interprets numeric values as relative timeouts; this one + interprets them as absolute deadlines and requires + ``timedelta`` objects for relative timeouts (consistent + with other timeouts in Tornado). + + """ + future = Future() # type: Future[_T] + try: + future.set_result(self.get_nowait()) + except QueueEmpty: + self._getters.append(future) + _set_timeout(future, timeout) + return future + + def get_nowait(self) -> _T: + """Remove and return an item from the queue without blocking. + + Return an item if one is immediately available, else raise + `QueueEmpty`. + """ + self._consume_expired() + if self._putters: + assert self.full(), "queue not full, why are putters waiting?" + item, putter = self._putters.popleft() + self.__put_internal(item) + future_set_result_unless_cancelled(putter, None) + return self._get() + elif self.qsize(): + return self._get() + else: + raise QueueEmpty + + def task_done(self) -> None: + """Indicate that a formerly enqueued task is complete. + + Used by queue consumers. For each `.get` used to fetch a task, a + subsequent call to `.task_done` tells the queue that the processing + on the task is complete. + + If a `.join` is blocking, it resumes when all items have been + processed; that is, when every `.put` is matched by a `.task_done`. + + Raises `ValueError` if called more times than `.put`. + """ + if self._unfinished_tasks <= 0: + raise ValueError("task_done() called too many times") + self._unfinished_tasks -= 1 + if self._unfinished_tasks == 0: + self._finished.set() + + def join( + self, timeout: Optional[Union[float, datetime.timedelta]] = None + ) -> Awaitable[None]: + """Block until all items in the queue are processed. + + Returns an awaitable, which raises `tornado.util.TimeoutError` after a + timeout. + """ + return self._finished.wait(timeout) + + def __aiter__(self) -> _QueueIterator[_T]: + return _QueueIterator(self) + + # These three are overridable in subclasses. + def _init(self) -> None: + self._queue = collections.deque() + + def _get(self) -> _T: + return self._queue.popleft() + + def _put(self, item: _T) -> None: + self._queue.append(item) + + # End of the overridable methods. + + def __put_internal(self, item: _T) -> None: + self._unfinished_tasks += 1 + self._finished.clear() + self._put(item) + + def _consume_expired(self) -> None: + # Remove timed-out waiters. + while self._putters and self._putters[0][1].done(): + self._putters.popleft() + + while self._getters and self._getters[0].done(): + self._getters.popleft() + + def __repr__(self) -> str: + return "<%s at %s %s>" % (type(self).__name__, hex(id(self)), self._format()) + + def __str__(self) -> str: + return "<%s %s>" % (type(self).__name__, self._format()) + + def _format(self) -> str: + result = "maxsize=%r" % (self.maxsize,) + if getattr(self, "_queue", None): + result += " queue=%r" % self._queue + if self._getters: + result += " getters[%s]" % len(self._getters) + if self._putters: + result += " putters[%s]" % len(self._putters) + if self._unfinished_tasks: + result += " tasks=%s" % self._unfinished_tasks + return result + + +class PriorityQueue(Queue): + """A `.Queue` that retrieves entries in priority order, lowest first. + + Entries are typically tuples like ``(priority number, data)``. + + .. testcode:: + + from tornado.queues import PriorityQueue + + q = PriorityQueue() + q.put((1, 'medium-priority item')) + q.put((0, 'high-priority item')) + q.put((10, 'low-priority item')) + + print(q.get_nowait()) + print(q.get_nowait()) + print(q.get_nowait()) + + .. testoutput:: + + (0, 'high-priority item') + (1, 'medium-priority item') + (10, 'low-priority item') + """ + + def _init(self) -> None: + self._queue = [] + + def _put(self, item: _T) -> None: + heapq.heappush(self._queue, item) + + def _get(self) -> _T: + return heapq.heappop(self._queue) + + +class LifoQueue(Queue): + """A `.Queue` that retrieves the most recently put items first. + + .. testcode:: + + from tornado.queues import LifoQueue + + q = LifoQueue() + q.put(3) + q.put(2) + q.put(1) + + print(q.get_nowait()) + print(q.get_nowait()) + print(q.get_nowait()) + + .. testoutput:: + + 1 + 2 + 3 + """ + + def _init(self) -> None: + self._queue = [] + + def _put(self, item: _T) -> None: + self._queue.append(item) + + def _get(self) -> _T: + return self._queue.pop() diff --git a/venv/lib/python3.8/site-packages/tornado/routing.py b/venv/lib/python3.8/site-packages/tornado/routing.py new file mode 100644 index 0000000..a145d71 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/routing.py @@ -0,0 +1,717 @@ +# Copyright 2015 The Tornado Authors +# +# 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. + +"""Flexible routing implementation. + +Tornado routes HTTP requests to appropriate handlers using `Router` +class implementations. The `tornado.web.Application` class is a +`Router` implementation and may be used directly, or the classes in +this module may be used for additional flexibility. The `RuleRouter` +class can match on more criteria than `.Application`, or the `Router` +interface can be subclassed for maximum customization. + +`Router` interface extends `~.httputil.HTTPServerConnectionDelegate` +to provide additional routing capabilities. This also means that any +`Router` implementation can be used directly as a ``request_callback`` +for `~.httpserver.HTTPServer` constructor. + +`Router` subclass must implement a ``find_handler`` method to provide +a suitable `~.httputil.HTTPMessageDelegate` instance to handle the +request: + +.. code-block:: python + + class CustomRouter(Router): + def find_handler(self, request, **kwargs): + # some routing logic providing a suitable HTTPMessageDelegate instance + return MessageDelegate(request.connection) + + class MessageDelegate(HTTPMessageDelegate): + def __init__(self, connection): + self.connection = connection + + def finish(self): + self.connection.write_headers( + ResponseStartLine("HTTP/1.1", 200, "OK"), + HTTPHeaders({"Content-Length": "2"}), + b"OK") + self.connection.finish() + + router = CustomRouter() + server = HTTPServer(router) + +The main responsibility of `Router` implementation is to provide a +mapping from a request to `~.httputil.HTTPMessageDelegate` instance +that will handle this request. In the example above we can see that +routing is possible even without instantiating an `~.web.Application`. + +For routing to `~.web.RequestHandler` implementations we need an +`~.web.Application` instance. `~.web.Application.get_handler_delegate` +provides a convenient way to create `~.httputil.HTTPMessageDelegate` +for a given request and `~.web.RequestHandler`. + +Here is a simple example of how we can we route to +`~.web.RequestHandler` subclasses by HTTP method: + +.. code-block:: python + + resources = {} + + class GetResource(RequestHandler): + def get(self, path): + if path not in resources: + raise HTTPError(404) + + self.finish(resources[path]) + + class PostResource(RequestHandler): + def post(self, path): + resources[path] = self.request.body + + class HTTPMethodRouter(Router): + def __init__(self, app): + self.app = app + + def find_handler(self, request, **kwargs): + handler = GetResource if request.method == "GET" else PostResource + return self.app.get_handler_delegate(request, handler, path_args=[request.path]) + + router = HTTPMethodRouter(Application()) + server = HTTPServer(router) + +`ReversibleRouter` interface adds the ability to distinguish between +the routes and reverse them to the original urls using route's name +and additional arguments. `~.web.Application` is itself an +implementation of `ReversibleRouter` class. + +`RuleRouter` and `ReversibleRuleRouter` are implementations of +`Router` and `ReversibleRouter` interfaces and can be used for +creating rule-based routing configurations. + +Rules are instances of `Rule` class. They contain a `Matcher`, which +provides the logic for determining whether the rule is a match for a +particular request and a target, which can be one of the following. + +1) An instance of `~.httputil.HTTPServerConnectionDelegate`: + +.. code-block:: python + + router = RuleRouter([ + Rule(PathMatches("/handler"), ConnectionDelegate()), + # ... more rules + ]) + + class ConnectionDelegate(HTTPServerConnectionDelegate): + def start_request(self, server_conn, request_conn): + return MessageDelegate(request_conn) + +2) A callable accepting a single argument of `~.httputil.HTTPServerRequest` type: + +.. code-block:: python + + router = RuleRouter([ + Rule(PathMatches("/callable"), request_callable) + ]) + + def request_callable(request): + request.write(b"HTTP/1.1 200 OK\\r\\nContent-Length: 2\\r\\n\\r\\nOK") + request.finish() + +3) Another `Router` instance: + +.. code-block:: python + + router = RuleRouter([ + Rule(PathMatches("/router.*"), CustomRouter()) + ]) + +Of course a nested `RuleRouter` or a `~.web.Application` is allowed: + +.. code-block:: python + + router = RuleRouter([ + Rule(HostMatches("example.com"), RuleRouter([ + Rule(PathMatches("/app1/.*"), Application([(r"/app1/handler", Handler)])), + ])) + ]) + + server = HTTPServer(router) + +In the example below `RuleRouter` is used to route between applications: + +.. code-block:: python + + app1 = Application([ + (r"/app1/handler", Handler1), + # other handlers ... + ]) + + app2 = Application([ + (r"/app2/handler", Handler2), + # other handlers ... + ]) + + router = RuleRouter([ + Rule(PathMatches("/app1.*"), app1), + Rule(PathMatches("/app2.*"), app2) + ]) + + server = HTTPServer(router) + +For more information on application-level routing see docs for `~.web.Application`. + +.. versionadded:: 4.5 + +""" + +import re +from functools import partial + +from tornado import httputil +from tornado.httpserver import _CallableAdapter +from tornado.escape import url_escape, url_unescape, utf8 +from tornado.log import app_log +from tornado.util import basestring_type, import_object, re_unescape, unicode_type + +from typing import Any, Union, Optional, Awaitable, List, Dict, Pattern, Tuple, overload + + +class Router(httputil.HTTPServerConnectionDelegate): + """Abstract router interface.""" + + def find_handler( + self, request: httputil.HTTPServerRequest, **kwargs: Any + ) -> Optional[httputil.HTTPMessageDelegate]: + """Must be implemented to return an appropriate instance of `~.httputil.HTTPMessageDelegate` + that can serve the request. + Routing implementations may pass additional kwargs to extend the routing logic. + + :arg httputil.HTTPServerRequest request: current HTTP request. + :arg kwargs: additional keyword arguments passed by routing implementation. + :returns: an instance of `~.httputil.HTTPMessageDelegate` that will be used to + process the request. + """ + raise NotImplementedError() + + def start_request( + self, server_conn: object, request_conn: httputil.HTTPConnection + ) -> httputil.HTTPMessageDelegate: + return _RoutingDelegate(self, server_conn, request_conn) + + +class ReversibleRouter(Router): + """Abstract router interface for routers that can handle named routes + and support reversing them to original urls. + """ + + def reverse_url(self, name: str, *args: Any) -> Optional[str]: + """Returns url string for a given route name and arguments + or ``None`` if no match is found. + + :arg str name: route name. + :arg args: url parameters. + :returns: parametrized url string for a given route name (or ``None``). + """ + raise NotImplementedError() + + +class _RoutingDelegate(httputil.HTTPMessageDelegate): + def __init__( + self, router: Router, server_conn: object, request_conn: httputil.HTTPConnection + ) -> None: + self.server_conn = server_conn + self.request_conn = request_conn + self.delegate = None # type: Optional[httputil.HTTPMessageDelegate] + self.router = router # type: Router + + def headers_received( + self, + start_line: Union[httputil.RequestStartLine, httputil.ResponseStartLine], + headers: httputil.HTTPHeaders, + ) -> Optional[Awaitable[None]]: + assert isinstance(start_line, httputil.RequestStartLine) + request = httputil.HTTPServerRequest( + connection=self.request_conn, + server_connection=self.server_conn, + start_line=start_line, + headers=headers, + ) + + self.delegate = self.router.find_handler(request) + if self.delegate is None: + app_log.debug( + "Delegate for %s %s request not found", + start_line.method, + start_line.path, + ) + self.delegate = _DefaultMessageDelegate(self.request_conn) + + return self.delegate.headers_received(start_line, headers) + + def data_received(self, chunk: bytes) -> Optional[Awaitable[None]]: + assert self.delegate is not None + return self.delegate.data_received(chunk) + + def finish(self) -> None: + assert self.delegate is not None + self.delegate.finish() + + def on_connection_close(self) -> None: + assert self.delegate is not None + self.delegate.on_connection_close() + + +class _DefaultMessageDelegate(httputil.HTTPMessageDelegate): + def __init__(self, connection: httputil.HTTPConnection) -> None: + self.connection = connection + + def finish(self) -> None: + self.connection.write_headers( + httputil.ResponseStartLine("HTTP/1.1", 404, "Not Found"), + httputil.HTTPHeaders(), + ) + self.connection.finish() + + +# _RuleList can either contain pre-constructed Rules or a sequence of +# arguments to be passed to the Rule constructor. +_RuleList = List[ + Union[ + "Rule", + List[Any], # Can't do detailed typechecking of lists. + Tuple[Union[str, "Matcher"], Any], + Tuple[Union[str, "Matcher"], Any, Dict[str, Any]], + Tuple[Union[str, "Matcher"], Any, Dict[str, Any], str], + ] +] + + +class RuleRouter(Router): + """Rule-based router implementation.""" + + def __init__(self, rules: Optional[_RuleList] = None) -> None: + """Constructs a router from an ordered list of rules:: + + RuleRouter([ + Rule(PathMatches("/handler"), Target), + # ... more rules + ]) + + You can also omit explicit `Rule` constructor and use tuples of arguments:: + + RuleRouter([ + (PathMatches("/handler"), Target), + ]) + + `PathMatches` is a default matcher, so the example above can be simplified:: + + RuleRouter([ + ("/handler", Target), + ]) + + In the examples above, ``Target`` can be a nested `Router` instance, an instance of + `~.httputil.HTTPServerConnectionDelegate` or an old-style callable, + accepting a request argument. + + :arg rules: a list of `Rule` instances or tuples of `Rule` + constructor arguments. + """ + self.rules = [] # type: List[Rule] + if rules: + self.add_rules(rules) + + def add_rules(self, rules: _RuleList) -> None: + """Appends new rules to the router. + + :arg rules: a list of Rule instances (or tuples of arguments, which are + passed to Rule constructor). + """ + for rule in rules: + if isinstance(rule, (tuple, list)): + assert len(rule) in (2, 3, 4) + if isinstance(rule[0], basestring_type): + rule = Rule(PathMatches(rule[0]), *rule[1:]) + else: + rule = Rule(*rule) + + self.rules.append(self.process_rule(rule)) + + def process_rule(self, rule: "Rule") -> "Rule": + """Override this method for additional preprocessing of each rule. + + :arg Rule rule: a rule to be processed. + :returns: the same or modified Rule instance. + """ + return rule + + def find_handler( + self, request: httputil.HTTPServerRequest, **kwargs: Any + ) -> Optional[httputil.HTTPMessageDelegate]: + for rule in self.rules: + target_params = rule.matcher.match(request) + if target_params is not None: + if rule.target_kwargs: + target_params["target_kwargs"] = rule.target_kwargs + + delegate = self.get_target_delegate( + rule.target, request, **target_params + ) + + if delegate is not None: + return delegate + + return None + + def get_target_delegate( + self, target: Any, request: httputil.HTTPServerRequest, **target_params: Any + ) -> Optional[httputil.HTTPMessageDelegate]: + """Returns an instance of `~.httputil.HTTPMessageDelegate` for a + Rule's target. This method is called by `~.find_handler` and can be + extended to provide additional target types. + + :arg target: a Rule's target. + :arg httputil.HTTPServerRequest request: current request. + :arg target_params: additional parameters that can be useful + for `~.httputil.HTTPMessageDelegate` creation. + """ + if isinstance(target, Router): + return target.find_handler(request, **target_params) + + elif isinstance(target, httputil.HTTPServerConnectionDelegate): + assert request.connection is not None + return target.start_request(request.server_connection, request.connection) + + elif callable(target): + assert request.connection is not None + return _CallableAdapter( + partial(target, **target_params), request.connection + ) + + return None + + +class ReversibleRuleRouter(ReversibleRouter, RuleRouter): + """A rule-based router that implements ``reverse_url`` method. + + Each rule added to this router may have a ``name`` attribute that can be + used to reconstruct an original uri. The actual reconstruction takes place + in a rule's matcher (see `Matcher.reverse`). + """ + + def __init__(self, rules: Optional[_RuleList] = None) -> None: + self.named_rules = {} # type: Dict[str, Any] + super().__init__(rules) + + def process_rule(self, rule: "Rule") -> "Rule": + rule = super().process_rule(rule) + + if rule.name: + if rule.name in self.named_rules: + app_log.warning( + "Multiple handlers named %s; replacing previous value", rule.name + ) + self.named_rules[rule.name] = rule + + return rule + + def reverse_url(self, name: str, *args: Any) -> Optional[str]: + if name in self.named_rules: + return self.named_rules[name].matcher.reverse(*args) + + for rule in self.rules: + if isinstance(rule.target, ReversibleRouter): + reversed_url = rule.target.reverse_url(name, *args) + if reversed_url is not None: + return reversed_url + + return None + + +class Rule(object): + """A routing rule.""" + + def __init__( + self, + matcher: "Matcher", + target: Any, + target_kwargs: Optional[Dict[str, Any]] = None, + name: Optional[str] = None, + ) -> None: + """Constructs a Rule instance. + + :arg Matcher matcher: a `Matcher` instance used for determining + whether the rule should be considered a match for a specific + request. + :arg target: a Rule's target (typically a ``RequestHandler`` or + `~.httputil.HTTPServerConnectionDelegate` subclass or even a nested `Router`, + depending on routing implementation). + :arg dict target_kwargs: a dict of parameters that can be useful + at the moment of target instantiation (for example, ``status_code`` + for a ``RequestHandler`` subclass). They end up in + ``target_params['target_kwargs']`` of `RuleRouter.get_target_delegate` + method. + :arg str name: the name of the rule that can be used to find it + in `ReversibleRouter.reverse_url` implementation. + """ + if isinstance(target, str): + # import the Module and instantiate the class + # Must be a fully qualified name (module.ClassName) + target = import_object(target) + + self.matcher = matcher # type: Matcher + self.target = target + self.target_kwargs = target_kwargs if target_kwargs else {} + self.name = name + + def reverse(self, *args: Any) -> Optional[str]: + return self.matcher.reverse(*args) + + def __repr__(self) -> str: + return "%s(%r, %s, kwargs=%r, name=%r)" % ( + self.__class__.__name__, + self.matcher, + self.target, + self.target_kwargs, + self.name, + ) + + +class Matcher(object): + """Represents a matcher for request features.""" + + def match(self, request: httputil.HTTPServerRequest) -> Optional[Dict[str, Any]]: + """Matches current instance against the request. + + :arg httputil.HTTPServerRequest request: current HTTP request + :returns: a dict of parameters to be passed to the target handler + (for example, ``handler_kwargs``, ``path_args``, ``path_kwargs`` + can be passed for proper `~.web.RequestHandler` instantiation). + An empty dict is a valid (and common) return value to indicate a match + when the argument-passing features are not used. + ``None`` must be returned to indicate that there is no match.""" + raise NotImplementedError() + + def reverse(self, *args: Any) -> Optional[str]: + """Reconstructs full url from matcher instance and additional arguments.""" + return None + + +class AnyMatches(Matcher): + """Matches any request.""" + + def match(self, request: httputil.HTTPServerRequest) -> Optional[Dict[str, Any]]: + return {} + + +class HostMatches(Matcher): + """Matches requests from hosts specified by ``host_pattern`` regex.""" + + def __init__(self, host_pattern: Union[str, Pattern]) -> None: + if isinstance(host_pattern, basestring_type): + if not host_pattern.endswith("$"): + host_pattern += "$" + self.host_pattern = re.compile(host_pattern) + else: + self.host_pattern = host_pattern + + def match(self, request: httputil.HTTPServerRequest) -> Optional[Dict[str, Any]]: + if self.host_pattern.match(request.host_name): + return {} + + return None + + +class DefaultHostMatches(Matcher): + """Matches requests from host that is equal to application's default_host. + Always returns no match if ``X-Real-Ip`` header is present. + """ + + def __init__(self, application: Any, host_pattern: Pattern) -> None: + self.application = application + self.host_pattern = host_pattern + + def match(self, request: httputil.HTTPServerRequest) -> Optional[Dict[str, Any]]: + # Look for default host if not behind load balancer (for debugging) + if "X-Real-Ip" not in request.headers: + if self.host_pattern.match(self.application.default_host): + return {} + return None + + +class PathMatches(Matcher): + """Matches requests with paths specified by ``path_pattern`` regex.""" + + def __init__(self, path_pattern: Union[str, Pattern]) -> None: + if isinstance(path_pattern, basestring_type): + if not path_pattern.endswith("$"): + path_pattern += "$" + self.regex = re.compile(path_pattern) + else: + self.regex = path_pattern + + assert len(self.regex.groupindex) in (0, self.regex.groups), ( + "groups in url regexes must either be all named or all " + "positional: %r" % self.regex.pattern + ) + + self._path, self._group_count = self._find_groups() + + def match(self, request: httputil.HTTPServerRequest) -> Optional[Dict[str, Any]]: + match = self.regex.match(request.path) + if match is None: + return None + if not self.regex.groups: + return {} + + path_args = [] # type: List[bytes] + path_kwargs = {} # type: Dict[str, bytes] + + # Pass matched groups to the handler. Since + # match.groups() includes both named and + # unnamed groups, we want to use either groups + # or groupdict but not both. + if self.regex.groupindex: + path_kwargs = dict( + (str(k), _unquote_or_none(v)) for (k, v) in match.groupdict().items() + ) + else: + path_args = [_unquote_or_none(s) for s in match.groups()] + + return dict(path_args=path_args, path_kwargs=path_kwargs) + + def reverse(self, *args: Any) -> Optional[str]: + if self._path is None: + raise ValueError("Cannot reverse url regex " + self.regex.pattern) + assert len(args) == self._group_count, ( + "required number of arguments " "not found" + ) + if not len(args): + return self._path + converted_args = [] + for a in args: + if not isinstance(a, (unicode_type, bytes)): + a = str(a) + converted_args.append(url_escape(utf8(a), plus=False)) + return self._path % tuple(converted_args) + + def _find_groups(self) -> Tuple[Optional[str], Optional[int]]: + """Returns a tuple (reverse string, group count) for a url. + + For example: Given the url pattern /([0-9]{4})/([a-z-]+)/, this method + would return ('/%s/%s/', 2). + """ + pattern = self.regex.pattern + if pattern.startswith("^"): + pattern = pattern[1:] + if pattern.endswith("$"): + pattern = pattern[:-1] + + if self.regex.groups != pattern.count("("): + # The pattern is too complicated for our simplistic matching, + # so we can't support reversing it. + return None, None + + pieces = [] + for fragment in pattern.split("("): + if ")" in fragment: + paren_loc = fragment.index(")") + if paren_loc >= 0: + try: + unescaped_fragment = re_unescape(fragment[paren_loc + 1 :]) + except ValueError: + # If we can't unescape part of it, we can't + # reverse this url. + return (None, None) + pieces.append("%s" + unescaped_fragment) + else: + try: + unescaped_fragment = re_unescape(fragment) + except ValueError: + # If we can't unescape part of it, we can't + # reverse this url. + return (None, None) + pieces.append(unescaped_fragment) + + return "".join(pieces), self.regex.groups + + +class URLSpec(Rule): + """Specifies mappings between URLs and handlers. + + .. versionchanged: 4.5 + `URLSpec` is now a subclass of a `Rule` with `PathMatches` matcher and is preserved for + backwards compatibility. + """ + + def __init__( + self, + pattern: Union[str, Pattern], + handler: Any, + kwargs: Optional[Dict[str, Any]] = None, + name: Optional[str] = None, + ) -> None: + """Parameters: + + * ``pattern``: Regular expression to be matched. Any capturing + groups in the regex will be passed in to the handler's + get/post/etc methods as arguments (by keyword if named, by + position if unnamed. Named and unnamed capturing groups + may not be mixed in the same rule). + + * ``handler``: `~.web.RequestHandler` subclass to be invoked. + + * ``kwargs`` (optional): A dictionary of additional arguments + to be passed to the handler's constructor. + + * ``name`` (optional): A name for this handler. Used by + `~.web.Application.reverse_url`. + + """ + matcher = PathMatches(pattern) + super().__init__(matcher, handler, kwargs, name) + + self.regex = matcher.regex + self.handler_class = self.target + self.kwargs = kwargs + + def __repr__(self) -> str: + return "%s(%r, %s, kwargs=%r, name=%r)" % ( + self.__class__.__name__, + self.regex.pattern, + self.handler_class, + self.kwargs, + self.name, + ) + + +@overload +def _unquote_or_none(s: str) -> bytes: + pass + + +@overload # noqa: F811 +def _unquote_or_none(s: None) -> None: + pass + + +def _unquote_or_none(s: Optional[str]) -> Optional[bytes]: # noqa: F811 + """None-safe wrapper around url_unescape to handle unmatched optional + groups correctly. + + Note that args are passed as bytes so the handler can decide what + encoding to use. + """ + if s is None: + return s + return url_unescape(s, encoding=None, plus=False) diff --git a/venv/lib/python3.8/site-packages/tornado/simple_httpclient.py b/venv/lib/python3.8/site-packages/tornado/simple_httpclient.py new file mode 100644 index 0000000..f99f391 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/simple_httpclient.py @@ -0,0 +1,699 @@ +from tornado.escape import _unicode +from tornado import gen, version +from tornado.httpclient import ( + HTTPResponse, + HTTPError, + AsyncHTTPClient, + main, + _RequestProxy, + HTTPRequest, +) +from tornado import httputil +from tornado.http1connection import HTTP1Connection, HTTP1ConnectionParameters +from tornado.ioloop import IOLoop +from tornado.iostream import StreamClosedError, IOStream +from tornado.netutil import ( + Resolver, + OverrideResolver, + _client_ssl_defaults, + is_valid_ip, +) +from tornado.log import gen_log +from tornado.tcpclient import TCPClient + +import base64 +import collections +import copy +import functools +import re +import socket +import ssl +import sys +import time +from io import BytesIO +import urllib.parse + +from typing import Dict, Any, Callable, Optional, Type, Union +from types import TracebackType +import typing + +if typing.TYPE_CHECKING: + from typing import Deque, Tuple, List # noqa: F401 + + +class HTTPTimeoutError(HTTPError): + """Error raised by SimpleAsyncHTTPClient on timeout. + + For historical reasons, this is a subclass of `.HTTPClientError` + which simulates a response code of 599. + + .. versionadded:: 5.1 + """ + + def __init__(self, message: str) -> None: + super().__init__(599, message=message) + + def __str__(self) -> str: + return self.message or "Timeout" + + +class HTTPStreamClosedError(HTTPError): + """Error raised by SimpleAsyncHTTPClient when the underlying stream is closed. + + When a more specific exception is available (such as `ConnectionResetError`), + it may be raised instead of this one. + + For historical reasons, this is a subclass of `.HTTPClientError` + which simulates a response code of 599. + + .. versionadded:: 5.1 + """ + + def __init__(self, message: str) -> None: + super().__init__(599, message=message) + + def __str__(self) -> str: + return self.message or "Stream closed" + + +class SimpleAsyncHTTPClient(AsyncHTTPClient): + """Non-blocking HTTP client with no external dependencies. + + This class implements an HTTP 1.1 client on top of Tornado's IOStreams. + Some features found in the curl-based AsyncHTTPClient are not yet + supported. In particular, proxies are not supported, connections + are not reused, and callers cannot select the network interface to be + used. + """ + + def initialize( # type: ignore + self, + max_clients: int = 10, + hostname_mapping: Optional[Dict[str, str]] = None, + max_buffer_size: int = 104857600, + resolver: Optional[Resolver] = None, + defaults: Optional[Dict[str, Any]] = None, + max_header_size: Optional[int] = None, + max_body_size: Optional[int] = None, + ) -> None: + """Creates a AsyncHTTPClient. + + Only a single AsyncHTTPClient instance exists per IOLoop + in order to provide limitations on the number of pending connections. + ``force_instance=True`` may be used to suppress this behavior. + + Note that because of this implicit reuse, unless ``force_instance`` + is used, only the first call to the constructor actually uses + its arguments. It is recommended to use the ``configure`` method + instead of the constructor to ensure that arguments take effect. + + ``max_clients`` is the number of concurrent requests that can be + in progress; when this limit is reached additional requests will be + queued. Note that time spent waiting in this queue still counts + against the ``request_timeout``. + + ``hostname_mapping`` is a dictionary mapping hostnames to IP addresses. + It can be used to make local DNS changes when modifying system-wide + settings like ``/etc/hosts`` is not possible or desirable (e.g. in + unittests). + + ``max_buffer_size`` (default 100MB) is the number of bytes + that can be read into memory at once. ``max_body_size`` + (defaults to ``max_buffer_size``) is the largest response body + that the client will accept. Without a + ``streaming_callback``, the smaller of these two limits + applies; with a ``streaming_callback`` only ``max_body_size`` + does. + + .. versionchanged:: 4.2 + Added the ``max_body_size`` argument. + """ + super().initialize(defaults=defaults) + self.max_clients = max_clients + self.queue = ( + collections.deque() + ) # type: Deque[Tuple[object, HTTPRequest, Callable[[HTTPResponse], None]]] + self.active = ( + {} + ) # type: Dict[object, Tuple[HTTPRequest, Callable[[HTTPResponse], None]]] + self.waiting = ( + {} + ) # type: Dict[object, Tuple[HTTPRequest, Callable[[HTTPResponse], None], object]] + self.max_buffer_size = max_buffer_size + self.max_header_size = max_header_size + self.max_body_size = max_body_size + # TCPClient could create a Resolver for us, but we have to do it + # ourselves to support hostname_mapping. + if resolver: + self.resolver = resolver + self.own_resolver = False + else: + self.resolver = Resolver() + self.own_resolver = True + if hostname_mapping is not None: + self.resolver = OverrideResolver( + resolver=self.resolver, mapping=hostname_mapping + ) + self.tcp_client = TCPClient(resolver=self.resolver) + + def close(self) -> None: + super().close() + if self.own_resolver: + self.resolver.close() + self.tcp_client.close() + + def fetch_impl( + self, request: HTTPRequest, callback: Callable[[HTTPResponse], None] + ) -> None: + key = object() + self.queue.append((key, request, callback)) + assert request.connect_timeout is not None + assert request.request_timeout is not None + timeout_handle = None + if len(self.active) >= self.max_clients: + timeout = ( + min(request.connect_timeout, request.request_timeout) + or request.connect_timeout + or request.request_timeout + ) # min but skip zero + if timeout: + timeout_handle = self.io_loop.add_timeout( + self.io_loop.time() + timeout, + functools.partial(self._on_timeout, key, "in request queue"), + ) + self.waiting[key] = (request, callback, timeout_handle) + self._process_queue() + if self.queue: + gen_log.debug( + "max_clients limit reached, request queued. " + "%d active, %d queued requests." % (len(self.active), len(self.queue)) + ) + + def _process_queue(self) -> None: + while self.queue and len(self.active) < self.max_clients: + key, request, callback = self.queue.popleft() + if key not in self.waiting: + continue + self._remove_timeout(key) + self.active[key] = (request, callback) + release_callback = functools.partial(self._release_fetch, key) + self._handle_request(request, release_callback, callback) + + def _connection_class(self) -> type: + return _HTTPConnection + + def _handle_request( + self, + request: HTTPRequest, + release_callback: Callable[[], None], + final_callback: Callable[[HTTPResponse], None], + ) -> None: + self._connection_class()( + self, + request, + release_callback, + final_callback, + self.max_buffer_size, + self.tcp_client, + self.max_header_size, + self.max_body_size, + ) + + def _release_fetch(self, key: object) -> None: + del self.active[key] + self._process_queue() + + def _remove_timeout(self, key: object) -> None: + if key in self.waiting: + request, callback, timeout_handle = self.waiting[key] + if timeout_handle is not None: + self.io_loop.remove_timeout(timeout_handle) + del self.waiting[key] + + def _on_timeout(self, key: object, info: Optional[str] = None) -> None: + """Timeout callback of request. + + Construct a timeout HTTPResponse when a timeout occurs. + + :arg object key: A simple object to mark the request. + :info string key: More detailed timeout information. + """ + request, callback, timeout_handle = self.waiting[key] + self.queue.remove((key, request, callback)) + + error_message = "Timeout {0}".format(info) if info else "Timeout" + timeout_response = HTTPResponse( + request, + 599, + error=HTTPTimeoutError(error_message), + request_time=self.io_loop.time() - request.start_time, + ) + self.io_loop.add_callback(callback, timeout_response) + del self.waiting[key] + + +class _HTTPConnection(httputil.HTTPMessageDelegate): + _SUPPORTED_METHODS = set( + ["GET", "HEAD", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"] + ) + + def __init__( + self, + client: Optional[SimpleAsyncHTTPClient], + request: HTTPRequest, + release_callback: Callable[[], None], + final_callback: Callable[[HTTPResponse], None], + max_buffer_size: int, + tcp_client: TCPClient, + max_header_size: int, + max_body_size: int, + ) -> None: + self.io_loop = IOLoop.current() + self.start_time = self.io_loop.time() + self.start_wall_time = time.time() + self.client = client + self.request = request + self.release_callback = release_callback + self.final_callback = final_callback + self.max_buffer_size = max_buffer_size + self.tcp_client = tcp_client + self.max_header_size = max_header_size + self.max_body_size = max_body_size + self.code = None # type: Optional[int] + self.headers = None # type: Optional[httputil.HTTPHeaders] + self.chunks = [] # type: List[bytes] + self._decompressor = None + # Timeout handle returned by IOLoop.add_timeout + self._timeout = None # type: object + self._sockaddr = None + IOLoop.current().add_future( + gen.convert_yielded(self.run()), lambda f: f.result() + ) + + async def run(self) -> None: + try: + self.parsed = urllib.parse.urlsplit(_unicode(self.request.url)) + if self.parsed.scheme not in ("http", "https"): + raise ValueError("Unsupported url scheme: %s" % self.request.url) + # urlsplit results have hostname and port results, but they + # didn't support ipv6 literals until python 2.7. + netloc = self.parsed.netloc + if "@" in netloc: + userpass, _, netloc = netloc.rpartition("@") + host, port = httputil.split_host_and_port(netloc) + if port is None: + port = 443 if self.parsed.scheme == "https" else 80 + if re.match(r"^\[.*\]$", host): + # raw ipv6 addresses in urls are enclosed in brackets + host = host[1:-1] + self.parsed_hostname = host # save final host for _on_connect + + if self.request.allow_ipv6 is False: + af = socket.AF_INET + else: + af = socket.AF_UNSPEC + + ssl_options = self._get_ssl_options(self.parsed.scheme) + + source_ip = None + if self.request.network_interface: + if is_valid_ip(self.request.network_interface): + source_ip = self.request.network_interface + else: + raise ValueError( + "Unrecognized IPv4 or IPv6 address for network_interface, got %r" + % (self.request.network_interface,) + ) + + timeout = ( + min(self.request.connect_timeout, self.request.request_timeout) + or self.request.connect_timeout + or self.request.request_timeout + ) # min but skip zero + if timeout: + self._timeout = self.io_loop.add_timeout( + self.start_time + timeout, + functools.partial(self._on_timeout, "while connecting"), + ) + stream = await self.tcp_client.connect( + host, + port, + af=af, + ssl_options=ssl_options, + max_buffer_size=self.max_buffer_size, + source_ip=source_ip, + ) + + if self.final_callback is None: + # final_callback is cleared if we've hit our timeout. + stream.close() + return + self.stream = stream + self.stream.set_close_callback(self.on_connection_close) + self._remove_timeout() + if self.final_callback is None: + return + if self.request.request_timeout: + self._timeout = self.io_loop.add_timeout( + self.start_time + self.request.request_timeout, + functools.partial(self._on_timeout, "during request"), + ) + if ( + self.request.method not in self._SUPPORTED_METHODS + and not self.request.allow_nonstandard_methods + ): + raise KeyError("unknown method %s" % self.request.method) + for key in ( + "proxy_host", + "proxy_port", + "proxy_username", + "proxy_password", + "proxy_auth_mode", + ): + if getattr(self.request, key, None): + raise NotImplementedError("%s not supported" % key) + if "Connection" not in self.request.headers: + self.request.headers["Connection"] = "close" + if "Host" not in self.request.headers: + if "@" in self.parsed.netloc: + self.request.headers["Host"] = self.parsed.netloc.rpartition("@")[ + -1 + ] + else: + self.request.headers["Host"] = self.parsed.netloc + username, password = None, None + if self.parsed.username is not None: + username, password = self.parsed.username, self.parsed.password + elif self.request.auth_username is not None: + username = self.request.auth_username + password = self.request.auth_password or "" + if username is not None: + assert password is not None + if self.request.auth_mode not in (None, "basic"): + raise ValueError("unsupported auth_mode %s", self.request.auth_mode) + self.request.headers["Authorization"] = "Basic " + _unicode( + base64.b64encode( + httputil.encode_username_password(username, password) + ) + ) + if self.request.user_agent: + self.request.headers["User-Agent"] = self.request.user_agent + elif self.request.headers.get("User-Agent") is None: + self.request.headers["User-Agent"] = "Tornado/{}".format(version) + if not self.request.allow_nonstandard_methods: + # Some HTTP methods nearly always have bodies while others + # almost never do. Fail in this case unless the user has + # opted out of sanity checks with allow_nonstandard_methods. + body_expected = self.request.method in ("POST", "PATCH", "PUT") + body_present = ( + self.request.body is not None + or self.request.body_producer is not None + ) + if (body_expected and not body_present) or ( + body_present and not body_expected + ): + raise ValueError( + "Body must %sbe None for method %s (unless " + "allow_nonstandard_methods is true)" + % ("not " if body_expected else "", self.request.method) + ) + if self.request.expect_100_continue: + self.request.headers["Expect"] = "100-continue" + if self.request.body is not None: + # When body_producer is used the caller is responsible for + # setting Content-Length (or else chunked encoding will be used). + self.request.headers["Content-Length"] = str(len(self.request.body)) + if ( + self.request.method == "POST" + and "Content-Type" not in self.request.headers + ): + self.request.headers[ + "Content-Type" + ] = "application/x-www-form-urlencoded" + if self.request.decompress_response: + self.request.headers["Accept-Encoding"] = "gzip" + req_path = (self.parsed.path or "/") + ( + ("?" + self.parsed.query) if self.parsed.query else "" + ) + self.connection = self._create_connection(stream) + start_line = httputil.RequestStartLine(self.request.method, req_path, "") + self.connection.write_headers(start_line, self.request.headers) + if self.request.expect_100_continue: + await self.connection.read_response(self) + else: + await self._write_body(True) + except Exception: + if not self._handle_exception(*sys.exc_info()): + raise + + def _get_ssl_options( + self, scheme: str + ) -> Union[None, Dict[str, Any], ssl.SSLContext]: + if scheme == "https": + if self.request.ssl_options is not None: + return self.request.ssl_options + # If we are using the defaults, don't construct a + # new SSLContext. + if ( + self.request.validate_cert + and self.request.ca_certs is None + and self.request.client_cert is None + and self.request.client_key is None + ): + return _client_ssl_defaults + ssl_ctx = ssl.create_default_context( + ssl.Purpose.SERVER_AUTH, cafile=self.request.ca_certs + ) + if not self.request.validate_cert: + ssl_ctx.check_hostname = False + ssl_ctx.verify_mode = ssl.CERT_NONE + if self.request.client_cert is not None: + ssl_ctx.load_cert_chain( + self.request.client_cert, self.request.client_key + ) + if hasattr(ssl, "OP_NO_COMPRESSION"): + # See netutil.ssl_options_to_context + ssl_ctx.options |= ssl.OP_NO_COMPRESSION + return ssl_ctx + return None + + def _on_timeout(self, info: Optional[str] = None) -> None: + """Timeout callback of _HTTPConnection instance. + + Raise a `HTTPTimeoutError` when a timeout occurs. + + :info string key: More detailed timeout information. + """ + self._timeout = None + error_message = "Timeout {0}".format(info) if info else "Timeout" + if self.final_callback is not None: + self._handle_exception( + HTTPTimeoutError, HTTPTimeoutError(error_message), None + ) + + def _remove_timeout(self) -> None: + if self._timeout is not None: + self.io_loop.remove_timeout(self._timeout) + self._timeout = None + + def _create_connection(self, stream: IOStream) -> HTTP1Connection: + stream.set_nodelay(True) + connection = HTTP1Connection( + stream, + True, + HTTP1ConnectionParameters( + no_keep_alive=True, + max_header_size=self.max_header_size, + max_body_size=self.max_body_size, + decompress=bool(self.request.decompress_response), + ), + self._sockaddr, + ) + return connection + + async def _write_body(self, start_read: bool) -> None: + if self.request.body is not None: + self.connection.write(self.request.body) + elif self.request.body_producer is not None: + fut = self.request.body_producer(self.connection.write) + if fut is not None: + await fut + self.connection.finish() + if start_read: + try: + await self.connection.read_response(self) + except StreamClosedError: + if not self._handle_exception(*sys.exc_info()): + raise + + def _release(self) -> None: + if self.release_callback is not None: + release_callback = self.release_callback + self.release_callback = None # type: ignore + release_callback() + + def _run_callback(self, response: HTTPResponse) -> None: + self._release() + if self.final_callback is not None: + final_callback = self.final_callback + self.final_callback = None # type: ignore + self.io_loop.add_callback(final_callback, response) + + def _handle_exception( + self, + typ: "Optional[Type[BaseException]]", + value: Optional[BaseException], + tb: Optional[TracebackType], + ) -> bool: + if self.final_callback: + self._remove_timeout() + if isinstance(value, StreamClosedError): + if value.real_error is None: + value = HTTPStreamClosedError("Stream closed") + else: + value = value.real_error + self._run_callback( + HTTPResponse( + self.request, + 599, + error=value, + request_time=self.io_loop.time() - self.start_time, + start_time=self.start_wall_time, + ) + ) + + if hasattr(self, "stream"): + # TODO: this may cause a StreamClosedError to be raised + # by the connection's Future. Should we cancel the + # connection more gracefully? + self.stream.close() + return True + else: + # If our callback has already been called, we are probably + # catching an exception that is not caused by us but rather + # some child of our callback. Rather than drop it on the floor, + # pass it along, unless it's just the stream being closed. + return isinstance(value, StreamClosedError) + + def on_connection_close(self) -> None: + if self.final_callback is not None: + message = "Connection closed" + if self.stream.error: + raise self.stream.error + try: + raise HTTPStreamClosedError(message) + except HTTPStreamClosedError: + self._handle_exception(*sys.exc_info()) + + async def headers_received( + self, + first_line: Union[httputil.ResponseStartLine, httputil.RequestStartLine], + headers: httputil.HTTPHeaders, + ) -> None: + assert isinstance(first_line, httputil.ResponseStartLine) + if self.request.expect_100_continue and first_line.code == 100: + await self._write_body(False) + return + self.code = first_line.code + self.reason = first_line.reason + self.headers = headers + + if self._should_follow_redirect(): + return + + if self.request.header_callback is not None: + # Reassemble the start line. + self.request.header_callback("%s %s %s\r\n" % first_line) + for k, v in self.headers.get_all(): + self.request.header_callback("%s: %s\r\n" % (k, v)) + self.request.header_callback("\r\n") + + def _should_follow_redirect(self) -> bool: + if self.request.follow_redirects: + assert self.request.max_redirects is not None + return ( + self.code in (301, 302, 303, 307, 308) + and self.request.max_redirects > 0 + and self.headers is not None + and self.headers.get("Location") is not None + ) + return False + + def finish(self) -> None: + assert self.code is not None + data = b"".join(self.chunks) + self._remove_timeout() + original_request = getattr(self.request, "original_request", self.request) + if self._should_follow_redirect(): + assert isinstance(self.request, _RequestProxy) + new_request = copy.copy(self.request.request) + new_request.url = urllib.parse.urljoin( + self.request.url, self.headers["Location"] + ) + new_request.max_redirects = self.request.max_redirects - 1 + del new_request.headers["Host"] + # https://tools.ietf.org/html/rfc7231#section-6.4 + # + # The original HTTP spec said that after a 301 or 302 + # redirect, the request method should be preserved. + # However, browsers implemented this by changing the + # method to GET, and the behavior stuck. 303 redirects + # always specified this POST-to-GET behavior, arguably + # for *all* methods, but libcurl < 7.70 only does this + # for POST, while libcurl >= 7.70 does it for other methods. + if (self.code == 303 and self.request.method != "HEAD") or ( + self.code in (301, 302) and self.request.method == "POST" + ): + new_request.method = "GET" + new_request.body = None + for h in [ + "Content-Length", + "Content-Type", + "Content-Encoding", + "Transfer-Encoding", + ]: + try: + del self.request.headers[h] + except KeyError: + pass + new_request.original_request = original_request + final_callback = self.final_callback + self.final_callback = None + self._release() + fut = self.client.fetch(new_request, raise_error=False) + fut.add_done_callback(lambda f: final_callback(f.result())) + self._on_end_request() + return + if self.request.streaming_callback: + buffer = BytesIO() + else: + buffer = BytesIO(data) # TODO: don't require one big string? + response = HTTPResponse( + original_request, + self.code, + reason=getattr(self, "reason", None), + headers=self.headers, + request_time=self.io_loop.time() - self.start_time, + start_time=self.start_wall_time, + buffer=buffer, + effective_url=self.request.url, + ) + self._run_callback(response) + self._on_end_request() + + def _on_end_request(self) -> None: + self.stream.close() + + def data_received(self, chunk: bytes) -> None: + if self._should_follow_redirect(): + # We're going to follow a redirect so just discard the body. + return + if self.request.streaming_callback is not None: + self.request.streaming_callback(chunk) + else: + self.chunks.append(chunk) + + +if __name__ == "__main__": + AsyncHTTPClient.configure(SimpleAsyncHTTPClient) + main() diff --git a/venv/lib/python3.8/site-packages/tornado/speedups.cpython-38-x86_64-linux-gnu.so b/venv/lib/python3.8/site-packages/tornado/speedups.cpython-38-x86_64-linux-gnu.so new file mode 100755 index 0000000000000000000000000000000000000000..407a15c07fa53ac76d792189c3f5131ef559f16f GIT binary patch literal 29256 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 BvEKjy literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/tornado/tcpclient.py b/venv/lib/python3.8/site-packages/tornado/tcpclient.py new file mode 100644 index 0000000..e2d682e --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/tcpclient.py @@ -0,0 +1,328 @@ +# +# Copyright 2014 Facebook +# +# 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. + +"""A non-blocking TCP connection factory. +""" + +import functools +import socket +import numbers +import datetime +import ssl + +from tornado.concurrent import Future, future_add_done_callback +from tornado.ioloop import IOLoop +from tornado.iostream import IOStream +from tornado import gen +from tornado.netutil import Resolver +from tornado.gen import TimeoutError + +from typing import Any, Union, Dict, Tuple, List, Callable, Iterator, Optional, Set + +_INITIAL_CONNECT_TIMEOUT = 0.3 + + +class _Connector(object): + """A stateless implementation of the "Happy Eyeballs" algorithm. + + "Happy Eyeballs" is documented in RFC6555 as the recommended practice + for when both IPv4 and IPv6 addresses are available. + + In this implementation, we partition the addresses by family, and + make the first connection attempt to whichever address was + returned first by ``getaddrinfo``. If that connection fails or + times out, we begin a connection in parallel to the first address + of the other family. If there are additional failures we retry + with other addresses, keeping one connection attempt per family + in flight at a time. + + http://tools.ietf.org/html/rfc6555 + + """ + + def __init__( + self, + addrinfo: List[Tuple], + connect: Callable[ + [socket.AddressFamily, Tuple], Tuple[IOStream, "Future[IOStream]"] + ], + ) -> None: + self.io_loop = IOLoop.current() + self.connect = connect + + self.future = ( + Future() + ) # type: Future[Tuple[socket.AddressFamily, Any, IOStream]] + self.timeout = None # type: Optional[object] + self.connect_timeout = None # type: Optional[object] + self.last_error = None # type: Optional[Exception] + self.remaining = len(addrinfo) + self.primary_addrs, self.secondary_addrs = self.split(addrinfo) + self.streams = set() # type: Set[IOStream] + + @staticmethod + def split( + addrinfo: List[Tuple], + ) -> Tuple[ + List[Tuple[socket.AddressFamily, Tuple]], + List[Tuple[socket.AddressFamily, Tuple]], + ]: + """Partition the ``addrinfo`` list by address family. + + Returns two lists. The first list contains the first entry from + ``addrinfo`` and all others with the same family, and the + second list contains all other addresses (normally one list will + be AF_INET and the other AF_INET6, although non-standard resolvers + may return additional families). + """ + primary = [] + secondary = [] + primary_af = addrinfo[0][0] + for af, addr in addrinfo: + if af == primary_af: + primary.append((af, addr)) + else: + secondary.append((af, addr)) + return primary, secondary + + def start( + self, + timeout: float = _INITIAL_CONNECT_TIMEOUT, + connect_timeout: Optional[Union[float, datetime.timedelta]] = None, + ) -> "Future[Tuple[socket.AddressFamily, Any, IOStream]]": + self.try_connect(iter(self.primary_addrs)) + self.set_timeout(timeout) + if connect_timeout is not None: + self.set_connect_timeout(connect_timeout) + return self.future + + def try_connect(self, addrs: Iterator[Tuple[socket.AddressFamily, Tuple]]) -> None: + try: + af, addr = next(addrs) + except StopIteration: + # We've reached the end of our queue, but the other queue + # might still be working. Send a final error on the future + # only when both queues are finished. + if self.remaining == 0 and not self.future.done(): + self.future.set_exception( + self.last_error or IOError("connection failed") + ) + return + stream, future = self.connect(af, addr) + self.streams.add(stream) + future_add_done_callback( + future, functools.partial(self.on_connect_done, addrs, af, addr) + ) + + def on_connect_done( + self, + addrs: Iterator[Tuple[socket.AddressFamily, Tuple]], + af: socket.AddressFamily, + addr: Tuple, + future: "Future[IOStream]", + ) -> None: + self.remaining -= 1 + try: + stream = future.result() + except Exception as e: + if self.future.done(): + return + # Error: try again (but remember what happened so we have an + # error to raise in the end) + self.last_error = e + self.try_connect(addrs) + if self.timeout is not None: + # If the first attempt failed, don't wait for the + # timeout to try an address from the secondary queue. + self.io_loop.remove_timeout(self.timeout) + self.on_timeout() + return + self.clear_timeouts() + if self.future.done(): + # This is a late arrival; just drop it. + stream.close() + else: + self.streams.discard(stream) + self.future.set_result((af, addr, stream)) + self.close_streams() + + def set_timeout(self, timeout: float) -> None: + self.timeout = self.io_loop.add_timeout( + self.io_loop.time() + timeout, self.on_timeout + ) + + def on_timeout(self) -> None: + self.timeout = None + if not self.future.done(): + self.try_connect(iter(self.secondary_addrs)) + + def clear_timeout(self) -> None: + if self.timeout is not None: + self.io_loop.remove_timeout(self.timeout) + + def set_connect_timeout( + self, connect_timeout: Union[float, datetime.timedelta] + ) -> None: + self.connect_timeout = self.io_loop.add_timeout( + connect_timeout, self.on_connect_timeout + ) + + def on_connect_timeout(self) -> None: + if not self.future.done(): + self.future.set_exception(TimeoutError()) + self.close_streams() + + def clear_timeouts(self) -> None: + if self.timeout is not None: + self.io_loop.remove_timeout(self.timeout) + if self.connect_timeout is not None: + self.io_loop.remove_timeout(self.connect_timeout) + + def close_streams(self) -> None: + for stream in self.streams: + stream.close() + + +class TCPClient(object): + """A non-blocking TCP connection factory. + + .. versionchanged:: 5.0 + The ``io_loop`` argument (deprecated since version 4.1) has been removed. + """ + + def __init__(self, resolver: Optional[Resolver] = None) -> None: + if resolver is not None: + self.resolver = resolver + self._own_resolver = False + else: + self.resolver = Resolver() + self._own_resolver = True + + def close(self) -> None: + if self._own_resolver: + self.resolver.close() + + async def connect( + self, + host: str, + port: int, + af: socket.AddressFamily = socket.AF_UNSPEC, + ssl_options: Optional[Union[Dict[str, Any], ssl.SSLContext]] = None, + max_buffer_size: Optional[int] = None, + source_ip: Optional[str] = None, + source_port: Optional[int] = None, + timeout: Optional[Union[float, datetime.timedelta]] = None, + ) -> IOStream: + """Connect to the given host and port. + + Asynchronously returns an `.IOStream` (or `.SSLIOStream` if + ``ssl_options`` is not None). + + Using the ``source_ip`` kwarg, one can specify the source + IP address to use when establishing the connection. + In case the user needs to resolve and + use a specific interface, it has to be handled outside + of Tornado as this depends very much on the platform. + + Raises `TimeoutError` if the input future does not complete before + ``timeout``, which may be specified in any form allowed by + `.IOLoop.add_timeout` (i.e. a `datetime.timedelta` or an absolute time + relative to `.IOLoop.time`) + + Similarly, when the user requires a certain source port, it can + be specified using the ``source_port`` arg. + + .. versionchanged:: 4.5 + Added the ``source_ip`` and ``source_port`` arguments. + + .. versionchanged:: 5.0 + Added the ``timeout`` argument. + """ + if timeout is not None: + if isinstance(timeout, numbers.Real): + timeout = IOLoop.current().time() + timeout + elif isinstance(timeout, datetime.timedelta): + timeout = IOLoop.current().time() + timeout.total_seconds() + else: + raise TypeError("Unsupported timeout %r" % timeout) + if timeout is not None: + addrinfo = await gen.with_timeout( + timeout, self.resolver.resolve(host, port, af) + ) + else: + addrinfo = await self.resolver.resolve(host, port, af) + connector = _Connector( + addrinfo, + functools.partial( + self._create_stream, + max_buffer_size, + source_ip=source_ip, + source_port=source_port, + ), + ) + af, addr, stream = await connector.start(connect_timeout=timeout) + # TODO: For better performance we could cache the (af, addr) + # information here and re-use it on subsequent connections to + # the same host. (http://tools.ietf.org/html/rfc6555#section-4.2) + if ssl_options is not None: + if timeout is not None: + stream = await gen.with_timeout( + timeout, + stream.start_tls( + False, ssl_options=ssl_options, server_hostname=host + ), + ) + else: + stream = await stream.start_tls( + False, ssl_options=ssl_options, server_hostname=host + ) + return stream + + def _create_stream( + self, + max_buffer_size: int, + af: socket.AddressFamily, + addr: Tuple, + source_ip: Optional[str] = None, + source_port: Optional[int] = None, + ) -> Tuple[IOStream, "Future[IOStream]"]: + # Always connect in plaintext; we'll convert to ssl if necessary + # after one connection has completed. + source_port_bind = source_port if isinstance(source_port, int) else 0 + source_ip_bind = source_ip + if source_port_bind and not source_ip: + # User required a specific port, but did not specify + # a certain source IP, will bind to the default loopback. + source_ip_bind = "::1" if af == socket.AF_INET6 else "127.0.0.1" + # Trying to use the same address family as the requested af socket: + # - 127.0.0.1 for IPv4 + # - ::1 for IPv6 + socket_obj = socket.socket(af) + if source_port_bind or source_ip_bind: + # If the user requires binding also to a specific IP/port. + try: + socket_obj.bind((source_ip_bind, source_port_bind)) + except socket.error: + socket_obj.close() + # Fail loudly if unable to use the IP/port. + raise + try: + stream = IOStream(socket_obj, max_buffer_size=max_buffer_size) + except socket.error as e: + fu = Future() # type: Future[IOStream] + fu.set_exception(e) + return stream, fu + else: + return stream, stream.connect(addr) diff --git a/venv/lib/python3.8/site-packages/tornado/tcpserver.py b/venv/lib/python3.8/site-packages/tornado/tcpserver.py new file mode 100644 index 0000000..476ffc9 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/tcpserver.py @@ -0,0 +1,334 @@ +# +# Copyright 2011 Facebook +# +# 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. + +"""A non-blocking, single-threaded TCP server.""" + +import errno +import os +import socket +import ssl + +from tornado import gen +from tornado.log import app_log +from tornado.ioloop import IOLoop +from tornado.iostream import IOStream, SSLIOStream +from tornado.netutil import bind_sockets, add_accept_handler, ssl_wrap_socket +from tornado import process +from tornado.util import errno_from_exception + +import typing +from typing import Union, Dict, Any, Iterable, Optional, Awaitable + +if typing.TYPE_CHECKING: + from typing import Callable, List # noqa: F401 + + +class TCPServer(object): + r"""A non-blocking, single-threaded TCP server. + + To use `TCPServer`, define a subclass which overrides the `handle_stream` + method. For example, a simple echo server could be defined like this:: + + from tornado.tcpserver import TCPServer + from tornado.iostream import StreamClosedError + from tornado import gen + + class EchoServer(TCPServer): + async def handle_stream(self, stream, address): + while True: + try: + data = await stream.read_until(b"\n") + await stream.write(data) + except StreamClosedError: + break + + To make this server serve SSL traffic, send the ``ssl_options`` keyword + argument with an `ssl.SSLContext` object. For compatibility with older + versions of Python ``ssl_options`` may also be a dictionary of keyword + arguments for the `ssl.wrap_socket` method.:: + + ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) + ssl_ctx.load_cert_chain(os.path.join(data_dir, "mydomain.crt"), + os.path.join(data_dir, "mydomain.key")) + TCPServer(ssl_options=ssl_ctx) + + `TCPServer` initialization follows one of three patterns: + + 1. `listen`: simple single-process:: + + server = TCPServer() + server.listen(8888) + IOLoop.current().start() + + 2. `bind`/`start`: simple multi-process:: + + server = TCPServer() + server.bind(8888) + server.start(0) # Forks multiple sub-processes + IOLoop.current().start() + + When using this interface, an `.IOLoop` must *not* be passed + to the `TCPServer` constructor. `start` will always start + the server on the default singleton `.IOLoop`. + + 3. `add_sockets`: advanced multi-process:: + + sockets = bind_sockets(8888) + tornado.process.fork_processes(0) + server = TCPServer() + server.add_sockets(sockets) + IOLoop.current().start() + + The `add_sockets` interface is more complicated, but it can be + used with `tornado.process.fork_processes` to give you more + flexibility in when the fork happens. `add_sockets` can + also be used in single-process servers if you want to create + your listening sockets in some way other than + `~tornado.netutil.bind_sockets`. + + .. versionadded:: 3.1 + The ``max_buffer_size`` argument. + + .. versionchanged:: 5.0 + The ``io_loop`` argument has been removed. + """ + + def __init__( + self, + ssl_options: Optional[Union[Dict[str, Any], ssl.SSLContext]] = None, + max_buffer_size: Optional[int] = None, + read_chunk_size: Optional[int] = None, + ) -> None: + self.ssl_options = ssl_options + self._sockets = {} # type: Dict[int, socket.socket] + self._handlers = {} # type: Dict[int, Callable[[], None]] + self._pending_sockets = [] # type: List[socket.socket] + self._started = False + self._stopped = False + self.max_buffer_size = max_buffer_size + self.read_chunk_size = read_chunk_size + + # Verify the SSL options. Otherwise we don't get errors until clients + # connect. This doesn't verify that the keys are legitimate, but + # the SSL module doesn't do that until there is a connected socket + # which seems like too much work + if self.ssl_options is not None and isinstance(self.ssl_options, dict): + # Only certfile is required: it can contain both keys + if "certfile" not in self.ssl_options: + raise KeyError('missing key "certfile" in ssl_options') + + if not os.path.exists(self.ssl_options["certfile"]): + raise ValueError( + 'certfile "%s" does not exist' % self.ssl_options["certfile"] + ) + if "keyfile" in self.ssl_options and not os.path.exists( + self.ssl_options["keyfile"] + ): + raise ValueError( + 'keyfile "%s" does not exist' % self.ssl_options["keyfile"] + ) + + def listen(self, port: int, address: str = "") -> None: + """Starts accepting connections on the given port. + + This method may be called more than once to listen on multiple ports. + `listen` takes effect immediately; it is not necessary to call + `TCPServer.start` afterwards. It is, however, necessary to start + the `.IOLoop`. + """ + sockets = bind_sockets(port, address=address) + self.add_sockets(sockets) + + def add_sockets(self, sockets: Iterable[socket.socket]) -> None: + """Makes this server start accepting connections on the given sockets. + + The ``sockets`` parameter is a list of socket objects such as + those returned by `~tornado.netutil.bind_sockets`. + `add_sockets` is typically used in combination with that + method and `tornado.process.fork_processes` to provide greater + control over the initialization of a multi-process server. + """ + for sock in sockets: + self._sockets[sock.fileno()] = sock + self._handlers[sock.fileno()] = add_accept_handler( + sock, self._handle_connection + ) + + def add_socket(self, socket: socket.socket) -> None: + """Singular version of `add_sockets`. Takes a single socket object.""" + self.add_sockets([socket]) + + def bind( + self, + port: int, + address: Optional[str] = None, + family: socket.AddressFamily = socket.AF_UNSPEC, + backlog: int = 128, + reuse_port: bool = False, + ) -> None: + """Binds this server to the given port on the given address. + + To start the server, call `start`. If you want to run this server + in a single process, you can call `listen` as a shortcut to the + sequence of `bind` and `start` calls. + + Address may be either an IP address or hostname. If it's a hostname, + the server will listen on all IP addresses associated with the + name. Address may be an empty string or None to listen on all + available interfaces. Family may be set to either `socket.AF_INET` + or `socket.AF_INET6` to restrict to IPv4 or IPv6 addresses, otherwise + both will be used if available. + + The ``backlog`` argument has the same meaning as for + `socket.listen <socket.socket.listen>`. The ``reuse_port`` argument + has the same meaning as for `.bind_sockets`. + + This method may be called multiple times prior to `start` to listen + on multiple ports or interfaces. + + .. versionchanged:: 4.4 + Added the ``reuse_port`` argument. + """ + sockets = bind_sockets( + port, address=address, family=family, backlog=backlog, reuse_port=reuse_port + ) + if self._started: + self.add_sockets(sockets) + else: + self._pending_sockets.extend(sockets) + + def start( + self, num_processes: Optional[int] = 1, max_restarts: Optional[int] = None + ) -> None: + """Starts this server in the `.IOLoop`. + + By default, we run the server in this process and do not fork any + additional child process. + + If num_processes is ``None`` or <= 0, we detect the number of cores + available on this machine and fork that number of child + processes. If num_processes is given and > 1, we fork that + specific number of sub-processes. + + Since we use processes and not threads, there is no shared memory + between any server code. + + Note that multiple processes are not compatible with the autoreload + module (or the ``autoreload=True`` option to `tornado.web.Application` + which defaults to True when ``debug=True``). + When using multiple processes, no IOLoops can be created or + referenced until after the call to ``TCPServer.start(n)``. + + Values of ``num_processes`` other than 1 are not supported on Windows. + + The ``max_restarts`` argument is passed to `.fork_processes`. + + .. versionchanged:: 6.0 + + Added ``max_restarts`` argument. + """ + assert not self._started + self._started = True + if num_processes != 1: + process.fork_processes(num_processes, max_restarts) + sockets = self._pending_sockets + self._pending_sockets = [] + self.add_sockets(sockets) + + def stop(self) -> None: + """Stops listening for new connections. + + Requests currently in progress may still continue after the + server is stopped. + """ + if self._stopped: + return + self._stopped = True + for fd, sock in self._sockets.items(): + assert sock.fileno() == fd + # Unregister socket from IOLoop + self._handlers.pop(fd)() + sock.close() + + def handle_stream( + self, stream: IOStream, address: tuple + ) -> Optional[Awaitable[None]]: + """Override to handle a new `.IOStream` from an incoming connection. + + This method may be a coroutine; if so any exceptions it raises + asynchronously will be logged. Accepting of incoming connections + will not be blocked by this coroutine. + + If this `TCPServer` is configured for SSL, ``handle_stream`` + may be called before the SSL handshake has completed. Use + `.SSLIOStream.wait_for_handshake` if you need to verify the client's + certificate or use NPN/ALPN. + + .. versionchanged:: 4.2 + Added the option for this method to be a coroutine. + """ + raise NotImplementedError() + + def _handle_connection(self, connection: socket.socket, address: Any) -> None: + if self.ssl_options is not None: + assert ssl, "Python 2.6+ and OpenSSL required for SSL" + try: + connection = ssl_wrap_socket( + connection, + self.ssl_options, + server_side=True, + do_handshake_on_connect=False, + ) + except ssl.SSLError as err: + if err.args[0] == ssl.SSL_ERROR_EOF: + return connection.close() + else: + raise + except socket.error as err: + # If the connection is closed immediately after it is created + # (as in a port scan), we can get one of several errors. + # wrap_socket makes an internal call to getpeername, + # which may return either EINVAL (Mac OS X) or ENOTCONN + # (Linux). If it returns ENOTCONN, this error is + # silently swallowed by the ssl module, so we need to + # catch another error later on (AttributeError in + # SSLIOStream._do_ssl_handshake). + # To test this behavior, try nmap with the -sT flag. + # https://github.com/tornadoweb/tornado/pull/750 + if errno_from_exception(err) in (errno.ECONNABORTED, errno.EINVAL): + return connection.close() + else: + raise + try: + if self.ssl_options is not None: + stream = SSLIOStream( + connection, + max_buffer_size=self.max_buffer_size, + read_chunk_size=self.read_chunk_size, + ) # type: IOStream + else: + stream = IOStream( + connection, + max_buffer_size=self.max_buffer_size, + read_chunk_size=self.read_chunk_size, + ) + + future = self.handle_stream(stream, address) + if future is not None: + IOLoop.current().add_future( + gen.convert_yielded(future), lambda f: f.result() + ) + except Exception: + app_log.error("Error in connection callback", exc_info=True) diff --git a/venv/lib/python3.8/site-packages/tornado/template.py b/venv/lib/python3.8/site-packages/tornado/template.py new file mode 100644 index 0000000..2e6e0a2 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/template.py @@ -0,0 +1,1048 @@ +# +# Copyright 2009 Facebook +# +# 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. + +"""A simple template system that compiles templates to Python code. + +Basic usage looks like:: + + t = template.Template("<html>{{ myvalue }}</html>") + print(t.generate(myvalue="XXX")) + +`Loader` is a class that loads templates from a root directory and caches +the compiled templates:: + + loader = template.Loader("/home/btaylor") + print(loader.load("test.html").generate(myvalue="XXX")) + +We compile all templates to raw Python. Error-reporting is currently... uh, +interesting. Syntax for the templates:: + + ### base.html + <html> + <head> + <title>{% block title %}Default title{% end %}</title> + </head> + <body> + <ul> + {% for student in students %} + {% block student %} + <li>{{ escape(student.name) }}</li> + {% end %} + {% end %} + </ul> + </body> + </html> + + ### bold.html + {% extends "base.html" %} + + {% block title %}A bolder title{% end %} + + {% block student %} + <li><span style="bold">{{ escape(student.name) }}</span></li> + {% end %} + +Unlike most other template systems, we do not put any restrictions on the +expressions you can include in your statements. ``if`` and ``for`` blocks get +translated exactly into Python, so you can do complex expressions like:: + + {% for student in [p for p in people if p.student and p.age > 23] %} + <li>{{ escape(student.name) }}</li> + {% end %} + +Translating directly to Python means you can apply functions to expressions +easily, like the ``escape()`` function in the examples above. You can pass +functions in to your template just like any other variable +(In a `.RequestHandler`, override `.RequestHandler.get_template_namespace`):: + + ### Python code + def add(x, y): + return x + y + template.execute(add=add) + + ### The template + {{ add(1, 2) }} + +We provide the functions `escape() <.xhtml_escape>`, `.url_escape()`, +`.json_encode()`, and `.squeeze()` to all templates by default. + +Typical applications do not create `Template` or `Loader` instances by +hand, but instead use the `~.RequestHandler.render` and +`~.RequestHandler.render_string` methods of +`tornado.web.RequestHandler`, which load templates automatically based +on the ``template_path`` `.Application` setting. + +Variable names beginning with ``_tt_`` are reserved by the template +system and should not be used by application code. + +Syntax Reference +---------------- + +Template expressions are surrounded by double curly braces: ``{{ ... }}``. +The contents may be any python expression, which will be escaped according +to the current autoescape setting and inserted into the output. Other +template directives use ``{% %}``. + +To comment out a section so that it is omitted from the output, surround it +with ``{# ... #}``. + + +To include a literal ``{{``, ``{%``, or ``{#`` in the output, escape them as +``{{!``, ``{%!``, and ``{#!``, respectively. + + +``{% apply *function* %}...{% end %}`` + Applies a function to the output of all template code between ``apply`` + and ``end``:: + + {% apply linkify %}{{name}} said: {{message}}{% end %} + + Note that as an implementation detail apply blocks are implemented + as nested functions and thus may interact strangely with variables + set via ``{% set %}``, or the use of ``{% break %}`` or ``{% continue %}`` + within loops. + +``{% autoescape *function* %}`` + Sets the autoescape mode for the current file. This does not affect + other files, even those referenced by ``{% include %}``. Note that + autoescaping can also be configured globally, at the `.Application` + or `Loader`.:: + + {% autoescape xhtml_escape %} + {% autoescape None %} + +``{% block *name* %}...{% end %}`` + Indicates a named, replaceable block for use with ``{% extends %}``. + Blocks in the parent template will be replaced with the contents of + the same-named block in a child template.:: + + <!-- base.html --> + <title>{% block title %}Default title{% end %}</title> + + <!-- mypage.html --> + {% extends "base.html" %} + {% block title %}My page title{% end %} + +``{% comment ... %}`` + A comment which will be removed from the template output. Note that + there is no ``{% end %}`` tag; the comment goes from the word ``comment`` + to the closing ``%}`` tag. + +``{% extends *filename* %}`` + Inherit from another template. Templates that use ``extends`` should + contain one or more ``block`` tags to replace content from the parent + template. Anything in the child template not contained in a ``block`` + tag will be ignored. For an example, see the ``{% block %}`` tag. + +``{% for *var* in *expr* %}...{% end %}`` + Same as the python ``for`` statement. ``{% break %}`` and + ``{% continue %}`` may be used inside the loop. + +``{% from *x* import *y* %}`` + Same as the python ``import`` statement. + +``{% if *condition* %}...{% elif *condition* %}...{% else %}...{% end %}`` + Conditional statement - outputs the first section whose condition is + true. (The ``elif`` and ``else`` sections are optional) + +``{% import *module* %}`` + Same as the python ``import`` statement. + +``{% include *filename* %}`` + Includes another template file. The included file can see all the local + variables as if it were copied directly to the point of the ``include`` + directive (the ``{% autoescape %}`` directive is an exception). + Alternately, ``{% module Template(filename, **kwargs) %}`` may be used + to include another template with an isolated namespace. + +``{% module *expr* %}`` + Renders a `~tornado.web.UIModule`. The output of the ``UIModule`` is + not escaped:: + + {% module Template("foo.html", arg=42) %} + + ``UIModules`` are a feature of the `tornado.web.RequestHandler` + class (and specifically its ``render`` method) and will not work + when the template system is used on its own in other contexts. + +``{% raw *expr* %}`` + Outputs the result of the given expression without autoescaping. + +``{% set *x* = *y* %}`` + Sets a local variable. + +``{% try %}...{% except %}...{% else %}...{% finally %}...{% end %}`` + Same as the python ``try`` statement. + +``{% while *condition* %}... {% end %}`` + Same as the python ``while`` statement. ``{% break %}`` and + ``{% continue %}`` may be used inside the loop. + +``{% whitespace *mode* %}`` + Sets the whitespace mode for the remainder of the current file + (or until the next ``{% whitespace %}`` directive). See + `filter_whitespace` for available options. New in Tornado 4.3. +""" + +import datetime +from io import StringIO +import linecache +import os.path +import posixpath +import re +import threading + +from tornado import escape +from tornado.log import app_log +from tornado.util import ObjectDict, exec_in, unicode_type + +from typing import Any, Union, Callable, List, Dict, Iterable, Optional, TextIO +import typing + +if typing.TYPE_CHECKING: + from typing import Tuple, ContextManager # noqa: F401 + +_DEFAULT_AUTOESCAPE = "xhtml_escape" + + +class _UnsetMarker: + pass + + +_UNSET = _UnsetMarker() + + +def filter_whitespace(mode: str, text: str) -> str: + """Transform whitespace in ``text`` according to ``mode``. + + Available modes are: + + * ``all``: Return all whitespace unmodified. + * ``single``: Collapse consecutive whitespace with a single whitespace + character, preserving newlines. + * ``oneline``: Collapse all runs of whitespace into a single space + character, removing all newlines in the process. + + .. versionadded:: 4.3 + """ + if mode == "all": + return text + elif mode == "single": + text = re.sub(r"([\t ]+)", " ", text) + text = re.sub(r"(\s*\n\s*)", "\n", text) + return text + elif mode == "oneline": + return re.sub(r"(\s+)", " ", text) + else: + raise Exception("invalid whitespace mode %s" % mode) + + +class Template(object): + """A compiled template. + + We compile into Python from the given template_string. You can generate + the template from variables with generate(). + """ + + # note that the constructor's signature is not extracted with + # autodoc because _UNSET looks like garbage. When changing + # this signature update website/sphinx/template.rst too. + def __init__( + self, + template_string: Union[str, bytes], + name: str = "<string>", + loader: Optional["BaseLoader"] = None, + compress_whitespace: Union[bool, _UnsetMarker] = _UNSET, + autoescape: Optional[Union[str, _UnsetMarker]] = _UNSET, + whitespace: Optional[str] = None, + ) -> None: + """Construct a Template. + + :arg str template_string: the contents of the template file. + :arg str name: the filename from which the template was loaded + (used for error message). + :arg tornado.template.BaseLoader loader: the `~tornado.template.BaseLoader` responsible + for this template, used to resolve ``{% include %}`` and ``{% extend %}`` directives. + :arg bool compress_whitespace: Deprecated since Tornado 4.3. + Equivalent to ``whitespace="single"`` if true and + ``whitespace="all"`` if false. + :arg str autoescape: The name of a function in the template + namespace, or ``None`` to disable escaping by default. + :arg str whitespace: A string specifying treatment of whitespace; + see `filter_whitespace` for options. + + .. versionchanged:: 4.3 + Added ``whitespace`` parameter; deprecated ``compress_whitespace``. + """ + self.name = escape.native_str(name) + + if compress_whitespace is not _UNSET: + # Convert deprecated compress_whitespace (bool) to whitespace (str). + if whitespace is not None: + raise Exception("cannot set both whitespace and compress_whitespace") + whitespace = "single" if compress_whitespace else "all" + if whitespace is None: + if loader and loader.whitespace: + whitespace = loader.whitespace + else: + # Whitespace defaults by filename. + if name.endswith(".html") or name.endswith(".js"): + whitespace = "single" + else: + whitespace = "all" + # Validate the whitespace setting. + assert whitespace is not None + filter_whitespace(whitespace, "") + + if not isinstance(autoescape, _UnsetMarker): + self.autoescape = autoescape # type: Optional[str] + elif loader: + self.autoescape = loader.autoescape + else: + self.autoescape = _DEFAULT_AUTOESCAPE + + self.namespace = loader.namespace if loader else {} + reader = _TemplateReader(name, escape.native_str(template_string), whitespace) + self.file = _File(self, _parse(reader, self)) + self.code = self._generate_python(loader) + self.loader = loader + try: + # Under python2.5, the fake filename used here must match + # the module name used in __name__ below. + # The dont_inherit flag prevents template.py's future imports + # from being applied to the generated code. + self.compiled = compile( + escape.to_unicode(self.code), + "%s.generated.py" % self.name.replace(".", "_"), + "exec", + dont_inherit=True, + ) + except Exception: + formatted_code = _format_code(self.code).rstrip() + app_log.error("%s code:\n%s", self.name, formatted_code) + raise + + def generate(self, **kwargs: Any) -> bytes: + """Generate this template with the given arguments.""" + namespace = { + "escape": escape.xhtml_escape, + "xhtml_escape": escape.xhtml_escape, + "url_escape": escape.url_escape, + "json_encode": escape.json_encode, + "squeeze": escape.squeeze, + "linkify": escape.linkify, + "datetime": datetime, + "_tt_utf8": escape.utf8, # for internal use + "_tt_string_types": (unicode_type, bytes), + # __name__ and __loader__ allow the traceback mechanism to find + # the generated source code. + "__name__": self.name.replace(".", "_"), + "__loader__": ObjectDict(get_source=lambda name: self.code), + } + namespace.update(self.namespace) + namespace.update(kwargs) + exec_in(self.compiled, namespace) + execute = typing.cast(Callable[[], bytes], namespace["_tt_execute"]) + # Clear the traceback module's cache of source data now that + # we've generated a new template (mainly for this module's + # unittests, where different tests reuse the same name). + linecache.clearcache() + return execute() + + def _generate_python(self, loader: Optional["BaseLoader"]) -> str: + buffer = StringIO() + try: + # named_blocks maps from names to _NamedBlock objects + named_blocks = {} # type: Dict[str, _NamedBlock] + ancestors = self._get_ancestors(loader) + ancestors.reverse() + for ancestor in ancestors: + ancestor.find_named_blocks(loader, named_blocks) + writer = _CodeWriter(buffer, named_blocks, loader, ancestors[0].template) + ancestors[0].generate(writer) + return buffer.getvalue() + finally: + buffer.close() + + def _get_ancestors(self, loader: Optional["BaseLoader"]) -> List["_File"]: + ancestors = [self.file] + for chunk in self.file.body.chunks: + if isinstance(chunk, _ExtendsBlock): + if not loader: + raise ParseError( + "{% extends %} block found, but no " "template loader" + ) + template = loader.load(chunk.name, self.name) + ancestors.extend(template._get_ancestors(loader)) + return ancestors + + +class BaseLoader(object): + """Base class for template loaders. + + You must use a template loader to use template constructs like + ``{% extends %}`` and ``{% include %}``. The loader caches all + templates after they are loaded the first time. + """ + + def __init__( + self, + autoescape: str = _DEFAULT_AUTOESCAPE, + namespace: Optional[Dict[str, Any]] = None, + whitespace: Optional[str] = None, + ) -> None: + """Construct a template loader. + + :arg str autoescape: The name of a function in the template + namespace, such as "xhtml_escape", or ``None`` to disable + autoescaping by default. + :arg dict namespace: A dictionary to be added to the default template + namespace, or ``None``. + :arg str whitespace: A string specifying default behavior for + whitespace in templates; see `filter_whitespace` for options. + Default is "single" for files ending in ".html" and ".js" and + "all" for other files. + + .. versionchanged:: 4.3 + Added ``whitespace`` parameter. + """ + self.autoescape = autoescape + self.namespace = namespace or {} + self.whitespace = whitespace + self.templates = {} # type: Dict[str, Template] + # self.lock protects self.templates. It's a reentrant lock + # because templates may load other templates via `include` or + # `extends`. Note that thanks to the GIL this code would be safe + # even without the lock, but could lead to wasted work as multiple + # threads tried to compile the same template simultaneously. + self.lock = threading.RLock() + + def reset(self) -> None: + """Resets the cache of compiled templates.""" + with self.lock: + self.templates = {} + + def resolve_path(self, name: str, parent_path: Optional[str] = None) -> str: + """Converts a possibly-relative path to absolute (used internally).""" + raise NotImplementedError() + + def load(self, name: str, parent_path: Optional[str] = None) -> Template: + """Loads a template.""" + name = self.resolve_path(name, parent_path=parent_path) + with self.lock: + if name not in self.templates: + self.templates[name] = self._create_template(name) + return self.templates[name] + + def _create_template(self, name: str) -> Template: + raise NotImplementedError() + + +class Loader(BaseLoader): + """A template loader that loads from a single root directory. + """ + + def __init__(self, root_directory: str, **kwargs: Any) -> None: + super().__init__(**kwargs) + self.root = os.path.abspath(root_directory) + + def resolve_path(self, name: str, parent_path: Optional[str] = None) -> str: + if ( + parent_path + and not parent_path.startswith("<") + and not parent_path.startswith("/") + and not name.startswith("/") + ): + current_path = os.path.join(self.root, parent_path) + file_dir = os.path.dirname(os.path.abspath(current_path)) + relative_path = os.path.abspath(os.path.join(file_dir, name)) + if relative_path.startswith(self.root): + name = relative_path[len(self.root) + 1 :] + return name + + def _create_template(self, name: str) -> Template: + path = os.path.join(self.root, name) + with open(path, "rb") as f: + template = Template(f.read(), name=name, loader=self) + return template + + +class DictLoader(BaseLoader): + """A template loader that loads from a dictionary.""" + + def __init__(self, dict: Dict[str, str], **kwargs: Any) -> None: + super().__init__(**kwargs) + self.dict = dict + + def resolve_path(self, name: str, parent_path: Optional[str] = None) -> str: + if ( + parent_path + and not parent_path.startswith("<") + and not parent_path.startswith("/") + and not name.startswith("/") + ): + file_dir = posixpath.dirname(parent_path) + name = posixpath.normpath(posixpath.join(file_dir, name)) + return name + + def _create_template(self, name: str) -> Template: + return Template(self.dict[name], name=name, loader=self) + + +class _Node(object): + def each_child(self) -> Iterable["_Node"]: + return () + + def generate(self, writer: "_CodeWriter") -> None: + raise NotImplementedError() + + def find_named_blocks( + self, loader: Optional[BaseLoader], named_blocks: Dict[str, "_NamedBlock"] + ) -> None: + for child in self.each_child(): + child.find_named_blocks(loader, named_blocks) + + +class _File(_Node): + def __init__(self, template: Template, body: "_ChunkList") -> None: + self.template = template + self.body = body + self.line = 0 + + def generate(self, writer: "_CodeWriter") -> None: + writer.write_line("def _tt_execute():", self.line) + with writer.indent(): + writer.write_line("_tt_buffer = []", self.line) + writer.write_line("_tt_append = _tt_buffer.append", self.line) + self.body.generate(writer) + writer.write_line("return _tt_utf8('').join(_tt_buffer)", self.line) + + def each_child(self) -> Iterable["_Node"]: + return (self.body,) + + +class _ChunkList(_Node): + def __init__(self, chunks: List[_Node]) -> None: + self.chunks = chunks + + def generate(self, writer: "_CodeWriter") -> None: + for chunk in self.chunks: + chunk.generate(writer) + + def each_child(self) -> Iterable["_Node"]: + return self.chunks + + +class _NamedBlock(_Node): + def __init__(self, name: str, body: _Node, template: Template, line: int) -> None: + self.name = name + self.body = body + self.template = template + self.line = line + + def each_child(self) -> Iterable["_Node"]: + return (self.body,) + + def generate(self, writer: "_CodeWriter") -> None: + block = writer.named_blocks[self.name] + with writer.include(block.template, self.line): + block.body.generate(writer) + + def find_named_blocks( + self, loader: Optional[BaseLoader], named_blocks: Dict[str, "_NamedBlock"] + ) -> None: + named_blocks[self.name] = self + _Node.find_named_blocks(self, loader, named_blocks) + + +class _ExtendsBlock(_Node): + def __init__(self, name: str) -> None: + self.name = name + + +class _IncludeBlock(_Node): + def __init__(self, name: str, reader: "_TemplateReader", line: int) -> None: + self.name = name + self.template_name = reader.name + self.line = line + + def find_named_blocks( + self, loader: Optional[BaseLoader], named_blocks: Dict[str, _NamedBlock] + ) -> None: + assert loader is not None + included = loader.load(self.name, self.template_name) + included.file.find_named_blocks(loader, named_blocks) + + def generate(self, writer: "_CodeWriter") -> None: + assert writer.loader is not None + included = writer.loader.load(self.name, self.template_name) + with writer.include(included, self.line): + included.file.body.generate(writer) + + +class _ApplyBlock(_Node): + def __init__(self, method: str, line: int, body: _Node) -> None: + self.method = method + self.line = line + self.body = body + + def each_child(self) -> Iterable["_Node"]: + return (self.body,) + + def generate(self, writer: "_CodeWriter") -> None: + method_name = "_tt_apply%d" % writer.apply_counter + writer.apply_counter += 1 + writer.write_line("def %s():" % method_name, self.line) + with writer.indent(): + writer.write_line("_tt_buffer = []", self.line) + writer.write_line("_tt_append = _tt_buffer.append", self.line) + self.body.generate(writer) + writer.write_line("return _tt_utf8('').join(_tt_buffer)", self.line) + writer.write_line( + "_tt_append(_tt_utf8(%s(%s())))" % (self.method, method_name), self.line + ) + + +class _ControlBlock(_Node): + def __init__(self, statement: str, line: int, body: _Node) -> None: + self.statement = statement + self.line = line + self.body = body + + def each_child(self) -> Iterable[_Node]: + return (self.body,) + + def generate(self, writer: "_CodeWriter") -> None: + writer.write_line("%s:" % self.statement, self.line) + with writer.indent(): + self.body.generate(writer) + # Just in case the body was empty + writer.write_line("pass", self.line) + + +class _IntermediateControlBlock(_Node): + def __init__(self, statement: str, line: int) -> None: + self.statement = statement + self.line = line + + def generate(self, writer: "_CodeWriter") -> None: + # In case the previous block was empty + writer.write_line("pass", self.line) + writer.write_line("%s:" % self.statement, self.line, writer.indent_size() - 1) + + +class _Statement(_Node): + def __init__(self, statement: str, line: int) -> None: + self.statement = statement + self.line = line + + def generate(self, writer: "_CodeWriter") -> None: + writer.write_line(self.statement, self.line) + + +class _Expression(_Node): + def __init__(self, expression: str, line: int, raw: bool = False) -> None: + self.expression = expression + self.line = line + self.raw = raw + + def generate(self, writer: "_CodeWriter") -> None: + writer.write_line("_tt_tmp = %s" % self.expression, self.line) + writer.write_line( + "if isinstance(_tt_tmp, _tt_string_types):" " _tt_tmp = _tt_utf8(_tt_tmp)", + self.line, + ) + writer.write_line("else: _tt_tmp = _tt_utf8(str(_tt_tmp))", self.line) + if not self.raw and writer.current_template.autoescape is not None: + # In python3 functions like xhtml_escape return unicode, + # so we have to convert to utf8 again. + writer.write_line( + "_tt_tmp = _tt_utf8(%s(_tt_tmp))" % writer.current_template.autoescape, + self.line, + ) + writer.write_line("_tt_append(_tt_tmp)", self.line) + + +class _Module(_Expression): + def __init__(self, expression: str, line: int) -> None: + super().__init__("_tt_modules." + expression, line, raw=True) + + +class _Text(_Node): + def __init__(self, value: str, line: int, whitespace: str) -> None: + self.value = value + self.line = line + self.whitespace = whitespace + + def generate(self, writer: "_CodeWriter") -> None: + value = self.value + + # Compress whitespace if requested, with a crude heuristic to avoid + # altering preformatted whitespace. + if "<pre>" not in value: + value = filter_whitespace(self.whitespace, value) + + if value: + writer.write_line("_tt_append(%r)" % escape.utf8(value), self.line) + + +class ParseError(Exception): + """Raised for template syntax errors. + + ``ParseError`` instances have ``filename`` and ``lineno`` attributes + indicating the position of the error. + + .. versionchanged:: 4.3 + Added ``filename`` and ``lineno`` attributes. + """ + + def __init__( + self, message: str, filename: Optional[str] = None, lineno: int = 0 + ) -> None: + self.message = message + # The names "filename" and "lineno" are chosen for consistency + # with python SyntaxError. + self.filename = filename + self.lineno = lineno + + def __str__(self) -> str: + return "%s at %s:%d" % (self.message, self.filename, self.lineno) + + +class _CodeWriter(object): + def __init__( + self, + file: TextIO, + named_blocks: Dict[str, _NamedBlock], + loader: Optional[BaseLoader], + current_template: Template, + ) -> None: + self.file = file + self.named_blocks = named_blocks + self.loader = loader + self.current_template = current_template + self.apply_counter = 0 + self.include_stack = [] # type: List[Tuple[Template, int]] + self._indent = 0 + + def indent_size(self) -> int: + return self._indent + + def indent(self) -> "ContextManager": + class Indenter(object): + def __enter__(_) -> "_CodeWriter": + self._indent += 1 + return self + + def __exit__(_, *args: Any) -> None: + assert self._indent > 0 + self._indent -= 1 + + return Indenter() + + def include(self, template: Template, line: int) -> "ContextManager": + self.include_stack.append((self.current_template, line)) + self.current_template = template + + class IncludeTemplate(object): + def __enter__(_) -> "_CodeWriter": + return self + + def __exit__(_, *args: Any) -> None: + self.current_template = self.include_stack.pop()[0] + + return IncludeTemplate() + + def write_line( + self, line: str, line_number: int, indent: Optional[int] = None + ) -> None: + if indent is None: + indent = self._indent + line_comment = " # %s:%d" % (self.current_template.name, line_number) + if self.include_stack: + ancestors = [ + "%s:%d" % (tmpl.name, lineno) for (tmpl, lineno) in self.include_stack + ] + line_comment += " (via %s)" % ", ".join(reversed(ancestors)) + print(" " * indent + line + line_comment, file=self.file) + + +class _TemplateReader(object): + def __init__(self, name: str, text: str, whitespace: str) -> None: + self.name = name + self.text = text + self.whitespace = whitespace + self.line = 1 + self.pos = 0 + + def find(self, needle: str, start: int = 0, end: Optional[int] = None) -> int: + assert start >= 0, start + pos = self.pos + start += pos + if end is None: + index = self.text.find(needle, start) + else: + end += pos + assert end >= start + index = self.text.find(needle, start, end) + if index != -1: + index -= pos + return index + + def consume(self, count: Optional[int] = None) -> str: + if count is None: + count = len(self.text) - self.pos + newpos = self.pos + count + self.line += self.text.count("\n", self.pos, newpos) + s = self.text[self.pos : newpos] + self.pos = newpos + return s + + def remaining(self) -> int: + return len(self.text) - self.pos + + def __len__(self) -> int: + return self.remaining() + + def __getitem__(self, key: Union[int, slice]) -> str: + if isinstance(key, slice): + size = len(self) + start, stop, step = key.indices(size) + if start is None: + start = self.pos + else: + start += self.pos + if stop is not None: + stop += self.pos + return self.text[slice(start, stop, step)] + elif key < 0: + return self.text[key] + else: + return self.text[self.pos + key] + + def __str__(self) -> str: + return self.text[self.pos :] + + def raise_parse_error(self, msg: str) -> None: + raise ParseError(msg, self.name, self.line) + + +def _format_code(code: str) -> str: + lines = code.splitlines() + format = "%%%dd %%s\n" % len(repr(len(lines) + 1)) + return "".join([format % (i + 1, line) for (i, line) in enumerate(lines)]) + + +def _parse( + reader: _TemplateReader, + template: Template, + in_block: Optional[str] = None, + in_loop: Optional[str] = None, +) -> _ChunkList: + body = _ChunkList([]) + while True: + # Find next template directive + curly = 0 + while True: + curly = reader.find("{", curly) + if curly == -1 or curly + 1 == reader.remaining(): + # EOF + if in_block: + reader.raise_parse_error( + "Missing {%% end %%} block for %s" % in_block + ) + body.chunks.append( + _Text(reader.consume(), reader.line, reader.whitespace) + ) + return body + # If the first curly brace is not the start of a special token, + # start searching from the character after it + if reader[curly + 1] not in ("{", "%", "#"): + curly += 1 + continue + # When there are more than 2 curlies in a row, use the + # innermost ones. This is useful when generating languages + # like latex where curlies are also meaningful + if ( + curly + 2 < reader.remaining() + and reader[curly + 1] == "{" + and reader[curly + 2] == "{" + ): + curly += 1 + continue + break + + # Append any text before the special token + if curly > 0: + cons = reader.consume(curly) + body.chunks.append(_Text(cons, reader.line, reader.whitespace)) + + start_brace = reader.consume(2) + line = reader.line + + # Template directives may be escaped as "{{!" or "{%!". + # In this case output the braces and consume the "!". + # This is especially useful in conjunction with jquery templates, + # which also use double braces. + if reader.remaining() and reader[0] == "!": + reader.consume(1) + body.chunks.append(_Text(start_brace, line, reader.whitespace)) + continue + + # Comment + if start_brace == "{#": + end = reader.find("#}") + if end == -1: + reader.raise_parse_error("Missing end comment #}") + contents = reader.consume(end).strip() + reader.consume(2) + continue + + # Expression + if start_brace == "{{": + end = reader.find("}}") + if end == -1: + reader.raise_parse_error("Missing end expression }}") + contents = reader.consume(end).strip() + reader.consume(2) + if not contents: + reader.raise_parse_error("Empty expression") + body.chunks.append(_Expression(contents, line)) + continue + + # Block + assert start_brace == "{%", start_brace + end = reader.find("%}") + if end == -1: + reader.raise_parse_error("Missing end block %}") + contents = reader.consume(end).strip() + reader.consume(2) + if not contents: + reader.raise_parse_error("Empty block tag ({% %})") + + operator, space, suffix = contents.partition(" ") + suffix = suffix.strip() + + # Intermediate ("else", "elif", etc) blocks + intermediate_blocks = { + "else": set(["if", "for", "while", "try"]), + "elif": set(["if"]), + "except": set(["try"]), + "finally": set(["try"]), + } + allowed_parents = intermediate_blocks.get(operator) + if allowed_parents is not None: + if not in_block: + reader.raise_parse_error( + "%s outside %s block" % (operator, allowed_parents) + ) + if in_block not in allowed_parents: + reader.raise_parse_error( + "%s block cannot be attached to %s block" % (operator, in_block) + ) + body.chunks.append(_IntermediateControlBlock(contents, line)) + continue + + # End tag + elif operator == "end": + if not in_block: + reader.raise_parse_error("Extra {% end %} block") + return body + + elif operator in ( + "extends", + "include", + "set", + "import", + "from", + "comment", + "autoescape", + "whitespace", + "raw", + "module", + ): + if operator == "comment": + continue + if operator == "extends": + suffix = suffix.strip('"').strip("'") + if not suffix: + reader.raise_parse_error("extends missing file path") + block = _ExtendsBlock(suffix) # type: _Node + elif operator in ("import", "from"): + if not suffix: + reader.raise_parse_error("import missing statement") + block = _Statement(contents, line) + elif operator == "include": + suffix = suffix.strip('"').strip("'") + if not suffix: + reader.raise_parse_error("include missing file path") + block = _IncludeBlock(suffix, reader, line) + elif operator == "set": + if not suffix: + reader.raise_parse_error("set missing statement") + block = _Statement(suffix, line) + elif operator == "autoescape": + fn = suffix.strip() # type: Optional[str] + if fn == "None": + fn = None + template.autoescape = fn + continue + elif operator == "whitespace": + mode = suffix.strip() + # Validate the selected mode + filter_whitespace(mode, "") + reader.whitespace = mode + continue + elif operator == "raw": + block = _Expression(suffix, line, raw=True) + elif operator == "module": + block = _Module(suffix, line) + body.chunks.append(block) + continue + + elif operator in ("apply", "block", "try", "if", "for", "while"): + # parse inner body recursively + if operator in ("for", "while"): + block_body = _parse(reader, template, operator, operator) + elif operator == "apply": + # apply creates a nested function so syntactically it's not + # in the loop. + block_body = _parse(reader, template, operator, None) + else: + block_body = _parse(reader, template, operator, in_loop) + + if operator == "apply": + if not suffix: + reader.raise_parse_error("apply missing method name") + block = _ApplyBlock(suffix, line, block_body) + elif operator == "block": + if not suffix: + reader.raise_parse_error("block missing name") + block = _NamedBlock(suffix, block_body, template, line) + else: + block = _ControlBlock(contents, line, block_body) + body.chunks.append(block) + continue + + elif operator in ("break", "continue"): + if not in_loop: + reader.raise_parse_error( + "%s outside %s block" % (operator, set(["for", "while"])) + ) + body.chunks.append(_Statement(contents, line)) + continue + + else: + reader.raise_parse_error("unknown operator: %r" % operator) diff --git a/venv/lib/python3.8/site-packages/tornado/test/__main__.py b/venv/lib/python3.8/site-packages/tornado/test/__main__.py new file mode 100644 index 0000000..430c895 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/__main__.py @@ -0,0 +1,12 @@ +"""Shim to allow python -m tornado.test. + +This only works in python 2.7+. +""" +from tornado.test.runtests import all, main + +# tornado.testing.main autodiscovery relies on 'all' being present in +# the main module, so import it here even though it is not used directly. +# The following line prevents a pyflakes warning. +all = all + +main() diff --git a/venv/lib/python3.8/site-packages/tornado/test/asyncio_test.py b/venv/lib/python3.8/site-packages/tornado/test/asyncio_test.py new file mode 100644 index 0000000..3f9f338 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/asyncio_test.py @@ -0,0 +1,190 @@ +# 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. + +import asyncio +import unittest + +from concurrent.futures import ThreadPoolExecutor +from tornado import gen +from tornado.ioloop import IOLoop +from tornado.platform.asyncio import ( + AsyncIOLoop, + to_asyncio_future, + AnyThreadEventLoopPolicy, +) +from tornado.testing import AsyncTestCase, gen_test + + +class AsyncIOLoopTest(AsyncTestCase): + def get_new_ioloop(self): + io_loop = AsyncIOLoop() + return io_loop + + def test_asyncio_callback(self): + # Basic test that the asyncio loop is set up correctly. + asyncio.get_event_loop().call_soon(self.stop) + self.wait() + + @gen_test + def test_asyncio_future(self): + # Test that we can yield an asyncio future from a tornado coroutine. + # Without 'yield from', we must wrap coroutines in ensure_future, + # which was introduced during Python 3.4, deprecating the prior "async". + if hasattr(asyncio, "ensure_future"): + ensure_future = asyncio.ensure_future + else: + # async is a reserved word in Python 3.7 + ensure_future = getattr(asyncio, "async") + + x = yield ensure_future( + asyncio.get_event_loop().run_in_executor(None, lambda: 42) + ) + self.assertEqual(x, 42) + + @gen_test + def test_asyncio_yield_from(self): + @gen.coroutine + def f(): + event_loop = asyncio.get_event_loop() + x = yield from event_loop.run_in_executor(None, lambda: 42) + return x + + result = yield f() + self.assertEqual(result, 42) + + def test_asyncio_adapter(self): + # This test demonstrates that when using the asyncio coroutine + # runner (i.e. run_until_complete), the to_asyncio_future + # adapter is needed. No adapter is needed in the other direction, + # as demonstrated by other tests in the package. + @gen.coroutine + def tornado_coroutine(): + yield gen.moment + raise gen.Return(42) + + async def native_coroutine_without_adapter(): + return await tornado_coroutine() + + async def native_coroutine_with_adapter(): + return await to_asyncio_future(tornado_coroutine()) + + # Use the adapter, but two degrees from the tornado coroutine. + async def native_coroutine_with_adapter2(): + return await to_asyncio_future(native_coroutine_without_adapter()) + + # Tornado supports native coroutines both with and without adapters + self.assertEqual(self.io_loop.run_sync(native_coroutine_without_adapter), 42) + self.assertEqual(self.io_loop.run_sync(native_coroutine_with_adapter), 42) + self.assertEqual(self.io_loop.run_sync(native_coroutine_with_adapter2), 42) + + # Asyncio only supports coroutines that yield asyncio-compatible + # Futures (which our Future is since 5.0). + self.assertEqual( + asyncio.get_event_loop().run_until_complete( + native_coroutine_without_adapter() + ), + 42, + ) + self.assertEqual( + asyncio.get_event_loop().run_until_complete( + native_coroutine_with_adapter() + ), + 42, + ) + self.assertEqual( + asyncio.get_event_loop().run_until_complete( + native_coroutine_with_adapter2() + ), + 42, + ) + + +class LeakTest(unittest.TestCase): + def setUp(self): + # Trigger a cleanup of the mapping so we start with a clean slate. + AsyncIOLoop().close() + # If we don't clean up after ourselves other tests may fail on + # py34. + self.orig_policy = asyncio.get_event_loop_policy() + asyncio.set_event_loop_policy(asyncio.DefaultEventLoopPolicy()) + + def tearDown(self): + asyncio.get_event_loop().close() + asyncio.set_event_loop_policy(self.orig_policy) + + def test_ioloop_close_leak(self): + orig_count = len(IOLoop._ioloop_for_asyncio) + for i in range(10): + # Create and close an AsyncIOLoop using Tornado interfaces. + loop = AsyncIOLoop() + loop.close() + new_count = len(IOLoop._ioloop_for_asyncio) - orig_count + self.assertEqual(new_count, 0) + + def test_asyncio_close_leak(self): + orig_count = len(IOLoop._ioloop_for_asyncio) + for i in range(10): + # Create and close an AsyncIOMainLoop using asyncio interfaces. + loop = asyncio.new_event_loop() + loop.call_soon(IOLoop.current) + loop.call_soon(loop.stop) + loop.run_forever() + loop.close() + new_count = len(IOLoop._ioloop_for_asyncio) - orig_count + # Because the cleanup is run on new loop creation, we have one + # dangling entry in the map (but only one). + self.assertEqual(new_count, 1) + + +class AnyThreadEventLoopPolicyTest(unittest.TestCase): + def setUp(self): + self.orig_policy = asyncio.get_event_loop_policy() + self.executor = ThreadPoolExecutor(1) + + def tearDown(self): + asyncio.set_event_loop_policy(self.orig_policy) + self.executor.shutdown() + + def get_event_loop_on_thread(self): + def get_and_close_event_loop(): + """Get the event loop. Close it if one is returned. + + Returns the (closed) event loop. This is a silly thing + to do and leaves the thread in a broken state, but it's + enough for this test. Closing the loop avoids resource + leak warnings. + """ + loop = asyncio.get_event_loop() + loop.close() + return loop + + future = self.executor.submit(get_and_close_event_loop) + return future.result() + + def run_policy_test(self, accessor, expected_type): + # With the default policy, non-main threads don't get an event + # loop. + self.assertRaises( + (RuntimeError, AssertionError), self.executor.submit(accessor).result + ) + # Set the policy and we can get a loop. + asyncio.set_event_loop_policy(AnyThreadEventLoopPolicy()) + self.assertIsInstance(self.executor.submit(accessor).result(), expected_type) + # Clean up to silence leak warnings. Always use asyncio since + # IOLoop doesn't (currently) close the underlying loop. + self.executor.submit(lambda: asyncio.get_event_loop().close()).result() # type: ignore + + def test_asyncio_accessor(self): + self.run_policy_test(asyncio.get_event_loop, asyncio.AbstractEventLoop) + + def test_tornado_accessor(self): + self.run_policy_test(IOLoop.current, IOLoop) diff --git a/venv/lib/python3.8/site-packages/tornado/test/auth_test.py b/venv/lib/python3.8/site-packages/tornado/test/auth_test.py new file mode 100644 index 0000000..8de863e --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/auth_test.py @@ -0,0 +1,609 @@ +# These tests do not currently do much to verify the correct implementation +# of the openid/oauth protocols, they just exercise the major code paths +# and ensure that it doesn't blow up (e.g. with unicode/bytes issues in +# python 3) + +import unittest + +from tornado.auth import ( + OpenIdMixin, + OAuthMixin, + OAuth2Mixin, + GoogleOAuth2Mixin, + FacebookGraphMixin, + TwitterMixin, +) +from tornado.escape import json_decode +from tornado import gen +from tornado.httpclient import HTTPClientError +from tornado.httputil import url_concat +from tornado.log import app_log +from tornado.testing import AsyncHTTPTestCase, ExpectLog +from tornado.web import RequestHandler, Application, HTTPError + +try: + from unittest import mock +except ImportError: + mock = None # type: ignore + + +class OpenIdClientLoginHandler(RequestHandler, OpenIdMixin): + def initialize(self, test): + self._OPENID_ENDPOINT = test.get_url("/openid/server/authenticate") + + @gen.coroutine + def get(self): + if self.get_argument("openid.mode", None): + user = yield self.get_authenticated_user( + http_client=self.settings["http_client"] + ) + if user is None: + raise Exception("user is None") + self.finish(user) + return + res = self.authenticate_redirect() # type: ignore + assert res is None + + +class OpenIdServerAuthenticateHandler(RequestHandler): + def post(self): + if self.get_argument("openid.mode") != "check_authentication": + raise Exception("incorrect openid.mode %r") + self.write("is_valid:true") + + +class OAuth1ClientLoginHandler(RequestHandler, OAuthMixin): + def initialize(self, test, version): + self._OAUTH_VERSION = version + self._OAUTH_REQUEST_TOKEN_URL = test.get_url("/oauth1/server/request_token") + self._OAUTH_AUTHORIZE_URL = test.get_url("/oauth1/server/authorize") + self._OAUTH_ACCESS_TOKEN_URL = test.get_url("/oauth1/server/access_token") + + def _oauth_consumer_token(self): + return dict(key="asdf", secret="qwer") + + @gen.coroutine + def get(self): + if self.get_argument("oauth_token", None): + user = yield self.get_authenticated_user( + http_client=self.settings["http_client"] + ) + if user is None: + raise Exception("user is None") + self.finish(user) + return + yield self.authorize_redirect(http_client=self.settings["http_client"]) + + @gen.coroutine + def _oauth_get_user_future(self, access_token): + if self.get_argument("fail_in_get_user", None): + raise Exception("failing in get_user") + if access_token != dict(key="uiop", secret="5678"): + raise Exception("incorrect access token %r" % access_token) + return dict(email="foo@example.com") + + +class OAuth1ClientLoginCoroutineHandler(OAuth1ClientLoginHandler): + """Replaces OAuth1ClientLoginCoroutineHandler's get() with a coroutine.""" + + @gen.coroutine + def get(self): + if self.get_argument("oauth_token", None): + # Ensure that any exceptions are set on the returned Future, + # not simply thrown into the surrounding StackContext. + try: + yield self.get_authenticated_user() + except Exception as e: + self.set_status(503) + self.write("got exception: %s" % e) + else: + yield self.authorize_redirect() + + +class OAuth1ClientRequestParametersHandler(RequestHandler, OAuthMixin): + def initialize(self, version): + self._OAUTH_VERSION = version + + def _oauth_consumer_token(self): + return dict(key="asdf", secret="qwer") + + def get(self): + params = self._oauth_request_parameters( + "http://www.example.com/api/asdf", + dict(key="uiop", secret="5678"), + parameters=dict(foo="bar"), + ) + self.write(params) + + +class OAuth1ServerRequestTokenHandler(RequestHandler): + def get(self): + self.write("oauth_token=zxcv&oauth_token_secret=1234") + + +class OAuth1ServerAccessTokenHandler(RequestHandler): + def get(self): + self.write("oauth_token=uiop&oauth_token_secret=5678") + + +class OAuth2ClientLoginHandler(RequestHandler, OAuth2Mixin): + def initialize(self, test): + self._OAUTH_AUTHORIZE_URL = test.get_url("/oauth2/server/authorize") + + def get(self): + res = self.authorize_redirect() # type: ignore + assert res is None + + +class FacebookClientLoginHandler(RequestHandler, FacebookGraphMixin): + def initialize(self, test): + self._OAUTH_AUTHORIZE_URL = test.get_url("/facebook/server/authorize") + self._OAUTH_ACCESS_TOKEN_URL = test.get_url("/facebook/server/access_token") + self._FACEBOOK_BASE_URL = test.get_url("/facebook/server") + + @gen.coroutine + def get(self): + if self.get_argument("code", None): + user = yield self.get_authenticated_user( + redirect_uri=self.request.full_url(), + client_id=self.settings["facebook_api_key"], + client_secret=self.settings["facebook_secret"], + code=self.get_argument("code"), + ) + self.write(user) + else: + self.authorize_redirect( + redirect_uri=self.request.full_url(), + client_id=self.settings["facebook_api_key"], + extra_params={"scope": "read_stream,offline_access"}, + ) + + +class FacebookServerAccessTokenHandler(RequestHandler): + def get(self): + self.write(dict(access_token="asdf", expires_in=3600)) + + +class FacebookServerMeHandler(RequestHandler): + def get(self): + self.write("{}") + + +class TwitterClientHandler(RequestHandler, TwitterMixin): + def initialize(self, test): + self._OAUTH_REQUEST_TOKEN_URL = test.get_url("/oauth1/server/request_token") + self._OAUTH_ACCESS_TOKEN_URL = test.get_url("/twitter/server/access_token") + self._OAUTH_AUTHORIZE_URL = test.get_url("/oauth1/server/authorize") + self._OAUTH_AUTHENTICATE_URL = test.get_url("/twitter/server/authenticate") + self._TWITTER_BASE_URL = test.get_url("/twitter/api") + + def get_auth_http_client(self): + return self.settings["http_client"] + + +class TwitterClientLoginHandler(TwitterClientHandler): + @gen.coroutine + def get(self): + if self.get_argument("oauth_token", None): + user = yield self.get_authenticated_user() + if user is None: + raise Exception("user is None") + self.finish(user) + return + yield self.authorize_redirect() + + +class TwitterClientAuthenticateHandler(TwitterClientHandler): + # Like TwitterClientLoginHandler, but uses authenticate_redirect + # instead of authorize_redirect. + @gen.coroutine + def get(self): + if self.get_argument("oauth_token", None): + user = yield self.get_authenticated_user() + if user is None: + raise Exception("user is None") + self.finish(user) + return + yield self.authenticate_redirect() + + +class TwitterClientLoginGenCoroutineHandler(TwitterClientHandler): + @gen.coroutine + def get(self): + if self.get_argument("oauth_token", None): + user = yield self.get_authenticated_user() + self.finish(user) + else: + # New style: with @gen.coroutine the result must be yielded + # or else the request will be auto-finished too soon. + yield self.authorize_redirect() + + +class TwitterClientShowUserHandler(TwitterClientHandler): + @gen.coroutine + def get(self): + # TODO: would be nice to go through the login flow instead of + # cheating with a hard-coded access token. + try: + response = yield self.twitter_request( + "/users/show/%s" % self.get_argument("name"), + access_token=dict(key="hjkl", secret="vbnm"), + ) + except HTTPClientError: + # TODO(bdarnell): Should we catch HTTP errors and + # transform some of them (like 403s) into AuthError? + self.set_status(500) + self.finish("error from twitter request") + else: + self.finish(response) + + +class TwitterServerAccessTokenHandler(RequestHandler): + def get(self): + self.write("oauth_token=hjkl&oauth_token_secret=vbnm&screen_name=foo") + + +class TwitterServerShowUserHandler(RequestHandler): + def get(self, screen_name): + if screen_name == "error": + raise HTTPError(500) + assert "oauth_nonce" in self.request.arguments + assert "oauth_timestamp" in self.request.arguments + assert "oauth_signature" in self.request.arguments + assert self.get_argument("oauth_consumer_key") == "test_twitter_consumer_key" + assert self.get_argument("oauth_signature_method") == "HMAC-SHA1" + assert self.get_argument("oauth_version") == "1.0" + assert self.get_argument("oauth_token") == "hjkl" + self.write(dict(screen_name=screen_name, name=screen_name.capitalize())) + + +class TwitterServerVerifyCredentialsHandler(RequestHandler): + def get(self): + assert "oauth_nonce" in self.request.arguments + assert "oauth_timestamp" in self.request.arguments + assert "oauth_signature" in self.request.arguments + assert self.get_argument("oauth_consumer_key") == "test_twitter_consumer_key" + assert self.get_argument("oauth_signature_method") == "HMAC-SHA1" + assert self.get_argument("oauth_version") == "1.0" + assert self.get_argument("oauth_token") == "hjkl" + self.write(dict(screen_name="foo", name="Foo")) + + +class AuthTest(AsyncHTTPTestCase): + def get_app(self): + return Application( + [ + # test endpoints + ("/openid/client/login", OpenIdClientLoginHandler, dict(test=self)), + ( + "/oauth10/client/login", + OAuth1ClientLoginHandler, + dict(test=self, version="1.0"), + ), + ( + "/oauth10/client/request_params", + OAuth1ClientRequestParametersHandler, + dict(version="1.0"), + ), + ( + "/oauth10a/client/login", + OAuth1ClientLoginHandler, + dict(test=self, version="1.0a"), + ), + ( + "/oauth10a/client/login_coroutine", + OAuth1ClientLoginCoroutineHandler, + dict(test=self, version="1.0a"), + ), + ( + "/oauth10a/client/request_params", + OAuth1ClientRequestParametersHandler, + dict(version="1.0a"), + ), + ("/oauth2/client/login", OAuth2ClientLoginHandler, dict(test=self)), + ("/facebook/client/login", FacebookClientLoginHandler, dict(test=self)), + ("/twitter/client/login", TwitterClientLoginHandler, dict(test=self)), + ( + "/twitter/client/authenticate", + TwitterClientAuthenticateHandler, + dict(test=self), + ), + ( + "/twitter/client/login_gen_coroutine", + TwitterClientLoginGenCoroutineHandler, + dict(test=self), + ), + ( + "/twitter/client/show_user", + TwitterClientShowUserHandler, + dict(test=self), + ), + # simulated servers + ("/openid/server/authenticate", OpenIdServerAuthenticateHandler), + ("/oauth1/server/request_token", OAuth1ServerRequestTokenHandler), + ("/oauth1/server/access_token", OAuth1ServerAccessTokenHandler), + ("/facebook/server/access_token", FacebookServerAccessTokenHandler), + ("/facebook/server/me", FacebookServerMeHandler), + ("/twitter/server/access_token", TwitterServerAccessTokenHandler), + (r"/twitter/api/users/show/(.*)\.json", TwitterServerShowUserHandler), + ( + r"/twitter/api/account/verify_credentials\.json", + TwitterServerVerifyCredentialsHandler, + ), + ], + http_client=self.http_client, + twitter_consumer_key="test_twitter_consumer_key", + twitter_consumer_secret="test_twitter_consumer_secret", + facebook_api_key="test_facebook_api_key", + facebook_secret="test_facebook_secret", + ) + + def test_openid_redirect(self): + response = self.fetch("/openid/client/login", follow_redirects=False) + self.assertEqual(response.code, 302) + self.assertTrue("/openid/server/authenticate?" in response.headers["Location"]) + + def test_openid_get_user(self): + response = self.fetch( + "/openid/client/login?openid.mode=blah" + "&openid.ns.ax=http://openid.net/srv/ax/1.0" + "&openid.ax.type.email=http://axschema.org/contact/email" + "&openid.ax.value.email=foo@example.com" + ) + response.rethrow() + parsed = json_decode(response.body) + self.assertEqual(parsed["email"], "foo@example.com") + + def test_oauth10_redirect(self): + response = self.fetch("/oauth10/client/login", follow_redirects=False) + self.assertEqual(response.code, 302) + self.assertTrue( + response.headers["Location"].endswith( + "/oauth1/server/authorize?oauth_token=zxcv" + ) + ) + # the cookie is base64('zxcv')|base64('1234') + self.assertTrue( + '_oauth_request_token="enhjdg==|MTIzNA=="' + in response.headers["Set-Cookie"], + response.headers["Set-Cookie"], + ) + + def test_oauth10_get_user(self): + response = self.fetch( + "/oauth10/client/login?oauth_token=zxcv", + headers={"Cookie": "_oauth_request_token=enhjdg==|MTIzNA=="}, + ) + response.rethrow() + parsed = json_decode(response.body) + self.assertEqual(parsed["email"], "foo@example.com") + self.assertEqual(parsed["access_token"], dict(key="uiop", secret="5678")) + + def test_oauth10_request_parameters(self): + response = self.fetch("/oauth10/client/request_params") + response.rethrow() + parsed = json_decode(response.body) + self.assertEqual(parsed["oauth_consumer_key"], "asdf") + self.assertEqual(parsed["oauth_token"], "uiop") + self.assertTrue("oauth_nonce" in parsed) + self.assertTrue("oauth_signature" in parsed) + + def test_oauth10a_redirect(self): + response = self.fetch("/oauth10a/client/login", follow_redirects=False) + self.assertEqual(response.code, 302) + self.assertTrue( + response.headers["Location"].endswith( + "/oauth1/server/authorize?oauth_token=zxcv" + ) + ) + # the cookie is base64('zxcv')|base64('1234') + self.assertTrue( + '_oauth_request_token="enhjdg==|MTIzNA=="' + in response.headers["Set-Cookie"], + response.headers["Set-Cookie"], + ) + + @unittest.skipIf(mock is None, "mock package not present") + def test_oauth10a_redirect_error(self): + with mock.patch.object(OAuth1ServerRequestTokenHandler, "get") as get: + get.side_effect = Exception("boom") + with ExpectLog(app_log, "Uncaught exception"): + response = self.fetch("/oauth10a/client/login", follow_redirects=False) + self.assertEqual(response.code, 500) + + def test_oauth10a_get_user(self): + response = self.fetch( + "/oauth10a/client/login?oauth_token=zxcv", + headers={"Cookie": "_oauth_request_token=enhjdg==|MTIzNA=="}, + ) + response.rethrow() + parsed = json_decode(response.body) + self.assertEqual(parsed["email"], "foo@example.com") + self.assertEqual(parsed["access_token"], dict(key="uiop", secret="5678")) + + def test_oauth10a_request_parameters(self): + response = self.fetch("/oauth10a/client/request_params") + response.rethrow() + parsed = json_decode(response.body) + self.assertEqual(parsed["oauth_consumer_key"], "asdf") + self.assertEqual(parsed["oauth_token"], "uiop") + self.assertTrue("oauth_nonce" in parsed) + self.assertTrue("oauth_signature" in parsed) + + def test_oauth10a_get_user_coroutine_exception(self): + response = self.fetch( + "/oauth10a/client/login_coroutine?oauth_token=zxcv&fail_in_get_user=true", + headers={"Cookie": "_oauth_request_token=enhjdg==|MTIzNA=="}, + ) + self.assertEqual(response.code, 503) + + def test_oauth2_redirect(self): + response = self.fetch("/oauth2/client/login", follow_redirects=False) + self.assertEqual(response.code, 302) + self.assertTrue("/oauth2/server/authorize?" in response.headers["Location"]) + + def test_facebook_login(self): + response = self.fetch("/facebook/client/login", follow_redirects=False) + self.assertEqual(response.code, 302) + self.assertTrue("/facebook/server/authorize?" in response.headers["Location"]) + response = self.fetch( + "/facebook/client/login?code=1234", follow_redirects=False + ) + self.assertEqual(response.code, 200) + user = json_decode(response.body) + self.assertEqual(user["access_token"], "asdf") + self.assertEqual(user["session_expires"], "3600") + + def base_twitter_redirect(self, url): + # Same as test_oauth10a_redirect + response = self.fetch(url, follow_redirects=False) + self.assertEqual(response.code, 302) + self.assertTrue( + response.headers["Location"].endswith( + "/oauth1/server/authorize?oauth_token=zxcv" + ) + ) + # the cookie is base64('zxcv')|base64('1234') + self.assertTrue( + '_oauth_request_token="enhjdg==|MTIzNA=="' + in response.headers["Set-Cookie"], + response.headers["Set-Cookie"], + ) + + def test_twitter_redirect(self): + self.base_twitter_redirect("/twitter/client/login") + + def test_twitter_redirect_gen_coroutine(self): + self.base_twitter_redirect("/twitter/client/login_gen_coroutine") + + def test_twitter_authenticate_redirect(self): + response = self.fetch("/twitter/client/authenticate", follow_redirects=False) + self.assertEqual(response.code, 302) + self.assertTrue( + response.headers["Location"].endswith( + "/twitter/server/authenticate?oauth_token=zxcv" + ), + response.headers["Location"], + ) + # the cookie is base64('zxcv')|base64('1234') + self.assertTrue( + '_oauth_request_token="enhjdg==|MTIzNA=="' + in response.headers["Set-Cookie"], + response.headers["Set-Cookie"], + ) + + def test_twitter_get_user(self): + response = self.fetch( + "/twitter/client/login?oauth_token=zxcv", + headers={"Cookie": "_oauth_request_token=enhjdg==|MTIzNA=="}, + ) + response.rethrow() + parsed = json_decode(response.body) + self.assertEqual( + parsed, + { + u"access_token": { + u"key": u"hjkl", + u"screen_name": u"foo", + u"secret": u"vbnm", + }, + u"name": u"Foo", + u"screen_name": u"foo", + u"username": u"foo", + }, + ) + + def test_twitter_show_user(self): + response = self.fetch("/twitter/client/show_user?name=somebody") + response.rethrow() + self.assertEqual( + json_decode(response.body), {"name": "Somebody", "screen_name": "somebody"} + ) + + def test_twitter_show_user_error(self): + response = self.fetch("/twitter/client/show_user?name=error") + self.assertEqual(response.code, 500) + self.assertEqual(response.body, b"error from twitter request") + + +class GoogleLoginHandler(RequestHandler, GoogleOAuth2Mixin): + def initialize(self, test): + self.test = test + self._OAUTH_REDIRECT_URI = test.get_url("/client/login") + self._OAUTH_AUTHORIZE_URL = test.get_url("/google/oauth2/authorize") + self._OAUTH_ACCESS_TOKEN_URL = test.get_url("/google/oauth2/token") + + @gen.coroutine + def get(self): + code = self.get_argument("code", None) + if code is not None: + # retrieve authenticate google user + access = yield self.get_authenticated_user(self._OAUTH_REDIRECT_URI, code) + user = yield self.oauth2_request( + self.test.get_url("/google/oauth2/userinfo"), + access_token=access["access_token"], + ) + # return the user and access token as json + user["access_token"] = access["access_token"] + self.write(user) + else: + self.authorize_redirect( + redirect_uri=self._OAUTH_REDIRECT_URI, + client_id=self.settings["google_oauth"]["key"], + client_secret=self.settings["google_oauth"]["secret"], + scope=["profile", "email"], + response_type="code", + extra_params={"prompt": "select_account"}, + ) + + +class GoogleOAuth2AuthorizeHandler(RequestHandler): + def get(self): + # issue a fake auth code and redirect to redirect_uri + code = "fake-authorization-code" + self.redirect(url_concat(self.get_argument("redirect_uri"), dict(code=code))) + + +class GoogleOAuth2TokenHandler(RequestHandler): + def post(self): + assert self.get_argument("code") == "fake-authorization-code" + # issue a fake token + self.finish( + {"access_token": "fake-access-token", "expires_in": "never-expires"} + ) + + +class GoogleOAuth2UserinfoHandler(RequestHandler): + def get(self): + assert self.get_argument("access_token") == "fake-access-token" + # return a fake user + self.finish({"name": "Foo", "email": "foo@example.com"}) + + +class GoogleOAuth2Test(AsyncHTTPTestCase): + def get_app(self): + return Application( + [ + # test endpoints + ("/client/login", GoogleLoginHandler, dict(test=self)), + # simulated google authorization server endpoints + ("/google/oauth2/authorize", GoogleOAuth2AuthorizeHandler), + ("/google/oauth2/token", GoogleOAuth2TokenHandler), + ("/google/oauth2/userinfo", GoogleOAuth2UserinfoHandler), + ], + google_oauth={ + "key": "fake_google_client_id", + "secret": "fake_google_client_secret", + }, + ) + + def test_google_login(self): + response = self.fetch("/client/login") + self.assertDictEqual( + { + u"name": u"Foo", + u"email": u"foo@example.com", + u"access_token": u"fake-access-token", + }, + json_decode(response.body), + ) diff --git a/venv/lib/python3.8/site-packages/tornado/test/autoreload_test.py b/venv/lib/python3.8/site-packages/tornado/test/autoreload_test.py new file mode 100644 index 0000000..be481e1 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/autoreload_test.py @@ -0,0 +1,127 @@ +import os +import shutil +import subprocess +from subprocess import Popen +import sys +from tempfile import mkdtemp +import time +import unittest + + +class AutoreloadTest(unittest.TestCase): + def setUp(self): + self.path = mkdtemp() + + def tearDown(self): + try: + shutil.rmtree(self.path) + except OSError: + # Windows disallows deleting files that are in use by + # another process, and even though we've waited for our + # child process below, it appears that its lock on these + # files is not guaranteed to be released by this point. + # Sleep and try again (once). + time.sleep(1) + shutil.rmtree(self.path) + + def test_reload_module(self): + main = """\ +import os +import sys + +from tornado import autoreload + +# This import will fail if path is not set up correctly +import testapp + +print('Starting') +if 'TESTAPP_STARTED' not in os.environ: + os.environ['TESTAPP_STARTED'] = '1' + sys.stdout.flush() + autoreload._reload() +""" + + # Create temporary test application + os.mkdir(os.path.join(self.path, "testapp")) + open(os.path.join(self.path, "testapp/__init__.py"), "w").close() + with open(os.path.join(self.path, "testapp/__main__.py"), "w") as f: + f.write(main) + + # Make sure the tornado module under test is available to the test + # application + pythonpath = os.getcwd() + if "PYTHONPATH" in os.environ: + pythonpath += os.pathsep + os.environ["PYTHONPATH"] + + p = Popen( + [sys.executable, "-m", "testapp"], + stdout=subprocess.PIPE, + cwd=self.path, + env=dict(os.environ, PYTHONPATH=pythonpath), + universal_newlines=True, + ) + out = p.communicate()[0] + self.assertEqual(out, "Starting\nStarting\n") + + def test_reload_wrapper_preservation(self): + # This test verifies that when `python -m tornado.autoreload` + # is used on an application that also has an internal + # autoreload, the reload wrapper is preserved on restart. + main = """\ +import os +import sys + +# This import will fail if path is not set up correctly +import testapp + +if 'tornado.autoreload' not in sys.modules: + raise Exception('started without autoreload wrapper') + +import tornado.autoreload + +print('Starting') +sys.stdout.flush() +if 'TESTAPP_STARTED' not in os.environ: + os.environ['TESTAPP_STARTED'] = '1' + # Simulate an internal autoreload (one not caused + # by the wrapper). + tornado.autoreload._reload() +else: + # Exit directly so autoreload doesn't catch it. + os._exit(0) +""" + + # Create temporary test application + os.mkdir(os.path.join(self.path, "testapp")) + init_file = os.path.join(self.path, "testapp", "__init__.py") + open(init_file, "w").close() + main_file = os.path.join(self.path, "testapp", "__main__.py") + with open(main_file, "w") as f: + f.write(main) + + # Make sure the tornado module under test is available to the test + # application + pythonpath = os.getcwd() + if "PYTHONPATH" in os.environ: + pythonpath += os.pathsep + os.environ["PYTHONPATH"] + + autoreload_proc = Popen( + [sys.executable, "-m", "tornado.autoreload", "-m", "testapp"], + stdout=subprocess.PIPE, + cwd=self.path, + env=dict(os.environ, PYTHONPATH=pythonpath), + universal_newlines=True, + ) + + # This timeout needs to be fairly generous for pypy due to jit + # warmup costs. + for i in range(40): + if autoreload_proc.poll() is not None: + break + time.sleep(0.1) + else: + autoreload_proc.kill() + raise Exception("subprocess failed to terminate") + + out = autoreload_proc.communicate()[0] + self.assertEqual(out, "Starting\n" * 2) diff --git a/venv/lib/python3.8/site-packages/tornado/test/concurrent_test.py b/venv/lib/python3.8/site-packages/tornado/test/concurrent_test.py new file mode 100644 index 0000000..b121c69 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/concurrent_test.py @@ -0,0 +1,212 @@ +# +# Copyright 2012 Facebook +# +# 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. +from concurrent import futures +import logging +import re +import socket +import typing +import unittest + +from tornado.concurrent import ( + Future, + run_on_executor, + future_set_result_unless_cancelled, +) +from tornado.escape import utf8, to_unicode +from tornado import gen +from tornado.iostream import IOStream +from tornado.tcpserver import TCPServer +from tornado.testing import AsyncTestCase, bind_unused_port, gen_test + + +class MiscFutureTest(AsyncTestCase): + def test_future_set_result_unless_cancelled(self): + fut = Future() # type: Future[int] + future_set_result_unless_cancelled(fut, 42) + self.assertEqual(fut.result(), 42) + self.assertFalse(fut.cancelled()) + + fut = Future() + fut.cancel() + is_cancelled = fut.cancelled() + future_set_result_unless_cancelled(fut, 42) + self.assertEqual(fut.cancelled(), is_cancelled) + if not is_cancelled: + self.assertEqual(fut.result(), 42) + + +# The following series of classes demonstrate and test various styles +# of use, with and without generators and futures. + + +class CapServer(TCPServer): + @gen.coroutine + def handle_stream(self, stream, address): + data = yield stream.read_until(b"\n") + data = to_unicode(data) + if data == data.upper(): + stream.write(b"error\talready capitalized\n") + else: + # data already has \n + stream.write(utf8("ok\t%s" % data.upper())) + stream.close() + + +class CapError(Exception): + pass + + +class BaseCapClient(object): + def __init__(self, port): + self.port = port + + def process_response(self, data): + m = re.match("(.*)\t(.*)\n", to_unicode(data)) + if m is None: + raise Exception("did not match") + status, message = m.groups() + if status == "ok": + return message + else: + raise CapError(message) + + +class GeneratorCapClient(BaseCapClient): + @gen.coroutine + def capitalize(self, request_data): + logging.debug("capitalize") + stream = IOStream(socket.socket()) + logging.debug("connecting") + yield stream.connect(("127.0.0.1", self.port)) + stream.write(utf8(request_data + "\n")) + logging.debug("reading") + data = yield stream.read_until(b"\n") + logging.debug("returning") + stream.close() + raise gen.Return(self.process_response(data)) + + +class ClientTestMixin(object): + client_class = None # type: typing.Callable + + def setUp(self): + super().setUp() # type: ignore + self.server = CapServer() + sock, port = bind_unused_port() + self.server.add_sockets([sock]) + self.client = self.client_class(port=port) + + def tearDown(self): + self.server.stop() + super().tearDown() # type: ignore + + def test_future(self: typing.Any): + future = self.client.capitalize("hello") + self.io_loop.add_future(future, self.stop) + self.wait() + self.assertEqual(future.result(), "HELLO") + + def test_future_error(self: typing.Any): + future = self.client.capitalize("HELLO") + self.io_loop.add_future(future, self.stop) + self.wait() + self.assertRaisesRegexp(CapError, "already capitalized", future.result) # type: ignore + + def test_generator(self: typing.Any): + @gen.coroutine + def f(): + result = yield self.client.capitalize("hello") + self.assertEqual(result, "HELLO") + + self.io_loop.run_sync(f) + + def test_generator_error(self: typing.Any): + @gen.coroutine + def f(): + with self.assertRaisesRegexp(CapError, "already capitalized"): + yield self.client.capitalize("HELLO") + + self.io_loop.run_sync(f) + + +class GeneratorClientTest(ClientTestMixin, AsyncTestCase): + client_class = GeneratorCapClient + + +class RunOnExecutorTest(AsyncTestCase): + @gen_test + def test_no_calling(self): + class Object(object): + def __init__(self): + self.executor = futures.thread.ThreadPoolExecutor(1) + + @run_on_executor + def f(self): + return 42 + + o = Object() + answer = yield o.f() + self.assertEqual(answer, 42) + + @gen_test + def test_call_with_no_args(self): + class Object(object): + def __init__(self): + self.executor = futures.thread.ThreadPoolExecutor(1) + + @run_on_executor() + def f(self): + return 42 + + o = Object() + answer = yield o.f() + self.assertEqual(answer, 42) + + @gen_test + def test_call_with_executor(self): + class Object(object): + def __init__(self): + self.__executor = futures.thread.ThreadPoolExecutor(1) + + @run_on_executor(executor="_Object__executor") + def f(self): + return 42 + + o = Object() + answer = yield o.f() + self.assertEqual(answer, 42) + + @gen_test + def test_async_await(self): + class Object(object): + def __init__(self): + self.executor = futures.thread.ThreadPoolExecutor(1) + + @run_on_executor() + def f(self): + return 42 + + o = Object() + + async def f(): + answer = await o.f() + return answer + + result = yield f() + self.assertEqual(result, 42) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/lib/python3.8/site-packages/tornado/test/csv_translations/fr_FR.csv b/venv/lib/python3.8/site-packages/tornado/test/csv_translations/fr_FR.csv new file mode 100644 index 0000000..6321b6e --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/csv_translations/fr_FR.csv @@ -0,0 +1 @@ +"school","école" diff --git a/venv/lib/python3.8/site-packages/tornado/test/curl_httpclient_test.py b/venv/lib/python3.8/site-packages/tornado/test/curl_httpclient_test.py new file mode 100644 index 0000000..99af293 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/curl_httpclient_test.py @@ -0,0 +1,129 @@ +from hashlib import md5 +import unittest + +from tornado.escape import utf8 +from tornado.testing import AsyncHTTPTestCase +from tornado.test import httpclient_test +from tornado.web import Application, RequestHandler + + +try: + import pycurl +except ImportError: + pycurl = None # type: ignore + +if pycurl is not None: + from tornado.curl_httpclient import CurlAsyncHTTPClient + + +@unittest.skipIf(pycurl is None, "pycurl module not present") +class CurlHTTPClientCommonTestCase(httpclient_test.HTTPClientCommonTestCase): + def get_http_client(self): + client = CurlAsyncHTTPClient(defaults=dict(allow_ipv6=False)) + # make sure AsyncHTTPClient magic doesn't give us the wrong class + self.assertTrue(isinstance(client, CurlAsyncHTTPClient)) + return client + + +class DigestAuthHandler(RequestHandler): + def initialize(self, username, password): + self.username = username + self.password = password + + def get(self): + realm = "test" + opaque = "asdf" + # Real implementations would use a random nonce. + nonce = "1234" + + auth_header = self.request.headers.get("Authorization", None) + if auth_header is not None: + auth_mode, params = auth_header.split(" ", 1) + assert auth_mode == "Digest" + param_dict = {} + for pair in params.split(","): + k, v = pair.strip().split("=", 1) + if v[0] == '"' and v[-1] == '"': + v = v[1:-1] + param_dict[k] = v + assert param_dict["realm"] == realm + assert param_dict["opaque"] == opaque + assert param_dict["nonce"] == nonce + assert param_dict["username"] == self.username + assert param_dict["uri"] == self.request.path + h1 = md5( + utf8("%s:%s:%s" % (self.username, realm, self.password)) + ).hexdigest() + h2 = md5( + utf8("%s:%s" % (self.request.method, self.request.path)) + ).hexdigest() + digest = md5(utf8("%s:%s:%s" % (h1, nonce, h2))).hexdigest() + if digest == param_dict["response"]: + self.write("ok") + else: + self.write("fail") + else: + self.set_status(401) + self.set_header( + "WWW-Authenticate", + 'Digest realm="%s", nonce="%s", opaque="%s"' % (realm, nonce, opaque), + ) + + +class CustomReasonHandler(RequestHandler): + def get(self): + self.set_status(200, "Custom reason") + + +class CustomFailReasonHandler(RequestHandler): + def get(self): + self.set_status(400, "Custom reason") + + +@unittest.skipIf(pycurl is None, "pycurl module not present") +class CurlHTTPClientTestCase(AsyncHTTPTestCase): + def setUp(self): + super().setUp() + self.http_client = self.create_client() + + def get_app(self): + return Application( + [ + ("/digest", DigestAuthHandler, {"username": "foo", "password": "bar"}), + ( + "/digest_non_ascii", + DigestAuthHandler, + {"username": "foo", "password": "barユ£"}, + ), + ("/custom_reason", CustomReasonHandler), + ("/custom_fail_reason", CustomFailReasonHandler), + ] + ) + + def create_client(self, **kwargs): + return CurlAsyncHTTPClient( + force_instance=True, defaults=dict(allow_ipv6=False), **kwargs + ) + + def test_digest_auth(self): + response = self.fetch( + "/digest", auth_mode="digest", auth_username="foo", auth_password="bar" + ) + self.assertEqual(response.body, b"ok") + + def test_custom_reason(self): + response = self.fetch("/custom_reason") + self.assertEqual(response.reason, "Custom reason") + + def test_fail_custom_reason(self): + response = self.fetch("/custom_fail_reason") + self.assertEqual(str(response.error), "HTTP 400: Custom reason") + + def test_digest_auth_non_ascii(self): + response = self.fetch( + "/digest_non_ascii", + auth_mode="digest", + auth_username="foo", + auth_password="barユ£", + ) + self.assertEqual(response.body, b"ok") diff --git a/venv/lib/python3.8/site-packages/tornado/test/escape_test.py b/venv/lib/python3.8/site-packages/tornado/test/escape_test.py new file mode 100644 index 0000000..d8f95e4 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/escape_test.py @@ -0,0 +1,322 @@ +import unittest + +import tornado.escape +from tornado.escape import ( + utf8, + xhtml_escape, + xhtml_unescape, + url_escape, + url_unescape, + to_unicode, + json_decode, + json_encode, + squeeze, + recursive_unicode, +) +from tornado.util import unicode_type + +from typing import List, Tuple, Union, Dict, Any # noqa: F401 + +linkify_tests = [ + # (input, linkify_kwargs, expected_output) + ( + "hello http://world.com/!", + {}, + u'hello <a href="http://world.com/">http://world.com/</a>!', + ), + ( + "hello http://world.com/with?param=true&stuff=yes", + {}, + u'hello <a href="http://world.com/with?param=true&amp;stuff=yes">http://world.com/with?param=true&amp;stuff=yes</a>', # noqa: E501 + ), + # an opened paren followed by many chars killed Gruber's regex + ( + "http://url.com/w(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + {}, + u'<a href="http://url.com/w">http://url.com/w</a>(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', # noqa: E501 + ), + # as did too many dots at the end + ( + "http://url.com/withmany.......................................", + {}, + u'<a href="http://url.com/withmany">http://url.com/withmany</a>.......................................', # noqa: E501 + ), + ( + "http://url.com/withmany((((((((((((((((((((((((((((((((((a)", + {}, + u'<a href="http://url.com/withmany">http://url.com/withmany</a>((((((((((((((((((((((((((((((((((a)', # noqa: E501 + ), + # some examples from http://daringfireball.net/2009/11/liberal_regex_for_matching_urls + # plus a fex extras (such as multiple parentheses). + ( + "http://foo.com/blah_blah", + {}, + u'<a href="http://foo.com/blah_blah">http://foo.com/blah_blah</a>', + ), + ( + "http://foo.com/blah_blah/", + {}, + u'<a href="http://foo.com/blah_blah/">http://foo.com/blah_blah/</a>', + ), + ( + "(Something like http://foo.com/blah_blah)", + {}, + u'(Something like <a href="http://foo.com/blah_blah">http://foo.com/blah_blah</a>)', + ), + ( + "http://foo.com/blah_blah_(wikipedia)", + {}, + u'<a href="http://foo.com/blah_blah_(wikipedia)">http://foo.com/blah_blah_(wikipedia)</a>', + ), + ( + "http://foo.com/blah_(blah)_(wikipedia)_blah", + {}, + u'<a href="http://foo.com/blah_(blah)_(wikipedia)_blah">http://foo.com/blah_(blah)_(wikipedia)_blah</a>', # noqa: E501 + ), + ( + "(Something like http://foo.com/blah_blah_(wikipedia))", + {}, + u'(Something like <a href="http://foo.com/blah_blah_(wikipedia)">http://foo.com/blah_blah_(wikipedia)</a>)', # noqa: E501 + ), + ( + "http://foo.com/blah_blah.", + {}, + u'<a href="http://foo.com/blah_blah">http://foo.com/blah_blah</a>.', + ), + ( + "http://foo.com/blah_blah/.", + {}, + u'<a href="http://foo.com/blah_blah/">http://foo.com/blah_blah/</a>.', + ), + ( + "<http://foo.com/blah_blah>", + {}, + u'&lt;<a href="http://foo.com/blah_blah">http://foo.com/blah_blah</a>&gt;', + ), + ( + "<http://foo.com/blah_blah/>", + {}, + u'&lt;<a href="http://foo.com/blah_blah/">http://foo.com/blah_blah/</a>&gt;', + ), + ( + "http://foo.com/blah_blah,", + {}, + u'<a href="http://foo.com/blah_blah">http://foo.com/blah_blah</a>,', + ), + ( + "http://www.example.com/wpstyle/?p=364.", + {}, + u'<a href="http://www.example.com/wpstyle/?p=364">http://www.example.com/wpstyle/?p=364</a>.', # noqa: E501 + ), + ( + "rdar://1234", + {"permitted_protocols": ["http", "rdar"]}, + u'<a href="rdar://1234">rdar://1234</a>', + ), + ( + "rdar:/1234", + {"permitted_protocols": ["rdar"]}, + u'<a href="rdar:/1234">rdar:/1234</a>', + ), + ( + "http://userid:password@example.com:8080", + {}, + u'<a href="http://userid:password@example.com:8080">http://userid:password@example.com:8080</a>', # noqa: E501 + ), + ( + "http://userid@example.com", + {}, + u'<a href="http://userid@example.com">http://userid@example.com</a>', + ), + ( + "http://userid@example.com:8080", + {}, + u'<a href="http://userid@example.com:8080">http://userid@example.com:8080</a>', + ), + ( + "http://userid:password@example.com", + {}, + u'<a href="http://userid:password@example.com">http://userid:password@example.com</a>', + ), + ( + "message://%3c330e7f8409726r6a4ba78dkf1fd71420c1bf6ff@mail.gmail.com%3e", + {"permitted_protocols": ["http", "message"]}, + u'<a href="message://%3c330e7f8409726r6a4ba78dkf1fd71420c1bf6ff@mail.gmail.com%3e">' + u"message://%3c330e7f8409726r6a4ba78dkf1fd71420c1bf6ff@mail.gmail.com%3e</a>", + ), + ( + u"http://\u27a1.ws/\u4a39", + {}, + u'<a href="http://\u27a1.ws/\u4a39">http://\u27a1.ws/\u4a39</a>', + ), + ( + "<tag>http://example.com</tag>", + {}, + u'&lt;tag&gt;<a href="http://example.com">http://example.com</a>&lt;/tag&gt;', + ), + ( + "Just a www.example.com link.", + {}, + u'Just a <a href="http://www.example.com">www.example.com</a> link.', + ), + ( + "Just a www.example.com link.", + {"require_protocol": True}, + u"Just a www.example.com link.", + ), + ( + "A http://reallylong.com/link/that/exceedsthelenglimit.html", + {"require_protocol": True, "shorten": True}, + u'A <a href="http://reallylong.com/link/that/exceedsthelenglimit.html"' + u' title="http://reallylong.com/link/that/exceedsthelenglimit.html">http://reallylong.com/link...</a>', # noqa: E501 + ), + ( + "A http://reallylongdomainnamethatwillbetoolong.com/hi!", + {"shorten": True}, + u'A <a href="http://reallylongdomainnamethatwillbetoolong.com/hi"' + u' title="http://reallylongdomainnamethatwillbetoolong.com/hi">http://reallylongdomainnametha...</a>!', # noqa: E501 + ), + ( + "A file:///passwords.txt and http://web.com link", + {}, + u'A file:///passwords.txt and <a href="http://web.com">http://web.com</a> link', + ), + ( + "A file:///passwords.txt and http://web.com link", + {"permitted_protocols": ["file"]}, + u'A <a href="file:///passwords.txt">file:///passwords.txt</a> and http://web.com link', + ), + ( + "www.external-link.com", + {"extra_params": 'rel="nofollow" class="external"'}, + u'<a href="http://www.external-link.com" rel="nofollow" class="external">www.external-link.com</a>', # noqa: E501 + ), + ( + "www.external-link.com and www.internal-link.com/blogs extra", + { + "extra_params": lambda href: 'class="internal"' + if href.startswith("http://www.internal-link.com") + else 'rel="nofollow" class="external"' + }, + u'<a href="http://www.external-link.com" rel="nofollow" class="external">www.external-link.com</a>' # noqa: E501 + u' and <a href="http://www.internal-link.com/blogs" class="internal">www.internal-link.com/blogs</a> extra', # noqa: E501 + ), + ( + "www.external-link.com", + {"extra_params": lambda href: ' rel="nofollow" class="external" '}, + u'<a href="http://www.external-link.com" rel="nofollow" class="external">www.external-link.com</a>', # noqa: E501 + ), +] # type: List[Tuple[Union[str, bytes], Dict[str, Any], str]] + + +class EscapeTestCase(unittest.TestCase): + def test_linkify(self): + for text, kwargs, html in linkify_tests: + linked = tornado.escape.linkify(text, **kwargs) + self.assertEqual(linked, html) + + def test_xhtml_escape(self): + tests = [ + ("<foo>", "&lt;foo&gt;"), + (u"<foo>", u"&lt;foo&gt;"), + (b"<foo>", b"&lt;foo&gt;"), + ("<>&\"'", "&lt;&gt;&amp;&quot;&#39;"), + ("&amp;", "&amp;amp;"), + (u"<\u00e9>", u"&lt;\u00e9&gt;"), + (b"<\xc3\xa9>", b"&lt;\xc3\xa9&gt;"), + ] # type: List[Tuple[Union[str, bytes], Union[str, bytes]]] + for unescaped, escaped in tests: + self.assertEqual(utf8(xhtml_escape(unescaped)), utf8(escaped)) + self.assertEqual(utf8(unescaped), utf8(xhtml_unescape(escaped))) + + def test_xhtml_unescape_numeric(self): + tests = [ + ("foo&#32;bar", "foo bar"), + ("foo&#x20;bar", "foo bar"), + ("foo&#X20;bar", "foo bar"), + ("foo&#xabc;bar", u"foo\u0abcbar"), + ("foo&#xyz;bar", "foo&#xyz;bar"), # invalid encoding + ("foo&#;bar", "foo&#;bar"), # invalid encoding + ("foo&#x;bar", "foo&#x;bar"), # invalid encoding + ] + for escaped, unescaped in tests: + self.assertEqual(unescaped, xhtml_unescape(escaped)) + + def test_url_escape_unicode(self): + tests = [ + # byte strings are passed through as-is + (u"\u00e9".encode("utf8"), "%C3%A9"), + (u"\u00e9".encode("latin1"), "%E9"), + # unicode strings become utf8 + (u"\u00e9", "%C3%A9"), + ] # type: List[Tuple[Union[str, bytes], str]] + for unescaped, escaped in tests: + self.assertEqual(url_escape(unescaped), escaped) + + def test_url_unescape_unicode(self): + tests = [ + ("%C3%A9", u"\u00e9", "utf8"), + ("%C3%A9", u"\u00c3\u00a9", "latin1"), + ("%C3%A9", utf8(u"\u00e9"), None), + ] + for escaped, unescaped, encoding in tests: + # input strings to url_unescape should only contain ascii + # characters, but make sure the function accepts both byte + # and unicode strings. + self.assertEqual(url_unescape(to_unicode(escaped), encoding), unescaped) + self.assertEqual(url_unescape(utf8(escaped), encoding), unescaped) + + def test_url_escape_quote_plus(self): + unescaped = "+ #%" + plus_escaped = "%2B+%23%25" + escaped = "%2B%20%23%25" + self.assertEqual(url_escape(unescaped), plus_escaped) + self.assertEqual(url_escape(unescaped, plus=False), escaped) + self.assertEqual(url_unescape(plus_escaped), unescaped) + self.assertEqual(url_unescape(escaped, plus=False), unescaped) + self.assertEqual(url_unescape(plus_escaped, encoding=None), utf8(unescaped)) + self.assertEqual( + url_unescape(escaped, encoding=None, plus=False), utf8(unescaped) + ) + + def test_escape_return_types(self): + # On python2 the escape methods should generally return the same + # type as their argument + self.assertEqual(type(xhtml_escape("foo")), str) + self.assertEqual(type(xhtml_escape(u"foo")), unicode_type) + + def test_json_decode(self): + # json_decode accepts both bytes and unicode, but strings it returns + # are always unicode. + self.assertEqual(json_decode(b'"foo"'), u"foo") + self.assertEqual(json_decode(u'"foo"'), u"foo") + + # Non-ascii bytes are interpreted as utf8 + self.assertEqual(json_decode(utf8(u'"\u00e9"')), u"\u00e9") + + def test_json_encode(self): + # json deals with strings, not bytes. On python 2 byte strings will + # convert automatically if they are utf8; on python 3 byte strings + # are not allowed. + self.assertEqual(json_decode(json_encode(u"\u00e9")), u"\u00e9") + if bytes is str: + self.assertEqual(json_decode(json_encode(utf8(u"\u00e9"))), u"\u00e9") + self.assertRaises(UnicodeDecodeError, json_encode, b"\xe9") + + def test_squeeze(self): + self.assertEqual( + squeeze(u"sequences of whitespace chars"), + u"sequences of whitespace chars", + ) + + def test_recursive_unicode(self): + tests = { + "dict": {b"foo": b"bar"}, + "list": [b"foo", b"bar"], + "tuple": (b"foo", b"bar"), + "bytes": b"foo", + } + self.assertEqual(recursive_unicode(tests["dict"]), {u"foo": u"bar"}) + self.assertEqual(recursive_unicode(tests["list"]), [u"foo", u"bar"]) + self.assertEqual(recursive_unicode(tests["tuple"]), (u"foo", u"bar")) + self.assertEqual(recursive_unicode(tests["bytes"]), u"foo") diff --git a/venv/lib/python3.8/site-packages/tornado/test/gen_test.py b/venv/lib/python3.8/site-packages/tornado/test/gen_test.py new file mode 100644 index 0000000..73c3387 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/gen_test.py @@ -0,0 +1,1119 @@ +import asyncio +from concurrent import futures +import gc +import datetime +import platform +import sys +import time +import weakref +import unittest + +from tornado.concurrent import Future +from tornado.log import app_log +from tornado.testing import AsyncHTTPTestCase, AsyncTestCase, ExpectLog, gen_test +from tornado.test.util import skipOnTravis, skipNotCPython +from tornado.web import Application, RequestHandler, HTTPError + +from tornado import gen + +try: + import contextvars +except ImportError: + contextvars = None # type: ignore + +import typing + +if typing.TYPE_CHECKING: + from typing import List, Optional # noqa: F401 + + +class GenBasicTest(AsyncTestCase): + @gen.coroutine + def delay(self, iterations, arg): + """Returns arg after a number of IOLoop iterations.""" + for i in range(iterations): + yield gen.moment + raise gen.Return(arg) + + @gen.coroutine + def async_future(self, result): + yield gen.moment + return result + + @gen.coroutine + def async_exception(self, e): + yield gen.moment + raise e + + @gen.coroutine + def add_one_async(self, x): + yield gen.moment + raise gen.Return(x + 1) + + def test_no_yield(self): + @gen.coroutine + def f(): + pass + + self.io_loop.run_sync(f) + + def test_exception_phase1(self): + @gen.coroutine + def f(): + 1 / 0 + + self.assertRaises(ZeroDivisionError, self.io_loop.run_sync, f) + + def test_exception_phase2(self): + @gen.coroutine + def f(): + yield gen.moment + 1 / 0 + + self.assertRaises(ZeroDivisionError, self.io_loop.run_sync, f) + + def test_bogus_yield(self): + @gen.coroutine + def f(): + yield 42 + + self.assertRaises(gen.BadYieldError, self.io_loop.run_sync, f) + + def test_bogus_yield_tuple(self): + @gen.coroutine + def f(): + yield (1, 2) + + self.assertRaises(gen.BadYieldError, self.io_loop.run_sync, f) + + def test_reuse(self): + @gen.coroutine + def f(): + yield gen.moment + + self.io_loop.run_sync(f) + self.io_loop.run_sync(f) + + def test_none(self): + @gen.coroutine + def f(): + yield None + + self.io_loop.run_sync(f) + + def test_multi(self): + @gen.coroutine + def f(): + results = yield [self.add_one_async(1), self.add_one_async(2)] + self.assertEqual(results, [2, 3]) + + self.io_loop.run_sync(f) + + def test_multi_dict(self): + @gen.coroutine + def f(): + results = yield dict(foo=self.add_one_async(1), bar=self.add_one_async(2)) + self.assertEqual(results, dict(foo=2, bar=3)) + + self.io_loop.run_sync(f) + + def test_multi_delayed(self): + @gen.coroutine + def f(): + # callbacks run at different times + responses = yield gen.multi_future( + [self.delay(3, "v1"), self.delay(1, "v2")] + ) + self.assertEqual(responses, ["v1", "v2"]) + + self.io_loop.run_sync(f) + + def test_multi_dict_delayed(self): + @gen.coroutine + def f(): + # callbacks run at different times + responses = yield gen.multi_future( + dict(foo=self.delay(3, "v1"), bar=self.delay(1, "v2")) + ) + self.assertEqual(responses, dict(foo="v1", bar="v2")) + + self.io_loop.run_sync(f) + + @skipOnTravis + @gen_test + def test_multi_performance(self): + # Yielding a list used to have quadratic performance; make + # sure a large list stays reasonable. On my laptop a list of + # 2000 used to take 1.8s, now it takes 0.12. + start = time.time() + yield [gen.moment for i in range(2000)] + end = time.time() + self.assertLess(end - start, 1.0) + + @gen_test + def test_multi_empty(self): + # Empty lists or dicts should return the same type. + x = yield [] + self.assertTrue(isinstance(x, list)) + y = yield {} + self.assertTrue(isinstance(y, dict)) + + @gen_test + def test_future(self): + result = yield self.async_future(1) + self.assertEqual(result, 1) + + @gen_test + def test_multi_future(self): + results = yield [self.async_future(1), self.async_future(2)] + self.assertEqual(results, [1, 2]) + + @gen_test + def test_multi_future_duplicate(self): + # Note that this doesn't work with native corotines, only with + # decorated coroutines. + f = self.async_future(2) + results = yield [self.async_future(1), f, self.async_future(3), f] + self.assertEqual(results, [1, 2, 3, 2]) + + @gen_test + def test_multi_dict_future(self): + results = yield dict(foo=self.async_future(1), bar=self.async_future(2)) + self.assertEqual(results, dict(foo=1, bar=2)) + + @gen_test + def test_multi_exceptions(self): + with ExpectLog(app_log, "Multiple exceptions in yield list"): + with self.assertRaises(RuntimeError) as cm: + yield gen.Multi( + [ + self.async_exception(RuntimeError("error 1")), + self.async_exception(RuntimeError("error 2")), + ] + ) + self.assertEqual(str(cm.exception), "error 1") + + # With only one exception, no error is logged. + with self.assertRaises(RuntimeError): + yield gen.Multi( + [self.async_exception(RuntimeError("error 1")), self.async_future(2)] + ) + + # Exception logging may be explicitly quieted. + with self.assertRaises(RuntimeError): + yield gen.Multi( + [ + self.async_exception(RuntimeError("error 1")), + self.async_exception(RuntimeError("error 2")), + ], + quiet_exceptions=RuntimeError, + ) + + @gen_test + def test_multi_future_exceptions(self): + with ExpectLog(app_log, "Multiple exceptions in yield list"): + with self.assertRaises(RuntimeError) as cm: + yield [ + self.async_exception(RuntimeError("error 1")), + self.async_exception(RuntimeError("error 2")), + ] + self.assertEqual(str(cm.exception), "error 1") + + # With only one exception, no error is logged. + with self.assertRaises(RuntimeError): + yield [self.async_exception(RuntimeError("error 1")), self.async_future(2)] + + # Exception logging may be explicitly quieted. + with self.assertRaises(RuntimeError): + yield gen.multi_future( + [ + self.async_exception(RuntimeError("error 1")), + self.async_exception(RuntimeError("error 2")), + ], + quiet_exceptions=RuntimeError, + ) + + def test_sync_raise_return(self): + @gen.coroutine + def f(): + raise gen.Return() + + self.io_loop.run_sync(f) + + def test_async_raise_return(self): + @gen.coroutine + def f(): + yield gen.moment + raise gen.Return() + + self.io_loop.run_sync(f) + + def test_sync_raise_return_value(self): + @gen.coroutine + def f(): + raise gen.Return(42) + + self.assertEqual(42, self.io_loop.run_sync(f)) + + def test_sync_raise_return_value_tuple(self): + @gen.coroutine + def f(): + raise gen.Return((1, 2)) + + self.assertEqual((1, 2), self.io_loop.run_sync(f)) + + def test_async_raise_return_value(self): + @gen.coroutine + def f(): + yield gen.moment + raise gen.Return(42) + + self.assertEqual(42, self.io_loop.run_sync(f)) + + def test_async_raise_return_value_tuple(self): + @gen.coroutine + def f(): + yield gen.moment + raise gen.Return((1, 2)) + + self.assertEqual((1, 2), self.io_loop.run_sync(f)) + + +class GenCoroutineTest(AsyncTestCase): + def setUp(self): + # Stray StopIteration exceptions can lead to tests exiting prematurely, + # so we need explicit checks here to make sure the tests run all + # the way through. + self.finished = False + super().setUp() + + def tearDown(self): + super().tearDown() + assert self.finished + + def test_attributes(self): + self.finished = True + + def f(): + yield gen.moment + + coro = gen.coroutine(f) + self.assertEqual(coro.__name__, f.__name__) + self.assertEqual(coro.__module__, f.__module__) + self.assertIs(coro.__wrapped__, f) # type: ignore + + def test_is_coroutine_function(self): + self.finished = True + + def f(): + yield gen.moment + + coro = gen.coroutine(f) + self.assertFalse(gen.is_coroutine_function(f)) + self.assertTrue(gen.is_coroutine_function(coro)) + self.assertFalse(gen.is_coroutine_function(coro())) + + @gen_test + def test_sync_gen_return(self): + @gen.coroutine + def f(): + raise gen.Return(42) + + result = yield f() + self.assertEqual(result, 42) + self.finished = True + + @gen_test + def test_async_gen_return(self): + @gen.coroutine + def f(): + yield gen.moment + raise gen.Return(42) + + result = yield f() + self.assertEqual(result, 42) + self.finished = True + + @gen_test + def test_sync_return(self): + @gen.coroutine + def f(): + return 42 + + result = yield f() + self.assertEqual(result, 42) + self.finished = True + + @gen_test + def test_async_return(self): + @gen.coroutine + def f(): + yield gen.moment + return 42 + + result = yield f() + self.assertEqual(result, 42) + self.finished = True + + @gen_test + def test_async_early_return(self): + # A yield statement exists but is not executed, which means + # this function "returns" via an exception. This exception + # doesn't happen before the exception handling is set up. + @gen.coroutine + def f(): + if True: + return 42 + yield gen.Task(self.io_loop.add_callback) + + result = yield f() + self.assertEqual(result, 42) + self.finished = True + + @gen_test + def test_async_await(self): + @gen.coroutine + def f1(): + yield gen.moment + raise gen.Return(42) + + # This test verifies that an async function can await a + # yield-based gen.coroutine, and that a gen.coroutine + # (the test method itself) can yield an async function. + async def f2(): + result = await f1() + return result + + result = yield f2() + self.assertEqual(result, 42) + self.finished = True + + @gen_test + def test_asyncio_sleep_zero(self): + # asyncio.sleep(0) turns into a special case (equivalent to + # `yield None`) + async def f(): + import asyncio + + await asyncio.sleep(0) + return 42 + + result = yield f() + self.assertEqual(result, 42) + self.finished = True + + @gen_test + def test_async_await_mixed_multi_native_future(self): + @gen.coroutine + def f1(): + yield gen.moment + + async def f2(): + await f1() + return 42 + + @gen.coroutine + def f3(): + yield gen.moment + raise gen.Return(43) + + results = yield [f2(), f3()] + self.assertEqual(results, [42, 43]) + self.finished = True + + @gen_test + def test_async_with_timeout(self): + async def f1(): + return 42 + + result = yield gen.with_timeout(datetime.timedelta(hours=1), f1()) + self.assertEqual(result, 42) + self.finished = True + + @gen_test + def test_sync_return_no_value(self): + @gen.coroutine + def f(): + return + + result = yield f() + self.assertEqual(result, None) + self.finished = True + + @gen_test + def test_async_return_no_value(self): + # Without a return value we don't need python 3.3. + @gen.coroutine + def f(): + yield gen.moment + return + + result = yield f() + self.assertEqual(result, None) + self.finished = True + + @gen_test + def test_sync_raise(self): + @gen.coroutine + def f(): + 1 / 0 + + # The exception is raised when the future is yielded + # (or equivalently when its result method is called), + # not when the function itself is called). + future = f() + with self.assertRaises(ZeroDivisionError): + yield future + self.finished = True + + @gen_test + def test_async_raise(self): + @gen.coroutine + def f(): + yield gen.moment + 1 / 0 + + future = f() + with self.assertRaises(ZeroDivisionError): + yield future + self.finished = True + + @gen_test + def test_replace_yieldpoint_exception(self): + # Test exception handling: a coroutine can catch one exception + # raised by a yield point and raise a different one. + @gen.coroutine + def f1(): + 1 / 0 + + @gen.coroutine + def f2(): + try: + yield f1() + except ZeroDivisionError: + raise KeyError() + + future = f2() + with self.assertRaises(KeyError): + yield future + self.finished = True + + @gen_test + def test_swallow_yieldpoint_exception(self): + # Test exception handling: a coroutine can catch an exception + # raised by a yield point and not raise a different one. + @gen.coroutine + def f1(): + 1 / 0 + + @gen.coroutine + def f2(): + try: + yield f1() + except ZeroDivisionError: + raise gen.Return(42) + + result = yield f2() + self.assertEqual(result, 42) + self.finished = True + + @gen_test + def test_moment(self): + calls = [] + + @gen.coroutine + def f(name, yieldable): + for i in range(5): + calls.append(name) + yield yieldable + + # First, confirm the behavior without moment: each coroutine + # monopolizes the event loop until it finishes. + immediate = Future() # type: Future[None] + immediate.set_result(None) + yield [f("a", immediate), f("b", immediate)] + self.assertEqual("".join(calls), "aaaaabbbbb") + + # With moment, they take turns. + calls = [] + yield [f("a", gen.moment), f("b", gen.moment)] + self.assertEqual("".join(calls), "ababababab") + self.finished = True + + calls = [] + yield [f("a", gen.moment), f("b", immediate)] + self.assertEqual("".join(calls), "abbbbbaaaa") + + @gen_test + def test_sleep(self): + yield gen.sleep(0.01) + self.finished = True + + @gen_test + def test_py3_leak_exception_context(self): + class LeakedException(Exception): + pass + + @gen.coroutine + def inner(iteration): + raise LeakedException(iteration) + + try: + yield inner(1) + except LeakedException as e: + self.assertEqual(str(e), "1") + self.assertIsNone(e.__context__) + + try: + yield inner(2) + except LeakedException as e: + self.assertEqual(str(e), "2") + self.assertIsNone(e.__context__) + + self.finished = True + + @skipNotCPython + @unittest.skipIf( + (3,) < sys.version_info < (3, 6), "asyncio.Future has reference cycles" + ) + def test_coroutine_refcounting(self): + # On CPython, tasks and their arguments should be released immediately + # without waiting for garbage collection. + @gen.coroutine + def inner(): + class Foo(object): + pass + + local_var = Foo() + self.local_ref = weakref.ref(local_var) + + def dummy(): + pass + + yield gen.coroutine(dummy)() + raise ValueError("Some error") + + @gen.coroutine + def inner2(): + try: + yield inner() + except ValueError: + pass + + self.io_loop.run_sync(inner2, timeout=3) + + self.assertIs(self.local_ref(), None) + self.finished = True + + def test_asyncio_future_debug_info(self): + self.finished = True + # Enable debug mode + asyncio_loop = asyncio.get_event_loop() + self.addCleanup(asyncio_loop.set_debug, asyncio_loop.get_debug()) + asyncio_loop.set_debug(True) + + def f(): + yield gen.moment + + coro = gen.coroutine(f)() + self.assertIsInstance(coro, asyncio.Future) + # We expect the coroutine repr() to show the place where + # it was instantiated + expected = "created at %s:%d" % (__file__, f.__code__.co_firstlineno + 3) + actual = repr(coro) + self.assertIn(expected, actual) + + @gen_test + def test_asyncio_gather(self): + # This demonstrates that tornado coroutines can be understood + # by asyncio (This failed prior to Tornado 5.0). + @gen.coroutine + def f(): + yield gen.moment + raise gen.Return(1) + + ret = yield asyncio.gather(f(), f()) + self.assertEqual(ret, [1, 1]) + self.finished = True + + +class GenCoroutineSequenceHandler(RequestHandler): + @gen.coroutine + def get(self): + yield gen.moment + self.write("1") + yield gen.moment + self.write("2") + yield gen.moment + self.finish("3") + + +class GenCoroutineUnfinishedSequenceHandler(RequestHandler): + @gen.coroutine + def get(self): + yield gen.moment + self.write("1") + yield gen.moment + self.write("2") + yield gen.moment + # just write, don't finish + self.write("3") + + +# "Undecorated" here refers to the absence of @asynchronous. +class UndecoratedCoroutinesHandler(RequestHandler): + @gen.coroutine + def prepare(self): + self.chunks = [] # type: List[str] + yield gen.moment + self.chunks.append("1") + + @gen.coroutine + def get(self): + self.chunks.append("2") + yield gen.moment + self.chunks.append("3") + yield gen.moment + self.write("".join(self.chunks)) + + +class AsyncPrepareErrorHandler(RequestHandler): + @gen.coroutine + def prepare(self): + yield gen.moment + raise HTTPError(403) + + def get(self): + self.finish("ok") + + +class NativeCoroutineHandler(RequestHandler): + async def get(self): + await asyncio.sleep(0) + self.write("ok") + + +class GenWebTest(AsyncHTTPTestCase): + def get_app(self): + return Application( + [ + ("/coroutine_sequence", GenCoroutineSequenceHandler), + ( + "/coroutine_unfinished_sequence", + GenCoroutineUnfinishedSequenceHandler, + ), + ("/undecorated_coroutine", UndecoratedCoroutinesHandler), + ("/async_prepare_error", AsyncPrepareErrorHandler), + ("/native_coroutine", NativeCoroutineHandler), + ] + ) + + def test_coroutine_sequence_handler(self): + response = self.fetch("/coroutine_sequence") + self.assertEqual(response.body, b"123") + + def test_coroutine_unfinished_sequence_handler(self): + response = self.fetch("/coroutine_unfinished_sequence") + self.assertEqual(response.body, b"123") + + def test_undecorated_coroutines(self): + response = self.fetch("/undecorated_coroutine") + self.assertEqual(response.body, b"123") + + def test_async_prepare_error_handler(self): + response = self.fetch("/async_prepare_error") + self.assertEqual(response.code, 403) + + def test_native_coroutine_handler(self): + response = self.fetch("/native_coroutine") + self.assertEqual(response.code, 200) + self.assertEqual(response.body, b"ok") + + +class WithTimeoutTest(AsyncTestCase): + @gen_test + def test_timeout(self): + with self.assertRaises(gen.TimeoutError): + yield gen.with_timeout(datetime.timedelta(seconds=0.1), Future()) + + @gen_test + def test_completes_before_timeout(self): + future = Future() # type: Future[str] + self.io_loop.add_timeout( + datetime.timedelta(seconds=0.1), lambda: future.set_result("asdf") + ) + result = yield gen.with_timeout(datetime.timedelta(seconds=3600), future) + self.assertEqual(result, "asdf") + + @gen_test + def test_fails_before_timeout(self): + future = Future() # type: Future[str] + self.io_loop.add_timeout( + datetime.timedelta(seconds=0.1), + lambda: future.set_exception(ZeroDivisionError()), + ) + with self.assertRaises(ZeroDivisionError): + yield gen.with_timeout(datetime.timedelta(seconds=3600), future) + + @gen_test + def test_already_resolved(self): + future = Future() # type: Future[str] + future.set_result("asdf") + result = yield gen.with_timeout(datetime.timedelta(seconds=3600), future) + self.assertEqual(result, "asdf") + + @gen_test + def test_timeout_concurrent_future(self): + # A concurrent future that does not resolve before the timeout. + with futures.ThreadPoolExecutor(1) as executor: + with self.assertRaises(gen.TimeoutError): + yield gen.with_timeout( + self.io_loop.time(), executor.submit(time.sleep, 0.1) + ) + + @gen_test + def test_completed_concurrent_future(self): + # A concurrent future that is resolved before we even submit it + # to with_timeout. + with futures.ThreadPoolExecutor(1) as executor: + + def dummy(): + pass + + f = executor.submit(dummy) + f.result() # wait for completion + yield gen.with_timeout(datetime.timedelta(seconds=3600), f) + + @gen_test + def test_normal_concurrent_future(self): + # A conccurrent future that resolves while waiting for the timeout. + with futures.ThreadPoolExecutor(1) as executor: + yield gen.with_timeout( + datetime.timedelta(seconds=3600), + executor.submit(lambda: time.sleep(0.01)), + ) + + +class WaitIteratorTest(AsyncTestCase): + @gen_test + def test_empty_iterator(self): + g = gen.WaitIterator() + self.assertTrue(g.done(), "empty generator iterated") + + with self.assertRaises(ValueError): + g = gen.WaitIterator(Future(), bar=Future()) + + self.assertEqual(g.current_index, None, "bad nil current index") + self.assertEqual(g.current_future, None, "bad nil current future") + + @gen_test + def test_already_done(self): + f1 = Future() # type: Future[int] + f2 = Future() # type: Future[int] + f3 = Future() # type: Future[int] + f1.set_result(24) + f2.set_result(42) + f3.set_result(84) + + g = gen.WaitIterator(f1, f2, f3) + i = 0 + while not g.done(): + r = yield g.next() + # Order is not guaranteed, but the current implementation + # preserves ordering of already-done Futures. + if i == 0: + self.assertEqual(g.current_index, 0) + self.assertIs(g.current_future, f1) + self.assertEqual(r, 24) + elif i == 1: + self.assertEqual(g.current_index, 1) + self.assertIs(g.current_future, f2) + self.assertEqual(r, 42) + elif i == 2: + self.assertEqual(g.current_index, 2) + self.assertIs(g.current_future, f3) + self.assertEqual(r, 84) + i += 1 + + self.assertEqual(g.current_index, None, "bad nil current index") + self.assertEqual(g.current_future, None, "bad nil current future") + + dg = gen.WaitIterator(f1=f1, f2=f2) + + while not dg.done(): + dr = yield dg.next() + if dg.current_index == "f1": + self.assertTrue( + dg.current_future == f1 and dr == 24, + "WaitIterator dict status incorrect", + ) + elif dg.current_index == "f2": + self.assertTrue( + dg.current_future == f2 and dr == 42, + "WaitIterator dict status incorrect", + ) + else: + self.fail("got bad WaitIterator index {}".format(dg.current_index)) + + i += 1 + + self.assertEqual(dg.current_index, None, "bad nil current index") + self.assertEqual(dg.current_future, None, "bad nil current future") + + def finish_coroutines(self, iteration, futures): + if iteration == 3: + futures[2].set_result(24) + elif iteration == 5: + futures[0].set_exception(ZeroDivisionError()) + elif iteration == 8: + futures[1].set_result(42) + futures[3].set_result(84) + + if iteration < 8: + self.io_loop.add_callback(self.finish_coroutines, iteration + 1, futures) + + @gen_test + def test_iterator(self): + futures = [Future(), Future(), Future(), Future()] # type: List[Future[int]] + + self.finish_coroutines(0, futures) + + g = gen.WaitIterator(*futures) + + i = 0 + while not g.done(): + try: + r = yield g.next() + except ZeroDivisionError: + self.assertIs(g.current_future, futures[0], "exception future invalid") + else: + if i == 0: + self.assertEqual(r, 24, "iterator value incorrect") + self.assertEqual(g.current_index, 2, "wrong index") + elif i == 2: + self.assertEqual(r, 42, "iterator value incorrect") + self.assertEqual(g.current_index, 1, "wrong index") + elif i == 3: + self.assertEqual(r, 84, "iterator value incorrect") + self.assertEqual(g.current_index, 3, "wrong index") + i += 1 + + @gen_test + def test_iterator_async_await(self): + # Recreate the previous test with py35 syntax. It's a little clunky + # because of the way the previous test handles an exception on + # a single iteration. + futures = [Future(), Future(), Future(), Future()] # type: List[Future[int]] + self.finish_coroutines(0, futures) + self.finished = False + + async def f(): + i = 0 + g = gen.WaitIterator(*futures) + try: + async for r in g: + if i == 0: + self.assertEqual(r, 24, "iterator value incorrect") + self.assertEqual(g.current_index, 2, "wrong index") + else: + raise Exception("expected exception on iteration 1") + i += 1 + except ZeroDivisionError: + i += 1 + async for r in g: + if i == 2: + self.assertEqual(r, 42, "iterator value incorrect") + self.assertEqual(g.current_index, 1, "wrong index") + elif i == 3: + self.assertEqual(r, 84, "iterator value incorrect") + self.assertEqual(g.current_index, 3, "wrong index") + else: + raise Exception("didn't expect iteration %d" % i) + i += 1 + self.finished = True + + yield f() + self.assertTrue(self.finished) + + @gen_test + def test_no_ref(self): + # In this usage, there is no direct hard reference to the + # WaitIterator itself, only the Future it returns. Since + # WaitIterator uses weak references internally to improve GC + # performance, this used to cause problems. + yield gen.with_timeout( + datetime.timedelta(seconds=0.1), gen.WaitIterator(gen.sleep(0)).next() + ) + + +class RunnerGCTest(AsyncTestCase): + def is_pypy3(self): + return platform.python_implementation() == "PyPy" and sys.version_info > (3,) + + @gen_test + def test_gc(self): + # GitHub issue 1769: Runner objects can get GCed unexpectedly + # while their future is alive. + weakref_scope = [None] # type: List[Optional[weakref.ReferenceType]] + + def callback(): + gc.collect(2) + weakref_scope[0]().set_result(123) # type: ignore + + @gen.coroutine + def tester(): + fut = Future() # type: Future[int] + weakref_scope[0] = weakref.ref(fut) + self.io_loop.add_callback(callback) + yield fut + + yield gen.with_timeout(datetime.timedelta(seconds=0.2), tester()) + + def test_gc_infinite_coro(self): + # GitHub issue 2229: suspended coroutines should be GCed when + # their loop is closed, even if they're involved in a reference + # cycle. + loop = self.get_new_ioloop() + result = [] # type: List[Optional[bool]] + wfut = [] + + @gen.coroutine + def infinite_coro(): + try: + while True: + yield gen.sleep(1e-3) + result.append(True) + finally: + # coroutine finalizer + result.append(None) + + @gen.coroutine + def do_something(): + fut = infinite_coro() + fut._refcycle = fut # type: ignore + wfut.append(weakref.ref(fut)) + yield gen.sleep(0.2) + + loop.run_sync(do_something) + loop.close() + gc.collect() + # Future was collected + self.assertIs(wfut[0](), None) + # At least one wakeup + self.assertGreaterEqual(len(result), 2) + if not self.is_pypy3(): + # coroutine finalizer was called (not on PyPy3 apparently) + self.assertIs(result[-1], None) + + def test_gc_infinite_async_await(self): + # Same as test_gc_infinite_coro, but with a `async def` function + import asyncio + + async def infinite_coro(result): + try: + while True: + await gen.sleep(1e-3) + result.append(True) + finally: + # coroutine finalizer + result.append(None) + + loop = self.get_new_ioloop() + result = [] # type: List[Optional[bool]] + wfut = [] + + @gen.coroutine + def do_something(): + fut = asyncio.get_event_loop().create_task(infinite_coro(result)) + fut._refcycle = fut # type: ignore + wfut.append(weakref.ref(fut)) + yield gen.sleep(0.2) + + loop.run_sync(do_something) + with ExpectLog("asyncio", "Task was destroyed but it is pending"): + loop.close() + gc.collect() + # Future was collected + self.assertIs(wfut[0](), None) + # At least one wakeup and one finally + self.assertGreaterEqual(len(result), 2) + if not self.is_pypy3(): + # coroutine finalizer was called (not on PyPy3 apparently) + self.assertIs(result[-1], None) + + def test_multi_moment(self): + # Test gen.multi with moment + # now that it's not a real Future + @gen.coroutine + def wait_a_moment(): + result = yield gen.multi([gen.moment, gen.moment]) + raise gen.Return(result) + + loop = self.get_new_ioloop() + result = loop.run_sync(wait_a_moment) + self.assertEqual(result, [None, None]) + + +if contextvars is not None: + ctx_var = contextvars.ContextVar("ctx_var") # type: contextvars.ContextVar[int] + + +@unittest.skipIf(contextvars is None, "contextvars module not present") +class ContextVarsTest(AsyncTestCase): + async def native_root(self, x): + ctx_var.set(x) + await self.inner(x) + + @gen.coroutine + def gen_root(self, x): + ctx_var.set(x) + yield + yield self.inner(x) + + async def inner(self, x): + self.assertEqual(ctx_var.get(), x) + await self.gen_inner(x) + self.assertEqual(ctx_var.get(), x) + + # IOLoop.run_in_executor doesn't automatically copy context + ctx = contextvars.copy_context() + await self.io_loop.run_in_executor(None, lambda: ctx.run(self.thread_inner, x)) + self.assertEqual(ctx_var.get(), x) + + # Neither does asyncio's run_in_executor. + await asyncio.get_event_loop().run_in_executor( + None, lambda: ctx.run(self.thread_inner, x) + ) + self.assertEqual(ctx_var.get(), x) + + @gen.coroutine + def gen_inner(self, x): + self.assertEqual(ctx_var.get(), x) + yield + self.assertEqual(ctx_var.get(), x) + + def thread_inner(self, x): + self.assertEqual(ctx_var.get(), x) + + @gen_test + def test_propagate(self): + # Verify that context vars get propagated across various + # combinations of native and decorated coroutines. + yield [ + self.native_root(1), + self.native_root(2), + self.gen_root(3), + self.gen_root(4), + ] + + @gen_test + def test_reset(self): + token = ctx_var.set(1) + yield + # reset asserts that we are still at the same level of the context tree, + # so we must make sure that we maintain that property across yield. + ctx_var.reset(token) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/lib/python3.8/site-packages/tornado/test/gettext_translations/fr_FR/LC_MESSAGES/tornado_test.mo b/venv/lib/python3.8/site-packages/tornado/test/gettext_translations/fr_FR/LC_MESSAGES/tornado_test.mo new file mode 100644 index 0000000000000000000000000000000000000000..a97bf9c57460ecfc27761accf90d712ea5cebb44 GIT binary patch literal 665 zcmYk3PjAyO7{(2hf8hd1hzkcFL6b*PG%=;?w5-jxh@`2~Zqm59iI;kKc4a#Z&~AJN zz5pk7=gei_VK?{)d<I^Jit<XoJWujIj^D(;9(TSVs5`(jAO#)(7l5m8fCpRx_kr)g zQ{V^S)?5P*fuF$X4TOG!-UW_tB6JUwf<AIRP?x^|eFFL!6ypEt7C6^;1ufKR9YVL4 zifW~*j^_2;B0<lWPU)IT{)t+yWTzC(47rOzrkpD!kg>dc_y6;;R;R4AB&o;|(*{<B zcpMGhMEfy5ii=5-kGz5{l(r-@HLu8SQyVf>A@;`klngX$w<1GoS%|xSutEHQbYJ5j z2>p#U|CR4UkQD4acQ0S&j^n5xSx$x#KFGr?S$mt0VlSn}lBuTB2x^rM@!nyY;!%{v zcq`7LB;ARI!y=wcwjnC(hSrQs89fVe8jbc3-N;*Mx+C~H{DoBpM$M8eUVUG%?t23z zEt9a_#|6x7*$4Y_At;wUT+XRB%=R05LN-@9H`WQ$B$lPBxU56GIpfwFi$+sH_LM#| zA(o5w*7UnQ{MYuMOT3MP7d;ONhG(2fr<GP5PL1LAgak9KG3e^DRD!k1tFKnMtiiL^ G8uSP9S*+y% literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/tornado/test/gettext_translations/fr_FR/LC_MESSAGES/tornado_test.po b/venv/lib/python3.8/site-packages/tornado/test/gettext_translations/fr_FR/LC_MESSAGES/tornado_test.po new file mode 100644 index 0000000..88d72c8 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/gettext_translations/fr_FR/LC_MESSAGES/tornado_test.po @@ -0,0 +1,47 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-01-27 11:05+0300\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" +"Language-Team: LANGUAGE <LL@li.org>\n" +"Language: \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" + +#: extract_me.py:11 +msgid "school" +msgstr "école" + +#: extract_me.py:12 +msgctxt "law" +msgid "right" +msgstr "le droit" + +#: extract_me.py:13 +msgctxt "good" +msgid "right" +msgstr "le bien" + +#: extract_me.py:14 +msgctxt "organization" +msgid "club" +msgid_plural "clubs" +msgstr[0] "le club" +msgstr[1] "les clubs" + +#: extract_me.py:15 +msgctxt "stick" +msgid "club" +msgid_plural "clubs" +msgstr[0] "le bâton" +msgstr[1] "les bâtons" diff --git a/venv/lib/python3.8/site-packages/tornado/test/http1connection_test.py b/venv/lib/python3.8/site-packages/tornado/test/http1connection_test.py new file mode 100644 index 0000000..d21d506 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/http1connection_test.py @@ -0,0 +1,61 @@ +import socket +import typing + +from tornado.http1connection import HTTP1Connection +from tornado.httputil import HTTPMessageDelegate +from tornado.iostream import IOStream +from tornado.locks import Event +from tornado.netutil import add_accept_handler +from tornado.testing import AsyncTestCase, bind_unused_port, gen_test + + +class HTTP1ConnectionTest(AsyncTestCase): + code = None # type: typing.Optional[int] + + def setUp(self): + super().setUp() + self.asyncSetUp() + + @gen_test + def asyncSetUp(self): + listener, port = bind_unused_port() + event = Event() + + def accept_callback(conn, addr): + self.server_stream = IOStream(conn) + self.addCleanup(self.server_stream.close) + event.set() + + add_accept_handler(listener, accept_callback) + self.client_stream = IOStream(socket.socket()) + self.addCleanup(self.client_stream.close) + yield [self.client_stream.connect(("127.0.0.1", port)), event.wait()] + self.io_loop.remove_handler(listener) + listener.close() + + @gen_test + def test_http10_no_content_length(self): + # Regression test for a bug in which can_keep_alive would crash + # for an HTTP/1.0 (not 1.1) response with no content-length. + conn = HTTP1Connection(self.client_stream, True) + self.server_stream.write(b"HTTP/1.0 200 Not Modified\r\n\r\nhello") + self.server_stream.close() + + event = Event() + test = self + body = [] + + class Delegate(HTTPMessageDelegate): + def headers_received(self, start_line, headers): + test.code = start_line.code + + def data_received(self, data): + body.append(data) + + def finish(self): + event.set() + + yield conn.read_response(Delegate()) + yield event.wait() + self.assertEqual(self.code, 200) + self.assertEqual(b"".join(body), b"hello") diff --git a/venv/lib/python3.8/site-packages/tornado/test/httpclient_test.py b/venv/lib/python3.8/site-packages/tornado/test/httpclient_test.py new file mode 100644 index 0000000..fd9a978 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/httpclient_test.py @@ -0,0 +1,898 @@ +import base64 +import binascii +from contextlib import closing +import copy +import gzip +import threading +import datetime +from io import BytesIO +import subprocess +import sys +import time +import typing # noqa: F401 +import unicodedata +import unittest + +from tornado.escape import utf8, native_str, to_unicode +from tornado import gen +from tornado.httpclient import ( + HTTPRequest, + HTTPResponse, + _RequestProxy, + HTTPError, + HTTPClient, +) +from tornado.httpserver import HTTPServer +from tornado.ioloop import IOLoop +from tornado.iostream import IOStream +from tornado.log import gen_log, app_log +from tornado import netutil +from tornado.testing import AsyncHTTPTestCase, bind_unused_port, gen_test, ExpectLog +from tornado.test.util import skipOnTravis +from tornado.web import Application, RequestHandler, url +from tornado.httputil import format_timestamp, HTTPHeaders + + +class HelloWorldHandler(RequestHandler): + def get(self): + name = self.get_argument("name", "world") + self.set_header("Content-Type", "text/plain") + self.finish("Hello %s!" % name) + + +class PostHandler(RequestHandler): + def post(self): + self.finish( + "Post arg1: %s, arg2: %s" + % (self.get_argument("arg1"), self.get_argument("arg2")) + ) + + +class PutHandler(RequestHandler): + def put(self): + self.write("Put body: ") + self.write(self.request.body) + + +class RedirectHandler(RequestHandler): + def prepare(self): + self.write("redirects can have bodies too") + self.redirect( + self.get_argument("url"), status=int(self.get_argument("status", "302")) + ) + + +class RedirectWithoutLocationHandler(RequestHandler): + def prepare(self): + # For testing error handling of a redirect with no location header. + self.set_status(301) + self.finish() + + +class ChunkHandler(RequestHandler): + @gen.coroutine + def get(self): + self.write("asdf") + self.flush() + # Wait a bit to ensure the chunks are sent and received separately. + yield gen.sleep(0.01) + self.write("qwer") + + +class AuthHandler(RequestHandler): + def get(self): + self.finish(self.request.headers["Authorization"]) + + +class CountdownHandler(RequestHandler): + def get(self, count): + count = int(count) + if count > 0: + self.redirect(self.reverse_url("countdown", count - 1)) + else: + self.write("Zero") + + +class EchoPostHandler(RequestHandler): + def post(self): + self.write(self.request.body) + + +class UserAgentHandler(RequestHandler): + def get(self): + self.write(self.request.headers.get("User-Agent", "User agent not set")) + + +class ContentLength304Handler(RequestHandler): + def get(self): + self.set_status(304) + self.set_header("Content-Length", 42) + + def _clear_representation_headers(self): + # Tornado strips content-length from 304 responses, but here we + # want to simulate servers that include the headers anyway. + pass + + +class PatchHandler(RequestHandler): + def patch(self): + "Return the request payload - so we can check it is being kept" + self.write(self.request.body) + + +class AllMethodsHandler(RequestHandler): + SUPPORTED_METHODS = RequestHandler.SUPPORTED_METHODS + ("OTHER",) # type: ignore + + def method(self): + assert self.request.method is not None + self.write(self.request.method) + + get = head = post = put = delete = options = patch = other = method # type: ignore + + +class SetHeaderHandler(RequestHandler): + def get(self): + # Use get_arguments for keys to get strings, but + # request.arguments for values to get bytes. + for k, v in zip(self.get_arguments("k"), self.request.arguments["v"]): + self.set_header(k, v) + + +class InvalidGzipHandler(RequestHandler): + def get(self): + # set Content-Encoding manually to avoid automatic gzip encoding + self.set_header("Content-Type", "text/plain") + self.set_header("Content-Encoding", "gzip") + # Triggering the potential bug seems to depend on input length. + # This length is taken from the bad-response example reported in + # https://github.com/tornadoweb/tornado/pull/2875 (uncompressed). + body = "".join("Hello World {}\n".format(i) for i in range(9000))[:149051] + body = gzip.compress(body.encode(), compresslevel=6) + b"\00" + self.write(body) + + +# These tests end up getting run redundantly: once here with the default +# HTTPClient implementation, and then again in each implementation's own +# test suite. + + +class HTTPClientCommonTestCase(AsyncHTTPTestCase): + def get_app(self): + return Application( + [ + url("/hello", HelloWorldHandler), + url("/post", PostHandler), + url("/put", PutHandler), + url("/redirect", RedirectHandler), + url("/redirect_without_location", RedirectWithoutLocationHandler), + url("/chunk", ChunkHandler), + url("/auth", AuthHandler), + url("/countdown/([0-9]+)", CountdownHandler, name="countdown"), + url("/echopost", EchoPostHandler), + url("/user_agent", UserAgentHandler), + url("/304_with_content_length", ContentLength304Handler), + url("/all_methods", AllMethodsHandler), + url("/patch", PatchHandler), + url("/set_header", SetHeaderHandler), + url("/invalid_gzip", InvalidGzipHandler), + ], + gzip=True, + ) + + def test_patch_receives_payload(self): + body = b"some patch data" + response = self.fetch("/patch", method="PATCH", body=body) + self.assertEqual(response.code, 200) + self.assertEqual(response.body, body) + + @skipOnTravis + def test_hello_world(self): + response = self.fetch("/hello") + self.assertEqual(response.code, 200) + self.assertEqual(response.headers["Content-Type"], "text/plain") + self.assertEqual(response.body, b"Hello world!") + assert response.request_time is not None + self.assertEqual(int(response.request_time), 0) + + response = self.fetch("/hello?name=Ben") + self.assertEqual(response.body, b"Hello Ben!") + + def test_streaming_callback(self): + # streaming_callback is also tested in test_chunked + chunks = [] # type: typing.List[bytes] + response = self.fetch("/hello", streaming_callback=chunks.append) + # with streaming_callback, data goes to the callback and not response.body + self.assertEqual(chunks, [b"Hello world!"]) + self.assertFalse(response.body) + + def test_post(self): + response = self.fetch("/post", method="POST", body="arg1=foo&arg2=bar") + self.assertEqual(response.code, 200) + self.assertEqual(response.body, b"Post arg1: foo, arg2: bar") + + def test_chunked(self): + response = self.fetch("/chunk") + self.assertEqual(response.body, b"asdfqwer") + + chunks = [] # type: typing.List[bytes] + response = self.fetch("/chunk", streaming_callback=chunks.append) + self.assertEqual(chunks, [b"asdf", b"qwer"]) + self.assertFalse(response.body) + + def test_chunked_close(self): + # test case in which chunks spread read-callback processing + # over several ioloop iterations, but the connection is already closed. + sock, port = bind_unused_port() + with closing(sock): + + @gen.coroutine + def accept_callback(conn, address): + # fake an HTTP server using chunked encoding where the final chunks + # and connection close all happen at once + stream = IOStream(conn) + request_data = yield stream.read_until(b"\r\n\r\n") + if b"HTTP/1." not in request_data: + self.skipTest("requires HTTP/1.x") + yield stream.write( + b"""\ +HTTP/1.1 200 OK +Transfer-Encoding: chunked + +1 +1 +1 +2 +0 + +""".replace( + b"\n", b"\r\n" + ) + ) + stream.close() + + netutil.add_accept_handler(sock, accept_callback) # type: ignore + resp = self.fetch("http://127.0.0.1:%d/" % port) + resp.rethrow() + self.assertEqual(resp.body, b"12") + self.io_loop.remove_handler(sock.fileno()) + + def test_basic_auth(self): + # This test data appears in section 2 of RFC 7617. + self.assertEqual( + self.fetch( + "/auth", auth_username="Aladdin", auth_password="open sesame" + ).body, + b"Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==", + ) + + def test_basic_auth_explicit_mode(self): + self.assertEqual( + self.fetch( + "/auth", + auth_username="Aladdin", + auth_password="open sesame", + auth_mode="basic", + ).body, + b"Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==", + ) + + def test_basic_auth_unicode(self): + # This test data appears in section 2.1 of RFC 7617. + self.assertEqual( + self.fetch("/auth", auth_username="test", auth_password="123£").body, + b"Basic dGVzdDoxMjPCow==", + ) + + # The standard mandates NFC. Give it a decomposed username + # and ensure it is normalized to composed form. + username = unicodedata.normalize("NFD", u"josé") + self.assertEqual( + self.fetch("/auth", auth_username=username, auth_password="səcrət").body, + b"Basic am9zw6k6c8mZY3LJmXQ=", + ) + + def test_unsupported_auth_mode(self): + # curl and simple clients handle errors a bit differently; the + # important thing is that they don't fall back to basic auth + # on an unknown mode. + with ExpectLog(gen_log, "uncaught exception", required=False): + with self.assertRaises((ValueError, HTTPError)): # type: ignore + self.fetch( + "/auth", + auth_username="Aladdin", + auth_password="open sesame", + auth_mode="asdf", + raise_error=True, + ) + + def test_follow_redirect(self): + response = self.fetch("/countdown/2", follow_redirects=False) + self.assertEqual(302, response.code) + self.assertTrue(response.headers["Location"].endswith("/countdown/1")) + + response = self.fetch("/countdown/2") + self.assertEqual(200, response.code) + self.assertTrue(response.effective_url.endswith("/countdown/0")) + self.assertEqual(b"Zero", response.body) + + def test_redirect_without_location(self): + response = self.fetch("/redirect_without_location", follow_redirects=True) + # If there is no location header, the redirect response should + # just be returned as-is. (This should arguably raise an + # error, but libcurl doesn't treat this as an error, so we + # don't either). + self.assertEqual(301, response.code) + + def test_redirect_put_with_body(self): + response = self.fetch( + "/redirect?url=/put&status=307", method="PUT", body="hello" + ) + self.assertEqual(response.body, b"Put body: hello") + + def test_redirect_put_without_body(self): + # This "without body" edge case is similar to what happens with body_producer. + response = self.fetch( + "/redirect?url=/put&status=307", + method="PUT", + allow_nonstandard_methods=True, + ) + self.assertEqual(response.body, b"Put body: ") + + def test_method_after_redirect(self): + # Legacy redirect codes (301, 302) convert POST requests to GET. + for status in [301, 302, 303]: + url = "/redirect?url=/all_methods&status=%d" % status + resp = self.fetch(url, method="POST", body=b"") + self.assertEqual(b"GET", resp.body) + + # Other methods are left alone, except for 303 redirect, depending on client + for method in ["GET", "OPTIONS", "PUT", "DELETE"]: + resp = self.fetch(url, method=method, allow_nonstandard_methods=True) + if status in [301, 302]: + self.assertEqual(utf8(method), resp.body) + else: + self.assertIn(resp.body, [utf8(method), b"GET"]) + + # HEAD is different so check it separately. + resp = self.fetch(url, method="HEAD") + self.assertEqual(200, resp.code) + self.assertEqual(b"", resp.body) + + # Newer redirects always preserve the original method. + for status in [307, 308]: + url = "/redirect?url=/all_methods&status=307" + for method in ["GET", "OPTIONS", "POST", "PUT", "DELETE"]: + resp = self.fetch(url, method=method, allow_nonstandard_methods=True) + self.assertEqual(method, to_unicode(resp.body)) + resp = self.fetch(url, method="HEAD") + self.assertEqual(200, resp.code) + self.assertEqual(b"", resp.body) + + def test_credentials_in_url(self): + url = self.get_url("/auth").replace("http://", "http://me:secret@") + response = self.fetch(url) + self.assertEqual(b"Basic " + base64.b64encode(b"me:secret"), response.body) + + def test_body_encoding(self): + unicode_body = u"\xe9" + byte_body = binascii.a2b_hex(b"e9") + + # unicode string in body gets converted to utf8 + response = self.fetch( + "/echopost", + method="POST", + body=unicode_body, + headers={"Content-Type": "application/blah"}, + ) + self.assertEqual(response.headers["Content-Length"], "2") + self.assertEqual(response.body, utf8(unicode_body)) + + # byte strings pass through directly + response = self.fetch( + "/echopost", + method="POST", + body=byte_body, + headers={"Content-Type": "application/blah"}, + ) + self.assertEqual(response.headers["Content-Length"], "1") + self.assertEqual(response.body, byte_body) + + # Mixing unicode in headers and byte string bodies shouldn't + # break anything + response = self.fetch( + "/echopost", + method="POST", + body=byte_body, + headers={"Content-Type": "application/blah"}, + user_agent=u"foo", + ) + self.assertEqual(response.headers["Content-Length"], "1") + self.assertEqual(response.body, byte_body) + + def test_types(self): + response = self.fetch("/hello") + self.assertEqual(type(response.body), bytes) + self.assertEqual(type(response.headers["Content-Type"]), str) + self.assertEqual(type(response.code), int) + self.assertEqual(type(response.effective_url), str) + + def test_gzip(self): + # All the tests in this file should be using gzip, but this test + # ensures that it is in fact getting compressed, and also tests + # the httpclient's decompress=False option. + # Setting Accept-Encoding manually bypasses the client's + # decompression so we can see the raw data. + response = self.fetch( + "/chunk", decompress_response=False, headers={"Accept-Encoding": "gzip"} + ) + self.assertEqual(response.headers["Content-Encoding"], "gzip") + self.assertNotEqual(response.body, b"asdfqwer") + # Our test data gets bigger when gzipped. Oops. :) + # Chunked encoding bypasses the MIN_LENGTH check. + self.assertEqual(len(response.body), 34) + f = gzip.GzipFile(mode="r", fileobj=response.buffer) + self.assertEqual(f.read(), b"asdfqwer") + + def test_invalid_gzip(self): + # test if client hangs on tricky invalid gzip + # curl/simple httpclient have different behavior (exception, logging) + with ExpectLog( + app_log, "(Uncaught exception|Exception in callback)", required=False + ): + try: + response = self.fetch("/invalid_gzip") + self.assertEqual(response.code, 200) + self.assertEqual(response.body[:14], b"Hello World 0\n") + except HTTPError: + pass # acceptable + + def test_header_callback(self): + first_line = [] + headers = {} + chunks = [] + + def header_callback(header_line): + if header_line.startswith("HTTP/1.1 101"): + # Upgrading to HTTP/2 + pass + elif header_line.startswith("HTTP/"): + first_line.append(header_line) + elif header_line != "\r\n": + k, v = header_line.split(":", 1) + headers[k.lower()] = v.strip() + + def streaming_callback(chunk): + # All header callbacks are run before any streaming callbacks, + # so the header data is available to process the data as it + # comes in. + self.assertEqual(headers["content-type"], "text/html; charset=UTF-8") + chunks.append(chunk) + + self.fetch( + "/chunk", + header_callback=header_callback, + streaming_callback=streaming_callback, + ) + self.assertEqual(len(first_line), 1, first_line) + self.assertRegexpMatches(first_line[0], "HTTP/[0-9]\\.[0-9] 200.*\r\n") + self.assertEqual(chunks, [b"asdf", b"qwer"]) + + @gen_test + def test_configure_defaults(self): + defaults = dict(user_agent="TestDefaultUserAgent", allow_ipv6=False) + # Construct a new instance of the configured client class + client = self.http_client.__class__(force_instance=True, defaults=defaults) + try: + response = yield client.fetch(self.get_url("/user_agent")) + self.assertEqual(response.body, b"TestDefaultUserAgent") + finally: + client.close() + + def test_header_types(self): + # Header values may be passed as character or utf8 byte strings, + # in a plain dictionary or an HTTPHeaders object. + # Keys must always be the native str type. + # All combinations should have the same results on the wire. + for value in [u"MyUserAgent", b"MyUserAgent"]: + for container in [dict, HTTPHeaders]: + headers = container() + headers["User-Agent"] = value + resp = self.fetch("/user_agent", headers=headers) + self.assertEqual( + resp.body, + b"MyUserAgent", + "response=%r, value=%r, container=%r" + % (resp.body, value, container), + ) + + def test_multi_line_headers(self): + # Multi-line http headers are rare but rfc-allowed + # http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 + sock, port = bind_unused_port() + with closing(sock): + + @gen.coroutine + def accept_callback(conn, address): + stream = IOStream(conn) + request_data = yield stream.read_until(b"\r\n\r\n") + if b"HTTP/1." not in request_data: + self.skipTest("requires HTTP/1.x") + yield stream.write( + b"""\ +HTTP/1.1 200 OK +X-XSS-Protection: 1; +\tmode=block + +""".replace( + b"\n", b"\r\n" + ) + ) + stream.close() + + netutil.add_accept_handler(sock, accept_callback) # type: ignore + try: + resp = self.fetch("http://127.0.0.1:%d/" % port) + resp.rethrow() + self.assertEqual(resp.headers["X-XSS-Protection"], "1; mode=block") + finally: + self.io_loop.remove_handler(sock.fileno()) + + def test_304_with_content_length(self): + # According to the spec 304 responses SHOULD NOT include + # Content-Length or other entity headers, but some servers do it + # anyway. + # http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5 + response = self.fetch("/304_with_content_length") + self.assertEqual(response.code, 304) + self.assertEqual(response.headers["Content-Length"], "42") + + @gen_test + def test_future_interface(self): + response = yield self.http_client.fetch(self.get_url("/hello")) + self.assertEqual(response.body, b"Hello world!") + + @gen_test + def test_future_http_error(self): + with self.assertRaises(HTTPError) as context: + yield self.http_client.fetch(self.get_url("/notfound")) + assert context.exception is not None + assert context.exception.response is not None + self.assertEqual(context.exception.code, 404) + self.assertEqual(context.exception.response.code, 404) + + @gen_test + def test_future_http_error_no_raise(self): + response = yield self.http_client.fetch( + self.get_url("/notfound"), raise_error=False + ) + self.assertEqual(response.code, 404) + + @gen_test + def test_reuse_request_from_response(self): + # The response.request attribute should be an HTTPRequest, not + # a _RequestProxy. + # This test uses self.http_client.fetch because self.fetch calls + # self.get_url on the input unconditionally. + url = self.get_url("/hello") + response = yield self.http_client.fetch(url) + self.assertEqual(response.request.url, url) + self.assertTrue(isinstance(response.request, HTTPRequest)) + response2 = yield self.http_client.fetch(response.request) + self.assertEqual(response2.body, b"Hello world!") + + @gen_test + def test_bind_source_ip(self): + url = self.get_url("/hello") + request = HTTPRequest(url, network_interface="127.0.0.1") + response = yield self.http_client.fetch(request) + self.assertEqual(response.code, 200) + + with self.assertRaises((ValueError, HTTPError)) as context: # type: ignore + request = HTTPRequest(url, network_interface="not-interface-or-ip") + yield self.http_client.fetch(request) + self.assertIn("not-interface-or-ip", str(context.exception)) + + def test_all_methods(self): + for method in ["GET", "DELETE", "OPTIONS"]: + response = self.fetch("/all_methods", method=method) + self.assertEqual(response.body, utf8(method)) + for method in ["POST", "PUT", "PATCH"]: + response = self.fetch("/all_methods", method=method, body=b"") + self.assertEqual(response.body, utf8(method)) + response = self.fetch("/all_methods", method="HEAD") + self.assertEqual(response.body, b"") + response = self.fetch( + "/all_methods", method="OTHER", allow_nonstandard_methods=True + ) + self.assertEqual(response.body, b"OTHER") + + def test_body_sanity_checks(self): + # These methods require a body. + for method in ("POST", "PUT", "PATCH"): + with self.assertRaises(ValueError) as context: + self.fetch("/all_methods", method=method, raise_error=True) + self.assertIn("must not be None", str(context.exception)) + + resp = self.fetch( + "/all_methods", method=method, allow_nonstandard_methods=True + ) + self.assertEqual(resp.code, 200) + + # These methods don't allow a body. + for method in ("GET", "DELETE", "OPTIONS"): + with self.assertRaises(ValueError) as context: + self.fetch( + "/all_methods", method=method, body=b"asdf", raise_error=True + ) + self.assertIn("must be None", str(context.exception)) + + # In most cases this can be overridden, but curl_httpclient + # does not allow body with a GET at all. + if method != "GET": + self.fetch( + "/all_methods", + method=method, + body=b"asdf", + allow_nonstandard_methods=True, + raise_error=True, + ) + self.assertEqual(resp.code, 200) + + # This test causes odd failures with the combination of + # curl_httpclient (at least with the version of libcurl available + # on ubuntu 12.04), TwistedIOLoop, and epoll. For POST (but not PUT), + # curl decides the response came back too soon and closes the connection + # to start again. It does this *before* telling the socket callback to + # unregister the FD. Some IOLoop implementations have special kernel + # integration to discover this immediately. Tornado's IOLoops + # ignore errors on remove_handler to accommodate this behavior, but + # Twisted's reactor does not. The removeReader call fails and so + # do all future removeAll calls (which our tests do at cleanup). + # + # def test_post_307(self): + # response = self.fetch("/redirect?status=307&url=/post", + # method="POST", body=b"arg1=foo&arg2=bar") + # self.assertEqual(response.body, b"Post arg1: foo, arg2: bar") + + def test_put_307(self): + response = self.fetch( + "/redirect?status=307&url=/put", method="PUT", body=b"hello" + ) + response.rethrow() + self.assertEqual(response.body, b"Put body: hello") + + def test_non_ascii_header(self): + # Non-ascii headers are sent as latin1. + response = self.fetch("/set_header?k=foo&v=%E9") + response.rethrow() + self.assertEqual(response.headers["Foo"], native_str(u"\u00e9")) + + def test_response_times(self): + # A few simple sanity checks of the response time fields to + # make sure they're using the right basis (between the + # wall-time and monotonic clocks). + start_time = time.time() + response = self.fetch("/hello") + response.rethrow() + self.assertGreaterEqual(response.request_time, 0) + self.assertLess(response.request_time, 1.0) + # A very crude check to make sure that start_time is based on + # wall time and not the monotonic clock. + assert response.start_time is not None + self.assertLess(abs(response.start_time - start_time), 1.0) + + for k, v in response.time_info.items(): + self.assertTrue(0 <= v < 1.0, "time_info[%s] out of bounds: %s" % (k, v)) + + def test_zero_timeout(self): + response = self.fetch("/hello", connect_timeout=0) + self.assertEqual(response.code, 200) + + response = self.fetch("/hello", request_timeout=0) + self.assertEqual(response.code, 200) + + response = self.fetch("/hello", connect_timeout=0, request_timeout=0) + self.assertEqual(response.code, 200) + + @gen_test + def test_error_after_cancel(self): + fut = self.http_client.fetch(self.get_url("/404")) + self.assertTrue(fut.cancel()) + with ExpectLog(app_log, "Exception after Future was cancelled") as el: + # We can't wait on the cancelled Future any more, so just + # let the IOLoop run until the exception gets logged (or + # not, in which case we exit the loop and ExpectLog will + # raise). + for i in range(100): + yield gen.sleep(0.01) + if el.logged_stack: + break + + +class RequestProxyTest(unittest.TestCase): + def test_request_set(self): + proxy = _RequestProxy( + HTTPRequest("http://example.com/", user_agent="foo"), dict() + ) + self.assertEqual(proxy.user_agent, "foo") + + def test_default_set(self): + proxy = _RequestProxy( + HTTPRequest("http://example.com/"), dict(network_interface="foo") + ) + self.assertEqual(proxy.network_interface, "foo") + + def test_both_set(self): + proxy = _RequestProxy( + HTTPRequest("http://example.com/", proxy_host="foo"), dict(proxy_host="bar") + ) + self.assertEqual(proxy.proxy_host, "foo") + + def test_neither_set(self): + proxy = _RequestProxy(HTTPRequest("http://example.com/"), dict()) + self.assertIs(proxy.auth_username, None) + + def test_bad_attribute(self): + proxy = _RequestProxy(HTTPRequest("http://example.com/"), dict()) + with self.assertRaises(AttributeError): + proxy.foo + + def test_defaults_none(self): + proxy = _RequestProxy(HTTPRequest("http://example.com/"), None) + self.assertIs(proxy.auth_username, None) + + +class HTTPResponseTestCase(unittest.TestCase): + def test_str(self): + response = HTTPResponse( # type: ignore + HTTPRequest("http://example.com"), 200, buffer=BytesIO() + ) + s = str(response) + self.assertTrue(s.startswith("HTTPResponse(")) + self.assertIn("code=200", s) + + +class SyncHTTPClientTest(unittest.TestCase): + def setUp(self): + self.server_ioloop = IOLoop() + event = threading.Event() + + @gen.coroutine + def init_server(): + sock, self.port = bind_unused_port() + app = Application([("/", HelloWorldHandler)]) + self.server = HTTPServer(app) + self.server.add_socket(sock) + event.set() + + def start(): + self.server_ioloop.run_sync(init_server) + self.server_ioloop.start() + + self.server_thread = threading.Thread(target=start) + self.server_thread.start() + event.wait() + + self.http_client = HTTPClient() + + def tearDown(self): + def stop_server(): + self.server.stop() + # Delay the shutdown of the IOLoop by several iterations because + # the server may still have some cleanup work left when + # the client finishes with the response (this is noticeable + # with http/2, which leaves a Future with an unexamined + # StreamClosedError on the loop). + + @gen.coroutine + def slow_stop(): + yield self.server.close_all_connections() + # The number of iterations is difficult to predict. Typically, + # one is sufficient, although sometimes it needs more. + for i in range(5): + yield + self.server_ioloop.stop() + + self.server_ioloop.add_callback(slow_stop) + + self.server_ioloop.add_callback(stop_server) + self.server_thread.join() + self.http_client.close() + self.server_ioloop.close(all_fds=True) + + def get_url(self, path): + return "http://127.0.0.1:%d%s" % (self.port, path) + + def test_sync_client(self): + response = self.http_client.fetch(self.get_url("/")) + self.assertEqual(b"Hello world!", response.body) + + def test_sync_client_error(self): + # Synchronous HTTPClient raises errors directly; no need for + # response.rethrow() + with self.assertRaises(HTTPError) as assertion: + self.http_client.fetch(self.get_url("/notfound")) + self.assertEqual(assertion.exception.code, 404) + + +class SyncHTTPClientSubprocessTest(unittest.TestCase): + def test_destructor_log(self): + # Regression test for + # https://github.com/tornadoweb/tornado/issues/2539 + # + # In the past, the following program would log an + # "inconsistent AsyncHTTPClient cache" error from a destructor + # when the process is shutting down. The shutdown process is + # subtle and I don't fully understand it; the failure does not + # manifest if that lambda isn't there or is a simpler object + # like an int (nor does it manifest in the tornado test suite + # as a whole, which is why we use this subprocess). + proc = subprocess.run( + [ + sys.executable, + "-c", + "from tornado.httpclient import HTTPClient; f = lambda: None; c = HTTPClient()", + ], + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + check=True, + timeout=5, + ) + if proc.stdout: + print("STDOUT:") + print(to_unicode(proc.stdout)) + if proc.stdout: + self.fail("subprocess produced unexpected output") + + +class HTTPRequestTestCase(unittest.TestCase): + def test_headers(self): + request = HTTPRequest("http://example.com", headers={"foo": "bar"}) + self.assertEqual(request.headers, {"foo": "bar"}) + + def test_headers_setter(self): + request = HTTPRequest("http://example.com") + request.headers = {"bar": "baz"} # type: ignore + self.assertEqual(request.headers, {"bar": "baz"}) + + def test_null_headers_setter(self): + request = HTTPRequest("http://example.com") + request.headers = None # type: ignore + self.assertEqual(request.headers, {}) + + def test_body(self): + request = HTTPRequest("http://example.com", body="foo") + self.assertEqual(request.body, utf8("foo")) + + def test_body_setter(self): + request = HTTPRequest("http://example.com") + request.body = "foo" # type: ignore + self.assertEqual(request.body, utf8("foo")) + + def test_if_modified_since(self): + http_date = datetime.datetime.utcnow() + request = HTTPRequest("http://example.com", if_modified_since=http_date) + self.assertEqual( + request.headers, {"If-Modified-Since": format_timestamp(http_date)} + ) + + +class HTTPErrorTestCase(unittest.TestCase): + def test_copy(self): + e = HTTPError(403) + e2 = copy.copy(e) + self.assertIsNot(e, e2) + self.assertEqual(e.code, e2.code) + + def test_plain_error(self): + e = HTTPError(403) + self.assertEqual(str(e), "HTTP 403: Forbidden") + self.assertEqual(repr(e), "HTTP 403: Forbidden") + + def test_error_with_response(self): + resp = HTTPResponse(HTTPRequest("http://example.com/"), 403) + with self.assertRaises(HTTPError) as cm: + resp.rethrow() + e = cm.exception + self.assertEqual(str(e), "HTTP 403: Forbidden") + self.assertEqual(repr(e), "HTTP 403: Forbidden") diff --git a/venv/lib/python3.8/site-packages/tornado/test/httpserver_test.py b/venv/lib/python3.8/site-packages/tornado/test/httpserver_test.py new file mode 100644 index 0000000..614dec7 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/httpserver_test.py @@ -0,0 +1,1339 @@ +from tornado import gen, netutil +from tornado.escape import ( + json_decode, + json_encode, + utf8, + _unicode, + recursive_unicode, + native_str, +) +from tornado.http1connection import HTTP1Connection +from tornado.httpclient import HTTPError +from tornado.httpserver import HTTPServer +from tornado.httputil import ( + HTTPHeaders, + HTTPMessageDelegate, + HTTPServerConnectionDelegate, + ResponseStartLine, +) +from tornado.iostream import IOStream +from tornado.locks import Event +from tornado.log import gen_log +from tornado.netutil import ssl_options_to_context +from tornado.simple_httpclient import SimpleAsyncHTTPClient +from tornado.testing import ( + AsyncHTTPTestCase, + AsyncHTTPSTestCase, + AsyncTestCase, + ExpectLog, + gen_test, +) +from tornado.test.util import skipOnTravis +from tornado.web import Application, RequestHandler, stream_request_body + +from contextlib import closing +import datetime +import gzip +import logging +import os +import shutil +import socket +import ssl +import sys +import tempfile +import unittest +import urllib.parse +from io import BytesIO + +import typing + +if typing.TYPE_CHECKING: + from typing import Dict, List # noqa: F401 + + +async def read_stream_body(stream): + """Reads an HTTP response from `stream` and returns a tuple of its + start_line, headers and body.""" + chunks = [] + + class Delegate(HTTPMessageDelegate): + def headers_received(self, start_line, headers): + self.headers = headers + self.start_line = start_line + + def data_received(self, chunk): + chunks.append(chunk) + + def finish(self): + conn.detach() # type: ignore + + conn = HTTP1Connection(stream, True) + delegate = Delegate() + await conn.read_response(delegate) + return delegate.start_line, delegate.headers, b"".join(chunks) + + +class HandlerBaseTestCase(AsyncHTTPTestCase): + Handler = None + + def get_app(self): + return Application([("/", self.__class__.Handler)]) + + def fetch_json(self, *args, **kwargs): + response = self.fetch(*args, **kwargs) + response.rethrow() + return json_decode(response.body) + + +class HelloWorldRequestHandler(RequestHandler): + def initialize(self, protocol="http"): + self.expected_protocol = protocol + + def get(self): + if self.request.protocol != self.expected_protocol: + raise Exception("unexpected protocol") + self.finish("Hello world") + + def post(self): + self.finish("Got %d bytes in POST" % len(self.request.body)) + + +# In pre-1.0 versions of openssl, SSLv23 clients always send SSLv2 +# ClientHello messages, which are rejected by SSLv3 and TLSv1 +# servers. Note that while the OPENSSL_VERSION_INFO was formally +# introduced in python3.2, it was present but undocumented in +# python 2.7 +skipIfOldSSL = unittest.skipIf( + getattr(ssl, "OPENSSL_VERSION_INFO", (0, 0)) < (1, 0), + "old version of ssl module and/or openssl", +) + + +class BaseSSLTest(AsyncHTTPSTestCase): + def get_app(self): + return Application([("/", HelloWorldRequestHandler, dict(protocol="https"))]) + + +class SSLTestMixin(object): + def get_ssl_options(self): + return dict( + ssl_version=self.get_ssl_version(), + **AsyncHTTPSTestCase.default_ssl_options() + ) + + def get_ssl_version(self): + raise NotImplementedError() + + def test_ssl(self: typing.Any): + response = self.fetch("/") + self.assertEqual(response.body, b"Hello world") + + def test_large_post(self: typing.Any): + response = self.fetch("/", method="POST", body="A" * 5000) + self.assertEqual(response.body, b"Got 5000 bytes in POST") + + def test_non_ssl_request(self: typing.Any): + # Make sure the server closes the connection when it gets a non-ssl + # connection, rather than waiting for a timeout or otherwise + # misbehaving. + with ExpectLog(gen_log, "(SSL Error|uncaught exception)"): + with ExpectLog(gen_log, "Uncaught exception", required=False): + with self.assertRaises((IOError, HTTPError)): # type: ignore + self.fetch( + self.get_url("/").replace("https:", "http:"), + request_timeout=3600, + connect_timeout=3600, + raise_error=True, + ) + + def test_error_logging(self: typing.Any): + # No stack traces are logged for SSL errors. + with ExpectLog(gen_log, "SSL Error") as expect_log: + with self.assertRaises((IOError, HTTPError)): # type: ignore + self.fetch( + self.get_url("/").replace("https:", "http:"), raise_error=True + ) + self.assertFalse(expect_log.logged_stack) + + +# Python's SSL implementation differs significantly between versions. +# For example, SSLv3 and TLSv1 throw an exception if you try to read +# from the socket before the handshake is complete, but the default +# of SSLv23 allows it. + + +class SSLv23Test(BaseSSLTest, SSLTestMixin): + def get_ssl_version(self): + return ssl.PROTOCOL_SSLv23 + + +@skipIfOldSSL +class SSLv3Test(BaseSSLTest, SSLTestMixin): + def get_ssl_version(self): + return ssl.PROTOCOL_SSLv3 + + +@skipIfOldSSL +class TLSv1Test(BaseSSLTest, SSLTestMixin): + def get_ssl_version(self): + return ssl.PROTOCOL_TLSv1 + + +class SSLContextTest(BaseSSLTest, SSLTestMixin): + def get_ssl_options(self): + context = ssl_options_to_context(AsyncHTTPSTestCase.get_ssl_options(self)) + assert isinstance(context, ssl.SSLContext) + return context + + +class BadSSLOptionsTest(unittest.TestCase): + def test_missing_arguments(self): + application = Application() + self.assertRaises( + KeyError, + HTTPServer, + application, + ssl_options={"keyfile": "/__missing__.crt"}, + ) + + def test_missing_key(self): + """A missing SSL key should cause an immediate exception.""" + + application = Application() + module_dir = os.path.dirname(__file__) + existing_certificate = os.path.join(module_dir, "test.crt") + existing_key = os.path.join(module_dir, "test.key") + + self.assertRaises( + (ValueError, IOError), + HTTPServer, + application, + ssl_options={"certfile": "/__mising__.crt"}, + ) + self.assertRaises( + (ValueError, IOError), + HTTPServer, + application, + ssl_options={ + "certfile": existing_certificate, + "keyfile": "/__missing__.key", + }, + ) + + # This actually works because both files exist + HTTPServer( + application, + ssl_options={"certfile": existing_certificate, "keyfile": existing_key}, + ) + + +class MultipartTestHandler(RequestHandler): + def post(self): + self.finish( + { + "header": self.request.headers["X-Header-Encoding-Test"], + "argument": self.get_argument("argument"), + "filename": self.request.files["files"][0].filename, + "filebody": _unicode(self.request.files["files"][0]["body"]), + } + ) + + +# This test is also called from wsgi_test +class HTTPConnectionTest(AsyncHTTPTestCase): + def get_handlers(self): + return [ + ("/multipart", MultipartTestHandler), + ("/hello", HelloWorldRequestHandler), + ] + + def get_app(self): + return Application(self.get_handlers()) + + def raw_fetch(self, headers, body, newline=b"\r\n"): + with closing(IOStream(socket.socket())) as stream: + self.io_loop.run_sync( + lambda: stream.connect(("127.0.0.1", self.get_http_port())) + ) + stream.write( + newline.join(headers + [utf8("Content-Length: %d" % len(body))]) + + newline + + newline + + body + ) + start_line, headers, body = self.io_loop.run_sync( + lambda: read_stream_body(stream) + ) + return body + + def test_multipart_form(self): + # Encodings here are tricky: Headers are latin1, bodies can be + # anything (we use utf8 by default). + response = self.raw_fetch( + [ + b"POST /multipart HTTP/1.0", + b"Content-Type: multipart/form-data; boundary=1234567890", + b"X-Header-encoding-test: \xe9", + ], + b"\r\n".join( + [ + b"Content-Disposition: form-data; name=argument", + b"", + u"\u00e1".encode("utf-8"), + b"--1234567890", + u'Content-Disposition: form-data; name="files"; filename="\u00f3"'.encode( + "utf8" + ), + b"", + u"\u00fa".encode("utf-8"), + b"--1234567890--", + b"", + ] + ), + ) + data = json_decode(response) + self.assertEqual(u"\u00e9", data["header"]) + self.assertEqual(u"\u00e1", data["argument"]) + self.assertEqual(u"\u00f3", data["filename"]) + self.assertEqual(u"\u00fa", data["filebody"]) + + def test_newlines(self): + # We support both CRLF and bare LF as line separators. + for newline in (b"\r\n", b"\n"): + response = self.raw_fetch([b"GET /hello HTTP/1.0"], b"", newline=newline) + self.assertEqual(response, b"Hello world") + + @gen_test + def test_100_continue(self): + # Run through a 100-continue interaction by hand: + # When given Expect: 100-continue, we get a 100 response after the + # headers, and then the real response after the body. + stream = IOStream(socket.socket()) + yield stream.connect(("127.0.0.1", self.get_http_port())) + yield stream.write( + b"\r\n".join( + [ + b"POST /hello HTTP/1.1", + b"Content-Length: 1024", + b"Expect: 100-continue", + b"Connection: close", + b"\r\n", + ] + ) + ) + data = yield stream.read_until(b"\r\n\r\n") + self.assertTrue(data.startswith(b"HTTP/1.1 100 "), data) + stream.write(b"a" * 1024) + first_line = yield stream.read_until(b"\r\n") + self.assertTrue(first_line.startswith(b"HTTP/1.1 200"), first_line) + header_data = yield stream.read_until(b"\r\n\r\n") + headers = HTTPHeaders.parse(native_str(header_data.decode("latin1"))) + body = yield stream.read_bytes(int(headers["Content-Length"])) + self.assertEqual(body, b"Got 1024 bytes in POST") + stream.close() + + +class EchoHandler(RequestHandler): + def get(self): + self.write(recursive_unicode(self.request.arguments)) + + def post(self): + self.write(recursive_unicode(self.request.arguments)) + + +class TypeCheckHandler(RequestHandler): + def prepare(self): + self.errors = {} # type: Dict[str, str] + fields = [ + ("method", str), + ("uri", str), + ("version", str), + ("remote_ip", str), + ("protocol", str), + ("host", str), + ("path", str), + ("query", str), + ] + for field, expected_type in fields: + self.check_type(field, getattr(self.request, field), expected_type) + + self.check_type("header_key", list(self.request.headers.keys())[0], str) + self.check_type("header_value", list(self.request.headers.values())[0], str) + + self.check_type("cookie_key", list(self.request.cookies.keys())[0], str) + self.check_type( + "cookie_value", list(self.request.cookies.values())[0].value, str + ) + # secure cookies + + self.check_type("arg_key", list(self.request.arguments.keys())[0], str) + self.check_type("arg_value", list(self.request.arguments.values())[0][0], bytes) + + def post(self): + self.check_type("body", self.request.body, bytes) + self.write(self.errors) + + def get(self): + self.write(self.errors) + + def check_type(self, name, obj, expected_type): + actual_type = type(obj) + if expected_type != actual_type: + self.errors[name] = "expected %s, got %s" % (expected_type, actual_type) + + +class PostEchoHandler(RequestHandler): + def post(self, *path_args): + self.write(dict(echo=self.get_argument("data"))) + + +class PostEchoGBKHandler(PostEchoHandler): + def decode_argument(self, value, name=None): + try: + return value.decode("gbk") + except Exception: + raise HTTPError(400, "invalid gbk bytes: %r" % value) + + +class HTTPServerTest(AsyncHTTPTestCase): + def get_app(self): + return Application( + [ + ("/echo", EchoHandler), + ("/typecheck", TypeCheckHandler), + ("//doubleslash", EchoHandler), + ("/post_utf8", PostEchoHandler), + ("/post_gbk", PostEchoGBKHandler), + ] + ) + + def test_query_string_encoding(self): + response = self.fetch("/echo?foo=%C3%A9") + data = json_decode(response.body) + self.assertEqual(data, {u"foo": [u"\u00e9"]}) + + def test_empty_query_string(self): + response = self.fetch("/echo?foo=&foo=") + data = json_decode(response.body) + self.assertEqual(data, {u"foo": [u"", u""]}) + + def test_empty_post_parameters(self): + response = self.fetch("/echo", method="POST", body="foo=&bar=") + data = json_decode(response.body) + self.assertEqual(data, {u"foo": [u""], u"bar": [u""]}) + + def test_types(self): + headers = {"Cookie": "foo=bar"} + response = self.fetch("/typecheck?foo=bar", headers=headers) + data = json_decode(response.body) + self.assertEqual(data, {}) + + response = self.fetch( + "/typecheck", method="POST", body="foo=bar", headers=headers + ) + data = json_decode(response.body) + self.assertEqual(data, {}) + + def test_double_slash(self): + # urlparse.urlsplit (which tornado.httpserver used to use + # incorrectly) would parse paths beginning with "//" as + # protocol-relative urls. + response = self.fetch("//doubleslash") + self.assertEqual(200, response.code) + self.assertEqual(json_decode(response.body), {}) + + def test_post_encodings(self): + headers = {"Content-Type": "application/x-www-form-urlencoded"} + uni_text = "chinese: \u5f20\u4e09" + for enc in ("utf8", "gbk"): + for quote in (True, False): + with self.subTest(enc=enc, quote=quote): + bin_text = uni_text.encode(enc) + if quote: + bin_text = urllib.parse.quote(bin_text).encode("ascii") + response = self.fetch( + "/post_" + enc, + method="POST", + headers=headers, + body=(b"data=" + bin_text), + ) + self.assertEqual(json_decode(response.body), {"echo": uni_text}) + + +class HTTPServerRawTest(AsyncHTTPTestCase): + def get_app(self): + return Application([("/echo", EchoHandler)]) + + def setUp(self): + super().setUp() + self.stream = IOStream(socket.socket()) + self.io_loop.run_sync( + lambda: self.stream.connect(("127.0.0.1", self.get_http_port())) + ) + + def tearDown(self): + self.stream.close() + super().tearDown() + + def test_empty_request(self): + self.stream.close() + self.io_loop.add_timeout(datetime.timedelta(seconds=0.001), self.stop) + self.wait() + + def test_malformed_first_line_response(self): + with ExpectLog(gen_log, ".*Malformed HTTP request line", level=logging.INFO): + self.stream.write(b"asdf\r\n\r\n") + start_line, headers, response = self.io_loop.run_sync( + lambda: read_stream_body(self.stream) + ) + self.assertEqual("HTTP/1.1", start_line.version) + self.assertEqual(400, start_line.code) + self.assertEqual("Bad Request", start_line.reason) + + def test_malformed_first_line_log(self): + with ExpectLog(gen_log, ".*Malformed HTTP request line", level=logging.INFO): + self.stream.write(b"asdf\r\n\r\n") + # TODO: need an async version of ExpectLog so we don't need + # hard-coded timeouts here. + self.io_loop.add_timeout(datetime.timedelta(seconds=0.05), self.stop) + self.wait() + + def test_malformed_headers(self): + with ExpectLog( + gen_log, + ".*Malformed HTTP message.*no colon in header line", + level=logging.INFO, + ): + self.stream.write(b"GET / HTTP/1.0\r\nasdf\r\n\r\n") + self.io_loop.add_timeout(datetime.timedelta(seconds=0.05), self.stop) + self.wait() + + def test_chunked_request_body(self): + # Chunked requests are not widely supported and we don't have a way + # to generate them in AsyncHTTPClient, but HTTPServer will read them. + self.stream.write( + b"""\ +POST /echo HTTP/1.1 +Transfer-Encoding: chunked +Content-Type: application/x-www-form-urlencoded + +4 +foo= +3 +bar +0 + +""".replace( + b"\n", b"\r\n" + ) + ) + start_line, headers, response = self.io_loop.run_sync( + lambda: read_stream_body(self.stream) + ) + self.assertEqual(json_decode(response), {u"foo": [u"bar"]}) + + def test_chunked_request_uppercase(self): + # As per RFC 2616 section 3.6, "Transfer-Encoding" header's value is + # case-insensitive. + self.stream.write( + b"""\ +POST /echo HTTP/1.1 +Transfer-Encoding: Chunked +Content-Type: application/x-www-form-urlencoded + +4 +foo= +3 +bar +0 + +""".replace( + b"\n", b"\r\n" + ) + ) + start_line, headers, response = self.io_loop.run_sync( + lambda: read_stream_body(self.stream) + ) + self.assertEqual(json_decode(response), {u"foo": [u"bar"]}) + + @gen_test + def test_invalid_content_length(self): + with ExpectLog( + gen_log, ".*Only integer Content-Length is allowed", level=logging.INFO + ): + self.stream.write( + b"""\ +POST /echo HTTP/1.1 +Content-Length: foo + +bar + +""".replace( + b"\n", b"\r\n" + ) + ) + yield self.stream.read_until_close() + + +class XHeaderTest(HandlerBaseTestCase): + class Handler(RequestHandler): + def get(self): + self.set_header("request-version", self.request.version) + self.write( + dict( + remote_ip=self.request.remote_ip, + remote_protocol=self.request.protocol, + ) + ) + + def get_httpserver_options(self): + return dict(xheaders=True, trusted_downstream=["5.5.5.5"]) + + def test_ip_headers(self): + self.assertEqual(self.fetch_json("/")["remote_ip"], "127.0.0.1") + + valid_ipv4 = {"X-Real-IP": "4.4.4.4"} + self.assertEqual( + self.fetch_json("/", headers=valid_ipv4)["remote_ip"], "4.4.4.4" + ) + + valid_ipv4_list = {"X-Forwarded-For": "127.0.0.1, 4.4.4.4"} + self.assertEqual( + self.fetch_json("/", headers=valid_ipv4_list)["remote_ip"], "4.4.4.4" + ) + + valid_ipv6 = {"X-Real-IP": "2620:0:1cfe:face:b00c::3"} + self.assertEqual( + self.fetch_json("/", headers=valid_ipv6)["remote_ip"], + "2620:0:1cfe:face:b00c::3", + ) + + valid_ipv6_list = {"X-Forwarded-For": "::1, 2620:0:1cfe:face:b00c::3"} + self.assertEqual( + self.fetch_json("/", headers=valid_ipv6_list)["remote_ip"], + "2620:0:1cfe:face:b00c::3", + ) + + invalid_chars = {"X-Real-IP": "4.4.4.4<script>"} + self.assertEqual( + self.fetch_json("/", headers=invalid_chars)["remote_ip"], "127.0.0.1" + ) + + invalid_chars_list = {"X-Forwarded-For": "4.4.4.4, 5.5.5.5<script>"} + self.assertEqual( + self.fetch_json("/", headers=invalid_chars_list)["remote_ip"], "127.0.0.1" + ) + + invalid_host = {"X-Real-IP": "www.google.com"} + self.assertEqual( + self.fetch_json("/", headers=invalid_host)["remote_ip"], "127.0.0.1" + ) + + def test_trusted_downstream(self): + valid_ipv4_list = {"X-Forwarded-For": "127.0.0.1, 4.4.4.4, 5.5.5.5"} + resp = self.fetch("/", headers=valid_ipv4_list) + if resp.headers["request-version"].startswith("HTTP/2"): + # This is a hack - there's nothing that fundamentally requires http/1 + # here but tornado_http2 doesn't support it yet. + self.skipTest("requires HTTP/1.x") + result = json_decode(resp.body) + self.assertEqual(result["remote_ip"], "4.4.4.4") + + def test_scheme_headers(self): + self.assertEqual(self.fetch_json("/")["remote_protocol"], "http") + + https_scheme = {"X-Scheme": "https"} + self.assertEqual( + self.fetch_json("/", headers=https_scheme)["remote_protocol"], "https" + ) + + https_forwarded = {"X-Forwarded-Proto": "https"} + self.assertEqual( + self.fetch_json("/", headers=https_forwarded)["remote_protocol"], "https" + ) + + https_multi_forwarded = {"X-Forwarded-Proto": "https , http"} + self.assertEqual( + self.fetch_json("/", headers=https_multi_forwarded)["remote_protocol"], + "http", + ) + + http_multi_forwarded = {"X-Forwarded-Proto": "http,https"} + self.assertEqual( + self.fetch_json("/", headers=http_multi_forwarded)["remote_protocol"], + "https", + ) + + bad_forwarded = {"X-Forwarded-Proto": "unknown"} + self.assertEqual( + self.fetch_json("/", headers=bad_forwarded)["remote_protocol"], "http" + ) + + +class SSLXHeaderTest(AsyncHTTPSTestCase, HandlerBaseTestCase): + def get_app(self): + return Application([("/", XHeaderTest.Handler)]) + + def get_httpserver_options(self): + output = super().get_httpserver_options() + output["xheaders"] = True + return output + + def test_request_without_xprotocol(self): + self.assertEqual(self.fetch_json("/")["remote_protocol"], "https") + + http_scheme = {"X-Scheme": "http"} + self.assertEqual( + self.fetch_json("/", headers=http_scheme)["remote_protocol"], "http" + ) + + bad_scheme = {"X-Scheme": "unknown"} + self.assertEqual( + self.fetch_json("/", headers=bad_scheme)["remote_protocol"], "https" + ) + + +class ManualProtocolTest(HandlerBaseTestCase): + class Handler(RequestHandler): + def get(self): + self.write(dict(protocol=self.request.protocol)) + + def get_httpserver_options(self): + return dict(protocol="https") + + def test_manual_protocol(self): + self.assertEqual(self.fetch_json("/")["protocol"], "https") + + +@unittest.skipIf( + not hasattr(socket, "AF_UNIX") or sys.platform == "cygwin", + "unix sockets not supported on this platform", +) +class UnixSocketTest(AsyncTestCase): + """HTTPServers can listen on Unix sockets too. + + Why would you want to do this? Nginx can proxy to backends listening + on unix sockets, for one thing (and managing a namespace for unix + sockets can be easier than managing a bunch of TCP port numbers). + + Unfortunately, there's no way to specify a unix socket in a url for + an HTTP client, so we have to test this by hand. + """ + + def setUp(self): + super().setUp() + self.tmpdir = tempfile.mkdtemp() + self.sockfile = os.path.join(self.tmpdir, "test.sock") + sock = netutil.bind_unix_socket(self.sockfile) + app = Application([("/hello", HelloWorldRequestHandler)]) + self.server = HTTPServer(app) + self.server.add_socket(sock) + self.stream = IOStream(socket.socket(socket.AF_UNIX)) + self.io_loop.run_sync(lambda: self.stream.connect(self.sockfile)) + + def tearDown(self): + self.stream.close() + self.io_loop.run_sync(self.server.close_all_connections) + self.server.stop() + shutil.rmtree(self.tmpdir) + super().tearDown() + + @gen_test + def test_unix_socket(self): + self.stream.write(b"GET /hello HTTP/1.0\r\n\r\n") + response = yield self.stream.read_until(b"\r\n") + self.assertEqual(response, b"HTTP/1.1 200 OK\r\n") + header_data = yield self.stream.read_until(b"\r\n\r\n") + headers = HTTPHeaders.parse(header_data.decode("latin1")) + body = yield self.stream.read_bytes(int(headers["Content-Length"])) + self.assertEqual(body, b"Hello world") + + @gen_test + def test_unix_socket_bad_request(self): + # Unix sockets don't have remote addresses so they just return an + # empty string. + with ExpectLog(gen_log, "Malformed HTTP message from"): + self.stream.write(b"garbage\r\n\r\n") + response = yield self.stream.read_until_close() + self.assertEqual(response, b"HTTP/1.1 400 Bad Request\r\n\r\n") + + +class KeepAliveTest(AsyncHTTPTestCase): + """Tests various scenarios for HTTP 1.1 keep-alive support. + + These tests don't use AsyncHTTPClient because we want to control + connection reuse and closing. + """ + + def get_app(self): + class HelloHandler(RequestHandler): + def get(self): + self.finish("Hello world") + + def post(self): + self.finish("Hello world") + + class LargeHandler(RequestHandler): + def get(self): + # 512KB should be bigger than the socket buffers so it will + # be written out in chunks. + self.write("".join(chr(i % 256) * 1024 for i in range(512))) + + class TransferEncodingChunkedHandler(RequestHandler): + @gen.coroutine + def head(self): + self.write("Hello world") + yield self.flush() + + class FinishOnCloseHandler(RequestHandler): + def initialize(self, cleanup_event): + self.cleanup_event = cleanup_event + + @gen.coroutine + def get(self): + self.flush() + yield self.cleanup_event.wait() + + def on_connection_close(self): + # This is not very realistic, but finishing the request + # from the close callback has the right timing to mimic + # some errors seen in the wild. + self.finish("closed") + + self.cleanup_event = Event() + return Application( + [ + ("/", HelloHandler), + ("/large", LargeHandler), + ("/chunked", TransferEncodingChunkedHandler), + ( + "/finish_on_close", + FinishOnCloseHandler, + dict(cleanup_event=self.cleanup_event), + ), + ] + ) + + def setUp(self): + super().setUp() + self.http_version = b"HTTP/1.1" + + def tearDown(self): + # We just closed the client side of the socket; let the IOLoop run + # once to make sure the server side got the message. + self.io_loop.add_timeout(datetime.timedelta(seconds=0.001), self.stop) + self.wait() + + if hasattr(self, "stream"): + self.stream.close() + super().tearDown() + + # The next few methods are a crude manual http client + @gen.coroutine + def connect(self): + self.stream = IOStream(socket.socket()) + yield self.stream.connect(("127.0.0.1", self.get_http_port())) + + @gen.coroutine + def read_headers(self): + first_line = yield self.stream.read_until(b"\r\n") + self.assertTrue(first_line.startswith(b"HTTP/1.1 200"), first_line) + header_bytes = yield self.stream.read_until(b"\r\n\r\n") + headers = HTTPHeaders.parse(header_bytes.decode("latin1")) + raise gen.Return(headers) + + @gen.coroutine + def read_response(self): + self.headers = yield self.read_headers() + body = yield self.stream.read_bytes(int(self.headers["Content-Length"])) + self.assertEqual(b"Hello world", body) + + def close(self): + self.stream.close() + del self.stream + + @gen_test + def test_two_requests(self): + yield self.connect() + self.stream.write(b"GET / HTTP/1.1\r\n\r\n") + yield self.read_response() + self.stream.write(b"GET / HTTP/1.1\r\n\r\n") + yield self.read_response() + self.close() + + @gen_test + def test_request_close(self): + yield self.connect() + self.stream.write(b"GET / HTTP/1.1\r\nConnection: close\r\n\r\n") + yield self.read_response() + data = yield self.stream.read_until_close() + self.assertTrue(not data) + self.assertEqual(self.headers["Connection"], "close") + self.close() + + # keepalive is supported for http 1.0 too, but it's opt-in + @gen_test + def test_http10(self): + self.http_version = b"HTTP/1.0" + yield self.connect() + self.stream.write(b"GET / HTTP/1.0\r\n\r\n") + yield self.read_response() + data = yield self.stream.read_until_close() + self.assertTrue(not data) + self.assertTrue("Connection" not in self.headers) + self.close() + + @gen_test + def test_http10_keepalive(self): + self.http_version = b"HTTP/1.0" + yield self.connect() + self.stream.write(b"GET / HTTP/1.0\r\nConnection: keep-alive\r\n\r\n") + yield self.read_response() + self.assertEqual(self.headers["Connection"], "Keep-Alive") + self.stream.write(b"GET / HTTP/1.0\r\nConnection: keep-alive\r\n\r\n") + yield self.read_response() + self.assertEqual(self.headers["Connection"], "Keep-Alive") + self.close() + + @gen_test + def test_http10_keepalive_extra_crlf(self): + self.http_version = b"HTTP/1.0" + yield self.connect() + self.stream.write(b"GET / HTTP/1.0\r\nConnection: keep-alive\r\n\r\n\r\n") + yield self.read_response() + self.assertEqual(self.headers["Connection"], "Keep-Alive") + self.stream.write(b"GET / HTTP/1.0\r\nConnection: keep-alive\r\n\r\n") + yield self.read_response() + self.assertEqual(self.headers["Connection"], "Keep-Alive") + self.close() + + @gen_test + def test_pipelined_requests(self): + yield self.connect() + self.stream.write(b"GET / HTTP/1.1\r\n\r\nGET / HTTP/1.1\r\n\r\n") + yield self.read_response() + yield self.read_response() + self.close() + + @gen_test + def test_pipelined_cancel(self): + yield self.connect() + self.stream.write(b"GET / HTTP/1.1\r\n\r\nGET / HTTP/1.1\r\n\r\n") + # only read once + yield self.read_response() + self.close() + + @gen_test + def test_cancel_during_download(self): + yield self.connect() + self.stream.write(b"GET /large HTTP/1.1\r\n\r\n") + yield self.read_headers() + yield self.stream.read_bytes(1024) + self.close() + + @gen_test + def test_finish_while_closed(self): + yield self.connect() + self.stream.write(b"GET /finish_on_close HTTP/1.1\r\n\r\n") + yield self.read_headers() + self.close() + # Let the hanging coroutine clean up after itself + self.cleanup_event.set() + + @gen_test + def test_keepalive_chunked(self): + self.http_version = b"HTTP/1.0" + yield self.connect() + self.stream.write( + b"POST / HTTP/1.0\r\n" + b"Connection: keep-alive\r\n" + b"Transfer-Encoding: chunked\r\n" + b"\r\n" + b"0\r\n" + b"\r\n" + ) + yield self.read_response() + self.assertEqual(self.headers["Connection"], "Keep-Alive") + self.stream.write(b"GET / HTTP/1.0\r\nConnection: keep-alive\r\n\r\n") + yield self.read_response() + self.assertEqual(self.headers["Connection"], "Keep-Alive") + self.close() + + @gen_test + def test_keepalive_chunked_head_no_body(self): + yield self.connect() + self.stream.write(b"HEAD /chunked HTTP/1.1\r\n\r\n") + yield self.read_headers() + + self.stream.write(b"HEAD /chunked HTTP/1.1\r\n\r\n") + yield self.read_headers() + self.close() + + +class GzipBaseTest(AsyncHTTPTestCase): + def get_app(self): + return Application([("/", EchoHandler)]) + + def post_gzip(self, body): + bytesio = BytesIO() + gzip_file = gzip.GzipFile(mode="w", fileobj=bytesio) + gzip_file.write(utf8(body)) + gzip_file.close() + compressed_body = bytesio.getvalue() + return self.fetch( + "/", + method="POST", + body=compressed_body, + headers={"Content-Encoding": "gzip"}, + ) + + def test_uncompressed(self): + response = self.fetch("/", method="POST", body="foo=bar") + self.assertEqual(json_decode(response.body), {u"foo": [u"bar"]}) + + +class GzipTest(GzipBaseTest, AsyncHTTPTestCase): + def get_httpserver_options(self): + return dict(decompress_request=True) + + def test_gzip(self): + response = self.post_gzip("foo=bar") + self.assertEqual(json_decode(response.body), {u"foo": [u"bar"]}) + + +class GzipUnsupportedTest(GzipBaseTest, AsyncHTTPTestCase): + def test_gzip_unsupported(self): + # Gzip support is opt-in; without it the server fails to parse + # the body (but parsing form bodies is currently just a log message, + # not a fatal error). + with ExpectLog(gen_log, "Unsupported Content-Encoding"): + response = self.post_gzip("foo=bar") + self.assertEqual(json_decode(response.body), {}) + + +class StreamingChunkSizeTest(AsyncHTTPTestCase): + # 50 characters long, and repetitive so it can be compressed. + BODY = b"01234567890123456789012345678901234567890123456789" + CHUNK_SIZE = 16 + + def get_http_client(self): + # body_producer doesn't work on curl_httpclient, so override the + # configured AsyncHTTPClient implementation. + return SimpleAsyncHTTPClient() + + def get_httpserver_options(self): + return dict(chunk_size=self.CHUNK_SIZE, decompress_request=True) + + class MessageDelegate(HTTPMessageDelegate): + def __init__(self, connection): + self.connection = connection + + def headers_received(self, start_line, headers): + self.chunk_lengths = [] # type: List[int] + + def data_received(self, chunk): + self.chunk_lengths.append(len(chunk)) + + def finish(self): + response_body = utf8(json_encode(self.chunk_lengths)) + self.connection.write_headers( + ResponseStartLine("HTTP/1.1", 200, "OK"), + HTTPHeaders({"Content-Length": str(len(response_body))}), + ) + self.connection.write(response_body) + self.connection.finish() + + def get_app(self): + class App(HTTPServerConnectionDelegate): + def start_request(self, server_conn, request_conn): + return StreamingChunkSizeTest.MessageDelegate(request_conn) + + return App() + + def fetch_chunk_sizes(self, **kwargs): + response = self.fetch("/", method="POST", **kwargs) + response.rethrow() + chunks = json_decode(response.body) + self.assertEqual(len(self.BODY), sum(chunks)) + for chunk_size in chunks: + self.assertLessEqual( + chunk_size, self.CHUNK_SIZE, "oversized chunk: " + str(chunks) + ) + self.assertGreater(chunk_size, 0, "empty chunk: " + str(chunks)) + return chunks + + def compress(self, body): + bytesio = BytesIO() + gzfile = gzip.GzipFile(mode="w", fileobj=bytesio) + gzfile.write(body) + gzfile.close() + compressed = bytesio.getvalue() + if len(compressed) >= len(body): + raise Exception("body did not shrink when compressed") + return compressed + + def test_regular_body(self): + chunks = self.fetch_chunk_sizes(body=self.BODY) + # Without compression we know exactly what to expect. + self.assertEqual([16, 16, 16, 2], chunks) + + def test_compressed_body(self): + self.fetch_chunk_sizes( + body=self.compress(self.BODY), headers={"Content-Encoding": "gzip"} + ) + # Compression creates irregular boundaries so the assertions + # in fetch_chunk_sizes are as specific as we can get. + + def test_chunked_body(self): + def body_producer(write): + write(self.BODY[:20]) + write(self.BODY[20:]) + + chunks = self.fetch_chunk_sizes(body_producer=body_producer) + # HTTP chunk boundaries translate to application-visible breaks + self.assertEqual([16, 4, 16, 14], chunks) + + def test_chunked_compressed(self): + compressed = self.compress(self.BODY) + self.assertGreater(len(compressed), 20) + + def body_producer(write): + write(compressed[:20]) + write(compressed[20:]) + + self.fetch_chunk_sizes( + body_producer=body_producer, headers={"Content-Encoding": "gzip"} + ) + + +class MaxHeaderSizeTest(AsyncHTTPTestCase): + def get_app(self): + return Application([("/", HelloWorldRequestHandler)]) + + def get_httpserver_options(self): + return dict(max_header_size=1024) + + def test_small_headers(self): + response = self.fetch("/", headers={"X-Filler": "a" * 100}) + response.rethrow() + self.assertEqual(response.body, b"Hello world") + + def test_large_headers(self): + with ExpectLog(gen_log, "Unsatisfiable read", required=False): + try: + self.fetch("/", headers={"X-Filler": "a" * 1000}, raise_error=True) + self.fail("did not raise expected exception") + except HTTPError as e: + # 431 is "Request Header Fields Too Large", defined in RFC + # 6585. However, many implementations just close the + # connection in this case, resulting in a missing response. + if e.response is not None: + self.assertIn(e.response.code, (431, 599)) + + +@skipOnTravis +class IdleTimeoutTest(AsyncHTTPTestCase): + def get_app(self): + return Application([("/", HelloWorldRequestHandler)]) + + def get_httpserver_options(self): + return dict(idle_connection_timeout=0.1) + + def setUp(self): + super().setUp() + self.streams = [] # type: List[IOStream] + + def tearDown(self): + super().tearDown() + for stream in self.streams: + stream.close() + + @gen.coroutine + def connect(self): + stream = IOStream(socket.socket()) + yield stream.connect(("127.0.0.1", self.get_http_port())) + self.streams.append(stream) + raise gen.Return(stream) + + @gen_test + def test_unused_connection(self): + stream = yield self.connect() + event = Event() + stream.set_close_callback(event.set) + yield event.wait() + + @gen_test + def test_idle_after_use(self): + stream = yield self.connect() + event = Event() + stream.set_close_callback(event.set) + + # Use the connection twice to make sure keep-alives are working + for i in range(2): + stream.write(b"GET / HTTP/1.1\r\n\r\n") + yield stream.read_until(b"\r\n\r\n") + data = yield stream.read_bytes(11) + self.assertEqual(data, b"Hello world") + + # Now let the timeout trigger and close the connection. + yield event.wait() + + +class BodyLimitsTest(AsyncHTTPTestCase): + def get_app(self): + class BufferedHandler(RequestHandler): + def put(self): + self.write(str(len(self.request.body))) + + @stream_request_body + class StreamingHandler(RequestHandler): + def initialize(self): + self.bytes_read = 0 + + def prepare(self): + conn = typing.cast(HTTP1Connection, self.request.connection) + if "expected_size" in self.request.arguments: + conn.set_max_body_size(int(self.get_argument("expected_size"))) + if "body_timeout" in self.request.arguments: + conn.set_body_timeout(float(self.get_argument("body_timeout"))) + + def data_received(self, data): + self.bytes_read += len(data) + + def put(self): + self.write(str(self.bytes_read)) + + return Application( + [("/buffered", BufferedHandler), ("/streaming", StreamingHandler)] + ) + + def get_httpserver_options(self): + return dict(body_timeout=3600, max_body_size=4096) + + def get_http_client(self): + # body_producer doesn't work on curl_httpclient, so override the + # configured AsyncHTTPClient implementation. + return SimpleAsyncHTTPClient() + + def test_small_body(self): + response = self.fetch("/buffered", method="PUT", body=b"a" * 4096) + self.assertEqual(response.body, b"4096") + response = self.fetch("/streaming", method="PUT", body=b"a" * 4096) + self.assertEqual(response.body, b"4096") + + def test_large_body_buffered(self): + with ExpectLog(gen_log, ".*Content-Length too long", level=logging.INFO): + response = self.fetch("/buffered", method="PUT", body=b"a" * 10240) + self.assertEqual(response.code, 400) + + @unittest.skipIf(os.name == "nt", "flaky on windows") + def test_large_body_buffered_chunked(self): + # This test is flaky on windows for unknown reasons. + with ExpectLog(gen_log, ".*chunked body too large", level=logging.INFO): + response = self.fetch( + "/buffered", + method="PUT", + body_producer=lambda write: write(b"a" * 10240), + ) + self.assertEqual(response.code, 400) + + def test_large_body_streaming(self): + with ExpectLog(gen_log, ".*Content-Length too long", level=logging.INFO): + response = self.fetch("/streaming", method="PUT", body=b"a" * 10240) + self.assertEqual(response.code, 400) + + @unittest.skipIf(os.name == "nt", "flaky on windows") + def test_large_body_streaming_chunked(self): + with ExpectLog(gen_log, ".*chunked body too large", level=logging.INFO): + response = self.fetch( + "/streaming", + method="PUT", + body_producer=lambda write: write(b"a" * 10240), + ) + self.assertEqual(response.code, 400) + + def test_large_body_streaming_override(self): + response = self.fetch( + "/streaming?expected_size=10240", method="PUT", body=b"a" * 10240 + ) + self.assertEqual(response.body, b"10240") + + def test_large_body_streaming_chunked_override(self): + response = self.fetch( + "/streaming?expected_size=10240", + method="PUT", + body_producer=lambda write: write(b"a" * 10240), + ) + self.assertEqual(response.body, b"10240") + + @gen_test + def test_timeout(self): + stream = IOStream(socket.socket()) + try: + yield stream.connect(("127.0.0.1", self.get_http_port())) + # Use a raw stream because AsyncHTTPClient won't let us read a + # response without finishing a body. + stream.write( + b"PUT /streaming?body_timeout=0.1 HTTP/1.0\r\n" + b"Content-Length: 42\r\n\r\n" + ) + with ExpectLog(gen_log, "Timeout reading body", level=logging.INFO): + response = yield stream.read_until_close() + self.assertEqual(response, b"") + finally: + stream.close() + + @gen_test + def test_body_size_override_reset(self): + # The max_body_size override is reset between requests. + stream = IOStream(socket.socket()) + try: + yield stream.connect(("127.0.0.1", self.get_http_port())) + # Use a raw stream so we can make sure it's all on one connection. + stream.write( + b"PUT /streaming?expected_size=10240 HTTP/1.1\r\n" + b"Content-Length: 10240\r\n\r\n" + ) + stream.write(b"a" * 10240) + start_line, headers, response = yield read_stream_body(stream) + self.assertEqual(response, b"10240") + # Without the ?expected_size parameter, we get the old default value + stream.write( + b"PUT /streaming HTTP/1.1\r\n" b"Content-Length: 10240\r\n\r\n" + ) + with ExpectLog(gen_log, ".*Content-Length too long", level=logging.INFO): + data = yield stream.read_until_close() + self.assertEqual(data, b"HTTP/1.1 400 Bad Request\r\n\r\n") + finally: + stream.close() + + +class LegacyInterfaceTest(AsyncHTTPTestCase): + def get_app(self): + # The old request_callback interface does not implement the + # delegate interface, and writes its response via request.write + # instead of request.connection.write_headers. + def handle_request(request): + self.http1 = request.version.startswith("HTTP/1.") + if not self.http1: + # This test will be skipped if we're using HTTP/2, + # so just close it out cleanly using the modern interface. + request.connection.write_headers( + ResponseStartLine("", 200, "OK"), HTTPHeaders() + ) + request.connection.finish() + return + message = b"Hello world" + request.connection.write( + utf8("HTTP/1.1 200 OK\r\n" "Content-Length: %d\r\n\r\n" % len(message)) + ) + request.connection.write(message) + request.connection.finish() + + return handle_request + + def test_legacy_interface(self): + response = self.fetch("/") + if not self.http1: + self.skipTest("requires HTTP/1.x") + self.assertEqual(response.body, b"Hello world") diff --git a/venv/lib/python3.8/site-packages/tornado/test/httputil_test.py b/venv/lib/python3.8/site-packages/tornado/test/httputil_test.py new file mode 100644 index 0000000..0fad403 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/httputil_test.py @@ -0,0 +1,521 @@ +from tornado.httputil import ( + url_concat, + parse_multipart_form_data, + HTTPHeaders, + format_timestamp, + HTTPServerRequest, + parse_request_start_line, + parse_cookie, + qs_to_qsl, + HTTPInputError, + HTTPFile, +) +from tornado.escape import utf8, native_str +from tornado.log import gen_log +from tornado.testing import ExpectLog + +import copy +import datetime +import logging +import pickle +import time +import urllib.parse +import unittest + +from typing import Tuple, Dict, List + + +def form_data_args() -> Tuple[Dict[str, List[bytes]], Dict[str, List[HTTPFile]]]: + """Return two empty dicts suitable for use with parse_multipart_form_data. + + mypy insists on type annotations for dict literals, so this lets us avoid + the verbose types throughout this test. + """ + return {}, {} + + +class TestUrlConcat(unittest.TestCase): + def test_url_concat_no_query_params(self): + url = url_concat("https://localhost/path", [("y", "y"), ("z", "z")]) + self.assertEqual(url, "https://localhost/path?y=y&z=z") + + def test_url_concat_encode_args(self): + url = url_concat("https://localhost/path", [("y", "/y"), ("z", "z")]) + self.assertEqual(url, "https://localhost/path?y=%2Fy&z=z") + + def test_url_concat_trailing_q(self): + url = url_concat("https://localhost/path?", [("y", "y"), ("z", "z")]) + self.assertEqual(url, "https://localhost/path?y=y&z=z") + + def test_url_concat_q_with_no_trailing_amp(self): + url = url_concat("https://localhost/path?x", [("y", "y"), ("z", "z")]) + self.assertEqual(url, "https://localhost/path?x=&y=y&z=z") + + def test_url_concat_trailing_amp(self): + url = url_concat("https://localhost/path?x&", [("y", "y"), ("z", "z")]) + self.assertEqual(url, "https://localhost/path?x=&y=y&z=z") + + def test_url_concat_mult_params(self): + url = url_concat("https://localhost/path?a=1&b=2", [("y", "y"), ("z", "z")]) + self.assertEqual(url, "https://localhost/path?a=1&b=2&y=y&z=z") + + def test_url_concat_no_params(self): + url = url_concat("https://localhost/path?r=1&t=2", []) + self.assertEqual(url, "https://localhost/path?r=1&t=2") + + def test_url_concat_none_params(self): + url = url_concat("https://localhost/path?r=1&t=2", None) + self.assertEqual(url, "https://localhost/path?r=1&t=2") + + def test_url_concat_with_frag(self): + url = url_concat("https://localhost/path#tab", [("y", "y")]) + self.assertEqual(url, "https://localhost/path?y=y#tab") + + def test_url_concat_multi_same_params(self): + url = url_concat("https://localhost/path", [("y", "y1"), ("y", "y2")]) + self.assertEqual(url, "https://localhost/path?y=y1&y=y2") + + def test_url_concat_multi_same_query_params(self): + url = url_concat("https://localhost/path?r=1&r=2", [("y", "y")]) + self.assertEqual(url, "https://localhost/path?r=1&r=2&y=y") + + def test_url_concat_dict_params(self): + url = url_concat("https://localhost/path", dict(y="y")) + self.assertEqual(url, "https://localhost/path?y=y") + + +class QsParseTest(unittest.TestCase): + def test_parsing(self): + qsstring = "a=1&b=2&a=3" + qs = urllib.parse.parse_qs(qsstring) + qsl = list(qs_to_qsl(qs)) + self.assertIn(("a", "1"), qsl) + self.assertIn(("a", "3"), qsl) + self.assertIn(("b", "2"), qsl) + + +class MultipartFormDataTest(unittest.TestCase): + def test_file_upload(self): + data = b"""\ +--1234 +Content-Disposition: form-data; name="files"; filename="ab.txt" + +Foo +--1234--""".replace( + b"\n", b"\r\n" + ) + args, files = form_data_args() + parse_multipart_form_data(b"1234", data, args, files) + file = files["files"][0] + self.assertEqual(file["filename"], "ab.txt") + self.assertEqual(file["body"], b"Foo") + + def test_unquoted_names(self): + # quotes are optional unless special characters are present + data = b"""\ +--1234 +Content-Disposition: form-data; name=files; filename=ab.txt + +Foo +--1234--""".replace( + b"\n", b"\r\n" + ) + args, files = form_data_args() + parse_multipart_form_data(b"1234", data, args, files) + file = files["files"][0] + self.assertEqual(file["filename"], "ab.txt") + self.assertEqual(file["body"], b"Foo") + + def test_special_filenames(self): + filenames = [ + "a;b.txt", + 'a"b.txt', + 'a";b.txt', + 'a;"b.txt', + 'a";";.txt', + 'a\\"b.txt', + "a\\b.txt", + ] + for filename in filenames: + logging.debug("trying filename %r", filename) + str_data = """\ +--1234 +Content-Disposition: form-data; name="files"; filename="%s" + +Foo +--1234--""" % filename.replace( + "\\", "\\\\" + ).replace( + '"', '\\"' + ) + data = utf8(str_data.replace("\n", "\r\n")) + args, files = form_data_args() + parse_multipart_form_data(b"1234", data, args, files) + file = files["files"][0] + self.assertEqual(file["filename"], filename) + self.assertEqual(file["body"], b"Foo") + + def test_non_ascii_filename(self): + data = b"""\ +--1234 +Content-Disposition: form-data; name="files"; filename="ab.txt"; filename*=UTF-8''%C3%A1b.txt + +Foo +--1234--""".replace( + b"\n", b"\r\n" + ) + args, files = form_data_args() + parse_multipart_form_data(b"1234", data, args, files) + file = files["files"][0] + self.assertEqual(file["filename"], u"áb.txt") + self.assertEqual(file["body"], b"Foo") + + def test_boundary_starts_and_ends_with_quotes(self): + data = b"""\ +--1234 +Content-Disposition: form-data; name="files"; filename="ab.txt" + +Foo +--1234--""".replace( + b"\n", b"\r\n" + ) + args, files = form_data_args() + parse_multipart_form_data(b'"1234"', data, args, files) + file = files["files"][0] + self.assertEqual(file["filename"], "ab.txt") + self.assertEqual(file["body"], b"Foo") + + def test_missing_headers(self): + data = b"""\ +--1234 + +Foo +--1234--""".replace( + b"\n", b"\r\n" + ) + args, files = form_data_args() + with ExpectLog(gen_log, "multipart/form-data missing headers"): + parse_multipart_form_data(b"1234", data, args, files) + self.assertEqual(files, {}) + + def test_invalid_content_disposition(self): + data = b"""\ +--1234 +Content-Disposition: invalid; name="files"; filename="ab.txt" + +Foo +--1234--""".replace( + b"\n", b"\r\n" + ) + args, files = form_data_args() + with ExpectLog(gen_log, "Invalid multipart/form-data"): + parse_multipart_form_data(b"1234", data, args, files) + self.assertEqual(files, {}) + + def test_line_does_not_end_with_correct_line_break(self): + data = b"""\ +--1234 +Content-Disposition: form-data; name="files"; filename="ab.txt" + +Foo--1234--""".replace( + b"\n", b"\r\n" + ) + args, files = form_data_args() + with ExpectLog(gen_log, "Invalid multipart/form-data"): + parse_multipart_form_data(b"1234", data, args, files) + self.assertEqual(files, {}) + + def test_content_disposition_header_without_name_parameter(self): + data = b"""\ +--1234 +Content-Disposition: form-data; filename="ab.txt" + +Foo +--1234--""".replace( + b"\n", b"\r\n" + ) + args, files = form_data_args() + with ExpectLog(gen_log, "multipart/form-data value missing name"): + parse_multipart_form_data(b"1234", data, args, files) + self.assertEqual(files, {}) + + def test_data_after_final_boundary(self): + # The spec requires that data after the final boundary be ignored. + # http://www.w3.org/Protocols/rfc1341/7_2_Multipart.html + # In practice, some libraries include an extra CRLF after the boundary. + data = b"""\ +--1234 +Content-Disposition: form-data; name="files"; filename="ab.txt" + +Foo +--1234-- +""".replace( + b"\n", b"\r\n" + ) + args, files = form_data_args() + parse_multipart_form_data(b"1234", data, args, files) + file = files["files"][0] + self.assertEqual(file["filename"], "ab.txt") + self.assertEqual(file["body"], b"Foo") + + +class HTTPHeadersTest(unittest.TestCase): + def test_multi_line(self): + # Lines beginning with whitespace are appended to the previous line + # with any leading whitespace replaced by a single space. + # Note that while multi-line headers are a part of the HTTP spec, + # their use is strongly discouraged. + data = """\ +Foo: bar + baz +Asdf: qwer +\tzxcv +Foo: even + more + lines +""".replace( + "\n", "\r\n" + ) + headers = HTTPHeaders.parse(data) + self.assertEqual(headers["asdf"], "qwer zxcv") + self.assertEqual(headers.get_list("asdf"), ["qwer zxcv"]) + self.assertEqual(headers["Foo"], "bar baz,even more lines") + self.assertEqual(headers.get_list("foo"), ["bar baz", "even more lines"]) + self.assertEqual( + sorted(list(headers.get_all())), + [("Asdf", "qwer zxcv"), ("Foo", "bar baz"), ("Foo", "even more lines")], + ) + + def test_malformed_continuation(self): + # If the first line starts with whitespace, it's a + # continuation line with nothing to continue, so reject it + # (with a proper error). + data = " Foo: bar" + self.assertRaises(HTTPInputError, HTTPHeaders.parse, data) + + def test_unicode_newlines(self): + # Ensure that only \r\n is recognized as a header separator, and not + # the other newline-like unicode characters. + # Characters that are likely to be problematic can be found in + # http://unicode.org/standard/reports/tr13/tr13-5.html + # and cpython's unicodeobject.c (which defines the implementation + # of unicode_type.splitlines(), and uses a different list than TR13). + newlines = [ + u"\u001b", # VERTICAL TAB + u"\u001c", # FILE SEPARATOR + u"\u001d", # GROUP SEPARATOR + u"\u001e", # RECORD SEPARATOR + u"\u0085", # NEXT LINE + u"\u2028", # LINE SEPARATOR + u"\u2029", # PARAGRAPH SEPARATOR + ] + for newline in newlines: + # Try the utf8 and latin1 representations of each newline + for encoding in ["utf8", "latin1"]: + try: + try: + encoded = newline.encode(encoding) + except UnicodeEncodeError: + # Some chars cannot be represented in latin1 + continue + data = b"Cookie: foo=" + encoded + b"bar" + # parse() wants a native_str, so decode through latin1 + # in the same way the real parser does. + headers = HTTPHeaders.parse(native_str(data.decode("latin1"))) + expected = [ + ( + "Cookie", + "foo=" + native_str(encoded.decode("latin1")) + "bar", + ) + ] + self.assertEqual(expected, list(headers.get_all())) + except Exception: + gen_log.warning("failed while trying %r in %s", newline, encoding) + raise + + def test_optional_cr(self): + # Both CRLF and LF should be accepted as separators. CR should not be + # part of the data when followed by LF, but it is a normal char + # otherwise (or should bare CR be an error?) + headers = HTTPHeaders.parse("CRLF: crlf\r\nLF: lf\nCR: cr\rMore: more\r\n") + self.assertEqual( + sorted(headers.get_all()), + [("Cr", "cr\rMore: more"), ("Crlf", "crlf"), ("Lf", "lf")], + ) + + def test_copy(self): + all_pairs = [("A", "1"), ("A", "2"), ("B", "c")] + h1 = HTTPHeaders() + for k, v in all_pairs: + h1.add(k, v) + h2 = h1.copy() + h3 = copy.copy(h1) + h4 = copy.deepcopy(h1) + for headers in [h1, h2, h3, h4]: + # All the copies are identical, no matter how they were + # constructed. + self.assertEqual(list(sorted(headers.get_all())), all_pairs) + for headers in [h2, h3, h4]: + # Neither the dict or its member lists are reused. + self.assertIsNot(headers, h1) + self.assertIsNot(headers.get_list("A"), h1.get_list("A")) + + def test_pickle_roundtrip(self): + headers = HTTPHeaders() + headers.add("Set-Cookie", "a=b") + headers.add("Set-Cookie", "c=d") + headers.add("Content-Type", "text/html") + pickled = pickle.dumps(headers) + unpickled = pickle.loads(pickled) + self.assertEqual(sorted(headers.get_all()), sorted(unpickled.get_all())) + self.assertEqual(sorted(headers.items()), sorted(unpickled.items())) + + def test_setdefault(self): + headers = HTTPHeaders() + headers["foo"] = "bar" + # If a value is present, setdefault returns it without changes. + self.assertEqual(headers.setdefault("foo", "baz"), "bar") + self.assertEqual(headers["foo"], "bar") + # If a value is not present, setdefault sets it for future use. + self.assertEqual(headers.setdefault("quux", "xyzzy"), "xyzzy") + self.assertEqual(headers["quux"], "xyzzy") + self.assertEqual(sorted(headers.get_all()), [("Foo", "bar"), ("Quux", "xyzzy")]) + + def test_string(self): + headers = HTTPHeaders() + headers.add("Foo", "1") + headers.add("Foo", "2") + headers.add("Foo", "3") + headers2 = HTTPHeaders.parse(str(headers)) + self.assertEqual(headers, headers2) + + +class FormatTimestampTest(unittest.TestCase): + # Make sure that all the input types are supported. + TIMESTAMP = 1359312200.503611 + EXPECTED = "Sun, 27 Jan 2013 18:43:20 GMT" + + def check(self, value): + self.assertEqual(format_timestamp(value), self.EXPECTED) + + def test_unix_time_float(self): + self.check(self.TIMESTAMP) + + def test_unix_time_int(self): + self.check(int(self.TIMESTAMP)) + + def test_struct_time(self): + self.check(time.gmtime(self.TIMESTAMP)) + + def test_time_tuple(self): + tup = tuple(time.gmtime(self.TIMESTAMP)) + self.assertEqual(9, len(tup)) + self.check(tup) + + def test_datetime(self): + self.check(datetime.datetime.utcfromtimestamp(self.TIMESTAMP)) + + +# HTTPServerRequest is mainly tested incidentally to the server itself, +# but this tests the parts of the class that can be tested in isolation. +class HTTPServerRequestTest(unittest.TestCase): + def test_default_constructor(self): + # All parameters are formally optional, but uri is required + # (and has been for some time). This test ensures that no + # more required parameters slip in. + HTTPServerRequest(uri="/") + + def test_body_is_a_byte_string(self): + requets = HTTPServerRequest(uri="/") + self.assertIsInstance(requets.body, bytes) + + def test_repr_does_not_contain_headers(self): + request = HTTPServerRequest( + uri="/", headers=HTTPHeaders({"Canary": ["Coal Mine"]}) + ) + self.assertTrue("Canary" not in repr(request)) + + +class ParseRequestStartLineTest(unittest.TestCase): + METHOD = "GET" + PATH = "/foo" + VERSION = "HTTP/1.1" + + def test_parse_request_start_line(self): + start_line = " ".join([self.METHOD, self.PATH, self.VERSION]) + parsed_start_line = parse_request_start_line(start_line) + self.assertEqual(parsed_start_line.method, self.METHOD) + self.assertEqual(parsed_start_line.path, self.PATH) + self.assertEqual(parsed_start_line.version, self.VERSION) + + +class ParseCookieTest(unittest.TestCase): + # These tests copied from Django: + # https://github.com/django/django/pull/6277/commits/da810901ada1cae9fc1f018f879f11a7fb467b28 + def test_python_cookies(self): + """ + Test cases copied from Python's Lib/test/test_http_cookies.py + """ + self.assertEqual( + parse_cookie("chips=ahoy; vienna=finger"), + {"chips": "ahoy", "vienna": "finger"}, + ) + # Here parse_cookie() differs from Python's cookie parsing in that it + # treats all semicolons as delimiters, even within quotes. + self.assertEqual( + parse_cookie('keebler="E=mc2; L=\\"Loves\\"; fudge=\\012;"'), + {"keebler": '"E=mc2', "L": '\\"Loves\\"', "fudge": "\\012", "": '"'}, + ) + # Illegal cookies that have an '=' char in an unquoted value. + self.assertEqual(parse_cookie("keebler=E=mc2"), {"keebler": "E=mc2"}) + # Cookies with ':' character in their name. + self.assertEqual( + parse_cookie("key:term=value:term"), {"key:term": "value:term"} + ) + # Cookies with '[' and ']'. + self.assertEqual( + parse_cookie("a=b; c=[; d=r; f=h"), {"a": "b", "c": "[", "d": "r", "f": "h"} + ) + + def test_cookie_edgecases(self): + # Cookies that RFC6265 allows. + self.assertEqual( + parse_cookie("a=b; Domain=example.com"), {"a": "b", "Domain": "example.com"} + ) + # parse_cookie() has historically kept only the last cookie with the + # same name. + self.assertEqual(parse_cookie("a=b; h=i; a=c"), {"a": "c", "h": "i"}) + + def test_invalid_cookies(self): + """ + Cookie strings that go against RFC6265 but browsers will send if set + via document.cookie. + """ + # Chunks without an equals sign appear as unnamed values per + # https://bugzilla.mozilla.org/show_bug.cgi?id=169091 + self.assertIn( + "django_language", + parse_cookie("abc=def; unnamed; django_language=en").keys(), + ) + # Even a double quote may be an unamed value. + self.assertEqual(parse_cookie('a=b; "; c=d'), {"a": "b", "": '"', "c": "d"}) + # Spaces in names and values, and an equals sign in values. + self.assertEqual( + parse_cookie("a b c=d e = f; gh=i"), {"a b c": "d e = f", "gh": "i"} + ) + # More characters the spec forbids. + self.assertEqual( + parse_cookie('a b,c<>@:/[]?{}=d " =e,f g'), + {"a b,c<>@:/[]?{}": 'd " =e,f g'}, + ) + # Unicode characters. The spec only allows ASCII. + self.assertEqual( + parse_cookie("saint=André Bessette"), + {"saint": native_str("André Bessette")}, + ) + # Browsers don't send extra whitespace or semicolons in Cookie headers, + # but parse_cookie() should parse whitespace the same way + # document.cookie parses whitespace. + self.assertEqual( + parse_cookie(" = b ; ; = ; c = ; "), {"": "b", "c": ""} + ) diff --git a/venv/lib/python3.8/site-packages/tornado/test/import_test.py b/venv/lib/python3.8/site-packages/tornado/test/import_test.py new file mode 100644 index 0000000..23450fb --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/import_test.py @@ -0,0 +1,66 @@ +# flake8: noqa +import subprocess +import sys +import unittest + +_import_everything = b""" +# The event loop is not fork-safe, and it's easy to initialize an asyncio.Future +# at startup, which in turn creates the default event loop and prevents forking. +# Explicitly disallow the default event loop so that an error will be raised +# if something tries to touch it. +import asyncio +asyncio.set_event_loop(None) + +import tornado.auth +import tornado.autoreload +import tornado.concurrent +import tornado.escape +import tornado.gen +import tornado.http1connection +import tornado.httpclient +import tornado.httpserver +import tornado.httputil +import tornado.ioloop +import tornado.iostream +import tornado.locale +import tornado.log +import tornado.netutil +import tornado.options +import tornado.process +import tornado.simple_httpclient +import tornado.tcpserver +import tornado.tcpclient +import tornado.template +import tornado.testing +import tornado.util +import tornado.web +import tornado.websocket +import tornado.wsgi + +try: + import pycurl +except ImportError: + pass +else: + import tornado.curl_httpclient +""" + + +class ImportTest(unittest.TestCase): + def test_import_everything(self): + # Test that all Tornado modules can be imported without side effects, + # specifically without initializing the default asyncio event loop. + # Since we can't tell which modules may have already beein imported + # in our process, do it in a subprocess for a clean slate. + proc = subprocess.Popen([sys.executable], stdin=subprocess.PIPE) + proc.communicate(_import_everything) + self.assertEqual(proc.returncode, 0) + + def test_import_aliases(self): + # Ensure we don't delete formerly-documented aliases accidentally. + import tornado.ioloop + import tornado.gen + import tornado.util + + self.assertIs(tornado.ioloop.TimeoutError, tornado.util.TimeoutError) + self.assertIs(tornado.gen.TimeoutError, tornado.util.TimeoutError) diff --git a/venv/lib/python3.8/site-packages/tornado/test/ioloop_test.py b/venv/lib/python3.8/site-packages/tornado/test/ioloop_test.py new file mode 100644 index 0000000..16848b3 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/ioloop_test.py @@ -0,0 +1,725 @@ +from concurrent.futures import ThreadPoolExecutor +from concurrent import futures +import contextlib +import datetime +import functools +import socket +import subprocess +import sys +import threading +import time +import types +from unittest import mock +import unittest + +from tornado.escape import native_str +from tornado import gen +from tornado.ioloop import IOLoop, TimeoutError, PeriodicCallback +from tornado.log import app_log +from tornado.testing import AsyncTestCase, bind_unused_port, ExpectLog, gen_test +from tornado.test.util import skipIfNonUnix, skipOnTravis + +import typing + +if typing.TYPE_CHECKING: + from typing import List # noqa: F401 + + +class TestIOLoop(AsyncTestCase): + def test_add_callback_return_sequence(self): + # A callback returning {} or [] shouldn't spin the CPU, see Issue #1803. + self.calls = 0 + + loop = self.io_loop + test = self + old_add_callback = loop.add_callback + + def add_callback(self, callback, *args, **kwargs): + test.calls += 1 + old_add_callback(callback, *args, **kwargs) + + loop.add_callback = types.MethodType(add_callback, loop) # type: ignore + loop.add_callback(lambda: {}) # type: ignore + loop.add_callback(lambda: []) # type: ignore + loop.add_timeout(datetime.timedelta(milliseconds=50), loop.stop) + loop.start() + self.assertLess(self.calls, 10) + + @skipOnTravis + def test_add_callback_wakeup(self): + # Make sure that add_callback from inside a running IOLoop + # wakes up the IOLoop immediately instead of waiting for a timeout. + def callback(): + self.called = True + self.stop() + + def schedule_callback(): + self.called = False + self.io_loop.add_callback(callback) + # Store away the time so we can check if we woke up immediately + self.start_time = time.time() + + self.io_loop.add_timeout(self.io_loop.time(), schedule_callback) + self.wait() + self.assertAlmostEqual(time.time(), self.start_time, places=2) + self.assertTrue(self.called) + + @skipOnTravis + def test_add_callback_wakeup_other_thread(self): + def target(): + # sleep a bit to let the ioloop go into its poll loop + time.sleep(0.01) + self.stop_time = time.time() + self.io_loop.add_callback(self.stop) + + thread = threading.Thread(target=target) + self.io_loop.add_callback(thread.start) + self.wait() + delta = time.time() - self.stop_time + self.assertLess(delta, 0.1) + thread.join() + + def test_add_timeout_timedelta(self): + self.io_loop.add_timeout(datetime.timedelta(microseconds=1), self.stop) + self.wait() + + def test_multiple_add(self): + sock, port = bind_unused_port() + try: + self.io_loop.add_handler( + sock.fileno(), lambda fd, events: None, IOLoop.READ + ) + # Attempting to add the same handler twice fails + # (with a platform-dependent exception) + self.assertRaises( + Exception, + self.io_loop.add_handler, + sock.fileno(), + lambda fd, events: None, + IOLoop.READ, + ) + finally: + self.io_loop.remove_handler(sock.fileno()) + sock.close() + + def test_remove_without_add(self): + # remove_handler should not throw an exception if called on an fd + # was never added. + sock, port = bind_unused_port() + try: + self.io_loop.remove_handler(sock.fileno()) + finally: + sock.close() + + def test_add_callback_from_signal(self): + # cheat a little bit and just run this normally, since we can't + # easily simulate the races that happen with real signal handlers + self.io_loop.add_callback_from_signal(self.stop) + self.wait() + + def test_add_callback_from_signal_other_thread(self): + # Very crude test, just to make sure that we cover this case. + # This also happens to be the first test where we run an IOLoop in + # a non-main thread. + other_ioloop = IOLoop() + thread = threading.Thread(target=other_ioloop.start) + thread.start() + other_ioloop.add_callback_from_signal(other_ioloop.stop) + thread.join() + other_ioloop.close() + + def test_add_callback_while_closing(self): + # add_callback should not fail if it races with another thread + # closing the IOLoop. The callbacks are dropped silently + # without executing. + closing = threading.Event() + + def target(): + other_ioloop.add_callback(other_ioloop.stop) + other_ioloop.start() + closing.set() + other_ioloop.close(all_fds=True) + + other_ioloop = IOLoop() + thread = threading.Thread(target=target) + thread.start() + closing.wait() + for i in range(1000): + other_ioloop.add_callback(lambda: None) + + @skipIfNonUnix # just because socketpair is so convenient + def test_read_while_writeable(self): + # Ensure that write events don't come in while we're waiting for + # a read and haven't asked for writeability. (the reverse is + # difficult to test for) + client, server = socket.socketpair() + try: + + def handler(fd, events): + self.assertEqual(events, IOLoop.READ) + self.stop() + + self.io_loop.add_handler(client.fileno(), handler, IOLoop.READ) + self.io_loop.add_timeout( + self.io_loop.time() + 0.01, functools.partial(server.send, b"asdf") # type: ignore + ) + self.wait() + self.io_loop.remove_handler(client.fileno()) + finally: + client.close() + server.close() + + def test_remove_timeout_after_fire(self): + # It is not an error to call remove_timeout after it has run. + handle = self.io_loop.add_timeout(self.io_loop.time(), self.stop) + self.wait() + self.io_loop.remove_timeout(handle) + + def test_remove_timeout_cleanup(self): + # Add and remove enough callbacks to trigger cleanup. + # Not a very thorough test, but it ensures that the cleanup code + # gets executed and doesn't blow up. This test is only really useful + # on PollIOLoop subclasses, but it should run silently on any + # implementation. + for i in range(2000): + timeout = self.io_loop.add_timeout(self.io_loop.time() + 3600, lambda: None) + self.io_loop.remove_timeout(timeout) + # HACK: wait two IOLoop iterations for the GC to happen. + self.io_loop.add_callback(lambda: self.io_loop.add_callback(self.stop)) + self.wait() + + def test_remove_timeout_from_timeout(self): + calls = [False, False] + + # Schedule several callbacks and wait for them all to come due at once. + # t2 should be cancelled by t1, even though it is already scheduled to + # be run before the ioloop even looks at it. + now = self.io_loop.time() + + def t1(): + calls[0] = True + self.io_loop.remove_timeout(t2_handle) + + self.io_loop.add_timeout(now + 0.01, t1) + + def t2(): + calls[1] = True + + t2_handle = self.io_loop.add_timeout(now + 0.02, t2) + self.io_loop.add_timeout(now + 0.03, self.stop) + time.sleep(0.03) + self.wait() + self.assertEqual(calls, [True, False]) + + def test_timeout_with_arguments(self): + # This tests that all the timeout methods pass through *args correctly. + results = [] # type: List[int] + self.io_loop.add_timeout(self.io_loop.time(), results.append, 1) + self.io_loop.add_timeout(datetime.timedelta(seconds=0), results.append, 2) + self.io_loop.call_at(self.io_loop.time(), results.append, 3) + self.io_loop.call_later(0, results.append, 4) + self.io_loop.call_later(0, self.stop) + self.wait() + # The asyncio event loop does not guarantee the order of these + # callbacks. + self.assertEqual(sorted(results), [1, 2, 3, 4]) + + def test_add_timeout_return(self): + # All the timeout methods return non-None handles that can be + # passed to remove_timeout. + handle = self.io_loop.add_timeout(self.io_loop.time(), lambda: None) + self.assertFalse(handle is None) + self.io_loop.remove_timeout(handle) + + def test_call_at_return(self): + handle = self.io_loop.call_at(self.io_loop.time(), lambda: None) + self.assertFalse(handle is None) + self.io_loop.remove_timeout(handle) + + def test_call_later_return(self): + handle = self.io_loop.call_later(0, lambda: None) + self.assertFalse(handle is None) + self.io_loop.remove_timeout(handle) + + def test_close_file_object(self): + """When a file object is used instead of a numeric file descriptor, + the object should be closed (by IOLoop.close(all_fds=True), + not just the fd. + """ + # Use a socket since they are supported by IOLoop on all platforms. + # Unfortunately, sockets don't support the .closed attribute for + # inspecting their close status, so we must use a wrapper. + class SocketWrapper(object): + def __init__(self, sockobj): + self.sockobj = sockobj + self.closed = False + + def fileno(self): + return self.sockobj.fileno() + + def close(self): + self.closed = True + self.sockobj.close() + + sockobj, port = bind_unused_port() + socket_wrapper = SocketWrapper(sockobj) + io_loop = IOLoop() + io_loop.add_handler(socket_wrapper, lambda fd, events: None, IOLoop.READ) + io_loop.close(all_fds=True) + self.assertTrue(socket_wrapper.closed) + + def test_handler_callback_file_object(self): + """The handler callback receives the same fd object it passed in.""" + server_sock, port = bind_unused_port() + fds = [] + + def handle_connection(fd, events): + fds.append(fd) + conn, addr = server_sock.accept() + conn.close() + self.stop() + + self.io_loop.add_handler(server_sock, handle_connection, IOLoop.READ) + with contextlib.closing(socket.socket()) as client_sock: + client_sock.connect(("127.0.0.1", port)) + self.wait() + self.io_loop.remove_handler(server_sock) + self.io_loop.add_handler(server_sock.fileno(), handle_connection, IOLoop.READ) + with contextlib.closing(socket.socket()) as client_sock: + client_sock.connect(("127.0.0.1", port)) + self.wait() + self.assertIs(fds[0], server_sock) + self.assertEqual(fds[1], server_sock.fileno()) + self.io_loop.remove_handler(server_sock.fileno()) + server_sock.close() + + def test_mixed_fd_fileobj(self): + server_sock, port = bind_unused_port() + + def f(fd, events): + pass + + self.io_loop.add_handler(server_sock, f, IOLoop.READ) + with self.assertRaises(Exception): + # The exact error is unspecified - some implementations use + # IOError, others use ValueError. + self.io_loop.add_handler(server_sock.fileno(), f, IOLoop.READ) + self.io_loop.remove_handler(server_sock.fileno()) + server_sock.close() + + def test_reentrant(self): + """Calling start() twice should raise an error, not deadlock.""" + returned_from_start = [False] + got_exception = [False] + + def callback(): + try: + self.io_loop.start() + returned_from_start[0] = True + except Exception: + got_exception[0] = True + self.stop() + + self.io_loop.add_callback(callback) + self.wait() + self.assertTrue(got_exception[0]) + self.assertFalse(returned_from_start[0]) + + def test_exception_logging(self): + """Uncaught exceptions get logged by the IOLoop.""" + self.io_loop.add_callback(lambda: 1 / 0) + self.io_loop.add_callback(self.stop) + with ExpectLog(app_log, "Exception in callback"): + self.wait() + + def test_exception_logging_future(self): + """The IOLoop examines exceptions from Futures and logs them.""" + + @gen.coroutine + def callback(): + self.io_loop.add_callback(self.stop) + 1 / 0 + + self.io_loop.add_callback(callback) + with ExpectLog(app_log, "Exception in callback"): + self.wait() + + def test_exception_logging_native_coro(self): + """The IOLoop examines exceptions from awaitables and logs them.""" + + async def callback(): + # Stop the IOLoop two iterations after raising an exception + # to give the exception time to be logged. + self.io_loop.add_callback(self.io_loop.add_callback, self.stop) + 1 / 0 + + self.io_loop.add_callback(callback) + with ExpectLog(app_log, "Exception in callback"): + self.wait() + + def test_spawn_callback(self): + # Both add_callback and spawn_callback run directly on the IOLoop, + # so their errors are logged without stopping the test. + self.io_loop.add_callback(lambda: 1 / 0) + self.io_loop.add_callback(self.stop) + with ExpectLog(app_log, "Exception in callback"): + self.wait() + # A spawned callback is run directly on the IOLoop, so it will be + # logged without stopping the test. + self.io_loop.spawn_callback(lambda: 1 / 0) + self.io_loop.add_callback(self.stop) + with ExpectLog(app_log, "Exception in callback"): + self.wait() + + @skipIfNonUnix + def test_remove_handler_from_handler(self): + # Create two sockets with simultaneous read events. + client, server = socket.socketpair() + try: + client.send(b"abc") + server.send(b"abc") + + # After reading from one fd, remove the other from the IOLoop. + chunks = [] + + def handle_read(fd, events): + chunks.append(fd.recv(1024)) + if fd is client: + self.io_loop.remove_handler(server) + else: + self.io_loop.remove_handler(client) + + self.io_loop.add_handler(client, handle_read, self.io_loop.READ) + self.io_loop.add_handler(server, handle_read, self.io_loop.READ) + self.io_loop.call_later(0.1, self.stop) + self.wait() + + # Only one fd was read; the other was cleanly removed. + self.assertEqual(chunks, [b"abc"]) + finally: + client.close() + server.close() + + @skipIfNonUnix + @gen_test + def test_init_close_race(self): + # Regression test for #2367 + # + # Skipped on windows because of what looks like a bug in the + # proactor event loop when started and stopped on non-main + # threads. + def f(): + for i in range(10): + loop = IOLoop() + loop.close() + + yield gen.multi([self.io_loop.run_in_executor(None, f) for i in range(2)]) + + +# Deliberately not a subclass of AsyncTestCase so the IOLoop isn't +# automatically set as current. +class TestIOLoopCurrent(unittest.TestCase): + def setUp(self): + self.io_loop = None # type: typing.Optional[IOLoop] + IOLoop.clear_current() + + def tearDown(self): + if self.io_loop is not None: + self.io_loop.close() + + def test_default_current(self): + self.io_loop = IOLoop() + # The first IOLoop with default arguments is made current. + self.assertIs(self.io_loop, IOLoop.current()) + # A second IOLoop can be created but is not made current. + io_loop2 = IOLoop() + self.assertIs(self.io_loop, IOLoop.current()) + io_loop2.close() + + def test_non_current(self): + self.io_loop = IOLoop(make_current=False) + # The new IOLoop is not initially made current. + self.assertIsNone(IOLoop.current(instance=False)) + # Starting the IOLoop makes it current, and stopping the loop + # makes it non-current. This process is repeatable. + for i in range(3): + + def f(): + self.current_io_loop = IOLoop.current() + assert self.io_loop is not None + self.io_loop.stop() + + self.io_loop.add_callback(f) + self.io_loop.start() + self.assertIs(self.current_io_loop, self.io_loop) + # Now that the loop is stopped, it is no longer current. + self.assertIsNone(IOLoop.current(instance=False)) + + def test_force_current(self): + self.io_loop = IOLoop(make_current=True) + self.assertIs(self.io_loop, IOLoop.current()) + with self.assertRaises(RuntimeError): + # A second make_current=True construction cannot succeed. + IOLoop(make_current=True) + # current() was not affected by the failed construction. + self.assertIs(self.io_loop, IOLoop.current()) + + +class TestIOLoopCurrentAsync(AsyncTestCase): + @gen_test + def test_clear_without_current(self): + # If there is no current IOLoop, clear_current is a no-op (but + # should not fail). Use a thread so we see the threading.Local + # in a pristine state. + with ThreadPoolExecutor(1) as e: + yield e.submit(IOLoop.clear_current) + + +class TestIOLoopFutures(AsyncTestCase): + def test_add_future_threads(self): + with futures.ThreadPoolExecutor(1) as pool: + + def dummy(): + pass + + self.io_loop.add_future( + pool.submit(dummy), lambda future: self.stop(future) + ) + future = self.wait() + self.assertTrue(future.done()) + self.assertTrue(future.result() is None) + + @gen_test + def test_run_in_executor_gen(self): + event1 = threading.Event() + event2 = threading.Event() + + def sync_func(self_event, other_event): + self_event.set() + other_event.wait() + # Note that return value doesn't actually do anything, + # it is just passed through to our final assertion to + # make sure it is passed through properly. + return self_event + + # Run two synchronous functions, which would deadlock if not + # run in parallel. + res = yield [ + IOLoop.current().run_in_executor(None, sync_func, event1, event2), + IOLoop.current().run_in_executor(None, sync_func, event2, event1), + ] + + self.assertEqual([event1, event2], res) + + @gen_test + def test_run_in_executor_native(self): + event1 = threading.Event() + event2 = threading.Event() + + def sync_func(self_event, other_event): + self_event.set() + other_event.wait() + return self_event + + # Go through an async wrapper to ensure that the result of + # run_in_executor works with await and not just gen.coroutine + # (simply passing the underlying concurrent future would do that). + async def async_wrapper(self_event, other_event): + return await IOLoop.current().run_in_executor( + None, sync_func, self_event, other_event + ) + + res = yield [async_wrapper(event1, event2), async_wrapper(event2, event1)] + + self.assertEqual([event1, event2], res) + + @gen_test + def test_set_default_executor(self): + count = [0] + + class MyExecutor(futures.ThreadPoolExecutor): + def submit(self, func, *args): + count[0] += 1 + return super().submit(func, *args) + + event = threading.Event() + + def sync_func(): + event.set() + + executor = MyExecutor(1) + loop = IOLoop.current() + loop.set_default_executor(executor) + yield loop.run_in_executor(None, sync_func) + self.assertEqual(1, count[0]) + self.assertTrue(event.is_set()) + + +class TestIOLoopRunSync(unittest.TestCase): + def setUp(self): + self.io_loop = IOLoop() + + def tearDown(self): + self.io_loop.close() + + def test_sync_result(self): + with self.assertRaises(gen.BadYieldError): + self.io_loop.run_sync(lambda: 42) + + def test_sync_exception(self): + with self.assertRaises(ZeroDivisionError): + self.io_loop.run_sync(lambda: 1 / 0) + + def test_async_result(self): + @gen.coroutine + def f(): + yield gen.moment + raise gen.Return(42) + + self.assertEqual(self.io_loop.run_sync(f), 42) + + def test_async_exception(self): + @gen.coroutine + def f(): + yield gen.moment + 1 / 0 + + with self.assertRaises(ZeroDivisionError): + self.io_loop.run_sync(f) + + def test_current(self): + def f(): + self.assertIs(IOLoop.current(), self.io_loop) + + self.io_loop.run_sync(f) + + def test_timeout(self): + @gen.coroutine + def f(): + yield gen.sleep(1) + + self.assertRaises(TimeoutError, self.io_loop.run_sync, f, timeout=0.01) + + def test_native_coroutine(self): + @gen.coroutine + def f1(): + yield gen.moment + + async def f2(): + await f1() + + self.io_loop.run_sync(f2) + + +class TestPeriodicCallbackMath(unittest.TestCase): + def simulate_calls(self, pc, durations): + """Simulate a series of calls to the PeriodicCallback. + + Pass a list of call durations in seconds (negative values + work to simulate clock adjustments during the call, or more or + less equivalently, between calls). This method returns the + times at which each call would be made. + """ + calls = [] + now = 1000 + pc._next_timeout = now + for d in durations: + pc._update_next(now) + calls.append(pc._next_timeout) + now = pc._next_timeout + d + return calls + + def dummy(self): + pass + + def test_basic(self): + pc = PeriodicCallback(self.dummy, 10000) + self.assertEqual( + self.simulate_calls(pc, [0] * 5), [1010, 1020, 1030, 1040, 1050] + ) + + def test_overrun(self): + # If a call runs for too long, we skip entire cycles to get + # back on schedule. + call_durations = [9, 9, 10, 11, 20, 20, 35, 35, 0, 0, 0] + expected = [ + 1010, + 1020, + 1030, # first 3 calls on schedule + 1050, + 1070, # next 2 delayed one cycle + 1100, + 1130, # next 2 delayed 2 cycles + 1170, + 1210, # next 2 delayed 3 cycles + 1220, + 1230, # then back on schedule. + ] + + pc = PeriodicCallback(self.dummy, 10000) + self.assertEqual(self.simulate_calls(pc, call_durations), expected) + + def test_clock_backwards(self): + pc = PeriodicCallback(self.dummy, 10000) + # Backwards jumps are ignored, potentially resulting in a + # slightly slow schedule (although we assume that when + # time.time() and time.monotonic() are different, time.time() + # is getting adjusted by NTP and is therefore more accurate) + self.assertEqual( + self.simulate_calls(pc, [-2, -1, -3, -2, 0]), [1010, 1020, 1030, 1040, 1050] + ) + + # For big jumps, we should perhaps alter the schedule, but we + # don't currently. This trace shows that we run callbacks + # every 10s of time.time(), but the first and second calls are + # 110s of real time apart because the backwards jump is + # ignored. + self.assertEqual(self.simulate_calls(pc, [-100, 0, 0]), [1010, 1020, 1030]) + + def test_jitter(self): + random_times = [0.5, 1, 0, 0.75] + expected = [1010, 1022.5, 1030, 1041.25] + call_durations = [0] * len(random_times) + pc = PeriodicCallback(self.dummy, 10000, jitter=0.5) + + def mock_random(): + return random_times.pop(0) + + with mock.patch("random.random", mock_random): + self.assertEqual(self.simulate_calls(pc, call_durations), expected) + + +class TestIOLoopConfiguration(unittest.TestCase): + def run_python(self, *statements): + stmt_list = [ + "from tornado.ioloop import IOLoop", + "classname = lambda x: x.__class__.__name__", + ] + list(statements) + args = [sys.executable, "-c", "; ".join(stmt_list)] + return native_str(subprocess.check_output(args)).strip() + + def test_default(self): + # When asyncio is available, it is used by default. + cls = self.run_python("print(classname(IOLoop.current()))") + self.assertEqual(cls, "AsyncIOMainLoop") + cls = self.run_python("print(classname(IOLoop()))") + self.assertEqual(cls, "AsyncIOLoop") + + def test_asyncio(self): + cls = self.run_python( + 'IOLoop.configure("tornado.platform.asyncio.AsyncIOLoop")', + "print(classname(IOLoop.current()))", + ) + self.assertEqual(cls, "AsyncIOMainLoop") + + def test_asyncio_main(self): + cls = self.run_python( + "from tornado.platform.asyncio import AsyncIOMainLoop", + "AsyncIOMainLoop().install()", + "print(classname(IOLoop.current()))", + ) + self.assertEqual(cls, "AsyncIOMainLoop") + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/lib/python3.8/site-packages/tornado/test/iostream_test.py b/venv/lib/python3.8/site-packages/tornado/test/iostream_test.py new file mode 100644 index 0000000..a43aa64 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/iostream_test.py @@ -0,0 +1,1282 @@ +from tornado.concurrent import Future +from tornado import gen +from tornado import netutil +from tornado.ioloop import IOLoop +from tornado.iostream import ( + IOStream, + SSLIOStream, + PipeIOStream, + StreamClosedError, + _StreamBuffer, +) +from tornado.httputil import HTTPHeaders +from tornado.locks import Condition, Event +from tornado.log import gen_log +from tornado.netutil import ssl_wrap_socket +from tornado.platform.asyncio import AddThreadSelectorEventLoop +from tornado.tcpserver import TCPServer +from tornado.testing import ( + AsyncHTTPTestCase, + AsyncHTTPSTestCase, + AsyncTestCase, + bind_unused_port, + ExpectLog, + gen_test, +) +from tornado.test.util import skipIfNonUnix, refusing_port, skipPypy3V58 +from tornado.web import RequestHandler, Application +import asyncio +import errno +import hashlib +import logging +import os +import platform +import random +import socket +import ssl +import typing +from unittest import mock +import unittest + + +def _server_ssl_options(): + return dict( + certfile=os.path.join(os.path.dirname(__file__), "test.crt"), + keyfile=os.path.join(os.path.dirname(__file__), "test.key"), + ) + + +class HelloHandler(RequestHandler): + def get(self): + self.write("Hello") + + +class TestIOStreamWebMixin(object): + def _make_client_iostream(self): + raise NotImplementedError() + + def get_app(self): + return Application([("/", HelloHandler)]) + + def test_connection_closed(self: typing.Any): + # When a server sends a response and then closes the connection, + # the client must be allowed to read the data before the IOStream + # closes itself. Epoll reports closed connections with a separate + # EPOLLRDHUP event delivered at the same time as the read event, + # while kqueue reports them as a second read/write event with an EOF + # flag. + response = self.fetch("/", headers={"Connection": "close"}) + response.rethrow() + + @gen_test + def test_read_until_close(self: typing.Any): + stream = self._make_client_iostream() + yield stream.connect(("127.0.0.1", self.get_http_port())) + stream.write(b"GET / HTTP/1.0\r\n\r\n") + + data = yield stream.read_until_close() + self.assertTrue(data.startswith(b"HTTP/1.1 200")) + self.assertTrue(data.endswith(b"Hello")) + + @gen_test + def test_read_zero_bytes(self: typing.Any): + self.stream = self._make_client_iostream() + yield self.stream.connect(("127.0.0.1", self.get_http_port())) + self.stream.write(b"GET / HTTP/1.0\r\n\r\n") + + # normal read + data = yield self.stream.read_bytes(9) + self.assertEqual(data, b"HTTP/1.1 ") + + # zero bytes + data = yield self.stream.read_bytes(0) + self.assertEqual(data, b"") + + # another normal read + data = yield self.stream.read_bytes(3) + self.assertEqual(data, b"200") + + self.stream.close() + + @gen_test + def test_write_while_connecting(self: typing.Any): + stream = self._make_client_iostream() + connect_fut = stream.connect(("127.0.0.1", self.get_http_port())) + # unlike the previous tests, try to write before the connection + # is complete. + write_fut = stream.write(b"GET / HTTP/1.0\r\nConnection: close\r\n\r\n") + self.assertFalse(connect_fut.done()) + + # connect will always complete before write. + it = gen.WaitIterator(connect_fut, write_fut) + resolved_order = [] + while not it.done(): + yield it.next() + resolved_order.append(it.current_future) + self.assertEqual(resolved_order, [connect_fut, write_fut]) + + data = yield stream.read_until_close() + self.assertTrue(data.endswith(b"Hello")) + + stream.close() + + @gen_test + def test_future_interface(self: typing.Any): + """Basic test of IOStream's ability to return Futures.""" + stream = self._make_client_iostream() + connect_result = yield stream.connect(("127.0.0.1", self.get_http_port())) + self.assertIs(connect_result, stream) + yield stream.write(b"GET / HTTP/1.0\r\n\r\n") + first_line = yield stream.read_until(b"\r\n") + self.assertEqual(first_line, b"HTTP/1.1 200 OK\r\n") + # callback=None is equivalent to no callback. + header_data = yield stream.read_until(b"\r\n\r\n") + headers = HTTPHeaders.parse(header_data.decode("latin1")) + content_length = int(headers["Content-Length"]) + body = yield stream.read_bytes(content_length) + self.assertEqual(body, b"Hello") + stream.close() + + @gen_test + def test_future_close_while_reading(self: typing.Any): + stream = self._make_client_iostream() + yield stream.connect(("127.0.0.1", self.get_http_port())) + yield stream.write(b"GET / HTTP/1.0\r\n\r\n") + with self.assertRaises(StreamClosedError): + yield stream.read_bytes(1024 * 1024) + stream.close() + + @gen_test + def test_future_read_until_close(self: typing.Any): + # Ensure that the data comes through before the StreamClosedError. + stream = self._make_client_iostream() + yield stream.connect(("127.0.0.1", self.get_http_port())) + yield stream.write(b"GET / HTTP/1.0\r\nConnection: close\r\n\r\n") + yield stream.read_until(b"\r\n\r\n") + body = yield stream.read_until_close() + self.assertEqual(body, b"Hello") + + # Nothing else to read; the error comes immediately without waiting + # for yield. + with self.assertRaises(StreamClosedError): + stream.read_bytes(1) + + +class TestReadWriteMixin(object): + # Tests where one stream reads and the other writes. + # These should work for BaseIOStream implementations. + + def make_iostream_pair(self, **kwargs): + raise NotImplementedError + + def iostream_pair(self, **kwargs): + """Like make_iostream_pair, but called by ``async with``. + + In py37 this becomes simpler with contextlib.asynccontextmanager. + """ + + class IOStreamPairContext: + def __init__(self, test, kwargs): + self.test = test + self.kwargs = kwargs + + async def __aenter__(self): + self.pair = await self.test.make_iostream_pair(**self.kwargs) + return self.pair + + async def __aexit__(self, typ, value, tb): + for s in self.pair: + s.close() + + return IOStreamPairContext(self, kwargs) + + @gen_test + def test_write_zero_bytes(self): + # Attempting to write zero bytes should run the callback without + # going into an infinite loop. + rs, ws = yield self.make_iostream_pair() + yield ws.write(b"") + ws.close() + rs.close() + + @gen_test + def test_future_delayed_close_callback(self: typing.Any): + # Same as test_delayed_close_callback, but with the future interface. + rs, ws = yield self.make_iostream_pair() + + try: + ws.write(b"12") + chunks = [] + chunks.append((yield rs.read_bytes(1))) + ws.close() + chunks.append((yield rs.read_bytes(1))) + self.assertEqual(chunks, [b"1", b"2"]) + finally: + ws.close() + rs.close() + + @gen_test + def test_close_buffered_data(self: typing.Any): + # Similar to the previous test, but with data stored in the OS's + # socket buffers instead of the IOStream's read buffer. Out-of-band + # close notifications must be delayed until all data has been + # drained into the IOStream buffer. (epoll used to use out-of-band + # close events with EPOLLRDHUP, but no longer) + # + # This depends on the read_chunk_size being smaller than the + # OS socket buffer, so make it small. + rs, ws = yield self.make_iostream_pair(read_chunk_size=256) + try: + ws.write(b"A" * 512) + data = yield rs.read_bytes(256) + self.assertEqual(b"A" * 256, data) + ws.close() + # Allow the close to propagate to the `rs` side of the + # connection. Using add_callback instead of add_timeout + # doesn't seem to work, even with multiple iterations + yield gen.sleep(0.01) + data = yield rs.read_bytes(256) + self.assertEqual(b"A" * 256, data) + finally: + ws.close() + rs.close() + + @gen_test + def test_read_until_close_after_close(self: typing.Any): + # Similar to test_delayed_close_callback, but read_until_close takes + # a separate code path so test it separately. + rs, ws = yield self.make_iostream_pair() + try: + ws.write(b"1234") + # Read one byte to make sure the client has received the data. + # It won't run the close callback as long as there is more buffered + # data that could satisfy a later read. + data = yield rs.read_bytes(1) + ws.close() + self.assertEqual(data, b"1") + data = yield rs.read_until_close() + self.assertEqual(data, b"234") + finally: + ws.close() + rs.close() + + @gen_test + def test_large_read_until(self: typing.Any): + # Performance test: read_until used to have a quadratic component + # so a read_until of 4MB would take 8 seconds; now it takes 0.25 + # seconds. + rs, ws = yield self.make_iostream_pair() + try: + # This test fails on pypy with ssl. I think it's because + # pypy's gc defeats moves objects, breaking the + # "frozen write buffer" assumption. + if ( + isinstance(rs, SSLIOStream) + and platform.python_implementation() == "PyPy" + ): + raise unittest.SkipTest("pypy gc causes problems with openssl") + NUM_KB = 4096 + for i in range(NUM_KB): + ws.write(b"A" * 1024) + ws.write(b"\r\n") + data = yield rs.read_until(b"\r\n") + self.assertEqual(len(data), NUM_KB * 1024 + 2) + finally: + ws.close() + rs.close() + + @gen_test + async def test_read_until_with_close_after_second_packet(self): + # This is a regression test for a regression in Tornado 6.0 + # (maybe 6.0.3?) reported in + # https://github.com/tornadoweb/tornado/issues/2717 + # + # The data arrives in two chunks; the stream is closed at the + # same time that the second chunk is received. If the second + # chunk is larger than the first, it works, but when this bug + # existed it would fail if the second chunk were smaller than + # the first. This is due to the optimization that the + # read_until condition is only checked when the buffer doubles + # in size + async with self.iostream_pair() as (rs, ws): + rf = asyncio.ensure_future(rs.read_until(b"done")) + # We need to wait for the read_until to actually start. On + # windows that's tricky because the selector runs in + # another thread; sleeping is the simplest way. + await asyncio.sleep(0.1) + await ws.write(b"x" * 2048) + ws.write(b"done") + ws.close() + await rf + + @gen_test + async def test_read_until_unsatisfied_after_close(self: typing.Any): + # If a stream is closed while reading, it raises + # StreamClosedError instead of UnsatisfiableReadError (the + # latter should only be raised when byte limits are reached). + # The particular scenario tested here comes from #2717. + async with self.iostream_pair() as (rs, ws): + rf = asyncio.ensure_future(rs.read_until(b"done")) + await ws.write(b"x" * 2048) + ws.write(b"foo") + ws.close() + with self.assertRaises(StreamClosedError): + await rf + + @gen_test + def test_close_callback_with_pending_read(self: typing.Any): + # Regression test for a bug that was introduced in 2.3 + # where the IOStream._close_callback would never be called + # if there were pending reads. + OK = b"OK\r\n" + rs, ws = yield self.make_iostream_pair() + event = Event() + rs.set_close_callback(event.set) + try: + ws.write(OK) + res = yield rs.read_until(b"\r\n") + self.assertEqual(res, OK) + + ws.close() + rs.read_until(b"\r\n") + # If _close_callback (self.stop) is not called, + # an AssertionError: Async operation timed out after 5 seconds + # will be raised. + yield event.wait() + finally: + ws.close() + rs.close() + + @gen_test + def test_future_close_callback(self: typing.Any): + # Regression test for interaction between the Future read interfaces + # and IOStream._maybe_add_error_listener. + rs, ws = yield self.make_iostream_pair() + closed = [False] + cond = Condition() + + def close_callback(): + closed[0] = True + cond.notify() + + rs.set_close_callback(close_callback) + try: + ws.write(b"a") + res = yield rs.read_bytes(1) + self.assertEqual(res, b"a") + self.assertFalse(closed[0]) + ws.close() + yield cond.wait() + self.assertTrue(closed[0]) + finally: + rs.close() + ws.close() + + @gen_test + def test_write_memoryview(self: typing.Any): + rs, ws = yield self.make_iostream_pair() + try: + fut = rs.read_bytes(4) + ws.write(memoryview(b"hello")) + data = yield fut + self.assertEqual(data, b"hell") + finally: + ws.close() + rs.close() + + @gen_test + def test_read_bytes_partial(self: typing.Any): + rs, ws = yield self.make_iostream_pair() + try: + # Ask for more than is available with partial=True + fut = rs.read_bytes(50, partial=True) + ws.write(b"hello") + data = yield fut + self.assertEqual(data, b"hello") + + # Ask for less than what is available; num_bytes is still + # respected. + fut = rs.read_bytes(3, partial=True) + ws.write(b"world") + data = yield fut + self.assertEqual(data, b"wor") + + # Partial reads won't return an empty string, but read_bytes(0) + # will. + data = yield rs.read_bytes(0, partial=True) + self.assertEqual(data, b"") + finally: + ws.close() + rs.close() + + @gen_test + def test_read_until_max_bytes(self: typing.Any): + rs, ws = yield self.make_iostream_pair() + closed = Event() + rs.set_close_callback(closed.set) + try: + # Extra room under the limit + fut = rs.read_until(b"def", max_bytes=50) + ws.write(b"abcdef") + data = yield fut + self.assertEqual(data, b"abcdef") + + # Just enough space + fut = rs.read_until(b"def", max_bytes=6) + ws.write(b"abcdef") + data = yield fut + self.assertEqual(data, b"abcdef") + + # Not enough space, but we don't know it until all we can do is + # log a warning and close the connection. + with ExpectLog(gen_log, "Unsatisfiable read", level=logging.INFO): + fut = rs.read_until(b"def", max_bytes=5) + ws.write(b"123456") + yield closed.wait() + finally: + ws.close() + rs.close() + + @gen_test + def test_read_until_max_bytes_inline(self: typing.Any): + rs, ws = yield self.make_iostream_pair() + closed = Event() + rs.set_close_callback(closed.set) + try: + # Similar to the error case in the previous test, but the + # ws writes first so rs reads are satisfied + # inline. For consistency with the out-of-line case, we + # do not raise the error synchronously. + ws.write(b"123456") + with ExpectLog(gen_log, "Unsatisfiable read", level=logging.INFO): + with self.assertRaises(StreamClosedError): + yield rs.read_until(b"def", max_bytes=5) + yield closed.wait() + finally: + ws.close() + rs.close() + + @gen_test + def test_read_until_max_bytes_ignores_extra(self: typing.Any): + rs, ws = yield self.make_iostream_pair() + closed = Event() + rs.set_close_callback(closed.set) + try: + # Even though data that matches arrives the same packet that + # puts us over the limit, we fail the request because it was not + # found within the limit. + ws.write(b"abcdef") + with ExpectLog(gen_log, "Unsatisfiable read", level=logging.INFO): + rs.read_until(b"def", max_bytes=5) + yield closed.wait() + finally: + ws.close() + rs.close() + + @gen_test + def test_read_until_regex_max_bytes(self: typing.Any): + rs, ws = yield self.make_iostream_pair() + closed = Event() + rs.set_close_callback(closed.set) + try: + # Extra room under the limit + fut = rs.read_until_regex(b"def", max_bytes=50) + ws.write(b"abcdef") + data = yield fut + self.assertEqual(data, b"abcdef") + + # Just enough space + fut = rs.read_until_regex(b"def", max_bytes=6) + ws.write(b"abcdef") + data = yield fut + self.assertEqual(data, b"abcdef") + + # Not enough space, but we don't know it until all we can do is + # log a warning and close the connection. + with ExpectLog(gen_log, "Unsatisfiable read", level=logging.INFO): + rs.read_until_regex(b"def", max_bytes=5) + ws.write(b"123456") + yield closed.wait() + finally: + ws.close() + rs.close() + + @gen_test + def test_read_until_regex_max_bytes_inline(self: typing.Any): + rs, ws = yield self.make_iostream_pair() + closed = Event() + rs.set_close_callback(closed.set) + try: + # Similar to the error case in the previous test, but the + # ws writes first so rs reads are satisfied + # inline. For consistency with the out-of-line case, we + # do not raise the error synchronously. + ws.write(b"123456") + with ExpectLog(gen_log, "Unsatisfiable read", level=logging.INFO): + rs.read_until_regex(b"def", max_bytes=5) + yield closed.wait() + finally: + ws.close() + rs.close() + + @gen_test + def test_read_until_regex_max_bytes_ignores_extra(self): + rs, ws = yield self.make_iostream_pair() + closed = Event() + rs.set_close_callback(closed.set) + try: + # Even though data that matches arrives the same packet that + # puts us over the limit, we fail the request because it was not + # found within the limit. + ws.write(b"abcdef") + with ExpectLog(gen_log, "Unsatisfiable read", level=logging.INFO): + rs.read_until_regex(b"def", max_bytes=5) + yield closed.wait() + finally: + ws.close() + rs.close() + + @gen_test + def test_small_reads_from_large_buffer(self: typing.Any): + # 10KB buffer size, 100KB available to read. + # Read 1KB at a time and make sure that the buffer is not eagerly + # filled. + rs, ws = yield self.make_iostream_pair(max_buffer_size=10 * 1024) + try: + ws.write(b"a" * 1024 * 100) + for i in range(100): + data = yield rs.read_bytes(1024) + self.assertEqual(data, b"a" * 1024) + finally: + ws.close() + rs.close() + + @gen_test + def test_small_read_untils_from_large_buffer(self: typing.Any): + # 10KB buffer size, 100KB available to read. + # Read 1KB at a time and make sure that the buffer is not eagerly + # filled. + rs, ws = yield self.make_iostream_pair(max_buffer_size=10 * 1024) + try: + ws.write((b"a" * 1023 + b"\n") * 100) + for i in range(100): + data = yield rs.read_until(b"\n", max_bytes=4096) + self.assertEqual(data, b"a" * 1023 + b"\n") + finally: + ws.close() + rs.close() + + @gen_test + def test_flow_control(self): + MB = 1024 * 1024 + rs, ws = yield self.make_iostream_pair(max_buffer_size=5 * MB) + try: + # Client writes more than the rs will accept. + ws.write(b"a" * 10 * MB) + # The rs pauses while reading. + yield rs.read_bytes(MB) + yield gen.sleep(0.1) + # The ws's writes have been blocked; the rs can + # continue to read gradually. + for i in range(9): + yield rs.read_bytes(MB) + finally: + rs.close() + ws.close() + + @gen_test + def test_read_into(self: typing.Any): + rs, ws = yield self.make_iostream_pair() + + def sleep_some(): + self.io_loop.run_sync(lambda: gen.sleep(0.05)) + + try: + buf = bytearray(10) + fut = rs.read_into(buf) + ws.write(b"hello") + yield gen.sleep(0.05) + self.assertTrue(rs.reading()) + ws.write(b"world!!") + data = yield fut + self.assertFalse(rs.reading()) + self.assertEqual(data, 10) + self.assertEqual(bytes(buf), b"helloworld") + + # Existing buffer is fed into user buffer + fut = rs.read_into(buf) + yield gen.sleep(0.05) + self.assertTrue(rs.reading()) + ws.write(b"1234567890") + data = yield fut + self.assertFalse(rs.reading()) + self.assertEqual(data, 10) + self.assertEqual(bytes(buf), b"!!12345678") + + # Existing buffer can satisfy read immediately + buf = bytearray(4) + ws.write(b"abcdefghi") + data = yield rs.read_into(buf) + self.assertEqual(data, 4) + self.assertEqual(bytes(buf), b"90ab") + + data = yield rs.read_bytes(7) + self.assertEqual(data, b"cdefghi") + finally: + ws.close() + rs.close() + + @gen_test + def test_read_into_partial(self: typing.Any): + rs, ws = yield self.make_iostream_pair() + + try: + # Partial read + buf = bytearray(10) + fut = rs.read_into(buf, partial=True) + ws.write(b"hello") + data = yield fut + self.assertFalse(rs.reading()) + self.assertEqual(data, 5) + self.assertEqual(bytes(buf), b"hello\0\0\0\0\0") + + # Full read despite partial=True + ws.write(b"world!1234567890") + data = yield rs.read_into(buf, partial=True) + self.assertEqual(data, 10) + self.assertEqual(bytes(buf), b"world!1234") + + # Existing buffer can satisfy read immediately + data = yield rs.read_into(buf, partial=True) + self.assertEqual(data, 6) + self.assertEqual(bytes(buf), b"5678901234") + + finally: + ws.close() + rs.close() + + @gen_test + def test_read_into_zero_bytes(self: typing.Any): + rs, ws = yield self.make_iostream_pair() + try: + buf = bytearray() + fut = rs.read_into(buf) + self.assertEqual(fut.result(), 0) + finally: + ws.close() + rs.close() + + @gen_test + def test_many_mixed_reads(self): + # Stress buffer handling when going back and forth between + # read_bytes() (using an internal buffer) and read_into() + # (using a user-allocated buffer). + r = random.Random(42) + nbytes = 1000000 + rs, ws = yield self.make_iostream_pair() + + produce_hash = hashlib.sha1() + consume_hash = hashlib.sha1() + + @gen.coroutine + def produce(): + remaining = nbytes + while remaining > 0: + size = r.randint(1, min(1000, remaining)) + data = os.urandom(size) + produce_hash.update(data) + yield ws.write(data) + remaining -= size + assert remaining == 0 + + @gen.coroutine + def consume(): + remaining = nbytes + while remaining > 0: + if r.random() > 0.5: + # read_bytes() + size = r.randint(1, min(1000, remaining)) + data = yield rs.read_bytes(size) + consume_hash.update(data) + remaining -= size + else: + # read_into() + size = r.randint(1, min(1000, remaining)) + buf = bytearray(size) + n = yield rs.read_into(buf) + assert n == size + consume_hash.update(buf) + remaining -= size + assert remaining == 0 + + try: + yield [produce(), consume()] + assert produce_hash.hexdigest() == consume_hash.hexdigest() + finally: + ws.close() + rs.close() + + +class TestIOStreamMixin(TestReadWriteMixin): + def _make_server_iostream(self, connection, **kwargs): + raise NotImplementedError() + + def _make_client_iostream(self, connection, **kwargs): + raise NotImplementedError() + + @gen.coroutine + def make_iostream_pair(self: typing.Any, **kwargs): + listener, port = bind_unused_port() + server_stream_fut = Future() # type: Future[IOStream] + + def accept_callback(connection, address): + server_stream_fut.set_result( + self._make_server_iostream(connection, **kwargs) + ) + + netutil.add_accept_handler(listener, accept_callback) + client_stream = self._make_client_iostream(socket.socket(), **kwargs) + connect_fut = client_stream.connect(("127.0.0.1", port)) + server_stream, client_stream = yield [server_stream_fut, connect_fut] + self.io_loop.remove_handler(listener.fileno()) + listener.close() + raise gen.Return((server_stream, client_stream)) + + @gen_test + def test_connection_refused(self: typing.Any): + # When a connection is refused, the connect callback should not + # be run. (The kqueue IOLoop used to behave differently from the + # epoll IOLoop in this respect) + cleanup_func, port = refusing_port() + self.addCleanup(cleanup_func) + stream = IOStream(socket.socket()) + + stream.set_close_callback(self.stop) + # log messages vary by platform and ioloop implementation + with ExpectLog(gen_log, ".*", required=False): + with self.assertRaises(StreamClosedError): + yield stream.connect(("127.0.0.1", port)) + + self.assertTrue(isinstance(stream.error, ConnectionRefusedError), stream.error) + + @gen_test + def test_gaierror(self: typing.Any): + # Test that IOStream sets its exc_info on getaddrinfo error. + # It's difficult to reliably trigger a getaddrinfo error; + # some resolvers own't even return errors for malformed names, + # so we mock it instead. If IOStream changes to call a Resolver + # before sock.connect, the mock target will need to change too. + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) + stream = IOStream(s) + stream.set_close_callback(self.stop) + with mock.patch( + "socket.socket.connect", side_effect=socket.gaierror(errno.EIO, "boom") + ): + with self.assertRaises(StreamClosedError): + yield stream.connect(("localhost", 80)) + self.assertTrue(isinstance(stream.error, socket.gaierror)) + + @gen_test + def test_read_until_close_with_error(self: typing.Any): + server, client = yield self.make_iostream_pair() + try: + with mock.patch( + "tornado.iostream.BaseIOStream._try_inline_read", + side_effect=IOError("boom"), + ): + with self.assertRaisesRegexp(IOError, "boom"): + client.read_until_close() + finally: + server.close() + client.close() + + @skipIfNonUnix + @skipPypy3V58 + @gen_test + def test_inline_read_error(self: typing.Any): + # An error on an inline read is raised without logging (on the + # assumption that it will eventually be noticed or logged further + # up the stack). + # + # This test is posix-only because windows os.close() doesn't work + # on socket FDs, but we can't close the socket object normally + # because we won't get the error we want if the socket knows + # it's closed. + # + # This test is also disabled when the + # AddThreadSelectorEventLoop is used, because a race between + # this thread closing the socket and the selector thread + # calling the select system call can make this test flaky. + # This event loop implementation is normally only used on + # windows, making this check redundant with skipIfNonUnix, but + # we sometimes enable it on other platforms for testing. + io_loop = IOLoop.current() + if isinstance(io_loop.selector_loop, AddThreadSelectorEventLoop): + self.skipTest("AddThreadSelectorEventLoop not supported") + server, client = yield self.make_iostream_pair() + try: + os.close(server.socket.fileno()) + with self.assertRaises(socket.error): + server.read_bytes(1) + finally: + server.close() + client.close() + + @skipPypy3V58 + @gen_test + def test_async_read_error_logging(self): + # Socket errors on asynchronous reads should be logged (but only + # once). + server, client = yield self.make_iostream_pair() + closed = Event() + server.set_close_callback(closed.set) + try: + # Start a read that will be fulfilled asynchronously. + server.read_bytes(1) + client.write(b"a") + # Stub out read_from_fd to make it fail. + + def fake_read_from_fd(): + os.close(server.socket.fileno()) + server.__class__.read_from_fd(server) + + server.read_from_fd = fake_read_from_fd + # This log message is from _handle_read (not read_from_fd). + with ExpectLog(gen_log, "error on read"): + yield closed.wait() + finally: + server.close() + client.close() + + @gen_test + def test_future_write(self): + """ + Test that write() Futures are never orphaned. + """ + # Run concurrent writers that will write enough bytes so as to + # clog the socket buffer and accumulate bytes in our write buffer. + m, n = 5000, 1000 + nproducers = 10 + total_bytes = m * n * nproducers + server, client = yield self.make_iostream_pair(max_buffer_size=total_bytes) + + @gen.coroutine + def produce(): + data = b"x" * m + for i in range(n): + yield server.write(data) + + @gen.coroutine + def consume(): + nread = 0 + while nread < total_bytes: + res = yield client.read_bytes(m) + nread += len(res) + + try: + yield [produce() for i in range(nproducers)] + [consume()] + finally: + server.close() + client.close() + + +class TestIOStreamWebHTTP(TestIOStreamWebMixin, AsyncHTTPTestCase): + def _make_client_iostream(self): + return IOStream(socket.socket()) + + +class TestIOStreamWebHTTPS(TestIOStreamWebMixin, AsyncHTTPSTestCase): + def _make_client_iostream(self): + return SSLIOStream(socket.socket(), ssl_options=dict(cert_reqs=ssl.CERT_NONE)) + + +class TestIOStream(TestIOStreamMixin, AsyncTestCase): + def _make_server_iostream(self, connection, **kwargs): + return IOStream(connection, **kwargs) + + def _make_client_iostream(self, connection, **kwargs): + return IOStream(connection, **kwargs) + + +class TestIOStreamSSL(TestIOStreamMixin, AsyncTestCase): + def _make_server_iostream(self, connection, **kwargs): + connection = ssl.wrap_socket( + connection, + server_side=True, + do_handshake_on_connect=False, + **_server_ssl_options() + ) + return SSLIOStream(connection, **kwargs) + + def _make_client_iostream(self, connection, **kwargs): + return SSLIOStream( + connection, ssl_options=dict(cert_reqs=ssl.CERT_NONE), **kwargs + ) + + +# This will run some tests that are basically redundant but it's the +# simplest way to make sure that it works to pass an SSLContext +# instead of an ssl_options dict to the SSLIOStream constructor. +class TestIOStreamSSLContext(TestIOStreamMixin, AsyncTestCase): + def _make_server_iostream(self, connection, **kwargs): + context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) + context.load_cert_chain( + os.path.join(os.path.dirname(__file__), "test.crt"), + os.path.join(os.path.dirname(__file__), "test.key"), + ) + connection = ssl_wrap_socket( + connection, context, server_side=True, do_handshake_on_connect=False + ) + return SSLIOStream(connection, **kwargs) + + def _make_client_iostream(self, connection, **kwargs): + context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) + return SSLIOStream(connection, ssl_options=context, **kwargs) + + +class TestIOStreamStartTLS(AsyncTestCase): + def setUp(self): + try: + super().setUp() + self.listener, self.port = bind_unused_port() + self.server_stream = None + self.server_accepted = Future() # type: Future[None] + netutil.add_accept_handler(self.listener, self.accept) + self.client_stream = IOStream( + socket.socket() + ) # type: typing.Optional[IOStream] + self.io_loop.add_future( + self.client_stream.connect(("127.0.0.1", self.port)), self.stop + ) + self.wait() + self.io_loop.add_future(self.server_accepted, self.stop) + self.wait() + except Exception as e: + print(e) + raise + + def tearDown(self): + if self.server_stream is not None: + self.server_stream.close() + if self.client_stream is not None: + self.client_stream.close() + self.io_loop.remove_handler(self.listener.fileno()) + self.listener.close() + super().tearDown() + + def accept(self, connection, address): + if self.server_stream is not None: + self.fail("should only get one connection") + self.server_stream = IOStream(connection) + self.server_accepted.set_result(None) + + @gen.coroutine + def client_send_line(self, line): + assert self.client_stream is not None + self.client_stream.write(line) + assert self.server_stream is not None + recv_line = yield self.server_stream.read_until(b"\r\n") + self.assertEqual(line, recv_line) + + @gen.coroutine + def server_send_line(self, line): + assert self.server_stream is not None + self.server_stream.write(line) + assert self.client_stream is not None + recv_line = yield self.client_stream.read_until(b"\r\n") + self.assertEqual(line, recv_line) + + def client_start_tls(self, ssl_options=None, server_hostname=None): + assert self.client_stream is not None + client_stream = self.client_stream + self.client_stream = None + return client_stream.start_tls(False, ssl_options, server_hostname) + + def server_start_tls(self, ssl_options=None): + assert self.server_stream is not None + server_stream = self.server_stream + self.server_stream = None + return server_stream.start_tls(True, ssl_options) + + @gen_test + def test_start_tls_smtp(self): + # This flow is simplified from RFC 3207 section 5. + # We don't really need all of this, but it helps to make sure + # that after realistic back-and-forth traffic the buffers end up + # in a sane state. + yield self.server_send_line(b"220 mail.example.com ready\r\n") + yield self.client_send_line(b"EHLO mail.example.com\r\n") + yield self.server_send_line(b"250-mail.example.com welcome\r\n") + yield self.server_send_line(b"250 STARTTLS\r\n") + yield self.client_send_line(b"STARTTLS\r\n") + yield self.server_send_line(b"220 Go ahead\r\n") + client_future = self.client_start_tls(dict(cert_reqs=ssl.CERT_NONE)) + server_future = self.server_start_tls(_server_ssl_options()) + self.client_stream = yield client_future + self.server_stream = yield server_future + self.assertTrue(isinstance(self.client_stream, SSLIOStream)) + self.assertTrue(isinstance(self.server_stream, SSLIOStream)) + yield self.client_send_line(b"EHLO mail.example.com\r\n") + yield self.server_send_line(b"250 mail.example.com welcome\r\n") + + @gen_test + def test_handshake_fail(self): + server_future = self.server_start_tls(_server_ssl_options()) + # Certificates are verified with the default configuration. + with ExpectLog(gen_log, "SSL Error"): + client_future = self.client_start_tls(server_hostname="localhost") + with self.assertRaises(ssl.SSLError): + yield client_future + with self.assertRaises((ssl.SSLError, socket.error)): + yield server_future + + @gen_test + def test_check_hostname(self): + # Test that server_hostname parameter to start_tls is being used. + # The check_hostname functionality is only available in python 2.7 and + # up and in python 3.4 and up. + server_future = self.server_start_tls(_server_ssl_options()) + with ExpectLog(gen_log, "SSL Error"): + client_future = self.client_start_tls( + ssl.create_default_context(), server_hostname="127.0.0.1" + ) + with self.assertRaises(ssl.SSLError): + # The client fails to connect with an SSL error. + yield client_future + with self.assertRaises(Exception): + # The server fails to connect, but the exact error is unspecified. + yield server_future + + +class WaitForHandshakeTest(AsyncTestCase): + @gen.coroutine + def connect_to_server(self, server_cls): + server = client = None + try: + sock, port = bind_unused_port() + server = server_cls(ssl_options=_server_ssl_options()) + server.add_socket(sock) + + ssl_ctx = ssl.create_default_context(ssl.Purpose.SERVER_AUTH) + ssl_ctx.check_hostname = False + ssl_ctx.verify_mode = ssl.CERT_NONE + # These tests fail with ConnectionAbortedErrors with TLS + # 1.3 on windows python 3.7.4 (which includes an upgrade + # to openssl 1.1.c. Other platforms might be affected with + # newer openssl too). Disable it until we figure out + # what's up. + ssl_ctx.options |= getattr(ssl, "OP_NO_TLSv1_3", 0) + client = SSLIOStream(socket.socket(), ssl_options=ssl_ctx) + yield client.connect(("127.0.0.1", port)) + self.assertIsNotNone(client.socket.cipher()) + finally: + if server is not None: + server.stop() + if client is not None: + client.close() + + @gen_test + def test_wait_for_handshake_future(self): + test = self + handshake_future = Future() # type: Future[None] + + class TestServer(TCPServer): + def handle_stream(self, stream, address): + test.assertIsNone(stream.socket.cipher()) + test.io_loop.spawn_callback(self.handle_connection, stream) + + @gen.coroutine + def handle_connection(self, stream): + yield stream.wait_for_handshake() + handshake_future.set_result(None) + + yield self.connect_to_server(TestServer) + yield handshake_future + + @gen_test + def test_wait_for_handshake_already_waiting_error(self): + test = self + handshake_future = Future() # type: Future[None] + + class TestServer(TCPServer): + @gen.coroutine + def handle_stream(self, stream, address): + fut = stream.wait_for_handshake() + test.assertRaises(RuntimeError, stream.wait_for_handshake) + yield fut + + handshake_future.set_result(None) + + yield self.connect_to_server(TestServer) + yield handshake_future + + @gen_test + def test_wait_for_handshake_already_connected(self): + handshake_future = Future() # type: Future[None] + + class TestServer(TCPServer): + @gen.coroutine + def handle_stream(self, stream, address): + yield stream.wait_for_handshake() + yield stream.wait_for_handshake() + handshake_future.set_result(None) + + yield self.connect_to_server(TestServer) + yield handshake_future + + +@skipIfNonUnix +class TestPipeIOStream(TestReadWriteMixin, AsyncTestCase): + @gen.coroutine + def make_iostream_pair(self, **kwargs): + r, w = os.pipe() + + return PipeIOStream(r, **kwargs), PipeIOStream(w, **kwargs) + + @gen_test + def test_pipe_iostream(self): + rs, ws = yield self.make_iostream_pair() + + ws.write(b"hel") + ws.write(b"lo world") + + data = yield rs.read_until(b" ") + self.assertEqual(data, b"hello ") + + data = yield rs.read_bytes(3) + self.assertEqual(data, b"wor") + + ws.close() + + data = yield rs.read_until_close() + self.assertEqual(data, b"ld") + + rs.close() + + @gen_test + def test_pipe_iostream_big_write(self): + rs, ws = yield self.make_iostream_pair() + + NUM_BYTES = 1048576 + + # Write 1MB of data, which should fill the buffer + ws.write(b"1" * NUM_BYTES) + + data = yield rs.read_bytes(NUM_BYTES) + self.assertEqual(data, b"1" * NUM_BYTES) + + ws.close() + rs.close() + + +class TestStreamBuffer(unittest.TestCase): + """ + Unit tests for the private _StreamBuffer class. + """ + + def setUp(self): + self.random = random.Random(42) + + def to_bytes(self, b): + if isinstance(b, (bytes, bytearray)): + return bytes(b) + elif isinstance(b, memoryview): + return b.tobytes() # For py2 + else: + raise TypeError(b) + + def make_streambuffer(self, large_buf_threshold=10): + buf = _StreamBuffer() + assert buf._large_buf_threshold + buf._large_buf_threshold = large_buf_threshold + return buf + + def check_peek(self, buf, expected): + size = 1 + while size < 2 * len(expected): + got = self.to_bytes(buf.peek(size)) + self.assertTrue(got) # Not empty + self.assertLessEqual(len(got), size) + self.assertTrue(expected.startswith(got), (expected, got)) + size = (size * 3 + 1) // 2 + + def check_append_all_then_skip_all(self, buf, objs, input_type): + self.assertEqual(len(buf), 0) + + expected = b"" + + for o in objs: + expected += o + buf.append(input_type(o)) + self.assertEqual(len(buf), len(expected)) + self.check_peek(buf, expected) + + while expected: + n = self.random.randrange(1, len(expected) + 1) + expected = expected[n:] + buf.advance(n) + self.assertEqual(len(buf), len(expected)) + self.check_peek(buf, expected) + + self.assertEqual(len(buf), 0) + + def test_small(self): + objs = [b"12", b"345", b"67", b"89a", b"bcde", b"fgh", b"ijklmn"] + + buf = self.make_streambuffer() + self.check_append_all_then_skip_all(buf, objs, bytes) + + buf = self.make_streambuffer() + self.check_append_all_then_skip_all(buf, objs, bytearray) + + buf = self.make_streambuffer() + self.check_append_all_then_skip_all(buf, objs, memoryview) + + # Test internal algorithm + buf = self.make_streambuffer(10) + for i in range(9): + buf.append(b"x") + self.assertEqual(len(buf._buffers), 1) + for i in range(9): + buf.append(b"x") + self.assertEqual(len(buf._buffers), 2) + buf.advance(10) + self.assertEqual(len(buf._buffers), 1) + buf.advance(8) + self.assertEqual(len(buf._buffers), 0) + self.assertEqual(len(buf), 0) + + def test_large(self): + objs = [ + b"12" * 5, + b"345" * 2, + b"67" * 20, + b"89a" * 12, + b"bcde" * 1, + b"fgh" * 7, + b"ijklmn" * 2, + ] + + buf = self.make_streambuffer() + self.check_append_all_then_skip_all(buf, objs, bytes) + + buf = self.make_streambuffer() + self.check_append_all_then_skip_all(buf, objs, bytearray) + + buf = self.make_streambuffer() + self.check_append_all_then_skip_all(buf, objs, memoryview) + + # Test internal algorithm + buf = self.make_streambuffer(10) + for i in range(3): + buf.append(b"x" * 11) + self.assertEqual(len(buf._buffers), 3) + buf.append(b"y") + self.assertEqual(len(buf._buffers), 4) + buf.append(b"z") + self.assertEqual(len(buf._buffers), 4) + buf.advance(33) + self.assertEqual(len(buf._buffers), 1) + buf.advance(2) + self.assertEqual(len(buf._buffers), 0) + self.assertEqual(len(buf), 0) diff --git a/venv/lib/python3.8/site-packages/tornado/test/locale_test.py b/venv/lib/python3.8/site-packages/tornado/test/locale_test.py new file mode 100644 index 0000000..a12dc98 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/locale_test.py @@ -0,0 +1,151 @@ +import datetime +import os +import shutil +import tempfile +import unittest + +import tornado.locale +from tornado.escape import utf8, to_unicode +from tornado.util import unicode_type + + +class TranslationLoaderTest(unittest.TestCase): + # TODO: less hacky way to get isolated tests + SAVE_VARS = ["_translations", "_supported_locales", "_use_gettext"] + + def clear_locale_cache(self): + tornado.locale.Locale._cache = {} + + def setUp(self): + self.saved = {} # type: dict + for var in TranslationLoaderTest.SAVE_VARS: + self.saved[var] = getattr(tornado.locale, var) + self.clear_locale_cache() + + def tearDown(self): + for k, v in self.saved.items(): + setattr(tornado.locale, k, v) + self.clear_locale_cache() + + def test_csv(self): + tornado.locale.load_translations( + os.path.join(os.path.dirname(__file__), "csv_translations") + ) + locale = tornado.locale.get("fr_FR") + self.assertTrue(isinstance(locale, tornado.locale.CSVLocale)) + self.assertEqual(locale.translate("school"), u"\u00e9cole") + + def test_csv_bom(self): + with open( + os.path.join(os.path.dirname(__file__), "csv_translations", "fr_FR.csv"), + "rb", + ) as f: + char_data = to_unicode(f.read()) + # Re-encode our input data (which is utf-8 without BOM) in + # encodings that use the BOM and ensure that we can still load + # it. Note that utf-16-le and utf-16-be do not write a BOM, + # so we only test whichver variant is native to our platform. + for encoding in ["utf-8-sig", "utf-16"]: + tmpdir = tempfile.mkdtemp() + try: + with open(os.path.join(tmpdir, "fr_FR.csv"), "wb") as f: + f.write(char_data.encode(encoding)) + tornado.locale.load_translations(tmpdir) + locale = tornado.locale.get("fr_FR") + self.assertIsInstance(locale, tornado.locale.CSVLocale) + self.assertEqual(locale.translate("school"), u"\u00e9cole") + finally: + shutil.rmtree(tmpdir) + + def test_gettext(self): + tornado.locale.load_gettext_translations( + os.path.join(os.path.dirname(__file__), "gettext_translations"), + "tornado_test", + ) + locale = tornado.locale.get("fr_FR") + self.assertTrue(isinstance(locale, tornado.locale.GettextLocale)) + self.assertEqual(locale.translate("school"), u"\u00e9cole") + self.assertEqual(locale.pgettext("law", "right"), u"le droit") + self.assertEqual(locale.pgettext("good", "right"), u"le bien") + self.assertEqual( + locale.pgettext("organization", "club", "clubs", 1), u"le club" + ) + self.assertEqual( + locale.pgettext("organization", "club", "clubs", 2), u"les clubs" + ) + self.assertEqual(locale.pgettext("stick", "club", "clubs", 1), u"le b\xe2ton") + self.assertEqual(locale.pgettext("stick", "club", "clubs", 2), u"les b\xe2tons") + + +class LocaleDataTest(unittest.TestCase): + def test_non_ascii_name(self): + name = tornado.locale.LOCALE_NAMES["es_LA"]["name"] + self.assertTrue(isinstance(name, unicode_type)) + self.assertEqual(name, u"Espa\u00f1ol") + self.assertEqual(utf8(name), b"Espa\xc3\xb1ol") + + +class EnglishTest(unittest.TestCase): + def test_format_date(self): + locale = tornado.locale.get("en_US") + date = datetime.datetime(2013, 4, 28, 18, 35) + self.assertEqual( + locale.format_date(date, full_format=True), "April 28, 2013 at 6:35 pm" + ) + + now = datetime.datetime.utcnow() + + self.assertEqual( + locale.format_date(now - datetime.timedelta(seconds=2), full_format=False), + "2 seconds ago", + ) + self.assertEqual( + locale.format_date(now - datetime.timedelta(minutes=2), full_format=False), + "2 minutes ago", + ) + self.assertEqual( + locale.format_date(now - datetime.timedelta(hours=2), full_format=False), + "2 hours ago", + ) + + self.assertEqual( + locale.format_date( + now - datetime.timedelta(days=1), full_format=False, shorter=True + ), + "yesterday", + ) + + date = now - datetime.timedelta(days=2) + self.assertEqual( + locale.format_date(date, full_format=False, shorter=True), + locale._weekdays[date.weekday()], + ) + + date = now - datetime.timedelta(days=300) + self.assertEqual( + locale.format_date(date, full_format=False, shorter=True), + "%s %d" % (locale._months[date.month - 1], date.day), + ) + + date = now - datetime.timedelta(days=500) + self.assertEqual( + locale.format_date(date, full_format=False, shorter=True), + "%s %d, %d" % (locale._months[date.month - 1], date.day, date.year), + ) + + def test_friendly_number(self): + locale = tornado.locale.get("en_US") + self.assertEqual(locale.friendly_number(1000000), "1,000,000") + + def test_list(self): + locale = tornado.locale.get("en_US") + self.assertEqual(locale.list([]), "") + self.assertEqual(locale.list(["A"]), "A") + self.assertEqual(locale.list(["A", "B"]), "A and B") + self.assertEqual(locale.list(["A", "B", "C"]), "A, B and C") + + def test_format_day(self): + locale = tornado.locale.get("en_US") + date = datetime.datetime(2013, 4, 28, 18, 35) + self.assertEqual(locale.format_day(date=date, dow=True), "Sunday, April 28") + self.assertEqual(locale.format_day(date=date, dow=False), "April 28") diff --git a/venv/lib/python3.8/site-packages/tornado/test/locks_test.py b/venv/lib/python3.8/site-packages/tornado/test/locks_test.py new file mode 100644 index 0000000..23e1c52 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/locks_test.py @@ -0,0 +1,535 @@ +# 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. + +import asyncio +from datetime import timedelta +import typing # noqa: F401 +import unittest + +from tornado import gen, locks +from tornado.gen import TimeoutError +from tornado.testing import gen_test, AsyncTestCase + + +class ConditionTest(AsyncTestCase): + def setUp(self): + super().setUp() + self.history = [] # type: typing.List[typing.Union[int, str]] + + def record_done(self, future, key): + """Record the resolution of a Future returned by Condition.wait.""" + + def callback(_): + if not future.result(): + # wait() resolved to False, meaning it timed out. + self.history.append("timeout") + else: + self.history.append(key) + + future.add_done_callback(callback) + + def loop_briefly(self): + """Run all queued callbacks on the IOLoop. + + In these tests, this method is used after calling notify() to + preserve the pre-5.0 behavior in which callbacks ran + synchronously. + """ + self.io_loop.add_callback(self.stop) + self.wait() + + def test_repr(self): + c = locks.Condition() + self.assertIn("Condition", repr(c)) + self.assertNotIn("waiters", repr(c)) + c.wait() + self.assertIn("waiters", repr(c)) + + @gen_test + def test_notify(self): + c = locks.Condition() + self.io_loop.call_later(0.01, c.notify) + yield c.wait() + + def test_notify_1(self): + c = locks.Condition() + self.record_done(c.wait(), "wait1") + self.record_done(c.wait(), "wait2") + c.notify(1) + self.loop_briefly() + self.history.append("notify1") + c.notify(1) + self.loop_briefly() + self.history.append("notify2") + self.assertEqual(["wait1", "notify1", "wait2", "notify2"], self.history) + + def test_notify_n(self): + c = locks.Condition() + for i in range(6): + self.record_done(c.wait(), i) + + c.notify(3) + self.loop_briefly() + + # Callbacks execute in the order they were registered. + self.assertEqual(list(range(3)), self.history) + c.notify(1) + self.loop_briefly() + self.assertEqual(list(range(4)), self.history) + c.notify(2) + self.loop_briefly() + self.assertEqual(list(range(6)), self.history) + + def test_notify_all(self): + c = locks.Condition() + for i in range(4): + self.record_done(c.wait(), i) + + c.notify_all() + self.loop_briefly() + self.history.append("notify_all") + + # Callbacks execute in the order they were registered. + self.assertEqual(list(range(4)) + ["notify_all"], self.history) # type: ignore + + @gen_test + def test_wait_timeout(self): + c = locks.Condition() + wait = c.wait(timedelta(seconds=0.01)) + self.io_loop.call_later(0.02, c.notify) # Too late. + yield gen.sleep(0.03) + self.assertFalse((yield wait)) + + @gen_test + def test_wait_timeout_preempted(self): + c = locks.Condition() + + # This fires before the wait times out. + self.io_loop.call_later(0.01, c.notify) + wait = c.wait(timedelta(seconds=0.02)) + yield gen.sleep(0.03) + yield wait # No TimeoutError. + + @gen_test + def test_notify_n_with_timeout(self): + # Register callbacks 0, 1, 2, and 3. Callback 1 has a timeout. + # Wait for that timeout to expire, then do notify(2) and make + # sure everyone runs. Verifies that a timed-out callback does + # not count against the 'n' argument to notify(). + c = locks.Condition() + self.record_done(c.wait(), 0) + self.record_done(c.wait(timedelta(seconds=0.01)), 1) + self.record_done(c.wait(), 2) + self.record_done(c.wait(), 3) + + # Wait for callback 1 to time out. + yield gen.sleep(0.02) + self.assertEqual(["timeout"], self.history) + + c.notify(2) + yield gen.sleep(0.01) + self.assertEqual(["timeout", 0, 2], self.history) + self.assertEqual(["timeout", 0, 2], self.history) + c.notify() + yield + self.assertEqual(["timeout", 0, 2, 3], self.history) + + @gen_test + def test_notify_all_with_timeout(self): + c = locks.Condition() + self.record_done(c.wait(), 0) + self.record_done(c.wait(timedelta(seconds=0.01)), 1) + self.record_done(c.wait(), 2) + + # Wait for callback 1 to time out. + yield gen.sleep(0.02) + self.assertEqual(["timeout"], self.history) + + c.notify_all() + yield + self.assertEqual(["timeout", 0, 2], self.history) + + @gen_test + def test_nested_notify(self): + # Ensure no notifications lost, even if notify() is reentered by a + # waiter calling notify(). + c = locks.Condition() + + # Three waiters. + futures = [asyncio.ensure_future(c.wait()) for _ in range(3)] + + # First and second futures resolved. Second future reenters notify(), + # resolving third future. + futures[1].add_done_callback(lambda _: c.notify()) + c.notify(2) + yield + self.assertTrue(all(f.done() for f in futures)) + + @gen_test + def test_garbage_collection(self): + # Test that timed-out waiters are occasionally cleaned from the queue. + c = locks.Condition() + for _ in range(101): + c.wait(timedelta(seconds=0.01)) + + future = asyncio.ensure_future(c.wait()) + self.assertEqual(102, len(c._waiters)) + + # Let first 101 waiters time out, triggering a collection. + yield gen.sleep(0.02) + self.assertEqual(1, len(c._waiters)) + + # Final waiter is still active. + self.assertFalse(future.done()) + c.notify() + self.assertTrue(future.done()) + + +class EventTest(AsyncTestCase): + def test_repr(self): + event = locks.Event() + self.assertTrue("clear" in str(event)) + self.assertFalse("set" in str(event)) + event.set() + self.assertFalse("clear" in str(event)) + self.assertTrue("set" in str(event)) + + def test_event(self): + e = locks.Event() + future_0 = asyncio.ensure_future(e.wait()) + e.set() + future_1 = asyncio.ensure_future(e.wait()) + e.clear() + future_2 = asyncio.ensure_future(e.wait()) + + self.assertTrue(future_0.done()) + self.assertTrue(future_1.done()) + self.assertFalse(future_2.done()) + + @gen_test + def test_event_timeout(self): + e = locks.Event() + with self.assertRaises(TimeoutError): + yield e.wait(timedelta(seconds=0.01)) + + # After a timed-out waiter, normal operation works. + self.io_loop.add_timeout(timedelta(seconds=0.01), e.set) + yield e.wait(timedelta(seconds=1)) + + def test_event_set_multiple(self): + e = locks.Event() + e.set() + e.set() + self.assertTrue(e.is_set()) + + def test_event_wait_clear(self): + e = locks.Event() + f0 = asyncio.ensure_future(e.wait()) + e.clear() + f1 = asyncio.ensure_future(e.wait()) + e.set() + self.assertTrue(f0.done()) + self.assertTrue(f1.done()) + + +class SemaphoreTest(AsyncTestCase): + def test_negative_value(self): + self.assertRaises(ValueError, locks.Semaphore, value=-1) + + def test_repr(self): + sem = locks.Semaphore() + self.assertIn("Semaphore", repr(sem)) + self.assertIn("unlocked,value:1", repr(sem)) + sem.acquire() + self.assertIn("locked", repr(sem)) + self.assertNotIn("waiters", repr(sem)) + sem.acquire() + self.assertIn("waiters", repr(sem)) + + def test_acquire(self): + sem = locks.Semaphore() + f0 = asyncio.ensure_future(sem.acquire()) + self.assertTrue(f0.done()) + + # Wait for release(). + f1 = asyncio.ensure_future(sem.acquire()) + self.assertFalse(f1.done()) + f2 = asyncio.ensure_future(sem.acquire()) + sem.release() + self.assertTrue(f1.done()) + self.assertFalse(f2.done()) + sem.release() + self.assertTrue(f2.done()) + + sem.release() + # Now acquire() is instant. + self.assertTrue(asyncio.ensure_future(sem.acquire()).done()) + self.assertEqual(0, len(sem._waiters)) + + @gen_test + def test_acquire_timeout(self): + sem = locks.Semaphore(2) + yield sem.acquire() + yield sem.acquire() + acquire = sem.acquire(timedelta(seconds=0.01)) + self.io_loop.call_later(0.02, sem.release) # Too late. + yield gen.sleep(0.3) + with self.assertRaises(gen.TimeoutError): + yield acquire + + sem.acquire() + f = asyncio.ensure_future(sem.acquire()) + self.assertFalse(f.done()) + sem.release() + self.assertTrue(f.done()) + + @gen_test + def test_acquire_timeout_preempted(self): + sem = locks.Semaphore(1) + yield sem.acquire() + + # This fires before the wait times out. + self.io_loop.call_later(0.01, sem.release) + acquire = sem.acquire(timedelta(seconds=0.02)) + yield gen.sleep(0.03) + yield acquire # No TimeoutError. + + def test_release_unacquired(self): + # Unbounded releases are allowed, and increment the semaphore's value. + sem = locks.Semaphore() + sem.release() + sem.release() + + # Now the counter is 3. We can acquire three times before blocking. + self.assertTrue(asyncio.ensure_future(sem.acquire()).done()) + self.assertTrue(asyncio.ensure_future(sem.acquire()).done()) + self.assertTrue(asyncio.ensure_future(sem.acquire()).done()) + self.assertFalse(asyncio.ensure_future(sem.acquire()).done()) + + @gen_test + def test_garbage_collection(self): + # Test that timed-out waiters are occasionally cleaned from the queue. + sem = locks.Semaphore(value=0) + futures = [ + asyncio.ensure_future(sem.acquire(timedelta(seconds=0.01))) + for _ in range(101) + ] + + future = asyncio.ensure_future(sem.acquire()) + self.assertEqual(102, len(sem._waiters)) + + # Let first 101 waiters time out, triggering a collection. + yield gen.sleep(0.02) + self.assertEqual(1, len(sem._waiters)) + + # Final waiter is still active. + self.assertFalse(future.done()) + sem.release() + self.assertTrue(future.done()) + + # Prevent "Future exception was never retrieved" messages. + for future in futures: + self.assertRaises(TimeoutError, future.result) + + +class SemaphoreContextManagerTest(AsyncTestCase): + @gen_test + def test_context_manager(self): + sem = locks.Semaphore() + with (yield sem.acquire()) as yielded: + self.assertTrue(yielded is None) + + # Semaphore was released and can be acquired again. + self.assertTrue(asyncio.ensure_future(sem.acquire()).done()) + + @gen_test + def test_context_manager_async_await(self): + # Repeat the above test using 'async with'. + sem = locks.Semaphore() + + async def f(): + async with sem as yielded: + self.assertTrue(yielded is None) + + yield f() + + # Semaphore was released and can be acquired again. + self.assertTrue(asyncio.ensure_future(sem.acquire()).done()) + + @gen_test + def test_context_manager_exception(self): + sem = locks.Semaphore() + with self.assertRaises(ZeroDivisionError): + with (yield sem.acquire()): + 1 / 0 + + # Semaphore was released and can be acquired again. + self.assertTrue(asyncio.ensure_future(sem.acquire()).done()) + + @gen_test + def test_context_manager_timeout(self): + sem = locks.Semaphore() + with (yield sem.acquire(timedelta(seconds=0.01))): + pass + + # Semaphore was released and can be acquired again. + self.assertTrue(asyncio.ensure_future(sem.acquire()).done()) + + @gen_test + def test_context_manager_timeout_error(self): + sem = locks.Semaphore(value=0) + with self.assertRaises(gen.TimeoutError): + with (yield sem.acquire(timedelta(seconds=0.01))): + pass + + # Counter is still 0. + self.assertFalse(asyncio.ensure_future(sem.acquire()).done()) + + @gen_test + def test_context_manager_contended(self): + sem = locks.Semaphore() + history = [] + + @gen.coroutine + def f(index): + with (yield sem.acquire()): + history.append("acquired %d" % index) + yield gen.sleep(0.01) + history.append("release %d" % index) + + yield [f(i) for i in range(2)] + + expected_history = [] + for i in range(2): + expected_history.extend(["acquired %d" % i, "release %d" % i]) + + self.assertEqual(expected_history, history) + + @gen_test + def test_yield_sem(self): + # Ensure we catch a "with (yield sem)", which should be + # "with (yield sem.acquire())". + with self.assertRaises(gen.BadYieldError): + with (yield locks.Semaphore()): + pass + + def test_context_manager_misuse(self): + # Ensure we catch a "with sem", which should be + # "with (yield sem.acquire())". + with self.assertRaises(RuntimeError): + with locks.Semaphore(): + pass + + +class BoundedSemaphoreTest(AsyncTestCase): + def test_release_unacquired(self): + sem = locks.BoundedSemaphore() + self.assertRaises(ValueError, sem.release) + # Value is 0. + sem.acquire() + # Block on acquire(). + future = asyncio.ensure_future(sem.acquire()) + self.assertFalse(future.done()) + sem.release() + self.assertTrue(future.done()) + # Value is 1. + sem.release() + self.assertRaises(ValueError, sem.release) + + +class LockTests(AsyncTestCase): + def test_repr(self): + lock = locks.Lock() + # No errors. + repr(lock) + lock.acquire() + repr(lock) + + def test_acquire_release(self): + lock = locks.Lock() + self.assertTrue(asyncio.ensure_future(lock.acquire()).done()) + future = asyncio.ensure_future(lock.acquire()) + self.assertFalse(future.done()) + lock.release() + self.assertTrue(future.done()) + + @gen_test + def test_acquire_fifo(self): + lock = locks.Lock() + self.assertTrue(asyncio.ensure_future(lock.acquire()).done()) + N = 5 + history = [] + + @gen.coroutine + def f(idx): + with (yield lock.acquire()): + history.append(idx) + + futures = [f(i) for i in range(N)] + self.assertFalse(any(future.done() for future in futures)) + lock.release() + yield futures + self.assertEqual(list(range(N)), history) + + @gen_test + def test_acquire_fifo_async_with(self): + # Repeat the above test using `async with lock:` + # instead of `with (yield lock.acquire()):`. + lock = locks.Lock() + self.assertTrue(asyncio.ensure_future(lock.acquire()).done()) + N = 5 + history = [] + + async def f(idx): + async with lock: + history.append(idx) + + futures = [f(i) for i in range(N)] + lock.release() + yield futures + self.assertEqual(list(range(N)), history) + + @gen_test + def test_acquire_timeout(self): + lock = locks.Lock() + lock.acquire() + with self.assertRaises(gen.TimeoutError): + yield lock.acquire(timeout=timedelta(seconds=0.01)) + + # Still locked. + self.assertFalse(asyncio.ensure_future(lock.acquire()).done()) + + def test_multi_release(self): + lock = locks.Lock() + self.assertRaises(RuntimeError, lock.release) + lock.acquire() + lock.release() + self.assertRaises(RuntimeError, lock.release) + + @gen_test + def test_yield_lock(self): + # Ensure we catch a "with (yield lock)", which should be + # "with (yield lock.acquire())". + with self.assertRaises(gen.BadYieldError): + with (yield locks.Lock()): + pass + + def test_context_manager_misuse(self): + # Ensure we catch a "with lock", which should be + # "with (yield lock.acquire())". + with self.assertRaises(RuntimeError): + with locks.Lock(): + pass + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/lib/python3.8/site-packages/tornado/test/log_test.py b/venv/lib/python3.8/site-packages/tornado/test/log_test.py new file mode 100644 index 0000000..8450e50 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/log_test.py @@ -0,0 +1,245 @@ +# +# Copyright 2012 Facebook +# +# 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. +import contextlib +import glob +import logging +import os +import re +import subprocess +import sys +import tempfile +import unittest +import warnings + +from tornado.escape import utf8 +from tornado.log import LogFormatter, define_logging_options, enable_pretty_logging +from tornado.options import OptionParser +from tornado.util import basestring_type + + +@contextlib.contextmanager +def ignore_bytes_warning(): + with warnings.catch_warnings(): + warnings.simplefilter("ignore", category=BytesWarning) + yield + + +class LogFormatterTest(unittest.TestCase): + # Matches the output of a single logging call (which may be multiple lines + # if a traceback was included, so we use the DOTALL option) + LINE_RE = re.compile( + b"(?s)\x01\\[E [0-9]{6} [0-9]{2}:[0-9]{2}:[0-9]{2} log_test:[0-9]+\\]\x02 (.*)" + ) + + def setUp(self): + self.formatter = LogFormatter(color=False) + # Fake color support. We can't guarantee anything about the $TERM + # variable when the tests are run, so just patch in some values + # for testing. (testing with color off fails to expose some potential + # encoding issues from the control characters) + self.formatter._colors = {logging.ERROR: u"\u0001"} + self.formatter._normal = u"\u0002" + # construct a Logger directly to bypass getLogger's caching + self.logger = logging.Logger("LogFormatterTest") + self.logger.propagate = False + self.tempdir = tempfile.mkdtemp() + self.filename = os.path.join(self.tempdir, "log.out") + self.handler = self.make_handler(self.filename) + self.handler.setFormatter(self.formatter) + self.logger.addHandler(self.handler) + + def tearDown(self): + self.handler.close() + os.unlink(self.filename) + os.rmdir(self.tempdir) + + def make_handler(self, filename): + # Base case: default setup without explicit encoding. + # In python 2, supports arbitrary byte strings and unicode objects + # that contain only ascii. In python 3, supports ascii-only unicode + # strings (but byte strings will be repr'd automatically). + return logging.FileHandler(filename) + + def get_output(self): + with open(self.filename, "rb") as f: + line = f.read().strip() + m = LogFormatterTest.LINE_RE.match(line) + if m: + return m.group(1) + else: + raise Exception("output didn't match regex: %r" % line) + + def test_basic_logging(self): + self.logger.error("foo") + self.assertEqual(self.get_output(), b"foo") + + def test_bytes_logging(self): + with ignore_bytes_warning(): + # This will be "\xe9" on python 2 or "b'\xe9'" on python 3 + self.logger.error(b"\xe9") + self.assertEqual(self.get_output(), utf8(repr(b"\xe9"))) + + def test_utf8_logging(self): + with ignore_bytes_warning(): + self.logger.error(u"\u00e9".encode("utf8")) + if issubclass(bytes, basestring_type): + # on python 2, utf8 byte strings (and by extension ascii byte + # strings) are passed through as-is. + self.assertEqual(self.get_output(), utf8(u"\u00e9")) + else: + # on python 3, byte strings always get repr'd even if + # they're ascii-only, so this degenerates into another + # copy of test_bytes_logging. + self.assertEqual(self.get_output(), utf8(repr(utf8(u"\u00e9")))) + + def test_bytes_exception_logging(self): + try: + raise Exception(b"\xe9") + except Exception: + self.logger.exception("caught exception") + # This will be "Exception: \xe9" on python 2 or + # "Exception: b'\xe9'" on python 3. + output = self.get_output() + self.assertRegexpMatches(output, br"Exception.*\\xe9") + # The traceback contains newlines, which should not have been escaped. + self.assertNotIn(br"\n", output) + + +class UnicodeLogFormatterTest(LogFormatterTest): + def make_handler(self, filename): + # Adding an explicit encoding configuration allows non-ascii unicode + # strings in both python 2 and 3, without changing the behavior + # for byte strings. + return logging.FileHandler(filename, encoding="utf8") + + def test_unicode_logging(self): + self.logger.error(u"\u00e9") + self.assertEqual(self.get_output(), utf8(u"\u00e9")) + + +class EnablePrettyLoggingTest(unittest.TestCase): + def setUp(self): + super().setUp() + self.options = OptionParser() + define_logging_options(self.options) + self.logger = logging.Logger("tornado.test.log_test.EnablePrettyLoggingTest") + self.logger.propagate = False + + def test_log_file(self): + tmpdir = tempfile.mkdtemp() + try: + self.options.log_file_prefix = tmpdir + "/test_log" + enable_pretty_logging(options=self.options, logger=self.logger) + self.assertEqual(1, len(self.logger.handlers)) + self.logger.error("hello") + self.logger.handlers[0].flush() + filenames = glob.glob(tmpdir + "/test_log*") + self.assertEqual(1, len(filenames)) + with open(filenames[0]) as f: + self.assertRegexpMatches(f.read(), r"^\[E [^]]*\] hello$") + finally: + for handler in self.logger.handlers: + handler.flush() + handler.close() + for filename in glob.glob(tmpdir + "/test_log*"): + os.unlink(filename) + os.rmdir(tmpdir) + + def test_log_file_with_timed_rotating(self): + tmpdir = tempfile.mkdtemp() + try: + self.options.log_file_prefix = tmpdir + "/test_log" + self.options.log_rotate_mode = "time" + enable_pretty_logging(options=self.options, logger=self.logger) + self.logger.error("hello") + self.logger.handlers[0].flush() + filenames = glob.glob(tmpdir + "/test_log*") + self.assertEqual(1, len(filenames)) + with open(filenames[0]) as f: + self.assertRegexpMatches(f.read(), r"^\[E [^]]*\] hello$") + finally: + for handler in self.logger.handlers: + handler.flush() + handler.close() + for filename in glob.glob(tmpdir + "/test_log*"): + os.unlink(filename) + os.rmdir(tmpdir) + + def test_wrong_rotate_mode_value(self): + try: + self.options.log_file_prefix = "some_path" + self.options.log_rotate_mode = "wrong_mode" + self.assertRaises( + ValueError, + enable_pretty_logging, + options=self.options, + logger=self.logger, + ) + finally: + for handler in self.logger.handlers: + handler.flush() + handler.close() + + +class LoggingOptionTest(unittest.TestCase): + """Test the ability to enable and disable Tornado's logging hooks.""" + + def logs_present(self, statement, args=None): + # Each test may manipulate and/or parse the options and then logs + # a line at the 'info' level. This level is ignored in the + # logging module by default, but Tornado turns it on by default + # so it is the easiest way to tell whether tornado's logging hooks + # ran. + IMPORT = "from tornado.options import options, parse_command_line" + LOG_INFO = 'import logging; logging.info("hello")' + program = ";".join([IMPORT, statement, LOG_INFO]) + proc = subprocess.Popen( + [sys.executable, "-c", program] + (args or []), + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + ) + stdout, stderr = proc.communicate() + self.assertEqual(proc.returncode, 0, "process failed: %r" % stdout) + return b"hello" in stdout + + def test_default(self): + self.assertFalse(self.logs_present("pass")) + + def test_tornado_default(self): + self.assertTrue(self.logs_present("parse_command_line()")) + + def test_disable_command_line(self): + self.assertFalse(self.logs_present("parse_command_line()", ["--logging=none"])) + + def test_disable_command_line_case_insensitive(self): + self.assertFalse(self.logs_present("parse_command_line()", ["--logging=None"])) + + def test_disable_code_string(self): + self.assertFalse( + self.logs_present('options.logging = "none"; parse_command_line()') + ) + + def test_disable_code_none(self): + self.assertFalse( + self.logs_present("options.logging = None; parse_command_line()") + ) + + def test_disable_override(self): + # command line trumps code defaults + self.assertTrue( + self.logs_present( + "options.logging = None; parse_command_line()", ["--logging=info"] + ) + ) diff --git a/venv/lib/python3.8/site-packages/tornado/test/netutil_test.py b/venv/lib/python3.8/site-packages/tornado/test/netutil_test.py new file mode 100644 index 0000000..f36b7c2 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/netutil_test.py @@ -0,0 +1,233 @@ +import errno +import os +import signal +import socket +from subprocess import Popen +import sys +import time +import unittest + +from tornado.netutil import ( + BlockingResolver, + OverrideResolver, + ThreadedResolver, + is_valid_ip, + bind_sockets, +) +from tornado.testing import AsyncTestCase, gen_test, bind_unused_port +from tornado.test.util import skipIfNoNetwork + +import typing + +if typing.TYPE_CHECKING: + from typing import List # noqa: F401 + +try: + import pycares # type: ignore +except ImportError: + pycares = None +else: + from tornado.platform.caresresolver import CaresResolver + +try: + import twisted # type: ignore + import twisted.names # type: ignore +except ImportError: + twisted = None +else: + from tornado.platform.twisted import TwistedResolver + + +class _ResolverTestMixin(object): + resolver = None # type: typing.Any + + @gen_test + def test_localhost(self: typing.Any): + addrinfo = yield self.resolver.resolve("localhost", 80, socket.AF_UNSPEC) + self.assertIn((socket.AF_INET, ("127.0.0.1", 80)), addrinfo) + + +# It is impossible to quickly and consistently generate an error in name +# resolution, so test this case separately, using mocks as needed. +class _ResolverErrorTestMixin(object): + resolver = None # type: typing.Any + + @gen_test + def test_bad_host(self: typing.Any): + with self.assertRaises(IOError): + yield self.resolver.resolve("an invalid domain", 80, socket.AF_UNSPEC) + + +def _failing_getaddrinfo(*args): + """Dummy implementation of getaddrinfo for use in mocks""" + raise socket.gaierror(errno.EIO, "mock: lookup failed") + + +@skipIfNoNetwork +class BlockingResolverTest(AsyncTestCase, _ResolverTestMixin): + def setUp(self): + super().setUp() + self.resolver = BlockingResolver() + + +# getaddrinfo-based tests need mocking to reliably generate errors; +# some configurations are slow to produce errors and take longer than +# our default timeout. +class BlockingResolverErrorTest(AsyncTestCase, _ResolverErrorTestMixin): + def setUp(self): + super().setUp() + self.resolver = BlockingResolver() + self.real_getaddrinfo = socket.getaddrinfo + socket.getaddrinfo = _failing_getaddrinfo + + def tearDown(self): + socket.getaddrinfo = self.real_getaddrinfo + super().tearDown() + + +class OverrideResolverTest(AsyncTestCase, _ResolverTestMixin): + def setUp(self): + super().setUp() + mapping = { + ("google.com", 80): ("1.2.3.4", 80), + ("google.com", 80, socket.AF_INET): ("1.2.3.4", 80), + ("google.com", 80, socket.AF_INET6): ( + "2a02:6b8:7c:40c:c51e:495f:e23a:3", + 80, + ), + } + self.resolver = OverrideResolver(BlockingResolver(), mapping) + + @gen_test + def test_resolve_multiaddr(self): + result = yield self.resolver.resolve("google.com", 80, socket.AF_INET) + self.assertIn((socket.AF_INET, ("1.2.3.4", 80)), result) + + result = yield self.resolver.resolve("google.com", 80, socket.AF_INET6) + self.assertIn( + (socket.AF_INET6, ("2a02:6b8:7c:40c:c51e:495f:e23a:3", 80, 0, 0)), result + ) + + +@skipIfNoNetwork +class ThreadedResolverTest(AsyncTestCase, _ResolverTestMixin): + def setUp(self): + super().setUp() + self.resolver = ThreadedResolver() + + def tearDown(self): + self.resolver.close() + super().tearDown() + + +class ThreadedResolverErrorTest(AsyncTestCase, _ResolverErrorTestMixin): + def setUp(self): + super().setUp() + self.resolver = BlockingResolver() + self.real_getaddrinfo = socket.getaddrinfo + socket.getaddrinfo = _failing_getaddrinfo + + def tearDown(self): + socket.getaddrinfo = self.real_getaddrinfo + super().tearDown() + + +@skipIfNoNetwork +@unittest.skipIf(sys.platform == "win32", "preexec_fn not available on win32") +class ThreadedResolverImportTest(unittest.TestCase): + def test_import(self): + TIMEOUT = 5 + + # Test for a deadlock when importing a module that runs the + # ThreadedResolver at import-time. See resolve_test.py for + # full explanation. + command = [sys.executable, "-c", "import tornado.test.resolve_test_helper"] + + start = time.time() + popen = Popen(command, preexec_fn=lambda: signal.alarm(TIMEOUT)) + while time.time() - start < TIMEOUT: + return_code = popen.poll() + if return_code is not None: + self.assertEqual(0, return_code) + return # Success. + time.sleep(0.05) + + self.fail("import timed out") + + +# We do not test errors with CaresResolver: +# Some DNS-hijacking ISPs (e.g. Time Warner) return non-empty results +# with an NXDOMAIN status code. Most resolvers treat this as an error; +# C-ares returns the results, making the "bad_host" tests unreliable. +# C-ares will try to resolve even malformed names, such as the +# name with spaces used in this test. +@skipIfNoNetwork +@unittest.skipIf(pycares is None, "pycares module not present") +@unittest.skipIf(sys.platform == "win32", "pycares doesn't return loopback on windows") +@unittest.skipIf(sys.platform == "darwin", "pycares doesn't return 127.0.0.1 on darwin") +class CaresResolverTest(AsyncTestCase, _ResolverTestMixin): + def setUp(self): + super().setUp() + self.resolver = CaresResolver() + + +# TwistedResolver produces consistent errors in our test cases so we +# could test the regular and error cases in the same class. However, +# in the error cases it appears that cleanup of socket objects is +# handled asynchronously and occasionally results in "unclosed socket" +# warnings if not given time to shut down (and there is no way to +# explicitly shut it down). This makes the test flaky, so we do not +# test error cases here. +@skipIfNoNetwork +@unittest.skipIf(twisted is None, "twisted module not present") +@unittest.skipIf( + getattr(twisted, "__version__", "0.0") < "12.1", "old version of twisted" +) +@unittest.skipIf(sys.platform == "win32", "twisted resolver hangs on windows") +class TwistedResolverTest(AsyncTestCase, _ResolverTestMixin): + def setUp(self): + super().setUp() + self.resolver = TwistedResolver() + + +class IsValidIPTest(unittest.TestCase): + def test_is_valid_ip(self): + self.assertTrue(is_valid_ip("127.0.0.1")) + self.assertTrue(is_valid_ip("4.4.4.4")) + self.assertTrue(is_valid_ip("::1")) + self.assertTrue(is_valid_ip("2620:0:1cfe:face:b00c::3")) + self.assertTrue(not is_valid_ip("www.google.com")) + self.assertTrue(not is_valid_ip("localhost")) + self.assertTrue(not is_valid_ip("4.4.4.4<")) + self.assertTrue(not is_valid_ip(" 127.0.0.1")) + self.assertTrue(not is_valid_ip("")) + self.assertTrue(not is_valid_ip(" ")) + self.assertTrue(not is_valid_ip("\n")) + self.assertTrue(not is_valid_ip("\x00")) + + +class TestPortAllocation(unittest.TestCase): + def test_same_port_allocation(self): + if "TRAVIS" in os.environ: + self.skipTest("dual-stack servers often have port conflicts on travis") + sockets = bind_sockets(0, "localhost") + try: + port = sockets[0].getsockname()[1] + self.assertTrue(all(s.getsockname()[1] == port for s in sockets[1:])) + finally: + for sock in sockets: + sock.close() + + @unittest.skipIf( + not hasattr(socket, "SO_REUSEPORT"), "SO_REUSEPORT is not supported" + ) + def test_reuse_port(self): + sockets = [] # type: List[socket.socket] + socket, port = bind_unused_port(reuse_port=True) + try: + sockets = bind_sockets(port, "127.0.0.1", reuse_port=True) + self.assertTrue(all(s.getsockname()[1] == port for s in sockets)) + finally: + socket.close() + for sock in sockets: + sock.close() diff --git a/venv/lib/python3.8/site-packages/tornado/test/options_test.cfg b/venv/lib/python3.8/site-packages/tornado/test/options_test.cfg new file mode 100644 index 0000000..4ead46a --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/options_test.cfg @@ -0,0 +1,7 @@ +port=443 +port=443 +username='李康' + +foo_bar='a' + +my_path = __file__ diff --git a/venv/lib/python3.8/site-packages/tornado/test/options_test.py b/venv/lib/python3.8/site-packages/tornado/test/options_test.py new file mode 100644 index 0000000..6aedbec --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/options_test.py @@ -0,0 +1,328 @@ +import datetime +from io import StringIO +import os +import sys +from unittest import mock +import unittest + +from tornado.options import OptionParser, Error +from tornado.util import basestring_type +from tornado.test.util import subTest + +import typing + +if typing.TYPE_CHECKING: + from typing import List # noqa: F401 + + +class Email(object): + def __init__(self, value): + if isinstance(value, str) and "@" in value: + self._value = value + else: + raise ValueError() + + @property + def value(self): + return self._value + + +class OptionsTest(unittest.TestCase): + def test_parse_command_line(self): + options = OptionParser() + options.define("port", default=80) + options.parse_command_line(["main.py", "--port=443"]) + self.assertEqual(options.port, 443) + + def test_parse_config_file(self): + options = OptionParser() + options.define("port", default=80) + options.define("username", default="foo") + options.define("my_path") + config_path = os.path.join( + os.path.dirname(os.path.abspath(__file__)), "options_test.cfg" + ) + options.parse_config_file(config_path) + self.assertEqual(options.port, 443) + self.assertEqual(options.username, "李康") + self.assertEqual(options.my_path, config_path) + + def test_parse_callbacks(self): + options = OptionParser() + self.called = False + + def callback(): + self.called = True + + options.add_parse_callback(callback) + + # non-final parse doesn't run callbacks + options.parse_command_line(["main.py"], final=False) + self.assertFalse(self.called) + + # final parse does + options.parse_command_line(["main.py"]) + self.assertTrue(self.called) + + # callbacks can be run more than once on the same options + # object if there are multiple final parses + self.called = False + options.parse_command_line(["main.py"]) + self.assertTrue(self.called) + + def test_help(self): + options = OptionParser() + try: + orig_stderr = sys.stderr + sys.stderr = StringIO() + with self.assertRaises(SystemExit): + options.parse_command_line(["main.py", "--help"]) + usage = sys.stderr.getvalue() + finally: + sys.stderr = orig_stderr + self.assertIn("Usage:", usage) + + def test_subcommand(self): + base_options = OptionParser() + base_options.define("verbose", default=False) + sub_options = OptionParser() + sub_options.define("foo", type=str) + rest = base_options.parse_command_line( + ["main.py", "--verbose", "subcommand", "--foo=bar"] + ) + self.assertEqual(rest, ["subcommand", "--foo=bar"]) + self.assertTrue(base_options.verbose) + rest2 = sub_options.parse_command_line(rest) + self.assertEqual(rest2, []) + self.assertEqual(sub_options.foo, "bar") + + # the two option sets are distinct + try: + orig_stderr = sys.stderr + sys.stderr = StringIO() + with self.assertRaises(Error): + sub_options.parse_command_line(["subcommand", "--verbose"]) + finally: + sys.stderr = orig_stderr + + def test_setattr(self): + options = OptionParser() + options.define("foo", default=1, type=int) + options.foo = 2 + self.assertEqual(options.foo, 2) + + def test_setattr_type_check(self): + # setattr requires that options be the right type and doesn't + # parse from string formats. + options = OptionParser() + options.define("foo", default=1, type=int) + with self.assertRaises(Error): + options.foo = "2" + + def test_setattr_with_callback(self): + values = [] # type: List[int] + options = OptionParser() + options.define("foo", default=1, type=int, callback=values.append) + options.foo = 2 + self.assertEqual(values, [2]) + + def _sample_options(self): + options = OptionParser() + options.define("a", default=1) + options.define("b", default=2) + return options + + def test_iter(self): + options = self._sample_options() + # OptionParsers always define 'help'. + self.assertEqual(set(["a", "b", "help"]), set(iter(options))) + + def test_getitem(self): + options = self._sample_options() + self.assertEqual(1, options["a"]) + + def test_setitem(self): + options = OptionParser() + options.define("foo", default=1, type=int) + options["foo"] = 2 + self.assertEqual(options["foo"], 2) + + def test_items(self): + options = self._sample_options() + # OptionParsers always define 'help'. + expected = [("a", 1), ("b", 2), ("help", options.help)] + actual = sorted(options.items()) + self.assertEqual(expected, actual) + + def test_as_dict(self): + options = self._sample_options() + expected = {"a": 1, "b": 2, "help": options.help} + self.assertEqual(expected, options.as_dict()) + + def test_group_dict(self): + options = OptionParser() + options.define("a", default=1) + options.define("b", group="b_group", default=2) + + frame = sys._getframe(0) + this_file = frame.f_code.co_filename + self.assertEqual(set(["b_group", "", this_file]), options.groups()) + + b_group_dict = options.group_dict("b_group") + self.assertEqual({"b": 2}, b_group_dict) + + self.assertEqual({}, options.group_dict("nonexistent")) + + def test_mock_patch(self): + # ensure that our setattr hooks don't interfere with mock.patch + options = OptionParser() + options.define("foo", default=1) + options.parse_command_line(["main.py", "--foo=2"]) + self.assertEqual(options.foo, 2) + + with mock.patch.object(options.mockable(), "foo", 3): + self.assertEqual(options.foo, 3) + self.assertEqual(options.foo, 2) + + # Try nested patches mixed with explicit sets + with mock.patch.object(options.mockable(), "foo", 4): + self.assertEqual(options.foo, 4) + options.foo = 5 + self.assertEqual(options.foo, 5) + with mock.patch.object(options.mockable(), "foo", 6): + self.assertEqual(options.foo, 6) + self.assertEqual(options.foo, 5) + self.assertEqual(options.foo, 2) + + def _define_options(self): + options = OptionParser() + options.define("str", type=str) + options.define("basestring", type=basestring_type) + options.define("int", type=int) + options.define("float", type=float) + options.define("datetime", type=datetime.datetime) + options.define("timedelta", type=datetime.timedelta) + options.define("email", type=Email) + options.define("list-of-int", type=int, multiple=True) + return options + + def _check_options_values(self, options): + self.assertEqual(options.str, "asdf") + self.assertEqual(options.basestring, "qwer") + self.assertEqual(options.int, 42) + self.assertEqual(options.float, 1.5) + self.assertEqual(options.datetime, datetime.datetime(2013, 4, 28, 5, 16)) + self.assertEqual(options.timedelta, datetime.timedelta(seconds=45)) + self.assertEqual(options.email.value, "tornado@web.com") + self.assertTrue(isinstance(options.email, Email)) + self.assertEqual(options.list_of_int, [1, 2, 3]) + + def test_types(self): + options = self._define_options() + options.parse_command_line( + [ + "main.py", + "--str=asdf", + "--basestring=qwer", + "--int=42", + "--float=1.5", + "--datetime=2013-04-28 05:16", + "--timedelta=45s", + "--email=tornado@web.com", + "--list-of-int=1,2,3", + ] + ) + self._check_options_values(options) + + def test_types_with_conf_file(self): + for config_file_name in ( + "options_test_types.cfg", + "options_test_types_str.cfg", + ): + options = self._define_options() + options.parse_config_file( + os.path.join(os.path.dirname(__file__), config_file_name) + ) + self._check_options_values(options) + + def test_multiple_string(self): + options = OptionParser() + options.define("foo", type=str, multiple=True) + options.parse_command_line(["main.py", "--foo=a,b,c"]) + self.assertEqual(options.foo, ["a", "b", "c"]) + + def test_multiple_int(self): + options = OptionParser() + options.define("foo", type=int, multiple=True) + options.parse_command_line(["main.py", "--foo=1,3,5:7"]) + self.assertEqual(options.foo, [1, 3, 5, 6, 7]) + + def test_error_redefine(self): + options = OptionParser() + options.define("foo") + with self.assertRaises(Error) as cm: + options.define("foo") + self.assertRegexpMatches(str(cm.exception), "Option.*foo.*already defined") + + def test_error_redefine_underscore(self): + # Ensure that the dash/underscore normalization doesn't + # interfere with the redefinition error. + tests = [ + ("foo-bar", "foo-bar"), + ("foo_bar", "foo_bar"), + ("foo-bar", "foo_bar"), + ("foo_bar", "foo-bar"), + ] + for a, b in tests: + with subTest(self, a=a, b=b): + options = OptionParser() + options.define(a) + with self.assertRaises(Error) as cm: + options.define(b) + self.assertRegexpMatches( + str(cm.exception), "Option.*foo.bar.*already defined" + ) + + def test_dash_underscore_cli(self): + # Dashes and underscores should be interchangeable. + for defined_name in ["foo-bar", "foo_bar"]: + for flag in ["--foo-bar=a", "--foo_bar=a"]: + options = OptionParser() + options.define(defined_name) + options.parse_command_line(["main.py", flag]) + # Attr-style access always uses underscores. + self.assertEqual(options.foo_bar, "a") + # Dict-style access allows both. + self.assertEqual(options["foo-bar"], "a") + self.assertEqual(options["foo_bar"], "a") + + def test_dash_underscore_file(self): + # No matter how an option was defined, it can be set with underscores + # in a config file. + for defined_name in ["foo-bar", "foo_bar"]: + options = OptionParser() + options.define(defined_name) + options.parse_config_file( + os.path.join(os.path.dirname(__file__), "options_test.cfg") + ) + self.assertEqual(options.foo_bar, "a") + + def test_dash_underscore_introspection(self): + # Original names are preserved in introspection APIs. + options = OptionParser() + options.define("with-dash", group="g") + options.define("with_underscore", group="g") + all_options = ["help", "with-dash", "with_underscore"] + self.assertEqual(sorted(options), all_options) + self.assertEqual(sorted(k for (k, v) in options.items()), all_options) + self.assertEqual(sorted(options.as_dict().keys()), all_options) + + self.assertEqual( + sorted(options.group_dict("g")), ["with-dash", "with_underscore"] + ) + + # --help shows CLI-style names with dashes. + buf = StringIO() + options.print_help(buf) + self.assertIn("--with-dash", buf.getvalue()) + self.assertIn("--with-underscore", buf.getvalue()) diff --git a/venv/lib/python3.8/site-packages/tornado/test/options_test_types.cfg b/venv/lib/python3.8/site-packages/tornado/test/options_test_types.cfg new file mode 100644 index 0000000..e1d53cb --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/options_test_types.cfg @@ -0,0 +1,11 @@ +from datetime import datetime, timedelta +from tornado.test.options_test import Email + +str = 'asdf' +basestring = 'qwer' +int = 42 +float = 1.5 +datetime = datetime(2013, 4, 28, 5, 16) +timedelta = timedelta(0, 45) +email = Email('tornado@web.com') +list_of_int = [1, 2, 3] diff --git a/venv/lib/python3.8/site-packages/tornado/test/options_test_types_str.cfg b/venv/lib/python3.8/site-packages/tornado/test/options_test_types_str.cfg new file mode 100644 index 0000000..25dfbc2 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/options_test_types_str.cfg @@ -0,0 +1,8 @@ +str = 'asdf' +basestring = 'qwer' +int = 42 +float = 1.5 +datetime = '2013-04-28 05:16' +timedelta = '45s' +email = 'tornado@web.com' +list_of_int = '1,2,3' diff --git a/venv/lib/python3.8/site-packages/tornado/test/process_test.py b/venv/lib/python3.8/site-packages/tornado/test/process_test.py new file mode 100644 index 0000000..6ff8efd --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/process_test.py @@ -0,0 +1,274 @@ +import asyncio +import logging +import os +import signal +import subprocess +import sys +import time +import unittest + +from tornado.httpclient import HTTPClient, HTTPError +from tornado.httpserver import HTTPServer +from tornado.ioloop import IOLoop +from tornado.log import gen_log +from tornado.process import fork_processes, task_id, Subprocess +from tornado.simple_httpclient import SimpleAsyncHTTPClient +from tornado.testing import bind_unused_port, ExpectLog, AsyncTestCase, gen_test +from tornado.test.util import skipIfNonUnix +from tornado.web import RequestHandler, Application + + +# Not using AsyncHTTPTestCase because we need control over the IOLoop. +@skipIfNonUnix +class ProcessTest(unittest.TestCase): + def get_app(self): + class ProcessHandler(RequestHandler): + def get(self): + if self.get_argument("exit", None): + # must use os._exit instead of sys.exit so unittest's + # exception handler doesn't catch it + os._exit(int(self.get_argument("exit"))) + if self.get_argument("signal", None): + os.kill(os.getpid(), int(self.get_argument("signal"))) + self.write(str(os.getpid())) + + return Application([("/", ProcessHandler)]) + + def tearDown(self): + if task_id() is not None: + # We're in a child process, and probably got to this point + # via an uncaught exception. If we return now, both + # processes will continue with the rest of the test suite. + # Exit now so the parent process will restart the child + # (since we don't have a clean way to signal failure to + # the parent that won't restart) + logging.error("aborting child process from tearDown") + logging.shutdown() + os._exit(1) + # In the surviving process, clear the alarm we set earlier + signal.alarm(0) + super().tearDown() + + def test_multi_process(self): + # This test doesn't work on twisted because we use the global + # reactor and don't restore it to a sane state after the fork + # (asyncio has the same issue, but we have a special case in + # place for it). + with ExpectLog( + gen_log, "(Starting .* processes|child .* exited|uncaught exception)" + ): + sock, port = bind_unused_port() + + def get_url(path): + return "http://127.0.0.1:%d%s" % (port, path) + + # ensure that none of these processes live too long + signal.alarm(5) # master process + try: + id = fork_processes(3, max_restarts=3) + self.assertTrue(id is not None) + signal.alarm(5) # child processes + except SystemExit as e: + # if we exit cleanly from fork_processes, all the child processes + # finished with status 0 + self.assertEqual(e.code, 0) + self.assertTrue(task_id() is None) + sock.close() + return + try: + if asyncio is not None: + # Reset the global asyncio event loop, which was put into + # a broken state by the fork. + asyncio.set_event_loop(asyncio.new_event_loop()) + if id in (0, 1): + self.assertEqual(id, task_id()) + server = HTTPServer(self.get_app()) + server.add_sockets([sock]) + IOLoop.current().start() + elif id == 2: + self.assertEqual(id, task_id()) + sock.close() + # Always use SimpleAsyncHTTPClient here; the curl + # version appears to get confused sometimes if the + # connection gets closed before it's had a chance to + # switch from writing mode to reading mode. + client = HTTPClient(SimpleAsyncHTTPClient) + + def fetch(url, fail_ok=False): + try: + return client.fetch(get_url(url)) + except HTTPError as e: + if not (fail_ok and e.code == 599): + raise + + # Make two processes exit abnormally + fetch("/?exit=2", fail_ok=True) + fetch("/?exit=3", fail_ok=True) + + # They've been restarted, so a new fetch will work + int(fetch("/").body) + + # Now the same with signals + # Disabled because on the mac a process dying with a signal + # can trigger an "Application exited abnormally; send error + # report to Apple?" prompt. + # fetch("/?signal=%d" % signal.SIGTERM, fail_ok=True) + # fetch("/?signal=%d" % signal.SIGABRT, fail_ok=True) + # int(fetch("/").body) + + # Now kill them normally so they won't be restarted + fetch("/?exit=0", fail_ok=True) + # One process left; watch it's pid change + pid = int(fetch("/").body) + fetch("/?exit=4", fail_ok=True) + pid2 = int(fetch("/").body) + self.assertNotEqual(pid, pid2) + + # Kill the last one so we shut down cleanly + fetch("/?exit=0", fail_ok=True) + + os._exit(0) + except Exception: + logging.error("exception in child process %d", id, exc_info=True) + raise + + +@skipIfNonUnix +class SubprocessTest(AsyncTestCase): + def term_and_wait(self, subproc): + subproc.proc.terminate() + subproc.proc.wait() + + @gen_test + def test_subprocess(self): + if IOLoop.configured_class().__name__.endswith("LayeredTwistedIOLoop"): + # This test fails non-deterministically with LayeredTwistedIOLoop. + # (the read_until('\n') returns '\n' instead of 'hello\n') + # This probably indicates a problem with either TornadoReactor + # or TwistedIOLoop, but I haven't been able to track it down + # and for now this is just causing spurious travis-ci failures. + raise unittest.SkipTest( + "Subprocess tests not compatible with " "LayeredTwistedIOLoop" + ) + subproc = Subprocess( + [sys.executable, "-u", "-i"], + stdin=Subprocess.STREAM, + stdout=Subprocess.STREAM, + stderr=subprocess.STDOUT, + ) + self.addCleanup(lambda: self.term_and_wait(subproc)) + self.addCleanup(subproc.stdout.close) + self.addCleanup(subproc.stdin.close) + yield subproc.stdout.read_until(b">>> ") + subproc.stdin.write(b"print('hello')\n") + data = yield subproc.stdout.read_until(b"\n") + self.assertEqual(data, b"hello\n") + + yield subproc.stdout.read_until(b">>> ") + subproc.stdin.write(b"raise SystemExit\n") + data = yield subproc.stdout.read_until_close() + self.assertEqual(data, b"") + + @gen_test + def test_close_stdin(self): + # Close the parent's stdin handle and see that the child recognizes it. + subproc = Subprocess( + [sys.executable, "-u", "-i"], + stdin=Subprocess.STREAM, + stdout=Subprocess.STREAM, + stderr=subprocess.STDOUT, + ) + self.addCleanup(lambda: self.term_and_wait(subproc)) + yield subproc.stdout.read_until(b">>> ") + subproc.stdin.close() + data = yield subproc.stdout.read_until_close() + self.assertEqual(data, b"\n") + + @gen_test + def test_stderr(self): + # This test is mysteriously flaky on twisted: it succeeds, but logs + # an error of EBADF on closing a file descriptor. + subproc = Subprocess( + [sys.executable, "-u", "-c", r"import sys; sys.stderr.write('hello\n')"], + stderr=Subprocess.STREAM, + ) + self.addCleanup(lambda: self.term_and_wait(subproc)) + data = yield subproc.stderr.read_until(b"\n") + self.assertEqual(data, b"hello\n") + # More mysterious EBADF: This fails if done with self.addCleanup instead of here. + subproc.stderr.close() + + def test_sigchild(self): + Subprocess.initialize() + self.addCleanup(Subprocess.uninitialize) + subproc = Subprocess([sys.executable, "-c", "pass"]) + subproc.set_exit_callback(self.stop) + ret = self.wait() + self.assertEqual(ret, 0) + self.assertEqual(subproc.returncode, ret) + + @gen_test + def test_sigchild_future(self): + Subprocess.initialize() + self.addCleanup(Subprocess.uninitialize) + subproc = Subprocess([sys.executable, "-c", "pass"]) + ret = yield subproc.wait_for_exit() + self.assertEqual(ret, 0) + self.assertEqual(subproc.returncode, ret) + + def test_sigchild_signal(self): + Subprocess.initialize() + self.addCleanup(Subprocess.uninitialize) + subproc = Subprocess( + [sys.executable, "-c", "import time; time.sleep(30)"], + stdout=Subprocess.STREAM, + ) + self.addCleanup(subproc.stdout.close) + subproc.set_exit_callback(self.stop) + + # For unclear reasons, killing a process too soon after + # creating it can result in an exit status corresponding to + # SIGKILL instead of the actual signal involved. This has been + # observed on macOS 10.15 with Python 3.8 installed via brew, + # but not with the system-installed Python 3.7. + time.sleep(0.1) + + os.kill(subproc.pid, signal.SIGTERM) + try: + ret = self.wait() + except AssertionError: + # We failed to get the termination signal. This test is + # occasionally flaky on pypy, so try to get a little more + # information: did the process close its stdout + # (indicating that the problem is in the parent process's + # signal handling) or did the child process somehow fail + # to terminate? + fut = subproc.stdout.read_until_close() + fut.add_done_callback(lambda f: self.stop()) # type: ignore + try: + self.wait() + except AssertionError: + raise AssertionError("subprocess failed to terminate") + else: + raise AssertionError( + "subprocess closed stdout but failed to " "get termination signal" + ) + self.assertEqual(subproc.returncode, ret) + self.assertEqual(ret, -signal.SIGTERM) + + @gen_test + def test_wait_for_exit_raise(self): + Subprocess.initialize() + self.addCleanup(Subprocess.uninitialize) + subproc = Subprocess([sys.executable, "-c", "import sys; sys.exit(1)"]) + with self.assertRaises(subprocess.CalledProcessError) as cm: + yield subproc.wait_for_exit() + self.assertEqual(cm.exception.returncode, 1) + + @gen_test + def test_wait_for_exit_raise_disabled(self): + Subprocess.initialize() + self.addCleanup(Subprocess.uninitialize) + subproc = Subprocess([sys.executable, "-c", "import sys; sys.exit(1)"]) + ret = yield subproc.wait_for_exit(raise_error=False) + self.assertEqual(ret, 1) diff --git a/venv/lib/python3.8/site-packages/tornado/test/queues_test.py b/venv/lib/python3.8/site-packages/tornado/test/queues_test.py new file mode 100644 index 0000000..98a29a8 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/queues_test.py @@ -0,0 +1,431 @@ +# 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. + +import asyncio +from datetime import timedelta +from random import random +import unittest + +from tornado import gen, queues +from tornado.gen import TimeoutError +from tornado.testing import gen_test, AsyncTestCase + + +class QueueBasicTest(AsyncTestCase): + def test_repr_and_str(self): + q = queues.Queue(maxsize=1) # type: queues.Queue[None] + self.assertIn(hex(id(q)), repr(q)) + self.assertNotIn(hex(id(q)), str(q)) + q.get() + + for q_str in repr(q), str(q): + self.assertTrue(q_str.startswith("<Queue")) + self.assertIn("maxsize=1", q_str) + self.assertIn("getters[1]", q_str) + self.assertNotIn("putters", q_str) + self.assertNotIn("tasks", q_str) + + q.put(None) + q.put(None) + # Now the queue is full, this putter blocks. + q.put(None) + + for q_str in repr(q), str(q): + self.assertNotIn("getters", q_str) + self.assertIn("putters[1]", q_str) + self.assertIn("tasks=2", q_str) + + def test_order(self): + q = queues.Queue() # type: queues.Queue[int] + for i in [1, 3, 2]: + q.put_nowait(i) + + items = [q.get_nowait() for _ in range(3)] + self.assertEqual([1, 3, 2], items) + + @gen_test + def test_maxsize(self): + self.assertRaises(TypeError, queues.Queue, maxsize=None) + self.assertRaises(ValueError, queues.Queue, maxsize=-1) + + q = queues.Queue(maxsize=2) # type: queues.Queue[int] + self.assertTrue(q.empty()) + self.assertFalse(q.full()) + self.assertEqual(2, q.maxsize) + self.assertTrue(q.put(0).done()) + self.assertTrue(q.put(1).done()) + self.assertFalse(q.empty()) + self.assertTrue(q.full()) + put2 = q.put(2) + self.assertFalse(put2.done()) + self.assertEqual(0, (yield q.get())) # Make room. + self.assertTrue(put2.done()) + self.assertFalse(q.empty()) + self.assertTrue(q.full()) + + +class QueueGetTest(AsyncTestCase): + @gen_test + def test_blocking_get(self): + q = queues.Queue() # type: queues.Queue[int] + q.put_nowait(0) + self.assertEqual(0, (yield q.get())) + + def test_nonblocking_get(self): + q = queues.Queue() # type: queues.Queue[int] + q.put_nowait(0) + self.assertEqual(0, q.get_nowait()) + + def test_nonblocking_get_exception(self): + q = queues.Queue() # type: queues.Queue[int] + self.assertRaises(queues.QueueEmpty, q.get_nowait) + + @gen_test + def test_get_with_putters(self): + q = queues.Queue(1) # type: queues.Queue[int] + q.put_nowait(0) + put = q.put(1) + self.assertEqual(0, (yield q.get())) + self.assertIsNone((yield put)) + + @gen_test + def test_blocking_get_wait(self): + q = queues.Queue() # type: queues.Queue[int] + q.put(0) + self.io_loop.call_later(0.01, q.put_nowait, 1) + self.io_loop.call_later(0.02, q.put_nowait, 2) + self.assertEqual(0, (yield q.get(timeout=timedelta(seconds=1)))) + self.assertEqual(1, (yield q.get(timeout=timedelta(seconds=1)))) + + @gen_test + def test_get_timeout(self): + q = queues.Queue() # type: queues.Queue[int] + get_timeout = q.get(timeout=timedelta(seconds=0.01)) + get = q.get() + with self.assertRaises(TimeoutError): + yield get_timeout + + q.put_nowait(0) + self.assertEqual(0, (yield get)) + + @gen_test + def test_get_timeout_preempted(self): + q = queues.Queue() # type: queues.Queue[int] + get = q.get(timeout=timedelta(seconds=0.01)) + q.put(0) + yield gen.sleep(0.02) + self.assertEqual(0, (yield get)) + + @gen_test + def test_get_clears_timed_out_putters(self): + q = queues.Queue(1) # type: queues.Queue[int] + # First putter succeeds, remainder block. + putters = [q.put(i, timedelta(seconds=0.01)) for i in range(10)] + put = q.put(10) + self.assertEqual(10, len(q._putters)) + yield gen.sleep(0.02) + self.assertEqual(10, len(q._putters)) + self.assertFalse(put.done()) # Final waiter is still active. + q.put(11) + self.assertEqual(0, (yield q.get())) # get() clears the waiters. + self.assertEqual(1, len(q._putters)) + for putter in putters[1:]: + self.assertRaises(TimeoutError, putter.result) + + @gen_test + def test_get_clears_timed_out_getters(self): + q = queues.Queue() # type: queues.Queue[int] + getters = [ + asyncio.ensure_future(q.get(timedelta(seconds=0.01))) for _ in range(10) + ] + get = asyncio.ensure_future(q.get()) + self.assertEqual(11, len(q._getters)) + yield gen.sleep(0.02) + self.assertEqual(11, len(q._getters)) + self.assertFalse(get.done()) # Final waiter is still active. + q.get() # get() clears the waiters. + self.assertEqual(2, len(q._getters)) + for getter in getters: + self.assertRaises(TimeoutError, getter.result) + + @gen_test + def test_async_for(self): + q = queues.Queue() # type: queues.Queue[int] + for i in range(5): + q.put(i) + + async def f(): + results = [] + async for i in q: + results.append(i) + if i == 4: + return results + + results = yield f() + self.assertEqual(results, list(range(5))) + + +class QueuePutTest(AsyncTestCase): + @gen_test + def test_blocking_put(self): + q = queues.Queue() # type: queues.Queue[int] + q.put(0) + self.assertEqual(0, q.get_nowait()) + + def test_nonblocking_put_exception(self): + q = queues.Queue(1) # type: queues.Queue[int] + q.put(0) + self.assertRaises(queues.QueueFull, q.put_nowait, 1) + + @gen_test + def test_put_with_getters(self): + q = queues.Queue() # type: queues.Queue[int] + get0 = q.get() + get1 = q.get() + yield q.put(0) + self.assertEqual(0, (yield get0)) + yield q.put(1) + self.assertEqual(1, (yield get1)) + + @gen_test + def test_nonblocking_put_with_getters(self): + q = queues.Queue() # type: queues.Queue[int] + get0 = q.get() + get1 = q.get() + q.put_nowait(0) + # put_nowait does *not* immediately unblock getters. + yield gen.moment + self.assertEqual(0, (yield get0)) + q.put_nowait(1) + yield gen.moment + self.assertEqual(1, (yield get1)) + + @gen_test + def test_blocking_put_wait(self): + q = queues.Queue(1) # type: queues.Queue[int] + q.put_nowait(0) + + def get_and_discard(): + q.get() + + self.io_loop.call_later(0.01, get_and_discard) + self.io_loop.call_later(0.02, get_and_discard) + futures = [q.put(0), q.put(1)] + self.assertFalse(any(f.done() for f in futures)) + yield futures + + @gen_test + def test_put_timeout(self): + q = queues.Queue(1) # type: queues.Queue[int] + q.put_nowait(0) # Now it's full. + put_timeout = q.put(1, timeout=timedelta(seconds=0.01)) + put = q.put(2) + with self.assertRaises(TimeoutError): + yield put_timeout + + self.assertEqual(0, q.get_nowait()) + # 1 was never put in the queue. + self.assertEqual(2, (yield q.get())) + + # Final get() unblocked this putter. + yield put + + @gen_test + def test_put_timeout_preempted(self): + q = queues.Queue(1) # type: queues.Queue[int] + q.put_nowait(0) + put = q.put(1, timeout=timedelta(seconds=0.01)) + q.get() + yield gen.sleep(0.02) + yield put # No TimeoutError. + + @gen_test + def test_put_clears_timed_out_putters(self): + q = queues.Queue(1) # type: queues.Queue[int] + # First putter succeeds, remainder block. + putters = [q.put(i, timedelta(seconds=0.01)) for i in range(10)] + put = q.put(10) + self.assertEqual(10, len(q._putters)) + yield gen.sleep(0.02) + self.assertEqual(10, len(q._putters)) + self.assertFalse(put.done()) # Final waiter is still active. + q.put(11) # put() clears the waiters. + self.assertEqual(2, len(q._putters)) + for putter in putters[1:]: + self.assertRaises(TimeoutError, putter.result) + + @gen_test + def test_put_clears_timed_out_getters(self): + q = queues.Queue() # type: queues.Queue[int] + getters = [ + asyncio.ensure_future(q.get(timedelta(seconds=0.01))) for _ in range(10) + ] + get = asyncio.ensure_future(q.get()) + q.get() + self.assertEqual(12, len(q._getters)) + yield gen.sleep(0.02) + self.assertEqual(12, len(q._getters)) + self.assertFalse(get.done()) # Final waiters still active. + q.put(0) # put() clears the waiters. + self.assertEqual(1, len(q._getters)) + self.assertEqual(0, (yield get)) + for getter in getters: + self.assertRaises(TimeoutError, getter.result) + + @gen_test + def test_float_maxsize(self): + # If a float is passed for maxsize, a reasonable limit should + # be enforced, instead of being treated as unlimited. + # It happens to be rounded up. + # http://bugs.python.org/issue21723 + q = queues.Queue(maxsize=1.3) # type: ignore + self.assertTrue(q.empty()) + self.assertFalse(q.full()) + q.put_nowait(0) + q.put_nowait(1) + self.assertFalse(q.empty()) + self.assertTrue(q.full()) + self.assertRaises(queues.QueueFull, q.put_nowait, 2) + self.assertEqual(0, q.get_nowait()) + self.assertFalse(q.empty()) + self.assertFalse(q.full()) + + yield q.put(2) + put = q.put(3) + self.assertFalse(put.done()) + self.assertEqual(1, (yield q.get())) + yield put + self.assertTrue(q.full()) + + +class QueueJoinTest(AsyncTestCase): + queue_class = queues.Queue + + def test_task_done_underflow(self): + q = self.queue_class() # type: queues.Queue + self.assertRaises(ValueError, q.task_done) + + @gen_test + def test_task_done(self): + q = self.queue_class() # type: queues.Queue + for i in range(100): + q.put_nowait(i) + + self.accumulator = 0 + + @gen.coroutine + def worker(): + while True: + item = yield q.get() + self.accumulator += item + q.task_done() + yield gen.sleep(random() * 0.01) + + # Two coroutines share work. + worker() + worker() + yield q.join() + self.assertEqual(sum(range(100)), self.accumulator) + + @gen_test + def test_task_done_delay(self): + # Verify it is task_done(), not get(), that unblocks join(). + q = self.queue_class() # type: queues.Queue + q.put_nowait(0) + join = asyncio.ensure_future(q.join()) + self.assertFalse(join.done()) + yield q.get() + self.assertFalse(join.done()) + yield gen.moment + self.assertFalse(join.done()) + q.task_done() + self.assertTrue(join.done()) + + @gen_test + def test_join_empty_queue(self): + q = self.queue_class() # type: queues.Queue + yield q.join() + yield q.join() + + @gen_test + def test_join_timeout(self): + q = self.queue_class() # type: queues.Queue + q.put(0) + with self.assertRaises(TimeoutError): + yield q.join(timeout=timedelta(seconds=0.01)) + + +class PriorityQueueJoinTest(QueueJoinTest): + queue_class = queues.PriorityQueue + + @gen_test + def test_order(self): + q = self.queue_class(maxsize=2) + q.put_nowait((1, "a")) + q.put_nowait((0, "b")) + self.assertTrue(q.full()) + q.put((3, "c")) + q.put((2, "d")) + self.assertEqual((0, "b"), q.get_nowait()) + self.assertEqual((1, "a"), (yield q.get())) + self.assertEqual((2, "d"), q.get_nowait()) + self.assertEqual((3, "c"), (yield q.get())) + self.assertTrue(q.empty()) + + +class LifoQueueJoinTest(QueueJoinTest): + queue_class = queues.LifoQueue + + @gen_test + def test_order(self): + q = self.queue_class(maxsize=2) + q.put_nowait(1) + q.put_nowait(0) + self.assertTrue(q.full()) + q.put(3) + q.put(2) + self.assertEqual(3, q.get_nowait()) + self.assertEqual(2, (yield q.get())) + self.assertEqual(0, q.get_nowait()) + self.assertEqual(1, (yield q.get())) + self.assertTrue(q.empty()) + + +class ProducerConsumerTest(AsyncTestCase): + @gen_test + def test_producer_consumer(self): + q = queues.Queue(maxsize=3) # type: queues.Queue[int] + history = [] + + # We don't yield between get() and task_done(), so get() must wait for + # the next tick. Otherwise we'd immediately call task_done and unblock + # join() before q.put() resumes, and we'd only process the first four + # items. + @gen.coroutine + def consumer(): + while True: + history.append((yield q.get())) + q.task_done() + + @gen.coroutine + def producer(): + for item in range(10): + yield q.put(item) + + consumer() + yield producer() + yield q.join() + self.assertEqual(list(range(10)), history) + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/lib/python3.8/site-packages/tornado/test/resolve_test_helper.py b/venv/lib/python3.8/site-packages/tornado/test/resolve_test_helper.py new file mode 100644 index 0000000..491737f --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/resolve_test_helper.py @@ -0,0 +1,10 @@ +from tornado.ioloop import IOLoop +from tornado.netutil import ThreadedResolver + +# When this module is imported, it runs getaddrinfo on a thread. Since +# the hostname is unicode, getaddrinfo attempts to import encodings.idna +# but blocks on the import lock. Verify that ThreadedResolver avoids +# this deadlock. + +resolver = ThreadedResolver() +IOLoop.current().run_sync(lambda: resolver.resolve(u"localhost", 80)) diff --git a/venv/lib/python3.8/site-packages/tornado/test/routing_test.py b/venv/lib/python3.8/site-packages/tornado/test/routing_test.py new file mode 100644 index 0000000..6e02697 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/routing_test.py @@ -0,0 +1,276 @@ +# 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. + +from tornado.httputil import ( + HTTPHeaders, + HTTPMessageDelegate, + HTTPServerConnectionDelegate, + ResponseStartLine, +) +from tornado.routing import ( + HostMatches, + PathMatches, + ReversibleRouter, + Router, + Rule, + RuleRouter, +) +from tornado.testing import AsyncHTTPTestCase +from tornado.web import Application, HTTPError, RequestHandler +from tornado.wsgi import WSGIContainer + +import typing # noqa: F401 + + +class BasicRouter(Router): + def find_handler(self, request, **kwargs): + class MessageDelegate(HTTPMessageDelegate): + def __init__(self, connection): + self.connection = connection + + def finish(self): + self.connection.write_headers( + ResponseStartLine("HTTP/1.1", 200, "OK"), + HTTPHeaders({"Content-Length": "2"}), + b"OK", + ) + self.connection.finish() + + return MessageDelegate(request.connection) + + +class BasicRouterTestCase(AsyncHTTPTestCase): + def get_app(self): + return BasicRouter() + + def test_basic_router(self): + response = self.fetch("/any_request") + self.assertEqual(response.body, b"OK") + + +resources = {} # type: typing.Dict[str, bytes] + + +class GetResource(RequestHandler): + def get(self, path): + if path not in resources: + raise HTTPError(404) + + self.finish(resources[path]) + + +class PostResource(RequestHandler): + def post(self, path): + resources[path] = self.request.body + + +class HTTPMethodRouter(Router): + def __init__(self, app): + self.app = app + + def find_handler(self, request, **kwargs): + handler = GetResource if request.method == "GET" else PostResource + return self.app.get_handler_delegate(request, handler, path_args=[request.path]) + + +class HTTPMethodRouterTestCase(AsyncHTTPTestCase): + def get_app(self): + return HTTPMethodRouter(Application()) + + def test_http_method_router(self): + response = self.fetch("/post_resource", method="POST", body="data") + self.assertEqual(response.code, 200) + + response = self.fetch("/get_resource") + self.assertEqual(response.code, 404) + + response = self.fetch("/post_resource") + self.assertEqual(response.code, 200) + self.assertEqual(response.body, b"data") + + +def _get_named_handler(handler_name): + class Handler(RequestHandler): + def get(self, *args, **kwargs): + if self.application.settings.get("app_name") is not None: + self.write(self.application.settings["app_name"] + ": ") + + self.finish(handler_name + ": " + self.reverse_url(handler_name)) + + return Handler + + +FirstHandler = _get_named_handler("first_handler") +SecondHandler = _get_named_handler("second_handler") + + +class CustomRouter(ReversibleRouter): + def __init__(self): + super().__init__() + self.routes = {} # type: typing.Dict[str, typing.Any] + + def add_routes(self, routes): + self.routes.update(routes) + + def find_handler(self, request, **kwargs): + if request.path in self.routes: + app, handler = self.routes[request.path] + return app.get_handler_delegate(request, handler) + + def reverse_url(self, name, *args): + handler_path = "/" + name + return handler_path if handler_path in self.routes else None + + +class CustomRouterTestCase(AsyncHTTPTestCase): + def get_app(self): + router = CustomRouter() + + class CustomApplication(Application): + def reverse_url(self, name, *args): + return router.reverse_url(name, *args) + + app1 = CustomApplication(app_name="app1") + app2 = CustomApplication(app_name="app2") + + router.add_routes( + { + "/first_handler": (app1, FirstHandler), + "/second_handler": (app2, SecondHandler), + "/first_handler_second_app": (app2, FirstHandler), + } + ) + + return router + + def test_custom_router(self): + response = self.fetch("/first_handler") + self.assertEqual(response.body, b"app1: first_handler: /first_handler") + response = self.fetch("/second_handler") + self.assertEqual(response.body, b"app2: second_handler: /second_handler") + response = self.fetch("/first_handler_second_app") + self.assertEqual(response.body, b"app2: first_handler: /first_handler") + + +class ConnectionDelegate(HTTPServerConnectionDelegate): + def start_request(self, server_conn, request_conn): + class MessageDelegate(HTTPMessageDelegate): + def __init__(self, connection): + self.connection = connection + + def finish(self): + response_body = b"OK" + self.connection.write_headers( + ResponseStartLine("HTTP/1.1", 200, "OK"), + HTTPHeaders({"Content-Length": str(len(response_body))}), + ) + self.connection.write(response_body) + self.connection.finish() + + return MessageDelegate(request_conn) + + +class RuleRouterTest(AsyncHTTPTestCase): + def get_app(self): + app = Application() + + def request_callable(request): + request.connection.write_headers( + ResponseStartLine("HTTP/1.1", 200, "OK"), + HTTPHeaders({"Content-Length": "2"}), + ) + request.connection.write(b"OK") + request.connection.finish() + + router = CustomRouter() + router.add_routes( + {"/nested_handler": (app, _get_named_handler("nested_handler"))} + ) + + app.add_handlers( + ".*", + [ + ( + HostMatches("www.example.com"), + [ + ( + PathMatches("/first_handler"), + "tornado.test.routing_test.SecondHandler", + {}, + "second_handler", + ) + ], + ), + Rule(PathMatches("/.*handler"), router), + Rule(PathMatches("/first_handler"), FirstHandler, name="first_handler"), + Rule(PathMatches("/request_callable"), request_callable), + ("/connection_delegate", ConnectionDelegate()), + ], + ) + + return app + + def test_rule_based_router(self): + response = self.fetch("/first_handler") + self.assertEqual(response.body, b"first_handler: /first_handler") + + response = self.fetch("/first_handler", headers={"Host": "www.example.com"}) + self.assertEqual(response.body, b"second_handler: /first_handler") + + response = self.fetch("/nested_handler") + self.assertEqual(response.body, b"nested_handler: /nested_handler") + + response = self.fetch("/nested_not_found_handler") + self.assertEqual(response.code, 404) + + response = self.fetch("/connection_delegate") + self.assertEqual(response.body, b"OK") + + response = self.fetch("/request_callable") + self.assertEqual(response.body, b"OK") + + response = self.fetch("/404") + self.assertEqual(response.code, 404) + + +class WSGIContainerTestCase(AsyncHTTPTestCase): + def get_app(self): + wsgi_app = WSGIContainer(self.wsgi_app) + + class Handler(RequestHandler): + def get(self, *args, **kwargs): + self.finish(self.reverse_url("tornado")) + + return RuleRouter( + [ + ( + PathMatches("/tornado.*"), + Application([(r"/tornado/test", Handler, {}, "tornado")]), + ), + (PathMatches("/wsgi"), wsgi_app), + ] + ) + + def wsgi_app(self, environ, start_response): + start_response("200 OK", []) + return [b"WSGI"] + + def test_wsgi_container(self): + response = self.fetch("/tornado/test") + self.assertEqual(response.body, b"/tornado/test") + + response = self.fetch("/wsgi") + self.assertEqual(response.body, b"WSGI") + + def test_delegate_not_found(self): + response = self.fetch("/404") + self.assertEqual(response.code, 404) diff --git a/venv/lib/python3.8/site-packages/tornado/test/runtests.py b/venv/lib/python3.8/site-packages/tornado/test/runtests.py new file mode 100644 index 0000000..6075b1e --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/runtests.py @@ -0,0 +1,241 @@ +from functools import reduce +import gc +import io +import locale # system locale module, not tornado.locale +import logging +import operator +import textwrap +import sys +import unittest +import warnings + +from tornado.httpclient import AsyncHTTPClient +from tornado.httpserver import HTTPServer +from tornado.netutil import Resolver +from tornado.options import define, add_parse_callback, options + + +TEST_MODULES = [ + "tornado.httputil.doctests", + "tornado.iostream.doctests", + "tornado.util.doctests", + "tornado.test.asyncio_test", + "tornado.test.auth_test", + "tornado.test.autoreload_test", + "tornado.test.concurrent_test", + "tornado.test.curl_httpclient_test", + "tornado.test.escape_test", + "tornado.test.gen_test", + "tornado.test.http1connection_test", + "tornado.test.httpclient_test", + "tornado.test.httpserver_test", + "tornado.test.httputil_test", + "tornado.test.import_test", + "tornado.test.ioloop_test", + "tornado.test.iostream_test", + "tornado.test.locale_test", + "tornado.test.locks_test", + "tornado.test.netutil_test", + "tornado.test.log_test", + "tornado.test.options_test", + "tornado.test.process_test", + "tornado.test.queues_test", + "tornado.test.routing_test", + "tornado.test.simple_httpclient_test", + "tornado.test.tcpclient_test", + "tornado.test.tcpserver_test", + "tornado.test.template_test", + "tornado.test.testing_test", + "tornado.test.twisted_test", + "tornado.test.util_test", + "tornado.test.web_test", + "tornado.test.websocket_test", + "tornado.test.wsgi_test", +] + + +def all(): + return unittest.defaultTestLoader.loadTestsFromNames(TEST_MODULES) + + +def test_runner_factory(stderr): + class TornadoTextTestRunner(unittest.TextTestRunner): + def __init__(self, *args, **kwargs): + kwargs["stream"] = stderr + super().__init__(*args, **kwargs) + + def run(self, test): + result = super().run(test) + if result.skipped: + skip_reasons = set(reason for (test, reason) in result.skipped) + self.stream.write( # type: ignore + textwrap.fill( + "Some tests were skipped because: %s" + % ", ".join(sorted(skip_reasons)) + ) + ) + self.stream.write("\n") # type: ignore + return result + + return TornadoTextTestRunner + + +class LogCounter(logging.Filter): + """Counts the number of WARNING or higher log records.""" + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.info_count = self.warning_count = self.error_count = 0 + + def filter(self, record): + if record.levelno >= logging.ERROR: + self.error_count += 1 + elif record.levelno >= logging.WARNING: + self.warning_count += 1 + elif record.levelno >= logging.INFO: + self.info_count += 1 + return True + + +class CountingStderr(io.IOBase): + def __init__(self, real): + self.real = real + self.byte_count = 0 + + def write(self, data): + self.byte_count += len(data) + return self.real.write(data) + + def flush(self): + return self.real.flush() + + +def main(): + # Be strict about most warnings (This is set in our test running + # scripts to catch import-time warnings, but set it again here to + # be sure). This also turns on warnings that are ignored by + # default, including DeprecationWarnings and python 3.2's + # ResourceWarnings. + warnings.filterwarnings("error") + # setuptools sometimes gives ImportWarnings about things that are on + # sys.path even if they're not being used. + warnings.filterwarnings("ignore", category=ImportWarning) + # Tornado generally shouldn't use anything deprecated, but some of + # our dependencies do (last match wins). + warnings.filterwarnings("ignore", category=DeprecationWarning) + warnings.filterwarnings("error", category=DeprecationWarning, module=r"tornado\..*") + warnings.filterwarnings("ignore", category=PendingDeprecationWarning) + warnings.filterwarnings( + "error", category=PendingDeprecationWarning, module=r"tornado\..*" + ) + # The unittest module is aggressive about deprecating redundant methods, + # leaving some without non-deprecated spellings that work on both + # 2.7 and 3.2 + warnings.filterwarnings( + "ignore", category=DeprecationWarning, message="Please use assert.* instead" + ) + warnings.filterwarnings( + "ignore", + category=PendingDeprecationWarning, + message="Please use assert.* instead", + ) + # Twisted 15.0.0 triggers some warnings on py3 with -bb. + warnings.filterwarnings("ignore", category=BytesWarning, module=r"twisted\..*") + if (3,) < sys.version_info < (3, 6): + # Prior to 3.6, async ResourceWarnings were rather noisy + # and even + # `python3.4 -W error -c 'import asyncio; asyncio.get_event_loop()'` + # would generate a warning. + warnings.filterwarnings( + "ignore", category=ResourceWarning, module=r"asyncio\..*" + ) + # This deprecation warning is introduced in Python 3.8 and is + # triggered by pycurl. Unforunately, because it is raised in the C + # layer it can't be filtered by module and we must match the + # message text instead (Tornado's C module uses PY_SSIZE_T_CLEAN + # so it's not at risk of running into this issue). + warnings.filterwarnings( + "ignore", + category=DeprecationWarning, + message="PY_SSIZE_T_CLEAN will be required", + ) + + logging.getLogger("tornado.access").setLevel(logging.CRITICAL) + + define( + "httpclient", + type=str, + default=None, + callback=lambda s: AsyncHTTPClient.configure( + s, defaults=dict(allow_ipv6=False) + ), + ) + define("httpserver", type=str, default=None, callback=HTTPServer.configure) + define("resolver", type=str, default=None, callback=Resolver.configure) + define( + "debug_gc", + type=str, + multiple=True, + help="A comma-separated list of gc module debug constants, " + "e.g. DEBUG_STATS or DEBUG_COLLECTABLE,DEBUG_OBJECTS", + callback=lambda values: gc.set_debug( + reduce(operator.or_, (getattr(gc, v) for v in values)) + ), + ) + define( + "fail-if-logs", + default=True, + help="If true, fail the tests if any log output is produced (unless captured by ExpectLog)", + ) + + def set_locale(x): + locale.setlocale(locale.LC_ALL, x) + + define("locale", type=str, default=None, callback=set_locale) + + log_counter = LogCounter() + add_parse_callback(lambda: logging.getLogger().handlers[0].addFilter(log_counter)) + + # Certain errors (especially "unclosed resource" errors raised in + # destructors) go directly to stderr instead of logging. Count + # anything written by anything but the test runner as an error. + orig_stderr = sys.stderr + counting_stderr = CountingStderr(orig_stderr) + sys.stderr = counting_stderr # type: ignore + + import tornado.testing + + kwargs = {} + + # HACK: unittest.main will make its own changes to the warning + # configuration, which may conflict with the settings above + # or command-line flags like -bb. Passing warnings=False + # suppresses this behavior, although this looks like an implementation + # detail. http://bugs.python.org/issue15626 + kwargs["warnings"] = False + + kwargs["testRunner"] = test_runner_factory(orig_stderr) + try: + tornado.testing.main(**kwargs) + finally: + # The tests should run clean; consider it a failure if they + # logged anything at info level or above. + if ( + log_counter.info_count > 0 + or log_counter.warning_count > 0 + or log_counter.error_count > 0 + or counting_stderr.byte_count > 0 + ): + logging.error( + "logged %d infos, %d warnings, %d errors, and %d bytes to stderr", + log_counter.info_count, + log_counter.warning_count, + log_counter.error_count, + counting_stderr.byte_count, + ) + if options.fail_if_logs: + sys.exit(1) + + +if __name__ == "__main__": + main() diff --git a/venv/lib/python3.8/site-packages/tornado/test/simple_httpclient_test.py b/venv/lib/python3.8/site-packages/tornado/test/simple_httpclient_test.py new file mode 100644 index 0000000..eadd4ed --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/simple_httpclient_test.py @@ -0,0 +1,834 @@ +import collections +from contextlib import closing +import errno +import logging +import os +import re +import socket +import ssl +import sys +import typing # noqa: F401 + +from tornado.escape import to_unicode, utf8 +from tornado import gen, version +from tornado.httpclient import AsyncHTTPClient +from tornado.httputil import HTTPHeaders, ResponseStartLine +from tornado.ioloop import IOLoop +from tornado.iostream import UnsatisfiableReadError +from tornado.locks import Event +from tornado.log import gen_log +from tornado.netutil import Resolver, bind_sockets +from tornado.simple_httpclient import ( + SimpleAsyncHTTPClient, + HTTPStreamClosedError, + HTTPTimeoutError, +) +from tornado.test.httpclient_test import ( + ChunkHandler, + CountdownHandler, + HelloWorldHandler, + RedirectHandler, + UserAgentHandler, +) +from tornado.test import httpclient_test +from tornado.testing import ( + AsyncHTTPTestCase, + AsyncHTTPSTestCase, + AsyncTestCase, + ExpectLog, + gen_test, +) +from tornado.test.util import skipOnTravis, skipIfNoIPv6, refusing_port +from tornado.web import RequestHandler, Application, url, stream_request_body + + +class SimpleHTTPClientCommonTestCase(httpclient_test.HTTPClientCommonTestCase): + def get_http_client(self): + client = SimpleAsyncHTTPClient(force_instance=True) + self.assertTrue(isinstance(client, SimpleAsyncHTTPClient)) + return client + + +class TriggerHandler(RequestHandler): + def initialize(self, queue, wake_callback): + self.queue = queue + self.wake_callback = wake_callback + + @gen.coroutine + def get(self): + logging.debug("queuing trigger") + event = Event() + self.queue.append(event.set) + if self.get_argument("wake", "true") == "true": + self.wake_callback() + yield event.wait() + + +class ContentLengthHandler(RequestHandler): + def get(self): + self.stream = self.detach() + IOLoop.current().spawn_callback(self.write_response) + + @gen.coroutine + def write_response(self): + yield self.stream.write( + utf8( + "HTTP/1.0 200 OK\r\nContent-Length: %s\r\n\r\nok" + % self.get_argument("value") + ) + ) + self.stream.close() + + +class HeadHandler(RequestHandler): + def head(self): + self.set_header("Content-Length", "7") + + +class OptionsHandler(RequestHandler): + def options(self): + self.set_header("Access-Control-Allow-Origin", "*") + self.write("ok") + + +class NoContentHandler(RequestHandler): + def get(self): + self.set_status(204) + self.finish() + + +class SeeOtherPostHandler(RequestHandler): + def post(self): + redirect_code = int(self.request.body) + assert redirect_code in (302, 303), "unexpected body %r" % self.request.body + self.set_header("Location", "/see_other_get") + self.set_status(redirect_code) + + +class SeeOtherGetHandler(RequestHandler): + def get(self): + if self.request.body: + raise Exception("unexpected body %r" % self.request.body) + self.write("ok") + + +class HostEchoHandler(RequestHandler): + def get(self): + self.write(self.request.headers["Host"]) + + +class NoContentLengthHandler(RequestHandler): + def get(self): + if self.request.version.startswith("HTTP/1"): + # Emulate the old HTTP/1.0 behavior of returning a body with no + # content-length. Tornado handles content-length at the framework + # level so we have to go around it. + stream = self.detach() + stream.write(b"HTTP/1.0 200 OK\r\n\r\n" b"hello") + stream.close() + else: + self.finish("HTTP/1 required") + + +class EchoPostHandler(RequestHandler): + def post(self): + self.write(self.request.body) + + +@stream_request_body +class RespondInPrepareHandler(RequestHandler): + def prepare(self): + self.set_status(403) + self.finish("forbidden") + + +class SimpleHTTPClientTestMixin(object): + def create_client(self, **kwargs): + raise NotImplementedError() + + def get_app(self: typing.Any): + # callable objects to finish pending /trigger requests + self.triggers = ( + collections.deque() + ) # type: typing.Deque[typing.Callable[[], None]] + return Application( + [ + url( + "/trigger", + TriggerHandler, + dict(queue=self.triggers, wake_callback=self.stop), + ), + url("/chunk", ChunkHandler), + url("/countdown/([0-9]+)", CountdownHandler, name="countdown"), + url("/hello", HelloWorldHandler), + url("/content_length", ContentLengthHandler), + url("/head", HeadHandler), + url("/options", OptionsHandler), + url("/no_content", NoContentHandler), + url("/see_other_post", SeeOtherPostHandler), + url("/see_other_get", SeeOtherGetHandler), + url("/host_echo", HostEchoHandler), + url("/no_content_length", NoContentLengthHandler), + url("/echo_post", EchoPostHandler), + url("/respond_in_prepare", RespondInPrepareHandler), + url("/redirect", RedirectHandler), + url("/user_agent", UserAgentHandler), + ], + gzip=True, + ) + + def test_singleton(self: typing.Any): + # Class "constructor" reuses objects on the same IOLoop + self.assertTrue(SimpleAsyncHTTPClient() is SimpleAsyncHTTPClient()) + # unless force_instance is used + self.assertTrue( + SimpleAsyncHTTPClient() is not SimpleAsyncHTTPClient(force_instance=True) + ) + # different IOLoops use different objects + with closing(IOLoop()) as io_loop2: + + async def make_client(): + await gen.sleep(0) + return SimpleAsyncHTTPClient() + + client1 = self.io_loop.run_sync(make_client) + client2 = io_loop2.run_sync(make_client) + self.assertTrue(client1 is not client2) + + def test_connection_limit(self: typing.Any): + with closing(self.create_client(max_clients=2)) as client: + self.assertEqual(client.max_clients, 2) + seen = [] + # Send 4 requests. Two can be sent immediately, while the others + # will be queued + for i in range(4): + + def cb(fut, i=i): + seen.append(i) + self.stop() + + client.fetch(self.get_url("/trigger")).add_done_callback(cb) + self.wait(condition=lambda: len(self.triggers) == 2) + self.assertEqual(len(client.queue), 2) + + # Finish the first two requests and let the next two through + self.triggers.popleft()() + self.triggers.popleft()() + self.wait(condition=lambda: (len(self.triggers) == 2 and len(seen) == 2)) + self.assertEqual(set(seen), set([0, 1])) + self.assertEqual(len(client.queue), 0) + + # Finish all the pending requests + self.triggers.popleft()() + self.triggers.popleft()() + self.wait(condition=lambda: len(seen) == 4) + self.assertEqual(set(seen), set([0, 1, 2, 3])) + self.assertEqual(len(self.triggers), 0) + + @gen_test + def test_redirect_connection_limit(self: typing.Any): + # following redirects should not consume additional connections + with closing(self.create_client(max_clients=1)) as client: + response = yield client.fetch(self.get_url("/countdown/3"), max_redirects=3) + response.rethrow() + + def test_max_redirects(self: typing.Any): + response = self.fetch("/countdown/5", max_redirects=3) + self.assertEqual(302, response.code) + # We requested 5, followed three redirects for 4, 3, 2, then the last + # unfollowed redirect is to 1. + self.assertTrue(response.request.url.endswith("/countdown/5")) + self.assertTrue(response.effective_url.endswith("/countdown/2")) + self.assertTrue(response.headers["Location"].endswith("/countdown/1")) + + def test_header_reuse(self: typing.Any): + # Apps may reuse a headers object if they are only passing in constant + # headers like user-agent. The header object should not be modified. + headers = HTTPHeaders({"User-Agent": "Foo"}) + self.fetch("/hello", headers=headers) + self.assertEqual(list(headers.get_all()), [("User-Agent", "Foo")]) + + def test_default_user_agent(self: typing.Any): + response = self.fetch("/user_agent", method="GET") + self.assertEqual(200, response.code) + self.assertEqual(response.body.decode(), "Tornado/{}".format(version)) + + def test_see_other_redirect(self: typing.Any): + for code in (302, 303): + response = self.fetch("/see_other_post", method="POST", body="%d" % code) + self.assertEqual(200, response.code) + self.assertTrue(response.request.url.endswith("/see_other_post")) + self.assertTrue(response.effective_url.endswith("/see_other_get")) + # request is the original request, is a POST still + self.assertEqual("POST", response.request.method) + + @skipOnTravis + @gen_test + def test_connect_timeout(self: typing.Any): + timeout = 0.1 + + cleanup_event = Event() + test = self + + class TimeoutResolver(Resolver): + async def resolve(self, *args, **kwargs): + await cleanup_event.wait() + # Return something valid so the test doesn't raise during shutdown. + return [(socket.AF_INET, ("127.0.0.1", test.get_http_port()))] + + with closing(self.create_client(resolver=TimeoutResolver())) as client: + with self.assertRaises(HTTPTimeoutError): + yield client.fetch( + self.get_url("/hello"), + connect_timeout=timeout, + request_timeout=3600, + raise_error=True, + ) + + # Let the hanging coroutine clean up after itself. We need to + # wait more than a single IOLoop iteration for the SSL case, + # which logs errors on unexpected EOF. + cleanup_event.set() + yield gen.sleep(0.2) + + @skipOnTravis + def test_request_timeout(self: typing.Any): + timeout = 0.1 + if os.name == "nt": + timeout = 0.5 + + with self.assertRaises(HTTPTimeoutError): + self.fetch("/trigger?wake=false", request_timeout=timeout, raise_error=True) + # trigger the hanging request to let it clean up after itself + self.triggers.popleft()() + self.io_loop.run_sync(lambda: gen.sleep(0)) + + @skipIfNoIPv6 + def test_ipv6(self: typing.Any): + [sock] = bind_sockets(0, "::1", family=socket.AF_INET6) + port = sock.getsockname()[1] + self.http_server.add_socket(sock) + url = "%s://[::1]:%d/hello" % (self.get_protocol(), port) + + # ipv6 is currently enabled by default but can be disabled + with self.assertRaises(Exception): + self.fetch(url, allow_ipv6=False, raise_error=True) + + response = self.fetch(url) + self.assertEqual(response.body, b"Hello world!") + + def test_multiple_content_length_accepted(self: typing.Any): + response = self.fetch("/content_length?value=2,2") + self.assertEqual(response.body, b"ok") + response = self.fetch("/content_length?value=2,%202,2") + self.assertEqual(response.body, b"ok") + + with ExpectLog( + gen_log, ".*Multiple unequal Content-Lengths", level=logging.INFO + ): + with self.assertRaises(HTTPStreamClosedError): + self.fetch("/content_length?value=2,4", raise_error=True) + with self.assertRaises(HTTPStreamClosedError): + self.fetch("/content_length?value=2,%202,3", raise_error=True) + + def test_head_request(self: typing.Any): + response = self.fetch("/head", method="HEAD") + self.assertEqual(response.code, 200) + self.assertEqual(response.headers["content-length"], "7") + self.assertFalse(response.body) + + def test_options_request(self: typing.Any): + response = self.fetch("/options", method="OPTIONS") + self.assertEqual(response.code, 200) + self.assertEqual(response.headers["content-length"], "2") + self.assertEqual(response.headers["access-control-allow-origin"], "*") + self.assertEqual(response.body, b"ok") + + def test_no_content(self: typing.Any): + response = self.fetch("/no_content") + self.assertEqual(response.code, 204) + # 204 status shouldn't have a content-length + # + # Tests with a content-length header are included below + # in HTTP204NoContentTestCase. + self.assertNotIn("Content-Length", response.headers) + + def test_host_header(self: typing.Any): + host_re = re.compile(b"^127.0.0.1:[0-9]+$") + response = self.fetch("/host_echo") + self.assertTrue(host_re.match(response.body)) + + url = self.get_url("/host_echo").replace("http://", "http://me:secret@") + response = self.fetch(url) + self.assertTrue(host_re.match(response.body), response.body) + + def test_connection_refused(self: typing.Any): + cleanup_func, port = refusing_port() + self.addCleanup(cleanup_func) + with ExpectLog(gen_log, ".*", required=False): + with self.assertRaises(socket.error) as cm: + self.fetch("http://127.0.0.1:%d/" % port, raise_error=True) + + if sys.platform != "cygwin": + # cygwin returns EPERM instead of ECONNREFUSED here + contains_errno = str(errno.ECONNREFUSED) in str(cm.exception) + if not contains_errno and hasattr(errno, "WSAECONNREFUSED"): + contains_errno = str(errno.WSAECONNREFUSED) in str( # type: ignore + cm.exception + ) + self.assertTrue(contains_errno, cm.exception) + # This is usually "Connection refused". + # On windows, strerror is broken and returns "Unknown error". + expected_message = os.strerror(errno.ECONNREFUSED) + self.assertTrue(expected_message in str(cm.exception), cm.exception) + + def test_queue_timeout(self: typing.Any): + with closing(self.create_client(max_clients=1)) as client: + # Wait for the trigger request to block, not complete. + fut1 = client.fetch(self.get_url("/trigger"), request_timeout=10) + self.wait() + with self.assertRaises(HTTPTimeoutError) as cm: + self.io_loop.run_sync( + lambda: client.fetch( + self.get_url("/hello"), connect_timeout=0.1, raise_error=True + ) + ) + + self.assertEqual(str(cm.exception), "Timeout in request queue") + self.triggers.popleft()() + self.io_loop.run_sync(lambda: fut1) + + def test_no_content_length(self: typing.Any): + response = self.fetch("/no_content_length") + if response.body == b"HTTP/1 required": + self.skipTest("requires HTTP/1.x") + else: + self.assertEqual(b"hello", response.body) + + def sync_body_producer(self, write): + write(b"1234") + write(b"5678") + + @gen.coroutine + def async_body_producer(self, write): + yield write(b"1234") + yield gen.moment + yield write(b"5678") + + def test_sync_body_producer_chunked(self: typing.Any): + response = self.fetch( + "/echo_post", method="POST", body_producer=self.sync_body_producer + ) + response.rethrow() + self.assertEqual(response.body, b"12345678") + + def test_sync_body_producer_content_length(self: typing.Any): + response = self.fetch( + "/echo_post", + method="POST", + body_producer=self.sync_body_producer, + headers={"Content-Length": "8"}, + ) + response.rethrow() + self.assertEqual(response.body, b"12345678") + + def test_async_body_producer_chunked(self: typing.Any): + response = self.fetch( + "/echo_post", method="POST", body_producer=self.async_body_producer + ) + response.rethrow() + self.assertEqual(response.body, b"12345678") + + def test_async_body_producer_content_length(self: typing.Any): + response = self.fetch( + "/echo_post", + method="POST", + body_producer=self.async_body_producer, + headers={"Content-Length": "8"}, + ) + response.rethrow() + self.assertEqual(response.body, b"12345678") + + def test_native_body_producer_chunked(self: typing.Any): + async def body_producer(write): + await write(b"1234") + import asyncio + + await asyncio.sleep(0) + await write(b"5678") + + response = self.fetch("/echo_post", method="POST", body_producer=body_producer) + response.rethrow() + self.assertEqual(response.body, b"12345678") + + def test_native_body_producer_content_length(self: typing.Any): + async def body_producer(write): + await write(b"1234") + import asyncio + + await asyncio.sleep(0) + await write(b"5678") + + response = self.fetch( + "/echo_post", + method="POST", + body_producer=body_producer, + headers={"Content-Length": "8"}, + ) + response.rethrow() + self.assertEqual(response.body, b"12345678") + + def test_100_continue(self: typing.Any): + response = self.fetch( + "/echo_post", method="POST", body=b"1234", expect_100_continue=True + ) + self.assertEqual(response.body, b"1234") + + def test_100_continue_early_response(self: typing.Any): + def body_producer(write): + raise Exception("should not be called") + + response = self.fetch( + "/respond_in_prepare", + method="POST", + body_producer=body_producer, + expect_100_continue=True, + ) + self.assertEqual(response.code, 403) + + def test_streaming_follow_redirects(self: typing.Any): + # When following redirects, header and streaming callbacks + # should only be called for the final result. + # TODO(bdarnell): this test belongs in httpclient_test instead of + # simple_httpclient_test, but it fails with the version of libcurl + # available on travis-ci. Move it when that has been upgraded + # or we have a better framework to skip tests based on curl version. + headers = [] # type: typing.List[str] + chunk_bytes = [] # type: typing.List[bytes] + self.fetch( + "/redirect?url=/hello", + header_callback=headers.append, + streaming_callback=chunk_bytes.append, + ) + chunks = list(map(to_unicode, chunk_bytes)) + self.assertEqual(chunks, ["Hello world!"]) + # Make sure we only got one set of headers. + num_start_lines = len([h for h in headers if h.startswith("HTTP/")]) + self.assertEqual(num_start_lines, 1) + + +class SimpleHTTPClientTestCase(SimpleHTTPClientTestMixin, AsyncHTTPTestCase): + def setUp(self): + super().setUp() + self.http_client = self.create_client() + + def create_client(self, **kwargs): + return SimpleAsyncHTTPClient(force_instance=True, **kwargs) + + +class SimpleHTTPSClientTestCase(SimpleHTTPClientTestMixin, AsyncHTTPSTestCase): + def setUp(self): + super().setUp() + self.http_client = self.create_client() + + def create_client(self, **kwargs): + return SimpleAsyncHTTPClient( + force_instance=True, defaults=dict(validate_cert=False), **kwargs + ) + + def test_ssl_options(self): + resp = self.fetch("/hello", ssl_options={}) + self.assertEqual(resp.body, b"Hello world!") + + def test_ssl_context(self): + resp = self.fetch("/hello", ssl_options=ssl.SSLContext(ssl.PROTOCOL_SSLv23)) + self.assertEqual(resp.body, b"Hello world!") + + def test_ssl_options_handshake_fail(self): + with ExpectLog(gen_log, "SSL Error|Uncaught exception", required=False): + with self.assertRaises(ssl.SSLError): + self.fetch( + "/hello", + ssl_options=dict(cert_reqs=ssl.CERT_REQUIRED), + raise_error=True, + ) + + def test_ssl_context_handshake_fail(self): + with ExpectLog(gen_log, "SSL Error|Uncaught exception"): + ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) + ctx.verify_mode = ssl.CERT_REQUIRED + with self.assertRaises(ssl.SSLError): + self.fetch("/hello", ssl_options=ctx, raise_error=True) + + def test_error_logging(self): + # No stack traces are logged for SSL errors (in this case, + # failure to validate the testing self-signed cert). + # The SSLError is exposed through ssl.SSLError. + with ExpectLog(gen_log, ".*") as expect_log: + with self.assertRaises(ssl.SSLError): + self.fetch("/", validate_cert=True, raise_error=True) + self.assertFalse(expect_log.logged_stack) + + +class CreateAsyncHTTPClientTestCase(AsyncTestCase): + def setUp(self): + super().setUp() + self.saved = AsyncHTTPClient._save_configuration() + + def tearDown(self): + AsyncHTTPClient._restore_configuration(self.saved) + super().tearDown() + + def test_max_clients(self): + AsyncHTTPClient.configure(SimpleAsyncHTTPClient) + with closing(AsyncHTTPClient(force_instance=True)) as client: + self.assertEqual(client.max_clients, 10) # type: ignore + with closing(AsyncHTTPClient(max_clients=11, force_instance=True)) as client: + self.assertEqual(client.max_clients, 11) # type: ignore + + # Now configure max_clients statically and try overriding it + # with each way max_clients can be passed + AsyncHTTPClient.configure(SimpleAsyncHTTPClient, max_clients=12) + with closing(AsyncHTTPClient(force_instance=True)) as client: + self.assertEqual(client.max_clients, 12) # type: ignore + with closing(AsyncHTTPClient(max_clients=13, force_instance=True)) as client: + self.assertEqual(client.max_clients, 13) # type: ignore + with closing(AsyncHTTPClient(max_clients=14, force_instance=True)) as client: + self.assertEqual(client.max_clients, 14) # type: ignore + + +class HTTP100ContinueTestCase(AsyncHTTPTestCase): + def respond_100(self, request): + self.http1 = request.version.startswith("HTTP/1.") + if not self.http1: + request.connection.write_headers( + ResponseStartLine("", 200, "OK"), HTTPHeaders() + ) + request.connection.finish() + return + self.request = request + fut = self.request.connection.stream.write(b"HTTP/1.1 100 CONTINUE\r\n\r\n") + fut.add_done_callback(self.respond_200) + + def respond_200(self, fut): + fut.result() + fut = self.request.connection.stream.write( + b"HTTP/1.1 200 OK\r\nContent-Length: 1\r\n\r\nA" + ) + fut.add_done_callback(lambda f: self.request.connection.stream.close()) + + def get_app(self): + # Not a full Application, but works as an HTTPServer callback + return self.respond_100 + + def test_100_continue(self): + res = self.fetch("/") + if not self.http1: + self.skipTest("requires HTTP/1.x") + self.assertEqual(res.body, b"A") + + +class HTTP204NoContentTestCase(AsyncHTTPTestCase): + def respond_204(self, request): + self.http1 = request.version.startswith("HTTP/1.") + if not self.http1: + # Close the request cleanly in HTTP/2; it will be skipped anyway. + request.connection.write_headers( + ResponseStartLine("", 200, "OK"), HTTPHeaders() + ) + request.connection.finish() + return + + # A 204 response never has a body, even if doesn't have a content-length + # (which would otherwise mean read-until-close). We simulate here a + # server that sends no content length and does not close the connection. + # + # Tests of a 204 response with no Content-Length header are included + # in SimpleHTTPClientTestMixin. + stream = request.connection.detach() + stream.write(b"HTTP/1.1 204 No content\r\n") + if request.arguments.get("error", [False])[-1]: + stream.write(b"Content-Length: 5\r\n") + else: + stream.write(b"Content-Length: 0\r\n") + stream.write(b"\r\n") + stream.close() + + def get_app(self): + return self.respond_204 + + def test_204_no_content(self): + resp = self.fetch("/") + if not self.http1: + self.skipTest("requires HTTP/1.x") + self.assertEqual(resp.code, 204) + self.assertEqual(resp.body, b"") + + def test_204_invalid_content_length(self): + # 204 status with non-zero content length is malformed + with ExpectLog( + gen_log, ".*Response with code 204 should not have body", level=logging.INFO + ): + with self.assertRaises(HTTPStreamClosedError): + self.fetch("/?error=1", raise_error=True) + if not self.http1: + self.skipTest("requires HTTP/1.x") + if self.http_client.configured_class != SimpleAsyncHTTPClient: + self.skipTest("curl client accepts invalid headers") + + +class HostnameMappingTestCase(AsyncHTTPTestCase): + def setUp(self): + super().setUp() + self.http_client = SimpleAsyncHTTPClient( + hostname_mapping={ + "www.example.com": "127.0.0.1", + ("foo.example.com", 8000): ("127.0.0.1", self.get_http_port()), + } + ) + + def get_app(self): + return Application([url("/hello", HelloWorldHandler)]) + + def test_hostname_mapping(self): + response = self.fetch("http://www.example.com:%d/hello" % self.get_http_port()) + response.rethrow() + self.assertEqual(response.body, b"Hello world!") + + def test_port_mapping(self): + response = self.fetch("http://foo.example.com:8000/hello") + response.rethrow() + self.assertEqual(response.body, b"Hello world!") + + +class ResolveTimeoutTestCase(AsyncHTTPTestCase): + def setUp(self): + self.cleanup_event = Event() + test = self + + # Dummy Resolver subclass that never finishes. + class BadResolver(Resolver): + @gen.coroutine + def resolve(self, *args, **kwargs): + yield test.cleanup_event.wait() + # Return something valid so the test doesn't raise during cleanup. + return [(socket.AF_INET, ("127.0.0.1", test.get_http_port()))] + + super().setUp() + self.http_client = SimpleAsyncHTTPClient(resolver=BadResolver()) + + def get_app(self): + return Application([url("/hello", HelloWorldHandler)]) + + def test_resolve_timeout(self): + with self.assertRaises(HTTPTimeoutError): + self.fetch("/hello", connect_timeout=0.1, raise_error=True) + + # Let the hanging coroutine clean up after itself + self.cleanup_event.set() + self.io_loop.run_sync(lambda: gen.sleep(0)) + + +class MaxHeaderSizeTest(AsyncHTTPTestCase): + def get_app(self): + class SmallHeaders(RequestHandler): + def get(self): + self.set_header("X-Filler", "a" * 100) + self.write("ok") + + class LargeHeaders(RequestHandler): + def get(self): + self.set_header("X-Filler", "a" * 1000) + self.write("ok") + + return Application([("/small", SmallHeaders), ("/large", LargeHeaders)]) + + def get_http_client(self): + return SimpleAsyncHTTPClient(max_header_size=1024) + + def test_small_headers(self): + response = self.fetch("/small") + response.rethrow() + self.assertEqual(response.body, b"ok") + + def test_large_headers(self): + with ExpectLog(gen_log, "Unsatisfiable read", level=logging.INFO): + with self.assertRaises(UnsatisfiableReadError): + self.fetch("/large", raise_error=True) + + +class MaxBodySizeTest(AsyncHTTPTestCase): + def get_app(self): + class SmallBody(RequestHandler): + def get(self): + self.write("a" * 1024 * 64) + + class LargeBody(RequestHandler): + def get(self): + self.write("a" * 1024 * 100) + + return Application([("/small", SmallBody), ("/large", LargeBody)]) + + def get_http_client(self): + return SimpleAsyncHTTPClient(max_body_size=1024 * 64) + + def test_small_body(self): + response = self.fetch("/small") + response.rethrow() + self.assertEqual(response.body, b"a" * 1024 * 64) + + def test_large_body(self): + with ExpectLog( + gen_log, + "Malformed HTTP message from None: Content-Length too long", + level=logging.INFO, + ): + with self.assertRaises(HTTPStreamClosedError): + self.fetch("/large", raise_error=True) + + +class MaxBufferSizeTest(AsyncHTTPTestCase): + def get_app(self): + class LargeBody(RequestHandler): + def get(self): + self.write("a" * 1024 * 100) + + return Application([("/large", LargeBody)]) + + def get_http_client(self): + # 100KB body with 64KB buffer + return SimpleAsyncHTTPClient( + max_body_size=1024 * 100, max_buffer_size=1024 * 64 + ) + + def test_large_body(self): + response = self.fetch("/large") + response.rethrow() + self.assertEqual(response.body, b"a" * 1024 * 100) + + +class ChunkedWithContentLengthTest(AsyncHTTPTestCase): + def get_app(self): + class ChunkedWithContentLength(RequestHandler): + def get(self): + # Add an invalid Transfer-Encoding to the response + self.set_header("Transfer-Encoding", "chunked") + self.write("Hello world") + + return Application([("/chunkwithcl", ChunkedWithContentLength)]) + + def get_http_client(self): + return SimpleAsyncHTTPClient() + + def test_chunked_with_content_length(self): + # Make sure the invalid headers are detected + with ExpectLog( + gen_log, + ( + "Malformed HTTP message from None: Response " + "with both Transfer-Encoding and Content-Length" + ), + level=logging.INFO, + ): + with self.assertRaises(HTTPStreamClosedError): + self.fetch("/chunkwithcl", raise_error=True) diff --git a/venv/lib/python3.8/site-packages/tornado/test/static/dir/index.html b/venv/lib/python3.8/site-packages/tornado/test/static/dir/index.html new file mode 100644 index 0000000..e1cd9d8 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/static/dir/index.html @@ -0,0 +1 @@ +this is the index diff --git a/venv/lib/python3.8/site-packages/tornado/test/static/robots.txt b/venv/lib/python3.8/site-packages/tornado/test/static/robots.txt new file mode 100644 index 0000000..1f53798 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/static/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: / diff --git a/venv/lib/python3.8/site-packages/tornado/test/static/sample.xml b/venv/lib/python3.8/site-packages/tornado/test/static/sample.xml new file mode 100644 index 0000000..35ea0e2 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/static/sample.xml @@ -0,0 +1,23 @@ +<?xml version="1.0"?> +<data> + <country name="Liechtenstein"> + <rank>1</rank> + <year>2008</year> + <gdppc>141100</gdppc> + <neighbor name="Austria" direction="E"/> + <neighbor name="Switzerland" direction="W"/> + </country> + <country name="Singapore"> + <rank>4</rank> + <year>2011</year> + <gdppc>59900</gdppc> + <neighbor name="Malaysia" direction="N"/> + </country> + <country name="Panama"> + <rank>68</rank> + <year>2011</year> + <gdppc>13600</gdppc> + <neighbor name="Costa Rica" direction="W"/> + <neighbor name="Colombia" direction="E"/> + </country> +</data> diff --git a/venv/lib/python3.8/site-packages/tornado/test/static/sample.xml.bz2 b/venv/lib/python3.8/site-packages/tornado/test/static/sample.xml.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..44dc6633324307e6834e0346eefe7874f1061b3c GIT binary patch literal 285 zcmV+&0pk8bT4*^jL0KkKS>2RqRsaBWUw}jqPyzpEss~trKJVY~FaaAOiqz214H^I% z0000Osgq4W22C{aKmY&%6sD6y5NWB9VFOJD)Ow86kS3)_1!n}|LR|HTBj$IEaP;31 z;m?&8&W5YRNP|^vgqR)$6TyPAz={Y#J+F>qV@u_3X_IFvAew0?Adx~wsED2oK~j1d z-KD{_6*6^@hl~aM+AfjHIv)IM9(sq^pDoGwIjGX>W=iEN5}~e;HI7*(MABi>RJAzL zl(zbRufD<kpF(U-x(3>J^oW2kvO_M=BGjH?&w$~(5cVe7_6)<4!L249=C)Z<+{6ys jF<YlyL~hWNVj8i5^YPfofWTmB&&Ax4P81|JWf~QLEi;1B literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/tornado/test/static/sample.xml.gz b/venv/lib/python3.8/site-packages/tornado/test/static/sample.xml.gz new file mode 100644 index 0000000000000000000000000000000000000000..c0fd5e6fd3c3a42dd2c9ec81e9a3ca424ef35b24 GIT binary patch literal 264 zcmV+j0r&nNiwFqEjJZ_;19M?*aBO8Rcx`L|m6Fd+!!QiS?|X_U4?q$a(<Wt^5aKov zVh7G%YIPB<QzhA-^7KsYP=U2l@x@N;Px*dH^y*X=?0_LUPfM<DBwv|{&LDxAuybhZ z_mo1-2ufV?wL`m0NHL)!-i|b50qDahEt=eI*9gJfN;%h}DZ5UdRh2brs+5#kw5zU5 z=<?mxhs&`K`<Q|Q&N3I!rpD_N7sG<h(WOre1yJ@&^!_c<;sVx-xp9<3<pW+JPKOYc z8bG{XEJhGMLjiUCgZMJe?JJx!Tv?sX|Ls-X%|>{A^f3W@a~AsVwqH~Day#^dKlrq0 OKi?O$L>^X}0ssI%#(xO_ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.8/site-packages/tornado/test/static_foo.txt b/venv/lib/python3.8/site-packages/tornado/test/static_foo.txt new file mode 100644 index 0000000..bdb44f3 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/static_foo.txt @@ -0,0 +1,2 @@ +This file should not be served by StaticFileHandler even though +its name starts with "static". diff --git a/venv/lib/python3.8/site-packages/tornado/test/tcpclient_test.py b/venv/lib/python3.8/site-packages/tornado/test/tcpclient_test.py new file mode 100644 index 0000000..75f4818 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/tcpclient_test.py @@ -0,0 +1,438 @@ +# +# Copyright 2014 Facebook +# +# 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. +from contextlib import closing +import getpass +import os +import socket +import unittest + +from tornado.concurrent import Future +from tornado.netutil import bind_sockets, Resolver +from tornado.queues import Queue +from tornado.tcpclient import TCPClient, _Connector +from tornado.tcpserver import TCPServer +from tornado.testing import AsyncTestCase, gen_test +from tornado.test.util import skipIfNoIPv6, refusing_port, skipIfNonUnix +from tornado.gen import TimeoutError + +import typing + +if typing.TYPE_CHECKING: + from tornado.iostream import IOStream # noqa: F401 + from typing import List, Dict, Tuple # noqa: F401 + +# Fake address families for testing. Used in place of AF_INET +# and AF_INET6 because some installations do not have AF_INET6. +AF1, AF2 = 1, 2 + + +class TestTCPServer(TCPServer): + def __init__(self, family): + super().__init__() + self.streams = [] # type: List[IOStream] + self.queue = Queue() # type: Queue[IOStream] + sockets = bind_sockets(0, "localhost", family) + self.add_sockets(sockets) + self.port = sockets[0].getsockname()[1] + + def handle_stream(self, stream, address): + self.streams.append(stream) + self.queue.put(stream) + + def stop(self): + super().stop() + for stream in self.streams: + stream.close() + + +class TCPClientTest(AsyncTestCase): + def setUp(self): + super().setUp() + self.server = None + self.client = TCPClient() + + def start_server(self, family): + if family == socket.AF_UNSPEC and "TRAVIS" in os.environ: + self.skipTest("dual-stack servers often have port conflicts on travis") + self.server = TestTCPServer(family) + return self.server.port + + def stop_server(self): + if self.server is not None: + self.server.stop() + self.server = None + + def tearDown(self): + self.client.close() + self.stop_server() + super().tearDown() + + def skipIfLocalhostV4(self): + # The port used here doesn't matter, but some systems require it + # to be non-zero if we do not also pass AI_PASSIVE. + addrinfo = self.io_loop.run_sync(lambda: Resolver().resolve("localhost", 80)) + families = set(addr[0] for addr in addrinfo) + if socket.AF_INET6 not in families: + self.skipTest("localhost does not resolve to ipv6") + + @gen_test + def do_test_connect(self, family, host, source_ip=None, source_port=None): + port = self.start_server(family) + stream = yield self.client.connect( + host, port, source_ip=source_ip, source_port=source_port + ) + assert self.server is not None + server_stream = yield self.server.queue.get() + with closing(stream): + stream.write(b"hello") + data = yield server_stream.read_bytes(5) + self.assertEqual(data, b"hello") + + def test_connect_ipv4_ipv4(self): + self.do_test_connect(socket.AF_INET, "127.0.0.1") + + def test_connect_ipv4_dual(self): + self.do_test_connect(socket.AF_INET, "localhost") + + @skipIfNoIPv6 + def test_connect_ipv6_ipv6(self): + self.skipIfLocalhostV4() + self.do_test_connect(socket.AF_INET6, "::1") + + @skipIfNoIPv6 + def test_connect_ipv6_dual(self): + self.skipIfLocalhostV4() + if Resolver.configured_class().__name__.endswith("TwistedResolver"): + self.skipTest("TwistedResolver does not support multiple addresses") + self.do_test_connect(socket.AF_INET6, "localhost") + + def test_connect_unspec_ipv4(self): + self.do_test_connect(socket.AF_UNSPEC, "127.0.0.1") + + @skipIfNoIPv6 + def test_connect_unspec_ipv6(self): + self.skipIfLocalhostV4() + self.do_test_connect(socket.AF_UNSPEC, "::1") + + def test_connect_unspec_dual(self): + self.do_test_connect(socket.AF_UNSPEC, "localhost") + + @gen_test + def test_refused_ipv4(self): + cleanup_func, port = refusing_port() + self.addCleanup(cleanup_func) + with self.assertRaises(IOError): + yield self.client.connect("127.0.0.1", port) + + def test_source_ip_fail(self): + """Fail when trying to use the source IP Address '8.8.8.8'. + """ + self.assertRaises( + socket.error, + self.do_test_connect, + socket.AF_INET, + "127.0.0.1", + source_ip="8.8.8.8", + ) + + def test_source_ip_success(self): + """Success when trying to use the source IP Address '127.0.0.1'. + """ + self.do_test_connect(socket.AF_INET, "127.0.0.1", source_ip="127.0.0.1") + + @skipIfNonUnix + def test_source_port_fail(self): + """Fail when trying to use source port 1. + """ + if getpass.getuser() == "root": + # Root can use any port so we can't easily force this to fail. + # This is mainly relevant for docker. + self.skipTest("running as root") + self.assertRaises( + socket.error, + self.do_test_connect, + socket.AF_INET, + "127.0.0.1", + source_port=1, + ) + + @gen_test + def test_connect_timeout(self): + timeout = 0.05 + + class TimeoutResolver(Resolver): + def resolve(self, *args, **kwargs): + return Future() # never completes + + with self.assertRaises(TimeoutError): + yield TCPClient(resolver=TimeoutResolver()).connect( + "1.2.3.4", 12345, timeout=timeout + ) + + +class TestConnectorSplit(unittest.TestCase): + def test_one_family(self): + # These addresses aren't in the right format, but split doesn't care. + primary, secondary = _Connector.split([(AF1, "a"), (AF1, "b")]) + self.assertEqual(primary, [(AF1, "a"), (AF1, "b")]) + self.assertEqual(secondary, []) + + def test_mixed(self): + primary, secondary = _Connector.split( + [(AF1, "a"), (AF2, "b"), (AF1, "c"), (AF2, "d")] + ) + self.assertEqual(primary, [(AF1, "a"), (AF1, "c")]) + self.assertEqual(secondary, [(AF2, "b"), (AF2, "d")]) + + +class ConnectorTest(AsyncTestCase): + class FakeStream(object): + def __init__(self): + self.closed = False + + def close(self): + self.closed = True + + def setUp(self): + super().setUp() + self.connect_futures = ( + {} + ) # type: Dict[Tuple[int, typing.Any], Future[ConnectorTest.FakeStream]] + self.streams = {} # type: Dict[typing.Any, ConnectorTest.FakeStream] + self.addrinfo = [(AF1, "a"), (AF1, "b"), (AF2, "c"), (AF2, "d")] + + def tearDown(self): + # Unless explicitly checked (and popped) in the test, we shouldn't + # be closing any streams + for stream in self.streams.values(): + self.assertFalse(stream.closed) + super().tearDown() + + def create_stream(self, af, addr): + stream = ConnectorTest.FakeStream() + self.streams[addr] = stream + future = Future() # type: Future[ConnectorTest.FakeStream] + self.connect_futures[(af, addr)] = future + return stream, future + + def assert_pending(self, *keys): + self.assertEqual(sorted(self.connect_futures.keys()), sorted(keys)) + + def resolve_connect(self, af, addr, success): + future = self.connect_futures.pop((af, addr)) + if success: + future.set_result(self.streams[addr]) + else: + self.streams.pop(addr) + future.set_exception(IOError()) + # Run the loop to allow callbacks to be run. + self.io_loop.add_callback(self.stop) + self.wait() + + def assert_connector_streams_closed(self, conn): + for stream in conn.streams: + self.assertTrue(stream.closed) + + def start_connect(self, addrinfo): + conn = _Connector(addrinfo, self.create_stream) + # Give it a huge timeout; we'll trigger timeouts manually. + future = conn.start(3600, connect_timeout=self.io_loop.time() + 3600) + return conn, future + + def test_immediate_success(self): + conn, future = self.start_connect(self.addrinfo) + self.assertEqual(list(self.connect_futures.keys()), [(AF1, "a")]) + self.resolve_connect(AF1, "a", True) + self.assertEqual(future.result(), (AF1, "a", self.streams["a"])) + + def test_immediate_failure(self): + # Fail with just one address. + conn, future = self.start_connect([(AF1, "a")]) + self.assert_pending((AF1, "a")) + self.resolve_connect(AF1, "a", False) + self.assertRaises(IOError, future.result) + + def test_one_family_second_try(self): + conn, future = self.start_connect([(AF1, "a"), (AF1, "b")]) + self.assert_pending((AF1, "a")) + self.resolve_connect(AF1, "a", False) + self.assert_pending((AF1, "b")) + self.resolve_connect(AF1, "b", True) + self.assertEqual(future.result(), (AF1, "b", self.streams["b"])) + + def test_one_family_second_try_failure(self): + conn, future = self.start_connect([(AF1, "a"), (AF1, "b")]) + self.assert_pending((AF1, "a")) + self.resolve_connect(AF1, "a", False) + self.assert_pending((AF1, "b")) + self.resolve_connect(AF1, "b", False) + self.assertRaises(IOError, future.result) + + def test_one_family_second_try_timeout(self): + conn, future = self.start_connect([(AF1, "a"), (AF1, "b")]) + self.assert_pending((AF1, "a")) + # trigger the timeout while the first lookup is pending; + # nothing happens. + conn.on_timeout() + self.assert_pending((AF1, "a")) + self.resolve_connect(AF1, "a", False) + self.assert_pending((AF1, "b")) + self.resolve_connect(AF1, "b", True) + self.assertEqual(future.result(), (AF1, "b", self.streams["b"])) + + def test_two_families_immediate_failure(self): + conn, future = self.start_connect(self.addrinfo) + self.assert_pending((AF1, "a")) + self.resolve_connect(AF1, "a", False) + self.assert_pending((AF1, "b"), (AF2, "c")) + self.resolve_connect(AF1, "b", False) + self.resolve_connect(AF2, "c", True) + self.assertEqual(future.result(), (AF2, "c", self.streams["c"])) + + def test_two_families_timeout(self): + conn, future = self.start_connect(self.addrinfo) + self.assert_pending((AF1, "a")) + conn.on_timeout() + self.assert_pending((AF1, "a"), (AF2, "c")) + self.resolve_connect(AF2, "c", True) + self.assertEqual(future.result(), (AF2, "c", self.streams["c"])) + # resolving 'a' after the connection has completed doesn't start 'b' + self.resolve_connect(AF1, "a", False) + self.assert_pending() + + def test_success_after_timeout(self): + conn, future = self.start_connect(self.addrinfo) + self.assert_pending((AF1, "a")) + conn.on_timeout() + self.assert_pending((AF1, "a"), (AF2, "c")) + self.resolve_connect(AF1, "a", True) + self.assertEqual(future.result(), (AF1, "a", self.streams["a"])) + # resolving 'c' after completion closes the connection. + self.resolve_connect(AF2, "c", True) + self.assertTrue(self.streams.pop("c").closed) + + def test_all_fail(self): + conn, future = self.start_connect(self.addrinfo) + self.assert_pending((AF1, "a")) + conn.on_timeout() + self.assert_pending((AF1, "a"), (AF2, "c")) + self.resolve_connect(AF2, "c", False) + self.assert_pending((AF1, "a"), (AF2, "d")) + self.resolve_connect(AF2, "d", False) + # one queue is now empty + self.assert_pending((AF1, "a")) + self.resolve_connect(AF1, "a", False) + self.assert_pending((AF1, "b")) + self.assertFalse(future.done()) + self.resolve_connect(AF1, "b", False) + self.assertRaises(IOError, future.result) + + def test_one_family_timeout_after_connect_timeout(self): + conn, future = self.start_connect([(AF1, "a"), (AF1, "b")]) + self.assert_pending((AF1, "a")) + conn.on_connect_timeout() + # the connector will close all streams on connect timeout, we + # should explicitly pop the connect_future. + self.connect_futures.pop((AF1, "a")) + self.assertTrue(self.streams.pop("a").closed) + conn.on_timeout() + # if the future is set with TimeoutError, we will not iterate next + # possible address. + self.assert_pending() + self.assertEqual(len(conn.streams), 1) + self.assert_connector_streams_closed(conn) + self.assertRaises(TimeoutError, future.result) + + def test_one_family_success_before_connect_timeout(self): + conn, future = self.start_connect([(AF1, "a"), (AF1, "b")]) + self.assert_pending((AF1, "a")) + self.resolve_connect(AF1, "a", True) + conn.on_connect_timeout() + self.assert_pending() + self.assertEqual(self.streams["a"].closed, False) + # success stream will be pop + self.assertEqual(len(conn.streams), 0) + # streams in connector should be closed after connect timeout + self.assert_connector_streams_closed(conn) + self.assertEqual(future.result(), (AF1, "a", self.streams["a"])) + + def test_one_family_second_try_after_connect_timeout(self): + conn, future = self.start_connect([(AF1, "a"), (AF1, "b")]) + self.assert_pending((AF1, "a")) + self.resolve_connect(AF1, "a", False) + self.assert_pending((AF1, "b")) + conn.on_connect_timeout() + self.connect_futures.pop((AF1, "b")) + self.assertTrue(self.streams.pop("b").closed) + self.assert_pending() + self.assertEqual(len(conn.streams), 2) + self.assert_connector_streams_closed(conn) + self.assertRaises(TimeoutError, future.result) + + def test_one_family_second_try_failure_before_connect_timeout(self): + conn, future = self.start_connect([(AF1, "a"), (AF1, "b")]) + self.assert_pending((AF1, "a")) + self.resolve_connect(AF1, "a", False) + self.assert_pending((AF1, "b")) + self.resolve_connect(AF1, "b", False) + conn.on_connect_timeout() + self.assert_pending() + self.assertEqual(len(conn.streams), 2) + self.assert_connector_streams_closed(conn) + self.assertRaises(IOError, future.result) + + def test_two_family_timeout_before_connect_timeout(self): + conn, future = self.start_connect(self.addrinfo) + self.assert_pending((AF1, "a")) + conn.on_timeout() + self.assert_pending((AF1, "a"), (AF2, "c")) + conn.on_connect_timeout() + self.connect_futures.pop((AF1, "a")) + self.assertTrue(self.streams.pop("a").closed) + self.connect_futures.pop((AF2, "c")) + self.assertTrue(self.streams.pop("c").closed) + self.assert_pending() + self.assertEqual(len(conn.streams), 2) + self.assert_connector_streams_closed(conn) + self.assertRaises(TimeoutError, future.result) + + def test_two_family_success_after_timeout(self): + conn, future = self.start_connect(self.addrinfo) + self.assert_pending((AF1, "a")) + conn.on_timeout() + self.assert_pending((AF1, "a"), (AF2, "c")) + self.resolve_connect(AF1, "a", True) + # if one of streams succeed, connector will close all other streams + self.connect_futures.pop((AF2, "c")) + self.assertTrue(self.streams.pop("c").closed) + self.assert_pending() + self.assertEqual(len(conn.streams), 1) + self.assert_connector_streams_closed(conn) + self.assertEqual(future.result(), (AF1, "a", self.streams["a"])) + + def test_two_family_timeout_after_connect_timeout(self): + conn, future = self.start_connect(self.addrinfo) + self.assert_pending((AF1, "a")) + conn.on_connect_timeout() + self.connect_futures.pop((AF1, "a")) + self.assertTrue(self.streams.pop("a").closed) + self.assert_pending() + conn.on_timeout() + # if the future is set with TimeoutError, connector will not + # trigger secondary address. + self.assert_pending() + self.assertEqual(len(conn.streams), 1) + self.assert_connector_streams_closed(conn) + self.assertRaises(TimeoutError, future.result) diff --git a/venv/lib/python3.8/site-packages/tornado/test/tcpserver_test.py b/venv/lib/python3.8/site-packages/tornado/test/tcpserver_test.py new file mode 100644 index 0000000..7c75acf --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/tcpserver_test.py @@ -0,0 +1,192 @@ +import socket +import subprocess +import sys +import textwrap +import unittest + +from tornado.escape import utf8, to_unicode +from tornado import gen +from tornado.iostream import IOStream +from tornado.log import app_log +from tornado.tcpserver import TCPServer +from tornado.test.util import skipIfNonUnix +from tornado.testing import AsyncTestCase, ExpectLog, bind_unused_port, gen_test + + +class TCPServerTest(AsyncTestCase): + @gen_test + def test_handle_stream_coroutine_logging(self): + # handle_stream may be a coroutine and any exception in its + # Future will be logged. + class TestServer(TCPServer): + @gen.coroutine + def handle_stream(self, stream, address): + yield stream.read_bytes(len(b"hello")) + stream.close() + 1 / 0 + + server = client = None + try: + sock, port = bind_unused_port() + server = TestServer() + server.add_socket(sock) + client = IOStream(socket.socket()) + with ExpectLog(app_log, "Exception in callback"): + yield client.connect(("localhost", port)) + yield client.write(b"hello") + yield client.read_until_close() + yield gen.moment + finally: + if server is not None: + server.stop() + if client is not None: + client.close() + + @gen_test + def test_handle_stream_native_coroutine(self): + # handle_stream may be a native coroutine. + + class TestServer(TCPServer): + async def handle_stream(self, stream, address): + stream.write(b"data") + stream.close() + + sock, port = bind_unused_port() + server = TestServer() + server.add_socket(sock) + client = IOStream(socket.socket()) + yield client.connect(("localhost", port)) + result = yield client.read_until_close() + self.assertEqual(result, b"data") + server.stop() + client.close() + + def test_stop_twice(self): + sock, port = bind_unused_port() + server = TCPServer() + server.add_socket(sock) + server.stop() + server.stop() + + @gen_test + def test_stop_in_callback(self): + # Issue #2069: calling server.stop() in a loop callback should not + # raise EBADF when the loop handles other server connection + # requests in the same loop iteration + + class TestServer(TCPServer): + @gen.coroutine + def handle_stream(self, stream, address): + server.stop() # type: ignore + yield stream.read_until_close() + + sock, port = bind_unused_port() + server = TestServer() + server.add_socket(sock) + server_addr = ("localhost", port) + N = 40 + clients = [IOStream(socket.socket()) for i in range(N)] + connected_clients = [] + + @gen.coroutine + def connect(c): + try: + yield c.connect(server_addr) + except EnvironmentError: + pass + else: + connected_clients.append(c) + + yield [connect(c) for c in clients] + + self.assertGreater(len(connected_clients), 0, "all clients failed connecting") + try: + if len(connected_clients) == N: + # Ideally we'd make the test deterministic, but we're testing + # for a race condition in combination with the system's TCP stack... + self.skipTest( + "at least one client should fail connecting " + "for the test to be meaningful" + ) + finally: + for c in connected_clients: + c.close() + + # Here tearDown() would re-raise the EBADF encountered in the IO loop + + +@skipIfNonUnix +class TestMultiprocess(unittest.TestCase): + # These tests verify that the two multiprocess examples from the + # TCPServer docs work. Both tests start a server with three worker + # processes, each of which prints its task id to stdout (a single + # byte, so we don't have to worry about atomicity of the shared + # stdout stream) and then exits. + def run_subproc(self, code): + proc = subprocess.Popen( + sys.executable, stdin=subprocess.PIPE, stdout=subprocess.PIPE + ) + proc.stdin.write(utf8(code)) + proc.stdin.close() + proc.wait() + stdout = proc.stdout.read() + proc.stdout.close() + if proc.returncode != 0: + raise RuntimeError( + "Process returned %d. stdout=%r" % (proc.returncode, stdout) + ) + return to_unicode(stdout) + + def test_single(self): + # As a sanity check, run the single-process version through this test + # harness too. + code = textwrap.dedent( + """ + from tornado.ioloop import IOLoop + from tornado.tcpserver import TCPServer + + server = TCPServer() + server.listen(0, address='127.0.0.1') + IOLoop.current().run_sync(lambda: None) + print('012', end='') + """ + ) + out = self.run_subproc(code) + self.assertEqual("".join(sorted(out)), "012") + + def test_simple(self): + code = textwrap.dedent( + """ + from tornado.ioloop import IOLoop + from tornado.process import task_id + from tornado.tcpserver import TCPServer + + server = TCPServer() + server.bind(0, address='127.0.0.1') + server.start(3) + IOLoop.current().run_sync(lambda: None) + print(task_id(), end='') + """ + ) + out = self.run_subproc(code) + self.assertEqual("".join(sorted(out)), "012") + + def test_advanced(self): + code = textwrap.dedent( + """ + from tornado.ioloop import IOLoop + from tornado.netutil import bind_sockets + from tornado.process import fork_processes, task_id + from tornado.ioloop import IOLoop + from tornado.tcpserver import TCPServer + + sockets = bind_sockets(0, address='127.0.0.1') + fork_processes(3) + server = TCPServer() + server.add_sockets(sockets) + IOLoop.current().run_sync(lambda: None) + print(task_id(), end='') + """ + ) + out = self.run_subproc(code) + self.assertEqual("".join(sorted(out)), "012") diff --git a/venv/lib/python3.8/site-packages/tornado/test/template_test.py b/venv/lib/python3.8/site-packages/tornado/test/template_test.py new file mode 100644 index 0000000..f71f037 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/template_test.py @@ -0,0 +1,536 @@ +import os +import traceback +import unittest + +from tornado.escape import utf8, native_str, to_unicode +from tornado.template import Template, DictLoader, ParseError, Loader +from tornado.util import ObjectDict + +import typing # noqa: F401 + + +class TemplateTest(unittest.TestCase): + def test_simple(self): + template = Template("Hello {{ name }}!") + self.assertEqual(template.generate(name="Ben"), b"Hello Ben!") + + def test_bytes(self): + template = Template("Hello {{ name }}!") + self.assertEqual(template.generate(name=utf8("Ben")), b"Hello Ben!") + + def test_expressions(self): + template = Template("2 + 2 = {{ 2 + 2 }}") + self.assertEqual(template.generate(), b"2 + 2 = 4") + + def test_comment(self): + template = Template("Hello{# TODO i18n #} {{ name }}!") + self.assertEqual(template.generate(name=utf8("Ben")), b"Hello Ben!") + + def test_include(self): + loader = DictLoader( + { + "index.html": '{% include "header.html" %}\nbody text', + "header.html": "header text", + } + ) + self.assertEqual( + loader.load("index.html").generate(), b"header text\nbody text" + ) + + def test_extends(self): + loader = DictLoader( + { + "base.html": """\ +<title>{% block title %}default title{% end %}</title> +<body>{% block body %}default body{% end %}</body> +""", + "page.html": """\ +{% extends "base.html" %} +{% block title %}page title{% end %} +{% block body %}page body{% end %} +""", + } + ) + self.assertEqual( + loader.load("page.html").generate(), + b"<title>page title</title>\n<body>page body</body>\n", + ) + + def test_relative_load(self): + loader = DictLoader( + { + "a/1.html": "{% include '2.html' %}", + "a/2.html": "{% include '../b/3.html' %}", + "b/3.html": "ok", + } + ) + self.assertEqual(loader.load("a/1.html").generate(), b"ok") + + def test_escaping(self): + self.assertRaises(ParseError, lambda: Template("{{")) + self.assertRaises(ParseError, lambda: Template("{%")) + self.assertEqual(Template("{{!").generate(), b"{{") + self.assertEqual(Template("{%!").generate(), b"{%") + self.assertEqual(Template("{#!").generate(), b"{#") + self.assertEqual( + Template("{{ 'expr' }} {{!jquery expr}}").generate(), + b"expr {{jquery expr}}", + ) + + def test_unicode_template(self): + template = Template(utf8(u"\u00e9")) + self.assertEqual(template.generate(), utf8(u"\u00e9")) + + def test_unicode_literal_expression(self): + # Unicode literals should be usable in templates. Note that this + # test simulates unicode characters appearing directly in the + # template file (with utf8 encoding), i.e. \u escapes would not + # be used in the template file itself. + template = Template(utf8(u'{{ "\u00e9" }}')) + self.assertEqual(template.generate(), utf8(u"\u00e9")) + + def test_custom_namespace(self): + loader = DictLoader( + {"test.html": "{{ inc(5) }}"}, namespace={"inc": lambda x: x + 1} + ) + self.assertEqual(loader.load("test.html").generate(), b"6") + + def test_apply(self): + def upper(s): + return s.upper() + + template = Template(utf8("{% apply upper %}foo{% end %}")) + self.assertEqual(template.generate(upper=upper), b"FOO") + + def test_unicode_apply(self): + def upper(s): + return to_unicode(s).upper() + + template = Template(utf8(u"{% apply upper %}foo \u00e9{% end %}")) + self.assertEqual(template.generate(upper=upper), utf8(u"FOO \u00c9")) + + def test_bytes_apply(self): + def upper(s): + return utf8(to_unicode(s).upper()) + + template = Template(utf8(u"{% apply upper %}foo \u00e9{% end %}")) + self.assertEqual(template.generate(upper=upper), utf8(u"FOO \u00c9")) + + def test_if(self): + template = Template(utf8("{% if x > 4 %}yes{% else %}no{% end %}")) + self.assertEqual(template.generate(x=5), b"yes") + self.assertEqual(template.generate(x=3), b"no") + + def test_if_empty_body(self): + template = Template(utf8("{% if True %}{% else %}{% end %}")) + self.assertEqual(template.generate(), b"") + + def test_try(self): + template = Template( + utf8( + """{% try %} +try{% set y = 1/x %} +{% except %}-except +{% else %}-else +{% finally %}-finally +{% end %}""" + ) + ) + self.assertEqual(template.generate(x=1), b"\ntry\n-else\n-finally\n") + self.assertEqual(template.generate(x=0), b"\ntry-except\n-finally\n") + + def test_comment_directive(self): + template = Template(utf8("{% comment blah blah %}foo")) + self.assertEqual(template.generate(), b"foo") + + def test_break_continue(self): + template = Template( + utf8( + """\ +{% for i in range(10) %} + {% if i == 2 %} + {% continue %} + {% end %} + {{ i }} + {% if i == 6 %} + {% break %} + {% end %} +{% end %}""" + ) + ) + result = template.generate() + # remove extraneous whitespace + result = b"".join(result.split()) + self.assertEqual(result, b"013456") + + def test_break_outside_loop(self): + try: + Template(utf8("{% break %}")) + raise Exception("Did not get expected exception") + except ParseError: + pass + + def test_break_in_apply(self): + # This test verifies current behavior, although of course it would + # be nice if apply didn't cause seemingly unrelated breakage + try: + Template( + utf8("{% for i in [] %}{% apply foo %}{% break %}{% end %}{% end %}") + ) + raise Exception("Did not get expected exception") + except ParseError: + pass + + @unittest.skip("no testable future imports") + def test_no_inherit_future(self): + # TODO(bdarnell): make a test like this for one of the future + # imports available in python 3. Unfortunately they're harder + # to use in a template than division was. + + # This file has from __future__ import division... + self.assertEqual(1 / 2, 0.5) + # ...but the template doesn't + template = Template("{{ 1 / 2 }}") + self.assertEqual(template.generate(), "0") + + def test_non_ascii_name(self): + loader = DictLoader({u"t\u00e9st.html": "hello"}) + self.assertEqual(loader.load(u"t\u00e9st.html").generate(), b"hello") + + +class StackTraceTest(unittest.TestCase): + def test_error_line_number_expression(self): + loader = DictLoader( + { + "test.html": """one +two{{1/0}} +three + """ + } + ) + try: + loader.load("test.html").generate() + self.fail("did not get expected exception") + except ZeroDivisionError: + self.assertTrue("# test.html:2" in traceback.format_exc()) + + def test_error_line_number_directive(self): + loader = DictLoader( + { + "test.html": """one +two{%if 1/0%} +three{%end%} + """ + } + ) + try: + loader.load("test.html").generate() + self.fail("did not get expected exception") + except ZeroDivisionError: + self.assertTrue("# test.html:2" in traceback.format_exc()) + + def test_error_line_number_module(self): + loader = None # type: typing.Optional[DictLoader] + + def load_generate(path, **kwargs): + assert loader is not None + return loader.load(path).generate(**kwargs) + + loader = DictLoader( + {"base.html": "{% module Template('sub.html') %}", "sub.html": "{{1/0}}"}, + namespace={"_tt_modules": ObjectDict(Template=load_generate)}, + ) + try: + loader.load("base.html").generate() + self.fail("did not get expected exception") + except ZeroDivisionError: + exc_stack = traceback.format_exc() + self.assertTrue("# base.html:1" in exc_stack) + self.assertTrue("# sub.html:1" in exc_stack) + + def test_error_line_number_include(self): + loader = DictLoader( + {"base.html": "{% include 'sub.html' %}", "sub.html": "{{1/0}}"} + ) + try: + loader.load("base.html").generate() + self.fail("did not get expected exception") + except ZeroDivisionError: + self.assertTrue("# sub.html:1 (via base.html:1)" in traceback.format_exc()) + + def test_error_line_number_extends_base_error(self): + loader = DictLoader( + {"base.html": "{{1/0}}", "sub.html": "{% extends 'base.html' %}"} + ) + try: + loader.load("sub.html").generate() + self.fail("did not get expected exception") + except ZeroDivisionError: + exc_stack = traceback.format_exc() + self.assertTrue("# base.html:1" in exc_stack) + + def test_error_line_number_extends_sub_error(self): + loader = DictLoader( + { + "base.html": "{% block 'block' %}{% end %}", + "sub.html": """ +{% extends 'base.html' %} +{% block 'block' %} +{{1/0}} +{% end %} + """, + } + ) + try: + loader.load("sub.html").generate() + self.fail("did not get expected exception") + except ZeroDivisionError: + self.assertTrue("# sub.html:4 (via base.html:1)" in traceback.format_exc()) + + def test_multi_includes(self): + loader = DictLoader( + { + "a.html": "{% include 'b.html' %}", + "b.html": "{% include 'c.html' %}", + "c.html": "{{1/0}}", + } + ) + try: + loader.load("a.html").generate() + self.fail("did not get expected exception") + except ZeroDivisionError: + self.assertTrue( + "# c.html:1 (via b.html:1, a.html:1)" in traceback.format_exc() + ) + + +class ParseErrorDetailTest(unittest.TestCase): + def test_details(self): + loader = DictLoader({"foo.html": "\n\n{{"}) + with self.assertRaises(ParseError) as cm: + loader.load("foo.html") + self.assertEqual("Missing end expression }} at foo.html:3", str(cm.exception)) + self.assertEqual("foo.html", cm.exception.filename) + self.assertEqual(3, cm.exception.lineno) + + def test_custom_parse_error(self): + # Make sure that ParseErrors remain compatible with their + # pre-4.3 signature. + self.assertEqual("asdf at None:0", str(ParseError("asdf"))) + + +class AutoEscapeTest(unittest.TestCase): + def setUp(self): + self.templates = { + "escaped.html": "{% autoescape xhtml_escape %}{{ name }}", + "unescaped.html": "{% autoescape None %}{{ name }}", + "default.html": "{{ name }}", + "include.html": """\ +escaped: {% include 'escaped.html' %} +unescaped: {% include 'unescaped.html' %} +default: {% include 'default.html' %} +""", + "escaped_block.html": """\ +{% autoescape xhtml_escape %}\ +{% block name %}base: {{ name }}{% end %}""", + "unescaped_block.html": """\ +{% autoescape None %}\ +{% block name %}base: {{ name }}{% end %}""", + # Extend a base template with different autoescape policy, + # with and without overriding the base's blocks + "escaped_extends_unescaped.html": """\ +{% autoescape xhtml_escape %}\ +{% extends "unescaped_block.html" %}""", + "escaped_overrides_unescaped.html": """\ +{% autoescape xhtml_escape %}\ +{% extends "unescaped_block.html" %}\ +{% block name %}extended: {{ name }}{% end %}""", + "unescaped_extends_escaped.html": """\ +{% autoescape None %}\ +{% extends "escaped_block.html" %}""", + "unescaped_overrides_escaped.html": """\ +{% autoescape None %}\ +{% extends "escaped_block.html" %}\ +{% block name %}extended: {{ name }}{% end %}""", + "raw_expression.html": """\ +{% autoescape xhtml_escape %}\ +expr: {{ name }} +raw: {% raw name %}""", + } + + def test_default_off(self): + loader = DictLoader(self.templates, autoescape=None) + name = "Bobby <table>s" + self.assertEqual( + loader.load("escaped.html").generate(name=name), b"Bobby &lt;table&gt;s" + ) + self.assertEqual( + loader.load("unescaped.html").generate(name=name), b"Bobby <table>s" + ) + self.assertEqual( + loader.load("default.html").generate(name=name), b"Bobby <table>s" + ) + + self.assertEqual( + loader.load("include.html").generate(name=name), + b"escaped: Bobby &lt;table&gt;s\n" + b"unescaped: Bobby <table>s\n" + b"default: Bobby <table>s\n", + ) + + def test_default_on(self): + loader = DictLoader(self.templates, autoescape="xhtml_escape") + name = "Bobby <table>s" + self.assertEqual( + loader.load("escaped.html").generate(name=name), b"Bobby &lt;table&gt;s" + ) + self.assertEqual( + loader.load("unescaped.html").generate(name=name), b"Bobby <table>s" + ) + self.assertEqual( + loader.load("default.html").generate(name=name), b"Bobby &lt;table&gt;s" + ) + + self.assertEqual( + loader.load("include.html").generate(name=name), + b"escaped: Bobby &lt;table&gt;s\n" + b"unescaped: Bobby <table>s\n" + b"default: Bobby &lt;table&gt;s\n", + ) + + def test_unextended_block(self): + loader = DictLoader(self.templates) + name = "<script>" + self.assertEqual( + loader.load("escaped_block.html").generate(name=name), + b"base: &lt;script&gt;", + ) + self.assertEqual( + loader.load("unescaped_block.html").generate(name=name), b"base: <script>" + ) + + def test_extended_block(self): + loader = DictLoader(self.templates) + + def render(name): + return loader.load(name).generate(name="<script>") + + self.assertEqual(render("escaped_extends_unescaped.html"), b"base: <script>") + self.assertEqual( + render("escaped_overrides_unescaped.html"), b"extended: &lt;script&gt;" + ) + + self.assertEqual( + render("unescaped_extends_escaped.html"), b"base: &lt;script&gt;" + ) + self.assertEqual( + render("unescaped_overrides_escaped.html"), b"extended: <script>" + ) + + def test_raw_expression(self): + loader = DictLoader(self.templates) + + def render(name): + return loader.load(name).generate(name='<>&"') + + self.assertEqual( + render("raw_expression.html"), b"expr: &lt;&gt;&amp;&quot;\n" b'raw: <>&"' + ) + + def test_custom_escape(self): + loader = DictLoader({"foo.py": "{% autoescape py_escape %}s = {{ name }}\n"}) + + def py_escape(s): + self.assertEqual(type(s), bytes) + return repr(native_str(s)) + + def render(template, name): + return loader.load(template).generate(py_escape=py_escape, name=name) + + self.assertEqual(render("foo.py", "<html>"), b"s = '<html>'\n") + self.assertEqual(render("foo.py", "';sys.exit()"), b"""s = "';sys.exit()"\n""") + self.assertEqual( + render("foo.py", ["not a string"]), b"""s = "['not a string']"\n""" + ) + + def test_manual_minimize_whitespace(self): + # Whitespace including newlines is allowed within template tags + # and directives, and this is one way to avoid long lines while + # keeping extra whitespace out of the rendered output. + loader = DictLoader( + { + "foo.txt": """\ +{% for i in items + %}{% if i > 0 %}, {% end %}{# + #}{{i + }}{% end +%}""" + } + ) + self.assertEqual( + loader.load("foo.txt").generate(items=range(5)), b"0, 1, 2, 3, 4" + ) + + def test_whitespace_by_filename(self): + # Default whitespace handling depends on the template filename. + loader = DictLoader( + { + "foo.html": " \n\t\n asdf\t ", + "bar.js": " \n\n\n\t qwer ", + "baz.txt": "\t zxcv\n\n", + "include.html": " {% include baz.txt %} \n ", + "include.txt": "\t\t{% include foo.html %} ", + } + ) + + # HTML and JS files have whitespace compressed by default. + self.assertEqual(loader.load("foo.html").generate(), b"\nasdf ") + self.assertEqual(loader.load("bar.js").generate(), b"\nqwer ") + # TXT files do not. + self.assertEqual(loader.load("baz.txt").generate(), b"\t zxcv\n\n") + + # Each file maintains its own status even when included in + # a file of the other type. + self.assertEqual(loader.load("include.html").generate(), b" \t zxcv\n\n\n") + self.assertEqual(loader.load("include.txt").generate(), b"\t\t\nasdf ") + + def test_whitespace_by_loader(self): + templates = {"foo.html": "\t\tfoo\n\n", "bar.txt": "\t\tbar\n\n"} + loader = DictLoader(templates, whitespace="all") + self.assertEqual(loader.load("foo.html").generate(), b"\t\tfoo\n\n") + self.assertEqual(loader.load("bar.txt").generate(), b"\t\tbar\n\n") + + loader = DictLoader(templates, whitespace="single") + self.assertEqual(loader.load("foo.html").generate(), b" foo\n") + self.assertEqual(loader.load("bar.txt").generate(), b" bar\n") + + loader = DictLoader(templates, whitespace="oneline") + self.assertEqual(loader.load("foo.html").generate(), b" foo ") + self.assertEqual(loader.load("bar.txt").generate(), b" bar ") + + def test_whitespace_directive(self): + loader = DictLoader( + { + "foo.html": """\ +{% whitespace oneline %} + {% for i in range(3) %} + {{ i }} + {% end %} +{% whitespace all %} + pre\tformatted +""" + } + ) + self.assertEqual( + loader.load("foo.html").generate(), b" 0 1 2 \n pre\tformatted\n" + ) + + +class TemplateLoaderTest(unittest.TestCase): + def setUp(self): + self.loader = Loader(os.path.join(os.path.dirname(__file__), "templates")) + + def test_utf8_in_file(self): + tmpl = self.loader.load("utf8.html") + result = tmpl.generate() + self.assertEqual(to_unicode(result).strip(), u"H\u00e9llo") diff --git a/venv/lib/python3.8/site-packages/tornado/test/templates/utf8.html b/venv/lib/python3.8/site-packages/tornado/test/templates/utf8.html new file mode 100644 index 0000000..c5253df --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/templates/utf8.html @@ -0,0 +1 @@ +Héllo diff --git a/venv/lib/python3.8/site-packages/tornado/test/test.crt b/venv/lib/python3.8/site-packages/tornado/test/test.crt new file mode 100644 index 0000000..ffc49b0 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/test.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDWzCCAkOgAwIBAgIUV4spou0CenmvKqa7Hml/MC+JKiAwDQYJKoZIhvcNAQEL +BQAwPTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExGTAXBgNVBAoM +EFRvcm5hZG8gV2ViIFRlc3QwHhcNMTgwOTI5MTM1NjQ1WhcNMjgwOTI2MTM1NjQ1 +WjA9MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEZMBcGA1UECgwQ +VG9ybmFkbyBXZWIgVGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB +AKT0LdyI8tW5uwP3ahE8BFSz+j3SsKBDv/0cKvqxVVE6sLEST2s3HjArZvIIG5sb +iBkWDrqnZ6UKDvB4jlobLGAkepxDbrxHWxK53n0C28XXGLqJQ01TlTZ5rpjttMeg +5SKNjHbxpOvpUwwQS4br4WjZKKyTGiXpFkFUty+tYVU35/U2yyvreWHmzpHx/25t +H7O2RBARVwJYKOGPtlH62lQjpIWfVfklY4Ip8Hjl3B6rBxPyBULmVQw0qgoZn648 +oa4oLjs0wnYBz01gVjNMDHej52SsB/ieH7W1TxFMzqOlcvHh41uFbQJPgcXsruSS +9Z4twzSWkUp2vk/C//4Sz38CAwEAAaNTMFEwHQYDVR0OBBYEFLf8fQ5+u8sDWAd3 +r5ZjZ5MmDWJeMB8GA1UdIwQYMBaAFLf8fQ5+u8sDWAd3r5ZjZ5MmDWJeMA8GA1Ud +EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBADkkm3pIb9IeqVNmQ2uhQOgw +UwyToTYUHNTb/Nm5lzBTBqC8gbXAS24RQ30AB/7G115Uxeo+YMKfITxm/CgR+vhF +F59/YrzwXj+G8bdbuVl/UbB6f9RSp+Zo93rUZAtPWr77gxLUrcwSRzzDwxFjC2nC +6eigbkvt1OQY775RwnFAt7HKPclE0Out+cGJIboJuO1f3r57ZdyFH0GzbZEff/7K +atGXohijWJjYvU4mk0KFHORZrcBpsv9cfkFbmgVmiRwxRJ1tLauHM3Ne+VfqYE5M +4rTStSyz3ASqVKJ2iFMQueNR/tUOuDlfRt+0nhJMuYSSkW+KTgnwyOGU9cv+mxA= +-----END CERTIFICATE----- diff --git a/venv/lib/python3.8/site-packages/tornado/test/test.key b/venv/lib/python3.8/site-packages/tornado/test/test.key new file mode 100644 index 0000000..7cb7d8d --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/test.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCk9C3ciPLVubsD +92oRPARUs/o90rCgQ7/9HCr6sVVROrCxEk9rNx4wK2byCBubG4gZFg66p2elCg7w +eI5aGyxgJHqcQ268R1sSud59AtvF1xi6iUNNU5U2ea6Y7bTHoOUijYx28aTr6VMM +EEuG6+Fo2Siskxol6RZBVLcvrWFVN+f1Nssr63lh5s6R8f9ubR+ztkQQEVcCWCjh +j7ZR+tpUI6SFn1X5JWOCKfB45dweqwcT8gVC5lUMNKoKGZ+uPKGuKC47NMJ2Ac9N +YFYzTAx3o+dkrAf4nh+1tU8RTM6jpXLx4eNbhW0CT4HF7K7kkvWeLcM0lpFKdr5P +wv/+Es9/AgMBAAECggEABi6AaXtYXloPgB6NgwfUwbfc8OQsalUfpMShd7OdluW0 +KW6eO05de0ClIvzay/1EJGyHMMeFQtIVrT1XWFkcWJ4FWkXMqJGkABenFtg8lDVz +X8o1E3jGZrw4ptKBq9mDvL/BO9PiclTUH+ecbPn6AIvi0lTQ7grGIryiAM9mjmLy +jpCwoutF2LD4RPNg8vqWe/Z1rQw5lp8FOHhRwPooHHeoq1bSrp8dqvVAwAam7Mmf +uFgI8jrNycPgr2cwEEtbq2TQ625MhVnCpwT+kErmAStfbXXuqv1X1ZZgiNxf+61C +OL0bhPRVIHmmjiK/5qHRuN4Q5u9/Yp2SJ4W5xadSQQKBgQDR7dnOlYYQiaoPJeD/ +7jcLVJbWwbr7bE19O/QpYAtkA/FtGlKr+hQxPhK6OYp+in8eHf+ga/NSAjCWRBoh +MNAVCJtiirHo2tFsLFOmlJpGL9n3sX8UnkJN90oHfWrzJ8BZnXaSw2eOuyw8LLj+ +Q+ISl6Go8/xfsuy3EDv4AP1wCwKBgQDJJ4vEV3Kr+bc6N/xeu+G0oHvRAWwuQpcx +9D+XpnqbJbFDnWKNE7oGsDCs8Qjr0CdFUN1pm1ppITDZ5N1cWuDg/47ZAXqEK6D1 +z13S7O0oQPlnsPL7mHs2Vl73muAaBPAojFvceHHfccr7Z94BXqKsiyfaWz6kclT/ +Nl4JTdsC3QKBgQCeYgozL2J/da2lUhnIXcyPstk+29kbueFYu/QBh2HwqnzqqLJ4 +5+t2H3P3plQUFp/DdDSZrvhcBiTsKiNgqThEtkKtfSCvIvBf4a2W/4TJsW6MzxCm +2KQDuK/UqM4Y+APKWN/N6Lln2VWNbNyBkWuuRVKFatccyJyJnSjxeqW7cwKBgGyN +idCYPIrwROAHLItXKvOWE5t0ABRq3TsZC2RkdA/b5HCPs4pclexcEriRjvXrK/Yt +MH94Ve8b+UftSUQ4ytjBMS6MrLg87y0YDhLwxv8NKUq65DXAUOW+8JsAmmWQOqY3 +MK+m1BT4TMklgVoN3w3sPsKIsSJ/jLz5cv/kYweFAoGAG4iWU1378tI2Ts/Fngsv +7eoWhoda77Y9D0Yoy20aN9VdMHzIYCBOubtRPEuwgaReNwbUBWap01J63yY/fF3K +8PTz6covjoOJqxQJOvM7nM0CsJawG9ccw3YXyd9KgRIdSt6ooEhb7N8W2EXYoKl3 +g1i2t41Q/SC3HUGC5mJjpO8= +-----END PRIVATE KEY----- diff --git a/venv/lib/python3.8/site-packages/tornado/test/testing_test.py b/venv/lib/python3.8/site-packages/tornado/test/testing_test.py new file mode 100644 index 0000000..37cb246 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/testing_test.py @@ -0,0 +1,353 @@ +from tornado import gen, ioloop +from tornado.httpserver import HTTPServer +from tornado.locks import Event +from tornado.testing import AsyncHTTPTestCase, AsyncTestCase, bind_unused_port, gen_test +from tornado.web import Application +import asyncio +import contextlib +import gc +import os +import platform +import traceback +import unittest +import warnings + + +@contextlib.contextmanager +def set_environ(name, value): + old_value = os.environ.get(name) + os.environ[name] = value + + try: + yield + finally: + if old_value is None: + del os.environ[name] + else: + os.environ[name] = old_value + + +class AsyncTestCaseTest(AsyncTestCase): + def test_wait_timeout(self): + time = self.io_loop.time + + # Accept default 5-second timeout, no error + self.io_loop.add_timeout(time() + 0.01, self.stop) + self.wait() + + # Timeout passed to wait() + self.io_loop.add_timeout(time() + 1, self.stop) + with self.assertRaises(self.failureException): + self.wait(timeout=0.01) + + # Timeout set with environment variable + self.io_loop.add_timeout(time() + 1, self.stop) + with set_environ("ASYNC_TEST_TIMEOUT", "0.01"): + with self.assertRaises(self.failureException): + self.wait() + + def test_subsequent_wait_calls(self): + """ + This test makes sure that a second call to wait() + clears the first timeout. + """ + # The first wait ends with time left on the clock + self.io_loop.add_timeout(self.io_loop.time() + 0.00, self.stop) + self.wait(timeout=0.1) + # The second wait has enough time for itself but would fail if the + # first wait's deadline were still in effect. + self.io_loop.add_timeout(self.io_loop.time() + 0.2, self.stop) + self.wait(timeout=0.4) + + +class LeakTest(AsyncTestCase): + def tearDown(self): + super().tearDown() + # Trigger a gc to make warnings more deterministic. + gc.collect() + + def test_leaked_coroutine(self): + # This test verifies that "leaked" coroutines are shut down + # without triggering warnings like "task was destroyed but it + # is pending". If this test were to fail, it would fail + # because runtests.py detected unexpected output to stderr. + event = Event() + + async def callback(): + try: + await event.wait() + except asyncio.CancelledError: + pass + + self.io_loop.add_callback(callback) + self.io_loop.add_callback(self.stop) + self.wait() + + +class AsyncHTTPTestCaseTest(AsyncHTTPTestCase): + def setUp(self): + super().setUp() + # Bind a second port. + sock, port = bind_unused_port() + app = Application() + server = HTTPServer(app, **self.get_httpserver_options()) + server.add_socket(sock) + self.second_port = port + self.second_server = server + + def get_app(self): + return Application() + + def test_fetch_segment(self): + path = "/path" + response = self.fetch(path) + self.assertEqual(response.request.url, self.get_url(path)) + + def test_fetch_full_http_url(self): + # Ensure that self.fetch() recognizes absolute urls and does + # not transform them into references to our main test server. + path = "http://localhost:%d/path" % self.second_port + + response = self.fetch(path) + self.assertEqual(response.request.url, path) + + def tearDown(self): + self.second_server.stop() + super().tearDown() + + +class AsyncTestCaseWrapperTest(unittest.TestCase): + def test_undecorated_generator(self): + class Test(AsyncTestCase): + def test_gen(self): + yield + + test = Test("test_gen") + result = unittest.TestResult() + test.run(result) + self.assertEqual(len(result.errors), 1) + self.assertIn("should be decorated", result.errors[0][1]) + + @unittest.skipIf( + platform.python_implementation() == "PyPy", + "pypy destructor warnings cannot be silenced", + ) + def test_undecorated_coroutine(self): + class Test(AsyncTestCase): + async def test_coro(self): + pass + + test = Test("test_coro") + result = unittest.TestResult() + + # Silence "RuntimeWarning: coroutine 'test_coro' was never awaited". + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + test.run(result) + + self.assertEqual(len(result.errors), 1) + self.assertIn("should be decorated", result.errors[0][1]) + + def test_undecorated_generator_with_skip(self): + class Test(AsyncTestCase): + @unittest.skip("don't run this") + def test_gen(self): + yield + + test = Test("test_gen") + result = unittest.TestResult() + test.run(result) + self.assertEqual(len(result.errors), 0) + self.assertEqual(len(result.skipped), 1) + + def test_other_return(self): + class Test(AsyncTestCase): + def test_other_return(self): + return 42 + + test = Test("test_other_return") + result = unittest.TestResult() + test.run(result) + self.assertEqual(len(result.errors), 1) + self.assertIn("Return value from test method ignored", result.errors[0][1]) + + +class SetUpTearDownTest(unittest.TestCase): + def test_set_up_tear_down(self): + """ + This test makes sure that AsyncTestCase calls super methods for + setUp and tearDown. + + InheritBoth is a subclass of both AsyncTestCase and + SetUpTearDown, with the ordering so that the super of + AsyncTestCase will be SetUpTearDown. + """ + events = [] + result = unittest.TestResult() + + class SetUpTearDown(unittest.TestCase): + def setUp(self): + events.append("setUp") + + def tearDown(self): + events.append("tearDown") + + class InheritBoth(AsyncTestCase, SetUpTearDown): + def test(self): + events.append("test") + + InheritBoth("test").run(result) + expected = ["setUp", "test", "tearDown"] + self.assertEqual(expected, events) + + +class AsyncHTTPTestCaseSetUpTearDownTest(unittest.TestCase): + def test_tear_down_releases_app_and_http_server(self): + result = unittest.TestResult() + + class SetUpTearDown(AsyncHTTPTestCase): + def get_app(self): + return Application() + + def test(self): + self.assertTrue(hasattr(self, "_app")) + self.assertTrue(hasattr(self, "http_server")) + + test = SetUpTearDown("test") + test.run(result) + self.assertFalse(hasattr(test, "_app")) + self.assertFalse(hasattr(test, "http_server")) + + +class GenTest(AsyncTestCase): + def setUp(self): + super().setUp() + self.finished = False + + def tearDown(self): + self.assertTrue(self.finished) + super().tearDown() + + @gen_test + def test_sync(self): + self.finished = True + + @gen_test + def test_async(self): + yield gen.moment + self.finished = True + + def test_timeout(self): + # Set a short timeout and exceed it. + @gen_test(timeout=0.1) + def test(self): + yield gen.sleep(1) + + # This can't use assertRaises because we need to inspect the + # exc_info triple (and not just the exception object) + try: + test(self) + self.fail("did not get expected exception") + except ioloop.TimeoutError: + # The stack trace should blame the add_timeout line, not just + # unrelated IOLoop/testing internals. + self.assertIn("gen.sleep(1)", traceback.format_exc()) + + self.finished = True + + def test_no_timeout(self): + # A test that does not exceed its timeout should succeed. + @gen_test(timeout=1) + def test(self): + yield gen.sleep(0.1) + + test(self) + self.finished = True + + def test_timeout_environment_variable(self): + @gen_test(timeout=0.5) + def test_long_timeout(self): + yield gen.sleep(0.25) + + # Uses provided timeout of 0.5 seconds, doesn't time out. + with set_environ("ASYNC_TEST_TIMEOUT", "0.1"): + test_long_timeout(self) + + self.finished = True + + def test_no_timeout_environment_variable(self): + @gen_test(timeout=0.01) + def test_short_timeout(self): + yield gen.sleep(1) + + # Uses environment-variable timeout of 0.1, times out. + with set_environ("ASYNC_TEST_TIMEOUT", "0.1"): + with self.assertRaises(ioloop.TimeoutError): + test_short_timeout(self) + + self.finished = True + + def test_with_method_args(self): + @gen_test + def test_with_args(self, *args): + self.assertEqual(args, ("test",)) + yield gen.moment + + test_with_args(self, "test") + self.finished = True + + def test_with_method_kwargs(self): + @gen_test + def test_with_kwargs(self, **kwargs): + self.assertDictEqual(kwargs, {"test": "test"}) + yield gen.moment + + test_with_kwargs(self, test="test") + self.finished = True + + def test_native_coroutine(self): + @gen_test + async def test(self): + self.finished = True + + test(self) + + def test_native_coroutine_timeout(self): + # Set a short timeout and exceed it. + @gen_test(timeout=0.1) + async def test(self): + await gen.sleep(1) + + try: + test(self) + self.fail("did not get expected exception") + except ioloop.TimeoutError: + self.finished = True + + +class GetNewIOLoopTest(AsyncTestCase): + def get_new_ioloop(self): + # Use the current loop instead of creating a new one here. + return ioloop.IOLoop.current() + + def setUp(self): + # This simulates the effect of an asyncio test harness like + # pytest-asyncio. + self.orig_loop = asyncio.get_event_loop() + self.new_loop = asyncio.new_event_loop() + asyncio.set_event_loop(self.new_loop) + super().setUp() + + def tearDown(self): + super().tearDown() + # AsyncTestCase must not affect the existing asyncio loop. + self.assertFalse(asyncio.get_event_loop().is_closed()) + asyncio.set_event_loop(self.orig_loop) + self.new_loop.close() + + def test_loop(self): + self.assertIs(self.io_loop.asyncio_loop, self.new_loop) # type: ignore + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/lib/python3.8/site-packages/tornado/test/twisted_test.py b/venv/lib/python3.8/site-packages/tornado/test/twisted_test.py new file mode 100644 index 0000000..661953d --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/twisted_test.py @@ -0,0 +1,247 @@ +# Author: Ovidiu Predescu +# Date: July 2011 +# +# 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. + +import asyncio +import logging +import signal +import unittest +import warnings + +from tornado.escape import utf8 +from tornado import gen +from tornado.httpclient import AsyncHTTPClient +from tornado.httpserver import HTTPServer +from tornado.ioloop import IOLoop +from tornado.testing import bind_unused_port, AsyncTestCase, gen_test +from tornado.web import RequestHandler, Application + +try: + from twisted.internet.defer import ( # type: ignore + Deferred, + inlineCallbacks, + returnValue, + ) + from twisted.internet.protocol import Protocol # type: ignore + from twisted.internet.asyncioreactor import AsyncioSelectorReactor # type: ignore + from twisted.web.client import Agent, readBody # type: ignore + from twisted.web.resource import Resource # type: ignore + from twisted.web.server import Site # type: ignore + + have_twisted = True +except ImportError: + have_twisted = False +else: + # Not used directly but needed for `yield deferred` to work. + import tornado.platform.twisted # noqa: F401 + +skipIfNoTwisted = unittest.skipUnless(have_twisted, "twisted module not present") + + +def save_signal_handlers(): + saved = {} + signals = [signal.SIGINT, signal.SIGTERM] + if hasattr(signal, "SIGCHLD"): + signals.append(signal.SIGCHLD) + for sig in signals: + saved[sig] = signal.getsignal(sig) + if "twisted" in repr(saved): + # This indicates we're not cleaning up after ourselves properly. + raise Exception("twisted signal handlers already installed") + return saved + + +def restore_signal_handlers(saved): + for sig, handler in saved.items(): + signal.signal(sig, handler) + + +# Test various combinations of twisted and tornado http servers, +# http clients, and event loop interfaces. + + +@skipIfNoTwisted +class CompatibilityTests(unittest.TestCase): + def setUp(self): + self.saved_signals = save_signal_handlers() + self.saved_policy = asyncio.get_event_loop_policy() + if hasattr(asyncio, "WindowsSelectorEventLoopPolicy"): + # Twisted requires a selector event loop, even if Tornado is + # doing its own tricks in AsyncIOLoop to support proactors. + # Setting an AddThreadSelectorEventLoop exposes various edge + # cases so just use a regular selector. + asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) # type: ignore + self.io_loop = IOLoop() + self.io_loop.make_current() + self.reactor = AsyncioSelectorReactor() + + def tearDown(self): + self.reactor.disconnectAll() + self.io_loop.clear_current() + self.io_loop.close(all_fds=True) + asyncio.set_event_loop_policy(self.saved_policy) + restore_signal_handlers(self.saved_signals) + + def start_twisted_server(self): + class HelloResource(Resource): + isLeaf = True + + def render_GET(self, request): + return b"Hello from twisted!" + + site = Site(HelloResource()) + port = self.reactor.listenTCP(0, site, interface="127.0.0.1") + self.twisted_port = port.getHost().port + + def start_tornado_server(self): + class HelloHandler(RequestHandler): + def get(self): + self.write("Hello from tornado!") + + app = Application([("/", HelloHandler)], log_function=lambda x: None) + server = HTTPServer(app) + sock, self.tornado_port = bind_unused_port() + server.add_sockets([sock]) + + def run_reactor(self): + # In theory, we can run the event loop through Tornado, + # Twisted, or asyncio interfaces. However, since we're trying + # to avoid installing anything as the global event loop, only + # the twisted interface gets everything wired up correectly + # without extra hacks. This method is a part of a + # no-longer-used generalization that allowed us to test + # different combinations. + self.stop_loop = self.reactor.stop + self.stop = self.reactor.stop + self.reactor.run() + + def tornado_fetch(self, url, runner): + client = AsyncHTTPClient() + fut = asyncio.ensure_future(client.fetch(url)) + fut.add_done_callback(lambda f: self.stop_loop()) + runner() + return fut.result() + + def twisted_fetch(self, url, runner): + # http://twistedmatrix.com/documents/current/web/howto/client.html + chunks = [] + client = Agent(self.reactor) + d = client.request(b"GET", utf8(url)) + + class Accumulator(Protocol): + def __init__(self, finished): + self.finished = finished + + def dataReceived(self, data): + chunks.append(data) + + def connectionLost(self, reason): + self.finished.callback(None) + + def callback(response): + finished = Deferred() + response.deliverBody(Accumulator(finished)) + return finished + + d.addCallback(callback) + + def shutdown(failure): + if hasattr(self, "stop_loop"): + self.stop_loop() + elif failure is not None: + # loop hasn't been initialized yet; try our best to + # get an error message out. (the runner() interaction + # should probably be refactored). + try: + failure.raiseException() + except: + logging.error("exception before starting loop", exc_info=True) + + d.addBoth(shutdown) + runner() + self.assertTrue(chunks) + return b"".join(chunks) + + def twisted_coroutine_fetch(self, url, runner): + body = [None] + + @gen.coroutine + def f(): + # This is simpler than the non-coroutine version, but it cheats + # by reading the body in one blob instead of streaming it with + # a Protocol. + client = Agent(self.reactor) + response = yield client.request(b"GET", utf8(url)) + with warnings.catch_warnings(): + # readBody has a buggy DeprecationWarning in Twisted 15.0: + # https://twistedmatrix.com/trac/changeset/43379 + warnings.simplefilter("ignore", category=DeprecationWarning) + body[0] = yield readBody(response) + self.stop_loop() + + self.io_loop.add_callback(f) + runner() + return body[0] + + def testTwistedServerTornadoClientReactor(self): + self.start_twisted_server() + response = self.tornado_fetch( + "http://127.0.0.1:%d" % self.twisted_port, self.run_reactor + ) + self.assertEqual(response.body, b"Hello from twisted!") + + def testTornadoServerTwistedClientReactor(self): + self.start_tornado_server() + response = self.twisted_fetch( + "http://127.0.0.1:%d" % self.tornado_port, self.run_reactor + ) + self.assertEqual(response, b"Hello from tornado!") + + def testTornadoServerTwistedCoroutineClientReactor(self): + self.start_tornado_server() + response = self.twisted_coroutine_fetch( + "http://127.0.0.1:%d" % self.tornado_port, self.run_reactor + ) + self.assertEqual(response, b"Hello from tornado!") + + +@skipIfNoTwisted +class ConvertDeferredTest(AsyncTestCase): + @gen_test + def test_success(self): + @inlineCallbacks + def fn(): + if False: + # inlineCallbacks doesn't work with regular functions; + # must have a yield even if it's unreachable. + yield + returnValue(42) + + res = yield fn() + self.assertEqual(res, 42) + + @gen_test + def test_failure(self): + @inlineCallbacks + def fn(): + if False: + yield + 1 / 0 + + with self.assertRaises(ZeroDivisionError): + yield fn() + + +if __name__ == "__main__": + unittest.main() diff --git a/venv/lib/python3.8/site-packages/tornado/test/util.py b/venv/lib/python3.8/site-packages/tornado/test/util.py new file mode 100644 index 0000000..bcb9bbd --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/util.py @@ -0,0 +1,114 @@ +import contextlib +import os +import platform +import socket +import sys +import textwrap +import typing # noqa: F401 +import unittest +import warnings + +from tornado.testing import bind_unused_port + +skipIfNonUnix = unittest.skipIf( + os.name != "posix" or sys.platform == "cygwin", "non-unix platform" +) + +# travis-ci.org runs our tests in an overworked virtual machine, which makes +# timing-related tests unreliable. +skipOnTravis = unittest.skipIf( + "TRAVIS" in os.environ, "timing tests unreliable on travis" +) + +# Set the environment variable NO_NETWORK=1 to disable any tests that +# depend on an external network. +skipIfNoNetwork = unittest.skipIf("NO_NETWORK" in os.environ, "network access disabled") + +skipNotCPython = unittest.skipIf( + platform.python_implementation() != "CPython", "Not CPython implementation" +) + +# Used for tests affected by +# https://bitbucket.org/pypy/pypy/issues/2616/incomplete-error-handling-in +# TODO: remove this after pypy3 5.8 is obsolete. +skipPypy3V58 = unittest.skipIf( + platform.python_implementation() == "PyPy" + and sys.version_info > (3,) + and sys.pypy_version_info < (5, 9), # type: ignore + "pypy3 5.8 has buggy ssl module", +) + + +def _detect_ipv6(): + if not socket.has_ipv6: + # socket.has_ipv6 check reports whether ipv6 was present at compile + # time. It's usually true even when ipv6 doesn't work for other reasons. + return False + sock = None + try: + sock = socket.socket(socket.AF_INET6) + sock.bind(("::1", 0)) + except socket.error: + return False + finally: + if sock is not None: + sock.close() + return True + + +skipIfNoIPv6 = unittest.skipIf(not _detect_ipv6(), "ipv6 support not present") + + +def refusing_port(): + """Returns a local port number that will refuse all connections. + + Return value is (cleanup_func, port); the cleanup function + must be called to free the port to be reused. + """ + # On travis-ci, port numbers are reassigned frequently. To avoid + # collisions with other tests, we use an open client-side socket's + # ephemeral port number to ensure that nothing can listen on that + # port. + server_socket, port = bind_unused_port() + server_socket.setblocking(True) + client_socket = socket.socket() + client_socket.connect(("127.0.0.1", port)) + conn, client_addr = server_socket.accept() + conn.close() + server_socket.close() + return (client_socket.close, client_addr[1]) + + +def exec_test(caller_globals, caller_locals, s): + """Execute ``s`` in a given context and return the result namespace. + + Used to define functions for tests in particular python + versions that would be syntax errors in older versions. + """ + # Flatten the real global and local namespace into our fake + # globals: it's all global from the perspective of code defined + # in s. + global_namespace = dict(caller_globals, **caller_locals) # type: ignore + local_namespace = {} # type: typing.Dict[str, typing.Any] + exec(textwrap.dedent(s), global_namespace, local_namespace) + return local_namespace + + +def subTest(test, *args, **kwargs): + """Compatibility shim for unittest.TestCase.subTest. + + Usage: ``with tornado.test.util.subTest(self, x=x):`` + """ + try: + subTest = test.subTest # py34+ + except AttributeError: + subTest = contextlib.contextmanager(lambda *a, **kw: (yield)) + return subTest(*args, **kwargs) + + +@contextlib.contextmanager +def ignore_deprecation(): + """Context manager to ignore deprecation warnings.""" + with warnings.catch_warnings(): + warnings.simplefilter("ignore", DeprecationWarning) + yield diff --git a/venv/lib/python3.8/site-packages/tornado/test/util_test.py b/venv/lib/python3.8/site-packages/tornado/test/util_test.py new file mode 100644 index 0000000..0cbc13c --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/util_test.py @@ -0,0 +1,308 @@ +from io import StringIO +import re +import sys +import datetime +import unittest + +import tornado.escape +from tornado.escape import utf8 +from tornado.util import ( + raise_exc_info, + Configurable, + exec_in, + ArgReplacer, + timedelta_to_seconds, + import_object, + re_unescape, + is_finalizing, +) + +import typing +from typing import cast + +if typing.TYPE_CHECKING: + from typing import Dict, Any # noqa: F401 + + +class RaiseExcInfoTest(unittest.TestCase): + def test_two_arg_exception(self): + # This test would fail on python 3 if raise_exc_info were simply + # a three-argument raise statement, because TwoArgException + # doesn't have a "copy constructor" + class TwoArgException(Exception): + def __init__(self, a, b): + super().__init__() + self.a, self.b = a, b + + try: + raise TwoArgException(1, 2) + except TwoArgException: + exc_info = sys.exc_info() + try: + raise_exc_info(exc_info) + self.fail("didn't get expected exception") + except TwoArgException as e: + self.assertIs(e, exc_info[1]) + + +class TestConfigurable(Configurable): + @classmethod + def configurable_base(cls): + return TestConfigurable + + @classmethod + def configurable_default(cls): + return TestConfig1 + + +class TestConfig1(TestConfigurable): + def initialize(self, pos_arg=None, a=None): + self.a = a + self.pos_arg = pos_arg + + +class TestConfig2(TestConfigurable): + def initialize(self, pos_arg=None, b=None): + self.b = b + self.pos_arg = pos_arg + + +class TestConfig3(TestConfigurable): + # TestConfig3 is a configuration option that is itself configurable. + @classmethod + def configurable_base(cls): + return TestConfig3 + + @classmethod + def configurable_default(cls): + return TestConfig3A + + +class TestConfig3A(TestConfig3): + def initialize(self, a=None): + self.a = a + + +class TestConfig3B(TestConfig3): + def initialize(self, b=None): + self.b = b + + +class ConfigurableTest(unittest.TestCase): + def setUp(self): + self.saved = TestConfigurable._save_configuration() + self.saved3 = TestConfig3._save_configuration() + + def tearDown(self): + TestConfigurable._restore_configuration(self.saved) + TestConfig3._restore_configuration(self.saved3) + + def checkSubclasses(self): + # no matter how the class is configured, it should always be + # possible to instantiate the subclasses directly + self.assertIsInstance(TestConfig1(), TestConfig1) + self.assertIsInstance(TestConfig2(), TestConfig2) + + obj = TestConfig1(a=1) + self.assertEqual(obj.a, 1) + obj2 = TestConfig2(b=2) + self.assertEqual(obj2.b, 2) + + def test_default(self): + # In these tests we combine a typing.cast to satisfy mypy with + # a runtime type-assertion. Without the cast, mypy would only + # let us access attributes of the base class. + obj = cast(TestConfig1, TestConfigurable()) + self.assertIsInstance(obj, TestConfig1) + self.assertIs(obj.a, None) + + obj = cast(TestConfig1, TestConfigurable(a=1)) + self.assertIsInstance(obj, TestConfig1) + self.assertEqual(obj.a, 1) + + self.checkSubclasses() + + def test_config_class(self): + TestConfigurable.configure(TestConfig2) + obj = cast(TestConfig2, TestConfigurable()) + self.assertIsInstance(obj, TestConfig2) + self.assertIs(obj.b, None) + + obj = cast(TestConfig2, TestConfigurable(b=2)) + self.assertIsInstance(obj, TestConfig2) + self.assertEqual(obj.b, 2) + + self.checkSubclasses() + + def test_config_str(self): + TestConfigurable.configure("tornado.test.util_test.TestConfig2") + obj = cast(TestConfig2, TestConfigurable()) + self.assertIsInstance(obj, TestConfig2) + self.assertIs(obj.b, None) + + obj = cast(TestConfig2, TestConfigurable(b=2)) + self.assertIsInstance(obj, TestConfig2) + self.assertEqual(obj.b, 2) + + self.checkSubclasses() + + def test_config_args(self): + TestConfigurable.configure(None, a=3) + obj = cast(TestConfig1, TestConfigurable()) + self.assertIsInstance(obj, TestConfig1) + self.assertEqual(obj.a, 3) + + obj = cast(TestConfig1, TestConfigurable(42, a=4)) + self.assertIsInstance(obj, TestConfig1) + self.assertEqual(obj.a, 4) + self.assertEqual(obj.pos_arg, 42) + + self.checkSubclasses() + # args bound in configure don't apply when using the subclass directly + obj = TestConfig1() + self.assertIs(obj.a, None) + + def test_config_class_args(self): + TestConfigurable.configure(TestConfig2, b=5) + obj = cast(TestConfig2, TestConfigurable()) + self.assertIsInstance(obj, TestConfig2) + self.assertEqual(obj.b, 5) + + obj = cast(TestConfig2, TestConfigurable(42, b=6)) + self.assertIsInstance(obj, TestConfig2) + self.assertEqual(obj.b, 6) + self.assertEqual(obj.pos_arg, 42) + + self.checkSubclasses() + # args bound in configure don't apply when using the subclass directly + obj = TestConfig2() + self.assertIs(obj.b, None) + + def test_config_multi_level(self): + TestConfigurable.configure(TestConfig3, a=1) + obj = cast(TestConfig3A, TestConfigurable()) + self.assertIsInstance(obj, TestConfig3A) + self.assertEqual(obj.a, 1) + + TestConfigurable.configure(TestConfig3) + TestConfig3.configure(TestConfig3B, b=2) + obj2 = cast(TestConfig3B, TestConfigurable()) + self.assertIsInstance(obj2, TestConfig3B) + self.assertEqual(obj2.b, 2) + + def test_config_inner_level(self): + # The inner level can be used even when the outer level + # doesn't point to it. + obj = TestConfig3() + self.assertIsInstance(obj, TestConfig3A) + + TestConfig3.configure(TestConfig3B) + obj = TestConfig3() + self.assertIsInstance(obj, TestConfig3B) + + # Configuring the base doesn't configure the inner. + obj2 = TestConfigurable() + self.assertIsInstance(obj2, TestConfig1) + TestConfigurable.configure(TestConfig2) + + obj3 = TestConfigurable() + self.assertIsInstance(obj3, TestConfig2) + + obj = TestConfig3() + self.assertIsInstance(obj, TestConfig3B) + + +class UnicodeLiteralTest(unittest.TestCase): + def test_unicode_escapes(self): + self.assertEqual(utf8(u"\u00e9"), b"\xc3\xa9") + + +class ExecInTest(unittest.TestCase): + # TODO(bdarnell): make a version of this test for one of the new + # future imports available in python 3. + @unittest.skip("no testable future imports") + def test_no_inherit_future(self): + # This file has from __future__ import print_function... + f = StringIO() + print("hello", file=f) + # ...but the template doesn't + exec_in('print >> f, "world"', dict(f=f)) + self.assertEqual(f.getvalue(), "hello\nworld\n") + + +class ArgReplacerTest(unittest.TestCase): + def setUp(self): + def function(x, y, callback=None, z=None): + pass + + self.replacer = ArgReplacer(function, "callback") + + def test_omitted(self): + args = (1, 2) + kwargs = dict() # type: Dict[str, Any] + self.assertIs(self.replacer.get_old_value(args, kwargs), None) + self.assertEqual( + self.replacer.replace("new", args, kwargs), + (None, (1, 2), dict(callback="new")), + ) + + def test_position(self): + args = (1, 2, "old", 3) + kwargs = dict() # type: Dict[str, Any] + self.assertEqual(self.replacer.get_old_value(args, kwargs), "old") + self.assertEqual( + self.replacer.replace("new", args, kwargs), + ("old", [1, 2, "new", 3], dict()), + ) + + def test_keyword(self): + args = (1,) + kwargs = dict(y=2, callback="old", z=3) + self.assertEqual(self.replacer.get_old_value(args, kwargs), "old") + self.assertEqual( + self.replacer.replace("new", args, kwargs), + ("old", (1,), dict(y=2, callback="new", z=3)), + ) + + +class TimedeltaToSecondsTest(unittest.TestCase): + def test_timedelta_to_seconds(self): + time_delta = datetime.timedelta(hours=1) + self.assertEqual(timedelta_to_seconds(time_delta), 3600.0) + + +class ImportObjectTest(unittest.TestCase): + def test_import_member(self): + self.assertIs(import_object("tornado.escape.utf8"), utf8) + + def test_import_member_unicode(self): + self.assertIs(import_object(u"tornado.escape.utf8"), utf8) + + def test_import_module(self): + self.assertIs(import_object("tornado.escape"), tornado.escape) + + def test_import_module_unicode(self): + # The internal implementation of __import__ differs depending on + # whether the thing being imported is a module or not. + # This variant requires a byte string in python 2. + self.assertIs(import_object(u"tornado.escape"), tornado.escape) + + +class ReUnescapeTest(unittest.TestCase): + def test_re_unescape(self): + test_strings = ("/favicon.ico", "index.html", "Hello, World!", "!$@#%;") + for string in test_strings: + self.assertEqual(string, re_unescape(re.escape(string))) + + def test_re_unescape_raises_error_on_invalid_input(self): + with self.assertRaises(ValueError): + re_unescape("\\d") + with self.assertRaises(ValueError): + re_unescape("\\b") + with self.assertRaises(ValueError): + re_unescape("\\Z") + + +class IsFinalizingTest(unittest.TestCase): + def test_basic(self): + self.assertFalse(is_finalizing()) diff --git a/venv/lib/python3.8/site-packages/tornado/test/web_test.py b/venv/lib/python3.8/site-packages/tornado/test/web_test.py new file mode 100644 index 0000000..5490ba2 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/web_test.py @@ -0,0 +1,3156 @@ +from tornado.concurrent import Future +from tornado import gen +from tornado.escape import ( + json_decode, + utf8, + to_unicode, + recursive_unicode, + native_str, + to_basestring, +) +from tornado.httpclient import HTTPClientError +from tornado.httputil import format_timestamp +from tornado.iostream import IOStream +from tornado import locale +from tornado.locks import Event +from tornado.log import app_log, gen_log +from tornado.simple_httpclient import SimpleAsyncHTTPClient +from tornado.template import DictLoader +from tornado.testing import AsyncHTTPTestCase, AsyncTestCase, ExpectLog, gen_test +from tornado.util import ObjectDict, unicode_type +from tornado.web import ( + Application, + RequestHandler, + StaticFileHandler, + RedirectHandler as WebRedirectHandler, + HTTPError, + MissingArgumentError, + ErrorHandler, + authenticated, + url, + _create_signature_v1, + create_signed_value, + decode_signed_value, + get_signature_key_version, + UIModule, + Finish, + stream_request_body, + removeslash, + addslash, + GZipContentEncoding, +) + +import binascii +import contextlib +import copy +import datetime +import email.utils +import gzip +from io import BytesIO +import itertools +import logging +import os +import re +import socket +import typing # noqa: F401 +import unittest +import urllib.parse + + +def relpath(*a): + return os.path.join(os.path.dirname(__file__), *a) + + +class WebTestCase(AsyncHTTPTestCase): + """Base class for web tests that also supports WSGI mode. + + Override get_handlers and get_app_kwargs instead of get_app. + This class is deprecated since WSGI mode is no longer supported. + """ + + def get_app(self): + self.app = Application(self.get_handlers(), **self.get_app_kwargs()) + return self.app + + def get_handlers(self): + raise NotImplementedError() + + def get_app_kwargs(self): + return {} + + +class SimpleHandlerTestCase(WebTestCase): + """Simplified base class for tests that work with a single handler class. + + To use, define a nested class named ``Handler``. + """ + + Handler = None + + def get_handlers(self): + return [("/", self.Handler)] + + +class HelloHandler(RequestHandler): + def get(self): + self.write("hello") + + +class CookieTestRequestHandler(RequestHandler): + # stub out enough methods to make the secure_cookie functions work + def __init__(self, cookie_secret="0123456789", key_version=None): + # don't call super.__init__ + self._cookies = {} # type: typing.Dict[str, bytes] + if key_version is None: + self.application = ObjectDict( # type: ignore + settings=dict(cookie_secret=cookie_secret) + ) + else: + self.application = ObjectDict( # type: ignore + settings=dict(cookie_secret=cookie_secret, key_version=key_version) + ) + + def get_cookie(self, name): + return self._cookies.get(name) + + def set_cookie(self, name, value, expires_days=None): + self._cookies[name] = value + + +# See SignedValueTest below for more. +class SecureCookieV1Test(unittest.TestCase): + def test_round_trip(self): + handler = CookieTestRequestHandler() + handler.set_secure_cookie("foo", b"bar", version=1) + self.assertEqual(handler.get_secure_cookie("foo", min_version=1), b"bar") + + def test_cookie_tampering_future_timestamp(self): + handler = CookieTestRequestHandler() + # this string base64-encodes to '12345678' + handler.set_secure_cookie("foo", binascii.a2b_hex(b"d76df8e7aefc"), version=1) + cookie = handler._cookies["foo"] + match = re.match(br"12345678\|([0-9]+)\|([0-9a-f]+)", cookie) + assert match is not None + timestamp = match.group(1) + sig = match.group(2) + self.assertEqual( + _create_signature_v1( + handler.application.settings["cookie_secret"], + "foo", + "12345678", + timestamp, + ), + sig, + ) + # shifting digits from payload to timestamp doesn't alter signature + # (this is not desirable behavior, just confirming that that's how it + # works) + self.assertEqual( + _create_signature_v1( + handler.application.settings["cookie_secret"], + "foo", + "1234", + b"5678" + timestamp, + ), + sig, + ) + # tamper with the cookie + handler._cookies["foo"] = utf8( + "1234|5678%s|%s" % (to_basestring(timestamp), to_basestring(sig)) + ) + # it gets rejected + with ExpectLog(gen_log, "Cookie timestamp in future"): + self.assertTrue(handler.get_secure_cookie("foo", min_version=1) is None) + + def test_arbitrary_bytes(self): + # Secure cookies accept arbitrary data (which is base64 encoded). + # Note that normal cookies accept only a subset of ascii. + handler = CookieTestRequestHandler() + handler.set_secure_cookie("foo", b"\xe9", version=1) + self.assertEqual(handler.get_secure_cookie("foo", min_version=1), b"\xe9") + + +# See SignedValueTest below for more. +class SecureCookieV2Test(unittest.TestCase): + KEY_VERSIONS = {0: "ajklasdf0ojaisdf", 1: "aslkjasaolwkjsdf"} + + def test_round_trip(self): + handler = CookieTestRequestHandler() + handler.set_secure_cookie("foo", b"bar", version=2) + self.assertEqual(handler.get_secure_cookie("foo", min_version=2), b"bar") + + def test_key_version_roundtrip(self): + handler = CookieTestRequestHandler( + cookie_secret=self.KEY_VERSIONS, key_version=0 + ) + handler.set_secure_cookie("foo", b"bar") + self.assertEqual(handler.get_secure_cookie("foo"), b"bar") + + def test_key_version_roundtrip_differing_version(self): + handler = CookieTestRequestHandler( + cookie_secret=self.KEY_VERSIONS, key_version=1 + ) + handler.set_secure_cookie("foo", b"bar") + self.assertEqual(handler.get_secure_cookie("foo"), b"bar") + + def test_key_version_increment_version(self): + handler = CookieTestRequestHandler( + cookie_secret=self.KEY_VERSIONS, key_version=0 + ) + handler.set_secure_cookie("foo", b"bar") + new_handler = CookieTestRequestHandler( + cookie_secret=self.KEY_VERSIONS, key_version=1 + ) + new_handler._cookies = handler._cookies + self.assertEqual(new_handler.get_secure_cookie("foo"), b"bar") + + def test_key_version_invalidate_version(self): + handler = CookieTestRequestHandler( + cookie_secret=self.KEY_VERSIONS, key_version=0 + ) + handler.set_secure_cookie("foo", b"bar") + new_key_versions = self.KEY_VERSIONS.copy() + new_key_versions.pop(0) + new_handler = CookieTestRequestHandler( + cookie_secret=new_key_versions, key_version=1 + ) + new_handler._cookies = handler._cookies + self.assertEqual(new_handler.get_secure_cookie("foo"), None) + + +class FinalReturnTest(WebTestCase): + final_return = None # type: Future + + def get_handlers(self): + test = self + + class FinishHandler(RequestHandler): + @gen.coroutine + def get(self): + test.final_return = self.finish() + yield test.final_return + + @gen.coroutine + def post(self): + self.write("hello,") + yield self.flush() + test.final_return = self.finish("world") + yield test.final_return + + class RenderHandler(RequestHandler): + def create_template_loader(self, path): + return DictLoader({"foo.html": "hi"}) + + @gen.coroutine + def get(self): + test.final_return = self.render("foo.html") + + return [("/finish", FinishHandler), ("/render", RenderHandler)] + + def get_app_kwargs(self): + return dict(template_path="FinalReturnTest") + + def test_finish_method_return_future(self): + response = self.fetch(self.get_url("/finish")) + self.assertEqual(response.code, 200) + self.assertIsInstance(self.final_return, Future) + self.assertTrue(self.final_return.done()) + + response = self.fetch(self.get_url("/finish"), method="POST", body=b"") + self.assertEqual(response.code, 200) + self.assertIsInstance(self.final_return, Future) + self.assertTrue(self.final_return.done()) + + def test_render_method_return_future(self): + response = self.fetch(self.get_url("/render")) + self.assertEqual(response.code, 200) + self.assertIsInstance(self.final_return, Future) + + +class CookieTest(WebTestCase): + def get_handlers(self): + class SetCookieHandler(RequestHandler): + def get(self): + # Try setting cookies with different argument types + # to ensure that everything gets encoded correctly + self.set_cookie("str", "asdf") + self.set_cookie("unicode", u"qwer") + self.set_cookie("bytes", b"zxcv") + + class GetCookieHandler(RequestHandler): + def get(self): + cookie = self.get_cookie("foo", "default") + assert cookie is not None + self.write(cookie) + + class SetCookieDomainHandler(RequestHandler): + def get(self): + # unicode domain and path arguments shouldn't break things + # either (see bug #285) + self.set_cookie("unicode_args", "blah", domain=u"foo.com", path=u"/foo") + + class SetCookieSpecialCharHandler(RequestHandler): + def get(self): + self.set_cookie("equals", "a=b") + self.set_cookie("semicolon", "a;b") + self.set_cookie("quote", 'a"b') + + class SetCookieOverwriteHandler(RequestHandler): + def get(self): + self.set_cookie("a", "b", domain="example.com") + self.set_cookie("c", "d", domain="example.com") + # A second call with the same name clobbers the first. + # Attributes from the first call are not carried over. + self.set_cookie("a", "e") + + class SetCookieMaxAgeHandler(RequestHandler): + def get(self): + self.set_cookie("foo", "bar", max_age=10) + + class SetCookieExpiresDaysHandler(RequestHandler): + def get(self): + self.set_cookie("foo", "bar", expires_days=10) + + class SetCookieFalsyFlags(RequestHandler): + def get(self): + self.set_cookie("a", "1", secure=True) + self.set_cookie("b", "1", secure=False) + self.set_cookie("c", "1", httponly=True) + self.set_cookie("d", "1", httponly=False) + + return [ + ("/set", SetCookieHandler), + ("/get", GetCookieHandler), + ("/set_domain", SetCookieDomainHandler), + ("/special_char", SetCookieSpecialCharHandler), + ("/set_overwrite", SetCookieOverwriteHandler), + ("/set_max_age", SetCookieMaxAgeHandler), + ("/set_expires_days", SetCookieExpiresDaysHandler), + ("/set_falsy_flags", SetCookieFalsyFlags), + ] + + def test_set_cookie(self): + response = self.fetch("/set") + self.assertEqual( + sorted(response.headers.get_list("Set-Cookie")), + ["bytes=zxcv; Path=/", "str=asdf; Path=/", "unicode=qwer; Path=/"], + ) + + def test_get_cookie(self): + response = self.fetch("/get", headers={"Cookie": "foo=bar"}) + self.assertEqual(response.body, b"bar") + + response = self.fetch("/get", headers={"Cookie": 'foo="bar"'}) + self.assertEqual(response.body, b"bar") + + response = self.fetch("/get", headers={"Cookie": "/=exception;"}) + self.assertEqual(response.body, b"default") + + def test_set_cookie_domain(self): + response = self.fetch("/set_domain") + self.assertEqual( + response.headers.get_list("Set-Cookie"), + ["unicode_args=blah; Domain=foo.com; Path=/foo"], + ) + + def test_cookie_special_char(self): + response = self.fetch("/special_char") + headers = sorted(response.headers.get_list("Set-Cookie")) + self.assertEqual(len(headers), 3) + self.assertEqual(headers[0], 'equals="a=b"; Path=/') + self.assertEqual(headers[1], 'quote="a\\"b"; Path=/') + # python 2.7 octal-escapes the semicolon; older versions leave it alone + self.assertTrue( + headers[2] in ('semicolon="a;b"; Path=/', 'semicolon="a\\073b"; Path=/'), + headers[2], + ) + + data = [ + ("foo=a=b", "a=b"), + ('foo="a=b"', "a=b"), + ('foo="a;b"', '"a'), # even quoted, ";" is a delimiter + ("foo=a\\073b", "a\\073b"), # escapes only decoded in quotes + ('foo="a\\073b"', "a;b"), + ('foo="a\\"b"', 'a"b'), + ] + for header, expected in data: + logging.debug("trying %r", header) + response = self.fetch("/get", headers={"Cookie": header}) + self.assertEqual(response.body, utf8(expected)) + + def test_set_cookie_overwrite(self): + response = self.fetch("/set_overwrite") + headers = response.headers.get_list("Set-Cookie") + self.assertEqual( + sorted(headers), ["a=e; Path=/", "c=d; Domain=example.com; Path=/"] + ) + + def test_set_cookie_max_age(self): + response = self.fetch("/set_max_age") + headers = response.headers.get_list("Set-Cookie") + self.assertEqual(sorted(headers), ["foo=bar; Max-Age=10; Path=/"]) + + def test_set_cookie_expires_days(self): + response = self.fetch("/set_expires_days") + header = response.headers.get("Set-Cookie") + assert header is not None + match = re.match("foo=bar; expires=(?P<expires>.+); Path=/", header) + assert match is not None + + expires = datetime.datetime.utcnow() + datetime.timedelta(days=10) + parsed = email.utils.parsedate(match.groupdict()["expires"]) + assert parsed is not None + header_expires = datetime.datetime(*parsed[:6]) + self.assertTrue(abs((expires - header_expires).total_seconds()) < 10) + + def test_set_cookie_false_flags(self): + response = self.fetch("/set_falsy_flags") + headers = sorted(response.headers.get_list("Set-Cookie")) + # The secure and httponly headers are capitalized in py35 and + # lowercase in older versions. + self.assertEqual(headers[0].lower(), "a=1; path=/; secure") + self.assertEqual(headers[1].lower(), "b=1; path=/") + self.assertEqual(headers[2].lower(), "c=1; httponly; path=/") + self.assertEqual(headers[3].lower(), "d=1; path=/") + + +class AuthRedirectRequestHandler(RequestHandler): + def initialize(self, login_url): + self.login_url = login_url + + def get_login_url(self): + return self.login_url + + @authenticated + def get(self): + # we'll never actually get here because the test doesn't follow redirects + self.send_error(500) + + +class AuthRedirectTest(WebTestCase): + def get_handlers(self): + return [ + ("/relative", AuthRedirectRequestHandler, dict(login_url="/login")), + ( + "/absolute", + AuthRedirectRequestHandler, + dict(login_url="http://example.com/login"), + ), + ] + + def test_relative_auth_redirect(self): + response = self.fetch(self.get_url("/relative"), follow_redirects=False) + self.assertEqual(response.code, 302) + self.assertEqual(response.headers["Location"], "/login?next=%2Frelative") + + def test_absolute_auth_redirect(self): + response = self.fetch(self.get_url("/absolute"), follow_redirects=False) + self.assertEqual(response.code, 302) + self.assertTrue( + re.match( + r"http://example.com/login\?next=http%3A%2F%2F127.0.0.1%3A[0-9]+%2Fabsolute", + response.headers["Location"], + ), + response.headers["Location"], + ) + + +class ConnectionCloseHandler(RequestHandler): + def initialize(self, test): + self.test = test + + @gen.coroutine + def get(self): + self.test.on_handler_waiting() + yield self.test.cleanup_event.wait() + + def on_connection_close(self): + self.test.on_connection_close() + + +class ConnectionCloseTest(WebTestCase): + def get_handlers(self): + self.cleanup_event = Event() + return [("/", ConnectionCloseHandler, dict(test=self))] + + def test_connection_close(self): + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) + s.connect(("127.0.0.1", self.get_http_port())) + self.stream = IOStream(s) + self.stream.write(b"GET / HTTP/1.0\r\n\r\n") + self.wait() + # Let the hanging coroutine clean up after itself + self.cleanup_event.set() + self.io_loop.run_sync(lambda: gen.sleep(0)) + + def on_handler_waiting(self): + logging.debug("handler waiting") + self.stream.close() + + def on_connection_close(self): + logging.debug("connection closed") + self.stop() + + +class EchoHandler(RequestHandler): + def get(self, *path_args): + # Type checks: web.py interfaces convert argument values to + # unicode strings (by default, but see also decode_argument). + # In httpserver.py (i.e. self.request.arguments), they're left + # as bytes. Keys are always native strings. + for key in self.request.arguments: + if type(key) != str: + raise Exception("incorrect type for key: %r" % type(key)) + for bvalue in self.request.arguments[key]: + if type(bvalue) != bytes: + raise Exception("incorrect type for value: %r" % type(bvalue)) + for svalue in self.get_arguments(key): + if type(svalue) != unicode_type: + raise Exception("incorrect type for value: %r" % type(svalue)) + for arg in path_args: + if type(arg) != unicode_type: + raise Exception("incorrect type for path arg: %r" % type(arg)) + self.write( + dict( + path=self.request.path, + path_args=path_args, + args=recursive_unicode(self.request.arguments), + ) + ) + + +class RequestEncodingTest(WebTestCase): + def get_handlers(self): + return [("/group/(.*)", EchoHandler), ("/slashes/([^/]*)/([^/]*)", EchoHandler)] + + def fetch_json(self, path): + return json_decode(self.fetch(path).body) + + def test_group_question_mark(self): + # Ensure that url-encoded question marks are handled properly + self.assertEqual( + self.fetch_json("/group/%3F"), + dict(path="/group/%3F", path_args=["?"], args={}), + ) + self.assertEqual( + self.fetch_json("/group/%3F?%3F=%3F"), + dict(path="/group/%3F", path_args=["?"], args={"?": ["?"]}), + ) + + def test_group_encoding(self): + # Path components and query arguments should be decoded the same way + self.assertEqual( + self.fetch_json("/group/%C3%A9?arg=%C3%A9"), + { + u"path": u"/group/%C3%A9", + u"path_args": [u"\u00e9"], + u"args": {u"arg": [u"\u00e9"]}, + }, + ) + + def test_slashes(self): + # Slashes may be escaped to appear as a single "directory" in the path, + # but they are then unescaped when passed to the get() method. + self.assertEqual( + self.fetch_json("/slashes/foo/bar"), + dict(path="/slashes/foo/bar", path_args=["foo", "bar"], args={}), + ) + self.assertEqual( + self.fetch_json("/slashes/a%2Fb/c%2Fd"), + dict(path="/slashes/a%2Fb/c%2Fd", path_args=["a/b", "c/d"], args={}), + ) + + def test_error(self): + # Percent signs (encoded as %25) should not mess up printf-style + # messages in logs + with ExpectLog(gen_log, ".*Invalid unicode"): + self.fetch("/group/?arg=%25%e9") + + +class TypeCheckHandler(RequestHandler): + def prepare(self): + self.errors = {} # type: typing.Dict[str, str] + + self.check_type("status", self.get_status(), int) + + # get_argument is an exception from the general rule of using + # type str for non-body data mainly for historical reasons. + self.check_type("argument", self.get_argument("foo"), unicode_type) + self.check_type("cookie_key", list(self.cookies.keys())[0], str) + self.check_type("cookie_value", list(self.cookies.values())[0].value, str) + + # Secure cookies return bytes because they can contain arbitrary + # data, but regular cookies are native strings. + if list(self.cookies.keys()) != ["asdf"]: + raise Exception( + "unexpected values for cookie keys: %r" % self.cookies.keys() + ) + self.check_type("get_secure_cookie", self.get_secure_cookie("asdf"), bytes) + self.check_type("get_cookie", self.get_cookie("asdf"), str) + + self.check_type("xsrf_token", self.xsrf_token, bytes) + self.check_type("xsrf_form_html", self.xsrf_form_html(), str) + + self.check_type("reverse_url", self.reverse_url("typecheck", "foo"), str) + + self.check_type("request_summary", self._request_summary(), str) + + def get(self, path_component): + # path_component uses type unicode instead of str for consistency + # with get_argument() + self.check_type("path_component", path_component, unicode_type) + self.write(self.errors) + + def post(self, path_component): + self.check_type("path_component", path_component, unicode_type) + self.write(self.errors) + + def check_type(self, name, obj, expected_type): + actual_type = type(obj) + if expected_type != actual_type: + self.errors[name] = "expected %s, got %s" % (expected_type, actual_type) + + +class DecodeArgHandler(RequestHandler): + def decode_argument(self, value, name=None): + if type(value) != bytes: + raise Exception("unexpected type for value: %r" % type(value)) + # use self.request.arguments directly to avoid recursion + if "encoding" in self.request.arguments: + return value.decode(to_unicode(self.request.arguments["encoding"][0])) + else: + return value + + def get(self, arg): + def describe(s): + if type(s) == bytes: + return ["bytes", native_str(binascii.b2a_hex(s))] + elif type(s) == unicode_type: + return ["unicode", s] + raise Exception("unknown type") + + self.write({"path": describe(arg), "query": describe(self.get_argument("foo"))}) + + +class LinkifyHandler(RequestHandler): + def get(self): + self.render("linkify.html", message="http://example.com") + + +class UIModuleResourceHandler(RequestHandler): + def get(self): + self.render("page.html", entries=[1, 2]) + + +class OptionalPathHandler(RequestHandler): + def get(self, path): + self.write({"path": path}) + + +class MultiHeaderHandler(RequestHandler): + def get(self): + self.set_header("x-overwrite", "1") + self.set_header("X-Overwrite", 2) + self.add_header("x-multi", 3) + self.add_header("X-Multi", "4") + + +class RedirectHandler(RequestHandler): + def get(self): + if self.get_argument("permanent", None) is not None: + self.redirect("/", permanent=bool(int(self.get_argument("permanent")))) + elif self.get_argument("status", None) is not None: + self.redirect("/", status=int(self.get_argument("status"))) + else: + raise Exception("didn't get permanent or status arguments") + + +class EmptyFlushCallbackHandler(RequestHandler): + @gen.coroutine + def get(self): + # Ensure that the flush callback is run whether or not there + # was any output. The gen.Task and direct yield forms are + # equivalent. + yield self.flush() # "empty" flush, but writes headers + yield self.flush() # empty flush + self.write("o") + yield self.flush() # flushes the "o" + yield self.flush() # empty flush + self.finish("k") + + +class HeaderInjectionHandler(RequestHandler): + def get(self): + try: + self.set_header("X-Foo", "foo\r\nX-Bar: baz") + raise Exception("Didn't get expected exception") + except ValueError as e: + if "Unsafe header value" in str(e): + self.finish(b"ok") + else: + raise + + +class GetArgumentHandler(RequestHandler): + def prepare(self): + if self.get_argument("source", None) == "query": + method = self.get_query_argument + elif self.get_argument("source", None) == "body": + method = self.get_body_argument + else: + method = self.get_argument # type: ignore + self.finish(method("foo", "default")) + + +class GetArgumentsHandler(RequestHandler): + def prepare(self): + self.finish( + dict( + default=self.get_arguments("foo"), + query=self.get_query_arguments("foo"), + body=self.get_body_arguments("foo"), + ) + ) + + +# This test was shared with wsgi_test.py; now the name is meaningless. +class WSGISafeWebTest(WebTestCase): + COOKIE_SECRET = "WebTest.COOKIE_SECRET" + + def get_app_kwargs(self): + loader = DictLoader( + { + "linkify.html": "{% module linkify(message) %}", + "page.html": """\ +<html><head></head><body> +{% for e in entries %} +{% module Template("entry.html", entry=e) %} +{% end %} +</body></html>""", + "entry.html": """\ +{{ set_resources(embedded_css=".entry { margin-bottom: 1em; }", + embedded_javascript="js_embed()", + css_files=["/base.css", "/foo.css"], + javascript_files="/common.js", + html_head="<meta>", + html_body='<script src="/analytics.js"/>') }} +<div class="entry">...</div>""", + } + ) + return dict( + template_loader=loader, + autoescape="xhtml_escape", + cookie_secret=self.COOKIE_SECRET, + ) + + def tearDown(self): + super().tearDown() + RequestHandler._template_loaders.clear() + + def get_handlers(self): + urls = [ + url("/typecheck/(.*)", TypeCheckHandler, name="typecheck"), + url("/decode_arg/(.*)", DecodeArgHandler, name="decode_arg"), + url("/decode_arg_kw/(?P<arg>.*)", DecodeArgHandler), + url("/linkify", LinkifyHandler), + url("/uimodule_resources", UIModuleResourceHandler), + url("/optional_path/(.+)?", OptionalPathHandler), + url("/multi_header", MultiHeaderHandler), + url("/redirect", RedirectHandler), + url( + "/web_redirect_permanent", + WebRedirectHandler, + {"url": "/web_redirect_newpath"}, + ), + url( + "/web_redirect", + WebRedirectHandler, + {"url": "/web_redirect_newpath", "permanent": False}, + ), + url( + "//web_redirect_double_slash", + WebRedirectHandler, + {"url": "/web_redirect_newpath"}, + ), + url("/header_injection", HeaderInjectionHandler), + url("/get_argument", GetArgumentHandler), + url("/get_arguments", GetArgumentsHandler), + ] + return urls + + def fetch_json(self, *args, **kwargs): + response = self.fetch(*args, **kwargs) + response.rethrow() + return json_decode(response.body) + + def test_types(self): + cookie_value = to_unicode( + create_signed_value(self.COOKIE_SECRET, "asdf", "qwer") + ) + response = self.fetch( + "/typecheck/asdf?foo=bar", headers={"Cookie": "asdf=" + cookie_value} + ) + data = json_decode(response.body) + self.assertEqual(data, {}) + + response = self.fetch( + "/typecheck/asdf?foo=bar", + method="POST", + headers={"Cookie": "asdf=" + cookie_value}, + body="foo=bar", + ) + + def test_decode_argument(self): + # These urls all decode to the same thing + urls = [ + "/decode_arg/%C3%A9?foo=%C3%A9&encoding=utf-8", + "/decode_arg/%E9?foo=%E9&encoding=latin1", + "/decode_arg_kw/%E9?foo=%E9&encoding=latin1", + ] + for req_url in urls: + response = self.fetch(req_url) + response.rethrow() + data = json_decode(response.body) + self.assertEqual( + data, + {u"path": [u"unicode", u"\u00e9"], u"query": [u"unicode", u"\u00e9"]}, + ) + + response = self.fetch("/decode_arg/%C3%A9?foo=%C3%A9") + response.rethrow() + data = json_decode(response.body) + self.assertEqual( + data, {u"path": [u"bytes", u"c3a9"], u"query": [u"bytes", u"c3a9"]} + ) + + def test_decode_argument_invalid_unicode(self): + # test that invalid unicode in URLs causes 400, not 500 + with ExpectLog(gen_log, ".*Invalid unicode.*"): + response = self.fetch("/typecheck/invalid%FF") + self.assertEqual(response.code, 400) + response = self.fetch("/typecheck/invalid?foo=%FF") + self.assertEqual(response.code, 400) + + def test_decode_argument_plus(self): + # These urls are all equivalent. + urls = [ + "/decode_arg/1%20%2B%201?foo=1%20%2B%201&encoding=utf-8", + "/decode_arg/1%20+%201?foo=1+%2B+1&encoding=utf-8", + ] + for req_url in urls: + response = self.fetch(req_url) + response.rethrow() + data = json_decode(response.body) + self.assertEqual( + data, + {u"path": [u"unicode", u"1 + 1"], u"query": [u"unicode", u"1 + 1"]}, + ) + + def test_reverse_url(self): + self.assertEqual(self.app.reverse_url("decode_arg", "foo"), "/decode_arg/foo") + self.assertEqual(self.app.reverse_url("decode_arg", 42), "/decode_arg/42") + self.assertEqual(self.app.reverse_url("decode_arg", b"\xe9"), "/decode_arg/%E9") + self.assertEqual( + self.app.reverse_url("decode_arg", u"\u00e9"), "/decode_arg/%C3%A9" + ) + self.assertEqual( + self.app.reverse_url("decode_arg", "1 + 1"), "/decode_arg/1%20%2B%201" + ) + + def test_uimodule_unescaped(self): + response = self.fetch("/linkify") + self.assertEqual( + response.body, b'<a href="http://example.com">http://example.com</a>' + ) + + def test_uimodule_resources(self): + response = self.fetch("/uimodule_resources") + self.assertEqual( + response.body, + b"""\ +<html><head><link href="/base.css" type="text/css" rel="stylesheet"/><link href="/foo.css" type="text/css" rel="stylesheet"/> +<style type="text/css"> +.entry { margin-bottom: 1em; } +</style> +<meta> +</head><body> + + +<div class="entry">...</div> + + +<div class="entry">...</div> + +<script src="/common.js" type="text/javascript"></script> +<script type="text/javascript"> +//<![CDATA[ +js_embed() +//]]> +</script> +<script src="/analytics.js"/> +</body></html>""", # noqa: E501 + ) + + def test_optional_path(self): + self.assertEqual(self.fetch_json("/optional_path/foo"), {u"path": u"foo"}) + self.assertEqual(self.fetch_json("/optional_path/"), {u"path": None}) + + def test_multi_header(self): + response = self.fetch("/multi_header") + self.assertEqual(response.headers["x-overwrite"], "2") + self.assertEqual(response.headers.get_list("x-multi"), ["3", "4"]) + + def test_redirect(self): + response = self.fetch("/redirect?permanent=1", follow_redirects=False) + self.assertEqual(response.code, 301) + response = self.fetch("/redirect?permanent=0", follow_redirects=False) + self.assertEqual(response.code, 302) + response = self.fetch("/redirect?status=307", follow_redirects=False) + self.assertEqual(response.code, 307) + + def test_web_redirect(self): + response = self.fetch("/web_redirect_permanent", follow_redirects=False) + self.assertEqual(response.code, 301) + self.assertEqual(response.headers["Location"], "/web_redirect_newpath") + response = self.fetch("/web_redirect", follow_redirects=False) + self.assertEqual(response.code, 302) + self.assertEqual(response.headers["Location"], "/web_redirect_newpath") + + def test_web_redirect_double_slash(self): + response = self.fetch("//web_redirect_double_slash", follow_redirects=False) + self.assertEqual(response.code, 301) + self.assertEqual(response.headers["Location"], "/web_redirect_newpath") + + def test_header_injection(self): + response = self.fetch("/header_injection") + self.assertEqual(response.body, b"ok") + + def test_get_argument(self): + response = self.fetch("/get_argument?foo=bar") + self.assertEqual(response.body, b"bar") + response = self.fetch("/get_argument?foo=") + self.assertEqual(response.body, b"") + response = self.fetch("/get_argument") + self.assertEqual(response.body, b"default") + + # Test merging of query and body arguments. + # In singular form, body arguments take precedence over query arguments. + body = urllib.parse.urlencode(dict(foo="hello")) + response = self.fetch("/get_argument?foo=bar", method="POST", body=body) + self.assertEqual(response.body, b"hello") + # In plural methods they are merged. + response = self.fetch("/get_arguments?foo=bar", method="POST", body=body) + self.assertEqual( + json_decode(response.body), + dict(default=["bar", "hello"], query=["bar"], body=["hello"]), + ) + + def test_get_query_arguments(self): + # send as a post so we can ensure the separation between query + # string and body arguments. + body = urllib.parse.urlencode(dict(foo="hello")) + response = self.fetch( + "/get_argument?source=query&foo=bar", method="POST", body=body + ) + self.assertEqual(response.body, b"bar") + response = self.fetch( + "/get_argument?source=query&foo=", method="POST", body=body + ) + self.assertEqual(response.body, b"") + response = self.fetch("/get_argument?source=query", method="POST", body=body) + self.assertEqual(response.body, b"default") + + def test_get_body_arguments(self): + body = urllib.parse.urlencode(dict(foo="bar")) + response = self.fetch( + "/get_argument?source=body&foo=hello", method="POST", body=body + ) + self.assertEqual(response.body, b"bar") + + body = urllib.parse.urlencode(dict(foo="")) + response = self.fetch( + "/get_argument?source=body&foo=hello", method="POST", body=body + ) + self.assertEqual(response.body, b"") + + body = urllib.parse.urlencode(dict()) + response = self.fetch( + "/get_argument?source=body&foo=hello", method="POST", body=body + ) + self.assertEqual(response.body, b"default") + + def test_no_gzip(self): + response = self.fetch("/get_argument") + self.assertNotIn("Accept-Encoding", response.headers.get("Vary", "")) + self.assertNotIn("gzip", response.headers.get("Content-Encoding", "")) + + +class NonWSGIWebTests(WebTestCase): + def get_handlers(self): + return [("/empty_flush", EmptyFlushCallbackHandler)] + + def test_empty_flush(self): + response = self.fetch("/empty_flush") + self.assertEqual(response.body, b"ok") + + +class ErrorResponseTest(WebTestCase): + def get_handlers(self): + class DefaultHandler(RequestHandler): + def get(self): + if self.get_argument("status", None): + raise HTTPError(int(self.get_argument("status"))) + 1 / 0 + + class WriteErrorHandler(RequestHandler): + def get(self): + if self.get_argument("status", None): + self.send_error(int(self.get_argument("status"))) + else: + 1 / 0 + + def write_error(self, status_code, **kwargs): + self.set_header("Content-Type", "text/plain") + if "exc_info" in kwargs: + self.write("Exception: %s" % kwargs["exc_info"][0].__name__) + else: + self.write("Status: %d" % status_code) + + class FailedWriteErrorHandler(RequestHandler): + def get(self): + 1 / 0 + + def write_error(self, status_code, **kwargs): + raise Exception("exception in write_error") + + return [ + url("/default", DefaultHandler), + url("/write_error", WriteErrorHandler), + url("/failed_write_error", FailedWriteErrorHandler), + ] + + def test_default(self): + with ExpectLog(app_log, "Uncaught exception"): + response = self.fetch("/default") + self.assertEqual(response.code, 500) + self.assertTrue(b"500: Internal Server Error" in response.body) + + response = self.fetch("/default?status=503") + self.assertEqual(response.code, 503) + self.assertTrue(b"503: Service Unavailable" in response.body) + + response = self.fetch("/default?status=435") + self.assertEqual(response.code, 435) + self.assertTrue(b"435: Unknown" in response.body) + + def test_write_error(self): + with ExpectLog(app_log, "Uncaught exception"): + response = self.fetch("/write_error") + self.assertEqual(response.code, 500) + self.assertEqual(b"Exception: ZeroDivisionError", response.body) + + response = self.fetch("/write_error?status=503") + self.assertEqual(response.code, 503) + self.assertEqual(b"Status: 503", response.body) + + def test_failed_write_error(self): + with ExpectLog(app_log, "Uncaught exception"): + response = self.fetch("/failed_write_error") + self.assertEqual(response.code, 500) + self.assertEqual(b"", response.body) + + +class StaticFileTest(WebTestCase): + # The expected SHA-512 hash of robots.txt, used in tests that call + # StaticFileHandler.get_version + robots_txt_hash = ( + b"63a36e950e134b5217e33c763e88840c10a07d80e6057d92b9ac97508de7fb1f" + b"a6f0e9b7531e169657165ea764e8963399cb6d921ffe6078425aaafe54c04563" + ) + static_dir = os.path.join(os.path.dirname(__file__), "static") + + def get_handlers(self): + class StaticUrlHandler(RequestHandler): + def get(self, path): + with_v = int(self.get_argument("include_version", "1")) + self.write(self.static_url(path, include_version=with_v)) + + class AbsoluteStaticUrlHandler(StaticUrlHandler): + include_host = True + + class OverrideStaticUrlHandler(RequestHandler): + def get(self, path): + do_include = bool(self.get_argument("include_host")) + self.include_host = not do_include + + regular_url = self.static_url(path) + override_url = self.static_url(path, include_host=do_include) + if override_url == regular_url: + return self.write(str(False)) + + protocol = self.request.protocol + "://" + protocol_length = len(protocol) + check_regular = regular_url.find(protocol, 0, protocol_length) + check_override = override_url.find(protocol, 0, protocol_length) + + if do_include: + result = check_override == 0 and check_regular == -1 + else: + result = check_override == -1 and check_regular == 0 + self.write(str(result)) + + return [ + ("/static_url/(.*)", StaticUrlHandler), + ("/abs_static_url/(.*)", AbsoluteStaticUrlHandler), + ("/override_static_url/(.*)", OverrideStaticUrlHandler), + ("/root_static/(.*)", StaticFileHandler, dict(path="/")), + ] + + def get_app_kwargs(self): + return dict(static_path=relpath("static")) + + def test_static_files(self): + response = self.fetch("/robots.txt") + self.assertTrue(b"Disallow: /" in response.body) + + response = self.fetch("/static/robots.txt") + self.assertTrue(b"Disallow: /" in response.body) + self.assertEqual(response.headers.get("Content-Type"), "text/plain") + + def test_static_compressed_files(self): + response = self.fetch("/static/sample.xml.gz") + self.assertEqual(response.headers.get("Content-Type"), "application/gzip") + response = self.fetch("/static/sample.xml.bz2") + self.assertEqual( + response.headers.get("Content-Type"), "application/octet-stream" + ) + # make sure the uncompressed file still has the correct type + response = self.fetch("/static/sample.xml") + self.assertTrue( + response.headers.get("Content-Type") in set(("text/xml", "application/xml")) + ) + + def test_static_url(self): + response = self.fetch("/static_url/robots.txt") + self.assertEqual(response.body, b"/static/robots.txt?v=" + self.robots_txt_hash) + + def test_absolute_static_url(self): + response = self.fetch("/abs_static_url/robots.txt") + self.assertEqual( + response.body, + (utf8(self.get_url("/")) + b"static/robots.txt?v=" + self.robots_txt_hash), + ) + + def test_relative_version_exclusion(self): + response = self.fetch("/static_url/robots.txt?include_version=0") + self.assertEqual(response.body, b"/static/robots.txt") + + def test_absolute_version_exclusion(self): + response = self.fetch("/abs_static_url/robots.txt?include_version=0") + self.assertEqual(response.body, utf8(self.get_url("/") + "static/robots.txt")) + + def test_include_host_override(self): + self._trigger_include_host_check(False) + self._trigger_include_host_check(True) + + def _trigger_include_host_check(self, include_host): + path = "/override_static_url/robots.txt?include_host=%s" + response = self.fetch(path % int(include_host)) + self.assertEqual(response.body, utf8(str(True))) + + def get_and_head(self, *args, **kwargs): + """Performs a GET and HEAD request and returns the GET response. + + Fails if any ``Content-*`` headers returned by the two requests + differ. + """ + head_response = self.fetch(*args, method="HEAD", **kwargs) + get_response = self.fetch(*args, method="GET", **kwargs) + content_headers = set() + for h in itertools.chain(head_response.headers, get_response.headers): + if h.startswith("Content-"): + content_headers.add(h) + for h in content_headers: + self.assertEqual( + head_response.headers.get(h), + get_response.headers.get(h), + "%s differs between GET (%s) and HEAD (%s)" + % (h, head_response.headers.get(h), get_response.headers.get(h)), + ) + return get_response + + def test_static_304_if_modified_since(self): + response1 = self.get_and_head("/static/robots.txt") + response2 = self.get_and_head( + "/static/robots.txt", + headers={"If-Modified-Since": response1.headers["Last-Modified"]}, + ) + self.assertEqual(response2.code, 304) + self.assertTrue("Content-Length" not in response2.headers) + + def test_static_304_if_none_match(self): + response1 = self.get_and_head("/static/robots.txt") + response2 = self.get_and_head( + "/static/robots.txt", headers={"If-None-Match": response1.headers["Etag"]} + ) + self.assertEqual(response2.code, 304) + + def test_static_304_etag_modified_bug(self): + response1 = self.get_and_head("/static/robots.txt") + response2 = self.get_and_head( + "/static/robots.txt", + headers={ + "If-None-Match": '"MISMATCH"', + "If-Modified-Since": response1.headers["Last-Modified"], + }, + ) + self.assertEqual(response2.code, 200) + + def test_static_if_modified_since_pre_epoch(self): + # On windows, the functions that work with time_t do not accept + # negative values, and at least one client (processing.js) seems + # to use if-modified-since 1/1/1960 as a cache-busting technique. + response = self.get_and_head( + "/static/robots.txt", + headers={"If-Modified-Since": "Fri, 01 Jan 1960 00:00:00 GMT"}, + ) + self.assertEqual(response.code, 200) + + def test_static_if_modified_since_time_zone(self): + # Instead of the value from Last-Modified, make requests with times + # chosen just before and after the known modification time + # of the file to ensure that the right time zone is being used + # when parsing If-Modified-Since. + stat = os.stat(relpath("static/robots.txt")) + + response = self.get_and_head( + "/static/robots.txt", + headers={"If-Modified-Since": format_timestamp(stat.st_mtime - 1)}, + ) + self.assertEqual(response.code, 200) + response = self.get_and_head( + "/static/robots.txt", + headers={"If-Modified-Since": format_timestamp(stat.st_mtime + 1)}, + ) + self.assertEqual(response.code, 304) + + def test_static_etag(self): + response = self.get_and_head("/static/robots.txt") + self.assertEqual( + utf8(response.headers.get("Etag")), b'"' + self.robots_txt_hash + b'"' + ) + + def test_static_with_range(self): + response = self.get_and_head( + "/static/robots.txt", headers={"Range": "bytes=0-9"} + ) + self.assertEqual(response.code, 206) + self.assertEqual(response.body, b"User-agent") + self.assertEqual( + utf8(response.headers.get("Etag")), b'"' + self.robots_txt_hash + b'"' + ) + self.assertEqual(response.headers.get("Content-Length"), "10") + self.assertEqual(response.headers.get("Content-Range"), "bytes 0-9/26") + + def test_static_with_range_full_file(self): + response = self.get_and_head( + "/static/robots.txt", headers={"Range": "bytes=0-"} + ) + # Note: Chrome refuses to play audio if it gets an HTTP 206 in response + # to ``Range: bytes=0-`` :( + self.assertEqual(response.code, 200) + robots_file_path = os.path.join(self.static_dir, "robots.txt") + with open(robots_file_path) as f: + self.assertEqual(response.body, utf8(f.read())) + self.assertEqual(response.headers.get("Content-Length"), "26") + self.assertEqual(response.headers.get("Content-Range"), None) + + def test_static_with_range_full_past_end(self): + response = self.get_and_head( + "/static/robots.txt", headers={"Range": "bytes=0-10000000"} + ) + self.assertEqual(response.code, 200) + robots_file_path = os.path.join(self.static_dir, "robots.txt") + with open(robots_file_path) as f: + self.assertEqual(response.body, utf8(f.read())) + self.assertEqual(response.headers.get("Content-Length"), "26") + self.assertEqual(response.headers.get("Content-Range"), None) + + def test_static_with_range_partial_past_end(self): + response = self.get_and_head( + "/static/robots.txt", headers={"Range": "bytes=1-10000000"} + ) + self.assertEqual(response.code, 206) + robots_file_path = os.path.join(self.static_dir, "robots.txt") + with open(robots_file_path) as f: + self.assertEqual(response.body, utf8(f.read()[1:])) + self.assertEqual(response.headers.get("Content-Length"), "25") + self.assertEqual(response.headers.get("Content-Range"), "bytes 1-25/26") + + def test_static_with_range_end_edge(self): + response = self.get_and_head( + "/static/robots.txt", headers={"Range": "bytes=22-"} + ) + self.assertEqual(response.body, b": /\n") + self.assertEqual(response.headers.get("Content-Length"), "4") + self.assertEqual(response.headers.get("Content-Range"), "bytes 22-25/26") + + def test_static_with_range_neg_end(self): + response = self.get_and_head( + "/static/robots.txt", headers={"Range": "bytes=-4"} + ) + self.assertEqual(response.body, b": /\n") + self.assertEqual(response.headers.get("Content-Length"), "4") + self.assertEqual(response.headers.get("Content-Range"), "bytes 22-25/26") + + def test_static_with_range_neg_past_start(self): + response = self.get_and_head( + "/static/robots.txt", headers={"Range": "bytes=-1000000"} + ) + self.assertEqual(response.code, 200) + robots_file_path = os.path.join(self.static_dir, "robots.txt") + with open(robots_file_path) as f: + self.assertEqual(response.body, utf8(f.read())) + self.assertEqual(response.headers.get("Content-Length"), "26") + self.assertEqual(response.headers.get("Content-Range"), None) + + def test_static_invalid_range(self): + response = self.get_and_head("/static/robots.txt", headers={"Range": "asdf"}) + self.assertEqual(response.code, 200) + + def test_static_unsatisfiable_range_zero_suffix(self): + response = self.get_and_head( + "/static/robots.txt", headers={"Range": "bytes=-0"} + ) + self.assertEqual(response.headers.get("Content-Range"), "bytes */26") + self.assertEqual(response.code, 416) + + def test_static_unsatisfiable_range_invalid_start(self): + response = self.get_and_head( + "/static/robots.txt", headers={"Range": "bytes=26"} + ) + self.assertEqual(response.code, 416) + self.assertEqual(response.headers.get("Content-Range"), "bytes */26") + + def test_static_unsatisfiable_range_end_less_than_start(self): + response = self.get_and_head( + "/static/robots.txt", headers={"Range": "bytes=10-3"} + ) + self.assertEqual(response.code, 416) + self.assertEqual(response.headers.get("Content-Range"), "bytes */26") + + def test_static_head(self): + response = self.fetch("/static/robots.txt", method="HEAD") + self.assertEqual(response.code, 200) + # No body was returned, but we did get the right content length. + self.assertEqual(response.body, b"") + self.assertEqual(response.headers["Content-Length"], "26") + self.assertEqual( + utf8(response.headers["Etag"]), b'"' + self.robots_txt_hash + b'"' + ) + + def test_static_head_range(self): + response = self.fetch( + "/static/robots.txt", method="HEAD", headers={"Range": "bytes=1-4"} + ) + self.assertEqual(response.code, 206) + self.assertEqual(response.body, b"") + self.assertEqual(response.headers["Content-Length"], "4") + self.assertEqual( + utf8(response.headers["Etag"]), b'"' + self.robots_txt_hash + b'"' + ) + + def test_static_range_if_none_match(self): + response = self.get_and_head( + "/static/robots.txt", + headers={ + "Range": "bytes=1-4", + "If-None-Match": b'"' + self.robots_txt_hash + b'"', + }, + ) + self.assertEqual(response.code, 304) + self.assertEqual(response.body, b"") + self.assertTrue("Content-Length" not in response.headers) + self.assertEqual( + utf8(response.headers["Etag"]), b'"' + self.robots_txt_hash + b'"' + ) + + def test_static_404(self): + response = self.get_and_head("/static/blarg") + self.assertEqual(response.code, 404) + + def test_path_traversal_protection(self): + # curl_httpclient processes ".." on the client side, so we + # must test this with simple_httpclient. + self.http_client.close() + self.http_client = SimpleAsyncHTTPClient() + with ExpectLog(gen_log, ".*not in root static directory"): + response = self.get_and_head("/static/../static_foo.txt") + # Attempted path traversal should result in 403, not 200 + # (which means the check failed and the file was served) + # or 404 (which means that the file didn't exist and + # is probably a packaging error). + self.assertEqual(response.code, 403) + + @unittest.skipIf(os.name != "posix", "non-posix OS") + def test_root_static_path(self): + # Sometimes people set the StaticFileHandler's path to '/' + # to disable Tornado's path validation (in conjunction with + # their own validation in get_absolute_path). Make sure + # that the stricter validation in 4.2.1 doesn't break them. + path = os.path.join( + os.path.dirname(os.path.abspath(__file__)), "static/robots.txt" + ) + response = self.get_and_head("/root_static" + urllib.parse.quote(path)) + self.assertEqual(response.code, 200) + + +class StaticDefaultFilenameTest(WebTestCase): + def get_app_kwargs(self): + return dict( + static_path=relpath("static"), + static_handler_args=dict(default_filename="index.html"), + ) + + def get_handlers(self): + return [] + + def test_static_default_filename(self): + response = self.fetch("/static/dir/", follow_redirects=False) + self.assertEqual(response.code, 200) + self.assertEqual(b"this is the index\n", response.body) + + def test_static_default_redirect(self): + response = self.fetch("/static/dir", follow_redirects=False) + self.assertEqual(response.code, 301) + self.assertTrue(response.headers["Location"].endswith("/static/dir/")) + + +class StaticFileWithPathTest(WebTestCase): + def get_app_kwargs(self): + return dict( + static_path=relpath("static"), + static_handler_args=dict(default_filename="index.html"), + ) + + def get_handlers(self): + return [("/foo/(.*)", StaticFileHandler, {"path": relpath("templates/")})] + + def test_serve(self): + response = self.fetch("/foo/utf8.html") + self.assertEqual(response.body, b"H\xc3\xa9llo\n") + + +class CustomStaticFileTest(WebTestCase): + def get_handlers(self): + class MyStaticFileHandler(StaticFileHandler): + @classmethod + def make_static_url(cls, settings, path): + version_hash = cls.get_version(settings, path) + extension_index = path.rindex(".") + before_version = path[:extension_index] + after_version = path[(extension_index + 1) :] + return "/static/%s.%s.%s" % ( + before_version, + version_hash, + after_version, + ) + + def parse_url_path(self, url_path): + extension_index = url_path.rindex(".") + version_index = url_path.rindex(".", 0, extension_index) + return "%s%s" % (url_path[:version_index], url_path[extension_index:]) + + @classmethod + def get_absolute_path(cls, settings, path): + return "CustomStaticFileTest:" + path + + def validate_absolute_path(self, root, absolute_path): + return absolute_path + + @classmethod + def get_content(self, path, start=None, end=None): + assert start is None and end is None + if path == "CustomStaticFileTest:foo.txt": + return b"bar" + raise Exception("unexpected path %r" % path) + + def get_content_size(self): + if self.absolute_path == "CustomStaticFileTest:foo.txt": + return 3 + raise Exception("unexpected path %r" % self.absolute_path) + + def get_modified_time(self): + return None + + @classmethod + def get_version(cls, settings, path): + return "42" + + class StaticUrlHandler(RequestHandler): + def get(self, path): + self.write(self.static_url(path)) + + self.static_handler_class = MyStaticFileHandler + + return [("/static_url/(.*)", StaticUrlHandler)] + + def get_app_kwargs(self): + return dict(static_path="dummy", static_handler_class=self.static_handler_class) + + def test_serve(self): + response = self.fetch("/static/foo.42.txt") + self.assertEqual(response.body, b"bar") + + def test_static_url(self): + with ExpectLog(gen_log, "Could not open static file", required=False): + response = self.fetch("/static_url/foo.txt") + self.assertEqual(response.body, b"/static/foo.42.txt") + + +class HostMatchingTest(WebTestCase): + class Handler(RequestHandler): + def initialize(self, reply): + self.reply = reply + + def get(self): + self.write(self.reply) + + def get_handlers(self): + return [("/foo", HostMatchingTest.Handler, {"reply": "wildcard"})] + + def test_host_matching(self): + self.app.add_handlers( + "www.example.com", [("/foo", HostMatchingTest.Handler, {"reply": "[0]"})] + ) + self.app.add_handlers( + r"www\.example\.com", [("/bar", HostMatchingTest.Handler, {"reply": "[1]"})] + ) + self.app.add_handlers( + "www.example.com", [("/baz", HostMatchingTest.Handler, {"reply": "[2]"})] + ) + self.app.add_handlers( + "www.e.*e.com", [("/baz", HostMatchingTest.Handler, {"reply": "[3]"})] + ) + + response = self.fetch("/foo") + self.assertEqual(response.body, b"wildcard") + response = self.fetch("/bar") + self.assertEqual(response.code, 404) + response = self.fetch("/baz") + self.assertEqual(response.code, 404) + + response = self.fetch("/foo", headers={"Host": "www.example.com"}) + self.assertEqual(response.body, b"[0]") + response = self.fetch("/bar", headers={"Host": "www.example.com"}) + self.assertEqual(response.body, b"[1]") + response = self.fetch("/baz", headers={"Host": "www.example.com"}) + self.assertEqual(response.body, b"[2]") + response = self.fetch("/baz", headers={"Host": "www.exe.com"}) + self.assertEqual(response.body, b"[3]") + + +class DefaultHostMatchingTest(WebTestCase): + def get_handlers(self): + return [] + + def get_app_kwargs(self): + return {"default_host": "www.example.com"} + + def test_default_host_matching(self): + self.app.add_handlers( + "www.example.com", [("/foo", HostMatchingTest.Handler, {"reply": "[0]"})] + ) + self.app.add_handlers( + r"www\.example\.com", [("/bar", HostMatchingTest.Handler, {"reply": "[1]"})] + ) + self.app.add_handlers( + "www.test.com", [("/baz", HostMatchingTest.Handler, {"reply": "[2]"})] + ) + + response = self.fetch("/foo") + self.assertEqual(response.body, b"[0]") + response = self.fetch("/bar") + self.assertEqual(response.body, b"[1]") + response = self.fetch("/baz") + self.assertEqual(response.code, 404) + + response = self.fetch("/foo", headers={"X-Real-Ip": "127.0.0.1"}) + self.assertEqual(response.code, 404) + + self.app.default_host = "www.test.com" + + response = self.fetch("/baz") + self.assertEqual(response.body, b"[2]") + + +class NamedURLSpecGroupsTest(WebTestCase): + def get_handlers(self): + class EchoHandler(RequestHandler): + def get(self, path): + self.write(path) + + return [ + ("/str/(?P<path>.*)", EchoHandler), + (u"/unicode/(?P<path>.*)", EchoHandler), + ] + + def test_named_urlspec_groups(self): + response = self.fetch("/str/foo") + self.assertEqual(response.body, b"foo") + + response = self.fetch("/unicode/bar") + self.assertEqual(response.body, b"bar") + + +class ClearHeaderTest(SimpleHandlerTestCase): + class Handler(RequestHandler): + def get(self): + self.set_header("h1", "foo") + self.set_header("h2", "bar") + self.clear_header("h1") + self.clear_header("nonexistent") + + def test_clear_header(self): + response = self.fetch("/") + self.assertTrue("h1" not in response.headers) + self.assertEqual(response.headers["h2"], "bar") + + +class Header204Test(SimpleHandlerTestCase): + class Handler(RequestHandler): + def get(self): + self.set_status(204) + self.finish() + + def test_204_headers(self): + response = self.fetch("/") + self.assertEqual(response.code, 204) + self.assertNotIn("Content-Length", response.headers) + self.assertNotIn("Transfer-Encoding", response.headers) + + +class Header304Test(SimpleHandlerTestCase): + class Handler(RequestHandler): + def get(self): + self.set_header("Content-Language", "en_US") + self.write("hello") + + def test_304_headers(self): + response1 = self.fetch("/") + self.assertEqual(response1.headers["Content-Length"], "5") + self.assertEqual(response1.headers["Content-Language"], "en_US") + + response2 = self.fetch( + "/", headers={"If-None-Match": response1.headers["Etag"]} + ) + self.assertEqual(response2.code, 304) + self.assertTrue("Content-Length" not in response2.headers) + self.assertTrue("Content-Language" not in response2.headers) + # Not an entity header, but should not be added to 304s by chunking + self.assertTrue("Transfer-Encoding" not in response2.headers) + + +class StatusReasonTest(SimpleHandlerTestCase): + class Handler(RequestHandler): + def get(self): + reason = self.request.arguments.get("reason", []) + self.set_status( + int(self.get_argument("code")), + reason=to_unicode(reason[0]) if reason else None, + ) + + def get_http_client(self): + # simple_httpclient only: curl doesn't expose the reason string + return SimpleAsyncHTTPClient() + + def test_status(self): + response = self.fetch("/?code=304") + self.assertEqual(response.code, 304) + self.assertEqual(response.reason, "Not Modified") + response = self.fetch("/?code=304&reason=Foo") + self.assertEqual(response.code, 304) + self.assertEqual(response.reason, "Foo") + response = self.fetch("/?code=682&reason=Bar") + self.assertEqual(response.code, 682) + self.assertEqual(response.reason, "Bar") + response = self.fetch("/?code=682") + self.assertEqual(response.code, 682) + self.assertEqual(response.reason, "Unknown") + + +class DateHeaderTest(SimpleHandlerTestCase): + class Handler(RequestHandler): + def get(self): + self.write("hello") + + def test_date_header(self): + response = self.fetch("/") + parsed = email.utils.parsedate(response.headers["Date"]) + assert parsed is not None + header_date = datetime.datetime(*parsed[:6]) + self.assertTrue( + header_date - datetime.datetime.utcnow() < datetime.timedelta(seconds=2) + ) + + +class RaiseWithReasonTest(SimpleHandlerTestCase): + class Handler(RequestHandler): + def get(self): + raise HTTPError(682, reason="Foo") + + def get_http_client(self): + # simple_httpclient only: curl doesn't expose the reason string + return SimpleAsyncHTTPClient() + + def test_raise_with_reason(self): + response = self.fetch("/") + self.assertEqual(response.code, 682) + self.assertEqual(response.reason, "Foo") + self.assertIn(b"682: Foo", response.body) + + def test_httperror_str(self): + self.assertEqual(str(HTTPError(682, reason="Foo")), "HTTP 682: Foo") + + def test_httperror_str_from_httputil(self): + self.assertEqual(str(HTTPError(682)), "HTTP 682: Unknown") + + +class ErrorHandlerXSRFTest(WebTestCase): + def get_handlers(self): + # note that if the handlers list is empty we get the default_host + # redirect fallback instead of a 404, so test with both an + # explicitly defined error handler and an implicit 404. + return [("/error", ErrorHandler, dict(status_code=417))] + + def get_app_kwargs(self): + return dict(xsrf_cookies=True) + + def test_error_xsrf(self): + response = self.fetch("/error", method="POST", body="") + self.assertEqual(response.code, 417) + + def test_404_xsrf(self): + response = self.fetch("/404", method="POST", body="") + self.assertEqual(response.code, 404) + + +class GzipTestCase(SimpleHandlerTestCase): + class Handler(RequestHandler): + def get(self): + for v in self.get_arguments("vary"): + self.add_header("Vary", v) + # Must write at least MIN_LENGTH bytes to activate compression. + self.write("hello world" + ("!" * GZipContentEncoding.MIN_LENGTH)) + + def get_app_kwargs(self): + return dict( + gzip=True, static_path=os.path.join(os.path.dirname(__file__), "static") + ) + + def assert_compressed(self, response): + # simple_httpclient renames the content-encoding header; + # curl_httpclient doesn't. + self.assertEqual( + response.headers.get( + "Content-Encoding", response.headers.get("X-Consumed-Content-Encoding") + ), + "gzip", + ) + + def test_gzip(self): + response = self.fetch("/") + self.assert_compressed(response) + self.assertEqual(response.headers["Vary"], "Accept-Encoding") + + def test_gzip_static(self): + # The streaming responses in StaticFileHandler have subtle + # interactions with the gzip output so test this case separately. + response = self.fetch("/robots.txt") + self.assert_compressed(response) + self.assertEqual(response.headers["Vary"], "Accept-Encoding") + + def test_gzip_not_requested(self): + response = self.fetch("/", use_gzip=False) + self.assertNotIn("Content-Encoding", response.headers) + self.assertEqual(response.headers["Vary"], "Accept-Encoding") + + def test_vary_already_present(self): + response = self.fetch("/?vary=Accept-Language") + self.assert_compressed(response) + self.assertEqual( + [s.strip() for s in response.headers["Vary"].split(",")], + ["Accept-Language", "Accept-Encoding"], + ) + + def test_vary_already_present_multiple(self): + # Regression test for https://github.com/tornadoweb/tornado/issues/1670 + response = self.fetch("/?vary=Accept-Language&vary=Cookie") + self.assert_compressed(response) + self.assertEqual( + [s.strip() for s in response.headers["Vary"].split(",")], + ["Accept-Language", "Cookie", "Accept-Encoding"], + ) + + +class PathArgsInPrepareTest(WebTestCase): + class Handler(RequestHandler): + def prepare(self): + self.write(dict(args=self.path_args, kwargs=self.path_kwargs)) + + def get(self, path): + assert path == "foo" + self.finish() + + def get_handlers(self): + return [("/pos/(.*)", self.Handler), ("/kw/(?P<path>.*)", self.Handler)] + + def test_pos(self): + response = self.fetch("/pos/foo") + response.rethrow() + data = json_decode(response.body) + self.assertEqual(data, {"args": ["foo"], "kwargs": {}}) + + def test_kw(self): + response = self.fetch("/kw/foo") + response.rethrow() + data = json_decode(response.body) + self.assertEqual(data, {"args": [], "kwargs": {"path": "foo"}}) + + +class ClearAllCookiesTest(SimpleHandlerTestCase): + class Handler(RequestHandler): + def get(self): + self.clear_all_cookies() + self.write("ok") + + def test_clear_all_cookies(self): + response = self.fetch("/", headers={"Cookie": "foo=bar; baz=xyzzy"}) + set_cookies = sorted(response.headers.get_list("Set-Cookie")) + # Python 3.5 sends 'baz="";'; older versions use 'baz=;' + self.assertTrue( + set_cookies[0].startswith("baz=;") or set_cookies[0].startswith('baz="";') + ) + self.assertTrue( + set_cookies[1].startswith("foo=;") or set_cookies[1].startswith('foo="";') + ) + + +class PermissionError(Exception): + pass + + +class ExceptionHandlerTest(SimpleHandlerTestCase): + class Handler(RequestHandler): + def get(self): + exc = self.get_argument("exc") + if exc == "http": + raise HTTPError(410, "no longer here") + elif exc == "zero": + 1 / 0 + elif exc == "permission": + raise PermissionError("not allowed") + + def write_error(self, status_code, **kwargs): + if "exc_info" in kwargs: + typ, value, tb = kwargs["exc_info"] + if isinstance(value, PermissionError): + self.set_status(403) + self.write("PermissionError") + return + RequestHandler.write_error(self, status_code, **kwargs) + + def log_exception(self, typ, value, tb): + if isinstance(value, PermissionError): + app_log.warning("custom logging for PermissionError: %s", value.args[0]) + else: + RequestHandler.log_exception(self, typ, value, tb) + + def test_http_error(self): + # HTTPErrors are logged as warnings with no stack trace. + # TODO: extend ExpectLog to test this more precisely + with ExpectLog(gen_log, ".*no longer here"): + response = self.fetch("/?exc=http") + self.assertEqual(response.code, 410) + + def test_unknown_error(self): + # Unknown errors are logged as errors with a stack trace. + with ExpectLog(app_log, "Uncaught exception"): + response = self.fetch("/?exc=zero") + self.assertEqual(response.code, 500) + + def test_known_error(self): + # log_exception can override logging behavior, and write_error + # can override the response. + with ExpectLog(app_log, "custom logging for PermissionError: not allowed"): + response = self.fetch("/?exc=permission") + self.assertEqual(response.code, 403) + + +class BuggyLoggingTest(SimpleHandlerTestCase): + class Handler(RequestHandler): + def get(self): + 1 / 0 + + def log_exception(self, typ, value, tb): + 1 / 0 + + def test_buggy_log_exception(self): + # Something gets logged even though the application's + # logger is broken. + with ExpectLog(app_log, ".*"): + self.fetch("/") + + +class UIMethodUIModuleTest(SimpleHandlerTestCase): + """Test that UI methods and modules are created correctly and + associated with the handler. + """ + + class Handler(RequestHandler): + def get(self): + self.render("foo.html") + + def value(self): + return self.get_argument("value") + + def get_app_kwargs(self): + def my_ui_method(handler, x): + return "In my_ui_method(%s) with handler value %s." % (x, handler.value()) + + class MyModule(UIModule): + def render(self, x): + return "In MyModule(%s) with handler value %s." % ( + x, + typing.cast(UIMethodUIModuleTest.Handler, self.handler).value(), + ) + + loader = DictLoader( + {"foo.html": "{{ my_ui_method(42) }} {% module MyModule(123) %}"} + ) + return dict( + template_loader=loader, + ui_methods={"my_ui_method": my_ui_method}, + ui_modules={"MyModule": MyModule}, + ) + + def tearDown(self): + super().tearDown() + # TODO: fix template loader caching so this isn't necessary. + RequestHandler._template_loaders.clear() + + def test_ui_method(self): + response = self.fetch("/?value=asdf") + self.assertEqual( + response.body, + b"In my_ui_method(42) with handler value asdf. " + b"In MyModule(123) with handler value asdf.", + ) + + +class GetArgumentErrorTest(SimpleHandlerTestCase): + class Handler(RequestHandler): + def get(self): + try: + self.get_argument("foo") + self.write({}) + except MissingArgumentError as e: + self.write({"arg_name": e.arg_name, "log_message": e.log_message}) + + def test_catch_error(self): + response = self.fetch("/") + self.assertEqual( + json_decode(response.body), + {"arg_name": "foo", "log_message": "Missing argument foo"}, + ) + + +class SetLazyPropertiesTest(SimpleHandlerTestCase): + class Handler(RequestHandler): + def prepare(self): + self.current_user = "Ben" + self.locale = locale.get("en_US") + + def get_user_locale(self): + raise NotImplementedError() + + def get_current_user(self): + raise NotImplementedError() + + def get(self): + self.write("Hello %s (%s)" % (self.current_user, self.locale.code)) + + def test_set_properties(self): + # Ensure that current_user can be assigned to normally for apps + # that want to forgo the lazy get_current_user property + response = self.fetch("/") + self.assertEqual(response.body, b"Hello Ben (en_US)") + + +class GetCurrentUserTest(WebTestCase): + def get_app_kwargs(self): + class WithoutUserModule(UIModule): + def render(self): + return "" + + class WithUserModule(UIModule): + def render(self): + return str(self.current_user) + + loader = DictLoader( + { + "without_user.html": "", + "with_user.html": "{{ current_user }}", + "without_user_module.html": "{% module WithoutUserModule() %}", + "with_user_module.html": "{% module WithUserModule() %}", + } + ) + return dict( + template_loader=loader, + ui_modules={ + "WithUserModule": WithUserModule, + "WithoutUserModule": WithoutUserModule, + }, + ) + + def tearDown(self): + super().tearDown() + RequestHandler._template_loaders.clear() + + def get_handlers(self): + class CurrentUserHandler(RequestHandler): + def prepare(self): + self.has_loaded_current_user = False + + def get_current_user(self): + self.has_loaded_current_user = True + return "" + + class WithoutUserHandler(CurrentUserHandler): + def get(self): + self.render_string("without_user.html") + self.finish(str(self.has_loaded_current_user)) + + class WithUserHandler(CurrentUserHandler): + def get(self): + self.render_string("with_user.html") + self.finish(str(self.has_loaded_current_user)) + + class CurrentUserModuleHandler(CurrentUserHandler): + def get_template_namespace(self): + # If RequestHandler.get_template_namespace is called, then + # get_current_user is evaluated. Until #820 is fixed, this + # is a small hack to circumvent the issue. + return self.ui + + class WithoutUserModuleHandler(CurrentUserModuleHandler): + def get(self): + self.render_string("without_user_module.html") + self.finish(str(self.has_loaded_current_user)) + + class WithUserModuleHandler(CurrentUserModuleHandler): + def get(self): + self.render_string("with_user_module.html") + self.finish(str(self.has_loaded_current_user)) + + return [ + ("/without_user", WithoutUserHandler), + ("/with_user", WithUserHandler), + ("/without_user_module", WithoutUserModuleHandler), + ("/with_user_module", WithUserModuleHandler), + ] + + @unittest.skip("needs fix") + def test_get_current_user_is_lazy(self): + # TODO: Make this test pass. See #820. + response = self.fetch("/without_user") + self.assertEqual(response.body, b"False") + + def test_get_current_user_works(self): + response = self.fetch("/with_user") + self.assertEqual(response.body, b"True") + + def test_get_current_user_from_ui_module_is_lazy(self): + response = self.fetch("/without_user_module") + self.assertEqual(response.body, b"False") + + def test_get_current_user_from_ui_module_works(self): + response = self.fetch("/with_user_module") + self.assertEqual(response.body, b"True") + + +class UnimplementedHTTPMethodsTest(SimpleHandlerTestCase): + class Handler(RequestHandler): + pass + + def test_unimplemented_standard_methods(self): + for method in ["HEAD", "GET", "DELETE", "OPTIONS"]: + response = self.fetch("/", method=method) + self.assertEqual(response.code, 405) + for method in ["POST", "PUT"]: + response = self.fetch("/", method=method, body=b"") + self.assertEqual(response.code, 405) + + +class UnimplementedNonStandardMethodsTest(SimpleHandlerTestCase): + class Handler(RequestHandler): + def other(self): + # Even though this method exists, it won't get called automatically + # because it is not in SUPPORTED_METHODS. + self.write("other") + + def test_unimplemented_patch(self): + # PATCH is recently standardized; Tornado supports it by default + # but wsgiref.validate doesn't like it. + response = self.fetch("/", method="PATCH", body=b"") + self.assertEqual(response.code, 405) + + def test_unimplemented_other(self): + response = self.fetch("/", method="OTHER", allow_nonstandard_methods=True) + self.assertEqual(response.code, 405) + + +class AllHTTPMethodsTest(SimpleHandlerTestCase): + class Handler(RequestHandler): + def method(self): + assert self.request.method is not None + self.write(self.request.method) + + get = delete = options = post = put = method # type: ignore + + def test_standard_methods(self): + response = self.fetch("/", method="HEAD") + self.assertEqual(response.body, b"") + for method in ["GET", "DELETE", "OPTIONS"]: + response = self.fetch("/", method=method) + self.assertEqual(response.body, utf8(method)) + for method in ["POST", "PUT"]: + response = self.fetch("/", method=method, body=b"") + self.assertEqual(response.body, utf8(method)) + + +class PatchMethodTest(SimpleHandlerTestCase): + class Handler(RequestHandler): + SUPPORTED_METHODS = RequestHandler.SUPPORTED_METHODS + ( # type: ignore + "OTHER", + ) + + def patch(self): + self.write("patch") + + def other(self): + self.write("other") + + def test_patch(self): + response = self.fetch("/", method="PATCH", body=b"") + self.assertEqual(response.body, b"patch") + + def test_other(self): + response = self.fetch("/", method="OTHER", allow_nonstandard_methods=True) + self.assertEqual(response.body, b"other") + + +class FinishInPrepareTest(SimpleHandlerTestCase): + class Handler(RequestHandler): + def prepare(self): + self.finish("done") + + def get(self): + # It's difficult to assert for certain that a method did not + # or will not be called in an asynchronous context, but this + # will be logged noisily if it is reached. + raise Exception("should not reach this method") + + def test_finish_in_prepare(self): + response = self.fetch("/") + self.assertEqual(response.body, b"done") + + +class Default404Test(WebTestCase): + def get_handlers(self): + # If there are no handlers at all a default redirect handler gets added. + return [("/foo", RequestHandler)] + + def test_404(self): + response = self.fetch("/") + self.assertEqual(response.code, 404) + self.assertEqual( + response.body, + b"<html><title>404: Not Found</title>" + b"<body>404: Not Found</body></html>", + ) + + +class Custom404Test(WebTestCase): + def get_handlers(self): + return [("/foo", RequestHandler)] + + def get_app_kwargs(self): + class Custom404Handler(RequestHandler): + def get(self): + self.set_status(404) + self.write("custom 404 response") + + return dict(default_handler_class=Custom404Handler) + + def test_404(self): + response = self.fetch("/") + self.assertEqual(response.code, 404) + self.assertEqual(response.body, b"custom 404 response") + + +class DefaultHandlerArgumentsTest(WebTestCase): + def get_handlers(self): + return [("/foo", RequestHandler)] + + def get_app_kwargs(self): + return dict( + default_handler_class=ErrorHandler, + default_handler_args=dict(status_code=403), + ) + + def test_403(self): + response = self.fetch("/") + self.assertEqual(response.code, 403) + + +class HandlerByNameTest(WebTestCase): + def get_handlers(self): + # All three are equivalent. + return [ + ("/hello1", HelloHandler), + ("/hello2", "tornado.test.web_test.HelloHandler"), + url("/hello3", "tornado.test.web_test.HelloHandler"), + ] + + def test_handler_by_name(self): + resp = self.fetch("/hello1") + self.assertEqual(resp.body, b"hello") + resp = self.fetch("/hello2") + self.assertEqual(resp.body, b"hello") + resp = self.fetch("/hello3") + self.assertEqual(resp.body, b"hello") + + +class StreamingRequestBodyTest(WebTestCase): + def get_handlers(self): + @stream_request_body + class StreamingBodyHandler(RequestHandler): + def initialize(self, test): + self.test = test + + def prepare(self): + self.test.prepared.set_result(None) + + def data_received(self, data): + self.test.data.set_result(data) + + def get(self): + self.test.finished.set_result(None) + self.write({}) + + @stream_request_body + class EarlyReturnHandler(RequestHandler): + def prepare(self): + # If we finish the response in prepare, it won't continue to + # the (non-existent) data_received. + raise HTTPError(401) + + @stream_request_body + class CloseDetectionHandler(RequestHandler): + def initialize(self, test): + self.test = test + + def on_connection_close(self): + super().on_connection_close() + self.test.close_future.set_result(None) + + return [ + ("/stream_body", StreamingBodyHandler, dict(test=self)), + ("/early_return", EarlyReturnHandler), + ("/close_detection", CloseDetectionHandler, dict(test=self)), + ] + + def connect(self, url, connection_close): + # Use a raw connection so we can control the sending of data. + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) + s.connect(("127.0.0.1", self.get_http_port())) + stream = IOStream(s) + stream.write(b"GET " + url + b" HTTP/1.1\r\n") + if connection_close: + stream.write(b"Connection: close\r\n") + stream.write(b"Transfer-Encoding: chunked\r\n\r\n") + return stream + + @gen_test + def test_streaming_body(self): + self.prepared = Future() # type: Future[None] + self.data = Future() # type: Future[bytes] + self.finished = Future() # type: Future[None] + + stream = self.connect(b"/stream_body", connection_close=True) + yield self.prepared + stream.write(b"4\r\nasdf\r\n") + # Ensure the first chunk is received before we send the second. + data = yield self.data + self.assertEqual(data, b"asdf") + self.data = Future() + stream.write(b"4\r\nqwer\r\n") + data = yield self.data + self.assertEqual(data, b"qwer") + stream.write(b"0\r\n\r\n") + yield self.finished + data = yield stream.read_until_close() + # This would ideally use an HTTP1Connection to read the response. + self.assertTrue(data.endswith(b"{}")) + stream.close() + + @gen_test + def test_early_return(self): + stream = self.connect(b"/early_return", connection_close=False) + data = yield stream.read_until_close() + self.assertTrue(data.startswith(b"HTTP/1.1 401")) + + @gen_test + def test_early_return_with_data(self): + stream = self.connect(b"/early_return", connection_close=False) + stream.write(b"4\r\nasdf\r\n") + data = yield stream.read_until_close() + self.assertTrue(data.startswith(b"HTTP/1.1 401")) + + @gen_test + def test_close_during_upload(self): + self.close_future = Future() # type: Future[None] + stream = self.connect(b"/close_detection", connection_close=False) + stream.close() + yield self.close_future + + +# Each method in this handler returns a yieldable object and yields to the +# IOLoop so the future is not immediately ready. Ensure that the +# yieldables are respected and no method is called before the previous +# one has completed. +@stream_request_body +class BaseFlowControlHandler(RequestHandler): + def initialize(self, test): + self.test = test + self.method = None + self.methods = [] # type: typing.List[str] + + @contextlib.contextmanager + def in_method(self, method): + if self.method is not None: + self.test.fail("entered method %s while in %s" % (method, self.method)) + self.method = method + self.methods.append(method) + try: + yield + finally: + self.method = None + + @gen.coroutine + def prepare(self): + # Note that asynchronous prepare() does not block data_received, + # so we don't use in_method here. + self.methods.append("prepare") + yield gen.moment + + @gen.coroutine + def post(self): + with self.in_method("post"): + yield gen.moment + self.write(dict(methods=self.methods)) + + +class BaseStreamingRequestFlowControlTest(object): + def get_httpserver_options(self): + # Use a small chunk size so flow control is relevant even though + # all the data arrives at once. + return dict(chunk_size=10, decompress_request=True) + + def get_http_client(self): + # simple_httpclient only: curl doesn't support body_producer. + return SimpleAsyncHTTPClient() + + # Test all the slightly different code paths for fixed, chunked, etc bodies. + def test_flow_control_fixed_body(self: typing.Any): + response = self.fetch("/", body="abcdefghijklmnopqrstuvwxyz", method="POST") + response.rethrow() + self.assertEqual( + json_decode(response.body), + dict( + methods=[ + "prepare", + "data_received", + "data_received", + "data_received", + "post", + ] + ), + ) + + def test_flow_control_chunked_body(self: typing.Any): + chunks = [b"abcd", b"efgh", b"ijkl"] + + @gen.coroutine + def body_producer(write): + for i in chunks: + yield write(i) + + response = self.fetch("/", body_producer=body_producer, method="POST") + response.rethrow() + self.assertEqual( + json_decode(response.body), + dict( + methods=[ + "prepare", + "data_received", + "data_received", + "data_received", + "post", + ] + ), + ) + + def test_flow_control_compressed_body(self: typing.Any): + bytesio = BytesIO() + gzip_file = gzip.GzipFile(mode="w", fileobj=bytesio) + gzip_file.write(b"abcdefghijklmnopqrstuvwxyz") + gzip_file.close() + compressed_body = bytesio.getvalue() + response = self.fetch( + "/", + body=compressed_body, + method="POST", + headers={"Content-Encoding": "gzip"}, + ) + response.rethrow() + self.assertEqual( + json_decode(response.body), + dict( + methods=[ + "prepare", + "data_received", + "data_received", + "data_received", + "post", + ] + ), + ) + + +class DecoratedStreamingRequestFlowControlTest( + BaseStreamingRequestFlowControlTest, WebTestCase +): + def get_handlers(self): + class DecoratedFlowControlHandler(BaseFlowControlHandler): + @gen.coroutine + def data_received(self, data): + with self.in_method("data_received"): + yield gen.moment + + return [("/", DecoratedFlowControlHandler, dict(test=self))] + + +class NativeStreamingRequestFlowControlTest( + BaseStreamingRequestFlowControlTest, WebTestCase +): + def get_handlers(self): + class NativeFlowControlHandler(BaseFlowControlHandler): + async def data_received(self, data): + with self.in_method("data_received"): + import asyncio + + await asyncio.sleep(0) + + return [("/", NativeFlowControlHandler, dict(test=self))] + + +class IncorrectContentLengthTest(SimpleHandlerTestCase): + def get_handlers(self): + test = self + self.server_error = None + + # Manually set a content-length that doesn't match the actual content. + class TooHigh(RequestHandler): + def get(self): + self.set_header("Content-Length", "42") + try: + self.finish("ok") + except Exception as e: + test.server_error = e + raise + + class TooLow(RequestHandler): + def get(self): + self.set_header("Content-Length", "2") + try: + self.finish("hello") + except Exception as e: + test.server_error = e + raise + + return [("/high", TooHigh), ("/low", TooLow)] + + def test_content_length_too_high(self): + # When the content-length is too high, the connection is simply + # closed without completing the response. An error is logged on + # the server. + with ExpectLog(app_log, "(Uncaught exception|Exception in callback)"): + with ExpectLog( + gen_log, + "(Cannot send error response after headers written" + "|Failed to flush partial response)", + ): + with self.assertRaises(HTTPClientError): + self.fetch("/high", raise_error=True) + self.assertEqual( + str(self.server_error), "Tried to write 40 bytes less than Content-Length" + ) + + def test_content_length_too_low(self): + # When the content-length is too low, the connection is closed + # without writing the last chunk, so the client never sees the request + # complete (which would be a framing error). + with ExpectLog(app_log, "(Uncaught exception|Exception in callback)"): + with ExpectLog( + gen_log, + "(Cannot send error response after headers written" + "|Failed to flush partial response)", + ): + with self.assertRaises(HTTPClientError): + self.fetch("/low", raise_error=True) + self.assertEqual( + str(self.server_error), "Tried to write more data than Content-Length" + ) + + +class ClientCloseTest(SimpleHandlerTestCase): + class Handler(RequestHandler): + def get(self): + if self.request.version.startswith("HTTP/1"): + # Simulate a connection closed by the client during + # request processing. The client will see an error, but the + # server should respond gracefully (without logging errors + # because we were unable to write out as many bytes as + # Content-Length said we would) + self.request.connection.stream.close() # type: ignore + self.write("hello") + else: + # TODO: add a HTTP2-compatible version of this test. + self.write("requires HTTP/1.x") + + def test_client_close(self): + with self.assertRaises((HTTPClientError, unittest.SkipTest)): # type: ignore + response = self.fetch("/", raise_error=True) + if response.body == b"requires HTTP/1.x": + self.skipTest("requires HTTP/1.x") + self.assertEqual(response.code, 599) + + +class SignedValueTest(unittest.TestCase): + SECRET = "It's a secret to everybody" + SECRET_DICT = {0: "asdfbasdf", 1: "12312312", 2: "2342342"} + + def past(self): + return self.present() - 86400 * 32 + + def present(self): + return 1300000000 + + def test_known_values(self): + signed_v1 = create_signed_value( + SignedValueTest.SECRET, "key", "value", version=1, clock=self.present + ) + self.assertEqual( + signed_v1, b"dmFsdWU=|1300000000|31c934969f53e48164c50768b40cbd7e2daaaa4f" + ) + + signed_v2 = create_signed_value( + SignedValueTest.SECRET, "key", "value", version=2, clock=self.present + ) + self.assertEqual( + signed_v2, + b"2|1:0|10:1300000000|3:key|8:dmFsdWU=|" + b"3d4e60b996ff9c5d5788e333a0cba6f238a22c6c0f94788870e1a9ecd482e152", + ) + + signed_default = create_signed_value( + SignedValueTest.SECRET, "key", "value", clock=self.present + ) + self.assertEqual(signed_default, signed_v2) + + decoded_v1 = decode_signed_value( + SignedValueTest.SECRET, "key", signed_v1, min_version=1, clock=self.present + ) + self.assertEqual(decoded_v1, b"value") + + decoded_v2 = decode_signed_value( + SignedValueTest.SECRET, "key", signed_v2, min_version=2, clock=self.present + ) + self.assertEqual(decoded_v2, b"value") + + def test_name_swap(self): + signed1 = create_signed_value( + SignedValueTest.SECRET, "key1", "value", clock=self.present + ) + signed2 = create_signed_value( + SignedValueTest.SECRET, "key2", "value", clock=self.present + ) + # Try decoding each string with the other's "name" + decoded1 = decode_signed_value( + SignedValueTest.SECRET, "key2", signed1, clock=self.present + ) + self.assertIs(decoded1, None) + decoded2 = decode_signed_value( + SignedValueTest.SECRET, "key1", signed2, clock=self.present + ) + self.assertIs(decoded2, None) + + def test_expired(self): + signed = create_signed_value( + SignedValueTest.SECRET, "key1", "value", clock=self.past + ) + decoded_past = decode_signed_value( + SignedValueTest.SECRET, "key1", signed, clock=self.past + ) + self.assertEqual(decoded_past, b"value") + decoded_present = decode_signed_value( + SignedValueTest.SECRET, "key1", signed, clock=self.present + ) + self.assertIs(decoded_present, None) + + def test_payload_tampering(self): + # These cookies are variants of the one in test_known_values. + sig = "3d4e60b996ff9c5d5788e333a0cba6f238a22c6c0f94788870e1a9ecd482e152" + + def validate(prefix): + return b"value" == decode_signed_value( + SignedValueTest.SECRET, "key", prefix + sig, clock=self.present + ) + + self.assertTrue(validate("2|1:0|10:1300000000|3:key|8:dmFsdWU=|")) + # Change key version + self.assertFalse(validate("2|1:1|10:1300000000|3:key|8:dmFsdWU=|")) + # length mismatch (field too short) + self.assertFalse(validate("2|1:0|10:130000000|3:key|8:dmFsdWU=|")) + # length mismatch (field too long) + self.assertFalse(validate("2|1:0|10:1300000000|3:keey|8:dmFsdWU=|")) + + def test_signature_tampering(self): + prefix = "2|1:0|10:1300000000|3:key|8:dmFsdWU=|" + + def validate(sig): + return b"value" == decode_signed_value( + SignedValueTest.SECRET, "key", prefix + sig, clock=self.present + ) + + self.assertTrue( + validate("3d4e60b996ff9c5d5788e333a0cba6f238a22c6c0f94788870e1a9ecd482e152") + ) + # All zeros + self.assertFalse(validate("0" * 32)) + # Change one character + self.assertFalse( + validate("4d4e60b996ff9c5d5788e333a0cba6f238a22c6c0f94788870e1a9ecd482e152") + ) + # Change another character + self.assertFalse( + validate("3d4e60b996ff9c5d5788e333a0cba6f238a22c6c0f94788870e1a9ecd482e153") + ) + # Truncate + self.assertFalse( + validate("3d4e60b996ff9c5d5788e333a0cba6f238a22c6c0f94788870e1a9ecd482e15") + ) + # Lengthen + self.assertFalse( + validate( + "3d4e60b996ff9c5d5788e333a0cba6f238a22c6c0f94788870e1a9ecd482e1538" + ) + ) + + def test_non_ascii(self): + value = b"\xe9" + signed = create_signed_value( + SignedValueTest.SECRET, "key", value, clock=self.present + ) + decoded = decode_signed_value( + SignedValueTest.SECRET, "key", signed, clock=self.present + ) + self.assertEqual(value, decoded) + + def test_key_versioning_read_write_default_key(self): + value = b"\xe9" + signed = create_signed_value( + SignedValueTest.SECRET_DICT, "key", value, clock=self.present, key_version=0 + ) + decoded = decode_signed_value( + SignedValueTest.SECRET_DICT, "key", signed, clock=self.present + ) + self.assertEqual(value, decoded) + + def test_key_versioning_read_write_non_default_key(self): + value = b"\xe9" + signed = create_signed_value( + SignedValueTest.SECRET_DICT, "key", value, clock=self.present, key_version=1 + ) + decoded = decode_signed_value( + SignedValueTest.SECRET_DICT, "key", signed, clock=self.present + ) + self.assertEqual(value, decoded) + + def test_key_versioning_invalid_key(self): + value = b"\xe9" + signed = create_signed_value( + SignedValueTest.SECRET_DICT, "key", value, clock=self.present, key_version=0 + ) + newkeys = SignedValueTest.SECRET_DICT.copy() + newkeys.pop(0) + decoded = decode_signed_value(newkeys, "key", signed, clock=self.present) + self.assertEqual(None, decoded) + + def test_key_version_retrieval(self): + value = b"\xe9" + signed = create_signed_value( + SignedValueTest.SECRET_DICT, "key", value, clock=self.present, key_version=1 + ) + key_version = get_signature_key_version(signed) + self.assertEqual(1, key_version) + + +class XSRFTest(SimpleHandlerTestCase): + class Handler(RequestHandler): + def get(self): + version = int(self.get_argument("version", "2")) + # This would be a bad idea in a real app, but in this test + # it's fine. + self.settings["xsrf_cookie_version"] = version + self.write(self.xsrf_token) + + def post(self): + self.write("ok") + + def get_app_kwargs(self): + return dict(xsrf_cookies=True) + + def setUp(self): + super().setUp() + self.xsrf_token = self.get_token() + + def get_token(self, old_token=None, version=None): + if old_token is not None: + headers = self.cookie_headers(old_token) + else: + headers = None + response = self.fetch( + "/" if version is None else ("/?version=%d" % version), headers=headers + ) + response.rethrow() + return native_str(response.body) + + def cookie_headers(self, token=None): + if token is None: + token = self.xsrf_token + return {"Cookie": "_xsrf=" + token} + + def test_xsrf_fail_no_token(self): + with ExpectLog(gen_log, ".*'_xsrf' argument missing"): + response = self.fetch("/", method="POST", body=b"") + self.assertEqual(response.code, 403) + + def test_xsrf_fail_body_no_cookie(self): + with ExpectLog(gen_log, ".*XSRF cookie does not match POST"): + response = self.fetch( + "/", + method="POST", + body=urllib.parse.urlencode(dict(_xsrf=self.xsrf_token)), + ) + self.assertEqual(response.code, 403) + + def test_xsrf_fail_argument_invalid_format(self): + with ExpectLog(gen_log, ".*'_xsrf' argument has invalid format"): + response = self.fetch( + "/", + method="POST", + headers=self.cookie_headers(), + body=urllib.parse.urlencode(dict(_xsrf="3|")), + ) + self.assertEqual(response.code, 403) + + def test_xsrf_fail_cookie_invalid_format(self): + with ExpectLog(gen_log, ".*XSRF cookie does not match POST"): + response = self.fetch( + "/", + method="POST", + headers=self.cookie_headers(token="3|"), + body=urllib.parse.urlencode(dict(_xsrf=self.xsrf_token)), + ) + self.assertEqual(response.code, 403) + + def test_xsrf_fail_cookie_no_body(self): + with ExpectLog(gen_log, ".*'_xsrf' argument missing"): + response = self.fetch( + "/", method="POST", body=b"", headers=self.cookie_headers() + ) + self.assertEqual(response.code, 403) + + def test_xsrf_success_short_token(self): + response = self.fetch( + "/", + method="POST", + body=urllib.parse.urlencode(dict(_xsrf="deadbeef")), + headers=self.cookie_headers(token="deadbeef"), + ) + self.assertEqual(response.code, 200) + + def test_xsrf_success_non_hex_token(self): + response = self.fetch( + "/", + method="POST", + body=urllib.parse.urlencode(dict(_xsrf="xoxo")), + headers=self.cookie_headers(token="xoxo"), + ) + self.assertEqual(response.code, 200) + + def test_xsrf_success_post_body(self): + response = self.fetch( + "/", + method="POST", + body=urllib.parse.urlencode(dict(_xsrf=self.xsrf_token)), + headers=self.cookie_headers(), + ) + self.assertEqual(response.code, 200) + + def test_xsrf_success_query_string(self): + response = self.fetch( + "/?" + urllib.parse.urlencode(dict(_xsrf=self.xsrf_token)), + method="POST", + body=b"", + headers=self.cookie_headers(), + ) + self.assertEqual(response.code, 200) + + def test_xsrf_success_header(self): + response = self.fetch( + "/", + method="POST", + body=b"", + headers=dict( + {"X-Xsrftoken": self.xsrf_token}, # type: ignore + **self.cookie_headers() + ), + ) + self.assertEqual(response.code, 200) + + def test_distinct_tokens(self): + # Every request gets a distinct token. + NUM_TOKENS = 10 + tokens = set() + for i in range(NUM_TOKENS): + tokens.add(self.get_token()) + self.assertEqual(len(tokens), NUM_TOKENS) + + def test_cross_user(self): + token2 = self.get_token() + # Each token can be used to authenticate its own request. + for token in (self.xsrf_token, token2): + response = self.fetch( + "/", + method="POST", + body=urllib.parse.urlencode(dict(_xsrf=token)), + headers=self.cookie_headers(token), + ) + self.assertEqual(response.code, 200) + # Sending one in the cookie and the other in the body is not allowed. + for cookie_token, body_token in ( + (self.xsrf_token, token2), + (token2, self.xsrf_token), + ): + with ExpectLog(gen_log, ".*XSRF cookie does not match POST"): + response = self.fetch( + "/", + method="POST", + body=urllib.parse.urlencode(dict(_xsrf=body_token)), + headers=self.cookie_headers(cookie_token), + ) + self.assertEqual(response.code, 403) + + def test_refresh_token(self): + token = self.xsrf_token + tokens_seen = set([token]) + # A user's token is stable over time. Refreshing the page in one tab + # might update the cookie while an older tab still has the old cookie + # in its DOM. Simulate this scenario by passing a constant token + # in the body and re-querying for the token. + for i in range(5): + token = self.get_token(token) + # Tokens are encoded uniquely each time + tokens_seen.add(token) + response = self.fetch( + "/", + method="POST", + body=urllib.parse.urlencode(dict(_xsrf=self.xsrf_token)), + headers=self.cookie_headers(token), + ) + self.assertEqual(response.code, 200) + self.assertEqual(len(tokens_seen), 6) + + def test_versioning(self): + # Version 1 still produces distinct tokens per request. + self.assertNotEqual(self.get_token(version=1), self.get_token(version=1)) + + # Refreshed v1 tokens are all identical. + v1_token = self.get_token(version=1) + for i in range(5): + self.assertEqual(self.get_token(v1_token, version=1), v1_token) + + # Upgrade to a v2 version of the same token + v2_token = self.get_token(v1_token) + self.assertNotEqual(v1_token, v2_token) + # Each v1 token can map to many v2 tokens. + self.assertNotEqual(v2_token, self.get_token(v1_token)) + + # The tokens are cross-compatible. + for cookie_token, body_token in ((v1_token, v2_token), (v2_token, v1_token)): + response = self.fetch( + "/", + method="POST", + body=urllib.parse.urlencode(dict(_xsrf=body_token)), + headers=self.cookie_headers(cookie_token), + ) + self.assertEqual(response.code, 200) + + +class XSRFCookieKwargsTest(SimpleHandlerTestCase): + class Handler(RequestHandler): + def get(self): + self.write(self.xsrf_token) + + def get_app_kwargs(self): + return dict( + xsrf_cookies=True, xsrf_cookie_kwargs=dict(httponly=True, expires_days=2) + ) + + def test_xsrf_httponly(self): + response = self.fetch("/") + self.assertIn("httponly;", response.headers["Set-Cookie"].lower()) + self.assertIn("expires=", response.headers["Set-Cookie"].lower()) + header = response.headers.get("Set-Cookie") + assert header is not None + match = re.match(".*; expires=(?P<expires>.+);.*", header) + assert match is not None + + expires = datetime.datetime.utcnow() + datetime.timedelta(days=2) + parsed = email.utils.parsedate(match.groupdict()["expires"]) + assert parsed is not None + header_expires = datetime.datetime(*parsed[:6]) + self.assertTrue(abs((expires - header_expires).total_seconds()) < 10) + + +class FinishExceptionTest(SimpleHandlerTestCase): + class Handler(RequestHandler): + def get(self): + self.set_status(401) + self.set_header("WWW-Authenticate", 'Basic realm="something"') + if self.get_argument("finish_value", ""): + raise Finish("authentication required") + else: + self.write("authentication required") + raise Finish() + + def test_finish_exception(self): + for u in ["/", "/?finish_value=1"]: + response = self.fetch(u) + self.assertEqual(response.code, 401) + self.assertEqual( + 'Basic realm="something"', response.headers.get("WWW-Authenticate") + ) + self.assertEqual(b"authentication required", response.body) + + +class DecoratorTest(WebTestCase): + def get_handlers(self): + class RemoveSlashHandler(RequestHandler): + @removeslash + def get(self): + pass + + class AddSlashHandler(RequestHandler): + @addslash + def get(self): + pass + + return [("/removeslash/", RemoveSlashHandler), ("/addslash", AddSlashHandler)] + + def test_removeslash(self): + response = self.fetch("/removeslash/", follow_redirects=False) + self.assertEqual(response.code, 301) + self.assertEqual(response.headers["Location"], "/removeslash") + + response = self.fetch("/removeslash/?foo=bar", follow_redirects=False) + self.assertEqual(response.code, 301) + self.assertEqual(response.headers["Location"], "/removeslash?foo=bar") + + def test_addslash(self): + response = self.fetch("/addslash", follow_redirects=False) + self.assertEqual(response.code, 301) + self.assertEqual(response.headers["Location"], "/addslash/") + + response = self.fetch("/addslash?foo=bar", follow_redirects=False) + self.assertEqual(response.code, 301) + self.assertEqual(response.headers["Location"], "/addslash/?foo=bar") + + +class CacheTest(WebTestCase): + def get_handlers(self): + class EtagHandler(RequestHandler): + def get(self, computed_etag): + self.write(computed_etag) + + def compute_etag(self): + return self._write_buffer[0] + + return [("/etag/(.*)", EtagHandler)] + + def test_wildcard_etag(self): + computed_etag = '"xyzzy"' + etags = "*" + self._test_etag(computed_etag, etags, 304) + + def test_strong_etag_match(self): + computed_etag = '"xyzzy"' + etags = '"xyzzy"' + self._test_etag(computed_etag, etags, 304) + + def test_multiple_strong_etag_match(self): + computed_etag = '"xyzzy1"' + etags = '"xyzzy1", "xyzzy2"' + self._test_etag(computed_etag, etags, 304) + + def test_strong_etag_not_match(self): + computed_etag = '"xyzzy"' + etags = '"xyzzy1"' + self._test_etag(computed_etag, etags, 200) + + def test_multiple_strong_etag_not_match(self): + computed_etag = '"xyzzy"' + etags = '"xyzzy1", "xyzzy2"' + self._test_etag(computed_etag, etags, 200) + + def test_weak_etag_match(self): + computed_etag = '"xyzzy1"' + etags = 'W/"xyzzy1"' + self._test_etag(computed_etag, etags, 304) + + def test_multiple_weak_etag_match(self): + computed_etag = '"xyzzy2"' + etags = 'W/"xyzzy1", W/"xyzzy2"' + self._test_etag(computed_etag, etags, 304) + + def test_weak_etag_not_match(self): + computed_etag = '"xyzzy2"' + etags = 'W/"xyzzy1"' + self._test_etag(computed_etag, etags, 200) + + def test_multiple_weak_etag_not_match(self): + computed_etag = '"xyzzy3"' + etags = 'W/"xyzzy1", W/"xyzzy2"' + self._test_etag(computed_etag, etags, 200) + + def _test_etag(self, computed_etag, etags, status_code): + response = self.fetch( + "/etag/" + computed_etag, headers={"If-None-Match": etags} + ) + self.assertEqual(response.code, status_code) + + +class RequestSummaryTest(SimpleHandlerTestCase): + class Handler(RequestHandler): + def get(self): + # remote_ip is optional, although it's set by + # both HTTPServer and WSGIAdapter. + # Clobber it to make sure it doesn't break logging. + self.request.remote_ip = None + self.finish(self._request_summary()) + + def test_missing_remote_ip(self): + resp = self.fetch("/") + self.assertEqual(resp.body, b"GET / (None)") + + +class HTTPErrorTest(unittest.TestCase): + def test_copy(self): + e = HTTPError(403, reason="Go away") + e2 = copy.copy(e) + self.assertIsNot(e, e2) + self.assertEqual(e.status_code, e2.status_code) + self.assertEqual(e.reason, e2.reason) + + +class ApplicationTest(AsyncTestCase): + def test_listen(self): + app = Application([]) + server = app.listen(0, address="127.0.0.1") + server.stop() + + +class URLSpecReverseTest(unittest.TestCase): + def test_reverse(self): + self.assertEqual("/favicon.ico", url(r"/favicon\.ico", None).reverse()) + self.assertEqual("/favicon.ico", url(r"^/favicon\.ico$", None).reverse()) + + def test_non_reversible(self): + # URLSpecs are non-reversible if they include non-constant + # regex features outside capturing groups. Currently, this is + # only strictly enforced for backslash-escaped character + # classes. + paths = [r"^/api/v\d+/foo/(\w+)$"] + for path in paths: + # A URLSpec can still be created even if it cannot be reversed. + url_spec = url(path, None) + try: + result = url_spec.reverse() + self.fail( + "did not get expected exception when reversing %s. " + "result: %s" % (path, result) + ) + except ValueError: + pass + + def test_reverse_arguments(self): + self.assertEqual( + "/api/v1/foo/bar", url(r"^/api/v1/foo/(\w+)$", None).reverse("bar") + ) + self.assertEqual( + "/api.v1/foo/5/icon.png", + url(r"/api\.v1/foo/([0-9]+)/icon\.png", None).reverse(5), + ) + + +class RedirectHandlerTest(WebTestCase): + def get_handlers(self): + return [ + ("/src", WebRedirectHandler, {"url": "/dst"}), + ("/src2", WebRedirectHandler, {"url": "/dst2?foo=bar"}), + (r"/(.*?)/(.*?)/(.*)", WebRedirectHandler, {"url": "/{1}/{0}/{2}"}), + ] + + def test_basic_redirect(self): + response = self.fetch("/src", follow_redirects=False) + self.assertEqual(response.code, 301) + self.assertEqual(response.headers["Location"], "/dst") + + def test_redirect_with_argument(self): + response = self.fetch("/src?foo=bar", follow_redirects=False) + self.assertEqual(response.code, 301) + self.assertEqual(response.headers["Location"], "/dst?foo=bar") + + def test_redirect_with_appending_argument(self): + response = self.fetch("/src2?foo2=bar2", follow_redirects=False) + self.assertEqual(response.code, 301) + self.assertEqual(response.headers["Location"], "/dst2?foo=bar&foo2=bar2") + + def test_redirect_pattern(self): + response = self.fetch("/a/b/c", follow_redirects=False) + self.assertEqual(response.code, 301) + self.assertEqual(response.headers["Location"], "/b/a/c") diff --git a/venv/lib/python3.8/site-packages/tornado/test/websocket_test.py b/venv/lib/python3.8/site-packages/tornado/test/websocket_test.py new file mode 100644 index 0000000..befe06d --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/websocket_test.py @@ -0,0 +1,840 @@ +import asyncio +import functools +import traceback +import typing +import unittest + +from tornado.concurrent import Future +from tornado import gen +from tornado.httpclient import HTTPError, HTTPRequest +from tornado.locks import Event +from tornado.log import gen_log, app_log +from tornado.simple_httpclient import SimpleAsyncHTTPClient +from tornado.template import DictLoader +from tornado.testing import AsyncHTTPTestCase, gen_test, bind_unused_port, ExpectLog +from tornado.web import Application, RequestHandler + +try: + import tornado.websocket # noqa: F401 + from tornado.util import _websocket_mask_python +except ImportError: + # The unittest module presents misleading errors on ImportError + # (it acts as if websocket_test could not be found, hiding the underlying + # error). If we get an ImportError here (which could happen due to + # TORNADO_EXTENSION=1), print some extra information before failing. + traceback.print_exc() + raise + +from tornado.websocket import ( + WebSocketHandler, + websocket_connect, + WebSocketError, + WebSocketClosedError, +) + +try: + from tornado import speedups +except ImportError: + speedups = None # type: ignore + + +class TestWebSocketHandler(WebSocketHandler): + """Base class for testing handlers that exposes the on_close event. + + This allows for tests to see the close code and reason on the + server side. + + """ + + def initialize(self, close_future=None, compression_options=None): + self.close_future = close_future + self.compression_options = compression_options + + def get_compression_options(self): + return self.compression_options + + def on_close(self): + if self.close_future is not None: + self.close_future.set_result((self.close_code, self.close_reason)) + + +class EchoHandler(TestWebSocketHandler): + @gen.coroutine + def on_message(self, message): + try: + yield self.write_message(message, isinstance(message, bytes)) + except asyncio.CancelledError: + pass + except WebSocketClosedError: + pass + + +class ErrorInOnMessageHandler(TestWebSocketHandler): + def on_message(self, message): + 1 / 0 + + +class HeaderHandler(TestWebSocketHandler): + def open(self): + methods_to_test = [ + functools.partial(self.write, "This should not work"), + functools.partial(self.redirect, "http://localhost/elsewhere"), + functools.partial(self.set_header, "X-Test", ""), + functools.partial(self.set_cookie, "Chocolate", "Chip"), + functools.partial(self.set_status, 503), + self.flush, + self.finish, + ] + for method in methods_to_test: + try: + # In a websocket context, many RequestHandler methods + # raise RuntimeErrors. + method() # type: ignore + raise Exception("did not get expected exception") + except RuntimeError: + pass + self.write_message(self.request.headers.get("X-Test", "")) + + +class HeaderEchoHandler(TestWebSocketHandler): + def set_default_headers(self): + self.set_header("X-Extra-Response-Header", "Extra-Response-Value") + + def prepare(self): + for k, v in self.request.headers.get_all(): + if k.lower().startswith("x-test"): + self.set_header(k, v) + + +class NonWebSocketHandler(RequestHandler): + def get(self): + self.write("ok") + + +class RedirectHandler(RequestHandler): + def get(self): + self.redirect("/echo") + + +class CloseReasonHandler(TestWebSocketHandler): + def open(self): + self.on_close_called = False + self.close(1001, "goodbye") + + +class AsyncPrepareHandler(TestWebSocketHandler): + @gen.coroutine + def prepare(self): + yield gen.moment + + def on_message(self, message): + self.write_message(message) + + +class PathArgsHandler(TestWebSocketHandler): + def open(self, arg): + self.write_message(arg) + + +class CoroutineOnMessageHandler(TestWebSocketHandler): + def initialize(self, **kwargs): + super().initialize(**kwargs) + self.sleeping = 0 + + @gen.coroutine + def on_message(self, message): + if self.sleeping > 0: + self.write_message("another coroutine is already sleeping") + self.sleeping += 1 + yield gen.sleep(0.01) + self.sleeping -= 1 + self.write_message(message) + + +class RenderMessageHandler(TestWebSocketHandler): + def on_message(self, message): + self.write_message(self.render_string("message.html", message=message)) + + +class SubprotocolHandler(TestWebSocketHandler): + def initialize(self, **kwargs): + super().initialize(**kwargs) + self.select_subprotocol_called = False + + def select_subprotocol(self, subprotocols): + if self.select_subprotocol_called: + raise Exception("select_subprotocol called twice") + self.select_subprotocol_called = True + if "goodproto" in subprotocols: + return "goodproto" + return None + + def open(self): + if not self.select_subprotocol_called: + raise Exception("select_subprotocol not called") + self.write_message("subprotocol=%s" % self.selected_subprotocol) + + +class OpenCoroutineHandler(TestWebSocketHandler): + def initialize(self, test, **kwargs): + super().initialize(**kwargs) + self.test = test + self.open_finished = False + + @gen.coroutine + def open(self): + yield self.test.message_sent.wait() + yield gen.sleep(0.010) + self.open_finished = True + + def on_message(self, message): + if not self.open_finished: + raise Exception("on_message called before open finished") + self.write_message("ok") + + +class ErrorInOpenHandler(TestWebSocketHandler): + def open(self): + raise Exception("boom") + + +class ErrorInAsyncOpenHandler(TestWebSocketHandler): + async def open(self): + await asyncio.sleep(0) + raise Exception("boom") + + +class NoDelayHandler(TestWebSocketHandler): + def open(self): + self.set_nodelay(True) + self.write_message("hello") + + +class WebSocketBaseTestCase(AsyncHTTPTestCase): + @gen.coroutine + def ws_connect(self, path, **kwargs): + ws = yield websocket_connect( + "ws://127.0.0.1:%d%s" % (self.get_http_port(), path), **kwargs + ) + raise gen.Return(ws) + + +class WebSocketTest(WebSocketBaseTestCase): + def get_app(self): + self.close_future = Future() # type: Future[None] + return Application( + [ + ("/echo", EchoHandler, dict(close_future=self.close_future)), + ("/non_ws", NonWebSocketHandler), + ("/redirect", RedirectHandler), + ("/header", HeaderHandler, dict(close_future=self.close_future)), + ( + "/header_echo", + HeaderEchoHandler, + dict(close_future=self.close_future), + ), + ( + "/close_reason", + CloseReasonHandler, + dict(close_future=self.close_future), + ), + ( + "/error_in_on_message", + ErrorInOnMessageHandler, + dict(close_future=self.close_future), + ), + ( + "/async_prepare", + AsyncPrepareHandler, + dict(close_future=self.close_future), + ), + ( + "/path_args/(.*)", + PathArgsHandler, + dict(close_future=self.close_future), + ), + ( + "/coroutine", + CoroutineOnMessageHandler, + dict(close_future=self.close_future), + ), + ("/render", RenderMessageHandler, dict(close_future=self.close_future)), + ( + "/subprotocol", + SubprotocolHandler, + dict(close_future=self.close_future), + ), + ( + "/open_coroutine", + OpenCoroutineHandler, + dict(close_future=self.close_future, test=self), + ), + ("/error_in_open", ErrorInOpenHandler), + ("/error_in_async_open", ErrorInAsyncOpenHandler), + ("/nodelay", NoDelayHandler), + ], + template_loader=DictLoader({"message.html": "<b>{{ message }}</b>"}), + ) + + def get_http_client(self): + # These tests require HTTP/1; force the use of SimpleAsyncHTTPClient. + return SimpleAsyncHTTPClient() + + def tearDown(self): + super().tearDown() + RequestHandler._template_loaders.clear() + + def test_http_request(self): + # WS server, HTTP client. + response = self.fetch("/echo") + self.assertEqual(response.code, 400) + + def test_missing_websocket_key(self): + response = self.fetch( + "/echo", + headers={ + "Connection": "Upgrade", + "Upgrade": "WebSocket", + "Sec-WebSocket-Version": "13", + }, + ) + self.assertEqual(response.code, 400) + + def test_bad_websocket_version(self): + response = self.fetch( + "/echo", + headers={ + "Connection": "Upgrade", + "Upgrade": "WebSocket", + "Sec-WebSocket-Version": "12", + }, + ) + self.assertEqual(response.code, 426) + + @gen_test + def test_websocket_gen(self): + ws = yield self.ws_connect("/echo") + yield ws.write_message("hello") + response = yield ws.read_message() + self.assertEqual(response, "hello") + + def test_websocket_callbacks(self): + websocket_connect( + "ws://127.0.0.1:%d/echo" % self.get_http_port(), callback=self.stop + ) + ws = self.wait().result() + ws.write_message("hello") + ws.read_message(self.stop) + response = self.wait().result() + self.assertEqual(response, "hello") + self.close_future.add_done_callback(lambda f: self.stop()) + ws.close() + self.wait() + + @gen_test + def test_binary_message(self): + ws = yield self.ws_connect("/echo") + ws.write_message(b"hello \xe9", binary=True) + response = yield ws.read_message() + self.assertEqual(response, b"hello \xe9") + + @gen_test + def test_unicode_message(self): + ws = yield self.ws_connect("/echo") + ws.write_message(u"hello \u00e9") + response = yield ws.read_message() + self.assertEqual(response, u"hello \u00e9") + + @gen_test + def test_render_message(self): + ws = yield self.ws_connect("/render") + ws.write_message("hello") + response = yield ws.read_message() + self.assertEqual(response, "<b>hello</b>") + + @gen_test + def test_error_in_on_message(self): + ws = yield self.ws_connect("/error_in_on_message") + ws.write_message("hello") + with ExpectLog(app_log, "Uncaught exception"): + response = yield ws.read_message() + self.assertIs(response, None) + + @gen_test + def test_websocket_http_fail(self): + with self.assertRaises(HTTPError) as cm: + yield self.ws_connect("/notfound") + self.assertEqual(cm.exception.code, 404) + + @gen_test + def test_websocket_http_success(self): + with self.assertRaises(WebSocketError): + yield self.ws_connect("/non_ws") + + @gen_test + def test_websocket_http_redirect(self): + with self.assertRaises(HTTPError): + yield self.ws_connect("/redirect") + + @gen_test + def test_websocket_network_fail(self): + sock, port = bind_unused_port() + sock.close() + with self.assertRaises(IOError): + with ExpectLog(gen_log, ".*"): + yield websocket_connect( + "ws://127.0.0.1:%d/" % port, connect_timeout=3600 + ) + + @gen_test + def test_websocket_close_buffered_data(self): + ws = yield websocket_connect("ws://127.0.0.1:%d/echo" % self.get_http_port()) + ws.write_message("hello") + ws.write_message("world") + # Close the underlying stream. + ws.stream.close() + + @gen_test + def test_websocket_headers(self): + # Ensure that arbitrary headers can be passed through websocket_connect. + ws = yield websocket_connect( + HTTPRequest( + "ws://127.0.0.1:%d/header" % self.get_http_port(), + headers={"X-Test": "hello"}, + ) + ) + response = yield ws.read_message() + self.assertEqual(response, "hello") + + @gen_test + def test_websocket_header_echo(self): + # Ensure that headers can be returned in the response. + # Specifically, that arbitrary headers passed through websocket_connect + # can be returned. + ws = yield websocket_connect( + HTTPRequest( + "ws://127.0.0.1:%d/header_echo" % self.get_http_port(), + headers={"X-Test-Hello": "hello"}, + ) + ) + self.assertEqual(ws.headers.get("X-Test-Hello"), "hello") + self.assertEqual( + ws.headers.get("X-Extra-Response-Header"), "Extra-Response-Value" + ) + + @gen_test + def test_server_close_reason(self): + ws = yield self.ws_connect("/close_reason") + msg = yield ws.read_message() + # A message of None means the other side closed the connection. + self.assertIs(msg, None) + self.assertEqual(ws.close_code, 1001) + self.assertEqual(ws.close_reason, "goodbye") + # The on_close callback is called no matter which side closed. + code, reason = yield self.close_future + # The client echoed the close code it received to the server, + # so the server's close code (returned via close_future) is + # the same. + self.assertEqual(code, 1001) + + @gen_test + def test_client_close_reason(self): + ws = yield self.ws_connect("/echo") + ws.close(1001, "goodbye") + code, reason = yield self.close_future + self.assertEqual(code, 1001) + self.assertEqual(reason, "goodbye") + + @gen_test + def test_write_after_close(self): + ws = yield self.ws_connect("/close_reason") + msg = yield ws.read_message() + self.assertIs(msg, None) + with self.assertRaises(WebSocketClosedError): + ws.write_message("hello") + + @gen_test + def test_async_prepare(self): + # Previously, an async prepare method triggered a bug that would + # result in a timeout on test shutdown (and a memory leak). + ws = yield self.ws_connect("/async_prepare") + ws.write_message("hello") + res = yield ws.read_message() + self.assertEqual(res, "hello") + + @gen_test + def test_path_args(self): + ws = yield self.ws_connect("/path_args/hello") + res = yield ws.read_message() + self.assertEqual(res, "hello") + + @gen_test + def test_coroutine(self): + ws = yield self.ws_connect("/coroutine") + # Send both messages immediately, coroutine must process one at a time. + yield ws.write_message("hello1") + yield ws.write_message("hello2") + res = yield ws.read_message() + self.assertEqual(res, "hello1") + res = yield ws.read_message() + self.assertEqual(res, "hello2") + + @gen_test + def test_check_origin_valid_no_path(self): + port = self.get_http_port() + + url = "ws://127.0.0.1:%d/echo" % port + headers = {"Origin": "http://127.0.0.1:%d" % port} + + ws = yield websocket_connect(HTTPRequest(url, headers=headers)) + ws.write_message("hello") + response = yield ws.read_message() + self.assertEqual(response, "hello") + + @gen_test + def test_check_origin_valid_with_path(self): + port = self.get_http_port() + + url = "ws://127.0.0.1:%d/echo" % port + headers = {"Origin": "http://127.0.0.1:%d/something" % port} + + ws = yield websocket_connect(HTTPRequest(url, headers=headers)) + ws.write_message("hello") + response = yield ws.read_message() + self.assertEqual(response, "hello") + + @gen_test + def test_check_origin_invalid_partial_url(self): + port = self.get_http_port() + + url = "ws://127.0.0.1:%d/echo" % port + headers = {"Origin": "127.0.0.1:%d" % port} + + with self.assertRaises(HTTPError) as cm: + yield websocket_connect(HTTPRequest(url, headers=headers)) + self.assertEqual(cm.exception.code, 403) + + @gen_test + def test_check_origin_invalid(self): + port = self.get_http_port() + + url = "ws://127.0.0.1:%d/echo" % port + # Host is 127.0.0.1, which should not be accessible from some other + # domain + headers = {"Origin": "http://somewhereelse.com"} + + with self.assertRaises(HTTPError) as cm: + yield websocket_connect(HTTPRequest(url, headers=headers)) + + self.assertEqual(cm.exception.code, 403) + + @gen_test + def test_check_origin_invalid_subdomains(self): + port = self.get_http_port() + + url = "ws://localhost:%d/echo" % port + # Subdomains should be disallowed by default. If we could pass a + # resolver to websocket_connect we could test sibling domains as well. + headers = {"Origin": "http://subtenant.localhost"} + + with self.assertRaises(HTTPError) as cm: + yield websocket_connect(HTTPRequest(url, headers=headers)) + + self.assertEqual(cm.exception.code, 403) + + @gen_test + def test_subprotocols(self): + ws = yield self.ws_connect( + "/subprotocol", subprotocols=["badproto", "goodproto"] + ) + self.assertEqual(ws.selected_subprotocol, "goodproto") + res = yield ws.read_message() + self.assertEqual(res, "subprotocol=goodproto") + + @gen_test + def test_subprotocols_not_offered(self): + ws = yield self.ws_connect("/subprotocol") + self.assertIs(ws.selected_subprotocol, None) + res = yield ws.read_message() + self.assertEqual(res, "subprotocol=None") + + @gen_test + def test_open_coroutine(self): + self.message_sent = Event() + ws = yield self.ws_connect("/open_coroutine") + yield ws.write_message("hello") + self.message_sent.set() + res = yield ws.read_message() + self.assertEqual(res, "ok") + + @gen_test + def test_error_in_open(self): + with ExpectLog(app_log, "Uncaught exception"): + ws = yield self.ws_connect("/error_in_open") + res = yield ws.read_message() + self.assertIsNone(res) + + @gen_test + def test_error_in_async_open(self): + with ExpectLog(app_log, "Uncaught exception"): + ws = yield self.ws_connect("/error_in_async_open") + res = yield ws.read_message() + self.assertIsNone(res) + + @gen_test + def test_nodelay(self): + ws = yield self.ws_connect("/nodelay") + res = yield ws.read_message() + self.assertEqual(res, "hello") + + +class NativeCoroutineOnMessageHandler(TestWebSocketHandler): + def initialize(self, **kwargs): + super().initialize(**kwargs) + self.sleeping = 0 + + async def on_message(self, message): + if self.sleeping > 0: + self.write_message("another coroutine is already sleeping") + self.sleeping += 1 + await gen.sleep(0.01) + self.sleeping -= 1 + self.write_message(message) + + +class WebSocketNativeCoroutineTest(WebSocketBaseTestCase): + def get_app(self): + return Application([("/native", NativeCoroutineOnMessageHandler)]) + + @gen_test + def test_native_coroutine(self): + ws = yield self.ws_connect("/native") + # Send both messages immediately, coroutine must process one at a time. + yield ws.write_message("hello1") + yield ws.write_message("hello2") + res = yield ws.read_message() + self.assertEqual(res, "hello1") + res = yield ws.read_message() + self.assertEqual(res, "hello2") + + +class CompressionTestMixin(object): + MESSAGE = "Hello world. Testing 123 123" + + def get_app(self): + class LimitedHandler(TestWebSocketHandler): + @property + def max_message_size(self): + return 1024 + + def on_message(self, message): + self.write_message(str(len(message))) + + return Application( + [ + ( + "/echo", + EchoHandler, + dict(compression_options=self.get_server_compression_options()), + ), + ( + "/limited", + LimitedHandler, + dict(compression_options=self.get_server_compression_options()), + ), + ] + ) + + def get_server_compression_options(self): + return None + + def get_client_compression_options(self): + return None + + def verify_wire_bytes(self, bytes_in: int, bytes_out: int) -> None: + raise NotImplementedError() + + @gen_test + def test_message_sizes(self: typing.Any): + ws = yield self.ws_connect( + "/echo", compression_options=self.get_client_compression_options() + ) + # Send the same message three times so we can measure the + # effect of the context_takeover options. + for i in range(3): + ws.write_message(self.MESSAGE) + response = yield ws.read_message() + self.assertEqual(response, self.MESSAGE) + self.assertEqual(ws.protocol._message_bytes_out, len(self.MESSAGE) * 3) + self.assertEqual(ws.protocol._message_bytes_in, len(self.MESSAGE) * 3) + self.verify_wire_bytes(ws.protocol._wire_bytes_in, ws.protocol._wire_bytes_out) + + @gen_test + def test_size_limit(self: typing.Any): + ws = yield self.ws_connect( + "/limited", compression_options=self.get_client_compression_options() + ) + # Small messages pass through. + ws.write_message("a" * 128) + response = yield ws.read_message() + self.assertEqual(response, "128") + # This message is too big after decompression, but it compresses + # down to a size that will pass the initial checks. + ws.write_message("a" * 2048) + response = yield ws.read_message() + self.assertIsNone(response) + + +class UncompressedTestMixin(CompressionTestMixin): + """Specialization of CompressionTestMixin when we expect no compression.""" + + def verify_wire_bytes(self: typing.Any, bytes_in, bytes_out): + # Bytes out includes the 4-byte mask key per message. + self.assertEqual(bytes_out, 3 * (len(self.MESSAGE) + 6)) + self.assertEqual(bytes_in, 3 * (len(self.MESSAGE) + 2)) + + +class NoCompressionTest(UncompressedTestMixin, WebSocketBaseTestCase): + pass + + +# If only one side tries to compress, the extension is not negotiated. +class ServerOnlyCompressionTest(UncompressedTestMixin, WebSocketBaseTestCase): + def get_server_compression_options(self): + return {} + + +class ClientOnlyCompressionTest(UncompressedTestMixin, WebSocketBaseTestCase): + def get_client_compression_options(self): + return {} + + +class DefaultCompressionTest(CompressionTestMixin, WebSocketBaseTestCase): + def get_server_compression_options(self): + return {} + + def get_client_compression_options(self): + return {} + + def verify_wire_bytes(self, bytes_in, bytes_out): + self.assertLess(bytes_out, 3 * (len(self.MESSAGE) + 6)) + self.assertLess(bytes_in, 3 * (len(self.MESSAGE) + 2)) + # Bytes out includes the 4 bytes mask key per message. + self.assertEqual(bytes_out, bytes_in + 12) + + +class MaskFunctionMixin(object): + # Subclasses should define self.mask(mask, data) + def mask(self, mask: bytes, data: bytes) -> bytes: + raise NotImplementedError() + + def test_mask(self: typing.Any): + self.assertEqual(self.mask(b"abcd", b""), b"") + self.assertEqual(self.mask(b"abcd", b"b"), b"\x03") + self.assertEqual(self.mask(b"abcd", b"54321"), b"TVPVP") + self.assertEqual(self.mask(b"ZXCV", b"98765432"), b"c`t`olpd") + # Include test cases with \x00 bytes (to ensure that the C + # extension isn't depending on null-terminated strings) and + # bytes with the high bit set (to smoke out signedness issues). + self.assertEqual( + self.mask(b"\x00\x01\x02\x03", b"\xff\xfb\xfd\xfc\xfe\xfa"), + b"\xff\xfa\xff\xff\xfe\xfb", + ) + self.assertEqual( + self.mask(b"\xff\xfb\xfd\xfc", b"\x00\x01\x02\x03\x04\x05"), + b"\xff\xfa\xff\xff\xfb\xfe", + ) + + +class PythonMaskFunctionTest(MaskFunctionMixin, unittest.TestCase): + def mask(self, mask, data): + return _websocket_mask_python(mask, data) + + +@unittest.skipIf(speedups is None, "tornado.speedups module not present") +class CythonMaskFunctionTest(MaskFunctionMixin, unittest.TestCase): + def mask(self, mask, data): + return speedups.websocket_mask(mask, data) + + +class ServerPeriodicPingTest(WebSocketBaseTestCase): + def get_app(self): + class PingHandler(TestWebSocketHandler): + def on_pong(self, data): + self.write_message("got pong") + + return Application([("/", PingHandler)], websocket_ping_interval=0.01) + + @gen_test + def test_server_ping(self): + ws = yield self.ws_connect("/") + for i in range(3): + response = yield ws.read_message() + self.assertEqual(response, "got pong") + # TODO: test that the connection gets closed if ping responses stop. + + +class ClientPeriodicPingTest(WebSocketBaseTestCase): + def get_app(self): + class PingHandler(TestWebSocketHandler): + def on_ping(self, data): + self.write_message("got ping") + + return Application([("/", PingHandler)]) + + @gen_test + def test_client_ping(self): + ws = yield self.ws_connect("/", ping_interval=0.01) + for i in range(3): + response = yield ws.read_message() + self.assertEqual(response, "got ping") + # TODO: test that the connection gets closed if ping responses stop. + + +class ManualPingTest(WebSocketBaseTestCase): + def get_app(self): + class PingHandler(TestWebSocketHandler): + def on_ping(self, data): + self.write_message(data, binary=isinstance(data, bytes)) + + return Application([("/", PingHandler)]) + + @gen_test + def test_manual_ping(self): + ws = yield self.ws_connect("/") + + self.assertRaises(ValueError, ws.ping, "a" * 126) + + ws.ping("hello") + resp = yield ws.read_message() + # on_ping always sees bytes. + self.assertEqual(resp, b"hello") + + ws.ping(b"binary hello") + resp = yield ws.read_message() + self.assertEqual(resp, b"binary hello") + + +class MaxMessageSizeTest(WebSocketBaseTestCase): + def get_app(self): + return Application([("/", EchoHandler)], websocket_max_message_size=1024) + + @gen_test + def test_large_message(self): + ws = yield self.ws_connect("/") + + # Write a message that is allowed. + msg = "a" * 1024 + ws.write_message(msg) + resp = yield ws.read_message() + self.assertEqual(resp, msg) + + # Write a message that is too large. + ws.write_message(msg + "b") + resp = yield ws.read_message() + # A message of None means the other side closed the connection. + self.assertIs(resp, None) + self.assertEqual(ws.close_code, 1009) + self.assertEqual(ws.close_reason, "message too big") + # TODO: Needs tests of messages split over multiple + # continuation frames. diff --git a/venv/lib/python3.8/site-packages/tornado/test/wsgi_test.py b/venv/lib/python3.8/site-packages/tornado/test/wsgi_test.py new file mode 100644 index 0000000..f98da5b --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/test/wsgi_test.py @@ -0,0 +1,20 @@ +from wsgiref.validate import validator + +from tornado.testing import AsyncHTTPTestCase +from tornado.wsgi import WSGIContainer + + +class WSGIContainerTest(AsyncHTTPTestCase): + # TODO: Now that WSGIAdapter is gone, this is a pretty weak test. + def wsgi_app(self, environ, start_response): + status = "200 OK" + response_headers = [("Content-Type", "text/plain")] + start_response(status, response_headers) + return [b"Hello world!"] + + def get_app(self): + return WSGIContainer(validator(self.wsgi_app)) + + def test_simple(self): + response = self.fetch("/") + self.assertEqual(response.body, b"Hello world!") diff --git a/venv/lib/python3.8/site-packages/tornado/testing.py b/venv/lib/python3.8/site-packages/tornado/testing.py new file mode 100644 index 0000000..3351b92 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/testing.py @@ -0,0 +1,818 @@ +"""Support classes for automated testing. + +* `AsyncTestCase` and `AsyncHTTPTestCase`: Subclasses of unittest.TestCase + with additional support for testing asynchronous (`.IOLoop`-based) code. + +* `ExpectLog`: Make test logs less spammy. + +* `main()`: A simple test runner (wrapper around unittest.main()) with support + for the tornado.autoreload module to rerun the tests when code changes. +""" + +import asyncio +from collections.abc import Generator +import functools +import inspect +import logging +import os +import re +import signal +import socket +import sys +import unittest + +from tornado import gen +from tornado.httpclient import AsyncHTTPClient, HTTPResponse +from tornado.httpserver import HTTPServer +from tornado.ioloop import IOLoop, TimeoutError +from tornado import netutil +from tornado.platform.asyncio import AsyncIOMainLoop +from tornado.process import Subprocess +from tornado.log import app_log +from tornado.util import raise_exc_info, basestring_type +from tornado.web import Application + +import typing +from typing import Tuple, Any, Callable, Type, Dict, Union, Optional +from types import TracebackType + +if typing.TYPE_CHECKING: + # Coroutine wasn't added to typing until 3.5.3, so only import it + # when mypy is running and use forward references. + from typing import Coroutine # noqa: F401 + + _ExcInfoTuple = Tuple[ + Optional[Type[BaseException]], Optional[BaseException], Optional[TracebackType] + ] + + +_NON_OWNED_IOLOOPS = AsyncIOMainLoop + + +def bind_unused_port(reuse_port: bool = False) -> Tuple[socket.socket, int]: + """Binds a server socket to an available port on localhost. + + Returns a tuple (socket, port). + + .. versionchanged:: 4.4 + Always binds to ``127.0.0.1`` without resolving the name + ``localhost``. + """ + sock = netutil.bind_sockets( + 0, "127.0.0.1", family=socket.AF_INET, reuse_port=reuse_port + )[0] + port = sock.getsockname()[1] + return sock, port + + +def get_async_test_timeout() -> float: + """Get the global timeout setting for async tests. + + Returns a float, the timeout in seconds. + + .. versionadded:: 3.1 + """ + env = os.environ.get("ASYNC_TEST_TIMEOUT") + if env is not None: + try: + return float(env) + except ValueError: + pass + return 5 + + +class _TestMethodWrapper(object): + """Wraps a test method to raise an error if it returns a value. + + This is mainly used to detect undecorated generators (if a test + method yields it must use a decorator to consume the generator), + but will also detect other kinds of return values (these are not + necessarily errors, but we alert anyway since there is no good + reason to return a value from a test). + """ + + def __init__(self, orig_method: Callable) -> None: + self.orig_method = orig_method + + def __call__(self, *args: Any, **kwargs: Any) -> None: + result = self.orig_method(*args, **kwargs) + if isinstance(result, Generator) or inspect.iscoroutine(result): + raise TypeError( + "Generator and coroutine test methods should be" + " decorated with tornado.testing.gen_test" + ) + elif result is not None: + raise ValueError("Return value from test method ignored: %r" % result) + + def __getattr__(self, name: str) -> Any: + """Proxy all unknown attributes to the original method. + + This is important for some of the decorators in the `unittest` + module, such as `unittest.skipIf`. + """ + return getattr(self.orig_method, name) + + +class AsyncTestCase(unittest.TestCase): + """`~unittest.TestCase` subclass for testing `.IOLoop`-based + asynchronous code. + + The unittest framework is synchronous, so the test must be + complete by the time the test method returns. This means that + asynchronous code cannot be used in quite the same way as usual + and must be adapted to fit. To write your tests with coroutines, + decorate your test methods with `tornado.testing.gen_test` instead + of `tornado.gen.coroutine`. + + This class also provides the (deprecated) `stop()` and `wait()` + methods for a more manual style of testing. The test method itself + must call ``self.wait()``, and asynchronous callbacks should call + ``self.stop()`` to signal completion. + + By default, a new `.IOLoop` is constructed for each test and is available + as ``self.io_loop``. If the code being tested requires a + global `.IOLoop`, subclasses should override `get_new_ioloop` to return it. + + The `.IOLoop`'s ``start`` and ``stop`` methods should not be + called directly. Instead, use `self.stop <stop>` and `self.wait + <wait>`. Arguments passed to ``self.stop`` are returned from + ``self.wait``. It is possible to have multiple ``wait``/``stop`` + cycles in the same test. + + Example:: + + # This test uses coroutine style. + class MyTestCase(AsyncTestCase): + @tornado.testing.gen_test + def test_http_fetch(self): + client = AsyncHTTPClient() + response = yield client.fetch("http://www.tornadoweb.org") + # Test contents of response + self.assertIn("FriendFeed", response.body) + + # This test uses argument passing between self.stop and self.wait. + class MyTestCase2(AsyncTestCase): + def test_http_fetch(self): + client = AsyncHTTPClient() + client.fetch("http://www.tornadoweb.org/", self.stop) + response = self.wait() + # Test contents of response + self.assertIn("FriendFeed", response.body) + """ + + def __init__(self, methodName: str = "runTest") -> None: + super().__init__(methodName) + self.__stopped = False + self.__running = False + self.__failure = None # type: Optional[_ExcInfoTuple] + self.__stop_args = None # type: Any + self.__timeout = None # type: Optional[object] + + # It's easy to forget the @gen_test decorator, but if you do + # the test will silently be ignored because nothing will consume + # the generator. Replace the test method with a wrapper that will + # make sure it's not an undecorated generator. + setattr(self, methodName, _TestMethodWrapper(getattr(self, methodName))) + + # Not used in this class itself, but used by @gen_test + self._test_generator = None # type: Optional[Union[Generator, Coroutine]] + + def setUp(self) -> None: + super().setUp() + self.io_loop = self.get_new_ioloop() + self.io_loop.make_current() + + def tearDown(self) -> None: + # Native coroutines tend to produce warnings if they're not + # allowed to run to completion. It's difficult to ensure that + # this always happens in tests, so cancel any tasks that are + # still pending by the time we get here. + asyncio_loop = self.io_loop.asyncio_loop # type: ignore + if hasattr(asyncio, "all_tasks"): # py37 + tasks = asyncio.all_tasks(asyncio_loop) # type: ignore + else: + tasks = asyncio.Task.all_tasks(asyncio_loop) + # Tasks that are done may still appear here and may contain + # non-cancellation exceptions, so filter them out. + tasks = [t for t in tasks if not t.done()] + for t in tasks: + t.cancel() + # Allow the tasks to run and finalize themselves (which means + # raising a CancelledError inside the coroutine). This may + # just transform the "task was destroyed but it is pending" + # warning into a "uncaught CancelledError" warning, but + # catching CancelledErrors in coroutines that may leak is + # simpler than ensuring that no coroutines leak. + if tasks: + done, pending = self.io_loop.run_sync(lambda: asyncio.wait(tasks)) + assert not pending + # If any task failed with anything but a CancelledError, raise it. + for f in done: + try: + f.result() + except asyncio.CancelledError: + pass + + # Clean up Subprocess, so it can be used again with a new ioloop. + Subprocess.uninitialize() + self.io_loop.clear_current() + if not isinstance(self.io_loop, _NON_OWNED_IOLOOPS): + # Try to clean up any file descriptors left open in the ioloop. + # This avoids leaks, especially when tests are run repeatedly + # in the same process with autoreload (because curl does not + # set FD_CLOEXEC on its file descriptors) + self.io_loop.close(all_fds=True) + super().tearDown() + # In case an exception escaped or the StackContext caught an exception + # when there wasn't a wait() to re-raise it, do so here. + # This is our last chance to raise an exception in a way that the + # unittest machinery understands. + self.__rethrow() + + def get_new_ioloop(self) -> IOLoop: + """Returns the `.IOLoop` to use for this test. + + By default, a new `.IOLoop` is created for each test. + Subclasses may override this method to return + `.IOLoop.current()` if it is not appropriate to use a new + `.IOLoop` in each tests (for example, if there are global + singletons using the default `.IOLoop`) or if a per-test event + loop is being provided by another system (such as + ``pytest-asyncio``). + """ + return IOLoop() + + def _handle_exception( + self, typ: Type[Exception], value: Exception, tb: TracebackType + ) -> bool: + if self.__failure is None: + self.__failure = (typ, value, tb) + else: + app_log.error( + "multiple unhandled exceptions in test", exc_info=(typ, value, tb) + ) + self.stop() + return True + + def __rethrow(self) -> None: + if self.__failure is not None: + failure = self.__failure + self.__failure = None + raise_exc_info(failure) + + def run( + self, result: Optional[unittest.TestResult] = None + ) -> Optional[unittest.TestResult]: + ret = super().run(result) + # As a last resort, if an exception escaped super.run() and wasn't + # re-raised in tearDown, raise it here. This will cause the + # unittest run to fail messily, but that's better than silently + # ignoring an error. + self.__rethrow() + return ret + + def stop(self, _arg: Any = None, **kwargs: Any) -> None: + """Stops the `.IOLoop`, causing one pending (or future) call to `wait()` + to return. + + Keyword arguments or a single positional argument passed to `stop()` are + saved and will be returned by `wait()`. + + .. deprecated:: 5.1 + + `stop` and `wait` are deprecated; use ``@gen_test`` instead. + """ + assert _arg is None or not kwargs + self.__stop_args = kwargs or _arg + if self.__running: + self.io_loop.stop() + self.__running = False + self.__stopped = True + + def wait( + self, + condition: Optional[Callable[..., bool]] = None, + timeout: Optional[float] = None, + ) -> Any: + """Runs the `.IOLoop` until stop is called or timeout has passed. + + In the event of a timeout, an exception will be thrown. The + default timeout is 5 seconds; it may be overridden with a + ``timeout`` keyword argument or globally with the + ``ASYNC_TEST_TIMEOUT`` environment variable. + + If ``condition`` is not ``None``, the `.IOLoop` will be restarted + after `stop()` until ``condition()`` returns ``True``. + + .. versionchanged:: 3.1 + Added the ``ASYNC_TEST_TIMEOUT`` environment variable. + + .. deprecated:: 5.1 + + `stop` and `wait` are deprecated; use ``@gen_test`` instead. + """ + if timeout is None: + timeout = get_async_test_timeout() + + if not self.__stopped: + if timeout: + + def timeout_func() -> None: + try: + raise self.failureException( + "Async operation timed out after %s seconds" % timeout + ) + except Exception: + self.__failure = sys.exc_info() + self.stop() + + self.__timeout = self.io_loop.add_timeout( + self.io_loop.time() + timeout, timeout_func + ) + while True: + self.__running = True + self.io_loop.start() + if self.__failure is not None or condition is None or condition(): + break + if self.__timeout is not None: + self.io_loop.remove_timeout(self.__timeout) + self.__timeout = None + assert self.__stopped + self.__stopped = False + self.__rethrow() + result = self.__stop_args + self.__stop_args = None + return result + + +class AsyncHTTPTestCase(AsyncTestCase): + """A test case that starts up an HTTP server. + + Subclasses must override `get_app()`, which returns the + `tornado.web.Application` (or other `.HTTPServer` callback) to be tested. + Tests will typically use the provided ``self.http_client`` to fetch + URLs from this server. + + Example, assuming the "Hello, world" example from the user guide is in + ``hello.py``:: + + import hello + + class TestHelloApp(AsyncHTTPTestCase): + def get_app(self): + return hello.make_app() + + def test_homepage(self): + response = self.fetch('/') + self.assertEqual(response.code, 200) + self.assertEqual(response.body, 'Hello, world') + + That call to ``self.fetch()`` is equivalent to :: + + self.http_client.fetch(self.get_url('/'), self.stop) + response = self.wait() + + which illustrates how AsyncTestCase can turn an asynchronous operation, + like ``http_client.fetch()``, into a synchronous operation. If you need + to do other asynchronous operations in tests, you'll probably need to use + ``stop()`` and ``wait()`` yourself. + """ + + def setUp(self) -> None: + super().setUp() + sock, port = bind_unused_port() + self.__port = port + + self.http_client = self.get_http_client() + self._app = self.get_app() + self.http_server = self.get_http_server() + self.http_server.add_sockets([sock]) + + def get_http_client(self) -> AsyncHTTPClient: + return AsyncHTTPClient() + + def get_http_server(self) -> HTTPServer: + return HTTPServer(self._app, **self.get_httpserver_options()) + + def get_app(self) -> Application: + """Should be overridden by subclasses to return a + `tornado.web.Application` or other `.HTTPServer` callback. + """ + raise NotImplementedError() + + def fetch( + self, path: str, raise_error: bool = False, **kwargs: Any + ) -> HTTPResponse: + """Convenience method to synchronously fetch a URL. + + The given path will be appended to the local server's host and + port. Any additional keyword arguments will be passed directly to + `.AsyncHTTPClient.fetch` (and so could be used to pass + ``method="POST"``, ``body="..."``, etc). + + If the path begins with http:// or https://, it will be treated as a + full URL and will be fetched as-is. + + If ``raise_error`` is ``True``, a `tornado.httpclient.HTTPError` will + be raised if the response code is not 200. This is the same behavior + as the ``raise_error`` argument to `.AsyncHTTPClient.fetch`, but + the default is ``False`` here (it's ``True`` in `.AsyncHTTPClient`) + because tests often need to deal with non-200 response codes. + + .. versionchanged:: 5.0 + Added support for absolute URLs. + + .. versionchanged:: 5.1 + + Added the ``raise_error`` argument. + + .. deprecated:: 5.1 + + This method currently turns any exception into an + `.HTTPResponse` with status code 599. In Tornado 6.0, + errors other than `tornado.httpclient.HTTPError` will be + passed through, and ``raise_error=False`` will only + suppress errors that would be raised due to non-200 + response codes. + + """ + if path.lower().startswith(("http://", "https://")): + url = path + else: + url = self.get_url(path) + return self.io_loop.run_sync( + lambda: self.http_client.fetch(url, raise_error=raise_error, **kwargs), + timeout=get_async_test_timeout(), + ) + + def get_httpserver_options(self) -> Dict[str, Any]: + """May be overridden by subclasses to return additional + keyword arguments for the server. + """ + return {} + + def get_http_port(self) -> int: + """Returns the port used by the server. + + A new port is chosen for each test. + """ + return self.__port + + def get_protocol(self) -> str: + return "http" + + def get_url(self, path: str) -> str: + """Returns an absolute url for the given path on the test server.""" + return "%s://127.0.0.1:%s%s" % (self.get_protocol(), self.get_http_port(), path) + + def tearDown(self) -> None: + self.http_server.stop() + self.io_loop.run_sync( + self.http_server.close_all_connections, timeout=get_async_test_timeout() + ) + self.http_client.close() + del self.http_server + del self._app + super().tearDown() + + +class AsyncHTTPSTestCase(AsyncHTTPTestCase): + """A test case that starts an HTTPS server. + + Interface is generally the same as `AsyncHTTPTestCase`. + """ + + def get_http_client(self) -> AsyncHTTPClient: + return AsyncHTTPClient(force_instance=True, defaults=dict(validate_cert=False)) + + def get_httpserver_options(self) -> Dict[str, Any]: + return dict(ssl_options=self.get_ssl_options()) + + def get_ssl_options(self) -> Dict[str, Any]: + """May be overridden by subclasses to select SSL options. + + By default includes a self-signed testing certificate. + """ + return AsyncHTTPSTestCase.default_ssl_options() + + @staticmethod + def default_ssl_options() -> Dict[str, Any]: + # Testing keys were generated with: + # openssl req -new -keyout tornado/test/test.key \ + # -out tornado/test/test.crt -nodes -days 3650 -x509 + module_dir = os.path.dirname(__file__) + return dict( + certfile=os.path.join(module_dir, "test", "test.crt"), + keyfile=os.path.join(module_dir, "test", "test.key"), + ) + + def get_protocol(self) -> str: + return "https" + + +@typing.overload +def gen_test( + *, timeout: Optional[float] = None +) -> Callable[[Callable[..., Union[Generator, "Coroutine"]]], Callable[..., None]]: + pass + + +@typing.overload # noqa: F811 +def gen_test(func: Callable[..., Union[Generator, "Coroutine"]]) -> Callable[..., None]: + pass + + +def gen_test( # noqa: F811 + func: Optional[Callable[..., Union[Generator, "Coroutine"]]] = None, + timeout: Optional[float] = None, +) -> Union[ + Callable[..., None], + Callable[[Callable[..., Union[Generator, "Coroutine"]]], Callable[..., None]], +]: + """Testing equivalent of ``@gen.coroutine``, to be applied to test methods. + + ``@gen.coroutine`` cannot be used on tests because the `.IOLoop` is not + already running. ``@gen_test`` should be applied to test methods + on subclasses of `AsyncTestCase`. + + Example:: + + class MyTest(AsyncHTTPTestCase): + @gen_test + def test_something(self): + response = yield self.http_client.fetch(self.get_url('/')) + + By default, ``@gen_test`` times out after 5 seconds. The timeout may be + overridden globally with the ``ASYNC_TEST_TIMEOUT`` environment variable, + or for each test with the ``timeout`` keyword argument:: + + class MyTest(AsyncHTTPTestCase): + @gen_test(timeout=10) + def test_something_slow(self): + response = yield self.http_client.fetch(self.get_url('/')) + + Note that ``@gen_test`` is incompatible with `AsyncTestCase.stop`, + `AsyncTestCase.wait`, and `AsyncHTTPTestCase.fetch`. Use ``yield + self.http_client.fetch(self.get_url())`` as shown above instead. + + .. versionadded:: 3.1 + The ``timeout`` argument and ``ASYNC_TEST_TIMEOUT`` environment + variable. + + .. versionchanged:: 4.0 + The wrapper now passes along ``*args, **kwargs`` so it can be used + on functions with arguments. + + """ + if timeout is None: + timeout = get_async_test_timeout() + + def wrap(f: Callable[..., Union[Generator, "Coroutine"]]) -> Callable[..., None]: + # Stack up several decorators to allow us to access the generator + # object itself. In the innermost wrapper, we capture the generator + # and save it in an attribute of self. Next, we run the wrapped + # function through @gen.coroutine. Finally, the coroutine is + # wrapped again to make it synchronous with run_sync. + # + # This is a good case study arguing for either some sort of + # extensibility in the gen decorators or cancellation support. + @functools.wraps(f) + def pre_coroutine(self, *args, **kwargs): + # type: (AsyncTestCase, *Any, **Any) -> Union[Generator, Coroutine] + # Type comments used to avoid pypy3 bug. + result = f(self, *args, **kwargs) + if isinstance(result, Generator) or inspect.iscoroutine(result): + self._test_generator = result + else: + self._test_generator = None + return result + + if inspect.iscoroutinefunction(f): + coro = pre_coroutine + else: + coro = gen.coroutine(pre_coroutine) + + @functools.wraps(coro) + def post_coroutine(self, *args, **kwargs): + # type: (AsyncTestCase, *Any, **Any) -> None + try: + return self.io_loop.run_sync( + functools.partial(coro, self, *args, **kwargs), timeout=timeout + ) + except TimeoutError as e: + # run_sync raises an error with an unhelpful traceback. + # If the underlying generator is still running, we can throw the + # exception back into it so the stack trace is replaced by the + # point where the test is stopped. The only reason the generator + # would not be running would be if it were cancelled, which means + # a native coroutine, so we can rely on the cr_running attribute. + if self._test_generator is not None and getattr( + self._test_generator, "cr_running", True + ): + self._test_generator.throw(type(e), e) + # In case the test contains an overly broad except + # clause, we may get back here. + # Coroutine was stopped or didn't raise a useful stack trace, + # so re-raise the original exception which is better than nothing. + raise + + return post_coroutine + + if func is not None: + # Used like: + # @gen_test + # def f(self): + # pass + return wrap(func) + else: + # Used like @gen_test(timeout=10) + return wrap + + +# Without this attribute, nosetests will try to run gen_test as a test +# anywhere it is imported. +gen_test.__test__ = False # type: ignore + + +class ExpectLog(logging.Filter): + """Context manager to capture and suppress expected log output. + + Useful to make tests of error conditions less noisy, while still + leaving unexpected log entries visible. *Not thread safe.* + + The attribute ``logged_stack`` is set to ``True`` if any exception + stack trace was logged. + + Usage:: + + with ExpectLog('tornado.application', "Uncaught exception"): + error_response = self.fetch("/some_page") + + .. versionchanged:: 4.3 + Added the ``logged_stack`` attribute. + """ + + def __init__( + self, + logger: Union[logging.Logger, basestring_type], + regex: str, + required: bool = True, + level: Optional[int] = None, + ) -> None: + """Constructs an ExpectLog context manager. + + :param logger: Logger object (or name of logger) to watch. Pass + an empty string to watch the root logger. + :param regex: Regular expression to match. Any log entries on + the specified logger that match this regex will be suppressed. + :param required: If true, an exception will be raised if the end of + the ``with`` statement is reached without matching any log entries. + :param level: A constant from the ``logging`` module indicating the + expected log level. If this parameter is provided, only log messages + at this level will be considered to match. Additionally, the + supplied ``logger`` will have its level adjusted if necessary + (for the duration of the ``ExpectLog`` to enable the expected + message. + + .. versionchanged:: 6.1 + Added the ``level`` parameter. + """ + if isinstance(logger, basestring_type): + logger = logging.getLogger(logger) + self.logger = logger + self.regex = re.compile(regex) + self.required = required + self.matched = False + self.logged_stack = False + self.level = level + self.orig_level = None # type: Optional[int] + + def filter(self, record: logging.LogRecord) -> bool: + if record.exc_info: + self.logged_stack = True + message = record.getMessage() + if self.regex.match(message): + if self.level is not None and record.levelno != self.level: + app_log.warning( + "Got expected log message %r at unexpected level (%s vs %s)" + % (message, logging.getLevelName(self.level), record.levelname) + ) + return True + self.matched = True + return False + return True + + def __enter__(self) -> "ExpectLog": + if self.level is not None and self.level < self.logger.getEffectiveLevel(): + self.orig_level = self.logger.level + self.logger.setLevel(self.level) + self.logger.addFilter(self) + return self + + def __exit__( + self, + typ: "Optional[Type[BaseException]]", + value: Optional[BaseException], + tb: Optional[TracebackType], + ) -> None: + if self.orig_level is not None: + self.logger.setLevel(self.orig_level) + self.logger.removeFilter(self) + if not typ and self.required and not self.matched: + raise Exception("did not get expected log message") + + +def main(**kwargs: Any) -> None: + """A simple test runner. + + This test runner is essentially equivalent to `unittest.main` from + the standard library, but adds support for Tornado-style option + parsing and log formatting. It is *not* necessary to use this + `main` function to run tests using `AsyncTestCase`; these tests + are self-contained and can run with any test runner. + + The easiest way to run a test is via the command line:: + + python -m tornado.testing tornado.test.web_test + + See the standard library ``unittest`` module for ways in which + tests can be specified. + + Projects with many tests may wish to define a test script like + ``tornado/test/runtests.py``. This script should define a method + ``all()`` which returns a test suite and then call + `tornado.testing.main()`. Note that even when a test script is + used, the ``all()`` test suite may be overridden by naming a + single test on the command line:: + + # Runs all tests + python -m tornado.test.runtests + # Runs one test + python -m tornado.test.runtests tornado.test.web_test + + Additional keyword arguments passed through to ``unittest.main()``. + For example, use ``tornado.testing.main(verbosity=2)`` + to show many test details as they are run. + See http://docs.python.org/library/unittest.html#unittest.main + for full argument list. + + .. versionchanged:: 5.0 + + This function produces no output of its own; only that produced + by the `unittest` module (previously it would add a PASS or FAIL + log message). + """ + from tornado.options import define, options, parse_command_line + + define( + "exception_on_interrupt", + type=bool, + default=True, + help=( + "If true (default), ctrl-c raises a KeyboardInterrupt " + "exception. This prints a stack trace but cannot interrupt " + "certain operations. If false, the process is more reliably " + "killed, but does not print a stack trace." + ), + ) + + # support the same options as unittest's command-line interface + define("verbose", type=bool) + define("quiet", type=bool) + define("failfast", type=bool) + define("catch", type=bool) + define("buffer", type=bool) + + argv = [sys.argv[0]] + parse_command_line(sys.argv) + + if not options.exception_on_interrupt: + signal.signal(signal.SIGINT, signal.SIG_DFL) + + if options.verbose is not None: + kwargs["verbosity"] = 2 + if options.quiet is not None: + kwargs["verbosity"] = 0 + if options.failfast is not None: + kwargs["failfast"] = True + if options.catch is not None: + kwargs["catchbreak"] = True + if options.buffer is not None: + kwargs["buffer"] = True + + if __name__ == "__main__" and len(argv) == 1: + print("No tests specified", file=sys.stderr) + sys.exit(1) + # In order to be able to run tests by their fully-qualified name + # on the command line without importing all tests here, + # module must be set to None. Python 3.2's unittest.main ignores + # defaultTest if no module is given (it tries to do its own + # test discovery, which is incompatible with auto2to3), so don't + # set module if we're not asking for a specific test. + if len(argv) > 1: + unittest.main(module=None, argv=argv, **kwargs) # type: ignore + else: + unittest.main(defaultTest="all", argv=argv, **kwargs) + + +if __name__ == "__main__": + main() diff --git a/venv/lib/python3.8/site-packages/tornado/util.py b/venv/lib/python3.8/site-packages/tornado/util.py new file mode 100644 index 0000000..77c5f94 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/util.py @@ -0,0 +1,474 @@ +"""Miscellaneous utility functions and classes. + +This module is used internally by Tornado. It is not necessarily expected +that the functions and classes defined here will be useful to other +applications, but they are documented here in case they are. + +The one public-facing part of this module is the `Configurable` class +and its `~Configurable.configure` method, which becomes a part of the +interface of its subclasses, including `.AsyncHTTPClient`, `.IOLoop`, +and `.Resolver`. +""" + +import array +import atexit +from inspect import getfullargspec +import os +import re +import typing +import zlib + +from typing import ( + Any, + Optional, + Dict, + Mapping, + List, + Tuple, + Match, + Callable, + Type, + Sequence, +) + +if typing.TYPE_CHECKING: + # Additional imports only used in type comments. + # This lets us make these imports lazy. + import datetime # noqa: F401 + from types import TracebackType # noqa: F401 + from typing import Union # noqa: F401 + import unittest # noqa: F401 + +# Aliases for types that are spelled differently in different Python +# versions. bytes_type is deprecated and no longer used in Tornado +# itself but is left in case anyone outside Tornado is using it. +bytes_type = bytes +unicode_type = str +basestring_type = str + +try: + from sys import is_finalizing +except ImportError: + # Emulate it + def _get_emulated_is_finalizing() -> Callable[[], bool]: + L = [] # type: List[None] + atexit.register(lambda: L.append(None)) + + def is_finalizing() -> bool: + # Not referencing any globals here + return L != [] + + return is_finalizing + + is_finalizing = _get_emulated_is_finalizing() + + +class TimeoutError(Exception): + """Exception raised by `.with_timeout` and `.IOLoop.run_sync`. + + .. versionchanged:: 5.0: + Unified ``tornado.gen.TimeoutError`` and + ``tornado.ioloop.TimeoutError`` as ``tornado.util.TimeoutError``. + Both former names remain as aliases. + """ + + +class ObjectDict(Dict[str, Any]): + """Makes a dictionary behave like an object, with attribute-style access. + """ + + def __getattr__(self, name: str) -> Any: + try: + return self[name] + except KeyError: + raise AttributeError(name) + + def __setattr__(self, name: str, value: Any) -> None: + self[name] = value + + +class GzipDecompressor(object): + """Streaming gzip decompressor. + + The interface is like that of `zlib.decompressobj` (without some of the + optional arguments, but it understands gzip headers and checksums. + """ + + def __init__(self) -> None: + # Magic parameter makes zlib module understand gzip header + # http://stackoverflow.com/questions/1838699/how-can-i-decompress-a-gzip-stream-with-zlib + # This works on cpython and pypy, but not jython. + self.decompressobj = zlib.decompressobj(16 + zlib.MAX_WBITS) + + def decompress(self, value: bytes, max_length: int = 0) -> bytes: + """Decompress a chunk, returning newly-available data. + + Some data may be buffered for later processing; `flush` must + be called when there is no more input data to ensure that + all data was processed. + + If ``max_length`` is given, some input data may be left over + in ``unconsumed_tail``; you must retrieve this value and pass + it back to a future call to `decompress` if it is not empty. + """ + return self.decompressobj.decompress(value, max_length) + + @property + def unconsumed_tail(self) -> bytes: + """Returns the unconsumed portion left over + """ + return self.decompressobj.unconsumed_tail + + def flush(self) -> bytes: + """Return any remaining buffered data not yet returned by decompress. + + Also checks for errors such as truncated input. + No other methods may be called on this object after `flush`. + """ + return self.decompressobj.flush() + + +def import_object(name: str) -> Any: + """Imports an object by name. + + ``import_object('x')`` is equivalent to ``import x``. + ``import_object('x.y.z')`` is equivalent to ``from x.y import z``. + + >>> import tornado.escape + >>> import_object('tornado.escape') is tornado.escape + True + >>> import_object('tornado.escape.utf8') is tornado.escape.utf8 + True + >>> import_object('tornado') is tornado + True + >>> import_object('tornado.missing_module') + Traceback (most recent call last): + ... + ImportError: No module named missing_module + """ + if name.count(".") == 0: + return __import__(name) + + parts = name.split(".") + obj = __import__(".".join(parts[:-1]), fromlist=[parts[-1]]) + try: + return getattr(obj, parts[-1]) + except AttributeError: + raise ImportError("No module named %s" % parts[-1]) + + +def exec_in( + code: Any, glob: Dict[str, Any], loc: Optional[Optional[Mapping[str, Any]]] = None +) -> None: + if isinstance(code, str): + # exec(string) inherits the caller's future imports; compile + # the string first to prevent that. + code = compile(code, "<string>", "exec", dont_inherit=True) + exec(code, glob, loc) + + +def raise_exc_info( + exc_info, # type: Tuple[Optional[type], Optional[BaseException], Optional[TracebackType]] +): + # type: (...) -> typing.NoReturn + # + # This function's type annotation must use comments instead of + # real annotations because typing.NoReturn does not exist in + # python 3.5's typing module. The formatting is funky because this + # is apparently what flake8 wants. + try: + if exc_info[1] is not None: + raise exc_info[1].with_traceback(exc_info[2]) + else: + raise TypeError("raise_exc_info called with no exception") + finally: + # Clear the traceback reference from our stack frame to + # minimize circular references that slow down GC. + exc_info = (None, None, None) + + +def errno_from_exception(e: BaseException) -> Optional[int]: + """Provides the errno from an Exception object. + + There are cases that the errno attribute was not set so we pull + the errno out of the args but if someone instantiates an Exception + without any args you will get a tuple error. So this function + abstracts all that behavior to give you a safe way to get the + errno. + """ + + if hasattr(e, "errno"): + return e.errno # type: ignore + elif e.args: + return e.args[0] + else: + return None + + +_alphanum = frozenset("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") + + +def _re_unescape_replacement(match: Match[str]) -> str: + group = match.group(1) + if group[0] in _alphanum: + raise ValueError("cannot unescape '\\\\%s'" % group[0]) + return group + + +_re_unescape_pattern = re.compile(r"\\(.)", re.DOTALL) + + +def re_unescape(s: str) -> str: + r"""Unescape a string escaped by `re.escape`. + + May raise ``ValueError`` for regular expressions which could not + have been produced by `re.escape` (for example, strings containing + ``\d`` cannot be unescaped). + + .. versionadded:: 4.4 + """ + return _re_unescape_pattern.sub(_re_unescape_replacement, s) + + +class Configurable(object): + """Base class for configurable interfaces. + + A configurable interface is an (abstract) class whose constructor + acts as a factory function for one of its implementation subclasses. + The implementation subclass as well as optional keyword arguments to + its initializer can be set globally at runtime with `configure`. + + By using the constructor as the factory method, the interface + looks like a normal class, `isinstance` works as usual, etc. This + pattern is most useful when the choice of implementation is likely + to be a global decision (e.g. when `~select.epoll` is available, + always use it instead of `~select.select`), or when a + previously-monolithic class has been split into specialized + subclasses. + + Configurable subclasses must define the class methods + `configurable_base` and `configurable_default`, and use the instance + method `initialize` instead of ``__init__``. + + .. versionchanged:: 5.0 + + It is now possible for configuration to be specified at + multiple levels of a class hierarchy. + + """ + + # Type annotations on this class are mostly done with comments + # because they need to refer to Configurable, which isn't defined + # until after the class definition block. These can use regular + # annotations when our minimum python version is 3.7. + # + # There may be a clever way to use generics here to get more + # precise types (i.e. for a particular Configurable subclass T, + # all the types are subclasses of T, not just Configurable). + __impl_class = None # type: Optional[Type[Configurable]] + __impl_kwargs = None # type: Dict[str, Any] + + def __new__(cls, *args: Any, **kwargs: Any) -> Any: + base = cls.configurable_base() + init_kwargs = {} # type: Dict[str, Any] + if cls is base: + impl = cls.configured_class() + if base.__impl_kwargs: + init_kwargs.update(base.__impl_kwargs) + else: + impl = cls + init_kwargs.update(kwargs) + if impl.configurable_base() is not base: + # The impl class is itself configurable, so recurse. + return impl(*args, **init_kwargs) + instance = super(Configurable, cls).__new__(impl) + # initialize vs __init__ chosen for compatibility with AsyncHTTPClient + # singleton magic. If we get rid of that we can switch to __init__ + # here too. + instance.initialize(*args, **init_kwargs) + return instance + + @classmethod + def configurable_base(cls): + # type: () -> Type[Configurable] + """Returns the base class of a configurable hierarchy. + + This will normally return the class in which it is defined. + (which is *not* necessarily the same as the ``cls`` classmethod + parameter). + + """ + raise NotImplementedError() + + @classmethod + def configurable_default(cls): + # type: () -> Type[Configurable] + """Returns the implementation class to be used if none is configured.""" + raise NotImplementedError() + + def _initialize(self) -> None: + pass + + initialize = _initialize # type: Callable[..., None] + """Initialize a `Configurable` subclass instance. + + Configurable classes should use `initialize` instead of ``__init__``. + + .. versionchanged:: 4.2 + Now accepts positional arguments in addition to keyword arguments. + """ + + @classmethod + def configure(cls, impl, **kwargs): + # type: (Union[None, str, Type[Configurable]], Any) -> None + """Sets the class to use when the base class is instantiated. + + Keyword arguments will be saved and added to the arguments passed + to the constructor. This can be used to set global defaults for + some parameters. + """ + base = cls.configurable_base() + if isinstance(impl, str): + impl = typing.cast(Type[Configurable], import_object(impl)) + if impl is not None and not issubclass(impl, cls): + raise ValueError("Invalid subclass of %s" % cls) + base.__impl_class = impl + base.__impl_kwargs = kwargs + + @classmethod + def configured_class(cls): + # type: () -> Type[Configurable] + """Returns the currently configured class.""" + base = cls.configurable_base() + # Manually mangle the private name to see whether this base + # has been configured (and not another base higher in the + # hierarchy). + if base.__dict__.get("_Configurable__impl_class") is None: + base.__impl_class = cls.configurable_default() + if base.__impl_class is not None: + return base.__impl_class + else: + # Should be impossible, but mypy wants an explicit check. + raise ValueError("configured class not found") + + @classmethod + def _save_configuration(cls): + # type: () -> Tuple[Optional[Type[Configurable]], Dict[str, Any]] + base = cls.configurable_base() + return (base.__impl_class, base.__impl_kwargs) + + @classmethod + def _restore_configuration(cls, saved): + # type: (Tuple[Optional[Type[Configurable]], Dict[str, Any]]) -> None + base = cls.configurable_base() + base.__impl_class = saved[0] + base.__impl_kwargs = saved[1] + + +class ArgReplacer(object): + """Replaces one value in an ``args, kwargs`` pair. + + Inspects the function signature to find an argument by name + whether it is passed by position or keyword. For use in decorators + and similar wrappers. + """ + + def __init__(self, func: Callable, name: str) -> None: + self.name = name + try: + self.arg_pos = self._getargnames(func).index(name) # type: Optional[int] + except ValueError: + # Not a positional parameter + self.arg_pos = None + + def _getargnames(self, func: Callable) -> List[str]: + try: + return getfullargspec(func).args + except TypeError: + if hasattr(func, "func_code"): + # Cython-generated code has all the attributes needed + # by inspect.getfullargspec, but the inspect module only + # works with ordinary functions. Inline the portion of + # getfullargspec that we need here. Note that for static + # functions the @cython.binding(True) decorator must + # be used (for methods it works out of the box). + code = func.func_code # type: ignore + return code.co_varnames[: code.co_argcount] + raise + + def get_old_value( + self, args: Sequence[Any], kwargs: Dict[str, Any], default: Any = None + ) -> Any: + """Returns the old value of the named argument without replacing it. + + Returns ``default`` if the argument is not present. + """ + if self.arg_pos is not None and len(args) > self.arg_pos: + return args[self.arg_pos] + else: + return kwargs.get(self.name, default) + + def replace( + self, new_value: Any, args: Sequence[Any], kwargs: Dict[str, Any] + ) -> Tuple[Any, Sequence[Any], Dict[str, Any]]: + """Replace the named argument in ``args, kwargs`` with ``new_value``. + + Returns ``(old_value, args, kwargs)``. The returned ``args`` and + ``kwargs`` objects may not be the same as the input objects, or + the input objects may be mutated. + + If the named argument was not found, ``new_value`` will be added + to ``kwargs`` and None will be returned as ``old_value``. + """ + if self.arg_pos is not None and len(args) > self.arg_pos: + # The arg to replace is passed positionally + old_value = args[self.arg_pos] + args = list(args) # *args is normally a tuple + args[self.arg_pos] = new_value + else: + # The arg to replace is either omitted or passed by keyword. + old_value = kwargs.get(self.name) + kwargs[self.name] = new_value + return old_value, args, kwargs + + +def timedelta_to_seconds(td): + # type: (datetime.timedelta) -> float + """Equivalent to ``td.total_seconds()`` (introduced in Python 2.7).""" + return td.total_seconds() + + +def _websocket_mask_python(mask: bytes, data: bytes) -> bytes: + """Websocket masking function. + + `mask` is a `bytes` object of length 4; `data` is a `bytes` object of any length. + Returns a `bytes` object of the same length as `data` with the mask applied + as specified in section 5.3 of RFC 6455. + + This pure-python implementation may be replaced by an optimized version when available. + """ + mask_arr = array.array("B", mask) + unmasked_arr = array.array("B", data) + for i in range(len(data)): + unmasked_arr[i] = unmasked_arr[i] ^ mask_arr[i % 4] + return unmasked_arr.tobytes() + + +if os.environ.get("TORNADO_NO_EXTENSION") or os.environ.get("TORNADO_EXTENSION") == "0": + # These environment variables exist to make it easier to do performance + # comparisons; they are not guaranteed to remain supported in the future. + _websocket_mask = _websocket_mask_python +else: + try: + from tornado.speedups import websocket_mask as _websocket_mask + except ImportError: + if os.environ.get("TORNADO_EXTENSION") == "1": + raise + _websocket_mask = _websocket_mask_python + + +def doctests(): + # type: () -> unittest.TestSuite + import doctest + + return doctest.DocTestSuite() diff --git a/venv/lib/python3.8/site-packages/tornado/web.py b/venv/lib/python3.8/site-packages/tornado/web.py new file mode 100644 index 0000000..546e6ec --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/web.py @@ -0,0 +1,3588 @@ +# +# Copyright 2009 Facebook +# +# 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. + +"""``tornado.web`` provides a simple web framework with asynchronous +features that allow it to scale to large numbers of open connections, +making it ideal for `long polling +<http://en.wikipedia.org/wiki/Push_technology#Long_polling>`_. + +Here is a simple "Hello, world" example app: + +.. testcode:: + + import tornado.ioloop + import tornado.web + + class MainHandler(tornado.web.RequestHandler): + def get(self): + self.write("Hello, world") + + if __name__ == "__main__": + application = tornado.web.Application([ + (r"/", MainHandler), + ]) + application.listen(8888) + tornado.ioloop.IOLoop.current().start() + +.. testoutput:: + :hide: + + +See the :doc:`guide` for additional information. + +Thread-safety notes +------------------- + +In general, methods on `RequestHandler` and elsewhere in Tornado are +not thread-safe. In particular, methods such as +`~RequestHandler.write()`, `~RequestHandler.finish()`, and +`~RequestHandler.flush()` must only be called from the main thread. If +you use multiple threads it is important to use `.IOLoop.add_callback` +to transfer control back to the main thread before finishing the +request, or to limit your use of other threads to +`.IOLoop.run_in_executor` and ensure that your callbacks running in +the executor do not refer to Tornado objects. + +""" + +import base64 +import binascii +import datetime +import email.utils +import functools +import gzip +import hashlib +import hmac +import http.cookies +from inspect import isclass +from io import BytesIO +import mimetypes +import numbers +import os.path +import re +import sys +import threading +import time +import tornado +import traceback +import types +import urllib.parse +from urllib.parse import urlencode + +from tornado.concurrent import Future, future_set_result_unless_cancelled +from tornado import escape +from tornado import gen +from tornado.httpserver import HTTPServer +from tornado import httputil +from tornado import iostream +import tornado.locale +from tornado import locale +from tornado.log import access_log, app_log, gen_log +from tornado import template +from tornado.escape import utf8, _unicode +from tornado.routing import ( + AnyMatches, + DefaultHostMatches, + HostMatches, + ReversibleRouter, + Rule, + ReversibleRuleRouter, + URLSpec, + _RuleList, +) +from tornado.util import ObjectDict, unicode_type, _websocket_mask + +url = URLSpec + +from typing import ( + Dict, + Any, + Union, + Optional, + Awaitable, + Tuple, + List, + Callable, + Iterable, + Generator, + Type, + cast, + overload, +) +from types import TracebackType +import typing + +if typing.TYPE_CHECKING: + from typing import Set # noqa: F401 + + +# The following types are accepted by RequestHandler.set_header +# and related methods. +_HeaderTypes = Union[bytes, unicode_type, int, numbers.Integral, datetime.datetime] + +_CookieSecretTypes = Union[str, bytes, Dict[int, str], Dict[int, bytes]] + + +MIN_SUPPORTED_SIGNED_VALUE_VERSION = 1 +"""The oldest signed value version supported by this version of Tornado. + +Signed values older than this version cannot be decoded. + +.. versionadded:: 3.2.1 +""" + +MAX_SUPPORTED_SIGNED_VALUE_VERSION = 2 +"""The newest signed value version supported by this version of Tornado. + +Signed values newer than this version cannot be decoded. + +.. versionadded:: 3.2.1 +""" + +DEFAULT_SIGNED_VALUE_VERSION = 2 +"""The signed value version produced by `.RequestHandler.create_signed_value`. + +May be overridden by passing a ``version`` keyword argument. + +.. versionadded:: 3.2.1 +""" + +DEFAULT_SIGNED_VALUE_MIN_VERSION = 1 +"""The oldest signed value accepted by `.RequestHandler.get_secure_cookie`. + +May be overridden by passing a ``min_version`` keyword argument. + +.. versionadded:: 3.2.1 +""" + + +class _ArgDefaultMarker: + pass + + +_ARG_DEFAULT = _ArgDefaultMarker() + + +class RequestHandler(object): + """Base class for HTTP request handlers. + + Subclasses must define at least one of the methods defined in the + "Entry points" section below. + + Applications should not construct `RequestHandler` objects + directly and subclasses should not override ``__init__`` (override + `~RequestHandler.initialize` instead). + + """ + + SUPPORTED_METHODS = ("GET", "HEAD", "POST", "DELETE", "PATCH", "PUT", "OPTIONS") + + _template_loaders = {} # type: Dict[str, template.BaseLoader] + _template_loader_lock = threading.Lock() + _remove_control_chars_regex = re.compile(r"[\x00-\x08\x0e-\x1f]") + + _stream_request_body = False + + # Will be set in _execute. + _transforms = None # type: List[OutputTransform] + path_args = None # type: List[str] + path_kwargs = None # type: Dict[str, str] + + def __init__( + self, + application: "Application", + request: httputil.HTTPServerRequest, + **kwargs: Any + ) -> None: + super().__init__() + + self.application = application + self.request = request + self._headers_written = False + self._finished = False + self._auto_finish = True + self._prepared_future = None + self.ui = ObjectDict( + (n, self._ui_method(m)) for n, m in application.ui_methods.items() + ) + # UIModules are available as both `modules` and `_tt_modules` in the + # template namespace. Historically only `modules` was available + # but could be clobbered by user additions to the namespace. + # The template {% module %} directive looks in `_tt_modules` to avoid + # possible conflicts. + self.ui["_tt_modules"] = _UIModuleNamespace(self, application.ui_modules) + self.ui["modules"] = self.ui["_tt_modules"] + self.clear() + assert self.request.connection is not None + # TODO: need to add set_close_callback to HTTPConnection interface + self.request.connection.set_close_callback( # type: ignore + self.on_connection_close + ) + self.initialize(**kwargs) # type: ignore + + def _initialize(self) -> None: + pass + + initialize = _initialize # type: Callable[..., None] + """Hook for subclass initialization. Called for each request. + + A dictionary passed as the third argument of a ``URLSpec`` will be + supplied as keyword arguments to ``initialize()``. + + Example:: + + class ProfileHandler(RequestHandler): + def initialize(self, database): + self.database = database + + def get(self, username): + ... + + app = Application([ + (r'/user/(.*)', ProfileHandler, dict(database=database)), + ]) + """ + + @property + def settings(self) -> Dict[str, Any]: + """An alias for `self.application.settings <Application.settings>`.""" + return self.application.settings + + def _unimplemented_method(self, *args: str, **kwargs: str) -> None: + raise HTTPError(405) + + head = _unimplemented_method # type: Callable[..., Optional[Awaitable[None]]] + get = _unimplemented_method # type: Callable[..., Optional[Awaitable[None]]] + post = _unimplemented_method # type: Callable[..., Optional[Awaitable[None]]] + delete = _unimplemented_method # type: Callable[..., Optional[Awaitable[None]]] + patch = _unimplemented_method # type: Callable[..., Optional[Awaitable[None]]] + put = _unimplemented_method # type: Callable[..., Optional[Awaitable[None]]] + options = _unimplemented_method # type: Callable[..., Optional[Awaitable[None]]] + + def prepare(self) -> Optional[Awaitable[None]]: + """Called at the beginning of a request before `get`/`post`/etc. + + Override this method to perform common initialization regardless + of the request method. + + Asynchronous support: Use ``async def`` or decorate this method with + `.gen.coroutine` to make it asynchronous. + If this method returns an ``Awaitable`` execution will not proceed + until the ``Awaitable`` is done. + + .. versionadded:: 3.1 + Asynchronous support. + """ + pass + + def on_finish(self) -> None: + """Called after the end of a request. + + Override this method to perform cleanup, logging, etc. + This method is a counterpart to `prepare`. ``on_finish`` may + not produce any output, as it is called after the response + has been sent to the client. + """ + pass + + def on_connection_close(self) -> None: + """Called in async handlers if the client closed the connection. + + Override this to clean up resources associated with + long-lived connections. Note that this method is called only if + the connection was closed during asynchronous processing; if you + need to do cleanup after every request override `on_finish` + instead. + + Proxies may keep a connection open for a time (perhaps + indefinitely) after the client has gone away, so this method + may not be called promptly after the end user closes their + connection. + """ + if _has_stream_request_body(self.__class__): + if not self.request._body_future.done(): + self.request._body_future.set_exception(iostream.StreamClosedError()) + self.request._body_future.exception() + + def clear(self) -> None: + """Resets all headers and content for this response.""" + self._headers = httputil.HTTPHeaders( + { + "Server": "TornadoServer/%s" % tornado.version, + "Content-Type": "text/html; charset=UTF-8", + "Date": httputil.format_timestamp(time.time()), + } + ) + self.set_default_headers() + self._write_buffer = [] # type: List[bytes] + self._status_code = 200 + self._reason = httputil.responses[200] + + def set_default_headers(self) -> None: + """Override this to set HTTP headers at the beginning of the request. + + For example, this is the place to set a custom ``Server`` header. + Note that setting such headers in the normal flow of request + processing may not do what you want, since headers may be reset + during error handling. + """ + pass + + def set_status(self, status_code: int, reason: Optional[str] = None) -> None: + """Sets the status code for our response. + + :arg int status_code: Response status code. + :arg str reason: Human-readable reason phrase describing the status + code. If ``None``, it will be filled in from + `http.client.responses` or "Unknown". + + .. versionchanged:: 5.0 + + No longer validates that the response code is in + `http.client.responses`. + """ + self._status_code = status_code + if reason is not None: + self._reason = escape.native_str(reason) + else: + self._reason = httputil.responses.get(status_code, "Unknown") + + def get_status(self) -> int: + """Returns the status code for our response.""" + return self._status_code + + def set_header(self, name: str, value: _HeaderTypes) -> None: + """Sets the given response header name and value. + + All header values are converted to strings (`datetime` objects + are formatted according to the HTTP specification for the + ``Date`` header). + + """ + self._headers[name] = self._convert_header_value(value) + + def add_header(self, name: str, value: _HeaderTypes) -> None: + """Adds the given response header and value. + + Unlike `set_header`, `add_header` may be called multiple times + to return multiple values for the same header. + """ + self._headers.add(name, self._convert_header_value(value)) + + def clear_header(self, name: str) -> None: + """Clears an outgoing header, undoing a previous `set_header` call. + + Note that this method does not apply to multi-valued headers + set by `add_header`. + """ + if name in self._headers: + del self._headers[name] + + _INVALID_HEADER_CHAR_RE = re.compile(r"[\x00-\x1f]") + + def _convert_header_value(self, value: _HeaderTypes) -> str: + # Convert the input value to a str. This type check is a bit + # subtle: The bytes case only executes on python 3, and the + # unicode case only executes on python 2, because the other + # cases are covered by the first match for str. + if isinstance(value, str): + retval = value + elif isinstance(value, bytes): # py3 + # Non-ascii characters in headers are not well supported, + # but if you pass bytes, use latin1 so they pass through as-is. + retval = value.decode("latin1") + elif isinstance(value, unicode_type): # py2 + # TODO: This is inconsistent with the use of latin1 above, + # but it's been that way for a long time. Should it change? + retval = escape.utf8(value) + elif isinstance(value, numbers.Integral): + # return immediately since we know the converted value will be safe + return str(value) + elif isinstance(value, datetime.datetime): + return httputil.format_timestamp(value) + else: + raise TypeError("Unsupported header value %r" % value) + # If \n is allowed into the header, it is possible to inject + # additional headers or split the request. + if RequestHandler._INVALID_HEADER_CHAR_RE.search(retval): + raise ValueError("Unsafe header value %r", retval) + return retval + + @overload + def get_argument(self, name: str, default: str, strip: bool = True) -> str: + pass + + @overload + def get_argument( # noqa: F811 + self, name: str, default: _ArgDefaultMarker = _ARG_DEFAULT, strip: bool = True + ) -> str: + pass + + @overload + def get_argument( # noqa: F811 + self, name: str, default: None, strip: bool = True + ) -> Optional[str]: + pass + + def get_argument( # noqa: F811 + self, + name: str, + default: Union[None, str, _ArgDefaultMarker] = _ARG_DEFAULT, + strip: bool = True, + ) -> Optional[str]: + """Returns the value of the argument with the given name. + + If default is not provided, the argument is considered to be + required, and we raise a `MissingArgumentError` if it is missing. + + If the argument appears in the request more than once, we return the + last value. + + This method searches both the query and body arguments. + """ + return self._get_argument(name, default, self.request.arguments, strip) + + def get_arguments(self, name: str, strip: bool = True) -> List[str]: + """Returns a list of the arguments with the given name. + + If the argument is not present, returns an empty list. + + This method searches both the query and body arguments. + """ + + # Make sure `get_arguments` isn't accidentally being called with a + # positional argument that's assumed to be a default (like in + # `get_argument`.) + assert isinstance(strip, bool) + + return self._get_arguments(name, self.request.arguments, strip) + + def get_body_argument( + self, + name: str, + default: Union[None, str, _ArgDefaultMarker] = _ARG_DEFAULT, + strip: bool = True, + ) -> Optional[str]: + """Returns the value of the argument with the given name + from the request body. + + If default is not provided, the argument is considered to be + required, and we raise a `MissingArgumentError` if it is missing. + + If the argument appears in the url more than once, we return the + last value. + + .. versionadded:: 3.2 + """ + return self._get_argument(name, default, self.request.body_arguments, strip) + + def get_body_arguments(self, name: str, strip: bool = True) -> List[str]: + """Returns a list of the body arguments with the given name. + + If the argument is not present, returns an empty list. + + .. versionadded:: 3.2 + """ + return self._get_arguments(name, self.request.body_arguments, strip) + + def get_query_argument( + self, + name: str, + default: Union[None, str, _ArgDefaultMarker] = _ARG_DEFAULT, + strip: bool = True, + ) -> Optional[str]: + """Returns the value of the argument with the given name + from the request query string. + + If default is not provided, the argument is considered to be + required, and we raise a `MissingArgumentError` if it is missing. + + If the argument appears in the url more than once, we return the + last value. + + .. versionadded:: 3.2 + """ + return self._get_argument(name, default, self.request.query_arguments, strip) + + def get_query_arguments(self, name: str, strip: bool = True) -> List[str]: + """Returns a list of the query arguments with the given name. + + If the argument is not present, returns an empty list. + + .. versionadded:: 3.2 + """ + return self._get_arguments(name, self.request.query_arguments, strip) + + def _get_argument( + self, + name: str, + default: Union[None, str, _ArgDefaultMarker], + source: Dict[str, List[bytes]], + strip: bool = True, + ) -> Optional[str]: + args = self._get_arguments(name, source, strip=strip) + if not args: + if isinstance(default, _ArgDefaultMarker): + raise MissingArgumentError(name) + return default + return args[-1] + + def _get_arguments( + self, name: str, source: Dict[str, List[bytes]], strip: bool = True + ) -> List[str]: + values = [] + for v in source.get(name, []): + s = self.decode_argument(v, name=name) + if isinstance(s, unicode_type): + # Get rid of any weird control chars (unless decoding gave + # us bytes, in which case leave it alone) + s = RequestHandler._remove_control_chars_regex.sub(" ", s) + if strip: + s = s.strip() + values.append(s) + return values + + def decode_argument(self, value: bytes, name: Optional[str] = None) -> str: + """Decodes an argument from the request. + + The argument has been percent-decoded and is now a byte string. + By default, this method decodes the argument as utf-8 and returns + a unicode string, but this may be overridden in subclasses. + + This method is used as a filter for both `get_argument()` and for + values extracted from the url and passed to `get()`/`post()`/etc. + + The name of the argument is provided if known, but may be None + (e.g. for unnamed groups in the url regex). + """ + try: + return _unicode(value) + except UnicodeDecodeError: + raise HTTPError( + 400, "Invalid unicode in %s: %r" % (name or "url", value[:40]) + ) + + @property + def cookies(self) -> Dict[str, http.cookies.Morsel]: + """An alias for + `self.request.cookies <.httputil.HTTPServerRequest.cookies>`.""" + return self.request.cookies + + def get_cookie(self, name: str, default: Optional[str] = None) -> Optional[str]: + """Returns the value of the request cookie with the given name. + + If the named cookie is not present, returns ``default``. + + This method only returns cookies that were present in the request. + It does not see the outgoing cookies set by `set_cookie` in this + handler. + """ + if self.request.cookies is not None and name in self.request.cookies: + return self.request.cookies[name].value + return default + + def set_cookie( + self, + name: str, + value: Union[str, bytes], + domain: Optional[str] = None, + expires: Optional[Union[float, Tuple, datetime.datetime]] = None, + path: str = "/", + expires_days: Optional[float] = None, + **kwargs: Any + ) -> None: + """Sets an outgoing cookie name/value with the given options. + + Newly-set cookies are not immediately visible via `get_cookie`; + they are not present until the next request. + + expires may be a numeric timestamp as returned by `time.time`, + a time tuple as returned by `time.gmtime`, or a + `datetime.datetime` object. + + Additional keyword arguments are set on the cookies.Morsel + directly. + See https://docs.python.org/3/library/http.cookies.html#http.cookies.Morsel + for available attributes. + """ + # The cookie library only accepts type str, in both python 2 and 3 + name = escape.native_str(name) + value = escape.native_str(value) + if re.search(r"[\x00-\x20]", name + value): + # Don't let us accidentally inject bad stuff + raise ValueError("Invalid cookie %r: %r" % (name, value)) + if not hasattr(self, "_new_cookie"): + self._new_cookie = ( + http.cookies.SimpleCookie() + ) # type: http.cookies.SimpleCookie + if name in self._new_cookie: + del self._new_cookie[name] + self._new_cookie[name] = value + morsel = self._new_cookie[name] + if domain: + morsel["domain"] = domain + if expires_days is not None and not expires: + expires = datetime.datetime.utcnow() + datetime.timedelta(days=expires_days) + if expires: + morsel["expires"] = httputil.format_timestamp(expires) + if path: + morsel["path"] = path + for k, v in kwargs.items(): + if k == "max_age": + k = "max-age" + + # skip falsy values for httponly and secure flags because + # SimpleCookie sets them regardless + if k in ["httponly", "secure"] and not v: + continue + + morsel[k] = v + + def clear_cookie( + self, name: str, path: str = "/", domain: Optional[str] = None + ) -> None: + """Deletes the cookie with the given name. + + Due to limitations of the cookie protocol, you must pass the same + path and domain to clear a cookie as were used when that cookie + was set (but there is no way to find out on the server side + which values were used for a given cookie). + + Similar to `set_cookie`, the effect of this method will not be + seen until the following request. + """ + expires = datetime.datetime.utcnow() - datetime.timedelta(days=365) + self.set_cookie(name, value="", path=path, expires=expires, domain=domain) + + def clear_all_cookies(self, path: str = "/", domain: Optional[str] = None) -> None: + """Deletes all the cookies the user sent with this request. + + See `clear_cookie` for more information on the path and domain + parameters. + + Similar to `set_cookie`, the effect of this method will not be + seen until the following request. + + .. versionchanged:: 3.2 + + Added the ``path`` and ``domain`` parameters. + """ + for name in self.request.cookies: + self.clear_cookie(name, path=path, domain=domain) + + def set_secure_cookie( + self, + name: str, + value: Union[str, bytes], + expires_days: Optional[float] = 30, + version: Optional[int] = None, + **kwargs: Any + ) -> None: + """Signs and timestamps a cookie so it cannot be forged. + + You must specify the ``cookie_secret`` setting in your Application + to use this method. It should be a long, random sequence of bytes + to be used as the HMAC secret for the signature. + + To read a cookie set with this method, use `get_secure_cookie()`. + + Note that the ``expires_days`` parameter sets the lifetime of the + cookie in the browser, but is independent of the ``max_age_days`` + parameter to `get_secure_cookie`. + A value of None limits the lifetime to the current browser session. + + Secure cookies may contain arbitrary byte values, not just unicode + strings (unlike regular cookies) + + Similar to `set_cookie`, the effect of this method will not be + seen until the following request. + + .. versionchanged:: 3.2.1 + + Added the ``version`` argument. Introduced cookie version 2 + and made it the default. + """ + self.set_cookie( + name, + self.create_signed_value(name, value, version=version), + expires_days=expires_days, + **kwargs + ) + + def create_signed_value( + self, name: str, value: Union[str, bytes], version: Optional[int] = None + ) -> bytes: + """Signs and timestamps a string so it cannot be forged. + + Normally used via set_secure_cookie, but provided as a separate + method for non-cookie uses. To decode a value not stored + as a cookie use the optional value argument to get_secure_cookie. + + .. versionchanged:: 3.2.1 + + Added the ``version`` argument. Introduced cookie version 2 + and made it the default. + """ + self.require_setting("cookie_secret", "secure cookies") + secret = self.application.settings["cookie_secret"] + key_version = None + if isinstance(secret, dict): + if self.application.settings.get("key_version") is None: + raise Exception("key_version setting must be used for secret_key dicts") + key_version = self.application.settings["key_version"] + + return create_signed_value( + secret, name, value, version=version, key_version=key_version + ) + + def get_secure_cookie( + self, + name: str, + value: Optional[str] = None, + max_age_days: float = 31, + min_version: Optional[int] = None, + ) -> Optional[bytes]: + """Returns the given signed cookie if it validates, or None. + + The decoded cookie value is returned as a byte string (unlike + `get_cookie`). + + Similar to `get_cookie`, this method only returns cookies that + were present in the request. It does not see outgoing cookies set by + `set_secure_cookie` in this handler. + + .. versionchanged:: 3.2.1 + + Added the ``min_version`` argument. Introduced cookie version 2; + both versions 1 and 2 are accepted by default. + """ + self.require_setting("cookie_secret", "secure cookies") + if value is None: + value = self.get_cookie(name) + return decode_signed_value( + self.application.settings["cookie_secret"], + name, + value, + max_age_days=max_age_days, + min_version=min_version, + ) + + def get_secure_cookie_key_version( + self, name: str, value: Optional[str] = None + ) -> Optional[int]: + """Returns the signing key version of the secure cookie. + + The version is returned as int. + """ + self.require_setting("cookie_secret", "secure cookies") + if value is None: + value = self.get_cookie(name) + if value is None: + return None + return get_signature_key_version(value) + + def redirect( + self, url: str, permanent: bool = False, status: Optional[int] = None + ) -> None: + """Sends a redirect to the given (optionally relative) URL. + + If the ``status`` argument is specified, that value is used as the + HTTP status code; otherwise either 301 (permanent) or 302 + (temporary) is chosen based on the ``permanent`` argument. + The default is 302 (temporary). + """ + if self._headers_written: + raise Exception("Cannot redirect after headers have been written") + if status is None: + status = 301 if permanent else 302 + else: + assert isinstance(status, int) and 300 <= status <= 399 + self.set_status(status) + self.set_header("Location", utf8(url)) + self.finish() + + def write(self, chunk: Union[str, bytes, dict]) -> None: + """Writes the given chunk to the output buffer. + + To write the output to the network, use the `flush()` method below. + + If the given chunk is a dictionary, we write it as JSON and set + the Content-Type of the response to be ``application/json``. + (if you want to send JSON as a different ``Content-Type``, call + ``set_header`` *after* calling ``write()``). + + Note that lists are not converted to JSON because of a potential + cross-site security vulnerability. All JSON output should be + wrapped in a dictionary. More details at + http://haacked.com/archive/2009/06/25/json-hijacking.aspx/ and + https://github.com/facebook/tornado/issues/1009 + """ + if self._finished: + raise RuntimeError("Cannot write() after finish()") + if not isinstance(chunk, (bytes, unicode_type, dict)): + message = "write() only accepts bytes, unicode, and dict objects" + if isinstance(chunk, list): + message += ( + ". Lists not accepted for security reasons; see " + + "http://www.tornadoweb.org/en/stable/web.html#tornado.web.RequestHandler.write" # noqa: E501 + ) + raise TypeError(message) + if isinstance(chunk, dict): + chunk = escape.json_encode(chunk) + self.set_header("Content-Type", "application/json; charset=UTF-8") + chunk = utf8(chunk) + self._write_buffer.append(chunk) + + def render(self, template_name: str, **kwargs: Any) -> "Future[None]": + """Renders the template with the given arguments as the response. + + ``render()`` calls ``finish()``, so no other output methods can be called + after it. + + Returns a `.Future` with the same semantics as the one returned by `finish`. + Awaiting this `.Future` is optional. + + .. versionchanged:: 5.1 + + Now returns a `.Future` instead of ``None``. + """ + if self._finished: + raise RuntimeError("Cannot render() after finish()") + html = self.render_string(template_name, **kwargs) + + # Insert the additional JS and CSS added by the modules on the page + js_embed = [] + js_files = [] + css_embed = [] + css_files = [] + html_heads = [] + html_bodies = [] + for module in getattr(self, "_active_modules", {}).values(): + embed_part = module.embedded_javascript() + if embed_part: + js_embed.append(utf8(embed_part)) + file_part = module.javascript_files() + if file_part: + if isinstance(file_part, (unicode_type, bytes)): + js_files.append(_unicode(file_part)) + else: + js_files.extend(file_part) + embed_part = module.embedded_css() + if embed_part: + css_embed.append(utf8(embed_part)) + file_part = module.css_files() + if file_part: + if isinstance(file_part, (unicode_type, bytes)): + css_files.append(_unicode(file_part)) + else: + css_files.extend(file_part) + head_part = module.html_head() + if head_part: + html_heads.append(utf8(head_part)) + body_part = module.html_body() + if body_part: + html_bodies.append(utf8(body_part)) + + if js_files: + # Maintain order of JavaScript files given by modules + js = self.render_linked_js(js_files) + sloc = html.rindex(b"</body>") + html = html[:sloc] + utf8(js) + b"\n" + html[sloc:] + if js_embed: + js_bytes = self.render_embed_js(js_embed) + sloc = html.rindex(b"</body>") + html = html[:sloc] + js_bytes + b"\n" + html[sloc:] + if css_files: + css = self.render_linked_css(css_files) + hloc = html.index(b"</head>") + html = html[:hloc] + utf8(css) + b"\n" + html[hloc:] + if css_embed: + css_bytes = self.render_embed_css(css_embed) + hloc = html.index(b"</head>") + html = html[:hloc] + css_bytes + b"\n" + html[hloc:] + if html_heads: + hloc = html.index(b"</head>") + html = html[:hloc] + b"".join(html_heads) + b"\n" + html[hloc:] + if html_bodies: + hloc = html.index(b"</body>") + html = html[:hloc] + b"".join(html_bodies) + b"\n" + html[hloc:] + return self.finish(html) + + def render_linked_js(self, js_files: Iterable[str]) -> str: + """Default method used to render the final js links for the + rendered webpage. + + Override this method in a sub-classed controller to change the output. + """ + paths = [] + unique_paths = set() # type: Set[str] + + for path in js_files: + if not is_absolute(path): + path = self.static_url(path) + if path not in unique_paths: + paths.append(path) + unique_paths.add(path) + + return "".join( + '<script src="' + + escape.xhtml_escape(p) + + '" type="text/javascript"></script>' + for p in paths + ) + + def render_embed_js(self, js_embed: Iterable[bytes]) -> bytes: + """Default method used to render the final embedded js for the + rendered webpage. + + Override this method in a sub-classed controller to change the output. + """ + return ( + b'<script type="text/javascript">\n//<![CDATA[\n' + + b"\n".join(js_embed) + + b"\n//]]>\n</script>" + ) + + def render_linked_css(self, css_files: Iterable[str]) -> str: + """Default method used to render the final css links for the + rendered webpage. + + Override this method in a sub-classed controller to change the output. + """ + paths = [] + unique_paths = set() # type: Set[str] + + for path in css_files: + if not is_absolute(path): + path = self.static_url(path) + if path not in unique_paths: + paths.append(path) + unique_paths.add(path) + + return "".join( + '<link href="' + escape.xhtml_escape(p) + '" ' + 'type="text/css" rel="stylesheet"/>' + for p in paths + ) + + def render_embed_css(self, css_embed: Iterable[bytes]) -> bytes: + """Default method used to render the final embedded css for the + rendered webpage. + + Override this method in a sub-classed controller to change the output. + """ + return b'<style type="text/css">\n' + b"\n".join(css_embed) + b"\n</style>" + + def render_string(self, template_name: str, **kwargs: Any) -> bytes: + """Generate the given template with the given arguments. + + We return the generated byte string (in utf8). To generate and + write a template as a response, use render() above. + """ + # If no template_path is specified, use the path of the calling file + template_path = self.get_template_path() + if not template_path: + frame = sys._getframe(0) + web_file = frame.f_code.co_filename + while frame.f_code.co_filename == web_file: + frame = frame.f_back + assert frame.f_code.co_filename is not None + template_path = os.path.dirname(frame.f_code.co_filename) + with RequestHandler._template_loader_lock: + if template_path not in RequestHandler._template_loaders: + loader = self.create_template_loader(template_path) + RequestHandler._template_loaders[template_path] = loader + else: + loader = RequestHandler._template_loaders[template_path] + t = loader.load(template_name) + namespace = self.get_template_namespace() + namespace.update(kwargs) + return t.generate(**namespace) + + def get_template_namespace(self) -> Dict[str, Any]: + """Returns a dictionary to be used as the default template namespace. + + May be overridden by subclasses to add or modify values. + + The results of this method will be combined with additional + defaults in the `tornado.template` module and keyword arguments + to `render` or `render_string`. + """ + namespace = dict( + handler=self, + request=self.request, + current_user=self.current_user, + locale=self.locale, + _=self.locale.translate, + pgettext=self.locale.pgettext, + static_url=self.static_url, + xsrf_form_html=self.xsrf_form_html, + reverse_url=self.reverse_url, + ) + namespace.update(self.ui) + return namespace + + def create_template_loader(self, template_path: str) -> template.BaseLoader: + """Returns a new template loader for the given path. + + May be overridden by subclasses. By default returns a + directory-based loader on the given path, using the + ``autoescape`` and ``template_whitespace`` application + settings. If a ``template_loader`` application setting is + supplied, uses that instead. + """ + settings = self.application.settings + if "template_loader" in settings: + return settings["template_loader"] + kwargs = {} + if "autoescape" in settings: + # autoescape=None means "no escaping", so we have to be sure + # to only pass this kwarg if the user asked for it. + kwargs["autoescape"] = settings["autoescape"] + if "template_whitespace" in settings: + kwargs["whitespace"] = settings["template_whitespace"] + return template.Loader(template_path, **kwargs) + + def flush(self, include_footers: bool = False) -> "Future[None]": + """Flushes the current output buffer to the network. + + .. versionchanged:: 4.0 + Now returns a `.Future` if no callback is given. + + .. versionchanged:: 6.0 + + The ``callback`` argument was removed. + """ + assert self.request.connection is not None + chunk = b"".join(self._write_buffer) + self._write_buffer = [] + if not self._headers_written: + self._headers_written = True + for transform in self._transforms: + assert chunk is not None + ( + self._status_code, + self._headers, + chunk, + ) = transform.transform_first_chunk( + self._status_code, self._headers, chunk, include_footers + ) + # Ignore the chunk and only write the headers for HEAD requests + if self.request.method == "HEAD": + chunk = b"" + + # Finalize the cookie headers (which have been stored in a side + # object so an outgoing cookie could be overwritten before it + # is sent). + if hasattr(self, "_new_cookie"): + for cookie in self._new_cookie.values(): + self.add_header("Set-Cookie", cookie.OutputString(None)) + + start_line = httputil.ResponseStartLine("", self._status_code, self._reason) + return self.request.connection.write_headers( + start_line, self._headers, chunk + ) + else: + for transform in self._transforms: + chunk = transform.transform_chunk(chunk, include_footers) + # Ignore the chunk and only write the headers for HEAD requests + if self.request.method != "HEAD": + return self.request.connection.write(chunk) + else: + future = Future() # type: Future[None] + future.set_result(None) + return future + + def finish(self, chunk: Optional[Union[str, bytes, dict]] = None) -> "Future[None]": + """Finishes this response, ending the HTTP request. + + Passing a ``chunk`` to ``finish()`` is equivalent to passing that + chunk to ``write()`` and then calling ``finish()`` with no arguments. + + Returns a `.Future` which may optionally be awaited to track the sending + of the response to the client. This `.Future` resolves when all the response + data has been sent, and raises an error if the connection is closed before all + data can be sent. + + .. versionchanged:: 5.1 + + Now returns a `.Future` instead of ``None``. + """ + if self._finished: + raise RuntimeError("finish() called twice") + + if chunk is not None: + self.write(chunk) + + # Automatically support ETags and add the Content-Length header if + # we have not flushed any content yet. + if not self._headers_written: + if ( + self._status_code == 200 + and self.request.method in ("GET", "HEAD") + and "Etag" not in self._headers + ): + self.set_etag_header() + if self.check_etag_header(): + self._write_buffer = [] + self.set_status(304) + if self._status_code in (204, 304) or (100 <= self._status_code < 200): + assert not self._write_buffer, ( + "Cannot send body with %s" % self._status_code + ) + self._clear_representation_headers() + elif "Content-Length" not in self._headers: + content_length = sum(len(part) for part in self._write_buffer) + self.set_header("Content-Length", content_length) + + assert self.request.connection is not None + # Now that the request is finished, clear the callback we + # set on the HTTPConnection (which would otherwise prevent the + # garbage collection of the RequestHandler when there + # are keepalive connections) + self.request.connection.set_close_callback(None) # type: ignore + + future = self.flush(include_footers=True) + self.request.connection.finish() + self._log() + self._finished = True + self.on_finish() + self._break_cycles() + return future + + def detach(self) -> iostream.IOStream: + """Take control of the underlying stream. + + Returns the underlying `.IOStream` object and stops all + further HTTP processing. Intended for implementing protocols + like websockets that tunnel over an HTTP handshake. + + This method is only supported when HTTP/1.1 is used. + + .. versionadded:: 5.1 + """ + self._finished = True + # TODO: add detach to HTTPConnection? + return self.request.connection.detach() # type: ignore + + def _break_cycles(self) -> None: + # Break up a reference cycle between this handler and the + # _ui_module closures to allow for faster GC on CPython. + self.ui = None # type: ignore + + def send_error(self, status_code: int = 500, **kwargs: Any) -> None: + """Sends the given HTTP error code to the browser. + + If `flush()` has already been called, it is not possible to send + an error, so this method will simply terminate the response. + If output has been written but not yet flushed, it will be discarded + and replaced with the error page. + + Override `write_error()` to customize the error page that is returned. + Additional keyword arguments are passed through to `write_error`. + """ + if self._headers_written: + gen_log.error("Cannot send error response after headers written") + if not self._finished: + # If we get an error between writing headers and finishing, + # we are unlikely to be able to finish due to a + # Content-Length mismatch. Try anyway to release the + # socket. + try: + self.finish() + except Exception: + gen_log.error("Failed to flush partial response", exc_info=True) + return + self.clear() + + reason = kwargs.get("reason") + if "exc_info" in kwargs: + exception = kwargs["exc_info"][1] + if isinstance(exception, HTTPError) and exception.reason: + reason = exception.reason + self.set_status(status_code, reason=reason) + try: + self.write_error(status_code, **kwargs) + except Exception: + app_log.error("Uncaught exception in write_error", exc_info=True) + if not self._finished: + self.finish() + + def write_error(self, status_code: int, **kwargs: Any) -> None: + """Override to implement custom error pages. + + ``write_error`` may call `write`, `render`, `set_header`, etc + to produce output as usual. + + If this error was caused by an uncaught exception (including + HTTPError), an ``exc_info`` triple will be available as + ``kwargs["exc_info"]``. Note that this exception may not be + the "current" exception for purposes of methods like + ``sys.exc_info()`` or ``traceback.format_exc``. + """ + if self.settings.get("serve_traceback") and "exc_info" in kwargs: + # in debug mode, try to send a traceback + self.set_header("Content-Type", "text/plain") + for line in traceback.format_exception(*kwargs["exc_info"]): + self.write(line) + self.finish() + else: + self.finish( + "<html><title>%(code)d: %(message)s</title>" + "<body>%(code)d: %(message)s</body></html>" + % {"code": status_code, "message": self._reason} + ) + + @property + def locale(self) -> tornado.locale.Locale: + """The locale for the current session. + + Determined by either `get_user_locale`, which you can override to + set the locale based on, e.g., a user preference stored in a + database, or `get_browser_locale`, which uses the ``Accept-Language`` + header. + + .. versionchanged: 4.1 + Added a property setter. + """ + if not hasattr(self, "_locale"): + loc = self.get_user_locale() + if loc is not None: + self._locale = loc + else: + self._locale = self.get_browser_locale() + assert self._locale + return self._locale + + @locale.setter + def locale(self, value: tornado.locale.Locale) -> None: + self._locale = value + + def get_user_locale(self) -> Optional[tornado.locale.Locale]: + """Override to determine the locale from the authenticated user. + + If None is returned, we fall back to `get_browser_locale()`. + + This method should return a `tornado.locale.Locale` object, + most likely obtained via a call like ``tornado.locale.get("en")`` + """ + return None + + def get_browser_locale(self, default: str = "en_US") -> tornado.locale.Locale: + """Determines the user's locale from ``Accept-Language`` header. + + See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4 + """ + if "Accept-Language" in self.request.headers: + languages = self.request.headers["Accept-Language"].split(",") + locales = [] + for language in languages: + parts = language.strip().split(";") + if len(parts) > 1 and parts[1].startswith("q="): + try: + score = float(parts[1][2:]) + except (ValueError, TypeError): + score = 0.0 + else: + score = 1.0 + locales.append((parts[0], score)) + if locales: + locales.sort(key=lambda pair: pair[1], reverse=True) + codes = [loc[0] for loc in locales] + return locale.get(*codes) + return locale.get(default) + + @property + def current_user(self) -> Any: + """The authenticated user for this request. + + This is set in one of two ways: + + * A subclass may override `get_current_user()`, which will be called + automatically the first time ``self.current_user`` is accessed. + `get_current_user()` will only be called once per request, + and is cached for future access:: + + def get_current_user(self): + user_cookie = self.get_secure_cookie("user") + if user_cookie: + return json.loads(user_cookie) + return None + + * It may be set as a normal variable, typically from an overridden + `prepare()`:: + + @gen.coroutine + def prepare(self): + user_id_cookie = self.get_secure_cookie("user_id") + if user_id_cookie: + self.current_user = yield load_user(user_id_cookie) + + Note that `prepare()` may be a coroutine while `get_current_user()` + may not, so the latter form is necessary if loading the user requires + asynchronous operations. + + The user object may be any type of the application's choosing. + """ + if not hasattr(self, "_current_user"): + self._current_user = self.get_current_user() + return self._current_user + + @current_user.setter + def current_user(self, value: Any) -> None: + self._current_user = value + + def get_current_user(self) -> Any: + """Override to determine the current user from, e.g., a cookie. + + This method may not be a coroutine. + """ + return None + + def get_login_url(self) -> str: + """Override to customize the login URL based on the request. + + By default, we use the ``login_url`` application setting. + """ + self.require_setting("login_url", "@tornado.web.authenticated") + return self.application.settings["login_url"] + + def get_template_path(self) -> Optional[str]: + """Override to customize template path for each handler. + + By default, we use the ``template_path`` application setting. + Return None to load templates relative to the calling file. + """ + return self.application.settings.get("template_path") + + @property + def xsrf_token(self) -> bytes: + """The XSRF-prevention token for the current user/session. + + To prevent cross-site request forgery, we set an '_xsrf' cookie + and include the same '_xsrf' value as an argument with all POST + requests. If the two do not match, we reject the form submission + as a potential forgery. + + See http://en.wikipedia.org/wiki/Cross-site_request_forgery + + This property is of type `bytes`, but it contains only ASCII + characters. If a character string is required, there is no + need to base64-encode it; just decode the byte string as + UTF-8. + + .. versionchanged:: 3.2.2 + The xsrf token will now be have a random mask applied in every + request, which makes it safe to include the token in pages + that are compressed. See http://breachattack.com for more + information on the issue fixed by this change. Old (version 1) + cookies will be converted to version 2 when this method is called + unless the ``xsrf_cookie_version`` `Application` setting is + set to 1. + + .. versionchanged:: 4.3 + The ``xsrf_cookie_kwargs`` `Application` setting may be + used to supply additional cookie options (which will be + passed directly to `set_cookie`). For example, + ``xsrf_cookie_kwargs=dict(httponly=True, secure=True)`` + will set the ``secure`` and ``httponly`` flags on the + ``_xsrf`` cookie. + """ + if not hasattr(self, "_xsrf_token"): + version, token, timestamp = self._get_raw_xsrf_token() + output_version = self.settings.get("xsrf_cookie_version", 2) + cookie_kwargs = self.settings.get("xsrf_cookie_kwargs", {}) + if output_version == 1: + self._xsrf_token = binascii.b2a_hex(token) + elif output_version == 2: + mask = os.urandom(4) + self._xsrf_token = b"|".join( + [ + b"2", + binascii.b2a_hex(mask), + binascii.b2a_hex(_websocket_mask(mask, token)), + utf8(str(int(timestamp))), + ] + ) + else: + raise ValueError("unknown xsrf cookie version %d", output_version) + if version is None: + if self.current_user and "expires_days" not in cookie_kwargs: + cookie_kwargs["expires_days"] = 30 + self.set_cookie("_xsrf", self._xsrf_token, **cookie_kwargs) + return self._xsrf_token + + def _get_raw_xsrf_token(self) -> Tuple[Optional[int], bytes, float]: + """Read or generate the xsrf token in its raw form. + + The raw_xsrf_token is a tuple containing: + + * version: the version of the cookie from which this token was read, + or None if we generated a new token in this request. + * token: the raw token data; random (non-ascii) bytes. + * timestamp: the time this token was generated (will not be accurate + for version 1 cookies) + """ + if not hasattr(self, "_raw_xsrf_token"): + cookie = self.get_cookie("_xsrf") + if cookie: + version, token, timestamp = self._decode_xsrf_token(cookie) + else: + version, token, timestamp = None, None, None + if token is None: + version = None + token = os.urandom(16) + timestamp = time.time() + assert token is not None + assert timestamp is not None + self._raw_xsrf_token = (version, token, timestamp) + return self._raw_xsrf_token + + def _decode_xsrf_token( + self, cookie: str + ) -> Tuple[Optional[int], Optional[bytes], Optional[float]]: + """Convert a cookie string into a the tuple form returned by + _get_raw_xsrf_token. + """ + + try: + m = _signed_value_version_re.match(utf8(cookie)) + + if m: + version = int(m.group(1)) + if version == 2: + _, mask_str, masked_token, timestamp_str = cookie.split("|") + + mask = binascii.a2b_hex(utf8(mask_str)) + token = _websocket_mask(mask, binascii.a2b_hex(utf8(masked_token))) + timestamp = int(timestamp_str) + return version, token, timestamp + else: + # Treat unknown versions as not present instead of failing. + raise Exception("Unknown xsrf cookie version") + else: + version = 1 + try: + token = binascii.a2b_hex(utf8(cookie)) + except (binascii.Error, TypeError): + token = utf8(cookie) + # We don't have a usable timestamp in older versions. + timestamp = int(time.time()) + return (version, token, timestamp) + except Exception: + # Catch exceptions and return nothing instead of failing. + gen_log.debug("Uncaught exception in _decode_xsrf_token", exc_info=True) + return None, None, None + + def check_xsrf_cookie(self) -> None: + """Verifies that the ``_xsrf`` cookie matches the ``_xsrf`` argument. + + To prevent cross-site request forgery, we set an ``_xsrf`` + cookie and include the same value as a non-cookie + field with all ``POST`` requests. If the two do not match, we + reject the form submission as a potential forgery. + + The ``_xsrf`` value may be set as either a form field named ``_xsrf`` + or in a custom HTTP header named ``X-XSRFToken`` or ``X-CSRFToken`` + (the latter is accepted for compatibility with Django). + + See http://en.wikipedia.org/wiki/Cross-site_request_forgery + + .. versionchanged:: 3.2.2 + Added support for cookie version 2. Both versions 1 and 2 are + supported. + """ + # Prior to release 1.1.1, this check was ignored if the HTTP header + # ``X-Requested-With: XMLHTTPRequest`` was present. This exception + # has been shown to be insecure and has been removed. For more + # information please see + # http://www.djangoproject.com/weblog/2011/feb/08/security/ + # http://weblog.rubyonrails.org/2011/2/8/csrf-protection-bypass-in-ruby-on-rails + token = ( + self.get_argument("_xsrf", None) + or self.request.headers.get("X-Xsrftoken") + or self.request.headers.get("X-Csrftoken") + ) + if not token: + raise HTTPError(403, "'_xsrf' argument missing from POST") + _, token, _ = self._decode_xsrf_token(token) + _, expected_token, _ = self._get_raw_xsrf_token() + if not token: + raise HTTPError(403, "'_xsrf' argument has invalid format") + if not hmac.compare_digest(utf8(token), utf8(expected_token)): + raise HTTPError(403, "XSRF cookie does not match POST argument") + + def xsrf_form_html(self) -> str: + """An HTML ``<input/>`` element to be included with all POST forms. + + It defines the ``_xsrf`` input value, which we check on all POST + requests to prevent cross-site request forgery. If you have set + the ``xsrf_cookies`` application setting, you must include this + HTML within all of your HTML forms. + + In a template, this method should be called with ``{% module + xsrf_form_html() %}`` + + See `check_xsrf_cookie()` above for more information. + """ + return ( + '<input type="hidden" name="_xsrf" value="' + + escape.xhtml_escape(self.xsrf_token) + + '"/>' + ) + + def static_url( + self, path: str, include_host: Optional[bool] = None, **kwargs: Any + ) -> str: + """Returns a static URL for the given relative static file path. + + This method requires you set the ``static_path`` setting in your + application (which specifies the root directory of your static + files). + + This method returns a versioned url (by default appending + ``?v=<signature>``), which allows the static files to be + cached indefinitely. This can be disabled by passing + ``include_version=False`` (in the default implementation; + other static file implementations are not required to support + this, but they may support other options). + + By default this method returns URLs relative to the current + host, but if ``include_host`` is true the URL returned will be + absolute. If this handler has an ``include_host`` attribute, + that value will be used as the default for all `static_url` + calls that do not pass ``include_host`` as a keyword argument. + + """ + self.require_setting("static_path", "static_url") + get_url = self.settings.get( + "static_handler_class", StaticFileHandler + ).make_static_url + + if include_host is None: + include_host = getattr(self, "include_host", False) + + if include_host: + base = self.request.protocol + "://" + self.request.host + else: + base = "" + + return base + get_url(self.settings, path, **kwargs) + + def require_setting(self, name: str, feature: str = "this feature") -> None: + """Raises an exception if the given app setting is not defined.""" + if not self.application.settings.get(name): + raise Exception( + "You must define the '%s' setting in your " + "application to use %s" % (name, feature) + ) + + def reverse_url(self, name: str, *args: Any) -> str: + """Alias for `Application.reverse_url`.""" + return self.application.reverse_url(name, *args) + + def compute_etag(self) -> Optional[str]: + """Computes the etag header to be used for this request. + + By default uses a hash of the content written so far. + + May be overridden to provide custom etag implementations, + or may return None to disable tornado's default etag support. + """ + hasher = hashlib.sha1() + for part in self._write_buffer: + hasher.update(part) + return '"%s"' % hasher.hexdigest() + + def set_etag_header(self) -> None: + """Sets the response's Etag header using ``self.compute_etag()``. + + Note: no header will be set if ``compute_etag()`` returns ``None``. + + This method is called automatically when the request is finished. + """ + etag = self.compute_etag() + if etag is not None: + self.set_header("Etag", etag) + + def check_etag_header(self) -> bool: + """Checks the ``Etag`` header against requests's ``If-None-Match``. + + Returns ``True`` if the request's Etag matches and a 304 should be + returned. For example:: + + self.set_etag_header() + if self.check_etag_header(): + self.set_status(304) + return + + This method is called automatically when the request is finished, + but may be called earlier for applications that override + `compute_etag` and want to do an early check for ``If-None-Match`` + before completing the request. The ``Etag`` header should be set + (perhaps with `set_etag_header`) before calling this method. + """ + computed_etag = utf8(self._headers.get("Etag", "")) + # Find all weak and strong etag values from If-None-Match header + # because RFC 7232 allows multiple etag values in a single header. + etags = re.findall( + br'\*|(?:W/)?"[^"]*"', utf8(self.request.headers.get("If-None-Match", "")) + ) + if not computed_etag or not etags: + return False + + match = False + if etags[0] == b"*": + match = True + else: + # Use a weak comparison when comparing entity-tags. + def val(x: bytes) -> bytes: + return x[2:] if x.startswith(b"W/") else x + + for etag in etags: + if val(etag) == val(computed_etag): + match = True + break + return match + + async def _execute( + self, transforms: List["OutputTransform"], *args: bytes, **kwargs: bytes + ) -> None: + """Executes this request with the given output transforms.""" + self._transforms = transforms + try: + if self.request.method not in self.SUPPORTED_METHODS: + raise HTTPError(405) + self.path_args = [self.decode_argument(arg) for arg in args] + self.path_kwargs = dict( + (k, self.decode_argument(v, name=k)) for (k, v) in kwargs.items() + ) + # If XSRF cookies are turned on, reject form submissions without + # the proper cookie + if self.request.method not in ( + "GET", + "HEAD", + "OPTIONS", + ) and self.application.settings.get("xsrf_cookies"): + self.check_xsrf_cookie() + + result = self.prepare() + if result is not None: + result = await result + if self._prepared_future is not None: + # Tell the Application we've finished with prepare() + # and are ready for the body to arrive. + future_set_result_unless_cancelled(self._prepared_future, None) + if self._finished: + return + + if _has_stream_request_body(self.__class__): + # In streaming mode request.body is a Future that signals + # the body has been completely received. The Future has no + # result; the data has been passed to self.data_received + # instead. + try: + await self.request._body_future + except iostream.StreamClosedError: + return + + method = getattr(self, self.request.method.lower()) + result = method(*self.path_args, **self.path_kwargs) + if result is not None: + result = await result + if self._auto_finish and not self._finished: + self.finish() + except Exception as e: + try: + self._handle_request_exception(e) + except Exception: + app_log.error("Exception in exception handler", exc_info=True) + finally: + # Unset result to avoid circular references + result = None + if self._prepared_future is not None and not self._prepared_future.done(): + # In case we failed before setting _prepared_future, do it + # now (to unblock the HTTP server). Note that this is not + # in a finally block to avoid GC issues prior to Python 3.4. + self._prepared_future.set_result(None) + + def data_received(self, chunk: bytes) -> Optional[Awaitable[None]]: + """Implement this method to handle streamed request data. + + Requires the `.stream_request_body` decorator. + + May be a coroutine for flow control. + """ + raise NotImplementedError() + + def _log(self) -> None: + """Logs the current request. + + Sort of deprecated since this functionality was moved to the + Application, but left in place for the benefit of existing apps + that have overridden this method. + """ + self.application.log_request(self) + + def _request_summary(self) -> str: + return "%s %s (%s)" % ( + self.request.method, + self.request.uri, + self.request.remote_ip, + ) + + def _handle_request_exception(self, e: BaseException) -> None: + if isinstance(e, Finish): + # Not an error; just finish the request without logging. + if not self._finished: + self.finish(*e.args) + return + try: + self.log_exception(*sys.exc_info()) + except Exception: + # An error here should still get a best-effort send_error() + # to avoid leaking the connection. + app_log.error("Error in exception logger", exc_info=True) + if self._finished: + # Extra errors after the request has been finished should + # be logged, but there is no reason to continue to try and + # send a response. + return + if isinstance(e, HTTPError): + self.send_error(e.status_code, exc_info=sys.exc_info()) + else: + self.send_error(500, exc_info=sys.exc_info()) + + def log_exception( + self, + typ: "Optional[Type[BaseException]]", + value: Optional[BaseException], + tb: Optional[TracebackType], + ) -> None: + """Override to customize logging of uncaught exceptions. + + By default logs instances of `HTTPError` as warnings without + stack traces (on the ``tornado.general`` logger), and all + other exceptions as errors with stack traces (on the + ``tornado.application`` logger). + + .. versionadded:: 3.1 + """ + if isinstance(value, HTTPError): + if value.log_message: + format = "%d %s: " + value.log_message + args = [value.status_code, self._request_summary()] + list(value.args) + gen_log.warning(format, *args) + else: + app_log.error( + "Uncaught exception %s\n%r", + self._request_summary(), + self.request, + exc_info=(typ, value, tb), # type: ignore + ) + + def _ui_module(self, name: str, module: Type["UIModule"]) -> Callable[..., str]: + def render(*args, **kwargs) -> str: # type: ignore + if not hasattr(self, "_active_modules"): + self._active_modules = {} # type: Dict[str, UIModule] + if name not in self._active_modules: + self._active_modules[name] = module(self) + rendered = self._active_modules[name].render(*args, **kwargs) + return rendered + + return render + + def _ui_method(self, method: Callable[..., str]) -> Callable[..., str]: + return lambda *args, **kwargs: method(self, *args, **kwargs) + + def _clear_representation_headers(self) -> None: + # 304 responses should not contain representation metadata + # headers (defined in + # https://tools.ietf.org/html/rfc7231#section-3.1) + # not explicitly allowed by + # https://tools.ietf.org/html/rfc7232#section-4.1 + headers = ["Content-Encoding", "Content-Language", "Content-Type"] + for h in headers: + self.clear_header(h) + + +def stream_request_body(cls: Type[RequestHandler]) -> Type[RequestHandler]: + """Apply to `RequestHandler` subclasses to enable streaming body support. + + This decorator implies the following changes: + + * `.HTTPServerRequest.body` is undefined, and body arguments will not + be included in `RequestHandler.get_argument`. + * `RequestHandler.prepare` is called when the request headers have been + read instead of after the entire body has been read. + * The subclass must define a method ``data_received(self, data):``, which + will be called zero or more times as data is available. Note that + if the request has an empty body, ``data_received`` may not be called. + * ``prepare`` and ``data_received`` may return Futures (such as via + ``@gen.coroutine``, in which case the next method will not be called + until those futures have completed. + * The regular HTTP method (``post``, ``put``, etc) will be called after + the entire body has been read. + + See the `file receiver demo <https://github.com/tornadoweb/tornado/tree/master/demos/file_upload/>`_ + for example usage. + """ # noqa: E501 + if not issubclass(cls, RequestHandler): + raise TypeError("expected subclass of RequestHandler, got %r", cls) + cls._stream_request_body = True + return cls + + +def _has_stream_request_body(cls: Type[RequestHandler]) -> bool: + if not issubclass(cls, RequestHandler): + raise TypeError("expected subclass of RequestHandler, got %r", cls) + return cls._stream_request_body + + +def removeslash( + method: Callable[..., Optional[Awaitable[None]]] +) -> Callable[..., Optional[Awaitable[None]]]: + """Use this decorator to remove trailing slashes from the request path. + + For example, a request to ``/foo/`` would redirect to ``/foo`` with this + decorator. Your request handler mapping should use a regular expression + like ``r'/foo/*'`` in conjunction with using the decorator. + """ + + @functools.wraps(method) + def wrapper( # type: ignore + self: RequestHandler, *args, **kwargs + ) -> Optional[Awaitable[None]]: + if self.request.path.endswith("/"): + if self.request.method in ("GET", "HEAD"): + uri = self.request.path.rstrip("/") + if uri: # don't try to redirect '/' to '' + if self.request.query: + uri += "?" + self.request.query + self.redirect(uri, permanent=True) + return None + else: + raise HTTPError(404) + return method(self, *args, **kwargs) + + return wrapper + + +def addslash( + method: Callable[..., Optional[Awaitable[None]]] +) -> Callable[..., Optional[Awaitable[None]]]: + """Use this decorator to add a missing trailing slash to the request path. + + For example, a request to ``/foo`` would redirect to ``/foo/`` with this + decorator. Your request handler mapping should use a regular expression + like ``r'/foo/?'`` in conjunction with using the decorator. + """ + + @functools.wraps(method) + def wrapper( # type: ignore + self: RequestHandler, *args, **kwargs + ) -> Optional[Awaitable[None]]: + if not self.request.path.endswith("/"): + if self.request.method in ("GET", "HEAD"): + uri = self.request.path + "/" + if self.request.query: + uri += "?" + self.request.query + self.redirect(uri, permanent=True) + return None + raise HTTPError(404) + return method(self, *args, **kwargs) + + return wrapper + + +class _ApplicationRouter(ReversibleRuleRouter): + """Routing implementation used internally by `Application`. + + Provides a binding between `Application` and `RequestHandler`. + This implementation extends `~.routing.ReversibleRuleRouter` in a couple of ways: + * it allows to use `RequestHandler` subclasses as `~.routing.Rule` target and + * it allows to use a list/tuple of rules as `~.routing.Rule` target. + ``process_rule`` implementation will substitute this list with an appropriate + `_ApplicationRouter` instance. + """ + + def __init__( + self, application: "Application", rules: Optional[_RuleList] = None + ) -> None: + assert isinstance(application, Application) + self.application = application + super().__init__(rules) + + def process_rule(self, rule: Rule) -> Rule: + rule = super().process_rule(rule) + + if isinstance(rule.target, (list, tuple)): + rule.target = _ApplicationRouter( + self.application, rule.target # type: ignore + ) + + return rule + + def get_target_delegate( + self, target: Any, request: httputil.HTTPServerRequest, **target_params: Any + ) -> Optional[httputil.HTTPMessageDelegate]: + if isclass(target) and issubclass(target, RequestHandler): + return self.application.get_handler_delegate( + request, target, **target_params + ) + + return super().get_target_delegate(target, request, **target_params) + + +class Application(ReversibleRouter): + r"""A collection of request handlers that make up a web application. + + Instances of this class are callable and can be passed directly to + HTTPServer to serve the application:: + + application = web.Application([ + (r"/", MainPageHandler), + ]) + http_server = httpserver.HTTPServer(application) + http_server.listen(8080) + ioloop.IOLoop.current().start() + + The constructor for this class takes in a list of `~.routing.Rule` + objects or tuples of values corresponding to the arguments of + `~.routing.Rule` constructor: ``(matcher, target, [target_kwargs], [name])``, + the values in square brackets being optional. The default matcher is + `~.routing.PathMatches`, so ``(regexp, target)`` tuples can also be used + instead of ``(PathMatches(regexp), target)``. + + A common routing target is a `RequestHandler` subclass, but you can also + use lists of rules as a target, which create a nested routing configuration:: + + application = web.Application([ + (HostMatches("example.com"), [ + (r"/", MainPageHandler), + (r"/feed", FeedHandler), + ]), + ]) + + In addition to this you can use nested `~.routing.Router` instances, + `~.httputil.HTTPMessageDelegate` subclasses and callables as routing targets + (see `~.routing` module docs for more information). + + When we receive requests, we iterate over the list in order and + instantiate an instance of the first request class whose regexp + matches the request path. The request class can be specified as + either a class object or a (fully-qualified) name. + + A dictionary may be passed as the third element (``target_kwargs``) + of the tuple, which will be used as keyword arguments to the handler's + constructor and `~RequestHandler.initialize` method. This pattern + is used for the `StaticFileHandler` in this example (note that a + `StaticFileHandler` can be installed automatically with the + static_path setting described below):: + + application = web.Application([ + (r"/static/(.*)", web.StaticFileHandler, {"path": "/var/www"}), + ]) + + We support virtual hosts with the `add_handlers` method, which takes in + a host regular expression as the first argument:: + + application.add_handlers(r"www\.myhost\.com", [ + (r"/article/([0-9]+)", ArticleHandler), + ]) + + If there's no match for the current request's host, then ``default_host`` + parameter value is matched against host regular expressions. + + + .. warning:: + + Applications that do not use TLS may be vulnerable to :ref:`DNS + rebinding <dnsrebinding>` attacks. This attack is especially + relevant to applications that only listen on ``127.0.0.1`` or + other private networks. Appropriate host patterns must be used + (instead of the default of ``r'.*'``) to prevent this risk. The + ``default_host`` argument must not be used in applications that + may be vulnerable to DNS rebinding. + + You can serve static files by sending the ``static_path`` setting + as a keyword argument. We will serve those files from the + ``/static/`` URI (this is configurable with the + ``static_url_prefix`` setting), and we will serve ``/favicon.ico`` + and ``/robots.txt`` from the same directory. A custom subclass of + `StaticFileHandler` can be specified with the + ``static_handler_class`` setting. + + .. versionchanged:: 4.5 + Integration with the new `tornado.routing` module. + + """ + + def __init__( + self, + handlers: Optional[_RuleList] = None, + default_host: Optional[str] = None, + transforms: Optional[List[Type["OutputTransform"]]] = None, + **settings: Any + ) -> None: + if transforms is None: + self.transforms = [] # type: List[Type[OutputTransform]] + if settings.get("compress_response") or settings.get("gzip"): + self.transforms.append(GZipContentEncoding) + else: + self.transforms = transforms + self.default_host = default_host + self.settings = settings + self.ui_modules = { + "linkify": _linkify, + "xsrf_form_html": _xsrf_form_html, + "Template": TemplateModule, + } + self.ui_methods = {} # type: Dict[str, Callable[..., str]] + self._load_ui_modules(settings.get("ui_modules", {})) + self._load_ui_methods(settings.get("ui_methods", {})) + if self.settings.get("static_path"): + path = self.settings["static_path"] + handlers = list(handlers or []) + static_url_prefix = settings.get("static_url_prefix", "/static/") + static_handler_class = settings.get( + "static_handler_class", StaticFileHandler + ) + static_handler_args = settings.get("static_handler_args", {}) + static_handler_args["path"] = path + for pattern in [ + re.escape(static_url_prefix) + r"(.*)", + r"/(favicon\.ico)", + r"/(robots\.txt)", + ]: + handlers.insert(0, (pattern, static_handler_class, static_handler_args)) + + if self.settings.get("debug"): + self.settings.setdefault("autoreload", True) + self.settings.setdefault("compiled_template_cache", False) + self.settings.setdefault("static_hash_cache", False) + self.settings.setdefault("serve_traceback", True) + + self.wildcard_router = _ApplicationRouter(self, handlers) + self.default_router = _ApplicationRouter( + self, [Rule(AnyMatches(), self.wildcard_router)] + ) + + # Automatically reload modified modules + if self.settings.get("autoreload"): + from tornado import autoreload + + autoreload.start() + + def listen(self, port: int, address: str = "", **kwargs: Any) -> HTTPServer: + """Starts an HTTP server for this application on the given port. + + This is a convenience alias for creating an `.HTTPServer` + object and calling its listen method. Keyword arguments not + supported by `HTTPServer.listen <.TCPServer.listen>` are passed to the + `.HTTPServer` constructor. For advanced uses + (e.g. multi-process mode), do not use this method; create an + `.HTTPServer` and call its + `.TCPServer.bind`/`.TCPServer.start` methods directly. + + Note that after calling this method you still need to call + ``IOLoop.current().start()`` to start the server. + + Returns the `.HTTPServer` object. + + .. versionchanged:: 4.3 + Now returns the `.HTTPServer` object. + """ + server = HTTPServer(self, **kwargs) + server.listen(port, address) + return server + + def add_handlers(self, host_pattern: str, host_handlers: _RuleList) -> None: + """Appends the given handlers to our handler list. + + Host patterns are processed sequentially in the order they were + added. All matching patterns will be considered. + """ + host_matcher = HostMatches(host_pattern) + rule = Rule(host_matcher, _ApplicationRouter(self, host_handlers)) + + self.default_router.rules.insert(-1, rule) + + if self.default_host is not None: + self.wildcard_router.add_rules( + [(DefaultHostMatches(self, host_matcher.host_pattern), host_handlers)] + ) + + def add_transform(self, transform_class: Type["OutputTransform"]) -> None: + self.transforms.append(transform_class) + + def _load_ui_methods(self, methods: Any) -> None: + if isinstance(methods, types.ModuleType): + self._load_ui_methods(dict((n, getattr(methods, n)) for n in dir(methods))) + elif isinstance(methods, list): + for m in methods: + self._load_ui_methods(m) + else: + for name, fn in methods.items(): + if ( + not name.startswith("_") + and hasattr(fn, "__call__") + and name[0].lower() == name[0] + ): + self.ui_methods[name] = fn + + def _load_ui_modules(self, modules: Any) -> None: + if isinstance(modules, types.ModuleType): + self._load_ui_modules(dict((n, getattr(modules, n)) for n in dir(modules))) + elif isinstance(modules, list): + for m in modules: + self._load_ui_modules(m) + else: + assert isinstance(modules, dict) + for name, cls in modules.items(): + try: + if issubclass(cls, UIModule): + self.ui_modules[name] = cls + except TypeError: + pass + + def __call__( + self, request: httputil.HTTPServerRequest + ) -> Optional[Awaitable[None]]: + # Legacy HTTPServer interface + dispatcher = self.find_handler(request) + return dispatcher.execute() + + def find_handler( + self, request: httputil.HTTPServerRequest, **kwargs: Any + ) -> "_HandlerDelegate": + route = self.default_router.find_handler(request) + if route is not None: + return cast("_HandlerDelegate", route) + + if self.settings.get("default_handler_class"): + return self.get_handler_delegate( + request, + self.settings["default_handler_class"], + self.settings.get("default_handler_args", {}), + ) + + return self.get_handler_delegate(request, ErrorHandler, {"status_code": 404}) + + def get_handler_delegate( + self, + request: httputil.HTTPServerRequest, + target_class: Type[RequestHandler], + target_kwargs: Optional[Dict[str, Any]] = None, + path_args: Optional[List[bytes]] = None, + path_kwargs: Optional[Dict[str, bytes]] = None, + ) -> "_HandlerDelegate": + """Returns `~.httputil.HTTPMessageDelegate` that can serve a request + for application and `RequestHandler` subclass. + + :arg httputil.HTTPServerRequest request: current HTTP request. + :arg RequestHandler target_class: a `RequestHandler` class. + :arg dict target_kwargs: keyword arguments for ``target_class`` constructor. + :arg list path_args: positional arguments for ``target_class`` HTTP method that + will be executed while handling a request (``get``, ``post`` or any other). + :arg dict path_kwargs: keyword arguments for ``target_class`` HTTP method. + """ + return _HandlerDelegate( + self, request, target_class, target_kwargs, path_args, path_kwargs + ) + + def reverse_url(self, name: str, *args: Any) -> str: + """Returns a URL path for handler named ``name`` + + The handler must be added to the application as a named `URLSpec`. + + Args will be substituted for capturing groups in the `URLSpec` regex. + They will be converted to strings if necessary, encoded as utf8, + and url-escaped. + """ + reversed_url = self.default_router.reverse_url(name, *args) + if reversed_url is not None: + return reversed_url + + raise KeyError("%s not found in named urls" % name) + + def log_request(self, handler: RequestHandler) -> None: + """Writes a completed HTTP request to the logs. + + By default writes to the python root logger. To change + this behavior either subclass Application and override this method, + or pass a function in the application settings dictionary as + ``log_function``. + """ + if "log_function" in self.settings: + self.settings["log_function"](handler) + return + if handler.get_status() < 400: + log_method = access_log.info + elif handler.get_status() < 500: + log_method = access_log.warning + else: + log_method = access_log.error + request_time = 1000.0 * handler.request.request_time() + log_method( + "%d %s %.2fms", + handler.get_status(), + handler._request_summary(), + request_time, + ) + + +class _HandlerDelegate(httputil.HTTPMessageDelegate): + def __init__( + self, + application: Application, + request: httputil.HTTPServerRequest, + handler_class: Type[RequestHandler], + handler_kwargs: Optional[Dict[str, Any]], + path_args: Optional[List[bytes]], + path_kwargs: Optional[Dict[str, bytes]], + ) -> None: + self.application = application + self.connection = request.connection + self.request = request + self.handler_class = handler_class + self.handler_kwargs = handler_kwargs or {} + self.path_args = path_args or [] + self.path_kwargs = path_kwargs or {} + self.chunks = [] # type: List[bytes] + self.stream_request_body = _has_stream_request_body(self.handler_class) + + def headers_received( + self, + start_line: Union[httputil.RequestStartLine, httputil.ResponseStartLine], + headers: httputil.HTTPHeaders, + ) -> Optional[Awaitable[None]]: + if self.stream_request_body: + self.request._body_future = Future() + return self.execute() + return None + + def data_received(self, data: bytes) -> Optional[Awaitable[None]]: + if self.stream_request_body: + return self.handler.data_received(data) + else: + self.chunks.append(data) + return None + + def finish(self) -> None: + if self.stream_request_body: + future_set_result_unless_cancelled(self.request._body_future, None) + else: + self.request.body = b"".join(self.chunks) + self.request._parse_body() + self.execute() + + def on_connection_close(self) -> None: + if self.stream_request_body: + self.handler.on_connection_close() + else: + self.chunks = None # type: ignore + + def execute(self) -> Optional[Awaitable[None]]: + # If template cache is disabled (usually in the debug mode), + # re-compile templates and reload static files on every + # request so you don't need to restart to see changes + if not self.application.settings.get("compiled_template_cache", True): + with RequestHandler._template_loader_lock: + for loader in RequestHandler._template_loaders.values(): + loader.reset() + if not self.application.settings.get("static_hash_cache", True): + StaticFileHandler.reset() + + self.handler = self.handler_class( + self.application, self.request, **self.handler_kwargs + ) + transforms = [t(self.request) for t in self.application.transforms] + + if self.stream_request_body: + self.handler._prepared_future = Future() + # Note that if an exception escapes handler._execute it will be + # trapped in the Future it returns (which we are ignoring here, + # leaving it to be logged when the Future is GC'd). + # However, that shouldn't happen because _execute has a blanket + # except handler, and we cannot easily access the IOLoop here to + # call add_future (because of the requirement to remain compatible + # with WSGI) + fut = gen.convert_yielded( + self.handler._execute(transforms, *self.path_args, **self.path_kwargs) + ) + fut.add_done_callback(lambda f: f.result()) + # If we are streaming the request body, then execute() is finished + # when the handler has prepared to receive the body. If not, + # it doesn't matter when execute() finishes (so we return None) + return self.handler._prepared_future + + +class HTTPError(Exception): + """An exception that will turn into an HTTP error response. + + Raising an `HTTPError` is a convenient alternative to calling + `RequestHandler.send_error` since it automatically ends the + current function. + + To customize the response sent with an `HTTPError`, override + `RequestHandler.write_error`. + + :arg int status_code: HTTP status code. Must be listed in + `httplib.responses <http.client.responses>` unless the ``reason`` + keyword argument is given. + :arg str log_message: Message to be written to the log for this error + (will not be shown to the user unless the `Application` is in debug + mode). May contain ``%s``-style placeholders, which will be filled + in with remaining positional parameters. + :arg str reason: Keyword-only argument. The HTTP "reason" phrase + to pass in the status line along with ``status_code``. Normally + determined automatically from ``status_code``, but can be used + to use a non-standard numeric code. + """ + + def __init__( + self, + status_code: int = 500, + log_message: Optional[str] = None, + *args: Any, + **kwargs: Any + ) -> None: + self.status_code = status_code + self.log_message = log_message + self.args = args + self.reason = kwargs.get("reason", None) + if log_message and not args: + self.log_message = log_message.replace("%", "%%") + + def __str__(self) -> str: + message = "HTTP %d: %s" % ( + self.status_code, + self.reason or httputil.responses.get(self.status_code, "Unknown"), + ) + if self.log_message: + return message + " (" + (self.log_message % self.args) + ")" + else: + return message + + +class Finish(Exception): + """An exception that ends the request without producing an error response. + + When `Finish` is raised in a `RequestHandler`, the request will + end (calling `RequestHandler.finish` if it hasn't already been + called), but the error-handling methods (including + `RequestHandler.write_error`) will not be called. + + If `Finish()` was created with no arguments, the pending response + will be sent as-is. If `Finish()` was given an argument, that + argument will be passed to `RequestHandler.finish()`. + + This can be a more convenient way to implement custom error pages + than overriding ``write_error`` (especially in library code):: + + if self.current_user is None: + self.set_status(401) + self.set_header('WWW-Authenticate', 'Basic realm="something"') + raise Finish() + + .. versionchanged:: 4.3 + Arguments passed to ``Finish()`` will be passed on to + `RequestHandler.finish`. + """ + + pass + + +class MissingArgumentError(HTTPError): + """Exception raised by `RequestHandler.get_argument`. + + This is a subclass of `HTTPError`, so if it is uncaught a 400 response + code will be used instead of 500 (and a stack trace will not be logged). + + .. versionadded:: 3.1 + """ + + def __init__(self, arg_name: str) -> None: + super().__init__(400, "Missing argument %s" % arg_name) + self.arg_name = arg_name + + +class ErrorHandler(RequestHandler): + """Generates an error response with ``status_code`` for all requests.""" + + def initialize(self, status_code: int) -> None: + self.set_status(status_code) + + def prepare(self) -> None: + raise HTTPError(self._status_code) + + def check_xsrf_cookie(self) -> None: + # POSTs to an ErrorHandler don't actually have side effects, + # so we don't need to check the xsrf token. This allows POSTs + # to the wrong url to return a 404 instead of 403. + pass + + +class RedirectHandler(RequestHandler): + """Redirects the client to the given URL for all GET requests. + + You should provide the keyword argument ``url`` to the handler, e.g.:: + + application = web.Application([ + (r"/oldpath", web.RedirectHandler, {"url": "/newpath"}), + ]) + + `RedirectHandler` supports regular expression substitutions. E.g., to + swap the first and second parts of a path while preserving the remainder:: + + application = web.Application([ + (r"/(.*?)/(.*?)/(.*)", web.RedirectHandler, {"url": "/{1}/{0}/{2}"}), + ]) + + The final URL is formatted with `str.format` and the substrings that match + the capturing groups. In the above example, a request to "/a/b/c" would be + formatted like:: + + str.format("/{1}/{0}/{2}", "a", "b", "c") # -> "/b/a/c" + + Use Python's :ref:`format string syntax <formatstrings>` to customize how + values are substituted. + + .. versionchanged:: 4.5 + Added support for substitutions into the destination URL. + + .. versionchanged:: 5.0 + If any query arguments are present, they will be copied to the + destination URL. + """ + + def initialize(self, url: str, permanent: bool = True) -> None: + self._url = url + self._permanent = permanent + + def get(self, *args: Any, **kwargs: Any) -> None: + to_url = self._url.format(*args, **kwargs) + if self.request.query_arguments: + # TODO: figure out typing for the next line. + to_url = httputil.url_concat( + to_url, + list(httputil.qs_to_qsl(self.request.query_arguments)), # type: ignore + ) + self.redirect(to_url, permanent=self._permanent) + + +class StaticFileHandler(RequestHandler): + """A simple handler that can serve static content from a directory. + + A `StaticFileHandler` is configured automatically if you pass the + ``static_path`` keyword argument to `Application`. This handler + can be customized with the ``static_url_prefix``, ``static_handler_class``, + and ``static_handler_args`` settings. + + To map an additional path to this handler for a static data directory + you would add a line to your application like:: + + application = web.Application([ + (r"/content/(.*)", web.StaticFileHandler, {"path": "/var/www"}), + ]) + + The handler constructor requires a ``path`` argument, which specifies the + local root directory of the content to be served. + + Note that a capture group in the regex is required to parse the value for + the ``path`` argument to the get() method (different than the constructor + argument above); see `URLSpec` for details. + + To serve a file like ``index.html`` automatically when a directory is + requested, set ``static_handler_args=dict(default_filename="index.html")`` + in your application settings, or add ``default_filename`` as an initializer + argument for your ``StaticFileHandler``. + + To maximize the effectiveness of browser caching, this class supports + versioned urls (by default using the argument ``?v=``). If a version + is given, we instruct the browser to cache this file indefinitely. + `make_static_url` (also available as `RequestHandler.static_url`) can + be used to construct a versioned url. + + This handler is intended primarily for use in development and light-duty + file serving; for heavy traffic it will be more efficient to use + a dedicated static file server (such as nginx or Apache). We support + the HTTP ``Accept-Ranges`` mechanism to return partial content (because + some browsers require this functionality to be present to seek in + HTML5 audio or video). + + **Subclassing notes** + + This class is designed to be extensible by subclassing, but because + of the way static urls are generated with class methods rather than + instance methods, the inheritance patterns are somewhat unusual. + Be sure to use the ``@classmethod`` decorator when overriding a + class method. Instance methods may use the attributes ``self.path`` + ``self.absolute_path``, and ``self.modified``. + + Subclasses should only override methods discussed in this section; + overriding other methods is error-prone. Overriding + ``StaticFileHandler.get`` is particularly problematic due to the + tight coupling with ``compute_etag`` and other methods. + + To change the way static urls are generated (e.g. to match the behavior + of another server or CDN), override `make_static_url`, `parse_url_path`, + `get_cache_time`, and/or `get_version`. + + To replace all interaction with the filesystem (e.g. to serve + static content from a database), override `get_content`, + `get_content_size`, `get_modified_time`, `get_absolute_path`, and + `validate_absolute_path`. + + .. versionchanged:: 3.1 + Many of the methods for subclasses were added in Tornado 3.1. + """ + + CACHE_MAX_AGE = 86400 * 365 * 10 # 10 years + + _static_hashes = {} # type: Dict[str, Optional[str]] + _lock = threading.Lock() # protects _static_hashes + + def initialize(self, path: str, default_filename: Optional[str] = None) -> None: + self.root = path + self.default_filename = default_filename + + @classmethod + def reset(cls) -> None: + with cls._lock: + cls._static_hashes = {} + + def head(self, path: str) -> Awaitable[None]: + return self.get(path, include_body=False) + + async def get(self, path: str, include_body: bool = True) -> None: + # Set up our path instance variables. + self.path = self.parse_url_path(path) + del path # make sure we don't refer to path instead of self.path again + absolute_path = self.get_absolute_path(self.root, self.path) + self.absolute_path = self.validate_absolute_path(self.root, absolute_path) + if self.absolute_path is None: + return + + self.modified = self.get_modified_time() + self.set_headers() + + if self.should_return_304(): + self.set_status(304) + return + + request_range = None + range_header = self.request.headers.get("Range") + if range_header: + # As per RFC 2616 14.16, if an invalid Range header is specified, + # the request will be treated as if the header didn't exist. + request_range = httputil._parse_request_range(range_header) + + size = self.get_content_size() + if request_range: + start, end = request_range + if start is not None and start < 0: + start += size + if start < 0: + start = 0 + if ( + start is not None + and (start >= size or (end is not None and start >= end)) + ) or end == 0: + # As per RFC 2616 14.35.1, a range is not satisfiable only: if + # the first requested byte is equal to or greater than the + # content, or when a suffix with length 0 is specified. + # https://tools.ietf.org/html/rfc7233#section-2.1 + # A byte-range-spec is invalid if the last-byte-pos value is present + # and less than the first-byte-pos. + self.set_status(416) # Range Not Satisfiable + self.set_header("Content-Type", "text/plain") + self.set_header("Content-Range", "bytes */%s" % (size,)) + return + if end is not None and end > size: + # Clients sometimes blindly use a large range to limit their + # download size; cap the endpoint at the actual file size. + end = size + # Note: only return HTTP 206 if less than the entire range has been + # requested. Not only is this semantically correct, but Chrome + # refuses to play audio if it gets an HTTP 206 in response to + # ``Range: bytes=0-``. + if size != (end or size) - (start or 0): + self.set_status(206) # Partial Content + self.set_header( + "Content-Range", httputil._get_content_range(start, end, size) + ) + else: + start = end = None + + if start is not None and end is not None: + content_length = end - start + elif end is not None: + content_length = end + elif start is not None: + content_length = size - start + else: + content_length = size + self.set_header("Content-Length", content_length) + + if include_body: + content = self.get_content(self.absolute_path, start, end) + if isinstance(content, bytes): + content = [content] + for chunk in content: + try: + self.write(chunk) + await self.flush() + except iostream.StreamClosedError: + return + else: + assert self.request.method == "HEAD" + + def compute_etag(self) -> Optional[str]: + """Sets the ``Etag`` header based on static url version. + + This allows efficient ``If-None-Match`` checks against cached + versions, and sends the correct ``Etag`` for a partial response + (i.e. the same ``Etag`` as the full file). + + .. versionadded:: 3.1 + """ + assert self.absolute_path is not None + version_hash = self._get_cached_version(self.absolute_path) + if not version_hash: + return None + return '"%s"' % (version_hash,) + + def set_headers(self) -> None: + """Sets the content and caching headers on the response. + + .. versionadded:: 3.1 + """ + self.set_header("Accept-Ranges", "bytes") + self.set_etag_header() + + if self.modified is not None: + self.set_header("Last-Modified", self.modified) + + content_type = self.get_content_type() + if content_type: + self.set_header("Content-Type", content_type) + + cache_time = self.get_cache_time(self.path, self.modified, content_type) + if cache_time > 0: + self.set_header( + "Expires", + datetime.datetime.utcnow() + datetime.timedelta(seconds=cache_time), + ) + self.set_header("Cache-Control", "max-age=" + str(cache_time)) + + self.set_extra_headers(self.path) + + def should_return_304(self) -> bool: + """Returns True if the headers indicate that we should return 304. + + .. versionadded:: 3.1 + """ + # If client sent If-None-Match, use it, ignore If-Modified-Since + if self.request.headers.get("If-None-Match"): + return self.check_etag_header() + + # Check the If-Modified-Since, and don't send the result if the + # content has not been modified + ims_value = self.request.headers.get("If-Modified-Since") + if ims_value is not None: + date_tuple = email.utils.parsedate(ims_value) + if date_tuple is not None: + if_since = datetime.datetime(*date_tuple[:6]) + assert self.modified is not None + if if_since >= self.modified: + return True + + return False + + @classmethod + def get_absolute_path(cls, root: str, path: str) -> str: + """Returns the absolute location of ``path`` relative to ``root``. + + ``root`` is the path configured for this `StaticFileHandler` + (in most cases the ``static_path`` `Application` setting). + + This class method may be overridden in subclasses. By default + it returns a filesystem path, but other strings may be used + as long as they are unique and understood by the subclass's + overridden `get_content`. + + .. versionadded:: 3.1 + """ + abspath = os.path.abspath(os.path.join(root, path)) + return abspath + + def validate_absolute_path(self, root: str, absolute_path: str) -> Optional[str]: + """Validate and return the absolute path. + + ``root`` is the configured path for the `StaticFileHandler`, + and ``path`` is the result of `get_absolute_path` + + This is an instance method called during request processing, + so it may raise `HTTPError` or use methods like + `RequestHandler.redirect` (return None after redirecting to + halt further processing). This is where 404 errors for missing files + are generated. + + This method may modify the path before returning it, but note that + any such modifications will not be understood by `make_static_url`. + + In instance methods, this method's result is available as + ``self.absolute_path``. + + .. versionadded:: 3.1 + """ + # os.path.abspath strips a trailing /. + # We must add it back to `root` so that we only match files + # in a directory named `root` instead of files starting with + # that prefix. + root = os.path.abspath(root) + if not root.endswith(os.path.sep): + # abspath always removes a trailing slash, except when + # root is '/'. This is an unusual case, but several projects + # have independently discovered this technique to disable + # Tornado's path validation and (hopefully) do their own, + # so we need to support it. + root += os.path.sep + # The trailing slash also needs to be temporarily added back + # the requested path so a request to root/ will match. + if not (absolute_path + os.path.sep).startswith(root): + raise HTTPError(403, "%s is not in root static directory", self.path) + if os.path.isdir(absolute_path) and self.default_filename is not None: + # need to look at the request.path here for when path is empty + # but there is some prefix to the path that was already + # trimmed by the routing + if not self.request.path.endswith("/"): + self.redirect(self.request.path + "/", permanent=True) + return None + absolute_path = os.path.join(absolute_path, self.default_filename) + if not os.path.exists(absolute_path): + raise HTTPError(404) + if not os.path.isfile(absolute_path): + raise HTTPError(403, "%s is not a file", self.path) + return absolute_path + + @classmethod + def get_content( + cls, abspath: str, start: Optional[int] = None, end: Optional[int] = None + ) -> Generator[bytes, None, None]: + """Retrieve the content of the requested resource which is located + at the given absolute path. + + This class method may be overridden by subclasses. Note that its + signature is different from other overridable class methods + (no ``settings`` argument); this is deliberate to ensure that + ``abspath`` is able to stand on its own as a cache key. + + This method should either return a byte string or an iterator + of byte strings. The latter is preferred for large files + as it helps reduce memory fragmentation. + + .. versionadded:: 3.1 + """ + with open(abspath, "rb") as file: + if start is not None: + file.seek(start) + if end is not None: + remaining = end - (start or 0) # type: Optional[int] + else: + remaining = None + while True: + chunk_size = 64 * 1024 + if remaining is not None and remaining < chunk_size: + chunk_size = remaining + chunk = file.read(chunk_size) + if chunk: + if remaining is not None: + remaining -= len(chunk) + yield chunk + else: + if remaining is not None: + assert remaining == 0 + return + + @classmethod + def get_content_version(cls, abspath: str) -> str: + """Returns a version string for the resource at the given path. + + This class method may be overridden by subclasses. The + default implementation is a SHA-512 hash of the file's contents. + + .. versionadded:: 3.1 + """ + data = cls.get_content(abspath) + hasher = hashlib.sha512() + if isinstance(data, bytes): + hasher.update(data) + else: + for chunk in data: + hasher.update(chunk) + return hasher.hexdigest() + + def _stat(self) -> os.stat_result: + assert self.absolute_path is not None + if not hasattr(self, "_stat_result"): + self._stat_result = os.stat(self.absolute_path) + return self._stat_result + + def get_content_size(self) -> int: + """Retrieve the total size of the resource at the given path. + + This method may be overridden by subclasses. + + .. versionadded:: 3.1 + + .. versionchanged:: 4.0 + This method is now always called, instead of only when + partial results are requested. + """ + stat_result = self._stat() + return stat_result.st_size + + def get_modified_time(self) -> Optional[datetime.datetime]: + """Returns the time that ``self.absolute_path`` was last modified. + + May be overridden in subclasses. Should return a `~datetime.datetime` + object or None. + + .. versionadded:: 3.1 + """ + stat_result = self._stat() + # NOTE: Historically, this used stat_result[stat.ST_MTIME], + # which truncates the fractional portion of the timestamp. It + # was changed from that form to stat_result.st_mtime to + # satisfy mypy (which disallows the bracket operator), but the + # latter form returns a float instead of an int. For + # consistency with the past (and because we have a unit test + # that relies on this), we truncate the float here, although + # I'm not sure that's the right thing to do. + modified = datetime.datetime.utcfromtimestamp(int(stat_result.st_mtime)) + return modified + + def get_content_type(self) -> str: + """Returns the ``Content-Type`` header to be used for this request. + + .. versionadded:: 3.1 + """ + assert self.absolute_path is not None + mime_type, encoding = mimetypes.guess_type(self.absolute_path) + # per RFC 6713, use the appropriate type for a gzip compressed file + if encoding == "gzip": + return "application/gzip" + # As of 2015-07-21 there is no bzip2 encoding defined at + # http://www.iana.org/assignments/media-types/media-types.xhtml + # So for that (and any other encoding), use octet-stream. + elif encoding is not None: + return "application/octet-stream" + elif mime_type is not None: + return mime_type + # if mime_type not detected, use application/octet-stream + else: + return "application/octet-stream" + + def set_extra_headers(self, path: str) -> None: + """For subclass to add extra headers to the response""" + pass + + def get_cache_time( + self, path: str, modified: Optional[datetime.datetime], mime_type: str + ) -> int: + """Override to customize cache control behavior. + + Return a positive number of seconds to make the result + cacheable for that amount of time or 0 to mark resource as + cacheable for an unspecified amount of time (subject to + browser heuristics). + + By default returns cache expiry of 10 years for resources requested + with ``v`` argument. + """ + return self.CACHE_MAX_AGE if "v" in self.request.arguments else 0 + + @classmethod + def make_static_url( + cls, settings: Dict[str, Any], path: str, include_version: bool = True + ) -> str: + """Constructs a versioned url for the given path. + + This method may be overridden in subclasses (but note that it + is a class method rather than an instance method). Subclasses + are only required to implement the signature + ``make_static_url(cls, settings, path)``; other keyword + arguments may be passed through `~RequestHandler.static_url` + but are not standard. + + ``settings`` is the `Application.settings` dictionary. ``path`` + is the static path being requested. The url returned should be + relative to the current host. + + ``include_version`` determines whether the generated URL should + include the query string containing the version hash of the + file corresponding to the given ``path``. + + """ + url = settings.get("static_url_prefix", "/static/") + path + if not include_version: + return url + + version_hash = cls.get_version(settings, path) + if not version_hash: + return url + + return "%s?v=%s" % (url, version_hash) + + def parse_url_path(self, url_path: str) -> str: + """Converts a static URL path into a filesystem path. + + ``url_path`` is the path component of the URL with + ``static_url_prefix`` removed. The return value should be + filesystem path relative to ``static_path``. + + This is the inverse of `make_static_url`. + """ + if os.path.sep != "/": + url_path = url_path.replace("/", os.path.sep) + return url_path + + @classmethod + def get_version(cls, settings: Dict[str, Any], path: str) -> Optional[str]: + """Generate the version string to be used in static URLs. + + ``settings`` is the `Application.settings` dictionary and ``path`` + is the relative location of the requested asset on the filesystem. + The returned value should be a string, or ``None`` if no version + could be determined. + + .. versionchanged:: 3.1 + This method was previously recommended for subclasses to override; + `get_content_version` is now preferred as it allows the base + class to handle caching of the result. + """ + abs_path = cls.get_absolute_path(settings["static_path"], path) + return cls._get_cached_version(abs_path) + + @classmethod + def _get_cached_version(cls, abs_path: str) -> Optional[str]: + with cls._lock: + hashes = cls._static_hashes + if abs_path not in hashes: + try: + hashes[abs_path] = cls.get_content_version(abs_path) + except Exception: + gen_log.error("Could not open static file %r", abs_path) + hashes[abs_path] = None + hsh = hashes.get(abs_path) + if hsh: + return hsh + return None + + +class FallbackHandler(RequestHandler): + """A `RequestHandler` that wraps another HTTP server callback. + + The fallback is a callable object that accepts an + `~.httputil.HTTPServerRequest`, such as an `Application` or + `tornado.wsgi.WSGIContainer`. This is most useful to use both + Tornado ``RequestHandlers`` and WSGI in the same server. Typical + usage:: + + wsgi_app = tornado.wsgi.WSGIContainer( + django.core.handlers.wsgi.WSGIHandler()) + application = tornado.web.Application([ + (r"/foo", FooHandler), + (r".*", FallbackHandler, dict(fallback=wsgi_app), + ]) + """ + + def initialize( + self, fallback: Callable[[httputil.HTTPServerRequest], None] + ) -> None: + self.fallback = fallback + + def prepare(self) -> None: + self.fallback(self.request) + self._finished = True + self.on_finish() + + +class OutputTransform(object): + """A transform modifies the result of an HTTP request (e.g., GZip encoding) + + Applications are not expected to create their own OutputTransforms + or interact with them directly; the framework chooses which transforms + (if any) to apply. + """ + + def __init__(self, request: httputil.HTTPServerRequest) -> None: + pass + + def transform_first_chunk( + self, + status_code: int, + headers: httputil.HTTPHeaders, + chunk: bytes, + finishing: bool, + ) -> Tuple[int, httputil.HTTPHeaders, bytes]: + return status_code, headers, chunk + + def transform_chunk(self, chunk: bytes, finishing: bool) -> bytes: + return chunk + + +class GZipContentEncoding(OutputTransform): + """Applies the gzip content encoding to the response. + + See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11 + + .. versionchanged:: 4.0 + Now compresses all mime types beginning with ``text/``, instead + of just a whitelist. (the whitelist is still used for certain + non-text mime types). + """ + + # Whitelist of compressible mime types (in addition to any types + # beginning with "text/"). + CONTENT_TYPES = set( + [ + "application/javascript", + "application/x-javascript", + "application/xml", + "application/atom+xml", + "application/json", + "application/xhtml+xml", + "image/svg+xml", + ] + ) + # Python's GzipFile defaults to level 9, while most other gzip + # tools (including gzip itself) default to 6, which is probably a + # better CPU/size tradeoff. + GZIP_LEVEL = 6 + # Responses that are too short are unlikely to benefit from gzipping + # after considering the "Content-Encoding: gzip" header and the header + # inside the gzip encoding. + # Note that responses written in multiple chunks will be compressed + # regardless of size. + MIN_LENGTH = 1024 + + def __init__(self, request: httputil.HTTPServerRequest) -> None: + self._gzipping = "gzip" in request.headers.get("Accept-Encoding", "") + + def _compressible_type(self, ctype: str) -> bool: + return ctype.startswith("text/") or ctype in self.CONTENT_TYPES + + def transform_first_chunk( + self, + status_code: int, + headers: httputil.HTTPHeaders, + chunk: bytes, + finishing: bool, + ) -> Tuple[int, httputil.HTTPHeaders, bytes]: + # TODO: can/should this type be inherited from the superclass? + if "Vary" in headers: + headers["Vary"] += ", Accept-Encoding" + else: + headers["Vary"] = "Accept-Encoding" + if self._gzipping: + ctype = _unicode(headers.get("Content-Type", "")).split(";")[0] + self._gzipping = ( + self._compressible_type(ctype) + and (not finishing or len(chunk) >= self.MIN_LENGTH) + and ("Content-Encoding" not in headers) + ) + if self._gzipping: + headers["Content-Encoding"] = "gzip" + self._gzip_value = BytesIO() + self._gzip_file = gzip.GzipFile( + mode="w", fileobj=self._gzip_value, compresslevel=self.GZIP_LEVEL + ) + chunk = self.transform_chunk(chunk, finishing) + if "Content-Length" in headers: + # The original content length is no longer correct. + # If this is the last (and only) chunk, we can set the new + # content-length; otherwise we remove it and fall back to + # chunked encoding. + if finishing: + headers["Content-Length"] = str(len(chunk)) + else: + del headers["Content-Length"] + return status_code, headers, chunk + + def transform_chunk(self, chunk: bytes, finishing: bool) -> bytes: + if self._gzipping: + self._gzip_file.write(chunk) + if finishing: + self._gzip_file.close() + else: + self._gzip_file.flush() + chunk = self._gzip_value.getvalue() + self._gzip_value.truncate(0) + self._gzip_value.seek(0) + return chunk + + +def authenticated( + method: Callable[..., Optional[Awaitable[None]]] +) -> Callable[..., Optional[Awaitable[None]]]: + """Decorate methods with this to require that the user be logged in. + + If the user is not logged in, they will be redirected to the configured + `login url <RequestHandler.get_login_url>`. + + If you configure a login url with a query parameter, Tornado will + assume you know what you're doing and use it as-is. If not, it + will add a `next` parameter so the login page knows where to send + you once you're logged in. + """ + + @functools.wraps(method) + def wrapper( # type: ignore + self: RequestHandler, *args, **kwargs + ) -> Optional[Awaitable[None]]: + if not self.current_user: + if self.request.method in ("GET", "HEAD"): + url = self.get_login_url() + if "?" not in url: + if urllib.parse.urlsplit(url).scheme: + # if login url is absolute, make next absolute too + next_url = self.request.full_url() + else: + assert self.request.uri is not None + next_url = self.request.uri + url += "?" + urlencode(dict(next=next_url)) + self.redirect(url) + return None + raise HTTPError(403) + return method(self, *args, **kwargs) + + return wrapper + + +class UIModule(object): + """A re-usable, modular UI unit on a page. + + UI modules often execute additional queries, and they can include + additional CSS and JavaScript that will be included in the output + page, which is automatically inserted on page render. + + Subclasses of UIModule must override the `render` method. + """ + + def __init__(self, handler: RequestHandler) -> None: + self.handler = handler + self.request = handler.request + self.ui = handler.ui + self.locale = handler.locale + + @property + def current_user(self) -> Any: + return self.handler.current_user + + def render(self, *args: Any, **kwargs: Any) -> str: + """Override in subclasses to return this module's output.""" + raise NotImplementedError() + + def embedded_javascript(self) -> Optional[str]: + """Override to return a JavaScript string + to be embedded in the page.""" + return None + + def javascript_files(self) -> Optional[Iterable[str]]: + """Override to return a list of JavaScript files needed by this module. + + If the return values are relative paths, they will be passed to + `RequestHandler.static_url`; otherwise they will be used as-is. + """ + return None + + def embedded_css(self) -> Optional[str]: + """Override to return a CSS string + that will be embedded in the page.""" + return None + + def css_files(self) -> Optional[Iterable[str]]: + """Override to returns a list of CSS files required by this module. + + If the return values are relative paths, they will be passed to + `RequestHandler.static_url`; otherwise they will be used as-is. + """ + return None + + def html_head(self) -> Optional[str]: + """Override to return an HTML string that will be put in the <head/> + element. + """ + return None + + def html_body(self) -> Optional[str]: + """Override to return an HTML string that will be put at the end of + the <body/> element. + """ + return None + + def render_string(self, path: str, **kwargs: Any) -> bytes: + """Renders a template and returns it as a string.""" + return self.handler.render_string(path, **kwargs) + + +class _linkify(UIModule): + def render(self, text: str, **kwargs: Any) -> str: # type: ignore + return escape.linkify(text, **kwargs) + + +class _xsrf_form_html(UIModule): + def render(self) -> str: # type: ignore + return self.handler.xsrf_form_html() + + +class TemplateModule(UIModule): + """UIModule that simply renders the given template. + + {% module Template("foo.html") %} is similar to {% include "foo.html" %}, + but the module version gets its own namespace (with kwargs passed to + Template()) instead of inheriting the outer template's namespace. + + Templates rendered through this module also get access to UIModule's + automatic JavaScript/CSS features. Simply call set_resources + inside the template and give it keyword arguments corresponding to + the methods on UIModule: {{ set_resources(js_files=static_url("my.js")) }} + Note that these resources are output once per template file, not once + per instantiation of the template, so they must not depend on + any arguments to the template. + """ + + def __init__(self, handler: RequestHandler) -> None: + super().__init__(handler) + # keep resources in both a list and a dict to preserve order + self._resource_list = [] # type: List[Dict[str, Any]] + self._resource_dict = {} # type: Dict[str, Dict[str, Any]] + + def render(self, path: str, **kwargs: Any) -> bytes: # type: ignore + def set_resources(**kwargs) -> str: # type: ignore + if path not in self._resource_dict: + self._resource_list.append(kwargs) + self._resource_dict[path] = kwargs + else: + if self._resource_dict[path] != kwargs: + raise ValueError( + "set_resources called with different " + "resources for the same template" + ) + return "" + + return self.render_string(path, set_resources=set_resources, **kwargs) + + def _get_resources(self, key: str) -> Iterable[str]: + return (r[key] for r in self._resource_list if key in r) + + def embedded_javascript(self) -> str: + return "\n".join(self._get_resources("embedded_javascript")) + + def javascript_files(self) -> Iterable[str]: + result = [] + for f in self._get_resources("javascript_files"): + if isinstance(f, (unicode_type, bytes)): + result.append(f) + else: + result.extend(f) + return result + + def embedded_css(self) -> str: + return "\n".join(self._get_resources("embedded_css")) + + def css_files(self) -> Iterable[str]: + result = [] + for f in self._get_resources("css_files"): + if isinstance(f, (unicode_type, bytes)): + result.append(f) + else: + result.extend(f) + return result + + def html_head(self) -> str: + return "".join(self._get_resources("html_head")) + + def html_body(self) -> str: + return "".join(self._get_resources("html_body")) + + +class _UIModuleNamespace(object): + """Lazy namespace which creates UIModule proxies bound to a handler.""" + + def __init__( + self, handler: RequestHandler, ui_modules: Dict[str, Type[UIModule]] + ) -> None: + self.handler = handler + self.ui_modules = ui_modules + + def __getitem__(self, key: str) -> Callable[..., str]: + return self.handler._ui_module(key, self.ui_modules[key]) + + def __getattr__(self, key: str) -> Callable[..., str]: + try: + return self[key] + except KeyError as e: + raise AttributeError(str(e)) + + +def create_signed_value( + secret: _CookieSecretTypes, + name: str, + value: Union[str, bytes], + version: Optional[int] = None, + clock: Optional[Callable[[], float]] = None, + key_version: Optional[int] = None, +) -> bytes: + if version is None: + version = DEFAULT_SIGNED_VALUE_VERSION + if clock is None: + clock = time.time + + timestamp = utf8(str(int(clock()))) + value = base64.b64encode(utf8(value)) + if version == 1: + assert not isinstance(secret, dict) + signature = _create_signature_v1(secret, name, value, timestamp) + value = b"|".join([value, timestamp, signature]) + return value + elif version == 2: + # The v2 format consists of a version number and a series of + # length-prefixed fields "%d:%s", the last of which is a + # signature, all separated by pipes. All numbers are in + # decimal format with no leading zeros. The signature is an + # HMAC-SHA256 of the whole string up to that point, including + # the final pipe. + # + # The fields are: + # - format version (i.e. 2; no length prefix) + # - key version (integer, default is 0) + # - timestamp (integer seconds since epoch) + # - name (not encoded; assumed to be ~alphanumeric) + # - value (base64-encoded) + # - signature (hex-encoded; no length prefix) + def format_field(s: Union[str, bytes]) -> bytes: + return utf8("%d:" % len(s)) + utf8(s) + + to_sign = b"|".join( + [ + b"2", + format_field(str(key_version or 0)), + format_field(timestamp), + format_field(name), + format_field(value), + b"", + ] + ) + + if isinstance(secret, dict): + assert ( + key_version is not None + ), "Key version must be set when sign key dict is used" + assert version >= 2, "Version must be at least 2 for key version support" + secret = secret[key_version] + + signature = _create_signature_v2(secret, to_sign) + return to_sign + signature + else: + raise ValueError("Unsupported version %d" % version) + + +# A leading version number in decimal +# with no leading zeros, followed by a pipe. +_signed_value_version_re = re.compile(br"^([1-9][0-9]*)\|(.*)$") + + +def _get_version(value: bytes) -> int: + # Figures out what version value is. Version 1 did not include an + # explicit version field and started with arbitrary base64 data, + # which makes this tricky. + m = _signed_value_version_re.match(value) + if m is None: + version = 1 + else: + try: + version = int(m.group(1)) + if version > 999: + # Certain payloads from the version-less v1 format may + # be parsed as valid integers. Due to base64 padding + # restrictions, this can only happen for numbers whose + # length is a multiple of 4, so we can treat all + # numbers up to 999 as versions, and for the rest we + # fall back to v1 format. + version = 1 + except ValueError: + version = 1 + return version + + +def decode_signed_value( + secret: _CookieSecretTypes, + name: str, + value: Union[None, str, bytes], + max_age_days: float = 31, + clock: Optional[Callable[[], float]] = None, + min_version: Optional[int] = None, +) -> Optional[bytes]: + if clock is None: + clock = time.time + if min_version is None: + min_version = DEFAULT_SIGNED_VALUE_MIN_VERSION + if min_version > 2: + raise ValueError("Unsupported min_version %d" % min_version) + if not value: + return None + + value = utf8(value) + version = _get_version(value) + + if version < min_version: + return None + if version == 1: + assert not isinstance(secret, dict) + return _decode_signed_value_v1(secret, name, value, max_age_days, clock) + elif version == 2: + return _decode_signed_value_v2(secret, name, value, max_age_days, clock) + else: + return None + + +def _decode_signed_value_v1( + secret: Union[str, bytes], + name: str, + value: bytes, + max_age_days: float, + clock: Callable[[], float], +) -> Optional[bytes]: + parts = utf8(value).split(b"|") + if len(parts) != 3: + return None + signature = _create_signature_v1(secret, name, parts[0], parts[1]) + if not hmac.compare_digest(parts[2], signature): + gen_log.warning("Invalid cookie signature %r", value) + return None + timestamp = int(parts[1]) + if timestamp < clock() - max_age_days * 86400: + gen_log.warning("Expired cookie %r", value) + return None + if timestamp > clock() + 31 * 86400: + # _cookie_signature does not hash a delimiter between the + # parts of the cookie, so an attacker could transfer trailing + # digits from the payload to the timestamp without altering the + # signature. For backwards compatibility, sanity-check timestamp + # here instead of modifying _cookie_signature. + gen_log.warning("Cookie timestamp in future; possible tampering %r", value) + return None + if parts[1].startswith(b"0"): + gen_log.warning("Tampered cookie %r", value) + return None + try: + return base64.b64decode(parts[0]) + except Exception: + return None + + +def _decode_fields_v2(value: bytes) -> Tuple[int, bytes, bytes, bytes, bytes]: + def _consume_field(s: bytes) -> Tuple[bytes, bytes]: + length, _, rest = s.partition(b":") + n = int(length) + field_value = rest[:n] + # In python 3, indexing bytes returns small integers; we must + # use a slice to get a byte string as in python 2. + if rest[n : n + 1] != b"|": + raise ValueError("malformed v2 signed value field") + rest = rest[n + 1 :] + return field_value, rest + + rest = value[2:] # remove version number + key_version, rest = _consume_field(rest) + timestamp, rest = _consume_field(rest) + name_field, rest = _consume_field(rest) + value_field, passed_sig = _consume_field(rest) + return int(key_version), timestamp, name_field, value_field, passed_sig + + +def _decode_signed_value_v2( + secret: _CookieSecretTypes, + name: str, + value: bytes, + max_age_days: float, + clock: Callable[[], float], +) -> Optional[bytes]: + try: + ( + key_version, + timestamp_bytes, + name_field, + value_field, + passed_sig, + ) = _decode_fields_v2(value) + except ValueError: + return None + signed_string = value[: -len(passed_sig)] + + if isinstance(secret, dict): + try: + secret = secret[key_version] + except KeyError: + return None + + expected_sig = _create_signature_v2(secret, signed_string) + if not hmac.compare_digest(passed_sig, expected_sig): + return None + if name_field != utf8(name): + return None + timestamp = int(timestamp_bytes) + if timestamp < clock() - max_age_days * 86400: + # The signature has expired. + return None + try: + return base64.b64decode(value_field) + except Exception: + return None + + +def get_signature_key_version(value: Union[str, bytes]) -> Optional[int]: + value = utf8(value) + version = _get_version(value) + if version < 2: + return None + try: + key_version, _, _, _, _ = _decode_fields_v2(value) + except ValueError: + return None + + return key_version + + +def _create_signature_v1(secret: Union[str, bytes], *parts: Union[str, bytes]) -> bytes: + hash = hmac.new(utf8(secret), digestmod=hashlib.sha1) + for part in parts: + hash.update(utf8(part)) + return utf8(hash.hexdigest()) + + +def _create_signature_v2(secret: Union[str, bytes], s: bytes) -> bytes: + hash = hmac.new(utf8(secret), digestmod=hashlib.sha256) + hash.update(utf8(s)) + return utf8(hash.hexdigest()) + + +def is_absolute(path: str) -> bool: + return any(path.startswith(x) for x in ["/", "http:", "https:"]) diff --git a/venv/lib/python3.8/site-packages/tornado/websocket.py b/venv/lib/python3.8/site-packages/tornado/websocket.py new file mode 100644 index 0000000..eef49e7 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/websocket.py @@ -0,0 +1,1666 @@ +"""Implementation of the WebSocket protocol. + +`WebSockets <http://dev.w3.org/html5/websockets/>`_ allow for bidirectional +communication between the browser and server. + +WebSockets are supported in the current versions of all major browsers, +although older versions that do not support WebSockets are still in use +(refer to http://caniuse.com/websockets for details). + +This module implements the final version of the WebSocket protocol as +defined in `RFC 6455 <http://tools.ietf.org/html/rfc6455>`_. Certain +browser versions (notably Safari 5.x) implemented an earlier draft of +the protocol (known as "draft 76") and are not compatible with this module. + +.. versionchanged:: 4.0 + Removed support for the draft 76 protocol version. +""" + +import abc +import asyncio +import base64 +import hashlib +import os +import sys +import struct +import tornado.escape +import tornado.web +from urllib.parse import urlparse +import zlib + +from tornado.concurrent import Future, future_set_result_unless_cancelled +from tornado.escape import utf8, native_str, to_unicode +from tornado import gen, httpclient, httputil +from tornado.ioloop import IOLoop, PeriodicCallback +from tornado.iostream import StreamClosedError, IOStream +from tornado.log import gen_log, app_log +from tornado import simple_httpclient +from tornado.queues import Queue +from tornado.tcpclient import TCPClient +from tornado.util import _websocket_mask + +from typing import ( + TYPE_CHECKING, + cast, + Any, + Optional, + Dict, + Union, + List, + Awaitable, + Callable, + Tuple, + Type, +) +from types import TracebackType + +if TYPE_CHECKING: + from typing_extensions import Protocol + + # The zlib compressor types aren't actually exposed anywhere + # publicly, so declare protocols for the portions we use. + class _Compressor(Protocol): + def compress(self, data: bytes) -> bytes: + pass + + def flush(self, mode: int) -> bytes: + pass + + class _Decompressor(Protocol): + unconsumed_tail = b"" # type: bytes + + def decompress(self, data: bytes, max_length: int) -> bytes: + pass + + class _WebSocketDelegate(Protocol): + # The common base interface implemented by WebSocketHandler on + # the server side and WebSocketClientConnection on the client + # side. + def on_ws_connection_close( + self, close_code: Optional[int] = None, close_reason: Optional[str] = None + ) -> None: + pass + + def on_message(self, message: Union[str, bytes]) -> Optional["Awaitable[None]"]: + pass + + def on_ping(self, data: bytes) -> None: + pass + + def on_pong(self, data: bytes) -> None: + pass + + def log_exception( + self, + typ: Optional[Type[BaseException]], + value: Optional[BaseException], + tb: Optional[TracebackType], + ) -> None: + pass + + +_default_max_message_size = 10 * 1024 * 1024 + + +class WebSocketError(Exception): + pass + + +class WebSocketClosedError(WebSocketError): + """Raised by operations on a closed connection. + + .. versionadded:: 3.2 + """ + + pass + + +class _DecompressTooLargeError(Exception): + pass + + +class _WebSocketParams(object): + def __init__( + self, + ping_interval: Optional[float] = None, + ping_timeout: Optional[float] = None, + max_message_size: int = _default_max_message_size, + compression_options: Optional[Dict[str, Any]] = None, + ) -> None: + self.ping_interval = ping_interval + self.ping_timeout = ping_timeout + self.max_message_size = max_message_size + self.compression_options = compression_options + + +class WebSocketHandler(tornado.web.RequestHandler): + """Subclass this class to create a basic WebSocket handler. + + Override `on_message` to handle incoming messages, and use + `write_message` to send messages to the client. You can also + override `open` and `on_close` to handle opened and closed + connections. + + Custom upgrade response headers can be sent by overriding + `~tornado.web.RequestHandler.set_default_headers` or + `~tornado.web.RequestHandler.prepare`. + + See http://dev.w3.org/html5/websockets/ for details on the + JavaScript interface. The protocol is specified at + http://tools.ietf.org/html/rfc6455. + + Here is an example WebSocket handler that echos back all received messages + back to the client: + + .. testcode:: + + class EchoWebSocket(tornado.websocket.WebSocketHandler): + def open(self): + print("WebSocket opened") + + def on_message(self, message): + self.write_message(u"You said: " + message) + + def on_close(self): + print("WebSocket closed") + + .. testoutput:: + :hide: + + WebSockets are not standard HTTP connections. The "handshake" is + HTTP, but after the handshake, the protocol is + message-based. Consequently, most of the Tornado HTTP facilities + are not available in handlers of this type. The only communication + methods available to you are `write_message()`, `ping()`, and + `close()`. Likewise, your request handler class should implement + `open()` method rather than ``get()`` or ``post()``. + + If you map the handler above to ``/websocket`` in your application, you can + invoke it in JavaScript with:: + + var ws = new WebSocket("ws://localhost:8888/websocket"); + ws.onopen = function() { + ws.send("Hello, world"); + }; + ws.onmessage = function (evt) { + alert(evt.data); + }; + + This script pops up an alert box that says "You said: Hello, world". + + Web browsers allow any site to open a websocket connection to any other, + instead of using the same-origin policy that governs other network + access from JavaScript. This can be surprising and is a potential + security hole, so since Tornado 4.0 `WebSocketHandler` requires + applications that wish to receive cross-origin websockets to opt in + by overriding the `~WebSocketHandler.check_origin` method (see that + method's docs for details). Failure to do so is the most likely + cause of 403 errors when making a websocket connection. + + When using a secure websocket connection (``wss://``) with a self-signed + certificate, the connection from a browser may fail because it wants + to show the "accept this certificate" dialog but has nowhere to show it. + You must first visit a regular HTML page using the same certificate + to accept it before the websocket connection will succeed. + + If the application setting ``websocket_ping_interval`` has a non-zero + value, a ping will be sent periodically, and the connection will be + closed if a response is not received before the ``websocket_ping_timeout``. + + Messages larger than the ``websocket_max_message_size`` application setting + (default 10MiB) will not be accepted. + + .. versionchanged:: 4.5 + Added ``websocket_ping_interval``, ``websocket_ping_timeout``, and + ``websocket_max_message_size``. + """ + + def __init__( + self, + application: tornado.web.Application, + request: httputil.HTTPServerRequest, + **kwargs: Any + ) -> None: + super().__init__(application, request, **kwargs) + self.ws_connection = None # type: Optional[WebSocketProtocol] + self.close_code = None # type: Optional[int] + self.close_reason = None # type: Optional[str] + self.stream = None # type: Optional[IOStream] + self._on_close_called = False + + async def get(self, *args: Any, **kwargs: Any) -> None: + self.open_args = args + self.open_kwargs = kwargs + + # Upgrade header should be present and should be equal to WebSocket + if self.request.headers.get("Upgrade", "").lower() != "websocket": + self.set_status(400) + log_msg = 'Can "Upgrade" only to "WebSocket".' + self.finish(log_msg) + gen_log.debug(log_msg) + return + + # Connection header should be upgrade. + # Some proxy servers/load balancers + # might mess with it. + headers = self.request.headers + connection = map( + lambda s: s.strip().lower(), headers.get("Connection", "").split(",") + ) + if "upgrade" not in connection: + self.set_status(400) + log_msg = '"Connection" must be "Upgrade".' + self.finish(log_msg) + gen_log.debug(log_msg) + return + + # Handle WebSocket Origin naming convention differences + # The difference between version 8 and 13 is that in 8 the + # client sends a "Sec-Websocket-Origin" header and in 13 it's + # simply "Origin". + if "Origin" in self.request.headers: + origin = self.request.headers.get("Origin") + else: + origin = self.request.headers.get("Sec-Websocket-Origin", None) + + # If there was an origin header, check to make sure it matches + # according to check_origin. When the origin is None, we assume it + # did not come from a browser and that it can be passed on. + if origin is not None and not self.check_origin(origin): + self.set_status(403) + log_msg = "Cross origin websockets not allowed" + self.finish(log_msg) + gen_log.debug(log_msg) + return + + self.ws_connection = self.get_websocket_protocol() + if self.ws_connection: + await self.ws_connection.accept_connection(self) + else: + self.set_status(426, "Upgrade Required") + self.set_header("Sec-WebSocket-Version", "7, 8, 13") + + @property + def ping_interval(self) -> Optional[float]: + """The interval for websocket keep-alive pings. + + Set websocket_ping_interval = 0 to disable pings. + """ + return self.settings.get("websocket_ping_interval", None) + + @property + def ping_timeout(self) -> Optional[float]: + """If no ping is received in this many seconds, + close the websocket connection (VPNs, etc. can fail to cleanly close ws connections). + Default is max of 3 pings or 30 seconds. + """ + return self.settings.get("websocket_ping_timeout", None) + + @property + def max_message_size(self) -> int: + """Maximum allowed message size. + + If the remote peer sends a message larger than this, the connection + will be closed. + + Default is 10MiB. + """ + return self.settings.get( + "websocket_max_message_size", _default_max_message_size + ) + + def write_message( + self, message: Union[bytes, str, Dict[str, Any]], binary: bool = False + ) -> "Future[None]": + """Sends the given message to the client of this Web Socket. + + The message may be either a string or a dict (which will be + encoded as json). If the ``binary`` argument is false, the + message will be sent as utf8; in binary mode any byte string + is allowed. + + If the connection is already closed, raises `WebSocketClosedError`. + Returns a `.Future` which can be used for flow control. + + .. versionchanged:: 3.2 + `WebSocketClosedError` was added (previously a closed connection + would raise an `AttributeError`) + + .. versionchanged:: 4.3 + Returns a `.Future` which can be used for flow control. + + .. versionchanged:: 5.0 + Consistently raises `WebSocketClosedError`. Previously could + sometimes raise `.StreamClosedError`. + """ + if self.ws_connection is None or self.ws_connection.is_closing(): + raise WebSocketClosedError() + if isinstance(message, dict): + message = tornado.escape.json_encode(message) + return self.ws_connection.write_message(message, binary=binary) + + def select_subprotocol(self, subprotocols: List[str]) -> Optional[str]: + """Override to implement subprotocol negotiation. + + ``subprotocols`` is a list of strings identifying the + subprotocols proposed by the client. This method may be + overridden to return one of those strings to select it, or + ``None`` to not select a subprotocol. + + Failure to select a subprotocol does not automatically abort + the connection, although clients may close the connection if + none of their proposed subprotocols was selected. + + The list may be empty, in which case this method must return + None. This method is always called exactly once even if no + subprotocols were proposed so that the handler can be advised + of this fact. + + .. versionchanged:: 5.1 + + Previously, this method was called with a list containing + an empty string instead of an empty list if no subprotocols + were proposed by the client. + """ + return None + + @property + def selected_subprotocol(self) -> Optional[str]: + """The subprotocol returned by `select_subprotocol`. + + .. versionadded:: 5.1 + """ + assert self.ws_connection is not None + return self.ws_connection.selected_subprotocol + + def get_compression_options(self) -> Optional[Dict[str, Any]]: + """Override to return compression options for the connection. + + If this method returns None (the default), compression will + be disabled. If it returns a dict (even an empty one), it + will be enabled. The contents of the dict may be used to + control the following compression options: + + ``compression_level`` specifies the compression level. + + ``mem_level`` specifies the amount of memory used for the internal compression state. + + These parameters are documented in details here: + https://docs.python.org/3.6/library/zlib.html#zlib.compressobj + + .. versionadded:: 4.1 + + .. versionchanged:: 4.5 + + Added ``compression_level`` and ``mem_level``. + """ + # TODO: Add wbits option. + return None + + def open(self, *args: str, **kwargs: str) -> Optional[Awaitable[None]]: + """Invoked when a new WebSocket is opened. + + The arguments to `open` are extracted from the `tornado.web.URLSpec` + regular expression, just like the arguments to + `tornado.web.RequestHandler.get`. + + `open` may be a coroutine. `on_message` will not be called until + `open` has returned. + + .. versionchanged:: 5.1 + + ``open`` may be a coroutine. + """ + pass + + def on_message(self, message: Union[str, bytes]) -> Optional[Awaitable[None]]: + """Handle incoming messages on the WebSocket + + This method must be overridden. + + .. versionchanged:: 4.5 + + ``on_message`` can be a coroutine. + """ + raise NotImplementedError + + def ping(self, data: Union[str, bytes] = b"") -> None: + """Send ping frame to the remote end. + + The data argument allows a small amount of data (up to 125 + bytes) to be sent as a part of the ping message. Note that not + all websocket implementations expose this data to + applications. + + Consider using the ``websocket_ping_interval`` application + setting instead of sending pings manually. + + .. versionchanged:: 5.1 + + The data argument is now optional. + + """ + data = utf8(data) + if self.ws_connection is None or self.ws_connection.is_closing(): + raise WebSocketClosedError() + self.ws_connection.write_ping(data) + + def on_pong(self, data: bytes) -> None: + """Invoked when the response to a ping frame is received.""" + pass + + def on_ping(self, data: bytes) -> None: + """Invoked when the a ping frame is received.""" + pass + + def on_close(self) -> None: + """Invoked when the WebSocket is closed. + + If the connection was closed cleanly and a status code or reason + phrase was supplied, these values will be available as the attributes + ``self.close_code`` and ``self.close_reason``. + + .. versionchanged:: 4.0 + + Added ``close_code`` and ``close_reason`` attributes. + """ + pass + + def close(self, code: Optional[int] = None, reason: Optional[str] = None) -> None: + """Closes this Web Socket. + + Once the close handshake is successful the socket will be closed. + + ``code`` may be a numeric status code, taken from the values + defined in `RFC 6455 section 7.4.1 + <https://tools.ietf.org/html/rfc6455#section-7.4.1>`_. + ``reason`` may be a textual message about why the connection is + closing. These values are made available to the client, but are + not otherwise interpreted by the websocket protocol. + + .. versionchanged:: 4.0 + + Added the ``code`` and ``reason`` arguments. + """ + if self.ws_connection: + self.ws_connection.close(code, reason) + self.ws_connection = None + + def check_origin(self, origin: str) -> bool: + """Override to enable support for allowing alternate origins. + + The ``origin`` argument is the value of the ``Origin`` HTTP + header, the url responsible for initiating this request. This + method is not called for clients that do not send this header; + such requests are always allowed (because all browsers that + implement WebSockets support this header, and non-browser + clients do not have the same cross-site security concerns). + + Should return ``True`` to accept the request or ``False`` to + reject it. By default, rejects all requests with an origin on + a host other than this one. + + This is a security protection against cross site scripting attacks on + browsers, since WebSockets are allowed to bypass the usual same-origin + policies and don't use CORS headers. + + .. warning:: + + This is an important security measure; don't disable it + without understanding the security implications. In + particular, if your authentication is cookie-based, you + must either restrict the origins allowed by + ``check_origin()`` or implement your own XSRF-like + protection for websocket connections. See `these + <https://www.christian-schneider.net/CrossSiteWebSocketHijacking.html>`_ + `articles + <https://devcenter.heroku.com/articles/websocket-security>`_ + for more. + + To accept all cross-origin traffic (which was the default prior to + Tornado 4.0), simply override this method to always return ``True``:: + + def check_origin(self, origin): + return True + + To allow connections from any subdomain of your site, you might + do something like:: + + def check_origin(self, origin): + parsed_origin = urllib.parse.urlparse(origin) + return parsed_origin.netloc.endswith(".mydomain.com") + + .. versionadded:: 4.0 + + """ + parsed_origin = urlparse(origin) + origin = parsed_origin.netloc + origin = origin.lower() + + host = self.request.headers.get("Host") + + # Check to see that origin matches host directly, including ports + return origin == host + + def set_nodelay(self, value: bool) -> None: + """Set the no-delay flag for this stream. + + By default, small messages may be delayed and/or combined to minimize + the number of packets sent. This can sometimes cause 200-500ms delays + due to the interaction between Nagle's algorithm and TCP delayed + ACKs. To reduce this delay (at the expense of possibly increasing + bandwidth usage), call ``self.set_nodelay(True)`` once the websocket + connection is established. + + See `.BaseIOStream.set_nodelay` for additional details. + + .. versionadded:: 3.1 + """ + assert self.ws_connection is not None + self.ws_connection.set_nodelay(value) + + def on_connection_close(self) -> None: + if self.ws_connection: + self.ws_connection.on_connection_close() + self.ws_connection = None + if not self._on_close_called: + self._on_close_called = True + self.on_close() + self._break_cycles() + + def on_ws_connection_close( + self, close_code: Optional[int] = None, close_reason: Optional[str] = None + ) -> None: + self.close_code = close_code + self.close_reason = close_reason + self.on_connection_close() + + def _break_cycles(self) -> None: + # WebSocketHandlers call finish() early, but we don't want to + # break up reference cycles (which makes it impossible to call + # self.render_string) until after we've really closed the + # connection (if it was established in the first place, + # indicated by status code 101). + if self.get_status() != 101 or self._on_close_called: + super()._break_cycles() + + def send_error(self, *args: Any, **kwargs: Any) -> None: + if self.stream is None: + super().send_error(*args, **kwargs) + else: + # If we get an uncaught exception during the handshake, + # we have no choice but to abruptly close the connection. + # TODO: for uncaught exceptions after the handshake, + # we can close the connection more gracefully. + self.stream.close() + + def get_websocket_protocol(self) -> Optional["WebSocketProtocol"]: + websocket_version = self.request.headers.get("Sec-WebSocket-Version") + if websocket_version in ("7", "8", "13"): + params = _WebSocketParams( + ping_interval=self.ping_interval, + ping_timeout=self.ping_timeout, + max_message_size=self.max_message_size, + compression_options=self.get_compression_options(), + ) + return WebSocketProtocol13(self, False, params) + return None + + def _detach_stream(self) -> IOStream: + # disable non-WS methods + for method in [ + "write", + "redirect", + "set_header", + "set_cookie", + "set_status", + "flush", + "finish", + ]: + setattr(self, method, _raise_not_supported_for_websockets) + return self.detach() + + +def _raise_not_supported_for_websockets(*args: Any, **kwargs: Any) -> None: + raise RuntimeError("Method not supported for Web Sockets") + + +class WebSocketProtocol(abc.ABC): + """Base class for WebSocket protocol versions. + """ + + def __init__(self, handler: "_WebSocketDelegate") -> None: + self.handler = handler + self.stream = None # type: Optional[IOStream] + self.client_terminated = False + self.server_terminated = False + + def _run_callback( + self, callback: Callable, *args: Any, **kwargs: Any + ) -> "Optional[Future[Any]]": + """Runs the given callback with exception handling. + + If the callback is a coroutine, returns its Future. On error, aborts the + websocket connection and returns None. + """ + try: + result = callback(*args, **kwargs) + except Exception: + self.handler.log_exception(*sys.exc_info()) + self._abort() + return None + else: + if result is not None: + result = gen.convert_yielded(result) + assert self.stream is not None + self.stream.io_loop.add_future(result, lambda f: f.result()) + return result + + def on_connection_close(self) -> None: + self._abort() + + def _abort(self) -> None: + """Instantly aborts the WebSocket connection by closing the socket""" + self.client_terminated = True + self.server_terminated = True + if self.stream is not None: + self.stream.close() # forcibly tear down the connection + self.close() # let the subclass cleanup + + @abc.abstractmethod + def close(self, code: Optional[int] = None, reason: Optional[str] = None) -> None: + raise NotImplementedError() + + @abc.abstractmethod + def is_closing(self) -> bool: + raise NotImplementedError() + + @abc.abstractmethod + async def accept_connection(self, handler: WebSocketHandler) -> None: + raise NotImplementedError() + + @abc.abstractmethod + def write_message( + self, message: Union[str, bytes], binary: bool = False + ) -> "Future[None]": + raise NotImplementedError() + + @property + @abc.abstractmethod + def selected_subprotocol(self) -> Optional[str]: + raise NotImplementedError() + + @abc.abstractmethod + def write_ping(self, data: bytes) -> None: + raise NotImplementedError() + + # The entry points below are used by WebSocketClientConnection, + # which was introduced after we only supported a single version of + # WebSocketProtocol. The WebSocketProtocol/WebSocketProtocol13 + # boundary is currently pretty ad-hoc. + @abc.abstractmethod + def _process_server_headers( + self, key: Union[str, bytes], headers: httputil.HTTPHeaders + ) -> None: + raise NotImplementedError() + + @abc.abstractmethod + def start_pinging(self) -> None: + raise NotImplementedError() + + @abc.abstractmethod + async def _receive_frame_loop(self) -> None: + raise NotImplementedError() + + @abc.abstractmethod + def set_nodelay(self, x: bool) -> None: + raise NotImplementedError() + + +class _PerMessageDeflateCompressor(object): + def __init__( + self, + persistent: bool, + max_wbits: Optional[int], + compression_options: Optional[Dict[str, Any]] = None, + ) -> None: + if max_wbits is None: + max_wbits = zlib.MAX_WBITS + # There is no symbolic constant for the minimum wbits value. + if not (8 <= max_wbits <= zlib.MAX_WBITS): + raise ValueError( + "Invalid max_wbits value %r; allowed range 8-%d", + max_wbits, + zlib.MAX_WBITS, + ) + self._max_wbits = max_wbits + + if ( + compression_options is None + or "compression_level" not in compression_options + ): + self._compression_level = tornado.web.GZipContentEncoding.GZIP_LEVEL + else: + self._compression_level = compression_options["compression_level"] + + if compression_options is None or "mem_level" not in compression_options: + self._mem_level = 8 + else: + self._mem_level = compression_options["mem_level"] + + if persistent: + self._compressor = self._create_compressor() # type: Optional[_Compressor] + else: + self._compressor = None + + def _create_compressor(self) -> "_Compressor": + return zlib.compressobj( + self._compression_level, zlib.DEFLATED, -self._max_wbits, self._mem_level + ) + + def compress(self, data: bytes) -> bytes: + compressor = self._compressor or self._create_compressor() + data = compressor.compress(data) + compressor.flush(zlib.Z_SYNC_FLUSH) + assert data.endswith(b"\x00\x00\xff\xff") + return data[:-4] + + +class _PerMessageDeflateDecompressor(object): + def __init__( + self, + persistent: bool, + max_wbits: Optional[int], + max_message_size: int, + compression_options: Optional[Dict[str, Any]] = None, + ) -> None: + self._max_message_size = max_message_size + if max_wbits is None: + max_wbits = zlib.MAX_WBITS + if not (8 <= max_wbits <= zlib.MAX_WBITS): + raise ValueError( + "Invalid max_wbits value %r; allowed range 8-%d", + max_wbits, + zlib.MAX_WBITS, + ) + self._max_wbits = max_wbits + if persistent: + self._decompressor = ( + self._create_decompressor() + ) # type: Optional[_Decompressor] + else: + self._decompressor = None + + def _create_decompressor(self) -> "_Decompressor": + return zlib.decompressobj(-self._max_wbits) + + def decompress(self, data: bytes) -> bytes: + decompressor = self._decompressor or self._create_decompressor() + result = decompressor.decompress( + data + b"\x00\x00\xff\xff", self._max_message_size + ) + if decompressor.unconsumed_tail: + raise _DecompressTooLargeError() + return result + + +class WebSocketProtocol13(WebSocketProtocol): + """Implementation of the WebSocket protocol from RFC 6455. + + This class supports versions 7 and 8 of the protocol in addition to the + final version 13. + """ + + # Bit masks for the first byte of a frame. + FIN = 0x80 + RSV1 = 0x40 + RSV2 = 0x20 + RSV3 = 0x10 + RSV_MASK = RSV1 | RSV2 | RSV3 + OPCODE_MASK = 0x0F + + stream = None # type: IOStream + + def __init__( + self, + handler: "_WebSocketDelegate", + mask_outgoing: bool, + params: _WebSocketParams, + ) -> None: + WebSocketProtocol.__init__(self, handler) + self.mask_outgoing = mask_outgoing + self.params = params + self._final_frame = False + self._frame_opcode = None + self._masked_frame = None + self._frame_mask = None # type: Optional[bytes] + self._frame_length = None + self._fragmented_message_buffer = None # type: Optional[bytes] + self._fragmented_message_opcode = None + self._waiting = None # type: object + self._compression_options = params.compression_options + self._decompressor = None # type: Optional[_PerMessageDeflateDecompressor] + self._compressor = None # type: Optional[_PerMessageDeflateCompressor] + self._frame_compressed = None # type: Optional[bool] + # The total uncompressed size of all messages received or sent. + # Unicode messages are encoded to utf8. + # Only for testing; subject to change. + self._message_bytes_in = 0 + self._message_bytes_out = 0 + # The total size of all packets received or sent. Includes + # the effect of compression, frame overhead, and control frames. + self._wire_bytes_in = 0 + self._wire_bytes_out = 0 + self.ping_callback = None # type: Optional[PeriodicCallback] + self.last_ping = 0.0 + self.last_pong = 0.0 + self.close_code = None # type: Optional[int] + self.close_reason = None # type: Optional[str] + + # Use a property for this to satisfy the abc. + @property + def selected_subprotocol(self) -> Optional[str]: + return self._selected_subprotocol + + @selected_subprotocol.setter + def selected_subprotocol(self, value: Optional[str]) -> None: + self._selected_subprotocol = value + + async def accept_connection(self, handler: WebSocketHandler) -> None: + try: + self._handle_websocket_headers(handler) + except ValueError: + handler.set_status(400) + log_msg = "Missing/Invalid WebSocket headers" + handler.finish(log_msg) + gen_log.debug(log_msg) + return + + try: + await self._accept_connection(handler) + except asyncio.CancelledError: + self._abort() + return + except ValueError: + gen_log.debug("Malformed WebSocket request received", exc_info=True) + self._abort() + return + + def _handle_websocket_headers(self, handler: WebSocketHandler) -> None: + """Verifies all invariant- and required headers + + If a header is missing or have an incorrect value ValueError will be + raised + """ + fields = ("Host", "Sec-Websocket-Key", "Sec-Websocket-Version") + if not all(map(lambda f: handler.request.headers.get(f), fields)): + raise ValueError("Missing/Invalid WebSocket headers") + + @staticmethod + def compute_accept_value(key: Union[str, bytes]) -> str: + """Computes the value for the Sec-WebSocket-Accept header, + given the value for Sec-WebSocket-Key. + """ + sha1 = hashlib.sha1() + sha1.update(utf8(key)) + sha1.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") # Magic value + return native_str(base64.b64encode(sha1.digest())) + + def _challenge_response(self, handler: WebSocketHandler) -> str: + return WebSocketProtocol13.compute_accept_value( + cast(str, handler.request.headers.get("Sec-Websocket-Key")) + ) + + async def _accept_connection(self, handler: WebSocketHandler) -> None: + subprotocol_header = handler.request.headers.get("Sec-WebSocket-Protocol") + if subprotocol_header: + subprotocols = [s.strip() for s in subprotocol_header.split(",")] + else: + subprotocols = [] + self.selected_subprotocol = handler.select_subprotocol(subprotocols) + if self.selected_subprotocol: + assert self.selected_subprotocol in subprotocols + handler.set_header("Sec-WebSocket-Protocol", self.selected_subprotocol) + + extensions = self._parse_extensions_header(handler.request.headers) + for ext in extensions: + if ext[0] == "permessage-deflate" and self._compression_options is not None: + # TODO: negotiate parameters if compression_options + # specifies limits. + self._create_compressors("server", ext[1], self._compression_options) + if ( + "client_max_window_bits" in ext[1] + and ext[1]["client_max_window_bits"] is None + ): + # Don't echo an offered client_max_window_bits + # parameter with no value. + del ext[1]["client_max_window_bits"] + handler.set_header( + "Sec-WebSocket-Extensions", + httputil._encode_header("permessage-deflate", ext[1]), + ) + break + + handler.clear_header("Content-Type") + handler.set_status(101) + handler.set_header("Upgrade", "websocket") + handler.set_header("Connection", "Upgrade") + handler.set_header("Sec-WebSocket-Accept", self._challenge_response(handler)) + handler.finish() + + self.stream = handler._detach_stream() + + self.start_pinging() + try: + open_result = handler.open(*handler.open_args, **handler.open_kwargs) + if open_result is not None: + await open_result + except Exception: + handler.log_exception(*sys.exc_info()) + self._abort() + return + + await self._receive_frame_loop() + + def _parse_extensions_header( + self, headers: httputil.HTTPHeaders + ) -> List[Tuple[str, Dict[str, str]]]: + extensions = headers.get("Sec-WebSocket-Extensions", "") + if extensions: + return [httputil._parse_header(e.strip()) for e in extensions.split(",")] + return [] + + def _process_server_headers( + self, key: Union[str, bytes], headers: httputil.HTTPHeaders + ) -> None: + """Process the headers sent by the server to this client connection. + + 'key' is the websocket handshake challenge/response key. + """ + assert headers["Upgrade"].lower() == "websocket" + assert headers["Connection"].lower() == "upgrade" + accept = self.compute_accept_value(key) + assert headers["Sec-Websocket-Accept"] == accept + + extensions = self._parse_extensions_header(headers) + for ext in extensions: + if ext[0] == "permessage-deflate" and self._compression_options is not None: + self._create_compressors("client", ext[1]) + else: + raise ValueError("unsupported extension %r", ext) + + self.selected_subprotocol = headers.get("Sec-WebSocket-Protocol", None) + + def _get_compressor_options( + self, + side: str, + agreed_parameters: Dict[str, Any], + compression_options: Optional[Dict[str, Any]] = None, + ) -> Dict[str, Any]: + """Converts a websocket agreed_parameters set to keyword arguments + for our compressor objects. + """ + options = dict( + persistent=(side + "_no_context_takeover") not in agreed_parameters + ) # type: Dict[str, Any] + wbits_header = agreed_parameters.get(side + "_max_window_bits", None) + if wbits_header is None: + options["max_wbits"] = zlib.MAX_WBITS + else: + options["max_wbits"] = int(wbits_header) + options["compression_options"] = compression_options + return options + + def _create_compressors( + self, + side: str, + agreed_parameters: Dict[str, Any], + compression_options: Optional[Dict[str, Any]] = None, + ) -> None: + # TODO: handle invalid parameters gracefully + allowed_keys = set( + [ + "server_no_context_takeover", + "client_no_context_takeover", + "server_max_window_bits", + "client_max_window_bits", + ] + ) + for key in agreed_parameters: + if key not in allowed_keys: + raise ValueError("unsupported compression parameter %r" % key) + other_side = "client" if (side == "server") else "server" + self._compressor = _PerMessageDeflateCompressor( + **self._get_compressor_options(side, agreed_parameters, compression_options) + ) + self._decompressor = _PerMessageDeflateDecompressor( + max_message_size=self.params.max_message_size, + **self._get_compressor_options( + other_side, agreed_parameters, compression_options + ) + ) + + def _write_frame( + self, fin: bool, opcode: int, data: bytes, flags: int = 0 + ) -> "Future[None]": + data_len = len(data) + if opcode & 0x8: + # All control frames MUST have a payload length of 125 + # bytes or less and MUST NOT be fragmented. + if not fin: + raise ValueError("control frames may not be fragmented") + if data_len > 125: + raise ValueError("control frame payloads may not exceed 125 bytes") + if fin: + finbit = self.FIN + else: + finbit = 0 + frame = struct.pack("B", finbit | opcode | flags) + if self.mask_outgoing: + mask_bit = 0x80 + else: + mask_bit = 0 + if data_len < 126: + frame += struct.pack("B", data_len | mask_bit) + elif data_len <= 0xFFFF: + frame += struct.pack("!BH", 126 | mask_bit, data_len) + else: + frame += struct.pack("!BQ", 127 | mask_bit, data_len) + if self.mask_outgoing: + mask = os.urandom(4) + data = mask + _websocket_mask(mask, data) + frame += data + self._wire_bytes_out += len(frame) + return self.stream.write(frame) + + def write_message( + self, message: Union[str, bytes], binary: bool = False + ) -> "Future[None]": + """Sends the given message to the client of this Web Socket.""" + if binary: + opcode = 0x2 + else: + opcode = 0x1 + message = tornado.escape.utf8(message) + assert isinstance(message, bytes) + self._message_bytes_out += len(message) + flags = 0 + if self._compressor: + message = self._compressor.compress(message) + flags |= self.RSV1 + # For historical reasons, write methods in Tornado operate in a semi-synchronous + # mode in which awaiting the Future they return is optional (But errors can + # still be raised). This requires us to go through an awkward dance here + # to transform the errors that may be returned while presenting the same + # semi-synchronous interface. + try: + fut = self._write_frame(True, opcode, message, flags=flags) + except StreamClosedError: + raise WebSocketClosedError() + + async def wrapper() -> None: + try: + await fut + except StreamClosedError: + raise WebSocketClosedError() + + return asyncio.ensure_future(wrapper()) + + def write_ping(self, data: bytes) -> None: + """Send ping frame.""" + assert isinstance(data, bytes) + self._write_frame(True, 0x9, data) + + async def _receive_frame_loop(self) -> None: + try: + while not self.client_terminated: + await self._receive_frame() + except StreamClosedError: + self._abort() + self.handler.on_ws_connection_close(self.close_code, self.close_reason) + + async def _read_bytes(self, n: int) -> bytes: + data = await self.stream.read_bytes(n) + self._wire_bytes_in += n + return data + + async def _receive_frame(self) -> None: + # Read the frame header. + data = await self._read_bytes(2) + header, mask_payloadlen = struct.unpack("BB", data) + is_final_frame = header & self.FIN + reserved_bits = header & self.RSV_MASK + opcode = header & self.OPCODE_MASK + opcode_is_control = opcode & 0x8 + if self._decompressor is not None and opcode != 0: + # Compression flag is present in the first frame's header, + # but we can't decompress until we have all the frames of + # the message. + self._frame_compressed = bool(reserved_bits & self.RSV1) + reserved_bits &= ~self.RSV1 + if reserved_bits: + # client is using as-yet-undefined extensions; abort + self._abort() + return + is_masked = bool(mask_payloadlen & 0x80) + payloadlen = mask_payloadlen & 0x7F + + # Parse and validate the length. + if opcode_is_control and payloadlen >= 126: + # control frames must have payload < 126 + self._abort() + return + if payloadlen < 126: + self._frame_length = payloadlen + elif payloadlen == 126: + data = await self._read_bytes(2) + payloadlen = struct.unpack("!H", data)[0] + elif payloadlen == 127: + data = await self._read_bytes(8) + payloadlen = struct.unpack("!Q", data)[0] + new_len = payloadlen + if self._fragmented_message_buffer is not None: + new_len += len(self._fragmented_message_buffer) + if new_len > self.params.max_message_size: + self.close(1009, "message too big") + self._abort() + return + + # Read the payload, unmasking if necessary. + if is_masked: + self._frame_mask = await self._read_bytes(4) + data = await self._read_bytes(payloadlen) + if is_masked: + assert self._frame_mask is not None + data = _websocket_mask(self._frame_mask, data) + + # Decide what to do with this frame. + if opcode_is_control: + # control frames may be interleaved with a series of fragmented + # data frames, so control frames must not interact with + # self._fragmented_* + if not is_final_frame: + # control frames must not be fragmented + self._abort() + return + elif opcode == 0: # continuation frame + if self._fragmented_message_buffer is None: + # nothing to continue + self._abort() + return + self._fragmented_message_buffer += data + if is_final_frame: + opcode = self._fragmented_message_opcode + data = self._fragmented_message_buffer + self._fragmented_message_buffer = None + else: # start of new data message + if self._fragmented_message_buffer is not None: + # can't start new message until the old one is finished + self._abort() + return + if not is_final_frame: + self._fragmented_message_opcode = opcode + self._fragmented_message_buffer = data + + if is_final_frame: + handled_future = self._handle_message(opcode, data) + if handled_future is not None: + await handled_future + + def _handle_message(self, opcode: int, data: bytes) -> "Optional[Future[None]]": + """Execute on_message, returning its Future if it is a coroutine.""" + if self.client_terminated: + return None + + if self._frame_compressed: + assert self._decompressor is not None + try: + data = self._decompressor.decompress(data) + except _DecompressTooLargeError: + self.close(1009, "message too big after decompression") + self._abort() + return None + + if opcode == 0x1: + # UTF-8 data + self._message_bytes_in += len(data) + try: + decoded = data.decode("utf-8") + except UnicodeDecodeError: + self._abort() + return None + return self._run_callback(self.handler.on_message, decoded) + elif opcode == 0x2: + # Binary data + self._message_bytes_in += len(data) + return self._run_callback(self.handler.on_message, data) + elif opcode == 0x8: + # Close + self.client_terminated = True + if len(data) >= 2: + self.close_code = struct.unpack(">H", data[:2])[0] + if len(data) > 2: + self.close_reason = to_unicode(data[2:]) + # Echo the received close code, if any (RFC 6455 section 5.5.1). + self.close(self.close_code) + elif opcode == 0x9: + # Ping + try: + self._write_frame(True, 0xA, data) + except StreamClosedError: + self._abort() + self._run_callback(self.handler.on_ping, data) + elif opcode == 0xA: + # Pong + self.last_pong = IOLoop.current().time() + return self._run_callback(self.handler.on_pong, data) + else: + self._abort() + return None + + def close(self, code: Optional[int] = None, reason: Optional[str] = None) -> None: + """Closes the WebSocket connection.""" + if not self.server_terminated: + if not self.stream.closed(): + if code is None and reason is not None: + code = 1000 # "normal closure" status code + if code is None: + close_data = b"" + else: + close_data = struct.pack(">H", code) + if reason is not None: + close_data += utf8(reason) + try: + self._write_frame(True, 0x8, close_data) + except StreamClosedError: + self._abort() + self.server_terminated = True + if self.client_terminated: + if self._waiting is not None: + self.stream.io_loop.remove_timeout(self._waiting) + self._waiting = None + self.stream.close() + elif self._waiting is None: + # Give the client a few seconds to complete a clean shutdown, + # otherwise just close the connection. + self._waiting = self.stream.io_loop.add_timeout( + self.stream.io_loop.time() + 5, self._abort + ) + if self.ping_callback: + self.ping_callback.stop() + self.ping_callback = None + + def is_closing(self) -> bool: + """Return ``True`` if this connection is closing. + + The connection is considered closing if either side has + initiated its closing handshake or if the stream has been + shut down uncleanly. + """ + return self.stream.closed() or self.client_terminated or self.server_terminated + + @property + def ping_interval(self) -> Optional[float]: + interval = self.params.ping_interval + if interval is not None: + return interval + return 0 + + @property + def ping_timeout(self) -> Optional[float]: + timeout = self.params.ping_timeout + if timeout is not None: + return timeout + assert self.ping_interval is not None + return max(3 * self.ping_interval, 30) + + def start_pinging(self) -> None: + """Start sending periodic pings to keep the connection alive""" + assert self.ping_interval is not None + if self.ping_interval > 0: + self.last_ping = self.last_pong = IOLoop.current().time() + self.ping_callback = PeriodicCallback( + self.periodic_ping, self.ping_interval * 1000 + ) + self.ping_callback.start() + + def periodic_ping(self) -> None: + """Send a ping to keep the websocket alive + + Called periodically if the websocket_ping_interval is set and non-zero. + """ + if self.is_closing() and self.ping_callback is not None: + self.ping_callback.stop() + return + + # Check for timeout on pong. Make sure that we really have + # sent a recent ping in case the machine with both server and + # client has been suspended since the last ping. + now = IOLoop.current().time() + since_last_pong = now - self.last_pong + since_last_ping = now - self.last_ping + assert self.ping_interval is not None + assert self.ping_timeout is not None + if ( + since_last_ping < 2 * self.ping_interval + and since_last_pong > self.ping_timeout + ): + self.close() + return + + self.write_ping(b"") + self.last_ping = now + + def set_nodelay(self, x: bool) -> None: + self.stream.set_nodelay(x) + + +class WebSocketClientConnection(simple_httpclient._HTTPConnection): + """WebSocket client connection. + + This class should not be instantiated directly; use the + `websocket_connect` function instead. + """ + + protocol = None # type: WebSocketProtocol + + def __init__( + self, + request: httpclient.HTTPRequest, + on_message_callback: Optional[Callable[[Union[None, str, bytes]], None]] = None, + compression_options: Optional[Dict[str, Any]] = None, + ping_interval: Optional[float] = None, + ping_timeout: Optional[float] = None, + max_message_size: int = _default_max_message_size, + subprotocols: Optional[List[str]] = [], + ) -> None: + self.connect_future = Future() # type: Future[WebSocketClientConnection] + self.read_queue = Queue(1) # type: Queue[Union[None, str, bytes]] + self.key = base64.b64encode(os.urandom(16)) + self._on_message_callback = on_message_callback + self.close_code = None # type: Optional[int] + self.close_reason = None # type: Optional[str] + self.params = _WebSocketParams( + ping_interval=ping_interval, + ping_timeout=ping_timeout, + max_message_size=max_message_size, + compression_options=compression_options, + ) + + scheme, sep, rest = request.url.partition(":") + scheme = {"ws": "http", "wss": "https"}[scheme] + request.url = scheme + sep + rest + request.headers.update( + { + "Upgrade": "websocket", + "Connection": "Upgrade", + "Sec-WebSocket-Key": self.key, + "Sec-WebSocket-Version": "13", + } + ) + if subprotocols is not None: + request.headers["Sec-WebSocket-Protocol"] = ",".join(subprotocols) + if compression_options is not None: + # Always offer to let the server set our max_wbits (and even though + # we don't offer it, we will accept a client_no_context_takeover + # from the server). + # TODO: set server parameters for deflate extension + # if requested in self.compression_options. + request.headers[ + "Sec-WebSocket-Extensions" + ] = "permessage-deflate; client_max_window_bits" + + # Websocket connection is currently unable to follow redirects + request.follow_redirects = False + + self.tcp_client = TCPClient() + super().__init__( + None, + request, + lambda: None, + self._on_http_response, + 104857600, + self.tcp_client, + 65536, + 104857600, + ) + + def close(self, code: Optional[int] = None, reason: Optional[str] = None) -> None: + """Closes the websocket connection. + + ``code`` and ``reason`` are documented under + `WebSocketHandler.close`. + + .. versionadded:: 3.2 + + .. versionchanged:: 4.0 + + Added the ``code`` and ``reason`` arguments. + """ + if self.protocol is not None: + self.protocol.close(code, reason) + self.protocol = None # type: ignore + + def on_connection_close(self) -> None: + if not self.connect_future.done(): + self.connect_future.set_exception(StreamClosedError()) + self._on_message(None) + self.tcp_client.close() + super().on_connection_close() + + def on_ws_connection_close( + self, close_code: Optional[int] = None, close_reason: Optional[str] = None + ) -> None: + self.close_code = close_code + self.close_reason = close_reason + self.on_connection_close() + + def _on_http_response(self, response: httpclient.HTTPResponse) -> None: + if not self.connect_future.done(): + if response.error: + self.connect_future.set_exception(response.error) + else: + self.connect_future.set_exception( + WebSocketError("Non-websocket response") + ) + + async def headers_received( + self, + start_line: Union[httputil.RequestStartLine, httputil.ResponseStartLine], + headers: httputil.HTTPHeaders, + ) -> None: + assert isinstance(start_line, httputil.ResponseStartLine) + if start_line.code != 101: + await super().headers_received(start_line, headers) + return + + if self._timeout is not None: + self.io_loop.remove_timeout(self._timeout) + self._timeout = None + + self.headers = headers + self.protocol = self.get_websocket_protocol() + self.protocol._process_server_headers(self.key, self.headers) + self.protocol.stream = self.connection.detach() + + IOLoop.current().add_callback(self.protocol._receive_frame_loop) + self.protocol.start_pinging() + + # Once we've taken over the connection, clear the final callback + # we set on the http request. This deactivates the error handling + # in simple_httpclient that would otherwise interfere with our + # ability to see exceptions. + self.final_callback = None # type: ignore + + future_set_result_unless_cancelled(self.connect_future, self) + + def write_message( + self, message: Union[str, bytes], binary: bool = False + ) -> "Future[None]": + """Sends a message to the WebSocket server. + + If the stream is closed, raises `WebSocketClosedError`. + Returns a `.Future` which can be used for flow control. + + .. versionchanged:: 5.0 + Exception raised on a closed stream changed from `.StreamClosedError` + to `WebSocketClosedError`. + """ + return self.protocol.write_message(message, binary=binary) + + def read_message( + self, + callback: Optional[Callable[["Future[Union[None, str, bytes]]"], None]] = None, + ) -> Awaitable[Union[None, str, bytes]]: + """Reads a message from the WebSocket server. + + If on_message_callback was specified at WebSocket + initialization, this function will never return messages + + Returns a future whose result is the message, or None + if the connection is closed. If a callback argument + is given it will be called with the future when it is + ready. + """ + + awaitable = self.read_queue.get() + if callback is not None: + self.io_loop.add_future(asyncio.ensure_future(awaitable), callback) + return awaitable + + def on_message(self, message: Union[str, bytes]) -> Optional[Awaitable[None]]: + return self._on_message(message) + + def _on_message( + self, message: Union[None, str, bytes] + ) -> Optional[Awaitable[None]]: + if self._on_message_callback: + self._on_message_callback(message) + return None + else: + return self.read_queue.put(message) + + def ping(self, data: bytes = b"") -> None: + """Send ping frame to the remote end. + + The data argument allows a small amount of data (up to 125 + bytes) to be sent as a part of the ping message. Note that not + all websocket implementations expose this data to + applications. + + Consider using the ``ping_interval`` argument to + `websocket_connect` instead of sending pings manually. + + .. versionadded:: 5.1 + + """ + data = utf8(data) + if self.protocol is None: + raise WebSocketClosedError() + self.protocol.write_ping(data) + + def on_pong(self, data: bytes) -> None: + pass + + def on_ping(self, data: bytes) -> None: + pass + + def get_websocket_protocol(self) -> WebSocketProtocol: + return WebSocketProtocol13(self, mask_outgoing=True, params=self.params) + + @property + def selected_subprotocol(self) -> Optional[str]: + """The subprotocol selected by the server. + + .. versionadded:: 5.1 + """ + return self.protocol.selected_subprotocol + + def log_exception( + self, + typ: "Optional[Type[BaseException]]", + value: Optional[BaseException], + tb: Optional[TracebackType], + ) -> None: + assert typ is not None + assert value is not None + app_log.error("Uncaught exception %s", value, exc_info=(typ, value, tb)) + + +def websocket_connect( + url: Union[str, httpclient.HTTPRequest], + callback: Optional[Callable[["Future[WebSocketClientConnection]"], None]] = None, + connect_timeout: Optional[float] = None, + on_message_callback: Optional[Callable[[Union[None, str, bytes]], None]] = None, + compression_options: Optional[Dict[str, Any]] = None, + ping_interval: Optional[float] = None, + ping_timeout: Optional[float] = None, + max_message_size: int = _default_max_message_size, + subprotocols: Optional[List[str]] = None, +) -> "Awaitable[WebSocketClientConnection]": + """Client-side websocket support. + + Takes a url and returns a Future whose result is a + `WebSocketClientConnection`. + + ``compression_options`` is interpreted in the same way as the + return value of `.WebSocketHandler.get_compression_options`. + + The connection supports two styles of operation. In the coroutine + style, the application typically calls + `~.WebSocketClientConnection.read_message` in a loop:: + + conn = yield websocket_connect(url) + while True: + msg = yield conn.read_message() + if msg is None: break + # Do something with msg + + In the callback style, pass an ``on_message_callback`` to + ``websocket_connect``. In both styles, a message of ``None`` + indicates that the connection has been closed. + + ``subprotocols`` may be a list of strings specifying proposed + subprotocols. The selected protocol may be found on the + ``selected_subprotocol`` attribute of the connection object + when the connection is complete. + + .. versionchanged:: 3.2 + Also accepts ``HTTPRequest`` objects in place of urls. + + .. versionchanged:: 4.1 + Added ``compression_options`` and ``on_message_callback``. + + .. versionchanged:: 4.5 + Added the ``ping_interval``, ``ping_timeout``, and ``max_message_size`` + arguments, which have the same meaning as in `WebSocketHandler`. + + .. versionchanged:: 5.0 + The ``io_loop`` argument (deprecated since version 4.1) has been removed. + + .. versionchanged:: 5.1 + Added the ``subprotocols`` argument. + """ + if isinstance(url, httpclient.HTTPRequest): + assert connect_timeout is None + request = url + # Copy and convert the headers dict/object (see comments in + # AsyncHTTPClient.fetch) + request.headers = httputil.HTTPHeaders(request.headers) + else: + request = httpclient.HTTPRequest(url, connect_timeout=connect_timeout) + request = cast( + httpclient.HTTPRequest, + httpclient._RequestProxy(request, httpclient.HTTPRequest._DEFAULTS), + ) + conn = WebSocketClientConnection( + request, + on_message_callback=on_message_callback, + compression_options=compression_options, + ping_interval=ping_interval, + ping_timeout=ping_timeout, + max_message_size=max_message_size, + subprotocols=subprotocols, + ) + if callback is not None: + IOLoop.current().add_future(conn.connect_future, callback) + return conn.connect_future diff --git a/venv/lib/python3.8/site-packages/tornado/wsgi.py b/venv/lib/python3.8/site-packages/tornado/wsgi.py new file mode 100644 index 0000000..77124aa --- /dev/null +++ b/venv/lib/python3.8/site-packages/tornado/wsgi.py @@ -0,0 +1,199 @@ +# +# Copyright 2009 Facebook +# +# 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. + +"""WSGI support for the Tornado web framework. + +WSGI is the Python standard for web servers, and allows for interoperability +between Tornado and other Python web frameworks and servers. + +This module provides WSGI support via the `WSGIContainer` class, which +makes it possible to run applications using other WSGI frameworks on +the Tornado HTTP server. The reverse is not supported; the Tornado +`.Application` and `.RequestHandler` classes are designed for use with +the Tornado `.HTTPServer` and cannot be used in a generic WSGI +container. + +""" + +import sys +from io import BytesIO +import tornado + +from tornado import escape +from tornado import httputil +from tornado.log import access_log + +from typing import List, Tuple, Optional, Callable, Any, Dict, Text +from types import TracebackType +import typing + +if typing.TYPE_CHECKING: + from typing import Type # noqa: F401 + from wsgiref.types import WSGIApplication as WSGIAppType # noqa: F401 + + +# PEP 3333 specifies that WSGI on python 3 generally deals with byte strings +# that are smuggled inside objects of type unicode (via the latin1 encoding). +# This function is like those in the tornado.escape module, but defined +# here to minimize the temptation to use it in non-wsgi contexts. +def to_wsgi_str(s: bytes) -> str: + assert isinstance(s, bytes) + return s.decode("latin1") + + +class WSGIContainer(object): + r"""Makes a WSGI-compatible function runnable on Tornado's HTTP server. + + .. warning:: + + WSGI is a *synchronous* interface, while Tornado's concurrency model + is based on single-threaded asynchronous execution. This means that + running a WSGI app with Tornado's `WSGIContainer` is *less scalable* + than running the same app in a multi-threaded WSGI server like + ``gunicorn`` or ``uwsgi``. Use `WSGIContainer` only when there are + benefits to combining Tornado and WSGI in the same process that + outweigh the reduced scalability. + + Wrap a WSGI function in a `WSGIContainer` and pass it to `.HTTPServer` to + run it. For example:: + + def simple_app(environ, start_response): + status = "200 OK" + response_headers = [("Content-type", "text/plain")] + start_response(status, response_headers) + return ["Hello world!\n"] + + container = tornado.wsgi.WSGIContainer(simple_app) + http_server = tornado.httpserver.HTTPServer(container) + http_server.listen(8888) + tornado.ioloop.IOLoop.current().start() + + This class is intended to let other frameworks (Django, web.py, etc) + run on the Tornado HTTP server and I/O loop. + + The `tornado.web.FallbackHandler` class is often useful for mixing + Tornado and WSGI apps in the same server. See + https://github.com/bdarnell/django-tornado-demo for a complete example. + """ + + def __init__(self, wsgi_application: "WSGIAppType") -> None: + self.wsgi_application = wsgi_application + + def __call__(self, request: httputil.HTTPServerRequest) -> None: + data = {} # type: Dict[str, Any] + response = [] # type: List[bytes] + + def start_response( + status: str, + headers: List[Tuple[str, str]], + exc_info: Optional[ + Tuple[ + "Optional[Type[BaseException]]", + Optional[BaseException], + Optional[TracebackType], + ] + ] = None, + ) -> Callable[[bytes], Any]: + data["status"] = status + data["headers"] = headers + return response.append + + app_response = self.wsgi_application( + WSGIContainer.environ(request), start_response + ) + try: + response.extend(app_response) + body = b"".join(response) + finally: + if hasattr(app_response, "close"): + app_response.close() # type: ignore + if not data: + raise Exception("WSGI app did not call start_response") + + status_code_str, reason = data["status"].split(" ", 1) + status_code = int(status_code_str) + headers = data["headers"] # type: List[Tuple[str, str]] + header_set = set(k.lower() for (k, v) in headers) + body = escape.utf8(body) + if status_code != 304: + if "content-length" not in header_set: + headers.append(("Content-Length", str(len(body)))) + if "content-type" not in header_set: + headers.append(("Content-Type", "text/html; charset=UTF-8")) + if "server" not in header_set: + headers.append(("Server", "TornadoServer/%s" % tornado.version)) + + start_line = httputil.ResponseStartLine("HTTP/1.1", status_code, reason) + header_obj = httputil.HTTPHeaders() + for key, value in headers: + header_obj.add(key, value) + assert request.connection is not None + request.connection.write_headers(start_line, header_obj, chunk=body) + request.connection.finish() + self._log(status_code, request) + + @staticmethod + def environ(request: httputil.HTTPServerRequest) -> Dict[Text, Any]: + """Converts a `tornado.httputil.HTTPServerRequest` to a WSGI environment. + """ + hostport = request.host.split(":") + if len(hostport) == 2: + host = hostport[0] + port = int(hostport[1]) + else: + host = request.host + port = 443 if request.protocol == "https" else 80 + environ = { + "REQUEST_METHOD": request.method, + "SCRIPT_NAME": "", + "PATH_INFO": to_wsgi_str( + escape.url_unescape(request.path, encoding=None, plus=False) + ), + "QUERY_STRING": request.query, + "REMOTE_ADDR": request.remote_ip, + "SERVER_NAME": host, + "SERVER_PORT": str(port), + "SERVER_PROTOCOL": request.version, + "wsgi.version": (1, 0), + "wsgi.url_scheme": request.protocol, + "wsgi.input": BytesIO(escape.utf8(request.body)), + "wsgi.errors": sys.stderr, + "wsgi.multithread": False, + "wsgi.multiprocess": True, + "wsgi.run_once": False, + } + if "Content-Type" in request.headers: + environ["CONTENT_TYPE"] = request.headers.pop("Content-Type") + if "Content-Length" in request.headers: + environ["CONTENT_LENGTH"] = request.headers.pop("Content-Length") + for key, value in request.headers.items(): + environ["HTTP_" + key.replace("-", "_").upper()] = value + return environ + + def _log(self, status_code: int, request: httputil.HTTPServerRequest) -> None: + if status_code < 400: + log_method = access_log.info + elif status_code < 500: + log_method = access_log.warning + else: + log_method = access_log.error + request_time = 1000.0 * request.request_time() + assert request.method is not None + assert request.uri is not None + summary = request.method + " " + request.uri + " (" + request.remote_ip + ")" + log_method("%d %s %.2fms", status_code, summary, request_time) + + +HTTPRequest = httputil.HTTPServerRequest diff --git a/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/INSTALLER b/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/LICENSE.txt b/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/LICENSE.txt new file mode 100644 index 0000000..9be1d2f --- /dev/null +++ b/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/LICENSE.txt @@ -0,0 +1,19 @@ +Copyright 2011-2017 Lennart Regebro + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/METADATA b/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/METADATA new file mode 100644 index 0000000..7bafd42 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/METADATA @@ -0,0 +1,326 @@ +Metadata-Version: 2.1 +Name: tzlocal +Version: 2.1 +Summary: tzinfo object for the local timezone +Home-page: https://github.com/regebro/tzlocal +Author: Lennart Regebro +Author-email: regebro@gmail.com +License: MIT +Keywords: timezone pytz +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: Microsoft :: Windows +Classifier: Operating System :: Unix +Classifier: Operating System :: MacOS :: MacOS X +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 +Requires-Dist: pytz + +tzlocal +======= + +This Python module returns a ``tzinfo`` object with the local timezone information under Unix and Win-32. +It requires ``pytz``, and returns ``pytz`` ``tzinfo`` objects. + +This module attempts to fix a glaring hole in ``pytz``, that there is no way to +get the local timezone information, unless you know the zoneinfo name, and +under several Linux distros that's hard or impossible to figure out. + +Also, with Windows different timezone system using pytz isn't of much use +unless you separately configure the zoneinfo timezone name. + +With ``tzlocal`` you only need to call ``get_localzone()`` and you will get a +``tzinfo`` object with the local time zone info. On some Unices you will still +not get to know what the timezone name is, but you don't need that when you +have the tzinfo file. However, if the timezone name is readily available it +will be used. + + +Supported systems +----------------- + +These are the systems that are in theory supported: + + * Windows 2000 and later + + * Any unix-like system with a ``/etc/localtime`` or ``/usr/local/etc/localtime`` + +If you have one of the above systems and it does not work, it's a bug. +Please report it. + +Please note that if you getting a time zone called ``local``, this is not a bug, it's +actually the main feature of ``tzlocal``, that even if your system does NOT have a configuration file +with the zoneinfo name of your time zone, it will still work. + +You can also use ``tzlocal`` to get the name of your local timezone, but only if your system is +configured to make that possible. ``tzlocal`` looks for the timezone name in ``/etc/timezone``, ``/var/db/zoneinfo``, +``/etc/sysconfig/clock`` and ``/etc/conf.d/clock``. If your ``/etc/localtime`` is a symlink it can also extract the +name from that symlink. + +If you need the name of your local time zone, then please make sure your system is properly configured to allow that. +If it isn't configured, tzlocal will default to UTC. + +Usage +----- + +Load the local timezone: + + >>> from tzlocal import get_localzone + >>> tz = get_localzone() + >>> tz + <DstTzInfo 'Europe/Warsaw' WMT+1:24:00 STD> + +Create a local datetime: + + >>> from datetime import datetime + >>> dt = tz.localize(datetime(2015, 4, 10, 7, 22)) + >>> dt + datetime.datetime(2015, 4, 10, 7, 22, tzinfo=<DstTzInfo 'Europe/Warsaw' CEST+2:00:00 DST>) + +Lookup another timezone with `pytz`: + + >>> import pytz + >>> eastern = pytz.timezone('US/Eastern') + +Convert the datetime: + + >>> dt.astimezone(eastern) + datetime.datetime(2015, 4, 10, 1, 22, tzinfo=<DstTzInfo 'US/Eastern' EDT-1 day, 20:00:00 DST>) + + +Maintainer +---------- + +* Lennart Regebro, regebro@gmail.com + +Contributors +------------ + +* Marc Van Olmen +* Benjamen Meyer +* Manuel Ebert +* Xiaokun Zhu +* Cameris +* Edward Betts +* McK KIM +* Cris Ewing +* Ayala Shachar +* Lev Maximov +* Jakub Wilk +* John Quarles +* Preston Landers +* Victor Torres +* Jean Jordaan +* Zackary Welch +* Mickaël Schoentgen +* Gabriel Corona + +(Sorry if I forgot someone) + +License +------- + +* MIT https://opensource.org/licenses/MIT + + +Changes +======= + +2.1 (2020-05-08) +---------------- + +- No changes. + + +2.1b1 (2020-02-08) +------------------ + +- The is_dst flag is wrong for Europe/Dublin on some Unix releases. + I changed to another way of determining if DST is in effect or not. + +- Added support for Python 3.7 and 3.8. Dropped 3.5 although it still works. + + +2.0.0 (2019-07-23) +------------------ + +- No differences since 2.0.0b3 + +Major differences since 1.5.1 +............................. + +- When no time zone configuration can be find, tzlocal now return UTC. + This is a major difference from 1.x, where an exception would be raised. + This change is because Docker images often have no configuration at all, + and the unix utilities will then default to UTC, so we follow that. + +- If tzlocal on Unix finds a timezone name in a /etc config file, then + tzlocal now verifies that the timezone it fouds has the same offset as + the local computer is configured with. If it doesn't, something is + configured incorrectly. (Victor Torres, regebro) + +- Get timezone via Termux `getprop` wrapper on Android. It's not officially + supported because we can't test it, but at least we make an effort. + (Jean Jordaan) + +Minor differences and bug fixes +............................... + +- Skip comment lines when parsing /etc/timezone. (Edward Betts) + +- Don't load timezone from current directory. (Gabriel Corona) + +- Now verifies that the config files actually contain something before + reading them. (Zackary Welch, regebro) + +- Got rid of a BytesWarning (Mickaël Schoentgen) + +- Now handles if config file paths exists, but are directories. + +- Moved tests out from distributions + +- Support wheels + + +1.5.1 (2017-12-01) +------------------ + +- 1.5 had a bug that slipped through testing, fixed that, + increased test coverage. + + +1.5 (2017-11-30) +---------------- + +- No longer treats macOS as special, but as a unix. + +- get_windows_info.py is renamed to update_windows_mappings.py + +- Windows mappings now also contain mappings from deprecated zoneinfo names. + (Preston-Landers, regebro) + + +1.4 (2017-04-18) +---------------- + +- I use MIT on my other projects, so relicensing. + + +1.4b1 (2017-04-14) +------------------ + +- Dropping support for Python versions nobody uses (2.5, 3.1, 3.2), adding 3.6 + Python 3.1 and 3.2 still works, 2.5 has been broken for some time. + +- Ayalash's OS X fix didn't work on Python 2.7, fixed that. + + +1.3.2 (2017-04-12) +------------------ + +- Ensure closing of subprocess on OS X (ayalash) + +- Removed unused imports (jwilk) + +- Closes stdout and stderr to get rid of ResourceWarnings (johnwquarles) + +- Updated Windows timezones (axil) + + +1.3 (2016-10-15) +---------------- + +- #34: Added support for /var/db/zoneinfo + + +1.2.2 (2016-03-02) +------------------ + +- #30: Fixed a bug on OS X. + + +1.2.1 (2016-02-28) +------------------ + +- Tests failed if TZ was set in the environment. (EdwardBetts) + +- Replaces os.popen() with subprocess.Popen() for OS X to + handle when systemsetup doesn't exist. (mckabi, cewing) + + +1.2 (2015-06-14) +---------------- + +- Systemd stores no time zone name, forcing us to look at the name of the file + that localtime symlinks to. (cameris) + + +1.1.2 (2014-10-18) +------------------ + +- Timezones that has 3 items did not work on Mac OS X. + (Marc Van Olmen) + +- Now doesn't fail if the TZ environment variable isn't an Olsen time zone. + +- Some timezones on Windows can apparently be empty (perhaps the are deleted). + Now these are ignored. + (Xiaokun Zhu) + + +1.1.1 (2014-01-29) +------------------ + +- I forgot to add Etc/UTC as an alias for Etc/GMT. + + +1.1 (2014-01-28) +---------------- + +- Adding better support for OS X. + +- Added support to map from tzdata/Olsen names to Windows names. + (Thanks to Benjamen Meyer). + + +1.0 (2013-05-29) +---------------- + +- Fixed some more cases where spaces needs replacing with underscores. + +- Better handling of misconfigured /etc/timezone. + +- Better error message on Windows if we can't find a timezone at all. + + +0.3 (2012-09-13) +---------------- + +- Windows 7 support. + +- Python 2.5 supported; because it only needed a __future__ import. + +- Python 3.3 tested, it worked. + +- Got rid of relative imports, because I don't actually like them, + so I don't know why I used them in the first place. + +- For each Windows zone, use the default zoneinfo zone, not the last one. + + +0.2 (2012-09-12) +---------------- + +- Python 3 support. + + +0.1 (2012-09-11) +---------------- + +- Initial release. + + diff --git a/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/RECORD b/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/RECORD new file mode 100644 index 0000000..5d4aa54 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/RECORD @@ -0,0 +1,17 @@ +tzlocal-2.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +tzlocal-2.1.dist-info/LICENSE.txt,sha256=2ZqyCa6xaq0sJckP_YPBqYHikP__dqQgoqsD4D8EG4w,1060 +tzlocal-2.1.dist-info/METADATA,sha256=CFvLexLJNXCk-hBmflVJxv7P2Izms0iDeVubwshTF1g,8227 +tzlocal-2.1.dist-info/RECORD,, +tzlocal-2.1.dist-info/WHEEL,sha256=aSdOKpzTGLLkKenfdFGiq92od_Dmr98YfEe8iw7iZoo,110 +tzlocal-2.1.dist-info/top_level.txt,sha256=QR6vZWP520waETnkotApPQPyVh9VnjoYPoAVHLK1DrE,8 +tzlocal-2.1.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1 +tzlocal/__init__.py,sha256=zOXBN5IP3Nc1gNiL8aVwHAhXAYTFfkTSDJ6VdjmifCQ,168 +tzlocal/__pycache__/__init__.cpython-38.pyc,, +tzlocal/__pycache__/unix.cpython-38.pyc,, +tzlocal/__pycache__/utils.cpython-38.pyc,, +tzlocal/__pycache__/win32.cpython-38.pyc,, +tzlocal/__pycache__/windows_tz.cpython-38.pyc,, +tzlocal/unix.py,sha256=7dFkjHfqNz4k9F_-PseJaKHCy8uHLKYckbIydpMGXo0,6062 +tzlocal/utils.py,sha256=FYqtaomESB2nQWR8cJalSLoQ9uq7QE0Sx0Hhud1kpTM,1692 +tzlocal/win32.py,sha256=GlvUX_yS1OGEkGmHvW_A3GR5Arxr6lrn0DetVcRanKg,3265 +tzlocal/windows_tz.py,sha256=J-5L3_TUGPiyg69GhqxFnAHhiHsjrZKfkgR1WbofaLk,31441 diff --git a/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/WHEEL b/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/WHEEL new file mode 100644 index 0000000..131c7a8 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.33.0) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/top_level.txt b/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/top_level.txt new file mode 100644 index 0000000..cd5e9b1 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/top_level.txt @@ -0,0 +1 @@ +tzlocal diff --git a/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/zip-safe b/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/zip-safe new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/zip-safe @@ -0,0 +1 @@ + diff --git a/venv/lib/python3.8/site-packages/tzlocal/__init__.py b/venv/lib/python3.8/site-packages/tzlocal/__init__.py new file mode 100644 index 0000000..c8196d6 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tzlocal/__init__.py @@ -0,0 +1,5 @@ +import sys +if sys.platform == 'win32': + from tzlocal.win32 import get_localzone, reload_localzone +else: + from tzlocal.unix import get_localzone, reload_localzone diff --git a/venv/lib/python3.8/site-packages/tzlocal/unix.py b/venv/lib/python3.8/site-packages/tzlocal/unix.py new file mode 100644 index 0000000..8574965 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tzlocal/unix.py @@ -0,0 +1,174 @@ +import os +import pytz +import re +import warnings + +from tzlocal import utils + +_cache_tz = None + + +def _tz_from_env(tzenv): + if tzenv[0] == ':': + tzenv = tzenv[1:] + + # TZ specifies a file + if os.path.isabs(tzenv) and os.path.exists(tzenv): + with open(tzenv, 'rb') as tzfile: + return pytz.tzfile.build_tzinfo('local', tzfile) + + # TZ specifies a zoneinfo zone. + try: + tz = pytz.timezone(tzenv) + # That worked, so we return this: + return tz + except pytz.UnknownTimeZoneError: + raise pytz.UnknownTimeZoneError( + "tzlocal() does not support non-zoneinfo timezones like %s. \n" + "Please use a timezone in the form of Continent/City") + + +def _try_tz_from_env(): + tzenv = os.environ.get('TZ') + if tzenv: + try: + return _tz_from_env(tzenv) + except pytz.UnknownTimeZoneError: + pass + + +def _get_localzone(_root='/'): + """Tries to find the local timezone configuration. + + This method prefers finding the timezone name and passing that to pytz, + over passing in the localtime file, as in the later case the zoneinfo + name is unknown. + + The parameter _root makes the function look for files like /etc/localtime + beneath the _root directory. This is primarily used by the tests. + In normal usage you call the function without parameters.""" + + tzenv = _try_tz_from_env() + if tzenv: + return tzenv + + # Are we under Termux on Android? + if os.path.exists('/system/bin/getprop'): + import subprocess + androidtz = subprocess.check_output(['getprop', 'persist.sys.timezone']).strip().decode() + return pytz.timezone(androidtz) + + # Now look for distribution specific configuration files + # that contain the timezone name. + for configfile in ('etc/timezone', 'var/db/zoneinfo'): + tzpath = os.path.join(_root, configfile) + try: + with open(tzpath, 'rb') as tzfile: + data = tzfile.read() + + # Issue #3 was that /etc/timezone was a zoneinfo file. + # That's a misconfiguration, but we need to handle it gracefully: + if data[:5] == b'TZif2': + continue + + etctz = data.strip().decode() + if not etctz: + # Empty file, skip + continue + for etctz in data.decode().splitlines(): + # Get rid of host definitions and comments: + if ' ' in etctz: + etctz, dummy = etctz.split(' ', 1) + if '#' in etctz: + etctz, dummy = etctz.split('#', 1) + if not etctz: + continue + tz = pytz.timezone(etctz.replace(' ', '_')) + if _root == '/': + # We are using a file in etc to name the timezone. + # Verify that the timezone specified there is actually used: + utils.assert_tz_offset(tz) + return tz + + except IOError: + # File doesn't exist or is a directory + continue + + # CentOS has a ZONE setting in /etc/sysconfig/clock, + # OpenSUSE has a TIMEZONE setting in /etc/sysconfig/clock and + # Gentoo has a TIMEZONE setting in /etc/conf.d/clock + # We look through these files for a timezone: + + zone_re = re.compile(r'\s*ZONE\s*=\s*\"') + timezone_re = re.compile(r'\s*TIMEZONE\s*=\s*\"') + end_re = re.compile('\"') + + for filename in ('etc/sysconfig/clock', 'etc/conf.d/clock'): + tzpath = os.path.join(_root, filename) + try: + with open(tzpath, 'rt') as tzfile: + data = tzfile.readlines() + + for line in data: + # Look for the ZONE= setting. + match = zone_re.match(line) + if match is None: + # No ZONE= setting. Look for the TIMEZONE= setting. + match = timezone_re.match(line) + if match is not None: + # Some setting existed + line = line[match.end():] + etctz = line[:end_re.search(line).start()] + + # We found a timezone + tz = pytz.timezone(etctz.replace(' ', '_')) + if _root == '/': + # We are using a file in etc to name the timezone. + # Verify that the timezone specified there is actually used: + utils.assert_tz_offset(tz) + return tz + + except IOError: + # File doesn't exist or is a directory + continue + + # systemd distributions use symlinks that include the zone name, + # see manpage of localtime(5) and timedatectl(1) + tzpath = os.path.join(_root, 'etc/localtime') + if os.path.exists(tzpath) and os.path.islink(tzpath): + tzpath = os.path.realpath(tzpath) + start = tzpath.find("/")+1 + while start != 0: + tzpath = tzpath[start:] + try: + return pytz.timezone(tzpath) + except pytz.UnknownTimeZoneError: + pass + start = tzpath.find("/")+1 + + # No explicit setting existed. Use localtime + for filename in ('etc/localtime', 'usr/local/etc/localtime'): + tzpath = os.path.join(_root, filename) + + if not os.path.exists(tzpath): + continue + with open(tzpath, 'rb') as tzfile: + return pytz.tzfile.build_tzinfo('local', tzfile) + + warnings.warn('Can not find any timezone configuration, defaulting to UTC.') + return pytz.utc + +def get_localzone(): + """Get the computers configured local timezone, if any.""" + global _cache_tz + if _cache_tz is None: + _cache_tz = _get_localzone() + + return _cache_tz + + +def reload_localzone(): + """Reload the cached localzone. You need to call this if the timezone has changed.""" + global _cache_tz + _cache_tz = _get_localzone() + return _cache_tz diff --git a/venv/lib/python3.8/site-packages/tzlocal/utils.py b/venv/lib/python3.8/site-packages/tzlocal/utils.py new file mode 100644 index 0000000..5a67799 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tzlocal/utils.py @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- +import time +import datetime +import calendar + + +def get_system_offset(): + """Get system's timezone offset using built-in library time. + + For the Timezone constants (altzone, daylight, timezone, and tzname), the + value is determined by the timezone rules in effect at module load time or + the last time tzset() is called and may be incorrect for times in the past. + + To keep compatibility with Windows, we're always importing time module here. + """ + + localtime = calendar.timegm(time.localtime()) + gmtime = calendar.timegm(time.gmtime()) + offset = gmtime - localtime + # We could get the localtime and gmtime on either side of a second switch + # so we check that the difference is less than one minute, because nobody + # has that small DST differences. + if abs(offset - time.altzone) < 60: + return -time.altzone + else: + return -time.timezone + + +def get_tz_offset(tz): + """Get timezone's offset using built-in function datetime.utcoffset().""" + return int(datetime.datetime.now(tz).utcoffset().total_seconds()) + + +def assert_tz_offset(tz): + """Assert that system's timezone offset equals to the timezone offset found. + + If they don't match, we probably have a misconfiguration, for example, an + incorrect timezone set in /etc/timezone file in systemd distributions.""" + tz_offset = get_tz_offset(tz) + system_offset = get_system_offset() + if tz_offset != system_offset: + msg = ('Timezone offset does not match system offset: {0} != {1}. ' + 'Please, check your config files.').format( + tz_offset, system_offset + ) + raise ValueError(msg) diff --git a/venv/lib/python3.8/site-packages/tzlocal/win32.py b/venv/lib/python3.8/site-packages/tzlocal/win32.py new file mode 100644 index 0000000..fcc42a2 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tzlocal/win32.py @@ -0,0 +1,104 @@ +try: + import _winreg as winreg +except ImportError: + import winreg + +import pytz + +from tzlocal.windows_tz import win_tz +from tzlocal import utils + +_cache_tz = None + + +def valuestodict(key): + """Convert a registry key's values to a dictionary.""" + dict = {} + size = winreg.QueryInfoKey(key)[1] + for i in range(size): + data = winreg.EnumValue(key, i) + dict[data[0]] = data[1] + return dict + + +def get_localzone_name(): + # Windows is special. It has unique time zone names (in several + # meanings of the word) available, but unfortunately, they can be + # translated to the language of the operating system, so we need to + # do a backwards lookup, by going through all time zones and see which + # one matches. + handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) + + TZLOCALKEYNAME = r"SYSTEM\CurrentControlSet\Control\TimeZoneInformation" + localtz = winreg.OpenKey(handle, TZLOCALKEYNAME) + keyvalues = valuestodict(localtz) + localtz.Close() + + if 'TimeZoneKeyName' in keyvalues: + # Windows 7 (and Vista?) + + # For some reason this returns a string with loads of NUL bytes at + # least on some systems. I don't know if this is a bug somewhere, I + # just work around it. + tzkeyname = keyvalues['TimeZoneKeyName'].split('\x00', 1)[0] + else: + # Windows 2000 or XP + + # This is the localized name: + tzwin = keyvalues['StandardName'] + + # Open the list of timezones to look up the real name: + TZKEYNAME = r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones" + tzkey = winreg.OpenKey(handle, TZKEYNAME) + + # Now, match this value to Time Zone information + tzkeyname = None + for i in range(winreg.QueryInfoKey(tzkey)[0]): + subkey = winreg.EnumKey(tzkey, i) + sub = winreg.OpenKey(tzkey, subkey) + data = valuestodict(sub) + sub.Close() + try: + if data['Std'] == tzwin: + tzkeyname = subkey + break + except KeyError: + # This timezone didn't have proper configuration. + # Ignore it. + pass + + tzkey.Close() + handle.Close() + + if tzkeyname is None: + raise LookupError('Can not find Windows timezone configuration') + + timezone = win_tz.get(tzkeyname) + if timezone is None: + # Nope, that didn't work. Try adding "Standard Time", + # it seems to work a lot of times: + timezone = win_tz.get(tzkeyname + " Standard Time") + + # Return what we have. + if timezone is None: + raise pytz.UnknownTimeZoneError('Can not find timezone ' + tzkeyname) + + return timezone + + +def get_localzone(): + """Returns the zoneinfo-based tzinfo object that matches the Windows-configured timezone.""" + global _cache_tz + if _cache_tz is None: + _cache_tz = pytz.timezone(get_localzone_name()) + + utils.assert_tz_offset(_cache_tz) + return _cache_tz + + +def reload_localzone(): + """Reload the cached localzone. You need to call this if the timezone has changed.""" + global _cache_tz + _cache_tz = pytz.timezone(get_localzone_name()) + utils.assert_tz_offset(_cache_tz) + return _cache_tz diff --git a/venv/lib/python3.8/site-packages/tzlocal/windows_tz.py b/venv/lib/python3.8/site-packages/tzlocal/windows_tz.py new file mode 100644 index 0000000..86ba807 --- /dev/null +++ b/venv/lib/python3.8/site-packages/tzlocal/windows_tz.py @@ -0,0 +1,697 @@ +# This file is autogenerated by the update_windows_mapping.py script +# Do not edit. +win_tz = {'AUS Central Standard Time': 'Australia/Darwin', + 'AUS Eastern Standard Time': 'Australia/Sydney', + 'Afghanistan Standard Time': 'Asia/Kabul', + 'Alaskan Standard Time': 'America/Anchorage', + 'Aleutian Standard Time': 'America/Adak', + 'Altai Standard Time': 'Asia/Barnaul', + 'Arab Standard Time': 'Asia/Riyadh', + 'Arabian Standard Time': 'Asia/Dubai', + 'Arabic Standard Time': 'Asia/Baghdad', + 'Argentina Standard Time': 'America/Buenos_Aires', + 'Astrakhan Standard Time': 'Europe/Astrakhan', + 'Atlantic Standard Time': 'America/Halifax', + 'Aus Central W. Standard Time': 'Australia/Eucla', + 'Azerbaijan Standard Time': 'Asia/Baku', + 'Azores Standard Time': 'Atlantic/Azores', + 'Bahia Standard Time': 'America/Bahia', + 'Bangladesh Standard Time': 'Asia/Dhaka', + 'Belarus Standard Time': 'Europe/Minsk', + 'Bougainville Standard Time': 'Pacific/Bougainville', + 'Canada Central Standard Time': 'America/Regina', + 'Cape Verde Standard Time': 'Atlantic/Cape_Verde', + 'Caucasus Standard Time': 'Asia/Yerevan', + 'Cen. Australia Standard Time': 'Australia/Adelaide', + 'Central America Standard Time': 'America/Guatemala', + 'Central Asia Standard Time': 'Asia/Almaty', + 'Central Brazilian Standard Time': 'America/Cuiaba', + 'Central Europe Standard Time': 'Europe/Budapest', + 'Central European Standard Time': 'Europe/Warsaw', + 'Central Pacific Standard Time': 'Pacific/Guadalcanal', + 'Central Standard Time': 'America/Chicago', + 'Central Standard Time (Mexico)': 'America/Mexico_City', + 'Chatham Islands Standard Time': 'Pacific/Chatham', + 'China Standard Time': 'Asia/Shanghai', + 'Cuba Standard Time': 'America/Havana', + 'Dateline Standard Time': 'Etc/GMT+12', + 'E. Africa Standard Time': 'Africa/Nairobi', + 'E. Australia Standard Time': 'Australia/Brisbane', + 'E. Europe Standard Time': 'Europe/Chisinau', + 'E. South America Standard Time': 'America/Sao_Paulo', + 'Easter Island Standard Time': 'Pacific/Easter', + 'Eastern Standard Time': 'America/New_York', + 'Eastern Standard Time (Mexico)': 'America/Cancun', + 'Egypt Standard Time': 'Africa/Cairo', + 'Ekaterinburg Standard Time': 'Asia/Yekaterinburg', + 'FLE Standard Time': 'Europe/Kiev', + 'Fiji Standard Time': 'Pacific/Fiji', + 'GMT Standard Time': 'Europe/London', + 'GTB Standard Time': 'Europe/Bucharest', + 'Georgian Standard Time': 'Asia/Tbilisi', + 'Greenland Standard Time': 'America/Godthab', + 'Greenwich Standard Time': 'Atlantic/Reykjavik', + 'Haiti Standard Time': 'America/Port-au-Prince', + 'Hawaiian Standard Time': 'Pacific/Honolulu', + 'India Standard Time': 'Asia/Calcutta', + 'Iran Standard Time': 'Asia/Tehran', + 'Israel Standard Time': 'Asia/Jerusalem', + 'Jordan Standard Time': 'Asia/Amman', + 'Kaliningrad Standard Time': 'Europe/Kaliningrad', + 'Korea Standard Time': 'Asia/Seoul', + 'Libya Standard Time': 'Africa/Tripoli', + 'Line Islands Standard Time': 'Pacific/Kiritimati', + 'Lord Howe Standard Time': 'Australia/Lord_Howe', + 'Magadan Standard Time': 'Asia/Magadan', + 'Magallanes Standard Time': 'America/Punta_Arenas', + 'Marquesas Standard Time': 'Pacific/Marquesas', + 'Mauritius Standard Time': 'Indian/Mauritius', + 'Middle East Standard Time': 'Asia/Beirut', + 'Montevideo Standard Time': 'America/Montevideo', + 'Morocco Standard Time': 'Africa/Casablanca', + 'Mountain Standard Time': 'America/Denver', + 'Mountain Standard Time (Mexico)': 'America/Chihuahua', + 'Myanmar Standard Time': 'Asia/Rangoon', + 'N. Central Asia Standard Time': 'Asia/Novosibirsk', + 'Namibia Standard Time': 'Africa/Windhoek', + 'Nepal Standard Time': 'Asia/Katmandu', + 'New Zealand Standard Time': 'Pacific/Auckland', + 'Newfoundland Standard Time': 'America/St_Johns', + 'Norfolk Standard Time': 'Pacific/Norfolk', + 'North Asia East Standard Time': 'Asia/Irkutsk', + 'North Asia Standard Time': 'Asia/Krasnoyarsk', + 'North Korea Standard Time': 'Asia/Pyongyang', + 'Omsk Standard Time': 'Asia/Omsk', + 'Pacific SA Standard Time': 'America/Santiago', + 'Pacific Standard Time': 'America/Los_Angeles', + 'Pacific Standard Time (Mexico)': 'America/Tijuana', + 'Pakistan Standard Time': 'Asia/Karachi', + 'Paraguay Standard Time': 'America/Asuncion', + 'Qyzylorda Standard Time': 'Asia/Qyzylorda', + 'Romance Standard Time': 'Europe/Paris', + 'Russia Time Zone 10': 'Asia/Srednekolymsk', + 'Russia Time Zone 11': 'Asia/Kamchatka', + 'Russia Time Zone 3': 'Europe/Samara', + 'Russian Standard Time': 'Europe/Moscow', + 'SA Eastern Standard Time': 'America/Cayenne', + 'SA Pacific Standard Time': 'America/Bogota', + 'SA Western Standard Time': 'America/La_Paz', + 'SE Asia Standard Time': 'Asia/Bangkok', + 'Saint Pierre Standard Time': 'America/Miquelon', + 'Sakhalin Standard Time': 'Asia/Sakhalin', + 'Samoa Standard Time': 'Pacific/Apia', + 'Sao Tome Standard Time': 'Africa/Sao_Tome', + 'Saratov Standard Time': 'Europe/Saratov', + 'Singapore Standard Time': 'Asia/Singapore', + 'South Africa Standard Time': 'Africa/Johannesburg', + 'Sri Lanka Standard Time': 'Asia/Colombo', + 'Sudan Standard Time': 'Africa/Khartoum', + 'Syria Standard Time': 'Asia/Damascus', + 'Taipei Standard Time': 'Asia/Taipei', + 'Tasmania Standard Time': 'Australia/Hobart', + 'Tocantins Standard Time': 'America/Araguaina', + 'Tokyo Standard Time': 'Asia/Tokyo', + 'Tomsk Standard Time': 'Asia/Tomsk', + 'Tonga Standard Time': 'Pacific/Tongatapu', + 'Transbaikal Standard Time': 'Asia/Chita', + 'Turkey Standard Time': 'Europe/Istanbul', + 'Turks And Caicos Standard Time': 'America/Grand_Turk', + 'US Eastern Standard Time': 'America/Indianapolis', + 'US Mountain Standard Time': 'America/Phoenix', + 'UTC': 'Etc/GMT', + 'UTC+12': 'Etc/GMT-12', + 'UTC+13': 'Etc/GMT-13', + 'UTC-02': 'Etc/GMT+2', + 'UTC-08': 'Etc/GMT+8', + 'UTC-09': 'Etc/GMT+9', + 'UTC-11': 'Etc/GMT+11', + 'Ulaanbaatar Standard Time': 'Asia/Ulaanbaatar', + 'Venezuela Standard Time': 'America/Caracas', + 'Vladivostok Standard Time': 'Asia/Vladivostok', + 'Volgograd Standard Time': 'Europe/Volgograd', + 'W. Australia Standard Time': 'Australia/Perth', + 'W. Central Africa Standard Time': 'Africa/Lagos', + 'W. Europe Standard Time': 'Europe/Berlin', + 'W. Mongolia Standard Time': 'Asia/Hovd', + 'West Asia Standard Time': 'Asia/Tashkent', + 'West Bank Standard Time': 'Asia/Hebron', + 'West Pacific Standard Time': 'Pacific/Port_Moresby', + 'Yakutsk Standard Time': 'Asia/Yakutsk'} + +# Old name for the win_tz variable: +tz_names = win_tz + +tz_win = {'Africa/Abidjan': 'Greenwich Standard Time', + 'Africa/Accra': 'Greenwich Standard Time', + 'Africa/Addis_Ababa': 'E. Africa Standard Time', + 'Africa/Algiers': 'W. Central Africa Standard Time', + 'Africa/Asmera': 'E. Africa Standard Time', + 'Africa/Bamako': 'Greenwich Standard Time', + 'Africa/Bangui': 'W. Central Africa Standard Time', + 'Africa/Banjul': 'Greenwich Standard Time', + 'Africa/Bissau': 'Greenwich Standard Time', + 'Africa/Blantyre': 'South Africa Standard Time', + 'Africa/Brazzaville': 'W. Central Africa Standard Time', + 'Africa/Bujumbura': 'South Africa Standard Time', + 'Africa/Cairo': 'Egypt Standard Time', + 'Africa/Casablanca': 'Morocco Standard Time', + 'Africa/Ceuta': 'Romance Standard Time', + 'Africa/Conakry': 'Greenwich Standard Time', + 'Africa/Dakar': 'Greenwich Standard Time', + 'Africa/Dar_es_Salaam': 'E. Africa Standard Time', + 'Africa/Djibouti': 'E. Africa Standard Time', + 'Africa/Douala': 'W. Central Africa Standard Time', + 'Africa/El_Aaiun': 'Morocco Standard Time', + 'Africa/Freetown': 'Greenwich Standard Time', + 'Africa/Gaborone': 'South Africa Standard Time', + 'Africa/Harare': 'South Africa Standard Time', + 'Africa/Johannesburg': 'South Africa Standard Time', + 'Africa/Juba': 'E. Africa Standard Time', + 'Africa/Kampala': 'E. Africa Standard Time', + 'Africa/Khartoum': 'Sudan Standard Time', + 'Africa/Kigali': 'South Africa Standard Time', + 'Africa/Kinshasa': 'W. Central Africa Standard Time', + 'Africa/Lagos': 'W. Central Africa Standard Time', + 'Africa/Libreville': 'W. Central Africa Standard Time', + 'Africa/Lome': 'Greenwich Standard Time', + 'Africa/Luanda': 'W. Central Africa Standard Time', + 'Africa/Lubumbashi': 'South Africa Standard Time', + 'Africa/Lusaka': 'South Africa Standard Time', + 'Africa/Malabo': 'W. Central Africa Standard Time', + 'Africa/Maputo': 'South Africa Standard Time', + 'Africa/Maseru': 'South Africa Standard Time', + 'Africa/Mbabane': 'South Africa Standard Time', + 'Africa/Mogadishu': 'E. Africa Standard Time', + 'Africa/Monrovia': 'Greenwich Standard Time', + 'Africa/Nairobi': 'E. Africa Standard Time', + 'Africa/Ndjamena': 'W. Central Africa Standard Time', + 'Africa/Niamey': 'W. Central Africa Standard Time', + 'Africa/Nouakchott': 'Greenwich Standard Time', + 'Africa/Ouagadougou': 'Greenwich Standard Time', + 'Africa/Porto-Novo': 'W. Central Africa Standard Time', + 'Africa/Sao_Tome': 'Sao Tome Standard Time', + 'Africa/Timbuktu': 'Greenwich Standard Time', + 'Africa/Tripoli': 'Libya Standard Time', + 'Africa/Tunis': 'W. Central Africa Standard Time', + 'Africa/Windhoek': 'Namibia Standard Time', + 'America/Adak': 'Aleutian Standard Time', + 'America/Anchorage': 'Alaskan Standard Time', + 'America/Anguilla': 'SA Western Standard Time', + 'America/Antigua': 'SA Western Standard Time', + 'America/Araguaina': 'Tocantins Standard Time', + 'America/Argentina/La_Rioja': 'Argentina Standard Time', + 'America/Argentina/Rio_Gallegos': 'Argentina Standard Time', + 'America/Argentina/Salta': 'Argentina Standard Time', + 'America/Argentina/San_Juan': 'Argentina Standard Time', + 'America/Argentina/San_Luis': 'Argentina Standard Time', + 'America/Argentina/Tucuman': 'Argentina Standard Time', + 'America/Argentina/Ushuaia': 'Argentina Standard Time', + 'America/Aruba': 'SA Western Standard Time', + 'America/Asuncion': 'Paraguay Standard Time', + 'America/Atka': 'Aleutian Standard Time', + 'America/Bahia': 'Bahia Standard Time', + 'America/Bahia_Banderas': 'Central Standard Time (Mexico)', + 'America/Barbados': 'SA Western Standard Time', + 'America/Belem': 'SA Eastern Standard Time', + 'America/Belize': 'Central America Standard Time', + 'America/Blanc-Sablon': 'SA Western Standard Time', + 'America/Boa_Vista': 'SA Western Standard Time', + 'America/Bogota': 'SA Pacific Standard Time', + 'America/Boise': 'Mountain Standard Time', + 'America/Buenos_Aires': 'Argentina Standard Time', + 'America/Cambridge_Bay': 'Mountain Standard Time', + 'America/Campo_Grande': 'Central Brazilian Standard Time', + 'America/Cancun': 'Eastern Standard Time (Mexico)', + 'America/Caracas': 'Venezuela Standard Time', + 'America/Catamarca': 'Argentina Standard Time', + 'America/Cayenne': 'SA Eastern Standard Time', + 'America/Cayman': 'SA Pacific Standard Time', + 'America/Chicago': 'Central Standard Time', + 'America/Chihuahua': 'Mountain Standard Time (Mexico)', + 'America/Coral_Harbour': 'SA Pacific Standard Time', + 'America/Cordoba': 'Argentina Standard Time', + 'America/Costa_Rica': 'Central America Standard Time', + 'America/Creston': 'US Mountain Standard Time', + 'America/Cuiaba': 'Central Brazilian Standard Time', + 'America/Curacao': 'SA Western Standard Time', + 'America/Danmarkshavn': 'UTC', + 'America/Dawson': 'Pacific Standard Time', + 'America/Dawson_Creek': 'US Mountain Standard Time', + 'America/Denver': 'Mountain Standard Time', + 'America/Detroit': 'Eastern Standard Time', + 'America/Dominica': 'SA Western Standard Time', + 'America/Edmonton': 'Mountain Standard Time', + 'America/Eirunepe': 'SA Pacific Standard Time', + 'America/El_Salvador': 'Central America Standard Time', + 'America/Ensenada': 'Pacific Standard Time (Mexico)', + 'America/Fort_Nelson': 'US Mountain Standard Time', + 'America/Fortaleza': 'SA Eastern Standard Time', + 'America/Glace_Bay': 'Atlantic Standard Time', + 'America/Godthab': 'Greenland Standard Time', + 'America/Goose_Bay': 'Atlantic Standard Time', + 'America/Grand_Turk': 'Turks And Caicos Standard Time', + 'America/Grenada': 'SA Western Standard Time', + 'America/Guadeloupe': 'SA Western Standard Time', + 'America/Guatemala': 'Central America Standard Time', + 'America/Guayaquil': 'SA Pacific Standard Time', + 'America/Guyana': 'SA Western Standard Time', + 'America/Halifax': 'Atlantic Standard Time', + 'America/Havana': 'Cuba Standard Time', + 'America/Hermosillo': 'US Mountain Standard Time', + 'America/Indiana/Knox': 'Central Standard Time', + 'America/Indiana/Marengo': 'US Eastern Standard Time', + 'America/Indiana/Petersburg': 'Eastern Standard Time', + 'America/Indiana/Tell_City': 'Central Standard Time', + 'America/Indiana/Vevay': 'US Eastern Standard Time', + 'America/Indiana/Vincennes': 'Eastern Standard Time', + 'America/Indiana/Winamac': 'Eastern Standard Time', + 'America/Indianapolis': 'US Eastern Standard Time', + 'America/Inuvik': 'Mountain Standard Time', + 'America/Iqaluit': 'Eastern Standard Time', + 'America/Jamaica': 'SA Pacific Standard Time', + 'America/Jujuy': 'Argentina Standard Time', + 'America/Juneau': 'Alaskan Standard Time', + 'America/Kentucky/Monticello': 'Eastern Standard Time', + 'America/Knox_IN': 'Central Standard Time', + 'America/Kralendijk': 'SA Western Standard Time', + 'America/La_Paz': 'SA Western Standard Time', + 'America/Lima': 'SA Pacific Standard Time', + 'America/Los_Angeles': 'Pacific Standard Time', + 'America/Louisville': 'Eastern Standard Time', + 'America/Lower_Princes': 'SA Western Standard Time', + 'America/Maceio': 'SA Eastern Standard Time', + 'America/Managua': 'Central America Standard Time', + 'America/Manaus': 'SA Western Standard Time', + 'America/Marigot': 'SA Western Standard Time', + 'America/Martinique': 'SA Western Standard Time', + 'America/Matamoros': 'Central Standard Time', + 'America/Mazatlan': 'Mountain Standard Time (Mexico)', + 'America/Mendoza': 'Argentina Standard Time', + 'America/Menominee': 'Central Standard Time', + 'America/Merida': 'Central Standard Time (Mexico)', + 'America/Metlakatla': 'Alaskan Standard Time', + 'America/Mexico_City': 'Central Standard Time (Mexico)', + 'America/Miquelon': 'Saint Pierre Standard Time', + 'America/Moncton': 'Atlantic Standard Time', + 'America/Monterrey': 'Central Standard Time (Mexico)', + 'America/Montevideo': 'Montevideo Standard Time', + 'America/Montreal': 'Eastern Standard Time', + 'America/Montserrat': 'SA Western Standard Time', + 'America/Nassau': 'Eastern Standard Time', + 'America/New_York': 'Eastern Standard Time', + 'America/Nipigon': 'Eastern Standard Time', + 'America/Nome': 'Alaskan Standard Time', + 'America/Noronha': 'UTC-02', + 'America/North_Dakota/Beulah': 'Central Standard Time', + 'America/North_Dakota/Center': 'Central Standard Time', + 'America/North_Dakota/New_Salem': 'Central Standard Time', + 'America/Ojinaga': 'Mountain Standard Time', + 'America/Panama': 'SA Pacific Standard Time', + 'America/Pangnirtung': 'Eastern Standard Time', + 'America/Paramaribo': 'SA Eastern Standard Time', + 'America/Phoenix': 'US Mountain Standard Time', + 'America/Port-au-Prince': 'Haiti Standard Time', + 'America/Port_of_Spain': 'SA Western Standard Time', + 'America/Porto_Acre': 'SA Pacific Standard Time', + 'America/Porto_Velho': 'SA Western Standard Time', + 'America/Puerto_Rico': 'SA Western Standard Time', + 'America/Punta_Arenas': 'Magallanes Standard Time', + 'America/Rainy_River': 'Central Standard Time', + 'America/Rankin_Inlet': 'Central Standard Time', + 'America/Recife': 'SA Eastern Standard Time', + 'America/Regina': 'Canada Central Standard Time', + 'America/Resolute': 'Central Standard Time', + 'America/Rio_Branco': 'SA Pacific Standard Time', + 'America/Santa_Isabel': 'Pacific Standard Time (Mexico)', + 'America/Santarem': 'SA Eastern Standard Time', + 'America/Santiago': 'Pacific SA Standard Time', + 'America/Santo_Domingo': 'SA Western Standard Time', + 'America/Sao_Paulo': 'E. South America Standard Time', + 'America/Scoresbysund': 'Azores Standard Time', + 'America/Shiprock': 'Mountain Standard Time', + 'America/Sitka': 'Alaskan Standard Time', + 'America/St_Barthelemy': 'SA Western Standard Time', + 'America/St_Johns': 'Newfoundland Standard Time', + 'America/St_Kitts': 'SA Western Standard Time', + 'America/St_Lucia': 'SA Western Standard Time', + 'America/St_Thomas': 'SA Western Standard Time', + 'America/St_Vincent': 'SA Western Standard Time', + 'America/Swift_Current': 'Canada Central Standard Time', + 'America/Tegucigalpa': 'Central America Standard Time', + 'America/Thule': 'Atlantic Standard Time', + 'America/Thunder_Bay': 'Eastern Standard Time', + 'America/Tijuana': 'Pacific Standard Time (Mexico)', + 'America/Toronto': 'Eastern Standard Time', + 'America/Tortola': 'SA Western Standard Time', + 'America/Vancouver': 'Pacific Standard Time', + 'America/Virgin': 'SA Western Standard Time', + 'America/Whitehorse': 'Pacific Standard Time', + 'America/Winnipeg': 'Central Standard Time', + 'America/Yakutat': 'Alaskan Standard Time', + 'America/Yellowknife': 'Mountain Standard Time', + 'Antarctica/Casey': 'Singapore Standard Time', + 'Antarctica/Davis': 'SE Asia Standard Time', + 'Antarctica/DumontDUrville': 'West Pacific Standard Time', + 'Antarctica/Macquarie': 'Central Pacific Standard Time', + 'Antarctica/Mawson': 'West Asia Standard Time', + 'Antarctica/McMurdo': 'New Zealand Standard Time', + 'Antarctica/Palmer': 'SA Eastern Standard Time', + 'Antarctica/Rothera': 'SA Eastern Standard Time', + 'Antarctica/South_Pole': 'New Zealand Standard Time', + 'Antarctica/Syowa': 'E. Africa Standard Time', + 'Antarctica/Vostok': 'Central Asia Standard Time', + 'Arctic/Longyearbyen': 'W. Europe Standard Time', + 'Asia/Aden': 'Arab Standard Time', + 'Asia/Almaty': 'Central Asia Standard Time', + 'Asia/Amman': 'Jordan Standard Time', + 'Asia/Anadyr': 'Russia Time Zone 11', + 'Asia/Aqtau': 'West Asia Standard Time', + 'Asia/Aqtobe': 'West Asia Standard Time', + 'Asia/Ashgabat': 'West Asia Standard Time', + 'Asia/Ashkhabad': 'West Asia Standard Time', + 'Asia/Atyrau': 'West Asia Standard Time', + 'Asia/Baghdad': 'Arabic Standard Time', + 'Asia/Bahrain': 'Arab Standard Time', + 'Asia/Baku': 'Azerbaijan Standard Time', + 'Asia/Bangkok': 'SE Asia Standard Time', + 'Asia/Barnaul': 'Altai Standard Time', + 'Asia/Beirut': 'Middle East Standard Time', + 'Asia/Bishkek': 'Central Asia Standard Time', + 'Asia/Brunei': 'Singapore Standard Time', + 'Asia/Calcutta': 'India Standard Time', + 'Asia/Chita': 'Transbaikal Standard Time', + 'Asia/Choibalsan': 'Ulaanbaatar Standard Time', + 'Asia/Chongqing': 'China Standard Time', + 'Asia/Chungking': 'China Standard Time', + 'Asia/Colombo': 'Sri Lanka Standard Time', + 'Asia/Dacca': 'Bangladesh Standard Time', + 'Asia/Damascus': 'Syria Standard Time', + 'Asia/Dhaka': 'Bangladesh Standard Time', + 'Asia/Dili': 'Tokyo Standard Time', + 'Asia/Dubai': 'Arabian Standard Time', + 'Asia/Dushanbe': 'West Asia Standard Time', + 'Asia/Famagusta': 'GTB Standard Time', + 'Asia/Gaza': 'West Bank Standard Time', + 'Asia/Harbin': 'China Standard Time', + 'Asia/Hebron': 'West Bank Standard Time', + 'Asia/Hong_Kong': 'China Standard Time', + 'Asia/Hovd': 'W. Mongolia Standard Time', + 'Asia/Irkutsk': 'North Asia East Standard Time', + 'Asia/Jakarta': 'SE Asia Standard Time', + 'Asia/Jayapura': 'Tokyo Standard Time', + 'Asia/Jerusalem': 'Israel Standard Time', + 'Asia/Kabul': 'Afghanistan Standard Time', + 'Asia/Kamchatka': 'Russia Time Zone 11', + 'Asia/Karachi': 'Pakistan Standard Time', + 'Asia/Kashgar': 'Central Asia Standard Time', + 'Asia/Katmandu': 'Nepal Standard Time', + 'Asia/Khandyga': 'Yakutsk Standard Time', + 'Asia/Krasnoyarsk': 'North Asia Standard Time', + 'Asia/Kuala_Lumpur': 'Singapore Standard Time', + 'Asia/Kuching': 'Singapore Standard Time', + 'Asia/Kuwait': 'Arab Standard Time', + 'Asia/Macao': 'China Standard Time', + 'Asia/Macau': 'China Standard Time', + 'Asia/Magadan': 'Magadan Standard Time', + 'Asia/Makassar': 'Singapore Standard Time', + 'Asia/Manila': 'Singapore Standard Time', + 'Asia/Muscat': 'Arabian Standard Time', + 'Asia/Nicosia': 'GTB Standard Time', + 'Asia/Novokuznetsk': 'North Asia Standard Time', + 'Asia/Novosibirsk': 'N. Central Asia Standard Time', + 'Asia/Omsk': 'Omsk Standard Time', + 'Asia/Oral': 'West Asia Standard Time', + 'Asia/Phnom_Penh': 'SE Asia Standard Time', + 'Asia/Pontianak': 'SE Asia Standard Time', + 'Asia/Pyongyang': 'North Korea Standard Time', + 'Asia/Qatar': 'Arab Standard Time', + 'Asia/Qostanay': 'Central Asia Standard Time', + 'Asia/Qyzylorda': 'Qyzylorda Standard Time', + 'Asia/Rangoon': 'Myanmar Standard Time', + 'Asia/Riyadh': 'Arab Standard Time', + 'Asia/Saigon': 'SE Asia Standard Time', + 'Asia/Sakhalin': 'Sakhalin Standard Time', + 'Asia/Samarkand': 'West Asia Standard Time', + 'Asia/Seoul': 'Korea Standard Time', + 'Asia/Shanghai': 'China Standard Time', + 'Asia/Singapore': 'Singapore Standard Time', + 'Asia/Srednekolymsk': 'Russia Time Zone 10', + 'Asia/Taipei': 'Taipei Standard Time', + 'Asia/Tashkent': 'West Asia Standard Time', + 'Asia/Tbilisi': 'Georgian Standard Time', + 'Asia/Tehran': 'Iran Standard Time', + 'Asia/Tel_Aviv': 'Israel Standard Time', + 'Asia/Thimbu': 'Bangladesh Standard Time', + 'Asia/Thimphu': 'Bangladesh Standard Time', + 'Asia/Tokyo': 'Tokyo Standard Time', + 'Asia/Tomsk': 'Tomsk Standard Time', + 'Asia/Ujung_Pandang': 'Singapore Standard Time', + 'Asia/Ulaanbaatar': 'Ulaanbaatar Standard Time', + 'Asia/Ulan_Bator': 'Ulaanbaatar Standard Time', + 'Asia/Urumqi': 'Central Asia Standard Time', + 'Asia/Ust-Nera': 'Vladivostok Standard Time', + 'Asia/Vientiane': 'SE Asia Standard Time', + 'Asia/Vladivostok': 'Vladivostok Standard Time', + 'Asia/Yakutsk': 'Yakutsk Standard Time', + 'Asia/Yekaterinburg': 'Ekaterinburg Standard Time', + 'Asia/Yerevan': 'Caucasus Standard Time', + 'Atlantic/Azores': 'Azores Standard Time', + 'Atlantic/Bermuda': 'Atlantic Standard Time', + 'Atlantic/Canary': 'GMT Standard Time', + 'Atlantic/Cape_Verde': 'Cape Verde Standard Time', + 'Atlantic/Faeroe': 'GMT Standard Time', + 'Atlantic/Jan_Mayen': 'W. Europe Standard Time', + 'Atlantic/Madeira': 'GMT Standard Time', + 'Atlantic/Reykjavik': 'Greenwich Standard Time', + 'Atlantic/South_Georgia': 'UTC-02', + 'Atlantic/St_Helena': 'Greenwich Standard Time', + 'Atlantic/Stanley': 'SA Eastern Standard Time', + 'Australia/ACT': 'AUS Eastern Standard Time', + 'Australia/Adelaide': 'Cen. Australia Standard Time', + 'Australia/Brisbane': 'E. Australia Standard Time', + 'Australia/Broken_Hill': 'Cen. Australia Standard Time', + 'Australia/Canberra': 'AUS Eastern Standard Time', + 'Australia/Currie': 'Tasmania Standard Time', + 'Australia/Darwin': 'AUS Central Standard Time', + 'Australia/Eucla': 'Aus Central W. Standard Time', + 'Australia/Hobart': 'Tasmania Standard Time', + 'Australia/LHI': 'Lord Howe Standard Time', + 'Australia/Lindeman': 'E. Australia Standard Time', + 'Australia/Lord_Howe': 'Lord Howe Standard Time', + 'Australia/Melbourne': 'AUS Eastern Standard Time', + 'Australia/NSW': 'AUS Eastern Standard Time', + 'Australia/North': 'AUS Central Standard Time', + 'Australia/Perth': 'W. Australia Standard Time', + 'Australia/Queensland': 'E. Australia Standard Time', + 'Australia/South': 'Cen. Australia Standard Time', + 'Australia/Sydney': 'AUS Eastern Standard Time', + 'Australia/Tasmania': 'Tasmania Standard Time', + 'Australia/Victoria': 'AUS Eastern Standard Time', + 'Australia/West': 'W. Australia Standard Time', + 'Australia/Yancowinna': 'Cen. Australia Standard Time', + 'Brazil/Acre': 'SA Pacific Standard Time', + 'Brazil/DeNoronha': 'UTC-02', + 'Brazil/East': 'E. South America Standard Time', + 'Brazil/West': 'SA Western Standard Time', + 'CST6CDT': 'Central Standard Time', + 'Canada/Atlantic': 'Atlantic Standard Time', + 'Canada/Central': 'Central Standard Time', + 'Canada/Eastern': 'Eastern Standard Time', + 'Canada/Mountain': 'Mountain Standard Time', + 'Canada/Newfoundland': 'Newfoundland Standard Time', + 'Canada/Pacific': 'Pacific Standard Time', + 'Canada/Saskatchewan': 'Canada Central Standard Time', + 'Canada/Yukon': 'Pacific Standard Time', + 'Chile/Continental': 'Pacific SA Standard Time', + 'Chile/EasterIsland': 'Easter Island Standard Time', + 'Cuba': 'Cuba Standard Time', + 'EST5EDT': 'Eastern Standard Time', + 'Egypt': 'Egypt Standard Time', + 'Eire': 'GMT Standard Time', + 'Etc/GMT': 'UTC', + 'Etc/GMT+1': 'Cape Verde Standard Time', + 'Etc/GMT+10': 'Hawaiian Standard Time', + 'Etc/GMT+11': 'UTC-11', + 'Etc/GMT+12': 'Dateline Standard Time', + 'Etc/GMT+2': 'UTC-02', + 'Etc/GMT+3': 'SA Eastern Standard Time', + 'Etc/GMT+4': 'SA Western Standard Time', + 'Etc/GMT+5': 'SA Pacific Standard Time', + 'Etc/GMT+6': 'Central America Standard Time', + 'Etc/GMT+7': 'US Mountain Standard Time', + 'Etc/GMT+8': 'UTC-08', + 'Etc/GMT+9': 'UTC-09', + 'Etc/GMT-1': 'W. Central Africa Standard Time', + 'Etc/GMT-10': 'West Pacific Standard Time', + 'Etc/GMT-11': 'Central Pacific Standard Time', + 'Etc/GMT-12': 'UTC+12', + 'Etc/GMT-13': 'UTC+13', + 'Etc/GMT-14': 'Line Islands Standard Time', + 'Etc/GMT-2': 'South Africa Standard Time', + 'Etc/GMT-3': 'E. Africa Standard Time', + 'Etc/GMT-4': 'Arabian Standard Time', + 'Etc/GMT-5': 'West Asia Standard Time', + 'Etc/GMT-6': 'Central Asia Standard Time', + 'Etc/GMT-7': 'SE Asia Standard Time', + 'Etc/GMT-8': 'Singapore Standard Time', + 'Etc/GMT-9': 'Tokyo Standard Time', + 'Etc/UCT': 'UTC', + 'Etc/UTC': 'UTC', + 'Europe/Amsterdam': 'W. Europe Standard Time', + 'Europe/Andorra': 'W. Europe Standard Time', + 'Europe/Astrakhan': 'Astrakhan Standard Time', + 'Europe/Athens': 'GTB Standard Time', + 'Europe/Belfast': 'GMT Standard Time', + 'Europe/Belgrade': 'Central Europe Standard Time', + 'Europe/Berlin': 'W. Europe Standard Time', + 'Europe/Bratislava': 'Central Europe Standard Time', + 'Europe/Brussels': 'Romance Standard Time', + 'Europe/Bucharest': 'GTB Standard Time', + 'Europe/Budapest': 'Central Europe Standard Time', + 'Europe/Busingen': 'W. Europe Standard Time', + 'Europe/Chisinau': 'E. Europe Standard Time', + 'Europe/Copenhagen': 'Romance Standard Time', + 'Europe/Dublin': 'GMT Standard Time', + 'Europe/Gibraltar': 'W. Europe Standard Time', + 'Europe/Guernsey': 'GMT Standard Time', + 'Europe/Helsinki': 'FLE Standard Time', + 'Europe/Isle_of_Man': 'GMT Standard Time', + 'Europe/Istanbul': 'Turkey Standard Time', + 'Europe/Jersey': 'GMT Standard Time', + 'Europe/Kaliningrad': 'Kaliningrad Standard Time', + 'Europe/Kiev': 'FLE Standard Time', + 'Europe/Kirov': 'Russian Standard Time', + 'Europe/Lisbon': 'GMT Standard Time', + 'Europe/Ljubljana': 'Central Europe Standard Time', + 'Europe/London': 'GMT Standard Time', + 'Europe/Luxembourg': 'W. Europe Standard Time', + 'Europe/Madrid': 'Romance Standard Time', + 'Europe/Malta': 'W. Europe Standard Time', + 'Europe/Mariehamn': 'FLE Standard Time', + 'Europe/Minsk': 'Belarus Standard Time', + 'Europe/Monaco': 'W. Europe Standard Time', + 'Europe/Moscow': 'Russian Standard Time', + 'Europe/Oslo': 'W. Europe Standard Time', + 'Europe/Paris': 'Romance Standard Time', + 'Europe/Podgorica': 'Central Europe Standard Time', + 'Europe/Prague': 'Central Europe Standard Time', + 'Europe/Riga': 'FLE Standard Time', + 'Europe/Rome': 'W. Europe Standard Time', + 'Europe/Samara': 'Russia Time Zone 3', + 'Europe/San_Marino': 'W. Europe Standard Time', + 'Europe/Sarajevo': 'Central European Standard Time', + 'Europe/Saratov': 'Saratov Standard Time', + 'Europe/Simferopol': 'Russian Standard Time', + 'Europe/Skopje': 'Central European Standard Time', + 'Europe/Sofia': 'FLE Standard Time', + 'Europe/Stockholm': 'W. Europe Standard Time', + 'Europe/Tallinn': 'FLE Standard Time', + 'Europe/Tirane': 'Central Europe Standard Time', + 'Europe/Tiraspol': 'E. Europe Standard Time', + 'Europe/Ulyanovsk': 'Astrakhan Standard Time', + 'Europe/Uzhgorod': 'FLE Standard Time', + 'Europe/Vaduz': 'W. Europe Standard Time', + 'Europe/Vatican': 'W. Europe Standard Time', + 'Europe/Vienna': 'W. Europe Standard Time', + 'Europe/Vilnius': 'FLE Standard Time', + 'Europe/Volgograd': 'Volgograd Standard Time', + 'Europe/Warsaw': 'Central European Standard Time', + 'Europe/Zagreb': 'Central European Standard Time', + 'Europe/Zaporozhye': 'FLE Standard Time', + 'Europe/Zurich': 'W. Europe Standard Time', + 'GB': 'GMT Standard Time', + 'GB-Eire': 'GMT Standard Time', + 'GMT+0': 'UTC', + 'GMT-0': 'UTC', + 'GMT0': 'UTC', + 'Greenwich': 'UTC', + 'Hongkong': 'China Standard Time', + 'Iceland': 'Greenwich Standard Time', + 'Indian/Antananarivo': 'E. Africa Standard Time', + 'Indian/Chagos': 'Central Asia Standard Time', + 'Indian/Christmas': 'SE Asia Standard Time', + 'Indian/Cocos': 'Myanmar Standard Time', + 'Indian/Comoro': 'E. Africa Standard Time', + 'Indian/Kerguelen': 'West Asia Standard Time', + 'Indian/Mahe': 'Mauritius Standard Time', + 'Indian/Maldives': 'West Asia Standard Time', + 'Indian/Mauritius': 'Mauritius Standard Time', + 'Indian/Mayotte': 'E. Africa Standard Time', + 'Indian/Reunion': 'Mauritius Standard Time', + 'Iran': 'Iran Standard Time', + 'Israel': 'Israel Standard Time', + 'Jamaica': 'SA Pacific Standard Time', + 'Japan': 'Tokyo Standard Time', + 'Kwajalein': 'UTC+12', + 'Libya': 'Libya Standard Time', + 'MST7MDT': 'Mountain Standard Time', + 'Mexico/BajaNorte': 'Pacific Standard Time (Mexico)', + 'Mexico/BajaSur': 'Mountain Standard Time (Mexico)', + 'Mexico/General': 'Central Standard Time (Mexico)', + 'NZ': 'New Zealand Standard Time', + 'NZ-CHAT': 'Chatham Islands Standard Time', + 'Navajo': 'Mountain Standard Time', + 'PRC': 'China Standard Time', + 'PST8PDT': 'Pacific Standard Time', + 'Pacific/Apia': 'Samoa Standard Time', + 'Pacific/Auckland': 'New Zealand Standard Time', + 'Pacific/Bougainville': 'Bougainville Standard Time', + 'Pacific/Chatham': 'Chatham Islands Standard Time', + 'Pacific/Easter': 'Easter Island Standard Time', + 'Pacific/Efate': 'Central Pacific Standard Time', + 'Pacific/Enderbury': 'UTC+13', + 'Pacific/Fakaofo': 'UTC+13', + 'Pacific/Fiji': 'Fiji Standard Time', + 'Pacific/Funafuti': 'UTC+12', + 'Pacific/Galapagos': 'Central America Standard Time', + 'Pacific/Gambier': 'UTC-09', + 'Pacific/Guadalcanal': 'Central Pacific Standard Time', + 'Pacific/Guam': 'West Pacific Standard Time', + 'Pacific/Honolulu': 'Hawaiian Standard Time', + 'Pacific/Johnston': 'Hawaiian Standard Time', + 'Pacific/Kiritimati': 'Line Islands Standard Time', + 'Pacific/Kosrae': 'Central Pacific Standard Time', + 'Pacific/Kwajalein': 'UTC+12', + 'Pacific/Majuro': 'UTC+12', + 'Pacific/Marquesas': 'Marquesas Standard Time', + 'Pacific/Midway': 'UTC-11', + 'Pacific/Nauru': 'UTC+12', + 'Pacific/Niue': 'UTC-11', + 'Pacific/Norfolk': 'Norfolk Standard Time', + 'Pacific/Noumea': 'Central Pacific Standard Time', + 'Pacific/Pago_Pago': 'UTC-11', + 'Pacific/Palau': 'Tokyo Standard Time', + 'Pacific/Pitcairn': 'UTC-08', + 'Pacific/Ponape': 'Central Pacific Standard Time', + 'Pacific/Port_Moresby': 'West Pacific Standard Time', + 'Pacific/Rarotonga': 'Hawaiian Standard Time', + 'Pacific/Saipan': 'West Pacific Standard Time', + 'Pacific/Samoa': 'UTC-11', + 'Pacific/Tahiti': 'Hawaiian Standard Time', + 'Pacific/Tarawa': 'UTC+12', + 'Pacific/Tongatapu': 'Tonga Standard Time', + 'Pacific/Truk': 'West Pacific Standard Time', + 'Pacific/Wake': 'UTC+12', + 'Pacific/Wallis': 'UTC+12', + 'Poland': 'Central European Standard Time', + 'Portugal': 'GMT Standard Time', + 'ROC': 'Taipei Standard Time', + 'ROK': 'Korea Standard Time', + 'Singapore': 'Singapore Standard Time', + 'Turkey': 'Turkey Standard Time', + 'UCT': 'UTC', + 'US/Alaska': 'Alaskan Standard Time', + 'US/Aleutian': 'Aleutian Standard Time', + 'US/Arizona': 'US Mountain Standard Time', + 'US/Central': 'Central Standard Time', + 'US/Eastern': 'Eastern Standard Time', + 'US/Hawaii': 'Hawaiian Standard Time', + 'US/Indiana-Starke': 'Central Standard Time', + 'US/Michigan': 'Eastern Standard Time', + 'US/Mountain': 'Mountain Standard Time', + 'US/Pacific': 'Pacific Standard Time', + 'US/Samoa': 'UTC-11', + 'UTC': 'UTC', + 'Universal': 'UTC', + 'W-SU': 'Russian Standard Time', + 'Zulu': 'UTC'} diff --git a/venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/INSTALLER b/venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/LICENSE.txt b/venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/LICENSE.txt new file mode 100644 index 0000000..429a176 --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2008-2020 Andrey Petrov and contributors (see CONTRIBUTORS.txt) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/METADATA b/venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/METADATA new file mode 100644 index 0000000..af99541 --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/METADATA @@ -0,0 +1,1388 @@ +Metadata-Version: 2.1 +Name: urllib3 +Version: 1.26.6 +Summary: HTTP library with thread-safe connection pooling, file post, and more. +Home-page: https://urllib3.readthedocs.io/ +Author: Andrey Petrov +Author-email: andrey.petrov@shazow.net +License: MIT +Project-URL: Documentation, https://urllib3.readthedocs.io/ +Project-URL: Code, https://github.com/urllib3/urllib3 +Project-URL: Issue tracker, https://github.com/urllib3/urllib3/issues +Keywords: urllib httplib threadsafe filepost http https ssl pooling +Platform: UNKNOWN +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.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 :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Internet :: WWW/HTTP +Classifier: Topic :: Software Development :: Libraries +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4 +Description-Content-Type: text/x-rst +License-File: LICENSE.txt +Provides-Extra: brotli +Requires-Dist: brotlipy (>=0.6.0) ; extra == 'brotli' +Provides-Extra: secure +Requires-Dist: pyOpenSSL (>=0.14) ; extra == 'secure' +Requires-Dist: cryptography (>=1.3.4) ; extra == 'secure' +Requires-Dist: idna (>=2.0.0) ; extra == 'secure' +Requires-Dist: certifi ; extra == 'secure' +Requires-Dist: ipaddress ; (python_version == "2.7") and extra == 'secure' +Provides-Extra: socks +Requires-Dist: PySocks (!=1.5.7,<2.0,>=1.5.6) ; extra == 'socks' + + +urllib3 is a powerful, *user-friendly* HTTP client for Python. Much of the +Python ecosystem already uses urllib3 and you should too. +urllib3 brings many critical features that are missing from the Python +standard libraries: + +- Thread safety. +- Connection pooling. +- Client-side SSL/TLS verification. +- File uploads with multipart encoding. +- Helpers for retrying requests and dealing with HTTP redirects. +- Support for gzip, deflate, and brotli encoding. +- Proxy support for HTTP and SOCKS. +- 100% test coverage. + +urllib3 is powerful and easy to use: + +.. code-block:: python + + >>> import urllib3 + >>> http = urllib3.PoolManager() + >>> r = http.request('GET', 'http://httpbin.org/robots.txt') + >>> r.status + 200 + >>> r.data + 'User-agent: *\nDisallow: /deny\n' + + +Installing +---------- + +urllib3 can be installed with `pip <https://pip.pypa.io>`_:: + + $ python -m pip install urllib3 + +Alternatively, you can grab the latest source code from `GitHub <https://github.com/urllib3/urllib3>`_:: + + $ git clone git://github.com/urllib3/urllib3.git + $ python setup.py install + + +Documentation +------------- + +urllib3 has usage and reference documentation at `urllib3.readthedocs.io <https://urllib3.readthedocs.io>`_. + + +Contributing +------------ + +urllib3 happily accepts contributions. Please see our +`contributing documentation <https://urllib3.readthedocs.io/en/latest/contributing.html>`_ +for some tips on getting started. + + +Security Disclosures +-------------------- + +To report a security vulnerability, please use the +`Tidelift security contact <https://tidelift.com/security>`_. +Tidelift will coordinate the fix and disclosure with maintainers. + + +Maintainers +----------- + +- `@sethmlarson <https://github.com/sethmlarson>`__ (Seth M. Larson) +- `@pquentin <https://github.com/pquentin>`__ (Quentin Pradet) +- `@theacodes <https://github.com/theacodes>`__ (Thea Flowers) +- `@haikuginger <https://github.com/haikuginger>`__ (Jess Shapiro) +- `@lukasa <https://github.com/lukasa>`__ (Cory Benfield) +- `@sigmavirus24 <https://github.com/sigmavirus24>`__ (Ian Stapleton Cordasco) +- `@shazow <https://github.com/shazow>`__ (Andrey Petrov) + +👋 + + +Sponsorship +----------- + +If your company benefits from this library, please consider `sponsoring its +development <https://urllib3.readthedocs.io/en/latest/sponsors.html>`_. + + +For Enterprise +-------------- + +.. |tideliftlogo| image:: https://nedbatchelder.com/pix/Tidelift_Logos_RGB_Tidelift_Shorthand_On-White_small.png + :width: 75 + :alt: Tidelift + +.. list-table:: + :widths: 10 100 + + * - |tideliftlogo| + - Professional support for urllib3 is available as part of the `Tidelift + Subscription`_. Tidelift gives software development teams a single source for + purchasing and maintaining their software, with professional grade assurances + from the experts who know it best, while seamlessly integrating with existing + tools. + +.. _Tidelift Subscription: https://tidelift.com/subscription/pkg/pypi-urllib3?utm_source=pypi-urllib3&utm_medium=referral&utm_campaign=readme + + +Changes +======= + +1.26.6 (2021-06-25) +------------------- + +* Deprecated the ``urllib3.contrib.ntlmpool`` module. urllib3 is not able to support + it properly due to `reasons listed in this issue <https://github.com/urllib3/urllib3/issues/2282>`_. + If you are a user of this module please leave a comment. +* Changed ``HTTPConnection.request_chunked()`` to not erroneously emit multiple + ``Transfer-Encoding`` headers in the case that one is already specified. +* Fixed typo in deprecation message to recommend ``Retry.DEFAULT_ALLOWED_METHODS``. + + +1.26.5 (2021-05-26) +------------------- + +* Fixed deprecation warnings emitted in Python 3.10. +* Updated vendored ``six`` library to 1.16.0. +* Improved performance of URL parser when splitting + the authority component. + + +1.26.4 (2021-03-15) +------------------- + +* Changed behavior of the default ``SSLContext`` when connecting to HTTPS proxy + during HTTPS requests. The default ``SSLContext`` now sets ``check_hostname=True``. + + +1.26.3 (2021-01-26) +------------------- + +* Fixed bytes and string comparison issue with headers (Pull #2141) + +* Changed ``ProxySchemeUnknown`` error message to be + more actionable if the user supplies a proxy URL without + a scheme. (Pull #2107) + + +1.26.2 (2020-11-12) +------------------- + +* Fixed an issue where ``wrap_socket`` and ``CERT_REQUIRED`` wouldn't + be imported properly on Python 2.7.8 and earlier (Pull #2052) + + +1.26.1 (2020-11-11) +------------------- + +* Fixed an issue where two ``User-Agent`` headers would be sent if a + ``User-Agent`` header key is passed as ``bytes`` (Pull #2047) + + +1.26.0 (2020-11-10) +------------------- + +* **NOTE: urllib3 v2.0 will drop support for Python 2**. + `Read more in the v2.0 Roadmap <https://urllib3.readthedocs.io/en/latest/v2-roadmap.html>`_. + +* Added support for HTTPS proxies contacting HTTPS servers (Pull #1923, Pull #1806) + +* Deprecated negotiating TLSv1 and TLSv1.1 by default. Users that + still wish to use TLS earlier than 1.2 without a deprecation warning + should opt-in explicitly by setting ``ssl_version=ssl.PROTOCOL_TLSv1_1`` (Pull #2002) + **Starting in urllib3 v2.0: Connections that receive a ``DeprecationWarning`` will fail** + +* Deprecated ``Retry`` options ``Retry.DEFAULT_METHOD_WHITELIST``, ``Retry.DEFAULT_REDIRECT_HEADERS_BLACKLIST`` + and ``Retry(method_whitelist=...)`` in favor of ``Retry.DEFAULT_ALLOWED_METHODS``, + ``Retry.DEFAULT_REMOVE_HEADERS_ON_REDIRECT``, and ``Retry(allowed_methods=...)`` + (Pull #2000) **Starting in urllib3 v2.0: Deprecated options will be removed** + +* Added default ``User-Agent`` header to every request (Pull #1750) + +* Added ``urllib3.util.SKIP_HEADER`` for skipping ``User-Agent``, ``Accept-Encoding``, + and ``Host`` headers from being automatically emitted with requests (Pull #2018) + +* Collapse ``transfer-encoding: chunked`` request data and framing into + the same ``socket.send()`` call (Pull #1906) + +* Send ``http/1.1`` ALPN identifier with every TLS handshake by default (Pull #1894) + +* Properly terminate SecureTransport connections when CA verification fails (Pull #1977) + +* Don't emit an ``SNIMissingWarning`` when passing ``server_hostname=None`` + to SecureTransport (Pull #1903) + +* Disabled requesting TLSv1.2 session tickets as they weren't being used by urllib3 (Pull #1970) + +* Suppress ``BrokenPipeError`` when writing request body after the server + has closed the socket (Pull #1524) + +* Wrap ``ssl.SSLError`` that can be raised from reading a socket (e.g. "bad MAC") + into an ``urllib3.exceptions.SSLError`` (Pull #1939) + + +1.25.11 (2020-10-19) +-------------------- + +* Fix retry backoff time parsed from ``Retry-After`` header when given + in the HTTP date format. The HTTP date was parsed as the local timezone + rather than accounting for the timezone in the HTTP date (typically + UTC) (Pull #1932, Pull #1935, Pull #1938, Pull #1949) + +* Fix issue where an error would be raised when the ``SSLKEYLOGFILE`` + environment variable was set to the empty string. Now ``SSLContext.keylog_file`` + is not set in this situation (Pull #2016) + + +1.25.10 (2020-07-22) +-------------------- + +* Added support for ``SSLKEYLOGFILE`` environment variable for + logging TLS session keys with use with programs like + Wireshark for decrypting captured web traffic (Pull #1867) + +* Fixed loading of SecureTransport libraries on macOS Big Sur + due to the new dynamic linker cache (Pull #1905) + +* Collapse chunked request bodies data and framing into one + call to ``send()`` to reduce the number of TCP packets by 2-4x (Pull #1906) + +* Don't insert ``None`` into ``ConnectionPool`` if the pool + was empty when requesting a connection (Pull #1866) + +* Avoid ``hasattr`` call in ``BrotliDecoder.decompress()`` (Pull #1858) + + +1.25.9 (2020-04-16) +------------------- + +* Added ``InvalidProxyConfigurationWarning`` which is raised when + erroneously specifying an HTTPS proxy URL. urllib3 doesn't currently + support connecting to HTTPS proxies but will soon be able to + and we would like users to migrate properly without much breakage. + + See `this GitHub issue <https://github.com/urllib3/urllib3/issues/1850>`_ + for more information on how to fix your proxy config. (Pull #1851) + +* Drain connection after ``PoolManager`` redirect (Pull #1817) + +* Ensure ``load_verify_locations`` raises ``SSLError`` for all backends (Pull #1812) + +* Rename ``VerifiedHTTPSConnection`` to ``HTTPSConnection`` (Pull #1805) + +* Allow the CA certificate data to be passed as a string (Pull #1804) + +* Raise ``ValueError`` if method contains control characters (Pull #1800) + +* Add ``__repr__`` to ``Timeout`` (Pull #1795) + + +1.25.8 (2020-01-20) +------------------- + +* Drop support for EOL Python 3.4 (Pull #1774) + +* Optimize _encode_invalid_chars (Pull #1787) + + +1.25.7 (2019-11-11) +------------------- + +* Preserve ``chunked`` parameter on retries (Pull #1715, Pull #1734) + +* Allow unset ``SERVER_SOFTWARE`` in App Engine (Pull #1704, Issue #1470) + +* Fix issue where URL fragment was sent within the request target. (Pull #1732) + +* Fix issue where an empty query section in a URL would fail to parse. (Pull #1732) + +* Remove TLS 1.3 support in SecureTransport due to Apple removing support (Pull #1703) + + +1.25.6 (2019-09-24) +------------------- + +* Fix issue where tilde (``~``) characters were incorrectly + percent-encoded in the path. (Pull #1692) + + +1.25.5 (2019-09-19) +------------------- + +* Add mitigation for BPO-37428 affecting Python <3.7.4 and OpenSSL 1.1.1+ which + caused certificate verification to be enabled when using ``cert_reqs=CERT_NONE``. + (Issue #1682) + + +1.25.4 (2019-09-19) +------------------- + +* Propagate Retry-After header settings to subsequent retries. (Pull #1607) + +* Fix edge case where Retry-After header was still respected even when + explicitly opted out of. (Pull #1607) + +* Remove dependency on ``rfc3986`` for URL parsing. + +* Fix issue where URLs containing invalid characters within ``Url.auth`` would + raise an exception instead of percent-encoding those characters. + +* Add support for ``HTTPResponse.auto_close = False`` which makes HTTP responses + work well with BufferedReaders and other ``io`` module features. (Pull #1652) + +* Percent-encode invalid characters in URL for ``HTTPConnectionPool.request()`` (Pull #1673) + + +1.25.3 (2019-05-23) +------------------- + +* Change ``HTTPSConnection`` to load system CA certificates + when ``ca_certs``, ``ca_cert_dir``, and ``ssl_context`` are + unspecified. (Pull #1608, Issue #1603) + +* Upgrade bundled rfc3986 to v1.3.2. (Pull #1609, Issue #1605) + + +1.25.2 (2019-04-28) +------------------- + +* Change ``is_ipaddress`` to not detect IPvFuture addresses. (Pull #1583) + +* Change ``parse_url`` to percent-encode invalid characters within the + path, query, and target components. (Pull #1586) + + +1.25.1 (2019-04-24) +------------------- + +* Add support for Google's ``Brotli`` package. (Pull #1572, Pull #1579) + +* Upgrade bundled rfc3986 to v1.3.1 (Pull #1578) + + +1.25 (2019-04-22) +----------------- + +* Require and validate certificates by default when using HTTPS (Pull #1507) + +* Upgraded ``urllib3.utils.parse_url()`` to be RFC 3986 compliant. (Pull #1487) + +* Added support for ``key_password`` for ``HTTPSConnectionPool`` to use + encrypted ``key_file`` without creating your own ``SSLContext`` object. (Pull #1489) + +* Add TLSv1.3 support to CPython, pyOpenSSL, and SecureTransport ``SSLContext`` + implementations. (Pull #1496) + +* Switched the default multipart header encoder from RFC 2231 to HTML 5 working draft. (Issue #303, Pull #1492) + +* Fixed issue where OpenSSL would block if an encrypted client private key was + given and no password was given. Instead an ``SSLError`` is raised. (Pull #1489) + +* Added support for Brotli content encoding. It is enabled automatically if + ``brotlipy`` package is installed which can be requested with + ``urllib3[brotli]`` extra. (Pull #1532) + +* Drop ciphers using DSS key exchange from default TLS cipher suites. + Improve default ciphers when using SecureTransport. (Pull #1496) + +* Implemented a more efficient ``HTTPResponse.__iter__()`` method. (Issue #1483) + +1.24.3 (2019-05-01) +------------------- + +* Apply fix for CVE-2019-9740. (Pull #1591) + +1.24.2 (2019-04-17) +------------------- + +* Don't load system certificates by default when any other ``ca_certs``, ``ca_certs_dir`` or + ``ssl_context`` parameters are specified. + +* Remove Authorization header regardless of case when redirecting to cross-site. (Issue #1510) + +* Add support for IPv6 addresses in subjectAltName section of certificates. (Issue #1269) + + +1.24.1 (2018-11-02) +------------------- + +* Remove quadratic behavior within ``GzipDecoder.decompress()`` (Issue #1467) + +* Restored functionality of ``ciphers`` parameter for ``create_urllib3_context()``. (Issue #1462) + + +1.24 (2018-10-16) +----------------- + +* Allow key_server_hostname to be specified when initializing a PoolManager to allow custom SNI to be overridden. (Pull #1449) + +* Test against Python 3.7 on AppVeyor. (Pull #1453) + +* Early-out ipv6 checks when running on App Engine. (Pull #1450) + +* Change ambiguous description of backoff_factor (Pull #1436) + +* Add ability to handle multiple Content-Encodings (Issue #1441 and Pull #1442) + +* Skip DNS names that can't be idna-decoded when using pyOpenSSL (Issue #1405). + +* Add a server_hostname parameter to HTTPSConnection which allows for + overriding the SNI hostname sent in the handshake. (Pull #1397) + +* Drop support for EOL Python 2.6 (Pull #1429 and Pull #1430) + +* Fixed bug where responses with header Content-Type: message/* erroneously + raised HeaderParsingError, resulting in a warning being logged. (Pull #1439) + +* Move urllib3 to src/urllib3 (Pull #1409) + + +1.23 (2018-06-04) +----------------- + +* Allow providing a list of headers to strip from requests when redirecting + to a different host. Defaults to the ``Authorization`` header. Different + headers can be set via ``Retry.remove_headers_on_redirect``. (Issue #1316) + +* Fix ``util.selectors._fileobj_to_fd`` to accept ``long`` (Issue #1247). + +* Dropped Python 3.3 support. (Pull #1242) + +* Put the connection back in the pool when calling stream() or read_chunked() on + a chunked HEAD response. (Issue #1234) + +* Fixed pyOpenSSL-specific ssl client authentication issue when clients + attempted to auth via certificate + chain (Issue #1060) + +* Add the port to the connectionpool connect print (Pull #1251) + +* Don't use the ``uuid`` module to create multipart data boundaries. (Pull #1380) + +* ``read_chunked()`` on a closed response returns no chunks. (Issue #1088) + +* Add Python 2.6 support to ``contrib.securetransport`` (Pull #1359) + +* Added support for auth info in url for SOCKS proxy (Pull #1363) + + +1.22 (2017-07-20) +----------------- + +* Fixed missing brackets in ``HTTP CONNECT`` when connecting to IPv6 address via + IPv6 proxy. (Issue #1222) + +* Made the connection pool retry on ``SSLError``. The original ``SSLError`` + is available on ``MaxRetryError.reason``. (Issue #1112) + +* Drain and release connection before recursing on retry/redirect. Fixes + deadlocks with a blocking connectionpool. (Issue #1167) + +* Fixed compatibility for cookiejar. (Issue #1229) + +* pyopenssl: Use vendored version of ``six``. (Issue #1231) + + +1.21.1 (2017-05-02) +------------------- + +* Fixed SecureTransport issue that would cause long delays in response body + delivery. (Pull #1154) + +* Fixed regression in 1.21 that threw exceptions when users passed the + ``socket_options`` flag to the ``PoolManager``. (Issue #1165) + +* Fixed regression in 1.21 that threw exceptions when users passed the + ``assert_hostname`` or ``assert_fingerprint`` flag to the ``PoolManager``. + (Pull #1157) + + +1.21 (2017-04-25) +----------------- + +* Improved performance of certain selector system calls on Python 3.5 and + later. (Pull #1095) + +* Resolved issue where the PyOpenSSL backend would not wrap SysCallError + exceptions appropriately when sending data. (Pull #1125) + +* Selectors now detects a monkey-patched select module after import for modules + that patch the select module like eventlet, greenlet. (Pull #1128) + +* Reduced memory consumption when streaming zlib-compressed responses + (as opposed to raw deflate streams). (Pull #1129) + +* Connection pools now use the entire request context when constructing the + pool key. (Pull #1016) + +* ``PoolManager.connection_from_*`` methods now accept a new keyword argument, + ``pool_kwargs``, which are merged with the existing ``connection_pool_kw``. + (Pull #1016) + +* Add retry counter for ``status_forcelist``. (Issue #1147) + +* Added ``contrib`` module for using SecureTransport on macOS: + ``urllib3.contrib.securetransport``. (Pull #1122) + +* urllib3 now only normalizes the case of ``http://`` and ``https://`` schemes: + for schemes it does not recognise, it assumes they are case-sensitive and + leaves them unchanged. + (Issue #1080) + + +1.20 (2017-01-19) +----------------- + +* Added support for waiting for I/O using selectors other than select, + improving urllib3's behaviour with large numbers of concurrent connections. + (Pull #1001) + +* Updated the date for the system clock check. (Issue #1005) + +* ConnectionPools now correctly consider hostnames to be case-insensitive. + (Issue #1032) + +* Outdated versions of PyOpenSSL now cause the PyOpenSSL contrib module + to fail when it is injected, rather than at first use. (Pull #1063) + +* Outdated versions of cryptography now cause the PyOpenSSL contrib module + to fail when it is injected, rather than at first use. (Issue #1044) + +* Automatically attempt to rewind a file-like body object when a request is + retried or redirected. (Pull #1039) + +* Fix some bugs that occur when modules incautiously patch the queue module. + (Pull #1061) + +* Prevent retries from occurring on read timeouts for which the request method + was not in the method whitelist. (Issue #1059) + +* Changed the PyOpenSSL contrib module to lazily load idna to avoid + unnecessarily bloating the memory of programs that don't need it. (Pull + #1076) + +* Add support for IPv6 literals with zone identifiers. (Pull #1013) + +* Added support for socks5h:// and socks4a:// schemes when working with SOCKS + proxies, and controlled remote DNS appropriately. (Issue #1035) + + +1.19.1 (2016-11-16) +------------------- + +* Fixed AppEngine import that didn't function on Python 3.5. (Pull #1025) + + +1.19 (2016-11-03) +----------------- + +* urllib3 now respects Retry-After headers on 413, 429, and 503 responses when + using the default retry logic. (Pull #955) + +* Remove markers from setup.py to assist ancient setuptools versions. (Issue + #986) + +* Disallow superscripts and other integerish things in URL ports. (Issue #989) + +* Allow urllib3's HTTPResponse.stream() method to continue to work with + non-httplib underlying FPs. (Pull #990) + +* Empty filenames in multipart headers are now emitted as such, rather than + being suppressed. (Issue #1015) + +* Prefer user-supplied Host headers on chunked uploads. (Issue #1009) + + +1.18.1 (2016-10-27) +------------------- + +* CVE-2016-9015. Users who are using urllib3 version 1.17 or 1.18 along with + PyOpenSSL injection and OpenSSL 1.1.0 *must* upgrade to this version. This + release fixes a vulnerability whereby urllib3 in the above configuration + would silently fail to validate TLS certificates due to erroneously setting + invalid flags in OpenSSL's ``SSL_CTX_set_verify`` function. These erroneous + flags do not cause a problem in OpenSSL versions before 1.1.0, which + interprets the presence of any flag as requesting certificate validation. + + There is no PR for this patch, as it was prepared for simultaneous disclosure + and release. The master branch received the same fix in Pull #1010. + + +1.18 (2016-09-26) +----------------- + +* Fixed incorrect message for IncompleteRead exception. (Pull #973) + +* Accept ``iPAddress`` subject alternative name fields in TLS certificates. + (Issue #258) + +* Fixed consistency of ``HTTPResponse.closed`` between Python 2 and 3. + (Issue #977) + +* Fixed handling of wildcard certificates when using PyOpenSSL. (Issue #979) + + +1.17 (2016-09-06) +----------------- + +* Accept ``SSLContext`` objects for use in SSL/TLS negotiation. (Issue #835) + +* ConnectionPool debug log now includes scheme, host, and port. (Issue #897) + +* Substantially refactored documentation. (Issue #887) + +* Used URLFetch default timeout on AppEngine, rather than hardcoding our own. + (Issue #858) + +* Normalize the scheme and host in the URL parser (Issue #833) + +* ``HTTPResponse`` contains the last ``Retry`` object, which now also + contains retries history. (Issue #848) + +* Timeout can no longer be set as boolean, and must be greater than zero. + (Pull #924) + +* Removed pyasn1 and ndg-httpsclient from dependencies used for PyOpenSSL. We + now use cryptography and idna, both of which are already dependencies of + PyOpenSSL. (Pull #930) + +* Fixed infinite loop in ``stream`` when amt=None. (Issue #928) + +* Try to use the operating system's certificates when we are using an + ``SSLContext``. (Pull #941) + +* Updated cipher suite list to allow ChaCha20+Poly1305. AES-GCM is preferred to + ChaCha20, but ChaCha20 is then preferred to everything else. (Pull #947) + +* Updated cipher suite list to remove 3DES-based cipher suites. (Pull #958) + +* Removed the cipher suite fallback to allow HIGH ciphers. (Pull #958) + +* Implemented ``length_remaining`` to determine remaining content + to be read. (Pull #949) + +* Implemented ``enforce_content_length`` to enable exceptions when + incomplete data chunks are received. (Pull #949) + +* Dropped connection start, dropped connection reset, redirect, forced retry, + and new HTTPS connection log levels to DEBUG, from INFO. (Pull #967) + + +1.16 (2016-06-11) +----------------- + +* Disable IPv6 DNS when IPv6 connections are not possible. (Issue #840) + +* Provide ``key_fn_by_scheme`` pool keying mechanism that can be + overridden. (Issue #830) + +* Normalize scheme and host to lowercase for pool keys, and include + ``source_address``. (Issue #830) + +* Cleaner exception chain in Python 3 for ``_make_request``. + (Issue #861) + +* Fixed installing ``urllib3[socks]`` extra. (Issue #864) + +* Fixed signature of ``ConnectionPool.close`` so it can actually safely be + called by subclasses. (Issue #873) + +* Retain ``release_conn`` state across retries. (Issues #651, #866) + +* Add customizable ``HTTPConnectionPool.ResponseCls``, which defaults to + ``HTTPResponse`` but can be replaced with a subclass. (Issue #879) + + +1.15.1 (2016-04-11) +------------------- + +* Fix packaging to include backports module. (Issue #841) + + +1.15 (2016-04-06) +----------------- + +* Added Retry(raise_on_status=False). (Issue #720) + +* Always use setuptools, no more distutils fallback. (Issue #785) + +* Dropped support for Python 3.2. (Issue #786) + +* Chunked transfer encoding when requesting with ``chunked=True``. + (Issue #790) + +* Fixed regression with IPv6 port parsing. (Issue #801) + +* Append SNIMissingWarning messages to allow users to specify it in + the PYTHONWARNINGS environment variable. (Issue #816) + +* Handle unicode headers in Py2. (Issue #818) + +* Log certificate when there is a hostname mismatch. (Issue #820) + +* Preserve order of request/response headers. (Issue #821) + + +1.14 (2015-12-29) +----------------- + +* contrib: SOCKS proxy support! (Issue #762) + +* Fixed AppEngine handling of transfer-encoding header and bug + in Timeout defaults checking. (Issue #763) + + +1.13.1 (2015-12-18) +------------------- + +* Fixed regression in IPv6 + SSL for match_hostname. (Issue #761) + + +1.13 (2015-12-14) +----------------- + +* Fixed ``pip install urllib3[secure]`` on modern pip. (Issue #706) + +* pyopenssl: Fixed SSL3_WRITE_PENDING error. (Issue #717) + +* pyopenssl: Support for TLSv1.1 and TLSv1.2. (Issue #696) + +* Close connections more defensively on exception. (Issue #734) + +* Adjusted ``read_chunked`` to handle gzipped, chunk-encoded bodies without + repeatedly flushing the decoder, to function better on Jython. (Issue #743) + +* Accept ``ca_cert_dir`` for SSL-related PoolManager configuration. (Issue #758) + + +1.12 (2015-09-03) +----------------- + +* Rely on ``six`` for importing ``httplib`` to work around + conflicts with other Python 3 shims. (Issue #688) + +* Add support for directories of certificate authorities, as supported by + OpenSSL. (Issue #701) + +* New exception: ``NewConnectionError``, raised when we fail to establish + a new connection, usually ``ECONNREFUSED`` socket error. + + +1.11 (2015-07-21) +----------------- + +* When ``ca_certs`` is given, ``cert_reqs`` defaults to + ``'CERT_REQUIRED'``. (Issue #650) + +* ``pip install urllib3[secure]`` will install Certifi and + PyOpenSSL as dependencies. (Issue #678) + +* Made ``HTTPHeaderDict`` usable as a ``headers`` input value + (Issues #632, #679) + +* Added `urllib3.contrib.appengine <https://urllib3.readthedocs.io/en/latest/contrib.html#google-app-engine>`_ + which has an ``AppEngineManager`` for using ``URLFetch`` in a + Google AppEngine environment. (Issue #664) + +* Dev: Added test suite for AppEngine. (Issue #631) + +* Fix performance regression when using PyOpenSSL. (Issue #626) + +* Passing incorrect scheme (e.g. ``foo://``) will raise + ``ValueError`` instead of ``AssertionError`` (backwards + compatible for now, but please migrate). (Issue #640) + +* Fix pools not getting replenished when an error occurs during a + request using ``release_conn=False``. (Issue #644) + +* Fix pool-default headers not applying for url-encoded requests + like GET. (Issue #657) + +* log.warning in Python 3 when headers are skipped due to parsing + errors. (Issue #642) + +* Close and discard connections if an error occurs during read. + (Issue #660) + +* Fix host parsing for IPv6 proxies. (Issue #668) + +* Separate warning type SubjectAltNameWarning, now issued once + per host. (Issue #671) + +* Fix ``httplib.IncompleteRead`` not getting converted to + ``ProtocolError`` when using ``HTTPResponse.stream()`` + (Issue #674) + +1.10.4 (2015-05-03) +------------------- + +* Migrate tests to Tornado 4. (Issue #594) + +* Append default warning configuration rather than overwrite. + (Issue #603) + +* Fix streaming decoding regression. (Issue #595) + +* Fix chunked requests losing state across keep-alive connections. + (Issue #599) + +* Fix hanging when chunked HEAD response has no body. (Issue #605) + + +1.10.3 (2015-04-21) +------------------- + +* Emit ``InsecurePlatformWarning`` when SSLContext object is missing. + (Issue #558) + +* Fix regression of duplicate header keys being discarded. + (Issue #563) + +* ``Response.stream()`` returns a generator for chunked responses. + (Issue #560) + +* Set upper-bound timeout when waiting for a socket in PyOpenSSL. + (Issue #585) + +* Work on platforms without `ssl` module for plain HTTP requests. + (Issue #587) + +* Stop relying on the stdlib's default cipher list. (Issue #588) + + +1.10.2 (2015-02-25) +------------------- + +* Fix file descriptor leakage on retries. (Issue #548) + +* Removed RC4 from default cipher list. (Issue #551) + +* Header performance improvements. (Issue #544) + +* Fix PoolManager not obeying redirect retry settings. (Issue #553) + + +1.10.1 (2015-02-10) +------------------- + +* Pools can be used as context managers. (Issue #545) + +* Don't re-use connections which experienced an SSLError. (Issue #529) + +* Don't fail when gzip decoding an empty stream. (Issue #535) + +* Add sha256 support for fingerprint verification. (Issue #540) + +* Fixed handling of header values containing commas. (Issue #533) + + +1.10 (2014-12-14) +----------------- + +* Disabled SSLv3. (Issue #473) + +* Add ``Url.url`` property to return the composed url string. (Issue #394) + +* Fixed PyOpenSSL + gevent ``WantWriteError``. (Issue #412) + +* ``MaxRetryError.reason`` will always be an exception, not string. + (Issue #481) + +* Fixed SSL-related timeouts not being detected as timeouts. (Issue #492) + +* Py3: Use ``ssl.create_default_context()`` when available. (Issue #473) + +* Emit ``InsecureRequestWarning`` for *every* insecure HTTPS request. + (Issue #496) + +* Emit ``SecurityWarning`` when certificate has no ``subjectAltName``. + (Issue #499) + +* Close and discard sockets which experienced SSL-related errors. + (Issue #501) + +* Handle ``body`` param in ``.request(...)``. (Issue #513) + +* Respect timeout with HTTPS proxy. (Issue #505) + +* PyOpenSSL: Handle ZeroReturnError exception. (Issue #520) + + +1.9.1 (2014-09-13) +------------------ + +* Apply socket arguments before binding. (Issue #427) + +* More careful checks if fp-like object is closed. (Issue #435) + +* Fixed packaging issues of some development-related files not + getting included. (Issue #440) + +* Allow performing *only* fingerprint verification. (Issue #444) + +* Emit ``SecurityWarning`` if system clock is waaay off. (Issue #445) + +* Fixed PyOpenSSL compatibility with PyPy. (Issue #450) + +* Fixed ``BrokenPipeError`` and ``ConnectionError`` handling in Py3. + (Issue #443) + + + +1.9 (2014-07-04) +---------------- + +* Shuffled around development-related files. If you're maintaining a distro + package of urllib3, you may need to tweak things. (Issue #415) + +* Unverified HTTPS requests will trigger a warning on the first request. See + our new `security documentation + <https://urllib3.readthedocs.io/en/latest/security.html>`_ for details. + (Issue #426) + +* New retry logic and ``urllib3.util.retry.Retry`` configuration object. + (Issue #326) + +* All raised exceptions should now wrapped in a + ``urllib3.exceptions.HTTPException``-extending exception. (Issue #326) + +* All errors during a retry-enabled request should be wrapped in + ``urllib3.exceptions.MaxRetryError``, including timeout-related exceptions + which were previously exempt. Underlying error is accessible from the + ``.reason`` property. (Issue #326) + +* ``urllib3.exceptions.ConnectionError`` renamed to + ``urllib3.exceptions.ProtocolError``. (Issue #326) + +* Errors during response read (such as IncompleteRead) are now wrapped in + ``urllib3.exceptions.ProtocolError``. (Issue #418) + +* Requesting an empty host will raise ``urllib3.exceptions.LocationValueError``. + (Issue #417) + +* Catch read timeouts over SSL connections as + ``urllib3.exceptions.ReadTimeoutError``. (Issue #419) + +* Apply socket arguments before connecting. (Issue #427) + + +1.8.3 (2014-06-23) +------------------ + +* Fix TLS verification when using a proxy in Python 3.4.1. (Issue #385) + +* Add ``disable_cache`` option to ``urllib3.util.make_headers``. (Issue #393) + +* Wrap ``socket.timeout`` exception with + ``urllib3.exceptions.ReadTimeoutError``. (Issue #399) + +* Fixed proxy-related bug where connections were being reused incorrectly. + (Issues #366, #369) + +* Added ``socket_options`` keyword parameter which allows to define + ``setsockopt`` configuration of new sockets. (Issue #397) + +* Removed ``HTTPConnection.tcp_nodelay`` in favor of + ``HTTPConnection.default_socket_options``. (Issue #397) + +* Fixed ``TypeError`` bug in Python 2.6.4. (Issue #411) + + +1.8.2 (2014-04-17) +------------------ + +* Fix ``urllib3.util`` not being included in the package. + + +1.8.1 (2014-04-17) +------------------ + +* Fix AppEngine bug of HTTPS requests going out as HTTP. (Issue #356) + +* Don't install ``dummyserver`` into ``site-packages`` as it's only needed + for the test suite. (Issue #362) + +* Added support for specifying ``source_address``. (Issue #352) + + +1.8 (2014-03-04) +---------------- + +* Improved url parsing in ``urllib3.util.parse_url`` (properly parse '@' in + username, and blank ports like 'hostname:'). + +* New ``urllib3.connection`` module which contains all the HTTPConnection + objects. + +* Several ``urllib3.util.Timeout``-related fixes. Also changed constructor + signature to a more sensible order. [Backwards incompatible] + (Issues #252, #262, #263) + +* Use ``backports.ssl_match_hostname`` if it's installed. (Issue #274) + +* Added ``.tell()`` method to ``urllib3.response.HTTPResponse`` which + returns the number of bytes read so far. (Issue #277) + +* Support for platforms without threading. (Issue #289) + +* Expand default-port comparison in ``HTTPConnectionPool.is_same_host`` + to allow a pool with no specified port to be considered equal to to an + HTTP/HTTPS url with port 80/443 explicitly provided. (Issue #305) + +* Improved default SSL/TLS settings to avoid vulnerabilities. + (Issue #309) + +* Fixed ``urllib3.poolmanager.ProxyManager`` not retrying on connect errors. + (Issue #310) + +* Disable Nagle's Algorithm on the socket for non-proxies. A subset of requests + will send the entire HTTP request ~200 milliseconds faster; however, some of + the resulting TCP packets will be smaller. (Issue #254) + +* Increased maximum number of SubjectAltNames in ``urllib3.contrib.pyopenssl`` + from the default 64 to 1024 in a single certificate. (Issue #318) + +* Headers are now passed and stored as a custom + ``urllib3.collections_.HTTPHeaderDict`` object rather than a plain ``dict``. + (Issue #329, #333) + +* Headers no longer lose their case on Python 3. (Issue #236) + +* ``urllib3.contrib.pyopenssl`` now uses the operating system's default CA + certificates on inject. (Issue #332) + +* Requests with ``retries=False`` will immediately raise any exceptions without + wrapping them in ``MaxRetryError``. (Issue #348) + +* Fixed open socket leak with SSL-related failures. (Issue #344, #348) + + +1.7.1 (2013-09-25) +------------------ + +* Added granular timeout support with new ``urllib3.util.Timeout`` class. + (Issue #231) + +* Fixed Python 3.4 support. (Issue #238) + + +1.7 (2013-08-14) +---------------- + +* More exceptions are now pickle-able, with tests. (Issue #174) + +* Fixed redirecting with relative URLs in Location header. (Issue #178) + +* Support for relative urls in ``Location: ...`` header. (Issue #179) + +* ``urllib3.response.HTTPResponse`` now inherits from ``io.IOBase`` for bonus + file-like functionality. (Issue #187) + +* Passing ``assert_hostname=False`` when creating a HTTPSConnectionPool will + skip hostname verification for SSL connections. (Issue #194) + +* New method ``urllib3.response.HTTPResponse.stream(...)`` which acts as a + generator wrapped around ``.read(...)``. (Issue #198) + +* IPv6 url parsing enforces brackets around the hostname. (Issue #199) + +* Fixed thread race condition in + ``urllib3.poolmanager.PoolManager.connection_from_host(...)`` (Issue #204) + +* ``ProxyManager`` requests now include non-default port in ``Host: ...`` + header. (Issue #217) + +* Added HTTPS proxy support in ``ProxyManager``. (Issue #170 #139) + +* New ``RequestField`` object can be passed to the ``fields=...`` param which + can specify headers. (Issue #220) + +* Raise ``urllib3.exceptions.ProxyError`` when connecting to proxy fails. + (Issue #221) + +* Use international headers when posting file names. (Issue #119) + +* Improved IPv6 support. (Issue #203) + + +1.6 (2013-04-25) +---------------- + +* Contrib: Optional SNI support for Py2 using PyOpenSSL. (Issue #156) + +* ``ProxyManager`` automatically adds ``Host: ...`` header if not given. + +* Improved SSL-related code. ``cert_req`` now optionally takes a string like + "REQUIRED" or "NONE". Same with ``ssl_version`` takes strings like "SSLv23" + The string values reflect the suffix of the respective constant variable. + (Issue #130) + +* Vendored ``socksipy`` now based on Anorov's fork which handles unexpectedly + closed proxy connections and larger read buffers. (Issue #135) + +* Ensure the connection is closed if no data is received, fixes connection leak + on some platforms. (Issue #133) + +* Added SNI support for SSL/TLS connections on Py32+. (Issue #89) + +* Tests fixed to be compatible with Py26 again. (Issue #125) + +* Added ability to choose SSL version by passing an ``ssl.PROTOCOL_*`` constant + to the ``ssl_version`` parameter of ``HTTPSConnectionPool``. (Issue #109) + +* Allow an explicit content type to be specified when encoding file fields. + (Issue #126) + +* Exceptions are now pickleable, with tests. (Issue #101) + +* Fixed default headers not getting passed in some cases. (Issue #99) + +* Treat "content-encoding" header value as case-insensitive, per RFC 2616 + Section 3.5. (Issue #110) + +* "Connection Refused" SocketErrors will get retried rather than raised. + (Issue #92) + +* Updated vendored ``six``, no longer overrides the global ``six`` module + namespace. (Issue #113) + +* ``urllib3.exceptions.MaxRetryError`` contains a ``reason`` property holding + the exception that prompted the final retry. If ``reason is None`` then it + was due to a redirect. (Issue #92, #114) + +* Fixed ``PoolManager.urlopen()`` from not redirecting more than once. + (Issue #149) + +* Don't assume ``Content-Type: text/plain`` for multi-part encoding parameters + that are not files. (Issue #111) + +* Pass `strict` param down to ``httplib.HTTPConnection``. (Issue #122) + +* Added mechanism to verify SSL certificates by fingerprint (md5, sha1) or + against an arbitrary hostname (when connecting by IP or for misconfigured + servers). (Issue #140) + +* Streaming decompression support. (Issue #159) + + +1.5 (2012-08-02) +---------------- + +* Added ``urllib3.add_stderr_logger()`` for quickly enabling STDERR debug + logging in urllib3. + +* Native full URL parsing (including auth, path, query, fragment) available in + ``urllib3.util.parse_url(url)``. + +* Built-in redirect will switch method to 'GET' if status code is 303. + (Issue #11) + +* ``urllib3.PoolManager`` strips the scheme and host before sending the request + uri. (Issue #8) + +* New ``urllib3.exceptions.DecodeError`` exception for when automatic decoding, + based on the Content-Type header, fails. + +* Fixed bug with pool depletion and leaking connections (Issue #76). Added + explicit connection closing on pool eviction. Added + ``urllib3.PoolManager.clear()``. + +* 99% -> 100% unit test coverage. + + +1.4 (2012-06-16) +---------------- + +* Minor AppEngine-related fixes. + +* Switched from ``mimetools.choose_boundary`` to ``uuid.uuid4()``. + +* Improved url parsing. (Issue #73) + +* IPv6 url support. (Issue #72) + + +1.3 (2012-03-25) +---------------- + +* Removed pre-1.0 deprecated API. + +* Refactored helpers into a ``urllib3.util`` submodule. + +* Fixed multipart encoding to support list-of-tuples for keys with multiple + values. (Issue #48) + +* Fixed multiple Set-Cookie headers in response not getting merged properly in + Python 3. (Issue #53) + +* AppEngine support with Py27. (Issue #61) + +* Minor ``encode_multipart_formdata`` fixes related to Python 3 strings vs + bytes. + + +1.2.2 (2012-02-06) +------------------ + +* Fixed packaging bug of not shipping ``test-requirements.txt``. (Issue #47) + + +1.2.1 (2012-02-05) +------------------ + +* Fixed another bug related to when ``ssl`` module is not available. (Issue #41) + +* Location parsing errors now raise ``urllib3.exceptions.LocationParseError`` + which inherits from ``ValueError``. + + +1.2 (2012-01-29) +---------------- + +* Added Python 3 support (tested on 3.2.2) + +* Dropped Python 2.5 support (tested on 2.6.7, 2.7.2) + +* Use ``select.poll`` instead of ``select.select`` for platforms that support + it. + +* Use ``Queue.LifoQueue`` instead of ``Queue.Queue`` for more aggressive + connection reusing. Configurable by overriding ``ConnectionPool.QueueCls``. + +* Fixed ``ImportError`` during install when ``ssl`` module is not available. + (Issue #41) + +* Fixed ``PoolManager`` redirects between schemes (such as HTTP -> HTTPS) not + completing properly. (Issue #28, uncovered by Issue #10 in v1.1) + +* Ported ``dummyserver`` to use ``tornado`` instead of ``webob`` + + ``eventlet``. Removed extraneous unsupported dummyserver testing backends. + Added socket-level tests. + +* More tests. Achievement Unlocked: 99% Coverage. + + +1.1 (2012-01-07) +---------------- + +* Refactored ``dummyserver`` to its own root namespace module (used for + testing). + +* Added hostname verification for ``VerifiedHTTPSConnection`` by vendoring in + Py32's ``ssl_match_hostname``. (Issue #25) + +* Fixed cross-host HTTP redirects when using ``PoolManager``. (Issue #10) + +* Fixed ``decode_content`` being ignored when set through ``urlopen``. (Issue + #27) + +* Fixed timeout-related bugs. (Issues #17, #23) + + +1.0.2 (2011-11-04) +------------------ + +* Fixed typo in ``VerifiedHTTPSConnection`` which would only present as a bug if + you're using the object manually. (Thanks pyos) + +* Made RecentlyUsedContainer (and consequently PoolManager) more thread-safe by + wrapping the access log in a mutex. (Thanks @christer) + +* Made RecentlyUsedContainer more dict-like (corrected ``__delitem__`` and + ``__getitem__`` behaviour), with tests. Shouldn't affect core urllib3 code. + + +1.0.1 (2011-10-10) +------------------ + +* Fixed a bug where the same connection would get returned into the pool twice, + causing extraneous "HttpConnectionPool is full" log warnings. + + +1.0 (2011-10-08) +---------------- + +* Added ``PoolManager`` with LRU expiration of connections (tested and + documented). +* Added ``ProxyManager`` (needs tests, docs, and confirmation that it works + with HTTPS proxies). +* Added optional partial-read support for responses when + ``preload_content=False``. You can now make requests and just read the headers + without loading the content. +* Made response decoding optional (default on, same as before). +* Added optional explicit boundary string for ``encode_multipart_formdata``. +* Convenience request methods are now inherited from ``RequestMethods``. Old + helpers like ``get_url`` and ``post_url`` should be abandoned in favour of + the new ``request(method, url, ...)``. +* Refactored code to be even more decoupled, reusable, and extendable. +* License header added to ``.py`` files. +* Embiggened the documentation: Lots of Sphinx-friendly docstrings in the code + and docs in ``docs/`` and on https://urllib3.readthedocs.io/. +* Embettered all the things! +* Started writing this file. + + +0.4.1 (2011-07-17) +------------------ + +* Minor bug fixes, code cleanup. + + +0.4 (2011-03-01) +---------------- + +* Better unicode support. +* Added ``VerifiedHTTPSConnection``. +* Added ``NTLMConnectionPool`` in contrib. +* Minor improvements. + + +0.3.1 (2010-07-13) +------------------ + +* Added ``assert_host_name`` optional parameter. Now compatible with proxies. + + +0.3 (2009-12-10) +---------------- + +* Added HTTPS support. +* Minor bug fixes. +* Refactored, broken backwards compatibility with 0.2. +* API to be treated as stable from this version forward. + + +0.2 (2008-11-17) +---------------- + +* Added unit tests. +* Bug fixes. + + +0.1 (2008-11-16) +---------------- + +* First release. + + diff --git a/venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/RECORD b/venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/RECORD new file mode 100644 index 0000000..712b755 --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/RECORD @@ -0,0 +1,84 @@ +urllib3-1.26.6.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +urllib3-1.26.6.dist-info/LICENSE.txt,sha256=w3vxhuJ8-dvpYZ5V7f486nswCRzrPaY8fay-Dm13kHs,1115 +urllib3-1.26.6.dist-info/METADATA,sha256=GTqag0OUj9vLryU3xGQO2LJGvkatmJYgTZxnWYT8fpc,44267 +urllib3-1.26.6.dist-info/RECORD,, +urllib3-1.26.6.dist-info/WHEEL,sha256=Z-nyYpwrcSqxfdux5Mbn_DQ525iP7J2DG3JgGvOYyTQ,110 +urllib3-1.26.6.dist-info/top_level.txt,sha256=EMiXL2sKrTcmrMxIHTqdc3ET54pQI2Y072LexFEemvo,8 +urllib3/__init__.py,sha256=j3yzHIbmW7CS-IKQJ9-PPQf_YKO8EOAey_rMW0UR7us,2763 +urllib3/__pycache__/__init__.cpython-38.pyc,, +urllib3/__pycache__/_collections.cpython-38.pyc,, +urllib3/__pycache__/_version.cpython-38.pyc,, +urllib3/__pycache__/connection.cpython-38.pyc,, +urllib3/__pycache__/connectionpool.cpython-38.pyc,, +urllib3/__pycache__/exceptions.cpython-38.pyc,, +urllib3/__pycache__/fields.cpython-38.pyc,, +urllib3/__pycache__/filepost.cpython-38.pyc,, +urllib3/__pycache__/poolmanager.cpython-38.pyc,, +urllib3/__pycache__/request.cpython-38.pyc,, +urllib3/__pycache__/response.cpython-38.pyc,, +urllib3/_collections.py,sha256=Rp1mVyBgc_UlAcp6M3at1skJBXR5J43NawRTvW2g_XY,10811 +urllib3/_version.py,sha256=6fJAIPnJkT0m9wzVjHrFcq5wYt65dStDpaRcjj5ugoo,63 +urllib3/connection.py,sha256=kAlubwsW33FUSUroPSVHMF_Zzv-uzX_BwUFMXX9Pt8c,18754 +urllib3/connectionpool.py,sha256=jXNmm4y3LJWYgteNeGcYJx8-0k7bzKRU__AVTXzaIak,37131 +urllib3/contrib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +urllib3/contrib/__pycache__/__init__.cpython-38.pyc,, +urllib3/contrib/__pycache__/_appengine_environ.cpython-38.pyc,, +urllib3/contrib/__pycache__/appengine.cpython-38.pyc,, +urllib3/contrib/__pycache__/ntlmpool.cpython-38.pyc,, +urllib3/contrib/__pycache__/pyopenssl.cpython-38.pyc,, +urllib3/contrib/__pycache__/securetransport.cpython-38.pyc,, +urllib3/contrib/__pycache__/socks.cpython-38.pyc,, +urllib3/contrib/_appengine_environ.py,sha256=bDbyOEhW2CKLJcQqAKAyrEHN-aklsyHFKq6vF8ZFsmk,957 +urllib3/contrib/_securetransport/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +urllib3/contrib/_securetransport/__pycache__/__init__.cpython-38.pyc,, +urllib3/contrib/_securetransport/__pycache__/bindings.cpython-38.pyc,, +urllib3/contrib/_securetransport/__pycache__/low_level.cpython-38.pyc,, +urllib3/contrib/_securetransport/bindings.py,sha256=E1_7ScsgOchfxneozbAueK7ziCwF35fna4DuDCYJ9_o,17637 +urllib3/contrib/_securetransport/low_level.py,sha256=lgIdsSycqfB0Xm5BiJzXGeIKT7ybCQMFPJAgkcwPa1s,13908 +urllib3/contrib/appengine.py,sha256=jz515jZYBDFTnhR4zqfeaCo6JdDgAQqYbqzHK9sDkfw,11010 +urllib3/contrib/ntlmpool.py,sha256=ej9gGvfAb2Gt00lafFp45SIoRz-QwrQ4WChm6gQmAlM,4538 +urllib3/contrib/pyopenssl.py,sha256=YIMyTiXiLPV_QfFw3PjZ31mGqJmM5EzxIjhSLxZ7VUM,16874 +urllib3/contrib/securetransport.py,sha256=izdx43gFoUGFSgxasZlOCL42FaM4vSsAVTmhO0EH1vM,34417 +urllib3/contrib/socks.py,sha256=aRi9eWXo9ZEb95XUxef4Z21CFlnnjbEiAo9HOseoMt4,7097 +urllib3/exceptions.py,sha256=0Mnno3KHTNfXRfY7638NufOPkUb6mXOm-Lqj-4x2w8A,8217 +urllib3/fields.py,sha256=kvLDCg_JmH1lLjUUEY_FLS8UhY7hBvDPuVETbY8mdrM,8579 +urllib3/filepost.py,sha256=5b_qqgRHVlL7uLtdAYBzBh-GHmU5AfJVt_2N0XS3PeY,2440 +urllib3/packages/__init__.py,sha256=h4BLhD4tLaBx1adaDtKXfupsgqY0wWLXb_f1_yVlV6A,108 +urllib3/packages/__pycache__/__init__.cpython-38.pyc,, +urllib3/packages/__pycache__/six.cpython-38.pyc,, +urllib3/packages/backports/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +urllib3/packages/backports/__pycache__/__init__.cpython-38.pyc,, +urllib3/packages/backports/__pycache__/makefile.cpython-38.pyc,, +urllib3/packages/backports/makefile.py,sha256=nbzt3i0agPVP07jqqgjhaYjMmuAi_W5E0EywZivVO8E,1417 +urllib3/packages/six.py,sha256=1LVW7ljqRirFlfExjwl-v1B7vSAUNTmzGMs-qays2zg,34666 +urllib3/packages/ssl_match_hostname/__init__.py,sha256=ZVMwCkHx-py8ERsxxM3Il-MiREZktV-8iLBmCfRRHI4,927 +urllib3/packages/ssl_match_hostname/__pycache__/__init__.cpython-38.pyc,, +urllib3/packages/ssl_match_hostname/__pycache__/_implementation.cpython-38.pyc,, +urllib3/packages/ssl_match_hostname/_implementation.py,sha256=6dZ-q074g7XhsJ27MFCgkct8iVNZB3sMZvKhf-KUVy0,5679 +urllib3/poolmanager.py,sha256=whzlX6UTEgODMOCy0ZDMUONRBCz5wyIM8Z9opXAY-Lk,19763 +urllib3/request.py,sha256=ZFSIqX0C6WizixecChZ3_okyu7BEv0lZu1VT0s6h4SM,5985 +urllib3/response.py,sha256=hGhGBh7TkEkh_IQg5C1W_xuPNrgIKv5BUXPyE-q0LuE,28203 +urllib3/util/__init__.py,sha256=JEmSmmqqLyaw8P51gUImZh8Gwg9i1zSe-DoqAitn2nc,1155 +urllib3/util/__pycache__/__init__.cpython-38.pyc,, +urllib3/util/__pycache__/connection.cpython-38.pyc,, +urllib3/util/__pycache__/proxy.cpython-38.pyc,, +urllib3/util/__pycache__/queue.cpython-38.pyc,, +urllib3/util/__pycache__/request.cpython-38.pyc,, +urllib3/util/__pycache__/response.cpython-38.pyc,, +urllib3/util/__pycache__/retry.cpython-38.pyc,, +urllib3/util/__pycache__/ssl_.cpython-38.pyc,, +urllib3/util/__pycache__/ssltransport.cpython-38.pyc,, +urllib3/util/__pycache__/timeout.cpython-38.pyc,, +urllib3/util/__pycache__/url.cpython-38.pyc,, +urllib3/util/__pycache__/wait.cpython-38.pyc,, +urllib3/util/connection.py,sha256=Z9JufD13VNcga6RTW1wRIULbWdxsPE0WCUi5VTebALA,4908 +urllib3/util/proxy.py,sha256=FGipAEnvZteyldXNjce4DEB7YzwU-a5lep8y5S0qHQg,1604 +urllib3/util/queue.py,sha256=nRgX8_eX-_VkvxoX096QWoz8Ps0QHUAExILCY_7PncM,498 +urllib3/util/request.py,sha256=NnzaEKQ1Pauw5MFMV6HmgEMHITf0Aua9fQuzi2uZzGc,4123 +urllib3/util/response.py,sha256=GJpg3Egi9qaJXRwBh5wv-MNuRWan5BIu40oReoxWP28,3510 +urllib3/util/retry.py,sha256=tOWfZpLsuc7Vbk5nWpMwkHdMoXCp90IAvH4xtjSDRqQ,21391 +urllib3/util/ssl_.py,sha256=c0sYiSC6272r6uPkxQpo5rYPP9QC1eR6oI7004gYqZo,17165 +urllib3/util/ssltransport.py,sha256=3bLBqYPryT9UMGbx5iRgMgb2sj7VEKp5pmRD1g8d6VI,6907 +urllib3/util/timeout.py,sha256=QSbBUNOB9yh6AnDn61SrLQ0hg5oz0I9-uXEG91AJuIg,10003 +urllib3/util/url.py,sha256=au9jkUMnVr9Qp_9kg4HfZx9q9ur6yXQ4u5M17In-UKY,14030 +urllib3/util/wait.py,sha256=3MUKRSAUJDB2tgco7qRUskW0zXGAWYvRRE4Q1_6xlLs,5404 diff --git a/venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/WHEEL b/venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/WHEEL new file mode 100644 index 0000000..01b8fc7 --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.36.2) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/top_level.txt b/venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/top_level.txt new file mode 100644 index 0000000..a42590b --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/top_level.txt @@ -0,0 +1 @@ +urllib3 diff --git a/venv/lib/python3.8/site-packages/urllib3/__init__.py b/venv/lib/python3.8/site-packages/urllib3/__init__.py new file mode 100644 index 0000000..fe86b59 --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3/__init__.py @@ -0,0 +1,85 @@ +""" +Python HTTP library with thread-safe connection pooling, file post support, user friendly, and more +""" +from __future__ import absolute_import + +# Set default logging handler to avoid "No handler found" warnings. +import logging +import warnings +from logging import NullHandler + +from . import exceptions +from ._version import __version__ +from .connectionpool import HTTPConnectionPool, HTTPSConnectionPool, connection_from_url +from .filepost import encode_multipart_formdata +from .poolmanager import PoolManager, ProxyManager, proxy_from_url +from .response import HTTPResponse +from .util.request import make_headers +from .util.retry import Retry +from .util.timeout import Timeout +from .util.url import get_host + +__author__ = "Andrey Petrov (andrey.petrov@shazow.net)" +__license__ = "MIT" +__version__ = __version__ + +__all__ = ( + "HTTPConnectionPool", + "HTTPSConnectionPool", + "PoolManager", + "ProxyManager", + "HTTPResponse", + "Retry", + "Timeout", + "add_stderr_logger", + "connection_from_url", + "disable_warnings", + "encode_multipart_formdata", + "get_host", + "make_headers", + "proxy_from_url", +) + +logging.getLogger(__name__).addHandler(NullHandler()) + + +def add_stderr_logger(level=logging.DEBUG): + """ + Helper for quickly adding a StreamHandler to the logger. Useful for + debugging. + + Returns the handler after adding it. + """ + # This method needs to be in this __init__.py to get the __name__ correct + # even if urllib3 is vendored within another package. + logger = logging.getLogger(__name__) + handler = logging.StreamHandler() + handler.setFormatter(logging.Formatter("%(asctime)s %(levelname)s %(message)s")) + logger.addHandler(handler) + logger.setLevel(level) + logger.debug("Added a stderr logging handler to logger: %s", __name__) + return handler + + +# ... Clean up. +del NullHandler + + +# All warning filters *must* be appended unless you're really certain that they +# shouldn't be: otherwise, it's very hard for users to use most Python +# mechanisms to silence them. +# SecurityWarning's always go off by default. +warnings.simplefilter("always", exceptions.SecurityWarning, append=True) +# SubjectAltNameWarning's should go off once per host +warnings.simplefilter("default", exceptions.SubjectAltNameWarning, append=True) +# InsecurePlatformWarning's don't vary between requests, so we keep it default. +warnings.simplefilter("default", exceptions.InsecurePlatformWarning, append=True) +# SNIMissingWarnings should go off only once. +warnings.simplefilter("default", exceptions.SNIMissingWarning, append=True) + + +def disable_warnings(category=exceptions.HTTPWarning): + """ + Helper for quickly disabling all urllib3 warnings. + """ + warnings.simplefilter("ignore", category) diff --git a/venv/lib/python3.8/site-packages/urllib3/_collections.py b/venv/lib/python3.8/site-packages/urllib3/_collections.py new file mode 100644 index 0000000..da9857e --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3/_collections.py @@ -0,0 +1,337 @@ +from __future__ import absolute_import + +try: + from collections.abc import Mapping, MutableMapping +except ImportError: + from collections import Mapping, MutableMapping +try: + from threading import RLock +except ImportError: # Platform-specific: No threads available + + class RLock: + def __enter__(self): + pass + + def __exit__(self, exc_type, exc_value, traceback): + pass + + +from collections import OrderedDict + +from .exceptions import InvalidHeader +from .packages import six +from .packages.six import iterkeys, itervalues + +__all__ = ["RecentlyUsedContainer", "HTTPHeaderDict"] + + +_Null = object() + + +class RecentlyUsedContainer(MutableMapping): + """ + Provides a thread-safe dict-like container which maintains up to + ``maxsize`` keys while throwing away the least-recently-used keys beyond + ``maxsize``. + + :param maxsize: + Maximum number of recent elements to retain. + + :param dispose_func: + Every time an item is evicted from the container, + ``dispose_func(value)`` is called. Callback which will get called + """ + + ContainerCls = OrderedDict + + def __init__(self, maxsize=10, dispose_func=None): + self._maxsize = maxsize + self.dispose_func = dispose_func + + self._container = self.ContainerCls() + self.lock = RLock() + + def __getitem__(self, key): + # Re-insert the item, moving it to the end of the eviction line. + with self.lock: + item = self._container.pop(key) + self._container[key] = item + return item + + def __setitem__(self, key, value): + evicted_value = _Null + with self.lock: + # Possibly evict the existing value of 'key' + evicted_value = self._container.get(key, _Null) + self._container[key] = value + + # If we didn't evict an existing value, we might have to evict the + # least recently used item from the beginning of the container. + if len(self._container) > self._maxsize: + _key, evicted_value = self._container.popitem(last=False) + + if self.dispose_func and evicted_value is not _Null: + self.dispose_func(evicted_value) + + def __delitem__(self, key): + with self.lock: + value = self._container.pop(key) + + if self.dispose_func: + self.dispose_func(value) + + def __len__(self): + with self.lock: + return len(self._container) + + def __iter__(self): + raise NotImplementedError( + "Iteration over this class is unlikely to be threadsafe." + ) + + def clear(self): + with self.lock: + # Copy pointers to all values, then wipe the mapping + values = list(itervalues(self._container)) + self._container.clear() + + if self.dispose_func: + for value in values: + self.dispose_func(value) + + def keys(self): + with self.lock: + return list(iterkeys(self._container)) + + +class HTTPHeaderDict(MutableMapping): + """ + :param headers: + An iterable of field-value pairs. Must not contain multiple field names + when compared case-insensitively. + + :param kwargs: + Additional field-value pairs to pass in to ``dict.update``. + + A ``dict`` like container for storing HTTP Headers. + + Field names are stored and compared case-insensitively in compliance with + RFC 7230. Iteration provides the first case-sensitive key seen for each + case-insensitive pair. + + Using ``__setitem__`` syntax overwrites fields that compare equal + case-insensitively in order to maintain ``dict``'s api. For fields that + compare equal, instead create a new ``HTTPHeaderDict`` and use ``.add`` + in a loop. + + If multiple fields that are equal case-insensitively are passed to the + constructor or ``.update``, the behavior is undefined and some will be + lost. + + >>> headers = HTTPHeaderDict() + >>> headers.add('Set-Cookie', 'foo=bar') + >>> headers.add('set-cookie', 'baz=quxx') + >>> headers['content-length'] = '7' + >>> headers['SET-cookie'] + 'foo=bar, baz=quxx' + >>> headers['Content-Length'] + '7' + """ + + def __init__(self, headers=None, **kwargs): + super(HTTPHeaderDict, self).__init__() + self._container = OrderedDict() + if headers is not None: + if isinstance(headers, HTTPHeaderDict): + self._copy_from(headers) + else: + self.extend(headers) + if kwargs: + self.extend(kwargs) + + def __setitem__(self, key, val): + self._container[key.lower()] = [key, val] + return self._container[key.lower()] + + def __getitem__(self, key): + val = self._container[key.lower()] + return ", ".join(val[1:]) + + def __delitem__(self, key): + del self._container[key.lower()] + + def __contains__(self, key): + return key.lower() in self._container + + def __eq__(self, other): + if not isinstance(other, Mapping) and not hasattr(other, "keys"): + return False + if not isinstance(other, type(self)): + other = type(self)(other) + return dict((k.lower(), v) for k, v in self.itermerged()) == dict( + (k.lower(), v) for k, v in other.itermerged() + ) + + def __ne__(self, other): + return not self.__eq__(other) + + if six.PY2: # Python 2 + iterkeys = MutableMapping.iterkeys + itervalues = MutableMapping.itervalues + + __marker = object() + + def __len__(self): + return len(self._container) + + def __iter__(self): + # Only provide the originally cased names + for vals in self._container.values(): + yield vals[0] + + def pop(self, key, default=__marker): + """D.pop(k[,d]) -> v, remove specified key and return the corresponding value. + If key is not found, d is returned if given, otherwise KeyError is raised. + """ + # Using the MutableMapping function directly fails due to the private marker. + # Using ordinary dict.pop would expose the internal structures. + # So let's reinvent the wheel. + try: + value = self[key] + except KeyError: + if default is self.__marker: + raise + return default + else: + del self[key] + return value + + def discard(self, key): + try: + del self[key] + except KeyError: + pass + + def add(self, key, val): + """Adds a (name, value) pair, doesn't overwrite the value if it already + exists. + + >>> headers = HTTPHeaderDict(foo='bar') + >>> headers.add('Foo', 'baz') + >>> headers['foo'] + 'bar, baz' + """ + key_lower = key.lower() + new_vals = [key, val] + # Keep the common case aka no item present as fast as possible + vals = self._container.setdefault(key_lower, new_vals) + if new_vals is not vals: + vals.append(val) + + def extend(self, *args, **kwargs): + """Generic import function for any type of header-like object. + Adapted version of MutableMapping.update in order to insert items + with self.add instead of self.__setitem__ + """ + if len(args) > 1: + raise TypeError( + "extend() takes at most 1 positional " + "arguments ({0} given)".format(len(args)) + ) + other = args[0] if len(args) >= 1 else () + + if isinstance(other, HTTPHeaderDict): + for key, val in other.iteritems(): + self.add(key, val) + elif isinstance(other, Mapping): + for key in other: + self.add(key, other[key]) + elif hasattr(other, "keys"): + for key in other.keys(): + self.add(key, other[key]) + else: + for key, value in other: + self.add(key, value) + + for key, value in kwargs.items(): + self.add(key, value) + + def getlist(self, key, default=__marker): + """Returns a list of all the values for the named field. Returns an + empty list if the key doesn't exist.""" + try: + vals = self._container[key.lower()] + except KeyError: + if default is self.__marker: + return [] + return default + else: + return vals[1:] + + # Backwards compatibility for httplib + getheaders = getlist + getallmatchingheaders = getlist + iget = getlist + + # Backwards compatibility for http.cookiejar + get_all = getlist + + def __repr__(self): + return "%s(%s)" % (type(self).__name__, dict(self.itermerged())) + + def _copy_from(self, other): + for key in other: + val = other.getlist(key) + if isinstance(val, list): + # Don't need to convert tuples + val = list(val) + self._container[key.lower()] = [key] + val + + def copy(self): + clone = type(self)() + clone._copy_from(self) + return clone + + def iteritems(self): + """Iterate over all header lines, including duplicate ones.""" + for key in self: + vals = self._container[key.lower()] + for val in vals[1:]: + yield vals[0], val + + def itermerged(self): + """Iterate over all headers, merging duplicate ones together.""" + for key in self: + val = self._container[key.lower()] + yield val[0], ", ".join(val[1:]) + + def items(self): + return list(self.iteritems()) + + @classmethod + def from_httplib(cls, message): # Python 2 + """Read headers from a Python 2 httplib message object.""" + # python2.7 does not expose a proper API for exporting multiheaders + # efficiently. This function re-reads raw lines from the message + # object and extracts the multiheaders properly. + obs_fold_continued_leaders = (" ", "\t") + headers = [] + + for line in message.headers: + if line.startswith(obs_fold_continued_leaders): + if not headers: + # We received a header line that starts with OWS as described + # in RFC-7230 S3.2.4. This indicates a multiline header, but + # there exists no previous header to which we can attach it. + raise InvalidHeader( + "Header continuation with no previous header: %s" % line + ) + else: + key, value = headers[-1] + headers[-1] = (key, value + " " + line.strip()) + continue + + key, value = line.split(":", 1) + headers.append((key, value.strip())) + + return cls(headers) diff --git a/venv/lib/python3.8/site-packages/urllib3/_version.py b/venv/lib/python3.8/site-packages/urllib3/_version.py new file mode 100644 index 0000000..e8ebee9 --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3/_version.py @@ -0,0 +1,2 @@ +# This file is protected via CODEOWNERS +__version__ = "1.26.6" diff --git a/venv/lib/python3.8/site-packages/urllib3/connection.py b/venv/lib/python3.8/site-packages/urllib3/connection.py new file mode 100644 index 0000000..4c99665 --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3/connection.py @@ -0,0 +1,539 @@ +from __future__ import absolute_import + +import datetime +import logging +import os +import re +import socket +import warnings +from socket import error as SocketError +from socket import timeout as SocketTimeout + +from .packages import six +from .packages.six.moves.http_client import HTTPConnection as _HTTPConnection +from .packages.six.moves.http_client import HTTPException # noqa: F401 +from .util.proxy import create_proxy_ssl_context + +try: # Compiled with SSL? + import ssl + + BaseSSLError = ssl.SSLError +except (ImportError, AttributeError): # Platform-specific: No SSL. + ssl = None + + class BaseSSLError(BaseException): + pass + + +try: + # Python 3: not a no-op, we're adding this to the namespace so it can be imported. + ConnectionError = ConnectionError +except NameError: + # Python 2 + class ConnectionError(Exception): + pass + + +try: # Python 3: + # Not a no-op, we're adding this to the namespace so it can be imported. + BrokenPipeError = BrokenPipeError +except NameError: # Python 2: + + class BrokenPipeError(Exception): + pass + + +from ._collections import HTTPHeaderDict # noqa (historical, removed in v2) +from ._version import __version__ +from .exceptions import ( + ConnectTimeoutError, + NewConnectionError, + SubjectAltNameWarning, + SystemTimeWarning, +) +from .packages.ssl_match_hostname import CertificateError, match_hostname +from .util import SKIP_HEADER, SKIPPABLE_HEADERS, connection +from .util.ssl_ import ( + assert_fingerprint, + create_urllib3_context, + resolve_cert_reqs, + resolve_ssl_version, + ssl_wrap_socket, +) + +log = logging.getLogger(__name__) + +port_by_scheme = {"http": 80, "https": 443} + +# When it comes time to update this value as a part of regular maintenance +# (ie test_recent_date is failing) update it to ~6 months before the current date. +RECENT_DATE = datetime.date(2020, 7, 1) + +_CONTAINS_CONTROL_CHAR_RE = re.compile(r"[^-!#$%&'*+.^_`|~0-9a-zA-Z]") + + +class HTTPConnection(_HTTPConnection, object): + """ + Based on :class:`http.client.HTTPConnection` but provides an extra constructor + backwards-compatibility layer between older and newer Pythons. + + Additional keyword parameters are used to configure attributes of the connection. + Accepted parameters include: + + - ``strict``: See the documentation on :class:`urllib3.connectionpool.HTTPConnectionPool` + - ``source_address``: Set the source address for the current connection. + - ``socket_options``: Set specific options on the underlying socket. If not specified, then + defaults are loaded from ``HTTPConnection.default_socket_options`` which includes disabling + Nagle's algorithm (sets TCP_NODELAY to 1) unless the connection is behind a proxy. + + For example, if you wish to enable TCP Keep Alive in addition to the defaults, + you might pass: + + .. code-block:: python + + HTTPConnection.default_socket_options + [ + (socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1), + ] + + Or you may want to disable the defaults by passing an empty list (e.g., ``[]``). + """ + + default_port = port_by_scheme["http"] + + #: Disable Nagle's algorithm by default. + #: ``[(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)]`` + default_socket_options = [(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)] + + #: Whether this connection verifies the host's certificate. + is_verified = False + + def __init__(self, *args, **kw): + if not six.PY2: + kw.pop("strict", None) + + # Pre-set source_address. + self.source_address = kw.get("source_address") + + #: The socket options provided by the user. If no options are + #: provided, we use the default options. + self.socket_options = kw.pop("socket_options", self.default_socket_options) + + # Proxy options provided by the user. + self.proxy = kw.pop("proxy", None) + self.proxy_config = kw.pop("proxy_config", None) + + _HTTPConnection.__init__(self, *args, **kw) + + @property + def host(self): + """ + Getter method to remove any trailing dots that indicate the hostname is an FQDN. + + In general, SSL certificates don't include the trailing dot indicating a + fully-qualified domain name, and thus, they don't validate properly when + checked against a domain name that includes the dot. In addition, some + servers may not expect to receive the trailing dot when provided. + + However, the hostname with trailing dot is critical to DNS resolution; doing a + lookup with the trailing dot will properly only resolve the appropriate FQDN, + whereas a lookup without a trailing dot will search the system's search domain + list. Thus, it's important to keep the original host around for use only in + those cases where it's appropriate (i.e., when doing DNS lookup to establish the + actual TCP connection across which we're going to send HTTP requests). + """ + return self._dns_host.rstrip(".") + + @host.setter + def host(self, value): + """ + Setter for the `host` property. + + We assume that only urllib3 uses the _dns_host attribute; httplib itself + only uses `host`, and it seems reasonable that other libraries follow suit. + """ + self._dns_host = value + + def _new_conn(self): + """Establish a socket connection and set nodelay settings on it. + + :return: New socket connection. + """ + extra_kw = {} + if self.source_address: + extra_kw["source_address"] = self.source_address + + if self.socket_options: + extra_kw["socket_options"] = self.socket_options + + try: + conn = connection.create_connection( + (self._dns_host, self.port), self.timeout, **extra_kw + ) + + except SocketTimeout: + raise ConnectTimeoutError( + self, + "Connection to %s timed out. (connect timeout=%s)" + % (self.host, self.timeout), + ) + + except SocketError as e: + raise NewConnectionError( + self, "Failed to establish a new connection: %s" % e + ) + + return conn + + def _is_using_tunnel(self): + # Google App Engine's httplib does not define _tunnel_host + return getattr(self, "_tunnel_host", None) + + def _prepare_conn(self, conn): + self.sock = conn + if self._is_using_tunnel(): + # TODO: Fix tunnel so it doesn't depend on self.sock state. + self._tunnel() + # Mark this connection as not reusable + self.auto_open = 0 + + def connect(self): + conn = self._new_conn() + self._prepare_conn(conn) + + def putrequest(self, method, url, *args, **kwargs): + """ """ + # Empty docstring because the indentation of CPython's implementation + # is broken but we don't want this method in our documentation. + match = _CONTAINS_CONTROL_CHAR_RE.search(method) + if match: + raise ValueError( + "Method cannot contain non-token characters %r (found at least %r)" + % (method, match.group()) + ) + + return _HTTPConnection.putrequest(self, method, url, *args, **kwargs) + + def putheader(self, header, *values): + """ """ + if not any(isinstance(v, str) and v == SKIP_HEADER for v in values): + _HTTPConnection.putheader(self, header, *values) + elif six.ensure_str(header.lower()) not in SKIPPABLE_HEADERS: + raise ValueError( + "urllib3.util.SKIP_HEADER only supports '%s'" + % ("', '".join(map(str.title, sorted(SKIPPABLE_HEADERS))),) + ) + + def request(self, method, url, body=None, headers=None): + if headers is None: + headers = {} + else: + # Avoid modifying the headers passed into .request() + headers = headers.copy() + if "user-agent" not in (six.ensure_str(k.lower()) for k in headers): + headers["User-Agent"] = _get_default_user_agent() + super(HTTPConnection, self).request(method, url, body=body, headers=headers) + + def request_chunked(self, method, url, body=None, headers=None): + """ + Alternative to the common request method, which sends the + body with chunked encoding and not as one block + """ + headers = headers or {} + header_keys = set([six.ensure_str(k.lower()) for k in headers]) + skip_accept_encoding = "accept-encoding" in header_keys + skip_host = "host" in header_keys + self.putrequest( + method, url, skip_accept_encoding=skip_accept_encoding, skip_host=skip_host + ) + if "user-agent" not in header_keys: + self.putheader("User-Agent", _get_default_user_agent()) + for header, value in headers.items(): + self.putheader(header, value) + if "transfer-encoding" not in header_keys: + self.putheader("Transfer-Encoding", "chunked") + self.endheaders() + + if body is not None: + stringish_types = six.string_types + (bytes,) + if isinstance(body, stringish_types): + body = (body,) + for chunk in body: + if not chunk: + continue + if not isinstance(chunk, bytes): + chunk = chunk.encode("utf8") + len_str = hex(len(chunk))[2:] + to_send = bytearray(len_str.encode()) + to_send += b"\r\n" + to_send += chunk + to_send += b"\r\n" + self.send(to_send) + + # After the if clause, to always have a closed body + self.send(b"0\r\n\r\n") + + +class HTTPSConnection(HTTPConnection): + """ + Many of the parameters to this constructor are passed to the underlying SSL + socket by means of :py:func:`urllib3.util.ssl_wrap_socket`. + """ + + default_port = port_by_scheme["https"] + + cert_reqs = None + ca_certs = None + ca_cert_dir = None + ca_cert_data = None + ssl_version = None + assert_fingerprint = None + tls_in_tls_required = False + + def __init__( + self, + host, + port=None, + key_file=None, + cert_file=None, + key_password=None, + strict=None, + timeout=socket._GLOBAL_DEFAULT_TIMEOUT, + ssl_context=None, + server_hostname=None, + **kw + ): + + HTTPConnection.__init__(self, host, port, strict=strict, timeout=timeout, **kw) + + self.key_file = key_file + self.cert_file = cert_file + self.key_password = key_password + self.ssl_context = ssl_context + self.server_hostname = server_hostname + + # Required property for Google AppEngine 1.9.0 which otherwise causes + # HTTPS requests to go out as HTTP. (See Issue #356) + self._protocol = "https" + + def set_cert( + self, + key_file=None, + cert_file=None, + cert_reqs=None, + key_password=None, + ca_certs=None, + assert_hostname=None, + assert_fingerprint=None, + ca_cert_dir=None, + ca_cert_data=None, + ): + """ + This method should only be called once, before the connection is used. + """ + # If cert_reqs is not provided we'll assume CERT_REQUIRED unless we also + # have an SSLContext object in which case we'll use its verify_mode. + if cert_reqs is None: + if self.ssl_context is not None: + cert_reqs = self.ssl_context.verify_mode + else: + cert_reqs = resolve_cert_reqs(None) + + self.key_file = key_file + self.cert_file = cert_file + self.cert_reqs = cert_reqs + self.key_password = key_password + self.assert_hostname = assert_hostname + self.assert_fingerprint = assert_fingerprint + self.ca_certs = ca_certs and os.path.expanduser(ca_certs) + self.ca_cert_dir = ca_cert_dir and os.path.expanduser(ca_cert_dir) + self.ca_cert_data = ca_cert_data + + def connect(self): + # Add certificate verification + conn = self._new_conn() + hostname = self.host + tls_in_tls = False + + if self._is_using_tunnel(): + if self.tls_in_tls_required: + conn = self._connect_tls_proxy(hostname, conn) + tls_in_tls = True + + self.sock = conn + + # Calls self._set_hostport(), so self.host is + # self._tunnel_host below. + self._tunnel() + # Mark this connection as not reusable + self.auto_open = 0 + + # Override the host with the one we're requesting data from. + hostname = self._tunnel_host + + server_hostname = hostname + if self.server_hostname is not None: + server_hostname = self.server_hostname + + is_time_off = datetime.date.today() < RECENT_DATE + if is_time_off: + warnings.warn( + ( + "System time is way off (before {0}). This will probably " + "lead to SSL verification errors" + ).format(RECENT_DATE), + SystemTimeWarning, + ) + + # Wrap socket using verification with the root certs in + # trusted_root_certs + default_ssl_context = False + if self.ssl_context is None: + default_ssl_context = True + self.ssl_context = create_urllib3_context( + ssl_version=resolve_ssl_version(self.ssl_version), + cert_reqs=resolve_cert_reqs(self.cert_reqs), + ) + + context = self.ssl_context + context.verify_mode = resolve_cert_reqs(self.cert_reqs) + + # Try to load OS default certs if none are given. + # Works well on Windows (requires Python3.4+) + if ( + not self.ca_certs + and not self.ca_cert_dir + and not self.ca_cert_data + and default_ssl_context + and hasattr(context, "load_default_certs") + ): + context.load_default_certs() + + self.sock = ssl_wrap_socket( + sock=conn, + keyfile=self.key_file, + certfile=self.cert_file, + key_password=self.key_password, + ca_certs=self.ca_certs, + ca_cert_dir=self.ca_cert_dir, + ca_cert_data=self.ca_cert_data, + server_hostname=server_hostname, + ssl_context=context, + tls_in_tls=tls_in_tls, + ) + + # If we're using all defaults and the connection + # is TLSv1 or TLSv1.1 we throw a DeprecationWarning + # for the host. + if ( + default_ssl_context + and self.ssl_version is None + and hasattr(self.sock, "version") + and self.sock.version() in {"TLSv1", "TLSv1.1"} + ): + warnings.warn( + "Negotiating TLSv1/TLSv1.1 by default is deprecated " + "and will be disabled in urllib3 v2.0.0. Connecting to " + "'%s' with '%s' can be enabled by explicitly opting-in " + "with 'ssl_version'" % (self.host, self.sock.version()), + DeprecationWarning, + ) + + if self.assert_fingerprint: + assert_fingerprint( + self.sock.getpeercert(binary_form=True), self.assert_fingerprint + ) + elif ( + context.verify_mode != ssl.CERT_NONE + and not getattr(context, "check_hostname", False) + and self.assert_hostname is not False + ): + # While urllib3 attempts to always turn off hostname matching from + # the TLS library, this cannot always be done. So we check whether + # the TLS Library still thinks it's matching hostnames. + cert = self.sock.getpeercert() + if not cert.get("subjectAltName", ()): + warnings.warn( + ( + "Certificate for {0} has no `subjectAltName`, falling back to check for a " + "`commonName` for now. This feature is being removed by major browsers and " + "deprecated by RFC 2818. (See https://github.com/urllib3/urllib3/issues/497 " + "for details.)".format(hostname) + ), + SubjectAltNameWarning, + ) + _match_hostname(cert, self.assert_hostname or server_hostname) + + self.is_verified = ( + context.verify_mode == ssl.CERT_REQUIRED + or self.assert_fingerprint is not None + ) + + def _connect_tls_proxy(self, hostname, conn): + """ + Establish a TLS connection to the proxy using the provided SSL context. + """ + proxy_config = self.proxy_config + ssl_context = proxy_config.ssl_context + if ssl_context: + # If the user provided a proxy context, we assume CA and client + # certificates have already been set + return ssl_wrap_socket( + sock=conn, + server_hostname=hostname, + ssl_context=ssl_context, + ) + + ssl_context = create_proxy_ssl_context( + self.ssl_version, + self.cert_reqs, + self.ca_certs, + self.ca_cert_dir, + self.ca_cert_data, + ) + # By default urllib3's SSLContext disables `check_hostname` and uses + # a custom check. For proxies we're good with relying on the default + # verification. + ssl_context.check_hostname = True + + # If no cert was provided, use only the default options for server + # certificate validation + return ssl_wrap_socket( + sock=conn, + ca_certs=self.ca_certs, + ca_cert_dir=self.ca_cert_dir, + ca_cert_data=self.ca_cert_data, + server_hostname=hostname, + ssl_context=ssl_context, + ) + + +def _match_hostname(cert, asserted_hostname): + try: + match_hostname(cert, asserted_hostname) + except CertificateError as e: + log.warning( + "Certificate did not match expected hostname: %s. Certificate: %s", + asserted_hostname, + cert, + ) + # Add cert to exception and reraise so client code can inspect + # the cert when catching the exception, if they want to + e._peer_cert = cert + raise + + +def _get_default_user_agent(): + return "python-urllib3/%s" % __version__ + + +class DummyConnection(object): + """Used to detect a failed ConnectionCls import.""" + + pass + + +if not ssl: + HTTPSConnection = DummyConnection # noqa: F811 + + +VerifiedHTTPSConnection = HTTPSConnection diff --git a/venv/lib/python3.8/site-packages/urllib3/connectionpool.py b/venv/lib/python3.8/site-packages/urllib3/connectionpool.py new file mode 100644 index 0000000..459bbe0 --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3/connectionpool.py @@ -0,0 +1,1067 @@ +from __future__ import absolute_import + +import errno +import logging +import socket +import sys +import warnings +from socket import error as SocketError +from socket import timeout as SocketTimeout + +from .connection import ( + BaseSSLError, + BrokenPipeError, + DummyConnection, + HTTPConnection, + HTTPException, + HTTPSConnection, + VerifiedHTTPSConnection, + port_by_scheme, +) +from .exceptions import ( + ClosedPoolError, + EmptyPoolError, + HeaderParsingError, + HostChangedError, + InsecureRequestWarning, + LocationValueError, + MaxRetryError, + NewConnectionError, + ProtocolError, + ProxyError, + ReadTimeoutError, + SSLError, + TimeoutError, +) +from .packages import six +from .packages.six.moves import queue +from .packages.ssl_match_hostname import CertificateError +from .request import RequestMethods +from .response import HTTPResponse +from .util.connection import is_connection_dropped +from .util.proxy import connection_requires_http_tunnel +from .util.queue import LifoQueue +from .util.request import set_file_position +from .util.response import assert_header_parsing +from .util.retry import Retry +from .util.timeout import Timeout +from .util.url import Url, _encode_target +from .util.url import _normalize_host as normalize_host +from .util.url import get_host, parse_url + +xrange = six.moves.xrange + +log = logging.getLogger(__name__) + +_Default = object() + + +# Pool objects +class ConnectionPool(object): + """ + Base class for all connection pools, such as + :class:`.HTTPConnectionPool` and :class:`.HTTPSConnectionPool`. + + .. note:: + ConnectionPool.urlopen() does not normalize or percent-encode target URIs + which is useful if your target server doesn't support percent-encoded + target URIs. + """ + + scheme = None + QueueCls = LifoQueue + + def __init__(self, host, port=None): + if not host: + raise LocationValueError("No host specified.") + + self.host = _normalize_host(host, scheme=self.scheme) + self._proxy_host = host.lower() + self.port = port + + def __str__(self): + return "%s(host=%r, port=%r)" % (type(self).__name__, self.host, self.port) + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.close() + # Return False to re-raise any potential exceptions + return False + + def close(self): + """ + Close all pooled connections and disable the pool. + """ + pass + + +# This is taken from http://hg.python.org/cpython/file/7aaba721ebc0/Lib/socket.py#l252 +_blocking_errnos = {errno.EAGAIN, errno.EWOULDBLOCK} + + +class HTTPConnectionPool(ConnectionPool, RequestMethods): + """ + Thread-safe connection pool for one host. + + :param host: + Host used for this HTTP Connection (e.g. "localhost"), passed into + :class:`http.client.HTTPConnection`. + + :param port: + Port used for this HTTP Connection (None is equivalent to 80), passed + into :class:`http.client.HTTPConnection`. + + :param strict: + Causes BadStatusLine to be raised if the status line can't be parsed + as a valid HTTP/1.0 or 1.1 status line, passed into + :class:`http.client.HTTPConnection`. + + .. note:: + Only works in Python 2. This parameter is ignored in Python 3. + + :param timeout: + Socket timeout in seconds for each individual connection. This can + be a float or integer, which sets the timeout for the HTTP request, + or an instance of :class:`urllib3.util.Timeout` which gives you more + fine-grained control over request timeouts. After the constructor has + been parsed, this is always a `urllib3.util.Timeout` object. + + :param maxsize: + Number of connections to save that can be reused. More than 1 is useful + in multithreaded situations. If ``block`` is set to False, more + connections will be created but they will not be saved once they've + been used. + + :param block: + If set to True, no more than ``maxsize`` connections will be used at + a time. When no free connections are available, the call will block + until a connection has been released. This is a useful side effect for + particular multithreaded situations where one does not want to use more + than maxsize connections per host to prevent flooding. + + :param headers: + Headers to include with all requests, unless other headers are given + explicitly. + + :param retries: + Retry configuration to use by default with requests in this pool. + + :param _proxy: + Parsed proxy URL, should not be used directly, instead, see + :class:`urllib3.ProxyManager` + + :param _proxy_headers: + A dictionary with proxy headers, should not be used directly, + instead, see :class:`urllib3.ProxyManager` + + :param \\**conn_kw: + Additional parameters are used to create fresh :class:`urllib3.connection.HTTPConnection`, + :class:`urllib3.connection.HTTPSConnection` instances. + """ + + scheme = "http" + ConnectionCls = HTTPConnection + ResponseCls = HTTPResponse + + def __init__( + self, + host, + port=None, + strict=False, + timeout=Timeout.DEFAULT_TIMEOUT, + maxsize=1, + block=False, + headers=None, + retries=None, + _proxy=None, + _proxy_headers=None, + _proxy_config=None, + **conn_kw + ): + ConnectionPool.__init__(self, host, port) + RequestMethods.__init__(self, headers) + + self.strict = strict + + if not isinstance(timeout, Timeout): + timeout = Timeout.from_float(timeout) + + if retries is None: + retries = Retry.DEFAULT + + self.timeout = timeout + self.retries = retries + + self.pool = self.QueueCls(maxsize) + self.block = block + + self.proxy = _proxy + self.proxy_headers = _proxy_headers or {} + self.proxy_config = _proxy_config + + # Fill the queue up so that doing get() on it will block properly + for _ in xrange(maxsize): + self.pool.put(None) + + # These are mostly for testing and debugging purposes. + self.num_connections = 0 + self.num_requests = 0 + self.conn_kw = conn_kw + + if self.proxy: + # Enable Nagle's algorithm for proxies, to avoid packet fragmentation. + # We cannot know if the user has added default socket options, so we cannot replace the + # list. + self.conn_kw.setdefault("socket_options", []) + + self.conn_kw["proxy"] = self.proxy + self.conn_kw["proxy_config"] = self.proxy_config + + def _new_conn(self): + """ + Return a fresh :class:`HTTPConnection`. + """ + self.num_connections += 1 + log.debug( + "Starting new HTTP connection (%d): %s:%s", + self.num_connections, + self.host, + self.port or "80", + ) + + conn = self.ConnectionCls( + host=self.host, + port=self.port, + timeout=self.timeout.connect_timeout, + strict=self.strict, + **self.conn_kw + ) + return conn + + def _get_conn(self, timeout=None): + """ + Get a connection. Will return a pooled connection if one is available. + + If no connections are available and :prop:`.block` is ``False``, then a + fresh connection is returned. + + :param timeout: + Seconds to wait before giving up and raising + :class:`urllib3.exceptions.EmptyPoolError` if the pool is empty and + :prop:`.block` is ``True``. + """ + conn = None + try: + conn = self.pool.get(block=self.block, timeout=timeout) + + except AttributeError: # self.pool is None + raise ClosedPoolError(self, "Pool is closed.") + + except queue.Empty: + if self.block: + raise EmptyPoolError( + self, + "Pool reached maximum size and no more connections are allowed.", + ) + pass # Oh well, we'll create a new connection then + + # If this is a persistent connection, check if it got disconnected + if conn and is_connection_dropped(conn): + log.debug("Resetting dropped connection: %s", self.host) + conn.close() + if getattr(conn, "auto_open", 1) == 0: + # This is a proxied connection that has been mutated by + # http.client._tunnel() and cannot be reused (since it would + # attempt to bypass the proxy) + conn = None + + return conn or self._new_conn() + + def _put_conn(self, conn): + """ + Put a connection back into the pool. + + :param conn: + Connection object for the current host and port as returned by + :meth:`._new_conn` or :meth:`._get_conn`. + + If the pool is already full, the connection is closed and discarded + because we exceeded maxsize. If connections are discarded frequently, + then maxsize should be increased. + + If the pool is closed, then the connection will be closed and discarded. + """ + try: + self.pool.put(conn, block=False) + return # Everything is dandy, done. + except AttributeError: + # self.pool is None. + pass + except queue.Full: + # This should never happen if self.block == True + log.warning("Connection pool is full, discarding connection: %s", self.host) + + # Connection never got put back into the pool, close it. + if conn: + conn.close() + + def _validate_conn(self, conn): + """ + Called right before a request is made, after the socket is created. + """ + pass + + def _prepare_proxy(self, conn): + # Nothing to do for HTTP connections. + pass + + def _get_timeout(self, timeout): + """Helper that always returns a :class:`urllib3.util.Timeout`""" + if timeout is _Default: + return self.timeout.clone() + + if isinstance(timeout, Timeout): + return timeout.clone() + else: + # User passed us an int/float. This is for backwards compatibility, + # can be removed later + return Timeout.from_float(timeout) + + def _raise_timeout(self, err, url, timeout_value): + """Is the error actually a timeout? Will raise a ReadTimeout or pass""" + + if isinstance(err, SocketTimeout): + raise ReadTimeoutError( + self, url, "Read timed out. (read timeout=%s)" % timeout_value + ) + + # See the above comment about EAGAIN in Python 3. In Python 2 we have + # to specifically catch it and throw the timeout error + if hasattr(err, "errno") and err.errno in _blocking_errnos: + raise ReadTimeoutError( + self, url, "Read timed out. (read timeout=%s)" % timeout_value + ) + + # Catch possible read timeouts thrown as SSL errors. If not the + # case, rethrow the original. We need to do this because of: + # http://bugs.python.org/issue10272 + if "timed out" in str(err) or "did not complete (read)" in str( + err + ): # Python < 2.7.4 + raise ReadTimeoutError( + self, url, "Read timed out. (read timeout=%s)" % timeout_value + ) + + def _make_request( + self, conn, method, url, timeout=_Default, chunked=False, **httplib_request_kw + ): + """ + Perform a request on a given urllib connection object taken from our + pool. + + :param conn: + a connection from one of our connection pools + + :param timeout: + Socket timeout in seconds for the request. This can be a + float or integer, which will set the same timeout value for + the socket connect and the socket read, or an instance of + :class:`urllib3.util.Timeout`, which gives you more fine-grained + control over your timeouts. + """ + self.num_requests += 1 + + timeout_obj = self._get_timeout(timeout) + timeout_obj.start_connect() + conn.timeout = timeout_obj.connect_timeout + + # Trigger any extra validation we need to do. + try: + self._validate_conn(conn) + except (SocketTimeout, BaseSSLError) as e: + # Py2 raises this as a BaseSSLError, Py3 raises it as socket timeout. + self._raise_timeout(err=e, url=url, timeout_value=conn.timeout) + raise + + # conn.request() calls http.client.*.request, not the method in + # urllib3.request. It also calls makefile (recv) on the socket. + try: + if chunked: + conn.request_chunked(method, url, **httplib_request_kw) + else: + conn.request(method, url, **httplib_request_kw) + + # We are swallowing BrokenPipeError (errno.EPIPE) since the server is + # legitimately able to close the connection after sending a valid response. + # With this behaviour, the received response is still readable. + except BrokenPipeError: + # Python 3 + pass + except IOError as e: + # Python 2 and macOS/Linux + # EPIPE and ESHUTDOWN are BrokenPipeError on Python 2, and EPROTOTYPE is needed on macOS + # https://erickt.github.io/blog/2014/11/19/adventures-in-debugging-a-potential-osx-kernel-bug/ + if e.errno not in { + errno.EPIPE, + errno.ESHUTDOWN, + errno.EPROTOTYPE, + }: + raise + + # Reset the timeout for the recv() on the socket + read_timeout = timeout_obj.read_timeout + + # App Engine doesn't have a sock attr + if getattr(conn, "sock", None): + # In Python 3 socket.py will catch EAGAIN and return None when you + # try and read into the file pointer created by http.client, which + # instead raises a BadStatusLine exception. Instead of catching + # the exception and assuming all BadStatusLine exceptions are read + # timeouts, check for a zero timeout before making the request. + if read_timeout == 0: + raise ReadTimeoutError( + self, url, "Read timed out. (read timeout=%s)" % read_timeout + ) + if read_timeout is Timeout.DEFAULT_TIMEOUT: + conn.sock.settimeout(socket.getdefaulttimeout()) + else: # None or a value + conn.sock.settimeout(read_timeout) + + # Receive the response from the server + try: + try: + # Python 2.7, use buffering of HTTP responses + httplib_response = conn.getresponse(buffering=True) + except TypeError: + # Python 3 + try: + httplib_response = conn.getresponse() + except BaseException as e: + # Remove the TypeError from the exception chain in + # Python 3 (including for exceptions like SystemExit). + # Otherwise it looks like a bug in the code. + six.raise_from(e, None) + except (SocketTimeout, BaseSSLError, SocketError) as e: + self._raise_timeout(err=e, url=url, timeout_value=read_timeout) + raise + + # AppEngine doesn't have a version attr. + http_version = getattr(conn, "_http_vsn_str", "HTTP/?") + log.debug( + '%s://%s:%s "%s %s %s" %s %s', + self.scheme, + self.host, + self.port, + method, + url, + http_version, + httplib_response.status, + httplib_response.length, + ) + + try: + assert_header_parsing(httplib_response.msg) + except (HeaderParsingError, TypeError) as hpe: # Platform-specific: Python 3 + log.warning( + "Failed to parse headers (url=%s): %s", + self._absolute_url(url), + hpe, + exc_info=True, + ) + + return httplib_response + + def _absolute_url(self, path): + return Url(scheme=self.scheme, host=self.host, port=self.port, path=path).url + + def close(self): + """ + Close all pooled connections and disable the pool. + """ + if self.pool is None: + return + # Disable access to the pool + old_pool, self.pool = self.pool, None + + try: + while True: + conn = old_pool.get(block=False) + if conn: + conn.close() + + except queue.Empty: + pass # Done. + + def is_same_host(self, url): + """ + Check if the given ``url`` is a member of the same host as this + connection pool. + """ + if url.startswith("/"): + return True + + # TODO: Add optional support for socket.gethostbyname checking. + scheme, host, port = get_host(url) + if host is not None: + host = _normalize_host(host, scheme=scheme) + + # Use explicit default port for comparison when none is given + if self.port and not port: + port = port_by_scheme.get(scheme) + elif not self.port and port == port_by_scheme.get(scheme): + port = None + + return (scheme, host, port) == (self.scheme, self.host, self.port) + + def urlopen( + self, + method, + url, + body=None, + headers=None, + retries=None, + redirect=True, + assert_same_host=True, + timeout=_Default, + pool_timeout=None, + release_conn=None, + chunked=False, + body_pos=None, + **response_kw + ): + """ + Get a connection from the pool and perform an HTTP request. This is the + lowest level call for making a request, so you'll need to specify all + the raw details. + + .. note:: + + More commonly, it's appropriate to use a convenience method provided + by :class:`.RequestMethods`, such as :meth:`request`. + + .. note:: + + `release_conn` will only behave as expected if + `preload_content=False` because we want to make + `preload_content=False` the default behaviour someday soon without + breaking backwards compatibility. + + :param method: + HTTP request method (such as GET, POST, PUT, etc.) + + :param url: + The URL to perform the request on. + + :param body: + Data to send in the request body, either :class:`str`, :class:`bytes`, + an iterable of :class:`str`/:class:`bytes`, or a file-like object. + + :param headers: + Dictionary of custom headers to send, such as User-Agent, + If-None-Match, etc. If None, pool headers are used. If provided, + these headers completely replace any pool-specific headers. + + :param retries: + Configure the number of retries to allow before raising a + :class:`~urllib3.exceptions.MaxRetryError` exception. + + Pass ``None`` to retry until you receive a response. Pass a + :class:`~urllib3.util.retry.Retry` object for fine-grained control + over different types of retries. + Pass an integer number to retry connection errors that many times, + but no other types of errors. Pass zero to never retry. + + If ``False``, then retries are disabled and any exception is raised + immediately. Also, instead of raising a MaxRetryError on redirects, + the redirect response will be returned. + + :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int. + + :param redirect: + If True, automatically handle redirects (status codes 301, 302, + 303, 307, 308). Each redirect counts as a retry. Disabling retries + will disable redirect, too. + + :param assert_same_host: + If ``True``, will make sure that the host of the pool requests is + consistent else will raise HostChangedError. When ``False``, you can + use the pool on an HTTP proxy and request foreign hosts. + + :param timeout: + If specified, overrides the default timeout for this one + request. It may be a float (in seconds) or an instance of + :class:`urllib3.util.Timeout`. + + :param pool_timeout: + If set and the pool is set to block=True, then this method will + block for ``pool_timeout`` seconds and raise EmptyPoolError if no + connection is available within the time period. + + :param release_conn: + If False, then the urlopen call will not release the connection + back into the pool once a response is received (but will release if + you read the entire contents of the response such as when + `preload_content=True`). This is useful if you're not preloading + the response's content immediately. You will need to call + ``r.release_conn()`` on the response ``r`` to return the connection + back into the pool. If None, it takes the value of + ``response_kw.get('preload_content', True)``. + + :param chunked: + If True, urllib3 will send the body using chunked transfer + encoding. Otherwise, urllib3 will send the body using the standard + content-length form. Defaults to False. + + :param int body_pos: + Position to seek to in file-like body in the event of a retry or + redirect. Typically this won't need to be set because urllib3 will + auto-populate the value when needed. + + :param \\**response_kw: + Additional parameters are passed to + :meth:`urllib3.response.HTTPResponse.from_httplib` + """ + + parsed_url = parse_url(url) + destination_scheme = parsed_url.scheme + + if headers is None: + headers = self.headers + + if not isinstance(retries, Retry): + retries = Retry.from_int(retries, redirect=redirect, default=self.retries) + + if release_conn is None: + release_conn = response_kw.get("preload_content", True) + + # Check host + if assert_same_host and not self.is_same_host(url): + raise HostChangedError(self, url, retries) + + # Ensure that the URL we're connecting to is properly encoded + if url.startswith("/"): + url = six.ensure_str(_encode_target(url)) + else: + url = six.ensure_str(parsed_url.url) + + conn = None + + # Track whether `conn` needs to be released before + # returning/raising/recursing. Update this variable if necessary, and + # leave `release_conn` constant throughout the function. That way, if + # the function recurses, the original value of `release_conn` will be + # passed down into the recursive call, and its value will be respected. + # + # See issue #651 [1] for details. + # + # [1] <https://github.com/urllib3/urllib3/issues/651> + release_this_conn = release_conn + + http_tunnel_required = connection_requires_http_tunnel( + self.proxy, self.proxy_config, destination_scheme + ) + + # Merge the proxy headers. Only done when not using HTTP CONNECT. We + # have to copy the headers dict so we can safely change it without those + # changes being reflected in anyone else's copy. + if not http_tunnel_required: + headers = headers.copy() + headers.update(self.proxy_headers) + + # Must keep the exception bound to a separate variable or else Python 3 + # complains about UnboundLocalError. + err = None + + # Keep track of whether we cleanly exited the except block. This + # ensures we do proper cleanup in finally. + clean_exit = False + + # Rewind body position, if needed. Record current position + # for future rewinds in the event of a redirect/retry. + body_pos = set_file_position(body, body_pos) + + try: + # Request a connection from the queue. + timeout_obj = self._get_timeout(timeout) + conn = self._get_conn(timeout=pool_timeout) + + conn.timeout = timeout_obj.connect_timeout + + is_new_proxy_conn = self.proxy is not None and not getattr( + conn, "sock", None + ) + if is_new_proxy_conn and http_tunnel_required: + self._prepare_proxy(conn) + + # Make the request on the httplib connection object. + httplib_response = self._make_request( + conn, + method, + url, + timeout=timeout_obj, + body=body, + headers=headers, + chunked=chunked, + ) + + # If we're going to release the connection in ``finally:``, then + # the response doesn't need to know about the connection. Otherwise + # it will also try to release it and we'll have a double-release + # mess. + response_conn = conn if not release_conn else None + + # Pass method to Response for length checking + response_kw["request_method"] = method + + # Import httplib's response into our own wrapper object + response = self.ResponseCls.from_httplib( + httplib_response, + pool=self, + connection=response_conn, + retries=retries, + **response_kw + ) + + # Everything went great! + clean_exit = True + + except EmptyPoolError: + # Didn't get a connection from the pool, no need to clean up + clean_exit = True + release_this_conn = False + raise + + except ( + TimeoutError, + HTTPException, + SocketError, + ProtocolError, + BaseSSLError, + SSLError, + CertificateError, + ) as e: + # Discard the connection for these exceptions. It will be + # replaced during the next _get_conn() call. + clean_exit = False + if isinstance(e, (BaseSSLError, CertificateError)): + e = SSLError(e) + elif isinstance(e, (SocketError, NewConnectionError)) and self.proxy: + e = ProxyError("Cannot connect to proxy.", e) + elif isinstance(e, (SocketError, HTTPException)): + e = ProtocolError("Connection aborted.", e) + + retries = retries.increment( + method, url, error=e, _pool=self, _stacktrace=sys.exc_info()[2] + ) + retries.sleep() + + # Keep track of the error for the retry warning. + err = e + + finally: + if not clean_exit: + # We hit some kind of exception, handled or otherwise. We need + # to throw the connection away unless explicitly told not to. + # Close the connection, set the variable to None, and make sure + # we put the None back in the pool to avoid leaking it. + conn = conn and conn.close() + release_this_conn = True + + if release_this_conn: + # Put the connection back to be reused. If the connection is + # expired then it will be None, which will get replaced with a + # fresh connection during _get_conn. + self._put_conn(conn) + + if not conn: + # Try again + log.warning( + "Retrying (%r) after connection broken by '%r': %s", retries, err, url + ) + return self.urlopen( + method, + url, + body, + headers, + retries, + redirect, + assert_same_host, + timeout=timeout, + pool_timeout=pool_timeout, + release_conn=release_conn, + chunked=chunked, + body_pos=body_pos, + **response_kw + ) + + # Handle redirect? + redirect_location = redirect and response.get_redirect_location() + if redirect_location: + if response.status == 303: + method = "GET" + + try: + retries = retries.increment(method, url, response=response, _pool=self) + except MaxRetryError: + if retries.raise_on_redirect: + response.drain_conn() + raise + return response + + response.drain_conn() + retries.sleep_for_retry(response) + log.debug("Redirecting %s -> %s", url, redirect_location) + return self.urlopen( + method, + redirect_location, + body, + headers, + retries=retries, + redirect=redirect, + assert_same_host=assert_same_host, + timeout=timeout, + pool_timeout=pool_timeout, + release_conn=release_conn, + chunked=chunked, + body_pos=body_pos, + **response_kw + ) + + # Check if we should retry the HTTP response. + has_retry_after = bool(response.getheader("Retry-After")) + if retries.is_retry(method, response.status, has_retry_after): + try: + retries = retries.increment(method, url, response=response, _pool=self) + except MaxRetryError: + if retries.raise_on_status: + response.drain_conn() + raise + return response + + response.drain_conn() + retries.sleep(response) + log.debug("Retry: %s", url) + return self.urlopen( + method, + url, + body, + headers, + retries=retries, + redirect=redirect, + assert_same_host=assert_same_host, + timeout=timeout, + pool_timeout=pool_timeout, + release_conn=release_conn, + chunked=chunked, + body_pos=body_pos, + **response_kw + ) + + return response + + +class HTTPSConnectionPool(HTTPConnectionPool): + """ + Same as :class:`.HTTPConnectionPool`, but HTTPS. + + :class:`.HTTPSConnection` uses one of ``assert_fingerprint``, + ``assert_hostname`` and ``host`` in this order to verify connections. + If ``assert_hostname`` is False, no verification is done. + + The ``key_file``, ``cert_file``, ``cert_reqs``, ``ca_certs``, + ``ca_cert_dir``, ``ssl_version``, ``key_password`` are only used if :mod:`ssl` + is available and are fed into :meth:`urllib3.util.ssl_wrap_socket` to upgrade + the connection socket into an SSL socket. + """ + + scheme = "https" + ConnectionCls = HTTPSConnection + + def __init__( + self, + host, + port=None, + strict=False, + timeout=Timeout.DEFAULT_TIMEOUT, + maxsize=1, + block=False, + headers=None, + retries=None, + _proxy=None, + _proxy_headers=None, + key_file=None, + cert_file=None, + cert_reqs=None, + key_password=None, + ca_certs=None, + ssl_version=None, + assert_hostname=None, + assert_fingerprint=None, + ca_cert_dir=None, + **conn_kw + ): + + HTTPConnectionPool.__init__( + self, + host, + port, + strict, + timeout, + maxsize, + block, + headers, + retries, + _proxy, + _proxy_headers, + **conn_kw + ) + + self.key_file = key_file + self.cert_file = cert_file + self.cert_reqs = cert_reqs + self.key_password = key_password + self.ca_certs = ca_certs + self.ca_cert_dir = ca_cert_dir + self.ssl_version = ssl_version + self.assert_hostname = assert_hostname + self.assert_fingerprint = assert_fingerprint + + def _prepare_conn(self, conn): + """ + Prepare the ``connection`` for :meth:`urllib3.util.ssl_wrap_socket` + and establish the tunnel if proxy is used. + """ + + if isinstance(conn, VerifiedHTTPSConnection): + conn.set_cert( + key_file=self.key_file, + key_password=self.key_password, + cert_file=self.cert_file, + cert_reqs=self.cert_reqs, + ca_certs=self.ca_certs, + ca_cert_dir=self.ca_cert_dir, + assert_hostname=self.assert_hostname, + assert_fingerprint=self.assert_fingerprint, + ) + conn.ssl_version = self.ssl_version + return conn + + def _prepare_proxy(self, conn): + """ + Establishes a tunnel connection through HTTP CONNECT. + + Tunnel connection is established early because otherwise httplib would + improperly set Host: header to proxy's IP:port. + """ + + conn.set_tunnel(self._proxy_host, self.port, self.proxy_headers) + + if self.proxy.scheme == "https": + conn.tls_in_tls_required = True + + conn.connect() + + def _new_conn(self): + """ + Return a fresh :class:`http.client.HTTPSConnection`. + """ + self.num_connections += 1 + log.debug( + "Starting new HTTPS connection (%d): %s:%s", + self.num_connections, + self.host, + self.port or "443", + ) + + if not self.ConnectionCls or self.ConnectionCls is DummyConnection: + raise SSLError( + "Can't connect to HTTPS URL because the SSL module is not available." + ) + + actual_host = self.host + actual_port = self.port + if self.proxy is not None: + actual_host = self.proxy.host + actual_port = self.proxy.port + + conn = self.ConnectionCls( + host=actual_host, + port=actual_port, + timeout=self.timeout.connect_timeout, + strict=self.strict, + cert_file=self.cert_file, + key_file=self.key_file, + key_password=self.key_password, + **self.conn_kw + ) + + return self._prepare_conn(conn) + + def _validate_conn(self, conn): + """ + Called right before a request is made, after the socket is created. + """ + super(HTTPSConnectionPool, self)._validate_conn(conn) + + # Force connect early to allow us to validate the connection. + if not getattr(conn, "sock", None): # AppEngine might not have `.sock` + conn.connect() + + if not conn.is_verified: + warnings.warn( + ( + "Unverified HTTPS request is being made to host '%s'. " + "Adding certificate verification is strongly advised. See: " + "https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html" + "#ssl-warnings" % conn.host + ), + InsecureRequestWarning, + ) + + +def connection_from_url(url, **kw): + """ + Given a url, return an :class:`.ConnectionPool` instance of its host. + + This is a shortcut for not having to parse out the scheme, host, and port + of the url before creating an :class:`.ConnectionPool` instance. + + :param url: + Absolute URL string that must include the scheme. Port is optional. + + :param \\**kw: + Passes additional parameters to the constructor of the appropriate + :class:`.ConnectionPool`. Useful for specifying things like + timeout, maxsize, headers, etc. + + Example:: + + >>> conn = connection_from_url('http://google.com/') + >>> r = conn.request('GET', '/') + """ + scheme, host, port = get_host(url) + port = port or port_by_scheme.get(scheme, 80) + if scheme == "https": + return HTTPSConnectionPool(host, port=port, **kw) + else: + return HTTPConnectionPool(host, port=port, **kw) + + +def _normalize_host(host, scheme): + """ + Normalize hosts for comparisons and use with sockets. + """ + + host = normalize_host(host, scheme) + + # httplib doesn't like it when we include brackets in IPv6 addresses + # Specifically, if we include brackets but also pass the port then + # httplib crazily doubles up the square brackets on the Host header. + # Instead, we need to make sure we never pass ``None`` as the port. + # However, for backward compatibility reasons we can't actually + # *assert* that. See http://bugs.python.org/issue28539 + if host.startswith("[") and host.endswith("]"): + host = host[1:-1] + return host diff --git a/venv/lib/python3.8/site-packages/urllib3/contrib/__init__.py b/venv/lib/python3.8/site-packages/urllib3/contrib/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.8/site-packages/urllib3/contrib/_appengine_environ.py b/venv/lib/python3.8/site-packages/urllib3/contrib/_appengine_environ.py new file mode 100644 index 0000000..8765b90 --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3/contrib/_appengine_environ.py @@ -0,0 +1,36 @@ +""" +This module provides means to detect the App Engine environment. +""" + +import os + + +def is_appengine(): + return is_local_appengine() or is_prod_appengine() + + +def is_appengine_sandbox(): + """Reports if the app is running in the first generation sandbox. + + The second generation runtimes are technically still in a sandbox, but it + is much less restrictive, so generally you shouldn't need to check for it. + see https://cloud.google.com/appengine/docs/standard/runtimes + """ + return is_appengine() and os.environ["APPENGINE_RUNTIME"] == "python27" + + +def is_local_appengine(): + return "APPENGINE_RUNTIME" in os.environ and os.environ.get( + "SERVER_SOFTWARE", "" + ).startswith("Development/") + + +def is_prod_appengine(): + return "APPENGINE_RUNTIME" in os.environ and os.environ.get( + "SERVER_SOFTWARE", "" + ).startswith("Google App Engine/") + + +def is_prod_appengine_mvms(): + """Deprecated.""" + return False diff --git a/venv/lib/python3.8/site-packages/urllib3/contrib/_securetransport/__init__.py b/venv/lib/python3.8/site-packages/urllib3/contrib/_securetransport/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.8/site-packages/urllib3/contrib/_securetransport/bindings.py b/venv/lib/python3.8/site-packages/urllib3/contrib/_securetransport/bindings.py new file mode 100644 index 0000000..11524d4 --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3/contrib/_securetransport/bindings.py @@ -0,0 +1,519 @@ +""" +This module uses ctypes to bind a whole bunch of functions and constants from +SecureTransport. The goal here is to provide the low-level API to +SecureTransport. These are essentially the C-level functions and constants, and +they're pretty gross to work with. + +This code is a bastardised version of the code found in Will Bond's oscrypto +library. An enormous debt is owed to him for blazing this trail for us. For +that reason, this code should be considered to be covered both by urllib3's +license and by oscrypto's: + + Copyright (c) 2015-2016 Will Bond <will@wbond.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. +""" +from __future__ import absolute_import + +import platform +from ctypes import ( + CDLL, + CFUNCTYPE, + POINTER, + c_bool, + c_byte, + c_char_p, + c_int32, + c_long, + c_size_t, + c_uint32, + c_ulong, + c_void_p, +) +from ctypes.util import find_library + +from urllib3.packages.six import raise_from + +if platform.system() != "Darwin": + raise ImportError("Only macOS is supported") + +version = platform.mac_ver()[0] +version_info = tuple(map(int, version.split("."))) +if version_info < (10, 8): + raise OSError( + "Only OS X 10.8 and newer are supported, not %s.%s" + % (version_info[0], version_info[1]) + ) + + +def load_cdll(name, macos10_16_path): + """Loads a CDLL by name, falling back to known path on 10.16+""" + try: + # Big Sur is technically 11 but we use 10.16 due to the Big Sur + # beta being labeled as 10.16. + if version_info >= (10, 16): + path = macos10_16_path + else: + path = find_library(name) + if not path: + raise OSError # Caught and reraised as 'ImportError' + return CDLL(path, use_errno=True) + except OSError: + raise_from(ImportError("The library %s failed to load" % name), None) + + +Security = load_cdll( + "Security", "/System/Library/Frameworks/Security.framework/Security" +) +CoreFoundation = load_cdll( + "CoreFoundation", + "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation", +) + + +Boolean = c_bool +CFIndex = c_long +CFStringEncoding = c_uint32 +CFData = c_void_p +CFString = c_void_p +CFArray = c_void_p +CFMutableArray = c_void_p +CFDictionary = c_void_p +CFError = c_void_p +CFType = c_void_p +CFTypeID = c_ulong + +CFTypeRef = POINTER(CFType) +CFAllocatorRef = c_void_p + +OSStatus = c_int32 + +CFDataRef = POINTER(CFData) +CFStringRef = POINTER(CFString) +CFArrayRef = POINTER(CFArray) +CFMutableArrayRef = POINTER(CFMutableArray) +CFDictionaryRef = POINTER(CFDictionary) +CFArrayCallBacks = c_void_p +CFDictionaryKeyCallBacks = c_void_p +CFDictionaryValueCallBacks = c_void_p + +SecCertificateRef = POINTER(c_void_p) +SecExternalFormat = c_uint32 +SecExternalItemType = c_uint32 +SecIdentityRef = POINTER(c_void_p) +SecItemImportExportFlags = c_uint32 +SecItemImportExportKeyParameters = c_void_p +SecKeychainRef = POINTER(c_void_p) +SSLProtocol = c_uint32 +SSLCipherSuite = c_uint32 +SSLContextRef = POINTER(c_void_p) +SecTrustRef = POINTER(c_void_p) +SSLConnectionRef = c_uint32 +SecTrustResultType = c_uint32 +SecTrustOptionFlags = c_uint32 +SSLProtocolSide = c_uint32 +SSLConnectionType = c_uint32 +SSLSessionOption = c_uint32 + + +try: + Security.SecItemImport.argtypes = [ + CFDataRef, + CFStringRef, + POINTER(SecExternalFormat), + POINTER(SecExternalItemType), + SecItemImportExportFlags, + POINTER(SecItemImportExportKeyParameters), + SecKeychainRef, + POINTER(CFArrayRef), + ] + Security.SecItemImport.restype = OSStatus + + Security.SecCertificateGetTypeID.argtypes = [] + Security.SecCertificateGetTypeID.restype = CFTypeID + + Security.SecIdentityGetTypeID.argtypes = [] + Security.SecIdentityGetTypeID.restype = CFTypeID + + Security.SecKeyGetTypeID.argtypes = [] + Security.SecKeyGetTypeID.restype = CFTypeID + + Security.SecCertificateCreateWithData.argtypes = [CFAllocatorRef, CFDataRef] + Security.SecCertificateCreateWithData.restype = SecCertificateRef + + Security.SecCertificateCopyData.argtypes = [SecCertificateRef] + Security.SecCertificateCopyData.restype = CFDataRef + + Security.SecCopyErrorMessageString.argtypes = [OSStatus, c_void_p] + Security.SecCopyErrorMessageString.restype = CFStringRef + + Security.SecIdentityCreateWithCertificate.argtypes = [ + CFTypeRef, + SecCertificateRef, + POINTER(SecIdentityRef), + ] + Security.SecIdentityCreateWithCertificate.restype = OSStatus + + Security.SecKeychainCreate.argtypes = [ + c_char_p, + c_uint32, + c_void_p, + Boolean, + c_void_p, + POINTER(SecKeychainRef), + ] + Security.SecKeychainCreate.restype = OSStatus + + Security.SecKeychainDelete.argtypes = [SecKeychainRef] + Security.SecKeychainDelete.restype = OSStatus + + Security.SecPKCS12Import.argtypes = [ + CFDataRef, + CFDictionaryRef, + POINTER(CFArrayRef), + ] + Security.SecPKCS12Import.restype = OSStatus + + SSLReadFunc = CFUNCTYPE(OSStatus, SSLConnectionRef, c_void_p, POINTER(c_size_t)) + SSLWriteFunc = CFUNCTYPE( + OSStatus, SSLConnectionRef, POINTER(c_byte), POINTER(c_size_t) + ) + + Security.SSLSetIOFuncs.argtypes = [SSLContextRef, SSLReadFunc, SSLWriteFunc] + Security.SSLSetIOFuncs.restype = OSStatus + + Security.SSLSetPeerID.argtypes = [SSLContextRef, c_char_p, c_size_t] + Security.SSLSetPeerID.restype = OSStatus + + Security.SSLSetCertificate.argtypes = [SSLContextRef, CFArrayRef] + Security.SSLSetCertificate.restype = OSStatus + + Security.SSLSetCertificateAuthorities.argtypes = [SSLContextRef, CFTypeRef, Boolean] + Security.SSLSetCertificateAuthorities.restype = OSStatus + + Security.SSLSetConnection.argtypes = [SSLContextRef, SSLConnectionRef] + Security.SSLSetConnection.restype = OSStatus + + Security.SSLSetPeerDomainName.argtypes = [SSLContextRef, c_char_p, c_size_t] + Security.SSLSetPeerDomainName.restype = OSStatus + + Security.SSLHandshake.argtypes = [SSLContextRef] + Security.SSLHandshake.restype = OSStatus + + Security.SSLRead.argtypes = [SSLContextRef, c_char_p, c_size_t, POINTER(c_size_t)] + Security.SSLRead.restype = OSStatus + + Security.SSLWrite.argtypes = [SSLContextRef, c_char_p, c_size_t, POINTER(c_size_t)] + Security.SSLWrite.restype = OSStatus + + Security.SSLClose.argtypes = [SSLContextRef] + Security.SSLClose.restype = OSStatus + + Security.SSLGetNumberSupportedCiphers.argtypes = [SSLContextRef, POINTER(c_size_t)] + Security.SSLGetNumberSupportedCiphers.restype = OSStatus + + Security.SSLGetSupportedCiphers.argtypes = [ + SSLContextRef, + POINTER(SSLCipherSuite), + POINTER(c_size_t), + ] + Security.SSLGetSupportedCiphers.restype = OSStatus + + Security.SSLSetEnabledCiphers.argtypes = [ + SSLContextRef, + POINTER(SSLCipherSuite), + c_size_t, + ] + Security.SSLSetEnabledCiphers.restype = OSStatus + + Security.SSLGetNumberEnabledCiphers.argtype = [SSLContextRef, POINTER(c_size_t)] + Security.SSLGetNumberEnabledCiphers.restype = OSStatus + + Security.SSLGetEnabledCiphers.argtypes = [ + SSLContextRef, + POINTER(SSLCipherSuite), + POINTER(c_size_t), + ] + Security.SSLGetEnabledCiphers.restype = OSStatus + + Security.SSLGetNegotiatedCipher.argtypes = [SSLContextRef, POINTER(SSLCipherSuite)] + Security.SSLGetNegotiatedCipher.restype = OSStatus + + Security.SSLGetNegotiatedProtocolVersion.argtypes = [ + SSLContextRef, + POINTER(SSLProtocol), + ] + Security.SSLGetNegotiatedProtocolVersion.restype = OSStatus + + Security.SSLCopyPeerTrust.argtypes = [SSLContextRef, POINTER(SecTrustRef)] + Security.SSLCopyPeerTrust.restype = OSStatus + + Security.SecTrustSetAnchorCertificates.argtypes = [SecTrustRef, CFArrayRef] + Security.SecTrustSetAnchorCertificates.restype = OSStatus + + Security.SecTrustSetAnchorCertificatesOnly.argstypes = [SecTrustRef, Boolean] + Security.SecTrustSetAnchorCertificatesOnly.restype = OSStatus + + Security.SecTrustEvaluate.argtypes = [SecTrustRef, POINTER(SecTrustResultType)] + Security.SecTrustEvaluate.restype = OSStatus + + Security.SecTrustGetCertificateCount.argtypes = [SecTrustRef] + Security.SecTrustGetCertificateCount.restype = CFIndex + + Security.SecTrustGetCertificateAtIndex.argtypes = [SecTrustRef, CFIndex] + Security.SecTrustGetCertificateAtIndex.restype = SecCertificateRef + + Security.SSLCreateContext.argtypes = [ + CFAllocatorRef, + SSLProtocolSide, + SSLConnectionType, + ] + Security.SSLCreateContext.restype = SSLContextRef + + Security.SSLSetSessionOption.argtypes = [SSLContextRef, SSLSessionOption, Boolean] + Security.SSLSetSessionOption.restype = OSStatus + + Security.SSLSetProtocolVersionMin.argtypes = [SSLContextRef, SSLProtocol] + Security.SSLSetProtocolVersionMin.restype = OSStatus + + Security.SSLSetProtocolVersionMax.argtypes = [SSLContextRef, SSLProtocol] + Security.SSLSetProtocolVersionMax.restype = OSStatus + + try: + Security.SSLSetALPNProtocols.argtypes = [SSLContextRef, CFArrayRef] + Security.SSLSetALPNProtocols.restype = OSStatus + except AttributeError: + # Supported only in 10.12+ + pass + + Security.SecCopyErrorMessageString.argtypes = [OSStatus, c_void_p] + Security.SecCopyErrorMessageString.restype = CFStringRef + + Security.SSLReadFunc = SSLReadFunc + Security.SSLWriteFunc = SSLWriteFunc + Security.SSLContextRef = SSLContextRef + Security.SSLProtocol = SSLProtocol + Security.SSLCipherSuite = SSLCipherSuite + Security.SecIdentityRef = SecIdentityRef + Security.SecKeychainRef = SecKeychainRef + Security.SecTrustRef = SecTrustRef + Security.SecTrustResultType = SecTrustResultType + Security.SecExternalFormat = SecExternalFormat + Security.OSStatus = OSStatus + + Security.kSecImportExportPassphrase = CFStringRef.in_dll( + Security, "kSecImportExportPassphrase" + ) + Security.kSecImportItemIdentity = CFStringRef.in_dll( + Security, "kSecImportItemIdentity" + ) + + # CoreFoundation time! + CoreFoundation.CFRetain.argtypes = [CFTypeRef] + CoreFoundation.CFRetain.restype = CFTypeRef + + CoreFoundation.CFRelease.argtypes = [CFTypeRef] + CoreFoundation.CFRelease.restype = None + + CoreFoundation.CFGetTypeID.argtypes = [CFTypeRef] + CoreFoundation.CFGetTypeID.restype = CFTypeID + + CoreFoundation.CFStringCreateWithCString.argtypes = [ + CFAllocatorRef, + c_char_p, + CFStringEncoding, + ] + CoreFoundation.CFStringCreateWithCString.restype = CFStringRef + + CoreFoundation.CFStringGetCStringPtr.argtypes = [CFStringRef, CFStringEncoding] + CoreFoundation.CFStringGetCStringPtr.restype = c_char_p + + CoreFoundation.CFStringGetCString.argtypes = [ + CFStringRef, + c_char_p, + CFIndex, + CFStringEncoding, + ] + CoreFoundation.CFStringGetCString.restype = c_bool + + CoreFoundation.CFDataCreate.argtypes = [CFAllocatorRef, c_char_p, CFIndex] + CoreFoundation.CFDataCreate.restype = CFDataRef + + CoreFoundation.CFDataGetLength.argtypes = [CFDataRef] + CoreFoundation.CFDataGetLength.restype = CFIndex + + CoreFoundation.CFDataGetBytePtr.argtypes = [CFDataRef] + CoreFoundation.CFDataGetBytePtr.restype = c_void_p + + CoreFoundation.CFDictionaryCreate.argtypes = [ + CFAllocatorRef, + POINTER(CFTypeRef), + POINTER(CFTypeRef), + CFIndex, + CFDictionaryKeyCallBacks, + CFDictionaryValueCallBacks, + ] + CoreFoundation.CFDictionaryCreate.restype = CFDictionaryRef + + CoreFoundation.CFDictionaryGetValue.argtypes = [CFDictionaryRef, CFTypeRef] + CoreFoundation.CFDictionaryGetValue.restype = CFTypeRef + + CoreFoundation.CFArrayCreate.argtypes = [ + CFAllocatorRef, + POINTER(CFTypeRef), + CFIndex, + CFArrayCallBacks, + ] + CoreFoundation.CFArrayCreate.restype = CFArrayRef + + CoreFoundation.CFArrayCreateMutable.argtypes = [ + CFAllocatorRef, + CFIndex, + CFArrayCallBacks, + ] + CoreFoundation.CFArrayCreateMutable.restype = CFMutableArrayRef + + CoreFoundation.CFArrayAppendValue.argtypes = [CFMutableArrayRef, c_void_p] + CoreFoundation.CFArrayAppendValue.restype = None + + CoreFoundation.CFArrayGetCount.argtypes = [CFArrayRef] + CoreFoundation.CFArrayGetCount.restype = CFIndex + + CoreFoundation.CFArrayGetValueAtIndex.argtypes = [CFArrayRef, CFIndex] + CoreFoundation.CFArrayGetValueAtIndex.restype = c_void_p + + CoreFoundation.kCFAllocatorDefault = CFAllocatorRef.in_dll( + CoreFoundation, "kCFAllocatorDefault" + ) + CoreFoundation.kCFTypeArrayCallBacks = c_void_p.in_dll( + CoreFoundation, "kCFTypeArrayCallBacks" + ) + CoreFoundation.kCFTypeDictionaryKeyCallBacks = c_void_p.in_dll( + CoreFoundation, "kCFTypeDictionaryKeyCallBacks" + ) + CoreFoundation.kCFTypeDictionaryValueCallBacks = c_void_p.in_dll( + CoreFoundation, "kCFTypeDictionaryValueCallBacks" + ) + + CoreFoundation.CFTypeRef = CFTypeRef + CoreFoundation.CFArrayRef = CFArrayRef + CoreFoundation.CFStringRef = CFStringRef + CoreFoundation.CFDictionaryRef = CFDictionaryRef + +except (AttributeError): + raise ImportError("Error initializing ctypes") + + +class CFConst(object): + """ + A class object that acts as essentially a namespace for CoreFoundation + constants. + """ + + kCFStringEncodingUTF8 = CFStringEncoding(0x08000100) + + +class SecurityConst(object): + """ + A class object that acts as essentially a namespace for Security constants. + """ + + kSSLSessionOptionBreakOnServerAuth = 0 + + kSSLProtocol2 = 1 + kSSLProtocol3 = 2 + kTLSProtocol1 = 4 + kTLSProtocol11 = 7 + kTLSProtocol12 = 8 + # SecureTransport does not support TLS 1.3 even if there's a constant for it + kTLSProtocol13 = 10 + kTLSProtocolMaxSupported = 999 + + kSSLClientSide = 1 + kSSLStreamType = 0 + + kSecFormatPEMSequence = 10 + + kSecTrustResultInvalid = 0 + kSecTrustResultProceed = 1 + # This gap is present on purpose: this was kSecTrustResultConfirm, which + # is deprecated. + kSecTrustResultDeny = 3 + kSecTrustResultUnspecified = 4 + kSecTrustResultRecoverableTrustFailure = 5 + kSecTrustResultFatalTrustFailure = 6 + kSecTrustResultOtherError = 7 + + errSSLProtocol = -9800 + errSSLWouldBlock = -9803 + errSSLClosedGraceful = -9805 + errSSLClosedNoNotify = -9816 + errSSLClosedAbort = -9806 + + errSSLXCertChainInvalid = -9807 + errSSLCrypto = -9809 + errSSLInternal = -9810 + errSSLCertExpired = -9814 + errSSLCertNotYetValid = -9815 + errSSLUnknownRootCert = -9812 + errSSLNoRootCert = -9813 + errSSLHostNameMismatch = -9843 + errSSLPeerHandshakeFail = -9824 + errSSLPeerUserCancelled = -9839 + errSSLWeakPeerEphemeralDHKey = -9850 + errSSLServerAuthCompleted = -9841 + errSSLRecordOverflow = -9847 + + errSecVerifyFailed = -67808 + errSecNoTrustSettings = -25263 + errSecItemNotFound = -25300 + errSecInvalidTrustSettings = -25262 + + # Cipher suites. We only pick the ones our default cipher string allows. + # Source: https://developer.apple.com/documentation/security/1550981-ssl_cipher_suite_values + TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = 0xC02C + TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = 0xC030 + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = 0xC02B + TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = 0xC02F + TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCCA9 + TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCCA8 + TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 = 0x009F + TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 = 0x009E + TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = 0xC024 + TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = 0xC028 + TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = 0xC00A + TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = 0xC014 + TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = 0x006B + TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0x0039 + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = 0xC023 + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = 0xC027 + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = 0xC009 + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = 0xC013 + TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = 0x0067 + TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0x0033 + TLS_RSA_WITH_AES_256_GCM_SHA384 = 0x009D + TLS_RSA_WITH_AES_128_GCM_SHA256 = 0x009C + TLS_RSA_WITH_AES_256_CBC_SHA256 = 0x003D + TLS_RSA_WITH_AES_128_CBC_SHA256 = 0x003C + TLS_RSA_WITH_AES_256_CBC_SHA = 0x0035 + TLS_RSA_WITH_AES_128_CBC_SHA = 0x002F + TLS_AES_128_GCM_SHA256 = 0x1301 + TLS_AES_256_GCM_SHA384 = 0x1302 + TLS_AES_128_CCM_8_SHA256 = 0x1305 + TLS_AES_128_CCM_SHA256 = 0x1304 diff --git a/venv/lib/python3.8/site-packages/urllib3/contrib/_securetransport/low_level.py b/venv/lib/python3.8/site-packages/urllib3/contrib/_securetransport/low_level.py new file mode 100644 index 0000000..ed81201 --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3/contrib/_securetransport/low_level.py @@ -0,0 +1,396 @@ +""" +Low-level helpers for the SecureTransport bindings. + +These are Python functions that are not directly related to the high-level APIs +but are necessary to get them to work. They include a whole bunch of low-level +CoreFoundation messing about and memory management. The concerns in this module +are almost entirely about trying to avoid memory leaks and providing +appropriate and useful assistance to the higher-level code. +""" +import base64 +import ctypes +import itertools +import os +import re +import ssl +import struct +import tempfile + +from .bindings import CFConst, CoreFoundation, Security + +# This regular expression is used to grab PEM data out of a PEM bundle. +_PEM_CERTS_RE = re.compile( + b"-----BEGIN CERTIFICATE-----\n(.*?)\n-----END CERTIFICATE-----", re.DOTALL +) + + +def _cf_data_from_bytes(bytestring): + """ + Given a bytestring, create a CFData object from it. This CFData object must + be CFReleased by the caller. + """ + return CoreFoundation.CFDataCreate( + CoreFoundation.kCFAllocatorDefault, bytestring, len(bytestring) + ) + + +def _cf_dictionary_from_tuples(tuples): + """ + Given a list of Python tuples, create an associated CFDictionary. + """ + dictionary_size = len(tuples) + + # We need to get the dictionary keys and values out in the same order. + keys = (t[0] for t in tuples) + values = (t[1] for t in tuples) + cf_keys = (CoreFoundation.CFTypeRef * dictionary_size)(*keys) + cf_values = (CoreFoundation.CFTypeRef * dictionary_size)(*values) + + return CoreFoundation.CFDictionaryCreate( + CoreFoundation.kCFAllocatorDefault, + cf_keys, + cf_values, + dictionary_size, + CoreFoundation.kCFTypeDictionaryKeyCallBacks, + CoreFoundation.kCFTypeDictionaryValueCallBacks, + ) + + +def _cfstr(py_bstr): + """ + Given a Python binary data, create a CFString. + The string must be CFReleased by the caller. + """ + c_str = ctypes.c_char_p(py_bstr) + cf_str = CoreFoundation.CFStringCreateWithCString( + CoreFoundation.kCFAllocatorDefault, + c_str, + CFConst.kCFStringEncodingUTF8, + ) + return cf_str + + +def _create_cfstring_array(lst): + """ + Given a list of Python binary data, create an associated CFMutableArray. + The array must be CFReleased by the caller. + + Raises an ssl.SSLError on failure. + """ + cf_arr = None + try: + cf_arr = CoreFoundation.CFArrayCreateMutable( + CoreFoundation.kCFAllocatorDefault, + 0, + ctypes.byref(CoreFoundation.kCFTypeArrayCallBacks), + ) + if not cf_arr: + raise MemoryError("Unable to allocate memory!") + for item in lst: + cf_str = _cfstr(item) + if not cf_str: + raise MemoryError("Unable to allocate memory!") + try: + CoreFoundation.CFArrayAppendValue(cf_arr, cf_str) + finally: + CoreFoundation.CFRelease(cf_str) + except BaseException as e: + if cf_arr: + CoreFoundation.CFRelease(cf_arr) + raise ssl.SSLError("Unable to allocate array: %s" % (e,)) + return cf_arr + + +def _cf_string_to_unicode(value): + """ + Creates a Unicode string from a CFString object. Used entirely for error + reporting. + + Yes, it annoys me quite a lot that this function is this complex. + """ + value_as_void_p = ctypes.cast(value, ctypes.POINTER(ctypes.c_void_p)) + + string = CoreFoundation.CFStringGetCStringPtr( + value_as_void_p, CFConst.kCFStringEncodingUTF8 + ) + if string is None: + buffer = ctypes.create_string_buffer(1024) + result = CoreFoundation.CFStringGetCString( + value_as_void_p, buffer, 1024, CFConst.kCFStringEncodingUTF8 + ) + if not result: + raise OSError("Error copying C string from CFStringRef") + string = buffer.value + if string is not None: + string = string.decode("utf-8") + return string + + +def _assert_no_error(error, exception_class=None): + """ + Checks the return code and throws an exception if there is an error to + report + """ + if error == 0: + return + + cf_error_string = Security.SecCopyErrorMessageString(error, None) + output = _cf_string_to_unicode(cf_error_string) + CoreFoundation.CFRelease(cf_error_string) + + if output is None or output == u"": + output = u"OSStatus %s" % error + + if exception_class is None: + exception_class = ssl.SSLError + + raise exception_class(output) + + +def _cert_array_from_pem(pem_bundle): + """ + Given a bundle of certs in PEM format, turns them into a CFArray of certs + that can be used to validate a cert chain. + """ + # Normalize the PEM bundle's line endings. + pem_bundle = pem_bundle.replace(b"\r\n", b"\n") + + der_certs = [ + base64.b64decode(match.group(1)) for match in _PEM_CERTS_RE.finditer(pem_bundle) + ] + if not der_certs: + raise ssl.SSLError("No root certificates specified") + + cert_array = CoreFoundation.CFArrayCreateMutable( + CoreFoundation.kCFAllocatorDefault, + 0, + ctypes.byref(CoreFoundation.kCFTypeArrayCallBacks), + ) + if not cert_array: + raise ssl.SSLError("Unable to allocate memory!") + + try: + for der_bytes in der_certs: + certdata = _cf_data_from_bytes(der_bytes) + if not certdata: + raise ssl.SSLError("Unable to allocate memory!") + cert = Security.SecCertificateCreateWithData( + CoreFoundation.kCFAllocatorDefault, certdata + ) + CoreFoundation.CFRelease(certdata) + if not cert: + raise ssl.SSLError("Unable to build cert object!") + + CoreFoundation.CFArrayAppendValue(cert_array, cert) + CoreFoundation.CFRelease(cert) + except Exception: + # We need to free the array before the exception bubbles further. + # We only want to do that if an error occurs: otherwise, the caller + # should free. + CoreFoundation.CFRelease(cert_array) + + return cert_array + + +def _is_cert(item): + """ + Returns True if a given CFTypeRef is a certificate. + """ + expected = Security.SecCertificateGetTypeID() + return CoreFoundation.CFGetTypeID(item) == expected + + +def _is_identity(item): + """ + Returns True if a given CFTypeRef is an identity. + """ + expected = Security.SecIdentityGetTypeID() + return CoreFoundation.CFGetTypeID(item) == expected + + +def _temporary_keychain(): + """ + This function creates a temporary Mac keychain that we can use to work with + credentials. This keychain uses a one-time password and a temporary file to + store the data. We expect to have one keychain per socket. The returned + SecKeychainRef must be freed by the caller, including calling + SecKeychainDelete. + + Returns a tuple of the SecKeychainRef and the path to the temporary + directory that contains it. + """ + # Unfortunately, SecKeychainCreate requires a path to a keychain. This + # means we cannot use mkstemp to use a generic temporary file. Instead, + # we're going to create a temporary directory and a filename to use there. + # This filename will be 8 random bytes expanded into base64. We also need + # some random bytes to password-protect the keychain we're creating, so we + # ask for 40 random bytes. + random_bytes = os.urandom(40) + filename = base64.b16encode(random_bytes[:8]).decode("utf-8") + password = base64.b16encode(random_bytes[8:]) # Must be valid UTF-8 + tempdirectory = tempfile.mkdtemp() + + keychain_path = os.path.join(tempdirectory, filename).encode("utf-8") + + # We now want to create the keychain itself. + keychain = Security.SecKeychainRef() + status = Security.SecKeychainCreate( + keychain_path, len(password), password, False, None, ctypes.byref(keychain) + ) + _assert_no_error(status) + + # Having created the keychain, we want to pass it off to the caller. + return keychain, tempdirectory + + +def _load_items_from_file(keychain, path): + """ + Given a single file, loads all the trust objects from it into arrays and + the keychain. + Returns a tuple of lists: the first list is a list of identities, the + second a list of certs. + """ + certificates = [] + identities = [] + result_array = None + + with open(path, "rb") as f: + raw_filedata = f.read() + + try: + filedata = CoreFoundation.CFDataCreate( + CoreFoundation.kCFAllocatorDefault, raw_filedata, len(raw_filedata) + ) + result_array = CoreFoundation.CFArrayRef() + result = Security.SecItemImport( + filedata, # cert data + None, # Filename, leaving it out for now + None, # What the type of the file is, we don't care + None, # what's in the file, we don't care + 0, # import flags + None, # key params, can include passphrase in the future + keychain, # The keychain to insert into + ctypes.byref(result_array), # Results + ) + _assert_no_error(result) + + # A CFArray is not very useful to us as an intermediary + # representation, so we are going to extract the objects we want + # and then free the array. We don't need to keep hold of keys: the + # keychain already has them! + result_count = CoreFoundation.CFArrayGetCount(result_array) + for index in range(result_count): + item = CoreFoundation.CFArrayGetValueAtIndex(result_array, index) + item = ctypes.cast(item, CoreFoundation.CFTypeRef) + + if _is_cert(item): + CoreFoundation.CFRetain(item) + certificates.append(item) + elif _is_identity(item): + CoreFoundation.CFRetain(item) + identities.append(item) + finally: + if result_array: + CoreFoundation.CFRelease(result_array) + + CoreFoundation.CFRelease(filedata) + + return (identities, certificates) + + +def _load_client_cert_chain(keychain, *paths): + """ + Load certificates and maybe keys from a number of files. Has the end goal + of returning a CFArray containing one SecIdentityRef, and then zero or more + SecCertificateRef objects, suitable for use as a client certificate trust + chain. + """ + # Ok, the strategy. + # + # This relies on knowing that macOS will not give you a SecIdentityRef + # unless you have imported a key into a keychain. This is a somewhat + # artificial limitation of macOS (for example, it doesn't necessarily + # affect iOS), but there is nothing inside Security.framework that lets you + # get a SecIdentityRef without having a key in a keychain. + # + # So the policy here is we take all the files and iterate them in order. + # Each one will use SecItemImport to have one or more objects loaded from + # it. We will also point at a keychain that macOS can use to work with the + # private key. + # + # Once we have all the objects, we'll check what we actually have. If we + # already have a SecIdentityRef in hand, fab: we'll use that. Otherwise, + # we'll take the first certificate (which we assume to be our leaf) and + # ask the keychain to give us a SecIdentityRef with that cert's associated + # key. + # + # We'll then return a CFArray containing the trust chain: one + # SecIdentityRef and then zero-or-more SecCertificateRef objects. The + # responsibility for freeing this CFArray will be with the caller. This + # CFArray must remain alive for the entire connection, so in practice it + # will be stored with a single SSLSocket, along with the reference to the + # keychain. + certificates = [] + identities = [] + + # Filter out bad paths. + paths = (path for path in paths if path) + + try: + for file_path in paths: + new_identities, new_certs = _load_items_from_file(keychain, file_path) + identities.extend(new_identities) + certificates.extend(new_certs) + + # Ok, we have everything. The question is: do we have an identity? If + # not, we want to grab one from the first cert we have. + if not identities: + new_identity = Security.SecIdentityRef() + status = Security.SecIdentityCreateWithCertificate( + keychain, certificates[0], ctypes.byref(new_identity) + ) + _assert_no_error(status) + identities.append(new_identity) + + # We now want to release the original certificate, as we no longer + # need it. + CoreFoundation.CFRelease(certificates.pop(0)) + + # We now need to build a new CFArray that holds the trust chain. + trust_chain = CoreFoundation.CFArrayCreateMutable( + CoreFoundation.kCFAllocatorDefault, + 0, + ctypes.byref(CoreFoundation.kCFTypeArrayCallBacks), + ) + for item in itertools.chain(identities, certificates): + # ArrayAppendValue does a CFRetain on the item. That's fine, + # because the finally block will release our other refs to them. + CoreFoundation.CFArrayAppendValue(trust_chain, item) + + return trust_chain + finally: + for obj in itertools.chain(identities, certificates): + CoreFoundation.CFRelease(obj) + + +TLS_PROTOCOL_VERSIONS = { + "SSLv2": (0, 2), + "SSLv3": (3, 0), + "TLSv1": (3, 1), + "TLSv1.1": (3, 2), + "TLSv1.2": (3, 3), +} + + +def _build_tls_unknown_ca_alert(version): + """ + Builds a TLS alert record for an unknown CA. + """ + ver_maj, ver_min = TLS_PROTOCOL_VERSIONS[version] + severity_fatal = 0x02 + description_unknown_ca = 0x30 + msg = struct.pack(">BB", severity_fatal, description_unknown_ca) + msg_len = len(msg) + record_type_alert = 0x15 + record = struct.pack(">BBBH", record_type_alert, ver_maj, ver_min, msg_len) + msg + return record diff --git a/venv/lib/python3.8/site-packages/urllib3/contrib/appengine.py b/venv/lib/python3.8/site-packages/urllib3/contrib/appengine.py new file mode 100644 index 0000000..f91bdd6 --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3/contrib/appengine.py @@ -0,0 +1,314 @@ +""" +This module provides a pool manager that uses Google App Engine's +`URLFetch Service <https://cloud.google.com/appengine/docs/python/urlfetch>`_. + +Example usage:: + + from urllib3 import PoolManager + from urllib3.contrib.appengine import AppEngineManager, is_appengine_sandbox + + if is_appengine_sandbox(): + # AppEngineManager uses AppEngine's URLFetch API behind the scenes + http = AppEngineManager() + else: + # PoolManager uses a socket-level API behind the scenes + http = PoolManager() + + r = http.request('GET', 'https://google.com/') + +There are `limitations <https://cloud.google.com/appengine/docs/python/\ +urlfetch/#Python_Quotas_and_limits>`_ to the URLFetch service and it may not be +the best choice for your application. There are three options for using +urllib3 on Google App Engine: + +1. You can use :class:`AppEngineManager` with URLFetch. URLFetch is + cost-effective in many circumstances as long as your usage is within the + limitations. +2. You can use a normal :class:`~urllib3.PoolManager` by enabling sockets. + Sockets also have `limitations and restrictions + <https://cloud.google.com/appengine/docs/python/sockets/\ + #limitations-and-restrictions>`_ and have a lower free quota than URLFetch. + To use sockets, be sure to specify the following in your ``app.yaml``:: + + env_variables: + GAE_USE_SOCKETS_HTTPLIB : 'true' + +3. If you are using `App Engine Flexible +<https://cloud.google.com/appengine/docs/flexible/>`_, you can use the standard +:class:`PoolManager` without any configuration or special environment variables. +""" + +from __future__ import absolute_import + +import io +import logging +import warnings + +from ..exceptions import ( + HTTPError, + HTTPWarning, + MaxRetryError, + ProtocolError, + SSLError, + TimeoutError, +) +from ..packages.six.moves.urllib.parse import urljoin +from ..request import RequestMethods +from ..response import HTTPResponse +from ..util.retry import Retry +from ..util.timeout import Timeout +from . import _appengine_environ + +try: + from google.appengine.api import urlfetch +except ImportError: + urlfetch = None + + +log = logging.getLogger(__name__) + + +class AppEnginePlatformWarning(HTTPWarning): + pass + + +class AppEnginePlatformError(HTTPError): + pass + + +class AppEngineManager(RequestMethods): + """ + Connection manager for Google App Engine sandbox applications. + + This manager uses the URLFetch service directly instead of using the + emulated httplib, and is subject to URLFetch limitations as described in + the App Engine documentation `here + <https://cloud.google.com/appengine/docs/python/urlfetch>`_. + + Notably it will raise an :class:`AppEnginePlatformError` if: + * URLFetch is not available. + * If you attempt to use this on App Engine Flexible, as full socket + support is available. + * If a request size is more than 10 megabytes. + * If a response size is more than 32 megabytes. + * If you use an unsupported request method such as OPTIONS. + + Beyond those cases, it will raise normal urllib3 errors. + """ + + def __init__( + self, + headers=None, + retries=None, + validate_certificate=True, + urlfetch_retries=True, + ): + if not urlfetch: + raise AppEnginePlatformError( + "URLFetch is not available in this environment." + ) + + warnings.warn( + "urllib3 is using URLFetch on Google App Engine sandbox instead " + "of sockets. To use sockets directly instead of URLFetch see " + "https://urllib3.readthedocs.io/en/1.26.x/reference/urllib3.contrib.html.", + AppEnginePlatformWarning, + ) + + RequestMethods.__init__(self, headers) + self.validate_certificate = validate_certificate + self.urlfetch_retries = urlfetch_retries + + self.retries = retries or Retry.DEFAULT + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + # Return False to re-raise any potential exceptions + return False + + def urlopen( + self, + method, + url, + body=None, + headers=None, + retries=None, + redirect=True, + timeout=Timeout.DEFAULT_TIMEOUT, + **response_kw + ): + + retries = self._get_retries(retries, redirect) + + try: + follow_redirects = redirect and retries.redirect != 0 and retries.total + response = urlfetch.fetch( + url, + payload=body, + method=method, + headers=headers or {}, + allow_truncated=False, + follow_redirects=self.urlfetch_retries and follow_redirects, + deadline=self._get_absolute_timeout(timeout), + validate_certificate=self.validate_certificate, + ) + except urlfetch.DeadlineExceededError as e: + raise TimeoutError(self, e) + + except urlfetch.InvalidURLError as e: + if "too large" in str(e): + raise AppEnginePlatformError( + "URLFetch request too large, URLFetch only " + "supports requests up to 10mb in size.", + e, + ) + raise ProtocolError(e) + + except urlfetch.DownloadError as e: + if "Too many redirects" in str(e): + raise MaxRetryError(self, url, reason=e) + raise ProtocolError(e) + + except urlfetch.ResponseTooLargeError as e: + raise AppEnginePlatformError( + "URLFetch response too large, URLFetch only supports" + "responses up to 32mb in size.", + e, + ) + + except urlfetch.SSLCertificateError as e: + raise SSLError(e) + + except urlfetch.InvalidMethodError as e: + raise AppEnginePlatformError( + "URLFetch does not support method: %s" % method, e + ) + + http_response = self._urlfetch_response_to_http_response( + response, retries=retries, **response_kw + ) + + # Handle redirect? + redirect_location = redirect and http_response.get_redirect_location() + if redirect_location: + # Check for redirect response + if self.urlfetch_retries and retries.raise_on_redirect: + raise MaxRetryError(self, url, "too many redirects") + else: + if http_response.status == 303: + method = "GET" + + try: + retries = retries.increment( + method, url, response=http_response, _pool=self + ) + except MaxRetryError: + if retries.raise_on_redirect: + raise MaxRetryError(self, url, "too many redirects") + return http_response + + retries.sleep_for_retry(http_response) + log.debug("Redirecting %s -> %s", url, redirect_location) + redirect_url = urljoin(url, redirect_location) + return self.urlopen( + method, + redirect_url, + body, + headers, + retries=retries, + redirect=redirect, + timeout=timeout, + **response_kw + ) + + # Check if we should retry the HTTP response. + has_retry_after = bool(http_response.getheader("Retry-After")) + if retries.is_retry(method, http_response.status, has_retry_after): + retries = retries.increment(method, url, response=http_response, _pool=self) + log.debug("Retry: %s", url) + retries.sleep(http_response) + return self.urlopen( + method, + url, + body=body, + headers=headers, + retries=retries, + redirect=redirect, + timeout=timeout, + **response_kw + ) + + return http_response + + def _urlfetch_response_to_http_response(self, urlfetch_resp, **response_kw): + + if is_prod_appengine(): + # Production GAE handles deflate encoding automatically, but does + # not remove the encoding header. + content_encoding = urlfetch_resp.headers.get("content-encoding") + + if content_encoding == "deflate": + del urlfetch_resp.headers["content-encoding"] + + transfer_encoding = urlfetch_resp.headers.get("transfer-encoding") + # We have a full response's content, + # so let's make sure we don't report ourselves as chunked data. + if transfer_encoding == "chunked": + encodings = transfer_encoding.split(",") + encodings.remove("chunked") + urlfetch_resp.headers["transfer-encoding"] = ",".join(encodings) + + original_response = HTTPResponse( + # In order for decoding to work, we must present the content as + # a file-like object. + body=io.BytesIO(urlfetch_resp.content), + msg=urlfetch_resp.header_msg, + headers=urlfetch_resp.headers, + status=urlfetch_resp.status_code, + **response_kw + ) + + return HTTPResponse( + body=io.BytesIO(urlfetch_resp.content), + headers=urlfetch_resp.headers, + status=urlfetch_resp.status_code, + original_response=original_response, + **response_kw + ) + + def _get_absolute_timeout(self, timeout): + if timeout is Timeout.DEFAULT_TIMEOUT: + return None # Defer to URLFetch's default. + if isinstance(timeout, Timeout): + if timeout._read is not None or timeout._connect is not None: + warnings.warn( + "URLFetch does not support granular timeout settings, " + "reverting to total or default URLFetch timeout.", + AppEnginePlatformWarning, + ) + return timeout.total + return timeout + + def _get_retries(self, retries, redirect): + if not isinstance(retries, Retry): + retries = Retry.from_int(retries, redirect=redirect, default=self.retries) + + if retries.connect or retries.read or retries.redirect: + warnings.warn( + "URLFetch only supports total retries and does not " + "recognize connect, read, or redirect retry parameters.", + AppEnginePlatformWarning, + ) + + return retries + + +# Alias methods from _appengine_environ to maintain public API interface. + +is_appengine = _appengine_environ.is_appengine +is_appengine_sandbox = _appengine_environ.is_appengine_sandbox +is_local_appengine = _appengine_environ.is_local_appengine +is_prod_appengine = _appengine_environ.is_prod_appengine +is_prod_appengine_mvms = _appengine_environ.is_prod_appengine_mvms diff --git a/venv/lib/python3.8/site-packages/urllib3/contrib/ntlmpool.py b/venv/lib/python3.8/site-packages/urllib3/contrib/ntlmpool.py new file mode 100644 index 0000000..41a8fd1 --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3/contrib/ntlmpool.py @@ -0,0 +1,130 @@ +""" +NTLM authenticating pool, contributed by erikcederstran + +Issue #10, see: http://code.google.com/p/urllib3/issues/detail?id=10 +""" +from __future__ import absolute_import + +import warnings +from logging import getLogger + +from ntlm import ntlm + +from .. import HTTPSConnectionPool +from ..packages.six.moves.http_client import HTTPSConnection + +warnings.warn( + "The 'urllib3.contrib.ntlmpool' module is deprecated and will be removed " + "in urllib3 v2.0 release, urllib3 is not able to support it properly due " + "to reasons listed in issue: https://github.com/urllib3/urllib3/issues/2282. " + "If you are a user of this module please comment in the mentioned issue.", + DeprecationWarning, +) + +log = getLogger(__name__) + + +class NTLMConnectionPool(HTTPSConnectionPool): + """ + Implements an NTLM authentication version of an urllib3 connection pool + """ + + scheme = "https" + + def __init__(self, user, pw, authurl, *args, **kwargs): + """ + authurl is a random URL on the server that is protected by NTLM. + user is the Windows user, probably in the DOMAIN\\username format. + pw is the password for the user. + """ + super(NTLMConnectionPool, self).__init__(*args, **kwargs) + self.authurl = authurl + self.rawuser = user + user_parts = user.split("\\", 1) + self.domain = user_parts[0].upper() + self.user = user_parts[1] + self.pw = pw + + def _new_conn(self): + # Performs the NTLM handshake that secures the connection. The socket + # must be kept open while requests are performed. + self.num_connections += 1 + log.debug( + "Starting NTLM HTTPS connection no. %d: https://%s%s", + self.num_connections, + self.host, + self.authurl, + ) + + headers = {"Connection": "Keep-Alive"} + req_header = "Authorization" + resp_header = "www-authenticate" + + conn = HTTPSConnection(host=self.host, port=self.port) + + # Send negotiation message + headers[req_header] = "NTLM %s" % ntlm.create_NTLM_NEGOTIATE_MESSAGE( + self.rawuser + ) + log.debug("Request headers: %s", headers) + conn.request("GET", self.authurl, None, headers) + res = conn.getresponse() + reshdr = dict(res.getheaders()) + log.debug("Response status: %s %s", res.status, res.reason) + log.debug("Response headers: %s", reshdr) + log.debug("Response data: %s [...]", res.read(100)) + + # Remove the reference to the socket, so that it can not be closed by + # the response object (we want to keep the socket open) + res.fp = None + + # Server should respond with a challenge message + auth_header_values = reshdr[resp_header].split(", ") + auth_header_value = None + for s in auth_header_values: + if s[:5] == "NTLM ": + auth_header_value = s[5:] + if auth_header_value is None: + raise Exception( + "Unexpected %s response header: %s" % (resp_header, reshdr[resp_header]) + ) + + # Send authentication message + ServerChallenge, NegotiateFlags = ntlm.parse_NTLM_CHALLENGE_MESSAGE( + auth_header_value + ) + auth_msg = ntlm.create_NTLM_AUTHENTICATE_MESSAGE( + ServerChallenge, self.user, self.domain, self.pw, NegotiateFlags + ) + headers[req_header] = "NTLM %s" % auth_msg + log.debug("Request headers: %s", headers) + conn.request("GET", self.authurl, None, headers) + res = conn.getresponse() + log.debug("Response status: %s %s", res.status, res.reason) + log.debug("Response headers: %s", dict(res.getheaders())) + log.debug("Response data: %s [...]", res.read()[:100]) + if res.status != 200: + if res.status == 401: + raise Exception("Server rejected request: wrong username or password") + raise Exception("Wrong server response: %s %s" % (res.status, res.reason)) + + res.fp = None + log.debug("Connection established") + return conn + + def urlopen( + self, + method, + url, + body=None, + headers=None, + retries=3, + redirect=True, + assert_same_host=True, + ): + if headers is None: + headers = {} + headers["Connection"] = "Keep-Alive" + return super(NTLMConnectionPool, self).urlopen( + method, url, body, headers, retries, redirect, assert_same_host + ) diff --git a/venv/lib/python3.8/site-packages/urllib3/contrib/pyopenssl.py b/venv/lib/python3.8/site-packages/urllib3/contrib/pyopenssl.py new file mode 100644 index 0000000..def83af --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3/contrib/pyopenssl.py @@ -0,0 +1,511 @@ +""" +TLS with SNI_-support for Python 2. Follow these instructions if you would +like to verify TLS certificates in Python 2. Note, the default libraries do +*not* do certificate checking; you need to do additional work to validate +certificates yourself. + +This needs the following packages installed: + +* `pyOpenSSL`_ (tested with 16.0.0) +* `cryptography`_ (minimum 1.3.4, from pyopenssl) +* `idna`_ (minimum 2.0, from cryptography) + +However, pyopenssl depends on cryptography, which depends on idna, so while we +use all three directly here we end up having relatively few packages required. + +You can install them with the following command: + +.. code-block:: bash + + $ python -m pip install pyopenssl cryptography idna + +To activate certificate checking, call +:func:`~urllib3.contrib.pyopenssl.inject_into_urllib3` from your Python code +before you begin making HTTP requests. This can be done in a ``sitecustomize`` +module, or at any other time before your application begins using ``urllib3``, +like this: + +.. code-block:: python + + try: + import urllib3.contrib.pyopenssl + urllib3.contrib.pyopenssl.inject_into_urllib3() + except ImportError: + pass + +Now you can use :mod:`urllib3` as you normally would, and it will support SNI +when the required modules are installed. + +Activating this module also has the positive side effect of disabling SSL/TLS +compression in Python 2 (see `CRIME attack`_). + +.. _sni: https://en.wikipedia.org/wiki/Server_Name_Indication +.. _crime attack: https://en.wikipedia.org/wiki/CRIME_(security_exploit) +.. _pyopenssl: https://www.pyopenssl.org +.. _cryptography: https://cryptography.io +.. _idna: https://github.com/kjd/idna +""" +from __future__ import absolute_import + +import OpenSSL.SSL +from cryptography import x509 +from cryptography.hazmat.backends.openssl import backend as openssl_backend +from cryptography.hazmat.backends.openssl.x509 import _Certificate + +try: + from cryptography.x509 import UnsupportedExtension +except ImportError: + # UnsupportedExtension is gone in cryptography >= 2.1.0 + class UnsupportedExtension(Exception): + pass + + +from io import BytesIO +from socket import error as SocketError +from socket import timeout + +try: # Platform-specific: Python 2 + from socket import _fileobject +except ImportError: # Platform-specific: Python 3 + _fileobject = None + from ..packages.backports.makefile import backport_makefile + +import logging +import ssl +import sys + +from .. import util +from ..packages import six +from ..util.ssl_ import PROTOCOL_TLS_CLIENT + +__all__ = ["inject_into_urllib3", "extract_from_urllib3"] + +# SNI always works. +HAS_SNI = True + +# Map from urllib3 to PyOpenSSL compatible parameter-values. +_openssl_versions = { + util.PROTOCOL_TLS: OpenSSL.SSL.SSLv23_METHOD, + PROTOCOL_TLS_CLIENT: OpenSSL.SSL.SSLv23_METHOD, + ssl.PROTOCOL_TLSv1: OpenSSL.SSL.TLSv1_METHOD, +} + +if hasattr(ssl, "PROTOCOL_SSLv3") and hasattr(OpenSSL.SSL, "SSLv3_METHOD"): + _openssl_versions[ssl.PROTOCOL_SSLv3] = OpenSSL.SSL.SSLv3_METHOD + +if hasattr(ssl, "PROTOCOL_TLSv1_1") and hasattr(OpenSSL.SSL, "TLSv1_1_METHOD"): + _openssl_versions[ssl.PROTOCOL_TLSv1_1] = OpenSSL.SSL.TLSv1_1_METHOD + +if hasattr(ssl, "PROTOCOL_TLSv1_2") and hasattr(OpenSSL.SSL, "TLSv1_2_METHOD"): + _openssl_versions[ssl.PROTOCOL_TLSv1_2] = OpenSSL.SSL.TLSv1_2_METHOD + + +_stdlib_to_openssl_verify = { + ssl.CERT_NONE: OpenSSL.SSL.VERIFY_NONE, + ssl.CERT_OPTIONAL: OpenSSL.SSL.VERIFY_PEER, + ssl.CERT_REQUIRED: OpenSSL.SSL.VERIFY_PEER + + OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT, +} +_openssl_to_stdlib_verify = dict((v, k) for k, v in _stdlib_to_openssl_verify.items()) + +# OpenSSL will only write 16K at a time +SSL_WRITE_BLOCKSIZE = 16384 + +orig_util_HAS_SNI = util.HAS_SNI +orig_util_SSLContext = util.ssl_.SSLContext + + +log = logging.getLogger(__name__) + + +def inject_into_urllib3(): + "Monkey-patch urllib3 with PyOpenSSL-backed SSL-support." + + _validate_dependencies_met() + + util.SSLContext = PyOpenSSLContext + util.ssl_.SSLContext = PyOpenSSLContext + util.HAS_SNI = HAS_SNI + util.ssl_.HAS_SNI = HAS_SNI + util.IS_PYOPENSSL = True + util.ssl_.IS_PYOPENSSL = True + + +def extract_from_urllib3(): + "Undo monkey-patching by :func:`inject_into_urllib3`." + + util.SSLContext = orig_util_SSLContext + util.ssl_.SSLContext = orig_util_SSLContext + util.HAS_SNI = orig_util_HAS_SNI + util.ssl_.HAS_SNI = orig_util_HAS_SNI + util.IS_PYOPENSSL = False + util.ssl_.IS_PYOPENSSL = False + + +def _validate_dependencies_met(): + """ + Verifies that PyOpenSSL's package-level dependencies have been met. + Throws `ImportError` if they are not met. + """ + # Method added in `cryptography==1.1`; not available in older versions + from cryptography.x509.extensions import Extensions + + if getattr(Extensions, "get_extension_for_class", None) is None: + raise ImportError( + "'cryptography' module missing required functionality. " + "Try upgrading to v1.3.4 or newer." + ) + + # pyOpenSSL 0.14 and above use cryptography for OpenSSL bindings. The _x509 + # attribute is only present on those versions. + from OpenSSL.crypto import X509 + + x509 = X509() + if getattr(x509, "_x509", None) is None: + raise ImportError( + "'pyOpenSSL' module missing required functionality. " + "Try upgrading to v0.14 or newer." + ) + + +def _dnsname_to_stdlib(name): + """ + Converts a dNSName SubjectAlternativeName field to the form used by the + standard library on the given Python version. + + Cryptography produces a dNSName as a unicode string that was idna-decoded + from ASCII bytes. We need to idna-encode that string to get it back, and + then on Python 3 we also need to convert to unicode via UTF-8 (the stdlib + uses PyUnicode_FromStringAndSize on it, which decodes via UTF-8). + + If the name cannot be idna-encoded then we return None signalling that + the name given should be skipped. + """ + + def idna_encode(name): + """ + Borrowed wholesale from the Python Cryptography Project. It turns out + that we can't just safely call `idna.encode`: it can explode for + wildcard names. This avoids that problem. + """ + import idna + + try: + for prefix in [u"*.", u"."]: + if name.startswith(prefix): + name = name[len(prefix) :] + return prefix.encode("ascii") + idna.encode(name) + return idna.encode(name) + except idna.core.IDNAError: + return None + + # Don't send IPv6 addresses through the IDNA encoder. + if ":" in name: + return name + + name = idna_encode(name) + if name is None: + return None + elif sys.version_info >= (3, 0): + name = name.decode("utf-8") + return name + + +def get_subj_alt_name(peer_cert): + """ + Given an PyOpenSSL certificate, provides all the subject alternative names. + """ + # Pass the cert to cryptography, which has much better APIs for this. + if hasattr(peer_cert, "to_cryptography"): + cert = peer_cert.to_cryptography() + else: + # This is technically using private APIs, but should work across all + # relevant versions before PyOpenSSL got a proper API for this. + cert = _Certificate(openssl_backend, peer_cert._x509) + + # We want to find the SAN extension. Ask Cryptography to locate it (it's + # faster than looping in Python) + try: + ext = cert.extensions.get_extension_for_class(x509.SubjectAlternativeName).value + except x509.ExtensionNotFound: + # No such extension, return the empty list. + return [] + except ( + x509.DuplicateExtension, + UnsupportedExtension, + x509.UnsupportedGeneralNameType, + UnicodeError, + ) as e: + # A problem has been found with the quality of the certificate. Assume + # no SAN field is present. + log.warning( + "A problem was encountered with the certificate that prevented " + "urllib3 from finding the SubjectAlternativeName field. This can " + "affect certificate validation. The error was %s", + e, + ) + return [] + + # We want to return dNSName and iPAddress fields. We need to cast the IPs + # back to strings because the match_hostname function wants them as + # strings. + # Sadly the DNS names need to be idna encoded and then, on Python 3, UTF-8 + # decoded. This is pretty frustrating, but that's what the standard library + # does with certificates, and so we need to attempt to do the same. + # We also want to skip over names which cannot be idna encoded. + names = [ + ("DNS", name) + for name in map(_dnsname_to_stdlib, ext.get_values_for_type(x509.DNSName)) + if name is not None + ] + names.extend( + ("IP Address", str(name)) for name in ext.get_values_for_type(x509.IPAddress) + ) + + return names + + +class WrappedSocket(object): + """API-compatibility wrapper for Python OpenSSL's Connection-class. + + Note: _makefile_refs, _drop() and _reuse() are needed for the garbage + collector of pypy. + """ + + def __init__(self, connection, socket, suppress_ragged_eofs=True): + self.connection = connection + self.socket = socket + self.suppress_ragged_eofs = suppress_ragged_eofs + self._makefile_refs = 0 + self._closed = False + + def fileno(self): + return self.socket.fileno() + + # Copy-pasted from Python 3.5 source code + def _decref_socketios(self): + if self._makefile_refs > 0: + self._makefile_refs -= 1 + if self._closed: + self.close() + + def recv(self, *args, **kwargs): + try: + data = self.connection.recv(*args, **kwargs) + except OpenSSL.SSL.SysCallError as e: + if self.suppress_ragged_eofs and e.args == (-1, "Unexpected EOF"): + return b"" + else: + raise SocketError(str(e)) + except OpenSSL.SSL.ZeroReturnError: + if self.connection.get_shutdown() == OpenSSL.SSL.RECEIVED_SHUTDOWN: + return b"" + else: + raise + except OpenSSL.SSL.WantReadError: + if not util.wait_for_read(self.socket, self.socket.gettimeout()): + raise timeout("The read operation timed out") + else: + return self.recv(*args, **kwargs) + + # TLS 1.3 post-handshake authentication + except OpenSSL.SSL.Error as e: + raise ssl.SSLError("read error: %r" % e) + else: + return data + + def recv_into(self, *args, **kwargs): + try: + return self.connection.recv_into(*args, **kwargs) + except OpenSSL.SSL.SysCallError as e: + if self.suppress_ragged_eofs and e.args == (-1, "Unexpected EOF"): + return 0 + else: + raise SocketError(str(e)) + except OpenSSL.SSL.ZeroReturnError: + if self.connection.get_shutdown() == OpenSSL.SSL.RECEIVED_SHUTDOWN: + return 0 + else: + raise + except OpenSSL.SSL.WantReadError: + if not util.wait_for_read(self.socket, self.socket.gettimeout()): + raise timeout("The read operation timed out") + else: + return self.recv_into(*args, **kwargs) + + # TLS 1.3 post-handshake authentication + except OpenSSL.SSL.Error as e: + raise ssl.SSLError("read error: %r" % e) + + def settimeout(self, timeout): + return self.socket.settimeout(timeout) + + def _send_until_done(self, data): + while True: + try: + return self.connection.send(data) + except OpenSSL.SSL.WantWriteError: + if not util.wait_for_write(self.socket, self.socket.gettimeout()): + raise timeout() + continue + except OpenSSL.SSL.SysCallError as e: + raise SocketError(str(e)) + + def sendall(self, data): + total_sent = 0 + while total_sent < len(data): + sent = self._send_until_done( + data[total_sent : total_sent + SSL_WRITE_BLOCKSIZE] + ) + total_sent += sent + + def shutdown(self): + # FIXME rethrow compatible exceptions should we ever use this + self.connection.shutdown() + + def close(self): + if self._makefile_refs < 1: + try: + self._closed = True + return self.connection.close() + except OpenSSL.SSL.Error: + return + else: + self._makefile_refs -= 1 + + def getpeercert(self, binary_form=False): + x509 = self.connection.get_peer_certificate() + + if not x509: + return x509 + + if binary_form: + return OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_ASN1, x509) + + return { + "subject": ((("commonName", x509.get_subject().CN),),), + "subjectAltName": get_subj_alt_name(x509), + } + + def version(self): + return self.connection.get_protocol_version_name() + + def _reuse(self): + self._makefile_refs += 1 + + def _drop(self): + if self._makefile_refs < 1: + self.close() + else: + self._makefile_refs -= 1 + + +if _fileobject: # Platform-specific: Python 2 + + def makefile(self, mode, bufsize=-1): + self._makefile_refs += 1 + return _fileobject(self, mode, bufsize, close=True) + + +else: # Platform-specific: Python 3 + makefile = backport_makefile + +WrappedSocket.makefile = makefile + + +class PyOpenSSLContext(object): + """ + I am a wrapper class for the PyOpenSSL ``Context`` object. I am responsible + for translating the interface of the standard library ``SSLContext`` object + to calls into PyOpenSSL. + """ + + def __init__(self, protocol): + self.protocol = _openssl_versions[protocol] + self._ctx = OpenSSL.SSL.Context(self.protocol) + self._options = 0 + self.check_hostname = False + + @property + def options(self): + return self._options + + @options.setter + def options(self, value): + self._options = value + self._ctx.set_options(value) + + @property + def verify_mode(self): + return _openssl_to_stdlib_verify[self._ctx.get_verify_mode()] + + @verify_mode.setter + def verify_mode(self, value): + self._ctx.set_verify(_stdlib_to_openssl_verify[value], _verify_callback) + + def set_default_verify_paths(self): + self._ctx.set_default_verify_paths() + + def set_ciphers(self, ciphers): + if isinstance(ciphers, six.text_type): + ciphers = ciphers.encode("utf-8") + self._ctx.set_cipher_list(ciphers) + + def load_verify_locations(self, cafile=None, capath=None, cadata=None): + if cafile is not None: + cafile = cafile.encode("utf-8") + if capath is not None: + capath = capath.encode("utf-8") + try: + self._ctx.load_verify_locations(cafile, capath) + if cadata is not None: + self._ctx.load_verify_locations(BytesIO(cadata)) + except OpenSSL.SSL.Error as e: + raise ssl.SSLError("unable to load trusted certificates: %r" % e) + + def load_cert_chain(self, certfile, keyfile=None, password=None): + self._ctx.use_certificate_chain_file(certfile) + if password is not None: + if not isinstance(password, six.binary_type): + password = password.encode("utf-8") + self._ctx.set_passwd_cb(lambda *_: password) + self._ctx.use_privatekey_file(keyfile or certfile) + + def set_alpn_protocols(self, protocols): + protocols = [six.ensure_binary(p) for p in protocols] + return self._ctx.set_alpn_protos(protocols) + + def wrap_socket( + self, + sock, + server_side=False, + do_handshake_on_connect=True, + suppress_ragged_eofs=True, + server_hostname=None, + ): + cnx = OpenSSL.SSL.Connection(self._ctx, sock) + + if isinstance(server_hostname, six.text_type): # Platform-specific: Python 3 + server_hostname = server_hostname.encode("utf-8") + + if server_hostname is not None: + cnx.set_tlsext_host_name(server_hostname) + + cnx.set_connect_state() + + while True: + try: + cnx.do_handshake() + except OpenSSL.SSL.WantReadError: + if not util.wait_for_read(sock, sock.gettimeout()): + raise timeout("select timed out") + continue + except OpenSSL.SSL.Error as e: + raise ssl.SSLError("bad handshake: %r" % e) + break + + return WrappedSocket(cnx, sock) + + +def _verify_callback(cnx, x509, err_no, err_depth, return_code): + return err_no == 0 diff --git a/venv/lib/python3.8/site-packages/urllib3/contrib/securetransport.py b/venv/lib/python3.8/site-packages/urllib3/contrib/securetransport.py new file mode 100644 index 0000000..554c015 --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3/contrib/securetransport.py @@ -0,0 +1,922 @@ +""" +SecureTranport support for urllib3 via ctypes. + +This makes platform-native TLS available to urllib3 users on macOS without the +use of a compiler. This is an important feature because the Python Package +Index is moving to become a TLSv1.2-or-higher server, and the default OpenSSL +that ships with macOS is not capable of doing TLSv1.2. The only way to resolve +this is to give macOS users an alternative solution to the problem, and that +solution is to use SecureTransport. + +We use ctypes here because this solution must not require a compiler. That's +because pip is not allowed to require a compiler either. + +This is not intended to be a seriously long-term solution to this problem. +The hope is that PEP 543 will eventually solve this issue for us, at which +point we can retire this contrib module. But in the short term, we need to +solve the impending tire fire that is Python on Mac without this kind of +contrib module. So...here we are. + +To use this module, simply import and inject it:: + + import urllib3.contrib.securetransport + urllib3.contrib.securetransport.inject_into_urllib3() + +Happy TLSing! + +This code is a bastardised version of the code found in Will Bond's oscrypto +library. An enormous debt is owed to him for blazing this trail for us. For +that reason, this code should be considered to be covered both by urllib3's +license and by oscrypto's: + +.. code-block:: + + Copyright (c) 2015-2016 Will Bond <will@wbond.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. +""" +from __future__ import absolute_import + +import contextlib +import ctypes +import errno +import os.path +import shutil +import socket +import ssl +import struct +import threading +import weakref + +import six + +from .. import util +from ..util.ssl_ import PROTOCOL_TLS_CLIENT +from ._securetransport.bindings import CoreFoundation, Security, SecurityConst +from ._securetransport.low_level import ( + _assert_no_error, + _build_tls_unknown_ca_alert, + _cert_array_from_pem, + _create_cfstring_array, + _load_client_cert_chain, + _temporary_keychain, +) + +try: # Platform-specific: Python 2 + from socket import _fileobject +except ImportError: # Platform-specific: Python 3 + _fileobject = None + from ..packages.backports.makefile import backport_makefile + +__all__ = ["inject_into_urllib3", "extract_from_urllib3"] + +# SNI always works +HAS_SNI = True + +orig_util_HAS_SNI = util.HAS_SNI +orig_util_SSLContext = util.ssl_.SSLContext + +# This dictionary is used by the read callback to obtain a handle to the +# calling wrapped socket. This is a pretty silly approach, but for now it'll +# do. I feel like I should be able to smuggle a handle to the wrapped socket +# directly in the SSLConnectionRef, but for now this approach will work I +# guess. +# +# We need to lock around this structure for inserts, but we don't do it for +# reads/writes in the callbacks. The reasoning here goes as follows: +# +# 1. It is not possible to call into the callbacks before the dictionary is +# populated, so once in the callback the id must be in the dictionary. +# 2. The callbacks don't mutate the dictionary, they only read from it, and +# so cannot conflict with any of the insertions. +# +# This is good: if we had to lock in the callbacks we'd drastically slow down +# the performance of this code. +_connection_refs = weakref.WeakValueDictionary() +_connection_ref_lock = threading.Lock() + +# Limit writes to 16kB. This is OpenSSL's limit, but we'll cargo-cult it over +# for no better reason than we need *a* limit, and this one is right there. +SSL_WRITE_BLOCKSIZE = 16384 + +# This is our equivalent of util.ssl_.DEFAULT_CIPHERS, but expanded out to +# individual cipher suites. We need to do this because this is how +# SecureTransport wants them. +CIPHER_SUITES = [ + SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + SecurityConst.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + SecurityConst.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + SecurityConst.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, + SecurityConst.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + SecurityConst.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, + SecurityConst.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, + SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, + SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, + SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + SecurityConst.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, + SecurityConst.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + SecurityConst.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, + SecurityConst.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + SecurityConst.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, + SecurityConst.TLS_DHE_RSA_WITH_AES_256_CBC_SHA, + SecurityConst.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, + SecurityConst.TLS_DHE_RSA_WITH_AES_128_CBC_SHA, + SecurityConst.TLS_AES_256_GCM_SHA384, + SecurityConst.TLS_AES_128_GCM_SHA256, + SecurityConst.TLS_RSA_WITH_AES_256_GCM_SHA384, + SecurityConst.TLS_RSA_WITH_AES_128_GCM_SHA256, + SecurityConst.TLS_AES_128_CCM_8_SHA256, + SecurityConst.TLS_AES_128_CCM_SHA256, + SecurityConst.TLS_RSA_WITH_AES_256_CBC_SHA256, + SecurityConst.TLS_RSA_WITH_AES_128_CBC_SHA256, + SecurityConst.TLS_RSA_WITH_AES_256_CBC_SHA, + SecurityConst.TLS_RSA_WITH_AES_128_CBC_SHA, +] + +# Basically this is simple: for PROTOCOL_SSLv23 we turn it into a low of +# TLSv1 and a high of TLSv1.2. For everything else, we pin to that version. +# TLSv1 to 1.2 are supported on macOS 10.8+ +_protocol_to_min_max = { + util.PROTOCOL_TLS: (SecurityConst.kTLSProtocol1, SecurityConst.kTLSProtocol12), + PROTOCOL_TLS_CLIENT: (SecurityConst.kTLSProtocol1, SecurityConst.kTLSProtocol12), +} + +if hasattr(ssl, "PROTOCOL_SSLv2"): + _protocol_to_min_max[ssl.PROTOCOL_SSLv2] = ( + SecurityConst.kSSLProtocol2, + SecurityConst.kSSLProtocol2, + ) +if hasattr(ssl, "PROTOCOL_SSLv3"): + _protocol_to_min_max[ssl.PROTOCOL_SSLv3] = ( + SecurityConst.kSSLProtocol3, + SecurityConst.kSSLProtocol3, + ) +if hasattr(ssl, "PROTOCOL_TLSv1"): + _protocol_to_min_max[ssl.PROTOCOL_TLSv1] = ( + SecurityConst.kTLSProtocol1, + SecurityConst.kTLSProtocol1, + ) +if hasattr(ssl, "PROTOCOL_TLSv1_1"): + _protocol_to_min_max[ssl.PROTOCOL_TLSv1_1] = ( + SecurityConst.kTLSProtocol11, + SecurityConst.kTLSProtocol11, + ) +if hasattr(ssl, "PROTOCOL_TLSv1_2"): + _protocol_to_min_max[ssl.PROTOCOL_TLSv1_2] = ( + SecurityConst.kTLSProtocol12, + SecurityConst.kTLSProtocol12, + ) + + +def inject_into_urllib3(): + """ + Monkey-patch urllib3 with SecureTransport-backed SSL-support. + """ + util.SSLContext = SecureTransportContext + util.ssl_.SSLContext = SecureTransportContext + util.HAS_SNI = HAS_SNI + util.ssl_.HAS_SNI = HAS_SNI + util.IS_SECURETRANSPORT = True + util.ssl_.IS_SECURETRANSPORT = True + + +def extract_from_urllib3(): + """ + Undo monkey-patching by :func:`inject_into_urllib3`. + """ + util.SSLContext = orig_util_SSLContext + util.ssl_.SSLContext = orig_util_SSLContext + util.HAS_SNI = orig_util_HAS_SNI + util.ssl_.HAS_SNI = orig_util_HAS_SNI + util.IS_SECURETRANSPORT = False + util.ssl_.IS_SECURETRANSPORT = False + + +def _read_callback(connection_id, data_buffer, data_length_pointer): + """ + SecureTransport read callback. This is called by ST to request that data + be returned from the socket. + """ + wrapped_socket = None + try: + wrapped_socket = _connection_refs.get(connection_id) + if wrapped_socket is None: + return SecurityConst.errSSLInternal + base_socket = wrapped_socket.socket + + requested_length = data_length_pointer[0] + + timeout = wrapped_socket.gettimeout() + error = None + read_count = 0 + + try: + while read_count < requested_length: + if timeout is None or timeout >= 0: + if not util.wait_for_read(base_socket, timeout): + raise socket.error(errno.EAGAIN, "timed out") + + remaining = requested_length - read_count + buffer = (ctypes.c_char * remaining).from_address( + data_buffer + read_count + ) + chunk_size = base_socket.recv_into(buffer, remaining) + read_count += chunk_size + if not chunk_size: + if not read_count: + return SecurityConst.errSSLClosedGraceful + break + except (socket.error) as e: + error = e.errno + + if error is not None and error != errno.EAGAIN: + data_length_pointer[0] = read_count + if error == errno.ECONNRESET or error == errno.EPIPE: + return SecurityConst.errSSLClosedAbort + raise + + data_length_pointer[0] = read_count + + if read_count != requested_length: + return SecurityConst.errSSLWouldBlock + + return 0 + except Exception as e: + if wrapped_socket is not None: + wrapped_socket._exception = e + return SecurityConst.errSSLInternal + + +def _write_callback(connection_id, data_buffer, data_length_pointer): + """ + SecureTransport write callback. This is called by ST to request that data + actually be sent on the network. + """ + wrapped_socket = None + try: + wrapped_socket = _connection_refs.get(connection_id) + if wrapped_socket is None: + return SecurityConst.errSSLInternal + base_socket = wrapped_socket.socket + + bytes_to_write = data_length_pointer[0] + data = ctypes.string_at(data_buffer, bytes_to_write) + + timeout = wrapped_socket.gettimeout() + error = None + sent = 0 + + try: + while sent < bytes_to_write: + if timeout is None or timeout >= 0: + if not util.wait_for_write(base_socket, timeout): + raise socket.error(errno.EAGAIN, "timed out") + chunk_sent = base_socket.send(data) + sent += chunk_sent + + # This has some needless copying here, but I'm not sure there's + # much value in optimising this data path. + data = data[chunk_sent:] + except (socket.error) as e: + error = e.errno + + if error is not None and error != errno.EAGAIN: + data_length_pointer[0] = sent + if error == errno.ECONNRESET or error == errno.EPIPE: + return SecurityConst.errSSLClosedAbort + raise + + data_length_pointer[0] = sent + + if sent != bytes_to_write: + return SecurityConst.errSSLWouldBlock + + return 0 + except Exception as e: + if wrapped_socket is not None: + wrapped_socket._exception = e + return SecurityConst.errSSLInternal + + +# We need to keep these two objects references alive: if they get GC'd while +# in use then SecureTransport could attempt to call a function that is in freed +# memory. That would be...uh...bad. Yeah, that's the word. Bad. +_read_callback_pointer = Security.SSLReadFunc(_read_callback) +_write_callback_pointer = Security.SSLWriteFunc(_write_callback) + + +class WrappedSocket(object): + """ + API-compatibility wrapper for Python's OpenSSL wrapped socket object. + + Note: _makefile_refs, _drop(), and _reuse() are needed for the garbage + collector of PyPy. + """ + + def __init__(self, socket): + self.socket = socket + self.context = None + self._makefile_refs = 0 + self._closed = False + self._exception = None + self._keychain = None + self._keychain_dir = None + self._client_cert_chain = None + + # We save off the previously-configured timeout and then set it to + # zero. This is done because we use select and friends to handle the + # timeouts, but if we leave the timeout set on the lower socket then + # Python will "kindly" call select on that socket again for us. Avoid + # that by forcing the timeout to zero. + self._timeout = self.socket.gettimeout() + self.socket.settimeout(0) + + @contextlib.contextmanager + def _raise_on_error(self): + """ + A context manager that can be used to wrap calls that do I/O from + SecureTransport. If any of the I/O callbacks hit an exception, this + context manager will correctly propagate the exception after the fact. + This avoids silently swallowing those exceptions. + + It also correctly forces the socket closed. + """ + self._exception = None + + # We explicitly don't catch around this yield because in the unlikely + # event that an exception was hit in the block we don't want to swallow + # it. + yield + if self._exception is not None: + exception, self._exception = self._exception, None + self.close() + raise exception + + def _set_ciphers(self): + """ + Sets up the allowed ciphers. By default this matches the set in + util.ssl_.DEFAULT_CIPHERS, at least as supported by macOS. This is done + custom and doesn't allow changing at this time, mostly because parsing + OpenSSL cipher strings is going to be a freaking nightmare. + """ + ciphers = (Security.SSLCipherSuite * len(CIPHER_SUITES))(*CIPHER_SUITES) + result = Security.SSLSetEnabledCiphers( + self.context, ciphers, len(CIPHER_SUITES) + ) + _assert_no_error(result) + + def _set_alpn_protocols(self, protocols): + """ + Sets up the ALPN protocols on the context. + """ + if not protocols: + return + protocols_arr = _create_cfstring_array(protocols) + try: + result = Security.SSLSetALPNProtocols(self.context, protocols_arr) + _assert_no_error(result) + finally: + CoreFoundation.CFRelease(protocols_arr) + + def _custom_validate(self, verify, trust_bundle): + """ + Called when we have set custom validation. We do this in two cases: + first, when cert validation is entirely disabled; and second, when + using a custom trust DB. + Raises an SSLError if the connection is not trusted. + """ + # If we disabled cert validation, just say: cool. + if not verify: + return + + successes = ( + SecurityConst.kSecTrustResultUnspecified, + SecurityConst.kSecTrustResultProceed, + ) + try: + trust_result = self._evaluate_trust(trust_bundle) + if trust_result in successes: + return + reason = "error code: %d" % (trust_result,) + except Exception as e: + # Do not trust on error + reason = "exception: %r" % (e,) + + # SecureTransport does not send an alert nor shuts down the connection. + rec = _build_tls_unknown_ca_alert(self.version()) + self.socket.sendall(rec) + # close the connection immediately + # l_onoff = 1, activate linger + # l_linger = 0, linger for 0 seoncds + opts = struct.pack("ii", 1, 0) + self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, opts) + self.close() + raise ssl.SSLError("certificate verify failed, %s" % reason) + + def _evaluate_trust(self, trust_bundle): + # We want data in memory, so load it up. + if os.path.isfile(trust_bundle): + with open(trust_bundle, "rb") as f: + trust_bundle = f.read() + + cert_array = None + trust = Security.SecTrustRef() + + try: + # Get a CFArray that contains the certs we want. + cert_array = _cert_array_from_pem(trust_bundle) + + # Ok, now the hard part. We want to get the SecTrustRef that ST has + # created for this connection, shove our CAs into it, tell ST to + # ignore everything else it knows, and then ask if it can build a + # chain. This is a buuuunch of code. + result = Security.SSLCopyPeerTrust(self.context, ctypes.byref(trust)) + _assert_no_error(result) + if not trust: + raise ssl.SSLError("Failed to copy trust reference") + + result = Security.SecTrustSetAnchorCertificates(trust, cert_array) + _assert_no_error(result) + + result = Security.SecTrustSetAnchorCertificatesOnly(trust, True) + _assert_no_error(result) + + trust_result = Security.SecTrustResultType() + result = Security.SecTrustEvaluate(trust, ctypes.byref(trust_result)) + _assert_no_error(result) + finally: + if trust: + CoreFoundation.CFRelease(trust) + + if cert_array is not None: + CoreFoundation.CFRelease(cert_array) + + return trust_result.value + + def handshake( + self, + server_hostname, + verify, + trust_bundle, + min_version, + max_version, + client_cert, + client_key, + client_key_passphrase, + alpn_protocols, + ): + """ + Actually performs the TLS handshake. This is run automatically by + wrapped socket, and shouldn't be needed in user code. + """ + # First, we do the initial bits of connection setup. We need to create + # a context, set its I/O funcs, and set the connection reference. + self.context = Security.SSLCreateContext( + None, SecurityConst.kSSLClientSide, SecurityConst.kSSLStreamType + ) + result = Security.SSLSetIOFuncs( + self.context, _read_callback_pointer, _write_callback_pointer + ) + _assert_no_error(result) + + # Here we need to compute the handle to use. We do this by taking the + # id of self modulo 2**31 - 1. If this is already in the dictionary, we + # just keep incrementing by one until we find a free space. + with _connection_ref_lock: + handle = id(self) % 2147483647 + while handle in _connection_refs: + handle = (handle + 1) % 2147483647 + _connection_refs[handle] = self + + result = Security.SSLSetConnection(self.context, handle) + _assert_no_error(result) + + # If we have a server hostname, we should set that too. + if server_hostname: + if not isinstance(server_hostname, bytes): + server_hostname = server_hostname.encode("utf-8") + + result = Security.SSLSetPeerDomainName( + self.context, server_hostname, len(server_hostname) + ) + _assert_no_error(result) + + # Setup the ciphers. + self._set_ciphers() + + # Setup the ALPN protocols. + self._set_alpn_protocols(alpn_protocols) + + # Set the minimum and maximum TLS versions. + result = Security.SSLSetProtocolVersionMin(self.context, min_version) + _assert_no_error(result) + + result = Security.SSLSetProtocolVersionMax(self.context, max_version) + _assert_no_error(result) + + # If there's a trust DB, we need to use it. We do that by telling + # SecureTransport to break on server auth. We also do that if we don't + # want to validate the certs at all: we just won't actually do any + # authing in that case. + if not verify or trust_bundle is not None: + result = Security.SSLSetSessionOption( + self.context, SecurityConst.kSSLSessionOptionBreakOnServerAuth, True + ) + _assert_no_error(result) + + # If there's a client cert, we need to use it. + if client_cert: + self._keychain, self._keychain_dir = _temporary_keychain() + self._client_cert_chain = _load_client_cert_chain( + self._keychain, client_cert, client_key + ) + result = Security.SSLSetCertificate(self.context, self._client_cert_chain) + _assert_no_error(result) + + while True: + with self._raise_on_error(): + result = Security.SSLHandshake(self.context) + + if result == SecurityConst.errSSLWouldBlock: + raise socket.timeout("handshake timed out") + elif result == SecurityConst.errSSLServerAuthCompleted: + self._custom_validate(verify, trust_bundle) + continue + else: + _assert_no_error(result) + break + + def fileno(self): + return self.socket.fileno() + + # Copy-pasted from Python 3.5 source code + def _decref_socketios(self): + if self._makefile_refs > 0: + self._makefile_refs -= 1 + if self._closed: + self.close() + + def recv(self, bufsiz): + buffer = ctypes.create_string_buffer(bufsiz) + bytes_read = self.recv_into(buffer, bufsiz) + data = buffer[:bytes_read] + return data + + def recv_into(self, buffer, nbytes=None): + # Read short on EOF. + if self._closed: + return 0 + + if nbytes is None: + nbytes = len(buffer) + + buffer = (ctypes.c_char * nbytes).from_buffer(buffer) + processed_bytes = ctypes.c_size_t(0) + + with self._raise_on_error(): + result = Security.SSLRead( + self.context, buffer, nbytes, ctypes.byref(processed_bytes) + ) + + # There are some result codes that we want to treat as "not always + # errors". Specifically, those are errSSLWouldBlock, + # errSSLClosedGraceful, and errSSLClosedNoNotify. + if result == SecurityConst.errSSLWouldBlock: + # If we didn't process any bytes, then this was just a time out. + # However, we can get errSSLWouldBlock in situations when we *did* + # read some data, and in those cases we should just read "short" + # and return. + if processed_bytes.value == 0: + # Timed out, no data read. + raise socket.timeout("recv timed out") + elif result in ( + SecurityConst.errSSLClosedGraceful, + SecurityConst.errSSLClosedNoNotify, + ): + # The remote peer has closed this connection. We should do so as + # well. Note that we don't actually return here because in + # principle this could actually be fired along with return data. + # It's unlikely though. + self.close() + else: + _assert_no_error(result) + + # Ok, we read and probably succeeded. We should return whatever data + # was actually read. + return processed_bytes.value + + def settimeout(self, timeout): + self._timeout = timeout + + def gettimeout(self): + return self._timeout + + def send(self, data): + processed_bytes = ctypes.c_size_t(0) + + with self._raise_on_error(): + result = Security.SSLWrite( + self.context, data, len(data), ctypes.byref(processed_bytes) + ) + + if result == SecurityConst.errSSLWouldBlock and processed_bytes.value == 0: + # Timed out + raise socket.timeout("send timed out") + else: + _assert_no_error(result) + + # We sent, and probably succeeded. Tell them how much we sent. + return processed_bytes.value + + def sendall(self, data): + total_sent = 0 + while total_sent < len(data): + sent = self.send(data[total_sent : total_sent + SSL_WRITE_BLOCKSIZE]) + total_sent += sent + + def shutdown(self): + with self._raise_on_error(): + Security.SSLClose(self.context) + + def close(self): + # TODO: should I do clean shutdown here? Do I have to? + if self._makefile_refs < 1: + self._closed = True + if self.context: + CoreFoundation.CFRelease(self.context) + self.context = None + if self._client_cert_chain: + CoreFoundation.CFRelease(self._client_cert_chain) + self._client_cert_chain = None + if self._keychain: + Security.SecKeychainDelete(self._keychain) + CoreFoundation.CFRelease(self._keychain) + shutil.rmtree(self._keychain_dir) + self._keychain = self._keychain_dir = None + return self.socket.close() + else: + self._makefile_refs -= 1 + + def getpeercert(self, binary_form=False): + # Urgh, annoying. + # + # Here's how we do this: + # + # 1. Call SSLCopyPeerTrust to get hold of the trust object for this + # connection. + # 2. Call SecTrustGetCertificateAtIndex for index 0 to get the leaf. + # 3. To get the CN, call SecCertificateCopyCommonName and process that + # string so that it's of the appropriate type. + # 4. To get the SAN, we need to do something a bit more complex: + # a. Call SecCertificateCopyValues to get the data, requesting + # kSecOIDSubjectAltName. + # b. Mess about with this dictionary to try to get the SANs out. + # + # This is gross. Really gross. It's going to be a few hundred LoC extra + # just to repeat something that SecureTransport can *already do*. So my + # operating assumption at this time is that what we want to do is + # instead to just flag to urllib3 that it shouldn't do its own hostname + # validation when using SecureTransport. + if not binary_form: + raise ValueError("SecureTransport only supports dumping binary certs") + trust = Security.SecTrustRef() + certdata = None + der_bytes = None + + try: + # Grab the trust store. + result = Security.SSLCopyPeerTrust(self.context, ctypes.byref(trust)) + _assert_no_error(result) + if not trust: + # Probably we haven't done the handshake yet. No biggie. + return None + + cert_count = Security.SecTrustGetCertificateCount(trust) + if not cert_count: + # Also a case that might happen if we haven't handshaked. + # Handshook? Handshaken? + return None + + leaf = Security.SecTrustGetCertificateAtIndex(trust, 0) + assert leaf + + # Ok, now we want the DER bytes. + certdata = Security.SecCertificateCopyData(leaf) + assert certdata + + data_length = CoreFoundation.CFDataGetLength(certdata) + data_buffer = CoreFoundation.CFDataGetBytePtr(certdata) + der_bytes = ctypes.string_at(data_buffer, data_length) + finally: + if certdata: + CoreFoundation.CFRelease(certdata) + if trust: + CoreFoundation.CFRelease(trust) + + return der_bytes + + def version(self): + protocol = Security.SSLProtocol() + result = Security.SSLGetNegotiatedProtocolVersion( + self.context, ctypes.byref(protocol) + ) + _assert_no_error(result) + if protocol.value == SecurityConst.kTLSProtocol13: + raise ssl.SSLError("SecureTransport does not support TLS 1.3") + elif protocol.value == SecurityConst.kTLSProtocol12: + return "TLSv1.2" + elif protocol.value == SecurityConst.kTLSProtocol11: + return "TLSv1.1" + elif protocol.value == SecurityConst.kTLSProtocol1: + return "TLSv1" + elif protocol.value == SecurityConst.kSSLProtocol3: + return "SSLv3" + elif protocol.value == SecurityConst.kSSLProtocol2: + return "SSLv2" + else: + raise ssl.SSLError("Unknown TLS version: %r" % protocol) + + def _reuse(self): + self._makefile_refs += 1 + + def _drop(self): + if self._makefile_refs < 1: + self.close() + else: + self._makefile_refs -= 1 + + +if _fileobject: # Platform-specific: Python 2 + + def makefile(self, mode, bufsize=-1): + self._makefile_refs += 1 + return _fileobject(self, mode, bufsize, close=True) + + +else: # Platform-specific: Python 3 + + def makefile(self, mode="r", buffering=None, *args, **kwargs): + # We disable buffering with SecureTransport because it conflicts with + # the buffering that ST does internally (see issue #1153 for more). + buffering = 0 + return backport_makefile(self, mode, buffering, *args, **kwargs) + + +WrappedSocket.makefile = makefile + + +class SecureTransportContext(object): + """ + I am a wrapper class for the SecureTransport library, to translate the + interface of the standard library ``SSLContext`` object to calls into + SecureTransport. + """ + + def __init__(self, protocol): + self._min_version, self._max_version = _protocol_to_min_max[protocol] + self._options = 0 + self._verify = False + self._trust_bundle = None + self._client_cert = None + self._client_key = None + self._client_key_passphrase = None + self._alpn_protocols = None + + @property + def check_hostname(self): + """ + SecureTransport cannot have its hostname checking disabled. For more, + see the comment on getpeercert() in this file. + """ + return True + + @check_hostname.setter + def check_hostname(self, value): + """ + SecureTransport cannot have its hostname checking disabled. For more, + see the comment on getpeercert() in this file. + """ + pass + + @property + def options(self): + # TODO: Well, crap. + # + # So this is the bit of the code that is the most likely to cause us + # trouble. Essentially we need to enumerate all of the SSL options that + # users might want to use and try to see if we can sensibly translate + # them, or whether we should just ignore them. + return self._options + + @options.setter + def options(self, value): + # TODO: Update in line with above. + self._options = value + + @property + def verify_mode(self): + return ssl.CERT_REQUIRED if self._verify else ssl.CERT_NONE + + @verify_mode.setter + def verify_mode(self, value): + self._verify = True if value == ssl.CERT_REQUIRED else False + + def set_default_verify_paths(self): + # So, this has to do something a bit weird. Specifically, what it does + # is nothing. + # + # This means that, if we had previously had load_verify_locations + # called, this does not undo that. We need to do that because it turns + # out that the rest of the urllib3 code will attempt to load the + # default verify paths if it hasn't been told about any paths, even if + # the context itself was sometime earlier. We resolve that by just + # ignoring it. + pass + + def load_default_certs(self): + return self.set_default_verify_paths() + + def set_ciphers(self, ciphers): + # For now, we just require the default cipher string. + if ciphers != util.ssl_.DEFAULT_CIPHERS: + raise ValueError("SecureTransport doesn't support custom cipher strings") + + def load_verify_locations(self, cafile=None, capath=None, cadata=None): + # OK, we only really support cadata and cafile. + if capath is not None: + raise ValueError("SecureTransport does not support cert directories") + + # Raise if cafile does not exist. + if cafile is not None: + with open(cafile): + pass + + self._trust_bundle = cafile or cadata + + def load_cert_chain(self, certfile, keyfile=None, password=None): + self._client_cert = certfile + self._client_key = keyfile + self._client_cert_passphrase = password + + def set_alpn_protocols(self, protocols): + """ + Sets the ALPN protocols that will later be set on the context. + + Raises a NotImplementedError if ALPN is not supported. + """ + if not hasattr(Security, "SSLSetALPNProtocols"): + raise NotImplementedError( + "SecureTransport supports ALPN only in macOS 10.12+" + ) + self._alpn_protocols = [six.ensure_binary(p) for p in protocols] + + def wrap_socket( + self, + sock, + server_side=False, + do_handshake_on_connect=True, + suppress_ragged_eofs=True, + server_hostname=None, + ): + # So, what do we do here? Firstly, we assert some properties. This is a + # stripped down shim, so there is some functionality we don't support. + # See PEP 543 for the real deal. + assert not server_side + assert do_handshake_on_connect + assert suppress_ragged_eofs + + # Ok, we're good to go. Now we want to create the wrapped socket object + # and store it in the appropriate place. + wrapped_socket = WrappedSocket(sock) + + # Now we can handshake + wrapped_socket.handshake( + server_hostname, + self._verify, + self._trust_bundle, + self._min_version, + self._max_version, + self._client_cert, + self._client_key, + self._client_key_passphrase, + self._alpn_protocols, + ) + return wrapped_socket diff --git a/venv/lib/python3.8/site-packages/urllib3/contrib/socks.py b/venv/lib/python3.8/site-packages/urllib3/contrib/socks.py new file mode 100644 index 0000000..c326e80 --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3/contrib/socks.py @@ -0,0 +1,216 @@ +# -*- coding: utf-8 -*- +""" +This module contains provisional support for SOCKS proxies from within +urllib3. This module supports SOCKS4, SOCKS4A (an extension of SOCKS4), and +SOCKS5. To enable its functionality, either install PySocks or install this +module with the ``socks`` extra. + +The SOCKS implementation supports the full range of urllib3 features. It also +supports the following SOCKS features: + +- SOCKS4A (``proxy_url='socks4a://...``) +- SOCKS4 (``proxy_url='socks4://...``) +- SOCKS5 with remote DNS (``proxy_url='socks5h://...``) +- SOCKS5 with local DNS (``proxy_url='socks5://...``) +- Usernames and passwords for the SOCKS proxy + +.. note:: + It is recommended to use ``socks5h://`` or ``socks4a://`` schemes in + your ``proxy_url`` to ensure that DNS resolution is done from the remote + server instead of client-side when connecting to a domain name. + +SOCKS4 supports IPv4 and domain names with the SOCKS4A extension. SOCKS5 +supports IPv4, IPv6, and domain names. + +When connecting to a SOCKS4 proxy the ``username`` portion of the ``proxy_url`` +will be sent as the ``userid`` section of the SOCKS request: + +.. code-block:: python + + proxy_url="socks4a://<userid>@proxy-host" + +When connecting to a SOCKS5 proxy the ``username`` and ``password`` portion +of the ``proxy_url`` will be sent as the username/password to authenticate +with the proxy: + +.. code-block:: python + + proxy_url="socks5h://<username>:<password>@proxy-host" + +""" +from __future__ import absolute_import + +try: + import socks +except ImportError: + import warnings + + from ..exceptions import DependencyWarning + + warnings.warn( + ( + "SOCKS support in urllib3 requires the installation of optional " + "dependencies: specifically, PySocks. For more information, see " + "https://urllib3.readthedocs.io/en/1.26.x/contrib.html#socks-proxies" + ), + DependencyWarning, + ) + raise + +from socket import error as SocketError +from socket import timeout as SocketTimeout + +from ..connection import HTTPConnection, HTTPSConnection +from ..connectionpool import HTTPConnectionPool, HTTPSConnectionPool +from ..exceptions import ConnectTimeoutError, NewConnectionError +from ..poolmanager import PoolManager +from ..util.url import parse_url + +try: + import ssl +except ImportError: + ssl = None + + +class SOCKSConnection(HTTPConnection): + """ + A plain-text HTTP connection that connects via a SOCKS proxy. + """ + + def __init__(self, *args, **kwargs): + self._socks_options = kwargs.pop("_socks_options") + super(SOCKSConnection, self).__init__(*args, **kwargs) + + def _new_conn(self): + """ + Establish a new connection via the SOCKS proxy. + """ + extra_kw = {} + if self.source_address: + extra_kw["source_address"] = self.source_address + + if self.socket_options: + extra_kw["socket_options"] = self.socket_options + + try: + conn = socks.create_connection( + (self.host, self.port), + proxy_type=self._socks_options["socks_version"], + proxy_addr=self._socks_options["proxy_host"], + proxy_port=self._socks_options["proxy_port"], + proxy_username=self._socks_options["username"], + proxy_password=self._socks_options["password"], + proxy_rdns=self._socks_options["rdns"], + timeout=self.timeout, + **extra_kw + ) + + except SocketTimeout: + raise ConnectTimeoutError( + self, + "Connection to %s timed out. (connect timeout=%s)" + % (self.host, self.timeout), + ) + + except socks.ProxyError as e: + # This is fragile as hell, but it seems to be the only way to raise + # useful errors here. + if e.socket_err: + error = e.socket_err + if isinstance(error, SocketTimeout): + raise ConnectTimeoutError( + self, + "Connection to %s timed out. (connect timeout=%s)" + % (self.host, self.timeout), + ) + else: + raise NewConnectionError( + self, "Failed to establish a new connection: %s" % error + ) + else: + raise NewConnectionError( + self, "Failed to establish a new connection: %s" % e + ) + + except SocketError as e: # Defensive: PySocks should catch all these. + raise NewConnectionError( + self, "Failed to establish a new connection: %s" % e + ) + + return conn + + +# We don't need to duplicate the Verified/Unverified distinction from +# urllib3/connection.py here because the HTTPSConnection will already have been +# correctly set to either the Verified or Unverified form by that module. This +# means the SOCKSHTTPSConnection will automatically be the correct type. +class SOCKSHTTPSConnection(SOCKSConnection, HTTPSConnection): + pass + + +class SOCKSHTTPConnectionPool(HTTPConnectionPool): + ConnectionCls = SOCKSConnection + + +class SOCKSHTTPSConnectionPool(HTTPSConnectionPool): + ConnectionCls = SOCKSHTTPSConnection + + +class SOCKSProxyManager(PoolManager): + """ + A version of the urllib3 ProxyManager that routes connections via the + defined SOCKS proxy. + """ + + pool_classes_by_scheme = { + "http": SOCKSHTTPConnectionPool, + "https": SOCKSHTTPSConnectionPool, + } + + def __init__( + self, + proxy_url, + username=None, + password=None, + num_pools=10, + headers=None, + **connection_pool_kw + ): + parsed = parse_url(proxy_url) + + if username is None and password is None and parsed.auth is not None: + split = parsed.auth.split(":") + if len(split) == 2: + username, password = split + if parsed.scheme == "socks5": + socks_version = socks.PROXY_TYPE_SOCKS5 + rdns = False + elif parsed.scheme == "socks5h": + socks_version = socks.PROXY_TYPE_SOCKS5 + rdns = True + elif parsed.scheme == "socks4": + socks_version = socks.PROXY_TYPE_SOCKS4 + rdns = False + elif parsed.scheme == "socks4a": + socks_version = socks.PROXY_TYPE_SOCKS4 + rdns = True + else: + raise ValueError("Unable to determine SOCKS version from %s" % proxy_url) + + self.proxy_url = proxy_url + + socks_options = { + "socks_version": socks_version, + "proxy_host": parsed.host, + "proxy_port": parsed.port, + "username": username, + "password": password, + "rdns": rdns, + } + connection_pool_kw["_socks_options"] = socks_options + + super(SOCKSProxyManager, self).__init__( + num_pools, headers, **connection_pool_kw + ) + + self.pool_classes_by_scheme = SOCKSProxyManager.pool_classes_by_scheme diff --git a/venv/lib/python3.8/site-packages/urllib3/exceptions.py b/venv/lib/python3.8/site-packages/urllib3/exceptions.py new file mode 100644 index 0000000..cba6f3f --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3/exceptions.py @@ -0,0 +1,323 @@ +from __future__ import absolute_import + +from .packages.six.moves.http_client import IncompleteRead as httplib_IncompleteRead + +# Base Exceptions + + +class HTTPError(Exception): + """Base exception used by this module.""" + + pass + + +class HTTPWarning(Warning): + """Base warning used by this module.""" + + pass + + +class PoolError(HTTPError): + """Base exception for errors caused within a pool.""" + + def __init__(self, pool, message): + self.pool = pool + HTTPError.__init__(self, "%s: %s" % (pool, message)) + + def __reduce__(self): + # For pickling purposes. + return self.__class__, (None, None) + + +class RequestError(PoolError): + """Base exception for PoolErrors that have associated URLs.""" + + def __init__(self, pool, url, message): + self.url = url + PoolError.__init__(self, pool, message) + + def __reduce__(self): + # For pickling purposes. + return self.__class__, (None, self.url, None) + + +class SSLError(HTTPError): + """Raised when SSL certificate fails in an HTTPS connection.""" + + pass + + +class ProxyError(HTTPError): + """Raised when the connection to a proxy fails.""" + + def __init__(self, message, error, *args): + super(ProxyError, self).__init__(message, error, *args) + self.original_error = error + + +class DecodeError(HTTPError): + """Raised when automatic decoding based on Content-Type fails.""" + + pass + + +class ProtocolError(HTTPError): + """Raised when something unexpected happens mid-request/response.""" + + pass + + +#: Renamed to ProtocolError but aliased for backwards compatibility. +ConnectionError = ProtocolError + + +# Leaf Exceptions + + +class MaxRetryError(RequestError): + """Raised when the maximum number of retries is exceeded. + + :param pool: The connection pool + :type pool: :class:`~urllib3.connectionpool.HTTPConnectionPool` + :param string url: The requested Url + :param exceptions.Exception reason: The underlying error + + """ + + def __init__(self, pool, url, reason=None): + self.reason = reason + + message = "Max retries exceeded with url: %s (Caused by %r)" % (url, reason) + + RequestError.__init__(self, pool, url, message) + + +class HostChangedError(RequestError): + """Raised when an existing pool gets a request for a foreign host.""" + + def __init__(self, pool, url, retries=3): + message = "Tried to open a foreign host with url: %s" % url + RequestError.__init__(self, pool, url, message) + self.retries = retries + + +class TimeoutStateError(HTTPError): + """Raised when passing an invalid state to a timeout""" + + pass + + +class TimeoutError(HTTPError): + """Raised when a socket timeout error occurs. + + Catching this error will catch both :exc:`ReadTimeoutErrors + <ReadTimeoutError>` and :exc:`ConnectTimeoutErrors <ConnectTimeoutError>`. + """ + + pass + + +class ReadTimeoutError(TimeoutError, RequestError): + """Raised when a socket timeout occurs while receiving data from a server""" + + pass + + +# This timeout error does not have a URL attached and needs to inherit from the +# base HTTPError +class ConnectTimeoutError(TimeoutError): + """Raised when a socket timeout occurs while connecting to a server""" + + pass + + +class NewConnectionError(ConnectTimeoutError, PoolError): + """Raised when we fail to establish a new connection. Usually ECONNREFUSED.""" + + pass + + +class EmptyPoolError(PoolError): + """Raised when a pool runs out of connections and no more are allowed.""" + + pass + + +class ClosedPoolError(PoolError): + """Raised when a request enters a pool after the pool has been closed.""" + + pass + + +class LocationValueError(ValueError, HTTPError): + """Raised when there is something wrong with a given URL input.""" + + pass + + +class LocationParseError(LocationValueError): + """Raised when get_host or similar fails to parse the URL input.""" + + def __init__(self, location): + message = "Failed to parse: %s" % location + HTTPError.__init__(self, message) + + self.location = location + + +class URLSchemeUnknown(LocationValueError): + """Raised when a URL input has an unsupported scheme.""" + + def __init__(self, scheme): + message = "Not supported URL scheme %s" % scheme + super(URLSchemeUnknown, self).__init__(message) + + self.scheme = scheme + + +class ResponseError(HTTPError): + """Used as a container for an error reason supplied in a MaxRetryError.""" + + GENERIC_ERROR = "too many error responses" + SPECIFIC_ERROR = "too many {status_code} error responses" + + +class SecurityWarning(HTTPWarning): + """Warned when performing security reducing actions""" + + pass + + +class SubjectAltNameWarning(SecurityWarning): + """Warned when connecting to a host with a certificate missing a SAN.""" + + pass + + +class InsecureRequestWarning(SecurityWarning): + """Warned when making an unverified HTTPS request.""" + + pass + + +class SystemTimeWarning(SecurityWarning): + """Warned when system time is suspected to be wrong""" + + pass + + +class InsecurePlatformWarning(SecurityWarning): + """Warned when certain TLS/SSL configuration is not available on a platform.""" + + pass + + +class SNIMissingWarning(HTTPWarning): + """Warned when making a HTTPS request without SNI available.""" + + pass + + +class DependencyWarning(HTTPWarning): + """ + Warned when an attempt is made to import a module with missing optional + dependencies. + """ + + pass + + +class ResponseNotChunked(ProtocolError, ValueError): + """Response needs to be chunked in order to read it as chunks.""" + + pass + + +class BodyNotHttplibCompatible(HTTPError): + """ + Body should be :class:`http.client.HTTPResponse` like + (have an fp attribute which returns raw chunks) for read_chunked(). + """ + + pass + + +class IncompleteRead(HTTPError, httplib_IncompleteRead): + """ + Response length doesn't match expected Content-Length + + Subclass of :class:`http.client.IncompleteRead` to allow int value + for ``partial`` to avoid creating large objects on streamed reads. + """ + + def __init__(self, partial, expected): + super(IncompleteRead, self).__init__(partial, expected) + + def __repr__(self): + return "IncompleteRead(%i bytes read, %i more expected)" % ( + self.partial, + self.expected, + ) + + +class InvalidChunkLength(HTTPError, httplib_IncompleteRead): + """Invalid chunk length in a chunked response.""" + + def __init__(self, response, length): + super(InvalidChunkLength, self).__init__( + response.tell(), response.length_remaining + ) + self.response = response + self.length = length + + def __repr__(self): + return "InvalidChunkLength(got length %r, %i bytes read)" % ( + self.length, + self.partial, + ) + + +class InvalidHeader(HTTPError): + """The header provided was somehow invalid.""" + + pass + + +class ProxySchemeUnknown(AssertionError, URLSchemeUnknown): + """ProxyManager does not support the supplied scheme""" + + # TODO(t-8ch): Stop inheriting from AssertionError in v2.0. + + def __init__(self, scheme): + # 'localhost' is here because our URL parser parses + # localhost:8080 -> scheme=localhost, remove if we fix this. + if scheme == "localhost": + scheme = None + if scheme is None: + message = "Proxy URL had no scheme, should start with http:// or https://" + else: + message = ( + "Proxy URL had unsupported scheme %s, should use http:// or https://" + % scheme + ) + super(ProxySchemeUnknown, self).__init__(message) + + +class ProxySchemeUnsupported(ValueError): + """Fetching HTTPS resources through HTTPS proxies is unsupported""" + + pass + + +class HeaderParsingError(HTTPError): + """Raised by assert_header_parsing, but we convert it to a log.warning statement.""" + + def __init__(self, defects, unparsed_data): + message = "%s, unparsed data: %r" % (defects or "Unknown", unparsed_data) + super(HeaderParsingError, self).__init__(message) + + +class UnrewindableBodyError(HTTPError): + """urllib3 encountered an error when trying to rewind a body""" + + pass diff --git a/venv/lib/python3.8/site-packages/urllib3/fields.py b/venv/lib/python3.8/site-packages/urllib3/fields.py new file mode 100644 index 0000000..9d630f4 --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3/fields.py @@ -0,0 +1,274 @@ +from __future__ import absolute_import + +import email.utils +import mimetypes +import re + +from .packages import six + + +def guess_content_type(filename, default="application/octet-stream"): + """ + Guess the "Content-Type" of a file. + + :param filename: + The filename to guess the "Content-Type" of using :mod:`mimetypes`. + :param default: + If no "Content-Type" can be guessed, default to `default`. + """ + if filename: + return mimetypes.guess_type(filename)[0] or default + return default + + +def format_header_param_rfc2231(name, value): + """ + Helper function to format and quote a single header parameter using the + strategy defined in RFC 2231. + + Particularly useful for header parameters which might contain + non-ASCII values, like file names. This follows + `RFC 2388 Section 4.4 <https://tools.ietf.org/html/rfc2388#section-4.4>`_. + + :param name: + The name of the parameter, a string expected to be ASCII only. + :param value: + The value of the parameter, provided as ``bytes`` or `str``. + :ret: + An RFC-2231-formatted unicode string. + """ + if isinstance(value, six.binary_type): + value = value.decode("utf-8") + + if not any(ch in value for ch in '"\\\r\n'): + result = u'%s="%s"' % (name, value) + try: + result.encode("ascii") + except (UnicodeEncodeError, UnicodeDecodeError): + pass + else: + return result + + if six.PY2: # Python 2: + value = value.encode("utf-8") + + # encode_rfc2231 accepts an encoded string and returns an ascii-encoded + # string in Python 2 but accepts and returns unicode strings in Python 3 + value = email.utils.encode_rfc2231(value, "utf-8") + value = "%s*=%s" % (name, value) + + if six.PY2: # Python 2: + value = value.decode("utf-8") + + return value + + +_HTML5_REPLACEMENTS = { + u"\u0022": u"%22", + # Replace "\" with "\\". + u"\u005C": u"\u005C\u005C", +} + +# All control characters from 0x00 to 0x1F *except* 0x1B. +_HTML5_REPLACEMENTS.update( + { + six.unichr(cc): u"%{:02X}".format(cc) + for cc in range(0x00, 0x1F + 1) + if cc not in (0x1B,) + } +) + + +def _replace_multiple(value, needles_and_replacements): + def replacer(match): + return needles_and_replacements[match.group(0)] + + pattern = re.compile( + r"|".join([re.escape(needle) for needle in needles_and_replacements.keys()]) + ) + + result = pattern.sub(replacer, value) + + return result + + +def format_header_param_html5(name, value): + """ + Helper function to format and quote a single header parameter using the + HTML5 strategy. + + Particularly useful for header parameters which might contain + non-ASCII values, like file names. This follows the `HTML5 Working Draft + Section 4.10.22.7`_ and matches the behavior of curl and modern browsers. + + .. _HTML5 Working Draft Section 4.10.22.7: + https://w3c.github.io/html/sec-forms.html#multipart-form-data + + :param name: + The name of the parameter, a string expected to be ASCII only. + :param value: + The value of the parameter, provided as ``bytes`` or `str``. + :ret: + A unicode string, stripped of troublesome characters. + """ + if isinstance(value, six.binary_type): + value = value.decode("utf-8") + + value = _replace_multiple(value, _HTML5_REPLACEMENTS) + + return u'%s="%s"' % (name, value) + + +# For backwards-compatibility. +format_header_param = format_header_param_html5 + + +class RequestField(object): + """ + A data container for request body parameters. + + :param name: + The name of this request field. Must be unicode. + :param data: + The data/value body. + :param filename: + An optional filename of the request field. Must be unicode. + :param headers: + An optional dict-like object of headers to initially use for the field. + :param header_formatter: + An optional callable that is used to encode and format the headers. By + default, this is :func:`format_header_param_html5`. + """ + + def __init__( + self, + name, + data, + filename=None, + headers=None, + header_formatter=format_header_param_html5, + ): + self._name = name + self._filename = filename + self.data = data + self.headers = {} + if headers: + self.headers = dict(headers) + self.header_formatter = header_formatter + + @classmethod + def from_tuples(cls, fieldname, value, header_formatter=format_header_param_html5): + """ + A :class:`~urllib3.fields.RequestField` factory from old-style tuple parameters. + + Supports constructing :class:`~urllib3.fields.RequestField` from + parameter of key/value strings AND key/filetuple. A filetuple is a + (filename, data, MIME type) tuple where the MIME type is optional. + For example:: + + 'foo': 'bar', + 'fakefile': ('foofile.txt', 'contents of foofile'), + 'realfile': ('barfile.txt', open('realfile').read()), + 'typedfile': ('bazfile.bin', open('bazfile').read(), 'image/jpeg'), + 'nonamefile': 'contents of nonamefile field', + + Field names and filenames must be unicode. + """ + if isinstance(value, tuple): + if len(value) == 3: + filename, data, content_type = value + else: + filename, data = value + content_type = guess_content_type(filename) + else: + filename = None + content_type = None + data = value + + request_param = cls( + fieldname, data, filename=filename, header_formatter=header_formatter + ) + request_param.make_multipart(content_type=content_type) + + return request_param + + def _render_part(self, name, value): + """ + Overridable helper function to format a single header parameter. By + default, this calls ``self.header_formatter``. + + :param name: + The name of the parameter, a string expected to be ASCII only. + :param value: + The value of the parameter, provided as a unicode string. + """ + + return self.header_formatter(name, value) + + def _render_parts(self, header_parts): + """ + Helper function to format and quote a single header. + + Useful for single headers that are composed of multiple items. E.g., + 'Content-Disposition' fields. + + :param header_parts: + A sequence of (k, v) tuples or a :class:`dict` of (k, v) to format + as `k1="v1"; k2="v2"; ...`. + """ + parts = [] + iterable = header_parts + if isinstance(header_parts, dict): + iterable = header_parts.items() + + for name, value in iterable: + if value is not None: + parts.append(self._render_part(name, value)) + + return u"; ".join(parts) + + def render_headers(self): + """ + Renders the headers for this request field. + """ + lines = [] + + sort_keys = ["Content-Disposition", "Content-Type", "Content-Location"] + for sort_key in sort_keys: + if self.headers.get(sort_key, False): + lines.append(u"%s: %s" % (sort_key, self.headers[sort_key])) + + for header_name, header_value in self.headers.items(): + if header_name not in sort_keys: + if header_value: + lines.append(u"%s: %s" % (header_name, header_value)) + + lines.append(u"\r\n") + return u"\r\n".join(lines) + + def make_multipart( + self, content_disposition=None, content_type=None, content_location=None + ): + """ + Makes this request field into a multipart request field. + + This method overrides "Content-Disposition", "Content-Type" and + "Content-Location" headers to the request parameter. + + :param content_type: + The 'Content-Type' of the request body. + :param content_location: + The 'Content-Location' of the request body. + + """ + self.headers["Content-Disposition"] = content_disposition or u"form-data" + self.headers["Content-Disposition"] += u"; ".join( + [ + u"", + self._render_parts( + ((u"name", self._name), (u"filename", self._filename)) + ), + ] + ) + self.headers["Content-Type"] = content_type + self.headers["Content-Location"] = content_location diff --git a/venv/lib/python3.8/site-packages/urllib3/filepost.py b/venv/lib/python3.8/site-packages/urllib3/filepost.py new file mode 100644 index 0000000..36c9252 --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3/filepost.py @@ -0,0 +1,98 @@ +from __future__ import absolute_import + +import binascii +import codecs +import os +from io import BytesIO + +from .fields import RequestField +from .packages import six +from .packages.six import b + +writer = codecs.lookup("utf-8")[3] + + +def choose_boundary(): + """ + Our embarrassingly-simple replacement for mimetools.choose_boundary. + """ + boundary = binascii.hexlify(os.urandom(16)) + if not six.PY2: + boundary = boundary.decode("ascii") + return boundary + + +def iter_field_objects(fields): + """ + Iterate over fields. + + Supports list of (k, v) tuples and dicts, and lists of + :class:`~urllib3.fields.RequestField`. + + """ + if isinstance(fields, dict): + i = six.iteritems(fields) + else: + i = iter(fields) + + for field in i: + if isinstance(field, RequestField): + yield field + else: + yield RequestField.from_tuples(*field) + + +def iter_fields(fields): + """ + .. deprecated:: 1.6 + + Iterate over fields. + + The addition of :class:`~urllib3.fields.RequestField` makes this function + obsolete. Instead, use :func:`iter_field_objects`, which returns + :class:`~urllib3.fields.RequestField` objects. + + Supports list of (k, v) tuples and dicts. + """ + if isinstance(fields, dict): + return ((k, v) for k, v in six.iteritems(fields)) + + return ((k, v) for k, v in fields) + + +def encode_multipart_formdata(fields, boundary=None): + """ + Encode a dictionary of ``fields`` using the multipart/form-data MIME format. + + :param fields: + Dictionary of fields or list of (key, :class:`~urllib3.fields.RequestField`). + + :param boundary: + If not specified, then a random boundary will be generated using + :func:`urllib3.filepost.choose_boundary`. + """ + body = BytesIO() + if boundary is None: + boundary = choose_boundary() + + for field in iter_field_objects(fields): + body.write(b("--%s\r\n" % (boundary))) + + writer(body).write(field.render_headers()) + data = field.data + + if isinstance(data, int): + data = str(data) # Backwards compatibility + + if isinstance(data, six.text_type): + writer(body).write(data) + else: + body.write(data) + + body.write(b"\r\n") + + body.write(b("--%s--\r\n" % (boundary))) + + content_type = str("multipart/form-data; boundary=%s" % boundary) + + return body.getvalue(), content_type diff --git a/venv/lib/python3.8/site-packages/urllib3/packages/__init__.py b/venv/lib/python3.8/site-packages/urllib3/packages/__init__.py new file mode 100644 index 0000000..fce4caa --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3/packages/__init__.py @@ -0,0 +1,5 @@ +from __future__ import absolute_import + +from . import ssl_match_hostname + +__all__ = ("ssl_match_hostname",) diff --git a/venv/lib/python3.8/site-packages/urllib3/packages/backports/__init__.py b/venv/lib/python3.8/site-packages/urllib3/packages/backports/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.8/site-packages/urllib3/packages/backports/makefile.py b/venv/lib/python3.8/site-packages/urllib3/packages/backports/makefile.py new file mode 100644 index 0000000..b8fb215 --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3/packages/backports/makefile.py @@ -0,0 +1,51 @@ +# -*- coding: utf-8 -*- +""" +backports.makefile +~~~~~~~~~~~~~~~~~~ + +Backports the Python 3 ``socket.makefile`` method for use with anything that +wants to create a "fake" socket object. +""" +import io +from socket import SocketIO + + +def backport_makefile( + self, mode="r", buffering=None, encoding=None, errors=None, newline=None +): + """ + Backport of ``socket.makefile`` from Python 3.5. + """ + if not set(mode) <= {"r", "w", "b"}: + raise ValueError("invalid mode %r (only r, w, b allowed)" % (mode,)) + writing = "w" in mode + reading = "r" in mode or not writing + assert reading or writing + binary = "b" in mode + rawmode = "" + if reading: + rawmode += "r" + if writing: + rawmode += "w" + raw = SocketIO(self, rawmode) + self._makefile_refs += 1 + if buffering is None: + buffering = -1 + if buffering < 0: + buffering = io.DEFAULT_BUFFER_SIZE + if buffering == 0: + if not binary: + raise ValueError("unbuffered streams must be binary") + return raw + if reading and writing: + buffer = io.BufferedRWPair(raw, raw, buffering) + elif reading: + buffer = io.BufferedReader(raw, buffering) + else: + assert writing + buffer = io.BufferedWriter(raw, buffering) + if binary: + return buffer + text = io.TextIOWrapper(buffer, encoding, errors, newline) + text.mode = mode + return text diff --git a/venv/lib/python3.8/site-packages/urllib3/packages/six.py b/venv/lib/python3.8/site-packages/urllib3/packages/six.py new file mode 100644 index 0000000..ba50acb --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3/packages/six.py @@ -0,0 +1,1077 @@ +# Copyright (c) 2010-2020 Benjamin Peterson +# +# 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. + +"""Utilities for writing code that runs on Python 2 and 3""" + +from __future__ import absolute_import + +import functools +import itertools +import operator +import sys +import types + +__author__ = "Benjamin Peterson <benjamin@python.org>" +__version__ = "1.16.0" + + +# Useful for very coarse version differentiation. +PY2 = sys.version_info[0] == 2 +PY3 = sys.version_info[0] == 3 +PY34 = sys.version_info[0:2] >= (3, 4) + +if PY3: + string_types = (str,) + integer_types = (int,) + class_types = (type,) + text_type = str + binary_type = bytes + + MAXSIZE = sys.maxsize +else: + string_types = (basestring,) + integer_types = (int, long) + class_types = (type, types.ClassType) + text_type = unicode + binary_type = str + + if sys.platform.startswith("java"): + # Jython always uses 32 bits. + MAXSIZE = int((1 << 31) - 1) + else: + # It's possible to have sizeof(long) != sizeof(Py_ssize_t). + class X(object): + def __len__(self): + return 1 << 31 + + try: + len(X()) + except OverflowError: + # 32-bit + MAXSIZE = int((1 << 31) - 1) + else: + # 64-bit + MAXSIZE = int((1 << 63) - 1) + del X + +if PY34: + from importlib.util import spec_from_loader +else: + spec_from_loader = None + + +def _add_doc(func, doc): + """Add documentation to a function.""" + func.__doc__ = doc + + +def _import_module(name): + """Import module, returning the module after the last dot.""" + __import__(name) + return sys.modules[name] + + +class _LazyDescr(object): + def __init__(self, name): + self.name = name + + def __get__(self, obj, tp): + result = self._resolve() + setattr(obj, self.name, result) # Invokes __set__. + try: + # This is a bit ugly, but it avoids running this again by + # removing this descriptor. + delattr(obj.__class__, self.name) + except AttributeError: + pass + return result + + +class MovedModule(_LazyDescr): + def __init__(self, name, old, new=None): + super(MovedModule, self).__init__(name) + if PY3: + if new is None: + new = name + self.mod = new + else: + self.mod = old + + def _resolve(self): + return _import_module(self.mod) + + def __getattr__(self, attr): + _module = self._resolve() + value = getattr(_module, attr) + setattr(self, attr, value) + return value + + +class _LazyModule(types.ModuleType): + def __init__(self, name): + super(_LazyModule, self).__init__(name) + self.__doc__ = self.__class__.__doc__ + + def __dir__(self): + attrs = ["__doc__", "__name__"] + attrs += [attr.name for attr in self._moved_attributes] + return attrs + + # Subclasses should override this + _moved_attributes = [] + + +class MovedAttribute(_LazyDescr): + def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None): + super(MovedAttribute, self).__init__(name) + if PY3: + if new_mod is None: + new_mod = name + self.mod = new_mod + if new_attr is None: + if old_attr is None: + new_attr = name + else: + new_attr = old_attr + self.attr = new_attr + else: + self.mod = old_mod + if old_attr is None: + old_attr = name + self.attr = old_attr + + def _resolve(self): + module = _import_module(self.mod) + return getattr(module, self.attr) + + +class _SixMetaPathImporter(object): + + """ + A meta path importer to import six.moves and its submodules. + + This class implements a PEP302 finder and loader. It should be compatible + with Python 2.5 and all existing versions of Python3 + """ + + def __init__(self, six_module_name): + self.name = six_module_name + self.known_modules = {} + + def _add_module(self, mod, *fullnames): + for fullname in fullnames: + self.known_modules[self.name + "." + fullname] = mod + + def _get_module(self, fullname): + return self.known_modules[self.name + "." + fullname] + + def find_module(self, fullname, path=None): + if fullname in self.known_modules: + return self + return None + + def find_spec(self, fullname, path, target=None): + if fullname in self.known_modules: + return spec_from_loader(fullname, self) + return None + + def __get_module(self, fullname): + try: + return self.known_modules[fullname] + except KeyError: + raise ImportError("This loader does not know module " + fullname) + + def load_module(self, fullname): + try: + # in case of a reload + return sys.modules[fullname] + except KeyError: + pass + mod = self.__get_module(fullname) + if isinstance(mod, MovedModule): + mod = mod._resolve() + else: + mod.__loader__ = self + sys.modules[fullname] = mod + return mod + + def is_package(self, fullname): + """ + Return true, if the named module is a package. + + We need this method to get correct spec objects with + Python 3.4 (see PEP451) + """ + return hasattr(self.__get_module(fullname), "__path__") + + def get_code(self, fullname): + """Return None + + Required, if is_package is implemented""" + self.__get_module(fullname) # eventually raises ImportError + return None + + get_source = get_code # same as get_code + + def create_module(self, spec): + return self.load_module(spec.name) + + def exec_module(self, module): + pass + + +_importer = _SixMetaPathImporter(__name__) + + +class _MovedItems(_LazyModule): + + """Lazy loading of moved objects""" + + __path__ = [] # mark as package + + +_moved_attributes = [ + MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"), + MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"), + MovedAttribute( + "filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse" + ), + MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"), + MovedAttribute("intern", "__builtin__", "sys"), + MovedAttribute("map", "itertools", "builtins", "imap", "map"), + MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"), + MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"), + MovedAttribute("getoutput", "commands", "subprocess"), + MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"), + MovedAttribute( + "reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload" + ), + MovedAttribute("reduce", "__builtin__", "functools"), + MovedAttribute("shlex_quote", "pipes", "shlex", "quote"), + MovedAttribute("StringIO", "StringIO", "io"), + MovedAttribute("UserDict", "UserDict", "collections"), + MovedAttribute("UserList", "UserList", "collections"), + MovedAttribute("UserString", "UserString", "collections"), + MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"), + MovedAttribute("zip", "itertools", "builtins", "izip", "zip"), + MovedAttribute( + "zip_longest", "itertools", "itertools", "izip_longest", "zip_longest" + ), + MovedModule("builtins", "__builtin__"), + MovedModule("configparser", "ConfigParser"), + MovedModule( + "collections_abc", + "collections", + "collections.abc" if sys.version_info >= (3, 3) else "collections", + ), + MovedModule("copyreg", "copy_reg"), + MovedModule("dbm_gnu", "gdbm", "dbm.gnu"), + MovedModule("dbm_ndbm", "dbm", "dbm.ndbm"), + MovedModule( + "_dummy_thread", + "dummy_thread", + "_dummy_thread" if sys.version_info < (3, 9) else "_thread", + ), + MovedModule("http_cookiejar", "cookielib", "http.cookiejar"), + MovedModule("http_cookies", "Cookie", "http.cookies"), + MovedModule("html_entities", "htmlentitydefs", "html.entities"), + MovedModule("html_parser", "HTMLParser", "html.parser"), + MovedModule("http_client", "httplib", "http.client"), + MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"), + MovedModule("email_mime_image", "email.MIMEImage", "email.mime.image"), + MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"), + MovedModule( + "email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart" + ), + MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"), + MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"), + MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"), + MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"), + MovedModule("cPickle", "cPickle", "pickle"), + MovedModule("queue", "Queue"), + MovedModule("reprlib", "repr"), + MovedModule("socketserver", "SocketServer"), + MovedModule("_thread", "thread", "_thread"), + MovedModule("tkinter", "Tkinter"), + MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"), + MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"), + MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"), + MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"), + MovedModule("tkinter_tix", "Tix", "tkinter.tix"), + MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"), + MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"), + MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"), + MovedModule("tkinter_colorchooser", "tkColorChooser", "tkinter.colorchooser"), + MovedModule("tkinter_commondialog", "tkCommonDialog", "tkinter.commondialog"), + MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"), + MovedModule("tkinter_font", "tkFont", "tkinter.font"), + MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"), + MovedModule("tkinter_tksimpledialog", "tkSimpleDialog", "tkinter.simpledialog"), + MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"), + MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"), + MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"), + MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"), + MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"), + MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"), +] +# Add windows specific modules. +if sys.platform == "win32": + _moved_attributes += [ + MovedModule("winreg", "_winreg"), + ] + +for attr in _moved_attributes: + setattr(_MovedItems, attr.name, attr) + if isinstance(attr, MovedModule): + _importer._add_module(attr, "moves." + attr.name) +del attr + +_MovedItems._moved_attributes = _moved_attributes + +moves = _MovedItems(__name__ + ".moves") +_importer._add_module(moves, "moves") + + +class Module_six_moves_urllib_parse(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_parse""" + + +_urllib_parse_moved_attributes = [ + MovedAttribute("ParseResult", "urlparse", "urllib.parse"), + MovedAttribute("SplitResult", "urlparse", "urllib.parse"), + MovedAttribute("parse_qs", "urlparse", "urllib.parse"), + MovedAttribute("parse_qsl", "urlparse", "urllib.parse"), + MovedAttribute("urldefrag", "urlparse", "urllib.parse"), + MovedAttribute("urljoin", "urlparse", "urllib.parse"), + MovedAttribute("urlparse", "urlparse", "urllib.parse"), + MovedAttribute("urlsplit", "urlparse", "urllib.parse"), + MovedAttribute("urlunparse", "urlparse", "urllib.parse"), + MovedAttribute("urlunsplit", "urlparse", "urllib.parse"), + MovedAttribute("quote", "urllib", "urllib.parse"), + MovedAttribute("quote_plus", "urllib", "urllib.parse"), + MovedAttribute("unquote", "urllib", "urllib.parse"), + MovedAttribute("unquote_plus", "urllib", "urllib.parse"), + MovedAttribute( + "unquote_to_bytes", "urllib", "urllib.parse", "unquote", "unquote_to_bytes" + ), + MovedAttribute("urlencode", "urllib", "urllib.parse"), + MovedAttribute("splitquery", "urllib", "urllib.parse"), + MovedAttribute("splittag", "urllib", "urllib.parse"), + MovedAttribute("splituser", "urllib", "urllib.parse"), + MovedAttribute("splitvalue", "urllib", "urllib.parse"), + MovedAttribute("uses_fragment", "urlparse", "urllib.parse"), + MovedAttribute("uses_netloc", "urlparse", "urllib.parse"), + MovedAttribute("uses_params", "urlparse", "urllib.parse"), + MovedAttribute("uses_query", "urlparse", "urllib.parse"), + MovedAttribute("uses_relative", "urlparse", "urllib.parse"), +] +for attr in _urllib_parse_moved_attributes: + setattr(Module_six_moves_urllib_parse, attr.name, attr) +del attr + +Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes + +_importer._add_module( + Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"), + "moves.urllib_parse", + "moves.urllib.parse", +) + + +class Module_six_moves_urllib_error(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_error""" + + +_urllib_error_moved_attributes = [ + MovedAttribute("URLError", "urllib2", "urllib.error"), + MovedAttribute("HTTPError", "urllib2", "urllib.error"), + MovedAttribute("ContentTooShortError", "urllib", "urllib.error"), +] +for attr in _urllib_error_moved_attributes: + setattr(Module_six_moves_urllib_error, attr.name, attr) +del attr + +Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes + +_importer._add_module( + Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"), + "moves.urllib_error", + "moves.urllib.error", +) + + +class Module_six_moves_urllib_request(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_request""" + + +_urllib_request_moved_attributes = [ + MovedAttribute("urlopen", "urllib2", "urllib.request"), + MovedAttribute("install_opener", "urllib2", "urllib.request"), + MovedAttribute("build_opener", "urllib2", "urllib.request"), + MovedAttribute("pathname2url", "urllib", "urllib.request"), + MovedAttribute("url2pathname", "urllib", "urllib.request"), + MovedAttribute("getproxies", "urllib", "urllib.request"), + MovedAttribute("Request", "urllib2", "urllib.request"), + MovedAttribute("OpenerDirector", "urllib2", "urllib.request"), + MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"), + MovedAttribute("ProxyHandler", "urllib2", "urllib.request"), + MovedAttribute("BaseHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"), + MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"), + MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"), + MovedAttribute("FileHandler", "urllib2", "urllib.request"), + MovedAttribute("FTPHandler", "urllib2", "urllib.request"), + MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"), + MovedAttribute("UnknownHandler", "urllib2", "urllib.request"), + MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"), + MovedAttribute("urlretrieve", "urllib", "urllib.request"), + MovedAttribute("urlcleanup", "urllib", "urllib.request"), + MovedAttribute("URLopener", "urllib", "urllib.request"), + MovedAttribute("FancyURLopener", "urllib", "urllib.request"), + MovedAttribute("proxy_bypass", "urllib", "urllib.request"), + MovedAttribute("parse_http_list", "urllib2", "urllib.request"), + MovedAttribute("parse_keqv_list", "urllib2", "urllib.request"), +] +for attr in _urllib_request_moved_attributes: + setattr(Module_six_moves_urllib_request, attr.name, attr) +del attr + +Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes + +_importer._add_module( + Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"), + "moves.urllib_request", + "moves.urllib.request", +) + + +class Module_six_moves_urllib_response(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_response""" + + +_urllib_response_moved_attributes = [ + MovedAttribute("addbase", "urllib", "urllib.response"), + MovedAttribute("addclosehook", "urllib", "urllib.response"), + MovedAttribute("addinfo", "urllib", "urllib.response"), + MovedAttribute("addinfourl", "urllib", "urllib.response"), +] +for attr in _urllib_response_moved_attributes: + setattr(Module_six_moves_urllib_response, attr.name, attr) +del attr + +Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes + +_importer._add_module( + Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"), + "moves.urllib_response", + "moves.urllib.response", +) + + +class Module_six_moves_urllib_robotparser(_LazyModule): + + """Lazy loading of moved objects in six.moves.urllib_robotparser""" + + +_urllib_robotparser_moved_attributes = [ + MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"), +] +for attr in _urllib_robotparser_moved_attributes: + setattr(Module_six_moves_urllib_robotparser, attr.name, attr) +del attr + +Module_six_moves_urllib_robotparser._moved_attributes = ( + _urllib_robotparser_moved_attributes +) + +_importer._add_module( + Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"), + "moves.urllib_robotparser", + "moves.urllib.robotparser", +) + + +class Module_six_moves_urllib(types.ModuleType): + + """Create a six.moves.urllib namespace that resembles the Python 3 namespace""" + + __path__ = [] # mark as package + parse = _importer._get_module("moves.urllib_parse") + error = _importer._get_module("moves.urllib_error") + request = _importer._get_module("moves.urllib_request") + response = _importer._get_module("moves.urllib_response") + robotparser = _importer._get_module("moves.urllib_robotparser") + + def __dir__(self): + return ["parse", "error", "request", "response", "robotparser"] + + +_importer._add_module( + Module_six_moves_urllib(__name__ + ".moves.urllib"), "moves.urllib" +) + + +def add_move(move): + """Add an item to six.moves.""" + setattr(_MovedItems, move.name, move) + + +def remove_move(name): + """Remove item from six.moves.""" + try: + delattr(_MovedItems, name) + except AttributeError: + try: + del moves.__dict__[name] + except KeyError: + raise AttributeError("no such move, %r" % (name,)) + + +if PY3: + _meth_func = "__func__" + _meth_self = "__self__" + + _func_closure = "__closure__" + _func_code = "__code__" + _func_defaults = "__defaults__" + _func_globals = "__globals__" +else: + _meth_func = "im_func" + _meth_self = "im_self" + + _func_closure = "func_closure" + _func_code = "func_code" + _func_defaults = "func_defaults" + _func_globals = "func_globals" + + +try: + advance_iterator = next +except NameError: + + def advance_iterator(it): + return it.next() + + +next = advance_iterator + + +try: + callable = callable +except NameError: + + def callable(obj): + return any("__call__" in klass.__dict__ for klass in type(obj).__mro__) + + +if PY3: + + def get_unbound_function(unbound): + return unbound + + create_bound_method = types.MethodType + + def create_unbound_method(func, cls): + return func + + Iterator = object +else: + + def get_unbound_function(unbound): + return unbound.im_func + + def create_bound_method(func, obj): + return types.MethodType(func, obj, obj.__class__) + + def create_unbound_method(func, cls): + return types.MethodType(func, None, cls) + + class Iterator(object): + def next(self): + return type(self).__next__(self) + + callable = callable +_add_doc( + get_unbound_function, """Get the function out of a possibly unbound function""" +) + + +get_method_function = operator.attrgetter(_meth_func) +get_method_self = operator.attrgetter(_meth_self) +get_function_closure = operator.attrgetter(_func_closure) +get_function_code = operator.attrgetter(_func_code) +get_function_defaults = operator.attrgetter(_func_defaults) +get_function_globals = operator.attrgetter(_func_globals) + + +if PY3: + + def iterkeys(d, **kw): + return iter(d.keys(**kw)) + + def itervalues(d, **kw): + return iter(d.values(**kw)) + + def iteritems(d, **kw): + return iter(d.items(**kw)) + + def iterlists(d, **kw): + return iter(d.lists(**kw)) + + viewkeys = operator.methodcaller("keys") + + viewvalues = operator.methodcaller("values") + + viewitems = operator.methodcaller("items") +else: + + def iterkeys(d, **kw): + return d.iterkeys(**kw) + + def itervalues(d, **kw): + return d.itervalues(**kw) + + def iteritems(d, **kw): + return d.iteritems(**kw) + + def iterlists(d, **kw): + return d.iterlists(**kw) + + viewkeys = operator.methodcaller("viewkeys") + + viewvalues = operator.methodcaller("viewvalues") + + viewitems = operator.methodcaller("viewitems") + +_add_doc(iterkeys, "Return an iterator over the keys of a dictionary.") +_add_doc(itervalues, "Return an iterator over the values of a dictionary.") +_add_doc(iteritems, "Return an iterator over the (key, value) pairs of a dictionary.") +_add_doc( + iterlists, "Return an iterator over the (key, [values]) pairs of a dictionary." +) + + +if PY3: + + def b(s): + return s.encode("latin-1") + + def u(s): + return s + + unichr = chr + import struct + + int2byte = struct.Struct(">B").pack + del struct + byte2int = operator.itemgetter(0) + indexbytes = operator.getitem + iterbytes = iter + import io + + StringIO = io.StringIO + BytesIO = io.BytesIO + del io + _assertCountEqual = "assertCountEqual" + if sys.version_info[1] <= 1: + _assertRaisesRegex = "assertRaisesRegexp" + _assertRegex = "assertRegexpMatches" + _assertNotRegex = "assertNotRegexpMatches" + else: + _assertRaisesRegex = "assertRaisesRegex" + _assertRegex = "assertRegex" + _assertNotRegex = "assertNotRegex" +else: + + def b(s): + return s + + # Workaround for standalone backslash + + def u(s): + return unicode(s.replace(r"\\", r"\\\\"), "unicode_escape") + + unichr = unichr + int2byte = chr + + def byte2int(bs): + return ord(bs[0]) + + def indexbytes(buf, i): + return ord(buf[i]) + + iterbytes = functools.partial(itertools.imap, ord) + import StringIO + + StringIO = BytesIO = StringIO.StringIO + _assertCountEqual = "assertItemsEqual" + _assertRaisesRegex = "assertRaisesRegexp" + _assertRegex = "assertRegexpMatches" + _assertNotRegex = "assertNotRegexpMatches" +_add_doc(b, """Byte literal""") +_add_doc(u, """Text literal""") + + +def assertCountEqual(self, *args, **kwargs): + return getattr(self, _assertCountEqual)(*args, **kwargs) + + +def assertRaisesRegex(self, *args, **kwargs): + return getattr(self, _assertRaisesRegex)(*args, **kwargs) + + +def assertRegex(self, *args, **kwargs): + return getattr(self, _assertRegex)(*args, **kwargs) + + +def assertNotRegex(self, *args, **kwargs): + return getattr(self, _assertNotRegex)(*args, **kwargs) + + +if PY3: + exec_ = getattr(moves.builtins, "exec") + + def reraise(tp, value, tb=None): + try: + if value is None: + value = tp() + if value.__traceback__ is not tb: + raise value.with_traceback(tb) + raise value + finally: + value = None + tb = None + + +else: + + def exec_(_code_, _globs_=None, _locs_=None): + """Execute code in a namespace.""" + if _globs_ is None: + frame = sys._getframe(1) + _globs_ = frame.f_globals + if _locs_ is None: + _locs_ = frame.f_locals + del frame + elif _locs_ is None: + _locs_ = _globs_ + exec ("""exec _code_ in _globs_, _locs_""") + + exec_( + """def reraise(tp, value, tb=None): + try: + raise tp, value, tb + finally: + tb = None +""" + ) + + +if sys.version_info[:2] > (3,): + exec_( + """def raise_from(value, from_value): + try: + raise value from from_value + finally: + value = None +""" + ) +else: + + def raise_from(value, from_value): + raise value + + +print_ = getattr(moves.builtins, "print", None) +if print_ is None: + + def print_(*args, **kwargs): + """The new-style print function for Python 2.4 and 2.5.""" + fp = kwargs.pop("file", sys.stdout) + if fp is None: + return + + def write(data): + if not isinstance(data, basestring): + data = str(data) + # If the file has an encoding, encode unicode with it. + if ( + isinstance(fp, file) + and isinstance(data, unicode) + and fp.encoding is not None + ): + errors = getattr(fp, "errors", None) + if errors is None: + errors = "strict" + data = data.encode(fp.encoding, errors) + fp.write(data) + + want_unicode = False + sep = kwargs.pop("sep", None) + if sep is not None: + if isinstance(sep, unicode): + want_unicode = True + elif not isinstance(sep, str): + raise TypeError("sep must be None or a string") + end = kwargs.pop("end", None) + if end is not None: + if isinstance(end, unicode): + want_unicode = True + elif not isinstance(end, str): + raise TypeError("end must be None or a string") + if kwargs: + raise TypeError("invalid keyword arguments to print()") + if not want_unicode: + for arg in args: + if isinstance(arg, unicode): + want_unicode = True + break + if want_unicode: + newline = unicode("\n") + space = unicode(" ") + else: + newline = "\n" + space = " " + if sep is None: + sep = space + if end is None: + end = newline + for i, arg in enumerate(args): + if i: + write(sep) + write(arg) + write(end) + + +if sys.version_info[:2] < (3, 3): + _print = print_ + + def print_(*args, **kwargs): + fp = kwargs.get("file", sys.stdout) + flush = kwargs.pop("flush", False) + _print(*args, **kwargs) + if flush and fp is not None: + fp.flush() + + +_add_doc(reraise, """Reraise an exception.""") + +if sys.version_info[0:2] < (3, 4): + # This does exactly the same what the :func:`py3:functools.update_wrapper` + # function does on Python versions after 3.2. It sets the ``__wrapped__`` + # attribute on ``wrapper`` object and it doesn't raise an error if any of + # the attributes mentioned in ``assigned`` and ``updated`` are missing on + # ``wrapped`` object. + def _update_wrapper( + wrapper, + wrapped, + assigned=functools.WRAPPER_ASSIGNMENTS, + updated=functools.WRAPPER_UPDATES, + ): + for attr in assigned: + try: + value = getattr(wrapped, attr) + except AttributeError: + continue + else: + setattr(wrapper, attr, value) + for attr in updated: + getattr(wrapper, attr).update(getattr(wrapped, attr, {})) + wrapper.__wrapped__ = wrapped + return wrapper + + _update_wrapper.__doc__ = functools.update_wrapper.__doc__ + + def wraps( + wrapped, + assigned=functools.WRAPPER_ASSIGNMENTS, + updated=functools.WRAPPER_UPDATES, + ): + return functools.partial( + _update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated + ) + + wraps.__doc__ = functools.wraps.__doc__ + +else: + wraps = functools.wraps + + +def with_metaclass(meta, *bases): + """Create a base class with a metaclass.""" + # This requires a bit of explanation: the basic idea is to make a dummy + # metaclass for one level of class instantiation that replaces itself with + # the actual metaclass. + class metaclass(type): + def __new__(cls, name, this_bases, d): + if sys.version_info[:2] >= (3, 7): + # This version introduced PEP 560 that requires a bit + # of extra care (we mimic what is done by __build_class__). + resolved_bases = types.resolve_bases(bases) + if resolved_bases is not bases: + d["__orig_bases__"] = bases + else: + resolved_bases = bases + return meta(name, resolved_bases, d) + + @classmethod + def __prepare__(cls, name, this_bases): + return meta.__prepare__(name, bases) + + return type.__new__(metaclass, "temporary_class", (), {}) + + +def add_metaclass(metaclass): + """Class decorator for creating a class with a metaclass.""" + + def wrapper(cls): + orig_vars = cls.__dict__.copy() + slots = orig_vars.get("__slots__") + if slots is not None: + if isinstance(slots, str): + slots = [slots] + for slots_var in slots: + orig_vars.pop(slots_var) + orig_vars.pop("__dict__", None) + orig_vars.pop("__weakref__", None) + if hasattr(cls, "__qualname__"): + orig_vars["__qualname__"] = cls.__qualname__ + return metaclass(cls.__name__, cls.__bases__, orig_vars) + + return wrapper + + +def ensure_binary(s, encoding="utf-8", errors="strict"): + """Coerce **s** to six.binary_type. + + For Python 2: + - `unicode` -> encoded to `str` + - `str` -> `str` + + For Python 3: + - `str` -> encoded to `bytes` + - `bytes` -> `bytes` + """ + if isinstance(s, binary_type): + return s + if isinstance(s, text_type): + return s.encode(encoding, errors) + raise TypeError("not expecting type '%s'" % type(s)) + + +def ensure_str(s, encoding="utf-8", errors="strict"): + """Coerce *s* to `str`. + + For Python 2: + - `unicode` -> encoded to `str` + - `str` -> `str` + + For Python 3: + - `str` -> `str` + - `bytes` -> decoded to `str` + """ + # Optimization: Fast return for the common case. + if type(s) is str: + return s + if PY2 and isinstance(s, text_type): + return s.encode(encoding, errors) + elif PY3 and isinstance(s, binary_type): + return s.decode(encoding, errors) + elif not isinstance(s, (text_type, binary_type)): + raise TypeError("not expecting type '%s'" % type(s)) + return s + + +def ensure_text(s, encoding="utf-8", errors="strict"): + """Coerce *s* to six.text_type. + + For Python 2: + - `unicode` -> `unicode` + - `str` -> `unicode` + + For Python 3: + - `str` -> `str` + - `bytes` -> decoded to `str` + """ + if isinstance(s, binary_type): + return s.decode(encoding, errors) + elif isinstance(s, text_type): + return s + else: + raise TypeError("not expecting type '%s'" % type(s)) + + +def python_2_unicode_compatible(klass): + """ + A class decorator that defines __unicode__ and __str__ methods under Python 2. + Under Python 3 it does nothing. + + To support Python 2 and 3 with a single code base, define a __str__ method + returning text and apply this decorator to the class. + """ + if PY2: + if "__str__" not in klass.__dict__: + raise ValueError( + "@python_2_unicode_compatible cannot be applied " + "to %s because it doesn't define __str__()." % klass.__name__ + ) + klass.__unicode__ = klass.__str__ + klass.__str__ = lambda self: self.__unicode__().encode("utf-8") + return klass + + +# Complete the moves implementation. +# This code is at the end of this module to speed up module loading. +# Turn this module into a package. +__path__ = [] # required for PEP 302 and PEP 451 +__package__ = __name__ # see PEP 366 @ReservedAssignment +if globals().get("__spec__") is not None: + __spec__.submodule_search_locations = [] # PEP 451 @UndefinedVariable +# Remove other six meta path importers, since they cause problems. This can +# happen if six is removed from sys.modules and then reloaded. (Setuptools does +# this for some reason.) +if sys.meta_path: + for i, importer in enumerate(sys.meta_path): + # Here's some real nastiness: Another "instance" of the six module might + # be floating around. Therefore, we can't use isinstance() to check for + # the six meta path importer, since the other six instance will have + # inserted an importer with different class. + if ( + type(importer).__name__ == "_SixMetaPathImporter" + and importer.name == __name__ + ): + del sys.meta_path[i] + break + del i, importer +# Finally, add the importer to the meta path import hook. +sys.meta_path.append(_importer) diff --git a/venv/lib/python3.8/site-packages/urllib3/packages/ssl_match_hostname/__init__.py b/venv/lib/python3.8/site-packages/urllib3/packages/ssl_match_hostname/__init__.py new file mode 100644 index 0000000..ef3fde5 --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3/packages/ssl_match_hostname/__init__.py @@ -0,0 +1,24 @@ +import sys + +try: + # Our match_hostname function is the same as 3.10's, so we only want to + # import the match_hostname function if it's at least that good. + # We also fallback on Python 3.10+ because our code doesn't emit + # deprecation warnings and is the same as Python 3.10 otherwise. + if sys.version_info < (3, 5) or sys.version_info >= (3, 10): + raise ImportError("Fallback to vendored code") + + from ssl import CertificateError, match_hostname +except ImportError: + try: + # Backport of the function from a pypi module + from backports.ssl_match_hostname import ( # type: ignore + CertificateError, + match_hostname, + ) + except ImportError: + # Our vendored copy + from ._implementation import CertificateError, match_hostname # type: ignore + +# Not needed, but documenting what we provide. +__all__ = ("CertificateError", "match_hostname") diff --git a/venv/lib/python3.8/site-packages/urllib3/packages/ssl_match_hostname/_implementation.py b/venv/lib/python3.8/site-packages/urllib3/packages/ssl_match_hostname/_implementation.py new file mode 100644 index 0000000..689208d --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3/packages/ssl_match_hostname/_implementation.py @@ -0,0 +1,160 @@ +"""The match_hostname() function from Python 3.3.3, essential when using SSL.""" + +# Note: This file is under the PSF license as the code comes from the python +# stdlib. http://docs.python.org/3/license.html + +import re +import sys + +# ipaddress has been backported to 2.6+ in pypi. If it is installed on the +# system, use it to handle IPAddress ServerAltnames (this was added in +# python-3.5) otherwise only do DNS matching. This allows +# backports.ssl_match_hostname to continue to be used in Python 2.7. +try: + import ipaddress +except ImportError: + ipaddress = None + +__version__ = "3.5.0.1" + + +class CertificateError(ValueError): + pass + + +def _dnsname_match(dn, hostname, max_wildcards=1): + """Matching according to RFC 6125, section 6.4.3 + + http://tools.ietf.org/html/rfc6125#section-6.4.3 + """ + pats = [] + if not dn: + return False + + # Ported from python3-syntax: + # leftmost, *remainder = dn.split(r'.') + parts = dn.split(r".") + leftmost = parts[0] + remainder = parts[1:] + + wildcards = leftmost.count("*") + if wildcards > max_wildcards: + # Issue #17980: avoid denials of service by refusing more + # than one wildcard per fragment. A survey of established + # policy among SSL implementations showed it to be a + # reasonable choice. + raise CertificateError( + "too many wildcards in certificate DNS name: " + repr(dn) + ) + + # speed up common case w/o wildcards + if not wildcards: + return dn.lower() == hostname.lower() + + # RFC 6125, section 6.4.3, subitem 1. + # The client SHOULD NOT attempt to match a presented identifier in which + # the wildcard character comprises a label other than the left-most label. + if leftmost == "*": + # When '*' is a fragment by itself, it matches a non-empty dotless + # fragment. + pats.append("[^.]+") + elif leftmost.startswith("xn--") or hostname.startswith("xn--"): + # RFC 6125, section 6.4.3, subitem 3. + # The client SHOULD NOT attempt to match a presented identifier + # where the wildcard character is embedded within an A-label or + # U-label of an internationalized domain name. + pats.append(re.escape(leftmost)) + else: + # Otherwise, '*' matches any dotless string, e.g. www* + pats.append(re.escape(leftmost).replace(r"\*", "[^.]*")) + + # add the remaining fragments, ignore any wildcards + for frag in remainder: + pats.append(re.escape(frag)) + + pat = re.compile(r"\A" + r"\.".join(pats) + r"\Z", re.IGNORECASE) + return pat.match(hostname) + + +def _to_unicode(obj): + if isinstance(obj, str) and sys.version_info < (3,): + obj = unicode(obj, encoding="ascii", errors="strict") + return obj + + +def _ipaddress_match(ipname, host_ip): + """Exact matching of IP addresses. + + RFC 6125 explicitly doesn't define an algorithm for this + (section 1.7.2 - "Out of Scope"). + """ + # OpenSSL may add a trailing newline to a subjectAltName's IP address + # Divergence from upstream: ipaddress can't handle byte str + ip = ipaddress.ip_address(_to_unicode(ipname).rstrip()) + return ip == host_ip + + +def match_hostname(cert, hostname): + """Verify that *cert* (in decoded format as returned by + SSLSocket.getpeercert()) matches the *hostname*. RFC 2818 and RFC 6125 + rules are followed, but IP addresses are not accepted for *hostname*. + + CertificateError is raised on failure. On success, the function + returns nothing. + """ + if not cert: + raise ValueError( + "empty or no certificate, match_hostname needs a " + "SSL socket or SSL context with either " + "CERT_OPTIONAL or CERT_REQUIRED" + ) + try: + # Divergence from upstream: ipaddress can't handle byte str + host_ip = ipaddress.ip_address(_to_unicode(hostname)) + except ValueError: + # Not an IP address (common case) + host_ip = None + except UnicodeError: + # Divergence from upstream: Have to deal with ipaddress not taking + # byte strings. addresses should be all ascii, so we consider it not + # an ipaddress in this case + host_ip = None + except AttributeError: + # Divergence from upstream: Make ipaddress library optional + if ipaddress is None: + host_ip = None + else: + raise + dnsnames = [] + san = cert.get("subjectAltName", ()) + for key, value in san: + if key == "DNS": + if host_ip is None and _dnsname_match(value, hostname): + return + dnsnames.append(value) + elif key == "IP Address": + if host_ip is not None and _ipaddress_match(value, host_ip): + return + dnsnames.append(value) + if not dnsnames: + # The subject is only checked when there is no dNSName entry + # in subjectAltName + for sub in cert.get("subject", ()): + for key, value in sub: + # XXX according to RFC 2818, the most specific Common Name + # must be used. + if key == "commonName": + if _dnsname_match(value, hostname): + return + dnsnames.append(value) + if len(dnsnames) > 1: + raise CertificateError( + "hostname %r " + "doesn't match either of %s" % (hostname, ", ".join(map(repr, dnsnames))) + ) + elif len(dnsnames) == 1: + raise CertificateError("hostname %r doesn't match %r" % (hostname, dnsnames[0])) + else: + raise CertificateError( + "no appropriate commonName or subjectAltName fields were found" + ) diff --git a/venv/lib/python3.8/site-packages/urllib3/poolmanager.py b/venv/lib/python3.8/site-packages/urllib3/poolmanager.py new file mode 100644 index 0000000..3a31a28 --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3/poolmanager.py @@ -0,0 +1,536 @@ +from __future__ import absolute_import + +import collections +import functools +import logging + +from ._collections import RecentlyUsedContainer +from .connectionpool import HTTPConnectionPool, HTTPSConnectionPool, port_by_scheme +from .exceptions import ( + LocationValueError, + MaxRetryError, + ProxySchemeUnknown, + ProxySchemeUnsupported, + URLSchemeUnknown, +) +from .packages import six +from .packages.six.moves.urllib.parse import urljoin +from .request import RequestMethods +from .util.proxy import connection_requires_http_tunnel +from .util.retry import Retry +from .util.url import parse_url + +__all__ = ["PoolManager", "ProxyManager", "proxy_from_url"] + + +log = logging.getLogger(__name__) + +SSL_KEYWORDS = ( + "key_file", + "cert_file", + "cert_reqs", + "ca_certs", + "ssl_version", + "ca_cert_dir", + "ssl_context", + "key_password", +) + +# All known keyword arguments that could be provided to the pool manager, its +# pools, or the underlying connections. This is used to construct a pool key. +_key_fields = ( + "key_scheme", # str + "key_host", # str + "key_port", # int + "key_timeout", # int or float or Timeout + "key_retries", # int or Retry + "key_strict", # bool + "key_block", # bool + "key_source_address", # str + "key_key_file", # str + "key_key_password", # str + "key_cert_file", # str + "key_cert_reqs", # str + "key_ca_certs", # str + "key_ssl_version", # str + "key_ca_cert_dir", # str + "key_ssl_context", # instance of ssl.SSLContext or urllib3.util.ssl_.SSLContext + "key_maxsize", # int + "key_headers", # dict + "key__proxy", # parsed proxy url + "key__proxy_headers", # dict + "key__proxy_config", # class + "key_socket_options", # list of (level (int), optname (int), value (int or str)) tuples + "key__socks_options", # dict + "key_assert_hostname", # bool or string + "key_assert_fingerprint", # str + "key_server_hostname", # str +) + +#: The namedtuple class used to construct keys for the connection pool. +#: All custom key schemes should include the fields in this key at a minimum. +PoolKey = collections.namedtuple("PoolKey", _key_fields) + +_proxy_config_fields = ("ssl_context", "use_forwarding_for_https") +ProxyConfig = collections.namedtuple("ProxyConfig", _proxy_config_fields) + + +def _default_key_normalizer(key_class, request_context): + """ + Create a pool key out of a request context dictionary. + + According to RFC 3986, both the scheme and host are case-insensitive. + Therefore, this function normalizes both before constructing the pool + key for an HTTPS request. If you wish to change this behaviour, provide + alternate callables to ``key_fn_by_scheme``. + + :param key_class: + The class to use when constructing the key. This should be a namedtuple + with the ``scheme`` and ``host`` keys at a minimum. + :type key_class: namedtuple + :param request_context: + A dictionary-like object that contain the context for a request. + :type request_context: dict + + :return: A namedtuple that can be used as a connection pool key. + :rtype: PoolKey + """ + # Since we mutate the dictionary, make a copy first + context = request_context.copy() + context["scheme"] = context["scheme"].lower() + context["host"] = context["host"].lower() + + # These are both dictionaries and need to be transformed into frozensets + for key in ("headers", "_proxy_headers", "_socks_options"): + if key in context and context[key] is not None: + context[key] = frozenset(context[key].items()) + + # The socket_options key may be a list and needs to be transformed into a + # tuple. + socket_opts = context.get("socket_options") + if socket_opts is not None: + context["socket_options"] = tuple(socket_opts) + + # Map the kwargs to the names in the namedtuple - this is necessary since + # namedtuples can't have fields starting with '_'. + for key in list(context.keys()): + context["key_" + key] = context.pop(key) + + # Default to ``None`` for keys missing from the context + for field in key_class._fields: + if field not in context: + context[field] = None + + return key_class(**context) + + +#: A dictionary that maps a scheme to a callable that creates a pool key. +#: This can be used to alter the way pool keys are constructed, if desired. +#: Each PoolManager makes a copy of this dictionary so they can be configured +#: globally here, or individually on the instance. +key_fn_by_scheme = { + "http": functools.partial(_default_key_normalizer, PoolKey), + "https": functools.partial(_default_key_normalizer, PoolKey), +} + +pool_classes_by_scheme = {"http": HTTPConnectionPool, "https": HTTPSConnectionPool} + + +class PoolManager(RequestMethods): + """ + Allows for arbitrary requests while transparently keeping track of + necessary connection pools for you. + + :param num_pools: + Number of connection pools to cache before discarding the least + recently used pool. + + :param headers: + Headers to include with all requests, unless other headers are given + explicitly. + + :param \\**connection_pool_kw: + Additional parameters are used to create fresh + :class:`urllib3.connectionpool.ConnectionPool` instances. + + Example:: + + >>> manager = PoolManager(num_pools=2) + >>> r = manager.request('GET', 'http://google.com/') + >>> r = manager.request('GET', 'http://google.com/mail') + >>> r = manager.request('GET', 'http://yahoo.com/') + >>> len(manager.pools) + 2 + + """ + + proxy = None + proxy_config = None + + def __init__(self, num_pools=10, headers=None, **connection_pool_kw): + RequestMethods.__init__(self, headers) + self.connection_pool_kw = connection_pool_kw + self.pools = RecentlyUsedContainer(num_pools, dispose_func=lambda p: p.close()) + + # Locally set the pool classes and keys so other PoolManagers can + # override them. + self.pool_classes_by_scheme = pool_classes_by_scheme + self.key_fn_by_scheme = key_fn_by_scheme.copy() + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.clear() + # Return False to re-raise any potential exceptions + return False + + def _new_pool(self, scheme, host, port, request_context=None): + """ + Create a new :class:`urllib3.connectionpool.ConnectionPool` based on host, port, scheme, and + any additional pool keyword arguments. + + If ``request_context`` is provided, it is provided as keyword arguments + to the pool class used. This method is used to actually create the + connection pools handed out by :meth:`connection_from_url` and + companion methods. It is intended to be overridden for customization. + """ + pool_cls = self.pool_classes_by_scheme[scheme] + if request_context is None: + request_context = self.connection_pool_kw.copy() + + # Although the context has everything necessary to create the pool, + # this function has historically only used the scheme, host, and port + # in the positional args. When an API change is acceptable these can + # be removed. + for key in ("scheme", "host", "port"): + request_context.pop(key, None) + + if scheme == "http": + for kw in SSL_KEYWORDS: + request_context.pop(kw, None) + + return pool_cls(host, port, **request_context) + + def clear(self): + """ + Empty our store of pools and direct them all to close. + + This will not affect in-flight connections, but they will not be + re-used after completion. + """ + self.pools.clear() + + def connection_from_host(self, host, port=None, scheme="http", pool_kwargs=None): + """ + Get a :class:`urllib3.connectionpool.ConnectionPool` based on the host, port, and scheme. + + If ``port`` isn't given, it will be derived from the ``scheme`` using + ``urllib3.connectionpool.port_by_scheme``. If ``pool_kwargs`` is + provided, it is merged with the instance's ``connection_pool_kw`` + variable and used to create the new connection pool, if one is + needed. + """ + + if not host: + raise LocationValueError("No host specified.") + + request_context = self._merge_pool_kwargs(pool_kwargs) + request_context["scheme"] = scheme or "http" + if not port: + port = port_by_scheme.get(request_context["scheme"].lower(), 80) + request_context["port"] = port + request_context["host"] = host + + return self.connection_from_context(request_context) + + def connection_from_context(self, request_context): + """ + Get a :class:`urllib3.connectionpool.ConnectionPool` based on the request context. + + ``request_context`` must at least contain the ``scheme`` key and its + value must be a key in ``key_fn_by_scheme`` instance variable. + """ + scheme = request_context["scheme"].lower() + pool_key_constructor = self.key_fn_by_scheme.get(scheme) + if not pool_key_constructor: + raise URLSchemeUnknown(scheme) + pool_key = pool_key_constructor(request_context) + + return self.connection_from_pool_key(pool_key, request_context=request_context) + + def connection_from_pool_key(self, pool_key, request_context=None): + """ + Get a :class:`urllib3.connectionpool.ConnectionPool` based on the provided pool key. + + ``pool_key`` should be a namedtuple that only contains immutable + objects. At a minimum it must have the ``scheme``, ``host``, and + ``port`` fields. + """ + with self.pools.lock: + # If the scheme, host, or port doesn't match existing open + # connections, open a new ConnectionPool. + pool = self.pools.get(pool_key) + if pool: + return pool + + # Make a fresh ConnectionPool of the desired type + scheme = request_context["scheme"] + host = request_context["host"] + port = request_context["port"] + pool = self._new_pool(scheme, host, port, request_context=request_context) + self.pools[pool_key] = pool + + return pool + + def connection_from_url(self, url, pool_kwargs=None): + """ + Similar to :func:`urllib3.connectionpool.connection_from_url`. + + If ``pool_kwargs`` is not provided and a new pool needs to be + constructed, ``self.connection_pool_kw`` is used to initialize + the :class:`urllib3.connectionpool.ConnectionPool`. If ``pool_kwargs`` + is provided, it is used instead. Note that if a new pool does not + need to be created for the request, the provided ``pool_kwargs`` are + not used. + """ + u = parse_url(url) + return self.connection_from_host( + u.host, port=u.port, scheme=u.scheme, pool_kwargs=pool_kwargs + ) + + def _merge_pool_kwargs(self, override): + """ + Merge a dictionary of override values for self.connection_pool_kw. + + This does not modify self.connection_pool_kw and returns a new dict. + Any keys in the override dictionary with a value of ``None`` are + removed from the merged dictionary. + """ + base_pool_kwargs = self.connection_pool_kw.copy() + if override: + for key, value in override.items(): + if value is None: + try: + del base_pool_kwargs[key] + except KeyError: + pass + else: + base_pool_kwargs[key] = value + return base_pool_kwargs + + def _proxy_requires_url_absolute_form(self, parsed_url): + """ + Indicates if the proxy requires the complete destination URL in the + request. Normally this is only needed when not using an HTTP CONNECT + tunnel. + """ + if self.proxy is None: + return False + + return not connection_requires_http_tunnel( + self.proxy, self.proxy_config, parsed_url.scheme + ) + + def _validate_proxy_scheme_url_selection(self, url_scheme): + """ + Validates that were not attempting to do TLS in TLS connections on + Python2 or with unsupported SSL implementations. + """ + if self.proxy is None or url_scheme != "https": + return + + if self.proxy.scheme != "https": + return + + if six.PY2 and not self.proxy_config.use_forwarding_for_https: + raise ProxySchemeUnsupported( + "Contacting HTTPS destinations through HTTPS proxies " + "'via CONNECT tunnels' is not supported in Python 2" + ) + + def urlopen(self, method, url, redirect=True, **kw): + """ + Same as :meth:`urllib3.HTTPConnectionPool.urlopen` + with custom cross-host redirect logic and only sends the request-uri + portion of the ``url``. + + The given ``url`` parameter must be absolute, such that an appropriate + :class:`urllib3.connectionpool.ConnectionPool` can be chosen for it. + """ + u = parse_url(url) + self._validate_proxy_scheme_url_selection(u.scheme) + + conn = self.connection_from_host(u.host, port=u.port, scheme=u.scheme) + + kw["assert_same_host"] = False + kw["redirect"] = False + + if "headers" not in kw: + kw["headers"] = self.headers.copy() + + if self._proxy_requires_url_absolute_form(u): + response = conn.urlopen(method, url, **kw) + else: + response = conn.urlopen(method, u.request_uri, **kw) + + redirect_location = redirect and response.get_redirect_location() + if not redirect_location: + return response + + # Support relative URLs for redirecting. + redirect_location = urljoin(url, redirect_location) + + # RFC 7231, Section 6.4.4 + if response.status == 303: + method = "GET" + + retries = kw.get("retries") + if not isinstance(retries, Retry): + retries = Retry.from_int(retries, redirect=redirect) + + # Strip headers marked as unsafe to forward to the redirected location. + # Check remove_headers_on_redirect to avoid a potential network call within + # conn.is_same_host() which may use socket.gethostbyname() in the future. + if retries.remove_headers_on_redirect and not conn.is_same_host( + redirect_location + ): + headers = list(six.iterkeys(kw["headers"])) + for header in headers: + if header.lower() in retries.remove_headers_on_redirect: + kw["headers"].pop(header, None) + + try: + retries = retries.increment(method, url, response=response, _pool=conn) + except MaxRetryError: + if retries.raise_on_redirect: + response.drain_conn() + raise + return response + + kw["retries"] = retries + kw["redirect"] = redirect + + log.info("Redirecting %s -> %s", url, redirect_location) + + response.drain_conn() + return self.urlopen(method, redirect_location, **kw) + + +class ProxyManager(PoolManager): + """ + Behaves just like :class:`PoolManager`, but sends all requests through + the defined proxy, using the CONNECT method for HTTPS URLs. + + :param proxy_url: + The URL of the proxy to be used. + + :param proxy_headers: + A dictionary containing headers that will be sent to the proxy. In case + of HTTP they are being sent with each request, while in the + HTTPS/CONNECT case they are sent only once. Could be used for proxy + authentication. + + :param proxy_ssl_context: + The proxy SSL context is used to establish the TLS connection to the + proxy when using HTTPS proxies. + + :param use_forwarding_for_https: + (Defaults to False) If set to True will forward requests to the HTTPS + proxy to be made on behalf of the client instead of creating a TLS + tunnel via the CONNECT method. **Enabling this flag means that request + and response headers and content will be visible from the HTTPS proxy** + whereas tunneling keeps request and response headers and content + private. IP address, target hostname, SNI, and port are always visible + to an HTTPS proxy even when this flag is disabled. + + Example: + >>> proxy = urllib3.ProxyManager('http://localhost:3128/') + >>> r1 = proxy.request('GET', 'http://google.com/') + >>> r2 = proxy.request('GET', 'http://httpbin.org/') + >>> len(proxy.pools) + 1 + >>> r3 = proxy.request('GET', 'https://httpbin.org/') + >>> r4 = proxy.request('GET', 'https://twitter.com/') + >>> len(proxy.pools) + 3 + + """ + + def __init__( + self, + proxy_url, + num_pools=10, + headers=None, + proxy_headers=None, + proxy_ssl_context=None, + use_forwarding_for_https=False, + **connection_pool_kw + ): + + if isinstance(proxy_url, HTTPConnectionPool): + proxy_url = "%s://%s:%i" % ( + proxy_url.scheme, + proxy_url.host, + proxy_url.port, + ) + proxy = parse_url(proxy_url) + + if proxy.scheme not in ("http", "https"): + raise ProxySchemeUnknown(proxy.scheme) + + if not proxy.port: + port = port_by_scheme.get(proxy.scheme, 80) + proxy = proxy._replace(port=port) + + self.proxy = proxy + self.proxy_headers = proxy_headers or {} + self.proxy_ssl_context = proxy_ssl_context + self.proxy_config = ProxyConfig(proxy_ssl_context, use_forwarding_for_https) + + connection_pool_kw["_proxy"] = self.proxy + connection_pool_kw["_proxy_headers"] = self.proxy_headers + connection_pool_kw["_proxy_config"] = self.proxy_config + + super(ProxyManager, self).__init__(num_pools, headers, **connection_pool_kw) + + def connection_from_host(self, host, port=None, scheme="http", pool_kwargs=None): + if scheme == "https": + return super(ProxyManager, self).connection_from_host( + host, port, scheme, pool_kwargs=pool_kwargs + ) + + return super(ProxyManager, self).connection_from_host( + self.proxy.host, self.proxy.port, self.proxy.scheme, pool_kwargs=pool_kwargs + ) + + def _set_proxy_headers(self, url, headers=None): + """ + Sets headers needed by proxies: specifically, the Accept and Host + headers. Only sets headers not provided by the user. + """ + headers_ = {"Accept": "*/*"} + + netloc = parse_url(url).netloc + if netloc: + headers_["Host"] = netloc + + if headers: + headers_.update(headers) + return headers_ + + def urlopen(self, method, url, redirect=True, **kw): + "Same as HTTP(S)ConnectionPool.urlopen, ``url`` must be absolute." + u = parse_url(url) + if not connection_requires_http_tunnel(self.proxy, self.proxy_config, u.scheme): + # For connections using HTTP CONNECT, httplib sets the necessary + # headers on the CONNECT to the proxy. If we're not using CONNECT, + # we'll definitely need to set 'Host' at the very least. + headers = kw.get("headers", self.headers) + kw["headers"] = self._set_proxy_headers(url, headers) + + return super(ProxyManager, self).urlopen(method, url, redirect=redirect, **kw) + + +def proxy_from_url(url, **kw): + return ProxyManager(proxy_url=url, **kw) diff --git a/venv/lib/python3.8/site-packages/urllib3/request.py b/venv/lib/python3.8/site-packages/urllib3/request.py new file mode 100644 index 0000000..398386a --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3/request.py @@ -0,0 +1,170 @@ +from __future__ import absolute_import + +from .filepost import encode_multipart_formdata +from .packages.six.moves.urllib.parse import urlencode + +__all__ = ["RequestMethods"] + + +class RequestMethods(object): + """ + Convenience mixin for classes who implement a :meth:`urlopen` method, such + as :class:`urllib3.HTTPConnectionPool` and + :class:`urllib3.PoolManager`. + + Provides behavior for making common types of HTTP request methods and + decides which type of request field encoding to use. + + Specifically, + + :meth:`.request_encode_url` is for sending requests whose fields are + encoded in the URL (such as GET, HEAD, DELETE). + + :meth:`.request_encode_body` is for sending requests whose fields are + encoded in the *body* of the request using multipart or www-form-urlencoded + (such as for POST, PUT, PATCH). + + :meth:`.request` is for making any kind of request, it will look up the + appropriate encoding format and use one of the above two methods to make + the request. + + Initializer parameters: + + :param headers: + Headers to include with all requests, unless other headers are given + explicitly. + """ + + _encode_url_methods = {"DELETE", "GET", "HEAD", "OPTIONS"} + + def __init__(self, headers=None): + self.headers = headers or {} + + def urlopen( + self, + method, + url, + body=None, + headers=None, + encode_multipart=True, + multipart_boundary=None, + **kw + ): # Abstract + raise NotImplementedError( + "Classes extending RequestMethods must implement " + "their own ``urlopen`` method." + ) + + def request(self, method, url, fields=None, headers=None, **urlopen_kw): + """ + Make a request using :meth:`urlopen` with the appropriate encoding of + ``fields`` based on the ``method`` used. + + This is a convenience method that requires the least amount of manual + effort. It can be used in most situations, while still having the + option to drop down to more specific methods when necessary, such as + :meth:`request_encode_url`, :meth:`request_encode_body`, + or even the lowest level :meth:`urlopen`. + """ + method = method.upper() + + urlopen_kw["request_url"] = url + + if method in self._encode_url_methods: + return self.request_encode_url( + method, url, fields=fields, headers=headers, **urlopen_kw + ) + else: + return self.request_encode_body( + method, url, fields=fields, headers=headers, **urlopen_kw + ) + + def request_encode_url(self, method, url, fields=None, headers=None, **urlopen_kw): + """ + Make a request using :meth:`urlopen` with the ``fields`` encoded in + the url. This is useful for request methods like GET, HEAD, DELETE, etc. + """ + if headers is None: + headers = self.headers + + extra_kw = {"headers": headers} + extra_kw.update(urlopen_kw) + + if fields: + url += "?" + urlencode(fields) + + return self.urlopen(method, url, **extra_kw) + + def request_encode_body( + self, + method, + url, + fields=None, + headers=None, + encode_multipart=True, + multipart_boundary=None, + **urlopen_kw + ): + """ + Make a request using :meth:`urlopen` with the ``fields`` encoded in + the body. This is useful for request methods like POST, PUT, PATCH, etc. + + When ``encode_multipart=True`` (default), then + :func:`urllib3.encode_multipart_formdata` is used to encode + the payload with the appropriate content type. Otherwise + :func:`urllib.parse.urlencode` is used with the + 'application/x-www-form-urlencoded' content type. + + Multipart encoding must be used when posting files, and it's reasonably + safe to use it in other times too. However, it may break request + signing, such as with OAuth. + + Supports an optional ``fields`` parameter of key/value strings AND + key/filetuple. A filetuple is a (filename, data, MIME type) tuple where + the MIME type is optional. For example:: + + fields = { + 'foo': 'bar', + 'fakefile': ('foofile.txt', 'contents of foofile'), + 'realfile': ('barfile.txt', open('realfile').read()), + 'typedfile': ('bazfile.bin', open('bazfile').read(), + 'image/jpeg'), + 'nonamefile': 'contents of nonamefile field', + } + + When uploading a file, providing a filename (the first parameter of the + tuple) is optional but recommended to best mimic behavior of browsers. + + Note that if ``headers`` are supplied, the 'Content-Type' header will + be overwritten because it depends on the dynamic random boundary string + which is used to compose the body of the request. The random boundary + string can be explicitly set with the ``multipart_boundary`` parameter. + """ + if headers is None: + headers = self.headers + + extra_kw = {"headers": {}} + + if fields: + if "body" in urlopen_kw: + raise TypeError( + "request got values for both 'fields' and 'body', can only specify one." + ) + + if encode_multipart: + body, content_type = encode_multipart_formdata( + fields, boundary=multipart_boundary + ) + else: + body, content_type = ( + urlencode(fields), + "application/x-www-form-urlencoded", + ) + + extra_kw["body"] = body + extra_kw["headers"] = {"Content-Type": content_type} + + extra_kw["headers"].update(headers) + extra_kw.update(urlopen_kw) + + return self.urlopen(method, url, **extra_kw) diff --git a/venv/lib/python3.8/site-packages/urllib3/response.py b/venv/lib/python3.8/site-packages/urllib3/response.py new file mode 100644 index 0000000..38693f4 --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3/response.py @@ -0,0 +1,821 @@ +from __future__ import absolute_import + +import io +import logging +import zlib +from contextlib import contextmanager +from socket import error as SocketError +from socket import timeout as SocketTimeout + +try: + import brotli +except ImportError: + brotli = None + +from ._collections import HTTPHeaderDict +from .connection import BaseSSLError, HTTPException +from .exceptions import ( + BodyNotHttplibCompatible, + DecodeError, + HTTPError, + IncompleteRead, + InvalidChunkLength, + InvalidHeader, + ProtocolError, + ReadTimeoutError, + ResponseNotChunked, + SSLError, +) +from .packages import six +from .util.response import is_fp_closed, is_response_to_head + +log = logging.getLogger(__name__) + + +class DeflateDecoder(object): + def __init__(self): + self._first_try = True + self._data = b"" + self._obj = zlib.decompressobj() + + def __getattr__(self, name): + return getattr(self._obj, name) + + def decompress(self, data): + if not data: + return data + + if not self._first_try: + return self._obj.decompress(data) + + self._data += data + try: + decompressed = self._obj.decompress(data) + if decompressed: + self._first_try = False + self._data = None + return decompressed + except zlib.error: + self._first_try = False + self._obj = zlib.decompressobj(-zlib.MAX_WBITS) + try: + return self.decompress(self._data) + finally: + self._data = None + + +class GzipDecoderState(object): + + FIRST_MEMBER = 0 + OTHER_MEMBERS = 1 + SWALLOW_DATA = 2 + + +class GzipDecoder(object): + def __init__(self): + self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS) + self._state = GzipDecoderState.FIRST_MEMBER + + def __getattr__(self, name): + return getattr(self._obj, name) + + def decompress(self, data): + ret = bytearray() + if self._state == GzipDecoderState.SWALLOW_DATA or not data: + return bytes(ret) + while True: + try: + ret += self._obj.decompress(data) + except zlib.error: + previous_state = self._state + # Ignore data after the first error + self._state = GzipDecoderState.SWALLOW_DATA + if previous_state == GzipDecoderState.OTHER_MEMBERS: + # Allow trailing garbage acceptable in other gzip clients + return bytes(ret) + raise + data = self._obj.unused_data + if not data: + return bytes(ret) + self._state = GzipDecoderState.OTHER_MEMBERS + self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS) + + +if brotli is not None: + + class BrotliDecoder(object): + # Supports both 'brotlipy' and 'Brotli' packages + # since they share an import name. The top branches + # are for 'brotlipy' and bottom branches for 'Brotli' + def __init__(self): + self._obj = brotli.Decompressor() + if hasattr(self._obj, "decompress"): + self.decompress = self._obj.decompress + else: + self.decompress = self._obj.process + + def flush(self): + if hasattr(self._obj, "flush"): + return self._obj.flush() + return b"" + + +class MultiDecoder(object): + """ + From RFC7231: + If one or more encodings have been applied to a representation, the + sender that applied the encodings MUST generate a Content-Encoding + header field that lists the content codings in the order in which + they were applied. + """ + + def __init__(self, modes): + self._decoders = [_get_decoder(m.strip()) for m in modes.split(",")] + + def flush(self): + return self._decoders[0].flush() + + def decompress(self, data): + for d in reversed(self._decoders): + data = d.decompress(data) + return data + + +def _get_decoder(mode): + if "," in mode: + return MultiDecoder(mode) + + if mode == "gzip": + return GzipDecoder() + + if brotli is not None and mode == "br": + return BrotliDecoder() + + return DeflateDecoder() + + +class HTTPResponse(io.IOBase): + """ + HTTP Response container. + + Backwards-compatible with :class:`http.client.HTTPResponse` but the response ``body`` is + loaded and decoded on-demand when the ``data`` property is accessed. This + class is also compatible with the Python standard library's :mod:`io` + module, and can hence be treated as a readable object in the context of that + framework. + + Extra parameters for behaviour not present in :class:`http.client.HTTPResponse`: + + :param preload_content: + If True, the response's body will be preloaded during construction. + + :param decode_content: + If True, will attempt to decode the body based on the + 'content-encoding' header. + + :param original_response: + When this HTTPResponse wrapper is generated from an :class:`http.client.HTTPResponse` + object, it's convenient to include the original for debug purposes. It's + otherwise unused. + + :param retries: + The retries contains the last :class:`~urllib3.util.retry.Retry` that + was used during the request. + + :param enforce_content_length: + Enforce content length checking. Body returned by server must match + value of Content-Length header, if present. Otherwise, raise error. + """ + + CONTENT_DECODERS = ["gzip", "deflate"] + if brotli is not None: + CONTENT_DECODERS += ["br"] + REDIRECT_STATUSES = [301, 302, 303, 307, 308] + + def __init__( + self, + body="", + headers=None, + status=0, + version=0, + reason=None, + strict=0, + preload_content=True, + decode_content=True, + original_response=None, + pool=None, + connection=None, + msg=None, + retries=None, + enforce_content_length=False, + request_method=None, + request_url=None, + auto_close=True, + ): + + if isinstance(headers, HTTPHeaderDict): + self.headers = headers + else: + self.headers = HTTPHeaderDict(headers) + self.status = status + self.version = version + self.reason = reason + self.strict = strict + self.decode_content = decode_content + self.retries = retries + self.enforce_content_length = enforce_content_length + self.auto_close = auto_close + + self._decoder = None + self._body = None + self._fp = None + self._original_response = original_response + self._fp_bytes_read = 0 + self.msg = msg + self._request_url = request_url + + if body and isinstance(body, (six.string_types, bytes)): + self._body = body + + self._pool = pool + self._connection = connection + + if hasattr(body, "read"): + self._fp = body + + # Are we using the chunked-style of transfer encoding? + self.chunked = False + self.chunk_left = None + tr_enc = self.headers.get("transfer-encoding", "").lower() + # Don't incur the penalty of creating a list and then discarding it + encodings = (enc.strip() for enc in tr_enc.split(",")) + if "chunked" in encodings: + self.chunked = True + + # Determine length of response + self.length_remaining = self._init_length(request_method) + + # If requested, preload the body. + if preload_content and not self._body: + self._body = self.read(decode_content=decode_content) + + def get_redirect_location(self): + """ + Should we redirect and where to? + + :returns: Truthy redirect location string if we got a redirect status + code and valid location. ``None`` if redirect status and no + location. ``False`` if not a redirect status code. + """ + if self.status in self.REDIRECT_STATUSES: + return self.headers.get("location") + + return False + + def release_conn(self): + if not self._pool or not self._connection: + return + + self._pool._put_conn(self._connection) + self._connection = None + + def drain_conn(self): + """ + Read and discard any remaining HTTP response data in the response connection. + + Unread data in the HTTPResponse connection blocks the connection from being released back to the pool. + """ + try: + self.read() + except (HTTPError, SocketError, BaseSSLError, HTTPException): + pass + + @property + def data(self): + # For backwards-compat with earlier urllib3 0.4 and earlier. + if self._body: + return self._body + + if self._fp: + return self.read(cache_content=True) + + @property + def connection(self): + return self._connection + + def isclosed(self): + return is_fp_closed(self._fp) + + def tell(self): + """ + Obtain the number of bytes pulled over the wire so far. May differ from + the amount of content returned by :meth:``urllib3.response.HTTPResponse.read`` + if bytes are encoded on the wire (e.g, compressed). + """ + return self._fp_bytes_read + + def _init_length(self, request_method): + """ + Set initial length value for Response content if available. + """ + length = self.headers.get("content-length") + + if length is not None: + if self.chunked: + # This Response will fail with an IncompleteRead if it can't be + # received as chunked. This method falls back to attempt reading + # the response before raising an exception. + log.warning( + "Received response with both Content-Length and " + "Transfer-Encoding set. This is expressly forbidden " + "by RFC 7230 sec 3.3.2. Ignoring Content-Length and " + "attempting to process response as Transfer-Encoding: " + "chunked." + ) + return None + + try: + # RFC 7230 section 3.3.2 specifies multiple content lengths can + # be sent in a single Content-Length header + # (e.g. Content-Length: 42, 42). This line ensures the values + # are all valid ints and that as long as the `set` length is 1, + # all values are the same. Otherwise, the header is invalid. + lengths = set([int(val) for val in length.split(",")]) + if len(lengths) > 1: + raise InvalidHeader( + "Content-Length contained multiple " + "unmatching values (%s)" % length + ) + length = lengths.pop() + except ValueError: + length = None + else: + if length < 0: + length = None + + # Convert status to int for comparison + # In some cases, httplib returns a status of "_UNKNOWN" + try: + status = int(self.status) + except ValueError: + status = 0 + + # Check for responses that shouldn't include a body + if status in (204, 304) or 100 <= status < 200 or request_method == "HEAD": + length = 0 + + return length + + def _init_decoder(self): + """ + Set-up the _decoder attribute if necessary. + """ + # Note: content-encoding value should be case-insensitive, per RFC 7230 + # Section 3.2 + content_encoding = self.headers.get("content-encoding", "").lower() + if self._decoder is None: + if content_encoding in self.CONTENT_DECODERS: + self._decoder = _get_decoder(content_encoding) + elif "," in content_encoding: + encodings = [ + e.strip() + for e in content_encoding.split(",") + if e.strip() in self.CONTENT_DECODERS + ] + if len(encodings): + self._decoder = _get_decoder(content_encoding) + + DECODER_ERROR_CLASSES = (IOError, zlib.error) + if brotli is not None: + DECODER_ERROR_CLASSES += (brotli.error,) + + def _decode(self, data, decode_content, flush_decoder): + """ + Decode the data passed in and potentially flush the decoder. + """ + if not decode_content: + return data + + try: + if self._decoder: + data = self._decoder.decompress(data) + except self.DECODER_ERROR_CLASSES as e: + content_encoding = self.headers.get("content-encoding", "").lower() + raise DecodeError( + "Received response with content-encoding: %s, but " + "failed to decode it." % content_encoding, + e, + ) + if flush_decoder: + data += self._flush_decoder() + + return data + + def _flush_decoder(self): + """ + Flushes the decoder. Should only be called if the decoder is actually + being used. + """ + if self._decoder: + buf = self._decoder.decompress(b"") + return buf + self._decoder.flush() + + return b"" + + @contextmanager + def _error_catcher(self): + """ + Catch low-level python exceptions, instead re-raising urllib3 + variants, so that low-level exceptions are not leaked in the + high-level api. + + On exit, release the connection back to the pool. + """ + clean_exit = False + + try: + try: + yield + + except SocketTimeout: + # FIXME: Ideally we'd like to include the url in the ReadTimeoutError but + # there is yet no clean way to get at it from this context. + raise ReadTimeoutError(self._pool, None, "Read timed out.") + + except BaseSSLError as e: + # FIXME: Is there a better way to differentiate between SSLErrors? + if "read operation timed out" not in str(e): + # SSL errors related to framing/MAC get wrapped and reraised here + raise SSLError(e) + + raise ReadTimeoutError(self._pool, None, "Read timed out.") + + except (HTTPException, SocketError) as e: + # This includes IncompleteRead. + raise ProtocolError("Connection broken: %r" % e, e) + + # If no exception is thrown, we should avoid cleaning up + # unnecessarily. + clean_exit = True + finally: + # If we didn't terminate cleanly, we need to throw away our + # connection. + if not clean_exit: + # The response may not be closed but we're not going to use it + # anymore so close it now to ensure that the connection is + # released back to the pool. + if self._original_response: + self._original_response.close() + + # Closing the response may not actually be sufficient to close + # everything, so if we have a hold of the connection close that + # too. + if self._connection: + self._connection.close() + + # If we hold the original response but it's closed now, we should + # return the connection back to the pool. + if self._original_response and self._original_response.isclosed(): + self.release_conn() + + def read(self, amt=None, decode_content=None, cache_content=False): + """ + Similar to :meth:`http.client.HTTPResponse.read`, but with two additional + parameters: ``decode_content`` and ``cache_content``. + + :param amt: + How much of the content to read. If specified, caching is skipped + because it doesn't make sense to cache partial content as the full + response. + + :param decode_content: + If True, will attempt to decode the body based on the + 'content-encoding' header. + + :param cache_content: + If True, will save the returned data such that the same result is + returned despite of the state of the underlying file object. This + is useful if you want the ``.data`` property to continue working + after having ``.read()`` the file object. (Overridden if ``amt`` is + set.) + """ + self._init_decoder() + if decode_content is None: + decode_content = self.decode_content + + if self._fp is None: + return + + flush_decoder = False + fp_closed = getattr(self._fp, "closed", False) + + with self._error_catcher(): + if amt is None: + # cStringIO doesn't like amt=None + data = self._fp.read() if not fp_closed else b"" + flush_decoder = True + else: + cache_content = False + data = self._fp.read(amt) if not fp_closed else b"" + if ( + amt != 0 and not data + ): # Platform-specific: Buggy versions of Python. + # Close the connection when no data is returned + # + # This is redundant to what httplib/http.client _should_ + # already do. However, versions of python released before + # December 15, 2012 (http://bugs.python.org/issue16298) do + # not properly close the connection in all cases. There is + # no harm in redundantly calling close. + self._fp.close() + flush_decoder = True + if self.enforce_content_length and self.length_remaining not in ( + 0, + None, + ): + # This is an edge case that httplib failed to cover due + # to concerns of backward compatibility. We're + # addressing it here to make sure IncompleteRead is + # raised during streaming, so all calls with incorrect + # Content-Length are caught. + raise IncompleteRead(self._fp_bytes_read, self.length_remaining) + + if data: + self._fp_bytes_read += len(data) + if self.length_remaining is not None: + self.length_remaining -= len(data) + + data = self._decode(data, decode_content, flush_decoder) + + if cache_content: + self._body = data + + return data + + def stream(self, amt=2 ** 16, decode_content=None): + """ + A generator wrapper for the read() method. A call will block until + ``amt`` bytes have been read from the connection or until the + connection is closed. + + :param amt: + How much of the content to read. The generator will return up to + much data per iteration, but may return less. This is particularly + likely when using compressed data. However, the empty string will + never be returned. + + :param decode_content: + If True, will attempt to decode the body based on the + 'content-encoding' header. + """ + if self.chunked and self.supports_chunked_reads(): + for line in self.read_chunked(amt, decode_content=decode_content): + yield line + else: + while not is_fp_closed(self._fp): + data = self.read(amt=amt, decode_content=decode_content) + + if data: + yield data + + @classmethod + def from_httplib(ResponseCls, r, **response_kw): + """ + Given an :class:`http.client.HTTPResponse` instance ``r``, return a + corresponding :class:`urllib3.response.HTTPResponse` object. + + Remaining parameters are passed to the HTTPResponse constructor, along + with ``original_response=r``. + """ + headers = r.msg + + if not isinstance(headers, HTTPHeaderDict): + if six.PY2: + # Python 2.7 + headers = HTTPHeaderDict.from_httplib(headers) + else: + headers = HTTPHeaderDict(headers.items()) + + # HTTPResponse objects in Python 3 don't have a .strict attribute + strict = getattr(r, "strict", 0) + resp = ResponseCls( + body=r, + headers=headers, + status=r.status, + version=r.version, + reason=r.reason, + strict=strict, + original_response=r, + **response_kw + ) + return resp + + # Backwards-compatibility methods for http.client.HTTPResponse + def getheaders(self): + return self.headers + + def getheader(self, name, default=None): + return self.headers.get(name, default) + + # Backwards compatibility for http.cookiejar + def info(self): + return self.headers + + # Overrides from io.IOBase + def close(self): + if not self.closed: + self._fp.close() + + if self._connection: + self._connection.close() + + if not self.auto_close: + io.IOBase.close(self) + + @property + def closed(self): + if not self.auto_close: + return io.IOBase.closed.__get__(self) + elif self._fp is None: + return True + elif hasattr(self._fp, "isclosed"): + return self._fp.isclosed() + elif hasattr(self._fp, "closed"): + return self._fp.closed + else: + return True + + def fileno(self): + if self._fp is None: + raise IOError("HTTPResponse has no file to get a fileno from") + elif hasattr(self._fp, "fileno"): + return self._fp.fileno() + else: + raise IOError( + "The file-like object this HTTPResponse is wrapped " + "around has no file descriptor" + ) + + def flush(self): + if ( + self._fp is not None + and hasattr(self._fp, "flush") + and not getattr(self._fp, "closed", False) + ): + return self._fp.flush() + + def readable(self): + # This method is required for `io` module compatibility. + return True + + def readinto(self, b): + # This method is required for `io` module compatibility. + temp = self.read(len(b)) + if len(temp) == 0: + return 0 + else: + b[: len(temp)] = temp + return len(temp) + + def supports_chunked_reads(self): + """ + Checks if the underlying file-like object looks like a + :class:`http.client.HTTPResponse` object. We do this by testing for + the fp attribute. If it is present we assume it returns raw chunks as + processed by read_chunked(). + """ + return hasattr(self._fp, "fp") + + def _update_chunk_length(self): + # First, we'll figure out length of a chunk and then + # we'll try to read it from socket. + if self.chunk_left is not None: + return + line = self._fp.fp.readline() + line = line.split(b";", 1)[0] + try: + self.chunk_left = int(line, 16) + except ValueError: + # Invalid chunked protocol response, abort. + self.close() + raise InvalidChunkLength(self, line) + + def _handle_chunk(self, amt): + returned_chunk = None + if amt is None: + chunk = self._fp._safe_read(self.chunk_left) + returned_chunk = chunk + self._fp._safe_read(2) # Toss the CRLF at the end of the chunk. + self.chunk_left = None + elif amt < self.chunk_left: + value = self._fp._safe_read(amt) + self.chunk_left = self.chunk_left - amt + returned_chunk = value + elif amt == self.chunk_left: + value = self._fp._safe_read(amt) + self._fp._safe_read(2) # Toss the CRLF at the end of the chunk. + self.chunk_left = None + returned_chunk = value + else: # amt > self.chunk_left + returned_chunk = self._fp._safe_read(self.chunk_left) + self._fp._safe_read(2) # Toss the CRLF at the end of the chunk. + self.chunk_left = None + return returned_chunk + + def read_chunked(self, amt=None, decode_content=None): + """ + Similar to :meth:`HTTPResponse.read`, but with an additional + parameter: ``decode_content``. + + :param amt: + How much of the content to read. If specified, caching is skipped + because it doesn't make sense to cache partial content as the full + response. + + :param decode_content: + If True, will attempt to decode the body based on the + 'content-encoding' header. + """ + self._init_decoder() + # FIXME: Rewrite this method and make it a class with a better structured logic. + if not self.chunked: + raise ResponseNotChunked( + "Response is not chunked. " + "Header 'transfer-encoding: chunked' is missing." + ) + if not self.supports_chunked_reads(): + raise BodyNotHttplibCompatible( + "Body should be http.client.HTTPResponse like. " + "It should have have an fp attribute which returns raw chunks." + ) + + with self._error_catcher(): + # Don't bother reading the body of a HEAD request. + if self._original_response and is_response_to_head(self._original_response): + self._original_response.close() + return + + # If a response is already read and closed + # then return immediately. + if self._fp.fp is None: + return + + while True: + self._update_chunk_length() + if self.chunk_left == 0: + break + chunk = self._handle_chunk(amt) + decoded = self._decode( + chunk, decode_content=decode_content, flush_decoder=False + ) + if decoded: + yield decoded + + if decode_content: + # On CPython and PyPy, we should never need to flush the + # decoder. However, on Jython we *might* need to, so + # lets defensively do it anyway. + decoded = self._flush_decoder() + if decoded: # Platform-specific: Jython. + yield decoded + + # Chunk content ends with \r\n: discard it. + while True: + line = self._fp.fp.readline() + if not line: + # Some sites may not end with '\r\n'. + break + if line == b"\r\n": + break + + # We read everything; close the "file". + if self._original_response: + self._original_response.close() + + def geturl(self): + """ + Returns the URL that was the source of this response. + If the request that generated this response redirected, this method + will return the final redirect location. + """ + if self.retries is not None and len(self.retries.history): + return self.retries.history[-1].redirect_location + else: + return self._request_url + + def __iter__(self): + buffer = [] + for chunk in self.stream(decode_content=True): + if b"\n" in chunk: + chunk = chunk.split(b"\n") + yield b"".join(buffer) + chunk[0] + b"\n" + for x in chunk[1:-1]: + yield x + b"\n" + if chunk[-1]: + buffer = [chunk[-1]] + else: + buffer = [] + else: + buffer.append(chunk) + if buffer: + yield b"".join(buffer) diff --git a/venv/lib/python3.8/site-packages/urllib3/util/__init__.py b/venv/lib/python3.8/site-packages/urllib3/util/__init__.py new file mode 100644 index 0000000..4547fc5 --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3/util/__init__.py @@ -0,0 +1,49 @@ +from __future__ import absolute_import + +# For backwards compatibility, provide imports that used to be here. +from .connection import is_connection_dropped +from .request import SKIP_HEADER, SKIPPABLE_HEADERS, make_headers +from .response import is_fp_closed +from .retry import Retry +from .ssl_ import ( + ALPN_PROTOCOLS, + HAS_SNI, + IS_PYOPENSSL, + IS_SECURETRANSPORT, + PROTOCOL_TLS, + SSLContext, + assert_fingerprint, + resolve_cert_reqs, + resolve_ssl_version, + ssl_wrap_socket, +) +from .timeout import Timeout, current_time +from .url import Url, get_host, parse_url, split_first +from .wait import wait_for_read, wait_for_write + +__all__ = ( + "HAS_SNI", + "IS_PYOPENSSL", + "IS_SECURETRANSPORT", + "SSLContext", + "PROTOCOL_TLS", + "ALPN_PROTOCOLS", + "Retry", + "Timeout", + "Url", + "assert_fingerprint", + "current_time", + "is_connection_dropped", + "is_fp_closed", + "get_host", + "parse_url", + "make_headers", + "resolve_cert_reqs", + "resolve_ssl_version", + "split_first", + "ssl_wrap_socket", + "wait_for_read", + "wait_for_write", + "SKIP_HEADER", + "SKIPPABLE_HEADERS", +) diff --git a/venv/lib/python3.8/site-packages/urllib3/util/connection.py b/venv/lib/python3.8/site-packages/urllib3/util/connection.py new file mode 100644 index 0000000..bdc240c --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3/util/connection.py @@ -0,0 +1,150 @@ +from __future__ import absolute_import + +import socket + +from urllib3.exceptions import LocationParseError + +from ..contrib import _appengine_environ +from ..packages import six +from .wait import NoWayToWaitForSocketError, wait_for_read + + +def is_connection_dropped(conn): # Platform-specific + """ + Returns True if the connection is dropped and should be closed. + + :param conn: + :class:`http.client.HTTPConnection` object. + + Note: For platforms like AppEngine, this will always return ``False`` to + let the platform handle connection recycling transparently for us. + """ + sock = getattr(conn, "sock", False) + if sock is False: # Platform-specific: AppEngine + return False + if sock is None: # Connection already closed (such as by httplib). + return True + try: + # Returns True if readable, which here means it's been dropped + return wait_for_read(sock, timeout=0.0) + except NoWayToWaitForSocketError: # Platform-specific: AppEngine + return False + + +# This function is copied from socket.py in the Python 2.7 standard +# library test suite. Added to its signature is only `socket_options`. +# One additional modification is that we avoid binding to IPv6 servers +# discovered in DNS if the system doesn't have IPv6 functionality. +def create_connection( + address, + timeout=socket._GLOBAL_DEFAULT_TIMEOUT, + source_address=None, + socket_options=None, +): + """Connect to *address* and return the socket object. + + Convenience function. Connect to *address* (a 2-tuple ``(host, + port)``) and return the socket object. Passing the optional + *timeout* parameter will set the timeout on the socket instance + before attempting to connect. If no *timeout* is supplied, the + global default timeout setting returned by :func:`socket.getdefaulttimeout` + is used. If *source_address* is set it must be a tuple of (host, port) + for the socket to bind as a source address before making the connection. + An host of '' or port 0 tells the OS to use the default. + """ + + host, port = address + if host.startswith("["): + host = host.strip("[]") + err = None + + # Using the value from allowed_gai_family() in the context of getaddrinfo lets + # us select whether to work with IPv4 DNS records, IPv6 records, or both. + # The original create_connection function always returns all records. + family = allowed_gai_family() + + try: + host.encode("idna") + except UnicodeError: + return six.raise_from( + LocationParseError(u"'%s', label empty or too long" % host), None + ) + + for res in socket.getaddrinfo(host, port, family, socket.SOCK_STREAM): + af, socktype, proto, canonname, sa = res + sock = None + try: + sock = socket.socket(af, socktype, proto) + + # If provided, set socket level options before connecting. + _set_socket_options(sock, socket_options) + + if timeout is not socket._GLOBAL_DEFAULT_TIMEOUT: + sock.settimeout(timeout) + if source_address: + sock.bind(source_address) + sock.connect(sa) + return sock + + except socket.error as e: + err = e + if sock is not None: + sock.close() + sock = None + + if err is not None: + raise err + + raise socket.error("getaddrinfo returns an empty list") + + +def _set_socket_options(sock, options): + if options is None: + return + + for opt in options: + sock.setsockopt(*opt) + + +def allowed_gai_family(): + """This function is designed to work in the context of + getaddrinfo, where family=socket.AF_UNSPEC is the default and + will perform a DNS search for both IPv6 and IPv4 records.""" + + family = socket.AF_INET + if HAS_IPV6: + family = socket.AF_UNSPEC + return family + + +def _has_ipv6(host): + """Returns True if the system can bind an IPv6 address.""" + sock = None + has_ipv6 = False + + # App Engine doesn't support IPV6 sockets and actually has a quota on the + # number of sockets that can be used, so just early out here instead of + # creating a socket needlessly. + # See https://github.com/urllib3/urllib3/issues/1446 + if _appengine_environ.is_appengine_sandbox(): + return False + + if socket.has_ipv6: + # has_ipv6 returns true if cPython was compiled with IPv6 support. + # It does not tell us if the system has IPv6 support enabled. To + # determine that we must bind to an IPv6 address. + # https://github.com/urllib3/urllib3/pull/611 + # https://bugs.python.org/issue658327 + try: + sock = socket.socket(socket.AF_INET6) + sock.bind((host, 0)) + has_ipv6 = True + except Exception: + pass + + if sock: + sock.close() + return has_ipv6 + + +HAS_IPV6 = _has_ipv6("::1") diff --git a/venv/lib/python3.8/site-packages/urllib3/util/proxy.py b/venv/lib/python3.8/site-packages/urllib3/util/proxy.py new file mode 100644 index 0000000..34f884d --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3/util/proxy.py @@ -0,0 +1,56 @@ +from .ssl_ import create_urllib3_context, resolve_cert_reqs, resolve_ssl_version + + +def connection_requires_http_tunnel( + proxy_url=None, proxy_config=None, destination_scheme=None +): + """ + Returns True if the connection requires an HTTP CONNECT through the proxy. + + :param URL proxy_url: + URL of the proxy. + :param ProxyConfig proxy_config: + Proxy configuration from poolmanager.py + :param str destination_scheme: + The scheme of the destination. (i.e https, http, etc) + """ + # If we're not using a proxy, no way to use a tunnel. + if proxy_url is None: + return False + + # HTTP destinations never require tunneling, we always forward. + if destination_scheme == "http": + return False + + # Support for forwarding with HTTPS proxies and HTTPS destinations. + if ( + proxy_url.scheme == "https" + and proxy_config + and proxy_config.use_forwarding_for_https + ): + return False + + # Otherwise always use a tunnel. + return True + + +def create_proxy_ssl_context( + ssl_version, cert_reqs, ca_certs=None, ca_cert_dir=None, ca_cert_data=None +): + """ + Generates a default proxy ssl context if one hasn't been provided by the + user. + """ + ssl_context = create_urllib3_context( + ssl_version=resolve_ssl_version(ssl_version), + cert_reqs=resolve_cert_reqs(cert_reqs), + ) + if ( + not ca_certs + and not ca_cert_dir + and not ca_cert_data + and hasattr(ssl_context, "load_default_certs") + ): + ssl_context.load_default_certs() + + return ssl_context diff --git a/venv/lib/python3.8/site-packages/urllib3/util/queue.py b/venv/lib/python3.8/site-packages/urllib3/util/queue.py new file mode 100644 index 0000000..4178410 --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3/util/queue.py @@ -0,0 +1,22 @@ +import collections + +from ..packages import six +from ..packages.six.moves import queue + +if six.PY2: + # Queue is imported for side effects on MS Windows. See issue #229. + import Queue as _unused_module_Queue # noqa: F401 + + +class LifoQueue(queue.Queue): + def _init(self, _): + self.queue = collections.deque() + + def _qsize(self, len=len): + return len(self.queue) + + def _put(self, item): + self.queue.append(item) + + def _get(self): + return self.queue.pop() diff --git a/venv/lib/python3.8/site-packages/urllib3/util/request.py b/venv/lib/python3.8/site-packages/urllib3/util/request.py new file mode 100644 index 0000000..2510338 --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3/util/request.py @@ -0,0 +1,143 @@ +from __future__ import absolute_import + +from base64 import b64encode + +from ..exceptions import UnrewindableBodyError +from ..packages.six import b, integer_types + +# Pass as a value within ``headers`` to skip +# emitting some HTTP headers that are added automatically. +# The only headers that are supported are ``Accept-Encoding``, +# ``Host``, and ``User-Agent``. +SKIP_HEADER = "@@@SKIP_HEADER@@@" +SKIPPABLE_HEADERS = frozenset(["accept-encoding", "host", "user-agent"]) + +ACCEPT_ENCODING = "gzip,deflate" +try: + import brotli as _unused_module_brotli # noqa: F401 +except ImportError: + pass +else: + ACCEPT_ENCODING += ",br" + +_FAILEDTELL = object() + + +def make_headers( + keep_alive=None, + accept_encoding=None, + user_agent=None, + basic_auth=None, + proxy_basic_auth=None, + disable_cache=None, +): + """ + Shortcuts for generating request headers. + + :param keep_alive: + If ``True``, adds 'connection: keep-alive' header. + + :param accept_encoding: + Can be a boolean, list, or string. + ``True`` translates to 'gzip,deflate'. + List will get joined by comma. + String will be used as provided. + + :param user_agent: + String representing the user-agent you want, such as + "python-urllib3/0.6" + + :param basic_auth: + Colon-separated username:password string for 'authorization: basic ...' + auth header. + + :param proxy_basic_auth: + Colon-separated username:password string for 'proxy-authorization: basic ...' + auth header. + + :param disable_cache: + If ``True``, adds 'cache-control: no-cache' header. + + Example:: + + >>> make_headers(keep_alive=True, user_agent="Batman/1.0") + {'connection': 'keep-alive', 'user-agent': 'Batman/1.0'} + >>> make_headers(accept_encoding=True) + {'accept-encoding': 'gzip,deflate'} + """ + headers = {} + if accept_encoding: + if isinstance(accept_encoding, str): + pass + elif isinstance(accept_encoding, list): + accept_encoding = ",".join(accept_encoding) + else: + accept_encoding = ACCEPT_ENCODING + headers["accept-encoding"] = accept_encoding + + if user_agent: + headers["user-agent"] = user_agent + + if keep_alive: + headers["connection"] = "keep-alive" + + if basic_auth: + headers["authorization"] = "Basic " + b64encode(b(basic_auth)).decode("utf-8") + + if proxy_basic_auth: + headers["proxy-authorization"] = "Basic " + b64encode( + b(proxy_basic_auth) + ).decode("utf-8") + + if disable_cache: + headers["cache-control"] = "no-cache" + + return headers + + +def set_file_position(body, pos): + """ + If a position is provided, move file to that point. + Otherwise, we'll attempt to record a position for future use. + """ + if pos is not None: + rewind_body(body, pos) + elif getattr(body, "tell", None) is not None: + try: + pos = body.tell() + except (IOError, OSError): + # This differentiates from None, allowing us to catch + # a failed `tell()` later when trying to rewind the body. + pos = _FAILEDTELL + + return pos + + +def rewind_body(body, body_pos): + """ + Attempt to rewind body to a certain position. + Primarily used for request redirects and retries. + + :param body: + File-like object that supports seek. + + :param int pos: + Position to seek to in file. + """ + body_seek = getattr(body, "seek", None) + if body_seek is not None and isinstance(body_pos, integer_types): + try: + body_seek(body_pos) + except (IOError, OSError): + raise UnrewindableBodyError( + "An error occurred when rewinding request body for redirect/retry." + ) + elif body_pos is _FAILEDTELL: + raise UnrewindableBodyError( + "Unable to record file position for rewinding " + "request body during a redirect/retry." + ) + else: + raise ValueError( + "body_pos must be of type integer, instead it was %s." % type(body_pos) + ) diff --git a/venv/lib/python3.8/site-packages/urllib3/util/response.py b/venv/lib/python3.8/site-packages/urllib3/util/response.py new file mode 100644 index 0000000..5ea609c --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3/util/response.py @@ -0,0 +1,107 @@ +from __future__ import absolute_import + +from email.errors import MultipartInvariantViolationDefect, StartBoundaryNotFoundDefect + +from ..exceptions import HeaderParsingError +from ..packages.six.moves import http_client as httplib + + +def is_fp_closed(obj): + """ + Checks whether a given file-like object is closed. + + :param obj: + The file-like object to check. + """ + + try: + # Check `isclosed()` first, in case Python3 doesn't set `closed`. + # GH Issue #928 + return obj.isclosed() + except AttributeError: + pass + + try: + # Check via the official file-like-object way. + return obj.closed + except AttributeError: + pass + + try: + # Check if the object is a container for another file-like object that + # gets released on exhaustion (e.g. HTTPResponse). + return obj.fp is None + except AttributeError: + pass + + raise ValueError("Unable to determine whether fp is closed.") + + +def assert_header_parsing(headers): + """ + Asserts whether all headers have been successfully parsed. + Extracts encountered errors from the result of parsing headers. + + Only works on Python 3. + + :param http.client.HTTPMessage headers: Headers to verify. + + :raises urllib3.exceptions.HeaderParsingError: + If parsing errors are found. + """ + + # This will fail silently if we pass in the wrong kind of parameter. + # To make debugging easier add an explicit check. + if not isinstance(headers, httplib.HTTPMessage): + raise TypeError("expected httplib.Message, got {0}.".format(type(headers))) + + defects = getattr(headers, "defects", None) + get_payload = getattr(headers, "get_payload", None) + + unparsed_data = None + if get_payload: + # get_payload is actually email.message.Message.get_payload; + # we're only interested in the result if it's not a multipart message + if not headers.is_multipart(): + payload = get_payload() + + if isinstance(payload, (bytes, str)): + unparsed_data = payload + if defects: + # httplib is assuming a response body is available + # when parsing headers even when httplib only sends + # header data to parse_headers() This results in + # defects on multipart responses in particular. + # See: https://github.com/urllib3/urllib3/issues/800 + + # So we ignore the following defects: + # - StartBoundaryNotFoundDefect: + # The claimed start boundary was never found. + # - MultipartInvariantViolationDefect: + # A message claimed to be a multipart but no subparts were found. + defects = [ + defect + for defect in defects + if not isinstance( + defect, (StartBoundaryNotFoundDefect, MultipartInvariantViolationDefect) + ) + ] + + if defects or unparsed_data: + raise HeaderParsingError(defects=defects, unparsed_data=unparsed_data) + + +def is_response_to_head(response): + """ + Checks whether the request of a response has been a HEAD-request. + Handles the quirks of AppEngine. + + :param http.client.HTTPResponse response: + Response to check if the originating request + used 'HEAD' as a method. + """ + # FIXME: Can we do this somehow without accessing private httplib _method? + method = response._method + if isinstance(method, int): # Platform-specific: Appengine + return method == 3 + return method.upper() == "HEAD" diff --git a/venv/lib/python3.8/site-packages/urllib3/util/retry.py b/venv/lib/python3.8/site-packages/urllib3/util/retry.py new file mode 100644 index 0000000..c7dc42f --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3/util/retry.py @@ -0,0 +1,602 @@ +from __future__ import absolute_import + +import email +import logging +import re +import time +import warnings +from collections import namedtuple +from itertools import takewhile + +from ..exceptions import ( + ConnectTimeoutError, + InvalidHeader, + MaxRetryError, + ProtocolError, + ProxyError, + ReadTimeoutError, + ResponseError, +) +from ..packages import six + +log = logging.getLogger(__name__) + + +# Data structure for representing the metadata of requests that result in a retry. +RequestHistory = namedtuple( + "RequestHistory", ["method", "url", "error", "status", "redirect_location"] +) + + +# TODO: In v2 we can remove this sentinel and metaclass with deprecated options. +_Default = object() + + +class _RetryMeta(type): + @property + def DEFAULT_METHOD_WHITELIST(cls): + warnings.warn( + "Using 'Retry.DEFAULT_METHOD_WHITELIST' is deprecated and " + "will be removed in v2.0. Use 'Retry.DEFAULT_ALLOWED_METHODS' instead", + DeprecationWarning, + ) + return cls.DEFAULT_ALLOWED_METHODS + + @DEFAULT_METHOD_WHITELIST.setter + def DEFAULT_METHOD_WHITELIST(cls, value): + warnings.warn( + "Using 'Retry.DEFAULT_METHOD_WHITELIST' is deprecated and " + "will be removed in v2.0. Use 'Retry.DEFAULT_ALLOWED_METHODS' instead", + DeprecationWarning, + ) + cls.DEFAULT_ALLOWED_METHODS = value + + @property + def DEFAULT_REDIRECT_HEADERS_BLACKLIST(cls): + warnings.warn( + "Using 'Retry.DEFAULT_REDIRECT_HEADERS_BLACKLIST' is deprecated and " + "will be removed in v2.0. Use 'Retry.DEFAULT_REMOVE_HEADERS_ON_REDIRECT' instead", + DeprecationWarning, + ) + return cls.DEFAULT_REMOVE_HEADERS_ON_REDIRECT + + @DEFAULT_REDIRECT_HEADERS_BLACKLIST.setter + def DEFAULT_REDIRECT_HEADERS_BLACKLIST(cls, value): + warnings.warn( + "Using 'Retry.DEFAULT_REDIRECT_HEADERS_BLACKLIST' is deprecated and " + "will be removed in v2.0. Use 'Retry.DEFAULT_REMOVE_HEADERS_ON_REDIRECT' instead", + DeprecationWarning, + ) + cls.DEFAULT_REMOVE_HEADERS_ON_REDIRECT = value + + +@six.add_metaclass(_RetryMeta) +class Retry(object): + """Retry configuration. + + Each retry attempt will create a new Retry object with updated values, so + they can be safely reused. + + Retries can be defined as a default for a pool:: + + retries = Retry(connect=5, read=2, redirect=5) + http = PoolManager(retries=retries) + response = http.request('GET', 'http://example.com/') + + Or per-request (which overrides the default for the pool):: + + response = http.request('GET', 'http://example.com/', retries=Retry(10)) + + Retries can be disabled by passing ``False``:: + + response = http.request('GET', 'http://example.com/', retries=False) + + Errors will be wrapped in :class:`~urllib3.exceptions.MaxRetryError` unless + retries are disabled, in which case the causing exception will be raised. + + :param int total: + Total number of retries to allow. Takes precedence over other counts. + + Set to ``None`` to remove this constraint and fall back on other + counts. + + Set to ``0`` to fail on the first retry. + + Set to ``False`` to disable and imply ``raise_on_redirect=False``. + + :param int connect: + How many connection-related errors to retry on. + + These are errors raised before the request is sent to the remote server, + which we assume has not triggered the server to process the request. + + Set to ``0`` to fail on the first retry of this type. + + :param int read: + How many times to retry on read errors. + + These errors are raised after the request was sent to the server, so the + request may have side-effects. + + Set to ``0`` to fail on the first retry of this type. + + :param int redirect: + How many redirects to perform. Limit this to avoid infinite redirect + loops. + + A redirect is a HTTP response with a status code 301, 302, 303, 307 or + 308. + + Set to ``0`` to fail on the first retry of this type. + + Set to ``False`` to disable and imply ``raise_on_redirect=False``. + + :param int status: + How many times to retry on bad status codes. + + These are retries made on responses, where status code matches + ``status_forcelist``. + + Set to ``0`` to fail on the first retry of this type. + + :param int other: + How many times to retry on other errors. + + Other errors are errors that are not connect, read, redirect or status errors. + These errors might be raised after the request was sent to the server, so the + request might have side-effects. + + Set to ``0`` to fail on the first retry of this type. + + If ``total`` is not set, it's a good idea to set this to 0 to account + for unexpected edge cases and avoid infinite retry loops. + + :param iterable allowed_methods: + Set of uppercased HTTP method verbs that we should retry on. + + By default, we only retry on methods which are considered to be + idempotent (multiple requests with the same parameters end with the + same state). See :attr:`Retry.DEFAULT_ALLOWED_METHODS`. + + Set to a ``False`` value to retry on any verb. + + .. warning:: + + Previously this parameter was named ``method_whitelist``, that + usage is deprecated in v1.26.0 and will be removed in v2.0. + + :param iterable status_forcelist: + A set of integer HTTP status codes that we should force a retry on. + A retry is initiated if the request method is in ``allowed_methods`` + and the response status code is in ``status_forcelist``. + + By default, this is disabled with ``None``. + + :param float backoff_factor: + A backoff factor to apply between attempts after the second try + (most errors are resolved immediately by a second try without a + delay). urllib3 will sleep for:: + + {backoff factor} * (2 ** ({number of total retries} - 1)) + + seconds. If the backoff_factor is 0.1, then :func:`.sleep` will sleep + for [0.0s, 0.2s, 0.4s, ...] between retries. It will never be longer + than :attr:`Retry.BACKOFF_MAX`. + + By default, backoff is disabled (set to 0). + + :param bool raise_on_redirect: Whether, if the number of redirects is + exhausted, to raise a MaxRetryError, or to return a response with a + response code in the 3xx range. + + :param bool raise_on_status: Similar meaning to ``raise_on_redirect``: + whether we should raise an exception, or return a response, + if status falls in ``status_forcelist`` range and retries have + been exhausted. + + :param tuple history: The history of the request encountered during + each call to :meth:`~Retry.increment`. The list is in the order + the requests occurred. Each list item is of class :class:`RequestHistory`. + + :param bool respect_retry_after_header: + Whether to respect Retry-After header on status codes defined as + :attr:`Retry.RETRY_AFTER_STATUS_CODES` or not. + + :param iterable remove_headers_on_redirect: + Sequence of headers to remove from the request when a response + indicating a redirect is returned before firing off the redirected + request. + """ + + #: Default methods to be used for ``allowed_methods`` + DEFAULT_ALLOWED_METHODS = frozenset( + ["HEAD", "GET", "PUT", "DELETE", "OPTIONS", "TRACE"] + ) + + #: Default status codes to be used for ``status_forcelist`` + RETRY_AFTER_STATUS_CODES = frozenset([413, 429, 503]) + + #: Default headers to be used for ``remove_headers_on_redirect`` + DEFAULT_REMOVE_HEADERS_ON_REDIRECT = frozenset(["Authorization"]) + + #: Maximum backoff time. + BACKOFF_MAX = 120 + + def __init__( + self, + total=10, + connect=None, + read=None, + redirect=None, + status=None, + other=None, + allowed_methods=_Default, + status_forcelist=None, + backoff_factor=0, + raise_on_redirect=True, + raise_on_status=True, + history=None, + respect_retry_after_header=True, + remove_headers_on_redirect=_Default, + # TODO: Deprecated, remove in v2.0 + method_whitelist=_Default, + ): + + if method_whitelist is not _Default: + if allowed_methods is not _Default: + raise ValueError( + "Using both 'allowed_methods' and " + "'method_whitelist' together is not allowed. " + "Instead only use 'allowed_methods'" + ) + warnings.warn( + "Using 'method_whitelist' with Retry is deprecated and " + "will be removed in v2.0. Use 'allowed_methods' instead", + DeprecationWarning, + stacklevel=2, + ) + allowed_methods = method_whitelist + if allowed_methods is _Default: + allowed_methods = self.DEFAULT_ALLOWED_METHODS + if remove_headers_on_redirect is _Default: + remove_headers_on_redirect = self.DEFAULT_REMOVE_HEADERS_ON_REDIRECT + + self.total = total + self.connect = connect + self.read = read + self.status = status + self.other = other + + if redirect is False or total is False: + redirect = 0 + raise_on_redirect = False + + self.redirect = redirect + self.status_forcelist = status_forcelist or set() + self.allowed_methods = allowed_methods + self.backoff_factor = backoff_factor + self.raise_on_redirect = raise_on_redirect + self.raise_on_status = raise_on_status + self.history = history or tuple() + self.respect_retry_after_header = respect_retry_after_header + self.remove_headers_on_redirect = frozenset( + [h.lower() for h in remove_headers_on_redirect] + ) + + def new(self, **kw): + params = dict( + total=self.total, + connect=self.connect, + read=self.read, + redirect=self.redirect, + status=self.status, + other=self.other, + status_forcelist=self.status_forcelist, + backoff_factor=self.backoff_factor, + raise_on_redirect=self.raise_on_redirect, + raise_on_status=self.raise_on_status, + history=self.history, + remove_headers_on_redirect=self.remove_headers_on_redirect, + respect_retry_after_header=self.respect_retry_after_header, + ) + + # TODO: If already given in **kw we use what's given to us + # If not given we need to figure out what to pass. We decide + # based on whether our class has the 'method_whitelist' property + # and if so we pass the deprecated 'method_whitelist' otherwise + # we use 'allowed_methods'. Remove in v2.0 + if "method_whitelist" not in kw and "allowed_methods" not in kw: + if "method_whitelist" in self.__dict__: + warnings.warn( + "Using 'method_whitelist' with Retry is deprecated and " + "will be removed in v2.0. Use 'allowed_methods' instead", + DeprecationWarning, + ) + params["method_whitelist"] = self.allowed_methods + else: + params["allowed_methods"] = self.allowed_methods + + params.update(kw) + return type(self)(**params) + + @classmethod + def from_int(cls, retries, redirect=True, default=None): + """Backwards-compatibility for the old retries format.""" + if retries is None: + retries = default if default is not None else cls.DEFAULT + + if isinstance(retries, Retry): + return retries + + redirect = bool(redirect) and None + new_retries = cls(retries, redirect=redirect) + log.debug("Converted retries value: %r -> %r", retries, new_retries) + return new_retries + + def get_backoff_time(self): + """Formula for computing the current backoff + + :rtype: float + """ + # We want to consider only the last consecutive errors sequence (Ignore redirects). + consecutive_errors_len = len( + list( + takewhile(lambda x: x.redirect_location is None, reversed(self.history)) + ) + ) + if consecutive_errors_len <= 1: + return 0 + + backoff_value = self.backoff_factor * (2 ** (consecutive_errors_len - 1)) + return min(self.BACKOFF_MAX, backoff_value) + + def parse_retry_after(self, retry_after): + # Whitespace: https://tools.ietf.org/html/rfc7230#section-3.2.4 + if re.match(r"^\s*[0-9]+\s*$", retry_after): + seconds = int(retry_after) + else: + retry_date_tuple = email.utils.parsedate_tz(retry_after) + if retry_date_tuple is None: + raise InvalidHeader("Invalid Retry-After header: %s" % retry_after) + if retry_date_tuple[9] is None: # Python 2 + # Assume UTC if no timezone was specified + # On Python2.7, parsedate_tz returns None for a timezone offset + # instead of 0 if no timezone is given, where mktime_tz treats + # a None timezone offset as local time. + retry_date_tuple = retry_date_tuple[:9] + (0,) + retry_date_tuple[10:] + + retry_date = email.utils.mktime_tz(retry_date_tuple) + seconds = retry_date - time.time() + + if seconds < 0: + seconds = 0 + + return seconds + + def get_retry_after(self, response): + """Get the value of Retry-After in seconds.""" + + retry_after = response.getheader("Retry-After") + + if retry_after is None: + return None + + return self.parse_retry_after(retry_after) + + def sleep_for_retry(self, response=None): + retry_after = self.get_retry_after(response) + if retry_after: + time.sleep(retry_after) + return True + + return False + + def _sleep_backoff(self): + backoff = self.get_backoff_time() + if backoff <= 0: + return + time.sleep(backoff) + + def sleep(self, response=None): + """Sleep between retry attempts. + + This method will respect a server's ``Retry-After`` response header + and sleep the duration of the time requested. If that is not present, it + will use an exponential backoff. By default, the backoff factor is 0 and + this method will return immediately. + """ + + if self.respect_retry_after_header and response: + slept = self.sleep_for_retry(response) + if slept: + return + + self._sleep_backoff() + + def _is_connection_error(self, err): + """Errors when we're fairly sure that the server did not receive the + request, so it should be safe to retry. + """ + if isinstance(err, ProxyError): + err = err.original_error + return isinstance(err, ConnectTimeoutError) + + def _is_read_error(self, err): + """Errors that occur after the request has been started, so we should + assume that the server began processing it. + """ + return isinstance(err, (ReadTimeoutError, ProtocolError)) + + def _is_method_retryable(self, method): + """Checks if a given HTTP method should be retried upon, depending if + it is included in the allowed_methods + """ + # TODO: For now favor if the Retry implementation sets its own method_whitelist + # property outside of our constructor to avoid breaking custom implementations. + if "method_whitelist" in self.__dict__: + warnings.warn( + "Using 'method_whitelist' with Retry is deprecated and " + "will be removed in v2.0. Use 'allowed_methods' instead", + DeprecationWarning, + ) + allowed_methods = self.method_whitelist + else: + allowed_methods = self.allowed_methods + + if allowed_methods and method.upper() not in allowed_methods: + return False + return True + + def is_retry(self, method, status_code, has_retry_after=False): + """Is this method/status code retryable? (Based on allowlists and control + variables such as the number of total retries to allow, whether to + respect the Retry-After header, whether this header is present, and + whether the returned status code is on the list of status codes to + be retried upon on the presence of the aforementioned header) + """ + if not self._is_method_retryable(method): + return False + + if self.status_forcelist and status_code in self.status_forcelist: + return True + + return ( + self.total + and self.respect_retry_after_header + and has_retry_after + and (status_code in self.RETRY_AFTER_STATUS_CODES) + ) + + def is_exhausted(self): + """Are we out of retries?""" + retry_counts = ( + self.total, + self.connect, + self.read, + self.redirect, + self.status, + self.other, + ) + retry_counts = list(filter(None, retry_counts)) + if not retry_counts: + return False + + return min(retry_counts) < 0 + + def increment( + self, + method=None, + url=None, + response=None, + error=None, + _pool=None, + _stacktrace=None, + ): + """Return a new Retry object with incremented retry counters. + + :param response: A response object, or None, if the server did not + return a response. + :type response: :class:`~urllib3.response.HTTPResponse` + :param Exception error: An error encountered during the request, or + None if the response was received successfully. + + :return: A new ``Retry`` object. + """ + if self.total is False and error: + # Disabled, indicate to re-raise the error. + raise six.reraise(type(error), error, _stacktrace) + + total = self.total + if total is not None: + total -= 1 + + connect = self.connect + read = self.read + redirect = self.redirect + status_count = self.status + other = self.other + cause = "unknown" + status = None + redirect_location = None + + if error and self._is_connection_error(error): + # Connect retry? + if connect is False: + raise six.reraise(type(error), error, _stacktrace) + elif connect is not None: + connect -= 1 + + elif error and self._is_read_error(error): + # Read retry? + if read is False or not self._is_method_retryable(method): + raise six.reraise(type(error), error, _stacktrace) + elif read is not None: + read -= 1 + + elif error: + # Other retry? + if other is not None: + other -= 1 + + elif response and response.get_redirect_location(): + # Redirect retry? + if redirect is not None: + redirect -= 1 + cause = "too many redirects" + redirect_location = response.get_redirect_location() + status = response.status + + else: + # Incrementing because of a server error like a 500 in + # status_forcelist and the given method is in the allowed_methods + cause = ResponseError.GENERIC_ERROR + if response and response.status: + if status_count is not None: + status_count -= 1 + cause = ResponseError.SPECIFIC_ERROR.format(status_code=response.status) + status = response.status + + history = self.history + ( + RequestHistory(method, url, error, status, redirect_location), + ) + + new_retry = self.new( + total=total, + connect=connect, + read=read, + redirect=redirect, + status=status_count, + other=other, + history=history, + ) + + if new_retry.is_exhausted(): + raise MaxRetryError(_pool, url, error or ResponseError(cause)) + + log.debug("Incremented Retry for (url='%s'): %r", url, new_retry) + + return new_retry + + def __repr__(self): + return ( + "{cls.__name__}(total={self.total}, connect={self.connect}, " + "read={self.read}, redirect={self.redirect}, status={self.status})" + ).format(cls=type(self), self=self) + + def __getattr__(self, item): + if item == "method_whitelist": + # TODO: Remove this deprecated alias in v2.0 + warnings.warn( + "Using 'method_whitelist' with Retry is deprecated and " + "will be removed in v2.0. Use 'allowed_methods' instead", + DeprecationWarning, + ) + return self.allowed_methods + try: + return getattr(super(Retry, self), item) + except AttributeError: + return getattr(Retry, item) + + +# For backwards compatibility (equivalent to pre-v1.9): +Retry.DEFAULT = Retry(3) diff --git a/venv/lib/python3.8/site-packages/urllib3/util/ssl_.py b/venv/lib/python3.8/site-packages/urllib3/util/ssl_.py new file mode 100644 index 0000000..8f86781 --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3/util/ssl_.py @@ -0,0 +1,495 @@ +from __future__ import absolute_import + +import hmac +import os +import sys +import warnings +from binascii import hexlify, unhexlify +from hashlib import md5, sha1, sha256 + +from ..exceptions import ( + InsecurePlatformWarning, + ProxySchemeUnsupported, + SNIMissingWarning, + SSLError, +) +from ..packages import six +from .url import BRACELESS_IPV6_ADDRZ_RE, IPV4_RE + +SSLContext = None +SSLTransport = None +HAS_SNI = False +IS_PYOPENSSL = False +IS_SECURETRANSPORT = False +ALPN_PROTOCOLS = ["http/1.1"] + +# Maps the length of a digest to a possible hash function producing this digest +HASHFUNC_MAP = {32: md5, 40: sha1, 64: sha256} + + +def _const_compare_digest_backport(a, b): + """ + Compare two digests of equal length in constant time. + + The digests must be of type str/bytes. + Returns True if the digests match, and False otherwise. + """ + result = abs(len(a) - len(b)) + for left, right in zip(bytearray(a), bytearray(b)): + result |= left ^ right + return result == 0 + + +_const_compare_digest = getattr(hmac, "compare_digest", _const_compare_digest_backport) + +try: # Test for SSL features + import ssl + from ssl import CERT_REQUIRED, wrap_socket +except ImportError: + pass + +try: + from ssl import HAS_SNI # Has SNI? +except ImportError: + pass + +try: + from .ssltransport import SSLTransport +except ImportError: + pass + + +try: # Platform-specific: Python 3.6 + from ssl import PROTOCOL_TLS + + PROTOCOL_SSLv23 = PROTOCOL_TLS +except ImportError: + try: + from ssl import PROTOCOL_SSLv23 as PROTOCOL_TLS + + PROTOCOL_SSLv23 = PROTOCOL_TLS + except ImportError: + PROTOCOL_SSLv23 = PROTOCOL_TLS = 2 + +try: + from ssl import PROTOCOL_TLS_CLIENT +except ImportError: + PROTOCOL_TLS_CLIENT = PROTOCOL_TLS + + +try: + from ssl import OP_NO_COMPRESSION, OP_NO_SSLv2, OP_NO_SSLv3 +except ImportError: + OP_NO_SSLv2, OP_NO_SSLv3 = 0x1000000, 0x2000000 + OP_NO_COMPRESSION = 0x20000 + + +try: # OP_NO_TICKET was added in Python 3.6 + from ssl import OP_NO_TICKET +except ImportError: + OP_NO_TICKET = 0x4000 + + +# A secure default. +# Sources for more information on TLS ciphers: +# +# - https://wiki.mozilla.org/Security/Server_Side_TLS +# - https://www.ssllabs.com/projects/best-practices/index.html +# - https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/ +# +# The general intent is: +# - prefer cipher suites that offer perfect forward secrecy (DHE/ECDHE), +# - prefer ECDHE over DHE for better performance, +# - prefer any AES-GCM and ChaCha20 over any AES-CBC for better performance and +# security, +# - prefer AES-GCM over ChaCha20 because hardware-accelerated AES is common, +# - disable NULL authentication, MD5 MACs, DSS, and other +# insecure ciphers for security reasons. +# - NOTE: TLS 1.3 cipher suites are managed through a different interface +# not exposed by CPython (yet!) and are enabled by default if they're available. +DEFAULT_CIPHERS = ":".join( + [ + "ECDHE+AESGCM", + "ECDHE+CHACHA20", + "DHE+AESGCM", + "DHE+CHACHA20", + "ECDH+AESGCM", + "DH+AESGCM", + "ECDH+AES", + "DH+AES", + "RSA+AESGCM", + "RSA+AES", + "!aNULL", + "!eNULL", + "!MD5", + "!DSS", + ] +) + +try: + from ssl import SSLContext # Modern SSL? +except ImportError: + + class SSLContext(object): # Platform-specific: Python 2 + def __init__(self, protocol_version): + self.protocol = protocol_version + # Use default values from a real SSLContext + self.check_hostname = False + self.verify_mode = ssl.CERT_NONE + self.ca_certs = None + self.options = 0 + self.certfile = None + self.keyfile = None + self.ciphers = None + + def load_cert_chain(self, certfile, keyfile): + self.certfile = certfile + self.keyfile = keyfile + + def load_verify_locations(self, cafile=None, capath=None, cadata=None): + self.ca_certs = cafile + + if capath is not None: + raise SSLError("CA directories not supported in older Pythons") + + if cadata is not None: + raise SSLError("CA data not supported in older Pythons") + + def set_ciphers(self, cipher_suite): + self.ciphers = cipher_suite + + def wrap_socket(self, socket, server_hostname=None, server_side=False): + warnings.warn( + "A true SSLContext object is not available. This prevents " + "urllib3 from configuring SSL appropriately and may cause " + "certain SSL connections to fail. You can upgrade to a newer " + "version of Python to solve this. For more information, see " + "https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html" + "#ssl-warnings", + InsecurePlatformWarning, + ) + kwargs = { + "keyfile": self.keyfile, + "certfile": self.certfile, + "ca_certs": self.ca_certs, + "cert_reqs": self.verify_mode, + "ssl_version": self.protocol, + "server_side": server_side, + } + return wrap_socket(socket, ciphers=self.ciphers, **kwargs) + + +def assert_fingerprint(cert, fingerprint): + """ + Checks if given fingerprint matches the supplied certificate. + + :param cert: + Certificate as bytes object. + :param fingerprint: + Fingerprint as string of hexdigits, can be interspersed by colons. + """ + + fingerprint = fingerprint.replace(":", "").lower() + digest_length = len(fingerprint) + hashfunc = HASHFUNC_MAP.get(digest_length) + if not hashfunc: + raise SSLError("Fingerprint of invalid length: {0}".format(fingerprint)) + + # We need encode() here for py32; works on py2 and p33. + fingerprint_bytes = unhexlify(fingerprint.encode()) + + cert_digest = hashfunc(cert).digest() + + if not _const_compare_digest(cert_digest, fingerprint_bytes): + raise SSLError( + 'Fingerprints did not match. Expected "{0}", got "{1}".'.format( + fingerprint, hexlify(cert_digest) + ) + ) + + +def resolve_cert_reqs(candidate): + """ + Resolves the argument to a numeric constant, which can be passed to + the wrap_socket function/method from the ssl module. + Defaults to :data:`ssl.CERT_REQUIRED`. + If given a string it is assumed to be the name of the constant in the + :mod:`ssl` module or its abbreviation. + (So you can specify `REQUIRED` instead of `CERT_REQUIRED`. + If it's neither `None` nor a string we assume it is already the numeric + constant which can directly be passed to wrap_socket. + """ + if candidate is None: + return CERT_REQUIRED + + if isinstance(candidate, str): + res = getattr(ssl, candidate, None) + if res is None: + res = getattr(ssl, "CERT_" + candidate) + return res + + return candidate + + +def resolve_ssl_version(candidate): + """ + like resolve_cert_reqs + """ + if candidate is None: + return PROTOCOL_TLS + + if isinstance(candidate, str): + res = getattr(ssl, candidate, None) + if res is None: + res = getattr(ssl, "PROTOCOL_" + candidate) + return res + + return candidate + + +def create_urllib3_context( + ssl_version=None, cert_reqs=None, options=None, ciphers=None +): + """All arguments have the same meaning as ``ssl_wrap_socket``. + + By default, this function does a lot of the same work that + ``ssl.create_default_context`` does on Python 3.4+. It: + + - Disables SSLv2, SSLv3, and compression + - Sets a restricted set of server ciphers + + If you wish to enable SSLv3, you can do:: + + from urllib3.util import ssl_ + context = ssl_.create_urllib3_context() + context.options &= ~ssl_.OP_NO_SSLv3 + + You can do the same to enable compression (substituting ``COMPRESSION`` + for ``SSLv3`` in the last line above). + + :param ssl_version: + The desired protocol version to use. This will default to + PROTOCOL_SSLv23 which will negotiate the highest protocol that both + the server and your installation of OpenSSL support. + :param cert_reqs: + Whether to require the certificate verification. This defaults to + ``ssl.CERT_REQUIRED``. + :param options: + Specific OpenSSL options. These default to ``ssl.OP_NO_SSLv2``, + ``ssl.OP_NO_SSLv3``, ``ssl.OP_NO_COMPRESSION``, and ``ssl.OP_NO_TICKET``. + :param ciphers: + Which cipher suites to allow the server to select. + :returns: + Constructed SSLContext object with specified options + :rtype: SSLContext + """ + # PROTOCOL_TLS is deprecated in Python 3.10 + if not ssl_version or ssl_version == PROTOCOL_TLS: + ssl_version = PROTOCOL_TLS_CLIENT + + context = SSLContext(ssl_version) + + context.set_ciphers(ciphers or DEFAULT_CIPHERS) + + # Setting the default here, as we may have no ssl module on import + cert_reqs = ssl.CERT_REQUIRED if cert_reqs is None else cert_reqs + + if options is None: + options = 0 + # SSLv2 is easily broken and is considered harmful and dangerous + options |= OP_NO_SSLv2 + # SSLv3 has several problems and is now dangerous + options |= OP_NO_SSLv3 + # Disable compression to prevent CRIME attacks for OpenSSL 1.0+ + # (issue #309) + options |= OP_NO_COMPRESSION + # TLSv1.2 only. Unless set explicitly, do not request tickets. + # This may save some bandwidth on wire, and although the ticket is encrypted, + # there is a risk associated with it being on wire, + # if the server is not rotating its ticketing keys properly. + options |= OP_NO_TICKET + + context.options |= options + + # Enable post-handshake authentication for TLS 1.3, see GH #1634. PHA is + # necessary for conditional client cert authentication with TLS 1.3. + # The attribute is None for OpenSSL <= 1.1.0 or does not exist in older + # versions of Python. We only enable on Python 3.7.4+ or if certificate + # verification is enabled to work around Python issue #37428 + # See: https://bugs.python.org/issue37428 + if (cert_reqs == ssl.CERT_REQUIRED or sys.version_info >= (3, 7, 4)) and getattr( + context, "post_handshake_auth", None + ) is not None: + context.post_handshake_auth = True + + def disable_check_hostname(): + if ( + getattr(context, "check_hostname", None) is not None + ): # Platform-specific: Python 3.2 + # We do our own verification, including fingerprints and alternative + # hostnames. So disable it here + context.check_hostname = False + + # The order of the below lines setting verify_mode and check_hostname + # matter due to safe-guards SSLContext has to prevent an SSLContext with + # check_hostname=True, verify_mode=NONE/OPTIONAL. This is made even more + # complex because we don't know whether PROTOCOL_TLS_CLIENT will be used + # or not so we don't know the initial state of the freshly created SSLContext. + if cert_reqs == ssl.CERT_REQUIRED: + context.verify_mode = cert_reqs + disable_check_hostname() + else: + disable_check_hostname() + context.verify_mode = cert_reqs + + # Enable logging of TLS session keys via defacto standard environment variable + # 'SSLKEYLOGFILE', if the feature is available (Python 3.8+). Skip empty values. + if hasattr(context, "keylog_filename"): + sslkeylogfile = os.environ.get("SSLKEYLOGFILE") + if sslkeylogfile: + context.keylog_filename = sslkeylogfile + + return context + + +def ssl_wrap_socket( + sock, + keyfile=None, + certfile=None, + cert_reqs=None, + ca_certs=None, + server_hostname=None, + ssl_version=None, + ciphers=None, + ssl_context=None, + ca_cert_dir=None, + key_password=None, + ca_cert_data=None, + tls_in_tls=False, +): + """ + All arguments except for server_hostname, ssl_context, and ca_cert_dir have + the same meaning as they do when using :func:`ssl.wrap_socket`. + + :param server_hostname: + When SNI is supported, the expected hostname of the certificate + :param ssl_context: + A pre-made :class:`SSLContext` object. If none is provided, one will + be created using :func:`create_urllib3_context`. + :param ciphers: + A string of ciphers we wish the client to support. + :param ca_cert_dir: + A directory containing CA certificates in multiple separate files, as + supported by OpenSSL's -CApath flag or the capath argument to + SSLContext.load_verify_locations(). + :param key_password: + Optional password if the keyfile is encrypted. + :param ca_cert_data: + Optional string containing CA certificates in PEM format suitable for + passing as the cadata parameter to SSLContext.load_verify_locations() + :param tls_in_tls: + Use SSLTransport to wrap the existing socket. + """ + context = ssl_context + if context is None: + # Note: This branch of code and all the variables in it are no longer + # used by urllib3 itself. We should consider deprecating and removing + # this code. + context = create_urllib3_context(ssl_version, cert_reqs, ciphers=ciphers) + + if ca_certs or ca_cert_dir or ca_cert_data: + try: + context.load_verify_locations(ca_certs, ca_cert_dir, ca_cert_data) + except (IOError, OSError) as e: + raise SSLError(e) + + elif ssl_context is None and hasattr(context, "load_default_certs"): + # try to load OS default certs; works well on Windows (require Python3.4+) + context.load_default_certs() + + # Attempt to detect if we get the goofy behavior of the + # keyfile being encrypted and OpenSSL asking for the + # passphrase via the terminal and instead error out. + if keyfile and key_password is None and _is_key_file_encrypted(keyfile): + raise SSLError("Client private key is encrypted, password is required") + + if certfile: + if key_password is None: + context.load_cert_chain(certfile, keyfile) + else: + context.load_cert_chain(certfile, keyfile, key_password) + + try: + if hasattr(context, "set_alpn_protocols"): + context.set_alpn_protocols(ALPN_PROTOCOLS) + except NotImplementedError: # Defensive: in CI, we always have set_alpn_protocols + pass + + # If we detect server_hostname is an IP address then the SNI + # extension should not be used according to RFC3546 Section 3.1 + use_sni_hostname = server_hostname and not is_ipaddress(server_hostname) + # SecureTransport uses server_hostname in certificate verification. + send_sni = (use_sni_hostname and HAS_SNI) or ( + IS_SECURETRANSPORT and server_hostname + ) + # Do not warn the user if server_hostname is an invalid SNI hostname. + if not HAS_SNI and use_sni_hostname: + warnings.warn( + "An HTTPS request has been made, but the SNI (Server Name " + "Indication) extension to TLS is not available on this platform. " + "This may cause the server to present an incorrect TLS " + "certificate, which can cause validation failures. You can upgrade to " + "a newer version of Python to solve this. For more information, see " + "https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html" + "#ssl-warnings", + SNIMissingWarning, + ) + + if send_sni: + ssl_sock = _ssl_wrap_socket_impl( + sock, context, tls_in_tls, server_hostname=server_hostname + ) + else: + ssl_sock = _ssl_wrap_socket_impl(sock, context, tls_in_tls) + return ssl_sock + + +def is_ipaddress(hostname): + """Detects whether the hostname given is an IPv4 or IPv6 address. + Also detects IPv6 addresses with Zone IDs. + + :param str hostname: Hostname to examine. + :return: True if the hostname is an IP address, False otherwise. + """ + if not six.PY2 and isinstance(hostname, bytes): + # IDN A-label bytes are ASCII compatible. + hostname = hostname.decode("ascii") + return bool(IPV4_RE.match(hostname) or BRACELESS_IPV6_ADDRZ_RE.match(hostname)) + + +def _is_key_file_encrypted(key_file): + """Detects if a key file is encrypted or not.""" + with open(key_file, "r") as f: + for line in f: + # Look for Proc-Type: 4,ENCRYPTED + if "ENCRYPTED" in line: + return True + + return False + + +def _ssl_wrap_socket_impl(sock, ssl_context, tls_in_tls, server_hostname=None): + if tls_in_tls: + if not SSLTransport: + # Import error, ssl is not available. + raise ProxySchemeUnsupported( + "TLS in TLS requires support for the 'ssl' module" + ) + + SSLTransport._validate_ssl_context_for_tls_in_tls(ssl_context) + return SSLTransport(sock, ssl_context, server_hostname) + + if server_hostname: + return ssl_context.wrap_socket(sock, server_hostname=server_hostname) + else: + return ssl_context.wrap_socket(sock) diff --git a/venv/lib/python3.8/site-packages/urllib3/util/ssltransport.py b/venv/lib/python3.8/site-packages/urllib3/util/ssltransport.py new file mode 100644 index 0000000..c2186bc --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3/util/ssltransport.py @@ -0,0 +1,221 @@ +import io +import socket +import ssl + +from urllib3.exceptions import ProxySchemeUnsupported +from urllib3.packages import six + +SSL_BLOCKSIZE = 16384 + + +class SSLTransport: + """ + The SSLTransport wraps an existing socket and establishes an SSL connection. + + Contrary to Python's implementation of SSLSocket, it allows you to chain + multiple TLS connections together. It's particularly useful if you need to + implement TLS within TLS. + + The class supports most of the socket API operations. + """ + + @staticmethod + def _validate_ssl_context_for_tls_in_tls(ssl_context): + """ + Raises a ProxySchemeUnsupported if the provided ssl_context can't be used + for TLS in TLS. + + The only requirement is that the ssl_context provides the 'wrap_bio' + methods. + """ + + if not hasattr(ssl_context, "wrap_bio"): + if six.PY2: + raise ProxySchemeUnsupported( + "TLS in TLS requires SSLContext.wrap_bio() which isn't " + "supported on Python 2" + ) + else: + raise ProxySchemeUnsupported( + "TLS in TLS requires SSLContext.wrap_bio() which isn't " + "available on non-native SSLContext" + ) + + def __init__( + self, socket, ssl_context, server_hostname=None, suppress_ragged_eofs=True + ): + """ + Create an SSLTransport around socket using the provided ssl_context. + """ + self.incoming = ssl.MemoryBIO() + self.outgoing = ssl.MemoryBIO() + + self.suppress_ragged_eofs = suppress_ragged_eofs + self.socket = socket + + self.sslobj = ssl_context.wrap_bio( + self.incoming, self.outgoing, server_hostname=server_hostname + ) + + # Perform initial handshake. + self._ssl_io_loop(self.sslobj.do_handshake) + + def __enter__(self): + return self + + def __exit__(self, *_): + self.close() + + def fileno(self): + return self.socket.fileno() + + def read(self, len=1024, buffer=None): + return self._wrap_ssl_read(len, buffer) + + def recv(self, len=1024, flags=0): + if flags != 0: + raise ValueError("non-zero flags not allowed in calls to recv") + return self._wrap_ssl_read(len) + + def recv_into(self, buffer, nbytes=None, flags=0): + if flags != 0: + raise ValueError("non-zero flags not allowed in calls to recv_into") + if buffer and (nbytes is None): + nbytes = len(buffer) + elif nbytes is None: + nbytes = 1024 + return self.read(nbytes, buffer) + + def sendall(self, data, flags=0): + if flags != 0: + raise ValueError("non-zero flags not allowed in calls to sendall") + count = 0 + with memoryview(data) as view, view.cast("B") as byte_view: + amount = len(byte_view) + while count < amount: + v = self.send(byte_view[count:]) + count += v + + def send(self, data, flags=0): + if flags != 0: + raise ValueError("non-zero flags not allowed in calls to send") + response = self._ssl_io_loop(self.sslobj.write, data) + return response + + def makefile( + self, mode="r", buffering=None, encoding=None, errors=None, newline=None + ): + """ + Python's httpclient uses makefile and buffered io when reading HTTP + messages and we need to support it. + + This is unfortunately a copy and paste of socket.py makefile with small + changes to point to the socket directly. + """ + if not set(mode) <= {"r", "w", "b"}: + raise ValueError("invalid mode %r (only r, w, b allowed)" % (mode,)) + + writing = "w" in mode + reading = "r" in mode or not writing + assert reading or writing + binary = "b" in mode + rawmode = "" + if reading: + rawmode += "r" + if writing: + rawmode += "w" + raw = socket.SocketIO(self, rawmode) + self.socket._io_refs += 1 + if buffering is None: + buffering = -1 + if buffering < 0: + buffering = io.DEFAULT_BUFFER_SIZE + if buffering == 0: + if not binary: + raise ValueError("unbuffered streams must be binary") + return raw + if reading and writing: + buffer = io.BufferedRWPair(raw, raw, buffering) + elif reading: + buffer = io.BufferedReader(raw, buffering) + else: + assert writing + buffer = io.BufferedWriter(raw, buffering) + if binary: + return buffer + text = io.TextIOWrapper(buffer, encoding, errors, newline) + text.mode = mode + return text + + def unwrap(self): + self._ssl_io_loop(self.sslobj.unwrap) + + def close(self): + self.socket.close() + + def getpeercert(self, binary_form=False): + return self.sslobj.getpeercert(binary_form) + + def version(self): + return self.sslobj.version() + + def cipher(self): + return self.sslobj.cipher() + + def selected_alpn_protocol(self): + return self.sslobj.selected_alpn_protocol() + + def selected_npn_protocol(self): + return self.sslobj.selected_npn_protocol() + + def shared_ciphers(self): + return self.sslobj.shared_ciphers() + + def compression(self): + return self.sslobj.compression() + + def settimeout(self, value): + self.socket.settimeout(value) + + def gettimeout(self): + return self.socket.gettimeout() + + def _decref_socketios(self): + self.socket._decref_socketios() + + def _wrap_ssl_read(self, len, buffer=None): + try: + return self._ssl_io_loop(self.sslobj.read, len, buffer) + except ssl.SSLError as e: + if e.errno == ssl.SSL_ERROR_EOF and self.suppress_ragged_eofs: + return 0 # eof, return 0. + else: + raise + + def _ssl_io_loop(self, func, *args): + """Performs an I/O loop between incoming/outgoing and the socket.""" + should_loop = True + ret = None + + while should_loop: + errno = None + try: + ret = func(*args) + except ssl.SSLError as e: + if e.errno not in (ssl.SSL_ERROR_WANT_READ, ssl.SSL_ERROR_WANT_WRITE): + # WANT_READ, and WANT_WRITE are expected, others are not. + raise e + errno = e.errno + + buf = self.outgoing.read() + self.socket.sendall(buf) + + if errno is None: + should_loop = False + elif errno == ssl.SSL_ERROR_WANT_READ: + buf = self.socket.recv(SSL_BLOCKSIZE) + if buf: + self.incoming.write(buf) + else: + self.incoming.write_eof() + return ret diff --git a/venv/lib/python3.8/site-packages/urllib3/util/timeout.py b/venv/lib/python3.8/site-packages/urllib3/util/timeout.py new file mode 100644 index 0000000..ff69593 --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3/util/timeout.py @@ -0,0 +1,268 @@ +from __future__ import absolute_import + +import time + +# The default socket timeout, used by httplib to indicate that no timeout was +# specified by the user +from socket import _GLOBAL_DEFAULT_TIMEOUT + +from ..exceptions import TimeoutStateError + +# A sentinel value to indicate that no timeout was specified by the user in +# urllib3 +_Default = object() + + +# Use time.monotonic if available. +current_time = getattr(time, "monotonic", time.time) + + +class Timeout(object): + """Timeout configuration. + + Timeouts can be defined as a default for a pool: + + .. code-block:: python + + timeout = Timeout(connect=2.0, read=7.0) + http = PoolManager(timeout=timeout) + response = http.request('GET', 'http://example.com/') + + Or per-request (which overrides the default for the pool): + + .. code-block:: python + + response = http.request('GET', 'http://example.com/', timeout=Timeout(10)) + + Timeouts can be disabled by setting all the parameters to ``None``: + + .. code-block:: python + + no_timeout = Timeout(connect=None, read=None) + response = http.request('GET', 'http://example.com/, timeout=no_timeout) + + + :param total: + This combines the connect and read timeouts into one; the read timeout + will be set to the time leftover from the connect attempt. In the + event that both a connect timeout and a total are specified, or a read + timeout and a total are specified, the shorter timeout will be applied. + + Defaults to None. + + :type total: int, float, or None + + :param connect: + The maximum amount of time (in seconds) to wait for a connection + attempt to a server to succeed. Omitting the parameter will default the + connect timeout to the system default, probably `the global default + timeout in socket.py + <http://hg.python.org/cpython/file/603b4d593758/Lib/socket.py#l535>`_. + None will set an infinite timeout for connection attempts. + + :type connect: int, float, or None + + :param read: + The maximum amount of time (in seconds) to wait between consecutive + read operations for a response from the server. Omitting the parameter + will default the read timeout to the system default, probably `the + global default timeout in socket.py + <http://hg.python.org/cpython/file/603b4d593758/Lib/socket.py#l535>`_. + None will set an infinite timeout. + + :type read: int, float, or None + + .. note:: + + Many factors can affect the total amount of time for urllib3 to return + an HTTP response. + + For example, Python's DNS resolver does not obey the timeout specified + on the socket. Other factors that can affect total request time include + high CPU load, high swap, the program running at a low priority level, + or other behaviors. + + In addition, the read and total timeouts only measure the time between + read operations on the socket connecting the client and the server, + not the total amount of time for the request to return a complete + response. For most requests, the timeout is raised because the server + has not sent the first byte in the specified time. This is not always + the case; if a server streams one byte every fifteen seconds, a timeout + of 20 seconds will not trigger, even though the request will take + several minutes to complete. + + If your goal is to cut off any request after a set amount of wall clock + time, consider having a second "watcher" thread to cut off a slow + request. + """ + + #: A sentinel object representing the default timeout value + DEFAULT_TIMEOUT = _GLOBAL_DEFAULT_TIMEOUT + + def __init__(self, total=None, connect=_Default, read=_Default): + self._connect = self._validate_timeout(connect, "connect") + self._read = self._validate_timeout(read, "read") + self.total = self._validate_timeout(total, "total") + self._start_connect = None + + def __repr__(self): + return "%s(connect=%r, read=%r, total=%r)" % ( + type(self).__name__, + self._connect, + self._read, + self.total, + ) + + # __str__ provided for backwards compatibility + __str__ = __repr__ + + @classmethod + def _validate_timeout(cls, value, name): + """Check that a timeout attribute is valid. + + :param value: The timeout value to validate + :param name: The name of the timeout attribute to validate. This is + used to specify in error messages. + :return: The validated and casted version of the given value. + :raises ValueError: If it is a numeric value less than or equal to + zero, or the type is not an integer, float, or None. + """ + if value is _Default: + return cls.DEFAULT_TIMEOUT + + if value is None or value is cls.DEFAULT_TIMEOUT: + return value + + if isinstance(value, bool): + raise ValueError( + "Timeout cannot be a boolean value. It must " + "be an int, float or None." + ) + try: + float(value) + except (TypeError, ValueError): + raise ValueError( + "Timeout value %s was %s, but it must be an " + "int, float or None." % (name, value) + ) + + try: + if value <= 0: + raise ValueError( + "Attempted to set %s timeout to %s, but the " + "timeout cannot be set to a value less " + "than or equal to 0." % (name, value) + ) + except TypeError: + # Python 3 + raise ValueError( + "Timeout value %s was %s, but it must be an " + "int, float or None." % (name, value) + ) + + return value + + @classmethod + def from_float(cls, timeout): + """Create a new Timeout from a legacy timeout value. + + The timeout value used by httplib.py sets the same timeout on the + connect(), and recv() socket requests. This creates a :class:`Timeout` + object that sets the individual timeouts to the ``timeout`` value + passed to this function. + + :param timeout: The legacy timeout value. + :type timeout: integer, float, sentinel default object, or None + :return: Timeout object + :rtype: :class:`Timeout` + """ + return Timeout(read=timeout, connect=timeout) + + def clone(self): + """Create a copy of the timeout object + + Timeout properties are stored per-pool but each request needs a fresh + Timeout object to ensure each one has its own start/stop configured. + + :return: a copy of the timeout object + :rtype: :class:`Timeout` + """ + # We can't use copy.deepcopy because that will also create a new object + # for _GLOBAL_DEFAULT_TIMEOUT, which socket.py uses as a sentinel to + # detect the user default. + return Timeout(connect=self._connect, read=self._read, total=self.total) + + def start_connect(self): + """Start the timeout clock, used during a connect() attempt + + :raises urllib3.exceptions.TimeoutStateError: if you attempt + to start a timer that has been started already. + """ + if self._start_connect is not None: + raise TimeoutStateError("Timeout timer has already been started.") + self._start_connect = current_time() + return self._start_connect + + def get_connect_duration(self): + """Gets the time elapsed since the call to :meth:`start_connect`. + + :return: Elapsed time in seconds. + :rtype: float + :raises urllib3.exceptions.TimeoutStateError: if you attempt + to get duration for a timer that hasn't been started. + """ + if self._start_connect is None: + raise TimeoutStateError( + "Can't get connect duration for timer that has not started." + ) + return current_time() - self._start_connect + + @property + def connect_timeout(self): + """Get the value to use when setting a connection timeout. + + This will be a positive float or integer, the value None + (never timeout), or the default system timeout. + + :return: Connect timeout. + :rtype: int, float, :attr:`Timeout.DEFAULT_TIMEOUT` or None + """ + if self.total is None: + return self._connect + + if self._connect is None or self._connect is self.DEFAULT_TIMEOUT: + return self.total + + return min(self._connect, self.total) + + @property + def read_timeout(self): + """Get the value for the read timeout. + + This assumes some time has elapsed in the connection timeout and + computes the read timeout appropriately. + + If self.total is set, the read timeout is dependent on the amount of + time taken by the connect timeout. If the connection time has not been + established, a :exc:`~urllib3.exceptions.TimeoutStateError` will be + raised. + + :return: Value to use for the read timeout. + :rtype: int, float, :attr:`Timeout.DEFAULT_TIMEOUT` or None + :raises urllib3.exceptions.TimeoutStateError: If :meth:`start_connect` + has not yet been called on this object. + """ + if ( + self.total is not None + and self.total is not self.DEFAULT_TIMEOUT + and self._read is not None + and self._read is not self.DEFAULT_TIMEOUT + ): + # In case the connect timeout has not yet been established. + if self._start_connect is None: + return self._read + return max(0, min(self.total - self.get_connect_duration(), self._read)) + elif self.total is not None and self.total is not self.DEFAULT_TIMEOUT: + return max(0, self.total - self.get_connect_duration()) + else: + return self._read diff --git a/venv/lib/python3.8/site-packages/urllib3/util/url.py b/venv/lib/python3.8/site-packages/urllib3/util/url.py new file mode 100644 index 0000000..81a03da --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3/util/url.py @@ -0,0 +1,432 @@ +from __future__ import absolute_import + +import re +from collections import namedtuple + +from ..exceptions import LocationParseError +from ..packages import six + +url_attrs = ["scheme", "auth", "host", "port", "path", "query", "fragment"] + +# We only want to normalize urls with an HTTP(S) scheme. +# urllib3 infers URLs without a scheme (None) to be http. +NORMALIZABLE_SCHEMES = ("http", "https", None) + +# Almost all of these patterns were derived from the +# 'rfc3986' module: https://github.com/python-hyper/rfc3986 +PERCENT_RE = re.compile(r"%[a-fA-F0-9]{2}") +SCHEME_RE = re.compile(r"^(?:[a-zA-Z][a-zA-Z0-9+-]*:|/)") +URI_RE = re.compile( + r"^(?:([a-zA-Z][a-zA-Z0-9+.-]*):)?" + r"(?://([^\\/?#]*))?" + r"([^?#]*)" + r"(?:\?([^#]*))?" + r"(?:#(.*))?$", + re.UNICODE | re.DOTALL, +) + +IPV4_PAT = r"(?:[0-9]{1,3}\.){3}[0-9]{1,3}" +HEX_PAT = "[0-9A-Fa-f]{1,4}" +LS32_PAT = "(?:{hex}:{hex}|{ipv4})".format(hex=HEX_PAT, ipv4=IPV4_PAT) +_subs = {"hex": HEX_PAT, "ls32": LS32_PAT} +_variations = [ + # 6( h16 ":" ) ls32 + "(?:%(hex)s:){6}%(ls32)s", + # "::" 5( h16 ":" ) ls32 + "::(?:%(hex)s:){5}%(ls32)s", + # [ h16 ] "::" 4( h16 ":" ) ls32 + "(?:%(hex)s)?::(?:%(hex)s:){4}%(ls32)s", + # [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32 + "(?:(?:%(hex)s:)?%(hex)s)?::(?:%(hex)s:){3}%(ls32)s", + # [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32 + "(?:(?:%(hex)s:){0,2}%(hex)s)?::(?:%(hex)s:){2}%(ls32)s", + # [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32 + "(?:(?:%(hex)s:){0,3}%(hex)s)?::%(hex)s:%(ls32)s", + # [ *4( h16 ":" ) h16 ] "::" ls32 + "(?:(?:%(hex)s:){0,4}%(hex)s)?::%(ls32)s", + # [ *5( h16 ":" ) h16 ] "::" h16 + "(?:(?:%(hex)s:){0,5}%(hex)s)?::%(hex)s", + # [ *6( h16 ":" ) h16 ] "::" + "(?:(?:%(hex)s:){0,6}%(hex)s)?::", +] + +UNRESERVED_PAT = r"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._!\-~" +IPV6_PAT = "(?:" + "|".join([x % _subs for x in _variations]) + ")" +ZONE_ID_PAT = "(?:%25|%)(?:[" + UNRESERVED_PAT + "]|%[a-fA-F0-9]{2})+" +IPV6_ADDRZ_PAT = r"\[" + IPV6_PAT + r"(?:" + ZONE_ID_PAT + r")?\]" +REG_NAME_PAT = r"(?:[^\[\]%:/?#]|%[a-fA-F0-9]{2})*" +TARGET_RE = re.compile(r"^(/[^?#]*)(?:\?([^#]*))?(?:#.*)?$") + +IPV4_RE = re.compile("^" + IPV4_PAT + "$") +IPV6_RE = re.compile("^" + IPV6_PAT + "$") +IPV6_ADDRZ_RE = re.compile("^" + IPV6_ADDRZ_PAT + "$") +BRACELESS_IPV6_ADDRZ_RE = re.compile("^" + IPV6_ADDRZ_PAT[2:-2] + "$") +ZONE_ID_RE = re.compile("(" + ZONE_ID_PAT + r")\]$") + +_HOST_PORT_PAT = ("^(%s|%s|%s)(?::([0-9]{0,5}))?$") % ( + REG_NAME_PAT, + IPV4_PAT, + IPV6_ADDRZ_PAT, +) +_HOST_PORT_RE = re.compile(_HOST_PORT_PAT, re.UNICODE | re.DOTALL) + +UNRESERVED_CHARS = set( + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-~" +) +SUB_DELIM_CHARS = set("!$&'()*+,;=") +USERINFO_CHARS = UNRESERVED_CHARS | SUB_DELIM_CHARS | {":"} +PATH_CHARS = USERINFO_CHARS | {"@", "/"} +QUERY_CHARS = FRAGMENT_CHARS = PATH_CHARS | {"?"} + + +class Url(namedtuple("Url", url_attrs)): + """ + Data structure for representing an HTTP URL. Used as a return value for + :func:`parse_url`. Both the scheme and host are normalized as they are + both case-insensitive according to RFC 3986. + """ + + __slots__ = () + + def __new__( + cls, + scheme=None, + auth=None, + host=None, + port=None, + path=None, + query=None, + fragment=None, + ): + if path and not path.startswith("/"): + path = "/" + path + if scheme is not None: + scheme = scheme.lower() + return super(Url, cls).__new__( + cls, scheme, auth, host, port, path, query, fragment + ) + + @property + def hostname(self): + """For backwards-compatibility with urlparse. We're nice like that.""" + return self.host + + @property + def request_uri(self): + """Absolute path including the query string.""" + uri = self.path or "/" + + if self.query is not None: + uri += "?" + self.query + + return uri + + @property + def netloc(self): + """Network location including host and port""" + if self.port: + return "%s:%d" % (self.host, self.port) + return self.host + + @property + def url(self): + """ + Convert self into a url + + This function should more or less round-trip with :func:`.parse_url`. The + returned url may not be exactly the same as the url inputted to + :func:`.parse_url`, but it should be equivalent by the RFC (e.g., urls + with a blank port will have : removed). + + Example: :: + + >>> U = parse_url('http://google.com/mail/') + >>> U.url + 'http://google.com/mail/' + >>> Url('http', 'username:password', 'host.com', 80, + ... '/path', 'query', 'fragment').url + 'http://username:password@host.com:80/path?query#fragment' + """ + scheme, auth, host, port, path, query, fragment = self + url = u"" + + # We use "is not None" we want things to happen with empty strings (or 0 port) + if scheme is not None: + url += scheme + u"://" + if auth is not None: + url += auth + u"@" + if host is not None: + url += host + if port is not None: + url += u":" + str(port) + if path is not None: + url += path + if query is not None: + url += u"?" + query + if fragment is not None: + url += u"#" + fragment + + return url + + def __str__(self): + return self.url + + +def split_first(s, delims): + """ + .. deprecated:: 1.25 + + Given a string and an iterable of delimiters, split on the first found + delimiter. Return two split parts and the matched delimiter. + + If not found, then the first part is the full input string. + + Example:: + + >>> split_first('foo/bar?baz', '?/=') + ('foo', 'bar?baz', '/') + >>> split_first('foo/bar?baz', '123') + ('foo/bar?baz', '', None) + + Scales linearly with number of delims. Not ideal for large number of delims. + """ + min_idx = None + min_delim = None + for d in delims: + idx = s.find(d) + if idx < 0: + continue + + if min_idx is None or idx < min_idx: + min_idx = idx + min_delim = d + + if min_idx is None or min_idx < 0: + return s, "", None + + return s[:min_idx], s[min_idx + 1 :], min_delim + + +def _encode_invalid_chars(component, allowed_chars, encoding="utf-8"): + """Percent-encodes a URI component without reapplying + onto an already percent-encoded component. + """ + if component is None: + return component + + component = six.ensure_text(component) + + # Normalize existing percent-encoded bytes. + # Try to see if the component we're encoding is already percent-encoded + # so we can skip all '%' characters but still encode all others. + component, percent_encodings = PERCENT_RE.subn( + lambda match: match.group(0).upper(), component + ) + + uri_bytes = component.encode("utf-8", "surrogatepass") + is_percent_encoded = percent_encodings == uri_bytes.count(b"%") + encoded_component = bytearray() + + for i in range(0, len(uri_bytes)): + # Will return a single character bytestring on both Python 2 & 3 + byte = uri_bytes[i : i + 1] + byte_ord = ord(byte) + if (is_percent_encoded and byte == b"%") or ( + byte_ord < 128 and byte.decode() in allowed_chars + ): + encoded_component += byte + continue + encoded_component.extend(b"%" + (hex(byte_ord)[2:].encode().zfill(2).upper())) + + return encoded_component.decode(encoding) + + +def _remove_path_dot_segments(path): + # See http://tools.ietf.org/html/rfc3986#section-5.2.4 for pseudo-code + segments = path.split("/") # Turn the path into a list of segments + output = [] # Initialize the variable to use to store output + + for segment in segments: + # '.' is the current directory, so ignore it, it is superfluous + if segment == ".": + continue + # Anything other than '..', should be appended to the output + elif segment != "..": + output.append(segment) + # In this case segment == '..', if we can, we should pop the last + # element + elif output: + output.pop() + + # If the path starts with '/' and the output is empty or the first string + # is non-empty + if path.startswith("/") and (not output or output[0]): + output.insert(0, "") + + # If the path starts with '/.' or '/..' ensure we add one more empty + # string to add a trailing '/' + if path.endswith(("/.", "/..")): + output.append("") + + return "/".join(output) + + +def _normalize_host(host, scheme): + if host: + if isinstance(host, six.binary_type): + host = six.ensure_str(host) + + if scheme in NORMALIZABLE_SCHEMES: + is_ipv6 = IPV6_ADDRZ_RE.match(host) + if is_ipv6: + match = ZONE_ID_RE.search(host) + if match: + start, end = match.span(1) + zone_id = host[start:end] + + if zone_id.startswith("%25") and zone_id != "%25": + zone_id = zone_id[3:] + else: + zone_id = zone_id[1:] + zone_id = "%" + _encode_invalid_chars(zone_id, UNRESERVED_CHARS) + return host[:start].lower() + zone_id + host[end:] + else: + return host.lower() + elif not IPV4_RE.match(host): + return six.ensure_str( + b".".join([_idna_encode(label) for label in host.split(".")]) + ) + return host + + +def _idna_encode(name): + if name and any([ord(x) > 128 for x in name]): + try: + import idna + except ImportError: + six.raise_from( + LocationParseError("Unable to parse URL without the 'idna' module"), + None, + ) + try: + return idna.encode(name.lower(), strict=True, std3_rules=True) + except idna.IDNAError: + six.raise_from( + LocationParseError(u"Name '%s' is not a valid IDNA label" % name), None + ) + return name.lower().encode("ascii") + + +def _encode_target(target): + """Percent-encodes a request target so that there are no invalid characters""" + path, query = TARGET_RE.match(target).groups() + target = _encode_invalid_chars(path, PATH_CHARS) + query = _encode_invalid_chars(query, QUERY_CHARS) + if query is not None: + target += "?" + query + return target + + +def parse_url(url): + """ + Given a url, return a parsed :class:`.Url` namedtuple. Best-effort is + performed to parse incomplete urls. Fields not provided will be None. + This parser is RFC 3986 compliant. + + The parser logic and helper functions are based heavily on + work done in the ``rfc3986`` module. + + :param str url: URL to parse into a :class:`.Url` namedtuple. + + Partly backwards-compatible with :mod:`urlparse`. + + Example:: + + >>> parse_url('http://google.com/mail/') + Url(scheme='http', host='google.com', port=None, path='/mail/', ...) + >>> parse_url('google.com:80') + Url(scheme=None, host='google.com', port=80, path=None, ...) + >>> parse_url('/foo?bar') + Url(scheme=None, host=None, port=None, path='/foo', query='bar', ...) + """ + if not url: + # Empty + return Url() + + source_url = url + if not SCHEME_RE.search(url): + url = "//" + url + + try: + scheme, authority, path, query, fragment = URI_RE.match(url).groups() + normalize_uri = scheme is None or scheme.lower() in NORMALIZABLE_SCHEMES + + if scheme: + scheme = scheme.lower() + + if authority: + auth, _, host_port = authority.rpartition("@") + auth = auth or None + host, port = _HOST_PORT_RE.match(host_port).groups() + if auth and normalize_uri: + auth = _encode_invalid_chars(auth, USERINFO_CHARS) + if port == "": + port = None + else: + auth, host, port = None, None, None + + if port is not None: + port = int(port) + if not (0 <= port <= 65535): + raise LocationParseError(url) + + host = _normalize_host(host, scheme) + + if normalize_uri and path: + path = _remove_path_dot_segments(path) + path = _encode_invalid_chars(path, PATH_CHARS) + if normalize_uri and query: + query = _encode_invalid_chars(query, QUERY_CHARS) + if normalize_uri and fragment: + fragment = _encode_invalid_chars(fragment, FRAGMENT_CHARS) + + except (ValueError, AttributeError): + return six.raise_from(LocationParseError(source_url), None) + + # For the sake of backwards compatibility we put empty + # string values for path if there are any defined values + # beyond the path in the URL. + # TODO: Remove this when we break backwards compatibility. + if not path: + if query is not None or fragment is not None: + path = "" + else: + path = None + + # Ensure that each part of the URL is a `str` for + # backwards compatibility. + if isinstance(url, six.text_type): + ensure_func = six.ensure_text + else: + ensure_func = six.ensure_str + + def ensure_type(x): + return x if x is None else ensure_func(x) + + return Url( + scheme=ensure_type(scheme), + auth=ensure_type(auth), + host=ensure_type(host), + port=port, + path=ensure_type(path), + query=ensure_type(query), + fragment=ensure_type(fragment), + ) + + +def get_host(url): + """ + Deprecated. Use :func:`parse_url` instead. + """ + p = parse_url(url) + return p.scheme or "http", p.hostname, p.port diff --git a/venv/lib/python3.8/site-packages/urllib3/util/wait.py b/venv/lib/python3.8/site-packages/urllib3/util/wait.py new file mode 100644 index 0000000..c280646 --- /dev/null +++ b/venv/lib/python3.8/site-packages/urllib3/util/wait.py @@ -0,0 +1,153 @@ +import errno +import select +import sys +from functools import partial + +try: + from time import monotonic +except ImportError: + from time import time as monotonic + +__all__ = ["NoWayToWaitForSocketError", "wait_for_read", "wait_for_write"] + + +class NoWayToWaitForSocketError(Exception): + pass + + +# How should we wait on sockets? +# +# There are two types of APIs you can use for waiting on sockets: the fancy +# modern stateful APIs like epoll/kqueue, and the older stateless APIs like +# select/poll. The stateful APIs are more efficient when you have a lots of +# sockets to keep track of, because you can set them up once and then use them +# lots of times. But we only ever want to wait on a single socket at a time +# and don't want to keep track of state, so the stateless APIs are actually +# more efficient. So we want to use select() or poll(). +# +# Now, how do we choose between select() and poll()? On traditional Unixes, +# select() has a strange calling convention that makes it slow, or fail +# altogether, for high-numbered file descriptors. The point of poll() is to fix +# that, so on Unixes, we prefer poll(). +# +# On Windows, there is no poll() (or at least Python doesn't provide a wrapper +# for it), but that's OK, because on Windows, select() doesn't have this +# strange calling convention; plain select() works fine. +# +# So: on Windows we use select(), and everywhere else we use poll(). We also +# fall back to select() in case poll() is somehow broken or missing. + +if sys.version_info >= (3, 5): + # Modern Python, that retries syscalls by default + def _retry_on_intr(fn, timeout): + return fn(timeout) + + +else: + # Old and broken Pythons. + def _retry_on_intr(fn, timeout): + if timeout is None: + deadline = float("inf") + else: + deadline = monotonic() + timeout + + while True: + try: + return fn(timeout) + # OSError for 3 <= pyver < 3.5, select.error for pyver <= 2.7 + except (OSError, select.error) as e: + # 'e.args[0]' incantation works for both OSError and select.error + if e.args[0] != errno.EINTR: + raise + else: + timeout = deadline - monotonic() + if timeout < 0: + timeout = 0 + if timeout == float("inf"): + timeout = None + continue + + +def select_wait_for_socket(sock, read=False, write=False, timeout=None): + if not read and not write: + raise RuntimeError("must specify at least one of read=True, write=True") + rcheck = [] + wcheck = [] + if read: + rcheck.append(sock) + if write: + wcheck.append(sock) + # When doing a non-blocking connect, most systems signal success by + # marking the socket writable. Windows, though, signals success by marked + # it as "exceptional". We paper over the difference by checking the write + # sockets for both conditions. (The stdlib selectors module does the same + # thing.) + fn = partial(select.select, rcheck, wcheck, wcheck) + rready, wready, xready = _retry_on_intr(fn, timeout) + return bool(rready or wready or xready) + + +def poll_wait_for_socket(sock, read=False, write=False, timeout=None): + if not read and not write: + raise RuntimeError("must specify at least one of read=True, write=True") + mask = 0 + if read: + mask |= select.POLLIN + if write: + mask |= select.POLLOUT + poll_obj = select.poll() + poll_obj.register(sock, mask) + + # For some reason, poll() takes timeout in milliseconds + def do_poll(t): + if t is not None: + t *= 1000 + return poll_obj.poll(t) + + return bool(_retry_on_intr(do_poll, timeout)) + + +def null_wait_for_socket(*args, **kwargs): + raise NoWayToWaitForSocketError("no select-equivalent available") + + +def _have_working_poll(): + # Apparently some systems have a select.poll that fails as soon as you try + # to use it, either due to strange configuration or broken monkeypatching + # from libraries like eventlet/greenlet. + try: + poll_obj = select.poll() + _retry_on_intr(poll_obj.poll, 0) + except (AttributeError, OSError): + return False + else: + return True + + +def wait_for_socket(*args, **kwargs): + # We delay choosing which implementation to use until the first time we're + # called. We could do it at import time, but then we might make the wrong + # decision if someone goes wild with monkeypatching select.poll after + # we're imported. + global wait_for_socket + if _have_working_poll(): + wait_for_socket = poll_wait_for_socket + elif hasattr(select, "select"): + wait_for_socket = select_wait_for_socket + else: # Platform-specific: Appengine. + wait_for_socket = null_wait_for_socket + return wait_for_socket(*args, **kwargs) + + +def wait_for_read(sock, timeout=None): + """Waits for reading to be available on a given socket. + Returns True if the socket is readable, or False if the timeout expired. + """ + return wait_for_socket(sock, read=True, timeout=timeout) + + +def wait_for_write(sock, timeout=None): + """Waits for writing to be available on a given socket. + Returns True if the socket is readable, or False if the timeout expired. + """ + return wait_for_socket(sock, write=True, timeout=timeout) diff --git a/venv/lib64 b/venv/lib64 new file mode 120000 index 0000000..7951405 --- /dev/null +++ b/venv/lib64 @@ -0,0 +1 @@ +lib \ No newline at end of file diff --git a/venv/pyvenv.cfg b/venv/pyvenv.cfg new file mode 100644 index 0000000..5d5aef2 --- /dev/null +++ b/venv/pyvenv.cfg @@ -0,0 +1,3 @@ +home = /usr/bin +include-system-site-packages = false +version = 3.8.6 diff --git a/venv/share/python-wheels/CacheControl-0.12.6-py2.py3-none-any.whl b/venv/share/python-wheels/CacheControl-0.12.6-py2.py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..4924d956ad131cbe41250e2e7bdce3e42be2335e GIT binary patch literal 23290 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 Q?jxQ>h+eOZ?%&`24bo5WhyVZp literal 0 HcmV?d00001 diff --git a/venv/share/python-wheels/appdirs-1.4.4-py2.py3-none-any.whl b/venv/share/python-wheels/appdirs-1.4.4-py2.py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..fab3a7b2758c2c31aa62a2454244e57f7fd43e43 GIT binary patch literal 14131 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 XMnxHLh<{y!{9BO!>Tejfe;xfVe6*92 literal 0 HcmV?d00001 diff --git a/venv/share/python-wheels/certifi-2020.4.5.1-py2.py3-none-any.whl b/venv/share/python-wheels/certifi-2020.4.5.1-py2.py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..c2220c20167c43c6e9d3a1b2f27ecaa53d1d13d1 GIT binary patch literal 161630 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 O_32A76`j5UkpBaaFa5>< literal 0 HcmV?d00001 diff --git a/venv/share/python-wheels/chardet-3.0.4-py2.py3-none-any.whl b/venv/share/python-wheels/chardet-3.0.4-py2.py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..455eac3a3a287330fc94c76a95e77db8f7847452 GIT binary patch literal 136755 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 ZvJ#*GB@IaU2l!(Fcn<7C03HN@{y(7kPj~<T literal 0 HcmV?d00001 diff --git a/venv/share/python-wheels/colorama-0.4.3-py2.py3-none-any.whl b/venv/share/python-wheels/colorama-0.4.3-py2.py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..6d5bdb900347b768aa0af39127a01a79356fc3de GIT binary patch literal 20362 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 E0P%w@F#rGn literal 0 HcmV?d00001 diff --git a/venv/share/python-wheels/contextlib2-0.6.0-py2.py3-none-any.whl b/venv/share/python-wheels/contextlib2-0.6.0-py2.py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..6f611c17fc58f2dccb4a961d89b020df697ad5f7 GIT binary patch literal 12457 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 O>Hk(EOz8i0_J07;-CUvo literal 0 HcmV?d00001 diff --git a/venv/share/python-wheels/distlib-0.3.0-py2.py3-none-any.whl b/venv/share/python-wheels/distlib-0.3.0-py2.py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..43c7867224814e8c142404b19a9ebeaafd17c2a9 GIT binary patch literal 147296 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%0D(-|d<Q-VUpi8x-8AEY0c8m_M z>4ev*;#QfHo;5)Q?z|Mr*2E;`P;}WCmx&k>(wQc0a`~9tW{(lfJq#r5M3u%1_+l97 zA;KCnQ2619{)s7AHyW4>s4d-4C=d~ghJr4hPkq54V|a-|cuHS<9EQEYKxowCDo{Hx zm^n*lU00Cfg*phFaaEzt{KY8v)X=JcJw;3-s8Y!F0fXsyi+%zo94(L0z1V7o+I4%i z^`GHDHoU<g&tO$;QNpDZ7Wv<&M~B1U3OE6k@5^*@i(;wBuG7gQQU^>z)_g!MN0uU3 zF*YG6st}L?*bx@xcPi8zKR*c&7+)V_^9EwZ;84+V2;I#}QkTPvaX2Ucd@RU`Pt;dK zSt8qUNcuyL9%DHqao%RLCbAS7VgNAL$WG@f{({t3VMUCj9f37Hx&^5&Be4)6jtM>T zS=K^771~Zili%xx63C5jk?p9st-fk<Rz&iv@cLbgUqA`TZlj%Huruh?eBxGqA5G@N zz+hOxv{F^T_aRk4btJTCHJQiioioa=<|T?>%~jbAeoSoLg~Z1kT2CAMQluFy*3$!> zBnG_qd4n5Br+l*HEzKJ~_h8ctgV8cgiV9wqrz&Dl6EF&)WBsnKe`+j4ca@|9dNtxO zOyn$pQZh;YR{$gswo&iWVvz}8%<oWd;I1?VyK7Y~ujHB>zZSP|((4%QX_Powapkmy z69JJi=YnsIzptTpN(PI6E#CfD3S(-&M;Ncg;D&%=^j!f3V*TiwBT!K@kl$1qtBIWx z9Ij63hVf3Pz;?_)(XDA|ijgUUyO`_QVh}X|8Xh(!mG$P8m0Xhbb#n~+16ZFoyMo*F z+C!sNN1Nf7S4Dd5QDY<<kDoUe1h~=NK3Y|4w}+-#i!z?eF!wid>|z?)PGoI-)g3~M z#n)L{reH`AC*p~$X<kc$wo{THd`c^x-A?hlPpCcSSuus;%nf*8qR`&*NvOD<0UBA< zP6sRTnA{*1Q-Q|he#+`N@G5-wApkFB9TO=(Myfb~TZ1foS}wsuVijn|z?W4yZAPy? zlL*3u8;Megq)>fjc@Ms#Y~z#_u-EEEFA%^7do?LQmhq{wDJr&ekZX@ob@>y_D}g!o zE&*whw@DJA7y~^E%tdWN;lmi8q16Kabn}^<GO*C%R7A^<4{9OTCdsUtE(-N)T20`q zAqxnyu%W40{5n*2HMS(5ks+h$07-%(T%rrz83vQ0(d`{E<KUHl?h7Goh;3eMMqPiA zP~9*v)#4-(SVQ~NvML@+0yvA$CKQCXcnT>=#%={%AXc<4_xG?AuNlB4uokrJ_Q5}N z%ttv;MYKXF--NtTMB#Ac0-%FX_f<`*G+O)UfVs=qv-;S;MAr^bvD>ZTBZXK2ojGXy zfvw2;cw51k&{2?U3_e^?R6K&6ENXOF@ZjYbg;Ig=7Eacxj)UNk92kMztwID4P11_V z4FO%52hF6;K{b*=6~blFEard`?_hl>LDV<xBl^=2x0@8bbhHu*VxbG4T^mI;NeiC3 z_^QNZ1_}a4XTd#`Pr>e-pd+bx40sDIn@M~$3I)LlZW!>w^*s&_X=X?vJUoUNZRO2P zz{M#tL>m!tc!oW`LB(5s8BBf-Buaw@=I@OeqlsMIpnHydFWdUoMdu$@8w|owm(Nxf zmcM1}*S51Y(seR=MqCl%LJ0K2c2MWIY^q|>X3t;^Q(WnQ-+J}C;NuA`A`MhD8(=R7 z{A`5R9Ulv$TDdOS?SZ0yQ3EUTPAXK<eBbypW(RMi3Jz>qHVz?G*$wky=ih!o6+5Yn zXJwB>1kp;7Jgpy-dQpzPO+hEIWwUsRhCY8YUxRhJsIw`_mR7S4=p{D;v$CqEkuGBO z=UCEilwSc*LdjYzaDpVLd4Or`Zx<-lBok0dS`9PJ$V1>ss(=VGSQ|R15_h;*W`TnU zYLpRs#8pFOhJGgoE>B#;Yy?rJH3L)cECXSgbNDpBC&K`1qcjzAiU7pjcIAoKUutW# zVqofX37Gf~U^cM#48Y7#=s+LXu?q_)1&9$`1uEoLLpoE}14@>W(SaUJu5hrh{$&NT zi0YbEF+LHyg3APGKiJx1wLm|!f<^t6?Z+$tgJW0&QarhhY|S!I#}Y9T!Ku)shS*`% ziuFjvMoN<l1ok5c;Rzm6&vser29jmu(ja9Q4>@X1ys)wCmpyp~U3nJk1FG{7HYTSk zlQUwxEvteBl${hHdPX};;q%(=CP*kp&G&p{(;zu%Ef;M&alICb4x18+EO=;(!y}?# zrD-L6_>s&|UktubuLMl>s+%a2YW^rZB{W&U{G@#=P&WAsS#=|9*qk|-hyzx#D?Uep zp)f6Npx2LED6^3HV9}kxs*1*qe~dISmY~iqDFNS6%trzVjbxlpAVwoO3K0ct^EuhY zu$(yPJG9p2sujuJT>E0M&{>TX@I*absgcW@A}?<hx;;@Z)Bu`-IY;))uo9YtqMlQW z&cIsSA=@AV>)ew!G>T8c0ackgyIvG&O#|7742F|7o`ZGH%8u|~1|crUlN(S%F&G(i z2h7_cgtfKVC=5vCLPEcH{IvBzUp`bhlc9xMOR_Zo)R;OeClw|Mu}ur%Au{Pooax2q zkF&1u*%%ybVfzFgCSL^itlu>PV3nr`Gmu1zD&hU5H9US#i4H;dnruL!Mq~NK1Z^12 zJ?sG5Q)JM?_U7WpF`gYX9slXt%*6h?%N#RI=u#4gdPr_qTYXx>5~QL$Z8WXPZ>dSD zqe`=N;{r&lrqN-XX^hciymH}O38#|fNA?rTQn;8>v@`0ZQ^yZB#atS9wPLE2MXIjW zBB++=jF3%T=IB|SrOoY-RSL^v(8PRV48-5OYVwB=RiH?J{8M_DvhfQ~6RWgEc1$PL zij*O0w;fRckoS~LM{EQkI55VG=>Tj;3k0xjXLoid2+U&x=!?Oy2`=SbhWc4ZestOM zj6w-eL?HF>yu<V68PM!W5u8|aMC2p=;)+!ZeEKVqVG#Tqjm7W6hGb!dI1TBkKR$&# zeegO`rKnhA#9t%=(;}T+PGQjnn7aX**@Aa=s?R?AY#8iRe})ecLGhP1lf6cYh|;mO zJaY;P+gRoeG3+*b1@E8adNs}3(Thw0c?}yjklkXojGCIS%{2;Da@MaxVUv4LZ!Kp( zz-V@hO?m70nt2LY-JtYYdY6wNJ!A?aUFuYz#n1AeGq$aVtc}Va?AI4@6*p;vepC_O zO5sY5K|U43?PT&2(uxLBwAi!ee+`&!F{YN*Dg>UxIxE))*03={5td@3R|n=57v$`q z{`)8QG*7QZZ~c40y<(v!+))piTGE&bfRy2dX7sff<K*@pj2UZZQS{6+kiuce`^H_~ zJXi>iA14P|!S^5zY$@+HI}UZ=Btt^<@^+A858Qa~?f%|(``;vQ-<-ZRTF~lA9@fTh zsK_%U({C8Ocwyo*ASjzc6Q@9zRSUPpW-?TdV)ty}$7;p2*GscnbQxBX5(6IVg)FEZ zrWMm@nq4lgqwoZgB3n~=opJjqNZW2U^=9>0y;hogTD`!QN-j}G2DLhZtp7lOEAx6) zyPm^1j#=76RB8>aK{7+1Fw3bDnTzWV6o<ACarym&gR@N46@Z>RForX6#mJbBM*|f# zcXBR3;h)}#qk=0;7b|<QIT=Ia1m3M}4d_vh=>+q23XuZ8|CStm=Mv40wBu-0O`kAq z7#lBHnnn0Jk$g(xs~sf9+=!r%^u&Yod22hXbwAP`l@Q)#(5ytT>@Z;e*p+lV({XKX zMb#B${SGRzplK}S4x-B!Lw6RNLfLZ8ujqeW6$Ng^*%VkgX_V=J2b&`oPrrI#aoJUm z=;&smWjSo3TyEr1bhL3UVP%@lTa0bKAIeauc~;+~b2|QERZo)nBdb{nCY?oSR*5>p zXqk*p-lwfBg<;fLTFdP|Fs<@h@R$jK3gfmu?i@zWU=3vh?DlkMN?vNL;4z^KjvE5% z;5UzoEvQTdmugW0)F{A+Xho5*=SbSrK6Zfy0Yd0a`Gx~HBkRV4p?W!$8ip9pt28f| z^U5t6)TNv);!vBa06r0s102XQt$+iki6+C)$=H=3>HG+`13l6x4G%=Xw|F(yYKiPF z#?r+Vl7!RxCW(%R+5pthaXn{UBFk#(X+UOK)L_UB$~YXjP-G+oKpTp*c6e}PNAnFK zm(9h2(AHuz2aXI&pZjCYc~^3ug17c5EN<1NB#)2`eUhh&I7rEI-iRzbrMX=LFVtZp zEB=aJis-G8fNj2{b}%Fb|79uol@;lt5T~#STP}74Ahy%c8S2d&aVK>)uSNd{{b{E) z=;7xYMFSD0xJ!!87aZm#$uram(sS}|$w$L@s1eA(KKs}O&0yq#yGUq}>r`T>Gla9( z<W)~xg-{iYG+r1n3j7Py{GJXQOd{)u-z#cK?vb^`?-jKKTggg-h+S8lr8h~?oJ{bj zvkDR7Cork@56@2iCpmEvEr((B<?-j(_b;OJ`(MXf@ym<B%f9Rc=go@|{Et;8uu!7L zh}B*WqVeu|e1YFyEU6ovk40_j%@^bI`>l(Y(Fp5(84ckbd=ozb5dOXxeAxpJP{(yI z{(k@D>!Z{Cfqt4v52<A@<%Dco!8o`NAPEvTuma;TZljzOvv&F~$v}pm0r!{3AuRwp z5Oi~d7w+@*_Ht!L8WW_Ojm7hMhLI{5mE!4>IVq;y@o|g^(^NYlC#Pe|Z>BBcLKB7; zk^{7tld9mOp0uV+sznKF%5G@*h-8_Oom9b;-vY?cB(*!IJBXi*f>(W8e*aYZuA=eM z4#|~Pr;1!bfT;9UqbO-!_}05U_J=s{|Cl<m(^^&^cXU;uE13gO+h3r4dO^-%IJj`9 zsjfsUQxd#-h!iKR$X?R1JF2B`!b;;yL^<N_h=_otgUJ-$N3<h7oaxLy*(MGSIF6@t z3t`v>fm5LyLp;!%t8kMz_|S-O5@ssUFz#|RArU@4r&bk2UcR-%ap=MgV}VF04h-iQ zq@zHIpqQgF_*-61t9vj@q1d~ly*KaP93Ox4=Ijk31n^|;cRqhihavI2{SY6N440d4 zn#GJG9_cJVhaK-W<!o}b6y8aec}EeIDU!}4NyLtiP7nUhwJU|D4@;z@z?9I!5Xw4i zf}2X{e_cykB2*Mlc0SAjG!~7*e}n^gwE{;1rQ=Bt&eQ`$<)=l{TEndmMCpf}HbQOU ztTMO@a|!AlMPJcYDF@7guvXh~{QSosnL~d3(Fxn^JBy&?REL+WqHjBvEpIx8I<Z6Z z(5z?4?96l|?p<0pQTQi{eg!KS_fA9K3Wb?#kb45!)#QBcVAY8sU)72l!VQLXPYe)* z<k<}=bRkPA*M7*}15hbs^e>dXPfMIIqO!CkDcK(79i&(yF$!SS>+!3m4_O?o?YgyS zXaiRFc}c6t@p=h0gsYh1QMfPf(;Cx$MBz7zZ$vcS<w8ZVNf+NPyEgUHz9z|?KnL6r zOK&rDAQ*>)ozAEO?F5wFCZL*`N5p)1e<%q82nd#QI*R0gp;Ja4?}lo+Q~i6$r8uPL z5Q&$ZLS`x<z9<>&P{<00lD>Fb*$rjIiJZLcP106kbx|7)=Bl#C(c%FHfs1fvR=|K# znjB>TfGfa)vtFdU#AtFTEv_qIfSVZ>!C+63m~b;T1U+U8{P9OnPJaARilk|c!T7*L zA~S=MFX7hKRw%^_z<C38s|iQhPiSZS#~(RD9D#Z3>(${wOjw6poHNVG=mK?L$dC?A z8{5W&VdUM{?))XD(mPdoCZMmwfV#qE>5#deg@O}MsP}UFDR>D*Uj`Cqc_5p&p(tEF z(hg#i-xKpMiPXf~p47w*r>4+bX^aHUFgNH16kzqpNN$N@PAKe{viY9lq4f-_;a4P} zxt8V$650?yN52StiEE)%edS~U26D;R0N<9Zj*00<adkUccBmuGwK^qPwGVB}3c46o z&56sLBKb%Q^=II^|4TI|Ysp8(7`q5cN@?1mxMD0>VDyMQt)?$W{9>ni{hEQRM@#Z8 zh+P?RTED@o+t3rzsI1*?4iO{&Gm3&7Bn}_bhUF6@m$m8|S89%y{`>$&lctviKiz(b za0TbiX;rI($0tYsy}x&s9KLzKpS(HzCK2h?O!q_>jnl24ceeg3xp*0k<E;z)nOvxc zF9t6LTkfWw|I-1B>FO-@9vlodj{oQE?a`qhgF4)rKSt-%^Z3j2>6hI-QpBH$JRlUw zFO;kST`%OU_1OvgoUuV3E9Nt_P>r+c8fp1bbpR=d$|_LD`-LY>SR4)@_=;MRqI{QA z-S%B@S)FZUd)>s4j|QE<q|=~M9HJ}5B%pMtsG4#jYJL>ivhY1bnvBtKkYC5UGmg%P zgpHS98FVIX6yq>dlff4O$7OVd29zUFH8bOJmdT#uteK?q%&Ad_=a=CyF#F>62R|kC zhf?hM=S|n0@}dJdE;)Il7&_U%&TcSubfS09<Pp7D2U+{7D;R;H`u^!aN5-1Dppa9R zNLXYid@_!PKx)mf>Wgd`Q&K>S{5A`oo!!F^So!y=I(xQ3c*}f>u1iumB**9Xfw~%R z`7DQViiB$s@cv@_!+A5nii1Ce1APglV~)TsG7)4nx8~=Y0D~#=_A!`cFeRs~E`hp* zCv6n7S@Tp}jKK5qTYQ$q*D<^}W|O+vLJtc&|3#@?Jasq==DX0MN-mI63XveZs;VG* z74HnV*SkCfyQIiDIM8WI%J*z)N|e>yq_kj=d9QoZ?+pqMiegJ7-^S**Wz+Khqx0~2 za~@L69fS7!6{YGVeTvehBa`k7@fE-hFLYlnW(CCiDi&EoTb=10*kP3Q$XW`!!(FPh zc-s92!8jJ%iwce?)cw{9p~mwf<g6$HhOW1XM{;91eBo}N{W|JeQfqVF0}&@a+1Oj& zJC!J$u-0>fU<KpOi!D1OY*C^WOQfis%fnEqlJA99r;zQ9YEtIW0@U+Kk=FLz2NI+c zccI!+S!Vj8K_o?8P+kvk{ZGWc_K9zu@}@w<t3da0X+|d;$c&V7o#44?y66!_30?t8 z`(A>fQL8KxEEg^6!e(O;C1_aToAUP6U`AI7OIHNOkSy?y-x4HLov}e^Cd}N_MYBlS zPnQG)o3B3okN^6QIQTYy;2|M1x6*<aHielB=H#MjL9EFpf*ZcVHP*QuEhm8{^-I0G zp-eHH-ME=^aB25;f}IvcFk=CpHGv^7+pROuLe0Gcx^}WP7(T^g*KD3|W3D8d|IG-m z4_yjX#04nDb~EO6k`q!mNG9zvrsJ$p!LmeB*nkyjBJ$vHNs$&R7U|byJ+nra<Vog% zYOLc92J>{;qPPtsnU9j_xMpbm5hThwf&VS=SGVj*mgO`)NUrCNAQFu8Fvz?%jLGTb zKTn`Ix)<@{;AVGw`~LnOh%nun!c<2EV0->J&$opR)_^IjTUn%+(WKGx3kZPEn{D_{ z6pD!rWC9*c>b98Ad41{BBCaT|GLCw1rTz`f>De=h`>Z%Zo{pqu9r8+F_x6HIZ#{2T zbfkmwJ9|XP_Vq``VeFxM!;HY_bR{m5&p`P=&%clrSi{Pa%l^@fd8#0XQkTL&Bqd;0 zMa8MPA+ZcfNS#uOG0=Q)4}@C7?4}gt%i5RLMnzdqmAuP2P;Vj+^^qob`N;d}B6J7y z7GjHt%Kc5272<iPO0hoU#+*>vS$}lj0hG%@^5bn-WgyLK?X0m-{tyH!b>^lGV#48I zf|eqb=~8Sb=_hXVcK?unn*prv<HnD59+-XIOqiu1DfrQy%4P~*fU3^v&>MAB=ilhu z%K&$Jcf3;G;|OQnRQe<4b$$l~4DGbR6mdbL;2x0ClW)=ks;b4au+Ivex!TzqJL9k! z{z-1#hOS#<_La$weU4o*RfJ2|2T)6*VfmEBNd|@MqyX!DX=o}ISk)eoQij@_JGitt zTZ+9P8BnN*YbO&d?HE8+66|AZyV!gD(v2O5YP3gW9x}f2g^uD!3ktQ`!;f*EnYp_c zk{N|>L+j5l=pm`RR7D3OMp!G=Map5;nD_Yu(62{KQv!pA#B?xUT*A2AY&VNbOk{H@ zrLTJ}w;}NCIJ!jDuf@?8RS#8Vo&?z)Z3lNnhr+AxIi9b+znRiK<Ejp4+%6fID@5tB zW*S#lT4Aef2b3#ljflPJDQfW%n%5ZJf_oLXl?}6DnfrknLkS~j3+9T`H1~Tq_}dL9 zC&GD7kC0nomeSYO!6_~K8YX#8C$hT=6o4xO0W1<2X$+u>3<TE)QWwG8DR~SK%2+4- z;K`WEP+nKmoTG6E>SCGh+<c@+N(I2S<^-*ro;M%m%;*|g=Y)x>S7cYMQCIP-5CT1H z+rz0RoPPcPidm(!_*V_FlPn=TtTZgp1gKFvB`^b{WihZ)wt7j9dZz|Wr+qKI`Q9^( zE#Y)UirIB(WDY_92ypkwaOTZ66UNe&ma<ej#3l1pa8EQaR0Ng`CWF1e195mnP8^N% z_xhNt0-G_y-F*?-4RD-&QaoohH`mS(=r}H8N<|WZuPep?PcDk_80_J|hYM8yNd?EP zGMU?qz=iIOKQ2yIGfWU}=r((#&AQ*$N>4lHkP6ez(qps<Cr@74JZp0+e!Pl`N~)(S zM?FmNM76=S-8(CPx<L1=7*rZj_LF$-PmuUI=Vzt+i{-ABPSEtN2%aJ5fH?8`9D1gX zzdmn<9j(!O;2$wT7bXi=He)OpEpt<1V>38q{YGq-;$35#LP0te`=_h2n>jiTtjkmD z;I5qWlZp3531&(oebMwB?|PZa8#%!eBAD9*z)+c}syxqt*#T^12n_il%Px69w|3d} zLCQ?8v&K0WPBz;#Q!LGJtp!?ZP>Ar-NNa$L2SRs`Z_OF7IK9ObB(caip;YuN(0p8t z&nAlQJCGX_GEwkJkhz>S!#3qAj%S1NtZ|x^$%MNjX`)jit8o93^*g_zFwF{`y~ei} z>$J(;{o`#C9Bk90t|LCE_DuAotMZ6EI%GZ>(Ocgv(Ne!gSZ2smV89s=YTbjccSx%x zTJLHRB0VbFlTme~vYgxcP+$#nG~`6riHBvim}M5x-(`;+=eE-E;i^^7dHW)z*0QES z`;{(kZErw~(M4)RisgM#6R5U#UYOKM7t=xg%dltFP_P1_WF9yMlXEW99l}>P8Y;ra zos{C?LNQ=G=JBcAI||KWB+6{v6G}*}lTtGEoK%&_+GYII_)y-K)qN>-W3IGR)o80} zWj<*#PqIoZrW^w%R6d7|1uQX+G#GJBKCow7S{;>q2gx_d7~?|dbxjN0RCuJ)?&7^k zURm6dl6o0l!_!oBBNc{Ei^HzsdPh%vvbDuYRtoH9Ru}|v98)AKj)~CtJ=KXSge_h{ zBytN&$0_EG=glnp{4Q6<ST9$FlqC9O#L)fH)!ecqc3xIa+OST!9_uv|8AJVmR{_P3 zN7m8G$+U_**Y*<6P{a{SZ{Nu?9w!yXMg_idPCPbkU6t1f(7%+IFj%_QCT<7qZf`?3 z@AKPyo=x*KuIlS;{Iz|S)<31?^Vff-a5w-}JW61A6;CyrgUSk4L82mDyIEXLvxkIE zA<<Tyem!Q>Vy<Xo+7;D3x)3eBj)0ht^jWMPUf1dT##|}7mmMJl>XD`55gl;GixVVs zO80;*GryDjdYY;Gux99;0@Duzl4<i6ikg!fpNz2%`ezJE*tdkrey>;Bei^(R1+Ofz z1EiG<sp+a+KlgwOa@;;uONKf1{HgX-Sv*RN)MkXAXfPRI#;)$wtzzU9k%he)S65az zQ6wq-asq4=RpBP(4T;ALlU0M<yUW3z&ip4rP1aGZ`lXCBoU^=)%!fnuQ^E3_xhL<p zNe&#@zP_;=MwRZ8rqfKLtVR?UE_XAuZ0s&DIn@I-)dMxvgXnZ`@AvneXNKN!i#rdl zf*-LcN1^j|n`}G4B5HN%Ix8u*79CE2mA$^&_>A;<=@QZ-*DNU`KdbJ%?*?Kd<|8Tq zexi9=?fk4uS<T=N=p1%yx94_sy+;(S7J1rrn?Y8nYMH`cyR%9Em}{U0&G6?)vzKIt z6GB99S59M(5O>lW>u0jv^>A7_nPIy1B%J2Fj{G(FCA7U!lZmAc{~m+pinkl4B7olp z;!-mVFj>IX7x4Elq|$4q*T75PUblh=Fo87feXG=Op`&_)=VhoLtr@Tb=tGHd$2lc% zGUBfYyPxwpWmJbh*FVFbOZantQ($b?o0Gk_2jA}}`+q;%Kg3YUQ%n&M#!x!G{+aH+ z!LOG;zn0(WUx3)>!@^Rs<|Y3NZOKs7g+Mfm#J@=wKaMw$;?C_*+$JY7{uxQF6)(}# z?%s{1!To%g+IJHqF;AD#t~VY@KX+sAjdKPUg}Xm<>|77rl7(rzc0LAyP|_vXeBx%6 znML?wzFbfv^jlk{-8I*4AjVcas4E1hAhr*MFlyX<A%@60Ps4-bhG(O}WQ}Qe>L(IB zBe}u7TMuE5f)Gn}CVH_7sLrSGZ$DgoYrGQ4M#Fknf3seTYC2plZSu0WNd&NNn>_3K zTY;DUR`eE{?DzOLghek~qwqK4F&kUv7ejaLIAtV;)$BpXT>qQT@xlU+M1Vdxc6(2T zcfPD<B*D^=UGgEi>#DrkP6qJzsH~cVF^?3uwrbZG7!5jLNs*v#hujRg>-Pw(R(kX= z=utOTpNO#{4bOMg-RJsEclg2V%9$Bm`|8iHKKryg;*Z7}2`#+SD+Q^Hmjt1l9a?|{ z@#NL6bjl#jiw6B6qJh`(1AAs>*$j85IAO0In8lz}Q<(ee&FS930Va<_sJO+sg^rmb zOZk#M+*F-mByHYWP%vLDDF6#bSX^O52LRZk!k_^NuN-bVXy_A?jsmp1fn@BxH;1~* zmjEFW6!k4*@}rk#hEzX$mp6%-AUqh@+DbsBoW$*&$ns7FmByWyePAh0VJxG&x;Pzp zWrTfEdQb}LP6N!s+Z-H;oIcKJuDpsx2{9+8+DfKcqBpb!B?XN<mHh1f8KqbMS<A0Z zv72-sJ%;Cr^yDI_>pm@Roi6AV<s9ru|9!P63OnqJ+cKx4{L~p1#}Z@g*{+*TPTU@E zow+Xh0RAkq#v>-IaCxJ5wLL{p;;-Rx6I`Y>DvTcv56)Oe#1-&6{PQ0F{52egXYl`V z*u~Eti@N6C<3cPdAZb1ves_5Ex5KbE(sV`{d`CN&EdBw%z1rDvcRl!>)JRaN5>LJu z2?(9<3l(&DCXEF!#e<$gDZ0KGkokr*xy(3btlnisI&bLRj`?DWn8^dAs=Eu!{vbDY z0GB(%&8}y(M4Ue#i8B5Y>4Q!JE{S#ITN5Gfxdjgf24zMLvI74^#u8z4-kX!hA`d`Y zvS?cL!lt(j2->DeIjJeiTHO*dsa-nZQyg-O@*0h)(=WNYb~yo^uk`JL>s4U@9BT|; z=y0mJC-0{|IPzSuhZ06xsg{9TXP@p)A=kQwO8IOt>&dXkZHTF7VMQ#11JtofPaE(H zZ^%lookV`>Y6H(Tk3w9BFnNRLmfmaQ(N{P4@=LR>%}#ev3L1!af)_zI*jsA$41(=I zQCEN7)8O+@r@`~*sO;V?^Ku|nSa(XMcu5w<p)ixmpC*wa`50&B4ky?4P2X;gjufhW zwE6POUHY#h&nD5fYf3-<yJ=S5+S;Z6meICLAcB&iY3nPJ4&n2+yU*Y6K0k#8fZklw zg;lDH1JBOMGXK#2*_-v*N+qofzkzqA38Yf}3h`p9b(~x@m`^YNf`90O3DkRZap%&Y zYY)&2%=T9Du|#Ui+%D*5fRcm26m;2%Z~Q$PUu&#1e$3bIv<~#DsM2=zeBt8T+G^UB z^umo=DDi3llhivv(#<7KSqZ0`mQT}~YVDwZ_idhK&b5g?diU@;h>~@tM4znjc8~JZ zlsS1?Nt1Gqb28k|QI_qv<LEk=MTKpWemc&Ilpx2NueX_)QuRe7gzxaLMRn;O+B`Yf zdz<|A-O<<f5%u$5qVW&EUA!2aqkA%;+Y*wK{k;z-r|3xZRT=-VeSSXt<>LIs`HNri z4?p<rq66^$;Pm~QGidU3|IDub!}y0^E?%7f_UrjC)bgKHDvJCXa3}X(g5Nr$LY+#* z$CtWSR3@RG)BWhdix(t;f2ro}t0DY(jekD<E!I+odAlexJ=ksIhc9je2;%w)LLzux z??ShLPa5<T(4%KBUOWqCm>W$V(Mk&t9Y%nr@76ZH--VmCu+-`J`*57)4IP!I`1%Z$ z>-rW9?eG`6gem+jd^&paxSc&*VicX{;#6=xxk=PRz*e!Oc4H2`(-Y;O?Pu1+j2N#R zWzkm-gu$mnt6f#E6GN?**0QHCC825gw&Dga2UnRIJz<05egi><Q26(i+(S4jgO)G; zjjw&DJ3;WLDXZud|BEhhkwn$SL*d&_dq%`<G?!-=-G+6V)#)^!q=oRZ6G%xCz|F|B zByjGs4TquIc()eE&O)r(@>lIp39ZB$Jqsru78K%wE^J)_QGAOFPVS(tJYKK#`MFhG zG6%ULJe~;WoSh<1YTS0E4)6J|;pon-iD5Uq35<Zi)yIAKVP?20H#Ts6ZA7dPolzw@ zj@t#Se?)K3&W=yt@)3IUy?mWEnf?qdeULuMP1TUQb4e2JJ($OwV3mar$`f4B2;80u zx)B##-eonWh-`vMSFPEm#^B+!nxVT8S3U&I{tF9GguyyRei>WOHKI(?WRh`)c~azM zTuZJZ_GJn?iUXjc<noN-d8XZ!$evn8N|=2Bt19^-^eK6bWm9^(DNV^QVf6T>SMr`7 z3-#y??OCgG;u3oft}s<4{4^Cs3gJH>#W+Es7S9y1@`Ga~GpEBK55#x01*%2s%x#$q zpUtE&X%_&mpb-aIU<Yk0RLC>X;o~nLfJIhhgK(<KyQP3dq2bfhca(17q4nJ*wHbU1 z6XSLK;JlGKq#S`BXFI$~>g*%!OE*Qlw|{a5O2q&BaB#B!jZ>rl1|Kh+!=uCf<rIRF z_jNi?c<3VhM-0nt##c9rp9G(N_s_ItXpPjjrvU&AWhSB#VtagYbau3N^e%y6xqJQT z6R{CPF){|m6Joe>6O5oSR|qn8Y!Z3!bmb}EZKm<r(J_n{7xyum)?!>y<W_^3bFeL~ zW<M9o@mmfV6JronlF3afj~jPmZ?cBlslJQc3`~~K2Z0F5;YWGb<La5=bV2}-iAkGi zk|NH_hF-%|2_G7ow{K39)5C)$V#g%FI0WSp5Kzk#T_~r7;L<56JK;`C{{bkQtevY! zUmZLy0bc|me$0h6Qn=xU6xhl&wh~F<jm7!`&GeH`Z>y%2YwJ{GMp*(t1S#4}_j>cv zplFPz&ZpIV8Hv^D^z8>=qi_Cp;zzryXx}ibf5@P5bO527M7FY`-#O`SUdVwP8q2wT z{u@6w+}J#uWiH7EPmEM6o<gP)q5m|)b7@6SFeQatl>3io;zzdt@k1F(Fi8oY8}CvX zr$MJHbjd(KRjDzE_c3^^7NO~!qr;6xH68}sVXYF}RUdL<=av%2WA65J(k=)Zb<l}% zPZ<JdOs7QToCb-S5!X1x!J7v78dJD5sPA89Hz^qDR2qZ-4S;|fXzUBz0~9g#Sa?Ww zf=X6$^d0Sg1DY5sE-x;VmtYz2pxz5~0=!V2XMFFouqYHI%iu%Vq*s}(+)`l^9;v&8 zJ1C!xsY?PKNz$oMRH81WiKip2L+5Ii$xT&Z$`pc%I<0mDRSZeIlslBC%vPtD9{*gu zsEA-WZ7LWQddr)$!kH-+?vC3UKR9V9krQ=a%$eFqF^eCsB-Zz11pUN0w{8|PFjISB z!TI6j9SKY;jg>~VP_u7XFh5chMK<M2F<|Y>F#T3j^`-M*r;aV6^-SdgEU$&SK^3f< zk(NFo=hLFhbJ@qf6{A-()@1c2{|(OQkSU)Pzea<u4Q7}f<eHcd1|+=#L^&FO*fEH* zhZHxu8_Y)eJ}tKn%B{1TY)b%qpHHW}3;ysZLOuu*h8ATdMW&El`|tn$DJAHqq(^vm zVFm?YDA8ggGBpC=+q3uYWONGWj1osc9v*)VF!Gj<0)gP@go(@<21N!#0S81Uh%ZXi z%*muGOihXqMSeOZMrh)qu;jC9l)+S|Mr=^<01pn;w+$VmFK=L=Dboho@>oln?pr9! zE*E(*B^J(57Lqi^6ea?e!~}<#TFhJGbge;ckv#%h$%WSR2x#qED=t!I`5a_smea<_ zf=4Kc#CHMt2~wTvDGc0XQLo_Xuv@BjJ6;y9^}oM=w{>#7Cvr%!IZQqVRAMQlDj2y@ zR=ck+$dRHI8U@koVelWKZynJLm&9^y1ZUR>gEo*~MQCl$`i}lLWNO+Rp^@APW?2gC zj@(ACcK8-;{mvJB?z*A~j(fIV92EjtIM<{f(=nm`MeJ2T02-p`;}Iw-Ka<5rrklp< z+8-m#Kbbho2=qsZ!~{930Wo|VJ<N)FK0&gmXZ@E73RcCd9w>ERh7U%1<c;p&5&OdM zO}+NC7F%uTptWEOT>o?rQ#VFh>o>z7ga02s+xaiKgyXSREJYJ0GMAENb4h*-EhV~9 zG#L3^S>9Bv>fEf>0bCRi8#<M3y&La%4#IFDio{F0?4g<KcXnDD1<VaP|Lfk%o=67= zt5^DMQilGc&pMG`0#s5TlNryK3#Qe~wg$tQOlP#d2ID=6`7{PpUXhh7sBwr$@Upgx zMS31YmphMxj|S_ox-t4fWD?_8vTu#uk$)D`s}Wv@@w>t+nBVZ-i|#$it=RkV(+EFn zO)D<wyZZH%RO(|?H}%=nJ?$6Ti#qo%T>hB@-?${5j#JFVRO-65$v5cWy<0rvvxc`J zCe=)Y>CTJvkz=xLhTKG_fV!JY7snEb{*X8@$uQa(Z}g;{LX3Ehpo=EO^|{>jh%zbb zub^9=1OU_o?GuuM?b$4BCk67LAx_qq6{4EIiki;yElp?|8K@TdrJ*Ua3_{W9N>~WR zvj}Va<48k;YgldFJN@1a2#J-8N8P!nGHX*zK3_05Y3@W0Su{<;c0-x~GT=WB-d6YM z5Fu}g%!xbA(t=fFQH-u`!PK-T`+G+x-|)_7tWt?XGpzGpm3*SYVS60iRc9B-0sRsN zU)=O&4y7EWGQ;DL?B)%%_&RwW;nVJVIxxsfz+PEPbiW&P`P&L}oQjxx4FVr^kX3*V z<ewEOdatn3G@weVkb|9k!RTo%$h)|DsMKXRKK&kjk4|zZ)LCgMQcZ@_tjK4W`z_oh zCjtgD3}s&^NneY%y4Nz<aF=SA#u?A3-E}H%NLQ@jkqim$nFbCXC<hhr)SKf2SjgfB zVPc|P-2uYk;Ss>BcoN!q84iL?$xu9He$&IuGd#oZCcp9q_Co0gZOXimm$KPHw!u8; zGwtYuBJv66M;GMom*F1qjV>JqO#U06_Q0=|{2R;iPIgJ(r1)ZFpXlK+z)@?|y_K{d z#$a7VR5stA51xy7B$ujd!R`qcSH(LaAp49P>*0lUW{fIz`RbcH@gvfpA=TL%C-~mD zt~+0!O-kA#v<nJ#K)sCh?DR{<#W`ptF1C_kI^Eq?&JBwiWa}sq#}chNLc{>aIVHrv z{J4GRhP*d%V^8TOZv3Lnfxp$1IdbJ3KzY@t#(2gbi--62nA0&AIp+Lh-7)9V)xC5n zRrgl>=sJT{2i^=Da_|7CcetKBR0L3r60HV3mnjfV@?bfZwv0hK_fh+37%O@pC0IeA zG~QSF^+IGKwSz~+m}_Nd>r8(j&vH{*#e~n*wXE{fwK;bA*e*EmRv(9XIpO6HzQ`B- z2aG1v1gAvT?<^xCEbztw9SPpr9CSJqSNG>qr++vfH%P?E{WQ{;Y$Bin?sUC~fsSP_ zi%vw9>!#EAr5XlNLANGTiV0t+Ru{&P%5*h|#u9YScT49KUUp$yeojL;LVkG@MgzVM zcbQ~S+b%W{swcVsty^R44`mZvf=dTue0#zB^Gs&=xsL7Y^hFHPGAmC$o^X56dp5tK zf#<Rpu{jw{EK*Noo0veqxWfYKJx0Md7Vy|()$Pf>(tyK%bGls<%rq?>k#I-opvD)W znKX-zf!g|rsK}{K#vNs-J#iHFy3vSCxgAkrMz=#X4%{vd#-JNZeu&Ky-U;Cy-D(%0 zD>n*>5rXVVLO1E(edHVV=AHzfrN~W5uVq3?p9haaOk}Km+4bpe`H>hFP#`T3wvth| z*`rUR(5BEBid^U&(59=zg61q=UM=RR?;0u_D8=G0owF;_)5>mX(pYqh6Y6%&KYR8} zUOKGgxk_>k)pxhIk@9Udsft+NWOlCNNH3enhK?VZ>9_CR1uMlbnWRFeB~^polZH7| zHrYrnx40vFWhnvf)kIglgpv-R#ih7bb;-2`^ooxvFUnG6!WY#t4iuWC^L8PV2jw*; z44DhpOz%YpbgRxK7%!YTcc>2kIx8d6Oq7N0iErj>b#Qp3z~~80l@>k>q)H|Nq<S-; zr+6(6+S&5zLDlC_bWfThNPsLSLt2I^q#YI#q7<+}lwWmjDoV;iI!|}@8Pz;IcSPq$ zD$)R(7CO+AC|&EiK?+r%Bb`pkj`4ajTs6v0A|nEc5qVwA9`CYyaERrc=wP28PVWw0 zk}Jn(jrCEc<>k)x_<TD`^1*aite&C+IQ1LbR&k+eb*_p<bEA>aHsJ9YvFoD5L|wDA zl=*@uv#Hlg!9+nFU&hBIH>fZ)N!v-<%Y)<n75-?()2ZZHwc1y>;@%)%;C-BD^bJ!- zz-ltm>`u-uK8i3Q(UcsGA%D?H)xMIK&UTMp{|@+oJHv-B2K?6!{CRwz=0=0BSUwxI ztS2%^Xf+=j#i9_8lcHJ_V#JTeaovGTFWb88N`THw*Cw8e!%Zc{y5&Ff{j2)@Z6GlY z<x3P#>`)X}pozOqgCY%%_m6|mc0QE?W;4*QkmFjEGIW~VZO^lLgMYSmpvLy5YJ9py zX<;@r1nVpYwgQ!ID~T^&^1a3)Z-l&*bmRX6P)h>@6aWAK2mqM{yHNIMC@fAH003WG z000sI003lZb98KJVlQ@Oa&u{KZZ2?n-8^e|+qRP5^(zp&IV59=kz}W7v~kkhtlOJC zt?LuJ-McI6>QW>mv!O_qq+}~~^V@f30FVGl$#x&NJ?o}6iN|0t7|aU;?z7&L9`lnR zj29!eD(1Z}u%xr!*=KK)bd!aPtAg2Y9X9L_hCTT8oLyXTcD5<5l9-(*^WxgeIQuGD z#er9ZN$f(;bI#c}@7|uAo}akIO~Jf4U~j)Wy?FobZ{J^h_x>CUp<QQhZ?E%inMQoc z<AQp#WX?P`kN8bEi#S{JEQeA+j^+LpG-GL&tiyl`R%x1K1)C=sJ3Be+9Ub+%otzh| zv`CUD@A=6x1(*m1$ItoFi;K|LV7i1rCtMPoC|N9^P`zfn)0t<<lDPs9ljV7lL91!8 zNqH_CtcoyF)v1@|e46o}R$)fd>U5@4FN&s9cFe}sX_76yDE!ES9|Rg!muZFHdId}~ zv$`Et{aD}dh39Xy4x*sF@wuF*)?5{}clbV*lq_*N$+9HFjtgE)1>LPlr-KCI8B9Y` z%7yB0sLY;DV{gf)Q>WAE_>q_AYztKT2QON2dUQsF1}wqFRhTpQ=f!MQbyExF;v!+o z6yTQdB~Uw={mA`7!V37DO{ZZT7SpMn^Jv~>xvat;EODn|0bv?B{_o;zYCE+?u#5%P ztG`rAYis9KTR?=vnumE9=Y<#h+@|(j222?7M!Sf|qJhI+v3{pSS;B4Ln|Wc**=bUg zdxQsqiWa<kP#3BS7RIn|^3{x}V>uP@DXgFWVOs45IZ#pnD`<m-bA~)kwGMl9EZ*v^ zDzq-3S|a0nahw#4h5%XcIHL{sIJ4MeW{jqzHRV5*i&P&)tU&{D(X1j5?DZ@*7wlNT zlJEL(G2c3z1cY-Czyxk`I1NTr{QfAv+=}sH`)C@*wnUk56YUsC#O6fIncPW@`+_wv zzAx0p{h$g>a#a-R=;_lS@pCsNz2hd?;%Ua`JmawGo`T}>mPx>)eIX41)RmWCO{W@a zqCjwW11qewwM8)|mGLy&+H>!5Zd;FG!|f?vhrwwNPN%Mtid{qU7{H-uD{Q@!=<_9L zzZ4|Nri2jY(=-DzkT__-*)BiMTI7e49z1ugN{~yXVG3F)n#D{(Jf0>oS4*}=36J8O zhq#m=mVD5E9_nFOYA9kz6`|;t9F{Ynj#HeOS0ow2`?;Kh_0k%#$Xm_=kFC4R@3M5n z*05{*N{d;qTHCxb+Ppk&Z3Gg-N4y#!?`m#BKi=NlXmy`v`)szs#r0NE(Pf$$bNq_E zI(92?pB{$eqxR;H%E5n8OIRp{EEk9+akODYQrcWzRPZbYwALCAkpY)0E(krA0GniF zteL7#H;>xXo?!o$rpDIUs^&qH(bh4U6sCh*+NR1Xo21+rdCL88z5xnIC`>6<)%9M+ zL}r){^~q=mqa@Gn!VPvZ?yfKxN#&Z?(4mcW%rbf~t3L3J!UZecD7l7B?TE!f6WWJq z_rQ+faURmT3UwalYEALSkHWk_Lw2GgpMi-C1`r?|7r8l!{n9QDX8(b|T(Hom&=hPX z$7qQ-Bq^*UilQA5)e5^j4)SXdF}CGCv7BZj*)U0oxB%3~UD~C6u%&rB*)L&$ON*d@ zAOpGugsim{MB~Q-lSrEoE?ts3t^LvMT15eyf!9LTXXr&G58B*axMJ`jPMTd`h5pqR zIM-nOOMe6m(2A3R#0mSrdCI~<R7e%m24)S-LBY(!8|0qxs5hK+*+sVETL%5F74QcL z3NnO1j)32^j)f>8&Q(aXc5m)ldmT5)#G{<IuOHY8S46!nv%Utd1}DSMxL2T8xCMx^ z=84j%u&S+a4<a=ukvm=Xl?PZideeS#y)*@8wrynp3YN3YCn4v;rmmVmT%w+q(ohbs zak=uL@aHY94chxx%Ac;hEdht;a^5A+x}CEB2oUj>s>6ul0jf7FJpo|e!b37jRU!#m z>8=ra7Zr$eAx44RBO=-8U(&z(S4&@gF5z7FzN)p>ob=jWSD3c0lp<W&Lr5iIm~=II zlnWjj*1S2?Tn$p$Hs~|k>dj<rb1L(llTgqBnpYH=T=sbbAj+(Hv+FWPm1Uz?BH37( zhufu^g`{{)vdgY0vc=+cn!9$pF$&nUBVMg%lkhDBk#>W*(_|rutSvS)zw!KHD#vQt z;yIXM%EZ+$L}y-i8PMz+$VgLJI_^*4pRRn+1g!hhYKU6L!K6M5(en58?MwfQjE6_c zfyTE7y8XFu`}2RJ+fP=FLK$Cb^#9`m0{?#36sG5}gWu?@KF<DlPqlM)a&~mopZ;+2 z{`}o{r_=W*Xp?e^qlU1anf1^0Yx^=dc;wI@`_hHq&J)MBz1!KXf1CLZmOIYtJ8i7Y zg5GwTfGU(-@IBz`2SGTn$6oK_o8JFk1`|X_dvjg`kk7~;COV`%o#NzRHEbo7o3{TF zN*YvfrHU3!q>x+I-SusOQ?mYRR@6xDHVJZ(C94#XS-Rp;ViT{HmE8a`)LuKJ*w!eR zL`x7hZk|SA0oJr7r8gLt;B=y#LjV}F6!Hz<#=XG=H&?$xUyeexBdG4^)0Ct1Csli% zCSWH32r4m+I#q|rmR$u_ApTMDiNd4N=R!y#2UNw+M=vIlb=Ottpg$T6MR}C?U{+T( zhZBV?fd}1);=W5lUt@PMwxp_wv8aOIfM}QS#^=GLTx@~iR>%VXcF>{@|5U*7MT1Tg z-3DAxp%u2Mg5M=%eAWO9N;RBkMZk81rJ<^MiO6nPj2uUOHEyeWj9^286S@L|lK%h< z#k0^?dL~D+{uRR$B0pJVUJ5QymwD?X3~F$s)ed$g$n7Ny!1MNtXwzl0RRJUTAeLc6 z(XJ4VlpHp1z{#*DI1u2C)%>K8LK=k|=0UiC`LviNG;N^NK&~9T*36@Jheq}5cj?jW zLL^p>gITSXMr?PfBP6c46@f3S!S+>@ZpLAW&>i4C8BOe>WiSt8047Ul_j~h#XZ6qp zu_)F8_tclO3E7;9*i)7V)=_WZR6Ky>R-L_mB^nyUQV>2`U8fpWK_Gn5an~_WQK~q( z26`nQm{*X)1IBkjp-Fv0u0cJhXl`3;D#qS7u!cG5T@BjEJ!uhvp|i9q(hPaT0$Zy0 zsx+m#nn0JVBNZ>n$u7xUGK{-~Q5T_i1tWmon#Se%;#7ozbS+i}dK*WR_78>|32xUL z&`}uVt3ndeE&Mu3f@*F9cc`sD#=JmlVUQWtWDhFc{+`~}?dxyez^FU)hUWXMR`1u| z-J|mT;=BL+ZUih0Yfo-yvXZv*-#i^#jg|J<GK|CJYRQW01j#ysX&Ts7E!C!o_?ky- ziGhzRZ;c{F)#M<zU<FL{6)j8CYU}Bratmtfr$-L=>y@zRIXdrPOGGI7KJqN#6jDR> zuJ6BnjB2iMtApd|3wdkhEan^|0yR1O5BGmi#lRo8Up{DSx6l5bTmvn@D+JSr0edMQ znd~0K1_1*y#fbC)_+97<>Va?j6F5=sk^9W;J7pvy2<K!@7a|6&wSiVuSYWr!Rjx0t zQ@-+jK&9-u&2YjWVcSZ|O$EJvg)t>owBf~_y+3(>^3C+(&DZDT02cO`B%w9KUq1fI z=r`<WYvTO6V<0iC7jNuBdZRQceQb(!)q)x1HkO7j5ppV4)V}GmjU0huUPWf#h<R@0 z>!#E>H^?lT20CRBQA)=fFraZ%3h8c|=vQt%#%|Cm-58?qW*n163M6k4Y3dY9{@r?v zRTF`K(3ut;+*p#Nm8Waz$5mR3sIY2>U8-hb)V$Qen&4jPRSTo)Sg+zgS&j25Rp({1 z5CluMvFe9Pszs~-|Dt)0UhpIAxhZKQGd_7oTt`^rP-d!o^0TJO%CQbC72mIbk>*w! zN(NMVS~#U?Lx7nA-u)I349w12>jtNkamw7SHGMbN!3HRf5n-t-#5|A(z`h1D)H;^} zxC*f%gxCUt30`z}5J!Y()Yuv&?jjH#uvCz0^asFYSK;$3X?FmUYT$s3F*@vwxaJM< z*uoqdH>n-*AWmv&RfgLP_S^+dCytuZt7ENYJ*w9ljjX8=eRa&r%Ep|dhy}6c{+NWZ zJx1vo3Y`<uS((vo(x4|YfhoPqSpsOMLEFV&gtjmLAJVpr(Eb^;HTRcE-zFFQg)n`! z6I1@vpUbb(r*7z}(tfu~0jSTTg3;7QmFeHkTWwIb9TC)Y_k(Dq!n?35)X5l50^fBM z>Vw69Cht6GMIJqPMRx4?hp$TG;O0*jxyN^kT;u3p7uNTa)%#mkY5%UFevNRKhjeBw zg|X`x)?k|jBABfj|5lB$Q(J(;diKqmw<mqQ1CS=m*6;naZBE<fOm|P)wr$(CIc-nd zw%t8#+qP}rKJk6$?DySwpPLaCRrN%yU#^u|nNLOKs()=}rfX;Om@3$4aB$QNT=3c4 zr0)Algm$fXGceUicDK^x0gkC2BHDpy>OR<<$sdfi2#Uu}+L8m<r@Rg_^=V2Gd^pFv zAv9{j(7KPMoQah5!0w=&iJi<=FHjC=o+Y#AgA)RSfVMHqb<w8FfYevz%{w~BvZnlE z0$CFfu|*TPR=SN?bZo%xd2Op>;<G~5bwW+8Ip!JEk<bVSit3cU)*iz)tWfGkQ_qDQ zE*B)KI1lZG89E@f#hWpgMs5>CQhGtr&UqR5#pj!@1QCGMi=tA&?km~&VIGbU!L-o> z?G+XV>P*_N_NX+TJgbZbtn5GDRdhOD2f3U_c?R=jE>NAvdf*S*=}pvkFXFid@pQDM zov+-Xtk85k66Cja+|;n^W%2?j<5!JgAQ0=BZagRcQ0%}sqBZfpaxD+9)9O;RR~o|j zcQdoSf2_toUT#QFZe(?@%*l90I&7RUG3(Hx<IE+trYjifDe{@Tc*G9BDVRsIS)8yV zh;EREZBi+rY?h8S+auD-tCKnDH)0kJ0~J>5Q}!OA2#<tQx8mpL$rhLu=V>Pjip}o? z!rW2QVVVO6aB2K$omv`K`GLLaVpL-%OB}B5?w=j}NrRUD_1A|P>d#J#0$oUrLd0ND zwv}>~Tn-)Flw_!bgf;=gIRD-j$ILjOu3`2~&#Fg<V}-767xko+NM~Fqs6M8;+^(8R zU9o1_PA9sGMI(xlri|K1PJ#0J#83lEK(`Br1wJvGKco5{&Oz)Fl1!n(#7caZ)VOqI z!c^s{<g9MJ8WAK4K_nik(9aUgT9)4#3s+h_X(uX&X|+I5h7+>{9+N6p{#^E&o2`o= zvYqo0ov4`<D7j&LeU9k1X=-XsHFt@z7U=|1#Usvm<4;g^P>dlL44*86_F76dVGSiX zQBzOA{+|zs+Kwo(l)N(#yL^_Z%CWlNKlH+<3LR&Ij@&3&%beBCJ%CXF*WuJPkc;j1 z9Y&rqvX|@WR&j~pn!ly`zR88g4xhwK!E0SK3eF>?z#7z2y!rYM_w*R}cja>wr2rzY zop>#J7;(z*Nmf#-qf|$UeOF3I#8~YPeu`*m<0{T53555!-?$>o>q>u%AvNn00*@!q zPtsxm+0_PpyskZ=Ib3dSZ>AENOzj%kb3<c*dO?--X=L*_tgV7d8T6n39z+LP+{}NI zyuFSVduw@%t{wdT5kbd+<$aB_ZGaV^I*o^o2Om7<?R?b9>PZtlqV7LaJR!RiFpWr` zU?Rv4Z*ou(4(jgT7$cd#P&f!5or%x*8sWFfL)D|R3tVAev&1`48qa>4J)skRx0U`5 z%k&!55vG>Hj4pbO=7i{(QFm}{FXpUj6T5;uL0y1*<!>^|ApBylpoWp^yi>mmP!eJl zC2&Jh?dU1&<NsRP%PQ(`tf%2RCQUvLN*#hw81S2`Pnh6~fXvUML^Pr4K)?~qYd7FK z9#Cs8-pjPo_(L)%z*`%W<NM2qoh08SuT!sV6o0k!9{Di56O{56ap-6jJ{JO5>V9Qf zoV^DbC!skq4v!VWanETm)HR;~R$aW7A}baA&AZv6!jUo}B5}WxsqQ@dWq%|mSR$r3 z_V#)qY>6+W$4?!)j;>Pg2N=-Vsdqn+?q?kON&tG+Igq61(Qd#VPaT>sO2rmmLn)#! zkm#9mXw2GL+I_G`Xn*G6pMWuaAe@5c7{CZa0P0N2JrBr@4d#uYN^_vr0E~`vDC+@G zF$1tKZ2KGZAXHo~n2X2R_#4!LRTRBPGO9eQZJ#9_M6!Sb3xR?=!=SeFlc#Sin5)Y+ z?uKDNCkG;2W*1^?2+#tL&-C|d9Qa$V{@v5F2A1YkoOjwQJx+ZA%sB^ywmSxFN4*3L z>(6*evJ$u*@89j{3XXK^i}vajx{F?cEqFuqknPxsr-v&GE9N&Ft_;61ZN)|API{?) zQ4_)_W<)W}Xv;9mHC4@~cHJ<q@UkWu#o$!F*+4lh<55HlG<}YpcP+(F$wA0PDRApg zX8m}bMGWMq_8mF;e(1$^ijT;6z8FmhV)ELa`snyDhtWnPJ<`kP?BA65;ETC|M@PbS z|ETG#?VS(wrNd^lbf!=nzUqH+b@Z(+t8J2dGl*87YC-h-#?Jnhk`*x_xkjIQQBe^( zb$d|r??8=j+AF48osA{Ev~Qh`KMVmGJ=OICdfc&~At#iHP!@tNu?z~dTXM~?tA|r4 zP*W2V@4JjS_q-Ch<%p|1-6Z*3t?Qt{@v@IV2iRo4ViLZo+^_FyKbStQ$@^HzzjF+D zF7bBr>eCb@*t@{;|52Beq6oJaB~0*dlq;UCFqLsw{sGY)A+Bs3D<fGxMT|Fe?WvQ0 zQ!++NlbC@S8cb}nWgO7C*4RB#3;PQDqTY*fv8`uw<;jYp3|Avr-*@A_E7`EI(mWiq zY<1bVs4H|fPjzlOk&+3J5Ax^U>nxvo#G0RCGZldNomSk-Jy5%yBaBGdpCfB?K=&ut zvMF!*%)nXYhb#yl{OL$AFdxMa>=XL{FD%Z}fCP>e%Kbk0E-*<Ophyo(TQNlpD?($7 z4^%hYKf=J9V9j%kLl;emUZJuhu!4+5IXqJucW+bzHOl}BFvJDIE_BD(x!YCB8#7j2 z=goJ|rZos?z?cTqW1|Tq2|noQm6Dag^Ym;40>zPiWAesXNkqJ!v2|HNvX|^mr!g@z z>#{5p$GDr3%=)7I<PA#^)~`n|_7G(JMM^G2hD6WI_(cN<!WZH?rJjZ=7`CY@g+iRn z4mY1^Nbeo5xZxgJ$!qjIf>1sfDapr-*=cz+%1XI|Fug$BA7!4Yaz?}R3?uGO!tzx` z;oYT+8e7UCkM#2#?J@YI8*4ZB7--U=rVj)6=rn`$Kytrh)_>=!Pu>-UMoJ@ptD^46 zRnO!ES2@YgE{iiuo~IKxP*y#Sv}H(QC?dp-21oI%)>b`l3bd=9dk=N%dB8wu(Uv64 zCP(McHOteE$sHSVVLwM(K-msH<0Pz%Zy+&yr6Lf5C9bo>#nY%xmW10#&wvaav6JH( zxyo(dC+2u)L{yY!l$u$|_-N~X*q4D>Q%<Q6OaeuPYN3Ly_|6+CV=|At;zF(yF{^IC z@iua%(UM}^h+KJmvD#a0+UQL9ROn2Ya^$9<<3eLKbtA0ty5LcV+`HiMUiZrbztOIY zZ~t|F35%MD!aRQ%JV%EDai!m^Xu<xMSUt*G%s7)ekWyx#<d2PJ?<LkqdFtoYo9}p; z2szNn`%P@(`AP?^sTQ+C4r;%r`hTvhS<v?)tSv9Bo<z}^(!LvfCn^+4Jw-koe7>+z zhwN1wWphi{sK~clA+uyiPPM2a{}t>=A%>lo>ioM+&Fw;Al4(6d$1hE#`0@6@1t8{^ zmE{QoU3^|kl}eUe`C-D5!Mpk>yZ-1wKT?)|wU$OucHSH*z9`$|@>X7t8JJl)0hcf* ze@lNTr}a~b9PA{fp>mB8oDJ>f$EE-N@7rdEW%t!Xhmk<4>5?|;pwhPlyaA4tiOVaK ztoNT@dA+3<iMxyBeT-ybU7Db?$G7nzcS_OERH|D@{BTp20zg4{CvL5tL^8sZ$vlHm zZq1rPccd{Zq`d>l+#_MoRFTxTe5RW>FIlWG;?#*!b=HMI$0v9{yE-$e9PhGEdt5Yu zwB31j4zar126!mX-;)C5-F%E3SyPKm2bB0j1dix7p`m=qWHX1N+lq-1S|7=5#D)2p z<qaJhq4NOOC9ab2_N>Q5qD8CnkFckis=@wE8V6gB4RYd6im#vtRkE)Q6*n4{>qq!b zm{W@cc(}Xm*h?ESUJD1xpLhpsUKO_!Rr-JGTW`G4y!!-j_O8yFo$XX#?NK*SnZk{1 z)YaX;mr0~Jn$u))u<sv{wOud6IncspRdJs^Xn+nlGbc=Vy$gWwpDqfX9H;MFk~kw| zjO&1ZiigNt-}2MmPVsc!deQL&6+92Q^7;+>;dwv%j|<>|xmlQac`zNBfR*jr3*Z;% zKJ2c=;<Hg8CE+ye?%JSzo-b$)m}oigz5nLbh(bh@Dmt|J^u9SCcH19T*@m`l8uwC% zF>*}%xzLDbn#jZP9k6GYLfW2kaFpmW%WU;j`68W7as_EhqenTt6j%r|Zmm_m&KzA) zq6-g3j;b`6^u|E6{Gn7Lyc<^UQW}l1IwTS&B3nhIGR$EB&960nvgxDIkH53WuB?+? zNWVLTaD}8h`xb|(H=cj%^S@VLyj3#iQpo@S&`baT@qZ{HyO<go{Yw)0oa<}trMYJF zox1t-AV!?zVEQbN`~HDFtnPG`)6>$VsbbfN0;;wpNfa-xHn;x$(ghCy8ACwI(bmy% zm}K%ZiQ;SR1s41kxcW5mBD!6SMQUc0%SLTncylK$V?9Ib(k-bfV(+H(#{UrHayW0W z3%`eF)0KzJto=cHS0|1$P`@fJOjLsLzI3dtGSH>Hva)uLW88S2iZ1Z+yGG$`v-lRS zCt?tWfQOk9$*xgiPtz!WXpks%pc7T#<H^zUcG_%j^^2;T9s7M|m)F-bxVy9U<<)ov zPpExoW1+^YT+_z#q@YkDdbK?@IiNStR-#-t`7ol)WDbs-5IfEAs;p8QRb%;58{f3z zxS*-c_*!-4;da<-9cyu#9m7g>wb0sM^g@AMf^~+K7TW#$^PJzxs;)%5-U`O#@7*%B zw1FGu7bS_~OpI<Aqsyr8bEjfPss9LhX`Hers_v0NXCZ%#n1(>_Q?!1)t0;gdByb7l zh&aXh#)`xSA3?)0j6T(@(gc*pBtaLlu^IP9+KuC0hkOKHkIi3)UskMs`1Cy$q=pnW z+vr!lvTW2$ZTO)BV?T>o-{}K-Zg@>Q)vLNUzIzqIB)m3GI<6pnv^H)ho2wV=o%hT3 z)s@oR3!gv#4g~|y&I?P(HN*uLQ5oN28RRkhU1rvYE0Mk~|I3qtpC>T>?r<XJh3mPA zf0txl`w&340na@-H~h#ba2@9lV*jkDXJ67NVdMZ4B{(vzm_yKVTDfZ9?OuG!#}E%} zhl^Ru*tN*}MKwjOz6nGsXyHibP7)%Px6q|Oh4?NQ!@I6Y2!kKLO|2q9Yug4WBCzhp ziFm#?RiC1y9`aZW^KK~>Fy=ze;o+%g1sjo=Nh;4$?}{6e4&4qH{kX676-Vse(Y>9c zr~T8-5&cwL*5OA~3W%UD>cMUEZ@wyiOe2DBs*+0J&*Uev4ZIC{3kXgdeDBmT6dw%= zC_SZcu0b1=C#%E3-uR=tbqVjU2ln~f`O(u-nxLJ0Nla<Ri9EbJ1#0{AfQNSJ{Bq?t zkNu9B#|ybhN&T!#u9hXX4{B60|4Oe*KRE}8>cgyG)~aC6@Y0!|fUZ^l@RwXjOxQpC z-N|8)Z?Oo(c+UfAvYkMplTq%+b}#7S3`o@!;Ra6@aE~P9Zan^k<X8-%GzF`(LcvT} zAO^*S`UgS``0?0C{ktSFyjR0DZ~&($r(kd(I!7eqH2AgX#p#G%lgrLWxD+gF%)=JZ zB0nB5$421C+3973>1!Pw{C4;I2RELv{ze9%eixgluQ6bUnSu9yK7~)P%X1FW!NiLJ ztlTws`+k*7BL+hCCBM_1TbBQ@=Gj)4w`b~T4~YiN7XcWW%)avSA%B{^#-HtXIpm3^ z!-I7ee!3@nzj(g`>TKazf;yUCa%Fx(!5CfK?9k!zUF>;{;eox7fZPT3iPPBu?y@DM zx#rf?8uw`eiOe&Fi|+Kfeb~Et?m5nRM0kVeygEBSCS;%^gwv6U-spV3kJ&8TpT&pI z!fk)<oIh&5+Dv|Q>0<qS_PXZoXhr}j2=DYYIz37(8<+%|hw9|~d>)N}(D~SXKMwd3 z`FtjTyhQLe;br|eT}H6k<h`%ydIg&#>$={RS*W7U>ho3(E*KI^=e|p=Dy1P30$EIQ zWy~DVZag#^NN~iMs!QdAM<S3lF!>%mI^zMyjz?3#$MPX0S?b5w#J5ALgbG%WGWkm^ zKu16oL(VIp0a`ue;NwH))kRi*&jOA<QyOY+suv6w<4+DmD<nlWf!62-_=Hj<jIY|F z+0Sou4s%c-Al8w*gy;kp*sPf63yHGTjWLj4UsH2r)`Br?bm6+QZYN<TSn>x1-(vYJ zx?VIep{H-Y9NwNrV4bVQN#_Z%XicD9)a`pt+zB{7$OSR90!5Ypb6KJ1YEDouPyYt} zov6NFomlv`gKwdDsJ7;3j^JJ0XP+ny`*q(^dLV=_Vhqy!@rcqHiX!VCEjmdI2T$UJ z6@3UCNtEx!Rm!wbj(OzWA_qPI6^1#>oFGod$7Og=aN61I8z>hD5CkHVH;B2Cqb~PH zLN|ghM4^U^hLCa}3sN_1zic0bCn{#Sb+wNKM`jU6o50s{jC6NQG+LCE7K>3Yd<#Sw zNTSg3ekOhQk_Pjw-!=N46{j9oU9cT{Af+_@9jO2V2OrNvCd=~&Bs1g-@2#AfhcEAy z>f^Wb<|8Z-xIJSxG@j=Zi>?D1iTv1i;uu$^0A0hlQO8fxrOc~uzT|bxK0jPl?t!z2 z0g1kHfHjn&wJ=Abb|WZu9?X#*xHlHuBVm4W#2s);Oo(qEOy12SNw;QwL%dKQy2*s> z8!<gV5=Hk4od=JH`8C>0JpRahSnAMTk7-?K@zgJj(u?Dp-J-dv4bjx7rb6-aOx2EL z^Lq4@Vx~)L!VDw;pH@wp1@G5Kchh%~Z37WM(Vs-54KEwS=;#!Emg~ftee-)%vWXhA z#?zUUreJ_<Ay+lS>Ln7C6o-#&rLi-zZ}8r&3=}1qT9<-|hl>6<47ZlZlU(y&s^tc? zLF-!<RCX{wOMK)kE|5yk^62JZE4N2>=lnL3>YZn?@rP;d6%87DjHnI$_6xbVS+#@X zRymZJzFVHN4Zz}~-%5RoZQ&O%$#C(*_qAP?uU|hwr*U0s^NsT3JI7&KzpXe#grY`E zykQUNunW)P5FH*Nf_G6JI@@oV+@{5;Yr<QeMaWiJ;U3k}#QVluQC0iyV%g~}W>b9@ z;D`j{4Fp=9^cJ%E6k;&9C=W0n&fWya<D3nWXe8lbp%CCJR3l|{Pkk_%nf!>Nd=xnf zsUCS4;(PSZDTYVYO{>R?_#G^1(gxZ71DZh#n{>-a%WyHCXaw8sDENwqp3YA?O;Bgt zg6y=xi<B1oRhy09WkU2l#F=Vhp4Z_;76{*bhgB>5BE*zQa0Qm@!W;r5ESkV;gzR<e zj)lxqiiMVgHfQxDt28A+H4rvI8n*PQcAopBp7TjurqG6EQkM|NQwfy2sUH)KAAG7{ zD?($X0tM(cUyLoxx!0krMn&5M0}NZ=!GkJJK)IH?MkJnD()!08P7DrG_klU#%dPNU zWY7w9K3zN26hxpAo2Q?-0$-<PH8X>?fi0~R)Nvz%xxh008_-0&%#XC}a%c;m_H>-1 z@>(A#?r}@G=2pKy&Z!Pr374^sCTaXNMhXOkaB%JF2fi0>amsw(34{r>)z&rZ9jVF= z@Cz<3bjfP}Omg@`Oz;L&Z7?gNH<{a?f?H-=x1|6CE=^1kby3cp%k<APQOq&N`ZWg= zQ}WOj{kRhwRamf;4YOqG5DTTT>IslxB26wHN?u@F{Fj+AC)cc0*Hv=x<;S{rR(0;@ z#Eon9e}X^#(zDlW5{HyuY3GSxPCd3pWK&I+iV~=(E>ly6@%eQqK^W;%fH<?}3&tn8 zLyB4=puNw+p4%ll5(ix8zz_$9)iUGYJBk`jRy~+aI*~?)HmGR4dmm2;{D~%iru=q1 z+ipJ6u*yirXi(H=SyS}uJU4vx*9|zCf;fLXFpUH}OF8FKm5$SVOF=?Yx>H)d2Lv%+ z5!uvgaXa!ZYe#}+U_+#I&bX4taKW&Ukz_@^o<7t~BMtvA`y~OQ)g9wpSLHDNhG;$p zO^1i<1uzWOkZ6y_g!TKV9Q@p7KKxOvguqeK18m>U&}z{%>8ZyAfg+*l^d|!yw>dG= z?ciRwMt&0|4fG*kB$e+JgdKMpG*sBU^>0WO3;`r9fpw7rz^3x@Z`}gKyy`AS46OKE z8^+(}=Dik&2uGK-+<BSHYsGJ4l<-)E+Xit`QRC3~9UH+7KE0-^R}Sio!{%({z`Nh3 zJp$1=JzwBYSe3Q?w#}kXZ1}#_FU3-m_v86`ZgI7A>%#6p+^?6(tn*J>=Cx%A3vCLm z3Nsu7spyI~fns;oEg(3CW8HeGdWhlH1gr#{+-;`9E5`}H1ko+b*j7VUNcqARd>^vJ z28ng&-2d()Yc~^SOY@-Bi9<{pK;Uux_MMt{jxNDxU^+9Y;uom|2jW(8ZaJ_B<Aexw za)0|T6Cy01cg6f>Q7}z?MD!H8c#yP<S3pRuH82kyx!4SgG&6T^QoFWZu!JJ-JAeQ9 zlSB#kP#>n?5GKDGq<}APHm^6XFNId$qW|~i8)nK9Qdug-1LLUh_Fn|x=2Fys={U0I zWDw(IO8Fe!h{UCAoq4b<SWM{r8IuN${4j(_J$e!7%g{otpevaQn)G`-%T&If5Y{tE zagEJ=2!4hJ@;Xyk{h}O1^6X(A+Au1LY0a%UGTS0rxgNkv3PVv;1H6McZDxA2Q?W7L z`3i*75saq@@Z02I!!&}-r8QrvP<6=7^e8$BxqP*~3xF%ic$vZj5YlU@n4bb_EC#yK z%{7F4m_vMWYbKQP%xdrPy@xh3+L*H;Q+39nnb<8@LcP@cduN3MrC2o`YQHa($#496 zr1yS=bN8g%1UI!U6-&Hp^pwY%`EGAUMe)(PKA&uzT?Hvnt|bXwZKpHE2=DG2ZG9>l zCITEldu^}iu}+GmUj*A(ZB}ivNNPZy+t!`(R#QYVbdtVj8}}domWb@N8bMo<8$se# z{L*0;GlmLvTn4zSB$HAH-bXK4O6f@Eq~(e?i^{_e=Hw3HeSGsO3})}BgdFX7nWlGA z2Z?3*rW4VC+>|c=4RaY|2_npG%YYq7k#{@vS^LS30W*bB8FoQD^wlXx*thK$BBJ!t zH*gAUs(_UK>Nr96mq9f%j0yhl(5_c!#k(%wp!(VyHc~ty<&|iD>dl3Uup^oWlWMUJ zALY}cDq^$BQzS7kB5nZsX=$)>12rm6yIt~v_jg!!A%wwP^%jcXyW>P$l?a4c4}n-1 zy7Hc--5d2fdsT||I}=kclib^9jyIh<lEwID+SDg>2|L86)-_I;U}BJnQ~6~lg-2q5 zf`ftmWJG~qbz+%yb_VT%U*wfoP;ME_z|F;`aQ)$Cr{f*XJht*BGQy-1th+0`4tUX= zQ`^>;g_4w-4bk?ilSE}b&?c+ePD)y5AX4g)HE0y=q>@^eA4dA5CTIAfQ6@BhB<3d7 zkz7>H*I`iwV-fB1jgNU?UFzVpnGf>`Ef)r7fU-x~N8y2{{>BQA&K*V^H?deRdcHg6 z$2C%GWYVOtYAD9<pMRhz1xrq2IM__Hod4}Lp8E5y_9T3b*e-lDLr#lQ2{u<7Xg@)Z zZ+^xy&HAEE67KGu9}UO-twG9PtNPj0uCjJ5EdqNAwAK;cQgz^Gt}xhYu##MTJdtx) z{KzRNQ*QW3!SV=O1qyGvagk^;%$hX;L$|i`)hZJ+`Eh;kZPbPT+}@V@*uzx~pWfiv zrFn!ouovR-Z9cAuO7v<hUUET9no+*D)^0dKfBr}~Gv-dVrXM9&{xDl_1@A``m}OqV zYCq;r_Oo_NHMf!{Rk!``B@_)``I)ME9hs&Nb}hP0>wL%yb6_|8LiPoR76i5sK^bKr z+_VM)606G7xr;Q)GmTo4wD>TyuDZxQzZMLT+#!shXv8>b2mYi16$Pk$3rCz5f<sBR zOSvH$PfAv~e=|b9z%HnNH^ffN*bS<eo;Sy)uz;lSygRr%+nO)yMR~J->FpUN>_~$D zVA*a<uK&H8KDwf8{JZVISO6|dx%zI+-!O#dvE5_#Y9oP(kz*TCi`>xXw+)2zfbVCA zs2lz)9vmH{^0!aMM~7u4X<rBtk^Q5T$UrVNzS0G!Z5RvQG(JaMFOmIvde!ouWa<6M zOAEydoEnsH%)_r^jwWM8+VANRS?Whql%oJE8i*$5T~g$x+MVlI2@B1h6Mrl^8Q-a= z_Y_op0{Zd_UGJGs(BI5bHi31A(Bo3|(L?LXe`NCuVqcf-H52%z9`NB>Ipw4*<^0qZ zm+PC|z5Vy2ACOLvUekG%G86^jqv#feXRAs^<}-mclZaKJ!W$eh0KUTd&1OMeF#{Z_ zC;4N2E5qAJn9=bDa^gg1n&;`eIBK(1VKCf9n7h`TCJt>I-(uiVYz@|u#6j<r)lO6( z@q^P_^h_0bwG2qJ9Td%LX`p#6I+HewzP*sAV4Gr*B+5OK>t?v6)>P&yuYscdOd*(B zZOF6AYZZ+lBD8L)C~2}lZ7wZsU-NjnLWZUrY_{0f>zvpPVQRo5tL_WE*^cMo>~Ko7 z=~`|T?@XV}`Gb!GS-Qr00B}(938fwtV7vELOYA&0i4QPsOS4VtVQTUDbPw_?nb5S7 zW>ldgYuRks)`0FHW{^RQdfWzi1A_Y41{vCPXDPlBm}9U2|J4D-J17MrP?A`MYzpU{ zI)$!o>}Rgz5lE>A9yH99+LvfA$7t`K!KZ^(eqXQ>6-iSRVJ7QdMs@ts*D7$MADbf1 z&;(C1mXGL`{v~mpQf`!wm#L?Ll45Kisc(W7IFP|<B?`|Q?-`8a)6>KcrUT0g4#yWN zRNRY#)={Sqm9p*fhxg?Vo;ZH8qF#1Z@Fu@CAKpo&L=(^ubt4{It`N^6d%5<uly32I z_Ev?UdE~9DR%|JMrZr<E^2BGh)+O0SZDnxL$+c`AFYrjV4)QBw?iEU~7{hHIxTpq} zu#VTgA;7VCSzM&zmu@2-A-yZz<30~mmm345%P%ApbGmh1a2SLKyz`!=*R8eg_nxKV z7~l?zjgKqBc;aI$<{Knp0~y;0*L~BcUI->69?xnpODl2o(_+<JQlTF#37ZyLeuda? zW49?C=5I4o6sYEr_9x7u2pctW(KCI_m60c2G_nD2PUv$!)GApMy~_y`v*N)&5;!Ha zRv}9YNJe5d2i)1g6`R_H)C(#iHi)WbBvtGkV^NZn;bo#S_zy>dS6Sr3ve)POKbW6W z{gmz_ypk(=M-Zf>A%Kp&rYc$LtFg|Qz7o_dG5NVkwQV(fkXCBFPTBivrEVn3Dq)*6 zmzwA0bPUp{o#ywD17bODX_T7NWNIPB_ZIs<T!qn6T-tC)*pJq=VDanYvWvednse6* z96p03H?&DeW=?W978#u5TVLShgq@TdNNx+`YXAA!nE%!X+wGt2fF)m3iowFr*6^rM z$l*&RG#aG?j}2fL23R(bTJ?NSa3o?ctS4d{cMt<^u|FT}I(JLnCq%(C-#HnE^K0!w z&euU(_T-KtUrb1&ntW!^`$aB`G>^9S1brZgR?}0=4DbI)q_IObuc-Nl-HDjj%`0&| z^!Wt_TNOM`_9b|NzL=;M8Af5oY)amIDlkqU^hA)0;#!u}MGT|aOnbX-B-|oX>_jom z){d)x67G?Gice7+%%X}HA%8TnEy6L*k7<nwZ+zE?-4BU$UEyNVkfTISrc|uT&`p3( zr<O=rnZc!8y!=<fa%~D^i}gq+YdGUdtt$29YU)yC{+pmU<(Os+>QgLmKQ5kx848eR z>HdaA5#Cl-zM>`mQ0V{^5103$kzx}G58J47QMnWE^f#IDNI1AYHy?|0)TwOum<z|l zoq!oT9SIh=30hD}%o=td`yRr8Qb==qk%Ux#YJ802fg);z$T$OZF|n5PKH#PmrO@cf za6PHSPHWDKp4j+NRf)~yg2avL%?0eSLG^W1yfkOTE#i){-AJHDQ`JMfh96PEnHebi zM;+yG20~nCB4rlMBr%iN44!-0$AqU?Kdky?sUooSZ%s3KD~bd<uw43CuWDvJP@lM* zf8{uA<I!bdr$A+Gd`n7*)kJ&f=nix4$bAeEI+oMh#FGE<wkpMEa{60-JusYtvZQ;q z%U0`W_th`n&)InEwSD~+rZ-g&l5UKL8Y4av$PS%qe|_Segn$%f)1PN)a1E>jh*7=f z-+nJF1RuH6Q{N#9uvOB2pDSOa9HO|%XDv4gnb8W0n;VnO2~)j<AE?VY=^tQRj17oH zt2YN{hoo>jqK-utCe5lLAAXo|krix_GL^Unm#Z2UsE>8UN<~Ve2%KEV)!<^t<9+^s zrL=Zd1$oienX&va@MKB7d`U7tzZ+mK7XGx30SOn55gu6{=%Gr+^iW$&NpyQ(2%0)k z5quB;^yJ0NG1V73N2n4Wz@1kFAF|T9O4^jl_ZtNX@v@4<1=-YlNfIW#71O1qk7D*a z`3s1Uuq2W*?!=Cvwsqlf<xlMyzZ^`;ZY0p#YpMwe`{)=<Kw5rA?~Lc(2wlge-{)9R zRLV;e9ti<_hG}y&`iWLjv6{K4_nqVHGGx-+W%Bb=cE!GZfjD-#M;5ixM`AK?kYvb; z-y~{=s_~$j%@S)Y?!#_<#)bY)NNB=}M${*`SAC2Y@Gd*>yjg8I17?tj9h8^8cuPN) zh=`WdI8_CE@W)A^ee(AaAdorXX~&Cd*lE4<@0Hib2ZLHNg&L4(81@L;l`aEzSa;le z7M3)9w_b3El9YnDoIiF&Sa4vy^{i3G&f<XVUs2U_i*bjc=n=P#idm3cx`7)AzI4*R zXO=IgMQwk=PR7K|W(p3^B}iH`%M#D=@p@uK>2V)?-N>7<Cb!)&VRv^P^1$OeS%&Oh zbOaQrJxr{i&U#)|_u?HAwm{|LY$%gvlCJmgK3Qr$(hL*cSetlbi<A(ghCsA+yd4<8 zO7;e<d6sLMAr>03U>rTSYm%iYdw5o|U7#GVt$09MVXsF_kndes6*-h}XS`ybg<g~l zOcijhugTT*{&ZSBT*M$uy)jA-8M{wdJO9cuZG*byA46uywE1Jt79gXMl6M0nzZO{M zM(tw$0~!GUky=YiXbGq5?u}BqOWS6#E}dm&4u5%<6Fk&rE-W7K;asFmduO*v@RQFp zHzyZ#i<a+r?UTclpegM@BluFCfhG9%cQoU&omGwl0b}K0&B06P6dq6^-r6Ef&bqa{ zykr7TsT9Kz7Q*~!W}}Z1-RtFSlMQEtmh~W>)WL~Ka>Wp7P$_aOt#~X`8R_Nb=du(P z;>f$MtodUAL4s8vF9DYC>o7g8wJ>75Mw5ZD7h--^&jyl0z&bx<Q?%@JEWB)NZjdv& zE{aQaidTkhLk<S~d+SB-0hkKj<|<|wqUC$P@@b57#2+Hi&k-ZY9_!3q+!5}8waORc zejgMV%W>PMAx=WgT`~IQU5dkl`;GjD>7571fkOvVDbc%Wk7D*Fu5u3Ku0)ZFw?cM^ z=1Fe*17|Qd5sfxHtExv<x6R0?wKI{T9b4(Da;jU6s+~LescUi16eM&<1B!$963j|} z_RCz9CI=m3f2KzYHBzolbv|R&WEI_RDPm5w7;xqow!Dd<4tHIaz4i1ZdwwedH)5B? z6Q9UpX~%q$Z24!DksLC_<GPRjignHmt@$E?#0Q4Pq|XWLA7dh=K)KExBXp_KREuWm zR66{Hf~+_b_3dX%PV&BIQ}0iu8P%$aL5L$Eh9rn0_3Y)-q<rLD%+Zdm=_b3b6F&!! zlAHNwwP+{cwk<ab6a4+`3`h3H+n>lJ3e&k@VAzeVz1N5r{Uzm=yl#%JXGI#(WRfqL z0{y*Aq!=*e%U6oHe;q;iRHu?Npj5wdqonPfXk)dil4l2S-(AL;q;Rt+Su{L+t{wk! zf);4H-M*qX39-4FI#O`(7^RJJnj0L%JPcm@PC9LNv9<!yIuGTuAO)F(wEMszmbqOQ znifB%6+((N0}mq>z*QQ$6{Uf$J}y*w{HOZKojiC6+qyn+1Isd+3|L84t2;8;7_6xb z&Lw-KnED*OzAAL7{6UhfaN#1iy=Nqf$pQP_qiS4xbl0>d7OoUyOS3Otys*wmBdTM8 zT@KVM#8nUb5qgsA@L}7aK09r#v7)ll8|EHDGPfTA;1mnddIo+Q^0?uhn@x&)TXeK^ zsg}LujzQJqB~JFIN+VlVVbS+RYkj%%I>G6+1U@5vU-2+_gKVQ;L>oHCd5n>I)^^#6 z1#ip@cVyX)Q%_#lGeYZo<|AH>)+MZju{)2<pCU5{tCm&pM+zE+o2=ei2#4{Gdx@Q0 z)34h{zhuomm%d0B&43+Pe>ISs0SkH{51q@wGl6KDa;=7vb?kW$&B7}nVmOmY?KwyV zV)H!QNS#wEn8DU^__R&;j7I68{9j7Y<f{3WLrFqmA<*{KKnVDM)X#H3e%BPD?!;BN zps24MM?HhQNtd56uKA)eb%jP);4!o+^3K0mdNM8V&;LBHLp*!>ri(J^mR7_G*8h`^ zeg-Y0Y3pi;<8H43%hs%qHF-4(g-%IJ_R6m)K!nb+*!`5HpfGo7#eK@jEAB1zGEGio ze5-&L7^O2kM2tew329yhcqYm1j=hh%)LdxHEo|<4#o>YtTN)E@UYEvIxSje$l4mZ2 zqIUE?-Z=Q-_m=Y0niYfYAQnHNUroS8Y+H1B^ffVgRU+{}VLrb^m_C=c?z7;uKmFmf z+cuV0F>LNL^>#i3*9|_a9y!;Ivj!GCm@b-m4AMHjtv4=cJs4h{ueUFIJYMfsJ+yz< z81gzOa1nyI541mI4aJk}&z^-I7;QvwU0e&5b`6wGp3%)UMItvt4btm;=)974L*XtO zCOdC_tQ>4&n~`?p6wVSBBi6@J3N*u92#Ps57QL}n00fU92(Xj4_r9(s8c@Y!?&qM& zemWyb=hm=iE)7k&=((<P{m7tP)3{80e)Ia?HI0`#{%XK-7TL1fnZmJ;W1Xnz_1MAC zv<z{ZcHw7t;X_!EYGY*N;TS8$n6FVy4}{_4rg;|pgL4B35&c{Dk|P|iamsS@ay&9v zTv${1;#aOtHded`5HrK+6uetK5Wefcp^;<^jh&nhTeV2zOM~jFh~f~jnK0+8k!KiP zL*PvMP#-y1<fvt5xhhpHhrdLcx$^W8t`8-&+<_W<fdy$KiY+g2*)IE$Ez5~*#dArN z0hK->1*rh|^>0+gKdpBZZBcvYh%VX->=mlVWY6|L<_aU7cmZ9Z?7ctsdIfoNT1N^U zd4;WfMQt!xpzrwtn{1~=>ig=`n5b=W6cKGi^9p;E1~5+*_~qF{0wyrGU5$95mekb9 zcAwQNsDdxF5PsH=uzj=_rA$H%q)#B=qc+{tU=GMJI5t<SrV<ZZ<2OtP#EXd#b0^s) zW?!OH8wuHm)s(k_gD=hzl0LBE!wEOO@fVvY-s_i$vhFz)4_(i)9tcIjg6IiT+m#r* znIbDC9<wh9XfqO^iOaX^B~C`NHq!nwPgKHVTOLu|pH1LP;!J3qRaS=PK1VS?N^E2( z*I@m)eay@INxwP6W>NbMV@TV!mbjGnwNI^W^JRdfyjrHy*a)75$(CDJ2shK0)auV| zsKtr~DYl`?Sj~CoJ~ova4R6CUNg>Y)Ei1Z)jSk^RvLmYvo)CAx2K(1*>5)Xg#sUTt zM2-nyxYt*zS}{^-a^h$S+3TeI*=5=xHg>sgI|nQCLE7J3@1B5f+3{`ssz<mI&(BDk zpcWP}$o#{Nuxvfe>Si~s*PICli+bO!Il?j>#Bqrc97qe!Np3-#uxE}1WwN-jEY)AV z`X?T*46VpDNWyt=;fMO?xDar_A~}Rfo1H&d6B8#Tx2BR-NE`TchsgGpAD|<10-Gm& zR+KFL#dj>6vv*G~(HxsQ`7+?vvM~ximFVXxfDfCT&x*s(_CgA9dn-LBAr8%1HJMgD z98t$*!P{;pKOHayAa;c3y&P08T~Pz{BrS%Teu{BVRu2@-HanxS<mP8RF-d3e?orWU zcs*7&Xq<a3xC>Z?NLb~%(T#?whW4v&coZgSl>M5aI3-Rdvhj)cUohP#O$Cla2ObMQ zbhXbdL0PdHX>x=}r_rs?jch&G$u4b?j^rMf<r4}BkxHV>tf1N}8M>*AQRlJ&iV3k3 zPU3fzU>Bvq&K~*$`I}yEh6!quan+?G;28Bs`~HoEjyr5eFR^I+vid`tL7R`jrGxY0 z{+<UA*{C9BQek0^OKJ<2z@&e@``WS1Nvf0?c5{B69k{HR3E-M6-7Bk7yK~lCf8t>I z@Eeyt@UIJSXk7RX1?+=6!^}jY6gC{X_3ulmiupr}#P4l;o7e#KMQLf$0VYB6Zg<2p zf!{_2(q4RA<D)#LZi)^<Ml=m&PPhhDr23O2yXNNtF&d<}Cgd9at+%rJFuYzVHTm-c z<{Fd0sXpPa;gkz`*rpIX1$JM`L=*5U4o-N2f<K)k3gx7$Q7UJ-Gc+>DR+B~a_+~^R z{B!Phx5XS^F7`+Bx~d85Lw$y2Kg%}DilIwoB1j5$6Z|arxWOts<*Sp0H+FO02HTg^ z@L9{EaFfv|*_emIDnPw#bKt%G@UT=WVkt%Z4MQhpAZtX?*`CFoJ37n|aS!fRIEe=a z%e;ScP}blEC6&rUY-GY_tAIqtxCP)c*<GDMu2*{M$iXFvFHj=Oj`(I%#4NmKkH5*% zL4u4HHO{Nh>qRrD^F&h<4EQ^5O7H3?raa2g4b{<KBGJBWy`S_DKyS!I`fQJ1W*a~* zjj)-n(TzZt<KSUox&3+Tv>Pw3fJSuL+ILCBk$5%f3*!i~RbRX*-aX}ee0^`ynI%<w z?rS(#0-gy>?;k(!&Y0So9JJ|*>hx|UUE6#F0`~<RH4@Zp85=f1gnenk(DMEvuau7u z<fs+W7-i}S!}+<Yp|vf?%lWZ+-loY(!bQ;tU=^#z)mOCESN@DWKG7HUpD~+DV5N^8 zeB@lIp|2|*`nKAFd0RjGr+b?&n=WdKT(Ilhy{fKO{$dLXveQznn8~LiHYb619;wGd zFE}|$Zw^?HUkdVtFA9g)0Hq{0p(Nkb_U?t1otq8Ru7V4m6!M~{yK{hVXN*esH<CU= zOHT=J3{gfoW%cPiVq_N6&F~bbYkQ}NNQ0Hu?-u5fP`U`Ar-;S2WidIZ@OBXwve0~y zIv_EW>|iwr%DjP{rsJ-xs`t&@L-e&MZU?U!a&ftmHVYSL=dUypFHc+NyR&&cN9U_| z%1eue24qF$gYiX<@;^&0S>IuEssa-Pr;EJIT*7EXkLeG%QVrA2ZawIjwtB*kf8)@X ze0?KVE$UlGg8Y^M^HJxl+{WS3Q9a(?!#LGL0Tq-{%rOkp{(b<{w43#<#apg%*EM=) z3;0~3v5wB3VUf%yf~*7(Fe(V@SIQbBAQh}lmU!AH00RjCV8H_bh`)aQcggqr*O8%_ zgQKOHJ}m>?4>|_Af1S~qSsUBX^C>Bc%E&9wIl4Oj9e65vKj#k&0PutU9jN+M&3^+* ziU|lwD+v7)a6i1HXaooV*!=<${M)^+eZC*|R~Y{dC?%xGC&;JB_jmUwTMTj%zDR8l z0Kiws|0(%?#OVK>CNCr)BQN-OR(H{?s?Ha|`fJ1e59wc?-D3TBmWrs5kmTP{a^G_3 zp}!E2UmNNFLPcW#ca)=zt&XLU^H;{<KXk<K_-L2bSGx&)bq31+LazLUq}S0gvo>?o z(fP_*{JT%YmnLt$UxvtEkpCT?>DTH1-|+N0`g#Tywl?;T|1VTkIK9!t7iJU$0Ql0Z z_)p3AGydv?{~Kjx=3wv-9_{FJO^M(D0Q80cz*h|aDfxaD1pkC_Fm-Y?`&T;V-$S!O z2UI+K`NQ_r=J@}?{Hy0qIsXyl=3roBZER*jXJBmdci4y9X<o@!7zd_*zohVZ{@<|w z+c80Yd;xtm0AS7x2=Eo?e@ea|i1t6R9QEvt%`A=nAw=VqnPYlt0H8ew0Qees|0(%? zSxtYD3~a1y^&J1f+=eKO=7}BvFdF>()$_jdm${*yqn^H=!#~xZRYW)T0}TKWm;e7V zWdH3zz8@J1(0{tz%-Yb%^&hHNlB1$^_yGU}j{d#+5Q@L7Eo}_+9Bu3!{sG`x$ZTTy zm6^NB_ICia=3f9SJ!>;#BZq%#fX1d!V-WDKIqa+PkpJ!c*FN8G$nt*z>@B_oSN_3) z1lA>R$giPHmGO56UhV&fy^*8dzZ&r$08#6K$i*-K06Y}{@UQv$-zDFVDdjJKy^({B zlf8k_Ke^y%C-AEIWopd-_YmOo{~|aT*qhlp{*%2tSU-iy*CpJ43;-bfyZWzvzTfZW zzwH0Z5c|76&A;vQ{pg<lGX6`g=I^8G?-|yA*_R^$|L6MocfPf(1lU(!{cCdh23Y($ La$x<M^#K0|KSYI- literal 0 HcmV?d00001 diff --git a/venv/share/python-wheels/distro-1.5.0-py2.py3-none-any.whl b/venv/share/python-wheels/distro-1.5.0-py2.py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..1dfd7ab92c26525274da9c4606544ae5265b5138 GIT binary patch literal 19272 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 Z+zvgBpnLcIdIZ=$ZMLiE-b=sk{sQuGw7viU literal 0 HcmV?d00001 diff --git a/venv/share/python-wheels/html5lib-1.0.1-py2.py3-none-any.whl b/venv/share/python-wheels/html5lib-1.0.1-py2.py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..a37d282b156463491f5f44cf073944e212a6c7b1 GIT binary patch literal 115285 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%0A8AySY5A)uULcQ!$ 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 LB-H^rK%oBzItQ!z literal 0 HcmV?d00001 diff --git a/venv/share/python-wheels/idna-2.9-py2.py3-none-any.whl b/venv/share/python-wheels/idna-2.9-py2.py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..61a0f37c99fb834cefb81acad7d31f768de2870d GIT binary patch literal 62768 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 literal 0 HcmV?d00001 diff --git a/venv/share/python-wheels/ipaddr-2.2.0-py2.py3-none-any.whl b/venv/share/python-wheels/ipaddr-2.2.0-py2.py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..2c9dfd25b4e1252b1d6203e34ceee0baba494067 GIT binary patch literal 19552 zcmaI6Q>-vbu&q07+qP}nwr$(CZQHhOd;Zh5?Xynq(>}?*50!NKp;F1$H7Xg^3evzJ zC;$Ke5CEB=-3r8u{=w*o003-w002b)-C8;rnwU7zGSM;7G0>S<I=j$X+L_tY3#zI} z$SWz+xp=skW^%_9OFE7Je507|Vlr=pqlLeW_%-3%IA!<pW;uqKs5Vh`<4sQ2kd#|o z5af~zCQu5@30=_~LvTnS5Y*=Ef||_vfm|e?qidSX=Nu;>Dvnmoczhq>Px9;D+T^R} z`__^9``t;gF1FrYDqPqodG#*GX4Oz_UD&p*l)hRyG5LPoY#!UTb>#ENplv>0-a1u1 zQ~A7npzHgWl67{n=-Oi!lZDzfFH3FN@lU}Y82Ak1dY4A8xncCM>ascSf~`~PUJPEv zUVzWGPO$~6A#a7|KKZ&9leNOBwmrL53)i>nSi7Y6vhs9jV(yv4H^vk)Z3X{cGCktt zn!K)MaG8)dCcm+j)yK@yVYM^!Mf~!0uLz%g3%<_({Zp;86n|OkT*xp~(Ws?-p`iE9 zRkt&D&2`y99W$S<!tdF_qun(ruY2l}0An_RZh!F7o+iesCaayLvze$?W81l~TiBG@ z+KpQ3Hk-hc(R-<D?h($zZ^Finc`B{o@lg_^ZbTFfzh-;gjm?^+i=B&Kce`d_E9Tjc zC|hZ*LHhX!Psq(Qv+aJKChWc++ut@?vCGoH@{F1-%NMI?=0gMBbSet=C}<uz6Ktm@ zT56oLJnpX7VK<RpkM~@BnR6q{9!1bu>ayvZm1KHNS0hdfz5O9fD$-7u&8i&>rOU?J zi_CsIDkbb@y{PORrA<pXSfi_>a!M=5*tDmy$=`{E+#W5zUP9GsddTknXfIbj)Vye8 zy<WYlO!M{JioLipQWTZn=H1NN>5j9ACibzPh*3yH9+6rj{3mz2SPRF!qgCqdDUQDp zK6@HUS4&>96$irUntHJkx%<ra{5}*GYnh|rGmcEp8mC3tiGt{Ce`%xlNw{}p-m|04 z^p_}Q<arr_#Ff02O*W~_{w&$yPMG1s%YGOjI6_YAt(lQ0ljM#^8{fsfhn0Wp$YEm` z`_{Alo<&Mefu|d_W+{&$r`PQGw`C#Jq>9nJd37Dj8cLXW(wP^KOwVggi1q%ohz6`( zS;OUMItX@(y>p^!A`S#_x7({sKElEM##X=lZ((FKSuhHvmRcfiYkjk~@xb7G@)#ur z+5Qvn51H#B7#%+MaU<_NBREdD%cXkD6`t?3XLEec^l8j4_T{r+H+zonuRu=dE_z|@ zJ3w19d#t6#3YEA2>?LWagmyQxaeC^q;E}#hp?t)KboWB?xwk@lyW7TAzwn(b8}l_; zM7&dLC+Zq22OQ6()B=Ru8vu6M*9MiORA%xYmb^J~UQOfX<tocaNFXj%_Uwka`gDB~ zTdb}>LOrbEm5i@~`A6oJ4o!9N?-;8!^Au&f95(K<cYIi7W9`QZLp-P;KgM=hQo-{$ zdvqYJkI&y=!!;O!%!&Mmec$(NdQ|&67q=s@1~JrXN<Ld+3%BcN0-rz}A>m@>Fy|)r zR1^k4g@G#@JoTBVGd3O^Qb@56KaMK=TBe<?ta8jhZ2RdbQ%~FJ>#&*23&CyA?TsXp zlC%{|lA!&fEAUi!g2om$fX5i8gEsr3mpDF$FrOt0C&`l1T`j52FvVzDW(uX;_UJ(R zDE%UwxJ#8_qF+&GSWPE|I^Fa5$0nfe!Er^_P0tO7)xLA+J16au)qu!=5)f;Zk<zZ> zb~lVR&Bsm&m$=mN?J&h|GTtPM=oRITy8_(ybdxh^W(j62SIM1VkG|EN2f+5EFmO*q zUj_q94lFzha%Z1+?5UG`>h@O7Zg#U`>&-^{Rw7+DO7?jf245PH4Xn=@SsThwQqW=f z8p>Q6(RvC$_RIW=6}-TH8y7;})0x(Qqu8$xe$(&(FXe@aBd?ukwc807%3<cI;=)2c zm4+Z@e?yiWKpd`Uj=t$SE()dUIkyEcVel3qggNL!aLFbBc{WOtjxxDU(b*-H$yyyF z$K4H^Om*%k-}og6_@xEH0v?si9#9_nqP=cK9U)4Gb4~~fTC}XPT%d}F^-g-5^ku~_ zGOEG3YbOvSA?{1%Kuw0Lf=*aeA}87e*eJMSAg)KSPl@wp_D#)a>dn*D)##fSeC*Oa zUF1iA&zxZdhvDLfk+7fC2Aac>rF++gl<QE->#u8CZhdWx&FY55PDS*#Mr<R+ZUg_{ zY6Wdja%qiRgl-STy9YnZ_rflKS7&6WH^rfg0H1~2jS6TjD!`r<>U=6XuPeQlAfrNd z)kLh`m0f6jYZ9XqjdCFR^s(CYp(H!mm+#<@3VLp3lq1+a7J<+nF%#)O8<Nf`sjAnd zx-YWDKyq8xQmJlxUCi)#RZVm{^>jO7u4h#?<@BfU&IPKDJSz4!Gu0J6QdAn%I?79? zSHpA3YytppOmLxA_7b2C^;^rLeE)}1q6zuLmNwd=cA-AU_z9G0Vg*`Ba0ZgH9t~_R z^~$nAEAmacK*88jX?%v=Si+Z!Ef5zL#hn4tgB29RP*d${%1(W0EOr@agOOB_xLev= zbj*QJYeXu=kjhE+5>H@2_rEiyZNZG(E-Jy-?2d8^;ZX79J{RhIuIE$-KfR2NIaFkz z(zEap)cRX8b7YS=;^;bnW-{-==S_Kk$@{;nJNQ=>i-VJ<uB2Yt?LG#cQ>`<*)bIBa z>nm%@Vr$*;R2m+LRs7a*!VWJEif6mV_Q#d55qVnc6?&RYw*>e~w_H7S<o+{!(L()w zT<rzYyn*F9i-x3#%^z!@<A16G-~$-g5o4{3JJs>Jsptx~b>6Ob6|!}8>xamcsU-Q9 z8RT@GY_ihkB_iBsexJc!K_@+bhtAi#Ex|T*($?6k?q0MP&al;$L>~ipw%L+{C5kuy zqNd3N8r0V7q*8Qei1-G8bqSLZ7zoqUr*S^vZ7p36UFA2t7=|X`B`^kTXfNoeG)oo? zEG0D&$`eE!-sdFO&y&aMLz7BO#uB9Tuv)+t>y<5c2So(^1yMdL0`s?}8i~{eqOX?7 zL<;SKI43CUYdGN4UO=W-zs~MD(6U1$R!aO9=`abAmr->wIF1v<9$KjXM0A1I()z@8 zK<>ClErbNg3ReNR7Y0C9nr&6B5!*CHv5j6>2U%523hnll0Yd!xlU4cwGXV-J9ndkg z7+r9s4OC-q-bfA?33zPc$!e0}gw`=m64mff43aX-FW@hGNA4I9w=>=t9nnR&nXDck z&HT7KySZ|!u#TrzVFN3<a%bPPVskyx<|l-|otar6jer%^kQ^P8)AT&6hx;5;)FA5Z zDnQ!2s|~$%=`HAaY9zt3_I12cJigXA3{{0%6WgELY9(q0S#twEkc<i$Z3dpS#hzLg zYwf7Y?TqDibF>U^+8Gz2nK+IqSdGyGOpk-6>uM91EQ`Fkq`ua%d)3?L_ZpAS_)A#L zn@-Q}dVu&IMe?-7{C#p=PIt}DlW>LuZ=vV*)oF!h=aE;Xoen>RdPR<YDeo8DFQ|%J zQtPw8h~}?mlNXQ~(3V({k(z>MgE4h6|7%s0KS}*0!4Sbw)MA!pSFaKnF*{IQg8kYV zDzo&O#|q~y)g_5IFCzG%>-aG0e;q0lislYRL*%6KV4Kn$JvwCt*GDEPyJqY<UhrPq zBK&e6lB_k9a7@N+FkFeLiuH&|D`+DEtt-k5vjcgCp;;>&KIX}LO9Y{^xUgsSnLoVD zEc+fUJ1j$_@&6WgYMO9mhxmGQ>R+DtS(QHGcu*v=Hkqchd*TEDB4-fTn^Sp{W;07m zj)4J;D3Uc%Q?a@d>z^-l*+7l`KC#CyGr^oLl#X^oDgtVZZo!kx0`@AngJ@<I;+<Ug z|LWl_UCaT(ud%AOHBk)1>e!PG+#RC+e&6<j#njBBr4Vl8Kp$$FlC)%|n(&)VSMY4K z<3+GnAqRN@H54zU@L-~$FSKq<@VXsk%2-CZ&A0(45>xg#bra3{un|D>Ji^c5T-S$B z=?$f-w$QX$^|QNJ*%r~-(;BU=RIu83DQS3qD|i#=Q?;G*F-*$(O17ArUh!d<ps`f; z*}CI}#?}*ga_2(?1O4RHX0_k9wK<f_b;RQ`$~96>uj*HH0t~5`_j!&BRv$KmXWuq) z`4By{EY3SFtjdqSC4F4c)OTU&sZ`ac&)rt+U*wpqn5%lLVSm<Q(o4757hGB-*s`XY z+ezjvkj+r;T<*K@Pdqmk0mU@Es-NWz>KKlQL6j#HGYpt)CZX#IBe(_C$iYjR=5kA5 zNlKIZ+8JDHDMQZgcmd_e`FI$4{M}VBdO;G{%HHa|222GHF()l$o16HAjIm-<dphpN zVwZwUl0qb>vZXTQk_sQz=l7HaM7q!8$-10~@nrsi>DV7QhJ=IlH#nVk7+zTMSbM#s zg#e(em5hQdXiR*oK}X|;^CAa1XfUeF2VVu>ubDo}yHu)VJqHyv9l<I}<n7vw;iCwr z#OX?;^rnqJkL!rtnIa9L2V0CiJ3R+o^;igcP#Jg5EJOE){{ijBm|8Se))w3pV86ho z6r>Ox=~3NeXTU)-dA44lve@CcnJ-RvxXK@)dr5guV9MUQHm98{U2j*vc}u$+@)g#9 z7?s|}PGUkElgm8gIT4h{xELPGU5|QnINCq)<j&5zK;q9lO$GEC$(1`FdBm&1Z|Z(X z%^jl30)n+x%y=W3GH~R{;jC!-S*lYzeHRGd=*j4vn}K~L{6QxnEyX%@@Vwr7le64t zO)KeA!%PjH=n6W)8AURAPA6t}OiXHy8p&EsXm-$!94}vlCeUzBr6{JFW#zG%*vnu! zk@EaKefg`r1;-$`@J$Ufr%v2Y{;nn!wYAs>HLc8|WnBoup99+>W28M{efC?2_JU;^ zOR%s$s&2^h+nGR8DhI}skE|ZNzi5S}-y#nyVL`hXSV~1qg{Hdoh4iIJpB*z`f|_wL z#DH$W1Y9beXVq~23>K!T9*yw>i?{&+J&F$$q_If1eON3z-YUJrG(+QYPCyIcm>!l9 z-P_ac1vz~y%{4Wda><xA-^=)=3FNMjP9Dg(guirn+^5X3UBcnpCI@?UFt5-5NGWb& z2kk^SS~uzIS`D=Rxu(t44iA2cPiYoa75f|ka43*j+SoSe)|d30zk-ze{|f4j02?qh ze)xx7t0ym?eBXYr=j(J@!gTA25oTn{^rjYs2o!1A8S2roJnpS3K+uD%r*rT4zizHe z!6}46i0aGLo2lRR^=9^DR``v|Q^LO}Y?7PlTUcOw;k_s%_RKhzZLy1oD#oN3*^Bcg z+02UnXese0t_2^IMGn6ny)-s1M>jXG=ToF31SXKU5tElnvUnAHg(TbptNX-URp9Al z>vEVCFhuQ&H1#vd)D`hhk=JK^(xvl9h}qr-f4hbe`HQHigxj4c=BnHn{uT99w-A#8 zw16k+$c#_-8UsAtBwWc-je(PqTR}L54{KNBWhiBur*GRx6&AsNy;~74cxZ`E-7ChE zSK2I2a9$P9dS~7<N{-qjckN7glCNL7*vgN<V*OBQuL<w*`^T>dDx`fzss-juV>q5O zci=|Pf_IUz?4dl8R6u&KP&b@4E{56~x-3KtoIjtk9)xATBT^VdTdw;s$DnPpq@l|3 zB}~}3O*h~f5YnfG+vH&|bjjQ>m%D{jo8)ikG}BqaDNWnl&ASjWqtp8v_qr!lUi#j} z)~#+$+9bWllu-Do+M5;t4lW7uW8DyQH+$vtt!OI*rPb_;nPGI&C2zI9f1V?9I(VB? z!1hsP4>^dbtajIKPWv-31d4#K&i6<6IKo$6NY(QBydCKCeUH=oza5NU5A*xHpXvV| zruYAz*!zF%g!_Np7k}z2{102@O6FxH2nYZ`2;~3QR*{hu7L`*L{lB(~uCl!SKL(Wk zGi4q}tI`-(Ufb@>5fp2}I2`3MMv^cOC`Xj+Ccm#<^z(nRLPBkOcXz=fu=T~fZGg9z z-X1<4@1GYB2h;2ewSj|h3mNFkor5uWw>^vlY+j_Qobdg?I5y_D#T5)klV0|^@N2@> zV$J@cM;b4KEQ~l}BAvi1wyb!vFoS}t{XmRF12@8^-dp&^P*yEM$%Ud=cW?(vv0&lY z6+P~)wF&T8>iP0z@Tvs7P61;=)<v40!ZWwziDN3b8+e;AJ-maXVQaa-F=OG2Ya@t9 z3Ol*jkN2<Jo5{VD2tJqN$QPT&K#!QildP`-duCCrId8cywm7V56>nz&>3MY4%g9j9 zK5oPw%dR5^i*G3}J3B1FREq+kVcMd}x23M-{>cWS;ZGaIC6;9!aMal-{+V0|(6RVB z>z&YI!jpZCDHHzjL|S&O?(}9;PP+bgKw7<81)wl@+P%CVZ9;e6$hy$Nx;5>e2<9Z7 z_zn+f-T2!a7eDyUai7$1r8<|i$~YpBp-J;ZCzLZ9k!PAP+JXGdv0yn0H0#_6(gq)J zei1ye#J|l7Jv4$;2v<bNJh6hul5LWrzaY>fCrZL(YeK}8X#zp)RD+1^F>5-c)I3e0 z6Ct~!4JcgXbEHX36d6lIn<g@Xjf$cFiEFtcopT~RYSlgK{0ok%BGfxGUV%;{O?HW$ zKhk6Rgi-m(vedAY8RhsiXgt#(8fL$gVFih?5w7sm+I6HnMI;TB#r3IO_u(??CF3`V z)&$Rx98#ur=s1Ql)em|XDrtNmrJ@p{G-+bqrASDQ1VZ`~HMA=1pACrkc@O1BcX~=Q zOs5o(KTe*wKfwQd!E?93yDfkK00zJS0QmpAF(@mlA}AuLBABWq8^6qe(EFu66Dyr8 zB<MX6i7KJcC`%2x@kEkIwl;>}L|*%NhuLnqD&eqiFp1aic{e*AhoNmU<EI?)Zxe{^ z16;MJ5U6Fm4fgWDJh@+e)dD80GQfV$6}UILfmZ-XDaK&IiXUzw2_U#Gm|)f2oZ@K% z(scgXxKYnN>#K1N+k9;&)XW!k`n$xff_A#lVc7%1)I<TE-5zLOi_5pq$z?E>k4)*M z2)juUB%ha!cko+pPzR<&3hwafJcx2%{iArhKkaflfbp_eZb|<_B={+eMtF3>IHV|m ze8PY{UI6-jjcGGY%L7kawyiKE7gNMBFt?Xvr0-vpF#firQgrv$6z)gNft`0^AG*** z{Y^m@QF7;FL~xqVqk$(NKgc>L3mIuo!Hrm^uoS1vHuo3)g3A`oJ%8@HEL8brFzN5t zU2oQS99kv3B`?dUf5}cYb>uu<Pb6(=o%8$;2p7<<8jMK{gYiC1_e(=Ein>C#^!YR7 zLfge-3U#aLIirxQ31OV2ObVHX{F76uFCUnBfGLSHJfDzB;lRRfi8{K}tm13}?8-)u zC%Oj93jY5D&R)=3r}7_gy#Hhi_kRbjBq}VgB;vX-Z5Jc}Ah6iG$D|Opo+65_GKL;J zVrY;OE4Uk41S)cWmCeF<5r)sv*?B@Mm88}qTR=^uxy(=0)D?5RQ}|Y%g%O0VIbmu{ zBipL$Pqi8ee?zC2om9mk5DvD4c7jhhQA8tUq~zACz_$4^`@A_;nzs@EGhGI&oqL^j zlCC|Ly+D~C@+;vEnr3Z%ro&bEjahUJmEH)6ptQo7Ws~l4cksuu-oE*xs16kU8S}|h z7%`lSEI*g-mbc$mlp5_WEKCbiU?Sn%5}aw7Ipfo5lL;q_p)pt7R=0QF08iD&CKgfZ zmsCn8uQR6ZrBNgfv-`4X)Hj&XGh;QIAoVWt(?DvKkSxT1rm$Nk=*xC1hJm8EbUMB; zP7ZKjW98qQd*vc=^@lGe-3|@xrTQ$%qI9L>$gO|TJ-O4MM`tsO*W}`@lHmkkAy?*c zp#&W;O8-A`43sZx=>Lbo?!UnK-*Ko*h>FTU&r8V8F2YLFQq9fGH!Cr$Fz-9b&q~uu z(M-}eDM?68($GcHgI6jpFf1^$Eix}1Lru-oFTT*M!BWsl%}&ZRDN#^T$(}$-%Csv{ zRIn_~PR~oP%Fa}WL}Cz&bo@WU(B|So1^Hh=;Qs~5|6Z7jy@S4ushg?I{~d1AG!inB zl!rk7Pbzf&-r{UV008ty0D%9S^8Z^t&^dVC_*%PTi^rY2|3t<0;w3SPCZfnr;z*jK ziqD<v#3whV&fGpc+_OxUtr$0DU)X6aZFj!4(+7C*cWsuWa4=)f*&!vWQlLPE0x1Ao zUZ{g#@o;C1Ob%Z5bx0=nmV3(wt6yC5Mc3O$73|&Mf$o)FybwXrC0l~~!R(GKQ%n|X zDwGVu-|2&2nV^{pLi8pPMU!6<%?3SP(L|*wD!D)uTo3(2V^?(OgDStL|CQ!`r<{7^ zkPY%H$7X39ME+e)Uc(0*^6i34JMc{?5p9?w20%O;<N<3b>b7j53gUn)yKria7&gHI zZFh7O9(Evzc=vZkxF~@rbcMK4zhBp}M-Krdl*!L7(ujqFv$MD7CN$iVY`zKxwa&!v z>GW}Zc>NjWGm!E1lR;C=1J`_h;+iw4Oa3Cz0Tfzx0J5MP+5&(;CNhk02^g|PLw9uA zfqQh(+YZwNQ806ytFTazE&xwn!v^RbBJptg<?HbIBY8jl{yF(#8+gAuS<UbJd!Ty1 z`sj8)v#+P4-v!_6ht~7`d)=C@p1#`~(ytGGYX8Ii&Yy1IYYT?3038-_uZDS$XAVFh zCN0(^_rMng1A0m!OsOxj<cTk5s6Y0?)e|3d{p6fN%7Amx7u{r<bL4dva6qFuG}Q?K z{kf5;YHoi!o=ko+z&jPi&H~!o5gYMM=l8+G8Q>3Vu#@c3qK5!s$uu!^i%0nm%s?a1 zA>^OHcREHadSr<nBI430%`XCmBq5pz!4!lyXU_3TxjRsoRM{@uEYCS;ZD+^xH|ycV z11}dW-U|e^zrF#CT&jUEU|d@k`gP48rg#2!7k`dQ_Qc8oogH?wZVC5kl}NS@Kp_YH z@k|GVBz_P2?QM7e7?uxaN4M|q{zUe1-x%)?f4tNC^RTzK?}9Kaox}Xc9~$lIl4xqV zrt&u#PBgUC4(JQJ9r;AQw2yS3>26VkbG=oe5%y6Y9w3VW0q2G`8#srvMTXym>+qS= zCz~uW*bBukI<b<@Phc6C3l|{QqN1r%!))~K^7v+<6;aDA+YIwZbE`ff4ROZPJ%=gs zeUB(U$O#^ajaVSIuDC{qz>rZOf}qpzBR~U`O_+e6tS*rzV?bV`-lG0XApnGb$VX)d zu>8BOkN+x&MT>@&19_Np%y<nf)&yxTk$@pk?a&L*NQvc41^6g{9LP+B2E#o_>YxRZ zZI(s`O90ToCjc!7L~mFwGdy~zhwX-j+Cht)5XWw4IGbGoj$Mw-AO{zCZc`83>jXPR z^owFyy=mPFsKe76NLh={%$Vx7aPD^R-z&x~V3O!&3oB#Ha>@E`)mt38iUv~-CGd_> z)cu{TrvD6UtO32M+IUG3f$4wGst;%n+<Al}Iclnhv4C~dACBb|g#HSmywnevqXDz2 z=8K+_2Ns+NMuGrSEi204FWnZ6Miya+8Bquvgf)~^jh78}EN;4th-2%%+>WAAqH|(F zXBW?;6=q#sYtj5b1FRNa8?FVAQ>&QqaDz-{)Q{EOg2=->VOj4WEmhtwbN*GTob6$u zmD2}@{&Cl2#jT0z&xlF7=29HP#c>^+L6xWk?r?0Eq~b#YDD?YLEm^hy1rr#OqZkT@ zyd5S(80*B7o5(DR3>&eAA>I?mFFr{;#b<8K2;!C)SXw}3YDfyypCR*YD()L#b3Co9 z&gO>~0Hz%i?E=HLP;NmM+Jh84&}AT4bebz_Ari1N&f=QnRS=sEZk0JA9is9WfS9~c zqCc6ojh0>I>pA&aDggb7W(h?m5BAw5xjl{V^BLS48iK<OJ+>F(`Mg}f%;*1P_WiRJ z{e}h2NllG{&-$8Edr~mi5$U|c{wA8jo+-FAIBLb#*99_2h9*;Ye&60)G(4`Wn7fav z@-eNCq8ZfOY`~%5|4V2wB*}pT@+DYLYRQ&2K4~+v6*H-1J$0mtc<VYNLKCI)EL`I3 z3ZcFTg@MpTJJ2#t$EQk0MLO@PP@@jbRle95NDjet!!zep789VVZeaq337E#5%Z?-K zdTi)C_RxGTM?tIR-`(!2(%>ksS+C4`9)2rs_A~Tm4ED!z-b7b%RD)1wwS(=;5|`z% ziYc6}43_cx<+;Et55;HF<J5No%m)sv#qIVuam_zjbe}xOEt@5iEzrU$Ks$%BuE+=$ zmNV{tB$}dw&OU3>n<JuGkK6Ef-X7=-9V^%uouM}DCk91d<Pc^ZcB6n8%sL&=agfBV zZKu4uF)!dVfOt#Zx5>2@@B7V2$~t5jSR4mYZ0dndzb*~S9HuDc$2w4H<!zS*_aOa| zLUKnyOn~12Tb3B-446-QyNTf$D4+2AY6TlI=7(@q{qLk2{2xJtpp#3`FE{od@zfHd z+kUl0{SLK_eJ$RrVQ`6!IzvC@5VV4Iod)w?QX^=kR*b9CiguK2N950}R|gh;IEcwD z7ZzMlZM#WMMvF-8zUIPPo$|~Yi9UV0A=)2tlSpkF{Hj+EdaR%e6mHtbl0@hZ3Ft=% z{p}EGgnZ~Krh!&ixSbZe7w)%y`=S*#^JB{et`K$Uz28Es65wgU9}od(Uj6_8C&%^0 z@H-Z++hUBR?=vHgqG1VQ$x!c5Dfg^;BdL;oNj@0sSNc;WhwMg_?D8m)j$?VPC(>gi zo72wFD$8|P;iP47K<mUahqLD?-<Uy}mfR2&t3|S6+Z{b9Ub{64jBNk&;A%l(Ut~kw zWOyzkwQk(asFa3c5BVE%7dN(_^_XYQF{oa8#Eq!d#R)uZR@y5w_wPtOt+sk<h#ebE z70vp6yrhXjvurUmIrq8&AUPW)V_^L|=bc9GYl3`UBXyX0)T>U-#j!t7Q29j$cL7RM zW%~qIv1gkWnOH#$@}2tmS(_h;nQaX=ptXav>I_~=D!k7y7Yc)|m5T54&OpsXX#M)a z4J(WHMfXVV9M?xmN&E5Yp#tc?hp0I5fJrdiVaCxHd<FlM*YML&tC3a4I$p?C1wVi9 z;C7Fyy~#?Os@x2p?I>n#Aq!}p)PdZ(W}2eH#a!}!GhyZp^D)YBe2qB>j4KpeW5{)4 zFEMCPwZgxgH)gEI+j2F34PL+@ZtDj{FG@d*!9<L@&q~BV;a3IVj`)^ivm;Hvdz-a^ z-a>m&uqIO%19qcxbqO=sckQ1F*~90Q6_@ogSMtKA$n#$v;`j!l71>}m)`RR5n6W<= z8^gdRm6weNqIhQ>gE37I;j;qjcbQIh%Pt{UHtF?s_D@sHC<ZuqR9%Md5fFogNupdo zClzR0;nx}8nYcSTyuYC=^PA5;H{SN0!g}33TlV`_ZkMgz`&R6Zo3LNcXSh#aLc06r z#7F!9l8Iv9?{UIk<A6Vpz&{K>8_+LvEcDJOWW~BW)f|u|d{j0U>72a+bPV3y^KCeE zXaz1a#;z0eH-8u-F1L^M{38YI9q!cA@c3HUv>(q(KI2QqQZT>X+d-P48_9GqNaun* zv3vi_B#)U^8%mG{(=o%e(6?)jq536NM0&v=(FgH#Ja47V@K9nPjMFa5l0i%wL#}^( zUs@4JfVHM9!s=o<HN?^r6ON=A@L#?0rx0AH>X~3caMF+<BB_8S$@S`rVAvg-L4P?5 z{yq(c+#A*OY8O#nPz1GI5}SMxP*9M(f<n$UO|jjwLT3ve{2#1uZXcXG#3cF;VPR8r zDF;lz)h76a&e?|vwpPl|o}xi(Hw_~o|5|W=+}Tm(+CLe3zLY2l8~A5^Exk)p34^Wp z`f-&&^vB#Osycuy4ryKeF06&Qj;)Hvsc+!-b#zI6v5u=nZ93szATUn=G*YF3XX7H& zr=l1-^Kg7%IKH#ljy0G;6{;O*04KlVEf6E%tArn-vO#f*(^@MJtQ*A(D=Ezp3@b69 zdnXps{$@}27$ps)S$R+sIyv6H*UTssn#v>guB>U=K*PKUftoGa^en$1{3Fa}apVBr zgMg2^rM_VMEgdapz#@Z_0WyNTDnHV@@)bYcbR_nLMvLRKvcmA}cm8TEH%K737Ig!Y ztB>57<6~mQVe{)b@eBfz?ZNYlzLb$b38=YECLju#!txzz$_Ghu{JLP9HRpI1M0p|w zadz$^g~4fq*%>n-^-K`P^cgW?JyRJRkWB8m=IjNYsO^YviH_TEJMymiZ2W`N#nyC{ z;RZ%(Q_%t*xJD-=x%U4JmMo4okadywAPR<UQ!;Se_7wbK_lzLOwp~~CcEBdHYhwJ@ zT0l6#!f0QK095&f*n}Gf4+sZ9Fx8v98nzc_9%v^#EN;0nh&Kq7VZf)9RKXZr&`7!! z-9|u$Z4nP{0OgG-%wQxBHbyJ^c%=#96=RU`MwY}HXr__q`d5(9L?B9lx{24GDS%Ui zGK>^M)@+UV&M_D#F3?#%NxlX@<$!NmBh)0K;+y{8&~CZw9l`KjD$|9yYC_o#5Z;fU zcp@n|lm&VRj!ck7Nk@=dJ|Uzr(z0(Owtw0Qa^GqCK}TD;in6<^Rzd;S>x@iC9xzMB zjP{&R#JA&MS6?*tg}m?tTxR5D8wX;<zJ@UqhicYALj}*B?mTvoZ{##)IttfJcn=-9 z7kc4$I2S`j1xR0U$;`aJX4Jw$M#KU^bwrWB5i)*z`>#+9_cSDSIy426Jo(}#re`!` zDdW_@#Z+H&XI}O#3!R5g8O+IPT*k*BS|QSCi=fWs6DE%;z<n;n=|hV^QS3EWvR>G} zV_$@Af+9Abv=V4RU^@QDK+DW^#^ay`GsESLoG^~iRD74t@8u|plsCI<ev=zO$3al; zXWm%s$VvdF6a{X*VnmB-#zgDp@jx%)RA~~+>NgcqHa3>s4gh8sRMC#n!x?qln#vCV zFzXKnF=@sH1M_t)_H8Nb%g|E_=(Z9<htvW+qgyQ<C_uDXk>{t3$$$`Tlc(EQlaL3! zBS||cO4eutHEx8tMYn9nz=!R}Yb;(U+O7SS0r35-qWE*|f05M4rlY+efLlh1a}tXT z1{Jfi?J$;3vTp%PHW^!kZX}JHn;VGMHw5$I*k|kmUdIWs>c(r8no&e~rzCW21eAe% z0MZJ#9q-6j^B7f?4}oI<X9R@F6w&2VF(=n@b;R#Uf(MOgot_s-48rj4M@&J&7HLl% z!wJzWQ&Iq);c>&Ep0q_bRI#{4`JC)6z(&%sYGT`&Y^IY$7H$gU7gp{3E{HO<tyjRi zqYhO|uO{Ieo`cQuJn9;x*z&UEky7QzKQUZPgu`aDSm$XZEP<>Hh3kR?pQ!Np=jOPz zqMTamp+Z+(_eHL{JXrso<JMd`wV+{ZL-A`zj|y8E7PL@GEfj0&=j8P_zfBAc_VCx3 zuCYqPa<^}1YK+fYVVVeJei8=BO!XpZ7ll(V1v@5lzf#+rd#%Z|^E}!(?2A8aIr)G3 z9Qt!ZxvN_p<b&TH5lRZ=@#G-K#b#6lQ4X#o6GKa|+%`BzZIIy%F+*i|MRHS>0496~ z32`iXYaK*KIqywTuin$aRPg&Nm1rGUqUk9y4ua1B!zt~4Va#kVWZ;%RiYji`#aHc@ zA-!)gF`PA{b?2A_<*UX$VE$48*5k%)N3+NvqnsKb(qTk^CQ-^Cc%;)SIwCbKpvcyx zhQG^nXhZR{E3%7}DnGF~Hlw=mm6i)sx%acM+Z<XYcBcSEwfA(`=|D0n1bhNvpEtmC zSwWglrZ2;^J}L1xTF8w^M`t^1zZrn!C|f^S-uwUV(#_jDBAT*U=$+!}{&1I~mu#WG z*(c~{5W_N)cI11{cLioTo6GM62`4GC!Oh?p#*8y>btSTSmC=NYLObu_VYnuj9N0z) zaJ9G4K+yhpb<JrQ(-#ARtug(UCsV{Rqt%dnrXdgv@%TbKoTj)kk-+>t?ZiX2#}|#t zCQ)rb1g<2I#qhmRrOZ^!+4OD52xttLq$f`!+3*q1G&#vTcUPZ=js}q5hHt4XQqDF6 z2C2I<J4D(6ATjqai!2HPX-k98uXhVc=n@yrDaoTJ@*r05qpASg=8Ar{v_Q-7t--(X z#Jf>?h%L`_Ep(?*c;#l`_$D$O%ml{hsR)(hk(-DA^nj1`^Tg-;81Xo_lEnSqMs1Fw zH+T3oE+3wp3Z7A>p59tQjIZ@R8Dn7<iYy@BmkgrU)cnM*@(QMq?-wGmliPEvYW)HC zPRWe#12%(Y35^*Nigl%;1R#lN2TEH@8_%gW{GC5W0w`^&l#uvghemBZ^1+=^C{Re# z6*@`u&cI1&<pYE7!f<n6wQ+dDR+NnAiyQ*ei&fmDj{iv(i(yy&eiS~{@J!aqhBH6m zV}y-GbJ1O$DF#U=oTVv+a#1n3pg)Q1?RUuTW7B8ho#<%0wxBXr6q}4bbkS+ii~t>W z)eY5XY(oR%NK=sb9GaqQ1SJ#^W<{etJm=3GZR$j41df=YHIB-c*1^CH?J~J5StSVW z0d`kxB5ZzzJ$D!n5jUot&p{NV6J5jKnr&IcNz@s2_#}AvgfQOP{M${PRaq)o(=ojY zpLxx<YCCt_aO{Fgy&<Cst6|k&^a#J`8o%D-@JWnSBwcAQ4HI$UHYx~FEEnq}my(xC zG*>df=SnShU{Z-a;Cx#-Fv}GpEl#PmyD=mYPn!;VX`1PMRWtjPQpdt`Cc+L4ZTu3+ z-*Y{2_f9Qn&3;3j<Bb1W<sTyBYupgb#U7f6i8?mojh>2+cVA@sks;*~VFBbCVr;^S zwlM)bd9=tAqFu8$@t~^Ym%dhH6w}r3i?i6Kx8`|fxplp!M1)u<$))`n1m(g(SZOoo zk)au@F{Tv`6K}B3!&eg<@;Q=KMn+9(%S>a8U96Y}=m46rSPfSb$JT}|SamS2Hnw;f zTCZBZP<gqI>nc97Yv;zo#lgdJVNFJiSei&6))Tz!pP}F!XD@IpOpX%R_q<NeOEnmr zX(jM;dkP4QYhZ^FnC8$t(+ON0YhgmVH#Q?pxD1YBQ^#knq6-l8eu@ZP*McJba-d95 zexX(Q7aBDuM2&0=Ms`ul#VaOX1%i#5SO{aZ4Lb$Xf0fVe!L|{xDwh|2O7!K!6Mq^g zbSwq&6(SlFB^b-tNt-N1yT%@+7%oK<SQcU(PJms!G*t6jAzhIceRfd^FYadGv(RQd zc1Qf;g8t0|`x}E;@WC}a(kX`aa7bQM5m&OMbB(x|9A7UD{PfIT1L~W~orQZ-8oe-g zJwda{b_dwew?HBKnf0Byvv<sE`Hv}HO#k=BLtUg1<NVmQoZ(;OOhnI~)23$8iZkL6 zyr_4T<EQJ`g=*|FJ@z=8&chRm=ol>;Em$bY6cJSYd=Z!!vfSD_%C+=hZ(Yaub9GGt z3!e$Q6KG4YSupAlD6Uza5$Nz$fE=qDe4}Fe4z_>;3cdjRH#$FYUMhN%3%|_jH6(4b z{t3&iB;=W-5RJBx7H5g)Y+Y}abS*CWA-Z-5INbo*A-5Dw^hTP<Rt84#ijH2Y<gZTM zS)UPY<!w@OZX~|ravs_BK#md86%7RWMc2Nmv?RnS6-fFz?b7KHnwj#U(oXl&AOl%s zdU%i<64XD&8Y9I0X!kFz8^s!u(A&Ha(BWo+C^-V5bNgYD)fN@eY7_~ms`7wOiW%b! zixdU3KN?t-B=;lvh3_2kwF7_u;J=-U>hVlN!uJO&>vX0V&2#<~`lBiZAy*4$ze(C& zpMLTkee%9p2<}_2W67e>wM*%84FGYZ8Gsg)IKk{2_wIVJ;N8W}^Qyl`*x$$4)qZM3 zWFsSBBN}XA?W?_4Yh$;2CyH+Fem~)UECZC2Ije(lNO!aj%PG|J7ZwojUOu1-i=9^O zyPGjKCUrCBJqq2o5hd5@3&N^XDmkpQP0u{XIjh)W;S`a(evd`OzrEEa_j}`u$5rR2 z%kZyWCjho3J%FmeWmz{7hDfvv+FXxYT#w07U)>VvTbHXs9k>2=NJD*|0W^rOx+wgJ z20v5DefipM>o1yHt%oSFsHE|)F~8k%VdUi#5wA4rpH{AYm*Y_kFpPQQ#G1+Yaj}8} zIztB=Pm}r?z-Y<`QIm6CK#;r&9frh)@JRzC1n&r9dan0q8Kk4;#>fNcQIrx}Y?sx$ z3k?{`XmV3E*mbFtNMpVIhyh-`<p@<qp%b9!fx$}O=(W-UfmO<y$II5LW?S@EG4Uw1 zq{b+|GJD?lY=VsM(`%Xr-Bl4Hz4}SG&Qc~>GmIvwFs91k+>|Ya@Ig08;x;e})x{ks z43HfX96GCo12NSywnkpOl6JRJ>)QQCD_siv(K83cc^>4|b<yg!0rYWNxiEY)81+=c zf+`jN2J7j=aT>!?2<T{A@l#5dipzAmCl7oC@mW0wr=mtkFbS{HJZ{)|UmE9L?)Y|= zzQ||;R5VbEmntC+nww`bj&t9gpU(otvHb6T)c7=;qkIQn3P2t2&w-ugwYsX#$eXS) zZQC>IL74#Wth0v@Ob&vz1x+dLNWG)Nw~Q$9Lv>r}ebf7_o&Yso+4w8Pr)x=}mJ7dL zS&6nDIKKHH{%IYR1=!L_;&j=~+}`p?3iQoUZ{OA5k?vWmVvc6__Qo359b7z@TwLYJ ze>|$IhqsNHf%I@x*`=Nb5N=u@bFolx<Ae=Ji!@nd(+-3NyeaFlAj8}7>v1!%9*2bi zcX69GHz(HQK(Wn9G=6_Kqt(;=`Tdyw-XA+Bt6y?C%0DzU2}*4!PN}r*&XL!x8Ce08 zh*LnbQ<sftPj<f@J=R7iojWcej<};k`!=ub>7^f)UIcbUvUPMP0`+l&o>~^D1EfG! z+11F;P?C14iXTfpwDlr3HPY{&miNLLCy8}}l#hySQLOxni#rH9s0jz5Qog5G<LYx} z|D3;e5^_D$<pJiw8PnJntFQAap<F`AEmugIPt<zKhF2icqUl%0Vb)IVRxd3EcFROb zeEp7NVbYV|y>jas_lb6;*@j1fV5s!WVEzU^>lAmBG?ieK1YgV|QaPklRp@q<bpB4W z+GUN?on<JA_lyiVbd%Hsm5p!3ptxBs+!uUzz5NJ2s0V=gq0F@+2#h28bG5+6>UlfG z4G0o(*v!_MI-Mtq(l1f;r6TM&4?mRy-VabYIRN~uf8J1Z2Pmmm4<p?ds|N2qG8oQm z#Os(c^Tflr#Uicj+cy$xD@yTSPrRv_cou8|<C&l!dM+AP)v_3Lr<6TT_8M7Sy5?%4 z&#6QKCy%x44wU%B3?{^`&JA1T9OK6z(JYNP!*F{MsA$RhV9^2@a<qR||0N6?CK~hp zx4hD8#Z0Wp6XopnhuYH~2Y>r{dfX^vMT_q`m<MHfB3(0>6=5|}{o&~{4()lTe}&b( zSfR<vLjGrSGKC@rRc8VB%W30Tr{p7^;P+ZFEHe(Q|62G#6g+9}x7|H{x2MVgNnb~f z4#PW`jPjzA;g@B}uj!CU9hsb+tgobfO$Vn!6Fo~_gWkQC2&lruTt9RDa7`MoXsDD- zipCX4ZPT22fCTnLMBky9V%Cg|T|ApbE_N)%hh7tVinXCb>rG)j*vIwaiMfqfW;kS| z9Cb<B4%YH7?~-}vZG8UYfu~WKL>EOCG}a5!C<jy*mN7K=wpwwIryY!5Q_;q&EmIRm z1lQ_|!F<g!rvcbb&O2Q76)llQ4|Z>$&K9Jq;z)3fl^znAk%+-MY|=xC35P3fB&|VS z)r;J3Bae9d#9i&ddwMX8{pnQcT(h&MK8nAUJ!<WJ1!{tR`p$8VMD1)dDshcSFJIk+ z_^M$=L>gTdhI~5GDn>!_J?mNBdLU7e3hh!a8_F_sQSZ{x#dT+{pg{318olk5S6LNk z1{=_JiJJ-A8#rRf!%Yc&50grrDj<*zF8nQ)V_nEK=c`Qmq(ZZyt*$?-;yj`S=GqhT z9=xI(Cg=ucNe{Cjij*hs6N01}P3{c8RCbO?H=CupplLka=H|A5f1$p;#99!KsX-&$ zwrlxt+5AHSE+en2b>bsxa%%IPQh8s(za3c0`pTAPM0NCX5b`oFDR;jK*;S(iQZ=Au zQNGApZD{qe8f0x;>6tE<xU;QJ{GV=VnQql(=4^+ZIW~rn?Y7`*b1IbSB%eYow>JrE z92CMY*b7H?+E<rd|CvH>mU+8ch76lvLj%pc*-e0aJY%1^_wwMufOQtfKceQ74l#UX z*QA{(%a-Ot6}<s0e_#1>C_1tq@V~g|K4nVK3-7uCody=jmx?lpoB}bPsk>S)t*JPK z<Jpd{qZNs2)@Xts76<F%!?$fnqcy&v>cdf@-ce_%6gDAG5-2Q7UkdTaNlHb)<bd~l z^ag4IURXLmz43ySC#QBV4uo(1sor5e|9c0#XRK}VirZuP3(NIsd_Sz7PLHph)qIsf zyelf8)PFQT;A;SMS+REY{u~~RJY0U3+bL_+qa?xsL4hyPhHVLMl=n+ul~fH{N$90g zc~TU3<Bws{fIRRUf^_)p?etw6)(lKcEvF{{!KC?3=KL$2Knbz!PJi8TPJW>A0UOX) zLy3|;Ubowl=VuyRv>J^5acsTui#9GZA+j@?#<bcVEF1L2$sw-yR$RO8YB70MaQE%p z_rW6a<teE$!Wjd&Zw;^&mA@REka60B{G*mZ>R84>kQ3UB&#UaFu4bfL4_BIjp?-m- zh6Bc#5B<7ezN2*ajn7>Dyrp5<x+78xZ1Pa06tEEaTsf0sdtubHZZsqaV~N+L@1wnJ z!ceO33pWJ?Um9NYFYDM18WYcizPDr}Lve^<slh$DN-J*7p>I?dw4E0kK}#gR;u(ga zPe#1?*e6gbVk#f1wf2c9;vRJtn&57CqOL$70d5Odm!Xh-vCcxOeUvkF!T$=fWQA*@ z@=69>0^xUzH%4IKv`(?b*89LtU&#*3@YM{~c@G7!5C*=9Bp;D(>xpzQLKHaiLBA^$ zJ^au8L|oezZ5uGS8-F4x77EqVnTlFEF=V!INK>(X42{)k&JpB>e<XD(&aRND80FI& zjM^H83Q=1$_<d};xpn+k?NUs#9Uq|#f2|Px6sY15S8%=CO%@()-g<zm;2`46)O)Ol zg?qc)>-D+gw<ZSajJ<sYcHQsMq#!<;V9bsJ>Sv7Dgjb~o7&9*(o^=*ejgidWc3EIh z4KAJCeDD&i6iSR?{Y*nYnpW(6g^1d^K}2%m5ofQPnenSG6VZjJrpV7cso->J_4Ram z;Y9vsGaHjxKnVfEKuw`L0~Y58l+I|KQ(y<4ffA*yN4qURR!`$&EO<B;@f$KeZU+l^ z4sauyrUZIviT1Fhiz-e`*fpYEq}&fWKt24mgZ%&;Nl*dS_jj(;1@BDnI>gQ!goE-5 z0KlHhUw;($%eC(+_AX#6u}S4uZr_l;aGT?X#XMa>3qG8BDU9?blbqC2L<F;@e=Y8L za`usOE>OJiMMZvxcNOEqazza~X{S(DrOdA3tr(BECe;ZN&l>g5-zAG(|3#wFAi@S( zB|JL=Cmd;xf-#iLMi&pG4<5jw9Mot^#)@XuE#%e9L#@<n<ad=Ho82xLM8SG`cx>z# z&h`E#{!37Oic6L^PGOA3eFF#DAP0cY?+Yp|`$HmY8h#F^7fi*IfF%6E|3ntrMlV`V zL&l4AKP(_kwZ|lTu<8|9q{hXb%822)oABTT-_`86#JDS<L8r<aNad*njIai#?F#iR zaTys;e67Ks_tf<8ajvYz{>tFsM1)rj`c2Wooh?sqK{S!ee}8H4-?+o?<KW`5+KjXJ z!L-f{q7+JPLky2nQ~;;LZw)=-Di`(qs@;J|cYf$g9*^C(^YE241*pkKe6DDU{@}?Q zn=oH?5pBF`IKHCX)wy_$MB|<-Y<cO_`q!ZFkV3xbNi+sm&cK)`!O*RO)r-wQ6>sX! z$kghnxeCs^HgS6>e{lKM&nd@D`5+@<r7r)Knn80*p64~pVhX;Tq`5q7v*y$5hb0)o z_UUgqGsiX9m=#-3hmGZbp4(v`)*j#XGzSrJ%ss(?IOI-vf^>p2^H&;Cu&PgxEs`ZM z<i7Hr+H9GQF~&Le{E!l(BZ6CPV0huHLP5B6+(%5+c~$YCWT{abU^wOL$d%!gpQ?r! zls`1BfzDaE%?09Q=y~NH_h`$bxPb!l4(?}}H4P!`D&YE=J3O}!V2wq|oxY0-xqpAz zcMX@S+z`B{6~CwGKFdh?B;X7C0)eZUGGjH_QZk&kt0HRpUXW!gs#U(Z<Zy_+xpFCI zhVmR=(;e{W+%mgkUao>Nw4zRD>5RtcU4vx*U1c9iJ-18!Fi_sJqQ)2Nwy;OP=7Krb z4rpv)t^ZiAu|X?2co6ya4kKyr>LXu#tbs|Dw{#V84(sjual_4ruwcMj%Hhd%+(k6L z$7g>41Ks&%`gi6kVJQENtB7F#6y!M@GzKV<pJ8;OdfW;s1sYzAArgpk7-p9KE|^4i z-ZMO%S%B$U$L-=Nj1zh}IM|pg67RBnSi(yH%2Q1o>^G2ss_P2lqb=I&02>P__i!mo zR6I-T!O~ZgUJ9Cr?~>~(n72<oj~;~DFtHh{60xeJ?uC}?A&9g$FGgro&5a|0CcAtU zvKwE2ih|}+r$6(rx@2c}UvmxA0yA}x<C=S!6J9MkfqL$7!1gd0H>p@#U~Lp=l<zxM zJ@*<{dMh0%g?OfVZfUF8;*#>1kzho03WAj~W?GypZez!ogdS>Vc;NwM|MecFx!S^d zhiC1!qtNip?q8^U{}rW6NxO5423${9`fdws$<B(7p>nw^rd&^b<xOG$9%XPmo)BnS z0BI}|RiEg?XFDP^S;l^F^UR}z28#Els~G^)ghA<U@wGAgbPDoCLz&5~ig(NySkMby zTfa?>IqA8;6mpu%HnLFCVC5|uJ-A&s%c2lSJHgz<p;@3N8taAmLrz9pgo78Y412us zkpgTn67jf&#yrO3#o?TCmbM0=4m-OnX}+n@RLR_dp6a$5&x5S@bd6I{0hRNrDZJ*; zkibxjj~jzY&J#sJvo$ejr7CXpSb(0<7Vo}Orw?il=<rvJxK?$RWF`x{d~fr3Q!Yje z)+;i+Rr4&x_dSB;P7D$wEV$bXA>M|7;hYC_*D#Z6oj_*hYvF(2O@Xx6)%0ovQJ)KL zPISa})Y%uGkvGk<yslP`0F1g3bF89TIVAEO?uxzF)}*(p$8@G`RNL!h?&$M}mGfFq zchgBhZ~5F&r;c;m`(2EA5v{y{tB%bjXR+p=(B30Q3ol0Uq1wJLS18hy$?2Xo<y0G0 zIsEWY9}~rNoj#5%vim%me95l`#9ErI4jx63ULACDGe)Ps|5JDmK!{xQ11BbE%~n-7 ztzG@cG5<7nW763ZUG%$qv2ELw7Ib&~BF`KjFX41R)0>l>P}E%x8hCr0TZCN>pOkws z`JBUrNagS4QGZ=somhR}zoV^cff2I(c5EW_`F_uro6#!=rd-h{a8X9MT74eH7-8}# z$FFzcvQaqGl3lbyUDL)eq<^R06lFMSF5V6$2M)p|2T?k>ZUqMwhUdd)ITAvO@<kAt z%>x0H8?L?^L(nxy8$2fWT4844XGC9I9FTDCFiJjDG01_#u@raro(=ivZyFx|iTJGr zG$|-AXF~?N!N^kpK5(^Ixu7@=(W_zq+oGN}TD_5^lhux9X|-AP$+_dTxL$1A!*$%@ zXg1Q)rse|n|0(3YgPO|r0FKj9K#`VE<1UJTlmG%E-9@^z1PDqG(ov9JB7#T>UFls2 z2nis?7)t1oE=cd4fOKT(MR@G)yytt&IPcs)&fK{(pPBpL`Qv<lIB(`yCTilk;ITu- z?L=$#xw$wV%_QS^m*;}OZwn#K3^2}?p_d!_;h1{(bc+wbG$;}Xdo5C7K(kFc=no2d z?GUMQWih#NIKVr0h~hI~WY+gSwc%aKlxC=_Z(J9MYBUvbSI{WtAaHH}1WKnr;J_v2 z3&gR`D^+=Ulh4_J5Mk=s$WKxwX2$u<nLgZ3Z$x!ZwoqU@BDqbh-B=412gLyYG$VYS z<mTXqRYksNXE?)FY}>x<$VUEcT%q5yBCWo!y^S|h^J|2QM9WEVYL28Rcr<lt5G*uU zBg6#xXFP{ql~3k}cE<n_HJe+F@$ou~*gWQA{<?+uw3?yk`)qx4`WzGeWVgH>gsVbU z>yBkH@Zb$q7)u;#V|;hq+pD*s#KzgkF}HVG#iIU4O>{QpNks)G1X*xr(Ije`dy=ib z_a)zn3hL~;Zu+J%8q5y2Q?S!umrok0JcLl?#{KDp?jj}1#~t}Gu#Y5exug%%Bqzrc z1mCB{u8VYOi=il8G(?+x8efd}x*AMW1YKrblhxqT2Gc>mZET{&ak><qYom^9M+q_E zcqXM{#&u2!-O=u4Ltz)M5)&z_!_09>+Hl);!UM8p*QMQ<T??y-OF7*PatzZFy&tWs zlVkJOfT3=#WaE}bd#eh0Xf!xMioV9Oj?UuyC-pZPg8P&P<M;Q68}wx-AIPnOOg>$` zA$0i4s=?iDPgVJd66R)vH^t1N89=|&2BEeZ#Od^yzi1FhX2^I`kb&XTNoviyEt#1i zv!+7L<e5(7!YSD3cMk0B8hNHZ*AocY0a(4Xq1K+U%;z3Hc=t<`it{jcZC#q1KqacL zi;{$LoZbf(su`hAyW5gh50Sg%IfLBkG*KxuHAF#W1?|#TDK>z!nrN5c?ESb6rmfp) z7}8zhWxQ?5n^P^@2-aIYaEgLhBX=%dq|0UCAAxU6Xv&0Cy?zum4Ei>OfU#}&BCj>r z=&0xzjlKGfQKrW5k+iYSjl*v8Hx{>YPIh0B^npB4;~jgFl>E}zff)KzeWlv(MzoOj z#k7WwNZV!K^02lRcIXU=3&zlI!k$nATtQ6q)MEs=SRVRl8#O6HpNfBbrT&Z|_Haa< z$XI0?F1NVNnAZ~|J!iIf+h0dZM80vx6g%x&?>wx^0khn<AYk?m?94+Z5&#Usk{LnP zB)3{*1)o1iD#Gq+)qa4NcYCRL)lXN4TVXEYoeg95w7-2BD#$S8lW2G^oYL#IxwER< zrw_@5cvBfO!AyLdb6-HYpXiXk=&#&iCZq6d3{{y&=^P-w>v$14u9=H@%y=)NkVGL{ zo(gycLX3`DB<}#|upC7YDam465)dQwlM5wepr56hZ=5$-;sy#_q-TYHfJ!AW8}{}T zaR*0_ndM2j+uoAu2Y`_s-7I?fY5bczm2$^lOVTA0sA3TMgEgu8)-#3V$&+|)!pAmE zYDhL<Qi4vL$WR_-J4ra@0(Ya0ud=tM*vF5d2b*UyJS}*kG=uFs;jR*~jPOkrudmeC z)mg;L=9J3$Wu((b)+GDys$7A(jTS4C6)jNKx(4uaC3vdmJbDrJe$LF2S0xE793N0> zq(l4J;uueyRP~>C!8oKX-3{9qC1Qt1-B*u3&rLPKZ%?{<a{V?$Cz$2u^;^vb?(1Y~ z2m)zom($<QJz#^faRmBSe}!mzKB-H@8Cd71zo>E!@jruU0YUyL?z7WIi8ckKJGV)= z%|E{Mc4ys@QI%P6x@t|ajL?puf#t7QpT@6%lc7;}Z?5&=aPb<&pj7lAM_B(3Bvj8v z$+Og9iV0gZiPDja#x04y0}+ILIiWGY@h);a9Zo3%ls}cz>2fUGI_`CEx~{Wu9dF{K zQ#L$VJiM^GH574n^s2h1NZa5nsk3ddZ&NwH{?THYkz!A-`o}sdy+<y=xm@A{&xh?$ z9aD_f!=1?8G|iEzw@)M(M=9HVW0cFMAs@VKV418t=6jy^q;DV|Z@+_OOl7qy@4Q3b zAhBIpi~wSguipj%SkSCUwiT<Q^j2bKUd8q6wfd>eF)olo5t$AwKbp3wwwq3#vvKw2 zsZW%!I9&+S47O6dISw&%e{*3LTpAV%_KmC!l@VINwm?p4nf1!TjQvib*`e{;*Kfon z+DSj<yR5~}U1Vu$$(xlW!FA1YM)9qV`AB${v%Wm5axz~qcH(LxfLi4l*WR-Bq+fAv z!`SCtN>WYyTc=L3BftT($BLDZ#!*ldK!~?DvTvq<Kk`$RRN_(u@hM~BlXZ*gh9}1W zvWD^N+%fHssjeYLW8idwm6k2rm;VS1{xZeXm3)VB(4CxyuUc*ZeY6maxN=m_>3U?P z`UOx}OQq73OzI|Oml82MWIlL&`tpn>QP>hR&9W?OYAYexR;otrpzOF2Cs4azH<^}1 z|Gw|{#d3DV2aaBke7X#c#<fNagiK0?VFJU`_TN~)N8^S3sL`K~vX`1rC0>FBVgodo zuxG{(#F7?X3fSYcPQ50_1OS_v3h(N|Z(0T6mS?;#o!`GM>P9-rE!78XFE*DBuXBMs z%speO!PT`%sz2tF2phen!<(Q+dvU}^s3_o`+C5()=h$o1sCAN{rU&=EH$#ImLEA*I zd8G2gy?wZ##GS)BJJG~6R^&YT^Pfreh(?IuSf98vTyQobe?ft?|4RJve$fcGfz`If zXdXPGl8y&irq!PKJJ5^(Y(@E>A$C?ycALXELu!L&8~CQ03b96z7!NwteizVIw6(P{ z#y46+v$DVp)ypYAq|mWirGKS@G}dfQIdIEeY->oPj*j}V|3C=Te>D|M2pvGM$-8y| z?`J)hFyA?9=HW57E3=8Sf)F{(aT-YHXY>USGCUUZ5D8iE1ViUqE6X1u=?hiSQ22ym zm_%^ziN^!kV*JWW<6VxYcI{W>?ZRz)IxRgMVe#KZF?hD8DfDhi)Evc+Gc?MWYP*;Y zU}#gg(=3-}5+AG4giU@Qk4L-%SI7K-FhA*OTCpjl)ANAGF-fg62jht(J}=og5*QSI zqjqA3&vidP`ySVNw%6OPGdkW`gW#XId0fr!yureA7#!{<C4N{8_~zm(on>C{8@jrt z^2y`NWfPV_<@EuwAN0DKq-4zGzaAiUo^kxWas&U`{{J|si{8a@@*j<aBsUOtKBnpy z-hXwJ7rl!e+fR?}{3m|l{kv+rh+S-?equC$Ut<3hQx~a=ea}xS1^7$q@7m|0bTP>J rDT%TEQu?1f=c0JA%lRq3_>XvA>F8=wQvLOb`uw3iuf`NK{(Acts%b!i literal 0 HcmV?d00001 diff --git a/venv/share/python-wheels/lockfile-0.12.2-py2.py3-none-any.whl b/venv/share/python-wheels/lockfile-0.12.2-py2.py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..66fb5fe9de50c4145a1a097f87a142400ae85858 GIT binary patch literal 17238 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 literal 0 HcmV?d00001 diff --git a/venv/share/python-wheels/msgpack-0.6.2-py2.py3-none-any.whl b/venv/share/python-wheels/msgpack-0.6.2-py2.py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..b853ffd764257d3c2b9605da08994f921307cced GIT binary patch literal 88193 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 K2*z4a0RI9Rx&<Tv literal 0 HcmV?d00001 diff --git a/venv/share/python-wheels/packaging-20.3-py2.py3-none-any.whl b/venv/share/python-wheels/packaging-20.3-py2.py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..904450446b9df9081bf92eef3f6b05ed07642990 GIT binary patch literal 37509 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 literal 0 HcmV?d00001 diff --git a/venv/share/python-wheels/pep517-0.8.2-py2.py3-none-any.whl b/venv/share/python-wheels/pep517-0.8.2-py2.py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..1e63a69c59332682cc4ad0b8a8e7b894315a8795 GIT binary patch literal 21951 zcmaI7Q<P>wx3!t5M5S$1+O}=mwr$(CZ9B8lw)v)Q+u3!-=<fe~r^o4wxY-wLuMvCC z6*Hb#Auk2`3k3)W2ofj*tW%z7-Y*Cp5eSGC4+x0x-&1=Ndlm*Z8hToGT1Hx93nyn9 z3tLk=Isp}BaXCdLT4#4>lMJpnA_>RQuTK<{ZA_-MFto6zA>T%PYsai^o=k^eW0gkA zPQ3BSYT`2Uvp+dx0`V05GlCb?hmh>z2!Cp_x512Oe1DxKouX?P&t@OSBPtA6PPu;` z;E(g^TwCX<<@wZ-`uW~Svdp(!pUa<FD|&V>#$;AgZk*Y)E|ol6Ix_lvTmcSkTHEuu zrO^QQ=hu#vkCfg|Z|Hh{C8Ql4%sO`1MWi9NO^cEnwtN%td-~pkxLzeuE3Oz_EIO=C z+u*AdI%oYCF=r6dEfcIks>mB5IS)QAMWiioDy@&MRYG-b+E&hK-7MVg8kjp~@D0%g zj2l7U=ZyC_ImXW`>72%74M{JorFGFWv{-FSyy4%xol8O|p90UbKkF*B7Gh5;9dqdh z%IY-~Pvmr7Icm0ME;-Iys3T^RmH1s7cr@F_Wwj4~#le}3q1)~}wI+$Msz__5X|2bq zR9UyqZ07*d8{3f!ou*@W(z;KzO<h8{_>I`O(GMl%+}?_!R1JtCVVA7W+cBBbv@tVr ztFD*ytVP_r;iXG0)kt4&VevT`rZ%0AlLVc&BfFc1OSYNnSRRqnrFo*|O}uDe0LQ{0 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 MTwh!0{Qc?w0FgceumAu6 literal 0 HcmV?d00001 diff --git a/venv/share/python-wheels/pip-20.1.1-py2.py3-none-any.whl b/venv/share/python-wheels/pip-20.1.1-py2.py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..4fbfb3da154999f6ed10a2ee353a137f38ba43f3 GIT binary patch literal 285469 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 M111<sAQvM359hj$ga7~l literal 0 HcmV?d00001 diff --git a/venv/share/python-wheels/pkg_resources-0.0.0-py2.py3-none-any.whl b/venv/share/python-wheels/pkg_resources-0.0.0-py2.py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..1c5c09198a2f1bc1a07d5747c99b0e1fa50895f1 GIT binary patch literal 122578 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 Hu7H05tAt4f literal 0 HcmV?d00001 diff --git a/venv/share/python-wheels/progress-1.5-py2.py3-none-any.whl b/venv/share/python-wheels/progress-1.5-py2.py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..b795d93ed9a248550e59b5aea5dafd5a102b88ee GIT binary patch literal 12812 zcmaKy1B~R)*06iWwr$(?%#LjvJ2rQW9ox2T+dH;x+cV$Z_syICy_?*xJHK?glX_B} zRGo9`IVCRz41xjx03ZOVpzZR+Gd=<6hyVZ^9soe}=T|!iTQdg}M@L#lI#xPk3r8nf z3ma2gdO;OsaXCdLIwv<LlT_|#VhM-gk9QQ4O-$zH5VVko0q;6|D~I$>-Zc9_W0g9p zcD&K?3X)>;6M{@~!5B(`Nue{EeFzS51cJ(pO;F=WZ;+GtV{{GUsf_&?M1{e!-)`@F z_@n$fmsZ(o**~kue7vtDS!WtAPvuXn6g@iUBGW3U)=sRO<_jNxI57QuyI9$`ZfeQq zkw#m&J-u`&yQlJcctO|mDI{xcWzn(4&L<19sh^Wvv*90u-_iH#$Mq}>Uv$CfVAWxB z+yq;q)H&%ri#!3JXdGh;P(@w~%DnsOoKMyWr_yxqQZ8KGtZnI(+{wz*qJg<(245SI z%d{5odCGK)lWF|8n8IaDUK{_!R#Y7^Nr%<U%=hb)uYF$l=w0w}>T6Y{%HsROV(WB@ zfwFof<pTx1XQrBsnRBMo2I`R6co}}j8XoPYadFjMn>ZM=F?92dht@bTRykSa1fA7L zxhmVniOuwi^x9_FY`f_Qp0w^mRegtW7JeNzZp2+-36Gbe7<Db8XvjI+<7Q;q1YP80 z^peXt16w}N_OGJ(#tNj5mynpuR8#Br`*Fhd>!Iy+!+D!Dbu9O=iK1+=l6pQg&=rTg z0Jog_fg{0YYNFZNNsImVYHfC7sikQ5nTJUivh+a&?b$Y~t_caI$7EIFq@c?W!ni!G zWSO+ep&+_+tgX=Wr@cbLcGi>9&OzFwn4LwsDk_JhVvH4A8msJ$NXYfU;`3Ql&AOZP z_Lt^jrCp7aCf4(Xv(luW?rV`JXNC%*a_hV+X&dcP=HbL%wj&YpvB(3Gi-fDPmot@c z+#8yOp6=iAmqR8FgXk*B3)Z4QIGqzu=0i8{+3uhFf+H<5)V+q0=~<&RNn2469c@po zbYBU#_RKmqw3xnPB@NwA1ChAm*V4&GmDukkT3iWJoOs!HeFX=|X+1SkvZUi&@o1yl zxVNyfFYP(33?iR8)}PZz=_&AZ!WJ#$Fl2S>?Z4K{h3Zr=>Q~OrBUyt8V-H%heB<eP zEeWxn?`F_|wMr|v>`i*X4zV{5RE)m^0j@SXmB<G;xS!an=T@f&2IB?8P%5d#qt=#I zI%{|Ik4N`W5|C|Q@xG9`ZUWHZGjEr(o>Ky%gxj3T*PP+`4m(zcCr$2#Y$6|Cb2if_ z`Mz>wg|5P<7vFugB+`c(Dt@5yb{{>&^%c-=rq+&+o#x!qcgYtISdng?NZfapXsx$f zS?lFKlci%m#*2J!)!Ya>$I1Z5b1F0kA@>Bp&i%APB`K61UB!|!L(ZzGT{&G~83^>l zrAnVzHd7m~j$@0|@j<ADH8_+0DR1_YdZtZN9`HHDYRNoC*({5VJLef4Tv}WCGS3hV zD#(wqUKE#eKg=HPN9*PF)mw88h9G?)_hQ@iK9L;O{LIB|53EiMwUCg_7Tdt>JQ%|# z5JgBhQ`*nDf;|?70VvUTW`n0b5_QDJgF_0;_u|J<fnQ9uv6fMaSjDy-4>NJM9zPHM zeR?9e?!LYpXIzjpZ$aX}op%PF2v1Pkzy`RDaM)?G&3lOAvkUf`HFuCGDBRSPTnSbP zmtm$*%xn(#qYu-|!-+ao4j}pzb%fP$kgw7?j=rq}YVRFZU|n%vwp-{rhQ4ypDp>Fh z^(_FgR30d7%WrnUXwtZC6?ckC99|DrXeZ;1GY_9vYPrh6ZB8~mf@T(H#&VX}2yp9K z*tq%D92X4kj`)*7-+}`RkAmFM>lu6O;F`L*k+YrMG~aTi*0zyI$Ayx8N}Ay(jmR?A z>u(t=${<qEez^+DOd8Q@3UBt)?2>srziulhLf*sQjlO%4Z!i2NA-*0;(<6Hx8{w*# zBTkh4%wzevxqQks{>(lGEE(T$xWYNQ#;dp}6w4=Fron{48-x%hp>x3{>Hu<Vlq4-h zvaO;Mv&y5D+J^R<%T}ps++jbXXCdHcrwMa-lutWAdF1l8+7+~gDD93pAt-3k(uy*H zN^X`~>8+CI6yC_FdMD2vK#+vEPnG;M7|wE9VNr=3Xk%c*;PQdEZoyu~kL%f2H14Ta z4i^@}FCOr*3%7KTZvn3v{Rnpb`8NZ>ABi<Iy92Y=&NT_=K^Et4=d|2<S{N(kH8ZUW z=uNfQh6?TaKA+|CTA<`o>X``bZVFd7-WJcfZGcBdWQQk(z7t=s>CEL4Xichb9rM)L zRCFF^x()t@x$G*jSe^5m(D;@lh6n1!K=jE&l}mkbHZl+I0WT%=+)5~Wuw5(yK^<bo zQeRditz(j9kF!;8WHWx`*3N~J?Y26YAyX<E=yYnyHo{!@Dr`#0cOk9QR4rLl>`kUB z^SY#{G%8h;r%aCq#}erT08dPCp+@!spk=j7i@a=~n?j-yx!8s#+Pr3=F8k;alyPEt zS_yCllA;cEY%aCZqTV0mD|CK>k%dzD44aXJ4<~CNPAm!=J)}GHC<Z|$TIH0jdQw>I z($M+?i6Bvzw3q0ZJwcX;R0@HmqwEFlz~5ZIj+oX3Q!?AA1Rv8|ip_<CzQ=btQD<}A zC)#=IrYujQA_Em3g$$rpUy_+2yG0R)R{`qDJbUj~<a{Kqzs|1UAC=8_4(i(CI%(It z7<djfk8Bd(p9?I{EGhFXb%qmZcpw(=8;1#7JUA%sZEBlu=Yt32Xf5aIX;xff;7eUH zb=8o&kMKov^|o=frb)AU=BmtV;(o1sSbFWRstADhU||0mYMj|9kJd><m%ps?biOK) zsj6DqMW#$7$+k!#r)y=Ckuoa~;Xd+y4e;<k==j=oJl|{xu&R=>#9naqpgnPfEiWZ{ z>AA8_m*_1}xL6GvCljbqU8<5y(D_Zo*8{9W7>~d}n4~t2^9pZm;k4^4x9q{tHv%t? z(PKq>LO-TaFs*MPp@C2wBVzYFDY0}MKU5tQS71C8BdLqk05(&tWU<*RBIqNC@>=4T zy)Icxq$Uu4HcKXwYva#3LRnqG0jK%^GQRM3bk%~E9w<Iv;5|c!Nr*g$s)NC?A0u|t zK>a161H72j^<5j}ihIypNRTXd0l+=o12SK4tzwDTq#=rJ_`urBs%)HVv#kUO^zM#V z?*5hv$SJi$$JAtW!j;ljiM)6s*_|Qav5F?Eh=&te!Z?Uk#Y54LOD#TuKkXd2VnAF^ zd1ACj7vX05aeHg(&E4A0m05<hKehntSIU(+@uV4<>6SD#BK+>i%mQf$te}cyZy%qe z>t5d9WuKr5QEgKK(&Slg;Hg7zPR~;z0hYF{?UCU2w#Z?iBGee$eBV?lUeU{%>HC6Y zn9FF@bEhSC*DzCQLse{JB)gfRX>ifZI0MbZu}{Hjgzjsy?>}Bu89Qr{=gB4cwuIfO z);zUUyMM%Az-m@^cy!eP#CI!_r77m)mFaZ2X?h%o)9-f)J-Mw$D>N~MyddSU`zq8a zviC`OJ?(lzmEVw9od!lUbv6+{jm&^H%ZiLt7cdckse}1vtD<~K=*0;J3J#*?v&=br z6u^ktfa(xzSN^6lO|G~taa>cG6_4^Dg6}(z4yImhQ65n+voq`?CyfSMk>cpkF3LII zGfvnvW!LtA_gEL<mwl07t)PTsGHQb1icM6gMvR+B8xUxmS7Mmx$ubB^o9FN{i{F|h z2$I2tJ*rOq;ALjnc5B#R=_8F^o!O|U!<Fgd>(H)#xZ`J4e2L;g5l>rT8q?~C5&(q$ zMqsZ`<c*t1EiBjv1{hMrYoI1#wZ&H7pXjiG8hO8B51*!jIh-i&Z3dS3Rv2D_$C>(W zm2mshOvpz&IB$Pd!&^9+0Yc8P%GNbd41%lJ<91x_!oEJAwgSXd&B7%SE~7wiD(d1i zrN`><>rLkIthAy<uoobEdB3SEoJ!)sghQWbUKr!G+e;U*404-te;bKS*y7ZQHSNMi z0L^j>If8Ru>OZ76kStq6(_+<2Z)0VfL2FK`{c)y@)x=9l!}D3f8$+L{<(Q3OT+~&t z#$5M^4?7EurM%779xXJq6w8x26)5QEEvGu6^}Mddp;WB>Ju0PGJ>l@IdS2VtfQosW zXFq4*W?6XRX$6-L(M{9*xaH(W@&3Dnmou8$CM-RbirV<G%e?J_EYlC>vd(hYkHv`O z!gcm(rv`Dhw6XeTk|}d!Q<N*G>o)uY_vM*yVj3Rh_j3AG412^NN+Sv>`b<`%(A9*$ zxCK?o!3*jpGYeoz3gf$)8JsIA1COqFzsZvG@i6lExGH0Gg2b>DJym=3m<aA-j#|jn z*YOD%VMQi(v|JBG&iWh21xk#iOQy)i<=!k!Z7B(ev>!*4wK)*uNw0!w+wRy0hJba~ zI2^VZoc!Ri^ms@L1fVPy41!IokG!iwhvSCuBKzB^Gpfl2oCRDjn%v7dl`5y*`{&i| z!77MnZCVZCqX;KN>4+zECJo;YYl~f(AoZaKm=E1M-20z(m<zg58MXeNgYFLb0@{o) zF|RGH%(=+Het=ELNg&$OrMgH@frDmpZ#+R|vB7aMn;CC$mfJ)3kn|kEl(}@SPdZjS zUoU_1lyWuT%dLJfEWC^y#e_B@m%hhyASjM-GT4_rA9QQ6x4q-ZoS1Ne#Q%La=G$o~ zTkN>!7Oe`uqVpm-xr-|E4Xm-`w<n?r14ouD&b)@Vg&MWPdyephuC(s4DcD=g7jzub zY@|aA&*P;hIm?CSxS|d<%vkS%j-UgaVJMUPcx-yh$f(Akq0EmFjTYL0{kfB%7#hy8 z1cgM?v@AAbTWKr@Ql787Hy`DvfCvO9zOjDh#F6XK&xN?WrUqO8y7>vTv=c%2V_<7! zjHElP*KW(8POwxXaTeBFm1Q}88)HaHCBJC$frXvt2hHH*OXPk<ENCZv3&~$&L5VJ1 zfn5nwNBazzpr%|55uj@@zNd=EX%(Cwy}3y$dqe!dA}&Bcx8Hkml31jgUd-q0FBP9* z>Y?#CN1%mpOm>Tiu5IbI{2ksEC+q4=xTH<%ucf_{1TyDIM|Y&1LLOS&t`jENPT}ya z;{!Zen3twLBo$V${WpHuTh{66{OD=?a!#78?C*X3KBkdZmhZI(;E*S?u(GbvsV?X^ zegrA@`4rS00M=)!eenrCSBsxJc)xsK%GPeRfN9qiBTPw^?o7-H6v)%GG0>%Bx!qcj zhoA>pO6K11d0bhNgp&`35Y>~dHdVXo>P+oOE%6?dqlABuUm-WuGdIWfz<ZF7?f7k9 zw8s8DNFgG@(DplToYlnl4^2h>*u{XIqR{@wy@%S`x$ye>rEH311iu&(7h>{42^Noh zkHDBqU^TCZvl2Y*bR7=U9EPw>k-Bas>8d>bG4krPSGr{WUt-pm0q@SiL_Q+Q${{uf z3Yp3m248s{<qgE7fClh5ZRz3hP9wnGMa-ED)etxt`40$(kbbRlycES$v*dLv$=p2n zx91<k({7rgW7i7N<fT?KBb;aX6P~Hpj1q%Z@ogI;?&M3SPS$b*uvi~dT8qM4{65i( zg7QhPp{jlv;~4hG%q_U#6X0!REL$kIBqflZ^VBs*wKGB122RtzdXDc8S$BfdpAjka z!!4G)m?O|uSdvg>`C>+_T*hng^a<&cLaeed7}}&Sn2TKk%Z;;_wd?6D;1tKLuBM!b zn9=Edj5=N8N>6`YMOH1WjatP$M-)(atJs?4eCwSR<j1-o=C1e1=9|}&_fM+W6f?zW zrHfx{e11Jf<h1iNqk!$AO7F81Q(kDVTp9OaVDJ+GUzq9+@34n2J&~;B^LpCR<9i>b z_j%eGKJVxEdOp(o+)eKOJh1h7*$DA@yUu^rlm8E`awh#S?+*k32!Z^6wTiTau&At( z=)bgzj*^`1Dg#RQkrI#nkHQFNUhDSM0TfHZC>*6BMv`DRD0`IjI`6km^y5_-A)%(N ztE+$k*y?=Vrf-+0o^D=l&#xypJLBxrm43Z&(<$h4t-TR=mmQ2fY#yX4obcViI96tt z`6Uc{qaL<8@QcEhV)Z^jd+HCpEQ~l}BCWvl)~t9kFuj5c-9U^)Jr}|zo@@B|P(K=k z;&Vl@uHbeQBf&zjOFCQ|D`ViX)UxG@;8h5C9ejs`Eb}zng@0d?#||muF5|7hbnx~L z1}|m;M+}9`EDj*<$!}z0-(Ekiuf%s!B6yt+BcH4o0o`KukFq`rY?+3!W;|s+SmUrJ zl{_8!CTG!E&LKlNdbtq0%{dR~&pahOY;3RuP|XMg1#5}MUluwS`^4*uhTJXZ7g!Xv zz)`28_@r_nKu6+hFSSC836FNwCXDz*6KUEsy3(7DIq3LY0cmz>=77RnX?60xGzndK zBI`g4>r^zqBAAi5<J;Y!wd1dIoP6LrM!izQ6>6W-D&dGg2E|Pg9Z>#O4?WU=(emT3 zj|9t*r&;2Tk<x#G^ZvyXN&Hza-$5ftg>XiM%o8cNFVQ3+`UwI(aG)qmwkSkgnk3-Q zPSuOp9I>cPO3hOjG!nQuScAevK1mwKM3FK}v|=nRSgR29C%6_X&^gA^qn2H>PCekL zC_p_k<K<}A(xeyI_#oXTj~EsY%t`i3no<srgGMv;qG5JR8kCS28R80$EuM$UQH0V! znV%opwC~QLo-)3ZXpZpo$s(m%1`T5<QGKAdp^`@XQ7R}BN|DB9or(lzh$AH5QA4Z1 zep!KhKklG>X-`h5hiR1r^1;da?gRMG6}<6eP51>007Sq80Qmo149bWq3yKIT3l^$b z+pe)8d`{~1=0aGZhprdd`uYM+;!I(aioUHoFBhl9QiO+#{2)0P5cYo0A~qS7oh};s z1rirEyti@Vet9f68?NnUf32cf93lH+a2ux+rdiZcYidyFSds0S+F?-NR28IC_#R+K zeF<xud9L!(SQGV=rIE*c0EkWUD&2`oheEGuNy7B>L{YO5fqm{Fj?#1Mb#^)7t0+PT zW4K!k_Mj~lSOZ$6utUqeBS)@okWQJbv7haz9@#|&QV&C`_&s`ji=O|>eN>ieCxa>> z@CM$av|^@lKC76LpK&!+(xx=SlHQrl@w00paXyt~P^mQ`(IUo=cEiSO_L+zK=n6Zq zeqfg6c~&m^#-4FS(_Pd)yiL`kmp)LpVFa1BU6W8%#x`VhEmN&y&3>?ae_@hZ_o`!e zVv>533C(T+cx-G)T~5lbDU*uZ!-2tNs{+e8+KkRJz%1^XVz-RUT+E8gS7{-9AW>4a zRVpDhZq{jKkJ)}4bT6Y=cRA?3pJ`UgSAF(f%hVfqra^7_aYk2los6GIm^LHXMKU~B zEih8_05YV};9M<l=^L1lo}>jS`m;~74F9gNDi-iF>f$`55x5uM@YoAaM`i*92qZ3v zSy>rD%Ew$^h9?QX0$VxT!4X$|Tnb5<pj+YP{?Jhc$_tfu9eu6%v*P00`_-a*R%n@j zT#~CdA9;vq7s>!fuHy)FVIuXOw3l4}H&e1?@TJ62o0wTLLqA0npo{t#0%&obo#6g} z62Us+SDa|yewZJ>tQw{)?OmOo4UsAV24U0_w9}Ns2*rZ3dzk#J>$x>IT1K`WjK9fH z2Hom5Nkid;d-S7r(L7L_*g+L@aHf7CYj4AU%RO9ocgyude(TQf0Bz{PC%Fh!5tiqN zdIlHdhsel*$ZBi4wF7{AMy3c4B(^~gM@5#6t@ov(utZnE!QH-@r3diiJ-t8d+#iIa zf0Kk0R4Y>l?I%!(T#bd?e_><rFW9I3UgVfh8br>bmXmlrba|I(kz1_+F3}Tt2x!tI zT6j@1tC3ylr;$TqVpjcp%P~;X;vv1v15~(yNv3FiP*+i}yn(~b<;H}M5mmR+Kea~# zNtmWI5%niomRg1jZGeI;42_ZRE^qe-A-WGhV)9|(?$Kg#V_ihfyiSk5lWeVF2i1$| z_EQ4?a!>#Gt>B7%{kAu8lj*o=bY4vd?8l?s{LmP29?RjrQ+i6PS;ij)XUJC_t2hn* z9b^2vlQ-Y+qwx3b_t7lDrL0D3J<)}+jU;Mqyvw!&4NF=b)}&sT=cVCat}4yW>_#Ux z`IMXn!T8tuK@X_7#H*RJJZG}R>Zi_Gj=RC?bgwc%-%0FhNalbj@^#NpcLP9)geQha zGUH1GTGJUcLWg!fg^WJ%=D`aaC)u;%xpKo|4e6-qpE16xHmK-J7$w3*avyU<Pl2-e zFM7lbPq}9Ur9lq`AWyHYJj)IbPO^GbjzDTe{!09{isVl_pC{VblbM_zj2E@1B8cBd zu$5Dq=u6UHeDMqBRyzdi3k1{%pF?;nUyO6;OYG#B0XFLK9cPSf1|E3|T;aPn1o#jc zeRwA?!4KOAV_64wtQ1lzGY-0n#WEhYlIaY#)F6`KX*Y<8_0w!9Gq79!DAT#l&yMay zhI2Ab_^EH;!pg(G9C<h8x^d(F{0s~(byRpPbksjBAzM{q5#oxJK2K>M;Mpt_7M;@Z z?d*c(6(sr@L%<{pzi*ibb|`rHCJsFm<4MJb54rqU+emXhyL=B#J8R8vY@wg@LZQcK zE(EHE42k>lcgo7t%bMcz=D_83S30q>WxKfid<L8JGi+)0oz6@<tBTCT|G<^Af#$=^ zZze^rxwS*23l5-|hU0-|F<gt_5gnrj!BKK)Y*UP8K9dZ+MDP2dj4XlKuJB$vwrmDi zshiwKI5Z_^EI>k}RuD*f7L=Gkf0C)6Qs6xKbCzamhb*x3#l*_2wVJS!MGqHG<yvoU zPL1mcza%F(3pg8R#WF`Fcig54A-=y$to`~ccPyObV{Ci_03d+@0NnqcI}}BQ<rGDn zr-$S6<N*RRKYgHA_iIu>B}5=!N319W6ovVj{Pp<jYu7ZMfs1W6Y|O(6v4^K9%Jf-9 zXS&v6Y9s8!KI4l=A5NQ5&h2VDZ3>+W-fc?C@2i4>lXL)#<@PVWNufj}QjGW;$WpsI zgRPUZ=U6ArdQNA?(&eFe9$<P?Dz&#l=ib$RMC+r-h+<6s^(ZfA1s5>I=L@s=cF4g8 zyRfGD#szq{k-H??asx#PGYVE9nDpPPX25v-5n(<pBXvM`d{ig0kVf~!u{Yd5&yOri z@W!+(wf&=>#|)01fPVK19gICs8P4EahFp|>RALqDfZjdEyPoGmR(v$b%3%q-A!LBJ zi?^)@<m&RWOy@KEsf0Pr#@nksNM$sqq})REBkXf)Dv7St?5nNjFL-saKTJjy<8ZWq zVZd{roD}&e%mibymdLy`2oQ`y1UuN4JFgs)ZXRY=jj1=%F|(qPPoiKm#I|S}o~)TB zhOO3c@!*}-6Wu0*ha;@NVQ(rVHD(WnO~j-%e<R0XnWb%ri-LktV{Q&@Nrm2E>Vgfz z=W_7XU)FN`(Oxo|RN;<mKi(nar)Ojs>w*TVpJ?8z-`u1(orN3CvKP^}f-rY6K(x+{ zIg$rS0`l?<{hu{OPw||(-k<eg^XI|&@9RQMTvSvVdP-boVg^=<mTL0%RJ|g@JoC1L z+=LXZB+V#&ouatpC=FdGJ$R|YG{ZDA+YIyUKGfJ0{mcW+A}j^1<ix0SogxJ#mCON@ zgmkkaMG4F7#Q2odg3Ryoz)%cgk(R#}?7*I6CG?*OLH>D2{`<t7Z0+={Ok7N?{#CG3 zQ;f;cOVZLE0{sOOvOt!y0s{bEkN|*xHCq3#rAn`-XJKREq^Cz`=iaEMWt%RJ;(ers z!wNq{=^QWlQ-gIwF=W6TcLc~r#hO$^-)agCn43B3!l&CTIGl0FVs_y+W}ErQ`{mFM zY_DUPu}vLndXKQ9y~PW>nZ+zTqaWQLd<K4Or{C!1)uJ}coGa{Z;roR&cYtS~YJy{$ z8G(bkqoF{=D~$R9Wai!%g%m-qHp6QT8pr@r;*A#_8zM2o6eiQTyj-oR=p>|7i8_$t z!Iu}UzAQw}KpewuO#o;(lOPf>R1*JeAV~>5(sPKweGEU6G79^Qacd5v0vtv8;O4?> z35EE8uPH)dX+l9@w6c2d0MJ$^WLH`iXcPQX*4toLQ`Ju5$=;QkKG#y%Xa*?qQh?<e zzMRb4B)B6NXu_>Dc?~VT%Fo6CNVmnxlia{?p%R<wRZKavr6$Mn{qy#>(nzt#+wIMq zFz#_|xfp%#rec?C8O-il;Nja3#4^Az=vnvy$hKTTT9RHiZOZE5Q7I^URY;oj5%%-b z;xbz?7}tfyUXK9m1GZ#@&T#W*MlRdFpXJ?TN1~0JWWy_Eep-s(Rh|mG(Vf|xz>wWu zt1E-^&l9%aUeGcrew0CsKF2k-IT=Bh?z5J2v2c;VYtAJ6Sa3W_9y{vIN^gq}LrEyk zs6N{sBOG_s-+-m39t&k$(Gnya5*6on)eB`4-BO|NMPBsXQv$h_PC7Yh2E^wMY4ij! zCYKB+#4&($P&tv8+oP2qBhER~AbF+?{kp0BIOLS_AUa|RzA7Z#(?t9s+K3)vz2wBH z@^0Nw4eHgtGv-=I9JGs}qC*-;BU?SCgFTnrHT9`PRc4s6ERL{|1p%~XXonnJghV>O zcaWA@82s9!%^zr~*0<yI;Gb@QWb@+4a_2jQ3*Bl?hWGjSy!^>E{T}+(cw`(Zq?sX> z5s*1yAqF~g7t+nh+dqb$hJ;d*7l+an)(1Ng=M`{24qcMXd_AMH-__4Kg{Gh9Gb7X& zu&<JL6F0ywMCd|+$?&^{gbop<&uxN3NL*C)KJa&K(`+HbJg3AFgnXc*vO6mVhMo5( z@QrydHGiVn2#b)Vad;RV+^DvQbfEv9M7-!vw-IDsx+qZLg5WcuCQ(Z7oT~merC@76 zfV;|LdRJHz<!F`UCt0~?G0FTV0mMkO0u^F4j9Vb9rhO->YpJe?Pz{wr<GlRY^42uS z+Y`kIRV@?e!J2N=q!ii$1X9X4jibg;6*8-Bc|i!wtpamtGuHwjj<l?3c1Xp@x&$}8 zvGZq^wlLnr9IM`Gzl$ra-8^HuOn||rCZPd`IEB>c!9@{#pCGxh7=kC0-ED+9?&@v} zNnEAFHu7eOTW6@w9-KtJf4s;|bA|G%@qOiF5PQhaN9M|0j>49296Zr?G&?3_)UB#* zWrRKMB|<{JG6M!(OwSPLA((Nr_=ed=jyrlk`N4Ue74Ks^_Uc9CKstiXW2lu%=Gc30 zIm^8QCy*|zM*vT#bQE+@%Yaf4Qj?yTHE=ovM?nmPz*5|VT-S6BTdyxbCgotzQAxce z_|`qq@b?xRJUL-#w`Y%qNjR`C<*rB0Ga!_<X<E(Zdr+XytnUxgb2Rp0T54&|sk%UL z2LSjkX6L7OMh@Pt$OYK^#4E6CJ(h42a#o5Zh9|6NiVx2TY9303T6ml3wQmkmxby<) zU?zy$YiJR5IsIn931Qu1ZMhxKgCr&SZNWeNx)}PrT@OBe6Ta4o<x+imQRg(>vt}$4 zg+DM_;nQx#Up6@Ewk*WM@P$L(q{N!?z{blTpR<Q*MG}bDbHrUk%zN!1dwz0@t6FQr zw(5p!^6LsO7PsmsSarXC=2;i0WqZYWr+Bv3SRE7z4caTXBoshey$MQ_o^JmjdtMkR z3vX@TOY~(uFQ4@bv$k{{FyTgN_fN2G!B!~<sk$u-51BCZnz{uQ-k&~$ZH+tDke@p6 zU+hk=y3t&;R0(Ec#bMpm>7DdI8=X}-!>>Yp1yC;kPDV#BzWV8$o4rc1UmU)<&U;jd zDW;0}8c!Q6XYuoej4&_$^;%83E`Pk3*F`ju`5tMHx3q*#vAYO$;$A9$<HI(6KFg_U zbeOV`wPXCX!-A51+weL5>|vmX76Ja$FFtLRBW>^&xb(iu`a-@qjb!vKg3*Rg(X&lP zSET`zZejR`FY)}Va%J{M6G8SDG~OrZf9Bxi-;FIrf2<VQpM3Y{X#Y=kGBj}bS7K6` zvfUFw={l-*TP>4R<jmEgGY6$!ACREsbg9X#QZ1))*t2Ka){D4kihb<)CWwxPKyVSZ zR|g)2!+G0%Prow};X^_wAV{S6#>9N}w#jb0>B;H4sQ`}_Dz|q)OmUm@gtukU2&W%Y zU@4Yd{->W!mx062<Hsno%rv^4vF-N+IkEjg{qoRnvOiPPEuJ@A2@E0!8E&35LlVs6 zM??$-Cb0x1f<Yy4HputPGLG3v;{fymHCjh9Qq3zyAdbOR5lc?1o@NYEWzhw+e!xcQ z00Hq$qymCC*;1W}eloOLU@VUM6dC`e1Lq6znl7H&UnKmM%|31p6cI>dz9Ci<w~+D% zV;ZA_VP9ObuB#=<v&hdVa-F=a((kfozG?Cymn{&yEZ_`0Crx;#U~-*#JUI6f21X^D zBL@qNU`$m;Z3(BqBd^^|-_mG7EHH?mz_Mh*j}iOyP<{J;bbgvqJOJD>5CwSxFJmXz zqYS(4O&J9Lq^gut7N4@GL4bQn8a;zqwm$bv8CY0N4i;7{DN?%Z1tp`DZCXWGaHfgP z4%N7%i_lO%HR^E&W@Q>Y_*4Yf5wpoRNy@vNdBK?`;>X@bM(WNjcZ8KCQ1F4>3WFmH zOl}($xY4J4O+JCFusfStWt#SM&jM}yo00yKYAciyHukGJGdNa=X5Ut$l~V>Mslc~| zMO?hOv{ojGBmz-1rT7e@8y@r$5%Xy)={^zEj{J*|<7UloQbZ|J0Yvl|sZ)Mp7JUvB zhG9CwhlCT5cYPHLRPc4qs{XHuR|%w2Vod9{v_kab+w(@5KkDB~K%ZNS_*9?4uP;N@ zO+^u=v9+7wxmg}ZWtM!7YLMN{*ZOv5jqVa+XCbrL+hOlHM|6-1Up(;SX-qGv*~<?E z+esJsAalfj(vxRK1PW4?-;#XtklZMW7ueHjzbf7#{u0&PC>|QEVYLFDT|2Z|h=G9Y zAT8}EKgd;I)O8yl6JFmn53!LFIB1Ox%%`<z^vvYg(W`P13Sl`sUA_1mhK%H%k_-wP zV2RGNiw%pYx2KRuOtX0+o}y2~87p9<sbjdj-ri{Y1x6iBYj1UD*w=mA%LWZjzUDvR zzQoV7uEp~9!_;<kedDu1hsCwpX00&>(IyY>Xb#BCb?CrKoZ95#y7SdN`RXG387zUe z&-1qP(>dhoAv{<v8a+ZJ1%iHk5*601`EhP~{05!;)U0**HsWi*X?2Ok#`a#I?UpHy z(7Ct=g;G9eKe@2edi;sVK<tqa1n|)nf2d{A6?<67q9=8i$U<MRGw?N?ZjTEVuHjO+ zesXECbwRd%vKGulA%f(d&c1y4>CX$O|3wEGKmzd7+Ey}Ilb~p28?giYqR>H6*vuJk zE$YK9z20yTTqs%narh%byway!a<`!3i_ffJ#H=#}U7IOd(~}lzsHVk*C#ZFsl+5uO zBTCe7`?zJ;t50x?Q?*R$X<#qOzHQ^nQ9n_zZ1iC%;D=e>NBJmgA-hP!u8UccN#_iQ zt1TaL=JlbYMOVzBl)+}wA-aWk{Na-e^00>c=PRH67}$qy8h*h`twkUIUj?_@cB|jb zAK9+`M^_^Mdq^{~b+&Ob`BzxWRGzR|<3Q*-qXe5Ebjih#krSOk8y{(q5lGTjlvSWX z3pP|>L)1bMr&_^j{t|!}_1n03dysIUSh25bKhEWPM&`WxfU$mskj2aDQA97(<P921 zB$s=aMZgg(IK$3YwFK`p!N=q0`UzuHI3cOUk*q#KpBQAOwsA&ZZe7I|P`KFz5f#G| zZ(3fV(gswVTgxO8|4J4}tC{%AT}2?bg84Mh9%&tGu!3&G*@h%xRlgthbUw1QG10Da z9m{Sh-v%c^5r}DVb|f5IJ+;H34kDNBRT8yMpmTjEB=B8GPXa}AQ&!2MIH?YHx@|F} z<V{g$eBHN<V9Sa}NrKyac#I51glkL}QPvMK<>o#E_5=YB!S4)QAkJV-<Zy-LfWeq3 z3^E;xz#e8~mt+(JmEs}H1bN#@nuAG^BzIkqD|GiIhIB7!xTroQchnF51cJ0E;XCp= zff<eI%GsjVKwTgdqX4A1V$KoEsDO0G?@Vno6hpB|L#X_Od?X3ofRveEu^a=_8Dbj0 zpx)SxMJ$Mp$2rRk;9*7+B7VYbD!NMXF9aGBiK<1_hq`CHV2bf%3S~gyV;}nGfsXzn z-+M98M<j|i<hfLe9{>+yN+RpRk7Snh3JZ)fVk?pm;bpact4}c6(>{kFM3@YGl0MRK z6}O-cqk_C(SqpeF^OIPGN!TNlmMG_L`x1rm&tdU^4i{Z%85$V`nr~Vh5>%q>V0EZf zkWKS4YVYdp`dy}|q7G$XdOs#^89<<J<6wEC%ld4@+WAxJ%L4F>QWsc6=RoeMYBRP` z<@4@fXPr>ZF{cV%Mzw$S@%eK`NKdV^b4zX%D|D%)@5`Tiw(nqk+-H38Y+Vw1D%TZe zm=MS3>n$2?)9Jb?z!kUSYFii_pZnP<0*^mRePh+ic!BiX<+Yg>DqKtD;jxn34r_P9 zx&2b-hg-|i>C@K}0B*LsYzwY_D&f5G?#uQ3YKyPg(d(@~pc?mmp%)$J68}GwKK-9y z1@%Y982`OP9PKP@Z2o75M8;1<t+Am5J$ZzM!$3ttN3WTpg2*UDNw0wzj}o3h`jarQ zpqU^iiu%QwG6`f8n#YMIiSB`q6!8npHC)A!pOBhNNw--vY$J|(c6o}Af493mfUJ-% z8h`j{p8md{r3L9v3?bue^58Mob5jQI+WmP*C*4qMsnnm^7kLk^)8CA~arSg(T^7DG zX4MTHHO-^uQhuhHj)VnlT?w{a(1z86rgczakt$epHgtN|q%duTpqk#%DqZQnu1?b; zB)hOWHV;MTT>nkm`Nt}lLm>bc+hpMdwZdAHjS5@9WFlx%Ik=;tS5VNyh7QGFb*Y$A zCSPp~{930xy(FZvOtBPHM@SQ8vQ&llemG7EiU@Q3d!Uj&&>;_}5iyrPx5)N8T#Va( z_=u1!G8{2k->;ff0FtOLovh(#iNHKDS#i%vpq&$mxzIW+7hL|}uR-K1qk8v&n$bx7 zI7TAVgb*cdf?^uO+ge*bQ>G#z7{qV(K=%<tNCWc*HV0gV2#gL`3K--#5+vR*hO)w9 zdEbH$SrULra5kqA$!c@p(Z&0*Fk&%NTQJtOo|Ih6C}W9wt8k{s&|;m;Fz$@O6o|B~ z)FHxXf00Z^JcalT0)C?G*(awB(8*J1Ahml~(Qw*R8ghj$2M!TBFAgk?2O8}Nox=hX zWI!%4Ym8jRA;F7EN^=)=ySbvL44CEM&>M*HxW1pjGs5_<r_s_RyRS8<(kACLC)UC? z6b|`BYNE9%u+g4Y*|;s6np8=xL;35g6gb1?&6<>+-x%ck@B_TcWHigM@Otd83fO%& z=ZbCKXJGXnUb~C~@b4WKR<ZcMzzM9w<(sogaaO6Mu${HbiMD_@@@pq)VVzS;kFG&c z%I;bFt8~8FX6bb`JI&6YvX9L^&bA#Z;Z~krw~pmJ@VDM~kbJ!EJjuJAZ!ND@SWQi( zUobP0Gw)Q$`JHcH(a2{H%=X=Hie0<hwnp_by`GI9Khd14vdeeBYTLUzotH9Qo~q)r zJKt}klbbWo+a}xLm-qj4a=!tg0RQ(Z@_#bS|GWzP{`K*HcIUrenE#vicW?NAX#hZh zpW2^``2U6XZ=K@5d4G56{^4Q%`4j(z_kVr6zhQr?+kapxSpOCFzasZ<)Ze!6AC&bU z`S)Mu^*`?KZ_?j-?jI7^AHDovNdF=0{wDtI=>8!p{TuP$josgbzt2(s5N?S7nG^m0 zo~r&H{CCCj&)@-ye;fQy{qi^9?|}Xf;E?*?0RMz{c`498N)iBo`tx4+Q!5eD|LfcT E1FM$f;Q#;t literal 0 HcmV?d00001 diff --git a/venv/share/python-wheels/pyparsing-2.4.7-py2.py3-none-any.whl b/venv/share/python-wheels/pyparsing-2.4.7-py2.py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..375b386e2f819afef1ef45723008fb08015a929b GIT binary patch literal 72474 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 literal 0 HcmV?d00001 diff --git a/venv/share/python-wheels/requests-2.23.0-py2.py3-none-any.whl b/venv/share/python-wheels/requests-2.23.0-py2.py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..1d646c91dce75e74ac36152467fb32bc5194f347 GIT binary patch literal 63192 zcmag_Q;;}56D<IaZQHhO+qP}nwr$(CZQJ(DZ_NGQt=fn0KHPoiN>v_`u2koo?vsv! zG%yGX00004KqhFn0`a1MFghXt02>|v0O^0TPNt5orp_+Tv`lnN%ybNNCYH`Fw3c>e z_Vj|PDiZQa%5*LsE~c5>@x+o&<3HahrhAyo8{uf-FC%_U_%=@2y}VhDAttI#RNZ)! z(={aJ7MBFM<bny50&_ywG$#-o5(osfIeVZcbABL~$rtFFCi6Kb35bfLRWlyn$M}={ zx_37D>iNEPWd45lQml)ucUKCRHcDQ-%duHCRNI%fZ7Zd(R!&U5U$>hlwrw5xJThpT zPgi$NRnJsDFCXao{-tD{oh-Wc*u`X_cFoID+jjg@@P`II!?@n1(Q9rPJ*>KH&U;|% zl)9IL*Rhx2v#nEX!D`6cp}GHjU5m+D;Z)n6-KvG_+jXp6(tBBXIy5o&&EXqk3YoTp zf3KLHaB@vv*D|<F$QzU2*vjf-=IF56nfW4q`MOtx&%Xs<=l`};>nz1z);bq53{^C0 zDPJh)y>r#=%w2O`c2UR7r>pRLw()59Ov>y2bxD9Rn?ScedTCD+V^x#Y&eGXTRI9P= zUfL~e%53jNEp?ks;K}H{)HU}A=ixVD<Hr0et>E!d5~FTJ6b-*&d)<r8nx%`Ki(hxU zVPGrfIfy7*X{|x}`3O(Q%`~&^ex4@mei%F0F<P<9(!lbJnk~y0t7zs!1Ko5g3ic>y z9yu3mrzTozoU=UXuGe8VkzSAYTzr{xBg-B|&{^uT>6?{gdQDd&P7A&JAxtXLPM6K9 z9Sfz)#@dg}emgED>}I{J>>Z^|OE_GktD|yCE63Qhr?JW3jfLD9Ex%bp)oOao?*3>m zS3c6bY-7Dyy{=62_1uoVyf#u4mEYmr%-Zdavxp}4v7d-hNJJiyS|i+&yIZV<<KERO z_4X9U-w2;Q3#F?iFWHU*;dD*CT#4L!W_x}g3X8SO(eN2Zre}@QBJD&$bhf{;(fcIa zKQ`~#)n@ujlrr+X3PIvZ-p(eQRAzsc>~JT{aN%V?3J@G2r}fs%$dgHO$D@t!;@-!~ zzjNfUF^qld*?G?*rKiBtjasvm$B@%&cKqA65NcAzXx_ZOiDeBXOg!z(3rMEtwI;-R z|F?(+tX)~d<!Cwxc80xss%jz*1aQCCt4uz^!TrWozr3|DGMX$Hg;Gl`5x2d*+1q$% za4~s;l7ejiiT8)h^%#r}pZm0t_nr|PC*0*yz3mFmch<8xK4<!G%r5rjvtTcKj_<EP zPUt>*VeLCWTQYmBrN#=CxBvVlX{dyDFSBua>Z;(0zE7ci#D;Y5Qu4XCLVKs%##X=Z zoh%#kHCaTwQ)@Ts1}g^~&!yA?gxnhdcG=ekm84W=atlk|967J1ar0`GWh5jJmnwU9 z!(4s3K8Y<>*B_xC*6>=!SHb)v^IC_dI{0^t)tY&VvRw`vciB5Wtg^B8V}&6eRFEHI zr!1-9d7M2ukk-fNZ?NG83_<2p{=>fSdp13){hf>35m<v5YBeRFEwP2$bu@ubAdZl5 zv2vJm6MHHO1E9jdl?|TyT+|sG4-P4$*oPlS6@D$#&Q?}AW((VXI?B}3cKRl4=IT;# z$8%>R$)qH0#gZiGpy(Pr6`r86g$>{-#_6!lzUU>6&mqib$-+spq;yY9YBNkRT9%nY zDYrd3kUmPk2q*4JC79?})EQRONuf^nBL1lfsC#f+k#*B^!(p}W0{Y%byJR&WGN1&+ zT4kiPtGL|_qfPUvQ^F-Kb$lmGv73xH$s&41x#PY7w>{nD9GY2z8Ov32H`t?Zb@vgl zJt+*_6VaE!z>)(CkAmFU=N)_M^ntp)m9v}Otk`<9(Y}>P*Nu{WUWUP!Mq~r)b4J#N zGL#f_SiXibmqxUn!jJtbzhVV1u;0dokoRn+HQ+e*>x17kJitqNVdB_pH(Kp(!i92} zd8)XukWZx{h}qweB?l0PE1IKkx{ixNsd~<B0ZbUYMF?RIx)5Bl2|%8WlBA<du2Xb& zNoBHD$H;MS!zNRmJIXhH2?Bm;fv|u_<*EmiN4{vkTTw@d(&2&=f`S$;t1K6&;&Hu` z-X?un@r#UVaPGzl1WAbdN;y!I;kuv`7L~|}HUTyYt{8~x3G7qiqM3bD^O<_{Y;`sI z_5~libYB<w3E(ql7{Ot<_;DocC$)j*Xk_WZwISsu)bi%*hL&4j8)LJ&VX;#Yy{!@3 zNU__%|F>E}8<bpHBNw6DL-GF6&+@&n3*glm+38Jj=rX`(A$Ow!T8j#>XN5YSiq7j= zuO-N+kX<zqt9NA&8sD14=v1Q|h(3L+c6}(xPWI(H_@jcJTN&jTwvR<1v`5TD`p<@> zb4se}b*b))Y%!4B*0ofs+g=wld|p)(olZU7PMGUil}$PQUwG#NRYx8bdz+c+iXJH{ zjcOg`71OKXg=97XfHx+%P%C>0(1!Y*Wl_HWV=2*ud}2!*ZBe^WpJV(4$~3V8tt2=D zNm-8uHkW#3*`O8qCS9OlY^gLp!(J@m%jGtR3yb3J0O{chiead!b~R<EzBCrQ479;W zDoETN?HxMiK&Uk$m10QcBzuV`FrfS2In$0{Ms63C;A?hAxrK13cygZ$bw1Z~s)L_i z#>N~fGEnJx_y}tK9ho_@M;vi<9Y8ag_u%uUyuakb-}OEGtBS?pX;W8HFYQhr1J9Y( zxn1h_dx`b6HD$52?szH<55y{d>o{SD7YD_&U1R&xO4x`zt@R2$&8Axde5G5io;q^> zIlgG2{sFG`0%_jBa-Bs(QpDzuwa>|xssQ)^26n_)>*8*8ylyJG!d;!W>wSf6UETT- zGG!`BzGVhET_>BYw0VgL_qpF^uvgG&&)<>r&0b5eO`Wtg_Nu!V?WHqpbtTcqz`bp@ z<Y0;7?N-z@nLvZudYx2??hFy%0I)7$G6Dl(n))=(C%mnt%aN=6h8M%o1iS>sfDP>> z{gh_Of`O%^CPI0Fh{OAw<oZSOSbb<xiOE=klpa<K*kZl1<=&u(puZr>XGLKCj#ML& zx<K^x5}8P$T@dF4Wql0?oZ1V>^y=67eFs{0h{Q^X-y$6*A@VY+E(XU*g4kmV^`D3? z@LF1*xDLoY_o#)CAX(um0QbTG$V#)Vsx@MprYN@23+o`Oib<i}figgdUw^VnKVT+6 zL8SvarWT_MuC#$_?Cl%L(INqlO*~mmGMvyl#%ZD&9*RLyX89%jRqx0>1L97`8>1t- z2se|})03GWcV{<OZWY$a)GBOXC0Fk3n^tVDN80>^@V7HF3#1XSq8gH;V{)3FXZ3KO zV~QF?y<G)Jn|HOLw=TT}Jx`4!Sk{4#SBl5i8i%2(P-|lQb6c%M%^+)Tzz331A*0Q} zKW(vpEsM2wRONQYa(g*ihPUmEi_lCQClsv4=mDlDLDO}$iA$D6-ds{&>)5^O?eqJM zC+GYntmaK;=l4B8d`}{IT4Me_xh`jWW*12~!-03ua|i0QLbLP8tI|$KpF+JN$G?;h z3+|Ux#Vx7zSztu-*R#nB$P8#ptjI`B!Lz}bx|si6Rg^zT{UpH<!BNy=mStD35*RT% zP+fw9+8HXd^qQv%=WW#`i8wDJ_@SHlFzT%il?g?22csc!(s-~<X^tM9vVxmqlaxI( zb{#KxuN@J7xerO!8cH}O<2D$s#8kz4#H1Cp5rNhfWro>-Jj2ke6%HTs<ozXrP+45q z^ZLvmUS^g9kCt7QA=3D*#od}FT-hPM9-aD^fBdXUA8|Y=5?Px}Q`$Xo0sxUS2<*+N zyh*c}r6ni807ewany9H*U5WM2m%41A#(tmJ<5!trPM1o@dm$A8HAZ*fNoE2272H8I zvkLJ}t_Oeh@Rly-0O2=SRXds}hGBK=Nr&zZQGdU0`@v#r=Fw6JcX6PPHBCucGE+_X z&891OHrnwb*sG9(ynq^tS5kN|(a@J#w<dVqjxuE|qugfPfD?%+`<%LoW_{QQpm`qQ z=Wwp;!)Nq{QdQe%+N}E7U94=2Xzgi@R@W+6ZM>8;JiisZ3G}Jj&iNQ7Wql>v%uTQO zuuITbDhF)c@j_$ki9EUUA%cN^@@li%?>pKY%H=xZaT(<rDQDO9D>?y&RLloFCk3mI z8^W`1o49<49$FR`9hX++C*P7ju4w9eu=G@_>eCl)EA}sPOjgWQz16TkYcc7iJM0TC zEfQ>5Q_bxp^A^ZvDEBT8UHGS-8;gKqnqJk<@&<Jb$HXAY6N(uIOg59y^@I`Jf@<X8 zB~5d=C9ou=$$jk%uC<gQ=l8sTa^!qGj6DACDj2;W32bF=^<D#}f=8H>ma@%Fd_u-p zv8g>B4`Z=QK_*Edl2h4I8FER5kL&aM$^s(Y7x83WPQ-XJTVOi&hmIlPVEqkFXB~!@ zRy@{TFKHnFC~GC7U<(=(-)hj&xZ%9WK@J*>>hi(Y!4GSu&+;ynDp}7#MNP-BiV}Hy zHe>iG!YOgO5-GiD<Im$dV)v#<L+HU4W6w^{LDxMNf*w@HoioeO{o#K=doiXKjg_?p zw*}ZQuqg#8M8|qmx7itR&`h4Km#8duIBw>P(;cqz$LL;C-V>OzcdpH87fLrf)o<R? z?uLAY^&dv1cd?V0(8lC4&v;G*<uNXXCvrEV9vzPM|9Em|XI&uiXZ}qE^cu;PJ0E+* ztHE#Ten`z7p~?b+wN}h{BbqXB<jLWzX!=>IQ#*YZ2;b_-=v|nBeI@)sCm}7xI(6{8 z-g%R=+-glL=~BZ?4W8->I>8x5GI>rXW_L_XYK|JoT1{wn(2kreUxp^oa89KtrkZ8t zv6<M*U^$WU{Qdj#S9uGLL2%)l8fH$Nc$oZMO)6?@u@7omnMKRG6okJ3wnfHB`-k<} zZynkTmT4@(!uq7TA<u7T0!gVH7*9U3diegL6_$R7JgkHT?P6dl6)_c>>ed(1mm+<B z!hi{C#>Ef=x(yR>rF4;1!}&8<n5KF>#t$sw1_bmZK2VUxBHi|3vFv!K^bXSujmJ3w zErerwR7Uh*Pq!cB^sO}4)MUyfW7hm2<Ci9oyFxm7DB}|T(&6!tGRJlWhi{u4?A5`% zKK~=7xQQLK8{uf(q_1l=(E8_^Hdi}5_$fZ6SyWZ*a}2<tKxS!U+n`%t(sS_&QttmN zs5b&^z|{ERA9kajynOn7_r0F4(`gCQttUp9ktx%gS`Z>oq-AHQN5}HCzp4O153-)l zz3czFxh@5#5C$QtFIR7-e&5%d*^^n}H!4pF|Dv!-Zl-Txf$fF&qLA1#<5;%ME*`2F zlVW5q&YNU2EB>RU#Gkkpd{`Da{CfP-*ti_s+`OJok&Y0UK;lMBUMk7rRqPd#a0jgJ z6LVdGr<1MAVOGEpwI|Zl&m>b<#6Lw|pY=(X&L1IWdl&re8b;(VqM{ORcdD4Ha%=ck z)KlF;ObXBfo}?o)KHX~!@b5O^T9#@IoQ&KG!YO=MyBaS;DbqZC$408K2>$Ecig>|8 zOLXc%F`m5AW^sb^x_H(*^MO%v)F!!Wcfyl={mR8wegqclhe~@*c%R=teoasz?K4s> zFlQRW@q)PnH+mMli;QI-<%y&M(tCxv;k<D%)Yi~tA!6X-`Hb~2Ec+di!XVmm-G?~_ zZIdMpRgN!V!p3d70ndPtJ}ulP4}+mg=9anKEu`8ce?zC4&Js>(+U9=Vg@_rQ-ru;_ zJ*o1__dd36b$ik#={=@|!cW!Sv;c5$Nsu4wmYBQQE1z#gTOlZ|W>3rvqmwRqyY>C^ z0+G|f+nfTnk1Bh}K}=<}yLNNhpMfDz1blVAKf1>ezVcG4me1$yP@nI6oZkQKaQtSN z-{<{Y|Mw`p|M%41|6@1Y|LdXnQ(xhKl$C3lmz5wO001G7|9{GgjHIxroU-WuQC4)7 z<?Xi^Q2Ni6c^s`uV_bP{yE8{ntO?_Al*brJ!aSfHQL>x-zIxFwwq%8b+V=17gGXTN zi+S4s@2<Q(d_3MiFCP!5*%xX92jLbn(3d+0WAN^J7zfzANL4xE`+;$6%<qaT7>*~s z>~-PSgssJz{X>s6UItkhal}MAfmdu<@nm5J1y}ol7>NdMg-yM;@r$9XT7;4dMX~PT z4wYiT!m%rQ+*@lC;IY*6<;&nz33#0X#)PbkG(Cl9?#L6zRB$)&Heq^r2S>x!a)D#U z!WY*@5RVmhbFrTuUUxQ=dnplouEvosH;sXwFo!2uUj_EfqF8g@a$jt5Sko%r&I8i( z=&YBKp`3l(h&`5FM+_F<QeJj<S%Rq+1wzBLMU(GJUCaHG4MfBLZ4{SSmUX~UXQTLM zav?y+;_Iw;LW>Dc_BEzV_{S4z*|oaUn@u_C`riX-^=cJ>!rW{3@_w`l-FqYJLJRBG zw0|O)lX&7gJfd~u?{HlH;5)~CQp1(%T+u4yh(LxW%@dtc&S*rQYr<#;@;AqV<tWgs zb0<g}e8Bld@Wc}THY@bd2vQ+j6Cv}&3Z6)|Ns9i0K#!a%36re}5m%-O1hG>MBDTk@ z>5x+MG=)xt?2R^{aFNfECNWWDED>#*$OtwnhW>}I<%)F9iS(#d53KVqII4<J@631w zI*l~hC3gNuPw5jz<s-{d!%}9H<I|w=OoM2c{ZfV%B*sR#!c%KEk@6IgG*A{dXLj93 z%cxh3-y~WSJVSCwnbx7>7|K*X=v}C!@qv_zN`%s+iFsEdAvqEV>HnyqRbl^ZK*TS4 zC_lQ>Q<`BqrGWf#^2GfC{x^sj`lr)ypa1}#F#!OG{-5%otf-2hh@gsKuf}fDb{lHn zx$=ON@huk;sUp(Laq3npdmL}uI+iti?%J`YAPLE!G$IW^-HZv>G5Uq7Q*!1^3;XSJ z)BJ+?Ciw;NGq9xPOS84OEY@Zk<xx&>F#P#BupX1FZ<XbTH5n?pVLFG~ELW-X8fnrG zrI{49we3vhwyHJ8{J9F5E|bKwOvuUQ=4OCQ2#NeLCv2)MFRHUz+y#o5nU;8!b|p>h zW|E@*d<H#_sk0&OI0Iq#2`990nfVFp@n`n8ZRRW`eAj>aq<bc;G_w^nXRDq=d?*w$ zj`&J8V~1KRm{N~%9$kLF-y$jbQ1m&?ipucI68X=@0&bLs*NvFv)C&#Xc3y@$5v%5A z0~p|{##@i{oP2(M-{()|3rB&}Bc!>;5@fegU_=bE2?W29XqWC1iD}T}_XcyEDgy)D zM%Z4nLi2(-A7`BJoKQSw>kfvSk?<>u87b@pG?tt(fSpJ`OgW%>Gi)ag9rL%<J4}J7 zl8#~29n?T!#sz4q4P{p$TzGlX+&NE<olGj|0AA7A<fi(b-EF1f{(r+=?crT*;~Uk@ zYaZ78nc{$&p#2`tZ@!zw`Wyi!$(r>DZ@Nq>^CaEnTLU|(Q+;@q0sjP^)ik*Ihk`yI z%MJJ%q;lR#VxzVnjZDe)lO_^jBCB^jbp>^LpGF87etk!LXP-|!=`GS|kA_q4*$AY1 zmo!hN$W{$`7U@aBezjrO7@?;`#v*Yq9wnV>^mdox6P3}S!}}10+U-`Z7xx^*y^^gq zHi_`RES#NSWZ8oy`9Jse7_3ZOc{CmxXOs@6H6)>50n#g?sp{xOYJs9V6bM+~4%>zP zj;Sgqt|(gyoU&kU=0oQaA}l1V2g?m=f=<@tP(D5Jq!-$tc|=l*+GM>$WYs363;f5A z6pG8*$)(U-)Cmp7OH=PIW$MOesDElRWc2%~z>KJFD00x+bBR)a6+(wbS2^?bX~%%s z7eaT=Aej{YuOaiF(*R;+o3Ks?&5*Icx<tZgh)YCrt!tEtTHV(zU8?5~6-iXJ*Kc3G zP9-fUhb{Bxi3wh-!0}WcU)(Dsm$fFhl*{0wq&zG~uUdZzG)Pv!nMb;H5?{GUhl7XN zLH@}sq3!Jw=<$(9WaiQ&hFJ{(vXohJTj{`jX%=g4j>7do3hD1++=Y&8$54WK>>-${ zCNmlm2Vf@)tTOfTB054lMW*w{_F{XHB_^@Sy9!%(I}wGkdiHEtJLDM%w35Z3!+bY6 zg`~F|S~O^GXg`&t!A6Do_n%e%yoin$<)PCVZM80)5GX#G9^-#xxJ&Q%`|#sbUKU~O zei@Cn3Tc6lUfe`6*An%l7i5slvl|2aqcqN~B4dp3E?|2v@c!-T%61+MSg}PQn<kkG z8&P7`^$E<Dnly+|a;w}FXZ=x#SVE5v49uq0Dfv1X5RExjtp41>uf<b6lxLc{YZWV_ z?P`f)iUYkUCsB|~;Un3Kl^J)VUQ2XmR|j-M;^~c19@=`nY@vHm(fepItwQY%aPd%W zw)Er8743bo(R}LZ=#4`DR7JR5w(ElJk<p1K>MG6Al<b$wq_J+rA_fQZU@XcHQ~e|6 z=HhAG@e>duLYXiGS_RC8<Fjh&R&KVf#Fm6&@UTcj6-R<b*$HVkpTqD`AweN9j&QaJ zXBe+YLcaL|sEI)xKo(OmMo^LhlB$seJ`Y3B!A?=s(_rGk|C$k>%vn5GM}iNZPCkd< zAQ)pU(FookQ}#!tkZ*VdX~~I!A0TS51~2xT*U-Ww{2m4(W<XD5@!>#NWmx7J8Ahdr z(OLpF!7r{9aX`Yv99qyVpW<SyV$-Q*MX5{%H%=!!M0n*Tkm1a5^&Nj$@X{wfS1#I+ z1i@(b-f5;N9B?8ZZU@OdJU~}X2v1B&)uCHIZSSr?-@MQDc|FB*$q(_vSGO+N$79va z_51j9{q*<;_l1?M#a!E64_$T;C99d&g`CQ4p1^G$a>z!Em6Y*@8X+pm8mui5Mw?nG zQ_Z+-tho*BDhaniX^j+vd>+gyWG_FATg!laAiY8rWI`g_wz2BP&yV8frmX<xuVu3E ztiAfU-FVxVGgq$rhPPP9%U9mWT-z6GI&Rf~{i|xda=DPrm#VsCzpprIRvohGoaQn+ z;<TNy?WS#wb_P9aS4Z4&y<C?&UF#j1b{>SV0!`z?h(rP*rm*q$Y20OgD7Cd~mLvzf zLOFf)^&A-D>}s`sz6}YB0lOPWD;zArH-u`R{uwy`sAV&qsal4w^*~m$YOU0F#Xg$s zT&nECIdj>5W8V*)x#{fN0<tKVZ~@FY1I7(M<OFS90c^<qo&fQHCt)}jHbPf50#~ZR z(d82-@WaudSyp432j(xa1jF|^g;m&H<aA}-MZf5BrYqU0GCoMgSrM0PA=_?MF=<)1 zX|Fo=^5QMWDc8nx+nFCJx$hX&x)pO`#&5gGw;)#Fg4knwaJ{R_E7}1Z!)=Kp6C(%v zb)mbi|L_;&*SY~`!d~$8LboFY6=yc<%7;0ccmQ6VAe+$vWeAabgmBjJ`>-dhEOSf+ zSIp%6nkBN=@EMboZG6GVLbPhhC>bTCSx}CZ4PY__ha8>75#2g6)DVf$PhtTJ_-ke{ z>C&>MxIu7p8zao)@OgvAUOGSJ`SnTIbD3md6#{Z1I;&`=%2|2sN!@T7D}HbssKZPT z7c!b$?m}Wh7<SEfjS?zbPMDuuH6o<vBnD0b=kU#_N|C)v6a_MC%CQG#ARnyD9C_r> zTI?PWv)IEg=RHvFke?Yr9h?WT8_8ef0Fyl%=X+!Q+;s=&H|+qn+99Ad$Y~Ie!)OBd zD8<8Ce0X|D+kC7=d}&YbCTs<n%HH4zT4M}bmo3N(0^<!L5ebhXCjWpJG+hpNou+ee zJvxaDa^*W1xZs(>`W^%K==1vVv9LqkBPWR;ccrq{&%NhFYS?Q|)CN#3KJyu^O4#X> zN<=W6Ocby-ExwkrcV*h3g{RXT8&Mk>YIY;<`P`+)kiz5Y9^Q~R8nFSwy$>9+;u=f4 zI@x<VY2anqaWc@}>i)gUKjr^d9q6ACPVeUb+3sq=s$G67y)(X^YeIwv6GZRFFKaos zB$2(IVUBAB90epjE?`Vx95tx~lA4`)N{KH!%O)XBvKL1L+vvvHZD_s@?eRU}CIPE} z6Z0`yXk%`L?><Ka6G3)lzF;R=4oAD-vWw>$^HWPqzYN6!#*;-%77^JyWtH#g`M-y| z{v5wya}W^m!lOohq+!azgH!K}fLzWgU)44Zs7hyDZ_t|f?ArMm{*5$;nEJkAVr~d; zJKX#K*&g3*8o2w2dM2PLRsrtjqSIJg?74yt4?(GgCr%aqENXnG(z~X7Zpg}^wX_Fx z4rje-Ezzb!_m61NotCdZG57SnU>&DFVBh->k$t28Z*B?qcPy;*UvZ=e4gf&#|I96w zM1|#*M0{7q(~7iEzz#h5p;eqGV7vf=h>$=enG6YWf<Rspt}pA|7pg1pR-k>Z_Ynuz zA-)R#aK}~EVI998bsGC*B*K1(gVCC#Gp^mj_*Gh0pE~Z>(~B9_lLwu@#wF5rZP_}P z#wY?${0ix9f-36qcG>B@%L*w>!^0bt_Wb;}yd4?F)L)Vu>QLyqi(2l8-4El}@ro@Q z4y)_}Dx|YKaH`7o6BdPXxksg!S?@`Ef&g3+>A}9O*Da_OX%0-Wpu(ZhA20|&UZ-W6 zPCmriH2|`s0ZVdm&Dy(}rg~d?<eDgksp%_kmkK`2+`1%*M2txaEWC<&t6^R2RDjiW zuWXoSxz6A{EPQ*G(aMi{=CtAcCN=rUAq(Y=X?|!|Ia07EnDDk1`D^3)pz5MP8lEgP zzbs_3KWGlg5zr2ly;}CXfdU93XCag#!fYKgNf{@|PazaCmHI#?rH#5~GPHb9V*rlj z>60Lc<m>Wz#F$sWyjtc>HY8F{WQg&YSQ?cto7du@iOQZ2++=UWPN~l_rgw%~+Bz|T zapdhP#dQa5tEm0BLu<G}SNgiyps3?UNO64lC6Jl7<%>DCr(^IVrg)74$|;YagQcPJ zhrP$!@@Dl75ol7Y!c1#xa(`K(bZ5pW;&!fO$i&;x&vr#)W~jvg^FEHGHh9<-ip!TA zkdQ~ZYo;F+9F)1Hnl%(#d^cgG6?X&5vMvj77^48SFLY1ZCE$2!s2!b^Mhd+4V%KJ6 zuC`m{IZNy06tdu-r9)YXY-5bskZtfWzuRtPsUA^V4m-;RK#wwQ*`-Da_nIRCa<-m; zOmN6eQf~L(B>LH(r@hE5b5ZuS?2|3zFJ!WnnrY=IzoM`g@#pGnNYQrCndVjpN7t^q zjf`P>GmYTCe)HR`iSONI5psJuL_Dl^<O@BokHcivON3K)peWO?r;#_sV^AdAmh1c^ z!W!e3-5a$V9XJoa$&|k6P~~~@6Vy=%t|d0xD4xjnE#EeFxsQD$8L=L|(L{{7VlJ@P zUylMpUO`(#XB}oWtBdo@zs@|D&n&m%&7n^7ZpU7W3{V7Zo_@X@eJasIT%JB6P=bUZ zf-g$_#CQ<hi4o2}{C-xPBxYV6ulA7+`r@$3`6aG`-zTd42CC`&ztMQrTXUwz8({oB z%bnlWk)5Kqnc=%8D)?N_MPpDZ;F`>Kyn4K3C4T|BRYo}Ciu@N|j^!BXr_|s#jQQqd zW4k94xbZ5vbpTk1bz`}a>j!Fbx0G5colQ>v+$FyYu%oD_il~1}W77p%$PM^(?b%cc zn`)4Bp_R>x0T&DtDmy&qx*mQry)mYj_(9=SL>K?MUItGscr|e8g}83fy(Y&%3E~&* zjSNwU`em3@LK4e$7y<mGczE(0fyp;)xRbEa`&Iv82it*P57HsqjRvDPx$|gLm)@g( zFU?lo(3HhO@*l)CHRE6o`~86bFCGn)FKg)kheLM%8UFthkJKeZMP;DpC1ht8VWnxQ z=4R%bl^9l-51iy@rD>&TCh41$B%~&3=pyOCD-{<Q7MR%<nU_wWrsnAvUuf1~DQKl; zCuN$HC@869PoX4b+Lb6OSe9m|=cQL=XR1RYF^EMv{;xWm{Ahp<`aho_|1<Lcr*AIy z4*E8xZl*T>M^2)aqNS0grK3Cp`oGr8>qEJO0|Nk1hX(-oKg~e@zqTKGeSJ$iOBa28 zItR~Mb$$D7HU$6k@{TU}H1N>4Ts!I*E`jw@>qZt>q<UWpsMIuz>{^m4l2jGyuK7M< z(W$0mFkA-W+R3l+Zv6YW^KggfWyBID<Wn!OR!v;qHWVQ|Ac3TfddH*~huhzRAO1iS zoBjmeFbMTUL=odRcMvtK&dG_*hkQoD;K2Z$$9dLuvEk^^Bc!=eCC1eRe>mR>H4O^` z)9R#lD#jfuLl}C&6o<`>SQ=vuNzm*rfko1B2Nu$PMp~u!V;jI$GiyF#5M54QUQk69 zB}|3i5CJuYdkdFYS(Y6P<;zVEA8&7IYInF)D_$H|EEQ}st6YMR9i;N{@xXSRwmi<i zLM5kK4aEZUgk~q*VqxLyzM@JRMik>0w5qcZ1u4MbP9NXijZd9MvUD0@bmqjY3uJq; ze}}Ns)_j;_0o#@Pa^80@z*Qx8q9*<6L!r!VI4y~c!)L!4b0Vc8mPDeke?~Zu)Q;>? zd~MNyM|v=3fpH+$SV&;C&cPk?8E!F`1*QJc?l6ADCXI&#vtiY*bI@@VW)X!)1=mx1 zIP(V(Eawk}(Q&Frz@g`^dBSANT>=7`h)pDDzQFQAJGnteG{eFQ8p?$7l!VPHYOzSy zv6+G?aSwFl{X<QG{GOUc@D8J)AK6KobV_<we8J_Y(u?bqym7hg=k)oxx;putGBhMz z*^a{^ahVp$`R_H=s&SS+NNty4lqt~L+GSGNy(Xn5fGPfxo~FkOgqFgZ-*eP@W<4_5 z?X^&ZB*)Y(<ID0H@uH!R^rCb!$REVX*mW%ptw->%A&WD+gLxQa^LU|GP`9GOTV)sw zwI6Ina`%Hcd$7!Y%s%iB2zw5sYO)AJRuti2$oSCY^N&QjIo5_1(=I9fX&%Q#2V8e9 zCYkIR6KsAXfPbOM8DW$3E=y%a8iI4vKL+9q`NJ+~Ne^-oHBB61!^Sa_-VZZE8@P7% z&fs&eEkV91RA4j~U!glL&gcx*wJG_VFnRoWGIxv3qGue%9lF|W`rMg`Z?qn+T;Y(p zau+0F<aQs<e_}b5*zYFcR<T;Mmw-%Kg4o;;?=&Cw5I3c2^rm~Wa(jRH2q5hY3CLbD z<q-gMWY6yeK;+;;yP>7714BpB6pySWSyLNzy0%#r{hQR-&lTe>YnPC|CmLd`+cVrI zK*w{TZGq~DU|9GlSB4x`f)?9AJ&m!?GL)5V<rH>Ss!0ln;PAdc_YC%OMjp?8)fe3G zUMxPj=DLxSy4VQ5KWsuS*b<txjl}0qY{~7UxJq9L49*ypKgukv(G&Ma_wKEUxuRPx zHrNDhF*Fd6b?~I-;h(&{31oxqB$uCt`5Z)eCl{5{$Ru1P$9PwKfNsWEAxN$gn)g0^ zUA|<U)&Zf?Tx;HoV7Ox2^8?-g3=kH64Bw7{&+f!ODCJZ@!E8t#l4zarvSt;AUq+`7 ztZbH{#KCA4Orl$_j|aKAmna%x?A2B!coeR8B;B~Frs8>6A<6n=daPR3L*1R`#oKx9 z!>{450}b}Wg)c8)z8zA-MLaHV-ll4Yz>EU7hg`rlV7-W~Y062{q6W?>PccckHFkZE z?)h$Y!z@uIKcr5=sx2tiHs(0u?850<a0xywTmUc)o$QdwC7J4!Nq0VI0e7v?bN77H z(po2))$&$3$}4kO=^ef;Dg7+E_O;jpTDd5{Oi+8o5UOG0RJ>VmM)(c|a3?_Jjz4}! zOtNF@5X|s~N#T$=<jwL<R~^E3zAO=de_<jFgPV<PocG?(q57?KjwyEvI5+q5*^4{Z zey*RtFzU8N5w?GwE<|?Ex{LKiyhMG_HW+Cfw362H`|IXt)eTH+Kj=$*MyJlA%q67% z+t{t-)%PZIq?2uzjjj9<C;1uG>ygdHjD9uOF;wFn*3tGDOB=f{t7Z=N#HqK<ej+SY zGY*)i4atodl&u|l6H&d1u6eM{I&5*By8RGbI?p{Y_$OK|A7Q?ke{s$+GBtsOl$t?Z zEX6c4J=%+FaiX&eJtwSn<PEkv)75oY7~|Rd<?KVl!QH@We4_IQke%oc=zqDAA7ms6 z6c7NQ^FKrXU;c12b#k_}xBLH6h-tjMG%zE===~QZm{&x)tnsS?BFL!ppmd@a_08B# z3*@fs+BYKg&jXpPH6mnursqFnyiCB_OI3ltIo4V;haNzVHOXg)^7KzSTjgwPA_*_u z+|@;;=%ie0)mGaD!-2L?Z~{1fqR#`#ChzB^OG*ptDJNHmDJ+e;b?OZ*@M#XHV@tDQ zY^Y+PjPD;GKTZ+cC_ajt+GmyR8NZ@`{p_5lu%?@S@m?45WM4)(>@lRuBPf?ppFv{= z3J+0SKFQZe;)U~<#C&(qr%WQX+olc+NU{9>kCsSEgbztnw=ND|<wBZ#`eFw$%<t%w zqkTD%CdeN_`-5k(jBeewXfRR2RrvpVauJoB-6;P(3rYM}`C$Lg$ywUDm^#@R+UUEw zSlT%MN5G~^gLc~tFum8*5jP7a5<VA}3=6{zuEOxZQMKINQL^h>Hj~8_Wqmi>;*xF4 zW?UnPFYgk4<L(X~{sCL8V|=Ly9lSmfh^1`Vu|(g<3(fRY#+Z{=eNZ-D^}l_bQoG6C zY_MJt^I_x`!L^$l*MZ!#1(2m-FNOnPXmx%;#~}OXSXV2VUBO`DEwCKW??WNLP*tPK zJ*6ZU4fu&XHogcQuS481S?-mFt4Y`e6NC)I7ZQAZSmoEeIKh{j8&k};f_^DVux$f% zO<A+dW8jL0+5FxD*`}SHOMPr-R_as<#IAi%TR~wlAnxCxtoMNrlFG})ZwDdnSd3#F z2@?gU`w|z6O>sjIM2)1LW_ZS@Q3>6eL78Tkpe+&02R@vx5*ZdWYf5U%Dg(miB{}h0 z-tX_n%e%NB*;z*G(M?K0a%0AgGRb{qsJSsOHMX(UAoV2K<?-X7VcDJiC?k8vADoJ! zlk<hsHAJ()+om<UQ9jZy`g&MDu6jXciNsE?EE>p;sn3Z$+hLnK&EffqXjTkp#{JBG ztSeJ%lYLESqGqtya>;e1<LI3hoKgl6lno8(=^{5I@YnmGKG1oG5zq#?44;;`!#^Xr zHlwUOQdh>WWhEAVkmBc`>}HYO8ED?DHkSmnZfePvT+p38^h5O2y+CG=_!K9552a&? zhvs%~Y^J+NoK*D6eHM)}KfwPROtJTSL_YuJZwAW$R~lz%V(9Q+H2t3_y5+HU-sVW! zf1!4G1($SYVxRQcpk1X<jXUmitTjHjF>kkOrUXMGgtm@ac`_7bW_{bP?|vi@2x@xD z=-%p7RyB&WVZn;^E1ooVd)kH6K8c*UE3c_bBljPo4jx=wTr5ENs}a>qMU;OpLlWhD zuYWaX=+K@_s{L0Y2YN6`Mc169N<CN=WPVCUPh}Q1Y^v9Y9h<sZ8X(OnJ)&f0G|(JU zYsg|GAd{(~!Zbe>VSzcpdN?(0F<hPcp?MY!t_TY@O{Cx4C85mu$G3Ij*>#55j}E%* zV1KxT?P@v1Ci-iMew=_2_HGOf$YNf~0PNq@?d@G$|B>KIstnwEC`#Eip_9PfiRKAA zLovIqtw#^U5g1ank!i^OJ`9eOk7guX!zf^GsTT#Z?xBa``AE`XR7ZAPKsW&gB=Twe zbzNy_|4yzoAUL3I<ZageQ-EmiNQ~W-l@AV6^E4WG(}l?Mfupy(r^m*Ui7zi-WO74r zFzqw=IHd2Pb&Y5x0TM;A1gGTdoLDdDJ|in2Z^Uir440*WY5>GS5LGD3<mLN&eAzwS z{eHvZ_i}gja_ag0`g~UoiJUJmimv+IykjGRRIHVj3<&LWCyE*^qlsDSPJKYB0kR_6 zh^UE_9-XQYtwDDz6CpzK6XBs-Tk|C6fN3BA<rlwBUV}mjp&&!Ww>BNvx*A;tw%UdT zK-~v0W>Q*nQtUyCo_ebIOMorVEauBu_w<ghb1!dTEJh2M*WzM(1hqUOCFRlhY-!>( zgr%C*5Pg$a&eSQ|=J=Idu)nKwCs;uUIMD!(X^w^vOfwOB#MofV5P(@8GJ`D1@*J8Y zZsCXB+0Xa&k5;jO_Evx~LU+NJNarvJ_F5>u?|76~V#Ix)*XD8C!wOx|0TOLf`|08$ zmPR^(Tp$bx<S2Bz4WyNLrly9S!`g)f4<-hrzqhZ?#}%@DGv;SPSpnv4?sjy4?r`j% z`Rmo}$L{Rt2d$3Jnc$c^y8T@J{_bFGHIB}@L4$;+W|KOBTKUvw?9&Io!Tt-;K=5v$ z^vKuE+@~n4)ZJ_YX`CrpH3wcG0X;6-fD=F^GhpPW6V4{!F&HF-n-Bz<%$Gwz9n|1D zv({^fsuYO1#BT_1ln|YJb9WIM?WAVJ5I~_6VDx3WFouFZ^l~aeCD2WzM2o+96d<CM zt!_XRhOvnq3{4be%(1obRSIEs*~sGMINKV&7P_9FiF2S4fHhbSZHm>RGTW4-yeF5L zzb<5i925-CiY}De^A5^j2!f@bXNKQYJI$=2l|buh6VaitNht;13(Np!d?92#2Len& z(C)N2Nzb0lg0e%Kj58c|Xk4%?bYqSm&LzWy%)LDvLVgCf@oVs}8jyIES2C12?5Z7c z7U=>H2W()gdX>qb_C+U29N-~>Aw-@mhKR*>s!q)Y5UCbbA1WtDY^~Y7nuQGBB&>TF z0+{YzlFwu*h&$QyR4Or)Ok<s){~3?~1;F#dnZwIX%Iq~wAOnh@kj<tZhTJLbHOn@k zjw4Xg55?el0k0dSkccykiJ@7di-{0*NI0^ny1scNiTD6vhA<F&c1j<|5n89#N|T$q zC#V}UXgLH@rUkh@iccV*{<a7}9P<udL=8LHnc1lrjRWU^U?W{I@cH5^%rTGgJkIhl zcB?1t@)bxMbYZM4u`a`&(BhApBPQvOo=MTcW#pDtM!UvSXaOS|cR)f3$vPBGagR}9 zk-}K3)M31KPO*tIRQf8GLTSP%F7vhw3Zs<P3RXLlETq2f8c!%~5UzfJ6(BQ${pm)L zwkXn<pg*9jGKatoNF^Vk)(OFWsa|U$>O#(jq*Y4d^wkRv*qQV&75RN3q16ixkKW2) z+gZNUN3%l4LAcJkHFz;IrY6yEL`~Vtfdf2#OdR7ifhAn=a(m`MMG~6(alV>oE?JB^ zff;tgCxP09S;9QU2M5c13J^`FOkihyz1^VC8T<=aPT$-y3|qR#3^Z;V1~a>1=7QSV zNu`C)KwVO-?&Fe?ws1`(nh141lK`T3tFZ2otCV4;SmKF*WtzH-sbSO_f-YjWMw6}{ zbBy{XuY`8)(-4MG8b4L!0Cc1ZH6deTM~dq<6fd&9jw^COu}nbe_j{sHf4taU0x9;p zk)xs!Y@|CVT_H8)Ka>t`Tb}%)sZ{1>Ul2*J3(|v-M_ow8Ef=eu*XeY6*ut>Cxm+Y6 zVr{;KD<DKE-~n9#Wr7Hu;A4o>8*g_DNKLt1)#AgdDz;_*Z$pS*XB!%%pIGCB;i4Gh zjFX=QL68DrjZLM!<Mxi))LGG5onZljTEYm`VR+ue?ULfhX15AVfm^xVQ1?}rH7Lce z1jN*4x$kQa*iM(nrp=gE1$o|;j*bcJf~BOzW=K#HssWsB#)R0YVFr<u<-kNY_dY?9 z;g!9?2z|d7`--GE%Fl%#wTqhwHT?^lMpqDEhBo?8v5Q*fg->$`CCaUt%@Q<7kxb<Y ztk&~<4`-Q_t2rzmV|6A%dpc?d%iW%$f{UD=ASmY1Z>)X`#IbthDTgr=<OlXogjTp> z<Nhw>)L)Sdw*h+dKI4hrW<$`|Od-~X2A;tt0BkR94wc1bZg`F}Q1|05<K7p!)_AF? zoKhcNd4hsE=A%`SZ7t2C8SGAv00zrDu?b(M6>6W?xI<_XMU5E3*MlVDsCKdAwj1{k z>EkV=jm_T%9XX(-cJjCKc%+mz8m=Rx9PgnXOKqcdMuv<r<R>{gc(zX<vV?@GKbdS( zA^dWY>yxmm9+)_4`Iuy(`xrqi5$gj_Rb3z-F15x$g6CKzQ0!R5&z3=;N+>D9lMoKT zw#vL@_EkV*<lSqFc}9$z@ZP$s({Vedub0NW;2Z4_FE}n-_#Pr`k)8<xD(aAjV>*b^ zcj6KLzN(JE(5)Rx?r|ziZ-j1JJpmYvopp>z<xqaXsFGa=A}IH)&005*VO3il5P)I3 z#Gr~LxJ$Y<N?udQ%<Ev<7eFyClYHH3W@l4(kT0R(X-x@ZGjJ<QY28bIsv`lVN+?!Z zSnKEYW@E;NSrHPC+%QA|31-#WGDXR99`kDKw<koBFo$or=ae<ZR?jcFQ{)lQz3FfR zN(1)>E(&oabS-R)tvD_jRMdbu>Poiu#tP<EPB(-JRmw`xVJ-)G86Wml2siX6-k;9{ z5Dzftlr!ywKSvO_hKi}$8nt3V)rfFf_6VbdM^-dcL+D89W;<K|lIZt*Nz9$=wKVRn zvXnySO$D}Q5;t+HB=a+A^b$ruUb}AQA&qe19nXzG_d_4iH@o}j`Beg6fn#PZ{qLvP zM|nN?JyiSG%(rX(;14;E^4MszSmh;TQPk?BN@Rz{k2J~!d5DSj4gW%JgKDkT=?i9> zCgnW~&9lGS2}#Tofr64bI1HI&dXm+Pg_(*ZFq%H&48YK#(#Zh8dpkOAgR+Ys?<$w$ zDqv7sQEQHyB$OPmTaGoYfw*J`3p-ezDG5J8^qb5K?|&J&WdW%+!;y57!)gZ@X;;HH z6WD+y6_yGpigt`=nQkjHnX2|e*wAsT3f|-4an0UyedFHdgS(^qU8<x=`6Ls66FYeB zl?&(D>ngtZxVf69x>5%05>m9(F+-9G25-Bxs!0rn;<z=x=Mq)N%1M=!Ck^6=6faro zu!gm!g<GO7$SL5wgAX^~VADc>A9qJ*-!BXkAk7w<WKA3GW}&&`5JG_6U@rjOdzHK_ zVU|M0-NfE$&aS?$d@ulPDTy5XjQ#XaN}2yGBLtg9xM=6mf;x`f^q-v|&o!r1E<*eK zUkPC#2+P6WzJ~{QY-Arve&Li)nqnbkMJ3>QD(2U~xV9f}DTPJ!O9A;Lj}L}!j^1jg z0el~u00!GN<4Q*+VIC{!B4wksmk9&@QnC3PJVF~Z@)`AZ^Y+>4c6Gcy7CFqKC~b~T zKzN}P#7XnB39=YQs=I#34kaom51X-(Wb(@6IH?QceORHpm{YL%_b9h=k=#P$KDn?F zp3l%`XI}L>Qtymy0wvFV9s^p6_=+oxC5Xc=oGRlq(;K&7Pu|@?qX(U9g&vk%H{5LJ z5K<QvTaoSMHxzbpuA-WxC$N7BGA20~pturcoz)Do$T%TcoMN?>tqd~W()GvpTH1?@ z%4lgBqB~2SmkofoD`b~DqRS7oxo)V~1HDHieYXX!tMm9BcffA^L^KC|)FYcrEotxq z6vS=bX{A8!CM_gz`-Xil^)Ujc+m=C8)NL{?Q;A1i;nZ@S<SIPt3^V)gvIyMs{t~J{ zHeBFRKeSjefzJlQGRg3Yy1cg~iB;0JB&T33j2Rt|vmLjLkp6vb7s?DH!;>=jp~5;R z21wfc_oYDg_|GKFESZWxf4x~HUCB=&ex{PwmY=d3mqVpokxYN<6|<?x;~@U#l4Yjl zT3_~<bj>LERUx(COfULkVt2Z++_8#jgEm$HlX$0vYl&2CDlP2zZbO4I)fOFIRmmmC z;;>j%Pp$VbWdDtm%M03)S_gb+ppM#0a)OTG$;3L(D25=ZJP3N4f7efN7BHx`G?g;U z#L(T;J@Ly*P$eF&2Fr8;ErO+{xKVZ%;`f$WfBXikRp>Ux)*2zkN$ZK0Z?FSd!<S`u zfzR)oLpx36tz!F<Lc;q?ry&2kZC7xhJiA+O8cDTRg!FJz?u9u}>=Jk!>{?S7g{XQd z*KU9?q?Ff-G1O*9a|D<Si?&vq-u6nfi>Z)-fQ3$>1DDgZBW>XnOv3EYA#Tq3lX@wU z>(w&9ph~KF(A2Z+7Pzrv_1!9E`}p)F2amZ@Wu^3*V#=-VBN)*!VkWS6?NtK=9fiEH zm7<Xx47K`FFqB(VZ@+%vTe&-n4Kk!oPPr+QIu6_w4L5=ut2;v1__;N8qoBKWNLmfA zviKiQ#0w_dt^%V>q97=3^i4I8&9P|C?cZ$gr2WFHb?=<zbUQ_}f>G$0k0@OMWpS~x zHN$jW`Jmf-LIL=0R3hg7e{F;cYm<#!aNitC?YQPDV^E?<#m14@9O9ZvTESx<_RMBh zu5LcD+~~`aGBy>exA$&ge(vb*k*a6f$(B{2eX}q#7e>&yh^*JGiR6tSqIr0=P7$}q z5t6gq|Kx$mcD<cOwgck=+YlMHu<}UQzU?=&2AZJ>s4y6cFIg<3q0nU9EsZ6K-K55T z9z~yJH0^H0S~3g_sZl;Um)kk&C+o|ND!1kvZyORK!GulM<##c0+ctK_*639Z{+P?a zs_z=Y&HjKK>o`9}M|Oktvk3{kXPg0x9XA}6jLT8k{tjk2C+?>?eS*aUvq-bm0{sOr zVy6lKT|<W6=}yg8(T1(?q+Az_n6g;=)1gH`Guyc)&MrPi;I_rGo=L+6OcV`y#PSqh z_O0SI9Cl-;m}3Aqs;v}2knn}Gb=VkZUshK?Hg%7!Cyjrhr;C<70?s7vQ<>6cp<Meq z=z)h|;h~h2NgcU1`R*@vTRY84?4@2v?!!^|@^XOEdJ_1TBj*s}eYE9MVn5;6_^*vC z?zgOD7u!9tuKw@?K6m*6MzhFOZ-lq3!nb(d+2X}Kr5nP>^_>lF44>iS{lVkKaMhme zbTk^T^S&}~dQ|7O@k_7E)w|)fi(A^N%j{Uepc#j-vNM0T?H*mR`BbXI#pBkW7NKG- zd$OP0l63v4*o|zn1zyS<1I3nOFkLP)Dv_m)A-YYQN2})WD)NH(HlEz`$X(*(!(j&c z4>OyX$kU0s>(zu)EP$=AFL+n&rSU24tGO07eTV@X4zE5y2xN^f1}?7w4*LoQGYT@p z&BFdZIOEaMdyRtfjZf#-eacJ6DA<(8-Je0S1wa(dX>`VF?j@kJNI%l`iC@$5V2p_4 z=N$hSj}kFuVpzz)$iSHkX-GEjt>D8v<Iu#ib-z4NIowy9t>H;xWAWS>DB)Omum_=b zpY-PUy0KU25IQC0+WFo`$hI*pl3{nfYoafI6oT+6mV+9XZYL_%Kg3LS+t|M=<Y<j) zh+dd+NC5LNw;~Q?S6VZxJq#I^W!9Ct85l&ck$^pM=|K$xZY>rZ-i&L?Z-RGGfIw&> zT^kzVRd981fh_Z4toZd&!t64;;bf}O!Qi1^D1FBT56O450EZfnNO8repzHCS2AeFp z$=7^Zx`_fU3&3$VSoX*0Y;1h87n3wEVnL7TiV9|3%p=%bOVN3`M0kYr^&DY+r@%WS zKY(T{d0k5#cm#O;7;aRau6aV2k!~LTarjQF28-b><xSo)B)}gVzb#PeZYl7>6GR|o zq`tFA4SGyGzW+pDg1d6<=3KbRT4T)myuTgYZ$2nEe8@hu3FZ^lgu%mcgqc_p&V1C{ znpotrgrj!L=b-N48^Z7133xES5`7+rKwbay>O?sSB!n(6>dkDt84dB<po3PKXIs@U z(J~SacCBy#cdY%Vmf{z*8tr|eQ`WRqDHNkO{I>Y^_xr)}>Y)2Y^_HrBRVY)_DCCFY zro+;t-?`|ec(Ve(Byz$me23=~{ss3P@-2?g(XDKiKIH8jV=j=;Q)^NxHyY)W7Zhl? z!3R9ZbQbiE6{Z&04vt<ThVol&Q8A;+X&X&iGs8m}nekp!<vDfZ{r}<W9D_3rwrCyO z=ESybn_q0(wr$(S#I}=(ZQFJ-xpVHHd(Wxrx8DC<)!n<-diLt@!MCfl>fqses0Gzn zEQ?4yPli$E_+tsQ*f^>@x+ukiMXzgQamUXG0>125w|c?mD@gw`&9ZNKG93K+%l?(i z)m4>x(#sq;Xs~S*wiC@K8yF1H`a?{AufM!U&Dy?M(^K2(DbJi}@pM^p-(35>;NA?7 zm$q~^9`DC2T(^psx#hs`QJz!Pb%VI!-fRp8aQw}ey)q$u{PB9-1vqwpXpkin(PAOK z7tvmz?tl+A|Ml701NLMbcs}Q%SGU9I!xByJhdm8<-z?cav!(<0!t?sjx+P1gZWhyg zC-^(|u2mI1>Xf~unP~TbA45Ri(^{5N&Hk`z@wK#e7j3Nn#r<!!vK6Jl(&3-!Z14{z z|K~gZKhxRJ!SX*srN*wxrZ|${tA0Z=@0wXm?gGCHYalj=9g%53<n&YFxv06Nt$w1* z#WwWnd9%N_`>i}P2uR6vGb^gVnsDdlw_TsTf5d5hPYZmcv}r>`LF41K{kwem<JEdo z+^9Yc>k6D06_3B(rwjLDDQiM?^B*J=J+lmBL-;ka!R&h2m)ZF6T=|p=r`ls9OOi7( z-!;$sWrV4fJ5UVp4Klj)m+yL1Q|5s|1F+9h$+UJBpkOG9G04Nk39J+8WS-cBB6MaJ z5y*O$RqAje62*-L2;&lJ+44mxM+9I$1_};pe8JKtU>jTA-ywP#eoMd~38|nPhOVhd zMoJ|nC6ebbMWm>sqK=#h-Ef%RO!)uqa;0;`koJ5qeF&5ih5gHNs7w{>3>k`e2XCME ztZ|Soj&A&X{5-jD0&%0C;eRi_Y)~+A^p`L{7lTQ9Nf8}=IQg*^#+U*-!b0V-21c@z z#|kWLU3SBuluJvYqG}MsnH|%;_yS~=ftK)W#AI<H7`3%K>;HsKY97SX=BPguuL=s0 zDX}Tq4O+Y_grdhk@!$38Vx2G#UCZhj1^4IILa2deRk~c$@`fB@7Dr*k`Fiki@sJs7 zMalMJvMhYQXJyd;t*j=CLVFH3njw!XTXg1pn8e|rk>YwRxEHOIiEN8?o<rDbS{2^q z9XOPAp1KvmAKMl_T8m}BvhkK6kF&&$etlg*8M`EK+<Mj2GgV8Xfz^2H1bfnnbXiNl z8_V`JVL=9;N>Fwi+bufnp|5k0hnRsTI&;49@x4s~c0mPbP@CRfbq>?pu2ae+huia8 zeF7!@(Maus)!_lFCbME!WY~6-Imb$>j#J1QrAlSebb!i8s|WTFp=${39vpmkAEAlc z{54S%kn-lpyA;wyw0|ANnwmGJl@M#61kPvsknY<YLP*_Zb1FUZ;do!zgN7@gram}s z;zEf@S~4F9dKx-it^HCnr37d-eUPjr!~{o2C7r932~JID6%vc|4DC#0TunRyV##qH zD?su@h8J{*I3*?Lx$_anIaS&s*$kZoLo^hu6|t$(YTpb`-~V$p@;3*#kEA5<_NvLV ztpvS+R;Ah<N2QVrUyH)GR5h#!YjADEHbwgIKqA%%&1*O!dobc-V7w(L(H@w@4o4A} z%vywVxTAp9X+G+(@^}3?D#8UF9*fhC6{Oa;oBBJHW?ppTQNjXqHA-p&0eLWw!W@~l zM%x)#){)OPGgnzqu<XzjfnUFvOH0Z`lGDbV!G38Kz>L#&>i``>2A(gjNE}8NbTJv4 zw4yd=Qd9#@^>eCoNKC%y>A4uqZJk|)3JCI(u{vt0x|7+%-sf9$0yC=HRc#{mo+lCe zh`8T_Eh|YpUQVyhB#j9v^Hda`Xm%x`3NSE&xaj6vez?sl01bJh(jLNyO`2&k*}a7s zxl=#fEf8|ZC99bSdgl60wOn;W_Pfh>gWmP7bY3m%W50|5Y?$G)y2mRE3Rgo9nbq02 zX9`gkQ=FDDikoQI+uQqjPtCslCB$yvW>lGP(v^w;>vCaZL9`h8XU2p{)r(21;QD2g zd{7@=@6GabBs%}~Vt!V{6QOQJ)JE5=YYVb#n20HXM^6%0RYF!wU(dpB>L@7J<d4B0 zA2m`XxRc@3B&viW-F+tN4pEe7YDW@291II`J<exTPQW>sKibB!iE@RKr)`X>^df@# zYYaC>yD+`QR*9p>v^>3M@WByd9>?m~rKShxJ!TKTdY=P_mFf-E?_0!8lE<5t3C}h@ zzHsDh;T>nhFQ5+ZDwu9IW9z6VQrTrueK{-dn7_MmzwO(0!Vbk9FbEU$FaY1;qSJ(N zLz$HX+K!PY$rKtgbH8Th3gmoCFI??Ye58r!wfVJ!AhOU7d135j0@Z$;v;7F17P~H| zFK{lwLl9mfD}TO(2|zY_-Wzcarb#wL2ErH-zg`2&$eXa&?L`M-yFwdzDRm}NtSh!$ z1Yz<oYkT#D6>Q3s0cko;mx&~z*u?YzCD6ba+R6{=ZGRA#E|slm4%82##`B!Q_6Jp5 zX_~$QejQU!#jjx$k4F15pP|CfP4avL?2by*72#Uca)`e$R(o|kODfwKv%XOsZ^Rk1 z(u~WxUL9m8hRMeg6CwJ%eNe~FC@?a6$jVYoBGHHl1b_We6pX&!)Q8T7oV!wg!2kPj z>S~UpasG!`?f%27kpAm%a&@uzcRC&8eEy@MKHPuMc_BkfR@8o3cM(@GnaH`(ZIp>+ z?R%Y}gV-*z<7%o(QOmPm{eAi5=O>kJJ$woiL3H0q_;c{;m;Ce#n;$PJGULI>PnMbw zmw$+(N3U=9R_dk2NV+;j&1?SC{O$ai9#bc=G((LG^h;PpkFp3ehLDklHD7UBObDYn z<3yI488u1ABPz@<o<W9)4f&6N)JZ<8{>m(D6$Tf<stoJ|CCrt6O$F^<^~JN9GVMeL z^~)2JWAtHpye2RVb6b}DaAU~^gE})qrK*i!N*ZV|ETZI=NHon%3ZyxQ)<WdWKm0QK z3N{si{V>$5vA|Q!GH;a=NF{*ox8_RGRuB`ji3&mqW&vJu&rY=aX}bAo`ug$iZoX+> zcb7-@x7Yp2)z?VZVv`CpF*4oc7PjY)S-Vzkn8E%r5?bSjd@*}uTVHR7Pil`qN4w~i zX{t4X&U5cTma<&2ULA)iOHv^68>xsu(XeBwVkKEdMTvB6NDlcJ9|*zSKKNoP*qF)# z3vnW<AhFu?QajfEi{uYFXC;ueNCcF!8V=H^4?mhG*g%txa5qu}I-NAJSx9kwrCWQ{ z4)r7cU%~O%^&mZGB`Fa7vSlaPQ9-*A$$_;c#dJ8ZUNZ#zh}iXzAe0i5q7aMHB%y-i zHbN5SWA1AnjW@W7?29OBtKIh3bXY>mI}EtLl!>6+4_d-Y#z!JsvcC!8%A?lq4vh1h zeJ}5ro`gK0l#(84#DSzrhfU_9PPw3<K<Gx;D1n;&BoX%ng8!J8AR$%5B*`oq4T6}n z7G7)x66C{B@ee;+AJ#f6!O?--tK$6#C+MI#lPjSBQn8ZMF!Jk5cFRmnNpGDYlnwss zvm|H6MBHPt&mXC&&a<%~8&i$+{fPZdESTpmsffk|5y#oJN|;ClA|=&eq@Jh=;xvws zs{_w>vrJKrac)($6c}+R>ugnFwh$8Tt?x)^D^`JUG-^7vUonF>P!{l{PGB-5C+(rz zxrcr@?LMshy7iLSO^a<v5;!GM7=5oOyKu7SBsCvFlLdblbAHqMv@=!%j_fxK{P{Mv zs<y^ECe(1mBFjEwbDS%~9KRrFn;W`-ZP%!>HH{rFZjoOIQQSU0aCE^d)dyoZkPGFJ zQWm8%w*ECHn?-%&DU6$O6krg=#c1B(>Z$VV&u(aHAZu8LR2mVp4TlH6yu}HB!IDf! zHxQ=o4!UU62)$>bS);*^n=mJu<V5I4|3sq@EjL?&#vCW>tSNXJI#8^vu?n43h@?Zc zF&+8+@bJ*nfIT>-7b*UMT6+#g-3bi$p~l!ONNVgbEA+-ask2v(FXl1eT06d?7D)gm z#UZMSYakL4a<#Ual?jBbo#w1J_4uYjQ^*}7VKUP%lt2?U7$E9LhZC?LZ8v=t(GqvF z%Ig*T%>^ySutq=MkVOo{%tZJaov{=rdyyQ8MD%Vy8a;1bZ|I(3xo$MKLU;a$M4RbZ zFDhFbRizec6GH>SN5o*>J9OE%nGG-OM=4j~9nYj&omg}3=Rx)X$oq)Rm`v6DjBV|Y zG<mq2K5!3)4I+*3f@ipqnGiE9vy~fhr6(%nzFi7%)vpl;=1y?0D<Ny;HLhH|KLw6i zkGlnQ{sTA^1-W1g%N2Gn0kw%zBd+&^42c?O^_w*kQ3eH5r8R5xiV?86=;GuSvh(x~ zpwQl>Re}(ZUHufW#>=}uYv39%;0_wrZqkZ$O=FPZ<hfQk8&Zc+rz&f%hI^g9{~7?u zf=hy4;JYgO1F-7<zH1yHImf{Fw){FmolfUWu~B<cF##%?WeaM%R09J=BJ>HpUQoM3 zt8&2u{uju?Ic@m+z{@dQ1EUrKE<sF+$lKjes{#m~<F=k4kI!0jH`IXyX_)_aYcLxu zc-&4Nza??p@df?f2Un;kc6SySSNh_yhqU2rl`8o0Q0FebDP_}SQ?`?&kX5<aR{F_R z)^Xt#kpKlg!o+1=IKd3RPsGNc(Gy*{LX6=-wtO5n!~n17B0lNREc}_bN_^r897TQK zPy55ojIy!;f=^-kmd5uXyZ9L!gSo+{>$5;N?|MOz*4%A5F{40tU7X&WE;mAa9`AMy z1+9-dAn=ES^0IWh@-}&>c=}^-(0v*6%|EzTZ=>v^dsKu~8zurL;oLD8<&~h~5VA_) zR{~agQVF0LX8|`l4Yfu0@@0H1p5WS2sHv8yO_l?Jl9h77*4ore9>Ou~o+6d$r6lZ* z367)vQF$1D6@g}AUaH$69IUUKP(lGQKWRBg0mA@J=~#sX<|==!(WP893|ARvSytr{ z-%88Bj{v7Y57O_UwYEp--?sUPYNxT85X&Wx&`^L&GxU?l<l-&KHtl#><K?7!h-<R@ zJJEZuCOu5ya5Z^|RD;K=4!@=6s`Gx-Z8b)SC%oDL45SHfXTIMJK@r}GsiUmJa&$g8 z*qp;6xT_(XYXv`f3qH?APBK&rYrIS7?u$QnZ`T8osc=Dh!H7ETzNsG^RRCe6*6X(x z)zA6c-T5i0%jWlnJqP1PAyhSJ^<jTxqKmP};ob7IH(&$K&(}%{%yd{OxIiX}5G)`K z`{0g~;6=_Xz(FCQqdujI`IJ!&zSFszh?70odl%M!>rR`dKpqH_Q?D-Y(2Uf2pOnYt z@hh1JWCMfG8`xwfJgj@}{Klxm`q1$2^@^JMs)NpuHT;@r$Ao+)w|SkYK@zF}Tez7= z44YM)fVja#FAd+#dcD)EqWZRq=-+uZhY)g<(8hjuRaSHN8dXsHRW-0p=uTTH5-PRj zK<(chYjwEh7qz5T5n0mT<fJA%3u@FWoovvs_y={Sk^ykm#r$Dl8y?JF1wNweCzl~s zC^t2-bD}rH1EzG!i0pgpSIiS-I*pMp6jY!OcSJi&Qvh#$_W`uUk{(^w(gdk)(gzb& zoEu;vsZ1vT%ew9?&*uCPo2Q{`dd2f2S&tDlr`|o0WB}ScN*!Hoa+t+=V5QDKgRdl( z?wh@}_p--9l-=Iyb-Y@02r>+THZ<PeU@#lz(dKs)?ipfCV(3aK_s(v<NC3dN+kcy3 z*=E;y>$D!x*y<;oz@Ha}&YF?{FX5Dgk@;7GD)kU4`Rqh;aIpW-5|Oa;8oI-l)52b} zPX5!&IJoxxAVw~BI5Fhj7M}NjHZO3n6TO+4CvDlus6!}61U@xhUH$YlrJgRg*9>p2 zQ|8C2Bm*Eu*Y@IwP<+m0T8I#vjUwEwJdR^@K$q{=UvZ_bSuu7WS(ZkV1)UlP9$R6X z^5y*G;=`Rbt_!7A6%Td9Miys#ME1DSWSGfu+Hz;Mpb>R{K7V(|mxH4r&Bo|_9#gF@ z$M`^%swzi3V8iO`{<MI3!?mB<Sv^6Jy>sBdPr&wd^S_eTVL6=V$=`D@`=NngDB+RN z@L@dAa)P;_cT6#Dj`{2k3!Gfg@*ISZTo3#2uY0G#ZICv|DamMJUwzMHMLjnI*T0&= zu#{AOoaPc3<6T;2C`JTSnd2AB=9r2!yAIEG-s~2Uw>KP&DVM#0z7{q}_9>D_A!0d{ zr&vk!70r1l&w~!R?rfzeQ3{W70$$h0>#uFAm@>Pa8`t&9H`uJkT7b|_KF&CKr`ahc zh0g7x8{bp7Ez>{IQyjeDb-{y>{fqX<v0O)FP>Tq^<ET4r`&>?^r`293H<lZ(&9}E> z?D)9TTK%ljP6J!7%m$_9<XN9)97{7h+^*8T)L(YIgCY@HdVHloiph6Uv!8M|*srYn zGF%@CC;$_8ZM4rj+fTq&UK4X)%ELP;aP<v)Zs3XBCL6wEuGv|?l@@oI9q_4wjN>ry ziBGN3PyEVnGJu@Nks}DZ(_=5GIGwa#&8nn&u_qJ&6K$olx$lquZoVH3|6QPe)-Hik z{KHL0{(b)fOaGsGWNhl>@*mI*kkBLl4>k?)78prDlTviDR4PG>fQf`DZOeJ&Zac8^ zeS>U=xJTk8QV6<rLbEZAXKi}CelW{7Udz{fA+<jXU-D3rxw3Pw=rQfUOGw__j*U`| z9uWrjnnqKpv4Wwhn)NSUs@#v5+1x?_Da9itW((m@C`K9|Ok(Mf^JpK#8i=z_hB~Ef zErlr$0|_jCSU|WFetZAOBOYyo?ak(ILhq^6p9-Ze{e=&aZy5DSo%Z69w`nJ|T)Hv% z4irq0_60o21kQgttjBnso0wz@=m3Xgz?a&PFKj_xicN%-n}h{{)%QiXH9mZXn3x?V zqf)jP9<YLB<7g(igX6+?5`G`r`~6C!TbyD9Sv%rV!WJh{(|iLLy;2=4oXKBb^4#rK z><9ecvr0LiGj9A3M}7IH%c1<&tlHZ;7`ptM)|M1G`+pQ_*zE_psJB$uC|1&>V!>MB zW+7G-!kOKW!8k&01%MP#)b-Z5%P$?*x6%AL=z=WOQ$l%}s9<<+23)F3)5H~?RW;Iu zg?w;yB<kT)!K64Y-Q}D#9Dj~<FsTN<w(eSs+`3T12BFAf&L@;z1XGI6Rv^45tw`uA z!FtzGSj$!qHiHalo?6N$mfn}@7rXRX2rZm5ScGrWVrhtG{MgDw`igWB`;<9OFh3+F zJG}<;Crc;uPvc#;J<(<#CiT&8%|<5-mfqfP2u#fSoOsu2y*95R?S?oXXZiq%RoYpc zTM&vrK#myg4D-l3WCIenwfQEb(++7agWBPxRjSzJj)l|~xOT9rJ2wR{TGd4~>@u+b zB%!oBI4ftyg%lp$aQ-z<y<$TIjb<UIog4J9rd~xjR?m4(Yz^KQC)W5s+D#%Nhg*(5 z{O3zj1of9Kk1CKY*jGH&vdlroAxSNxe<r6FRT#RIsW^5~I&`W94`;Qtyz3H1L>^3G zT!XA9JG?Y{$YvQ1F3PlTze+em6(SJquoUAj5vxcmYQlxnUUxG$7()ectJ2i0X(NTM zb|*@gv@o(}eduxz`PM3^#J&8R<B=*glxXDs90j869&K8Pe2qf%>DI<Zt!_}8?7iYC z48jH{ugLa@)cwi9Nw1nx?N+cghD>dJaEQbkf&U<3_JjNiMRfR`H<0=L+~ThD7kO$- za{{5S88acX{wID4QG4t`1?jdVULcG_Ror%EbV$aA`g6AukHlRzeWK{gHb~$2g>%5t zPyQ;Vw#m)$FHBQkkt@C5|FGpf6qwxos6aq}C4hkb{r<m&Zf|dGY5Jd~zO7>$e>j@> z_qYB$M>KF{Y?yowgF8$J&!*Ij_x(onv<;jwO9H1!d>9W}rAu-#I^1bnx!y-=32RdW zC?2r^A4*qOXLYAuUX|TPXuFpuSyXFH*0u7}_V%*>LGt?5!GTfP(XLk|PcFLcr=k?! z=jR?vw(s)Ii>Lawn(H!tVjP+-ja})uz4gb2H5EH=?{B-Ny0gunV=EE_fIGt$8jFDT zE}#Wt*>1N=KALCwX1GVyiHKE+-ihq?BWo;M54+ZVw9f$hv-o=lz;m8=+G6uZXWC4Z zRa;$-0+76V=^(A~+zFib>sZSj=E%qkbGXXE87mE=Nd1{#U2CDOmuXkO?XEnm&o{i$ zBlq@I(t4%x(20D{*t|=fS>k^7XiWHq=RPX$N2pRw41dzEjpw(nd*Y?Rm5tg`#|oqM z{aqS(W@{UP$^3LC)cC1)>TS#T$f(rD)7GB&b(Jo_fQAv+#`gxt&^n?2x##G+HVYM( zTHwZzUk3o*C_2A$4E}5nphA~dZk86x|Bxhg_e{1gMJ`=ya|HyX(TS!`*bqrWqqzY{ zM)vjG3V`c57hA@0m%!+{Le~bx*%-@7lT5oNtHq;V5C}A%Q9M-^?0*qBELB-)2ST*x z(Xs;L6<E}5l<}KQdFxJ$vYz>Fp24tv{RRj&|2BlP15Fz7#PI~moes37`$dCvq2^}o z(aw&z_#U<*s=PrH8SJ<xACOhyR#(-X%=w6Dt020+PggOogy*CImT0U8Hv<3X5+MW- zWN`74ur6n=Rw!2^v|Vl2BQHdEi;-qn{OfJtbX_Yl)fTrI>@u8R;4d17`&duN*b0`i z2wgDbqbz2B_LKF%^C8d$IxR5ieDx@5jKo%3!SW(WS-Gu=dYhPRh`SFwZC<g2$yUx| z2ABtd19sJ~IA5Y(P}c@hjUP#XNzq7G+ipZu3yMz>%B$x(DgFf`-)ATM(f1%_yf+YN zc54$)N~Uf<co}q@Y!Cph!@v-%S%027uBb*jtM@_?w|{v;qF#+1qh49Vz5F96eXJFJ zV+7))qR_)&HJqLWzvhXr?!k=6WN5%FRk2>`Bo6Ib-%~m?=(!KS2A&Ld=FUJJnpd_W z+;QssQ&N$)a())Pp{X8mU~?BzK(%-AhGH$8o4!nPyV9o%RAGO^4&=J>snh;fY1Iui z91KOut=4nk$?oY!MsC9v`R>F$p-)t=8=>c&LvUGt4CD!0PKb~6&g%BXW@~1KlQh2P zmPJ{?^jr?4(ZnQk-nY;%%mb#nV6K7mj*4Jr;9#VdEj6UQ0d<raL37ywbIAK5I{$DN zr9%7117NwcwHFW{6RLo0IN#z!iaLY0He1MswzPKd#uA_$JqI7>8J*oWUtN@bDw#Po z5Tf?4UZutwH0;P@Q$MCX$0`*{yS?^wl6bs`d%l-0VBEsI`<KxD;}{j(+n*nU;lwH) zZl~Efr6M-f(|4+%{4<yEZH0wzG{j#-q;8YtL<_#F*T_3QzP{flElW5Kf6%1=7^qjD z{0`N}pfJ^RYoG1<!O%bH1R2&0CJ)xP5*nD(#AXP0$yG+~9Tty(C6vQt!^`138Uu0$ zm#hvY5_Nxd>E~z~A%Euf2Li-}2%DkJKr|6zFn{fvOYO`l>wpA8dlsGo2dKAgwys8O zEYBC<@i6L)3!d`LV0BQZylR5yJJ}T)#_(FO(!zSF2+aMfLIm8X8ECH-tf4#!oKgn` z!b>siPP@gw1H-}3Sk~+}@f{6dm0b)r#y7^XPc)*S$LW;8z+-6@_o_h75@CZkS}s`; zsWL<9!7XYm5M!~*Kp=ibjXe@&2DpE;H%!Xu27tO^A!<wZN*{l#RF>8wO>BVNv;>Pg zgW-Wb4a%*zzgo<mpTZ`cv~zfPL+^Ah*oYZydDr(Sszcg1h(Z<y9E4V;fKQsW@&O4V z6$;q}{!!tCV$G>v>XncT0>;vI6LhmIo43O`jGuAHyM9VLg>)T<*oXj?g0F3jLkW>o z>hW6G<*1_b9$zA?hFL&F4&@){pD}sGQ6Vx~Ax};S2<Rb^ukWlz>Su7&Va?>G&@zDs zHSKmO9vU47uuGR=K|Ok*(twb;(*Y@qT)ec4Tg$&wKo9jJgEWUYAZ@$860HS_^?|Ot zZ=B|}Nw6UGVo{Q4J#Fk==zd6TA~ZK6LyV!@?}*V2xKCkLWbKwt^G1t`)?z6t3GD37 zvB<Mpf)_}}!P+AjxR7^|wZ9V3Xqn|;0NI7fHl^<q>M_%U*<yH>FK3Sljw&8QDlCe$ zN-UifmWK-D7aW-;6fU!yW{JaUhBRXkU1Dey4cqA7m^jv#Ut{i*TD_R@E{H(wjMZ(N z{QeE|d#S|!6GBGrX^3W)4db^c!cV8j<(EI?8xUjF#1{;}6{ygukf;JQDXG*I-K@`1 zN%Ri?jY`!O#j<QVy^89hH^pr%r`@?_S?T^5BNvf&WJ(1rVStex=GVFC5_VcMZ(Fbt zVbT|Vl`ubgcYi=X12gj=y{TzYL^WOqGkjX|TIlDTyWoJ7i%KB=LE2`7co5J+C&;Z7 zF$XyDpH3+-2_f-1p&-IkH}h!T1VNxZ=82NWKDSq!X6EK?XE5XMJQ>&iXu%4Yg@A@I zWEx$KV3W@?c*>H$h9fbPNzcf`t7KX}XKYMkJ48v$T!s-4to<03_44VF3>O<R!P4&J z-dxQWfs%$$EUAr~FUGR4b6_DsV^yTSOS%ZcMV%XFht__3&!(-WVjDKS?|<dyL~-la zzZ$Ac@0P|7bXC+tcvH7t*sjbAFjEE_ga^}o0lWcXLA_i7@E#g$8ufZfM}os0+z=0D zpd!`QS}i1My)ynR<+|V`5%_iyC<-UN3L(%Um#_61GzYMj)6>jW*Jz+eZRN)+<u%KR z&T6n9t1Iy+n4$NW(Xr^4tOMhEhbm7^JKBo8PAP8vqTrUb@bbWM@uKHP=D`a=E@))w za>TCc6Rr7Bp~gi$b{nqiplj6qimo^iIv7O^ml+4I`A19@K8R4+`1jgnklNy!_rl#i z?+${Vc^mlOKVI%-qThoZY5jwl!Fl(Q&%%4~0}fTT!2mec)tq9+NOED=C$LwX&G3i3 zAo)bcdan8$Y`^<r6T2xAn?cA4AO42&CI>M>u0spurevQ8W=cDZfGD@604XenBuKCe z)k~t6KqWk;s|3s3$R^=y2N$h3^5S?QQ*4p9VBR=thQyr?dGYrQIB_(qKRi(S^~UY= z56v%Y(<siKhmh$+2aq)yGLczuYB3=ZWI3UGz(LXSH%R0P7iuxI4W9|nUwBl>Fa~L- z-%`C4o)`v{+h|>JauQc?T_S1<O_nck=EsALyRn|#@nI(_Jm+QnZRuO*r#5BCJAGC( zkfFoocYZ<kZTTc=0+u4iZUT-x*9#E1e?sy$6j-*C%REQonu6P39@`dwzhSaXk3>%U zrs0vBAZ1z&|9x5^ey~B@7_Or6rU8mB1cE|tEInjS1&&GC;k1hPR9SYVe;K>^6##u` z^}tE)bNwiNZhp4l$)!M@oG4Zxv)0S*=p`I;%N=&)^AUiTyp>=L@?OSnki>(g+77XK z#r*e_CP3jE-cD!>!XIv;-I+0cx~6!bn9`gZaaeFURsj<Po`(#??n@Jdu-R;l!pZog zgC4c%m$A|ir|XlAc8Qxf=nhWw04T5Xn)SjD(G;xM9_8A;KiGF_(a3zb^kn^=U6fUu zt+s;I14E_Q5b;dGbBtf;X~s|UP6JwdYc*8Gfhiowq8~KD9eeyXQ4MU8yJ5*kPRcd6 ze}76I9$$Z7o+68nKrZy$e!FYTCpRyg{Q!JlBp+apX#x;x$V3eazV%aEhlVeF5t-|5 znlwN2Da+ZJbAL6hAhDU@B}Pc*kWzzCqbAOOh{GS-*3v&<;RR=GTs<`FGpNqhy8}st zFe_M0$f5X4fSMO^h?<1DfCm*94=i`e!h1Y+j467y<5W{LLnbsWK+2keIxHD=gyQFt z&4M+oP~|e#$bHS*uGLqSDhft)^%Z9D$)HvhC_)Ew1x`pkn=zius6FdntFT6Lw2q8F z$zWQmMe|n#TR;_yD>5oB<9hTgy1yRZ0oQT3C#5bQ(e^#jm*BYF90RFQP5g>Suh)|~ zoN6*?;zm$QESlO%+^>nRkecU`nsP96mTg9oI55DU4=T2lmMaqn*}>HZr(zPHzYUq) z9PLuwKJ3}&3qyFY;fvmWy~<4SQDW?=r*40ND+NxzlL5t1cDr-fW@k1S#Phnpxnn=4 zPty}w{`gpD>BzbUoSkNeQxNs;_D`5f3-?o*WPLr?VM5msV}nmq@B%buI0t$#HToC^ z>|*MnV&MvYwPb(hX{;GNBPRED7di@U|3WmaVGG5@PWQJ+*)EjSg;<Cx#)ZcXPf#K& z-zH%Bibo#&(%C+Pj>I8q@Bqmc`e6Yu@kEPnK?~K@>g0ZRR`Cj2$tJ<A=B$D7KLO6V zU{M|0*`;us_F9A<ZI`Kf*%i0iTwp}X+tTLpOVLp6mh?)BqAQTlx@9isR!0Vgc&hG& zM_;AR`cZtsxUATP(EE}|T;?n}XYk~rmWo>6!Jt7k<xvV*CLT$l+GLRoHnrtJlN4r8 zAt^elE0c8=Z`Xlrc{db2AVjl&MH6U4;sbCi66u%MgZ#1xQLAN+X@UEa@O7$0b)qU4 z0}F-VK|ac}R@3S9G}e$5wVVZ=$5ij2dNFg#gLrQ~!jO)V6!vhiF|NJ42Sa}!^b>VE zntT6<OUG`Oe+R~>%VcBiwD<yjTnA89coSp(N)x>wl2Y11hhwmGzj_!@fnR9wAB5;i zTeOL&tsweoZH**utAWV;LSeaR+C)Ao{nWAUjWb}N%E>_xu(?-hBT2ekT<lOaA_7rh z<fMZU7(fs=fX3o6FasfnTiI~ovyADA)mO^XZ~MBCHLf#mpF_hJTjwHgV%>bJb8<b) z2ZC~40J;IbYLqzjY5%TCeuTOvF-^cfl~QHYtiwhKZM(wOeEfuor6Ak!Tf{)zuN9DB z*=+k{b;KmKKH~sZY&a!^hV|5Sh}X|JjsQekTjn_|LRz=E4qH3{;VG+d!sv(9+yC<f ztM9InlO8HNiO3W_NzDD1hi!8rD7t~veFDx$)7?&j<wJbWpQ-b5=;tzbAC*plUgF*2 zyN1!*0`5rF|L)A-UYy${D`HK{o88H->YQj7o7iNT-)v{C8yqseW8s_N8XX<kN@P#Z zfA@h|hMlj%-uKA%i={HxF|j@z{~cw(ax){n-uH0{ox)vYl|#}2y=jI*A>o;rvIA#s zLE%?_H@JPs68DZw$Qzlb>BO?=637Jt&z5xsBz-y0Ol`w6I_GZHgwzSLdPpql+LGu5 z*}rI3Je79!wlGqFq2ssMI#37CSoFeox%u7Bc3<vG4@e0Qzs+Fk`B*SQR1|yHF<eiv zF?XMaay+vJ@@Xj1(^HNeis{4M7*SW=o2^TKoq=Tm8Fn8g(vH;m4n*hh^AbaY`#PRS za#bMY9hxF|$a*Xbu(?yF^((Al)+zKi%?^fZVe|<9QKdk{IU4f?ug)XXJ115rV>QTR zvY_0+Ps<)7kp=C&WVZ|9au|=FSk-MC!`zik&mZJ>A35!NfA$}#{)*)I%g%7FH629_ z5KkUP|2C?etzFOhtyf+uyeVn4ofA#BQ)#``Wrg_QVF5UY`ShZqcV&*)SRLcr-H=T@ zBO?IGg0@vXIo6oP(nH%%du`6OE<c7&E5DB+hu=)j_JFg0=};2KFB{vR#0TirO|}*% z4hbotQ_DbHf~RtK>8W<$j`<~=yj#hBJd|!zxS<!zaCO~%Am}2Ew1ske?SpA=ZMN=T zA{sgcVZ`md?l(y|!DV(em^br^-lysge43>DcmHW)?%-0{d_^<(K+_ct`vGSAK<C4r z&x-%^;V)F2S9OBOI=LYD4GIKzbCzcBX-5V;c&|ETj9+gu&20jm))mI;rq5C&L+{)_ zcf5Rjy?l&#@Njv2{BPus{Pgz9n;HMU-n<)rcEcq2N#G>Z+)9=dx7HYT_8t%oBxRp1 zz!23lHLcWob#B6P6B=tG?!kM`{hS%CtA&W0GqC4b$Qm)Cj7ojK#D(g8Y=_$wb%77r zrxRjNEI^j^LI0F=Nvs|h+8B64fca%k&Jozfy5lqs<^7?7@DG<WDu6Oh=Y!%PH|l8F zgmMeEEQK~&iSq0M0;*y1dkm}s)_e2a=gF{w-7)7i@M|AzKdAk#<spBj46hzM%M>^) znI>2ox#b0Cp&z;Z?unnBdM0+j3doqtOnAJ*@{|qH%ZITd)PFmbgwRKU-<`SGhzR?~ z)ZSmrh_XVEWl&`td{tB#D!6}f#YuS{1N&xo+*{7N8|z?qD;=-$3U~Hea^prw)x5WQ zDxyT7=|8rzwA_t9FVRrm^MSs`iPifL!9<}_SrG_HXIqWHW^ls0HHka8ffPYJKFTyb zRvMfb-pE(gy40z3sL4?Fx9g{v7SIIV9aaO2*7H6~>lb7WtV2l*mAfwRnhn*j?k<y( zeU?42w8Xp&<PXIhIb6_&k>tgPTRw<vF8-7U)7vI6LZoGRjNnaIU>;$eEOPT77ZS@k zigs7SaNhrolI4tOQMu%teT4#efU{Z5U(6!$_yBuaxNf?uybWmM6!0>OnJb~T*_PQ7 z<M~NH|NM^z{p}^s#_}%?!4VD!2;=`3{7gNJO&whRg-QHJ^Gj8ebN&}c)bpr*#R)n2 zD>Ge(JMWyxF(=aefZe$IdOj$kG$I2`1E{&?*TZHPED9Rc{DKB%;@-_>8-YhZWP4|K z(3E89>gwFv*9C{3R8mt@)9^tbJol}#&vgCEAB*%a?k}>5B1Hshl57-c8SlboP<=wq zCj%#svw#`H@RTs54mNbwR@&u@LqfQUD)yD3wvmIe+LqBEhdWKqE6gO)3F&>E;ojKZ zrY?ctfe}}br((ir5W2xIq!0+D+NDmW*i9v(vLFjHO=CLgHMFP&%8)cNbnw=)2H?tS zaU8?sJ3^-La*EPaf3GYq+D9%Om@c;`_xJAo@;J#;SBW&~lnVh~0|eY-SPeJFv|+V} z?CMIwcCe<8NNl!X5sCgcbiZ(R4Xtc1w_oYAr+4A=9`l<l11@`L1h4QQ!Ju>XUICR( z8P5r<kQ;9X$ZwC6P{|nHvu`vZs5_g#Oc8wRqlKQy-(nvkFS|^#aIS6orXKfP6JK;U zZ`B2~zU%P~uEH*p5zGP%r4Nxp$;C2oi`iV`w&a80ZQ_ak)}Od;23-dtHdwWCLp;8{ zeWOK~6&qv00tzj^5=$&TM|wc>YRD3NH*WH9_nU&;GtI#*hip_eg+~btOns2Aep@!_ zG5E_tDQ`I5deD9X^Bg<`2*11#Rp4G-IIbG`d6Q+04J#b2S4OsNCX^a_n&A084HPox zxi0h;Tt}fSH!hQ16xlEf<EBU^<Z&gE6l;*)iF^d(nJ24mCJ+L)N}9DpcY@IL0u};u zDP<1%Mlez>T@svTY*>N(`FzX=qaY5?O!^Yeq*~2l>vJI~6eG=}mL@MP+G9E><Pj++ zGMaDKQn1B||FYx6C)}huF9nX(^h?W14(=A&+}&+K`RF<XVV7N^!Q5IGVBGa}?deou zc%j|Mhr8^e-ykO{pw6cZ_v{GED{U0DfNiOQ9lXxiSmf!Y9684!h?-N=PKABo&y^AT z6bogk&bI}j4Fpzlyxmv`t#elD`WZi|Er~}eB9<Z9M~Mp*cQ0RGpQOAXyn>;CD44GZ z1G!<<TMf$Z8`F;3#J+&<CeLH?VtDfR&R#|MpqF47noC0TZxiLWw39%;Vu*<W>xx7@ zs+Eki=3S_UW0KQV{Ogs_Ns|sr({6>?Gj=7K=K{=Uk9u})HwaR>C}y?%Aw*n{1rycY zqNE$C8lDx;3%Nc{>=LdD*`h+8os<joB5b2$otTVD5LrUJi?7e(@A{@Gx#XYf{Lz)X zL0cxR39}N5|I4g~Dj)xvs@z>ZBi7CL#pN@QMJnx}2id?cG(!R5-oI4g*-J&_^XxNF zR*f8Qpbrw6;#V4k-t#*J!wr_~qJ^QXLrlF$FiL@Jt9QW31=^zS5KZjGju4*PSH5{r zX?hI2cZIauL@ay!9(@$1XOt=af47-%4K)bCf7?tK{QnSs7N#~1|1rAMxBqY6*{Z&y zGx9hDFP{q*1lZkVRE^}^hWNsbDHfPkku5n&Wuhud;oVQ~VY=))EcOacBwg-}->a`g zta$Nkkqr$@=w24%%o~K-H3X?`$WnbNK;&3Mu5sQXrKYrkXm+*Mj%?c5pvBaR^bn`A zdrtO_^!`X9lq0Z|*o)2t{{~S0Ap>|Ot~nyrX=|)nyGVD?wuz*zl+QudoXb6(Ri##q zK0yjK`&m>j1r(4+rfs`|yfrxeVrAKpZoS|;6BX%b2<gRWo_DZ5=TL?@FY!jm7|?OB zii9QQ<MoM>3cbRiV^3n;q@S}atq{4t=+=>qI!+>`I>&MHQJv2+(v#I0Lk$m%Y%k9M zLI9Iiv+ywVg7uOyTtBbfV?+ZTl)0N9M~SXaImk>!QyYYJQdXHXx8r4qc=l90wW1+I zsX{QBl-oDC3r`T#kKE4%k@me?xNX{P)DOhgu7*iAnQFt@RW9b~30rC^Q<3Ze53>Sa z%;or+OrwHwg<ufor_wO&GzN^unzmj24s^7LSgNt0Aubp9CK-vUshSB&4WiDof(6yc zb~pvPyHJC<+4~14UqQXZM6HdEsM?BYr&i!9`5d%3NER)#+lBU@8MrN_v9f|SAz`@{ z!#1E_cL|#kH5HN`fX#UI)-;IYqlZN!XcI`yyg0g!IKvTeABW)lfZfMp)ymT_4*0=( zd6hDMrVpaWI06-9m0fP8-?xlgJy0Gsk9i%Q!eJclB3CCEHNHCfhAAvWp@izsHV5U; zow6O4L=`!630uBUViEkfnmk!1p5xYF34Z%>CA<IhDFf{cKpGCShQ@P7EsMo|ihnX` z4Q=({z0`e0Mq}o6vO6tW3S@>k1>d{iIGvuhO^C5J3n<Hz%`YvOUI!VN0Y_rkVVDW_ zwN6oR+AT(7_~V+ejZn`ui+g_nasBaNru|vM6rVbmV!E6GpJf;nYX<v?rt?*u-Easp zPS3##5L&!nW9jxQemxOAho0o;CgI%u(mY6s@n=oJ&I5|$i$9tk-2F_3NVF*Rbayv2 z`y3KP+kcEgNb#IsTMM?xpYwmVf^a}$`-wiD#`Av^u)iU&!+iAl`}}yz@fr?}oUce9 zW+1{Oq!nijY?D1M*>toxL5SdS=Z#un*bQdpuY-JY(;T*I&da;kQ?VOPC+sFu(5KQL z+IrsR3~3uh2P0yNi2p%pC2lRK$~)vGkjDXe<!znt++Q0}3-C~#{3K@i_-wL05+j{= z>D4mYA<<a1`E2Dexyx<2Z6FD&(1Tkw>={WMpk};>0-*B2*aN-2+3e!=l8Kh?tR~{` zv-Kj2k@!SfE^W`g_>SeBPVL2warFjn@zI`qqqXH2KN6>;+HO}gY(lrUJFc86G^;c* zG>$YeACi^1zW4>1cYx8*%uc@yxZ^aDJ#MW9rry9gij)0sLKd#H^S<XlRN?ubx&B|c zg2g`<^FQ^BZK9BUkRVd%?I#Vn7f`H|og^>o{alHZl$QNyKMbhNux@A98kVuYcR0A{ zraTC&eWv{me_4GF0}&uIK@2K(I$fc5aLt6-5Jv!)bp@<c8FHwXAgV!*3Jwpjq6*cb zMv+(utW8|fed4VIO(Qv;>UQ9b2nq@6%#INcY&=UrPu)uqwh4tTgA!Y&wqTGH0$0Jl zBw(RfAUaKFmSF7)#-9Ls`c4+5Ctv`sZEtbs7SjOdToBEX8oQ0>zf#DyAuiLt2VDwp z*yS9yjSB^h;BIOIlWl<?S`0gn516=+<-ik%QgO~svkUX@e=Onwv<+jo`2at@??+z_ zJ|T=hciI=Xw|^!HR-#KgZ7)dCf^h|D8A!8OA_NA#w9^&9x-8cn{dM}Th6LYOnVYhW z^pV8<utK+MZ`ruT_jb&AsERVSXZLfP-R=zEwylGo$t>UUo8OGGM}Ert`eF98AX0JH zMe9(-*rB|UcrdUEi06Cl^FaIG7cSb_KkDhpfq+Uw{|A7uwKp;SzcF0beBaKS?WujA zb^YtfsK<X|P;c#2Y*X2%C04KPk|J|AGf$XNXocBV(JE0=@ZHUC?fYJV1Arty4mUDe zSxz&zB}wmqczL^TA+IBYzd;*n8oPP(qimbFJ;D^++}zyV-L0NiYZqeWR{>=(J&ywW zyE8NAV!y$=w=iG~QevlM=(1qR*j;<mo?|O!{FEml@+ZV?s;mLgh!~Xc4as#Jfb9rb z_Ns~1KYptmUgqWsc#j-_2RJcJT?J7UXiva#W<aZ0?-Z^fH#$&>e24bk0k=K<1B#gv zP3Az%ajeFlTD61Es?IGty;WC0^d&3+W_z4D*_Ax%t7a6vAEdAx&7aFp0C?Q1s~agP zuSYMxl2#?t!+%jn)s$L31qD;CX?}4me%5gKTC=leC7#3UdClm-@i&`~htJb<U4E%s zt(z<Nbd&PURn3JJU8^gw3a7Ms2erYUvPz*HTpz49nx(P@y9qGW>DA4m364g)lj<rx z&@|IE+s&iUYmn*YtfB1s$d5+VZ1Os3j%X8!{#}|-5~Le)MyAZ%!M}jbQC?4db-9)r zn8)W&D=Or1Z@iGa*lFp<KZD;I7uOI1l~>#1%S(BiC7AU}c3-l!q&3#^h;pFYOPi)m zwW-$6%2uvAR)CA{iMpj~pY;r6l@42ao2FZNh20;a3!it8Us<m*Ksjv*Z<h*<d54#t z5DDZ5I&98<Onm_(G#Vs6yIX7Fb6bMA!h~@)^^c%);EMed55l#_qIl`*jpI%61ikqY z>6n`j%BFSji4Kq#KPd7!)VLdvuMqiZ4krejk9#G+Rr*85J-VQH;(W6<d7vSkDI<92 z{c?4cC#9k})4<h0p2V%D@<%C`9ZQqE9N)ou-4)IS3Vae)w8vUZSxDP4+y#}9{X>du zl9pTyqKj~+*vLzGtq!2cp|8A@zuw+UJ2OG$PsDx$zsgp|xOu4RSwW->S)Jg-^)8^Y zB<H&T1~1f5IXiJ}YX3w6u`)2&`U|`6Y{hJ!)NwRIt3NAag!0lD&<l)DLnsNydsgqK z$lf*E$Yf#quJi}sd<;W621VyYG-ZpgcU-)moKVexuf+znns4IGSaF?(33kVP{k7b0 zOhDXU6!smcyCEDmt3Ktdkm$bye>+#r0dZcbLSBv<S8%Yl>(}9C2<#0^gn<UN$+m(| zsSi2cHF%ZN1-4@=0%>KMv@U3NIUTxGA0yD~<IT;_>E-0ZU<qagfoVLHHbq7LdmULk zM4?v<Xrc4Q<$J~f5NclZic9Dfi|;1|I?rBzk#C)?>X8tJw9xKf4aeqP1F3sGe@sWm z@8-{JH}(qr-G4(%b9HHdeAwPxT(ws?W$62SdzpPqKJ4obJ5@j!;s3flSLYckuM-Hl z?e%+bF*i5Yl&qzDZIyTr|B}%orzIX!$=bOE9$@S^3F`&U2UQMl0yRmo0My9Re1Y!2 zLlS1hjL@;7^wTM_25HDhHEyKMVV~TeJAayh?$X7gY@zkW_Pj#bk+W0zIVe1$N9=~_ zwJzRe#s7*A5>nx$s+vOaxdw(r3(ycddzye$Konm4l{0@Uepu+fw1``xMhGL#gi|U2 z2sm`}?2`zZO}7Ro=5dzH!?lDyRsZc8WW+4WW{Z7*y+dQbEKap{WL0@bYZ%{*|97mL zQW4PK)VMLY&UCN_DR?moF%H5C#W}8Apn+TvE*U6`Q1CDM1Tl*)$0;|;y`S1@Ny;Fw zz(!~_2Xf5(ckv|<Zz*yk|0FIiGJjQ1<hT}*J($s*dD6$^?tRw@VWpy+7Pat_C@Gya zZv4<S%cr1MxG%()6B&I;nw$zQ6v@)0_|I7HBUi(>XImcxS)kOeKSESOdrkz+#*k$5 zu=Z}>6%9V4#TF|swwvCYmxJ01Vpw>l?)hwP8)qL)&SvV(ElhI9;P)ugu3G7Z{c=(N zucQI9w{)E{+2V<ant*vuttYa`dL|p-v+49??ZC)to&eqV{@<gAy|M0%Ec>RiqH31U ztLv6M0ONS#W}LEY?;KB6fQ#@?e#Fg$edd*B>h|1;<bLzTSOtJ!4w#ktuWvgL{0kDq zUH{<^BJWoP1D1mYTW)1q8)<D)c)nm<EX9Gv+jWSnC{iZ}uKkZekN$QYqR)=ioJ7n{ z*%(pu!%F(z1R?1dt<Z^}{SR3*T{hvw4emx18_;M=;8V|^ff5<_F`~)yJKo#3UAAGG zEdm_ia`0lw0X|2x)i%{tXX8t7yh*;xL)D0$e1B~3SVy+))~_vAJMAG*5X31(jB!Vg zdIzETfz*-fZp7W)KVJ@%M?Q^bjizSajc2C)uX~=}2LM2v;BKnNg8?^VUlJLroVtQz zz$=G@0Tq;uv);Z?4b55%ky<oKSWYzAHsfkf(DVMD`mf*LeQwpaM^n%(GV9DZMrCG* zo?27N@AHiDevJMI5fG*W%NfuRP&C8Cd5q$`YykZjiqT)!4zo(Uhi+jC3?F%J<QYh- z|3>sP!Xj{3h%Qo7rpHE~E)64udIf^MtKMRVJuu!jgux)qIVg%ux!o8v1LxJ&t|LHr zXl`)yyij=2c5<>4Je;$;yz5?|@%OPD0k`_FgBcJ<Rz-Ot(XgH_Jy?QKvdLB`sB;+0 zj(@Kb($TTnHl*COs>n`vP<Ssaoe<m%z2?oV+SCS}nR&aI_{x+TW@22U^y<UHV;z~e z;<S?Lw3^&nxA)Oys(XcEi$hTyVZSIOpNAA|t@VS8(8$TD`x)D11D_IA)iPHOxxx0C z7RjOm@e;Zqh-`ndBAb^&D|H21E2bp7P3kBHsE~oU7EB|@gtL429-iloAgHkY5_5Pe zXq!m-Z*aJ5GB<+r?L-e!6t5HKnuIgQqsYfoQIn0CYt+DZ8~138UHeeRexbxw@XB6R zu%x#`@FFn%vBjqoi<O{H(B`)Ue6P~(+V!Oi>blmAO-4al+l<S{zz9j$r3Odwir0m! zCCn=z4}TIR(s~`ddgSc2h}(k#wKI&UxeFzxxZR@cukv4(PZyu84H+xR2-CP=10nha z)g}BIAS}W#*~(+*gHK3(Yy^1>vS>pVF9b^Z_SB-M5H05CUcILjnZZbW9=$+~J>%(^ z<43H@^Z}ORMC$s6dqH~&QaqS8wX*9nWBN7jWA+f@3rk*pKqeU7tW(y~+`f9LXo;HZ zV?DYW1rqpvt+b9-&rX744C0$$lyPFv3FE17M8soRtq^Ds_F3W}C{qWu+oW;oqaXF4 zt9IEWLuL(cDFJ>mRy1ot`IxZ76@VRzpcrOMmQDzkno>D~4I`Ct(+KgWeEIdtsPc!I z^(e5?)a9yL@G!iYh6+bUAn!DfYTifKebn%VyZvtgOw_aLe3+O}pm3Td5DiEx9}iV> zliE1XtAgan^bi-7==7&Ig~n0r%?#-fWoEP3<EvzP=!ggerCNdHNf|$xYE<?hU<#2u z8h7#iM;9y2g~!v`T8b@*gKmyHsFK=fSFIVQkHgDFWJWjK`62(=2j<#~$Fb8Y$6iTL zVz#gTO1ArR%zU7|)6=xiW?p<!iA;`1E|$lDmivzULSfMcu*V5%vai_jIUjPqFn;l0 zS|$985bkR}tlmZg{~F@Vd10O$d2O+IGSu-rQLTC`?JV3`uR%KKJyO&tvFNTA&39!2 z8P{u|@Vr-?jz_=fEac*KoF@m(4Caj>Kl#p#e%*v<IQUMj7QhNvhZj~9<AxX~3?QKe zx?F1uLFNWgmX=?KVW6#_E|G$R8^ObWqD3fPBqNEnp!ZGtuq5N)S~8*L{d-07$N~t$ zb4ZFOWK^Sg)y;cQw?N%2J$SnWb6Cz?RB9i#4H3EZoGjGLT(o5WUwDpLn$<Tdm_#i* z#kfd*EXdai{(!{Cqw@j^pQz_WD&Nqy25guD)nE+)>78cQQse*O>Kvj30hR>Vwr$(C z?Vh%cY1_7K+qP}nwr%&$-_!0t*0oOg@<m20Sw`I%PQkf(TQ^m8NqWzsVp$=A#9Fb% z3_jIE*z)eri`N*i^LZJyhxPs%K%dai0tVTJuW}$k>>_^JDbGzt@hC#<BKtZtA@nrD zOqPb3sSFKm1g`bqjyl!<Qw>Eu_XunkS@Jh`kaS3{4|ndcq2PK0MAz||5KknD1}<PN z13rra8Ie9_6*f`~%!hK6@%<<yr*Q&uQ3VI8#0V<Inu0HDp{!YI*f1`A&LS1U<Pl4q zZ{r#+TULC#XHjsu0@7q#F!g7b{pc&g4V9LLhPqCe#WG)Eg5uu!nm(VqX<2Q?v4j86 zLXRjN0b4hg6ERE;8)4+Ph#*Y2$8@xA@qq~5`~)j)qM6yud8|nkaNcVHw-t|;5LqHw zNx^4n=bxLmINmf^u$VhgCCEIc430uKy47*LXPcFTxDuZ6T^NV8aFcxQBz@!#W-x<} z0OT0fomzg>l{3IYk_ZHE@Ot!x$rBjyQanhraTEZazFFOPWPm<LRQiez&kGUiA<8B< z0{gojJ4<gLP4u6hzM}>YRk@>ZC8+CTXdZx)sRq2Z^jASjaU7_?G%;~VS}B+JCTrLk z{@|JgZzebCicFtjm_?n*NDPHDd>g{Iq{CsK$aqBSq(O0TGWyny#|Pcv79=5G1&xp} z$xB-%qV2|OfaBIyejpJOFF?>TORXReiR1u)zl6q;|I466$g#v^CDfaZ)LKlDZlI;d zX_#*L1DlmL3jgBs3nX6J{c^K#O^rqRZx{dN#Jl!?(q+DFwp#O?cTmY4FJS?Nssrg- zg*L6HMP#Uqo`pN?8X(zA{aJ$Db>x}L%{I`bC4U5u#FT~qJXgr2Nhwqs*OhEUAGGp| z?L6IsYTDP5#f+4B^kHDY01AJ^^3ITK&5W){yuWrAN}CRo>>zU|0A?b4lx5%HijEl? z?|Ly9rHshdms^_vJG?_=2o&>uhW*Pq<lnnSDwQ3p*X=!jibm@DAwH8|^m-3=V7JZN z)NVSIjC0$yN>}hWu`3i8N}s|qPXPZVq)UkmgzmP5O4T^j$-@i!@lz&7K-w~O<Y$?U z>Yk3uj<d}=o*xSc$55Ye)bZjeJ-tJ^@aMrn!-`o|f5WbB+F2y<%ZddGgflAu_SiYH z@JX7Xx>K=>y-yLJ-`nG9s#JBhS>EhAl8}3GYxhNem3y9UG1y+v+=d6EB!x+>U%-h* zmoM&B2c<83jMgoF(3s5ulG}p0*R>;&3c);+#BXT-1?EV|eXvKC2=<?easrkDo?||# zIDtUrZ+(jUymDkXxP`xiBcXDm6Oz<Q8X8sCmwCnxkSTMivexCF*S@+%#YlKt-H5_n zo=-5ghPx%Iz8Nzvp;2f$m}q-roF<+sIf)TUN-HeqgrKOD9Y49%$b}qge139WimfXo zeP~rZ#U-gl7zV+G!Y`Y*pg*G@t0D}E0%gb-ocm3Za~u}#Jz|Y^E2a;RE8HIjHS@B= zqk~9)6%aqokmnP<lP5m3L;YDF+!mh(b|Ug-L>ep!5bVFa-teF4mGl?4#5<-6mAllQ zgSX7=m8|_&rPV<X@Z{EKLwmn$T(_XJeq`r|X)}ukH_y}3kx@tu?=}LmK1I?Kg3Rp0 zuDKDAY3>zdFNsfV)LNl0B)vdlrS0WXxMUtQ!!6CH-0NiGa$8a9ar_ryK{;hbX6)#- z><|5i5C2^)9p5t+Cr^@^&sX&WE>_jB4tK3V-k!P`W$^jys<M^{FOu-I{e?<%(Y3x* z?gHG(w8Gle@*kBM5?<Vp8fGh^aS9G`=;^p8I343l5@Qo0kF5p_x8l|^B$R952XiUc z&qS^5H#E`0BD}gw9O*<)r5#G>cx~IyMVzSu-6nbx?l?L;j@+U<f_smOv!Y{ot^sKo zN>UzURw*jvIDjGkxH9M7xIOCPgXn05r5DU;qy^Zt_0A4DQDhy8f*xemCU*mzjjBcK z7B5ur^Yy@$n{|3$mWlG=j{xjfT9Dwu7&`_d1i=194QIDPr8$AeNHt-T#*C5Bz6ra4 zOWvX{+#X-vTsWku962h#*?H6|qW(ZQ)!zn6P2~kyy$11h1JFhz`2J&!3h?y^5GIE4 z9N5(U`*aKJr#a6CvWo2eVg&x-$7aei*GgL7=_V>ZqCP6*DK~k%#rpRKF$Ha?24X74 z-kU3FSqWjk(Edr{_mo(6rB=`rntG<@VluJ8ZbR38IZUl0xd~NnoLu@eg)Tj24H%`I zICnJuw{SU|t0nY#xbEA4m+7^Ex2k#D8ME2cU0zfl$tqYj4T3?`oa^d(NE??q26DwY z9_oUX(V(=sfYLyt)?ax3!)C<XRwKh+Cc3jU2dNnHUuMHuBPP^e9`{2O;czyMJnT=$ zr{E9GPE?HAB^`NgEBjG$9#Xo#tH8xxfOQ`_ZXI$VDyw>17^KSEcw-L(E0Fq&$dVS- zX?4pf`W*mE-@r;qas0nL%Os)=pjirS9^bEBlFw>~Cais4S)M-m#TCjHjuZFQ`hf<Q z0B3;+lkL5BcZrQU53V^-s_Evln7Ew`RcO75`)fod<nc@9k9d#;PQMu*TQ?5?YPAiC z0=r504~95CXf>=)*M(4y4$=oR@01%&vJygQLlLZ*P(MTLiX$DA=yL%@f_(m^aTx%G zldkw8)3B8F16L`We9$;CTXHsD=Lb*Eu&+|tLl#I;CH3(^{@R9=9N=LI$}8v;S7>$P z?k7~vDDa@u+5EoQMys>+d*mu8i-r)+?Od6HD5GHuZx3%fo;R32mYuRiJ1BPkQPK@t zm4Wh8MmChri7C$bQ4Aq3o(v)jv;`;@??(hAj><XpjM){SfgyRz9gEFe<>aBBFH5i) zLVTQ4d*ycbp{r@_PPX0o)1PC&YPv}^>fo_)6QgcQGB-n6bY0dgo>^-|As}UmK2b6> zo>ovjt3FWSIuRy6oCB+x4d9jOoi^jG{MZ~PpD&|IAUDdL%Dg{inOqOXL&L`mY8b@q zKQMA=g1BDY))YBWYcwrbYs&gAX$t8>o=YZrF3~d0pZ%{(9zlwem1%MqW8O_U2v?M3 zfBSN9*Yx=X@o3vGdX6J>)IATtr#yM`hQx_<XMC2<dFL~n9Gge$H`c1<I!B>oJ5>0K zKL`VQI#ze&T$2RypIu`k<bG@AH(r{tYx2(gktCYw!B<yT!IJ>br63y>B)k=(V*ME@ z=Wj%YI>>d6({Z2tz(l854m1<M2UR=&NK7Xs3=bj5V8%)_JpjfG@Vv)B;Y@Woa{O6A z01O2M5G0oeaAoa*0I&K)B>Q0DMZ}Y;+#xbCE^}Oms15Jivp`f;t`SGZLgD9iNO2__ zxI{oF%$^6xr*Ywsa03?FDLTL<8`VB_`#abSR5SSwz)Rq_?Se6^j6pV^EbNPZN~9Ny z-^K*8uV~)m`F*f#CbI?u6iu+5=vHU%D>$9Q0f-{f2_DHqVi`KhI-gNY!)Zv|X=obz zG#3>B5VB{msX~>&6a0HPWH2*^Yd3RvGv5g-UO1?b%13E7qkJxO+Bkpa;{w51@o|OF zK*e#6Ik)T>(ckd1kf($U&n@YkSOweFy&}7(m;fe&eu>e_@E)CQsnF$#@kLkCei?o@ znK|Tx@0ow-2G{ytj^SGL#zeSZZ|L_u?BJQTMi&`KietmG|K1>KQQDsFV%I9yAP?-s zL3JLmU`(d3fV!t%h}_Pj7Ee<h-5O8)!B`ZF-6a|U5&2xGk{^Yf*!LP>%qijeF?D*L zB0$pYxqu1sy!Q;I{C4)VrB%g&w>8b}tU)HT$JXOZzi~2hFN#u>v~fpaxvX_~d&(ln zf{jjgXjxwev!&P;I0(ER6;yq47ufzqhFaT#lIJYnR{)yH%1=*@(+lB^Yz&m9d8V1& z86=8U+#s;LKXPvo1y(<~t0iUGG?^d_4-lC+v3IH1P6fAD>?9c4n+9HLT5=%j4*YN` za~PR$8L1_WtJ<S3q6N`bWP)@GvIA5Fj6jc)2JW^#)dCV6^J<qGzbhqjX*n<e(ZMsC zri!tSL*xEB(;^%B%r<87^gPUTx;<s_*;DED{0dPsV&PcCvl`(lpR(`M-^fsCLiFb4 zc?nIpm2<lfiF#%HL|E$^dl=skAGI0pkZ{B0l+}Q5%$)`VNFv!K-M4)uK*>j@HLn`& zjulTCc)ynxg<>zIVyb*N*24hRqyq@FR<h&<xC0yV#LzX!ig~thC-80ptxV`TCuNt3 zIP^Q<e_xB+w_%O9UiIvw0tx0_GGlwSd}tqHt?ppKRJyrkoEUP6<gj^Vro?$_gLz~K zEcb)6ufV9oIA^AA_($!C<i{(<G$LoVeq*TG+<2XZN__`aGpS?hDF|QiW+4&hQO8!S zy4TzoxP`dId#(^H7e??<TxARv0i?Gyyx#u({f5TKlfx{4!J5wb$~*FRf!7vzT58US zYo@5XoP*81l78M-y&8s(u}!LshcL<yEh(q;pmMM_PBRA&Pwcz`Z|7q~;Pq2*=VN!c zk^p!0`p4CNhUv*$*cEb&)%^ku+I6V<{AliX-9b0;=!n_JZ}7&!ftVIe?$W7+-^nFu z$Oy(%?iCz4fU|Q+H_-r}jJw$^q#vn6ovc#`F30}io<pEdTy{~H#=>2;k;TVkVICd& z1w?TLql=e0wJTXLxETIs32g@uAtK8FAt#M0W6o<9_5n2$Ugyt_v#0CdG4LbjU7y}@ z#(1n`V{Go1R(FoV?a=#;V?pJB#sUsOKQDuXnw5N(h9<y)7=aF)2)s6WZPH`jG<fcZ zubZM}24sef;9=NHs1?z3wlxkumGpQ07VL>MdCJ=yvY_OC?faXmsEV;RFu$H^MrJ^P z!yIR}6v?G2>aIuFSDZgVQV@-$opSFtS_C2NX@1R-rQWaGxvq!Se>u9>V5Ru=HWuVl zYi6IR&8);3Y*%RlE-k05LmXfok22Q0qRX3xO!pyJR-x#fK$AA35CiG)16c5sHC8!y zWQ^Dvc~hOpk%VTH=f~_{5!SIkt&ZtW7yVW$T2+nm!VS8uG3BXCC>zKqofc+-l9gPl zQrdg+41qK(Q*n*giaFp^Qx?})J&#+9Nv4qz9f{S&n$#IBn}I@9PIYU-uW1_r`5en_ zY8a^qE+1(@w+n&IUJOraUS)B~5(jTo`P3OpWds+Xg<vfvUJaJNt40b~=t|RO=Noym zykq18SM)X-bn4~D?c=9((UMgq<96XH=p!VTm840gaI4GQmf78m?%!MSVh^8ac8JV@ zC5;(E+kcv&G7KMPF%z<6Z{sz{flKs)&*tA`5@)K3`459i=z5HCSYS((?VQ4gu)SP! zWJ^Q74~)b^*V5;{i+qyO9i+PZTy-51f84s@P7a@;7lPT|9}-~12d^3@w9P@Ope9<f zee4S11_WB6=}RNI0BEpnJpbHR(8@tu;__Hi1GuWHh@#`1_1+)jDQz?bgNNF{Go(<O z&Fkfdpno7~4ip-LZkLdBcp7u_u&kzBbE*TRb8N8R(Jwo$Z;fC%65e0YMdFmFI`W<? z@(^=!Tq@yswjKr_%69=ONEZ9+_l2jz-{>$8oX1~>&l&pSxA^+vlMB8>_Jer4q|a}l zLE{{4=b}gYTy7oWnLD4~{_EoUDmg#@W<KB6X}H&#^?4d|)T1${z6YSmKR_h9n=@;K zgb?k8WRu9}@HMJXWMBGCXY>2=R}Znje{Cwv^kVEk>3N96J9f2M&M?b!ofF<5y=l?0 zM&K<RO8`H`Te=oI!{;}xavfJohd38os-U3IG>`Z(8*o60h<Z~X;qoX_$t<99bp&`l zfGkZ>e$<yhEBV7(q}D`GAD@(>1GBqjn2-@$vc(*@nPGoE=)lcUbcK7}p%@U^o<iMu z9zt)shrHpU$XKl^7YLaqOa6HWuco@UQM4u3{c|Jm>wI$9Ut9=$hK5FTI3aN=Nj@8| zl70SSDNZ;E9sWw(RtP&bK(U9=NKC#o_jLp&9$Kt^*=?&er_X$?T|6`ddO0^l2%BcR z(#n54&yK%H68uX8s*daWRsMYL&e!3ml*s`b;(yBZo0-9zjzJ&%eIJ0Cy=V6^8V%VU zN6o&+hSGz0ApS#%bh@w)Jy<0?ss(Z#V&MLiNwGnuFM0wbF8Y8ZY-JIB<DcwXiGo3Y zP1Bb|;uy6;YNs=jhH~uUT{2d5N=@m&fJ+z0?532E&M#vD5^=wl8sWp2Hv_#xgq#ZQ z2W1;1M9Q~8<dXmQgq?1z{bpBtIRs;itc}T>r!c9YpY2*JLZ;U&TH|37+|{sMB7O2O zz}?is$O~d5_XI#)c&(AXo0pjg;;vt#Fo^DfnWDqv3+t_dNDo48V^>WR`tP6oQgAL~ zC(1N`ITBWTb}Dx_2LyqrfgtF{P`r#7HAH_RkgS?XVFxuXyUr<*Pm1X&*PJox^u_NW z>*|Eb&pUIEy#xUsX|^ZyOl!}Bpup*Xfa#-17Jf10rbiote}<`t9paP^hgh&hV0(}f zm&pV`<q5xpl!mQ+wz31F?ft7F?5@H@K-Ue7d;BjcIeE;S??aTXp4|Y+CH;qjS7=_> zz?*l*bS;6=-d9Kbx1ZUCp}fz<u9rE|@!rv<h^+JNqRdO^ss2IQ^IUM-yQ*!yj^LK< z?fxltW9=m?x6)YvRoB@2*;4-+pEdLr^JQ-49|7qlw66u?UepsS6;WGz_1RfKQiX^3 zQR#0jD68fwe9M;^u)6gfK%F1QhRwmEa=Pk%W8a^0+HHc-q=R_5dK)Cnwq9}FXtogk z)-=pZksMtkleYaFG2uo$YIgEq*NrLJ!t~!nK}IO=g)k1U&E8`JZpPmn(Lh++;_4+E zLU0fShbx3po2pG;k#PGnqDvj#GTbF|PEp;Kc8cm4<nIyL-jP80NUvx+4=B-_IX|)@ z!^69>_PWn)Gtuq@wz-&_rHBpd4jt|bGf~<V#R+RAC1fB7+x)VAx&i840rrGS!u!7} z5gcv{$s+y(=hnip>J8io|8f#`EFdQ0y{xCZ57L`&YTnvWWs6o$=pYIRBMuVK`@7f< z)3?L`9smp~FUIjoN)sl7^0{z1UM03&QG1--nV4m7#ieia*YM9$?8_yN2JX8-p)aVv zVI^^8=NqF9^rTtEpgk}cec7MG-!hGaixaJyT&>s+N90aE1oD4ndmW2i(-QO(r43o( znn7}*U6l@Rk=^_F(Ma)INFRVw$hr?)oG#LNtvXJ0|4q8tG6Ct28?NT%nbQo&p=QEu zcCUM^&-OK9<n`Yv1t7JX>EGuSbns_CAnR#Jclpvu=e%V)P25B6oh>50s=-3hn^x%x zYdxgsb7MjAZvn7O4bh5tVaCQqtLoowgspBy9Q_AXBCV-C^aNoP&gL!Wu4-Fibs^Wm zVzHB4b|Vq%{gReF>Vu&^`u$jZaASrBS)gZtPhG`1-^iXK-G}~gAs({)>w~HZHBg`< zCd2Jga5>$f$Y!f(F#ED(^1bd4(bE7F%7Ofj5tTx@jg4WHo<;Ge6Tim<uD=r|8ajh5 z+0>~f)brjE&Z14aNdeKVX^?=iRh~%=k)qdeZR&aWU@ui89^?}PN1j++dBx~N_;JCW z0!i#g5rS_?uX}1DPDjp8WnC<>1lNV03gM^Q=g%#MY(ErT==;&##B*C|_I)`-OY2h% z=ApDBBxpL(NV2VmcTl%lWG_b6&I7Qg_%5Nh>aDarP0exHHk&rgoEy(p%G3_!PW0(g zUHIeKO&eaLroM<@8FUUhN9*a&Wv!z!4Jd`XUQXuTeCdo`FQF8mx;dQ+eO7mI`GdyU zfes<D@ejiJ4Xf!XnGLejR^({5%hhpmR7X~BqLJO<6`hc-2i<|!F;q9qBF6se4wi{9 zFZ8vAJb@dIJ46}v&;H#QChHB7=gg8+M0agz?M~mlufLlx45+tdE;?v*t%JoG3akvM z9sT#>U!IEIQf13OwyXrXP;EqNftyauiF4*Rrvz)?+5`MUHk(<aTjviYDTH@N5vTXF zulgo#o$q}viua|7uK(8WKF`yOdV|C+Ab9p3{v+9cO~Z}}@0fsI@1Lgo8^bvO*kGMp z?4DSH8zZv@5ZWXG!5r_jA`wnVl2Fye=dwDHp#>E%@^mcM=K@wj0_^=?9}?A;+&W+_ zWAh{(wiq+<ONFN>zS_4C{Of&=@G}j74d=E`D7vfZ$UU%raA|zmUR+qX!|grkJU-z+ z>SWrxPD!yVuD=m|31ME-fas(Rg8N$Q^0npdOWweT9hVXjNJS8U_v*}~)GQH}oH!pF z0~@n^3ti9KC;e3jS#^(91osPm^d2`HF|EjKGLA7Voc_XKselEy9-BL`XP(~zL+{`N zgu+Gs><SGAz0fsAw9X-xj#h^xaeo}2Xay*IEw(hP-W<SO%ojd03PZmIQ?s3|j1eaN znKHVeRCyG04M1^v_w5V9P*g5VYlJWP>|DBeiQ$vJTTl<Mci{ceslaCAqj#Ul%ZQbj zw#7GK@<?rql%IQUJl~9`+bO2bUUQliV_;`b<=%YaL2uASIHAPpD3S(jFoVu8WhM`2 z*Rwog+=o@De@u9k{IrenV-A}k_;NlSnFK9~B(_>9;tX(Vcw-rAHK(Dkh_D1<fY3^7 zlh)l#Qg^J?u+U)fjeSO<dM=LFSuZo1X|I9H;r;wz2bbqKhSi;yjM7)%0Tm`CmkNKy zAKIB;6`virzB0+9yIdJu-{Z}Hdj+s@rM_}8Z`GAt2PftbNJDwp)L0$)seb#oW9T4e zCCj@$i$|m9{5w>J9@_+quz$Mq)D~V>w2Y<^f_GaBe)=^1ed08*^@`6zZp_@z;O*n= z3X@oOJ;XSYetJa;j!<0qa<9eo>1_PUT|o9vSs_ZblkdLk#wVYtvw>x<9W;vmWb*cC zS4O_p0Gil>{e^Y0Ko*x3h<8R={OJb$qMTK?B06u>aRy#g{jAm`>T5l1({W2*t>)b& zUqTHQ7VxA~Vl9O7Lfsxk3&;0Ct6fvd9ttp!_j1%4aR2*XjeAP3-#E^H6d>L|3h@7R zmhB9TEDiqtugt_mK~{e7U*_>uP5mGau0*>{HiH9L%?7!mYouzWp=9k`?3Y(gtwiz- z>HTp1w)@UpB0-S6x&r*|Og&%L-_J+AaX<}e&B(JWFKB@iHqCuD{t-l|tX$2uO%0;l z6_W@bk^|WOMuMj++G02<MxV1tF$h`?kFBzTsuO%O8hr5SPp5+6(RZU(;NhH+`{oRs zl1rs5C>mokMziiU+7`K0zPa1V9Luw!&U9mB28|n;LX<uv95B=~r`(*9bOi<S*_z7; z{G&`l;4>%ldedBkIf7yWGiX_Gk2sU%mxIi=&?bKhbnB5+ff-NnpC?h~Cbrz}V<QqB zlH|QwceBp!cl%)XX$lSclapLFH=xsP+?Jv3mF!RXIn1$*;i}JZMXKDN8E=8lO_bFW z0WA1!tRQ$DpYs1U841fBZAuUT04O;8*H=55IQ}O{`XA=<n%B}1do+IcotkU~9DvV` zQlmpe5VN9yV&f#6=3Iixl~NRx#vic##1MT4oN}o6>*aEl$5l{qhS$N_w4FxZwd8L} zXK86}pt!~FrFSz$s)jwMf_3ADZ;brQOV7teWw+Gt)<s8oqUNfzDw?Nn<j>2?Ol^Z^ z^`uFrWpnvNrd7FRas~5E-b7^XQ-OkP`HFeGu0=AMbo0DQ_HuNE^I~7!oR31XvvsJ_ zps0rK-wwRWChM9Jh&N;}TvC=wt8U6lvE=4=W!vjfGOf#Q6_uK0CTkWSrJc;;nam_T z`U#%U^nM)6#RKbqDt6tT3AAZEb}2izM-P|ym370ASW{;u$w<-mouX*-!N-}#$oh$k zb<<C$stu~&@+qi~I>}1S*yY%BQ{c-M1hZ<eAv^hgeEu)WYST5dmLSgP<ew$w^MZ8A zSPi9_ykYfhsGXRz_ujq2<{G+YbB=^~KN+r8V9DBg4>j|&G~EsG+L&H$uip<Z7mu%t zqo=nsua}Rb(L_f;2T%susAAn>>z%2yeRbMKthoBNg4+e36x8UN2$tMt*%PtQc69T^ zZL^_bVX>_fP20chbL_KrhAtf0K;;(fi>|ivv$G&UKTUI)esxg`j}2dpv@N9`=_&&5 zXWohcXIAblZ3~x9RWUUi2b%P;&^xfBDk?x^u~KQi^IZ!&i}CyLX`Y>C8x!%j6xGj? z3YP^lcFsdG1JaXDz-e`~z8w6%u4A(=AF8vBBfJW19xJNr>N*#uC6Sp`RFUadkUr{X zC59_Fl^+#WkH=SrosyRuY{dF&NpGoXP#6v{ceaf{nyHi5IjvPq=9c=o#abBN>zkfM zswSXY$+q!W8u_UgP%f}Q3%P72w7d1m9TMoPt>(?jU6KuvG_x7j{LEOY+}!*;{QU-g z)M_0-Ey|Hy+S;*zSU}+E4xY)hHG9BT)+oFT>K*D$s8_CDnHAD~p8i7l^Owf-TKl8M ziKVbJ+Onk<0Mb4m)A~Xj<`vf>lo+;~+Jdj8<Bh%rr*Ex{j%o8aOG!l%Ko6FnW9ISo z<+P1iTvmR`^c!Nxi3m%FO%u#I<tJ3MTL`bP0(vh1ycwr$g_w|?-Mo2$SFVU<!iYsD z+;<?6My~*%PyoPi=^lo*LxcWt-o*yimIU+=r?7W(B@+m}3%O;M2s)Vc^F^y~a4(+W zD1u)MA+;>}W{H0zrzX6LQ1*)KyYKb;Qc46>$J8?13*=O(NbOnxbC}!U+_F_S8QFF# zHfd&;gH3|~{@I}MFch0vU(!3BXQvfk&wv{w!$@%UVC~k26e}0%mahY3xi|SedK!IM z;9h-;bQeNI1w_|Dq?LrTwaG5T)YdJynFb9i^MhsK4WjFuBZKi=An5+iK-_m#Dur6h zkY6x(U=U&4qd_XgE{DVm#Qx>PdKQq_fW<q`?wQ}4Q@eAkSUrwbooh2i3v7f<2TMjM z5-*5($2lgetg1NI@lZ0APCn^-Yr_Bwp*ce|Tvrv*FiSjO-WdlK$VRLy|FDzIG=c!S zG!2r$sRrw)x!i|<{5KgN5exR)0Dyd|`@tO(&=CK@&+8xU=8eVM{}f=F1GKg$8*LWs z<?X&rfxH!fiQ6NOYwn;B<ZR%=zR?3LgU}yvBnCzNp?(6|Awr^mBC@uGb=Z=G&jE%y z)dRE3u-SWB2@L<ZyJx<(97Vq<SfFg;c??yw6Bx|Tu|@7IFXW}wgg(>)ED1!1gb2^a zb`5%byR#?nRmz=dxrIUOa@#}bZ|WGjmU#Q5fb2Ak<--WVd_En$Qc{J{-~~szWsI$s z5G^a3u9BqAa;bhq#k+eRNd)veQX-(l0i+0(H!*<p8aO{-1{Uk)=N0stIt@#I---)$ zU8__*ycvuJgCZ<btk4EjvBmw{e;-%{e25X&R)2p5KCeqBdE^No_(rez=f;4Zoobcx z>ISJO(}JB8pVA~*$22dFN*MM)XS1z+8f_yGyxR#1N_<;)iKDo{p1Khsqz@ubI|iwi zI7i)Leg(FS+fsy`NnC5Oyhs3FJz!kqa%^(a3J^^gSPaPqKAFyTp#ada+{zN3z)7o5 zhNXI729O0PL6kwEzc4#lU5`=`Snduxt`M(nsf^lYVQA)=4DfKcFBhaV7}sh7RuuV{ zfq@<jKky}XNdY=SdfsoXue^B}NfZKVzOrN;V-gV{pdJJ!OtS<j50Rh`|IAL~9z?mn zMZu$cyaI-znguIcV!xxiizJ4yel{BM)XvU^SYIXLAfVhn(;o*ozSGyu#mS)nO^q@K zuBaTns5ldn6frJw#3Ik#CHl?}pw3|F^YJ!Enj9ni30@JvU5XJSA&vyeen?aUQ6pSX zLP?X6C)x#4W;H>7v}#6LCG{QlaYcQbi2us*FOmOs?z23Eo1gV++ymnC^k@(vJUEQS zzc^U<RYY`m{yDE|V2cLttA`|f5{eu}xMW~9yK!Hb1l2yF24ir~FnqonP$Db_a4cp) zAK_DA^{*PfI}qlpwy4G6LYCCj7lWFf=DwTpAUz=PNDlr4%@&p&+qS7`%#W!fKz~h5 zCXtTib7whtA79SX{&SbbH>`JyKk8tJx?eF1pez|UrBtWYFX;Cr2t{pzv*AL6AfR?Y z@d==CW0l<0y$+0kv-n*ljH+|JO6e|cIltHAQ?5I+P^M**Uli7Hq!CZ8J&qCVN<Qb< zCOiV*Qk&o?0@h72uPX4n_y!Igbg*ar^9(TJH7gN<0$Ny8e&`8Sw70A(L4mPA!>*_N z3dL2_{^O|8!GOYFbba_(A;cjM1ok?DTwYHq2J!BrFFMdj+gYtUcrS^t%|Hnt5n*;L zNywxJX(B=^_l#gIHi>$mWWfvO>na9gCa<M)^OfR`HE7RAVR<DJ^5`fY7%!G0FlPWL zRl^|S^SOy|)22YfpSIWes@hp#a|bdlQ5OxBl&Za|{k+h}P7Uqh1{wm;Gr@g_tR&!o zf~^*E+iObQx8GdBSxbHP>Qa_+Moz$qmUN<(k!;dVem0y^3fd8ieCl(9t%?WhOml&X zbr;j9+FrEYWf=BblW$S1y<)n#KLM<RA#AV~L;m&}WGeupz0^-og}PB;Ju4oCbALL? zq7ihH?V>hY2&D2U4JpnSH6*p3ziHSpDU=#jl67kof*(PcX*dP@v(i#qHm_B{HsN=I ztLhO$%LUOWh55-N9U5_CUII#DmpqyDroX}w2a`1%M!`9$)fZyds5@!?tcNA3=K#M; zOQh4V0}=$q`4QGengpSqDA>kPvi{r|KQL;8evEN_iSnXf;gX8NhiwkLR80=Eo(VXI zLtO(k;c;mzw65fz3U-+ehJNadUNq6hU9LlS8p)}6WcIOXz-eS>jpL*j5`XxGjXN_w z)iWs42i2~elec1ef=M&a)f=@w*xA8cE|isjKdckq5D2~+P5ir`@nC78`b?rku^*r; zjD>)&q~x#@B&X`!yc;f|c`TCN6x9WabrqPHH$=sKsvHo6IS`3K0!0RW4>|oxJdMo_ z{2r^$i8cfo_z{R@EQ5wH;NalEc!~=ly{$U%zO?2`Gs;6t=eOZVgF%YQh2eKfl7KJB zA|{S#@VcUTfi>it{gLua2Wd_7g2i$X<Dj6%nd=-O!HLLu6!|7}Pw+yXX{bDOMgxjF z8naITM;qo65~sQzz=9$C<7dw1-Z3Y<XtDu_BqwmXP5A_~NQ_@7Cx~AX-P9)Hp6jY{ z)#>Dqg(t<o_AA15d?jKM$YGWfp?Hci8IwH3H`fnn7NZ6(>+V--qDA{8kpGLMpHD*y zYvo{9N3&|KN+R2H)q*eT7b}20&0N>2fgF6F`*Z((J8rjOb_PJta|xMFTf%Tb5fCZF zUN=A&K)Z@ek6nWQxsPj@ljhdE14@0<?s|%tY*#vickx1UuY4ZK25jxeOEZX(!4YT} zkoW<;)(gVZf{ua3yS7vbT&Rd+><o(!m&4=pLnB6LFa*twD5vnZq)utU3<kM)c?D{k z5xj^2tx*n|Ai;Z)*b|SZxpemDt*w(&)1eZow?K+JZqWR<nT{^A5-_d)Wc=Nw@cz?1 z8SPn0?ejz(+lds%!)q8WxHx3c34LB#^$>V1DU;B5$E4Y*!*C29?U2U$@f5AYvaRQY zB^WR?58M<9F%V;vd&7q8O6L#^`Ei=7=18JZ;jV@{>??S~0}}ap!7ce2;ApBtv>li! zAJn^ZD{tNcZE?OKs91|rzrQJOk4Phv0HkICJNo1{MF@fxhh_2)&{OC!cP3f-dKK8h zadZt*0u{v8E@<FOIqco8q`A8t{}SGC;1NKv!C1VC&j14GB@-LaK?qso0L6(|)Yu^& zry&!!OC*8AE6*PQ+zOS9{L|KXP8<o0=kn#OfK7dG1Cbt@lQC__mnb-K$9ucH&)9!) z>pQY(E!czJ5`^EZz~g@>N2hFaW2&gQ`eqS<Sb%pLtTK^nXcRa>sSK0~7Tv%wvciW+ z_8GcWE0`D*kvF?%`yZ5OzyrwzDE15pzg!Ejt(ozV1oa*wnX5!a#;HQE5e^P0_e^%l zW^6ReP!z4PKFao5t}z;|H+;jpC5%pK#mwQY`Uq<44ZCp>_TP@NI9F>3`PW<7c-`Xq zyrZ7Ah(<1dqE)qS75tcrUW4Bt-g1A)M(hcGU)Ygq0e=^FgS;T$dVf|&dJ&HDhJ2eG zvuH_tLU&5)=?fOkmPAkB_OGO8?L&Kd>~0juKuR7<5~xNI^BA))ytuqAI#xJ-yyGti zzA(`$*n39D663FEF7%-AD)LWHcIN@T@)cIn?&sgDDM6egHyF53=lA6X@PVriK1-i) zkrRjc5B=*HpR{>;p#7q7{R@apNex3O4cv2d9JIrDZ(}mtW&mz&1gOPl6*)d=P0;-r zDw$FITx8hM_PSoYD0_Z?pjoi%?L3yuMiB+>1rbyrL`cDh?BQJt&_hVV!Bb>bC0vU! zh~_|yr0|mM=8L}aN;6?lA&nTi=R&~cq6kFYu3+&D68xjjf~h~xJ_V2`*p)7?9x4dG zB^K)bNDI8!juXaqq^1{RgLl_0*<qQ~#M2HidJ1SNHM5d-#wRKFugjdY3*5^!c4j-N zLKoD__(sK!c8;4-cd{kTYXp2BHL{Ov{&56=Z8BYjF_*PlsBV}{VHTfT8ZLy7$(Mrj zf|gVK8iVVVtb~c};zHEzvr0)r-^uL((`Qd>0JNjcVz>Q!E4TYInwu^f#_lpjreMn` z=8~B|`I@q5vZ9ZiE`lLO;c}RTiDX}=kK+cx(~EG65(c-G!?F@`{l3J7&f`y*qIr-u zF^WG1tqeal-w)vxYIOT5b|*pLwneHzhIb~p?5Dt%UlpcXzt^Pt2<c6BQdmldNd5Eh z-m9LIM#i>>)RuT~2PMjQ0ExZZXstYxrd<PioSSwEe5?J4BwFun`*9XmShe73!3UC` zVYaC_1d4DP2=8i^G)@IX=+WVL6tnH07|XR-ARAVGyA9A3+h2Bxe3Nb+<T*Em6^^%# zc#yvTJ~!C@L&>;K>-*{9q1bkq2>#hTAi+2VjNqfCD&21uchCK_a_3L}Gas*@{qS3{ z&f?w&fWr-y4RMB?(qhFT^@y;w4GlV{Fz{W+-4kjV-t1m^3FUHc`pr%ug|k4cK*|JT z#ra}Z*RKz-L1Ma;p|l4KQ<13QtdQJVCx8J3w^UX2!HVI(LoE3g?JI?ytEQBa=V#KP zL2BacZns?Z7--QfKz>=60Xy}*OFo<Mmk+Qy;(+_OMCra`S#wruqC((fqR59`B@jOb zUJq7?Ym*Ybho2As-@ZX5;7JZ!D2b+5brR|E>r!^5ttp60@@uH#mchiaDr`?4-&e^I z1|)AaTc%`NT0NOI1mGv;JlC8<IJN4n($#i$=DsSfj3;;M=#QL1jJ$D+2J!hkhnBCT z)0YmwtD2n`6tv$52t1=BS22(0UJA04QU$rM+t(Ge>V!M(jua!1|D*SwlxrOp3kwf= z2?pG!BCHP9c|PpV#*q!)Wi}<gVdqp5q=Ciinq$b7QC{RiqLK@~n*|K8N4SG<_ozsC zcyp~@mzzNZY{3$emr|s7w&8*)E^#klF1o4welNO)AU2e)`sqz8*+ey;*W=s$C_2x_ zW`yG%1=4$Yyk;3y77nAdE8N;59&#Q0*{&WpHX$H9ccuZDK5wSM*tVi4fdgjtnjyiV zc+$XIEri;a#CXXQP4xn+x8dLZzVut*B*!Ja3cWk#PO`g174$DUK`UilFQ)}Bwtq^2 z^l6EhSf1bU!f-AUStou+P!69Lwtsx8Q6R5de)TQpBeypL^1<o2HU{dw1itQ6dt_Rl z#`fyCF_|y*zvs3tDeky=v;uD;z7ViqEy?vML(^7<OQMobePwl`fT<Fn72>?t5Ek^T z9nP+S&2%t8**?p0!IZt*CuS?*hTDi`te8KJZxP}<182l5^r^1wlD<mHxTvOV4&VC; z=RL~k?U?aU<Bsj))qSEZSg!aylYdloR(Vp%=bj07Gct<@{=q#g7r*sSF-c=6$&uA_ z-4899UY{F7sKulpJB_RiaDz7>Z~-x?zJ-IrDw!jOH1QbUW4`}a2r`fc1eo5S7xP8a zktF3tkNPcgZNjTFy5Qd?U!A5A5`PFbB8sj}K&dP#P`?@7O8)#YhOTXR|6(YCJg-rV zKB8GWI}{d}F|w)oc`q>z@$7m+<yB`o9WQ~kOrAN5G^-~Mk(C$Do2Gg!O+v7dTYZqY z2C57~=i7B5{*v4V=T248&Yn4yxN9TB9hQVrssy;2RA=#?qjj!9F3L$9`;&3)^#$<- z5eBgR;0gc`bIbso7^SqskjndnpNZM}q^;mb_YV#sA%a#wZ0-q(K*;<r_%GZRGPhwO zvKQqwqCfaDN1H^m*!tA+MqHeaO`+*<$+UT-DPYym>@ahZv{p!->ug2I3BHRV45R^= zL}Mv6-CG+dGf@sEi`*|Al?N)jnh#?VlBLs;oTPgncQUYofQh82-h8bl<KfpFxtlCo zUD)>b+lLk#YSBDj$Bz_q$0q)|9toTehle9e{c_(Cmb32tQ$fdpa)bWcr^}OY;+<Nr zY%fXR(JGm8o(%d{-?BYWn!XJcBkJC`qykJSUtd&L#$QoFJefn|^<{nkcwWv5f|_n? z++?Fl+d}ZXptpzaelwi+i=anp$=)d}K5Cb~?8?ffmd$BqhH{$)j`v%|V43Z_B%74x z6r)}D9ie2i8}8#XJ4UnfD<F8TFiJtn%CUYnBPN6=f34_4j>FGJZps0n+W2dXU3H!l z$g!e58fE%Pq$9y(o2)Ac8fGaYd(;%RgQZ4d;@#iv&RXm`-y)x)4~~I&%ArJ4MCZS7 zE@?Ih>486$F-Mp&1vns$Wp;{xx#DgGNFFYRh_wEgOauwe0ny@;iHfow_0_`L@orRs zei^E4BTRqiL(KACR)ZBbApW`;S{f0-Fk;P%<%G02F4(Y9qz`bAN3lJN!RZw^C~mGk z(OUUw7JJ9)4XpAnn;7UFrrtHD5iIU74Gx`Lyo1U7Vcc-M6>Q>KA#;W4qaW?r!E_ey z5XnC70Tx~>3$#0AIeIr+E^C$dlrl!vQa5k%hW9Adq=Xp%P|Pit&F|JVu6s?Q7{!Oh ze9P1T@->1xBl|=)ZIk?iI0sqnSRobnyc-C6L#+YwC8`K$tXSjc=N7@#eZ#-f0Uq|; zf1p9SzhEc{o*Haw0f~cB&sk*&3`bPhJroLU<ZFndMaST~$!lW>D<PnN!;jh2Tf&Tt z8MTv;^uU4-DrQhj*MdUm)B_=DMchflbGYWf(irx44iihmVzkeQ3F*8{>=P_4tAud` zavdj2-|o~*04QBj@h5NX{dESMlQa#UuMOCc;ir2}mcazQL`{3-J<#!IuC74NYhS;C zk~@&_C+h}p|7sOhl=~+}W%?A@iYNw2y2~4{D`$2P8H7w?g&!a_%XC70^T?#*DoR$o zn4hI1KkE@vx=Lxh&kwS%RG-G7AFpeo4)1j@%rY+=45FAhC9GP%4Szx_IaPbhB{RT} zp-b=b0u0&$voV_(;bj3T5s|JDTNjr+trE4WfshP5UHN?3m=8ru^tnXP05sg4S#fuw z6l(}}zfTL;BFzSp1rAPlnoAv4)S>Qxxu+1Qm<4Qxy9WWU40ykQ<}v2T0JAsJ`Nr{7 zv@`&v<i_sSxoliqoS~(>9~5ET1J+R<n<iB^r4^J(FYXH)_uxoVD#}|j)0K~0ZK12v z;4Kd-gl~pJPSkC|-2Xh~U^cHRILd0Jgz9la?ok!GNS`j|T_BRz*ZZV1E2!SWp3ONV z?}4^yVjLbdVAyVMo-pm+i&!B1XUeUA42Ab{7!#zjdvSmH*#Q*Uy==77NGW?H3EI|; z1IWdUgTn*sRNcX+SfS(-<@6KfB*wx-nWC`x#caN_>2CtQ@!|8?j83*j5{G@_%M<Z* zRMV2~^b=fi(()``G_nd=A`gZq)}G$3=DBgR$V#PibGie&Vj!>4G{r`|LD-<fNJe*{ zOoFV*YF*5kEMFaXWby6IQ?~H1A`<ufF%AqT!aY=}c5NM=h@w41_;HctZ@aCC<7Avh zeeHqxdRv=URphgW>m$MdkF0ArRQ~m4Eq8Mhs#QAkf)6Fj)dZFcWnX9WPOr4d_vET? z{J89rRy-9{Ps<p*L;Z*sU1R3#{S3W#YG<(;%Nl)vCw+2>@EBuuC~l;*6iC`Fr7rH_ zia~C%(KjfH+vm;K(RF6yZrPovGD6k1ASBATo&ea?$Xhg6447h{7dawDpb0xDn+a|h z(d@H+^t<P|P&?hPmeYH$&H4`fy>H6DzHnGWpcfjUZ$T;e^Mh(<Wb@5o>1%KOB0tjo z?(2L{?4H}^crD5M{`)+9FXA_T*qKCJXuNm1qin^4@a(<XXl?9l>~C(?QTLh&%$7Y} zq6wl%gl9dKM6>Iy*nC+|L1-w}`I(nPIw2W#>SNX&5_(q#7X2K7D}KtLL%Vp!Zpmhb zg&&W;cK5{VTKg4|90y>g{W@LKTkO$EbPVHKA^dukAbq8olNxwp)EPPA_PSse9$Vq* z%m^Lg!YmoI)iyGWYlkAMh=nxgj5bFy-JMTI0idYuWCJm4P8=LHzv6DI+qtqwx*<cl z|9G$!bcKglLS8E+1ivf&Yjf-H=&Fvw@Ix*GeU##FXdr(otwImY)Dw|SWuhSY(x#2} za6-GViKuJ7n5&jT*XR~H{VL8waVeO7(Qg1OopN3z*iGXftCe)80xt~%!qthRdr$>_ zU)f#D9f%*&wS+#R94>Y}_bU~bi9!REHQ4$P_R}~uVOaAd`Spyh!a^NZ5T{kRRDieE z0QlRdMviw7UK8D`*|Q03{2BN4J=9G1j{Hbz`;7gj1C7m|68Tw?Wj^`=St|SLYj{>a zo*|G=531V$_jQ3iF4_j!Olev5K0(xNzUyxie^<a;b;+RCjru#+2VzuvDA1D4%*uj- zgKKfJWceYoPu}Tc&9qy;9FrQ%d?(Dr(D@`2011~Vuw+PE2GnofvX*q}^xHB^9|9C$ zf{W-RyVU&wywPr}TW`k!2)uSJ!UNBniXJ8U0yZ7<iy}ZY9SNY~&FL4cM))9J{Ah+B z@y+o>D&>V&!ZI7)P75{ap3GFAtfB&`_$Uc2bA)pyIRbOfa1a>4F4cO7{m7BflYbh7 zZ2^as5bgmj`2@tceWN}_FZcL(dCnbeD}b6sld=L;hem85;d4wKK=kcjH0?%lo@>eL zh#R4Ok1~~U6oKE`_SBheUhOwL--6(7A_VEf&_V#;q*~<QmH>^HUBT3;vMC>_<(EP5 zIyI+B!cr0SoX8rz1B<rClC7*X?A_0rvx;tF;S?gqI*3`M=?jm@Y$CT%<Q=89Tc@tj zkAiP6r(*QgFC!S;9@<n;g9CLkbp7SyjUOoCZ&H({zG$!2`v9f|YbZjq$fn>pldgQ= zhfqxId%6p<_;jkNy!~&LT356emm6PyLSGa63V6~lP5}6lcUr%m%QY_65)cAD8{I%R zG)i(*6+ZJp4@VLf-DsOcA7XWpPtY~>Y)>_kZ@fFv{PTu~9H+~h`&qIp_(`sKN=8b# z*x&2#`}Ozrt24Wohwn_a+E{-IlV$(CA43Rn2GL$uc_<Q7E8@fOi@&?vnj!ASHte7o zUFW7M<8`U)9^EHl!vbrgR*SlkA`uV+cut)Wwh2QGhv-J9GF1q5E#pIwP=%jzOEr-O zYhU|{VYB=2Kp4C$QhB&UBN#9BBU`ditsy*{^+PV5)@qrOKS(e*kC~F*$a&o%7p5=f zRv`t}=*Bsn(ddm_J2#=?nxOw6nPO657F&;7TvE-VlhZ65@g7Ra=)FvT|5vh4@R$H& zN6=m&)~^fM^;F^6S1P+{D!PZ%U6tHkCiaMjVgD4vta!ZRRwGS3zS0h4@RXYVDnSwY zny=i=aC?u%VZv41;f2eRO!(RM_m(p*0$Hc@JJJ+SRYginN0?(t2vVF7_-m=Vo$v;W zwm&ZAm%%5*r9(u(GG+TcZo8Moxq(Nutm+5gH+S=xGBfyjtwj`z^wVqj-t9N~<6HEe zyo$RE;9#5&PqMdv^}NamH3!}I;d?PmHWq-Nx!e$!xcYX6BlNdvUGqjUOh=LCAZ;AJ z2$Tn69Rl%x7m&SLr5jZWbB!cL7{2!}?cNw$?@SH+Vvh@&W&ECUqnu|+%6BDvE=t%~ z8(UV=ew<$wMxP;A04XQ7PYbkHWXkjs`nde`({>xPWR?<->>t{GN04ZW+vYm%xXQQ& zFF@NDa<~^=CM{gb=YrpTNJnF!ACRBLb`>dG+fTr4saT}nGf@*7JhZs35`OOjfLcVA z)RKl4Pc;c2H^JSydo-J$sA<yR2*Vg2)B(W9P&Yag&VNDve?y6Pa@QmJUq4CvUpE%x z|N1K(oeZ3u9rcX<nS}mBA9$<vJN&P~lA2-Mje@kraI)dhjjX-tylGKx)7&AF89_t{ z$q-2&V6J83T<vL2y0=DeVVF)rz(En$%J9{oeodzfG^Zi)FL@PH^FpTO%IEXAN*qeC z_rsCoy$|)e1El78inOU}uJN%3?W&aYD2S!#YClg)O9?2pwI$190qFLI`pfs{YcJDj z@NKqJF#D8kaf8fjbyEcrtZ?V3jB>J*Ts78s5m1x~P?V?ba>c9uWL}<XvYHrlCv{S4 zbtdZYCiuKdbXN}@6j(32?GD4T%ZP{R@u@D?t=Kz3+I|MUR2_f-!$@^ia<FwWKBAY; z#{+euscyuK+Y;SOO^?OLNLN_PNolF*{Y+DW%S6k8Ttka(7f>zbpE^&S#^igg71!*h ze_FFCUN6-FNf+|!Kx<)?70@BF5H<C25oG=6C~t7U1eAzFLM>*;PVJI;dj1f^G`a-c zD}rKukgP`4j+wrJq#_>2Gmo|LDhN;o{ffUcn>`P_GT1~viHxn@ue2oP6dcyCte=5M zk4fKo`2?E&kXEJ?Jlwq9ril$q8`RsA4{jbf$A1NHZjx(T{%ChKj$}@-&;?EbgP^E$ zcqE$7%%7>Mwq`4AkWb^BKB?N<!r02B4Ns);^pM9YogC%2!}cN6-r)m{NDApmb}*K} z?Xu?s?EUusekIfF=TK1xr#_!8X1yR@^lqje(lyO%KlxZz1t^zskD~@Lru{UKfpO4w z5K!|BshifP<?4dK8q0qa8IwpX(ld??c#vk`pov1hF#*)qaH7fzz&iU-4AgrB{Tbgv z1^WlBFYmjBJWK>Ki}xx|`m0LdL|(PJB@lu&x~0hf1F^W4S18KT=9f5&i&<S8PVC+^ z^9>?lO;Lgwv&oM+0FhhRx@(xJ(`d;_+5NlgH1CW+hD6+UfM#owr^t<{^r`b_@Lkdm zm~aEdxuV|CIbc%c7VM!5Dcpk?@mjMm1$e)OcmdRetpS^bzq+DCfd=-Z!#G(W2+G|F zVv<3qhFH@VuDo2hj*c_M`mwJ5sZ$jV(UQ`V%iMYV`k7$B!O@e_bw{awd7;;da(wD7 z$De0;-*lBs3TQMqOP$t}D=f>Ik&VO*=``FE7P|6^nvhm%+yz8yiW^fyh<_Xy#Q$mt z&`+XyVy<5pgqEW51ihe7IPJb8*6~Z-HSM5g>mAV5YMOgU`F!E{*Ak7^V5^V<sb?8{ zv5Wn+$uStiE@$`2<YcQLK9#CdrGE0ERc3z689F@pd)l6AfbAnrLVZQ1=N5k`M#cv) z&p8jbL4pKin{NvG+6g!L5Dx}#9}wk2*EkGd8N4GgRUi02eVt>JCCk>XR~cQl?JnE4 zZQDi{x@_CFZL7O%S9RHDmvQTS_nve1?y<icW5mc@KjxDWGa^@xTx-sEVstd+|Ed#$ z4DSxbr7=q17lJqxKl@=Oto<3Qo^wSj5aRTxsBK(sFq_FP$-$Y&$i+w;sF@KB%kT|# zKqhWvZ-knxgkizvVjD+E!24FyRdJxMY+9NXYleaR=OU6Nn1}Ej!pCg8LiQELOZS?( z!dTa8OnqRdhqCpH*#4J&)*(&!B9Ovn?EJteGlb}6Czum7&d5d_$hI;aUFS+K5^Pi2 z;9^NNGIArnNralxer|dC+K1%u5%PN-ZG;zvt0$^nXPXP$kV$Cwi1o#tB#5<hKl?_e z*gaelm<BlIA?!9FdS^L^3owuue}kK^`QUq|x-36&l~qYD-DdkynaMA|5ZSeAOMGeJ zxIpML;Sb!08=@PZfL#xH$3yEO@PH?m2%1C^=lVME#qe<&kJa9w9lb*uHKVF4Ky|XA zOKGHN`*TO4os(4KET|7?U2@^otUC8XFhZF++0;k;@FK57;&cWzYfZ)mVI$7bVW16t zMXjClsG@>tzMYO_vh5&9*6sWKs=L779c77%a3Dl#B7+y%?%-~CwN>tQwXJWuO-!~l zyNT`j;zL6of)o9)Hkl*BpnWnY<Aa1pTqD)KHB;1+i3ZjQkExB7m?K>?lXryyvuXsM zIUmRtU<#VEtz_E^t1b+N(3imYx)qMK5uEV&O?a3gJ?CP3K3%|B9R3ouwIR4;-j$KE z3`Z|<?znruMk8l?%$gBbwNJtzp{WcZbtUg`#R^R|^}9d%aG^GB%+|GbJ#n#v8>h{O z(Blik6D;$L*2JjUS!uVa7_D@={NA*^w&z?bDt8VC1O&U7!fS96`M{x5YsX1E58p4N z*m$dg52IjzE4Wi{K|I-#kU7HY0q9YKP#^Gnqk2D2{YPMYqnn5iz~3KXkWo#WUZ2{i zU7r=u|0cog<m~8T<m}@3KM$}Z)iv8SQH1Y@YB1KIg)reFo6rTc`s|cg1QHSb0(dw= z+Hu4dyQC=_I-02A_iJ1YV-?nIRd_qGo(HZ6<J40I?sb8JDfJt=f~Txw_>VFuSy@>k z;P_gNlctMl&GuCS*l%yI=puGO$n^fb=YavDmovSWUGSF-s~9>8>_xTqic4t53+B69 zYD)QiH&xWy5TnpKEPKTuUMMm`9K~04E{0XLp3(WG^8K2vh-jNjXjWgdyaZhn$MYh_ zAdkc>w1otYig31L4@oulo)kwQK)c>WpG@M|zUi?*f33^{%R^B<a&0gCSRy?FkAieL zih?+N;x^9?sI3)aEbPG{ZU&`tb{f8gsZLthsAhPUNFFu|ch`~#Ng@>=-cCQmzv5Sb z1%98AcUAYFs}()S0$zc!bz^4*g4x%unz3h_=GxAul=BAP8Lu1KfM}mrOFTqbCJ~N8 zcJYhgmg{I|_v)VlQj)<R|HjUV$-mL3s|XcTofYen>qC-L#q=0-;w_i}4D}PIl;pC4 zscs{TnDpAOF)vjDf{qSEsasy7e<31VU7Eq|+C@QscgIt3Xr7Mr%jU#ow}#G;Q)z3P z`@<TIkX}D<=0KH&L#@JWdms#YWDe+w1Kwi;>%4T|vmucig*oJz&NxfLMzVTHU*x5P zXf}Vq{F=wnQG$GxT^YgcV=<HGQbruAjFHfdFyy3?M;&UhvN=eBamSn|U6`-0rZS`_ zQU$BySF89}Kjk6|_7`_Z=zNlZ<;Ly3hGxnjp=5yC?`3Gxb)Z)SYzdqo``zB!_?Gz; zPRO;I$SeYuZ(8?95Po3Bb9p-~NTQ0M@%&mTt#K^mi?FWZu^auCq*lkO6@&S!h5Th< z6>{xl*>tpc_x;v3EpU%Rsn+`uB&5=+Gs1L^yIJ<y_e@wXp<a$)KJP4Um=qF^&PZ<Q zBonwXBeCQPalzHHvs@ul^Za~G<B(r_?ixA>@e&u|ZG>Q|w9udT;{20+<&n`N(Iw~d zb6Iu?d8O}>pxi(&Rt{Ih$t+|VHhHJK<6TP@l)Nvydvczs6uNdIWaT*1S+eeB4|m+j z!py44t9``t@*RFMj>l(`W<I5SrU#mQt(5zj+hDw-Z^))`I@DbF3*PHoy4m#TP`5p+ z$2s_Ch|Y*2AFVCf@F4c%$q|0J|FZ5lf^;9#JdWd_NXiNz&A~rL=#V*VOuD>aB(Awf z9?2)Y|5f(F=lyE%1kM(MoywCr5En705!=?9njG1FS8e8ORzAcC>nRuxHuK(Ud+8fT zp@TC<=oaLJA3CTHo5UQLnfGHmA7N^W<eM58mbL6yX0sz>^2}i?Mt36bW7IYXgY_%* zj#^`S5Qno?(FdG|O~Z}LHrwen@9&4<BtCq2&DD>QRQ{8^2<xk-&5B5$Gsjn~o;tnV z9K&xQBM6T^m1Rzk{@g~+Uu=)2X3rySTe#ZcVAs)9L%PgXQp}Tf;mK&(JVZO}R>LWE zsu;sDn~O_K$AdTJRKFkIrS>lAxQa#`;s5>n>ayZ3U5gX|*mC(pUDd_e;(tUt7rtA0 zuKi59a(fHcD5vBP@uzj|q&4Dnv2Ig1T`r>?X|DegFevX21`Go@*|C0Jd-w&O3dBEp ze9?W`;IWztYC1Wd$>DV2)LP|=cUG!_N51kyy{i0a64|T1i3J0u8T##3GDQWmvYdpb z<^A~8#wJUbtVnb3nrgvPV{b{KQYuI$;Y4;qZKYE3rc!yqM7gYV`cq?4eVt^%B)-fD zs7s|MYL;<`>{g}xz&-EIrYM41(!f!pO_Lf?o&Qs+18uCc)PB)Jm36Zo`nhmqo?F84 zma;|*b=8aNb|tC$#7?Cyon`alQxij%`cOjCts^WP#$Ki8Bk}6gJ&sNv&Z698<>uW6 z@l<e#4%v4y%AdY-Q3NWgf4Z?APlEW?wD?Q!Y;*YyeMI@5W(d7XsxR=b8b-lmQW$#0 zITh0Hdx!=OSQFLyqYh9`TGT+jiOoafBqJCjgy*%G4Lr$>rjW%mj8u}ix~dC|(g{fS zwaSEi12x-4(fZq6Ja05$K72Jd(8XO;iYH)SS}UA6`m=mX(mK1RQDYZvfbB}rz1zN& zxQ&%km)%k^trsZXI*UQ4xa39Dwrdd$7s8~t!FK=zvvkNsvT2-ESA^Q8dSa5Ld^szZ z;`IbFJbaE$he{!@T`+ceorK8BRAw5#11WKjN@gWN89tcIscuf*&E{c?&MLU#7D;%y zzIqt*`iO<%mZ|Z(Yz{y@hCw+NPSy)<l4#(_D81R>ZQ`Pd=)$x#Z{TF(^+4+3cJXp6 zAn$t$6jvA?L?xo%kelD$TrJ!-ER}3W9B#Lm+39xk!uWjie#T`czxiSto9$Jx4sRDD zhqy|IhvdtqDt8aS^QPS%D-eVCS@$>M911|8o+|}b)Gi$ncBk(Pf!IhzYq4n!4$rhv za706Sy(Cwc_f|q$8}{qh>*i3P%=K!bZh;i9JiN$8dj>wLX}zVpt;f0%e}srhr+b8$ zGwQd;pZm&j3YB};?_M#dSYw0l2*C|qRo&Th61qC`vy~qjHZZ<Strzt7Vld^L!@@#X zHI=boEeN;#m1|i;&k>hixA#NJKu-|eWONMtW@fM%dB{+~WagJkk{q>O?7NQ31dX_q ztMjbfm-Pr01;F*kF!uF@_)is6{aj4!#pY+AmMwar)d1o;Nh6kplgBH$?U7B?TEf@6 zo066xIx#8`MF8i!Fn6V6FEtGTvUa7$q@G%P>kEUV+Vj<-9dTYq<AhH(i<;fH?uTwS z8aqG8FNHE&4GQhUaRWtcGq_$#{is|@H81mPH+-B9OfF0?GTkzUc5)ZQbhijcd}CiB zj%$^E6Elq-BAhg93afpKG)wVtEvk0t3oit&YdKN;>O_qiiyF(~1<_4E_c#f>%Oi8E zk;r=sIz)g{%Et2pWMW+<@yDH4GDueP7<a@u?22jw#aILAv;9l1_reDGp{G2p0Q>XC z5}Lamh^Vcxj&B_{tW=e0N^b^0$H~p2@uD6R28@1~8Nq9XEE8DWGU#=tvL|F{JPG|< zBOd_HVaCSjeA=RJcG45i{~ZeS>74*0Qkmf!I!y3y-efhZNrC;=mP?QmZ0^#RN!o%l z!HNjxoN}b!9oF}lN{_*Pkcns*kJ^n6Do4J}y<+Ud{ezJBc(5Ii$3mhhfoqJy!Vq@v zQwr<IiBr4aTcNCQ_c=%Poy^)X21o4XlS5xfa^i;o^N_dQp;U<#4o>1YT_8UW6{q6e z^LK+)2qZL^(U%h%VqAMzci}x_ZaIrW5oc;sqpwa+FQN6PK@hr1(Svf;u-dPT(j=mk z^efXCpUq|X<`ISEL5HlGA`2uTjDd%#=n5Fi%ll&lUc~uTAo}K|>A^K4Ks+MbBUm=o zO;xIsb4iOiZ=H_S_EF6TuJ-cV1262hQs-_lzYN-^6<mOaj|iW;n8p>z24xLQXN!Fy zgCELrSv`THV{@JWd2B5v*Cf=qu$leV3e~qA)7{iU%^T0n4&r1r;tFbxDiS#6vc1J> zM-YBrIHs?ws<3~XDkL8{!1!bw2LHOIx+$_Wd_7W_2M2(RCPNq`8WESD21WtFBm6qa z+*oykMo<fSC{d?B&>%>h^t|q?nH-P~s-r5kmp2zU3{9<$+n5%~R;6KsryoIU$B?Y= zi|^Hwf(aj)6`{32{S%Td_r7u!Q97=%cLnZQAdCeLQjnPtpaCG78z#~|#$ca~>J}vi z!mk1nWAD?DX_|yF)NeBvMwU&?0p%=Zu>%cK*MOjnqAlfO9@rS*uk#^j55SGE&v^7r z7|vEX-D(ww>OCp@4t8PyPz^>PAO9*7w~po!r#CRaH1VZ2T#6>E$*=WzsasQ3rDUS^ zVOot-hAq1j?>-J<xxy3p`^;AFmggARuU3)GK(%RmeQ2p=R&Dh(I^SLw#X)}9h44x0 z)!DDp%F|eF^BOXEH0Gt7{%Kf6$GGLq6b`;0NG^lznW!W6z$nE~M{XuymS{FmvliI0 z;AUv-thnRsQ=O7Jc_+>TCDWN&81M&41t_4u@ym7+Xk(do&^nb1T0~vFUE4;hYk8u9 z=jS<U;HLaYw^u|C)_IzFv<%!fdY3dabS=N{!)l<~L~ZchG;<Ob-5=4oJfpqgUOh3k zgU<ugJ8m2AffCzfKAAvBhqPinf`ZAH198&_PTFSlaQ7zjW)=q+*abxYLeyMmrfpBR zw-=}_M}(Q$o31|Yjtr+F1g4Hv+G=zQ-MTpz(?{JeW^ryt4t1&ND4pWgwp!c_eV*W2 z-;_y=7IBWia9cfd9-g6)&h4r5B#TsCDC(h7ly@vBoX`8|o`O89*CC0L-I#8mT0uIE z2uyH{R2H#^#SR28%1Qt?N1+O-PY3_mC7>sI0{eao!nqC^04sCloT5;`!I3<TgPF7+ zX-NtDT^aT#!dC=H=IItGb~bxX=*^eI3%VW;p!OvBI*fK~+Ke~!?@LBsb~jz&rFTki zDJ0Ug-Y-521mo8ypf(2>yJm<nkSI6WsY*zHALGw5N2oZ0#J;?cRm;VrzU22c70}f_ zBQt56h46fd!7tl<@MT=5<=?9=K4MwdNxsz?0BiGX>-gB4*=0$dRLwA8IR(w?yaUSP zLAkWXVLoO~?QiR>pLjb|B7ww3wKrXXrkYmrm&U*E+MYZzGWUIO{CPhZ0ZL}j*)RSe z<f*@xEA?ZqRa4qUVKERI89gfiY&*ml4-^OkkzkU~OP&Fm+$5~ZMuEkT*(a9<_-zMJ zxMTt>$TZ1P_0t@?f?9x`074)rAYq9*&I?@svbVBiW4R$EJ5iM4<|#;(=1ePVVu)ao zJ^oT;pIU-i4m2$dxmS)L!o)7<SnRXhAr>SP@{!!f^F%ca$R2#Jf4l~0e7E(AS3Szb zhFkm~kthqI`62M+BP}K*oBIq8?L5IC?)?K+Exi*`i)GJPYmoc%tRkQjKdl<#vI9#w zLa1t~FdF7K-v&WJ9K^+Hr#2kp015TJ-gt@|j}J*f6i7^h#j>w+29Kf`U+oCF6<E`x z6B%CDBsV0PUS_#oLou&kMK=y?pfU@BmTNR>;=$7k=P}t05AMLxJyj>S%Nc41<DCX9 zvoC7jAFu2%cZ?+0<%rc|xF1;nl)3~)0zC|E6(a5zWY!!oF(LhTOXUJkY^;DlQn)WS zy^j>7eV`iTR!Va*xpLb=cEUJ@=7UvoGzwbvlSsS`yF8Tv+e##bK0<WqO9qQ~9%eb4 zd<{u1dGrI6h_qEGA4Y`?%dlYPBikjQ%onMXGRJerb)fWI%uK0#j9Q9*wYY0}7>)Wg zShfD)lQ_a~tHPFfaWRD5M3H1jou#Qdz&nr1m=F{dY);Gt#=QJo4PNeM_BtY9xz2%! z6;UNAkP6A6HY9sUbH99vR@TU%n^tnFw`vzh14Wamo_=2Q=N|LVPy$EDdK+bckOx6+ z8caV3PN;!px3Hen#SrQvG}R#}0x_}iGlX(oY5*)Y=>sJD$4QB22;_Z%S!&QUam-9W zBm<GWS(&viLze4V37)taWv~_kH5drPH2o1IPP?VE-4}kAbv93H!q<X6i`#O6q~f`R zco1z=qkD}fjPo5<n?_$^2cVh}%$yKV3Oy||MNC%nD;Walqk*m-jGsm?Y{287!cGUB zVGuen;IG(V13D9`2!*5<Ws#63ZV!gVpZOca77Qh5O`}&K?D4LgGEodImdJ;WxWESj zd5(A#;W0YHz|TAe@}dS7Y1;u+zg<Mj>j>?<@XUlMQhTSX6K2opB18Sh)t+fPMTvnK zBn2QMNR<eF+H3RTi{F?B`k97nN{E!xw#oXc`>qk<_az9?V})4dPO9rmz-xQ8pg&`X znocT+(pMIS#QDoWigwmtx6a6C^LQ>cq&sZ}Tw-Jfi)~CJU7(G_Rz2r=P*YHwoS?{8 zj2Ql=Y*stMWIV%E&!dXU>}8;c`)vldAE)3)ArM*XZy~)vwg$F|dln0(y1~??XU<}z zJ5iI<Vf@qFj|0w#e4_Bj2nW{EOqa<J7T1J|dfAfrQ(`n>8Ri_f9A%rKIlj@XHrC+d zh8=(8VSHzoez6td3)P2@*qxZ_X>ct^W*ANgS$ACJT7!;U^*I}MUnOzECg|SBi-P?y zTFISHoUZ2(Ynb4KdS@ck#~OB6eJQ5+cdaf#BUd2s^%KUnQ8znhhu;!4w26A;QyOF= z^tl5wBkh*>@Qgv`rHTp|!0YWwzHD7eLp8dk0bN6K^HAi~WguZ%cqV5l8CA2P#wh)% z`w=3IN|ujk+dzh?iFkuR<H|<AY6AoMXCD=B0Q4}i#tqJ37{&9|-$J13U=lqpcy~aN zPGV+!Df)KBh?TVDYu#GA>em_$_~|4SHXsLy!i-|uB;S(swv*FSfz(Z&hy=${Iyaqa z&!Z5{YvuFu2w{5*yQnn6@Qu88A3+Mb=fQ9B)i=pj^Ue<_dv|73@KG)6Br8C(998Oj zM*t=1etmh;iWtSRWEhm-Xe!!E0((lc+F^z#yMFEz(|lBhEZKbmG(-3Z3;2PU+uN6l z!D{<zoY-Z4`mwpNf!LY1T6-k-R&uY<C2i?><x$U=0aipylQ7E8KpCupACg_L{<Ytl z)E8SBIr8g=859@%hj5lGSf%g!ecH?jxC0RwU57TtbpchiK=wpaX;S&O5D!pL#Ti{k znZ!<KdB2}9&W1+<`7Y05jw9I2No^2*g-Mv8#1i`5l^wogoXzC@*s`|;`r&M7$<W9F z*7I)12n9W`IYq)h?l+AARYgNg|ARNcVV;#ObJa>mejb8BN|n}AKw?@GG@S7HV!YEm zTMk@!=eDpDC$~;d8XRMI*21zhsSw+`0U!RFeNgmwSprY3fP{l}k1Pm+-~*3us532n z7hxzI4qDCvNCCA8?Q|>qOruF-tr+fA;E8{js5k%9Jdgk6i9DW^a?*$Z+MU!?1_M;5 z9^VIGNBn~e0)fzu*O$5339#GDtBK#M=lzBbpUYN8e7jtCE-iX>__))R)ot)DpG}gM z1T)x8LR?ap!|+1J51q_6OF?#UcAL@^vdMqO^Y*Ld;W1}7a05GO+vn=FCI@m~47()@ zS(QqEX_67KjAf*bu^`bWk^|f%k*EXV<Rtpq03#H1fGOPyZUWjMpNS=@Ord$ReCOMB z<FK8i^Tpf*07?!SXVRO$K2El)QOZJN(Rl_50R|M#4>;`MG>0P1J?B32?ZVb=_sc+% zi`tK}r`x^cuAkG@<1)74Sude5sK{iE_Q)JmsipPpTQEnQK&f8C?m%M=Z<&emJW<8D z<?@33(b8l6q_>>Q?FB+@hKMxs=neryfK;AenXCf4aJrG3KyF?T+DxUk6+r!rBy%<A zjP7fB*x|@wbF~i08Pc-TCeZmn(oaGy5YnypX`1pxF82pP-!K`hXB_NrsHGR7k?E+P z#*HV`Yo*~Vv#ePcEW86O4ksuQiG<3}y`q~*HGFMthnox8=ofdqg8E*N)OU&yz1dyg zq*XID-nJjtgTrh)&jvUFL7XM=nQ17MO5t?2e9tFg*v3M^%bA9EfG;ha`Y{h&kGHFx z^)uwB&eFE*{cs!8-kiN5qIau0=b(I!HuG#muPZ~gUg;zUw07}HYhsSnigcxyIew#= zN<1&@wz`;K@o#aKMT*C>U;=lt?Zg0Kj{Y_hL=70_`v^UKAP~C?rS+>hw}-t~=1)}S zwFpMP5$}W@aME$au?2`bZ19`YO}>ObPq#p6`I6BqyUgfAg)!Q5GAm(xb?y!Y9^Oqv zgUmOxO0ZU5iqY}nqHwqvd0cGu4T*6*0m0lg$HPj`ucX&|KPM`;oig7kO=v{pDGnm> zW;4|T`pStW(suRhXt;fl?~=lbF_}Wm=1p?-*viiX3}sn3rb{IH#Pla7T<w^?A4mwH zRGf%eW@3Yi#l?udwd2dy*7Yv`6NNR6y6I0c3681RRe}k>OE94+$q>&lIL2sJ3AD^s z>R6_NGA)7xI_CA0ehmI?9<V%AF!=5`w1nF}uFE$NzQ>ykLT|5oyi^D>$YkWvIWqGx zqIPxR3}1#~(B&nTs|kHObPM=#AMWoDu$@4qrd%EeM;@lHrfoprMf@OTBXZx5?PonG zA6WKATr@HJ(ZSU5=FV9PAaD6}+S&F3Z6xXuTu#enBexO=TCUGPdSiaxn<Q)I9d;5r zbk~Lyu|)o8|FJNTS}Nw226#ffYL8!ruZlps4;O<eEbQby1B1rcD3VHkw>QS~TkTSb zQPUjH+#^i)NVJw6Awp&W92bGZ7MOvOq&c??Y&;tFf20f8a7fW<GgxAd&N|F@c>!Tp z+YNZ(0eb?#I`Dug`|zc~v%Df)A!4`nt=OxK?Lkhxew`TA9^@Bf7;KNfb@E)LK-<4z z##UyrhiHK1iUX~{dCH`9pEm~;O|Yg}F|H&!!i-MseQaiBzvn)7lY}+p9s&}LGLk(> z_+u0euwikZtHL@5w+b%P0!_UR+h)`|*1*Lc(&y^@w3esR33;~7b@7jvX4JjBblF(6 z_^vi!!O<wj3(45Am$q=TI@jHA_A2<!&O8rB!9-65-j(8&hErPfQRDUYl{{2}+9=T) zxbk?zUvd?VH96b_!gDw3Wv_Z&nNlY&EZU`*#YL^>Gy~g+0*%lM@3yO)eyx#Ypzd8n zE4rVvIbl4<mmG&7(NspG$V{4EWJo$hrKn=0kAM~&z+qEWzmVx^+f{)u{FYZH(@2z! zWm~wm#+HW-WP?6LOSWK~E3&&#nNu6lv1vXGRRt0qVj&3iv?mKX(h;@OJRl|gF}lo3 z-(Y0k%087N7-AYe`L$bun3BITRbdef?sndLNtcL^H^kM*`lSe@IV^joBkXo|M^3PI zJR1h{g$F4e7q}2ru^sM<Vt5M>7$imtlb<p#T4-_|NWr2-C^*b5nS&=8C)&`iw|*iE zsS6Yqo-iyNFw4**o(#x-8$-~w0gt#%ScgDI^VD9;@jzGTOHV1BTIiK%*I_Pj*Glk2 zYlj(xr7p_~!9{p4WM}$VTJYyv802k`4KRT5s`O%6B87Vw_E;jxwrV<%3`@LzRV_Gi z4=#%*Zz2J+%$t@{i3`lS>EJV<2^@_>n1Q=_RC-)G3m1RImIR;23jX72@7n(KY~p%* zWcxZMgl-^VK&h7}_XU|Ek)SlKFvsU*XMekb@4MUGVNd7#`@|alyN8#f$NjF{$8}4O z*c@i&Tg2Gju1fpx&Hj{#Mpd<)?Ika)ZxGD=Jv<)o^T~A&-_w9B!n>2cvd6Bgjp<=c zc;PmZ*-A968KT94+fmbx<qmh_S4EVmNOKJth9oR~n~ZBmQV1;BA(l}|R}#g6IDesH zx_o7%+4`(Qa=Pf~W#Hti7AW>=u2T#oT1o*f2FX|SWMe7&VlY#b=NICgzWKiB9=-Z< zjikeom)ovufdPBJ_PU{c1f5D08O0O<MNx}p%|^QFdtLP2yMq-IKlJmrvA9*AUp{ob zquNKlTW7w-XTf~2Q>XW)m7R2wcDdd1DOINowV9at14V5YvEZ2O?zx3nY!JH-7iXSQ za_U_M<dyGQr!O`aM$T*!6nn5Jj-sxzd)g$lxcFAlBU&6i{M9aZSeN>em0^w%F2}5a zb|T&F{D-9+j2$p`u51J5?zGYk+6u)$K})CtMZ@1k<D2#xwZ8RkpL&|NMINO0+vJ_m zq=$brzje@gUp@^$=ta8@>B)6J?LNKuG^ZOmPoB?g_T|mkkj9~)u_cYwQ7f!Dvx_`5 zFAQbsW;Ffa&_McC&U=IwYl<-XrCP3{X>NW+Z=g)H@j?PZ4KBxaGNNlMrw|3Qy$-Cs z<J1|E9_(v@uy&d++!=L{G_^R6*AM3KGS*x}?TC>(0>c3ynMH<$0tCYuHv%2%&+pw3 zk$L6*Z4CNCu#^VK0wu4dU^w`q7Er5NRT3K*jXehI&K@w+8FI`GP5zYb9BQ#|EWM)! zPH<3HHq@R@DK$ruS(JQ0L%T;1&`P;K1?s?nAS1H+#fl$=;LajVs!2IWhO2xpV&C|1 zKwn~VKwtWJrGRxf<Q`n%@!Gt8`sQtI9rmxR8HrC~4kl6`B9KW5!)^HFIZ6O6I;HD8 zZR|C%#bfCR0LKc|CNTD{*3x<a!`FSCmJ}p{>eiy{D2769e3U+N&^2hUx+7xnuMH70 zlkdMb6HMe#^!e?{gg-Pv0r?rZb$2_#K4FAx=5Q!pV~OR_7luxna!v5V>ET|rZZUGt z(bE%K{liY-%YmJd7{OqG7%WZtI^W|-MenPR9g|fO%}PhsSk80E&BMZ6$;r0gszT=^ zZj+r+zo@S2ejFW!=_@bS&9@ROI}6}L3->pQ!~xPpJZ`J2y0kl-_g^dR;F%N0g=rTm zk{QpOuIq6g&4a`P8c68it!Iu_{d|_~^Ky9_yibmLKpp85()9RTd*MV&3UOOe+gsfY ztZEm%xxzJ!ymaC&FW8aL9Ae+dH0jfs+`2crBAaAaPUuLCDXz*^#VkZ}a)2gYr55TJ zZ7ik+AKH;GH;*^gU0EtUL$_mO^7{FCY4fSur@>x^hA|4EsrAiuLR9_3_Yvk)I&`IF zKu4L@xw)_L4iOpBW$8tb##c^B^pYg&`GzSO%Litig~(F8WLv88(bY-)r>5SR=rt0Z znBaGhFvA*uSP2Akmx)lI$4721caPhJE?X=U@XGB@vp3u_#+JpQe@4%(>=*a7xgS55 z<2n-I)FlPTHqLuAdGp>hr!B6I0_tQv$?q_qKhj<11F%}YwsA^_;g!J*wkX14TR0Hz z_5h!U%!=DO>+FVB+(98wV!7g9_SIWT=#rqKea+hf?04PI$c<zVE;x=v74jk6CM`;h zg0YtKmI|gIDw_AXQ)OQJKa@InWDZA>0_&%-@k7K%1j3;oWFjYtMp)pKRXAiA^Yd?$ zPA?Alng+QC{(KNvnopI%R$hq2RLXw5X>C*WU7%~N8vy_>{BG)PpUExVIa7x%euba0 zvx-f{9jc&@=`ZD{i+{3&3*&)GIXPiV07vdN%ML#g?h9)DpmHTTE_Cp93!>aEWEy6z zu1FLlP~?bVY?MK76YN8^`Yg@okXv71!Zc@1Q)Xg}k+r!V*sh3eap}s{hGdA<>Ka^@ zWdQ9tVxmMqJrXc(SV97~Q4ISme~Jd0Kel#6m<OMHW$S2-V!HfIh&Wl4AfawYT$eR@ zdO9xA2CTG+oF)bej5ka-zKF+fL(-|b*|5EeGCA%Ji@j<ka-K(iHDkkD46J6=m@REy ze`!IOqdulT-qs_-9}WXt>e>TnS-H3W(Z5PLRRD|NdxiH*)p9Qg0%DjD2mtC_9;c~A zY?G*?6E}qdoNW<5wJ~KQnehe-+l^rc_<mp5-KfGlc%fx~;G|$#*WY3SF4a_f$5&g1 zA1c)pt_u8=^)m5^m^}K%;pez$w~X~f7&ny5dR_*FmYOBF%)!1Q4t*2ouD>X|qWxvE z0*E14bNOQJRNO#n7T283NfNe2CX;NRa_5|`n#~Ti#C-uK0WPUp;PoJl{<0~U&HiEy z&uP<)2O?>EiMSx_=4`V;&y$1Lu?_v+$&sph&ecMVpY+j%PY#yh?9^>r0Rv=W^2Lk< zryQ@;M_MBap%rSp`fSA^TM*iJqqJnK3f~C*B8I}Cs=g9uB?U{t$)ZYP7E$l^K_tXx znV~p=Z+r*lVt(6<3D7n_FwPelPt<wbZe5h2V66JeGoHjZ?lZ%|_ZcZsw&3t4+|!oZ zbGCvPK*L~{u>!1p-FpN~YQrUViu1cw9(F9EGgEW}(b)ox7@qWwxu6FZ=(PazDZNjw zZZn7LY18I9B?n;9-+bKC(S5#ej!$$)PY)Zm^Tum5xWPooV*ipk{Dw7sbJKaTy$Yua zgx_IYa!q;c-Y8jtFh&rhALbt==LQ7sWnnf1>Hu*%S-dB=sAeVe9R;Yev>OSidx+G| z5MD2_LoYG=Sx}-5zJm9?mc;`3tIqE4GM|B5$|1bF1%t~p5jm!h6w{O`eFd&52ZfDR z_#jo76;EEF<_;$c1G&z@FQa%6>Ry*SO7(-60Fo#wSmyQPa2~uf-m6M<x*O`<3bjWh znF3t-mFlL(rv(B@=-;<lk<262qxTCn9{3ZuW(x0hbrPnQ*P2wYPgol<3rfr_KRW~v z&L;gB)cS^sy1(7C=rd$Z2h>p7*fWZw`KErp3Smf)p9IAjbs&3xw9lCg{4jXt|JvYx zm9G|p5<DcH;&BK&2*0y2whu#I(xr6ecbV9@f)cf~hayNE{(VuTQ0$~nY3lc{Ej=;c z1}}OEo#{@AXlGi2^<BABUjd_hg#+`ib-H|wAdY??qxD@SQ;-Y;dh3=pRX7q~jc%EM z>((=e4^$WI;6|FmW6~DnlMOZ(yEZ%P;3Q8n!Cz;)(_~&cnyNM`>AQde_Vm_*Y@lgU zu6^eW@@0#iLBp}vGuTMu`eR71DpgoEp_u~x*%)je?zt(YRMDRV&ub?k{U&izTci>g zd_l%vh{fUOf%rVkc|4Bhtr?A89F#?@mW?ui>?-(jI=>sixV9$}tNHepCs?ptiz#;0 zmD4~#Uzy5L>N_hNx_=eHGbM(%Pp`C0^^B01No3ujxR7*yI9EN_3&`f@kvmoJGyDE> z|AIIsiNsS$mEu)rk#B!|xGQ#P#UpRaZQ#vDek1U4b#}Kf5ODQ-TigZD+jCh3g6B0W zGXx@g$6e6KsfEXNhy$Om@WqgJp8O4vbCx&~v;@wsxS7+-`>U_;`?$lX8d&Y%w`IJe zt?yI$_xKOg(0J84^Y6P&5&c~S>wU}Uuv9Z3MBTv#tP`2@JZ43@cBdd>4-B6_PRIlf z!vAD$d5gF5;-)sNo(9z5yl>H3n3Z?o4Zq+{ubmJSFvgr9dU)`HI9dv9sL~-<-;y-C z6D))S4yRRT6gKnrQe8WHqQXMDQok*aH~-EcrPZm{xjekzY%L$w{G8Og%8FOwZK?(` zkSfeLt8o*j^a0_Gq9ijvm-OavMzGpjm?9X_4N&X=iW7i>-dW5k-cljTg&#y+1N=2O ztzXLNrBT+ESz0KaWq*+#wTYG)O~Jy0{y;6_g+-kSwR(m<J|mo3SnR~?l_wU_zURoW z@0hr`Zf~oXJyiz8$&OLVR4o+(aeE4npekM{uw0^-vSf3Mv3kFq%#5V=n<7hv@|27Y z^JvMn<Y(!Gw{E5gRn%Z_V+4L!NH%bS>Bn{`vdhT~jT;=pifW=TX)1M#uPU#@j*?oB zL`8n1!`Jq#94vfKdoMjuOF}Omn8`+a%2K{!u9hKt)BUC~c1n22MJT#dz&FEG&iZ3I zKpoRSn^|#E4CZjLU`AAi&7~ou3;NfxOOqR0o^E$E<y0IBWNt&P-^WV_o<kZf(Q~AY zjzF8fx4`X{j&$I-4&5xvoLfV86RRA1QdPv)lq31*f=S6|kN^)(xMb@W*J+O_e*69! zeOFX<_2YEl(60XyE~kf^8!iU^!}$?^yTyl#$NADhrpu?()6Eg?gL0#5Y=iG{-RFJR zjXt4!lDuRni%WmLsg{$GM}E1ty&-#0!eyz={&xZGRSNr_J%`&^!fbicmU2uIwz753 z@SDClQ2HLy6Ffbm6LE1?cbK0VRbj*E)ufwgVJ%FiF}{o3KDbj!gt@)3p;$b_)>@wN zgJ^*kSYJ2wqSjHUvq6a_g=4*o=khM6)+W$>mDIsON_f7c_fwILG9u+_T87tgiNuC= z0j7c-Yv2RXh~?RL1w&4=UAFbu$X{#+F)l6$E0ucP6o^MPmVRmrCE8f1cF+dfdghBC zV_*k%1V1VfK)9JaiN&;mgAf%P*!9t`;OTjlxH^m8*0`gYF4E*9)frQ6v?}3obw46@ zYS7#<auc2<t(b%1KWG$)4DAi~6bXMG<B#m{)|{ffRuB!{2FvtQzmw>(PwaBxqk~AA z;DpPSub>!boSo?%DDULa7RR_N4>Lrhj_OE6fhtjFD`aymoad)j^iYic3P+~K*~)g! zlols_$w2BnZv$H%ejOI5ps<_U9Gx&nKRySL;LMv`X!XprjtD5iyWx-9CJLSK#*EkG z|E`bR*p#`0m|{|b@DOErHmd$IWwWyOsqtL@^w=(j*^6ve$|h>--Awc)<G|%7--0L{ zq?gWA0s5m4kh~Po=b!2SQnQ2vq=9wF6VLbrpnsOQX2k;lK0~tp(+d6mb?Rv1;9}zB z>_o#z%g97aPit)9<V<5>YidU)prR};r>I2h{LT4K<f-)UdH+wzOu^5P)W0J&KQHvZ zBc&yTL}Zmj{s~FnGnR}44FKF>0sut+86yBt=!gF~mH!<nBcd!IETAm#=MdpOc7+r_ zho=Am01*6*=lSV}|DC5OA|$6M{3orqWKLc0lVbbX@&88qLj3=usfmk-NdE~V-|40O zjN=7BeRlG{!AkzWFlRe^J!=zJ6YGESUv@XjG2Ca8iyHj@mDl_?x6tq5FHkx?Jque4 zXFa{obeBJe#RobV5B8~r+V<Je|84$xEc9ce`tKY+39crN{}Sx{M@VQHM+eI1&Jh1} zJ@(%q4qyKYv9NVEakMqC*86ur;Gd(3y4)c0`doQ^r9bD>P4gF!fw6)8C+T15JAV?I zk?Jh$KRu%VxuZUv@}E}dXD#?wg1yB*7<V*=eRcX=q|MI-`b-=8Pb>6;lK88!i?jJZ zSie-wgOGo^@yBQXS8@4&w?e;i<-b@PnK(NC)5s}iGKY;mop}E_dZd5bejY#XSk=Fp z+u7I~IRC@tyU5WwdyxTvcQF9q^YEWm=$D}WH+wrPi~k86|I>AE9<nS<pDXA9^MAw5 z|4k_L3$*?Vz~q~eiM{jx({BBf5u&aN&i~2ifc?{hr}lqgn44JJ|HBlpC7rh2KfU++ z(+z+3pvGrN>A!DZI&(WatAFy~pH<`kI{_fKznK50hWwv{|5F$EzxH}rf3g3IO7NeA zKjm)!OBl`m3*j%~w|^4;Ok4XeLAd9yguf@T{Ym*VbKt)eh@XF>{3VazPsX3oy#Hmi cjQ)l3-&+~%bL0Li*A4^V_jx98^{-F=2NYKwNB{r; literal 0 HcmV?d00001 diff --git a/venv/share/python-wheels/resolvelib-0.3.0-py2.py3-none-any.whl b/venv/share/python-wheels/resolvelib-0.3.0-py2.py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..7b1a28acf42ef5cb214a5158b5d7331f892e778f GIT binary patch literal 15663 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 D#pD5M literal 0 HcmV?d00001 diff --git a/venv/share/python-wheels/retrying-1.3.3-py2.py3-none-any.whl b/venv/share/python-wheels/retrying-1.3.3-py2.py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..bcd789f8acca8d7cd17827b9c343fdbf38c1d163 GIT binary patch literal 11621 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 Bz48D6 literal 0 HcmV?d00001 diff --git a/venv/share/python-wheels/setuptools-44.0.0-py2.py3-none-any.whl b/venv/share/python-wheels/setuptools-44.0.0-py2.py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..e962ad5ec780971814cf1732e7957275b4778c2d GIT binary patch literal 472710 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%0D^DR3c2J)>d79?LQZ?iewk^+6H{Mfnt zC*VT8a=91eUyI`e&0rom@QVRvd<($)a+{*A9l~eV(pUfYM%&z5K?Hx~(ASD<`%3IL z*GEsd)dF}na<ikkyywc9A>*1$neLrlq^<;E?|}#O6DP#g3N2e7a)01Bkys1<*EDCe zT}5ch)h4UuYCtF)q?q`W?f?`sSSnTeMinWRuyQSy5#D!A9k2)R7tA{F$IR~frT2IP zXr(zVM4ooPg~8yCn*7F?rX<ygNu<ZDZ-;G|L&L~pcsRkGXqvO56*^yJ^$2c=ZL8j* z#wkYu;8kiU)y9pE7i8ED3BPmchp^B=`(VDqLO(8TOX2ODvL1i6MKUuluBE@`p^-o$ z2XuU>*|y48CMpRD`PsQB=%_)yHso@40KVexDt8akZ(&bub!53XYgTLf$Bp%>X%ff@ zTm4QAsDi&<hhQrMGL~mBA&RA3LOQ4n(UfeDuA0^nLkImtEB#Kl@AC(J*tl2zcJ5** ztb<6JYABrDA2l)@ePZX<KJhG@J`(-Y@%I){J9;C$D_7j4r)Z_K!wT4Xwp_TpD|?qa z^w@apmhJvD6R$K&feC%=21t?x02wz$nbZCj?91Uz{nGl;fI@z~u<ZG?DzFP7ms+NG zY!(&RtlSH5FBFqg3<~WLVa1LjXE64k8L+6j1%{aw!CII$NSsFfE@FvohpC%*ybgj6 z-P6k`qG4ZGPY0?>G&id6`6X0eXG>Ej_Z2|oI2Uo*@WU;y*l?jG;xah`nN!MhaAr7m ziDkr?X%yhY>UT_iabqAaB7FHc@|wwSEF`>&N1vg#kj#=P9dT-(wi4qTy&c{&rXkw| zBH^r(HM$Cz!N+mm?Z2nD9L2P0CCH1(8l)^f6vySq**MS=aM~DjVai}2==%DU>Si8k zRgVuHZ@dStx%msmx~iL@OXF^kW1$fg&eU!R24!eBmIc)^Zp*F^BoumuN?02f`Ub;f z8p^0&^fQsJ5CbLJ3_$?-`);&wjdM=Yzs?f$uZKLKN?+iljpS7>I>)Us<e8xR#eTJa z+9Pv;Ec_LWkc+ui5I)KTYuz!VaJBJMLBQL_u~E-4&lWqvzE=yyJi=+DaD%|J@jn!0 zPu@d^m@?@cpHTqC%6VZZu13J(()pwTT{?@pSh{hM<dM8=UO>p1o>)F>=k`*MR_5Wa zQ|x-ZewVXW?ew~SEu))27^_Gvpma??f`Z|-$MCn8usa1wEFOiDKPJn;coR}UeO6bI zHF?z>@Izh#4!?<YlLjz!_f6%G2*UG>@dGRpW7oylGALxF2?_+?mHuJFx3pHxN*m1h z3)Uo_T1C)hePEZDA63v8G_Liq7f=#~(m!PDuIm=Fg6gwu_gVq3lg7(pL3CJf%if?( za5p>wl(JyEoKLL!I<of7x%7aRrHO5B1IUMneVm9Q40XE;^gd8roSYet%ql`)i?89b zS$#P(yQf@&v9Ny2Iq_(I3~UGJAk#>-MnB?dr#*=RhO%P6)+;hxS+b(3PgcZ9ojMsK zIf60K6(6@b9EERHtf=~WDxExRZ+j?Cj8>YXzf;t|8KB&{gyP7=gVaX^Eg_8~oA9za z8O0s}5W~z6IV@Q|nsZ%dWmyiSZ^BCGr&B)+C=1BTBy$KZ@kC#W%_x}i6ghBc1=0F& z0Ql||;LG&=)=#|%?bU;TvkWM;v<(gt4EYLal-xp4ISeGaeeX`&vErI6C<Y-uRckuG zqJ%+EGH0lpJmnEccl?VpXIojj7|wnJ&Kau8dGu%u_nLd9w-!(4%xv&ke?UC9ocy2X zI|N{o?QfKx%&~qEy`Op5CK%UOtcuJNCUFa}YPoSAsj-$yrRrfb8Ua9%JF*akn=UEB z@tvjWR+Kj8S^0dkaYztv0i7)0+KO6Xp2q1P9IvY-3?-ZZyk#k6Jb5z}S56hraC1^x z4bTW0m5R=9Tuz<574iN3?4mxHc3Ir@o9`bSq)Kr>z9yJN{xK6iL2w2tAHnw!#VNw= zL|lRdE9f*3_9v-&522$K9*&1KwYDEaoknO?kFhMQcT|f@aP!C57?AT8v=LSc9Us+l z{-7Qr(wL{r(o01zu_(1uW=WxfZn*_&${DLR7Cf=`MeY~`lQ35^fc&wj%FW+aeQLEI z;ex*9s->JTzhJ;yyf|kt`@&~5WE=U*>@gLL_%`hE{+8JFT(eXwU1T;NX$Rq8?QD;| z_rO+1&{zCUI&lpv`PhVb(0r&<nDZusBpgi)c?2frr|J=6{H_p~+m3<y=O+35?CE^H z&5G^zfurARIRU$a>Ps#TX(}zyR5&+MJjIm(Xny9#lKY)@1STPqAE6G&wUgQux0cOB zXGRjD$24J*;giY-Fig&dt(btRb}6~R(!4PewVBH|u_OYT-y`Bt_~X<V5)*J=NjkDG z3d*$m>KkCcol`}vB<wnxNWg`4N#-Nn_k0_&&3@gPXX8(n{vzUq+$<tn!y`ZBnA}BP zM$v0ly>%ko?w8qV7RG6u8t5wU+d{2^K+v#CEyDpw*o@&l_{%P)ySdd-lKW#1iKP+= zOmRutjghZb<3(i3)cv+2OmnLWJc_9+BomtQDV&%nmlMP5$VeNUPvV9LjdO~c$%59O z;;0EX%of;a`R)_4&doBSf0d)#v|9uYsMbB!!o1<2T*euPU}jv=ZllhoFonCKQ&ZC& zcS$-i0?5X*nJ7OX>}VsAawI?HB-%l`-;qZ?4<IU1q%R*GKtD(c$%$tRomvWLxY9za z(39Lo7|oSpJ1L+kKjG%N_lHkQ{h>)2I7R)|OryVrCpHjv+er$ocI?LUTbI7zB1C)L zQaD}wd>(mSJ`RqKU&Dk5j>e!+Foi;Naui)&nqUs1>@qUNRcmhdi_xTi2J^~NHC6ra z^vr(0zt?a(!}>-9Um%8c(pwD1nzu?r9CC}Db@h7OpPRGMA%SamyW(<HUlm@Er}xRT zorCfHoGXwP|6*Vww))^5X{EAL#OBv!4907H0b>6$$m-XRb!64X<0f3;Me+5<GJJxM ze^5+UllYmB<hBSKsl&Ep!Z=;gS{V9%-;8bD0udl@u$}-qc-Y40F7A-`Yb{j6s@EtE zj5c&prJiw;DCEp~`5UjF*un|PC75)00k1w(Y`G&ceSj;WrCr**!bXB143z`f_N&)2 z`<_~q&V6oPss8f0e7wH3<|A|ox)JpY4Df~(pM{TtwYt|eb)-=hw?~m*fdpJluUTm3 zpUU)fMLsirI}30=Z|<+sgbE(cU-6Fd^u&<&sx4#mDcTmaQIk}KM`bv`tf4&i!RPPl zeeA=T{#%W`BjqY2H8XlB<0pzt{$cWVt-i#B`o-Vz*&gx+qHxK1jFM6`Ku~}l&WKSS zp(&C(9}t8@tiIs$bTO{*dOgAOdyxI|eib}lI|fn{#&hvh*$S!H3A6ht+Q6a`{UU6? zd~JA-f@;T-oEoXvOIP7!MaC5OAu7^(Cr<<Qq3U%6kh5{)0v6*oL_d;~92}P1Dy^&p z{mK1<H(Q-1YE($X#%=x0cM(A;C%3p#W;cN2;}H{4bnbZbdo%7gS6TntSt>V0Kg)xV z%!u7t%2V%kbx<H0@rhtA>lI(Ib$nuVeSP%qr+zf3KPKZO0)Hn?SSZ)0AhfY%feo)i zttvF;5G_G3-Yb6S*zCnPElv6w%O6K~?}4RF@>@j#MJYGtwNpGOB1&WVh(T$OEkpK= z0aK4^u@MS9l1GF+w(n(|^>3EBUw(<7grR=R7%E(xjb~fWvi<%x0vXk>Q*OWh7oOYg z0%J2@UT6XiM!-?|@b=7-CQD>QyZ+(l0=Cnv*|YQO*)?qwdpk&1QT!g{gQ+q6319wd z28d)=?5Jus%GLLrd_P=5*Hh<8ZfbmE<Y)NOk!MDD^VlED?SKpDq5KzVr(su{a%PC0 zatl6eP#huM(}U!BB7Bdxg7T1%hSF7Guzdtx5+yx|Bu83VQR09ByZSX{Nc8E#h-*&a zmGef;@j}&^KiowG9Hq%^N|L;=@yqSBBTw33336D($&<rG4h5uy34A9;a44p+e_=oz zop5I8n`s7~FCWWwPSmTNA36zQr<%?c*V8Tw+u=e;<GC5zg_Px{Ob?mRaX*9=cWr#6 zhuzinv*aiq<PNBN<X>5A3Z|${LrpDge~sm#c}^`N_}1hxEXj-NGvFUnKsI0LUHJry z6)8{h+|5z{K~M|?CH+!tZ?;9kgS3SRUI2M^Y*lvt><8&v^Wg!P5WzUpj5gU?qbWuz zoOX6s-13I{t4}Ma_3AE@!A-C>%{D}K(Bl*%wIFRKK)Lb?NN>^C*jtiTF8F*0_Dc(L zIG`Q~sr^<F;#J%U&p*+XM^nV*Oo{YE@n}vN2*Oi*BanMAWX{k2)LZ@FhpY0L_Ez_1 zM?RD~f7HGlOp{wz+6LK>gFwVeD`LA36&Bo-p&3KnpFks=vB(jMc4YL1Y~bL@Gde{y zn5UI|E$HdI<z4s9w!K_t*QU>t8sWxo^nL7-$ADe?_;#!Umyv-=@j#_og4{6+Hv?|W z88EW-SK`vSX-vuUwhLrkJ<Ph`rLjZL!G*81)bc@Mf<<Bd`fdP$>k}QR+=|IbK$l?L z9kVCNWwC_`_TvLP3`?E&v)e$p!I(&F!z$QMZlOl#!a)bcc=L53K0>?|*r&pr?*5gc zM7m&1KFJwC;JP4<;$2j{DaMQ#A7YWmQLbvm!`O6c=-;h@NwSoedP~C+iwB8eB?v)@ z7ek-oA$}@%Qhq`Vi>+377==9%$~O*Ymb3h|^|UX<J2WcKx*1;=<yf}IS~uO%vNJNr zTb%4tz!J@Z`;`rh-P}yIx_@#y({;9+8fjzhY6WgBIz7tN@^QLE1Qa<aA(_cNHKC8A z^CW*HXPmJl7TzIZJPk5nsKE7IGW){;$mSPhEUJd9zYl~@j!(ap9Y6JTZRgh*A>)8G z!aNm8!F~p+eHf&ku-n(}*b!MBvSL6{&r?<*IhJFeyN0d!Yt3HuIY%czrh}&<q*a)P z!u7s|BK-DT_|Wc}>2?p_e@RJ@kHrD&);IkjaVe#^L=8z2vN~VN-?I(%1jma3`wty) zaZ&!a)J**&3~fVnPYLv`in<YNUd^J?(_Ve4seZ$z%zUF-4Gms@jYRH{Heug)zBNp! z=uU-%fsYXKRz(_!kd9NNg1-DCsNQ<{&ROsD%$8hhX8pOqZ5&B}&u-Exx?pWwR$$gw z7WKALc6a`7C$}|BZXjc12P4lHQqDD9R7fPKJA@EdY$y_viSj;yEisEYK{JpiCcRc# z)$;XVE0a57{xe7vRsI5N)BZ5bMChF>p$|-Q+p=@Y?sR0du8|y3=~SK}WC4iTCM@Vg zMF5)2sN5mmWPq+hzP>g~K}TweB)*Xt#3KgJ0n2)mhySyhz04;P2F6#RIH;IwQmhtc z7j1-1_a|42xnz4Wd;8-=){oGl%^>bW1Xh0qRu`jurgOYoyD8{5M>Rf`{X84-`HTSC zC5TMCi-`@-X7q4}U8DX0hL#1_{8z4P>9I^nloQy?S}fecl5Aes=j-m*RTfe#$}GSY zkQ9T<JY!_is@FIbq`(YbrrU2hn2PMVDaTAI6tvuNPe+JXOf*VqNE_ehlk5e$JIj^v z4Fxt(DxP3O<VI4GC~pobY`lXZ|NSQmMpUZ_<&Et~#V<ydm~z-db5^t6F}q)W0Q_;j zm8^TP^JbdruVPhH<{^FRuqa<Ia|DlxpYw+ehcbN{fEFlBZPQ`@002R#XK-&Lf0|BU zZuzOj9;FNngx{d)@_?%0xcspIUilewPNryFqIkqT+7tUGEDS+c(E#&7F@UG%*=+>y z$3cpl_6}xQLkbkci4Ch@6tBgi7aG#+=tC|Y;m2`4^_FW;YU$(9Q%fv&;UbcU#UDfr zIJ4GEPV}R|1Z>A*vxOF<P2KwO`X`{R3n$rG4EXYGIoZg8k7hjp;$BhiN2tZx<B8et zeCte`c^n>}A56evt_e7Zk`g0t!fw_pGLH|1vAJoi^#`2idWgWkAxXVGpHnaFnNVPi zqP_D4Vx*0Ed}NaJ{0UHQp~zBqC}LlwLQ`D5`^Y12dcD$(X>7VrB7_DF+oe$hsSG*p ztkOPLh9e?}>4Z-buIR(_07~$g4<O>YESZllnpS!eN)u|Iej1sZlDJ5!ZUkC<sw+bM z)j%ai9qruyzq=&t;Ag{q2;DJ!*GzxtSa&$ukF}jzI~IZ#Rfp5})K*M`qhkr+s>0uN z^C&)oD959XG>xRQbG4S>BmW|v&J5KNWmMrQ&l{w$tGh`Z<Tud%RQr?+iqA)vfI<7< zwuz474-8d-0TiQ=hW0M79~#>;0}O<niSj`Ntd=;;wp2xZyZS=<&?J*D-}=6G8Vf;3 zcbQck-k5cXZu^v#fn4NpW-5NQuW`@U4ULtx92tp&!L~a}EDDtm!5MYsbGH<i$va?C z?JvA#yJ!x9$GC5jkAM*Gp#2sj+R>%KV<k{+zQ&fvo(zA)a*7yFkD^!vi?+7~Q>pEW zF$!%H4#S1I3QSikj_3N5vQu&RWmtM-b=tdZvi1aFng-I;db!SXpxP@T)X~=!zK`v0 z=uwQO+rC#B02i#z6XQm9<_u6S(bi75GboS>9O2uy+Cf<nP<42>PTS+6%@)xEHBQv5 zH~KXurrjnavzqEVSom7qdBNbq5&71qnV@+cXBC|Dc?-;?17m8TlJe=QHqJfE!M?bk z#jGK2t6v7x5y1g7ny4w08M+~|bSAb+%n(cmjU;IBj+@-{m)3bGzZ`)^C(arLo{Co; zU^{z@(<#gKzN63Z_hIUSuaqd5zjk!=8*4$D{t%S%e_}}-pVW+@KW{!>6Iazg`DBmm zc#A3IjGfm=w{Hvv+fkLkJN1OYxgRAa)Eb({9-E=^_souSEr9t&=fWb>_qFa~G-p}x zz0g;Db9k=6e_`VN9@8hO)%JQbZ=EYwm$-U67?`~nweR=klz&&tPhQ#|Xu|V}x-<;) zHA^tBB)pT(jDmdP?(3j|c0fjI1@*e=xcJA$!+LP+?)K5qtKJavm2}(RY`SwuC3{>~ zn6qH8H#t6C5|rjRo2jcK@xIy;v%cwu<natwSm+Tp`P%bbW-^D?$D~pfp3^bl?j#X+ z3nId|%lCIWDJ!sFOPH8yyuLj@l&qyqUg6R~a)KRQxrBL1*susV>1@p<n3^Q@+iZ$h zYG>w!A^nS1G=($pe>()(f7j)gDk249Ji^j)=3e&fzBWU{$;gJo7<t#TyD6m8Ax4=Q zMwER`!85C<eYY~Q5f0}c5C;JEqBL-Gn5uS~+4@+;<QkI~&whRRz1Zhob7g$euX)T4 zM=loRj!;*0-<2VXf>05D9<t#JjemZqe~$QYAO|elP~b5JgP_!*ITZHg<*)$zF?2V1 zdV;Pgpby?;E#EA8@jAVXInOGuMX=4BgGrX8xRQ5FXPR7c4Z7@z#ObxsCL{T^4jhV9 zI2Ed4h}y-BqlILLD|KWS)ytDyUzKPd3SfF~j4A;OTp>TtdSa}`J<CV4GtNpKqkg0Y zHe`X+;(WA?+VK9=-;&eI$d(PeHg`PcC{$o>EC>dJzfs&b)F*MidsCWz#J|q{vq%C( zCf@PQ$CiuNv75t6goU08E5ug_fW1m)D<9xWKab9*U&I@s1rawfrt>StnJi)}R2R^9 z9<9B-HlNY^^H}ZL2(t*KE_5UoC4ga<dwchkI`7$A5qb*e*Dv~r%I^`E8j!oOJlybK zM1syaR%v)`LN}@jl-9+8f_3lwn3bx90irSx^M@2*!h3KrrhHn7J<qVBmPSf&u$XZt zB)ChzqX5N%Rr4Z}<_p}(raa%7s)CyuyizbtZ2)~&%B=P4-TtvLOl3vH&lx;Ae;R+i ztmE_yj!m*cSx3xb{8OOth7(8DDWum-Xyv8Ty!f`MfAUz?U*<N|23&iX!rW<`EMUNq z*<#W;<XAEOOrfoqPTWUbw-P1Hrmvj?w#fpJ=HHnUAJ(O!xn_+VbuD(f9=##-Rdw9M zCW(nSm%qt4`HB_eV^x3cRDynIR_I?0M{WhD#{Ae^#w;XdE_AMc$4jz4;b%!3WHhhq z2-+A<>^B6O=N=)cbry4$Mx<KLfz`!}TdrZ2-Reg3VVIe9LaxEYWws9JffzF^^=axv z0rNpPU~8K-z;3O$K*B|y#u~v|LA%jYtd0-UV!LLrl7R73!+^SCk9$(oqlURcIn||S zZYJZg%#h|IA5dD&wvGhcxp$bST%dK#lEe0#jY|SVOW`>Cyp{R~_P#+As0c6``=BJl zEg6JG6UJZHCs8)W78v4A>FYZ=G1BPLmdt*Gmx^XgDOvNs=sL&lK%is+#<p$Sw(VqM z+qP{_Y}>YN+qR82Z$Iui`!DY8?y6D-=f$)mid9ET!bi@+Wh{*<iLnjP+%r7SL`4&( zqPz9$Qg@A}%s$SN%PF{Q?o3X0q}5W5qScn#B;iB+svotfE^lJ(dzG{!V7T+cIkKQf z2$3Pf2efwdR$wEc6>fym0c`pty65+JzggaVB?sp<{>^2xbK{(9LeF<<d{@L1_%JFo z1WI0j9<W~6Zs*3g(h?3he3G>$!p<1XPRjodZuksk6)#k`ZK&I(g+s6*%e}me;f{Jq z7(cb_N1L;SP8s%0FYqMWw2|PNq5MP1%WL@+>kFGPWF6)VU4{`*basT8rZC{PT_)?4 zkGK~LZSzIRahFCfg0muQhkRe*->gI7R-bkFnixxm$CPI)y^-{Z)&3r}2<|L3O&6V1 zhm8$!lb0_;<nl;Jw#-A&X6y!)t@!X*&^=kF-|>&Np6vX5hzrWBeLUWd3-OsL$G`3i zKN;qfiy5``O5I!Y!sE)Aq7jy+SHEgl<Gji%b-3rcjv%+T``iU<rEpy`$S*+#BqA17 zcQW4;exUW*De%$?V{M&=k%pOKke|_ulVn|6-LxOX{RYasO4lpc{j^4UA{8T20AF2- zNn=;nPsEm+Bs+WxB*p5vVP<|(;nY`<Bl*5<Qlnt_m60B(Z6@;00ySuLbP7A(<E!ik zrUm0R)Nz%UjhBiiwu^W7{-P1qtNV1W#qF*X`fSsDENrSN?3s=zDSJOHWBf(^n4r<p zF;kNH%t2Z8qdVb5zb)xn<_e{;Q~8$>NX1QCo2$_Pbna!qEZed<x{CTrW-pOr7i*C2 zCa&UdE=k*1Akh)Pz`5yztf8&T7kFeUcGP%IiQ*}kaG;QzIyaYaXq8m1nJ}3F9T{g_ zA>_mXC>flrFJdUR0B{hH%5th>fKC@xHq3F)gqi!p?&+a5y%!`-DH$Bzb7$&^X5JhC zbZJC@i_0rjoCzqc1^JlU+6%IG$_pU74Cp>aKN&SSU_n^$zBoAyoN(zP+76W&+34N+ zO?fYCp{RO@<wUSl#-fX=`$aU3F$1lvAUi+7+?{5a_EN>bxB=B3y3(sM%)K^Z`RY84 zIi+Nl(Knr3bZM&D$SpS&^V7SS(5jrhx&=MdtT;RJi(g0-2Lnoj2CRqppjy9`WtaLB zTP?uWr$ypmn`t5!>v`g6(BC7L>wnbz?)yzKJTFG@Nq`R8HBlC@tI%Wtfcj*#Asc!= zI#olhp}>Ato)o*8kRSgE?GdGO%w^5H@4k~WQwGPsJ$x*hNugZG^v5#eFQoPTgZ3Jj zDRq&o`@1{&e1wk#C&jM!{RzXpc5IoTrF^gOCg*iWj8}Z6DbHU#g(?9QGjk(`_V251 zzA&RwZ@I6bjH)4G)!GBpjdFy5jG^~_<&TG!d!E6O(34FBnOI!Mw#o-o*fChl+bL1f zVYYCTx1MPG>H8+Q!4FhQ@SJF@Q*Vko9pR>WjaQMJrrbgNS|~P#MXa@th_`7de8wf# z-Av`)L+%pqTrX|3Pvk%^+^n61q{J7~CN!1%`fcF^grFi*6S2c|%2)TI`Vy^D?LJ5I zuXv*vu5yk<xaxX)DsIl^29hzOm)CiE0ArS4VYP_(?~!a)%B^Am;xLVLy8+AOT=H3O zLx&i*N6$1Kxh~73aT1S<#{dX)NMs2)btGGk{^}mMH!t`h{DFEdf*;1K85XL0XHQE& zrW`rXyI6YohS{oBrBN@-Z;|y=gp`M;JD5Qu5%Xs^hcK4B1c|~pcmeBQ^5o8|x0WLP zhfDCaGDgTKr)<!A$a4%)Hha|WCr>KVwECF`45!wukOQc8&{VlFEVr;E$e$2alTfoB ze(jYcnZ?syj>Z#&$6`c+_ziMlDL1bt1|<7jfzYsc#SY$h3Yq7=>^$N#o8-ENDs`s5 zp2wSbX#5V4&^)Ko%8kUFj07Oib{5{}<zTA*n1EHEH<!F#3zv=Q-2(9jsz-H{@Cm@u zInoObxyBduf-{{F{L%<t9fw{gsWpL~Wh6@dcwHvYZ-*x0e}3p#89%C9Ah<d$<G)Mg z4iv9T$D%!8#!+baGDm*-9)_6}ABT+pjH;Mh0@GdIQ3qLnjxd6f&64F>iNx)_WEI86 zkQG^(iDPI&ysWp_$DxWaDV>M*0m$}HizG}1C#;fz-<79JfOhp9hZlp<fOlm9OUJnZ z+aWdbDe0260rFUfr-qa~6w(%5;FQj%KyCq%jo%QaO0{TGeGoHF$$)}Jnurt4uWc~@ zdYx3nVL(7-mgc2}3mO*91%#KS6>gE@rA!-_umTz{oG1cXoZQ)7D%Q^!iniO+o=7q& zG<IieLkOqdhaIrUtn<^E^ibF~+Q@zw;W&dj0{r9{(Y9VSSax;n?3bB3jg?sT8U`|* zcs^S-s@*4@agkMa5$tPr{Nc%X*v^DWEUu{p!4lBtE1eK)xRtt;RApBgSIDx{-EFrn zO1{Ql?}@G~`N>O`T(}PBD*4EZ?UF1n>wS#cfdSRMf@8t4>{f-&E3w2X4`pd_Qk-p; z+HGd`^mFqVX8=md0m>X2ep1Ek9y2Sd;n+d#7Mm!5oaG^UCQ?7uewHNQ8j0WqZ`0hq zBzBQ?fz|HtPCKGB^jL_hJ0B@<g=OV#{5WCK>tj6^llIzErREL{S&sStr10s)TdeuM z27;LA&CCrD<w1%0fUsnvaO>Pe^KnOGBX1meH?odT?QD!lcgl8ok3V^TMY)%JQ&P+1 zO~*EDCT=W~4;|W(rr?guyz)zn+9~zN+n`$XuFt8BM+TjpIr>81U<TM$p<GRHbA*b5 z4^4BOkJ97HB6kx9k~IvD3lsHTaj=_lXN%n#Iif-uYE1TPaZ|Yq0Fp^n-ZVb9&nI$I zFc?EKPPqv#XMNv_vwRL3`ua9LzgbLTY!{rJ;fkD5%F}EF&)9{b<jLCJlh<`JBDM*F zrd4otP3nU0gWAU4PK$kLa!6o@6&*DFYC)O}{X#$ZV{s!e<y<}#2yU26xh@zt;EkCf z%~_UErts9chyN*Ze0w7jYS26+P!#s{$5+>#6HM-@eD+cJj`pcfthW1~xncH$0;4XS z<e(H*PyC@QUA#S`K{~-7|D!Jv`Rrd0<!9Ky$}3zVw18|^dBtpF344xzJ}vsGakpVe z9`gcn*3fO=ywPFXic&MFV>1f;C>s8PFfm&4yLO65qsX);Z|BHgIr$y4-LCh8H|ylD z+at;6%-t{3<S%%s>buNcXAQ}TUi+DJ!KM`9TK{>K>Or&In~d{<2Gy@R@(s!xgS;;$ z%Qrov(M91-xP%XaM8>`qmf_fye9<a2Ss*2~c{Jah>TN@E>a#95UT`kC=r;Q&<7hKB z`q&&kl9O3`zY?!k=WfJ85gsmB_=-%WEW!2jd@J9ZdI`U15WQ4%2qKjI`kx9~M8Dp7 zz(x$W3j4!lmlqZ{_gz)3lwhr;tY$;_x`oPS!+hk{KvOD^TGbPUy<n9PeI##sX@uC~ zs?_TF=&HhGPS#mKg3shchIX&VUEPvRN+^9&?hE|Qj?s!6HmE#K8R}ro&fZ=o$Wn$! z5X~TSh)RjFxipQWaB4J_c~Q#vxbvsEi^si!?ZcvfHh}tn$|TdXTmmx4V<^uUs(f^8 zy!T_=P-8`>EoDAU)OfkXC)LRpvj<87CswTj)OhT-NOwgMs3Q^_5<$)ZK^b)@X8kaz z%uZ?>u_gN2>n6o)mPlIpu0^-nITY+C1h0}}aJtl+g+PZG3rB(eQ%BuY<~|D<k(XI& z`)>X)*(x<;-rI<M=6#xLj^3Uhm$(SI1iJm_gkTpaqjVXomXBun2O-_X7QbW>5+L_G z&_RyKDMDB(&(Ol~s9Z{X)G27R=a?A(0+|?<D?qKnW95f_$rEZUY)<qFNq>^|Lec(M zY%dXmeV|m?4T!ZUN5ONpcuZ$d-3_T>HKd`>;-Y{l4OF}Ontp?o=77QGfTt{gt9KK5 zzn|hHzv(9Aj&M2npOj!pQ*+9~n@`GvaN2gAG$h3foS~T$`b{&cF;`VJ<-`qR29>9Q zia&^?1=+0s942%`e-4AlXnEWHmu}XpDmI**F^o3(i7=z#U|q<W+vBT}pc`R(<=LF0 z4gvRqf|sS#DUzT_=fOnQFnxqfk@*<Iwvxt81o}%_BEzh0ts7mj&A4ug871D3Ii(+9 zz$_eK)ghQUncUa>hTeq3sDZeu8Hjj1x=twLTua!fJey^gdP!NUBxdOLyWK)8y)}sm zJGt^KJH_<cewnW;k)v)zxs}Tg+|yv<g7iI%-R{{0h7d)#-uQt{G?{-6wUv^aw2o=1 zPOa4D7U!xAXZF_NDxvy72BX0^V$v?{<TaE!tDRp3ZD|uGLu^|RKJO5*$OWvu9*l$E zu0Ay~@wbCWm2dh-i5Aj%WJ<$kXYI?+@7A9<dr)Rea_{+j4LrQV`{$8d*@|QXW-u}J z8?NSv$Ilw9oy?iONqP$R`ylmdF<l9mn=b{f1A$0JGV~3s1@zl^ANUJNxh&mTzSvpt zaA+pi0Xv(&unDR>{$@(+>%o1se=Nj8_p!vA9&2LzZq;tOcw{=9=h_$a7uk0+(OUO7 zIoclxwN2SR%Q8Urzsw}RT>s)Lhg8NxUOwNYZ*cPcnm9$yh}F!ZkLvZj-93BtkIxhl zmA$gcl)?{poVgGMjO^q+H8AZX4Nn@;xED&s6Ul_;i+E9vpAx(z`65<#ohx9=*yPe} zk_D8PSO;pXF@d|bUB~xGV5hP(yy1k8Q8GX`8pI`m{JCRHHrP`j_!+xgA3(&j&fJJw za;#CZm4zp<x~BvTxHirY*RlyLE{i&?1$A<6Qj_>2;jAxRS?D+g@u92td$g>VFUVu= z%_S0yorCEd;onl6S0*SBD><V8jiXHb>njqt3}{ykn&mYLyZ44%4b6JOll1*J-~1%O zmf`G7aAU;uACI`Fnbw|E2*1<aR~si`;nslb8?UzW2WC*vQCVU?sGhHtPYa$Ha|>Xg zAxB*^6mLJo+zGEI%1b0MZ34-QwDce4MSO)KPU^2rwt#|-r(Gn-wjx2O31kr}l3|L= zI+YhH?>*Y>^e`n716)sdWVpB%`V_?j5yO;pMLyKdm|DFQ+QDh99`yodw;!lXrT&}D zGkku_JnfWET|I}BNM}v$rUn-2g7nyVPe=Ig0@mD|x1j(~n-w~VJ9NFL!b7df_Fmzl zA^nf6jBVp&9BKo5#VBBxla%90sVzffn(rK&qBVr75#jE>X|5PzJO6wBPr~@KFMpl( zG@M;4U@jY29cb2LEFT{KCh%8|dc9s}Qy9%fX>KY1H%}T7-;vFSdUafO&M$t|9MPN- zF@l{(k>6P-rk@*ruyAL~9iVa(hwm-PU}jiZ@7QG~Q_8t%F02o0yi+u-;pqXHN3__< zXj<DuSx&trw}1u-JzJ&;`|^&j;oqFaqvGYoq-sy)C1jFMBmW(;v4Ry&a6yqioGv=e ztOy%6^3zZagTllLIePW`c-95w&cysewfj-Yp_jYsw~J}^QC`3)1{l|iS!}_KFw;h6 zEz7Fe8<ZyD^@x4mX?O4&D^WN5H|ZM!mtE4Hi`<_g0z#iu*+V%0hav$+4fC^kY}*#r zxd%)#GG%-q-^H+(zXhdOd;>|X{@&8{76v?##&iL*9t^^Z(&sD+`0oD=#@v))^8hGs z%JsRw9K{DKz^hZAcNw?J9<>i)cbTtiG!smhcrHDboZsQ1@FKx7C$WXrGYGam)H4W8 zb=-%R9D6p}V2{H3{6Vu9v?<G5sZIcm{!SP+Oogd9He6_On>379FEHgSE>N#r61ck6 z&E$dRv8P#}s4}Ka(ET_=#lacocetFrfCJgclEUYo{Z|?6KU%6K-jUO(vu=Kfv~l@I zuYFSD#|ana$?*v4xvbG;>6Eq!@K{XwK2#@9WF*C8_{=gwr!b3$`V{o^a#YDg@)kE| z?lBw)p=C~1MzLz1Z?8r3vxCNH{F(e|2YI;WZu0lKyb~2Z)Hq47=sa}B5ljO>(`S7R zhm){u$ayXChAtUu9l}yuS@vvLv$bb=lNAv(yFI#ZE9lHc3D^GI(;{=c%pv&`4*XWF zh5+xLEEp$^2Y9Vb3ZxV@U;nC6)UzVZ+@<poc7w{co6SS%IbOFJo2B}OEGqXsm<ml8 z^Gr%Im$J5<nzEG0m(&^qdSXLsYBlvFXNG>_Bz$fuFBu1`IylgS9p4<~`9as~A?ep! z+&j8LC<A8PU_Qq_R?1Q}ZFSa7D*$F$5kPkSRI+~Wd0&&}7f?<-%S%Kl>*k&Zeq*8T z1byjVz({tyQ~K+WA_KB;ZZ{)#6StdlUa!5%Pa>b2(EHILH6=HXSHRik26xiv6n`68 zxfGBIz~S<}@nsnO^HV3?=U<cZGyouEcUsMHT^z)pYyw&J!ii0o-`PqH&`;p@arAQD zc$)it(%S3AD0g-17n@p~4>Z_Blj_v+oCx7k3KtY~G`hIlsGe$0@jZTG&MOltp*AR! za#s!wxKGpBc}FeU#$9mBP>kXq?~|Z0Y)<QGSBE^oX%Bn%W1TAfK#=KK?Ln7FE#1V_ zxc@4zPbtq>s0n~|X`o=>aigYW&i0qcND;`w;B=%<tX|j|07evoa`z9ZwWPSTjkoVt z6k{8)9q^`%9nyJd3?vIlL|QmX>xFkx0q1RS)pzYq5loF%$QpO1e;hOd<q^L<MHSs9 z3JP^0b1u<*I9tB^Vh)zn4#oo}0D>5ebC>dL)^f53Ch>h7UH6xCfJ4pjkrRvsv8`fh zfpK%G$X`V~gGhRYsr(g>^@yUuR{R}Yzwe7#@Tv>!OS>N5d%WKDEkIR|ADO3*+1%&W zD_^5V(26fDF<IX|_V0t?Pjq8AC}R@v#QRTi(a7IF?eB>d;%C<viT27q2=~9@jt~T5 zBpi|kp_Fy}8C@GkO~f~K<mK5*>-)xzW!&yF!>E+}+l|Z%WNSF1iaSA>e7w*XNwO3} z-KXCz84~E=vC7CH5P&@1u51fo2x=Tm{LF3sf4Ebg#uXo?w&KAX#yiz@mwg&++5Vv8 zLk}4zXW7;#T5uWSY1U!Yi^n&@mn7eQCs;W1BnOJDY@To4=8U%L^)vQjZJ<Xa2!t?v z(wNJwrL0_X8c4l&6Xt>%lIb|_z3v_|eJ&J3b#K1yz$KDen87UybY>Tb4+4J0A#rBf z;1eIsOKh!}`w-TD&PyLwjVpLsCCbJoaZ^G<_F9O(r>|OUDBQdMHezMd(0b>0pJ)-( zJ(7k$jsF9jPs8k#P_1t$uAu+ErA9+{$PZMYPS_caQ`Pm-cC>>29chH|2%<rDiiUDP zS@zd!O`39`Dk>B9tAd^tHz(=pG3Pg)^dcy5Mg}Y^4^}9%tQN9tj#$(mFEz9NLPpLL zkB(W4?E$b}9m0j<y_!;z-DqSCVfTWZj(&vkWQl3|C6VX2Gj<ey2jrCXO^TqwL~BJ{ zhT6y~cV1F;AXjd|uF;6jOUv&q6)Xxz6z>wFhz;)7)O6*I>%q;R@|<OTUD?zED)~c^ z%mtDYy=iguvQZ)y!zF~t^_Lqd6{18vvGh;NZfn`j`HgZoIwg!moWE}n3**E&oA|5Y zlS`@PV%Ce#J`fDioZ7o*RB~+8G;K?kKotTNA>fBk=1Gev(k56dQ%6$`boJJSL!8^X zuyUr-t%%N)FKsZ_tZYb_@e8X$llwJnf(TCG)j#bf3Z23eVZ=cR#!3jnBI_7!*!^nN ztGy&+;Nk_97!eogrO|-6iQ(y$OE`%lWNKed-rVa<%CU9j^%qn75Kg#vc~Mt~GSH5; zQjvkNIXo`RfOtv1>kcAkWcjtHl_MzBORQd5m<<?3%mW$1TqR$ttme%PLY-!Vx#uk6 zsL$ove0@e+Ek+%HCvS!PgVkx{<@{WkXF@K;mWzk-6@;%>IceF$ouL)-%Eo;@oS~B& zqSKc{e>-={6%|96F}{&AF=^WUsK`Y{L+~52G=8U5qGeF80GBx3WhHFhs}J^eC(Exz z%$<nez}Sdmtf+Nmh*$Qq#yutu)f16eET3yxti#<r55ia%E!sHz+dX{EL(stv055Bc z(O)XU5x(YY_#8L47U^8K;4SQ$>I&}emn3h#+7>Id5tve8NkWYp;ntL&`q(i%N5!Vc zOwl`lQAZI)00|mkf!AU<!yoP#R@vx=;C_qqA$M(+wo{T_2NHjr5|ZF;pDY<oFGnfo zh-l5KanpM%^i7>4ty+B9Sy`ak2Ue##f~qr|lPXh)G~kQ#l5iP-OOw=)S@bfNfPzjA z(YMG$+M%r+dact_VT#yaLjwdy0H_wsQ4QwByY~dlUMtDNOP3=^0-XvmW#t>GN1JWP z7>8?b3;Ex*;8E=2*SpN?twTEK<7pV~^JHIMQXj-fRIXiAkvi@Mv$ue}{@k)vI4n** zphhetsh07n)T6wXExKe|zt;LmOee#-ijsd+<=P0p{vs2?i8)&{`jS-_<1J3(pl%0t zNIDsLWzPlC)TB8+D?o_=XG6-PGJ6gc6L9nwFD=^!`V-uXTbjWH!%C3>NLX%CB7hAX z`%oh~d%vZPxXKCuzaV;X8>I5j&3(|d$IL&D_xJAQJCj{6*O+|w-z?#+@pY8G*Yo?L zmk%dtR?nB2<S&u^M6g-`KTHB-=uJQOA(WID*v27@vi>WF>B{ghnzA8!E4IwIKgi!3 zhR}9TgfAN9$}HtvL<YDutCAfE^_@CG;8#!GB0P$%ot84jLR~Glbimqb2hiu!KzefV zRbSsH?+@n>Oho3d@AW6jV=zNx2_j<I<`oDs{eiNA#Rg5@!nWB~vR+}&9-Udr-hGT| z<dNYQp8nbKm>rXo(Z<u&gJ`Quim*MG%B2CAbbUwD@T=w4+c9vmEes5h&4?&zXs0$j z@^o2fZt`0a!i=)XDrl&?e~&m#?IbezA3(*YMG{;ILj{$mb(0t|*X4Semp5+ZRd={g zfXN;jJ4IJ1x|C&@kh5S-$X_vkUx~Bs;MuYl(&vR;sSUg*Yoq$+z{5W3_AX`0rFo@; zdRWRoB&7DqdZE8~vcn-_HSQ<!yJAyG7m!YGiUCp%^?Akt%u5L4R18mEvx>AwXIZM) zoS2zX{n8n!UFt>?E$_wA3u*S60CIZ@<~5XgNVc)bgCw*JpdX)Ci0!b`)&lPX!#ni1 zYdJz1bB`jC0B)|4g!+4RFhuLB|L(djMe=4UNw1}{wNstsTK>u>)v9|Jf(|OCi;k03 zKXAk4o>~HVTR~!xIqiAFLsr}(h$-Ocj}CA~>r6oR@j0Xb0jVrGPRvi-zsSs|ikm~c z4s<D)Q>MVyg-zJ8;8krK3nVxShS(uVaxKa*%Cj998T2oMW)Eq*ipMhsA{k{&HE@g; zf>d<$4gDR)4f)PJJw|GU3h?|K^lCGTD;a0R<3%6`_(wGD!V4F8kYmdz*3|)9(!+X( zqoR!ujHg70SyzaTaj}PRc$OKFl@;+Gdi)w`v7B6FQoLZhQ_)xDS~D4#4{g&(Jht>@ z?RU3Yt(_@5%m@XNU(HKqIt8*LxQ)y#6;NG!G=t{ZvyXTOag4Jg0R|x@3zEo(rkw{9 zze?OXYV4iEk5d;55MRrxvfE}txCRlicKrOnf7AW7qHKrWoEJ18X`v(HEc)ZPj@RVe zLO`E7Gi%9iSVtps%&b2NlJO2@T1Q9G+9gRGDW8=t?36C8rt+a~y6#7TWDJF|sf`*{ zUw+!ZKPp`XWLsk$;lia&<u(Dhp^yl)#C6b}&{rO(N%0d}3Kch1tk4`;*_poCB89dL zd-@bF;5t**QKIr<3=!aWex7Wlx6%a*?IOX`c$eq><?W{dlnKS0{zprQ00FCo`ta85 zMuR@UIYgBrrpgy!i!Esp)|RyfIp_~whjP>O98%I}T_vaKQ5vdtY!V)W=bJ&?gX1>* z9M2CJv&^^EF>=(#$K*w*()03@0%FKN8!L@&PoBRa;Q_|Z_9oUyg$*%DRF2_=l_cPC z`d}v4u@vc*p+%0D)=iv3Ku4#`1G0Z(U73U}*%&=BFM*lQ+Q7pG+1;+=K3o<vmlNYg z)I*o)ta9J`h)khGje=WjG(r<`O|X-=v=5H%Uy=)pwK{lu==hY&z;t+at&<Iu)M1(3 zfurbl!BM9v+d*5=FM)$Oh&)sRcVLcUcz!LojHA;d51j$$RP_jv_?2z=@7RaKD7zT5 zcV$*R5FgmM_BhN;88qT7YJ>x*q@p>tYEmPSprn(=2*Uz@$D+Qg=YoUB!p6Nr!CI;j z*(b1}Z38<Tl#++g93DXM?92;=ANQ=UkTw16=>_`9AVSPK>NE;&$;b0$l(x!!Dm#Sx zW9|S@S^=pdvp?D+-`oE-5pTSFl}9Bc*XE<3Qut9MFjGr%Um`CqW=?C_q`Wg<7#TcL zebv^NFAerVQfS1<oM(KF7A0ucsLqweXX5Hz!e;P}%3g$=mgY#Y!UM&N%la^rOgY9W zic=&ZAPQonzRg!lZT?8D&0~2Gv4>BH=cOmCo^U`ECxS%p(}KuSvTmciy-#M7J<-%l z;ad@xN?L!?RHqioN|++*5im&8dbig`Q))T4$eb2E<g1Vz44!syd;Jh=)McjjP~stq z1V<fm<5?Pr>{Ni94Q<Hml%t)-%SgN!io%<7W^8hml4H{UHSTtFwJWqN7A!sF(X}>h z-&&{zuuRf@lu8TmSb&#ED<pTunTx67uP4`E8UHQQ7VVA17o%_%n{%o4Riwkll8W+6 zqP&zzGbg*|J0r{PoHM#eINXIPco_~Ne=$y+sLU%*OH7Xfg79Sw!fu-<Etce|P!op8 z8`3@da`tU8M<mG1a*cLev#6tog?Q#jUzq98_KR+?b>abRkrGiPtwR;r`unl<U+uLk zz#nwqUTC48bC`t)zHOsoq)FCL`hE$ovkzs#Ofi%-SKN$1;qYNtFp?hp@r<13|9*Iy zNP|A34GB4(^9T)hiA6Wc7XyWHzYAnB=U5&I|6zqqdBgD%4EfAbh|Za1CHih?8-cD9 zHM5jCEdi48Pt}M=cO7ul(du(qCyLq+pr%wtDRIh!?PoDomPIY|BqLoDCHaAPAc&my zXdVjm);UNT-#%YpD$!O%HBY5sSSYxSJC>)sC+U5FW9zJDV1ED_JZ!I^y)5@nRA%ZG zyO?7HAC<UxASMzHDQ>rXkwM(dx6O0|K*v4<_F9g9da8;aMtvY5%hR4!-0xwKDqRom zVPgq>gmXkboHXQYm%=HOXkD<bcovd~8m&RC)DUDWRcB0Cqm!pTc(eonZ?sT%qj}k# z%(^G|Ad08Q^t$c4H`mg9b=h<$n{)1-zY!sPGIzfAbh;>UDKmYuct}QOuCI^ICKSFz zsG02$@aT#B%I-H%tZ`Ln19ur6NLv*@GCd`J0RNy09HW7z^t;E~x)z3|<is0|q0lw& ze+g*2N6$#7iBo+YLvZ9x&N`~%=}J>$)OQh}ll0BVB_>GftYbq(|HvssoYcx_J{VUA z#eO9Mw<F7UJCV_#6tj?_WTnswaqoXCK>lS`T>>M2(6nmI;;_SWM9aA|Nk`3>TbXDC zFq{DD+Tr9ns`s>bHef4bO87?bFM)&U8L6m>!Qq~AsZ!x0kxXO~18V|sFaSVYMcs1q za`K~{J}EtZewtl0b_x@nLzbiT%nhVbK;AE`-kX1<#Z=}D2Fp~w==6}5@$|`=<+Xis zcnI-%D>jqVkTB?_8xz)_>Ht-$&QptYsI{)@I&>n7=Fn<si=fbVSZOfYaqxusV=Qzf z!e}?_5=T3oWrAg3gZ(#RC3i}69xsnp6~;h~kWIFS1r-q;G(16C$YIoqMHFPs!z4u> z)W;i*&4JQ{9ss$OnPnWeZ~cU7_)2h{WwU_u-*jo6?>iE+Q6HJ?uHWz94e5F#Ib#}t zBbdzR!_D6Mv0w7_?^mV`$dtiI>s7ehlk?$bJU4y;e9XDQ9Ur-GlCS(eYMlW04Et6+ zdviQywCvQ@1|PhSP<jsv{%5#4*hOliJ`cljLQyP)P+mP$oB(9V9|A}W`QhtTgIE0$ zkQFt~Yn?pqJp1BK$iN9$ire$iTHsd1;@(y_-U)MRthsOW7n~Y4%}bl|MMJw^z5`M& ze^{<T{jG5|7^9v%@{(HK6vB{Q@n?tr5B0&eKLck*-^kQFkv9O@FWv!weHzz9w5Zqk znb%5@9VamcR~7^+!HJ?($*<A5P>9rf9_yQac_Qsol9RcsW%D@T(x@5DK;|l_S=N+M zwB0>zy9JG-K5cq@4X8#hFU>o8k=%Cs4*fa?m8^F44B&|a*m}N3t}2CqO?dZ6$aTh; ze0mzD$Xf<fnCiMCp41Z?WXTV@&yaI5w|)WY&7)9gUJ3lVvW1D#_Rm@uKUO#V%J!Z+ zdI^z<i9^bAz{a5xoOVS!Zx%neYXJZ_mh08klV{C7>r<L(3jC3nSz2nkbe$1yFQCEQ zCLZlAcWb{Pc7>{q8=2=pj6scf8WY(01-=@(`Kg1js5doZSZf3yiA<!&1EOuCgggs5 z*6*fCtH19aob(omB|D6ccbA>mJqdM&J1dU3{s%GWdXA;x=u}}9fJ>qd5a{+fWB17n zYCUkP9MmfWY@iN<Iz+X-F-V~jC=o#erwKP?1vvjo5A;TaoV_RDJREP2QTVuDjPSET zw=o_qlVXWm#W?vkUk!1ge)=F^TOgA#x~x-<52tK3x^RiaPQM%oMk!DLb<N6MfC3A{ z!EVCzjdGrj;Ay_n_iKko-`k<eSI*t-+QENo*Z<aXayM(}JEeDAtjJA$16d7Ljg2Ol zApG$eWHnoN*w7{`Z;m=0{~<s6<X|F-Xw{|nYYi$|bSvyO;Ps%|`M}OKt$v6?N)pSm z<EVQ|?-jL^GxpN$K3~tuOKvTHo6(O;-2WjLUe9vL{5H}8v^{wSefM9Vey9IRb2PS} zS9kyoL34f_f9zsI`e-F^Ey%_RI=?T(vLTh@9L#CnOo#AKemh+EZWahXr}XE!+$%`_ zl_j;QiQ}-11tWa-Y7kHIMD>NQLppjTD;J1IWKTXp8awW%v4f9v-MMFAA$FlMG3aSI zb7LR8p<FY^pQ09}i<k8c+W{dkqY5il+U?hYj`b%~ht*AQ-=})YX1POE;fK3P$|r~H z6}krC%EuZ8Xo-)e?PGEb;5O!PZxOEFO|h2iy>|>v+qiEz-^c~~kZm+#GR<YE@6sis z={U@aE+DlD%sQtw<PAtuy;J%Mf8EmMKQN}o78xd8*gIRFb(H_7mHJR4^;whuArBH$ z0{!EpMprL{=sVnD@KEfHvs8KNtQXwA<v-4*x_F>Qr5T#Te=kO?)ta1L33fGYS7Gl` zCb<$&T@L68bjW3&5DDW6e2ABo<nA-3$o0?qmijK;vqLWMzEB)h%#gYt()}xeEqVz) z6t|r)5^1<_&HSzoo9#baBW3juEWp3P(i>=%AlN=OLQSSEqn^+fN|vc8Rfe+_Oe`DZ zo*+9r-%);fCtXFdj6o?>%f0her#Dd@A=e`U9*L|X(`8*ZzE)@BCJWPGU=q&^^2kVJ zplSo)1X|$FysCQ$3>gf)+0%G=>FmYp{jqv^j)Je%^L6>68>H$p_1F0fdnFf^?u$GG zJzMRWW?^IFaPLkySQFQ|4<R){IcY(uh_&S#N$3O0L@hXviaFx;LEdvXxXsys{qS|u z3pw9LJ`&5>3E^8$&x9PrGk-+cq0n{CWnE@3c4{{~$cAQTjmbj-PVQi3D))+&i@ULl z*W9HXfJ<<2cBQvZha?31{Q;P|I|nZWJ9md36bG8rM3=3%6{VcT#i0})33_-!;ARsx zd1+`nMlS-_BjIeeOncBjJi0g1?k=Rto($$TR#MD7&J?-!_3`)@p@#&*!F)UsU@RdU zPX{gOD;p4+B5;Vjqqr0i?96dR00z(ON>4SRiZL|kE0KBIM^-_~fg^7nY|IWw*$<xQ zA#!U62b6JS^KR<?xTljvrIm{eVXS)7aJ(!OiL<mE3)K$37I7fKfJYIjlsSivowe6G zg^TLR(Op`0P2xLlpb*~D2n|aF^PbD^+1dutt#n@`J9J};u5Fn&4Tod>xUxrv`RLa- z_mLqZ6rEk4%bOZx-nc+N?&a(9kUv%l4Z2<Kx<~y5UzcwaB!7e3Hy69d*WL={Yq7rN zHw?)gI>x}t;p5FJ(|o+h%)U(6-h+03Lu~EOjPi^v*`{S8AEp9lYD%_B^5sioaOlh3 zxR*_S-QioOV{6n@AK7iZiI29jh8p|;9Dh%7rbr~Q?Knl&QIF+c^e54xlO>^<t}5R( z$?eEOTAe0j+vq<SAV%5M`<&Xj_sp@wS{Nz#19`!luuEKAuFBl_ZlL^^0CXb*Rb}2` zJI^eNa2tIS3Hq89(62OdKg5O4%IEqu=@6ZKSGEXc_~`BV(`{FlgBXLMp0bCm(DRF; zxKpY(q3Ecfs1b%3P|96{3C4s;2dCQ@Qc#j6fkLoABZs}%B4k2%<<YnaUDr1}nx%&0 z29e5az7mzA&L0I>8r&>oURkBs7Aib@Wzcyb^Me=auiw}1F7YP&$6>D`Rb%}P%Y^{7 z?PLqK7M>hSb7pGWw)E6XOo8BD!b8}Dlo<rI(a=M@2ROZ8G49*6u(63R&^P#~l!L?2 zxgQC6@m^huD&i>v<}fUo*lncE8?atAWgvo|Bsjjm=iwR$1%%+Jhtq51?lXNn@cvx9 zU3=UnC{*asl6bkckdNP8o$Q8;C+<^fA*CcS911^}IjOeNRQEcl2MHK(H=ye^ZsHJg zMn-W_mkW$BI{Yeb0w-s+<C~u&0MCbyID_fwwuyrdO<aygbgaxouL7RN-wJSdFGHb? zC0XKYjb9&b%mO;$#aI?cr>onn&@^b1C||217Rzf_ql(c}!K(x>(DV^3&PY6yyv7$h z(M+!+m8rs6bqrKfE(|KKqJcE_<XN<mQAv3JQADmuq`2J5%I-}R%${K3bgl))GzS6b z2$=mSf$9AiR_cdK?)Cv6(00E$5Q=Zo1a=w1L6GX+IRr^QrSSUk*>#qcq;`42(5vu@ zDJigQvP4ON9X%|HBIl-_`l|j41(eU-fDvEpA`@YV`z9$IcfCv%avyDP=Vb>KpUDw} z)TSE;m{D^=-tf?I`SIz@Mv=WwwLC(goVLZ=UVaX2sT#X~fIzOmSV>@k-*l>03wTjb zYtLc<b2RfQsUwiAz5TALY2ZX^dSr>wf;q|aFNkNDeBU5GcD_PFs@M+Fg4`wLLu1ey zS===JN=!D&nbfhf(GItGDyHhSRR5f`0T-zP1vrffh@?x~$L`~$w|U?iGwv|n>hzOc zl+AXg<{{p+b~1VUYlr0%he0pv0BQL~Lv}=SqazzYtA)3fGAu4MyoF^Qwv89wJ#lVa zc$b7y#Ik06Sra(ps~D0TWf%IQB@u9y|78+bx&(wyDrT}%I+c&1j2|RH3GTL3G+u^s z@QYl<&6qeAvr-%?_m!DuXTx&P_^=<k&s(aV8$D&1wE_y%t!PVC1+`~?=U;AAGN?SG z&+*lFSKeM4OT1-v^I9i$%N`z~rxv~F!0(q959@4m6zaBQLIpdD4?E~V-&I=CBBTlo z+z$nq6&Uxm!IVk0EUY!NU#SY_w*}nUv<cB;$P}2?r4d{dW=3b8fk@o^ZKg0)Kz>&e zwkc(-tx8mXTvFon&7wuZk~Ger&CmSit@NUmUigUDiuSW2$-?npkUYN>N6eTucIdTT ztz{q!)gha9Ei`BS7=L4b$I(TZ?-61xm-G7lt-vhLo#kN8IOMh*ms2o95(Fw)liM*m znBVXvI=_B?r}x%GKf5!%w7ol-L8gda9>Y_IeT^OgdJ^GB5bo$EvyLf!)qipU&Z4lV z#iJA_qQ!n%bXyf)w<1JH-uh8+Xq>)e*exCPD|v-OhH`6@3J0nuS>KTS1s4ODVRqq6 zTA)&SO_C{Of63wG<#iSa(L$2yC}@H{>1d@&0VNV~idj#vZE=Sc(XS*$J*uR9U}bcl zMrXZ`-F$FJN&2yVXHuNZ3<>=`expYVj)1BR#z|`&v%S@V^i%96J;f+Qpp2f6$xHUz zSiK$&MNXf&f8*D<An^@Swg8-R<^A{gMTM{&N{M66LZYh<PSe-xa18}emr@L*u=z(Z zho!(cgOrI)3b3EAI62T)Q`vM+*r=&t@OU9QyE$NB0Ga$4n;)CCSnU(9P=jv{DXrxP z&G&C3n$(xBe0?@!U`TVEeTukhZn{?d(pfkis@46x&oy_N7jnEP+4pK*>PGCMLB{9q zVMdeH84;)64@%`t$K6UYlz>Z>w6GR=jCB`k*<BcH(gl(|-Me*_qwkSlU0!hZ$OgCJ z_!))AV;|w?*d-6ct-jPKzx&PvPxw*8*Gfb*HRvx~Or+jOZC!*q4rcDZo?2)q;y5#* z$<P@^v@l+@tLk+~+eSoF1<f(0z2DYqu90q6*q?L+SYrUkoDYLE_f%jF&3uozv1tMJ z`R4`0>Ru1%<hg0hvJ_wo^q;)?)^wa1;F3D8xEbNQbSX}gGMwy9ATr}Ex=KAX1WE>O zFs($y9j!3n$!4QdiP>t*u>DymA=J7GB%kv9UNfM8lv3p8y-cdJ&mMBqAl@WsEPHfD zEwXDyY&z<UqGdyZh?)%<Z;7e`uKH*>t^{wMwS_>t^Zi{WEn~4^S;0v??^jlb^0qt3 zQCylY&nDEi17@aGdmvZfI0EDq)KX9`BprgG76qzHD<~|`BDq^f)KA(nQ`XllxyXZ$ z;p!wbvjM=j<JA${7`=rblWM4#GWD)EN3FTC;Ppq)@L+de>41BII^$4gJc=q7gZt{j zOmM}W2+`!m^b?BltfV-TYfk|5*X<cIi<`@i=FIB$?WtzCPQADnibBsjMqbD)tenJQ zn=jrEw}T0n6PJ~LY;;f#u+^1dN29j@vDwxLsD=IT+l`YN><1;ZZ8se`ufdH4(-=>+ z4LCMy9!@3*#5xnT`@YVTF2<P|*VktABHYsMS_QIHRiQhxHmjZ!srpMC^D#iB#wE^` zw#xZOF2s`2^sN$Kar>0*=Oly}>(4e`y!GY+KSbKs+b>946ii1V&!(_6eVk|o@A%l~ z*Po^(6e_hhlM49%Efy+yeZ5_nmG~;Th+{Hbs`^o`@k;*A%u}Uk9Na#g?m8;m{26v6 z)~q30-nHU~e(TXR%i_MEU{v$^GH^?pgz{KA7SqlfBVEyoc_*AEzd86y>>r+D^h8_C z?z8#U+ZwF7kL2TZEPZ-XK%wU@74*7bCcS9p;KG&r5!A$ghDxgQ;~i2d<(T7GNgp6* z86aqX32@)O<2hf7z2Ri-#lDF$bbWdG5m9t)RnPFC>J?&FcbW#wNYJTUmd`{x2dHoy zCO#M(kLtw{?_y!`lFb{#4a)A%I8te9GmB_|GF8pCxin$Q_RJDi_0l0n=JA{!3F8C* zLV$KHv25(DQRVp*NAw|a<7RTh|Mq!*ptjfCA8Y05E#b=i;gh{Kewkt%=_$gQ@5n#h zk)=V@d#rm~hVy43B%Zuh!7C+Cu@_;PObPOkjE^Tpluc71(QV^1hEOru&jtD7RU~~_ zI4w2GZ>l~7K}H9r-^BH?w70nZ@4D7~B0u#sHUPkd(f^FqnwXjWGy4B0&M?jMow~{9 z*n6uNFt#mjS!i-~*~w;CyJ<D!>bNOw-Mc24QRAZ-8BF3znJBK%xkCEB%Z(54@6)K( zGvu@Fb}9kHkVX$<3I;4ghD_RNv$*V1o>;YGy+9>@WXVcjVdCTX(Dc`WT$JiT$i=39 z%~e!KR7yY9=?Vz8da9#i8xn)Eq2t1MxqRH%(Xqk$5*9XC5x_?yxgprDV2#CPGlG8q zbM=i^)zG#lILLT&rJ6}NCw;e8Kchuz@^lR+w%>0WLf}lUWxGqV(`9bfneuWu;s;}f z`)eD)K+|%w^zTX1#yWn~hIfbjW<{A=OEEQ@tAJW6DFdQ<CCe&K{@ANTg`gVh?dy|7 z9_9Ly+X7OHWF{cT;!Cn9ufK_kz;SHR*`$Nc?c#&$&O~RG)#Nv^@gH{A@Tn+UI7dyi zN*`jGRZuxr@a@Cc>1(JHrRSDu&x%82KtI_HD##eW%|KsU1yVDiVrkCWg_x{!(>WMW zncR5@OV-|S9l}X(U9`W!0kf4g+uapW6`2u0?!2jQgI)c4dF_>_WoQr{mM(dv23n{Z z*^`{qxD=hQgZ@XV8uT!<Z|{UL<_lMBIsul~$j?@vlg#UVhO&zDzWOdaoa4tz&NiCm zNN8Mi$icXWLyOP{&~zqWx7dr2Re*`q_L7L91vIwB;WLRhKIjnzK%oM;YBen;8&L0f zWU6D!!TVLvpwO1>AZpM;9vU_abXw$SunxU+4b2jh4LyGjdMF-gY@9;u%gOuCVdD}B zW>EMlM6?4qDOG80sc|ysE^NTlvVG7j(pd14NvmB8Hf+%vP@flq{z&|F4+hRYP!gGk z^zj-30Z=Mdkk#;qEE5U7i?W4n(lfIXAOoh0tdjYgc%d^O9B*BR%Ru@sp=*3;<5CI0 z)xbz-?@*0&L_?EkI-xv3ezq_nQbA)w@{%WJ-6=gulzW&Je)y~>zuYO26^X$$^>k+f zTQ=oRmmCYy0U4H7y6QN>FMyFk<kE$b-qwYZw^EYHfi5p+y()e{NxWMfz;6*{sd#W8 zA?@HQ#!sMFA+1Pbx8gY3B|bx3s1^aLO2g{NfImicaX(+ptLck;cpn3f_UV?fy{);R z&QMo}LZ#juv`?`mZ?JJh^RQuDe)Kb5fPwyLwx}Nu&G2(LT>kN-B8Z<XPG6c{H^A)I zW`(w_b^ziRi2JHmMaq;+*`~K@+N{AfgoTB!q;{7-A)VeC_}%~z6#-R)m5xdPUzr%G zM&1XKnI=TP{vrer!QZkQzV3w3W3Q4Yj<tf6rxNaW$^9|403}(yI^3y{w-vn*3n$g2 zR{(^0gU}FnJLCC=(hn}=a{6<a-yZaimvhr6vRa7D`+Pl=C$6Ykx0t66MQ}V05xm+e z3cMW&XYw^}c56O@C?E|znSkDDMT2kaBR=NK6lm=q`@<5t6gK^Q6Lf;L-?!?r?N1I` zg7KG&+A0KX54Yyqq#N{=45t9~l>>$U{h5O6>+N;YC#tygw6bGR7A_*eU%tC2?#u&N zqpg3>wIw(tYIiYbk9RL;xj-oVY^YHYq%xracf_HxWrvL!P?wh-<I{&1O1{#&7e2p3 z7F=hPwzQ;H7F|S1v79K(MqSyx+rQYJnwwP)vc8U;eCz_6xOg5gd_61WZ=)0ZyoVGo zRXb6txwj>4-{ojn>ZtunFWhTrJYMM6(ZM!HARJHJEsOP-`xkTPZ1X*^C&maaMnk|= zc%iFT@Z9AGBKI-kgpxk^Y~kB1)^-xg75yi0*?lnTn`w9I=?84t&Sw{J3{W&Tr$bNc z{N}IeeA6CA5I!u&K@U_YVJIDQJ<a0Zj$pms_nS-hKYDuI?mx`l9xo5m=z4yzJUj*w z+Jbjcf-2SMPN_8~QM7FpeI@91;+yzR&gRc{PltXiHroO+9Y(Fn4?AFZTJ6r-j4@d; z8fCl=gLlTH+_o8(^NIAiHEK-k0WuJ(zclf*Mtf6r<;18-umGL)z`4T4d#RJ!)|U2) zeeachfHNc>>Ao5ICw&0z4ZqpNQi&3<WE*Y8q!{Ji;x!2FWKh|DMWP<IM1($J{7Ky_ z3`h!^AstAs*UEb6+O}9&&wizaH1J#j;|}^>TWX&kIHJHu)fsPZ>lSoDwuJx+#V@g= zLqb5>ItO9yj=mp<=O-+=Fk?%?9FYVmx=@Ab^<>JI9rONee?HR33Csuj)68t<on_ug zxcTf@3~X&t)l)J62*|$wJuf*-0X>~Cr$tEib0zUVEqnw~u?9jFY#UY~26sh<2!@=s zT+#J^u{w8^gaBJ*IkRQV;K=$?oQ(O15{ZfQj@t7;;T&d45bI^sBHp$SM|=IgK6ici zL<=oR26L_ua3s?yv<UiE&l>36Fj!MX!RASy^4+n>JOMOSwYG8y%gp-j;nZ~1Y@N;x zJ*p#o%|<T2%@l?664Yu?JR?1n_qreC4Dro>$K~wIdJ*7K%idFc+s)0I-#S^6f}_Hm zah_p8Z!(l>6S5wCVv2x1u|9`6t@WCotE*1nqUn{_ww$;8hH~W)6m|kxAT=2OxS^U3 zL1nQE5eC9en}B0cG0IFnQ;-_mDsF-~v6amvs|69jKLt6$xIpe_Buz=aSd;B16NX{K zu(?~Wp&~nxt*t{_h6>KAg(AeAB!tu~a9f$JcQLqUN?)2Wlw*7a0m!ygiF73pu(df$ z4n{@dVs2)?8t0J&&|*K~x1j!<tKCrG$Vp;cgE=d^h>~5bz(zToZ!d#FROq1SWCo5~ zkh%zB?*IIwbKhHOM~*;N*Xy*aaEl!qy2qu1NgmBaS3JCK8d|tSlJ?2f;e#K2x<Q{- z`*>#n{4L_!nO}Ti`FlR@r*r>Z%s-;n{(gPDKbob+frrm6obZx)l7HBUbGpCzti!ll z0Fk?3W7kjjeF3qWUKPLZaZw@+;4}fn>AMV|k>8N2<4C5!XGyHJs2{Dj*d*-Jc<#*d zpwYM<j369&3NK=-8?pvY_u2KU7*V&tBAvkWV0MUMuNTiz%d+HQBS&)%YC>KzY$}y3 zDhAG(&bxhikFmuZ+*GxyJ;S!ybgo}<1fRZr>vTdVT1@}~TjBhHaCfTbAFh&T!iFQ+ z4ckFZ0O~{shy>5PIa1Nl&8dJKR{qYy;I_wR^DOl4b3bAV=8}0B4F){s$8DJf<H?bG zl_A?TLuzTcRct)7r@SLx6dLbmR5Y9|)=lJF>_a5eR!ydV$Rd(s33#-|J-~HmxuqW} z=MoRihU?>z&=T0_3u)T4$~Q-Uk_0)Gj2Qv10(OMM_09*^a+N{wFUa*xH&j3r--}tI z3Q&cnh2!I?Q>v>%qzGY307Q`ugBHP7IPDrf9Y%5TU4g~n+C>|er}GM?8;O{AO1J*{ z6)?y05-|1ME$7y9mOCZDb0mH=wo2cg0d6JE=^$jhdiA`2CPWU^GzUX(NR;OB_wSB- zEc$4Z;RIMCB{efFnVr3v*BhyAm_#yLy~p&O1Hb}xSehCBu#8|s`x=MSFOm(4m5YMp z%ubxOMLbvO`k4H4`iH*9n{)7Mu|&O^+c|dY`V&z+x=Eg1tDJ!qKn8e`JIMVBO<QvZ z<ql?G++CRmxPyHS$0cJhUa)ja7>wop465&tF^w;G(W8vm?hM`vG6}IQhl0)K0mRj6 z3e!U~zORLDlLJCN-^u)2XC_pK-yImke8;z;O9k|1`PF8=Uu=8ENh7dOL|Wd<^3`f0 z^$DBbd<<rpIVtss>yvH^9zt?UzZM&1C<fCbXeF?pnEki}&~GIc#ALxJd~}(!d6pv| zQWJEifu)oeDu(iGVH&njc1+IBHqpTxB;p~LqB9e_=<CGv1eX9aKJBFsSsD23WW*%g zMbj=(9}c~uislTZgr^o8+E(i?l8{Xp`2#N)KqG-$Vuloup#2isDjKd+$7G3ZrVA7w zV(!vN-x4+wv_TWe{FG<OsX<%~D7fEN0`1tmoOo6G;63B8{fjyeE@SB5@@VlaUo*Bw z<@pIAMZ}81DkF_rB;#58TT&)Dj~Jok!4*uQa`%aMJ99%BvV2W=0a)hRs{p(N)Z=FM z61II$Fa5u`-F1f9Bq0>w!l^c_sOL!AJ53e;$JaZBhZ1#LqOomTJGO1xwrxAvv2EM7 zZ9CbqZKu=sK6L;6opT=QwI0@2Yhc!#WA+i46^ZNg{<f>LE(Fk|VYGDisni1=4e>za zp>w!vrWN+ptT_>$xdX+W8qb2-SRf`l$OszDhqCqOL+mHTyvqG$yk%9Za`JdO-~-o% zwj3w@0@sG3t_>sKwDtIY8^WI47b9%y<ggzEZy18@jZa3N6n=>uLvK@kTwArU?FYuh z<Ql-)n7TWC#>DQ0N84iOvrsiXHHJrqXDS$}K&^9aHG+cb7Hee9)Y6{2!>cVT>7ZUU z8hpm2vHFeioj-FnZd0J?H_&jJk`&=jxzisf!3%+_bXv<FDp$9zjsQX?&J-3ysL%fT z9cLt+A^>2+DmuTH9Wml*s>(;Vnr}lNhndSR$=Q5CO)F~|d)v)KvNfrfSJxLpL|M`J zGha6k{sX?RBMbiostBg4a{XlJ@hw3g(5nx`q?5deIC*2q@d&}~&0U*yK~%ja2lUtr z4h8D@h3ej_UQDFh`+2=tI;)3#x4VrdRnDnssrDul6b*w{un}-B-?iSy4h@Yv<?4RB z?<z+vnks~|<=bXiLTKbHa7gM}mmHEJaIh!P_lLfR=$66H2W5yKewcUeATCG05#I4< zg_|QcjOng6mw3aja<BX>*hzpduw-p&R{iTNW2VmKRK+=h=z<Rh9zZ`~CdED<x2twj z3nE(+MEUx4DSpy0(G)zPEzx9KI-zwL!*#w=k%&oag|jh4VIo4HVRE(UsUQj4ABiyE zpLBs6yAOB<H2x@{X)LGd>3h$>Ju(o?Nhn@9pCe$Usp979EcVZIv`u^s8qJVLW=YYI z)C4)$JHQdGO{8b#5Sw0C+xz|71zR1>Q+~OM-7Z9xH_J^Qbm_iORm)NeGN0#LpBl!V z{Ud}7ddDN&_g_#LTLOrLJobiK9H4@(u(Yptv?Ppf2_LKx5ryI|smd5Je|-Gnq>|_{ zJ-VC4Y-liX0O@;Zej>$<WeZez)+l~$z!~_%o{N8$SzFQKtJO)$bfts?e%RdeLzj$j z`Xt}}5Bm3-P#Pcv&dX#&P-$L!w@N=lw!GigmRz{Kyry$Z-~i4=e%5w{vN+CQ14In% zA1jl+Q}S-~@1s!Ca8q7Haq(F|LOA)zCiP$Le#+jV=<NA3e)>bR{Ijzh<rk!|lq+=l z<ke=<H+Bn(@&ngd)K=<2W%&lle|ecBMPE9GU0Lij?P>SJIkYo(6Tk|kQWhF`Z{Yx~ zwu8YY9<jh6Yurl6>FG-ccV5kGE`&!z(E$Ql#C5=zQ$K}EDKpdqxEc!crVIkS{cxb2 zdt*m|c>3$9Z$0LA=TXxN9NlU((ye-MxG_R|$1x5{M(yDybr<hH)p74T{kVDWxgX${ z%7|6Y4O~l>uXDUr_}5%Yc*9CZDU1Jo6+S!?mzN#g22GJ7)~UnYzR@TB4FQ;$YEeO; z!l~X2LOjKc&b4&+W3Uk-Ci;LiHg#x_3LyLF)rHrp>T&H-v(bx5K)jk0gFIgYWx}}o zk(4*}`8o)Ek49e~McJv4N!=bqgY$|vaLR6`ciX_Gyu9`Z08c2zJIT_laL_a4o5wTt zI<p~Q^i>xqU%h)&d@(wUCih}C7XKh5O^5Lg@qvL*8uYH<_HB0{(JgUj9ONe00k$Ae z_a_j>r?DDA0^3*ib4j3mP~FEBkW`?+wFW%%h!0TeE!{uX!V*MH-`L%&rb*l?ZuEE_ zeG7zVRgVh?4gsoWyGnucxNVwYjOyPxXc>MzDh#WGk=9WCv7&-vrn1qjCLoLF)DYl5 zTUn6KTKxI@7aC2@Y|Q1(R#+>Pa=a|zjQ%L!^;6%SR;qV0?=K-7rZKjQ^F%6U6~gpL z@i5z*{qB15j$L|Vj5E<TkK_ouS2v04K8mx?WCydUOFFk)K7aecQB$c9*9C5H4MPC7 za+aY_zC}Y5#-^`-%E=917@BP-PWv)DJ$A`{Dv-9F$!)ao`>Ko&yf?V0*X+olp$W)B zEzzn{B*1{#ygn+!(A`1eQ42M!i9th*+fifV*j+U~N;9<mN}^{t6o=#HuF;<%`%S)# zQBj4tmN<*|Wa^z-33!JOd^Luha+>jjN>2J=>5bRGXBu5{HsH}H`aU3>%HJ*V!Q1v# zkd&XDw@G{8Nruqn_+ORF0dDs^pRWxRcif?NBDjX5e<kl%A?9Km;n$jpZGyD!);hC# z@U-MbbFY#QxFEA5C23PdR0+bcpz$}8ce?7weB{O}IOqVXFv{m08N7yqpy<EkLvOTL zj6^B<P5<D0|Dc7ELmbB<X0fmf_4|NuJ!qw4IAS`<5YSrv<>b^!%KVm;d2ER;LHDkH z?dCOsky`WvxLbX()VHiFLHTy_ari#WuFSWp2)xEW4ucFg$luSZ*_Vg^G`l>FKb2+{ zSsHht>By0_R@#eaiDj)293g=-WhM5(?~sUeJ)Bx_aLr_#E@FZ%&A+JFng=Bg-AMc- zPcPOAag(dVdh8kK+<0p6BL<yC%cS9n@jn*^G;e>nh&Rv4#0G>C)W9#F7O{vZW^K?~ zMd-6pInh2mw-if^qd(QAir#A*;5628w7KRz=E!NA?ANX9cE(Yipv*Kf4^<1NxD=HG zmU6CZAlC8U9?1H!nP=_`2=@ZG8(Fz9!$hsnXCR=hbixR~slA2t&p2Dms9~LTP$$@I zS5>&lh9fg9J#H^LM_OSKGkU61AYT8wA`FYcw6?Uv<_#JgHb6g63~9*b2Zjbu<9wnD zh5Q8zl>}`8irS4KifWQ?7m8r8egELFQKu`YHf`O!J5pih3Gla^dEcmgAV#vTz$gq; zxr|Rx!cc-W<zl`+wN1{=o3$obE3h^mMz$b5=TA;x2u)~4ym{?akjmfLuX+blJqrC6 zi)y4I915wN7BzEPs-Kwl@2ruiq|}=u0t&noMJwFP+o@#o-%+{uJk~0$v5!JcC+ok^ z6CBCe-nYxtbqY>CJ}|4_$i2yp%t5&{hQ{Au)5=q9Zcu-6aQu{tdZ(Ssn8(YT>Ppvx z9LxB5xTi*2@MxEqc=rEf)3{mdK!W8+-sfLMP{F-{EdIeYO(mP9kvb3(LG`8*mU4t4 z?h>?;Gas}>PJn#_eOM^{XQWVY?&??gOnXnWBO5HCyvAf4Vf0XqrtH#5m>+}v1K--? z*^E@Hx#RIf%)#WHVJ5F_G0#;O<Rnv^dpJO`a3E$}fz#bV0u4+h=tw;i!EF+Ox27Dv zI5K`4v#PiBGV&oWSbav6W_51XlESgIG-c{D&Gi^YowC@s>^i`OvH5E`ngy8*BUpJB zZ1(4g*&n9}2f)8Bp>@m#^lY>n!<wP#Q>l2EqpO(K>=A49uY3^nj@^@y@N+UQtX(hR z37zKz$pDpo*c1(9q(<-(4_a|RHxnzaDOp1XMmcA~WsX_c;nb7ea{F+%`4svLWV!mG zH9a=YC$0~pD)amCvx2woFD1=U!|x5?^%S-J!KiS(BLjHq&-a3nyInX7YMZNhn$u5| zI_$=Wm1Y^wbG(3nG9<m8I!^Y^AHZ#RG*;#+EVO~tTO6$!VR<mMlzwBv1);oF>iQ&^ zkcOqlxHKF{&=iI}0YYs_=WIT9LeSqwc$z)Vo75oS3TF0%8D?3ZpP_jn4P1A<YoyxV z6E<#RQnCXQ)nO*fL7x*jXLM0kn9tpq;r9C2)Vx6IsN)mVKXO|79?5!B>cK5$m=U*v zt)dW*fxDloY-_(_o1_2y3I8|pVT1DXbP^VWjP;5xc=NhhTI=Wg{&kW2kL<iA<Gckt z2J1>MUmvjg@MDtvlniVY`km74!P@NSFxTfbaXQ%}EaX~^23nq@!nKH!c7uW#m<Y+i zb0B!X`ZTJ>^nn<Eg4aOUMBDo;W9O<c6)9rI&ux}}X!<u=a}OtMc&Tdy{QIA4&<8^C z_!Pni_Xh5c`K*PR6A>{o8<$dAY|tj~Qhboxk7eJXFGKqNblwr@zxPoff$11EIz7Fw z)%J5&lN;<uulgQ=-MRfRF#P5sK|OUYCPk|p+BSB2S1&{P%i0$a?T{c&Kc`}Ni_z!$ z3*Vrb@NPuy)HhtdiK5gt8^{m1fYX9k#?_DwFp!^X7cLA;###g11;xoXBnWdwziI?- zdsz(+xeze@I(7MZDnsRiuor_ZIJDe+Z_#UxxN=HhW#9=hTO~_Vj2=$X$297WAqb#F zP6rA~d;1?<<|MiBDU*mDvW!gtESJmWtK-+c_`f`S(U!{y-ihrs0@<t3zgx+EfH&Ni zLTc`iZpY#Eyg&BOht<%D781|hgx?y_bc8f7gCA<n4i5Er0fTmh-egn3FEX)@RomWS zKK)r$jyv0*NEcj-%a|@NCEzFN4Q6m2Zc+|}EU~$<J~Hc*9{H)mMm=a*M@%U@mT95w zS|4E0rP6KDJSwcx#-TVxZot;aYz(;|T-rd9MVnhn%%d3$%I}M|&M}eTUk3LV(fNdq z_E}pH-7n5r((fu$J)v<A5cL2_Zy1w6;Gu>b#(jeH&hFV=N-KHR#0?;w25v4X)O#h3 z^v|E<mhMvB`t+t4{K0W^v$y+^Vz=LmzLZ}dv=`NUnqsrCx-qyM_M``_yiUXB3Q@CK z&P+r!-vp41%2A%~1Tob;>=d6643<7V@ri3IGm&Z);zInwnCa^x9*KhHkOzppAB)&9 zzXOh|eVN%L``&rdb@`qzDCNCQr#AtwoE4_NL<-Szv_rKGbOCrygb~^Wc!}*fE~uEQ zYQ$%qE6_Xkq+msJ2m=W{{R!cpGa-2k-86jbK5ipeo#Aa|5RC**jDY(bQ*(7Vn#e88 zudjI52;H-s6m~qAWP&c!M`K~yj~!|)H`YCYESgFdPoQ<-sPUEr9QVN`4|J)y8I(C{ zOZ0mnuShyOA8c3k0TX(%FifYOpi;a+vkDZiSr22bJ-4aYC|eTVpF^Jvago>aLha@j zU@dbHdV-oTc>>?*>8{zQz6wtv^<eW?g%1E#2Nw{*$MoxWcfi>n2a%CT)2;E5FmZ4v z7Q9mJDwRasnqI$B5uz=|X2fTw&^_QQ)rAYtso%|Cj{`ct>DQQL4S$?fZ!<V`Z>5Jl zK2GO}A>vXnNHA+vyzTHy>1RpL$$=^1uBIc8{_ygeXp4V@rm{tkGo3A#DlEMkIQnAh z2GTJj&#F;*pV_@?cj-(7G@@f}ZBI6%F!h6p7$hzR36%t7li5Lt>%uk9WW{n>&`%de z9$t1u|2xi={a4ZGmvI_t1PoB3uHR*<PQG4O77IV6k(g_qJU<<K#WAV-JoGnb!_Ckt zFpxR36z3K2Zx_ChmBu~yb9Erw<0Uq4G--s2N~^#Mgq`(2NrtR+N`r6o|6J29Z-7`; z3I+gRfCK=5`(N+&{y%HIv(^9EZL%WxuIf2B;ggiMY+1{}>RWHG0BsM-JLAR?LV#!% zSl1wx$1CGp)&9dJl}x%~*7=H)BzoI+>y4#puE<9iX;D=sJJO`G;a`egK=Xb2_wV#e zOEWwalu%~S=|b-%dE@Pbcu{ez`|d_&*t*>L>L0mAdxaHQBuYPZC8a)C657Yu4f9q@ zv`Ph|!Xpr`c|Nl`XhU@-T+QMt)oXV(pL3oEDSJ+`K0MC8bzh`FLq=^Mg?W=F0w}lv zU^zjW@+ivpE)LuZ>#=F$I<%L$o3O>AGwh~x1KU7aO6K&_#cJl5(cp^0(^4VD1eGZa z%#B1_TUR)MU*zz<++YCHVl+kB^lR7>c8Z^=SCRJ?O4nY)E~D7=t??m&=AcUn7F7~6 zIn2WPhE$sq_-X1;1?7tQi3`>IR@kg7YV5qbWI@?5`F1`BwSxf6A>ou;<Pjyi-CQ=R z9-qApg3mNQ%_@?K>jhrzt^NU~I)O4^C!Dkyb#1q4ot20R0i47niy7LNilP5d-;3A5 z@J?qhR}=4VqE3ihs!(>W;+vH+B!;-}R44)IUA_!B8s>tiT?$k`mFf*tsDf59+pR>a zx2dpS-=QY+inoCu9akbp1huejV%$hWY;a&I2FC!DYPer}tAL=oP}{tnX>DmsZ08w` z$e;-YIW+8F?y>HN=x)-+{)BboaqGGwK9+l$kWbH+RJK?zk@dzo$#uv*zj)%vSn~S7 zBs~vjTDVw+`zT|8Xmszr_62hC)6(=lWv<Ga@paKuDZg^G^A!TJ6>SCAI^CB(b4E|H z`cdFiA6LR3!V9$2J#WU0hbMv#xH5<hz^7Get2Cah4k~9r#5c5yZh-GKWunoJE+NG= z&IlG!&In{K1;|Z-YA9;Ou)G+0hx~g7<@W~|X`}HKM?6tEb3_s3pck)lX88VW8gP&X zvP9)<fJn|ucAvTGqK%QcS@0U*DnhBfux;Vy6|T|tv-Jh0Svtdn<o)o=i*+<XC7p<a zaU1cgB?Y?OYPN>sAAKq(8H6%ntj&CXfn|I^-$Dwix<BhoY<ko%|4yH!a<Ib1@=qBO z8*td}h^QR2$F-egLorFFwW`~jibrg7sZ&c4pX*7@eE;-NWJqter5lMINVp#HSS(;} zAV+;M*2474M?<kRh5NE%Fn>b+s~WS4$ybc}?#v^f7|(JHuw+JhJz+z0>UMzb+C`%g z1e6Xq3p5A^P7lCCg=ogFyyXgc@Id&;huQTxi&enCfv*nb2!YwDwS;lS(Q{?ykQTr~ zJ_Do-)fKxJ<d*S!4AzNTIFeL%asgr!Y)_~4XTq}+jUR{0A}X_O&2T_;nT8f993j}N zK>G;lCYoW&p`y-9F&!#Qs2_%U^#_JNacr12kKxEi;eAGw;R#u40vA1IpcSHzO6P() zz4NZn7~rQ`2S!FcS_r#~QE`rO<}geZr+e3KlfD@Y^e+>fBCciiqK1vs6K$tW1#&2j zhhw?O8#;2{LI32=T@VVan_OpPyhHZga6Uy(-+R@)!y*n=xEK-NG>rDFP5#_nIe748 zkMlX9tjgy!*_g;c6~%&EzSzukD=N#xYIjaHYcTWN8Oh17A~zFRWUDCZDY|SQzMpPx ztc7H}z5e*{U_M2~8ys|FTU~^L4R&I7%itydDnEjh40S1UY3}ipn~b_v#(;9>3~!9O zX4DX6vhIqKWlo=kB@f$dEXuqp`6M>9Sf9xHJd&Ln@Y=$U0w-s&G3QVsg|Xw<%!etk zrlB8}hp;#THNHMi8rn-|HwX5RInZp&&@QV7WJg2oX4@P-Fa%xlYdy#cys@?409#zA zl&3>TceK!)X8JYn7^7=4pHw3j5=KI~BFuP8)kEo)U9*HkFfl6XX)xzo&NXdH|748< ztJclnNT4Z0dbEtx+*%3wu|3$c-~xSjAf!)P&LSH&bCG~E&`z<mUD(ntuQxNaxegd$ z{LCi;`AW#l81u!Y&g78v=JVY#)q7i)P~arED{w%FFtcpM^<0}azIeD~2N<QBN}699 zTlltn&N9ppV_0_HW;{z}zRh|k?{wg`biM#l_ot2UHI%qcHppsKXQi^iO*koJex`al z`*-tVFm?ACMsOmlsV??RE-*C?p8j|Owzjs;t;)U<c8_cwgkmM_ZRsG->pNSO^7=zO z{@^Sz>8OhMsxw^Cc1=8EI*XNyG!lGK$$~YkL!tzDUF&Xl(h`l_v5UOD+%Dw5$?dtY zXo~&-{wKp#XH4*kg8%?{!2ke|{f`W%_kXp#RI4gj9sW|?KRrU6K<jfCLHzf)1i|rb zA!r*(LFgm)D8pE{<+X(P!)aSTA2aL8mM$*~`18LeG_&3h7LU{Bl!e%;k{6uhR+Gky zmIvz9ZhvYrvQ*g)3R?a&l6U_0)fx4>R4;nEdd|rZE58-bN;2zfDfsJX84sX%dHC~Y zu-%|+^c)|M&*uAVAAwa}!|YkJiqKGt%CCfX%owyz7FRfPk52ev^#n-p^dH&|-i8;L ze~ttjV!qpsr?$X`EFKS0+N5m)6B8MNpVpo6NY#bJS0`%Ldp$Q(0E?RSA9jq^LEM+? z6_Fnw*tS48%qopYeTJKImwx%)*(DWqpP0>74a6=;C`|VDAB>`%TW+!NJZ8LQ5z>$R zs8F?icB7GRw?~py2T0<LQtTM+D@Z)uP|JgOl+I~WQjkmWf~L}OXLIj(n4)jNliIvx zkmw;Nl}5gP9eZ@>suN5^L=bHb-T{m#68Y-4j@sGvb`GD=?tbG3fm;l(?R^k2k9C<# zN_)e13F+rPFw%ilkH*)An?HLYqLm5GF_o2G0zU&1>v2M%fG?eyFW$L9NGZ-jlB#1k z(Z7);YGl>fVdO#u+XcepP|-@`Zctp&uA4Ob0tcNc*2{GTqkq3$OEZXyLth5jImP-= z@?jOq;JBQtoUskV6<p`lu3W98?jjh*cbs9&P8{G`2D}ixecPGlRo80_dvE5{(3q`O zI=x-Zex~C4`FacLJPhBh@;Vt1?!&bKDx3^5mQKY9J5h%Y9C@VWP^lJF;8;2Tsm#~H zEpo^%6Tk(UMANz=Y76Q7@i3~Sys|;CA*553H9ra#*egtK(V*Jm{g9GEt>x0@RM2b& z;x2A+@&VUvl3y&3+=f~$9oWx-hxZI9C8P<BMn^&J!k^F`YLuW^w$ev7UDE4I8xcKt zI)&+5z^OHNnuuTW>1FS!0@*L@M_ji17rx>bK#Y<dgwf3@@~DU=EPYGqNyMsnr5=ph zJ*0JPP_YuPf<dJWNU@1IR!T+N1A%qRWu|-jEDR|)Abby~7k<!O4E?YnTGs8JU-`)R zpu$d<?~xOhs6n>mAO=`{WN6>UKsmQ|c~V}JU4v17{WruTjzDN5Fd44p0EQuzuzy`` zoq5fy>W@64t51!ZJMt<VOd&6ewXc@>QB+OoACbVXoERA5s}Lic{5l(TvU4_v1}gUc zSJ;1=<{^l1lA`yL4x?NK6Ik{*i>QMQZflYmQG1_;+W;*CcdS~Qf`n8WkK!8oB3BSE ztBUXk={#lF9b5R{?mc@aIyoEpe;BzL4=yvEKhm@ldkA;zkuJi5RZn&zji5zwW4-e) zltlD2b88FwNl1os@%{WfUthD@iDi*agzaBv-v6+AiuTZyyYJO^MC}-LE9;SMpw-#L z^8yh^gerIHc<VC#$z*PBM?hFT$-$ku(4%f%nq*o31pZGf!arxGvG`TnxyS$jg#R-Z zSz8#=+Iu9cZ`y9MBlx_iA<zPiR})!hwgSky&2Q4yb>~^2g9h^Fkxm?kqJbtvRQi6+ z$fGADB>Z+s)s3eQrZb_#4aPPrhl+RaZ?kQmtCSzc+YctiE1ECdEJ>ot*di6cs)%XA zV}Y)gFle7Lr;ZX=M<l5c5DAmL#>mSQ?SCv=CPP;MPF)SR?Lphos)6ucJiRwp5eb<q zAoNwW>x2FQ-L^6$`Lkyx5)0!mr8s{6sbmG$&~Sm}tcF&kPntChTN?PIpI!x<njFJ| zY~lywTY^>uUmk_^O2xwpRHW=npmi^xO1*`9XHJF96c(kL-1W|qnSwgN#KNSZ1jt>h z&HyFKBb^kb=T%u?+)?Kc)}`%gEL9MAMFhk!!Yy%=zF;pqQmMG3-P1;@riG+OayalX zvL9WZJXsNJe9LAQ9AkKfmv!D_`l38M|55Ab_jVCGTl*cw8Y8=`tOQ1LShH6UmaViK zFpa?7??el?g%{Emy2Qxpm`^7Mfl9t{PRM{f#+aZqJr*7h+-=q;E4Ah}NO=erQM|t1 zM1z5PI5cf={Z+$4eQ~$n4>Buq7~nH2QkZ%Vs^t6not`eL5*+9vShr;=;0fEV1VUA7 zY(iliF@RK2&Y=$NMjLx&0jip<Ec{?er_L&j?V}VIUof4wafVmqNo(=9#~kxmLFR!g zZWLh%5c)|c4cXnYm`PpKl|~FR!TxJD^JV?-h1^Eu1_3_AN9izb!s2N<?&p;Av}04b zoqc_6R#d4PEl7GX^)scYOP3Jph>u$oS9gv$bDt&YPCPc<5R*V<Zk}3p1lMc8T<^gP z4DmlL**cL8N!(_eA{!_mxnurmg3Ks_wBTrix=HbM2nGdRI2)Pd`p@kvB^_wneTrz- zL(Fza*xu{~QWr~wpX9E}z4`+bZPLSX&})fzTvnLbSQt;AJ#%QF=&k%sczS0S7ZDI` z)%t(hLcwK8jN1yJKfbTHcVuhgW4DbzSlhIC?wtIDiTxFIu}xXwhFh7cK{`WQmB<Oe zlJoOcsY)ST_EjuWO{u~L(cBB<I}Aq1!a*ldQ7)LoJlG9ErgT*EhC1yf?^Zf_Qr$*2 znnZ+|OW{^6S-f&%sj;<ux`vZS`lyrXE6UAl@sEJl(GOXbT>&)w26T{e8c<V;$QGF; z?Mowr`#POC*Hc6nf02S``#I|p4f3<#ZvTk~SjlL6>D!ghT^9QZ>=x@Yp_bwe2mG;T z%{~b3zkc{SUUA7G1b;AM*b<L)?d00(yt`RPOyUlEES=Yw_FA6pu1f^K8}a`;{|WvZ za3aE+<ZJ&Tf67!$gWv`jf<CJly04QyIiMmf`yd2f#0F2Q?q~9{%W4zK>Jgj+&uSm! z9Yv|*BB~Mkpr2Cgf?bWbK2<2jT3oteHWy%N85Lo$6aWTv5U($$imAmhZ~Dg#X9&(L z+GdSwkDVSUe2mdr;@}L?*&u6afOtW6N&ZIh^0H-jR=nvjv6UQuD`@=T^Q~}$;;tYO z!-+iAB@=U4ogK|tjX*lpb><wrkOZL|by0e|5oUj^Wfr+rpPfXmu3)opcR73KI|Tty zhTl3@i#pccJ)iz#=}z8;9NORt3CuB+Cp+(R<5{$Anwr$}ZMc8EyKYx^>Q;+@<)3V$ zejXgzW$_5Jmt&hh^++Gn52VMU7iXpFK5GABjbONsrr{SLk~9|FsBPcp($e#MdO<n; zyt*40UItXW1G~R~Y6Yt@o(0BG$QGBk-6#BpJxBftx-RXUG1GPu>Cg9AWysKcrk!5H zMXlYx?<X3lQC0RWgQ6-*W;nCELy^ZR<PMJBwytbuh)?CqLup9eq80hm9lm*u+_MKJ zpOV$XsG%K?)D!g9@!$eu)3^iV%63|#>ib|6dMRyL+)xpmMf62nK7^)6VHMQc+8cMB z!Dh56)K`6uAS?Y8>r5BMK`cJ=aqHGuAFt8c5>r`2{fq6p5I(@gkSW9lOfMmV-6Zsa zzggDRU53p7rQBUZTyEFE4I#g8s=l=&8cXr=9EgSjlo_c6(xSgdBgV~~GXW1Sj%Dw= ze^UY1FXYJMfAS#U9g#QuQ*C9>om0QV1b1<LYauhb=n8+v>}3W^9wK*GQ#|#Pvp{o@ z&0*ujRQ<Ev)2*x_ePpmtbwv>57lCyJkX&=r$(Ys~#ks!h_n$l^%6Eqs1PlQ17ZLz~ z^nd0lCnHA-duOL#u8LNjt<7Xd=y_0+F0Y8Ajr8<VEOx7;e40}!=6RH_jsq6jr&${_ z(q;X+-~t8%zA4_uAsRhMzsdY(k#&`~atL0l1+@LN;$eQp0XZt7s@!ssR1R%3R@p*R z?%44H64A%mO`)D4=Uhl)0h0IQON*O;s~rM82HtY{7#^*aIEa2kmpfmn>5&YKg@u#S z?5gf@VJnfKTurpH9cUKVW#;Ui3*fiF{H5QozFLk(HeZz^^bc-oYYSlZL@{$@V7a_U z3|$w=io7r#3tM$jw^H?|Z{c|$m2sd2lK<W#T+BhvW<EhLq@MKo76M;I3WH%=|Czu^ zdmg^K)ioJe*_jHsiv+}_0o1_C#67FHan{1PAoEP8TT&A7GYsU~vm*}Fon|V3K8D+! z%GltP{J`}#+BP1|YYfk>+HS`|zUS*9Y9FJvdc~@&nuGf6=>F~+tb2K6_RScx@z0tI z!e%Y&dkpcpGz{i>!?|TBKH%)>q-Z8X{1aUv#k^6qi-{R_-gsRdg<OQa*7G{k*|}g` z%o~r9sLSSw+^P7xr9v2q+@seCT&Y0oQ`U}<^2kperPq=2D44pM$4$eyAsl!-oNl%z z_u*|SOPgT#cWhh^iT_dZM<{Z8jcf+pYT2s4W<#3Q?=GWI+)auK-R$SB<yf4o{hRsh z+Jotis)9Eg4Vx^PkIY_srCXB@k7m)=3K^SPXLxg)TZLmIMB<j(Q#mk7TA*9>;G9a~ z42c;%Q7i=1{Du)KQ+TK{HB|J#sfKKh>1_SC4}NZ>x2;x9tj4yR+tybqRzf$n*}G?p zeN=7usX1;7Gnvut7w*r+e0IV&YEv`HZ~|x(dBxebgEshCXbmFdMC#u*XsiqV_QuCo zYbhw{8piT6ZF?w@BT$uSS}r_249-Hsve(P%Q@jKE9f%_jykp5zZVA9n84l-`k<q16 zj;>`hU0(ItKKJq{k^W4xY<^5}CxjD+<|<wd;mE=UX+O5_!IUyu>5z2T8HPs3Qxu<A z<QO(@LSj-WJ{ij`?%U8~o^j(H`3@&Xm__clbUkVR6Z`zflH%W_zt>bTyB5D*hE}b> zhcP;1$OnovYCK|t{8<2Ow}$C&tVz!;gKM$}{ng1%KNRSJcLicvdS8U&I9;Vzqp7p& zJ!RVUte5U4OB#cgZd~LBbzd`lJiOi6`C6lU<o~?II+1?_*#H3moPhuUDE{kPY;E9T zYh-TXNMK`NYhh~Q<V@>sV;!9!Ck4!aFnsfc!a#6JsADA{xxT#+B-kGWj#|sWwF&lM zmOWmxZD*&rxuHl&7N@<F`8F+ezrKOB0+{ezvs<_aYqpzI+oXl|dGsbA&0a{LLmKTS ze~TA3J0U<D-q(|vBhp(K*m_!0q^eH}S&8a-?}9L~Sx&-rDVn8m<_wFX3!j+`jJDdd zQ2>PQd>R|JaE!fuW;sViaL+E*ya1?d&Y;*Mb3Mb6)uiyNk*}>dOQC#_RrEHZ?L1mS zx)1`t09JUQsq`BxqEs1$<wf%}r4J!;t3~S+#DvI(R&eTy>+G9<%=8azn6V#f+&zRd zOH~=<%W~x1Hu{jtxYJM6TzX?nkS>Xx_0uHG`blZDPxt^hte&)snW1&1gzB)p_5OS` z8sy*_9k2Tyzv?w?Bc}%0{paEPIO+Gsf&u_|{z`p<|N8LlJ(yUH>}>1}oPW_XTV2NP zfEA(pL#>V#Ek#T07c%uDL3E5;`Qf2awt;w1LinYUrbUrJ6D0S)-+Ks2HFINHIoBFq zP1zsV^%|(HifNQgldV)5jPl{6-_4wFa!nW3MkWS^9@nc&D?HIQ$XHrS8E92Z#w)9W zurxJ1;t*TPs}=df)u^0NvEQ&#&o$EEawdVGE0-y0+8A^>_cT(BiB4n;raw>zn{{iq zU(DV-$*EMWo~W5La5ZWkp;y;&tNb1A37{=zACrz`k~PaIuXF5!{=%kfaESE#mQX%# zuIJo734I!MIacDMRwkJcC8n$=`v0W+lUx@Y>?q!4L||1$u(*s=V_cs!*`JsYN-Agw zaJ{G-^{S3Q<y>K|&1t&6gECF`Um<{xcJ~vR`REc6M|hvCTLj=YMBNqGYieTLK{ptX z_8Yyc^o2%Z7`a`($l>$)eh>Af_eNe-;sR`Oj68YV&OsUVmd4tRQW*<vo6p~AR#XvE zg@Gd+mfLftOEgzq32$iWP@RQwWob+=lKY}SrX5prGB=DRymx6K1V1!vhk_uzF#7^W zE#9w85#XmQM9T({J#)7mCrNV@j@7_?G7jw$BY;mgqm-0}gbZGJOczK)D%r&AZk3RS z<scvkX4=vEevPv{PGpHV{cS4D-QJ^z8<DbrS=c8hLr~Gje-TKffC+?AUE!5J@VyN7 zLMIP`k&Y7aB_5Y<>IA!Z)D>H%C95%_{p*SgeqIZ_08)Avn(#aa=vbD!SDkF}N8c2U zkxn9-%6AP3P`_YnuGZi^<U`DMC_6u|?p}jlkdd6c0;TzoWT8|AfRCGdO1ay;%V7Ui zJRy?G?^N_tkH$f1RZy%mvPF-*z-R><1b<o3#Bc$H4v{}ql;Yg7$ZAmXn*@UoLxs64 zQM4ZYlUnz6y$%^%0LMika*5KXoY<dh=X!ADD$(}DAEv=8bq<wIL~de<VpM_33(=AW z7D!x9T;5Sg2Sxdsw%P3usi+A%bzf+&cGH{lSHnxam|4+Le!g<J&nc;K|387C3!P-D z`0N_ONp^&AlG0^mVUK1r3V;xd>=0tal7X16j4GUDnYqntF*BCtfWK(mJ^G=uB@UL# zOexaOxWYHDSdSHH#Hy81kF-!YO}pJ$=jr147i`&V6E-1`1raN_+q9Hfd6^hHOiqe2 z@o(xP9|Z-yrvGTL4r;G*Y!3Y9`iTnc*_yH?@0N0EO&?8jj$b;@f1b0~b;Z>i-J($F zii9Y>3aw9blo+kSfq~}_xYRQ6TL(}7-Y`>l6j`IfM88CT^x)zZ(ykWghjeF}7OIYi zy%HMLxCAjMww`Kj)`{lWsIvvjOWDAf0>NmA8GIl}!$0YRVAaTkCVwX(=NaUB+3`H{ zqn0u}=*5#>J>uGMt+}?IUjfw>Gqke|Uai$$E@n9I+hY!DEo9(C8``Dx+d7$L;U{-| z^VrGyWnp7A8z4^K%WyG(Pp78)ANSw385O_^G-8V`EF!w7l|oX!_n<nq>g=&WdqwR> zPZ-pyfSg&#PL~*?=hfhVIC0W+4$oao3nboNl;Pm)i0oboUBhcAxfP=p<1dajNRc#W zK4~JK0eq>_CDp=KLhmea{4*R2`{>^+RpR^yQTJAd<bLVMl)+Q!@ihtR9CQ}~2F5wA zt9|9Il!KaHut##m73tdlBDw^6nO5!HZYFy+QEM-<>fNakrJFG$X3&Wd)klkplba2& zr3?_Txg&oM?A~rDgKPPZ%=T%#|EqGhOYYB#onwT5tCz@WtwW_3V8?Rp?Ev$MQm1>O z7R|HkY{$!k#)&FD#&Q1D#aK7g@HMj2$iQij4epve>=F1B_hTsU`(|06ar)lJuk$j< zz;cGTc6xfxRdrqlsQUhY>Nc(m=gpwMOuF>@;QiNN?r36W;pA-M_zUGW@dC0#^e`eX z93janRHA1+NL0+?Ri?@g0dpPMVPr8`C`+3MNeh6GwK!ZqZ(Nw^+%U99q@5fA5Ap1S z(uo_3g=U`jJE8sbvWh}rnf_}slF^_E^mGi!<1)r%y!yDF?|pk`TE4VA#man}NxOel zQ0D|{v_O$GFU$;Mxohi4a0nI&{mnnzxboE@>~(7CL~Sc&Sa%`1f+_d7uZxg)Wo{vs z9d^jNc5Y*~(1SCnpF=T<8aeoq&*J!W`V0-inbrXx@fU#2(SwPi&r_VFZ5D@EIEA=b z>eq*!bQCLzX;`CS15)OUif47)&NSx)QASJeQB5nq66#zGPjlU>g%vC5{*w(cCzgs( zehq~)1ONcee{+C#&IZmV|GVa;B4d|DkI?-<MO_5ZN%{>K|Gf0L_P8=>8KRD%&Ze)l z$-MsgK9j~mt)bY=d&|OPw=>0^Ig*jHJn=SPIU~`*xC}qysfzi9T}2nVkegt7gs#K6 z*wZLpx3adr$Kd<J>u&O>#z=;q>2NomJw~3Mhx6)iJA$xM30_H@qEyR9JO4cV=u>_{ zB2iJ}9HVg{1^;=k!A%0AmQfNr7XWVBfn`l#v+O`(3KuPLThXtg3ff^ky6`?2mc;`M zBiVWxZs87iqEX0cZ{d%LyEXuV@t6JMHXd#EeL<~MC#A7!R4U@Dm=X6O6cqUY%{O{N zkVY|H4^;8}LvtNLONqLN|0tTLF%?-|{~N?Ap{l74jBo*PHyz+{4Zog#QM$Z5!-YGc zAS}!wEyH=}Sg5=fntSM(McU#>Wxbp&3~ozcReOX#Quj#tGKL2e)(TpIqOL`Tcs@Lo z!=&(054qx)v(%B$n_;n`*s-o$z2_cU@tt+QZ5trjat0<pt-gwl9Z)y^_!<|cSOjuq zpK;M+;*16Zd|fhSoQ=g8BuT=2Q@V<0ScWDa@keVS<Bjo~VB2JaDXaB_<@pIF>Dk*? z&v3Unu)h)CgiUbl{pRxe2H07SB(_gdh9eI&v*uh)*5X7;2T*S$V-b;1qN{`E(*uB< zwM=aJ%I?_SXZMZ}09G4fWmmjz{+&{{BVQ@U%!5po{%^DLT^^-q^t&?Fxkko%{9|;d z-Nro0V_p71BSK`&RT<k0oG)F)ne)M)iemW=1~ne26XVTvBW}Vo4vi`0g`zPRgNsm+ z)a?eEgK+|_Dw$Ls`+nZWOQq1&$PXyPg=N~qlMxBanoo-*<(00*2Mp>V(^ub^;jV7A zv{pn8tCF+1c&2td+rr|(_cySrCjSRlb%6%PeLWdPE)P#NaJlOtNA8_=W;0xKJo+I) z??kt@n-iY<+ZcSu6W%05X!o}GBSG@d?%$85&0#n@Ke`uYG6!0DoMva3;aQ2pn$K>i zg}D0ch1%wZMt+kGH{a=&0fY?OrSy?0<p2Gp1ro5rEcy#Y3BSVrzkwqs16LEf|KFFJ zB*@qX)5C<kWDOKY0){&R6mf{8s)R5S=BNBdP1CEWJYBmm1{g4F5Psaf9dU5FLl^CL z2;aayEof0~Ejf+TA<ohA3d<vpD0r4ST>D>~Zo4BERa7L1A^?V0?sKyIHRV$7E3LV3 zyA~wu#dNNqhbRCC#ELdlNj^#>!lZBAgK+@@uAVfMml^%naH4yT=?#G2tL&fIk8K-d z0a0lsj;V8b$f#)SUh#a!wQC}?tJ8NIW=n?l^{wKi@jzig&Yy~?rEXNuvXy+6H?#kM zDXYa@x+f41mwBvE3FIC!-l;UD5vcd3`p>rWZjzW2b59l=7IeK|CC!zMrBWRx8hK)^ z?r+Oz88yq*gFEYZm~jJbYd}-pyN1UUDG&UNY8BZ7mu&ghZhkHfMrL~^4|i5qFfYw0 zWMxP8axzbFZoJyE>d$}TnSBH+cqbG9KpH*(!0#A6fRl-{i@md*owXC)ucH4oQ^s^o z#=m^<zu`>7%5IY#?JGyG-$h=0gi|nc$`x(cxPH5w>-4V#xJ(DUGcYX8JS%wvMVuni ztp4{$j?}q;f+VL^Q@xDN&dWjEj-`u!JF|<@<N&=#SyGKgzAO3F=(k2f`Cve*hoO16 z!(dVhPdei^xzi<|<g(9%vPR@+M_guNB274Rfo+B6pWES%ITP}Yu~Ag^6TwJsP!*|M z<<ZF1xx9TBISJ1q?%73cYY(NR<053W?JGr^C`)Iux(!7AE8a?%ep-!yZgO&R_dYy# zhgF_%r*bJ@gj9tlZ>ND<O=`3olXNCs6l*GI19c@qj!@VIaTU$QCQ5#@vsOta1qO|n zWO0%xX;AT4i(+GqO!j+k{;b7nl9`gkEr-Dw;5%d$MT(r!Nm+^57+tYH5nGCbbyd3~ z?C8TvV%64{+9cpyweVd|RFyCG%zunA=whFAQ@BhsBD$y?TR3Jm>@ZotLMtjpn1IFn z&Rn91)tz>m+oM!3C6f(V%6iT5HG;Ayt&c6*Ey9o^ZJx6+6&$7|K%sUW>$N>DZ-UEa z^nF3U=XDMnOU3H`=xbULVysr=zuF=aq*(M@HMsPDU)r2-Zccg`AQP|#s2h5O#>HtU z@FGR3#4k(YYgDT*FR6xbJZJ*$%EarsQ};A6cp0&6xfa-EH%iq9^}Gb)z?uC#cWQk% z`F>oFx^#TMOuwJM4~|w^K?w`LlWr_Mcl$cu{N?U=dPX2^Kr$7z-D^$l6$_7)jgr*q z0P(Amm<>-WMwU}4&SYdQSo4&S)I+W+wIL5DuHP(f*s3sJM}|x{{fnciex6-cPVG+U zC&J}!n@d{yDsQOYd9YYJwMg1k0fIr9m{)(9s3)K9(Ak&>NUr1e`FZy7)cmy0h>(6I zB6<~c0*=`Fym*o1V=0+5722$ssh}VvD9Ividr1T8VpbR)be_Xrd$2p+#0>6BuE^K! zU2RQnZ*!R-KvHXEGnn+sMG@;IXgr>}c_i+kd4p=Fw2Bz(GUG8#2%a6YrqHp+H%}vG z?07*TWzuMgz;n#H(hH4y^|&CL(vZTc(}9O#x;OWhP#Ojt`+QKSdUm~<aj}NX?t?ML zWl}*MQ>GkWXp_I<C&)FdRZOZK-eVu%CF^PV3IxpDK8oYd%L=&uZ+9RP)vMc(Zf^j# z0F12%>R!kw?UeC1|GHf9PHVehQ{c`b2PDD`Ia>Ee@x8_-DG8v|&*RB6<yv6nW5q%f z2Ze<!5v`#MdT~8+06BtP=EpX!kdX`GmD-I8I7NITwhX)n*)wc>vBAfLFYm^6%y@VU zPr4HaA2y=}piIJ?4^(8u+;eU|iv3A%tF2q{=TL-rBt_NTk#VBuF$Z1u?N8J}*x_2e zIS0%WU>Cwt5(Q^>XwF+2<l|4XPY|#fihDw?2&|BcQY{S-Qrf>tnrNCu4XHB|)2MUS z4;3RWQ^~=OK6bem?#@iKnQ6RzSIr|aQIOjP##3!(;m+(D^kKf9?)O_?AD^HE-GrX5 z$F-*Ke2&V7s`=2P=n_J{1;RVmE+w=ZeN*6LfF?u;LqV&e??K&NVm7fQGDqYxgy%p| zbNR`z7=OjNxl}n$GP%Efl_Bw>Hn^Yl6s1(}YIf$1c#z6wEgnM$s#<mlo{1^q?w<cF zr(%sW(I^i>-jG}Z3pa;4IM=G$nFoe%lfHy5jWrT7t*2XMuDIV=IrQ?2yCr)x)-^lC zXA;%qqXab|eBGQ8HxD!jHFaN2*F^j3wcaT1Q9X88Wl)M%7+c{?YQW{4@r8rWtzjfe z`|NebT0Z-y%J)BEN6M2kI0KlYL-8<KH*VBnj(T<KABxrLTHboJ8*XUL+;#~sKTI1A zKHG6mmin&XUeHBDD&Y2TNkOU8sPJl=yz~Ceu;>O4i#Un$lJR|=aQkB>HVWS33=(oc zBRd0Up@EPcDQ%|qP~v_kj1XOxajI&50i9+ooy!Y5$x{T|C-TU76g8YNFkQ~Y(mc9> zT-Tk%LOW`NB_Ty<E}O^WDeveDv7fL;Q#+1*LgihJ6&x|8EC^r@;Z_GlJ=5<ID0F45 zUqyk7TUu-t>}l=Qx^k!XYzh)>bez+88kW`ITTL@vj2Tchn!WCzn}fO)ds37enc{$t z^p75;@Tc?7C>55Z*lgA~_`H~Dn2IDuHVIA`9co?q;<;jzN%s8NKodMsiE<Pg#BN)_ zvtY9AQvF=Mof*#@)R~$*aV>^l+zq8C6<URZmScah$>A!y?3y_1l1`JJiO6hqVl5qc z7~_M*%m&OlLv=EP&5em8FqM^y=d_m#9szpmzqQwLdptYyiXgvWy-hjEALsX}XxDh? zUD*}nAck9HHS?Hh;f$R(4*Q2gRbMiM$3(S6>#^Grg|2&rAb13TUDdx;Gq-z+QJ*hs zhL+PR3O?T_^gOqcyS9<|jdIxR;Kt9kLtB~xRvMLFBL`Fknb-~8SIl_A=?3AiUo^eL zHg&0@beQJf_pf5;=j!#l*k}C%Dm5tw^8kP*2sj3eKxn+wd3lkA{@oUtmAd&>{vMq5 z1N_^{b{1Z2MF-be%nytJrgDRe;jweemAAtR2@X>ufAEja8da16E?nStw?Tr9+q`+0 zAqwc6mj$9af~p~&@H0xe2|VZZty4<*d02<&1M(6Vykl!^z$}5liJ7oCELsy_B6z=} ziYSZMu89o|NWwbg&q8I0ph2g@ezxVJGm(oTI1JdL+LS`<$A;QXBvKGTF)vXh4{ytb ze&m)RO){BCLJ5}wl-CJ6Pu^OFlUoXfboc{e_)tJUs0Jth=ft}UJY5SxGc1M*zrXhe zHcn~ZC1h?lxH5XsI+~AEGDTkAovU%cjy#;cq_UB!R=Gj$^n?_5(<t0KYqnv%*n8=u zg+xw=;kSWL^Y`Pk=~qlm=tnLL0`YJS?+$(Z<a@74QW&FBdzep>LB4hAJq+bX@Cn>^ zEAv%&Y)NQ$Sd6G>D+m0G((%d!*ZO{0sK0RG8+tXhotIfy%>foIV{7&Y9INv>SBJ<2 z;lO2Fv8ZjLmB2G123940H~qZf@W|e^+e_0apj?Q{(x#1jo|PDK%1iW3uaMEXZCTwc z+s*8EMx7Pm+S%}Aq;XSyZXx=j1U+U)_Ze;FDb09Dw3~4;$Xbf-74xUIWPz7ix!Fj; zjS3r{p1BrJ3SFZj#B+Tklj*gwO8*}8^T0Vhsw5qwUP?5?Cy5*B_D7S5wKb&;RLqQc z)d>AaYvMwF1bJ)56;q9skO`JpsrYZ)W~rGHmDy7U&rOugMc`)cCa}8vm~@h9Aaq>A zzeT5mre@}rMbRSD!`ig4U6#kq3EUa3_9xiem@l6)Gxyk;Or~@5mZ(5O?9~XpjA!1B zk7c^IQ(nEujou#B<nHOLedqHJ+a5zvQx_au;b}-AkwVDrkyUJQ3eR^}xmFDxLjNke z4jQ3dVTf=sUV)deD|n6Pld58JN_+D581WKwI`m9abh?7Rx9gVkfX+=;F6|b@!^ji3 zt*d5t*>(o{hop?8s?B+254Uw@SId(@<0SAOzLetLvN5*AV9V)XC%CS>NlU9el;+>8 zeT1l4GXksHQEOt1B(GV*VIZdW^+nT=)T`=a-<O=D*6e5O6BD;?964WY2sy***dOr! z)V!JYlcR^f747ZciuQlw;eTcDuj%;zs@Ynxnd~UOv$b_`M0ql0&n`t(%$A)WP3X-F z*MsK5IP~GIAaSsX<Eq>LcAUHi!Awm{xe)?p-#)V|;md`+$VgMa<{mUn-N`?<nhVH9 zHo58NPjIi~Dk<X{iCnz0s*I(>RM`XIpTF>RW;c(CX=|o37VGIW+ZW6eo`hCgX$E+n zrJ2(YW7pe#^cRTL?u^7jj15anLUvkDm~1ANDQ7KoPB_-%JJqd@QEN522pOn6axdIo z*C=z|0wkNE(r(Fm^r}@!E5k}Nz4v6=BhOp%T#|OGAhZ=wz9u{uaxnzrLvt`KsGcsP zwh@XO2uC}3cI~LdM~7SigkZiU1Fjr`csSr2$ie$8P*T?Ig@~&0|M){R6Hf|!-A51r ztY3*&IU7zR(gEfmMK{=<HWYA<Frh~Cu3DIczQuhl-jg{*y00fEKr?e=DiNu{O+KLD zaQ3)t?kCSc<caJ&n`{a_>cbx?qnv7rN2Kw4OJoh7hOqla(0E<)!x19$RVJSHx>>F3 z04pMD9N3nZkWi#XeTrNJlpo^S#C#fyOZZ)-L8sikj=U*|NNj>23K6SqSZAy0B9XB= zv8K)O*u}&#7PlQ6n!EPSX*Mvd^9Ew&lUacYFu153$M=wS{W;G!HnuZ(Cac|I+CyrR z(#^v|Rhy!F8OmSrfAIa`GT!l(!<z%;KZ5RTNWiIqs+<FTmSrp!iE|SjyAqDh!n7et zpwyW5ETIf!;X#kWSdJd(%!>2wD-T^0KY<zo_(3DzzzG0DSPCOegDz`obx$AYY>qI` zIAAs_d`!|uLqU9Otup?*mnNKxL4#<%Z*9$O1<BBCuxJ4+BP7`Ku0#1DOn0;VkbBO7 zNy-GcJDwfVwn~MnZq_a2te0S3@+30i<(eYFi3Yh8o0tev-3=*;GQB6WOg0bRgfm?q z->Eg}HH+11XP#2&B7?={Xe*5Tzy-xPwruaWyULGCb%mVFv@Gw5<iDx-)@zU&$2@fR zBk$T|p}{-7{;t#MV6=dqW&6qb(r%WCsC)mpl{0M8HL_M^(vo5%pR<%kGJYB$65Xzq zWhE`lBFz|}v+^Kh>HR3p?!zXH6rbJsT|sO)_|b6WgwBooNh*~)4cv9iahZ9mNWzzS zTnHQ<PD!7ti!Pn4!iT4Hinb_@HRXKdnH4kqFA%$<(bsgqdM1CK7=0%fAem*S9#wBY zNnU&_(_^-+4~@F~c8kiAlJxGldML{3;LX)5t~(DDr@T(O2}re+!?oyo%M7d*6>-}Z z)g_!pdv7;CbF&2kIFC3vZP0^D*3TZBLo9)pepUW|(REHiqC{P?Zriqv)3$A&wr$(C zyHDG;ZQHhOTeoNC<^B`*MpQ(-@BL7#GIM=N=;3A|vD?#iJD+iCXD06{dNvF^;>~lq zCvs|l00bu@!k%ozm`ro2r`;{|N!6>12MLfyLT@{pckOEPDn)zV<+2JWYQ|28?#=3| zu2&2n=m={|P+&Io(<B3$A*Ah|1&GfCYXL^E3jbkBkr(hf*^b>Zm2W72cf9shmCyLF z%_ng(+3)3&j(L>}Fg}<AezloW%p^YZZv~*dQq9jXd7v$jl#|cXq}5-?FAPBTljZWU z6MMd*tC~RRp6QKJc(LGV9(}*FNVI3qh?Yy`7V3DhxVs!aKbU#NUdOEVcTY9p&&eFv zy#C+XDM?>gGMyPL&n44JvxU@V7TbXP;&u;fDXKIY5Y>rVIgr|0OvA&epb{zMUwVZA zN1Lq>?4yAxlki_tiba_oe#SkQS-FGUiqjX#2Hc*oXafo;y5@5Vg?S`f4=_gjE)AB& zIdZxPC}*Wu5=<-rsifq9TFIBgDqm5f?kTw@YF(f9_vB4=sG4&n-eaYCeJb@>x~7Wd zVV`ago6#oZ6qV=>osA=}=ZX4;ZiBN7`{dHt`1tqze;?8!p`e{x8n0}2p1?E3Rwvw| zzG`HpA<^TGqwouMm{HHxEm*XYVl(}XOwPqWb$FLtX9T*Yw4<(<uy5yY$d{)U8vNv2 z2Fi!_9!v~BntspLOgn2ZrrW+$JO3+Yy_K9fV*?EU5b&E9!TNtIB2NG1FWb3SVQI&1 zwBC99f?g2BMVT!f-plI&qK|DIc>q>R)TZnsU_b{ao6$AYmlBiSwD)u~2}$NttaX@Y zfRB)I47`2sk9$`+4g711yVj&-w*7bQlVRACR8fuyFGI<;6=4-*^N;F-*qSs$H1*h^ zVksMSp4pmMDiNwGiFGpTy-m|MbYkrG!*EMndCtNw514jo`r3)j89Qh1!!`n4P<Itr zl-XKlu!z5LR@rraG!&U!aaHo=oZ$W9xl?vkC0Qo6xqHJ{17qpjiyh6CS{)Ju9m(xn zbr6^)El64N#+~wqwmzM$Wek+->qh5{OZ|$GfL>pH=%s&=Tdemp<_3fS8C<8i6LBs3 zf-7&v;6Nn)t}`Ayrk@l_gfwiBPqR#<e_J`4*GIA5B00~96V6xhgQo_nBg;lZ9ZlW) z(uHYuIEVJu17RIPL0ijcO^2DAu8l!`Sf!F<d4GRD0B!Y#qlQXv_M95;Z%b!8fh<&= zu{xQ+kUAQ+f{lKGp(%S-Ozb21t!g@MA>aeeuFWo)4qTWNfGEi^`tDIqxtWvz1X6Pe zJ|r+`9!Di_siYel9a^L%0*o4xX))-bv^6H3REUe2+BB>h2q$C;sum6P@+MSsBDey_ zB05j?i{^UcgftfaSz`u*KOA{@M)fH?wlGb`BS^U>Tr1V{6LqO}e!qJfVs(w~T62|y zmZYCbFC{j+dan0lD?)rTcYZMBGKB^)Oc`DHcgN<l)?dRp-RR2sJdw0%ODa%7gGdVw zi1Bg#p=Gv%qJJw*rBE|&^CKu7kF!8a1eCK4F<e!2g5k8uhH#=U8l}uZ;rMMN<D*{< zG*EH2NyGd?iZBHduIi$71QP%<5ZBd0FqCno*T#<6V&>ja$%RIOUn!{Dw%%YZ#T4R{ zSHqM}LjjR%&}c=7UPSFrOGg(OkYEZ}46*2=&;k4Z=!lU2yj92@!&K}@UC;z96z=mm z8L2lZ&BkNKfyTnz0B_>GIDsC^M^KTyl2RQkRfZx+M$qx;H#(hsBr28T;$&&|bn0JX zQvXF2=wAkM00~NlY9=6B%MDI0F29Gs&uS1d@&U8=TXBmpm}aYXuU3p$=`U;=ZqJSH z*YXGcnZ*7ctH#k5hgYdN9$=?%Bgc}<8KkcE|Gwqp`y80TleX@j122xJrwLTk2REd! z$wWCDn#9t^1%9lbk)aq`HRf`K6y|F2+mmlWMaBQact=|ZWw$=j9)vPQ!DQg(6qTwa zMP=dFH-yZut`(*ciSwvJgPXhzkww`r7+-rr5`!>T)YPa9qOT8+A8FYd;=-utChXsa z*0w1rU&GU-Mn;ImDXk`bh>8+4&ENdT8cUpFj)9)YQnpUqm2%UnYo^16!x3B@KoY)P zn7HheW%5tHmHz_VsR=zOGl97jIeBm`8G$yOYG7Qkc}Vkzp1na&p|pd?PW<_^Csa#) zdeKbFT%0I#NnCB+-Sre))p4Xn9vlxRDqdd}E_yDIY8Z(gH|*b3*p1R-7X}x=KLXm0 zq%JV%G&A$;7fJ<=LV!#>>@}DgeeF6@1XyNw&0@O`dv73uIjQJYds%9kyR&5;$@iFn ze*6OAUV=XRUQ^j11;w|IzHN?s&J=CY{7(B8TKsg!bdJsMqsCn#eB-%1YfR#=+d*pp z=)aqy0T)|?%G!@Z<HI^huwp4XN!eM00MhwIGw%y?g{uL2Im8uJ2EMv=uc1L-v=oFf ziu|R~eiJzDJh(C-5RurZ={bSzolYG}wf>nLqr0QM)M%ENg{!tiwu}V0tGQHl6KV3z zu^VyUAF;Dcn~vK2P4(aqZSh4`G5_{WZ=G>Jy$ECfs$rdoLry5?mRXi>!vy*-dV?wj ztBAhfWShvUxUZoR2}LqhJVm?0haZKCc8QXQPJb?>tP~zOCPQHc@%Kvm?ji6G-&KvU zn;c_4%fAFDa&3X{^bL$oLRtBduxkG+>PodC+)*xGn)L>h0c8hj*VNQyJxB5hFPkyn zGiEwjuwQ&yP?+Cp@My~fw5h;Mz3Y?lp1k*-8xo<(Z@>Ke*c%Dwh6u1>%$%f5UmJ#N zu<{XDosvi4QwRhmMv3Z?>rVAz&_ZkrdVO~RHXgaeKW6A~ng{HGhsuWV{&g>!>)7<l z^bEe58ek<Ia#*_{JffFIj~<#cIQ_TN`{=c&_Uqhp74J1!uC^{FF&MlQ?4e&RT6aa2 zt>DULTwktL7eV#h@G=(k(Vk}PPyZx#4JrH8B(>hULc%x{)fJgfT2yT`yk|q3{x>tP zgTXFZidPRM`xJA{DU)*vhzT!#V8-OooMVFq4;!NAv=>@!pG<1Yu7i%>5cFwpNZ+m| zejhtE(%AaRok{UXap6);Lcj$7X*Qg|ah3zQm<MTcz=a#tr%g{4gV}I4D!0TlD<q~k z6k{m6S49MQNfBn-?0UG<M>B;P4q1huVx$R!lTy8AA9N<<{)?P0@6Y?)KuJrEuW>%7 zcvX2<X*%A5zvUR4d?gmh5v(jDKVe(13pTTAGR%Am&=aKKO0*9qzFluSVse1fZB))j z5a^cw!G=y=-lP1j0K}CW{JY{EfgB1*+_#OuX6YKNMnnlm(a|(A79K;{0rG(W4(z9x zM5wvnjAoSp&W=CPegAdTLu8d#ErmE<zHASr`p}-<y1A>BO7!?GeGGxwJieiSMs3qj z`XquUlc;?7ht;mWu-^a=Z!Bsha9aBoL2wftpi?cJnTBSzt5Rkh2ox}|y(EX2fJO!9 z>_BTrpYMbBIwmWShU{C7^_PAdjkPnz!3pGymo0odAghSnBiljS`7!$yPhB>QCbG_4 z2bz0{qe=TV=UmsU%U{QS^TKI*21U1>2(q3jEwHUC8esF0MB;^4moE$&*ceW69Dqt5 zC6tq1F(^*?P`i{~^jc3KKZ-o}SWZyLOBrs4jSdvEm1t}_-L^f4TP)O_DqU@NCt4xM zmzfZApNT#Rc@s$c90X(?Y>1}O%UbYvT~OLEjEAPzgR7^|7yNH~ks4u)4!DF3yVG$b z=1={8(M6@&EeKY;44PiQTs9gjoULY9mA5}L#h1GB6c{R0!Ea$fV|ldxBy^4z-a<w| zx~po@a#m*XK&B(LqR&Usz3iKW<yuWx2HtyQ287k3JcW^Wk-B9rl=azejQBM3>)8KH zmZP+nSY4{ZP2C`@%FydZLzp+3giL)>WjUa{2RZtr<2R^j7+veD6|5ppO!^D}1fEmW z4tr(v35`Y;$mR1^Ii-2Ld{>W;QF-@=w;Eg`vWSh)VICC99H{2<jgchH2@bqaQB|M; z2M?m1W>8hOt|85hzHJ!n0!%NJpuHY#1FVCIiR(!}0xpu2FB?4j3~lOz&~EhS_vgC~ z1S>Z*-J(2P2(}<8jaOJ%{YEySRwxWxEQR+7iH|?XFS>0c#ES2CSReYl8nKVT0+SXO zi-O(>qmwUE*z_T=@u*F8mP^_xh0mHuF3tj1UcVd>K0YTBLTx@1S~GEOiqojQM$#`0 zCI#MeoT$-o?3UrTua_5YbeaAU#ZYE3j|<^HSpS&-z)OVaK6fuo?pydX+V~+A;}qMb z7qpFL@azb|b+Eef2;WQX34)I~5jaYa5zYxWQa(ZX*yR0>9p0MQ2_U-ZAwqf~wzGRN z$@|hjX0uVAantd^Gs7^c$9jSuW!2qR*p^814<VX1!^WpO#k8=BpBx2hXGiz98!pKF z9W_7ukFQcFuvWrj_}&%gxf9saCiKjgot9^HCUhaR@j$r4HQPIKm_kXg0+3LkrS|0x zJwz$SEj->W@F1<VH)~<!_tM0-a!^W$+&2TT9^XsysWJK~1w8|tFHhpUMyHz^EkDhu zHU$UtKTd{0sj#R2?Hm&UXiNS4PUq9V?(zRe!*RB=veh^Gozt!3Wo!ls{@XV;5LrZA z6FV<Ym(-r3I0rSeV=M(E_R%<c4mL_~DXeE~-Z?SF09KzRE6$w6=~I&<?2|^u#;0;1 zuuNL;6nkc(grx!kWvZ*<G8pGYOmczo@9(>qn@2xSiMFq18D6EYz_=k%U~q`ch!Nn( zd{Bi#8|dVZDJ7iaU9Q+ulEJV%Z`ax}Iy0^iKY$?QLbS)b$@H+w+{GNU*L}NT+w}i% zX{nzD&kwBS;9VMv>y94aJ9q;=fo!#B(5DR3l;m}>zCgDn2`+oOqO$QJh2`qEP^3Dc z=l}%ed-*E5@k2Mb^DOTnSkZE%2w)tV;hUk1$k*rlPx0$M<zcw}Hw_>AduoLL@86sM zIXGP-Tf_fK!&j+a{Mx=qKi540c8K!Z>yr59o})y)&NXAr9am)H^O~0|{sK~sQ_(c% z;^k$Ytv_ETuW_Yf5!-v8eYJyWd)z*m;9p@hK5B8&$N8H$iR+c<zI|+oXHFWb!A5V4 zDQVf#+gIfQH*V(4`iIf8#jN?WL88L{PCb&wwqlYvBsPKkgR$095$j1rW&b>*-;|Oq zZCe?)C9U6bCs{B_*-wlaRUO7urXJJ9hOH_qV&=m_7*Xj~>-^Td{XL4IvTeK#3f_EF zQLO&=7gnI)#Xa~ubANxZMgrHzJZ;M!IlDW;f))x74|c~n`w0y+gj~OsQ4uY=(plT& zI(R|aQAzb#WV{E!ehq`No0~trU$H$g$K7yvIn^Q!6=;)_yom~`?tZ_bV@lDU)-tK- zuyhg0Y{^Gm0ua%uu`D*O#6d1`jO4_!-pNPy@zPCj_h8FSu(W#bBm{HXd6-HzT&>{x zYzTh_l8zZ1szBJJ^hik$W)-5C-F*=#YPzcz(<%j3+7hX6lz8OkGtBQuGCUKx;RxiP zp|d`}9cdH2;uYkD9de$O1$RX?bz}62Q4@I&(@;x27%DQzX%`4*{XPIUiI1bl^ZUWa z#nI8((A!eS#lr;Otj1#_FE4lHbCNi&5n|=@TbwM7DO|REKM<5UZ_Giq+9ns=tN?A% z5r2+PJ>6a6>~b~oEt0a+HcbL$Q2MB|)d%@atf51$ZOLJ;ClRg&Q-)Z_X;r5#fGm}~ z-vDpVSb`X~0z02_-?QI#K7l`6?hh!y6@57YMI-UTRp)3hCnS<W+<w{;3imDr&`Q;p z4&W>YHL<N5v<GzGl4ZTIM_EM`MGr|jx+OgFCjru)4Av|GieI0_{QRydE$SXB;?b=U zNuvxdZ=!kBKslPobxTo0bt}ZlO8K#@(rC~G0f11ZlgK17lSxaJeLjk4t)SOY-)(pN zHV-@^tCP1}rka>j3ak>g&Hj;Sd=o{FShRip4=0iTpNOllL__$1{$$`Mc*(=Q10K^E zu!NB15tuS>0Ha0}+}}to-t4vK;`<-(LRo5)=Cd4tiNSh~s$?~+J3aj_YfxC_dLnno zv-E<|gey0}4fe->7*w;7nmCH<6Co(E2}QO{N~)L?lV?0i#*AMW#^<wC03;4N0{MEY z&~dSG7Jq7X{Nztz0Sp)LO4ZdROUw19#b9NiA)`eTE#PvIIZiW}E$gx<;kanM^;_by zkUzs^BkaIIq`Y9aZyV3}gq=gU{XJxhU*dg=ZCjNMTtoAu-=XyV-y4>}x>5xGf^$ep zKtAD$Hz~;xlL8!Mqq+i{3-JpU$^&t5U<RRg>GUTgaUM1n^Y?&<$Vr{O=mah}F6!;t zLc!(4Kq*M`(~q=Q502x9E9!!90`Ww1`3h-kmU)Z}zs-O-YjNrDJAX&riOkC(%;#y^ zE&yStQ$gml)C>;^;Ol`=z0!6UiTbH~)a2rknvHEjS&ms#QF^Reyw(d^WD5hRI<L*F z#Eu$k8z@7S$hP$N4Xpjq1*2nwq^Z{b^16)i)Mjm?6~DFE1sA+blrT%*qd0u!GM8!S z@CY)vQZ`T~mYm0BqcIIpSGIajkItHm>G+DVqk?yW5?)1g#^v)7^u#0#!yk+1CFbR4 z#Uf`TEVM91IS~-KDekebLSU+OrhXvvkxDtIE|vz0Tb<Isv1scD9$n;(7{uL~88cN` z#L0jmv4%w*eh=OL=bKpMPi6{uGFxnVd(9x~-NOI#ZN}pSgqLBk4ib-O){LNm&=82G z)cYw`tBS;mNwE=Q8HIO0@&w2fIh)#zS!`ailZk?`g%^Rf#Mh?Vf-Ar78YbStZie~p zISDB(3yLohJdGLKht0<t-d(qP@8jXXwd?Sa;}%e&9dJiRP#g3%#_Ouzh>r6f#GXq$ z;lD%0JKU4L{g3U)$!N%C%{6HOdZC-i<nHkm4SFDAn}U;h;0ACtFAOLn)i0wLAQyx3 z&6`jXqaXrn7~tODn6q~c&hfy^1w&BW6f_qw4_ySx^yl`2d_!U>Nn|zD6<=0j=(+hA zWVKJ;(V8^s9=yjuQw%+8X2!P0hv(yH>LX`ItINaw@$)i8cPFQ-i`)BY|7ecs)x-Jm zb1jk>>j~TXUu9#4LtXA617=W6io5ihzL(WfF0KZ51;l5ntxW-^btu(ND3H2ibX-1o z-klsL18{7y!hEXhgIwW+#OG{66NJ$7k?2^v;FU|IWGB)egR&*AG-ph&dwVu~^Je3G zX?s~=YE(^u@~FY-eD<S{VMHFE2|#*tucdn9KUuU>-Sv>wfXn*-7O(=fnK1AcGCMpW zikS%W$yVX*s3pB8woX|yTwSaxthAu;E(vdf*O1f&Oy`=T{#KpB)X*+(C7!hO*$I(P z-Iwm_GklsPSy9{pQv58%OUJ5*96qkf!b$OkyV?sXaOLvHE6iOXx|8}>pM}|x)HOzb zMNbf2`-&NhI3iE8RqS;HVVTiMt`ksaA6TlKQe?FwRkq=p?rO~$a{mgMpy4Mv<zCNz zVSA(oNQh2iDy~^e(6VA0kB<a}vy7Lyz6KgbMo<x=T8Yz?0KRDm+XC&4Y4t@rXRwl8 z<*HozFmU{V6=W1ves6_r2|UcA{=IEkv)f-TE_l|Dqp^(`MN;2#rM+YtA6Wyl0c>V& zdB@iTIsPa71Z|<oeh)Y-fO_nJ%aDj2&M`<CRrX>a=F9YFyHh%@)LGVVF#^C-GK5T? zI~*gG11@oRekc#e8g<bf8N7sSS+yKf^p+Oc{efS1wWa{VaUoXV2hC=pq#a6J?7^^H zt##=J>P;^pPIm2gKJ@J!GCMlDy8MnR4xa4Druy8A@WJOdi5^cfbzjp%(dIQ(S5tnh zRTIzei<bTbE_}q9uTer9Kx}693KPtZRHO}iiptpd&qfhV-WI>~)2Ia>6VV|nLR*KV z+1UpomMfFnyRVO^xG`1}=*l=N<V={m%xRMylV3c05t8ne1c;9C8w5BG)JWb)roZX% z)pE$C)NsY^NYIBI@Wse#lAL3ug6-s>TfH0|-3(oaW?R6DC}Iap2anOW-9d)ae7>Z; zS{aMM-C82~R+qL)zUs3<YZs#|+~eh{?kI^sFOIN)_d-1mW-XqiR5W!&Hq}fH_mwVd zn?`^kj|OtU!*<V&wzq$4h~c9{Jvr06T<!<_@}57hFqh|(<D|?tACR^w<_Z?s_rFiv zV$1^`RF@Ck&IP`WE!-6tNvCgLNGW)wJt*`a4YiP0SLL#Q6f%N&{@?zc9(yf;f5173 zer#CZ;Qw>*lew8!@<0Iq(3J-O_<j9n($B`k-1K+WJL0yCJrH%+IZ=IduOn!hz3W{2 zu#;!>&w5zr&BTY^;5eYiv}6BkDNH9qW#wS{Z|eJ{Lab+P-s}?sNm#9tqQ1SoeS2vs zb87ZRSly=B9?M8Q!ldOURN-$+xowF;@~0<dadp{86U~OnKcS^^XxP=q<MNi5MFH*9 ziw}#_^y_Kf4QXwjXC8vp-AU)2=6bx0ZY7iRrp>=fT-6yKMi^X!{FfE_R^`v53m<vw zmX}^7);3d2-&C$&9u`NSz*X2RvW5%gf^b57YTP+#A3N9a-7BwlXV*U4jS1HbXrv?N za!x4sfNG1VALTxpTYc-1t`72keFWc<+saRSwqB0m6$<zEBo=fRCJW+XyD!JnFAm(S zIxO&DTG7C}lp_N=<wb4}FRJM1=*De{hRQ8TiUc20{_uOOVf--l8Y#{@*6AJQrE$P- z!LvEAmEOA18>Cv!7xnlp{L4otxo8fQ=^fSJ%ID#hq!0gcXjOvt3SxQR;o>4Yj<YU> z=|T0;lv_g11PBEvF`|)Z<m9DEsr=g&v=Hi1Yiri`_P;eNN{ehrw|jpKE|DEqi+UHh zIKUQyQf>XSz8O{bN2&&?amtNY7B%b6zy;)xnJBrIzM277+jG{NT9bfK^O0}L^Ulag zpRJXpl2SQ`rsKd;3$Zr>LmC&(NNM#WToQW6WcUSEV#S9D`et{=nnsQ7Rl}Z05KFvD zN#R>g{g$1Xa;v(5jVyqK381z1EGWzEadxF*oa-nq<9e(>eyK9#<pL33vo{qT7D4KO z!CnA7A(jo#fJt^DjI8H^J9QxiTkp-B%q<JzXv*(=m=$x7vv)eEZpwa<12>!88uUgD zgv%JEqI-_ujrA4S<zUIIFW}SCw~1fw)jKmuYA?OQnPR*E0Yu0%BEn)ku)w2DM#V1! z{u1EERW~bd0eZWxU7&uO^3W^VO%J0>qr-c<5ah$!VB8Zdnfj<i3IKt*pp<;nE)rN- zba7JIG7#a4-R&;p_4YU;%B)#J9Z;`^w&+VfbREt#aGxOeG^4s9j|6E_q382D?&8h6 z${K}Fimw<Z-BWgEW05r<Th;x+7M4)E3Dtj`9rYV)E7q5hgHd;-*F8Ww`ev*C8S3Uc zADT!&U)4*=!|~YissMkrf0<Kmj|Vz-J$`|<ZA;Ss1E5Gv`uqbwLMY`Bb<oVX9ZwUt zWKKPhr}qx~QE)XY=emn!XZMCT>xF<|(9ENUmx-y0+XjPDwrEqtg8~>%k4K~yZU7Q* zjHa#P*RrK-_`NT(v9hak4~ji-mFL7xr>!G@>O=^R0#S>?VB7homkS2Xeu~%tL#FYn zXi&Ntc7T}Y-WMmNjls3N1R-4+SFuZO3(u*g!NQ9Kp((#k{mh}uc-n;9fTWu~2XXA= zu84e2IzeWP8!6`1&@9>+t21D1$MJ32h@W3b28tU{H13WEQ&4Gf?VeYuC{`V~k0pIl z(S>;k9g9yJP>0v2YC|L`Jn==qHZ|~s8ru<qX;vI0Fz-ftl_+bBJ6N(>l9|NV6%S0s zEAHK8gHUZ@E<1Wg-xxZ+;Ms@WrU8ob%c%5Fjb|lDkdU|ljB*ovy63U?b377?#}lrA z0r>7QX6?QsXaGK7Xgev=>p1cdGS~bPk!-vr-yJo#!bJAvI$F5}#+@GHh|CJ%bi6ml zf=*#Z658rlM4B&-hQX()`lG8QpG5?8VloxzORaAP!g2j#4IE&m$Pz*o_rc80?5Q`# z=1pF;bSKkDC~DA~#ERfBb<nJ^tUEVbLoOl-0d-fc&V-WKlN8NDB_*`Pnv@@P@df^H zs9B);8Fl9)8+1t^U}1w@It0Iu2UJr*l-g2`P$O{Cr|`3|+Edut-Lv%1dm%PAh^?nb zV3_~62SpKZpzK?XsX605<n#zM(I_O<V4Q8d*mAgjGRcZfUyWy{$(?BSBG#5`Y?nJe z11=!ceb9dWlks^;tw)WyU{hcpVHi2<?L!<2G!hHdffW8EdUzlFm4!7666KD_i3nM5 z#VS^wP9&KYsxj3&8+DB+SXTQjteR(VS!)wQPeT%hp2C?6=QJo{1Nd1C;&5z6YZ!nv z1Q-Sd>hTrXDFtaWe~Dt5MFi@|9;0#Ejlw@4c~JWH7-psoFZ~%V0%DVfp*krOa>+dR z*>~+qvn?=;Xr)XLw!9u!ql#5s!OS2i4=IvaLq`1^7r9kXa@=7L8<YkuywN4EZ9-Cl za6)r^vFqyn11^mV(7i3urT0x7O}2ez5MF4h49x(}6H4AuZ<2tJhX6M+zj#52-%JZy zZwi>I3ttD)I07Znt%&gmAX+Cg6v&EZ5NKLVC>U%=@uPyfwsan3XjKqpX0U|z+CboY z*1BQ?jJWRg+j@WsX<8I;qyf`!9t!$`#ML;*JZphwQ4*=aZf{|fp3q)E#D+Jdj+?+# z8*&Sh9B032jO$ojaNQS!j03nX`#Q`tmAHurGWABLiF0a3X-GL_d#_FK0jd%Fz^+#; z8uTw1elSz{h?4@-!abre=KwufD&7ZOgB-)ksN5*EUDL%T;0kE!<B_wag9?mnDx^@6 zZyIgG?2<P*AsmIgMG<N~BZtS{=zB&T9;o`X*|=@kI$GVRGj6dPGzw!gD9Rqh0&CWm z<zVdeI59S(W(C-uq?d@M4F*@2`8ll?e>xX?VtP@#hjBMOcBvLYy9>fMvlN0yonS{% zL`-z<pjAl@L0}m*DYE1-x+#|PGrsn)X9ZJ^9!*p?^gb>FF<%j8xImkB&o6#Ix55MZ zj|})N=t+#*NP@7>L};6jmVarg3zSpLuv-Q&c@R#@V_j)xE}e)=ntP;juI3-ZA^1P2 zYZ4r;6;QfwhV^$s9n$oGv{3SUYTMO$_iG1rd=cDzI-l3`N>gbA5iX`(c(S~KLvqhI z+Rhv8h5i5fCgoZqVKg9Jl;Y{^FIxjp)qmISQ*)SD_7G#G@GOtWCGfyU%egckA#zZ> zOJA&g<uWwq7#l@hiDq<6b|=Lk*k8TlsJPBB2ostXH15%=n_YBDHfkCxn7L5x`@sX& zlx<1>dIGch7)3s9`(SB*hZ}Q%aaF(L$ZZpl375S!_ss@yxwYm6U}y3N%Xj65K^PY) zs;LojMjC+oBNrchjUH!ZI^x((zG<skN46&)woL>iq8X-|u+hv?nO6`+S_^wptM*O~ zlUZP}Vnh8Yi8|V-<~a=^vi17Qa!f4GpAXG{-SzVdJOTWdFgg&#V8{?*^-BA1!0I5k zFaDNMGLMb);-q^z_L1=)!VWNK{v$KaL*lY<FFV;pRyi(6Xhn^ULE#QZHj*6dma)UL z-{004jPX4Ao-2I22Z;SG?;T@eviny2CEQ`!t4DteA^ZKS%G7HF<?BT}>Su7<kQI2; zWuEZn2}!S)_l22mA8nY`tJjB=9G{1wi<<7Q{8j(SMfo2<{fImLOmh~y!&Ewdu`|CN z+!akeC#43nWX#v93lXXXX%fINa}yvY#_9f$D%S(B8jas(qSoycb3Of{jFBnP_dH^t z60k*L;Fs{k(@h|z{<NH-!s6F5+k6$&VD<B*L<`3gnz%-`P*U1wRE|8r3V+U)!e%JL zelJAoFa*-4@cwTz_L{qo-nY6kLn)YI31*e1+eu_yA01%k<W1y#Z`KC!+p#QXA;~j( z{3fDUnh^%RI<)%nVmgmf%*%(OIPI+h@V3cf`-cxcW9W5z+4KG4UdVeU3z%}>Ppp9r z^R7aJa~RtZF+(laYXvz$>_d}sAm1#v$yLmA)my4Cawke=?dMW_2=MG95IcxsN~aJ% z#Pq8Ugp3~V7J9TR+XKYb?GSslNN;?j@JXtTADYIy4!}s_+;2Mioyp62j~FzJ7*Dcm zeqp<Eex~V#>^0u9g8lOY%SRe9|GNiiFRF8i=tZp{${T9ZNqe#s2D7P-P+w&>1Cx<Z zE|XJ?q`Y5L0Tsc82P*<K^y4@lP?$GOE+7B&y8{C@kflhd95MR7?$E^J@@Q0EPzK1c zz3UhXfb~Q8v4hcS%7gJF^dd8mZJIvZnn83XkBn6-FW*LLIKn(J!=s*+bdaR|k2D^K zze(B%l`}m<$pAotZ|9@E2X@Kba{6-R#O<r@wLSGevCf_`KPl7JKJ&Cw@lZKR8>I7z zij;~Ab;#4U)J8+O%fQ-D-@ZRNd&=z^l8cf99GX)0#*I5I;FCOW00G&G{M>UQN=tK; zx$aNMv#*X9xki}6a?ARr+mb=!ESwJWP9tWiga%=mzG9x$KGAjAknuCNyjWQ>zQdWo zgbboG*b8&ZjB+5>wAehdt;=W-DXw0(M!mb}0GUv8Z!r-X`4k$-Mau{n6A#lO;#r?z z<7;qvh(_XH$j_-!eeRkPfK<e0AK0#J8y2n|WTe`AzSBVpfM%wYbm4i>k~IS?g<O7_ zdjqQ%Zo}NE`ZnFyAYs|!FFyI^iT%=<eoF({RPZ?^qrsUi-7NUM5!0q3^?d%8?ToM^ zL1$;jL1*iQlduVv5H!9?4mGi^rw^1_oot#m9TCi^ROaQL8Cep7S#qf_;IR)0FBN5+ zY|-AIxhcJ083N5tIs?pqc(O+>y&Ai4n1yh42lRxu^EO{B4vSq_H`?w_^1kdAE@>y@ zNiJW65||HeaN2AtUnv&8%yCT`Pn`Pb%0MR8woLaMeEw#8K=KMjd~g+<$ycu_R1rpv z2`u&cC{NNKsq2YL`?l5w%XAUa=@>+0&>oZ6|D0kt4m^>0O1{2fevG=^gUrLIRry{I znYCp5l2&I|?6<WKFBK_ZnxNm^0qCYi4q@(38nPWWRji~UEmGh(7OUVJ&Edf;gchxq zbriX$1a|D?z1<;VWLRvn#lh}JVi5RRY{$JM5H~NJ2~(B_XSg39>$N9&%kuia=o+^A z<tOp#2afc;c5`J1Gr-LR<uR`?ppkf@9!da2EZ*2t$DqYMLgvg?ka55{)%9h4Hb!|V zz`CY3bh&xPs>YYF*p8yO#gk)XZKC>dn7WykNr;O%1yJ!mpk`Ju>R7sfkTZc-)~}6` za(Omixgs&&%9>Ee%Lrv~984}YZU_Vf$So@_$&(&{@PZ&p{6^K|K8m~u=zkDhBM=9* zumQY-AgpVOt#rX;yb$(ck$~VJ(1pLygcO(}ns4r|P|>=188`7R^{FeRv9-mwE^R}x z*Fih-fK}L@H<NfnA(WonQWe9o2dXnDihm-&%Z{^e7N_Ce$f+;IL6Z+{(1J<HMMf1= zozERVt%#^GaSLlnLY2RM4%G=)YM4*BI?+r(M8-rQP&?HR-<uKt#(|Zz>!I;J*_j;P z0EfE`*WM>1N6-eMymaF)lj}cnlqS*#e$JF(LWEHA;>pYxsRB_#-i6Ydm_%)Y!ow`s zfKmKtLQaFz%6Ku42xtd2)6(Ki?uC>ML?O+Ij|#T8_ci1?Lh(BGorpaTD}=;9y+)A8 zJ0}Qqzc6x3qCUy`Cgat+jW?GWm;7EwM#=MAygiI}gw_sm4L48h-4jCQbkGtV-}(|$ zZa0@IhgU{nP~6_Au%o>lK6edf?tC}X-10(EUo==Jq{fG->sV5cF)m8Y`_*(Cb!rxA ze|2TZ_m=U!Tf|UN&E**&{(0IfTUkLysm+Hu^DI=pT5w79+mxD<d`s@28U9o%CE&6H zfGP%I#W~hxCpP8w*)rO)p%Z;b29Hy#84xwboY}I|qO$0dm|L;f%@)0Or19&#W&R!a z^|Kq$p}1nz2<U{T+~>!xP7&9<sVKIkv+v{71>1hC@24ARAm%~nTkhNTWjGeVm~3a< zzis|`M;-2b&c7~eh6eg(QE+_c(dZK=VvUsWp(9f&52E+sF4R%$DiM^-yQ})WEd}E= zgsNhJ*82RrQ>fjc#-(r^+1uOCx2H_(3`~Y(;A1wAvO{TY)zj|vKUI_v+X0;JD~sMz zopbJ%c(Ksa*xwB+kq%-}`D+0}0wqdmVn_);7SBcHtn-{s!nhnhxALS$^EI-4sl^>l zU^IfVy`CzLB*`F3fg?V<6yD678uIAg_}D-(_qePb=Bw>BgxVN#aJ#7<NW%T)AxOHm z=^^iRZq*H$z}#2c*+E5LSbFJ4w-Tr9ZBTkyzevJ?2TC~{AsQybY3zO4-W3%`u47X+ zxKIc9YV#;DlKZqTftOfW@|jS3=;}euvY!<!*&?Qp(UAvC;5R1Z^ny^wvmu+C=vFEF zq`fXwo2EIT3aX09CUQcvOP9D8u@d8hg;)duLGceCH+su@Qv8l4^?+dUQ`E$;)Cr8P z9o40qde_Vg0uI~n?{oCbKjCVJS&VrpxSP)eVVAIH;jid-<!(vt(C%cXaz?A-fWfbg z1>Lwke6U!+-IF`5e+1v|lI3rc1<#(r)a}QS1O`xpG*@3$0-MO*g#dDaZ}?~g-5Fo< zflc;wE$Mwr2@j)-f^=Jh#EwHMVole2DSr#ea1sMb;>z5)?^%W9>d!tyre%8TG9IwF z`DTZayZk3?X}%9xl?WZ9y9V}C9z$Rdj4AYmV>kZAI|yHmuM+Td0Zdr>4ZQ{sa>jXj z#p2?I!5z4j4Vbxj+Y7s%plBW0_L1L@adh5)sJCJ*I0-Z{gI~j9nr+=w^B{$j*`LXc zW6cbLmFQzM?@1bNQ{Bp^HW|c5Ro{leU^r<DNQ$}RcCBx2*$*&Rl}DYYn!F=kP<ouj zaw*Z~RBARC_()bv%afEiUL8|K&8-}xmOa&-O0?fnnEKEvW`W#&M&?B;pNW);Ld0{9 z`;lwwk?_K0R~uUr>KHvBlQ3W>;9YXtOn#}3VXyQ=XV+>48hvvji3oq!p{W>Q!#^<Y zNw6kh{A}D4upF4{WIBwKV=%!b$rR=cBl#ZMp0i8ueH;od*UpzX4G)%pwxos6xJS&- z`UajtemWI=+j8iOvDvetMmAk6D7?P!<Nv2tiA4m$nDOiEm;90z(Ed}aG%~i+b#^kh z`c*4~6{lh{=zlqFC=HkX1jg=uk{r*V&$T?l6=p!dtt`zf&Dcj*u2B*|XObe~7@plZ zZ^Jwrkeo+CFp?j|#IBOm@`(*Ny|clu%(c<g6gqp7KJfZ~@eaFk!50&s07pTF3TtLH zT)iDnft_ceoAk;j_vG(H+}D?u0{2}}=&`Ux4f@i1j8M{&L6*f9z>H;-oE8U?iLuw+ zvD-*<ei9fC{R3)zQ3&MJlY8WU{2OWmGY2KKBFX_nqcjrHK;CjE0m{MqU4kYdnDp=2 zCZ?_Qg@Gk+tBlERD$kJUrC4ue3G3sz3EV+80+XeAxIHJeBIR1eHyXp<J9L)EMLc^| zP#ThxkSR+bNw1e@wDSK}g^--Fwp^doI2Dg^ua)i{(c9W0OTiZ$LgSYbe;GA*Qdht> zC)hj7)Am9YGxsqWo3bn9<Myj94@tj4os>Gg>}Yk*7;ynPwv#&h9h}rR?c!;68OxiG zN15bqu}#&qD}TL*@S)-@oouC4s@6tlfMpRcd_h;|oTHa(enoJY4n5#{Al%@m?nD3Q zb$(%LLIr~Z07Rn#0Q^4xxAgpboyIms|D7{X)BUeb2H%yET}7t^z!B?}P#et7s;hY- z{&WxtHm3_H|Af+@XkiPIqrs2I4r0pq`Xn3R<k01Ox1SpySMqI_U+=$#bMM+zDychf z>Q+rsf3?fpEq+n5xp05|F@(*dNng^DGOWkV7=>=C=9=C<MRn`>?Ln~_mt~+yRdYa6 zz3x}qM_<5ZL08@$FSlJy(E3d7;q`U3ckuXZ@OE=_|Ngj3`*L^wo;bQNoG~GQyG$S% zb6jV3mt8(I6x^ljGV*=as&kT<7l-22VLHfhs8z$Jg24+siby8QB+c=&U6cQfG`Se5 z<Ky6Tl4Kb`!LzVMVMs(|v!SA|2vhaP3oPs+H_86(1mKed{1<MlP?vtlfxda@ZXy@L zH<j)o0b<=pNa1HbP`>%$D*>jvHJa@Fm|nHu#F1ArEMa)TM7e7~t1K1mt%gH-pse%3 z7GxPf2Z_4W&F@8BSjQGa=D_{r!G>-EI@z$A()`T4wp}q4gp?ZV0tY7TE~f?Pwcxe; z@5Fo-sjF-J0g7hyL3u}cv9>av)Y_>Tf{}W;wc=GSOm9nQT)&i&TNebDU^->;QF4{K zu;7Sx@LVDjig(aeu2UlwE8bmY-4`O%VSj$){kBea%+NqtgM;v4GQd6Ctq=kYjyJI- zO={BL#o!{GtjsqaX={arjsv-PEuou>`5vL`-Ox&p#*QvdP2hP-HlY6we?gIf3j2{z zw`xp)&L+4M8Jsl*Jmss_r}tZr6exi2(FCY?(@a;uF7P>8J@&F>xX0M!AL)CuUc{(} zAAm|UY6cNoFD5<l6HS3|r@`MOHj<_QB^qG4R-(hgW`P=Gy7D6o^NHy$XIqypOB;;4 z)ZqXwQCB&ZzD#6?R+f6GzP5t&)0m{r<I4KRQD32q?DzzzzqNY1)B}GfKp{F0jzyoz zNSZ*c2Zc#+qCI1^1YJ5(3;G*rit59lPN7KR-O(a7M{EDaHu9=727%RS(@4-^fsIaC z198~8R|!46Xs`Hj^uboJ*N^E4d;_0iG;N6yP8O5yg<0ppww>cB4uE;riG?Gy&&=Fw zB}FgNY?R#9y*x|nG<+mDhh(m@<4}_>@jA-I6oX!{<$g%dWUkXc&8V>y*w@jqF~qbP z;L38R@oWP6(*fx^v26&?e_qH?xKulyZl${e?`!0U*cA{A2%JSYOaGPrr}=ldfgsMk z+XTPA1w$*7&cKk&Bk6Y)JW=Pg2cR3i6m$I=I9)aXE#k3{qSL>7%%lr}C86$%1af_A z-WpKC_`&@&k1trl>BzVFFF&+$L5JE#nl+lc$%MMn)u?ReH5zZM3+e-n7R0AI4aQ%f zSHPmqVn-JG;-6+(Bjog<y@oV^fSVlvu(-vU{NHe~E5a+{v6o*ms|#MM#5u-?tUab7 z9~P@aIf<jh(6#<(*uHfh7QbC502UB$2j&`+t2Rk*eNVv%G)QkwLf@(JqCQQ|9_TGc zD3kLD3v{%_;4-2jIr|xtHzYE&EZmFBFzCJJ?IMt3Vx-2k-wBM359B6Zyz4g2t-p9z ztV;voUt*W)wZ_M_p!E1B&TUl}6GIGEvn1~h{<ZgH*WRo2ltasaA@;V23q-XO^g3l? z|7tkrk@Pa|79`xMI*5%pS|hcjZv%PTAybufj@YR>SIcD@Pot^6m+j^u1QxXnwX|WH zCpcDapq2h*Na)BqcOO%5Fap(dZ+JOM=}|T(!xoC3HGAozf-{3d9f5{zCg(rY$*i_$ zjs&12t0ndR`V=~v<;d)-TaXR&$H%fw@Bnu=Ho&YP-0aWJF+*%|Z)H%$qjlex`x!)B zu^`<#_8Ral0O`;;pmT{%DY$yDidt6sG{~&w$?;MMGhF3X=Vv&qlac&CdINP8=9kU# z4-H|vqAQSv9JujZO9+N%!z=0308DDVZ%w`K@I|7zEEY@8-P!seMThP2pw_>~h6-CS z3S29PgSUA5;kOD3k2L7{Tes;~pve`zu0DWC3~EJxw)F8ZaqxM0)N!y#)WGNF>G6Gj zL>cuDml442Z|`|XQcJ4*^S0mSC={yjQOGk)ebq=_#~P^O$C%^kG`pRK1N7SFkYy*1 z5H?;R+}hmSt}(@*-d5Rw6)1WDZ6YFk-YCyes*@$2ziPk$X);ECQ~;1Kc^xg@s35xm z({HjxO{aO>-utt&vwJ=<XYVi1c`|uC-<ct!f#E{zm+<zlm8@V{)x%&`dA&sIp+w|q zxCn4<tF=h_&-1IvYxdk3gNU9u=Pl8nGED;EFB`rgq<LlL79!Nacl1x0M!4?bQc-d^ zZhmQ=6x3(XcI_uj&^&D)F7X|kE9(3hA3vZhwb};lAJA$NwL%g>+U(90yYpc-6t-q_ zt7VA#8BVY)?3$Lk4fwoX0AaG!lT`tI&Bd27!&+60!8>fZL;w^~uzv6)G&_w@?s)K~ z9u=yA|4?(28L>L-l6}Ce=YuuD^SN5DON<8=w(_PKP^-D@m<@OyjBos7{S4pL)q*D@ zF+n9>S<D_E#5%DZ`h7#RICe~4kvax++!A{J*D4g5aO0T+69B+iKLEgQt<rydxBrI; zbLDNFh}{x@>-rS|sa#HI{O2fzJ!yUO7;h*6S=m5>bj)7y9*svTpd*pgG&OCn8YAiZ z;|bdj3~ZptXs4+9dW}l6gJjl>87taH=)lM2{+2{@aiYGRd&*_&{IKP9tm~~)t>)z6 zlEyQGk8-1$lFmh2UG?p)%k#)YlTBM?`MJeqXI&TD(6?gCv_(V-(Cx*wX+tY@_^S=% z7Ql0BdilxtXF%jizg&)O;yd(pqf1%IcG2|pXL5gyMcZ3p<)U?NUhDFYbp^TH&+Qlf z0a``A#^p&$aYaj(^(u?VQg!6?<chO1q%Qlo6Bt<e$`ub-L+OfT1OI(f^UZu^#8$gz zGIZan6;$l$aHF-o`SI(NmvZ$~7Y6<Uv-3f2^o{ZD!=TTHL8Kwi5Sh}?nH0aXGF!&$ z!%Fdn_1l1FqR^qGO5~2u+tFrYq=Dsr2wQDFeW~>a7Q4yZR}vq}r6x|;DI?R3pK!Ik zW_L%yP_vpAdP=XbYhy)5k@=(p94wf|v|jC6aW_MZTZRGGl;7xW)t9SsrKZ$FT1Eo! z)1Vc014Y~@AHD61X)Cj)673d2%_N_zvEjbS^TkHJ#&XM5=a%)|4PK*+wsuCBHLMl; zj`BvnrdFD9%~gK2%282?)<QamZ?h$Y=|u6y#e}=zy2lC)OzpYXbk5AlL8lyR3s8fL zCE8JWP|*~*m@Cq=AKuF~;Em~n9^AoDdsZeAvZg-6fbMVsxwFcWb~AwaKWA0rj4Bt@ zt3pIaJ6}pNkYYeBKic<#(bw0ZVW*+`(}*?#Hk&CAQZp+X{zrj={0ppiuk<7P53h8d z8fsvII<dBXSwBLbVg5tIOI{&F2HpN`bIJ9rR+6l;cK4PYtX)l;ChPMIB#kM5KbbiX zdbkoj!{`S(Q{6-4mGMe_c0pIL{lfEIz6AnVaiKwIFerW#^+mTo4yW=dVKf`wuAmR* zsRNo)NyH(+Yu~_!`(7)pM|{jHbSApRCl+PLqh|K@_>1V)U97m?Ncu#rG|M6zjG7%f zwWJl!+BArL1-H;E`79%kZ`|l$_Z5hDn2+n5n+sOazDU??V6_9@QK3OJ5Z_d*F`@;k zv-!bQhK$gx9hA#lxgcZF0qLespnnEo)|p;fQrOMBprRp}4Fxk&L%`FkQVz;jF+_;5 zfb|<wZ0{-@y9f^_8fbpL-*R$#UiaMbkR(mQGac#PquPftDg_Wo5X~?HF|S?X2o{HJ z)-iI>5IsD<?Nb}0#%Jq;BcmJb1P=$H;vd4n{a*#xWL9waCX}(^dCZPMD=o_kWj5Ql ztXV}GQkGvDG!s#y1$5K`A*Ld5t<K0QDxQ3f_r^*PDZc;4RtV3ek!JxB3X(yd26amX zI(`Y})^ZuDsXh&7TKT)P<T|&}D{m0jdS!ZYWN$?K0_8qbR>p<P4#<=n3&Aj)PD2FE z6M*_37sf?TM{Z+$SH$W#vdPU-+6Wk1fFGOn#1OXGAj^X-8?#N9pixa2&M|w7t>?9U zX%SZ**{rVn8v5_d=<s@{c|Q%+G$8*oqh+KaSVSuL?WA`a2=~KjX2MxbHJ`(s+Qua! z)VR*f2%6d=M49>xxMqAHQ(E2d;+x<Es}ZCcFu&`b3#9E_Z_RwmH=00_OzO-FWP7uG za3V|2VLER3@i@N5y#Z#-5<c9|_;R~He{P^-RyzW^z~QlL<7P26<9}U%V(q0aPIAxW zzklD~=z1i$p`>y7bCl3z77$}2rYcO_oeFrS^O*ToimnAldCsmnD*01d5i-O{Sm65P z2^fQ9XNIKsn#P9raB3r0uGGy6*+F@5k2o5fn}?kYvoFaDG+N`PAy4T>uF6j(#Ywol zB_?*4Ba64)4b~KBKmCYX{1%u1?v8jZQ<Rp9phr&UGt3IXCHe62Dh!XYRGSA3dHfMP zmY%fwD44Ym-DO_uht0WosM&eva-G-L^u5NlIMW|FDZDQFE4`XZ!&-uAaYsR4kQRay z6@A=W%Hs*)t88bit?gL!9SU&3qByEIvS{-fi8E&bc(m9oWoq2T`xiX*G@K`^$M*>x znql_wMxBxJ17vKmLEQwvc_AjW^@)@%$-e$mfGhYbXW&|u->Ch%6`T>=C%G=iz7Ub5 zWgEE&O`7K~rU>q-ozcv<LP}DoZO>nlCVW`w+Zh%3)b`{r*zb=<Tvsgm!X+4-G(^G@ z(J10PEX6e{R3&iZ+rvypIZks0#(`>uEhS*fCbGE??3x0zy?tja@V>J@;Co&7qK$zj zv7Q}&0-5U4L$brYTvT_^WiRBjvYK<r_OkTSUj5M;{g~TyeXY@d%FW>0AVOTCvc4fJ zh|tnXJ^ANqd>=CS0dO803PWMtq;7H(ZCh`~uun5W8DFpa{@pG?z_q)@MLl9#2eh9} zI%J;P+cAkRB$lkAoQi4Bo-G00@plMZfU6*&<F4p#LPSzGw4%xB*aJ%9y*sOugj&d~ zTz;LJK=%TX?_ZjO(&_}LotYfE;hfw|-(NEM?|Jk;(_=vRJ@i?ba?@@%+@P6k7#otb zzLxz&Xdk_d;DQrv?tqNEx1;K(=Yw1j?Cry$dp_olv2xX7{gFO4g%>mL+N_$QoW?(7 z5#{Tpz|#e4hfg1)001n{BunJA4{zjN;uzTFVH4Jp4-*hguHZ47&*f}L0g0LGH}LDK zTE?jy^#0de7PAVxrQUd08Vc;c(or<#lGHkm3ghJ2M{ns^54^9B09-aVT%jUZ&`j-@ zq9&AWa=<bb2Br|97M7%*0c!<Izg!6n!2`$Lu#M4%BP*SKscO3a`o{JUMtVBFf0ec` zE4s_0(zIc?f{*&@qS>2l%*Lr^EzWSN@P`)t@71PvnYk1AN|}w$2H>Lned!Gl9jlE> z5Cia<&5;&YXpG@0##kY-gjC}4+)&h_gB~3Q?SYK=wi=t*pyNO9<<NOzG#aRC$Xzt% z=L?{FNE1KuNf)R{rRo%Z0W)69-Hd7ySn3?g23)gV@A`a=b=`O>A>n}>g4QvHXx@81 zZl9;mwFkZcXYuLxB0x}}X0l2myUeWEj6G&xgT2RhKjAZ8P?=FbW%xrYtXU=w2f=bw z8W5ZkVk5v*RyiV~I1^R0sSyX7mgW;?u;pfoX1z;4bKp6V&NHB5CIlMTN9>uUSH|L{ z=Bm1927_JXW^cS{GF3r<f@U*%mXFKla+_#pf`exmRb!(gkXzd6#-)0pR9p$+$2yZf z;tEc&S`g%a`DyU|Q=&Wy1>tOHNP?yn9JT0~uXr>cmJSPw6>0mQ3!7!M^I@&L>{k;J zx7m(?3_p%2Wnwd}mL}yH^<~uQ$S-_Duzz}(pazNdMsb$@f|!pm_nj^dsr`uIx7cEF zFLVzf+%kW7MM%8_8*Ar+^+ipS@*UYUh)De(vd$?wl&uT1v27<Ow(XqQwr$(CZQHhO z=ft*ccDmpG+pjgMUe>5J_O9CNo74RfZ}da?LBJl?g*g}m?seBqwpWm;SP2FhR)2Q2 zRz!3<J!3K5k)(VJd+tPxac-?ghs!wg2||Y&)>aLZ!=|0Orv+V(HD7I4Mo{I7bR2o) z>g(>*vvSU;%=1A<Xb;A*+;-Z*DQGS&udjG0V%tNc;ZJ=>LBTlh$_DrPu<P~vBkPa$ zbB^3cUh4<h1B^ds;g2ZyfygHaOY(`~$sPeoJ8`lsy{ENrFlJOT9?4|NB~ikV^A{-E zT@C8R^sTRzGt9c`0}YniXzoM>e9m~AO4A?tPTAUNflQm26GvbBPu>Dl_G1+Ky+h8$ zfQb%4-M6_VA^0mvC>ZFl7RisFHpQ{nRl@-JuuL<3$H#Hsff+e0!EPvJ&ZY_4l_$^( z@bf%zS(HEC0jv+aMoz)8{}w#NIJ`;97mQl-80aFvSoYu&z1QQ955rr3)6ZgMUSJYh zvrTeL-MnpC_zaeRU)C?p(S!iAT8RYp2D{;9^*;(vn5S#V1Oiv{<Lg=-<Y8HW-1*7# zWD@>`ys&Xd)zVR@_boJw&W=p6rad#;+~eEwVgIlP{>b7LBqn*v_>^S-z9BsQC>NhI z>v*Svd2Ln$GU?fV&+5#=rYVR!!6Fg6>r8UT{_}2V#qPoFg-ly$T#2r%i@7ntZaz%l zg_|i`%A{}ZI6@4<t-uT%({fRLd{$`pR&p|RnfI`3Is_n;aYL$OyWari3@Zd;y0CTA z;xTn`+ST-dk0SsAk;O)jRTfG%c1$YA%fj|mba+a6leiZab(tJow%p^gBu0s&89F)H zSs)Qnj+m6jA+cRNkTA=doBLx$8fZRYI|_@l6iKbBB@GrO>N57@?u>0@I8C@<#dOc= zcz7Z}pvMe?3mH5U`7CcY)Iz-!uG+8!l2Uk^4|VKu+JubZ#qa>0EfddAaDC0HVssdM z3(8SbQ|2jb!tJEK`r-8tsk38BZ8ZGWg7I*c!2sAnOS|`;UG&3EK*zIIs}!0mS%d5( zIB0!Tbz^lHZxvPaOnDt4M|+?myY#T&G``Rq)_keuStoT?#2fbi%)Hb~yHN4cXjD?& zM`C=9)B%p|70b(oR?+MQD)OZQQQKM2*OuE2AQ(y{pkG^^?$4wsYHw$$H-=4E7_|4f z4cq||?YwyQYYNkV_$w4L$`D7df*3aP6_I^}1+)M31<<(UahmKTOm?s4@oid0*6GX2 z4)&QGuCWsZ^&fhDfiWG5PI?GvzP^~|&h`Mcvkch6=&^9BA}Xj!><-VsTp<uQXH(Nx zwS9@(?cT!86s)45A9Y+lC!s@E{ym6ZWl(Z~fe^k4-tz`A4G>05)uKTt6z9gZ1`~o; zU-8+7VjI8yQ^CnE>kpc1&$UlMob=}@pD_k8Jxnn`DyQ5<Q&kd{v^&AtH+GT2bP6f1 z*~@s?K8MGvEvZVc(d*SNuHT4D-FwuQJbCn!26%caHLDM(Dsf!Z${Y<754z#P16p!2 zI?_QOg(;56Cmj)b;s%`+H56hNqJ{jAfL_)Z2-6HTc)!-b+JX2lQY?I^O8%h-RD?{_ zxHI&t6R<0Hy<f!x=&1yRX2ubWEVKZC-=NRInw1`CFJLR)hdRN0H!^{|k_=W_Q&y4c zA6hhp*qV+ji3o839ydARR)Gc4ZRbc@Ixw+Ps<LJ6`Ibj`R)0j85q*D6IVbB>$uf7n zCftheO)FBS3$vL|g6V;@`W3%j(~)uUN*X#{yV>{WFIUvM02NBqa0S6HHxJ1EzBLPi z)OWcPjyHXO4a9L`Z?ZwzA*|F~U1Aw}?tO2f4;+?M8It3ax>2gBwN<jD-=sHLrwwhW z@e)(OJi^G#B2(X1RY2CLf<Y5&S2Pa=K1BMeLCi-rrJFSiK4k+pseV1UbOg-y@zuKz zoKJ4t+SoQ_{w@zvKCU6Tei|%|tusPzLG4x9X8xJGFc`DR)|z|WJOhL&7i?WX_Ap3u zdcSGub(NPM!jg;?y2gq}6Fn!UHO14l;cBmMN4X7A0CDsBK@Svyus@?9$~4YL++wpQ zM=F^bbV01flYpQ{6mUJf9HwFikO%jxxt`05A09iZOmnVO$BNbHprt^4kFRXa&Vzu} zb=xlKDw(kMU$@6(IekX}(N^@?C{nU9_&~$>{X9eqn+tQM^$7_8RZC(yIRwlAt&wE} zm^73D1OKF7OlK>3{IP{Bb+4r*!K2Qu+Kf{<(gN!8eR%F$1sF<phC$N4xE$V{)w`*l z{~5SdD*22vlyfBwS*2cqtq2R4P|iwH2V~apflxs{167=~9w>;z_{fi4b7co-eb?MI zZ3;<9);X9g8BTN@wU}pK@htw42fUsiG%QsM_yrg}*3Uc<QrRs%B{jcjnER1dg0l=t zd?(fE_8#x$M09#M-18J&YFS*{t{%tQVKD_Xe~Qv@M|F6khL-c3SltnrkXg4?HYQwW z<K{I0uzKe%|D>iU8MkCo&G^0qG3zShOO@LAk&^%HrP}jl|Kk3A1ovc7e@@@f-K#Jc zpa;;AKqr#p6yAzK9ralska0!NUH@S@Y@I?vSh)so6QoM?0K}}nr%V4+SJhE4w9z!P zGyfmTD(kWNzihKn$g2JpMy_F8-F9BcmE^qoX+G(E?$7VjFSa>fM^B$0C$+u4Z}-EM zY_hpiy`JyKcZs96c!3h%+m?>tj!yTA5^|3XJS%VBw=|#x0k+PRaLjUSaHe#xFDoLh z@j}89IX#tw;OV(;jK^XXyA}W*;ir>tC06o!ayqOz`IHojo|D(6J7_C)Qktt~(SK6% z`vQu&PE3hXZ}pY-{D(bZWspXJU?xai8}scwm1%1lq{F4cpKrJ0RIdzFYq*wXxh`G- z=u5g4?8at6J7QDMUJPGQr-9p3ZhBYQJAYQUT_JnKwYTl@_dqAub<1f~LYRsfIy3aT zju2<b5;39rO)k5=8gTwV#Nn*8A++V7drlP$9db<Fzy)Y7sp^IcioiQiS}lCAw>r%r z%XFl7=p>~@c21m@9?)S0Z%fXAMyW;D$Z@G;0$V1#wJI{KU~1>yhiRj-k=n%qC((b| z7WLvv?-ySKvR@Tq_WS<y=i(0`n&vPqxw;JxX9fd)gt>Fv_~ORUo>RFCoorVrN#)lX zvD=-ZvcqSV)uKdXdBX^qz9BpZPD`%D%j(sV&q`fCK{C*p{OM{@pUUjGrdBuE@ZiE* zlNG&#WzV-$sHo!(pKAs?&EZk(r+5FPIsIolO9a83+TJl*@E*D&+)W{xu#i+B6$IC~ z?QAFYri@w8+k{ecD?Q)j^?;5Yam38Jp?=<=w@aQQym8<S@bb>w3AvBYEgJ3%BF(V4 zKEbe^9173A@)meci`ZBtdrSCB^Xt8(K*z8HvDb_I9RMrJi{o8Qcs#Muqg%uS-Ln}p z8K_}NPq-w<$y__4-q2y@e5!2&Fg|d#vM(%{>t_I|6gem6B$nVb<`+QdZF*4wkDP|# zZAQDQM>!8or{=$-RAWyOsY`KNnmt)eLWvVbibX6wAx!ciG9mAIpRnF`D19(mj2uB( z$uIo<t*#c>w8@c=EG!nFJ<zH1x>(VPWs{;PDjU9IAzw~t_s9GYAbouRxAElBR%r8M z&C)2Nx_rJKn3eD-We=+mh_Rs*ZIB<I7Aq>vFv80&gFR#aF23k4=+bphYGDhUt_Y;w zR@6Zv@*I^uZA}vf*lb8oEtm2Kl+21f8hi0k6Mp}@vJs?+`6Cz<B|-Yu^igX!zi8}E z0}3pBS9ih)_mZ`Zb1_i+eGI<!CeiqH@sG$^EPDF`2W(kySAz7t>f}AGyxBtOGhz~6 zJ~Fusy1K~$__UBgK!RXuyR?XfBcF-HoE!=feBq3^I@%2Yaj@|mBmfvCeKqvp6X6S7 zlqyNdTFYj`d?;d-`g1~HYc+#Y=l)9X_h$QLNFI&<r&|cY0r5)V3e5r-|5LeH{gN_z zao}^WvNI<{VEibIRQV-YD8G~aAz8+0g;%N=*W)N$*h}vID*4MN1q|>Pvt)r>O-xl> z{G4MbeQT;=VeAbq26IFs$tX;1)-HfPT^Hasm+&2Ukau{zzJUrxTXQ`5$(raWG>1O% zU6}Ufy78I5d_+hYhLP*>%wl3^86w8~r7*u{G9A2L6cu2Nr3(&;=sYPR->E;a5(ni1 z7%nB1k-3n?GH^d}y?DLD@E3D#*H@Qs6!2cTx(0@5B$fxfiQoRJ&K#u2l=1h29S6H3 z<2KLfzjRR;Ng5J5woU0!0{m6g9lKU~>QF9{btGCfK%iCU?{K2l!o|z0(*iTv2;VQq zR?nBtOCF+EeW&ll=Tq?q#TVyQc#Tpvyb0ATbi&2w$(JHFAtOdc@y=<NZTPqM1Z}51 zk|qh_bJ`9cKM4)Y?p$$eB4+ZI%j6chb#+~4;y4eg=~>Urj<Za$a-7Yf85>tBlsH1$ z<4-c}2eDHs*FP!Vq_;Dsc?bdO>@92|KlpW)s<f-4XYGpcrr#WWk*DG`%w#gw(r6Bq zBamQ>g~=74f`5eo#U2s?g0o{EP9ciZiAxT8UVIzia!xFAx4Nm|FI#Tr<To}fz68gQ z3hi$Bvn}9~qFhGTieXxf#nr(tlcF8_sU9<T66Qkyw~@NnFb-_}dG)+0=~eCYYSyMM z{rek}n4u7!0d{c(<M5zHhIu8r(%gmO$Bem5QEorN^p}7fIJ2}XJ@dQx55Yi0=maFf zVMu~mf({&Z2K|#YXJ*0t?P)sf=_kwaXIzmPL%zyFwh*(;;a^h3N&?DzXpZqIr%2D6 z92!Il<K`?C82?^TbyhZ|LA;kf*aq0sTR+kWWV$s$`0~o%U4tU;nK<yCiA!A+WBzSD zX@i7QhSpLuRde~O2O$9|TB(%tkT)XDPm*ASt+(eOFUi8-lvJq*0E1H1Mu^LfsVIU5 z#W94h#k;&~SS{#BM4yXNL^u7?AAq5Pv^B2LiH45bfbs<`uHQ|#r0sb624P27rv$Xu zyxd?Gzoz^mXF-A-9T^$z&7aj-Fx4R7?X0rM#Y<j$J>EWY>60foCovfspakoIs8D@C z9sLKO`{>ti4g$vW9Sq6m_)WgaLITU#Dwt(#>ls>`EK3GK{BjQk9H{-d*3mWgLFzge zoKY6bzY)XR!8nXG$%_Xtq~D_QQa}yV6kwLYVQyezZ}4+DIIyq13WLmgtLvn3qBDBd zIrcupshT4HNkTu`OHa5GJy`n}KVg>aG}(z5&QUkAL?}F?zXobgUU@CZh`OR;JAc;N zY4jQJ%f5&o>Lv%&iVMzJA(GgJFw{<o2LKn`n5R<UGR7L4xuuQxR$Yd~-?0Ph-`qVJ zPht2P>=YvreOYx^>!7zC8#o^C5O;8M?_s&`2=`IC65(K%W^cC`pdzfw#(3J@RisB{ zRzbuRPt|%hqchKenBkiqb@qGMUtkB)iwKp?aNcKJPoCj}E6aQ0&$++$R$zaLa}{45 zcu%?*Kb3$W|2UTJ?ZT%%#~aqJ9pHjVnnxLOc7g$rpb1Z7=JoxUA{pbIkhQs<y!G=6 zAvne79(+;H`u4!ZeYNL$hx!<ClQ54GjRQ!}O!+&4UNASYOdNo1DJX*gcdkgghtrZY zhl<CxKwlB={5k%MjQ#-mmo6(2q;!a8YYk7IQo0_`TqUsylX`lxeMQSi0B}!F%#Nua z{I!XC9MkLi5q11UjE<G@A4X3)kZ}g+q6_2FQ+2R+PK(AJINb5Tc=v=Bnj0M;Ai^L) z?qdhB_9Y`W5ZhF)wVD$Ywrus*)W5D#=0aisN+c?-2n!>fB`;c9|HVx0WLcT``_9Qq zUEFX0#QU~<#rP~>{_qn|Ifc}V0Ey^#vJUj(b3eno`N5Lbt&cDfjTg^72@oHSY1YnR zR8G$<xU~EZzcbh5?!SbpxwJ6Gnzdc;p{TKrW=W<8k=~~3;gTV%$|PvJlbmy_CajCG zg}Mn~!Rl}m7o(sb<ciV!Z_J$d_=$~Hl=GtNR~CX_cFnRaKeLzcCh~GE1-;Xz$o~E7 z6zImK^y*k6hXra{iXNC!`MD)<e6@b-FTJnRE4r}mu}4yp>kWRvrG{PQUYVGS!e_t( zVmnO!xeF_@gO&}ijWilJkgA51=&;JO&_N+~^&gM>_^fkc_g`^5{@)%*6NFy!YDZ9V zGaX(veS6cnd?++0AS0~80zh7p=t)k)=>&n!IDVOCJBIp`B25V*mWBm$;&T&Z77T(~ zU!aq=#EvU2CtRrgZAfvCA=ft0Qo(EmekVhC0X>pkh7|FpEZ{P`l$w&x;3iWbl8`R| z4|fN~-dPl>8u#K3EY?KjhE--n!suTs>;4T3n+eOU&Vhi<5`sT!TbUpZC$_;5L<VX~ zeK`hhR5$|z4dB$};)c&3ZR<HYsYKL^rRQ~ETZ2rKc)M%RKL^1+a}HPe1a-db7@oJG z^RY8chj-B@__P3+THUSmBTsevqI^Xc5f@|j;Y(w6T4<at!a>2w+Sh#-pV#hwU`(b@ z%7z6`8M6HYg5E!S+goCJxiPZSjfOU@rB?L0*#@JefJT7u>ZVnpAPt)D8%xPS9nFy( zLFA2ab+;F{<!)*@ybflW&S`$}a|Sm!EENYwp;!wSaAvxJn)*V@cyU^4xU1VQ1pR^S zC#Y#4MP>}j6nusV%fNJAO?eK?X+^KE5YzYM)d@_Au?{pcf*VdVwrg4P!`X7u1lYCC z9EV<k0<_Y3x1AIj4cpCYSW~^t9g2RcCKg^V1gGV2y#!X|?sYtyJj>UutANP7RfLVw zxZR;74heYW@O+ex1HTrnUEBhpsWW3mIvAZPhgLw<Z1XZYiNYo0mbtghf?v#-u?QS2 zZdp4g6)P%}U1DQ&(#)>b278wb+Fps{=5p4Gv?P-9FV}w6?^!~d{O|+n+@NC1Rfej_ zq#WbV`}{G+Y#$gTe%PR$G5suB;$f<zqx;%>7~l#kY@C<zx<|AtE0*H`I)gI~g$B6Q zxclZ+Ke4kp)<luvge613AF_=NvFUVbQ~J)jYPsO&DJ+(?^ZTd>>volVndT&q@4ZbK z_}%K#@NrZv0l|^tdIg*!ze?wZsZ#5#{5%Mq)QOghEs_-4A#A<8al`csVMq@|VJH~M zFxH+<yzNSN4Zo`1iVI7L4rSMVK%z}QP&EWM<DnhVkqd8r>6*p9ZJMqt6+@K>b%@m! zYz@Mf+l(u(@YdUm7DqNL?G)=w@0^$_0td$)@%$TcE{n4__C}(pb)CzTphFD(VxksS zgh-kamzl*&N8=fr52<Zgpw`tAq_N@wT7ZJ{f2L^F5JZjHd-9AqVE~E+BQqRRbg`I6 zy(Grji~fUdPy7>{-)(HJaA?Nh04-f3d)C=<5kQm_T249kV$F1&@0D*2I&ybOX=Yze zteLGSPLih0zb9kQt-bSb2{Ox#6L=a`zz&l+SzwdpO9@LdHk2LRDDBZl+_F)*QIr43 z`8q4r?dSJ<53F;wl=?;6^^o%dc|!wqL+iO-ibOpz(QJDF{sdw-hlk^Ng>QSMLn!YD z^PzQu_4qZX?e(LohzQp-T%G+%al!G6Oo7O-sX+{`lb<8?K(=*JrhP-(%9p`-SW9z% ziJ@BxBO*)_pToAS;q(4H>?~zEO&Eo6Ds#`Y$nt~2wdJ60Iln1N=6;J;yu-(5a5=J$ z_hU`2zjM}uDf<qLFz~5gIZ~fH2**yCgtv#I+YT8uJOvp^`%?Q-BPpN@Z2Kdwp-C2e zTPc6n*6$Pqtk!>KQ5Kh&J+wviQ{FS|7TrA>L#vHrWnQ<=?b(c@gQn(X1768qrUQFq z=oL9#)-Z8Y>}F=Js32PP?Lv^=H!kvP6^_O<<cv~~pw<9IgFOkFxpQluvZ4qVtq2Qx z&}>H{tg(vumlMcMx7GmeWY^A9o*dkltMG3e0fAF@R6YdZ23@tX04h|vbBOp0!6>Ck zl6PB#XbhESq7YnW3A{O@#@gg;VW-(i90M7osJMf9^QBb@T8nKiprPJOI`Nwn5L;8@ zsW%a|E^r+5l%wp=b&BlzbRT~y9_Y6*rS4<lgquB2jgPtSh*5i%+GOw<m$U04(`Ufh zeR>p=cxD3(gnK>s<Zo-%VXS~u^{lp4QTUc>#OM>2W3$?N3K}wVWT_?TO$*2*qZDu` zc*98js8@(WNZa~hpm~kvsyz8$@z(vr7dJ^`o1wssivFt&4$+i)y=>>-D4jI-MpN-x z_q9B1JThBmP=Sd?t7+2o)WC4@!v)3JH(&cl*5_HK#ZWkiVxztLkq_?c>^0E*X#u|b z0&ZtnH;1>$5lNHGhE{e5hJ@vXWENdu=m)kUKCey@ke%3Eu+&adlCj^y*`c1V9xPe2 z&sh72^EkF0x{Wba>smX<xuyC1*{(w)F;~I7Jd7amFaP)Dk$4u!S2HGQsg;cf@gouB z`x~*6Om%12xor@`@R%tm<qQd;4ywYXV49Hqzu?I6@P#gQg~1|7tR^=qZDox$d$2Ob zGb`zsO<78PBB0fruQv)2bu8~F`!Q3u?qMwJ^0y5aaB6sSOpott4Y8vfD?g!@D>_3~ zF02=KE$W5c4Cf5M+Y??}rOua28bXSkgNe#b1tQ7`M@8MrC8ZB!g$<8wu$C}Q+J0p^ z)hZ>C>tzs%MbF5Fjvu~qzU(D)1CcjGl^ORFCb0V5#<AYWHTVVAR45xS#iaER0jMij z#2>fI3sU(jkp&TX-75IEVcol;UOCFf8d`9L%-XIsK1c4@-!zJ<wyGWwY1cujC{b-( z%ZXEN3d4Ysg@Syo4yevo@lss)Rqh}e9xu{|yONLaW#F#d(MmPAb#QDrq{dcSj(vS; z&(eDSWKYj)-s_zf<T^b$hHyBc5;$sJCklQuWdjyG{>W3vkdSdVlJ&a|?$iJc^jL^a zxk2w=fo^IfZnTFx7rxYWWm8+x8<CSltqOGg;>u6$8e|V7;dX}|zL)%Lihuli3J-&b zr%&^cBBX78kFe;=S~sQr-e47-l(bac#qwhnhlG+);4%>><BHnVbYfB4kP#HrsRD22 z?K@CAax`$@Vz7VJOGyN1ZqY!)Tg!&*l8;gzPJA1MN4wNZs1%<m6*}^Z*7M`~R4Njw z`prT?C;My6rkD@X%m13GaWurFdMdA&-rND5o}zsJ)Xsw&n=h)_{gpq3tH!=QF9Go$ zmES2>s!5m_@#(z>Wqxfro#PpPdAcJ}Yz@13Z_t`MPAuXbe(tx=sCq-fO)}7bsmbQp zoOkKQvpbQ@6e0{qxFU^sCTm1<8{N2LHSX-wRARH})qK){qKAyRSEUXMJ)g9fX45o` zVN`Om9_6RERlU*Lf&~T{Gj*3WE6rVp>XGm`ZjC?KVwHI_X-U(zov%A9*YwD(u#7Jr z^)nYcc=*2CCy|CyeL1pU?KuANe%((#(hvIADym<#PA30*1QE^_JRi%C=ic-}uq8lx z6ge;*Qxkj0;JYF7ETq1y1RZXJwmDwv4{>Wmz{3d<r9dk_fUr}rtglZPl?D=ih?9db z(vpm1Q7WvdVVQr2eMDc%SHHSgOs0AtHBaQjmM~coo(LO@gcwClpE)*#=awgohy033 z=dKr$B)u4=Yt$sG6?3H-CGaXAc<1|sbZ6lKOph{}Z+RYe*c+QY?<jr;#Y~b;+O4<h z3m}MyEia>tsst@(7<GD*nEOmgURqkExEidc=Rip_473WkrKSe18IvSBpeT4wVG2`| zT3;28u9wk0%#<{FyHA&<)Tz@j0_Gc0EMDnd6J5V+#^r$TW_^hK+~4a-^of7;<MUTA zBAn0y;pNMAow^=s^q0S}9H$j)=h!zjb5n$n@X#2w|9jnS>=5~1Y&EZI?k;-c2Q^rr zOKy<(+#|HaGM@EkyDOrS{zJ;OK1iL%c>vX-RE}>G-w<;GSbK%#wQ?vIi&0JgR>w(3 zD!!$w0$&T)*`H9|g<IwrIgk%i&D@ldAKHt>3m*R`bG~nsi$zdjAHa)6x+6Ms@AWjR zo%g0T{081)X~N*kEm6%}{|YSi+y}GX=6s9VVmaNU59?=Woc5VRZXICf1NiLTo&hLq z$$q7O#4G{>Ll&vTjL8?{ib-YqU$*hn;E5vS+igcucG*wSeScr{IPG{(<Yv9T=k*<S znA+?LZ&PoZ-CIebDtLAPRT9<=JVjp539T0#PDj*ecPh0=R<kS%iGml16=-kqn!CYh zXuP82TD3BqYXN5@D%LQiUXA&oJx;<&#T&Z7LSX4gBs=6in^|uH=*-qjb@dPedy*2I z9aK4`JY|rlytVhpx}Cm>)@0~1%@+40L7wfI*^xK4LblWU8a44$uT%katcb(PROzE= zpAE_>otK<*-#s%Jow!^Jamh#7?S}2{Sx4WFm74U5YQ=U3&!r;t_Ei3^1fI1Tj9;vi zwD_T336g<?L1dD|xDs$_bK?r9^oEX<u6deyK!xsv!gF*3MXqT2e+GPo_w4Q=y5;YT zC8P?R3d6%mQd`c`zR~Bq?iY24`UJS*KMpH>EH5;eG0fLdv;{F|d438>M%J>leBUv6 zo;0)4gnZXU)$Ob%AD~h2!5(}$s%FsUj$L4}DG}r+10*ZteFl=LM2N!@PSnYfU}?Cc z!Qx7?BJNNbMJ!SF@^svUmNLlY*61}0vY>xL;@$?K0M8p^A2OcF!SAt{#mF?rF)X$l zwUHV(GkLRz2jDq&O*tfxou}COxDy&3kE~H&MEVxFFnC3MFng;n=@#HfF>}vZw`?fz z<{^Rqrbt)p^ki=MV3O?elCT1UfzMU8DsgI}@=yJ>XTtmjr*B0Q2B(htRkVtVRS&to z&sLCI`9dq@>qsBd@amoK#^)_Pw512Gvrd#02aqg|3PG^r1Zbjeg*}*A;<sNUwf%Bk zV5_2N;0_`X5PGOLQYdLTb`7s4hkFf`JrfLF*Yv-|HDK9SZ|+fSf3-0rK!Qk@=6Yth zE+_TKI^X&jn*<<&|483`UQpudmbsX78qPEH%$}jdR30miGulMUo)cVSmAO5>u{mMc zOicJ`2u59I+D6ieq2RtBo*xg{P9P0lFJ)pt^Va>d0RCFyqn5=La`zkqQ=MPD?Eahr z)^>2}8?$0VHX$!fil|p@#K_9jOnG?jE8)6pjPmpnY*~+nduA|HZ1&w;t}SONinYTY zGO7RTz#ssl_Zd~LEiknyyFTDIwvZ=y(cd$xVY?^cdxO3VY_uO25-sw=m36Ep=($cg z6&|+aB+$`W+`2WTJ7gB!0o2hy+hUlHMY-Him*g)|>%WAh-)KbVV^$Mj?6J9rF8B(% zkF(KFivllQLZ?m;0o~#-=XbDbkC~$Oq+o$V#h~2NVSc>Fw%Pg6^?tfguOqi{VFDN1 zCfYX;(Mp4zJan$y8Sy+p&$^YIqIsBtG4%a8)=aZj9$ep>yt%wdP+je6RfwCJQBb^_ zX5VA663TT?9NJ89n6SR&SNgncsp@%G&{_JdpNJ0(WJ*vvjNGy?&cLJGbEV|lWa(de z53Bt<>lY9re2cDn09gx810!o_ahEHyigP>ov-z*lj(pM!7w{+S4R&TeRjI=<;knz{ zT`b(b{%`q@0v+eQPeKcyKegtqVM|hypbY~p^TysV52bh{so$%LywBQ+b;+8ns#1fT zPAA2N3mNt;UrmS2Mh>rs6J+S@HBj@N=*Cxz+u_YC_x^Eg&-c}hZw9hwdnwO&X25-# z9_pHfXt>Gq7sPSl=p$Ip*|i7k>WP#5H_pcsUVgHbP%ESk=JASSU@758j*}_!Atl*# z&y^48QkscsC#<$l5N@<awgq}O3)jDNrEiwAh*aF5zZ(reB+cN6Ksk8V*rqN=ElG&_ z0kwmB!#BHYeUI2J3CYDexytah@ZI*GK=2QmbLO5zL9$?NcWoK1S<M)U6ay3B=WjZi zcpwKfRKZHavV<IQE^@luoyeli+38Qj1@RKYbY00Aog8>Ysih!%auRQQS|owu2X`0q zW)R3u=oCVi&gBB!0Yl3AmhQ4{)|HaMX&|#uA0E~jBhs&b8>j-qW&q*Cm9q7X*x}L0 zit(u7bWoI6VmG_nH@gd@gMn~&7!x-{ljMaDL1S<9aoTqg(?4$J??R3;_>0o(;jvxG zeb)=lCG|1R4&(_CiDC^Eam0JIt#eJJF1fr?Q|w`Ngi=Q#=X7CddZ?aZmN=d6Ra=&N zx?=F6YPY#Z(_-sWGq^2-gb`50>(pZrF0F46`_*-{s}Gy@lb7@;G`NGJKjjpItbswr z*LkTmcVq(WXDEV&ir;A@_W{39bz@Z`l{;^-^s7^oC^$5joi}J*w!+R=-9JllI8|rQ z9Eu_COYS{a`^3@o-Jkp@^*S^4S`cy6zMR;vFreGIquDo<3l~B7LtSo{8;<fAI(B6~ zV!2~AE2?d!RU_&UnytQ+Hj6AOJV>sRDJUcb*02@CvN*bu$WGX4*&R7)XD3rM2y7fZ zJ6+or7&g(^+IGp|v@qmvx_ze9i<4lw?=A0c9@2Ty|8+jN1!EWnosMbTkT|t3^gnoa zFDjt35$#`Wzl@N3Fl5BgikxtW(z{mA?tlo8uj(9jl^1wl?x5hUPPl~vH%*jmvl{Q^ zp!;5uid<NFkM?D}J}QOU3b5OYIS&cL&4phCPTwsAmHLQdp<!5nk{3kM*56TS9B&xR zs-SZOi&xCk)(co*x2W8#66K4*4~qEBTN?{DzizJbbUP?jMgs!LrdE0*!JDv9o6Jh( zp=IWAq%x^Y8j*c8=&0S9;@>wH*HQDuvkmfW4cj{1DdD%i_JnFOob`>83+GV3+b{cx z;Osorto<Wz$Ib5$k2-J)J^ea%0$txmuH3d+YfA0Lo+{*LdHw=ha;~iiePemnAHYO> zaa-JF)1BoeK;?tk4g&5fMbYyiJniS_vxDv^X>2Q*FgDdaL#U;p-+~sEZZ6?<9u{b~ zTVJ9Il$R$#a%e#MR7SJJHZ@yfs6Jf@g?~d!(Ez%KdD88N?OjP3QcvkX7M#{nUu0qn zuk&BAoc(MXAg$@@PtVM9$tCBL=T?U)+f5`bXdZG6MwWehCJ<Vb>HfwZc%(~sTo)Nr zXcnB6t+<EQ;qmYUFB%gjott4X-iP|`TCn}VBKO#OlEh$8j@QKSk>ZzNXHV2EVW<wU z9i%(D&h6?#^PqS`#Xq-7)bd2B)3tk%oqa}_|I31TmXz?W=}jnnqS(uRK+e9(Z|hu2 z*B!o>IA4-}hStdbHVe-F-n#iw4;!-@L|Lu!)vf-O8*b?_zg&ne`RH;*q`00C>c$*Y z#(e|=?wX><DtuDY>~1`fNur-NT>G`NM_uAzMo^CJlM$grn5-;PY#}A+BhZCTQXr75 ztw>mAYJVD6CsU5R(&W8XXM);MFa-l{eUWUS0x1w|mm&*xYSZE@DjNk#`<B)yxQ>6g znYs^%tGAs)aIH-)MNa|taKIIO`PWajdXi;4a|r3ZWqB~vf=V=4PlZ+p)wbxgq!{Rw zmZ%14B|+<-KapCUk}A0;N5xO!<+BKbdQy#81tDZ4XixDaG8Hf$5lb|*a{(^;N0!Eu zj_bTmC|HEV@+!d5ElUxzDVTbkV5J2eTs;Des(dLiJZprgLwWP6Vzryx7FqMUFAJ>Y zYB1e-J4MZ%Ij7fED3!FTQnGFi&1r47PTE4Zxkvom#!vs6?_(G_2DT=xlBUa76|<9L zJ~|+E!tYou>G8a6dcw4YH}0ObQk`50RL&Ay;qZxQV6aLoaYz*&lfXQbg@$B_+ko5k z#?1Eb5}8ZlA}D?f<!e*=9K@8TeTAgn(-XM{NJ(q&;#OTibt;}ZN0nqWU&t;+OwFKv zQ-NW>mQ4~1PXQgY6qw?$QS~xTDjC*upLgU`o)!s)r{qE*yWAi0xRegMEb!M{5r794 zd{RKvv_GkA_~)jy>s3#B-3YVSMMdssGCcCqOOU|Md<X-`L9faD?4zv+3R_hE=-(}U zOAk|Vos@pd#XS~UG20`I`+hIL|0ZiYf8>v0e}mF6zXI+5Kpl-89Bdu_Z?IPT7k~c$ zwAmcN!xhOQIC<JFTdIrD#C~ULiMjHZa}FOF1R?oVNE_}qo+aj3A{1=m<BpLWrBfqb z$ISD7Fs~a2(&WM+1MK{4gS>EmV26oXe{VA!$pV5IQV6=%;NMGW==)IlQJWY^+vYN1 zHxxsLv!wt*4_)`<jLF&6Dv;~*@bqEG%YFZM0mX8juZxOtxDP^W^Y;{i=<pu^Ij>)9 zNrjjEC1TYU_A(HIQ*al5#CpeQ{WD0F`e&Df!Y5d3yGk?GPwpzbJAA*kd_5Y$5n(WH zb_&;uuE4_lp)z=QrOwt)Kq4*;h507zQ|~FZjsk8D)jLwo%4H3D#@wv(wLYTgn9D}l z8}R>@ue~DvdhNG#{a^q9=>HpVGInz^wsADKwfU`Jv{HXe7ClV&1L|@UQk~=jVDj;j z4ZO1KzwHVr<35=AAYzGusoNK4Ai=zB!FG`0=f;OmD+UZ}9<`~V&z0zkI}OQ~HnZS| zLiB}t5wcdN$YqO<A?zExWMmCvb<-yRxGyt82WIu*thPo0-T8hbZo5YI#qN&XNBXS! zl|sf%Hl7ysl;%}|tp}>*=|j)zh<it{M_jm2x9=h?mHtj#L?Lk90%T^ben@mFt2J69 zu!?c=J%~4)fu5RKj_AKFEXp~euC}Ed#;?5m)E%pONwEtnZT~uJOck|lfh)rPQ0&~P z<|KU4uJuB&^3ZMXbqgHq(clfaRZQ8PG)RxJ(c&WcE7iBmo%*w*lKlzJZ5S&}r``_t zqv=#v>E+1~FVSX-=;mHMS5rt4QSeZ!jQ~k}Pmc4R<%x<pjB6wfl^M%}0TsCi6L591 zF8MHku#QBKhiaB1ygie1K_%za1C@zw5m4=iZauN<(y}>fF}>lLVMTyLF^IhCtpac@ z!lu9tcZB-qKQ9B4(7vgMIK`fKALE~HK>;QJRN0Qm5G5pf4qkl-qT28O3(s>w)O-EA zby?d-q-8T@rik+#BFN%eFBPD{Ve~UQ6w)nHNtJ*XzU6UO-CaYXdJ@*Cf5kxa5I3Ez z{&$zu3qD`CE~W>#_QgfE$deK{F+(sXK9?bw;T-nKsITNiq7ASN@clS}3|~CeMFc-O zUJ<ElSa#C0EIW3obRJxn(Z$RVwti-KDu-8=TbH5y1dw!w^pQBhT_2?3#6n;wNkFP- zC5frRHIzB_I0nwbCu!(iFTpscmX^t1pCm|m7|ZZp&gRx63Cmi3Af9^q!V*qQBOEz- zi8Y7ZM*DHf?gBIwG@35G!hMGK_#dfkd+K@M3Q<t7^4vD9!Qrx63GA(47ImxQozZ7+ z><sc)u!qDiGIQKo14G$LYj-u2<M0r}-;9bqwhQ*^{Xg9>N^F&w@=IJ;_|*g8{{P+J zU_+;?Yi?uiq^tYe6U{1;v74+gJ+rk0q~IIj2Po6k!yw~-Lc38SOHPX+V5+5OA>v6y z6B;d1zHUfJ_(lv*?8E(sV~p>K-tI`&Tt+<X0=aPDl96WmcgidcZwA1ddU5@74(>3% zdjmgSUT)u0b@PSk@{qrQ9Fl@Y=5m*smrUuiQ$?VQLsE5t@RkAngra)$yp!Mrpm#P1 zh?*ZBfh_~7c*B`E&8p1%u?{3@G^kD324b<W$tBB+=_Z%*E$)SxL&pu=oJ*NAV<xT_ z-yTEf(}wF_^{)(6LKcCV(9{DHvIKK$;2U{hTf`Ss>4y4|Qio;2p%y`M!vwPr<C5fA z#|^4%xhy%GeA0+q$*r6z(!UTsm6;U_Uf&Rg$Vryn2^K{0Nh99G0__M&grsyMwA%y< zD%j$?{ffkFj1r8-k<f+KGCEY*Nh{8hBi#1^Y!>aU?_`Nvo#-KBFE5LrlxUW@+>(@h zC9i{OILg#>gJw?uXn>#jNlgz6BrHFkK!26eDI(s4&X78|A;e_i3CK1w35)iK(Y`#E zqyVu=%8!u((A0ySA{;bFvE~qBE~q$}Gph{QajbjQVl-Z6rn%(Xk4G}@Q@OuMFkXk@ z?jcU0TR7L0s0G`Dxe5BA`X1xZKmVPTHA*6rF|Ci6B{1|GR<^AYzjIN;zZH}wW6s2r z*NK|30x@3=g37l?c5aA<h#yzfw-YY<_k~QtXG2_TT$09@K$~rClq<l+UZ9h)-5>n! zh&{w)k(9E4)bQ6nPgwiUNf7)9!sxOO>eaO#2CT#_Mlb$nunzfj4C5|FDN?tg8B&}P znZlk6KRL8#;7D8zlZDf~J?ZGHE4>+EJh0J?m0O}$sdQ;5R;W2{_pi1I!_6_^(HU+n zh0(`Ci7%<T-rFWIP!`n%Z$HP&wz^)E3HNI84Iz0jlNYrMv=(6jcHoYVkot{H<;Ztj zio#z1&XLX>>=SOZI)k<4Xqt23csGBA<z|JRac~dh2quv&4X+K_wJzYXur6aEUQn22 zzOqeD1Y-RRu<zP@Wx<^a-^1o)Uyb=PO*WVB#64dtqZ*q+lXS_A>~%S$Gm`LPoj{nf zEl$0oFzGIaF-F-~ehJvMQ}F6V6j>F?7Dr{b+yS;}X6Ib-Pe;rIZ--=R`B_FB``eHv zkApBuNUFa`7Pf9wb-XEuHhIElU5`((F@~3Mx*!0tJ<<i2ZIr{Xmm)c7L&M<D|1NJa zW3rYPzoOgCU(xM<^1G&1wg$gle5EF7yCL$6P*IgC1}0h2w+8RVKnNJHL%>hK68B61 zH5ZPVsxBvK?2H)texK<PlPEwT3M~k|H;CZkinZ-YUwhJ{58HkK0@WnqMn7^GA7-** zrfaJ~epRE?Ug{&Dsl=K<rH+~cQfbf{G^~D5=-W74A&$6qAkC2nL^rP=zhw=8R$Ib} zoPwhB3x~nG!T)7~Z}sgP03xj%u}vWnz51JCLaD_QL8S>H6oY+JOZ<-892yR-C{wT` zQFe*L*izM-a84JR@tO)V<PL(A03V#}B7t#t<w>Xq2dbk8W7b$z6-JzG3i*hyFGMSS zV#{nd{@qLaEDfdh73q!-Kp<~h00V3k^=~%IGeAg6LyuNKz%aSNcYg>jvivJ&HUdh1 z-@z}(fi{d?Z0WIcPbir_mBcW3X@jo_gg-&!Bj^r^Eq{v+1D%RSZK&eEAZ2kdnR0=% z`5gto%wGYeI0Ge?PAHzuw6$ybqz5*MwI8{9Oy+~Wv9)b`B<QZz{0czE;vg7zCgXPp zYMw_ARhpdi?@uOSBj>k>`d<otX^!BiL|$!)YY=|xlx$h?zU}X1T0pRGM85RqV{7hb zNM0IG!a*SR;ej#m)#I#yx=ZChGe3#nbfnpql>2YvC^6Y`D}sggGs+M7Ysbjec)}8( z*I}X_F!Uf#15|y^#g+kzNNLf;icsZ^7(+^_!CIa!*>}@xg>#z&2?=`XjQPjOX|UlH zWt}Z>A$n2GS><mTJP%E?z6p@)>#;t6PHF8#lMCKkLPwpC2<E7Xl!tq65%74(0ECwl zV3qonWUOe}ipEHKQJBd%-?)$PRf(DJPrJ4`LVeLGY7OACnVcZ{aMQF9xm=l>F1gz< zagDEvLOYq-t|+>{{}gAth1RW-&A9EQYTFvzyElpm04q{as|;yR#I>69=W7()8|$c& z!g3$(=H^~gPeJw-7TE|wNkOAf(U!r3k(>7<Lb-HJS3bbbJc<y~6mcX{lT46f+<_p+ z-7PM5mUeEqWd$9AuJ~j$X)hI37JoBvokm)4{RKW15L}%N+F^QHXw>U%UQCR|CyckZ zm>JHZju)6LV!C8c>AAl9Ry(JJ+O$ZZvWmMRZNyOFgzA~(AMN?2Pe{<N)6@tH&(FcI z1=|5L4^bx7t%oTg3!o$yx-I$%S@)%pqNB{t;bl#!(PSLUk;$myW>|Q(KwXy);WF2r zt)`WznIDPN;Bql%nR~52Rf3i;T!Jc($}HN6Rxls7W``%hbrAa)yc_5j7yxci$`^?p zTFC}y2RxDTXqaNbtD@AH6j>a;AS^eFI0HD1Wo3hcV0_7p`7;j6e{Q69hK9O%g>dk6 zUUj56Q=P_us|@w6U$w-TZ~>Elejn*fC~V_7;iS!UJkVx|nN=yu5mj~u7Xz>V6OVCU ziUD6~?-9u!n?52<CpEoBX<>`tT*vb9ABb2B#Cd9Yy%@euef_MG=qUG^&Vy0|y)oed z-DFDqfUfGlP!?HdZciv$_K}O7qY?HENmiq`*3dX@J1^rc)NlQ}F}0mV3GOSx$?e2p z(xg4?o3X7kodISNdZ2}O-x$poC5U`*f)7=S9mP|ZUH9BkV3YWiOKYJq(o?YwzD>zB z!uiRX<^oswVYC(9Nwg`nxMohh^ij@2*~4e$k}8*JV=#KZ$#MqymQ!@}`!HXG=whVn z;#ykV<=B)p>oZ9zuDs~J%XTH}N%m&NK~)DUgFlgG_+Qe+EaoRAuh|-4cik?TII77m z+2X!qg?U8@Z`#}}hHZX~<U~m7X`1TMHA8W#QylvrDvmC}xueT%T7W_>UB_{&7_Sf2 zwm)k6ixm_LQ3cGYGu1}PUnaDX%y-~Pm4MXpwuomLpU#G~6_N_C0qehWN1{trjtx^1 z(3>qubRky9Fqbi<OHa+68tXQ623TCDf#X?>RBmf{-0-x<E^n_UE%4skJ5ZdQo^Flm zF)55WyxOz-%U<}A@Bh?5$(}!yIAMHjZe)J`^Wli__DL}t^}ERf0Q@hK$<*1LhKZ5Z z*v<H|+t*8JxSidL)w6*^oRtIGih$n_Kwv(vK$7`_w2om7A$fNsS(}i!KZ4oDTyl`Z zPZg-Y(bAF8s<?Xl+`2nC(uc0Q^<}x`eo)0ObuI{Eg3i}Z4%>1mJQ7P%3a#O=YnI8B z4RZBkyT{l2$9*r+ab}8}>0xT>f%}1*X?9A5uPu<t0cUhDx5R$aN9O0`@cYFV<-5W3 z^G~KH$=7uH2dw0F)*Jsp;l;xWi}%llG`u(4&t7QHOZScB+l~iuulTplcj3-tZQE?( z&(=+?&*5=ZRaAfwCQr_7I=an=ZNle={;%X4{o@-JGvKA^*x;V93%;f!9%OYxz-M%u zEk5zGJM1#(<tvtVGwkh$OlylaM$>@aA!H{Z!$^zGl-UStf#Vt$g8JV9sTMdqwB(W} zV6P%OElWJv+i@0H_u}Ir8dz8z(M>%1N9!)q==2x(`=js2%DV6Ls?$Z;r|geS3f>xV z|HnfO$lq0!Z;Ldq7)@u##q-djQ1%)IUAn|fP+wbZSnwxK+vWbY!C<u<0lLN;Y`Z<* zF5#b_-k;1L3o&7T1PAPO5Ys%#o<sFx8ty|PW+nT?d0V?hX-u3_95kzpt1Jz9y|Z1D z;APB!T-!Tg>HJ(npN1lW*63MkbqZ{B(FaMBam9djw8+`s1<BU>E|Y^i=?nVms;H7x z=6is@vSuvFs+`|l?YR7nm}P8`P^)UcO4LS9N?0xLt%&t!YxF7pYA(%@RQr}ei#&e6 zxYRC%IA~jZ_vr48g|Rz+wG0Fe?Y`vXO~MCU<MjzvK>})DR49}*f3dCnD^N7O#f&*% z(B%(7R8W=H*l%iRs^%6eS_F26S3+hm-f61gKF3=~OnO7<Q}Y!0S!4|bz3RIKk1>cn zuQBd*$KX&6)`xT|K~%4jEct&5T?!KdUU`2T59Aa*z(@6qK8tf7qEkSNPy8Rdb9DmX zZn3f4%M$Jh;>GYkz#dNoIyNMA#YK%yL`q5Wc@g~7?;;=Hx*jo8tVrghPUFB9<ZZb` z6ai+fL+gLmV@ZA}&_OT^@z=ECL^($dZcetEU?+$zp^qE-XB02ko7K3}j!6U0Cjz+N z>8g6C`s<i=xZQH~?P0Br8NBGJedkGOZL}5Q&`%S3Xz;k*`Mzuz#U&J3(bd?^#j#Ps zjTG>BV2v2v^R@_LTZ6B}l;Z}%Wkcf!WZ*z&#nIrAgwykohlMvdFw(eX-rcd6<}$P~ zzaV`8vXc9y!PvvnGW|fY8eP)Zr-u>IRm*AJfb2R1x!KQrJeISDAhGIJ>sF<?rioz9 z)Io&oI!ny?1D3(^cnCgR+!6&ZEsK6w(QmW3eaKREM+5}Ud}gYT?6zcV_@MS&PIr!4 z>UsxYtr-kGcW0q|+v$(puVuo7O7bli)E4!qPh{;J5VBPP=QUzLp#t7jf$VR^D%)Q^ zIG%U>WLxq1rvQLnk6Et2=f>yP=<zA^OEclHokd`&LQ`7>(Qo_GOnO~<GlJ7BIDk@M zibGz3T%%J4FN%v;TKFmEzk=xcyykj9?A0*sgRYN}9tHdWpy0bBtevu8t0mVQ6i<a& zgMnMxgKS}~8Bg!?ruSj8fIQBr9dTgANe7SN>zI4{C2bl1j4q52$sI7hyOADVb%g}N zHQe(N)YG^YX#H8<*~Z_uHRp!m*nGT}BDIEs_|ZJ&97AJ?*;jQdTd-$n;+U>$FU-&R zEVmJM=xfm)lg6att3n|35AbqhaTwE=la0<D)L(F@nxh)aGPDN@X(?E;!&%o0e%FYw zO_>^-8taW28=>P$qpnjSc`vM<@WV7DHoex(A8kDDS8R^UdV8(e@2=1UxYfdtdbh15 zco@i|7|iJM`?HV+t>;wEz);3kM9&DRjCJAPi0Hg~?tV7*Z?(cDcRQ#Q`hL&3H<k94 z1!8p0@{=0{;YcVIAB=i1VQBX3RLj;J*^i7-gVtEAoF=v5u#B%bu-||odb!uYmTp#z zu`}A}ZZ!!9Fo$b;HRcM`9bhfRxZh8Q%gGwBOQRKiN;nCR9N{_?$Ta`5xLUC9cNggo z%A#|6+Wz=HiGT=PrG(HXAU*TQ>N1G&QgD9;sK7)=)JvQ8d+v7^Odg&^p2f??s9q{T z5J5?2o?+pEI}RGB#OXGw+cKs12vC$O`^wjLW(C%O(T1HE%IZ6CUV2>5p}vr+S+d(S z#ORHPoq0BKESt0fg$979rCkc?X&Zb9goF~Nq!;48n~aV*>y91!hl<xyENa~Yw=(1_ z&3>w{S{56VJxQMZjxcfirY2u@gk@TKa8-6geK6k^OD>2GYr1gpK?b^xX`FEo`S=7Y z!&P`OuR#!P#@6QY0-T%Egx?ytV$%>hk+c8K|5a*r{?Eyxt$-I98=~F)KHvMA6RR<~ zXwx>^A0(lAE0el~4U6pE{NAAFr3weHyv@rbHV?CDW(X<<>5Ph@kmB$|p+g5sjsh=s zqWk=DGoRyN?8!E>^U7JELf9l!t7KdLxp4>!5>dibh2(3@c$>s{_%pu`%)G`t;fX@g z65Z%uh={s#tVycp;Tm2Co(VD%bUU?8EommtqZO-MR^{kHp>Cr)Y3(8^KG>S{qC9cC zM;Rp6M$I^oc0je+&aC=G+jF+QDCWtN=7s$Im1r}Mg@Y4wX?%=!T7ZxXJ$|31Yqv_+ zf_Ba|cnHk^^ZSA_WcfG6<i&<{sm`!NVL2Cr21_Y<yw?#z?-i0n=5+2`=mp>a5CX3Q zIg%ua7s7@NEmiJJn3n~i7nVyr0B#JjT!aUeQLp7jv2&dMgC=Z?oi`T`3wBb%!W;c+ zR+5A-FY<91VO3<w)Q}0HHD>!RNkiZI$*E;Vv$Y%QQnx*ndu5!n$B=^H=qw<XhJ^@r zF>6M?)1hZ`mR6k8ld}il5D7Vh<%1B3mHlEYbRF>YMun3bfPH$hU61B0V@6=}CZc(U z`~>CHR?9?{^}nV82<9YICo|T`nv-el#8wSCTJ`*;W5{rBnDN|i_+6F>BKtV=nl@}O zJa8vNe_EF5en5_u>j+6?GfTWsM|-d>DEuPM8mPP<r!yGfERzv;IyVWAB{VQxA%N!p z16e?(zi{HV%P2UTvX#=-8(H7>J~Ibrr%TFZzUkJ%v&x4?$y|7{HBIR>D7^-G07$r7 zFh=lYf!7<#UyYI86v=e)KcV0Z9qu!Pg9;kj;mIfX6*=4&>=FY%LGt#HvmiUHgB@sc z!^CKjGoctU7=&Q-`Zkl&VMx{~6@p58iw-G&OwIzF{E+gIQJOFc1`u~BQG@(Bs?96v z8`=ju5nP&>EJO@E3t>H0{!A}K(i0)uz>0buUv-kw$zz?r{DU?;yoH#ICzL+Tc8E*_ zG59OaVAv*|51f+b1qP()gNJ|!ImwJ~PLmI-lcKrX{)$Tn@Rbc;9Q)#Jr&y_=kU+U+ zTUbrg>yQVa5n^zou4yr>*+6S@t|nVG*#hJ2*KnlWbC9)jlY~&?v7Ph!)Vi3xPLP^O zwb^l0PP5lp<R3&+;U)R)bykeXl~-Xzu2gHU%fpC#`96%um#XY_1@c0B-CTJg@Qf|& zES@fzswy4r8wXkz-YFM3j!ILMW{XjL;%jJxKLwERYc+J)bxa;ts<IHBgt-rOx?(ti z^rC$XnNnIOV|kid7l#s;i3d$?DnO=MAWCCpbYh#S<Q6HbWTli|a<eReNQIedi=nc3 zy8O0dNSXt9OH)Z_p-Zs4ayK-)S+&p?^gQbTi`pzi(}~OKXos3|i7O5t_c&ZalM5Os zO=kJ>H@K4d^5~0tK4`5N_)kEwP>$Q>xf^DK?2IEs0ewP;=nX+C7P7Ta7VL8V#x=l~ zP&#(&23D6<59R8iJUx`JhYIx2TntfuGL|IB6a5qGJ@`+ZPg`?!qogBxqrEOBf9#)C z3#=K5=6Od@y;Q&u(F=oeY~hCb6<tY5kvn*HYS(^b)!9dCfIvvK6=NVks)0@t0l*m& zErVyKhLvt(QciTTiLs!r-I0ajSWdav-n$!RM?!#k$yXhfW)$WR(?@OtnynN_)mk;1 zR5hwgd6MnOS~s<flg5**?NdPJSFMxND0d6MnMft?NZm0R5+@SKG?Fe*>3S@Ohu8t< zx)j-}RIN*aN(|8qB0$Mb9uqt2>kjcc8p;Kv_E2>nU4!i4>QnZE2FDq;ObEI9+<pPu z@yi8Fn}}LS%MlbB)q=Q>uTr{&mgYDorIG5G^3b{~i7r!0X#vPHc|0_bWUYb*0B{)q z*R_M~0Hp<?p4!?3ODPxffv4<sW_cQ|m;|a9{?jL7dTe4+JBU_8VK6%9y{e0<u5O%# zJ&3le+uiBvfdaR7x-Q&>neJj{jYX^OA$^<Dh^xCbH_G5VbjJdmKcVr-(Pe_&L+UKS zb8?z3-1{$3fKM6Xo8-{r@u0Thd%)pPahpX6^GbvV@pJ#3HF3GR&3y&FOYW?>BHz*G z9)|Dh?yMP>XSTUD__o{$q>!n&;=H{%-gGFsNZjkx#JzWG(MtFlhOgmh34C3FuPf2p z;42Pa@#tK=wy4-<fl{n@j*~6UGR+mY*TtJI08s+g;$BYNn_d`+{*B@9d!2$*^=UZ; zFj+y@YB~Avv8@whw`r?B<G77zX@1a<=xqA@?Hn6|&lcb;-U>8Hcisg0HVRDb1PpNk zu(1NPYP~ebpVPPi^>Hm{t{zUss!r4;Wu`!n;E1yN=K;hqzd&c9qSg){i}J=O34PH_ zVuAuvpf1pDWud7rsQ`GHG>nSC3l@?c>;jmR4947aAqk_DzEX%Y<>W?uQ&+Jr-ZEIt z7*$KR-T|#y1*&jk73#w~8L2^;cQx*=h42+<|9&T=bn*oi2=FifD5d+c*jj07BYx1& z@6gLNgT0%A<}SwC!a%;cjh3$=6Sab57U)838d8w$T)BN(F(^o4;7>U7Oj`ioZ7$2d zq0*!@o584m9y_?`*I4}gd6137)aElmP1>Xt?Z(KdEV56P&#TQns@$!7!Na#>u*pXU z3qh)xq|YI6k9Ir#su0ys`e7l80qwm+q32j^qOi9L8N1q>d*oERt6R#(GMmo;->@1; z^O@)`8`nYe_pio2XaKFXws8}NB@Ew(;iNJ<0}Y903n$N2Sreh%Yo`FNIP7r{Z_sv3 zmIO%fU_v|1wxV@`1BMF*2-rT%41~IoSOdoXS29*#S)kABVGKe9{ZS%FG%vk)BPv{8 zTI&D>hW6Zv&yC~o*~PwJVb5O_<Fn`vd`?F~_-r;b$8{t2M!_zm_WC3tRX|e=aw^?! z(;4FItqCrm*I&`4lYe>Rd>rhd@wzD!54oNN7FYlT?jLSYo8$YdALO_-_EcPJmWy|m zz-!xn4B#@qeEqAL226(e2a+c%`z3g1Z?M?9>@QRJ6rYKx)jd%o+DPZhJ@oh@MszSI z<<aFxwe<O$P@{wh3th}2e899Yz0+70CNvBFsr0%yGG5MnKx)?uIP^6OIc`@8G>&dB zO+X2hLnvx=BqGx3mtf@8dg#AnJgEL@Zu)18q1&Jv19gWblen+?NYv=hsI75(8?jAP z_#0TIu5Pr2K(m+*V?$l=fPRP;5!VGGkaV^BJQ#!ficrY5lSe3VorfGsa}S4E447pm zJQ9=zk~um7^dE#wMD1q-a2&?9oqh=o>D>geBhtZ3JtA82-@%?j{@hG|1xSIm?&y<w zlpXXr7Is2-6_l){^3V~3m1bN-m6v*ap^{(~a^xcJkGN$Z=X+?@1T-+ypr0p%Dy{w$ zn1NN(a<wuSX31z4S)^_e)P-t&u3FE7`I0gYZPW(mif9U$MoFpEEO65GfT0<x!g8g_ zUOFKMB=8!u_5~ocCYMvL<CHZ5R||Ot%FIs5q&x<h3becVO_^j|Yl>zN_lBcp@nE>d zO?z*`27+BC8`DkgnrT#eP5_mo%_V5nX1WIj*Fp_S0{OD_(<Cwji_K0CfReM)ZOT@G zljp&VVlYJu+l*SZK#tR9$X5;-<q7m1=uV~hMp-1sUtUC4V}a0=t?$&YNEEj1!lsdR zt3Ro(ILwr0T~7N*Gpfm<(2Kw=>Yi8ddEh)ggZtUDk3EmECuPqQ>=|ayBk-hy1DXc* zQxUBelcu*V?8blebhf@Ke&A&Q<fIG|{55J)tJYn?m4YJ~95+yDcFOf$>I7b>{R7(Z zV^#%lL4fo{hEv(9z#eAor;s<;lE9D0E(zdzz@^kNO9Cn65UvM^!EZxv*t#5N#Xuc= zwM|e%XAtvHH+#MY&(>$YglFKC7?=V0lq&}ifK#783@>qeCd9QJnwMX)eB(Ir;34r~ z%W{}Pm2S~C0A|U6Ei4`kL^eT`KP?jDYt`V>kj)VhfB0YNAdm`znKpn9Vb4ML?qHqF zx^55a(mkv*_pnahgPqyC0kT0o3eA`9QK(V6U7><Br>aWIfsh#V;nI8v;f3CNN51*q zMI+yaUK_6IvF{eND+)%EQhIaYyXEqY@;oq~^l>Iz<BnnV0AeGCE(s$g4nB`jy`SPD zJ{$h;gfqm0Z-gp@6FNEc9)l!x54Nl~BIw0lcWtqh75i_jSk?!<|I7-c*A&P~d7PDU zx3sL~a-&qya(S(k+j4oM7<^brwughS-UkrOu~wc~o`?ia)kmw>K7zlc_ok8W{N9<k zsBbK}U7ptRxM6`jsXUprWhCn`XqzQA25=h#cnJY;MIiz3X9QR+2HwH<qhjDqe19Jl z1$@h5-~hfiiGe-%UM>dyD-F8`sUZ|Z=5mXB54rV0ra~#3Bie#Ud9~6k5<<oc?Lo?; zFM<SbGnVVs2Et<CMUd`SK|BEvz13+tp~O~;Pf?JIV&E}c>Wg{Ar~bxa5C>nOWs(Jm zXF2={RaIi}Cos#k9LnzuA}ONTsZ+n+QBFG>&d~Gy@MKF`>hnE}&tG8USOqbiY^-qo zviBtj4l)5TANp4e;_ASdaZ<Ul$#TYM5@EEUT+-y!SFw+QYIHygl2np@)B{+z82Bv@ zcJZ*Bx$|id4r&l1343-j@xyHAtvt3Bdi{OC3EKKtVMGjE4`pMU{}mIzS%oxT+_yOH zZp3zmg4kqtD2QUgP49Iu(*vfa8J$ehVI|QCZHwcr46u{IVWgf>$EvpoDk5nkJOC52 zgH-X3x1<Gn-Pm^VbxsW-v}Ap*@X*QFm`3y&kz$w>_!vHS?igvWn;t?Hx%Vwx%a5%S zpBiEV{t+$`#~u;4zsBOfE&gZ$s#>u}r5`A<?@4o&*!RWY3y?Ozs&CQJ7I0DLp~Pt5 zvgI;z#|X~!&SF$9#K0|=HBHZ!FPYbnAQIjh)f5%<Pt`QqF}?qXPqLa*uOb6&OBOL0 zK^_wWzrwx6G~(lxPNDZ5oW{qsT>iHFh)zzddu#3Ndy7dI2iutN*aazD77<35+dAqD zs1eS}1a4+z3*r_fIE<4;?<jQ-QYtwU&Cm<R?6v_M6G08OV$$Nc8r(k0lp2%Cz(*RZ zLhl5KeSv{s4v$+aTAl}bSQ#$bYA476Y?pF4Z`-HHVN$-%G;(gDM2}Xq8o|fw;I*|a z2N2b7%XvV=V}Mp6(C0IfK#rT_afva3MwaW0=jk<~p2eDi!={FCQjQiVbiEkZ8)xJl zP;tz0ZrE!;_C$#5xogJU!X(0@0NKU>_?nL3+sK)%!FL!v<2-~r485oe!k}4@q3^|# zJNbb~zLcx?%s>QG9`W_X@hFeX^BgELi{lt+d=50JQ=>pr9q(?Pw3&BwtRFXcMmfa| zzCYTy1T*Xaig=&I<P_UEg^e}WY#u`nQxqnF2bmnYnlwmfX1i>f$&e1o7xn2xV?reu z-fF^R=_bM&{@nd;kB|0%4WUHlE0^r*^Nc`Z<ozusBkRr9?4{8IA=kyij>-gLDEC-q zbq{0Ihj8DSywzf#FL^b_yM#SE4D+4Qg?F!kc$3rVcuVdtWJGu}7M;rk){bigRy6JI zmSRpyMcA)(SiK_U0P+&__)26GhQ)5Dblb16x1@A^sBVhp?lvR?h0)C2DbhGSkgpFP z_8MWccH#5g?1`~D8JOis8dL5<jC(!)e7f#yW|e771tAAU6GI^^ly3MsnOOjXTL0qZ z@jj1#z79uk)=N+hpvdC%{+8AR!&|;Z_KcY}_L;O0ez^UnkgFeL?6VN4bXU@kixN^+ zo@-~3Qogq5*-<>I`{`Hx*g2S+tCjae^Ax7NX+U;t1l$Qs-T<)LgyOb2iK~RT<|iPY z=uhB^@`95lXnXL33aBK!#NuiRn{eBVt!!3C7Z4J9n)MA5b=!&F523w(N0ZeBBB_oy z)Z5-%LEn#RT37pyiG@yX(hW{-G5oy*e_z309RBXQ(aEiYH2(vQ%h4)*1Z1ZTt*?;l z7YVC0VMO_z{(Ml3A2Xp5;ph|txbwFQwOh4l2RuWqIG;r4cQ|=Y5ws3xYKFQ==x`Qr z9nLu!9nR|@Slr=UfcuCf3-fJ@U=By5>DU^3^IKvd1F6k*0?S5&jTDEL^C8}$x_S;W zz~Rj)WVqAS&G>Nz;zOgU37gGJs=GsGrfjPQB^43M5A9$W-8cp#WtG6StSV?pqNJ=U z=8`y#GrsFM)O1P%W3&|WZ+<>%BJ4|fq?-$BTfR$NJwyOKLGmh>hNYS|BXGdIy9GJ3 zM$2*POIRgD?j{|$PxQ%*$R{S_0)1NyGIFX32D6fHd;!doP^H;T12^i(ivjds(<%k1 zx?FMf@b>2J%|ErBBNwrRB36J2&5KMlFH9{<`Icx?M<u^4cur3B4=j&nkoGFJLLB}Y z#;gRrAz}*9Z+TFY7WqbSTc9qSgB`2HQe-T}8BJGWMwy3CVHB$`Zb)?L9e`0Z1K~PN z!_2xHGK$;LfYI21YdOVGF4)K8uC}(pl%fx(B$sM%HQF}d=#Zz;1BS#VXkr=GWf)n8 zH4>*~%$D6QH<;5S#^PM#SYuIn=?u&?oX5W;6g&@K=xuPZhjD2fnS3te*!gTyG^@dR zBT`KbF+=hhrY}7I_LUKPhglnIwm%bNuh0eddj1G|1rM{=OJVl<FJ#SMJjEEAxcE>t z-^pq+fMiVAqajql$lY;WtLkJ(P2#z5CqouV7ep|8X*tVr#fKwjw44XfHG?4z!{^q$ zSIjWDf<J{;-v-0ch$Uz_OS;)=X%!A|bsV`n{wZ>|zFt~{oknlWP3+CoY2A=L8?)E- z{w}%T0i6rxC;#Rd=uT-unR4l-rmsR(pDUNfZOry(Er&km-#kAaJ3qAonLfMLab#+E zc0>sab?x+p$!zJ!wBKnh<JuvvoraQ86?&98v8q7-ifb{|LX9fWCvcgG^wHPQ>YNYb zeC*h<My}Y&t=5VXel`|$ZGj~Oe}&y1uaAxPt**H3Pj2-Qs>w0piYKT`b;UxizSXEn z0fklftyZ(}v$mn3eg*lsu4dF5?AWoyMnJB<zOY`f6=AtPV(M^dAlCYs#{9Sixhjh+ z<&DQ}=3@G*PXO<wW>P8W;pZ^y5(b?78ZkH#MO3vVw2Z2rI9XxFU4!Zi%FwXX5W1TS z@hixZC#|81CoQV04>;Zx3wB9X@*WM`%5hMsAsF85+`5>!V&n|eD!<jz48pqrxqB=M z*CkN!G8FEl6B!EqdJEeDacpt43wn2({o(cB?Urv)O1HDU-uy;<Q)On-8B8S01i#^a zEeGS3!vd)`)9Y_#+u-))W@&t*-Xo{U5qhH@O{!yRmHAqfe){p%C@CMaJsnadK<f_7 z=eR%M;MhH8F>pV8B#J#s-+`pwJT1B0=Ccjps^}c7DpniR<m>IJ4*=P2nBmno8$wUw z9)m-VG=gX#eYjxt2I*`VS<#0=aQT<*gt=0&B-}Cohs$cermRFsD|DO?sd;vnS^5V{ zi+rOrOQOIzwo%leM9V)~;sL!xzqxS}&d8_H+?IvlfFvuW0T@N2T<+)TWInM;;H7ui zaIMkRgD!hsH(idwk#+V=w$9$e$#(!w(G19$YQ)uaFLYs%bOVa<Rl3BPNb|6&J}qY@ z${BiW2<@s``ZI`a_gfmDMQmJgT$)$wdi)0Z&sdOJ7xx<*)aGtSDf*H$`^aGAlN9DO zV(hTzN)?0~aGDiKbkjFV6HYcp&DEo5*3EMn7~xI2XG8^5%VM+zCVB-o3v}O;Jk#Rn zzh3JEV_;Yr=p88|`#>ICLnM`Ea-`)$qwQSFr4-ruD*<&@J8-j)EG&${EI!ZY_R@zg zLFsP#X$9NRaCFKd<O_r!6P4~OYNa`vrYtq*D@U~k$f&I0VeYOc?JLG?DFp}QbT38e zRU5s<OE;s0!yPP~%x2(vtrM!XdTA_%=JE;`zzv?Mof=Lo@cONd`>{I*z^p}et4D1< z4~?n7#(?sL`vTn#=A0vj6sUxCM2LUcUM$roI@AlznEYqlQ?Q-7OI;RE^ySN>$~+KJ zq+9IE1bLjB-h-H7r%#7Yk50BX3$k?}l7i!LOCm`&rn}BVtrTs#%4om_^wymih?l{> zWtFri2VguSD8T@OAQ_44Jl%L%ABq3s*w&nZ&cJeUdj;6x_2sxQUh?%4EAER-5Ak1D z!IxUh^bKvk(wR$}XC@R5bEPs|u=x~d6Akt4N&$mJ{o*U4dB`-R4(~yXgOLQqW`eSX zH%M7N?X-`c0Af(C1LEoswhcGtfbMplK{l{m!E}U_jc)DqX!<AhD@L>pZNZ-qIO&=L zjMt50^WY^Mo5e6VwsZDr$SQI!eFdgF|8$y?o7~oMe}ugQ6cJj$5VlX3c+wgDo<EnS z<K72}Ifi7BMt}}FIWt>}j@I}yXf3BRkA1p4k9CHRO8I(6$di0@nC+X8kzBxW(M)w= zG|fjp8XB{WmSl&&#c&WZ=-fo#Cp52+-ZW()Cr@zGSvr-1UNMeV{1tb2ZXfZMf>r}v zaddTzP1`ojaeTwg{_f?rQ-fbQT;{1^r#yoW4JPsN;XkSjqLyW~g?ryYi~cv&X7ZIP z3ywkAXd9?xazYvI-uP%zaNVnPh{`8@s*L;5j?{G!x$zDVNlOqhpg<IxRk!QXEZM>a zY++rG<1f-UNcMTC=^Rt-9Dk7?^7@6O5L=B((HV$bVlQoh7|G_PKbgUFAu-s*_Ju5H zS-7=i6M9{^77w&;1`JT6t8ItuSqx4x=`f_7J_~JZXL<w=7?Nh3LL<FtYs4?ZQ6b@Y zx?_#F6=Jq7w%{WlAM^3y#D^OntMIWd^g6E5+%2CVP!de#x|;+R>k^(LG27+B%gU!B zzF^KM0Y!tHRQ|eEUDoe-LmFTBMva@UM+F<EahE`r^#@N$E~Cp*cnA~?TbMM*NOk|k z|G=&On+N}*bV9*>7!4TrVRRpiD_LeS9w|I=zn`n2TUc2*6bW>I2J(>xRt-P`Of74~ zxsgs+53{#s<7OO3xKfyK!%{}+G<+Ft;r4{`uRPMjjqJen&~HHzNk@!aTi64NyXxu( zJUzcyPL34exg7WNzj(0lq%@=Ed0SZgH%zUg>aq)Jbsuv#hp1(cC$?hH6^9@%Wz&@! zTU<+pDp8KE=xV3WLDVkva|29t*9$fa*v|PJ7o}8toq1zEb%CMmpIFO0K!834dW>1$ zR?@+oLt(&y+S{ecZQPyh(gc4>gT2`-K8ZW)t)|Kj)18&1+Damhqmr|DvQz@L3iQ@8 zGYE#b<MR5)+AOUTE1ku;GIiI`3n2E}fQd_Pkt`)ECG%oOvw6Ljoe*K!T)9xu_^2Mg zuuW*qW?B1m_oM6EggcK)Gg~g*EaftYybjaNl?iCeC^UvQjDvA&&83ad7XPf?>Cg|Y z)5m%kG5;F@{ck=2h7tFoX4l`g%o=#WFioD$_SVM(VGtEPZ_txww#$OO8f3%j{Cgfa zex7Z+gMP#MT{&#2yDGuY(QQ}9b0cnV$l4z-Vg}z;hTX20XTf}s^=o|Q?8fJ`7x7v2 z0zONB0nattbB?fA)@$rF?OFCpeVV=I>|n2(w!`ZePo;)up}EcNdWF6DUHjo30*mr6 zhJ)QOQFNwq@Qo(hPE6eO%FHsZGj%sS)6q^#{q;;tO_-c2GvIax*ys5XyKPr&Ci*DT z-vIm9qALfQaE)&>=N2^Jlu`uXpi2ytAWUQWwH91g`%N!G`=wb5<)ujq&63PjjG^}P zc&KInc=qH4e2(LpIqmh4zD9!qS7<_&c|JECdIuy}SloAnMAR)j?kR6EM?SP<MnYRG z|M{Q)`6^Cz%*Q^j@U7P|W1H2`YH{8t4~Cwc2El_IixVJjsXW+FpB$LH)T_2<eW4(| zjK=8(Udw3&++W9hxNtGVCbZT-Dl)#)(b?4B7W@K0JAxRI9|%h~ho1lPGSc4>aj(&F zWaGrbh|?W<It$bN`S;V}cbE_=Z!?w$!txpD%MIpGFb-LuHaFCafNtiv@fc`PwsRhc zhggu;zL8`fWb)7l%aOb)5&-eB0Bl!<0TnTz0_?TzF05uCVvw?1mYAkl+P0@+vC(m; zALU?FK1M-7t=mo5T~VPUz&`M#LDRvgSMSBnU=Nh@OSZFn1N$b=;4>7+#$@A((1ZEP z(BzHgmL=Ix%gL5Q`B721Jb7a_M&v`pXZfv`sIi0N${fd=4&mAz8uv5Kpm7gE*@;5= zXdg_5&t{-av6Fe_EnX*0Q?{<<q)B9BBj}@oKc9Z@eN;I*=tq614rI}bgQ((xC<hQ# z?r{_`*S_1qn3w`a$U0r|7j>OTO7qemUPP@Mfz-u~gh4|#09`w}5J>TuX!J)!?tu#S z4~*y=AaFb|JScIb_rP?RcB}xXZ+KXq-kFM@*l$|SCMc-5E-tweq9t0Q3}2DQj|Gtc zBzjI6j-#tzA93=diP6KDHw_GEw$#}%D(v#V=}zEdz6UU^4yet7V_43H*?b?`FX7(j z@l*$%BCzj&b~5@`{TOQot0X+X6c2nheY#DfS8$VJodI3mdfE4C+~(TX2@JfM^&Hr` zcpk(>fdCm_V3ZBdnINx)%Ja|~I|UV<x(nB$9_Q8dX8STKJ{f~5TAIIrB9G$|g#2Y& zcA!fPpx3duw-T78tM~tKR~0kv6sl!CP|SC_=7Vt%`t5FgY@#=|Ridx-TygJ0^!0!) z>uzg#8WM#H$22I-u-FmX@EK?Um6a`^2A+g*(_G!42`kOrJQUE>OF99y&T_PrIQnhS zF8wC8+#D*mgw$U^IS;NOx0bC@=a)I1_sAE?Mfx7@_wEByXjx*M#ycI64Fgd27Thpc zfEyp>(_bCN1`2}nZut@^=jnJfCCkmKM~E8L^+G~q>5}SklvL5(_97f(F}Qq~tssu9 zUr%|5F@d#l6*57`=a5?6t<k5_kP*OYq9~L}LnDkgm2m+M6w7j64ES&u@FWy{;!EU- zGr@CWpb{cqZN)i%V<Q>5_>wZ4^WemU8!xq>batb%h}s5`&ubeRM>u30scbCOdBja0 z?n7m@zR^QUkt?+K1}fL3h{4ZrlPeWD(;x=_j6T*`RO(N%Upc?)JhYFL3%k16+q|o% z0JRp-bd^|Yvt<ogQf^tJnq4O#+8L!Rr4$LEIje0+ZeD9^>m*F*)f12#nn7aaqJ(K} z-I0rFpJ<F@N6?<YIC%u||G<t=r(v8&doRh&xXl)w56FK0H)Q4L9JC1Yw+-pJJXFG5 z)NldSW?Z(7^0*uhR7STzT)R^Gav}4|^<SZ0=HQo#5e7CfjJ3<3d<~;OFKd^+Us^Q{ z3U4G&zKl-h?NYrxSALK@xnB=Wf)H3MLtg-TdodUNc^PxCee#v70Nx)3C}IHGUM!Cu z8jaug1+&hc4C@&yAfuB!c^E=BA&I)_KLY@H@)&$G)x5CNO%)b(A`y~VVVIx#zhJse z=-}H(A!((pdC-VS_Gb|*8SLq)px$VA&~jF1Xp6hkC7@%%wym)pKo!zBk_ISb0tzq| z(-Fwt5C<J>F+UoehS8w8Yt@3>>7_9s_u7ULzbWX*A|yE<aI;T)m;4Z$i~5=y1N+AY zUKtw*j|M^wBWOLYqm@pKi8ST$IPN5s^T}{K!vhMy2B%_?5Ic$vq7l@@04`7<YDjhe z*U+k8K{^}i+Jl;O2cGNmlKGB7X|7K#rV*q{nDM51sf#(cakV(*Jv&98@@kRyNoPG6 zGC0?^pqOds1;&`i&gAKHZRI-9)3(4|n@4jndfnQ@gnQ+bKH)a?;)H9aPxK`?K2*7u zl%khCeUz<Q_guwq5ddvwa!Kw<EGlV50e~h&Ehtmog*MFG*)mmkKbz#%6Sa4>6ObT~ z7CfR6z5bx|k(2W#-KphFFI{*_Ux&(VT>a5l&uW2rR)cH=qXCV5j{b0Tq2T{p)$#wK z>h_b#s(1XqRjuU&Af6o(NYtz4V7;UddUUE*WSIk9_K3b=Fapqu03G%1BWO(ov~m&B z!92uIC|Q^SdU_%~8|vSVdUzHqp!W~JNHDlB;NU*-sis|nK9B*A=)*99sOqd-xue&~ z;o8p@E3}|M?@TfcTcn*<pTyp0t<+#Hg)nxBx@BF*lW0nncRYD7x=eIdHlhdx!TP-~ z5;Vc4l(CxBLYyYdwE7Eu`GdI3YUNs7pxKF(1K-+)wQQwxWW6T`1yL%rpdHWyT%q_P z6cR{#^FB|myXi}~S`l^%iP0Zp))TCUmp0<IEm$SLrMT8xi;QunSBKP!tk|WvjaAD= zJJ-*7>7S5&YPFoFu{)RYnre!sduct;d#!B%YT5zucqX6uQ*T9utB>)9g?@OP@kV{S zUuZmnJuiHcSjrXyr~#460(4~n<pv8QmGktFQ4cN9Ltj%CD$zrq>LI5dI;)2&^w3c~ zRHcUw=%JORIFuOiYm9*I>b{VileaX2w3y->qX%pHr01hs>6kwE>7(@T7xXyh*sx_S z<elxK7cZl$Gh=kgx=mw3#jGsiWGF<7jVWY0hrUABW4YAzv8Evhu;JSfWupe)X6lb7 zNAQ~j`tVz9H4z1FJ?=skAvHFJKVmYs@fCdUGS5LyZQRWQ7CrC+3s_k|DMbj#iww03 z8AzI_lp-J}Whtdr_JIdB3w9z;vLbdOA9bc;#;5Odf?<wOEU(VWyAnJn25=VD8Q6_d zL=5~9iS?NixM7Uh>4YKtL;!{<HL@@(kFh;=rq0(4U;5EyHsP|$=&yU(;?E<Etu;v6 ztbo!XMyk7#VxcNY-KReuq3#7&Q+LKtlDelNb$>c^Ep_AKQX2iq5ZVbzix~G1(Ji@} z(&yfQlIw&}xq<0m8%5%x`spQcAHO^*t93%8SrE`D0D;H$+uiivCnT1*$G5oze@d$> z)>?O|!*v<YtlGL->tY?QOI#V0<Tq&RtlByr&xF>5TrqbD<J@%1?P#^;;~|z}S3ep+ zeP{sL!cnWZ&lR8TGPgAMv-O%jG^$3<A))uUm#*)|8OTg3&9%FqkSEave??^umyX#s z#}Tdf7HG<Dr<6q}v!q!#M|}j=+-`$3QLX29Tg1Q*k?fZWO82mutyW@TO81w_krem_ z2(>Q$E9MSAkFIS`IL}LFx~e_tIG=^9MuJ5@i~!_3-HBTwm1eX$e7bii9ynVVsxqkA zWNB_;>~6=9x|H8C&4;JnXo-II1kAf=wQ?jMYQ?RV$4Ipq9Wth(L&iiBQMzZ4lab51 z>-95NoyO+#C96Nh<Ef!-Aa-XT0>VO)nFF=9RST^`bRtMpU&tk}>fXFDS)IK(E~O{> zDJmq#v|&YkvX5)P-V|`JgZa%k@~*U^Fi6MsK}DO?^aVUbWg|4xZ=~-#*%p{V3@p$i zx}18C0QYSlkETOlDjJ+aXoQG?GMs4EfdKoX6|@e|>-j*zKDwhgd3`~aey05G57>Gp zyD{aUeGZ-j=Q>hLuPZ}q+Nw*C>l&9sIgLXpD2A4flprQu<9Fy~07qnVoD*;?*--4I z@1w)~7Y<{G-}vf+xn*4A15ileks3Gk-oe)Lponp{0UeEMy@+UvZJ^N&a2_9Bcl$M{ z-k`$}S6o~0r|r;D0CexQKzyP-mV5)(I2TIt(c*>rNx|Fv{Rt13Gma0W0%b^(X81YA zDGRP(dD`uC4j^6Y)^7J`InUzcgiE5()%A<?zL#<!P?I<oGb7RO^2A2$a(V*@Ykgy9 z2AlUr7L|R815s}bpp3%fP-uR}=^qAkN#ht4pFl;Jd{Fq8P&u!}_@<3MTC|9r?JwtR z9kKOQ`<WY4Y<&vpG<G^Vn?xYBI9>l?;w;(3&|(Y3I$3O8B38OJGL!<1dzQZQHN@;f zB-jzquW@%)>EONeHI~3oatXD#hMQOg_WF5HQ9HX4Loa<s_m5*GFld;jQ~kNi>)Vy< zI6RS$mn`5k{Sb6N-El<U1Higs!@6#C?WR*R0JhWbA4x9tBkVo^KwqT6GqqJ{CwTXF z_dB_R`0$aKqhq~D(h?{2I(f%%(^pK!diPU=qW=q&&!&a;IrG>kcl0xF&|2sOZEh0< zfMdxs_=yu#28qYhb)>As7}-|LPEUPlJC!&;Rh26~eTW>Y`-Z;=ZiiHr7>|hi%B&u* zxbFuh+bLhDLdXpcY?w-#&7{igxYU$RmJ7zSj-jTEyOi);$Gc6G_4-xC>E-!{8!dyt zdCcEsC+-%x@t&d)CzqJ*Pwo+q7L|EX;g^0o>PEJlj+W0d!0RS<3QSLN>l;Ck;vmj~ z2%Rx_Lg_XncVNc&#pq5W`cW!_?G)R;VND<7vSkZ@GY2Sb^8s(_IS(VAk5um51hq|M zL~$aTcD2(N9V`K!Sqrf3jioCf+x57TxC>=Qds0q%>8h`F^-y1lA>NfcrMxm`&XPAg zcDs~K&V1*bS&5j9?>mk*ees>J*?7otWW8Xw%RGrBb|*5R>tVV{9IeF_Xk{o>Hlu4F z;MDsWivU6T0h_Q^sns!<B-Ev=NENSK62u@Hq$H~mDki0C@p;mC$?;xu!FRgMWXnor zwOxP&mOKrU?=t=c5OSQ}{8v&JC!qPQF8vX7p`6}Xxf&ThT3@;&8QzBBrKLYkh65O0 zSo+gsm|cZ%b7?3UegebOOP@-HpTux>=}$162H`f;s5Y$j3)<;gb<65#8aA><J55}% zTD5W&%t$L5lJgL{%@sp;?<&EE6CV|G%f{SlL9(#3y>>S*iR7#A4493wpoGnij;0IH zbYrzp?})5V#pD!Z8?6Y-pznXhtc(0cHxfhT`y>7eXJFP-hBCJ<k#b18Kc%)XBF%z7 z0sdAOM&t^*{vs~Evg4>SyNTr?oSqQHo%o2Z(l)Lnr)eEC8I%rzn4%Aoc7=*ki9$_M zVHFtLZD*6qPRV)7a#o*Y{`(-Jw-X=Hi3hRGJMj_CIEby@iI2qArJGLtik&g6wS|@D zZlH`a5NmgJ%V{tX9Qu={*<C$oA#`-3O%p~R!y!S+fW}Fw$`CJ4CHDapy{#@@1@W?z z+_ze-KGC^&^>#*Sf_$@1O=|UdlEnxr2ZP2p?A7O+CzI;)NLap=YQ;D~bDfW#qg(pe zfrT*^9hNdf+ql}JE$gn0PKKT(&1cYSN5Va|2mXRXz|yWpY#ebVu`&_Y33c&mTbR-_ zNpXx6vE(We*tPuX;7S(sTN>Bl;68dLDe}$i<ns$Kd4klB-jdk*g)X#pl}=*vBSIp` z{o9(mF$~6wpj(31Yy+>j3Yk@-wQEHfpqszc7Y#(VNKl*D+^uV8ayv=4+_qxo<#wa8 z$zqfXh|^k{pZe3uQcmeid}Wu;!dF@;=X?&2-j*}f9q%D%JlNn&?9H*YNSr_HY`qe} zz}6x~FC^x{gWm!(sm)Z9zfr(VD=_W~N@mIFwl1)@ps|<4y<woek92Gem6g%c0Gd|W zW(tJmubKIqTnJ62y`O2CmlWY?S*Q@NazW~U0miwcR5C2~(g1ob;{{?Y`)7WBv5(F? zi`-IMtCr^C?Q5EJR4>63y~|5I=;d~%yk%i&t#qs3;Gq}Kumx+JBbRzTZrXhFHx#<p z-)4*gQ>5`CF8sf$vGVAP$Ut-OlT)q-!|uhA)!JGRCcySsKi$Hhav2opy*;`JC)E~@ zE$mg($lu5^b0@A&10xAiI?4i<z^fC0d0H0Ek}bBd-4*}+Eb-}ZC93QtT3YawB(#}Y zQ|?lincJp|d)wWW^z{$*4xON-;c-(C?bYTsljbtF8Y-azs4j3$x=m@0bMmiRhVrG< zmZ5a{mrxSlahJv+twPJhKrf(yV<+(?>9VOZdU0v=BbI=Rxa=5hI^F|>2wF6Q?OeI7 zE1FVS*0OM=bP2J&ZXjX+O%Qjy&7n#|OYtn2Zu+8Gwy^CSGy`w%bHz{g2D_y3ceBb< zR^9~->XN_0w!j!l%NULVpm1+Vy0kcWPAU}-hTQ->o4((zH!`cu1kKYMr=^XyG@3>C zB|waj07=WtmAzi{bvPxZb)<0EW0=9xo6Xots9%AwN<OC<M)tqV>;@V8v;=iOLP3vZ z_CO=>nb*@gZ7p+?L2F<q61`e97X}w^If1qn=gLM^j+13^)TBM0P;)=cK$l?``Y)D3 zt&7&*L#q41)LMTRiA6q53Gt#M(sa9<7QD;!U&lr1hD3Jbu+NJHbX`dnP_+xM^iqrP zdM_|p(baL(PhsaeKn(E*mU#tNkZtGC9YelZdl!ADBy(pfLg-E?`ofkH+azcBQ<m?- zglMW>0vJ_6oPW{XO3%vl1H2NJbgr?_kg}c5HTGQjlK%P|DS8=-@_0Ojot~31r`zZ8 zsIGqPUDXwXUb)3h?|Fx5y?7(dOb?j<G0@BV0SebPP(sFO?Yjs8T0vdhr{(+_t&;ZW zN+p&e@z8)Lw4B{+VbgI@44?;6@pLHz{Wpg2F;LjybVFVAqqiC31G;9fmh&RyV2(*p zpVvqKL$`Vp3FsJ_>^5XDm>hsM8}W3MTg%yxi!ta7g%@t22zBm4ud9*!P%KR0R33>j z#_{-GU;2sjkAK9QksX~<R<K=4A3U)O9UY>pyf}_p&M~Z0j@#szmU9G!XrI1Ng73rZ zjaRv7Ibnoz_1j#1wm!$8oObX&C^?!LyeOxUj!3s9vrlE7*Msk>MOZ<7!-`R*1^u8! zy7OdmNdiSbJ29|XaIkY6O?gy-)WpdF1fiKH6MkpWDapguL_hoihQD~Q!oVxt&icA` zy~Rfiwk~_>Cg>S`-Wt`<mlW`W5q7IoL7PE|;6Cb7JwpDHU51?S?@HbWX<%1KB`%Os zB8lsxC@G6W&f5Y#Qo*m-1yU1!g^HV$5`8mNreQ6Gk@is8@W|Jdk*|2-Yh(u<S8QzO zKqa;~F3MKN&<2ZsLrsdB3)IXkOcpjOf`-mE+SUzI>BA?`!)fGhq6^0p{!LLY9t5oJ zqaW>K?%MX{Rx$VsC}RzASzkpnca0;m;dWqN5o*fxdAxM@@0pcIEhlh5Ze+{N@JTp* z<6YmhXJiPuZgUK6oJT)CjxI<ewSP~q9pJ^lW121lR;|0z`(1QVGU?cxIvGPVm^ou$ zCgc8bwYkRQ^ZE^;YHN*0tut%ucr6E+6*5}wb!IVGub(Y&9F-2JhUlwFsqjx?5DzUN zzu_?z$B_7B1H7?WCx6G9)q7vk75y65q|NM75bG$jB<?QykG;%yO1R2XY7QPE{kslQ z%v^poaSzckFJ8Br8J6e5AY0(ujLwwg4Bkry?>^E#xEkV*kPdtsPevER_ezMtYuy0m zWbesyCqFxRCbLWKAG}EV0Llsw6$O^TPmCv<vK;`oQD_n!0J|Z5X(1#`eW1W<I|p9^ ze3=K|A3USH&yhFCX>u0psXt`llsPSURDj)w>h(cgh?y0yBwcpDyQZe`<wr-(Wh8GF zh2mDLa~KCy6wC+n3!vxOCX;n$Wq26u&j$(?D3^yp=>2WO&7lPwLMwl7A(?8GS$Ul2 z<YUZ>fs_k0<yMYkx2$5o3W4a$tDj<QrX0>~K!;r9$1)zb0htS+WMlV8RtdHvbo?F- zdblxHTL<)D(bie%Lfw6_j=?}P)Rg_mx$Vo?EtWTEKgiR5kgNS*F3m{*f=0N^>+_J$ za9+2a!Ua3+<O=4!{~7s;MEnNYFdqdFq;^5NrhURTU43|qOry{5<Z9^8YB-MB`OC=K z0^$A|&=alnmBfWJhXlN+atG?t)80f~x(C<z9YxH~b(Wu}tKUxSJ$UIunOD2HCf8JM zcoR1gdD?J#bbk&CQHHz4AL8nP$45$6GY>Nq_2`m36Zf{J)9*)<D^~~hBK_?|;SaN- zoE;pHc#s9?)#r}p;gPRQP$?6>z!O0~HB{<;xua(S-a~&0`DVYl-k!?5X>*XU@9Ixz z>wr-2<B0WVNAW}t{fNC9Nc)PY)k~)$7(IS;)Z@9H85u8Q$MDD4`Z<)Ijq9va5slts zNFg%bdT91gBW@e@?!&`jy4$cA{HZ}dmDt0&p$(T#c{=H|zH8>8w==hSS2z0i{wt~g zdXL|YnsIJgQZr6PAL=46{WM+gd6@OCC*|=fFo07?2VVQtL+=DR@1dXIex9ova+^~a zapH|fRWP%eYy*|5Y##Aq##O;l_hY@x{A<hnWHyIhCf)RP{k&Up#BXNGX*Va|I%Wv4 zP|xVmjJMfYzUX-99OyJ?bk#{l7R^0imjqu&^;`FLp68`6{*8@}7(9hH;<(=cySBMo zUORfAW2g%|%oJ_Fyf~B4LLEqI)CVg11BS^r5daI`n;?V*Uh2>*l4ihYY<Sa43o%Up z(lt8X^x-#fW$+k8_2SV8$Ul)D>>7Kz<a=H0bP4H<o=Pm+p$6+Xx?!%r+jeR>I-OhA z=TQ~F5?8lj(R5r_a^^1+e^YG%0rnMMnV89L3&WF(<P2WGM?+V1a|#S8tK)<9mcolb z+{V9n=#gLRPS2gAehgr~1G(&63y<$~S&c`c<H$0h&~4s!8GiwwDP0L$LD!9r*rYH! zpeJ>i1?OrX87_PbC?X#DQY6P8?c(wJhV6z5Bq5kHvhP-_<6vHh!PAi73FX~NCaBB$ zi8rn;i;-phFue^NGRRWoGJlV9dC>-=f6;^FUfyx9Am4@CXD!O*{PmN`8>ge8B`N&i z>6t6{R}81ivjKsblcRZ|d%8zbez70@S|HJciM2ebGZT+MR`8@cZmjNCALP-bg6I8$ z>Jb1f+$kATYh6tF$e`Bsi@~SR_eG9DOk{}nF9Mppx8Cu=h7|IFu{x&bg6xiWA?97j z`%*pLFZTo9@dH729Ar2T<*%Paj-LKv@ZFgb;Jd`g%QF$FTccA#_ja@RS9EMKiQ)SL zo|PhyyLr5#kd;X87SyEzbaK>)24-_Vm{^YY6PrcVeIfHnQVY-m?mq$aQg{mRbSxF* zRc+8It<~aiq!m7}6X&!vi=3QI-eBE&ItrDhPiEh&cPsW+q~}I&U_ch=)-h1EJcR$i z!k>i#4DWQ%%Hpa?t(YGNwMrAj;6<D-H#6;9Utl6xoAKao(QCL(i^qW?ABx5*^B+-n z@YH~X!qQomMA_+Xfdz@vq9-aZwjSn^<wERmRk{9IWodb=oRia)Rs1lEQ8o#h{0Q<b zOpoufD3~R$KH`-ib4&v=Cpk#(g-1e5#$BihRatA?^z%ZdT;eHw2I@#f*bTh$UBSw@ zW0%CvG7GyfUM)ow+4|$oP4ETg8)ou>@zy6VP{Nk)gspC^2=n>IN)tyXyHsnFl8U)3 zdahlJ`39^;2H$wN3@^gFO14(wsf<oP-^k^&#c>N>Pk4r<;Q6ib+6IenY-^)GSC$Hz zx=`K1YpGZTskDH~OgfT#x-~V7i3QNOe_#QlGio%3%Y)(OOQikLFyrFDeB@%Fe^=~5 z)hVb>UI`2L$o+nv3^AiC@~LQi%-o10nm`79H*m2B4-bTX#;pS(uq^Jlys@0TQFuJk zYYr{8lqpp)O=-P==bu75;_y-}@ct5{r!(G%K{wyoLg51gsaVh5@=>s@K}SwS&y&!7 zX0?h}%Y@K9@FA#Wyt4XVE10{=YyXP$(pFjCc4Rmb2;&KXrRB0QeG|_}3|R8B!BaEc z0%;$6PQa{7Gc-LcKHTAWudoIr+N8*5B6;H)iPlf<i^DW^x8tkOW_z5>P^&Fq0E<6b z2B`z>Am;E;xA82f;7>W&S=o5x5)U#krd(RI!Q@|5i_7s1yrV&o%XRs7DS!PG<g-|4 ziGc~Y9Vp<g(*@iNCDJ`M@fSO;k#YA4P@0M#JlQI!kAb3YDSXRN9mfS3@kcKqBR0qJ z$d1O}7g};_T+x`gYan&~p}Zlr&H@4w^VeC_T0y;+M~QN;08dA)Ap6>uq=6KffKnul zSG4@~c`eNoP>LKMD@8&TJ1WTWXg*7`gzmdWcmx>I5S`?63tQWYhbnH1tAe`35C{3T z3|F4iyW(oaZL!`G)OW(Y#prJw!o7Kr<u^ddOAYG1@z6?J97ZZK%rAx610s}R)};CY zR~!a_2}e1O$;kxh9LIel6Us17C~twtlT69}&K{jmma+-O^mjWOCKTxJjZD~X6rfa; zx3a}3$5kDlkqWE(L*}o@W7w7G_6&LNg{P31*`QlZN#Shb5uv<<aDMA`)<s`p&)HeG zzJ=Y&Wb)GPF^P|jbnDVF-RiQaMztb0&W;d{61a6I69Cl$h$LewN*E<FN%^o3CTO5e z&)q<SUSD&j@|Je`3#B@yMYDkHls7cn!0FF$n$BW!?=0vA9-cU6FN@6{&U{bKP};3( zo!~grL>*`3tz;S&{6D~)1(>t)iYS;w0yidSALP6>ku&|Ow6l<QR?eX>;BkU8D$|&8 zJu4m62zn<wT6nKTHIQ<PQmjcItJ4^g<rZQAk)vD&y@zaPJw!I|sF+=i_#BsSV2)3E z$5mAjdlJuV%@rp<#_cL4!bd+vY4c6aU$UdZrp<m!9-k-}3ianVfZXg_9P9$Q2_O$# z;z>p!=sjO0$N|`W3sQt*Pz*3T@E+cAk07rEUSibPd>uKCj1muRE(V%Y>n_Y**;=8( z->@j#Nc9Dn_-AHD=K=TVVB6W0s6)@3JS;*EITJTbsxQpEmrp1PF{no%|HP}0@lYZ8 zClm}~AjH&$BxT+sr~pud0BVhpz^h)T%*^2kP$d#)^X!)9Ois>Zqz7E{Wx8Vwk;c<E zw^pFi03cbT1e*Rh>Rh4MS`!4yl%msLq~8I8EZ8Mwsu}8%ame%_3*|oJN#tvYx((R6 zpJay~GpGxLUGfyiG@NIlyFu4t`hc9K%)u!A9{A8*{3ww#A8VL<m7^NiDS5Q!pr)}i znu)tM&K_WTb7p(=u7OIkBHiJoM-JgO#Tj~dF1m!=_Zl8lj$WU*1E)C^N&;f8%!6q+ z1Jv~h+74Ut)GcN<d9cHRC(xj?9YmM>9^6C5d%|I$p9#Z+JdM6}Ah~y^9~SlMDByO2 z8LwHC%vczhythLM?OvMsf^N@w*{=6k+n60Vd52xqS^L6>S-ihz3N)<v#<540h|BD? z4XD8dALH#F#q2pBo_5*7xTn_y)?tTyJ*_yv4A&bEj4Uj&Zu;G8NgR6*nwYWOERfDf zEH#w4$i<}pzJal`ZFxb;xf4U`p1Dwb>+{#cvt=j+cPI?<e3*m=PvWM+b@UvR2pG+$ zufKM6Rg3kidds06=AASSF9p_DkRG0_-!%=N?|i0Pb%E!B8Hs72B8_hm13U0w1Hq+t z=UQ8ry~-L2<^cxc(-Ai@X$#WSQ2xhwR;@d6C}kDE100K$gupp5;Kl<{Ip<L?e4h0d zE5H_3gC*EsE{pi&U8#6kNyW!_OBc2;0Ji0~@xWLnVXd}>TP|hb=135WCD19#reaRY zX>%`VUDn@P{WadM<4?g`mZJBH2P1C!-UZ!qypx2m&cdU{Y759}#}V<#mr&J82?d=W z;~i(TWUl_}C$Yqhd*vEKBs$e^@aRBb+K+(=@%k3AKQ&a{U*k7~LI_ji*7jht61nwN zMBM>lC1mh(A=X;A7jYy(Y!u<3`*g=4?6@274n3BcgpiPo5&NDJ)?G+k;`SW8YwiHH zpA!RknslU0z+p_G9j^YYs|r4WcjO&FNQ1cjI0UpHmanmL**b5DLE=kN<eB0=o2_e& zG7McEDKA$TGAZgFY@a^N3Bda`7DwmI0W)}wgLRS^Y{Yt4p(zPGr5pTN%iStVr?G;u zzz&8-F~eg%yWzuPXZ49sTmpl-_j>ew&u*Kb!?ZpiE+E-zg;?C1ZAAJ)5&%*L`g|RU zRp&xB5I}K3+=)q0S2a*qz7c<-M5iPY!f53stcojSv=Itc!P8M~S#KxLlrW6&**3nc z<#L8>(edlxvYh(RwptP&+YYdip1^TUhsYVdl)^JOD)VquJbH}IC8MKp7sD4J46JF6 zc5(ZiEDkFzWG!(3PdtGq)qC++k<J*v@?!8LF2i7xs#C@`se(1B<nJ}9l03sw^|2K9 zjV~)(qd>DJDy&&4{;U;i)Lf@iVb!N3UTai~)47e&%rLfZ&p+P2ZyCPXz6T9S(jL>k zMc6+4%|+Ir%?R?%h9I9-UDC9AY)gsW7HEWF4}KWmVok}`+hFW4Fn-aW&;nzJ-h$mA z_L^Qt*TKeR_>*&?z9{f(D1_w}M%Z1HZW3{O8}aB}f^p9{J`e*xOE4L0E@?09aEAg# znECH9uw*vwK|sd`TaQM~`r4CD`4F>mZ0mJ~W_^%>SGp~NIzpHge||yRgCN@ckz#Z7 z&QxB)qBuS8)#WP(FpiVgDhC*hbdx`|-p)8ww$k72O>TG5KkUVsD7q-Yy$5meHhOD< zh?u;0N}|q7EyYuq?OZ^cSpGcB|4;C#<g;CRGhv7nG9qeN!S0Bvr)QpLC+Gl2K)Amw zjeR&>2llcpWZZR|N*C&R>Fg17lEy1c<eeiMa5HHRB3Vp__9WpF_do2>opHL@uONl; z*cKe=)9*ebnc~4ExAMw|2I+M-wHN4Dn-Jqb#eCi%O&r~OxjCla)#d7mPNdI{R6$?Z zgO#FgaqS{G59qL8KvD|Wog<b;OAOk!d(TMQCeZu#jBV3@V4Kc4+DF<nh2A^@z!n(k z-dFU-oX{Ina&==wXiPS1OoyAUovmNqLDB{)OwgEH5tr^+%<VL%CvhYuK@BdvjJ>YM zUe_Z{rf<H&j&Z62efgCU^!`o*XYWZg@ZV;STyLYFuf^XX$)ioLj4X>XW#aPhlgpxh zT$FTNl&8?8*TB51!$ec<ve1NNw2-;9_tB1@BU1gLO3hv?NO@Ium#{HI+-n)A$e6~< zefV=r(C)&omXeOKn}8#_=g4JD%e1lA@q^ukJ_(?<;g8qgcBTb?jsqtA-cLcUB=2XK zPG9={RlAor|2}y;Lm1@{<mFqZN4waT=#V_Ubvl)<&T!>-x+aA`&c^mTFVKtslGyJQ z<Q(8PpN4MmyE612hQXiBQktzATHzhC*e13L&c$~gm1f){UyM!}2@3Z}samyF{sK`j zw&pq=r^O&{0T$1|+tIBCxhS-WxqJ^dO%J&)xQQz+?&aL{#KDB?uAo)N?Q(qmU-1WU z;=92(Z|C%?<p=Snr(%W;cZN2bhSg>(lrd8;!^+CoKBf$-UA96QE;Bh^SZ&4g>U`^r zDBrr$q!ri2@Gw9>Zl3zx%h_+<KnHn#ch!#U`QIjXWJiHXM|3qgQuvl~DP?nYXj1}( z>0?ny|0W914C`)#l-D|g_CcBCi2ugrssYQLgx(=|oI87LEm!^GjSHPs$17CWR{ZBb za~vLb%mp$Z{lOONm?PX?+ynp0J}rP2P_f5@zWI%-KXd9oZ0ON)`Vyzh)KUbA=8W+S z=}g5aJZA?Zw`CUI-r=&`U7RZkPRCJsK<NU~uogzD94>3K!Ku2eI|IytBt;DT8VR#q z47`XWf*vKfGsS+EDPI<d34i6rl~0N;Fpn~OT><)qSi#^yPU8Q>ybU!uUw1zd15ZK3 zmU4YRV-U)3x+7GvNGQdhDBd`M{s>r`9Coxzd7a#`W1u;Vb5nB<9w%y-(mOfqBPA@T zu6~ps{r0+kF|ZI1OK5VxzIBbic9E~2wD}0-Mo}MgXwd<f3*Wos2pHgwqx#YEL6;e; zmTs`u<%t1y^tL)reCprPS3%AL&KaAtcL$~)-Qr4Y#~}LlP(^wI{fYEAh&$2`T<q^O zA^J*(5S`+t_k4713rHWH2mrt`=F>7-M{*2jc|7=QR=md(HR*^Tpa&br=6%%_^Xf;m zAus)n?p9RWTg!%~U#;synaD=Rs=9=$h6<%pem>jpyMX7K(FUA}W9-To1Lv6NM=t~D zOdL15FrRJrL7zhl-X=wqbtv?<JJ~JFI|zyy=-mgox0EWe?v2IJ$Yig)Ium*&?iiB( z+?mFDrIYmvp18TDS7P{^!2tLQG}hyz^M9h>e=Em)Y;^mtu93G5MCU-~gj~>yT(=K9 zN4`KqGw_V6D)#}_gC9&Cm<`!!2oDTKrzE>_)XPE3q0IgPT9VSSFQ5G_E+e`605h}Q zm5WZWK^D~!dZZiuz)^#sKYM26lF89aWq$k&`Y6qXPfadh*j!Z`or_m;9nSxIUJ^Am zql~_@6<AN__Dj&rJJIpTHc;thyzbR<Vo5eHLcr*PYaGB@bqBE4B>&=d3dp~mT!Me` zXWSY8<^oZqF`~#F<==c9Tnpo0^C<u3CixeCUu;XsHmy(7wr*T7mUmCh_$KeVyT38U zXM*RXM??G~x1aOSr90RN`#g!?fitk0@Bj@Gn1_u|Oec2_?YgW}c~rIyAagL}fxPps zY6<?zSXttyE171v*a4$B9f{fkL~X{#&_}1~KPs3DEO=f;LKs64FlssdY>yXG)4cS_ z->}orp+_!^4F9t~{X4_|lb_=77qH>~#@J6}{t$V8Z|uE^^Pk&ruHL}YiNC>%UId!W z-eziIZwnp%Z+u(n0DI@sFYtXk{gegs>0j8pfWF7xbLnyRo<}>`dp>=gy%*4Z?43t{ z!`{X8-`Tr_{_?*OL#MXENuOp>6?8j$SJ41_FQJ>++f60*et@oJ@8xtgd#|J`*?Sdz zfW24KCG6cuE7*H2En)9<bOC!ybRK(eq6O@|ndT)>*ozDHG#g|0;sPu+vQNCF;{R#y zTL7ZEu0_v$fDs30jHsxnV?<+uF(jw~Mw&qw#Kh4-1mr5}2!k;4%W#gLRCI74WjL8e z&8H?!lbBy^lcwoy;wNbm5DWh5Cz^yrn_$9C4jr0cC4dRxytVc|Gt8h^?`!VuefM>6 zxzE|(wLfR?wf0_nEur@}_=s}m!e7ZFPRhb(<nd8_{E$4Nr32vvc|_qZp@BR;i;w%r zBijEKUM7!w31$5oEPLjv0ELF^96nedL^LzNJW%-?a(`B-4_YMotS3GjRQfsQiPF`1 z^cj@NRz6j&4_YRrxtr#q)dww?e5O&KaDC89$!8SxiO>hFk$hy-CsH4jFZq1^3h~kD zg9;^|KNFt~QTjQ>5;n(Q@xunF4I&VW0<L_eTL0a~2}0tp2-)b0q4a*!UayqgJf4uJ z%GwCe$NcHI@vL(G5)Nfgzp5Ki8#+G~h(W~??lMrH+S&-AdoL1KXzlNk=Z%0{KiCSA z_%;0SNM|8aCl5spgok9Bmz7bTODM{7R0Mx#gRCx?1U1Pt&nu%UzTz8TzFg(Mp9`~M z0O@>_R2qJ&-bxkj4XD(mUwSL`zL#=7#%F5vXUXFkLiQrf8wy13e5ltXsF!D)?^U(L zkLH!vMnIK$La%Co{Ir>o<Xqmq2?hBk319tkpdGe*uU^qcKR$rpkzWSjm+r$a#@p!Q zpwZ6|$?(*K#({<&C%F9zXt>7psuPkaa8=JCBC<J;mnX=$S<tA{6D%@rT4)<Pu|d!# zB+0pP;5jnEqTsa72Bq_mGPI3*j~8R>8+S~oKhx^0mo@erA`)j2b#mw{$mUDvAV_qf z=MWN-><a}v1YrIr!M6$X|0Cr8wzEO*srBN6Ix&#_LdAWRD!zd~qiE9i!xz)5*^U%t z)fHlyb+Xqo>zM2;=a(Ai7aD#4s@0ro)#}{#nd5yXO-DDh%blMooL5x#+b+K-Mm^TH z)4=TDo8QDxXS>p_cD5=MN5rU_-W>);jB<BjIJle8Rl$F=0hR+y#pVsEOO@3wkkzHi zA>Y~sa%Ypm*-Uaj;maMyr7tdtC37~(oy~HL_0j+iG!6`0#IRY0p|$>boCoI!Ks~?# zfY$)_0z3<_dna0f|7n{m<>5AP1#ks$JHYJ#w-ek>aJ#_m0=F03UU2)s?Q<)UzhM-e zie9NOUc^fG0jPEvn8;lyhYam_v~dSw=>JS>FZtki>E9yI9NxHY_Rc;$+Lk&YYM>Ls zzQ6opAC&8O1k3ID2wFPk5mH}opIo7R5{-RQy^Hh-M&9u#JRbmP1*l6^Og&S(K;is~ zwBFaG_5R&2Ys5{8GtgIGK}^yMwSF;o_{D=r1AX?D!ud6#tl5sY2m<q-4bD7(6o5ql z%K%ma<O6Jcg!D}$v~?u75#UCE8xC$bxLR<v;Htq@gR25p1+EfYWnkaXHrfII?*`Zl z@P|kI`X*HYSo`$_c@OLdf4_jf^ZWj9Y`*11GSRBN6YV8;s^~Y<rl;ef5yS(!3;4wB zETBq-@R87+r+}Pm=0*xZ&wICO_-6h?&%HqCxJ`ZO<VL_~<|3ikAmS)Wo1(&5v(WP# z(%`3vDFDefHr+^ar^F~7y6;g1cxE38&)C8XV{r4z11X#*MYPn&wMx5Kk-}5Y(H**~ z=X^Lc@gKCGzIuz!{v6q&TmD?&7G3Key6bb~`df6|bm2~#!Pr3=JVP^Z9uxUPo)u=H zTpPHN7a1T&{VPKHX<fz(uFO`?c;V<C-*(=aJ#;(o0@2{*-SHw?R*e_<%vNF6bJC{Q zZ?wKmFKTO#NZSYppT{NNq;e(UPC}S-p<30P6oEmWk?^8)Cxt^0c;SrAC#jqkCF7F$ z?M7u~3-W{Xj+--a2RTS>(bW8uL4l$!yeamSB<-lFzHLCoM%QJcVguRia2Z}FTyy~H zq>O4q|K~9q@dKcAsOM?o`KaW1GxdC(c<z=w!w%rh*k_5T7#m*r6wTf&e6t_@p923q z_#aR%OX4SDG<Jbm$T)!4&hd@!6jBcmtyaB2Zq2L_*%^e380R+irrXqRQ%AZ@W)?pL zui$QDmy8=$WzwR)RZsk$M`^w>W<ha)p2ST<)jWOh5V>bJ4IE__zSvI#fj#IW;o=;u zrf^d7*ZT1f5W(-pIVA${`o_sElbl!NTh-1h3NCyPn#J_YAdV}Hyi5>YeJ1cgbnY|W zvsWrEY{swR{b$JS<Xk*i{?vQ2%svx%vfTHy?_@c{t7<sTrWC$;$txioPHyU;gfKgt zujq4rH4IhfDR|Cz#*E_aC@-tc@QINrFCw$dHwlkDL-g&SlmXWU`8K{t?!?LkvDSAQ zJ=jb|chC-?OJ!NC$`&e|eH$fYe|?x}Fj3jY2(Q3n4vhj_D?J(eudq?UDcwe;OEMDX zvs6JWMDd0`o0*yeqNX#@kjAg8yl=#K#(*si8$(T5jAj^v>y0*IX#-7bT*G*UO(B%j zi6Wh!;hW1O;`6(oAeMxMteY7o*Lx{_u)P0W<SIg1U+fX#<{BdJujS1%mh$GPrDz)$ z4H#S{?vIxkQlhk(W?O&Zvri1ZyI^*wL@DXrdWbax?=Il21(8i~Zi$*HvcY;bYUYO9 z-Lp6F>fgH-MXB-H!j|7F8E!1Sw~+FCm9UVJ9#9vxXFsAXU6z+FF2vU7^W?p1vl4OO zw0ydnU#gBzS8+k4YK<A`Z#@dV?HMjT@L1M;Dp#`7wO*Z>ZeE^~o3rAOk`Yh)<}2JQ zQ{is*v}$q`i#LPtu9n;tqwnEn3MEek%6NS9bMhHDDtj5f9oY63+(oYphXt@QT)yQf z{2#TgkvDZ@)J;M=KU-zagVZqhSls>9>}#~C%mP}%gE-VU_fB&0WnZIazjD5_6(`@I zy2%SX&5rMG=YpN42)QT7@m(~h08ic+4in`=_euMw)$_?il;+`h8L<;`o8!9}c3879 z9Bs0BX4i$x+r);=TTZ-C{k&%iJfL|nPpGq3%Z-BQ+z1j&Id3_qT!2OV4$;B+P>g-A zhYQ#2JFeNUUfkWFWL27Xjyv09JQI2v6i^;}XWel}yTx&39QbckINNp3hNF5@c*QtC zS`}~Xv){rg^~W|$fmbClMm&`_Ml9K@;&enmvI3YGTr4~*_}o6tZ*#*HAGvb-u<HCf zc=KwnlAEws#w9vi<?OJkO4Qrn*f<Po86D5{ZI~{ccv2L*jS(`cP=|%4>JvR0@R8e? z<uI8knuy2>8upXB;?SQ}^yKyhbRci+^F(;##0=`&f!qH;2KgrC_#iZt&V>|ing9b% zW)@!lUb@_LBJlSE@GD!whUQlueR>FfW$!NtZT!O1lwX;F?g8*?15iDEgZv8S{`dJ6 zg2Ryfij)Tr&L)6zfI@&Z0LuZ)0BKMEQ2YuO#*0|#R{#zGoOt@bgI|ex*2k~3J~Jf0 zGW!|QCm4B03OpAA?0Dwy@GBVm#`qPI?|+J4k@9W>96A8H0Qvxw;H?G-2e{?gABtb0 zZDfG|(*TwO6hHd|@hiT~vFt42ZKY%Z#k_}b1pPprbvtm^PsR;*_RG1*ZbOQU9RsAr zE|gD_@x6jeNe!;Cky%2ek{&UuE|MeWP|9)8ql7HsBb3g$is8s<0x}&H3aGOM%j0<e z49Fxxu~E$rNM)5h?k5y*>*JK=81cCO0s2p`<~W$g3B&NkV}T4q>0>u66cD8h<RwNR zg>YQbHssL={A1TUB=3Jr;ulD>3^X*Ks^05lC+$_S<8f>G_q#>0szBXC)I#LAg3%Or zs&dt!d(nhw1Hv_a&TF`zxWt*rPD*0>xgg;)SgQ8m3pqf7bq5xw@+`Nh6UEF-s&wd& zaM~a1oQarN&V4*^OmWIZGR(@d1))3`N`<M+S>kBzMWQ5=$hCx#+^>l2b6M`p&ZTCI zm@bZ1lU!MM0V=_uvK;CyxEJ3Xgjtds@t+U6IIO?Sj*idOvf8*ws689++6KiQEpVw~ z>ybhytZS!m?#JHiz}#dSDWpKNZv;g1SFeql@Q&dPZ_U17v+((0={UF&m2%g<LM9N| z)@ku3?G|0^d-1s{&0~j_LU*KR*@lrTyB&lZhS)$3nY4P6#IB25C1WS>4tyckf34&$ zFF7M<&%y3}{1NZXV}E3D3?>j&MWiHL?o^PqO%_<1rUoN<-t-A3cp1}k{gPn<zx6NO zjhC;FOsMZUJ@p8GcpB3wiuxn=P`)AOQJ!%rqZ)5V?y`pQwEHZoWY^Sh$)TS>MLHSb zWN3TEMKmzRo%3KE&yf_1p)zuAl2c$<E!sThMrGK#JgN-aHy%ZXty>%&flNk-D>4{X zbI%yziCsQ^dCxAdV2{th6y0FeAJ59(vO*t5aLC{r@Qc6Xo<{{#LnOn4P2C3gpyr@# zc#K!a*~IAMtac%*S~vt2PIWM}uV=I{Y5<D~@aT%58XE@o)^VnY5X7ByrfA#gH&b|T z@82vn(lu`AD;f|vE=qW3Cy~N^VQ1j={+T;{{G6PZjMMDEd8!!#yb`&5Pk@O<N!d^A z`S?{TZZ7a#y}PM$27DhsVBS!3P|~)BLOEip$~&pV5OIMvb|T4~O8H9js5>Q2ZKj5D zaN7CFPUHs910GPyfuD(f_I9qWsyju7X(h`-5rwZ|HJF`}$h3%NpN0!{KcjbX$<-kg z)dRoy-IRBARkk=qgT{?lLipKlW43sHhIbxtpGZl3f{0?dPK^_V<GNF!ZC5(Csu(UF zFzm$4W6vi;QxLz%fwmx<09bI4EBAs&0j+`5t}ufLsayaS$h}IPK`V}#vJ*0BO`J^z z&vw4Dh38tKfH!baX(S20Xo6_Y5n?n&w4py3TC+7s(FxqPv$9R(HZN$87O5>!;f`IR zSLr%yajV}Bu-(aztU5$0b*N(OAp4!pdIKc#{JG)FAXjA@9Sf(N7biDd^mbTNib^TV z7Mi}N&8ocC;?eLh-m@Mq^gJdG7%)%|ECtj$Y@t$%!VxOe)hUkdqmo_3$X6%^3v18> z8a*bxe}msK>1=<IbeR1jT*ek)jWS%u(>#;qGG2hek`3K&I^n8pbyc3z8`YZX)nv~J z?FhI{LOQC*o=7J(c9pYIka5dVsVGioxZQIf@iOw<g=XV99QnZ1;!M{fOn;kbWJ%Tc zY+X^+PtLA0+$nRVv+FwqV#Dw-5EOCJ+4b$&z-V58q<AE)63_Ce!~=NRb`)$i3!6~% zAENuqq@YY&Wm|k@8{6Vm&P8#AHlg%>vTKlqN|F7u17x@HxhM3WvJ<hO$PA2u5?OTh zgWxr;+*aVRCgN*+<vA`K=?Gsef)6_{%O(^09+rj-pc4&I%mb11&3K`_Rruo$^4+w0 zhQo*y*&yC@+9gBuHl8Q44y|r$z3*uIZ5I11U_DTwu$xBFFyZL%hMe|~ub@z><QwAk zJ$yx^-K@e7l<P$n3au<@8`?uW!S0_UVOgLl3kF!Mh5xd2@ZYK!$w<@^G!m7KMxs`O zS6P7p{wp=Ze;d}oe_P8TU>zEcDnr9j8_{sowsJQ)CH9(+dY*?e{VYgDx+=Q>4Wfxg z%{M;5A3-yp$D)rxP0$H6EybT1{vmfS4~z0i=f!O<lc2xEj*7m7m*sB}eHNiiLd{Wj zBcF?R)f8u=&$u!>6fM!f|90|R2VdC<5iY-grlvCVr?@#iA2}PeE>oMgCE6g&q*8zf zq|R)EZy?&(W?q_3EPc@uJmY=M#-9O3;PQ(+;Hw~+qNY8pVi(yZB1?HFy&0jo6ewb- zrD~6IwVLYpi5wH5Z@TQFh(bZLgoS*d5agLUuW}L}Wq~^h+uEPNc>&KX+2e$_kLR=- zW(c8!lJB}YIp5@2BhgY5f!xR@VyOypGXbNec<r3%p<bGO4APBeVFBL0fO>Xn_JvTN zIYiTdc7bTpvMQkBl=@EgPtl!_`$7NRRYIW>_C7wIQ*o1p!n(j+)J_+{kW|WZOFXA$ zFH}`(@onSTRk`i$P)ybURkV*%MXOL<klAcgz`sJs#Zb72?1x8QM3q87oHh~yIE$Zy zoCh*6NC6OS{CmnNWjx^H)tQ`#n#C{;Y7rySDS6qb<2`<k4m{Wlp-Dlugzlv=YPwki z(bbiJh*=I0ZP%V#%tF=yGXHEC#|Jy+#U*khv5Cz>sluo7%-N(wLx0>^%GL0&>c+`D zUBKP6;BvbYn#2|&e7S?DEO&8zWJ6j132rAhK@(2H@G+}haa8;4tF@#BVSa1hj;m}e zZ&d4>aQ6jhPa-V@Z^xhwg>X^YRc>OJn}t_V$4>788>~E&is=Tb0`ea#{IS-n89{in z76sIC{=5w)t8BAyxRn~SYx3&8RsBR#kW0&qb8%Ox2nlxK(iI}id)RO3ioj`AjT)+Z z%7}&yV%tgoNyRewQoTET;kbgJ{<!HcBGE12_FfoY<<(y8Y?Tr19#tpEexEX;9XC!T z&C*okG~d|%6hT999-w*Nc}<PiZ%CwtPvdo8ZSMC?#(pLT$jjG%;-&CW`E_5D@q3^0 zYo$B0*QQvSjt6X6VmU!rs3JNaqwoZ#4CjwtnP#7{mmQ|rXS&kRsv6!9p!^!Y6~Fzh z447bsA7xF*7*?wHC;k54_UVv^pB~y)7sB2WTF*{(Hp!gLvV<?~!3m#ll*_+JXojao zcxp;$1-`sp#+`{hn$XG)L(M*-UEcE%->|~R+v6l8%{yC4v01f9qI07HS*iB72!V-n z(i;y3PAZ8H4lyUyk|b*OPg!J2(x2QgUf47!F+&r3?%|DHDDE5%sH96@H_(MRr+DT< zyP_X}s!)a$O}QHRI^h>eqE=kr$Y}>nX&PsJ|B%Ao-r3`OFHhxFgblM(HlK)}H)@j$ zfe~z_t2z#Cn`q9;63^mcX%o8)wVK~vOPBLL@JNO*uGef6#k(;UjGVb{V93qFMajf_ z<;Zxhk0pB7E@C<;!P%_DLbyHB42g7EH%6$(2%b)IRIn&YJNyXlwsXVaUD<Q-ke12l zxhSb&%8v?H(5H)vvnwFT%V&8)7CPb>HrP;el>25O4D9HJG~cQ-)1SP<bH!MZ|Cql7 zR5X0r@ri5ju4bG~b^wJK;d?U!-7`9ha`WouAPgqVd!W!VdK01LO6}I^(8zqFP(~*h zSc4<<A8wrlAOBKe1@g<Mb6lAbo|~L7vsZowgA0XJoZpIDy7(~6#(71qslI~W|0zxN zC32bEpg+QW0L(;uB?=RcKs6htNGJ*xn-4WLPhz>5TC_O6yq$y0^rtlsm&j4Oqjsy( zrtq{=+B4E?=ZdXEG;akWRBmrYQ&w){SL}y%W?A)n?CHAU2`alX;n;@X84S>foZxvo zzA|EK9L7fLPlooJ<kSEbruv$u5`b!`8wLqg3CA=K0%0c7#1}m$slX-@kJ=32_5q6z z@JjSK{im905ys%VNZHn$-)f+;%9l}AdA2)cf=b`Kag;C}br&DTBhCR?%@_93lT3e_ zwv}2oLX|w4>b;OHD(xYI{Q^?5k@N_77lYT2@GFP_s?vu|&3X36Tj%?gKUXS$jPMdF zJ?^U!*?$WV37&El3UnV2BHoEI+$4K%x$Ic<I!6$qlDttw?w}=Gc;++_jBXVkM>TE6 zmYnuC$W|S2!j=AF(WKw0Sac+Qyu&UNHUZcM;3k1n(sPll8EfV?qA>J@EEF!i9V4|k z4@aQ&tVhW?AV!FQ2yG;Snkf0j2qNlkT2O<!o7UrrC439W@kJ1JKub6Rin)#)t3rc~ z$PmUt{A^)l4LQ$la$Ar1Nb{SEt|4_ASwy5x`AnGQbVT-)3Z4?F(>3JOGU8fNr+!oP zM}>fJCQi|3ubQHpeN*&JRe`hYla3*#=tl=l(I3DR{k|hGaV|~lxsMo3*TUK`8fV|7 z(kyxx(aWy&+#{C5BHD@GOT7~{5QbOCB#U$O1mVXH@4@$tPS+Co<(Yz36jVYyv8bU& zg9ChUoib!zB0I6Vo*n0<pg!W8qJuC&L$AE21!<{)cbHGfG@s3*vDs5FPE+GU*kR5F zrNJ4`a6MTDo6;=gY^VD0VR}Z*x3*!z$Ixk>5oRF|Z%v}cdeqvE>fJfdlwjW2=eLlC zQ?X4~ZWmN{qVUkRz=jOp=Gzx4&EjLSp$wpuGi-@j!dL~h-tMaG021DS3}bA4+-e!o z-P*ectDp~xL_#!Fm;*iaJn?Dd)?nvF#ZM$8X`~Q)g&fh}D~#OcZE3Hv()iq7P0enq zdhCuW6xE<vu%EahXnJlG1cj3z9Sv%9MbP$lah-ta>(OZ9xKCJ%s#SaS-{ovs8b66$ z?4JFOI9E_Z!{tCB+ytUp2wK7wK?qPjRf(^i3*560#82WniPpz^Dr`1owxq0gTNNcD z8`(_HVuI&q3@Spcl=pn<ULe;uYaW^lX^0+IjT1Lu%r>QzHrbn2Q+*SzESY_7^#RvN zRM}xtxyF%7VjFGZxjvgLi|EfX<QU9Cxr1uhg63Wcbn9!9f3|SxeQAubVN~XG&K642 zntJ)>=q81+qc+0O^U;K(J!hsKNr#nj2Hic^I89xmu)ESr8)gev9JERBT%b?zILIMI z4z#JUtGy6OV(@+6=L;WjM!%%pQMxFHOh*zqMi;cN;J8f95`OiX5AT~HAS+ui3`V&6 z#}wgaNwOu^e-<HE<{rr>rQ(f3ZidjdC2*V;Z@Fr=07Td<p6kNh$OM$k7f{JoPL3x@ zv+qoI%3Twc?07?+HsLJ$BhCJ!ntkszTvQD|7H?8>!_zzyHT%!RXR6sSLxE<W3c?Fu z4rvA#!$)8-W4&DFh`>UxzN2@S_l_RW$L{&!ibk)B)BGr)66$~w%HUgosOFb><!af{ zb)hH|dz?L0eUwd?gl#>;TeA7ahR?NG!&~^!cTq1Y-@y089#?cKt~f7=s3P@LY?Jel zvg#sgN#!D^5oM`o(UEbgsxOeW;0~`^y#jS}&+kiUWaq+E^mW4L>@C%8?3XCH+sKXv zuM6N63|{9vkFQ!yah~4~>A?A(I(_Jf(@x_KEur5s$v*j6m_yQj9N0IfAMni~y14P| zr@Tq6KhC!BGWdGli;G}SW~46_MrjCdIneQuuw>xTlC6Ka%h=({Y}0qbbSyp~?SDVu ze^OQp1S^()d5cOvha8pNBE0_q?xG8CJ>WxzY;-64kZDg3k`C{(uiDA4OH-mQiE!az znhWPE&SR_kmaz6_S8k{NtfpE8xpX(kH8rA=u1j~<8KUI%r+aIS{hD{`(`?EdHZqMH z!5`{5y;lbF{%8HJOfA|SgHH;zC({6KiZGRyHS7WJJV-x{otx=eHk&_mMsS(5`UblK z2vp>T$8RCTDo)*#gfp9cJnu*3Q6;rbAvxE~AZ9nWpaKhxD`mtClxR4tbuAk)lh-It zb|)#*Shj9qkmE`yTa3q9>uOcJ#vq!s&Bjh7otsid1ck=s_Opw5P2Hjq(=cK(M*NXC zqNB2329f17^0ZK(8ZhQ`j5!WthWllyps}WhX5h{%-Uj1C#M!~(=$RMk{rMl`@?sM7 z$2AX?EAZZ&R`Zi}=ocb0b-Gi6mEDX(Q;m8fp<JN7#~=xPoDJhmU5@xrF36!$dK3=b zcYJOa%;btjSFYA&?9{htoG8f&EMuK)-gr&*tMD=}j8)evl9Qlu$sIh1pQb-jG1i?V zbHs&mp-C9hqzLtJ(C(fR(WtdCl&yCg#X!8h2gLAX1lpTn@1Yl#)7WrFr5MT{Y*K{r zA$2CPc2RJUXPQ2@iwh<J&)Q@*5m+(kqZXn@UQ4`{5I-6By6~3#0z79M&4<w18?cUY zPf(o<aOWGNja}FQP)AJ-))3necNy-h8(w{MQ*d%STDky6K(p^C&@R2oZKI%Y`-uBA z`-U4F2U{nhw24qRO0(~n<{cNl0v8r0Y}x2t8$1sr0Y9Tuw0I1@0TY!Bba!of(3W9! zqj*j2vJumgQP-*WZF+Kai|3}EmM3horGyshKTB!`OjUGl*BP?24x_Tm#z-m$I>=qD zPH4Q@UZs^&HsblYsRQQzF1=BW_fRq)Alu3v&fb1a4KE}8)$XJ&KQ{I#EUb?;D1Zp* zbS)Ya<7t9XF#<+Kf%E#qLL@z})$CUlIIqCS_z<_0omawGO@V88a<ahyo!|aC89SZM zhJJlR#Uyu{oa7qjtOpujYYQc3_Bf1)UMHhgE)5hpUa}i%psXMRCDS`lW)wIpdqdfO zw}mY)a4B%G^x|N_hb!<fjSp!`37#J6xeW(T2#s7rMo&Ms@ssb7Hm3e6nn|*62%+*< zPXw=Vvm=z<!8n9Q$UUk8o*}WK$=%L&V!V)GXA4?I_R~1dcRE?g;Q?ZM5z@%LC7PO? ze&jql+E?}y^KEFP%cd>t#a%$2^OJEfa&+dtjq{(mQBPBV=J6>)Bq>0U`{L1Ex;pk+ zG7i1cu_4Mh#8VlEgM=$EX(t>_f(iU2OLBXi^%>KB%`8m*obG0z5JX&{W`wO*{4^tM zWqs9tkmPf%W39iil1xO==YE@mF|ZzW8?_EJAn(d;t<CLkHlD`G8JK8xm@BuX$tY?) zq0L5=6=Z62MYpllENH@rjVv!!RBD&VIPC${cvy3U8`;yq7(y5>DBjr0Djg=#ffm>l z(T#XISx=N<u?y1JS!wKa;cNvtM;;*x`ziu%@845FZ|~z~l`FH?Gp@Tq#i}4@26FzY z*@%`R4S3wt%NxUOTC_8BH^6NG69KeN!NBc_uk0n1ey3-WG@W}!OS8X6Ev*@Njk*)Q zsW%~GX6m7XxM`qoAg1iM>Dd@q|7Yr(*~y8x2?NY7q)22SCryn38o1fmK{C4o9+dbn z9Ue$I6B7}0R+GpCgR@3|NK>Ps31sveZicxKr@&@*3?HTfavJDfQv^(dArOLb_8Qom zs!Uz*q^vSQb!Cjx)T#UxiXO0vVU=Bbb>485Cmix6>abqgt7Su|uU2^eA~6QmD{|un zo88;cCOZz82#7&u0z6kq#2tN{<*5F3k?U|9Ps7XyoOCaaxetjsYLP1edJ^p<)lWSF z^K3MX9T_{V%G!&g8IwaQNPCThv-!D0-FfKu&Z6h<M``Ha-j7@1?W~d^W>iNTP&a5J zm-2TrKwD<J?<bocZB!IWf0=ttSbaa%7Nu}K&%;6hE15|&c!uE;fJ0M-vF8f2KS8Z3 z{AoO=|2BvZCpH3e8d`&MU>S5Am7%uStHQ}SzC6mIbJUu?cUZqqt2K#K(PDQ4Ec?HM zkpV3vXYaSkou|ZXDCT*UWIj;PH*@2J56VTcDh`!8u_g#@|40<uzlHA>*X%yCIJY*p zPuTU1mo*>nsO%fh0WT~(0V~y9;n`r484S)wpqu6jsVeXL@4Jm6AP@rxyo+DrLB;?B ztx}8E^;)Mkb3wyQT90Cw5j7)DZPquiDTz3|*jp1B12{Lso1DJM>6?-vc65{sH?hgs zFY}DWuU!V?oQ#8E;3xMeVEX7WYVrHjRKJ0GKaHZnl`Cj!_L60<_aGTK4T<>SYO42> z4+*D&jrs;nO*M(r0n6fpn~7|&e8UJJ05-%pdxJDJ1*q}z9b<p2n5L<o4lik%nx)`0 z8wIf+9r6{nk0;8)NMppEAS=x9Lu_*f@wf#%yw)8x)j!2nR*=ohxxyV?q=`uYN0tmZ zyB-FJrsg-0YgMK2^;_>UTn^T}{Q~2|6OY01cKL&A$>D=i^Aj|_CY68SxKzHTI$0#t zJ$66!1T>(inw^Mp5HY7BOhfUp#D4gX8wU|T{SZHe7fPi&l6+HpK2$9c>&iuD*yIpp zdGLUiGnDWreUL<oNu)uZC!l!{b!kchw4<BN?vzAQX%zDCrguPkMQ?m%$F}n@$d3$2 zs^D-Z!YWa9s=G}6j*Hu3R71r;YE|3NuC2cq;`nS^=&@Q=T<-VW6!-#E>;z174H+1v zL#5*@>6F5sB7<oQnN&9TK4NKFu_<s?srnLU8Y(0ZNsk-{sIZ@xkZ<_f<-ja4S2*=C zZbR<=4&u$_Px@7Y%qA}72uT61Exa(|3d%p0NCG+CF0K_%`Be05aH24*#Jg0}g@0$U zkA1YmnvGgG40N%^CDRQnu&b9I9~v)s*XEnZ(eed-KRZu2Sd220o_Axr<GEHgI-a}0 zPK0$ECp=SIfDns2MMY}EwF$pCPu6nCe0Yi1o>qD~9tCqMz|mS9cm({{^*$W$#RK3^ z2zF>owoeig7q$?s_~CeN+d^h=sENuZ7czrzHtyp)g-Seo;CcnFjO?oNO{)fW>4;jy z*z>6R<~vR&{Kxu07Q4h(e)~lkQI~T8k24$D_j%kDI|W?!@hscQY#|&-5ZfI<lL(<| za#96f8@1tcnJTEaC1eYUUrPoyFLM>y!onx1wKxUtMg6seZa%9CCYoyeiVN8;1Cy04 ztZy8&sq@<+f)(BJX=xY~x|4>wH_D-Eo=|cC-?TvvMVUH9+pH|1aJXc`cV-4|JK_C> z9HMQ%gRG;JV(Syu^h*?5XZu+a&?h|p1VuRrQBEk4!cnOQk@tF=M$0k_2M!HFs;^K& zxlc&POnMcSy*a`L8$CnrfT=dRN6`sXM8{;*%iSf$K-KJnbJ<68K?_Dg?l7qq8fQtD zvZ}JH6;f6n_Dm9VHtcUL56lgxcBwG(qu+b$f^WqoMD{L+*uzDXR+LcXAp_QY$SHJo z?0Jd52Xf1m+a)~Sgx2>2GAFw-Q4I^5Lncq4QXgnSEkaX|;dFgPWRr+Uh&H-&!nc~* zCTN&#Di{h6{sEreLUJer&CJcFlC#v}LLaP`V}-mT-)_V5B5WP<brZ$hSPB}9z;njl z8gWbLHl_ZuUCB3k&_Dwn_`)kMd*?`Y?h{!0rr>R7Yq~d{;w1t{C8Ux(Aij<9p@4eE zW6u*_R=A9<92dk57d|NT5+dX}XP4(~{de2$-vY%}tj`#r?YI5Wf1N_RHR$_uyr>3Q z$3O|xjB45w&;e5qxiY(O61-K|=*wQ%Rybf$!4(X+PUX7Dc}_Pyy@IY3Fw^jWqCO(L zQTs>Uz0xeASoLNs7)#I!qYM3*B994=-N^Q#blVlaIFTIWV6l=-PPJJGDwJf)Ck%b* zwb>`hiej-uRvY8G!|9HfT#BuZsY{BI*Jo??ZB}aDsjvDHNv$)zRo@|b!<xYb4|YDd zNX$$}7wDHs=mO=E=vb(9@S*NScShBXbbMCjI3}wd>A5A)ce~@5+#@(F%59#ofe^<O zM-A@wb0LJq$!)|gn8wtj9(DucXE~9GxWd%?mx92l*Iq!rHQSiwo=`q4A0--9#Qcf$ zeH79Ij%@fYfXjl(a5Neu)@~gGRLEAKRh66?STPwYvIbrzPWVLu*@bf!1kSL-3w$%| zt1vE!Q89O#EN&bd)Wqoc26*>m*-}<zxsAIs%)+^akPEk)C%chIIbLR?-Kp^5@u&UP z#?K}<d=?zHa-@<AUYrKAZ7Y0w51}f^s{XrTfh=>P$!fl7eSMI#URmHW9@Ffv$5Z@u zh4d8v1fC&iiDoyTWQ-@=X-fB&7^N$>cWXReca~`C0n^-dW@YywEvKp-3Da4KC#ZIu z6F4VhZ<4cF8PD}@IR=@;<%;Y~$SL+c97E22MWvGO_b6<N)%p)B)sR9Z&QAh-JZ&%y z;vS=5vtpCEjTd0O+l^{<P?-{)kva)Ip(Z>89lj!Wg6|b}Vhy0i!?J~YtSC9K+*zpt z4kAN%AsvlGB6)(x2@`Qk>;jN0D57aZ_6J^+m|bp%Cm7Nwxe)aG0M$@mz{A=PV4fKv z9M1PnPk6c2Z@M)2$q|@PC=RC2cQ(NS=C15~@x_7{U8ZwHoWx~n<xSx)*yJwb5xy5% z%Ov3WYHo)s_wXu@)-2rhh=|6J(WWFHk^@Ui2P`%&?u2lx0B?b|LjMGV?^K{bVK~k9 z;Umn;_urho1IR}_nuN;1u=&Hs-eV;o6vlA()8%B{TDtYImPn8s+(m?*7UZ}pPsitW z;7Lt~@WL)6GtrATp2K_0HdshuQbtT`QL4QOMn;H?4<?xInMaS}l7)_kMe%v*Z4O{9 z&c)l}!ruxA>Fk=6<BDjv%8B%mD}t{)!iVs4kz}|8=%==45`AE8KwZqJQ}LaSD~asn zEFoeSxisG9UL=!|lH9XZE>m0Gh=k+Z1ysdoYVkzJEtj#kJ2uG^xLX{X6p7pv7*S^7 z&pS!d7N9GG_%KZCGPWoh9C3;4N#58JZEWMYbBbP9WxZ!IX^dAOfti@Zn=6bBk~C?v zCa7-wB<|0O%F`$t7H5@ugojR)A^LbE11a#M&T&l=9$)M0ou{#_p$TXYwHFai=rGyL zc-_o5;bGbdbC$5}%|T0k;~Gjh+%1d)lyFqQ;PA{f16Rm1-c$<*r*ivJeZB)auoKcW z1?y6C_z>t1AU}oLRbuTVJ|;f*9MyG<BH+*nr=pLf)AmsuNzW3xA>ZiAHpp7h!&jd3 z%;k;sP*?G8C|CyNo;f(E+|j;r*Q1D@gl_y~t|>nEFt?7cJdJIdohAHiaLV(mNy@@C zpBoqmmme4u{uT|#fjJ2VCPevk|DY(lX%s~dOp5RY3i=pMQ9CKMc9JwKagX=@eC(Nt z^T<(X2U0&BLT)~xeqadotzH%Trxn8eX+D7ki87B8K3PNd`wp)OTqPE*@vRb>Jx28v zT>8(FB{fdsb;fvko!_oO2GO|&i5kz0y;|<(y)t%Ew^1!;BZO^haHQaNkYHKk+x<A> zzu+L*2NQ_f1XD$yaAARDH;<bk+_5HbP1(QtDkYJz^`84-k?zDp%W)__CfMXi1!0_Q zufoU0*>xi|`wnUL^>(M+JyFR{Nva!}aF!jd+4n8V<~7F~)!b-zl89zt!{T%MJPPzt zxJ-RX31_*+)d5;5jeXZSvGmg_8lOw`xj!kBWPUpYW`R%T=kx(8tC<{MsG$%|bqO&@ zLa-*bsF91&e@C>Ca<hcVs{`BPm#eO74=VC84U%RRX!dDDla`#-o>|bHBA=*)8nMZB zW1&(((AJ*i4Hs1q>%D^E$MD3Kzq9}%6zI#fb~XHe)5hQeMR~YqE<BI1$H4y)8*c-j z@t!EnemsMhcPCBMvSE;eYa(un>_6&JX!ak&Ja`UQ3kVq|8r2j79|A@`Q(bqH7l-Tt z9B5R6LK;CKji8W5P)H*vq!AR-ZU_a;=Oj0!0KS@GD1BYy0dg{M?2v_SLcOz9o`wOP z-U0LFRdR$=uW>iaE5C`HX1(*M__tS`4YHn(oL|f8jOy><tyvZq!r}qHoNw-1eH1mT z4*os$EyElDI0?`O&<!vGh{Py>c>v1*3IWOiwgc<{cn;uofF^(s0NMch0JMFO4!{7g z3cwDq9pI+`PXfFI@D9KS0IdKW0Q~^!?-?cnU^+kyfB_&2U@d?h;7Nej0ZssX0ni69 zrXR`zxC>wrz)Ao+z(WAL0bT;w2har20?+}_2XK?fFgF9t21o^14qyY=08kC^D8R1) z-UK)X&;sxmfIfgIAf;mf3;;{X=5XMzBf`LZmSkY^?=vv{%YhhPWAKID_ZtKAi*bgl z(iB*VimmxNwoJFq%Id6}idbD<S-w?QU@t4tmD|hmtQ8frLjB|A*{v4V>K~??R>8nO zCb^6&&exTeVLsM8^aVdlDS8wXmFDZro7uv$QWD6qmbJxJh=Mu>rcNm*A+sQaA@9C) zW#!gV66^MgJbO_&JF9&2MkvQ_1Vqgg1BNMKDwsT`jIlFT_?yM#GsW=7Ff*7^h9l3n zlDf_)<%)~xBOU|<V-so_MKBXA*D8%hV-Wu4#4u(OSr=zs9-?CIj)}=Ohd?EDxV|&0 zHHB;7$1t19H^EN@F_;iWr2<C<fB4GmostBdoJ7iz$rZ|=;1JcY(BbN^5gP5tn?{9? z9y2y#-1rHR6DLj9O}Tk$)U@fh%((To=$W_Ax+CV!yJBb0nR|C!e1d*n;*ahzB+XAw zF{Um^TX^q%i%g4`nA4YLEX&NwUY_%BD^}*NTD``yHZR{=u&%Jkw!XNew5<Godj-pF z*tlu)13%tUxpf=a)-{%5mzv9pN?EHN#{y%7@v|8IU&O>RcR`D#z|$gvZ;CZAZfbEw zs@-ZuH^a(iS&BLGyuj}{skpc-57XMYQnskXs<YbdWp*9IghA&nTeKu2gZkhrld*8| z0>4)#Wr-<i;o<?GrE_CqXNQF*mFg_z<;6vL7Pbh6OrfPhS7L!-X#szhwU(5#I24P^ zEHESst-55Lx9sAgwRVerv#tp0Y`0tU*y7EzLe0fiONA8%b}4JgV@V3X+;6GSRdD6y zWp)U$T1s>UfP6`r-3ocYV+n~fi(*Uhiwz6CU6(X~1_ybYG8QiK`*PUAq6(d*qQY9T zws^BHpR*U0uG5u5RvWA|R#9mYTVyFNdVpjfx(wsPH-acxA*F6Dw+`NQo69)6Kd!TM z3t1gREh(#Dp|0z#kULh#Zmr;o;d3d_<ynf0u`p;U#Oe0DvXXN0>CU(#uh@R8u7E4e zBW+6Xv<x6sTEW`6JQgYs|43j;ak0r#MC*?Az6<M3KJU^pZe5|SqTG^aCCvo`z)~F0 zVE*lO=b-lT)!j-vZ|O4H-fSTtT~?ZBops~w;l(Wm%fOrvzkvesrSQArFq|tTvrZri zg;q;B#TMh;eVsaPEGiq+Zv*M(4w<fk&A(2%Ihd}TgW7K>va_6}c%Xx@CrLz%H+#tZ zSC^IIw0#FO6wcmcV)f;JXMAA2$$W}^T?X&@)(u5@esQHXvTiDe?*>K;wv7L`igE59 z6sH7+T@hOdYeGJbg7t&r58W<OqI?T$f#_kh%Ljk-cI*9|wE_#mk+M|!$e|)IJCzib z;zCq}{f)z&E9EM%0XJHHz)v3P5EDOS9jv9$Yh|S+)>0N?W8AnQ<67+NIE+}~%a?pl z1u%)R_`#Oroa;jiv%u+%j$no{73JB>D#{92T~-mPWpZ@1uRRvgNe|<NLhM<yW-;?% zeO_mWs+C$G0#~}ev}|MPkDy#Bi4nVLN@%E=MoZ91^Z;-w^~0s-iSVqHo*(yncEhtu zdj6^3^TU46JN%w^`aSRRdw#_4IoRQN&{5@p1zGW+<H7BY@Sq@Ak!xyd0HK%|huKjJ ztLuzg;>_6&SZ`rbHk<M4jc$gc)&Z#)Se6S53stI+P37eq%gY1S<A427x7^^r8NR=( z!>;~I14`+7f7RFc3ye|a_b0o-KmYXG{r==P_~%Wl`)4=*|A61seOmb6JpyC{e>eII z7y+_@Klu&*4UB+)^zZN0AOFJP&;QLo?1rl>)jRP0M(aCJ@4-GY!Z13jwmYk99{fqI ztB!xj{nLkc?A-OpqmMoQv)xZT`SYiK@$@s#?s@L{7hZhnmwSKp>z7~o&8xqC?RWqF z``6#txBtMwH{bfh+wZ(v-*Bk$@E@C+j~qRA{KTJ5o;rQzy|d@u|KP)xk3K$s;m@CZ z+IsP`&)fdvi!X)tzj!+S`qkH+m;QFS>znSL-YegJ*Y|zD_zyEgLo+-##1Q?n>;KO# z|G%6e9XkAfMEj?uC6tsT;I09~<il^K&ICUlK5T{`V=~>5pMS?@LQ9!V43lIcJTdTb zgdJuUmu>JpF9B`|A2Y1wtk*M%TgO$f40A76O!BxFXk~Ph%I!tCCt<SK^YHq9s&%cM zlW4YkEv4iU%EA0GU(6Hp!hA3fNVggD!1S0F(=Ztpmb2$uNFJ&7BJ#AXkh51ve%aRi zQmgc`jH6GcvQpxa!AY)##k80X<6}IGgW(J?`O+RsHn3u48#7o!7^8n?h1I@ftqpj9 zg##2b?s!1hB1;9El!siUxvZQkCw}yuX2X~uN6R|v{IX3+OlF30Y3yCIQWh;DI6={X z0U!eS09uG0X&<OE)EpWB+5wsaS_K*h+6bBoS_~Twe#uJ~FUedM#moYp7vH`6Nwe0H zY{0)HpSUZbtj)kxlq@YPW9jOc_7AMActCi%%Yc%o3=_vNuN5)Ovrk+*E=n7rdroq_ z?-wEr0pUjmh5un{V0f)x__xyxOg{oV*MoabddBdF{NfePF)+n*4A;eDls+*0^q}yI zgThY?3SXaS@YVJ1M8lBfbpGi2cuX}69d1f8Fhxn%PoKNs`glg)cm4D~Uwr-WKbr^Y z*5UWuGAQ0NO9#SUUOIGpSaSl)^Ur7a3Ij8F#n9oo5M~(^UOy=R1FHhV{rfd-wSif^ z`ug=fXd5~`y2pyIpZ?_L>!<&u>iXgDZVwC}+@G&McK!6G-PaFq+jD*VSG*J$KKT2b zvX_SAFZY**A<Mb&>h<yHJ#_tg{`{DMS$V}*6f*`lv0IsI{{D5g@{gUZER`*=mRju= z)|yOr%#vAqv2la76xNI;2xIXSA{n>Ky(bZ+%4|y!n_6biC@Ni7Y^5tC^B9v%&P=3e zuuT3|kzr;1GEK9T<`)C~@D1i_D$D1Jt*J%D*2R_*E5!boG2(7~vb~5c%Ci(_Sjqk% z!*t0PSuGo^SNVTCkPFQ?8|FJ@MzIxWiks!qs-BdeZznhh$@~vf$}w$nSxE^bTvSvF z#m~bOu=Lwmt{fNpB&HLwr#UB=ao8F^qH*%6C$uc)f;CvSx!lUU3zSW<mAwklyOqnl zyLi49{52_`v)iGSy`E{x%+f-VbG~s?9uQlQ7&0dZ6qA*J%aFkz$QM?mSl4pv)>-Xl zs4jNhmokY)AzNTDn&fF#OF22@V4fq-^gv@J!NiPJX8tH&h&_NCoYwq>rFnL12^j?q z{{BFPc>OalZBnwCVZyOxmKaU=+zQxaS&EDD$(R8Oi20FnncrE;JbaT*Q|`fM--$~i zz7Z6=u<iY@f7P$OmXRIRg+Sx{OqmUBO~w$@Enie-$(ObWVKlu7ID0q02lYr&X?{j| zQ7P@z`(#+4abSltgT+$}7{2vn>|YhYEE*z3HdC$4F3Pti7h3Gg%1pRpJbyE5We#0C z9~iAKkba<F4Z~QJS#)olv_Os`owM3Eo2_<2c$VhTK?uEV!?s>ll($|Ql`mgCmY{Jm z$XF%h-?Ae3zADH#g(v1o#ZtC7vvea+sm!kk21~89J63rykb0+@ekJt#g`R!f?;Soo zz<ItbwV10Y#JuNo1qD_+jO{Pvi;_*2a#~I3iOC9ITP!Q{HV`BD$AY#n&~FRh@N0r} z$$>r)r=5&xatK2|QRYh=Cs?}gDDP!bqYUVE;AoiS;<5^9c3>W&qea3$iFwkmHcL3R zoMTBH17c+}!T9C*ee;{8Sq=+LVlo(*M9M98tFN|Mfj)qB3*zY4|5+A$5gt?|G4~ml zE;cR#z97FCn5I(2QW)1{Ff;GdH2F&k==*f}0GERGgPGks_aw1U&{~eQRwP|}ef-z& zpZ}|mPV%`je~||5)p7A&(bZB9f#CpDK&!v<9}u^H{r>m=7Jp%Q>v!YcP5BG(*En{H zKLh$20OdU$q5t>!;y6VaHSd^ING_hC;dM`x2t-jpG^~PR{2>4+PpXpKVUimvg$?%$ z8zZGfS0m-CmHb8m+#~_|Pm%oRNbgC~d$ROymeMSh{4*psTgpF2D!W+n$Bh*o08F&R zw!K}#HCT%8kZ`V&-0f1hQwpz^^1%ytD2ns6^u9;J=LM;}UrPS_CHziG;U7xj5h1iK zylv)fbAOllPx=oP{-2FMRQUhipLWO}4c86%`=_G)gZ+j+bfDowZ;JnO@%|xy|G$p` z>G%KmP$(P?beLSJdI1)!HQP6DpCb9c^eJ`syhz=uXK<GXxRb38;_ij`4bOl4yl#km ztNN*HklZ(JFn*Hc?t}QJo@;w<Jo6vV3D2z<I{&SE$P?;nO8<D($2w;9$F`5}x;p;Z zmQPx*FwC7>Y0Bci(mlImDg3``?%pvz=?8t6F<0Y?_MyGMLXUyz{Mx{jUotSYkx9(% z@l>%Xy4csE^ux8aS1^#Z^aQxLW<LuquHh<h@gu(QrGc!)uYim6MJ>3az+DM0(lk-v zjsv&v3j;GA+{55b0QVtqkygkDcM`ZM;7$g&^*;=Rme>m}j<eU=48#hT7TisUJh*sv z)%m%B!LO$kTpVl{z{Snb6X34eePe+17t&FfFV@M+USRv!pzn8IHZYF@>;QNOpcbGS zzyYucpd6qOU?qSVAPrz1KpenqfEa+805brh0CWJ601*J;09pVwfD)khZ_p<I!ry58 zR&ZMYP6HeU_yfRe051SM3-A=c4uCBH<p9H!1AUHtIt$wr`uw3=|2}M!erb|*npuO! z54Mvo=#g>E5Wm6vm7|=d@4Q6!r_CA5hDv%vKXb}Imi{!<OFM~<Yp<XGGk)X!(wN7w zs0YBA7smx!=0L@)=KwAPjD(8C04xT;iz(hT2@Iu+H!?&njzJwyc$55Z0C>6b4geEC z@&5t>@bAf~$Orut($AZ|xXZxg1FQsC)@8VA{QMtKO9KQH000080GS25P}mNu^oyAQ z001Td02KfL0CQz@b#QcVZ)|ffXLV^UHZ(3}cxCLpdw5jU)i8c0Gm}hioCFvMHyL11 zG>Xyjk}y!`kcpm=iN=bGii(XQR;)BR2e1Mro{7z5JC(M!)z-Gw>g%o5S8KT{CIoVU za0!asRN{RPBN#xFa6P}Z)}Bcw5&FL0?|HueJ{~e>pM70>@3q%$uf0#{ZObLABuO^- zGfhcaC5eAN>3{yW8~z53T{B2}JAKQzRhHnEaWm)LU+G#<@z8x0cR%PVzx!uDdq{Kr z<X%^W{xjG8KXdu7ztQ#JL-*V}IXgSU9j{};oiF_9zN<F1B>sHI-fX#t!kb&Bz;o|{ z*)8SpeE7lZT8im;SIdL+478-v^Y)gx@ci-p<@2z70=BXeNxJ88n>6B0c0(erQ<@-U zrld>Khww6A#I@zaPmbuaMT&=0B*~6HQr}ZrU=f2PlB*Jh5|1Cg_X|q4T#Ga*dGO{~ zBuB>oVvzr*f1Q%FJmu`kleK#nYw$ezK^!3LyRCm77eF();-0&;yJ7y%7j;S(z~A2f z`F!wyvdAWVaXA)*F&T#SSqA2-pS(b1q&`Alr7U=k{6Rk7|3Odx-@pG0|J3kow?hrj zcju^K&7G%)m$+TZOywr!X4Uw{6=a{PMyu(m53rMKaPp44u6DOa{OJ}o^029vx9~EU zS5KGcV6gn#CTYAHnPmyG&Kh&sz4F*9tY48=WL;QwY_@JQn_}lx9UHH^YPyyU^|Pk8 zW~*#7JI#LzHK^A8`CU!c*{azXOYw9;A=`zjxe;Ci-h;Kp=8{!VXmC=Y%S9oT&3CIR z)7)h$TjHM8WF6mBY>`wp+wBXmCe_&BQtnjlP-Zu_CH`T5^KMbAznKGzKxOuK219<& z1~nXVmr=|fl{LsK(p7dm)T#|xuA22#$1c`wO+IsWog>t$A5tSBH<F5A<O#Pg1)qMm zPmRoU7XWB#*zb1n>vMrZEO8e|a?R@!1%0#S(BE;m|3l$zqVQlSECyYTKtULB%G2Gh znk}l?s#;sBie~E$2*Oiyid1h)MP?K9gd+7=QnlC+5cnX#)(q9-obdhGl0?(F8dolV zA_D<?it@z<CnZ#30()Osg>NcrQCSaPn~A|@l|3N_%+tml2r+xsU4`$}8*pUrYD^mM zv*Q;IH+4104yf!zq|8AG2HoJ@K&L&X%8n}GrINfZ6VR%}^MxAD<M%>yHT9ZP9_yDN zWrhXNgqKmI-YKuhhgV<dpmw`YUblr8ip=(snlH3~uj&*cVsmT{gvRT`d|k~JeUPUf z66L4reU~2evyOJN#?%G}Su>*AR^FD5h}P{fvC8LtwUbrA<3IMx@=790Q>vtxB~qZg z1SX;>5WcJl3!MwV^EYz{jNIi3c%RD=@K$*NNv<(XlaO`*KA!=HVbmtowCaOd_G9BL zQcbJo@a!<1S9}DN8|MwOPwGSV`1t1_zIQ;XryfUij~WTO7x*LB%=7FBzvJ#CD&U7E z;b#{9%;6t8Bq?$WEb{Cp05rgx1@j=6={&R#QFb=u1q53Vgt}EM;KOMx#Gir^PiqNa zE_>h83a^t8<t$Y6wSCm#N&L7SvCa9~C-_k3@Cq9OhWOJX5&j^gcQrDALuEmCnX$<X z+kXeOn9jTQA)*Db`KJhO)9FuC`*%_8g^6lMou%54=<vY!wlm}FEr_dv5=I54uEp*I z*r`A{2VC`jtg<73v9P>?ksB;aM_$XOZW0-fydE$cAjxlS4|=yO`6^Jp35JD_O(Qtl zK9;0Xwh<Opkah6Ea$?Ox&7xYUGjhMVv>?cAp9IRcK#|`;k$|<0e>n)@pZZChNSKYZ zX8hJD6kD==03HR{20|e~AnK&=##@w|6-0<xDMSF*X7>`n0whT6h#$#Nu>2U&4`r1E z9rm=E&f|NM=~97Ms1bkG#fVM?s<&Zbo;+5nDx9q4P{}694iw9~eo?H6rUJ@RNzV=_ z%j{D=#(}`1;cHB0_rPoTnl!!(Bv7{7=rQ&2e4ABJNT6cQ6CcGVb~->ADYizBSp?N8 zfTw^G2vqnVZj^@jm^UD?yhV+?lZEMQGoMl0mt8eCspfjsyQ@-`SEPjMHOJHp%{Db# zk2a-9NHHl>#QEq)ST#yl+&zdE@I(OoR)Qp+DQsc(GKdH(4ta(BS_suDS=fI!X1Nrp z=&|Flx&?_ZRM~DI^nBqlT<}~4%ysc-3N^MD*A@^~?BktKE>e;b&88;ac9%gGm`!&u z{DND>S%Q8d`zVQAc;y-gve`(91=(=}@vtq3Q{#I~(>QGjgl+Bs47+2QOEnrD=2n$u z@>EDujb;bNsKy}+OhJ$S70m`e&~2J)1ubcI1ibq(ZRt39Y>4EA0L%J>H$xV{yQB<D zzBYicL(>9QwK)wlYZnCA2LKLV^CFCcCEm}yVj_cVBVP!aXnbSCO4!DD=7&$>;Iwe% zglPs@yu(a%SY={@k^LaLBKrwv&^ktZR_;>nyzBO40;n?Q{i7`s%f1VK6{3;R9%=wk zz6=(*>IjB?dBL#iy76XM?XcEil8$-yv7@X}^=_7bSMP1q&*RI_m8518c9BB31ex>f z@U-&(nkY#|iy3tyo<WiK6GiSgYmv%$k<TQ=?|a+}I3n}%u50pqa?S6EJZ<A&O@K^2 zrgnkRa~klj99H%wwc(gO7_m2>Z;_18#;OnOm=&-N1uV~=m|>A(xeyqgf$|T~4*T<v zscU-SqxwXwWhB<(#3jKR)P^3r@hKE<h2mNDT}ok<HlDve@oeC30A<bCYI=|A7a(Az zLvV$bvNj_0Gu`tra*h)sJ5{y|mYOsaI)jn_!XZHxRtVJRPMQ}rVh`IbQlsxiq^it5 z+iQ{5LVhITX{%7RirKx5a<CCVCCm=niy#ZPor`eUv-6>Qkkt*M0*G7TF{3f@>xq=u zd4WhwTQw3<YO$vk&}|g7riO=FRAYUCYBT`4$1EC%clPy=JN6~^A>teinMxw6H2~x| z;+!|h0(f2@AEp4at;eAXvZ0oMaop50;rFy=FRj_3r#7dY1_l{0>#_QP5w+;=Af?;j z!p<VE=D!4ms%n}WRUggHbI-%c&Au8T1y&txfNr&ku^`5rJs(6Z)w`!+3Jg?d8isc- znhbnHUG>_l^zQ;Szg_J<pf()05<*0;iUf0W_*Bqi<uwoF$*~MIGNZtB-uMAY0|<zy z-#9i@WqX&(MneuCl$`ro$UU(yw}2Z4<x?v*zp3I%0Oei+rDajRyyoY5vYNjs37+og zKw#d0K10n$1JwNf`@K>L)(cQ9mE|=Rc?8GfA|rwDYH!9ky!W_$LO$kyzW_&VH_q*- zB8bqO98`InYb}#^jRzzPx_x0lh{oPN^#3<^Zi0RR`Ui|2N5zfuiXDN~miWJb{6;%O z`zp>+yZ0EMrfI3c{023g1HyJGYY7+~R|OiPsd|xkNrM-wmOFRu+~v#Fa4uq1z--mO zD+PEmYI9YyAz-%XU5)ZspM;s<f1vu9G+L4>3ow8929Pjr$boVoINh)t{yLyMJUIMy z!e5WRJNDFEl5bVHF&F-z1pJ615ZH}BR0y6Ne>(A}N8jFAmF1SAGXW{j-2WikQ<_<? zxnT;s)~9Kc>VW;#+H&R4=Qud#dVpL@gB1O%SXO{FHmYG8bZ|Y4ZA!r4j*4>wtIgB& zZ&}a^vdi{>al|b3v<Fs8VkoOiYudHefKl&|Lk#MSS0C!DesSoFT6eCd$6xPP8+Z=o z(tZ+;x>@A7G5&f@Uk+b9>N1hzlKAVy-V9^oF+)U#9PujGOvPo2{jqLRJv(5ob1F)@ z8q%~3n627e$PzmY{c}}}NS>hZ4S6u)E=;KW8oK17AxMwUIhLq*K$N8-jb=S|6kBME z<8KMegY_0<t%~t^kJ2UCf~;K|qA;JMw7ksLy*p@a2O1Zg&>kpnyp|2kQCV>gQyr>x zhNDZd%37AZLa`bho$Av#(4I{J)=JnNeFmf=T1%x&0bT_O?K}+K>!$z+K87+hNOO~d z;h@`9in8W<73682GKq2)HVXY92zl~uy7?BNn1OU?d{cm&_hm_N-lu8d90S?Vv!j$9 zW1GS=-3wIjaV;b0J)+A&?|MyMO|11D)NSGQaL~I+&r*w?axaHy{WDnP@v!z`(0f26 zJ%>rnA_>FV+MxF{k@Vk~^be7QVeL85JGQ@Yh?Ys3a3hMAhpW6(^a}wBZ5+(0ResEi z(%|Y8Nyt*r*8pf}Lx9Y9cBqj@EHMY>wJNp4RMa?+V1>iAdr?K(I|(xZ>~^$546n0J zy;#ehI$KMhI#~yPaWrOABM+eNRyai8rg{%(7YAVkCI&&;%HI|&dV+c<KmKZR)7$vd zRIAEPVavy{<>4woaD(dYt_Z?NXybxxYrFy+gM~luExd)_PK9Amv@$jS6Se4B8jFS3 zp|*j16?3)m%OO|nVya8c-;cSdqDhpiw=TK2E}K$2)a|K{{u*+zO)(n~&jmryi_l(! zqXU4hUx-750B0xW4P%C5BZCstwGb-0Nx~WjC8lX1)eV@TPvm!wK^(gWq{6i*RP@Oc zpu$&-Mp-E~7?5NazZ^2I9*?Zv0kR3GFN*;+3s96Jt>w-;8vFDz4V78r8&GRNjy^8L zew7_Yaj;5IceQ(WfHjnk+E+SZH-v#Fl#begnkvxRpu4bi!gh*nRxuWYa$Fjd0u&1a zRywL)g;-$5yA-3tit7E|lR`P4gZk7w0Ilq<A266C{^HHPAAr(x)rN+gx!nz>siz!m zR2y1zqJQhh>zkB3U|>7sn#WMRxcqXIV2XhVEUzaCY>3KgS5asN(B5o&Ci35QZ5XRU z6L*b$Njfy*;OQRB0&v>P9gw4_*rAOgLQ+fFvTwp{>HNU?RJ{X}x~PT}-Dyysl&0c5 zSQba+hf<Epk6My>D8cG8rY#zQqg=j62k`8-gMcZow9PU)9I=~GV{mzP@N>z40cxYM zDhu*jmJLJ3?IHmV1i~w?kR(6b9fR^!X#MibD@V@)vgoK<;x3f5EG$}JJcr<%QV0Ma z$xkp7f;JKTLTKi|kO6L`j7s2EA6g07l@A|DvUThxwWd}35a*mGz5p$5gd(WqK#^v@ zyAYs$6rSpIEch2tBaHd(LJQlyI0LN=1x+9zk}g*OLhz$kka%xwnDZay3zPwL5Yd7_ zm)9m(A~Kq>b(ZOML(_pxOj)nrf-LGfP&}_yyBknd(m%a6GBkZ|^=GC$xB7UGyr^Ae z7T^l$K;-m|Bw+yS39L!*-i5${I?bSUN5Hc_P}8V20HB`wMitQ4*ljk3c4+5?y0i&u z!+{(KkAm><cvyyTrU=?XU3x7ROU$*4?cvuK(UiHaBti9`r(k3XE`bGVN^uEMH9L~> zgUI^pEog{2+A0LH5g<7}w1v!trt?rd(#AHM+xz1cwzU!_08*UWAREN5Ms$f*xbQ`U z=Z?iN2%(i15dpYGES}?JrnO?tDOfKkvEKa^2XU1aU@LbCz9zDxl0pTbmf;{l!ph1- z+(<Fo6D6a`CEJq9s>Zasb5M!dqvb(QAB8Z_@RB9Kfq?%EBQBppdhIVZ<0E?pJoqx` z7&LVoyzhtc<aI@uHfAhkndX8=Y|xoHU`(5U&4CmX$sUPy|9J{ECL@lwDv`1j)0qPC z*rx$~CEAFlo4jN;?kiy(Y_Fdkqw(a!U_6%_)Bciekt}lPBt$ja>+l6a{@RI;La=6^ zT(gZxX?E2ZfWUJxhC5M=C;)in&|gL3?U*=>5_`yS9b{by1F#*A?}e)It%J<Hs`qq7 z7T-S^vKFQ3DY36GVz$a;zH2hc^}G?E;WYDos5cYqT_+OY^*d18`5TjwGac3KK`+;! zp`+O2Nve1j^fnj=Bvu2nk+q3t;~-!bf9Dh$V4Ue9>NrNd0#VD+CY&J#<`gg_c-7Bs zwlB*P<DmedaPTi6K><FV1qI+~Iwv%v^aZ280Qmv3Dqk<F0^}iL6#eOGl)oViQ)Y?I zhBu^8{>XGo^m<BaBP%;ZvGvhu7$epMUwu*B(7u}=n1;d4{Q3BE&`|NLi@*OO{@gJ| zJi7|x?}gOOM*#)-Pc9<G`0Hc6+8xPz!nCPYfAd^|AezqGn*cRdmEI;vbBpX>?F7E{ z6Sdqv;zJy|%Rhv7)!I~Dh})`Kre|MRh$6A;R%fPQ2{kV{w$NCG)Ns(Eq&T-{U(wTO za+QDAn25{iO@=lqppEx%RA97UFD8S)xT0xU!1#1KUws*npwT!}zq~X~jQGD#Ko4hK zoXGiE2IYJbbK*uPzoR!N!<^>;0bkCalQI9p8LLNOLMkMf&RH92lpY2homVLou7S$< z5??$op~&9jP|5w%;!)`s)eKPpZQBW4?OGaZ;s3@=EmI}Q7h2+;FRuhSSy_!+pnkbz zQ;^l8D7cm1cM!_;Ag<Qz)3I0+U>Dy5Ke3Ul$9RW^1lT*Itb)ikz7^4xHOK6$Ofne> z5ih`Q&kL|hSAczfS3+;+?@bp<Ky)x68rivK!9tvur-m1}(B{>TK9sVD9i?nsfc?C% zH2>=^#WuGT#i;{97L{v0l4uVmthNNhzU@Unk{{0}!|0t^thguW?T{aP3FoW$B!-PY zLD+c2Cdna`EDf(k8v!JaEWB)Iz}jqX2l7#ih_S3vsa`6TS3cOGPXe0Porg5<96;Jb z5aO>~PBd@O8ewVQVmfz0G@D^l;yM6SwvE3(9TTtiu^Vlr<)yTPF$vx$1+2TsuD*q6 zf$3z8Fi{^uW)no=#vJdDDt{XN5zM-$J~lVN9(H*S2J+3K$qQ#fw{qBw?}FY>D}E%p zS9yi%JywyWdV4C<l&%t+OTXCgN?JPf%G;w&hz&>U*J9||o0dR0)eqxPYHe1`?dC>m zX>!GX6TrA(;)A&=2(Sm>S*gN&C6kN<{a)hEA^Rgrhn&l3&*tN%<5<X{KOnl*e}h)r z`U2IvTekuHL-^|=W)8+IqQ*@7&(bVXcX1xdVS0HmGI0l*ZpwQC#?+INp1&HM0Qj|o zVerDXlW0)^##Zbi*)wb<TWq-44WeRfM1W<TY%X?Vf#zZdK0p|ST$$A~@=|i+8&0v5 z1TSK^1%z7-v{MBPwtz^Qyyho)AmHt-91W@}ZvY}zU7lwiGEJl04Tw4c{>pQt0kT2Y z^gI};-5?nnzsP}At(a2mTw}V!T%4`4lv;;srpPNAVh(v-EC1?3vXknzbZacdw8m?y z*|97*a4!dI4zObZ*2(tz>Y}I|u@8N9Tg=V81~9_7%G7K%`yTx|-k<r%QZx`B`^g0Z z>QlOW2&$-5Wl=3FU@Rt(ExEBP0SZrDsU%v0X3jx5+1v;%>BIRn7*V6}0zFqGzj+lm zVaWmjTh0Oi?Oi9U>DAwC7n?X;N2SCjPD_f|_u7L}?>rQJU<ED?u<fNRihFy0)&Y;1 ze%1*O+VaD_KYq_q(=74q2zdAE3jaGGpJ(4d(VEP{eB~fXDtuO`^0EqQV=XRrA-khZ z`xJ<?im}b?D$er-BiYYxGflZ>jU;%};A|3=76G`5w^^HnM(GK`@_NWvxeX08EueLc zMJspd1NE~?t)bScVi3YJf^0oxDT6F9-i43q=VR$}u=EHrjIT#)ctej}Sj3-dz*1e) z3#&AR?;3RWzQnT6-WP>6M=wc3y%h%KxVF+)cd>$dV>8`8{P8Oc^v9>jG@?v7Acqd5 zid{vtnJ8<~kgb}{iuZ^b7UW!hq9qkKbvmZbS~OUd*KM3GuY1DL2_s>AD#xq}+oYDS zSIb+~$j}x@dMYF5J4tFdZiBXFvrUS3ha7qsz%imAxYau1fr}G?SR!d}BJf-y@CRtt zIA)P+rb5664I4f8$WJbV#Vd!ZQgH1katO6Dqo-I7ZO0MlDUm~yDdrkEG?4-~Y7ZJc zv*geh^mdyz+~~Pm4ms(qTn-^0h^jUu$t6<2*ysp&*J~H6Y!(FeYUe8QnlCct_oT|f z&w##FhJ+)3eS1%IFqFX2EQ>m5<7!OlVW{V@6^5{TLjiOS){(sCo6G>aLn`rhE39cX z>TI&V0o#B)IS%Xw8rPwnMAfS7ACq;MFfMvT`axZNCAAAn<dvm8xGh*8mxTPKtdal0 zNAs>gAI3nXvxv|QQR+&1;LVS3wV`;4XXzO&1(0!@9MgPN8(oUg<|~28kEbi_s2sTn zH>lR7V)h4U-0zj2a9S~N-?D8+&;4@fFb)3C<j}t<@Q@t(BLx;{_ZmHwa_D=Y4@QqJ zhuSE5v0SqgDq3|Of_J0YGS^>}tEGdom;#XN->UhW)%IhtaWFDCB1gWZ5s77(E&jq> z4QOZsW;>j}83=_x$_P3XoN$!nRj8FBy--M)DhYk@@EqF>O@4Q<K#AONq}J~)joqk_ zWQ1vcER-Ib7GO(h`uT;^5<@757N5j*yTPT|=Z3G0rG&3cjA?W}&NK{_kdc6!s)#9a zMH)V`Dl<ys*c6*gvxapHg<qeRRw}<&(i0mF^9PR{ic2jmhp?@LmGsbicByy$Qb(YB zH^Sx+6=zVz71k0~57V>Mp{%31%~Xspx=XxAOXTa1`hk(n!R;TIyZ3Mzckdq6I$;wG zlB%$+in&$sZhF)Xb!#pl4Xi!@Yqt9^$aazG1x8QNGOJ>3uC=P>=Gb=h_Q5KY_W*0n z{6^Jm#P-u+T>Y|vRux3C^eS(G9Ll79>CGl2HCYRysGI47d{w9J)0H@oMR5R?>eJ{- zwCsE(vhEJD%xvQi;~pqbf3nn~ED9O~>yD)=>;5i@MG3mp^5YVXCJ=#BYIzstM{32( z#tGbC>_;CYkk^Doun8?=xQqQVQSbNt!1P?^c7>hv)K`CvwiIoQ-`fcS1j{aks=0&e z0g*^Wb>CA@(2w-?=))k#1kCZ3D>+A%_afavlY`b=U=P<%A*8|K@fXc>&ys6q;27a# zUV;PXs7yl)ya?v2YlB70!Iyl}89;baW4REUqEQxCjKee{_ne7*bY8yZ_UCs)dKR!- z=&CQsHUi6a@ejI9lOk{cf*8At5A7j*b!fxk*VeB<0slJ`fU5nT`XV4Vn(pmc_H&iR z{6I*^zo0%vcn6?>uB^h<Zf;YJjVXNk)WnL=FJ;1l3RGP?H^}_%d2tY)pyK?u-NcL) z?{WPl0zWo^9>9~(+a@-m7ouG_Z1;%lP>&C4UosM*)`s@$=D{w?f;<jU1gY~7+GEck zpc0%+WrA6u)B&q;HZa|N%`h0m&yWKGr>k)vGfjWtQ@w2S3Bfl1Mr@NcVMI%OYyQvy zv<p7#c3EkQetUe2K4I4d1PN$U;CG&u55M!ZZ1`QI|DNb{?8&OD=Ia^AMd39oRt1D2 zC%On05(He)pFyB5jcC=>EA*jNk6JF%2dPGL3PnY)hvcaqiodis{yRB(CC1+aoD-iw za?isj5ZbZ$1j;%bpNr*?j8EWqY4Ai2HJi}ZC$HE-{EGKnfqswPCT$#Tfzv)Eh?0Ej z_ofL01yK8@9FjvRWS>sXFzS1niRd#x%b~Xy=p#y)PRkMqk{tO1M3=Dc=#%g)j%2Ms zhV74N>h|bTN;wkM69va8aq0+@jv}2Lx$QI!j;(ulOa^S28Of@`@)5tf9Wz9yh@vh{ zf!_(*CGeZCjfdZhv?1_YAlKxH8XQqMUR5+z1T4{0XaRw-O^Y5qMNuiy1E<8`EWn>x z_%joK)Drd?^g%FoQf+^1Pu>7P>Dd)G*UkgJ?<;(pkSV&Ti)<skI_m-uv=`?E!*g7{ z0`KxTp9anD72uM~*UUoYI`Wei+zHul$Gw-`B_1>2ZPpzqjy{q?`uy)47GT0{;cN}f z<aQ|&4NAK!i%V)BaRiJ^Q)wzr&nO8$k_8ck@KTfkKT|NK3}S)-qj469+1Do*u4rW0 z=RyQ<-6igy$e{pDHLPW5TMl{2$#b4fEiVXIzh5f>qb$mkgLy=)yqo1ngfzp;Pl9$v zeL(of3izP{?S4?tPBZ&PNLH*H!uEF{5Qs3*_MS@R2Y@S8<%LyehCIM*r~AO($m|cH zN@zBF8<&ItQO3-H*H{_=gYgP874QCK%T(h>ruG2*p4RRK<yW$3cjChVi-`>~ox!(- z2p<TRe~mt7AbbN49b5Xq7a+E~fe56c;}M8Vk^-`VBLGvDvj&YXeD4LKWSRoJE-OZ} zv=hl>a{v|RCWrULlE+FI)C#0yzxu$wS*mr+&Qx@m@S3O*dQWSqRWlq_u}7PV9n}gf zEE8F@(eV8$z#p^3`?c(EF`du<OBgQE`{i03(h@RB|Mp*^`7711M_y5H^rYxmn=h7b z^jLKp1RZK*MjY13aaiqUaaJq`w-qL1UbWeZZXb%dK}D;AX_cS20ZrN2!&1>r(e*D> z!D3d(kEWXC!c+sQXXT^-d!(S0l^6D!0DAXoYg+Y*{DPFT?rU6S5&Iferi>O_x1bMZ z+j}JPrK$d=18@gQE}+$+0rOb(6c)?ckNgd-l^~1cSOjmvXRq^SndxkPOXx0+6v3W- zz*V4ie(F&nO?VNeLLy|uC+CoqfT3AIbh?Yn2~;g>#CMmcm9K`<F&DBNZWq#tsK4+1 zWm+=g9i`{tHVOA-G!o*&Vn@<+=DvlNQnuT4ns185ubR$p-XyzUR?R-$5m8fk&t;f( zE5xqBT4<_Qy-8dLN9Ojk=<lFqM?pAQ*M&0ro&f7n*%9u`6Wtyegbstkyjdvd=vRk( zgXZ?wMA~8I#%0*y*#q;SYB}%p4_$hV4FzOJ0Is_83q+9sYxhTd4sV8*Z`KE_+l`)! zDvm^ygGNv8qSRHOoJx(=4Sw9(M-(uQ4N~N*>l@Xl73OcSH41y*A_1(Pu14%%e+eUQ zQ;qr@as#0BTawZ@C(?&fdhb4rCn?WMy?MfUd}JOHDd&@4#<y{Tk+K{RIJ}7b;gnuK zr!&|^(9!s?vBgAl=RKZY_nk>a_S?Rfq=hatrMJ9+r2DTNgaf~K%=GVZ4o=9|obsO1 zTav6FfKh#$9ewspXly|q@CTPLnqh-SU^am<ndF#;bHVRV?QQykBKv+&sTYpNrc3)Z z-TWOjt;pA$RJ<qk`sBu!;OzB5fYz<E!_Y-rO$39Ave_2y>g)T(YK^G@6t@Z}w!*r5 z9ijM3914Y?I0{gFr+B~9*ZmJroZVO1(?y7UK!NcOvQG&!cOrke?}xy&9Zdi;r5`YF zA58%Bz2f~|Uz_Zi-Y5{e*R2?L)2_Txcu6<FYU(l3)xdOCy-sU%IKL4$U~mD?eVweD zCqN+#TYGJOefw85j0K*q$aNO}Q;-anNA9%Za`KM3Y=}i#dVjF|b6~>`t3|rjnA#y} zW!JK-jxHt7&~o@&9^o&UYBoVtZsWwzC6_?veISBiF5!*#=YP`XRg;MPlq)9sn2uQi z?=uYd=aSio&BdN1Zx;S_3i&UJWvoH}(Jx_kV}D-+7gO?Z;`g|%Q&aS-x|KW!nzOH9 zMfnfs)R@aI;-k?4nBAD;XU)+0&p^om=|pD5d7=7;WuxO%xHvDCX3WTQ8CxOWj2xrf zLCtFDQ=i#?Z?ex<5Ew=p$5U9b3;9oJzfrRzgE&WCQ=T`d(n)(qAgV)?fA>lfu*iBc z)+Y9Ww7AVV7{14y*XQ@+XNOBXUx+Ed{xA2KbY{cYW_qW+o@<fh$m1xwlz$6@yUao} z!6ogd*Rr9!YdXxt9JY<u?J~{fkbb9y#+lO;U9K3XE&5Pigwz9=>O|n5erVhs8&y)% zr4NHlDKL*CMY1CMyKy^FWzIaRW#|E@c=awkkAMJ?0wAUdjaOJV6!}h!n>aoZWcL88 z>h&dQ6fR0B<QvyFhd2m%V*Lgq6aUdc=b6j^`^b32VbLe5<xM0Dm`y5((?B3!?L;P& z1#B;q4;oKf6&FGDzdl3O-IxOcfp_<k#`snR*>Q0m0Ulp`<*Mb)s<l2~xHq7bu<y+D zQ;m!n*MSXPbQ@O8PN?ikwWdoOWjyMzXfV03Vz<AFDO>px^iVO*Lx=4g)q85m2k{;5 zEb2k3>3r!`0UI6=`25VqWwJclU*8WIt*t79?wJ$wUX`SQ<3t2TE#I?FIGat&Btyk; zo;O00BG--Kd{|=BZCD3l{R!0y^2bFt?MKtYl2foSY^*8v$Z9+b$s5THp6HRxC&NoK z9TS96xs41$d@lSf7v=PeX&Ml#pLPklg5fIM+B@3QTeK^d69~^fCB@P)^(Q9?53?8U zN9jO)C9#|bPRbpPNqhd~d(_CZ7w{a3b)RZX-7o3694&9qB#0Why!{h|I%|L5!i2H< z;^p{Q(IOJ=NjL|WqTku{4z>HR>TRxcbCo>r2TFKZv|rgxyHa<k@*Bql`qY@J?C-%f zYj!L`Gs|C&!zh<IfTEku3tkaS`yyl7?~kJ@J_22?-x*6|vsta#r@hr|#foFE;!CP{ zNs#V>KEHth@(?mnfLsopAP{!Qp(A1&knKU|mT^j*6av`@?OKxR-6cQ%4yk0fT52s# z)+u;okF}RV&lRPrNCMFj7sP4V_&wyROHs}BXd7#+nj-0623RZKT_{Oag%@i>stRXo zgGA=a2gOl9bi$c~gE%5KIG%E2orTJ)W&_l&M={Gh%yLPc1)$2GI$0YZ&pN5eIvG9r z5=HX{7L8nEQN2wIbDBzE@c$cBhqdU07Rzn2A_h+2f5s@<EEq6fAQ-&~T6}^J{y@O% z&mVlaFVs#ttHO>ctdsZb5#Cah{PK!@N@$67j6N2Ywv#-lR91`hY`VPCcI$*Dq}WK< z2_JgBr9k+On_CcqGHiSnIwIhlvh}Q8S#6`KZUKOaPPVlrBFT{?dYhnusCQ7`_^nsQ z9YRrfcYr!kOOu)%IfM)6rT;=Xcg*5%h1xKSoaSeW^I5a_u1YC>fXrCpE|W9`4;sR> zVg-JoV-$!}invD$RHpEdC;;L@&|QZ1uUV*C%mJOD2I`89Pi)12;%@s^s0{RK)Wfja ze|?Ddybe$;_S+8%9b&o2Kl>2+v|I|2>8MQDFNBaF#rF2yqS<*6-VzTlFr9C`h=&ZG zg?xgWygo^sclynX!k_0A9D$|qVoY0j5Q$xe$oKdpOqdM`Ytj=M$JH;A#(}_|MJ|Sg zG8z`xIt!^j=*H>U!S8EFo6tTrvNT7D%t%$_m5u)J9X9xLz+cwfqptx)`Y|3m%0E?S z8!OP*IAqa}sFBDRsA&!MvCdXhYXR(5jRTl+_C3Tt|Bos=jm*kjz1xQiDCRH=*l>nH zH{AS!B(25jaT|J?g*F!<WkGF<Sr4n(+gR~^o!@<P6O5$`k9XZ1J6~RLiv>`--tS$% zXqb|}J;3U(jRb8A(EsHv7k_v=9X?8_OAFQO@3X73NV!A<*#blrcC`)EDS;{gk2QW& z70pI?JoZmlk)G?5ARoIqiyVJ2ALK!2AmQ#z2OL==ELGIS?wNY#A}IrlD0BcNUTX4G z;c0;osKDAlrS7s?w5+Q1oVw6ZY!CMxtSQ>ys&p5|K+)Q29I04ZQ?)=km<)4$z-Uat zQz!a+v8#|9TsH;=;;%}?=Q4UmEOJ17k?F2jmV$4Cpe|q+1L`r?LrvcIE9lfM&5);! z|7NF2<^`O?{+=N5GoR>B^f8^_?Mb+UUJZOu8=@Mka8pXcV=zynlWFW{t5MnH-95xE z|0*0$acI0_GJz3le&isdI}NL;4}%5Vj7I?(o%(Ch?EK_Wq-XX|@jzerm#f5Td;epx z!U{SK$wJ5|+Cba3N?Q927k_*gmLxh_C@@s`oQgB5=vmtKfoU2OcOF9h_rz&^Vza&J zkXX^C)AxLWCf=A#6JsUDiBtOEX8W_fIR`<`*ayamllo91vd#9YcpCHBVr$RfhMMp~ zP2O`y$e?H858|tZe9n&W0D6<`V?EwRJsZU_JBVY^JUZNc(Z?U5H>JvA0k%;==Xj~8 zP!64k0;{zxVEqQ&IgDfWifFaTPvKT3p0utuqZB4@sg<Cu-t{+785-r#*OIW$koJ6O zJhF)*uN#dfAEYXL#1_!5mf6C0X8DVNxXX`6;-vW8!rAU~wTlX8S+q&=ib8pXYVjUh z<jmg&bzV6J0IJHc1*{(g^4s+90kD+9JpFw&a`ic@Pb2ejI0DuUl*X>JRYzZdWuZ+n zqBd=`5zW?e6mJ`dc8#%-t86yhEnS6syRocQHU}Q*T9pfL;j6R!;kk~OHGHQ-jV#Ln zGPfExNPxaYJ8)>m9Qp=&T(c6lIa|!=hXZ?dRU3Mv&3_O^cFZGq7T9`FS%X}yG~z#) zgWdy$dD<m~w_3Cd<rTT|3dQ2xz6du<E*+!PSrzLCio=4jrPem@_J!ZzPHEu?eH$L* zD7Ai6n*V{m76z{RTkIP`s=1ACZCal3ZMK$$hJlf5Mc>wnzO5B~TT6YrGfR!!oD+yF zIcTF!$t%;4$jwDF$@&x=w}T|BA4ee%(X|j4@s@V6K~hERZG*4Z<Nb^_a1_u$gaEak z+tSFo$#cj%{V%xaK>Aw;Z+_O{Ew;&_Ct<`^yKp;c_8}6pL4-rg^b+DczZc82MOj5z zz67N-?8USGtc^R+tj{=Pu5nZ5Ut#7>!(!?q<1e5ot>20JNNw66e)3z>MEmi?H+JHh z|BJ|NwRAmB4(4)AI@Ho-Z`lh=POd?PL6Cyl@6fBQ*cP^D#L$h*5w_bYkQKH|7}$m8 zwqV45%Rd1jj@y@xP|G*TEB!Na<|^TkS_|CBT#s2|pNXv1#}Q4I4u@=Y{t=_6*M=;v z3wkqsifUuEiOYWJNVR-hU1$XIPRv!154lLKjC}$teE1&hfMn{qAaiHz5&g9Dq0mn? zJm%PL(LK?L#v{=Ad~`rM7e?TpA7JK>G(4QhzkqS)w|s-T35t<1y9b8#TLrz-dMyf| zf|Q}2I*atwJIH2dOv^@*TOYdm6gqJphTmp;_hCV>NQ0j=&<3Hh>Pa+Jd(ckzFvu;H zsK9s|v<FpYklh#J?=}i0eYVP&iy~UJVMY;ZH(o*zhBffwA7M2tuYZmaNjdhA<0->R zxg{z7`-2!Z3gV4jgN;px#6payjv^7^?UaY95cMA6eEv56u82d|4SaoFyka%{c@dsP zc5Ax}B_QB9BaPK~qYT1zx0hhS3|z;|kw<2civ?uA8)dwrYdW>TDwDA<8Q2#)FU5Su zqdmw8+4YX36c42|yGXWr7q9c^(-o0BMF$^5xfxahaJ1^gsM-XFt9A`|&l~Vw(C<B> z%o5wfYQ#zMS5a9fvY;GLxiCwLMKu-!jKEUL97%C>2+g8{j$Vzu?lh`!EG%S4L#>S* zl8jcf({D-d2c+NP=m(^D&l~Vw(C<AN$iY7Z(r?N50gx0o5J<nJb`GIuL$VEPFP2bn z{HF$4ZqU0!yBLqwu}%DszyV4jaclryCeoJg6g*QCu|NAE?qY3+)p(pJUt^L@EAB%b zrIvOlWS$>G2`#Tz<{89WDg9}DjpeT<)%*0fDELHJJrPCcAE2xJW;)ZdTV(k7P?FTL zeXEdKdhM6y#Es8LQX7b<=ESwn&{+lut$rqcPLE~J-G%0RQ_D7;m~Ldxgb0(|bj^ce z&vW4MhKT)!zaurReh%7iRz@SjH&<hqFw|6yn<T|e)!q1j%$IGa%&U5dYd&>}8G;x~ zacbp+euy4rQhIo8y)ZQ3wx0d3A7Ukj7zG*(o`aspqQstqVoReSS(gwno6aWy?^yOS zsDSmD&Zeh(4b5sqwX8vZ0Iu+awMX-?>>IHyw%v3-PkA>(>@bk`zQc_*=YL_GF~ebo zt+6!zY?K5nka-@byvh3k@j3sw*=tF1MARI9(UznsqIE%@%e{gz9Uuwdt{Y&|)F@`2 zp^CT3;%%0AbBVWk;%%^aTOi(S;%%{b>!R*4qG}ZJrHFV=P$T1Sf_T~a7Kj(K@ymlW zM@-1uC{IJdF~n$xLy<XKlf>*){yUCSK?Se-CNYhEQAJ`JwR|)J9X$apd#7y&W~7aT zitfXs)!rU$ka3lSXBmO!9_yXf6!akmZgmA0(_1*e*39qT227~!09lyl0B89pO;P3_ zP;HKUAdK!RO|ejnZ~dxwo-bk94}1`x=QY14Tj@FIg|eB>Q<%<mzwe!A;Z2;zH=iT{ zsc&x}S$&?PmLFpWP&e=e*mnL#3kWKayDUoe30xJ6$b#aFTTtYcwuhs5ScP@do@T>o zhfiLymH)^Y*C-JfU+vpuTJY7r;|}Ax3c2f$O!y<$T4F;mwpPT3DVA+g>8SZkcVRGY zlwitG(pnW8fhF`-P-TU-da!`Zal;Dz?pZ>?D2po?p8D8GkY(HpCTs-tV^-X*Qx?}@ zaLaa1fIZOPzn^5noP;lbSWOTNfNC#a@u_LD8F^}XXIH~x`f&cq=O}pKIR)BU0D1Z{ z6vG;PS~g!#X=LvD%wu*nShNx0M;u)ZIdUjWi@!L>`1G_IwuWcqvEn>PGdjLCT2jKr zd9RRT`NiC`uGbkIXzIjueU9jvAm-jbgf=-y3~I;Shho|lkwd79uzcJN$$ub6jZC*d zBdpkMws^k{7dw`X@Ux9jeBC&tBe7eIRu@1Jy$ZdvPn+5V<Me6m91x>b)&v}>{ws8z zjXVCf&Qh&e>tktvpn1*EPsQQVhI@9ft)OhDa3>y;0YsHU-_pkHjGQ`{v|3AS*t?dv zQdIz1*+yPWO?ywtH5(zPyaJ6^v?|#AzFi<!f4_YY&*!^cbfr~6FmicqJ5+JZvoFA! zybdiBZ8h~d#);t-hv7#yK0v`7?_A_28YX%yLM9hc-%KTh$u_1HHKDj1x|<Y26q@DG zA4v|HmIum`^6pT&9LJvdXPmEX0k)Het`HYv4YXJCef#ME)Uo~Ol7<?lr?ts`sDo7F z3BRERFM+CFewHj=J0RPd6G*W=XREM|D$ITva`Hb8Mneaz*q*5iuZGCqVr0!=k{KTR zj9{EW6$cAHQK*w@emj>gKTFjYlf#02=(A|m*om|%aM@Y1+AwQ*qsUfjt-qf6n;d-P z*|P8aght^vf5K77aarh=mD(a$10}1!LkCUgL%$|#2~w_0$#3LBwS1pyg^3J);^1%Q zB1khoafq7HVx$Hc=yJfA?7vBv)`dVnKQ7SUnK+jtW_OU6CR`gHpMN^tr;jnF1vkKC zgTRmT%wGW7DE3hPh#RL#cVf_i+Q_we{CnD5p>tx((4Z2wzyBrKKR3`;{XX3uDb9<f z;`xfC`$z`vdG%fMcbGrgB(_QzRKS0PUXiQ=UNwBZxSJ??z`H?yOt=a51oBS?BM&(O z#wmyV7@q0D{pCmLC|YO0yRmZS8agoIU9Za1x2x9es&{)uF6Mc!1DUz%ZPZ7C=(Z1( zW|!*yu;OY=`#bi^+o%<(4W?C%jP5}f#lLh>|BilvZEWRF(krCSaBxE;ZKtG9usXhB zW3NRiNyF-YiyHYw5FNlx(eB-5ix}f187wlUn9RS^roMQ#vzkdh3CZO~iE=~#Ps=p| zvwtsx1~-$x`n~8RUC;EbMUVC01nzggQNwC+XwRWp@dR+WI#so{c<QT*@T{JmwMHD! zyCF}0s{UwWTd-W23Tq<Bb_A^rioDV{v_xJxEA`q)P|7Q**{7YuZpZ>jydr}s4(oc5 zv@2u<P09_EO1zsZKEoD-5T9rt#xlqnf|2aE{)`7WS`&NG<4f}!fJb9YEedCNik11? z4Sa0(cB8`*7uzTG&W8u*lGSdHi%&MQJtpzT3Z?js7UE8t>~>U$pZJcZ{rpejiR)3$ zK9jAT9bw1#&EE^-I^u7m9I7MfzZRvkV7dJjI;q@VG({VNF5kxb9JQgtrdk^iU!!yh zP~x@H2Dz*O_I|+oz8oqhU#IDgQmpd|Jbz&H*!ApS_%??U@turL6j2u8g*coVeT^Kc z!~enuyVhnLbI3KE;BY#(p!hsw3)%%Ym9kBKZ~M{<0u7(qK!Qh56*MC^<dlYITY6ab z*KLs7{w4fcTOj9>z135GB}w&cEnS<D)okF?K<>V<ddhN0NyJrS+)t{f{5mNP7jNvk z>M6fXimSo6Db-UVNpW~jLG0Y>DNiQFp(j9WaP^emU|fcXL-~pQ7DIG8Kry$639eWg z4Gt`YFbzcX^V7l<c9wmL>>E(s4`=^aJZ=<^nIF;C3gCUV0>S80M-UfgC%eETjyAGA z<hroH)5Y4211WL{%}^A0UWx~*5`pCuu*#udQoyE_8V6Ff3ytFz?JoY*-h>H99jEoX z8SB+O!cy5z-kuX*qWcN6pMyujD}6!qRbejslSq52U)rxk+9Hv*AUQ3j^JlSdtdo=) zY~=yMqUEGeuuXuyu}zXxbgK<5`VBd~$hsbH1Lgf*EA5yq1=fA!ZbvD*&>b5K&35jk zW}|zPn&riZk@RyQ>=r%EQy=Y;@KS?=dWI4ywes^DL0bhi!vURd1!}$AIN{KS87DHe zT;qgI%L?KtKtD|6g4iWNwvH~4p}QfC|H7~Y+4UiQwgM5N`EmSx0#U<GMKH05W#c(* z)=uXT?3PW4<G2{q@=fHK@HlnfxTnP-?0N+(dv_~T@jhSL2?Qu?a|3v30Nw>49lVDa z=-sbpv)_|j`!>bg8MCv^@bK=}G7xS%z^xAsh6z^4n&uA^be{Uexy?e5!F@kGvzfhT z51=AEKkfH4z9}@FsdaSW1)WA8Ic+$uj!aq&rn51Oo3Q)*xW^>!x+sj-_sSkAaW5LF zr`b<K1pn8!f_Uc8kqJE7(Rc1L>7Fr_S*i=^L~XvYIM1d}WIoq4m;JXRH0QK&_!u;8 zJU-H<Nxo++dMf|rahS>eG#KdXn<NMQp|-!BG49b<G;QI>c#MkQ5<|osqtXqI_O(xt z$f3&q-Bn)KqVy`Sq<LTx&ad*0*V8@qH72kg)+4XT<O@F~-XON&8)Mt2LUst$Swr>u z(f*44S^PDPX@~JtG61oI&K8W>*GA3>Ao7gDH3Fz0O`QfDw;5HB({$P9Y^#M@_&Rcp zg(N7vDe+&l_0$7=<kmJ}@&ZycCIVrE|6VLzpN22fA`2{9v08p;jo3%t!WU!Fa2l4W zKz~=1KU;We{#oSCJ3feCwpiYzT49JJ{ds6<LK~Sq_<OrCb>fgVLhJLSX8ZU1dM&+Y z@-G0ycnR;Acw7|x<7T9#7TnN3qhDg5j5pssr<5HIupY&@7n#>*fMrUvMR=O*(11Lr z1dI(1&q18GT$s0mz7^wP>R^Hxj}_t7wrF8UtFzXosb;gh!h<PW`QP@_qz)OFf$rh$ z(nbOC_@}Sxv`b5c-*o+Nm?ypI8dHklDJf4EUV%&3j{){*_9}0>PB$<erufZ7e!kEg zf$&r}f~T0N@%`W!W-}YAytB0~1o?{4CVfmzmo`X^6kDna$3r!2cPtZUp{5H_u(LfH z%QaiE{nVzk*?6)9K(1-kV~8Hw^)+3(W2#HLW@@@t3<Gkdysm|BK&1f+jKUM?b%?ms zH!K+MW-OD=TbYd*M`K_%MsGDmF=$7MXO9jw(Wv=_W)B!{H{?t`)0Mx;k}B;z(qV}> z>UZrCsK4uL)MTbr?d;R%RJN<hUhyH3n6eO}))=HGYIxco=?<2CII@y%MVET?%AnIh zgrU8+R=<nNMmh3eJY<Rg#;V@Km9y3IAS%7b%*q?o$k4;8x4l9|Bdz@dv4Wucg~5oe zv#(zAeT~<8A8jVl^-I(Cx1c<**;DTikJ$!ca*^-n!Xo@<&f;I|W7)skiPZCp0Q*RZ zXzmon+ooS?I^UxXqkf`gHQOKDDb`PHoay}DK)LF!o#MEpe=EolJLAV;@l0~S`;qQ6 zosagGCzdya`0R<f{-O!mVAXmW0_W-7iNGOrm@LGf0yY1H+78^Z(X+!Jx!&SwMR&$Y znB+2@<FV3mu6V!E6r>s-?jUZCKwi>U1(u@<Jgq?JCdDr;_{zX@2OIQE+%o+02Pjy7 zhxFgM(Lm6eVwK*lS~~Pzt_c#we$hzuKn_j8BTI!Yy!);mo_bIG*_q!6YI=Dm))^pR zda%cXsN&gBK~y4d*e1Mg5(rxRIYgmMr;jRcj!zV-wlG_B5MAfdo+T<(<TeC61W<}J zKlGp}G)N_lzAxzO1iH#sxFI3hwKV(b4p+d~R3rKR>i8Y)#0Tx8{!Q%OT_CCNUHbg~ zi=N3xwX#{uQoFaKf6%{C%8lP)^7Ugv3y0tbj}ZqBc=nmjSxMoyA0tx)3MnGuPmc*7 z{=y*W2&)9%L(GKT>MBpXxuAD{5SUvqJmyz#1I~2651}XCPAL3mP|A|;1FQaKH*~nv zQ(uZ6EPxq!q17b*`|B`m1E$3b$M1WjfdsiG5AX8H2{bn#6OTFKd6xHO7WF62j~K^J z>)HIkwuH?u_T!q?#go0+AsGD1bIH5Yx%_?Ff=M=+G2421o!{XwI()J5{IzXoa!#bH zPU^SD&9a4YTSUS~gJ1Bk_}yRV&6e!FHW9y)aVDR&`1M|G1ARR@-unMr(|@>+4R3_o zqrQU2nKgOt@;Y1<p&i;?FQ@581FI7EY4zRJrLvq-)`G5PLF*>9dq=?29+>dH##L6< z1LbZ2j&@D_Dy<>_O+d202wxlzkHagrL@*=NrLP8JXaOMyeoxcyDf&H0zbEMTIQ<@@ z-yY=Zm%J6fCflMGWxoT8Fz_rPf6evdk(!%sCKI^lpg5*NS6c1VhXlPF7Y<UrTeOt$ z`9Qp0z)r)P)krr3)jfDzexaMUZ;AUdCVMfWXyxKxwV^9x>>)LND3#3EeCC@-3IM;A zq6db`HCxdBxKbP*CDYVgZ^Oc%>ir%Fr1#Xq>>z6vSKB=MDk$jXTM!NL3nF|L1exS3 zoG<L(eHQK{uZKD4@ql#|LtTrea`%?FFXj({EdpSvGC8EumQP=WbhNWJRrP+1zOG12 z;u*g_Ezl}qd5?aG5pnZ<_#gC8*bJL+=z(Sm(6&$esI;Ns*?~9N6CXC6!DXN&Y}AGo ziE?rc9u&nke-pOGeq}mCOOe(5Layn?Mt(RxOJ0HTDQ-J!2WM^W?cjX_;l3Fo`g}G& z6~@8BMq}bLcw^TOeFF9X*X~%f<UJwcwW@N-F~GB1x6+&L;^iR6uRaH->5^!|<aie? z!tBeo(lwTNjH6)*S@lp2y|BohzZEx8QF6WED9L@<vDbLT=7a+_zppold}=VyKZ@r+ zH~0B=57<-xfxj$m46|bhVFrpBc(-8er+DvQ8vhMoMr^if9Pe0E3_w1)CBZg?`au8( zk!5|^2lGQk_C=6SD?^z7e1u@mSB(=L3vq{^Gl=1DZ8|%A{CAt;r&nHngifza+k~fA zVmtYgM8cCI!A%L+?X?5?RDkZ&d-0-5kSi}iC%|hu)b67JZ++ziemPb%Zb`CXAwHHf zTFE1PT0nkdHyXtpe9S~)p+*k9l{cPF7zngss`o@?F5dqc$x6dPXymysVd{Y6EB*Fu z3yf`M{3yu;{(38dF}pt)bo6jTi)m&y$F8PR98>tIHrg;`JzTy(=rG=9I%dKr(dAfn zs5Lf3Wiuv`YX$#!GvaCaB*`exlY|(N@IdeNM-9dS0%)K#OhQeo{JVO*=$j8~?X|uP z)U5IWFxDJ97Xb5Vsm9%TQY??Z{sI}YH*+T*$?U;U{)?Co8}2s-uB5wkRuznbo__LE z+@0tEvEzk*NC}r%7o>O&ddw2WQE4jQ0}Itxg7=IAx&1nov?qNs{}li;u8`l?a)#NY zVO-iQj74v!;?g>S*VskuCqcmpG@Q08#@A!7Wm%m;K$)`A2h3SYohBFhQo4NGPlMW& zLdugxPgmH+?(HvIwB<^dUv{{(Y|jq1nYOt8cn)3M_-!|0xEwl6XD#i|LjBh=TPI{s zb5zNpy|}N_ENt+RnJCKD))UdUS8PUO(oh5<z_MidsYcWJ`oqHS_XQ{gDnvTyb8_ep zDJZfrNP=z#K@`VJgi2}-%ArLmC}@Es|1R!QW9AxzWa*jivbxL?Q1y;wsF8~tn<;Lm zq{vS-DaMlFWs>Gn>iollwL$kC;)4sde)nv}xCfFD%-OL3UiGw@`lekLU>nu^#(;H$ zio0jO+GY`4%P)%JS2ixcfcB;3&_YZDZE|$t^04<QCm))~aFazKR$*MqM3;8dWM-qZ z>Q8V05LGAHC8{beq8BfQ;pR9vLR}#Lcf?OMl6@ZDG{~|VP#Fpm{5Yb1w$XHcv`CET zbST75DETL?OWeMq`R<_n1gg3;a3!FwhTf3+)#|IAk9QDcx3x;N^Az+)O1{H3daE~` zRq?vNLPHx&jb+Irrr+%Y74=?39zvlMeYm{R3R5xH=*gIiH*Me~s77N-QkE;^l{iN8 z&P6_tca_xq7OQMd0m!rwY|C6&0e&7xB<qXKW^9NxD)}1}??(AC3lJt)ZNVVwwYYIw zW6CwFtcXN%=ofhB%?Z0)b1ww=l^YWxD-S|2oEP1F(lqO=RMc#~mIc4ZBjj@MTIPpP zvp<dQ_`%v^FPhGw3-MzFvES4C-vEtYYe9t1>ZJ7n2)_wEy7vXxH-wJcX?OuuPvTcZ zZp`+R%{lV6+m%L#j5mrNRGwRhdi=(z8G2^zFvV<A@qYu}6`qR0>SN{*NvhaR^b$o0 zEbeDb{``6XVNwgak7{`P2K0gU3GrqS%#&DMrt^KB%te=5@n~nf1~tD^Eyp7h-X{48 z+<s;o*C0Y9hV?q2Xi?#QF<QrdN1vk`9ZsjnH6J8;HXeFLrOwv3OXQW%Ib&lAqJS>X z4G&X{rWBR_8t89sIF(+jkDbPDZai~0mFE9NH^0#YPF@Q@pS7!dPyL{)xaA*R5AoEe z>(F7E4n)(pi-6`OIy1RnXR<(2wuoM=r@y)J*XrXh1J$i)NnYvXrjg%52M=(4-vsru zhSlhM{Y?IP&yMyUKPUnTc*UwO)o=hhu}4(^9G?5^TlnQ$q5oN!y9E6cvRzGmWI*-j zH;ED1TS*h2X$6k#_jWz{Zp;DoR^oKRtNdgOpg%h$dJFVH@t%?&OU2Q6<0RSvvSi{e zRHyi6is}4iyh=PK?AaH6@+4x&@e0C_$FRE1JZC-Bunf=JMeMa3lX!wp%T%hSx<|?( zJb=evZouV8H*LNPLBl0QRfx|&B|iCuyb%4Coi7T%<=RoC#v=3Ve_?muo(%E!<eTM7 zSO<RYt9%bS^pEB@Lo*&TT*xnK=yg~DE{XW;F}?fcC;o<p`7vuZfV6FhkE0v~-ib^z z7@77CL>pg?RUhb@HG|o@<#oXVhw-UJ&*!J>O{{fSeWF&nj5bMnIQSm%<Jf~RJl}&{ zwHzzx@)tNPT5bv35MVnY0q+N5JuxSLvbP@o0@Vz13f{c~L=Z%f^C=ygn|IdcmWk$2 z3YmxE*n)nyoF`-<8m{<<XbRNwV}^NJAHoOMCl3u;0YN^h#c#`br#;_@1M@r$%zl-1 zt28hZ{|?c{=VS5yi~zHJ2LqEw12d6te6JV8fdbXubz(?<!M5?w+<5j9igx+)U`X;I zYK9vdX)&FD`8hc*WSGvU77+bS@$3Wnz{$h!AqnR{>21Q;j5nnIXd>PBK7j|$-u9jA zddEi`+67EX+LJHqQw!WY<-Ic*D#ZQY>qur^h?4d$yz}`88Hdnatm=88(-tbmBMwO) zQ3cBds6er)spQs`I6pE)jofJBH=?}97iG#TQl`TQjIp8r{$@3Q6AYr7zlX{SjW$sZ zYf3<07QYKPir<|$%Q^kB5>(~!=1BS$!Jbm@7JX1a{Or_S(1{<xn>HNY77oTlyTA7Q z7%%m1)USdNKlSbzbb9hc;)CBsou0nbCT<>iU{Zip7T_k9II+*f^-bc7PxJm39~aum z*j!TdfJ1i$*|s2S;<Ivr;DJ7>YH#)%qra<$Y3jr4kR8&gGiAy~Z89A_i^b0EADxBK zS}J)md>Qbb(o+F^{7Q;<r(9#VU;~pe*|g}l1|xT)u`}rXykexhVh}lI@$>KwD$u$e zs<~D59<BUJVH@(BKnlK~r1nBL|Lz^rT!YqzaE<`A-?Xsx(W9g|1H7O*p0X^wUX5t^ zr&V?u>cUoJ(Mm&8Z!6nSoBE11<u^kkE`ROh-g-gIiL2wQ%5dZ5X{g#?J3rryedMpr z=l8#J2F+f~$+ER*mW68M(A}qn=^_DQw2UGeK&S<YHf71JYUJlXgm2tg;L8X2c<0*w zV<3lY@jLkw@X{#6)1EsuAni%KX4rRA5}BT(M$q9cd`FoY)@P~VrE@?l`qf{N{BKml zC3$}4bgz@7bty!rOWB@axHQKfE&=v<Bz%(t@Yx^vnd$fL(ytFj?A42qDQ;OKJ|-vZ zDNB%{&VLXc1+}aaw$mTJXve#f6dPqae>5N2th4c5vfKM*|A+pt^WX2H-gHNfpOr4~ zd$%pSTw$#NlsUKf3JbN2fOVsHn||16H5Jy7-=O4gRJ;vKGyD<N;t!WDh@}EI50^m6 z59QEoR8+jX<j{@y5j8}^DpFluB#+K+zxQiBO=VU;n`7(#GcJ@;Xot0p+R+QS@tH%h z?lhe*%t!x?9={h<iK(b^t?d*xWLa7F@yF<=hhN)WcDpzR9_a4I39bmvhy<_7fz`ce zvKmoj)!VShO76-Xo&2`hLI=f<f2trihrWa{Yffux!vlvr?@;fiOPW7iKu7*DQ#~#t z7?>a{$)Wu*0N0;1&L<zhf%i7ZA-qzL-6YYaJ!n>BrH&F@>&>Qf{{wVDSS{~Vyq$7r z9MyRfUI_VFMx~e4puJA<g6xw9DUjnyv=~8oa(ZPYi$y&O+Yy(Ro`m|M`>0UovN?&9 z@Le<nHvsLqf`;IN9}K}Qx5tM7H{iXywXw}s>i!Tu;-D#RciA2ACPtt!2Z4-P0~onm z`&n;?01&!C0#$v}nGzoX?JCg`04GfQ09)gC78Q6K^vvF2iDf5xMV*1+G@aM~ls<A6 znbGMlx<t2g>spkju8+TczXphIQ*;ZdgWW;)wcp!~J2-$w3x@i`x`Vxo=v8CtsSwE) z+Z48y&vW4zb38wU=7i<sR<v|6P9q-Hnu_aXUocX-fNf{n=+=8WoLb`&_APIt){4^( z0}y2OP+@Nt(`orBqGk&qzs>L6tf#RPQ9KO-VS$><eiDEMgcibE(SHP_eMHqom#L9k zVLJ9K%IL#o)%YBkR3l$^D^ASkG%>iRI59pkIlL;?>-60>E2TEvm$!NL#f;MO2I2Vq z$Wyo<c!w<xHB1(|LQKMKCjs`g_X80tv4MDD^O&*8VzOWaY%onYC2W_1mn;ER^GC<R zd@O~84o^K^LGJHK%*`Zz-)hs0jT5EgZDDB`qM%q2pUp!@Uvx!0ipRCK^2?zF@EyE2 z^rYrMf5Zu^h25w$PxWl!<Nk<U1bWDT9x|YZk$YVU`Rxqfs9As}dOG(HJa~`7dbk7? zu#kHdLG*0zm9u3y0O&Yg2#M%=LI>tqDE|2++DDxPug_7rX7-`@#_(~|1R-QzTnL$y z<T$<nczzD>`@Fd0xY#{Nc8x;XUI4Tm=)0~0ZHGSD-+CrN+Z}$E9b6T63i9kLWu1O@ zJjkMvMHWP)X)qb+-22a;3wXAf&K39JSyasto;DQ9#jY@&OXgx?wtZECf^YSQv%6O! z`fZg%=L$TOLt`kgO|C(II;PL_9@W$Ewo<mh)_uofn73J_tZCE^f!9ED2}i8EOy`C7 zA#!*4y`Kweq`XTgJx^T~$Js{#Ar{>_1Mi(nVD{w+LX**(OD1~r_07E`w*WY+xPP~o z<i5xS$%PJP`NNZt<i@OcvkB&8#2hvtZlen_fA-gi-UK$0VYZd_gyU3r;anOgXONZ7 z@uTbTF8Zd#qPZwU3rcc6P?FbHp!gQ8r3t@x0kj4E)Ezi5z><dcA16GqIev8f4s;M2 zZ}K*2ZkQqj0f<H)Mc`$lh4C05*cC*nvt&*jR0RQPi&O1S?<FedJ%P(&8$SnuX@W)I zz(p|n53~q;un0hC2E>Wno0Gf<`mcdGy=%ZHu2<tHe@|=Rx%e7*IkDk{YoL%0Qi!b= zL43uv4&rt-_Mvbnn0$&5f8dFUexKx+Ghj!y-}mp-{C4@VzX<<KN5$Rvah@yi2t;O` zEhAvIkl5PQkfO<R8AKR7VMOR^uxZ&M%0@9Z{2X9I)UMwk0#<FP3h62((kB5s@oRyl z=)Z?whQsdxLL1Zoej$)P7dKb@OTd@(y+9!GmD91pAe))tzz@->VWlI8p9y6Cj82U0 zq3;GNok9F&;0Msy*eITaO0I9YT74Wh<SYKY%7q(NdA1BW&!6E_s~eCs0vO+@)ltl` z%17gqCE5$hjp;%B@L-SyGjcF04_*T~7?+1}E{vOmUnIo%4vgm*F90)JFt#&DUnP7s zP|dN0Ky?p3WCMW|Un*REn!p{<fB0J-u(k}GAk}P5%n?nHYD80#CW$5p;%vQ>l$fBh zz6mm-4jfY&I7{CIrHKiWlA8Em&W}H%2YcKJHRA+<w0}bm#=^i270oD)U^rLbNz+ql z4(Kn<4^X2;Vt!yQs*<Nk%uhqo`~>6e;rRC8_;z9($2gpX0LQovjN6TI+W{_`A)LM& zaxk7C6BC5foco{VXANp5cz&(}7EGUSV!**u-x3FD_^CH3kjK9h0T+*nz$E^e2o&%= z6v*W5BErX8L_p>5i9i`&Ap*1bKSf{;e?bK1@jr<`A^(jCEZ|`gSj?;5>^*hIH4#R# z$>)hMk`F#xgpsW9vNwAV<#E3V(;e7_B8=>pUns)Jr@2dnkyrDfB8=pQJ46`m$^7Jh zQ+PLqJ4Lty!(WInx_I;5B8=Z2=WQa4*E{ff5k|d;zb(ReP>R1S!gR>`SrNvgx_r3^ z<1t<y5@9-gy;y|l)bxB2#&g$vjtHYG1)nLxc=(#DB8;|lKJ~w8BU$*8*0gHV`{p@a z^=6;{9DTZW7?qgefS9o&#wKENAjT<Tj=YhmiEsv)V-n8fLB{X?N*P<<5U2t%2Sm(D z5i<#5Iz-HiA_h2e_J<<ow<4wxV%kJZwTSUS%z6>?kcd$sW|fG!<Bh)V37?aKAZx{r zW}}hFfy@6wf31c8;~!_g@TvYay70-^P;h%A-fNZKchOGG4&AQQ=EmMr>ZE{KPvkvR zj|L4ihG4P`$^5#1ByN~`4!HEcdtoVMyGv_Y^+Brm*+G_{s}Q{52;N{!wEJt*W4sqo z>wf@rcoLvN)*fW*LBu!pJf+SWFdLQHlz_P&pu3O`Xdj5V2gGM#yp~FzGX4UawwBap zK*Ms)T>OG6R+Z_m_2-&O#8(!3y2&DO{k3?<q7RDC&We7WVSs16c6PY$dNmpDRxy@J zttF5&m<Mop2EkaSB$|x<8wP9BfAasKPw^oO86`fzH)XwkvzVY;65rnYYI&dg&w$VH zZBF_O-+O(Z-wRrI;P>~4&5IB4HOJ({$M-z-$TXJ!@4vyvlD^z`2Kb2!j>j$xox8lw zGR2mmUnnF9h|>?nS(`o<Z)cN5dRAP*IE-KS8&!`LFNaJi+Lh2B)eAXpSD6A!8Q7E_ zgkTN^bM$Et%)?-wKAFCJ3o^_W<XZ{;`KLtrQ3(;}5OUC%AwI1g|6^IXs@$T=tsrcR z)|1axm7_9*E^dXO4))*|VNi6<<rlruXB%!YW4ACmW$SlO#m^F;)p^eCBo`K9_93Qo z#BH?ek<ME9rBF21N*6XXf@bm(Zr;Z~avuMBchx-($0;;<75>o2{C~4gF^0eXa(thn z=H+BK$r>*<Dqci;{FuT2Ko0thG+?7*$Un}!QE?%^>1EnEnEdkDb`JdL$bm!ha~QB0 z+5L7Z2KVk%{E=*kJ+Wc@i<f%0DvrH`b*o~p0=JY@)*QQle@4-K?Mr8Cvi-kAlV{zn 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 Btp5N2 literal 0 HcmV?d00001 diff --git a/venv/share/python-wheels/six-1.15.0-py2.py3-none-any.whl b/venv/share/python-wheels/six-1.15.0-py2.py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..f8d49c6a103dc9788d2b288ac68c4cc87e084b3d GIT binary patch literal 15549 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%0AFaC~KQ9}Siu(%fxy~wkEKB6YQcW)D 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 aSSkwAVE?7803iO^zyFb?s=5B_>VE+{=r3FV literal 0 HcmV?d00001 diff --git a/venv/share/python-wheels/toml-0.10.1-py2.py3-none-any.whl b/venv/share/python-wheels/toml-0.10.1-py2.py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..bccd1ad7a2447014f69cfecaeda65562b8188f31 GIT binary patch literal 20955 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 Q*C?_3DRw~k1pWQ&KkyWpx&QzG literal 0 HcmV?d00001 diff --git a/venv/share/python-wheels/urllib3-1.25.9-py2.py3-none-any.whl b/venv/share/python-wheels/urllib3-1.25.9-py2.py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..94fd9f7f0e383f3605fb607a060b8ed4d6a990ba GIT binary patch literal 123228 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 ZZ`qyKA|%><7Z3Qg3LZ2u90p?r@PDw(7$g7y literal 0 HcmV?d00001 diff --git a/venv/share/python-wheels/webencodings-0.5.1-py2.py3-none-any.whl b/venv/share/python-wheels/webencodings-0.5.1-py2.py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..c4a86c103ffc06807cb1d3ff5579fc4afeba46cf GIT binary patch literal 15749 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 Tfq<a@Txx%0Sm>Pp`1QX4IJ`|D literal 0 HcmV?d00001 diff --git a/venv/share/python-wheels/wheel-0.34.2-py2.py3-none-any.whl b/venv/share/python-wheels/wheel-0.34.2-py2.py3-none-any.whl new file mode 100644 index 0000000000000000000000000000000000000000..e6ac0091e21f4600b201b0929d99054c0f2e55d1 GIT binary patch literal 30875 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 Y67;WF?2iN*RDd#20D$GcqL%^w55=wCLjV8( literal 0 HcmV?d00001 From 6d44e09be6548a6b99324e7810e8697cc5cb5088 Mon Sep 17 00:00:00 2001 From: Adi Bozzhanov <kyoumabat@pop-os.localdomain> Date: Tue, 29 Jun 2021 03:14:44 +0100 Subject: [PATCH 08/17] feat: * run.py: now uses .env * set up pipenv for the project --- .gitignore | 2 + Pipfile | 13 + Pipfile.lock | 152 + src/bottoken.py | 1 - src/run.py | 13 +- venv/bin/Activate.ps1 | 241 - venv/bin/activate | 76 - venv/bin/activate.csh | 37 - venv/bin/activate.fish | 75 - venv/bin/chardetect | 8 - venv/bin/easy_install | 8 - venv/bin/easy_install-3.8 | 8 - venv/bin/pip | 8 - venv/bin/pip3 | 8 - venv/bin/pip3.8 | 8 - venv/bin/python | 1 - venv/bin/python3 | 1 - .../APScheduler-3.6.3.dist-info/INSTALLER | 1 - .../APScheduler-3.6.3.dist-info/LICENSE.txt | 19 - .../APScheduler-3.6.3.dist-info/METADATA | 133 - .../APScheduler-3.6.3.dist-info/RECORD | 83 - .../APScheduler-3.6.3.dist-info/WHEEL | 6 - .../entry_points.txt | 24 - .../APScheduler-3.6.3.dist-info/top_level.txt | 1 - .../site-packages/apscheduler/__init__.py | 10 - .../site-packages/apscheduler/events.py | 94 - .../apscheduler/executors/__init__.py | 0 .../apscheduler/executors/asyncio.py | 59 - .../apscheduler/executors/base.py | 146 - .../apscheduler/executors/base_py3.py | 41 - .../apscheduler/executors/debug.py | 20 - .../apscheduler/executors/gevent.py | 30 - .../apscheduler/executors/pool.py | 54 - .../apscheduler/executors/tornado.py | 54 - .../apscheduler/executors/twisted.py | 25 - .../site-packages/apscheduler/job.py | 301 - .../apscheduler/jobstores/__init__.py | 0 .../apscheduler/jobstores/base.py | 143 - .../apscheduler/jobstores/memory.py | 108 - .../apscheduler/jobstores/mongodb.py | 141 - .../apscheduler/jobstores/redis.py | 150 - .../apscheduler/jobstores/rethinkdb.py | 155 - .../apscheduler/jobstores/sqlalchemy.py | 154 - .../apscheduler/jobstores/zookeeper.py | 179 - .../apscheduler/schedulers/__init__.py | 12 - .../apscheduler/schedulers/asyncio.py | 68 - .../apscheduler/schedulers/background.py | 41 - .../apscheduler/schedulers/base.py | 1022 -- .../apscheduler/schedulers/blocking.py | 33 - .../apscheduler/schedulers/gevent.py | 35 - .../apscheduler/schedulers/qt.py | 43 - .../apscheduler/schedulers/tornado.py | 63 - .../apscheduler/schedulers/twisted.py | 62 - .../apscheduler/triggers/__init__.py | 0 .../apscheduler/triggers/base.py | 48 - .../apscheduler/triggers/combining.py | 95 - .../apscheduler/triggers/cron/__init__.py | 238 - .../apscheduler/triggers/cron/expressions.py | 251 - .../apscheduler/triggers/cron/fields.py | 111 - .../apscheduler/triggers/date.py | 51 - .../apscheduler/triggers/interval.py | 106 - .../site-packages/apscheduler/util.py | 429 - .../cachetools-4.2.2.dist-info/INSTALLER | 1 - .../cachetools-4.2.2.dist-info/LICENSE | 20 - .../cachetools-4.2.2.dist-info/METADATA | 129 - .../cachetools-4.2.2.dist-info/RECORD | 28 - .../cachetools-4.2.2.dist-info/WHEEL | 5 - .../cachetools-4.2.2.dist-info/top_level.txt | 1 - .../site-packages/cachetools/__init__.py | 24 - .../site-packages/cachetools/cache.py | 117 - .../site-packages/cachetools/decorators.py | 102 - .../site-packages/cachetools/fifo.py | 31 - .../site-packages/cachetools/func.py | 176 - .../site-packages/cachetools/keys.py | 52 - .../python3.8/site-packages/cachetools/lfu.py | 34 - .../python3.8/site-packages/cachetools/lru.py | 40 - .../python3.8/site-packages/cachetools/mru.py | 40 - .../python3.8/site-packages/cachetools/rr.py | 34 - .../python3.8/site-packages/cachetools/ttl.py | 207 - .../certifi-2021.5.30.dist-info/INSTALLER | 1 - .../certifi-2021.5.30.dist-info/LICENSE | 21 - .../certifi-2021.5.30.dist-info/METADATA | 83 - .../certifi-2021.5.30.dist-info/RECORD | 13 - .../certifi-2021.5.30.dist-info/WHEEL | 6 - .../certifi-2021.5.30.dist-info/top_level.txt | 1 - .../site-packages/certifi/__init__.py | 3 - .../site-packages/certifi/__main__.py | 12 - .../site-packages/certifi/cacert.pem | 4257 --------- .../python3.8/site-packages/certifi/core.py | 60 - .../chardet-4.0.0.dist-info/INSTALLER | 1 - .../chardet-4.0.0.dist-info/LICENSE | 504 - .../chardet-4.0.0.dist-info/METADATA | 101 - .../chardet-4.0.0.dist-info/RECORD | 94 - .../chardet-4.0.0.dist-info/WHEEL | 6 - .../chardet-4.0.0.dist-info/entry_points.txt | 3 - .../chardet-4.0.0.dist-info/top_level.txt | 1 - .../site-packages/chardet/__init__.py | 83 - .../site-packages/chardet/big5freq.py | 386 - .../site-packages/chardet/big5prober.py | 47 - .../site-packages/chardet/chardistribution.py | 233 - .../chardet/charsetgroupprober.py | 107 - .../site-packages/chardet/charsetprober.py | 145 - .../site-packages/chardet/cli/__init__.py | 1 - .../site-packages/chardet/cli/chardetect.py | 84 - .../chardet/codingstatemachine.py | 88 - .../python3.8/site-packages/chardet/compat.py | 36 - .../site-packages/chardet/cp949prober.py | 49 - .../python3.8/site-packages/chardet/enums.py | 76 - .../site-packages/chardet/escprober.py | 101 - .../python3.8/site-packages/chardet/escsm.py | 246 - .../site-packages/chardet/eucjpprober.py | 92 - .../site-packages/chardet/euckrfreq.py | 195 - .../site-packages/chardet/euckrprober.py | 47 - .../site-packages/chardet/euctwfreq.py | 387 - .../site-packages/chardet/euctwprober.py | 46 - .../site-packages/chardet/gb2312freq.py | 283 - .../site-packages/chardet/gb2312prober.py | 46 - .../site-packages/chardet/hebrewprober.py | 292 - .../site-packages/chardet/jisfreq.py | 325 - .../python3.8/site-packages/chardet/jpcntx.py | 233 - .../chardet/langbulgarianmodel.py | 4650 --------- .../site-packages/chardet/langgreekmodel.py | 4398 --------- .../site-packages/chardet/langhebrewmodel.py | 4383 --------- .../chardet/langhungarianmodel.py | 4650 --------- .../site-packages/chardet/langrussianmodel.py | 5718 ----------- .../site-packages/chardet/langthaimodel.py | 4383 --------- .../site-packages/chardet/langturkishmodel.py | 4383 --------- .../site-packages/chardet/latin1prober.py | 145 - .../site-packages/chardet/mbcharsetprober.py | 91 - .../site-packages/chardet/mbcsgroupprober.py | 54 - .../python3.8/site-packages/chardet/mbcssm.py | 572 -- .../chardet/metadata/__init__.py | 0 .../chardet/metadata/languages.py | 310 - .../site-packages/chardet/sbcharsetprober.py | 145 - .../site-packages/chardet/sbcsgroupprober.py | 83 - .../site-packages/chardet/sjisprober.py | 92 - .../chardet/universaldetector.py | 286 - .../site-packages/chardet/utf8prober.py | 82 - .../site-packages/chardet/version.py | 9 - .../python3.8/site-packages/easy_install.py | 5 - .../idna-2.10.dist-info/INSTALLER | 1 - .../idna-2.10.dist-info/LICENSE.rst | 34 - .../idna-2.10.dist-info/METADATA | 243 - .../site-packages/idna-2.10.dist-info/RECORD | 22 - .../site-packages/idna-2.10.dist-info/WHEEL | 6 - .../idna-2.10.dist-info/top_level.txt | 1 - .../python3.8/site-packages/idna/__init__.py | 2 - .../lib/python3.8/site-packages/idna/codec.py | 118 - .../python3.8/site-packages/idna/compat.py | 12 - venv/lib/python3.8/site-packages/idna/core.py | 400 - .../python3.8/site-packages/idna/idnadata.py | 2050 ---- .../python3.8/site-packages/idna/intranges.py | 53 - .../site-packages/idna/package_data.py | 2 - .../python3.8/site-packages/idna/uts46data.py | 8357 ----------------- .../pip-20.1.1.dist-info/INSTALLER | 1 - .../pip-20.1.1.dist-info/LICENSE.txt | 20 - .../pip-20.1.1.dist-info/METADATA | 87 - .../site-packages/pip-20.1.1.dist-info/RECORD | 272 - .../site-packages/pip-20.1.1.dist-info/WHEEL | 6 - .../pip-20.1.1.dist-info/entry_points.txt | 5 - .../pip-20.1.1.dist-info/top_level.txt | 1 - .../python3.8/site-packages/pip/__init__.py | 18 - .../python3.8/site-packages/pip/__main__.py | 26 - .../site-packages/pip/_internal/__init__.py | 17 - .../site-packages/pip/_internal/build_env.py | 219 - .../site-packages/pip/_internal/cache.py | 349 - .../pip/_internal/cli/__init__.py | 4 - .../pip/_internal/cli/autocompletion.py | 164 - .../pip/_internal/cli/base_command.py | 228 - .../pip/_internal/cli/cmdoptions.py | 962 -- .../pip/_internal/cli/command_context.py | 36 - .../site-packages/pip/_internal/cli/main.py | 75 - .../pip/_internal/cli/main_parser.py | 99 - .../site-packages/pip/_internal/cli/parser.py | 266 - .../pip/_internal/cli/progress_bars.py | 277 - .../pip/_internal/cli/req_command.py | 408 - .../pip/_internal/cli/spinners.py | 173 - .../pip/_internal/cli/status_codes.py | 8 - .../pip/_internal/commands/__init__.py | 122 - .../pip/_internal/commands/cache.py | 181 - .../pip/_internal/commands/check.py | 51 - .../pip/_internal/commands/completion.py | 95 - .../pip/_internal/commands/configuration.py | 233 - .../pip/_internal/commands/debug.py | 258 - .../pip/_internal/commands/download.py | 142 - .../pip/_internal/commands/freeze.py | 99 - .../pip/_internal/commands/hash.py | 58 - .../pip/_internal/commands/help.py | 41 - .../pip/_internal/commands/install.py | 717 -- .../pip/_internal/commands/list.py | 301 - .../pip/_internal/commands/search.py | 146 - .../pip/_internal/commands/show.py | 180 - .../pip/_internal/commands/uninstall.py | 89 - .../pip/_internal/commands/wheel.py | 190 - .../pip/_internal/configuration.py | 426 - .../pip/_internal/distributions/__init__.py | 24 - .../pip/_internal/distributions/base.py | 45 - .../pip/_internal/distributions/installed.py | 24 - .../pip/_internal/distributions/sdist.py | 104 - .../pip/_internal/distributions/wheel.py | 36 - .../site-packages/pip/_internal/exceptions.py | 308 - .../pip/_internal/index/__init__.py | 2 - .../pip/_internal/index/collector.py | 661 -- .../pip/_internal/index/package_finder.py | 1016 -- .../site-packages/pip/_internal/locations.py | 200 - .../site-packages/pip/_internal/main.py | 16 - .../pip/_internal/models/__init__.py | 2 - .../pip/_internal/models/candidate.py | 36 - .../pip/_internal/models/direct_url.py | 245 - .../pip/_internal/models/format_control.py | 84 - .../pip/_internal/models/index.py | 31 - .../pip/_internal/models/link.py | 236 - .../pip/_internal/models/scheme.py | 25 - .../pip/_internal/models/search_scope.py | 133 - .../pip/_internal/models/selection_prefs.py | 47 - .../pip/_internal/models/target_python.py | 110 - .../pip/_internal/models/wheel.py | 78 - .../pip/_internal/network/__init__.py | 2 - .../pip/_internal/network/auth.py | 298 - .../pip/_internal/network/cache.py | 81 - .../pip/_internal/network/download.py | 200 - .../pip/_internal/network/session.py | 421 - .../pip/_internal/network/utils.py | 48 - .../pip/_internal/network/xmlrpc.py | 44 - .../pip/_internal/operations/__init__.py | 0 .../_internal/operations/build/__init__.py | 0 .../_internal/operations/build/metadata.py | 40 - .../operations/build/metadata_legacy.py | 77 - .../pip/_internal/operations/build/wheel.py | 46 - .../operations/build/wheel_legacy.py | 115 - .../pip/_internal/operations/check.py | 163 - .../pip/_internal/operations/freeze.py | 272 - .../_internal/operations/install/__init__.py | 2 - .../operations/install/editable_legacy.py | 52 - .../_internal/operations/install/legacy.py | 142 - .../pip/_internal/operations/install/wheel.py | 631 -- .../pip/_internal/operations/prepare.py | 568 -- .../site-packages/pip/_internal/pyproject.py | 196 - .../pip/_internal/req/__init__.py | 92 - .../pip/_internal/req/constructors.py | 464 - .../pip/_internal/req/req_file.py | 582 -- .../pip/_internal/req/req_install.py | 850 -- .../pip/_internal/req/req_set.py | 202 - .../pip/_internal/req/req_tracker.py | 151 - .../pip/_internal/req/req_uninstall.py | 649 -- .../pip/_internal/resolution/__init__.py | 0 .../pip/_internal/resolution/base.py | 20 - .../_internal/resolution/legacy/__init__.py | 0 .../_internal/resolution/legacy/resolver.py | 459 - .../resolution/resolvelib/__init__.py | 0 .../_internal/resolution/resolvelib/base.py | 52 - .../resolution/resolvelib/candidates.py | 450 - .../resolution/resolvelib/factory.py | 201 - .../resolution/resolvelib/provider.py | 54 - .../resolution/resolvelib/requirements.py | 119 - .../resolution/resolvelib/resolver.py | 174 - .../pip/_internal/self_outdated_check.py | 242 - .../pip/_internal/utils/__init__.py | 0 .../pip/_internal/utils/appdirs.py | 44 - .../pip/_internal/utils/compat.py | 270 - .../pip/_internal/utils/compatibility_tags.py | 169 - .../pip/_internal/utils/deprecation.py | 104 - .../pip/_internal/utils/direct_url_helpers.py | 130 - .../pip/_internal/utils/distutils_args.py | 48 - .../pip/_internal/utils/encoding.py | 42 - .../pip/_internal/utils/entrypoints.py | 31 - .../pip/_internal/utils/filesystem.py | 222 - .../pip/_internal/utils/filetypes.py | 16 - .../pip/_internal/utils/glibc.py | 98 - .../pip/_internal/utils/hashes.py | 133 - .../_internal/utils/inject_securetransport.py | 36 - .../pip/_internal/utils/logging.py | 399 - .../site-packages/pip/_internal/utils/misc.py | 927 -- .../pip/_internal/utils/models.py | 42 - .../pip/_internal/utils/packaging.py | 94 - .../pip/_internal/utils/pkg_resources.py | 44 - .../pip/_internal/utils/setuptools_build.py | 181 - .../pip/_internal/utils/subprocess.py | 277 - .../pip/_internal/utils/temp_dir.py | 271 - .../pip/_internal/utils/typing.py | 38 - .../pip/_internal/utils/unpacking.py | 272 - .../site-packages/pip/_internal/utils/urls.py | 55 - .../pip/_internal/utils/virtualenv.py | 116 - .../pip/_internal/utils/wheel.py | 225 - .../pip/_internal/vcs/__init__.py | 15 - .../site-packages/pip/_internal/vcs/bazaar.py | 120 - .../site-packages/pip/_internal/vcs/git.py | 394 - .../pip/_internal/vcs/mercurial.py | 161 - .../pip/_internal/vcs/subversion.py | 334 - .../pip/_internal/vcs/versioncontrol.py | 723 -- .../pip/_internal/wheel_builder.py | 309 - .../site-packages/pip/_vendor/__init__.py | 123 - .../pkg_resources-0.0.0.dist-info/AUTHORS.txt | 566 -- .../pkg_resources-0.0.0.dist-info/INSTALLER | 1 - .../pkg_resources-0.0.0.dist-info/LICENSE.txt | 20 - .../pkg_resources-0.0.0.dist-info/METADATA | 13 - .../pkg_resources-0.0.0.dist-info/RECORD | 38 - .../pkg_resources-0.0.0.dist-info/WHEEL | 6 - .../site-packages/pkg_resources/__init__.py | 3296 ------- .../pkg_resources/_vendor/__init__.py | 0 .../pkg_resources/_vendor/appdirs.py | 608 -- .../_vendor/packaging/__about__.py | 21 - .../_vendor/packaging/__init__.py | 14 - .../_vendor/packaging/_compat.py | 30 - .../_vendor/packaging/_structures.py | 68 - .../_vendor/packaging/markers.py | 301 - .../_vendor/packaging/requirements.py | 127 - .../_vendor/packaging/specifiers.py | 774 -- .../pkg_resources/_vendor/packaging/utils.py | 14 - .../_vendor/packaging/version.py | 393 - .../pkg_resources/_vendor/pyparsing.py | 5742 ----------- .../pkg_resources/_vendor/six.py | 868 -- .../pkg_resources/extern/__init__.py | 73 - .../site-packages/pkg_resources/py31compat.py | 23 - .../INSTALLER | 1 - .../LICENSE.dual | 792 -- .../METADATA | 285 - .../python_telegram_bot-13.6.dist-info/RECORD | 365 - .../python_telegram_bot-13.6.dist-info/WHEEL | 5 - .../top_level.txt | 1 - .../pytz-2021.1.dist-info/DESCRIPTION.rst | 598 -- .../pytz-2021.1.dist-info/INSTALLER | 1 - .../pytz-2021.1.dist-info/LICENSE.txt | 19 - .../pytz-2021.1.dist-info/METADATA | 634 -- .../pytz-2021.1.dist-info/RECORD | 620 -- .../site-packages/pytz-2021.1.dist-info/WHEEL | 6 - .../pytz-2021.1.dist-info/metadata.json | 1 - .../pytz-2021.1.dist-info/top_level.txt | 1 - .../pytz-2021.1.dist-info/zip-safe | 1 - .../python3.8/site-packages/pytz/__init__.py | 1558 --- .../site-packages/pytz/exceptions.py | 59 - venv/lib/python3.8/site-packages/pytz/lazy.py | 172 - .../python3.8/site-packages/pytz/reference.py | 140 - .../python3.8/site-packages/pytz/tzfile.py | 133 - .../python3.8/site-packages/pytz/tzinfo.py | 577 -- .../pytz/zoneinfo/Africa/Abidjan | Bin 148 -> 0 bytes .../site-packages/pytz/zoneinfo/Africa/Accra | Bin 1060 -> 0 bytes .../pytz/zoneinfo/Africa/Addis_Ababa | Bin 265 -> 0 bytes .../pytz/zoneinfo/Africa/Algiers | Bin 735 -> 0 bytes .../site-packages/pytz/zoneinfo/Africa/Asmara | Bin 265 -> 0 bytes .../site-packages/pytz/zoneinfo/Africa/Asmera | Bin 265 -> 0 bytes .../site-packages/pytz/zoneinfo/Africa/Bamako | Bin 148 -> 0 bytes .../site-packages/pytz/zoneinfo/Africa/Bangui | Bin 235 -> 0 bytes .../site-packages/pytz/zoneinfo/Africa/Banjul | Bin 148 -> 0 bytes .../site-packages/pytz/zoneinfo/Africa/Bissau | Bin 194 -> 0 bytes .../pytz/zoneinfo/Africa/Blantyre | Bin 149 -> 0 bytes .../pytz/zoneinfo/Africa/Brazzaville | Bin 235 -> 0 bytes .../pytz/zoneinfo/Africa/Bujumbura | Bin 149 -> 0 bytes .../site-packages/pytz/zoneinfo/Africa/Cairo | Bin 1955 -> 0 bytes .../pytz/zoneinfo/Africa/Casablanca | Bin 2429 -> 0 bytes .../site-packages/pytz/zoneinfo/Africa/Ceuta | Bin 2036 -> 0 bytes .../pytz/zoneinfo/Africa/Conakry | Bin 148 -> 0 bytes .../site-packages/pytz/zoneinfo/Africa/Dakar | Bin 148 -> 0 bytes .../pytz/zoneinfo/Africa/Dar_es_Salaam | Bin 265 -> 0 bytes .../pytz/zoneinfo/Africa/Djibouti | Bin 265 -> 0 bytes .../site-packages/pytz/zoneinfo/Africa/Douala | Bin 235 -> 0 bytes .../pytz/zoneinfo/Africa/El_Aaiun | Bin 2295 -> 0 bytes .../pytz/zoneinfo/Africa/Freetown | Bin 148 -> 0 bytes .../pytz/zoneinfo/Africa/Gaborone | Bin 149 -> 0 bytes .../site-packages/pytz/zoneinfo/Africa/Harare | Bin 149 -> 0 bytes .../pytz/zoneinfo/Africa/Johannesburg | Bin 246 -> 0 bytes .../site-packages/pytz/zoneinfo/Africa/Juba | Bin 679 -> 0 bytes .../pytz/zoneinfo/Africa/Kampala | Bin 265 -> 0 bytes .../pytz/zoneinfo/Africa/Khartoum | Bin 679 -> 0 bytes .../site-packages/pytz/zoneinfo/Africa/Kigali | Bin 149 -> 0 bytes .../pytz/zoneinfo/Africa/Kinshasa | Bin 235 -> 0 bytes .../site-packages/pytz/zoneinfo/Africa/Lagos | Bin 235 -> 0 bytes .../pytz/zoneinfo/Africa/Libreville | Bin 235 -> 0 bytes .../site-packages/pytz/zoneinfo/Africa/Lome | Bin 148 -> 0 bytes .../site-packages/pytz/zoneinfo/Africa/Luanda | Bin 235 -> 0 bytes .../pytz/zoneinfo/Africa/Lubumbashi | Bin 149 -> 0 bytes .../site-packages/pytz/zoneinfo/Africa/Lusaka | Bin 149 -> 0 bytes .../site-packages/pytz/zoneinfo/Africa/Malabo | Bin 235 -> 0 bytes .../site-packages/pytz/zoneinfo/Africa/Maputo | Bin 149 -> 0 bytes .../site-packages/pytz/zoneinfo/Africa/Maseru | Bin 246 -> 0 bytes .../pytz/zoneinfo/Africa/Mbabane | Bin 246 -> 0 bytes .../pytz/zoneinfo/Africa/Mogadishu | Bin 265 -> 0 bytes .../pytz/zoneinfo/Africa/Monrovia | Bin 208 -> 0 bytes .../pytz/zoneinfo/Africa/Nairobi | Bin 265 -> 0 bytes .../pytz/zoneinfo/Africa/Ndjamena | Bin 199 -> 0 bytes .../site-packages/pytz/zoneinfo/Africa/Niamey | Bin 235 -> 0 bytes .../pytz/zoneinfo/Africa/Nouakchott | Bin 148 -> 0 bytes .../pytz/zoneinfo/Africa/Ouagadougou | Bin 148 -> 0 bytes .../pytz/zoneinfo/Africa/Porto-Novo | Bin 235 -> 0 bytes .../pytz/zoneinfo/Africa/Sao_Tome | Bin 254 -> 0 bytes .../pytz/zoneinfo/Africa/Timbuktu | Bin 148 -> 0 bytes .../pytz/zoneinfo/Africa/Tripoli | Bin 625 -> 0 bytes .../site-packages/pytz/zoneinfo/Africa/Tunis | Bin 689 -> 0 bytes .../pytz/zoneinfo/Africa/Windhoek | Bin 955 -> 0 bytes .../site-packages/pytz/zoneinfo/America/Adak | Bin 2356 -> 0 bytes .../pytz/zoneinfo/America/Anchorage | Bin 2371 -> 0 bytes .../pytz/zoneinfo/America/Anguilla | Bin 148 -> 0 bytes .../pytz/zoneinfo/America/Antigua | Bin 148 -> 0 bytes .../pytz/zoneinfo/America/Araguaina | Bin 884 -> 0 bytes .../zoneinfo/America/Argentina/Buenos_Aires | Bin 1076 -> 0 bytes .../pytz/zoneinfo/America/Argentina/Catamarca | Bin 1076 -> 0 bytes .../zoneinfo/America/Argentina/ComodRivadavia | Bin 1076 -> 0 bytes .../pytz/zoneinfo/America/Argentina/Cordoba | Bin 1076 -> 0 bytes .../pytz/zoneinfo/America/Argentina/Jujuy | Bin 1048 -> 0 bytes .../pytz/zoneinfo/America/Argentina/La_Rioja | Bin 1090 -> 0 bytes .../pytz/zoneinfo/America/Argentina/Mendoza | Bin 1076 -> 0 bytes .../zoneinfo/America/Argentina/Rio_Gallegos | Bin 1076 -> 0 bytes .../pytz/zoneinfo/America/Argentina/Salta | Bin 1048 -> 0 bytes .../pytz/zoneinfo/America/Argentina/San_Juan | Bin 1090 -> 0 bytes .../pytz/zoneinfo/America/Argentina/San_Luis | Bin 1102 -> 0 bytes .../pytz/zoneinfo/America/Argentina/Tucuman | Bin 1104 -> 0 bytes .../pytz/zoneinfo/America/Argentina/Ushuaia | Bin 1076 -> 0 bytes .../site-packages/pytz/zoneinfo/America/Aruba | Bin 186 -> 0 bytes .../pytz/zoneinfo/America/Asuncion | Bin 2044 -> 0 bytes .../pytz/zoneinfo/America/Atikokan | Bin 336 -> 0 bytes .../site-packages/pytz/zoneinfo/America/Atka | Bin 2356 -> 0 bytes .../site-packages/pytz/zoneinfo/America/Bahia | Bin 1024 -> 0 bytes .../pytz/zoneinfo/America/Bahia_Banderas | Bin 1546 -> 0 bytes .../pytz/zoneinfo/America/Barbados | Bin 314 -> 0 bytes .../site-packages/pytz/zoneinfo/America/Belem | Bin 576 -> 0 bytes .../pytz/zoneinfo/America/Belize | Bin 1614 -> 0 bytes .../pytz/zoneinfo/America/Blanc-Sablon | Bin 298 -> 0 bytes .../pytz/zoneinfo/America/Boa_Vista | Bin 632 -> 0 bytes .../pytz/zoneinfo/America/Bogota | Bin 246 -> 0 bytes .../site-packages/pytz/zoneinfo/America/Boise | Bin 2394 -> 0 bytes .../pytz/zoneinfo/America/Buenos_Aires | Bin 1076 -> 0 bytes .../pytz/zoneinfo/America/Cambridge_Bay | Bin 2084 -> 0 bytes .../pytz/zoneinfo/America/Campo_Grande | Bin 1444 -> 0 bytes .../pytz/zoneinfo/America/Cancun | Bin 782 -> 0 bytes .../pytz/zoneinfo/America/Caracas | Bin 264 -> 0 bytes .../pytz/zoneinfo/America/Catamarca | Bin 1076 -> 0 bytes .../pytz/zoneinfo/America/Cayenne | Bin 198 -> 0 bytes .../pytz/zoneinfo/America/Cayman | Bin 182 -> 0 bytes .../pytz/zoneinfo/America/Chicago | Bin 3576 -> 0 bytes .../pytz/zoneinfo/America/Chihuahua | Bin 1484 -> 0 bytes .../pytz/zoneinfo/America/Coral_Harbour | Bin 336 -> 0 bytes .../pytz/zoneinfo/America/Cordoba | Bin 1076 -> 0 bytes .../pytz/zoneinfo/America/Costa_Rica | Bin 316 -> 0 bytes .../pytz/zoneinfo/America/Creston | Bin 208 -> 0 bytes .../pytz/zoneinfo/America/Cuiaba | Bin 1416 -> 0 bytes .../pytz/zoneinfo/America/Curacao | Bin 186 -> 0 bytes .../pytz/zoneinfo/America/Danmarkshavn | Bin 698 -> 0 bytes .../pytz/zoneinfo/America/Dawson | Bin 1614 -> 0 bytes .../pytz/zoneinfo/America/Dawson_Creek | Bin 1050 -> 0 bytes .../pytz/zoneinfo/America/Denver | Bin 2444 -> 0 bytes .../pytz/zoneinfo/America/Detroit | Bin 2230 -> 0 bytes .../pytz/zoneinfo/America/Dominica | Bin 148 -> 0 bytes .../pytz/zoneinfo/America/Edmonton | Bin 2332 -> 0 bytes .../pytz/zoneinfo/America/Eirunepe | Bin 656 -> 0 bytes .../pytz/zoneinfo/America/El_Salvador | Bin 224 -> 0 bytes .../pytz/zoneinfo/America/Ensenada | Bin 2342 -> 0 bytes .../pytz/zoneinfo/America/Fort_Nelson | Bin 2240 -> 0 bytes .../pytz/zoneinfo/America/Fort_Wayne | Bin 1666 -> 0 bytes .../pytz/zoneinfo/America/Fortaleza | Bin 716 -> 0 bytes .../pytz/zoneinfo/America/Glace_Bay | Bin 2192 -> 0 bytes .../pytz/zoneinfo/America/Godthab | Bin 1878 -> 0 bytes .../pytz/zoneinfo/America/Goose_Bay | Bin 3210 -> 0 bytes .../pytz/zoneinfo/America/Grand_Turk | Bin 1834 -> 0 bytes .../pytz/zoneinfo/America/Grenada | Bin 148 -> 0 bytes .../pytz/zoneinfo/America/Guadeloupe | Bin 148 -> 0 bytes .../pytz/zoneinfo/America/Guatemala | Bin 280 -> 0 bytes .../pytz/zoneinfo/America/Guayaquil | Bin 246 -> 0 bytes .../pytz/zoneinfo/America/Guyana | Bin 236 -> 0 bytes .../pytz/zoneinfo/America/Halifax | Bin 3424 -> 0 bytes .../pytz/zoneinfo/America/Havana | Bin 2416 -> 0 bytes .../pytz/zoneinfo/America/Hermosillo | Bin 416 -> 0 bytes .../zoneinfo/America/Indiana/Indianapolis | Bin 1666 -> 0 bytes .../pytz/zoneinfo/America/Indiana/Knox | Bin 2428 -> 0 bytes .../pytz/zoneinfo/America/Indiana/Marengo | Bin 1722 -> 0 bytes .../pytz/zoneinfo/America/Indiana/Petersburg | Bin 1904 -> 0 bytes .../pytz/zoneinfo/America/Indiana/Tell_City | Bin 1684 -> 0 bytes .../pytz/zoneinfo/America/Indiana/Vevay | Bin 1414 -> 0 bytes .../pytz/zoneinfo/America/Indiana/Vincennes | Bin 1694 -> 0 bytes .../pytz/zoneinfo/America/Indiana/Winamac | Bin 1778 -> 0 bytes .../pytz/zoneinfo/America/Indianapolis | Bin 1666 -> 0 bytes .../pytz/zoneinfo/America/Inuvik | Bin 1894 -> 0 bytes .../pytz/zoneinfo/America/Iqaluit | Bin 2032 -> 0 bytes .../pytz/zoneinfo/America/Jamaica | Bin 482 -> 0 bytes .../site-packages/pytz/zoneinfo/America/Jujuy | Bin 1048 -> 0 bytes .../pytz/zoneinfo/America/Juneau | Bin 2353 -> 0 bytes .../pytz/zoneinfo/America/Kentucky/Louisville | Bin 2772 -> 0 bytes .../pytz/zoneinfo/America/Kentucky/Monticello | Bin 2352 -> 0 bytes .../pytz/zoneinfo/America/Knox_IN | Bin 2428 -> 0 bytes .../pytz/zoneinfo/America/Kralendijk | Bin 186 -> 0 bytes .../pytz/zoneinfo/America/La_Paz | Bin 232 -> 0 bytes .../site-packages/pytz/zoneinfo/America/Lima | Bin 406 -> 0 bytes .../pytz/zoneinfo/America/Los_Angeles | Bin 2836 -> 0 bytes .../pytz/zoneinfo/America/Louisville | Bin 2772 -> 0 bytes .../pytz/zoneinfo/America/Lower_Princes | Bin 186 -> 0 bytes .../pytz/zoneinfo/America/Maceio | Bin 744 -> 0 bytes .../pytz/zoneinfo/America/Managua | Bin 430 -> 0 bytes .../pytz/zoneinfo/America/Manaus | Bin 604 -> 0 bytes .../pytz/zoneinfo/America/Marigot | Bin 148 -> 0 bytes .../pytz/zoneinfo/America/Martinique | Bin 232 -> 0 bytes .../pytz/zoneinfo/America/Matamoros | Bin 1390 -> 0 bytes .../pytz/zoneinfo/America/Mazatlan | Bin 1526 -> 0 bytes .../pytz/zoneinfo/America/Mendoza | Bin 1076 -> 0 bytes .../pytz/zoneinfo/America/Menominee | Bin 2274 -> 0 bytes .../pytz/zoneinfo/America/Merida | Bin 1422 -> 0 bytes .../pytz/zoneinfo/America/Metlakatla | Bin 1423 -> 0 bytes .../pytz/zoneinfo/America/Mexico_City | Bin 1584 -> 0 bytes .../pytz/zoneinfo/America/Miquelon | Bin 1666 -> 0 bytes .../pytz/zoneinfo/America/Moncton | Bin 3154 -> 0 bytes .../pytz/zoneinfo/America/Monterrey | Bin 1390 -> 0 bytes .../pytz/zoneinfo/America/Montevideo | Bin 1510 -> 0 bytes .../pytz/zoneinfo/America/Montreal | Bin 3494 -> 0 bytes .../pytz/zoneinfo/America/Montserrat | Bin 148 -> 0 bytes .../pytz/zoneinfo/America/Nassau | Bin 2388 -> 0 bytes .../pytz/zoneinfo/America/New_York | Bin 3536 -> 0 bytes .../pytz/zoneinfo/America/Nipigon | Bin 2122 -> 0 bytes .../site-packages/pytz/zoneinfo/America/Nome | Bin 2367 -> 0 bytes .../pytz/zoneinfo/America/Noronha | Bin 716 -> 0 bytes .../pytz/zoneinfo/America/North_Dakota/Beulah | Bin 2380 -> 0 bytes .../pytz/zoneinfo/America/North_Dakota/Center | Bin 2380 -> 0 bytes .../zoneinfo/America/North_Dakota/New_Salem | Bin 2380 -> 0 bytes .../site-packages/pytz/zoneinfo/America/Nuuk | Bin 1878 -> 0 bytes .../pytz/zoneinfo/America/Ojinaga | Bin 1484 -> 0 bytes .../pytz/zoneinfo/America/Panama | Bin 182 -> 0 bytes .../pytz/zoneinfo/America/Pangnirtung | Bin 2094 -> 0 bytes .../pytz/zoneinfo/America/Paramaribo | Bin 262 -> 0 bytes .../pytz/zoneinfo/America/Phoenix | Bin 328 -> 0 bytes .../pytz/zoneinfo/America/Port-au-Prince | Bin 1434 -> 0 bytes .../pytz/zoneinfo/America/Port_of_Spain | Bin 148 -> 0 bytes .../pytz/zoneinfo/America/Porto_Acre | Bin 628 -> 0 bytes .../pytz/zoneinfo/America/Porto_Velho | Bin 576 -> 0 bytes .../pytz/zoneinfo/America/Puerto_Rico | Bin 246 -> 0 bytes .../pytz/zoneinfo/America/Punta_Arenas | Bin 1902 -> 0 bytes .../pytz/zoneinfo/America/Rainy_River | Bin 2122 -> 0 bytes .../pytz/zoneinfo/America/Rankin_Inlet | Bin 1892 -> 0 bytes .../pytz/zoneinfo/America/Recife | Bin 716 -> 0 bytes .../pytz/zoneinfo/America/Regina | Bin 980 -> 0 bytes .../pytz/zoneinfo/America/Resolute | Bin 1892 -> 0 bytes .../pytz/zoneinfo/America/Rio_Branco | Bin 628 -> 0 bytes .../pytz/zoneinfo/America/Rosario | Bin 1076 -> 0 bytes .../pytz/zoneinfo/America/Santa_Isabel | Bin 2342 -> 0 bytes .../pytz/zoneinfo/America/Santarem | Bin 602 -> 0 bytes .../pytz/zoneinfo/America/Santiago | Bin 2529 -> 0 bytes .../pytz/zoneinfo/America/Santo_Domingo | Bin 458 -> 0 bytes .../pytz/zoneinfo/America/Sao_Paulo | Bin 1444 -> 0 bytes .../pytz/zoneinfo/America/Scoresbysund | Bin 1916 -> 0 bytes .../pytz/zoneinfo/America/Shiprock | Bin 2444 -> 0 bytes .../site-packages/pytz/zoneinfo/America/Sitka | Bin 2329 -> 0 bytes .../pytz/zoneinfo/America/St_Barthelemy | Bin 148 -> 0 bytes .../pytz/zoneinfo/America/St_Johns | Bin 3655 -> 0 bytes .../pytz/zoneinfo/America/St_Kitts | Bin 148 -> 0 bytes .../pytz/zoneinfo/America/St_Lucia | Bin 148 -> 0 bytes .../pytz/zoneinfo/America/St_Thomas | Bin 148 -> 0 bytes .../pytz/zoneinfo/America/St_Vincent | Bin 148 -> 0 bytes .../pytz/zoneinfo/America/Swift_Current | Bin 560 -> 0 bytes .../pytz/zoneinfo/America/Tegucigalpa | Bin 252 -> 0 bytes .../site-packages/pytz/zoneinfo/America/Thule | Bin 1502 -> 0 bytes .../pytz/zoneinfo/America/Thunder_Bay | Bin 2202 -> 0 bytes .../pytz/zoneinfo/America/Tijuana | Bin 2342 -> 0 bytes .../pytz/zoneinfo/America/Toronto | Bin 3494 -> 0 bytes .../pytz/zoneinfo/America/Tortola | Bin 148 -> 0 bytes .../pytz/zoneinfo/America/Vancouver | Bin 2892 -> 0 bytes .../pytz/zoneinfo/America/Virgin | Bin 148 -> 0 bytes .../pytz/zoneinfo/America/Whitehorse | Bin 1614 -> 0 bytes .../pytz/zoneinfo/America/Winnipeg | Bin 2868 -> 0 bytes .../pytz/zoneinfo/America/Yakutat | Bin 2305 -> 0 bytes .../pytz/zoneinfo/America/Yellowknife | Bin 1966 -> 0 bytes .../pytz/zoneinfo/Antarctica/Casey | Bin 384 -> 0 bytes .../pytz/zoneinfo/Antarctica/Davis | Bin 297 -> 0 bytes .../pytz/zoneinfo/Antarctica/DumontDUrville | Bin 194 -> 0 bytes .../pytz/zoneinfo/Antarctica/Macquarie | Bin 2260 -> 0 bytes .../pytz/zoneinfo/Antarctica/Mawson | Bin 199 -> 0 bytes .../pytz/zoneinfo/Antarctica/McMurdo | Bin 2437 -> 0 bytes .../pytz/zoneinfo/Antarctica/Palmer | Bin 1418 -> 0 bytes .../pytz/zoneinfo/Antarctica/Rothera | Bin 164 -> 0 bytes .../pytz/zoneinfo/Antarctica/South_Pole | Bin 2437 -> 0 bytes .../pytz/zoneinfo/Antarctica/Syowa | Bin 165 -> 0 bytes .../pytz/zoneinfo/Antarctica/Troll | Bin 1162 -> 0 bytes .../pytz/zoneinfo/Antarctica/Vostok | Bin 165 -> 0 bytes .../pytz/zoneinfo/Arctic/Longyearbyen | Bin 2228 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Aden | Bin 165 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Almaty | Bin 997 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Amman | Bin 1853 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Anadyr | Bin 1188 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Aqtau | Bin 983 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Aqtobe | Bin 1011 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Ashgabat | Bin 619 -> 0 bytes .../pytz/zoneinfo/Asia/Ashkhabad | Bin 619 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Atyrau | Bin 991 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Baghdad | Bin 983 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Bahrain | Bin 199 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Baku | Bin 1227 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Bangkok | Bin 199 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Barnaul | Bin 1221 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Beirut | Bin 2154 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Bishkek | Bin 983 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Brunei | Bin 203 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Calcutta | Bin 285 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Chita | Bin 1221 -> 0 bytes .../pytz/zoneinfo/Asia/Choibalsan | Bin 949 -> 0 bytes .../pytz/zoneinfo/Asia/Chongqing | Bin 561 -> 0 bytes .../pytz/zoneinfo/Asia/Chungking | Bin 561 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Colombo | Bin 372 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Dacca | Bin 337 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Damascus | Bin 2294 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Dhaka | Bin 337 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Dili | Bin 227 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Dubai | Bin 165 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Dushanbe | Bin 591 -> 0 bytes .../pytz/zoneinfo/Asia/Famagusta | Bin 2028 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Gaza | Bin 2422 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Harbin | Bin 561 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Hebron | Bin 2450 -> 0 bytes .../pytz/zoneinfo/Asia/Ho_Chi_Minh | Bin 351 -> 0 bytes .../pytz/zoneinfo/Asia/Hong_Kong | Bin 1203 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Hovd | Bin 891 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Irkutsk | Bin 1243 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Istanbul | Bin 1947 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Jakarta | Bin 355 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Jayapura | Bin 221 -> 0 bytes .../pytz/zoneinfo/Asia/Jerusalem | Bin 2388 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Kabul | Bin 208 -> 0 bytes .../pytz/zoneinfo/Asia/Kamchatka | Bin 1166 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Karachi | Bin 379 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Kashgar | Bin 165 -> 0 bytes .../pytz/zoneinfo/Asia/Kathmandu | Bin 212 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Katmandu | Bin 212 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Khandyga | Bin 1271 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Kolkata | Bin 285 -> 0 bytes .../pytz/zoneinfo/Asia/Krasnoyarsk | Bin 1207 -> 0 bytes .../pytz/zoneinfo/Asia/Kuala_Lumpur | Bin 383 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Kuching | Bin 483 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Kuwait | Bin 165 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Macao | Bin 1227 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Macau | Bin 1227 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Magadan | Bin 1222 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Makassar | Bin 254 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Manila | Bin 328 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Muscat | Bin 165 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Nicosia | Bin 2002 -> 0 bytes .../pytz/zoneinfo/Asia/Novokuznetsk | Bin 1165 -> 0 bytes .../pytz/zoneinfo/Asia/Novosibirsk | Bin 1221 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Omsk | Bin 1207 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Oral | Bin 1005 -> 0 bytes .../pytz/zoneinfo/Asia/Phnom_Penh | Bin 199 -> 0 bytes .../pytz/zoneinfo/Asia/Pontianak | Bin 353 -> 0 bytes .../pytz/zoneinfo/Asia/Pyongyang | Bin 237 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Qatar | Bin 199 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Qostanay | Bin 1011 -> 0 bytes .../pytz/zoneinfo/Asia/Qyzylorda | Bin 1025 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Rangoon | Bin 268 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Riyadh | Bin 165 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Saigon | Bin 351 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Sakhalin | Bin 1202 -> 0 bytes .../pytz/zoneinfo/Asia/Samarkand | Bin 577 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Seoul | Bin 617 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Shanghai | Bin 561 -> 0 bytes .../pytz/zoneinfo/Asia/Singapore | Bin 383 -> 0 bytes .../pytz/zoneinfo/Asia/Srednekolymsk | Bin 1208 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Taipei | Bin 761 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Tashkent | Bin 591 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Tbilisi | Bin 1035 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Tehran | Bin 2582 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Tel_Aviv | Bin 2388 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Thimbu | Bin 203 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Thimphu | Bin 203 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Tokyo | Bin 309 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Tomsk | Bin 1221 -> 0 bytes .../pytz/zoneinfo/Asia/Ujung_Pandang | Bin 254 -> 0 bytes .../pytz/zoneinfo/Asia/Ulaanbaatar | Bin 891 -> 0 bytes .../pytz/zoneinfo/Asia/Ulan_Bator | Bin 891 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Urumqi | Bin 165 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Ust-Nera | Bin 1252 -> 0 bytes .../pytz/zoneinfo/Asia/Vientiane | Bin 199 -> 0 bytes .../pytz/zoneinfo/Asia/Vladivostok | Bin 1208 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Yakutsk | Bin 1207 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Yangon | Bin 268 -> 0 bytes .../pytz/zoneinfo/Asia/Yekaterinburg | Bin 1243 -> 0 bytes .../site-packages/pytz/zoneinfo/Asia/Yerevan | Bin 1151 -> 0 bytes .../pytz/zoneinfo/Atlantic/Azores | Bin 3484 -> 0 bytes .../pytz/zoneinfo/Atlantic/Bermuda | Bin 2396 -> 0 bytes .../pytz/zoneinfo/Atlantic/Canary | Bin 1897 -> 0 bytes .../pytz/zoneinfo/Atlantic/Cape_Verde | Bin 270 -> 0 bytes .../pytz/zoneinfo/Atlantic/Faeroe | Bin 1815 -> 0 bytes .../pytz/zoneinfo/Atlantic/Faroe | Bin 1815 -> 0 bytes .../pytz/zoneinfo/Atlantic/Jan_Mayen | Bin 2228 -> 0 bytes .../pytz/zoneinfo/Atlantic/Madeira | Bin 3475 -> 0 bytes .../pytz/zoneinfo/Atlantic/Reykjavik | Bin 1162 -> 0 bytes .../pytz/zoneinfo/Atlantic/South_Georgia | Bin 164 -> 0 bytes .../pytz/zoneinfo/Atlantic/St_Helena | Bin 148 -> 0 bytes .../pytz/zoneinfo/Atlantic/Stanley | Bin 1214 -> 0 bytes .../site-packages/pytz/zoneinfo/Australia/ACT | Bin 2190 -> 0 bytes .../pytz/zoneinfo/Australia/Adelaide | Bin 2208 -> 0 bytes .../pytz/zoneinfo/Australia/Brisbane | Bin 419 -> 0 bytes .../pytz/zoneinfo/Australia/Broken_Hill | Bin 2229 -> 0 bytes .../pytz/zoneinfo/Australia/Canberra | Bin 2190 -> 0 bytes .../pytz/zoneinfo/Australia/Currie | Bin 2358 -> 0 bytes .../pytz/zoneinfo/Australia/Darwin | Bin 325 -> 0 bytes .../pytz/zoneinfo/Australia/Eucla | Bin 470 -> 0 bytes .../pytz/zoneinfo/Australia/Hobart | Bin 2358 -> 0 bytes .../site-packages/pytz/zoneinfo/Australia/LHI | Bin 1860 -> 0 bytes .../pytz/zoneinfo/Australia/Lindeman | Bin 475 -> 0 bytes .../pytz/zoneinfo/Australia/Lord_Howe | Bin 1860 -> 0 bytes .../pytz/zoneinfo/Australia/Melbourne | Bin 2190 -> 0 bytes .../site-packages/pytz/zoneinfo/Australia/NSW | Bin 2190 -> 0 bytes .../pytz/zoneinfo/Australia/North | Bin 325 -> 0 bytes .../pytz/zoneinfo/Australia/Perth | Bin 446 -> 0 bytes .../pytz/zoneinfo/Australia/Queensland | Bin 419 -> 0 bytes .../pytz/zoneinfo/Australia/South | Bin 2208 -> 0 bytes .../pytz/zoneinfo/Australia/Sydney | Bin 2190 -> 0 bytes .../pytz/zoneinfo/Australia/Tasmania | Bin 2358 -> 0 bytes .../pytz/zoneinfo/Australia/Victoria | Bin 2190 -> 0 bytes .../pytz/zoneinfo/Australia/West | Bin 446 -> 0 bytes .../pytz/zoneinfo/Australia/Yancowinna | Bin 2229 -> 0 bytes .../site-packages/pytz/zoneinfo/Brazil/Acre | Bin 628 -> 0 bytes .../pytz/zoneinfo/Brazil/DeNoronha | Bin 716 -> 0 bytes .../site-packages/pytz/zoneinfo/Brazil/East | Bin 1444 -> 0 bytes .../site-packages/pytz/zoneinfo/Brazil/West | Bin 604 -> 0 bytes .../python3.8/site-packages/pytz/zoneinfo/CET | Bin 2094 -> 0 bytes .../site-packages/pytz/zoneinfo/CST6CDT | Bin 2310 -> 0 bytes .../pytz/zoneinfo/Canada/Atlantic | Bin 3424 -> 0 bytes .../pytz/zoneinfo/Canada/Central | Bin 2868 -> 0 bytes .../pytz/zoneinfo/Canada/Eastern | Bin 3494 -> 0 bytes .../pytz/zoneinfo/Canada/Mountain | Bin 2332 -> 0 bytes .../pytz/zoneinfo/Canada/Newfoundland | Bin 3655 -> 0 bytes .../pytz/zoneinfo/Canada/Pacific | Bin 2892 -> 0 bytes .../pytz/zoneinfo/Canada/Saskatchewan | Bin 980 -> 0 bytes .../site-packages/pytz/zoneinfo/Canada/Yukon | Bin 1614 -> 0 bytes .../pytz/zoneinfo/Chile/Continental | Bin 2529 -> 0 bytes .../pytz/zoneinfo/Chile/EasterIsland | Bin 2233 -> 0 bytes .../site-packages/pytz/zoneinfo/Cuba | Bin 2416 -> 0 bytes .../python3.8/site-packages/pytz/zoneinfo/EET | Bin 1908 -> 0 bytes .../python3.8/site-packages/pytz/zoneinfo/EST | Bin 114 -> 0 bytes .../site-packages/pytz/zoneinfo/EST5EDT | Bin 2310 -> 0 bytes .../site-packages/pytz/zoneinfo/Egypt | Bin 1955 -> 0 bytes .../site-packages/pytz/zoneinfo/Eire | Bin 3492 -> 0 bytes .../site-packages/pytz/zoneinfo/Etc/GMT | Bin 114 -> 0 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+0 | Bin 114 -> 0 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+1 | Bin 116 -> 0 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+10 | Bin 117 -> 0 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+11 | Bin 117 -> 0 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+12 | Bin 117 -> 0 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+2 | Bin 116 -> 0 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+3 | Bin 116 -> 0 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+4 | Bin 116 -> 0 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+5 | Bin 116 -> 0 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+6 | Bin 116 -> 0 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+7 | Bin 116 -> 0 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+8 | Bin 116 -> 0 bytes .../site-packages/pytz/zoneinfo/Etc/GMT+9 | Bin 116 -> 0 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-0 | Bin 114 -> 0 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-1 | Bin 117 -> 0 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-10 | Bin 118 -> 0 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-11 | Bin 118 -> 0 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-12 | Bin 118 -> 0 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-13 | Bin 118 -> 0 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-14 | Bin 118 -> 0 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-2 | Bin 117 -> 0 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-3 | Bin 117 -> 0 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-4 | Bin 117 -> 0 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-5 | Bin 117 -> 0 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-6 | Bin 117 -> 0 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-7 | Bin 117 -> 0 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-8 | Bin 117 -> 0 bytes .../site-packages/pytz/zoneinfo/Etc/GMT-9 | Bin 117 -> 0 bytes .../site-packages/pytz/zoneinfo/Etc/GMT0 | Bin 114 -> 0 bytes .../site-packages/pytz/zoneinfo/Etc/Greenwich | Bin 114 -> 0 bytes .../site-packages/pytz/zoneinfo/Etc/UCT | Bin 114 -> 0 bytes .../site-packages/pytz/zoneinfo/Etc/UTC | Bin 114 -> 0 bytes .../site-packages/pytz/zoneinfo/Etc/Universal | Bin 114 -> 0 bytes .../site-packages/pytz/zoneinfo/Etc/Zulu | Bin 114 -> 0 bytes .../pytz/zoneinfo/Europe/Amsterdam | Bin 2910 -> 0 bytes .../pytz/zoneinfo/Europe/Andorra | Bin 1742 -> 0 bytes .../pytz/zoneinfo/Europe/Astrakhan | Bin 1165 -> 0 bytes .../site-packages/pytz/zoneinfo/Europe/Athens | Bin 2262 -> 0 bytes .../pytz/zoneinfo/Europe/Belfast | Bin 3648 -> 0 bytes .../pytz/zoneinfo/Europe/Belgrade | Bin 1920 -> 0 bytes .../site-packages/pytz/zoneinfo/Europe/Berlin | Bin 2298 -> 0 bytes .../pytz/zoneinfo/Europe/Bratislava | Bin 2301 -> 0 bytes .../pytz/zoneinfo/Europe/Brussels | Bin 2933 -> 0 bytes .../pytz/zoneinfo/Europe/Bucharest | Bin 2184 -> 0 bytes .../pytz/zoneinfo/Europe/Budapest | Bin 2368 -> 0 bytes .../pytz/zoneinfo/Europe/Busingen | Bin 1909 -> 0 bytes .../pytz/zoneinfo/Europe/Chisinau | Bin 2390 -> 0 bytes .../pytz/zoneinfo/Europe/Copenhagen | Bin 2137 -> 0 bytes .../site-packages/pytz/zoneinfo/Europe/Dublin | Bin 3492 -> 0 bytes .../pytz/zoneinfo/Europe/Gibraltar | Bin 3052 -> 0 bytes .../pytz/zoneinfo/Europe/Guernsey | Bin 3648 -> 0 bytes .../pytz/zoneinfo/Europe/Helsinki | Bin 1900 -> 0 bytes .../pytz/zoneinfo/Europe/Isle_of_Man | Bin 3648 -> 0 bytes .../pytz/zoneinfo/Europe/Istanbul | Bin 1947 -> 0 bytes .../site-packages/pytz/zoneinfo/Europe/Jersey | Bin 3648 -> 0 bytes .../pytz/zoneinfo/Europe/Kaliningrad | Bin 1493 -> 0 bytes .../site-packages/pytz/zoneinfo/Europe/Kiev | Bin 2088 -> 0 bytes .../site-packages/pytz/zoneinfo/Europe/Kirov | Bin 1153 -> 0 bytes .../site-packages/pytz/zoneinfo/Europe/Lisbon | Bin 3469 -> 0 bytes .../pytz/zoneinfo/Europe/Ljubljana | Bin 1920 -> 0 bytes .../site-packages/pytz/zoneinfo/Europe/London | Bin 3648 -> 0 bytes .../pytz/zoneinfo/Europe/Luxembourg | Bin 2946 -> 0 bytes .../site-packages/pytz/zoneinfo/Europe/Madrid | Bin 2614 -> 0 bytes .../site-packages/pytz/zoneinfo/Europe/Malta | Bin 2620 -> 0 bytes .../pytz/zoneinfo/Europe/Mariehamn | Bin 1900 -> 0 bytes .../site-packages/pytz/zoneinfo/Europe/Minsk | Bin 1321 -> 0 bytes .../site-packages/pytz/zoneinfo/Europe/Monaco | Bin 2944 -> 0 bytes .../site-packages/pytz/zoneinfo/Europe/Moscow | Bin 1535 -> 0 bytes .../pytz/zoneinfo/Europe/Nicosia | Bin 2002 -> 0 bytes .../site-packages/pytz/zoneinfo/Europe/Oslo | Bin 2228 -> 0 bytes .../site-packages/pytz/zoneinfo/Europe/Paris | Bin 2962 -> 0 bytes .../pytz/zoneinfo/Europe/Podgorica | Bin 1920 -> 0 bytes .../site-packages/pytz/zoneinfo/Europe/Prague | Bin 2301 -> 0 bytes .../site-packages/pytz/zoneinfo/Europe/Riga | Bin 2198 -> 0 bytes .../site-packages/pytz/zoneinfo/Europe/Rome | Bin 2641 -> 0 bytes .../site-packages/pytz/zoneinfo/Europe/Samara | Bin 1215 -> 0 bytes .../pytz/zoneinfo/Europe/San_Marino | Bin 2641 -> 0 bytes .../pytz/zoneinfo/Europe/Sarajevo | Bin 1920 -> 0 bytes .../pytz/zoneinfo/Europe/Saratov | Bin 1183 -> 0 bytes .../pytz/zoneinfo/Europe/Simferopol | Bin 1453 -> 0 bytes .../site-packages/pytz/zoneinfo/Europe/Skopje | Bin 1920 -> 0 bytes .../site-packages/pytz/zoneinfo/Europe/Sofia | Bin 2077 -> 0 bytes .../pytz/zoneinfo/Europe/Stockholm | Bin 1909 -> 0 bytes .../pytz/zoneinfo/Europe/Tallinn | Bin 2148 -> 0 bytes .../site-packages/pytz/zoneinfo/Europe/Tirane | Bin 2084 -> 0 bytes .../pytz/zoneinfo/Europe/Tiraspol | Bin 2390 -> 0 bytes .../pytz/zoneinfo/Europe/Ulyanovsk | Bin 1267 -> 0 bytes .../pytz/zoneinfo/Europe/Uzhgorod | Bin 2050 -> 0 bytes .../site-packages/pytz/zoneinfo/Europe/Vaduz | Bin 1909 -> 0 bytes .../pytz/zoneinfo/Europe/Vatican | Bin 2641 -> 0 bytes .../site-packages/pytz/zoneinfo/Europe/Vienna | Bin 2200 -> 0 bytes .../pytz/zoneinfo/Europe/Vilnius | Bin 2162 -> 0 bytes .../pytz/zoneinfo/Europe/Volgograd | Bin 1165 -> 0 bytes .../site-packages/pytz/zoneinfo/Europe/Warsaw | Bin 2654 -> 0 bytes .../site-packages/pytz/zoneinfo/Europe/Zagreb | Bin 1920 -> 0 bytes .../pytz/zoneinfo/Europe/Zaporozhye | Bin 2106 -> 0 bytes .../site-packages/pytz/zoneinfo/Europe/Zurich | Bin 1909 -> 0 bytes .../site-packages/pytz/zoneinfo/Factory | Bin 116 -> 0 bytes .../python3.8/site-packages/pytz/zoneinfo/GB | Bin 3648 -> 0 bytes .../site-packages/pytz/zoneinfo/GB-Eire | Bin 3648 -> 0 bytes .../python3.8/site-packages/pytz/zoneinfo/GMT | Bin 114 -> 0 bytes .../site-packages/pytz/zoneinfo/GMT+0 | Bin 114 -> 0 bytes .../site-packages/pytz/zoneinfo/GMT-0 | Bin 114 -> 0 bytes .../site-packages/pytz/zoneinfo/GMT0 | Bin 114 -> 0 bytes .../site-packages/pytz/zoneinfo/Greenwich | Bin 114 -> 0 bytes .../python3.8/site-packages/pytz/zoneinfo/HST | Bin 115 -> 0 bytes .../site-packages/pytz/zoneinfo/Hongkong | Bin 1203 -> 0 bytes .../site-packages/pytz/zoneinfo/Iceland | Bin 1162 -> 0 bytes .../pytz/zoneinfo/Indian/Antananarivo | Bin 265 -> 0 bytes .../site-packages/pytz/zoneinfo/Indian/Chagos | Bin 199 -> 0 bytes .../pytz/zoneinfo/Indian/Christmas | Bin 165 -> 0 bytes .../site-packages/pytz/zoneinfo/Indian/Cocos | Bin 174 -> 0 bytes .../site-packages/pytz/zoneinfo/Indian/Comoro | Bin 265 -> 0 bytes .../pytz/zoneinfo/Indian/Kerguelen | Bin 165 -> 0 bytes .../site-packages/pytz/zoneinfo/Indian/Mahe | Bin 165 -> 0 bytes .../pytz/zoneinfo/Indian/Maldives | Bin 199 -> 0 bytes .../pytz/zoneinfo/Indian/Mauritius | Bin 241 -> 0 bytes .../pytz/zoneinfo/Indian/Mayotte | Bin 265 -> 0 bytes .../pytz/zoneinfo/Indian/Reunion | Bin 165 -> 0 bytes .../site-packages/pytz/zoneinfo/Iran | Bin 2582 -> 0 bytes .../site-packages/pytz/zoneinfo/Israel | Bin 2388 -> 0 bytes .../site-packages/pytz/zoneinfo/Jamaica | Bin 482 -> 0 bytes .../site-packages/pytz/zoneinfo/Japan | Bin 309 -> 0 bytes .../site-packages/pytz/zoneinfo/Kwajalein | Bin 316 -> 0 bytes .../site-packages/pytz/zoneinfo/Libya | Bin 625 -> 0 bytes .../python3.8/site-packages/pytz/zoneinfo/MET | Bin 2094 -> 0 bytes .../python3.8/site-packages/pytz/zoneinfo/MST | Bin 114 -> 0 bytes .../site-packages/pytz/zoneinfo/MST7MDT | Bin 2310 -> 0 bytes .../pytz/zoneinfo/Mexico/BajaNorte | Bin 2342 -> 0 bytes .../pytz/zoneinfo/Mexico/BajaSur | Bin 1526 -> 0 bytes .../pytz/zoneinfo/Mexico/General | Bin 1584 -> 0 bytes .../python3.8/site-packages/pytz/zoneinfo/NZ | Bin 2437 -> 0 bytes .../site-packages/pytz/zoneinfo/NZ-CHAT | Bin 2068 -> 0 bytes .../site-packages/pytz/zoneinfo/Navajo | Bin 2444 -> 0 bytes .../python3.8/site-packages/pytz/zoneinfo/PRC | Bin 561 -> 0 bytes .../site-packages/pytz/zoneinfo/PST8PDT | Bin 2310 -> 0 bytes .../site-packages/pytz/zoneinfo/Pacific/Apia | Bin 1097 -> 0 bytes .../pytz/zoneinfo/Pacific/Auckland | Bin 2437 -> 0 bytes .../pytz/zoneinfo/Pacific/Bougainville | Bin 268 -> 0 bytes .../pytz/zoneinfo/Pacific/Chatham | Bin 2068 -> 0 bytes .../site-packages/pytz/zoneinfo/Pacific/Chuuk | Bin 269 -> 0 bytes .../pytz/zoneinfo/Pacific/Easter | Bin 2233 -> 0 bytes .../site-packages/pytz/zoneinfo/Pacific/Efate | Bin 538 -> 0 bytes .../pytz/zoneinfo/Pacific/Enderbury | Bin 234 -> 0 bytes .../pytz/zoneinfo/Pacific/Fakaofo | Bin 200 -> 0 bytes .../site-packages/pytz/zoneinfo/Pacific/Fiji | Bin 1077 -> 0 bytes .../pytz/zoneinfo/Pacific/Funafuti | Bin 166 -> 0 bytes .../pytz/zoneinfo/Pacific/Galapagos | Bin 238 -> 0 bytes .../pytz/zoneinfo/Pacific/Gambier | Bin 164 -> 0 bytes .../pytz/zoneinfo/Pacific/Guadalcanal | Bin 166 -> 0 bytes .../site-packages/pytz/zoneinfo/Pacific/Guam | Bin 494 -> 0 bytes .../pytz/zoneinfo/Pacific/Honolulu | Bin 329 -> 0 bytes .../pytz/zoneinfo/Pacific/Johnston | Bin 329 -> 0 bytes .../pytz/zoneinfo/Pacific/Kiritimati | Bin 238 -> 0 bytes .../pytz/zoneinfo/Pacific/Kosrae | Bin 351 -> 0 bytes .../pytz/zoneinfo/Pacific/Kwajalein | Bin 316 -> 0 bytes .../pytz/zoneinfo/Pacific/Majuro | Bin 310 -> 0 bytes .../pytz/zoneinfo/Pacific/Marquesas | Bin 173 -> 0 bytes .../pytz/zoneinfo/Pacific/Midway | Bin 175 -> 0 bytes .../site-packages/pytz/zoneinfo/Pacific/Nauru | Bin 252 -> 0 bytes .../site-packages/pytz/zoneinfo/Pacific/Niue | Bin 241 -> 0 bytes .../pytz/zoneinfo/Pacific/Norfolk | Bin 880 -> 0 bytes .../pytz/zoneinfo/Pacific/Noumea | Bin 304 -> 0 bytes .../pytz/zoneinfo/Pacific/Pago_Pago | Bin 175 -> 0 bytes .../site-packages/pytz/zoneinfo/Pacific/Palau | Bin 180 -> 0 bytes .../pytz/zoneinfo/Pacific/Pitcairn | Bin 202 -> 0 bytes .../pytz/zoneinfo/Pacific/Pohnpei | Bin 303 -> 0 bytes .../pytz/zoneinfo/Pacific/Ponape | Bin 303 -> 0 bytes .../pytz/zoneinfo/Pacific/Port_Moresby | Bin 186 -> 0 bytes .../pytz/zoneinfo/Pacific/Rarotonga | Bin 577 -> 0 bytes .../pytz/zoneinfo/Pacific/Saipan | Bin 494 -> 0 bytes .../site-packages/pytz/zoneinfo/Pacific/Samoa | Bin 175 -> 0 bytes .../pytz/zoneinfo/Pacific/Tahiti | Bin 165 -> 0 bytes .../pytz/zoneinfo/Pacific/Tarawa | Bin 166 -> 0 bytes .../pytz/zoneinfo/Pacific/Tongatapu | Bin 372 -> 0 bytes .../site-packages/pytz/zoneinfo/Pacific/Truk | Bin 269 -> 0 bytes .../site-packages/pytz/zoneinfo/Pacific/Wake | Bin 166 -> 0 bytes .../pytz/zoneinfo/Pacific/Wallis | Bin 166 -> 0 bytes .../site-packages/pytz/zoneinfo/Pacific/Yap | Bin 269 -> 0 bytes .../site-packages/pytz/zoneinfo/Poland | Bin 2654 -> 0 bytes .../site-packages/pytz/zoneinfo/Portugal | Bin 3469 -> 0 bytes .../python3.8/site-packages/pytz/zoneinfo/ROC | Bin 761 -> 0 bytes .../python3.8/site-packages/pytz/zoneinfo/ROK | Bin 617 -> 0 bytes .../site-packages/pytz/zoneinfo/Singapore | Bin 383 -> 0 bytes .../site-packages/pytz/zoneinfo/Turkey | Bin 1947 -> 0 bytes .../python3.8/site-packages/pytz/zoneinfo/UCT | Bin 114 -> 0 bytes .../site-packages/pytz/zoneinfo/US/Alaska | Bin 2371 -> 0 bytes .../site-packages/pytz/zoneinfo/US/Aleutian | Bin 2356 -> 0 bytes .../site-packages/pytz/zoneinfo/US/Arizona | Bin 328 -> 0 bytes .../site-packages/pytz/zoneinfo/US/Central | Bin 3576 -> 0 bytes .../pytz/zoneinfo/US/East-Indiana | Bin 1666 -> 0 bytes .../site-packages/pytz/zoneinfo/US/Eastern | Bin 3536 -> 0 bytes .../site-packages/pytz/zoneinfo/US/Hawaii | Bin 329 -> 0 bytes .../pytz/zoneinfo/US/Indiana-Starke | Bin 2428 -> 0 bytes .../site-packages/pytz/zoneinfo/US/Michigan | Bin 2230 -> 0 bytes .../site-packages/pytz/zoneinfo/US/Mountain | Bin 2444 -> 0 bytes .../site-packages/pytz/zoneinfo/US/Pacific | Bin 2836 -> 0 bytes .../site-packages/pytz/zoneinfo/US/Samoa | Bin 175 -> 0 bytes .../python3.8/site-packages/pytz/zoneinfo/UTC | Bin 114 -> 0 bytes .../site-packages/pytz/zoneinfo/Universal | Bin 114 -> 0 bytes .../site-packages/pytz/zoneinfo/W-SU | Bin 1535 -> 0 bytes .../python3.8/site-packages/pytz/zoneinfo/WET | Bin 1905 -> 0 bytes .../site-packages/pytz/zoneinfo/Zulu | Bin 114 -> 0 bytes .../site-packages/pytz/zoneinfo/iso3166.tab | 274 - .../site-packages/pytz/zoneinfo/leapseconds | 82 - .../site-packages/pytz/zoneinfo/tzdata.zi | 4459 --------- .../site-packages/pytz/zoneinfo/zone.tab | 451 - .../site-packages/pytz/zoneinfo/zone1970.tab | 383 - .../requests-2.25.1.dist-info/INSTALLER | 1 - .../requests-2.25.1.dist-info/LICENSE | 175 - .../requests-2.25.1.dist-info/METADATA | 103 - .../requests-2.25.1.dist-info/RECORD | 42 - .../requests-2.25.1.dist-info/WHEEL | 6 - .../requests-2.25.1.dist-info/top_level.txt | 1 - .../site-packages/requests/__init__.py | 137 - .../site-packages/requests/__version__.py | 14 - .../site-packages/requests/_internal_utils.py | 42 - .../site-packages/requests/adapters.py | 533 -- .../python3.8/site-packages/requests/api.py | 161 - .../python3.8/site-packages/requests/auth.py | 305 - .../python3.8/site-packages/requests/certs.py | 18 - .../site-packages/requests/compat.py | 72 - .../site-packages/requests/cookies.py | 549 -- .../site-packages/requests/exceptions.py | 123 - .../python3.8/site-packages/requests/help.py | 119 - .../python3.8/site-packages/requests/hooks.py | 34 - .../site-packages/requests/models.py | 956 -- .../site-packages/requests/packages.py | 14 - .../site-packages/requests/sessions.py | 781 -- .../site-packages/requests/status_codes.py | 123 - .../site-packages/requests/structures.py | 105 - .../python3.8/site-packages/requests/utils.py | 992 -- .../setuptools-44.0.0.dist-info/AUTHORS.txt | 566 -- .../setuptools-44.0.0.dist-info/INSTALLER | 1 - .../setuptools-44.0.0.dist-info/LICENSE.txt | 20 - .../setuptools-44.0.0.dist-info/METADATA | 82 - .../setuptools-44.0.0.dist-info/RECORD | 163 - .../setuptools-44.0.0.dist-info/WHEEL | 6 - .../dependency_links.txt | 2 - .../entry_points.txt | 68 - .../setuptools-44.0.0.dist-info/top_level.txt | 3 - .../setuptools-44.0.0.dist-info/zip-safe | 1 - .../site-packages/setuptools/__init__.py | 228 - .../setuptools/_deprecation_warning.py | 7 - .../site-packages/setuptools/_imp.py | 73 - .../setuptools/_vendor/__init__.py | 0 .../setuptools/_vendor/ordered_set.py | 488 - .../setuptools/_vendor/packaging/__about__.py | 27 - .../setuptools/_vendor/packaging/__init__.py | 26 - .../setuptools/_vendor/packaging/_compat.py | 31 - .../_vendor/packaging/_structures.py | 68 - .../setuptools/_vendor/packaging/markers.py | 296 - .../_vendor/packaging/requirements.py | 138 - .../_vendor/packaging/specifiers.py | 749 -- .../setuptools/_vendor/packaging/tags.py | 404 - .../setuptools/_vendor/packaging/utils.py | 57 - .../setuptools/_vendor/packaging/version.py | 420 - .../setuptools/_vendor/pyparsing.py | 5742 ----------- .../site-packages/setuptools/_vendor/six.py | 868 -- .../site-packages/setuptools/archive_util.py | 173 - .../site-packages/setuptools/build_meta.py | 257 - .../site-packages/setuptools/cli-32.exe | Bin 65536 -> 0 bytes .../site-packages/setuptools/cli-64.exe | Bin 74752 -> 0 bytes .../site-packages/setuptools/cli.exe | Bin 65536 -> 0 bytes .../setuptools/command/__init__.py | 17 - .../site-packages/setuptools/command/alias.py | 80 - .../setuptools/command/bdist_egg.py | 502 - .../setuptools/command/bdist_rpm.py | 43 - .../setuptools/command/bdist_wininst.py | 21 - .../setuptools/command/build_clib.py | 98 - .../setuptools/command/build_ext.py | 327 - .../setuptools/command/build_py.py | 270 - .../setuptools/command/develop.py | 221 - .../setuptools/command/dist_info.py | 36 - .../setuptools/command/easy_install.py | 2402 ----- .../setuptools/command/egg_info.py | 717 -- .../setuptools/command/install.py | 125 - .../setuptools/command/install_egg_info.py | 82 - .../setuptools/command/install_lib.py | 147 - .../setuptools/command/install_scripts.py | 65 - .../setuptools/command/launcher manifest.xml | 15 - .../setuptools/command/py36compat.py | 136 - .../setuptools/command/register.py | 18 - .../setuptools/command/rotate.py | 66 - .../setuptools/command/saveopts.py | 22 - .../site-packages/setuptools/command/sdist.py | 252 - .../setuptools/command/setopt.py | 149 - .../site-packages/setuptools/command/test.py | 279 - .../setuptools/command/upload.py | 17 - .../setuptools/command/upload_docs.py | 206 - .../site-packages/setuptools/config.py | 659 -- .../site-packages/setuptools/dep_util.py | 23 - .../site-packages/setuptools/depends.py | 176 - .../site-packages/setuptools/dist.py | 1274 --- .../site-packages/setuptools/errors.py | 16 - .../site-packages/setuptools/extension.py | 57 - .../setuptools/extern/__init__.py | 73 - .../site-packages/setuptools/glob.py | 174 - .../site-packages/setuptools/gui-32.exe | Bin 65536 -> 0 bytes .../site-packages/setuptools/gui-64.exe | Bin 75264 -> 0 bytes .../site-packages/setuptools/gui.exe | Bin 65536 -> 0 bytes .../site-packages/setuptools/installer.py | 150 - .../site-packages/setuptools/launch.py | 35 - .../site-packages/setuptools/lib2to3_ex.py | 62 - .../site-packages/setuptools/monkey.py | 179 - .../site-packages/setuptools/msvc.py | 1679 ---- .../site-packages/setuptools/namespaces.py | 107 - .../site-packages/setuptools/package_index.py | 1136 --- .../site-packages/setuptools/py27compat.py | 60 - .../site-packages/setuptools/py31compat.py | 32 - .../site-packages/setuptools/py33compat.py | 59 - .../site-packages/setuptools/py34compat.py | 13 - .../site-packages/setuptools/sandbox.py | 491 - .../setuptools/script (dev).tmpl | 6 - .../site-packages/setuptools/script.tmpl | 3 - .../site-packages/setuptools/site-patch.py | 74 - .../site-packages/setuptools/ssl_support.py | 260 - .../site-packages/setuptools/unicode_utils.py | 44 - .../site-packages/setuptools/version.py | 6 - .../site-packages/setuptools/wheel.py | 220 - .../setuptools/windows_support.py | 29 - .../six-1.16.0.dist-info/INSTALLER | 1 - .../six-1.16.0.dist-info/LICENSE | 18 - .../six-1.16.0.dist-info/METADATA | 49 - .../site-packages/six-1.16.0.dist-info/RECORD | 8 - .../site-packages/six-1.16.0.dist-info/WHEEL | 6 - .../six-1.16.0.dist-info/top_level.txt | 1 - venv/lib/python3.8/site-packages/six.py | 998 -- .../site-packages/telegram/__init__.py | 294 - .../site-packages/telegram/__main__.py | 54 - .../python3.8/site-packages/telegram/base.py | 152 - .../python3.8/site-packages/telegram/bot.py | 5318 ----------- .../site-packages/telegram/botcommand.py | 50 - .../site-packages/telegram/callbackquery.py | 658 -- .../python3.8/site-packages/telegram/chat.py | 1559 --- .../site-packages/telegram/chataction.py | 70 - .../site-packages/telegram/chatinvitelink.py | 114 - .../site-packages/telegram/chatlocation.py | 73 - .../site-packages/telegram/chatmember.py | 253 - .../telegram/chatmemberupdated.py | 173 - .../site-packages/telegram/chatpermissions.py | 124 - .../telegram/choseninlineresult.py | 98 - .../site-packages/telegram/constants.py | 345 - .../python3.8/site-packages/telegram/dice.py | 92 - .../python3.8/site-packages/telegram/error.py | 151 - .../site-packages/telegram/ext/__init__.py | 104 - .../telegram/ext/basepersistence.py | 538 -- .../telegram/ext/callbackcontext.py | 361 - .../telegram/ext/callbackdatacache.py | 427 - .../telegram/ext/callbackqueryhandler.py | 236 - .../telegram/ext/chatmemberhandler.py | 145 - .../telegram/ext/choseninlineresulthandler.py | 160 - .../telegram/ext/commandhandler.py | 456 - .../telegram/ext/contexttypes.py | 194 - .../telegram/ext/conversationhandler.py | 725 -- .../site-packages/telegram/ext/defaults.py | 267 - .../telegram/ext/dictpersistence.py | 404 - .../site-packages/telegram/ext/dispatcher.py | 820 -- .../site-packages/telegram/ext/extbot.py | 326 - .../site-packages/telegram/ext/filters.py | 2313 ----- .../site-packages/telegram/ext/handler.py | 260 - .../telegram/ext/inlinequeryhandler.py | 221 - .../site-packages/telegram/ext/jobqueue.py | 656 -- .../telegram/ext/messagehandler.py | 208 - .../telegram/ext/messagequeue.py | 334 - .../telegram/ext/picklepersistence.py | 463 - .../telegram/ext/pollanswerhandler.py | 98 - .../site-packages/telegram/ext/pollhandler.py | 98 - .../telegram/ext/precheckoutqueryhandler.py | 98 - .../telegram/ext/regexhandler.py | 166 - .../telegram/ext/shippingqueryhandler.py | 97 - .../telegram/ext/stringcommandhandler.py | 149 - .../telegram/ext/stringregexhandler.py | 166 - .../site-packages/telegram/ext/typehandler.py | 108 - .../site-packages/telegram/ext/updater.py | 890 -- .../telegram/ext/utils/__init__.py | 17 - .../telegram/ext/utils/promise.py | 158 - .../site-packages/telegram/ext/utils/types.py | 62 - .../telegram/ext/utils/webhookhandler.py | 177 - .../site-packages/telegram/files/__init__.py | 0 .../site-packages/telegram/files/animation.py | 137 - .../site-packages/telegram/files/audio.py | 141 - .../site-packages/telegram/files/chatphoto.py | 132 - .../site-packages/telegram/files/contact.py | 68 - .../site-packages/telegram/files/document.py | 125 - .../site-packages/telegram/files/file.py | 213 - .../site-packages/telegram/files/inputfile.py | 119 - .../telegram/files/inputmedia.py | 525 -- .../site-packages/telegram/files/location.py | 91 - .../site-packages/telegram/files/photosize.py | 98 - .../site-packages/telegram/files/sticker.py | 288 - .../site-packages/telegram/files/venue.py | 107 - .../site-packages/telegram/files/video.py | 138 - .../site-packages/telegram/files/videonote.py | 124 - .../site-packages/telegram/files/voice.py | 106 - .../site-packages/telegram/forcereply.py | 61 - .../site-packages/telegram/games/__init__.py | 0 .../telegram/games/callbackgame.py | 27 - .../site-packages/telegram/games/game.py | 186 - .../telegram/games/gamehighscore.py | 67 - .../site-packages/telegram/inline/__init__.py | 0 .../telegram/inline/inlinekeyboardbutton.py | 162 - .../telegram/inline/inlinekeyboardmarkup.py | 138 - .../telegram/inline/inlinequery.py | 168 - .../telegram/inline/inlinequeryresult.py | 71 - .../inline/inlinequeryresultarticle.py | 105 - .../telegram/inline/inlinequeryresultaudio.py | 116 - .../inline/inlinequeryresultcachedaudio.py | 100 - .../inline/inlinequeryresultcacheddocument.py | 113 - .../inline/inlinequeryresultcachedgif.py | 108 - .../inline/inlinequeryresultcachedmpeg4gif.py | 108 - .../inline/inlinequeryresultcachedphoto.py | 114 - .../inline/inlinequeryresultcachedsticker.py | 71 - .../inline/inlinequeryresultcachedvideo.py | 113 - .../inline/inlinequeryresultcachedvoice.py | 105 - .../inline/inlinequeryresultcontact.py | 107 - .../inline/inlinequeryresultdocument.py | 135 - .../telegram/inline/inlinequeryresultgame.py | 62 - .../telegram/inline/inlinequeryresultgif.py | 137 - .../inline/inlinequeryresultlocation.py | 131 - .../inline/inlinequeryresultmpeg4gif.py | 136 - .../telegram/inline/inlinequeryresultphoto.py | 129 - .../telegram/inline/inlinequeryresultvenue.py | 133 - .../telegram/inline/inlinequeryresultvideo.py | 146 - .../telegram/inline/inlinequeryresultvoice.py | 112 - .../inline/inputcontactmessagecontent.py | 66 - .../inline/inputinvoicemessagecontent.py | 242 - .../inline/inputlocationmessagecontent.py | 88 - .../telegram/inline/inputmessagecontent.py | 34 - .../inline/inputtextmessagecontent.py | 88 - .../inline/inputvenuemessagecontent.py | 102 - .../site-packages/telegram/keyboardbutton.py | 83 - .../telegram/keyboardbuttonpolltype.py | 45 - .../site-packages/telegram/loginurl.py | 89 - .../site-packages/telegram/message.py | 2888 ------ .../telegram/messageautodeletetimerchanged.py | 56 - .../site-packages/telegram/messageentity.py | 129 - .../site-packages/telegram/messageid.py | 40 - .../site-packages/telegram/parsemode.py | 45 - .../telegram/passport/__init__.py | 0 .../telegram/passport/credentials.py | 497 - .../site-packages/telegram/passport/data.py | 153 - .../passport/encryptedpassportelement.py | 266 - .../telegram/passport/passportdata.py | 121 - .../passport/passportelementerrors.py | 382 - .../telegram/passport/passportfile.py | 160 - .../telegram/payment/__init__.py | 0 .../site-packages/telegram/payment/invoice.py | 86 - .../telegram/payment/labeledprice.py | 54 - .../telegram/payment/orderinfo.py | 79 - .../telegram/payment/precheckoutquery.py | 140 - .../telegram/payment/shippingaddress.py | 86 - .../telegram/payment/shippingoption.py | 70 - .../telegram/payment/shippingquery.py | 113 - .../telegram/payment/successfulpayment.py | 107 - .../python3.8/site-packages/telegram/poll.py | 295 - .../telegram/proximityalerttriggered.py | 69 - .../python3.8/site-packages/telegram/py.typed | 0 .../telegram/replykeyboardmarkup.py | 251 - .../telegram/replykeyboardremove.py | 64 - .../site-packages/telegram/replymarkup.py | 33 - .../site-packages/telegram/update.py | 388 - .../python3.8/site-packages/telegram/user.py | 1142 --- .../telegram/userprofilephotos.py | 79 - .../site-packages/telegram/utils/__init__.py | 0 .../site-packages/telegram/utils/deprecate.py | 45 - .../site-packages/telegram/utils/helpers.py | 596 -- .../site-packages/telegram/utils/promise.py | 38 - .../site-packages/telegram/utils/request.py | 395 - .../site-packages/telegram/utils/types.py | 57 - .../telegram/utils/webhookhandler.py | 35 - .../site-packages/telegram/vendor/__init__.py | 0 .../telegram/vendor/ptb_urllib3/__init__.py | 0 .../vendor/ptb_urllib3/urllib3/__init__.py | 96 - .../ptb_urllib3/urllib3/_collections.py | 327 - .../vendor/ptb_urllib3/urllib3/connection.py | 369 - .../ptb_urllib3/urllib3/connectionpool.py | 912 -- .../ptb_urllib3/urllib3/contrib/__init__.py | 0 .../ptb_urllib3/urllib3/contrib/appengine.py | 296 - .../ptb_urllib3/urllib3/contrib/ntlmpool.py | 112 - .../ptb_urllib3/urllib3/contrib/pyopenssl.py | 450 - .../ptb_urllib3/urllib3/contrib/socks.py | 192 - .../vendor/ptb_urllib3/urllib3/exceptions.py | 246 - .../vendor/ptb_urllib3/urllib3/fields.py | 178 - .../vendor/ptb_urllib3/urllib3/filepost.py | 94 - .../ptb_urllib3/urllib3/packages/__init__.py | 5 - .../urllib3/packages/backports/__init__.py | 0 .../urllib3/packages/backports/makefile.py | 53 - .../urllib3/packages/ordered_dict.py | 259 - .../ptb_urllib3/urllib3/packages/six.py | 868 -- .../packages/ssl_match_hostname/__init__.py | 19 - .../ssl_match_hostname/_implementation.py | 157 - .../vendor/ptb_urllib3/urllib3/poolmanager.py | 363 - .../vendor/ptb_urllib3/urllib3/request.py | 148 - .../vendor/ptb_urllib3/urllib3/response.py | 618 -- .../ptb_urllib3/urllib3/util/__init__.py | 52 - .../ptb_urllib3/urllib3/util/connection.py | 130 - .../ptb_urllib3/urllib3/util/request.py | 118 - .../ptb_urllib3/urllib3/util/response.py | 81 - .../vendor/ptb_urllib3/urllib3/util/retry.py | 389 - .../ptb_urllib3/urllib3/util/selectors.py | 529 -- .../vendor/ptb_urllib3/urllib3/util/ssl_.py | 336 - .../ptb_urllib3/urllib3/util/timeout.py | 242 - .../vendor/ptb_urllib3/urllib3/util/url.py | 226 - .../vendor/ptb_urllib3/urllib3/util/wait.py | 40 - .../site-packages/telegram/version.py | 24 - .../site-packages/telegram/voicechat.py | 169 - .../site-packages/telegram/webhookinfo.py | 110 - .../tornado-6.1.dist-info/INSTALLER | 1 - .../tornado-6.1.dist-info/LICENSE | 202 - .../tornado-6.1.dist-info/METADATA | 70 - .../tornado-6.1.dist-info/RECORD | 165 - .../site-packages/tornado-6.1.dist-info/WHEEL | 5 - .../tornado-6.1.dist-info/top_level.txt | 1 - .../site-packages/tornado/__init__.py | 26 - .../site-packages/tornado/_locale_data.py | 80 - .../python3.8/site-packages/tornado/auth.py | 1187 --- .../site-packages/tornado/autoreload.py | 363 - .../site-packages/tornado/concurrent.py | 263 - .../site-packages/tornado/curl_httpclient.py | 583 -- .../python3.8/site-packages/tornado/escape.py | 402 - .../python3.8/site-packages/tornado/gen.py | 872 -- .../site-packages/tornado/http1connection.py | 842 -- .../site-packages/tornado/httpclient.py | 790 -- .../site-packages/tornado/httpserver.py | 398 - .../site-packages/tornado/httputil.py | 1133 --- .../python3.8/site-packages/tornado/ioloop.py | 944 -- .../site-packages/tornado/iostream.py | 1660 ---- .../python3.8/site-packages/tornado/locale.py | 581 -- .../python3.8/site-packages/tornado/locks.py | 571 -- .../python3.8/site-packages/tornado/log.py | 339 - .../site-packages/tornado/netutil.py | 617 -- .../site-packages/tornado/options.py | 735 -- .../tornado/platform/__init__.py | 0 .../site-packages/tornado/platform/asyncio.py | 611 -- .../tornado/platform/caresresolver.py | 89 - .../site-packages/tornado/platform/twisted.py | 146 - .../site-packages/tornado/process.py | 373 - .../python3.8/site-packages/tornado/py.typed | 0 .../python3.8/site-packages/tornado/queues.py | 414 - .../site-packages/tornado/routing.py | 717 -- .../tornado/simple_httpclient.py | 699 -- .../speedups.cpython-38-x86_64-linux-gnu.so | Bin 29256 -> 0 bytes .../site-packages/tornado/tcpclient.py | 328 - .../site-packages/tornado/tcpserver.py | 334 - .../site-packages/tornado/template.py | 1048 --- .../site-packages/tornado/test/__main__.py | 12 - .../tornado/test/asyncio_test.py | 190 - .../site-packages/tornado/test/auth_test.py | 609 -- .../tornado/test/autoreload_test.py | 127 - .../tornado/test/concurrent_test.py | 212 - .../tornado/test/csv_translations/fr_FR.csv | 1 - .../tornado/test/curl_httpclient_test.py | 129 - .../site-packages/tornado/test/escape_test.py | 322 - .../site-packages/tornado/test/gen_test.py | 1119 --- .../fr_FR/LC_MESSAGES/tornado_test.mo | Bin 665 -> 0 bytes .../fr_FR/LC_MESSAGES/tornado_test.po | 47 - .../tornado/test/http1connection_test.py | 61 - .../tornado/test/httpclient_test.py | 898 -- .../tornado/test/httpserver_test.py | 1339 --- .../tornado/test/httputil_test.py | 521 - .../site-packages/tornado/test/import_test.py | 66 - .../site-packages/tornado/test/ioloop_test.py | 725 -- .../tornado/test/iostream_test.py | 1282 --- .../site-packages/tornado/test/locale_test.py | 151 - .../site-packages/tornado/test/locks_test.py | 535 -- .../site-packages/tornado/test/log_test.py | 245 - .../tornado/test/netutil_test.py | 233 - .../tornado/test/options_test.cfg | 7 - .../tornado/test/options_test.py | 328 - .../tornado/test/options_test_types.cfg | 11 - .../tornado/test/options_test_types_str.cfg | 8 - .../tornado/test/process_test.py | 274 - .../site-packages/tornado/test/queues_test.py | 431 - .../tornado/test/resolve_test_helper.py | 10 - .../tornado/test/routing_test.py | 276 - .../site-packages/tornado/test/runtests.py | 241 - .../tornado/test/simple_httpclient_test.py | 834 -- .../tornado/test/static/dir/index.html | 1 - .../tornado/test/static/robots.txt | 2 - .../tornado/test/static/sample.xml | 23 - .../tornado/test/static/sample.xml.bz2 | Bin 285 -> 0 bytes .../tornado/test/static/sample.xml.gz | Bin 264 -> 0 bytes .../site-packages/tornado/test/static_foo.txt | 2 - .../tornado/test/tcpclient_test.py | 438 - .../tornado/test/tcpserver_test.py | 192 - .../tornado/test/template_test.py | 536 -- .../tornado/test/templates/utf8.html | 1 - .../site-packages/tornado/test/test.crt | 20 - .../site-packages/tornado/test/test.key | 28 - .../tornado/test/testing_test.py | 353 - .../tornado/test/twisted_test.py | 247 - .../site-packages/tornado/test/util.py | 114 - .../site-packages/tornado/test/util_test.py | 308 - .../site-packages/tornado/test/web_test.py | 3156 ------- .../tornado/test/websocket_test.py | 840 -- .../site-packages/tornado/test/wsgi_test.py | 20 - .../site-packages/tornado/testing.py | 818 -- .../python3.8/site-packages/tornado/util.py | 474 - .../python3.8/site-packages/tornado/web.py | 3588 ------- .../site-packages/tornado/websocket.py | 1666 ---- .../python3.8/site-packages/tornado/wsgi.py | 199 - .../tzlocal-2.1.dist-info/INSTALLER | 1 - .../tzlocal-2.1.dist-info/LICENSE.txt | 19 - .../tzlocal-2.1.dist-info/METADATA | 326 - .../tzlocal-2.1.dist-info/RECORD | 17 - .../site-packages/tzlocal-2.1.dist-info/WHEEL | 6 - .../tzlocal-2.1.dist-info/top_level.txt | 1 - .../tzlocal-2.1.dist-info/zip-safe | 1 - .../site-packages/tzlocal/__init__.py | 5 - .../python3.8/site-packages/tzlocal/unix.py | 174 - .../python3.8/site-packages/tzlocal/utils.py | 46 - .../python3.8/site-packages/tzlocal/win32.py | 104 - .../site-packages/tzlocal/windows_tz.py | 697 -- .../urllib3-1.26.6.dist-info/INSTALLER | 1 - .../urllib3-1.26.6.dist-info/LICENSE.txt | 21 - .../urllib3-1.26.6.dist-info/METADATA | 1388 --- .../urllib3-1.26.6.dist-info/RECORD | 84 - .../urllib3-1.26.6.dist-info/WHEEL | 6 - .../urllib3-1.26.6.dist-info/top_level.txt | 1 - .../site-packages/urllib3/__init__.py | 85 - .../site-packages/urllib3/_collections.py | 337 - .../site-packages/urllib3/_version.py | 2 - .../site-packages/urllib3/connection.py | 539 -- .../site-packages/urllib3/connectionpool.py | 1067 --- .../site-packages/urllib3/contrib/__init__.py | 0 .../urllib3/contrib/_appengine_environ.py | 36 - .../contrib/_securetransport/__init__.py | 0 .../contrib/_securetransport/bindings.py | 519 - .../contrib/_securetransport/low_level.py | 396 - .../urllib3/contrib/appengine.py | 314 - .../site-packages/urllib3/contrib/ntlmpool.py | 130 - .../urllib3/contrib/pyopenssl.py | 511 - .../urllib3/contrib/securetransport.py | 922 -- .../site-packages/urllib3/contrib/socks.py | 216 - .../site-packages/urllib3/exceptions.py | 323 - .../python3.8/site-packages/urllib3/fields.py | 274 - .../site-packages/urllib3/filepost.py | 98 - .../urllib3/packages/__init__.py | 5 - .../urllib3/packages/backports/__init__.py | 0 .../urllib3/packages/backports/makefile.py | 51 - .../site-packages/urllib3/packages/six.py | 1077 --- .../packages/ssl_match_hostname/__init__.py | 24 - .../ssl_match_hostname/_implementation.py | 160 - .../site-packages/urllib3/poolmanager.py | 536 -- .../site-packages/urllib3/request.py | 170 - .../site-packages/urllib3/response.py | 821 -- .../site-packages/urllib3/util/__init__.py | 49 - .../site-packages/urllib3/util/connection.py | 150 - .../site-packages/urllib3/util/proxy.py | 56 - .../site-packages/urllib3/util/queue.py | 22 - .../site-packages/urllib3/util/request.py | 143 - .../site-packages/urllib3/util/response.py | 107 - .../site-packages/urllib3/util/retry.py | 602 -- .../site-packages/urllib3/util/ssl_.py | 495 - .../urllib3/util/ssltransport.py | 221 - .../site-packages/urllib3/util/timeout.py | 268 - .../site-packages/urllib3/util/url.py | 432 - .../site-packages/urllib3/util/wait.py | 153 - venv/lib64 | 1 - venv/pyvenv.cfg | 3 - .../CacheControl-0.12.6-py2.py3-none-any.whl | Bin 23290 -> 0 bytes .../appdirs-1.4.4-py2.py3-none-any.whl | Bin 14131 -> 0 bytes .../certifi-2020.4.5.1-py2.py3-none-any.whl | Bin 161630 -> 0 bytes .../chardet-3.0.4-py2.py3-none-any.whl | Bin 136755 -> 0 bytes .../colorama-0.4.3-py2.py3-none-any.whl | Bin 20362 -> 0 bytes .../contextlib2-0.6.0-py2.py3-none-any.whl | Bin 12457 -> 0 bytes .../distlib-0.3.0-py2.py3-none-any.whl | Bin 147296 -> 0 bytes .../distro-1.5.0-py2.py3-none-any.whl | Bin 19272 -> 0 bytes .../html5lib-1.0.1-py2.py3-none-any.whl | Bin 115285 -> 0 bytes .../idna-2.9-py2.py3-none-any.whl | Bin 62768 -> 0 bytes .../ipaddr-2.2.0-py2.py3-none-any.whl | Bin 19552 -> 0 bytes .../lockfile-0.12.2-py2.py3-none-any.whl | Bin 17238 -> 0 bytes .../msgpack-0.6.2-py2.py3-none-any.whl | Bin 88193 -> 0 bytes .../packaging-20.3-py2.py3-none-any.whl | Bin 37509 -> 0 bytes .../pep517-0.8.2-py2.py3-none-any.whl | Bin 21951 -> 0 bytes .../pip-20.1.1-py2.py3-none-any.whl | Bin 285469 -> 0 bytes .../pkg_resources-0.0.0-py2.py3-none-any.whl | Bin 122578 -> 0 bytes .../progress-1.5-py2.py3-none-any.whl | Bin 12812 -> 0 bytes .../pyparsing-2.4.7-py2.py3-none-any.whl | Bin 72474 -> 0 bytes .../requests-2.23.0-py2.py3-none-any.whl | Bin 63192 -> 0 bytes .../resolvelib-0.3.0-py2.py3-none-any.whl | Bin 15663 -> 0 bytes .../retrying-1.3.3-py2.py3-none-any.whl | Bin 11621 -> 0 bytes .../setuptools-44.0.0-py2.py3-none-any.whl | Bin 472710 -> 0 bytes .../six-1.15.0-py2.py3-none-any.whl | Bin 15549 -> 0 bytes .../toml-0.10.1-py2.py3-none-any.whl | Bin 20955 -> 0 bytes .../urllib3-1.25.9-py2.py3-none-any.whl | Bin 123228 -> 0 bytes .../webencodings-0.5.1-py2.py3-none-any.whl | Bin 15749 -> 0 bytes .../wheel-0.34.2-py2.py3-none-any.whl | Bin 30875 -> 0 bytes 1415 files changed, 174 insertions(+), 242640 deletions(-) create mode 100644 Pipfile create mode 100644 Pipfile.lock delete mode 100644 src/bottoken.py delete mode 100644 venv/bin/Activate.ps1 delete mode 100644 venv/bin/activate delete mode 100644 venv/bin/activate.csh delete mode 100644 venv/bin/activate.fish delete mode 100755 venv/bin/chardetect delete mode 100755 venv/bin/easy_install delete mode 100755 venv/bin/easy_install-3.8 delete mode 100755 venv/bin/pip delete mode 100755 venv/bin/pip3 delete mode 100755 venv/bin/pip3.8 delete mode 120000 venv/bin/python delete mode 120000 venv/bin/python3 delete mode 100644 venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/INSTALLER delete mode 100644 venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/LICENSE.txt delete mode 100644 venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/METADATA delete mode 100644 venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/RECORD delete mode 100644 venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/WHEEL delete mode 100644 venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/entry_points.txt delete mode 100644 venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/top_level.txt delete mode 100644 venv/lib/python3.8/site-packages/apscheduler/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/apscheduler/events.py delete mode 100644 venv/lib/python3.8/site-packages/apscheduler/executors/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/apscheduler/executors/asyncio.py delete mode 100644 venv/lib/python3.8/site-packages/apscheduler/executors/base.py delete mode 100644 venv/lib/python3.8/site-packages/apscheduler/executors/base_py3.py delete mode 100644 venv/lib/python3.8/site-packages/apscheduler/executors/debug.py delete mode 100644 venv/lib/python3.8/site-packages/apscheduler/executors/gevent.py delete mode 100644 venv/lib/python3.8/site-packages/apscheduler/executors/pool.py delete mode 100644 venv/lib/python3.8/site-packages/apscheduler/executors/tornado.py delete mode 100644 venv/lib/python3.8/site-packages/apscheduler/executors/twisted.py delete mode 100644 venv/lib/python3.8/site-packages/apscheduler/job.py delete mode 100644 venv/lib/python3.8/site-packages/apscheduler/jobstores/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/apscheduler/jobstores/base.py delete mode 100644 venv/lib/python3.8/site-packages/apscheduler/jobstores/memory.py delete mode 100644 venv/lib/python3.8/site-packages/apscheduler/jobstores/mongodb.py delete mode 100644 venv/lib/python3.8/site-packages/apscheduler/jobstores/redis.py delete mode 100644 venv/lib/python3.8/site-packages/apscheduler/jobstores/rethinkdb.py delete mode 100644 venv/lib/python3.8/site-packages/apscheduler/jobstores/sqlalchemy.py delete mode 100644 venv/lib/python3.8/site-packages/apscheduler/jobstores/zookeeper.py delete mode 100644 venv/lib/python3.8/site-packages/apscheduler/schedulers/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/apscheduler/schedulers/asyncio.py delete mode 100644 venv/lib/python3.8/site-packages/apscheduler/schedulers/background.py delete mode 100644 venv/lib/python3.8/site-packages/apscheduler/schedulers/base.py delete mode 100644 venv/lib/python3.8/site-packages/apscheduler/schedulers/blocking.py delete mode 100644 venv/lib/python3.8/site-packages/apscheduler/schedulers/gevent.py delete mode 100644 venv/lib/python3.8/site-packages/apscheduler/schedulers/qt.py delete mode 100644 venv/lib/python3.8/site-packages/apscheduler/schedulers/tornado.py delete mode 100644 venv/lib/python3.8/site-packages/apscheduler/schedulers/twisted.py delete mode 100644 venv/lib/python3.8/site-packages/apscheduler/triggers/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/apscheduler/triggers/base.py delete mode 100644 venv/lib/python3.8/site-packages/apscheduler/triggers/combining.py delete mode 100644 venv/lib/python3.8/site-packages/apscheduler/triggers/cron/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/apscheduler/triggers/cron/expressions.py delete mode 100644 venv/lib/python3.8/site-packages/apscheduler/triggers/cron/fields.py delete mode 100644 venv/lib/python3.8/site-packages/apscheduler/triggers/date.py delete mode 100644 venv/lib/python3.8/site-packages/apscheduler/triggers/interval.py delete mode 100644 venv/lib/python3.8/site-packages/apscheduler/util.py delete mode 100644 venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/INSTALLER delete mode 100644 venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/LICENSE delete mode 100644 venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/METADATA delete mode 100644 venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/RECORD delete mode 100644 venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/WHEEL delete mode 100644 venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/top_level.txt delete mode 100644 venv/lib/python3.8/site-packages/cachetools/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/cachetools/cache.py delete mode 100644 venv/lib/python3.8/site-packages/cachetools/decorators.py delete mode 100644 venv/lib/python3.8/site-packages/cachetools/fifo.py delete mode 100644 venv/lib/python3.8/site-packages/cachetools/func.py delete mode 100644 venv/lib/python3.8/site-packages/cachetools/keys.py delete mode 100644 venv/lib/python3.8/site-packages/cachetools/lfu.py delete mode 100644 venv/lib/python3.8/site-packages/cachetools/lru.py delete mode 100644 venv/lib/python3.8/site-packages/cachetools/mru.py delete mode 100644 venv/lib/python3.8/site-packages/cachetools/rr.py delete mode 100644 venv/lib/python3.8/site-packages/cachetools/ttl.py delete mode 100644 venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/INSTALLER delete mode 100644 venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/LICENSE delete mode 100644 venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/METADATA delete mode 100644 venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/RECORD delete mode 100644 venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/WHEEL delete mode 100644 venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/top_level.txt delete mode 100644 venv/lib/python3.8/site-packages/certifi/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/certifi/__main__.py delete mode 100644 venv/lib/python3.8/site-packages/certifi/cacert.pem delete mode 100644 venv/lib/python3.8/site-packages/certifi/core.py delete mode 100644 venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/INSTALLER delete mode 100644 venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/LICENSE delete mode 100644 venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/METADATA delete mode 100644 venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/RECORD delete mode 100644 venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/WHEEL delete mode 100644 venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/entry_points.txt delete mode 100644 venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/top_level.txt delete mode 100644 venv/lib/python3.8/site-packages/chardet/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/big5freq.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/big5prober.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/chardistribution.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/charsetgroupprober.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/charsetprober.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/cli/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/cli/chardetect.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/codingstatemachine.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/compat.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/cp949prober.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/enums.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/escprober.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/escsm.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/eucjpprober.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/euckrfreq.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/euckrprober.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/euctwfreq.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/euctwprober.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/gb2312freq.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/gb2312prober.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/hebrewprober.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/jisfreq.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/jpcntx.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/langbulgarianmodel.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/langgreekmodel.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/langhebrewmodel.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/langhungarianmodel.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/langrussianmodel.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/langthaimodel.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/langturkishmodel.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/latin1prober.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/mbcharsetprober.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/mbcsgroupprober.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/mbcssm.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/metadata/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/metadata/languages.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/sbcharsetprober.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/sbcsgroupprober.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/sjisprober.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/universaldetector.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/utf8prober.py delete mode 100644 venv/lib/python3.8/site-packages/chardet/version.py delete mode 100644 venv/lib/python3.8/site-packages/easy_install.py delete mode 100644 venv/lib/python3.8/site-packages/idna-2.10.dist-info/INSTALLER delete mode 100644 venv/lib/python3.8/site-packages/idna-2.10.dist-info/LICENSE.rst delete mode 100644 venv/lib/python3.8/site-packages/idna-2.10.dist-info/METADATA delete mode 100644 venv/lib/python3.8/site-packages/idna-2.10.dist-info/RECORD delete mode 100644 venv/lib/python3.8/site-packages/idna-2.10.dist-info/WHEEL delete mode 100644 venv/lib/python3.8/site-packages/idna-2.10.dist-info/top_level.txt delete mode 100644 venv/lib/python3.8/site-packages/idna/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/idna/codec.py delete mode 100644 venv/lib/python3.8/site-packages/idna/compat.py delete mode 100644 venv/lib/python3.8/site-packages/idna/core.py delete mode 100644 venv/lib/python3.8/site-packages/idna/idnadata.py delete mode 100644 venv/lib/python3.8/site-packages/idna/intranges.py delete mode 100644 venv/lib/python3.8/site-packages/idna/package_data.py delete mode 100644 venv/lib/python3.8/site-packages/idna/uts46data.py delete mode 100644 venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/INSTALLER delete mode 100644 venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/LICENSE.txt delete mode 100644 venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/METADATA delete mode 100644 venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/RECORD delete mode 100644 venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/WHEEL delete mode 100644 venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/entry_points.txt delete mode 100644 venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/top_level.txt delete mode 100644 venv/lib/python3.8/site-packages/pip/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/pip/__main__.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/build_env.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/cache.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/cli/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/cli/autocompletion.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/cli/base_command.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/cli/cmdoptions.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/cli/command_context.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/cli/main.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/cli/main_parser.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/cli/parser.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/cli/progress_bars.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/cli/req_command.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/cli/spinners.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/cli/status_codes.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/commands/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/commands/cache.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/commands/check.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/commands/completion.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/commands/configuration.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/commands/debug.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/commands/download.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/commands/freeze.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/commands/hash.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/commands/help.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/commands/install.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/commands/list.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/commands/search.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/commands/show.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/commands/uninstall.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/commands/wheel.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/configuration.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/distributions/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/distributions/base.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/distributions/installed.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/distributions/sdist.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/distributions/wheel.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/exceptions.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/index/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/index/collector.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/index/package_finder.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/locations.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/main.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/models/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/models/candidate.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/models/direct_url.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/models/format_control.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/models/index.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/models/link.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/models/scheme.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/models/search_scope.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/models/selection_prefs.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/models/target_python.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/models/wheel.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/network/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/network/auth.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/network/cache.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/network/download.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/network/session.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/network/utils.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/network/xmlrpc.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/operations/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/operations/build/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/operations/build/metadata.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/operations/build/metadata_legacy.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/operations/build/wheel.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/operations/build/wheel_legacy.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/operations/check.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/operations/freeze.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/operations/install/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/operations/install/editable_legacy.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/operations/install/legacy.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/operations/install/wheel.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/operations/prepare.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/pyproject.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/req/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/req/constructors.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/req/req_file.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/req/req_install.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/req/req_set.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/req/req_tracker.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/req/req_uninstall.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/resolution/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/resolution/base.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/resolution/legacy/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/resolution/legacy/resolver.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/base.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/candidates.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/factory.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/provider.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/requirements.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/resolver.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/self_outdated_check.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/appdirs.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/compat.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/compatibility_tags.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/deprecation.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/direct_url_helpers.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/distutils_args.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/encoding.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/entrypoints.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/filesystem.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/filetypes.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/glibc.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/hashes.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/inject_securetransport.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/logging.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/misc.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/models.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/packaging.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/pkg_resources.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/setuptools_build.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/subprocess.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/temp_dir.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/typing.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/unpacking.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/urls.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/virtualenv.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/utils/wheel.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/vcs/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/vcs/bazaar.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/vcs/git.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/vcs/mercurial.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/vcs/subversion.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/vcs/versioncontrol.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_internal/wheel_builder.py delete mode 100644 venv/lib/python3.8/site-packages/pip/_vendor/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/AUTHORS.txt delete mode 100644 venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/INSTALLER delete mode 100644 venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/LICENSE.txt delete mode 100644 venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/METADATA delete mode 100644 venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/RECORD delete mode 100644 venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/WHEEL delete mode 100644 venv/lib/python3.8/site-packages/pkg_resources/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/pkg_resources/_vendor/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/pkg_resources/_vendor/appdirs.py delete mode 100644 venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__about__.py delete mode 100644 venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/_compat.py delete mode 100644 venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/_structures.py delete mode 100644 venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/markers.py delete mode 100644 venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/requirements.py delete mode 100644 venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/specifiers.py delete mode 100644 venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/utils.py delete mode 100644 venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/version.py delete mode 100644 venv/lib/python3.8/site-packages/pkg_resources/_vendor/pyparsing.py delete mode 100644 venv/lib/python3.8/site-packages/pkg_resources/_vendor/six.py delete mode 100644 venv/lib/python3.8/site-packages/pkg_resources/extern/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/pkg_resources/py31compat.py delete mode 100644 venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/INSTALLER delete mode 100644 venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/LICENSE.dual delete mode 100644 venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/METADATA delete mode 100644 venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/RECORD delete mode 100644 venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/WHEEL delete mode 100644 venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/top_level.txt delete mode 100644 venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/DESCRIPTION.rst delete mode 100644 venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/INSTALLER delete mode 100644 venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/LICENSE.txt delete mode 100644 venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/METADATA delete mode 100644 venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/RECORD delete mode 100644 venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/WHEEL delete mode 100644 venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/metadata.json delete mode 100644 venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/top_level.txt delete mode 100644 venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/zip-safe delete mode 100644 venv/lib/python3.8/site-packages/pytz/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/pytz/exceptions.py delete mode 100644 venv/lib/python3.8/site-packages/pytz/lazy.py delete mode 100644 venv/lib/python3.8/site-packages/pytz/reference.py delete mode 100644 venv/lib/python3.8/site-packages/pytz/tzfile.py delete mode 100644 venv/lib/python3.8/site-packages/pytz/tzinfo.py delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Abidjan delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Accra delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Addis_Ababa delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Algiers delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Asmara delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Asmera delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Bamako delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Bangui delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Banjul delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Bissau delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Blantyre delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Brazzaville delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Bujumbura delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Cairo delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Casablanca delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Ceuta delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Conakry delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Dakar delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Dar_es_Salaam delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Djibouti delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Douala delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/El_Aaiun delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Freetown delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Gaborone delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Harare delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Johannesburg delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Juba delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Kampala delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Khartoum delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Kigali delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Kinshasa delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Lagos delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Libreville delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Lome delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Luanda delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Lubumbashi delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Lusaka delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Malabo delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Maputo delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Maseru delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Mbabane delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Mogadishu delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Monrovia delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Nairobi delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Ndjamena delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Niamey delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Nouakchott delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Ouagadougou delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Porto-Novo delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Sao_Tome delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Timbuktu delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Tripoli delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Tunis delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Windhoek delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Adak delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Anchorage delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Anguilla delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Antigua delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Araguaina delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Buenos_Aires delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Catamarca delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/ComodRivadavia delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Cordoba delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Jujuy delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/La_Rioja delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Mendoza delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Rio_Gallegos delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Salta delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/San_Juan delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/San_Luis delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Tucuman delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Ushuaia delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Aruba delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Asuncion delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Atikokan delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Atka delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Bahia delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Bahia_Banderas delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Barbados delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Belem delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Belize delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Blanc-Sablon delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Boa_Vista delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Bogota delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Boise delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Buenos_Aires delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Cambridge_Bay delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Campo_Grande delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Cancun delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Caracas delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Catamarca delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Cayenne delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Cayman delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Chicago delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Chihuahua delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Coral_Harbour delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Cordoba delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Costa_Rica delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Creston delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Cuiaba delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Curacao delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Danmarkshavn delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Dawson delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Dawson_Creek delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Denver delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Detroit delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Dominica delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Edmonton delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Eirunepe delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/El_Salvador delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Ensenada delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Fort_Nelson delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Fort_Wayne delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Fortaleza delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Glace_Bay delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Godthab delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Goose_Bay delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Grand_Turk delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Grenada delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Guadeloupe delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Guatemala delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Guayaquil delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Guyana delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Halifax delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Havana delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Hermosillo delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Indianapolis delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Knox delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Marengo delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Petersburg delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Tell_City delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Vevay delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Vincennes delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Winamac delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indianapolis delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Inuvik delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Iqaluit delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Jamaica delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Jujuy delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Juneau delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Kentucky/Louisville delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Kentucky/Monticello delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Knox_IN delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Kralendijk delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/La_Paz delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Lima delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Los_Angeles delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Louisville delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Lower_Princes delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Maceio delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Managua delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Manaus delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Marigot delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Martinique delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Matamoros delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Mazatlan delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Mendoza delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Menominee delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Merida delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Metlakatla delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Mexico_City delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Miquelon delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Moncton delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Monterrey delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Montevideo delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Montreal delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Montserrat delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Nassau delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/New_York delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Nipigon delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Nome delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Noronha delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/North_Dakota/Beulah delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/North_Dakota/Center delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/North_Dakota/New_Salem delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Nuuk delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Ojinaga delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Panama delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Pangnirtung delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Paramaribo delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Phoenix delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Port-au-Prince delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Port_of_Spain delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Porto_Acre delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Porto_Velho delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Puerto_Rico delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Punta_Arenas delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Rainy_River delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Rankin_Inlet delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Recife delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Regina delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Resolute delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Rio_Branco delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Rosario delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Santa_Isabel delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Santarem delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Santiago delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Santo_Domingo delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Sao_Paulo delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Scoresbysund delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Shiprock delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Sitka delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Barthelemy delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Johns delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Kitts delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Lucia delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Thomas delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Vincent delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Swift_Current delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Tegucigalpa delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Thule delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Thunder_Bay delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Tijuana delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Toronto delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Tortola delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Vancouver delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Virgin delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Whitehorse delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Winnipeg delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Yakutat delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Yellowknife delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Casey delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Davis delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/DumontDUrville delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Macquarie delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Mawson delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/McMurdo delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Palmer delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Rothera delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/South_Pole delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Syowa delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Troll delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Vostok delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Arctic/Longyearbyen delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Aden delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Almaty delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Amman delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Anadyr delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Aqtau delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Aqtobe delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ashgabat delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ashkhabad delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Atyrau delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Baghdad delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Bahrain delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Baku delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Bangkok delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Barnaul delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Beirut delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Bishkek delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Brunei delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Calcutta delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Chita delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Choibalsan delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Chongqing delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Chungking delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Colombo delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Dacca delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Damascus delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Dhaka delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Dili delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Dubai delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Dushanbe delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Famagusta delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Gaza delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Harbin delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Hebron delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ho_Chi_Minh delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Hong_Kong delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Hovd delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Irkutsk delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Istanbul delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Jakarta delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Jayapura delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Jerusalem delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kabul delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kamchatka delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Karachi delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kashgar delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kathmandu delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Katmandu delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Khandyga delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kolkata delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Krasnoyarsk delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kuala_Lumpur delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kuching delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kuwait delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Macao delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Macau delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Magadan delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Makassar delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Manila delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Muscat delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Nicosia delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Novokuznetsk delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Novosibirsk delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Omsk delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Oral delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Phnom_Penh delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Pontianak delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Pyongyang delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Qatar delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Qostanay delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Qyzylorda delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Rangoon delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Riyadh delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Saigon delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Sakhalin delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Samarkand delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Seoul delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Shanghai delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Singapore delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Srednekolymsk delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Taipei delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Tashkent delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Tbilisi delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Tehran delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Tel_Aviv delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Thimbu delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Thimphu delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Tokyo delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Tomsk delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ujung_Pandang delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ulaanbaatar delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ulan_Bator delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Urumqi delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ust-Nera delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Vientiane delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Vladivostok delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Yakutsk delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Yangon delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Yekaterinburg delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Yerevan delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Azores delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Bermuda delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Canary delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Cape_Verde delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Faeroe delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Faroe delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Jan_Mayen delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Madeira delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Reykjavik delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/South_Georgia delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/St_Helena delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Stanley delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/ACT delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Adelaide delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Brisbane delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Broken_Hill delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Canberra delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Currie delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Darwin delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Eucla delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Hobart delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/LHI delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Lindeman delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Lord_Howe delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Melbourne delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/NSW delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/North delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Perth delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Queensland delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/South delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Sydney delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Tasmania delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Victoria delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/West delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Yancowinna delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Brazil/Acre delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Brazil/DeNoronha delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Brazil/East delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Brazil/West delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/CET delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/CST6CDT delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Atlantic delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Central delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Eastern delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Mountain delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Newfoundland delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Pacific delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Saskatchewan delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Yukon delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Chile/Continental delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Chile/EasterIsland delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Cuba delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/EET delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/EST delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/EST5EDT delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Egypt delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Eire delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+0 delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+1 delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+10 delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+11 delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+12 delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+2 delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+3 delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+4 delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+5 delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+6 delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+7 delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+8 delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+9 delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-0 delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-1 delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-10 delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-11 delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-12 delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-13 delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-14 delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-2 delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-3 delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-4 delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-5 delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-6 delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-7 delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-8 delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-9 delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT0 delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/Greenwich delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/UCT delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/UTC delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/Universal delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/Zulu delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Amsterdam delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Andorra delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Astrakhan delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Athens delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Belfast delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Belgrade delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Berlin delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Bratislava delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Brussels delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Bucharest delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Budapest delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Busingen delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Chisinau delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Copenhagen delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Dublin delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Gibraltar delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Guernsey delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Helsinki delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Isle_of_Man delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Istanbul delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Jersey delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Kaliningrad delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Kiev delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Kirov delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Lisbon delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Ljubljana delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/London delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Luxembourg delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Madrid delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Malta delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Mariehamn delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Minsk delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Monaco delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Moscow delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Nicosia delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Oslo delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Paris delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Podgorica delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Prague delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Riga delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Rome delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Samara delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/San_Marino delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Sarajevo delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Saratov delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Simferopol delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Skopje delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Sofia delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Stockholm delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Tallinn delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Tirane delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Tiraspol delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Ulyanovsk delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Uzhgorod delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Vaduz delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Vatican delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Vienna delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Vilnius delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Volgograd delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Warsaw delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Zagreb delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Zaporozhye delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Zurich delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Factory delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/GB delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/GB-Eire delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/GMT delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/GMT+0 delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/GMT-0 delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/GMT0 delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Greenwich delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/HST delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Hongkong delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Iceland delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Antananarivo delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Chagos delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Christmas delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Cocos delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Comoro delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Kerguelen delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Mahe delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Maldives delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Mauritius delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Mayotte delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Reunion delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Iran delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Israel delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Jamaica delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Japan delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Kwajalein delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Libya delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/MET delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/MST delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/MST7MDT delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Mexico/BajaNorte delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Mexico/BajaSur delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Mexico/General delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/NZ delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/NZ-CHAT delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Navajo delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/PRC delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/PST8PDT delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Apia delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Auckland delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Bougainville delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Chatham delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Chuuk delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Easter delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Efate delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Enderbury delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Fakaofo delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Fiji delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Funafuti delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Galapagos delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Gambier delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Guadalcanal delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Guam delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Honolulu delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Johnston delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Kiritimati delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Kosrae delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Kwajalein delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Majuro delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Marquesas delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Midway delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Nauru delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Niue delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Norfolk delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Noumea delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Pago_Pago delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Palau delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Pitcairn delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Pohnpei delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Ponape delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Port_Moresby delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Rarotonga delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Saipan delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Samoa delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Tahiti delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Tarawa delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Tongatapu delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Truk delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Wake delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Wallis delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Yap delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Poland delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Portugal delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/ROC delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/ROK delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Singapore delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Turkey delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/UCT delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Alaska delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Aleutian delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Arizona delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Central delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/US/East-Indiana delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Eastern delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Hawaii delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Indiana-Starke delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Michigan delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Mountain delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Pacific delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Samoa delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/UTC delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Universal delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/W-SU delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/WET delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/Zulu delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/iso3166.tab delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/leapseconds delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/tzdata.zi delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/zone.tab delete mode 100644 venv/lib/python3.8/site-packages/pytz/zoneinfo/zone1970.tab delete mode 100644 venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/INSTALLER delete mode 100644 venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/LICENSE delete mode 100644 venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/METADATA delete mode 100644 venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/RECORD delete mode 100644 venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/WHEEL delete mode 100644 venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/top_level.txt delete mode 100644 venv/lib/python3.8/site-packages/requests/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/requests/__version__.py delete mode 100644 venv/lib/python3.8/site-packages/requests/_internal_utils.py delete mode 100644 venv/lib/python3.8/site-packages/requests/adapters.py delete mode 100644 venv/lib/python3.8/site-packages/requests/api.py delete mode 100644 venv/lib/python3.8/site-packages/requests/auth.py delete mode 100644 venv/lib/python3.8/site-packages/requests/certs.py delete mode 100644 venv/lib/python3.8/site-packages/requests/compat.py delete mode 100644 venv/lib/python3.8/site-packages/requests/cookies.py delete mode 100644 venv/lib/python3.8/site-packages/requests/exceptions.py delete mode 100644 venv/lib/python3.8/site-packages/requests/help.py delete mode 100644 venv/lib/python3.8/site-packages/requests/hooks.py delete mode 100644 venv/lib/python3.8/site-packages/requests/models.py delete mode 100644 venv/lib/python3.8/site-packages/requests/packages.py delete mode 100644 venv/lib/python3.8/site-packages/requests/sessions.py delete mode 100644 venv/lib/python3.8/site-packages/requests/status_codes.py delete mode 100644 venv/lib/python3.8/site-packages/requests/structures.py delete mode 100644 venv/lib/python3.8/site-packages/requests/utils.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/AUTHORS.txt delete mode 100644 venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/INSTALLER delete mode 100644 venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/LICENSE.txt delete mode 100644 venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/METADATA delete mode 100644 venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/RECORD delete mode 100644 venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/WHEEL delete mode 100644 venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/dependency_links.txt delete mode 100644 venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/entry_points.txt delete mode 100644 venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/top_level.txt delete mode 100644 venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/zip-safe delete mode 100644 venv/lib/python3.8/site-packages/setuptools/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/_deprecation_warning.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/_imp.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/_vendor/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/_vendor/ordered_set.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__about__.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/_compat.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/_structures.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/markers.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/requirements.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/specifiers.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/tags.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/utils.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/version.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/_vendor/pyparsing.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/_vendor/six.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/archive_util.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/build_meta.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/cli-32.exe delete mode 100644 venv/lib/python3.8/site-packages/setuptools/cli-64.exe delete mode 100644 venv/lib/python3.8/site-packages/setuptools/cli.exe delete mode 100644 venv/lib/python3.8/site-packages/setuptools/command/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/command/alias.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/command/bdist_egg.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/command/bdist_rpm.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/command/bdist_wininst.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/command/build_clib.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/command/build_ext.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/command/build_py.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/command/develop.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/command/dist_info.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/command/easy_install.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/command/egg_info.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/command/install.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/command/install_egg_info.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/command/install_lib.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/command/install_scripts.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/command/launcher manifest.xml delete mode 100644 venv/lib/python3.8/site-packages/setuptools/command/py36compat.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/command/register.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/command/rotate.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/command/saveopts.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/command/sdist.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/command/setopt.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/command/test.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/command/upload.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/command/upload_docs.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/config.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/dep_util.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/depends.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/dist.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/errors.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/extension.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/extern/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/glob.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/gui-32.exe delete mode 100644 venv/lib/python3.8/site-packages/setuptools/gui-64.exe delete mode 100644 venv/lib/python3.8/site-packages/setuptools/gui.exe delete mode 100644 venv/lib/python3.8/site-packages/setuptools/installer.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/launch.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/lib2to3_ex.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/monkey.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/msvc.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/namespaces.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/package_index.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/py27compat.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/py31compat.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/py33compat.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/py34compat.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/sandbox.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/script (dev).tmpl delete mode 100644 venv/lib/python3.8/site-packages/setuptools/script.tmpl delete mode 100644 venv/lib/python3.8/site-packages/setuptools/site-patch.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/ssl_support.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/unicode_utils.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/version.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/wheel.py delete mode 100644 venv/lib/python3.8/site-packages/setuptools/windows_support.py delete mode 100644 venv/lib/python3.8/site-packages/six-1.16.0.dist-info/INSTALLER delete mode 100644 venv/lib/python3.8/site-packages/six-1.16.0.dist-info/LICENSE delete mode 100644 venv/lib/python3.8/site-packages/six-1.16.0.dist-info/METADATA delete mode 100644 venv/lib/python3.8/site-packages/six-1.16.0.dist-info/RECORD delete mode 100644 venv/lib/python3.8/site-packages/six-1.16.0.dist-info/WHEEL delete mode 100644 venv/lib/python3.8/site-packages/six-1.16.0.dist-info/top_level.txt delete mode 100644 venv/lib/python3.8/site-packages/six.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/__main__.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/base.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/bot.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/botcommand.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/callbackquery.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/chat.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/chataction.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/chatinvitelink.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/chatlocation.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/chatmember.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/chatmemberupdated.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/chatpermissions.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/choseninlineresult.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/constants.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/dice.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/error.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/ext/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/ext/basepersistence.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/ext/callbackcontext.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/ext/callbackdatacache.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/ext/callbackqueryhandler.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/ext/chatmemberhandler.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/ext/choseninlineresulthandler.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/ext/commandhandler.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/ext/contexttypes.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/ext/conversationhandler.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/ext/defaults.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/ext/dictpersistence.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/ext/dispatcher.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/ext/extbot.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/ext/filters.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/ext/handler.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/ext/inlinequeryhandler.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/ext/jobqueue.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/ext/messagehandler.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/ext/messagequeue.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/ext/picklepersistence.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/ext/pollanswerhandler.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/ext/pollhandler.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/ext/precheckoutqueryhandler.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/ext/regexhandler.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/ext/shippingqueryhandler.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/ext/stringcommandhandler.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/ext/stringregexhandler.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/ext/typehandler.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/ext/updater.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/ext/utils/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/ext/utils/promise.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/ext/utils/types.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/ext/utils/webhookhandler.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/files/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/files/animation.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/files/audio.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/files/chatphoto.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/files/contact.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/files/document.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/files/file.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/files/inputfile.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/files/inputmedia.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/files/location.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/files/photosize.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/files/sticker.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/files/venue.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/files/video.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/files/videonote.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/files/voice.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/forcereply.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/games/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/games/callbackgame.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/games/game.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/games/gamehighscore.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/inline/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinekeyboardbutton.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinekeyboardmarkup.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequery.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresult.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultarticle.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultaudio.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedaudio.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcacheddocument.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedgif.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedmpeg4gif.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedphoto.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedsticker.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedvideo.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedvoice.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcontact.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultdocument.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultgame.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultgif.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultlocation.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultmpeg4gif.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultphoto.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultvenue.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultvideo.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultvoice.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inputcontactmessagecontent.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inputinvoicemessagecontent.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inputlocationmessagecontent.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inputmessagecontent.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inputtextmessagecontent.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/inline/inputvenuemessagecontent.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/keyboardbutton.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/keyboardbuttonpolltype.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/loginurl.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/message.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/messageautodeletetimerchanged.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/messageentity.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/messageid.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/parsemode.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/passport/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/passport/credentials.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/passport/data.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/passport/encryptedpassportelement.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/passport/passportdata.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/passport/passportelementerrors.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/passport/passportfile.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/payment/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/payment/invoice.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/payment/labeledprice.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/payment/orderinfo.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/payment/precheckoutquery.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/payment/shippingaddress.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/payment/shippingoption.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/payment/shippingquery.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/payment/successfulpayment.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/poll.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/proximityalerttriggered.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/py.typed delete mode 100644 venv/lib/python3.8/site-packages/telegram/replykeyboardmarkup.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/replykeyboardremove.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/replymarkup.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/update.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/user.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/userprofilephotos.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/utils/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/utils/deprecate.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/utils/helpers.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/utils/promise.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/utils/request.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/utils/types.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/utils/webhookhandler.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/_collections.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/connection.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/connectionpool.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/contrib/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/contrib/appengine.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/contrib/ntlmpool.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/contrib/pyopenssl.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/contrib/socks.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/exceptions.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/fields.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/filepost.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/backports/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/backports/makefile.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/ordered_dict.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/six.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/ssl_match_hostname/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/ssl_match_hostname/_implementation.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/poolmanager.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/request.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/response.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/connection.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/request.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/response.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/retry.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/selectors.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/ssl_.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/timeout.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/url.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/wait.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/version.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/voicechat.py delete mode 100644 venv/lib/python3.8/site-packages/telegram/webhookinfo.py delete mode 100644 venv/lib/python3.8/site-packages/tornado-6.1.dist-info/INSTALLER delete mode 100644 venv/lib/python3.8/site-packages/tornado-6.1.dist-info/LICENSE delete mode 100644 venv/lib/python3.8/site-packages/tornado-6.1.dist-info/METADATA delete mode 100644 venv/lib/python3.8/site-packages/tornado-6.1.dist-info/RECORD delete mode 100644 venv/lib/python3.8/site-packages/tornado-6.1.dist-info/WHEEL delete mode 100644 venv/lib/python3.8/site-packages/tornado-6.1.dist-info/top_level.txt delete mode 100644 venv/lib/python3.8/site-packages/tornado/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/_locale_data.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/auth.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/autoreload.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/concurrent.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/curl_httpclient.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/escape.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/gen.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/http1connection.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/httpclient.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/httpserver.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/httputil.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/ioloop.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/iostream.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/locale.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/locks.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/log.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/netutil.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/options.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/platform/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/platform/asyncio.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/platform/caresresolver.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/platform/twisted.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/process.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/py.typed delete mode 100644 venv/lib/python3.8/site-packages/tornado/queues.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/routing.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/simple_httpclient.py delete mode 100755 venv/lib/python3.8/site-packages/tornado/speedups.cpython-38-x86_64-linux-gnu.so delete mode 100644 venv/lib/python3.8/site-packages/tornado/tcpclient.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/tcpserver.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/template.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/__main__.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/asyncio_test.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/auth_test.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/autoreload_test.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/concurrent_test.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/csv_translations/fr_FR.csv delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/curl_httpclient_test.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/escape_test.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/gen_test.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/gettext_translations/fr_FR/LC_MESSAGES/tornado_test.mo delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/gettext_translations/fr_FR/LC_MESSAGES/tornado_test.po delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/http1connection_test.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/httpclient_test.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/httpserver_test.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/httputil_test.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/import_test.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/ioloop_test.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/iostream_test.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/locale_test.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/locks_test.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/log_test.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/netutil_test.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/options_test.cfg delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/options_test.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/options_test_types.cfg delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/options_test_types_str.cfg delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/process_test.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/queues_test.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/resolve_test_helper.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/routing_test.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/runtests.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/simple_httpclient_test.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/static/dir/index.html delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/static/robots.txt delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/static/sample.xml delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/static/sample.xml.bz2 delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/static/sample.xml.gz delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/static_foo.txt delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/tcpclient_test.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/tcpserver_test.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/template_test.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/templates/utf8.html delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/test.crt delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/test.key delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/testing_test.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/twisted_test.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/util.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/util_test.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/web_test.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/websocket_test.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/test/wsgi_test.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/testing.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/util.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/web.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/websocket.py delete mode 100644 venv/lib/python3.8/site-packages/tornado/wsgi.py delete mode 100644 venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/INSTALLER delete mode 100644 venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/LICENSE.txt delete mode 100644 venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/METADATA delete mode 100644 venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/RECORD delete mode 100644 venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/WHEEL delete mode 100644 venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/top_level.txt delete mode 100644 venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/zip-safe delete mode 100644 venv/lib/python3.8/site-packages/tzlocal/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/tzlocal/unix.py delete mode 100644 venv/lib/python3.8/site-packages/tzlocal/utils.py delete mode 100644 venv/lib/python3.8/site-packages/tzlocal/win32.py delete mode 100644 venv/lib/python3.8/site-packages/tzlocal/windows_tz.py delete mode 100644 venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/INSTALLER delete mode 100644 venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/LICENSE.txt delete mode 100644 venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/METADATA delete mode 100644 venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/RECORD delete mode 100644 venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/WHEEL delete mode 100644 venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/top_level.txt delete mode 100644 venv/lib/python3.8/site-packages/urllib3/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/urllib3/_collections.py delete mode 100644 venv/lib/python3.8/site-packages/urllib3/_version.py delete mode 100644 venv/lib/python3.8/site-packages/urllib3/connection.py delete mode 100644 venv/lib/python3.8/site-packages/urllib3/connectionpool.py delete mode 100644 venv/lib/python3.8/site-packages/urllib3/contrib/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/urllib3/contrib/_appengine_environ.py delete mode 100644 venv/lib/python3.8/site-packages/urllib3/contrib/_securetransport/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/urllib3/contrib/_securetransport/bindings.py delete mode 100644 venv/lib/python3.8/site-packages/urllib3/contrib/_securetransport/low_level.py delete mode 100644 venv/lib/python3.8/site-packages/urllib3/contrib/appengine.py delete mode 100644 venv/lib/python3.8/site-packages/urllib3/contrib/ntlmpool.py delete mode 100644 venv/lib/python3.8/site-packages/urllib3/contrib/pyopenssl.py delete mode 100644 venv/lib/python3.8/site-packages/urllib3/contrib/securetransport.py delete mode 100644 venv/lib/python3.8/site-packages/urllib3/contrib/socks.py delete mode 100644 venv/lib/python3.8/site-packages/urllib3/exceptions.py delete mode 100644 venv/lib/python3.8/site-packages/urllib3/fields.py delete mode 100644 venv/lib/python3.8/site-packages/urllib3/filepost.py delete mode 100644 venv/lib/python3.8/site-packages/urllib3/packages/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/urllib3/packages/backports/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/urllib3/packages/backports/makefile.py delete mode 100644 venv/lib/python3.8/site-packages/urllib3/packages/six.py delete mode 100644 venv/lib/python3.8/site-packages/urllib3/packages/ssl_match_hostname/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/urllib3/packages/ssl_match_hostname/_implementation.py delete mode 100644 venv/lib/python3.8/site-packages/urllib3/poolmanager.py delete mode 100644 venv/lib/python3.8/site-packages/urllib3/request.py delete mode 100644 venv/lib/python3.8/site-packages/urllib3/response.py delete mode 100644 venv/lib/python3.8/site-packages/urllib3/util/__init__.py delete mode 100644 venv/lib/python3.8/site-packages/urllib3/util/connection.py delete mode 100644 venv/lib/python3.8/site-packages/urllib3/util/proxy.py delete mode 100644 venv/lib/python3.8/site-packages/urllib3/util/queue.py delete mode 100644 venv/lib/python3.8/site-packages/urllib3/util/request.py delete mode 100644 venv/lib/python3.8/site-packages/urllib3/util/response.py delete mode 100644 venv/lib/python3.8/site-packages/urllib3/util/retry.py delete mode 100644 venv/lib/python3.8/site-packages/urllib3/util/ssl_.py delete mode 100644 venv/lib/python3.8/site-packages/urllib3/util/ssltransport.py delete mode 100644 venv/lib/python3.8/site-packages/urllib3/util/timeout.py delete mode 100644 venv/lib/python3.8/site-packages/urllib3/util/url.py delete mode 100644 venv/lib/python3.8/site-packages/urllib3/util/wait.py delete mode 120000 venv/lib64 delete mode 100644 venv/pyvenv.cfg delete mode 100644 venv/share/python-wheels/CacheControl-0.12.6-py2.py3-none-any.whl delete mode 100644 venv/share/python-wheels/appdirs-1.4.4-py2.py3-none-any.whl delete mode 100644 venv/share/python-wheels/certifi-2020.4.5.1-py2.py3-none-any.whl delete mode 100644 venv/share/python-wheels/chardet-3.0.4-py2.py3-none-any.whl delete mode 100644 venv/share/python-wheels/colorama-0.4.3-py2.py3-none-any.whl delete mode 100644 venv/share/python-wheels/contextlib2-0.6.0-py2.py3-none-any.whl delete mode 100644 venv/share/python-wheels/distlib-0.3.0-py2.py3-none-any.whl delete mode 100644 venv/share/python-wheels/distro-1.5.0-py2.py3-none-any.whl delete mode 100644 venv/share/python-wheels/html5lib-1.0.1-py2.py3-none-any.whl delete mode 100644 venv/share/python-wheels/idna-2.9-py2.py3-none-any.whl delete mode 100644 venv/share/python-wheels/ipaddr-2.2.0-py2.py3-none-any.whl delete mode 100644 venv/share/python-wheels/lockfile-0.12.2-py2.py3-none-any.whl delete mode 100644 venv/share/python-wheels/msgpack-0.6.2-py2.py3-none-any.whl delete mode 100644 venv/share/python-wheels/packaging-20.3-py2.py3-none-any.whl delete mode 100644 venv/share/python-wheels/pep517-0.8.2-py2.py3-none-any.whl delete mode 100644 venv/share/python-wheels/pip-20.1.1-py2.py3-none-any.whl delete mode 100644 venv/share/python-wheels/pkg_resources-0.0.0-py2.py3-none-any.whl delete mode 100644 venv/share/python-wheels/progress-1.5-py2.py3-none-any.whl delete mode 100644 venv/share/python-wheels/pyparsing-2.4.7-py2.py3-none-any.whl delete mode 100644 venv/share/python-wheels/requests-2.23.0-py2.py3-none-any.whl delete mode 100644 venv/share/python-wheels/resolvelib-0.3.0-py2.py3-none-any.whl delete mode 100644 venv/share/python-wheels/retrying-1.3.3-py2.py3-none-any.whl delete mode 100644 venv/share/python-wheels/setuptools-44.0.0-py2.py3-none-any.whl delete mode 100644 venv/share/python-wheels/six-1.15.0-py2.py3-none-any.whl delete mode 100644 venv/share/python-wheels/toml-0.10.1-py2.py3-none-any.whl delete mode 100644 venv/share/python-wheels/urllib3-1.25.9-py2.py3-none-any.whl delete mode 100644 venv/share/python-wheels/webencodings-0.5.1-py2.py3-none-any.whl delete mode 100644 venv/share/python-wheels/wheel-0.34.2-py2.py3-none-any.whl diff --git a/.gitignore b/.gitignore index 5b50af3..9d1abf1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ .token .token~ +.env +.env~ __pycache__ \ No newline at end of file diff --git a/Pipfile b/Pipfile new file mode 100644 index 0000000..65f9554 --- /dev/null +++ b/Pipfile @@ -0,0 +1,13 @@ +[[source]] +url = "https://pypi.org/simple" +verify_ssl = true +name = "pypi" + +[packages] +python-telegram-bot = "*" +requests = "*" + +[dev-packages] + +[requires] +python_version = "3.8" diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100644 index 0000000..ff0eb22 --- /dev/null +++ b/Pipfile.lock @@ -0,0 +1,152 @@ +{ + "_meta": { + "hash": { + "sha256": "77aaff997ff5dda7155bc4abafcf3ce732b8448ce27e814db976d194d7c05292" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.8" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "apscheduler": { + "hashes": [ + "sha256:3bb5229eed6fbbdafc13ce962712ae66e175aa214c69bed35a06bffcf0c5e244", + "sha256:e8b1ecdb4c7cb2818913f766d5898183c7cb8936680710a4d3a966e02262e526" + ], + "version": "==3.6.3" + }, + "cachetools": { + "hashes": [ + "sha256:2cc0b89715337ab6dbba85b5b50effe2b0c74e035d83ee8ed637cf52f12ae001", + "sha256:61b5ed1e22a0924aed1d23b478f37e8d52549ff8a961de2909c69bf950020cff" + ], + "markers": "python_version ~= '3.5'", + "version": "==4.2.2" + }, + "certifi": { + "hashes": [ + "sha256:2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee", + "sha256:50b1e4f8446b06f41be7dd6338db18e0990601dce795c2b1686458aa7e8fa7d8" + ], + "version": "==2021.5.30" + }, + "chardet": { + "hashes": [ + "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa", + "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", + "version": "==4.0.0" + }, + "idna": { + "hashes": [ + "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6", + "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==2.10" + }, + "python-telegram-bot": { + "hashes": [ + "sha256:37cfe8faba16fb68a8b5ab41a10e787c385f6296200c84256cc54d7c16334643", + "sha256:d4b3a8fd6a927bc6dc498fa00e8d6388570d089f5c015418c3b2b954e0719a7a" + ], + "index": "pypi", + "version": "==13.6" + }, + "pytz": { + "hashes": [ + "sha256:83a4a90894bf38e243cf052c8b58f381bfe9a7a483f6a9cab140bc7f702ac4da", + "sha256:eb10ce3e7736052ed3623d49975ce333bcd712c7bb19a58b9e2089d4057d0798" + ], + "version": "==2021.1" + }, + "requests": { + "hashes": [ + "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804", + "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e" + ], + "index": "pypi", + "version": "==2.25.1" + }, + "six": { + "hashes": [ + "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", + "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", + "version": "==1.16.0" + }, + "tornado": { + "hashes": [ + "sha256:0a00ff4561e2929a2c37ce706cb8233b7907e0cdc22eab98888aca5dd3775feb", + "sha256:0d321a39c36e5f2c4ff12b4ed58d41390460f798422c4504e09eb5678e09998c", + "sha256:1e8225a1070cd8eec59a996c43229fe8f95689cb16e552d130b9793cb570a288", + "sha256:20241b3cb4f425e971cb0a8e4ffc9b0a861530ae3c52f2b0434e6c1b57e9fd95", + "sha256:25ad220258349a12ae87ede08a7b04aca51237721f63b1808d39bdb4b2164558", + "sha256:33892118b165401f291070100d6d09359ca74addda679b60390b09f8ef325ffe", + "sha256:33c6e81d7bd55b468d2e793517c909b139960b6c790a60b7991b9b6b76fb9791", + "sha256:3447475585bae2e77ecb832fc0300c3695516a47d46cefa0528181a34c5b9d3d", + "sha256:34ca2dac9e4d7afb0bed4677512e36a52f09caa6fded70b4e3e1c89dbd92c326", + "sha256:3e63498f680547ed24d2c71e6497f24bca791aca2fe116dbc2bd0ac7f191691b", + "sha256:548430be2740e327b3fe0201abe471f314741efcb0067ec4f2d7dcfb4825f3e4", + "sha256:6196a5c39286cc37c024cd78834fb9345e464525d8991c21e908cc046d1cc02c", + "sha256:61b32d06ae8a036a6607805e6720ef00a3c98207038444ba7fd3d169cd998910", + "sha256:6286efab1ed6e74b7028327365cf7346b1d777d63ab30e21a0f4d5b275fc17d5", + "sha256:65d98939f1a2e74b58839f8c4dab3b6b3c1ce84972ae712be02845e65391ac7c", + "sha256:66324e4e1beede9ac79e60f88de548da58b1f8ab4b2f1354d8375774f997e6c0", + "sha256:6c77c9937962577a6a76917845d06af6ab9197702a42e1346d8ae2e76b5e3675", + "sha256:70dec29e8ac485dbf57481baee40781c63e381bebea080991893cd297742b8fd", + "sha256:7250a3fa399f08ec9cb3f7b1b987955d17e044f1ade821b32e5f435130250d7f", + "sha256:748290bf9112b581c525e6e6d3820621ff020ed95af6f17fedef416b27ed564c", + "sha256:7da13da6f985aab7f6f28debab00c67ff9cbacd588e8477034c0652ac141feea", + "sha256:8f959b26f2634a091bb42241c3ed8d3cedb506e7c27b8dd5c7b9f745318ddbb6", + "sha256:9de9e5188a782be6b1ce866e8a51bc76a0fbaa0e16613823fc38e4fc2556ad05", + "sha256:a48900ecea1cbb71b8c71c620dee15b62f85f7c14189bdeee54966fbd9a0c5bd", + "sha256:b87936fd2c317b6ee08a5741ea06b9d11a6074ef4cc42e031bc6403f82a32575", + "sha256:c77da1263aa361938476f04c4b6c8916001b90b2c2fdd92d8d535e1af48fba5a", + "sha256:cb5ec8eead331e3bb4ce8066cf06d2dfef1bfb1b2a73082dfe8a161301b76e37", + "sha256:cc0ee35043162abbf717b7df924597ade8e5395e7b66d18270116f8745ceb795", + "sha256:d14d30e7f46a0476efb0deb5b61343b1526f73ebb5ed84f23dc794bdb88f9d9f", + "sha256:d371e811d6b156d82aa5f9a4e08b58debf97c302a35714f6f45e35139c332e32", + "sha256:d3d20ea5782ba63ed13bc2b8c291a053c8d807a8fa927d941bd718468f7b950c", + "sha256:d3f7594930c423fd9f5d1a76bee85a2c36fd8b4b16921cae7e965f22575e9c01", + "sha256:dcef026f608f678c118779cd6591c8af6e9b4155c44e0d1bc0c87c036fb8c8c4", + "sha256:e0791ac58d91ac58f694d8d2957884df8e4e2f6687cdf367ef7eb7497f79eaa2", + "sha256:e385b637ac3acaae8022e7e47dfa7b83d3620e432e3ecb9a3f7f58f150e50921", + "sha256:e519d64089b0876c7b467274468709dadf11e41d65f63bba207e04217f47c085", + "sha256:e7229e60ac41a1202444497ddde70a48d33909e484f96eb0da9baf8dc68541df", + "sha256:ed3ad863b1b40cd1d4bd21e7498329ccaece75db5a5bf58cd3c9f130843e7102", + "sha256:f0ba29bafd8e7e22920567ce0d232c26d4d47c8b5cf4ed7b562b5db39fa199c5", + "sha256:fa2ba70284fa42c2a5ecb35e322e68823288a4251f9ba9cc77be04ae15eada68", + "sha256:fba85b6cd9c39be262fcd23865652920832b61583de2a2ca907dbd8e8a8c81e5" + ], + "markers": "python_version >= '3.5'", + "version": "==6.1" + }, + "tzlocal": { + "hashes": [ + "sha256:643c97c5294aedc737780a49d9df30889321cbe1204eac2c2ec6134035a92e44", + "sha256:e2cb6c6b5b604af38597403e9852872d7f534962ae2954c7f35efcb1ccacf4a4" + ], + "version": "==2.1" + }, + "urllib3": { + "hashes": [ + "sha256:39fb8672126159acb139a7718dd10806104dec1e2f0f6c88aab05d17df10c8d4", + "sha256:f57b4c16c62fa2760b7e3d97c35b255512fb6b59a259730f36ba32ce9f8e342f" + ], + "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", + "version": "==1.26.6" + } + }, + "develop": {} +} diff --git a/src/bottoken.py b/src/bottoken.py deleted file mode 100644 index 2b0154c..0000000 --- a/src/bottoken.py +++ /dev/null @@ -1 +0,0 @@ -TOKEN = "1850056100:AAGki5PflfrwQlX4aQ7a6ErnCCxfwLRrxyA" diff --git a/src/run.py b/src/run.py index 4413552..acf9839 100644 --- a/src/run.py +++ b/src/run.py @@ -1,11 +1,12 @@ # driver code +import os from pyuku import Pyuku if __name__ == "__main__": - try: - with open(".token", "r") as tokenFile: - token = tokenFile.readline().strip() - Pyuku(token) - except IOError: - print("No token file detected.") + env = os.environ + if "BOT_TOKEN" in env: + token = env["BOT_TOKEN"] + Pyuku(token) + else: + print("There is no token present") diff --git a/venv/bin/Activate.ps1 b/venv/bin/Activate.ps1 deleted file mode 100644 index 2fb3852..0000000 --- a/venv/bin/Activate.ps1 +++ /dev/null @@ -1,241 +0,0 @@ -<# -.Synopsis -Activate a Python virtual environment for the current PowerShell session. - -.Description -Pushes the python executable for a virtual environment to the front of the -$Env:PATH environment variable and sets the prompt to signify that you are -in a Python virtual environment. Makes use of the command line switches as -well as the `pyvenv.cfg` file values present in the virtual environment. - -.Parameter VenvDir -Path to the directory that contains the virtual environment to activate. The -default value for this is the parent of the directory that the Activate.ps1 -script is located within. - -.Parameter Prompt -The prompt prefix to display when this virtual environment is activated. By -default, this prompt is the name of the virtual environment folder (VenvDir) -surrounded by parentheses and followed by a single space (ie. '(.venv) '). - -.Example -Activate.ps1 -Activates the Python virtual environment that contains the Activate.ps1 script. - -.Example -Activate.ps1 -Verbose -Activates the Python virtual environment that contains the Activate.ps1 script, -and shows extra information about the activation as it executes. - -.Example -Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv -Activates the Python virtual environment located in the specified location. - -.Example -Activate.ps1 -Prompt "MyPython" -Activates the Python virtual environment that contains the Activate.ps1 script, -and prefixes the current prompt with the specified string (surrounded in -parentheses) while the virtual environment is active. - -.Notes -On Windows, it may be required to enable this Activate.ps1 script by setting the -execution policy for the user. You can do this by issuing the following PowerShell -command: - -PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser - -For more information on Execution Policies: -https://go.microsoft.com/fwlink/?LinkID=135170 - -#> -Param( - [Parameter(Mandatory = $false)] - [String] - $VenvDir, - [Parameter(Mandatory = $false)] - [String] - $Prompt -) - -<# Function declarations --------------------------------------------------- #> - -<# -.Synopsis -Remove all shell session elements added by the Activate script, including the -addition of the virtual environment's Python executable from the beginning of -the PATH variable. - -.Parameter NonDestructive -If present, do not remove this function from the global namespace for the -session. - -#> -function global:deactivate ([switch]$NonDestructive) { - # Revert to original values - - # The prior prompt: - if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) { - Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt - Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT - } - - # The prior PYTHONHOME: - if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) { - Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME - Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME - } - - # The prior PATH: - if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) { - Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH - Remove-Item -Path Env:_OLD_VIRTUAL_PATH - } - - # Just remove the VIRTUAL_ENV altogether: - if (Test-Path -Path Env:VIRTUAL_ENV) { - Remove-Item -Path env:VIRTUAL_ENV - } - - # Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether: - if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) { - Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force - } - - # Leave deactivate function in the global namespace if requested: - if (-not $NonDestructive) { - Remove-Item -Path function:deactivate - } -} - -<# -.Description -Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the -given folder, and returns them in a map. - -For each line in the pyvenv.cfg file, if that line can be parsed into exactly -two strings separated by `=` (with any amount of whitespace surrounding the =) -then it is considered a `key = value` line. The left hand string is the key, -the right hand is the value. - -If the value starts with a `'` or a `"` then the first and last character is -stripped from the value before being captured. - -.Parameter ConfigDir -Path to the directory that contains the `pyvenv.cfg` file. -#> -function Get-PyVenvConfig( - [String] - $ConfigDir -) { - Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg" - - # Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue). - $pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue - - # An empty map will be returned if no config file is found. - $pyvenvConfig = @{ } - - if ($pyvenvConfigPath) { - - Write-Verbose "File exists, parse `key = value` lines" - $pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath - - $pyvenvConfigContent | ForEach-Object { - $keyval = $PSItem -split "\s*=\s*", 2 - if ($keyval[0] -and $keyval[1]) { - $val = $keyval[1] - - # Remove extraneous quotations around a string value. - if ("'""".Contains($val.Substring(0, 1))) { - $val = $val.Substring(1, $val.Length - 2) - } - - $pyvenvConfig[$keyval[0]] = $val - Write-Verbose "Adding Key: '$($keyval[0])'='$val'" - } - } - } - return $pyvenvConfig -} - - -<# Begin Activate script --------------------------------------------------- #> - -# Determine the containing directory of this script -$VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition -$VenvExecDir = Get-Item -Path $VenvExecPath - -Write-Verbose "Activation script is located in path: '$VenvExecPath'" -Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)" -Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)" - -# Set values required in priority: CmdLine, ConfigFile, Default -# First, get the location of the virtual environment, it might not be -# VenvExecDir if specified on the command line. -if ($VenvDir) { - Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values" -} -else { - Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir." - $VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/") - Write-Verbose "VenvDir=$VenvDir" -} - -# Next, read the `pyvenv.cfg` file to determine any required value such -# as `prompt`. -$pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir - -# Next, set the prompt from the command line, or the config file, or -# just use the name of the virtual environment folder. -if ($Prompt) { - Write-Verbose "Prompt specified as argument, using '$Prompt'" -} -else { - Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value" - if ($pyvenvCfg -and $pyvenvCfg['prompt']) { - Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'" - $Prompt = $pyvenvCfg['prompt']; - } - else { - Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virutal environment)" - Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'" - $Prompt = Split-Path -Path $venvDir -Leaf - } -} - -Write-Verbose "Prompt = '$Prompt'" -Write-Verbose "VenvDir='$VenvDir'" - -# Deactivate any currently active virtual environment, but leave the -# deactivate function in place. -deactivate -nondestructive - -# Now set the environment variable VIRTUAL_ENV, used by many tools to determine -# that there is an activated venv. -$env:VIRTUAL_ENV = $VenvDir - -if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) { - - Write-Verbose "Setting prompt to '$Prompt'" - - # Set the prompt to include the env name - # Make sure _OLD_VIRTUAL_PROMPT is global - function global:_OLD_VIRTUAL_PROMPT { "" } - Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT - New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt - - function global:prompt { - Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) " - _OLD_VIRTUAL_PROMPT - } -} - -# Clear PYTHONHOME -if (Test-Path -Path Env:PYTHONHOME) { - Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME - Remove-Item -Path Env:PYTHONHOME -} - -# Add the venv to the PATH -Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH -$Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH" diff --git a/venv/bin/activate b/venv/bin/activate deleted file mode 100644 index f3e9659..0000000 --- a/venv/bin/activate +++ /dev/null @@ -1,76 +0,0 @@ -# This file must be used with "source bin/activate" *from bash* -# you cannot run it directly - -deactivate () { - # reset old environment variables - if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then - PATH="${_OLD_VIRTUAL_PATH:-}" - export PATH - unset _OLD_VIRTUAL_PATH - fi - if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then - PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}" - export PYTHONHOME - unset _OLD_VIRTUAL_PYTHONHOME - fi - - # This should detect bash and zsh, which have a hash command that must - # be called to get it to forget past commands. Without forgetting - # past commands the $PATH changes we made may not be respected - if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then - hash -r - fi - - if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then - PS1="${_OLD_VIRTUAL_PS1:-}" - export PS1 - unset _OLD_VIRTUAL_PS1 - fi - - unset VIRTUAL_ENV - if [ ! "${1:-}" = "nondestructive" ] ; then - # Self destruct! - unset -f deactivate - fi -} - -# unset irrelevant variables -deactivate nondestructive - -VIRTUAL_ENV="/home/kyoumabat/Documents/PyukuBot/venv" -export VIRTUAL_ENV - -_OLD_VIRTUAL_PATH="$PATH" -PATH="$VIRTUAL_ENV/bin:$PATH" -export PATH - -# unset PYTHONHOME if set -# this will fail if PYTHONHOME is set to the empty string (which is bad anyway) -# could use `if (set -u; : $PYTHONHOME) ;` in bash -if [ -n "${PYTHONHOME:-}" ] ; then - _OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}" - unset PYTHONHOME -fi - -if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then - _OLD_VIRTUAL_PS1="${PS1:-}" - if [ "x(venv) " != x ] ; then - PS1="(venv) ${PS1:-}" - else - if [ "`basename \"$VIRTUAL_ENV\"`" = "__" ] ; then - # special case for Aspen magic directories - # see https://aspen.io/ - PS1="[`basename \`dirname \"$VIRTUAL_ENV\"\``] $PS1" - else - PS1="(`basename \"$VIRTUAL_ENV\"`)$PS1" - fi - fi - export PS1 -fi - -# This should detect bash and zsh, which have a hash command that must -# be called to get it to forget past commands. Without forgetting -# past commands the $PATH changes we made may not be respected -if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then - hash -r -fi diff --git a/venv/bin/activate.csh b/venv/bin/activate.csh deleted file mode 100644 index 9a704f8..0000000 --- a/venv/bin/activate.csh +++ /dev/null @@ -1,37 +0,0 @@ -# This file must be used with "source bin/activate.csh" *from csh*. -# You cannot run it directly. -# Created by Davide Di Blasi <davidedb@gmail.com>. -# Ported to Python 3.3 venv by Andrew Svetlov <andrew.svetlov@gmail.com> - -alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; test "\!:*" != "nondestructive" && unalias deactivate' - -# Unset irrelevant variables. -deactivate nondestructive - -setenv VIRTUAL_ENV "/home/kyoumabat/Documents/PyukuBot/venv" - -set _OLD_VIRTUAL_PATH="$PATH" -setenv PATH "$VIRTUAL_ENV/bin:$PATH" - - -set _OLD_VIRTUAL_PROMPT="$prompt" - -if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then - if ("venv" != "") then - set env_name = "venv" - else - if (`basename "VIRTUAL_ENV"` == "__") then - # special case for Aspen magic directories - # see https://aspen.io/ - set env_name = `basename \`dirname "$VIRTUAL_ENV"\`` - else - set env_name = `basename "$VIRTUAL_ENV"` - endif - endif - set prompt = "[$env_name] $prompt" - unset env_name -endif - -alias pydoc python -m pydoc - -rehash diff --git a/venv/bin/activate.fish b/venv/bin/activate.fish deleted file mode 100644 index e9232ca..0000000 --- a/venv/bin/activate.fish +++ /dev/null @@ -1,75 +0,0 @@ -# This file must be used with ". bin/activate.fish" *from fish* (http://fishshell.org) -# you cannot run it directly - -function deactivate -d "Exit virtualenv and return to normal shell environment" - # reset old environment variables - if test -n "$_OLD_VIRTUAL_PATH" - set -gx PATH $_OLD_VIRTUAL_PATH - set -e _OLD_VIRTUAL_PATH - end - if test -n "$_OLD_VIRTUAL_PYTHONHOME" - set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME - set -e _OLD_VIRTUAL_PYTHONHOME - end - - if test -n "$_OLD_FISH_PROMPT_OVERRIDE" - functions -e fish_prompt - set -e _OLD_FISH_PROMPT_OVERRIDE - functions -c _old_fish_prompt fish_prompt - functions -e _old_fish_prompt - end - - set -e VIRTUAL_ENV - if test "$argv[1]" != "nondestructive" - # Self destruct! - functions -e deactivate - end -end - -# unset irrelevant variables -deactivate nondestructive - -set -gx VIRTUAL_ENV "/home/kyoumabat/Documents/PyukuBot/venv" - -set -gx _OLD_VIRTUAL_PATH $PATH -set -gx PATH "$VIRTUAL_ENV/bin" $PATH - -# unset PYTHONHOME if set -if set -q PYTHONHOME - set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME - set -e PYTHONHOME -end - -if test -z "$VIRTUAL_ENV_DISABLE_PROMPT" - # fish uses a function instead of an env var to generate the prompt. - - # save the current fish_prompt function as the function _old_fish_prompt - functions -c fish_prompt _old_fish_prompt - - # with the original prompt function renamed, we can override with our own. - function fish_prompt - # Save the return status of the last command - set -l old_status $status - - # Prompt override? - if test -n "(venv) " - printf "%s%s" "(venv) " (set_color normal) - else - # ...Otherwise, prepend env - set -l _checkbase (basename "$VIRTUAL_ENV") - if test $_checkbase = "__" - # special case for Aspen magic directories - # see https://aspen.io/ - printf "%s[%s]%s " (set_color -b blue white) (basename (dirname "$VIRTUAL_ENV")) (set_color normal) - else - printf "%s(%s)%s" (set_color -b blue white) (basename "$VIRTUAL_ENV") (set_color normal) - end - end - - # Restore the return status of the previous command. - echo "exit $old_status" | . - _old_fish_prompt - end - - set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV" -end diff --git a/venv/bin/chardetect b/venv/bin/chardetect deleted file mode 100755 index 5a08aed..0000000 --- a/venv/bin/chardetect +++ /dev/null @@ -1,8 +0,0 @@ -#!/home/kyoumabat/Documents/PyukuBot/venv/bin/python3 -# -*- coding: utf-8 -*- -import re -import sys -from chardet.cli.chardetect import main -if __name__ == '__main__': - sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) - sys.exit(main()) diff --git a/venv/bin/easy_install b/venv/bin/easy_install deleted file mode 100755 index 09ba853..0000000 --- a/venv/bin/easy_install +++ /dev/null @@ -1,8 +0,0 @@ -#!/home/kyoumabat/Documents/PyukuBot/venv/bin/python3 -# -*- coding: utf-8 -*- -import re -import sys -from setuptools.command.easy_install import main -if __name__ == '__main__': - sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) - sys.exit(main()) diff --git a/venv/bin/easy_install-3.8 b/venv/bin/easy_install-3.8 deleted file mode 100755 index 09ba853..0000000 --- a/venv/bin/easy_install-3.8 +++ /dev/null @@ -1,8 +0,0 @@ -#!/home/kyoumabat/Documents/PyukuBot/venv/bin/python3 -# -*- coding: utf-8 -*- -import re -import sys -from setuptools.command.easy_install import main -if __name__ == '__main__': - sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) - sys.exit(main()) diff --git a/venv/bin/pip b/venv/bin/pip deleted file mode 100755 index 89079cf..0000000 --- a/venv/bin/pip +++ /dev/null @@ -1,8 +0,0 @@ -#!/home/kyoumabat/Documents/PyukuBot/venv/bin/python3 -# -*- coding: utf-8 -*- -import re -import sys -from pip._internal.cli.main import main -if __name__ == '__main__': - sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) - sys.exit(main()) diff --git a/venv/bin/pip3 b/venv/bin/pip3 deleted file mode 100755 index 89079cf..0000000 --- a/venv/bin/pip3 +++ /dev/null @@ -1,8 +0,0 @@ -#!/home/kyoumabat/Documents/PyukuBot/venv/bin/python3 -# -*- coding: utf-8 -*- -import re -import sys -from pip._internal.cli.main import main -if __name__ == '__main__': - sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) - sys.exit(main()) diff --git a/venv/bin/pip3.8 b/venv/bin/pip3.8 deleted file mode 100755 index 89079cf..0000000 --- a/venv/bin/pip3.8 +++ /dev/null @@ -1,8 +0,0 @@ -#!/home/kyoumabat/Documents/PyukuBot/venv/bin/python3 -# -*- coding: utf-8 -*- -import re -import sys -from pip._internal.cli.main import main -if __name__ == '__main__': - sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) - sys.exit(main()) diff --git a/venv/bin/python b/venv/bin/python deleted file mode 120000 index b8a0adb..0000000 --- a/venv/bin/python +++ /dev/null @@ -1 +0,0 @@ -python3 \ No newline at end of file diff --git a/venv/bin/python3 b/venv/bin/python3 deleted file mode 120000 index ae65fda..0000000 --- a/venv/bin/python3 +++ /dev/null @@ -1 +0,0 @@ -/usr/bin/python3 \ No newline at end of file diff --git a/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/INSTALLER b/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/LICENSE.txt b/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/LICENSE.txt deleted file mode 100644 index 07806f8..0000000 --- a/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/LICENSE.txt +++ /dev/null @@ -1,19 +0,0 @@ -This is the MIT license: http://www.opensource.org/licenses/mit-license.php - -Copyright (c) Alex Grönholm - -Permission is hereby granted, free of charge, to any person obtaining a copy of this -software and associated documentation files (the "Software"), to deal in the Software -without restriction, including without limitation the rights to use, copy, modify, merge, -publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons -to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or -substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, -INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR -PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE -FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR -OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. diff --git a/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/METADATA b/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/METADATA deleted file mode 100644 index ba40f6b..0000000 --- a/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/METADATA +++ /dev/null @@ -1,133 +0,0 @@ -Metadata-Version: 2.1 -Name: APScheduler -Version: 3.6.3 -Summary: In-process task scheduler with Cron-like capabilities -Home-page: https://github.com/agronholm/apscheduler -Author: Alex Grönholm -Author-email: apscheduler@nextday.fi -License: MIT -Keywords: scheduling cron -Platform: UNKNOWN -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: MIT License -Classifier: Programming Language :: Python -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 -Requires-Dist: setuptools (>=0.7) -Requires-Dist: six (>=1.4.0) -Requires-Dist: pytz -Requires-Dist: tzlocal (>=1.2) -Requires-Dist: futures ; python_version == "2.7" -Requires-Dist: funcsigs ; python_version == "2.7" -Provides-Extra: asyncio -Requires-Dist: trollius ; (python_version == "2.7") and extra == 'asyncio' -Provides-Extra: doc -Requires-Dist: sphinx ; extra == 'doc' -Requires-Dist: sphinx-rtd-theme ; extra == 'doc' -Provides-Extra: gevent -Requires-Dist: gevent ; extra == 'gevent' -Provides-Extra: mongodb -Requires-Dist: pymongo (>=2.8) ; extra == 'mongodb' -Provides-Extra: redis -Requires-Dist: redis (>=3.0) ; extra == 'redis' -Provides-Extra: rethinkdb -Requires-Dist: rethinkdb (>=2.4.0) ; extra == 'rethinkdb' -Provides-Extra: sqlalchemy -Requires-Dist: sqlalchemy (>=0.8) ; extra == 'sqlalchemy' -Provides-Extra: testing -Requires-Dist: pytest ; extra == 'testing' -Requires-Dist: pytest-cov ; extra == 'testing' -Requires-Dist: pytest-tornado5 ; extra == 'testing' -Requires-Dist: mock ; (python_version == "2.7") and extra == 'testing' -Requires-Dist: pytest-asyncio (<0.6) ; (python_version == "3.4") and extra == 'testing' -Requires-Dist: pytest-asyncio ; (python_version >= "3.5") and extra == 'testing' -Provides-Extra: tornado -Requires-Dist: tornado (>=4.3) ; extra == 'tornado' -Provides-Extra: twisted -Requires-Dist: twisted ; extra == 'twisted' -Provides-Extra: zookeeper -Requires-Dist: kazoo ; extra == 'zookeeper' - -.. image:: https://travis-ci.com/agronholm/apscheduler.svg?branch=master - :target: https://travis-ci.com/agronholm/apscheduler - :alt: Build Status -.. image:: https://coveralls.io/repos/github/agronholm/apscheduler/badge.svg?branch=master - :target: https://coveralls.io/github/agronholm/apscheduler?branch=master - :alt: Code Coverage - -Advanced Python Scheduler (APScheduler) is a Python library that lets you schedule your Python code -to be executed later, either just once or periodically. You can add new jobs or remove old ones on -the fly as you please. If you store your jobs in a database, they will also survive scheduler -restarts and maintain their state. When the scheduler is restarted, it will then run all the jobs -it should have run while it was offline [#f1]_. - -Among other things, APScheduler can be used as a cross-platform, application specific replacement -to platform specific schedulers, such as the cron daemon or the Windows task scheduler. Please -note, however, that APScheduler is **not** a daemon or service itself, nor does it come with any -command line tools. It is primarily meant to be run inside existing applications. That said, -APScheduler does provide some building blocks for you to build a scheduler service or to run a -dedicated scheduler process. - -APScheduler has three built-in scheduling systems you can use: - -* Cron-style scheduling (with optional start/end times) -* Interval-based execution (runs jobs on even intervals, with optional start/end times) -* One-off delayed execution (runs jobs once, on a set date/time) - -You can mix and match scheduling systems and the backends where the jobs are stored any way you -like. Supported backends for storing jobs include: - -* Memory -* `SQLAlchemy <http://www.sqlalchemy.org/>`_ (any RDBMS supported by SQLAlchemy works) -* `MongoDB <http://www.mongodb.org/>`_ -* `Redis <http://redis.io/>`_ -* `RethinkDB <https://www.rethinkdb.com/>`_ -* `ZooKeeper <https://zookeeper.apache.org/>`_ - -APScheduler also integrates with several common Python frameworks, like: - -* `asyncio <http://docs.python.org/3.4/library/asyncio.html>`_ (:pep:`3156`) -* `gevent <http://www.gevent.org/>`_ -* `Tornado <http://www.tornadoweb.org/>`_ -* `Twisted <http://twistedmatrix.com/>`_ -* `Qt <http://qt-project.org/>`_ (using either - `PyQt <http://www.riverbankcomputing.com/software/pyqt/intro>`_ or - `PySide <http://qt-project.org/wiki/PySide>`_) - -.. [#f1] The cutoff period for this is also configurable. - - -Documentation -------------- - -Documentation can be found `here <http://readthedocs.org/docs/apscheduler/en/latest/>`_. - - -Source ------- - -The source can be browsed at `Github <https://github.com/agronholm/apscheduler>`_. - - -Reporting bugs --------------- - -A `bug tracker <https://github.com/agronholm/apscheduler/issues>`_ is provided by Github. - - -Getting help ------------- - -If you have problems or other questions, you can either: - -* Ask in the `apscheduler <https://gitter.im/apscheduler/Lobby>`_ room on Gitter -* Ask on the `APScheduler Google group <http://groups.google.com/group/apscheduler>`_, or -* Ask on `StackOverflow <http://stackoverflow.com/questions/tagged/apscheduler>`_ and tag your - question with the ``apscheduler`` tag - - diff --git a/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/RECORD b/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/RECORD deleted file mode 100644 index 2c63ee3..0000000 --- a/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/RECORD +++ /dev/null @@ -1,83 +0,0 @@ -APScheduler-3.6.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -APScheduler-3.6.3.dist-info/LICENSE.txt,sha256=YWP3mH37ONa8MgzitwsvArhivEESZRbVUu8c1DJH51g,1130 -APScheduler-3.6.3.dist-info/METADATA,sha256=VHah1X4AqMCGgcvEm06M-pAqmNC9q4tOQRbUv3b0Jh0,5398 -APScheduler-3.6.3.dist-info/RECORD,, -APScheduler-3.6.3.dist-info/WHEEL,sha256=8zNYZbwQSXoB9IfXOjPfeNwvAsALAjffgk27FqvCWbo,110 -APScheduler-3.6.3.dist-info/entry_points.txt,sha256=7RgkYN_OYyCUQtIGhj-UNcelnIjsNm7nC9rogdMQh3U,1148 -APScheduler-3.6.3.dist-info/top_level.txt,sha256=O3oMCWxG-AHkecUoO6Ze7-yYjWrttL95uHO8-RFdYvE,12 -apscheduler/__init__.py,sha256=qFEK2ysRBcLiYmm3deyJJ1avUOugaM_nCGHMD42WMBw,380 -apscheduler/__pycache__/__init__.cpython-38.pyc,, -apscheduler/__pycache__/events.cpython-38.pyc,, -apscheduler/__pycache__/job.cpython-38.pyc,, -apscheduler/__pycache__/util.cpython-38.pyc,, -apscheduler/events.py,sha256=KRMTDQUS6d2uVnrQvPoz3ZPV5V9XKsCAZLsgx913FFo,3593 -apscheduler/executors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -apscheduler/executors/__pycache__/__init__.cpython-38.pyc,, -apscheduler/executors/__pycache__/asyncio.cpython-38.pyc,, -apscheduler/executors/__pycache__/base.cpython-38.pyc,, -apscheduler/executors/__pycache__/base_py3.cpython-38.pyc,, -apscheduler/executors/__pycache__/debug.cpython-38.pyc,, -apscheduler/executors/__pycache__/gevent.cpython-38.pyc,, -apscheduler/executors/__pycache__/pool.cpython-38.pyc,, -apscheduler/executors/__pycache__/tornado.cpython-38.pyc,, -apscheduler/executors/__pycache__/twisted.cpython-38.pyc,, -apscheduler/executors/asyncio.py,sha256=ji5f6Qm2uGhov-3w52CXHZi8jc5U_gS56lisQylKTBQ,2087 -apscheduler/executors/base.py,sha256=hogiMc_t-huw6BMod0HEeY2FhRNmAAUyNNuBHvIX31M,5336 -apscheduler/executors/base_py3.py,sha256=s_4siAjBHrr7JZnm64VVow9zyvs2JBc-VRPkPuDeBTI,1775 -apscheduler/executors/debug.py,sha256=15_ogSBzl8RRCfBYDnkIV2uMH8cLk1KImYmBa_NVGpc,573 -apscheduler/executors/gevent.py,sha256=aulrNmoefyBgrOkH9awRhFiXIDnSCnZ4U0o0_JXIXgc,777 -apscheduler/executors/pool.py,sha256=q9TC6KzwWI9tpLNxQhdrKRWFtsN5dmx_Vegu23BV-Sk,1672 -apscheduler/executors/tornado.py,sha256=DU75VaQ9R6nBuy8lbPUvDKUgsuJcZqwAvURC5vg3r6w,1780 -apscheduler/executors/twisted.py,sha256=bRoU0C4BoVcS6_BjKD5wfUs0IJpGkmLsRAcMH2rJJss,778 -apscheduler/job.py,sha256=zT9_GuOpxuxEPVZU38tantw9383tAPRBPoH6dd4uHGA,11088 -apscheduler/jobstores/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -apscheduler/jobstores/__pycache__/__init__.cpython-38.pyc,, -apscheduler/jobstores/__pycache__/base.cpython-38.pyc,, -apscheduler/jobstores/__pycache__/memory.cpython-38.pyc,, -apscheduler/jobstores/__pycache__/mongodb.cpython-38.pyc,, -apscheduler/jobstores/__pycache__/redis.cpython-38.pyc,, -apscheduler/jobstores/__pycache__/rethinkdb.cpython-38.pyc,, -apscheduler/jobstores/__pycache__/sqlalchemy.cpython-38.pyc,, -apscheduler/jobstores/__pycache__/zookeeper.cpython-38.pyc,, -apscheduler/jobstores/base.py,sha256=DXzSW9XscueHZHMvy1qFiG-vYqUl_MMv0n0uBSZWXGo,4523 -apscheduler/jobstores/memory.py,sha256=ZxWiKsqfsCHFvac-6X9BztuhnuSxlOYi1dhT6g-pjQo,3655 -apscheduler/jobstores/mongodb.py,sha256=e9KNzPFrjiVpiM3iPT_c0ONxZQT70VCF2rDXW0-22zk,5296 -apscheduler/jobstores/redis.py,sha256=kjQDIzPXz-Yq976U9HK3aMkcCI_QRLKgTADQWKewtik,5483 -apscheduler/jobstores/rethinkdb.py,sha256=k1rSLYJqejuhQxJY3pXwHAQYcpZ1QFJsoQ8n0oEu5MM,5863 -apscheduler/jobstores/sqlalchemy.py,sha256=5H5T05cQ2ZtkRuRb8hKkcLzZSQneAT13NMKXby3nzWE,6122 -apscheduler/jobstores/zookeeper.py,sha256=BzyqZ08XIDcbu5frQWGmDVEHAEScNxjt8oML6Tty8j8,6406 -apscheduler/schedulers/__init__.py,sha256=jM63xA_K7GSToBenhsz-SCcqfhk1pdEVb6ajwoO5Kqg,406 -apscheduler/schedulers/__pycache__/__init__.cpython-38.pyc,, -apscheduler/schedulers/__pycache__/asyncio.cpython-38.pyc,, -apscheduler/schedulers/__pycache__/background.cpython-38.pyc,, -apscheduler/schedulers/__pycache__/base.cpython-38.pyc,, -apscheduler/schedulers/__pycache__/blocking.cpython-38.pyc,, -apscheduler/schedulers/__pycache__/gevent.cpython-38.pyc,, -apscheduler/schedulers/__pycache__/qt.cpython-38.pyc,, -apscheduler/schedulers/__pycache__/tornado.cpython-38.pyc,, -apscheduler/schedulers/__pycache__/twisted.cpython-38.pyc,, -apscheduler/schedulers/asyncio.py,sha256=0j0mcDpf-zI_vQHcUCZZtBfEEZEiocEOZ767efIZ5YM,2082 -apscheduler/schedulers/background.py,sha256=dGX0T0z6T6HzZHG7njWgp90SFHpetZ4ZBUV2gGOSqoc,1505 -apscheduler/schedulers/base.py,sha256=EUGbQ5R2jGA4PEEehU2ASuKVe0SsLqtWESAtTqAJW50,42863 -apscheduler/schedulers/blocking.py,sha256=c-5YR-dKn3D82tPt38t50KGPJrAiC852v8ai2Vwanmg,924 -apscheduler/schedulers/gevent.py,sha256=csPBvV75FGcboXXsdex6fCD7J54QgBddYNdWj62ZO9g,1031 -apscheduler/schedulers/qt.py,sha256=AhHU62ybOOVSD4OhMwoPRRUCoM5cf5q26uD3hPglfnc,1297 -apscheduler/schedulers/tornado.py,sha256=D9Vaq3Ee9EFiXa1jDy9tedI048gR_YT_LAFUWqO_uEw,1926 -apscheduler/schedulers/twisted.py,sha256=D5EBjjMRtMBxy0_aAURcULAI8Ky2IvCTr9tK9sO1rYk,1844 -apscheduler/triggers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -apscheduler/triggers/__pycache__/__init__.cpython-38.pyc,, -apscheduler/triggers/__pycache__/base.cpython-38.pyc,, -apscheduler/triggers/__pycache__/combining.cpython-38.pyc,, -apscheduler/triggers/__pycache__/date.cpython-38.pyc,, -apscheduler/triggers/__pycache__/interval.cpython-38.pyc,, -apscheduler/triggers/base.py,sha256=WMo5f2g14fjO5VzpIxFQtk47Z9VEUDDPSxjoPL9FGSQ,1837 -apscheduler/triggers/combining.py,sha256=WTEnaEkBHysF1009sCvBaQa99hiy9l5Oz-hHyjy3jv8,3473 -apscheduler/triggers/cron/__init__.py,sha256=a8ASzvM7ci-djOI2jIL2XErL6zEx4Wr1012aD1XJw_w,9246 -apscheduler/triggers/cron/__pycache__/__init__.cpython-38.pyc,, -apscheduler/triggers/cron/__pycache__/expressions.cpython-38.pyc,, -apscheduler/triggers/cron/__pycache__/fields.cpython-38.pyc,, -apscheduler/triggers/cron/expressions.py,sha256=hu1kq0mKvivIw7U0D0Nnrbuk3q01dCuhZ7SHRPw6qhI,9184 -apscheduler/triggers/cron/fields.py,sha256=NWPClh1NgSOpTlJ3sm1TXM_ViC2qJGKWkd_vg0xsw7o,3510 -apscheduler/triggers/date.py,sha256=RrfB1PNO9G9e91p1BOf-y_TseVHQQR-KJPhNdPpAHcU,1705 -apscheduler/triggers/interval.py,sha256=LiIunGOd96yaiAceG1XGP8eY3JxSyHDWCipVhQWMzDU,4381 -apscheduler/util.py,sha256=bQLVYP-RHtjypxol40a_JPT1Ta9BYSlTNdsDTc7dNMU,13963 diff --git a/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/WHEEL b/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/WHEEL deleted file mode 100644 index 8b701e9..0000000 --- a/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/WHEEL +++ /dev/null @@ -1,6 +0,0 @@ -Wheel-Version: 1.0 -Generator: bdist_wheel (0.33.6) -Root-Is-Purelib: true -Tag: py2-none-any -Tag: py3-none-any - diff --git a/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/entry_points.txt b/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/entry_points.txt deleted file mode 100644 index d2bd62b..0000000 --- a/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/entry_points.txt +++ /dev/null @@ -1,24 +0,0 @@ -[apscheduler.executors] -asyncio = apscheduler.executors.asyncio:AsyncIOExecutor [asyncio] -debug = apscheduler.executors.debug:DebugExecutor -gevent = apscheduler.executors.gevent:GeventExecutor [gevent] -processpool = apscheduler.executors.pool:ProcessPoolExecutor -threadpool = apscheduler.executors.pool:ThreadPoolExecutor -tornado = apscheduler.executors.tornado:TornadoExecutor [tornado] -twisted = apscheduler.executors.twisted:TwistedExecutor [twisted] - -[apscheduler.jobstores] -memory = apscheduler.jobstores.memory:MemoryJobStore -mongodb = apscheduler.jobstores.mongodb:MongoDBJobStore [mongodb] -redis = apscheduler.jobstores.redis:RedisJobStore [redis] -rethinkdb = apscheduler.jobstores.rethinkdb:RethinkDBJobStore [rethinkdb] -sqlalchemy = apscheduler.jobstores.sqlalchemy:SQLAlchemyJobStore [sqlalchemy] -zookeeper = apscheduler.jobstores.zookeeper:ZooKeeperJobStore [zookeeper] - -[apscheduler.triggers] -and = apscheduler.triggers.combining:AndTrigger -cron = apscheduler.triggers.cron:CronTrigger -date = apscheduler.triggers.date:DateTrigger -interval = apscheduler.triggers.interval:IntervalTrigger -or = apscheduler.triggers.combining:OrTrigger - diff --git a/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/top_level.txt b/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/top_level.txt deleted file mode 100644 index d31d10d..0000000 --- a/venv/lib/python3.8/site-packages/APScheduler-3.6.3.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -apscheduler diff --git a/venv/lib/python3.8/site-packages/apscheduler/__init__.py b/venv/lib/python3.8/site-packages/apscheduler/__init__.py deleted file mode 100644 index 968169a..0000000 --- a/venv/lib/python3.8/site-packages/apscheduler/__init__.py +++ /dev/null @@ -1,10 +0,0 @@ -from pkg_resources import get_distribution, DistributionNotFound - -try: - release = get_distribution('APScheduler').version.split('-')[0] -except DistributionNotFound: - release = '3.5.0' - -version_info = tuple(int(x) if x.isdigit() else x for x in release.split('.')) -version = __version__ = '.'.join(str(x) for x in version_info[:3]) -del get_distribution, DistributionNotFound diff --git a/venv/lib/python3.8/site-packages/apscheduler/events.py b/venv/lib/python3.8/site-packages/apscheduler/events.py deleted file mode 100644 index 016da03..0000000 --- a/venv/lib/python3.8/site-packages/apscheduler/events.py +++ /dev/null @@ -1,94 +0,0 @@ -__all__ = ('EVENT_SCHEDULER_STARTED', 'EVENT_SCHEDULER_SHUTDOWN', 'EVENT_SCHEDULER_PAUSED', - 'EVENT_SCHEDULER_RESUMED', 'EVENT_EXECUTOR_ADDED', 'EVENT_EXECUTOR_REMOVED', - 'EVENT_JOBSTORE_ADDED', 'EVENT_JOBSTORE_REMOVED', 'EVENT_ALL_JOBS_REMOVED', - 'EVENT_JOB_ADDED', 'EVENT_JOB_REMOVED', 'EVENT_JOB_MODIFIED', 'EVENT_JOB_EXECUTED', - 'EVENT_JOB_ERROR', 'EVENT_JOB_MISSED', 'EVENT_JOB_SUBMITTED', 'EVENT_JOB_MAX_INSTANCES', - 'SchedulerEvent', 'JobEvent', 'JobExecutionEvent', 'JobSubmissionEvent') - - -EVENT_SCHEDULER_STARTED = EVENT_SCHEDULER_START = 2 ** 0 -EVENT_SCHEDULER_SHUTDOWN = 2 ** 1 -EVENT_SCHEDULER_PAUSED = 2 ** 2 -EVENT_SCHEDULER_RESUMED = 2 ** 3 -EVENT_EXECUTOR_ADDED = 2 ** 4 -EVENT_EXECUTOR_REMOVED = 2 ** 5 -EVENT_JOBSTORE_ADDED = 2 ** 6 -EVENT_JOBSTORE_REMOVED = 2 ** 7 -EVENT_ALL_JOBS_REMOVED = 2 ** 8 -EVENT_JOB_ADDED = 2 ** 9 -EVENT_JOB_REMOVED = 2 ** 10 -EVENT_JOB_MODIFIED = 2 ** 11 -EVENT_JOB_EXECUTED = 2 ** 12 -EVENT_JOB_ERROR = 2 ** 13 -EVENT_JOB_MISSED = 2 ** 14 -EVENT_JOB_SUBMITTED = 2 ** 15 -EVENT_JOB_MAX_INSTANCES = 2 ** 16 -EVENT_ALL = (EVENT_SCHEDULER_STARTED | EVENT_SCHEDULER_SHUTDOWN | EVENT_SCHEDULER_PAUSED | - EVENT_SCHEDULER_RESUMED | EVENT_EXECUTOR_ADDED | EVENT_EXECUTOR_REMOVED | - EVENT_JOBSTORE_ADDED | EVENT_JOBSTORE_REMOVED | EVENT_ALL_JOBS_REMOVED | - EVENT_JOB_ADDED | EVENT_JOB_REMOVED | EVENT_JOB_MODIFIED | EVENT_JOB_EXECUTED | - EVENT_JOB_ERROR | EVENT_JOB_MISSED | EVENT_JOB_SUBMITTED | EVENT_JOB_MAX_INSTANCES) - - -class SchedulerEvent(object): - """ - An event that concerns the scheduler itself. - - :ivar code: the type code of this event - :ivar alias: alias of the job store or executor that was added or removed (if applicable) - """ - - def __init__(self, code, alias=None): - super(SchedulerEvent, self).__init__() - self.code = code - self.alias = alias - - def __repr__(self): - return '<%s (code=%d)>' % (self.__class__.__name__, self.code) - - -class JobEvent(SchedulerEvent): - """ - An event that concerns a job. - - :ivar code: the type code of this event - :ivar job_id: identifier of the job in question - :ivar jobstore: alias of the job store containing the job in question - """ - - def __init__(self, code, job_id, jobstore): - super(JobEvent, self).__init__(code) - self.code = code - self.job_id = job_id - self.jobstore = jobstore - - -class JobSubmissionEvent(JobEvent): - """ - An event that concerns the submission of a job to its executor. - - :ivar scheduled_run_times: a list of datetimes when the job was intended to run - """ - - def __init__(self, code, job_id, jobstore, scheduled_run_times): - super(JobSubmissionEvent, self).__init__(code, job_id, jobstore) - self.scheduled_run_times = scheduled_run_times - - -class JobExecutionEvent(JobEvent): - """ - An event that concerns the running of a job within its executor. - - :ivar scheduled_run_time: the time when the job was scheduled to be run - :ivar retval: the return value of the successfully executed job - :ivar exception: the exception raised by the job - :ivar traceback: a formatted traceback for the exception - """ - - def __init__(self, code, job_id, jobstore, scheduled_run_time, retval=None, exception=None, - traceback=None): - super(JobExecutionEvent, self).__init__(code, job_id, jobstore) - self.scheduled_run_time = scheduled_run_time - self.retval = retval - self.exception = exception - self.traceback = traceback diff --git a/venv/lib/python3.8/site-packages/apscheduler/executors/__init__.py b/venv/lib/python3.8/site-packages/apscheduler/executors/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.8/site-packages/apscheduler/executors/asyncio.py b/venv/lib/python3.8/site-packages/apscheduler/executors/asyncio.py deleted file mode 100644 index 06fc7f9..0000000 --- a/venv/lib/python3.8/site-packages/apscheduler/executors/asyncio.py +++ /dev/null @@ -1,59 +0,0 @@ -from __future__ import absolute_import - -import sys - -from apscheduler.executors.base import BaseExecutor, run_job -from apscheduler.util import iscoroutinefunction_partial - -try: - from apscheduler.executors.base_py3 import run_coroutine_job -except ImportError: - run_coroutine_job = None - - -class AsyncIOExecutor(BaseExecutor): - """ - Runs jobs in the default executor of the event loop. - - If the job function is a native coroutine function, it is scheduled to be run directly in the - event loop as soon as possible. All other functions are run in the event loop's default - executor which is usually a thread pool. - - Plugin alias: ``asyncio`` - """ - - def start(self, scheduler, alias): - super(AsyncIOExecutor, self).start(scheduler, alias) - self._eventloop = scheduler._eventloop - self._pending_futures = set() - - def shutdown(self, wait=True): - # There is no way to honor wait=True without converting this method into a coroutine method - for f in self._pending_futures: - if not f.done(): - f.cancel() - - self._pending_futures.clear() - - def _do_submit_job(self, job, run_times): - def callback(f): - self._pending_futures.discard(f) - try: - events = f.result() - except BaseException: - self._run_job_error(job.id, *sys.exc_info()[1:]) - else: - self._run_job_success(job.id, events) - - if iscoroutinefunction_partial(job.func): - if run_coroutine_job is not None: - coro = run_coroutine_job(job, job._jobstore_alias, run_times, self._logger.name) - f = self._eventloop.create_task(coro) - else: - raise Exception('Executing coroutine based jobs is not supported with Trollius') - else: - f = self._eventloop.run_in_executor(None, run_job, job, job._jobstore_alias, run_times, - self._logger.name) - - f.add_done_callback(callback) - self._pending_futures.add(f) diff --git a/venv/lib/python3.8/site-packages/apscheduler/executors/base.py b/venv/lib/python3.8/site-packages/apscheduler/executors/base.py deleted file mode 100644 index 4c09fc1..0000000 --- a/venv/lib/python3.8/site-packages/apscheduler/executors/base.py +++ /dev/null @@ -1,146 +0,0 @@ -from abc import ABCMeta, abstractmethod -from collections import defaultdict -from datetime import datetime, timedelta -from traceback import format_tb -import logging -import sys - -from pytz import utc -import six - -from apscheduler.events import ( - JobExecutionEvent, EVENT_JOB_MISSED, EVENT_JOB_ERROR, EVENT_JOB_EXECUTED) - - -class MaxInstancesReachedError(Exception): - def __init__(self, job): - super(MaxInstancesReachedError, self).__init__( - 'Job "%s" has already reached its maximum number of instances (%d)' % - (job.id, job.max_instances)) - - -class BaseExecutor(six.with_metaclass(ABCMeta, object)): - """Abstract base class that defines the interface that every executor must implement.""" - - _scheduler = None - _lock = None - _logger = logging.getLogger('apscheduler.executors') - - def __init__(self): - super(BaseExecutor, self).__init__() - self._instances = defaultdict(lambda: 0) - - def start(self, scheduler, alias): - """ - Called by the scheduler when the scheduler is being started or when the executor is being - added to an already running scheduler. - - :param apscheduler.schedulers.base.BaseScheduler scheduler: the scheduler that is starting - this executor - :param str|unicode alias: alias of this executor as it was assigned to the scheduler - - """ - self._scheduler = scheduler - self._lock = scheduler._create_lock() - self._logger = logging.getLogger('apscheduler.executors.%s' % alias) - - def shutdown(self, wait=True): - """ - Shuts down this executor. - - :param bool wait: ``True`` to wait until all submitted jobs - have been executed - """ - - def submit_job(self, job, run_times): - """ - Submits job for execution. - - :param Job job: job to execute - :param list[datetime] run_times: list of datetimes specifying - when the job should have been run - :raises MaxInstancesReachedError: if the maximum number of - allowed instances for this job has been reached - - """ - assert self._lock is not None, 'This executor has not been started yet' - with self._lock: - if self._instances[job.id] >= job.max_instances: - raise MaxInstancesReachedError(job) - - self._do_submit_job(job, run_times) - self._instances[job.id] += 1 - - @abstractmethod - def _do_submit_job(self, job, run_times): - """Performs the actual task of scheduling `run_job` to be called.""" - - def _run_job_success(self, job_id, events): - """ - Called by the executor with the list of generated events when :func:`run_job` has been - successfully called. - - """ - with self._lock: - self._instances[job_id] -= 1 - if self._instances[job_id] == 0: - del self._instances[job_id] - - for event in events: - self._scheduler._dispatch_event(event) - - def _run_job_error(self, job_id, exc, traceback=None): - """Called by the executor with the exception if there is an error calling `run_job`.""" - with self._lock: - self._instances[job_id] -= 1 - if self._instances[job_id] == 0: - del self._instances[job_id] - - exc_info = (exc.__class__, exc, traceback) - self._logger.error('Error running job %s', job_id, exc_info=exc_info) - - -def run_job(job, jobstore_alias, run_times, logger_name): - """ - Called by executors to run the job. Returns a list of scheduler events to be dispatched by the - scheduler. - - """ - events = [] - logger = logging.getLogger(logger_name) - for run_time in run_times: - # See if the job missed its run time window, and handle - # possible misfires accordingly - if job.misfire_grace_time is not None: - difference = datetime.now(utc) - run_time - grace_time = timedelta(seconds=job.misfire_grace_time) - if difference > grace_time: - events.append(JobExecutionEvent(EVENT_JOB_MISSED, job.id, jobstore_alias, - run_time)) - logger.warning('Run time of job "%s" was missed by %s', job, difference) - continue - - logger.info('Running job "%s" (scheduled at %s)', job, run_time) - try: - retval = job.func(*job.args, **job.kwargs) - except BaseException: - exc, tb = sys.exc_info()[1:] - formatted_tb = ''.join(format_tb(tb)) - events.append(JobExecutionEvent(EVENT_JOB_ERROR, job.id, jobstore_alias, run_time, - exception=exc, traceback=formatted_tb)) - logger.exception('Job "%s" raised an exception', job) - - # This is to prevent cyclic references that would lead to memory leaks - if six.PY2: - sys.exc_clear() - del tb - else: - import traceback - traceback.clear_frames(tb) - del tb - else: - events.append(JobExecutionEvent(EVENT_JOB_EXECUTED, job.id, jobstore_alias, run_time, - retval=retval)) - logger.info('Job "%s" executed successfully', job) - - return events diff --git a/venv/lib/python3.8/site-packages/apscheduler/executors/base_py3.py b/venv/lib/python3.8/site-packages/apscheduler/executors/base_py3.py deleted file mode 100644 index 61abd84..0000000 --- a/venv/lib/python3.8/site-packages/apscheduler/executors/base_py3.py +++ /dev/null @@ -1,41 +0,0 @@ -import logging -import sys -from datetime import datetime, timedelta -from traceback import format_tb - -from pytz import utc - -from apscheduler.events import ( - JobExecutionEvent, EVENT_JOB_MISSED, EVENT_JOB_ERROR, EVENT_JOB_EXECUTED) - - -async def run_coroutine_job(job, jobstore_alias, run_times, logger_name): - """Coroutine version of run_job().""" - events = [] - logger = logging.getLogger(logger_name) - for run_time in run_times: - # See if the job missed its run time window, and handle possible misfires accordingly - if job.misfire_grace_time is not None: - difference = datetime.now(utc) - run_time - grace_time = timedelta(seconds=job.misfire_grace_time) - if difference > grace_time: - events.append(JobExecutionEvent(EVENT_JOB_MISSED, job.id, jobstore_alias, - run_time)) - logger.warning('Run time of job "%s" was missed by %s', job, difference) - continue - - logger.info('Running job "%s" (scheduled at %s)', job, run_time) - try: - retval = await job.func(*job.args, **job.kwargs) - except BaseException: - exc, tb = sys.exc_info()[1:] - formatted_tb = ''.join(format_tb(tb)) - events.append(JobExecutionEvent(EVENT_JOB_ERROR, job.id, jobstore_alias, run_time, - exception=exc, traceback=formatted_tb)) - logger.exception('Job "%s" raised an exception', job) - else: - events.append(JobExecutionEvent(EVENT_JOB_EXECUTED, job.id, jobstore_alias, run_time, - retval=retval)) - logger.info('Job "%s" executed successfully', job) - - return events diff --git a/venv/lib/python3.8/site-packages/apscheduler/executors/debug.py b/venv/lib/python3.8/site-packages/apscheduler/executors/debug.py deleted file mode 100644 index ac739ae..0000000 --- a/venv/lib/python3.8/site-packages/apscheduler/executors/debug.py +++ /dev/null @@ -1,20 +0,0 @@ -import sys - -from apscheduler.executors.base import BaseExecutor, run_job - - -class DebugExecutor(BaseExecutor): - """ - A special executor that executes the target callable directly instead of deferring it to a - thread or process. - - Plugin alias: ``debug`` - """ - - def _do_submit_job(self, job, run_times): - try: - events = run_job(job, job._jobstore_alias, run_times, self._logger.name) - except BaseException: - self._run_job_error(job.id, *sys.exc_info()[1:]) - else: - self._run_job_success(job.id, events) diff --git a/venv/lib/python3.8/site-packages/apscheduler/executors/gevent.py b/venv/lib/python3.8/site-packages/apscheduler/executors/gevent.py deleted file mode 100644 index 1235bb6..0000000 --- a/venv/lib/python3.8/site-packages/apscheduler/executors/gevent.py +++ /dev/null @@ -1,30 +0,0 @@ -from __future__ import absolute_import -import sys - -from apscheduler.executors.base import BaseExecutor, run_job - - -try: - import gevent -except ImportError: # pragma: nocover - raise ImportError('GeventExecutor requires gevent installed') - - -class GeventExecutor(BaseExecutor): - """ - Runs jobs as greenlets. - - Plugin alias: ``gevent`` - """ - - def _do_submit_job(self, job, run_times): - def callback(greenlet): - try: - events = greenlet.get() - except BaseException: - self._run_job_error(job.id, *sys.exc_info()[1:]) - else: - self._run_job_success(job.id, events) - - gevent.spawn(run_job, job, job._jobstore_alias, run_times, self._logger.name).\ - link(callback) diff --git a/venv/lib/python3.8/site-packages/apscheduler/executors/pool.py b/venv/lib/python3.8/site-packages/apscheduler/executors/pool.py deleted file mode 100644 index 2f4ef45..0000000 --- a/venv/lib/python3.8/site-packages/apscheduler/executors/pool.py +++ /dev/null @@ -1,54 +0,0 @@ -from abc import abstractmethod -import concurrent.futures - -from apscheduler.executors.base import BaseExecutor, run_job - - -class BasePoolExecutor(BaseExecutor): - @abstractmethod - def __init__(self, pool): - super(BasePoolExecutor, self).__init__() - self._pool = pool - - def _do_submit_job(self, job, run_times): - def callback(f): - exc, tb = (f.exception_info() if hasattr(f, 'exception_info') else - (f.exception(), getattr(f.exception(), '__traceback__', None))) - if exc: - self._run_job_error(job.id, exc, tb) - else: - self._run_job_success(job.id, f.result()) - - f = self._pool.submit(run_job, job, job._jobstore_alias, run_times, self._logger.name) - f.add_done_callback(callback) - - def shutdown(self, wait=True): - self._pool.shutdown(wait) - - -class ThreadPoolExecutor(BasePoolExecutor): - """ - An executor that runs jobs in a concurrent.futures thread pool. - - Plugin alias: ``threadpool`` - - :param max_workers: the maximum number of spawned threads. - """ - - def __init__(self, max_workers=10): - pool = concurrent.futures.ThreadPoolExecutor(int(max_workers)) - super(ThreadPoolExecutor, self).__init__(pool) - - -class ProcessPoolExecutor(BasePoolExecutor): - """ - An executor that runs jobs in a concurrent.futures process pool. - - Plugin alias: ``processpool`` - - :param max_workers: the maximum number of spawned processes. - """ - - def __init__(self, max_workers=10): - pool = concurrent.futures.ProcessPoolExecutor(int(max_workers)) - super(ProcessPoolExecutor, self).__init__(pool) diff --git a/venv/lib/python3.8/site-packages/apscheduler/executors/tornado.py b/venv/lib/python3.8/site-packages/apscheduler/executors/tornado.py deleted file mode 100644 index 3b97eec..0000000 --- a/venv/lib/python3.8/site-packages/apscheduler/executors/tornado.py +++ /dev/null @@ -1,54 +0,0 @@ -from __future__ import absolute_import - -import sys -from concurrent.futures import ThreadPoolExecutor - -from tornado.gen import convert_yielded - -from apscheduler.executors.base import BaseExecutor, run_job - -try: - from apscheduler.executors.base_py3 import run_coroutine_job - from apscheduler.util import iscoroutinefunction_partial -except ImportError: - def iscoroutinefunction_partial(func): - return False - - -class TornadoExecutor(BaseExecutor): - """ - Runs jobs either in a thread pool or directly on the I/O loop. - - If the job function is a native coroutine function, it is scheduled to be run directly in the - I/O loop as soon as possible. All other functions are run in a thread pool. - - Plugin alias: ``tornado`` - - :param int max_workers: maximum number of worker threads in the thread pool - """ - - def __init__(self, max_workers=10): - super(TornadoExecutor, self).__init__() - self.executor = ThreadPoolExecutor(max_workers) - - def start(self, scheduler, alias): - super(TornadoExecutor, self).start(scheduler, alias) - self._ioloop = scheduler._ioloop - - def _do_submit_job(self, job, run_times): - def callback(f): - try: - events = f.result() - except BaseException: - self._run_job_error(job.id, *sys.exc_info()[1:]) - else: - self._run_job_success(job.id, events) - - if iscoroutinefunction_partial(job.func): - f = run_coroutine_job(job, job._jobstore_alias, run_times, self._logger.name) - else: - f = self.executor.submit(run_job, job, job._jobstore_alias, run_times, - self._logger.name) - - f = convert_yielded(f) - f.add_done_callback(callback) diff --git a/venv/lib/python3.8/site-packages/apscheduler/executors/twisted.py b/venv/lib/python3.8/site-packages/apscheduler/executors/twisted.py deleted file mode 100644 index c7bcf64..0000000 --- a/venv/lib/python3.8/site-packages/apscheduler/executors/twisted.py +++ /dev/null @@ -1,25 +0,0 @@ -from __future__ import absolute_import - -from apscheduler.executors.base import BaseExecutor, run_job - - -class TwistedExecutor(BaseExecutor): - """ - Runs jobs in the reactor's thread pool. - - Plugin alias: ``twisted`` - """ - - def start(self, scheduler, alias): - super(TwistedExecutor, self).start(scheduler, alias) - self._reactor = scheduler._reactor - - def _do_submit_job(self, job, run_times): - def callback(success, result): - if success: - self._run_job_success(job.id, result) - else: - self._run_job_error(job.id, result.value, result.tb) - - self._reactor.getThreadPool().callInThreadWithCallback( - callback, run_job, job, job._jobstore_alias, run_times, self._logger.name) diff --git a/venv/lib/python3.8/site-packages/apscheduler/job.py b/venv/lib/python3.8/site-packages/apscheduler/job.py deleted file mode 100644 index d676ca8..0000000 --- a/venv/lib/python3.8/site-packages/apscheduler/job.py +++ /dev/null @@ -1,301 +0,0 @@ -from inspect import ismethod, isclass -from uuid import uuid4 - -import six - -from apscheduler.triggers.base import BaseTrigger -from apscheduler.util import ( - ref_to_obj, obj_to_ref, datetime_repr, repr_escape, get_callable_name, check_callable_args, - convert_to_datetime) - -try: - from collections.abc import Iterable, Mapping -except ImportError: - from collections import Iterable, Mapping - - -class Job(object): - """ - Contains the options given when scheduling callables and its current schedule and other state. - This class should never be instantiated by the user. - - :var str id: the unique identifier of this job - :var str name: the description of this job - :var func: the callable to execute - :var tuple|list args: positional arguments to the callable - :var dict kwargs: keyword arguments to the callable - :var bool coalesce: whether to only run the job once when several run times are due - :var trigger: the trigger object that controls the schedule of this job - :var str executor: the name of the executor that will run this job - :var int misfire_grace_time: the time (in seconds) how much this job's execution is allowed to - be late - :var int max_instances: the maximum number of concurrently executing instances allowed for this - job - :var datetime.datetime next_run_time: the next scheduled run time of this job - - .. note:: - The ``misfire_grace_time`` has some non-obvious effects on job execution. See the - :ref:`missed-job-executions` section in the documentation for an in-depth explanation. - """ - - __slots__ = ('_scheduler', '_jobstore_alias', 'id', 'trigger', 'executor', 'func', 'func_ref', - 'args', 'kwargs', 'name', 'misfire_grace_time', 'coalesce', 'max_instances', - 'next_run_time') - - def __init__(self, scheduler, id=None, **kwargs): - super(Job, self).__init__() - self._scheduler = scheduler - self._jobstore_alias = None - self._modify(id=id or uuid4().hex, **kwargs) - - def modify(self, **changes): - """ - Makes the given changes to this job and saves it in the associated job store. - - Accepted keyword arguments are the same as the variables on this class. - - .. seealso:: :meth:`~apscheduler.schedulers.base.BaseScheduler.modify_job` - - :return Job: this job instance - - """ - self._scheduler.modify_job(self.id, self._jobstore_alias, **changes) - return self - - def reschedule(self, trigger, **trigger_args): - """ - Shortcut for switching the trigger on this job. - - .. seealso:: :meth:`~apscheduler.schedulers.base.BaseScheduler.reschedule_job` - - :return Job: this job instance - - """ - self._scheduler.reschedule_job(self.id, self._jobstore_alias, trigger, **trigger_args) - return self - - def pause(self): - """ - Temporarily suspend the execution of this job. - - .. seealso:: :meth:`~apscheduler.schedulers.base.BaseScheduler.pause_job` - - :return Job: this job instance - - """ - self._scheduler.pause_job(self.id, self._jobstore_alias) - return self - - def resume(self): - """ - Resume the schedule of this job if previously paused. - - .. seealso:: :meth:`~apscheduler.schedulers.base.BaseScheduler.resume_job` - - :return Job: this job instance - - """ - self._scheduler.resume_job(self.id, self._jobstore_alias) - return self - - def remove(self): - """ - Unschedules this job and removes it from its associated job store. - - .. seealso:: :meth:`~apscheduler.schedulers.base.BaseScheduler.remove_job` - - """ - self._scheduler.remove_job(self.id, self._jobstore_alias) - - @property - def pending(self): - """ - Returns ``True`` if the referenced job is still waiting to be added to its designated job - store. - - """ - return self._jobstore_alias is None - - # - # Private API - # - - def _get_run_times(self, now): - """ - Computes the scheduled run times between ``next_run_time`` and ``now`` (inclusive). - - :type now: datetime.datetime - :rtype: list[datetime.datetime] - - """ - run_times = [] - next_run_time = self.next_run_time - while next_run_time and next_run_time <= now: - run_times.append(next_run_time) - next_run_time = self.trigger.get_next_fire_time(next_run_time, now) - - return run_times - - def _modify(self, **changes): - """ - Validates the changes to the Job and makes the modifications if and only if all of them - validate. - - """ - approved = {} - - if 'id' in changes: - value = changes.pop('id') - if not isinstance(value, six.string_types): - raise TypeError("id must be a nonempty string") - if hasattr(self, 'id'): - raise ValueError('The job ID may not be changed') - approved['id'] = value - - if 'func' in changes or 'args' in changes or 'kwargs' in changes: - func = changes.pop('func') if 'func' in changes else self.func - args = changes.pop('args') if 'args' in changes else self.args - kwargs = changes.pop('kwargs') if 'kwargs' in changes else self.kwargs - - if isinstance(func, six.string_types): - func_ref = func - func = ref_to_obj(func) - elif callable(func): - try: - func_ref = obj_to_ref(func) - except ValueError: - # If this happens, this Job won't be serializable - func_ref = None - else: - raise TypeError('func must be a callable or a textual reference to one') - - if not hasattr(self, 'name') and changes.get('name', None) is None: - changes['name'] = get_callable_name(func) - - if isinstance(args, six.string_types) or not isinstance(args, Iterable): - raise TypeError('args must be a non-string iterable') - if isinstance(kwargs, six.string_types) or not isinstance(kwargs, Mapping): - raise TypeError('kwargs must be a dict-like object') - - check_callable_args(func, args, kwargs) - - approved['func'] = func - approved['func_ref'] = func_ref - approved['args'] = args - approved['kwargs'] = kwargs - - if 'name' in changes: - value = changes.pop('name') - if not value or not isinstance(value, six.string_types): - raise TypeError("name must be a nonempty string") - approved['name'] = value - - if 'misfire_grace_time' in changes: - value = changes.pop('misfire_grace_time') - if value is not None and (not isinstance(value, six.integer_types) or value <= 0): - raise TypeError('misfire_grace_time must be either None or a positive integer') - approved['misfire_grace_time'] = value - - if 'coalesce' in changes: - value = bool(changes.pop('coalesce')) - approved['coalesce'] = value - - if 'max_instances' in changes: - value = changes.pop('max_instances') - if not isinstance(value, six.integer_types) or value <= 0: - raise TypeError('max_instances must be a positive integer') - approved['max_instances'] = value - - if 'trigger' in changes: - trigger = changes.pop('trigger') - if not isinstance(trigger, BaseTrigger): - raise TypeError('Expected a trigger instance, got %s instead' % - trigger.__class__.__name__) - - approved['trigger'] = trigger - - if 'executor' in changes: - value = changes.pop('executor') - if not isinstance(value, six.string_types): - raise TypeError('executor must be a string') - approved['executor'] = value - - if 'next_run_time' in changes: - value = changes.pop('next_run_time') - approved['next_run_time'] = convert_to_datetime(value, self._scheduler.timezone, - 'next_run_time') - - if changes: - raise AttributeError('The following are not modifiable attributes of Job: %s' % - ', '.join(changes)) - - for key, value in six.iteritems(approved): - setattr(self, key, value) - - def __getstate__(self): - # Don't allow this Job to be serialized if the function reference could not be determined - if not self.func_ref: - raise ValueError( - 'This Job cannot be serialized since the reference to its callable (%r) could not ' - 'be determined. Consider giving a textual reference (module:function name) ' - 'instead.' % (self.func,)) - - # Instance methods cannot survive serialization as-is, so store the "self" argument - # explicitly - if ismethod(self.func) and not isclass(self.func.__self__): - args = (self.func.__self__,) + tuple(self.args) - else: - args = self.args - - return { - 'version': 1, - 'id': self.id, - 'func': self.func_ref, - 'trigger': self.trigger, - 'executor': self.executor, - 'args': args, - 'kwargs': self.kwargs, - 'name': self.name, - 'misfire_grace_time': self.misfire_grace_time, - 'coalesce': self.coalesce, - 'max_instances': self.max_instances, - 'next_run_time': self.next_run_time - } - - def __setstate__(self, state): - if state.get('version', 1) > 1: - raise ValueError('Job has version %s, but only version 1 can be handled' % - state['version']) - - self.id = state['id'] - self.func_ref = state['func'] - self.func = ref_to_obj(self.func_ref) - self.trigger = state['trigger'] - self.executor = state['executor'] - self.args = state['args'] - self.kwargs = state['kwargs'] - self.name = state['name'] - self.misfire_grace_time = state['misfire_grace_time'] - self.coalesce = state['coalesce'] - self.max_instances = state['max_instances'] - self.next_run_time = state['next_run_time'] - - def __eq__(self, other): - if isinstance(other, Job): - return self.id == other.id - return NotImplemented - - def __repr__(self): - return '<Job (id=%s name=%s)>' % (repr_escape(self.id), repr_escape(self.name)) - - def __str__(self): - return repr_escape(self.__unicode__()) - - def __unicode__(self): - if hasattr(self, 'next_run_time'): - status = ('next run at: ' + datetime_repr(self.next_run_time) if - self.next_run_time else 'paused') - else: - status = 'pending' - - return u'%s (trigger: %s, %s)' % (self.name, self.trigger, status) diff --git a/venv/lib/python3.8/site-packages/apscheduler/jobstores/__init__.py b/venv/lib/python3.8/site-packages/apscheduler/jobstores/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.8/site-packages/apscheduler/jobstores/base.py b/venv/lib/python3.8/site-packages/apscheduler/jobstores/base.py deleted file mode 100644 index 9cff66c..0000000 --- a/venv/lib/python3.8/site-packages/apscheduler/jobstores/base.py +++ /dev/null @@ -1,143 +0,0 @@ -from abc import ABCMeta, abstractmethod -import logging - -import six - - -class JobLookupError(KeyError): - """Raised when the job store cannot find a job for update or removal.""" - - def __init__(self, job_id): - super(JobLookupError, self).__init__(u'No job by the id of %s was found' % job_id) - - -class ConflictingIdError(KeyError): - """Raised when the uniqueness of job IDs is being violated.""" - - def __init__(self, job_id): - super(ConflictingIdError, self).__init__( - u'Job identifier (%s) conflicts with an existing job' % job_id) - - -class TransientJobError(ValueError): - """ - Raised when an attempt to add transient (with no func_ref) job to a persistent job store is - detected. - """ - - def __init__(self, job_id): - super(TransientJobError, self).__init__( - u'Job (%s) cannot be added to this job store because a reference to the callable ' - u'could not be determined.' % job_id) - - -class BaseJobStore(six.with_metaclass(ABCMeta)): - """Abstract base class that defines the interface that every job store must implement.""" - - _scheduler = None - _alias = None - _logger = logging.getLogger('apscheduler.jobstores') - - def start(self, scheduler, alias): - """ - Called by the scheduler when the scheduler is being started or when the job store is being - added to an already running scheduler. - - :param apscheduler.schedulers.base.BaseScheduler scheduler: the scheduler that is starting - this job store - :param str|unicode alias: alias of this job store as it was assigned to the scheduler - """ - - self._scheduler = scheduler - self._alias = alias - self._logger = logging.getLogger('apscheduler.jobstores.%s' % alias) - - def shutdown(self): - """Frees any resources still bound to this job store.""" - - def _fix_paused_jobs_sorting(self, jobs): - for i, job in enumerate(jobs): - if job.next_run_time is not None: - if i > 0: - paused_jobs = jobs[:i] - del jobs[:i] - jobs.extend(paused_jobs) - break - - @abstractmethod - def lookup_job(self, job_id): - """ - Returns a specific job, or ``None`` if it isn't found.. - - The job store is responsible for setting the ``scheduler`` and ``jobstore`` attributes of - the returned job to point to the scheduler and itself, respectively. - - :param str|unicode job_id: identifier of the job - :rtype: Job - """ - - @abstractmethod - def get_due_jobs(self, now): - """ - Returns the list of jobs that have ``next_run_time`` earlier or equal to ``now``. - The returned jobs must be sorted by next run time (ascending). - - :param datetime.datetime now: the current (timezone aware) datetime - :rtype: list[Job] - """ - - @abstractmethod - def get_next_run_time(self): - """ - Returns the earliest run time of all the jobs stored in this job store, or ``None`` if - there are no active jobs. - - :rtype: datetime.datetime - """ - - @abstractmethod - def get_all_jobs(self): - """ - Returns a list of all jobs in this job store. - The returned jobs should be sorted by next run time (ascending). - Paused jobs (next_run_time == None) should be sorted last. - - The job store is responsible for setting the ``scheduler`` and ``jobstore`` attributes of - the returned jobs to point to the scheduler and itself, respectively. - - :rtype: list[Job] - """ - - @abstractmethod - def add_job(self, job): - """ - Adds the given job to this store. - - :param Job job: the job to add - :raises ConflictingIdError: if there is another job in this store with the same ID - """ - - @abstractmethod - def update_job(self, job): - """ - Replaces the job in the store with the given newer version. - - :param Job job: the job to update - :raises JobLookupError: if the job does not exist - """ - - @abstractmethod - def remove_job(self, job_id): - """ - Removes the given job from this store. - - :param str|unicode job_id: identifier of the job - :raises JobLookupError: if the job does not exist - """ - - @abstractmethod - def remove_all_jobs(self): - """Removes all jobs from this store.""" - - def __repr__(self): - return '<%s>' % self.__class__.__name__ diff --git a/venv/lib/python3.8/site-packages/apscheduler/jobstores/memory.py b/venv/lib/python3.8/site-packages/apscheduler/jobstores/memory.py deleted file mode 100644 index abfe7c6..0000000 --- a/venv/lib/python3.8/site-packages/apscheduler/jobstores/memory.py +++ /dev/null @@ -1,108 +0,0 @@ -from __future__ import absolute_import - -from apscheduler.jobstores.base import BaseJobStore, JobLookupError, ConflictingIdError -from apscheduler.util import datetime_to_utc_timestamp - - -class MemoryJobStore(BaseJobStore): - """ - Stores jobs in an array in RAM. Provides no persistence support. - - Plugin alias: ``memory`` - """ - - def __init__(self): - super(MemoryJobStore, self).__init__() - # list of (job, timestamp), sorted by next_run_time and job id (ascending) - self._jobs = [] - self._jobs_index = {} # id -> (job, timestamp) lookup table - - def lookup_job(self, job_id): - return self._jobs_index.get(job_id, (None, None))[0] - - def get_due_jobs(self, now): - now_timestamp = datetime_to_utc_timestamp(now) - pending = [] - for job, timestamp in self._jobs: - if timestamp is None or timestamp > now_timestamp: - break - pending.append(job) - - return pending - - def get_next_run_time(self): - return self._jobs[0][0].next_run_time if self._jobs else None - - def get_all_jobs(self): - return [j[0] for j in self._jobs] - - def add_job(self, job): - if job.id in self._jobs_index: - raise ConflictingIdError(job.id) - - timestamp = datetime_to_utc_timestamp(job.next_run_time) - index = self._get_job_index(timestamp, job.id) - self._jobs.insert(index, (job, timestamp)) - self._jobs_index[job.id] = (job, timestamp) - - def update_job(self, job): - old_job, old_timestamp = self._jobs_index.get(job.id, (None, None)) - if old_job is None: - raise JobLookupError(job.id) - - # If the next run time has not changed, simply replace the job in its present index. - # Otherwise, reinsert the job to the list to preserve the ordering. - old_index = self._get_job_index(old_timestamp, old_job.id) - new_timestamp = datetime_to_utc_timestamp(job.next_run_time) - if old_timestamp == new_timestamp: - self._jobs[old_index] = (job, new_timestamp) - else: - del self._jobs[old_index] - new_index = self._get_job_index(new_timestamp, job.id) - self._jobs.insert(new_index, (job, new_timestamp)) - - self._jobs_index[old_job.id] = (job, new_timestamp) - - def remove_job(self, job_id): - job, timestamp = self._jobs_index.get(job_id, (None, None)) - if job is None: - raise JobLookupError(job_id) - - index = self._get_job_index(timestamp, job_id) - del self._jobs[index] - del self._jobs_index[job.id] - - def remove_all_jobs(self): - self._jobs = [] - self._jobs_index = {} - - def shutdown(self): - self.remove_all_jobs() - - def _get_job_index(self, timestamp, job_id): - """ - Returns the index of the given job, or if it's not found, the index where the job should be - inserted based on the given timestamp. - - :type timestamp: int - :type job_id: str - - """ - lo, hi = 0, len(self._jobs) - timestamp = float('inf') if timestamp is None else timestamp - while lo < hi: - mid = (lo + hi) // 2 - mid_job, mid_timestamp = self._jobs[mid] - mid_timestamp = float('inf') if mid_timestamp is None else mid_timestamp - if mid_timestamp > timestamp: - hi = mid - elif mid_timestamp < timestamp: - lo = mid + 1 - elif mid_job.id > job_id: - hi = mid - elif mid_job.id < job_id: - lo = mid + 1 - else: - return mid - - return lo diff --git a/venv/lib/python3.8/site-packages/apscheduler/jobstores/mongodb.py b/venv/lib/python3.8/site-packages/apscheduler/jobstores/mongodb.py deleted file mode 100644 index 7dbc3b1..0000000 --- a/venv/lib/python3.8/site-packages/apscheduler/jobstores/mongodb.py +++ /dev/null @@ -1,141 +0,0 @@ -from __future__ import absolute_import -import warnings - -from apscheduler.jobstores.base import BaseJobStore, JobLookupError, ConflictingIdError -from apscheduler.util import maybe_ref, datetime_to_utc_timestamp, utc_timestamp_to_datetime -from apscheduler.job import Job - -try: - import cPickle as pickle -except ImportError: # pragma: nocover - import pickle - -try: - from bson.binary import Binary - from pymongo.errors import DuplicateKeyError - from pymongo import MongoClient, ASCENDING -except ImportError: # pragma: nocover - raise ImportError('MongoDBJobStore requires PyMongo installed') - - -class MongoDBJobStore(BaseJobStore): - """ - Stores jobs in a MongoDB database. Any leftover keyword arguments are directly passed to - pymongo's `MongoClient - <http://api.mongodb.org/python/current/api/pymongo/mongo_client.html#pymongo.mongo_client.MongoClient>`_. - - Plugin alias: ``mongodb`` - - :param str database: database to store jobs in - :param str collection: collection to store jobs in - :param client: a :class:`~pymongo.mongo_client.MongoClient` instance to use instead of - providing connection arguments - :param int pickle_protocol: pickle protocol level to use (for serialization), defaults to the - highest available - """ - - def __init__(self, database='apscheduler', collection='jobs', client=None, - pickle_protocol=pickle.HIGHEST_PROTOCOL, **connect_args): - super(MongoDBJobStore, self).__init__() - self.pickle_protocol = pickle_protocol - - if not database: - raise ValueError('The "database" parameter must not be empty') - if not collection: - raise ValueError('The "collection" parameter must not be empty') - - if client: - self.client = maybe_ref(client) - else: - connect_args.setdefault('w', 1) - self.client = MongoClient(**connect_args) - - self.collection = self.client[database][collection] - - def start(self, scheduler, alias): - super(MongoDBJobStore, self).start(scheduler, alias) - self.collection.ensure_index('next_run_time', sparse=True) - - @property - def connection(self): - warnings.warn('The "connection" member is deprecated -- use "client" instead', - DeprecationWarning) - return self.client - - def lookup_job(self, job_id): - document = self.collection.find_one(job_id, ['job_state']) - return self._reconstitute_job(document['job_state']) if document else None - - def get_due_jobs(self, now): - timestamp = datetime_to_utc_timestamp(now) - return self._get_jobs({'next_run_time': {'$lte': timestamp}}) - - def get_next_run_time(self): - document = self.collection.find_one({'next_run_time': {'$ne': None}}, - projection=['next_run_time'], - sort=[('next_run_time', ASCENDING)]) - return utc_timestamp_to_datetime(document['next_run_time']) if document else None - - def get_all_jobs(self): - jobs = self._get_jobs({}) - self._fix_paused_jobs_sorting(jobs) - return jobs - - def add_job(self, job): - try: - self.collection.insert({ - '_id': job.id, - 'next_run_time': datetime_to_utc_timestamp(job.next_run_time), - 'job_state': Binary(pickle.dumps(job.__getstate__(), self.pickle_protocol)) - }) - except DuplicateKeyError: - raise ConflictingIdError(job.id) - - def update_job(self, job): - changes = { - 'next_run_time': datetime_to_utc_timestamp(job.next_run_time), - 'job_state': Binary(pickle.dumps(job.__getstate__(), self.pickle_protocol)) - } - result = self.collection.update({'_id': job.id}, {'$set': changes}) - if result and result['n'] == 0: - raise JobLookupError(job.id) - - def remove_job(self, job_id): - result = self.collection.remove(job_id) - if result and result['n'] == 0: - raise JobLookupError(job_id) - - def remove_all_jobs(self): - self.collection.remove() - - def shutdown(self): - self.client.close() - - def _reconstitute_job(self, job_state): - job_state = pickle.loads(job_state) - job = Job.__new__(Job) - job.__setstate__(job_state) - job._scheduler = self._scheduler - job._jobstore_alias = self._alias - return job - - def _get_jobs(self, conditions): - jobs = [] - failed_job_ids = [] - for document in self.collection.find(conditions, ['_id', 'job_state'], - sort=[('next_run_time', ASCENDING)]): - try: - jobs.append(self._reconstitute_job(document['job_state'])) - except BaseException: - self._logger.exception('Unable to restore job "%s" -- removing it', - document['_id']) - failed_job_ids.append(document['_id']) - - # Remove all the jobs we failed to restore - if failed_job_ids: - self.collection.remove({'_id': {'$in': failed_job_ids}}) - - return jobs - - def __repr__(self): - return '<%s (client=%s)>' % (self.__class__.__name__, self.client) diff --git a/venv/lib/python3.8/site-packages/apscheduler/jobstores/redis.py b/venv/lib/python3.8/site-packages/apscheduler/jobstores/redis.py deleted file mode 100644 index 5bb69d6..0000000 --- a/venv/lib/python3.8/site-packages/apscheduler/jobstores/redis.py +++ /dev/null @@ -1,150 +0,0 @@ -from __future__ import absolute_import -from datetime import datetime - -from pytz import utc -import six - -from apscheduler.jobstores.base import BaseJobStore, JobLookupError, ConflictingIdError -from apscheduler.util import datetime_to_utc_timestamp, utc_timestamp_to_datetime -from apscheduler.job import Job - -try: - import cPickle as pickle -except ImportError: # pragma: nocover - import pickle - -try: - from redis import Redis -except ImportError: # pragma: nocover - raise ImportError('RedisJobStore requires redis installed') - - -class RedisJobStore(BaseJobStore): - """ - Stores jobs in a Redis database. Any leftover keyword arguments are directly passed to redis's - :class:`~redis.StrictRedis`. - - Plugin alias: ``redis`` - - :param int db: the database number to store jobs in - :param str jobs_key: key to store jobs in - :param str run_times_key: key to store the jobs' run times in - :param int pickle_protocol: pickle protocol level to use (for serialization), defaults to the - highest available - """ - - def __init__(self, db=0, jobs_key='apscheduler.jobs', run_times_key='apscheduler.run_times', - pickle_protocol=pickle.HIGHEST_PROTOCOL, **connect_args): - super(RedisJobStore, self).__init__() - - if db is None: - raise ValueError('The "db" parameter must not be empty') - if not jobs_key: - raise ValueError('The "jobs_key" parameter must not be empty') - if not run_times_key: - raise ValueError('The "run_times_key" parameter must not be empty') - - self.pickle_protocol = pickle_protocol - self.jobs_key = jobs_key - self.run_times_key = run_times_key - self.redis = Redis(db=int(db), **connect_args) - - def lookup_job(self, job_id): - job_state = self.redis.hget(self.jobs_key, job_id) - return self._reconstitute_job(job_state) if job_state else None - - def get_due_jobs(self, now): - timestamp = datetime_to_utc_timestamp(now) - job_ids = self.redis.zrangebyscore(self.run_times_key, 0, timestamp) - if job_ids: - job_states = self.redis.hmget(self.jobs_key, *job_ids) - return self._reconstitute_jobs(six.moves.zip(job_ids, job_states)) - return [] - - def get_next_run_time(self): - next_run_time = self.redis.zrange(self.run_times_key, 0, 0, withscores=True) - if next_run_time: - return utc_timestamp_to_datetime(next_run_time[0][1]) - - def get_all_jobs(self): - job_states = self.redis.hgetall(self.jobs_key) - jobs = self._reconstitute_jobs(six.iteritems(job_states)) - paused_sort_key = datetime(9999, 12, 31, tzinfo=utc) - return sorted(jobs, key=lambda job: job.next_run_time or paused_sort_key) - - def add_job(self, job): - if self.redis.hexists(self.jobs_key, job.id): - raise ConflictingIdError(job.id) - - with self.redis.pipeline() as pipe: - pipe.multi() - pipe.hset(self.jobs_key, job.id, pickle.dumps(job.__getstate__(), - self.pickle_protocol)) - if job.next_run_time: - pipe.zadd(self.run_times_key, - {job.id: datetime_to_utc_timestamp(job.next_run_time)}) - - pipe.execute() - - def update_job(self, job): - if not self.redis.hexists(self.jobs_key, job.id): - raise JobLookupError(job.id) - - with self.redis.pipeline() as pipe: - pipe.hset(self.jobs_key, job.id, pickle.dumps(job.__getstate__(), - self.pickle_protocol)) - if job.next_run_time: - pipe.zadd(self.run_times_key, - {job.id: datetime_to_utc_timestamp(job.next_run_time)}) - else: - pipe.zrem(self.run_times_key, job.id) - - pipe.execute() - - def remove_job(self, job_id): - if not self.redis.hexists(self.jobs_key, job_id): - raise JobLookupError(job_id) - - with self.redis.pipeline() as pipe: - pipe.hdel(self.jobs_key, job_id) - pipe.zrem(self.run_times_key, job_id) - pipe.execute() - - def remove_all_jobs(self): - with self.redis.pipeline() as pipe: - pipe.delete(self.jobs_key) - pipe.delete(self.run_times_key) - pipe.execute() - - def shutdown(self): - self.redis.connection_pool.disconnect() - - def _reconstitute_job(self, job_state): - job_state = pickle.loads(job_state) - job = Job.__new__(Job) - job.__setstate__(job_state) - job._scheduler = self._scheduler - job._jobstore_alias = self._alias - return job - - def _reconstitute_jobs(self, job_states): - jobs = [] - failed_job_ids = [] - for job_id, job_state in job_states: - try: - jobs.append(self._reconstitute_job(job_state)) - except BaseException: - self._logger.exception('Unable to restore job "%s" -- removing it', job_id) - failed_job_ids.append(job_id) - - # Remove all the jobs we failed to restore - if failed_job_ids: - with self.redis.pipeline() as pipe: - pipe.hdel(self.jobs_key, *failed_job_ids) - pipe.zrem(self.run_times_key, *failed_job_ids) - pipe.execute() - - return jobs - - def __repr__(self): - return '<%s>' % self.__class__.__name__ diff --git a/venv/lib/python3.8/site-packages/apscheduler/jobstores/rethinkdb.py b/venv/lib/python3.8/site-packages/apscheduler/jobstores/rethinkdb.py deleted file mode 100644 index d8a78cd..0000000 --- a/venv/lib/python3.8/site-packages/apscheduler/jobstores/rethinkdb.py +++ /dev/null @@ -1,155 +0,0 @@ -from __future__ import absolute_import - -from apscheduler.jobstores.base import BaseJobStore, JobLookupError, ConflictingIdError -from apscheduler.util import maybe_ref, datetime_to_utc_timestamp, utc_timestamp_to_datetime -from apscheduler.job import Job - -try: - import cPickle as pickle -except ImportError: # pragma: nocover - import pickle - -try: - from rethinkdb import RethinkDB -except ImportError: # pragma: nocover - raise ImportError('RethinkDBJobStore requires rethinkdb installed') - - -class RethinkDBJobStore(BaseJobStore): - """ - Stores jobs in a RethinkDB database. Any leftover keyword arguments are directly passed to - rethinkdb's `RethinkdbClient <http://www.rethinkdb.com/api/#connect>`_. - - Plugin alias: ``rethinkdb`` - - :param str database: database to store jobs in - :param str collection: collection to store jobs in - :param client: a :class:`rethinkdb.net.Connection` instance to use instead of providing - connection arguments - :param int pickle_protocol: pickle protocol level to use (for serialization), defaults to the - highest available - """ - - def __init__(self, database='apscheduler', table='jobs', client=None, - pickle_protocol=pickle.HIGHEST_PROTOCOL, **connect_args): - super(RethinkDBJobStore, self).__init__() - - if not database: - raise ValueError('The "database" parameter must not be empty') - if not table: - raise ValueError('The "table" parameter must not be empty') - - self.database = database - self.table_name = table - self.table = None - self.client = client - self.pickle_protocol = pickle_protocol - self.connect_args = connect_args - self.r = RethinkDB() - self.conn = None - - def start(self, scheduler, alias): - super(RethinkDBJobStore, self).start(scheduler, alias) - - if self.client: - self.conn = maybe_ref(self.client) - else: - self.conn = self.r.connect(db=self.database, **self.connect_args) - - if self.database not in self.r.db_list().run(self.conn): - self.r.db_create(self.database).run(self.conn) - - if self.table_name not in self.r.table_list().run(self.conn): - self.r.table_create(self.table_name).run(self.conn) - - if 'next_run_time' not in self.r.table(self.table_name).index_list().run(self.conn): - self.r.table(self.table_name).index_create('next_run_time').run(self.conn) - - self.table = self.r.db(self.database).table(self.table_name) - - def lookup_job(self, job_id): - results = list(self.table.get_all(job_id).pluck('job_state').run(self.conn)) - return self._reconstitute_job(results[0]['job_state']) if results else None - - def get_due_jobs(self, now): - return self._get_jobs(self.r.row['next_run_time'] <= datetime_to_utc_timestamp(now)) - - def get_next_run_time(self): - results = list( - self.table - .filter(self.r.row['next_run_time'] != None) # noqa - .order_by(self.r.asc('next_run_time')) - .map(lambda x: x['next_run_time']) - .limit(1) - .run(self.conn) - ) - return utc_timestamp_to_datetime(results[0]) if results else None - - def get_all_jobs(self): - jobs = self._get_jobs() - self._fix_paused_jobs_sorting(jobs) - return jobs - - def add_job(self, job): - job_dict = { - 'id': job.id, - 'next_run_time': datetime_to_utc_timestamp(job.next_run_time), - 'job_state': self.r.binary(pickle.dumps(job.__getstate__(), self.pickle_protocol)) - } - results = self.table.insert(job_dict).run(self.conn) - if results['errors'] > 0: - raise ConflictingIdError(job.id) - - def update_job(self, job): - changes = { - 'next_run_time': datetime_to_utc_timestamp(job.next_run_time), - 'job_state': self.r.binary(pickle.dumps(job.__getstate__(), self.pickle_protocol)) - } - results = self.table.get_all(job.id).update(changes).run(self.conn) - skipped = False in map(lambda x: results[x] == 0, results.keys()) - if results['skipped'] > 0 or results['errors'] > 0 or not skipped: - raise JobLookupError(job.id) - - def remove_job(self, job_id): - results = self.table.get_all(job_id).delete().run(self.conn) - if results['deleted'] + results['skipped'] != 1: - raise JobLookupError(job_id) - - def remove_all_jobs(self): - self.table.delete().run(self.conn) - - def shutdown(self): - self.conn.close() - - def _reconstitute_job(self, job_state): - job_state = pickle.loads(job_state) - job = Job.__new__(Job) - job.__setstate__(job_state) - job._scheduler = self._scheduler - job._jobstore_alias = self._alias - return job - - def _get_jobs(self, predicate=None): - jobs = [] - failed_job_ids = [] - query = (self.table.filter(self.r.row['next_run_time'] != None).filter(predicate) # noqa - if predicate else self.table) - query = query.order_by('next_run_time', 'id').pluck('id', 'job_state') - - for document in query.run(self.conn): - try: - jobs.append(self._reconstitute_job(document['job_state'])) - except Exception: - self._logger.exception('Unable to restore job "%s" -- removing it', document['id']) - failed_job_ids.append(document['id']) - - # Remove all the jobs we failed to restore - if failed_job_ids: - self.r.expr(failed_job_ids).for_each( - lambda job_id: self.table.get_all(job_id).delete()).run(self.conn) - - return jobs - - def __repr__(self): - connection = self.conn - return '<%s (connection=%s)>' % (self.__class__.__name__, connection) diff --git a/venv/lib/python3.8/site-packages/apscheduler/jobstores/sqlalchemy.py b/venv/lib/python3.8/site-packages/apscheduler/jobstores/sqlalchemy.py deleted file mode 100644 index fecbd83..0000000 --- a/venv/lib/python3.8/site-packages/apscheduler/jobstores/sqlalchemy.py +++ /dev/null @@ -1,154 +0,0 @@ -from __future__ import absolute_import - -from apscheduler.jobstores.base import BaseJobStore, JobLookupError, ConflictingIdError -from apscheduler.util import maybe_ref, datetime_to_utc_timestamp, utc_timestamp_to_datetime -from apscheduler.job import Job - -try: - import cPickle as pickle -except ImportError: # pragma: nocover - import pickle - -try: - from sqlalchemy import ( - create_engine, Table, Column, MetaData, Unicode, Float, LargeBinary, select) - from sqlalchemy.exc import IntegrityError - from sqlalchemy.sql.expression import null -except ImportError: # pragma: nocover - raise ImportError('SQLAlchemyJobStore requires SQLAlchemy installed') - - -class SQLAlchemyJobStore(BaseJobStore): - """ - Stores jobs in a database table using SQLAlchemy. - The table will be created if it doesn't exist in the database. - - Plugin alias: ``sqlalchemy`` - - :param str url: connection string (see - :ref:`SQLAlchemy documentation <sqlalchemy:database_urls>` on this) - :param engine: an SQLAlchemy :class:`~sqlalchemy.engine.Engine` to use instead of creating a - new one based on ``url`` - :param str tablename: name of the table to store jobs in - :param metadata: a :class:`~sqlalchemy.schema.MetaData` instance to use instead of creating a - new one - :param int pickle_protocol: pickle protocol level to use (for serialization), defaults to the - highest available - :param str tableschema: name of the (existing) schema in the target database where the table - should be - :param dict engine_options: keyword arguments to :func:`~sqlalchemy.create_engine` - (ignored if ``engine`` is given) - """ - - def __init__(self, url=None, engine=None, tablename='apscheduler_jobs', metadata=None, - pickle_protocol=pickle.HIGHEST_PROTOCOL, tableschema=None, engine_options=None): - super(SQLAlchemyJobStore, self).__init__() - self.pickle_protocol = pickle_protocol - metadata = maybe_ref(metadata) or MetaData() - - if engine: - self.engine = maybe_ref(engine) - elif url: - self.engine = create_engine(url, **(engine_options or {})) - else: - raise ValueError('Need either "engine" or "url" defined') - - # 191 = max key length in MySQL for InnoDB/utf8mb4 tables, - # 25 = precision that translates to an 8-byte float - self.jobs_t = Table( - tablename, metadata, - Column('id', Unicode(191, _warn_on_bytestring=False), primary_key=True), - Column('next_run_time', Float(25), index=True), - Column('job_state', LargeBinary, nullable=False), - schema=tableschema - ) - - def start(self, scheduler, alias): - super(SQLAlchemyJobStore, self).start(scheduler, alias) - self.jobs_t.create(self.engine, True) - - def lookup_job(self, job_id): - selectable = select([self.jobs_t.c.job_state]).where(self.jobs_t.c.id == job_id) - job_state = self.engine.execute(selectable).scalar() - return self._reconstitute_job(job_state) if job_state else None - - def get_due_jobs(self, now): - timestamp = datetime_to_utc_timestamp(now) - return self._get_jobs(self.jobs_t.c.next_run_time <= timestamp) - - def get_next_run_time(self): - selectable = select([self.jobs_t.c.next_run_time]).\ - where(self.jobs_t.c.next_run_time != null()).\ - order_by(self.jobs_t.c.next_run_time).limit(1) - next_run_time = self.engine.execute(selectable).scalar() - return utc_timestamp_to_datetime(next_run_time) - - def get_all_jobs(self): - jobs = self._get_jobs() - self._fix_paused_jobs_sorting(jobs) - return jobs - - def add_job(self, job): - insert = self.jobs_t.insert().values(**{ - 'id': job.id, - 'next_run_time': datetime_to_utc_timestamp(job.next_run_time), - 'job_state': pickle.dumps(job.__getstate__(), self.pickle_protocol) - }) - try: - self.engine.execute(insert) - except IntegrityError: - raise ConflictingIdError(job.id) - - def update_job(self, job): - update = self.jobs_t.update().values(**{ - 'next_run_time': datetime_to_utc_timestamp(job.next_run_time), - 'job_state': pickle.dumps(job.__getstate__(), self.pickle_protocol) - }).where(self.jobs_t.c.id == job.id) - result = self.engine.execute(update) - if result.rowcount == 0: - raise JobLookupError(job.id) - - def remove_job(self, job_id): - delete = self.jobs_t.delete().where(self.jobs_t.c.id == job_id) - result = self.engine.execute(delete) - if result.rowcount == 0: - raise JobLookupError(job_id) - - def remove_all_jobs(self): - delete = self.jobs_t.delete() - self.engine.execute(delete) - - def shutdown(self): - self.engine.dispose() - - def _reconstitute_job(self, job_state): - job_state = pickle.loads(job_state) - job_state['jobstore'] = self - job = Job.__new__(Job) - job.__setstate__(job_state) - job._scheduler = self._scheduler - job._jobstore_alias = self._alias - return job - - def _get_jobs(self, *conditions): - jobs = [] - selectable = select([self.jobs_t.c.id, self.jobs_t.c.job_state]).\ - order_by(self.jobs_t.c.next_run_time) - selectable = selectable.where(*conditions) if conditions else selectable - failed_job_ids = set() - for row in self.engine.execute(selectable): - try: - jobs.append(self._reconstitute_job(row.job_state)) - except BaseException: - self._logger.exception('Unable to restore job "%s" -- removing it', row.id) - failed_job_ids.add(row.id) - - # Remove all the jobs we failed to restore - if failed_job_ids: - delete = self.jobs_t.delete().where(self.jobs_t.c.id.in_(failed_job_ids)) - self.engine.execute(delete) - - return jobs - - def __repr__(self): - return '<%s (url=%s)>' % (self.__class__.__name__, self.engine.url) diff --git a/venv/lib/python3.8/site-packages/apscheduler/jobstores/zookeeper.py b/venv/lib/python3.8/site-packages/apscheduler/jobstores/zookeeper.py deleted file mode 100644 index 2cca83e..0000000 --- a/venv/lib/python3.8/site-packages/apscheduler/jobstores/zookeeper.py +++ /dev/null @@ -1,179 +0,0 @@ -from __future__ import absolute_import - -import os -from datetime import datetime - -from pytz import utc -from kazoo.exceptions import NoNodeError, NodeExistsError - -from apscheduler.jobstores.base import BaseJobStore, JobLookupError, ConflictingIdError -from apscheduler.util import maybe_ref, datetime_to_utc_timestamp, utc_timestamp_to_datetime -from apscheduler.job import Job - -try: - import cPickle as pickle -except ImportError: # pragma: nocover - import pickle - -try: - from kazoo.client import KazooClient -except ImportError: # pragma: nocover - raise ImportError('ZooKeeperJobStore requires Kazoo installed') - - -class ZooKeeperJobStore(BaseJobStore): - """ - Stores jobs in a ZooKeeper tree. Any leftover keyword arguments are directly passed to - kazoo's `KazooClient - <http://kazoo.readthedocs.io/en/latest/api/client.html>`_. - - Plugin alias: ``zookeeper`` - - :param str path: path to store jobs in - :param client: a :class:`~kazoo.client.KazooClient` instance to use instead of - providing connection arguments - :param int pickle_protocol: pickle protocol level to use (for serialization), defaults to the - highest available - """ - - def __init__(self, path='/apscheduler', client=None, close_connection_on_exit=False, - pickle_protocol=pickle.HIGHEST_PROTOCOL, **connect_args): - super(ZooKeeperJobStore, self).__init__() - self.pickle_protocol = pickle_protocol - self.close_connection_on_exit = close_connection_on_exit - - if not path: - raise ValueError('The "path" parameter must not be empty') - - self.path = path - - if client: - self.client = maybe_ref(client) - else: - self.client = KazooClient(**connect_args) - self._ensured_path = False - - def _ensure_paths(self): - if not self._ensured_path: - self.client.ensure_path(self.path) - self._ensured_path = True - - def start(self, scheduler, alias): - super(ZooKeeperJobStore, self).start(scheduler, alias) - if not self.client.connected: - self.client.start() - - def lookup_job(self, job_id): - self._ensure_paths() - node_path = os.path.join(self.path, job_id) - try: - content, _ = self.client.get(node_path) - doc = pickle.loads(content) - job = self._reconstitute_job(doc['job_state']) - return job - except BaseException: - return None - - def get_due_jobs(self, now): - timestamp = datetime_to_utc_timestamp(now) - jobs = [job_def['job'] for job_def in self._get_jobs() - if job_def['next_run_time'] is not None and job_def['next_run_time'] <= timestamp] - return jobs - - def get_next_run_time(self): - next_runs = [job_def['next_run_time'] for job_def in self._get_jobs() - if job_def['next_run_time'] is not None] - return utc_timestamp_to_datetime(min(next_runs)) if len(next_runs) > 0 else None - - def get_all_jobs(self): - jobs = [job_def['job'] for job_def in self._get_jobs()] - self._fix_paused_jobs_sorting(jobs) - return jobs - - def add_job(self, job): - self._ensure_paths() - node_path = os.path.join(self.path, str(job.id)) - value = { - 'next_run_time': datetime_to_utc_timestamp(job.next_run_time), - 'job_state': job.__getstate__() - } - data = pickle.dumps(value, self.pickle_protocol) - try: - self.client.create(node_path, value=data) - except NodeExistsError: - raise ConflictingIdError(job.id) - - def update_job(self, job): - self._ensure_paths() - node_path = os.path.join(self.path, str(job.id)) - changes = { - 'next_run_time': datetime_to_utc_timestamp(job.next_run_time), - 'job_state': job.__getstate__() - } - data = pickle.dumps(changes, self.pickle_protocol) - try: - self.client.set(node_path, value=data) - except NoNodeError: - raise JobLookupError(job.id) - - def remove_job(self, job_id): - self._ensure_paths() - node_path = os.path.join(self.path, str(job_id)) - try: - self.client.delete(node_path) - except NoNodeError: - raise JobLookupError(job_id) - - def remove_all_jobs(self): - try: - self.client.delete(self.path, recursive=True) - except NoNodeError: - pass - self._ensured_path = False - - def shutdown(self): - if self.close_connection_on_exit: - self.client.stop() - self.client.close() - - def _reconstitute_job(self, job_state): - job_state = job_state - job = Job.__new__(Job) - job.__setstate__(job_state) - job._scheduler = self._scheduler - job._jobstore_alias = self._alias - return job - - def _get_jobs(self): - self._ensure_paths() - jobs = [] - failed_job_ids = [] - all_ids = self.client.get_children(self.path) - for node_name in all_ids: - try: - node_path = os.path.join(self.path, node_name) - content, _ = self.client.get(node_path) - doc = pickle.loads(content) - job_def = { - 'job_id': node_name, - 'next_run_time': doc['next_run_time'] if doc['next_run_time'] else None, - 'job_state': doc['job_state'], - 'job': self._reconstitute_job(doc['job_state']), - 'creation_time': _.ctime - } - jobs.append(job_def) - except BaseException: - self._logger.exception('Unable to restore job "%s" -- removing it' % node_name) - failed_job_ids.append(node_name) - - # Remove all the jobs we failed to restore - if failed_job_ids: - for failed_id in failed_job_ids: - self.remove_job(failed_id) - paused_sort_key = datetime(9999, 12, 31, tzinfo=utc) - return sorted(jobs, key=lambda job_def: (job_def['job'].next_run_time or paused_sort_key, - job_def['creation_time'])) - - def __repr__(self): - self._logger.exception('<%s (client=%s)>' % (self.__class__.__name__, self.client)) - return '<%s (client=%s)>' % (self.__class__.__name__, self.client) diff --git a/venv/lib/python3.8/site-packages/apscheduler/schedulers/__init__.py b/venv/lib/python3.8/site-packages/apscheduler/schedulers/__init__.py deleted file mode 100644 index bd8a790..0000000 --- a/venv/lib/python3.8/site-packages/apscheduler/schedulers/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -class SchedulerAlreadyRunningError(Exception): - """Raised when attempting to start or configure the scheduler when it's already running.""" - - def __str__(self): - return 'Scheduler is already running' - - -class SchedulerNotRunningError(Exception): - """Raised when attempting to shutdown the scheduler when it's not running.""" - - def __str__(self): - return 'Scheduler is not running' diff --git a/venv/lib/python3.8/site-packages/apscheduler/schedulers/asyncio.py b/venv/lib/python3.8/site-packages/apscheduler/schedulers/asyncio.py deleted file mode 100644 index 289ef13..0000000 --- a/venv/lib/python3.8/site-packages/apscheduler/schedulers/asyncio.py +++ /dev/null @@ -1,68 +0,0 @@ -from __future__ import absolute_import -from functools import wraps, partial - -from apscheduler.schedulers.base import BaseScheduler -from apscheduler.util import maybe_ref - -try: - import asyncio -except ImportError: # pragma: nocover - try: - import trollius as asyncio - except ImportError: - raise ImportError( - 'AsyncIOScheduler requires either Python 3.4 or the asyncio package installed') - - -def run_in_event_loop(func): - @wraps(func) - def wrapper(self, *args, **kwargs): - wrapped = partial(func, self, *args, **kwargs) - self._eventloop.call_soon_threadsafe(wrapped) - return wrapper - - -class AsyncIOScheduler(BaseScheduler): - """ - A scheduler that runs on an asyncio (:pep:`3156`) event loop. - - The default executor can run jobs based on native coroutines (``async def``). - - Extra options: - - ============== ============================================================= - ``event_loop`` AsyncIO event loop to use (defaults to the global event loop) - ============== ============================================================= - """ - - _eventloop = None - _timeout = None - - @run_in_event_loop - def shutdown(self, wait=True): - super(AsyncIOScheduler, self).shutdown(wait) - self._stop_timer() - - def _configure(self, config): - self._eventloop = maybe_ref(config.pop('event_loop', None)) or asyncio.get_event_loop() - super(AsyncIOScheduler, self)._configure(config) - - def _start_timer(self, wait_seconds): - self._stop_timer() - if wait_seconds is not None: - self._timeout = self._eventloop.call_later(wait_seconds, self.wakeup) - - def _stop_timer(self): - if self._timeout: - self._timeout.cancel() - del self._timeout - - @run_in_event_loop - def wakeup(self): - self._stop_timer() - wait_seconds = self._process_jobs() - self._start_timer(wait_seconds) - - def _create_default_executor(self): - from apscheduler.executors.asyncio import AsyncIOExecutor - return AsyncIOExecutor() diff --git a/venv/lib/python3.8/site-packages/apscheduler/schedulers/background.py b/venv/lib/python3.8/site-packages/apscheduler/schedulers/background.py deleted file mode 100644 index 03f2982..0000000 --- a/venv/lib/python3.8/site-packages/apscheduler/schedulers/background.py +++ /dev/null @@ -1,41 +0,0 @@ -from __future__ import absolute_import - -from threading import Thread, Event - -from apscheduler.schedulers.base import BaseScheduler -from apscheduler.schedulers.blocking import BlockingScheduler -from apscheduler.util import asbool - - -class BackgroundScheduler(BlockingScheduler): - """ - A scheduler that runs in the background using a separate thread - (:meth:`~apscheduler.schedulers.base.BaseScheduler.start` will return immediately). - - Extra options: - - ========== ============================================================================= - ``daemon`` Set the ``daemon`` option in the background thread (defaults to ``True``, see - `the documentation - <https://docs.python.org/3.4/library/threading.html#thread-objects>`_ - for further details) - ========== ============================================================================= - """ - - _thread = None - - def _configure(self, config): - self._daemon = asbool(config.pop('daemon', True)) - super(BackgroundScheduler, self)._configure(config) - - def start(self, *args, **kwargs): - self._event = Event() - BaseScheduler.start(self, *args, **kwargs) - self._thread = Thread(target=self._main_loop, name='APScheduler') - self._thread.daemon = self._daemon - self._thread.start() - - def shutdown(self, *args, **kwargs): - super(BackgroundScheduler, self).shutdown(*args, **kwargs) - self._thread.join() - del self._thread diff --git a/venv/lib/python3.8/site-packages/apscheduler/schedulers/base.py b/venv/lib/python3.8/site-packages/apscheduler/schedulers/base.py deleted file mode 100644 index 8e71154..0000000 --- a/venv/lib/python3.8/site-packages/apscheduler/schedulers/base.py +++ /dev/null @@ -1,1022 +0,0 @@ -from __future__ import print_function - -from abc import ABCMeta, abstractmethod -from threading import RLock -from datetime import datetime, timedelta -from logging import getLogger -import warnings -import sys - -from pkg_resources import iter_entry_points -from tzlocal import get_localzone -import six - -from apscheduler.schedulers import SchedulerAlreadyRunningError, SchedulerNotRunningError -from apscheduler.executors.base import MaxInstancesReachedError, BaseExecutor -from apscheduler.executors.pool import ThreadPoolExecutor -from apscheduler.jobstores.base import ConflictingIdError, JobLookupError, BaseJobStore -from apscheduler.jobstores.memory import MemoryJobStore -from apscheduler.job import Job -from apscheduler.triggers.base import BaseTrigger -from apscheduler.util import ( - asbool, asint, astimezone, maybe_ref, timedelta_seconds, undefined, TIMEOUT_MAX) -from apscheduler.events import ( - SchedulerEvent, JobEvent, JobSubmissionEvent, EVENT_SCHEDULER_START, EVENT_SCHEDULER_SHUTDOWN, - EVENT_JOBSTORE_ADDED, EVENT_JOBSTORE_REMOVED, EVENT_ALL, EVENT_JOB_MODIFIED, EVENT_JOB_REMOVED, - EVENT_JOB_ADDED, EVENT_EXECUTOR_ADDED, EVENT_EXECUTOR_REMOVED, EVENT_ALL_JOBS_REMOVED, - EVENT_JOB_SUBMITTED, EVENT_JOB_MAX_INSTANCES, EVENT_SCHEDULER_RESUMED, EVENT_SCHEDULER_PAUSED) - -try: - from collections.abc import MutableMapping -except ImportError: - from collections import MutableMapping - -#: constant indicating a scheduler's stopped state -STATE_STOPPED = 0 -#: constant indicating a scheduler's running state (started and processing jobs) -STATE_RUNNING = 1 -#: constant indicating a scheduler's paused state (started but not processing jobs) -STATE_PAUSED = 2 - - -class BaseScheduler(six.with_metaclass(ABCMeta)): - """ - Abstract base class for all schedulers. - - Takes the following keyword arguments: - - :param str|logging.Logger logger: logger to use for the scheduler's logging (defaults to - apscheduler.scheduler) - :param str|datetime.tzinfo timezone: the default time zone (defaults to the local timezone) - :param int|float jobstore_retry_interval: the minimum number of seconds to wait between - retries in the scheduler's main loop if the job store raises an exception when getting - the list of due jobs - :param dict job_defaults: default values for newly added jobs - :param dict jobstores: a dictionary of job store alias -> job store instance or configuration - dict - :param dict executors: a dictionary of executor alias -> executor instance or configuration - dict - - :ivar int state: current running state of the scheduler (one of the following constants from - ``apscheduler.schedulers.base``: ``STATE_STOPPED``, ``STATE_RUNNING``, ``STATE_PAUSED``) - - .. seealso:: :ref:`scheduler-config` - """ - - _trigger_plugins = dict((ep.name, ep) for ep in iter_entry_points('apscheduler.triggers')) - _trigger_classes = {} - _executor_plugins = dict((ep.name, ep) for ep in iter_entry_points('apscheduler.executors')) - _executor_classes = {} - _jobstore_plugins = dict((ep.name, ep) for ep in iter_entry_points('apscheduler.jobstores')) - _jobstore_classes = {} - - # - # Public API - # - - def __init__(self, gconfig={}, **options): - super(BaseScheduler, self).__init__() - self._executors = {} - self._executors_lock = self._create_lock() - self._jobstores = {} - self._jobstores_lock = self._create_lock() - self._listeners = [] - self._listeners_lock = self._create_lock() - self._pending_jobs = [] - self.state = STATE_STOPPED - self.configure(gconfig, **options) - - def configure(self, gconfig={}, prefix='apscheduler.', **options): - """ - Reconfigures the scheduler with the given options. - - Can only be done when the scheduler isn't running. - - :param dict gconfig: a "global" configuration dictionary whose values can be overridden by - keyword arguments to this method - :param str|unicode prefix: pick only those keys from ``gconfig`` that are prefixed with - this string (pass an empty string or ``None`` to use all keys) - :raises SchedulerAlreadyRunningError: if the scheduler is already running - - """ - if self.state != STATE_STOPPED: - raise SchedulerAlreadyRunningError - - # If a non-empty prefix was given, strip it from the keys in the - # global configuration dict - if prefix: - prefixlen = len(prefix) - gconfig = dict((key[prefixlen:], value) for key, value in six.iteritems(gconfig) - if key.startswith(prefix)) - - # Create a structure from the dotted options - # (e.g. "a.b.c = d" -> {'a': {'b': {'c': 'd'}}}) - config = {} - for key, value in six.iteritems(gconfig): - parts = key.split('.') - parent = config - key = parts.pop(0) - while parts: - parent = parent.setdefault(key, {}) - key = parts.pop(0) - parent[key] = value - - # Override any options with explicit keyword arguments - config.update(options) - self._configure(config) - - def start(self, paused=False): - """ - Start the configured executors and job stores and begin processing scheduled jobs. - - :param bool paused: if ``True``, don't start job processing until :meth:`resume` is called - :raises SchedulerAlreadyRunningError: if the scheduler is already running - :raises RuntimeError: if running under uWSGI with threads disabled - - """ - if self.state != STATE_STOPPED: - raise SchedulerAlreadyRunningError - - self._check_uwsgi() - - with self._executors_lock: - # Create a default executor if nothing else is configured - if 'default' not in self._executors: - self.add_executor(self._create_default_executor(), 'default') - - # Start all the executors - for alias, executor in six.iteritems(self._executors): - executor.start(self, alias) - - with self._jobstores_lock: - # Create a default job store if nothing else is configured - if 'default' not in self._jobstores: - self.add_jobstore(self._create_default_jobstore(), 'default') - - # Start all the job stores - for alias, store in six.iteritems(self._jobstores): - store.start(self, alias) - - # Schedule all pending jobs - for job, jobstore_alias, replace_existing in self._pending_jobs: - self._real_add_job(job, jobstore_alias, replace_existing) - del self._pending_jobs[:] - - self.state = STATE_PAUSED if paused else STATE_RUNNING - self._logger.info('Scheduler started') - self._dispatch_event(SchedulerEvent(EVENT_SCHEDULER_START)) - - if not paused: - self.wakeup() - - @abstractmethod - def shutdown(self, wait=True): - """ - Shuts down the scheduler, along with its executors and job stores. - - Does not interrupt any currently running jobs. - - :param bool wait: ``True`` to wait until all currently executing jobs have finished - :raises SchedulerNotRunningError: if the scheduler has not been started yet - - """ - if self.state == STATE_STOPPED: - raise SchedulerNotRunningError - - self.state = STATE_STOPPED - - # Shut down all executors - with self._executors_lock: - for executor in six.itervalues(self._executors): - executor.shutdown(wait) - - # Shut down all job stores - with self._jobstores_lock: - for jobstore in six.itervalues(self._jobstores): - jobstore.shutdown() - - self._logger.info('Scheduler has been shut down') - self._dispatch_event(SchedulerEvent(EVENT_SCHEDULER_SHUTDOWN)) - - def pause(self): - """ - Pause job processing in the scheduler. - - This will prevent the scheduler from waking up to do job processing until :meth:`resume` - is called. It will not however stop any already running job processing. - - """ - if self.state == STATE_STOPPED: - raise SchedulerNotRunningError - elif self.state == STATE_RUNNING: - self.state = STATE_PAUSED - self._logger.info('Paused scheduler job processing') - self._dispatch_event(SchedulerEvent(EVENT_SCHEDULER_PAUSED)) - - def resume(self): - """Resume job processing in the scheduler.""" - if self.state == STATE_STOPPED: - raise SchedulerNotRunningError - elif self.state == STATE_PAUSED: - self.state = STATE_RUNNING - self._logger.info('Resumed scheduler job processing') - self._dispatch_event(SchedulerEvent(EVENT_SCHEDULER_RESUMED)) - self.wakeup() - - @property - def running(self): - """ - Return ``True`` if the scheduler has been started. - - This is a shortcut for ``scheduler.state != STATE_STOPPED``. - - """ - return self.state != STATE_STOPPED - - def add_executor(self, executor, alias='default', **executor_opts): - """ - Adds an executor to this scheduler. - - Any extra keyword arguments will be passed to the executor plugin's constructor, assuming - that the first argument is the name of an executor plugin. - - :param str|unicode|apscheduler.executors.base.BaseExecutor executor: either an executor - instance or the name of an executor plugin - :param str|unicode alias: alias for the scheduler - :raises ValueError: if there is already an executor by the given alias - - """ - with self._executors_lock: - if alias in self._executors: - raise ValueError('This scheduler already has an executor by the alias of "%s"' % - alias) - - if isinstance(executor, BaseExecutor): - self._executors[alias] = executor - elif isinstance(executor, six.string_types): - self._executors[alias] = executor = self._create_plugin_instance( - 'executor', executor, executor_opts) - else: - raise TypeError('Expected an executor instance or a string, got %s instead' % - executor.__class__.__name__) - - # Start the executor right away if the scheduler is running - if self.state != STATE_STOPPED: - executor.start(self, alias) - - self._dispatch_event(SchedulerEvent(EVENT_EXECUTOR_ADDED, alias)) - - def remove_executor(self, alias, shutdown=True): - """ - Removes the executor by the given alias from this scheduler. - - :param str|unicode alias: alias of the executor - :param bool shutdown: ``True`` to shut down the executor after - removing it - - """ - with self._executors_lock: - executor = self._lookup_executor(alias) - del self._executors[alias] - - if shutdown: - executor.shutdown() - - self._dispatch_event(SchedulerEvent(EVENT_EXECUTOR_REMOVED, alias)) - - def add_jobstore(self, jobstore, alias='default', **jobstore_opts): - """ - Adds a job store to this scheduler. - - Any extra keyword arguments will be passed to the job store plugin's constructor, assuming - that the first argument is the name of a job store plugin. - - :param str|unicode|apscheduler.jobstores.base.BaseJobStore jobstore: job store to be added - :param str|unicode alias: alias for the job store - :raises ValueError: if there is already a job store by the given alias - - """ - with self._jobstores_lock: - if alias in self._jobstores: - raise ValueError('This scheduler already has a job store by the alias of "%s"' % - alias) - - if isinstance(jobstore, BaseJobStore): - self._jobstores[alias] = jobstore - elif isinstance(jobstore, six.string_types): - self._jobstores[alias] = jobstore = self._create_plugin_instance( - 'jobstore', jobstore, jobstore_opts) - else: - raise TypeError('Expected a job store instance or a string, got %s instead' % - jobstore.__class__.__name__) - - # Start the job store right away if the scheduler isn't stopped - if self.state != STATE_STOPPED: - jobstore.start(self, alias) - - # Notify listeners that a new job store has been added - self._dispatch_event(SchedulerEvent(EVENT_JOBSTORE_ADDED, alias)) - - # Notify the scheduler so it can scan the new job store for jobs - if self.state != STATE_STOPPED: - self.wakeup() - - def remove_jobstore(self, alias, shutdown=True): - """ - Removes the job store by the given alias from this scheduler. - - :param str|unicode alias: alias of the job store - :param bool shutdown: ``True`` to shut down the job store after removing it - - """ - with self._jobstores_lock: - jobstore = self._lookup_jobstore(alias) - del self._jobstores[alias] - - if shutdown: - jobstore.shutdown() - - self._dispatch_event(SchedulerEvent(EVENT_JOBSTORE_REMOVED, alias)) - - def add_listener(self, callback, mask=EVENT_ALL): - """ - add_listener(callback, mask=EVENT_ALL) - - Adds a listener for scheduler events. - - When a matching event occurs, ``callback`` is executed with the event object as its - sole argument. If the ``mask`` parameter is not provided, the callback will receive events - of all types. - - :param callback: any callable that takes one argument - :param int mask: bitmask that indicates which events should be - listened to - - .. seealso:: :mod:`apscheduler.events` - .. seealso:: :ref:`scheduler-events` - - """ - with self._listeners_lock: - self._listeners.append((callback, mask)) - - def remove_listener(self, callback): - """Removes a previously added event listener.""" - - with self._listeners_lock: - for i, (cb, _) in enumerate(self._listeners): - if callback == cb: - del self._listeners[i] - - def add_job(self, func, trigger=None, args=None, kwargs=None, id=None, name=None, - misfire_grace_time=undefined, coalesce=undefined, max_instances=undefined, - next_run_time=undefined, jobstore='default', executor='default', - replace_existing=False, **trigger_args): - """ - add_job(func, trigger=None, args=None, kwargs=None, id=None, \ - name=None, misfire_grace_time=undefined, coalesce=undefined, \ - max_instances=undefined, next_run_time=undefined, \ - jobstore='default', executor='default', \ - replace_existing=False, **trigger_args) - - Adds the given job to the job list and wakes up the scheduler if it's already running. - - Any option that defaults to ``undefined`` will be replaced with the corresponding default - value when the job is scheduled (which happens when the scheduler is started, or - immediately if the scheduler is already running). - - The ``func`` argument can be given either as a callable object or a textual reference in - the ``package.module:some.object`` format, where the first half (separated by ``:``) is an - importable module and the second half is a reference to the callable object, relative to - the module. - - The ``trigger`` argument can either be: - #. the alias name of the trigger (e.g. ``date``, ``interval`` or ``cron``), in which case - any extra keyword arguments to this method are passed on to the trigger's constructor - #. an instance of a trigger class - - :param func: callable (or a textual reference to one) to run at the given time - :param str|apscheduler.triggers.base.BaseTrigger trigger: trigger that determines when - ``func`` is called - :param list|tuple args: list of positional arguments to call func with - :param dict kwargs: dict of keyword arguments to call func with - :param str|unicode id: explicit identifier for the job (for modifying it later) - :param str|unicode name: textual description of the job - :param int misfire_grace_time: seconds after the designated runtime that the job is still - allowed to be run - :param bool coalesce: run once instead of many times if the scheduler determines that the - job should be run more than once in succession - :param int max_instances: maximum number of concurrently running instances allowed for this - job - :param datetime next_run_time: when to first run the job, regardless of the trigger (pass - ``None`` to add the job as paused) - :param str|unicode jobstore: alias of the job store to store the job in - :param str|unicode executor: alias of the executor to run the job with - :param bool replace_existing: ``True`` to replace an existing job with the same ``id`` - (but retain the number of runs from the existing one) - :rtype: Job - - """ - job_kwargs = { - 'trigger': self._create_trigger(trigger, trigger_args), - 'executor': executor, - 'func': func, - 'args': tuple(args) if args is not None else (), - 'kwargs': dict(kwargs) if kwargs is not None else {}, - 'id': id, - 'name': name, - 'misfire_grace_time': misfire_grace_time, - 'coalesce': coalesce, - 'max_instances': max_instances, - 'next_run_time': next_run_time - } - job_kwargs = dict((key, value) for key, value in six.iteritems(job_kwargs) if - value is not undefined) - job = Job(self, **job_kwargs) - - # Don't really add jobs to job stores before the scheduler is up and running - with self._jobstores_lock: - if self.state == STATE_STOPPED: - self._pending_jobs.append((job, jobstore, replace_existing)) - self._logger.info('Adding job tentatively -- it will be properly scheduled when ' - 'the scheduler starts') - else: - self._real_add_job(job, jobstore, replace_existing) - - return job - - def scheduled_job(self, trigger, args=None, kwargs=None, id=None, name=None, - misfire_grace_time=undefined, coalesce=undefined, max_instances=undefined, - next_run_time=undefined, jobstore='default', executor='default', - **trigger_args): - """ - scheduled_job(trigger, args=None, kwargs=None, id=None, \ - name=None, misfire_grace_time=undefined, \ - coalesce=undefined, max_instances=undefined, \ - next_run_time=undefined, jobstore='default', \ - executor='default',**trigger_args) - - A decorator version of :meth:`add_job`, except that ``replace_existing`` is always - ``True``. - - .. important:: The ``id`` argument must be given if scheduling a job in a persistent job - store. The scheduler cannot, however, enforce this requirement. - - """ - def inner(func): - self.add_job(func, trigger, args, kwargs, id, name, misfire_grace_time, coalesce, - max_instances, next_run_time, jobstore, executor, True, **trigger_args) - return func - return inner - - def modify_job(self, job_id, jobstore=None, **changes): - """ - Modifies the properties of a single job. - - Modifications are passed to this method as extra keyword arguments. - - :param str|unicode job_id: the identifier of the job - :param str|unicode jobstore: alias of the job store that contains the job - :return Job: the relevant job instance - - """ - with self._jobstores_lock: - job, jobstore = self._lookup_job(job_id, jobstore) - job._modify(**changes) - if jobstore: - self._lookup_jobstore(jobstore).update_job(job) - - self._dispatch_event(JobEvent(EVENT_JOB_MODIFIED, job_id, jobstore)) - - # Wake up the scheduler since the job's next run time may have been changed - if self.state == STATE_RUNNING: - self.wakeup() - - return job - - def reschedule_job(self, job_id, jobstore=None, trigger=None, **trigger_args): - """ - Constructs a new trigger for a job and updates its next run time. - - Extra keyword arguments are passed directly to the trigger's constructor. - - :param str|unicode job_id: the identifier of the job - :param str|unicode jobstore: alias of the job store that contains the job - :param trigger: alias of the trigger type or a trigger instance - :return Job: the relevant job instance - - """ - trigger = self._create_trigger(trigger, trigger_args) - now = datetime.now(self.timezone) - next_run_time = trigger.get_next_fire_time(None, now) - return self.modify_job(job_id, jobstore, trigger=trigger, next_run_time=next_run_time) - - def pause_job(self, job_id, jobstore=None): - """ - Causes the given job not to be executed until it is explicitly resumed. - - :param str|unicode job_id: the identifier of the job - :param str|unicode jobstore: alias of the job store that contains the job - :return Job: the relevant job instance - - """ - return self.modify_job(job_id, jobstore, next_run_time=None) - - def resume_job(self, job_id, jobstore=None): - """ - Resumes the schedule of the given job, or removes the job if its schedule is finished. - - :param str|unicode job_id: the identifier of the job - :param str|unicode jobstore: alias of the job store that contains the job - :return Job|None: the relevant job instance if the job was rescheduled, or ``None`` if no - next run time could be calculated and the job was removed - - """ - with self._jobstores_lock: - job, jobstore = self._lookup_job(job_id, jobstore) - now = datetime.now(self.timezone) - next_run_time = job.trigger.get_next_fire_time(None, now) - if next_run_time: - return self.modify_job(job_id, jobstore, next_run_time=next_run_time) - else: - self.remove_job(job.id, jobstore) - - def get_jobs(self, jobstore=None, pending=None): - """ - Returns a list of pending jobs (if the scheduler hasn't been started yet) and scheduled - jobs, either from a specific job store or from all of them. - - If the scheduler has not been started yet, only pending jobs can be returned because the - job stores haven't been started yet either. - - :param str|unicode jobstore: alias of the job store - :param bool pending: **DEPRECATED** - :rtype: list[Job] - - """ - if pending is not None: - warnings.warn('The "pending" option is deprecated -- get_jobs() always returns ' - 'scheduled jobs if the scheduler has been started and pending jobs ' - 'otherwise', DeprecationWarning) - - with self._jobstores_lock: - jobs = [] - if self.state == STATE_STOPPED: - for job, alias, replace_existing in self._pending_jobs: - if jobstore is None or alias == jobstore: - jobs.append(job) - else: - for alias, store in six.iteritems(self._jobstores): - if jobstore is None or alias == jobstore: - jobs.extend(store.get_all_jobs()) - - return jobs - - def get_job(self, job_id, jobstore=None): - """ - Returns the Job that matches the given ``job_id``. - - :param str|unicode job_id: the identifier of the job - :param str|unicode jobstore: alias of the job store that most likely contains the job - :return: the Job by the given ID, or ``None`` if it wasn't found - :rtype: Job - - """ - with self._jobstores_lock: - try: - return self._lookup_job(job_id, jobstore)[0] - except JobLookupError: - return - - def remove_job(self, job_id, jobstore=None): - """ - Removes a job, preventing it from being run any more. - - :param str|unicode job_id: the identifier of the job - :param str|unicode jobstore: alias of the job store that contains the job - :raises JobLookupError: if the job was not found - - """ - jobstore_alias = None - with self._jobstores_lock: - # Check if the job is among the pending jobs - if self.state == STATE_STOPPED: - for i, (job, alias, replace_existing) in enumerate(self._pending_jobs): - if job.id == job_id and jobstore in (None, alias): - del self._pending_jobs[i] - jobstore_alias = alias - break - else: - # Otherwise, try to remove it from each store until it succeeds or we run out of - # stores to check - for alias, store in six.iteritems(self._jobstores): - if jobstore in (None, alias): - try: - store.remove_job(job_id) - jobstore_alias = alias - break - except JobLookupError: - continue - - if jobstore_alias is None: - raise JobLookupError(job_id) - - # Notify listeners that a job has been removed - event = JobEvent(EVENT_JOB_REMOVED, job_id, jobstore_alias) - self._dispatch_event(event) - - self._logger.info('Removed job %s', job_id) - - def remove_all_jobs(self, jobstore=None): - """ - Removes all jobs from the specified job store, or all job stores if none is given. - - :param str|unicode jobstore: alias of the job store - - """ - with self._jobstores_lock: - if self.state == STATE_STOPPED: - if jobstore: - self._pending_jobs = [pending for pending in self._pending_jobs if - pending[1] != jobstore] - else: - self._pending_jobs = [] - else: - for alias, store in six.iteritems(self._jobstores): - if jobstore in (None, alias): - store.remove_all_jobs() - - self._dispatch_event(SchedulerEvent(EVENT_ALL_JOBS_REMOVED, jobstore)) - - def print_jobs(self, jobstore=None, out=None): - """ - print_jobs(jobstore=None, out=sys.stdout) - - Prints out a textual listing of all jobs currently scheduled on either all job stores or - just a specific one. - - :param str|unicode jobstore: alias of the job store, ``None`` to list jobs from all stores - :param file out: a file-like object to print to (defaults to **sys.stdout** if nothing is - given) - - """ - out = out or sys.stdout - with self._jobstores_lock: - if self.state == STATE_STOPPED: - print(u'Pending jobs:', file=out) - if self._pending_jobs: - for job, jobstore_alias, replace_existing in self._pending_jobs: - if jobstore in (None, jobstore_alias): - print(u' %s' % job, file=out) - else: - print(u' No pending jobs', file=out) - else: - for alias, store in sorted(six.iteritems(self._jobstores)): - if jobstore in (None, alias): - print(u'Jobstore %s:' % alias, file=out) - jobs = store.get_all_jobs() - if jobs: - for job in jobs: - print(u' %s' % job, file=out) - else: - print(u' No scheduled jobs', file=out) - - @abstractmethod - def wakeup(self): - """ - Notifies the scheduler that there may be jobs due for execution. - Triggers :meth:`_process_jobs` to be run in an implementation specific manner. - """ - - # - # Private API - # - - def _configure(self, config): - # Set general options - self._logger = maybe_ref(config.pop('logger', None)) or getLogger('apscheduler.scheduler') - self.timezone = astimezone(config.pop('timezone', None)) or get_localzone() - self.jobstore_retry_interval = float(config.pop('jobstore_retry_interval', 10)) - - # Set the job defaults - job_defaults = config.get('job_defaults', {}) - self._job_defaults = { - 'misfire_grace_time': asint(job_defaults.get('misfire_grace_time', 1)), - 'coalesce': asbool(job_defaults.get('coalesce', True)), - 'max_instances': asint(job_defaults.get('max_instances', 1)) - } - - # Configure executors - self._executors.clear() - for alias, value in six.iteritems(config.get('executors', {})): - if isinstance(value, BaseExecutor): - self.add_executor(value, alias) - elif isinstance(value, MutableMapping): - executor_class = value.pop('class', None) - plugin = value.pop('type', None) - if plugin: - executor = self._create_plugin_instance('executor', plugin, value) - elif executor_class: - cls = maybe_ref(executor_class) - executor = cls(**value) - else: - raise ValueError( - 'Cannot create executor "%s" -- either "type" or "class" must be defined' % - alias) - - self.add_executor(executor, alias) - else: - raise TypeError( - "Expected executor instance or dict for executors['%s'], got %s instead" % - (alias, value.__class__.__name__)) - - # Configure job stores - self._jobstores.clear() - for alias, value in six.iteritems(config.get('jobstores', {})): - if isinstance(value, BaseJobStore): - self.add_jobstore(value, alias) - elif isinstance(value, MutableMapping): - jobstore_class = value.pop('class', None) - plugin = value.pop('type', None) - if plugin: - jobstore = self._create_plugin_instance('jobstore', plugin, value) - elif jobstore_class: - cls = maybe_ref(jobstore_class) - jobstore = cls(**value) - else: - raise ValueError( - 'Cannot create job store "%s" -- either "type" or "class" must be ' - 'defined' % alias) - - self.add_jobstore(jobstore, alias) - else: - raise TypeError( - "Expected job store instance or dict for jobstores['%s'], got %s instead" % - (alias, value.__class__.__name__)) - - def _create_default_executor(self): - """Creates a default executor store, specific to the particular scheduler type.""" - return ThreadPoolExecutor() - - def _create_default_jobstore(self): - """Creates a default job store, specific to the particular scheduler type.""" - return MemoryJobStore() - - def _lookup_executor(self, alias): - """ - Returns the executor instance by the given name from the list of executors that were added - to this scheduler. - - :type alias: str - :raises KeyError: if no executor by the given alias is not found - - """ - try: - return self._executors[alias] - except KeyError: - raise KeyError('No such executor: %s' % alias) - - def _lookup_jobstore(self, alias): - """ - Returns the job store instance by the given name from the list of job stores that were - added to this scheduler. - - :type alias: str - :raises KeyError: if no job store by the given alias is not found - - """ - try: - return self._jobstores[alias] - except KeyError: - raise KeyError('No such job store: %s' % alias) - - def _lookup_job(self, job_id, jobstore_alias): - """ - Finds a job by its ID. - - :type job_id: str - :param str jobstore_alias: alias of a job store to look in - :return tuple[Job, str]: a tuple of job, jobstore alias (jobstore alias is None in case of - a pending job) - :raises JobLookupError: if no job by the given ID is found. - - """ - if self.state == STATE_STOPPED: - # Check if the job is among the pending jobs - for job, alias, replace_existing in self._pending_jobs: - if job.id == job_id: - return job, None - else: - # Look in all job stores - for alias, store in six.iteritems(self._jobstores): - if jobstore_alias in (None, alias): - job = store.lookup_job(job_id) - if job is not None: - return job, alias - - raise JobLookupError(job_id) - - def _dispatch_event(self, event): - """ - Dispatches the given event to interested listeners. - - :param SchedulerEvent event: the event to send - - """ - with self._listeners_lock: - listeners = tuple(self._listeners) - - for cb, mask in listeners: - if event.code & mask: - try: - cb(event) - except BaseException: - self._logger.exception('Error notifying listener') - - def _check_uwsgi(self): - """Check if we're running under uWSGI with threads disabled.""" - uwsgi_module = sys.modules.get('uwsgi') - if not getattr(uwsgi_module, 'has_threads', True): - raise RuntimeError('The scheduler seems to be running under uWSGI, but threads have ' - 'been disabled. You must run uWSGI with the --enable-threads ' - 'option for the scheduler to work.') - - def _real_add_job(self, job, jobstore_alias, replace_existing): - """ - :param Job job: the job to add - :param bool replace_existing: ``True`` to use update_job() in case the job already exists - in the store - - """ - # Fill in undefined values with defaults - replacements = {} - for key, value in six.iteritems(self._job_defaults): - if not hasattr(job, key): - replacements[key] = value - - # Calculate the next run time if there is none defined - if not hasattr(job, 'next_run_time'): - now = datetime.now(self.timezone) - replacements['next_run_time'] = job.trigger.get_next_fire_time(None, now) - - # Apply any replacements - job._modify(**replacements) - - # Add the job to the given job store - store = self._lookup_jobstore(jobstore_alias) - try: - store.add_job(job) - except ConflictingIdError: - if replace_existing: - store.update_job(job) - else: - raise - - # Mark the job as no longer pending - job._jobstore_alias = jobstore_alias - - # Notify listeners that a new job has been added - event = JobEvent(EVENT_JOB_ADDED, job.id, jobstore_alias) - self._dispatch_event(event) - - self._logger.info('Added job "%s" to job store "%s"', job.name, jobstore_alias) - - # Notify the scheduler about the new job - if self.state == STATE_RUNNING: - self.wakeup() - - def _create_plugin_instance(self, type_, alias, constructor_kwargs): - """Creates an instance of the given plugin type, loading the plugin first if necessary.""" - plugin_container, class_container, base_class = { - 'trigger': (self._trigger_plugins, self._trigger_classes, BaseTrigger), - 'jobstore': (self._jobstore_plugins, self._jobstore_classes, BaseJobStore), - 'executor': (self._executor_plugins, self._executor_classes, BaseExecutor) - }[type_] - - try: - plugin_cls = class_container[alias] - except KeyError: - if alias in plugin_container: - plugin_cls = class_container[alias] = plugin_container[alias].load() - if not issubclass(plugin_cls, base_class): - raise TypeError('The {0} entry point does not point to a {0} class'. - format(type_)) - else: - raise LookupError('No {0} by the name "{1}" was found'.format(type_, alias)) - - return plugin_cls(**constructor_kwargs) - - def _create_trigger(self, trigger, trigger_args): - if isinstance(trigger, BaseTrigger): - return trigger - elif trigger is None: - trigger = 'date' - elif not isinstance(trigger, six.string_types): - raise TypeError('Expected a trigger instance or string, got %s instead' % - trigger.__class__.__name__) - - # Use the scheduler's time zone if nothing else is specified - trigger_args.setdefault('timezone', self.timezone) - - # Instantiate the trigger class - return self._create_plugin_instance('trigger', trigger, trigger_args) - - def _create_lock(self): - """Creates a reentrant lock object.""" - return RLock() - - def _process_jobs(self): - """ - Iterates through jobs in every jobstore, starts jobs that are due and figures out how long - to wait for the next round. - - If the ``get_due_jobs()`` call raises an exception, a new wakeup is scheduled in at least - ``jobstore_retry_interval`` seconds. - - """ - if self.state == STATE_PAUSED: - self._logger.debug('Scheduler is paused -- not processing jobs') - return None - - self._logger.debug('Looking for jobs to run') - now = datetime.now(self.timezone) - next_wakeup_time = None - events = [] - - with self._jobstores_lock: - for jobstore_alias, jobstore in six.iteritems(self._jobstores): - try: - due_jobs = jobstore.get_due_jobs(now) - except Exception as e: - # Schedule a wakeup at least in jobstore_retry_interval seconds - self._logger.warning('Error getting due jobs from job store %r: %s', - jobstore_alias, e) - retry_wakeup_time = now + timedelta(seconds=self.jobstore_retry_interval) - if not next_wakeup_time or next_wakeup_time > retry_wakeup_time: - next_wakeup_time = retry_wakeup_time - - continue - - for job in due_jobs: - # Look up the job's executor - try: - executor = self._lookup_executor(job.executor) - except BaseException: - self._logger.error( - 'Executor lookup ("%s") failed for job "%s" -- removing it from the ' - 'job store', job.executor, job) - self.remove_job(job.id, jobstore_alias) - continue - - run_times = job._get_run_times(now) - run_times = run_times[-1:] if run_times and job.coalesce else run_times - if run_times: - try: - executor.submit_job(job, run_times) - except MaxInstancesReachedError: - self._logger.warning( - 'Execution of job "%s" skipped: maximum number of running ' - 'instances reached (%d)', job, job.max_instances) - event = JobSubmissionEvent(EVENT_JOB_MAX_INSTANCES, job.id, - jobstore_alias, run_times) - events.append(event) - except BaseException: - self._logger.exception('Error submitting job "%s" to executor "%s"', - job, job.executor) - else: - event = JobSubmissionEvent(EVENT_JOB_SUBMITTED, job.id, jobstore_alias, - run_times) - events.append(event) - - # Update the job if it has a next execution time. - # Otherwise remove it from the job store. - job_next_run = job.trigger.get_next_fire_time(run_times[-1], now) - if job_next_run: - job._modify(next_run_time=job_next_run) - jobstore.update_job(job) - else: - self.remove_job(job.id, jobstore_alias) - - # Set a new next wakeup time if there isn't one yet or - # the jobstore has an even earlier one - jobstore_next_run_time = jobstore.get_next_run_time() - if jobstore_next_run_time and (next_wakeup_time is None or - jobstore_next_run_time < next_wakeup_time): - next_wakeup_time = jobstore_next_run_time.astimezone(self.timezone) - - # Dispatch collected events - for event in events: - self._dispatch_event(event) - - # Determine the delay until this method should be called again - if self.state == STATE_PAUSED: - wait_seconds = None - self._logger.debug('Scheduler is paused; waiting until resume() is called') - elif next_wakeup_time is None: - wait_seconds = None - self._logger.debug('No jobs; waiting until a job is added') - else: - wait_seconds = min(max(timedelta_seconds(next_wakeup_time - now), 0), TIMEOUT_MAX) - self._logger.debug('Next wakeup is due at %s (in %f seconds)', next_wakeup_time, - wait_seconds) - - return wait_seconds diff --git a/venv/lib/python3.8/site-packages/apscheduler/schedulers/blocking.py b/venv/lib/python3.8/site-packages/apscheduler/schedulers/blocking.py deleted file mode 100644 index e617157..0000000 --- a/venv/lib/python3.8/site-packages/apscheduler/schedulers/blocking.py +++ /dev/null @@ -1,33 +0,0 @@ -from __future__ import absolute_import - -from threading import Event - -from apscheduler.schedulers.base import BaseScheduler, STATE_STOPPED -from apscheduler.util import TIMEOUT_MAX - - -class BlockingScheduler(BaseScheduler): - """ - A scheduler that runs in the foreground - (:meth:`~apscheduler.schedulers.base.BaseScheduler.start` will block). - """ - _event = None - - def start(self, *args, **kwargs): - self._event = Event() - super(BlockingScheduler, self).start(*args, **kwargs) - self._main_loop() - - def shutdown(self, wait=True): - super(BlockingScheduler, self).shutdown(wait) - self._event.set() - - def _main_loop(self): - wait_seconds = TIMEOUT_MAX - while self.state != STATE_STOPPED: - self._event.wait(wait_seconds) - self._event.clear() - wait_seconds = self._process_jobs() - - def wakeup(self): - self._event.set() diff --git a/venv/lib/python3.8/site-packages/apscheduler/schedulers/gevent.py b/venv/lib/python3.8/site-packages/apscheduler/schedulers/gevent.py deleted file mode 100644 index d48ed74..0000000 --- a/venv/lib/python3.8/site-packages/apscheduler/schedulers/gevent.py +++ /dev/null @@ -1,35 +0,0 @@ -from __future__ import absolute_import - -from apscheduler.schedulers.blocking import BlockingScheduler -from apscheduler.schedulers.base import BaseScheduler - -try: - from gevent.event import Event - from gevent.lock import RLock - import gevent -except ImportError: # pragma: nocover - raise ImportError('GeventScheduler requires gevent installed') - - -class GeventScheduler(BlockingScheduler): - """A scheduler that runs as a Gevent greenlet.""" - - _greenlet = None - - def start(self, *args, **kwargs): - self._event = Event() - BaseScheduler.start(self, *args, **kwargs) - self._greenlet = gevent.spawn(self._main_loop) - return self._greenlet - - def shutdown(self, *args, **kwargs): - super(GeventScheduler, self).shutdown(*args, **kwargs) - self._greenlet.join() - del self._greenlet - - def _create_lock(self): - return RLock() - - def _create_default_executor(self): - from apscheduler.executors.gevent import GeventExecutor - return GeventExecutor() diff --git a/venv/lib/python3.8/site-packages/apscheduler/schedulers/qt.py b/venv/lib/python3.8/site-packages/apscheduler/schedulers/qt.py deleted file mode 100644 index 0329a00..0000000 --- a/venv/lib/python3.8/site-packages/apscheduler/schedulers/qt.py +++ /dev/null @@ -1,43 +0,0 @@ -from __future__ import absolute_import - -from apscheduler.schedulers.base import BaseScheduler - -try: - from PyQt5.QtCore import QObject, QTimer -except (ImportError, RuntimeError): # pragma: nocover - try: - from PyQt4.QtCore import QObject, QTimer - except ImportError: - try: - from PySide.QtCore import QObject, QTimer # noqa - except ImportError: - raise ImportError('QtScheduler requires either PyQt5, PyQt4 or PySide installed') - - -class QtScheduler(BaseScheduler): - """A scheduler that runs in a Qt event loop.""" - - _timer = None - - def shutdown(self, *args, **kwargs): - super(QtScheduler, self).shutdown(*args, **kwargs) - self._stop_timer() - - def _start_timer(self, wait_seconds): - self._stop_timer() - if wait_seconds is not None: - wait_time = min(wait_seconds * 1000, 2147483647) - self._timer = QTimer.singleShot(wait_time, self._process_jobs) - - def _stop_timer(self): - if self._timer: - if self._timer.isActive(): - self._timer.stop() - del self._timer - - def wakeup(self): - self._start_timer(0) - - def _process_jobs(self): - wait_seconds = super(QtScheduler, self)._process_jobs() - self._start_timer(wait_seconds) diff --git a/venv/lib/python3.8/site-packages/apscheduler/schedulers/tornado.py b/venv/lib/python3.8/site-packages/apscheduler/schedulers/tornado.py deleted file mode 100644 index 0a9171f..0000000 --- a/venv/lib/python3.8/site-packages/apscheduler/schedulers/tornado.py +++ /dev/null @@ -1,63 +0,0 @@ -from __future__ import absolute_import - -from datetime import timedelta -from functools import wraps - -from apscheduler.schedulers.base import BaseScheduler -from apscheduler.util import maybe_ref - -try: - from tornado.ioloop import IOLoop -except ImportError: # pragma: nocover - raise ImportError('TornadoScheduler requires tornado installed') - - -def run_in_ioloop(func): - @wraps(func) - def wrapper(self, *args, **kwargs): - self._ioloop.add_callback(func, self, *args, **kwargs) - return wrapper - - -class TornadoScheduler(BaseScheduler): - """ - A scheduler that runs on a Tornado IOLoop. - - The default executor can run jobs based on native coroutines (``async def``). - - =========== =============================================================== - ``io_loop`` Tornado IOLoop instance to use (defaults to the global IO loop) - =========== =============================================================== - """ - - _ioloop = None - _timeout = None - - @run_in_ioloop - def shutdown(self, wait=True): - super(TornadoScheduler, self).shutdown(wait) - self._stop_timer() - - def _configure(self, config): - self._ioloop = maybe_ref(config.pop('io_loop', None)) or IOLoop.current() - super(TornadoScheduler, self)._configure(config) - - def _start_timer(self, wait_seconds): - self._stop_timer() - if wait_seconds is not None: - self._timeout = self._ioloop.add_timeout(timedelta(seconds=wait_seconds), self.wakeup) - - def _stop_timer(self): - if self._timeout: - self._ioloop.remove_timeout(self._timeout) - del self._timeout - - def _create_default_executor(self): - from apscheduler.executors.tornado import TornadoExecutor - return TornadoExecutor() - - @run_in_ioloop - def wakeup(self): - self._stop_timer() - wait_seconds = self._process_jobs() - self._start_timer(wait_seconds) diff --git a/venv/lib/python3.8/site-packages/apscheduler/schedulers/twisted.py b/venv/lib/python3.8/site-packages/apscheduler/schedulers/twisted.py deleted file mode 100644 index 6b43a84..0000000 --- a/venv/lib/python3.8/site-packages/apscheduler/schedulers/twisted.py +++ /dev/null @@ -1,62 +0,0 @@ -from __future__ import absolute_import - -from functools import wraps - -from apscheduler.schedulers.base import BaseScheduler -from apscheduler.util import maybe_ref - -try: - from twisted.internet import reactor as default_reactor -except ImportError: # pragma: nocover - raise ImportError('TwistedScheduler requires Twisted installed') - - -def run_in_reactor(func): - @wraps(func) - def wrapper(self, *args, **kwargs): - self._reactor.callFromThread(func, self, *args, **kwargs) - return wrapper - - -class TwistedScheduler(BaseScheduler): - """ - A scheduler that runs on a Twisted reactor. - - Extra options: - - =========== ======================================================== - ``reactor`` Reactor instance to use (defaults to the global reactor) - =========== ======================================================== - """ - - _reactor = None - _delayedcall = None - - def _configure(self, config): - self._reactor = maybe_ref(config.pop('reactor', default_reactor)) - super(TwistedScheduler, self)._configure(config) - - @run_in_reactor - def shutdown(self, wait=True): - super(TwistedScheduler, self).shutdown(wait) - self._stop_timer() - - def _start_timer(self, wait_seconds): - self._stop_timer() - if wait_seconds is not None: - self._delayedcall = self._reactor.callLater(wait_seconds, self.wakeup) - - def _stop_timer(self): - if self._delayedcall and self._delayedcall.active(): - self._delayedcall.cancel() - del self._delayedcall - - @run_in_reactor - def wakeup(self): - self._stop_timer() - wait_seconds = self._process_jobs() - self._start_timer(wait_seconds) - - def _create_default_executor(self): - from apscheduler.executors.twisted import TwistedExecutor - return TwistedExecutor() diff --git a/venv/lib/python3.8/site-packages/apscheduler/triggers/__init__.py b/venv/lib/python3.8/site-packages/apscheduler/triggers/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.8/site-packages/apscheduler/triggers/base.py b/venv/lib/python3.8/site-packages/apscheduler/triggers/base.py deleted file mode 100644 index ce2526a..0000000 --- a/venv/lib/python3.8/site-packages/apscheduler/triggers/base.py +++ /dev/null @@ -1,48 +0,0 @@ -from abc import ABCMeta, abstractmethod -from datetime import timedelta -import random - -import six - - -class BaseTrigger(six.with_metaclass(ABCMeta)): - """Abstract base class that defines the interface that every trigger must implement.""" - - __slots__ = () - - @abstractmethod - def get_next_fire_time(self, previous_fire_time, now): - """ - Returns the next datetime to fire on, If no such datetime can be calculated, returns - ``None``. - - :param datetime.datetime previous_fire_time: the previous time the trigger was fired - :param datetime.datetime now: current datetime - """ - - def _apply_jitter(self, next_fire_time, jitter, now): - """ - Randomize ``next_fire_time`` by adding or subtracting a random value (the jitter). If the - resulting datetime is in the past, returns the initial ``next_fire_time`` without jitter. - - ``next_fire_time - jitter <= result <= next_fire_time + jitter`` - - :param datetime.datetime|None next_fire_time: next fire time without jitter applied. If - ``None``, returns ``None``. - :param int|None jitter: maximum number of seconds to add or subtract to - ``next_fire_time``. If ``None`` or ``0``, returns ``next_fire_time`` - :param datetime.datetime now: current datetime - :return datetime.datetime|None: next fire time with a jitter. - """ - if next_fire_time is None or not jitter: - return next_fire_time - - next_fire_time_with_jitter = next_fire_time + timedelta( - seconds=random.uniform(-jitter, jitter)) - - if next_fire_time_with_jitter < now: - # Next fire time with jitter is in the past. - # Ignore jitter to avoid false misfire. - return next_fire_time - - return next_fire_time_with_jitter diff --git a/venv/lib/python3.8/site-packages/apscheduler/triggers/combining.py b/venv/lib/python3.8/site-packages/apscheduler/triggers/combining.py deleted file mode 100644 index 64f8301..0000000 --- a/venv/lib/python3.8/site-packages/apscheduler/triggers/combining.py +++ /dev/null @@ -1,95 +0,0 @@ -from apscheduler.triggers.base import BaseTrigger -from apscheduler.util import obj_to_ref, ref_to_obj - - -class BaseCombiningTrigger(BaseTrigger): - __slots__ = ('triggers', 'jitter') - - def __init__(self, triggers, jitter=None): - self.triggers = triggers - self.jitter = jitter - - def __getstate__(self): - return { - 'version': 1, - 'triggers': [(obj_to_ref(trigger.__class__), trigger.__getstate__()) - for trigger in self.triggers], - 'jitter': self.jitter - } - - def __setstate__(self, state): - if state.get('version', 1) > 1: - raise ValueError( - 'Got serialized data for version %s of %s, but only versions up to 1 can be ' - 'handled' % (state['version'], self.__class__.__name__)) - - self.jitter = state['jitter'] - self.triggers = [] - for clsref, state in state['triggers']: - cls = ref_to_obj(clsref) - trigger = cls.__new__(cls) - trigger.__setstate__(state) - self.triggers.append(trigger) - - def __repr__(self): - return '<{}({}{})>'.format(self.__class__.__name__, self.triggers, - ', jitter={}'.format(self.jitter) if self.jitter else '') - - -class AndTrigger(BaseCombiningTrigger): - """ - Always returns the earliest next fire time that all the given triggers can agree on. - The trigger is considered to be finished when any of the given triggers has finished its - schedule. - - Trigger alias: ``and`` - - :param list triggers: triggers to combine - :param int|None jitter: advance or delay the job execution by ``jitter`` seconds at most. - """ - - __slots__ = () - - def get_next_fire_time(self, previous_fire_time, now): - while True: - fire_times = [trigger.get_next_fire_time(previous_fire_time, now) - for trigger in self.triggers] - if None in fire_times: - return None - elif min(fire_times) == max(fire_times): - return self._apply_jitter(fire_times[0], self.jitter, now) - else: - now = max(fire_times) - - def __str__(self): - return 'and[{}]'.format(', '.join(str(trigger) for trigger in self.triggers)) - - -class OrTrigger(BaseCombiningTrigger): - """ - Always returns the earliest next fire time produced by any of the given triggers. - The trigger is considered finished when all the given triggers have finished their schedules. - - Trigger alias: ``or`` - - :param list triggers: triggers to combine - :param int|None jitter: advance or delay the job execution by ``jitter`` seconds at most. - - .. note:: Triggers that depends on the previous fire time, such as the interval trigger, may - seem to behave strangely since they are always passed the previous fire time produced by - any of the given triggers. - """ - - __slots__ = () - - def get_next_fire_time(self, previous_fire_time, now): - fire_times = [trigger.get_next_fire_time(previous_fire_time, now) - for trigger in self.triggers] - fire_times = [fire_time for fire_time in fire_times if fire_time is not None] - if fire_times: - return self._apply_jitter(min(fire_times), self.jitter, now) - else: - return None - - def __str__(self): - return 'or[{}]'.format(', '.join(str(trigger) for trigger in self.triggers)) diff --git a/venv/lib/python3.8/site-packages/apscheduler/triggers/cron/__init__.py b/venv/lib/python3.8/site-packages/apscheduler/triggers/cron/__init__.py deleted file mode 100644 index ce675dd..0000000 --- a/venv/lib/python3.8/site-packages/apscheduler/triggers/cron/__init__.py +++ /dev/null @@ -1,238 +0,0 @@ -from datetime import datetime, timedelta - -from tzlocal import get_localzone -import six - -from apscheduler.triggers.base import BaseTrigger -from apscheduler.triggers.cron.fields import ( - BaseField, MonthField, WeekField, DayOfMonthField, DayOfWeekField, DEFAULT_VALUES) -from apscheduler.util import datetime_ceil, convert_to_datetime, datetime_repr, astimezone - - -class CronTrigger(BaseTrigger): - """ - Triggers when current time matches all specified time constraints, - similarly to how the UNIX cron scheduler works. - - :param int|str year: 4-digit year - :param int|str month: month (1-12) - :param int|str day: day of the (1-31) - :param int|str week: ISO week (1-53) - :param int|str day_of_week: number or name of weekday (0-6 or mon,tue,wed,thu,fri,sat,sun) - :param int|str hour: hour (0-23) - :param int|str minute: minute (0-59) - :param int|str second: second (0-59) - :param datetime|str start_date: earliest possible date/time to trigger on (inclusive) - :param datetime|str end_date: latest possible date/time to trigger on (inclusive) - :param datetime.tzinfo|str timezone: time zone to use for the date/time calculations (defaults - to scheduler timezone) - :param int|None jitter: advance or delay the job execution by ``jitter`` seconds at most. - - .. note:: The first weekday is always **monday**. - """ - - FIELD_NAMES = ('year', 'month', 'day', 'week', 'day_of_week', 'hour', 'minute', 'second') - FIELDS_MAP = { - 'year': BaseField, - 'month': MonthField, - 'week': WeekField, - 'day': DayOfMonthField, - 'day_of_week': DayOfWeekField, - 'hour': BaseField, - 'minute': BaseField, - 'second': BaseField - } - - __slots__ = 'timezone', 'start_date', 'end_date', 'fields', 'jitter' - - def __init__(self, year=None, month=None, day=None, week=None, day_of_week=None, hour=None, - minute=None, second=None, start_date=None, end_date=None, timezone=None, - jitter=None): - if timezone: - self.timezone = astimezone(timezone) - elif isinstance(start_date, datetime) and start_date.tzinfo: - self.timezone = start_date.tzinfo - elif isinstance(end_date, datetime) and end_date.tzinfo: - self.timezone = end_date.tzinfo - else: - self.timezone = get_localzone() - - self.start_date = convert_to_datetime(start_date, self.timezone, 'start_date') - self.end_date = convert_to_datetime(end_date, self.timezone, 'end_date') - - self.jitter = jitter - - values = dict((key, value) for (key, value) in six.iteritems(locals()) - if key in self.FIELD_NAMES and value is not None) - self.fields = [] - assign_defaults = False - for field_name in self.FIELD_NAMES: - if field_name in values: - exprs = values.pop(field_name) - is_default = False - assign_defaults = not values - elif assign_defaults: - exprs = DEFAULT_VALUES[field_name] - is_default = True - else: - exprs = '*' - is_default = True - - field_class = self.FIELDS_MAP[field_name] - field = field_class(field_name, exprs, is_default) - self.fields.append(field) - - @classmethod - def from_crontab(cls, expr, timezone=None): - """ - Create a :class:`~CronTrigger` from a standard crontab expression. - - See https://en.wikipedia.org/wiki/Cron for more information on the format accepted here. - - :param expr: minute, hour, day of month, month, day of week - :param datetime.tzinfo|str timezone: time zone to use for the date/time calculations ( - defaults to scheduler timezone) - :return: a :class:`~CronTrigger` instance - - """ - values = expr.split() - if len(values) != 5: - raise ValueError('Wrong number of fields; got {}, expected 5'.format(len(values))) - - return cls(minute=values[0], hour=values[1], day=values[2], month=values[3], - day_of_week=values[4], timezone=timezone) - - def _increment_field_value(self, dateval, fieldnum): - """ - Increments the designated field and resets all less significant fields to their minimum - values. - - :type dateval: datetime - :type fieldnum: int - :return: a tuple containing the new date, and the number of the field that was actually - incremented - :rtype: tuple - """ - - values = {} - i = 0 - while i < len(self.fields): - field = self.fields[i] - if not field.REAL: - if i == fieldnum: - fieldnum -= 1 - i -= 1 - else: - i += 1 - continue - - if i < fieldnum: - values[field.name] = field.get_value(dateval) - i += 1 - elif i > fieldnum: - values[field.name] = field.get_min(dateval) - i += 1 - else: - value = field.get_value(dateval) - maxval = field.get_max(dateval) - if value == maxval: - fieldnum -= 1 - i -= 1 - else: - values[field.name] = value + 1 - i += 1 - - difference = datetime(**values) - dateval.replace(tzinfo=None) - return self.timezone.normalize(dateval + difference), fieldnum - - def _set_field_value(self, dateval, fieldnum, new_value): - values = {} - for i, field in enumerate(self.fields): - if field.REAL: - if i < fieldnum: - values[field.name] = field.get_value(dateval) - elif i > fieldnum: - values[field.name] = field.get_min(dateval) - else: - values[field.name] = new_value - - return self.timezone.localize(datetime(**values)) - - def get_next_fire_time(self, previous_fire_time, now): - if previous_fire_time: - start_date = min(now, previous_fire_time + timedelta(microseconds=1)) - if start_date == previous_fire_time: - start_date += timedelta(microseconds=1) - else: - start_date = max(now, self.start_date) if self.start_date else now - - fieldnum = 0 - next_date = datetime_ceil(start_date).astimezone(self.timezone) - while 0 <= fieldnum < len(self.fields): - field = self.fields[fieldnum] - curr_value = field.get_value(next_date) - next_value = field.get_next_value(next_date) - - if next_value is None: - # No valid value was found - next_date, fieldnum = self._increment_field_value(next_date, fieldnum - 1) - elif next_value > curr_value: - # A valid, but higher than the starting value, was found - if field.REAL: - next_date = self._set_field_value(next_date, fieldnum, next_value) - fieldnum += 1 - else: - next_date, fieldnum = self._increment_field_value(next_date, fieldnum) - else: - # A valid value was found, no changes necessary - fieldnum += 1 - - # Return if the date has rolled past the end date - if self.end_date and next_date > self.end_date: - return None - - if fieldnum >= 0: - next_date = self._apply_jitter(next_date, self.jitter, now) - return min(next_date, self.end_date) if self.end_date else next_date - - def __getstate__(self): - return { - 'version': 2, - 'timezone': self.timezone, - 'start_date': self.start_date, - 'end_date': self.end_date, - 'fields': self.fields, - 'jitter': self.jitter, - } - - def __setstate__(self, state): - # This is for compatibility with APScheduler 3.0.x - if isinstance(state, tuple): - state = state[1] - - if state.get('version', 1) > 2: - raise ValueError( - 'Got serialized data for version %s of %s, but only versions up to 2 can be ' - 'handled' % (state['version'], self.__class__.__name__)) - - self.timezone = state['timezone'] - self.start_date = state['start_date'] - self.end_date = state['end_date'] - self.fields = state['fields'] - self.jitter = state.get('jitter') - - def __str__(self): - options = ["%s='%s'" % (f.name, f) for f in self.fields if not f.is_default] - return 'cron[%s]' % (', '.join(options)) - - def __repr__(self): - options = ["%s='%s'" % (f.name, f) for f in self.fields if not f.is_default] - if self.start_date: - options.append("start_date=%r" % datetime_repr(self.start_date)) - if self.end_date: - options.append("end_date=%r" % datetime_repr(self.end_date)) - if self.jitter: - options.append('jitter=%s' % self.jitter) - - return "<%s (%s, timezone='%s')>" % ( - self.__class__.__name__, ', '.join(options), self.timezone) diff --git a/venv/lib/python3.8/site-packages/apscheduler/triggers/cron/expressions.py b/venv/lib/python3.8/site-packages/apscheduler/triggers/cron/expressions.py deleted file mode 100644 index 55a3716..0000000 --- a/venv/lib/python3.8/site-packages/apscheduler/triggers/cron/expressions.py +++ /dev/null @@ -1,251 +0,0 @@ -"""This module contains the expressions applicable for CronTrigger's fields.""" - -from calendar import monthrange -import re - -from apscheduler.util import asint - -__all__ = ('AllExpression', 'RangeExpression', 'WeekdayRangeExpression', - 'WeekdayPositionExpression', 'LastDayOfMonthExpression') - - -WEEKDAYS = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun'] -MONTHS = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec'] - - -class AllExpression(object): - value_re = re.compile(r'\*(?:/(?P<step>\d+))?$') - - def __init__(self, step=None): - self.step = asint(step) - if self.step == 0: - raise ValueError('Increment must be higher than 0') - - def validate_range(self, field_name): - from apscheduler.triggers.cron.fields import MIN_VALUES, MAX_VALUES - - value_range = MAX_VALUES[field_name] - MIN_VALUES[field_name] - if self.step and self.step > value_range: - raise ValueError('the step value ({}) is higher than the total range of the ' - 'expression ({})'.format(self.step, value_range)) - - def get_next_value(self, date, field): - start = field.get_value(date) - minval = field.get_min(date) - maxval = field.get_max(date) - start = max(start, minval) - - if not self.step: - next = start - else: - distance_to_next = (self.step - (start - minval)) % self.step - next = start + distance_to_next - - if next <= maxval: - return next - - def __eq__(self, other): - return isinstance(other, self.__class__) and self.step == other.step - - def __str__(self): - if self.step: - return '*/%d' % self.step - return '*' - - def __repr__(self): - return "%s(%s)" % (self.__class__.__name__, self.step) - - -class RangeExpression(AllExpression): - value_re = re.compile( - r'(?P<first>\d+)(?:-(?P<last>\d+))?(?:/(?P<step>\d+))?$') - - def __init__(self, first, last=None, step=None): - super(RangeExpression, self).__init__(step) - first = asint(first) - last = asint(last) - if last is None and step is None: - last = first - if last is not None and first > last: - raise ValueError('The minimum value in a range must not be higher than the maximum') - self.first = first - self.last = last - - def validate_range(self, field_name): - from apscheduler.triggers.cron.fields import MIN_VALUES, MAX_VALUES - - super(RangeExpression, self).validate_range(field_name) - if self.first < MIN_VALUES[field_name]: - raise ValueError('the first value ({}) is lower than the minimum value ({})' - .format(self.first, MIN_VALUES[field_name])) - if self.last is not None and self.last > MAX_VALUES[field_name]: - raise ValueError('the last value ({}) is higher than the maximum value ({})' - .format(self.last, MAX_VALUES[field_name])) - value_range = (self.last or MAX_VALUES[field_name]) - self.first - if self.step and self.step > value_range: - raise ValueError('the step value ({}) is higher than the total range of the ' - 'expression ({})'.format(self.step, value_range)) - - def get_next_value(self, date, field): - startval = field.get_value(date) - minval = field.get_min(date) - maxval = field.get_max(date) - - # Apply range limits - minval = max(minval, self.first) - maxval = min(maxval, self.last) if self.last is not None else maxval - nextval = max(minval, startval) - - # Apply the step if defined - if self.step: - distance_to_next = (self.step - (nextval - minval)) % self.step - nextval += distance_to_next - - return nextval if nextval <= maxval else None - - def __eq__(self, other): - return (isinstance(other, self.__class__) and self.first == other.first and - self.last == other.last) - - def __str__(self): - if self.last != self.first and self.last is not None: - range = '%d-%d' % (self.first, self.last) - else: - range = str(self.first) - - if self.step: - return '%s/%d' % (range, self.step) - return range - - def __repr__(self): - args = [str(self.first)] - if self.last != self.first and self.last is not None or self.step: - args.append(str(self.last)) - if self.step: - args.append(str(self.step)) - return "%s(%s)" % (self.__class__.__name__, ', '.join(args)) - - -class MonthRangeExpression(RangeExpression): - value_re = re.compile(r'(?P<first>[a-z]+)(?:-(?P<last>[a-z]+))?', re.IGNORECASE) - - def __init__(self, first, last=None): - try: - first_num = MONTHS.index(first.lower()) + 1 - except ValueError: - raise ValueError('Invalid month name "%s"' % first) - - if last: - try: - last_num = MONTHS.index(last.lower()) + 1 - except ValueError: - raise ValueError('Invalid month name "%s"' % last) - else: - last_num = None - - super(MonthRangeExpression, self).__init__(first_num, last_num) - - def __str__(self): - if self.last != self.first and self.last is not None: - return '%s-%s' % (MONTHS[self.first - 1], MONTHS[self.last - 1]) - return MONTHS[self.first - 1] - - def __repr__(self): - args = ["'%s'" % MONTHS[self.first]] - if self.last != self.first and self.last is not None: - args.append("'%s'" % MONTHS[self.last - 1]) - return "%s(%s)" % (self.__class__.__name__, ', '.join(args)) - - -class WeekdayRangeExpression(RangeExpression): - value_re = re.compile(r'(?P<first>[a-z]+)(?:-(?P<last>[a-z]+))?', re.IGNORECASE) - - def __init__(self, first, last=None): - try: - first_num = WEEKDAYS.index(first.lower()) - except ValueError: - raise ValueError('Invalid weekday name "%s"' % first) - - if last: - try: - last_num = WEEKDAYS.index(last.lower()) - except ValueError: - raise ValueError('Invalid weekday name "%s"' % last) - else: - last_num = None - - super(WeekdayRangeExpression, self).__init__(first_num, last_num) - - def __str__(self): - if self.last != self.first and self.last is not None: - return '%s-%s' % (WEEKDAYS[self.first], WEEKDAYS[self.last]) - return WEEKDAYS[self.first] - - def __repr__(self): - args = ["'%s'" % WEEKDAYS[self.first]] - if self.last != self.first and self.last is not None: - args.append("'%s'" % WEEKDAYS[self.last]) - return "%s(%s)" % (self.__class__.__name__, ', '.join(args)) - - -class WeekdayPositionExpression(AllExpression): - options = ['1st', '2nd', '3rd', '4th', '5th', 'last'] - value_re = re.compile(r'(?P<option_name>%s) +(?P<weekday_name>(?:\d+|\w+))' % - '|'.join(options), re.IGNORECASE) - - def __init__(self, option_name, weekday_name): - super(WeekdayPositionExpression, self).__init__(None) - try: - self.option_num = self.options.index(option_name.lower()) - except ValueError: - raise ValueError('Invalid weekday position "%s"' % option_name) - - try: - self.weekday = WEEKDAYS.index(weekday_name.lower()) - except ValueError: - raise ValueError('Invalid weekday name "%s"' % weekday_name) - - def get_next_value(self, date, field): - # Figure out the weekday of the month's first day and the number of days in that month - first_day_wday, last_day = monthrange(date.year, date.month) - - # Calculate which day of the month is the first of the target weekdays - first_hit_day = self.weekday - first_day_wday + 1 - if first_hit_day <= 0: - first_hit_day += 7 - - # Calculate what day of the month the target weekday would be - if self.option_num < 5: - target_day = first_hit_day + self.option_num * 7 - else: - target_day = first_hit_day + ((last_day - first_hit_day) // 7) * 7 - - if target_day <= last_day and target_day >= date.day: - return target_day - - def __eq__(self, other): - return (super(WeekdayPositionExpression, self).__eq__(other) and - self.option_num == other.option_num and self.weekday == other.weekday) - - def __str__(self): - return '%s %s' % (self.options[self.option_num], WEEKDAYS[self.weekday]) - - def __repr__(self): - return "%s('%s', '%s')" % (self.__class__.__name__, self.options[self.option_num], - WEEKDAYS[self.weekday]) - - -class LastDayOfMonthExpression(AllExpression): - value_re = re.compile(r'last', re.IGNORECASE) - - def __init__(self): - super(LastDayOfMonthExpression, self).__init__(None) - - def get_next_value(self, date, field): - return monthrange(date.year, date.month)[1] - - def __str__(self): - return 'last' - - def __repr__(self): - return "%s()" % self.__class__.__name__ diff --git a/venv/lib/python3.8/site-packages/apscheduler/triggers/cron/fields.py b/venv/lib/python3.8/site-packages/apscheduler/triggers/cron/fields.py deleted file mode 100644 index 86d620c..0000000 --- a/venv/lib/python3.8/site-packages/apscheduler/triggers/cron/fields.py +++ /dev/null @@ -1,111 +0,0 @@ -"""Fields represent CronTrigger options which map to :class:`~datetime.datetime` fields.""" - -from calendar import monthrange -import re - -import six - -from apscheduler.triggers.cron.expressions import ( - AllExpression, RangeExpression, WeekdayPositionExpression, LastDayOfMonthExpression, - WeekdayRangeExpression, MonthRangeExpression) - - -__all__ = ('MIN_VALUES', 'MAX_VALUES', 'DEFAULT_VALUES', 'BaseField', 'WeekField', - 'DayOfMonthField', 'DayOfWeekField') - - -MIN_VALUES = {'year': 1970, 'month': 1, 'day': 1, 'week': 1, 'day_of_week': 0, 'hour': 0, - 'minute': 0, 'second': 0} -MAX_VALUES = {'year': 9999, 'month': 12, 'day': 31, 'week': 53, 'day_of_week': 6, 'hour': 23, - 'minute': 59, 'second': 59} -DEFAULT_VALUES = {'year': '*', 'month': 1, 'day': 1, 'week': '*', 'day_of_week': '*', 'hour': 0, - 'minute': 0, 'second': 0} -SEPARATOR = re.compile(' *, *') - - -class BaseField(object): - REAL = True - COMPILERS = [AllExpression, RangeExpression] - - def __init__(self, name, exprs, is_default=False): - self.name = name - self.is_default = is_default - self.compile_expressions(exprs) - - def get_min(self, dateval): - return MIN_VALUES[self.name] - - def get_max(self, dateval): - return MAX_VALUES[self.name] - - def get_value(self, dateval): - return getattr(dateval, self.name) - - def get_next_value(self, dateval): - smallest = None - for expr in self.expressions: - value = expr.get_next_value(dateval, self) - if smallest is None or (value is not None and value < smallest): - smallest = value - - return smallest - - def compile_expressions(self, exprs): - self.expressions = [] - - # Split a comma-separated expression list, if any - for expr in SEPARATOR.split(str(exprs).strip()): - self.compile_expression(expr) - - def compile_expression(self, expr): - for compiler in self.COMPILERS: - match = compiler.value_re.match(expr) - if match: - compiled_expr = compiler(**match.groupdict()) - - try: - compiled_expr.validate_range(self.name) - except ValueError as e: - exc = ValueError('Error validating expression {!r}: {}'.format(expr, e)) - six.raise_from(exc, None) - - self.expressions.append(compiled_expr) - return - - raise ValueError('Unrecognized expression "%s" for field "%s"' % (expr, self.name)) - - def __eq__(self, other): - return isinstance(self, self.__class__) and self.expressions == other.expressions - - def __str__(self): - expr_strings = (str(e) for e in self.expressions) - return ','.join(expr_strings) - - def __repr__(self): - return "%s('%s', '%s')" % (self.__class__.__name__, self.name, self) - - -class WeekField(BaseField): - REAL = False - - def get_value(self, dateval): - return dateval.isocalendar()[1] - - -class DayOfMonthField(BaseField): - COMPILERS = BaseField.COMPILERS + [WeekdayPositionExpression, LastDayOfMonthExpression] - - def get_max(self, dateval): - return monthrange(dateval.year, dateval.month)[1] - - -class DayOfWeekField(BaseField): - REAL = False - COMPILERS = BaseField.COMPILERS + [WeekdayRangeExpression] - - def get_value(self, dateval): - return dateval.weekday() - - -class MonthField(BaseField): - COMPILERS = BaseField.COMPILERS + [MonthRangeExpression] diff --git a/venv/lib/python3.8/site-packages/apscheduler/triggers/date.py b/venv/lib/python3.8/site-packages/apscheduler/triggers/date.py deleted file mode 100644 index 0768100..0000000 --- a/venv/lib/python3.8/site-packages/apscheduler/triggers/date.py +++ /dev/null @@ -1,51 +0,0 @@ -from datetime import datetime - -from tzlocal import get_localzone - -from apscheduler.triggers.base import BaseTrigger -from apscheduler.util import convert_to_datetime, datetime_repr, astimezone - - -class DateTrigger(BaseTrigger): - """ - Triggers once on the given datetime. If ``run_date`` is left empty, current time is used. - - :param datetime|str run_date: the date/time to run the job at - :param datetime.tzinfo|str timezone: time zone for ``run_date`` if it doesn't have one already - """ - - __slots__ = 'run_date' - - def __init__(self, run_date=None, timezone=None): - timezone = astimezone(timezone) or get_localzone() - if run_date is not None: - self.run_date = convert_to_datetime(run_date, timezone, 'run_date') - else: - self.run_date = datetime.now(timezone) - - def get_next_fire_time(self, previous_fire_time, now): - return self.run_date if previous_fire_time is None else None - - def __getstate__(self): - return { - 'version': 1, - 'run_date': self.run_date - } - - def __setstate__(self, state): - # This is for compatibility with APScheduler 3.0.x - if isinstance(state, tuple): - state = state[1] - - if state.get('version', 1) > 1: - raise ValueError( - 'Got serialized data for version %s of %s, but only version 1 can be handled' % - (state['version'], self.__class__.__name__)) - - self.run_date = state['run_date'] - - def __str__(self): - return 'date[%s]' % datetime_repr(self.run_date) - - def __repr__(self): - return "<%s (run_date='%s')>" % (self.__class__.__name__, datetime_repr(self.run_date)) diff --git a/venv/lib/python3.8/site-packages/apscheduler/triggers/interval.py b/venv/lib/python3.8/site-packages/apscheduler/triggers/interval.py deleted file mode 100644 index 831ba38..0000000 --- a/venv/lib/python3.8/site-packages/apscheduler/triggers/interval.py +++ /dev/null @@ -1,106 +0,0 @@ -from datetime import timedelta, datetime -from math import ceil - -from tzlocal import get_localzone - -from apscheduler.triggers.base import BaseTrigger -from apscheduler.util import convert_to_datetime, timedelta_seconds, datetime_repr, astimezone - - -class IntervalTrigger(BaseTrigger): - """ - Triggers on specified intervals, starting on ``start_date`` if specified, ``datetime.now()`` + - interval otherwise. - - :param int weeks: number of weeks to wait - :param int days: number of days to wait - :param int hours: number of hours to wait - :param int minutes: number of minutes to wait - :param int seconds: number of seconds to wait - :param datetime|str start_date: starting point for the interval calculation - :param datetime|str end_date: latest possible date/time to trigger on - :param datetime.tzinfo|str timezone: time zone to use for the date/time calculations - :param int|None jitter: advance or delay the job execution by ``jitter`` seconds at most. - """ - - __slots__ = 'timezone', 'start_date', 'end_date', 'interval', 'interval_length', 'jitter' - - def __init__(self, weeks=0, days=0, hours=0, minutes=0, seconds=0, start_date=None, - end_date=None, timezone=None, jitter=None): - self.interval = timedelta(weeks=weeks, days=days, hours=hours, minutes=minutes, - seconds=seconds) - self.interval_length = timedelta_seconds(self.interval) - if self.interval_length == 0: - self.interval = timedelta(seconds=1) - self.interval_length = 1 - - if timezone: - self.timezone = astimezone(timezone) - elif isinstance(start_date, datetime) and start_date.tzinfo: - self.timezone = start_date.tzinfo - elif isinstance(end_date, datetime) and end_date.tzinfo: - self.timezone = end_date.tzinfo - else: - self.timezone = get_localzone() - - start_date = start_date or (datetime.now(self.timezone) + self.interval) - self.start_date = convert_to_datetime(start_date, self.timezone, 'start_date') - self.end_date = convert_to_datetime(end_date, self.timezone, 'end_date') - - self.jitter = jitter - - def get_next_fire_time(self, previous_fire_time, now): - if previous_fire_time: - next_fire_time = previous_fire_time + self.interval - elif self.start_date > now: - next_fire_time = self.start_date - else: - timediff_seconds = timedelta_seconds(now - self.start_date) - next_interval_num = int(ceil(timediff_seconds / self.interval_length)) - next_fire_time = self.start_date + self.interval * next_interval_num - - if self.jitter is not None: - next_fire_time = self._apply_jitter(next_fire_time, self.jitter, now) - - if not self.end_date or next_fire_time <= self.end_date: - return self.timezone.normalize(next_fire_time) - - def __getstate__(self): - return { - 'version': 2, - 'timezone': self.timezone, - 'start_date': self.start_date, - 'end_date': self.end_date, - 'interval': self.interval, - 'jitter': self.jitter, - } - - def __setstate__(self, state): - # This is for compatibility with APScheduler 3.0.x - if isinstance(state, tuple): - state = state[1] - - if state.get('version', 1) > 2: - raise ValueError( - 'Got serialized data for version %s of %s, but only versions up to 2 can be ' - 'handled' % (state['version'], self.__class__.__name__)) - - self.timezone = state['timezone'] - self.start_date = state['start_date'] - self.end_date = state['end_date'] - self.interval = state['interval'] - self.interval_length = timedelta_seconds(self.interval) - self.jitter = state.get('jitter') - - def __str__(self): - return 'interval[%s]' % str(self.interval) - - def __repr__(self): - options = ['interval=%r' % self.interval, 'start_date=%r' % datetime_repr(self.start_date)] - if self.end_date: - options.append("end_date=%r" % datetime_repr(self.end_date)) - if self.jitter: - options.append('jitter=%s' % self.jitter) - - return "<%s (%s, timezone='%s')>" % ( - self.__class__.__name__, ', '.join(options), self.timezone) diff --git a/venv/lib/python3.8/site-packages/apscheduler/util.py b/venv/lib/python3.8/site-packages/apscheduler/util.py deleted file mode 100644 index 8b7b3f5..0000000 --- a/venv/lib/python3.8/site-packages/apscheduler/util.py +++ /dev/null @@ -1,429 +0,0 @@ -"""This module contains several handy functions primarily meant for internal use.""" - -from __future__ import division - -from datetime import date, datetime, time, timedelta, tzinfo -from calendar import timegm -from functools import partial -from inspect import isclass, ismethod -import re - -from pytz import timezone, utc, FixedOffset -import six - -try: - from inspect import signature -except ImportError: # pragma: nocover - from funcsigs import signature - -try: - from threading import TIMEOUT_MAX -except ImportError: - TIMEOUT_MAX = 4294967 # Maximum value accepted by Event.wait() on Windows - -try: - from asyncio import iscoroutinefunction -except ImportError: - try: - from trollius import iscoroutinefunction - except ImportError: - def iscoroutinefunction(func): - return False - -__all__ = ('asint', 'asbool', 'astimezone', 'convert_to_datetime', 'datetime_to_utc_timestamp', - 'utc_timestamp_to_datetime', 'timedelta_seconds', 'datetime_ceil', 'get_callable_name', - 'obj_to_ref', 'ref_to_obj', 'maybe_ref', 'repr_escape', 'check_callable_args', - 'TIMEOUT_MAX') - - -class _Undefined(object): - def __nonzero__(self): - return False - - def __bool__(self): - return False - - def __repr__(self): - return '<undefined>' - - -undefined = _Undefined() #: a unique object that only signifies that no value is defined - - -def asint(text): - """ - Safely converts a string to an integer, returning ``None`` if the string is ``None``. - - :type text: str - :rtype: int - - """ - if text is not None: - return int(text) - - -def asbool(obj): - """ - Interprets an object as a boolean value. - - :rtype: bool - - """ - if isinstance(obj, str): - obj = obj.strip().lower() - if obj in ('true', 'yes', 'on', 'y', 't', '1'): - return True - if obj in ('false', 'no', 'off', 'n', 'f', '0'): - return False - raise ValueError('Unable to interpret value "%s" as boolean' % obj) - return bool(obj) - - -def astimezone(obj): - """ - Interprets an object as a timezone. - - :rtype: tzinfo - - """ - if isinstance(obj, six.string_types): - return timezone(obj) - if isinstance(obj, tzinfo): - if not hasattr(obj, 'localize') or not hasattr(obj, 'normalize'): - raise TypeError('Only timezones from the pytz library are supported') - if obj.zone == 'local': - raise ValueError( - 'Unable to determine the name of the local timezone -- you must explicitly ' - 'specify the name of the local timezone. Please refrain from using timezones like ' - 'EST to prevent problems with daylight saving time. Instead, use a locale based ' - 'timezone name (such as Europe/Helsinki).') - return obj - if obj is not None: - raise TypeError('Expected tzinfo, got %s instead' % obj.__class__.__name__) - - -_DATE_REGEX = re.compile( - r'(?P<year>\d{4})-(?P<month>\d{1,2})-(?P<day>\d{1,2})' - r'(?:[ T](?P<hour>\d{1,2}):(?P<minute>\d{1,2}):(?P<second>\d{1,2})' - r'(?:\.(?P<microsecond>\d{1,6}))?' - r'(?P<timezone>Z|[+-]\d\d:\d\d)?)?$') - - -def convert_to_datetime(input, tz, arg_name): - """ - Converts the given object to a timezone aware datetime object. - - If a timezone aware datetime object is passed, it is returned unmodified. - If a native datetime object is passed, it is given the specified timezone. - If the input is a string, it is parsed as a datetime with the given timezone. - - Date strings are accepted in three different forms: date only (Y-m-d), date with time - (Y-m-d H:M:S) or with date+time with microseconds (Y-m-d H:M:S.micro). Additionally you can - override the time zone by giving a specific offset in the format specified by ISO 8601: - Z (UTC), +HH:MM or -HH:MM. - - :param str|datetime input: the datetime or string to convert to a timezone aware datetime - :param datetime.tzinfo tz: timezone to interpret ``input`` in - :param str arg_name: the name of the argument (used in an error message) - :rtype: datetime - - """ - if input is None: - return - elif isinstance(input, datetime): - datetime_ = input - elif isinstance(input, date): - datetime_ = datetime.combine(input, time()) - elif isinstance(input, six.string_types): - m = _DATE_REGEX.match(input) - if not m: - raise ValueError('Invalid date string') - - values = m.groupdict() - tzname = values.pop('timezone') - if tzname == 'Z': - tz = utc - elif tzname: - hours, minutes = (int(x) for x in tzname[1:].split(':')) - sign = 1 if tzname[0] == '+' else -1 - tz = FixedOffset(sign * (hours * 60 + minutes)) - - values = {k: int(v or 0) for k, v in values.items()} - datetime_ = datetime(**values) - else: - raise TypeError('Unsupported type for %s: %s' % (arg_name, input.__class__.__name__)) - - if datetime_.tzinfo is not None: - return datetime_ - if tz is None: - raise ValueError( - 'The "tz" argument must be specified if %s has no timezone information' % arg_name) - if isinstance(tz, six.string_types): - tz = timezone(tz) - - try: - return tz.localize(datetime_, is_dst=None) - except AttributeError: - raise TypeError( - 'Only pytz timezones are supported (need the localize() and normalize() methods)') - - -def datetime_to_utc_timestamp(timeval): - """ - Converts a datetime instance to a timestamp. - - :type timeval: datetime - :rtype: float - - """ - if timeval is not None: - return timegm(timeval.utctimetuple()) + timeval.microsecond / 1000000 - - -def utc_timestamp_to_datetime(timestamp): - """ - Converts the given timestamp to a datetime instance. - - :type timestamp: float - :rtype: datetime - - """ - if timestamp is not None: - return datetime.fromtimestamp(timestamp, utc) - - -def timedelta_seconds(delta): - """ - Converts the given timedelta to seconds. - - :type delta: timedelta - :rtype: float - - """ - return delta.days * 24 * 60 * 60 + delta.seconds + \ - delta.microseconds / 1000000.0 - - -def datetime_ceil(dateval): - """ - Rounds the given datetime object upwards. - - :type dateval: datetime - - """ - if dateval.microsecond > 0: - return dateval + timedelta(seconds=1, microseconds=-dateval.microsecond) - return dateval - - -def datetime_repr(dateval): - return dateval.strftime('%Y-%m-%d %H:%M:%S %Z') if dateval else 'None' - - -def get_callable_name(func): - """ - Returns the best available display name for the given function/callable. - - :rtype: str - - """ - # the easy case (on Python 3.3+) - if hasattr(func, '__qualname__'): - return func.__qualname__ - - # class methods, bound and unbound methods - f_self = getattr(func, '__self__', None) or getattr(func, 'im_self', None) - if f_self and hasattr(func, '__name__'): - f_class = f_self if isclass(f_self) else f_self.__class__ - else: - f_class = getattr(func, 'im_class', None) - - if f_class and hasattr(func, '__name__'): - return '%s.%s' % (f_class.__name__, func.__name__) - - # class or class instance - if hasattr(func, '__call__'): - # class - if hasattr(func, '__name__'): - return func.__name__ - - # instance of a class with a __call__ method - return func.__class__.__name__ - - raise TypeError('Unable to determine a name for %r -- maybe it is not a callable?' % func) - - -def obj_to_ref(obj): - """ - Returns the path to the given callable. - - :rtype: str - :raises TypeError: if the given object is not callable - :raises ValueError: if the given object is a :class:`~functools.partial`, lambda or a nested - function - - """ - if isinstance(obj, partial): - raise ValueError('Cannot create a reference to a partial()') - - name = get_callable_name(obj) - if '<lambda>' in name: - raise ValueError('Cannot create a reference to a lambda') - if '<locals>' in name: - raise ValueError('Cannot create a reference to a nested function') - - if ismethod(obj): - if hasattr(obj, 'im_self') and obj.im_self: - # bound method - module = obj.im_self.__module__ - elif hasattr(obj, 'im_class') and obj.im_class: - # unbound method - module = obj.im_class.__module__ - else: - module = obj.__module__ - else: - module = obj.__module__ - return '%s:%s' % (module, name) - - -def ref_to_obj(ref): - """ - Returns the object pointed to by ``ref``. - - :type ref: str - - """ - if not isinstance(ref, six.string_types): - raise TypeError('References must be strings') - if ':' not in ref: - raise ValueError('Invalid reference') - - modulename, rest = ref.split(':', 1) - try: - obj = __import__(modulename, fromlist=[rest]) - except ImportError: - raise LookupError('Error resolving reference %s: could not import module' % ref) - - try: - for name in rest.split('.'): - obj = getattr(obj, name) - return obj - except Exception: - raise LookupError('Error resolving reference %s: error looking up object' % ref) - - -def maybe_ref(ref): - """ - Returns the object that the given reference points to, if it is indeed a reference. - If it is not a reference, the object is returned as-is. - - """ - if not isinstance(ref, str): - return ref - return ref_to_obj(ref) - - -if six.PY2: - def repr_escape(string): - if isinstance(string, six.text_type): - return string.encode('ascii', 'backslashreplace') - return string -else: - def repr_escape(string): - return string - - -def check_callable_args(func, args, kwargs): - """ - Ensures that the given callable can be called with the given arguments. - - :type args: tuple - :type kwargs: dict - - """ - pos_kwargs_conflicts = [] # parameters that have a match in both args and kwargs - positional_only_kwargs = [] # positional-only parameters that have a match in kwargs - unsatisfied_args = [] # parameters in signature that don't have a match in args or kwargs - unsatisfied_kwargs = [] # keyword-only arguments that don't have a match in kwargs - unmatched_args = list(args) # args that didn't match any of the parameters in the signature - # kwargs that didn't match any of the parameters in the signature - unmatched_kwargs = list(kwargs) - # indicates if the signature defines *args and **kwargs respectively - has_varargs = has_var_kwargs = False - - try: - sig = signature(func) - except ValueError: - # signature() doesn't work against every kind of callable - return - - for param in six.itervalues(sig.parameters): - if param.kind == param.POSITIONAL_OR_KEYWORD: - if param.name in unmatched_kwargs and unmatched_args: - pos_kwargs_conflicts.append(param.name) - elif unmatched_args: - del unmatched_args[0] - elif param.name in unmatched_kwargs: - unmatched_kwargs.remove(param.name) - elif param.default is param.empty: - unsatisfied_args.append(param.name) - elif param.kind == param.POSITIONAL_ONLY: - if unmatched_args: - del unmatched_args[0] - elif param.name in unmatched_kwargs: - unmatched_kwargs.remove(param.name) - positional_only_kwargs.append(param.name) - elif param.default is param.empty: - unsatisfied_args.append(param.name) - elif param.kind == param.KEYWORD_ONLY: - if param.name in unmatched_kwargs: - unmatched_kwargs.remove(param.name) - elif param.default is param.empty: - unsatisfied_kwargs.append(param.name) - elif param.kind == param.VAR_POSITIONAL: - has_varargs = True - elif param.kind == param.VAR_KEYWORD: - has_var_kwargs = True - - # Make sure there are no conflicts between args and kwargs - if pos_kwargs_conflicts: - raise ValueError('The following arguments are supplied in both args and kwargs: %s' % - ', '.join(pos_kwargs_conflicts)) - - # Check if keyword arguments are being fed to positional-only parameters - if positional_only_kwargs: - raise ValueError('The following arguments cannot be given as keyword arguments: %s' % - ', '.join(positional_only_kwargs)) - - # Check that the number of positional arguments minus the number of matched kwargs matches the - # argspec - if unsatisfied_args: - raise ValueError('The following arguments have not been supplied: %s' % - ', '.join(unsatisfied_args)) - - # Check that all keyword-only arguments have been supplied - if unsatisfied_kwargs: - raise ValueError( - 'The following keyword-only arguments have not been supplied in kwargs: %s' % - ', '.join(unsatisfied_kwargs)) - - # Check that the callable can accept the given number of positional arguments - if not has_varargs and unmatched_args: - raise ValueError( - 'The list of positional arguments is longer than the target callable can handle ' - '(allowed: %d, given in args: %d)' % (len(args) - len(unmatched_args), len(args))) - - # Check that the callable can accept the given keyword arguments - if not has_var_kwargs and unmatched_kwargs: - raise ValueError( - 'The target callable does not accept the following keyword arguments: %s' % - ', '.join(unmatched_kwargs)) - - -def iscoroutinefunction_partial(f): - while isinstance(f, partial): - f = f.func - - # The asyncio version of iscoroutinefunction includes testing for @coroutine - # decorations vs. the inspect version which does not. - return iscoroutinefunction(f) diff --git a/venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/INSTALLER b/venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/LICENSE b/venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/LICENSE deleted file mode 100644 index fc2146e..0000000 --- a/venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2014-2021 Thomas Kemmer - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/METADATA b/venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/METADATA deleted file mode 100644 index 221d110..0000000 --- a/venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/METADATA +++ /dev/null @@ -1,129 +0,0 @@ -Metadata-Version: 2.1 -Name: cachetools -Version: 4.2.2 -Summary: Extensible memoizing collections and decorators -Home-page: https://github.com/tkem/cachetools/ -Author: Thomas Kemmer -Author-email: tkemmer@computer.org -License: MIT -Platform: UNKNOWN -Classifier: Development Status :: 5 - Production/Stable -Classifier: Environment :: Other Environment -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: MIT License -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.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 :: Software Development :: Libraries :: Python Modules -Requires-Python: ~=3.5 - -cachetools -======================================================================== - -.. image:: https://img.shields.io/pypi/v/cachetools - :target: https://pypi.org/project/cachetools/ - :alt: Latest PyPI version - -.. image:: https://img.shields.io/readthedocs/cachetools - :target: https://cachetools.readthedocs.io/ - :alt: Documentation build status - -.. image:: https://img.shields.io/travis/tkem/cachetools - :target: https://travis-ci.org/tkem/cachetools/ - :alt: Travis CI build status - -.. image:: https://img.shields.io/coveralls/tkem/cachetools - :target: https://coveralls.io/r/tkem/cachetools - :alt: Test coverage - -.. image:: https://img.shields.io/github/license/tkem/cachetools - :target: https://raw.github.com/tkem/cachetools/master/LICENSE - :alt: License - -.. image:: https://img.shields.io/badge/code%20style-black-000000.svg - :target: https://github.com/psf/black - :alt: Code style: black - -This module provides various memoizing collections and decorators, -including variants of the Python Standard Library's `@lru_cache`_ -function decorator. - -.. code-block:: python - - from cachetools import cached, LRUCache, TTLCache - - # speed up calculating Fibonacci numbers with dynamic programming - @cached(cache={}) - def fib(n): - return n if n < 2 else fib(n - 1) + fib(n - 2) - - # cache least recently used Python Enhancement Proposals - @cached(cache=LRUCache(maxsize=32)) - def get_pep(num): - url = 'http://www.python.org/dev/peps/pep-%04d/' % num - with urllib.request.urlopen(url) as s: - return s.read() - - # cache weather data for no longer than ten minutes - @cached(cache=TTLCache(maxsize=1024, ttl=600)) - def get_weather(place): - return owm.weather_at_place(place).get_weather() - -For the purpose of this module, a *cache* is a mutable_ mapping_ of a -fixed maximum size. When the cache is full, i.e. by adding another -item the cache would exceed its maximum size, the cache must choose -which item(s) to discard based on a suitable `cache algorithm`_. In -general, a cache's size is the total size of its items, and an item's -size is a property or function of its value, e.g. the result of -``sys.getsizeof(value)``. For the trivial but common case that each -item counts as ``1``, a cache's size is equal to the number of its -items, or ``len(cache)``. - -Multiple cache classes based on different caching algorithms are -implemented, and decorators for easily memoizing function and method -calls are provided, too. - - -Installation ------------------------------------------------------------------------- - -cachetools is available from PyPI_ and can be installed by running:: - - pip install cachetools - - -Project Resources ------------------------------------------------------------------------- - -- `Documentation`_ -- `Issue tracker`_ -- `Source code`_ -- `Change log`_ - - -License ------------------------------------------------------------------------- - -Copyright (c) 2014-2021 Thomas Kemmer. - -Licensed under the `MIT License`_. - - -.. _@lru_cache: https://docs.python.org/3/library/functools.html#functools.lru_cache -.. _mutable: https://docs.python.org/dev/glossary.html#term-mutable -.. _mapping: https://docs.python.org/dev/glossary.html#term-mapping -.. _cache algorithm: https://en.wikipedia.org/wiki/Cache_algorithms - -.. _PyPI: https://pypi.org/project/cachetools/ -.. _Documentation: https://cachetools.readthedocs.io/ -.. _Issue tracker: https://github.com/tkem/cachetools/issues/ -.. _Source code: https://github.com/tkem/cachetools/ -.. _Change log: https://github.com/tkem/cachetools/blob/master/CHANGELOG.rst -.. _MIT License: https://raw.github.com/tkem/cachetools/master/LICENSE - - diff --git a/venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/RECORD b/venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/RECORD deleted file mode 100644 index 82787c0..0000000 --- a/venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/RECORD +++ /dev/null @@ -1,28 +0,0 @@ -cachetools-4.2.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -cachetools-4.2.2.dist-info/LICENSE,sha256=cJEEfa2G-tF5p3smluByDLAX4PRo1HT_PvXKLpe1qQY,1085 -cachetools-4.2.2.dist-info/METADATA,sha256=2-1CYiDO6nrahV7tMFhZBmh5AdoqIPL8gtoxsVAgYiA,4582 -cachetools-4.2.2.dist-info/RECORD,, -cachetools-4.2.2.dist-info/WHEEL,sha256=OqRkF0eY5GHssMorFjlbTIq072vpHpF60fIQA6lS9xA,92 -cachetools-4.2.2.dist-info/top_level.txt,sha256=ai2FH78TGwoBcCgVfoqbzk5IQCtnDukdSs4zKuVPvDs,11 -cachetools/__init__.py,sha256=INbZdXJjaPHFNkdeHh03OCeAKWOKvvtHeWM1rfrm7Lk,463 -cachetools/__pycache__/__init__.cpython-38.pyc,, -cachetools/__pycache__/cache.cpython-38.pyc,, -cachetools/__pycache__/decorators.cpython-38.pyc,, -cachetools/__pycache__/fifo.cpython-38.pyc,, -cachetools/__pycache__/func.cpython-38.pyc,, -cachetools/__pycache__/keys.cpython-38.pyc,, -cachetools/__pycache__/lfu.cpython-38.pyc,, -cachetools/__pycache__/lru.cpython-38.pyc,, -cachetools/__pycache__/mru.cpython-38.pyc,, -cachetools/__pycache__/rr.cpython-38.pyc,, -cachetools/__pycache__/ttl.cpython-38.pyc,, -cachetools/cache.py,sha256=8iJ0a0exyZk20UNdope-eTxC473Eiq3QHmkSOz95ojE,2886 -cachetools/decorators.py,sha256=7nKyHBQg3qNdCB_PqGXipjYwECeSXTznm5xzlAM8_Jo,2983 -cachetools/fifo.py,sha256=_T2rdopIZk7NfIOOw8FkZOtcVMUalSQt9BXisUFGzqE,946 -cachetools/func.py,sha256=OBTNzjaTlyZHKZkY812MuxrCHtuHWDTi7VTplN7vJs0,4975 -cachetools/keys.py,sha256=SfGPnF5Goo1b8V-lrhB9Jxgqd3vm80R9h50k0hsAAjM,1466 -cachetools/lfu.py,sha256=kFj6k_4E8ryoom2SiIXUpMWsCZktZ0TFSeCzoi-4aP0,1103 -cachetools/lru.py,sha256=LD-A5cVyMLyeTMENwuyNcqBcjZ_QnaWTPJX4-4ii9zs,1224 -cachetools/mru.py,sha256=7o99EG4Tg6BdoAPUNpiPmtxM3Paudw9whOONOcGLPkM,1244 -cachetools/rr.py,sha256=zxhJi_Qkp3BQ_1vxj1atAWONfANYzwJficGLmTTTuUs,948 -cachetools/ttl.py,sha256=kQng24LIBhvSDtzD2NRrr4mEbPN7NsyQlsOxbdffhKk,5769 diff --git a/venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/WHEEL b/venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/WHEEL deleted file mode 100644 index 385faab..0000000 --- a/venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: bdist_wheel (0.36.2) -Root-Is-Purelib: true -Tag: py3-none-any - diff --git a/venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/top_level.txt b/venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/top_level.txt deleted file mode 100644 index 50d1408..0000000 --- a/venv/lib/python3.8/site-packages/cachetools-4.2.2.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -cachetools diff --git a/venv/lib/python3.8/site-packages/cachetools/__init__.py b/venv/lib/python3.8/site-packages/cachetools/__init__.py deleted file mode 100644 index c9d37e2..0000000 --- a/venv/lib/python3.8/site-packages/cachetools/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -"""Extensible memoizing collections and decorators.""" - -from .cache import Cache -from .decorators import cached, cachedmethod -from .fifo import FIFOCache -from .lfu import LFUCache -from .lru import LRUCache -from .mru import MRUCache -from .rr import RRCache -from .ttl import TTLCache - -__all__ = ( - "Cache", - "FIFOCache", - "LFUCache", - "LRUCache", - "MRUCache", - "RRCache", - "TTLCache", - "cached", - "cachedmethod", -) - -__version__ = "4.2.2" diff --git a/venv/lib/python3.8/site-packages/cachetools/cache.py b/venv/lib/python3.8/site-packages/cachetools/cache.py deleted file mode 100644 index 973d50b..0000000 --- a/venv/lib/python3.8/site-packages/cachetools/cache.py +++ /dev/null @@ -1,117 +0,0 @@ -from collections.abc import MutableMapping - - -class _DefaultSize: - - __slots__ = () - - def __getitem__(self, _): - return 1 - - def __setitem__(self, _, value): - assert value == 1 - - def pop(self, _): - return 1 - - -class Cache(MutableMapping): - """Mutable mapping to serve as a simple cache or cache base class.""" - - __marker = object() - - __size = _DefaultSize() - - def __init__(self, maxsize, getsizeof=None): - if getsizeof: - self.getsizeof = getsizeof - if self.getsizeof is not Cache.getsizeof: - self.__size = dict() - self.__data = dict() - self.__currsize = 0 - self.__maxsize = maxsize - - def __repr__(self): - return "%s(%r, maxsize=%r, currsize=%r)" % ( - self.__class__.__name__, - list(self.__data.items()), - self.__maxsize, - self.__currsize, - ) - - def __getitem__(self, key): - try: - return self.__data[key] - except KeyError: - return self.__missing__(key) - - def __setitem__(self, key, value): - maxsize = self.__maxsize - size = self.getsizeof(value) - if size > maxsize: - raise ValueError("value too large") - if key not in self.__data or self.__size[key] < size: - while self.__currsize + size > maxsize: - self.popitem() - if key in self.__data: - diffsize = size - self.__size[key] - else: - diffsize = size - self.__data[key] = value - self.__size[key] = size - self.__currsize += diffsize - - def __delitem__(self, key): - size = self.__size.pop(key) - del self.__data[key] - self.__currsize -= size - - def __contains__(self, key): - return key in self.__data - - def __missing__(self, key): - raise KeyError(key) - - def __iter__(self): - return iter(self.__data) - - def __len__(self): - return len(self.__data) - - def get(self, key, default=None): - if key in self: - return self[key] - else: - return default - - def pop(self, key, default=__marker): - if key in self: - value = self[key] - del self[key] - elif default is self.__marker: - raise KeyError(key) - else: - value = default - return value - - def setdefault(self, key, default=None): - if key in self: - value = self[key] - else: - self[key] = value = default - return value - - @property - def maxsize(self): - """The maximum size of the cache.""" - return self.__maxsize - - @property - def currsize(self): - """The current size of the cache.""" - return self.__currsize - - @staticmethod - def getsizeof(value): - """Return the size of a cache element's value.""" - return 1 diff --git a/venv/lib/python3.8/site-packages/cachetools/decorators.py b/venv/lib/python3.8/site-packages/cachetools/decorators.py deleted file mode 100644 index 3e78603..0000000 --- a/venv/lib/python3.8/site-packages/cachetools/decorators.py +++ /dev/null @@ -1,102 +0,0 @@ -import functools - -from .keys import hashkey - - -def cached(cache, key=hashkey, lock=None): - """Decorator to wrap a function with a memoizing callable that saves - results in a cache. - - """ - - def decorator(func): - if cache is None: - - def wrapper(*args, **kwargs): - return func(*args, **kwargs) - - elif lock is None: - - def wrapper(*args, **kwargs): - k = key(*args, **kwargs) - try: - return cache[k] - except KeyError: - pass # key not found - v = func(*args, **kwargs) - try: - cache[k] = v - except ValueError: - pass # value too large - return v - - else: - - def wrapper(*args, **kwargs): - k = key(*args, **kwargs) - try: - with lock: - return cache[k] - except KeyError: - pass # key not found - v = func(*args, **kwargs) - # in case of a race, prefer the item already in the cache - try: - with lock: - return cache.setdefault(k, v) - except ValueError: - return v # value too large - - return functools.update_wrapper(wrapper, func) - - return decorator - - -def cachedmethod(cache, key=hashkey, lock=None): - """Decorator to wrap a class or instance method with a memoizing - callable that saves results in a cache. - - """ - - def decorator(method): - if lock is None: - - def wrapper(self, *args, **kwargs): - c = cache(self) - if c is None: - return method(self, *args, **kwargs) - k = key(*args, **kwargs) - try: - return c[k] - except KeyError: - pass # key not found - v = method(self, *args, **kwargs) - try: - c[k] = v - except ValueError: - pass # value too large - return v - - else: - - def wrapper(self, *args, **kwargs): - c = cache(self) - if c is None: - return method(self, *args, **kwargs) - k = key(*args, **kwargs) - try: - with lock(self): - return c[k] - except KeyError: - pass # key not found - v = method(self, *args, **kwargs) - # in case of a race, prefer the item already in the cache - try: - with lock(self): - return c.setdefault(k, v) - except ValueError: - return v # value too large - - return functools.update_wrapper(wrapper, method) - - return decorator diff --git a/venv/lib/python3.8/site-packages/cachetools/fifo.py b/venv/lib/python3.8/site-packages/cachetools/fifo.py deleted file mode 100644 index e7c377e..0000000 --- a/venv/lib/python3.8/site-packages/cachetools/fifo.py +++ /dev/null @@ -1,31 +0,0 @@ -import collections - -from .cache import Cache - - -class FIFOCache(Cache): - """First In First Out (FIFO) cache implementation.""" - - def __init__(self, maxsize, getsizeof=None): - Cache.__init__(self, maxsize, getsizeof) - self.__order = collections.OrderedDict() - - def __setitem__(self, key, value, cache_setitem=Cache.__setitem__): - cache_setitem(self, key, value) - try: - self.__order.move_to_end(key) - except KeyError: - self.__order[key] = None - - def __delitem__(self, key, cache_delitem=Cache.__delitem__): - cache_delitem(self, key) - del self.__order[key] - - def popitem(self): - """Remove and return the `(key, value)` pair first inserted.""" - try: - key = next(iter(self.__order)) - except StopIteration: - raise KeyError("%s is empty" % type(self).__name__) from None - else: - return (key, self.pop(key)) diff --git a/venv/lib/python3.8/site-packages/cachetools/func.py b/venv/lib/python3.8/site-packages/cachetools/func.py deleted file mode 100644 index 57fb72d..0000000 --- a/venv/lib/python3.8/site-packages/cachetools/func.py +++ /dev/null @@ -1,176 +0,0 @@ -"""`functools.lru_cache` compatible memoizing function decorators.""" - -import collections -import functools -import math -import random -import time - -try: - from threading import RLock -except ImportError: # pragma: no cover - from dummy_threading import RLock - -from . import keys -from .fifo import FIFOCache -from .lfu import LFUCache -from .lru import LRUCache -from .mru import MRUCache -from .rr import RRCache -from .ttl import TTLCache - -__all__ = ("lfu_cache", "lru_cache", "mru_cache", "rr_cache", "ttl_cache") - - -_CacheInfo = collections.namedtuple( - "CacheInfo", ["hits", "misses", "maxsize", "currsize"] -) - - -class _UnboundCache(dict): - @property - def maxsize(self): - return None - - @property - def currsize(self): - return len(self) - - -class _UnboundTTLCache(TTLCache): - def __init__(self, ttl, timer): - TTLCache.__init__(self, math.inf, ttl, timer) - - @property - def maxsize(self): - return None - - -def _cache(cache, typed): - maxsize = cache.maxsize - - def decorator(func): - key = keys.typedkey if typed else keys.hashkey - lock = RLock() - stats = [0, 0] - - def wrapper(*args, **kwargs): - k = key(*args, **kwargs) - with lock: - try: - v = cache[k] - stats[0] += 1 - return v - except KeyError: - stats[1] += 1 - v = func(*args, **kwargs) - # in case of a race, prefer the item already in the cache - try: - with lock: - return cache.setdefault(k, v) - except ValueError: - return v # value too large - - def cache_info(): - with lock: - hits, misses = stats - maxsize = cache.maxsize - currsize = cache.currsize - return _CacheInfo(hits, misses, maxsize, currsize) - - def cache_clear(): - with lock: - try: - cache.clear() - finally: - stats[:] = [0, 0] - - wrapper.cache_info = cache_info - wrapper.cache_clear = cache_clear - wrapper.cache_parameters = lambda: {"maxsize": maxsize, "typed": typed} - functools.update_wrapper(wrapper, func) - return wrapper - - return decorator - - -def fifo_cache(maxsize=128, typed=False): - """Decorator to wrap a function with a memoizing callable that saves - up to `maxsize` results based on a First In First Out (FIFO) - algorithm. - - """ - if maxsize is None: - return _cache(_UnboundCache(), typed) - elif callable(maxsize): - return _cache(FIFOCache(128), typed)(maxsize) - else: - return _cache(FIFOCache(maxsize), typed) - - -def lfu_cache(maxsize=128, typed=False): - """Decorator to wrap a function with a memoizing callable that saves - up to `maxsize` results based on a Least Frequently Used (LFU) - algorithm. - - """ - if maxsize is None: - return _cache(_UnboundCache(), typed) - elif callable(maxsize): - return _cache(LFUCache(128), typed)(maxsize) - else: - return _cache(LFUCache(maxsize), typed) - - -def lru_cache(maxsize=128, typed=False): - """Decorator to wrap a function with a memoizing callable that saves - up to `maxsize` results based on a Least Recently Used (LRU) - algorithm. - - """ - if maxsize is None: - return _cache(_UnboundCache(), typed) - elif callable(maxsize): - return _cache(LRUCache(128), typed)(maxsize) - else: - return _cache(LRUCache(maxsize), typed) - - -def mru_cache(maxsize=128, typed=False): - """Decorator to wrap a function with a memoizing callable that saves - up to `maxsize` results based on a Most Recently Used (MRU) - algorithm. - """ - if maxsize is None: - return _cache(_UnboundCache(), typed) - elif callable(maxsize): - return _cache(MRUCache(128), typed)(maxsize) - else: - return _cache(MRUCache(maxsize), typed) - - -def rr_cache(maxsize=128, choice=random.choice, typed=False): - """Decorator to wrap a function with a memoizing callable that saves - up to `maxsize` results based on a Random Replacement (RR) - algorithm. - - """ - if maxsize is None: - return _cache(_UnboundCache(), typed) - elif callable(maxsize): - return _cache(RRCache(128, choice), typed)(maxsize) - else: - return _cache(RRCache(maxsize, choice), typed) - - -def ttl_cache(maxsize=128, ttl=600, timer=time.monotonic, typed=False): - """Decorator to wrap a function with a memoizing callable that saves - up to `maxsize` results based on a Least Recently Used (LRU) - algorithm with a per-item time-to-live (TTL) value. - """ - if maxsize is None: - return _cache(_UnboundTTLCache(ttl, timer), typed) - elif callable(maxsize): - return _cache(TTLCache(128, ttl, timer), typed)(maxsize) - else: - return _cache(TTLCache(maxsize, ttl, timer), typed) diff --git a/venv/lib/python3.8/site-packages/cachetools/keys.py b/venv/lib/python3.8/site-packages/cachetools/keys.py deleted file mode 100644 index 13630a4..0000000 --- a/venv/lib/python3.8/site-packages/cachetools/keys.py +++ /dev/null @@ -1,52 +0,0 @@ -"""Key functions for memoizing decorators.""" - -__all__ = ("hashkey", "typedkey") - - -class _HashedTuple(tuple): - """A tuple that ensures that hash() will be called no more than once - per element, since cache decorators will hash the key multiple - times on a cache miss. See also _HashedSeq in the standard - library functools implementation. - - """ - - __hashvalue = None - - def __hash__(self, hash=tuple.__hash__): - hashvalue = self.__hashvalue - if hashvalue is None: - self.__hashvalue = hashvalue = hash(self) - return hashvalue - - def __add__(self, other, add=tuple.__add__): - return _HashedTuple(add(self, other)) - - def __radd__(self, other, add=tuple.__add__): - return _HashedTuple(add(other, self)) - - def __getstate__(self): - return {} - - -# used for separating keyword arguments; we do not use an object -# instance here so identity is preserved when pickling/unpickling -_kwmark = (_HashedTuple,) - - -def hashkey(*args, **kwargs): - """Return a cache key for the specified hashable arguments.""" - - if kwargs: - return _HashedTuple(args + sum(sorted(kwargs.items()), _kwmark)) - else: - return _HashedTuple(args) - - -def typedkey(*args, **kwargs): - """Return a typed cache key for the specified hashable arguments.""" - - key = hashkey(*args, **kwargs) - key += tuple(type(v) for v in args) - key += tuple(type(v) for _, v in sorted(kwargs.items())) - return key diff --git a/venv/lib/python3.8/site-packages/cachetools/lfu.py b/venv/lib/python3.8/site-packages/cachetools/lfu.py deleted file mode 100644 index 6289b5c..0000000 --- a/venv/lib/python3.8/site-packages/cachetools/lfu.py +++ /dev/null @@ -1,34 +0,0 @@ -import collections - -from .cache import Cache - - -class LFUCache(Cache): - """Least Frequently Used (LFU) cache implementation.""" - - def __init__(self, maxsize, getsizeof=None): - Cache.__init__(self, maxsize, getsizeof) - self.__counter = collections.Counter() - - def __getitem__(self, key, cache_getitem=Cache.__getitem__): - value = cache_getitem(self, key) - if key in self: # __missing__ may not store item - self.__counter[key] -= 1 - return value - - def __setitem__(self, key, value, cache_setitem=Cache.__setitem__): - cache_setitem(self, key, value) - self.__counter[key] -= 1 - - def __delitem__(self, key, cache_delitem=Cache.__delitem__): - cache_delitem(self, key) - del self.__counter[key] - - def popitem(self): - """Remove and return the `(key, value)` pair least frequently used.""" - try: - ((key, _),) = self.__counter.most_common(1) - except ValueError: - raise KeyError("%s is empty" % type(self).__name__) from None - else: - return (key, self.pop(key)) diff --git a/venv/lib/python3.8/site-packages/cachetools/lru.py b/venv/lib/python3.8/site-packages/cachetools/lru.py deleted file mode 100644 index dbbe787..0000000 --- a/venv/lib/python3.8/site-packages/cachetools/lru.py +++ /dev/null @@ -1,40 +0,0 @@ -import collections - -from .cache import Cache - - -class LRUCache(Cache): - """Least Recently Used (LRU) cache implementation.""" - - def __init__(self, maxsize, getsizeof=None): - Cache.__init__(self, maxsize, getsizeof) - self.__order = collections.OrderedDict() - - def __getitem__(self, key, cache_getitem=Cache.__getitem__): - value = cache_getitem(self, key) - if key in self: # __missing__ may not store item - self.__update(key) - return value - - def __setitem__(self, key, value, cache_setitem=Cache.__setitem__): - cache_setitem(self, key, value) - self.__update(key) - - def __delitem__(self, key, cache_delitem=Cache.__delitem__): - cache_delitem(self, key) - del self.__order[key] - - def popitem(self): - """Remove and return the `(key, value)` pair least recently used.""" - try: - key = next(iter(self.__order)) - except StopIteration: - raise KeyError("%s is empty" % type(self).__name__) from None - else: - return (key, self.pop(key)) - - def __update(self, key): - try: - self.__order.move_to_end(key) - except KeyError: - self.__order[key] = None diff --git a/venv/lib/python3.8/site-packages/cachetools/mru.py b/venv/lib/python3.8/site-packages/cachetools/mru.py deleted file mode 100644 index 92ec6db..0000000 --- a/venv/lib/python3.8/site-packages/cachetools/mru.py +++ /dev/null @@ -1,40 +0,0 @@ -import collections - -from cachetools.cache import Cache - - -class MRUCache(Cache): - """Most Recently Used (MRU) cache implementation.""" - - def __init__(self, maxsize, getsizeof=None): - Cache.__init__(self, maxsize, getsizeof) - self.__order = collections.OrderedDict() - - def __getitem__(self, key, cache_getitem=Cache.__getitem__): - value = cache_getitem(self, key) - if key in self: # __missing__ may not store item - self.__update(key) - return value - - def __setitem__(self, key, value, cache_setitem=Cache.__setitem__): - cache_setitem(self, key, value) - self.__update(key) - - def __delitem__(self, key, cache_delitem=Cache.__delitem__): - cache_delitem(self, key) - del self.__order[key] - - def popitem(self): - """Remove and return the `(key, value)` pair most recently used.""" - try: - key = next(iter(self.__order)) - except StopIteration: - raise KeyError("%s is empty" % type(self).__name__) from None - else: - return (key, self.pop(key)) - - def __update(self, key): - try: - self.__order.move_to_end(key, last=False) - except KeyError: - self.__order[key] = None diff --git a/venv/lib/python3.8/site-packages/cachetools/rr.py b/venv/lib/python3.8/site-packages/cachetools/rr.py deleted file mode 100644 index 561dbe5..0000000 --- a/venv/lib/python3.8/site-packages/cachetools/rr.py +++ /dev/null @@ -1,34 +0,0 @@ -import random - -from .cache import Cache - - -# random.choice cannot be pickled in Python 2.7 -def _choice(seq): - return random.choice(seq) - - -class RRCache(Cache): - """Random Replacement (RR) cache implementation.""" - - def __init__(self, maxsize, choice=random.choice, getsizeof=None): - Cache.__init__(self, maxsize, getsizeof) - # TODO: use None as default, assing to self.choice directly? - if choice is random.choice: - self.__choice = _choice - else: - self.__choice = choice - - @property - def choice(self): - """The `choice` function used by the cache.""" - return self.__choice - - def popitem(self): - """Remove and return a random `(key, value)` pair.""" - try: - key = self.__choice(list(self)) - except IndexError: - raise KeyError("%s is empty" % type(self).__name__) from None - else: - return (key, self.pop(key)) diff --git a/venv/lib/python3.8/site-packages/cachetools/ttl.py b/venv/lib/python3.8/site-packages/cachetools/ttl.py deleted file mode 100644 index eef8877..0000000 --- a/venv/lib/python3.8/site-packages/cachetools/ttl.py +++ /dev/null @@ -1,207 +0,0 @@ -import collections -import time - -from .cache import Cache - - -class _Link: - - __slots__ = ("key", "expire", "next", "prev") - - def __init__(self, key=None, expire=None): - self.key = key - self.expire = expire - - def __reduce__(self): - return _Link, (self.key, self.expire) - - def unlink(self): - next = self.next - prev = self.prev - prev.next = next - next.prev = prev - - -class _Timer: - def __init__(self, timer): - self.__timer = timer - self.__nesting = 0 - - def __call__(self): - if self.__nesting == 0: - return self.__timer() - else: - return self.__time - - def __enter__(self): - if self.__nesting == 0: - self.__time = time = self.__timer() - else: - time = self.__time - self.__nesting += 1 - return time - - def __exit__(self, *exc): - self.__nesting -= 1 - - def __reduce__(self): - return _Timer, (self.__timer,) - - def __getattr__(self, name): - return getattr(self.__timer, name) - - -class TTLCache(Cache): - """LRU Cache implementation with per-item time-to-live (TTL) value.""" - - def __init__(self, maxsize, ttl, timer=time.monotonic, getsizeof=None): - Cache.__init__(self, maxsize, getsizeof) - self.__root = root = _Link() - root.prev = root.next = root - self.__links = collections.OrderedDict() - self.__timer = _Timer(timer) - self.__ttl = ttl - - def __contains__(self, key): - try: - link = self.__links[key] # no reordering - except KeyError: - return False - else: - return not (link.expire < self.__timer()) - - def __getitem__(self, key, cache_getitem=Cache.__getitem__): - try: - link = self.__getlink(key) - except KeyError: - expired = False - else: - expired = link.expire < self.__timer() - if expired: - return self.__missing__(key) - else: - return cache_getitem(self, key) - - def __setitem__(self, key, value, cache_setitem=Cache.__setitem__): - with self.__timer as time: - self.expire(time) - cache_setitem(self, key, value) - try: - link = self.__getlink(key) - except KeyError: - self.__links[key] = link = _Link(key) - else: - link.unlink() - link.expire = time + self.__ttl - link.next = root = self.__root - link.prev = prev = root.prev - prev.next = root.prev = link - - def __delitem__(self, key, cache_delitem=Cache.__delitem__): - cache_delitem(self, key) - link = self.__links.pop(key) - link.unlink() - if link.expire < self.__timer(): - raise KeyError(key) - - def __iter__(self): - root = self.__root - curr = root.next - while curr is not root: - # "freeze" time for iterator access - with self.__timer as time: - if not (curr.expire < time): - yield curr.key - curr = curr.next - - def __len__(self): - root = self.__root - curr = root.next - time = self.__timer() - count = len(self.__links) - while curr is not root and curr.expire < time: - count -= 1 - curr = curr.next - return count - - def __setstate__(self, state): - self.__dict__.update(state) - root = self.__root - root.prev = root.next = root - for link in sorted(self.__links.values(), key=lambda obj: obj.expire): - link.next = root - link.prev = prev = root.prev - prev.next = root.prev = link - self.expire(self.__timer()) - - def __repr__(self, cache_repr=Cache.__repr__): - with self.__timer as time: - self.expire(time) - return cache_repr(self) - - @property - def currsize(self): - with self.__timer as time: - self.expire(time) - return super().currsize - - @property - def timer(self): - """The timer function used by the cache.""" - return self.__timer - - @property - def ttl(self): - """The time-to-live value of the cache's items.""" - return self.__ttl - - def expire(self, time=None): - """Remove expired items from the cache.""" - if time is None: - time = self.__timer() - root = self.__root - curr = root.next - links = self.__links - cache_delitem = Cache.__delitem__ - while curr is not root and curr.expire < time: - cache_delitem(self, curr.key) - del links[curr.key] - next = curr.next - curr.unlink() - curr = next - - def clear(self): - with self.__timer as time: - self.expire(time) - Cache.clear(self) - - def get(self, *args, **kwargs): - with self.__timer: - return Cache.get(self, *args, **kwargs) - - def pop(self, *args, **kwargs): - with self.__timer: - return Cache.pop(self, *args, **kwargs) - - def setdefault(self, *args, **kwargs): - with self.__timer: - return Cache.setdefault(self, *args, **kwargs) - - def popitem(self): - """Remove and return the `(key, value)` pair least recently used that - has not already expired. - - """ - with self.__timer as time: - self.expire(time) - try: - key = next(iter(self.__links)) - except StopIteration: - raise KeyError("%s is empty" % type(self).__name__) from None - else: - return (key, self.pop(key)) - - def __getlink(self, key): - value = self.__links[key] - self.__links.move_to_end(key) - return value diff --git a/venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/INSTALLER b/venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/LICENSE b/venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/LICENSE deleted file mode 100644 index c2fda9a..0000000 --- a/venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -This package contains a modified version of ca-bundle.crt: - -ca-bundle.crt -- Bundle of CA Root Certificates - -Certificate data from Mozilla as of: Thu Nov 3 19:04:19 2011# -This is a bundle of X.509 certificates of public Certificate Authorities -(CA). These were automatically extracted from Mozilla's root certificates -file (certdata.txt). This file can be found in the mozilla source tree: -http://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1# -It contains the certificates in PEM format and therefore -can be directly used with curl / libcurl / php_curl, or with -an Apache+mod_ssl webserver for SSL client authentication. -Just configure this file as the SSLCACertificateFile.# - -***** BEGIN LICENSE BLOCK ***** -This Source Code Form is subject to the terms of the Mozilla Public License, -v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain -one at http://mozilla.org/MPL/2.0/. - -***** END LICENSE BLOCK ***** -@(#) $RCSfile: certdata.txt,v $ $Revision: 1.80 $ $Date: 2011/11/03 15:11:58 $ diff --git a/venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/METADATA b/venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/METADATA deleted file mode 100644 index df1cc0e..0000000 --- a/venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/METADATA +++ /dev/null @@ -1,83 +0,0 @@ -Metadata-Version: 2.1 -Name: certifi -Version: 2021.5.30 -Summary: Python package for providing Mozilla's CA Bundle. -Home-page: https://certifiio.readthedocs.io/en/latest/ -Author: Kenneth Reitz -Author-email: me@kennethreitz.com -License: MPL-2.0 -Project-URL: Documentation, https://certifiio.readthedocs.io/en/latest/ -Project-URL: Source, https://github.com/certifi/python-certifi -Platform: UNKNOWN -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0) -Classifier: Natural Language :: English -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.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 - -Certifi: Python SSL Certificates -================================ - -`Certifi`_ provides Mozilla's carefully curated collection of Root Certificates for -validating the trustworthiness of SSL certificates while verifying the identity -of TLS hosts. It has been extracted from the `Requests`_ project. - -Installation ------------- - -``certifi`` is available on PyPI. Simply install it with ``pip``:: - - $ pip install certifi - -Usage ------ - -To reference the installed certificate authority (CA) bundle, you can use the -built-in function:: - - >>> import certifi - - >>> certifi.where() - '/usr/local/lib/python3.7/site-packages/certifi/cacert.pem' - -Or from the command line:: - - $ python -m certifi - /usr/local/lib/python3.7/site-packages/certifi/cacert.pem - -Enjoy! - -1024-bit Root Certificates -~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Browsers and certificate authorities have concluded that 1024-bit keys are -unacceptably weak for certificates, particularly root certificates. For this -reason, Mozilla has removed any weak (i.e. 1024-bit key) certificate from its -bundle, replacing it with an equivalent strong (i.e. 2048-bit or greater key) -certificate from the same CA. Because Mozilla removed these certificates from -its bundle, ``certifi`` removed them as well. - -In previous versions, ``certifi`` provided the ``certifi.old_where()`` function -to intentionally re-add the 1024-bit roots back into your bundle. This was not -recommended in production and therefore was removed at the end of 2018. - -.. _`Certifi`: https://certifiio.readthedocs.io/en/latest/ -.. _`Requests`: https://requests.readthedocs.io/en/master/ - -Addition/Removal of Certificates --------------------------------- - -Certifi does not support any addition/removal or other modification of the -CA trust store content. This project is intended to provide a reliable and -highly portable root of trust to python deployments. Look to upstream projects -for methods to use alternate trust. - - diff --git a/venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/RECORD b/venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/RECORD deleted file mode 100644 index f2d2621..0000000 --- a/venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/RECORD +++ /dev/null @@ -1,13 +0,0 @@ -certifi-2021.5.30.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -certifi-2021.5.30.dist-info/LICENSE,sha256=vp2C82ES-Hp_HXTs1Ih-FGe7roh4qEAEoAEXseR1o-I,1049 -certifi-2021.5.30.dist-info/METADATA,sha256=RDzuah_IZxjVhKootR1Ha1BrDovPSA-xF-rcaD90PTo,2994 -certifi-2021.5.30.dist-info/RECORD,, -certifi-2021.5.30.dist-info/WHEEL,sha256=ADKeyaGyKF5DwBNE0sRE5pvW-bSkFMJfBuhzZ3rceP4,110 -certifi-2021.5.30.dist-info/top_level.txt,sha256=KMu4vUCfsjLrkPbSNdgdekS-pVJzBAJFO__nI8NF6-U,8 -certifi/__init__.py,sha256=-b78tXibbl0qtgCzv9tc9v6ozwcNX915lT9Tf4a9lds,62 -certifi/__main__.py,sha256=xBBoj905TUWBLRGANOcf7oi6e-3dMP4cEoG9OyMs11g,243 -certifi/__pycache__/__init__.cpython-38.pyc,, -certifi/__pycache__/__main__.cpython-38.pyc,, -certifi/__pycache__/core.cpython-38.pyc,, -certifi/cacert.pem,sha256=3i-hfE2K5o3CBKG2tYt6ehJWk2fP64o6Th83fHPoPp4,259465 -certifi/core.py,sha256=V0uyxKOYdz6ulDSusclrLmjbPgOXsD0BnEf0SQ7OnoE,2303 diff --git a/venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/WHEEL b/venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/WHEEL deleted file mode 100644 index 6d38aa0..0000000 --- a/venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/WHEEL +++ /dev/null @@ -1,6 +0,0 @@ -Wheel-Version: 1.0 -Generator: bdist_wheel (0.35.1) -Root-Is-Purelib: true -Tag: py2-none-any -Tag: py3-none-any - diff --git a/venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/top_level.txt b/venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/top_level.txt deleted file mode 100644 index 963eac5..0000000 --- a/venv/lib/python3.8/site-packages/certifi-2021.5.30.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -certifi diff --git a/venv/lib/python3.8/site-packages/certifi/__init__.py b/venv/lib/python3.8/site-packages/certifi/__init__.py deleted file mode 100644 index eebdf88..0000000 --- a/venv/lib/python3.8/site-packages/certifi/__init__.py +++ /dev/null @@ -1,3 +0,0 @@ -from .core import contents, where - -__version__ = "2021.05.30" diff --git a/venv/lib/python3.8/site-packages/certifi/__main__.py b/venv/lib/python3.8/site-packages/certifi/__main__.py deleted file mode 100644 index 8945b5d..0000000 --- a/venv/lib/python3.8/site-packages/certifi/__main__.py +++ /dev/null @@ -1,12 +0,0 @@ -import argparse - -from certifi import contents, where - -parser = argparse.ArgumentParser() -parser.add_argument("-c", "--contents", action="store_true") -args = parser.parse_args() - -if args.contents: - print(contents()) -else: - print(where()) diff --git a/venv/lib/python3.8/site-packages/certifi/cacert.pem b/venv/lib/python3.8/site-packages/certifi/cacert.pem deleted file mode 100644 index 96e2fc6..0000000 --- a/venv/lib/python3.8/site-packages/certifi/cacert.pem +++ /dev/null @@ -1,4257 +0,0 @@ - -# Issuer: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA -# Subject: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA -# Label: "GlobalSign Root CA" -# Serial: 4835703278459707669005204 -# MD5 Fingerprint: 3e:45:52:15:09:51:92:e1:b7:5d:37:9f:b1:87:29:8a -# SHA1 Fingerprint: b1:bc:96:8b:d4:f4:9d:62:2a:a8:9a:81:f2:15:01:52:a4:1d:82:9c -# SHA256 Fingerprint: eb:d4:10:40:e4:bb:3e:c7:42:c9:e3:81:d3:1e:f2:a4:1a:48:b6:68:5c:96:e7:ce:f3:c1:df:6c:d4:33:1c:99 ------BEGIN CERTIFICATE----- -MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG -A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv -b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw -MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i -YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT -aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ -jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp -xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp -1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG -snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ -U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 -9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E -BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B -AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz -yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE -38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP -AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad -DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME -HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== ------END CERTIFICATE----- - -# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R2 -# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R2 -# Label: "GlobalSign Root CA - R2" -# Serial: 4835703278459682885658125 -# MD5 Fingerprint: 94:14:77:7e:3e:5e:fd:8f:30:bd:41:b0:cf:e7:d0:30 -# SHA1 Fingerprint: 75:e0:ab:b6:13:85:12:27:1c:04:f8:5f:dd:de:38:e4:b7:24:2e:fe -# SHA256 Fingerprint: ca:42:dd:41:74:5f:d0:b8:1e:b9:02:36:2c:f9:d8:bf:71:9d:a1:bd:1b:1e:fc:94:6f:5b:4c:99:f4:2c:1b:9e ------BEGIN CERTIFICATE----- -MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G -A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp -Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1 -MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG -A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL -v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8 -eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq -tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd -C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa -zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB -mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH -V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n -bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG -3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs -J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO -291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS -ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd -AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7 -TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg== ------END CERTIFICATE----- - -# Issuer: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited -# Subject: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited -# Label: "Entrust.net Premium 2048 Secure Server CA" -# Serial: 946069240 -# MD5 Fingerprint: ee:29:31:bc:32:7e:9a:e6:e8:b5:f7:51:b4:34:71:90 -# SHA1 Fingerprint: 50:30:06:09:1d:97:d4:f5:ae:39:f7:cb:e7:92:7d:7d:65:2d:34:31 -# SHA256 Fingerprint: 6d:c4:71:72:e0:1c:bc:b0:bf:62:58:0d:89:5f:e2:b8:ac:9a:d4:f8:73:80:1e:0c:10:b9:c8:37:d2:1e:b1:77 ------BEGIN CERTIFICATE----- -MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML -RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp -bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 -IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp -ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0yOTA3 -MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 -LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp -YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG -A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq -K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe -sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX -MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT -XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ -HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH -4QIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV -HQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJKoZIhvcNAQEFBQADggEBADub -j1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPyT/4xmf3IDExo -U8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf -zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5b -u/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+ -bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er -fF6adulZkMV8gzURZVE= ------END CERTIFICATE----- - -# Issuer: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust -# Subject: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust -# Label: "Baltimore CyberTrust Root" -# Serial: 33554617 -# MD5 Fingerprint: ac:b6:94:a5:9c:17:e0:d7:91:52:9b:b1:97:06:a6:e4 -# SHA1 Fingerprint: d4:de:20:d0:5e:66:fc:53:fe:1a:50:88:2c:78:db:28:52:ca:e4:74 -# SHA256 Fingerprint: 16:af:57:a9:f6:76:b0:ab:12:60:95:aa:5e:ba:de:f2:2a:b3:11:19:d6:44:ac:95:cd:4b:93:db:f3:f2:6a:eb ------BEGIN CERTIFICATE----- -MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ -RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD -VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX -DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y -ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy -VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr -mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr -IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK -mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu -XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy -dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye -jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1 -BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 -DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92 -9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx -jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 -Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz -ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS -R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp ------END CERTIFICATE----- - -# Issuer: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc. -# Subject: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc. -# Label: "Entrust Root Certification Authority" -# Serial: 1164660820 -# MD5 Fingerprint: d6:a5:c3:ed:5d:dd:3e:00:c1:3d:87:92:1f:1d:3f:e4 -# SHA1 Fingerprint: b3:1e:b1:b7:40:e3:6c:84:02:da:dc:37:d4:4d:f5:d4:67:49:52:f9 -# SHA256 Fingerprint: 73:c1:76:43:4f:1b:c6:d5:ad:f4:5b:0e:76:e7:27:28:7c:8d:e5:76:16:c1:e6:e6:14:1a:2b:2c:bc:7d:8e:4c ------BEGIN CERTIFICATE----- -MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC -VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 -Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW -KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl -cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw -NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw -NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy -ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV -BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ -KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo -Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4 -4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9 -KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI -rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi -94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB -sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi -gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo -kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE -vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA -A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t -O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua -AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP -9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/ -eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m -0vdXcDazv/wor3ElhVsT/h5/WrQ8 ------END CERTIFICATE----- - -# Issuer: CN=AAA Certificate Services O=Comodo CA Limited -# Subject: CN=AAA Certificate Services O=Comodo CA Limited -# Label: "Comodo AAA Services root" -# Serial: 1 -# MD5 Fingerprint: 49:79:04:b0:eb:87:19:ac:47:b0:bc:11:51:9b:74:d0 -# SHA1 Fingerprint: d1:eb:23:a4:6d:17:d6:8f:d9:25:64:c2:f1:f1:60:17:64:d8:e3:49 -# SHA256 Fingerprint: d7:a7:a0:fb:5d:7e:27:31:d7:71:e9:48:4e:bc:de:f7:1d:5f:0c:3e:0a:29:48:78:2b:c8:3e:e0:ea:69:9e:f4 ------BEGIN CERTIFICATE----- -MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb -MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow -GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj -YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL -MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE -BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM -GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP -ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua -BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe -3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4 -YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR -rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm -ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU -oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF -MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v -QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t -b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF -AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q -GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz -Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2 -G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi -l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3 -smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== ------END CERTIFICATE----- - -# Issuer: CN=QuoVadis Root CA 2 O=QuoVadis Limited -# Subject: CN=QuoVadis Root CA 2 O=QuoVadis Limited -# Label: "QuoVadis Root CA 2" -# Serial: 1289 -# MD5 Fingerprint: 5e:39:7b:dd:f8:ba:ec:82:e9:ac:62:ba:0c:54:00:2b -# SHA1 Fingerprint: ca:3a:fb:cf:12:40:36:4b:44:b2:16:20:88:80:48:39:19:93:7c:f7 -# SHA256 Fingerprint: 85:a0:dd:7d:d7:20:ad:b7:ff:05:f8:3d:54:2b:20:9d:c7:ff:45:28:f7:d6:77:b1:83:89:fe:a5:e5:c4:9e:86 ------BEGIN CERTIFICATE----- -MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x -GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv -b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV -BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W -YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa -GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg -Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J -WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB -rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp -+ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1 -ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i -Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz -PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og -/zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH -oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI -yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud -EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2 -A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL -MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT -ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f -BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn -g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl -fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K -WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha -B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc -hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR -TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD -mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z -ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y -4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza -8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u ------END CERTIFICATE----- - -# Issuer: CN=QuoVadis Root CA 3 O=QuoVadis Limited -# Subject: CN=QuoVadis Root CA 3 O=QuoVadis Limited -# Label: "QuoVadis Root CA 3" -# Serial: 1478 -# MD5 Fingerprint: 31:85:3c:62:94:97:63:b9:aa:fd:89:4e:af:6f:e0:cf -# SHA1 Fingerprint: 1f:49:14:f7:d8:74:95:1d:dd:ae:02:c0:be:fd:3a:2d:82:75:51:85 -# SHA256 Fingerprint: 18:f1:fc:7f:20:5d:f8:ad:dd:eb:7f:e0:07:dd:57:e3:af:37:5a:9c:4d:8d:73:54:6b:f4:f1:fe:d1:e1:8d:35 ------BEGIN CERTIFICATE----- -MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x -GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv -b3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNV -BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W -YWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM -V0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNggDhoB -4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUr -H556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd -8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9Cabwv -vWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLT -mZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhe -btfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjc -T5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDt -WAEXMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZ -c6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A -4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYD -VR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMwgcUwgZMG -CCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0 -aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0 -aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu -dC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2Nw -czALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4G -A1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJC -TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMg -Um9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM0 -7ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSem -d1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd -+LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B -4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadN -t54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6x -DYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57 -k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6s -zHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0j -Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT -mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK -4SVhM7JZG+Ju1zdXtg2pEto= ------END CERTIFICATE----- - -# Issuer: O=SECOM Trust.net OU=Security Communication RootCA1 -# Subject: O=SECOM Trust.net OU=Security Communication RootCA1 -# Label: "Security Communication Root CA" -# Serial: 0 -# MD5 Fingerprint: f1:bc:63:6a:54:e0:b5:27:f5:cd:e7:1a:e3:4d:6e:4a -# SHA1 Fingerprint: 36:b1:2b:49:f9:81:9e:d7:4c:9e:bc:38:0f:c6:56:8f:5d:ac:b2:f7 -# SHA256 Fingerprint: e7:5e:72:ed:9f:56:0e:ec:6e:b4:80:00:73:a4:3f:c3:ad:19:19:5a:39:22:82:01:78:95:97:4a:99:02:6b:6c ------BEGIN CERTIFICATE----- -MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEY -MBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21t -dW5pY2F0aW9uIFJvb3RDQTEwHhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5 -WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYD -VQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEwggEiMA0GCSqGSIb3 -DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw8yl8 -9f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJ -DKaVv0uMDPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9 -Ms+k2Y7CI9eNqPPYJayX5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/N -QV3Is00qVUarH9oe4kA92819uZKAnDfdDJZkndwi92SL32HeFZRSFaB9UslLqCHJ -xrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2JChzAgMBAAGjPzA9MB0G -A1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYwDwYDVR0T -AQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vG -kl3g0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfr -Uj94nK9NrvjVT8+amCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5 -Bw+SUEmK3TGXX8npN6o7WWWXlDLJs58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJU -JRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ6rBK+1YWc26sTfcioU+tHXot -RSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAiFL39vmwLAw== ------END CERTIFICATE----- - -# Issuer: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com -# Subject: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com -# Label: "XRamp Global CA Root" -# Serial: 107108908803651509692980124233745014957 -# MD5 Fingerprint: a1:0b:44:b3:ca:10:d8:00:6e:9d:0f:d8:0f:92:0a:d1 -# SHA1 Fingerprint: b8:01:86:d1:eb:9c:86:a5:41:04:cf:30:54:f3:4c:52:b7:e5:58:c6 -# SHA256 Fingerprint: ce:cd:dc:90:50:99:d8:da:df:c5:b1:d2:09:b7:37:cb:e2:c1:8c:fb:2c:10:c0:ff:0b:cf:0d:32:86:fc:1a:a2 ------BEGIN CERTIFICATE----- -MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB -gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk -MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY -UmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcx -NDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3 -dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2Vy -dmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB -dXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS6 -38eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP -KZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7Q -DxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4 -qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRa -JSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNVi -PvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0P -BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs -jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0 -eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQAD -ggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR -vbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt -qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa -IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy -i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ -O+7ETPTsJ3xCwnR8gooJybQDJbw= ------END CERTIFICATE----- - -# Issuer: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority -# Subject: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority -# Label: "Go Daddy Class 2 CA" -# Serial: 0 -# MD5 Fingerprint: 91:de:06:25:ab:da:fd:32:17:0c:bb:25:17:2a:84:67 -# SHA1 Fingerprint: 27:96:ba:e6:3f:18:01:e2:77:26:1b:a0:d7:77:70:02:8f:20:ee:e4 -# SHA256 Fingerprint: c3:84:6b:f2:4b:9e:93:ca:64:27:4c:0e:c6:7c:1e:cc:5e:02:4f:fc:ac:d2:d7:40:19:35:0e:81:fe:54:6a:e4 ------BEGIN CERTIFICATE----- -MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh -MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE -YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3 -MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo -ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg -MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN -ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA -PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w -wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi -EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY -avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+ -YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE -sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h -/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5 -IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj -YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD -ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy -OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P -TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ -HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER -dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf -ReYNnyicsbkqWletNw+vHX/bvZ8= ------END CERTIFICATE----- - -# Issuer: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority -# Subject: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority -# Label: "Starfield Class 2 CA" -# Serial: 0 -# MD5 Fingerprint: 32:4a:4b:bb:c8:63:69:9b:be:74:9a:c6:dd:1d:46:24 -# SHA1 Fingerprint: ad:7e:1c:28:b0:64:ef:8f:60:03:40:20:14:c3:d0:e3:37:0e:b5:8a -# SHA256 Fingerprint: 14:65:fa:20:53:97:b8:76:fa:a6:f0:a9:95:8e:55:90:e4:0f:cc:7f:aa:4f:b7:c2:c8:67:75:21:fb:5f:b6:58 ------BEGIN CERTIFICATE----- -MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl -MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp -U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw -NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE -ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp -ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3 -DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf -8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN -+lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0 -X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa -K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA -1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G -A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR -zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0 -YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD -bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w -DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3 -L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D -eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl -xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp -VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY -WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q= ------END CERTIFICATE----- - -# Issuer: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Assured ID Root CA" -# Serial: 17154717934120587862167794914071425081 -# MD5 Fingerprint: 87:ce:0b:7b:2a:0e:49:00:e1:58:71:9b:37:a8:93:72 -# SHA1 Fingerprint: 05:63:b8:63:0d:62:d7:5a:bb:c8:ab:1e:4b:df:b5:a8:99:b2:4d:43 -# SHA256 Fingerprint: 3e:90:99:b5:01:5e:8f:48:6c:00:bc:ea:9d:11:1e:e7:21:fa:ba:35:5a:89:bc:f1:df:69:56:1e:3d:c6:32:5c ------BEGIN CERTIFICATE----- -MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv -b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG -EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl -cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi -MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c -JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP -mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+ -wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4 -VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/ -AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB -AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW -BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun -pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC -dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf -fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm -NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx -H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe -+o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g== ------END CERTIFICATE----- - -# Issuer: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Global Root CA" -# Serial: 10944719598952040374951832963794454346 -# MD5 Fingerprint: 79:e4:a9:84:0d:7d:3a:96:d7:c0:4f:e2:43:4c:89:2e -# SHA1 Fingerprint: a8:98:5d:3a:65:e5:e5:c4:b2:d7:d6:6d:40:c6:dd:2f:b1:9c:54:36 -# SHA256 Fingerprint: 43:48:a0:e9:44:4c:78:cb:26:5e:05:8d:5e:89:44:b4:d8:4f:96:62:bd:26:db:25:7f:89:34:a4:43:c7:01:61 ------BEGIN CERTIFICATE----- -MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD -QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT -MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j -b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG -9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB -CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97 -nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt -43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P -T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4 -gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO -BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR -TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw -DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr -hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg -06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF -PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls -YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk -CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4= ------END CERTIFICATE----- - -# Issuer: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert High Assurance EV Root CA" -# Serial: 3553400076410547919724730734378100087 -# MD5 Fingerprint: d4:74:de:57:5c:39:b2:d3:9c:85:83:c5:c0:65:49:8a -# SHA1 Fingerprint: 5f:b7:ee:06:33:e2:59:db:ad:0c:4c:9a:e6:d3:8f:1a:61:c7:dc:25 -# SHA256 Fingerprint: 74:31:e5:f4:c3:c1:ce:46:90:77:4f:0b:61:e0:54:40:88:3b:a9:a0:1e:d0:0b:a6:ab:d7:80:6e:d3:b1:18:cf ------BEGIN CERTIFICATE----- -MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j -ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL -MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 -LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug -RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm -+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW -PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM -xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB -Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 -hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg -EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF -MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA -FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec -nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z -eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF -hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 -Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe -vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep -+OkuE6N36B9K ------END CERTIFICATE----- - -# Issuer: CN=DST Root CA X3 O=Digital Signature Trust Co. -# Subject: CN=DST Root CA X3 O=Digital Signature Trust Co. -# Label: "DST Root CA X3" -# Serial: 91299735575339953335919266965803778155 -# MD5 Fingerprint: 41:03:52:dc:0f:f7:50:1b:16:f0:02:8e:ba:6f:45:c5 -# SHA1 Fingerprint: da:c9:02:4f:54:d8:f6:df:94:93:5f:b1:73:26:38:ca:6a:d7:7c:13 -# SHA256 Fingerprint: 06:87:26:03:31:a7:24:03:d9:09:f1:05:e6:9b:cf:0d:32:e1:bd:24:93:ff:c6:d9:20:6d:11:bc:d6:77:07:39 ------BEGIN CERTIFICATE----- -MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/ -MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT -DkRTVCBSb290IENBIFgzMB4XDTAwMDkzMDIxMTIxOVoXDTIxMDkzMDE0MDExNVow -PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD -Ew5EU1QgUm9vdCBDQSBYMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB -AN+v6ZdQCINXtMxiZfaQguzH0yxrMMpb7NnDfcdAwRgUi+DoM3ZJKuM/IUmTrE4O -rz5Iy2Xu/NMhD2XSKtkyj4zl93ewEnu1lcCJo6m67XMuegwGMoOifooUMM0RoOEq -OLl5CjH9UL2AZd+3UWODyOKIYepLYYHsUmu5ouJLGiifSKOeDNoJjj4XLh7dIN9b -xiqKqy69cK3FCxolkHRyxXtqqzTWMIn/5WgTe1QLyNau7Fqckh49ZLOMxt+/yUFw -7BZy1SbsOFU5Q9D8/RhcQPGX69Wam40dutolucbY38EVAjqr2m7xPi71XAicPNaD -aeQQmxkqtilX4+U9m5/wAl0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNV -HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFMSnsaR7LHH62+FLkHX/xBVghYkQMA0GCSqG -SIb3DQEBBQUAA4IBAQCjGiybFwBcqR7uKGY3Or+Dxz9LwwmglSBd49lZRNI+DT69 -ikugdB/OEIKcdBodfpga3csTS7MgROSR6cz8faXbauX+5v3gTt23ADq1cEmv8uXr -AvHRAosZy5Q6XkjEGB5YGV8eAlrwDPGxrancWYaLbumR9YbK+rlmM6pZW87ipxZz -R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5 -JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo -Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ ------END CERTIFICATE----- - -# Issuer: CN=SwissSign Gold CA - G2 O=SwissSign AG -# Subject: CN=SwissSign Gold CA - G2 O=SwissSign AG -# Label: "SwissSign Gold CA - G2" -# Serial: 13492815561806991280 -# MD5 Fingerprint: 24:77:d9:a8:91:d1:3b:fa:88:2d:c2:ff:f8:cd:33:93 -# SHA1 Fingerprint: d8:c5:38:8a:b7:30:1b:1b:6e:d4:7a:e6:45:25:3a:6f:9f:1a:27:61 -# SHA256 Fingerprint: 62:dd:0b:e9:b9:f5:0a:16:3e:a0:f8:e7:5c:05:3b:1e:ca:57:ea:55:c8:68:8f:64:7c:68:81:f2:c8:35:7b:95 ------BEGIN CERTIFICATE----- -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 ------END CERTIFICATE----- - -# Issuer: CN=SwissSign Silver CA - G2 O=SwissSign AG -# Subject: CN=SwissSign Silver CA - G2 O=SwissSign AG -# Label: "SwissSign Silver CA - G2" -# Serial: 5700383053117599563 -# MD5 Fingerprint: e0:06:a1:c9:7d:cf:c9:fc:0d:c0:56:75:96:d8:62:13 -# SHA1 Fingerprint: 9b:aa:e5:9f:56:ee:21:cb:43:5a:be:25:93:df:a7:f0:40:d1:1d:cb -# SHA256 Fingerprint: be:6c:4d:a2:bb:b9:ba:59:b6:f3:93:97:68:37:42:46:c3:c0:05:99:3f:a9:8f:02:0d:1d:ed:be:d4:8a:81:d5 ------BEGIN CERTIFICATE----- -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 ------END CERTIFICATE----- - -# Issuer: CN=SecureTrust CA O=SecureTrust Corporation -# Subject: CN=SecureTrust CA O=SecureTrust Corporation -# Label: "SecureTrust CA" -# Serial: 17199774589125277788362757014266862032 -# MD5 Fingerprint: dc:32:c3:a7:6d:25:57:c7:68:09:9d:ea:2d:a9:a2:d1 -# SHA1 Fingerprint: 87:82:c6:c3:04:35:3b:cf:d2:96:92:d2:59:3e:7d:44:d9:34:ff:11 -# SHA256 Fingerprint: f1:c1:b5:0a:e5:a2:0d:d8:03:0e:c9:f6:bc:24:82:3d:d3:67:b5:25:57:59:b4:e7:1b:61:fc:e9:f7:37:5d:73 ------BEGIN CERTIFICATE----- -MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI -MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x -FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz -MTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENv -cnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCCASIwDQYJKoZIhvcN -AQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQXOZEz -Zum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO -0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIao -wW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj -7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS -8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjAT -BgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB -/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCeg -JYYjaHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGC -NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3 -6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/ -3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cprp6poxkm -D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS -CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR -3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE= ------END CERTIFICATE----- - -# Issuer: CN=Secure Global CA O=SecureTrust Corporation -# Subject: CN=Secure Global CA O=SecureTrust Corporation -# Label: "Secure Global CA" -# Serial: 9751836167731051554232119481456978597 -# MD5 Fingerprint: cf:f4:27:0d:d4:ed:dc:65:16:49:6d:3d:da:bf:6e:de -# SHA1 Fingerprint: 3a:44:73:5a:e5:81:90:1f:24:86:61:46:1e:3b:9c:c4:5f:f5:3a:1b -# SHA256 Fingerprint: 42:00:f5:04:3a:c8:59:0e:bb:52:7d:20:9e:d1:50:30:29:fb:cb:d4:1c:a1:b5:06:ec:27:f1:5a:de:7d:ac:69 ------BEGIN CERTIFICATE----- -MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBK -MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x -GTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkx -MjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3Qg -Q29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwggEiMA0GCSqG -SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jxYDiJ -iQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa -/FHtaMbQbqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJ -jnIFHovdRIWCQtBJwB1g8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnI -HmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYVHDGA76oYa8J719rO+TMg1fW9ajMtgQT7 -sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi0XPnj3pDAgMBAAGjgZ0w -gZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQF -MAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCsw -KaAnoCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsG -AQQBgjcVAQQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0L -URYD7xh8yOOvaliTFGCRsoTciE6+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXO -H0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cnCDpOGR86p1hcF895P4vkp9Mm -I50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/53CYNv6ZHdAbY -iNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc -f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW ------END CERTIFICATE----- - -# Issuer: CN=COMODO Certification Authority O=COMODO CA Limited -# Subject: CN=COMODO Certification Authority O=COMODO CA Limited -# Label: "COMODO Certification Authority" -# Serial: 104350513648249232941998508985834464573 -# MD5 Fingerprint: 5c:48:dc:f7:42:72:ec:56:94:6d:1c:cc:71:35:80:75 -# SHA1 Fingerprint: 66:31:bf:9e:f7:4f:9e:b6:c9:d5:a6:0c:ba:6a:be:d1:f7:bd:ef:7b -# SHA256 Fingerprint: 0c:2c:d6:3d:f7:80:6f:a3:99:ed:e8:09:11:6b:57:5b:f8:79:89:f0:65:18:f9:80:8c:86:05:03:17:8b:af:66 ------BEGIN CERTIFICATE----- -MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB -gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G -A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV -BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw -MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl -YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P -RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0 -aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3 -UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI -2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8 -Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp -+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+ -DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O -nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW -/zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g -PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u -QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY -SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv -IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ -RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4 -zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd -BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB -ZQ== ------END CERTIFICATE----- - -# Issuer: CN=Network Solutions Certificate Authority O=Network Solutions L.L.C. -# Subject: CN=Network Solutions Certificate Authority O=Network Solutions L.L.C. -# Label: "Network Solutions Certificate Authority" -# Serial: 116697915152937497490437556386812487904 -# MD5 Fingerprint: d3:f3:a6:16:c0:fa:6b:1d:59:b1:2d:96:4d:0e:11:2e -# SHA1 Fingerprint: 74:f8:a3:c3:ef:e7:b3:90:06:4b:83:90:3c:21:64:60:20:e5:df:ce -# SHA256 Fingerprint: 15:f0:ba:00:a3:ac:7a:f3:ac:88:4c:07:2b:10:11:a0:77:bd:77:c0:97:f4:01:64:b2:f8:59:8a:bd:83:86:0c ------BEGIN CERTIFICATE----- -MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBi -MQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu -MTAwLgYDVQQDEydOZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3Jp -dHkwHhcNMDYxMjAxMDAwMDAwWhcNMjkxMjMxMjM1OTU5WjBiMQswCQYDVQQGEwJV -UzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMuMTAwLgYDVQQDEydO -ZXR3b3JrIFNvbHV0aW9ucyBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG -SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDkvH6SMG3G2I4rC7xGzuAnlt7e+foS0zwz -c7MEL7xxjOWftiJgPl9dzgn/ggwbmlFQGiaJ3dVhXRncEg8tCqJDXRfQNJIg6nPP -OCwGJgl6cvf6UDL4wpPTaaIjzkGxzOTVHzbRijr4jGPiFFlp7Q3Tf2vouAPlT2rl -mGNpSAW+Lv8ztumXWWn4Zxmuk2GWRBXTcrA/vGp97Eh/jcOrqnErU2lBUzS1sLnF -BgrEsEX1QV1uiUV7PTsmjHTC5dLRfbIR1PtYMiKagMnc/Qzpf14Dl847ABSHJ3A4 -qY5usyd2mFHgBeMhqxrVhSI8KbWaFsWAqPS7azCPL0YCorEMIuDTAgMBAAGjgZcw -gZQwHQYDVR0OBBYEFCEwyfsA106Y2oeqKtCnLrFAMadMMA4GA1UdDwEB/wQEAwIB -BjAPBgNVHRMBAf8EBTADAQH/MFIGA1UdHwRLMEkwR6BFoEOGQWh0dHA6Ly9jcmwu -bmV0c29sc3NsLmNvbS9OZXR3b3JrU29sdXRpb25zQ2VydGlmaWNhdGVBdXRob3Jp -dHkuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQC7rkvnt1frf6ott3NHhWrB5KUd5Oc8 -6fRZZXe1eltajSU24HqXLjjAV2CDmAaDn7l2em5Q4LqILPxFzBiwmZVRDuwduIj/ -h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/GGUsyfJj4akH -/nxxH2szJGoeBfcFaMBqEssuXmHLrijTfsK0ZpEmXzwuJF/LWA/rKOyvEZbz3Htv -wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHN -pGxlaKFJdlxDydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey ------END CERTIFICATE----- - -# Issuer: CN=COMODO ECC Certification Authority O=COMODO CA Limited -# Subject: CN=COMODO ECC Certification Authority O=COMODO CA Limited -# Label: "COMODO ECC Certification Authority" -# Serial: 41578283867086692638256921589707938090 -# MD5 Fingerprint: 7c:62:ff:74:9d:31:53:5e:68:4a:d5:78:aa:1e:bf:23 -# SHA1 Fingerprint: 9f:74:4e:9f:2b:4d:ba:ec:0f:31:2c:50:b6:56:3b:8e:2d:93:c3:11 -# SHA256 Fingerprint: 17:93:92:7a:06:14:54:97:89:ad:ce:2f:8f:34:f7:f0:b6:6d:0f:3a:e3:a3:b8:4d:21:ec:15:db:ba:4f:ad:c7 ------BEGIN CERTIFICATE----- -MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL -MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE -BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT -IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw -MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy -ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N -T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv -biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR -FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J -cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW -BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ -BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm -fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv -GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY= ------END CERTIFICATE----- - -# Issuer: CN=Certigna O=Dhimyotis -# Subject: CN=Certigna O=Dhimyotis -# Label: "Certigna" -# Serial: 18364802974209362175 -# MD5 Fingerprint: ab:57:a6:5b:7d:42:82:19:b5:d8:58:26:28:5e:fd:ff -# SHA1 Fingerprint: b1:2e:13:63:45:86:a4:6f:1a:b2:60:68:37:58:2d:c4:ac:fd:94:97 -# SHA256 Fingerprint: e3:b6:a2:db:2e:d7:ce:48:84:2f:7a:c5:32:41:c7:b7:1d:54:14:4b:fb:40:c1:1f:3f:1d:0b:42:f5:ee:a1:2d ------BEGIN CERTIFICATE----- -MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNV -BAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4X -DTA3MDYyOTE1MTMwNVoXDTI3MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQ -BgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwIQ2VydGlnbmEwggEiMA0GCSqGSIb3 -DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7qXOEm7RFHYeGifBZ4 -QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyHGxny -gQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbw -zBfsV1/pogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q -130yGLMLLGq/jj8UEYkgDncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2 -JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKfIrjxwo1p3Po6WAbfAgMBAAGjgbwwgbkw -DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQtCRZvgHyUtVF9lo53BEw -ZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJBgNVBAYT -AkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzj -AQ/JSP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG -9w0BAQUFAAOCAQEAhQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8h -bV6lUmPOEvjvKtpv6zf+EwLHyzs+ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFnc -fca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1kluPBS1xp81HlDQwY9qcEQCYsuu -HWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY1gkIl2PlwS6w -t0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw -WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg== ------END CERTIFICATE----- - -# Issuer: CN=Cybertrust Global Root O=Cybertrust, Inc -# Subject: CN=Cybertrust Global Root O=Cybertrust, Inc -# Label: "Cybertrust Global Root" -# Serial: 4835703278459682877484360 -# MD5 Fingerprint: 72:e4:4a:87:e3:69:40:80:77:ea:bc:e3:f4:ff:f0:e1 -# SHA1 Fingerprint: 5f:43:e5:b1:bf:f8:78:8c:ac:1c:c7:ca:4a:9a:c6:22:2b:cc:34:c6 -# SHA256 Fingerprint: 96:0a:df:00:63:e9:63:56:75:0c:29:65:dd:0a:08:67:da:0b:9c:bd:6e:77:71:4a:ea:fb:23:49:ab:39:3d:a3 ------BEGIN CERTIFICATE----- -MIIDoTCCAomgAwIBAgILBAAAAAABD4WqLUgwDQYJKoZIhvcNAQEFBQAwOzEYMBYG -A1UEChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2Jh -bCBSb290MB4XDTA2MTIxNTA4MDAwMFoXDTIxMTIxNTA4MDAwMFowOzEYMBYGA1UE -ChMPQ3liZXJ0cnVzdCwgSW5jMR8wHQYDVQQDExZDeWJlcnRydXN0IEdsb2JhbCBS -b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA+Mi8vRRQZhP/8NN5 -7CPytxrHjoXxEnOmGaoQ25yiZXRadz5RfVb23CO21O1fWLE3TdVJDm71aofW0ozS -J8bi/zafmGWgE07GKmSb1ZASzxQG9Dvj1Ci+6A74q05IlG2OlTEQXO2iLb3VOm2y -HLtgwEZLAfVJrn5GitB0jaEMAs7u/OePuGtm839EAL9mJRQr3RAwHQeWP032a7iP -t3sMpTjr3kfb1V05/Iin89cqdPHoWqI7n1C6poxFNcJQZZXcY4Lv3b93TZxiyWNz -FtApD0mpSPCzqrdsxacwOUBdrsTiXSZT8M4cIwhhqJQZugRiQOwfOHB3EgZxpzAY -XSUnpQIDAQABo4GlMIGiMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/ -MB0GA1UdDgQWBBS2CHsNesysIEyGVjJez6tuhS1wVzA/BgNVHR8EODA2MDSgMqAw -hi5odHRwOi8vd3d3Mi5wdWJsaWMtdHJ1c3QuY29tL2NybC9jdC9jdHJvb3QuY3Js -MB8GA1UdIwQYMBaAFLYIew16zKwgTIZWMl7Pq26FLXBXMA0GCSqGSIb3DQEBBQUA -A4IBAQBW7wojoFROlZfJ+InaRcHUowAl9B8Tq7ejhVhpwjCt2BWKLePJzYFa+HMj -Wqd8BfP9IjsO0QbE2zZMcwSO5bAi5MXzLqXZI+O4Tkogp24CJJ8iYGd7ix1yCcUx -XOl5n4BHPa2hCwcUPUf/A2kaDAtE52Mlp3+yybh2hO0j9n0Hq0V+09+zv+mKts2o -omcrUtW3ZfA5TGOgkXmTUg9U3YO7n9GPp1Nzw8v/MOx8BLjYRB+TX3EJIrduPuoc -A06dGiBh+4E37F78CkWr1+cXVdCg6mCbpvbjjFspwgZgFJ0tl0ypkxWdYcQBX0jW -WL1WMRJOEcgh4LMRkWXbtKaIOM5V ------END CERTIFICATE----- - -# Issuer: O=Chunghwa Telecom Co., Ltd. OU=ePKI Root Certification Authority -# Subject: O=Chunghwa Telecom Co., Ltd. OU=ePKI Root Certification Authority -# Label: "ePKI Root Certification Authority" -# Serial: 28956088682735189655030529057352760477 -# MD5 Fingerprint: 1b:2e:00:ca:26:06:90:3d:ad:fe:6f:15:68:d3:6b:b3 -# SHA1 Fingerprint: 67:65:0d:f1:7e:8e:7e:5b:82:40:a4:f4:56:4b:cf:e2:3d:69:c6:f0 -# SHA256 Fingerprint: c0:a6:f4:dc:63:a2:4b:fd:cf:54:ef:2a:6a:08:2a:0a:72:de:35:80:3e:2f:f5:ff:52:7a:e5:d8:72:06:df:d5 ------BEGIN CERTIFICATE----- -MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBe -MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0 -ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe -Fw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMxMjdaMF4xCzAJBgNVBAYTAlRXMSMw -IQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEqMCgGA1UECwwhZVBL -SSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEF -AAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAH -SyZbCUNsIZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAh -ijHyl3SJCRImHJ7K2RKilTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3X -DZoTM1PRYfl61dd4s5oz9wCGzh1NlDivqOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1 -TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX12ruOzjjK9SXDrkb5wdJ -fzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0OWQqraffA -sgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uU -WH1+ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLS -nT0IFaUQAS2zMnaolQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pH -dmX2Os+PYhcZewoozRrSgx4hxyy/vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJip -NiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXiZo1jDiVN1Rmy5nk3pyKdVDEC -AwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/QkqiMAwGA1UdEwQF -MAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH -ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGB -uvl2ICO1J2B01GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6Yl -PwZpVnPDimZI+ymBV3QGypzqKOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkP -JXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdVxrsStZf0X4OFunHB2WyBEXYKCrC/ -gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEPNXubrjlpC2JgQCA2 -j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+rGNm6 -5ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUB -o2M3IUxExJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS -/jQ6fbjpKdx2qcgw+BRxgMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2z -Gp1iro2C6pSe3VkQw63d4k3jMdXH7OjysP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTE -W9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+D -hNQ+IIX3Sj0rnP0qCglN6oH4EZw= ------END CERTIFICATE----- - -# Issuer: O=certSIGN OU=certSIGN ROOT CA -# Subject: O=certSIGN OU=certSIGN ROOT CA -# Label: "certSIGN ROOT CA" -# Serial: 35210227249154 -# MD5 Fingerprint: 18:98:c0:d6:e9:3a:fc:f9:b0:f5:0c:f7:4b:01:44:17 -# SHA1 Fingerprint: fa:b7:ee:36:97:26:62:fb:2d:b0:2a:f6:bf:03:fd:e8:7c:4b:2f:9b -# SHA256 Fingerprint: ea:a9:62:c4:fa:4a:6b:af:eb:e4:15:19:6d:35:1c:cd:88:8d:4f:53:f3:fa:8a:e6:d7:c4:66:a9:4e:60:42:bb ------BEGIN CERTIFICATE----- -MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYT -AlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBD -QTAeFw0wNjA3MDQxNzIwMDRaFw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJP -MREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTCC -ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7IJUqOtdu0KBuqV5Do -0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHHrfAQ -UySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5d -RdY4zTW2ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQ -OA7+j0xbm0bqQfWwCHTD0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwv -JoIQ4uNllAoEwF73XVv4EOLQunpL+943AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08C -AwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAcYwHQYDVR0O -BBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IBAQA+0hyJ -LjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecY -MnQ8SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ -44gx+FkagQnIl6Z0x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6I -Jd1hJyMctTEHBDa0GpC9oHRxUIltvBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNw -i/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7NzTogVZ96edhBiIL5VaZVDADlN -9u6wWk5JRFRYX0KD ------END CERTIFICATE----- - -# Issuer: CN=NetLock Arany (Class Gold) F\u0151tan\xfas\xedtv\xe1ny O=NetLock Kft. OU=Tan\xfas\xedtv\xe1nykiad\xf3k (Certification Services) -# Subject: CN=NetLock Arany (Class Gold) F\u0151tan\xfas\xedtv\xe1ny O=NetLock Kft. OU=Tan\xfas\xedtv\xe1nykiad\xf3k (Certification Services) -# Label: "NetLock Arany (Class Gold) F\u0151tan\xfas\xedtv\xe1ny" -# Serial: 80544274841616 -# MD5 Fingerprint: c5:a1:b7:ff:73:dd:d6:d7:34:32:18:df:fc:3c:ad:88 -# SHA1 Fingerprint: 06:08:3f:59:3f:15:a1:04:a0:69:a4:6b:a9:03:d0:06:b7:97:09:91 -# SHA256 Fingerprint: 6c:61:da:c3:a2:de:f0:31:50:6b:e0:36:d2:a6:fe:40:19:94:fb:d1:3d:f9:c8:d4:66:59:92:74:c4:46:ec:98 ------BEGIN CERTIFICATE----- -MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG -EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3 -MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl -cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR -dGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgxMjA2MTUwODIxWjCB -pzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxOZXRM -b2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlm -aWNhdGlvbiBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNz -IEdvbGQpIEbFkXRhbsO6c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEAxCRec75LbRTDofTjl5Bu0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrT -lF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw/HpYzY6b7cNGbIRwXdrz -AZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAkH3B5r9s5 -VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRG -ILdwfzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2 -BJtr+UBdADTHLpl1neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAG -AQH/AgEEMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2M -U9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwWqZw8UQCgwBEIBaeZ5m8BiFRh -bvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTtaYtOUZcTh5m2C -+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC -bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2F -uLjbvrW5KfnaNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2 -XjG4Kvte9nHfRCaexOYNkbQudZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E= ------END CERTIFICATE----- - -# Issuer: CN=Hongkong Post Root CA 1 O=Hongkong Post -# Subject: CN=Hongkong Post Root CA 1 O=Hongkong Post -# Label: "Hongkong Post Root CA 1" -# Serial: 1000 -# MD5 Fingerprint: a8:0d:6f:39:78:b9:43:6d:77:42:6d:98:5a:cc:23:ca -# SHA1 Fingerprint: d6:da:a8:20:8d:09:d2:15:4d:24:b5:2f:cb:34:6e:b2:58:b2:8a:58 -# SHA256 Fingerprint: f9:e6:7d:33:6c:51:00:2a:c0:54:c6:32:02:2d:66:dd:a2:e7:e3:ff:f1:0a:d0:61:ed:31:d8:bb:b4:10:cf:b2 ------BEGIN CERTIFICATE----- -MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsx -FjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3Qg -Um9vdCBDQSAxMB4XDTAzMDUxNTA1MTMxNFoXDTIzMDUxNTA0NTIyOVowRzELMAkG -A1UEBhMCSEsxFjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdr -b25nIFBvc3QgUm9vdCBDQSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC -AQEArP84tulmAknjorThkPlAj3n54r15/gK97iSSHSL22oVyaf7XPwnU3ZG1ApzQ -jVrhVcNQhrkpJsLj2aDxaQMoIIBFIi1WpztUlVYiWR8o3x8gPW2iNr4joLFutbEn -PzlTCeqrauh0ssJlXI6/fMN4hM2eFvz1Lk8gKgifd/PFHsSaUmYeSF7jEAaPIpjh -ZY4bXSNmO7ilMlHIhqqhqZ5/dpTCpmy3QfDVyAY45tQM4vM7TG1QjMSDJ8EThFk9 -nnV0ttgCXjqQesBCNnLsak3c78QA3xMYV18meMjWCnl3v/evt3a5pQuEF10Q6m/h -q5URX208o1xNg1vysxmKgIsLhwIDAQABoyYwJDASBgNVHRMBAf8ECDAGAQH/AgED -MA4GA1UdDwEB/wQEAwIBxjANBgkqhkiG9w0BAQUFAAOCAQEADkbVPK7ih9legYsC -mEEIjEy82tvuJxuC52pF7BaLT4Wg87JwvVqWuspube5Gi27nKi6Wsxkz67SfqLI3 -7piol7Yutmcn1KZJ/RyTZXaeQi/cImyaT/JaFTmxcdcrUehtHJjA2Sr0oYJ71clB -oiMBdDhViw+5LmeiIAQ32pwL0xch4I+XeTRvhEgCIDMb5jREn5Fw9IBehEPCKdJs -EhTkYY2sEJCehFC78JZvRZ+K88psT/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpO -fMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilTc4afU9hDDl3WY4JxHYB0yvbi -AmvZWg== ------END CERTIFICATE----- - -# Issuer: CN=SecureSign RootCA11 O=Japan Certification Services, Inc. -# Subject: CN=SecureSign RootCA11 O=Japan Certification Services, Inc. -# Label: "SecureSign RootCA11" -# Serial: 1 -# MD5 Fingerprint: b7:52:74:e2:92:b4:80:93:f2:75:e4:cc:d7:f2:ea:26 -# SHA1 Fingerprint: 3b:c4:9f:48:f8:f3:73:a0:9c:1e:bd:f8:5b:b1:c3:65:c7:d8:11:b3 -# SHA256 Fingerprint: bf:0f:ee:fb:9e:3a:58:1a:d5:f9:e9:db:75:89:98:57:43:d2:61:08:5c:4d:31:4f:6f:5d:72:59:aa:42:16:12 ------BEGIN CERTIFICATE----- -MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDEr -MCkGA1UEChMiSmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoG -A1UEAxMTU2VjdXJlU2lnbiBSb290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0 -MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSswKQYDVQQKEyJKYXBhbiBDZXJ0aWZp -Y2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1cmVTaWduIFJvb3RD -QTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvLTJsz -i1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8 -h9uuywGOwvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOV -MdrAG/LuYpmGYz+/3ZMqg6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9 -UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rPO7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni -8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitAbpSACW22s293bzUIUPsC -h8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZXt94wDgYD -VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB -AKChOBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xm -KbabfSVSSUOrTC4rbnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQ -X5Ucv+2rIrVls4W6ng+4reV6G4pQOh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWr -QbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01y8hSyn+B/tlr0/cR7SXf+Of5 -pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061lgeLKBObjBmN -QSdJQO7e5iNEOdyhIta6A/I= ------END CERTIFICATE----- - -# Issuer: CN=Microsec e-Szigno Root CA 2009 O=Microsec Ltd. -# Subject: CN=Microsec e-Szigno Root CA 2009 O=Microsec Ltd. -# Label: "Microsec e-Szigno Root CA 2009" -# Serial: 14014712776195784473 -# MD5 Fingerprint: f8:49:f4:03:bc:44:2d:83:be:48:69:7d:29:64:fc:b1 -# SHA1 Fingerprint: 89:df:74:fe:5c:f4:0f:4a:80:f9:e3:37:7d:54:da:91:e1:01:31:8e -# SHA256 Fingerprint: 3c:5f:81:fe:a5:fa:b8:2c:64:bf:a2:ea:ec:af:cd:e8:e0:77:fc:86:20:a7:ca:e5:37:16:3d:f3:6e:db:f3:78 ------BEGIN CERTIFICATE----- -MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD -VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0 -ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0G -CSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTAeFw0wOTA2MTYxMTMwMThaFw0y -OTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3Qx -FjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3pp -Z25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o -dTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvP -kd6mJviZpWNwrZuuyjNAfW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tc -cbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG0IMZfcChEhyVbUr02MelTTMuhTlAdX4U -fIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKApxn1ntxVUwOXewdI/5n7 -N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm1HxdrtbC -xkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1 -+rUCAwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G -A1UdDgQWBBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPM -Pcu1SCOhGnqmKrs0aDAbBgNVHREEFDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqG -SIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0olZMEyL/azXm4Q5DwpL7v8u8h -mLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfXI/OMn74dseGk -ddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775 -tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c -2Pm2G2JwCz02yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5t -HMN1Rq41Bab2XD0h7lbwyYIiLXpUq3DDfSJlgnCW ------END CERTIFICATE----- - -# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3 -# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3 -# Label: "GlobalSign Root CA - R3" -# Serial: 4835703278459759426209954 -# MD5 Fingerprint: c5:df:b8:49:ca:05:13:55:ee:2d:ba:1a:c3:3e:b0:28 -# SHA1 Fingerprint: d6:9b:56:11:48:f0:1c:77:c5:45:78:c1:09:26:df:5b:85:69:76:ad -# SHA256 Fingerprint: cb:b5:22:d7:b7:f1:27:ad:6a:01:13:86:5b:df:1c:d4:10:2e:7d:07:59:af:63:5a:7c:f4:72:0d:c9:63:c5:3b ------BEGIN CERTIFICATE----- -MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G -A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp -Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4 -MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG -A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8 -RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT -gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm -KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd -QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ -XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw -DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o -LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU -RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp -jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK -6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX -mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs -Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH -WD9f ------END CERTIFICATE----- - -# Issuer: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068 -# Subject: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068 -# Label: "Autoridad de Certificacion Firmaprofesional CIF A62634068" -# Serial: 6047274297262753887 -# MD5 Fingerprint: 73:3a:74:7a:ec:bb:a3:96:a6:c2:e4:e2:c8:9b:c0:c3 -# SHA1 Fingerprint: ae:c5:fb:3f:c8:e1:bf:c4:e5:4f:03:07:5a:9a:e8:00:b7:f7:b6:fa -# SHA256 Fingerprint: 04:04:80:28:bf:1f:28:64:d4:8f:9a:d4:d8:32:94:36:6a:82:88:56:55:3f:3b:14:30:3f:90:14:7f:5d:40:ef ------BEGIN CERTIFICATE----- -MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UE -BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h -cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEy -MzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg -Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi -MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9 -thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM -cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG -L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i -NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h -X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b -m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy -Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja -EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T -KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF -6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh -OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYD -VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNHDhpkLzCBpgYD -VR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp -cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBv -ACAAZABlACAAbABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBl -AGwAbwBuAGEAIAAwADgAMAAxADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF -661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx51tkljYyGOylMnfX40S2wBEqgLk9 -am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qkR71kMrv2JYSiJ0L1 -ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaPT481 -PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS -3a/DTg4fJl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5k -SeTy36LssUzAKh3ntLFlosS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF -3dvd6qJ2gHN99ZwExEWN57kci57q13XRcrHedUTnQn3iV2t93Jm8PYMo6oCTjcVM -ZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoRsaS8I8nkvof/uZS2+F0g -StRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTDKCOM/icz -Q0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQB -jLMi6Et8Vcad+qMUu2WFbm5PEn4KPJ2V ------END CERTIFICATE----- - -# Issuer: CN=Izenpe.com O=IZENPE S.A. -# Subject: CN=Izenpe.com O=IZENPE S.A. -# Label: "Izenpe.com" -# Serial: 917563065490389241595536686991402621 -# MD5 Fingerprint: a6:b0:cd:85:80:da:5c:50:34:a3:39:90:2f:55:67:73 -# SHA1 Fingerprint: 2f:78:3d:25:52:18:a7:4a:65:39:71:b5:2c:a2:9c:45:15:6f:e9:19 -# SHA256 Fingerprint: 25:30:cc:8e:98:32:15:02:ba:d9:6f:9b:1f:ba:1b:09:9e:2d:29:9e:0f:45:48:bb:91:4f:36:3b:c0:d4:53:1f ------BEGIN CERTIFICATE----- -MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4 -MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6 -ZW5wZS5jb20wHhcNMDcxMjEzMTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYD -VQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5j -b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ03rKDx6sp4boFmVq -scIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAKClaO -xdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6H -LmYRY2xU+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFX -uaOKmMPsOzTFlUFpfnXCPCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQD -yCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxTOTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+ -JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbKF7jJeodWLBoBHmy+E60Q -rLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK0GqfvEyN -BjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8L -hij+0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIB -QFqNeb+Lz0vPqhbBleStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+ -HMh3/1uaD7euBUbl8agW7EekFwIDAQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2lu -Zm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+SVpFTlBFIFMuQS4gLSBDSUYg -QTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBGNjIgUzgxQzBB -BgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx -MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC -AQYwHQYDVR0OBBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUA -A4ICAQB4pgwWSp9MiDrAyw6lFn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWb -laQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbgakEyrkgPH7UIBzg/YsfqikuFgba56 -awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8qhT/AQKM6WfxZSzwo -JNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Csg1lw -LDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCT -VyvehQP5aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGk -LhObNA5me0mrZJfQRsN5nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJb -UjWumDqtujWTI6cfSN01RpiyEGjkpTHCClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/ -QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZoQ0iy2+tzJOeRf1SktoA+ -naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGls -QyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw== ------END CERTIFICATE----- - -# Issuer: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc. -# Subject: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc. -# Label: "Go Daddy Root Certificate Authority - G2" -# Serial: 0 -# MD5 Fingerprint: 80:3a:bc:22:c1:e6:fb:8d:9b:3b:27:4a:32:1b:9a:01 -# SHA1 Fingerprint: 47:be:ab:c9:22:ea:e8:0e:78:78:34:62:a7:9f:45:c2:54:fd:e6:8b -# SHA256 Fingerprint: 45:14:0b:32:47:eb:9c:c8:c5:b4:f0:d7:b5:30:91:f7:32:92:08:9e:6e:5a:63:e2:74:9d:d3:ac:a9:19:8e:da ------BEGIN CERTIFICATE----- -MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx -EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT -EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp -ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz -NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH -EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE -AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw -DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD -E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH -/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy -DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh -GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR -tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA -AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE -FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX -WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu -9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr -gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo -2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO -LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI -4uJEvlz36hz1 ------END CERTIFICATE----- - -# Issuer: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc. -# Subject: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc. -# Label: "Starfield Root Certificate Authority - G2" -# Serial: 0 -# MD5 Fingerprint: d6:39:81:c6:52:7e:96:69:fc:fc:ca:66:ed:05:f2:96 -# SHA1 Fingerprint: b5:1c:06:7c:ee:2b:0c:3d:f8:55:ab:2d:92:f4:fe:39:d4:e7:0f:0e -# SHA256 Fingerprint: 2c:e1:cb:0b:f9:d2:f9:e1:02:99:3f:be:21:51:52:c3:b2:dd:0c:ab:de:1c:68:e5:31:9b:83:91:54:db:b7:f5 ------BEGIN CERTIFICATE----- -MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx -EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT -HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs -ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw -MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6 -b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj -aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp -Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg -nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1 -HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N -Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN -dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0 -HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO -BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G -CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU -sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3 -4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg -8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K -pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1 -mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0 ------END CERTIFICATE----- - -# Issuer: CN=Starfield Services Root Certificate Authority - G2 O=Starfield Technologies, Inc. -# Subject: CN=Starfield Services Root Certificate Authority - G2 O=Starfield Technologies, Inc. -# Label: "Starfield Services Root Certificate Authority - G2" -# Serial: 0 -# MD5 Fingerprint: 17:35:74:af:7b:61:1c:eb:f4:f9:3c:e2:ee:40:f9:a2 -# SHA1 Fingerprint: 92:5a:8f:8d:2c:6d:04:e0:66:5f:59:6a:ff:22:d8:63:e8:25:6f:3f -# SHA256 Fingerprint: 56:8d:69:05:a2:c8:87:08:a4:b3:02:51:90:ed:cf:ed:b1:97:4a:60:6a:13:c6:e5:29:0f:cb:2a:e6:3e:da:b5 ------BEGIN CERTIFICATE----- -MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx -EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT -HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs -ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5 -MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD -VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy -ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy -dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p -OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2 -8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K -Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe -hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk -6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw -DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q -AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI -bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB -ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z -qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd -iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn -0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN -sSi6 ------END CERTIFICATE----- - -# Issuer: CN=AffirmTrust Commercial O=AffirmTrust -# Subject: CN=AffirmTrust Commercial O=AffirmTrust -# Label: "AffirmTrust Commercial" -# Serial: 8608355977964138876 -# MD5 Fingerprint: 82:92:ba:5b:ef:cd:8a:6f:a6:3d:55:f9:84:f6:d6:b7 -# SHA1 Fingerprint: f9:b5:b6:32:45:5f:9c:be:ec:57:5f:80:dc:e9:6e:2c:c7:b2:78:b7 -# SHA256 Fingerprint: 03:76:ab:1d:54:c5:f9:80:3c:e4:b2:e2:01:a0:ee:7e:ef:7b:57:b6:36:e8:a9:3c:9b:8d:48:60:c9:6f:5f:a7 ------BEGIN CERTIFICATE----- -MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE -BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz -dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL -MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp -cm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC -AQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6EqdbDuKP -Hx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yr -ba0F8PrVC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPAL -MeIrJmqbTFeurCA+ukV6BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1 -yHp52UKqK39c/s4mT6NmgTWvRLpUHhwwMmWd5jyTXlBOeuM61G7MGvv50jeuJCqr -VwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNVHQ4EFgQUnZPGU4teyq8/ -nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ -KoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYG -XUPGhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNj -vbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivt -Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g -N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC -nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= ------END CERTIFICATE----- - -# Issuer: CN=AffirmTrust Networking O=AffirmTrust -# Subject: CN=AffirmTrust Networking O=AffirmTrust -# Label: "AffirmTrust Networking" -# Serial: 8957382827206547757 -# MD5 Fingerprint: 42:65:ca:be:01:9a:9a:4c:a9:8c:41:49:cd:c0:d5:7f -# SHA1 Fingerprint: 29:36:21:02:8b:20:ed:02:f5:66:c5:32:d1:d6:ed:90:9f:45:00:2f -# SHA256 Fingerprint: 0a:81:ec:5a:92:97:77:f1:45:90:4a:f3:8d:5d:50:9f:66:b5:e2:c5:8f:cd:b5:31:05:8b:0e:17:f3:f0:b4:1b ------BEGIN CERTIFICATE----- -MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE -BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz -dCBOZXR3b3JraW5nMB4XDTEwMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDEL -MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp -cm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC -AQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SEHi3y -YJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbua -kCNrmreIdIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRL -QESxG9fhwoXA3hA/Pe24/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp -6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gbh+0t+nvujArjqWaJGctB+d1ENmHP4ndG -yH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNVHQ4EFgQUBx/S55zawm6i -QLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ -KoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfO -tDIuUFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzu -QY0x2+c06lkh1QF612S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZ -Lgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u -olu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48 -x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= ------END CERTIFICATE----- - -# Issuer: CN=AffirmTrust Premium O=AffirmTrust -# Subject: CN=AffirmTrust Premium O=AffirmTrust -# Label: "AffirmTrust Premium" -# Serial: 7893706540734352110 -# MD5 Fingerprint: c4:5d:0e:48:b6:ac:28:30:4e:0a:bc:f9:38:16:87:57 -# SHA1 Fingerprint: d8:a6:33:2c:e0:03:6f:b1:85:f6:63:4f:7d:6a:06:65:26:32:28:27 -# SHA256 Fingerprint: 70:a7:3f:7f:37:6b:60:07:42:48:90:45:34:b1:14:82:d5:bf:0e:69:8e:cc:49:8d:f5:25:77:eb:f2:e9:3b:9a ------BEGIN CERTIFICATE----- -MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE -BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz -dCBQcmVtaXVtMB4XDTEwMDEyOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkG -A1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1U -cnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxBLf -qV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtnBKAQ -JG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ -+jjeRFcV5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrS -s8PhaJyJ+HoAVt70VZVs+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5 -HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmdGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d7 -70O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5Rp9EixAqnOEhss/n/fauG -V+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NIS+LI+H+S -qHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S -5u046uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4Ia -C1nEWTJ3s7xgaVY5/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TX -OwF0lkLgAOIua+rF7nKsu7/+6qqo+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYE -FJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ -BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByvMiPIs0laUZx2 -KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg -Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B -8OWycvpEgjNC6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQ -MKSOyARiqcTtNd56l+0OOF6SL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc -0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK+4w1IX2COPKpVJEZNZOUbWo6xbLQ -u4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmVBtWVyuEklut89pMF -u+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFgIxpH -YoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8 -GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO -RtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e -KeC2uAloGRwYQw== ------END CERTIFICATE----- - -# Issuer: CN=AffirmTrust Premium ECC O=AffirmTrust -# Subject: CN=AffirmTrust Premium ECC O=AffirmTrust -# Label: "AffirmTrust Premium ECC" -# Serial: 8401224907861490260 -# MD5 Fingerprint: 64:b0:09:55:cf:b1:d5:99:e2:be:13:ab:a6:5d:ea:4d -# SHA1 Fingerprint: b8:23:6b:00:2f:1d:16:86:53:01:55:6c:11:a4:37:ca:eb:ff:c3:bb -# SHA256 Fingerprint: bd:71:fd:f6:da:97:e4:cf:62:d1:64:7a:dd:25:81:b0:7d:79:ad:f8:39:7e:b4:ec:ba:9c:5e:84:88:82:14:23 ------BEGIN CERTIFICATE----- -MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC -VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ -cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ -BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt -VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D -0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9 -ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G -A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G -A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs -aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I -flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ== ------END CERTIFICATE----- - -# Issuer: CN=Certum Trusted Network CA O=Unizeto Technologies S.A. OU=Certum Certification Authority -# Subject: CN=Certum Trusted Network CA O=Unizeto Technologies S.A. OU=Certum Certification Authority -# Label: "Certum Trusted Network CA" -# Serial: 279744 -# MD5 Fingerprint: d5:e9:81:40:c5:18:69:fc:46:2c:89:75:62:0f:aa:78 -# SHA1 Fingerprint: 07:e0:32:e0:20:b7:2c:3f:19:2f:06:28:a2:59:3a:19:a7:0f:06:9e -# SHA256 Fingerprint: 5c:58:46:8d:55:f5:8e:49:7e:74:39:82:d2:b5:00:10:b6:d1:65:37:4a:cf:83:a7:d4:a3:2d:b7:68:c4:40:8e ------BEGIN CERTIFICATE----- -MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM -MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D -ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU -cnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIyMTIwNzM3WhcNMjkxMjMxMTIwNzM3 -WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMg -Uy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIw -IAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0B -AQEFAAOCAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rH -UV+rpDKmYYe2bg+G0jACl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LM -TXPb865Px1bVWqeWifrzq2jUI4ZZJ88JJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVU -BBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4fOQtf/WsX+sWn7Et0brM -kUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0cvW0QM8x -AcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNV -HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15y -sHhE49wcrwn9I0j6vSrEuVUEtRCjjSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfL -I9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv94nYmem8 -J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY -VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI -03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw= ------END CERTIFICATE----- - -# Issuer: CN=TWCA Root Certification Authority O=TAIWAN-CA OU=Root CA -# Subject: CN=TWCA Root Certification Authority O=TAIWAN-CA OU=Root CA -# Label: "TWCA Root Certification Authority" -# Serial: 1 -# MD5 Fingerprint: aa:08:8f:f6:f9:7b:b7:f2:b1:a7:1e:9b:ea:ea:bd:79 -# SHA1 Fingerprint: cf:9e:87:6d:d3:eb:fc:42:26:97:a3:b5:a3:7a:a0:76:a9:06:23:48 -# SHA256 Fingerprint: bf:d8:8f:e1:10:1c:41:ae:3e:80:1b:f8:be:56:35:0e:e9:ba:d1:a6:b9:bd:51:5e:dc:5c:6d:5b:87:11:ac:44 ------BEGIN CERTIFICATE----- -MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzES -MBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFU -V0NBIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMz -WhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJVEFJV0FO -LUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlm -aWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB -AQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFE -AcK0HMMxQhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HH -K3XLfJ+utdGdIzdjp9xCoi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeX -RfwZVzsrb+RH9JlF/h3x+JejiB03HFyP4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/z -rX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1ry+UPizgN7gr8/g+YnzAx -3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkq -hkiG9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeC -MErJk/9q56YAf4lCmtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdls -XebQ79NqZp4VKIV66IIArB6nCWlWQtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62D -lhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVYT0bf+215WfKEIlKuD8z7fDvn -aspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocnyYh0igzyXxfkZ -YiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw== ------END CERTIFICATE----- - -# Issuer: O=SECOM Trust Systems CO.,LTD. OU=Security Communication RootCA2 -# Subject: O=SECOM Trust Systems CO.,LTD. OU=Security Communication RootCA2 -# Label: "Security Communication RootCA2" -# Serial: 0 -# MD5 Fingerprint: 6c:39:7d:a4:0e:55:59:b2:3f:d6:41:b1:12:50:de:43 -# SHA1 Fingerprint: 5f:3b:8c:f2:f8:10:b3:7d:78:b4:ce:ec:19:19:c3:73:34:b9:c7:74 -# SHA256 Fingerprint: 51:3b:2c:ec:b8:10:d4:cd:e5:dd:85:39:1a:df:c6:c2:dd:60:d8:7b:b7:36:d2:b5:21:48:4a:a4:7a:0e:be:f6 ------BEGIN CERTIFICATE----- -MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDEl -MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMe -U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoX -DTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRy -dXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3VyaXR5IENvbW11bmlj -YXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANAV -OVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGr -zbl+dp+++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVM -VAX3NuRFg3sUZdbcDE3R3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQ -hNBqyjoGADdH5H5XTz+L62e4iKrFvlNVspHEfbmwhRkGeC7bYRr6hfVKkaHnFtWO -ojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1KEOtOghY6rCcMU/Gt1SSw -awNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8QIH4D5cs -OPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3 -DQEBCwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpF -coJxDjrSzG+ntKEju/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXc -okgfGT+Ok+vx+hfuzU7jBBJV1uXk3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8 -t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6qtnRGEmyR7jTV7JqR50S+kDFy -1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29mvVXIwAHIRc/ -SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03 ------END CERTIFICATE----- - -# Issuer: CN=EC-ACC O=Agencia Catalana de Certificacio (NIF Q-0801176-I) OU=Serveis Publics de Certificacio/Vegeu https://www.catcert.net/verarrel (c)03/Jerarquia Entitats de Certificacio Catalanes -# Subject: CN=EC-ACC O=Agencia Catalana de Certificacio (NIF Q-0801176-I) OU=Serveis Publics de Certificacio/Vegeu https://www.catcert.net/verarrel (c)03/Jerarquia Entitats de Certificacio Catalanes -# Label: "EC-ACC" -# Serial: -23701579247955709139626555126524820479 -# MD5 Fingerprint: eb:f5:9d:29:0d:61:f9:42:1f:7c:c2:ba:6d:e3:15:09 -# SHA1 Fingerprint: 28:90:3a:63:5b:52:80:fa:e6:77:4c:0b:6d:a7:d6:ba:a6:4a:f2:e8 -# SHA256 Fingerprint: 88:49:7f:01:60:2f:31:54:24:6a:e2:8c:4d:5a:ef:10:f1:d8:7e:bb:76:62:6f:4a:e0:b7:f9:5b:a7:96:87:99 ------BEGIN CERTIFICATE----- -MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB -8zELMAkGA1UEBhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2Vy -dGlmaWNhY2lvIChOSUYgUS0wODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1 -YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYDVQQLEyxWZWdldSBodHRwczovL3d3 -dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UECxMsSmVyYXJxdWlh -IEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMTBkVD -LUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQG -EwJFUzE7MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8g -KE5JRiBRLTA4MDExNzYtSSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBD -ZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZlZ2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQu -bmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJhcnF1aWEgRW50aXRhdHMg -ZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUNDMIIBIjAN -BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R -85iKw5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm -4CgPukLjbo73FCeTae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaV -HMf5NLWUhdWZXqBIoH7nF2W4onW4HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNd -QlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0aE9jD2z3Il3rucO2n5nzbcc8t -lGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw0JDnJwIDAQAB -o4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E -BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4 -opvpXY0wfwYDVR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBo -dHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidW -ZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAwDQYJKoZIhvcN -AQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJlF7W2u++AVtd0x7Y -/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNaAl6k -SBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhy -Rp/7SNVel+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOS -Agu+TGbrIP65y7WZf+a2E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xl -nJ2lYJU6Un/10asIbvPuW/mIPX64b24D5EI= ------END CERTIFICATE----- - -# Issuer: CN=Hellenic Academic and Research Institutions RootCA 2011 O=Hellenic Academic and Research Institutions Cert. Authority -# Subject: CN=Hellenic Academic and Research Institutions RootCA 2011 O=Hellenic Academic and Research Institutions Cert. Authority -# Label: "Hellenic Academic and Research Institutions RootCA 2011" -# Serial: 0 -# MD5 Fingerprint: 73:9f:4c:4b:73:5b:79:e9:fa:ba:1c:ef:6e:cb:d5:c9 -# SHA1 Fingerprint: fe:45:65:9b:79:03:5b:98:a1:61:b5:51:2e:ac:da:58:09:48:22:4d -# SHA256 Fingerprint: bc:10:4f:15:a4:8b:e7:09:dc:a5:42:a7:e1:d4:b9:df:6f:05:45:27:e8:02:ea:a9:2d:59:54:44:25:8a:fe:71 ------BEGIN CERTIFICATE----- -MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1Ix -RDBCBgNVBAoTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1 -dGlvbnMgQ2VydC4gQXV0aG9yaXR5MUAwPgYDVQQDEzdIZWxsZW5pYyBBY2FkZW1p -YyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIFJvb3RDQSAyMDExMB4XDTExMTIw -NjEzNDk1MloXDTMxMTIwMTEzNDk1MlowgZUxCzAJBgNVBAYTAkdSMUQwQgYDVQQK -EztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0dXRpb25zIENl -cnQuIEF1dGhvcml0eTFAMD4GA1UEAxM3SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl -c2VhcmNoIEluc3RpdHV0aW9ucyBSb290Q0EgMjAxMTCCASIwDQYJKoZIhvcNAQEB -BQADggEPADCCAQoCggEBAKlTAOMupvaO+mDYLZU++CwqVE7NuYRhlFhPjz2L5EPz -dYmNUeTDN9KKiE15HrcS3UN4SoqS5tdI1Q+kOilENbgH9mgdVc04UfCMJDGFr4PJ -fel3r+0ae50X+bOdOFAPplp5kYCvN66m0zH7tSYJnTxa71HFK9+WXesyHgLacEns -bgzImjeN9/E2YEsmLIKe0HjzDQ9jpFEw4fkrJxIH2Oq9GGKYsFk3fb7u8yBRQlqD -75O6aRXxYp2fmTmCobd0LovUxQt7L/DICto9eQqakxylKHJzkUOap9FNhYS5qXSP -FEDH3N6sQWRstBmbAmNtJGSPRLIl6s5ddAxjMlyNh+UCAwEAAaOBiTCBhjAPBgNV -HRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQUppFC/RNhSiOeCKQp -5dgTBCPuQSUwRwYDVR0eBEAwPqA8MAWCAy5ncjAFggMuZXUwBoIELmVkdTAGggQu -b3JnMAWBAy5ncjAFgQMuZXUwBoEELmVkdTAGgQQub3JnMA0GCSqGSIb3DQEBBQUA -A4IBAQAf73lB4XtuP7KMhjdCSk4cNx6NZrokgclPEg8hwAOXhiVtXdMiKahsog2p -6z0GW5k6x8zDmjR/qw7IThzh+uTczQ2+vyT+bOdrwg3IBp5OjWEopmr95fZi6hg8 -TqBTnbI6nOulnJEWtk2C4AwFSKls9cz4y51JtPACpf1wA+2KIaWuE4ZJwzNzvoc7 -dIsXRSZMFpGD/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8Acys -Nnq/onN694/BtZqhFLKPM58N7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXI -l7WdmplNsDz4SgCbZN2fOUvRJ9e4 ------END CERTIFICATE----- - -# Issuer: CN=Actalis Authentication Root CA O=Actalis S.p.A./03358520967 -# Subject: CN=Actalis Authentication Root CA O=Actalis S.p.A./03358520967 -# Label: "Actalis Authentication Root CA" -# Serial: 6271844772424770508 -# MD5 Fingerprint: 69:c1:0d:4f:07:a3:1b:c3:fe:56:3d:04:bc:11:f6:a6 -# SHA1 Fingerprint: f3:73:b3:87:06:5a:28:84:8a:f2:f3:4a:ce:19:2b:dd:c7:8e:9c:ac -# SHA256 Fingerprint: 55:92:60:84:ec:96:3a:64:b9:6e:2a:be:01:ce:0b:a8:6a:64:fb:fe:bc:c7:aa:b5:af:c1:55:b3:7f:d7:60:66 ------BEGIN CERTIFICATE----- -MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UE -BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w -MzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290 -IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDkyMjExMjIwMlowazELMAkGA1UEBhMC -SVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1 -ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENB -MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNv -UTufClrJwkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX -4ay8IMKx4INRimlNAJZaby/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9 -KK3giq0itFZljoZUj5NDKd45RnijMCO6zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/ -gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1fYVEiVRvjRuPjPdA1Yprb -rxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2oxgkg4YQ -51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2F -be8lEfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxe -KF+w6D9Fz8+vm2/7hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4F -v6MGn8i1zeQf1xcGDXqVdFUNaBr8EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbn -fpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5jF66CyCU3nuDuP/jVo23Eek7 -jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLYiDrIn3hm7Ynz -ezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt -ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAL -e3KHwGCmSUyIWOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70 -jsNjLiNmsGe+b7bAEzlgqqI0JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDz -WochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKxK3JCaKygvU5a2hi/a5iB0P2avl4V -SM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+Xlff1ANATIGk0k9j -pwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC4yyX -X04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+Ok -fcvHlXHo2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7R -K4X9p2jIugErsWx0Hbhzlefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btU -ZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXemOR/qnuOf0GZvBeyqdn6/axag67XH/JJU -LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT -LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg== ------END CERTIFICATE----- - -# Issuer: CN=Buypass Class 2 Root CA O=Buypass AS-983163327 -# Subject: CN=Buypass Class 2 Root CA O=Buypass AS-983163327 -# Label: "Buypass Class 2 Root CA" -# Serial: 2 -# MD5 Fingerprint: 46:a7:d2:fe:45:fb:64:5a:a8:59:90:9b:78:44:9b:29 -# SHA1 Fingerprint: 49:0a:75:74:de:87:0a:47:fe:58:ee:f6:c7:6b:eb:c6:0b:12:40:99 -# SHA256 Fingerprint: 9a:11:40:25:19:7c:5b:b9:5d:94:e6:3d:55:cd:43:79:08:47:b6:46:b2:3c:df:11:ad:a4:a0:0e:ff:15:fb:48 ------BEGIN CERTIFICATE----- -MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd -MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg -Q2xhc3MgMiBSb290IENBMB4XDTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1ow -TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw -HgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB -BQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1g1Lr -6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPV -L4O2fuPn9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC91 -1K2GScuVr1QGbNgGE41b/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHx -MlAQTn/0hpPshNOOvEu/XAFOBz3cFIqUCqTqc/sLUegTBxj6DvEr0VQVfTzh97QZ -QmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeffawrbD02TTqigzXsu8lkB -arcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgIzRFo1clr -Us3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLi -FRhnBkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRS -P/TizPJhk9H9Z2vXUq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN -9SG9dKpN6nIDSdvHXx1iY8f93ZHsM+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxP -AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMmAd+BikoL1Rpzz -uvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAU18h -9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s -A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3t -OluwlN5E40EIosHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo -+fsicdl9sz1Gv7SEr5AcD48Saq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7 -KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYdDnkM/crqJIByw5c/8nerQyIKx+u2 -DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWDLfJ6v9r9jv6ly0Us -H8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0oyLQ -I+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK7 -5t98biGCwWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h -3PFaTWwyI0PurKju7koSCTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPz -Y11aWOIv4x3kqdbQCtCev9eBCfHJxyYNrJgWVqA= ------END CERTIFICATE----- - -# Issuer: CN=Buypass Class 3 Root CA O=Buypass AS-983163327 -# Subject: CN=Buypass Class 3 Root CA O=Buypass AS-983163327 -# Label: "Buypass Class 3 Root CA" -# Serial: 2 -# MD5 Fingerprint: 3d:3b:18:9e:2c:64:5a:e8:d5:88:ce:0e:f9:37:c2:ec -# SHA1 Fingerprint: da:fa:f7:fa:66:84:ec:06:8f:14:50:bd:c7:c2:81:a5:bc:a9:64:57 -# SHA256 Fingerprint: ed:f7:eb:bc:a2:7a:2a:38:4d:38:7b:7d:40:10:c6:66:e2:ed:b4:84:3e:4c:29:b4:ae:1d:5b:93:32:e6:b2:4d ------BEGIN CERTIFICATE----- -MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd -MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg -Q2xhc3MgMyBSb290IENBMB4XDTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFow -TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw -HgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB -BQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRHsJ8Y -ZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3E -N3coTRiR5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9 -tznDDgFHmV0ST9tD+leh7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX -0DJq1l1sDPGzbjniazEuOQAnFN44wOwZZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c -/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH2xc519woe2v1n/MuwU8X -KhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV/afmiSTY -zIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvS -O1UQRwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D -34xFMFbG02SrZvPAXpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgP -K9Dx2hzLabjKSWJtyNBjYt1gD1iqj6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3 -AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFEe4zf/lb+74suwv -Tg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAACAj -QTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV -cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXS -IGrs/CIBKM+GuIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2 -HJLw5QY33KbmkJs4j1xrG0aGQ0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsa -O5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8ZORK15FTAaggiG6cX0S5y2CBNOxv -033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2KSb12tjE8nVhz36u -dmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz6MkE -kbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg41 -3OEMXbugUZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvD -u79leNKGef9JOxqDDPDeeOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq -4/g7u9xN12TyUb7mqqta6THuBrxzvxNiCp/HuZc= ------END CERTIFICATE----- - -# Issuer: CN=T-TeleSec GlobalRoot Class 3 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center -# Subject: CN=T-TeleSec GlobalRoot Class 3 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center -# Label: "T-TeleSec GlobalRoot Class 3" -# Serial: 1 -# MD5 Fingerprint: ca:fb:40:a8:4e:39:92:8a:1d:fe:8e:2f:c4:27:ea:ef -# SHA1 Fingerprint: 55:a6:72:3e:cb:f2:ec:cd:c3:23:74:70:19:9d:2a:be:11:e3:81:d1 -# SHA256 Fingerprint: fd:73:da:d3:1c:64:4f:f1:b4:3b:ef:0c:cd:da:96:71:0b:9c:d9:87:5e:ca:7e:31:70:7a:f3:e9:6d:52:2b:bd ------BEGIN CERTIFICATE----- -MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx -KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd -BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl -YyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgxMDAxMTAyOTU2WhcNMzMxMDAxMjM1 -OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy -aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 -ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0G -CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN -8ELg63iIVl6bmlQdTQyK9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/ -RLyTPWGrTs0NvvAgJ1gORH8EGoel15YUNpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4 -hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZFiP0Zf3WHHx+xGwpzJFu5 -ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W0eDrXltM -EnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGj -QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1 -A/d2O2GCahKqGFPrAyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOy -WL6ukK2YJ5f+AbGwUgC4TeQbIXQbfsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ -1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzTucpH9sry9uetuUg/vBa3wW30 -6gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7hP0HHRwA11fXT -91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml -e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4p -TpPDpFQUWw== ------END CERTIFICATE----- - -# Issuer: CN=D-TRUST Root Class 3 CA 2 2009 O=D-Trust GmbH -# Subject: CN=D-TRUST Root Class 3 CA 2 2009 O=D-Trust GmbH -# Label: "D-TRUST Root Class 3 CA 2 2009" -# Serial: 623603 -# MD5 Fingerprint: cd:e0:25:69:8d:47:ac:9c:89:35:90:f7:fd:51:3d:2f -# SHA1 Fingerprint: 58:e8:ab:b0:36:15:33:fb:80:f7:9b:1b:6d:29:d3:ff:8d:5f:00:f0 -# SHA256 Fingerprint: 49:e7:a4:42:ac:f0:ea:62:87:05:00:54:b5:25:64:b6:50:e4:f4:9e:42:e3:48:d6:aa:38:e0:39:e9:57:b1:c1 ------BEGIN CERTIFICATE----- -MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRF -MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBD -bGFzcyAzIENBIDIgMjAwOTAeFw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NTha -ME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMM -HkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIwDQYJKoZIhvcNAQEB -BQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOADER03 -UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42 -tSHKXzlABF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9R -ySPocq60vFYJfxLLHLGvKZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsM -lFqVlNpQmvH/pStmMaTJOKDfHR+4CS7zp+hnUquVH+BGPtikw8paxTGA6Eian5Rp -/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUCAwEAAaOCARowggEWMA8G -A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ4PGEMA4G -A1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVj -dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUy -MENBJTIwMiUyMDIwMDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRl -cmV2b2NhdGlvbmxpc3QwQ6BBoD+GPWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3Js -L2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAwOS5jcmwwDQYJKoZIhvcNAQEL -BQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm2H6NMLVwMeni -acfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 -o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4K -zCUqNQT4YJEVdT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8 -PIWmawomDeCTmGCufsYkl4phX5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3Y -Johw1+qRzT65ysCQblrGXnRl11z+o+I= ------END CERTIFICATE----- - -# Issuer: CN=D-TRUST Root Class 3 CA 2 EV 2009 O=D-Trust GmbH -# Subject: CN=D-TRUST Root Class 3 CA 2 EV 2009 O=D-Trust GmbH -# Label: "D-TRUST Root Class 3 CA 2 EV 2009" -# Serial: 623604 -# MD5 Fingerprint: aa:c6:43:2c:5e:2d:cd:c4:34:c0:50:4f:11:02:4f:b6 -# SHA1 Fingerprint: 96:c9:1b:0b:95:b4:10:98:42:fa:d0:d8:22:79:fe:60:fa:b9:16:83 -# SHA256 Fingerprint: ee:c5:49:6b:98:8c:e9:86:25:b9:34:09:2e:ec:29:08:be:d0:b0:f3:16:c2:d4:73:0c:84:ea:f1:f3:d3:48:81 ------BEGIN CERTIFICATE----- -MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRF -MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBD -bGFzcyAzIENBIDIgRVYgMjAwOTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUw -NDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNV -BAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAwOTCCASIwDQYJKoZI -hvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfSegpn -ljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM0 -3TP1YtHhzRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6Z -qQTMFexgaDbtCHu39b+T7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lR -p75mpoo6Kr3HGrHhFPC+Oh25z1uxav60sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8 -HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure3511H3a6UCAwEAAaOCASQw -ggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyvcop9Ntea -HNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFw -Oi8vZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xh -c3MlMjAzJTIwQ0ElMjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1E -RT9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0MEagRKBChkBodHRwOi8vd3d3LmQt -dHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xhc3NfM19jYV8yX2V2XzIwMDku -Y3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+PPoeUSbrh/Yp -3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 -nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNF -CSuGdXzfX2lXANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7na -xpeG0ILD5EJt/rDiZE4OJudANCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqX -KVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVvw9y4AyHqnxbxLFS1 ------END CERTIFICATE----- - -# Issuer: CN=CA Disig Root R2 O=Disig a.s. -# Subject: CN=CA Disig Root R2 O=Disig a.s. -# Label: "CA Disig Root R2" -# Serial: 10572350602393338211 -# MD5 Fingerprint: 26:01:fb:d8:27:a7:17:9a:45:54:38:1a:43:01:3b:03 -# SHA1 Fingerprint: b5:61:eb:ea:a4:de:e4:25:4b:69:1a:98:a5:57:47:c2:34:c7:d9:71 -# SHA256 Fingerprint: e2:3d:4a:03:6d:7b:70:e9:f5:95:b1:42:20:79:d2:b9:1e:df:bb:1f:b6:51:a0:63:3e:aa:8a:9d:c5:f8:07:03 ------BEGIN CERTIFICATE----- -MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNV -BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu -MRkwFwYDVQQDExBDQSBEaXNpZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQy -MDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sxEzARBgNVBAcTCkJyYXRpc2xhdmEx -EzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERpc2lnIFJvb3QgUjIw -ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbCw3Oe -NcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNH -PWSb6WiaxswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3I -x2ymrdMxp7zo5eFm1tL7A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbe -QTg06ov80egEFGEtQX6sx3dOy1FU+16SGBsEWmjGycT6txOgmLcRK7fWV8x8nhfR -yyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqVg8NTEQxzHQuyRpDRQjrO -QG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa5Beny912 -H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJ -QfYEkoopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUD -i/ZnWejBBhG93c+AAk9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORs -nLMOPReisjQS1n6yqEm70XooQL6iFh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1 -rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud -DwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5uQu0wDQYJKoZI -hvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM -tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqf -GopTpti72TVVsRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkb -lvdhuDvEK7Z4bLQjb/D907JedR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka -+elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W81k/BfDxujRNt+3vrMNDcTa/F1bal -TFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjxmHHEt38OFdAlab0i -nSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01utI3 -gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18Dr -G5gPcFw0sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3Os -zMOl6W8KjptlwlCFtaOgUxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8x -L4ysEr3vQCj8KWefshNPZiTEUxnpHikV7+ZtsH8tZ/3zbBt1RqPlShfppNcL ------END CERTIFICATE----- - -# Issuer: CN=ACCVRAIZ1 O=ACCV OU=PKIACCV -# Subject: CN=ACCVRAIZ1 O=ACCV OU=PKIACCV -# Label: "ACCVRAIZ1" -# Serial: 6828503384748696800 -# MD5 Fingerprint: d0:a0:5a:ee:05:b6:09:94:21:a1:7d:f1:b2:29:82:02 -# SHA1 Fingerprint: 93:05:7a:88:15:c6:4f:ce:88:2f:fa:91:16:52:28:78:bc:53:64:17 -# SHA256 Fingerprint: 9a:6e:c0:12:e1:a7:da:9d:be:34:19:4d:47:8a:d7:c0:db:18:22:fb:07:1d:f1:29:81:49:6e:d1:04:38:41:13 ------BEGIN CERTIFICATE----- -MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UE -AwwJQUNDVlJBSVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQsw -CQYDVQQGEwJFUzAeFw0xMTA1MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQ -BgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwHUEtJQUNDVjENMAsGA1UECgwEQUND -VjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCb -qau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gMjmoY -HtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWo -G2ioPej0RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpA -lHPrzg5XPAOBOp0KoVdDaaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhr -IA8wKFSVf+DuzgpmndFALW4ir50awQUZ0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/ -0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDGWuzndN9wrqODJerWx5eH -k6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs78yM2x/47 -4KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMO -m3WR5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpa -cXpkatcnYGMN285J9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPl -uUsXQA+xtrn13k/c4LOsOxFwYIRKQ26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYI -KwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRwOi8vd3d3LmFjY3YuZXMvZmls -ZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEuY3J0MB8GCCsG -AQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2 -VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeT -VfZW6oHlNsyMHj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIG -CCsGAQUFBwICMIIBFB6CARAAQQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUA -cgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBhAO0AegAgAGQAZQAgAGwAYQAgAEEA -QwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUAYwBuAG8AbABvAGcA -7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBjAHQA -cgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAA -QwBQAFMAIABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUA -czAwBggrBgEFBQcCARYkaHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2Mu -aHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRt -aW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2MV9kZXIuY3JsMA4GA1Ud -DwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZIhvcNAQEF -BQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdp -D70ER9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gU -JyCpZET/LtZ1qmxNYEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+m -AM/EKXMRNt6GGT6d7hmKG9Ww7Y49nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepD -vV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJTS+xJlsndQAJxGJ3KQhfnlms -tn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3sCPdK6jT2iWH -7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h -I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szA -h1xA2syVP1XgNce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xF -d3+YJ5oyXSrjhO7FmGYvliAd3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2H -pPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3pEfbRD0tVNEYqi4Y7 ------END CERTIFICATE----- - -# Issuer: CN=TWCA Global Root CA O=TAIWAN-CA OU=Root CA -# Subject: CN=TWCA Global Root CA O=TAIWAN-CA OU=Root CA -# Label: "TWCA Global Root CA" -# Serial: 3262 -# MD5 Fingerprint: f9:03:7e:cf:e6:9e:3c:73:7a:2a:90:07:69:ff:2b:96 -# SHA1 Fingerprint: 9c:bb:48:53:f6:a4:f6:d3:52:a4:e8:32:52:55:60:13:f5:ad:af:65 -# SHA256 Fingerprint: 59:76:90:07:f7:68:5d:0f:cd:50:87:2f:9f:95:d5:75:5a:5b:2b:45:7d:81:f3:69:2b:61:0a:98:67:2f:0e:1b ------BEGIN CERTIFICATE----- -MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcx -EjAQBgNVBAoTCVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMT -VFdDQSBHbG9iYWwgUm9vdCBDQTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5 -NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQKEwlUQUlXQU4tQ0ExEDAOBgNVBAsT -B1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3QgQ0EwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2CnJfF -10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz -0ALfUPZVr2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfCh -MBwqoJimFb3u/Rk28OKRQ4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbH -zIh1HrtsBv+baz4X7GGqcXzGHaL3SekVtTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc -46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1WKKD+u4ZqyPpcC1jcxkt2 -yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99sy2sbZCi -laLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYP -oA/pyJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQA -BDzfuBSO6N+pjWxnkjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcE -qYSjMq+u7msXi7Kx/mzhkIyIqJdIzshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm -4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB -/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6gcFGn90xHNcgL -1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn -LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WF -H6vPNOw/KP4M8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNo -RI2T9GRwoD2dKAXDOXC4Ynsg/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+ -nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlglPx4mI88k1HtQJAH32RjJMtOcQWh -15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryPA9gK8kxkRr05YuWW -6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3mi4TW -nsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5j -wa19hAM8EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWz -aGHQRiapIVJpLesux+t3zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmy -KwbQBM0= ------END CERTIFICATE----- - -# Issuer: CN=TeliaSonera Root CA v1 O=TeliaSonera -# Subject: CN=TeliaSonera Root CA v1 O=TeliaSonera -# Label: "TeliaSonera Root CA v1" -# Serial: 199041966741090107964904287217786801558 -# MD5 Fingerprint: 37:41:49:1b:18:56:9a:26:f5:ad:c2:66:fb:40:a5:4c -# SHA1 Fingerprint: 43:13:bb:96:f1:d5:86:9b:c1:4e:6a:92:f6:cf:f6:34:69:87:82:37 -# SHA256 Fingerprint: dd:69:36:fe:21:f8:f0:77:c1:23:a1:a5:21:c1:22:24:f7:22:55:b7:3e:03:a7:26:06:93:e8:a2:4b:0f:a3:89 ------BEGIN CERTIFICATE----- -MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAw -NzEUMBIGA1UECgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJv -b3QgQ0EgdjEwHhcNMDcxMDE4MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYD -VQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwWVGVsaWFTb25lcmEgUm9vdCBDQSB2 -MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+6yfwIaPzaSZVfp3F -VRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA3GV1 -7CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+X -Z75Ljo1kB1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+ -/jXh7VB7qTCNGdMJjmhnXb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs -81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxHoLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkm -dtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3F0fUTPHSiXk+TT2YqGHe -Oh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJoWjiUIMu -sDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4 -pgd7gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fs -slESl1MpWtTwEhDcTwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQ -arMCpgKIv7NHfirZ1fpoeDVNAgMBAAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYD -VR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qWDNXr+nuqF+gTEjANBgkqhkiG -9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNmzqjMDfz1mgbl -dxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx -0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1Tj -TQpgcmLNkQfWpb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBed -Y2gea+zDTYa4EzAvXUYNR0PVG6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7 -Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpcc41teyWRyu5FrgZLAMzTsVlQ2jqI -OylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOTJsjrDNYmiLbAJM+7 -vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2qReW -t88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcn -HL/EVlP6Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVx -SK236thZiNSQvxaz2emsWWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY= ------END CERTIFICATE----- - -# Issuer: CN=E-Tugra Certification Authority O=E-Tu\u011fra EBG Bili\u015fim Teknolojileri ve Hizmetleri A.\u015e. OU=E-Tugra Sertifikasyon Merkezi -# Subject: CN=E-Tugra Certification Authority O=E-Tu\u011fra EBG Bili\u015fim Teknolojileri ve Hizmetleri A.\u015e. OU=E-Tugra Sertifikasyon Merkezi -# Label: "E-Tugra Certification Authority" -# Serial: 7667447206703254355 -# MD5 Fingerprint: b8:a1:03:63:b0:bd:21:71:70:8a:6f:13:3a:bb:79:49 -# SHA1 Fingerprint: 51:c6:e7:08:49:06:6e:f3:92:d4:5c:a0:0d:6d:a3:62:8f:c3:52:39 -# SHA256 Fingerprint: b0:bf:d5:2b:b0:d7:d9:bd:92:bf:5d:4d:c1:3d:a2:55:c0:2c:54:2f:37:83:65:ea:89:39:11:f5:5e:55:f2:3c ------BEGIN CERTIFICATE----- -MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNV -BAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBC -aWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhpem1ldGxlcmkgQS7Fni4xJjAkBgNV -BAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBNZXJrZXppMSgwJgYDVQQDDB9FLVR1 -Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTEzMDMwNTEyMDk0OFoXDTIz -MDMwMzEyMDk0OFowgbIxCzAJBgNVBAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+ -BgNVBAoMN0UtVHXEn3JhIEVCRyBCaWxpxZ9pbSBUZWtub2xvamlsZXJpIHZlIEhp -em1ldGxlcmkgQS7Fni4xJjAkBgNVBAsMHUUtVHVncmEgU2VydGlmaWthc3lvbiBN -ZXJrZXppMSgwJgYDVQQDDB9FLVR1Z3JhIENlcnRpZmljYXRpb24gQXV0aG9yaXR5 -MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA4vU/kwVRHoViVF56C/UY -B4Oufq9899SKa6VjQzm5S/fDxmSJPZQuVIBSOTkHS0vdhQd2h8y/L5VMzH2nPbxH -D5hw+IyFHnSOkm0bQNGZDbt1bsipa5rAhDGvykPL6ys06I+XawGb1Q5KCKpbknSF -Q9OArqGIW66z6l7LFpp3RMih9lRozt6Plyu6W0ACDGQXwLWTzeHxE2bODHnv0ZEo -q1+gElIwcxmOj+GMB6LDu0rw6h8VqO4lzKRG+Bsi77MOQ7osJLjFLFzUHPhdZL3D -k14opz8n8Y4e0ypQBaNV2cvnOVPAmJ6MVGKLJrD3fY185MaeZkJVgkfnsliNZvcH -fC425lAcP9tDJMW/hkd5s3kc91r0E+xs+D/iWR+V7kI+ua2oMoVJl0b+SzGPWsut -dEcf6ZG33ygEIqDUD13ieU/qbIWGvaimzuT6w+Gzrt48Ue7LE3wBf4QOXVGUnhMM -ti6lTPk5cDZvlsouDERVxcr6XQKj39ZkjFqzAQqptQpHF//vkUAqjqFGOjGY5RH8 -zLtJVor8udBhmm9lbObDyz51Sf6Pp+KJxWfXnUYTTjF2OySznhFlhqt/7x3U+Lzn -rFpct1pHXFXOVbQicVtbC/DP3KBhZOqp12gKY6fgDT+gr9Oq0n7vUaDmUStVkhUX -U8u3Zg5mTPj5dUyQ5xJwx0UCAwEAAaNjMGEwHQYDVR0OBBYEFC7j27JJ0JxUeVz6 -Jyr+zE7S6E5UMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAULuPbsknQnFR5 -XPonKv7MTtLoTlQwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAF -Nzr0TbdF4kV1JI+2d1LoHNgQk2Xz8lkGpD4eKexd0dCrfOAKkEh47U6YA5n+KGCR -HTAduGN8qOY1tfrTYXbm1gdLymmasoR6d5NFFxWfJNCYExL/u6Au/U5Mh/jOXKqY -GwXgAEZKgoClM4so3O0409/lPun++1ndYYRP0lSWE2ETPo+Aab6TR7U1Q9Jauz1c -77NCR807VRMGsAnb/WP2OogKmW9+4c4bU2pEZiNRCHu8W1Ki/QY3OEBhj0qWuJA3 -+GbHeJAAFS6LrVE1Uweoa2iu+U48BybNCAVwzDk/dr2l02cmAYamU9JgO3xDf1WK -vJUawSg5TB9D0pH0clmKuVb8P7Sd2nCcdlqMQ1DujjByTd//SffGqWfZbawCEeI6 -FiWnWAjLb1NBnEg4R2gz0dfHj9R0IdTDBZB6/86WiLEVKV0jq9BgoRJP3vQXzTLl -yb/IQ639Lo7xr+L0mPoSHyDYwKcMhcWQ9DstliaxLL5Mq+ux0orJ23gTDx4JnW2P -AJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpD -y4Q08ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8d -NL/+I5c30jn6PQ0GC7TbO6Orb1wdtn7os4I07QZcJA== ------END CERTIFICATE----- - -# Issuer: CN=T-TeleSec GlobalRoot Class 2 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center -# Subject: CN=T-TeleSec GlobalRoot Class 2 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center -# Label: "T-TeleSec GlobalRoot Class 2" -# Serial: 1 -# MD5 Fingerprint: 2b:9b:9e:e4:7b:6c:1f:00:72:1a:cc:c1:77:79:df:6a -# SHA1 Fingerprint: 59:0d:2d:7d:88:4f:40:2e:61:7e:a5:62:32:17:65:cf:17:d8:94:e9 -# SHA256 Fingerprint: 91:e2:f5:78:8d:58:10:eb:a7:ba:58:73:7d:e1:54:8a:8e:ca:cd:01:45:98:bc:0b:14:3e:04:1b:17:05:25:52 ------BEGIN CERTIFICATE----- -MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx -KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd -BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl -YyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgxMDAxMTA0MDE0WhcNMzMxMDAxMjM1 -OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy -aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50 -ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0G -CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUd -AqSzm1nzHoqvNK38DcLZSBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiC -FoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/FvudocP05l03Sx5iRUKrERLMjfTlH6VJi -1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx9702cu+fjOlbpSD8DT6Iavq -jnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGVWOHAD3bZ -wI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGj -QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/ -WSA2AHmgoCJrjNXyYdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhy -NsZt+U2e+iKo4YFWz827n+qrkRk4r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPAC -uvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNfvNoBYimipidx5joifsFvHZVw -IEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR3p1m0IvVVGb6 -g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN -9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlP -BSeOE6Fuwg== ------END CERTIFICATE----- - -# Issuer: CN=Atos TrustedRoot 2011 O=Atos -# Subject: CN=Atos TrustedRoot 2011 O=Atos -# Label: "Atos TrustedRoot 2011" -# Serial: 6643877497813316402 -# MD5 Fingerprint: ae:b9:c4:32:4b:ac:7f:5d:66:cc:77:94:bb:2a:77:56 -# SHA1 Fingerprint: 2b:b1:f5:3e:55:0c:1d:c5:f1:d4:e6:b7:6a:46:4b:55:06:02:ac:21 -# SHA256 Fingerprint: f3:56:be:a2:44:b7:a9:1e:b3:5d:53:ca:9a:d7:86:4a:ce:01:8e:2d:35:d5:f8:f9:6d:df:68:a6:f4:1a:a4:74 ------BEGIN CERTIFICATE----- -MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE -AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG -EwJERTAeFw0xMTA3MDcxNDU4MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMM -FUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UEBhMC -REUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCVhTuXbyo7LjvPpvMp -Nb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr54rM -VD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+ -SZFhyBH+DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ -4J7sVaE3IqKHBAUsR320HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0L -cp2AMBYHlT8oDv3FdU9T1nSatCQujgKRz3bFmx5VdJx4IbHwLfELn8LVlhgf8FQi -eowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7Rl+lwrrw7GWzbITAPBgNV -HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZbNshMBgG -A1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3 -DQEBCwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8j -vZfza1zv7v1Apt+hk6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kP -DpFrdRbhIfzYJsdHt6bPWHJxfrrhTZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pc -maHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a961qn8FYiqTxlVMYVqL2Gns2D -lmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G3mB/ufNPRJLv -KrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed ------END CERTIFICATE----- - -# Issuer: CN=QuoVadis Root CA 1 G3 O=QuoVadis Limited -# Subject: CN=QuoVadis Root CA 1 G3 O=QuoVadis Limited -# Label: "QuoVadis Root CA 1 G3" -# Serial: 687049649626669250736271037606554624078720034195 -# MD5 Fingerprint: a4:bc:5b:3f:fe:37:9a:fa:64:f0:e2:fa:05:3d:0b:ab -# SHA1 Fingerprint: 1b:8e:ea:57:96:29:1a:c9:39:ea:b8:0a:81:1a:73:73:c0:93:79:67 -# SHA256 Fingerprint: 8a:86:6f:d1:b2:76:b5:7e:57:8e:92:1c:65:82:8a:2b:ed:58:e9:f2:f2:88:05:41:34:b7:f1:f4:bf:c9:cc:74 ------BEGIN CERTIFICATE----- -MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQEL -BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc -BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00 -MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM -aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEgRzMwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakEPBtV -wedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWe -rNrwU8lmPNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF341 -68Xfuw6cwI2H44g4hWf6Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh -4Pw5qlPafX7PGglTvF0FBM+hSo+LdoINofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXp -UhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/lg6AnhF4EwfWQvTA9xO+o -abw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV7qJZjqlc -3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/G -KubX9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSt -hfbZxbGL0eUQMk1fiyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KO -Tk0k+17kBL5yG6YnLUlamXrXXAkgt3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOt -zCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB -BjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZIhvcNAQELBQAD -ggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC -MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2 -cDMT/uFPpiN3GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUN -qXsCHKnQO18LwIE6PWThv6ctTr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5 -YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP+V04ikkwj+3x6xn0dxoxGE1nVGwv -b2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh3jRJjehZrJ3ydlo2 -8hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fawx/k -NSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNj -ZgKAvQU6O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhp -q1467HxpvMc7hU6eFbm0FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFt -nh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOVhMJKzRwuJIczYOXD ------END CERTIFICATE----- - -# Issuer: CN=QuoVadis Root CA 2 G3 O=QuoVadis Limited -# Subject: CN=QuoVadis Root CA 2 G3 O=QuoVadis Limited -# Label: "QuoVadis Root CA 2 G3" -# Serial: 390156079458959257446133169266079962026824725800 -# MD5 Fingerprint: af:0c:86:6e:bf:40:2d:7f:0b:3e:12:50:ba:12:3d:06 -# SHA1 Fingerprint: 09:3c:61:f3:8b:8b:dc:7d:55:df:75:38:02:05:00:e1:25:f5:c8:36 -# SHA256 Fingerprint: 8f:e4:fb:0a:f9:3a:4d:0d:67:db:0b:eb:b2:3e:37:c7:1b:f3:25:dc:bc:dd:24:0e:a0:4d:af:58:b4:7e:18:40 ------BEGIN CERTIFICATE----- -MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQEL -BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc -BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00 -MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM -aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIgRzMwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFhZiFf -qq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMW -n4rjyduYNM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ym -c5GQYaYDFCDy54ejiK2toIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+ -O7q414AB+6XrW7PFXmAqMaCvN+ggOp+oMiwMzAkd056OXbxMmO7FGmh77FOm6RQ1 -o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+lV0POKa2Mq1W/xPtbAd0j -IaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZoL1NesNKq -IcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz -8eQQsSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43eh -vNURG3YBZwjgQQvD6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l -7ZizlWNof/k19N+IxWA1ksB8aRxhlRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALG -cC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB -BjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZIhvcNAQELBQAD -ggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66 -AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RC -roijQ1h5fq7KpVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0Ga -W/ZZGYjeVYg3UQt4XAoeo0L9x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4n -lv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgzdWqTHBLmYF5vHX/JHyPLhGGfHoJE -+V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6XU/IyAgkwo1jwDQHV -csaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+NwmNtd -dbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNg -KCLjsZWDzYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeM -HVOyToV7BjjHLPj4sHKNJeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4 -WSr2Rz0ZiC3oheGe7IUIarFsNMkd7EgrO3jtZsSOeWmD3n+M ------END CERTIFICATE----- - -# Issuer: CN=QuoVadis Root CA 3 G3 O=QuoVadis Limited -# Subject: CN=QuoVadis Root CA 3 G3 O=QuoVadis Limited -# Label: "QuoVadis Root CA 3 G3" -# Serial: 268090761170461462463995952157327242137089239581 -# MD5 Fingerprint: df:7d:b9:ad:54:6f:68:a1:df:89:57:03:97:43:b0:d7 -# SHA1 Fingerprint: 48:12:bd:92:3c:a8:c4:39:06:e7:30:6d:27:96:e6:a4:cf:22:2e:7d -# SHA256 Fingerprint: 88:ef:81:de:20:2e:b0:18:45:2e:43:f8:64:72:5c:ea:5f:bd:1f:c2:d9:d2:05:73:07:09:c5:d8:b8:69:0f:46 ------BEGIN CERTIFICATE----- -MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQEL -BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc -BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00 -MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM -aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMgRzMwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286IxSR -/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNu -FoM7pmRLMon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXR -U7Ox7sWTaYI+FrUoRqHe6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+c -ra1AdHkrAj80//ogaX3T7mH1urPnMNA3I4ZyYUUpSFlob3emLoG+B01vr87ERROR -FHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3UVDmrJqMz6nWB2i3ND0/k -A9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f75li59wzw -eyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634Ryl -sSqiMd5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBp -VzgeAVuNVejH38DMdyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0Q -A4XN8f+MFrXBsj6IbGB/kE+V9/YtrQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+ -ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB -BjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZIhvcNAQELBQAD -ggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px -KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnI -FUBhynLWcKzSt/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5Wvv -oxXqA/4Ti2Tk08HS6IT7SdEQTXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFg -u/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9DuDcpmvJRPpq3t/O5jrFc/ZSXPsoaP -0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGibIh6BJpsQBJFxwAYf -3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmDhPbl -8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+ -DhcI00iX0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HN -PlopNLk9hM6xZdRZkZFWdSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/ -ywaZWWDYWGWVjUTR939+J399roD1B0y2PpxxVJkES/1Y+Zj0 ------END CERTIFICATE----- - -# Issuer: CN=DigiCert Assured ID Root G2 O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Assured ID Root G2 O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Assured ID Root G2" -# Serial: 15385348160840213938643033620894905419 -# MD5 Fingerprint: 92:38:b9:f8:63:24:82:65:2c:57:33:e6:fe:81:8f:9d -# SHA1 Fingerprint: a1:4b:48:d9:43:ee:0a:0e:40:90:4f:3c:e0:a4:c0:91:93:51:5d:3f -# SHA256 Fingerprint: 7d:05:eb:b6:82:33:9f:8c:94:51:ee:09:4e:eb:fe:fa:79:53:a1:14:ed:b2:f4:49:49:45:2f:ab:7d:2f:c1:85 ------BEGIN CERTIFICATE----- -MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv -b3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQG -EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl -cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwggEi -MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSA -n61UQbVH35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4Htecc -biJVMWWXvdMX0h5i89vqbFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9Hp -EgjAALAcKxHad3A2m67OeYfcgnDmCXRwVWmvo2ifv922ebPynXApVfSr/5Vh88lA -bx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OPYLfykqGxvYmJHzDNw6Yu -YjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+RnlTGNAgMB -AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQW -BBTOw0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPI -QW5pJ6d1Ee88hjZv0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I -0jJmwYrA8y8678Dj1JGG0VDjA9tzd29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4Gni -lmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAWhsI6yLETcDbYz+70CjTVW0z9 -B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv -ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo -IhNzbM8m9Yop5w== ------END CERTIFICATE----- - -# Issuer: CN=DigiCert Assured ID Root G3 O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Assured ID Root G3 O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Assured ID Root G3" -# Serial: 15459312981008553731928384953135426796 -# MD5 Fingerprint: 7c:7f:65:31:0c:81:df:8d:ba:3e:99:e2:5c:ad:6e:fb -# SHA1 Fingerprint: f5:17:a2:4f:9a:48:c6:c9:f8:a2:00:26:9f:dc:0f:48:2c:ab:30:89 -# SHA256 Fingerprint: 7e:37:cb:8b:4c:47:09:0c:ab:36:55:1b:a6:f4:5d:b8:40:68:0f:ba:16:6a:95:2d:b1:00:71:7f:43:05:3f:c2 ------BEGIN CERTIFICATE----- -MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw -CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu -ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg -RzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQGEwJV -UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu -Y29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQBgcq -hkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJf -Zn4f5dwbRXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17Q -RSAPWXYQ1qAk8C3eNvJsKTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ -BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgFUaFNN6KDec6NHSrkhDAKBggqhkjOPQQD -AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY -JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv -6pZjamVFkpUBtA== ------END CERTIFICATE----- - -# Issuer: CN=DigiCert Global Root G2 O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Global Root G2 O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Global Root G2" -# Serial: 4293743540046975378534879503202253541 -# MD5 Fingerprint: e4:a6:8a:c8:54:ac:52:42:46:0a:fd:72:48:1b:2a:44 -# SHA1 Fingerprint: df:3c:24:f9:bf:d6:66:76:1b:26:80:73:fe:06:d1:cc:8d:4f:82:a4 -# SHA256 Fingerprint: cb:3c:cb:b7:60:31:e5:e0:13:8f:8d:d3:9a:23:f9:de:47:ff:c3:5e:43:c1:14:4c:ea:27:d4:6a:5a:b1:cb:5f ------BEGIN CERTIFICATE----- -MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH -MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT -MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j -b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG -9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI -2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx -1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ -q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz -tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ -vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP -BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV -5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY -1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4 -NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG -Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91 -8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe -pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl -MrY= ------END CERTIFICATE----- - -# Issuer: CN=DigiCert Global Root G3 O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Global Root G3 O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Global Root G3" -# Serial: 7089244469030293291760083333884364146 -# MD5 Fingerprint: f5:5d:a4:50:a5:fb:28:7e:1e:0f:0d:cc:96:57:56:ca -# SHA1 Fingerprint: 7e:04:de:89:6a:3e:66:6d:00:e6:87:d3:3f:fa:d9:3b:e8:3d:34:9e -# SHA256 Fingerprint: 31:ad:66:48:f8:10:41:38:c7:38:f3:9e:a4:32:01:33:39:3e:3a:18:cc:02:29:6e:f9:7c:2a:c9:ef:67:31:d0 ------BEGIN CERTIFICATE----- -MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw -CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu -ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe -Fw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw -EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x -IDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF -K4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG -fp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO -Z9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd -BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx -AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/ -oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8 -sycX ------END CERTIFICATE----- - -# Issuer: CN=DigiCert Trusted Root G4 O=DigiCert Inc OU=www.digicert.com -# Subject: CN=DigiCert Trusted Root G4 O=DigiCert Inc OU=www.digicert.com -# Label: "DigiCert Trusted Root G4" -# Serial: 7451500558977370777930084869016614236 -# MD5 Fingerprint: 78:f2:fc:aa:60:1f:2f:b4:eb:c9:37:ba:53:2e:75:49 -# SHA1 Fingerprint: dd:fb:16:cd:49:31:c9:73:a2:03:7d:3f:c8:3a:4d:7d:77:5d:05:e4 -# SHA256 Fingerprint: 55:2f:7b:dc:f1:a7:af:9e:6c:e6:72:01:7f:4f:12:ab:f7:72:40:c7:8e:76:1a:c2:03:d1:d9:d2:0a:c8:99:88 ------BEGIN CERTIFICATE----- -MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi -MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 -d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg -RzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJV -UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu -Y29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3y -ithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1If -xp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDV -ySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiO -DCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQ -jdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/ -CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCi -EhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADM -fRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QY -uKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXK -chYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t -9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB -hjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD -ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2 -SV1EY+CtnJYYZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd -+SeuMIW59mdNOj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWc -fFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqa -sjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9N -cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N -0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie -4u1Ki7wb/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mI -r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1 -/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm -gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ ------END CERTIFICATE----- - -# Issuer: CN=COMODO RSA Certification Authority O=COMODO CA Limited -# Subject: CN=COMODO RSA Certification Authority O=COMODO CA Limited -# Label: "COMODO RSA Certification Authority" -# Serial: 101909084537582093308941363524873193117 -# MD5 Fingerprint: 1b:31:b0:71:40:36:cc:14:36:91:ad:c4:3e:fd:ec:18 -# SHA1 Fingerprint: af:e5:d2:44:a8:d1:19:42:30:ff:47:9f:e2:f8:97:bb:cd:7a:8c:b4 -# SHA256 Fingerprint: 52:f0:e1:c4:e5:8e:c6:29:29:1b:60:31:7f:07:46:71:b8:5d:7e:a8:0d:5b:07:27:34:63:53:4b:32:b4:02:34 ------BEGIN CERTIFICATE----- -MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB -hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G -A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV -BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5 -MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT -EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR -Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh -dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR -6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X -pz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC -9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV -/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf -Zd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z -+pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w -qP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah -SL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC -u9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf -Fobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq -crxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E -FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB -/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl -wFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM -4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV -2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna -FxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ -CuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK -boHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke -jkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL -S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb -QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl -0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB -NVOFBkpdn627G190 ------END CERTIFICATE----- - -# Issuer: CN=USERTrust RSA Certification Authority O=The USERTRUST Network -# Subject: CN=USERTrust RSA Certification Authority O=The USERTRUST Network -# Label: "USERTrust RSA Certification Authority" -# Serial: 2645093764781058787591871645665788717 -# MD5 Fingerprint: 1b:fe:69:d1:91:b7:19:33:a3:72:a8:0f:e1:55:e5:b5 -# SHA1 Fingerprint: 2b:8f:1b:57:33:0d:bb:a2:d0:7a:6c:51:f7:0e:e9:0d:da:b9:ad:8e -# SHA256 Fingerprint: e7:93:c9:b0:2f:d8:aa:13:e2:1c:31:22:8a:cc:b0:81:19:64:3b:74:9c:89:89:64:b1:74:6d:46:c3:d4:cb:d2 ------BEGIN CERTIFICATE----- -MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB -iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl -cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV -BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw -MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV -BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU -aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy -dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK -AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B -3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY -tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/ -Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2 -VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT -79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6 -c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT -Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l -c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee -UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE -Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd -BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G -A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF -Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO -VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3 -ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs -8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR -iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze -Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ -XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/ -qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB -VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB -L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG -jjxDah2nGN59PRbxYvnKkKj9 ------END CERTIFICATE----- - -# Issuer: CN=USERTrust ECC Certification Authority O=The USERTRUST Network -# Subject: CN=USERTrust ECC Certification Authority O=The USERTRUST Network -# Label: "USERTrust ECC Certification Authority" -# Serial: 123013823720199481456569720443997572134 -# MD5 Fingerprint: fa:68:bc:d9:b5:7f:ad:fd:c9:1d:06:83:28:cc:24:c1 -# SHA1 Fingerprint: d1:cb:ca:5d:b2:d5:2a:7f:69:3b:67:4d:e5:f0:5a:1d:0c:95:7d:f0 -# SHA256 Fingerprint: 4f:f4:60:d5:4b:9c:86:da:bf:bc:fc:57:12:e0:40:0d:2b:ed:3f:bc:4d:4f:bd:aa:86:e0:6a:dc:d2:a9:ad:7a ------BEGIN CERTIFICATE----- -MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDEL -MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl -eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT -JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMjAx -MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT -Ck5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUg -VVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlm -aWNhdGlvbiBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqflo -I+d61SRvU8Za2EurxtW20eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinng -o4N+LZfQYcTxmdwlkWOrfzCjtHDix6EznPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0G -A1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNVHQ8BAf8EBAMCAQYwDwYD -VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBBHU6+4WMB -zzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbW -RNZu9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg= ------END CERTIFICATE----- - -# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R4 -# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R4 -# Label: "GlobalSign ECC Root CA - R4" -# Serial: 14367148294922964480859022125800977897474 -# MD5 Fingerprint: 20:f0:27:68:d1:7e:a0:9d:0e:e6:2a:ca:df:5c:89:8e -# SHA1 Fingerprint: 69:69:56:2e:40:80:f4:24:a1:e7:19:9f:14:ba:f3:ee:58:ab:6a:bb -# SHA256 Fingerprint: be:c9:49:11:c2:95:56:76:db:6c:0a:55:09:86:d7:6e:3b:a0:05:66:7c:44:2c:97:62:b4:fb:b7:73:de:22:8c ------BEGIN CERTIFICATE----- -MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEk -MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpH -bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX -DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD -QSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu -MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprlOQcJ -FspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAw -DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61F -uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX -kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs -ewv4n4Q= ------END CERTIFICATE----- - -# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R5 -# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R5 -# Label: "GlobalSign ECC Root CA - R5" -# Serial: 32785792099990507226680698011560947931244 -# MD5 Fingerprint: 9f:ad:3b:1c:02:1e:8a:ba:17:74:38:81:0c:a2:bc:08 -# SHA1 Fingerprint: 1f:24:c6:30:cd:a4:18:ef:20:69:ff:ad:4f:dd:5f:46:3a:1b:69:aa -# SHA256 Fingerprint: 17:9f:bc:14:8a:3d:d0:0f:d2:4e:a1:34:58:cc:43:bf:a7:f5:9c:81:82:d7:83:a5:13:f6:eb:ec:10:0c:89:24 ------BEGIN CERTIFICATE----- -MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk -MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpH -bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX -DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD -QSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu -MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6SFkc -8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8ke -hOvRnkmSh5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD -VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYI -KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg -515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7yFz9SO8NdCKoCOJuxUnO -xwy8p2Fp8fc74SrL+SvzZpA3 ------END CERTIFICATE----- - -# Issuer: CN=Staat der Nederlanden EV Root CA O=Staat der Nederlanden -# Subject: CN=Staat der Nederlanden EV Root CA O=Staat der Nederlanden -# Label: "Staat der Nederlanden EV Root CA" -# Serial: 10000013 -# MD5 Fingerprint: fc:06:af:7b:e8:1a:f1:9a:b4:e8:d2:70:1f:c0:f5:ba -# SHA1 Fingerprint: 76:e2:7e:c1:4f:db:82:c1:c0:a6:75:b5:05:be:3d:29:b4:ed:db:bb -# SHA256 Fingerprint: 4d:24:91:41:4c:fe:95:67:46:ec:4c:ef:a6:cf:6f:72:e2:8a:13:29:43:2f:9d:8a:90:7a:c4:cb:5d:ad:c1:5a ------BEGIN CERTIFICATE----- -MIIFcDCCA1igAwIBAgIEAJiWjTANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJO -TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSkwJwYDVQQDDCBTdGFh -dCBkZXIgTmVkZXJsYW5kZW4gRVYgUm9vdCBDQTAeFw0xMDEyMDgxMTE5MjlaFw0y -MjEyMDgxMTEwMjhaMFgxCzAJBgNVBAYTAk5MMR4wHAYDVQQKDBVTdGFhdCBkZXIg -TmVkZXJsYW5kZW4xKTAnBgNVBAMMIFN0YWF0IGRlciBOZWRlcmxhbmRlbiBFViBS -b290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA48d+ifkkSzrS -M4M1LGns3Amk41GoJSt5uAg94JG6hIXGhaTK5skuU6TJJB79VWZxXSzFYGgEt9nC -UiY4iKTWO0Cmws0/zZiTs1QUWJZV1VD+hq2kY39ch/aO5ieSZxeSAgMs3NZmdO3d -Z//BYY1jTw+bbRcwJu+r0h8QoPnFfxZpgQNH7R5ojXKhTbImxrpsX23Wr9GxE46p -rfNeaXUmGD5BKyF/7otdBwadQ8QpCiv8Kj6GyzyDOvnJDdrFmeK8eEEzduG/L13l -pJhQDBXd4Pqcfzho0LKmeqfRMb1+ilgnQ7O6M5HTp5gVXJrm0w912fxBmJc+qiXb -j5IusHsMX/FjqTf5m3VpTCgmJdrV8hJwRVXj33NeN/UhbJCONVrJ0yPr08C+eKxC -KFhmpUZtcALXEPlLVPxdhkqHz3/KRawRWrUgUY0viEeXOcDPusBCAUCZSCELa6fS -/ZbV0b5GnUngC6agIk440ME8MLxwjyx1zNDFjFE7PZQIZCZhfbnDZY8UnCHQqv0X -cgOPvZuM5l5Tnrmd74K74bzickFbIZTTRTeU0d8JOV3nI6qaHcptqAqGhYqCvkIH -1vI4gnPah1vlPNOePqc7nvQDs/nxfRN0Av+7oeX6AHkcpmZBiFxgV6YuCcS6/ZrP -px9Aw7vMWgpVSzs4dlG4Y4uElBbmVvMCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB -/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFP6rAJCYniT8qcwaivsnuL8wbqg7 -MA0GCSqGSIb3DQEBCwUAA4ICAQDPdyxuVr5Os7aEAJSrR8kN0nbHhp8dB9O2tLsI -eK9p0gtJ3jPFrK3CiAJ9Brc1AsFgyb/E6JTe1NOpEyVa/m6irn0F3H3zbPB+po3u -2dfOWBfoqSmuc0iH55vKbimhZF8ZE/euBhD/UcabTVUlT5OZEAFTdfETzsemQUHS -v4ilf0X8rLiltTMMgsT7B/Zq5SWEXwbKwYY5EdtYzXc7LMJMD16a4/CrPmEbUCTC -wPTxGfARKbalGAKb12NMcIxHowNDXLldRqANb/9Zjr7dn3LDWyvfjFvO5QxGbJKy -CqNMVEIYFRIYvdr8unRu/8G2oGTYqV9Vrp9canaW2HNnh/tNf1zuacpzEPuKqf2e -vTY4SUmH9A4U8OmHuD+nT3pajnnUk+S7aFKErGzp85hwVXIy+TSrK0m1zSBi5Dp6 -Z2Orltxtrpfs/J92VoguZs9btsmksNcFuuEnL5O7Jiqik7Ab846+HUCjuTaPPoIa -Gl6I6lD4WeKDRikL40Rc4ZW2aZCaFG+XroHPaO+Zmr615+F/+PoTRxZMzG0IQOeL -eG9QgkRQP2YGiqtDhFZKDyAthg710tvSeopLzaXoTvFeJiUBWSOgftL2fiFX1ye8 -FVdMpEbB4IMeDExNH08GGeL5qPQ6gqGyeUN51q1veieQA6TqJIc/2b3Z6fJfUEkc -7uzXLg== ------END CERTIFICATE----- - -# Issuer: CN=IdenTrust Commercial Root CA 1 O=IdenTrust -# Subject: CN=IdenTrust Commercial Root CA 1 O=IdenTrust -# Label: "IdenTrust Commercial Root CA 1" -# Serial: 13298821034946342390520003877796839426 -# MD5 Fingerprint: b3:3e:77:73:75:ee:a0:d3:e3:7e:49:63:49:59:bb:c7 -# SHA1 Fingerprint: df:71:7e:aa:4a:d9:4e:c9:55:84:99:60:2d:48:de:5f:bc:f0:3a:25 -# SHA256 Fingerprint: 5d:56:49:9b:e4:d2:e0:8b:cf:ca:d0:8a:3e:38:72:3d:50:50:3b:de:70:69:48:e4:2f:55:60:30:19:e5:28:ae ------BEGIN CERTIFICATE----- -MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBK -MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVu -VHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQw -MTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScw -JQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwggIiMA0GCSqG -SIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ldhNlT -3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU -+ehcCuz/mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gp -S0l4PJNgiCL8mdo2yMKi1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1 -bVoE/c40yiTcdCMbXTMTEl3EASX2MN0CXZ/g1Ue9tOsbobtJSdifWwLziuQkkORi -T0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl3ZBWzvurpWCdxJ35UrCL -vYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzyNeVJSQjK -Vsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZK -dHzVWYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHT -c+XvvqDtMwt0viAgxGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hv -l7yTmvmcEpB4eoCHFddydJxVdHixuuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5N -iGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB -/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZIhvcNAQELBQAD -ggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH -6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwt -LRvM7Kqas6pgghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93 -nAbowacYXVKV7cndJZ5t+qntozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3 -+wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmVYjzlVYA211QC//G5Xc7UI2/YRYRK -W2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUXfeu+h1sXIFRRk0pT -AwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/rokTLq -l1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG -4iZZRHUe2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZ -mUlO+KWA2yUPHGNiiskzZ2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A -7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7RcGzM7vRX+Bi6hG6H ------END CERTIFICATE----- - -# Issuer: CN=IdenTrust Public Sector Root CA 1 O=IdenTrust -# Subject: CN=IdenTrust Public Sector Root CA 1 O=IdenTrust -# Label: "IdenTrust Public Sector Root CA 1" -# Serial: 13298821034946342390521976156843933698 -# MD5 Fingerprint: 37:06:a5:b0:fc:89:9d:ba:f4:6b:8c:1a:64:cd:d5:ba -# SHA1 Fingerprint: ba:29:41:60:77:98:3f:f4:f3:ef:f2:31:05:3b:2e:ea:6d:4d:45:fd -# SHA256 Fingerprint: 30:d0:89:5a:9a:44:8a:26:20:91:63:55:22:d1:f5:20:10:b5:86:7a:ca:e1:2c:78:ef:95:8f:d4:f4:38:9f:2f ------BEGIN CERTIFICATE----- -MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBN -MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVu -VHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcN -MzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0 -MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwggIi -MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTyP4o7 -ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGy -RBb06tD6Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlS -bdsHyo+1W/CD80/HLaXIrcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF -/YTLNiCBWS2ab21ISGHKTN9T0a9SvESfqy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R -3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoSmJxZZoY+rfGwyj4GD3vw -EUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFnol57plzy -9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9V -GxyhLrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ -2fjXctscvG29ZV/viDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsV -WaFHVCkugyhfHMKiq3IXAAaOReyL4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gD -W/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/ -BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMwDQYJKoZIhvcN -AQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj -t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHV -DRDtfULAj+7AmgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9 -TaDKQGXSc3z1i9kKlT/YPyNtGtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8G -lwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFtm6/n6J91eEyrRjuazr8FGF1NFTwW -mhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMxNRF4eKLg6TCMf4Df -WN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4Mhn5 -+bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJ -tshquDDIajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhA -GaQdp/lLQzfcaFpPz+vCZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv -8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ3Wl9af0AVqW3rLatt8o+Ae+c ------END CERTIFICATE----- - -# Issuer: CN=Entrust Root Certification Authority - G2 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2009 Entrust, Inc. - for authorized use only -# Subject: CN=Entrust Root Certification Authority - G2 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2009 Entrust, Inc. - for authorized use only -# Label: "Entrust Root Certification Authority - G2" -# Serial: 1246989352 -# MD5 Fingerprint: 4b:e2:c9:91:96:65:0c:f4:0e:5a:93:92:a0:0a:fe:b2 -# SHA1 Fingerprint: 8c:f4:27:fd:79:0c:3a:d1:66:06:8d:e8:1e:57:ef:bb:93:22:72:d4 -# SHA256 Fingerprint: 43:df:57:74:b0:3e:7f:ef:5f:e4:0d:93:1a:7b:ed:f1:bb:2e:6b:42:73:8c:4e:6d:38:41:10:3d:3a:a7:f3:39 ------BEGIN CERTIFICATE----- -MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC -VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50 -cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs -IEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz -dCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMDkwNzA3MTcy -NTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu -dHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt -dGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0 -aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmlj -YXRpb24gQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK -AoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP/vaCeb9zYQYKpSfYs1/T -RU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXzHHfV1IWN -cCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hW -wcKUs/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1 -U1+cPvQXLOZprE4yTGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0 -jaWvYkxN4FisZDQSA/i2jZRjJKRxAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP -BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ60B7vfec7aVHUbI2fkBJmqzAN -BgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5ZiXMRrEPR9RP/ -jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ -Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v -1fN2D807iDginWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4R -nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH -VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g== ------END CERTIFICATE----- - -# Issuer: CN=Entrust Root Certification Authority - EC1 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2012 Entrust, Inc. - for authorized use only -# Subject: CN=Entrust Root Certification Authority - EC1 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2012 Entrust, Inc. - for authorized use only -# Label: "Entrust Root Certification Authority - EC1" -# Serial: 51543124481930649114116133369 -# MD5 Fingerprint: b6:7e:1d:f0:58:c5:49:6c:24:3b:3d:ed:98:18:ed:bc -# SHA1 Fingerprint: 20:d8:06:40:df:9b:25:f5:12:25:3a:11:ea:f7:59:8a:eb:14:b5:47 -# SHA256 Fingerprint: 02:ed:0e:b2:8c:14:da:45:16:5c:56:67:91:70:0d:64:51:d7:fb:56:f0:b2:ab:1d:3b:8e:b0:70:e5:6e:df:f5 ------BEGIN CERTIFICATE----- -MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkG -A1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3 -d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVu -dHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEzMDEGA1UEAxMq -RW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRUMxMB4XDTEy -MTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYwFAYD -VQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0 -L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0g -Zm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBD -ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEVDMTB2MBAGByqGSM49AgEGBSuBBAAi -A2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHyAsWfoPZb1YsGGYZPUxBt -ByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef9eNi1KlH -Bz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O -BBYEFLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVC -R98crlOZF7ZvHH3hvxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nX -hTcGtXsI/esni0qU+eH6p44mCOh8kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G ------END CERTIFICATE----- - -# Issuer: CN=CFCA EV ROOT O=China Financial Certification Authority -# Subject: CN=CFCA EV ROOT O=China Financial Certification Authority -# Label: "CFCA EV ROOT" -# Serial: 407555286 -# MD5 Fingerprint: 74:e1:b6:ed:26:7a:7a:44:30:33:94:ab:7b:27:81:30 -# SHA1 Fingerprint: e2:b8:29:4b:55:84:ab:6b:58:c2:90:46:6c:ac:3f:b8:39:8f:84:83 -# SHA256 Fingerprint: 5c:c3:d7:8e:4e:1d:5e:45:54:7a:04:e6:87:3e:64:f9:0c:f9:53:6d:1c:cc:2e:f8:00:f3:55:c4:c5:fd:70:fd ------BEGIN CERTIFICATE----- -MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJD -TjEwMC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9y -aXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkx -MjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEwMC4GA1UECgwnQ2hpbmEgRmluYW5j -aWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJP -T1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnVBU03 -sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpL -TIpTUnrD7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5 -/ZOkVIBMUtRSqy5J35DNuF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp -7hZZLDRJGqgG16iI0gNyejLi6mhNbiyWZXvKWfry4t3uMCz7zEasxGPrb382KzRz -EpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7xzbh72fROdOXW3NiGUgt -hxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9fpy25IGvP -a931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqot -aK8KgWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNg -TnYGmE69g60dWIolhdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfV -PKPtl8MeNPo4+QgO48BdK4PRVmrJtqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hv -cWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAfBgNVHSMEGDAWgBTj/i39KNAL -tbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAd -BgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB -ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObT -ej/tUxPQ4i9qecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdL -jOztUmCypAbqTuv0axn96/Ua4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBS -ESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sGE5uPhnEFtC+NiWYzKXZUmhH4J/qy -P5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfXBDrDMlI1Dlb4pd19 -xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjnaH9d -Ci77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN -5mydLIhyPDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe -/v5WOaHIz16eGWRGENoXkbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+Z -AAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3CekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ -5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su ------END CERTIFICATE----- - -# Issuer: CN=OISTE WISeKey Global Root GB CA O=WISeKey OU=OISTE Foundation Endorsed -# Subject: CN=OISTE WISeKey Global Root GB CA O=WISeKey OU=OISTE Foundation Endorsed -# Label: "OISTE WISeKey Global Root GB CA" -# Serial: 157768595616588414422159278966750757568 -# MD5 Fingerprint: a4:eb:b9:61:28:2e:b7:2f:98:b0:35:26:90:99:51:1d -# SHA1 Fingerprint: 0f:f9:40:76:18:d3:d7:6a:4b:98:f0:a8:35:9e:0c:fd:27:ac:cc:ed -# SHA256 Fingerprint: 6b:9c:08:e8:6e:b0:f7:67:cf:ad:65:cd:98:b6:21:49:e5:49:4a:67:f5:84:5e:7b:d1:ed:01:9f:27:b8:6b:d6 ------BEGIN CERTIFICATE----- -MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBt -MQswCQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUg -Rm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9i -YWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAwMzJaFw0zOTEyMDExNTEwMzFaMG0x -CzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBG -b3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2Jh -bCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3 -HEokKtaXscriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGx -WuR51jIjK+FTzJlFXHtPrby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX -1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNk -u7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4oQnc/nSMbsrY9gBQHTC5P -99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvgGUpuuy9r -M2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw -AwEB/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUB -BAMCAQAwDQYJKoZIhvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrgh -cViXfa43FK8+5/ea4n32cZiZBKpDdHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5 -gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0VQreUGdNZtGn//3ZwLWoo4rO -ZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEuiHZeeevJuQHHf -aPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic -Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM= ------END CERTIFICATE----- - -# Issuer: CN=SZAFIR ROOT CA2 O=Krajowa Izba Rozliczeniowa S.A. -# Subject: CN=SZAFIR ROOT CA2 O=Krajowa Izba Rozliczeniowa S.A. -# Label: "SZAFIR ROOT CA2" -# Serial: 357043034767186914217277344587386743377558296292 -# MD5 Fingerprint: 11:64:c1:89:b0:24:b1:8c:b1:07:7e:89:9e:51:9e:99 -# SHA1 Fingerprint: e2:52:fa:95:3f:ed:db:24:60:bd:6e:28:f3:9c:cc:cf:5e:b3:3f:de -# SHA256 Fingerprint: a1:33:9d:33:28:1a:0b:56:e5:57:d3:d3:2b:1c:e7:f9:36:7e:b0:94:bd:5f:a7:2a:7e:50:04:c8:de:d7:ca:fe ------BEGIN CERTIFICATE----- -MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQEL -BQAwUTELMAkGA1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6 -ZW5pb3dhIFMuQS4xGDAWBgNVBAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkw -NzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9L -cmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYDVQQDDA9TWkFGSVIg -Uk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5QqEvN -QLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT -3PSQ1hNKDJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw -3gAeqDRHu5rr/gsUvTaE2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr6 -3fE9biCloBK0TXC5ztdyO4mTp4CEHCdJckm1/zuVnsHMyAHs6A6KCpbns6aH5db5 -BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwiieDhZNRnvDF5YTy7ykHN -XGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD -AgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsF -AAOCAQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw -8PRBEew/R40/cof5O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOG -nXkZ7/e7DDWQw4rtTw/1zBLZpD67oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCP -oky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul4+vJhaAlIDf7js4MNIThPIGy -d05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6+/NNIxuZMzSg -LvWpCz/UXeHPhJ/iGcJfitYgHuNztw== ------END CERTIFICATE----- - -# Issuer: CN=Certum Trusted Network CA 2 O=Unizeto Technologies S.A. OU=Certum Certification Authority -# Subject: CN=Certum Trusted Network CA 2 O=Unizeto Technologies S.A. OU=Certum Certification Authority -# Label: "Certum Trusted Network CA 2" -# Serial: 44979900017204383099463764357512596969 -# MD5 Fingerprint: 6d:46:9e:d9:25:6d:08:23:5b:5e:74:7d:1e:27:db:f2 -# SHA1 Fingerprint: d3:dd:48:3e:2b:bf:4c:05:e8:af:10:f5:fa:76:26:cf:d3:dc:30:92 -# SHA256 Fingerprint: b6:76:f2:ed:da:e8:77:5c:d3:6c:b0:f6:3c:d1:d4:60:39:61:f4:9e:62:65:ba:01:3a:2f:03:07:b6:d0:b8:04 ------BEGIN CERTIFICATE----- -MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCB -gDELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu -QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIG -A1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQSAyMCIYDzIwMTExMDA2MDgz -OTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQTDEiMCAGA1UEChMZ -VW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRp -ZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3 -b3JrIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWA -DGSdhhuWZGc/IjoedQF97/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn -0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+oCgCXhVqqndwpyeI1B+twTUrWwbNWuKFB -OJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40bRr5HMNUuctHFY9rnY3lE -fktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2puTRZCr+E -Sv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1m -o130GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02i -sx7QBlrd9pPPV3WZ9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOW -OZV7bIBaTxNyxtd9KXpEulKkKtVBRgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgez -Tv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pyehizKV/Ma5ciSixqClnrDvFAS -adgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vMBhBgu4M1t15n -3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD -AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMC -AQYwDQYJKoZIhvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQ -F/xlhMcQSZDe28cmk4gmb3DWAl45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTf -CVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuAL55MYIR4PSFk1vtBHxgP58l1cb29 -XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMoclm2q8KMZiYcdywm -djWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tMpkT/ -WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jb -AoJnwTnbw3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksq -P/ujmv5zMnHCnsZy4YpoJ/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Ko -b7a6bINDd82Kkhehnlt4Fj1F4jNy3eFmypnTycUm/Q1oBEauttmbjL4ZvrHG8hnj -XALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLXis7VmFxWlgPF7ncGNf/P -5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7zAYspsbi -DrW5viSP ------END CERTIFICATE----- - -# Issuer: CN=Hellenic Academic and Research Institutions RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority -# Subject: CN=Hellenic Academic and Research Institutions RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority -# Label: "Hellenic Academic and Research Institutions RootCA 2015" -# Serial: 0 -# MD5 Fingerprint: ca:ff:e2:db:03:d9:cb:4b:e9:0f:ad:84:fd:7b:18:ce -# SHA1 Fingerprint: 01:0c:06:95:a6:98:19:14:ff:bf:5f:c6:b0:b6:95:ea:29:e9:12:a6 -# SHA256 Fingerprint: a0:40:92:9a:02:ce:53:b4:ac:f4:f2:ff:c6:98:1c:e4:49:6f:75:5e:6d:45:fe:0b:2a:69:2b:cd:52:52:3f:36 ------BEGIN CERTIFICATE----- -MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1Ix -DzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5k -IFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMT -N0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9v -dENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAxMTIxWjCBpjELMAkG -A1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNh -ZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkx -QDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1 -dGlvbnMgUm9vdENBIDIwMTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC -AQDC+Kk/G4n8PDwEXT2QNrCROnk8ZlrvbTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA -4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+ehiGsxr/CL0BgzuNtFajT0 -AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+6PAQZe10 -4S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06C -ojXdFPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV -9Cz82XBST3i4vTwri5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrD -gfgXy5I2XdGj2HUb4Ysn6npIQf1FGQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6 -Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2fu/Z8VFRfS0myGlZYeCsargq -NhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9muiNX6hME6wGko -LfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc -Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNV -HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVd -ctA4GGqd83EkVAswDQYJKoZIhvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0I -XtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+D1hYc2Ryx+hFjtyp8iY/xnmMsVMI -M4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrMd/K4kPFox/la/vot -9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+yd+2V -Z5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/ea -j8GsGsVn82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnh -X9izjFk0WaSrT2y7HxjbdavYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQ -l033DlZdwJVqwjbDG2jJ9SrcR5q+ss7FJej6A7na+RZukYT1HCjI/CbM1xyQVqdf -bzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVtJ94Cj8rDtSvK6evIIVM4 -pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGaJI7ZjnHK -e7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0 -vm9qp/UsQu0yrbYhnr68 ------END CERTIFICATE----- - -# Issuer: CN=Hellenic Academic and Research Institutions ECC RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority -# Subject: CN=Hellenic Academic and Research Institutions ECC RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority -# Label: "Hellenic Academic and Research Institutions ECC RootCA 2015" -# Serial: 0 -# MD5 Fingerprint: 81:e5:b4:17:eb:c2:f5:e1:4b:0d:41:7b:49:92:fe:ef -# SHA1 Fingerprint: 9f:f1:71:8d:92:d5:9a:f3:7d:74:97:b4:bc:6f:84:68:0b:ba:b6:66 -# SHA256 Fingerprint: 44:b5:45:aa:8a:25:e6:5a:73:ca:15:dc:27:fc:36:d2:4c:1c:b9:95:3a:06:65:39:b1:15:82:dc:48:7b:48:33 ------BEGIN CERTIFICATE----- -MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzAN -BgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl -c2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hl -bGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgRUNDIFJv -b3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEwMzcxMlowgaoxCzAJ -BgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmljIEFj -YWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5 -MUQwQgYDVQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0 -dXRpb25zIEVDQyBSb290Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKg -QehLgoRc4vgxEZmGZE4JJS+dQS8KrjVPdJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJa -jq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoKVlp8aQuqgAkkbH7BRqNC -MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFLQi -C4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaep -lSTAGiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7Sof -TUwJCA3sS61kFyjndc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR ------END CERTIFICATE----- - -# Issuer: CN=ISRG Root X1 O=Internet Security Research Group -# Subject: CN=ISRG Root X1 O=Internet Security Research Group -# Label: "ISRG Root X1" -# Serial: 172886928669790476064670243504169061120 -# MD5 Fingerprint: 0c:d2:f9:e0:da:17:73:e9:ed:86:4d:a5:e3:70:e7:4e -# SHA1 Fingerprint: ca:bd:2a:79:a1:07:6a:31:f2:1d:25:36:35:cb:03:9d:43:29:a5:e8 -# SHA256 Fingerprint: 96:bc:ec:06:26:49:76:f3:74:60:77:9a:cf:28:c5:a7:cf:e8:a3:c0:aa:e1:1a:8f:fc:ee:05:c0:bd:df:08:c6 ------BEGIN CERTIFICATE----- -MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw -TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh -cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 -WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu -ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY -MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc -h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ -0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U -A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW -T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH -B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC -B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv -KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn -OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn -jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw -qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI -rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV -HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq -hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL -ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ -3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK -NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 -ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur -TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC -jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc -oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq -4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA -mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d -emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= ------END CERTIFICATE----- - -# Issuer: O=FNMT-RCM OU=AC RAIZ FNMT-RCM -# Subject: O=FNMT-RCM OU=AC RAIZ FNMT-RCM -# Label: "AC RAIZ FNMT-RCM" -# Serial: 485876308206448804701554682760554759 -# MD5 Fingerprint: e2:09:04:b4:d3:bd:d1:a0:14:fd:1a:d2:47:c4:57:1d -# SHA1 Fingerprint: ec:50:35:07:b2:15:c4:95:62:19:e2:a8:9a:5b:42:99:2c:4c:2c:20 -# SHA256 Fingerprint: eb:c5:57:0c:29:01:8c:4d:67:b1:aa:12:7b:af:12:f7:03:b4:61:1e:bc:17:b7:da:b5:57:38:94:17:9b:93:fa ------BEGIN CERTIFICATE----- -MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsx -CzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJ -WiBGTk1ULVJDTTAeFw0wODEwMjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJ -BgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBG -Tk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALpxgHpMhm5/ -yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcfqQgf -BBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAz -WHFctPVrbtQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxF -tBDXaEAUwED653cXeuYLj2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z -374jNUUeAlz+taibmSXaXvMiwzn15Cou08YfxGyqxRxqAQVKL9LFwag0Jl1mpdIC -IfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mwWsXmo8RZZUc1g16p6DUL -mbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnTtOmlcYF7 -wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peS -MKGJ47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2 -ZSysV4999AeU14ECll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMet -UqIJ5G+GR4of6ygnXYMgrwTJbFaai0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUw -AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFPd9xf3E6Jobd2Sn9R2gzL+H -YJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwOi8vd3d3 -LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD -nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1 -RXxlDPiyN8+sD8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYM -LVN0V2Ue1bLdI4E7pWYjJ2cJj+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf -77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrTQfv6MooqtyuGC2mDOL7Nii4LcK2N -JpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW+YJF1DngoABd15jm -fZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7Ixjp -6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp -1txyM/1d8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B -9kiABdcPUXmsEKvU7ANm5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wok -RqEIr9baRRmW1FMdW4R58MD3R++Lj8UGrp1MYp3/RgT408m2ECVAdf4WqslKYIYv -uu8wd+RU4riEmViAqhOLUTpPSPaLtrM= ------END CERTIFICATE----- - -# Issuer: CN=Amazon Root CA 1 O=Amazon -# Subject: CN=Amazon Root CA 1 O=Amazon -# Label: "Amazon Root CA 1" -# Serial: 143266978916655856878034712317230054538369994 -# MD5 Fingerprint: 43:c6:bf:ae:ec:fe:ad:2f:18:c6:88:68:30:fc:c8:e6 -# SHA1 Fingerprint: 8d:a7:f9:65:ec:5e:fc:37:91:0f:1c:6e:59:fd:c1:cc:6a:6e:de:16 -# SHA256 Fingerprint: 8e:cd:e6:88:4f:3d:87:b1:12:5b:a3:1a:c3:fc:b1:3d:70:16:de:7f:57:cc:90:4f:e1:cb:97:c6:ae:98:19:6e ------BEGIN CERTIFICATE----- -MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF -ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 -b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL -MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv -b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj -ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM -9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw -IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6 -VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L -93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm -jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC -AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA -A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI -U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs -N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv -o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU -5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy -rqXRfboQnoZsG4q5WTP468SQvvG5 ------END CERTIFICATE----- - -# Issuer: CN=Amazon Root CA 2 O=Amazon -# Subject: CN=Amazon Root CA 2 O=Amazon -# Label: "Amazon Root CA 2" -# Serial: 143266982885963551818349160658925006970653239 -# MD5 Fingerprint: c8:e5:8d:ce:a8:42:e2:7a:c0:2a:5c:7c:9e:26:bf:66 -# SHA1 Fingerprint: 5a:8c:ef:45:d7:a6:98:59:76:7a:8c:8b:44:96:b5:78:cf:47:4b:1a -# SHA256 Fingerprint: 1b:a5:b2:aa:8c:65:40:1a:82:96:01:18:f8:0b:ec:4f:62:30:4d:83:ce:c4:71:3a:19:c3:9c:01:1e:a4:6d:b4 ------BEGIN CERTIFICATE----- -MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwF -ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6 -b24gUm9vdCBDQSAyMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTEL -MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv -b3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2Wny2cSkxK -gXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4kHbZ -W0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg -1dKmSYXpN+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K -8nu+NQWpEjTj82R0Yiw9AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r -2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvdfLC6HM783k81ds8P+HgfajZRRidhW+me -z/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAExkv8LV/SasrlX6avvDXbR -8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSSbtqDT6Zj -mUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz -7Mt0Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6 -+XUyo05f7O0oYtlNc/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI -0u1ufm8/0i2BWSlmy5A5lREedCf+3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMB -Af8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSwDPBMMPQFWAJI/TPlUq9LhONm -UjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oAA7CXDpO8Wqj2 -LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY -+gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kS -k5Nrp+gvU5LEYFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl -7uxMMne0nxrpS10gxdr9HIcWxkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygm -btmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQgj9sAq+uEjonljYE1x2igGOpm/Hl -urR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbWaQbLU8uz/mtBzUF+ -fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoVYh63 -n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE -76KlXIx3KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H -9jVlpNMKVv/1F2Rs76giJUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT -4PsJYGw= ------END CERTIFICATE----- - -# Issuer: CN=Amazon Root CA 3 O=Amazon -# Subject: CN=Amazon Root CA 3 O=Amazon -# Label: "Amazon Root CA 3" -# Serial: 143266986699090766294700635381230934788665930 -# MD5 Fingerprint: a0:d4:ef:0b:f7:b5:d8:49:95:2a:ec:f5:c4:fc:81:87 -# SHA1 Fingerprint: 0d:44:dd:8c:3c:8c:1a:1a:58:75:64:81:e9:0f:2e:2a:ff:b3:d2:6e -# SHA256 Fingerprint: 18:ce:6c:fe:7b:f1:4e:60:b2:e3:47:b8:df:e8:68:cb:31:d0:2e:bb:3a:da:27:15:69:f5:03:43:b4:6d:b3:a4 ------BEGIN CERTIFICATE----- -MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5 -MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g -Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG -A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg -Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl -ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j -QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr -ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr -BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM -YyRIHN8wfdVoOw== ------END CERTIFICATE----- - -# Issuer: CN=Amazon Root CA 4 O=Amazon -# Subject: CN=Amazon Root CA 4 O=Amazon -# Label: "Amazon Root CA 4" -# Serial: 143266989758080763974105200630763877849284878 -# MD5 Fingerprint: 89:bc:27:d5:eb:17:8d:06:6a:69:d5:fd:89:47:b4:cd -# SHA1 Fingerprint: f6:10:84:07:d6:f8:bb:67:98:0c:c2:e2:44:c2:eb:ae:1c:ef:63:be -# SHA256 Fingerprint: e3:5d:28:41:9e:d0:20:25:cf:a6:90:38:cd:62:39:62:45:8d:a5:c6:95:fb:de:a3:c2:2b:0b:fb:25:89:70:92 ------BEGIN CERTIFICATE----- -MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5 -MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g -Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG -A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg -Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi -9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk -M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB -/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB -MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw -CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW -1KyLa2tJElMzrdfkviT8tQp21KW8EA== ------END CERTIFICATE----- - -# Issuer: CN=TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 O=Turkiye Bilimsel ve Teknolojik Arastirma Kurumu - TUBITAK OU=Kamu Sertifikasyon Merkezi - Kamu SM -# Subject: CN=TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 O=Turkiye Bilimsel ve Teknolojik Arastirma Kurumu - TUBITAK OU=Kamu Sertifikasyon Merkezi - Kamu SM -# Label: "TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1" -# Serial: 1 -# MD5 Fingerprint: dc:00:81:dc:69:2f:3e:2f:b0:3b:f6:3d:5a:91:8e:49 -# SHA1 Fingerprint: 31:43:64:9b:ec:ce:27:ec:ed:3a:3f:0b:8f:0d:e4:e8:91:dd:ee:ca -# SHA256 Fingerprint: 46:ed:c3:68:90:46:d5:3a:45:3f:b3:10:4a:b8:0d:ca:ec:65:8b:26:60:ea:16:29:dd:7e:86:79:90:64:87:16 ------BEGIN CERTIFICATE----- -MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIx -GDAWBgNVBAcTD0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxp -bXNlbCB2ZSBUZWtub2xvamlrIEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0w -KwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24gTWVya2V6aSAtIEthbXUgU00xNjA0 -BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRpZmlrYXNpIC0gU3Vy -dW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYDVQQG -EwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXll -IEJpbGltc2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklU -QUsxLTArBgNVBAsTJEthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBT -TTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11IFNNIFNTTCBLb2sgU2VydGlmaWthc2kg -LSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr3UwM6q7 -a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y86Ij5iySr -LqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INr -N3wcwv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2X -YacQuFWQfw4tJzh03+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/ -iSIzL+aFCr2lqBs23tPcLG07xxO9WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4f -AJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQUZT/HiobGPN08VFw1+DrtUgxH -V8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL -BQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh -AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPf -IPP54+M638yclNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4 -lzwDGrpDxpa5RXI4s6ehlj2Re37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c -8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0jq5Rm+K37DwhuJi1/FwcJsoz7UMCf -lo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM= ------END CERTIFICATE----- - -# Issuer: CN=GDCA TrustAUTH R5 ROOT O=GUANG DONG CERTIFICATE AUTHORITY CO.,LTD. -# Subject: CN=GDCA TrustAUTH R5 ROOT O=GUANG DONG CERTIFICATE AUTHORITY CO.,LTD. -# Label: "GDCA TrustAUTH R5 ROOT" -# Serial: 9009899650740120186 -# MD5 Fingerprint: 63:cc:d9:3d:34:35:5c:6f:53:a3:e2:08:70:48:1f:b4 -# SHA1 Fingerprint: 0f:36:38:5b:81:1a:25:c3:9b:31:4e:83:ca:e9:34:66:70:cc:74:b4 -# SHA256 Fingerprint: bf:ff:8f:d0:44:33:48:7d:6a:8a:a6:0c:1a:29:76:7a:9f:c2:bb:b0:5e:42:0f:71:3a:13:b9:92:89:1d:38:93 ------BEGIN CERTIFICATE----- -MIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE -BhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ -IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0 -MTEyNjA1MTMxNVoXDTQwMTIzMTE1NTk1OVowYjELMAkGA1UEBhMCQ04xMjAwBgNV -BAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMR8w -HQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMIICIjANBgkqhkiG9w0BAQEF -AAOCAg8AMIICCgKCAgEA2aMW8Mh0dHeb7zMNOwZ+Vfy1YI92hhJCfVZmPoiC7XJj -Dp6L3TQsAlFRwxn9WVSEyfFrs0yw6ehGXTjGoqcuEVe6ghWinI9tsJlKCvLriXBj -TnnEt1u9ol2x8kECK62pOqPseQrsXzrj/e+APK00mxqriCZ7VqKChh/rNYmDf1+u -KU49tm7srsHwJ5uu4/Ts765/94Y9cnrrpftZTqfrlYwiOXnhLQiPzLyRuEH3FMEj -qcOtmkVEs7LXLM3GKeJQEK5cy4KOFxg2fZfmiJqwTTQJ9Cy5WmYqsBebnh52nUpm -MUHfP/vFBu8btn4aRjb3ZGM74zkYI+dndRTVdVeSN72+ahsmUPI2JgaQxXABZG12 -ZuGR224HwGGALrIuL4xwp9E7PLOR5G62xDtw8mySlwnNR30YwPO7ng/Wi64HtloP -zgsMR6flPri9fcebNaBhlzpBdRfMK5Z3KpIhHtmVdiBnaM8Nvd/WHwlqmuLMc3Gk -L30SgLdTMEZeS1SZD2fJpcjyIMGC7J0R38IC+xo70e0gmu9lZJIQDSri3nDxGGeC -jGHeuLzRL5z7D9Ar7Rt2ueQ5Vfj4oR24qoAATILnsn8JuLwwoC8N9VKejveSswoA -HQBUlwbgsQfZxw9cZX08bVlX5O2ljelAU58VS6Bx9hoh49pwBiFYFIeFd3mqgnkC -AwEAAaNCMEAwHQYDVR0OBBYEFOLJQJ9NzuiaoXzPDj9lxSmIahlRMA8GA1UdEwEB -/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDRSVfg -p8xoWLoBDysZzY2wYUWsEe1jUGn4H3++Fo/9nesLqjJHdtJnJO29fDMylyrHBYZm -DRd9FBUb1Ov9H5r2XpdptxolpAqzkT9fNqyL7FeoPueBihhXOYV0GkLH6VsTX4/5 -COmSdI31R9KrO9b7eGZONn356ZLpBN79SWP8bfsUcZNnL0dKt7n/HipzcEYwv1ry -L3ml4Y0M2fmyYzeMN2WFcGpcWwlyua1jPLHd+PwyvzeG5LuOmCd+uh8W4XAR8gPf -JWIyJyYYMoSf/wA6E7qaTfRPuBRwIrHKK5DOKcFw9C+df/KQHtZa37dG/OaG+svg -IHZ6uqbL9XzeYqWxi+7egmaKTjowHz+Ay60nugxe19CxVsp3cbK1daFQqUBDF8Io -2c9Si1vIY9RCPqAzekYu9wogRlR+ak8x8YF+QnQ4ZXMn7sZ8uI7XpTrXmKGcjBBV -09tL7ECQ8s1uV9JiDnxXk7Gnbc2dg7sq5+W2O3FYrf3RRbxake5TFW/TRQl1brqQ -XR4EzzffHqhmsYzmIGrv/EhOdJhCrylvLmrH+33RZjEizIYAfmaDDEL0vTSSwxrq -T8p+ck0LcIymSLumoRT2+1hEmRSuqguTaaApJUqlyyvdimYHFngVV3Eb7PVHhPOe -MTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g== ------END CERTIFICATE----- - -# Issuer: CN=TrustCor RootCert CA-1 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority -# Subject: CN=TrustCor RootCert CA-1 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority -# Label: "TrustCor RootCert CA-1" -# Serial: 15752444095811006489 -# MD5 Fingerprint: 6e:85:f1:dc:1a:00:d3:22:d5:b2:b2:ac:6b:37:05:45 -# SHA1 Fingerprint: ff:bd:cd:e7:82:c8:43:5e:3c:6f:26:86:5c:ca:a8:3a:45:5b:c3:0a -# SHA256 Fingerprint: d4:0e:9c:86:cd:8f:e4:68:c1:77:69:59:f4:9e:a7:74:fa:54:86:84:b6:c4:06:f3:90:92:61:f4:dc:e2:57:5c ------BEGIN CERTIFICATE----- -MIIEMDCCAxigAwIBAgIJANqb7HHzA7AZMA0GCSqGSIb3DQEBCwUAMIGkMQswCQYD -VQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEk -MCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U -cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRydXN0Q29y -IFJvb3RDZXJ0IENBLTEwHhcNMTYwMjA0MTIzMjE2WhcNMjkxMjMxMTcyMzE2WjCB -pDELMAkGA1UEBhMCUEExDzANBgNVBAgMBlBhbmFtYTEUMBIGA1UEBwwLUGFuYW1h -IENpdHkxJDAiBgNVBAoMG1RydXN0Q29yIFN5c3RlbXMgUy4gZGUgUi5MLjEnMCUG -A1UECwweVHJ1c3RDb3IgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MR8wHQYDVQQDDBZU -cnVzdENvciBSb290Q2VydCBDQS0xMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB -CgKCAQEAv463leLCJhJrMxnHQFgKq1mqjQCj/IDHUHuO1CAmujIS2CNUSSUQIpid -RtLByZ5OGy4sDjjzGiVoHKZaBeYei0i/mJZ0PmnK6bV4pQa81QBeCQryJ3pS/C3V -seq0iWEk8xoT26nPUu0MJLq5nux+AHT6k61sKZKuUbS701e/s/OojZz0JEsq1pme -9J7+wH5COucLlVPat2gOkEz7cD+PSiyU8ybdY2mplNgQTsVHCJCZGxdNuWxu72CV -EY4hgLW9oHPY0LJ3xEXqWib7ZnZ2+AYfYW0PVcWDtxBWcgYHpfOxGgMFZA6dWorW -hnAbJN7+KIor0Gqw/Hqi3LJ5DotlDwIDAQABo2MwYTAdBgNVHQ4EFgQU7mtJPHo/ -DeOxCbeKyKsZn3MzUOcwHwYDVR0jBBgwFoAU7mtJPHo/DeOxCbeKyKsZn3MzUOcw -DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQAD -ggEBACUY1JGPE+6PHh0RU9otRCkZoB5rMZ5NDp6tPVxBb5UrJKF5mDo4Nvu7Zp5I -/5CQ7z3UuJu0h3U/IJvOcs+hVcFNZKIZBqEHMwwLKeXx6quj7LUKdJDHfXLy11yf -ke+Ri7fc7Waiz45mO7yfOgLgJ90WmMCV1Aqk5IGadZQ1nJBfiDcGrVmVCrDRZ9MZ -yonnMlo2HD6CqFqTvsbQZJG2z9m2GM/bftJlo6bEjhcxwft+dtvTheNYsnd6djts -L1Ac59v2Z3kf9YKVmgenFK+P3CghZwnS1k1aHBkcjndcw5QkPTJrS37UeJSDvjdN -zl/HHk484IkzlQsPpTLWPFp5LBk= ------END CERTIFICATE----- - -# Issuer: CN=TrustCor RootCert CA-2 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority -# Subject: CN=TrustCor RootCert CA-2 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority -# Label: "TrustCor RootCert CA-2" -# Serial: 2711694510199101698 -# MD5 Fingerprint: a2:e1:f8:18:0b:ba:45:d5:c7:41:2a:bb:37:52:45:64 -# SHA1 Fingerprint: b8:be:6d:cb:56:f1:55:b9:63:d4:12:ca:4e:06:34:c7:94:b2:1c:c0 -# SHA256 Fingerprint: 07:53:e9:40:37:8c:1b:d5:e3:83:6e:39:5d:ae:a5:cb:83:9e:50:46:f1:bd:0e:ae:19:51:cf:10:fe:c7:c9:65 ------BEGIN CERTIFICATE----- -MIIGLzCCBBegAwIBAgIIJaHfyjPLWQIwDQYJKoZIhvcNAQELBQAwgaQxCzAJBgNV -BAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQw -IgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRy -dXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0eTEfMB0GA1UEAwwWVHJ1c3RDb3Ig -Um9vdENlcnQgQ0EtMjAeFw0xNjAyMDQxMjMyMjNaFw0zNDEyMzExNzI2MzlaMIGk -MQswCQYDVQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEg -Q2l0eTEkMCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYD -VQQLDB5UcnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRy -dXN0Q29yIFJvb3RDZXJ0IENBLTIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK -AoICAQCnIG7CKqJiJJWQdsg4foDSq8GbZQWU9MEKENUCrO2fk8eHyLAnK0IMPQo+ -QVqedd2NyuCb7GgypGmSaIwLgQ5WoD4a3SwlFIIvl9NkRvRUqdw6VC0xK5mC8tkq -1+9xALgxpL56JAfDQiDyitSSBBtlVkxs1Pu2YVpHI7TYabS3OtB0PAx1oYxOdqHp -2yqlO/rOsP9+aij9JxzIsekp8VduZLTQwRVtDr4uDkbIXvRR/u8OYzo7cbrPb1nK -DOObXUm4TOJXsZiKQlecdu/vvdFoqNL0Cbt3Nb4lggjEFixEIFapRBF37120Hape -az6LMvYHL1cEksr1/p3C6eizjkxLAjHZ5DxIgif3GIJ2SDpxsROhOdUuxTTCHWKF -3wP+TfSvPd9cW436cOGlfifHhi5qjxLGhF5DUVCcGZt45vz27Ud+ez1m7xMTiF88 -oWP7+ayHNZ/zgp6kPwqcMWmLmaSISo5uZk3vFsQPeSghYA2FFn3XVDjxklb9tTNM -g9zXEJ9L/cb4Qr26fHMC4P99zVvh1Kxhe1fVSntb1IVYJ12/+CtgrKAmrhQhJ8Z3 -mjOAPF5GP/fDsaOGM8boXg25NSyqRsGFAnWAoOsk+xWq5Gd/bnc/9ASKL3x74xdh -8N0JqSDIvgmk0H5Ew7IwSjiqqewYmgeCK9u4nBit2uBGF6zPXQIDAQABo2MwYTAd -BgNVHQ4EFgQU2f4hQG6UnrybPZx9mCAZ5YwwYrIwHwYDVR0jBBgwFoAU2f4hQG6U -nrybPZx9mCAZ5YwwYrIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYw -DQYJKoZIhvcNAQELBQADggIBAJ5Fngw7tu/hOsh80QA9z+LqBrWyOrsGS2h60COX -dKcs8AjYeVrXWoSK2BKaG9l9XE1wxaX5q+WjiYndAfrs3fnpkpfbsEZC89NiqpX+ -MWcUaViQCqoL7jcjx1BRtPV+nuN79+TMQjItSQzL/0kMmx40/W5ulop5A7Zv2wnL -/V9lFDfhOPXzYRZY5LVtDQsEGz9QLX+zx3oaFoBg+Iof6Rsqxvm6ARppv9JYx1RX -CI/hOWB3S6xZhBqI8d3LT3jX5+EzLfzuQfogsL7L9ziUwOHQhQ+77Sxzq+3+knYa -ZH9bDTMJBzN7Bj8RpFxwPIXAz+OQqIN3+tvmxYxoZxBnpVIt8MSZj3+/0WvitUfW -2dCFmU2Umw9Lje4AWkcdEQOsQRivh7dvDDqPys/cA8GiCcjl/YBeyGBCARsaU1q7 -N6a3vLqE6R5sGtRk2tRD/pOLS/IseRYQ1JMLiI+h2IYURpFHmygk71dSTlxCnKr3 -Sewn6EAes6aJInKc9Q0ztFijMDvd1GpUk74aTfOTlPf8hAs/hCBcNANExdqtvArB -As8e5ZTZ845b2EzwnexhF7sUMlQMAimTHpKG9n/v55IFDlndmQguLvqcAFLTxWYp -5KeXRKQOKIETNcX2b2TmQcTVL8w0RSXPQQCWPUouwpaYT05KnJe32x+SMsj/D1Fu -1uwJ ------END CERTIFICATE----- - -# Issuer: CN=TrustCor ECA-1 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority -# Subject: CN=TrustCor ECA-1 O=TrustCor Systems S. de R.L. OU=TrustCor Certificate Authority -# Label: "TrustCor ECA-1" -# Serial: 9548242946988625984 -# MD5 Fingerprint: 27:92:23:1d:0a:f5:40:7c:e9:e6:6b:9d:d8:f5:e7:6c -# SHA1 Fingerprint: 58:d1:df:95:95:67:6b:63:c0:f0:5b:1c:17:4d:8b:84:0b:c8:78:bd -# SHA256 Fingerprint: 5a:88:5d:b1:9c:01:d9:12:c5:75:93:88:93:8c:af:bb:df:03:1a:b2:d4:8e:91:ee:15:58:9b:42:97:1d:03:9c ------BEGIN CERTIFICATE----- -MIIEIDCCAwigAwIBAgIJAISCLF8cYtBAMA0GCSqGSIb3DQEBCwUAMIGcMQswCQYD -VQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEk -MCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U -cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxFzAVBgNVBAMMDlRydXN0Q29y -IEVDQS0xMB4XDTE2MDIwNDEyMzIzM1oXDTI5MTIzMTE3MjgwN1owgZwxCzAJBgNV -BAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQw -IgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRy -dXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0eTEXMBUGA1UEAwwOVHJ1c3RDb3Ig -RUNBLTEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPj+ARtZ+odnbb -3w9U73NjKYKtR8aja+3+XzP4Q1HpGjORMRegdMTUpwHmspI+ap3tDvl0mEDTPwOA -BoJA6LHip1GnHYMma6ve+heRK9jGrB6xnhkB1Zem6g23xFUfJ3zSCNV2HykVh0A5 -3ThFEXXQmqc04L/NyFIduUd+Dbi7xgz2c1cWWn5DkR9VOsZtRASqnKmcp0yJF4Ou -owReUoCLHhIlERnXDH19MURB6tuvsBzvgdAsxZohmz3tQjtQJvLsznFhBmIhVE5/ -wZ0+fyCMgMsq2JdiyIMzkX2woloPV+g7zPIlstR8L+xNxqE6FXrntl019fZISjZF -ZtS6mFjBAgMBAAGjYzBhMB0GA1UdDgQWBBREnkj1zG1I1KBLf/5ZJC+Dl5mahjAf -BgNVHSMEGDAWgBREnkj1zG1I1KBLf/5ZJC+Dl5mahjAPBgNVHRMBAf8EBTADAQH/ -MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAQEABT41XBVwm8nHc2Fv -civUwo/yQ10CzsSUuZQRg2dd4mdsdXa/uwyqNsatR5Nj3B5+1t4u/ukZMjgDfxT2 -AHMsWbEhBuH7rBiVDKP/mZb3Kyeb1STMHd3BOuCYRLDE5D53sXOpZCz2HAF8P11F -hcCF5yWPldwX8zyfGm6wyuMdKulMY/okYWLW2n62HGz1Ah3UKt1VkOsqEUc8Ll50 -soIipX1TH0XsJ5F95yIW6MBoNtjG8U+ARDL54dHRHareqKucBK+tIA5kmE2la8BI -WJZpTdwHjFGTot+fDz2LYLSCjaoITmJF4PkL0uDgPFveXHEnJcLmA4GLEFPjx1Wi -tJ/X5g== ------END CERTIFICATE----- - -# Issuer: CN=SSL.com Root Certification Authority RSA O=SSL Corporation -# Subject: CN=SSL.com Root Certification Authority RSA O=SSL Corporation -# Label: "SSL.com Root Certification Authority RSA" -# Serial: 8875640296558310041 -# MD5 Fingerprint: 86:69:12:c0:70:f1:ec:ac:ac:c2:d5:bc:a5:5b:a1:29 -# SHA1 Fingerprint: b7:ab:33:08:d1:ea:44:77:ba:14:80:12:5a:6f:bd:a9:36:49:0c:bb -# SHA256 Fingerprint: 85:66:6a:56:2e:e0:be:5c:e9:25:c1:d8:89:0a:6f:76:a8:7e:c1:6d:4d:7d:5f:29:ea:74:19:cf:20:12:3b:69 ------BEGIN CERTIFICATE----- -MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE -BhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQK -DA9TU0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZp -Y2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYwMjEyMTczOTM5WhcNNDEwMjEyMTcz -OTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv -dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv -bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcN -AQEBBQADggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2R -xFdHaxh3a3by/ZPkPQ/CFp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aX -qhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcC -C52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/geoeOy3ZExqysdBP+lSgQ3 -6YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkpk8zruFvh -/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrF -YD3ZfBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93E -JNyAKoFBbZQ+yODJgUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVc -US4cK38acijnALXRdMbX5J+tB5O2UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8 -ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi81xtZPCvM8hnIk2snYxnP/Okm -+Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4sbE6x/c+cCbqi -M+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV -HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4G -A1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGV -cpNxJK1ok1iOMq8bs3AD/CUrdIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBc -Hadm47GUBwwyOabqG7B52B2ccETjit3E+ZUfijhDPwGFpUenPUayvOUiaPd7nNgs -PgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAslu1OJD7OAUN5F7kR/ -q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjqerQ0 -cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jr -a6x+3uxjMxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90I -H37hVZkLId6Tngr75qNJvTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/Y -K9f1JmzJBjSWFupwWRoyeXkLtoh/D1JIPb9s2KJELtFOt3JY04kTlf5Eq/jXixtu -nLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406ywKBjYZC6VWg3dGq2ktuf -oYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NIWuuA8ShY -Ic2wBlX7Jz9TkHCpBB5XJ7k= ------END CERTIFICATE----- - -# Issuer: CN=SSL.com Root Certification Authority ECC O=SSL Corporation -# Subject: CN=SSL.com Root Certification Authority ECC O=SSL Corporation -# Label: "SSL.com Root Certification Authority ECC" -# Serial: 8495723813297216424 -# MD5 Fingerprint: 2e:da:e4:39:7f:9c:8f:37:d1:70:9f:26:17:51:3a:8e -# SHA1 Fingerprint: c3:19:7c:39:24:e6:54:af:1b:c4:ab:20:95:7a:e2:c3:0e:13:02:6a -# SHA256 Fingerprint: 34:17:bb:06:cc:60:07:da:1b:96:1c:92:0b:8a:b4:ce:3f:ad:82:0e:4a:a3:0b:9a:cb:c4:a7:4e:bd:ce:bc:65 ------BEGIN CERTIFICATE----- -MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMC -VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T -U0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0 -aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNDAzWhcNNDEwMjEyMTgxNDAz -WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0 -b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBS -b290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB -BAAiA2IABEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI -7Z4INcgn64mMU1jrYor+8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPg -CemB+vNH06NjMGEwHQYDVR0OBBYEFILRhXMw5zUE044CkvvlpNHEIejNMA8GA1Ud -EwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTTjgKS++Wk0cQh6M0wDgYD -VR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCWe+0F+S8T -kdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+ -gA0z5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl ------END CERTIFICATE----- - -# Issuer: CN=SSL.com EV Root Certification Authority RSA R2 O=SSL Corporation -# Subject: CN=SSL.com EV Root Certification Authority RSA R2 O=SSL Corporation -# Label: "SSL.com EV Root Certification Authority RSA R2" -# Serial: 6248227494352943350 -# MD5 Fingerprint: e1:1e:31:58:1a:ae:54:53:02:f6:17:6a:11:7b:4d:95 -# SHA1 Fingerprint: 74:3a:f0:52:9b:d0:32:a0:f4:4a:83:cd:d4:ba:a9:7b:7c:2e:c4:9a -# SHA256 Fingerprint: 2e:7b:f1:6c:c2:24:85:a7:bb:e2:aa:86:96:75:07:61:b0:ae:39:be:3b:2f:e9:d0:cc:6d:4e:f7:34:91:42:5c ------BEGIN CERTIFICATE----- -MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNV -BAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UE -CgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2Vy -dGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMB4XDTE3MDUzMTE4MTQzN1oXDTQy -MDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4G -A1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQD -DC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy -MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvq -M0fNTPl9fb69LT3w23jhhqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssuf -OePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7wcXHswxzpY6IXFJ3vG2fThVUCAtZJycxa -4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTOZw+oz12WGQvE43LrrdF9 -HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+B6KjBSYR -aZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcA -b9ZhCBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQ -Gp8hLH94t2S42Oim9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQV -PWKchjgGAGYS5Fl2WlPAApiiECtoRHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMO -pgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+SlmJuwgUHfbSguPvuUCYHBBXtSu -UDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48+qvWBkofZ6aY -MBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV -HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa4 -9QaAJadz20ZpqJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBW -s47LCp1Jjr+kxJG7ZhcFUZh1++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5 -Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nxY/hoLVUE0fKNsKTPvDxeH3jnpaAg -cLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2GguDKBAdRUNf/ktUM -79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDzOFSz -/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXt -ll9ldDz7CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEm -Kf7GUmG6sXP/wwyc5WxqlD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKK -QbNmC1r7fSOl8hqw/96bg5Qu0T/fkreRrwU7ZcegbLHNYhLDkBvjJc40vG93drEQ -w/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1hlMYegouCRw2n5H9gooi -S9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX9hwJ1C07 -mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w== ------END CERTIFICATE----- - -# Issuer: CN=SSL.com EV Root Certification Authority ECC O=SSL Corporation -# Subject: CN=SSL.com EV Root Certification Authority ECC O=SSL Corporation -# Label: "SSL.com EV Root Certification Authority ECC" -# Serial: 3182246526754555285 -# MD5 Fingerprint: 59:53:22:65:83:42:01:54:c0:ce:42:b9:5a:7c:f2:90 -# SHA1 Fingerprint: 4c:dd:51:a3:d1:f5:20:32:14:b0:c6:c5:32:23:03:91:c7:46:42:6d -# SHA256 Fingerprint: 22:a2:c1:f7:bd:ed:70:4c:c1:e7:01:b5:f4:08:c3:10:88:0f:e9:56:b5:de:2a:4a:44:f9:9c:87:3a:25:a7:c8 ------BEGIN CERTIFICATE----- -MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMC -VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T -U0wgQ29ycG9yYXRpb24xNDAyBgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZp -Y2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNTIzWhcNNDEwMjEyMTgx -NTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv -dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NMLmNv -bSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49 -AgEGBSuBBAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMA -VIbc/R/fALhBYlzccBYy3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1Kthku -WnBaBu2+8KGwytAJKaNjMGEwHQYDVR0OBBYEFFvKXuXe0oGqzagtZFG22XKbl+ZP -MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe5d7SgarNqC1kUbbZcpuX -5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJN+vp1RPZ -ytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZg -h5Mmm7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg== ------END CERTIFICATE----- - -# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R6 -# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R6 -# Label: "GlobalSign Root CA - R6" -# Serial: 1417766617973444989252670301619537 -# MD5 Fingerprint: 4f:dd:07:e4:d4:22:64:39:1e:0c:37:42:ea:d1:c6:ae -# SHA1 Fingerprint: 80:94:64:0e:b5:a7:a1:ca:11:9c:1f:dd:d5:9f:81:02:63:a7:fb:d1 -# SHA256 Fingerprint: 2c:ab:ea:fe:37:d0:6c:a2:2a:ba:73:91:c0:03:3d:25:98:29:52:c4:53:64:73:49:76:3a:3a:b5:ad:6c:cf:69 ------BEGIN CERTIFICATE----- -MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEg -MB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2Jh -bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQx -MjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSNjET -MBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCAiIwDQYJ -KoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQssgrRI -xutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1k -ZguSgMpE3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxD -aNc9PIrFsmbVkJq3MQbFvuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJw -LnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqMPKq0pPbzlUoSB239jLKJz9CgYXfIWHSw -1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+azayOeSsJDa38O+2HBNX -k7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05OWgtH8wY2 -SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/h -bguyCLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4n -WUx2OVvq+aWh2IMP0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpY -rZxCRXluDocZXFSxZba/jJvcE+kNb7gu3GduyYsRtYQUigAZcIN5kZeR1Bonvzce -MgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTAD -AQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNVHSMEGDAWgBSu -bAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN -nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGt -Ixg93eFyRJa0lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr61 -55wsTLxDKZmOMNOsIeDjHfrYBzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLj -vUYAGm0CuiVdjaExUd1URhxN25mW7xocBFymFe944Hn+Xds+qkxV/ZoVqW/hpvvf -cDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr3TsTjxKM4kEaSHpz -oHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB10jZp -nOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfs -pA9MRf/TuTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+v -JJUEeKgDu+6B5dpffItKoZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R -8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+tJDfLRVpOoERIyNiwmcUVhAn21klJwGW4 -5hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA= ------END CERTIFICATE----- - -# Issuer: CN=OISTE WISeKey Global Root GC CA O=WISeKey OU=OISTE Foundation Endorsed -# Subject: CN=OISTE WISeKey Global Root GC CA O=WISeKey OU=OISTE Foundation Endorsed -# Label: "OISTE WISeKey Global Root GC CA" -# Serial: 44084345621038548146064804565436152554 -# MD5 Fingerprint: a9:d6:b9:2d:2f:93:64:f8:a5:69:ca:91:e9:68:07:23 -# SHA1 Fingerprint: e0:11:84:5e:34:de:be:88:81:b9:9c:f6:16:26:d1:96:1f:c3:b9:31 -# SHA256 Fingerprint: 85:60:f9:1c:36:24:da:ba:95:70:b5:fe:a0:db:e3:6f:f1:1a:83:23:be:94:86:85:4f:b3:f3:4a:55:71:19:8d ------BEGIN CERTIFICATE----- -MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQsw -CQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91 -bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwg -Um9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRaFw00MjA1MDkwOTU4MzNaMG0xCzAJ -BgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBGb3Vu -ZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2JhbCBS -b290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4ni -eUqjFqdrVCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4W -p2OQ0jnUsYd4XxiWD1AbNTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8E -BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7T -rYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0EAwMDaAAwZQIwJsdpW9zV -57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtkAjEA2zQg -Mgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9 ------END CERTIFICATE----- - -# Issuer: CN=GTS Root R1 O=Google Trust Services LLC -# Subject: CN=GTS Root R1 O=Google Trust Services LLC -# Label: "GTS Root R1" -# Serial: 146587175971765017618439757810265552097 -# MD5 Fingerprint: 82:1a:ef:d4:d2:4a:f2:9f:e2:3d:97:06:14:70:72:85 -# SHA1 Fingerprint: e1:c9:50:e6:ef:22:f8:4c:56:45:72:8b:92:20:60:d7:d5:a7:a3:e8 -# SHA256 Fingerprint: 2a:57:54:71:e3:13:40:bc:21:58:1c:bd:2c:f1:3e:15:84:63:20:3e:ce:94:bc:f9:d3:cc:19:6b:f0:9a:54:72 ------BEGIN CERTIFICATE----- -MIIFWjCCA0KgAwIBAgIQbkepxUtHDA3sM9CJuRz04TANBgkqhkiG9w0BAQwFADBH -MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM -QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy -MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl -cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEB -AQUAA4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaM -f/vo27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vX -mX7wCl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7 -zUjwTcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0P -fyblqAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtc -vfaHszVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4 -Zor8Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUsp -zBmkMiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOO -Rc92wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYW -k70paDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+ -DVrNVjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgF -lQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV -HQ4EFgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBADiW -Cu49tJYeX++dnAsznyvgyv3SjgofQXSlfKqE1OXyHuY3UjKcC9FhHb8owbZEKTV1 -d5iyfNm9dKyKaOOpMQkpAWBz40d8U6iQSifvS9efk+eCNs6aaAyC58/UEBZvXw6Z -XPYfcX3v73svfuo21pdwCxXu11xWajOl40k4DLh9+42FpLFZXvRq4d2h9mREruZR -gyFmxhE+885H7pwoHyXa/6xmld01D1zvICxi/ZG6qcz8WpyTgYMpl0p8WnK0OdC3 -d8t5/Wk6kjftbjhlRn7pYL15iJdfOBL07q9bgsiG1eGZbYwE8na6SfZu6W0eX6Dv -J4J2QPim01hcDyxC2kLGe4g0x8HYRZvBPsVhHdljUEn2NIVq4BjFbkerQUIpm/Zg -DdIx02OYI5NaAIFItO/Nis3Jz5nu2Z6qNuFoS3FJFDYoOj0dzpqPJeaAcWErtXvM -+SUWgeExX6GjfhaknBZqlxi9dnKlC54dNuYvoS++cJEPqOba+MSSQGwlfnuzCdyy -F62ARPBopY+Udf90WuioAnwMCeKpSwughQtiue+hMZL77/ZRBIls6Kl0obsXs7X9 -SQ98POyDGCBDTtWTurQ0sR8WNh8M5mQ5Fkzc4P4dyKliPUDqysU0ArSuiYgzNdws -E3PYJ/HQcu51OyLemGhmW/HGY0dVHLqlCFF1pkgl ------END CERTIFICATE----- - -# Issuer: CN=GTS Root R2 O=Google Trust Services LLC -# Subject: CN=GTS Root R2 O=Google Trust Services LLC -# Label: "GTS Root R2" -# Serial: 146587176055767053814479386953112547951 -# MD5 Fingerprint: 44:ed:9a:0e:a4:09:3b:00:f2:ae:4c:a3:c6:61:b0:8b -# SHA1 Fingerprint: d2:73:96:2a:2a:5e:39:9f:73:3f:e1:c7:1e:64:3f:03:38:34:fc:4d -# SHA256 Fingerprint: c4:5d:7b:b0:8e:6d:67:e6:2e:42:35:11:0b:56:4e:5f:78:fd:92:ef:05:8c:84:0a:ea:4e:64:55:d7:58:5c:60 ------BEGIN CERTIFICATE----- -MIIFWjCCA0KgAwIBAgIQbkepxlqz5yDFMJo/aFLybzANBgkqhkiG9w0BAQwFADBH -MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM -QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy -MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl -cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEB -AQUAA4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3Lv -CvptnfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3Kg -GjSY6Dlo7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9Bu -XvAuMC6C/Pq8tBcKSOWIm8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOd -re7kRXuJVfeKH2JShBKzwkCX44ofR5GmdFrS+LFjKBC4swm4VndAoiaYecb+3yXu -PuWgf9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7MkogwTZq9TwtImoS1 -mKPV+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJGr61K -8YzodDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqj -x5RWIr9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsR -nTKaG73VululycslaVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0 -kzCqgc7dGtxRcw1PcOnlthYhGXmy5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9Ok -twIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV -HQ4EFgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQADggIBALZp -8KZ3/p7uC4Gt4cCpx/k1HUCCq+YEtN/L9x0Pg/B+E02NjO7jMyLDOfxA325BS0JT -vhaI8dI4XsRomRyYUpOM52jtG2pzegVATX9lO9ZY8c6DR2Dj/5epnGB3GFW1fgiT -z9D2PGcDFWEJ+YF59exTpJ/JjwGLc8R3dtyDovUMSRqodt6Sm2T4syzFJ9MHwAiA -pJiS4wGWAqoC7o87xdFtCjMwc3i5T1QWvwsHoaRc5svJXISPD+AVdyx+Jn7axEvb -pxZ3B7DNdehyQtaVhJ2Gg/LkkM0JR9SLA3DaWsYDQvTtN6LwG1BUSw7YhN4ZKJmB -R64JGz9I0cNv4rBgF/XuIwKl2gBbbZCr7qLpGzvpx0QnRY5rn/WkhLx3+WuXrD5R -RaIRpsyF7gpo8j5QOHokYh4XIDdtak23CZvJ/KRY9bb7nE4Yu5UC56GtmwfuNmsk -0jmGwZODUNKBRqhfYlcsu2xkiAhu7xNUX90txGdj08+JN7+dIPT7eoOboB6BAFDC -5AwiWVIQ7UNWhwD4FFKnHYuTjKJNRn8nxnGbJN7k2oaLDX5rIMHAnuFl2GqjpuiF -izoHCBy69Y9Vmhh1fuXsgWbRIXOhNUQLgD1bnF5vKheW0YMjiGZt5obicDIvUiLn -yOd/xCxgXS/Dr55FBcOEArf9LAhST4Ldo/DUhgkC ------END CERTIFICATE----- - -# Issuer: CN=GTS Root R3 O=Google Trust Services LLC -# Subject: CN=GTS Root R3 O=Google Trust Services LLC -# Label: "GTS Root R3" -# Serial: 146587176140553309517047991083707763997 -# MD5 Fingerprint: 1a:79:5b:6b:04:52:9c:5d:c7:74:33:1b:25:9a:f9:25 -# SHA1 Fingerprint: 30:d4:24:6f:07:ff:db:91:89:8a:0b:e9:49:66:11:eb:8c:5e:46:e5 -# SHA256 Fingerprint: 15:d5:b8:77:46:19:ea:7d:54:ce:1c:a6:d0:b0:c4:03:e0:37:a9:17:f1:31:e8:a0:4e:1e:6b:7a:71:ba:bc:e5 ------BEGIN CERTIFICATE----- -MIICDDCCAZGgAwIBAgIQbkepx2ypcyRAiQ8DVd2NHTAKBggqhkjOPQQDAzBHMQsw -CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU -MBIGA1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw -MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp -Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjOPQIBBgUrgQQA -IgNiAAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout -736GjOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2A -DDL24CejQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud -DgQWBBTB8Sa6oC2uhYHP0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEAgFuk -fCPAlaUs3L6JbyO5o91lAFJekazInXJ0glMLfalAvWhgxeG4VDvBNhcl2MG9AjEA -njWSdIUlUfUk7GRSJFClH9voy8l27OyCbvWFGFPouOOaKaqW04MjyaR7YbPMAuhd ------END CERTIFICATE----- - -# Issuer: CN=GTS Root R4 O=Google Trust Services LLC -# Subject: CN=GTS Root R4 O=Google Trust Services LLC -# Label: "GTS Root R4" -# Serial: 146587176229350439916519468929765261721 -# MD5 Fingerprint: 5d:b6:6a:c4:60:17:24:6a:1a:99:a8:4b:ee:5e:b4:26 -# SHA1 Fingerprint: 2a:1d:60:27:d9:4a:b1:0a:1c:4d:91:5c:cd:33:a0:cb:3e:2d:54:cb -# SHA256 Fingerprint: 71:cc:a5:39:1f:9e:79:4b:04:80:25:30:b3:63:e1:21:da:8a:30:43:bb:26:66:2f:ea:4d:ca:7f:c9:51:a4:bd ------BEGIN CERTIFICATE----- -MIICCjCCAZGgAwIBAgIQbkepyIuUtui7OyrYorLBmTAKBggqhkjOPQQDAzBHMQsw -CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU -MBIGA1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw -MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp -Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQA -IgNiAATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzu -hXyiQHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/l -xKvRHYqjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud -DgQWBBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNnADBkAjBqUFJ0 -CMRw3J5QdCHojXohw0+WbhXRIjVhLfoIN+4Zba3bssx9BzT1YBkstTTZbyACMANx -sbqjYAuG7ZoIapVon+Kz4ZNkfF6Tpt95LY2F45TPI11xzPKwTdb+mciUqXWi4w== ------END CERTIFICATE----- - -# Issuer: CN=UCA Global G2 Root O=UniTrust -# Subject: CN=UCA Global G2 Root O=UniTrust -# Label: "UCA Global G2 Root" -# Serial: 124779693093741543919145257850076631279 -# MD5 Fingerprint: 80:fe:f0:c4:4a:f0:5c:62:32:9f:1c:ba:78:a9:50:f8 -# SHA1 Fingerprint: 28:f9:78:16:19:7a:ff:18:25:18:aa:44:fe:c1:a0:ce:5c:b6:4c:8a -# SHA256 Fingerprint: 9b:ea:11:c9:76:fe:01:47:64:c1:be:56:a6:f9:14:b5:a5:60:31:7a:bd:99:88:39:33:82:e5:16:1a:a0:49:3c ------BEGIN CERTIFICATE----- -MIIFRjCCAy6gAwIBAgIQXd+x2lqj7V2+WmUgZQOQ7zANBgkqhkiG9w0BAQsFADA9 -MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBH -bG9iYWwgRzIgUm9vdDAeFw0xNjAzMTEwMDAwMDBaFw00MDEyMzEwMDAwMDBaMD0x -CzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlUcnVzdDEbMBkGA1UEAwwSVUNBIEds -b2JhbCBHMiBSb290MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxeYr -b3zvJgUno4Ek2m/LAfmZmqkywiKHYUGRO8vDaBsGxUypK8FnFyIdK+35KYmToni9 -kmugow2ifsqTs6bRjDXVdfkX9s9FxeV67HeToI8jrg4aA3++1NDtLnurRiNb/yzm -VHqUwCoV8MmNsHo7JOHXaOIxPAYzRrZUEaalLyJUKlgNAQLx+hVRZ2zA+te2G3/R -VogvGjqNO7uCEeBHANBSh6v7hn4PJGtAnTRnvI3HLYZveT6OqTwXS3+wmeOwcWDc -C/Vkw85DvG1xudLeJ1uK6NjGruFZfc8oLTW4lVYa8bJYS7cSN8h8s+1LgOGN+jIj -tm+3SJUIsUROhYw6AlQgL9+/V087OpAh18EmNVQg7Mc/R+zvWr9LesGtOxdQXGLY -D0tK3Cv6brxzks3sx1DoQZbXqX5t2Okdj4q1uViSukqSKwxW/YDrCPBeKW4bHAyv -j5OJrdu9o54hyokZ7N+1wxrrFv54NkzWbtA+FxyQF2smuvt6L78RHBgOLXMDj6Dl -NaBa4kx1HXHhOThTeEDMg5PXCp6dW4+K5OXgSORIskfNTip1KnvyIvbJvgmRlld6 -iIis7nCs+dwp4wwcOxJORNanTrAmyPPZGpeRaOrvjUYG0lZFWJo8DA+DuAUlwznP -O6Q0ibd5Ei9Hxeepl2n8pndntd978XplFeRhVmUCAwEAAaNCMEAwDgYDVR0PAQH/ -BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFIHEjMz15DD/pQwIX4wV -ZyF0Ad/fMA0GCSqGSIb3DQEBCwUAA4ICAQATZSL1jiutROTL/7lo5sOASD0Ee/oj -L3rtNtqyzm325p7lX1iPyzcyochltq44PTUbPrw7tgTQvPlJ9Zv3hcU2tsu8+Mg5 -1eRfB70VVJd0ysrtT7q6ZHafgbiERUlMjW+i67HM0cOU2kTC5uLqGOiiHycFutfl -1qnN3e92mI0ADs0b+gO3joBYDic/UvuUospeZcnWhNq5NXHzJsBPd+aBJ9J3O5oU -b3n09tDh05S60FdRvScFDcH9yBIw7m+NESsIndTUv4BFFJqIRNow6rSn4+7vW4LV -PtateJLbXDzz2K36uGt/xDYotgIVilQsnLAXc47QN6MUPJiVAAwpBVueSUmxX8fj -y88nZY41F7dXyDDZQVu5FLbowg+UMaeUmMxq67XhJ/UQqAHojhJi6IjMtX9Gl8Cb -EGY4GjZGXyJoPd/JxhMnq1MGrKI8hgZlb7F+sSlEmqO6SWkoaY/X5V+tBIZkbxqg -DMUIYs6Ao9Dz7GjevjPHF1t/gMRMTLGmhIrDO7gJzRSBuhjjVFc2/tsvfEehOjPI -+Vg7RE+xygKJBJYoaMVLuCaJu9YzL1DV/pqJuhgyklTGW+Cd+V7lDSKb9triyCGy -YiGqhkCyLmTTX8jjfhFnRR8F/uOi77Oos/N9j/gMHyIfLXC0uAE0djAA5SN4p1bX -UB+K+wb1whnw0A== ------END CERTIFICATE----- - -# Issuer: CN=UCA Extended Validation Root O=UniTrust -# Subject: CN=UCA Extended Validation Root O=UniTrust -# Label: "UCA Extended Validation Root" -# Serial: 106100277556486529736699587978573607008 -# MD5 Fingerprint: a1:f3:5f:43:c6:34:9b:da:bf:8c:7e:05:53:ad:96:e2 -# SHA1 Fingerprint: a3:a1:b0:6f:24:61:23:4a:e3:36:a5:c2:37:fc:a6:ff:dd:f0:d7:3a -# SHA256 Fingerprint: d4:3a:f9:b3:54:73:75:5c:96:84:fc:06:d7:d8:cb:70:ee:5c:28:e7:73:fb:29:4e:b4:1e:e7:17:22:92:4d:24 ------BEGIN CERTIFICATE----- -MIIFWjCCA0KgAwIBAgIQT9Irj/VkyDOeTzRYZiNwYDANBgkqhkiG9w0BAQsFADBH -MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBF -eHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwHhcNMTUwMzEzMDAwMDAwWhcNMzgxMjMx -MDAwMDAwWjBHMQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNV -BAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwggIiMA0GCSqGSIb3DQEB -AQUAA4ICDwAwggIKAoICAQCpCQcoEwKwmeBkqh5DFnpzsZGgdT6o+uM4AHrsiWog -D4vFsJszA1qGxliG1cGFu0/GnEBNyr7uaZa4rYEwmnySBesFK5pI0Lh2PpbIILvS -sPGP2KxFRv+qZ2C0d35qHzwaUnoEPQc8hQ2E0B92CvdqFN9y4zR8V05WAT558aop -O2z6+I9tTcg1367r3CTueUWnhbYFiN6IXSV8l2RnCdm/WhUFhvMJHuxYMjMR83dk -sHYf5BA1FxvyDrFspCqjc/wJHx4yGVMR59mzLC52LqGj3n5qiAno8geK+LLNEOfi -c0CTuwjRP+H8C5SzJe98ptfRr5//lpr1kXuYC3fUfugH0mK1lTnj8/FtDw5lhIpj -VMWAtuCeS31HJqcBCF3RiJ7XwzJE+oJKCmhUfzhTA8ykADNkUVkLo4KRel7sFsLz -KuZi2irbWWIQJUoqgQtHB0MGcIfS+pMRKXpITeuUx3BNr2fVUbGAIAEBtHoIppB/ -TuDvB0GHr2qlXov7z1CymlSvw4m6WC31MJixNnI5fkkE/SmnTHnkBVfblLkWU41G -sx2VYVdWf6/wFlthWG82UBEL2KwrlRYaDh8IzTY0ZRBiZtWAXxQgXy0MoHgKaNYs -1+lvK9JKBZP8nm9rZ/+I8U6laUpSNwXqxhaN0sSZ0YIrO7o1dfdRUVjzyAfd5LQD -fwIDAQABo0IwQDAdBgNVHQ4EFgQU2XQ65DA9DfcS3H5aBZ8eNJr34RQwDwYDVR0T -AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBADaN -l8xCFWQpN5smLNb7rhVpLGsaGvdftvkHTFnq88nIua7Mui563MD1sC3AO6+fcAUR -ap8lTwEpcOPlDOHqWnzcSbvBHiqB9RZLcpHIojG5qtr8nR/zXUACE/xOHAbKsxSQ -VBcZEhrxH9cMaVr2cXj0lH2RC47skFSOvG+hTKv8dGT9cZr4QQehzZHkPJrgmzI5 -c6sq1WnIeJEmMX3ixzDx/BR4dxIOE/TdFpS/S2d7cFOFyrC78zhNLJA5wA3CXWvp -4uXViI3WLL+rG761KIcSF3Ru/H38j9CHJrAb+7lsq+KePRXBOy5nAliRn+/4Qh8s -t2j1da3Ptfb/EX3C8CSlrdP6oDyp+l3cpaDvRKS+1ujl5BOWF3sGPjLtx7dCvHaj -2GU4Kzg1USEODm8uNBNA4StnDG1KQTAYI1oyVZnJF+A83vbsea0rWBmirSwiGpWO -vpaQXUJXxPkUAzUrHC1RVwinOt4/5Mi0A3PCwSaAuwtCH60NryZy2sy+s6ODWA2C -xR9GUeOcGMyNm43sSet1UNWMKFnKdDTajAshqx7qG+XH/RU+wBeq+yNuJkbL+vmx -cmtpzyKEC2IPrNkZAJSidjzULZrtBJ4tBmIQN1IchXIbJ+XMxjHsN+xjWZsLHXbM -fjKaiJUINlK73nZfdklJrX+9ZSCyycErdhh2n1ax ------END CERTIFICATE----- - -# Issuer: CN=Certigna Root CA O=Dhimyotis OU=0002 48146308100036 -# Subject: CN=Certigna Root CA O=Dhimyotis OU=0002 48146308100036 -# Label: "Certigna Root CA" -# Serial: 269714418870597844693661054334862075617 -# MD5 Fingerprint: 0e:5c:30:62:27:eb:5b:bc:d7:ae:62:ba:e9:d5:df:77 -# SHA1 Fingerprint: 2d:0d:52:14:ff:9e:ad:99:24:01:74:20:47:6e:6c:85:27:27:f5:43 -# SHA256 Fingerprint: d4:8d:3d:23:ee:db:50:a4:59:e5:51:97:60:1c:27:77:4b:9d:7b:18:c9:4d:5a:05:95:11:a1:02:50:b9:31:68 ------BEGIN CERTIFICATE----- -MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAw -WjELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAw -MiA0ODE0NjMwODEwMDAzNjEZMBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0x -MzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjdaMFoxCzAJBgNVBAYTAkZSMRIwEAYD -VQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYzMDgxMDAwMzYxGTAX -BgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw -ggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sO -ty3tRQgXstmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9M -CiBtnyN6tMbaLOQdLNyzKNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPu -I9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8JXrJhFwLrN1CTivngqIkicuQstDuI7pm -TLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16XdG+RCYyKfHx9WzMfgIh -C59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq4NYKpkDf -ePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3Yz -IoejwpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWT -Co/1VTp2lc5ZmIoJlXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1k -JWumIWmbat10TWuXekG9qxf5kBdIjzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5 -hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp//TBt2dzhauH8XwIDAQABo4IB -GjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE -FBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of -1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczov -L3d3d3cuY2VydGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilo -dHRwOi8vY3JsLmNlcnRpZ25hLmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYr -aHR0cDovL2NybC5kaGlteW90aXMuY29tL2NlcnRpZ25hcm9vdGNhLmNybDANBgkq -hkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOItOoldaDgvUSILSo3L -6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxPTGRG -HVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH6 -0BGM+RFq7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncB -lA2c5uk5jR+mUYyZDDl34bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdi -o2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1 -gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS6Cvu5zHbugRqh5jnxV/v -faci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaYtlu3zM63 -Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayh -jWZSaX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw -3kAP+HwV96LOPNdeE4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0= ------END CERTIFICATE----- - -# Issuer: CN=emSign Root CA - G1 O=eMudhra Technologies Limited OU=emSign PKI -# Subject: CN=emSign Root CA - G1 O=eMudhra Technologies Limited OU=emSign PKI -# Label: "emSign Root CA - G1" -# Serial: 235931866688319308814040 -# MD5 Fingerprint: 9c:42:84:57:dd:cb:0b:a7:2e:95:ad:b6:f3:da:bc:ac -# SHA1 Fingerprint: 8a:c7:ad:8f:73:ac:4e:c1:b5:75:4d:a5:40:f4:fc:cf:7c:b5:8e:8c -# SHA256 Fingerprint: 40:f6:af:03:46:a9:9a:a1:cd:1d:55:5a:4e:9c:ce:62:c7:f9:63:46:03:ee:40:66:15:83:3d:c8:c8:d0:03:67 ------BEGIN CERTIFICATE----- -MIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYD -VQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBU -ZWNobm9sb2dpZXMgTGltaXRlZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBH -MTAeFw0xODAyMTgxODMwMDBaFw00MzAyMTgxODMwMDBaMGcxCzAJBgNVBAYTAklO -MRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVkaHJhIFRlY2hub2xv -Z2llcyBMaW1pdGVkMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEcxMIIBIjAN -BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk0u76WaK7p1b1TST0Bsew+eeuGQz -f2N4aLTNLnF115sgxk0pvLZoYIr3IZpWNVrzdr3YzZr/k1ZLpVkGoZM0Kd0WNHVO -8oG0x5ZOrRkVUkr+PHB1cM2vK6sVmjM8qrOLqs1D/fXqcP/tzxE7lM5OMhbTI0Aq -d7OvPAEsbO2ZLIvZTmmYsvePQbAyeGHWDV/D+qJAkh1cF+ZwPjXnorfCYuKrpDhM -tTk1b+oDafo6VGiFbdbyL0NVHpENDtjVaqSW0RM8LHhQ6DqS0hdW5TUaQBw+jSzt -Od9C4INBdN+jzcKGYEho42kLVACL5HZpIQ15TjQIXhTCzLG3rdd8cIrHhQIDAQAB -o0IwQDAdBgNVHQ4EFgQU++8Nhp6w492pufEhF38+/PB3KxowDgYDVR0PAQH/BAQD -AgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFn/8oz1h31x -PaOfG1vR2vjTnGs2vZupYeveFix0PZ7mddrXuqe8QhfnPZHr5X3dPpzxz5KsbEjM -wiI/aTvFthUvozXGaCocV685743QNcMYDHsAVhzNixl03r4PEuDQqqE/AjSxcM6d -GNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q+Mri/Tm3R7nrft8EI6/6nAYH -6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeihU80Bv2noWgby -RQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx -iN66zB+Afko= ------END CERTIFICATE----- - -# Issuer: CN=emSign ECC Root CA - G3 O=eMudhra Technologies Limited OU=emSign PKI -# Subject: CN=emSign ECC Root CA - G3 O=eMudhra Technologies Limited OU=emSign PKI -# Label: "emSign ECC Root CA - G3" -# Serial: 287880440101571086945156 -# MD5 Fingerprint: ce:0b:72:d1:9f:88:8e:d0:50:03:e8:e3:b8:8b:67:40 -# SHA1 Fingerprint: 30:43:fa:4f:f2:57:dc:a0:c3:80:ee:2e:58:ea:78:b2:3f:e6:bb:c1 -# SHA256 Fingerprint: 86:a1:ec:ba:08:9c:4a:8d:3b:be:27:34:c6:12:ba:34:1d:81:3e:04:3c:f9:e8:a8:62:cd:5c:57:a3:6b:be:6b ------BEGIN CERTIFICATE----- -MIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQG -EwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNo -bm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g -RzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4MTgzMDAwWjBrMQswCQYDVQQGEwJJ -TjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9s -b2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMw -djAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0 -WXTsuwYc58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xyS -fvalY8L1X44uT6EYGQIrMgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuB -zhccLikenEhjQjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggq -hkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+DCBeQyh+KTOgNG3qxrdWB -CUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7jHvrZQnD -+JbNR6iC8hZVdyR+EhCVBCyj ------END CERTIFICATE----- - -# Issuer: CN=emSign Root CA - C1 O=eMudhra Inc OU=emSign PKI -# Subject: CN=emSign Root CA - C1 O=eMudhra Inc OU=emSign PKI -# Label: "emSign Root CA - C1" -# Serial: 825510296613316004955058 -# MD5 Fingerprint: d8:e3:5d:01:21:fa:78:5a:b0:df:ba:d2:ee:2a:5f:68 -# SHA1 Fingerprint: e7:2e:f1:df:fc:b2:09:28:cf:5d:d4:d5:67:37:b1:51:cb:86:4f:01 -# SHA256 Fingerprint: 12:56:09:aa:30:1d:a0:a2:49:b9:7a:82:39:cb:6a:34:21:6f:44:dc:ac:9f:39:54:b1:42:92:f2:e8:c8:60:8f ------BEGIN CERTIFICATE----- -MIIDczCCAlugAwIBAgILAK7PALrEzzL4Q7IwDQYJKoZIhvcNAQELBQAwVjELMAkG -A1UEBhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEg -SW5jMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAw -MFoXDTQzMDIxODE4MzAwMFowVjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln -biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQDExNlbVNpZ24gUm9v -dCBDQSAtIEMxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+upufGZ -BczYKCFK83M0UYRWEPWgTywS4/oTmifQz/l5GnRfHXk5/Fv4cI7gklL35CX5VIPZ -HdPIWoU/Xse2B+4+wM6ar6xWQio5JXDWv7V7Nq2s9nPczdcdioOl+yuQFTdrHCZH -3DspVpNqs8FqOp099cGXOFgFixwR4+S0uF2FHYP+eF8LRWgYSKVGczQ7/g/IdrvH -GPMF0Ybzhe3nudkyrVWIzqa2kbBPrH4VI5b2P/AgNBbeCsbEBEV5f6f9vtKppa+c -xSMq9zwhbL2vj07FOrLzNBL834AaSaTUqZX3noleoomslMuoaJuvimUnzYnu3Yy1 -aylwQ6BpC+S5DwIDAQABo0IwQDAdBgNVHQ4EFgQU/qHgcB4qAzlSWkK+XJGFehiq -TbUwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL -BQADggEBAMJKVvoVIXsoounlHfv4LcQ5lkFMOycsxGwYFYDGrK9HWS8mC+M2sO87 -/kOXSTKZEhVb3xEp/6tT+LvBeA+snFOvV71ojD1pM/CjoCNjO2RnIkSt1XHLVip4 -kqNPEjE2NuLe/gDEo2APJ62gsIq1NnpSob0n9CAnYuhNlCQT5AoE6TyrLshDCUrG -YQTlSTR+08TI9Q/Aqum6VF7zYytPT1DU/rl7mYw9wC68AivTxEDkigcxHpvOJpkT -+xHqmiIMERnHXhuBUDDIlhJu58tBf5E7oke3VIAb3ADMmpDqw8NQBmIMMMAVSKeo -WXzhriKi4gp6D/piq1JM4fHfyr6DDUI= ------END CERTIFICATE----- - -# Issuer: CN=emSign ECC Root CA - C3 O=eMudhra Inc OU=emSign PKI -# Subject: CN=emSign ECC Root CA - C3 O=eMudhra Inc OU=emSign PKI -# Label: "emSign ECC Root CA - C3" -# Serial: 582948710642506000014504 -# MD5 Fingerprint: 3e:53:b3:a3:81:ee:d7:10:f8:d3:b0:1d:17:92:f5:d5 -# SHA1 Fingerprint: b6:af:43:c2:9b:81:53:7d:f6:ef:6b:c3:1f:1f:60:15:0c:ee:48:66 -# SHA256 Fingerprint: bc:4d:80:9b:15:18:9d:78:db:3e:1d:8c:f4:f9:72:6a:79:5d:a1:64:3c:a5:f1:35:8e:1d:db:0e:dc:0d:7e:b3 ------BEGIN CERTIFICATE----- -MIICKzCCAbGgAwIBAgIKe3G2gla4EnycqDAKBggqhkjOPQQDAzBaMQswCQYDVQQG -EwJVUzETMBEGA1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMx -IDAeBgNVBAMTF2VtU2lnbiBFQ0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAw -MFoXDTQzMDIxODE4MzAwMFowWjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln -biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMSAwHgYDVQQDExdlbVNpZ24gRUND -IFJvb3QgQ0EgLSBDMzB2MBAGByqGSM49AgEGBSuBBAAiA2IABP2lYa57JhAd6bci -MK4G9IGzsUJxlTm801Ljr6/58pc1kjZGDoeVjbk5Wum739D+yAdBPLtVb4Ojavti -sIGJAnB9SMVK4+kiVCJNk7tCDK93nCOmfddhEc5lx/h//vXyqaNCMEAwHQYDVR0O -BBYEFPtaSNCAIEDyqOkAB2kZd6fmw/TPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB -Af8EBTADAQH/MAoGCCqGSM49BAMDA2gAMGUCMQC02C8Cif22TGK6Q04ThHK1rt0c -3ta13FaPWEBaLd4gTCKDypOofu4SQMfWh0/434UCMBwUZOR8loMRnLDRWmFLpg9J -0wD8ofzkpf9/rdcw0Md3f76BB1UwUCAU9Vc4CqgxUQ== ------END CERTIFICATE----- - -# Issuer: CN=Hongkong Post Root CA 3 O=Hongkong Post -# Subject: CN=Hongkong Post Root CA 3 O=Hongkong Post -# Label: "Hongkong Post Root CA 3" -# Serial: 46170865288971385588281144162979347873371282084 -# MD5 Fingerprint: 11:fc:9f:bd:73:30:02:8a:fd:3f:f3:58:b9:cb:20:f0 -# SHA1 Fingerprint: 58:a2:d0:ec:20:52:81:5b:c1:f3:f8:64:02:24:4e:c2:8e:02:4b:02 -# SHA256 Fingerprint: 5a:2f:c0:3f:0c:83:b0:90:bb:fa:40:60:4b:09:88:44:6c:76:36:18:3d:f9:84:6e:17:10:1a:44:7f:b8:ef:d6 ------BEGIN CERTIFICATE----- -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 -mpv0 ------END CERTIFICATE----- - -# Issuer: CN=Entrust Root Certification Authority - G4 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2015 Entrust, Inc. - for authorized use only -# Subject: CN=Entrust Root Certification Authority - G4 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2015 Entrust, Inc. - for authorized use only -# Label: "Entrust Root Certification Authority - G4" -# Serial: 289383649854506086828220374796556676440 -# MD5 Fingerprint: 89:53:f1:83:23:b7:7c:8e:05:f1:8c:71:38:4e:1f:88 -# SHA1 Fingerprint: 14:88:4e:86:26:37:b0:26:af:59:62:5c:40:77:ec:35:29:ba:96:01 -# SHA256 Fingerprint: db:35:17:d1:f6:73:2a:2d:5a:b9:7c:53:3e:c7:07:79:ee:32:70:a6:2f:b4:ac:42:38:37:24:60:e6:f0:1e:88 ------BEGIN CERTIFICATE----- -MIIGSzCCBDOgAwIBAgIRANm1Q3+vqTkPAAAAAFVlrVgwDQYJKoZIhvcNAQELBQAw -gb4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQL -Ex9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykg -MjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAw -BgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0 -MB4XDTE1MDUyNzExMTExNloXDTM3MTIyNzExNDExNlowgb4xCzAJBgNVBAYTAlVT -MRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1 -c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJ -bmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3Qg -Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0MIICIjANBgkqhkiG9w0B -AQEFAAOCAg8AMIICCgKCAgEAsewsQu7i0TD/pZJH4i3DumSXbcr3DbVZwbPLqGgZ -2K+EbTBwXX7zLtJTmeH+H17ZSK9dE43b/2MzTdMAArzE+NEGCJR5WIoV3imz/f3E -T+iq4qA7ec2/a0My3dl0ELn39GjUu9CH1apLiipvKgS1sqbHoHrmSKvS0VnM1n4j -5pds8ELl3FFLFUHtSUrJ3hCX1nbB76W1NhSXNdh4IjVS70O92yfbYVaCNNzLiGAM -C1rlLAHGVK/XqsEQe9IFWrhAnoanw5CGAlZSCXqc0ieCU0plUmr1POeo8pyvi73T -DtTUXm6Hnmo9RR3RXRv06QqsYJn7ibT/mCzPfB3pAqoEmh643IhuJbNsZvc8kPNX -wbMv9W3y+8qh+CmdRouzavbmZwe+LGcKKh9asj5XxNMhIWNlUpEbsZmOeX7m640A -2Vqq6nPopIICR5b+W45UYaPrL0swsIsjdXJ8ITzI9vF01Bx7owVV7rtNOzK+mndm -nqxpkCIHH2E6lr7lmk/MBTwoWdPBDFSoWWG9yHJM6Nyfh3+9nEg2XpWjDrk4JFX8 -dWbrAuMINClKxuMrLzOg2qOGpRKX/YAr2hRC45K9PvJdXmd0LhyIRyk0X+IyqJwl -N4y6mACXi0mWHv0liqzc2thddG5msP9E36EYxr5ILzeUePiVSj9/E15dWf10hkNj -c0kCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD -VR0OBBYEFJ84xFYjwznooHFs6FRM5Og6sb9nMA0GCSqGSIb3DQEBCwUAA4ICAQAS -5UKme4sPDORGpbZgQIeMJX6tuGguW8ZAdjwD+MlZ9POrYs4QjbRaZIxowLByQzTS -Gwv2LFPSypBLhmb8qoMi9IsabyZIrHZ3CL/FmFz0Jomee8O5ZDIBf9PD3Vht7LGr -hFV0d4QEJ1JrhkzO3bll/9bGXp+aEJlLdWr+aumXIOTkdnrG0CSqkM0gkLpHZPt/ -B7NTeLUKYvJzQ85BK4FqLoUWlFPUa19yIqtRLULVAJyZv967lDtX/Zr1hstWO1uI -AeV8KEsD+UmDfLJ/fOPtjqF/YFOOVZ1QNBIPt5d7bIdKROf1beyAN/BYGW5KaHbw -H5Lk6rWS02FREAutp9lfx1/cH6NcjKF+m7ee01ZvZl4HliDtC3T7Zk6LERXpgUl+ -b7DUUH8i119lAg2m9IUe2K4GS0qn0jFmwvjO5QimpAKWRGhXxNUzzxkvFMSUHHuk -2fCfDrGA4tGeEWSpiBE6doLlYsKA2KSD7ZPvfC+QsDJMlhVoSFLUmQjAJOgc47Ol -IQ6SwJAfzyBfyjs4x7dtOvPmRLgOMWuIjnDrnBdSqEGULoe256YSxXXfW8AKbnuk -5F6G+TaU33fD6Q3AOfF5u0aOq0NZJ7cguyPpVkAh7DE9ZapD8j3fcEThuk0mEDuY -n/PIjhs4ViFqUZPTkcpG2om3PVODLAgfi49T3f+sHw== ------END CERTIFICATE----- - -# Issuer: CN=Microsoft ECC Root Certificate Authority 2017 O=Microsoft Corporation -# Subject: CN=Microsoft ECC Root Certificate Authority 2017 O=Microsoft Corporation -# Label: "Microsoft ECC Root Certificate Authority 2017" -# Serial: 136839042543790627607696632466672567020 -# MD5 Fingerprint: dd:a1:03:e6:4a:93:10:d1:bf:f0:19:42:cb:fe:ed:67 -# SHA1 Fingerprint: 99:9a:64:c3:7f:f4:7d:9f:ab:95:f1:47:69:89:14:60:ee:c4:c3:c5 -# SHA256 Fingerprint: 35:8d:f3:9d:76:4a:f9:e1:b7:66:e9:c9:72:df:35:2e:e1:5c:fa:c2:27:af:6a:d1:d7:0e:8e:4a:6e:dc:ba:02 ------BEGIN CERTIFICATE----- -MIICWTCCAd+gAwIBAgIQZvI9r4fei7FK6gxXMQHC7DAKBggqhkjOPQQDAzBlMQsw -CQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYD -VQQDEy1NaWNyb3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIw -MTcwHhcNMTkxMjE4MjMwNjQ1WhcNNDIwNzE4MjMxNjA0WjBlMQswCQYDVQQGEwJV -UzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNy -b3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwdjAQBgcq -hkjOPQIBBgUrgQQAIgNiAATUvD0CQnVBEyPNgASGAlEvaqiBYgtlzPbKnR5vSmZR -ogPZnZH6thaxjG7efM3beaYvzrvOcS/lpaso7GMEZpn4+vKTEAXhgShC48Zo9OYb -hGBKia/teQ87zvH2RPUBeMCjVDBSMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8E -BTADAQH/MB0GA1UdDgQWBBTIy5lycFIM+Oa+sgRXKSrPQhDtNTAQBgkrBgEEAYI3 -FQEEAwIBADAKBggqhkjOPQQDAwNoADBlAjBY8k3qDPlfXu5gKcs68tvWMoQZP3zV -L8KxzJOuULsJMsbG7X7JNpQS5GiFBqIb0C8CMQCZ6Ra0DvpWSNSkMBaReNtUjGUB -iudQZsIxtzm6uBoiB078a1QWIP8rtedMDE2mT3M= ------END CERTIFICATE----- - -# Issuer: CN=Microsoft RSA Root Certificate Authority 2017 O=Microsoft Corporation -# Subject: CN=Microsoft RSA Root Certificate Authority 2017 O=Microsoft Corporation -# Label: "Microsoft RSA Root Certificate Authority 2017" -# Serial: 40975477897264996090493496164228220339 -# MD5 Fingerprint: 10:ff:00:ff:cf:c9:f8:c7:7a:c0:ee:35:8e:c9:0f:47 -# SHA1 Fingerprint: 73:a5:e6:4a:3b:ff:83:16:ff:0e:dc:cc:61:8a:90:6e:4e:ae:4d:74 -# SHA256 Fingerprint: c7:41:f7:0f:4b:2a:8d:88:bf:2e:71:c1:41:22:ef:53:ef:10:eb:a0:cf:a5:e6:4c:fa:20:f4:18:85:30:73:e0 ------BEGIN CERTIFICATE----- -MIIFqDCCA5CgAwIBAgIQHtOXCV/YtLNHcB6qvn9FszANBgkqhkiG9w0BAQwFADBl -MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYw -NAYDVQQDEy1NaWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5 -IDIwMTcwHhcNMTkxMjE4MjI1MTIyWhcNNDIwNzE4MjMwMDIzWjBlMQswCQYDVQQG -EwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1N -aWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwggIi -MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKW76UM4wplZEWCpW9R2LBifOZ -Nt9GkMml7Xhqb0eRaPgnZ1AzHaGm++DlQ6OEAlcBXZxIQIJTELy/xztokLaCLeX0 -ZdDMbRnMlfl7rEqUrQ7eS0MdhweSE5CAg2Q1OQT85elss7YfUJQ4ZVBcF0a5toW1 -HLUX6NZFndiyJrDKxHBKrmCk3bPZ7Pw71VdyvD/IybLeS2v4I2wDwAW9lcfNcztm -gGTjGqwu+UcF8ga2m3P1eDNbx6H7JyqhtJqRjJHTOoI+dkC0zVJhUXAoP8XFWvLJ -jEm7FFtNyP9nTUwSlq31/niol4fX/V4ggNyhSyL71Imtus5Hl0dVe49FyGcohJUc -aDDv70ngNXtk55iwlNpNhTs+VcQor1fznhPbRiefHqJeRIOkpcrVE7NLP8TjwuaG -YaRSMLl6IE9vDzhTyzMMEyuP1pq9KsgtsRx9S1HKR9FIJ3Jdh+vVReZIZZ2vUpC6 -W6IYZVcSn2i51BVrlMRpIpj0M+Dt+VGOQVDJNE92kKz8OMHY4Xu54+OU4UZpyw4K -UGsTuqwPN1q3ErWQgR5WrlcihtnJ0tHXUeOrO8ZV/R4O03QK0dqq6mm4lyiPSMQH -+FJDOvTKVTUssKZqwJz58oHhEmrARdlns87/I6KJClTUFLkqqNfs+avNJVgyeY+Q -W5g5xAgGwax/Dj0ApQIDAQABo1QwUjAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/ -BAUwAwEB/zAdBgNVHQ4EFgQUCctZf4aycI8awznjwNnpv7tNsiMwEAYJKwYBBAGC -NxUBBAMCAQAwDQYJKoZIhvcNAQEMBQADggIBAKyvPl3CEZaJjqPnktaXFbgToqZC -LgLNFgVZJ8og6Lq46BrsTaiXVq5lQ7GPAJtSzVXNUzltYkyLDVt8LkS/gxCP81OC -gMNPOsduET/m4xaRhPtthH80dK2Jp86519efhGSSvpWhrQlTM93uCupKUY5vVau6 -tZRGrox/2KJQJWVggEbbMwSubLWYdFQl3JPk+ONVFT24bcMKpBLBaYVu32TxU5nh -SnUgnZUP5NbcA/FZGOhHibJXWpS2qdgXKxdJ5XbLwVaZOjex/2kskZGT4d9Mozd2 -TaGf+G0eHdP67Pv0RR0Tbc/3WeUiJ3IrhvNXuzDtJE3cfVa7o7P4NHmJweDyAmH3 -pvwPuxwXC65B2Xy9J6P9LjrRk5Sxcx0ki69bIImtt2dmefU6xqaWM/5TkshGsRGR -xpl/j8nWZjEgQRCHLQzWwa80mMpkg/sTV9HB8Dx6jKXB/ZUhoHHBk2dxEuqPiApp -GWSZI1b7rCoucL5mxAyE7+WL85MB+GqQk2dLsmijtWKP6T+MejteD+eMuMZ87zf9 -dOLITzNy4ZQ5bb0Sr74MTnB8G2+NszKTc0QWbej09+CVgI+WXTik9KveCjCHk9hN -AHFiRSdLOkKEW39lt2c0Ui2cFmuqqNh7o0JMcccMyj6D5KbvtwEwXlGjefVwaaZB -RA+GsCyRxj3qrg+E ------END CERTIFICATE----- - -# Issuer: CN=e-Szigno Root CA 2017 O=Microsec Ltd. -# Subject: CN=e-Szigno Root CA 2017 O=Microsec Ltd. -# Label: "e-Szigno Root CA 2017" -# Serial: 411379200276854331539784714 -# MD5 Fingerprint: de:1f:f6:9e:84:ae:a7:b4:21:ce:1e:58:7d:d1:84:98 -# SHA1 Fingerprint: 89:d4:83:03:4f:9e:9a:48:80:5f:72:37:d4:a9:a6:ef:cb:7c:1f:d1 -# SHA256 Fingerprint: be:b0:0b:30:83:9b:9b:c3:2c:32:e4:44:79:05:95:06:41:f2:64:21:b1:5e:d0:89:19:8b:51:8a:e2:ea:1b:99 ------BEGIN CERTIFICATE----- -MIICQDCCAeWgAwIBAgIMAVRI7yH9l1kN9QQKMAoGCCqGSM49BAMCMHExCzAJBgNV -BAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMgTHRk -LjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25vIFJv -b3QgQ0EgMjAxNzAeFw0xNzA4MjIxMjA3MDZaFw00MjA4MjIxMjA3MDZaMHExCzAJ -BgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMg -THRkLjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25v -IFJvb3QgQ0EgMjAxNzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJbcPYrYsHtv -xie+RJCxs1YVe45DJH0ahFnuY2iyxl6H0BVIHqiQrb1TotreOpCmYF9oMrWGQd+H -Wyx7xf58etqjYzBhMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G -A1UdDgQWBBSHERUI0arBeAyxr87GyZDvvzAEwDAfBgNVHSMEGDAWgBSHERUI0arB -eAyxr87GyZDvvzAEwDAKBggqhkjOPQQDAgNJADBGAiEAtVfd14pVCzbhhkT61Nlo -jbjcI4qKDdQvfepz7L9NbKgCIQDLpbQS+ue16M9+k/zzNY9vTlp8tLxOsvxyqltZ -+efcMQ== ------END CERTIFICATE----- - -# Issuer: O=CERTSIGN SA OU=certSIGN ROOT CA G2 -# Subject: O=CERTSIGN SA OU=certSIGN ROOT CA G2 -# Label: "certSIGN Root CA G2" -# Serial: 313609486401300475190 -# MD5 Fingerprint: 8c:f1:75:8a:c6:19:cf:94:b7:f7:65:20:87:c3:97:c7 -# SHA1 Fingerprint: 26:f9:93:b4:ed:3d:28:27:b0:b9:4b:a7:e9:15:1d:a3:8d:92:e5:32 -# SHA256 Fingerprint: 65:7c:fe:2f:a7:3f:aa:38:46:25:71:f3:32:a2:36:3a:46:fc:e7:02:09:51:71:07:02:cd:fb:b6:ee:da:33:05 ------BEGIN CERTIFICATE----- -MIIFRzCCAy+gAwIBAgIJEQA0tk7GNi02MA0GCSqGSIb3DQEBCwUAMEExCzAJBgNV -BAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJR04g -Uk9PVCBDQSBHMjAeFw0xNzAyMDYwOTI3MzVaFw00MjAyMDYwOTI3MzVaMEExCzAJ -BgNVBAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJ -R04gUk9PVCBDQSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDF -dRmRfUR0dIf+DjuW3NgBFszuY5HnC2/OOwppGnzC46+CjobXXo9X69MhWf05N0Iw -vlDqtg+piNguLWkh59E3GE59kdUWX2tbAMI5Qw02hVK5U2UPHULlj88F0+7cDBrZ -uIt4ImfkabBoxTzkbFpG583H+u/E7Eu9aqSs/cwoUe+StCmrqzWaTOTECMYmzPhp -n+Sc8CnTXPnGFiWeI8MgwT0PPzhAsP6CRDiqWhqKa2NYOLQV07YRaXseVO6MGiKs -cpc/I1mbySKEwQdPzH/iV8oScLumZfNpdWO9lfsbl83kqK/20U6o2YpxJM02PbyW -xPFsqa7lzw1uKA2wDrXKUXt4FMMgL3/7FFXhEZn91QqhngLjYl/rNUssuHLoPj1P -rCy7Lobio3aP5ZMqz6WryFyNSwb/EkaseMsUBzXgqd+L6a8VTxaJW732jcZZroiF -DsGJ6x9nxUWO/203Nit4ZoORUSs9/1F3dmKh7Gc+PoGD4FapUB8fepmrY7+EF3fx -DTvf95xhszWYijqy7DwaNz9+j5LP2RIUZNoQAhVB/0/E6xyjyfqZ90bp4RjZsbgy -LcsUDFDYg2WD7rlcz8sFWkz6GZdr1l0T08JcVLwyc6B49fFtHsufpaafItzRUZ6C -eWRgKRM+o/1Pcmqr4tTluCRVLERLiohEnMqE0yo7AgMBAAGjQjBAMA8GA1UdEwEB -/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSCIS1mxteg4BXrzkwJ -d8RgnlRuAzANBgkqhkiG9w0BAQsFAAOCAgEAYN4auOfyYILVAzOBywaK8SJJ6ejq -kX/GM15oGQOGO0MBzwdw5AgeZYWR5hEit/UCI46uuR59H35s5r0l1ZUa8gWmr4UC -b6741jH/JclKyMeKqdmfS0mbEVeZkkMR3rYzpMzXjWR91M08KCy0mpbqTfXERMQl -qiCA2ClV9+BB/AYm/7k29UMUA2Z44RGx2iBfRgB4ACGlHgAoYXhvqAEBj500mv/0 -OJD7uNGzcgbJceaBxXntC6Z58hMLnPddDnskk7RI24Zf3lCGeOdA5jGokHZwYa+c -NywRtYK3qq4kNFtyDGkNzVmf9nGvnAvRCjj5BiKDUyUM/FHE5r7iOZULJK2v0ZXk -ltd0ZGtxTgI8qoXzIKNDOXZbbFD+mpwUHmUUihW9o4JFWklWatKcsWMy5WHgUyIO -pwpJ6st+H6jiYoD2EEVSmAYY3qXNL3+q1Ok+CHLsIwMCPKaq2LxndD0UF/tUSxfj -03k9bWtJySgOLnRQvwzZRjoQhsmnP+mg7H/rpXdYaXHmgwo38oZJar55CJD2AhZk -PuXaTH4MNMn5X7azKFGnpyuqSfqNZSlO42sTp5SjLVFteAxEy9/eCG/Oo2Sr05WE -1LlSVHJ7liXMvGnjSG4N0MedJ5qq+BOS3R7fY581qRY27Iy4g/Q9iY/NtBde17MX -QRBdJ3NghVdJIgc= ------END CERTIFICATE----- - -# Issuer: CN=Trustwave Global Certification Authority O=Trustwave Holdings, Inc. -# Subject: CN=Trustwave Global Certification Authority O=Trustwave Holdings, Inc. -# Label: "Trustwave Global Certification Authority" -# Serial: 1846098327275375458322922162 -# MD5 Fingerprint: f8:1c:18:2d:2f:ba:5f:6d:a1:6c:bc:c7:ab:91:c7:0e -# SHA1 Fingerprint: 2f:8f:36:4f:e1:58:97:44:21:59:87:a5:2a:9a:d0:69:95:26:7f:b5 -# SHA256 Fingerprint: 97:55:20:15:f5:dd:fc:3c:87:88:c0:06:94:45:55:40:88:94:45:00:84:f1:00:86:70:86:bc:1a:2b:b5:8d:c8 ------BEGIN CERTIFICATE----- -MIIF2jCCA8KgAwIBAgIMBfcOhtpJ80Y1LrqyMA0GCSqGSIb3DQEBCwUAMIGIMQsw -CQYDVQQGEwJVUzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28x -ITAfBgNVBAoMGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1 -c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMx -OTM0MTJaFw00MjA4MjMxOTM0MTJaMIGIMQswCQYDVQQGEwJVUzERMA8GA1UECAwI -SWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2ZSBI -b2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZp -Y2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB -ALldUShLPDeS0YLOvR29zd24q88KPuFd5dyqCblXAj7mY2Hf8g+CY66j96xz0Xzn -swuvCAAJWX/NKSqIk4cXGIDtiLK0thAfLdZfVaITXdHG6wZWiYj+rDKd/VzDBcdu -7oaJuogDnXIhhpCujwOl3J+IKMujkkkP7NAP4m1ET4BqstTnoApTAbqOl5F2brz8 -1Ws25kCI1nsvXwXoLG0R8+eyvpJETNKXpP7ScoFDB5zpET71ixpZfR9oWN0EACyW -80OzfpgZdNmcc9kYvkHHNHnZ9GLCQ7mzJ7Aiy/k9UscwR7PJPrhq4ufogXBeQotP -JqX+OsIgbrv4Fo7NDKm0G2x2EOFYeUY+VM6AqFcJNykbmROPDMjWLBz7BegIlT1l -RtzuzWniTY+HKE40Cz7PFNm73bZQmq131BnW2hqIyE4bJ3XYsgjxroMwuREOzYfw -hI0Vcnyh78zyiGG69Gm7DIwLdVcEuE4qFC49DxweMqZiNu5m4iK4BUBjECLzMx10 -coos9TkpoNPnG4CELcU9402x/RpvumUHO1jsQkUm+9jaJXLE9gCxInm943xZYkqc -BW89zubWR2OZxiRvchLIrH+QtAuRcOi35hYQcRfO3gZPSEF9NUqjifLJS3tBEW1n -twiYTOURGa5CgNz7kAXU+FDKvuStx8KU1xad5hePrzb7AgMBAAGjQjBAMA8GA1Ud -EwEB/wQFMAMBAf8wHQYDVR0OBBYEFJngGWcNYtt2s9o9uFvo/ULSMQ6HMA4GA1Ud -DwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAmHNw4rDT7TnsTGDZqRKGFx6W -0OhUKDtkLSGm+J1WE2pIPU/HPinbbViDVD2HfSMF1OQc3Og4ZYbFdada2zUFvXfe -uyk3QAUHw5RSn8pk3fEbK9xGChACMf1KaA0HZJDmHvUqoai7PF35owgLEQzxPy0Q -lG/+4jSHg9bP5Rs1bdID4bANqKCqRieCNqcVtgimQlRXtpla4gt5kNdXElE1GYhB -aCXUNxeEFfsBctyV3lImIJgm4nb1J2/6ADtKYdkNy1GTKv0WBpanI5ojSP5RvbbE -sLFUzt5sQa0WZ37b/TjNuThOssFgy50X31ieemKyJo90lZvkWx3SD92YHJtZuSPT -MaCm/zjdzyBP6VhWOmfD0faZmZ26NraAL4hHT4a/RDqA5Dccprrql5gR0IRiR2Qe -qu5AvzSxnI9O4fKSTx+O856X3vOmeWqJcU9LJxdI/uz0UA9PSX3MReO9ekDFQdxh -VicGaeVyQYHTtgGJoC86cnn+OjC/QezHYj6RS8fZMXZC+fc8Y+wmjHMMfRod6qh8 -h6jCJ3zhM0EPz8/8AKAigJ5Kp28AsEFFtyLKaEjFQqKu3R3y4G5OBVixwJAWKqQ9 -EEC+j2Jjg6mcgn0tAumDMHzLJ8n9HmYAsC7TIS+OMxZsmO0QqAfWzJPP29FpHOTK -yeC2nOnOcXHebD8WpHk= ------END CERTIFICATE----- - -# Issuer: CN=Trustwave Global ECC P256 Certification Authority O=Trustwave Holdings, Inc. -# Subject: CN=Trustwave Global ECC P256 Certification Authority O=Trustwave Holdings, Inc. -# Label: "Trustwave Global ECC P256 Certification Authority" -# Serial: 4151900041497450638097112925 -# MD5 Fingerprint: 5b:44:e3:8d:5d:36:86:26:e8:0d:05:d2:59:a7:83:54 -# SHA1 Fingerprint: b4:90:82:dd:45:0c:be:8b:5b:b1:66:d3:e2:a4:08:26:cd:ed:42:cf -# SHA256 Fingerprint: 94:5b:bc:82:5e:a5:54:f4:89:d1:fd:51:a7:3d:df:2e:a6:24:ac:70:19:a0:52:05:22:5c:22:a7:8c:cf:a8:b4 ------BEGIN CERTIFICATE----- -MIICYDCCAgegAwIBAgIMDWpfCD8oXD5Rld9dMAoGCCqGSM49BAMCMIGRMQswCQYD -VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAf -BgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3 -YXZlIEdsb2JhbCBFQ0MgUDI1NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0x -NzA4MjMxOTM1MTBaFw00MjA4MjMxOTM1MTBaMIGRMQswCQYDVQQGEwJVUzERMA8G -A1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0 -d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBF -Q0MgUDI1NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTBZMBMGByqGSM49AgEGCCqG -SM49AwEHA0IABH77bOYj43MyCMpg5lOcunSNGLB4kFKA3TjASh3RqMyTpJcGOMoN -FWLGjgEqZZ2q3zSRLoHB5DOSMcT9CTqmP62jQzBBMA8GA1UdEwEB/wQFMAMBAf8w -DwYDVR0PAQH/BAUDAwcGADAdBgNVHQ4EFgQUo0EGrJBt0UrrdaVKEJmzsaGLSvcw -CgYIKoZIzj0EAwIDRwAwRAIgB+ZU2g6gWrKuEZ+Hxbb/ad4lvvigtwjzRM4q3wgh -DDcCIC0mA6AFvWvR9lz4ZcyGbbOcNEhjhAnFjXca4syc4XR7 ------END CERTIFICATE----- - -# Issuer: CN=Trustwave Global ECC P384 Certification Authority O=Trustwave Holdings, Inc. -# Subject: CN=Trustwave Global ECC P384 Certification Authority O=Trustwave Holdings, Inc. -# Label: "Trustwave Global ECC P384 Certification Authority" -# Serial: 2704997926503831671788816187 -# MD5 Fingerprint: ea:cf:60:c4:3b:b9:15:29:40:a1:97:ed:78:27:93:d6 -# SHA1 Fingerprint: e7:f3:a3:c8:cf:6f:c3:04:2e:6d:0e:67:32:c5:9e:68:95:0d:5e:d2 -# SHA256 Fingerprint: 55:90:38:59:c8:c0:c3:eb:b8:75:9e:ce:4e:25:57:22:5f:f5:75:8b:bd:38:eb:d4:82:76:60:1e:1b:d5:80:97 ------BEGIN CERTIFICATE----- -MIICnTCCAiSgAwIBAgIMCL2Fl2yZJ6SAaEc7MAoGCCqGSM49BAMDMIGRMQswCQYD -VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAf -BgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3 -YXZlIEdsb2JhbCBFQ0MgUDM4NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0x -NzA4MjMxOTM2NDNaFw00MjA4MjMxOTM2NDNaMIGRMQswCQYDVQQGEwJVUzERMA8G -A1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0 -d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBF -Q0MgUDM4NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTB2MBAGByqGSM49AgEGBSuB -BAAiA2IABGvaDXU1CDFHBa5FmVXxERMuSvgQMSOjfoPTfygIOiYaOs+Xgh+AtycJ -j9GOMMQKmw6sWASr9zZ9lCOkmwqKi6vr/TklZvFe/oyujUF5nQlgziip04pt89ZF -1PKYhDhloKNDMEEwDwYDVR0TAQH/BAUwAwEB/zAPBgNVHQ8BAf8EBQMDBwYAMB0G -A1UdDgQWBBRVqYSJ0sEyvRjLbKYHTsjnnb6CkDAKBggqhkjOPQQDAwNnADBkAjA3 -AZKXRRJ+oPM+rRk6ct30UJMDEr5E0k9BpIycnR+j9sKS50gU/k6bpZFXrsY3crsC -MGclCrEMXu6pY5Jv5ZAL/mYiykf9ijH3g/56vxC+GCsej/YpHpRZ744hN8tRmKVu -Sw== ------END CERTIFICATE----- - -# Issuer: CN=NAVER Global Root Certification Authority O=NAVER BUSINESS PLATFORM Corp. -# Subject: CN=NAVER Global Root Certification Authority O=NAVER BUSINESS PLATFORM Corp. -# Label: "NAVER Global Root Certification Authority" -# Serial: 9013692873798656336226253319739695165984492813 -# MD5 Fingerprint: c8:7e:41:f6:25:3b:f5:09:b3:17:e8:46:3d:bf:d0:9b -# SHA1 Fingerprint: 8f:6b:f2:a9:27:4a:da:14:a0:c4:f4:8e:61:27:f9:c0:1e:78:5d:d1 -# SHA256 Fingerprint: 88:f4:38:dc:f8:ff:d1:fa:8f:42:91:15:ff:e5:f8:2a:e1:e0:6e:0c:70:c3:75:fa:ad:71:7b:34:a4:9e:72:65 ------BEGIN CERTIFICATE----- -MIIFojCCA4qgAwIBAgIUAZQwHqIL3fXFMyqxQ0Rx+NZQTQ0wDQYJKoZIhvcNAQEM -BQAwaTELMAkGA1UEBhMCS1IxJjAkBgNVBAoMHU5BVkVSIEJVU0lORVNTIFBMQVRG -T1JNIENvcnAuMTIwMAYDVQQDDClOQVZFUiBHbG9iYWwgUm9vdCBDZXJ0aWZpY2F0 -aW9uIEF1dGhvcml0eTAeFw0xNzA4MTgwODU4NDJaFw0zNzA4MTgyMzU5NTlaMGkx -CzAJBgNVBAYTAktSMSYwJAYDVQQKDB1OQVZFUiBCVVNJTkVTUyBQTEFURk9STSBD -b3JwLjEyMDAGA1UEAwwpTkFWRVIgR2xvYmFsIFJvb3QgQ2VydGlmaWNhdGlvbiBB -dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC21PGTXLVA -iQqrDZBbUGOukJR0F0Vy1ntlWilLp1agS7gvQnXp2XskWjFlqxcX0TM62RHcQDaH -38dq6SZeWYp34+hInDEW+j6RscrJo+KfziFTowI2MMtSAuXaMl3Dxeb57hHHi8lE -HoSTGEq0n+USZGnQJoViAbbJAh2+g1G7XNr4rRVqmfeSVPc0W+m/6imBEtRTkZaz -kVrd/pBzKPswRrXKCAfHcXLJZtM0l/aM9BhK4dA9WkW2aacp+yPOiNgSnABIqKYP -szuSjXEOdMWLyEz59JuOuDxp7W87UC9Y7cSw0BwbagzivESq2M0UXZR4Yb8Obtoq -vC8MC3GmsxY/nOb5zJ9TNeIDoKAYv7vxvvTWjIcNQvcGufFt7QSUqP620wbGQGHf -nZ3zVHbOUzoBppJB7ASjjw2i1QnK1sua8e9DXcCrpUHPXFNwcMmIpi3Ua2FzUCaG -YQ5fG8Ir4ozVu53BA0K6lNpfqbDKzE0K70dpAy8i+/Eozr9dUGWokG2zdLAIx6yo -0es+nPxdGoMuK8u180SdOqcXYZaicdNwlhVNt0xz7hlcxVs+Qf6sdWA7G2POAN3a -CJBitOUt7kinaxeZVL6HSuOpXgRM6xBtVNbv8ejyYhbLgGvtPe31HzClrkvJE+2K -AQHJuFFYwGY6sWZLxNUxAmLpdIQM201GLQIDAQABo0IwQDAdBgNVHQ4EFgQU0p+I -36HNLL3s9TsBAZMzJ7LrYEswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB -Af8wDQYJKoZIhvcNAQEMBQADggIBADLKgLOdPVQG3dLSLvCkASELZ0jKbY7gyKoN -qo0hV4/GPnrK21HUUrPUloSlWGB/5QuOH/XcChWB5Tu2tyIvCZwTFrFsDDUIbatj -cu3cvuzHV+YwIHHW1xDBE1UBjCpD5EHxzzp6U5LOogMFDTjfArsQLtk70pt6wKGm -+LUx5vR1yblTmXVHIloUFcd4G7ad6Qz4G3bxhYTeodoS76TiEJd6eN4MUZeoIUCL -hr0N8F5OSza7OyAfikJW4Qsav3vQIkMsRIz75Sq0bBwcupTgE34h5prCy8VCZLQe -lHsIJchxzIdFV4XTnyliIoNRlwAYl3dqmJLJfGBs32x9SuRwTMKeuB330DTHD8z7 -p/8Dvq1wkNoL3chtl1+afwkyQf3NosxabUzyqkn+Zvjp2DXrDige7kgvOtB5CTh8 -piKCk5XQA76+AqAF3SAi428diDRgxuYKuQl1C/AH6GmWNcf7I4GOODm4RStDeKLR -LBT/DShycpWbXgnbiUSYqqFJu3FS8r/2/yehNq+4tneI3TqkbZs0kNwUXTC/t+sX -5Ie3cdCh13cV1ELX8vMxmV2b3RZtP+oGI/hGoiLtk/bdmuYqh7GYVPEi92tF4+KO -dh2ajcQGjTa3FPOdVGm3jjzVpG2Tgbet9r1ke8LJaDmgkpzNNIaRkPpkUZ3+/uul -9XXeifdy ------END CERTIFICATE----- - -# Issuer: CN=AC RAIZ FNMT-RCM SERVIDORES SEGUROS O=FNMT-RCM OU=Ceres -# Subject: CN=AC RAIZ FNMT-RCM SERVIDORES SEGUROS O=FNMT-RCM OU=Ceres -# Label: "AC RAIZ FNMT-RCM SERVIDORES SEGUROS" -# Serial: 131542671362353147877283741781055151509 -# MD5 Fingerprint: 19:36:9c:52:03:2f:d2:d1:bb:23:cc:dd:1e:12:55:bb -# SHA1 Fingerprint: 62:ff:d9:9e:c0:65:0d:03:ce:75:93:d2:ed:3f:2d:32:c9:e3:e5:4a -# SHA256 Fingerprint: 55:41:53:b1:3d:2c:f9:dd:b7:53:bf:be:1a:4e:0a:e0:8d:0a:a4:18:70:58:fe:60:a2:b8:62:b2:e4:b8:7b:cb ------BEGIN CERTIFICATE----- -MIICbjCCAfOgAwIBAgIQYvYybOXE42hcG2LdnC6dlTAKBggqhkjOPQQDAzB4MQsw -CQYDVQQGEwJFUzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNlcmVzMRgw -FgYDVQRhDA9WQVRFUy1RMjgyNjAwNEoxLDAqBgNVBAMMI0FDIFJBSVogRk5NVC1S -Q00gU0VSVklET1JFUyBTRUdVUk9TMB4XDTE4MTIyMDA5MzczM1oXDTQzMTIyMDA5 -MzczM1oweDELMAkGA1UEBhMCRVMxETAPBgNVBAoMCEZOTVQtUkNNMQ4wDAYDVQQL -DAVDZXJlczEYMBYGA1UEYQwPVkFURVMtUTI4MjYwMDRKMSwwKgYDVQQDDCNBQyBS -QUlaIEZOTVQtUkNNIFNFUlZJRE9SRVMgU0VHVVJPUzB2MBAGByqGSM49AgEGBSuB -BAAiA2IABPa6V1PIyqvfNkpSIeSX0oNnnvBlUdBeh8dHsVnyV0ebAAKTRBdp20LH -sbI6GA60XYyzZl2hNPk2LEnb80b8s0RpRBNm/dfF/a82Tc4DTQdxz69qBdKiQ1oK -Um8BA06Oi6NCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD -VR0OBBYEFAG5L++/EYZg8k/QQW6rcx/n0m5JMAoGCCqGSM49BAMDA2kAMGYCMQCu -SuMrQMN0EfKVrRYj3k4MGuZdpSRea0R7/DjiT8ucRRcRTBQnJlU5dUoDzBOQn5IC -MQD6SmxgiHPz7riYYqnOK8LZiqZwMR2vsJRM60/G49HzYqc8/5MuB1xJAWdpEgJy -v+c= ------END CERTIFICATE----- - -# Issuer: CN=GlobalSign Root R46 O=GlobalSign nv-sa -# Subject: CN=GlobalSign Root R46 O=GlobalSign nv-sa -# Label: "GlobalSign Root R46" -# Serial: 1552617688466950547958867513931858518042577 -# MD5 Fingerprint: c4:14:30:e4:fa:66:43:94:2a:6a:1b:24:5f:19:d0:ef -# SHA1 Fingerprint: 53:a2:b0:4b:ca:6b:d6:45:e6:39:8a:8e:c4:0d:d2:bf:77:c3:a2:90 -# SHA256 Fingerprint: 4f:a3:12:6d:8d:3a:11:d1:c4:85:5a:4f:80:7c:ba:d6:cf:91:9d:3a:5a:88:b0:3b:ea:2c:63:72:d9:3c:40:c9 ------BEGIN CERTIFICATE----- -MIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAUA -MEYxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYD -VQQDExNHbG9iYWxTaWduIFJvb3QgUjQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMy -MDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYt -c2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEB -AQUAA4ICDwAwggIKAoICAQCsrHQy6LNl5brtQyYdpokNRbopiLKkHWPd08EsCVeJ -OaFV6Wc0dwxu5FUdUiXSE2te4R2pt32JMl8Nnp8semNgQB+msLZ4j5lUlghYruQG -vGIFAha/r6gjA7aUD7xubMLL1aa7DOn2wQL7Id5m3RerdELv8HQvJfTqa1VbkNud -316HCkD7rRlr+/fKYIje2sGP1q7Vf9Q8g+7XFkyDRTNrJ9CG0Bwta/OrffGFqfUo -0q3v84RLHIf8E6M6cqJaESvWJ3En7YEtbWaBkoe0G1h6zD8K+kZPTXhc+CtI4wSE -y132tGqzZfxCnlEmIyDLPRT5ge1lFgBPGmSXZgjPjHvjK8Cd+RTyG/FWaha/LIWF -zXg4mutCagI0GIMXTpRW+LaCtfOW3T3zvn8gdz57GSNrLNRyc0NXfeD412lPFzYE -+cCQYDdF3uYM2HSNrpyibXRdQr4G9dlkbgIQrImwTDsHTUB+JMWKmIJ5jqSngiCN -I/onccnfxkF0oE32kRbcRoxfKWMxWXEM2G/CtjJ9++ZdU6Z+Ffy7dXxd7Pj2Fxzs -x2sZy/N78CsHpdlseVR2bJ0cpm4O6XkMqCNqo98bMDGfsVR7/mrLZqrcZdCinkqa -ByFrgY/bxFn63iLABJzjqls2k+g9vXqhnQt2sQvHnf3PmKgGwvgqo6GDoLclcqUC -4wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV -HQ4EFgQUA1yrc4GHqMywptWU4jaWSf8FmSwwDQYJKoZIhvcNAQEMBQADggIBAHx4 -7PYCLLtbfpIrXTncvtgdokIzTfnvpCo7RGkerNlFo048p9gkUbJUHJNOxO97k4Vg -JuoJSOD1u8fpaNK7ajFxzHmuEajwmf3lH7wvqMxX63bEIaZHU1VNaL8FpO7XJqti -2kM3S+LGteWygxk6x9PbTZ4IevPuzz5i+6zoYMzRx6Fcg0XERczzF2sUyQQCPtIk -pnnpHs6i58FZFZ8d4kuaPp92CC1r2LpXFNqD6v6MVenQTqnMdzGxRBF6XLE+0xRF -FRhiJBPSy03OXIPBNvIQtQ6IbbjhVp+J3pZmOUdkLG5NrmJ7v2B0GbhWrJKsFjLt -rWhV/pi60zTe9Mlhww6G9kuEYO4Ne7UyWHmRVSyBQ7N0H3qqJZ4d16GLuc1CLgSk -ZoNNiTW2bKg2SnkheCLQQrzRQDGQob4Ez8pn7fXwgNNgyYMqIgXQBztSvwyeqiv5 -u+YfjyW6hY0XHgL+XVAEV8/+LbzvXMAaq7afJMbfc2hIkCwU9D9SGuTSyxTDYWnP -4vkYxboznxSjBF25cfe1lNj2M8FawTSLfJvdkzrnE6JwYZ+vj+vYxXX4M2bUdGc6 -N3ec592kD3ZDZopD8p/7DEJ4Y9HiD2971KE9dJeFt0g5QdYg/NA6s/rob8SKunE3 -vouXsXgxT7PntgMTzlSdriVZzH81Xwj3QEUxeCp6 ------END CERTIFICATE----- - -# Issuer: CN=GlobalSign Root E46 O=GlobalSign nv-sa -# Subject: CN=GlobalSign Root E46 O=GlobalSign nv-sa -# Label: "GlobalSign Root E46" -# Serial: 1552617690338932563915843282459653771421763 -# MD5 Fingerprint: b5:b8:66:ed:de:08:83:e3:c9:e2:01:34:06:ac:51:6f -# SHA1 Fingerprint: 39:b4:6c:d5:fe:80:06:eb:e2:2f:4a:bb:08:33:a0:af:db:b9:dd:84 -# SHA256 Fingerprint: cb:b9:c4:4d:84:b8:04:3e:10:50:ea:31:a6:9f:51:49:55:d7:bf:d2:e2:c6:b4:93:01:01:9a:d6:1d:9f:50:58 ------BEGIN CERTIFICATE----- -MIICCzCCAZGgAwIBAgISEdK7ujNu1LzmJGjFDYQdmOhDMAoGCCqGSM49BAMDMEYx -CzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQD -ExNHbG9iYWxTaWduIFJvb3QgRTQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAw -MDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2Ex -HDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUrgQQA -IgNiAAScDrHPt+ieUnd1NPqlRqetMhkytAepJ8qUuwzSChDH2omwlwxwEwkBjtjq -R+q+soArzfwoDdusvKSGN+1wCAB16pMLey5SnCNoIwZD7JIvU4Tb+0cUB+hflGdd -yXqBPCCjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud -DgQWBBQxCpCPtsad0kRLgLWi5h+xEk8blTAKBggqhkjOPQQDAwNoADBlAjEA31SQ -7Zvvi5QCkxeCmb6zniz2C5GMn0oUsfZkvLtoURMMA/cVi4RguYv/Uo7njLwcAjA8 -+RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+CAezNIm8BZ/3Hobui3A= ------END CERTIFICATE----- - -# Issuer: CN=GLOBALTRUST 2020 O=e-commerce monitoring GmbH -# Subject: CN=GLOBALTRUST 2020 O=e-commerce monitoring GmbH -# Label: "GLOBALTRUST 2020" -# Serial: 109160994242082918454945253 -# MD5 Fingerprint: 8a:c7:6f:cb:6d:e3:cc:a2:f1:7c:83:fa:0e:78:d7:e8 -# SHA1 Fingerprint: d0:67:c1:13:51:01:0c:aa:d0:c7:6a:65:37:31:16:26:4f:53:71:a2 -# SHA256 Fingerprint: 9a:29:6a:51:82:d1:d4:51:a2:e3:7f:43:9b:74:da:af:a2:67:52:33:29:f9:0f:9a:0d:20:07:c3:34:e2:3c:9a ------BEGIN CERTIFICATE----- -MIIFgjCCA2qgAwIBAgILWku9WvtPilv6ZeUwDQYJKoZIhvcNAQELBQAwTTELMAkG -A1UEBhMCQVQxIzAhBgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkw -FwYDVQQDExBHTE9CQUxUUlVTVCAyMDIwMB4XDTIwMDIxMDAwMDAwMFoXDTQwMDYx -MDAwMDAwMFowTTELMAkGA1UEBhMCQVQxIzAhBgNVBAoTGmUtY29tbWVyY2UgbW9u -aXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVTVCAyMDIwMIICIjANBgkq -hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAri5WrRsc7/aVj6B3GyvTY4+ETUWiD59b -RatZe1E0+eyLinjF3WuvvcTfk0Uev5E4C64OFudBc/jbu9G4UeDLgztzOG53ig9Z -YybNpyrOVPu44sB8R85gfD+yc/LAGbaKkoc1DZAoouQVBGM+uq/ufF7MpotQsjj3 -QWPKzv9pj2gOlTblzLmMCcpL3TGQlsjMH/1WljTbjhzqLL6FLmPdqqmV0/0plRPw -yJiT2S0WR5ARg6I6IqIoV6Lr/sCMKKCmfecqQjuCgGOlYx8ZzHyyZqjC0203b+J+ -BlHZRYQfEs4kUmSFC0iAToexIiIwquuuvuAC4EDosEKAA1GqtH6qRNdDYfOiaxaJ -SaSjpCuKAsR49GiKweR6NrFvG5Ybd0mN1MkGco/PU+PcF4UgStyYJ9ORJitHHmkH -r96i5OTUawuzXnzUJIBHKWk7buis/UDr2O1xcSvy6Fgd60GXIsUf1DnQJ4+H4xj0 -4KlGDfV0OoIu0G4skaMxXDtG6nsEEFZegB31pWXogvziB4xiRfUg3kZwhqG8k9Me -dKZssCz3AwyIDMvUclOGvGBG85hqwvG/Q/lwIHfKN0F5VVJjjVsSn8VoxIidrPIw -q7ejMZdnrY8XD2zHc+0klGvIg5rQmjdJBKuxFshsSUktq6HQjJLyQUp5ISXbY9e2 -nKd+Qmn7OmMCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC -AQYwHQYDVR0OBBYEFNwuH9FhN3nkq9XVsxJxaD1qaJwiMB8GA1UdIwQYMBaAFNwu -H9FhN3nkq9XVsxJxaD1qaJwiMA0GCSqGSIb3DQEBCwUAA4ICAQCR8EICaEDuw2jA -VC/f7GLDw56KoDEoqoOOpFaWEhCGVrqXctJUMHytGdUdaG/7FELYjQ7ztdGl4wJC -XtzoRlgHNQIw4Lx0SsFDKv/bGtCwr2zD/cuz9X9tAy5ZVp0tLTWMstZDFyySCstd -6IwPS3BD0IL/qMy/pJTAvoe9iuOTe8aPmxadJ2W8esVCgmxcB9CpwYhgROmYhRZf -+I/KARDOJcP5YBugxZfD0yyIMaK9MOzQ0MAS8cE54+X1+NZK3TTN+2/BT+MAi1bi -kvcoskJ3ciNnxz8RFbLEAwW+uxF7Cr+obuf/WEPPm2eggAe2HcqtbepBEX4tdJP7 -wry+UUTF72glJ4DjyKDUEuzZpTcdN3y0kcra1LGWge9oXHYQSa9+pTeAsRxSvTOB -TI/53WXZFM2KJVj04sWDpQmQ1GwUY7VA3+vA/MRYfg0UFodUJ25W5HCEuGwyEn6C -MUO+1918oa2u1qsgEu8KwxCMSZY13At1XrFP1U80DhEgB3VDRemjEdqso5nCtnkn -4rnvyOL2NSl6dPrFf4IFYqYK6miyeUcGbvJXqBUzxvd4Sj1Ce2t+/vdG6tHrju+I -aFvowdlxfv1k7/9nR4hYJS8+hge9+6jlgqispdNpQ80xiEmEU5LAsTkbOYMBMMTy -qfrQA71yN2BWHzZ8vTmR9W0Nv3vXkg== ------END CERTIFICATE----- - -# Issuer: CN=ANF Secure Server Root CA O=ANF Autoridad de Certificacion OU=ANF CA Raiz -# Subject: CN=ANF Secure Server Root CA O=ANF Autoridad de Certificacion OU=ANF CA Raiz -# Label: "ANF Secure Server Root CA" -# Serial: 996390341000653745 -# MD5 Fingerprint: 26:a6:44:5a:d9:af:4e:2f:b2:1d:b6:65:b0:4e:e8:96 -# SHA1 Fingerprint: 5b:6e:68:d0:cc:15:b6:a0:5f:1e:c1:5f:ae:02:fc:6b:2f:5d:6f:74 -# SHA256 Fingerprint: fb:8f:ec:75:91:69:b9:10:6b:1e:51:16:44:c6:18:c5:13:04:37:3f:6c:06:43:08:8d:8b:ef:fd:1b:99:75:99 ------BEGIN CERTIFICATE----- -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 ------END CERTIFICATE----- - -# Issuer: CN=Certum EC-384 CA O=Asseco Data Systems S.A. OU=Certum Certification Authority -# Subject: CN=Certum EC-384 CA O=Asseco Data Systems S.A. OU=Certum Certification Authority -# Label: "Certum EC-384 CA" -# Serial: 160250656287871593594747141429395092468 -# MD5 Fingerprint: b6:65:b3:96:60:97:12:a1:ec:4e:e1:3d:a3:c6:c9:f1 -# SHA1 Fingerprint: f3:3e:78:3c:ac:df:f4:a2:cc:ac:67:55:69:56:d7:e5:16:3c:e1:ed -# SHA256 Fingerprint: 6b:32:80:85:62:53:18:aa:50:d1:73:c9:8d:8b:da:09:d5:7e:27:41:3d:11:4c:f7:87:a0:f5:d0:6c:03:0c:f6 ------BEGIN CERTIFICATE----- -MIICZTCCAeugAwIBAgIQeI8nXIESUiClBNAt3bpz9DAKBggqhkjOPQQDAzB0MQsw -CQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScw -JQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAXBgNVBAMT -EENlcnR1bSBFQy0zODQgQ0EwHhcNMTgwMzI2MDcyNDU0WhcNNDMwMzI2MDcyNDU0 -WjB0MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBT -LkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAX -BgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATE -KI6rGFtqvm5kN2PkzeyrOvfMobgOgknXhimfoZTy42B4mIF4Bk3y7JoOV2CDn7Tm -Fy8as10CW4kjPMIRBSqniBMY81CE1700LCeJVf/OTOffph8oxPBUw7l8t1Ot68Kj -QjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI0GZnQkdjrzife81r1HfS+8 -EF9LMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNoADBlAjADVS2m5hjEfO/J -UG7BJw+ch69u1RsIGL2SKcHvlJF40jocVYli5RsJHrpka/F2tNQCMQC0QoSZ/6vn -nvuRlydd3LBbMHHOXjgaatkl5+r3YZJW+OraNsKHZZYuciUvf9/DE8k= ------END CERTIFICATE----- - -# Issuer: CN=Certum Trusted Root CA O=Asseco Data Systems S.A. OU=Certum Certification Authority -# Subject: CN=Certum Trusted Root CA O=Asseco Data Systems S.A. OU=Certum Certification Authority -# Label: "Certum Trusted Root CA" -# Serial: 40870380103424195783807378461123655149 -# MD5 Fingerprint: 51:e1:c2:e7:fe:4c:84:af:59:0e:2f:f4:54:6f:ea:29 -# SHA1 Fingerprint: c8:83:44:c0:18:ae:9f:cc:f1:87:b7:8f:22:d1:c5:d7:45:84:ba:e5 -# SHA256 Fingerprint: fe:76:96:57:38:55:77:3e:37:a9:5e:7a:d4:d9:cc:96:c3:01:57:c1:5d:31:76:5b:a9:b1:57:04:e1:ae:78:fd ------BEGIN CERTIFICATE----- -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 ------END CERTIFICATE----- diff --git a/venv/lib/python3.8/site-packages/certifi/core.py b/venv/lib/python3.8/site-packages/certifi/core.py deleted file mode 100644 index 5d2b8cd..0000000 --- a/venv/lib/python3.8/site-packages/certifi/core.py +++ /dev/null @@ -1,60 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -certifi.py -~~~~~~~~~~ - -This module returns the installation location of cacert.pem or its contents. -""" -import os - -try: - from importlib.resources import path as get_path, read_text - - _CACERT_CTX = None - _CACERT_PATH = None - - def where(): - # This is slightly terrible, but we want to delay extracting the file - # in cases where we're inside of a zipimport situation until someone - # actually calls where(), but we don't want to re-extract the file - # on every call of where(), so we'll do it once then store it in a - # global variable. - global _CACERT_CTX - global _CACERT_PATH - if _CACERT_PATH is None: - # This is slightly janky, the importlib.resources API wants you to - # manage the cleanup of this file, so it doesn't actually return a - # path, it returns a context manager that will give you the path - # when you enter it and will do any cleanup when you leave it. In - # the common case of not needing a temporary file, it will just - # return the file system location and the __exit__() is a no-op. - # - # We also have to hold onto the actual context manager, because - # it will do the cleanup whenever it gets garbage collected, so - # we will also store that at the global level as well. - _CACERT_CTX = get_path("certifi", "cacert.pem") - _CACERT_PATH = str(_CACERT_CTX.__enter__()) - - return _CACERT_PATH - - -except ImportError: - # This fallback will work for Python versions prior to 3.7 that lack the - # importlib.resources module but relies on the existing `where` function - # so won't address issues with environments like PyOxidizer that don't set - # __file__ on modules. - def read_text(_module, _path, encoding="ascii"): - with open(where(), "r", encoding=encoding) as data: - return data.read() - - # If we don't have importlib.resources, then we will just do the old logic - # of assuming we're on the filesystem and munge the path directly. - def where(): - f = os.path.dirname(__file__) - - return os.path.join(f, "cacert.pem") - - -def contents(): - return read_text("certifi", "cacert.pem", encoding="ascii") diff --git a/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/INSTALLER b/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/LICENSE b/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/LICENSE deleted file mode 100644 index 8add30a..0000000 --- a/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/LICENSE +++ /dev/null @@ -1,504 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - <one line to give the library's name and a brief idea of what it does.> - Copyright (C) <year> <name of author> - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random Hacker. - - <signature of Ty Coon>, 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - diff --git a/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/METADATA b/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/METADATA deleted file mode 100644 index 590bcc3..0000000 --- a/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/METADATA +++ /dev/null @@ -1,101 +0,0 @@ -Metadata-Version: 2.1 -Name: chardet -Version: 4.0.0 -Summary: Universal encoding detector for Python 2 and 3 -Home-page: https://github.com/chardet/chardet -Author: Mark Pilgrim -Author-email: mark@diveintomark.org -Maintainer: Daniel Blanchard -Maintainer-email: dan.blanchard@gmail.com -License: LGPL -Keywords: encoding,i18n,xml -Platform: UNKNOWN -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: GNU Library or Lesser General Public License (LGPL) -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.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 -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Classifier: Topic :: Text Processing :: Linguistic -Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.* - -Chardet: The Universal Character Encoding Detector --------------------------------------------------- - -.. image:: https://img.shields.io/travis/chardet/chardet/stable.svg - :alt: Build status - :target: https://travis-ci.org/chardet/chardet - -.. image:: https://img.shields.io/coveralls/chardet/chardet/stable.svg - :target: https://coveralls.io/r/chardet/chardet - -.. image:: https://img.shields.io/pypi/v/chardet.svg - :target: https://warehouse.python.org/project/chardet/ - :alt: Latest version on PyPI - -.. image:: https://img.shields.io/pypi/l/chardet.svg - :alt: License - - -Detects - - ASCII, UTF-8, UTF-16 (2 variants), UTF-32 (4 variants) - - Big5, GB2312, EUC-TW, HZ-GB-2312, ISO-2022-CN (Traditional and Simplified Chinese) - - EUC-JP, SHIFT_JIS, CP932, ISO-2022-JP (Japanese) - - EUC-KR, ISO-2022-KR (Korean) - - KOI8-R, MacCyrillic, IBM855, IBM866, ISO-8859-5, windows-1251 (Cyrillic) - - ISO-8859-5, windows-1251 (Bulgarian) - - ISO-8859-1, windows-1252 (Western European languages) - - ISO-8859-7, windows-1253 (Greek) - - ISO-8859-8, windows-1255 (Visual and Logical Hebrew) - - TIS-620 (Thai) - -.. note:: - Our ISO-8859-2 and windows-1250 (Hungarian) probers have been temporarily - disabled until we can retrain the models. - -Requires Python 2.7 or 3.5+. - -Installation ------------- - -Install from `PyPI <https://pypi.org/project/chardet/>`_:: - - pip install chardet - -Documentation -------------- - -For users, docs are now available at https://chardet.readthedocs.io/. - -Command-line Tool ------------------ - -chardet comes with a command-line script which reports on the encodings of one -or more files:: - - % chardetect somefile someotherfile - somefile: windows-1252 with confidence 0.5 - someotherfile: ascii with confidence 1.0 - -About ------ - -This is a continuation of Mark Pilgrim's excellent chardet. Previously, two -versions needed to be maintained: one that supported python 2.x and one that -supported python 3.x. We've recently merged with `Ian Cordasco <https://github.com/sigmavirus24>`_'s -`charade <https://github.com/sigmavirus24/charade>`_ fork, so now we have one -coherent version that works for Python 2.7+ and 3.4+. - -:maintainer: Dan Blanchard - - diff --git a/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/RECORD b/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/RECORD deleted file mode 100644 index 4c99f45..0000000 --- a/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/RECORD +++ /dev/null @@ -1,94 +0,0 @@ -../../../bin/chardetect,sha256=iZ9vjG7hdTs6_ydzR-AuZRrpNSZn1GEHJdPYHbCr98k,256 -chardet-4.0.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -chardet-4.0.0.dist-info/LICENSE,sha256=YJXp_6d33SKDn3gBqoRbMcntB_PWv4om3F0t7IzMDvM,26432 -chardet-4.0.0.dist-info/METADATA,sha256=ySYQAE7NPm3LwxgMqFi1zdLQ48mmwMbrJwqAWCtcbH8,3526 -chardet-4.0.0.dist-info/RECORD,, -chardet-4.0.0.dist-info/WHEEL,sha256=ADKeyaGyKF5DwBNE0sRE5pvW-bSkFMJfBuhzZ3rceP4,110 -chardet-4.0.0.dist-info/entry_points.txt,sha256=fAMmhu5eJ-zAJ-smfqQwRClQ3-nozOCmvJ6-E8lgGJo,60 -chardet-4.0.0.dist-info/top_level.txt,sha256=AowzBbZy4x8EirABDdJSLJZMkJ_53iIag8xfKR6D7kI,8 -chardet/__init__.py,sha256=mWZaWmvZkhwfBEAT9O1Y6nRTfKzhT7FHhQTTAujbqUA,3271 -chardet/__pycache__/__init__.cpython-38.pyc,, -chardet/__pycache__/big5freq.cpython-38.pyc,, -chardet/__pycache__/big5prober.cpython-38.pyc,, -chardet/__pycache__/chardistribution.cpython-38.pyc,, -chardet/__pycache__/charsetgroupprober.cpython-38.pyc,, -chardet/__pycache__/charsetprober.cpython-38.pyc,, -chardet/__pycache__/codingstatemachine.cpython-38.pyc,, -chardet/__pycache__/compat.cpython-38.pyc,, -chardet/__pycache__/cp949prober.cpython-38.pyc,, -chardet/__pycache__/enums.cpython-38.pyc,, -chardet/__pycache__/escprober.cpython-38.pyc,, -chardet/__pycache__/escsm.cpython-38.pyc,, -chardet/__pycache__/eucjpprober.cpython-38.pyc,, -chardet/__pycache__/euckrfreq.cpython-38.pyc,, -chardet/__pycache__/euckrprober.cpython-38.pyc,, -chardet/__pycache__/euctwfreq.cpython-38.pyc,, -chardet/__pycache__/euctwprober.cpython-38.pyc,, -chardet/__pycache__/gb2312freq.cpython-38.pyc,, -chardet/__pycache__/gb2312prober.cpython-38.pyc,, -chardet/__pycache__/hebrewprober.cpython-38.pyc,, -chardet/__pycache__/jisfreq.cpython-38.pyc,, -chardet/__pycache__/jpcntx.cpython-38.pyc,, -chardet/__pycache__/langbulgarianmodel.cpython-38.pyc,, -chardet/__pycache__/langgreekmodel.cpython-38.pyc,, -chardet/__pycache__/langhebrewmodel.cpython-38.pyc,, -chardet/__pycache__/langhungarianmodel.cpython-38.pyc,, -chardet/__pycache__/langrussianmodel.cpython-38.pyc,, -chardet/__pycache__/langthaimodel.cpython-38.pyc,, -chardet/__pycache__/langturkishmodel.cpython-38.pyc,, -chardet/__pycache__/latin1prober.cpython-38.pyc,, -chardet/__pycache__/mbcharsetprober.cpython-38.pyc,, -chardet/__pycache__/mbcsgroupprober.cpython-38.pyc,, -chardet/__pycache__/mbcssm.cpython-38.pyc,, -chardet/__pycache__/sbcharsetprober.cpython-38.pyc,, -chardet/__pycache__/sbcsgroupprober.cpython-38.pyc,, -chardet/__pycache__/sjisprober.cpython-38.pyc,, -chardet/__pycache__/universaldetector.cpython-38.pyc,, -chardet/__pycache__/utf8prober.cpython-38.pyc,, -chardet/__pycache__/version.cpython-38.pyc,, -chardet/big5freq.py,sha256=D_zK5GyzoVsRes0HkLJziltFQX0bKCLOrFe9_xDvO_8,31254 -chardet/big5prober.py,sha256=kBxHbdetBpPe7xrlb-e990iot64g_eGSLd32lB7_h3M,1757 -chardet/chardistribution.py,sha256=3woWS62KrGooKyqz4zQSnjFbJpa6V7g02daAibTwcl8,9411 -chardet/charsetgroupprober.py,sha256=GZLReHP6FRRn43hvSOoGCxYamErKzyp6RgOQxVeC3kg,3839 -chardet/charsetprober.py,sha256=KSmwJErjypyj0bRZmC5F5eM7c8YQgLYIjZXintZNstg,5110 -chardet/cli/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1 -chardet/cli/__pycache__/__init__.cpython-38.pyc,, -chardet/cli/__pycache__/chardetect.cpython-38.pyc,, -chardet/cli/chardetect.py,sha256=kUPeQCi-olObXpOq5MtlKuBn1EU19rkeenAMwxl7URY,2711 -chardet/codingstatemachine.py,sha256=VYp_6cyyki5sHgXDSZnXW4q1oelHc3cu9AyQTX7uug8,3590 -chardet/compat.py,sha256=40zr6wICZwknxyuLGGcIOPyve8DTebBCbbvttvnmp5Q,1200 -chardet/cp949prober.py,sha256=TZ434QX8zzBsnUvL_8wm4AQVTZ2ZkqEEQL_lNw9f9ow,1855 -chardet/enums.py,sha256=Aimwdb9as1dJKZaFNUH2OhWIVBVd6ZkJJ_WK5sNY8cU,1661 -chardet/escprober.py,sha256=kkyqVg1Yw3DIOAMJ2bdlyQgUFQhuHAW8dUGskToNWSc,3950 -chardet/escsm.py,sha256=RuXlgNvTIDarndvllNCk5WZBIpdCxQ0kcd9EAuxUh84,10510 -chardet/eucjpprober.py,sha256=iD8Jdp0ISRjgjiVN7f0e8xGeQJ5GM2oeZ1dA8nbSeUw,3749 -chardet/euckrfreq.py,sha256=-7GdmvgWez4-eO4SuXpa7tBiDi5vRXQ8WvdFAzVaSfo,13546 -chardet/euckrprober.py,sha256=MqFMTQXxW4HbzIpZ9lKDHB3GN8SP4yiHenTmf8g_PxY,1748 -chardet/euctwfreq.py,sha256=No1WyduFOgB5VITUA7PLyC5oJRNzRyMbBxaKI1l16MA,31621 -chardet/euctwprober.py,sha256=13p6EP4yRaxqnP4iHtxHOJ6R2zxHq1_m8hTRjzVZ95c,1747 -chardet/gb2312freq.py,sha256=JX8lsweKLmnCwmk8UHEQsLgkr_rP_kEbvivC4qPOrlc,20715 -chardet/gb2312prober.py,sha256=gGvIWi9WhDjE-xQXHvNIyrnLvEbMAYgyUSZ65HUfylw,1754 -chardet/hebrewprober.py,sha256=c3SZ-K7hvyzGY6JRAZxJgwJ_sUS9k0WYkvMY00YBYFo,13838 -chardet/jisfreq.py,sha256=vpmJv2Bu0J8gnMVRPHMFefTRvo_ha1mryLig8CBwgOg,25777 -chardet/jpcntx.py,sha256=PYlNqRUQT8LM3cT5FmHGP0iiscFlTWED92MALvBungo,19643 -chardet/langbulgarianmodel.py,sha256=r6tvOtO8FqhnbWBB5V4czcl1fWM4pB9lGiWQU-8gvsw,105685 -chardet/langgreekmodel.py,sha256=1cMu2wUgPB8bQ2RbVjR4LNwCCETgQ-Dwo0Eg2_uB11s,99559 -chardet/langhebrewmodel.py,sha256=urMmJHHIXtCwaWAqy1zEY_4SmwwNzt730bDOtjXzRjs,98764 -chardet/langhungarianmodel.py,sha256=ODAisvqCfes8B4FeyM_Pg9HY3ZDnEyaCiT4Bxyzoc6w,102486 -chardet/langrussianmodel.py,sha256=sPqkrBbX0QVwwy6oqRl-x7ERv2J4-zaMoCvLpkSsSJI,131168 -chardet/langthaimodel.py,sha256=ppoKOGL9OPdj9A4CUyG8R48zbnXt9MN1WXeCYepa6sc,103300 -chardet/langturkishmodel.py,sha256=H3ldicI_rhlv0r3VFpVWtUL6X30Wy596v7_YHz2sEdg,95934 -chardet/latin1prober.py,sha256=S2IoORhFk39FEFOlSFWtgVybRiP6h7BlLldHVclNkU8,5370 -chardet/mbcharsetprober.py,sha256=AR95eFH9vuqSfvLQZN-L5ijea25NOBCoXqw8s5O9xLQ,3413 -chardet/mbcsgroupprober.py,sha256=h6TRnnYq2OxG1WdD5JOyxcdVpn7dG0q-vB8nWr5mbh4,2012 -chardet/mbcssm.py,sha256=SY32wVIF3HzcjY3BaEspy9metbNSKxIIB0RKPn7tjpI,25481 -chardet/metadata/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -chardet/metadata/__pycache__/__init__.cpython-38.pyc,, -chardet/metadata/__pycache__/languages.cpython-38.pyc,, -chardet/metadata/languages.py,sha256=41tLq3eLSrBEbEVVQpVGFq9K7o1ln9b1HpY1l0hCUQo,19474 -chardet/sbcharsetprober.py,sha256=nmyMyuxzG87DN6K3Rk2MUzJLMLR69MrWpdnHzOwVUwQ,6136 -chardet/sbcsgroupprober.py,sha256=hqefQuXmiFyDBArOjujH6hd6WFXlOD1kWCsxDhjx5Vc,4309 -chardet/sjisprober.py,sha256=IIt-lZj0WJqK4rmUZzKZP4GJlE8KUEtFYVuY96ek5MQ,3774 -chardet/universaldetector.py,sha256=DpZTXCX0nUHXxkQ9sr4GZxGB_hveZ6hWt3uM94cgWKs,12503 -chardet/utf8prober.py,sha256=IdD8v3zWOsB8OLiyPi-y_fqwipRFxV9Nc1eKBLSuIEw,2766 -chardet/version.py,sha256=A4CILFAd8MRVG1HoXPp45iK9RLlWyV73a1EtwE8Tvn8,242 diff --git a/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/WHEEL b/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/WHEEL deleted file mode 100644 index 6d38aa0..0000000 --- a/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/WHEEL +++ /dev/null @@ -1,6 +0,0 @@ -Wheel-Version: 1.0 -Generator: bdist_wheel (0.35.1) -Root-Is-Purelib: true -Tag: py2-none-any -Tag: py3-none-any - diff --git a/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/entry_points.txt b/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/entry_points.txt deleted file mode 100644 index a884269..0000000 --- a/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/entry_points.txt +++ /dev/null @@ -1,3 +0,0 @@ -[console_scripts] -chardetect = chardet.cli.chardetect:main - diff --git a/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/top_level.txt b/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/top_level.txt deleted file mode 100644 index 79236f2..0000000 --- a/venv/lib/python3.8/site-packages/chardet-4.0.0.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -chardet diff --git a/venv/lib/python3.8/site-packages/chardet/__init__.py b/venv/lib/python3.8/site-packages/chardet/__init__.py deleted file mode 100644 index 80ad254..0000000 --- a/venv/lib/python3.8/site-packages/chardet/__init__.py +++ /dev/null @@ -1,83 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - - -from .universaldetector import UniversalDetector -from .enums import InputState -from .version import __version__, VERSION - - -__all__ = ['UniversalDetector', 'detect', 'detect_all', '__version__', 'VERSION'] - - -def detect(byte_str): - """ - Detect the encoding of the given byte string. - - :param byte_str: The byte sequence to examine. - :type byte_str: ``bytes`` or ``bytearray`` - """ - if not isinstance(byte_str, bytearray): - if not isinstance(byte_str, bytes): - raise TypeError('Expected object of type bytes or bytearray, got: ' - '{}'.format(type(byte_str))) - else: - byte_str = bytearray(byte_str) - detector = UniversalDetector() - detector.feed(byte_str) - return detector.close() - - -def detect_all(byte_str): - """ - Detect all the possible encodings of the given byte string. - - :param byte_str: The byte sequence to examine. - :type byte_str: ``bytes`` or ``bytearray`` - """ - if not isinstance(byte_str, bytearray): - if not isinstance(byte_str, bytes): - raise TypeError('Expected object of type bytes or bytearray, got: ' - '{}'.format(type(byte_str))) - else: - byte_str = bytearray(byte_str) - - detector = UniversalDetector() - detector.feed(byte_str) - detector.close() - - if detector._input_state == InputState.HIGH_BYTE: - results = [] - for prober in detector._charset_probers: - if prober.get_confidence() > detector.MINIMUM_THRESHOLD: - charset_name = prober.charset_name - lower_charset_name = prober.charset_name.lower() - # Use Windows encoding name instead of ISO-8859 if we saw any - # extra Windows-specific bytes - if lower_charset_name.startswith('iso-8859'): - if detector._has_win_bytes: - charset_name = detector.ISO_WIN_MAP.get(lower_charset_name, - charset_name) - results.append({ - 'encoding': charset_name, - 'confidence': prober.get_confidence(), - 'language': prober.language, - }) - if len(results) > 0: - return sorted(results, key=lambda result: -result['confidence']) - - return [detector.result] diff --git a/venv/lib/python3.8/site-packages/chardet/big5freq.py b/venv/lib/python3.8/site-packages/chardet/big5freq.py deleted file mode 100644 index 38f3251..0000000 --- a/venv/lib/python3.8/site-packages/chardet/big5freq.py +++ /dev/null @@ -1,386 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is Mozilla Communicator client code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -# Big5 frequency table -# by Taiwan's Mandarin Promotion Council -# <http://www.edu.tw:81/mandr/> -# -# 128 --> 0.42261 -# 256 --> 0.57851 -# 512 --> 0.74851 -# 1024 --> 0.89384 -# 2048 --> 0.97583 -# -# Ideal Distribution Ratio = 0.74851/(1-0.74851) =2.98 -# Random Distribution Ration = 512/(5401-512)=0.105 -# -# Typical Distribution Ratio about 25% of Ideal one, still much higher than RDR - -BIG5_TYPICAL_DISTRIBUTION_RATIO = 0.75 - -#Char to FreqOrder table -BIG5_TABLE_SIZE = 5376 - -BIG5_CHAR_TO_FREQ_ORDER = ( - 1,1801,1506, 255,1431, 198, 9, 82, 6,5008, 177, 202,3681,1256,2821, 110, # 16 -3814, 33,3274, 261, 76, 44,2114, 16,2946,2187,1176, 659,3971, 26,3451,2653, # 32 -1198,3972,3350,4202, 410,2215, 302, 590, 361,1964, 8, 204, 58,4510,5009,1932, # 48 - 63,5010,5011, 317,1614, 75, 222, 159,4203,2417,1480,5012,3555,3091, 224,2822, # 64 -3682, 3, 10,3973,1471, 29,2787,1135,2866,1940, 873, 130,3275,1123, 312,5013, # 80 -4511,2052, 507, 252, 682,5014, 142,1915, 124, 206,2947, 34,3556,3204, 64, 604, # 96 -5015,2501,1977,1978, 155,1991, 645, 641,1606,5016,3452, 337, 72, 406,5017, 80, # 112 - 630, 238,3205,1509, 263, 939,1092,2654, 756,1440,1094,3453, 449, 69,2987, 591, # 128 - 179,2096, 471, 115,2035,1844, 60, 50,2988, 134, 806,1869, 734,2036,3454, 180, # 144 - 995,1607, 156, 537,2907, 688,5018, 319,1305, 779,2145, 514,2379, 298,4512, 359, # 160 -2502, 90,2716,1338, 663, 11, 906,1099,2553, 20,2441, 182, 532,1716,5019, 732, # 176 -1376,4204,1311,1420,3206, 25,2317,1056, 113, 399, 382,1950, 242,3455,2474, 529, # 192 -3276, 475,1447,3683,5020, 117, 21, 656, 810,1297,2300,2334,3557,5021, 126,4205, # 208 - 706, 456, 150, 613,4513, 71,1118,2037,4206, 145,3092, 85, 835, 486,2115,1246, # 224 -1426, 428, 727,1285,1015, 800, 106, 623, 303,1281,5022,2128,2359, 347,3815, 221, # 240 -3558,3135,5023,1956,1153,4207, 83, 296,1199,3093, 192, 624, 93,5024, 822,1898, # 256 -2823,3136, 795,2065, 991,1554,1542,1592, 27, 43,2867, 859, 139,1456, 860,4514, # 272 - 437, 712,3974, 164,2397,3137, 695, 211,3037,2097, 195,3975,1608,3559,3560,3684, # 288 -3976, 234, 811,2989,2098,3977,2233,1441,3561,1615,2380, 668,2077,1638, 305, 228, # 304 -1664,4515, 467, 415,5025, 262,2099,1593, 239, 108, 300, 200,1033, 512,1247,2078, # 320 -5026,5027,2176,3207,3685,2682, 593, 845,1062,3277, 88,1723,2038,3978,1951, 212, # 336 - 266, 152, 149, 468,1899,4208,4516, 77, 187,5028,3038, 37, 5,2990,5029,3979, # 352 -5030,5031, 39,2524,4517,2908,3208,2079, 55, 148, 74,4518, 545, 483,1474,1029, # 368 -1665, 217,1870,1531,3138,1104,2655,4209, 24, 172,3562, 900,3980,3563,3564,4519, # 384 - 32,1408,2824,1312, 329, 487,2360,2251,2717, 784,2683, 4,3039,3351,1427,1789, # 400 - 188, 109, 499,5032,3686,1717,1790, 888,1217,3040,4520,5033,3565,5034,3352,1520, # 416 -3687,3981, 196,1034, 775,5035,5036, 929,1816, 249, 439, 38,5037,1063,5038, 794, # 432 -3982,1435,2301, 46, 178,3278,2066,5039,2381,5040, 214,1709,4521, 804, 35, 707, # 448 - 324,3688,1601,2554, 140, 459,4210,5041,5042,1365, 839, 272, 978,2262,2580,3456, # 464 -2129,1363,3689,1423, 697, 100,3094, 48, 70,1231, 495,3139,2196,5043,1294,5044, # 480 -2080, 462, 586,1042,3279, 853, 256, 988, 185,2382,3457,1698, 434,1084,5045,3458, # 496 - 314,2625,2788,4522,2335,2336, 569,2285, 637,1817,2525, 757,1162,1879,1616,3459, # 512 - 287,1577,2116, 768,4523,1671,2868,3566,2526,1321,3816, 909,2418,5046,4211, 933, # 528 -3817,4212,2053,2361,1222,4524, 765,2419,1322, 786,4525,5047,1920,1462,1677,2909, # 544 -1699,5048,4526,1424,2442,3140,3690,2600,3353,1775,1941,3460,3983,4213, 309,1369, # 560 -1130,2825, 364,2234,1653,1299,3984,3567,3985,3986,2656, 525,1085,3041, 902,2001, # 576 -1475, 964,4527, 421,1845,1415,1057,2286, 940,1364,3141, 376,4528,4529,1381, 7, # 592 -2527, 983,2383, 336,1710,2684,1846, 321,3461, 559,1131,3042,2752,1809,1132,1313, # 608 - 265,1481,1858,5049, 352,1203,2826,3280, 167,1089, 420,2827, 776, 792,1724,3568, # 624 -4214,2443,3281,5050,4215,5051, 446, 229, 333,2753, 901,3818,1200,1557,4530,2657, # 640 -1921, 395,2754,2685,3819,4216,1836, 125, 916,3209,2626,4531,5052,5053,3820,5054, # 656 -5055,5056,4532,3142,3691,1133,2555,1757,3462,1510,2318,1409,3569,5057,2146, 438, # 672 -2601,2910,2384,3354,1068, 958,3043, 461, 311,2869,2686,4217,1916,3210,4218,1979, # 688 - 383, 750,2755,2627,4219, 274, 539, 385,1278,1442,5058,1154,1965, 384, 561, 210, # 704 - 98,1295,2556,3570,5059,1711,2420,1482,3463,3987,2911,1257, 129,5060,3821, 642, # 720 - 523,2789,2790,2658,5061, 141,2235,1333, 68, 176, 441, 876, 907,4220, 603,2602, # 736 - 710, 171,3464, 404, 549, 18,3143,2398,1410,3692,1666,5062,3571,4533,2912,4534, # 752 -5063,2991, 368,5064, 146, 366, 99, 871,3693,1543, 748, 807,1586,1185, 22,2263, # 768 - 379,3822,3211,5065,3212, 505,1942,2628,1992,1382,2319,5066, 380,2362, 218, 702, # 784 -1818,1248,3465,3044,3572,3355,3282,5067,2992,3694, 930,3283,3823,5068, 59,5069, # 800 - 585, 601,4221, 497,3466,1112,1314,4535,1802,5070,1223,1472,2177,5071, 749,1837, # 816 - 690,1900,3824,1773,3988,1476, 429,1043,1791,2236,2117, 917,4222, 447,1086,1629, # 832 -5072, 556,5073,5074,2021,1654, 844,1090, 105, 550, 966,1758,2828,1008,1783, 686, # 848 -1095,5075,2287, 793,1602,5076,3573,2603,4536,4223,2948,2302,4537,3825, 980,2503, # 864 - 544, 353, 527,4538, 908,2687,2913,5077, 381,2629,1943,1348,5078,1341,1252, 560, # 880 -3095,5079,3467,2870,5080,2054, 973, 886,2081, 143,4539,5081,5082, 157,3989, 496, # 896 -4224, 57, 840, 540,2039,4540,4541,3468,2118,1445, 970,2264,1748,1966,2082,4225, # 912 -3144,1234,1776,3284,2829,3695, 773,1206,2130,1066,2040,1326,3990,1738,1725,4226, # 928 - 279,3145, 51,1544,2604, 423,1578,2131,2067, 173,4542,1880,5083,5084,1583, 264, # 944 - 610,3696,4543,2444, 280, 154,5085,5086,5087,1739, 338,1282,3096, 693,2871,1411, # 960 -1074,3826,2445,5088,4544,5089,5090,1240, 952,2399,5091,2914,1538,2688, 685,1483, # 976 -4227,2475,1436, 953,4228,2055,4545, 671,2400, 79,4229,2446,3285, 608, 567,2689, # 992 -3469,4230,4231,1691, 393,1261,1792,2401,5092,4546,5093,5094,5095,5096,1383,1672, # 1008 -3827,3213,1464, 522,1119, 661,1150, 216, 675,4547,3991,1432,3574, 609,4548,2690, # 1024 -2402,5097,5098,5099,4232,3045, 0,5100,2476, 315, 231,2447, 301,3356,4549,2385, # 1040 -5101, 233,4233,3697,1819,4550,4551,5102, 96,1777,1315,2083,5103, 257,5104,1810, # 1056 -3698,2718,1139,1820,4234,2022,1124,2164,2791,1778,2659,5105,3097, 363,1655,3214, # 1072 -5106,2993,5107,5108,5109,3992,1567,3993, 718, 103,3215, 849,1443, 341,3357,2949, # 1088 -1484,5110,1712, 127, 67, 339,4235,2403, 679,1412, 821,5111,5112, 834, 738, 351, # 1104 -2994,2147, 846, 235,1497,1881, 418,1993,3828,2719, 186,1100,2148,2756,3575,1545, # 1120 -1355,2950,2872,1377, 583,3994,4236,2581,2995,5113,1298,3699,1078,2557,3700,2363, # 1136 - 78,3829,3830, 267,1289,2100,2002,1594,4237, 348, 369,1274,2197,2178,1838,4552, # 1152 -1821,2830,3701,2757,2288,2003,4553,2951,2758, 144,3358, 882,4554,3995,2759,3470, # 1168 -4555,2915,5114,4238,1726, 320,5115,3996,3046, 788,2996,5116,2831,1774,1327,2873, # 1184 -3997,2832,5117,1306,4556,2004,1700,3831,3576,2364,2660, 787,2023, 506, 824,3702, # 1200 - 534, 323,4557,1044,3359,2024,1901, 946,3471,5118,1779,1500,1678,5119,1882,4558, # 1216 - 165, 243,4559,3703,2528, 123, 683,4239, 764,4560, 36,3998,1793, 589,2916, 816, # 1232 - 626,1667,3047,2237,1639,1555,1622,3832,3999,5120,4000,2874,1370,1228,1933, 891, # 1248 -2084,2917, 304,4240,5121, 292,2997,2720,3577, 691,2101,4241,1115,4561, 118, 662, # 1264 -5122, 611,1156, 854,2386,1316,2875, 2, 386, 515,2918,5123,5124,3286, 868,2238, # 1280 -1486, 855,2661, 785,2216,3048,5125,1040,3216,3578,5126,3146, 448,5127,1525,5128, # 1296 -2165,4562,5129,3833,5130,4242,2833,3579,3147, 503, 818,4001,3148,1568, 814, 676, # 1312 -1444, 306,1749,5131,3834,1416,1030, 197,1428, 805,2834,1501,4563,5132,5133,5134, # 1328 -1994,5135,4564,5136,5137,2198, 13,2792,3704,2998,3149,1229,1917,5138,3835,2132, # 1344 -5139,4243,4565,2404,3580,5140,2217,1511,1727,1120,5141,5142, 646,3836,2448, 307, # 1360 -5143,5144,1595,3217,5145,5146,5147,3705,1113,1356,4002,1465,2529,2530,5148, 519, # 1376 -5149, 128,2133, 92,2289,1980,5150,4003,1512, 342,3150,2199,5151,2793,2218,1981, # 1392 -3360,4244, 290,1656,1317, 789, 827,2365,5152,3837,4566, 562, 581,4004,5153, 401, # 1408 -4567,2252, 94,4568,5154,1399,2794,5155,1463,2025,4569,3218,1944,5156, 828,1105, # 1424 -4245,1262,1394,5157,4246, 605,4570,5158,1784,2876,5159,2835, 819,2102, 578,2200, # 1440 -2952,5160,1502, 436,3287,4247,3288,2836,4005,2919,3472,3473,5161,2721,2320,5162, # 1456 -5163,2337,2068, 23,4571, 193, 826,3838,2103, 699,1630,4248,3098, 390,1794,1064, # 1472 -3581,5164,1579,3099,3100,1400,5165,4249,1839,1640,2877,5166,4572,4573, 137,4250, # 1488 - 598,3101,1967, 780, 104, 974,2953,5167, 278, 899, 253, 402, 572, 504, 493,1339, # 1504 -5168,4006,1275,4574,2582,2558,5169,3706,3049,3102,2253, 565,1334,2722, 863, 41, # 1520 -5170,5171,4575,5172,1657,2338, 19, 463,2760,4251, 606,5173,2999,3289,1087,2085, # 1536 -1323,2662,3000,5174,1631,1623,1750,4252,2691,5175,2878, 791,2723,2663,2339, 232, # 1552 -2421,5176,3001,1498,5177,2664,2630, 755,1366,3707,3290,3151,2026,1609, 119,1918, # 1568 -3474, 862,1026,4253,5178,4007,3839,4576,4008,4577,2265,1952,2477,5179,1125, 817, # 1584 -4254,4255,4009,1513,1766,2041,1487,4256,3050,3291,2837,3840,3152,5180,5181,1507, # 1600 -5182,2692, 733, 40,1632,1106,2879, 345,4257, 841,2531, 230,4578,3002,1847,3292, # 1616 -3475,5183,1263, 986,3476,5184, 735, 879, 254,1137, 857, 622,1300,1180,1388,1562, # 1632 -4010,4011,2954, 967,2761,2665,1349, 592,2134,1692,3361,3003,1995,4258,1679,4012, # 1648 -1902,2188,5185, 739,3708,2724,1296,1290,5186,4259,2201,2202,1922,1563,2605,2559, # 1664 -1871,2762,3004,5187, 435,5188, 343,1108, 596, 17,1751,4579,2239,3477,3709,5189, # 1680 -4580, 294,3582,2955,1693, 477, 979, 281,2042,3583, 643,2043,3710,2631,2795,2266, # 1696 -1031,2340,2135,2303,3584,4581, 367,1249,2560,5190,3585,5191,4582,1283,3362,2005, # 1712 - 240,1762,3363,4583,4584, 836,1069,3153, 474,5192,2149,2532, 268,3586,5193,3219, # 1728 -1521,1284,5194,1658,1546,4260,5195,3587,3588,5196,4261,3364,2693,1685,4262, 961, # 1744 -1673,2632, 190,2006,2203,3841,4585,4586,5197, 570,2504,3711,1490,5198,4587,2633, # 1760 -3293,1957,4588, 584,1514, 396,1045,1945,5199,4589,1968,2449,5200,5201,4590,4013, # 1776 - 619,5202,3154,3294, 215,2007,2796,2561,3220,4591,3221,4592, 763,4263,3842,4593, # 1792 -5203,5204,1958,1767,2956,3365,3712,1174, 452,1477,4594,3366,3155,5205,2838,1253, # 1808 -2387,2189,1091,2290,4264, 492,5206, 638,1169,1825,2136,1752,4014, 648, 926,1021, # 1824 -1324,4595, 520,4596, 997, 847,1007, 892,4597,3843,2267,1872,3713,2405,1785,4598, # 1840 -1953,2957,3103,3222,1728,4265,2044,3714,4599,2008,1701,3156,1551, 30,2268,4266, # 1856 -5207,2027,4600,3589,5208, 501,5209,4267, 594,3478,2166,1822,3590,3479,3591,3223, # 1872 - 829,2839,4268,5210,1680,3157,1225,4269,5211,3295,4601,4270,3158,2341,5212,4602, # 1888 -4271,5213,4015,4016,5214,1848,2388,2606,3367,5215,4603, 374,4017, 652,4272,4273, # 1904 - 375,1140, 798,5216,5217,5218,2366,4604,2269, 546,1659, 138,3051,2450,4605,5219, # 1920 -2254, 612,1849, 910, 796,3844,1740,1371, 825,3845,3846,5220,2920,2562,5221, 692, # 1936 - 444,3052,2634, 801,4606,4274,5222,1491, 244,1053,3053,4275,4276, 340,5223,4018, # 1952 -1041,3005, 293,1168, 87,1357,5224,1539, 959,5225,2240, 721, 694,4277,3847, 219, # 1968 -1478, 644,1417,3368,2666,1413,1401,1335,1389,4019,5226,5227,3006,2367,3159,1826, # 1984 - 730,1515, 184,2840, 66,4607,5228,1660,2958, 246,3369, 378,1457, 226,3480, 975, # 2000 -4020,2959,1264,3592, 674, 696,5229, 163,5230,1141,2422,2167, 713,3593,3370,4608, # 2016 -4021,5231,5232,1186, 15,5233,1079,1070,5234,1522,3224,3594, 276,1050,2725, 758, # 2032 -1126, 653,2960,3296,5235,2342, 889,3595,4022,3104,3007, 903,1250,4609,4023,3481, # 2048 -3596,1342,1681,1718, 766,3297, 286, 89,2961,3715,5236,1713,5237,2607,3371,3008, # 2064 -5238,2962,2219,3225,2880,5239,4610,2505,2533, 181, 387,1075,4024, 731,2190,3372, # 2080 -5240,3298, 310, 313,3482,2304, 770,4278, 54,3054, 189,4611,3105,3848,4025,5241, # 2096 -1230,1617,1850, 355,3597,4279,4612,3373, 111,4280,3716,1350,3160,3483,3055,4281, # 2112 -2150,3299,3598,5242,2797,4026,4027,3009, 722,2009,5243,1071, 247,1207,2343,2478, # 2128 -1378,4613,2010, 864,1437,1214,4614, 373,3849,1142,2220, 667,4615, 442,2763,2563, # 2144 -3850,4028,1969,4282,3300,1840, 837, 170,1107, 934,1336,1883,5244,5245,2119,4283, # 2160 -2841, 743,1569,5246,4616,4284, 582,2389,1418,3484,5247,1803,5248, 357,1395,1729, # 2176 -3717,3301,2423,1564,2241,5249,3106,3851,1633,4617,1114,2086,4285,1532,5250, 482, # 2192 -2451,4618,5251,5252,1492, 833,1466,5253,2726,3599,1641,2842,5254,1526,1272,3718, # 2208 -4286,1686,1795, 416,2564,1903,1954,1804,5255,3852,2798,3853,1159,2321,5256,2881, # 2224 -4619,1610,1584,3056,2424,2764, 443,3302,1163,3161,5257,5258,4029,5259,4287,2506, # 2240 -3057,4620,4030,3162,2104,1647,3600,2011,1873,4288,5260,4289, 431,3485,5261, 250, # 2256 - 97, 81,4290,5262,1648,1851,1558, 160, 848,5263, 866, 740,1694,5264,2204,2843, # 2272 -3226,4291,4621,3719,1687, 950,2479, 426, 469,3227,3720,3721,4031,5265,5266,1188, # 2288 - 424,1996, 861,3601,4292,3854,2205,2694, 168,1235,3602,4293,5267,2087,1674,4622, # 2304 -3374,3303, 220,2565,1009,5268,3855, 670,3010, 332,1208, 717,5269,5270,3603,2452, # 2320 -4032,3375,5271, 513,5272,1209,2882,3376,3163,4623,1080,5273,5274,5275,5276,2534, # 2336 -3722,3604, 815,1587,4033,4034,5277,3605,3486,3856,1254,4624,1328,3058,1390,4035, # 2352 -1741,4036,3857,4037,5278, 236,3858,2453,3304,5279,5280,3723,3859,1273,3860,4625, # 2368 -5281, 308,5282,4626, 245,4627,1852,2480,1307,2583, 430, 715,2137,2454,5283, 270, # 2384 - 199,2883,4038,5284,3606,2727,1753, 761,1754, 725,1661,1841,4628,3487,3724,5285, # 2400 -5286, 587, 14,3305, 227,2608, 326, 480,2270, 943,2765,3607, 291, 650,1884,5287, # 2416 -1702,1226, 102,1547, 62,3488, 904,4629,3489,1164,4294,5288,5289,1224,1548,2766, # 2432 - 391, 498,1493,5290,1386,1419,5291,2056,1177,4630, 813, 880,1081,2368, 566,1145, # 2448 -4631,2291,1001,1035,2566,2609,2242, 394,1286,5292,5293,2069,5294, 86,1494,1730, # 2464 -4039, 491,1588, 745, 897,2963, 843,3377,4040,2767,2884,3306,1768, 998,2221,2070, # 2480 - 397,1827,1195,1970,3725,3011,3378, 284,5295,3861,2507,2138,2120,1904,5296,4041, # 2496 -2151,4042,4295,1036,3490,1905, 114,2567,4296, 209,1527,5297,5298,2964,2844,2635, # 2512 -2390,2728,3164, 812,2568,5299,3307,5300,1559, 737,1885,3726,1210, 885, 28,2695, # 2528 -3608,3862,5301,4297,1004,1780,4632,5302, 346,1982,2222,2696,4633,3863,1742, 797, # 2544 -1642,4043,1934,1072,1384,2152, 896,4044,3308,3727,3228,2885,3609,5303,2569,1959, # 2560 -4634,2455,1786,5304,5305,5306,4045,4298,1005,1308,3728,4299,2729,4635,4636,1528, # 2576 -2610, 161,1178,4300,1983, 987,4637,1101,4301, 631,4046,1157,3229,2425,1343,1241, # 2592 -1016,2243,2570, 372, 877,2344,2508,1160, 555,1935, 911,4047,5307, 466,1170, 169, # 2608 -1051,2921,2697,3729,2481,3012,1182,2012,2571,1251,2636,5308, 992,2345,3491,1540, # 2624 -2730,1201,2071,2406,1997,2482,5309,4638, 528,1923,2191,1503,1874,1570,2369,3379, # 2640 -3309,5310, 557,1073,5311,1828,3492,2088,2271,3165,3059,3107, 767,3108,2799,4639, # 2656 -1006,4302,4640,2346,1267,2179,3730,3230, 778,4048,3231,2731,1597,2667,5312,4641, # 2672 -5313,3493,5314,5315,5316,3310,2698,1433,3311, 131, 95,1504,4049, 723,4303,3166, # 2688 -1842,3610,2768,2192,4050,2028,2105,3731,5317,3013,4051,1218,5318,3380,3232,4052, # 2704 -4304,2584, 248,1634,3864, 912,5319,2845,3732,3060,3865, 654, 53,5320,3014,5321, # 2720 -1688,4642, 777,3494,1032,4053,1425,5322, 191, 820,2121,2846, 971,4643, 931,3233, # 2736 - 135, 664, 783,3866,1998, 772,2922,1936,4054,3867,4644,2923,3234, 282,2732, 640, # 2752 -1372,3495,1127, 922, 325,3381,5323,5324, 711,2045,5325,5326,4055,2223,2800,1937, # 2768 -4056,3382,2224,2255,3868,2305,5327,4645,3869,1258,3312,4057,3235,2139,2965,4058, # 2784 -4059,5328,2225, 258,3236,4646, 101,1227,5329,3313,1755,5330,1391,3314,5331,2924, # 2800 -2057, 893,5332,5333,5334,1402,4305,2347,5335,5336,3237,3611,5337,5338, 878,1325, # 2816 -1781,2801,4647, 259,1385,2585, 744,1183,2272,4648,5339,4060,2509,5340, 684,1024, # 2832 -4306,5341, 472,3612,3496,1165,3315,4061,4062, 322,2153, 881, 455,1695,1152,1340, # 2848 - 660, 554,2154,4649,1058,4650,4307, 830,1065,3383,4063,4651,1924,5342,1703,1919, # 2864 -5343, 932,2273, 122,5344,4652, 947, 677,5345,3870,2637, 297,1906,1925,2274,4653, # 2880 -2322,3316,5346,5347,4308,5348,4309, 84,4310, 112, 989,5349, 547,1059,4064, 701, # 2896 -3613,1019,5350,4311,5351,3497, 942, 639, 457,2306,2456, 993,2966, 407, 851, 494, # 2912 -4654,3384, 927,5352,1237,5353,2426,3385, 573,4312, 680, 921,2925,1279,1875, 285, # 2928 - 790,1448,1984, 719,2168,5354,5355,4655,4065,4066,1649,5356,1541, 563,5357,1077, # 2944 -5358,3386,3061,3498, 511,3015,4067,4068,3733,4069,1268,2572,3387,3238,4656,4657, # 2960 -5359, 535,1048,1276,1189,2926,2029,3167,1438,1373,2847,2967,1134,2013,5360,4313, # 2976 -1238,2586,3109,1259,5361, 700,5362,2968,3168,3734,4314,5363,4315,1146,1876,1907, # 2992 -4658,2611,4070, 781,2427, 132,1589, 203, 147, 273,2802,2407, 898,1787,2155,4071, # 3008 -4072,5364,3871,2803,5365,5366,4659,4660,5367,3239,5368,1635,3872, 965,5369,1805, # 3024 -2699,1516,3614,1121,1082,1329,3317,4073,1449,3873, 65,1128,2848,2927,2769,1590, # 3040 -3874,5370,5371, 12,2668, 45, 976,2587,3169,4661, 517,2535,1013,1037,3240,5372, # 3056 -3875,2849,5373,3876,5374,3499,5375,2612, 614,1999,2323,3877,3110,2733,2638,5376, # 3072 -2588,4316, 599,1269,5377,1811,3735,5378,2700,3111, 759,1060, 489,1806,3388,3318, # 3088 -1358,5379,5380,2391,1387,1215,2639,2256, 490,5381,5382,4317,1759,2392,2348,5383, # 3104 -4662,3878,1908,4074,2640,1807,3241,4663,3500,3319,2770,2349, 874,5384,5385,3501, # 3120 -3736,1859, 91,2928,3737,3062,3879,4664,5386,3170,4075,2669,5387,3502,1202,1403, # 3136 -3880,2969,2536,1517,2510,4665,3503,2511,5388,4666,5389,2701,1886,1495,1731,4076, # 3152 -2370,4667,5390,2030,5391,5392,4077,2702,1216, 237,2589,4318,2324,4078,3881,4668, # 3168 -4669,2703,3615,3504, 445,4670,5393,5394,5395,5396,2771, 61,4079,3738,1823,4080, # 3184 -5397, 687,2046, 935, 925, 405,2670, 703,1096,1860,2734,4671,4081,1877,1367,2704, # 3200 -3389, 918,2106,1782,2483, 334,3320,1611,1093,4672, 564,3171,3505,3739,3390, 945, # 3216 -2641,2058,4673,5398,1926, 872,4319,5399,3506,2705,3112, 349,4320,3740,4082,4674, # 3232 -3882,4321,3741,2156,4083,4675,4676,4322,4677,2408,2047, 782,4084, 400, 251,4323, # 3248 -1624,5400,5401, 277,3742, 299,1265, 476,1191,3883,2122,4324,4325,1109, 205,5402, # 3264 -2590,1000,2157,3616,1861,5403,5404,5405,4678,5406,4679,2573, 107,2484,2158,4085, # 3280 -3507,3172,5407,1533, 541,1301, 158, 753,4326,2886,3617,5408,1696, 370,1088,4327, # 3296 -4680,3618, 579, 327, 440, 162,2244, 269,1938,1374,3508, 968,3063, 56,1396,3113, # 3312 -2107,3321,3391,5409,1927,2159,4681,3016,5410,3619,5411,5412,3743,4682,2485,5413, # 3328 -2804,5414,1650,4683,5415,2613,5416,5417,4086,2671,3392,1149,3393,4087,3884,4088, # 3344 -5418,1076, 49,5419, 951,3242,3322,3323, 450,2850, 920,5420,1812,2805,2371,4328, # 3360 -1909,1138,2372,3885,3509,5421,3243,4684,1910,1147,1518,2428,4685,3886,5422,4686, # 3376 -2393,2614, 260,1796,3244,5423,5424,3887,3324, 708,5425,3620,1704,5426,3621,1351, # 3392 -1618,3394,3017,1887, 944,4329,3395,4330,3064,3396,4331,5427,3744, 422, 413,1714, # 3408 -3325, 500,2059,2350,4332,2486,5428,1344,1911, 954,5429,1668,5430,5431,4089,2409, # 3424 -4333,3622,3888,4334,5432,2307,1318,2512,3114, 133,3115,2887,4687, 629, 31,2851, # 3440 -2706,3889,4688, 850, 949,4689,4090,2970,1732,2089,4335,1496,1853,5433,4091, 620, # 3456 -3245, 981,1242,3745,3397,1619,3746,1643,3326,2140,2457,1971,1719,3510,2169,5434, # 3472 -3246,5435,5436,3398,1829,5437,1277,4690,1565,2048,5438,1636,3623,3116,5439, 869, # 3488 -2852, 655,3890,3891,3117,4092,3018,3892,1310,3624,4691,5440,5441,5442,1733, 558, # 3504 -4692,3747, 335,1549,3065,1756,4336,3748,1946,3511,1830,1291,1192, 470,2735,2108, # 3520 -2806, 913,1054,4093,5443,1027,5444,3066,4094,4693, 982,2672,3399,3173,3512,3247, # 3536 -3248,1947,2807,5445, 571,4694,5446,1831,5447,3625,2591,1523,2429,5448,2090, 984, # 3552 -4695,3749,1960,5449,3750, 852, 923,2808,3513,3751, 969,1519, 999,2049,2325,1705, # 3568 -5450,3118, 615,1662, 151, 597,4095,2410,2326,1049, 275,4696,3752,4337, 568,3753, # 3584 -3626,2487,4338,3754,5451,2430,2275, 409,3249,5452,1566,2888,3514,1002, 769,2853, # 3600 - 194,2091,3174,3755,2226,3327,4339, 628,1505,5453,5454,1763,2180,3019,4096, 521, # 3616 -1161,2592,1788,2206,2411,4697,4097,1625,4340,4341, 412, 42,3119, 464,5455,2642, # 3632 -4698,3400,1760,1571,2889,3515,2537,1219,2207,3893,2643,2141,2373,4699,4700,3328, # 3648 -1651,3401,3627,5456,5457,3628,2488,3516,5458,3756,5459,5460,2276,2092, 460,5461, # 3664 -4701,5462,3020, 962, 588,3629, 289,3250,2644,1116, 52,5463,3067,1797,5464,5465, # 3680 -5466,1467,5467,1598,1143,3757,4342,1985,1734,1067,4702,1280,3402, 465,4703,1572, # 3696 - 510,5468,1928,2245,1813,1644,3630,5469,4704,3758,5470,5471,2673,1573,1534,5472, # 3712 -5473, 536,1808,1761,3517,3894,3175,2645,5474,5475,5476,4705,3518,2929,1912,2809, # 3728 -5477,3329,1122, 377,3251,5478, 360,5479,5480,4343,1529, 551,5481,2060,3759,1769, # 3744 -2431,5482,2930,4344,3330,3120,2327,2109,2031,4706,1404, 136,1468,1479, 672,1171, # 3760 -3252,2308, 271,3176,5483,2772,5484,2050, 678,2736, 865,1948,4707,5485,2014,4098, # 3776 -2971,5486,2737,2227,1397,3068,3760,4708,4709,1735,2931,3403,3631,5487,3895, 509, # 3792 -2854,2458,2890,3896,5488,5489,3177,3178,4710,4345,2538,4711,2309,1166,1010, 552, # 3808 - 681,1888,5490,5491,2972,2973,4099,1287,1596,1862,3179, 358, 453, 736, 175, 478, # 3824 -1117, 905,1167,1097,5492,1854,1530,5493,1706,5494,2181,3519,2292,3761,3520,3632, # 3840 -4346,2093,4347,5495,3404,1193,2489,4348,1458,2193,2208,1863,1889,1421,3331,2932, # 3856 -3069,2182,3521, 595,2123,5496,4100,5497,5498,4349,1707,2646, 223,3762,1359, 751, # 3872 -3121, 183,3522,5499,2810,3021, 419,2374, 633, 704,3897,2394, 241,5500,5501,5502, # 3888 - 838,3022,3763,2277,2773,2459,3898,1939,2051,4101,1309,3122,2246,1181,5503,1136, # 3904 -2209,3899,2375,1446,4350,2310,4712,5504,5505,4351,1055,2615, 484,3764,5506,4102, # 3920 - 625,4352,2278,3405,1499,4353,4103,5507,4104,4354,3253,2279,2280,3523,5508,5509, # 3936 -2774, 808,2616,3765,3406,4105,4355,3123,2539, 526,3407,3900,4356, 955,5510,1620, # 3952 -4357,2647,2432,5511,1429,3766,1669,1832, 994, 928,5512,3633,1260,5513,5514,5515, # 3968 -1949,2293, 741,2933,1626,4358,2738,2460, 867,1184, 362,3408,1392,5516,5517,4106, # 3984 -4359,1770,1736,3254,2934,4713,4714,1929,2707,1459,1158,5518,3070,3409,2891,1292, # 4000 -1930,2513,2855,3767,1986,1187,2072,2015,2617,4360,5519,2574,2514,2170,3768,2490, # 4016 -3332,5520,3769,4715,5521,5522, 666,1003,3023,1022,3634,4361,5523,4716,1814,2257, # 4032 - 574,3901,1603, 295,1535, 705,3902,4362, 283, 858, 417,5524,5525,3255,4717,4718, # 4048 -3071,1220,1890,1046,2281,2461,4107,1393,1599, 689,2575, 388,4363,5526,2491, 802, # 4064 -5527,2811,3903,2061,1405,2258,5528,4719,3904,2110,1052,1345,3256,1585,5529, 809, # 4080 -5530,5531,5532, 575,2739,3524, 956,1552,1469,1144,2328,5533,2329,1560,2462,3635, # 4096 -3257,4108, 616,2210,4364,3180,2183,2294,5534,1833,5535,3525,4720,5536,1319,3770, # 4112 -3771,1211,3636,1023,3258,1293,2812,5537,5538,5539,3905, 607,2311,3906, 762,2892, # 4128 -1439,4365,1360,4721,1485,3072,5540,4722,1038,4366,1450,2062,2648,4367,1379,4723, # 4144 -2593,5541,5542,4368,1352,1414,2330,2935,1172,5543,5544,3907,3908,4724,1798,1451, # 4160 -5545,5546,5547,5548,2936,4109,4110,2492,2351, 411,4111,4112,3637,3333,3124,4725, # 4176 -1561,2674,1452,4113,1375,5549,5550, 47,2974, 316,5551,1406,1591,2937,3181,5552, # 4192 -1025,2142,3125,3182, 354,2740, 884,2228,4369,2412, 508,3772, 726,3638, 996,2433, # 4208 -3639, 729,5553, 392,2194,1453,4114,4726,3773,5554,5555,2463,3640,2618,1675,2813, # 4224 - 919,2352,2975,2353,1270,4727,4115, 73,5556,5557, 647,5558,3259,2856,2259,1550, # 4240 -1346,3024,5559,1332, 883,3526,5560,5561,5562,5563,3334,2775,5564,1212, 831,1347, # 4256 -4370,4728,2331,3909,1864,3073, 720,3910,4729,4730,3911,5565,4371,5566,5567,4731, # 4272 -5568,5569,1799,4732,3774,2619,4733,3641,1645,2376,4734,5570,2938, 669,2211,2675, # 4288 -2434,5571,2893,5572,5573,1028,3260,5574,4372,2413,5575,2260,1353,5576,5577,4735, # 4304 -3183, 518,5578,4116,5579,4373,1961,5580,2143,4374,5581,5582,3025,2354,2355,3912, # 4320 - 516,1834,1454,4117,2708,4375,4736,2229,2620,1972,1129,3642,5583,2776,5584,2976, # 4336 -1422, 577,1470,3026,1524,3410,5585,5586, 432,4376,3074,3527,5587,2594,1455,2515, # 4352 -2230,1973,1175,5588,1020,2741,4118,3528,4737,5589,2742,5590,1743,1361,3075,3529, # 4368 -2649,4119,4377,4738,2295, 895, 924,4378,2171, 331,2247,3076, 166,1627,3077,1098, # 4384 -5591,1232,2894,2231,3411,4739, 657, 403,1196,2377, 542,3775,3412,1600,4379,3530, # 4400 -5592,4740,2777,3261, 576, 530,1362,4741,4742,2540,2676,3776,4120,5593, 842,3913, # 4416 -5594,2814,2032,1014,4121, 213,2709,3413, 665, 621,4380,5595,3777,2939,2435,5596, # 4432 -2436,3335,3643,3414,4743,4381,2541,4382,4744,3644,1682,4383,3531,1380,5597, 724, # 4448 -2282, 600,1670,5598,1337,1233,4745,3126,2248,5599,1621,4746,5600, 651,4384,5601, # 4464 -1612,4385,2621,5602,2857,5603,2743,2312,3078,5604, 716,2464,3079, 174,1255,2710, # 4480 -4122,3645, 548,1320,1398, 728,4123,1574,5605,1891,1197,3080,4124,5606,3081,3082, # 4496 -3778,3646,3779, 747,5607, 635,4386,4747,5608,5609,5610,4387,5611,5612,4748,5613, # 4512 -3415,4749,2437, 451,5614,3780,2542,2073,4388,2744,4389,4125,5615,1764,4750,5616, # 4528 -4390, 350,4751,2283,2395,2493,5617,4391,4126,2249,1434,4127, 488,4752, 458,4392, # 4544 -4128,3781, 771,1330,2396,3914,2576,3184,2160,2414,1553,2677,3185,4393,5618,2494, # 4560 -2895,2622,1720,2711,4394,3416,4753,5619,2543,4395,5620,3262,4396,2778,5621,2016, # 4576 -2745,5622,1155,1017,3782,3915,5623,3336,2313, 201,1865,4397,1430,5624,4129,5625, # 4592 -5626,5627,5628,5629,4398,1604,5630, 414,1866, 371,2595,4754,4755,3532,2017,3127, # 4608 -4756,1708, 960,4399, 887, 389,2172,1536,1663,1721,5631,2232,4130,2356,2940,1580, # 4624 -5632,5633,1744,4757,2544,4758,4759,5634,4760,5635,2074,5636,4761,3647,3417,2896, # 4640 -4400,5637,4401,2650,3418,2815, 673,2712,2465, 709,3533,4131,3648,4402,5638,1148, # 4656 - 502, 634,5639,5640,1204,4762,3649,1575,4763,2623,3783,5641,3784,3128, 948,3263, # 4672 - 121,1745,3916,1110,5642,4403,3083,2516,3027,4132,3785,1151,1771,3917,1488,4133, # 4688 -1987,5643,2438,3534,5644,5645,2094,5646,4404,3918,1213,1407,2816, 531,2746,2545, # 4704 -3264,1011,1537,4764,2779,4405,3129,1061,5647,3786,3787,1867,2897,5648,2018, 120, # 4720 -4406,4407,2063,3650,3265,2314,3919,2678,3419,1955,4765,4134,5649,3535,1047,2713, # 4736 -1266,5650,1368,4766,2858, 649,3420,3920,2546,2747,1102,2859,2679,5651,5652,2000, # 4752 -5653,1111,3651,2977,5654,2495,3921,3652,2817,1855,3421,3788,5655,5656,3422,2415, # 4768 -2898,3337,3266,3653,5657,2577,5658,3654,2818,4135,1460, 856,5659,3655,5660,2899, # 4784 -2978,5661,2900,3922,5662,4408, 632,2517, 875,3923,1697,3924,2296,5663,5664,4767, # 4800 -3028,1239, 580,4768,4409,5665, 914, 936,2075,1190,4136,1039,2124,5666,5667,5668, # 4816 -5669,3423,1473,5670,1354,4410,3925,4769,2173,3084,4137, 915,3338,4411,4412,3339, # 4832 -1605,1835,5671,2748, 398,3656,4413,3926,4138, 328,1913,2860,4139,3927,1331,4414, # 4848 -3029, 937,4415,5672,3657,4140,4141,3424,2161,4770,3425, 524, 742, 538,3085,1012, # 4864 -5673,5674,3928,2466,5675, 658,1103, 225,3929,5676,5677,4771,5678,4772,5679,3267, # 4880 -1243,5680,4142, 963,2250,4773,5681,2714,3658,3186,5682,5683,2596,2332,5684,4774, # 4896 -5685,5686,5687,3536, 957,3426,2547,2033,1931,2941,2467, 870,2019,3659,1746,2780, # 4912 -2781,2439,2468,5688,3930,5689,3789,3130,3790,3537,3427,3791,5690,1179,3086,5691, # 4928 -3187,2378,4416,3792,2548,3188,3131,2749,4143,5692,3428,1556,2549,2297, 977,2901, # 4944 -2034,4144,1205,3429,5693,1765,3430,3189,2125,1271, 714,1689,4775,3538,5694,2333, # 4960 -3931, 533,4417,3660,2184, 617,5695,2469,3340,3539,2315,5696,5697,3190,5698,5699, # 4976 -3932,1988, 618, 427,2651,3540,3431,5700,5701,1244,1690,5702,2819,4418,4776,5703, # 4992 -3541,4777,5704,2284,1576, 473,3661,4419,3432, 972,5705,3662,5706,3087,5707,5708, # 5008 -4778,4779,5709,3793,4145,4146,5710, 153,4780, 356,5711,1892,2902,4420,2144, 408, # 5024 - 803,2357,5712,3933,5713,4421,1646,2578,2518,4781,4782,3934,5714,3935,4422,5715, # 5040 -2416,3433, 752,5716,5717,1962,3341,2979,5718, 746,3030,2470,4783,4423,3794, 698, # 5056 -4784,1893,4424,3663,2550,4785,3664,3936,5719,3191,3434,5720,1824,1302,4147,2715, # 5072 -3937,1974,4425,5721,4426,3192, 823,1303,1288,1236,2861,3542,4148,3435, 774,3938, # 5088 -5722,1581,4786,1304,2862,3939,4787,5723,2440,2162,1083,3268,4427,4149,4428, 344, # 5104 -1173, 288,2316, 454,1683,5724,5725,1461,4788,4150,2597,5726,5727,4789, 985, 894, # 5120 -5728,3436,3193,5729,1914,2942,3795,1989,5730,2111,1975,5731,4151,5732,2579,1194, # 5136 - 425,5733,4790,3194,1245,3796,4429,5734,5735,2863,5736, 636,4791,1856,3940, 760, # 5152 -1800,5737,4430,2212,1508,4792,4152,1894,1684,2298,5738,5739,4793,4431,4432,2213, # 5168 - 479,5740,5741, 832,5742,4153,2496,5743,2980,2497,3797, 990,3132, 627,1815,2652, # 5184 -4433,1582,4434,2126,2112,3543,4794,5744, 799,4435,3195,5745,4795,2113,1737,3031, # 5200 -1018, 543, 754,4436,3342,1676,4796,4797,4154,4798,1489,5746,3544,5747,2624,2903, # 5216 -4155,5748,5749,2981,5750,5751,5752,5753,3196,4799,4800,2185,1722,5754,3269,3270, # 5232 -1843,3665,1715, 481, 365,1976,1857,5755,5756,1963,2498,4801,5757,2127,3666,3271, # 5248 - 433,1895,2064,2076,5758, 602,2750,5759,5760,5761,5762,5763,3032,1628,3437,5764, # 5264 -3197,4802,4156,2904,4803,2519,5765,2551,2782,5766,5767,5768,3343,4804,2905,5769, # 5280 -4805,5770,2864,4806,4807,1221,2982,4157,2520,5771,5772,5773,1868,1990,5774,5775, # 5296 -5776,1896,5777,5778,4808,1897,4158, 318,5779,2095,4159,4437,5780,5781, 485,5782, # 5312 - 938,3941, 553,2680, 116,5783,3942,3667,5784,3545,2681,2783,3438,3344,2820,5785, # 5328 -3668,2943,4160,1747,2944,2983,5786,5787, 207,5788,4809,5789,4810,2521,5790,3033, # 5344 - 890,3669,3943,5791,1878,3798,3439,5792,2186,2358,3440,1652,5793,5794,5795, 941, # 5360 -2299, 208,3546,4161,2020, 330,4438,3944,2906,2499,3799,4439,4811,5796,5797,5798, # 5376 -) - diff --git a/venv/lib/python3.8/site-packages/chardet/big5prober.py b/venv/lib/python3.8/site-packages/chardet/big5prober.py deleted file mode 100644 index 98f9970..0000000 --- a/venv/lib/python3.8/site-packages/chardet/big5prober.py +++ /dev/null @@ -1,47 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is Mozilla Communicator client code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -from .mbcharsetprober import MultiByteCharSetProber -from .codingstatemachine import CodingStateMachine -from .chardistribution import Big5DistributionAnalysis -from .mbcssm import BIG5_SM_MODEL - - -class Big5Prober(MultiByteCharSetProber): - def __init__(self): - super(Big5Prober, self).__init__() - self.coding_sm = CodingStateMachine(BIG5_SM_MODEL) - self.distribution_analyzer = Big5DistributionAnalysis() - self.reset() - - @property - def charset_name(self): - return "Big5" - - @property - def language(self): - return "Chinese" diff --git a/venv/lib/python3.8/site-packages/chardet/chardistribution.py b/venv/lib/python3.8/site-packages/chardet/chardistribution.py deleted file mode 100644 index c0395f4..0000000 --- a/venv/lib/python3.8/site-packages/chardet/chardistribution.py +++ /dev/null @@ -1,233 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is Mozilla Communicator client code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -from .euctwfreq import (EUCTW_CHAR_TO_FREQ_ORDER, EUCTW_TABLE_SIZE, - EUCTW_TYPICAL_DISTRIBUTION_RATIO) -from .euckrfreq import (EUCKR_CHAR_TO_FREQ_ORDER, EUCKR_TABLE_SIZE, - EUCKR_TYPICAL_DISTRIBUTION_RATIO) -from .gb2312freq import (GB2312_CHAR_TO_FREQ_ORDER, GB2312_TABLE_SIZE, - GB2312_TYPICAL_DISTRIBUTION_RATIO) -from .big5freq import (BIG5_CHAR_TO_FREQ_ORDER, BIG5_TABLE_SIZE, - BIG5_TYPICAL_DISTRIBUTION_RATIO) -from .jisfreq import (JIS_CHAR_TO_FREQ_ORDER, JIS_TABLE_SIZE, - JIS_TYPICAL_DISTRIBUTION_RATIO) - - -class CharDistributionAnalysis(object): - ENOUGH_DATA_THRESHOLD = 1024 - SURE_YES = 0.99 - SURE_NO = 0.01 - MINIMUM_DATA_THRESHOLD = 3 - - def __init__(self): - # Mapping table to get frequency order from char order (get from - # GetOrder()) - self._char_to_freq_order = None - self._table_size = None # Size of above table - # This is a constant value which varies from language to language, - # used in calculating confidence. See - # http://www.mozilla.org/projects/intl/UniversalCharsetDetection.html - # for further detail. - self.typical_distribution_ratio = None - self._done = None - self._total_chars = None - self._freq_chars = None - self.reset() - - def reset(self): - """reset analyser, clear any state""" - # If this flag is set to True, detection is done and conclusion has - # been made - self._done = False - self._total_chars = 0 # Total characters encountered - # The number of characters whose frequency order is less than 512 - self._freq_chars = 0 - - def feed(self, char, char_len): - """feed a character with known length""" - if char_len == 2: - # we only care about 2-bytes character in our distribution analysis - order = self.get_order(char) - else: - order = -1 - if order >= 0: - self._total_chars += 1 - # order is valid - if order < self._table_size: - if 512 > self._char_to_freq_order[order]: - self._freq_chars += 1 - - def get_confidence(self): - """return confidence based on existing data""" - # if we didn't receive any character in our consideration range, - # return negative answer - if self._total_chars <= 0 or self._freq_chars <= self.MINIMUM_DATA_THRESHOLD: - return self.SURE_NO - - if self._total_chars != self._freq_chars: - r = (self._freq_chars / ((self._total_chars - self._freq_chars) - * self.typical_distribution_ratio)) - if r < self.SURE_YES: - return r - - # normalize confidence (we don't want to be 100% sure) - return self.SURE_YES - - def got_enough_data(self): - # It is not necessary to receive all data to draw conclusion. - # For charset detection, certain amount of data is enough - return self._total_chars > self.ENOUGH_DATA_THRESHOLD - - def get_order(self, byte_str): - # We do not handle characters based on the original encoding string, - # but convert this encoding string to a number, here called order. - # This allows multiple encodings of a language to share one frequency - # table. - return -1 - - -class EUCTWDistributionAnalysis(CharDistributionAnalysis): - def __init__(self): - super(EUCTWDistributionAnalysis, self).__init__() - self._char_to_freq_order = EUCTW_CHAR_TO_FREQ_ORDER - self._table_size = EUCTW_TABLE_SIZE - self.typical_distribution_ratio = EUCTW_TYPICAL_DISTRIBUTION_RATIO - - def get_order(self, byte_str): - # for euc-TW encoding, we are interested - # first byte range: 0xc4 -- 0xfe - # second byte range: 0xa1 -- 0xfe - # no validation needed here. State machine has done that - first_char = byte_str[0] - if first_char >= 0xC4: - return 94 * (first_char - 0xC4) + byte_str[1] - 0xA1 - else: - return -1 - - -class EUCKRDistributionAnalysis(CharDistributionAnalysis): - def __init__(self): - super(EUCKRDistributionAnalysis, self).__init__() - self._char_to_freq_order = EUCKR_CHAR_TO_FREQ_ORDER - self._table_size = EUCKR_TABLE_SIZE - self.typical_distribution_ratio = EUCKR_TYPICAL_DISTRIBUTION_RATIO - - def get_order(self, byte_str): - # for euc-KR encoding, we are interested - # first byte range: 0xb0 -- 0xfe - # second byte range: 0xa1 -- 0xfe - # no validation needed here. State machine has done that - first_char = byte_str[0] - if first_char >= 0xB0: - return 94 * (first_char - 0xB0) + byte_str[1] - 0xA1 - else: - return -1 - - -class GB2312DistributionAnalysis(CharDistributionAnalysis): - def __init__(self): - super(GB2312DistributionAnalysis, self).__init__() - self._char_to_freq_order = GB2312_CHAR_TO_FREQ_ORDER - self._table_size = GB2312_TABLE_SIZE - self.typical_distribution_ratio = GB2312_TYPICAL_DISTRIBUTION_RATIO - - def get_order(self, byte_str): - # for GB2312 encoding, we are interested - # first byte range: 0xb0 -- 0xfe - # second byte range: 0xa1 -- 0xfe - # no validation needed here. State machine has done that - first_char, second_char = byte_str[0], byte_str[1] - if (first_char >= 0xB0) and (second_char >= 0xA1): - return 94 * (first_char - 0xB0) + second_char - 0xA1 - else: - return -1 - - -class Big5DistributionAnalysis(CharDistributionAnalysis): - def __init__(self): - super(Big5DistributionAnalysis, self).__init__() - self._char_to_freq_order = BIG5_CHAR_TO_FREQ_ORDER - self._table_size = BIG5_TABLE_SIZE - self.typical_distribution_ratio = BIG5_TYPICAL_DISTRIBUTION_RATIO - - def get_order(self, byte_str): - # for big5 encoding, we are interested - # first byte range: 0xa4 -- 0xfe - # second byte range: 0x40 -- 0x7e , 0xa1 -- 0xfe - # no validation needed here. State machine has done that - first_char, second_char = byte_str[0], byte_str[1] - if first_char >= 0xA4: - if second_char >= 0xA1: - return 157 * (first_char - 0xA4) + second_char - 0xA1 + 63 - else: - return 157 * (first_char - 0xA4) + second_char - 0x40 - else: - return -1 - - -class SJISDistributionAnalysis(CharDistributionAnalysis): - def __init__(self): - super(SJISDistributionAnalysis, self).__init__() - self._char_to_freq_order = JIS_CHAR_TO_FREQ_ORDER - self._table_size = JIS_TABLE_SIZE - self.typical_distribution_ratio = JIS_TYPICAL_DISTRIBUTION_RATIO - - def get_order(self, byte_str): - # for sjis encoding, we are interested - # first byte range: 0x81 -- 0x9f , 0xe0 -- 0xfe - # second byte range: 0x40 -- 0x7e, 0x81 -- oxfe - # no validation needed here. State machine has done that - first_char, second_char = byte_str[0], byte_str[1] - if (first_char >= 0x81) and (first_char <= 0x9F): - order = 188 * (first_char - 0x81) - elif (first_char >= 0xE0) and (first_char <= 0xEF): - order = 188 * (first_char - 0xE0 + 31) - else: - return -1 - order = order + second_char - 0x40 - if second_char > 0x7F: - order = -1 - return order - - -class EUCJPDistributionAnalysis(CharDistributionAnalysis): - def __init__(self): - super(EUCJPDistributionAnalysis, self).__init__() - self._char_to_freq_order = JIS_CHAR_TO_FREQ_ORDER - self._table_size = JIS_TABLE_SIZE - self.typical_distribution_ratio = JIS_TYPICAL_DISTRIBUTION_RATIO - - def get_order(self, byte_str): - # for euc-JP encoding, we are interested - # first byte range: 0xa0 -- 0xfe - # second byte range: 0xa1 -- 0xfe - # no validation needed here. State machine has done that - char = byte_str[0] - if char >= 0xA0: - return 94 * (char - 0xA1) + byte_str[1] - 0xa1 - else: - return -1 diff --git a/venv/lib/python3.8/site-packages/chardet/charsetgroupprober.py b/venv/lib/python3.8/site-packages/chardet/charsetgroupprober.py deleted file mode 100644 index 5812cef..0000000 --- a/venv/lib/python3.8/site-packages/chardet/charsetgroupprober.py +++ /dev/null @@ -1,107 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is Mozilla Communicator client code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -from .enums import ProbingState -from .charsetprober import CharSetProber - - -class CharSetGroupProber(CharSetProber): - def __init__(self, lang_filter=None): - super(CharSetGroupProber, self).__init__(lang_filter=lang_filter) - self._active_num = 0 - self.probers = [] - self._best_guess_prober = None - - def reset(self): - super(CharSetGroupProber, self).reset() - self._active_num = 0 - for prober in self.probers: - if prober: - prober.reset() - prober.active = True - self._active_num += 1 - self._best_guess_prober = None - - @property - def charset_name(self): - if not self._best_guess_prober: - self.get_confidence() - if not self._best_guess_prober: - return None - return self._best_guess_prober.charset_name - - @property - def language(self): - if not self._best_guess_prober: - self.get_confidence() - if not self._best_guess_prober: - return None - return self._best_guess_prober.language - - def feed(self, byte_str): - for prober in self.probers: - if not prober: - continue - if not prober.active: - continue - state = prober.feed(byte_str) - if not state: - continue - if state == ProbingState.FOUND_IT: - self._best_guess_prober = prober - self._state = ProbingState.FOUND_IT - return self.state - elif state == ProbingState.NOT_ME: - prober.active = False - self._active_num -= 1 - if self._active_num <= 0: - self._state = ProbingState.NOT_ME - return self.state - return self.state - - def get_confidence(self): - state = self.state - if state == ProbingState.FOUND_IT: - return 0.99 - elif state == ProbingState.NOT_ME: - return 0.01 - best_conf = 0.0 - self._best_guess_prober = None - for prober in self.probers: - if not prober: - continue - if not prober.active: - self.logger.debug('%s not active', prober.charset_name) - continue - conf = prober.get_confidence() - self.logger.debug('%s %s confidence = %s', prober.charset_name, prober.language, conf) - if best_conf < conf: - best_conf = conf - self._best_guess_prober = prober - if not self._best_guess_prober: - return 0.0 - return best_conf diff --git a/venv/lib/python3.8/site-packages/chardet/charsetprober.py b/venv/lib/python3.8/site-packages/chardet/charsetprober.py deleted file mode 100644 index eac4e59..0000000 --- a/venv/lib/python3.8/site-packages/chardet/charsetprober.py +++ /dev/null @@ -1,145 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is Mozilla Universal charset detector code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 2001 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# Shy Shalom - original C code -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -import logging -import re - -from .enums import ProbingState - - -class CharSetProber(object): - - SHORTCUT_THRESHOLD = 0.95 - - def __init__(self, lang_filter=None): - self._state = None - self.lang_filter = lang_filter - self.logger = logging.getLogger(__name__) - - def reset(self): - self._state = ProbingState.DETECTING - - @property - def charset_name(self): - return None - - def feed(self, buf): - pass - - @property - def state(self): - return self._state - - def get_confidence(self): - return 0.0 - - @staticmethod - def filter_high_byte_only(buf): - buf = re.sub(b'([\x00-\x7F])+', b' ', buf) - return buf - - @staticmethod - def filter_international_words(buf): - """ - We define three types of bytes: - alphabet: english alphabets [a-zA-Z] - international: international characters [\x80-\xFF] - marker: everything else [^a-zA-Z\x80-\xFF] - - The input buffer can be thought to contain a series of words delimited - by markers. This function works to filter all words that contain at - least one international character. All contiguous sequences of markers - are replaced by a single space ascii character. - - This filter applies to all scripts which do not use English characters. - """ - filtered = bytearray() - - # This regex expression filters out only words that have at-least one - # international character. The word may include one marker character at - # the end. - words = re.findall(b'[a-zA-Z]*[\x80-\xFF]+[a-zA-Z]*[^a-zA-Z\x80-\xFF]?', - buf) - - for word in words: - filtered.extend(word[:-1]) - - # If the last character in the word is a marker, replace it with a - # space as markers shouldn't affect our analysis (they are used - # similarly across all languages and may thus have similar - # frequencies). - last_char = word[-1:] - if not last_char.isalpha() and last_char < b'\x80': - last_char = b' ' - filtered.extend(last_char) - - return filtered - - @staticmethod - def filter_with_english_letters(buf): - """ - Returns a copy of ``buf`` that retains only the sequences of English - alphabet and high byte characters that are not between <> characters. - Also retains English alphabet and high byte characters immediately - before occurrences of >. - - This filter can be applied to all scripts which contain both English - characters and extended ASCII characters, but is currently only used by - ``Latin1Prober``. - """ - filtered = bytearray() - in_tag = False - prev = 0 - - for curr in range(len(buf)): - # Slice here to get bytes instead of an int with Python 3 - buf_char = buf[curr:curr + 1] - # Check if we're coming out of or entering an HTML tag - if buf_char == b'>': - in_tag = False - elif buf_char == b'<': - in_tag = True - - # If current character is not extended-ASCII and not alphabetic... - if buf_char < b'\x80' and not buf_char.isalpha(): - # ...and we're not in a tag - if curr > prev and not in_tag: - # Keep everything after last non-extended-ASCII, - # non-alphabetic character - filtered.extend(buf[prev:curr]) - # Output a space to delimit stretch we kept - filtered.extend(b' ') - prev = curr + 1 - - # If we're not in a tag... - if not in_tag: - # Keep everything after last non-extended-ASCII, non-alphabetic - # character - filtered.extend(buf[prev:]) - - return filtered diff --git a/venv/lib/python3.8/site-packages/chardet/cli/__init__.py b/venv/lib/python3.8/site-packages/chardet/cli/__init__.py deleted file mode 100644 index 8b13789..0000000 --- a/venv/lib/python3.8/site-packages/chardet/cli/__init__.py +++ /dev/null @@ -1 +0,0 @@ - diff --git a/venv/lib/python3.8/site-packages/chardet/cli/chardetect.py b/venv/lib/python3.8/site-packages/chardet/cli/chardetect.py deleted file mode 100644 index e1d8cd6..0000000 --- a/venv/lib/python3.8/site-packages/chardet/cli/chardetect.py +++ /dev/null @@ -1,84 +0,0 @@ -""" -Script which takes one or more file paths and reports on their detected -encodings - -Example:: - - % chardetect somefile someotherfile - somefile: windows-1252 with confidence 0.5 - someotherfile: ascii with confidence 1.0 - -If no paths are provided, it takes its input from stdin. - -""" - -from __future__ import absolute_import, print_function, unicode_literals - -import argparse -import sys - -from chardet import __version__ -from chardet.compat import PY2 -from chardet.universaldetector import UniversalDetector - - -def description_of(lines, name='stdin'): - """ - Return a string describing the probable encoding of a file or - list of strings. - - :param lines: The lines to get the encoding of. - :type lines: Iterable of bytes - :param name: Name of file or collection of lines - :type name: str - """ - u = UniversalDetector() - for line in lines: - line = bytearray(line) - u.feed(line) - # shortcut out of the loop to save reading further - particularly useful if we read a BOM. - if u.done: - break - u.close() - result = u.result - if PY2: - name = name.decode(sys.getfilesystemencoding(), 'ignore') - if result['encoding']: - return '{}: {} with confidence {}'.format(name, result['encoding'], - result['confidence']) - else: - return '{}: no result'.format(name) - - -def main(argv=None): - """ - Handles command line arguments and gets things started. - - :param argv: List of arguments, as if specified on the command-line. - If None, ``sys.argv[1:]`` is used instead. - :type argv: list of str - """ - # Get command line arguments - parser = argparse.ArgumentParser( - description="Takes one or more file paths and reports their detected \ - encodings") - parser.add_argument('input', - help='File whose encoding we would like to determine. \ - (default: stdin)', - type=argparse.FileType('rb'), nargs='*', - default=[sys.stdin if PY2 else sys.stdin.buffer]) - parser.add_argument('--version', action='version', - version='%(prog)s {}'.format(__version__)) - args = parser.parse_args(argv) - - for f in args.input: - if f.isatty(): - print("You are running chardetect interactively. Press " + - "CTRL-D twice at the start of a blank line to signal the " + - "end of your input. If you want help, run chardetect " + - "--help\n", file=sys.stderr) - print(description_of(f, f.name)) - - -if __name__ == '__main__': - main() diff --git a/venv/lib/python3.8/site-packages/chardet/codingstatemachine.py b/venv/lib/python3.8/site-packages/chardet/codingstatemachine.py deleted file mode 100644 index 68fba44..0000000 --- a/venv/lib/python3.8/site-packages/chardet/codingstatemachine.py +++ /dev/null @@ -1,88 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is mozilla.org code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -import logging - -from .enums import MachineState - - -class CodingStateMachine(object): - """ - A state machine to verify a byte sequence for a particular encoding. For - each byte the detector receives, it will feed that byte to every active - state machine available, one byte at a time. The state machine changes its - state based on its previous state and the byte it receives. There are 3 - states in a state machine that are of interest to an auto-detector: - - START state: This is the state to start with, or a legal byte sequence - (i.e. a valid code point) for character has been identified. - - ME state: This indicates that the state machine identified a byte sequence - that is specific to the charset it is designed for and that - there is no other possible encoding which can contain this byte - sequence. This will to lead to an immediate positive answer for - the detector. - - ERROR state: This indicates the state machine identified an illegal byte - sequence for that encoding. This will lead to an immediate - negative answer for this encoding. Detector will exclude this - encoding from consideration from here on. - """ - def __init__(self, sm): - self._model = sm - self._curr_byte_pos = 0 - self._curr_char_len = 0 - self._curr_state = None - self.logger = logging.getLogger(__name__) - self.reset() - - def reset(self): - self._curr_state = MachineState.START - - def next_state(self, c): - # for each byte we get its class - # if it is first byte, we also get byte length - byte_class = self._model['class_table'][c] - if self._curr_state == MachineState.START: - self._curr_byte_pos = 0 - self._curr_char_len = self._model['char_len_table'][byte_class] - # from byte's class and state_table, we get its next state - curr_state = (self._curr_state * self._model['class_factor'] - + byte_class) - self._curr_state = self._model['state_table'][curr_state] - self._curr_byte_pos += 1 - return self._curr_state - - def get_current_charlen(self): - return self._curr_char_len - - def get_coding_state_machine(self): - return self._model['name'] - - @property - def language(self): - return self._model['language'] diff --git a/venv/lib/python3.8/site-packages/chardet/compat.py b/venv/lib/python3.8/site-packages/chardet/compat.py deleted file mode 100644 index 8941572..0000000 --- a/venv/lib/python3.8/site-packages/chardet/compat.py +++ /dev/null @@ -1,36 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# Contributor(s): -# Dan Blanchard -# Ian Cordasco -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -import sys - - -if sys.version_info < (3, 0): - PY2 = True - PY3 = False - string_types = (str, unicode) - text_type = unicode - iteritems = dict.iteritems -else: - PY2 = False - PY3 = True - string_types = (bytes, str) - text_type = str - iteritems = dict.items diff --git a/venv/lib/python3.8/site-packages/chardet/cp949prober.py b/venv/lib/python3.8/site-packages/chardet/cp949prober.py deleted file mode 100644 index efd793a..0000000 --- a/venv/lib/python3.8/site-packages/chardet/cp949prober.py +++ /dev/null @@ -1,49 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is mozilla.org code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -from .chardistribution import EUCKRDistributionAnalysis -from .codingstatemachine import CodingStateMachine -from .mbcharsetprober import MultiByteCharSetProber -from .mbcssm import CP949_SM_MODEL - - -class CP949Prober(MultiByteCharSetProber): - def __init__(self): - super(CP949Prober, self).__init__() - self.coding_sm = CodingStateMachine(CP949_SM_MODEL) - # NOTE: CP949 is a superset of EUC-KR, so the distribution should be - # not different. - self.distribution_analyzer = EUCKRDistributionAnalysis() - self.reset() - - @property - def charset_name(self): - return "CP949" - - @property - def language(self): - return "Korean" diff --git a/venv/lib/python3.8/site-packages/chardet/enums.py b/venv/lib/python3.8/site-packages/chardet/enums.py deleted file mode 100644 index 0451207..0000000 --- a/venv/lib/python3.8/site-packages/chardet/enums.py +++ /dev/null @@ -1,76 +0,0 @@ -""" -All of the Enums that are used throughout the chardet package. - -:author: Dan Blanchard (dan.blanchard@gmail.com) -""" - - -class InputState(object): - """ - This enum represents the different states a universal detector can be in. - """ - PURE_ASCII = 0 - ESC_ASCII = 1 - HIGH_BYTE = 2 - - -class LanguageFilter(object): - """ - This enum represents the different language filters we can apply to a - ``UniversalDetector``. - """ - CHINESE_SIMPLIFIED = 0x01 - CHINESE_TRADITIONAL = 0x02 - JAPANESE = 0x04 - KOREAN = 0x08 - NON_CJK = 0x10 - ALL = 0x1F - CHINESE = CHINESE_SIMPLIFIED | CHINESE_TRADITIONAL - CJK = CHINESE | JAPANESE | KOREAN - - -class ProbingState(object): - """ - This enum represents the different states a prober can be in. - """ - DETECTING = 0 - FOUND_IT = 1 - NOT_ME = 2 - - -class MachineState(object): - """ - This enum represents the different states a state machine can be in. - """ - START = 0 - ERROR = 1 - ITS_ME = 2 - - -class SequenceLikelihood(object): - """ - This enum represents the likelihood of a character following the previous one. - """ - NEGATIVE = 0 - UNLIKELY = 1 - LIKELY = 2 - POSITIVE = 3 - - @classmethod - def get_num_categories(cls): - """:returns: The number of likelihood categories in the enum.""" - return 4 - - -class CharacterCategory(object): - """ - This enum represents the different categories language models for - ``SingleByteCharsetProber`` put characters into. - - Anything less than CONTROL is considered a letter. - """ - UNDEFINED = 255 - LINE_BREAK = 254 - SYMBOL = 253 - DIGIT = 252 - CONTROL = 251 diff --git a/venv/lib/python3.8/site-packages/chardet/escprober.py b/venv/lib/python3.8/site-packages/chardet/escprober.py deleted file mode 100644 index c70493f..0000000 --- a/venv/lib/python3.8/site-packages/chardet/escprober.py +++ /dev/null @@ -1,101 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is mozilla.org code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -from .charsetprober import CharSetProber -from .codingstatemachine import CodingStateMachine -from .enums import LanguageFilter, ProbingState, MachineState -from .escsm import (HZ_SM_MODEL, ISO2022CN_SM_MODEL, ISO2022JP_SM_MODEL, - ISO2022KR_SM_MODEL) - - -class EscCharSetProber(CharSetProber): - """ - This CharSetProber uses a "code scheme" approach for detecting encodings, - whereby easily recognizable escape or shift sequences are relied on to - identify these encodings. - """ - - def __init__(self, lang_filter=None): - super(EscCharSetProber, self).__init__(lang_filter=lang_filter) - self.coding_sm = [] - if self.lang_filter & LanguageFilter.CHINESE_SIMPLIFIED: - self.coding_sm.append(CodingStateMachine(HZ_SM_MODEL)) - self.coding_sm.append(CodingStateMachine(ISO2022CN_SM_MODEL)) - if self.lang_filter & LanguageFilter.JAPANESE: - self.coding_sm.append(CodingStateMachine(ISO2022JP_SM_MODEL)) - if self.lang_filter & LanguageFilter.KOREAN: - self.coding_sm.append(CodingStateMachine(ISO2022KR_SM_MODEL)) - self.active_sm_count = None - self._detected_charset = None - self._detected_language = None - self._state = None - self.reset() - - def reset(self): - super(EscCharSetProber, self).reset() - for coding_sm in self.coding_sm: - if not coding_sm: - continue - coding_sm.active = True - coding_sm.reset() - self.active_sm_count = len(self.coding_sm) - self._detected_charset = None - self._detected_language = None - - @property - def charset_name(self): - return self._detected_charset - - @property - def language(self): - return self._detected_language - - def get_confidence(self): - if self._detected_charset: - return 0.99 - else: - return 0.00 - - def feed(self, byte_str): - for c in byte_str: - for coding_sm in self.coding_sm: - if not coding_sm or not coding_sm.active: - continue - coding_state = coding_sm.next_state(c) - if coding_state == MachineState.ERROR: - coding_sm.active = False - self.active_sm_count -= 1 - if self.active_sm_count <= 0: - self._state = ProbingState.NOT_ME - return self.state - elif coding_state == MachineState.ITS_ME: - self._state = ProbingState.FOUND_IT - self._detected_charset = coding_sm.get_coding_state_machine() - self._detected_language = coding_sm.language - return self.state - - return self.state diff --git a/venv/lib/python3.8/site-packages/chardet/escsm.py b/venv/lib/python3.8/site-packages/chardet/escsm.py deleted file mode 100644 index 0069523..0000000 --- a/venv/lib/python3.8/site-packages/chardet/escsm.py +++ /dev/null @@ -1,246 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is mozilla.org code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -from .enums import MachineState - -HZ_CLS = ( -1,0,0,0,0,0,0,0, # 00 - 07 -0,0,0,0,0,0,0,0, # 08 - 0f -0,0,0,0,0,0,0,0, # 10 - 17 -0,0,0,1,0,0,0,0, # 18 - 1f -0,0,0,0,0,0,0,0, # 20 - 27 -0,0,0,0,0,0,0,0, # 28 - 2f -0,0,0,0,0,0,0,0, # 30 - 37 -0,0,0,0,0,0,0,0, # 38 - 3f -0,0,0,0,0,0,0,0, # 40 - 47 -0,0,0,0,0,0,0,0, # 48 - 4f -0,0,0,0,0,0,0,0, # 50 - 57 -0,0,0,0,0,0,0,0, # 58 - 5f -0,0,0,0,0,0,0,0, # 60 - 67 -0,0,0,0,0,0,0,0, # 68 - 6f -0,0,0,0,0,0,0,0, # 70 - 77 -0,0,0,4,0,5,2,0, # 78 - 7f -1,1,1,1,1,1,1,1, # 80 - 87 -1,1,1,1,1,1,1,1, # 88 - 8f -1,1,1,1,1,1,1,1, # 90 - 97 -1,1,1,1,1,1,1,1, # 98 - 9f -1,1,1,1,1,1,1,1, # a0 - a7 -1,1,1,1,1,1,1,1, # a8 - af -1,1,1,1,1,1,1,1, # b0 - b7 -1,1,1,1,1,1,1,1, # b8 - bf -1,1,1,1,1,1,1,1, # c0 - c7 -1,1,1,1,1,1,1,1, # c8 - cf -1,1,1,1,1,1,1,1, # d0 - d7 -1,1,1,1,1,1,1,1, # d8 - df -1,1,1,1,1,1,1,1, # e0 - e7 -1,1,1,1,1,1,1,1, # e8 - ef -1,1,1,1,1,1,1,1, # f0 - f7 -1,1,1,1,1,1,1,1, # f8 - ff -) - -HZ_ST = ( -MachineState.START,MachineState.ERROR, 3,MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,# 00-07 -MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,# 08-0f -MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START, 4,MachineState.ERROR,# 10-17 - 5,MachineState.ERROR, 6,MachineState.ERROR, 5, 5, 4,MachineState.ERROR,# 18-1f - 4,MachineState.ERROR, 4, 4, 4,MachineState.ERROR, 4,MachineState.ERROR,# 20-27 - 4,MachineState.ITS_ME,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,# 28-2f -) - -HZ_CHAR_LEN_TABLE = (0, 0, 0, 0, 0, 0) - -HZ_SM_MODEL = {'class_table': HZ_CLS, - 'class_factor': 6, - 'state_table': HZ_ST, - 'char_len_table': HZ_CHAR_LEN_TABLE, - 'name': "HZ-GB-2312", - 'language': 'Chinese'} - -ISO2022CN_CLS = ( -2,0,0,0,0,0,0,0, # 00 - 07 -0,0,0,0,0,0,0,0, # 08 - 0f -0,0,0,0,0,0,0,0, # 10 - 17 -0,0,0,1,0,0,0,0, # 18 - 1f -0,0,0,0,0,0,0,0, # 20 - 27 -0,3,0,0,0,0,0,0, # 28 - 2f -0,0,0,0,0,0,0,0, # 30 - 37 -0,0,0,0,0,0,0,0, # 38 - 3f -0,0,0,4,0,0,0,0, # 40 - 47 -0,0,0,0,0,0,0,0, # 48 - 4f -0,0,0,0,0,0,0,0, # 50 - 57 -0,0,0,0,0,0,0,0, # 58 - 5f -0,0,0,0,0,0,0,0, # 60 - 67 -0,0,0,0,0,0,0,0, # 68 - 6f -0,0,0,0,0,0,0,0, # 70 - 77 -0,0,0,0,0,0,0,0, # 78 - 7f -2,2,2,2,2,2,2,2, # 80 - 87 -2,2,2,2,2,2,2,2, # 88 - 8f -2,2,2,2,2,2,2,2, # 90 - 97 -2,2,2,2,2,2,2,2, # 98 - 9f -2,2,2,2,2,2,2,2, # a0 - a7 -2,2,2,2,2,2,2,2, # a8 - af -2,2,2,2,2,2,2,2, # b0 - b7 -2,2,2,2,2,2,2,2, # b8 - bf -2,2,2,2,2,2,2,2, # c0 - c7 -2,2,2,2,2,2,2,2, # c8 - cf -2,2,2,2,2,2,2,2, # d0 - d7 -2,2,2,2,2,2,2,2, # d8 - df -2,2,2,2,2,2,2,2, # e0 - e7 -2,2,2,2,2,2,2,2, # e8 - ef -2,2,2,2,2,2,2,2, # f0 - f7 -2,2,2,2,2,2,2,2, # f8 - ff -) - -ISO2022CN_ST = ( -MachineState.START, 3,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,# 00-07 -MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 08-0f -MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,# 10-17 -MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 4,MachineState.ERROR,# 18-1f -MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 20-27 - 5, 6,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 28-2f -MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 30-37 -MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.START,# 38-3f -) - -ISO2022CN_CHAR_LEN_TABLE = (0, 0, 0, 0, 0, 0, 0, 0, 0) - -ISO2022CN_SM_MODEL = {'class_table': ISO2022CN_CLS, - 'class_factor': 9, - 'state_table': ISO2022CN_ST, - 'char_len_table': ISO2022CN_CHAR_LEN_TABLE, - 'name': "ISO-2022-CN", - 'language': 'Chinese'} - -ISO2022JP_CLS = ( -2,0,0,0,0,0,0,0, # 00 - 07 -0,0,0,0,0,0,2,2, # 08 - 0f -0,0,0,0,0,0,0,0, # 10 - 17 -0,0,0,1,0,0,0,0, # 18 - 1f -0,0,0,0,7,0,0,0, # 20 - 27 -3,0,0,0,0,0,0,0, # 28 - 2f -0,0,0,0,0,0,0,0, # 30 - 37 -0,0,0,0,0,0,0,0, # 38 - 3f -6,0,4,0,8,0,0,0, # 40 - 47 -0,9,5,0,0,0,0,0, # 48 - 4f -0,0,0,0,0,0,0,0, # 50 - 57 -0,0,0,0,0,0,0,0, # 58 - 5f -0,0,0,0,0,0,0,0, # 60 - 67 -0,0,0,0,0,0,0,0, # 68 - 6f -0,0,0,0,0,0,0,0, # 70 - 77 -0,0,0,0,0,0,0,0, # 78 - 7f -2,2,2,2,2,2,2,2, # 80 - 87 -2,2,2,2,2,2,2,2, # 88 - 8f -2,2,2,2,2,2,2,2, # 90 - 97 -2,2,2,2,2,2,2,2, # 98 - 9f -2,2,2,2,2,2,2,2, # a0 - a7 -2,2,2,2,2,2,2,2, # a8 - af -2,2,2,2,2,2,2,2, # b0 - b7 -2,2,2,2,2,2,2,2, # b8 - bf -2,2,2,2,2,2,2,2, # c0 - c7 -2,2,2,2,2,2,2,2, # c8 - cf -2,2,2,2,2,2,2,2, # d0 - d7 -2,2,2,2,2,2,2,2, # d8 - df -2,2,2,2,2,2,2,2, # e0 - e7 -2,2,2,2,2,2,2,2, # e8 - ef -2,2,2,2,2,2,2,2, # f0 - f7 -2,2,2,2,2,2,2,2, # f8 - ff -) - -ISO2022JP_ST = ( -MachineState.START, 3,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,# 00-07 -MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 08-0f -MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,# 10-17 -MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,# 18-1f -MachineState.ERROR, 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 4,MachineState.ERROR,MachineState.ERROR,# 20-27 -MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 6,MachineState.ITS_ME,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,# 28-2f -MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,# 30-37 -MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 38-3f -MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,MachineState.START,MachineState.START,# 40-47 -) - -ISO2022JP_CHAR_LEN_TABLE = (0, 0, 0, 0, 0, 0, 0, 0, 0, 0) - -ISO2022JP_SM_MODEL = {'class_table': ISO2022JP_CLS, - 'class_factor': 10, - 'state_table': ISO2022JP_ST, - 'char_len_table': ISO2022JP_CHAR_LEN_TABLE, - 'name': "ISO-2022-JP", - 'language': 'Japanese'} - -ISO2022KR_CLS = ( -2,0,0,0,0,0,0,0, # 00 - 07 -0,0,0,0,0,0,0,0, # 08 - 0f -0,0,0,0,0,0,0,0, # 10 - 17 -0,0,0,1,0,0,0,0, # 18 - 1f -0,0,0,0,3,0,0,0, # 20 - 27 -0,4,0,0,0,0,0,0, # 28 - 2f -0,0,0,0,0,0,0,0, # 30 - 37 -0,0,0,0,0,0,0,0, # 38 - 3f -0,0,0,5,0,0,0,0, # 40 - 47 -0,0,0,0,0,0,0,0, # 48 - 4f -0,0,0,0,0,0,0,0, # 50 - 57 -0,0,0,0,0,0,0,0, # 58 - 5f -0,0,0,0,0,0,0,0, # 60 - 67 -0,0,0,0,0,0,0,0, # 68 - 6f -0,0,0,0,0,0,0,0, # 70 - 77 -0,0,0,0,0,0,0,0, # 78 - 7f -2,2,2,2,2,2,2,2, # 80 - 87 -2,2,2,2,2,2,2,2, # 88 - 8f -2,2,2,2,2,2,2,2, # 90 - 97 -2,2,2,2,2,2,2,2, # 98 - 9f -2,2,2,2,2,2,2,2, # a0 - a7 -2,2,2,2,2,2,2,2, # a8 - af -2,2,2,2,2,2,2,2, # b0 - b7 -2,2,2,2,2,2,2,2, # b8 - bf -2,2,2,2,2,2,2,2, # c0 - c7 -2,2,2,2,2,2,2,2, # c8 - cf -2,2,2,2,2,2,2,2, # d0 - d7 -2,2,2,2,2,2,2,2, # d8 - df -2,2,2,2,2,2,2,2, # e0 - e7 -2,2,2,2,2,2,2,2, # e8 - ef -2,2,2,2,2,2,2,2, # f0 - f7 -2,2,2,2,2,2,2,2, # f8 - ff -) - -ISO2022KR_ST = ( -MachineState.START, 3,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,# 00-07 -MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,# 08-0f -MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 4,MachineState.ERROR,MachineState.ERROR,# 10-17 -MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,# 18-1f -MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.START,MachineState.START,MachineState.START,MachineState.START,# 20-27 -) - -ISO2022KR_CHAR_LEN_TABLE = (0, 0, 0, 0, 0, 0) - -ISO2022KR_SM_MODEL = {'class_table': ISO2022KR_CLS, - 'class_factor': 6, - 'state_table': ISO2022KR_ST, - 'char_len_table': ISO2022KR_CHAR_LEN_TABLE, - 'name': "ISO-2022-KR", - 'language': 'Korean'} - - diff --git a/venv/lib/python3.8/site-packages/chardet/eucjpprober.py b/venv/lib/python3.8/site-packages/chardet/eucjpprober.py deleted file mode 100644 index 20ce8f7..0000000 --- a/venv/lib/python3.8/site-packages/chardet/eucjpprober.py +++ /dev/null @@ -1,92 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is mozilla.org code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -from .enums import ProbingState, MachineState -from .mbcharsetprober import MultiByteCharSetProber -from .codingstatemachine import CodingStateMachine -from .chardistribution import EUCJPDistributionAnalysis -from .jpcntx import EUCJPContextAnalysis -from .mbcssm import EUCJP_SM_MODEL - - -class EUCJPProber(MultiByteCharSetProber): - def __init__(self): - super(EUCJPProber, self).__init__() - self.coding_sm = CodingStateMachine(EUCJP_SM_MODEL) - self.distribution_analyzer = EUCJPDistributionAnalysis() - self.context_analyzer = EUCJPContextAnalysis() - self.reset() - - def reset(self): - super(EUCJPProber, self).reset() - self.context_analyzer.reset() - - @property - def charset_name(self): - return "EUC-JP" - - @property - def language(self): - return "Japanese" - - def feed(self, byte_str): - for i in range(len(byte_str)): - # PY3K: byte_str is a byte array, so byte_str[i] is an int, not a byte - coding_state = self.coding_sm.next_state(byte_str[i]) - if coding_state == MachineState.ERROR: - self.logger.debug('%s %s prober hit error at byte %s', - self.charset_name, self.language, i) - self._state = ProbingState.NOT_ME - break - elif coding_state == MachineState.ITS_ME: - self._state = ProbingState.FOUND_IT - break - elif coding_state == MachineState.START: - char_len = self.coding_sm.get_current_charlen() - if i == 0: - self._last_char[1] = byte_str[0] - self.context_analyzer.feed(self._last_char, char_len) - self.distribution_analyzer.feed(self._last_char, char_len) - else: - self.context_analyzer.feed(byte_str[i - 1:i + 1], - char_len) - self.distribution_analyzer.feed(byte_str[i - 1:i + 1], - char_len) - - self._last_char[0] = byte_str[-1] - - if self.state == ProbingState.DETECTING: - if (self.context_analyzer.got_enough_data() and - (self.get_confidence() > self.SHORTCUT_THRESHOLD)): - self._state = ProbingState.FOUND_IT - - return self.state - - def get_confidence(self): - context_conf = self.context_analyzer.get_confidence() - distrib_conf = self.distribution_analyzer.get_confidence() - return max(context_conf, distrib_conf) diff --git a/venv/lib/python3.8/site-packages/chardet/euckrfreq.py b/venv/lib/python3.8/site-packages/chardet/euckrfreq.py deleted file mode 100644 index b68078c..0000000 --- a/venv/lib/python3.8/site-packages/chardet/euckrfreq.py +++ /dev/null @@ -1,195 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is Mozilla Communicator client code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -# Sampling from about 20M text materials include literature and computer technology - -# 128 --> 0.79 -# 256 --> 0.92 -# 512 --> 0.986 -# 1024 --> 0.99944 -# 2048 --> 0.99999 -# -# Idea Distribution Ratio = 0.98653 / (1-0.98653) = 73.24 -# Random Distribution Ration = 512 / (2350-512) = 0.279. -# -# Typical Distribution Ratio - -EUCKR_TYPICAL_DISTRIBUTION_RATIO = 6.0 - -EUCKR_TABLE_SIZE = 2352 - -# Char to FreqOrder table , -EUCKR_CHAR_TO_FREQ_ORDER = ( - 13, 130, 120,1396, 481,1719,1720, 328, 609, 212,1721, 707, 400, 299,1722, 87, -1397,1723, 104, 536,1117,1203,1724,1267, 685,1268, 508,1725,1726,1727,1728,1398, -1399,1729,1730,1731, 141, 621, 326,1057, 368,1732, 267, 488, 20,1733,1269,1734, - 945,1400,1735, 47, 904,1270,1736,1737, 773, 248,1738, 409, 313, 786, 429,1739, - 116, 987, 813,1401, 683, 75,1204, 145,1740,1741,1742,1743, 16, 847, 667, 622, - 708,1744,1745,1746, 966, 787, 304, 129,1747, 60, 820, 123, 676,1748,1749,1750, -1751, 617,1752, 626,1753,1754,1755,1756, 653,1757,1758,1759,1760,1761,1762, 856, - 344,1763,1764,1765,1766, 89, 401, 418, 806, 905, 848,1767,1768,1769, 946,1205, - 709,1770,1118,1771, 241,1772,1773,1774,1271,1775, 569,1776, 999,1777,1778,1779, -1780, 337, 751,1058, 28, 628, 254,1781, 177, 906, 270, 349, 891,1079,1782, 19, -1783, 379,1784, 315,1785, 629, 754,1402, 559,1786, 636, 203,1206,1787, 710, 567, -1788, 935, 814,1789,1790,1207, 766, 528,1791,1792,1208,1793,1794,1795,1796,1797, -1403,1798,1799, 533,1059,1404,1405,1156,1406, 936, 884,1080,1800, 351,1801,1802, -1803,1804,1805, 801,1806,1807,1808,1119,1809,1157, 714, 474,1407,1810, 298, 899, - 885,1811,1120, 802,1158,1812, 892,1813,1814,1408, 659,1815,1816,1121,1817,1818, -1819,1820,1821,1822, 319,1823, 594, 545,1824, 815, 937,1209,1825,1826, 573,1409, -1022,1827,1210,1828,1829,1830,1831,1832,1833, 556, 722, 807,1122,1060,1834, 697, -1835, 900, 557, 715,1836,1410, 540,1411, 752,1159, 294, 597,1211, 976, 803, 770, -1412,1837,1838, 39, 794,1413, 358,1839, 371, 925,1840, 453, 661, 788, 531, 723, - 544,1023,1081, 869, 91,1841, 392, 430, 790, 602,1414, 677,1082, 457,1415,1416, -1842,1843, 475, 327,1024,1417, 795, 121,1844, 733, 403,1418,1845,1846,1847, 300, - 119, 711,1212, 627,1848,1272, 207,1849,1850, 796,1213, 382,1851, 519,1852,1083, - 893,1853,1854,1855, 367, 809, 487, 671,1856, 663,1857,1858, 956, 471, 306, 857, -1859,1860,1160,1084,1861,1862,1863,1864,1865,1061,1866,1867,1868,1869,1870,1871, - 282, 96, 574,1872, 502,1085,1873,1214,1874, 907,1875,1876, 827, 977,1419,1420, -1421, 268,1877,1422,1878,1879,1880, 308,1881, 2, 537,1882,1883,1215,1884,1885, - 127, 791,1886,1273,1423,1887, 34, 336, 404, 643,1888, 571, 654, 894, 840,1889, - 0, 886,1274, 122, 575, 260, 908, 938,1890,1275, 410, 316,1891,1892, 100,1893, -1894,1123, 48,1161,1124,1025,1895, 633, 901,1276,1896,1897, 115, 816,1898, 317, -1899, 694,1900, 909, 734,1424, 572, 866,1425, 691, 85, 524,1010, 543, 394, 841, -1901,1902,1903,1026,1904,1905,1906,1907,1908,1909, 30, 451, 651, 988, 310,1910, -1911,1426, 810,1216, 93,1912,1913,1277,1217,1914, 858, 759, 45, 58, 181, 610, - 269,1915,1916, 131,1062, 551, 443,1000, 821,1427, 957, 895,1086,1917,1918, 375, -1919, 359,1920, 687,1921, 822,1922, 293,1923,1924, 40, 662, 118, 692, 29, 939, - 887, 640, 482, 174,1925, 69,1162, 728,1428, 910,1926,1278,1218,1279, 386, 870, - 217, 854,1163, 823,1927,1928,1929,1930, 834,1931, 78,1932, 859,1933,1063,1934, -1935,1936,1937, 438,1164, 208, 595,1938,1939,1940,1941,1219,1125,1942, 280, 888, -1429,1430,1220,1431,1943,1944,1945,1946,1947,1280, 150, 510,1432,1948,1949,1950, -1951,1952,1953,1954,1011,1087,1955,1433,1043,1956, 881,1957, 614, 958,1064,1065, -1221,1958, 638,1001, 860, 967, 896,1434, 989, 492, 553,1281,1165,1959,1282,1002, -1283,1222,1960,1961,1962,1963, 36, 383, 228, 753, 247, 454,1964, 876, 678,1965, -1966,1284, 126, 464, 490, 835, 136, 672, 529, 940,1088,1435, 473,1967,1968, 467, - 50, 390, 227, 587, 279, 378, 598, 792, 968, 240, 151, 160, 849, 882,1126,1285, - 639,1044, 133, 140, 288, 360, 811, 563,1027, 561, 142, 523,1969,1970,1971, 7, - 103, 296, 439, 407, 506, 634, 990,1972,1973,1974,1975, 645,1976,1977,1978,1979, -1980,1981, 236,1982,1436,1983,1984,1089, 192, 828, 618, 518,1166, 333,1127,1985, - 818,1223,1986,1987,1988,1989,1990,1991,1992,1993, 342,1128,1286, 746, 842,1994, -1995, 560, 223,1287, 98, 8, 189, 650, 978,1288,1996,1437,1997, 17, 345, 250, - 423, 277, 234, 512, 226, 97, 289, 42, 167,1998, 201,1999,2000, 843, 836, 824, - 532, 338, 783,1090, 182, 576, 436,1438,1439, 527, 500,2001, 947, 889,2002,2003, -2004,2005, 262, 600, 314, 447,2006, 547,2007, 693, 738,1129,2008, 71,1440, 745, - 619, 688,2009, 829,2010,2011, 147,2012, 33, 948,2013,2014, 74, 224,2015, 61, - 191, 918, 399, 637,2016,1028,1130, 257, 902,2017,2018,2019,2020,2021,2022,2023, -2024,2025,2026, 837,2027,2028,2029,2030, 179, 874, 591, 52, 724, 246,2031,2032, -2033,2034,1167, 969,2035,1289, 630, 605, 911,1091,1168,2036,2037,2038,1441, 912, -2039, 623,2040,2041, 253,1169,1290,2042,1442, 146, 620, 611, 577, 433,2043,1224, - 719,1170, 959, 440, 437, 534, 84, 388, 480,1131, 159, 220, 198, 679,2044,1012, - 819,1066,1443, 113,1225, 194, 318,1003,1029,2045,2046,2047,2048,1067,2049,2050, -2051,2052,2053, 59, 913, 112,2054, 632,2055, 455, 144, 739,1291,2056, 273, 681, - 499,2057, 448,2058,2059, 760,2060,2061, 970, 384, 169, 245,1132,2062,2063, 414, -1444,2064,2065, 41, 235,2066, 157, 252, 877, 568, 919, 789, 580,2067, 725,2068, -2069,1292,2070,2071,1445,2072,1446,2073,2074, 55, 588, 66,1447, 271,1092,2075, -1226,2076, 960,1013, 372,2077,2078,2079,2080,2081,1293,2082,2083,2084,2085, 850, -2086,2087,2088,2089,2090, 186,2091,1068, 180,2092,2093,2094, 109,1227, 522, 606, -2095, 867,1448,1093, 991,1171, 926, 353,1133,2096, 581,2097,2098,2099,1294,1449, -1450,2100, 596,1172,1014,1228,2101,1451,1295,1173,1229,2102,2103,1296,1134,1452, - 949,1135,2104,2105,1094,1453,1454,1455,2106,1095,2107,2108,2109,2110,2111,2112, -2113,2114,2115,2116,2117, 804,2118,2119,1230,1231, 805,1456, 405,1136,2120,2121, -2122,2123,2124, 720, 701,1297, 992,1457, 927,1004,2125,2126,2127,2128,2129,2130, - 22, 417,2131, 303,2132, 385,2133, 971, 520, 513,2134,1174, 73,1096, 231, 274, - 962,1458, 673,2135,1459,2136, 152,1137,2137,2138,2139,2140,1005,1138,1460,1139, -2141,2142,2143,2144, 11, 374, 844,2145, 154,1232, 46,1461,2146, 838, 830, 721, -1233, 106,2147, 90, 428, 462, 578, 566,1175, 352,2148,2149, 538,1234, 124,1298, -2150,1462, 761, 565,2151, 686,2152, 649,2153, 72, 173,2154, 460, 415,2155,1463, -2156,1235, 305,2157,2158,2159,2160,2161,2162, 579,2163,2164,2165,2166,2167, 747, -2168,2169,2170,2171,1464, 669,2172,2173,2174,2175,2176,1465,2177, 23, 530, 285, -2178, 335, 729,2179, 397,2180,2181,2182,1030,2183,2184, 698,2185,2186, 325,2187, -2188, 369,2189, 799,1097,1015, 348,2190,1069, 680,2191, 851,1466,2192,2193, 10, -2194, 613, 424,2195, 979, 108, 449, 589, 27, 172, 81,1031, 80, 774, 281, 350, -1032, 525, 301, 582,1176,2196, 674,1045,2197,2198,1467, 730, 762,2199,2200,2201, -2202,1468,2203, 993,2204,2205, 266,1070, 963,1140,2206,2207,2208, 664,1098, 972, -2209,2210,2211,1177,1469,1470, 871,2212,2213,2214,2215,2216,1471,2217,2218,2219, -2220,2221,2222,2223,2224,2225,2226,2227,1472,1236,2228,2229,2230,2231,2232,2233, -2234,2235,1299,2236,2237, 200,2238, 477, 373,2239,2240, 731, 825, 777,2241,2242, -2243, 521, 486, 548,2244,2245,2246,1473,1300, 53, 549, 137, 875, 76, 158,2247, -1301,1474, 469, 396,1016, 278, 712,2248, 321, 442, 503, 767, 744, 941,1237,1178, -1475,2249, 82, 178,1141,1179, 973,2250,1302,2251, 297,2252,2253, 570,2254,2255, -2256, 18, 450, 206,2257, 290, 292,1142,2258, 511, 162, 99, 346, 164, 735,2259, -1476,1477, 4, 554, 343, 798,1099,2260,1100,2261, 43, 171,1303, 139, 215,2262, -2263, 717, 775,2264,1033, 322, 216,2265, 831,2266, 149,2267,1304,2268,2269, 702, -1238, 135, 845, 347, 309,2270, 484,2271, 878, 655, 238,1006,1478,2272, 67,2273, - 295,2274,2275, 461,2276, 478, 942, 412,2277,1034,2278,2279,2280, 265,2281, 541, -2282,2283,2284,2285,2286, 70, 852,1071,2287,2288,2289,2290, 21, 56, 509, 117, - 432,2291,2292, 331, 980, 552,1101, 148, 284, 105, 393,1180,1239, 755,2293, 187, -2294,1046,1479,2295, 340,2296, 63,1047, 230,2297,2298,1305, 763,1306, 101, 800, - 808, 494,2299,2300,2301, 903,2302, 37,1072, 14, 5,2303, 79, 675,2304, 312, -2305,2306,2307,2308,2309,1480, 6,1307,2310,2311,2312, 1, 470, 35, 24, 229, -2313, 695, 210, 86, 778, 15, 784, 592, 779, 32, 77, 855, 964,2314, 259,2315, - 501, 380,2316,2317, 83, 981, 153, 689,1308,1481,1482,1483,2318,2319, 716,1484, -2320,2321,2322,2323,2324,2325,1485,2326,2327, 128, 57, 68, 261,1048, 211, 170, -1240, 31,2328, 51, 435, 742,2329,2330,2331, 635,2332, 264, 456,2333,2334,2335, - 425,2336,1486, 143, 507, 263, 943,2337, 363, 920,1487, 256,1488,1102, 243, 601, -1489,2338,2339,2340,2341,2342,2343,2344, 861,2345,2346,2347,2348,2349,2350, 395, -2351,1490,1491, 62, 535, 166, 225,2352,2353, 668, 419,1241, 138, 604, 928,2354, -1181,2355,1492,1493,2356,2357,2358,1143,2359, 696,2360, 387, 307,1309, 682, 476, -2361,2362, 332, 12, 222, 156,2363, 232,2364, 641, 276, 656, 517,1494,1495,1035, - 416, 736,1496,2365,1017, 586,2366,2367,2368,1497,2369, 242,2370,2371,2372,1498, -2373, 965, 713,2374,2375,2376,2377, 740, 982,1499, 944,1500,1007,2378,2379,1310, -1501,2380,2381,2382, 785, 329,2383,2384,1502,2385,2386,2387, 932,2388,1503,2389, -2390,2391,2392,1242,2393,2394,2395,2396,2397, 994, 950,2398,2399,2400,2401,1504, -1311,2402,2403,2404,2405,1049, 749,2406,2407, 853, 718,1144,1312,2408,1182,1505, -2409,2410, 255, 516, 479, 564, 550, 214,1506,1507,1313, 413, 239, 444, 339,1145, -1036,1508,1509,1314,1037,1510,1315,2411,1511,2412,2413,2414, 176, 703, 497, 624, - 593, 921, 302,2415, 341, 165,1103,1512,2416,1513,2417,2418,2419, 376,2420, 700, -2421,2422,2423, 258, 768,1316,2424,1183,2425, 995, 608,2426,2427,2428,2429, 221, -2430,2431,2432,2433,2434,2435,2436,2437, 195, 323, 726, 188, 897, 983,1317, 377, - 644,1050, 879,2438, 452,2439,2440,2441,2442,2443,2444, 914,2445,2446,2447,2448, - 915, 489,2449,1514,1184,2450,2451, 515, 64, 427, 495,2452, 583,2453, 483, 485, -1038, 562, 213,1515, 748, 666,2454,2455,2456,2457, 334,2458, 780, 996,1008, 705, -1243,2459,2460,2461,2462,2463, 114,2464, 493,1146, 366, 163,1516, 961,1104,2465, - 291,2466,1318,1105,2467,1517, 365,2468, 355, 951,1244,2469,1319,2470, 631,2471, -2472, 218,1320, 364, 320, 756,1518,1519,1321,1520,1322,2473,2474,2475,2476, 997, -2477,2478,2479,2480, 665,1185,2481, 916,1521,2482,2483,2484, 584, 684,2485,2486, - 797,2487,1051,1186,2488,2489,2490,1522,2491,2492, 370,2493,1039,1187, 65,2494, - 434, 205, 463,1188,2495, 125, 812, 391, 402, 826, 699, 286, 398, 155, 781, 771, - 585,2496, 590, 505,1073,2497, 599, 244, 219, 917,1018, 952, 646,1523,2498,1323, -2499,2500, 49, 984, 354, 741,2501, 625,2502,1324,2503,1019, 190, 357, 757, 491, - 95, 782, 868,2504,2505,2506,2507,2508,2509, 134,1524,1074, 422,1525, 898,2510, - 161,2511,2512,2513,2514, 769,2515,1526,2516,2517, 411,1325,2518, 472,1527,2519, -2520,2521,2522,2523,2524, 985,2525,2526,2527,2528,2529,2530, 764,2531,1245,2532, -2533, 25, 204, 311,2534, 496,2535,1052,2536,2537,2538,2539,2540,2541,2542, 199, - 704, 504, 468, 758, 657,1528, 196, 44, 839,1246, 272, 750,2543, 765, 862,2544, -2545,1326,2546, 132, 615, 933,2547, 732,2548,2549,2550,1189,1529,2551, 283,1247, -1053, 607, 929,2552,2553,2554, 930, 183, 872, 616,1040,1147,2555,1148,1020, 441, - 249,1075,2556,2557,2558, 466, 743,2559,2560,2561, 92, 514, 426, 420, 526,2562, -2563,2564,2565,2566,2567,2568, 185,2569,2570,2571,2572, 776,1530, 658,2573, 362, -2574, 361, 922,1076, 793,2575,2576,2577,2578,2579,2580,1531, 251,2581,2582,2583, -2584,1532, 54, 612, 237,1327,2585,2586, 275, 408, 647, 111,2587,1533,1106, 465, - 3, 458, 9, 38,2588, 107, 110, 890, 209, 26, 737, 498,2589,1534,2590, 431, - 202, 88,1535, 356, 287,1107, 660,1149,2591, 381,1536, 986,1150, 445,1248,1151, - 974,2592,2593, 846,2594, 446, 953, 184,1249,1250, 727,2595, 923, 193, 883,2596, -2597,2598, 102, 324, 539, 817,2599, 421,1041,2600, 832,2601, 94, 175, 197, 406, -2602, 459,2603,2604,2605,2606,2607, 330, 555,2608,2609,2610, 706,1108, 389,2611, -2612,2613,2614, 233,2615, 833, 558, 931, 954,1251,2616,2617,1537, 546,2618,2619, -1009,2620,2621,2622,1538, 690,1328,2623, 955,2624,1539,2625,2626, 772,2627,2628, -2629,2630,2631, 924, 648, 863, 603,2632,2633, 934,1540, 864, 865,2634, 642,1042, - 670,1190,2635,2636,2637,2638, 168,2639, 652, 873, 542,1054,1541,2640,2641,2642, # 512, 256 -) - diff --git a/venv/lib/python3.8/site-packages/chardet/euckrprober.py b/venv/lib/python3.8/site-packages/chardet/euckrprober.py deleted file mode 100644 index 345a060..0000000 --- a/venv/lib/python3.8/site-packages/chardet/euckrprober.py +++ /dev/null @@ -1,47 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is mozilla.org code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -from .mbcharsetprober import MultiByteCharSetProber -from .codingstatemachine import CodingStateMachine -from .chardistribution import EUCKRDistributionAnalysis -from .mbcssm import EUCKR_SM_MODEL - - -class EUCKRProber(MultiByteCharSetProber): - def __init__(self): - super(EUCKRProber, self).__init__() - self.coding_sm = CodingStateMachine(EUCKR_SM_MODEL) - self.distribution_analyzer = EUCKRDistributionAnalysis() - self.reset() - - @property - def charset_name(self): - return "EUC-KR" - - @property - def language(self): - return "Korean" diff --git a/venv/lib/python3.8/site-packages/chardet/euctwfreq.py b/venv/lib/python3.8/site-packages/chardet/euctwfreq.py deleted file mode 100644 index ed7a995..0000000 --- a/venv/lib/python3.8/site-packages/chardet/euctwfreq.py +++ /dev/null @@ -1,387 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is Mozilla Communicator client code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -# EUCTW frequency table -# Converted from big5 work -# by Taiwan's Mandarin Promotion Council -# <http:#www.edu.tw:81/mandr/> - -# 128 --> 0.42261 -# 256 --> 0.57851 -# 512 --> 0.74851 -# 1024 --> 0.89384 -# 2048 --> 0.97583 -# -# Idea Distribution Ratio = 0.74851/(1-0.74851) =2.98 -# Random Distribution Ration = 512/(5401-512)=0.105 -# -# Typical Distribution Ratio about 25% of Ideal one, still much higher than RDR - -EUCTW_TYPICAL_DISTRIBUTION_RATIO = 0.75 - -# Char to FreqOrder table , -EUCTW_TABLE_SIZE = 5376 - -EUCTW_CHAR_TO_FREQ_ORDER = ( - 1,1800,1506, 255,1431, 198, 9, 82, 6,7310, 177, 202,3615,1256,2808, 110, # 2742 -3735, 33,3241, 261, 76, 44,2113, 16,2931,2184,1176, 659,3868, 26,3404,2643, # 2758 -1198,3869,3313,4060, 410,2211, 302, 590, 361,1963, 8, 204, 58,4296,7311,1931, # 2774 - 63,7312,7313, 317,1614, 75, 222, 159,4061,2412,1480,7314,3500,3068, 224,2809, # 2790 -3616, 3, 10,3870,1471, 29,2774,1135,2852,1939, 873, 130,3242,1123, 312,7315, # 2806 -4297,2051, 507, 252, 682,7316, 142,1914, 124, 206,2932, 34,3501,3173, 64, 604, # 2822 -7317,2494,1976,1977, 155,1990, 645, 641,1606,7318,3405, 337, 72, 406,7319, 80, # 2838 - 630, 238,3174,1509, 263, 939,1092,2644, 756,1440,1094,3406, 449, 69,2969, 591, # 2854 - 179,2095, 471, 115,2034,1843, 60, 50,2970, 134, 806,1868, 734,2035,3407, 180, # 2870 - 995,1607, 156, 537,2893, 688,7320, 319,1305, 779,2144, 514,2374, 298,4298, 359, # 2886 -2495, 90,2707,1338, 663, 11, 906,1099,2545, 20,2436, 182, 532,1716,7321, 732, # 2902 -1376,4062,1311,1420,3175, 25,2312,1056, 113, 399, 382,1949, 242,3408,2467, 529, # 2918 -3243, 475,1447,3617,7322, 117, 21, 656, 810,1297,2295,2329,3502,7323, 126,4063, # 2934 - 706, 456, 150, 613,4299, 71,1118,2036,4064, 145,3069, 85, 835, 486,2114,1246, # 2950 -1426, 428, 727,1285,1015, 800, 106, 623, 303,1281,7324,2127,2354, 347,3736, 221, # 2966 -3503,3110,7325,1955,1153,4065, 83, 296,1199,3070, 192, 624, 93,7326, 822,1897, # 2982 -2810,3111, 795,2064, 991,1554,1542,1592, 27, 43,2853, 859, 139,1456, 860,4300, # 2998 - 437, 712,3871, 164,2392,3112, 695, 211,3017,2096, 195,3872,1608,3504,3505,3618, # 3014 -3873, 234, 811,2971,2097,3874,2229,1441,3506,1615,2375, 668,2076,1638, 305, 228, # 3030 -1664,4301, 467, 415,7327, 262,2098,1593, 239, 108, 300, 200,1033, 512,1247,2077, # 3046 -7328,7329,2173,3176,3619,2673, 593, 845,1062,3244, 88,1723,2037,3875,1950, 212, # 3062 - 266, 152, 149, 468,1898,4066,4302, 77, 187,7330,3018, 37, 5,2972,7331,3876, # 3078 -7332,7333, 39,2517,4303,2894,3177,2078, 55, 148, 74,4304, 545, 483,1474,1029, # 3094 -1665, 217,1869,1531,3113,1104,2645,4067, 24, 172,3507, 900,3877,3508,3509,4305, # 3110 - 32,1408,2811,1312, 329, 487,2355,2247,2708, 784,2674, 4,3019,3314,1427,1788, # 3126 - 188, 109, 499,7334,3620,1717,1789, 888,1217,3020,4306,7335,3510,7336,3315,1520, # 3142 -3621,3878, 196,1034, 775,7337,7338, 929,1815, 249, 439, 38,7339,1063,7340, 794, # 3158 -3879,1435,2296, 46, 178,3245,2065,7341,2376,7342, 214,1709,4307, 804, 35, 707, # 3174 - 324,3622,1601,2546, 140, 459,4068,7343,7344,1365, 839, 272, 978,2257,2572,3409, # 3190 -2128,1363,3623,1423, 697, 100,3071, 48, 70,1231, 495,3114,2193,7345,1294,7346, # 3206 -2079, 462, 586,1042,3246, 853, 256, 988, 185,2377,3410,1698, 434,1084,7347,3411, # 3222 - 314,2615,2775,4308,2330,2331, 569,2280, 637,1816,2518, 757,1162,1878,1616,3412, # 3238 - 287,1577,2115, 768,4309,1671,2854,3511,2519,1321,3737, 909,2413,7348,4069, 933, # 3254 -3738,7349,2052,2356,1222,4310, 765,2414,1322, 786,4311,7350,1919,1462,1677,2895, # 3270 -1699,7351,4312,1424,2437,3115,3624,2590,3316,1774,1940,3413,3880,4070, 309,1369, # 3286 -1130,2812, 364,2230,1653,1299,3881,3512,3882,3883,2646, 525,1085,3021, 902,2000, # 3302 -1475, 964,4313, 421,1844,1415,1057,2281, 940,1364,3116, 376,4314,4315,1381, 7, # 3318 -2520, 983,2378, 336,1710,2675,1845, 321,3414, 559,1131,3022,2742,1808,1132,1313, # 3334 - 265,1481,1857,7352, 352,1203,2813,3247, 167,1089, 420,2814, 776, 792,1724,3513, # 3350 -4071,2438,3248,7353,4072,7354, 446, 229, 333,2743, 901,3739,1200,1557,4316,2647, # 3366 -1920, 395,2744,2676,3740,4073,1835, 125, 916,3178,2616,4317,7355,7356,3741,7357, # 3382 -7358,7359,4318,3117,3625,1133,2547,1757,3415,1510,2313,1409,3514,7360,2145, 438, # 3398 -2591,2896,2379,3317,1068, 958,3023, 461, 311,2855,2677,4074,1915,3179,4075,1978, # 3414 - 383, 750,2745,2617,4076, 274, 539, 385,1278,1442,7361,1154,1964, 384, 561, 210, # 3430 - 98,1295,2548,3515,7362,1711,2415,1482,3416,3884,2897,1257, 129,7363,3742, 642, # 3446 - 523,2776,2777,2648,7364, 141,2231,1333, 68, 176, 441, 876, 907,4077, 603,2592, # 3462 - 710, 171,3417, 404, 549, 18,3118,2393,1410,3626,1666,7365,3516,4319,2898,4320, # 3478 -7366,2973, 368,7367, 146, 366, 99, 871,3627,1543, 748, 807,1586,1185, 22,2258, # 3494 - 379,3743,3180,7368,3181, 505,1941,2618,1991,1382,2314,7369, 380,2357, 218, 702, # 3510 -1817,1248,3418,3024,3517,3318,3249,7370,2974,3628, 930,3250,3744,7371, 59,7372, # 3526 - 585, 601,4078, 497,3419,1112,1314,4321,1801,7373,1223,1472,2174,7374, 749,1836, # 3542 - 690,1899,3745,1772,3885,1476, 429,1043,1790,2232,2116, 917,4079, 447,1086,1629, # 3558 -7375, 556,7376,7377,2020,1654, 844,1090, 105, 550, 966,1758,2815,1008,1782, 686, # 3574 -1095,7378,2282, 793,1602,7379,3518,2593,4322,4080,2933,2297,4323,3746, 980,2496, # 3590 - 544, 353, 527,4324, 908,2678,2899,7380, 381,2619,1942,1348,7381,1341,1252, 560, # 3606 -3072,7382,3420,2856,7383,2053, 973, 886,2080, 143,4325,7384,7385, 157,3886, 496, # 3622 -4081, 57, 840, 540,2038,4326,4327,3421,2117,1445, 970,2259,1748,1965,2081,4082, # 3638 -3119,1234,1775,3251,2816,3629, 773,1206,2129,1066,2039,1326,3887,1738,1725,4083, # 3654 - 279,3120, 51,1544,2594, 423,1578,2130,2066, 173,4328,1879,7386,7387,1583, 264, # 3670 - 610,3630,4329,2439, 280, 154,7388,7389,7390,1739, 338,1282,3073, 693,2857,1411, # 3686 -1074,3747,2440,7391,4330,7392,7393,1240, 952,2394,7394,2900,1538,2679, 685,1483, # 3702 -4084,2468,1436, 953,4085,2054,4331, 671,2395, 79,4086,2441,3252, 608, 567,2680, # 3718 -3422,4087,4088,1691, 393,1261,1791,2396,7395,4332,7396,7397,7398,7399,1383,1672, # 3734 -3748,3182,1464, 522,1119, 661,1150, 216, 675,4333,3888,1432,3519, 609,4334,2681, # 3750 -2397,7400,7401,7402,4089,3025, 0,7403,2469, 315, 231,2442, 301,3319,4335,2380, # 3766 -7404, 233,4090,3631,1818,4336,4337,7405, 96,1776,1315,2082,7406, 257,7407,1809, # 3782 -3632,2709,1139,1819,4091,2021,1124,2163,2778,1777,2649,7408,3074, 363,1655,3183, # 3798 -7409,2975,7410,7411,7412,3889,1567,3890, 718, 103,3184, 849,1443, 341,3320,2934, # 3814 -1484,7413,1712, 127, 67, 339,4092,2398, 679,1412, 821,7414,7415, 834, 738, 351, # 3830 -2976,2146, 846, 235,1497,1880, 418,1992,3749,2710, 186,1100,2147,2746,3520,1545, # 3846 -1355,2935,2858,1377, 583,3891,4093,2573,2977,7416,1298,3633,1078,2549,3634,2358, # 3862 - 78,3750,3751, 267,1289,2099,2001,1594,4094, 348, 369,1274,2194,2175,1837,4338, # 3878 -1820,2817,3635,2747,2283,2002,4339,2936,2748, 144,3321, 882,4340,3892,2749,3423, # 3894 -4341,2901,7417,4095,1726, 320,7418,3893,3026, 788,2978,7419,2818,1773,1327,2859, # 3910 -3894,2819,7420,1306,4342,2003,1700,3752,3521,2359,2650, 787,2022, 506, 824,3636, # 3926 - 534, 323,4343,1044,3322,2023,1900, 946,3424,7421,1778,1500,1678,7422,1881,4344, # 3942 - 165, 243,4345,3637,2521, 123, 683,4096, 764,4346, 36,3895,1792, 589,2902, 816, # 3958 - 626,1667,3027,2233,1639,1555,1622,3753,3896,7423,3897,2860,1370,1228,1932, 891, # 3974 -2083,2903, 304,4097,7424, 292,2979,2711,3522, 691,2100,4098,1115,4347, 118, 662, # 3990 -7425, 611,1156, 854,2381,1316,2861, 2, 386, 515,2904,7426,7427,3253, 868,2234, # 4006 -1486, 855,2651, 785,2212,3028,7428,1040,3185,3523,7429,3121, 448,7430,1525,7431, # 4022 -2164,4348,7432,3754,7433,4099,2820,3524,3122, 503, 818,3898,3123,1568, 814, 676, # 4038 -1444, 306,1749,7434,3755,1416,1030, 197,1428, 805,2821,1501,4349,7435,7436,7437, # 4054 -1993,7438,4350,7439,7440,2195, 13,2779,3638,2980,3124,1229,1916,7441,3756,2131, # 4070 -7442,4100,4351,2399,3525,7443,2213,1511,1727,1120,7444,7445, 646,3757,2443, 307, # 4086 -7446,7447,1595,3186,7448,7449,7450,3639,1113,1356,3899,1465,2522,2523,7451, 519, # 4102 -7452, 128,2132, 92,2284,1979,7453,3900,1512, 342,3125,2196,7454,2780,2214,1980, # 4118 -3323,7455, 290,1656,1317, 789, 827,2360,7456,3758,4352, 562, 581,3901,7457, 401, # 4134 -4353,2248, 94,4354,1399,2781,7458,1463,2024,4355,3187,1943,7459, 828,1105,4101, # 4150 -1262,1394,7460,4102, 605,4356,7461,1783,2862,7462,2822, 819,2101, 578,2197,2937, # 4166 -7463,1502, 436,3254,4103,3255,2823,3902,2905,3425,3426,7464,2712,2315,7465,7466, # 4182 -2332,2067, 23,4357, 193, 826,3759,2102, 699,1630,4104,3075, 390,1793,1064,3526, # 4198 -7467,1579,3076,3077,1400,7468,4105,1838,1640,2863,7469,4358,4359, 137,4106, 598, # 4214 -3078,1966, 780, 104, 974,2938,7470, 278, 899, 253, 402, 572, 504, 493,1339,7471, # 4230 -3903,1275,4360,2574,2550,7472,3640,3029,3079,2249, 565,1334,2713, 863, 41,7473, # 4246 -7474,4361,7475,1657,2333, 19, 463,2750,4107, 606,7476,2981,3256,1087,2084,1323, # 4262 -2652,2982,7477,1631,1623,1750,4108,2682,7478,2864, 791,2714,2653,2334, 232,2416, # 4278 -7479,2983,1498,7480,2654,2620, 755,1366,3641,3257,3126,2025,1609, 119,1917,3427, # 4294 - 862,1026,4109,7481,3904,3760,4362,3905,4363,2260,1951,2470,7482,1125, 817,4110, # 4310 -4111,3906,1513,1766,2040,1487,4112,3030,3258,2824,3761,3127,7483,7484,1507,7485, # 4326 -2683, 733, 40,1632,1106,2865, 345,4113, 841,2524, 230,4364,2984,1846,3259,3428, # 4342 -7486,1263, 986,3429,7487, 735, 879, 254,1137, 857, 622,1300,1180,1388,1562,3907, # 4358 -3908,2939, 967,2751,2655,1349, 592,2133,1692,3324,2985,1994,4114,1679,3909,1901, # 4374 -2185,7488, 739,3642,2715,1296,1290,7489,4115,2198,2199,1921,1563,2595,2551,1870, # 4390 -2752,2986,7490, 435,7491, 343,1108, 596, 17,1751,4365,2235,3430,3643,7492,4366, # 4406 - 294,3527,2940,1693, 477, 979, 281,2041,3528, 643,2042,3644,2621,2782,2261,1031, # 4422 -2335,2134,2298,3529,4367, 367,1249,2552,7493,3530,7494,4368,1283,3325,2004, 240, # 4438 -1762,3326,4369,4370, 836,1069,3128, 474,7495,2148,2525, 268,3531,7496,3188,1521, # 4454 -1284,7497,1658,1546,4116,7498,3532,3533,7499,4117,3327,2684,1685,4118, 961,1673, # 4470 -2622, 190,2005,2200,3762,4371,4372,7500, 570,2497,3645,1490,7501,4373,2623,3260, # 4486 -1956,4374, 584,1514, 396,1045,1944,7502,4375,1967,2444,7503,7504,4376,3910, 619, # 4502 -7505,3129,3261, 215,2006,2783,2553,3189,4377,3190,4378, 763,4119,3763,4379,7506, # 4518 -7507,1957,1767,2941,3328,3646,1174, 452,1477,4380,3329,3130,7508,2825,1253,2382, # 4534 -2186,1091,2285,4120, 492,7509, 638,1169,1824,2135,1752,3911, 648, 926,1021,1324, # 4550 -4381, 520,4382, 997, 847,1007, 892,4383,3764,2262,1871,3647,7510,2400,1784,4384, # 4566 -1952,2942,3080,3191,1728,4121,2043,3648,4385,2007,1701,3131,1551, 30,2263,4122, # 4582 -7511,2026,4386,3534,7512, 501,7513,4123, 594,3431,2165,1821,3535,3432,3536,3192, # 4598 - 829,2826,4124,7514,1680,3132,1225,4125,7515,3262,4387,4126,3133,2336,7516,4388, # 4614 -4127,7517,3912,3913,7518,1847,2383,2596,3330,7519,4389, 374,3914, 652,4128,4129, # 4630 - 375,1140, 798,7520,7521,7522,2361,4390,2264, 546,1659, 138,3031,2445,4391,7523, # 4646 -2250, 612,1848, 910, 796,3765,1740,1371, 825,3766,3767,7524,2906,2554,7525, 692, # 4662 - 444,3032,2624, 801,4392,4130,7526,1491, 244,1053,3033,4131,4132, 340,7527,3915, # 4678 -1041,2987, 293,1168, 87,1357,7528,1539, 959,7529,2236, 721, 694,4133,3768, 219, # 4694 -1478, 644,1417,3331,2656,1413,1401,1335,1389,3916,7530,7531,2988,2362,3134,1825, # 4710 - 730,1515, 184,2827, 66,4393,7532,1660,2943, 246,3332, 378,1457, 226,3433, 975, # 4726 -3917,2944,1264,3537, 674, 696,7533, 163,7534,1141,2417,2166, 713,3538,3333,4394, # 4742 -3918,7535,7536,1186, 15,7537,1079,1070,7538,1522,3193,3539, 276,1050,2716, 758, # 4758 -1126, 653,2945,3263,7539,2337, 889,3540,3919,3081,2989, 903,1250,4395,3920,3434, # 4774 -3541,1342,1681,1718, 766,3264, 286, 89,2946,3649,7540,1713,7541,2597,3334,2990, # 4790 -7542,2947,2215,3194,2866,7543,4396,2498,2526, 181, 387,1075,3921, 731,2187,3335, # 4806 -7544,3265, 310, 313,3435,2299, 770,4134, 54,3034, 189,4397,3082,3769,3922,7545, # 4822 -1230,1617,1849, 355,3542,4135,4398,3336, 111,4136,3650,1350,3135,3436,3035,4137, # 4838 -2149,3266,3543,7546,2784,3923,3924,2991, 722,2008,7547,1071, 247,1207,2338,2471, # 4854 -1378,4399,2009, 864,1437,1214,4400, 373,3770,1142,2216, 667,4401, 442,2753,2555, # 4870 -3771,3925,1968,4138,3267,1839, 837, 170,1107, 934,1336,1882,7548,7549,2118,4139, # 4886 -2828, 743,1569,7550,4402,4140, 582,2384,1418,3437,7551,1802,7552, 357,1395,1729, # 4902 -3651,3268,2418,1564,2237,7553,3083,3772,1633,4403,1114,2085,4141,1532,7554, 482, # 4918 -2446,4404,7555,7556,1492, 833,1466,7557,2717,3544,1641,2829,7558,1526,1272,3652, # 4934 -4142,1686,1794, 416,2556,1902,1953,1803,7559,3773,2785,3774,1159,2316,7560,2867, # 4950 -4405,1610,1584,3036,2419,2754, 443,3269,1163,3136,7561,7562,3926,7563,4143,2499, # 4966 -3037,4406,3927,3137,2103,1647,3545,2010,1872,4144,7564,4145, 431,3438,7565, 250, # 4982 - 97, 81,4146,7566,1648,1850,1558, 160, 848,7567, 866, 740,1694,7568,2201,2830, # 4998 -3195,4147,4407,3653,1687, 950,2472, 426, 469,3196,3654,3655,3928,7569,7570,1188, # 5014 - 424,1995, 861,3546,4148,3775,2202,2685, 168,1235,3547,4149,7571,2086,1674,4408, # 5030 -3337,3270, 220,2557,1009,7572,3776, 670,2992, 332,1208, 717,7573,7574,3548,2447, # 5046 -3929,3338,7575, 513,7576,1209,2868,3339,3138,4409,1080,7577,7578,7579,7580,2527, # 5062 -3656,3549, 815,1587,3930,3931,7581,3550,3439,3777,1254,4410,1328,3038,1390,3932, # 5078 -1741,3933,3778,3934,7582, 236,3779,2448,3271,7583,7584,3657,3780,1273,3781,4411, # 5094 -7585, 308,7586,4412, 245,4413,1851,2473,1307,2575, 430, 715,2136,2449,7587, 270, # 5110 - 199,2869,3935,7588,3551,2718,1753, 761,1754, 725,1661,1840,4414,3440,3658,7589, # 5126 -7590, 587, 14,3272, 227,2598, 326, 480,2265, 943,2755,3552, 291, 650,1883,7591, # 5142 -1702,1226, 102,1547, 62,3441, 904,4415,3442,1164,4150,7592,7593,1224,1548,2756, # 5158 - 391, 498,1493,7594,1386,1419,7595,2055,1177,4416, 813, 880,1081,2363, 566,1145, # 5174 -4417,2286,1001,1035,2558,2599,2238, 394,1286,7596,7597,2068,7598, 86,1494,1730, # 5190 -3936, 491,1588, 745, 897,2948, 843,3340,3937,2757,2870,3273,1768, 998,2217,2069, # 5206 - 397,1826,1195,1969,3659,2993,3341, 284,7599,3782,2500,2137,2119,1903,7600,3938, # 5222 -2150,3939,4151,1036,3443,1904, 114,2559,4152, 209,1527,7601,7602,2949,2831,2625, # 5238 -2385,2719,3139, 812,2560,7603,3274,7604,1559, 737,1884,3660,1210, 885, 28,2686, # 5254 -3553,3783,7605,4153,1004,1779,4418,7606, 346,1981,2218,2687,4419,3784,1742, 797, # 5270 -1642,3940,1933,1072,1384,2151, 896,3941,3275,3661,3197,2871,3554,7607,2561,1958, # 5286 -4420,2450,1785,7608,7609,7610,3942,4154,1005,1308,3662,4155,2720,4421,4422,1528, # 5302 -2600, 161,1178,4156,1982, 987,4423,1101,4157, 631,3943,1157,3198,2420,1343,1241, # 5318 -1016,2239,2562, 372, 877,2339,2501,1160, 555,1934, 911,3944,7611, 466,1170, 169, # 5334 -1051,2907,2688,3663,2474,2994,1182,2011,2563,1251,2626,7612, 992,2340,3444,1540, # 5350 -2721,1201,2070,2401,1996,2475,7613,4424, 528,1922,2188,1503,1873,1570,2364,3342, # 5366 -3276,7614, 557,1073,7615,1827,3445,2087,2266,3140,3039,3084, 767,3085,2786,4425, # 5382 -1006,4158,4426,2341,1267,2176,3664,3199, 778,3945,3200,2722,1597,2657,7616,4427, # 5398 -7617,3446,7618,7619,7620,3277,2689,1433,3278, 131, 95,1504,3946, 723,4159,3141, # 5414 -1841,3555,2758,2189,3947,2027,2104,3665,7621,2995,3948,1218,7622,3343,3201,3949, # 5430 -4160,2576, 248,1634,3785, 912,7623,2832,3666,3040,3786, 654, 53,7624,2996,7625, # 5446 -1688,4428, 777,3447,1032,3950,1425,7626, 191, 820,2120,2833, 971,4429, 931,3202, # 5462 - 135, 664, 783,3787,1997, 772,2908,1935,3951,3788,4430,2909,3203, 282,2723, 640, # 5478 -1372,3448,1127, 922, 325,3344,7627,7628, 711,2044,7629,7630,3952,2219,2787,1936, # 5494 -3953,3345,2220,2251,3789,2300,7631,4431,3790,1258,3279,3954,3204,2138,2950,3955, # 5510 -3956,7632,2221, 258,3205,4432, 101,1227,7633,3280,1755,7634,1391,3281,7635,2910, # 5526 -2056, 893,7636,7637,7638,1402,4161,2342,7639,7640,3206,3556,7641,7642, 878,1325, # 5542 -1780,2788,4433, 259,1385,2577, 744,1183,2267,4434,7643,3957,2502,7644, 684,1024, # 5558 -4162,7645, 472,3557,3449,1165,3282,3958,3959, 322,2152, 881, 455,1695,1152,1340, # 5574 - 660, 554,2153,4435,1058,4436,4163, 830,1065,3346,3960,4437,1923,7646,1703,1918, # 5590 -7647, 932,2268, 122,7648,4438, 947, 677,7649,3791,2627, 297,1905,1924,2269,4439, # 5606 -2317,3283,7650,7651,4164,7652,4165, 84,4166, 112, 989,7653, 547,1059,3961, 701, # 5622 -3558,1019,7654,4167,7655,3450, 942, 639, 457,2301,2451, 993,2951, 407, 851, 494, # 5638 -4440,3347, 927,7656,1237,7657,2421,3348, 573,4168, 680, 921,2911,1279,1874, 285, # 5654 - 790,1448,1983, 719,2167,7658,7659,4441,3962,3963,1649,7660,1541, 563,7661,1077, # 5670 -7662,3349,3041,3451, 511,2997,3964,3965,3667,3966,1268,2564,3350,3207,4442,4443, # 5686 -7663, 535,1048,1276,1189,2912,2028,3142,1438,1373,2834,2952,1134,2012,7664,4169, # 5702 -1238,2578,3086,1259,7665, 700,7666,2953,3143,3668,4170,7667,4171,1146,1875,1906, # 5718 -4444,2601,3967, 781,2422, 132,1589, 203, 147, 273,2789,2402, 898,1786,2154,3968, # 5734 -3969,7668,3792,2790,7669,7670,4445,4446,7671,3208,7672,1635,3793, 965,7673,1804, # 5750 -2690,1516,3559,1121,1082,1329,3284,3970,1449,3794, 65,1128,2835,2913,2759,1590, # 5766 -3795,7674,7675, 12,2658, 45, 976,2579,3144,4447, 517,2528,1013,1037,3209,7676, # 5782 -3796,2836,7677,3797,7678,3452,7679,2602, 614,1998,2318,3798,3087,2724,2628,7680, # 5798 -2580,4172, 599,1269,7681,1810,3669,7682,2691,3088, 759,1060, 489,1805,3351,3285, # 5814 -1358,7683,7684,2386,1387,1215,2629,2252, 490,7685,7686,4173,1759,2387,2343,7687, # 5830 -4448,3799,1907,3971,2630,1806,3210,4449,3453,3286,2760,2344, 874,7688,7689,3454, # 5846 -3670,1858, 91,2914,3671,3042,3800,4450,7690,3145,3972,2659,7691,3455,1202,1403, # 5862 -3801,2954,2529,1517,2503,4451,3456,2504,7692,4452,7693,2692,1885,1495,1731,3973, # 5878 -2365,4453,7694,2029,7695,7696,3974,2693,1216, 237,2581,4174,2319,3975,3802,4454, # 5894 -4455,2694,3560,3457, 445,4456,7697,7698,7699,7700,2761, 61,3976,3672,1822,3977, # 5910 -7701, 687,2045, 935, 925, 405,2660, 703,1096,1859,2725,4457,3978,1876,1367,2695, # 5926 -3352, 918,2105,1781,2476, 334,3287,1611,1093,4458, 564,3146,3458,3673,3353, 945, # 5942 -2631,2057,4459,7702,1925, 872,4175,7703,3459,2696,3089, 349,4176,3674,3979,4460, # 5958 -3803,4177,3675,2155,3980,4461,4462,4178,4463,2403,2046, 782,3981, 400, 251,4179, # 5974 -1624,7704,7705, 277,3676, 299,1265, 476,1191,3804,2121,4180,4181,1109, 205,7706, # 5990 -2582,1000,2156,3561,1860,7707,7708,7709,4464,7710,4465,2565, 107,2477,2157,3982, # 6006 -3460,3147,7711,1533, 541,1301, 158, 753,4182,2872,3562,7712,1696, 370,1088,4183, # 6022 -4466,3563, 579, 327, 440, 162,2240, 269,1937,1374,3461, 968,3043, 56,1396,3090, # 6038 -2106,3288,3354,7713,1926,2158,4467,2998,7714,3564,7715,7716,3677,4468,2478,7717, # 6054 -2791,7718,1650,4469,7719,2603,7720,7721,3983,2661,3355,1149,3356,3984,3805,3985, # 6070 -7722,1076, 49,7723, 951,3211,3289,3290, 450,2837, 920,7724,1811,2792,2366,4184, # 6086 -1908,1138,2367,3806,3462,7725,3212,4470,1909,1147,1518,2423,4471,3807,7726,4472, # 6102 -2388,2604, 260,1795,3213,7727,7728,3808,3291, 708,7729,3565,1704,7730,3566,1351, # 6118 -1618,3357,2999,1886, 944,4185,3358,4186,3044,3359,4187,7731,3678, 422, 413,1714, # 6134 -3292, 500,2058,2345,4188,2479,7732,1344,1910, 954,7733,1668,7734,7735,3986,2404, # 6150 -4189,3567,3809,4190,7736,2302,1318,2505,3091, 133,3092,2873,4473, 629, 31,2838, # 6166 -2697,3810,4474, 850, 949,4475,3987,2955,1732,2088,4191,1496,1852,7737,3988, 620, # 6182 -3214, 981,1242,3679,3360,1619,3680,1643,3293,2139,2452,1970,1719,3463,2168,7738, # 6198 -3215,7739,7740,3361,1828,7741,1277,4476,1565,2047,7742,1636,3568,3093,7743, 869, # 6214 -2839, 655,3811,3812,3094,3989,3000,3813,1310,3569,4477,7744,7745,7746,1733, 558, # 6230 -4478,3681, 335,1549,3045,1756,4192,3682,1945,3464,1829,1291,1192, 470,2726,2107, # 6246 -2793, 913,1054,3990,7747,1027,7748,3046,3991,4479, 982,2662,3362,3148,3465,3216, # 6262 -3217,1946,2794,7749, 571,4480,7750,1830,7751,3570,2583,1523,2424,7752,2089, 984, # 6278 -4481,3683,1959,7753,3684, 852, 923,2795,3466,3685, 969,1519, 999,2048,2320,1705, # 6294 -7754,3095, 615,1662, 151, 597,3992,2405,2321,1049, 275,4482,3686,4193, 568,3687, # 6310 -3571,2480,4194,3688,7755,2425,2270, 409,3218,7756,1566,2874,3467,1002, 769,2840, # 6326 - 194,2090,3149,3689,2222,3294,4195, 628,1505,7757,7758,1763,2177,3001,3993, 521, # 6342 -1161,2584,1787,2203,2406,4483,3994,1625,4196,4197, 412, 42,3096, 464,7759,2632, # 6358 -4484,3363,1760,1571,2875,3468,2530,1219,2204,3814,2633,2140,2368,4485,4486,3295, # 6374 -1651,3364,3572,7760,7761,3573,2481,3469,7762,3690,7763,7764,2271,2091, 460,7765, # 6390 -4487,7766,3002, 962, 588,3574, 289,3219,2634,1116, 52,7767,3047,1796,7768,7769, # 6406 -7770,1467,7771,1598,1143,3691,4198,1984,1734,1067,4488,1280,3365, 465,4489,1572, # 6422 - 510,7772,1927,2241,1812,1644,3575,7773,4490,3692,7774,7775,2663,1573,1534,7776, # 6438 -7777,4199, 536,1807,1761,3470,3815,3150,2635,7778,7779,7780,4491,3471,2915,1911, # 6454 -2796,7781,3296,1122, 377,3220,7782, 360,7783,7784,4200,1529, 551,7785,2059,3693, # 6470 -1769,2426,7786,2916,4201,3297,3097,2322,2108,2030,4492,1404, 136,1468,1479, 672, # 6486 -1171,3221,2303, 271,3151,7787,2762,7788,2049, 678,2727, 865,1947,4493,7789,2013, # 6502 -3995,2956,7790,2728,2223,1397,3048,3694,4494,4495,1735,2917,3366,3576,7791,3816, # 6518 - 509,2841,2453,2876,3817,7792,7793,3152,3153,4496,4202,2531,4497,2304,1166,1010, # 6534 - 552, 681,1887,7794,7795,2957,2958,3996,1287,1596,1861,3154, 358, 453, 736, 175, # 6550 - 478,1117, 905,1167,1097,7796,1853,1530,7797,1706,7798,2178,3472,2287,3695,3473, # 6566 -3577,4203,2092,4204,7799,3367,1193,2482,4205,1458,2190,2205,1862,1888,1421,3298, # 6582 -2918,3049,2179,3474, 595,2122,7800,3997,7801,7802,4206,1707,2636, 223,3696,1359, # 6598 - 751,3098, 183,3475,7803,2797,3003, 419,2369, 633, 704,3818,2389, 241,7804,7805, # 6614 -7806, 838,3004,3697,2272,2763,2454,3819,1938,2050,3998,1309,3099,2242,1181,7807, # 6630 -1136,2206,3820,2370,1446,4207,2305,4498,7808,7809,4208,1055,2605, 484,3698,7810, # 6646 -3999, 625,4209,2273,3368,1499,4210,4000,7811,4001,4211,3222,2274,2275,3476,7812, # 6662 -7813,2764, 808,2606,3699,3369,4002,4212,3100,2532, 526,3370,3821,4213, 955,7814, # 6678 -1620,4214,2637,2427,7815,1429,3700,1669,1831, 994, 928,7816,3578,1260,7817,7818, # 6694 -7819,1948,2288, 741,2919,1626,4215,2729,2455, 867,1184, 362,3371,1392,7820,7821, # 6710 -4003,4216,1770,1736,3223,2920,4499,4500,1928,2698,1459,1158,7822,3050,3372,2877, # 6726 -1292,1929,2506,2842,3701,1985,1187,2071,2014,2607,4217,7823,2566,2507,2169,3702, # 6742 -2483,3299,7824,3703,4501,7825,7826, 666,1003,3005,1022,3579,4218,7827,4502,1813, # 6758 -2253, 574,3822,1603, 295,1535, 705,3823,4219, 283, 858, 417,7828,7829,3224,4503, # 6774 -4504,3051,1220,1889,1046,2276,2456,4004,1393,1599, 689,2567, 388,4220,7830,2484, # 6790 - 802,7831,2798,3824,2060,1405,2254,7832,4505,3825,2109,1052,1345,3225,1585,7833, # 6806 - 809,7834,7835,7836, 575,2730,3477, 956,1552,1469,1144,2323,7837,2324,1560,2457, # 6822 -3580,3226,4005, 616,2207,3155,2180,2289,7838,1832,7839,3478,4506,7840,1319,3704, # 6838 -3705,1211,3581,1023,3227,1293,2799,7841,7842,7843,3826, 607,2306,3827, 762,2878, # 6854 -1439,4221,1360,7844,1485,3052,7845,4507,1038,4222,1450,2061,2638,4223,1379,4508, # 6870 -2585,7846,7847,4224,1352,1414,2325,2921,1172,7848,7849,3828,3829,7850,1797,1451, # 6886 -7851,7852,7853,7854,2922,4006,4007,2485,2346, 411,4008,4009,3582,3300,3101,4509, # 6902 -1561,2664,1452,4010,1375,7855,7856, 47,2959, 316,7857,1406,1591,2923,3156,7858, # 6918 -1025,2141,3102,3157, 354,2731, 884,2224,4225,2407, 508,3706, 726,3583, 996,2428, # 6934 -3584, 729,7859, 392,2191,1453,4011,4510,3707,7860,7861,2458,3585,2608,1675,2800, # 6950 - 919,2347,2960,2348,1270,4511,4012, 73,7862,7863, 647,7864,3228,2843,2255,1550, # 6966 -1346,3006,7865,1332, 883,3479,7866,7867,7868,7869,3301,2765,7870,1212, 831,1347, # 6982 -4226,4512,2326,3830,1863,3053, 720,3831,4513,4514,3832,7871,4227,7872,7873,4515, # 6998 -7874,7875,1798,4516,3708,2609,4517,3586,1645,2371,7876,7877,2924, 669,2208,2665, # 7014 -2429,7878,2879,7879,7880,1028,3229,7881,4228,2408,7882,2256,1353,7883,7884,4518, # 7030 -3158, 518,7885,4013,7886,4229,1960,7887,2142,4230,7888,7889,3007,2349,2350,3833, # 7046 - 516,1833,1454,4014,2699,4231,4519,2225,2610,1971,1129,3587,7890,2766,7891,2961, # 7062 -1422, 577,1470,3008,1524,3373,7892,7893, 432,4232,3054,3480,7894,2586,1455,2508, # 7078 -2226,1972,1175,7895,1020,2732,4015,3481,4520,7896,2733,7897,1743,1361,3055,3482, # 7094 -2639,4016,4233,4521,2290, 895, 924,4234,2170, 331,2243,3056, 166,1627,3057,1098, # 7110 -7898,1232,2880,2227,3374,4522, 657, 403,1196,2372, 542,3709,3375,1600,4235,3483, # 7126 -7899,4523,2767,3230, 576, 530,1362,7900,4524,2533,2666,3710,4017,7901, 842,3834, # 7142 -7902,2801,2031,1014,4018, 213,2700,3376, 665, 621,4236,7903,3711,2925,2430,7904, # 7158 -2431,3302,3588,3377,7905,4237,2534,4238,4525,3589,1682,4239,3484,1380,7906, 724, # 7174 -2277, 600,1670,7907,1337,1233,4526,3103,2244,7908,1621,4527,7909, 651,4240,7910, # 7190 -1612,4241,2611,7911,2844,7912,2734,2307,3058,7913, 716,2459,3059, 174,1255,2701, # 7206 -4019,3590, 548,1320,1398, 728,4020,1574,7914,1890,1197,3060,4021,7915,3061,3062, # 7222 -3712,3591,3713, 747,7916, 635,4242,4528,7917,7918,7919,4243,7920,7921,4529,7922, # 7238 -3378,4530,2432, 451,7923,3714,2535,2072,4244,2735,4245,4022,7924,1764,4531,7925, # 7254 -4246, 350,7926,2278,2390,2486,7927,4247,4023,2245,1434,4024, 488,4532, 458,4248, # 7270 -4025,3715, 771,1330,2391,3835,2568,3159,2159,2409,1553,2667,3160,4249,7928,2487, # 7286 -2881,2612,1720,2702,4250,3379,4533,7929,2536,4251,7930,3231,4252,2768,7931,2015, # 7302 -2736,7932,1155,1017,3716,3836,7933,3303,2308, 201,1864,4253,1430,7934,4026,7935, # 7318 -7936,7937,7938,7939,4254,1604,7940, 414,1865, 371,2587,4534,4535,3485,2016,3104, # 7334 -4536,1708, 960,4255, 887, 389,2171,1536,1663,1721,7941,2228,4027,2351,2926,1580, # 7350 -7942,7943,7944,1744,7945,2537,4537,4538,7946,4539,7947,2073,7948,7949,3592,3380, # 7366 -2882,4256,7950,4257,2640,3381,2802, 673,2703,2460, 709,3486,4028,3593,4258,7951, # 7382 -1148, 502, 634,7952,7953,1204,4540,3594,1575,4541,2613,3717,7954,3718,3105, 948, # 7398 -3232, 121,1745,3837,1110,7955,4259,3063,2509,3009,4029,3719,1151,1771,3838,1488, # 7414 -4030,1986,7956,2433,3487,7957,7958,2093,7959,4260,3839,1213,1407,2803, 531,2737, # 7430 -2538,3233,1011,1537,7960,2769,4261,3106,1061,7961,3720,3721,1866,2883,7962,2017, # 7446 - 120,4262,4263,2062,3595,3234,2309,3840,2668,3382,1954,4542,7963,7964,3488,1047, # 7462 -2704,1266,7965,1368,4543,2845, 649,3383,3841,2539,2738,1102,2846,2669,7966,7967, # 7478 -1999,7968,1111,3596,2962,7969,2488,3842,3597,2804,1854,3384,3722,7970,7971,3385, # 7494 -2410,2884,3304,3235,3598,7972,2569,7973,3599,2805,4031,1460, 856,7974,3600,7975, # 7510 -2885,2963,7976,2886,3843,7977,4264, 632,2510, 875,3844,1697,3845,2291,7978,7979, # 7526 -4544,3010,1239, 580,4545,4265,7980, 914, 936,2074,1190,4032,1039,2123,7981,7982, # 7542 -7983,3386,1473,7984,1354,4266,3846,7985,2172,3064,4033, 915,3305,4267,4268,3306, # 7558 -1605,1834,7986,2739, 398,3601,4269,3847,4034, 328,1912,2847,4035,3848,1331,4270, # 7574 -3011, 937,4271,7987,3602,4036,4037,3387,2160,4546,3388, 524, 742, 538,3065,1012, # 7590 -7988,7989,3849,2461,7990, 658,1103, 225,3850,7991,7992,4547,7993,4548,7994,3236, # 7606 -1243,7995,4038, 963,2246,4549,7996,2705,3603,3161,7997,7998,2588,2327,7999,4550, # 7622 -8000,8001,8002,3489,3307, 957,3389,2540,2032,1930,2927,2462, 870,2018,3604,1746, # 7638 -2770,2771,2434,2463,8003,3851,8004,3723,3107,3724,3490,3390,3725,8005,1179,3066, # 7654 -8006,3162,2373,4272,3726,2541,3163,3108,2740,4039,8007,3391,1556,2542,2292, 977, # 7670 -2887,2033,4040,1205,3392,8008,1765,3393,3164,2124,1271,1689, 714,4551,3491,8009, # 7686 -2328,3852, 533,4273,3605,2181, 617,8010,2464,3308,3492,2310,8011,8012,3165,8013, # 7702 -8014,3853,1987, 618, 427,2641,3493,3394,8015,8016,1244,1690,8017,2806,4274,4552, # 7718 -8018,3494,8019,8020,2279,1576, 473,3606,4275,3395, 972,8021,3607,8022,3067,8023, # 7734 -8024,4553,4554,8025,3727,4041,4042,8026, 153,4555, 356,8027,1891,2888,4276,2143, # 7750 - 408, 803,2352,8028,3854,8029,4277,1646,2570,2511,4556,4557,3855,8030,3856,4278, # 7766 -8031,2411,3396, 752,8032,8033,1961,2964,8034, 746,3012,2465,8035,4279,3728, 698, # 7782 -4558,1892,4280,3608,2543,4559,3609,3857,8036,3166,3397,8037,1823,1302,4043,2706, # 7798 -3858,1973,4281,8038,4282,3167, 823,1303,1288,1236,2848,3495,4044,3398, 774,3859, # 7814 -8039,1581,4560,1304,2849,3860,4561,8040,2435,2161,1083,3237,4283,4045,4284, 344, # 7830 -1173, 288,2311, 454,1683,8041,8042,1461,4562,4046,2589,8043,8044,4563, 985, 894, # 7846 -8045,3399,3168,8046,1913,2928,3729,1988,8047,2110,1974,8048,4047,8049,2571,1194, # 7862 - 425,8050,4564,3169,1245,3730,4285,8051,8052,2850,8053, 636,4565,1855,3861, 760, # 7878 -1799,8054,4286,2209,1508,4566,4048,1893,1684,2293,8055,8056,8057,4287,4288,2210, # 7894 - 479,8058,8059, 832,8060,4049,2489,8061,2965,2490,3731, 990,3109, 627,1814,2642, # 7910 -4289,1582,4290,2125,2111,3496,4567,8062, 799,4291,3170,8063,4568,2112,1737,3013, # 7926 -1018, 543, 754,4292,3309,1676,4569,4570,4050,8064,1489,8065,3497,8066,2614,2889, # 7942 -4051,8067,8068,2966,8069,8070,8071,8072,3171,4571,4572,2182,1722,8073,3238,3239, # 7958 -1842,3610,1715, 481, 365,1975,1856,8074,8075,1962,2491,4573,8076,2126,3611,3240, # 7974 - 433,1894,2063,2075,8077, 602,2741,8078,8079,8080,8081,8082,3014,1628,3400,8083, # 7990 -3172,4574,4052,2890,4575,2512,8084,2544,2772,8085,8086,8087,3310,4576,2891,8088, # 8006 -4577,8089,2851,4578,4579,1221,2967,4053,2513,8090,8091,8092,1867,1989,8093,8094, # 8022 -8095,1895,8096,8097,4580,1896,4054, 318,8098,2094,4055,4293,8099,8100, 485,8101, # 8038 - 938,3862, 553,2670, 116,8102,3863,3612,8103,3498,2671,2773,3401,3311,2807,8104, # 8054 -3613,2929,4056,1747,2930,2968,8105,8106, 207,8107,8108,2672,4581,2514,8109,3015, # 8070 - 890,3614,3864,8110,1877,3732,3402,8111,2183,2353,3403,1652,8112,8113,8114, 941, # 8086 -2294, 208,3499,4057,2019, 330,4294,3865,2892,2492,3733,4295,8115,8116,8117,8118, # 8102 -) - diff --git a/venv/lib/python3.8/site-packages/chardet/euctwprober.py b/venv/lib/python3.8/site-packages/chardet/euctwprober.py deleted file mode 100644 index 35669cc..0000000 --- a/venv/lib/python3.8/site-packages/chardet/euctwprober.py +++ /dev/null @@ -1,46 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is mozilla.org code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -from .mbcharsetprober import MultiByteCharSetProber -from .codingstatemachine import CodingStateMachine -from .chardistribution import EUCTWDistributionAnalysis -from .mbcssm import EUCTW_SM_MODEL - -class EUCTWProber(MultiByteCharSetProber): - def __init__(self): - super(EUCTWProber, self).__init__() - self.coding_sm = CodingStateMachine(EUCTW_SM_MODEL) - self.distribution_analyzer = EUCTWDistributionAnalysis() - self.reset() - - @property - def charset_name(self): - return "EUC-TW" - - @property - def language(self): - return "Taiwan" diff --git a/venv/lib/python3.8/site-packages/chardet/gb2312freq.py b/venv/lib/python3.8/site-packages/chardet/gb2312freq.py deleted file mode 100644 index 697837b..0000000 --- a/venv/lib/python3.8/site-packages/chardet/gb2312freq.py +++ /dev/null @@ -1,283 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is Mozilla Communicator client code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -# GB2312 most frequently used character table -# -# Char to FreqOrder table , from hz6763 - -# 512 --> 0.79 -- 0.79 -# 1024 --> 0.92 -- 0.13 -# 2048 --> 0.98 -- 0.06 -# 6768 --> 1.00 -- 0.02 -# -# Ideal Distribution Ratio = 0.79135/(1-0.79135) = 3.79 -# Random Distribution Ration = 512 / (3755 - 512) = 0.157 -# -# Typical Distribution Ratio about 25% of Ideal one, still much higher that RDR - -GB2312_TYPICAL_DISTRIBUTION_RATIO = 0.9 - -GB2312_TABLE_SIZE = 3760 - -GB2312_CHAR_TO_FREQ_ORDER = ( -1671, 749,1443,2364,3924,3807,2330,3921,1704,3463,2691,1511,1515, 572,3191,2205, -2361, 224,2558, 479,1711, 963,3162, 440,4060,1905,2966,2947,3580,2647,3961,3842, -2204, 869,4207, 970,2678,5626,2944,2956,1479,4048, 514,3595, 588,1346,2820,3409, - 249,4088,1746,1873,2047,1774, 581,1813, 358,1174,3590,1014,1561,4844,2245, 670, -1636,3112, 889,1286, 953, 556,2327,3060,1290,3141, 613, 185,3477,1367, 850,3820, -1715,2428,2642,2303,2732,3041,2562,2648,3566,3946,1349, 388,3098,2091,1360,3585, - 152,1687,1539, 738,1559, 59,1232,2925,2267,1388,1249,1741,1679,2960, 151,1566, -1125,1352,4271, 924,4296, 385,3166,4459, 310,1245,2850, 70,3285,2729,3534,3575, -2398,3298,3466,1960,2265, 217,3647, 864,1909,2084,4401,2773,1010,3269,5152, 853, -3051,3121,1244,4251,1895, 364,1499,1540,2313,1180,3655,2268, 562, 715,2417,3061, - 544, 336,3768,2380,1752,4075, 950, 280,2425,4382, 183,2759,3272, 333,4297,2155, -1688,2356,1444,1039,4540, 736,1177,3349,2443,2368,2144,2225, 565, 196,1482,3406, - 927,1335,4147, 692, 878,1311,1653,3911,3622,1378,4200,1840,2969,3149,2126,1816, -2534,1546,2393,2760, 737,2494, 13, 447, 245,2747, 38,2765,2129,2589,1079, 606, - 360, 471,3755,2890, 404, 848, 699,1785,1236, 370,2221,1023,3746,2074,2026,2023, -2388,1581,2119, 812,1141,3091,2536,1519, 804,2053, 406,1596,1090, 784, 548,4414, -1806,2264,2936,1100, 343,4114,5096, 622,3358, 743,3668,1510,1626,5020,3567,2513, -3195,4115,5627,2489,2991, 24,2065,2697,1087,2719, 48,1634, 315, 68, 985,2052, - 198,2239,1347,1107,1439, 597,2366,2172, 871,3307, 919,2487,2790,1867, 236,2570, -1413,3794, 906,3365,3381,1701,1982,1818,1524,2924,1205, 616,2586,2072,2004, 575, - 253,3099, 32,1365,1182, 197,1714,2454,1201, 554,3388,3224,2748, 756,2587, 250, -2567,1507,1517,3529,1922,2761,2337,3416,1961,1677,2452,2238,3153, 615, 911,1506, -1474,2495,1265,1906,2749,3756,3280,2161, 898,2714,1759,3450,2243,2444, 563, 26, -3286,2266,3769,3344,2707,3677, 611,1402, 531,1028,2871,4548,1375, 261,2948, 835, -1190,4134, 353, 840,2684,1900,3082,1435,2109,1207,1674, 329,1872,2781,4055,2686, -2104, 608,3318,2423,2957,2768,1108,3739,3512,3271,3985,2203,1771,3520,1418,2054, -1681,1153, 225,1627,2929, 162,2050,2511,3687,1954, 124,1859,2431,1684,3032,2894, - 585,4805,3969,2869,2704,2088,2032,2095,3656,2635,4362,2209, 256, 518,2042,2105, -3777,3657, 643,2298,1148,1779, 190, 989,3544, 414, 11,2135,2063,2979,1471, 403, -3678, 126, 770,1563, 671,2499,3216,2877, 600,1179, 307,2805,4937,1268,1297,2694, - 252,4032,1448,1494,1331,1394, 127,2256, 222,1647,1035,1481,3056,1915,1048, 873, -3651, 210, 33,1608,2516, 200,1520, 415, 102, 0,3389,1287, 817, 91,3299,2940, - 836,1814, 549,2197,1396,1669,2987,3582,2297,2848,4528,1070, 687, 20,1819, 121, -1552,1364,1461,1968,2617,3540,2824,2083, 177, 948,4938,2291, 110,4549,2066, 648, -3359,1755,2110,2114,4642,4845,1693,3937,3308,1257,1869,2123, 208,1804,3159,2992, -2531,2549,3361,2418,1350,2347,2800,2568,1291,2036,2680, 72, 842,1990, 212,1233, -1154,1586, 75,2027,3410,4900,1823,1337,2710,2676, 728,2810,1522,3026,4995, 157, - 755,1050,4022, 710, 785,1936,2194,2085,1406,2777,2400, 150,1250,4049,1206, 807, -1910, 534, 529,3309,1721,1660, 274, 39,2827, 661,2670,1578, 925,3248,3815,1094, -4278,4901,4252, 41,1150,3747,2572,2227,4501,3658,4902,3813,3357,3617,2884,2258, - 887, 538,4187,3199,1294,2439,3042,2329,2343,2497,1255, 107, 543,1527, 521,3478, -3568, 194,5062, 15, 961,3870,1241,1192,2664, 66,5215,3260,2111,1295,1127,2152, -3805,4135, 901,1164,1976, 398,1278, 530,1460, 748, 904,1054,1966,1426, 53,2909, - 509, 523,2279,1534, 536,1019, 239,1685, 460,2353, 673,1065,2401,3600,4298,2272, -1272,2363, 284,1753,3679,4064,1695, 81, 815,2677,2757,2731,1386, 859, 500,4221, -2190,2566, 757,1006,2519,2068,1166,1455, 337,2654,3203,1863,1682,1914,3025,1252, -1409,1366, 847, 714,2834,2038,3209, 964,2970,1901, 885,2553,1078,1756,3049, 301, -1572,3326, 688,2130,1996,2429,1805,1648,2930,3421,2750,3652,3088, 262,1158,1254, - 389,1641,1812, 526,1719, 923,2073,1073,1902, 468, 489,4625,1140, 857,2375,3070, -3319,2863, 380, 116,1328,2693,1161,2244, 273,1212,1884,2769,3011,1775,1142, 461, -3066,1200,2147,2212, 790, 702,2695,4222,1601,1058, 434,2338,5153,3640, 67,2360, -4099,2502, 618,3472,1329, 416,1132, 830,2782,1807,2653,3211,3510,1662, 192,2124, - 296,3979,1739,1611,3684, 23, 118, 324, 446,1239,1225, 293,2520,3814,3795,2535, -3116, 17,1074, 467,2692,2201, 387,2922, 45,1326,3055,1645,3659,2817, 958, 243, -1903,2320,1339,2825,1784,3289, 356, 576, 865,2315,2381,3377,3916,1088,3122,1713, -1655, 935, 628,4689,1034,1327, 441, 800, 720, 894,1979,2183,1528,5289,2702,1071, -4046,3572,2399,1571,3281, 79, 761,1103, 327, 134, 758,1899,1371,1615, 879, 442, - 215,2605,2579, 173,2048,2485,1057,2975,3317,1097,2253,3801,4263,1403,1650,2946, - 814,4968,3487,1548,2644,1567,1285, 2, 295,2636, 97, 946,3576, 832, 141,4257, -3273, 760,3821,3521,3156,2607, 949,1024,1733,1516,1803,1920,2125,2283,2665,3180, -1501,2064,3560,2171,1592, 803,3518,1416, 732,3897,4258,1363,1362,2458, 119,1427, - 602,1525,2608,1605,1639,3175, 694,3064, 10, 465, 76,2000,4846,4208, 444,3781, -1619,3353,2206,1273,3796, 740,2483, 320,1723,2377,3660,2619,1359,1137,1762,1724, -2345,2842,1850,1862, 912, 821,1866, 612,2625,1735,2573,3369,1093, 844, 89, 937, - 930,1424,3564,2413,2972,1004,3046,3019,2011, 711,3171,1452,4178, 428, 801,1943, - 432, 445,2811, 206,4136,1472, 730, 349, 73, 397,2802,2547, 998,1637,1167, 789, - 396,3217, 154,1218, 716,1120,1780,2819,4826,1931,3334,3762,2139,1215,2627, 552, -3664,3628,3232,1405,2383,3111,1356,2652,3577,3320,3101,1703, 640,1045,1370,1246, -4996, 371,1575,2436,1621,2210, 984,4033,1734,2638, 16,4529, 663,2755,3255,1451, -3917,2257,1253,1955,2234,1263,2951, 214,1229, 617, 485, 359,1831,1969, 473,2310, - 750,2058, 165, 80,2864,2419, 361,4344,2416,2479,1134, 796,3726,1266,2943, 860, -2715, 938, 390,2734,1313,1384, 248, 202, 877,1064,2854, 522,3907, 279,1602, 297, -2357, 395,3740, 137,2075, 944,4089,2584,1267,3802, 62,1533,2285, 178, 176, 780, -2440, 201,3707, 590, 478,1560,4354,2117,1075, 30, 74,4643,4004,1635,1441,2745, - 776,2596, 238,1077,1692,1912,2844, 605, 499,1742,3947, 241,3053, 980,1749, 936, -2640,4511,2582, 515,1543,2162,5322,2892,2993, 890,2148,1924, 665,1827,3581,1032, - 968,3163, 339,1044,1896, 270, 583,1791,1720,4367,1194,3488,3669, 43,2523,1657, - 163,2167, 290,1209,1622,3378, 550, 634,2508,2510, 695,2634,2384,2512,1476,1414, - 220,1469,2341,2138,2852,3183,2900,4939,2865,3502,1211,3680, 854,3227,1299,2976, -3172, 186,2998,1459, 443,1067,3251,1495, 321,1932,3054, 909, 753,1410,1828, 436, -2441,1119,1587,3164,2186,1258, 227, 231,1425,1890,3200,3942, 247, 959, 725,5254, -2741, 577,2158,2079, 929, 120, 174, 838,2813, 591,1115, 417,2024, 40,3240,1536, -1037, 291,4151,2354, 632,1298,2406,2500,3535,1825,1846,3451, 205,1171, 345,4238, - 18,1163, 811, 685,2208,1217, 425,1312,1508,1175,4308,2552,1033, 587,1381,3059, -2984,3482, 340,1316,4023,3972, 792,3176, 519, 777,4690, 918, 933,4130,2981,3741, - 90,3360,2911,2200,5184,4550, 609,3079,2030, 272,3379,2736, 363,3881,1130,1447, - 286, 779, 357,1169,3350,3137,1630,1220,2687,2391, 747,1277,3688,2618,2682,2601, -1156,3196,5290,4034,3102,1689,3596,3128, 874, 219,2783, 798, 508,1843,2461, 269, -1658,1776,1392,1913,2983,3287,2866,2159,2372, 829,4076, 46,4253,2873,1889,1894, - 915,1834,1631,2181,2318, 298, 664,2818,3555,2735, 954,3228,3117, 527,3511,2173, - 681,2712,3033,2247,2346,3467,1652, 155,2164,3382, 113,1994, 450, 899, 494, 994, -1237,2958,1875,2336,1926,3727, 545,1577,1550, 633,3473, 204,1305,3072,2410,1956, -2471, 707,2134, 841,2195,2196,2663,3843,1026,4940, 990,3252,4997, 368,1092, 437, -3212,3258,1933,1829, 675,2977,2893, 412, 943,3723,4644,3294,3283,2230,2373,5154, -2389,2241,2661,2323,1404,2524, 593, 787, 677,3008,1275,2059, 438,2709,2609,2240, -2269,2246,1446, 36,1568,1373,3892,1574,2301,1456,3962, 693,2276,5216,2035,1143, -2720,1919,1797,1811,2763,4137,2597,1830,1699,1488,1198,2090, 424,1694, 312,3634, -3390,4179,3335,2252,1214, 561,1059,3243,2295,2561, 975,5155,2321,2751,3772, 472, -1537,3282,3398,1047,2077,2348,2878,1323,3340,3076, 690,2906, 51, 369, 170,3541, -1060,2187,2688,3670,2541,1083,1683, 928,3918, 459, 109,4427, 599,3744,4286, 143, -2101,2730,2490, 82,1588,3036,2121, 281,1860, 477,4035,1238,2812,3020,2716,3312, -1530,2188,2055,1317, 843, 636,1808,1173,3495, 649, 181,1002, 147,3641,1159,2414, -3750,2289,2795, 813,3123,2610,1136,4368, 5,3391,4541,2174, 420, 429,1728, 754, -1228,2115,2219, 347,2223,2733, 735,1518,3003,2355,3134,1764,3948,3329,1888,2424, -1001,1234,1972,3321,3363,1672,1021,1450,1584, 226, 765, 655,2526,3404,3244,2302, -3665, 731, 594,2184, 319,1576, 621, 658,2656,4299,2099,3864,1279,2071,2598,2739, - 795,3086,3699,3908,1707,2352,2402,1382,3136,2475,1465,4847,3496,3865,1085,3004, -2591,1084, 213,2287,1963,3565,2250, 822, 793,4574,3187,1772,1789,3050, 595,1484, -1959,2770,1080,2650, 456, 422,2996, 940,3322,4328,4345,3092,2742, 965,2784, 739, -4124, 952,1358,2498,2949,2565, 332,2698,2378, 660,2260,2473,4194,3856,2919, 535, -1260,2651,1208,1428,1300,1949,1303,2942, 433,2455,2450,1251,1946, 614,1269, 641, -1306,1810,2737,3078,2912, 564,2365,1419,1415,1497,4460,2367,2185,1379,3005,1307, -3218,2175,1897,3063, 682,1157,4040,4005,1712,1160,1941,1399, 394, 402,2952,1573, -1151,2986,2404, 862, 299,2033,1489,3006, 346, 171,2886,3401,1726,2932, 168,2533, - 47,2507,1030,3735,1145,3370,1395,1318,1579,3609,4560,2857,4116,1457,2529,1965, - 504,1036,2690,2988,2405, 745,5871, 849,2397,2056,3081, 863,2359,3857,2096, 99, -1397,1769,2300,4428,1643,3455,1978,1757,3718,1440, 35,4879,3742,1296,4228,2280, - 160,5063,1599,2013, 166, 520,3479,1646,3345,3012, 490,1937,1545,1264,2182,2505, -1096,1188,1369,1436,2421,1667,2792,2460,1270,2122, 727,3167,2143, 806,1706,1012, -1800,3037, 960,2218,1882, 805, 139,2456,1139,1521, 851,1052,3093,3089, 342,2039, - 744,5097,1468,1502,1585,2087, 223, 939, 326,2140,2577, 892,2481,1623,4077, 982, -3708, 135,2131, 87,2503,3114,2326,1106, 876,1616, 547,2997,2831,2093,3441,4530, -4314, 9,3256,4229,4148, 659,1462,1986,1710,2046,2913,2231,4090,4880,5255,3392, -3274,1368,3689,4645,1477, 705,3384,3635,1068,1529,2941,1458,3782,1509, 100,1656, -2548, 718,2339, 408,1590,2780,3548,1838,4117,3719,1345,3530, 717,3442,2778,3220, -2898,1892,4590,3614,3371,2043,1998,1224,3483, 891, 635, 584,2559,3355, 733,1766, -1729,1172,3789,1891,2307, 781,2982,2271,1957,1580,5773,2633,2005,4195,3097,1535, -3213,1189,1934,5693,3262, 586,3118,1324,1598, 517,1564,2217,1868,1893,4445,3728, -2703,3139,1526,1787,1992,3882,2875,1549,1199,1056,2224,1904,2711,5098,4287, 338, -1993,3129,3489,2689,1809,2815,1997, 957,1855,3898,2550,3275,3057,1105,1319, 627, -1505,1911,1883,3526, 698,3629,3456,1833,1431, 746, 77,1261,2017,2296,1977,1885, - 125,1334,1600, 525,1798,1109,2222,1470,1945, 559,2236,1186,3443,2476,1929,1411, -2411,3135,1777,3372,2621,1841,1613,3229, 668,1430,1839,2643,2916, 195,1989,2671, -2358,1387, 629,3205,2293,5256,4439, 123,1310, 888,1879,4300,3021,3605,1003,1162, -3192,2910,2010, 140,2395,2859, 55,1082,2012,2901, 662, 419,2081,1438, 680,2774, -4654,3912,1620,1731,1625,5035,4065,2328, 512,1344, 802,5443,2163,2311,2537, 524, -3399, 98,1155,2103,1918,2606,3925,2816,1393,2465,1504,3773,2177,3963,1478,4346, - 180,1113,4655,3461,2028,1698, 833,2696,1235,1322,1594,4408,3623,3013,3225,2040, -3022, 541,2881, 607,3632,2029,1665,1219, 639,1385,1686,1099,2803,3231,1938,3188, -2858, 427, 676,2772,1168,2025, 454,3253,2486,3556, 230,1950, 580, 791,1991,1280, -1086,1974,2034, 630, 257,3338,2788,4903,1017, 86,4790, 966,2789,1995,1696,1131, - 259,3095,4188,1308, 179,1463,5257, 289,4107,1248, 42,3413,1725,2288, 896,1947, - 774,4474,4254, 604,3430,4264, 392,2514,2588, 452, 237,1408,3018, 988,4531,1970, -3034,3310, 540,2370,1562,1288,2990, 502,4765,1147, 4,1853,2708, 207, 294,2814, -4078,2902,2509, 684, 34,3105,3532,2551, 644, 709,2801,2344, 573,1727,3573,3557, -2021,1081,3100,4315,2100,3681, 199,2263,1837,2385, 146,3484,1195,2776,3949, 997, -1939,3973,1008,1091,1202,1962,1847,1149,4209,5444,1076, 493, 117,5400,2521, 972, -1490,2934,1796,4542,2374,1512,2933,2657, 413,2888,1135,2762,2314,2156,1355,2369, - 766,2007,2527,2170,3124,2491,2593,2632,4757,2437, 234,3125,3591,1898,1750,1376, -1942,3468,3138, 570,2127,2145,3276,4131, 962, 132,1445,4196, 19, 941,3624,3480, -3366,1973,1374,4461,3431,2629, 283,2415,2275, 808,2887,3620,2112,2563,1353,3610, - 955,1089,3103,1053, 96, 88,4097, 823,3808,1583, 399, 292,4091,3313, 421,1128, - 642,4006, 903,2539,1877,2082, 596, 29,4066,1790, 722,2157, 130, 995,1569, 769, -1485, 464, 513,2213, 288,1923,1101,2453,4316, 133, 486,2445, 50, 625, 487,2207, - 57, 423, 481,2962, 159,3729,1558, 491, 303, 482, 501, 240,2837, 112,3648,2392, -1783, 362, 8,3433,3422, 610,2793,3277,1390,1284,1654, 21,3823, 734, 367, 623, - 193, 287, 374,1009,1483, 816, 476, 313,2255,2340,1262,2150,2899,1146,2581, 782, -2116,1659,2018,1880, 255,3586,3314,1110,2867,2137,2564, 986,2767,5185,2006, 650, - 158, 926, 762, 881,3157,2717,2362,3587, 306,3690,3245,1542,3077,2427,1691,2478, -2118,2985,3490,2438, 539,2305, 983, 129,1754, 355,4201,2386, 827,2923, 104,1773, -2838,2771, 411,2905,3919, 376, 767, 122,1114, 828,2422,1817,3506, 266,3460,1007, -1609,4998, 945,2612,4429,2274, 726,1247,1964,2914,2199,2070,4002,4108, 657,3323, -1422, 579, 455,2764,4737,1222,2895,1670, 824,1223,1487,2525, 558, 861,3080, 598, -2659,2515,1967, 752,2583,2376,2214,4180, 977, 704,2464,4999,2622,4109,1210,2961, - 819,1541, 142,2284, 44, 418, 457,1126,3730,4347,4626,1644,1876,3671,1864, 302, -1063,5694, 624, 723,1984,3745,1314,1676,2488,1610,1449,3558,3569,2166,2098, 409, -1011,2325,3704,2306, 818,1732,1383,1824,1844,3757, 999,2705,3497,1216,1423,2683, -2426,2954,2501,2726,2229,1475,2554,5064,1971,1794,1666,2014,1343, 783, 724, 191, -2434,1354,2220,5065,1763,2752,2472,4152, 131, 175,2885,3434, 92,1466,4920,2616, -3871,3872,3866, 128,1551,1632, 669,1854,3682,4691,4125,1230, 188,2973,3290,1302, -1213, 560,3266, 917, 763,3909,3249,1760, 868,1958, 764,1782,2097, 145,2277,3774, -4462, 64,1491,3062, 971,2132,3606,2442, 221,1226,1617, 218, 323,1185,3207,3147, - 571, 619,1473,1005,1744,2281, 449,1887,2396,3685, 275, 375,3816,1743,3844,3731, - 845,1983,2350,4210,1377, 773, 967,3499,3052,3743,2725,4007,1697,1022,3943,1464, -3264,2855,2722,1952,1029,2839,2467, 84,4383,2215, 820,1391,2015,2448,3672, 377, -1948,2168, 797,2545,3536,2578,2645, 94,2874,1678, 405,1259,3071, 771, 546,1315, - 470,1243,3083, 895,2468, 981, 969,2037, 846,4181, 653,1276,2928, 14,2594, 557, -3007,2474, 156, 902,1338,1740,2574, 537,2518, 973,2282,2216,2433,1928, 138,2903, -1293,2631,1612, 646,3457, 839,2935, 111, 496,2191,2847, 589,3186, 149,3994,2060, -4031,2641,4067,3145,1870, 37,3597,2136,1025,2051,3009,3383,3549,1121,1016,3261, -1301, 251,2446,2599,2153, 872,3246, 637, 334,3705, 831, 884, 921,3065,3140,4092, -2198,1944, 246,2964, 108,2045,1152,1921,2308,1031, 203,3173,4170,1907,3890, 810, -1401,2003,1690, 506, 647,1242,2828,1761,1649,3208,2249,1589,3709,2931,5156,1708, - 498, 666,2613, 834,3817,1231, 184,2851,1124, 883,3197,2261,3710,1765,1553,2658, -1178,2639,2351, 93,1193, 942,2538,2141,4402, 235,1821, 870,1591,2192,1709,1871, -3341,1618,4126,2595,2334, 603, 651, 69, 701, 268,2662,3411,2555,1380,1606, 503, - 448, 254,2371,2646, 574,1187,2309,1770, 322,2235,1292,1801, 305, 566,1133, 229, -2067,2057, 706, 167, 483,2002,2672,3295,1820,3561,3067, 316, 378,2746,3452,1112, - 136,1981, 507,1651,2917,1117, 285,4591, 182,2580,3522,1304, 335,3303,1835,2504, -1795,1792,2248, 674,1018,2106,2449,1857,2292,2845, 976,3047,1781,2600,2727,1389, -1281, 52,3152, 153, 265,3950, 672,3485,3951,4463, 430,1183, 365, 278,2169, 27, -1407,1336,2304, 209,1340,1730,2202,1852,2403,2883, 979,1737,1062, 631,2829,2542, -3876,2592, 825,2086,2226,3048,3625, 352,1417,3724, 542, 991, 431,1351,3938,1861, -2294, 826,1361,2927,3142,3503,1738, 463,2462,2723, 582,1916,1595,2808, 400,3845, -3891,2868,3621,2254, 58,2492,1123, 910,2160,2614,1372,1603,1196,1072,3385,1700, -3267,1980, 696, 480,2430, 920, 799,1570,2920,1951,2041,4047,2540,1321,4223,2469, -3562,2228,1271,2602, 401,2833,3351,2575,5157, 907,2312,1256, 410, 263,3507,1582, - 996, 678,1849,2316,1480, 908,3545,2237, 703,2322, 667,1826,2849,1531,2604,2999, -2407,3146,2151,2630,1786,3711, 469,3542, 497,3899,2409, 858, 837,4446,3393,1274, - 786, 620,1845,2001,3311, 484, 308,3367,1204,1815,3691,2332,1532,2557,1842,2020, -2724,1927,2333,4440, 567, 22,1673,2728,4475,1987,1858,1144,1597, 101,1832,3601, - 12, 974,3783,4391, 951,1412, 1,3720, 453,4608,4041, 528,1041,1027,3230,2628, -1129, 875,1051,3291,1203,2262,1069,2860,2799,2149,2615,3278, 144,1758,3040, 31, - 475,1680, 366,2685,3184, 311,1642,4008,2466,5036,1593,1493,2809, 216,1420,1668, - 233, 304,2128,3284, 232,1429,1768,1040,2008,3407,2740,2967,2543, 242,2133, 778, -1565,2022,2620, 505,2189,2756,1098,2273, 372,1614, 708, 553,2846,2094,2278, 169, -3626,2835,4161, 228,2674,3165, 809,1454,1309, 466,1705,1095, 900,3423, 880,2667, -3751,5258,2317,3109,2571,4317,2766,1503,1342, 866,4447,1118, 63,2076, 314,1881, -1348,1061, 172, 978,3515,1747, 532, 511,3970, 6, 601, 905,2699,3300,1751, 276, -1467,3725,2668, 65,4239,2544,2779,2556,1604, 578,2451,1802, 992,2331,2624,1320, -3446, 713,1513,1013, 103,2786,2447,1661, 886,1702, 916, 654,3574,2031,1556, 751, -2178,2821,2179,1498,1538,2176, 271, 914,2251,2080,1325, 638,1953,2937,3877,2432, -2754, 95,3265,1716, 260,1227,4083, 775, 106,1357,3254, 426,1607, 555,2480, 772, -1985, 244,2546, 474, 495,1046,2611,1851,2061, 71,2089,1675,2590, 742,3758,2843, -3222,1433, 267,2180,2576,2826,2233,2092,3913,2435, 956,1745,3075, 856,2113,1116, - 451, 3,1988,2896,1398, 993,2463,1878,2049,1341,2718,2721,2870,2108, 712,2904, -4363,2753,2324, 277,2872,2349,2649, 384, 987, 435, 691,3000, 922, 164,3939, 652, -1500,1184,4153,2482,3373,2165,4848,2335,3775,3508,3154,2806,2830,1554,2102,1664, -2530,1434,2408, 893,1547,2623,3447,2832,2242,2532,3169,2856,3223,2078, 49,3770, -3469, 462, 318, 656,2259,3250,3069, 679,1629,2758, 344,1138,1104,3120,1836,1283, -3115,2154,1437,4448, 934, 759,1999, 794,2862,1038, 533,2560,1722,2342, 855,2626, -1197,1663,4476,3127, 85,4240,2528, 25,1111,1181,3673, 407,3470,4561,2679,2713, - 768,1925,2841,3986,1544,1165, 932, 373,1240,2146,1930,2673, 721,4766, 354,4333, - 391,2963, 187, 61,3364,1442,1102, 330,1940,1767, 341,3809,4118, 393,2496,2062, -2211, 105, 331, 300, 439, 913,1332, 626, 379,3304,1557, 328, 689,3952, 309,1555, - 931, 317,2517,3027, 325, 569, 686,2107,3084, 60,1042,1333,2794, 264,3177,4014, -1628, 258,3712, 7,4464,1176,1043,1778, 683, 114,1975, 78,1492, 383,1886, 510, - 386, 645,5291,2891,2069,3305,4138,3867,2939,2603,2493,1935,1066,1848,3588,1015, -1282,1289,4609, 697,1453,3044,2666,3611,1856,2412, 54, 719,1330, 568,3778,2459, -1748, 788, 492, 551,1191,1000, 488,3394,3763, 282,1799, 348,2016,1523,3155,2390, -1049, 382,2019,1788,1170, 729,2968,3523, 897,3926,2785,2938,3292, 350,2319,3238, -1718,1717,2655,3453,3143,4465, 161,2889,2980,2009,1421, 56,1908,1640,2387,2232, -1917,1874,2477,4921, 148, 83,3438, 592,4245,2882,1822,1055, 741, 115,1496,1624, - 381,1638,4592,1020, 516,3214, 458, 947,4575,1432, 211,1514,2926,1865,2142, 189, - 852,1221,1400,1486, 882,2299,4036, 351, 28,1122, 700,6479,6480,6481,6482,6483, #last 512 -) - diff --git a/venv/lib/python3.8/site-packages/chardet/gb2312prober.py b/venv/lib/python3.8/site-packages/chardet/gb2312prober.py deleted file mode 100644 index 8446d2d..0000000 --- a/venv/lib/python3.8/site-packages/chardet/gb2312prober.py +++ /dev/null @@ -1,46 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is mozilla.org code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -from .mbcharsetprober import MultiByteCharSetProber -from .codingstatemachine import CodingStateMachine -from .chardistribution import GB2312DistributionAnalysis -from .mbcssm import GB2312_SM_MODEL - -class GB2312Prober(MultiByteCharSetProber): - def __init__(self): - super(GB2312Prober, self).__init__() - self.coding_sm = CodingStateMachine(GB2312_SM_MODEL) - self.distribution_analyzer = GB2312DistributionAnalysis() - self.reset() - - @property - def charset_name(self): - return "GB2312" - - @property - def language(self): - return "Chinese" diff --git a/venv/lib/python3.8/site-packages/chardet/hebrewprober.py b/venv/lib/python3.8/site-packages/chardet/hebrewprober.py deleted file mode 100644 index b0e1bf4..0000000 --- a/venv/lib/python3.8/site-packages/chardet/hebrewprober.py +++ /dev/null @@ -1,292 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is Mozilla Universal charset detector code. -# -# The Initial Developer of the Original Code is -# Shy Shalom -# Portions created by the Initial Developer are Copyright (C) 2005 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -from .charsetprober import CharSetProber -from .enums import ProbingState - -# This prober doesn't actually recognize a language or a charset. -# It is a helper prober for the use of the Hebrew model probers - -### General ideas of the Hebrew charset recognition ### -# -# Four main charsets exist in Hebrew: -# "ISO-8859-8" - Visual Hebrew -# "windows-1255" - Logical Hebrew -# "ISO-8859-8-I" - Logical Hebrew -# "x-mac-hebrew" - ?? Logical Hebrew ?? -# -# Both "ISO" charsets use a completely identical set of code points, whereas -# "windows-1255" and "x-mac-hebrew" are two different proper supersets of -# these code points. windows-1255 defines additional characters in the range -# 0x80-0x9F as some misc punctuation marks as well as some Hebrew-specific -# diacritics and additional 'Yiddish' ligature letters in the range 0xc0-0xd6. -# x-mac-hebrew defines similar additional code points but with a different -# mapping. -# -# As far as an average Hebrew text with no diacritics is concerned, all four -# charsets are identical with respect to code points. Meaning that for the -# main Hebrew alphabet, all four map the same values to all 27 Hebrew letters -# (including final letters). -# -# The dominant difference between these charsets is their directionality. -# "Visual" directionality means that the text is ordered as if the renderer is -# not aware of a BIDI rendering algorithm. The renderer sees the text and -# draws it from left to right. The text itself when ordered naturally is read -# backwards. A buffer of Visual Hebrew generally looks like so: -# "[last word of first line spelled backwards] [whole line ordered backwards -# and spelled backwards] [first word of first line spelled backwards] -# [end of line] [last word of second line] ... etc' " -# adding punctuation marks, numbers and English text to visual text is -# naturally also "visual" and from left to right. -# -# "Logical" directionality means the text is ordered "naturally" according to -# the order it is read. It is the responsibility of the renderer to display -# the text from right to left. A BIDI algorithm is used to place general -# punctuation marks, numbers and English text in the text. -# -# Texts in x-mac-hebrew are almost impossible to find on the Internet. From -# what little evidence I could find, it seems that its general directionality -# is Logical. -# -# To sum up all of the above, the Hebrew probing mechanism knows about two -# charsets: -# Visual Hebrew - "ISO-8859-8" - backwards text - Words and sentences are -# backwards while line order is natural. For charset recognition purposes -# the line order is unimportant (In fact, for this implementation, even -# word order is unimportant). -# Logical Hebrew - "windows-1255" - normal, naturally ordered text. -# -# "ISO-8859-8-I" is a subset of windows-1255 and doesn't need to be -# specifically identified. -# "x-mac-hebrew" is also identified as windows-1255. A text in x-mac-hebrew -# that contain special punctuation marks or diacritics is displayed with -# some unconverted characters showing as question marks. This problem might -# be corrected using another model prober for x-mac-hebrew. Due to the fact -# that x-mac-hebrew texts are so rare, writing another model prober isn't -# worth the effort and performance hit. -# -#### The Prober #### -# -# The prober is divided between two SBCharSetProbers and a HebrewProber, -# all of which are managed, created, fed data, inquired and deleted by the -# SBCSGroupProber. The two SBCharSetProbers identify that the text is in -# fact some kind of Hebrew, Logical or Visual. The final decision about which -# one is it is made by the HebrewProber by combining final-letter scores -# with the scores of the two SBCharSetProbers to produce a final answer. -# -# The SBCSGroupProber is responsible for stripping the original text of HTML -# tags, English characters, numbers, low-ASCII punctuation characters, spaces -# and new lines. It reduces any sequence of such characters to a single space. -# The buffer fed to each prober in the SBCS group prober is pure text in -# high-ASCII. -# The two SBCharSetProbers (model probers) share the same language model: -# Win1255Model. -# The first SBCharSetProber uses the model normally as any other -# SBCharSetProber does, to recognize windows-1255, upon which this model was -# built. The second SBCharSetProber is told to make the pair-of-letter -# lookup in the language model backwards. This in practice exactly simulates -# a visual Hebrew model using the windows-1255 logical Hebrew model. -# -# The HebrewProber is not using any language model. All it does is look for -# final-letter evidence suggesting the text is either logical Hebrew or visual -# Hebrew. Disjointed from the model probers, the results of the HebrewProber -# alone are meaningless. HebrewProber always returns 0.00 as confidence -# since it never identifies a charset by itself. Instead, the pointer to the -# HebrewProber is passed to the model probers as a helper "Name Prober". -# When the Group prober receives a positive identification from any prober, -# it asks for the name of the charset identified. If the prober queried is a -# Hebrew model prober, the model prober forwards the call to the -# HebrewProber to make the final decision. In the HebrewProber, the -# decision is made according to the final-letters scores maintained and Both -# model probers scores. The answer is returned in the form of the name of the -# charset identified, either "windows-1255" or "ISO-8859-8". - -class HebrewProber(CharSetProber): - # windows-1255 / ISO-8859-8 code points of interest - FINAL_KAF = 0xea - NORMAL_KAF = 0xeb - FINAL_MEM = 0xed - NORMAL_MEM = 0xee - FINAL_NUN = 0xef - NORMAL_NUN = 0xf0 - FINAL_PE = 0xf3 - NORMAL_PE = 0xf4 - FINAL_TSADI = 0xf5 - NORMAL_TSADI = 0xf6 - - # Minimum Visual vs Logical final letter score difference. - # If the difference is below this, don't rely solely on the final letter score - # distance. - MIN_FINAL_CHAR_DISTANCE = 5 - - # Minimum Visual vs Logical model score difference. - # If the difference is below this, don't rely at all on the model score - # distance. - MIN_MODEL_DISTANCE = 0.01 - - VISUAL_HEBREW_NAME = "ISO-8859-8" - LOGICAL_HEBREW_NAME = "windows-1255" - - def __init__(self): - super(HebrewProber, self).__init__() - self._final_char_logical_score = None - self._final_char_visual_score = None - self._prev = None - self._before_prev = None - self._logical_prober = None - self._visual_prober = None - self.reset() - - def reset(self): - self._final_char_logical_score = 0 - self._final_char_visual_score = 0 - # The two last characters seen in the previous buffer, - # mPrev and mBeforePrev are initialized to space in order to simulate - # a word delimiter at the beginning of the data - self._prev = ' ' - self._before_prev = ' ' - # These probers are owned by the group prober. - - def set_model_probers(self, logicalProber, visualProber): - self._logical_prober = logicalProber - self._visual_prober = visualProber - - def is_final(self, c): - return c in [self.FINAL_KAF, self.FINAL_MEM, self.FINAL_NUN, - self.FINAL_PE, self.FINAL_TSADI] - - def is_non_final(self, c): - # The normal Tsadi is not a good Non-Final letter due to words like - # 'lechotet' (to chat) containing an apostrophe after the tsadi. This - # apostrophe is converted to a space in FilterWithoutEnglishLetters - # causing the Non-Final tsadi to appear at an end of a word even - # though this is not the case in the original text. - # The letters Pe and Kaf rarely display a related behavior of not being - # a good Non-Final letter. Words like 'Pop', 'Winamp' and 'Mubarak' - # for example legally end with a Non-Final Pe or Kaf. However, the - # benefit of these letters as Non-Final letters outweighs the damage - # since these words are quite rare. - return c in [self.NORMAL_KAF, self.NORMAL_MEM, - self.NORMAL_NUN, self.NORMAL_PE] - - def feed(self, byte_str): - # Final letter analysis for logical-visual decision. - # Look for evidence that the received buffer is either logical Hebrew - # or visual Hebrew. - # The following cases are checked: - # 1) A word longer than 1 letter, ending with a final letter. This is - # an indication that the text is laid out "naturally" since the - # final letter really appears at the end. +1 for logical score. - # 2) A word longer than 1 letter, ending with a Non-Final letter. In - # normal Hebrew, words ending with Kaf, Mem, Nun, Pe or Tsadi, - # should not end with the Non-Final form of that letter. Exceptions - # to this rule are mentioned above in isNonFinal(). This is an - # indication that the text is laid out backwards. +1 for visual - # score - # 3) A word longer than 1 letter, starting with a final letter. Final - # letters should not appear at the beginning of a word. This is an - # indication that the text is laid out backwards. +1 for visual - # score. - # - # The visual score and logical score are accumulated throughout the - # text and are finally checked against each other in GetCharSetName(). - # No checking for final letters in the middle of words is done since - # that case is not an indication for either Logical or Visual text. - # - # We automatically filter out all 7-bit characters (replace them with - # spaces) so the word boundary detection works properly. [MAP] - - if self.state == ProbingState.NOT_ME: - # Both model probers say it's not them. No reason to continue. - return ProbingState.NOT_ME - - byte_str = self.filter_high_byte_only(byte_str) - - for cur in byte_str: - if cur == ' ': - # We stand on a space - a word just ended - if self._before_prev != ' ': - # next-to-last char was not a space so self._prev is not a - # 1 letter word - if self.is_final(self._prev): - # case (1) [-2:not space][-1:final letter][cur:space] - self._final_char_logical_score += 1 - elif self.is_non_final(self._prev): - # case (2) [-2:not space][-1:Non-Final letter][ - # cur:space] - self._final_char_visual_score += 1 - else: - # Not standing on a space - if ((self._before_prev == ' ') and - (self.is_final(self._prev)) and (cur != ' ')): - # case (3) [-2:space][-1:final letter][cur:not space] - self._final_char_visual_score += 1 - self._before_prev = self._prev - self._prev = cur - - # Forever detecting, till the end or until both model probers return - # ProbingState.NOT_ME (handled above) - return ProbingState.DETECTING - - @property - def charset_name(self): - # Make the decision: is it Logical or Visual? - # If the final letter score distance is dominant enough, rely on it. - finalsub = self._final_char_logical_score - self._final_char_visual_score - if finalsub >= self.MIN_FINAL_CHAR_DISTANCE: - return self.LOGICAL_HEBREW_NAME - if finalsub <= -self.MIN_FINAL_CHAR_DISTANCE: - return self.VISUAL_HEBREW_NAME - - # It's not dominant enough, try to rely on the model scores instead. - modelsub = (self._logical_prober.get_confidence() - - self._visual_prober.get_confidence()) - if modelsub > self.MIN_MODEL_DISTANCE: - return self.LOGICAL_HEBREW_NAME - if modelsub < -self.MIN_MODEL_DISTANCE: - return self.VISUAL_HEBREW_NAME - - # Still no good, back to final letter distance, maybe it'll save the - # day. - if finalsub < 0.0: - return self.VISUAL_HEBREW_NAME - - # (finalsub > 0 - Logical) or (don't know what to do) default to - # Logical. - return self.LOGICAL_HEBREW_NAME - - @property - def language(self): - return 'Hebrew' - - @property - def state(self): - # Remain active as long as any of the model probers are active. - if (self._logical_prober.state == ProbingState.NOT_ME) and \ - (self._visual_prober.state == ProbingState.NOT_ME): - return ProbingState.NOT_ME - return ProbingState.DETECTING diff --git a/venv/lib/python3.8/site-packages/chardet/jisfreq.py b/venv/lib/python3.8/site-packages/chardet/jisfreq.py deleted file mode 100644 index 83fc082..0000000 --- a/venv/lib/python3.8/site-packages/chardet/jisfreq.py +++ /dev/null @@ -1,325 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is Mozilla Communicator client code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -# Sampling from about 20M text materials include literature and computer technology -# -# Japanese frequency table, applied to both S-JIS and EUC-JP -# They are sorted in order. - -# 128 --> 0.77094 -# 256 --> 0.85710 -# 512 --> 0.92635 -# 1024 --> 0.97130 -# 2048 --> 0.99431 -# -# Ideal Distribution Ratio = 0.92635 / (1-0.92635) = 12.58 -# Random Distribution Ration = 512 / (2965+62+83+86-512) = 0.191 -# -# Typical Distribution Ratio, 25% of IDR - -JIS_TYPICAL_DISTRIBUTION_RATIO = 3.0 - -# Char to FreqOrder table , -JIS_TABLE_SIZE = 4368 - -JIS_CHAR_TO_FREQ_ORDER = ( - 40, 1, 6, 182, 152, 180, 295,2127, 285, 381,3295,4304,3068,4606,3165,3510, # 16 -3511,1822,2785,4607,1193,2226,5070,4608, 171,2996,1247, 18, 179,5071, 856,1661, # 32 -1262,5072, 619, 127,3431,3512,3230,1899,1700, 232, 228,1294,1298, 284, 283,2041, # 48 -2042,1061,1062, 48, 49, 44, 45, 433, 434,1040,1041, 996, 787,2997,1255,4305, # 64 -2108,4609,1684,1648,5073,5074,5075,5076,5077,5078,3687,5079,4610,5080,3927,3928, # 80 -5081,3296,3432, 290,2285,1471,2187,5082,2580,2825,1303,2140,1739,1445,2691,3375, # 96 -1691,3297,4306,4307,4611, 452,3376,1182,2713,3688,3069,4308,5083,5084,5085,5086, # 112 -5087,5088,5089,5090,5091,5092,5093,5094,5095,5096,5097,5098,5099,5100,5101,5102, # 128 -5103,5104,5105,5106,5107,5108,5109,5110,5111,5112,4097,5113,5114,5115,5116,5117, # 144 -5118,5119,5120,5121,5122,5123,5124,5125,5126,5127,5128,5129,5130,5131,5132,5133, # 160 -5134,5135,5136,5137,5138,5139,5140,5141,5142,5143,5144,5145,5146,5147,5148,5149, # 176 -5150,5151,5152,4612,5153,5154,5155,5156,5157,5158,5159,5160,5161,5162,5163,5164, # 192 -5165,5166,5167,5168,5169,5170,5171,5172,5173,5174,5175,1472, 598, 618, 820,1205, # 208 -1309,1412,1858,1307,1692,5176,5177,5178,5179,5180,5181,5182,1142,1452,1234,1172, # 224 -1875,2043,2149,1793,1382,2973, 925,2404,1067,1241, 960,1377,2935,1491, 919,1217, # 240 -1865,2030,1406,1499,2749,4098,5183,5184,5185,5186,5187,5188,2561,4099,3117,1804, # 256 -2049,3689,4309,3513,1663,5189,3166,3118,3298,1587,1561,3433,5190,3119,1625,2998, # 272 -3299,4613,1766,3690,2786,4614,5191,5192,5193,5194,2161, 26,3377, 2,3929, 20, # 288 -3691, 47,4100, 50, 17, 16, 35, 268, 27, 243, 42, 155, 24, 154, 29, 184, # 304 - 4, 91, 14, 92, 53, 396, 33, 289, 9, 37, 64, 620, 21, 39, 321, 5, # 320 - 12, 11, 52, 13, 3, 208, 138, 0, 7, 60, 526, 141, 151,1069, 181, 275, # 336 -1591, 83, 132,1475, 126, 331, 829, 15, 69, 160, 59, 22, 157, 55,1079, 312, # 352 - 109, 38, 23, 25, 10, 19, 79,5195, 61, 382,1124, 8, 30,5196,5197,5198, # 368 -5199,5200,5201,5202,5203,5204,5205,5206, 89, 62, 74, 34,2416, 112, 139, 196, # 384 - 271, 149, 84, 607, 131, 765, 46, 88, 153, 683, 76, 874, 101, 258, 57, 80, # 400 - 32, 364, 121,1508, 169,1547, 68, 235, 145,2999, 41, 360,3027, 70, 63, 31, # 416 - 43, 259, 262,1383, 99, 533, 194, 66, 93, 846, 217, 192, 56, 106, 58, 565, # 432 - 280, 272, 311, 256, 146, 82, 308, 71, 100, 128, 214, 655, 110, 261, 104,1140, # 448 - 54, 51, 36, 87, 67,3070, 185,2618,2936,2020, 28,1066,2390,2059,5207,5208, # 464 -5209,5210,5211,5212,5213,5214,5215,5216,4615,5217,5218,5219,5220,5221,5222,5223, # 480 -5224,5225,5226,5227,5228,5229,5230,5231,5232,5233,5234,5235,5236,3514,5237,5238, # 496 -5239,5240,5241,5242,5243,5244,2297,2031,4616,4310,3692,5245,3071,5246,3598,5247, # 512 -4617,3231,3515,5248,4101,4311,4618,3808,4312,4102,5249,4103,4104,3599,5250,5251, # 528 -5252,5253,5254,5255,5256,5257,5258,5259,5260,5261,5262,5263,5264,5265,5266,5267, # 544 -5268,5269,5270,5271,5272,5273,5274,5275,5276,5277,5278,5279,5280,5281,5282,5283, # 560 -5284,5285,5286,5287,5288,5289,5290,5291,5292,5293,5294,5295,5296,5297,5298,5299, # 576 -5300,5301,5302,5303,5304,5305,5306,5307,5308,5309,5310,5311,5312,5313,5314,5315, # 592 -5316,5317,5318,5319,5320,5321,5322,5323,5324,5325,5326,5327,5328,5329,5330,5331, # 608 -5332,5333,5334,5335,5336,5337,5338,5339,5340,5341,5342,5343,5344,5345,5346,5347, # 624 -5348,5349,5350,5351,5352,5353,5354,5355,5356,5357,5358,5359,5360,5361,5362,5363, # 640 -5364,5365,5366,5367,5368,5369,5370,5371,5372,5373,5374,5375,5376,5377,5378,5379, # 656 -5380,5381, 363, 642,2787,2878,2788,2789,2316,3232,2317,3434,2011, 165,1942,3930, # 672 -3931,3932,3933,5382,4619,5383,4620,5384,5385,5386,5387,5388,5389,5390,5391,5392, # 688 -5393,5394,5395,5396,5397,5398,5399,5400,5401,5402,5403,5404,5405,5406,5407,5408, # 704 -5409,5410,5411,5412,5413,5414,5415,5416,5417,5418,5419,5420,5421,5422,5423,5424, # 720 -5425,5426,5427,5428,5429,5430,5431,5432,5433,5434,5435,5436,5437,5438,5439,5440, # 736 -5441,5442,5443,5444,5445,5446,5447,5448,5449,5450,5451,5452,5453,5454,5455,5456, # 752 -5457,5458,5459,5460,5461,5462,5463,5464,5465,5466,5467,5468,5469,5470,5471,5472, # 768 -5473,5474,5475,5476,5477,5478,5479,5480,5481,5482,5483,5484,5485,5486,5487,5488, # 784 -5489,5490,5491,5492,5493,5494,5495,5496,5497,5498,5499,5500,5501,5502,5503,5504, # 800 -5505,5506,5507,5508,5509,5510,5511,5512,5513,5514,5515,5516,5517,5518,5519,5520, # 816 -5521,5522,5523,5524,5525,5526,5527,5528,5529,5530,5531,5532,5533,5534,5535,5536, # 832 -5537,5538,5539,5540,5541,5542,5543,5544,5545,5546,5547,5548,5549,5550,5551,5552, # 848 -5553,5554,5555,5556,5557,5558,5559,5560,5561,5562,5563,5564,5565,5566,5567,5568, # 864 -5569,5570,5571,5572,5573,5574,5575,5576,5577,5578,5579,5580,5581,5582,5583,5584, # 880 -5585,5586,5587,5588,5589,5590,5591,5592,5593,5594,5595,5596,5597,5598,5599,5600, # 896 -5601,5602,5603,5604,5605,5606,5607,5608,5609,5610,5611,5612,5613,5614,5615,5616, # 912 -5617,5618,5619,5620,5621,5622,5623,5624,5625,5626,5627,5628,5629,5630,5631,5632, # 928 -5633,5634,5635,5636,5637,5638,5639,5640,5641,5642,5643,5644,5645,5646,5647,5648, # 944 -5649,5650,5651,5652,5653,5654,5655,5656,5657,5658,5659,5660,5661,5662,5663,5664, # 960 -5665,5666,5667,5668,5669,5670,5671,5672,5673,5674,5675,5676,5677,5678,5679,5680, # 976 -5681,5682,5683,5684,5685,5686,5687,5688,5689,5690,5691,5692,5693,5694,5695,5696, # 992 -5697,5698,5699,5700,5701,5702,5703,5704,5705,5706,5707,5708,5709,5710,5711,5712, # 1008 -5713,5714,5715,5716,5717,5718,5719,5720,5721,5722,5723,5724,5725,5726,5727,5728, # 1024 -5729,5730,5731,5732,5733,5734,5735,5736,5737,5738,5739,5740,5741,5742,5743,5744, # 1040 -5745,5746,5747,5748,5749,5750,5751,5752,5753,5754,5755,5756,5757,5758,5759,5760, # 1056 -5761,5762,5763,5764,5765,5766,5767,5768,5769,5770,5771,5772,5773,5774,5775,5776, # 1072 -5777,5778,5779,5780,5781,5782,5783,5784,5785,5786,5787,5788,5789,5790,5791,5792, # 1088 -5793,5794,5795,5796,5797,5798,5799,5800,5801,5802,5803,5804,5805,5806,5807,5808, # 1104 -5809,5810,5811,5812,5813,5814,5815,5816,5817,5818,5819,5820,5821,5822,5823,5824, # 1120 -5825,5826,5827,5828,5829,5830,5831,5832,5833,5834,5835,5836,5837,5838,5839,5840, # 1136 -5841,5842,5843,5844,5845,5846,5847,5848,5849,5850,5851,5852,5853,5854,5855,5856, # 1152 -5857,5858,5859,5860,5861,5862,5863,5864,5865,5866,5867,5868,5869,5870,5871,5872, # 1168 -5873,5874,5875,5876,5877,5878,5879,5880,5881,5882,5883,5884,5885,5886,5887,5888, # 1184 -5889,5890,5891,5892,5893,5894,5895,5896,5897,5898,5899,5900,5901,5902,5903,5904, # 1200 -5905,5906,5907,5908,5909,5910,5911,5912,5913,5914,5915,5916,5917,5918,5919,5920, # 1216 -5921,5922,5923,5924,5925,5926,5927,5928,5929,5930,5931,5932,5933,5934,5935,5936, # 1232 -5937,5938,5939,5940,5941,5942,5943,5944,5945,5946,5947,5948,5949,5950,5951,5952, # 1248 -5953,5954,5955,5956,5957,5958,5959,5960,5961,5962,5963,5964,5965,5966,5967,5968, # 1264 -5969,5970,5971,5972,5973,5974,5975,5976,5977,5978,5979,5980,5981,5982,5983,5984, # 1280 -5985,5986,5987,5988,5989,5990,5991,5992,5993,5994,5995,5996,5997,5998,5999,6000, # 1296 -6001,6002,6003,6004,6005,6006,6007,6008,6009,6010,6011,6012,6013,6014,6015,6016, # 1312 -6017,6018,6019,6020,6021,6022,6023,6024,6025,6026,6027,6028,6029,6030,6031,6032, # 1328 -6033,6034,6035,6036,6037,6038,6039,6040,6041,6042,6043,6044,6045,6046,6047,6048, # 1344 -6049,6050,6051,6052,6053,6054,6055,6056,6057,6058,6059,6060,6061,6062,6063,6064, # 1360 -6065,6066,6067,6068,6069,6070,6071,6072,6073,6074,6075,6076,6077,6078,6079,6080, # 1376 -6081,6082,6083,6084,6085,6086,6087,6088,6089,6090,6091,6092,6093,6094,6095,6096, # 1392 -6097,6098,6099,6100,6101,6102,6103,6104,6105,6106,6107,6108,6109,6110,6111,6112, # 1408 -6113,6114,2044,2060,4621, 997,1235, 473,1186,4622, 920,3378,6115,6116, 379,1108, # 1424 -4313,2657,2735,3934,6117,3809, 636,3233, 573,1026,3693,3435,2974,3300,2298,4105, # 1440 - 854,2937,2463, 393,2581,2417, 539, 752,1280,2750,2480, 140,1161, 440, 708,1569, # 1456 - 665,2497,1746,1291,1523,3000, 164,1603, 847,1331, 537,1997, 486, 508,1693,2418, # 1472 -1970,2227, 878,1220, 299,1030, 969, 652,2751, 624,1137,3301,2619, 65,3302,2045, # 1488 -1761,1859,3120,1930,3694,3516, 663,1767, 852, 835,3695, 269, 767,2826,2339,1305, # 1504 - 896,1150, 770,1616,6118, 506,1502,2075,1012,2519, 775,2520,2975,2340,2938,4314, # 1520 -3028,2086,1224,1943,2286,6119,3072,4315,2240,1273,1987,3935,1557, 175, 597, 985, # 1536 -3517,2419,2521,1416,3029, 585, 938,1931,1007,1052,1932,1685,6120,3379,4316,4623, # 1552 - 804, 599,3121,1333,2128,2539,1159,1554,2032,3810, 687,2033,2904, 952, 675,1467, # 1568 -3436,6121,2241,1096,1786,2440,1543,1924, 980,1813,2228, 781,2692,1879, 728,1918, # 1584 -3696,4624, 548,1950,4625,1809,1088,1356,3303,2522,1944, 502, 972, 373, 513,2827, # 1600 - 586,2377,2391,1003,1976,1631,6122,2464,1084, 648,1776,4626,2141, 324, 962,2012, # 1616 -2177,2076,1384, 742,2178,1448,1173,1810, 222, 102, 301, 445, 125,2420, 662,2498, # 1632 - 277, 200,1476,1165,1068, 224,2562,1378,1446, 450,1880, 659, 791, 582,4627,2939, # 1648 -3936,1516,1274, 555,2099,3697,1020,1389,1526,3380,1762,1723,1787,2229, 412,2114, # 1664 -1900,2392,3518, 512,2597, 427,1925,2341,3122,1653,1686,2465,2499, 697, 330, 273, # 1680 - 380,2162, 951, 832, 780, 991,1301,3073, 965,2270,3519, 668,2523,2636,1286, 535, # 1696 -1407, 518, 671, 957,2658,2378, 267, 611,2197,3030,6123, 248,2299, 967,1799,2356, # 1712 - 850,1418,3437,1876,1256,1480,2828,1718,6124,6125,1755,1664,2405,6126,4628,2879, # 1728 -2829, 499,2179, 676,4629, 557,2329,2214,2090, 325,3234, 464, 811,3001, 992,2342, # 1744 -2481,1232,1469, 303,2242, 466,1070,2163, 603,1777,2091,4630,2752,4631,2714, 322, # 1760 -2659,1964,1768, 481,2188,1463,2330,2857,3600,2092,3031,2421,4632,2318,2070,1849, # 1776 -2598,4633,1302,2254,1668,1701,2422,3811,2905,3032,3123,2046,4106,1763,1694,4634, # 1792 -1604, 943,1724,1454, 917, 868,2215,1169,2940, 552,1145,1800,1228,1823,1955, 316, # 1808 -1080,2510, 361,1807,2830,4107,2660,3381,1346,1423,1134,4108,6127, 541,1263,1229, # 1824 -1148,2540, 545, 465,1833,2880,3438,1901,3074,2482, 816,3937, 713,1788,2500, 122, # 1840 -1575, 195,1451,2501,1111,6128, 859, 374,1225,2243,2483,4317, 390,1033,3439,3075, # 1856 -2524,1687, 266, 793,1440,2599, 946, 779, 802, 507, 897,1081, 528,2189,1292, 711, # 1872 -1866,1725,1167,1640, 753, 398,2661,1053, 246, 348,4318, 137,1024,3440,1600,2077, # 1888 -2129, 825,4319, 698, 238, 521, 187,2300,1157,2423,1641,1605,1464,1610,1097,2541, # 1904 -1260,1436, 759,2255,1814,2150, 705,3235, 409,2563,3304, 561,3033,2005,2564, 726, # 1920 -1956,2343,3698,4109, 949,3812,3813,3520,1669, 653,1379,2525, 881,2198, 632,2256, # 1936 -1027, 778,1074, 733,1957, 514,1481,2466, 554,2180, 702,3938,1606,1017,1398,6129, # 1952 -1380,3521, 921, 993,1313, 594, 449,1489,1617,1166, 768,1426,1360, 495,1794,3601, # 1968 -1177,3602,1170,4320,2344, 476, 425,3167,4635,3168,1424, 401,2662,1171,3382,1998, # 1984 -1089,4110, 477,3169, 474,6130,1909, 596,2831,1842, 494, 693,1051,1028,1207,3076, # 2000 - 606,2115, 727,2790,1473,1115, 743,3522, 630, 805,1532,4321,2021, 366,1057, 838, # 2016 - 684,1114,2142,4322,2050,1492,1892,1808,2271,3814,2424,1971,1447,1373,3305,1090, # 2032 -1536,3939,3523,3306,1455,2199, 336, 369,2331,1035, 584,2393, 902, 718,2600,6131, # 2048 -2753, 463,2151,1149,1611,2467, 715,1308,3124,1268, 343,1413,3236,1517,1347,2663, # 2064 -2093,3940,2022,1131,1553,2100,2941,1427,3441,2942,1323,2484,6132,1980, 872,2368, # 2080 -2441,2943, 320,2369,2116,1082, 679,1933,3941,2791,3815, 625,1143,2023, 422,2200, # 2096 -3816,6133, 730,1695, 356,2257,1626,2301,2858,2637,1627,1778, 937, 883,2906,2693, # 2112 -3002,1769,1086, 400,1063,1325,3307,2792,4111,3077, 456,2345,1046, 747,6134,1524, # 2128 - 884,1094,3383,1474,2164,1059, 974,1688,2181,2258,1047, 345,1665,1187, 358, 875, # 2144 -3170, 305, 660,3524,2190,1334,1135,3171,1540,1649,2542,1527, 927, 968,2793, 885, # 2160 -1972,1850, 482, 500,2638,1218,1109,1085,2543,1654,2034, 876, 78,2287,1482,1277, # 2176 - 861,1675,1083,1779, 724,2754, 454, 397,1132,1612,2332, 893, 672,1237, 257,2259, # 2192 -2370, 135,3384, 337,2244, 547, 352, 340, 709,2485,1400, 788,1138,2511, 540, 772, # 2208 -1682,2260,2272,2544,2013,1843,1902,4636,1999,1562,2288,4637,2201,1403,1533, 407, # 2224 - 576,3308,1254,2071, 978,3385, 170, 136,1201,3125,2664,3172,2394, 213, 912, 873, # 2240 -3603,1713,2202, 699,3604,3699, 813,3442, 493, 531,1054, 468,2907,1483, 304, 281, # 2256 -4112,1726,1252,2094, 339,2319,2130,2639, 756,1563,2944, 748, 571,2976,1588,2425, # 2272 -2715,1851,1460,2426,1528,1392,1973,3237, 288,3309, 685,3386, 296, 892,2716,2216, # 2288 -1570,2245, 722,1747,2217, 905,3238,1103,6135,1893,1441,1965, 251,1805,2371,3700, # 2304 -2601,1919,1078, 75,2182,1509,1592,1270,2640,4638,2152,6136,3310,3817, 524, 706, # 2320 -1075, 292,3818,1756,2602, 317, 98,3173,3605,3525,1844,2218,3819,2502, 814, 567, # 2336 - 385,2908,1534,6137, 534,1642,3239, 797,6138,1670,1529, 953,4323, 188,1071, 538, # 2352 - 178, 729,3240,2109,1226,1374,2000,2357,2977, 731,2468,1116,2014,2051,6139,1261, # 2368 -1593, 803,2859,2736,3443, 556, 682, 823,1541,6140,1369,2289,1706,2794, 845, 462, # 2384 -2603,2665,1361, 387, 162,2358,1740, 739,1770,1720,1304,1401,3241,1049, 627,1571, # 2400 -2427,3526,1877,3942,1852,1500, 431,1910,1503, 677, 297,2795, 286,1433,1038,1198, # 2416 -2290,1133,1596,4113,4639,2469,1510,1484,3943,6141,2442, 108, 712,4640,2372, 866, # 2432 -3701,2755,3242,1348, 834,1945,1408,3527,2395,3243,1811, 824, 994,1179,2110,1548, # 2448 -1453, 790,3003, 690,4324,4325,2832,2909,3820,1860,3821, 225,1748, 310, 346,1780, # 2464 -2470, 821,1993,2717,2796, 828, 877,3528,2860,2471,1702,2165,2910,2486,1789, 453, # 2480 - 359,2291,1676, 73,1164,1461,1127,3311, 421, 604, 314,1037, 589, 116,2487, 737, # 2496 - 837,1180, 111, 244, 735,6142,2261,1861,1362, 986, 523, 418, 581,2666,3822, 103, # 2512 - 855, 503,1414,1867,2488,1091, 657,1597, 979, 605,1316,4641,1021,2443,2078,2001, # 2528 -1209, 96, 587,2166,1032, 260,1072,2153, 173, 94, 226,3244, 819,2006,4642,4114, # 2544 -2203, 231,1744, 782, 97,2667, 786,3387, 887, 391, 442,2219,4326,1425,6143,2694, # 2560 - 633,1544,1202, 483,2015, 592,2052,1958,2472,1655, 419, 129,4327,3444,3312,1714, # 2576 -1257,3078,4328,1518,1098, 865,1310,1019,1885,1512,1734, 469,2444, 148, 773, 436, # 2592 -1815,1868,1128,1055,4329,1245,2756,3445,2154,1934,1039,4643, 579,1238, 932,2320, # 2608 - 353, 205, 801, 115,2428, 944,2321,1881, 399,2565,1211, 678, 766,3944, 335,2101, # 2624 -1459,1781,1402,3945,2737,2131,1010, 844, 981,1326,1013, 550,1816,1545,2620,1335, # 2640 -1008, 371,2881, 936,1419,1613,3529,1456,1395,2273,1834,2604,1317,2738,2503, 416, # 2656 -1643,4330, 806,1126, 229, 591,3946,1314,1981,1576,1837,1666, 347,1790, 977,3313, # 2672 - 764,2861,1853, 688,2429,1920,1462, 77, 595, 415,2002,3034, 798,1192,4115,6144, # 2688 -2978,4331,3035,2695,2582,2072,2566, 430,2430,1727, 842,1396,3947,3702, 613, 377, # 2704 - 278, 236,1417,3388,3314,3174, 757,1869, 107,3530,6145,1194, 623,2262, 207,1253, # 2720 -2167,3446,3948, 492,1117,1935, 536,1838,2757,1246,4332, 696,2095,2406,1393,1572, # 2736 -3175,1782, 583, 190, 253,1390,2230, 830,3126,3389, 934,3245,1703,1749,2979,1870, # 2752 -2545,1656,2204, 869,2346,4116,3176,1817, 496,1764,4644, 942,1504, 404,1903,1122, # 2768 -1580,3606,2945,1022, 515, 372,1735, 955,2431,3036,6146,2797,1110,2302,2798, 617, # 2784 -6147, 441, 762,1771,3447,3607,3608,1904, 840,3037, 86, 939,1385, 572,1370,2445, # 2800 -1336, 114,3703, 898, 294, 203,3315, 703,1583,2274, 429, 961,4333,1854,1951,3390, # 2816 -2373,3704,4334,1318,1381, 966,1911,2322,1006,1155, 309, 989, 458,2718,1795,1372, # 2832 -1203, 252,1689,1363,3177, 517,1936, 168,1490, 562, 193,3823,1042,4117,1835, 551, # 2848 - 470,4645, 395, 489,3448,1871,1465,2583,2641, 417,1493, 279,1295, 511,1236,1119, # 2864 - 72,1231,1982,1812,3004, 871,1564, 984,3449,1667,2696,2096,4646,2347,2833,1673, # 2880 -3609, 695,3246,2668, 807,1183,4647, 890, 388,2333,1801,1457,2911,1765,1477,1031, # 2896 -3316,3317,1278,3391,2799,2292,2526, 163,3450,4335,2669,1404,1802,6148,2323,2407, # 2912 -1584,1728,1494,1824,1269, 298, 909,3318,1034,1632, 375, 776,1683,2061, 291, 210, # 2928 -1123, 809,1249,1002,2642,3038, 206,1011,2132, 144, 975, 882,1565, 342, 667, 754, # 2944 -1442,2143,1299,2303,2062, 447, 626,2205,1221,2739,2912,1144,1214,2206,2584, 760, # 2960 -1715, 614, 950,1281,2670,2621, 810, 577,1287,2546,4648, 242,2168, 250,2643, 691, # 2976 - 123,2644, 647, 313,1029, 689,1357,2946,1650, 216, 771,1339,1306, 808,2063, 549, # 2992 - 913,1371,2913,2914,6149,1466,1092,1174,1196,1311,2605,2396,1783,1796,3079, 406, # 3008 -2671,2117,3949,4649, 487,1825,2220,6150,2915, 448,2348,1073,6151,2397,1707, 130, # 3024 - 900,1598, 329, 176,1959,2527,1620,6152,2275,4336,3319,1983,2191,3705,3610,2155, # 3040 -3706,1912,1513,1614,6153,1988, 646, 392,2304,1589,3320,3039,1826,1239,1352,1340, # 3056 -2916, 505,2567,1709,1437,2408,2547, 906,6154,2672, 384,1458,1594,1100,1329, 710, # 3072 - 423,3531,2064,2231,2622,1989,2673,1087,1882, 333, 841,3005,1296,2882,2379, 580, # 3088 -1937,1827,1293,2585, 601, 574, 249,1772,4118,2079,1120, 645, 901,1176,1690, 795, # 3104 -2207, 478,1434, 516,1190,1530, 761,2080, 930,1264, 355, 435,1552, 644,1791, 987, # 3120 - 220,1364,1163,1121,1538, 306,2169,1327,1222, 546,2645, 218, 241, 610,1704,3321, # 3136 -1984,1839,1966,2528, 451,6155,2586,3707,2568, 907,3178, 254,2947, 186,1845,4650, # 3152 - 745, 432,1757, 428,1633, 888,2246,2221,2489,3611,2118,1258,1265, 956,3127,1784, # 3168 -4337,2490, 319, 510, 119, 457,3612, 274,2035,2007,4651,1409,3128, 970,2758, 590, # 3184 -2800, 661,2247,4652,2008,3950,1420,1549,3080,3322,3951,1651,1375,2111, 485,2491, # 3200 -1429,1156,6156,2548,2183,1495, 831,1840,2529,2446, 501,1657, 307,1894,3247,1341, # 3216 - 666, 899,2156,1539,2549,1559, 886, 349,2208,3081,2305,1736,3824,2170,2759,1014, # 3232 -1913,1386, 542,1397,2948, 490, 368, 716, 362, 159, 282,2569,1129,1658,1288,1750, # 3248 -2674, 276, 649,2016, 751,1496, 658,1818,1284,1862,2209,2087,2512,3451, 622,2834, # 3264 - 376, 117,1060,2053,1208,1721,1101,1443, 247,1250,3179,1792,3952,2760,2398,3953, # 3280 -6157,2144,3708, 446,2432,1151,2570,3452,2447,2761,2835,1210,2448,3082, 424,2222, # 3296 -1251,2449,2119,2836, 504,1581,4338, 602, 817, 857,3825,2349,2306, 357,3826,1470, # 3312 -1883,2883, 255, 958, 929,2917,3248, 302,4653,1050,1271,1751,2307,1952,1430,2697, # 3328 -2719,2359, 354,3180, 777, 158,2036,4339,1659,4340,4654,2308,2949,2248,1146,2232, # 3344 -3532,2720,1696,2623,3827,6158,3129,1550,2698,1485,1297,1428, 637, 931,2721,2145, # 3360 - 914,2550,2587, 81,2450, 612, 827,2646,1242,4655,1118,2884, 472,1855,3181,3533, # 3376 -3534, 569,1353,2699,1244,1758,2588,4119,2009,2762,2171,3709,1312,1531,6159,1152, # 3392 -1938, 134,1830, 471,3710,2276,1112,1535,3323,3453,3535, 982,1337,2950, 488, 826, # 3408 - 674,1058,1628,4120,2017, 522,2399, 211, 568,1367,3454, 350, 293,1872,1139,3249, # 3424 -1399,1946,3006,1300,2360,3324, 588, 736,6160,2606, 744, 669,3536,3828,6161,1358, # 3440 - 199, 723, 848, 933, 851,1939,1505,1514,1338,1618,1831,4656,1634,3613, 443,2740, # 3456 -3829, 717,1947, 491,1914,6162,2551,1542,4121,1025,6163,1099,1223, 198,3040,2722, # 3472 - 370, 410,1905,2589, 998,1248,3182,2380, 519,1449,4122,1710, 947, 928,1153,4341, # 3488 -2277, 344,2624,1511, 615, 105, 161,1212,1076,1960,3130,2054,1926,1175,1906,2473, # 3504 - 414,1873,2801,6164,2309, 315,1319,3325, 318,2018,2146,2157, 963, 631, 223,4342, # 3520 -4343,2675, 479,3711,1197,2625,3712,2676,2361,6165,4344,4123,6166,2451,3183,1886, # 3536 -2184,1674,1330,1711,1635,1506, 799, 219,3250,3083,3954,1677,3713,3326,2081,3614, # 3552 -1652,2073,4657,1147,3041,1752, 643,1961, 147,1974,3955,6167,1716,2037, 918,3007, # 3568 -1994, 120,1537, 118, 609,3184,4345, 740,3455,1219, 332,1615,3830,6168,1621,2980, # 3584 -1582, 783, 212, 553,2350,3714,1349,2433,2082,4124, 889,6169,2310,1275,1410, 973, # 3600 - 166,1320,3456,1797,1215,3185,2885,1846,2590,2763,4658, 629, 822,3008, 763, 940, # 3616 -1990,2862, 439,2409,1566,1240,1622, 926,1282,1907,2764, 654,2210,1607, 327,1130, # 3632 -3956,1678,1623,6170,2434,2192, 686, 608,3831,3715, 903,3957,3042,6171,2741,1522, # 3648 -1915,1105,1555,2552,1359, 323,3251,4346,3457, 738,1354,2553,2311,2334,1828,2003, # 3664 -3832,1753,2351,1227,6172,1887,4125,1478,6173,2410,1874,1712,1847, 520,1204,2607, # 3680 - 264,4659, 836,2677,2102, 600,4660,3833,2278,3084,6174,4347,3615,1342, 640, 532, # 3696 - 543,2608,1888,2400,2591,1009,4348,1497, 341,1737,3616,2723,1394, 529,3252,1321, # 3712 - 983,4661,1515,2120, 971,2592, 924, 287,1662,3186,4349,2700,4350,1519, 908,1948, # 3728 -2452, 156, 796,1629,1486,2223,2055, 694,4126,1259,1036,3392,1213,2249,2742,1889, # 3744 -1230,3958,1015, 910, 408, 559,3617,4662, 746, 725, 935,4663,3959,3009,1289, 563, # 3760 - 867,4664,3960,1567,2981,2038,2626, 988,2263,2381,4351, 143,2374, 704,1895,6175, # 3776 -1188,3716,2088, 673,3085,2362,4352, 484,1608,1921,2765,2918, 215, 904,3618,3537, # 3792 - 894, 509, 976,3043,2701,3961,4353,2837,2982, 498,6176,6177,1102,3538,1332,3393, # 3808 -1487,1636,1637, 233, 245,3962, 383, 650, 995,3044, 460,1520,1206,2352, 749,3327, # 3824 - 530, 700, 389,1438,1560,1773,3963,2264, 719,2951,2724,3834, 870,1832,1644,1000, # 3840 - 839,2474,3717, 197,1630,3394, 365,2886,3964,1285,2133, 734, 922, 818,1106, 732, # 3856 - 480,2083,1774,3458, 923,2279,1350, 221,3086, 85,2233,2234,3835,1585,3010,2147, # 3872 -1387,1705,2382,1619,2475, 133, 239,2802,1991,1016,2084,2383, 411,2838,1113, 651, # 3888 -1985,1160,3328, 990,1863,3087,1048,1276,2647, 265,2627,1599,3253,2056, 150, 638, # 3904 -2019, 656, 853, 326,1479, 680,1439,4354,1001,1759, 413,3459,3395,2492,1431, 459, # 3920 -4355,1125,3329,2265,1953,1450,2065,2863, 849, 351,2678,3131,3254,3255,1104,1577, # 3936 - 227,1351,1645,2453,2193,1421,2887, 812,2121, 634, 95,2435, 201,2312,4665,1646, # 3952 -1671,2743,1601,2554,2702,2648,2280,1315,1366,2089,3132,1573,3718,3965,1729,1189, # 3968 - 328,2679,1077,1940,1136, 558,1283, 964,1195, 621,2074,1199,1743,3460,3619,1896, # 3984 -1916,1890,3836,2952,1154,2112,1064, 862, 378,3011,2066,2113,2803,1568,2839,6178, # 4000 -3088,2919,1941,1660,2004,1992,2194, 142, 707,1590,1708,1624,1922,1023,1836,1233, # 4016 -1004,2313, 789, 741,3620,6179,1609,2411,1200,4127,3719,3720,4666,2057,3721, 593, # 4032 -2840, 367,2920,1878,6180,3461,1521, 628,1168, 692,2211,2649, 300, 720,2067,2571, # 4048 -2953,3396, 959,2504,3966,3539,3462,1977, 701,6181, 954,1043, 800, 681, 183,3722, # 4064 -1803,1730,3540,4128,2103, 815,2314, 174, 467, 230,2454,1093,2134, 755,3541,3397, # 4080 -1141,1162,6182,1738,2039, 270,3256,2513,1005,1647,2185,3837, 858,1679,1897,1719, # 4096 -2954,2324,1806, 402, 670, 167,4129,1498,2158,2104, 750,6183, 915, 189,1680,1551, # 4112 - 455,4356,1501,2455, 405,1095,2955, 338,1586,1266,1819, 570, 641,1324, 237,1556, # 4128 -2650,1388,3723,6184,1368,2384,1343,1978,3089,2436, 879,3724, 792,1191, 758,3012, # 4144 -1411,2135,1322,4357, 240,4667,1848,3725,1574,6185, 420,3045,1546,1391, 714,4358, # 4160 -1967, 941,1864, 863, 664, 426, 560,1731,2680,1785,2864,1949,2363, 403,3330,1415, # 4176 -1279,2136,1697,2335, 204, 721,2097,3838, 90,6186,2085,2505, 191,3967, 124,2148, # 4192 -1376,1798,1178,1107,1898,1405, 860,4359,1243,1272,2375,2983,1558,2456,1638, 113, # 4208 -3621, 578,1923,2609, 880, 386,4130, 784,2186,2266,1422,2956,2172,1722, 497, 263, # 4224 -2514,1267,2412,2610, 177,2703,3542, 774,1927,1344, 616,1432,1595,1018, 172,4360, # 4240 -2325, 911,4361, 438,1468,3622, 794,3968,2024,2173,1681,1829,2957, 945, 895,3090, # 4256 - 575,2212,2476, 475,2401,2681, 785,2744,1745,2293,2555,1975,3133,2865, 394,4668, # 4272 -3839, 635,4131, 639, 202,1507,2195,2766,1345,1435,2572,3726,1908,1184,1181,2457, # 4288 -3727,3134,4362, 843,2611, 437, 916,4669, 234, 769,1884,3046,3047,3623, 833,6187, # 4304 -1639,2250,2402,1355,1185,2010,2047, 999, 525,1732,1290,1488,2612, 948,1578,3728, # 4320 -2413,2477,1216,2725,2159, 334,3840,1328,3624,2921,1525,4132, 564,1056, 891,4363, # 4336 -1444,1698,2385,2251,3729,1365,2281,2235,1717,6188, 864,3841,2515, 444, 527,2767, # 4352 -2922,3625, 544, 461,6189, 566, 209,2437,3398,2098,1065,2068,3331,3626,3257,2137, # 4368 #last 512 -) - - diff --git a/venv/lib/python3.8/site-packages/chardet/jpcntx.py b/venv/lib/python3.8/site-packages/chardet/jpcntx.py deleted file mode 100644 index 20044e4..0000000 --- a/venv/lib/python3.8/site-packages/chardet/jpcntx.py +++ /dev/null @@ -1,233 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is Mozilla Communicator client code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - - -# This is hiragana 2-char sequence table, the number in each cell represents its frequency category -jp2CharContext = ( -(0,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1), -(2,4,0,4,0,3,0,4,0,3,4,4,4,2,4,3,3,4,3,2,3,3,4,2,3,3,3,2,4,1,4,3,3,1,5,4,3,4,3,4,3,5,3,0,3,5,4,2,0,3,1,0,3,3,0,3,3,0,1,1,0,4,3,0,3,3,0,4,0,2,0,3,5,5,5,5,4,0,4,1,0,3,4), -(0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2), -(0,4,0,5,0,5,0,4,0,4,5,4,4,3,5,3,5,1,5,3,4,3,4,4,3,4,3,3,4,3,5,4,4,3,5,5,3,5,5,5,3,5,5,3,4,5,5,3,1,3,2,0,3,4,0,4,2,0,4,2,1,5,3,2,3,5,0,4,0,2,0,5,4,4,5,4,5,0,4,0,0,4,4), -(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), -(0,3,0,4,0,3,0,3,0,4,5,4,3,3,3,3,4,3,5,4,4,3,5,4,4,3,4,3,4,4,4,4,5,3,4,4,3,4,5,5,4,5,5,1,4,5,4,3,0,3,3,1,3,3,0,4,4,0,3,3,1,5,3,3,3,5,0,4,0,3,0,4,4,3,4,3,3,0,4,1,1,3,4), -(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), -(0,4,0,3,0,3,0,4,0,3,4,4,3,2,2,1,2,1,3,1,3,3,3,3,3,4,3,1,3,3,5,3,3,0,4,3,0,5,4,3,3,5,4,4,3,4,4,5,0,1,2,0,1,2,0,2,2,0,1,0,0,5,2,2,1,4,0,3,0,1,0,4,4,3,5,4,3,0,2,1,0,4,3), -(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), -(0,3,0,5,0,4,0,2,1,4,4,2,4,1,4,2,4,2,4,3,3,3,4,3,3,3,3,1,4,2,3,3,3,1,4,4,1,1,1,4,3,3,2,0,2,4,3,2,0,3,3,0,3,1,1,0,0,0,3,3,0,4,2,2,3,4,0,4,0,3,0,4,4,5,3,4,4,0,3,0,0,1,4), -(1,4,0,4,0,4,0,4,0,3,5,4,4,3,4,3,5,4,3,3,4,3,5,4,4,4,4,3,4,2,4,3,3,1,5,4,3,2,4,5,4,5,5,4,4,5,4,4,0,3,2,2,3,3,0,4,3,1,3,2,1,4,3,3,4,5,0,3,0,2,0,4,5,5,4,5,4,0,4,0,0,5,4), -(0,5,0,5,0,4,0,3,0,4,4,3,4,3,3,3,4,0,4,4,4,3,4,3,4,3,3,1,4,2,4,3,4,0,5,4,1,4,5,4,4,5,3,2,4,3,4,3,2,4,1,3,3,3,2,3,2,0,4,3,3,4,3,3,3,4,0,4,0,3,0,4,5,4,4,4,3,0,4,1,0,1,3), -(0,3,1,4,0,3,0,2,0,3,4,4,3,1,4,2,3,3,4,3,4,3,4,3,4,4,3,2,3,1,5,4,4,1,4,4,3,5,4,4,3,5,5,4,3,4,4,3,1,2,3,1,2,2,0,3,2,0,3,1,0,5,3,3,3,4,3,3,3,3,4,4,4,4,5,4,2,0,3,3,2,4,3), -(0,2,0,3,0,1,0,1,0,0,3,2,0,0,2,0,1,0,2,1,3,3,3,1,2,3,1,0,1,0,4,2,1,1,3,3,0,4,3,3,1,4,3,3,0,3,3,2,0,0,0,0,1,0,0,2,0,0,0,0,0,4,1,0,2,3,2,2,2,1,3,3,3,4,4,3,2,0,3,1,0,3,3), -(0,4,0,4,0,3,0,3,0,4,4,4,3,3,3,3,3,3,4,3,4,2,4,3,4,3,3,2,4,3,4,5,4,1,4,5,3,5,4,5,3,5,4,0,3,5,5,3,1,3,3,2,2,3,0,3,4,1,3,3,2,4,3,3,3,4,0,4,0,3,0,4,5,4,4,5,3,0,4,1,0,3,4), -(0,2,0,3,0,3,0,0,0,2,2,2,1,0,1,0,0,0,3,0,3,0,3,0,1,3,1,0,3,1,3,3,3,1,3,3,3,0,1,3,1,3,4,0,0,3,1,1,0,3,2,0,0,0,0,1,3,0,1,0,0,3,3,2,0,3,0,0,0,0,0,3,4,3,4,3,3,0,3,0,0,2,3), -(2,3,0,3,0,2,0,1,0,3,3,4,3,1,3,1,1,1,3,1,4,3,4,3,3,3,0,0,3,1,5,4,3,1,4,3,2,5,5,4,4,4,4,3,3,4,4,4,0,2,1,1,3,2,0,1,2,0,0,1,0,4,1,3,3,3,0,3,0,1,0,4,4,4,5,5,3,0,2,0,0,4,4), -(0,2,0,1,0,3,1,3,0,2,3,3,3,0,3,1,0,0,3,0,3,2,3,1,3,2,1,1,0,0,4,2,1,0,2,3,1,4,3,2,0,4,4,3,1,3,1,3,0,1,0,0,1,0,0,0,1,0,0,0,0,4,1,1,1,2,0,3,0,0,0,3,4,2,4,3,2,0,1,0,0,3,3), -(0,1,0,4,0,5,0,4,0,2,4,4,2,3,3,2,3,3,5,3,3,3,4,3,4,2,3,0,4,3,3,3,4,1,4,3,2,1,5,5,3,4,5,1,3,5,4,2,0,3,3,0,1,3,0,4,2,0,1,3,1,4,3,3,3,3,0,3,0,1,0,3,4,4,4,5,5,0,3,0,1,4,5), -(0,2,0,3,0,3,0,0,0,2,3,1,3,0,4,0,1,1,3,0,3,4,3,2,3,1,0,3,3,2,3,1,3,0,2,3,0,2,1,4,1,2,2,0,0,3,3,0,0,2,0,0,0,1,0,0,0,0,2,2,0,3,2,1,3,3,0,2,0,2,0,0,3,3,1,2,4,0,3,0,2,2,3), -(2,4,0,5,0,4,0,4,0,2,4,4,4,3,4,3,3,3,1,2,4,3,4,3,4,4,5,0,3,3,3,3,2,0,4,3,1,4,3,4,1,4,4,3,3,4,4,3,1,2,3,0,4,2,0,4,1,0,3,3,0,4,3,3,3,4,0,4,0,2,0,3,5,3,4,5,2,0,3,0,0,4,5), -(0,3,0,4,0,1,0,1,0,1,3,2,2,1,3,0,3,0,2,0,2,0,3,0,2,0,0,0,1,0,1,1,0,0,3,1,0,0,0,4,0,3,1,0,2,1,3,0,0,0,0,0,0,3,0,0,0,0,0,0,0,4,2,2,3,1,0,3,0,0,0,1,4,4,4,3,0,0,4,0,0,1,4), -(1,4,1,5,0,3,0,3,0,4,5,4,4,3,5,3,3,4,4,3,4,1,3,3,3,3,2,1,4,1,5,4,3,1,4,4,3,5,4,4,3,5,4,3,3,4,4,4,0,3,3,1,2,3,0,3,1,0,3,3,0,5,4,4,4,4,4,4,3,3,5,4,4,3,3,5,4,0,3,2,0,4,4), -(0,2,0,3,0,1,0,0,0,1,3,3,3,2,4,1,3,0,3,1,3,0,2,2,1,1,0,0,2,0,4,3,1,0,4,3,0,4,4,4,1,4,3,1,1,3,3,1,0,2,0,0,1,3,0,0,0,0,2,0,0,4,3,2,4,3,5,4,3,3,3,4,3,3,4,3,3,0,2,1,0,3,3), -(0,2,0,4,0,3,0,2,0,2,5,5,3,4,4,4,4,1,4,3,3,0,4,3,4,3,1,3,3,2,4,3,0,3,4,3,0,3,4,4,2,4,4,0,4,5,3,3,2,2,1,1,1,2,0,1,5,0,3,3,2,4,3,3,3,4,0,3,0,2,0,4,4,3,5,5,0,0,3,0,2,3,3), -(0,3,0,4,0,3,0,1,0,3,4,3,3,1,3,3,3,0,3,1,3,0,4,3,3,1,1,0,3,0,3,3,0,0,4,4,0,1,5,4,3,3,5,0,3,3,4,3,0,2,0,1,1,1,0,1,3,0,1,2,1,3,3,2,3,3,0,3,0,1,0,1,3,3,4,4,1,0,1,2,2,1,3), -(0,1,0,4,0,4,0,3,0,1,3,3,3,2,3,1,1,0,3,0,3,3,4,3,2,4,2,0,1,0,4,3,2,0,4,3,0,5,3,3,2,4,4,4,3,3,3,4,0,1,3,0,0,1,0,0,1,0,0,0,0,4,2,3,3,3,0,3,0,0,0,4,4,4,5,3,2,0,3,3,0,3,5), -(0,2,0,3,0,0,0,3,0,1,3,0,2,0,0,0,1,0,3,1,1,3,3,0,0,3,0,0,3,0,2,3,1,0,3,1,0,3,3,2,0,4,2,2,0,2,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,2,1,2,0,1,0,1,0,0,0,1,3,1,2,0,0,0,1,0,0,1,4), -(0,3,0,3,0,5,0,1,0,2,4,3,1,3,3,2,1,1,5,2,1,0,5,1,2,0,0,0,3,3,2,2,3,2,4,3,0,0,3,3,1,3,3,0,2,5,3,4,0,3,3,0,1,2,0,2,2,0,3,2,0,2,2,3,3,3,0,2,0,1,0,3,4,4,2,5,4,0,3,0,0,3,5), -(0,3,0,3,0,3,0,1,0,3,3,3,3,0,3,0,2,0,2,1,1,0,2,0,1,0,0,0,2,1,0,0,1,0,3,2,0,0,3,3,1,2,3,1,0,3,3,0,0,1,0,0,0,0,0,2,0,0,0,0,0,2,3,1,2,3,0,3,0,1,0,3,2,1,0,4,3,0,1,1,0,3,3), -(0,4,0,5,0,3,0,3,0,4,5,5,4,3,5,3,4,3,5,3,3,2,5,3,4,4,4,3,4,3,4,5,5,3,4,4,3,4,4,5,4,4,4,3,4,5,5,4,2,3,4,2,3,4,0,3,3,1,4,3,2,4,3,3,5,5,0,3,0,3,0,5,5,5,5,4,4,0,4,0,1,4,4), -(0,4,0,4,0,3,0,3,0,3,5,4,4,2,3,2,5,1,3,2,5,1,4,2,3,2,3,3,4,3,3,3,3,2,5,4,1,3,3,5,3,4,4,0,4,4,3,1,1,3,1,0,2,3,0,2,3,0,3,0,0,4,3,1,3,4,0,3,0,2,0,4,4,4,3,4,5,0,4,0,0,3,4), -(0,3,0,3,0,3,1,2,0,3,4,4,3,3,3,0,2,2,4,3,3,1,3,3,3,1,1,0,3,1,4,3,2,3,4,4,2,4,4,4,3,4,4,3,2,4,4,3,1,3,3,1,3,3,0,4,1,0,2,2,1,4,3,2,3,3,5,4,3,3,5,4,4,3,3,0,4,0,3,2,2,4,4), -(0,2,0,1,0,0,0,0,0,1,2,1,3,0,0,0,0,0,2,0,1,2,1,0,0,1,0,0,0,0,3,0,0,1,0,1,1,3,1,0,0,0,1,1,0,1,1,0,0,0,0,0,2,0,0,0,0,0,0,0,0,1,1,2,2,0,3,4,0,0,0,1,1,0,0,1,0,0,0,0,0,1,1), -(0,1,0,0,0,1,0,0,0,0,4,0,4,1,4,0,3,0,4,0,3,0,4,0,3,0,3,0,4,1,5,1,4,0,0,3,0,5,0,5,2,0,1,0,0,0,2,1,4,0,1,3,0,0,3,0,0,3,1,1,4,1,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0), -(1,4,0,5,0,3,0,2,0,3,5,4,4,3,4,3,5,3,4,3,3,0,4,3,3,3,3,3,3,2,4,4,3,1,3,4,4,5,4,4,3,4,4,1,3,5,4,3,3,3,1,2,2,3,3,1,3,1,3,3,3,5,3,3,4,5,0,3,0,3,0,3,4,3,4,4,3,0,3,0,2,4,3), -(0,1,0,4,0,0,0,0,0,1,4,0,4,1,4,2,4,0,3,0,1,0,1,0,0,0,0,0,2,0,3,1,1,1,0,3,0,0,0,1,2,1,0,0,1,1,1,1,0,1,0,0,0,1,0,0,3,0,0,0,0,3,2,0,2,2,0,1,0,0,0,2,3,2,3,3,0,0,0,0,2,1,0), -(0,5,1,5,0,3,0,3,0,5,4,4,5,1,5,3,3,0,4,3,4,3,5,3,4,3,3,2,4,3,4,3,3,0,3,3,1,4,4,3,4,4,4,3,4,5,5,3,2,3,1,1,3,3,1,3,1,1,3,3,2,4,5,3,3,5,0,4,0,3,0,4,4,3,5,3,3,0,3,4,0,4,3), -(0,5,0,5,0,3,0,2,0,4,4,3,5,2,4,3,3,3,4,4,4,3,5,3,5,3,3,1,4,0,4,3,3,0,3,3,0,4,4,4,4,5,4,3,3,5,5,3,2,3,1,2,3,2,0,1,0,0,3,2,2,4,4,3,1,5,0,4,0,3,0,4,3,1,3,2,1,0,3,3,0,3,3), -(0,4,0,5,0,5,0,4,0,4,5,5,5,3,4,3,3,2,5,4,4,3,5,3,5,3,4,0,4,3,4,4,3,2,4,4,3,4,5,4,4,5,5,0,3,5,5,4,1,3,3,2,3,3,1,3,1,0,4,3,1,4,4,3,4,5,0,4,0,2,0,4,3,4,4,3,3,0,4,0,0,5,5), -(0,4,0,4,0,5,0,1,1,3,3,4,4,3,4,1,3,0,5,1,3,0,3,1,3,1,1,0,3,0,3,3,4,0,4,3,0,4,4,4,3,4,4,0,3,5,4,1,0,3,0,0,2,3,0,3,1,0,3,1,0,3,2,1,3,5,0,3,0,1,0,3,2,3,3,4,4,0,2,2,0,4,4), -(2,4,0,5,0,4,0,3,0,4,5,5,4,3,5,3,5,3,5,3,5,2,5,3,4,3,3,4,3,4,5,3,2,1,5,4,3,2,3,4,5,3,4,1,2,5,4,3,0,3,3,0,3,2,0,2,3,0,4,1,0,3,4,3,3,5,0,3,0,1,0,4,5,5,5,4,3,0,4,2,0,3,5), -(0,5,0,4,0,4,0,2,0,5,4,3,4,3,4,3,3,3,4,3,4,2,5,3,5,3,4,1,4,3,4,4,4,0,3,5,0,4,4,4,4,5,3,1,3,4,5,3,3,3,3,3,3,3,0,2,2,0,3,3,2,4,3,3,3,5,3,4,1,3,3,5,3,2,0,0,0,0,4,3,1,3,3), -(0,1,0,3,0,3,0,1,0,1,3,3,3,2,3,3,3,0,3,0,0,0,3,1,3,0,0,0,2,2,2,3,0,0,3,2,0,1,2,4,1,3,3,0,0,3,3,3,0,1,0,0,2,1,0,0,3,0,3,1,0,3,0,0,1,3,0,2,0,1,0,3,3,1,3,3,0,0,1,1,0,3,3), -(0,2,0,3,0,2,1,4,0,2,2,3,1,1,3,1,1,0,2,0,3,1,2,3,1,3,0,0,1,0,4,3,2,3,3,3,1,4,2,3,3,3,3,1,0,3,1,4,0,1,1,0,1,2,0,1,1,0,1,1,0,3,1,3,2,2,0,1,0,0,0,2,3,3,3,1,0,0,0,0,0,2,3), -(0,5,0,4,0,5,0,2,0,4,5,5,3,3,4,3,3,1,5,4,4,2,4,4,4,3,4,2,4,3,5,5,4,3,3,4,3,3,5,5,4,5,5,1,3,4,5,3,1,4,3,1,3,3,0,3,3,1,4,3,1,4,5,3,3,5,0,4,0,3,0,5,3,3,1,4,3,0,4,0,1,5,3), -(0,5,0,5,0,4,0,2,0,4,4,3,4,3,3,3,3,3,5,4,4,4,4,4,4,5,3,3,5,2,4,4,4,3,4,4,3,3,4,4,5,5,3,3,4,3,4,3,3,4,3,3,3,3,1,2,2,1,4,3,3,5,4,4,3,4,0,4,0,3,0,4,4,4,4,4,1,0,4,2,0,2,4), -(0,4,0,4,0,3,0,1,0,3,5,2,3,0,3,0,2,1,4,2,3,3,4,1,4,3,3,2,4,1,3,3,3,0,3,3,0,0,3,3,3,5,3,3,3,3,3,2,0,2,0,0,2,0,0,2,0,0,1,0,0,3,1,2,2,3,0,3,0,2,0,4,4,3,3,4,1,0,3,0,0,2,4), -(0,0,0,4,0,0,0,0,0,0,1,0,1,0,2,0,0,0,0,0,1,0,2,0,1,0,0,0,0,0,3,1,3,0,3,2,0,0,0,1,0,3,2,0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,4,0,2,0,0,0,0,0,0,2), -(0,2,1,3,0,2,0,2,0,3,3,3,3,1,3,1,3,3,3,3,3,3,4,2,2,1,2,1,4,0,4,3,1,3,3,3,2,4,3,5,4,3,3,3,3,3,3,3,0,1,3,0,2,0,0,1,0,0,1,0,0,4,2,0,2,3,0,3,3,0,3,3,4,2,3,1,4,0,1,2,0,2,3), -(0,3,0,3,0,1,0,3,0,2,3,3,3,0,3,1,2,0,3,3,2,3,3,2,3,2,3,1,3,0,4,3,2,0,3,3,1,4,3,3,2,3,4,3,1,3,3,1,1,0,1,1,0,1,0,1,0,1,0,0,0,4,1,1,0,3,0,3,1,0,2,3,3,3,3,3,1,0,0,2,0,3,3), -(0,0,0,0,0,0,0,0,0,0,3,0,2,0,3,0,0,0,0,0,0,0,3,0,0,0,0,0,0,0,3,0,3,0,3,1,0,1,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,2,0,2,3,0,0,0,0,0,0,0,0,3), -(0,2,0,3,1,3,0,3,0,2,3,3,3,1,3,1,3,1,3,1,3,3,3,1,3,0,2,3,1,1,4,3,3,2,3,3,1,2,2,4,1,3,3,0,1,4,2,3,0,1,3,0,3,0,0,1,3,0,2,0,0,3,3,2,1,3,0,3,0,2,0,3,4,4,4,3,1,0,3,0,0,3,3), -(0,2,0,1,0,2,0,0,0,1,3,2,2,1,3,0,1,1,3,0,3,2,3,1,2,0,2,0,1,1,3,3,3,0,3,3,1,1,2,3,2,3,3,1,2,3,2,0,0,1,0,0,0,0,0,0,3,0,1,0,0,2,1,2,1,3,0,3,0,0,0,3,4,4,4,3,2,0,2,0,0,2,4), -(0,0,0,1,0,1,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,2,2,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,3,1,0,0,0,0,0,0,0,3), -(0,3,0,3,0,2,0,3,0,3,3,3,2,3,2,2,2,0,3,1,3,3,3,2,3,3,0,0,3,0,3,2,2,0,2,3,1,4,3,4,3,3,2,3,1,5,4,4,0,3,1,2,1,3,0,3,1,1,2,0,2,3,1,3,1,3,0,3,0,1,0,3,3,4,4,2,1,0,2,1,0,2,4), -(0,1,0,3,0,1,0,2,0,1,4,2,5,1,4,0,2,0,2,1,3,1,4,0,2,1,0,0,2,1,4,1,1,0,3,3,0,5,1,3,2,3,3,1,0,3,2,3,0,1,0,0,0,0,0,0,1,0,0,0,0,4,0,1,0,3,0,2,0,1,0,3,3,3,4,3,3,0,0,0,0,2,3), -(0,0,0,1,0,0,0,0,0,0,2,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,1,0,0,1,0,0,0,0,0,3), -(0,1,0,3,0,4,0,3,0,2,4,3,1,0,3,2,2,1,3,1,2,2,3,1,1,1,2,1,3,0,1,2,0,1,3,2,1,3,0,5,5,1,0,0,1,3,2,1,0,3,0,0,1,0,0,0,0,0,3,4,0,1,1,1,3,2,0,2,0,1,0,2,3,3,1,2,3,0,1,0,1,0,4), -(0,0,0,1,0,3,0,3,0,2,2,1,0,0,4,0,3,0,3,1,3,0,3,0,3,0,1,0,3,0,3,1,3,0,3,3,0,0,1,2,1,1,1,0,1,2,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,2,2,1,2,0,0,2,0,0,0,0,2,3,3,3,3,0,0,0,0,1,4), -(0,0,0,3,0,3,0,0,0,0,3,1,1,0,3,0,1,0,2,0,1,0,0,0,0,0,0,0,1,0,3,0,2,0,2,3,0,0,2,2,3,1,2,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,2,0,0,0,0,2,3), -(2,4,0,5,0,5,0,4,0,3,4,3,3,3,4,3,3,3,4,3,4,4,5,4,5,5,5,2,3,0,5,5,4,1,5,4,3,1,5,4,3,4,4,3,3,4,3,3,0,3,2,0,2,3,0,3,0,0,3,3,0,5,3,2,3,3,0,3,0,3,0,3,4,5,4,5,3,0,4,3,0,3,4), -(0,3,0,3,0,3,0,3,0,3,3,4,3,2,3,2,3,0,4,3,3,3,3,3,3,3,3,0,3,2,4,3,3,1,3,4,3,4,4,4,3,4,4,3,2,4,4,1,0,2,0,0,1,1,0,2,0,0,3,1,0,5,3,2,1,3,0,3,0,1,2,4,3,2,4,3,3,0,3,2,0,4,4), -(0,3,0,3,0,1,0,0,0,1,4,3,3,2,3,1,3,1,4,2,3,2,4,2,3,4,3,0,2,2,3,3,3,0,3,3,3,0,3,4,1,3,3,0,3,4,3,3,0,1,1,0,1,0,0,0,4,0,3,0,0,3,1,2,1,3,0,4,0,1,0,4,3,3,4,3,3,0,2,0,0,3,3), -(0,3,0,4,0,1,0,3,0,3,4,3,3,0,3,3,3,1,3,1,3,3,4,3,3,3,0,0,3,1,5,3,3,1,3,3,2,5,4,3,3,4,5,3,2,5,3,4,0,1,0,0,0,0,0,2,0,0,1,1,0,4,2,2,1,3,0,3,0,2,0,4,4,3,5,3,2,0,1,1,0,3,4), -(0,5,0,4,0,5,0,2,0,4,4,3,3,2,3,3,3,1,4,3,4,1,5,3,4,3,4,0,4,2,4,3,4,1,5,4,0,4,4,4,4,5,4,1,3,5,4,2,1,4,1,1,3,2,0,3,1,0,3,2,1,4,3,3,3,4,0,4,0,3,0,4,4,4,3,3,3,0,4,2,0,3,4), -(1,4,0,4,0,3,0,1,0,3,3,3,1,1,3,3,2,2,3,3,1,0,3,2,2,1,2,0,3,1,2,1,2,0,3,2,0,2,2,3,3,4,3,0,3,3,1,2,0,1,1,3,1,2,0,0,3,0,1,1,0,3,2,2,3,3,0,3,0,0,0,2,3,3,4,3,3,0,1,0,0,1,4), -(0,4,0,4,0,4,0,0,0,3,4,4,3,1,4,2,3,2,3,3,3,1,4,3,4,0,3,0,4,2,3,3,2,2,5,4,2,1,3,4,3,4,3,1,3,3,4,2,0,2,1,0,3,3,0,0,2,0,3,1,0,4,4,3,4,3,0,4,0,1,0,2,4,4,4,4,4,0,3,2,0,3,3), -(0,0,0,1,0,4,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,3,2,0,0,1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,2), -(0,2,0,3,0,4,0,4,0,1,3,3,3,0,4,0,2,1,2,1,1,1,2,0,3,1,1,0,1,0,3,1,0,0,3,3,2,0,1,1,0,0,0,0,0,1,0,2,0,2,2,0,3,1,0,0,1,0,1,1,0,1,2,0,3,0,0,0,0,1,0,0,3,3,4,3,1,0,1,0,3,0,2), -(0,0,0,3,0,5,0,0,0,0,1,0,2,0,3,1,0,1,3,0,0,0,2,0,0,0,1,0,0,0,1,1,0,0,4,0,0,0,2,3,0,1,4,1,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,1,0,0,0,0,0,0,0,2,0,0,3,0,0,0,0,0,3), -(0,2,0,5,0,5,0,1,0,2,4,3,3,2,5,1,3,2,3,3,3,0,4,1,2,0,3,0,4,0,2,2,1,1,5,3,0,0,1,4,2,3,2,0,3,3,3,2,0,2,4,1,1,2,0,1,1,0,3,1,0,1,3,1,2,3,0,2,0,0,0,1,3,5,4,4,4,0,3,0,0,1,3), -(0,4,0,5,0,4,0,4,0,4,5,4,3,3,4,3,3,3,4,3,4,4,5,3,4,5,4,2,4,2,3,4,3,1,4,4,1,3,5,4,4,5,5,4,4,5,5,5,2,3,3,1,4,3,1,3,3,0,3,3,1,4,3,4,4,4,0,3,0,4,0,3,3,4,4,5,0,0,4,3,0,4,5), -(0,4,0,4,0,3,0,3,0,3,4,4,4,3,3,2,4,3,4,3,4,3,5,3,4,3,2,1,4,2,4,4,3,1,3,4,2,4,5,5,3,4,5,4,1,5,4,3,0,3,2,2,3,2,1,3,1,0,3,3,3,5,3,3,3,5,4,4,2,3,3,4,3,3,3,2,1,0,3,2,1,4,3), -(0,4,0,5,0,4,0,3,0,3,5,5,3,2,4,3,4,0,5,4,4,1,4,4,4,3,3,3,4,3,5,5,2,3,3,4,1,2,5,5,3,5,5,2,3,5,5,4,0,3,2,0,3,3,1,1,5,1,4,1,0,4,3,2,3,5,0,4,0,3,0,5,4,3,4,3,0,0,4,1,0,4,4), -(1,3,0,4,0,2,0,2,0,2,5,5,3,3,3,3,3,0,4,2,3,4,4,4,3,4,0,0,3,4,5,4,3,3,3,3,2,5,5,4,5,5,5,4,3,5,5,5,1,3,1,0,1,0,0,3,2,0,4,2,0,5,2,3,2,4,1,3,0,3,0,4,5,4,5,4,3,0,4,2,0,5,4), -(0,3,0,4,0,5,0,3,0,3,4,4,3,2,3,2,3,3,3,3,3,2,4,3,3,2,2,0,3,3,3,3,3,1,3,3,3,0,4,4,3,4,4,1,1,4,4,2,0,3,1,0,1,1,0,4,1,0,2,3,1,3,3,1,3,4,0,3,0,1,0,3,1,3,0,0,1,0,2,0,0,4,4), -(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0), -(0,3,0,3,0,2,0,3,0,1,5,4,3,3,3,1,4,2,1,2,3,4,4,2,4,4,5,0,3,1,4,3,4,0,4,3,3,3,2,3,2,5,3,4,3,2,2,3,0,0,3,0,2,1,0,1,2,0,0,0,0,2,1,1,3,1,0,2,0,4,0,3,4,4,4,5,2,0,2,0,0,1,3), -(0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,1,1,0,0,1,1,0,0,0,4,2,1,1,0,1,0,3,2,0,0,3,1,1,1,2,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,1,0,0,0,2,0,0,0,1,4,0,4,2,1,0,0,0,0,0,1), -(0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,1,0,0,0,0,0,0,1,0,1,0,0,0,0,3,1,0,0,0,2,0,2,1,0,0,1,2,1,0,1,1,0,0,3,0,0,0,0,0,0,0,0,0,0,0,1,3,1,0,0,0,0,0,1,0,0,2,1,0,0,0,0,0,0,0,0,2), -(0,4,0,4,0,4,0,3,0,4,4,3,4,2,4,3,2,0,4,4,4,3,5,3,5,3,3,2,4,2,4,3,4,3,1,4,0,2,3,4,4,4,3,3,3,4,4,4,3,4,1,3,4,3,2,1,2,1,3,3,3,4,4,3,3,5,0,4,0,3,0,4,3,3,3,2,1,0,3,0,0,3,3), -(0,4,0,3,0,3,0,3,0,3,5,5,3,3,3,3,4,3,4,3,3,3,4,4,4,3,3,3,3,4,3,5,3,3,1,3,2,4,5,5,5,5,4,3,4,5,5,3,2,2,3,3,3,3,2,3,3,1,2,3,2,4,3,3,3,4,0,4,0,2,0,4,3,2,2,1,2,0,3,0,0,4,1), -) - -class JapaneseContextAnalysis(object): - NUM_OF_CATEGORY = 6 - DONT_KNOW = -1 - ENOUGH_REL_THRESHOLD = 100 - MAX_REL_THRESHOLD = 1000 - MINIMUM_DATA_THRESHOLD = 4 - - def __init__(self): - self._total_rel = None - self._rel_sample = None - self._need_to_skip_char_num = None - self._last_char_order = None - self._done = None - self.reset() - - def reset(self): - self._total_rel = 0 # total sequence received - # category counters, each integer counts sequence in its category - self._rel_sample = [0] * self.NUM_OF_CATEGORY - # if last byte in current buffer is not the last byte of a character, - # we need to know how many bytes to skip in next buffer - self._need_to_skip_char_num = 0 - self._last_char_order = -1 # The order of previous char - # If this flag is set to True, detection is done and conclusion has - # been made - self._done = False - - def feed(self, byte_str, num_bytes): - if self._done: - return - - # The buffer we got is byte oriented, and a character may span in more than one - # buffers. In case the last one or two byte in last buffer is not - # complete, we record how many byte needed to complete that character - # and skip these bytes here. We can choose to record those bytes as - # well and analyse the character once it is complete, but since a - # character will not make much difference, by simply skipping - # this character will simply our logic and improve performance. - i = self._need_to_skip_char_num - while i < num_bytes: - order, char_len = self.get_order(byte_str[i:i + 2]) - i += char_len - if i > num_bytes: - self._need_to_skip_char_num = i - num_bytes - self._last_char_order = -1 - else: - if (order != -1) and (self._last_char_order != -1): - self._total_rel += 1 - if self._total_rel > self.MAX_REL_THRESHOLD: - self._done = True - break - self._rel_sample[jp2CharContext[self._last_char_order][order]] += 1 - self._last_char_order = order - - def got_enough_data(self): - return self._total_rel > self.ENOUGH_REL_THRESHOLD - - def get_confidence(self): - # This is just one way to calculate confidence. It works well for me. - if self._total_rel > self.MINIMUM_DATA_THRESHOLD: - return (self._total_rel - self._rel_sample[0]) / self._total_rel - else: - return self.DONT_KNOW - - def get_order(self, byte_str): - return -1, 1 - -class SJISContextAnalysis(JapaneseContextAnalysis): - def __init__(self): - super(SJISContextAnalysis, self).__init__() - self._charset_name = "SHIFT_JIS" - - @property - def charset_name(self): - return self._charset_name - - def get_order(self, byte_str): - if not byte_str: - return -1, 1 - # find out current char's byte length - first_char = byte_str[0] - if (0x81 <= first_char <= 0x9F) or (0xE0 <= first_char <= 0xFC): - char_len = 2 - if (first_char == 0x87) or (0xFA <= first_char <= 0xFC): - self._charset_name = "CP932" - else: - char_len = 1 - - # return its order if it is hiragana - if len(byte_str) > 1: - second_char = byte_str[1] - if (first_char == 202) and (0x9F <= second_char <= 0xF1): - return second_char - 0x9F, char_len - - return -1, char_len - -class EUCJPContextAnalysis(JapaneseContextAnalysis): - def get_order(self, byte_str): - if not byte_str: - return -1, 1 - # find out current char's byte length - first_char = byte_str[0] - if (first_char == 0x8E) or (0xA1 <= first_char <= 0xFE): - char_len = 2 - elif first_char == 0x8F: - char_len = 3 - else: - char_len = 1 - - # return its order if it is hiragana - if len(byte_str) > 1: - second_char = byte_str[1] - if (first_char == 0xA4) and (0xA1 <= second_char <= 0xF3): - return second_char - 0xA1, char_len - - return -1, char_len - - diff --git a/venv/lib/python3.8/site-packages/chardet/langbulgarianmodel.py b/venv/lib/python3.8/site-packages/chardet/langbulgarianmodel.py deleted file mode 100644 index 561bfd9..0000000 --- a/venv/lib/python3.8/site-packages/chardet/langbulgarianmodel.py +++ /dev/null @@ -1,4650 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from chardet.sbcharsetprober import SingleByteCharSetModel - - -# 3: Positive -# 2: Likely -# 1: Unlikely -# 0: Negative - -BULGARIAN_LANG_MODEL = { - 63: { # 'e' - 63: 1, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 0, # 'а' - 18: 1, # 'б' - 9: 1, # 'в' - 20: 1, # 'г' - 11: 1, # 'д' - 3: 1, # 'е' - 23: 1, # 'ж' - 15: 1, # 'з' - 2: 0, # 'и' - 26: 1, # 'й' - 12: 1, # 'к' - 10: 1, # 'л' - 14: 1, # 'м' - 6: 1, # 'н' - 4: 1, # 'о' - 13: 1, # 'п' - 7: 1, # 'р' - 8: 1, # 'с' - 5: 1, # 'т' - 19: 0, # 'у' - 29: 1, # 'ф' - 25: 1, # 'х' - 22: 0, # 'ц' - 21: 1, # 'ч' - 27: 1, # 'ш' - 24: 1, # 'щ' - 17: 0, # 'ъ' - 52: 0, # 'ь' - 42: 0, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 45: { # '\xad' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 1, # 'Б' - 35: 1, # 'В' - 43: 0, # 'Г' - 37: 1, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 1, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 0, # 'Л' - 38: 1, # 'М' - 36: 0, # 'Н' - 41: 1, # 'О' - 30: 1, # 'П' - 39: 1, # 'Р' - 28: 1, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 1, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 0, # 'а' - 18: 0, # 'б' - 9: 0, # 'в' - 20: 0, # 'г' - 11: 0, # 'д' - 3: 0, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 0, # 'и' - 26: 0, # 'й' - 12: 0, # 'к' - 10: 0, # 'л' - 14: 0, # 'м' - 6: 0, # 'н' - 4: 0, # 'о' - 13: 0, # 'п' - 7: 0, # 'р' - 8: 0, # 'с' - 5: 0, # 'т' - 19: 0, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 0, # 'ъ' - 52: 0, # 'ь' - 42: 0, # 'ю' - 16: 0, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 31: { # 'А' - 63: 0, # 'e' - 45: 1, # '\xad' - 31: 1, # 'А' - 32: 1, # 'Б' - 35: 2, # 'В' - 43: 1, # 'Г' - 37: 2, # 'Д' - 44: 2, # 'Е' - 55: 1, # 'Ж' - 47: 2, # 'З' - 40: 1, # 'И' - 59: 1, # 'Й' - 33: 1, # 'К' - 46: 2, # 'Л' - 38: 1, # 'М' - 36: 2, # 'Н' - 41: 1, # 'О' - 30: 2, # 'П' - 39: 2, # 'Р' - 28: 2, # 'С' - 34: 2, # 'Т' - 51: 1, # 'У' - 48: 2, # 'Ф' - 49: 1, # 'Х' - 53: 1, # 'Ц' - 50: 1, # 'Ч' - 54: 1, # 'Ш' - 57: 2, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 1, # 'Я' - 1: 1, # 'а' - 18: 2, # 'б' - 9: 2, # 'в' - 20: 2, # 'г' - 11: 2, # 'д' - 3: 1, # 'е' - 23: 1, # 'ж' - 15: 2, # 'з' - 2: 0, # 'и' - 26: 2, # 'й' - 12: 2, # 'к' - 10: 3, # 'л' - 14: 2, # 'м' - 6: 3, # 'н' - 4: 0, # 'о' - 13: 2, # 'п' - 7: 2, # 'р' - 8: 2, # 'с' - 5: 2, # 'т' - 19: 1, # 'у' - 29: 2, # 'ф' - 25: 1, # 'х' - 22: 1, # 'ц' - 21: 1, # 'ч' - 27: 1, # 'ш' - 24: 0, # 'щ' - 17: 0, # 'ъ' - 52: 0, # 'ь' - 42: 0, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 32: { # 'Б' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 2, # 'А' - 32: 2, # 'Б' - 35: 1, # 'В' - 43: 1, # 'Г' - 37: 2, # 'Д' - 44: 1, # 'Е' - 55: 1, # 'Ж' - 47: 2, # 'З' - 40: 1, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 1, # 'Л' - 38: 1, # 'М' - 36: 2, # 'Н' - 41: 2, # 'О' - 30: 1, # 'П' - 39: 1, # 'Р' - 28: 2, # 'С' - 34: 2, # 'Т' - 51: 1, # 'У' - 48: 2, # 'Ф' - 49: 1, # 'Х' - 53: 1, # 'Ц' - 50: 1, # 'Ч' - 54: 0, # 'Ш' - 57: 1, # 'Щ' - 61: 2, # 'Ъ' - 60: 1, # 'Ю' - 56: 1, # 'Я' - 1: 3, # 'а' - 18: 0, # 'б' - 9: 0, # 'в' - 20: 0, # 'г' - 11: 1, # 'д' - 3: 3, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 2, # 'и' - 26: 0, # 'й' - 12: 0, # 'к' - 10: 2, # 'л' - 14: 0, # 'м' - 6: 0, # 'н' - 4: 3, # 'о' - 13: 0, # 'п' - 7: 2, # 'р' - 8: 1, # 'с' - 5: 0, # 'т' - 19: 2, # 'у' - 29: 0, # 'ф' - 25: 1, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 3, # 'ъ' - 52: 1, # 'ь' - 42: 1, # 'ю' - 16: 2, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 35: { # 'В' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 2, # 'А' - 32: 1, # 'Б' - 35: 1, # 'В' - 43: 0, # 'Г' - 37: 1, # 'Д' - 44: 2, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 2, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 1, # 'Л' - 38: 1, # 'М' - 36: 1, # 'Н' - 41: 1, # 'О' - 30: 1, # 'П' - 39: 2, # 'Р' - 28: 2, # 'С' - 34: 1, # 'Т' - 51: 1, # 'У' - 48: 2, # 'Ф' - 49: 0, # 'Х' - 53: 1, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 1, # 'Ъ' - 60: 1, # 'Ю' - 56: 2, # 'Я' - 1: 3, # 'а' - 18: 1, # 'б' - 9: 0, # 'в' - 20: 0, # 'г' - 11: 1, # 'д' - 3: 3, # 'е' - 23: 1, # 'ж' - 15: 2, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 1, # 'к' - 10: 2, # 'л' - 14: 1, # 'м' - 6: 2, # 'н' - 4: 2, # 'о' - 13: 1, # 'п' - 7: 2, # 'р' - 8: 2, # 'с' - 5: 2, # 'т' - 19: 1, # 'у' - 29: 0, # 'ф' - 25: 1, # 'х' - 22: 0, # 'ц' - 21: 2, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 2, # 'ъ' - 52: 1, # 'ь' - 42: 1, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 43: { # 'Г' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 2, # 'А' - 32: 1, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 1, # 'Д' - 44: 2, # 'Е' - 55: 0, # 'Ж' - 47: 1, # 'З' - 40: 1, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 1, # 'Л' - 38: 0, # 'М' - 36: 1, # 'Н' - 41: 1, # 'О' - 30: 0, # 'П' - 39: 1, # 'Р' - 28: 1, # 'С' - 34: 0, # 'Т' - 51: 1, # 'У' - 48: 1, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 1, # 'Щ' - 61: 1, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 2, # 'а' - 18: 1, # 'б' - 9: 1, # 'в' - 20: 0, # 'г' - 11: 1, # 'д' - 3: 3, # 'е' - 23: 1, # 'ж' - 15: 0, # 'з' - 2: 2, # 'и' - 26: 0, # 'й' - 12: 1, # 'к' - 10: 2, # 'л' - 14: 1, # 'м' - 6: 1, # 'н' - 4: 2, # 'о' - 13: 0, # 'п' - 7: 2, # 'р' - 8: 0, # 'с' - 5: 0, # 'т' - 19: 2, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 1, # 'щ' - 17: 2, # 'ъ' - 52: 1, # 'ь' - 42: 1, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 37: { # 'Д' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 2, # 'А' - 32: 1, # 'Б' - 35: 2, # 'В' - 43: 1, # 'Г' - 37: 2, # 'Д' - 44: 2, # 'Е' - 55: 2, # 'Ж' - 47: 1, # 'З' - 40: 2, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 1, # 'Л' - 38: 1, # 'М' - 36: 1, # 'Н' - 41: 2, # 'О' - 30: 2, # 'П' - 39: 1, # 'Р' - 28: 2, # 'С' - 34: 1, # 'Т' - 51: 1, # 'У' - 48: 1, # 'Ф' - 49: 0, # 'Х' - 53: 1, # 'Ц' - 50: 1, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 1, # 'Ъ' - 60: 1, # 'Ю' - 56: 1, # 'Я' - 1: 3, # 'а' - 18: 0, # 'б' - 9: 2, # 'в' - 20: 0, # 'г' - 11: 0, # 'д' - 3: 3, # 'е' - 23: 3, # 'ж' - 15: 1, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 0, # 'к' - 10: 1, # 'л' - 14: 1, # 'м' - 6: 2, # 'н' - 4: 3, # 'о' - 13: 0, # 'п' - 7: 2, # 'р' - 8: 0, # 'с' - 5: 0, # 'т' - 19: 2, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 2, # 'ъ' - 52: 1, # 'ь' - 42: 2, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 44: { # 'Е' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 1, # 'А' - 32: 1, # 'Б' - 35: 2, # 'В' - 43: 1, # 'Г' - 37: 1, # 'Д' - 44: 1, # 'Е' - 55: 1, # 'Ж' - 47: 1, # 'З' - 40: 1, # 'И' - 59: 1, # 'Й' - 33: 2, # 'К' - 46: 2, # 'Л' - 38: 1, # 'М' - 36: 2, # 'Н' - 41: 2, # 'О' - 30: 1, # 'П' - 39: 2, # 'Р' - 28: 2, # 'С' - 34: 2, # 'Т' - 51: 1, # 'У' - 48: 2, # 'Ф' - 49: 1, # 'Х' - 53: 2, # 'Ц' - 50: 1, # 'Ч' - 54: 1, # 'Ш' - 57: 1, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 1, # 'Я' - 1: 0, # 'а' - 18: 1, # 'б' - 9: 2, # 'в' - 20: 1, # 'г' - 11: 2, # 'д' - 3: 0, # 'е' - 23: 1, # 'ж' - 15: 1, # 'з' - 2: 0, # 'и' - 26: 1, # 'й' - 12: 2, # 'к' - 10: 2, # 'л' - 14: 2, # 'м' - 6: 2, # 'н' - 4: 0, # 'о' - 13: 1, # 'п' - 7: 2, # 'р' - 8: 2, # 'с' - 5: 1, # 'т' - 19: 1, # 'у' - 29: 1, # 'ф' - 25: 1, # 'х' - 22: 0, # 'ц' - 21: 1, # 'ч' - 27: 1, # 'ш' - 24: 1, # 'щ' - 17: 1, # 'ъ' - 52: 0, # 'ь' - 42: 1, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 55: { # 'Ж' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 1, # 'А' - 32: 0, # 'Б' - 35: 1, # 'В' - 43: 0, # 'Г' - 37: 1, # 'Д' - 44: 1, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 1, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 1, # 'Н' - 41: 1, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 1, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 2, # 'а' - 18: 0, # 'б' - 9: 0, # 'в' - 20: 0, # 'г' - 11: 1, # 'д' - 3: 2, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 2, # 'и' - 26: 0, # 'й' - 12: 0, # 'к' - 10: 0, # 'л' - 14: 0, # 'м' - 6: 0, # 'н' - 4: 2, # 'о' - 13: 1, # 'п' - 7: 1, # 'р' - 8: 0, # 'с' - 5: 0, # 'т' - 19: 1, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 1, # 'ъ' - 52: 1, # 'ь' - 42: 1, # 'ю' - 16: 0, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 47: { # 'З' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 2, # 'А' - 32: 1, # 'Б' - 35: 1, # 'В' - 43: 1, # 'Г' - 37: 1, # 'Д' - 44: 1, # 'Е' - 55: 0, # 'Ж' - 47: 1, # 'З' - 40: 1, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 1, # 'Л' - 38: 1, # 'М' - 36: 2, # 'Н' - 41: 1, # 'О' - 30: 1, # 'П' - 39: 1, # 'Р' - 28: 1, # 'С' - 34: 1, # 'Т' - 51: 1, # 'У' - 48: 0, # 'Ф' - 49: 1, # 'Х' - 53: 1, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 1, # 'Ъ' - 60: 0, # 'Ю' - 56: 1, # 'Я' - 1: 3, # 'а' - 18: 1, # 'б' - 9: 2, # 'в' - 20: 1, # 'г' - 11: 2, # 'д' - 3: 2, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 1, # 'и' - 26: 0, # 'й' - 12: 0, # 'к' - 10: 2, # 'л' - 14: 1, # 'м' - 6: 1, # 'н' - 4: 1, # 'о' - 13: 0, # 'п' - 7: 1, # 'р' - 8: 0, # 'с' - 5: 0, # 'т' - 19: 1, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 1, # 'ъ' - 52: 0, # 'ь' - 42: 1, # 'ю' - 16: 0, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 40: { # 'И' - 63: 0, # 'e' - 45: 1, # '\xad' - 31: 1, # 'А' - 32: 1, # 'Б' - 35: 1, # 'В' - 43: 1, # 'Г' - 37: 1, # 'Д' - 44: 2, # 'Е' - 55: 1, # 'Ж' - 47: 2, # 'З' - 40: 1, # 'И' - 59: 1, # 'Й' - 33: 2, # 'К' - 46: 2, # 'Л' - 38: 2, # 'М' - 36: 2, # 'Н' - 41: 1, # 'О' - 30: 1, # 'П' - 39: 2, # 'Р' - 28: 2, # 'С' - 34: 2, # 'Т' - 51: 0, # 'У' - 48: 1, # 'Ф' - 49: 1, # 'Х' - 53: 1, # 'Ц' - 50: 1, # 'Ч' - 54: 1, # 'Ш' - 57: 1, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 2, # 'Я' - 1: 1, # 'а' - 18: 1, # 'б' - 9: 3, # 'в' - 20: 2, # 'г' - 11: 1, # 'д' - 3: 1, # 'е' - 23: 0, # 'ж' - 15: 3, # 'з' - 2: 0, # 'и' - 26: 1, # 'й' - 12: 1, # 'к' - 10: 2, # 'л' - 14: 2, # 'м' - 6: 2, # 'н' - 4: 0, # 'о' - 13: 1, # 'п' - 7: 2, # 'р' - 8: 2, # 'с' - 5: 2, # 'т' - 19: 0, # 'у' - 29: 1, # 'ф' - 25: 1, # 'х' - 22: 1, # 'ц' - 21: 1, # 'ч' - 27: 1, # 'ш' - 24: 1, # 'щ' - 17: 0, # 'ъ' - 52: 0, # 'ь' - 42: 0, # 'ю' - 16: 0, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 59: { # 'Й' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 1, # 'Д' - 44: 1, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 1, # 'Л' - 38: 1, # 'М' - 36: 1, # 'Н' - 41: 1, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 1, # 'С' - 34: 1, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 1, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 1, # 'Я' - 1: 0, # 'а' - 18: 0, # 'б' - 9: 0, # 'в' - 20: 0, # 'г' - 11: 0, # 'д' - 3: 1, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 0, # 'и' - 26: 0, # 'й' - 12: 0, # 'к' - 10: 0, # 'л' - 14: 0, # 'м' - 6: 0, # 'н' - 4: 2, # 'о' - 13: 0, # 'п' - 7: 0, # 'р' - 8: 0, # 'с' - 5: 0, # 'т' - 19: 0, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 1, # 'ъ' - 52: 0, # 'ь' - 42: 0, # 'ю' - 16: 0, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 33: { # 'К' - 63: 0, # 'e' - 45: 1, # '\xad' - 31: 2, # 'А' - 32: 1, # 'Б' - 35: 1, # 'В' - 43: 1, # 'Г' - 37: 1, # 'Д' - 44: 1, # 'Е' - 55: 0, # 'Ж' - 47: 1, # 'З' - 40: 2, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 1, # 'Л' - 38: 0, # 'М' - 36: 2, # 'Н' - 41: 2, # 'О' - 30: 2, # 'П' - 39: 1, # 'Р' - 28: 2, # 'С' - 34: 1, # 'Т' - 51: 1, # 'У' - 48: 1, # 'Ф' - 49: 1, # 'Х' - 53: 1, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 1, # 'Ъ' - 60: 1, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 0, # 'б' - 9: 1, # 'в' - 20: 0, # 'г' - 11: 0, # 'д' - 3: 2, # 'е' - 23: 1, # 'ж' - 15: 0, # 'з' - 2: 2, # 'и' - 26: 0, # 'й' - 12: 0, # 'к' - 10: 2, # 'л' - 14: 1, # 'м' - 6: 2, # 'н' - 4: 3, # 'о' - 13: 0, # 'п' - 7: 3, # 'р' - 8: 1, # 'с' - 5: 0, # 'т' - 19: 2, # 'у' - 29: 0, # 'ф' - 25: 1, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 1, # 'ш' - 24: 0, # 'щ' - 17: 2, # 'ъ' - 52: 1, # 'ь' - 42: 2, # 'ю' - 16: 0, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 46: { # 'Л' - 63: 1, # 'e' - 45: 0, # '\xad' - 31: 2, # 'А' - 32: 1, # 'Б' - 35: 1, # 'В' - 43: 2, # 'Г' - 37: 1, # 'Д' - 44: 2, # 'Е' - 55: 0, # 'Ж' - 47: 1, # 'З' - 40: 2, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 1, # 'Л' - 38: 0, # 'М' - 36: 1, # 'Н' - 41: 2, # 'О' - 30: 1, # 'П' - 39: 0, # 'Р' - 28: 1, # 'С' - 34: 1, # 'Т' - 51: 1, # 'У' - 48: 0, # 'Ф' - 49: 1, # 'Х' - 53: 1, # 'Ц' - 50: 1, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 1, # 'Ъ' - 60: 1, # 'Ю' - 56: 1, # 'Я' - 1: 2, # 'а' - 18: 0, # 'б' - 9: 1, # 'в' - 20: 0, # 'г' - 11: 0, # 'д' - 3: 3, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 2, # 'и' - 26: 0, # 'й' - 12: 0, # 'к' - 10: 0, # 'л' - 14: 0, # 'м' - 6: 0, # 'н' - 4: 2, # 'о' - 13: 0, # 'п' - 7: 0, # 'р' - 8: 0, # 'с' - 5: 0, # 'т' - 19: 2, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 1, # 'ъ' - 52: 1, # 'ь' - 42: 2, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 38: { # 'М' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 2, # 'А' - 32: 1, # 'Б' - 35: 2, # 'В' - 43: 0, # 'Г' - 37: 1, # 'Д' - 44: 1, # 'Е' - 55: 0, # 'Ж' - 47: 1, # 'З' - 40: 2, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 1, # 'Л' - 38: 1, # 'М' - 36: 1, # 'Н' - 41: 2, # 'О' - 30: 1, # 'П' - 39: 1, # 'Р' - 28: 2, # 'С' - 34: 1, # 'Т' - 51: 1, # 'У' - 48: 1, # 'Ф' - 49: 0, # 'Х' - 53: 1, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 1, # 'Ъ' - 60: 0, # 'Ю' - 56: 1, # 'Я' - 1: 3, # 'а' - 18: 0, # 'б' - 9: 0, # 'в' - 20: 0, # 'г' - 11: 0, # 'д' - 3: 3, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 0, # 'к' - 10: 2, # 'л' - 14: 0, # 'м' - 6: 2, # 'н' - 4: 3, # 'о' - 13: 0, # 'п' - 7: 1, # 'р' - 8: 0, # 'с' - 5: 0, # 'т' - 19: 2, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 2, # 'ъ' - 52: 1, # 'ь' - 42: 2, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 36: { # 'Н' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 2, # 'А' - 32: 2, # 'Б' - 35: 1, # 'В' - 43: 1, # 'Г' - 37: 2, # 'Д' - 44: 2, # 'Е' - 55: 1, # 'Ж' - 47: 1, # 'З' - 40: 2, # 'И' - 59: 1, # 'Й' - 33: 2, # 'К' - 46: 1, # 'Л' - 38: 1, # 'М' - 36: 1, # 'Н' - 41: 2, # 'О' - 30: 1, # 'П' - 39: 1, # 'Р' - 28: 2, # 'С' - 34: 2, # 'Т' - 51: 1, # 'У' - 48: 1, # 'Ф' - 49: 1, # 'Х' - 53: 1, # 'Ц' - 50: 1, # 'Ч' - 54: 1, # 'Ш' - 57: 0, # 'Щ' - 61: 1, # 'Ъ' - 60: 1, # 'Ю' - 56: 1, # 'Я' - 1: 3, # 'а' - 18: 0, # 'б' - 9: 0, # 'в' - 20: 1, # 'г' - 11: 0, # 'д' - 3: 3, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 0, # 'к' - 10: 0, # 'л' - 14: 0, # 'м' - 6: 0, # 'н' - 4: 3, # 'о' - 13: 0, # 'п' - 7: 0, # 'р' - 8: 0, # 'с' - 5: 1, # 'т' - 19: 1, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 1, # 'ш' - 24: 0, # 'щ' - 17: 0, # 'ъ' - 52: 0, # 'ь' - 42: 2, # 'ю' - 16: 2, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 41: { # 'О' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 1, # 'А' - 32: 1, # 'Б' - 35: 2, # 'В' - 43: 1, # 'Г' - 37: 2, # 'Д' - 44: 1, # 'Е' - 55: 1, # 'Ж' - 47: 1, # 'З' - 40: 1, # 'И' - 59: 1, # 'Й' - 33: 2, # 'К' - 46: 2, # 'Л' - 38: 2, # 'М' - 36: 2, # 'Н' - 41: 2, # 'О' - 30: 1, # 'П' - 39: 2, # 'Р' - 28: 2, # 'С' - 34: 2, # 'Т' - 51: 1, # 'У' - 48: 1, # 'Ф' - 49: 1, # 'Х' - 53: 0, # 'Ц' - 50: 1, # 'Ч' - 54: 1, # 'Ш' - 57: 1, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 1, # 'Я' - 1: 1, # 'а' - 18: 2, # 'б' - 9: 2, # 'в' - 20: 2, # 'г' - 11: 1, # 'д' - 3: 1, # 'е' - 23: 1, # 'ж' - 15: 1, # 'з' - 2: 0, # 'и' - 26: 1, # 'й' - 12: 2, # 'к' - 10: 2, # 'л' - 14: 1, # 'м' - 6: 1, # 'н' - 4: 0, # 'о' - 13: 2, # 'п' - 7: 2, # 'р' - 8: 2, # 'с' - 5: 3, # 'т' - 19: 1, # 'у' - 29: 1, # 'ф' - 25: 1, # 'х' - 22: 1, # 'ц' - 21: 2, # 'ч' - 27: 0, # 'ш' - 24: 2, # 'щ' - 17: 0, # 'ъ' - 52: 0, # 'ь' - 42: 0, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 30: { # 'П' - 63: 0, # 'e' - 45: 1, # '\xad' - 31: 2, # 'А' - 32: 1, # 'Б' - 35: 1, # 'В' - 43: 1, # 'Г' - 37: 1, # 'Д' - 44: 1, # 'Е' - 55: 0, # 'Ж' - 47: 1, # 'З' - 40: 2, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 1, # 'Л' - 38: 1, # 'М' - 36: 1, # 'Н' - 41: 2, # 'О' - 30: 2, # 'П' - 39: 2, # 'Р' - 28: 2, # 'С' - 34: 1, # 'Т' - 51: 2, # 'У' - 48: 1, # 'Ф' - 49: 0, # 'Х' - 53: 1, # 'Ц' - 50: 1, # 'Ч' - 54: 1, # 'Ш' - 57: 0, # 'Щ' - 61: 1, # 'Ъ' - 60: 1, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 0, # 'б' - 9: 0, # 'в' - 20: 0, # 'г' - 11: 2, # 'д' - 3: 3, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 2, # 'и' - 26: 0, # 'й' - 12: 1, # 'к' - 10: 3, # 'л' - 14: 0, # 'м' - 6: 1, # 'н' - 4: 3, # 'о' - 13: 0, # 'п' - 7: 3, # 'р' - 8: 1, # 'с' - 5: 1, # 'т' - 19: 2, # 'у' - 29: 1, # 'ф' - 25: 1, # 'х' - 22: 0, # 'ц' - 21: 1, # 'ч' - 27: 1, # 'ш' - 24: 0, # 'щ' - 17: 2, # 'ъ' - 52: 1, # 'ь' - 42: 1, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 39: { # 'Р' - 63: 0, # 'e' - 45: 1, # '\xad' - 31: 2, # 'А' - 32: 1, # 'Б' - 35: 1, # 'В' - 43: 2, # 'Г' - 37: 2, # 'Д' - 44: 2, # 'Е' - 55: 0, # 'Ж' - 47: 1, # 'З' - 40: 2, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 0, # 'Л' - 38: 1, # 'М' - 36: 1, # 'Н' - 41: 2, # 'О' - 30: 2, # 'П' - 39: 1, # 'Р' - 28: 1, # 'С' - 34: 1, # 'Т' - 51: 1, # 'У' - 48: 1, # 'Ф' - 49: 1, # 'Х' - 53: 1, # 'Ц' - 50: 1, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 1, # 'Ъ' - 60: 1, # 'Ю' - 56: 1, # 'Я' - 1: 3, # 'а' - 18: 0, # 'б' - 9: 0, # 'в' - 20: 0, # 'г' - 11: 0, # 'д' - 3: 2, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 2, # 'и' - 26: 0, # 'й' - 12: 0, # 'к' - 10: 0, # 'л' - 14: 0, # 'м' - 6: 1, # 'н' - 4: 3, # 'о' - 13: 0, # 'п' - 7: 0, # 'р' - 8: 1, # 'с' - 5: 0, # 'т' - 19: 3, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 1, # 'ъ' - 52: 0, # 'ь' - 42: 1, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 28: { # 'С' - 63: 1, # 'e' - 45: 0, # '\xad' - 31: 3, # 'А' - 32: 2, # 'Б' - 35: 2, # 'В' - 43: 1, # 'Г' - 37: 2, # 'Д' - 44: 2, # 'Е' - 55: 1, # 'Ж' - 47: 1, # 'З' - 40: 2, # 'И' - 59: 0, # 'Й' - 33: 2, # 'К' - 46: 1, # 'Л' - 38: 1, # 'М' - 36: 1, # 'Н' - 41: 2, # 'О' - 30: 2, # 'П' - 39: 1, # 'Р' - 28: 2, # 'С' - 34: 2, # 'Т' - 51: 1, # 'У' - 48: 1, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 1, # 'Ъ' - 60: 1, # 'Ю' - 56: 1, # 'Я' - 1: 3, # 'а' - 18: 1, # 'б' - 9: 2, # 'в' - 20: 1, # 'г' - 11: 1, # 'д' - 3: 3, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 2, # 'к' - 10: 3, # 'л' - 14: 2, # 'м' - 6: 1, # 'н' - 4: 3, # 'о' - 13: 3, # 'п' - 7: 2, # 'р' - 8: 0, # 'с' - 5: 3, # 'т' - 19: 2, # 'у' - 29: 2, # 'ф' - 25: 1, # 'х' - 22: 1, # 'ц' - 21: 1, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 3, # 'ъ' - 52: 1, # 'ь' - 42: 1, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 34: { # 'Т' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 2, # 'А' - 32: 2, # 'Б' - 35: 1, # 'В' - 43: 0, # 'Г' - 37: 1, # 'Д' - 44: 2, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 2, # 'И' - 59: 0, # 'Й' - 33: 2, # 'К' - 46: 1, # 'Л' - 38: 1, # 'М' - 36: 1, # 'Н' - 41: 2, # 'О' - 30: 1, # 'П' - 39: 2, # 'Р' - 28: 2, # 'С' - 34: 1, # 'Т' - 51: 1, # 'У' - 48: 1, # 'Ф' - 49: 0, # 'Х' - 53: 1, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 1, # 'Ъ' - 60: 0, # 'Ю' - 56: 1, # 'Я' - 1: 3, # 'а' - 18: 1, # 'б' - 9: 1, # 'в' - 20: 0, # 'г' - 11: 0, # 'д' - 3: 3, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 2, # 'и' - 26: 0, # 'й' - 12: 1, # 'к' - 10: 1, # 'л' - 14: 0, # 'м' - 6: 0, # 'н' - 4: 3, # 'о' - 13: 0, # 'п' - 7: 3, # 'р' - 8: 0, # 'с' - 5: 0, # 'т' - 19: 2, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 2, # 'ъ' - 52: 0, # 'ь' - 42: 1, # 'ю' - 16: 2, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 51: { # 'У' - 63: 0, # 'e' - 45: 1, # '\xad' - 31: 1, # 'А' - 32: 1, # 'Б' - 35: 1, # 'В' - 43: 1, # 'Г' - 37: 1, # 'Д' - 44: 2, # 'Е' - 55: 1, # 'Ж' - 47: 1, # 'З' - 40: 1, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 1, # 'Л' - 38: 1, # 'М' - 36: 1, # 'Н' - 41: 0, # 'О' - 30: 1, # 'П' - 39: 1, # 'Р' - 28: 1, # 'С' - 34: 2, # 'Т' - 51: 0, # 'У' - 48: 1, # 'Ф' - 49: 1, # 'Х' - 53: 1, # 'Ц' - 50: 1, # 'Ч' - 54: 1, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 1, # 'а' - 18: 1, # 'б' - 9: 2, # 'в' - 20: 1, # 'г' - 11: 1, # 'д' - 3: 2, # 'е' - 23: 1, # 'ж' - 15: 1, # 'з' - 2: 2, # 'и' - 26: 1, # 'й' - 12: 2, # 'к' - 10: 1, # 'л' - 14: 1, # 'м' - 6: 2, # 'н' - 4: 2, # 'о' - 13: 1, # 'п' - 7: 1, # 'р' - 8: 2, # 'с' - 5: 1, # 'т' - 19: 1, # 'у' - 29: 0, # 'ф' - 25: 1, # 'х' - 22: 0, # 'ц' - 21: 2, # 'ч' - 27: 1, # 'ш' - 24: 0, # 'щ' - 17: 1, # 'ъ' - 52: 0, # 'ь' - 42: 0, # 'ю' - 16: 0, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 48: { # 'Ф' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 2, # 'А' - 32: 1, # 'Б' - 35: 1, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 1, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 2, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 1, # 'Л' - 38: 0, # 'М' - 36: 1, # 'Н' - 41: 1, # 'О' - 30: 2, # 'П' - 39: 1, # 'Р' - 28: 2, # 'С' - 34: 1, # 'Т' - 51: 1, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 2, # 'а' - 18: 0, # 'б' - 9: 0, # 'в' - 20: 0, # 'г' - 11: 0, # 'д' - 3: 2, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 2, # 'и' - 26: 0, # 'й' - 12: 0, # 'к' - 10: 2, # 'л' - 14: 0, # 'м' - 6: 0, # 'н' - 4: 2, # 'о' - 13: 0, # 'п' - 7: 2, # 'р' - 8: 0, # 'с' - 5: 0, # 'т' - 19: 1, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 1, # 'ъ' - 52: 1, # 'ь' - 42: 1, # 'ю' - 16: 0, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 49: { # 'Х' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 1, # 'А' - 32: 0, # 'Б' - 35: 1, # 'В' - 43: 1, # 'Г' - 37: 1, # 'Д' - 44: 1, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 1, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 1, # 'Л' - 38: 1, # 'М' - 36: 1, # 'Н' - 41: 1, # 'О' - 30: 1, # 'П' - 39: 1, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 1, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 2, # 'а' - 18: 0, # 'б' - 9: 1, # 'в' - 20: 0, # 'г' - 11: 0, # 'д' - 3: 2, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 2, # 'и' - 26: 0, # 'й' - 12: 0, # 'к' - 10: 1, # 'л' - 14: 1, # 'м' - 6: 0, # 'н' - 4: 2, # 'о' - 13: 0, # 'п' - 7: 2, # 'р' - 8: 0, # 'с' - 5: 0, # 'т' - 19: 2, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 2, # 'ъ' - 52: 1, # 'ь' - 42: 1, # 'ю' - 16: 0, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 53: { # 'Ц' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 1, # 'А' - 32: 0, # 'Б' - 35: 1, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 1, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 2, # 'И' - 59: 0, # 'Й' - 33: 2, # 'К' - 46: 1, # 'Л' - 38: 1, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 1, # 'Р' - 28: 2, # 'С' - 34: 0, # 'Т' - 51: 1, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 2, # 'а' - 18: 0, # 'б' - 9: 2, # 'в' - 20: 0, # 'г' - 11: 0, # 'д' - 3: 2, # 'е' - 23: 0, # 'ж' - 15: 1, # 'з' - 2: 2, # 'и' - 26: 0, # 'й' - 12: 0, # 'к' - 10: 0, # 'л' - 14: 0, # 'м' - 6: 0, # 'н' - 4: 1, # 'о' - 13: 0, # 'п' - 7: 1, # 'р' - 8: 0, # 'с' - 5: 0, # 'т' - 19: 1, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 1, # 'ъ' - 52: 0, # 'ь' - 42: 1, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 50: { # 'Ч' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 2, # 'А' - 32: 1, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 1, # 'Е' - 55: 0, # 'Ж' - 47: 1, # 'З' - 40: 1, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 1, # 'Л' - 38: 0, # 'М' - 36: 1, # 'Н' - 41: 1, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 1, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 2, # 'а' - 18: 0, # 'б' - 9: 0, # 'в' - 20: 0, # 'г' - 11: 0, # 'д' - 3: 3, # 'е' - 23: 1, # 'ж' - 15: 0, # 'з' - 2: 2, # 'и' - 26: 0, # 'й' - 12: 0, # 'к' - 10: 1, # 'л' - 14: 0, # 'м' - 6: 0, # 'н' - 4: 2, # 'о' - 13: 0, # 'п' - 7: 1, # 'р' - 8: 0, # 'с' - 5: 0, # 'т' - 19: 2, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 1, # 'ъ' - 52: 1, # 'ь' - 42: 0, # 'ю' - 16: 0, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 54: { # 'Ш' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 1, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 1, # 'Е' - 55: 0, # 'Ж' - 47: 1, # 'З' - 40: 1, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 1, # 'Н' - 41: 1, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 1, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 2, # 'а' - 18: 0, # 'б' - 9: 2, # 'в' - 20: 0, # 'г' - 11: 0, # 'д' - 3: 2, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 2, # 'и' - 26: 0, # 'й' - 12: 1, # 'к' - 10: 1, # 'л' - 14: 1, # 'м' - 6: 1, # 'н' - 4: 2, # 'о' - 13: 1, # 'п' - 7: 1, # 'р' - 8: 0, # 'с' - 5: 0, # 'т' - 19: 2, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 1, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 1, # 'ъ' - 52: 1, # 'ь' - 42: 0, # 'ю' - 16: 0, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 57: { # 'Щ' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 1, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 1, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 1, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 1, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 2, # 'а' - 18: 0, # 'б' - 9: 0, # 'в' - 20: 0, # 'г' - 11: 0, # 'д' - 3: 2, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 1, # 'и' - 26: 0, # 'й' - 12: 0, # 'к' - 10: 0, # 'л' - 14: 0, # 'м' - 6: 0, # 'н' - 4: 1, # 'о' - 13: 0, # 'п' - 7: 1, # 'р' - 8: 0, # 'с' - 5: 0, # 'т' - 19: 1, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 1, # 'ъ' - 52: 0, # 'ь' - 42: 0, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 61: { # 'Ъ' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 1, # 'Б' - 35: 1, # 'В' - 43: 0, # 'Г' - 37: 1, # 'Д' - 44: 0, # 'Е' - 55: 1, # 'Ж' - 47: 1, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 2, # 'Л' - 38: 1, # 'М' - 36: 1, # 'Н' - 41: 0, # 'О' - 30: 1, # 'П' - 39: 2, # 'Р' - 28: 1, # 'С' - 34: 1, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 1, # 'Х' - 53: 1, # 'Ц' - 50: 1, # 'Ч' - 54: 1, # 'Ш' - 57: 1, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 0, # 'а' - 18: 0, # 'б' - 9: 0, # 'в' - 20: 0, # 'г' - 11: 0, # 'д' - 3: 0, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 0, # 'и' - 26: 0, # 'й' - 12: 0, # 'к' - 10: 1, # 'л' - 14: 0, # 'м' - 6: 1, # 'н' - 4: 0, # 'о' - 13: 0, # 'п' - 7: 1, # 'р' - 8: 0, # 'с' - 5: 0, # 'т' - 19: 0, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 0, # 'ъ' - 52: 0, # 'ь' - 42: 0, # 'ю' - 16: 0, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 60: { # 'Ю' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 1, # 'А' - 32: 1, # 'Б' - 35: 0, # 'В' - 43: 1, # 'Г' - 37: 1, # 'Д' - 44: 0, # 'Е' - 55: 1, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 1, # 'Л' - 38: 0, # 'М' - 36: 1, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 1, # 'Р' - 28: 1, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 0, # 'а' - 18: 1, # 'б' - 9: 1, # 'в' - 20: 2, # 'г' - 11: 1, # 'д' - 3: 0, # 'е' - 23: 2, # 'ж' - 15: 1, # 'з' - 2: 1, # 'и' - 26: 0, # 'й' - 12: 1, # 'к' - 10: 1, # 'л' - 14: 1, # 'м' - 6: 1, # 'н' - 4: 0, # 'о' - 13: 1, # 'п' - 7: 1, # 'р' - 8: 1, # 'с' - 5: 1, # 'т' - 19: 0, # 'у' - 29: 0, # 'ф' - 25: 1, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 0, # 'ъ' - 52: 0, # 'ь' - 42: 0, # 'ю' - 16: 0, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 56: { # 'Я' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 1, # 'Б' - 35: 1, # 'В' - 43: 1, # 'Г' - 37: 1, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 1, # 'Л' - 38: 1, # 'М' - 36: 1, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 1, # 'С' - 34: 2, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 0, # 'а' - 18: 1, # 'б' - 9: 1, # 'в' - 20: 1, # 'г' - 11: 1, # 'д' - 3: 0, # 'е' - 23: 0, # 'ж' - 15: 1, # 'з' - 2: 1, # 'и' - 26: 1, # 'й' - 12: 1, # 'к' - 10: 1, # 'л' - 14: 2, # 'м' - 6: 2, # 'н' - 4: 0, # 'о' - 13: 2, # 'п' - 7: 1, # 'р' - 8: 1, # 'с' - 5: 1, # 'т' - 19: 0, # 'у' - 29: 0, # 'ф' - 25: 1, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 1, # 'ш' - 24: 0, # 'щ' - 17: 0, # 'ъ' - 52: 0, # 'ь' - 42: 1, # 'ю' - 16: 0, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 1: { # 'а' - 63: 1, # 'e' - 45: 1, # '\xad' - 31: 1, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 1, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 1, # 'а' - 18: 3, # 'б' - 9: 3, # 'в' - 20: 3, # 'г' - 11: 3, # 'д' - 3: 3, # 'е' - 23: 3, # 'ж' - 15: 3, # 'з' - 2: 3, # 'и' - 26: 3, # 'й' - 12: 3, # 'к' - 10: 3, # 'л' - 14: 3, # 'м' - 6: 3, # 'н' - 4: 2, # 'о' - 13: 3, # 'п' - 7: 3, # 'р' - 8: 3, # 'с' - 5: 3, # 'т' - 19: 3, # 'у' - 29: 3, # 'ф' - 25: 3, # 'х' - 22: 3, # 'ц' - 21: 3, # 'ч' - 27: 3, # 'ш' - 24: 3, # 'щ' - 17: 0, # 'ъ' - 52: 0, # 'ь' - 42: 1, # 'ю' - 16: 3, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 18: { # 'б' - 63: 1, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 0, # 'б' - 9: 3, # 'в' - 20: 1, # 'г' - 11: 2, # 'д' - 3: 3, # 'е' - 23: 1, # 'ж' - 15: 1, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 1, # 'к' - 10: 3, # 'л' - 14: 2, # 'м' - 6: 3, # 'н' - 4: 3, # 'о' - 13: 1, # 'п' - 7: 3, # 'р' - 8: 3, # 'с' - 5: 0, # 'т' - 19: 3, # 'у' - 29: 0, # 'ф' - 25: 2, # 'х' - 22: 1, # 'ц' - 21: 1, # 'ч' - 27: 1, # 'ш' - 24: 3, # 'щ' - 17: 3, # 'ъ' - 52: 1, # 'ь' - 42: 2, # 'ю' - 16: 3, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 9: { # 'в' - 63: 1, # 'e' - 45: 1, # '\xad' - 31: 0, # 'А' - 32: 1, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 1, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 1, # 'б' - 9: 0, # 'в' - 20: 2, # 'г' - 11: 3, # 'д' - 3: 3, # 'е' - 23: 1, # 'ж' - 15: 3, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 3, # 'к' - 10: 3, # 'л' - 14: 2, # 'м' - 6: 3, # 'н' - 4: 3, # 'о' - 13: 2, # 'п' - 7: 3, # 'р' - 8: 3, # 'с' - 5: 3, # 'т' - 19: 2, # 'у' - 29: 0, # 'ф' - 25: 2, # 'х' - 22: 2, # 'ц' - 21: 3, # 'ч' - 27: 2, # 'ш' - 24: 1, # 'щ' - 17: 3, # 'ъ' - 52: 1, # 'ь' - 42: 2, # 'ю' - 16: 3, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 20: { # 'г' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 1, # 'б' - 9: 2, # 'в' - 20: 1, # 'г' - 11: 2, # 'д' - 3: 3, # 'е' - 23: 0, # 'ж' - 15: 1, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 1, # 'к' - 10: 3, # 'л' - 14: 1, # 'м' - 6: 3, # 'н' - 4: 3, # 'о' - 13: 1, # 'п' - 7: 3, # 'р' - 8: 2, # 'с' - 5: 2, # 'т' - 19: 3, # 'у' - 29: 1, # 'ф' - 25: 1, # 'х' - 22: 0, # 'ц' - 21: 1, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 3, # 'ъ' - 52: 1, # 'ь' - 42: 1, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 11: { # 'д' - 63: 1, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 2, # 'б' - 9: 3, # 'в' - 20: 2, # 'г' - 11: 2, # 'д' - 3: 3, # 'е' - 23: 3, # 'ж' - 15: 2, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 3, # 'к' - 10: 3, # 'л' - 14: 3, # 'м' - 6: 3, # 'н' - 4: 3, # 'о' - 13: 3, # 'п' - 7: 3, # 'р' - 8: 3, # 'с' - 5: 1, # 'т' - 19: 3, # 'у' - 29: 1, # 'ф' - 25: 2, # 'х' - 22: 2, # 'ц' - 21: 2, # 'ч' - 27: 1, # 'ш' - 24: 1, # 'щ' - 17: 3, # 'ъ' - 52: 1, # 'ь' - 42: 1, # 'ю' - 16: 3, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 3: { # 'е' - 63: 0, # 'e' - 45: 1, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 2, # 'а' - 18: 3, # 'б' - 9: 3, # 'в' - 20: 3, # 'г' - 11: 3, # 'д' - 3: 2, # 'е' - 23: 3, # 'ж' - 15: 3, # 'з' - 2: 2, # 'и' - 26: 3, # 'й' - 12: 3, # 'к' - 10: 3, # 'л' - 14: 3, # 'м' - 6: 3, # 'н' - 4: 3, # 'о' - 13: 3, # 'п' - 7: 3, # 'р' - 8: 3, # 'с' - 5: 3, # 'т' - 19: 2, # 'у' - 29: 3, # 'ф' - 25: 3, # 'х' - 22: 3, # 'ц' - 21: 3, # 'ч' - 27: 3, # 'ш' - 24: 3, # 'щ' - 17: 1, # 'ъ' - 52: 0, # 'ь' - 42: 1, # 'ю' - 16: 3, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 23: { # 'ж' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 3, # 'б' - 9: 2, # 'в' - 20: 1, # 'г' - 11: 3, # 'д' - 3: 3, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 2, # 'к' - 10: 1, # 'л' - 14: 1, # 'м' - 6: 3, # 'н' - 4: 2, # 'о' - 13: 1, # 'п' - 7: 1, # 'р' - 8: 1, # 'с' - 5: 1, # 'т' - 19: 2, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 1, # 'ц' - 21: 1, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 2, # 'ъ' - 52: 0, # 'ь' - 42: 0, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 15: { # 'з' - 63: 1, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 3, # 'б' - 9: 3, # 'в' - 20: 3, # 'г' - 11: 3, # 'д' - 3: 3, # 'е' - 23: 1, # 'ж' - 15: 1, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 3, # 'к' - 10: 3, # 'л' - 14: 3, # 'м' - 6: 3, # 'н' - 4: 3, # 'о' - 13: 3, # 'п' - 7: 3, # 'р' - 8: 3, # 'с' - 5: 3, # 'т' - 19: 3, # 'у' - 29: 1, # 'ф' - 25: 2, # 'х' - 22: 2, # 'ц' - 21: 2, # 'ч' - 27: 2, # 'ш' - 24: 1, # 'щ' - 17: 2, # 'ъ' - 52: 1, # 'ь' - 42: 1, # 'ю' - 16: 2, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 2: { # 'и' - 63: 1, # 'e' - 45: 1, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 1, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 1, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 1, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 1, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 3, # 'б' - 9: 3, # 'в' - 20: 3, # 'г' - 11: 3, # 'д' - 3: 3, # 'е' - 23: 3, # 'ж' - 15: 3, # 'з' - 2: 3, # 'и' - 26: 3, # 'й' - 12: 3, # 'к' - 10: 3, # 'л' - 14: 3, # 'м' - 6: 3, # 'н' - 4: 3, # 'о' - 13: 3, # 'п' - 7: 3, # 'р' - 8: 3, # 'с' - 5: 3, # 'т' - 19: 2, # 'у' - 29: 3, # 'ф' - 25: 3, # 'х' - 22: 3, # 'ц' - 21: 3, # 'ч' - 27: 3, # 'ш' - 24: 3, # 'щ' - 17: 2, # 'ъ' - 52: 0, # 'ь' - 42: 1, # 'ю' - 16: 3, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 26: { # 'й' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 1, # 'а' - 18: 2, # 'б' - 9: 2, # 'в' - 20: 1, # 'г' - 11: 2, # 'д' - 3: 2, # 'е' - 23: 0, # 'ж' - 15: 2, # 'з' - 2: 1, # 'и' - 26: 0, # 'й' - 12: 3, # 'к' - 10: 2, # 'л' - 14: 2, # 'м' - 6: 3, # 'н' - 4: 2, # 'о' - 13: 1, # 'п' - 7: 2, # 'р' - 8: 3, # 'с' - 5: 3, # 'т' - 19: 1, # 'у' - 29: 2, # 'ф' - 25: 1, # 'х' - 22: 2, # 'ц' - 21: 2, # 'ч' - 27: 1, # 'ш' - 24: 1, # 'щ' - 17: 1, # 'ъ' - 52: 0, # 'ь' - 42: 0, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 12: { # 'к' - 63: 1, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 1, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 1, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 1, # 'б' - 9: 3, # 'в' - 20: 2, # 'г' - 11: 1, # 'д' - 3: 3, # 'е' - 23: 0, # 'ж' - 15: 2, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 1, # 'к' - 10: 3, # 'л' - 14: 2, # 'м' - 6: 3, # 'н' - 4: 3, # 'о' - 13: 1, # 'п' - 7: 3, # 'р' - 8: 3, # 'с' - 5: 3, # 'т' - 19: 3, # 'у' - 29: 1, # 'ф' - 25: 1, # 'х' - 22: 3, # 'ц' - 21: 2, # 'ч' - 27: 1, # 'ш' - 24: 0, # 'щ' - 17: 3, # 'ъ' - 52: 1, # 'ь' - 42: 2, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 10: { # 'л' - 63: 1, # 'e' - 45: 1, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 1, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 3, # 'б' - 9: 3, # 'в' - 20: 3, # 'г' - 11: 2, # 'д' - 3: 3, # 'е' - 23: 3, # 'ж' - 15: 2, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 3, # 'к' - 10: 1, # 'л' - 14: 2, # 'м' - 6: 3, # 'н' - 4: 3, # 'о' - 13: 2, # 'п' - 7: 2, # 'р' - 8: 3, # 'с' - 5: 3, # 'т' - 19: 3, # 'у' - 29: 2, # 'ф' - 25: 2, # 'х' - 22: 2, # 'ц' - 21: 2, # 'ч' - 27: 2, # 'ш' - 24: 1, # 'щ' - 17: 3, # 'ъ' - 52: 2, # 'ь' - 42: 3, # 'ю' - 16: 3, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 14: { # 'м' - 63: 1, # 'e' - 45: 0, # '\xad' - 31: 1, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 3, # 'б' - 9: 3, # 'в' - 20: 1, # 'г' - 11: 1, # 'д' - 3: 3, # 'е' - 23: 1, # 'ж' - 15: 1, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 2, # 'к' - 10: 3, # 'л' - 14: 1, # 'м' - 6: 3, # 'н' - 4: 3, # 'о' - 13: 3, # 'п' - 7: 2, # 'р' - 8: 2, # 'с' - 5: 1, # 'т' - 19: 3, # 'у' - 29: 2, # 'ф' - 25: 1, # 'х' - 22: 2, # 'ц' - 21: 2, # 'ч' - 27: 2, # 'ш' - 24: 1, # 'щ' - 17: 3, # 'ъ' - 52: 1, # 'ь' - 42: 2, # 'ю' - 16: 3, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 6: { # 'н' - 63: 1, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 1, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 2, # 'б' - 9: 2, # 'в' - 20: 3, # 'г' - 11: 3, # 'д' - 3: 3, # 'е' - 23: 2, # 'ж' - 15: 2, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 3, # 'к' - 10: 2, # 'л' - 14: 1, # 'м' - 6: 3, # 'н' - 4: 3, # 'о' - 13: 1, # 'п' - 7: 2, # 'р' - 8: 3, # 'с' - 5: 3, # 'т' - 19: 3, # 'у' - 29: 3, # 'ф' - 25: 2, # 'х' - 22: 3, # 'ц' - 21: 3, # 'ч' - 27: 2, # 'ш' - 24: 1, # 'щ' - 17: 3, # 'ъ' - 52: 2, # 'ь' - 42: 2, # 'ю' - 16: 3, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 4: { # 'о' - 63: 0, # 'e' - 45: 1, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 2, # 'а' - 18: 3, # 'б' - 9: 3, # 'в' - 20: 3, # 'г' - 11: 3, # 'д' - 3: 3, # 'е' - 23: 3, # 'ж' - 15: 3, # 'з' - 2: 3, # 'и' - 26: 3, # 'й' - 12: 3, # 'к' - 10: 3, # 'л' - 14: 3, # 'м' - 6: 3, # 'н' - 4: 2, # 'о' - 13: 3, # 'п' - 7: 3, # 'р' - 8: 3, # 'с' - 5: 3, # 'т' - 19: 2, # 'у' - 29: 3, # 'ф' - 25: 3, # 'х' - 22: 3, # 'ц' - 21: 3, # 'ч' - 27: 3, # 'ш' - 24: 3, # 'щ' - 17: 1, # 'ъ' - 52: 0, # 'ь' - 42: 1, # 'ю' - 16: 3, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 13: { # 'п' - 63: 1, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 1, # 'б' - 9: 2, # 'в' - 20: 1, # 'г' - 11: 1, # 'д' - 3: 3, # 'е' - 23: 0, # 'ж' - 15: 1, # 'з' - 2: 3, # 'и' - 26: 1, # 'й' - 12: 2, # 'к' - 10: 3, # 'л' - 14: 1, # 'м' - 6: 2, # 'н' - 4: 3, # 'о' - 13: 1, # 'п' - 7: 3, # 'р' - 8: 2, # 'с' - 5: 2, # 'т' - 19: 3, # 'у' - 29: 1, # 'ф' - 25: 1, # 'х' - 22: 2, # 'ц' - 21: 2, # 'ч' - 27: 1, # 'ш' - 24: 1, # 'щ' - 17: 3, # 'ъ' - 52: 1, # 'ь' - 42: 2, # 'ю' - 16: 2, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 7: { # 'р' - 63: 1, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 3, # 'б' - 9: 3, # 'в' - 20: 3, # 'г' - 11: 3, # 'д' - 3: 3, # 'е' - 23: 3, # 'ж' - 15: 2, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 3, # 'к' - 10: 3, # 'л' - 14: 3, # 'м' - 6: 3, # 'н' - 4: 3, # 'о' - 13: 2, # 'п' - 7: 1, # 'р' - 8: 3, # 'с' - 5: 3, # 'т' - 19: 3, # 'у' - 29: 2, # 'ф' - 25: 3, # 'х' - 22: 3, # 'ц' - 21: 2, # 'ч' - 27: 3, # 'ш' - 24: 1, # 'щ' - 17: 3, # 'ъ' - 52: 1, # 'ь' - 42: 2, # 'ю' - 16: 3, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 8: { # 'с' - 63: 1, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 2, # 'б' - 9: 3, # 'в' - 20: 2, # 'г' - 11: 2, # 'д' - 3: 3, # 'е' - 23: 0, # 'ж' - 15: 1, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 3, # 'к' - 10: 3, # 'л' - 14: 3, # 'м' - 6: 3, # 'н' - 4: 3, # 'о' - 13: 3, # 'п' - 7: 3, # 'р' - 8: 1, # 'с' - 5: 3, # 'т' - 19: 3, # 'у' - 29: 2, # 'ф' - 25: 2, # 'х' - 22: 2, # 'ц' - 21: 2, # 'ч' - 27: 2, # 'ш' - 24: 0, # 'щ' - 17: 3, # 'ъ' - 52: 2, # 'ь' - 42: 2, # 'ю' - 16: 3, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 5: { # 'т' - 63: 1, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 3, # 'б' - 9: 3, # 'в' - 20: 2, # 'г' - 11: 2, # 'д' - 3: 3, # 'е' - 23: 1, # 'ж' - 15: 1, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 3, # 'к' - 10: 3, # 'л' - 14: 2, # 'м' - 6: 3, # 'н' - 4: 3, # 'о' - 13: 2, # 'п' - 7: 3, # 'р' - 8: 3, # 'с' - 5: 3, # 'т' - 19: 3, # 'у' - 29: 1, # 'ф' - 25: 2, # 'х' - 22: 2, # 'ц' - 21: 2, # 'ч' - 27: 1, # 'ш' - 24: 1, # 'щ' - 17: 3, # 'ъ' - 52: 2, # 'ь' - 42: 2, # 'ю' - 16: 3, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 19: { # 'у' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 3, # 'б' - 9: 3, # 'в' - 20: 3, # 'г' - 11: 3, # 'д' - 3: 2, # 'е' - 23: 3, # 'ж' - 15: 3, # 'з' - 2: 2, # 'и' - 26: 2, # 'й' - 12: 3, # 'к' - 10: 3, # 'л' - 14: 3, # 'м' - 6: 3, # 'н' - 4: 2, # 'о' - 13: 3, # 'п' - 7: 3, # 'р' - 8: 3, # 'с' - 5: 3, # 'т' - 19: 1, # 'у' - 29: 2, # 'ф' - 25: 2, # 'х' - 22: 2, # 'ц' - 21: 3, # 'ч' - 27: 3, # 'ш' - 24: 2, # 'щ' - 17: 1, # 'ъ' - 52: 0, # 'ь' - 42: 1, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 29: { # 'ф' - 63: 1, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 1, # 'б' - 9: 1, # 'в' - 20: 1, # 'г' - 11: 0, # 'д' - 3: 3, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 2, # 'к' - 10: 2, # 'л' - 14: 1, # 'м' - 6: 1, # 'н' - 4: 3, # 'о' - 13: 0, # 'п' - 7: 2, # 'р' - 8: 2, # 'с' - 5: 2, # 'т' - 19: 2, # 'у' - 29: 0, # 'ф' - 25: 1, # 'х' - 22: 0, # 'ц' - 21: 1, # 'ч' - 27: 1, # 'ш' - 24: 0, # 'щ' - 17: 2, # 'ъ' - 52: 2, # 'ь' - 42: 1, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 25: { # 'х' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 1, # 'б' - 9: 3, # 'в' - 20: 0, # 'г' - 11: 1, # 'д' - 3: 2, # 'е' - 23: 0, # 'ж' - 15: 1, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 1, # 'к' - 10: 2, # 'л' - 14: 2, # 'м' - 6: 3, # 'н' - 4: 3, # 'о' - 13: 1, # 'п' - 7: 3, # 'р' - 8: 1, # 'с' - 5: 2, # 'т' - 19: 3, # 'у' - 29: 0, # 'ф' - 25: 1, # 'х' - 22: 0, # 'ц' - 21: 1, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 2, # 'ъ' - 52: 0, # 'ь' - 42: 1, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 22: { # 'ц' - 63: 1, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 1, # 'б' - 9: 2, # 'в' - 20: 1, # 'г' - 11: 1, # 'д' - 3: 3, # 'е' - 23: 0, # 'ж' - 15: 1, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 2, # 'к' - 10: 1, # 'л' - 14: 1, # 'м' - 6: 1, # 'н' - 4: 2, # 'о' - 13: 1, # 'п' - 7: 1, # 'р' - 8: 1, # 'с' - 5: 1, # 'т' - 19: 2, # 'у' - 29: 1, # 'ф' - 25: 1, # 'х' - 22: 1, # 'ц' - 21: 1, # 'ч' - 27: 1, # 'ш' - 24: 1, # 'щ' - 17: 2, # 'ъ' - 52: 1, # 'ь' - 42: 0, # 'ю' - 16: 2, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 21: { # 'ч' - 63: 1, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 1, # 'б' - 9: 3, # 'в' - 20: 1, # 'г' - 11: 0, # 'д' - 3: 3, # 'е' - 23: 1, # 'ж' - 15: 0, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 3, # 'к' - 10: 2, # 'л' - 14: 2, # 'м' - 6: 3, # 'н' - 4: 3, # 'о' - 13: 0, # 'п' - 7: 2, # 'р' - 8: 0, # 'с' - 5: 2, # 'т' - 19: 3, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 1, # 'ш' - 24: 0, # 'щ' - 17: 2, # 'ъ' - 52: 0, # 'ь' - 42: 1, # 'ю' - 16: 0, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 27: { # 'ш' - 63: 1, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 0, # 'б' - 9: 2, # 'в' - 20: 0, # 'г' - 11: 1, # 'д' - 3: 3, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 3, # 'к' - 10: 2, # 'л' - 14: 1, # 'м' - 6: 3, # 'н' - 4: 2, # 'о' - 13: 2, # 'п' - 7: 1, # 'р' - 8: 0, # 'с' - 5: 1, # 'т' - 19: 2, # 'у' - 29: 1, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 1, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 2, # 'ъ' - 52: 1, # 'ь' - 42: 1, # 'ю' - 16: 0, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 24: { # 'щ' - 63: 1, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 3, # 'а' - 18: 0, # 'б' - 9: 1, # 'в' - 20: 0, # 'г' - 11: 0, # 'д' - 3: 3, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 3, # 'и' - 26: 0, # 'й' - 12: 1, # 'к' - 10: 0, # 'л' - 14: 0, # 'м' - 6: 2, # 'н' - 4: 3, # 'о' - 13: 0, # 'п' - 7: 1, # 'р' - 8: 0, # 'с' - 5: 2, # 'т' - 19: 3, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 1, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 1, # 'ъ' - 52: 0, # 'ь' - 42: 0, # 'ю' - 16: 2, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 17: { # 'ъ' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 1, # 'а' - 18: 3, # 'б' - 9: 3, # 'в' - 20: 3, # 'г' - 11: 3, # 'д' - 3: 2, # 'е' - 23: 3, # 'ж' - 15: 3, # 'з' - 2: 1, # 'и' - 26: 2, # 'й' - 12: 3, # 'к' - 10: 3, # 'л' - 14: 3, # 'м' - 6: 3, # 'н' - 4: 3, # 'о' - 13: 3, # 'п' - 7: 3, # 'р' - 8: 3, # 'с' - 5: 3, # 'т' - 19: 1, # 'у' - 29: 1, # 'ф' - 25: 2, # 'х' - 22: 2, # 'ц' - 21: 3, # 'ч' - 27: 2, # 'ш' - 24: 3, # 'щ' - 17: 0, # 'ъ' - 52: 0, # 'ь' - 42: 2, # 'ю' - 16: 0, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 52: { # 'ь' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 0, # 'а' - 18: 0, # 'б' - 9: 0, # 'в' - 20: 0, # 'г' - 11: 0, # 'д' - 3: 1, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 0, # 'и' - 26: 0, # 'й' - 12: 1, # 'к' - 10: 0, # 'л' - 14: 0, # 'м' - 6: 1, # 'н' - 4: 3, # 'о' - 13: 0, # 'п' - 7: 0, # 'р' - 8: 0, # 'с' - 5: 1, # 'т' - 19: 0, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 1, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 0, # 'ъ' - 52: 0, # 'ь' - 42: 1, # 'ю' - 16: 0, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 42: { # 'ю' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 1, # 'а' - 18: 2, # 'б' - 9: 1, # 'в' - 20: 2, # 'г' - 11: 2, # 'д' - 3: 1, # 'е' - 23: 2, # 'ж' - 15: 2, # 'з' - 2: 1, # 'и' - 26: 1, # 'й' - 12: 2, # 'к' - 10: 2, # 'л' - 14: 2, # 'м' - 6: 2, # 'н' - 4: 1, # 'о' - 13: 1, # 'п' - 7: 2, # 'р' - 8: 2, # 'с' - 5: 2, # 'т' - 19: 1, # 'у' - 29: 1, # 'ф' - 25: 1, # 'х' - 22: 2, # 'ц' - 21: 3, # 'ч' - 27: 1, # 'ш' - 24: 1, # 'щ' - 17: 1, # 'ъ' - 52: 0, # 'ь' - 42: 0, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 16: { # 'я' - 63: 0, # 'e' - 45: 1, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 0, # 'а' - 18: 3, # 'б' - 9: 3, # 'в' - 20: 2, # 'г' - 11: 3, # 'д' - 3: 2, # 'е' - 23: 1, # 'ж' - 15: 2, # 'з' - 2: 1, # 'и' - 26: 2, # 'й' - 12: 3, # 'к' - 10: 3, # 'л' - 14: 3, # 'м' - 6: 3, # 'н' - 4: 1, # 'о' - 13: 2, # 'п' - 7: 2, # 'р' - 8: 3, # 'с' - 5: 3, # 'т' - 19: 1, # 'у' - 29: 1, # 'ф' - 25: 3, # 'х' - 22: 2, # 'ц' - 21: 1, # 'ч' - 27: 1, # 'ш' - 24: 2, # 'щ' - 17: 0, # 'ъ' - 52: 0, # 'ь' - 42: 0, # 'ю' - 16: 1, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 58: { # 'є' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 0, # 'а' - 18: 0, # 'б' - 9: 0, # 'в' - 20: 0, # 'г' - 11: 0, # 'д' - 3: 0, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 0, # 'и' - 26: 0, # 'й' - 12: 0, # 'к' - 10: 0, # 'л' - 14: 0, # 'м' - 6: 0, # 'н' - 4: 0, # 'о' - 13: 0, # 'п' - 7: 0, # 'р' - 8: 0, # 'с' - 5: 0, # 'т' - 19: 0, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 0, # 'ъ' - 52: 0, # 'ь' - 42: 0, # 'ю' - 16: 0, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, - 62: { # '№' - 63: 0, # 'e' - 45: 0, # '\xad' - 31: 0, # 'А' - 32: 0, # 'Б' - 35: 0, # 'В' - 43: 0, # 'Г' - 37: 0, # 'Д' - 44: 0, # 'Е' - 55: 0, # 'Ж' - 47: 0, # 'З' - 40: 0, # 'И' - 59: 0, # 'Й' - 33: 0, # 'К' - 46: 0, # 'Л' - 38: 0, # 'М' - 36: 0, # 'Н' - 41: 0, # 'О' - 30: 0, # 'П' - 39: 0, # 'Р' - 28: 0, # 'С' - 34: 0, # 'Т' - 51: 0, # 'У' - 48: 0, # 'Ф' - 49: 0, # 'Х' - 53: 0, # 'Ц' - 50: 0, # 'Ч' - 54: 0, # 'Ш' - 57: 0, # 'Щ' - 61: 0, # 'Ъ' - 60: 0, # 'Ю' - 56: 0, # 'Я' - 1: 0, # 'а' - 18: 0, # 'б' - 9: 0, # 'в' - 20: 0, # 'г' - 11: 0, # 'д' - 3: 0, # 'е' - 23: 0, # 'ж' - 15: 0, # 'з' - 2: 0, # 'и' - 26: 0, # 'й' - 12: 0, # 'к' - 10: 0, # 'л' - 14: 0, # 'м' - 6: 0, # 'н' - 4: 0, # 'о' - 13: 0, # 'п' - 7: 0, # 'р' - 8: 0, # 'с' - 5: 0, # 'т' - 19: 0, # 'у' - 29: 0, # 'ф' - 25: 0, # 'х' - 22: 0, # 'ц' - 21: 0, # 'ч' - 27: 0, # 'ш' - 24: 0, # 'щ' - 17: 0, # 'ъ' - 52: 0, # 'ь' - 42: 0, # 'ю' - 16: 0, # 'я' - 58: 0, # 'є' - 62: 0, # '№' - }, -} - -# 255: Undefined characters that did not exist in training text -# 254: Carriage/Return -# 253: symbol (punctuation) that does not belong to word -# 252: 0 - 9 -# 251: Control characters - -# Character Mapping Table(s): -ISO_8859_5_BULGARIAN_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 77, # 'A' - 66: 90, # 'B' - 67: 99, # 'C' - 68: 100, # 'D' - 69: 72, # 'E' - 70: 109, # 'F' - 71: 107, # 'G' - 72: 101, # 'H' - 73: 79, # 'I' - 74: 185, # 'J' - 75: 81, # 'K' - 76: 102, # 'L' - 77: 76, # 'M' - 78: 94, # 'N' - 79: 82, # 'O' - 80: 110, # 'P' - 81: 186, # 'Q' - 82: 108, # 'R' - 83: 91, # 'S' - 84: 74, # 'T' - 85: 119, # 'U' - 86: 84, # 'V' - 87: 96, # 'W' - 88: 111, # 'X' - 89: 187, # 'Y' - 90: 115, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 65, # 'a' - 98: 69, # 'b' - 99: 70, # 'c' - 100: 66, # 'd' - 101: 63, # 'e' - 102: 68, # 'f' - 103: 112, # 'g' - 104: 103, # 'h' - 105: 92, # 'i' - 106: 194, # 'j' - 107: 104, # 'k' - 108: 95, # 'l' - 109: 86, # 'm' - 110: 87, # 'n' - 111: 71, # 'o' - 112: 116, # 'p' - 113: 195, # 'q' - 114: 85, # 'r' - 115: 93, # 's' - 116: 97, # 't' - 117: 113, # 'u' - 118: 196, # 'v' - 119: 197, # 'w' - 120: 198, # 'x' - 121: 199, # 'y' - 122: 200, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 194, # '\x80' - 129: 195, # '\x81' - 130: 196, # '\x82' - 131: 197, # '\x83' - 132: 198, # '\x84' - 133: 199, # '\x85' - 134: 200, # '\x86' - 135: 201, # '\x87' - 136: 202, # '\x88' - 137: 203, # '\x89' - 138: 204, # '\x8a' - 139: 205, # '\x8b' - 140: 206, # '\x8c' - 141: 207, # '\x8d' - 142: 208, # '\x8e' - 143: 209, # '\x8f' - 144: 210, # '\x90' - 145: 211, # '\x91' - 146: 212, # '\x92' - 147: 213, # '\x93' - 148: 214, # '\x94' - 149: 215, # '\x95' - 150: 216, # '\x96' - 151: 217, # '\x97' - 152: 218, # '\x98' - 153: 219, # '\x99' - 154: 220, # '\x9a' - 155: 221, # '\x9b' - 156: 222, # '\x9c' - 157: 223, # '\x9d' - 158: 224, # '\x9e' - 159: 225, # '\x9f' - 160: 81, # '\xa0' - 161: 226, # 'Ё' - 162: 227, # 'Ђ' - 163: 228, # 'Ѓ' - 164: 229, # 'Є' - 165: 230, # 'Ѕ' - 166: 105, # 'І' - 167: 231, # 'Ї' - 168: 232, # 'Ј' - 169: 233, # 'Љ' - 170: 234, # 'Њ' - 171: 235, # 'Ћ' - 172: 236, # 'Ќ' - 173: 45, # '\xad' - 174: 237, # 'Ў' - 175: 238, # 'Џ' - 176: 31, # 'А' - 177: 32, # 'Б' - 178: 35, # 'В' - 179: 43, # 'Г' - 180: 37, # 'Д' - 181: 44, # 'Е' - 182: 55, # 'Ж' - 183: 47, # 'З' - 184: 40, # 'И' - 185: 59, # 'Й' - 186: 33, # 'К' - 187: 46, # 'Л' - 188: 38, # 'М' - 189: 36, # 'Н' - 190: 41, # 'О' - 191: 30, # 'П' - 192: 39, # 'Р' - 193: 28, # 'С' - 194: 34, # 'Т' - 195: 51, # 'У' - 196: 48, # 'Ф' - 197: 49, # 'Х' - 198: 53, # 'Ц' - 199: 50, # 'Ч' - 200: 54, # 'Ш' - 201: 57, # 'Щ' - 202: 61, # 'Ъ' - 203: 239, # 'Ы' - 204: 67, # 'Ь' - 205: 240, # 'Э' - 206: 60, # 'Ю' - 207: 56, # 'Я' - 208: 1, # 'а' - 209: 18, # 'б' - 210: 9, # 'в' - 211: 20, # 'г' - 212: 11, # 'д' - 213: 3, # 'е' - 214: 23, # 'ж' - 215: 15, # 'з' - 216: 2, # 'и' - 217: 26, # 'й' - 218: 12, # 'к' - 219: 10, # 'л' - 220: 14, # 'м' - 221: 6, # 'н' - 222: 4, # 'о' - 223: 13, # 'п' - 224: 7, # 'р' - 225: 8, # 'с' - 226: 5, # 'т' - 227: 19, # 'у' - 228: 29, # 'ф' - 229: 25, # 'х' - 230: 22, # 'ц' - 231: 21, # 'ч' - 232: 27, # 'ш' - 233: 24, # 'щ' - 234: 17, # 'ъ' - 235: 75, # 'ы' - 236: 52, # 'ь' - 237: 241, # 'э' - 238: 42, # 'ю' - 239: 16, # 'я' - 240: 62, # '№' - 241: 242, # 'ё' - 242: 243, # 'ђ' - 243: 244, # 'ѓ' - 244: 58, # 'є' - 245: 245, # 'ѕ' - 246: 98, # 'і' - 247: 246, # 'ї' - 248: 247, # 'ј' - 249: 248, # 'љ' - 250: 249, # 'њ' - 251: 250, # 'ћ' - 252: 251, # 'ќ' - 253: 91, # '§' - 254: 252, # 'ў' - 255: 253, # 'џ' -} - -ISO_8859_5_BULGARIAN_MODEL = SingleByteCharSetModel(charset_name='ISO-8859-5', - language='Bulgarian', - char_to_order_map=ISO_8859_5_BULGARIAN_CHAR_TO_ORDER, - language_model=BULGARIAN_LANG_MODEL, - typical_positive_ratio=0.969392, - keep_ascii_letters=False, - alphabet='АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЬЮЯабвгдежзийклмнопрстуфхцчшщъьюя') - -WINDOWS_1251_BULGARIAN_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 77, # 'A' - 66: 90, # 'B' - 67: 99, # 'C' - 68: 100, # 'D' - 69: 72, # 'E' - 70: 109, # 'F' - 71: 107, # 'G' - 72: 101, # 'H' - 73: 79, # 'I' - 74: 185, # 'J' - 75: 81, # 'K' - 76: 102, # 'L' - 77: 76, # 'M' - 78: 94, # 'N' - 79: 82, # 'O' - 80: 110, # 'P' - 81: 186, # 'Q' - 82: 108, # 'R' - 83: 91, # 'S' - 84: 74, # 'T' - 85: 119, # 'U' - 86: 84, # 'V' - 87: 96, # 'W' - 88: 111, # 'X' - 89: 187, # 'Y' - 90: 115, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 65, # 'a' - 98: 69, # 'b' - 99: 70, # 'c' - 100: 66, # 'd' - 101: 63, # 'e' - 102: 68, # 'f' - 103: 112, # 'g' - 104: 103, # 'h' - 105: 92, # 'i' - 106: 194, # 'j' - 107: 104, # 'k' - 108: 95, # 'l' - 109: 86, # 'm' - 110: 87, # 'n' - 111: 71, # 'o' - 112: 116, # 'p' - 113: 195, # 'q' - 114: 85, # 'r' - 115: 93, # 's' - 116: 97, # 't' - 117: 113, # 'u' - 118: 196, # 'v' - 119: 197, # 'w' - 120: 198, # 'x' - 121: 199, # 'y' - 122: 200, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 206, # 'Ђ' - 129: 207, # 'Ѓ' - 130: 208, # '‚' - 131: 209, # 'ѓ' - 132: 210, # '„' - 133: 211, # '…' - 134: 212, # '†' - 135: 213, # '‡' - 136: 120, # '€' - 137: 214, # '‰' - 138: 215, # 'Љ' - 139: 216, # '‹' - 140: 217, # 'Њ' - 141: 218, # 'Ќ' - 142: 219, # 'Ћ' - 143: 220, # 'Џ' - 144: 221, # 'ђ' - 145: 78, # '‘' - 146: 64, # '’' - 147: 83, # '“' - 148: 121, # '”' - 149: 98, # '•' - 150: 117, # '–' - 151: 105, # '—' - 152: 222, # None - 153: 223, # '™' - 154: 224, # 'љ' - 155: 225, # '›' - 156: 226, # 'њ' - 157: 227, # 'ќ' - 158: 228, # 'ћ' - 159: 229, # 'џ' - 160: 88, # '\xa0' - 161: 230, # 'Ў' - 162: 231, # 'ў' - 163: 232, # 'Ј' - 164: 233, # '¤' - 165: 122, # 'Ґ' - 166: 89, # '¦' - 167: 106, # '§' - 168: 234, # 'Ё' - 169: 235, # '©' - 170: 236, # 'Є' - 171: 237, # '«' - 172: 238, # '¬' - 173: 45, # '\xad' - 174: 239, # '®' - 175: 240, # 'Ї' - 176: 73, # '°' - 177: 80, # '±' - 178: 118, # 'І' - 179: 114, # 'і' - 180: 241, # 'ґ' - 181: 242, # 'µ' - 182: 243, # '¶' - 183: 244, # '·' - 184: 245, # 'ё' - 185: 62, # '№' - 186: 58, # 'є' - 187: 246, # '»' - 188: 247, # 'ј' - 189: 248, # 'Ѕ' - 190: 249, # 'ѕ' - 191: 250, # 'ї' - 192: 31, # 'А' - 193: 32, # 'Б' - 194: 35, # 'В' - 195: 43, # 'Г' - 196: 37, # 'Д' - 197: 44, # 'Е' - 198: 55, # 'Ж' - 199: 47, # 'З' - 200: 40, # 'И' - 201: 59, # 'Й' - 202: 33, # 'К' - 203: 46, # 'Л' - 204: 38, # 'М' - 205: 36, # 'Н' - 206: 41, # 'О' - 207: 30, # 'П' - 208: 39, # 'Р' - 209: 28, # 'С' - 210: 34, # 'Т' - 211: 51, # 'У' - 212: 48, # 'Ф' - 213: 49, # 'Х' - 214: 53, # 'Ц' - 215: 50, # 'Ч' - 216: 54, # 'Ш' - 217: 57, # 'Щ' - 218: 61, # 'Ъ' - 219: 251, # 'Ы' - 220: 67, # 'Ь' - 221: 252, # 'Э' - 222: 60, # 'Ю' - 223: 56, # 'Я' - 224: 1, # 'а' - 225: 18, # 'б' - 226: 9, # 'в' - 227: 20, # 'г' - 228: 11, # 'д' - 229: 3, # 'е' - 230: 23, # 'ж' - 231: 15, # 'з' - 232: 2, # 'и' - 233: 26, # 'й' - 234: 12, # 'к' - 235: 10, # 'л' - 236: 14, # 'м' - 237: 6, # 'н' - 238: 4, # 'о' - 239: 13, # 'п' - 240: 7, # 'р' - 241: 8, # 'с' - 242: 5, # 'т' - 243: 19, # 'у' - 244: 29, # 'ф' - 245: 25, # 'х' - 246: 22, # 'ц' - 247: 21, # 'ч' - 248: 27, # 'ш' - 249: 24, # 'щ' - 250: 17, # 'ъ' - 251: 75, # 'ы' - 252: 52, # 'ь' - 253: 253, # 'э' - 254: 42, # 'ю' - 255: 16, # 'я' -} - -WINDOWS_1251_BULGARIAN_MODEL = SingleByteCharSetModel(charset_name='windows-1251', - language='Bulgarian', - char_to_order_map=WINDOWS_1251_BULGARIAN_CHAR_TO_ORDER, - language_model=BULGARIAN_LANG_MODEL, - typical_positive_ratio=0.969392, - keep_ascii_letters=False, - alphabet='АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЬЮЯабвгдежзийклмнопрстуфхцчшщъьюя') - diff --git a/venv/lib/python3.8/site-packages/chardet/langgreekmodel.py b/venv/lib/python3.8/site-packages/chardet/langgreekmodel.py deleted file mode 100644 index 02b94de..0000000 --- a/venv/lib/python3.8/site-packages/chardet/langgreekmodel.py +++ /dev/null @@ -1,4398 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from chardet.sbcharsetprober import SingleByteCharSetModel - - -# 3: Positive -# 2: Likely -# 1: Unlikely -# 0: Negative - -GREEK_LANG_MODEL = { - 60: { # 'e' - 60: 2, # 'e' - 55: 1, # 'o' - 58: 2, # 't' - 36: 1, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 1, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 0, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 0, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 0, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 0, # 'ο' - 9: 0, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 0, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 55: { # 'o' - 60: 0, # 'e' - 55: 2, # 'o' - 58: 2, # 't' - 36: 1, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 0, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 0, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 0, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 1, # 'ν' - 30: 0, # 'ξ' - 4: 0, # 'ο' - 9: 0, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 1, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 58: { # 't' - 60: 2, # 'e' - 55: 1, # 'o' - 58: 1, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 2, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 0, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 0, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 0, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 1, # 'ο' - 9: 0, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 0, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 36: { # '·' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 0, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 0, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 0, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 0, # 'ο' - 9: 0, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 0, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 61: { # 'Ά' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 0, # 'α' - 29: 0, # 'β' - 20: 1, # 'γ' - 21: 2, # 'δ' - 3: 0, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 0, # 'ι' - 11: 0, # 'κ' - 16: 2, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 0, # 'ο' - 9: 1, # 'π' - 8: 2, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 0, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 46: { # 'Έ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 0, # 'α' - 29: 2, # 'β' - 20: 2, # 'γ' - 21: 0, # 'δ' - 3: 0, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 0, # 'ι' - 11: 2, # 'κ' - 16: 2, # 'λ' - 10: 0, # 'μ' - 6: 3, # 'ν' - 30: 2, # 'ξ' - 4: 0, # 'ο' - 9: 2, # 'π' - 8: 2, # 'ρ' - 14: 0, # 'ς' - 7: 1, # 'σ' - 2: 2, # 'τ' - 12: 0, # 'υ' - 28: 2, # 'φ' - 23: 3, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 54: { # 'Ό' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 0, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 0, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 0, # 'ι' - 11: 0, # 'κ' - 16: 2, # 'λ' - 10: 2, # 'μ' - 6: 2, # 'ν' - 30: 0, # 'ξ' - 4: 0, # 'ο' - 9: 2, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 2, # 'σ' - 2: 3, # 'τ' - 12: 0, # 'υ' - 28: 0, # 'φ' - 23: 2, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 31: { # 'Α' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 2, # 'Β' - 43: 2, # 'Γ' - 41: 1, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 2, # 'Θ' - 47: 2, # 'Ι' - 44: 2, # 'Κ' - 53: 2, # 'Λ' - 38: 2, # 'Μ' - 49: 2, # 'Ν' - 59: 1, # 'Ξ' - 39: 0, # 'Ο' - 35: 2, # 'Π' - 48: 2, # 'Ρ' - 37: 2, # 'Σ' - 33: 2, # 'Τ' - 45: 2, # 'Υ' - 56: 2, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 0, # 'α' - 29: 0, # 'β' - 20: 2, # 'γ' - 21: 0, # 'δ' - 3: 0, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 1, # 'θ' - 5: 0, # 'ι' - 11: 2, # 'κ' - 16: 3, # 'λ' - 10: 2, # 'μ' - 6: 3, # 'ν' - 30: 2, # 'ξ' - 4: 0, # 'ο' - 9: 3, # 'π' - 8: 3, # 'ρ' - 14: 2, # 'ς' - 7: 2, # 'σ' - 2: 0, # 'τ' - 12: 3, # 'υ' - 28: 2, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 2, # 'ύ' - 27: 0, # 'ώ' - }, - 51: { # 'Β' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 2, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 1, # 'Ε' - 40: 1, # 'Η' - 52: 0, # 'Θ' - 47: 1, # 'Ι' - 44: 0, # 'Κ' - 53: 1, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 2, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 2, # 'ά' - 18: 2, # 'έ' - 22: 2, # 'ή' - 15: 0, # 'ί' - 1: 2, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 2, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 2, # 'ι' - 11: 0, # 'κ' - 16: 2, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 2, # 'ο' - 9: 0, # 'π' - 8: 2, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 0, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 43: { # 'Γ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 1, # 'Α' - 51: 0, # 'Β' - 43: 2, # 'Γ' - 41: 0, # 'Δ' - 34: 2, # 'Ε' - 40: 1, # 'Η' - 52: 0, # 'Θ' - 47: 2, # 'Ι' - 44: 1, # 'Κ' - 53: 1, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 1, # 'Ο' - 35: 0, # 'Π' - 48: 2, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 2, # 'Υ' - 56: 0, # 'Φ' - 50: 1, # 'Χ' - 57: 2, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 2, # 'ί' - 1: 2, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 2, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 3, # 'ι' - 11: 0, # 'κ' - 16: 2, # 'λ' - 10: 0, # 'μ' - 6: 2, # 'ν' - 30: 0, # 'ξ' - 4: 0, # 'ο' - 9: 0, # 'π' - 8: 2, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 0, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 41: { # 'Δ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 2, # 'Ε' - 40: 2, # 'Η' - 52: 0, # 'Θ' - 47: 2, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 2, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 2, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 2, # 'ή' - 15: 2, # 'ί' - 1: 0, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 2, # 'η' - 25: 0, # 'θ' - 5: 3, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 2, # 'ο' - 9: 0, # 'π' - 8: 2, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 2, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 2, # 'ω' - 19: 1, # 'ό' - 26: 2, # 'ύ' - 27: 2, # 'ώ' - }, - 34: { # 'Ε' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 2, # 'Α' - 51: 0, # 'Β' - 43: 2, # 'Γ' - 41: 2, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 2, # 'Ι' - 44: 2, # 'Κ' - 53: 2, # 'Λ' - 38: 2, # 'Μ' - 49: 2, # 'Ν' - 59: 1, # 'Ξ' - 39: 0, # 'Ο' - 35: 2, # 'Π' - 48: 2, # 'Ρ' - 37: 2, # 'Σ' - 33: 2, # 'Τ' - 45: 2, # 'Υ' - 56: 0, # 'Φ' - 50: 2, # 'Χ' - 57: 2, # 'Ω' - 17: 3, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 3, # 'ί' - 1: 0, # 'α' - 29: 0, # 'β' - 20: 3, # 'γ' - 21: 2, # 'δ' - 3: 1, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 1, # 'θ' - 5: 2, # 'ι' - 11: 3, # 'κ' - 16: 3, # 'λ' - 10: 2, # 'μ' - 6: 3, # 'ν' - 30: 2, # 'ξ' - 4: 0, # 'ο' - 9: 3, # 'π' - 8: 2, # 'ρ' - 14: 0, # 'ς' - 7: 2, # 'σ' - 2: 2, # 'τ' - 12: 2, # 'υ' - 28: 2, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 1, # 'ύ' - 27: 0, # 'ώ' - }, - 40: { # 'Η' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 1, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 2, # 'Θ' - 47: 0, # 'Ι' - 44: 2, # 'Κ' - 53: 0, # 'Λ' - 38: 2, # 'Μ' - 49: 2, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 2, # 'Π' - 48: 2, # 'Ρ' - 37: 2, # 'Σ' - 33: 2, # 'Τ' - 45: 1, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 0, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 0, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 0, # 'ι' - 11: 0, # 'κ' - 16: 2, # 'λ' - 10: 0, # 'μ' - 6: 1, # 'ν' - 30: 0, # 'ξ' - 4: 0, # 'ο' - 9: 0, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 0, # 'υ' - 28: 0, # 'φ' - 23: 1, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 52: { # 'Θ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 2, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 2, # 'Ε' - 40: 2, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 2, # 'Ο' - 35: 0, # 'Π' - 48: 1, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 1, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 2, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 3, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 2, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 0, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 0, # 'ο' - 9: 0, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 2, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 2, # 'ύ' - 27: 0, # 'ώ' - }, - 47: { # 'Ι' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 2, # 'Α' - 51: 1, # 'Β' - 43: 1, # 'Γ' - 41: 2, # 'Δ' - 34: 2, # 'Ε' - 40: 2, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 2, # 'Κ' - 53: 2, # 'Λ' - 38: 2, # 'Μ' - 49: 2, # 'Ν' - 59: 0, # 'Ξ' - 39: 2, # 'Ο' - 35: 0, # 'Π' - 48: 2, # 'Ρ' - 37: 2, # 'Σ' - 33: 2, # 'Τ' - 45: 0, # 'Υ' - 56: 2, # 'Φ' - 50: 0, # 'Χ' - 57: 2, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 2, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 2, # 'δ' - 3: 0, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 0, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 1, # 'ν' - 30: 0, # 'ξ' - 4: 2, # 'ο' - 9: 0, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 2, # 'σ' - 2: 1, # 'τ' - 12: 0, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 1, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 44: { # 'Κ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 2, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 1, # 'Δ' - 34: 2, # 'Ε' - 40: 2, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 1, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 2, # 'Ο' - 35: 0, # 'Π' - 48: 2, # 'Ρ' - 37: 0, # 'Σ' - 33: 1, # 'Τ' - 45: 2, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 1, # 'Ω' - 17: 3, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 3, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 2, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 2, # 'ι' - 11: 0, # 'κ' - 16: 2, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 2, # 'ο' - 9: 0, # 'π' - 8: 2, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 2, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 2, # 'ό' - 26: 2, # 'ύ' - 27: 2, # 'ώ' - }, - 53: { # 'Λ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 2, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 2, # 'Ε' - 40: 2, # 'Η' - 52: 0, # 'Θ' - 47: 2, # 'Ι' - 44: 0, # 'Κ' - 53: 2, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 2, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 2, # 'Σ' - 33: 0, # 'Τ' - 45: 2, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 2, # 'Ω' - 17: 2, # 'ά' - 18: 2, # 'έ' - 22: 0, # 'ή' - 15: 2, # 'ί' - 1: 2, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 2, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 1, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 2, # 'ο' - 9: 0, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 2, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 2, # 'ό' - 26: 2, # 'ύ' - 27: 0, # 'ώ' - }, - 38: { # 'Μ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 2, # 'Α' - 51: 2, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 2, # 'Ε' - 40: 2, # 'Η' - 52: 0, # 'Θ' - 47: 2, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 2, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 2, # 'Ο' - 35: 2, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 2, # 'ά' - 18: 2, # 'έ' - 22: 2, # 'ή' - 15: 2, # 'ί' - 1: 2, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 2, # 'η' - 25: 0, # 'θ' - 5: 3, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 2, # 'ο' - 9: 3, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 2, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 2, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 49: { # 'Ν' - 60: 2, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 2, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 2, # 'Ε' - 40: 2, # 'Η' - 52: 0, # 'Θ' - 47: 2, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 2, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 2, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 2, # 'Ω' - 17: 0, # 'ά' - 18: 2, # 'έ' - 22: 0, # 'ή' - 15: 2, # 'ί' - 1: 2, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 1, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 0, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 2, # 'ο' - 9: 0, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 0, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 1, # 'ω' - 19: 2, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 59: { # 'Ξ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 1, # 'Ε' - 40: 1, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 1, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 2, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 2, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 2, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 0, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 0, # 'ο' - 9: 0, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 0, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 39: { # 'Ο' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 1, # 'Β' - 43: 2, # 'Γ' - 41: 2, # 'Δ' - 34: 2, # 'Ε' - 40: 1, # 'Η' - 52: 2, # 'Θ' - 47: 2, # 'Ι' - 44: 2, # 'Κ' - 53: 2, # 'Λ' - 38: 2, # 'Μ' - 49: 2, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 2, # 'Π' - 48: 2, # 'Ρ' - 37: 2, # 'Σ' - 33: 2, # 'Τ' - 45: 2, # 'Υ' - 56: 2, # 'Φ' - 50: 2, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 0, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 2, # 'δ' - 3: 0, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 3, # 'ι' - 11: 2, # 'κ' - 16: 2, # 'λ' - 10: 2, # 'μ' - 6: 2, # 'ν' - 30: 0, # 'ξ' - 4: 0, # 'ο' - 9: 2, # 'π' - 8: 2, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 2, # 'τ' - 12: 2, # 'υ' - 28: 1, # 'φ' - 23: 1, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 2, # 'ύ' - 27: 0, # 'ώ' - }, - 35: { # 'Π' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 2, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 2, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 2, # 'Ι' - 44: 0, # 'Κ' - 53: 2, # 'Λ' - 38: 1, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 2, # 'Ο' - 35: 0, # 'Π' - 48: 2, # 'Ρ' - 37: 0, # 'Σ' - 33: 1, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 1, # 'Χ' - 57: 2, # 'Ω' - 17: 2, # 'ά' - 18: 1, # 'έ' - 22: 1, # 'ή' - 15: 2, # 'ί' - 1: 3, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 2, # 'η' - 25: 0, # 'θ' - 5: 2, # 'ι' - 11: 0, # 'κ' - 16: 2, # 'λ' - 10: 0, # 'μ' - 6: 2, # 'ν' - 30: 0, # 'ξ' - 4: 3, # 'ο' - 9: 0, # 'π' - 8: 3, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 2, # 'υ' - 28: 0, # 'φ' - 23: 2, # 'χ' - 42: 0, # 'ψ' - 24: 2, # 'ω' - 19: 2, # 'ό' - 26: 0, # 'ύ' - 27: 3, # 'ώ' - }, - 48: { # 'Ρ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 2, # 'Α' - 51: 0, # 'Β' - 43: 1, # 'Γ' - 41: 1, # 'Δ' - 34: 2, # 'Ε' - 40: 2, # 'Η' - 52: 0, # 'Θ' - 47: 2, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 2, # 'Ν' - 59: 0, # 'Ξ' - 39: 2, # 'Ο' - 35: 0, # 'Π' - 48: 2, # 'Ρ' - 37: 0, # 'Σ' - 33: 1, # 'Τ' - 45: 1, # 'Υ' - 56: 0, # 'Φ' - 50: 1, # 'Χ' - 57: 1, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 2, # 'ί' - 1: 0, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 0, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 0, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 1, # 'ο' - 9: 0, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 3, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 2, # 'ω' - 19: 0, # 'ό' - 26: 2, # 'ύ' - 27: 0, # 'ώ' - }, - 37: { # 'Σ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 2, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 1, # 'Δ' - 34: 2, # 'Ε' - 40: 2, # 'Η' - 52: 0, # 'Θ' - 47: 2, # 'Ι' - 44: 2, # 'Κ' - 53: 0, # 'Λ' - 38: 2, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 2, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 2, # 'Σ' - 33: 2, # 'Τ' - 45: 2, # 'Υ' - 56: 0, # 'Φ' - 50: 2, # 'Χ' - 57: 2, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 2, # 'ή' - 15: 2, # 'ί' - 1: 2, # 'α' - 29: 2, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 3, # 'η' - 25: 0, # 'θ' - 5: 2, # 'ι' - 11: 2, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 2, # 'ο' - 9: 2, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 3, # 'τ' - 12: 3, # 'υ' - 28: 0, # 'φ' - 23: 2, # 'χ' - 42: 0, # 'ψ' - 24: 2, # 'ω' - 19: 0, # 'ό' - 26: 2, # 'ύ' - 27: 2, # 'ώ' - }, - 33: { # 'Τ' - 60: 0, # 'e' - 55: 1, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 2, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 2, # 'Ε' - 40: 2, # 'Η' - 52: 0, # 'Θ' - 47: 2, # 'Ι' - 44: 2, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 2, # 'Ο' - 35: 0, # 'Π' - 48: 2, # 'Ρ' - 37: 0, # 'Σ' - 33: 1, # 'Τ' - 45: 1, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 2, # 'Ω' - 17: 2, # 'ά' - 18: 2, # 'έ' - 22: 0, # 'ή' - 15: 2, # 'ί' - 1: 3, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 2, # 'ε' - 32: 0, # 'ζ' - 13: 2, # 'η' - 25: 0, # 'θ' - 5: 2, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 2, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 3, # 'ο' - 9: 0, # 'π' - 8: 2, # 'ρ' - 14: 0, # 'ς' - 7: 2, # 'σ' - 2: 0, # 'τ' - 12: 2, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 2, # 'ό' - 26: 2, # 'ύ' - 27: 3, # 'ώ' - }, - 45: { # 'Υ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 2, # 'Γ' - 41: 0, # 'Δ' - 34: 1, # 'Ε' - 40: 2, # 'Η' - 52: 2, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 1, # 'Λ' - 38: 2, # 'Μ' - 49: 2, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 2, # 'Π' - 48: 1, # 'Ρ' - 37: 2, # 'Σ' - 33: 2, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 1, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 0, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 0, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 0, # 'ι' - 11: 0, # 'κ' - 16: 2, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 0, # 'ο' - 9: 3, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 0, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 56: { # 'Φ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 1, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 1, # 'Η' - 52: 0, # 'Θ' - 47: 2, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 2, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 2, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 2, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 2, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 2, # 'ο' - 9: 0, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 2, # 'τ' - 12: 2, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 1, # 'ύ' - 27: 1, # 'ώ' - }, - 50: { # 'Χ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 1, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 2, # 'Ε' - 40: 2, # 'Η' - 52: 0, # 'Θ' - 47: 2, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 1, # 'Ν' - 59: 0, # 'Ξ' - 39: 1, # 'Ο' - 35: 0, # 'Π' - 48: 2, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 1, # 'Χ' - 57: 1, # 'Ω' - 17: 2, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 2, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 2, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 0, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 2, # 'ο' - 9: 0, # 'π' - 8: 3, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 2, # 'τ' - 12: 0, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 2, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 57: { # 'Ω' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 1, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 1, # 'Λ' - 38: 0, # 'Μ' - 49: 2, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 2, # 'Ρ' - 37: 2, # 'Σ' - 33: 2, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 0, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 0, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 0, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 0, # 'ο' - 9: 0, # 'π' - 8: 2, # 'ρ' - 14: 2, # 'ς' - 7: 2, # 'σ' - 2: 0, # 'τ' - 12: 0, # 'υ' - 28: 0, # 'φ' - 23: 1, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 17: { # 'ά' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 2, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 0, # 'α' - 29: 3, # 'β' - 20: 3, # 'γ' - 21: 3, # 'δ' - 3: 3, # 'ε' - 32: 3, # 'ζ' - 13: 0, # 'η' - 25: 3, # 'θ' - 5: 2, # 'ι' - 11: 3, # 'κ' - 16: 3, # 'λ' - 10: 3, # 'μ' - 6: 3, # 'ν' - 30: 3, # 'ξ' - 4: 0, # 'ο' - 9: 3, # 'π' - 8: 3, # 'ρ' - 14: 3, # 'ς' - 7: 3, # 'σ' - 2: 3, # 'τ' - 12: 0, # 'υ' - 28: 3, # 'φ' - 23: 3, # 'χ' - 42: 3, # 'ψ' - 24: 2, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 18: { # 'έ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 3, # 'α' - 29: 2, # 'β' - 20: 3, # 'γ' - 21: 2, # 'δ' - 3: 3, # 'ε' - 32: 2, # 'ζ' - 13: 0, # 'η' - 25: 3, # 'θ' - 5: 0, # 'ι' - 11: 3, # 'κ' - 16: 3, # 'λ' - 10: 3, # 'μ' - 6: 3, # 'ν' - 30: 3, # 'ξ' - 4: 3, # 'ο' - 9: 3, # 'π' - 8: 3, # 'ρ' - 14: 3, # 'ς' - 7: 3, # 'σ' - 2: 3, # 'τ' - 12: 0, # 'υ' - 28: 3, # 'φ' - 23: 3, # 'χ' - 42: 3, # 'ψ' - 24: 2, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 22: { # 'ή' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 1, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 0, # 'α' - 29: 0, # 'β' - 20: 3, # 'γ' - 21: 3, # 'δ' - 3: 0, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 3, # 'θ' - 5: 0, # 'ι' - 11: 3, # 'κ' - 16: 2, # 'λ' - 10: 3, # 'μ' - 6: 3, # 'ν' - 30: 2, # 'ξ' - 4: 0, # 'ο' - 9: 3, # 'π' - 8: 3, # 'ρ' - 14: 3, # 'ς' - 7: 3, # 'σ' - 2: 3, # 'τ' - 12: 0, # 'υ' - 28: 2, # 'φ' - 23: 3, # 'χ' - 42: 2, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 15: { # 'ί' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 3, # 'α' - 29: 2, # 'β' - 20: 3, # 'γ' - 21: 3, # 'δ' - 3: 3, # 'ε' - 32: 3, # 'ζ' - 13: 3, # 'η' - 25: 3, # 'θ' - 5: 0, # 'ι' - 11: 3, # 'κ' - 16: 3, # 'λ' - 10: 3, # 'μ' - 6: 3, # 'ν' - 30: 3, # 'ξ' - 4: 3, # 'ο' - 9: 3, # 'π' - 8: 3, # 'ρ' - 14: 3, # 'ς' - 7: 3, # 'σ' - 2: 3, # 'τ' - 12: 0, # 'υ' - 28: 1, # 'φ' - 23: 3, # 'χ' - 42: 2, # 'ψ' - 24: 3, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 1: { # 'α' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 2, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 2, # 'έ' - 22: 0, # 'ή' - 15: 3, # 'ί' - 1: 0, # 'α' - 29: 3, # 'β' - 20: 3, # 'γ' - 21: 3, # 'δ' - 3: 2, # 'ε' - 32: 3, # 'ζ' - 13: 1, # 'η' - 25: 3, # 'θ' - 5: 3, # 'ι' - 11: 3, # 'κ' - 16: 3, # 'λ' - 10: 3, # 'μ' - 6: 3, # 'ν' - 30: 3, # 'ξ' - 4: 2, # 'ο' - 9: 3, # 'π' - 8: 3, # 'ρ' - 14: 3, # 'ς' - 7: 3, # 'σ' - 2: 3, # 'τ' - 12: 3, # 'υ' - 28: 3, # 'φ' - 23: 3, # 'χ' - 42: 2, # 'ψ' - 24: 0, # 'ω' - 19: 2, # 'ό' - 26: 2, # 'ύ' - 27: 0, # 'ώ' - }, - 29: { # 'β' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 3, # 'ά' - 18: 2, # 'έ' - 22: 3, # 'ή' - 15: 2, # 'ί' - 1: 3, # 'α' - 29: 0, # 'β' - 20: 2, # 'γ' - 21: 2, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 2, # 'η' - 25: 0, # 'θ' - 5: 3, # 'ι' - 11: 0, # 'κ' - 16: 3, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 3, # 'ο' - 9: 0, # 'π' - 8: 3, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 0, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 2, # 'ω' - 19: 2, # 'ό' - 26: 2, # 'ύ' - 27: 2, # 'ώ' - }, - 20: { # 'γ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 3, # 'ά' - 18: 3, # 'έ' - 22: 3, # 'ή' - 15: 3, # 'ί' - 1: 3, # 'α' - 29: 0, # 'β' - 20: 3, # 'γ' - 21: 0, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 3, # 'η' - 25: 0, # 'θ' - 5: 3, # 'ι' - 11: 3, # 'κ' - 16: 3, # 'λ' - 10: 3, # 'μ' - 6: 3, # 'ν' - 30: 3, # 'ξ' - 4: 3, # 'ο' - 9: 0, # 'π' - 8: 3, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 2, # 'υ' - 28: 0, # 'φ' - 23: 3, # 'χ' - 42: 0, # 'ψ' - 24: 3, # 'ω' - 19: 3, # 'ό' - 26: 2, # 'ύ' - 27: 3, # 'ώ' - }, - 21: { # 'δ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 2, # 'ά' - 18: 3, # 'έ' - 22: 3, # 'ή' - 15: 3, # 'ί' - 1: 3, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 3, # 'η' - 25: 0, # 'θ' - 5: 3, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 3, # 'ο' - 9: 0, # 'π' - 8: 3, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 3, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 3, # 'ω' - 19: 3, # 'ό' - 26: 3, # 'ύ' - 27: 3, # 'ώ' - }, - 3: { # 'ε' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 2, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 3, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 3, # 'ί' - 1: 2, # 'α' - 29: 3, # 'β' - 20: 3, # 'γ' - 21: 3, # 'δ' - 3: 2, # 'ε' - 32: 2, # 'ζ' - 13: 0, # 'η' - 25: 3, # 'θ' - 5: 3, # 'ι' - 11: 3, # 'κ' - 16: 3, # 'λ' - 10: 3, # 'μ' - 6: 3, # 'ν' - 30: 3, # 'ξ' - 4: 2, # 'ο' - 9: 3, # 'π' - 8: 3, # 'ρ' - 14: 3, # 'ς' - 7: 3, # 'σ' - 2: 3, # 'τ' - 12: 3, # 'υ' - 28: 3, # 'φ' - 23: 3, # 'χ' - 42: 2, # 'ψ' - 24: 3, # 'ω' - 19: 2, # 'ό' - 26: 3, # 'ύ' - 27: 2, # 'ώ' - }, - 32: { # 'ζ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 2, # 'ά' - 18: 2, # 'έ' - 22: 2, # 'ή' - 15: 2, # 'ί' - 1: 2, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 3, # 'η' - 25: 0, # 'θ' - 5: 2, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 3, # 'ο' - 9: 0, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 1, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 3, # 'ω' - 19: 2, # 'ό' - 26: 0, # 'ύ' - 27: 2, # 'ώ' - }, - 13: { # 'η' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 2, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 0, # 'α' - 29: 0, # 'β' - 20: 3, # 'γ' - 21: 2, # 'δ' - 3: 0, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 3, # 'θ' - 5: 0, # 'ι' - 11: 3, # 'κ' - 16: 3, # 'λ' - 10: 3, # 'μ' - 6: 3, # 'ν' - 30: 2, # 'ξ' - 4: 0, # 'ο' - 9: 2, # 'π' - 8: 3, # 'ρ' - 14: 3, # 'ς' - 7: 3, # 'σ' - 2: 3, # 'τ' - 12: 0, # 'υ' - 28: 2, # 'φ' - 23: 3, # 'χ' - 42: 2, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 25: { # 'θ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 2, # 'ά' - 18: 3, # 'έ' - 22: 3, # 'ή' - 15: 2, # 'ί' - 1: 3, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 3, # 'η' - 25: 0, # 'θ' - 5: 3, # 'ι' - 11: 0, # 'κ' - 16: 1, # 'λ' - 10: 3, # 'μ' - 6: 2, # 'ν' - 30: 0, # 'ξ' - 4: 3, # 'ο' - 9: 0, # 'π' - 8: 3, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 3, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 3, # 'ω' - 19: 3, # 'ό' - 26: 3, # 'ύ' - 27: 3, # 'ώ' - }, - 5: { # 'ι' - 60: 0, # 'e' - 55: 1, # 'o' - 58: 0, # 't' - 36: 2, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 1, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 3, # 'ά' - 18: 3, # 'έ' - 22: 3, # 'ή' - 15: 0, # 'ί' - 1: 3, # 'α' - 29: 3, # 'β' - 20: 3, # 'γ' - 21: 3, # 'δ' - 3: 3, # 'ε' - 32: 2, # 'ζ' - 13: 3, # 'η' - 25: 3, # 'θ' - 5: 0, # 'ι' - 11: 3, # 'κ' - 16: 3, # 'λ' - 10: 3, # 'μ' - 6: 3, # 'ν' - 30: 3, # 'ξ' - 4: 3, # 'ο' - 9: 3, # 'π' - 8: 3, # 'ρ' - 14: 3, # 'ς' - 7: 3, # 'σ' - 2: 3, # 'τ' - 12: 0, # 'υ' - 28: 2, # 'φ' - 23: 3, # 'χ' - 42: 2, # 'ψ' - 24: 3, # 'ω' - 19: 3, # 'ό' - 26: 0, # 'ύ' - 27: 3, # 'ώ' - }, - 11: { # 'κ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 3, # 'ά' - 18: 3, # 'έ' - 22: 3, # 'ή' - 15: 3, # 'ί' - 1: 3, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 3, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 3, # 'η' - 25: 2, # 'θ' - 5: 3, # 'ι' - 11: 3, # 'κ' - 16: 3, # 'λ' - 10: 3, # 'μ' - 6: 2, # 'ν' - 30: 0, # 'ξ' - 4: 3, # 'ο' - 9: 2, # 'π' - 8: 3, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 3, # 'τ' - 12: 3, # 'υ' - 28: 2, # 'φ' - 23: 2, # 'χ' - 42: 0, # 'ψ' - 24: 3, # 'ω' - 19: 3, # 'ό' - 26: 3, # 'ύ' - 27: 3, # 'ώ' - }, - 16: { # 'λ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 3, # 'ά' - 18: 3, # 'έ' - 22: 3, # 'ή' - 15: 3, # 'ί' - 1: 3, # 'α' - 29: 1, # 'β' - 20: 2, # 'γ' - 21: 1, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 3, # 'η' - 25: 2, # 'θ' - 5: 3, # 'ι' - 11: 2, # 'κ' - 16: 3, # 'λ' - 10: 2, # 'μ' - 6: 2, # 'ν' - 30: 0, # 'ξ' - 4: 3, # 'ο' - 9: 3, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 3, # 'τ' - 12: 3, # 'υ' - 28: 2, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 3, # 'ω' - 19: 3, # 'ό' - 26: 3, # 'ύ' - 27: 3, # 'ώ' - }, - 10: { # 'μ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 1, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 3, # 'ά' - 18: 3, # 'έ' - 22: 3, # 'ή' - 15: 3, # 'ί' - 1: 3, # 'α' - 29: 3, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 3, # 'η' - 25: 0, # 'θ' - 5: 3, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 3, # 'μ' - 6: 3, # 'ν' - 30: 0, # 'ξ' - 4: 3, # 'ο' - 9: 3, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 2, # 'υ' - 28: 3, # 'φ' - 23: 0, # 'χ' - 42: 2, # 'ψ' - 24: 3, # 'ω' - 19: 3, # 'ό' - 26: 2, # 'ύ' - 27: 2, # 'ώ' - }, - 6: { # 'ν' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 2, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 3, # 'ά' - 18: 3, # 'έ' - 22: 3, # 'ή' - 15: 3, # 'ί' - 1: 3, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 3, # 'δ' - 3: 3, # 'ε' - 32: 2, # 'ζ' - 13: 3, # 'η' - 25: 3, # 'θ' - 5: 3, # 'ι' - 11: 0, # 'κ' - 16: 1, # 'λ' - 10: 0, # 'μ' - 6: 2, # 'ν' - 30: 0, # 'ξ' - 4: 3, # 'ο' - 9: 0, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 3, # 'σ' - 2: 3, # 'τ' - 12: 3, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 3, # 'ω' - 19: 3, # 'ό' - 26: 3, # 'ύ' - 27: 3, # 'ώ' - }, - 30: { # 'ξ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 2, # 'ά' - 18: 3, # 'έ' - 22: 3, # 'ή' - 15: 2, # 'ί' - 1: 3, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 3, # 'η' - 25: 0, # 'θ' - 5: 2, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 3, # 'ο' - 9: 0, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 3, # 'τ' - 12: 2, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 3, # 'ω' - 19: 2, # 'ό' - 26: 3, # 'ύ' - 27: 1, # 'ώ' - }, - 4: { # 'ο' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 2, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 2, # 'έ' - 22: 3, # 'ή' - 15: 3, # 'ί' - 1: 2, # 'α' - 29: 3, # 'β' - 20: 3, # 'γ' - 21: 3, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 3, # 'η' - 25: 3, # 'θ' - 5: 3, # 'ι' - 11: 3, # 'κ' - 16: 3, # 'λ' - 10: 3, # 'μ' - 6: 3, # 'ν' - 30: 2, # 'ξ' - 4: 2, # 'ο' - 9: 3, # 'π' - 8: 3, # 'ρ' - 14: 3, # 'ς' - 7: 3, # 'σ' - 2: 3, # 'τ' - 12: 3, # 'υ' - 28: 3, # 'φ' - 23: 3, # 'χ' - 42: 2, # 'ψ' - 24: 2, # 'ω' - 19: 1, # 'ό' - 26: 3, # 'ύ' - 27: 2, # 'ώ' - }, - 9: { # 'π' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 3, # 'ά' - 18: 3, # 'έ' - 22: 3, # 'ή' - 15: 3, # 'ί' - 1: 3, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 3, # 'η' - 25: 0, # 'θ' - 5: 3, # 'ι' - 11: 0, # 'κ' - 16: 3, # 'λ' - 10: 0, # 'μ' - 6: 2, # 'ν' - 30: 0, # 'ξ' - 4: 3, # 'ο' - 9: 0, # 'π' - 8: 3, # 'ρ' - 14: 2, # 'ς' - 7: 0, # 'σ' - 2: 3, # 'τ' - 12: 3, # 'υ' - 28: 0, # 'φ' - 23: 2, # 'χ' - 42: 0, # 'ψ' - 24: 3, # 'ω' - 19: 3, # 'ό' - 26: 2, # 'ύ' - 27: 3, # 'ώ' - }, - 8: { # 'ρ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 3, # 'ά' - 18: 3, # 'έ' - 22: 3, # 'ή' - 15: 3, # 'ί' - 1: 3, # 'α' - 29: 2, # 'β' - 20: 3, # 'γ' - 21: 2, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 3, # 'η' - 25: 3, # 'θ' - 5: 3, # 'ι' - 11: 3, # 'κ' - 16: 1, # 'λ' - 10: 3, # 'μ' - 6: 3, # 'ν' - 30: 2, # 'ξ' - 4: 3, # 'ο' - 9: 2, # 'π' - 8: 2, # 'ρ' - 14: 0, # 'ς' - 7: 2, # 'σ' - 2: 3, # 'τ' - 12: 3, # 'υ' - 28: 3, # 'φ' - 23: 3, # 'χ' - 42: 0, # 'ψ' - 24: 3, # 'ω' - 19: 3, # 'ό' - 26: 3, # 'ύ' - 27: 3, # 'ώ' - }, - 14: { # 'ς' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 2, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 0, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 0, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 0, # 'θ' - 5: 0, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 0, # 'ο' - 9: 0, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 0, # 'τ' - 12: 0, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 7: { # 'σ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 2, # 'ά' - 18: 2, # 'έ' - 22: 3, # 'ή' - 15: 3, # 'ί' - 1: 3, # 'α' - 29: 3, # 'β' - 20: 0, # 'γ' - 21: 2, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 3, # 'η' - 25: 3, # 'θ' - 5: 3, # 'ι' - 11: 3, # 'κ' - 16: 2, # 'λ' - 10: 3, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 3, # 'ο' - 9: 3, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 3, # 'σ' - 2: 3, # 'τ' - 12: 3, # 'υ' - 28: 3, # 'φ' - 23: 3, # 'χ' - 42: 0, # 'ψ' - 24: 3, # 'ω' - 19: 3, # 'ό' - 26: 3, # 'ύ' - 27: 2, # 'ώ' - }, - 2: { # 'τ' - 60: 0, # 'e' - 55: 2, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 3, # 'ά' - 18: 3, # 'έ' - 22: 3, # 'ή' - 15: 3, # 'ί' - 1: 3, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 3, # 'ε' - 32: 2, # 'ζ' - 13: 3, # 'η' - 25: 0, # 'θ' - 5: 3, # 'ι' - 11: 2, # 'κ' - 16: 2, # 'λ' - 10: 3, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 3, # 'ο' - 9: 0, # 'π' - 8: 3, # 'ρ' - 14: 0, # 'ς' - 7: 3, # 'σ' - 2: 3, # 'τ' - 12: 3, # 'υ' - 28: 2, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 3, # 'ω' - 19: 3, # 'ό' - 26: 3, # 'ύ' - 27: 3, # 'ώ' - }, - 12: { # 'υ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 2, # 'ά' - 18: 2, # 'έ' - 22: 3, # 'ή' - 15: 2, # 'ί' - 1: 3, # 'α' - 29: 2, # 'β' - 20: 3, # 'γ' - 21: 2, # 'δ' - 3: 2, # 'ε' - 32: 2, # 'ζ' - 13: 2, # 'η' - 25: 3, # 'θ' - 5: 2, # 'ι' - 11: 3, # 'κ' - 16: 3, # 'λ' - 10: 3, # 'μ' - 6: 3, # 'ν' - 30: 3, # 'ξ' - 4: 3, # 'ο' - 9: 3, # 'π' - 8: 3, # 'ρ' - 14: 3, # 'ς' - 7: 3, # 'σ' - 2: 3, # 'τ' - 12: 0, # 'υ' - 28: 2, # 'φ' - 23: 3, # 'χ' - 42: 2, # 'ψ' - 24: 2, # 'ω' - 19: 2, # 'ό' - 26: 0, # 'ύ' - 27: 2, # 'ώ' - }, - 28: { # 'φ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 3, # 'ά' - 18: 3, # 'έ' - 22: 3, # 'ή' - 15: 3, # 'ί' - 1: 3, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 2, # 'η' - 25: 2, # 'θ' - 5: 3, # 'ι' - 11: 0, # 'κ' - 16: 2, # 'λ' - 10: 0, # 'μ' - 6: 1, # 'ν' - 30: 0, # 'ξ' - 4: 3, # 'ο' - 9: 0, # 'π' - 8: 3, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 3, # 'τ' - 12: 3, # 'υ' - 28: 1, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 3, # 'ω' - 19: 3, # 'ό' - 26: 2, # 'ύ' - 27: 2, # 'ώ' - }, - 23: { # 'χ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 3, # 'ά' - 18: 2, # 'έ' - 22: 3, # 'ή' - 15: 3, # 'ί' - 1: 3, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 2, # 'η' - 25: 2, # 'θ' - 5: 3, # 'ι' - 11: 0, # 'κ' - 16: 2, # 'λ' - 10: 2, # 'μ' - 6: 3, # 'ν' - 30: 0, # 'ξ' - 4: 3, # 'ο' - 9: 0, # 'π' - 8: 3, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 3, # 'τ' - 12: 3, # 'υ' - 28: 0, # 'φ' - 23: 2, # 'χ' - 42: 0, # 'ψ' - 24: 3, # 'ω' - 19: 3, # 'ό' - 26: 3, # 'ύ' - 27: 3, # 'ώ' - }, - 42: { # 'ψ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 2, # 'ά' - 18: 2, # 'έ' - 22: 1, # 'ή' - 15: 2, # 'ί' - 1: 2, # 'α' - 29: 0, # 'β' - 20: 0, # 'γ' - 21: 0, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 3, # 'η' - 25: 0, # 'θ' - 5: 2, # 'ι' - 11: 0, # 'κ' - 16: 0, # 'λ' - 10: 0, # 'μ' - 6: 0, # 'ν' - 30: 0, # 'ξ' - 4: 2, # 'ο' - 9: 0, # 'π' - 8: 0, # 'ρ' - 14: 0, # 'ς' - 7: 0, # 'σ' - 2: 2, # 'τ' - 12: 1, # 'υ' - 28: 0, # 'φ' - 23: 0, # 'χ' - 42: 0, # 'ψ' - 24: 2, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 24: { # 'ω' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 1, # 'ά' - 18: 0, # 'έ' - 22: 2, # 'ή' - 15: 0, # 'ί' - 1: 0, # 'α' - 29: 2, # 'β' - 20: 3, # 'γ' - 21: 2, # 'δ' - 3: 0, # 'ε' - 32: 0, # 'ζ' - 13: 0, # 'η' - 25: 3, # 'θ' - 5: 2, # 'ι' - 11: 0, # 'κ' - 16: 2, # 'λ' - 10: 3, # 'μ' - 6: 3, # 'ν' - 30: 0, # 'ξ' - 4: 0, # 'ο' - 9: 3, # 'π' - 8: 3, # 'ρ' - 14: 3, # 'ς' - 7: 3, # 'σ' - 2: 3, # 'τ' - 12: 0, # 'υ' - 28: 2, # 'φ' - 23: 2, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 19: { # 'ό' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 0, # 'α' - 29: 3, # 'β' - 20: 3, # 'γ' - 21: 3, # 'δ' - 3: 1, # 'ε' - 32: 2, # 'ζ' - 13: 2, # 'η' - 25: 2, # 'θ' - 5: 2, # 'ι' - 11: 3, # 'κ' - 16: 3, # 'λ' - 10: 3, # 'μ' - 6: 3, # 'ν' - 30: 1, # 'ξ' - 4: 2, # 'ο' - 9: 3, # 'π' - 8: 3, # 'ρ' - 14: 3, # 'ς' - 7: 3, # 'σ' - 2: 3, # 'τ' - 12: 0, # 'υ' - 28: 2, # 'φ' - 23: 3, # 'χ' - 42: 2, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 26: { # 'ύ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 2, # 'α' - 29: 2, # 'β' - 20: 2, # 'γ' - 21: 1, # 'δ' - 3: 3, # 'ε' - 32: 0, # 'ζ' - 13: 2, # 'η' - 25: 3, # 'θ' - 5: 0, # 'ι' - 11: 3, # 'κ' - 16: 3, # 'λ' - 10: 3, # 'μ' - 6: 3, # 'ν' - 30: 2, # 'ξ' - 4: 3, # 'ο' - 9: 3, # 'π' - 8: 3, # 'ρ' - 14: 3, # 'ς' - 7: 3, # 'σ' - 2: 3, # 'τ' - 12: 0, # 'υ' - 28: 2, # 'φ' - 23: 2, # 'χ' - 42: 2, # 'ψ' - 24: 2, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, - 27: { # 'ώ' - 60: 0, # 'e' - 55: 0, # 'o' - 58: 0, # 't' - 36: 0, # '·' - 61: 0, # 'Ά' - 46: 0, # 'Έ' - 54: 0, # 'Ό' - 31: 0, # 'Α' - 51: 0, # 'Β' - 43: 0, # 'Γ' - 41: 0, # 'Δ' - 34: 0, # 'Ε' - 40: 0, # 'Η' - 52: 0, # 'Θ' - 47: 0, # 'Ι' - 44: 0, # 'Κ' - 53: 0, # 'Λ' - 38: 0, # 'Μ' - 49: 0, # 'Ν' - 59: 0, # 'Ξ' - 39: 0, # 'Ο' - 35: 0, # 'Π' - 48: 0, # 'Ρ' - 37: 0, # 'Σ' - 33: 0, # 'Τ' - 45: 0, # 'Υ' - 56: 0, # 'Φ' - 50: 0, # 'Χ' - 57: 0, # 'Ω' - 17: 0, # 'ά' - 18: 0, # 'έ' - 22: 0, # 'ή' - 15: 0, # 'ί' - 1: 0, # 'α' - 29: 1, # 'β' - 20: 0, # 'γ' - 21: 3, # 'δ' - 3: 0, # 'ε' - 32: 0, # 'ζ' - 13: 1, # 'η' - 25: 2, # 'θ' - 5: 2, # 'ι' - 11: 0, # 'κ' - 16: 2, # 'λ' - 10: 3, # 'μ' - 6: 3, # 'ν' - 30: 1, # 'ξ' - 4: 0, # 'ο' - 9: 2, # 'π' - 8: 3, # 'ρ' - 14: 3, # 'ς' - 7: 3, # 'σ' - 2: 3, # 'τ' - 12: 0, # 'υ' - 28: 1, # 'φ' - 23: 1, # 'χ' - 42: 0, # 'ψ' - 24: 0, # 'ω' - 19: 0, # 'ό' - 26: 0, # 'ύ' - 27: 0, # 'ώ' - }, -} - -# 255: Undefined characters that did not exist in training text -# 254: Carriage/Return -# 253: symbol (punctuation) that does not belong to word -# 252: 0 - 9 -# 251: Control characters - -# Character Mapping Table(s): -WINDOWS_1253_GREEK_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 82, # 'A' - 66: 100, # 'B' - 67: 104, # 'C' - 68: 94, # 'D' - 69: 98, # 'E' - 70: 101, # 'F' - 71: 116, # 'G' - 72: 102, # 'H' - 73: 111, # 'I' - 74: 187, # 'J' - 75: 117, # 'K' - 76: 92, # 'L' - 77: 88, # 'M' - 78: 113, # 'N' - 79: 85, # 'O' - 80: 79, # 'P' - 81: 118, # 'Q' - 82: 105, # 'R' - 83: 83, # 'S' - 84: 67, # 'T' - 85: 114, # 'U' - 86: 119, # 'V' - 87: 95, # 'W' - 88: 99, # 'X' - 89: 109, # 'Y' - 90: 188, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 72, # 'a' - 98: 70, # 'b' - 99: 80, # 'c' - 100: 81, # 'd' - 101: 60, # 'e' - 102: 96, # 'f' - 103: 93, # 'g' - 104: 89, # 'h' - 105: 68, # 'i' - 106: 120, # 'j' - 107: 97, # 'k' - 108: 77, # 'l' - 109: 86, # 'm' - 110: 69, # 'n' - 111: 55, # 'o' - 112: 78, # 'p' - 113: 115, # 'q' - 114: 65, # 'r' - 115: 66, # 's' - 116: 58, # 't' - 117: 76, # 'u' - 118: 106, # 'v' - 119: 103, # 'w' - 120: 87, # 'x' - 121: 107, # 'y' - 122: 112, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 255, # '€' - 129: 255, # None - 130: 255, # '‚' - 131: 255, # 'ƒ' - 132: 255, # '„' - 133: 255, # '…' - 134: 255, # '†' - 135: 255, # '‡' - 136: 255, # None - 137: 255, # '‰' - 138: 255, # None - 139: 255, # '‹' - 140: 255, # None - 141: 255, # None - 142: 255, # None - 143: 255, # None - 144: 255, # None - 145: 255, # '‘' - 146: 255, # '’' - 147: 255, # '“' - 148: 255, # '”' - 149: 255, # '•' - 150: 255, # '–' - 151: 255, # '—' - 152: 255, # None - 153: 255, # '™' - 154: 255, # None - 155: 255, # '›' - 156: 255, # None - 157: 255, # None - 158: 255, # None - 159: 255, # None - 160: 253, # '\xa0' - 161: 233, # '΅' - 162: 61, # 'Ά' - 163: 253, # '£' - 164: 253, # '¤' - 165: 253, # '¥' - 166: 253, # '¦' - 167: 253, # '§' - 168: 253, # '¨' - 169: 253, # '©' - 170: 253, # None - 171: 253, # '«' - 172: 253, # '¬' - 173: 74, # '\xad' - 174: 253, # '®' - 175: 253, # '―' - 176: 253, # '°' - 177: 253, # '±' - 178: 253, # '²' - 179: 253, # '³' - 180: 247, # '΄' - 181: 253, # 'µ' - 182: 253, # '¶' - 183: 36, # '·' - 184: 46, # 'Έ' - 185: 71, # 'Ή' - 186: 73, # 'Ί' - 187: 253, # '»' - 188: 54, # 'Ό' - 189: 253, # '½' - 190: 108, # 'Ύ' - 191: 123, # 'Ώ' - 192: 110, # 'ΐ' - 193: 31, # 'Α' - 194: 51, # 'Β' - 195: 43, # 'Γ' - 196: 41, # 'Δ' - 197: 34, # 'Ε' - 198: 91, # 'Ζ' - 199: 40, # 'Η' - 200: 52, # 'Θ' - 201: 47, # 'Ι' - 202: 44, # 'Κ' - 203: 53, # 'Λ' - 204: 38, # 'Μ' - 205: 49, # 'Ν' - 206: 59, # 'Ξ' - 207: 39, # 'Ο' - 208: 35, # 'Π' - 209: 48, # 'Ρ' - 210: 250, # None - 211: 37, # 'Σ' - 212: 33, # 'Τ' - 213: 45, # 'Υ' - 214: 56, # 'Φ' - 215: 50, # 'Χ' - 216: 84, # 'Ψ' - 217: 57, # 'Ω' - 218: 120, # 'Ϊ' - 219: 121, # 'Ϋ' - 220: 17, # 'ά' - 221: 18, # 'έ' - 222: 22, # 'ή' - 223: 15, # 'ί' - 224: 124, # 'ΰ' - 225: 1, # 'α' - 226: 29, # 'β' - 227: 20, # 'γ' - 228: 21, # 'δ' - 229: 3, # 'ε' - 230: 32, # 'ζ' - 231: 13, # 'η' - 232: 25, # 'θ' - 233: 5, # 'ι' - 234: 11, # 'κ' - 235: 16, # 'λ' - 236: 10, # 'μ' - 237: 6, # 'ν' - 238: 30, # 'ξ' - 239: 4, # 'ο' - 240: 9, # 'π' - 241: 8, # 'ρ' - 242: 14, # 'ς' - 243: 7, # 'σ' - 244: 2, # 'τ' - 245: 12, # 'υ' - 246: 28, # 'φ' - 247: 23, # 'χ' - 248: 42, # 'ψ' - 249: 24, # 'ω' - 250: 64, # 'ϊ' - 251: 75, # 'ϋ' - 252: 19, # 'ό' - 253: 26, # 'ύ' - 254: 27, # 'ώ' - 255: 253, # None -} - -WINDOWS_1253_GREEK_MODEL = SingleByteCharSetModel(charset_name='windows-1253', - language='Greek', - char_to_order_map=WINDOWS_1253_GREEK_CHAR_TO_ORDER, - language_model=GREEK_LANG_MODEL, - typical_positive_ratio=0.982851, - keep_ascii_letters=False, - alphabet='ΆΈΉΊΌΎΏΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩάέήίαβγδεζηθικλμνξοπρςστυφχψωόύώ') - -ISO_8859_7_GREEK_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 82, # 'A' - 66: 100, # 'B' - 67: 104, # 'C' - 68: 94, # 'D' - 69: 98, # 'E' - 70: 101, # 'F' - 71: 116, # 'G' - 72: 102, # 'H' - 73: 111, # 'I' - 74: 187, # 'J' - 75: 117, # 'K' - 76: 92, # 'L' - 77: 88, # 'M' - 78: 113, # 'N' - 79: 85, # 'O' - 80: 79, # 'P' - 81: 118, # 'Q' - 82: 105, # 'R' - 83: 83, # 'S' - 84: 67, # 'T' - 85: 114, # 'U' - 86: 119, # 'V' - 87: 95, # 'W' - 88: 99, # 'X' - 89: 109, # 'Y' - 90: 188, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 72, # 'a' - 98: 70, # 'b' - 99: 80, # 'c' - 100: 81, # 'd' - 101: 60, # 'e' - 102: 96, # 'f' - 103: 93, # 'g' - 104: 89, # 'h' - 105: 68, # 'i' - 106: 120, # 'j' - 107: 97, # 'k' - 108: 77, # 'l' - 109: 86, # 'm' - 110: 69, # 'n' - 111: 55, # 'o' - 112: 78, # 'p' - 113: 115, # 'q' - 114: 65, # 'r' - 115: 66, # 's' - 116: 58, # 't' - 117: 76, # 'u' - 118: 106, # 'v' - 119: 103, # 'w' - 120: 87, # 'x' - 121: 107, # 'y' - 122: 112, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 255, # '\x80' - 129: 255, # '\x81' - 130: 255, # '\x82' - 131: 255, # '\x83' - 132: 255, # '\x84' - 133: 255, # '\x85' - 134: 255, # '\x86' - 135: 255, # '\x87' - 136: 255, # '\x88' - 137: 255, # '\x89' - 138: 255, # '\x8a' - 139: 255, # '\x8b' - 140: 255, # '\x8c' - 141: 255, # '\x8d' - 142: 255, # '\x8e' - 143: 255, # '\x8f' - 144: 255, # '\x90' - 145: 255, # '\x91' - 146: 255, # '\x92' - 147: 255, # '\x93' - 148: 255, # '\x94' - 149: 255, # '\x95' - 150: 255, # '\x96' - 151: 255, # '\x97' - 152: 255, # '\x98' - 153: 255, # '\x99' - 154: 255, # '\x9a' - 155: 255, # '\x9b' - 156: 255, # '\x9c' - 157: 255, # '\x9d' - 158: 255, # '\x9e' - 159: 255, # '\x9f' - 160: 253, # '\xa0' - 161: 233, # '‘' - 162: 90, # '’' - 163: 253, # '£' - 164: 253, # '€' - 165: 253, # '₯' - 166: 253, # '¦' - 167: 253, # '§' - 168: 253, # '¨' - 169: 253, # '©' - 170: 253, # 'ͺ' - 171: 253, # '«' - 172: 253, # '¬' - 173: 74, # '\xad' - 174: 253, # None - 175: 253, # '―' - 176: 253, # '°' - 177: 253, # '±' - 178: 253, # '²' - 179: 253, # '³' - 180: 247, # '΄' - 181: 248, # '΅' - 182: 61, # 'Ά' - 183: 36, # '·' - 184: 46, # 'Έ' - 185: 71, # 'Ή' - 186: 73, # 'Ί' - 187: 253, # '»' - 188: 54, # 'Ό' - 189: 253, # '½' - 190: 108, # 'Ύ' - 191: 123, # 'Ώ' - 192: 110, # 'ΐ' - 193: 31, # 'Α' - 194: 51, # 'Β' - 195: 43, # 'Γ' - 196: 41, # 'Δ' - 197: 34, # 'Ε' - 198: 91, # 'Ζ' - 199: 40, # 'Η' - 200: 52, # 'Θ' - 201: 47, # 'Ι' - 202: 44, # 'Κ' - 203: 53, # 'Λ' - 204: 38, # 'Μ' - 205: 49, # 'Ν' - 206: 59, # 'Ξ' - 207: 39, # 'Ο' - 208: 35, # 'Π' - 209: 48, # 'Ρ' - 210: 250, # None - 211: 37, # 'Σ' - 212: 33, # 'Τ' - 213: 45, # 'Υ' - 214: 56, # 'Φ' - 215: 50, # 'Χ' - 216: 84, # 'Ψ' - 217: 57, # 'Ω' - 218: 120, # 'Ϊ' - 219: 121, # 'Ϋ' - 220: 17, # 'ά' - 221: 18, # 'έ' - 222: 22, # 'ή' - 223: 15, # 'ί' - 224: 124, # 'ΰ' - 225: 1, # 'α' - 226: 29, # 'β' - 227: 20, # 'γ' - 228: 21, # 'δ' - 229: 3, # 'ε' - 230: 32, # 'ζ' - 231: 13, # 'η' - 232: 25, # 'θ' - 233: 5, # 'ι' - 234: 11, # 'κ' - 235: 16, # 'λ' - 236: 10, # 'μ' - 237: 6, # 'ν' - 238: 30, # 'ξ' - 239: 4, # 'ο' - 240: 9, # 'π' - 241: 8, # 'ρ' - 242: 14, # 'ς' - 243: 7, # 'σ' - 244: 2, # 'τ' - 245: 12, # 'υ' - 246: 28, # 'φ' - 247: 23, # 'χ' - 248: 42, # 'ψ' - 249: 24, # 'ω' - 250: 64, # 'ϊ' - 251: 75, # 'ϋ' - 252: 19, # 'ό' - 253: 26, # 'ύ' - 254: 27, # 'ώ' - 255: 253, # None -} - -ISO_8859_7_GREEK_MODEL = SingleByteCharSetModel(charset_name='ISO-8859-7', - language='Greek', - char_to_order_map=ISO_8859_7_GREEK_CHAR_TO_ORDER, - language_model=GREEK_LANG_MODEL, - typical_positive_ratio=0.982851, - keep_ascii_letters=False, - alphabet='ΆΈΉΊΌΎΏΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩάέήίαβγδεζηθικλμνξοπρςστυφχψωόύώ') - diff --git a/venv/lib/python3.8/site-packages/chardet/langhebrewmodel.py b/venv/lib/python3.8/site-packages/chardet/langhebrewmodel.py deleted file mode 100644 index 40fd674..0000000 --- a/venv/lib/python3.8/site-packages/chardet/langhebrewmodel.py +++ /dev/null @@ -1,4383 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from chardet.sbcharsetprober import SingleByteCharSetModel - - -# 3: Positive -# 2: Likely -# 1: Unlikely -# 0: Negative - -HEBREW_LANG_MODEL = { - 50: { # 'a' - 50: 0, # 'a' - 60: 1, # 'c' - 61: 1, # 'd' - 42: 1, # 'e' - 53: 1, # 'i' - 56: 2, # 'l' - 54: 2, # 'n' - 49: 0, # 'o' - 51: 2, # 'r' - 43: 1, # 's' - 44: 2, # 't' - 63: 1, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 0, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 1, # 'ה' - 2: 0, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 0, # 'י' - 25: 0, # 'ך' - 15: 0, # 'כ' - 4: 0, # 'ל' - 11: 0, # 'ם' - 6: 1, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 1, # 'ק' - 7: 0, # 'ר' - 10: 1, # 'ש' - 5: 0, # 'ת' - 32: 0, # '–' - 52: 1, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 60: { # 'c' - 50: 1, # 'a' - 60: 1, # 'c' - 61: 0, # 'd' - 42: 1, # 'e' - 53: 1, # 'i' - 56: 1, # 'l' - 54: 0, # 'n' - 49: 1, # 'o' - 51: 1, # 'r' - 43: 1, # 's' - 44: 2, # 't' - 63: 1, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 1, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 1, # 'ה' - 2: 0, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 0, # 'י' - 25: 0, # 'ך' - 15: 0, # 'כ' - 4: 0, # 'ל' - 11: 0, # 'ם' - 6: 1, # 'מ' - 23: 0, # 'ן' - 12: 1, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 0, # 'ר' - 10: 0, # 'ש' - 5: 0, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 61: { # 'd' - 50: 1, # 'a' - 60: 0, # 'c' - 61: 1, # 'd' - 42: 1, # 'e' - 53: 1, # 'i' - 56: 1, # 'l' - 54: 1, # 'n' - 49: 2, # 'o' - 51: 1, # 'r' - 43: 1, # 's' - 44: 0, # 't' - 63: 1, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 0, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 1, # 'ה' - 2: 0, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 0, # 'י' - 25: 0, # 'ך' - 15: 0, # 'כ' - 4: 0, # 'ל' - 11: 0, # 'ם' - 6: 0, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 0, # 'ר' - 10: 0, # 'ש' - 5: 0, # 'ת' - 32: 1, # '–' - 52: 1, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 42: { # 'e' - 50: 1, # 'a' - 60: 1, # 'c' - 61: 2, # 'd' - 42: 1, # 'e' - 53: 1, # 'i' - 56: 2, # 'l' - 54: 2, # 'n' - 49: 1, # 'o' - 51: 2, # 'r' - 43: 2, # 's' - 44: 2, # 't' - 63: 1, # 'u' - 34: 1, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 0, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 0, # 'ה' - 2: 0, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 0, # 'י' - 25: 0, # 'ך' - 15: 0, # 'כ' - 4: 0, # 'ל' - 11: 0, # 'ם' - 6: 0, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 1, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 0, # 'ר' - 10: 0, # 'ש' - 5: 0, # 'ת' - 32: 1, # '–' - 52: 2, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 53: { # 'i' - 50: 1, # 'a' - 60: 2, # 'c' - 61: 1, # 'd' - 42: 1, # 'e' - 53: 0, # 'i' - 56: 1, # 'l' - 54: 2, # 'n' - 49: 2, # 'o' - 51: 1, # 'r' - 43: 2, # 's' - 44: 2, # 't' - 63: 1, # 'u' - 34: 0, # '\xa0' - 55: 1, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 0, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 0, # 'ה' - 2: 0, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 0, # 'י' - 25: 0, # 'ך' - 15: 0, # 'כ' - 4: 0, # 'ל' - 11: 0, # 'ם' - 6: 0, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 0, # 'ר' - 10: 0, # 'ש' - 5: 0, # 'ת' - 32: 0, # '–' - 52: 1, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 56: { # 'l' - 50: 1, # 'a' - 60: 1, # 'c' - 61: 1, # 'd' - 42: 2, # 'e' - 53: 2, # 'i' - 56: 2, # 'l' - 54: 1, # 'n' - 49: 1, # 'o' - 51: 0, # 'r' - 43: 1, # 's' - 44: 1, # 't' - 63: 1, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 0, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 0, # 'ה' - 2: 0, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 0, # 'י' - 25: 0, # 'ך' - 15: 0, # 'כ' - 4: 0, # 'ל' - 11: 0, # 'ם' - 6: 0, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 0, # 'ר' - 10: 0, # 'ש' - 5: 0, # 'ת' - 32: 0, # '–' - 52: 1, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 54: { # 'n' - 50: 1, # 'a' - 60: 1, # 'c' - 61: 1, # 'd' - 42: 1, # 'e' - 53: 1, # 'i' - 56: 1, # 'l' - 54: 1, # 'n' - 49: 1, # 'o' - 51: 0, # 'r' - 43: 1, # 's' - 44: 2, # 't' - 63: 1, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 0, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 1, # 'ה' - 2: 0, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 0, # 'י' - 25: 0, # 'ך' - 15: 0, # 'כ' - 4: 0, # 'ל' - 11: 0, # 'ם' - 6: 0, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 0, # 'ר' - 10: 0, # 'ש' - 5: 0, # 'ת' - 32: 0, # '–' - 52: 2, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 49: { # 'o' - 50: 1, # 'a' - 60: 1, # 'c' - 61: 1, # 'd' - 42: 1, # 'e' - 53: 1, # 'i' - 56: 1, # 'l' - 54: 2, # 'n' - 49: 1, # 'o' - 51: 2, # 'r' - 43: 1, # 's' - 44: 1, # 't' - 63: 1, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 0, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 0, # 'ה' - 2: 0, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 0, # 'י' - 25: 0, # 'ך' - 15: 0, # 'כ' - 4: 0, # 'ל' - 11: 0, # 'ם' - 6: 0, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 0, # 'ר' - 10: 0, # 'ש' - 5: 0, # 'ת' - 32: 0, # '–' - 52: 1, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 51: { # 'r' - 50: 2, # 'a' - 60: 1, # 'c' - 61: 1, # 'd' - 42: 2, # 'e' - 53: 1, # 'i' - 56: 1, # 'l' - 54: 1, # 'n' - 49: 2, # 'o' - 51: 1, # 'r' - 43: 1, # 's' - 44: 1, # 't' - 63: 1, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 0, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 0, # 'ה' - 2: 0, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 0, # 'י' - 25: 0, # 'ך' - 15: 0, # 'כ' - 4: 0, # 'ל' - 11: 0, # 'ם' - 6: 0, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 0, # 'ר' - 10: 0, # 'ש' - 5: 0, # 'ת' - 32: 0, # '–' - 52: 2, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 43: { # 's' - 50: 1, # 'a' - 60: 1, # 'c' - 61: 0, # 'd' - 42: 2, # 'e' - 53: 1, # 'i' - 56: 1, # 'l' - 54: 1, # 'n' - 49: 1, # 'o' - 51: 1, # 'r' - 43: 1, # 's' - 44: 2, # 't' - 63: 1, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 0, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 0, # 'ה' - 2: 0, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 0, # 'י' - 25: 0, # 'ך' - 15: 0, # 'כ' - 4: 0, # 'ל' - 11: 0, # 'ם' - 6: 0, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 0, # 'ר' - 10: 0, # 'ש' - 5: 0, # 'ת' - 32: 0, # '–' - 52: 1, # '’' - 47: 0, # '“' - 46: 2, # '”' - 58: 0, # '†' - 40: 2, # '…' - }, - 44: { # 't' - 50: 1, # 'a' - 60: 1, # 'c' - 61: 0, # 'd' - 42: 2, # 'e' - 53: 2, # 'i' - 56: 1, # 'l' - 54: 0, # 'n' - 49: 1, # 'o' - 51: 1, # 'r' - 43: 1, # 's' - 44: 1, # 't' - 63: 1, # 'u' - 34: 1, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 0, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 0, # 'ה' - 2: 0, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 0, # 'י' - 25: 0, # 'ך' - 15: 0, # 'כ' - 4: 0, # 'ל' - 11: 0, # 'ם' - 6: 0, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 0, # 'ר' - 10: 0, # 'ש' - 5: 0, # 'ת' - 32: 0, # '–' - 52: 2, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 63: { # 'u' - 50: 1, # 'a' - 60: 1, # 'c' - 61: 1, # 'd' - 42: 1, # 'e' - 53: 1, # 'i' - 56: 1, # 'l' - 54: 1, # 'n' - 49: 0, # 'o' - 51: 1, # 'r' - 43: 2, # 's' - 44: 1, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 0, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 0, # 'ה' - 2: 0, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 0, # 'י' - 25: 0, # 'ך' - 15: 0, # 'כ' - 4: 0, # 'ל' - 11: 0, # 'ם' - 6: 0, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 0, # 'ר' - 10: 0, # 'ש' - 5: 0, # 'ת' - 32: 0, # '–' - 52: 1, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 34: { # '\xa0' - 50: 1, # 'a' - 60: 0, # 'c' - 61: 1, # 'd' - 42: 0, # 'e' - 53: 1, # 'i' - 56: 0, # 'l' - 54: 1, # 'n' - 49: 1, # 'o' - 51: 0, # 'r' - 43: 1, # 's' - 44: 1, # 't' - 63: 0, # 'u' - 34: 2, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 2, # 'א' - 8: 1, # 'ב' - 20: 1, # 'ג' - 16: 1, # 'ד' - 3: 1, # 'ה' - 2: 1, # 'ו' - 24: 1, # 'ז' - 14: 1, # 'ח' - 22: 1, # 'ט' - 1: 2, # 'י' - 25: 0, # 'ך' - 15: 1, # 'כ' - 4: 1, # 'ל' - 11: 0, # 'ם' - 6: 2, # 'מ' - 23: 0, # 'ן' - 12: 1, # 'נ' - 19: 1, # 'ס' - 13: 1, # 'ע' - 26: 0, # 'ף' - 18: 1, # 'פ' - 27: 0, # 'ץ' - 21: 1, # 'צ' - 17: 1, # 'ק' - 7: 1, # 'ר' - 10: 1, # 'ש' - 5: 1, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 55: { # '´' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 1, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 1, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 1, # 'ה' - 2: 1, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 2, # 'י' - 25: 0, # 'ך' - 15: 0, # 'כ' - 4: 1, # 'ל' - 11: 0, # 'ם' - 6: 1, # 'מ' - 23: 1, # 'ן' - 12: 1, # 'נ' - 19: 1, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 1, # 'ר' - 10: 1, # 'ש' - 5: 0, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 48: { # '¼' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 1, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 0, # 'ה' - 2: 1, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 0, # 'י' - 25: 0, # 'ך' - 15: 1, # 'כ' - 4: 1, # 'ל' - 11: 0, # 'ם' - 6: 1, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 0, # 'ר' - 10: 0, # 'ש' - 5: 0, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 39: { # '½' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 0, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 0, # 'ה' - 2: 0, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 0, # 'י' - 25: 0, # 'ך' - 15: 1, # 'כ' - 4: 1, # 'ל' - 11: 0, # 'ם' - 6: 0, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 1, # 'צ' - 17: 1, # 'ק' - 7: 0, # 'ר' - 10: 0, # 'ש' - 5: 0, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 57: { # '¾' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 0, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 0, # 'ה' - 2: 0, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 0, # 'י' - 25: 0, # 'ך' - 15: 0, # 'כ' - 4: 0, # 'ל' - 11: 0, # 'ם' - 6: 0, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 0, # 'ר' - 10: 0, # 'ש' - 5: 0, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 30: { # 'ְ' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 1, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 1, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 2, # 'א' - 8: 2, # 'ב' - 20: 2, # 'ג' - 16: 2, # 'ד' - 3: 2, # 'ה' - 2: 2, # 'ו' - 24: 2, # 'ז' - 14: 2, # 'ח' - 22: 2, # 'ט' - 1: 2, # 'י' - 25: 2, # 'ך' - 15: 2, # 'כ' - 4: 2, # 'ל' - 11: 1, # 'ם' - 6: 2, # 'מ' - 23: 0, # 'ן' - 12: 2, # 'נ' - 19: 2, # 'ס' - 13: 2, # 'ע' - 26: 0, # 'ף' - 18: 2, # 'פ' - 27: 0, # 'ץ' - 21: 2, # 'צ' - 17: 2, # 'ק' - 7: 2, # 'ר' - 10: 2, # 'ש' - 5: 2, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 59: { # 'ֱ' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 1, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 0, # 'א' - 8: 1, # 'ב' - 20: 1, # 'ג' - 16: 0, # 'ד' - 3: 0, # 'ה' - 2: 0, # 'ו' - 24: 1, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 1, # 'י' - 25: 0, # 'ך' - 15: 1, # 'כ' - 4: 2, # 'ל' - 11: 0, # 'ם' - 6: 2, # 'מ' - 23: 0, # 'ן' - 12: 1, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 1, # 'ר' - 10: 1, # 'ש' - 5: 0, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 41: { # 'ֲ' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 0, # 'א' - 8: 2, # 'ב' - 20: 1, # 'ג' - 16: 2, # 'ד' - 3: 1, # 'ה' - 2: 1, # 'ו' - 24: 1, # 'ז' - 14: 1, # 'ח' - 22: 1, # 'ט' - 1: 1, # 'י' - 25: 1, # 'ך' - 15: 1, # 'כ' - 4: 2, # 'ל' - 11: 0, # 'ם' - 6: 2, # 'מ' - 23: 0, # 'ן' - 12: 2, # 'נ' - 19: 1, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 1, # 'פ' - 27: 0, # 'ץ' - 21: 2, # 'צ' - 17: 1, # 'ק' - 7: 2, # 'ר' - 10: 2, # 'ש' - 5: 1, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 33: { # 'ִ' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 1, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 1, # 'ִ' - 37: 0, # 'ֵ' - 36: 1, # 'ֶ' - 31: 0, # 'ַ' - 29: 1, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 1, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 1, # 'א' - 8: 2, # 'ב' - 20: 2, # 'ג' - 16: 2, # 'ד' - 3: 1, # 'ה' - 2: 1, # 'ו' - 24: 2, # 'ז' - 14: 1, # 'ח' - 22: 1, # 'ט' - 1: 3, # 'י' - 25: 1, # 'ך' - 15: 2, # 'כ' - 4: 2, # 'ל' - 11: 2, # 'ם' - 6: 2, # 'מ' - 23: 2, # 'ן' - 12: 2, # 'נ' - 19: 2, # 'ס' - 13: 1, # 'ע' - 26: 0, # 'ף' - 18: 2, # 'פ' - 27: 1, # 'ץ' - 21: 2, # 'צ' - 17: 2, # 'ק' - 7: 2, # 'ר' - 10: 2, # 'ש' - 5: 2, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 37: { # 'ֵ' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 1, # 'ֶ' - 31: 1, # 'ַ' - 29: 1, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 2, # 'א' - 8: 2, # 'ב' - 20: 1, # 'ג' - 16: 2, # 'ד' - 3: 2, # 'ה' - 2: 1, # 'ו' - 24: 1, # 'ז' - 14: 2, # 'ח' - 22: 1, # 'ט' - 1: 3, # 'י' - 25: 2, # 'ך' - 15: 1, # 'כ' - 4: 2, # 'ל' - 11: 2, # 'ם' - 6: 1, # 'מ' - 23: 2, # 'ן' - 12: 2, # 'נ' - 19: 1, # 'ס' - 13: 2, # 'ע' - 26: 1, # 'ף' - 18: 1, # 'פ' - 27: 1, # 'ץ' - 21: 1, # 'צ' - 17: 1, # 'ק' - 7: 2, # 'ר' - 10: 2, # 'ש' - 5: 2, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 36: { # 'ֶ' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 1, # 'ֶ' - 31: 1, # 'ַ' - 29: 1, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 2, # 'א' - 8: 2, # 'ב' - 20: 1, # 'ג' - 16: 2, # 'ד' - 3: 2, # 'ה' - 2: 1, # 'ו' - 24: 1, # 'ז' - 14: 2, # 'ח' - 22: 1, # 'ט' - 1: 2, # 'י' - 25: 2, # 'ך' - 15: 1, # 'כ' - 4: 2, # 'ל' - 11: 2, # 'ם' - 6: 2, # 'מ' - 23: 2, # 'ן' - 12: 2, # 'נ' - 19: 2, # 'ס' - 13: 1, # 'ע' - 26: 1, # 'ף' - 18: 1, # 'פ' - 27: 2, # 'ץ' - 21: 1, # 'צ' - 17: 1, # 'ק' - 7: 2, # 'ר' - 10: 2, # 'ש' - 5: 2, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 31: { # 'ַ' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 1, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 1, # 'ֶ' - 31: 0, # 'ַ' - 29: 2, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 2, # 'א' - 8: 2, # 'ב' - 20: 2, # 'ג' - 16: 2, # 'ד' - 3: 2, # 'ה' - 2: 1, # 'ו' - 24: 2, # 'ז' - 14: 2, # 'ח' - 22: 2, # 'ט' - 1: 3, # 'י' - 25: 1, # 'ך' - 15: 2, # 'כ' - 4: 2, # 'ל' - 11: 2, # 'ם' - 6: 2, # 'מ' - 23: 2, # 'ן' - 12: 2, # 'נ' - 19: 2, # 'ס' - 13: 2, # 'ע' - 26: 2, # 'ף' - 18: 2, # 'פ' - 27: 1, # 'ץ' - 21: 2, # 'צ' - 17: 2, # 'ק' - 7: 2, # 'ר' - 10: 2, # 'ש' - 5: 2, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 29: { # 'ָ' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 1, # 'ַ' - 29: 2, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 1, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 2, # 'א' - 8: 2, # 'ב' - 20: 2, # 'ג' - 16: 2, # 'ד' - 3: 3, # 'ה' - 2: 2, # 'ו' - 24: 2, # 'ז' - 14: 2, # 'ח' - 22: 1, # 'ט' - 1: 2, # 'י' - 25: 2, # 'ך' - 15: 2, # 'כ' - 4: 2, # 'ל' - 11: 2, # 'ם' - 6: 2, # 'מ' - 23: 2, # 'ן' - 12: 2, # 'נ' - 19: 1, # 'ס' - 13: 2, # 'ע' - 26: 1, # 'ף' - 18: 2, # 'פ' - 27: 1, # 'ץ' - 21: 2, # 'צ' - 17: 2, # 'ק' - 7: 2, # 'ר' - 10: 2, # 'ש' - 5: 2, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 35: { # 'ֹ' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 1, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 2, # 'א' - 8: 2, # 'ב' - 20: 1, # 'ג' - 16: 2, # 'ד' - 3: 2, # 'ה' - 2: 1, # 'ו' - 24: 1, # 'ז' - 14: 1, # 'ח' - 22: 1, # 'ט' - 1: 1, # 'י' - 25: 1, # 'ך' - 15: 2, # 'כ' - 4: 2, # 'ל' - 11: 2, # 'ם' - 6: 2, # 'מ' - 23: 2, # 'ן' - 12: 2, # 'נ' - 19: 2, # 'ס' - 13: 2, # 'ע' - 26: 1, # 'ף' - 18: 2, # 'פ' - 27: 1, # 'ץ' - 21: 2, # 'צ' - 17: 2, # 'ק' - 7: 2, # 'ר' - 10: 2, # 'ש' - 5: 2, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 62: { # 'ֻ' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 0, # 'א' - 8: 1, # 'ב' - 20: 1, # 'ג' - 16: 1, # 'ד' - 3: 1, # 'ה' - 2: 1, # 'ו' - 24: 1, # 'ז' - 14: 1, # 'ח' - 22: 0, # 'ט' - 1: 1, # 'י' - 25: 0, # 'ך' - 15: 1, # 'כ' - 4: 2, # 'ל' - 11: 1, # 'ם' - 6: 1, # 'מ' - 23: 1, # 'ן' - 12: 1, # 'נ' - 19: 1, # 'ס' - 13: 1, # 'ע' - 26: 0, # 'ף' - 18: 1, # 'פ' - 27: 0, # 'ץ' - 21: 1, # 'צ' - 17: 1, # 'ק' - 7: 1, # 'ר' - 10: 1, # 'ש' - 5: 1, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 28: { # 'ּ' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 3, # 'ְ' - 59: 0, # 'ֱ' - 41: 1, # 'ֲ' - 33: 3, # 'ִ' - 37: 2, # 'ֵ' - 36: 2, # 'ֶ' - 31: 3, # 'ַ' - 29: 3, # 'ָ' - 35: 2, # 'ֹ' - 62: 1, # 'ֻ' - 28: 0, # 'ּ' - 38: 2, # 'ׁ' - 45: 1, # 'ׂ' - 9: 2, # 'א' - 8: 2, # 'ב' - 20: 1, # 'ג' - 16: 2, # 'ד' - 3: 1, # 'ה' - 2: 2, # 'ו' - 24: 1, # 'ז' - 14: 1, # 'ח' - 22: 1, # 'ט' - 1: 2, # 'י' - 25: 2, # 'ך' - 15: 2, # 'כ' - 4: 2, # 'ל' - 11: 1, # 'ם' - 6: 2, # 'מ' - 23: 1, # 'ן' - 12: 2, # 'נ' - 19: 1, # 'ס' - 13: 2, # 'ע' - 26: 1, # 'ף' - 18: 1, # 'פ' - 27: 1, # 'ץ' - 21: 1, # 'צ' - 17: 1, # 'ק' - 7: 2, # 'ר' - 10: 2, # 'ש' - 5: 2, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 38: { # 'ׁ' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 2, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 2, # 'ִ' - 37: 2, # 'ֵ' - 36: 2, # 'ֶ' - 31: 2, # 'ַ' - 29: 2, # 'ָ' - 35: 1, # 'ֹ' - 62: 1, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 0, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 0, # 'ה' - 2: 2, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 1, # 'י' - 25: 0, # 'ך' - 15: 0, # 'כ' - 4: 0, # 'ל' - 11: 0, # 'ם' - 6: 0, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 0, # 'ס' - 13: 1, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 0, # 'ר' - 10: 0, # 'ש' - 5: 0, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 45: { # 'ׂ' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 2, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 2, # 'ִ' - 37: 1, # 'ֵ' - 36: 2, # 'ֶ' - 31: 1, # 'ַ' - 29: 2, # 'ָ' - 35: 1, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 1, # 'א' - 8: 0, # 'ב' - 20: 1, # 'ג' - 16: 0, # 'ד' - 3: 1, # 'ה' - 2: 2, # 'ו' - 24: 0, # 'ז' - 14: 1, # 'ח' - 22: 0, # 'ט' - 1: 1, # 'י' - 25: 0, # 'ך' - 15: 0, # 'כ' - 4: 0, # 'ל' - 11: 1, # 'ם' - 6: 1, # 'מ' - 23: 0, # 'ן' - 12: 1, # 'נ' - 19: 0, # 'ס' - 13: 1, # 'ע' - 26: 0, # 'ף' - 18: 1, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 1, # 'ר' - 10: 0, # 'ש' - 5: 1, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 9: { # 'א' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 1, # '\xa0' - 55: 1, # '´' - 48: 1, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 2, # 'ֱ' - 41: 2, # 'ֲ' - 33: 2, # 'ִ' - 37: 2, # 'ֵ' - 36: 2, # 'ֶ' - 31: 2, # 'ַ' - 29: 2, # 'ָ' - 35: 2, # 'ֹ' - 62: 1, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 2, # 'א' - 8: 3, # 'ב' - 20: 3, # 'ג' - 16: 3, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 3, # 'ז' - 14: 3, # 'ח' - 22: 3, # 'ט' - 1: 3, # 'י' - 25: 3, # 'ך' - 15: 3, # 'כ' - 4: 3, # 'ל' - 11: 3, # 'ם' - 6: 3, # 'מ' - 23: 3, # 'ן' - 12: 3, # 'נ' - 19: 3, # 'ס' - 13: 2, # 'ע' - 26: 3, # 'ף' - 18: 3, # 'פ' - 27: 1, # 'ץ' - 21: 3, # 'צ' - 17: 3, # 'ק' - 7: 3, # 'ר' - 10: 3, # 'ש' - 5: 3, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 8: { # 'ב' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 1, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 1, # '\xa0' - 55: 1, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 2, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 2, # 'ִ' - 37: 2, # 'ֵ' - 36: 2, # 'ֶ' - 31: 2, # 'ַ' - 29: 2, # 'ָ' - 35: 2, # 'ֹ' - 62: 1, # 'ֻ' - 28: 3, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 3, # 'א' - 8: 3, # 'ב' - 20: 3, # 'ג' - 16: 3, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 3, # 'ז' - 14: 3, # 'ח' - 22: 3, # 'ט' - 1: 3, # 'י' - 25: 2, # 'ך' - 15: 3, # 'כ' - 4: 3, # 'ל' - 11: 2, # 'ם' - 6: 3, # 'מ' - 23: 3, # 'ן' - 12: 3, # 'נ' - 19: 3, # 'ס' - 13: 3, # 'ע' - 26: 1, # 'ף' - 18: 3, # 'פ' - 27: 2, # 'ץ' - 21: 3, # 'צ' - 17: 3, # 'ק' - 7: 3, # 'ר' - 10: 3, # 'ש' - 5: 3, # 'ת' - 32: 1, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 20: { # 'ג' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 1, # '\xa0' - 55: 2, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 2, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 1, # 'ִ' - 37: 1, # 'ֵ' - 36: 1, # 'ֶ' - 31: 2, # 'ַ' - 29: 2, # 'ָ' - 35: 1, # 'ֹ' - 62: 0, # 'ֻ' - 28: 2, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 2, # 'א' - 8: 3, # 'ב' - 20: 2, # 'ג' - 16: 3, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 3, # 'ז' - 14: 2, # 'ח' - 22: 2, # 'ט' - 1: 3, # 'י' - 25: 1, # 'ך' - 15: 1, # 'כ' - 4: 3, # 'ל' - 11: 3, # 'ם' - 6: 3, # 'מ' - 23: 3, # 'ן' - 12: 3, # 'נ' - 19: 2, # 'ס' - 13: 3, # 'ע' - 26: 2, # 'ף' - 18: 2, # 'פ' - 27: 1, # 'ץ' - 21: 1, # 'צ' - 17: 1, # 'ק' - 7: 3, # 'ר' - 10: 3, # 'ש' - 5: 3, # 'ת' - 32: 0, # '–' - 52: 1, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 16: { # 'ד' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 2, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 2, # 'ִ' - 37: 2, # 'ֵ' - 36: 2, # 'ֶ' - 31: 2, # 'ַ' - 29: 2, # 'ָ' - 35: 2, # 'ֹ' - 62: 1, # 'ֻ' - 28: 2, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 3, # 'א' - 8: 3, # 'ב' - 20: 3, # 'ג' - 16: 3, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 1, # 'ז' - 14: 2, # 'ח' - 22: 2, # 'ט' - 1: 3, # 'י' - 25: 2, # 'ך' - 15: 2, # 'כ' - 4: 3, # 'ל' - 11: 3, # 'ם' - 6: 3, # 'מ' - 23: 2, # 'ן' - 12: 3, # 'נ' - 19: 2, # 'ס' - 13: 3, # 'ע' - 26: 2, # 'ף' - 18: 3, # 'פ' - 27: 0, # 'ץ' - 21: 2, # 'צ' - 17: 3, # 'ק' - 7: 3, # 'ר' - 10: 3, # 'ש' - 5: 3, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 3: { # 'ה' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 1, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 1, # '\xa0' - 55: 0, # '´' - 48: 1, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 1, # 'ְ' - 59: 1, # 'ֱ' - 41: 2, # 'ֲ' - 33: 2, # 'ִ' - 37: 2, # 'ֵ' - 36: 2, # 'ֶ' - 31: 3, # 'ַ' - 29: 2, # 'ָ' - 35: 1, # 'ֹ' - 62: 1, # 'ֻ' - 28: 2, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 3, # 'א' - 8: 3, # 'ב' - 20: 3, # 'ג' - 16: 3, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 3, # 'ז' - 14: 3, # 'ח' - 22: 3, # 'ט' - 1: 3, # 'י' - 25: 1, # 'ך' - 15: 3, # 'כ' - 4: 3, # 'ל' - 11: 3, # 'ם' - 6: 3, # 'מ' - 23: 3, # 'ן' - 12: 3, # 'נ' - 19: 3, # 'ס' - 13: 3, # 'ע' - 26: 0, # 'ף' - 18: 3, # 'פ' - 27: 1, # 'ץ' - 21: 3, # 'צ' - 17: 3, # 'ק' - 7: 3, # 'ר' - 10: 3, # 'ש' - 5: 3, # 'ת' - 32: 1, # '–' - 52: 1, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 2, # '…' - }, - 2: { # 'ו' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 1, # 't' - 63: 0, # 'u' - 34: 1, # '\xa0' - 55: 1, # '´' - 48: 1, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 2, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 2, # 'ִ' - 37: 1, # 'ֵ' - 36: 1, # 'ֶ' - 31: 2, # 'ַ' - 29: 2, # 'ָ' - 35: 3, # 'ֹ' - 62: 0, # 'ֻ' - 28: 3, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 3, # 'א' - 8: 3, # 'ב' - 20: 3, # 'ג' - 16: 3, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 3, # 'ז' - 14: 3, # 'ח' - 22: 3, # 'ט' - 1: 3, # 'י' - 25: 3, # 'ך' - 15: 3, # 'כ' - 4: 3, # 'ל' - 11: 3, # 'ם' - 6: 3, # 'מ' - 23: 3, # 'ן' - 12: 3, # 'נ' - 19: 3, # 'ס' - 13: 3, # 'ע' - 26: 3, # 'ף' - 18: 3, # 'פ' - 27: 3, # 'ץ' - 21: 3, # 'צ' - 17: 3, # 'ק' - 7: 3, # 'ר' - 10: 3, # 'ש' - 5: 3, # 'ת' - 32: 1, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 2, # '…' - }, - 24: { # 'ז' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 1, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 2, # 'ְ' - 59: 0, # 'ֱ' - 41: 1, # 'ֲ' - 33: 1, # 'ִ' - 37: 2, # 'ֵ' - 36: 2, # 'ֶ' - 31: 2, # 'ַ' - 29: 2, # 'ָ' - 35: 1, # 'ֹ' - 62: 1, # 'ֻ' - 28: 2, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 3, # 'א' - 8: 2, # 'ב' - 20: 2, # 'ג' - 16: 2, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 2, # 'ז' - 14: 2, # 'ח' - 22: 1, # 'ט' - 1: 3, # 'י' - 25: 1, # 'ך' - 15: 3, # 'כ' - 4: 3, # 'ל' - 11: 2, # 'ם' - 6: 3, # 'מ' - 23: 2, # 'ן' - 12: 2, # 'נ' - 19: 1, # 'ס' - 13: 2, # 'ע' - 26: 1, # 'ף' - 18: 1, # 'פ' - 27: 0, # 'ץ' - 21: 2, # 'צ' - 17: 3, # 'ק' - 7: 3, # 'ר' - 10: 1, # 'ש' - 5: 2, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 14: { # 'ח' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 1, # '\xa0' - 55: 1, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 2, # 'ְ' - 59: 1, # 'ֱ' - 41: 2, # 'ֲ' - 33: 2, # 'ִ' - 37: 2, # 'ֵ' - 36: 2, # 'ֶ' - 31: 2, # 'ַ' - 29: 2, # 'ָ' - 35: 2, # 'ֹ' - 62: 1, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 2, # 'א' - 8: 3, # 'ב' - 20: 2, # 'ג' - 16: 3, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 3, # 'ז' - 14: 2, # 'ח' - 22: 2, # 'ט' - 1: 3, # 'י' - 25: 1, # 'ך' - 15: 2, # 'כ' - 4: 3, # 'ל' - 11: 3, # 'ם' - 6: 3, # 'מ' - 23: 2, # 'ן' - 12: 3, # 'נ' - 19: 3, # 'ס' - 13: 1, # 'ע' - 26: 2, # 'ף' - 18: 2, # 'פ' - 27: 2, # 'ץ' - 21: 3, # 'צ' - 17: 3, # 'ק' - 7: 3, # 'ר' - 10: 3, # 'ש' - 5: 3, # 'ת' - 32: 0, # '–' - 52: 1, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 22: { # 'ט' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 1, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 2, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 2, # 'ִ' - 37: 1, # 'ֵ' - 36: 1, # 'ֶ' - 31: 2, # 'ַ' - 29: 1, # 'ָ' - 35: 1, # 'ֹ' - 62: 1, # 'ֻ' - 28: 1, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 3, # 'א' - 8: 3, # 'ב' - 20: 3, # 'ג' - 16: 1, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 2, # 'ז' - 14: 3, # 'ח' - 22: 2, # 'ט' - 1: 3, # 'י' - 25: 1, # 'ך' - 15: 2, # 'כ' - 4: 3, # 'ל' - 11: 2, # 'ם' - 6: 2, # 'מ' - 23: 2, # 'ן' - 12: 3, # 'נ' - 19: 2, # 'ס' - 13: 3, # 'ע' - 26: 2, # 'ף' - 18: 3, # 'פ' - 27: 1, # 'ץ' - 21: 2, # 'צ' - 17: 2, # 'ק' - 7: 3, # 'ר' - 10: 2, # 'ש' - 5: 3, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 1: { # 'י' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 1, # '\xa0' - 55: 1, # '´' - 48: 1, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 2, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 2, # 'ִ' - 37: 2, # 'ֵ' - 36: 1, # 'ֶ' - 31: 2, # 'ַ' - 29: 2, # 'ָ' - 35: 2, # 'ֹ' - 62: 1, # 'ֻ' - 28: 2, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 3, # 'א' - 8: 3, # 'ב' - 20: 3, # 'ג' - 16: 3, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 3, # 'ז' - 14: 3, # 'ח' - 22: 3, # 'ט' - 1: 3, # 'י' - 25: 3, # 'ך' - 15: 3, # 'כ' - 4: 3, # 'ל' - 11: 3, # 'ם' - 6: 3, # 'מ' - 23: 3, # 'ן' - 12: 3, # 'נ' - 19: 3, # 'ס' - 13: 3, # 'ע' - 26: 3, # 'ף' - 18: 3, # 'פ' - 27: 3, # 'ץ' - 21: 3, # 'צ' - 17: 3, # 'ק' - 7: 3, # 'ר' - 10: 3, # 'ש' - 5: 3, # 'ת' - 32: 1, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 2, # '…' - }, - 25: { # 'ך' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 2, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 2, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 1, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 1, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 1, # 'ה' - 2: 0, # 'ו' - 24: 0, # 'ז' - 14: 1, # 'ח' - 22: 0, # 'ט' - 1: 0, # 'י' - 25: 0, # 'ך' - 15: 0, # 'כ' - 4: 1, # 'ל' - 11: 0, # 'ם' - 6: 1, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 0, # 'ר' - 10: 1, # 'ש' - 5: 0, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 15: { # 'כ' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 2, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 2, # 'ִ' - 37: 2, # 'ֵ' - 36: 2, # 'ֶ' - 31: 2, # 'ַ' - 29: 2, # 'ָ' - 35: 1, # 'ֹ' - 62: 1, # 'ֻ' - 28: 3, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 3, # 'א' - 8: 3, # 'ב' - 20: 2, # 'ג' - 16: 3, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 3, # 'ז' - 14: 3, # 'ח' - 22: 2, # 'ט' - 1: 3, # 'י' - 25: 3, # 'ך' - 15: 3, # 'כ' - 4: 3, # 'ל' - 11: 3, # 'ם' - 6: 3, # 'מ' - 23: 3, # 'ן' - 12: 3, # 'נ' - 19: 3, # 'ס' - 13: 2, # 'ע' - 26: 3, # 'ף' - 18: 3, # 'פ' - 27: 1, # 'ץ' - 21: 2, # 'צ' - 17: 2, # 'ק' - 7: 3, # 'ר' - 10: 3, # 'ש' - 5: 3, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 4: { # 'ל' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 1, # '\xa0' - 55: 1, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 3, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 2, # 'ִ' - 37: 2, # 'ֵ' - 36: 2, # 'ֶ' - 31: 2, # 'ַ' - 29: 2, # 'ָ' - 35: 2, # 'ֹ' - 62: 1, # 'ֻ' - 28: 2, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 3, # 'א' - 8: 3, # 'ב' - 20: 3, # 'ג' - 16: 3, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 3, # 'ז' - 14: 3, # 'ח' - 22: 3, # 'ט' - 1: 3, # 'י' - 25: 3, # 'ך' - 15: 3, # 'כ' - 4: 3, # 'ל' - 11: 3, # 'ם' - 6: 3, # 'מ' - 23: 2, # 'ן' - 12: 3, # 'נ' - 19: 3, # 'ס' - 13: 3, # 'ע' - 26: 2, # 'ף' - 18: 3, # 'פ' - 27: 2, # 'ץ' - 21: 3, # 'צ' - 17: 3, # 'ק' - 7: 3, # 'ר' - 10: 3, # 'ש' - 5: 3, # 'ת' - 32: 1, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 11: { # 'ם' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 1, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 1, # 'א' - 8: 1, # 'ב' - 20: 1, # 'ג' - 16: 0, # 'ד' - 3: 1, # 'ה' - 2: 1, # 'ו' - 24: 1, # 'ז' - 14: 1, # 'ח' - 22: 0, # 'ט' - 1: 1, # 'י' - 25: 0, # 'ך' - 15: 1, # 'כ' - 4: 1, # 'ל' - 11: 1, # 'ם' - 6: 1, # 'מ' - 23: 0, # 'ן' - 12: 1, # 'נ' - 19: 0, # 'ס' - 13: 1, # 'ע' - 26: 0, # 'ף' - 18: 1, # 'פ' - 27: 1, # 'ץ' - 21: 1, # 'צ' - 17: 1, # 'ק' - 7: 1, # 'ר' - 10: 1, # 'ש' - 5: 1, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 2, # '…' - }, - 6: { # 'מ' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 1, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 2, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 2, # 'ִ' - 37: 2, # 'ֵ' - 36: 2, # 'ֶ' - 31: 2, # 'ַ' - 29: 2, # 'ָ' - 35: 2, # 'ֹ' - 62: 1, # 'ֻ' - 28: 2, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 3, # 'א' - 8: 3, # 'ב' - 20: 3, # 'ג' - 16: 3, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 3, # 'ז' - 14: 3, # 'ח' - 22: 3, # 'ט' - 1: 3, # 'י' - 25: 2, # 'ך' - 15: 3, # 'כ' - 4: 3, # 'ל' - 11: 3, # 'ם' - 6: 3, # 'מ' - 23: 3, # 'ן' - 12: 3, # 'נ' - 19: 3, # 'ס' - 13: 3, # 'ע' - 26: 0, # 'ף' - 18: 3, # 'פ' - 27: 2, # 'ץ' - 21: 3, # 'צ' - 17: 3, # 'ק' - 7: 3, # 'ר' - 10: 3, # 'ש' - 5: 3, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 23: { # 'ן' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 1, # '\xa0' - 55: 0, # '´' - 48: 1, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 1, # 'א' - 8: 1, # 'ב' - 20: 1, # 'ג' - 16: 1, # 'ד' - 3: 1, # 'ה' - 2: 1, # 'ו' - 24: 0, # 'ז' - 14: 1, # 'ח' - 22: 1, # 'ט' - 1: 1, # 'י' - 25: 0, # 'ך' - 15: 1, # 'כ' - 4: 1, # 'ל' - 11: 1, # 'ם' - 6: 1, # 'מ' - 23: 0, # 'ן' - 12: 1, # 'נ' - 19: 1, # 'ס' - 13: 1, # 'ע' - 26: 1, # 'ף' - 18: 1, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 1, # 'ק' - 7: 1, # 'ר' - 10: 1, # 'ש' - 5: 1, # 'ת' - 32: 1, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 2, # '…' - }, - 12: { # 'נ' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 2, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 2, # 'ִ' - 37: 2, # 'ֵ' - 36: 2, # 'ֶ' - 31: 2, # 'ַ' - 29: 2, # 'ָ' - 35: 1, # 'ֹ' - 62: 1, # 'ֻ' - 28: 2, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 3, # 'א' - 8: 3, # 'ב' - 20: 3, # 'ג' - 16: 3, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 3, # 'ז' - 14: 3, # 'ח' - 22: 3, # 'ט' - 1: 3, # 'י' - 25: 2, # 'ך' - 15: 3, # 'כ' - 4: 3, # 'ל' - 11: 3, # 'ם' - 6: 3, # 'מ' - 23: 3, # 'ן' - 12: 3, # 'נ' - 19: 3, # 'ס' - 13: 3, # 'ע' - 26: 2, # 'ף' - 18: 3, # 'פ' - 27: 2, # 'ץ' - 21: 3, # 'צ' - 17: 3, # 'ק' - 7: 3, # 'ר' - 10: 3, # 'ש' - 5: 3, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 19: { # 'ס' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 1, # '\xa0' - 55: 1, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 2, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 2, # 'ִ' - 37: 1, # 'ֵ' - 36: 2, # 'ֶ' - 31: 2, # 'ַ' - 29: 1, # 'ָ' - 35: 1, # 'ֹ' - 62: 2, # 'ֻ' - 28: 2, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 2, # 'א' - 8: 3, # 'ב' - 20: 3, # 'ג' - 16: 3, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 1, # 'ז' - 14: 3, # 'ח' - 22: 3, # 'ט' - 1: 3, # 'י' - 25: 2, # 'ך' - 15: 3, # 'כ' - 4: 3, # 'ל' - 11: 2, # 'ם' - 6: 3, # 'מ' - 23: 2, # 'ן' - 12: 3, # 'נ' - 19: 2, # 'ס' - 13: 3, # 'ע' - 26: 3, # 'ף' - 18: 3, # 'פ' - 27: 0, # 'ץ' - 21: 2, # 'צ' - 17: 3, # 'ק' - 7: 3, # 'ר' - 10: 1, # 'ש' - 5: 3, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 13: { # 'ע' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 1, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 1, # 'ְ' - 59: 1, # 'ֱ' - 41: 2, # 'ֲ' - 33: 2, # 'ִ' - 37: 2, # 'ֵ' - 36: 2, # 'ֶ' - 31: 2, # 'ַ' - 29: 2, # 'ָ' - 35: 2, # 'ֹ' - 62: 1, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 2, # 'א' - 8: 3, # 'ב' - 20: 3, # 'ג' - 16: 3, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 3, # 'ז' - 14: 1, # 'ח' - 22: 3, # 'ט' - 1: 3, # 'י' - 25: 2, # 'ך' - 15: 2, # 'כ' - 4: 3, # 'ל' - 11: 3, # 'ם' - 6: 3, # 'מ' - 23: 2, # 'ן' - 12: 3, # 'נ' - 19: 3, # 'ס' - 13: 2, # 'ע' - 26: 1, # 'ף' - 18: 2, # 'פ' - 27: 2, # 'ץ' - 21: 3, # 'צ' - 17: 3, # 'ק' - 7: 3, # 'ר' - 10: 3, # 'ש' - 5: 3, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 26: { # 'ף' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 1, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 0, # 'ה' - 2: 1, # 'ו' - 24: 0, # 'ז' - 14: 1, # 'ח' - 22: 0, # 'ט' - 1: 0, # 'י' - 25: 0, # 'ך' - 15: 1, # 'כ' - 4: 1, # 'ל' - 11: 0, # 'ם' - 6: 1, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 1, # 'ס' - 13: 0, # 'ע' - 26: 1, # 'ף' - 18: 1, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 1, # 'ק' - 7: 1, # 'ר' - 10: 1, # 'ש' - 5: 0, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 18: { # 'פ' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 1, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 2, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 2, # 'ִ' - 37: 1, # 'ֵ' - 36: 2, # 'ֶ' - 31: 1, # 'ַ' - 29: 2, # 'ָ' - 35: 1, # 'ֹ' - 62: 1, # 'ֻ' - 28: 2, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 3, # 'א' - 8: 2, # 'ב' - 20: 3, # 'ג' - 16: 2, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 2, # 'ז' - 14: 3, # 'ח' - 22: 3, # 'ט' - 1: 3, # 'י' - 25: 2, # 'ך' - 15: 3, # 'כ' - 4: 3, # 'ל' - 11: 2, # 'ם' - 6: 2, # 'מ' - 23: 3, # 'ן' - 12: 3, # 'נ' - 19: 3, # 'ס' - 13: 3, # 'ע' - 26: 2, # 'ף' - 18: 2, # 'פ' - 27: 2, # 'ץ' - 21: 3, # 'צ' - 17: 3, # 'ק' - 7: 3, # 'ר' - 10: 3, # 'ש' - 5: 3, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 27: { # 'ץ' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 1, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 1, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 0, # 'ה' - 2: 0, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 0, # 'י' - 25: 0, # 'ך' - 15: 0, # 'כ' - 4: 1, # 'ל' - 11: 0, # 'ם' - 6: 0, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 1, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 1, # 'ר' - 10: 0, # 'ש' - 5: 1, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 21: { # 'צ' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 1, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 2, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 2, # 'ִ' - 37: 2, # 'ֵ' - 36: 1, # 'ֶ' - 31: 2, # 'ַ' - 29: 2, # 'ָ' - 35: 1, # 'ֹ' - 62: 1, # 'ֻ' - 28: 2, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 3, # 'א' - 8: 3, # 'ב' - 20: 2, # 'ג' - 16: 3, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 1, # 'ז' - 14: 3, # 'ח' - 22: 2, # 'ט' - 1: 3, # 'י' - 25: 1, # 'ך' - 15: 1, # 'כ' - 4: 3, # 'ל' - 11: 2, # 'ם' - 6: 3, # 'מ' - 23: 2, # 'ן' - 12: 3, # 'נ' - 19: 1, # 'ס' - 13: 3, # 'ע' - 26: 2, # 'ף' - 18: 3, # 'פ' - 27: 2, # 'ץ' - 21: 2, # 'צ' - 17: 3, # 'ק' - 7: 3, # 'ר' - 10: 0, # 'ש' - 5: 3, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 17: { # 'ק' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 1, # '\xa0' - 55: 1, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 2, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 2, # 'ִ' - 37: 2, # 'ֵ' - 36: 1, # 'ֶ' - 31: 2, # 'ַ' - 29: 2, # 'ָ' - 35: 2, # 'ֹ' - 62: 1, # 'ֻ' - 28: 2, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 3, # 'א' - 8: 3, # 'ב' - 20: 2, # 'ג' - 16: 3, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 2, # 'ז' - 14: 3, # 'ח' - 22: 3, # 'ט' - 1: 3, # 'י' - 25: 1, # 'ך' - 15: 1, # 'כ' - 4: 3, # 'ל' - 11: 2, # 'ם' - 6: 3, # 'מ' - 23: 2, # 'ן' - 12: 3, # 'נ' - 19: 3, # 'ס' - 13: 3, # 'ע' - 26: 2, # 'ף' - 18: 3, # 'פ' - 27: 2, # 'ץ' - 21: 3, # 'צ' - 17: 2, # 'ק' - 7: 3, # 'ר' - 10: 3, # 'ש' - 5: 3, # 'ת' - 32: 0, # '–' - 52: 1, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 7: { # 'ר' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 1, # '\xa0' - 55: 2, # '´' - 48: 1, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 2, # 'ְ' - 59: 0, # 'ֱ' - 41: 1, # 'ֲ' - 33: 2, # 'ִ' - 37: 2, # 'ֵ' - 36: 2, # 'ֶ' - 31: 2, # 'ַ' - 29: 2, # 'ָ' - 35: 2, # 'ֹ' - 62: 1, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 3, # 'א' - 8: 3, # 'ב' - 20: 3, # 'ג' - 16: 3, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 3, # 'ז' - 14: 3, # 'ח' - 22: 3, # 'ט' - 1: 3, # 'י' - 25: 3, # 'ך' - 15: 3, # 'כ' - 4: 3, # 'ל' - 11: 3, # 'ם' - 6: 3, # 'מ' - 23: 3, # 'ן' - 12: 3, # 'נ' - 19: 3, # 'ס' - 13: 3, # 'ע' - 26: 2, # 'ף' - 18: 3, # 'פ' - 27: 3, # 'ץ' - 21: 3, # 'צ' - 17: 3, # 'ק' - 7: 3, # 'ר' - 10: 3, # 'ש' - 5: 3, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 2, # '…' - }, - 10: { # 'ש' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 1, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 1, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 1, # 'ִ' - 37: 1, # 'ֵ' - 36: 1, # 'ֶ' - 31: 1, # 'ַ' - 29: 1, # 'ָ' - 35: 1, # 'ֹ' - 62: 1, # 'ֻ' - 28: 2, # 'ּ' - 38: 3, # 'ׁ' - 45: 2, # 'ׂ' - 9: 3, # 'א' - 8: 3, # 'ב' - 20: 3, # 'ג' - 16: 3, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 2, # 'ז' - 14: 3, # 'ח' - 22: 3, # 'ט' - 1: 3, # 'י' - 25: 3, # 'ך' - 15: 3, # 'כ' - 4: 3, # 'ל' - 11: 3, # 'ם' - 6: 3, # 'מ' - 23: 2, # 'ן' - 12: 3, # 'נ' - 19: 2, # 'ס' - 13: 3, # 'ע' - 26: 2, # 'ף' - 18: 3, # 'פ' - 27: 1, # 'ץ' - 21: 2, # 'צ' - 17: 3, # 'ק' - 7: 3, # 'ר' - 10: 3, # 'ש' - 5: 3, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 1, # '…' - }, - 5: { # 'ת' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 1, # '\xa0' - 55: 0, # '´' - 48: 1, # '¼' - 39: 1, # '½' - 57: 0, # '¾' - 30: 2, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 2, # 'ִ' - 37: 2, # 'ֵ' - 36: 2, # 'ֶ' - 31: 2, # 'ַ' - 29: 2, # 'ָ' - 35: 1, # 'ֹ' - 62: 1, # 'ֻ' - 28: 2, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 3, # 'א' - 8: 3, # 'ב' - 20: 3, # 'ג' - 16: 2, # 'ד' - 3: 3, # 'ה' - 2: 3, # 'ו' - 24: 2, # 'ז' - 14: 3, # 'ח' - 22: 2, # 'ט' - 1: 3, # 'י' - 25: 2, # 'ך' - 15: 3, # 'כ' - 4: 3, # 'ל' - 11: 3, # 'ם' - 6: 3, # 'מ' - 23: 3, # 'ן' - 12: 3, # 'נ' - 19: 2, # 'ס' - 13: 3, # 'ע' - 26: 2, # 'ף' - 18: 3, # 'פ' - 27: 1, # 'ץ' - 21: 2, # 'צ' - 17: 3, # 'ק' - 7: 3, # 'ר' - 10: 3, # 'ש' - 5: 3, # 'ת' - 32: 1, # '–' - 52: 1, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 2, # '…' - }, - 32: { # '–' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 1, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 1, # 'א' - 8: 1, # 'ב' - 20: 1, # 'ג' - 16: 1, # 'ד' - 3: 1, # 'ה' - 2: 1, # 'ו' - 24: 0, # 'ז' - 14: 1, # 'ח' - 22: 0, # 'ט' - 1: 1, # 'י' - 25: 0, # 'ך' - 15: 1, # 'כ' - 4: 1, # 'ל' - 11: 0, # 'ם' - 6: 1, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 1, # 'ס' - 13: 1, # 'ע' - 26: 0, # 'ף' - 18: 1, # 'פ' - 27: 0, # 'ץ' - 21: 1, # 'צ' - 17: 0, # 'ק' - 7: 1, # 'ר' - 10: 1, # 'ש' - 5: 1, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 52: { # '’' - 50: 1, # 'a' - 60: 0, # 'c' - 61: 1, # 'd' - 42: 1, # 'e' - 53: 1, # 'i' - 56: 1, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 1, # 'r' - 43: 2, # 's' - 44: 2, # 't' - 63: 1, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 0, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 0, # 'ה' - 2: 1, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 0, # 'י' - 25: 0, # 'ך' - 15: 0, # 'כ' - 4: 0, # 'ל' - 11: 0, # 'ם' - 6: 1, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 0, # 'ר' - 10: 0, # 'ש' - 5: 1, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 47: { # '“' - 50: 1, # 'a' - 60: 1, # 'c' - 61: 1, # 'd' - 42: 1, # 'e' - 53: 1, # 'i' - 56: 1, # 'l' - 54: 1, # 'n' - 49: 1, # 'o' - 51: 1, # 'r' - 43: 1, # 's' - 44: 1, # 't' - 63: 1, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 2, # 'א' - 8: 1, # 'ב' - 20: 1, # 'ג' - 16: 1, # 'ד' - 3: 1, # 'ה' - 2: 1, # 'ו' - 24: 1, # 'ז' - 14: 1, # 'ח' - 22: 1, # 'ט' - 1: 1, # 'י' - 25: 0, # 'ך' - 15: 1, # 'כ' - 4: 1, # 'ל' - 11: 0, # 'ם' - 6: 1, # 'מ' - 23: 0, # 'ן' - 12: 1, # 'נ' - 19: 1, # 'ס' - 13: 1, # 'ע' - 26: 0, # 'ף' - 18: 1, # 'פ' - 27: 0, # 'ץ' - 21: 1, # 'צ' - 17: 1, # 'ק' - 7: 1, # 'ר' - 10: 1, # 'ש' - 5: 1, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 46: { # '”' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 1, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 1, # 'א' - 8: 1, # 'ב' - 20: 1, # 'ג' - 16: 0, # 'ד' - 3: 0, # 'ה' - 2: 0, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 1, # 'י' - 25: 0, # 'ך' - 15: 1, # 'כ' - 4: 1, # 'ל' - 11: 0, # 'ם' - 6: 1, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 1, # 'צ' - 17: 0, # 'ק' - 7: 1, # 'ר' - 10: 0, # 'ש' - 5: 0, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 0, # '†' - 40: 0, # '…' - }, - 58: { # '†' - 50: 0, # 'a' - 60: 0, # 'c' - 61: 0, # 'd' - 42: 0, # 'e' - 53: 0, # 'i' - 56: 0, # 'l' - 54: 0, # 'n' - 49: 0, # 'o' - 51: 0, # 'r' - 43: 0, # 's' - 44: 0, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 0, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 0, # 'ה' - 2: 0, # 'ו' - 24: 0, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 0, # 'י' - 25: 0, # 'ך' - 15: 0, # 'כ' - 4: 0, # 'ל' - 11: 0, # 'ם' - 6: 0, # 'מ' - 23: 0, # 'ן' - 12: 0, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 0, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 0, # 'ר' - 10: 0, # 'ש' - 5: 0, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 0, # '”' - 58: 2, # '†' - 40: 0, # '…' - }, - 40: { # '…' - 50: 1, # 'a' - 60: 1, # 'c' - 61: 1, # 'd' - 42: 1, # 'e' - 53: 1, # 'i' - 56: 0, # 'l' - 54: 1, # 'n' - 49: 0, # 'o' - 51: 1, # 'r' - 43: 1, # 's' - 44: 1, # 't' - 63: 0, # 'u' - 34: 0, # '\xa0' - 55: 0, # '´' - 48: 0, # '¼' - 39: 0, # '½' - 57: 0, # '¾' - 30: 0, # 'ְ' - 59: 0, # 'ֱ' - 41: 0, # 'ֲ' - 33: 0, # 'ִ' - 37: 0, # 'ֵ' - 36: 0, # 'ֶ' - 31: 0, # 'ַ' - 29: 0, # 'ָ' - 35: 0, # 'ֹ' - 62: 0, # 'ֻ' - 28: 0, # 'ּ' - 38: 0, # 'ׁ' - 45: 0, # 'ׂ' - 9: 1, # 'א' - 8: 0, # 'ב' - 20: 0, # 'ג' - 16: 0, # 'ד' - 3: 1, # 'ה' - 2: 1, # 'ו' - 24: 1, # 'ז' - 14: 0, # 'ח' - 22: 0, # 'ט' - 1: 1, # 'י' - 25: 0, # 'ך' - 15: 1, # 'כ' - 4: 1, # 'ל' - 11: 0, # 'ם' - 6: 1, # 'מ' - 23: 0, # 'ן' - 12: 1, # 'נ' - 19: 0, # 'ס' - 13: 0, # 'ע' - 26: 0, # 'ף' - 18: 1, # 'פ' - 27: 0, # 'ץ' - 21: 0, # 'צ' - 17: 0, # 'ק' - 7: 1, # 'ר' - 10: 1, # 'ש' - 5: 1, # 'ת' - 32: 0, # '–' - 52: 0, # '’' - 47: 0, # '“' - 46: 1, # '”' - 58: 0, # '†' - 40: 2, # '…' - }, -} - -# 255: Undefined characters that did not exist in training text -# 254: Carriage/Return -# 253: symbol (punctuation) that does not belong to word -# 252: 0 - 9 -# 251: Control characters - -# Character Mapping Table(s): -WINDOWS_1255_HEBREW_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 69, # 'A' - 66: 91, # 'B' - 67: 79, # 'C' - 68: 80, # 'D' - 69: 92, # 'E' - 70: 89, # 'F' - 71: 97, # 'G' - 72: 90, # 'H' - 73: 68, # 'I' - 74: 111, # 'J' - 75: 112, # 'K' - 76: 82, # 'L' - 77: 73, # 'M' - 78: 95, # 'N' - 79: 85, # 'O' - 80: 78, # 'P' - 81: 121, # 'Q' - 82: 86, # 'R' - 83: 71, # 'S' - 84: 67, # 'T' - 85: 102, # 'U' - 86: 107, # 'V' - 87: 84, # 'W' - 88: 114, # 'X' - 89: 103, # 'Y' - 90: 115, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 50, # 'a' - 98: 74, # 'b' - 99: 60, # 'c' - 100: 61, # 'd' - 101: 42, # 'e' - 102: 76, # 'f' - 103: 70, # 'g' - 104: 64, # 'h' - 105: 53, # 'i' - 106: 105, # 'j' - 107: 93, # 'k' - 108: 56, # 'l' - 109: 65, # 'm' - 110: 54, # 'n' - 111: 49, # 'o' - 112: 66, # 'p' - 113: 110, # 'q' - 114: 51, # 'r' - 115: 43, # 's' - 116: 44, # 't' - 117: 63, # 'u' - 118: 81, # 'v' - 119: 77, # 'w' - 120: 98, # 'x' - 121: 75, # 'y' - 122: 108, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 124, # '€' - 129: 202, # None - 130: 203, # '‚' - 131: 204, # 'ƒ' - 132: 205, # '„' - 133: 40, # '…' - 134: 58, # '†' - 135: 206, # '‡' - 136: 207, # 'ˆ' - 137: 208, # '‰' - 138: 209, # None - 139: 210, # '‹' - 140: 211, # None - 141: 212, # None - 142: 213, # None - 143: 214, # None - 144: 215, # None - 145: 83, # '‘' - 146: 52, # '’' - 147: 47, # '“' - 148: 46, # '”' - 149: 72, # '•' - 150: 32, # '–' - 151: 94, # '—' - 152: 216, # '˜' - 153: 113, # '™' - 154: 217, # None - 155: 109, # '›' - 156: 218, # None - 157: 219, # None - 158: 220, # None - 159: 221, # None - 160: 34, # '\xa0' - 161: 116, # '¡' - 162: 222, # '¢' - 163: 118, # '£' - 164: 100, # '₪' - 165: 223, # '¥' - 166: 224, # '¦' - 167: 117, # '§' - 168: 119, # '¨' - 169: 104, # '©' - 170: 125, # '×' - 171: 225, # '«' - 172: 226, # '¬' - 173: 87, # '\xad' - 174: 99, # '®' - 175: 227, # '¯' - 176: 106, # '°' - 177: 122, # '±' - 178: 123, # '²' - 179: 228, # '³' - 180: 55, # '´' - 181: 229, # 'µ' - 182: 230, # '¶' - 183: 101, # '·' - 184: 231, # '¸' - 185: 232, # '¹' - 186: 120, # '÷' - 187: 233, # '»' - 188: 48, # '¼' - 189: 39, # '½' - 190: 57, # '¾' - 191: 234, # '¿' - 192: 30, # 'ְ' - 193: 59, # 'ֱ' - 194: 41, # 'ֲ' - 195: 88, # 'ֳ' - 196: 33, # 'ִ' - 197: 37, # 'ֵ' - 198: 36, # 'ֶ' - 199: 31, # 'ַ' - 200: 29, # 'ָ' - 201: 35, # 'ֹ' - 202: 235, # None - 203: 62, # 'ֻ' - 204: 28, # 'ּ' - 205: 236, # 'ֽ' - 206: 126, # '־' - 207: 237, # 'ֿ' - 208: 238, # '׀' - 209: 38, # 'ׁ' - 210: 45, # 'ׂ' - 211: 239, # '׃' - 212: 240, # 'װ' - 213: 241, # 'ױ' - 214: 242, # 'ײ' - 215: 243, # '׳' - 216: 127, # '״' - 217: 244, # None - 218: 245, # None - 219: 246, # None - 220: 247, # None - 221: 248, # None - 222: 249, # None - 223: 250, # None - 224: 9, # 'א' - 225: 8, # 'ב' - 226: 20, # 'ג' - 227: 16, # 'ד' - 228: 3, # 'ה' - 229: 2, # 'ו' - 230: 24, # 'ז' - 231: 14, # 'ח' - 232: 22, # 'ט' - 233: 1, # 'י' - 234: 25, # 'ך' - 235: 15, # 'כ' - 236: 4, # 'ל' - 237: 11, # 'ם' - 238: 6, # 'מ' - 239: 23, # 'ן' - 240: 12, # 'נ' - 241: 19, # 'ס' - 242: 13, # 'ע' - 243: 26, # 'ף' - 244: 18, # 'פ' - 245: 27, # 'ץ' - 246: 21, # 'צ' - 247: 17, # 'ק' - 248: 7, # 'ר' - 249: 10, # 'ש' - 250: 5, # 'ת' - 251: 251, # None - 252: 252, # None - 253: 128, # '\u200e' - 254: 96, # '\u200f' - 255: 253, # None -} - -WINDOWS_1255_HEBREW_MODEL = SingleByteCharSetModel(charset_name='windows-1255', - language='Hebrew', - char_to_order_map=WINDOWS_1255_HEBREW_CHAR_TO_ORDER, - language_model=HEBREW_LANG_MODEL, - typical_positive_ratio=0.984004, - keep_ascii_letters=False, - alphabet='אבגדהוזחטיךכלםמןנסעףפץצקרשתװױײ') - diff --git a/venv/lib/python3.8/site-packages/chardet/langhungarianmodel.py b/venv/lib/python3.8/site-packages/chardet/langhungarianmodel.py deleted file mode 100644 index 24a097f..0000000 --- a/venv/lib/python3.8/site-packages/chardet/langhungarianmodel.py +++ /dev/null @@ -1,4650 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from chardet.sbcharsetprober import SingleByteCharSetModel - - -# 3: Positive -# 2: Likely -# 1: Unlikely -# 0: Negative - -HUNGARIAN_LANG_MODEL = { - 28: { # 'A' - 28: 0, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 2, # 'D' - 32: 1, # 'E' - 50: 1, # 'F' - 49: 2, # 'G' - 38: 1, # 'H' - 39: 2, # 'I' - 53: 1, # 'J' - 36: 2, # 'K' - 41: 2, # 'L' - 34: 1, # 'M' - 35: 2, # 'N' - 47: 1, # 'O' - 46: 2, # 'P' - 43: 2, # 'R' - 33: 2, # 'S' - 37: 2, # 'T' - 57: 1, # 'U' - 48: 1, # 'V' - 55: 1, # 'Y' - 52: 2, # 'Z' - 2: 0, # 'a' - 18: 1, # 'b' - 26: 1, # 'c' - 17: 2, # 'd' - 1: 1, # 'e' - 27: 1, # 'f' - 12: 1, # 'g' - 20: 1, # 'h' - 9: 1, # 'i' - 22: 1, # 'j' - 7: 2, # 'k' - 6: 2, # 'l' - 13: 2, # 'm' - 4: 2, # 'n' - 8: 0, # 'o' - 23: 2, # 'p' - 10: 2, # 'r' - 5: 1, # 's' - 3: 1, # 't' - 21: 1, # 'u' - 19: 1, # 'v' - 62: 1, # 'x' - 16: 0, # 'y' - 11: 3, # 'z' - 51: 1, # 'Á' - 44: 0, # 'É' - 61: 1, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 0, # 'á' - 15: 0, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 40: { # 'B' - 28: 2, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 2, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 1, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 1, # 'L' - 34: 0, # 'M' - 35: 1, # 'N' - 47: 2, # 'O' - 46: 0, # 'P' - 43: 1, # 'R' - 33: 1, # 'S' - 37: 1, # 'T' - 57: 1, # 'U' - 48: 1, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 2, # 'a' - 18: 0, # 'b' - 26: 0, # 'c' - 17: 0, # 'd' - 1: 3, # 'e' - 27: 0, # 'f' - 12: 0, # 'g' - 20: 0, # 'h' - 9: 2, # 'i' - 22: 1, # 'j' - 7: 0, # 'k' - 6: 1, # 'l' - 13: 0, # 'm' - 4: 0, # 'n' - 8: 2, # 'o' - 23: 1, # 'p' - 10: 2, # 'r' - 5: 0, # 's' - 3: 0, # 't' - 21: 3, # 'u' - 19: 0, # 'v' - 62: 0, # 'x' - 16: 1, # 'y' - 11: 0, # 'z' - 51: 1, # 'Á' - 44: 1, # 'É' - 61: 1, # 'Í' - 58: 1, # 'Ó' - 59: 1, # 'Ö' - 60: 1, # 'Ú' - 63: 1, # 'Ü' - 14: 2, # 'á' - 15: 2, # 'é' - 30: 1, # 'í' - 25: 1, # 'ó' - 24: 1, # 'ö' - 31: 1, # 'ú' - 29: 1, # 'ü' - 42: 1, # 'ő' - 56: 1, # 'ű' - }, - 54: { # 'C' - 28: 1, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 1, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 1, # 'H' - 39: 2, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 1, # 'L' - 34: 1, # 'M' - 35: 0, # 'N' - 47: 1, # 'O' - 46: 1, # 'P' - 43: 1, # 'R' - 33: 2, # 'S' - 37: 1, # 'T' - 57: 1, # 'U' - 48: 0, # 'V' - 55: 1, # 'Y' - 52: 1, # 'Z' - 2: 2, # 'a' - 18: 0, # 'b' - 26: 0, # 'c' - 17: 0, # 'd' - 1: 1, # 'e' - 27: 0, # 'f' - 12: 0, # 'g' - 20: 1, # 'h' - 9: 1, # 'i' - 22: 0, # 'j' - 7: 0, # 'k' - 6: 1, # 'l' - 13: 0, # 'm' - 4: 0, # 'n' - 8: 2, # 'o' - 23: 0, # 'p' - 10: 1, # 'r' - 5: 3, # 's' - 3: 0, # 't' - 21: 1, # 'u' - 19: 0, # 'v' - 62: 0, # 'x' - 16: 1, # 'y' - 11: 1, # 'z' - 51: 1, # 'Á' - 44: 1, # 'É' - 61: 1, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 1, # 'á' - 15: 1, # 'é' - 30: 1, # 'í' - 25: 1, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 45: { # 'D' - 28: 2, # 'A' - 40: 1, # 'B' - 54: 0, # 'C' - 45: 1, # 'D' - 32: 2, # 'E' - 50: 1, # 'F' - 49: 1, # 'G' - 38: 1, # 'H' - 39: 2, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 0, # 'L' - 34: 1, # 'M' - 35: 1, # 'N' - 47: 2, # 'O' - 46: 0, # 'P' - 43: 1, # 'R' - 33: 1, # 'S' - 37: 1, # 'T' - 57: 1, # 'U' - 48: 1, # 'V' - 55: 1, # 'Y' - 52: 1, # 'Z' - 2: 2, # 'a' - 18: 0, # 'b' - 26: 0, # 'c' - 17: 0, # 'd' - 1: 3, # 'e' - 27: 0, # 'f' - 12: 0, # 'g' - 20: 0, # 'h' - 9: 1, # 'i' - 22: 0, # 'j' - 7: 0, # 'k' - 6: 0, # 'l' - 13: 0, # 'm' - 4: 0, # 'n' - 8: 1, # 'o' - 23: 0, # 'p' - 10: 2, # 'r' - 5: 0, # 's' - 3: 0, # 't' - 21: 2, # 'u' - 19: 0, # 'v' - 62: 0, # 'x' - 16: 1, # 'y' - 11: 1, # 'z' - 51: 1, # 'Á' - 44: 1, # 'É' - 61: 1, # 'Í' - 58: 1, # 'Ó' - 59: 1, # 'Ö' - 60: 1, # 'Ú' - 63: 1, # 'Ü' - 14: 1, # 'á' - 15: 1, # 'é' - 30: 1, # 'í' - 25: 1, # 'ó' - 24: 1, # 'ö' - 31: 1, # 'ú' - 29: 1, # 'ü' - 42: 1, # 'ő' - 56: 0, # 'ű' - }, - 32: { # 'E' - 28: 1, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 1, # 'E' - 50: 1, # 'F' - 49: 2, # 'G' - 38: 1, # 'H' - 39: 1, # 'I' - 53: 1, # 'J' - 36: 2, # 'K' - 41: 2, # 'L' - 34: 2, # 'M' - 35: 2, # 'N' - 47: 1, # 'O' - 46: 1, # 'P' - 43: 2, # 'R' - 33: 2, # 'S' - 37: 2, # 'T' - 57: 1, # 'U' - 48: 1, # 'V' - 55: 1, # 'Y' - 52: 1, # 'Z' - 2: 1, # 'a' - 18: 1, # 'b' - 26: 1, # 'c' - 17: 2, # 'd' - 1: 1, # 'e' - 27: 1, # 'f' - 12: 3, # 'g' - 20: 1, # 'h' - 9: 1, # 'i' - 22: 1, # 'j' - 7: 1, # 'k' - 6: 2, # 'l' - 13: 2, # 'm' - 4: 2, # 'n' - 8: 0, # 'o' - 23: 1, # 'p' - 10: 2, # 'r' - 5: 2, # 's' - 3: 1, # 't' - 21: 2, # 'u' - 19: 1, # 'v' - 62: 1, # 'x' - 16: 0, # 'y' - 11: 3, # 'z' - 51: 1, # 'Á' - 44: 1, # 'É' - 61: 0, # 'Í' - 58: 1, # 'Ó' - 59: 1, # 'Ö' - 60: 0, # 'Ú' - 63: 1, # 'Ü' - 14: 0, # 'á' - 15: 0, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 1, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 50: { # 'F' - 28: 1, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 1, # 'E' - 50: 1, # 'F' - 49: 0, # 'G' - 38: 1, # 'H' - 39: 1, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 1, # 'L' - 34: 1, # 'M' - 35: 1, # 'N' - 47: 1, # 'O' - 46: 0, # 'P' - 43: 1, # 'R' - 33: 0, # 'S' - 37: 1, # 'T' - 57: 1, # 'U' - 48: 0, # 'V' - 55: 1, # 'Y' - 52: 0, # 'Z' - 2: 2, # 'a' - 18: 0, # 'b' - 26: 0, # 'c' - 17: 0, # 'd' - 1: 2, # 'e' - 27: 1, # 'f' - 12: 0, # 'g' - 20: 0, # 'h' - 9: 2, # 'i' - 22: 1, # 'j' - 7: 0, # 'k' - 6: 1, # 'l' - 13: 0, # 'm' - 4: 0, # 'n' - 8: 2, # 'o' - 23: 0, # 'p' - 10: 2, # 'r' - 5: 0, # 's' - 3: 0, # 't' - 21: 1, # 'u' - 19: 0, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 0, # 'z' - 51: 1, # 'Á' - 44: 1, # 'É' - 61: 0, # 'Í' - 58: 1, # 'Ó' - 59: 1, # 'Ö' - 60: 0, # 'Ú' - 63: 1, # 'Ü' - 14: 1, # 'á' - 15: 1, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 2, # 'ö' - 31: 1, # 'ú' - 29: 1, # 'ü' - 42: 1, # 'ő' - 56: 1, # 'ű' - }, - 49: { # 'G' - 28: 2, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 2, # 'E' - 50: 1, # 'F' - 49: 1, # 'G' - 38: 1, # 'H' - 39: 1, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 1, # 'L' - 34: 1, # 'M' - 35: 1, # 'N' - 47: 1, # 'O' - 46: 1, # 'P' - 43: 1, # 'R' - 33: 1, # 'S' - 37: 1, # 'T' - 57: 1, # 'U' - 48: 1, # 'V' - 55: 2, # 'Y' - 52: 1, # 'Z' - 2: 2, # 'a' - 18: 0, # 'b' - 26: 0, # 'c' - 17: 0, # 'd' - 1: 2, # 'e' - 27: 0, # 'f' - 12: 0, # 'g' - 20: 0, # 'h' - 9: 1, # 'i' - 22: 0, # 'j' - 7: 0, # 'k' - 6: 1, # 'l' - 13: 0, # 'm' - 4: 0, # 'n' - 8: 2, # 'o' - 23: 0, # 'p' - 10: 2, # 'r' - 5: 0, # 's' - 3: 0, # 't' - 21: 1, # 'u' - 19: 0, # 'v' - 62: 0, # 'x' - 16: 2, # 'y' - 11: 0, # 'z' - 51: 1, # 'Á' - 44: 1, # 'É' - 61: 1, # 'Í' - 58: 1, # 'Ó' - 59: 1, # 'Ö' - 60: 1, # 'Ú' - 63: 1, # 'Ü' - 14: 1, # 'á' - 15: 1, # 'é' - 30: 0, # 'í' - 25: 1, # 'ó' - 24: 1, # 'ö' - 31: 1, # 'ú' - 29: 1, # 'ü' - 42: 1, # 'ő' - 56: 0, # 'ű' - }, - 38: { # 'H' - 28: 2, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 0, # 'D' - 32: 1, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 1, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 1, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 1, # 'O' - 46: 0, # 'P' - 43: 1, # 'R' - 33: 1, # 'S' - 37: 1, # 'T' - 57: 1, # 'U' - 48: 0, # 'V' - 55: 1, # 'Y' - 52: 0, # 'Z' - 2: 3, # 'a' - 18: 0, # 'b' - 26: 0, # 'c' - 17: 0, # 'd' - 1: 2, # 'e' - 27: 0, # 'f' - 12: 0, # 'g' - 20: 0, # 'h' - 9: 2, # 'i' - 22: 1, # 'j' - 7: 0, # 'k' - 6: 1, # 'l' - 13: 1, # 'm' - 4: 0, # 'n' - 8: 3, # 'o' - 23: 0, # 'p' - 10: 1, # 'r' - 5: 0, # 's' - 3: 0, # 't' - 21: 2, # 'u' - 19: 0, # 'v' - 62: 0, # 'x' - 16: 1, # 'y' - 11: 0, # 'z' - 51: 2, # 'Á' - 44: 2, # 'É' - 61: 1, # 'Í' - 58: 1, # 'Ó' - 59: 1, # 'Ö' - 60: 1, # 'Ú' - 63: 1, # 'Ü' - 14: 2, # 'á' - 15: 1, # 'é' - 30: 2, # 'í' - 25: 1, # 'ó' - 24: 1, # 'ö' - 31: 1, # 'ú' - 29: 1, # 'ü' - 42: 1, # 'ő' - 56: 1, # 'ű' - }, - 39: { # 'I' - 28: 2, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 1, # 'E' - 50: 1, # 'F' - 49: 1, # 'G' - 38: 1, # 'H' - 39: 2, # 'I' - 53: 1, # 'J' - 36: 2, # 'K' - 41: 2, # 'L' - 34: 1, # 'M' - 35: 2, # 'N' - 47: 1, # 'O' - 46: 1, # 'P' - 43: 1, # 'R' - 33: 2, # 'S' - 37: 1, # 'T' - 57: 1, # 'U' - 48: 1, # 'V' - 55: 0, # 'Y' - 52: 2, # 'Z' - 2: 0, # 'a' - 18: 1, # 'b' - 26: 1, # 'c' - 17: 2, # 'd' - 1: 0, # 'e' - 27: 1, # 'f' - 12: 2, # 'g' - 20: 1, # 'h' - 9: 0, # 'i' - 22: 1, # 'j' - 7: 1, # 'k' - 6: 2, # 'l' - 13: 2, # 'm' - 4: 1, # 'n' - 8: 0, # 'o' - 23: 1, # 'p' - 10: 2, # 'r' - 5: 2, # 's' - 3: 2, # 't' - 21: 0, # 'u' - 19: 1, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 1, # 'z' - 51: 1, # 'Á' - 44: 1, # 'É' - 61: 0, # 'Í' - 58: 1, # 'Ó' - 59: 1, # 'Ö' - 60: 1, # 'Ú' - 63: 1, # 'Ü' - 14: 0, # 'á' - 15: 0, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 53: { # 'J' - 28: 2, # 'A' - 40: 0, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 2, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 1, # 'H' - 39: 1, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 1, # 'L' - 34: 1, # 'M' - 35: 1, # 'N' - 47: 1, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 1, # 'S' - 37: 1, # 'T' - 57: 1, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 1, # 'Z' - 2: 2, # 'a' - 18: 0, # 'b' - 26: 0, # 'c' - 17: 0, # 'd' - 1: 2, # 'e' - 27: 0, # 'f' - 12: 0, # 'g' - 20: 0, # 'h' - 9: 1, # 'i' - 22: 0, # 'j' - 7: 0, # 'k' - 6: 0, # 'l' - 13: 0, # 'm' - 4: 0, # 'n' - 8: 1, # 'o' - 23: 0, # 'p' - 10: 0, # 'r' - 5: 0, # 's' - 3: 0, # 't' - 21: 2, # 'u' - 19: 0, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 0, # 'z' - 51: 1, # 'Á' - 44: 1, # 'É' - 61: 0, # 'Í' - 58: 1, # 'Ó' - 59: 1, # 'Ö' - 60: 1, # 'Ú' - 63: 1, # 'Ü' - 14: 2, # 'á' - 15: 1, # 'é' - 30: 0, # 'í' - 25: 2, # 'ó' - 24: 2, # 'ö' - 31: 1, # 'ú' - 29: 0, # 'ü' - 42: 1, # 'ő' - 56: 0, # 'ű' - }, - 36: { # 'K' - 28: 2, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 2, # 'E' - 50: 1, # 'F' - 49: 0, # 'G' - 38: 1, # 'H' - 39: 2, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 1, # 'L' - 34: 1, # 'M' - 35: 1, # 'N' - 47: 2, # 'O' - 46: 0, # 'P' - 43: 1, # 'R' - 33: 1, # 'S' - 37: 1, # 'T' - 57: 1, # 'U' - 48: 1, # 'V' - 55: 1, # 'Y' - 52: 0, # 'Z' - 2: 2, # 'a' - 18: 0, # 'b' - 26: 0, # 'c' - 17: 0, # 'd' - 1: 2, # 'e' - 27: 1, # 'f' - 12: 0, # 'g' - 20: 1, # 'h' - 9: 3, # 'i' - 22: 0, # 'j' - 7: 0, # 'k' - 6: 1, # 'l' - 13: 1, # 'm' - 4: 1, # 'n' - 8: 2, # 'o' - 23: 0, # 'p' - 10: 2, # 'r' - 5: 0, # 's' - 3: 0, # 't' - 21: 1, # 'u' - 19: 1, # 'v' - 62: 0, # 'x' - 16: 1, # 'y' - 11: 0, # 'z' - 51: 1, # 'Á' - 44: 1, # 'É' - 61: 1, # 'Í' - 58: 1, # 'Ó' - 59: 2, # 'Ö' - 60: 1, # 'Ú' - 63: 1, # 'Ü' - 14: 2, # 'á' - 15: 2, # 'é' - 30: 1, # 'í' - 25: 1, # 'ó' - 24: 2, # 'ö' - 31: 1, # 'ú' - 29: 2, # 'ü' - 42: 1, # 'ő' - 56: 0, # 'ű' - }, - 41: { # 'L' - 28: 2, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 2, # 'E' - 50: 1, # 'F' - 49: 1, # 'G' - 38: 1, # 'H' - 39: 2, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 2, # 'L' - 34: 1, # 'M' - 35: 1, # 'N' - 47: 2, # 'O' - 46: 0, # 'P' - 43: 1, # 'R' - 33: 1, # 'S' - 37: 2, # 'T' - 57: 1, # 'U' - 48: 1, # 'V' - 55: 1, # 'Y' - 52: 1, # 'Z' - 2: 2, # 'a' - 18: 0, # 'b' - 26: 0, # 'c' - 17: 0, # 'd' - 1: 3, # 'e' - 27: 0, # 'f' - 12: 0, # 'g' - 20: 0, # 'h' - 9: 2, # 'i' - 22: 1, # 'j' - 7: 0, # 'k' - 6: 1, # 'l' - 13: 0, # 'm' - 4: 0, # 'n' - 8: 2, # 'o' - 23: 0, # 'p' - 10: 0, # 'r' - 5: 0, # 's' - 3: 0, # 't' - 21: 2, # 'u' - 19: 0, # 'v' - 62: 0, # 'x' - 16: 1, # 'y' - 11: 0, # 'z' - 51: 2, # 'Á' - 44: 1, # 'É' - 61: 1, # 'Í' - 58: 1, # 'Ó' - 59: 1, # 'Ö' - 60: 1, # 'Ú' - 63: 1, # 'Ü' - 14: 2, # 'á' - 15: 1, # 'é' - 30: 1, # 'í' - 25: 1, # 'ó' - 24: 1, # 'ö' - 31: 0, # 'ú' - 29: 1, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 34: { # 'M' - 28: 2, # 'A' - 40: 1, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 2, # 'E' - 50: 1, # 'F' - 49: 0, # 'G' - 38: 1, # 'H' - 39: 2, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 1, # 'L' - 34: 1, # 'M' - 35: 1, # 'N' - 47: 1, # 'O' - 46: 1, # 'P' - 43: 1, # 'R' - 33: 1, # 'S' - 37: 1, # 'T' - 57: 1, # 'U' - 48: 1, # 'V' - 55: 1, # 'Y' - 52: 1, # 'Z' - 2: 3, # 'a' - 18: 0, # 'b' - 26: 1, # 'c' - 17: 0, # 'd' - 1: 3, # 'e' - 27: 0, # 'f' - 12: 0, # 'g' - 20: 0, # 'h' - 9: 3, # 'i' - 22: 0, # 'j' - 7: 0, # 'k' - 6: 0, # 'l' - 13: 1, # 'm' - 4: 1, # 'n' - 8: 3, # 'o' - 23: 0, # 'p' - 10: 1, # 'r' - 5: 0, # 's' - 3: 0, # 't' - 21: 2, # 'u' - 19: 0, # 'v' - 62: 0, # 'x' - 16: 1, # 'y' - 11: 0, # 'z' - 51: 2, # 'Á' - 44: 1, # 'É' - 61: 1, # 'Í' - 58: 1, # 'Ó' - 59: 1, # 'Ö' - 60: 1, # 'Ú' - 63: 1, # 'Ü' - 14: 2, # 'á' - 15: 2, # 'é' - 30: 1, # 'í' - 25: 1, # 'ó' - 24: 1, # 'ö' - 31: 1, # 'ú' - 29: 1, # 'ü' - 42: 0, # 'ő' - 56: 1, # 'ű' - }, - 35: { # 'N' - 28: 2, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 2, # 'D' - 32: 2, # 'E' - 50: 1, # 'F' - 49: 1, # 'G' - 38: 1, # 'H' - 39: 1, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 1, # 'L' - 34: 1, # 'M' - 35: 1, # 'N' - 47: 1, # 'O' - 46: 1, # 'P' - 43: 1, # 'R' - 33: 1, # 'S' - 37: 2, # 'T' - 57: 1, # 'U' - 48: 1, # 'V' - 55: 2, # 'Y' - 52: 1, # 'Z' - 2: 3, # 'a' - 18: 0, # 'b' - 26: 0, # 'c' - 17: 0, # 'd' - 1: 3, # 'e' - 27: 0, # 'f' - 12: 0, # 'g' - 20: 0, # 'h' - 9: 2, # 'i' - 22: 0, # 'j' - 7: 0, # 'k' - 6: 0, # 'l' - 13: 0, # 'm' - 4: 1, # 'n' - 8: 2, # 'o' - 23: 0, # 'p' - 10: 0, # 'r' - 5: 0, # 's' - 3: 0, # 't' - 21: 1, # 'u' - 19: 0, # 'v' - 62: 0, # 'x' - 16: 2, # 'y' - 11: 0, # 'z' - 51: 1, # 'Á' - 44: 1, # 'É' - 61: 1, # 'Í' - 58: 1, # 'Ó' - 59: 1, # 'Ö' - 60: 1, # 'Ú' - 63: 1, # 'Ü' - 14: 1, # 'á' - 15: 2, # 'é' - 30: 1, # 'í' - 25: 1, # 'ó' - 24: 1, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 1, # 'ő' - 56: 0, # 'ű' - }, - 47: { # 'O' - 28: 1, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 1, # 'E' - 50: 1, # 'F' - 49: 1, # 'G' - 38: 1, # 'H' - 39: 1, # 'I' - 53: 1, # 'J' - 36: 2, # 'K' - 41: 2, # 'L' - 34: 2, # 'M' - 35: 2, # 'N' - 47: 1, # 'O' - 46: 1, # 'P' - 43: 2, # 'R' - 33: 2, # 'S' - 37: 2, # 'T' - 57: 1, # 'U' - 48: 1, # 'V' - 55: 1, # 'Y' - 52: 1, # 'Z' - 2: 0, # 'a' - 18: 1, # 'b' - 26: 1, # 'c' - 17: 1, # 'd' - 1: 1, # 'e' - 27: 1, # 'f' - 12: 1, # 'g' - 20: 1, # 'h' - 9: 1, # 'i' - 22: 1, # 'j' - 7: 2, # 'k' - 6: 2, # 'l' - 13: 1, # 'm' - 4: 1, # 'n' - 8: 1, # 'o' - 23: 1, # 'p' - 10: 2, # 'r' - 5: 1, # 's' - 3: 2, # 't' - 21: 1, # 'u' - 19: 0, # 'v' - 62: 1, # 'x' - 16: 0, # 'y' - 11: 1, # 'z' - 51: 1, # 'Á' - 44: 1, # 'É' - 61: 0, # 'Í' - 58: 1, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 0, # 'á' - 15: 0, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 46: { # 'P' - 28: 1, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 1, # 'E' - 50: 1, # 'F' - 49: 1, # 'G' - 38: 1, # 'H' - 39: 1, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 1, # 'L' - 34: 0, # 'M' - 35: 1, # 'N' - 47: 1, # 'O' - 46: 1, # 'P' - 43: 2, # 'R' - 33: 1, # 'S' - 37: 1, # 'T' - 57: 1, # 'U' - 48: 1, # 'V' - 55: 0, # 'Y' - 52: 1, # 'Z' - 2: 2, # 'a' - 18: 0, # 'b' - 26: 0, # 'c' - 17: 0, # 'd' - 1: 2, # 'e' - 27: 1, # 'f' - 12: 0, # 'g' - 20: 1, # 'h' - 9: 2, # 'i' - 22: 0, # 'j' - 7: 0, # 'k' - 6: 1, # 'l' - 13: 0, # 'm' - 4: 1, # 'n' - 8: 2, # 'o' - 23: 0, # 'p' - 10: 2, # 'r' - 5: 1, # 's' - 3: 0, # 't' - 21: 1, # 'u' - 19: 0, # 'v' - 62: 0, # 'x' - 16: 1, # 'y' - 11: 0, # 'z' - 51: 2, # 'Á' - 44: 1, # 'É' - 61: 1, # 'Í' - 58: 1, # 'Ó' - 59: 1, # 'Ö' - 60: 0, # 'Ú' - 63: 1, # 'Ü' - 14: 3, # 'á' - 15: 2, # 'é' - 30: 0, # 'í' - 25: 1, # 'ó' - 24: 1, # 'ö' - 31: 0, # 'ú' - 29: 1, # 'ü' - 42: 1, # 'ő' - 56: 0, # 'ű' - }, - 43: { # 'R' - 28: 2, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 2, # 'E' - 50: 1, # 'F' - 49: 1, # 'G' - 38: 1, # 'H' - 39: 2, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 1, # 'L' - 34: 1, # 'M' - 35: 1, # 'N' - 47: 2, # 'O' - 46: 1, # 'P' - 43: 1, # 'R' - 33: 2, # 'S' - 37: 2, # 'T' - 57: 1, # 'U' - 48: 1, # 'V' - 55: 1, # 'Y' - 52: 1, # 'Z' - 2: 2, # 'a' - 18: 0, # 'b' - 26: 0, # 'c' - 17: 0, # 'd' - 1: 2, # 'e' - 27: 0, # 'f' - 12: 0, # 'g' - 20: 1, # 'h' - 9: 2, # 'i' - 22: 0, # 'j' - 7: 0, # 'k' - 6: 0, # 'l' - 13: 0, # 'm' - 4: 0, # 'n' - 8: 2, # 'o' - 23: 0, # 'p' - 10: 0, # 'r' - 5: 0, # 's' - 3: 0, # 't' - 21: 1, # 'u' - 19: 0, # 'v' - 62: 0, # 'x' - 16: 1, # 'y' - 11: 0, # 'z' - 51: 2, # 'Á' - 44: 1, # 'É' - 61: 1, # 'Í' - 58: 2, # 'Ó' - 59: 1, # 'Ö' - 60: 1, # 'Ú' - 63: 1, # 'Ü' - 14: 2, # 'á' - 15: 2, # 'é' - 30: 1, # 'í' - 25: 2, # 'ó' - 24: 1, # 'ö' - 31: 1, # 'ú' - 29: 1, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 33: { # 'S' - 28: 2, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 2, # 'E' - 50: 1, # 'F' - 49: 1, # 'G' - 38: 1, # 'H' - 39: 2, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 1, # 'L' - 34: 1, # 'M' - 35: 1, # 'N' - 47: 2, # 'O' - 46: 1, # 'P' - 43: 1, # 'R' - 33: 2, # 'S' - 37: 2, # 'T' - 57: 1, # 'U' - 48: 1, # 'V' - 55: 1, # 'Y' - 52: 3, # 'Z' - 2: 2, # 'a' - 18: 0, # 'b' - 26: 1, # 'c' - 17: 0, # 'd' - 1: 2, # 'e' - 27: 0, # 'f' - 12: 0, # 'g' - 20: 1, # 'h' - 9: 2, # 'i' - 22: 0, # 'j' - 7: 1, # 'k' - 6: 1, # 'l' - 13: 1, # 'm' - 4: 0, # 'n' - 8: 2, # 'o' - 23: 1, # 'p' - 10: 0, # 'r' - 5: 0, # 's' - 3: 1, # 't' - 21: 1, # 'u' - 19: 1, # 'v' - 62: 0, # 'x' - 16: 1, # 'y' - 11: 3, # 'z' - 51: 2, # 'Á' - 44: 1, # 'É' - 61: 1, # 'Í' - 58: 1, # 'Ó' - 59: 1, # 'Ö' - 60: 1, # 'Ú' - 63: 1, # 'Ü' - 14: 2, # 'á' - 15: 1, # 'é' - 30: 1, # 'í' - 25: 1, # 'ó' - 24: 1, # 'ö' - 31: 1, # 'ú' - 29: 1, # 'ü' - 42: 1, # 'ő' - 56: 1, # 'ű' - }, - 37: { # 'T' - 28: 2, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 2, # 'E' - 50: 1, # 'F' - 49: 1, # 'G' - 38: 1, # 'H' - 39: 2, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 1, # 'L' - 34: 1, # 'M' - 35: 1, # 'N' - 47: 2, # 'O' - 46: 1, # 'P' - 43: 2, # 'R' - 33: 1, # 'S' - 37: 2, # 'T' - 57: 1, # 'U' - 48: 1, # 'V' - 55: 1, # 'Y' - 52: 1, # 'Z' - 2: 2, # 'a' - 18: 0, # 'b' - 26: 0, # 'c' - 17: 0, # 'd' - 1: 2, # 'e' - 27: 0, # 'f' - 12: 0, # 'g' - 20: 1, # 'h' - 9: 2, # 'i' - 22: 0, # 'j' - 7: 0, # 'k' - 6: 0, # 'l' - 13: 0, # 'm' - 4: 0, # 'n' - 8: 2, # 'o' - 23: 0, # 'p' - 10: 1, # 'r' - 5: 1, # 's' - 3: 0, # 't' - 21: 2, # 'u' - 19: 0, # 'v' - 62: 0, # 'x' - 16: 1, # 'y' - 11: 1, # 'z' - 51: 2, # 'Á' - 44: 2, # 'É' - 61: 1, # 'Í' - 58: 1, # 'Ó' - 59: 1, # 'Ö' - 60: 1, # 'Ú' - 63: 1, # 'Ü' - 14: 2, # 'á' - 15: 1, # 'é' - 30: 1, # 'í' - 25: 1, # 'ó' - 24: 2, # 'ö' - 31: 1, # 'ú' - 29: 1, # 'ü' - 42: 1, # 'ő' - 56: 1, # 'ű' - }, - 57: { # 'U' - 28: 1, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 1, # 'E' - 50: 1, # 'F' - 49: 1, # 'G' - 38: 1, # 'H' - 39: 1, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 1, # 'L' - 34: 1, # 'M' - 35: 1, # 'N' - 47: 1, # 'O' - 46: 1, # 'P' - 43: 1, # 'R' - 33: 2, # 'S' - 37: 1, # 'T' - 57: 0, # 'U' - 48: 1, # 'V' - 55: 0, # 'Y' - 52: 1, # 'Z' - 2: 0, # 'a' - 18: 1, # 'b' - 26: 1, # 'c' - 17: 1, # 'd' - 1: 1, # 'e' - 27: 0, # 'f' - 12: 2, # 'g' - 20: 0, # 'h' - 9: 0, # 'i' - 22: 1, # 'j' - 7: 1, # 'k' - 6: 1, # 'l' - 13: 1, # 'm' - 4: 1, # 'n' - 8: 0, # 'o' - 23: 1, # 'p' - 10: 1, # 'r' - 5: 1, # 's' - 3: 1, # 't' - 21: 0, # 'u' - 19: 0, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 1, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 1, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 0, # 'á' - 15: 0, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 48: { # 'V' - 28: 2, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 1, # 'D' - 32: 2, # 'E' - 50: 1, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 2, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 0, # 'L' - 34: 1, # 'M' - 35: 1, # 'N' - 47: 1, # 'O' - 46: 1, # 'P' - 43: 1, # 'R' - 33: 1, # 'S' - 37: 1, # 'T' - 57: 1, # 'U' - 48: 1, # 'V' - 55: 1, # 'Y' - 52: 0, # 'Z' - 2: 3, # 'a' - 18: 0, # 'b' - 26: 0, # 'c' - 17: 0, # 'd' - 1: 2, # 'e' - 27: 0, # 'f' - 12: 0, # 'g' - 20: 0, # 'h' - 9: 2, # 'i' - 22: 0, # 'j' - 7: 0, # 'k' - 6: 1, # 'l' - 13: 0, # 'm' - 4: 0, # 'n' - 8: 2, # 'o' - 23: 0, # 'p' - 10: 0, # 'r' - 5: 0, # 's' - 3: 0, # 't' - 21: 1, # 'u' - 19: 0, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 0, # 'z' - 51: 2, # 'Á' - 44: 2, # 'É' - 61: 1, # 'Í' - 58: 1, # 'Ó' - 59: 1, # 'Ö' - 60: 0, # 'Ú' - 63: 1, # 'Ü' - 14: 2, # 'á' - 15: 2, # 'é' - 30: 1, # 'í' - 25: 0, # 'ó' - 24: 1, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 55: { # 'Y' - 28: 2, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 2, # 'E' - 50: 1, # 'F' - 49: 1, # 'G' - 38: 1, # 'H' - 39: 1, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 1, # 'L' - 34: 1, # 'M' - 35: 1, # 'N' - 47: 1, # 'O' - 46: 1, # 'P' - 43: 1, # 'R' - 33: 1, # 'S' - 37: 1, # 'T' - 57: 1, # 'U' - 48: 1, # 'V' - 55: 0, # 'Y' - 52: 2, # 'Z' - 2: 1, # 'a' - 18: 0, # 'b' - 26: 0, # 'c' - 17: 1, # 'd' - 1: 1, # 'e' - 27: 0, # 'f' - 12: 0, # 'g' - 20: 0, # 'h' - 9: 0, # 'i' - 22: 0, # 'j' - 7: 0, # 'k' - 6: 0, # 'l' - 13: 0, # 'm' - 4: 0, # 'n' - 8: 1, # 'o' - 23: 1, # 'p' - 10: 0, # 'r' - 5: 0, # 's' - 3: 0, # 't' - 21: 0, # 'u' - 19: 1, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 0, # 'z' - 51: 1, # 'Á' - 44: 1, # 'É' - 61: 1, # 'Í' - 58: 1, # 'Ó' - 59: 1, # 'Ö' - 60: 1, # 'Ú' - 63: 1, # 'Ü' - 14: 0, # 'á' - 15: 0, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 52: { # 'Z' - 28: 2, # 'A' - 40: 1, # 'B' - 54: 0, # 'C' - 45: 1, # 'D' - 32: 2, # 'E' - 50: 1, # 'F' - 49: 1, # 'G' - 38: 1, # 'H' - 39: 2, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 1, # 'L' - 34: 1, # 'M' - 35: 1, # 'N' - 47: 2, # 'O' - 46: 1, # 'P' - 43: 1, # 'R' - 33: 2, # 'S' - 37: 1, # 'T' - 57: 1, # 'U' - 48: 1, # 'V' - 55: 1, # 'Y' - 52: 1, # 'Z' - 2: 1, # 'a' - 18: 0, # 'b' - 26: 0, # 'c' - 17: 0, # 'd' - 1: 1, # 'e' - 27: 0, # 'f' - 12: 0, # 'g' - 20: 0, # 'h' - 9: 1, # 'i' - 22: 0, # 'j' - 7: 0, # 'k' - 6: 0, # 'l' - 13: 0, # 'm' - 4: 1, # 'n' - 8: 1, # 'o' - 23: 0, # 'p' - 10: 1, # 'r' - 5: 2, # 's' - 3: 0, # 't' - 21: 1, # 'u' - 19: 0, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 0, # 'z' - 51: 2, # 'Á' - 44: 1, # 'É' - 61: 1, # 'Í' - 58: 1, # 'Ó' - 59: 1, # 'Ö' - 60: 1, # 'Ú' - 63: 1, # 'Ü' - 14: 1, # 'á' - 15: 1, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 1, # 'ö' - 31: 1, # 'ú' - 29: 1, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 2: { # 'a' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 1, # 'a' - 18: 3, # 'b' - 26: 3, # 'c' - 17: 3, # 'd' - 1: 2, # 'e' - 27: 2, # 'f' - 12: 3, # 'g' - 20: 3, # 'h' - 9: 3, # 'i' - 22: 3, # 'j' - 7: 3, # 'k' - 6: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 8: 2, # 'o' - 23: 3, # 'p' - 10: 3, # 'r' - 5: 3, # 's' - 3: 3, # 't' - 21: 3, # 'u' - 19: 3, # 'v' - 62: 1, # 'x' - 16: 2, # 'y' - 11: 3, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 1, # 'á' - 15: 1, # 'é' - 30: 1, # 'í' - 25: 1, # 'ó' - 24: 1, # 'ö' - 31: 1, # 'ú' - 29: 1, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 18: { # 'b' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 3, # 'a' - 18: 3, # 'b' - 26: 1, # 'c' - 17: 1, # 'd' - 1: 3, # 'e' - 27: 1, # 'f' - 12: 1, # 'g' - 20: 1, # 'h' - 9: 3, # 'i' - 22: 2, # 'j' - 7: 2, # 'k' - 6: 2, # 'l' - 13: 1, # 'm' - 4: 2, # 'n' - 8: 3, # 'o' - 23: 1, # 'p' - 10: 3, # 'r' - 5: 2, # 's' - 3: 1, # 't' - 21: 3, # 'u' - 19: 1, # 'v' - 62: 0, # 'x' - 16: 1, # 'y' - 11: 1, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 3, # 'á' - 15: 3, # 'é' - 30: 2, # 'í' - 25: 3, # 'ó' - 24: 2, # 'ö' - 31: 2, # 'ú' - 29: 2, # 'ü' - 42: 2, # 'ő' - 56: 1, # 'ű' - }, - 26: { # 'c' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 1, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 1, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 2, # 'a' - 18: 1, # 'b' - 26: 2, # 'c' - 17: 1, # 'd' - 1: 3, # 'e' - 27: 1, # 'f' - 12: 1, # 'g' - 20: 3, # 'h' - 9: 3, # 'i' - 22: 1, # 'j' - 7: 2, # 'k' - 6: 1, # 'l' - 13: 1, # 'm' - 4: 1, # 'n' - 8: 3, # 'o' - 23: 1, # 'p' - 10: 2, # 'r' - 5: 3, # 's' - 3: 2, # 't' - 21: 2, # 'u' - 19: 1, # 'v' - 62: 0, # 'x' - 16: 1, # 'y' - 11: 2, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 2, # 'á' - 15: 2, # 'é' - 30: 2, # 'í' - 25: 1, # 'ó' - 24: 1, # 'ö' - 31: 1, # 'ú' - 29: 1, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 17: { # 'd' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 3, # 'a' - 18: 2, # 'b' - 26: 1, # 'c' - 17: 2, # 'd' - 1: 3, # 'e' - 27: 1, # 'f' - 12: 1, # 'g' - 20: 2, # 'h' - 9: 3, # 'i' - 22: 3, # 'j' - 7: 2, # 'k' - 6: 1, # 'l' - 13: 2, # 'm' - 4: 3, # 'n' - 8: 3, # 'o' - 23: 1, # 'p' - 10: 3, # 'r' - 5: 3, # 's' - 3: 3, # 't' - 21: 3, # 'u' - 19: 3, # 'v' - 62: 0, # 'x' - 16: 2, # 'y' - 11: 2, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 3, # 'á' - 15: 3, # 'é' - 30: 3, # 'í' - 25: 3, # 'ó' - 24: 3, # 'ö' - 31: 2, # 'ú' - 29: 2, # 'ü' - 42: 2, # 'ő' - 56: 1, # 'ű' - }, - 1: { # 'e' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 2, # 'a' - 18: 3, # 'b' - 26: 3, # 'c' - 17: 3, # 'd' - 1: 2, # 'e' - 27: 3, # 'f' - 12: 3, # 'g' - 20: 3, # 'h' - 9: 3, # 'i' - 22: 3, # 'j' - 7: 3, # 'k' - 6: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 8: 2, # 'o' - 23: 3, # 'p' - 10: 3, # 'r' - 5: 3, # 's' - 3: 3, # 't' - 21: 2, # 'u' - 19: 3, # 'v' - 62: 2, # 'x' - 16: 2, # 'y' - 11: 3, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 3, # 'á' - 15: 1, # 'é' - 30: 1, # 'í' - 25: 1, # 'ó' - 24: 1, # 'ö' - 31: 1, # 'ú' - 29: 1, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 27: { # 'f' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 3, # 'a' - 18: 1, # 'b' - 26: 1, # 'c' - 17: 1, # 'd' - 1: 3, # 'e' - 27: 2, # 'f' - 12: 1, # 'g' - 20: 1, # 'h' - 9: 3, # 'i' - 22: 2, # 'j' - 7: 1, # 'k' - 6: 1, # 'l' - 13: 1, # 'm' - 4: 1, # 'n' - 8: 3, # 'o' - 23: 0, # 'p' - 10: 3, # 'r' - 5: 1, # 's' - 3: 1, # 't' - 21: 2, # 'u' - 19: 1, # 'v' - 62: 0, # 'x' - 16: 1, # 'y' - 11: 0, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 3, # 'á' - 15: 3, # 'é' - 30: 1, # 'í' - 25: 1, # 'ó' - 24: 3, # 'ö' - 31: 1, # 'ú' - 29: 2, # 'ü' - 42: 1, # 'ő' - 56: 1, # 'ű' - }, - 12: { # 'g' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 3, # 'a' - 18: 3, # 'b' - 26: 2, # 'c' - 17: 2, # 'd' - 1: 3, # 'e' - 27: 2, # 'f' - 12: 3, # 'g' - 20: 3, # 'h' - 9: 3, # 'i' - 22: 3, # 'j' - 7: 2, # 'k' - 6: 3, # 'l' - 13: 2, # 'm' - 4: 3, # 'n' - 8: 3, # 'o' - 23: 1, # 'p' - 10: 3, # 'r' - 5: 3, # 's' - 3: 3, # 't' - 21: 3, # 'u' - 19: 3, # 'v' - 62: 0, # 'x' - 16: 3, # 'y' - 11: 2, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 3, # 'á' - 15: 3, # 'é' - 30: 2, # 'í' - 25: 3, # 'ó' - 24: 2, # 'ö' - 31: 2, # 'ú' - 29: 2, # 'ü' - 42: 2, # 'ő' - 56: 1, # 'ű' - }, - 20: { # 'h' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 3, # 'a' - 18: 1, # 'b' - 26: 1, # 'c' - 17: 0, # 'd' - 1: 3, # 'e' - 27: 0, # 'f' - 12: 1, # 'g' - 20: 2, # 'h' - 9: 3, # 'i' - 22: 1, # 'j' - 7: 1, # 'k' - 6: 1, # 'l' - 13: 1, # 'm' - 4: 1, # 'n' - 8: 3, # 'o' - 23: 0, # 'p' - 10: 1, # 'r' - 5: 2, # 's' - 3: 1, # 't' - 21: 3, # 'u' - 19: 1, # 'v' - 62: 0, # 'x' - 16: 2, # 'y' - 11: 0, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 3, # 'á' - 15: 3, # 'é' - 30: 3, # 'í' - 25: 2, # 'ó' - 24: 2, # 'ö' - 31: 2, # 'ú' - 29: 1, # 'ü' - 42: 1, # 'ő' - 56: 1, # 'ű' - }, - 9: { # 'i' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 3, # 'a' - 18: 3, # 'b' - 26: 3, # 'c' - 17: 3, # 'd' - 1: 3, # 'e' - 27: 3, # 'f' - 12: 3, # 'g' - 20: 3, # 'h' - 9: 2, # 'i' - 22: 2, # 'j' - 7: 3, # 'k' - 6: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 8: 2, # 'o' - 23: 2, # 'p' - 10: 3, # 'r' - 5: 3, # 's' - 3: 3, # 't' - 21: 3, # 'u' - 19: 3, # 'v' - 62: 1, # 'x' - 16: 1, # 'y' - 11: 3, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 3, # 'á' - 15: 2, # 'é' - 30: 1, # 'í' - 25: 3, # 'ó' - 24: 1, # 'ö' - 31: 2, # 'ú' - 29: 1, # 'ü' - 42: 0, # 'ő' - 56: 1, # 'ű' - }, - 22: { # 'j' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 3, # 'a' - 18: 2, # 'b' - 26: 1, # 'c' - 17: 3, # 'd' - 1: 3, # 'e' - 27: 1, # 'f' - 12: 1, # 'g' - 20: 2, # 'h' - 9: 1, # 'i' - 22: 2, # 'j' - 7: 2, # 'k' - 6: 2, # 'l' - 13: 1, # 'm' - 4: 2, # 'n' - 8: 3, # 'o' - 23: 1, # 'p' - 10: 2, # 'r' - 5: 2, # 's' - 3: 3, # 't' - 21: 3, # 'u' - 19: 1, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 2, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 3, # 'á' - 15: 3, # 'é' - 30: 1, # 'í' - 25: 3, # 'ó' - 24: 3, # 'ö' - 31: 3, # 'ú' - 29: 2, # 'ü' - 42: 1, # 'ő' - 56: 1, # 'ű' - }, - 7: { # 'k' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 3, # 'a' - 18: 3, # 'b' - 26: 2, # 'c' - 17: 1, # 'd' - 1: 3, # 'e' - 27: 1, # 'f' - 12: 1, # 'g' - 20: 2, # 'h' - 9: 3, # 'i' - 22: 2, # 'j' - 7: 3, # 'k' - 6: 3, # 'l' - 13: 1, # 'm' - 4: 3, # 'n' - 8: 3, # 'o' - 23: 1, # 'p' - 10: 3, # 'r' - 5: 3, # 's' - 3: 3, # 't' - 21: 3, # 'u' - 19: 2, # 'v' - 62: 0, # 'x' - 16: 2, # 'y' - 11: 1, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 3, # 'á' - 15: 3, # 'é' - 30: 3, # 'í' - 25: 2, # 'ó' - 24: 3, # 'ö' - 31: 1, # 'ú' - 29: 3, # 'ü' - 42: 1, # 'ő' - 56: 1, # 'ű' - }, - 6: { # 'l' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 1, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 1, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 3, # 'a' - 18: 2, # 'b' - 26: 3, # 'c' - 17: 3, # 'd' - 1: 3, # 'e' - 27: 3, # 'f' - 12: 3, # 'g' - 20: 3, # 'h' - 9: 3, # 'i' - 22: 3, # 'j' - 7: 3, # 'k' - 6: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 8: 3, # 'o' - 23: 2, # 'p' - 10: 2, # 'r' - 5: 3, # 's' - 3: 3, # 't' - 21: 3, # 'u' - 19: 3, # 'v' - 62: 0, # 'x' - 16: 3, # 'y' - 11: 2, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 3, # 'á' - 15: 3, # 'é' - 30: 3, # 'í' - 25: 3, # 'ó' - 24: 3, # 'ö' - 31: 2, # 'ú' - 29: 2, # 'ü' - 42: 3, # 'ő' - 56: 1, # 'ű' - }, - 13: { # 'm' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 3, # 'a' - 18: 3, # 'b' - 26: 2, # 'c' - 17: 1, # 'd' - 1: 3, # 'e' - 27: 1, # 'f' - 12: 1, # 'g' - 20: 2, # 'h' - 9: 3, # 'i' - 22: 2, # 'j' - 7: 1, # 'k' - 6: 3, # 'l' - 13: 3, # 'm' - 4: 2, # 'n' - 8: 3, # 'o' - 23: 3, # 'p' - 10: 2, # 'r' - 5: 2, # 's' - 3: 2, # 't' - 21: 3, # 'u' - 19: 1, # 'v' - 62: 0, # 'x' - 16: 1, # 'y' - 11: 2, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 3, # 'á' - 15: 3, # 'é' - 30: 2, # 'í' - 25: 2, # 'ó' - 24: 2, # 'ö' - 31: 2, # 'ú' - 29: 2, # 'ü' - 42: 1, # 'ő' - 56: 2, # 'ű' - }, - 4: { # 'n' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 3, # 'a' - 18: 3, # 'b' - 26: 3, # 'c' - 17: 3, # 'd' - 1: 3, # 'e' - 27: 2, # 'f' - 12: 3, # 'g' - 20: 3, # 'h' - 9: 3, # 'i' - 22: 2, # 'j' - 7: 3, # 'k' - 6: 2, # 'l' - 13: 2, # 'm' - 4: 3, # 'n' - 8: 3, # 'o' - 23: 2, # 'p' - 10: 2, # 'r' - 5: 3, # 's' - 3: 3, # 't' - 21: 3, # 'u' - 19: 2, # 'v' - 62: 1, # 'x' - 16: 3, # 'y' - 11: 3, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 3, # 'á' - 15: 3, # 'é' - 30: 2, # 'í' - 25: 2, # 'ó' - 24: 3, # 'ö' - 31: 2, # 'ú' - 29: 3, # 'ü' - 42: 2, # 'ő' - 56: 1, # 'ű' - }, - 8: { # 'o' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 1, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 2, # 'a' - 18: 3, # 'b' - 26: 3, # 'c' - 17: 3, # 'd' - 1: 2, # 'e' - 27: 2, # 'f' - 12: 3, # 'g' - 20: 3, # 'h' - 9: 2, # 'i' - 22: 2, # 'j' - 7: 3, # 'k' - 6: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 8: 1, # 'o' - 23: 3, # 'p' - 10: 3, # 'r' - 5: 3, # 's' - 3: 3, # 't' - 21: 2, # 'u' - 19: 3, # 'v' - 62: 1, # 'x' - 16: 1, # 'y' - 11: 3, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 1, # 'á' - 15: 2, # 'é' - 30: 1, # 'í' - 25: 1, # 'ó' - 24: 1, # 'ö' - 31: 1, # 'ú' - 29: 1, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 23: { # 'p' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 3, # 'a' - 18: 1, # 'b' - 26: 2, # 'c' - 17: 1, # 'd' - 1: 3, # 'e' - 27: 1, # 'f' - 12: 1, # 'g' - 20: 2, # 'h' - 9: 3, # 'i' - 22: 2, # 'j' - 7: 2, # 'k' - 6: 3, # 'l' - 13: 1, # 'm' - 4: 2, # 'n' - 8: 3, # 'o' - 23: 3, # 'p' - 10: 3, # 'r' - 5: 2, # 's' - 3: 2, # 't' - 21: 3, # 'u' - 19: 2, # 'v' - 62: 0, # 'x' - 16: 1, # 'y' - 11: 2, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 3, # 'á' - 15: 3, # 'é' - 30: 2, # 'í' - 25: 2, # 'ó' - 24: 2, # 'ö' - 31: 1, # 'ú' - 29: 2, # 'ü' - 42: 1, # 'ő' - 56: 1, # 'ű' - }, - 10: { # 'r' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 3, # 'a' - 18: 3, # 'b' - 26: 3, # 'c' - 17: 3, # 'd' - 1: 3, # 'e' - 27: 2, # 'f' - 12: 3, # 'g' - 20: 2, # 'h' - 9: 3, # 'i' - 22: 3, # 'j' - 7: 3, # 'k' - 6: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 8: 3, # 'o' - 23: 2, # 'p' - 10: 3, # 'r' - 5: 3, # 's' - 3: 3, # 't' - 21: 3, # 'u' - 19: 3, # 'v' - 62: 1, # 'x' - 16: 2, # 'y' - 11: 3, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 3, # 'á' - 15: 3, # 'é' - 30: 2, # 'í' - 25: 3, # 'ó' - 24: 3, # 'ö' - 31: 3, # 'ú' - 29: 3, # 'ü' - 42: 2, # 'ő' - 56: 2, # 'ű' - }, - 5: { # 's' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 3, # 'a' - 18: 3, # 'b' - 26: 2, # 'c' - 17: 2, # 'd' - 1: 3, # 'e' - 27: 2, # 'f' - 12: 2, # 'g' - 20: 2, # 'h' - 9: 3, # 'i' - 22: 1, # 'j' - 7: 3, # 'k' - 6: 2, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 8: 3, # 'o' - 23: 2, # 'p' - 10: 3, # 'r' - 5: 3, # 's' - 3: 3, # 't' - 21: 3, # 'u' - 19: 2, # 'v' - 62: 0, # 'x' - 16: 1, # 'y' - 11: 3, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 3, # 'á' - 15: 3, # 'é' - 30: 3, # 'í' - 25: 3, # 'ó' - 24: 3, # 'ö' - 31: 3, # 'ú' - 29: 3, # 'ü' - 42: 2, # 'ő' - 56: 1, # 'ű' - }, - 3: { # 't' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 3, # 'a' - 18: 3, # 'b' - 26: 2, # 'c' - 17: 1, # 'd' - 1: 3, # 'e' - 27: 2, # 'f' - 12: 1, # 'g' - 20: 3, # 'h' - 9: 3, # 'i' - 22: 3, # 'j' - 7: 3, # 'k' - 6: 3, # 'l' - 13: 2, # 'm' - 4: 3, # 'n' - 8: 3, # 'o' - 23: 1, # 'p' - 10: 3, # 'r' - 5: 3, # 's' - 3: 3, # 't' - 21: 3, # 'u' - 19: 3, # 'v' - 62: 0, # 'x' - 16: 3, # 'y' - 11: 1, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 3, # 'á' - 15: 3, # 'é' - 30: 2, # 'í' - 25: 3, # 'ó' - 24: 3, # 'ö' - 31: 3, # 'ú' - 29: 3, # 'ü' - 42: 3, # 'ő' - 56: 2, # 'ű' - }, - 21: { # 'u' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 1, # 'a' - 18: 2, # 'b' - 26: 2, # 'c' - 17: 3, # 'd' - 1: 2, # 'e' - 27: 1, # 'f' - 12: 3, # 'g' - 20: 2, # 'h' - 9: 2, # 'i' - 22: 2, # 'j' - 7: 3, # 'k' - 6: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 8: 1, # 'o' - 23: 2, # 'p' - 10: 3, # 'r' - 5: 3, # 's' - 3: 3, # 't' - 21: 1, # 'u' - 19: 3, # 'v' - 62: 1, # 'x' - 16: 1, # 'y' - 11: 2, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 2, # 'á' - 15: 1, # 'é' - 30: 1, # 'í' - 25: 1, # 'ó' - 24: 0, # 'ö' - 31: 1, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 19: { # 'v' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 3, # 'a' - 18: 2, # 'b' - 26: 1, # 'c' - 17: 1, # 'd' - 1: 3, # 'e' - 27: 1, # 'f' - 12: 1, # 'g' - 20: 1, # 'h' - 9: 3, # 'i' - 22: 1, # 'j' - 7: 1, # 'k' - 6: 1, # 'l' - 13: 1, # 'm' - 4: 1, # 'n' - 8: 3, # 'o' - 23: 1, # 'p' - 10: 1, # 'r' - 5: 2, # 's' - 3: 2, # 't' - 21: 2, # 'u' - 19: 2, # 'v' - 62: 0, # 'x' - 16: 1, # 'y' - 11: 1, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 3, # 'á' - 15: 3, # 'é' - 30: 2, # 'í' - 25: 2, # 'ó' - 24: 2, # 'ö' - 31: 1, # 'ú' - 29: 2, # 'ü' - 42: 1, # 'ő' - 56: 1, # 'ű' - }, - 62: { # 'x' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 1, # 'a' - 18: 1, # 'b' - 26: 1, # 'c' - 17: 0, # 'd' - 1: 1, # 'e' - 27: 1, # 'f' - 12: 0, # 'g' - 20: 0, # 'h' - 9: 1, # 'i' - 22: 0, # 'j' - 7: 1, # 'k' - 6: 1, # 'l' - 13: 1, # 'm' - 4: 1, # 'n' - 8: 1, # 'o' - 23: 1, # 'p' - 10: 1, # 'r' - 5: 1, # 's' - 3: 1, # 't' - 21: 1, # 'u' - 19: 0, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 0, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 1, # 'á' - 15: 1, # 'é' - 30: 1, # 'í' - 25: 1, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 16: { # 'y' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 3, # 'a' - 18: 2, # 'b' - 26: 1, # 'c' - 17: 1, # 'd' - 1: 3, # 'e' - 27: 2, # 'f' - 12: 2, # 'g' - 20: 2, # 'h' - 9: 3, # 'i' - 22: 2, # 'j' - 7: 2, # 'k' - 6: 2, # 'l' - 13: 2, # 'm' - 4: 3, # 'n' - 8: 3, # 'o' - 23: 2, # 'p' - 10: 2, # 'r' - 5: 3, # 's' - 3: 3, # 't' - 21: 3, # 'u' - 19: 3, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 2, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 3, # 'á' - 15: 3, # 'é' - 30: 2, # 'í' - 25: 2, # 'ó' - 24: 3, # 'ö' - 31: 2, # 'ú' - 29: 2, # 'ü' - 42: 1, # 'ő' - 56: 2, # 'ű' - }, - 11: { # 'z' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 3, # 'a' - 18: 2, # 'b' - 26: 1, # 'c' - 17: 3, # 'd' - 1: 3, # 'e' - 27: 1, # 'f' - 12: 2, # 'g' - 20: 2, # 'h' - 9: 3, # 'i' - 22: 1, # 'j' - 7: 3, # 'k' - 6: 2, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 8: 3, # 'o' - 23: 1, # 'p' - 10: 2, # 'r' - 5: 3, # 's' - 3: 3, # 't' - 21: 3, # 'u' - 19: 2, # 'v' - 62: 0, # 'x' - 16: 1, # 'y' - 11: 3, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 3, # 'á' - 15: 3, # 'é' - 30: 3, # 'í' - 25: 3, # 'ó' - 24: 3, # 'ö' - 31: 2, # 'ú' - 29: 3, # 'ü' - 42: 2, # 'ő' - 56: 1, # 'ű' - }, - 51: { # 'Á' - 28: 0, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 0, # 'E' - 50: 1, # 'F' - 49: 2, # 'G' - 38: 1, # 'H' - 39: 1, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 2, # 'L' - 34: 1, # 'M' - 35: 2, # 'N' - 47: 0, # 'O' - 46: 1, # 'P' - 43: 2, # 'R' - 33: 2, # 'S' - 37: 1, # 'T' - 57: 0, # 'U' - 48: 1, # 'V' - 55: 0, # 'Y' - 52: 1, # 'Z' - 2: 0, # 'a' - 18: 1, # 'b' - 26: 1, # 'c' - 17: 1, # 'd' - 1: 0, # 'e' - 27: 0, # 'f' - 12: 1, # 'g' - 20: 1, # 'h' - 9: 0, # 'i' - 22: 1, # 'j' - 7: 1, # 'k' - 6: 2, # 'l' - 13: 2, # 'm' - 4: 0, # 'n' - 8: 0, # 'o' - 23: 1, # 'p' - 10: 1, # 'r' - 5: 1, # 's' - 3: 1, # 't' - 21: 0, # 'u' - 19: 0, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 1, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 1, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 0, # 'á' - 15: 0, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 44: { # 'É' - 28: 0, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 1, # 'E' - 50: 0, # 'F' - 49: 2, # 'G' - 38: 1, # 'H' - 39: 1, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 2, # 'L' - 34: 1, # 'M' - 35: 2, # 'N' - 47: 0, # 'O' - 46: 1, # 'P' - 43: 2, # 'R' - 33: 2, # 'S' - 37: 2, # 'T' - 57: 0, # 'U' - 48: 1, # 'V' - 55: 0, # 'Y' - 52: 1, # 'Z' - 2: 0, # 'a' - 18: 1, # 'b' - 26: 1, # 'c' - 17: 1, # 'd' - 1: 0, # 'e' - 27: 0, # 'f' - 12: 1, # 'g' - 20: 1, # 'h' - 9: 0, # 'i' - 22: 1, # 'j' - 7: 1, # 'k' - 6: 2, # 'l' - 13: 1, # 'm' - 4: 2, # 'n' - 8: 0, # 'o' - 23: 1, # 'p' - 10: 2, # 'r' - 5: 3, # 's' - 3: 1, # 't' - 21: 0, # 'u' - 19: 1, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 0, # 'z' - 51: 0, # 'Á' - 44: 1, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 0, # 'á' - 15: 0, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 61: { # 'Í' - 28: 0, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 0, # 'E' - 50: 1, # 'F' - 49: 1, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 1, # 'J' - 36: 0, # 'K' - 41: 1, # 'L' - 34: 1, # 'M' - 35: 1, # 'N' - 47: 0, # 'O' - 46: 1, # 'P' - 43: 1, # 'R' - 33: 1, # 'S' - 37: 1, # 'T' - 57: 0, # 'U' - 48: 1, # 'V' - 55: 0, # 'Y' - 52: 1, # 'Z' - 2: 0, # 'a' - 18: 0, # 'b' - 26: 0, # 'c' - 17: 0, # 'd' - 1: 0, # 'e' - 27: 0, # 'f' - 12: 2, # 'g' - 20: 0, # 'h' - 9: 0, # 'i' - 22: 0, # 'j' - 7: 0, # 'k' - 6: 0, # 'l' - 13: 1, # 'm' - 4: 0, # 'n' - 8: 0, # 'o' - 23: 0, # 'p' - 10: 1, # 'r' - 5: 0, # 's' - 3: 1, # 't' - 21: 0, # 'u' - 19: 0, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 1, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 0, # 'á' - 15: 0, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 58: { # 'Ó' - 28: 1, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 0, # 'E' - 50: 1, # 'F' - 49: 1, # 'G' - 38: 1, # 'H' - 39: 1, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 2, # 'L' - 34: 1, # 'M' - 35: 1, # 'N' - 47: 0, # 'O' - 46: 1, # 'P' - 43: 1, # 'R' - 33: 1, # 'S' - 37: 1, # 'T' - 57: 0, # 'U' - 48: 1, # 'V' - 55: 0, # 'Y' - 52: 1, # 'Z' - 2: 0, # 'a' - 18: 1, # 'b' - 26: 1, # 'c' - 17: 1, # 'd' - 1: 0, # 'e' - 27: 0, # 'f' - 12: 0, # 'g' - 20: 2, # 'h' - 9: 0, # 'i' - 22: 0, # 'j' - 7: 1, # 'k' - 6: 1, # 'l' - 13: 0, # 'm' - 4: 1, # 'n' - 8: 0, # 'o' - 23: 1, # 'p' - 10: 1, # 'r' - 5: 1, # 's' - 3: 0, # 't' - 21: 0, # 'u' - 19: 1, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 1, # 'z' - 51: 0, # 'Á' - 44: 1, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 0, # 'á' - 15: 0, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 59: { # 'Ö' - 28: 0, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 1, # 'G' - 38: 1, # 'H' - 39: 0, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 1, # 'L' - 34: 1, # 'M' - 35: 1, # 'N' - 47: 0, # 'O' - 46: 1, # 'P' - 43: 1, # 'R' - 33: 1, # 'S' - 37: 1, # 'T' - 57: 0, # 'U' - 48: 1, # 'V' - 55: 0, # 'Y' - 52: 1, # 'Z' - 2: 0, # 'a' - 18: 0, # 'b' - 26: 1, # 'c' - 17: 1, # 'd' - 1: 0, # 'e' - 27: 0, # 'f' - 12: 0, # 'g' - 20: 0, # 'h' - 9: 0, # 'i' - 22: 0, # 'j' - 7: 1, # 'k' - 6: 1, # 'l' - 13: 1, # 'm' - 4: 1, # 'n' - 8: 0, # 'o' - 23: 0, # 'p' - 10: 2, # 'r' - 5: 1, # 's' - 3: 1, # 't' - 21: 0, # 'u' - 19: 1, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 1, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 0, # 'á' - 15: 0, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 60: { # 'Ú' - 28: 0, # 'A' - 40: 1, # 'B' - 54: 1, # 'C' - 45: 1, # 'D' - 32: 0, # 'E' - 50: 1, # 'F' - 49: 1, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 1, # 'L' - 34: 1, # 'M' - 35: 1, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 1, # 'R' - 33: 1, # 'S' - 37: 1, # 'T' - 57: 0, # 'U' - 48: 1, # 'V' - 55: 0, # 'Y' - 52: 1, # 'Z' - 2: 0, # 'a' - 18: 0, # 'b' - 26: 0, # 'c' - 17: 0, # 'd' - 1: 0, # 'e' - 27: 0, # 'f' - 12: 2, # 'g' - 20: 0, # 'h' - 9: 0, # 'i' - 22: 2, # 'j' - 7: 0, # 'k' - 6: 0, # 'l' - 13: 0, # 'm' - 4: 1, # 'n' - 8: 0, # 'o' - 23: 0, # 'p' - 10: 1, # 'r' - 5: 1, # 's' - 3: 1, # 't' - 21: 0, # 'u' - 19: 0, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 0, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 0, # 'á' - 15: 0, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 63: { # 'Ü' - 28: 0, # 'A' - 40: 1, # 'B' - 54: 0, # 'C' - 45: 1, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 1, # 'G' - 38: 1, # 'H' - 39: 0, # 'I' - 53: 1, # 'J' - 36: 1, # 'K' - 41: 1, # 'L' - 34: 1, # 'M' - 35: 1, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 1, # 'R' - 33: 1, # 'S' - 37: 1, # 'T' - 57: 0, # 'U' - 48: 1, # 'V' - 55: 0, # 'Y' - 52: 1, # 'Z' - 2: 0, # 'a' - 18: 1, # 'b' - 26: 0, # 'c' - 17: 1, # 'd' - 1: 0, # 'e' - 27: 0, # 'f' - 12: 1, # 'g' - 20: 0, # 'h' - 9: 0, # 'i' - 22: 0, # 'j' - 7: 0, # 'k' - 6: 1, # 'l' - 13: 0, # 'm' - 4: 1, # 'n' - 8: 0, # 'o' - 23: 0, # 'p' - 10: 1, # 'r' - 5: 1, # 's' - 3: 1, # 't' - 21: 0, # 'u' - 19: 1, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 1, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 0, # 'á' - 15: 0, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 14: { # 'á' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 1, # 'a' - 18: 3, # 'b' - 26: 3, # 'c' - 17: 3, # 'd' - 1: 1, # 'e' - 27: 2, # 'f' - 12: 3, # 'g' - 20: 2, # 'h' - 9: 2, # 'i' - 22: 3, # 'j' - 7: 3, # 'k' - 6: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 8: 1, # 'o' - 23: 2, # 'p' - 10: 3, # 'r' - 5: 3, # 's' - 3: 3, # 't' - 21: 2, # 'u' - 19: 3, # 'v' - 62: 0, # 'x' - 16: 1, # 'y' - 11: 3, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 1, # 'á' - 15: 2, # 'é' - 30: 1, # 'í' - 25: 0, # 'ó' - 24: 1, # 'ö' - 31: 0, # 'ú' - 29: 1, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 15: { # 'é' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 1, # 'a' - 18: 3, # 'b' - 26: 2, # 'c' - 17: 3, # 'd' - 1: 1, # 'e' - 27: 1, # 'f' - 12: 3, # 'g' - 20: 3, # 'h' - 9: 2, # 'i' - 22: 2, # 'j' - 7: 3, # 'k' - 6: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 8: 1, # 'o' - 23: 3, # 'p' - 10: 3, # 'r' - 5: 3, # 's' - 3: 3, # 't' - 21: 0, # 'u' - 19: 3, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 3, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 1, # 'á' - 15: 1, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 1, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 30: { # 'í' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 0, # 'a' - 18: 1, # 'b' - 26: 2, # 'c' - 17: 1, # 'd' - 1: 0, # 'e' - 27: 1, # 'f' - 12: 3, # 'g' - 20: 0, # 'h' - 9: 0, # 'i' - 22: 1, # 'j' - 7: 1, # 'k' - 6: 2, # 'l' - 13: 2, # 'm' - 4: 3, # 'n' - 8: 0, # 'o' - 23: 1, # 'p' - 10: 3, # 'r' - 5: 2, # 's' - 3: 3, # 't' - 21: 0, # 'u' - 19: 3, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 2, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 0, # 'á' - 15: 0, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 25: { # 'ó' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 2, # 'a' - 18: 3, # 'b' - 26: 2, # 'c' - 17: 3, # 'd' - 1: 1, # 'e' - 27: 2, # 'f' - 12: 2, # 'g' - 20: 2, # 'h' - 9: 2, # 'i' - 22: 2, # 'j' - 7: 3, # 'k' - 6: 3, # 'l' - 13: 2, # 'm' - 4: 3, # 'n' - 8: 1, # 'o' - 23: 2, # 'p' - 10: 3, # 'r' - 5: 3, # 's' - 3: 3, # 't' - 21: 1, # 'u' - 19: 2, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 3, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 1, # 'á' - 15: 1, # 'é' - 30: 1, # 'í' - 25: 0, # 'ó' - 24: 1, # 'ö' - 31: 1, # 'ú' - 29: 1, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 24: { # 'ö' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 0, # 'a' - 18: 3, # 'b' - 26: 1, # 'c' - 17: 2, # 'd' - 1: 0, # 'e' - 27: 1, # 'f' - 12: 2, # 'g' - 20: 1, # 'h' - 9: 0, # 'i' - 22: 1, # 'j' - 7: 3, # 'k' - 6: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 8: 0, # 'o' - 23: 2, # 'p' - 10: 3, # 'r' - 5: 3, # 's' - 3: 3, # 't' - 21: 0, # 'u' - 19: 3, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 3, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 0, # 'á' - 15: 0, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 31: { # 'ú' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 1, # 'a' - 18: 1, # 'b' - 26: 2, # 'c' - 17: 1, # 'd' - 1: 1, # 'e' - 27: 2, # 'f' - 12: 3, # 'g' - 20: 1, # 'h' - 9: 1, # 'i' - 22: 3, # 'j' - 7: 1, # 'k' - 6: 3, # 'l' - 13: 1, # 'm' - 4: 2, # 'n' - 8: 0, # 'o' - 23: 1, # 'p' - 10: 3, # 'r' - 5: 3, # 's' - 3: 2, # 't' - 21: 1, # 'u' - 19: 1, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 2, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 1, # 'á' - 15: 1, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 29: { # 'ü' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 1, # 'a' - 18: 1, # 'b' - 26: 1, # 'c' - 17: 2, # 'd' - 1: 1, # 'e' - 27: 1, # 'f' - 12: 3, # 'g' - 20: 2, # 'h' - 9: 1, # 'i' - 22: 1, # 'j' - 7: 3, # 'k' - 6: 3, # 'l' - 13: 1, # 'm' - 4: 3, # 'n' - 8: 0, # 'o' - 23: 1, # 'p' - 10: 2, # 'r' - 5: 2, # 's' - 3: 2, # 't' - 21: 0, # 'u' - 19: 2, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 2, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 0, # 'á' - 15: 1, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 42: { # 'ő' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 1, # 'a' - 18: 2, # 'b' - 26: 1, # 'c' - 17: 2, # 'd' - 1: 1, # 'e' - 27: 1, # 'f' - 12: 1, # 'g' - 20: 1, # 'h' - 9: 1, # 'i' - 22: 1, # 'j' - 7: 2, # 'k' - 6: 3, # 'l' - 13: 1, # 'm' - 4: 2, # 'n' - 8: 1, # 'o' - 23: 1, # 'p' - 10: 2, # 'r' - 5: 2, # 's' - 3: 2, # 't' - 21: 1, # 'u' - 19: 1, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 2, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 0, # 'á' - 15: 1, # 'é' - 30: 1, # 'í' - 25: 0, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 1, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, - 56: { # 'ű' - 28: 0, # 'A' - 40: 0, # 'B' - 54: 0, # 'C' - 45: 0, # 'D' - 32: 0, # 'E' - 50: 0, # 'F' - 49: 0, # 'G' - 38: 0, # 'H' - 39: 0, # 'I' - 53: 0, # 'J' - 36: 0, # 'K' - 41: 0, # 'L' - 34: 0, # 'M' - 35: 0, # 'N' - 47: 0, # 'O' - 46: 0, # 'P' - 43: 0, # 'R' - 33: 0, # 'S' - 37: 0, # 'T' - 57: 0, # 'U' - 48: 0, # 'V' - 55: 0, # 'Y' - 52: 0, # 'Z' - 2: 1, # 'a' - 18: 1, # 'b' - 26: 0, # 'c' - 17: 1, # 'd' - 1: 1, # 'e' - 27: 1, # 'f' - 12: 1, # 'g' - 20: 1, # 'h' - 9: 1, # 'i' - 22: 1, # 'j' - 7: 1, # 'k' - 6: 1, # 'l' - 13: 0, # 'm' - 4: 2, # 'n' - 8: 0, # 'o' - 23: 0, # 'p' - 10: 1, # 'r' - 5: 1, # 's' - 3: 1, # 't' - 21: 0, # 'u' - 19: 1, # 'v' - 62: 0, # 'x' - 16: 0, # 'y' - 11: 2, # 'z' - 51: 0, # 'Á' - 44: 0, # 'É' - 61: 0, # 'Í' - 58: 0, # 'Ó' - 59: 0, # 'Ö' - 60: 0, # 'Ú' - 63: 0, # 'Ü' - 14: 0, # 'á' - 15: 0, # 'é' - 30: 0, # 'í' - 25: 0, # 'ó' - 24: 0, # 'ö' - 31: 0, # 'ú' - 29: 0, # 'ü' - 42: 0, # 'ő' - 56: 0, # 'ű' - }, -} - -# 255: Undefined characters that did not exist in training text -# 254: Carriage/Return -# 253: symbol (punctuation) that does not belong to word -# 252: 0 - 9 -# 251: Control characters - -# Character Mapping Table(s): -WINDOWS_1250_HUNGARIAN_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 28, # 'A' - 66: 40, # 'B' - 67: 54, # 'C' - 68: 45, # 'D' - 69: 32, # 'E' - 70: 50, # 'F' - 71: 49, # 'G' - 72: 38, # 'H' - 73: 39, # 'I' - 74: 53, # 'J' - 75: 36, # 'K' - 76: 41, # 'L' - 77: 34, # 'M' - 78: 35, # 'N' - 79: 47, # 'O' - 80: 46, # 'P' - 81: 72, # 'Q' - 82: 43, # 'R' - 83: 33, # 'S' - 84: 37, # 'T' - 85: 57, # 'U' - 86: 48, # 'V' - 87: 64, # 'W' - 88: 68, # 'X' - 89: 55, # 'Y' - 90: 52, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 2, # 'a' - 98: 18, # 'b' - 99: 26, # 'c' - 100: 17, # 'd' - 101: 1, # 'e' - 102: 27, # 'f' - 103: 12, # 'g' - 104: 20, # 'h' - 105: 9, # 'i' - 106: 22, # 'j' - 107: 7, # 'k' - 108: 6, # 'l' - 109: 13, # 'm' - 110: 4, # 'n' - 111: 8, # 'o' - 112: 23, # 'p' - 113: 67, # 'q' - 114: 10, # 'r' - 115: 5, # 's' - 116: 3, # 't' - 117: 21, # 'u' - 118: 19, # 'v' - 119: 65, # 'w' - 120: 62, # 'x' - 121: 16, # 'y' - 122: 11, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 161, # '€' - 129: 162, # None - 130: 163, # '‚' - 131: 164, # None - 132: 165, # '„' - 133: 166, # '…' - 134: 167, # '†' - 135: 168, # '‡' - 136: 169, # None - 137: 170, # '‰' - 138: 171, # 'Š' - 139: 172, # '‹' - 140: 173, # 'Ś' - 141: 174, # 'Ť' - 142: 175, # 'Ž' - 143: 176, # 'Ź' - 144: 177, # None - 145: 178, # '‘' - 146: 179, # '’' - 147: 180, # '“' - 148: 78, # '”' - 149: 181, # '•' - 150: 69, # '–' - 151: 182, # '—' - 152: 183, # None - 153: 184, # '™' - 154: 185, # 'š' - 155: 186, # '›' - 156: 187, # 'ś' - 157: 188, # 'ť' - 158: 189, # 'ž' - 159: 190, # 'ź' - 160: 191, # '\xa0' - 161: 192, # 'ˇ' - 162: 193, # '˘' - 163: 194, # 'Ł' - 164: 195, # '¤' - 165: 196, # 'Ą' - 166: 197, # '¦' - 167: 76, # '§' - 168: 198, # '¨' - 169: 199, # '©' - 170: 200, # 'Ş' - 171: 201, # '«' - 172: 202, # '¬' - 173: 203, # '\xad' - 174: 204, # '®' - 175: 205, # 'Ż' - 176: 81, # '°' - 177: 206, # '±' - 178: 207, # '˛' - 179: 208, # 'ł' - 180: 209, # '´' - 181: 210, # 'µ' - 182: 211, # '¶' - 183: 212, # '·' - 184: 213, # '¸' - 185: 214, # 'ą' - 186: 215, # 'ş' - 187: 216, # '»' - 188: 217, # 'Ľ' - 189: 218, # '˝' - 190: 219, # 'ľ' - 191: 220, # 'ż' - 192: 221, # 'Ŕ' - 193: 51, # 'Á' - 194: 83, # 'Â' - 195: 222, # 'Ă' - 196: 80, # 'Ä' - 197: 223, # 'Ĺ' - 198: 224, # 'Ć' - 199: 225, # 'Ç' - 200: 226, # 'Č' - 201: 44, # 'É' - 202: 227, # 'Ę' - 203: 228, # 'Ë' - 204: 229, # 'Ě' - 205: 61, # 'Í' - 206: 230, # 'Î' - 207: 231, # 'Ď' - 208: 232, # 'Đ' - 209: 233, # 'Ń' - 210: 234, # 'Ň' - 211: 58, # 'Ó' - 212: 235, # 'Ô' - 213: 66, # 'Ő' - 214: 59, # 'Ö' - 215: 236, # '×' - 216: 237, # 'Ř' - 217: 238, # 'Ů' - 218: 60, # 'Ú' - 219: 70, # 'Ű' - 220: 63, # 'Ü' - 221: 239, # 'Ý' - 222: 240, # 'Ţ' - 223: 241, # 'ß' - 224: 84, # 'ŕ' - 225: 14, # 'á' - 226: 75, # 'â' - 227: 242, # 'ă' - 228: 71, # 'ä' - 229: 82, # 'ĺ' - 230: 243, # 'ć' - 231: 73, # 'ç' - 232: 244, # 'č' - 233: 15, # 'é' - 234: 85, # 'ę' - 235: 79, # 'ë' - 236: 86, # 'ě' - 237: 30, # 'í' - 238: 77, # 'î' - 239: 87, # 'ď' - 240: 245, # 'đ' - 241: 246, # 'ń' - 242: 247, # 'ň' - 243: 25, # 'ó' - 244: 74, # 'ô' - 245: 42, # 'ő' - 246: 24, # 'ö' - 247: 248, # '÷' - 248: 249, # 'ř' - 249: 250, # 'ů' - 250: 31, # 'ú' - 251: 56, # 'ű' - 252: 29, # 'ü' - 253: 251, # 'ý' - 254: 252, # 'ţ' - 255: 253, # '˙' -} - -WINDOWS_1250_HUNGARIAN_MODEL = SingleByteCharSetModel(charset_name='windows-1250', - language='Hungarian', - char_to_order_map=WINDOWS_1250_HUNGARIAN_CHAR_TO_ORDER, - language_model=HUNGARIAN_LANG_MODEL, - typical_positive_ratio=0.947368, - keep_ascii_letters=True, - alphabet='ABCDEFGHIJKLMNOPRSTUVZabcdefghijklmnoprstuvzÁÉÍÓÖÚÜáéíóöúüŐőŰű') - -ISO_8859_2_HUNGARIAN_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 28, # 'A' - 66: 40, # 'B' - 67: 54, # 'C' - 68: 45, # 'D' - 69: 32, # 'E' - 70: 50, # 'F' - 71: 49, # 'G' - 72: 38, # 'H' - 73: 39, # 'I' - 74: 53, # 'J' - 75: 36, # 'K' - 76: 41, # 'L' - 77: 34, # 'M' - 78: 35, # 'N' - 79: 47, # 'O' - 80: 46, # 'P' - 81: 71, # 'Q' - 82: 43, # 'R' - 83: 33, # 'S' - 84: 37, # 'T' - 85: 57, # 'U' - 86: 48, # 'V' - 87: 64, # 'W' - 88: 68, # 'X' - 89: 55, # 'Y' - 90: 52, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 2, # 'a' - 98: 18, # 'b' - 99: 26, # 'c' - 100: 17, # 'd' - 101: 1, # 'e' - 102: 27, # 'f' - 103: 12, # 'g' - 104: 20, # 'h' - 105: 9, # 'i' - 106: 22, # 'j' - 107: 7, # 'k' - 108: 6, # 'l' - 109: 13, # 'm' - 110: 4, # 'n' - 111: 8, # 'o' - 112: 23, # 'p' - 113: 67, # 'q' - 114: 10, # 'r' - 115: 5, # 's' - 116: 3, # 't' - 117: 21, # 'u' - 118: 19, # 'v' - 119: 65, # 'w' - 120: 62, # 'x' - 121: 16, # 'y' - 122: 11, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 159, # '\x80' - 129: 160, # '\x81' - 130: 161, # '\x82' - 131: 162, # '\x83' - 132: 163, # '\x84' - 133: 164, # '\x85' - 134: 165, # '\x86' - 135: 166, # '\x87' - 136: 167, # '\x88' - 137: 168, # '\x89' - 138: 169, # '\x8a' - 139: 170, # '\x8b' - 140: 171, # '\x8c' - 141: 172, # '\x8d' - 142: 173, # '\x8e' - 143: 174, # '\x8f' - 144: 175, # '\x90' - 145: 176, # '\x91' - 146: 177, # '\x92' - 147: 178, # '\x93' - 148: 179, # '\x94' - 149: 180, # '\x95' - 150: 181, # '\x96' - 151: 182, # '\x97' - 152: 183, # '\x98' - 153: 184, # '\x99' - 154: 185, # '\x9a' - 155: 186, # '\x9b' - 156: 187, # '\x9c' - 157: 188, # '\x9d' - 158: 189, # '\x9e' - 159: 190, # '\x9f' - 160: 191, # '\xa0' - 161: 192, # 'Ą' - 162: 193, # '˘' - 163: 194, # 'Ł' - 164: 195, # '¤' - 165: 196, # 'Ľ' - 166: 197, # 'Ś' - 167: 75, # '§' - 168: 198, # '¨' - 169: 199, # 'Š' - 170: 200, # 'Ş' - 171: 201, # 'Ť' - 172: 202, # 'Ź' - 173: 203, # '\xad' - 174: 204, # 'Ž' - 175: 205, # 'Ż' - 176: 79, # '°' - 177: 206, # 'ą' - 178: 207, # '˛' - 179: 208, # 'ł' - 180: 209, # '´' - 181: 210, # 'ľ' - 182: 211, # 'ś' - 183: 212, # 'ˇ' - 184: 213, # '¸' - 185: 214, # 'š' - 186: 215, # 'ş' - 187: 216, # 'ť' - 188: 217, # 'ź' - 189: 218, # '˝' - 190: 219, # 'ž' - 191: 220, # 'ż' - 192: 221, # 'Ŕ' - 193: 51, # 'Á' - 194: 81, # 'Â' - 195: 222, # 'Ă' - 196: 78, # 'Ä' - 197: 223, # 'Ĺ' - 198: 224, # 'Ć' - 199: 225, # 'Ç' - 200: 226, # 'Č' - 201: 44, # 'É' - 202: 227, # 'Ę' - 203: 228, # 'Ë' - 204: 229, # 'Ě' - 205: 61, # 'Í' - 206: 230, # 'Î' - 207: 231, # 'Ď' - 208: 232, # 'Đ' - 209: 233, # 'Ń' - 210: 234, # 'Ň' - 211: 58, # 'Ó' - 212: 235, # 'Ô' - 213: 66, # 'Ő' - 214: 59, # 'Ö' - 215: 236, # '×' - 216: 237, # 'Ř' - 217: 238, # 'Ů' - 218: 60, # 'Ú' - 219: 69, # 'Ű' - 220: 63, # 'Ü' - 221: 239, # 'Ý' - 222: 240, # 'Ţ' - 223: 241, # 'ß' - 224: 82, # 'ŕ' - 225: 14, # 'á' - 226: 74, # 'â' - 227: 242, # 'ă' - 228: 70, # 'ä' - 229: 80, # 'ĺ' - 230: 243, # 'ć' - 231: 72, # 'ç' - 232: 244, # 'č' - 233: 15, # 'é' - 234: 83, # 'ę' - 235: 77, # 'ë' - 236: 84, # 'ě' - 237: 30, # 'í' - 238: 76, # 'î' - 239: 85, # 'ď' - 240: 245, # 'đ' - 241: 246, # 'ń' - 242: 247, # 'ň' - 243: 25, # 'ó' - 244: 73, # 'ô' - 245: 42, # 'ő' - 246: 24, # 'ö' - 247: 248, # '÷' - 248: 249, # 'ř' - 249: 250, # 'ů' - 250: 31, # 'ú' - 251: 56, # 'ű' - 252: 29, # 'ü' - 253: 251, # 'ý' - 254: 252, # 'ţ' - 255: 253, # '˙' -} - -ISO_8859_2_HUNGARIAN_MODEL = SingleByteCharSetModel(charset_name='ISO-8859-2', - language='Hungarian', - char_to_order_map=ISO_8859_2_HUNGARIAN_CHAR_TO_ORDER, - language_model=HUNGARIAN_LANG_MODEL, - typical_positive_ratio=0.947368, - keep_ascii_letters=True, - alphabet='ABCDEFGHIJKLMNOPRSTUVZabcdefghijklmnoprstuvzÁÉÍÓÖÚÜáéíóöúüŐőŰű') - diff --git a/venv/lib/python3.8/site-packages/chardet/langrussianmodel.py b/venv/lib/python3.8/site-packages/chardet/langrussianmodel.py deleted file mode 100644 index 569689d..0000000 --- a/venv/lib/python3.8/site-packages/chardet/langrussianmodel.py +++ /dev/null @@ -1,5718 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from chardet.sbcharsetprober import SingleByteCharSetModel - - -# 3: Positive -# 2: Likely -# 1: Unlikely -# 0: Negative - -RUSSIAN_LANG_MODEL = { - 37: { # 'А' - 37: 0, # 'А' - 44: 1, # 'Б' - 33: 1, # 'В' - 46: 1, # 'Г' - 41: 1, # 'Д' - 48: 1, # 'Е' - 56: 1, # 'Ж' - 51: 1, # 'З' - 42: 1, # 'И' - 60: 1, # 'Й' - 36: 1, # 'К' - 49: 1, # 'Л' - 38: 1, # 'М' - 31: 2, # 'Н' - 34: 1, # 'О' - 35: 1, # 'П' - 45: 1, # 'Р' - 32: 1, # 'С' - 40: 1, # 'Т' - 52: 1, # 'У' - 53: 1, # 'Ф' - 55: 1, # 'Х' - 58: 1, # 'Ц' - 50: 1, # 'Ч' - 57: 1, # 'Ш' - 63: 1, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 1, # 'Ю' - 43: 1, # 'Я' - 3: 1, # 'а' - 21: 2, # 'б' - 10: 2, # 'в' - 19: 2, # 'г' - 13: 2, # 'д' - 2: 0, # 'е' - 24: 1, # 'ж' - 20: 1, # 'з' - 4: 0, # 'и' - 23: 1, # 'й' - 11: 2, # 'к' - 8: 3, # 'л' - 12: 2, # 'м' - 5: 2, # 'н' - 1: 0, # 'о' - 15: 2, # 'п' - 9: 2, # 'р' - 7: 2, # 'с' - 6: 2, # 'т' - 14: 2, # 'у' - 39: 2, # 'ф' - 26: 2, # 'х' - 28: 0, # 'ц' - 22: 1, # 'ч' - 25: 2, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 1, # 'э' - 27: 0, # 'ю' - 16: 0, # 'я' - }, - 44: { # 'Б' - 37: 1, # 'А' - 44: 0, # 'Б' - 33: 1, # 'В' - 46: 1, # 'Г' - 41: 0, # 'Д' - 48: 1, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 1, # 'Л' - 38: 1, # 'М' - 31: 1, # 'Н' - 34: 1, # 'О' - 35: 0, # 'П' - 45: 1, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 1, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 1, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 1, # 'Я' - 3: 2, # 'а' - 21: 0, # 'б' - 10: 0, # 'в' - 19: 0, # 'г' - 13: 1, # 'д' - 2: 3, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 2, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 2, # 'л' - 12: 0, # 'м' - 5: 0, # 'н' - 1: 3, # 'о' - 15: 0, # 'п' - 9: 2, # 'р' - 7: 0, # 'с' - 6: 0, # 'т' - 14: 2, # 'у' - 39: 0, # 'ф' - 26: 0, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 2, # 'ы' - 17: 1, # 'ь' - 30: 2, # 'э' - 27: 1, # 'ю' - 16: 1, # 'я' - }, - 33: { # 'В' - 37: 2, # 'А' - 44: 0, # 'Б' - 33: 1, # 'В' - 46: 0, # 'Г' - 41: 1, # 'Д' - 48: 1, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 1, # 'К' - 49: 1, # 'Л' - 38: 1, # 'М' - 31: 1, # 'Н' - 34: 1, # 'О' - 35: 1, # 'П' - 45: 1, # 'Р' - 32: 1, # 'С' - 40: 1, # 'Т' - 52: 1, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 1, # 'Ш' - 63: 0, # 'Щ' - 62: 1, # 'Ы' - 61: 1, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 1, # 'Я' - 3: 2, # 'а' - 21: 1, # 'б' - 10: 1, # 'в' - 19: 1, # 'г' - 13: 2, # 'д' - 2: 3, # 'е' - 24: 0, # 'ж' - 20: 2, # 'з' - 4: 2, # 'и' - 23: 0, # 'й' - 11: 1, # 'к' - 8: 2, # 'л' - 12: 2, # 'м' - 5: 2, # 'н' - 1: 3, # 'о' - 15: 2, # 'п' - 9: 2, # 'р' - 7: 3, # 'с' - 6: 2, # 'т' - 14: 2, # 'у' - 39: 0, # 'ф' - 26: 1, # 'х' - 28: 1, # 'ц' - 22: 2, # 'ч' - 25: 1, # 'ш' - 29: 0, # 'щ' - 54: 1, # 'ъ' - 18: 3, # 'ы' - 17: 1, # 'ь' - 30: 2, # 'э' - 27: 0, # 'ю' - 16: 1, # 'я' - }, - 46: { # 'Г' - 37: 1, # 'А' - 44: 1, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 1, # 'Д' - 48: 1, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 1, # 'Л' - 38: 1, # 'М' - 31: 1, # 'Н' - 34: 1, # 'О' - 35: 1, # 'П' - 45: 1, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 1, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 2, # 'а' - 21: 0, # 'б' - 10: 1, # 'в' - 19: 0, # 'г' - 13: 2, # 'д' - 2: 2, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 2, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 2, # 'л' - 12: 1, # 'м' - 5: 1, # 'н' - 1: 3, # 'о' - 15: 0, # 'п' - 9: 2, # 'р' - 7: 0, # 'с' - 6: 0, # 'т' - 14: 2, # 'у' - 39: 0, # 'ф' - 26: 0, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 1, # 'ь' - 30: 1, # 'э' - 27: 1, # 'ю' - 16: 0, # 'я' - }, - 41: { # 'Д' - 37: 1, # 'А' - 44: 0, # 'Б' - 33: 1, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 2, # 'Е' - 56: 1, # 'Ж' - 51: 0, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 1, # 'К' - 49: 1, # 'Л' - 38: 0, # 'М' - 31: 1, # 'Н' - 34: 1, # 'О' - 35: 0, # 'П' - 45: 1, # 'Р' - 32: 1, # 'С' - 40: 0, # 'Т' - 52: 1, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 1, # 'Ц' - 50: 1, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 1, # 'Ы' - 61: 1, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 1, # 'Я' - 3: 3, # 'а' - 21: 0, # 'б' - 10: 2, # 'в' - 19: 0, # 'г' - 13: 0, # 'д' - 2: 2, # 'е' - 24: 3, # 'ж' - 20: 1, # 'з' - 4: 2, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 2, # 'л' - 12: 1, # 'м' - 5: 1, # 'н' - 1: 3, # 'о' - 15: 0, # 'п' - 9: 2, # 'р' - 7: 0, # 'с' - 6: 0, # 'т' - 14: 2, # 'у' - 39: 0, # 'ф' - 26: 1, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 1, # 'ы' - 17: 1, # 'ь' - 30: 2, # 'э' - 27: 1, # 'ю' - 16: 1, # 'я' - }, - 48: { # 'Е' - 37: 1, # 'А' - 44: 1, # 'Б' - 33: 1, # 'В' - 46: 1, # 'Г' - 41: 1, # 'Д' - 48: 1, # 'Е' - 56: 1, # 'Ж' - 51: 1, # 'З' - 42: 1, # 'И' - 60: 1, # 'Й' - 36: 1, # 'К' - 49: 1, # 'Л' - 38: 1, # 'М' - 31: 2, # 'Н' - 34: 1, # 'О' - 35: 1, # 'П' - 45: 2, # 'Р' - 32: 2, # 'С' - 40: 1, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 1, # 'Х' - 58: 1, # 'Ц' - 50: 1, # 'Ч' - 57: 1, # 'Ш' - 63: 1, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 1, # 'Я' - 3: 0, # 'а' - 21: 0, # 'б' - 10: 2, # 'в' - 19: 2, # 'г' - 13: 2, # 'д' - 2: 2, # 'е' - 24: 1, # 'ж' - 20: 1, # 'з' - 4: 0, # 'и' - 23: 2, # 'й' - 11: 1, # 'к' - 8: 2, # 'л' - 12: 2, # 'м' - 5: 1, # 'н' - 1: 0, # 'о' - 15: 1, # 'п' - 9: 1, # 'р' - 7: 3, # 'с' - 6: 0, # 'т' - 14: 0, # 'у' - 39: 1, # 'ф' - 26: 1, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 1, # 'ш' - 29: 2, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 0, # 'э' - 27: 1, # 'ю' - 16: 0, # 'я' - }, - 56: { # 'Ж' - 37: 1, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 1, # 'Д' - 48: 1, # 'Е' - 56: 0, # 'Ж' - 51: 1, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 1, # 'Н' - 34: 1, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 1, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 2, # 'а' - 21: 1, # 'б' - 10: 0, # 'в' - 19: 1, # 'г' - 13: 1, # 'д' - 2: 2, # 'е' - 24: 1, # 'ж' - 20: 0, # 'з' - 4: 2, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 0, # 'л' - 12: 1, # 'м' - 5: 0, # 'н' - 1: 2, # 'о' - 15: 0, # 'п' - 9: 1, # 'р' - 7: 0, # 'с' - 6: 0, # 'т' - 14: 2, # 'у' - 39: 0, # 'ф' - 26: 0, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 0, # 'э' - 27: 2, # 'ю' - 16: 0, # 'я' - }, - 51: { # 'З' - 37: 1, # 'А' - 44: 0, # 'Б' - 33: 1, # 'В' - 46: 1, # 'Г' - 41: 1, # 'Д' - 48: 1, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 1, # 'Л' - 38: 1, # 'М' - 31: 1, # 'Н' - 34: 1, # 'О' - 35: 0, # 'П' - 45: 1, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 1, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 1, # 'Ы' - 61: 1, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 1, # 'б' - 10: 2, # 'в' - 19: 0, # 'г' - 13: 2, # 'д' - 2: 2, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 2, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 1, # 'л' - 12: 1, # 'м' - 5: 2, # 'н' - 1: 2, # 'о' - 15: 0, # 'п' - 9: 1, # 'р' - 7: 0, # 'с' - 6: 0, # 'т' - 14: 1, # 'у' - 39: 0, # 'ф' - 26: 0, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 1, # 'ы' - 17: 0, # 'ь' - 30: 0, # 'э' - 27: 0, # 'ю' - 16: 1, # 'я' - }, - 42: { # 'И' - 37: 1, # 'А' - 44: 1, # 'Б' - 33: 1, # 'В' - 46: 1, # 'Г' - 41: 1, # 'Д' - 48: 2, # 'Е' - 56: 1, # 'Ж' - 51: 1, # 'З' - 42: 1, # 'И' - 60: 1, # 'Й' - 36: 1, # 'К' - 49: 1, # 'Л' - 38: 1, # 'М' - 31: 1, # 'Н' - 34: 1, # 'О' - 35: 1, # 'П' - 45: 1, # 'Р' - 32: 2, # 'С' - 40: 1, # 'Т' - 52: 0, # 'У' - 53: 1, # 'Ф' - 55: 1, # 'Х' - 58: 1, # 'Ц' - 50: 1, # 'Ч' - 57: 0, # 'Ш' - 63: 1, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 1, # 'Ю' - 43: 1, # 'Я' - 3: 1, # 'а' - 21: 2, # 'б' - 10: 2, # 'в' - 19: 2, # 'г' - 13: 2, # 'д' - 2: 2, # 'е' - 24: 0, # 'ж' - 20: 2, # 'з' - 4: 1, # 'и' - 23: 0, # 'й' - 11: 1, # 'к' - 8: 2, # 'л' - 12: 2, # 'м' - 5: 2, # 'н' - 1: 1, # 'о' - 15: 1, # 'п' - 9: 2, # 'р' - 7: 2, # 'с' - 6: 2, # 'т' - 14: 1, # 'у' - 39: 1, # 'ф' - 26: 2, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 1, # 'ш' - 29: 1, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 0, # 'э' - 27: 1, # 'ю' - 16: 0, # 'я' - }, - 60: { # 'Й' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 1, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 1, # 'К' - 49: 1, # 'Л' - 38: 0, # 'М' - 31: 1, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 1, # 'С' - 40: 1, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 1, # 'Х' - 58: 1, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 0, # 'а' - 21: 0, # 'б' - 10: 0, # 'в' - 19: 0, # 'г' - 13: 0, # 'д' - 2: 1, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 0, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 0, # 'л' - 12: 0, # 'м' - 5: 0, # 'н' - 1: 2, # 'о' - 15: 0, # 'п' - 9: 0, # 'р' - 7: 0, # 'с' - 6: 0, # 'т' - 14: 0, # 'у' - 39: 0, # 'ф' - 26: 0, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 0, # 'э' - 27: 0, # 'ю' - 16: 0, # 'я' - }, - 36: { # 'К' - 37: 2, # 'А' - 44: 0, # 'Б' - 33: 1, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 1, # 'Е' - 56: 0, # 'Ж' - 51: 1, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 1, # 'Л' - 38: 0, # 'М' - 31: 1, # 'Н' - 34: 2, # 'О' - 35: 1, # 'П' - 45: 1, # 'Р' - 32: 1, # 'С' - 40: 1, # 'Т' - 52: 1, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 1, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 0, # 'б' - 10: 1, # 'в' - 19: 0, # 'г' - 13: 0, # 'д' - 2: 2, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 2, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 2, # 'л' - 12: 0, # 'м' - 5: 1, # 'н' - 1: 3, # 'о' - 15: 0, # 'п' - 9: 2, # 'р' - 7: 2, # 'с' - 6: 2, # 'т' - 14: 2, # 'у' - 39: 0, # 'ф' - 26: 1, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 1, # 'ы' - 17: 1, # 'ь' - 30: 2, # 'э' - 27: 1, # 'ю' - 16: 0, # 'я' - }, - 49: { # 'Л' - 37: 2, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 1, # 'Г' - 41: 0, # 'Д' - 48: 1, # 'Е' - 56: 1, # 'Ж' - 51: 0, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 1, # 'К' - 49: 1, # 'Л' - 38: 1, # 'М' - 31: 0, # 'Н' - 34: 1, # 'О' - 35: 1, # 'П' - 45: 0, # 'Р' - 32: 1, # 'С' - 40: 1, # 'Т' - 52: 1, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 1, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 1, # 'Ы' - 61: 1, # 'Ь' - 47: 0, # 'Э' - 59: 1, # 'Ю' - 43: 1, # 'Я' - 3: 2, # 'а' - 21: 0, # 'б' - 10: 0, # 'в' - 19: 1, # 'г' - 13: 0, # 'д' - 2: 2, # 'е' - 24: 1, # 'ж' - 20: 0, # 'з' - 4: 2, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 1, # 'л' - 12: 0, # 'м' - 5: 1, # 'н' - 1: 2, # 'о' - 15: 0, # 'п' - 9: 0, # 'р' - 7: 0, # 'с' - 6: 0, # 'т' - 14: 2, # 'у' - 39: 0, # 'ф' - 26: 1, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 1, # 'ы' - 17: 1, # 'ь' - 30: 2, # 'э' - 27: 2, # 'ю' - 16: 1, # 'я' - }, - 38: { # 'М' - 37: 1, # 'А' - 44: 1, # 'Б' - 33: 1, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 1, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 1, # 'К' - 49: 1, # 'Л' - 38: 1, # 'М' - 31: 1, # 'Н' - 34: 1, # 'О' - 35: 1, # 'П' - 45: 1, # 'Р' - 32: 1, # 'С' - 40: 1, # 'Т' - 52: 1, # 'У' - 53: 1, # 'Ф' - 55: 1, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 1, # 'Ы' - 61: 0, # 'Ь' - 47: 1, # 'Э' - 59: 0, # 'Ю' - 43: 1, # 'Я' - 3: 3, # 'а' - 21: 0, # 'б' - 10: 0, # 'в' - 19: 1, # 'г' - 13: 0, # 'д' - 2: 2, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 1, # 'л' - 12: 1, # 'м' - 5: 2, # 'н' - 1: 3, # 'о' - 15: 0, # 'п' - 9: 1, # 'р' - 7: 1, # 'с' - 6: 0, # 'т' - 14: 2, # 'у' - 39: 0, # 'ф' - 26: 0, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 3, # 'ы' - 17: 1, # 'ь' - 30: 2, # 'э' - 27: 1, # 'ю' - 16: 1, # 'я' - }, - 31: { # 'Н' - 37: 2, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 1, # 'Г' - 41: 1, # 'Д' - 48: 1, # 'Е' - 56: 0, # 'Ж' - 51: 1, # 'З' - 42: 2, # 'И' - 60: 0, # 'Й' - 36: 1, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 1, # 'Н' - 34: 1, # 'О' - 35: 0, # 'П' - 45: 1, # 'Р' - 32: 1, # 'С' - 40: 1, # 'Т' - 52: 1, # 'У' - 53: 1, # 'Ф' - 55: 1, # 'Х' - 58: 1, # 'Ц' - 50: 1, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 1, # 'Ы' - 61: 1, # 'Ь' - 47: 1, # 'Э' - 59: 0, # 'Ю' - 43: 1, # 'Я' - 3: 3, # 'а' - 21: 0, # 'б' - 10: 0, # 'в' - 19: 0, # 'г' - 13: 0, # 'д' - 2: 3, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 0, # 'л' - 12: 0, # 'м' - 5: 0, # 'н' - 1: 3, # 'о' - 15: 0, # 'п' - 9: 1, # 'р' - 7: 0, # 'с' - 6: 0, # 'т' - 14: 3, # 'у' - 39: 0, # 'ф' - 26: 1, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 1, # 'ы' - 17: 2, # 'ь' - 30: 1, # 'э' - 27: 1, # 'ю' - 16: 1, # 'я' - }, - 34: { # 'О' - 37: 0, # 'А' - 44: 1, # 'Б' - 33: 1, # 'В' - 46: 1, # 'Г' - 41: 2, # 'Д' - 48: 1, # 'Е' - 56: 1, # 'Ж' - 51: 1, # 'З' - 42: 1, # 'И' - 60: 1, # 'Й' - 36: 1, # 'К' - 49: 2, # 'Л' - 38: 1, # 'М' - 31: 2, # 'Н' - 34: 1, # 'О' - 35: 1, # 'П' - 45: 2, # 'Р' - 32: 1, # 'С' - 40: 1, # 'Т' - 52: 1, # 'У' - 53: 1, # 'Ф' - 55: 1, # 'Х' - 58: 0, # 'Ц' - 50: 1, # 'Ч' - 57: 1, # 'Ш' - 63: 1, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 1, # 'Я' - 3: 1, # 'а' - 21: 2, # 'б' - 10: 1, # 'в' - 19: 2, # 'г' - 13: 2, # 'д' - 2: 0, # 'е' - 24: 1, # 'ж' - 20: 1, # 'з' - 4: 0, # 'и' - 23: 1, # 'й' - 11: 2, # 'к' - 8: 2, # 'л' - 12: 1, # 'м' - 5: 3, # 'н' - 1: 0, # 'о' - 15: 2, # 'п' - 9: 2, # 'р' - 7: 2, # 'с' - 6: 2, # 'т' - 14: 1, # 'у' - 39: 1, # 'ф' - 26: 2, # 'х' - 28: 1, # 'ц' - 22: 2, # 'ч' - 25: 2, # 'ш' - 29: 1, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 0, # 'э' - 27: 0, # 'ю' - 16: 0, # 'я' - }, - 35: { # 'П' - 37: 1, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 1, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 1, # 'Л' - 38: 0, # 'М' - 31: 1, # 'Н' - 34: 1, # 'О' - 35: 1, # 'П' - 45: 2, # 'Р' - 32: 1, # 'С' - 40: 1, # 'Т' - 52: 1, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 1, # 'Ы' - 61: 1, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 1, # 'Я' - 3: 2, # 'а' - 21: 0, # 'б' - 10: 0, # 'в' - 19: 0, # 'г' - 13: 0, # 'д' - 2: 2, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 2, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 2, # 'л' - 12: 0, # 'м' - 5: 1, # 'н' - 1: 3, # 'о' - 15: 0, # 'п' - 9: 3, # 'р' - 7: 1, # 'с' - 6: 1, # 'т' - 14: 2, # 'у' - 39: 1, # 'ф' - 26: 0, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 1, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 1, # 'ы' - 17: 2, # 'ь' - 30: 1, # 'э' - 27: 0, # 'ю' - 16: 2, # 'я' - }, - 45: { # 'Р' - 37: 2, # 'А' - 44: 1, # 'Б' - 33: 1, # 'В' - 46: 1, # 'Г' - 41: 1, # 'Д' - 48: 2, # 'Е' - 56: 1, # 'Ж' - 51: 0, # 'З' - 42: 2, # 'И' - 60: 0, # 'Й' - 36: 1, # 'К' - 49: 1, # 'Л' - 38: 1, # 'М' - 31: 1, # 'Н' - 34: 2, # 'О' - 35: 0, # 'П' - 45: 1, # 'Р' - 32: 1, # 'С' - 40: 1, # 'Т' - 52: 1, # 'У' - 53: 0, # 'Ф' - 55: 1, # 'Х' - 58: 1, # 'Ц' - 50: 1, # 'Ч' - 57: 1, # 'Ш' - 63: 0, # 'Щ' - 62: 1, # 'Ы' - 61: 1, # 'Ь' - 47: 1, # 'Э' - 59: 1, # 'Ю' - 43: 1, # 'Я' - 3: 3, # 'а' - 21: 0, # 'б' - 10: 1, # 'в' - 19: 0, # 'г' - 13: 0, # 'д' - 2: 2, # 'е' - 24: 1, # 'ж' - 20: 0, # 'з' - 4: 2, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 0, # 'л' - 12: 0, # 'м' - 5: 0, # 'н' - 1: 3, # 'о' - 15: 0, # 'п' - 9: 1, # 'р' - 7: 0, # 'с' - 6: 0, # 'т' - 14: 2, # 'у' - 39: 0, # 'ф' - 26: 0, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 2, # 'ы' - 17: 0, # 'ь' - 30: 1, # 'э' - 27: 1, # 'ю' - 16: 2, # 'я' - }, - 32: { # 'С' - 37: 1, # 'А' - 44: 1, # 'Б' - 33: 1, # 'В' - 46: 1, # 'Г' - 41: 1, # 'Д' - 48: 1, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 1, # 'К' - 49: 1, # 'Л' - 38: 1, # 'М' - 31: 1, # 'Н' - 34: 1, # 'О' - 35: 1, # 'П' - 45: 1, # 'Р' - 32: 1, # 'С' - 40: 2, # 'Т' - 52: 1, # 'У' - 53: 0, # 'Ф' - 55: 1, # 'Х' - 58: 1, # 'Ц' - 50: 1, # 'Ч' - 57: 1, # 'Ш' - 63: 0, # 'Щ' - 62: 1, # 'Ы' - 61: 1, # 'Ь' - 47: 1, # 'Э' - 59: 1, # 'Ю' - 43: 1, # 'Я' - 3: 2, # 'а' - 21: 1, # 'б' - 10: 2, # 'в' - 19: 1, # 'г' - 13: 2, # 'д' - 2: 3, # 'е' - 24: 1, # 'ж' - 20: 1, # 'з' - 4: 2, # 'и' - 23: 0, # 'й' - 11: 2, # 'к' - 8: 2, # 'л' - 12: 2, # 'м' - 5: 2, # 'н' - 1: 2, # 'о' - 15: 2, # 'п' - 9: 2, # 'р' - 7: 1, # 'с' - 6: 3, # 'т' - 14: 2, # 'у' - 39: 1, # 'ф' - 26: 1, # 'х' - 28: 1, # 'ц' - 22: 1, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 1, # 'ъ' - 18: 1, # 'ы' - 17: 1, # 'ь' - 30: 2, # 'э' - 27: 1, # 'ю' - 16: 1, # 'я' - }, - 40: { # 'Т' - 37: 1, # 'А' - 44: 0, # 'Б' - 33: 1, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 1, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 1, # 'К' - 49: 1, # 'Л' - 38: 1, # 'М' - 31: 1, # 'Н' - 34: 2, # 'О' - 35: 0, # 'П' - 45: 1, # 'Р' - 32: 1, # 'С' - 40: 1, # 'Т' - 52: 1, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 1, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 1, # 'Ы' - 61: 1, # 'Ь' - 47: 1, # 'Э' - 59: 1, # 'Ю' - 43: 1, # 'Я' - 3: 3, # 'а' - 21: 1, # 'б' - 10: 2, # 'в' - 19: 0, # 'г' - 13: 0, # 'д' - 2: 3, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 2, # 'и' - 23: 0, # 'й' - 11: 1, # 'к' - 8: 1, # 'л' - 12: 0, # 'м' - 5: 0, # 'н' - 1: 3, # 'о' - 15: 0, # 'п' - 9: 2, # 'р' - 7: 1, # 'с' - 6: 0, # 'т' - 14: 2, # 'у' - 39: 0, # 'ф' - 26: 0, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 1, # 'щ' - 54: 0, # 'ъ' - 18: 3, # 'ы' - 17: 1, # 'ь' - 30: 2, # 'э' - 27: 1, # 'ю' - 16: 1, # 'я' - }, - 52: { # 'У' - 37: 1, # 'А' - 44: 1, # 'Б' - 33: 1, # 'В' - 46: 1, # 'Г' - 41: 1, # 'Д' - 48: 1, # 'Е' - 56: 1, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 1, # 'Й' - 36: 1, # 'К' - 49: 1, # 'Л' - 38: 1, # 'М' - 31: 1, # 'Н' - 34: 1, # 'О' - 35: 1, # 'П' - 45: 1, # 'Р' - 32: 1, # 'С' - 40: 1, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 1, # 'Х' - 58: 0, # 'Ц' - 50: 1, # 'Ч' - 57: 1, # 'Ш' - 63: 1, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 1, # 'Ю' - 43: 0, # 'Я' - 3: 1, # 'а' - 21: 2, # 'б' - 10: 2, # 'в' - 19: 1, # 'г' - 13: 2, # 'д' - 2: 1, # 'е' - 24: 2, # 'ж' - 20: 2, # 'з' - 4: 2, # 'и' - 23: 1, # 'й' - 11: 1, # 'к' - 8: 2, # 'л' - 12: 2, # 'м' - 5: 1, # 'н' - 1: 2, # 'о' - 15: 1, # 'п' - 9: 2, # 'р' - 7: 2, # 'с' - 6: 2, # 'т' - 14: 0, # 'у' - 39: 1, # 'ф' - 26: 1, # 'х' - 28: 1, # 'ц' - 22: 2, # 'ч' - 25: 1, # 'ш' - 29: 1, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 2, # 'э' - 27: 1, # 'ю' - 16: 0, # 'я' - }, - 53: { # 'Ф' - 37: 1, # 'А' - 44: 1, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 1, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 1, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 1, # 'О' - 35: 0, # 'П' - 45: 1, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 1, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 2, # 'а' - 21: 0, # 'б' - 10: 0, # 'в' - 19: 0, # 'г' - 13: 0, # 'д' - 2: 2, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 2, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 2, # 'л' - 12: 0, # 'м' - 5: 0, # 'н' - 1: 2, # 'о' - 15: 0, # 'п' - 9: 2, # 'р' - 7: 0, # 'с' - 6: 1, # 'т' - 14: 2, # 'у' - 39: 0, # 'ф' - 26: 0, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 1, # 'ь' - 30: 2, # 'э' - 27: 0, # 'ю' - 16: 0, # 'я' - }, - 55: { # 'Х' - 37: 1, # 'А' - 44: 0, # 'Б' - 33: 1, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 1, # 'Л' - 38: 1, # 'М' - 31: 1, # 'Н' - 34: 1, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 2, # 'а' - 21: 0, # 'б' - 10: 2, # 'в' - 19: 0, # 'г' - 13: 0, # 'д' - 2: 2, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 2, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 2, # 'л' - 12: 1, # 'м' - 5: 0, # 'н' - 1: 2, # 'о' - 15: 0, # 'п' - 9: 2, # 'р' - 7: 0, # 'с' - 6: 0, # 'т' - 14: 1, # 'у' - 39: 0, # 'ф' - 26: 0, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 1, # 'ь' - 30: 1, # 'э' - 27: 0, # 'ю' - 16: 0, # 'я' - }, - 58: { # 'Ц' - 37: 1, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 1, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 1, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 1, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 1, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 1, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 1, # 'а' - 21: 0, # 'б' - 10: 1, # 'в' - 19: 0, # 'г' - 13: 0, # 'д' - 2: 2, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 2, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 0, # 'л' - 12: 0, # 'м' - 5: 0, # 'н' - 1: 0, # 'о' - 15: 0, # 'п' - 9: 0, # 'р' - 7: 0, # 'с' - 6: 0, # 'т' - 14: 1, # 'у' - 39: 0, # 'ф' - 26: 0, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 1, # 'ы' - 17: 0, # 'ь' - 30: 0, # 'э' - 27: 1, # 'ю' - 16: 0, # 'я' - }, - 50: { # 'Ч' - 37: 1, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 1, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 1, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 1, # 'Н' - 34: 0, # 'О' - 35: 1, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 1, # 'Т' - 52: 1, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 1, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 2, # 'а' - 21: 0, # 'б' - 10: 0, # 'в' - 19: 0, # 'г' - 13: 0, # 'д' - 2: 2, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 2, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 1, # 'л' - 12: 0, # 'м' - 5: 0, # 'н' - 1: 1, # 'о' - 15: 0, # 'п' - 9: 1, # 'р' - 7: 0, # 'с' - 6: 3, # 'т' - 14: 2, # 'у' - 39: 0, # 'ф' - 26: 0, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 1, # 'ь' - 30: 0, # 'э' - 27: 0, # 'ю' - 16: 0, # 'я' - }, - 57: { # 'Ш' - 37: 1, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 1, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 1, # 'К' - 49: 1, # 'Л' - 38: 0, # 'М' - 31: 1, # 'Н' - 34: 1, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 1, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 2, # 'а' - 21: 0, # 'б' - 10: 1, # 'в' - 19: 0, # 'г' - 13: 0, # 'д' - 2: 2, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 1, # 'и' - 23: 0, # 'й' - 11: 1, # 'к' - 8: 2, # 'л' - 12: 1, # 'м' - 5: 1, # 'н' - 1: 2, # 'о' - 15: 2, # 'п' - 9: 1, # 'р' - 7: 0, # 'с' - 6: 2, # 'т' - 14: 2, # 'у' - 39: 0, # 'ф' - 26: 1, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 1, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 1, # 'э' - 27: 0, # 'ю' - 16: 0, # 'я' - }, - 63: { # 'Щ' - 37: 1, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 1, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 1, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 1, # 'а' - 21: 0, # 'б' - 10: 0, # 'в' - 19: 0, # 'г' - 13: 0, # 'д' - 2: 1, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 1, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 0, # 'л' - 12: 0, # 'м' - 5: 0, # 'н' - 1: 1, # 'о' - 15: 0, # 'п' - 9: 0, # 'р' - 7: 0, # 'с' - 6: 0, # 'т' - 14: 1, # 'у' - 39: 0, # 'ф' - 26: 0, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 0, # 'э' - 27: 0, # 'ю' - 16: 0, # 'я' - }, - 62: { # 'Ы' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 1, # 'В' - 46: 1, # 'Г' - 41: 0, # 'Д' - 48: 1, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 1, # 'Й' - 36: 1, # 'К' - 49: 1, # 'Л' - 38: 1, # 'М' - 31: 1, # 'Н' - 34: 0, # 'О' - 35: 1, # 'П' - 45: 1, # 'Р' - 32: 1, # 'С' - 40: 1, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 1, # 'Х' - 58: 1, # 'Ц' - 50: 0, # 'Ч' - 57: 1, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 0, # 'а' - 21: 0, # 'б' - 10: 0, # 'в' - 19: 0, # 'г' - 13: 0, # 'д' - 2: 0, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 0, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 0, # 'л' - 12: 0, # 'м' - 5: 0, # 'н' - 1: 0, # 'о' - 15: 0, # 'п' - 9: 0, # 'р' - 7: 0, # 'с' - 6: 0, # 'т' - 14: 0, # 'у' - 39: 0, # 'ф' - 26: 0, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 0, # 'э' - 27: 0, # 'ю' - 16: 0, # 'я' - }, - 61: { # 'Ь' - 37: 0, # 'А' - 44: 1, # 'Б' - 33: 1, # 'В' - 46: 0, # 'Г' - 41: 1, # 'Д' - 48: 1, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 1, # 'К' - 49: 0, # 'Л' - 38: 1, # 'М' - 31: 1, # 'Н' - 34: 1, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 1, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 1, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 1, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 1, # 'Ю' - 43: 1, # 'Я' - 3: 0, # 'а' - 21: 0, # 'б' - 10: 0, # 'в' - 19: 0, # 'г' - 13: 0, # 'д' - 2: 0, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 0, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 0, # 'л' - 12: 0, # 'м' - 5: 0, # 'н' - 1: 0, # 'о' - 15: 0, # 'п' - 9: 0, # 'р' - 7: 0, # 'с' - 6: 0, # 'т' - 14: 0, # 'у' - 39: 0, # 'ф' - 26: 0, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 0, # 'э' - 27: 0, # 'ю' - 16: 0, # 'я' - }, - 47: { # 'Э' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 1, # 'В' - 46: 0, # 'Г' - 41: 1, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 1, # 'Й' - 36: 1, # 'К' - 49: 1, # 'Л' - 38: 1, # 'М' - 31: 1, # 'Н' - 34: 0, # 'О' - 35: 1, # 'П' - 45: 1, # 'Р' - 32: 1, # 'С' - 40: 1, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 1, # 'а' - 21: 1, # 'б' - 10: 2, # 'в' - 19: 1, # 'г' - 13: 2, # 'д' - 2: 0, # 'е' - 24: 1, # 'ж' - 20: 0, # 'з' - 4: 0, # 'и' - 23: 2, # 'й' - 11: 2, # 'к' - 8: 2, # 'л' - 12: 2, # 'м' - 5: 2, # 'н' - 1: 0, # 'о' - 15: 1, # 'п' - 9: 2, # 'р' - 7: 1, # 'с' - 6: 3, # 'т' - 14: 1, # 'у' - 39: 1, # 'ф' - 26: 1, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 1, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 0, # 'э' - 27: 0, # 'ю' - 16: 0, # 'я' - }, - 59: { # 'Ю' - 37: 1, # 'А' - 44: 1, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 1, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 1, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 1, # 'Р' - 32: 0, # 'С' - 40: 1, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 1, # 'Ч' - 57: 0, # 'Ш' - 63: 1, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 0, # 'а' - 21: 1, # 'б' - 10: 0, # 'в' - 19: 1, # 'г' - 13: 1, # 'д' - 2: 0, # 'е' - 24: 1, # 'ж' - 20: 0, # 'з' - 4: 0, # 'и' - 23: 0, # 'й' - 11: 1, # 'к' - 8: 2, # 'л' - 12: 1, # 'м' - 5: 2, # 'н' - 1: 0, # 'о' - 15: 1, # 'п' - 9: 1, # 'р' - 7: 1, # 'с' - 6: 0, # 'т' - 14: 0, # 'у' - 39: 0, # 'ф' - 26: 1, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 0, # 'э' - 27: 0, # 'ю' - 16: 0, # 'я' - }, - 43: { # 'Я' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 1, # 'В' - 46: 1, # 'Г' - 41: 0, # 'Д' - 48: 1, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 1, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 1, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 1, # 'С' - 40: 1, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 1, # 'Х' - 58: 0, # 'Ц' - 50: 1, # 'Ч' - 57: 0, # 'Ш' - 63: 1, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 1, # 'Ю' - 43: 1, # 'Я' - 3: 0, # 'а' - 21: 1, # 'б' - 10: 1, # 'в' - 19: 1, # 'г' - 13: 1, # 'д' - 2: 0, # 'е' - 24: 0, # 'ж' - 20: 1, # 'з' - 4: 0, # 'и' - 23: 1, # 'й' - 11: 1, # 'к' - 8: 1, # 'л' - 12: 1, # 'м' - 5: 2, # 'н' - 1: 0, # 'о' - 15: 1, # 'п' - 9: 1, # 'р' - 7: 1, # 'с' - 6: 0, # 'т' - 14: 0, # 'у' - 39: 0, # 'ф' - 26: 1, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 1, # 'ш' - 29: 1, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 0, # 'э' - 27: 0, # 'ю' - 16: 0, # 'я' - }, - 3: { # 'а' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 1, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 1, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 2, # 'а' - 21: 3, # 'б' - 10: 3, # 'в' - 19: 3, # 'г' - 13: 3, # 'д' - 2: 3, # 'е' - 24: 3, # 'ж' - 20: 3, # 'з' - 4: 3, # 'и' - 23: 3, # 'й' - 11: 3, # 'к' - 8: 3, # 'л' - 12: 3, # 'м' - 5: 3, # 'н' - 1: 2, # 'о' - 15: 3, # 'п' - 9: 3, # 'р' - 7: 3, # 'с' - 6: 3, # 'т' - 14: 3, # 'у' - 39: 2, # 'ф' - 26: 3, # 'х' - 28: 3, # 'ц' - 22: 3, # 'ч' - 25: 3, # 'ш' - 29: 3, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 2, # 'э' - 27: 3, # 'ю' - 16: 3, # 'я' - }, - 21: { # 'б' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 1, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 2, # 'б' - 10: 2, # 'в' - 19: 1, # 'г' - 13: 2, # 'д' - 2: 3, # 'е' - 24: 2, # 'ж' - 20: 1, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 2, # 'к' - 8: 3, # 'л' - 12: 2, # 'м' - 5: 3, # 'н' - 1: 3, # 'о' - 15: 1, # 'п' - 9: 3, # 'р' - 7: 3, # 'с' - 6: 2, # 'т' - 14: 3, # 'у' - 39: 0, # 'ф' - 26: 2, # 'х' - 28: 1, # 'ц' - 22: 1, # 'ч' - 25: 2, # 'ш' - 29: 3, # 'щ' - 54: 2, # 'ъ' - 18: 3, # 'ы' - 17: 2, # 'ь' - 30: 1, # 'э' - 27: 2, # 'ю' - 16: 3, # 'я' - }, - 10: { # 'в' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 2, # 'б' - 10: 2, # 'в' - 19: 2, # 'г' - 13: 3, # 'д' - 2: 3, # 'е' - 24: 1, # 'ж' - 20: 3, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 3, # 'к' - 8: 3, # 'л' - 12: 2, # 'м' - 5: 3, # 'н' - 1: 3, # 'о' - 15: 3, # 'п' - 9: 3, # 'р' - 7: 3, # 'с' - 6: 3, # 'т' - 14: 3, # 'у' - 39: 1, # 'ф' - 26: 2, # 'х' - 28: 2, # 'ц' - 22: 2, # 'ч' - 25: 3, # 'ш' - 29: 2, # 'щ' - 54: 2, # 'ъ' - 18: 3, # 'ы' - 17: 3, # 'ь' - 30: 1, # 'э' - 27: 1, # 'ю' - 16: 3, # 'я' - }, - 19: { # 'г' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 1, # 'б' - 10: 2, # 'в' - 19: 1, # 'г' - 13: 3, # 'д' - 2: 3, # 'е' - 24: 0, # 'ж' - 20: 1, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 2, # 'к' - 8: 3, # 'л' - 12: 2, # 'м' - 5: 3, # 'н' - 1: 3, # 'о' - 15: 0, # 'п' - 9: 3, # 'р' - 7: 2, # 'с' - 6: 2, # 'т' - 14: 3, # 'у' - 39: 1, # 'ф' - 26: 1, # 'х' - 28: 1, # 'ц' - 22: 2, # 'ч' - 25: 1, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 1, # 'ы' - 17: 1, # 'ь' - 30: 1, # 'э' - 27: 1, # 'ю' - 16: 0, # 'я' - }, - 13: { # 'д' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 2, # 'б' - 10: 3, # 'в' - 19: 2, # 'г' - 13: 2, # 'д' - 2: 3, # 'е' - 24: 2, # 'ж' - 20: 2, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 3, # 'к' - 8: 3, # 'л' - 12: 2, # 'м' - 5: 3, # 'н' - 1: 3, # 'о' - 15: 2, # 'п' - 9: 3, # 'р' - 7: 3, # 'с' - 6: 3, # 'т' - 14: 3, # 'у' - 39: 1, # 'ф' - 26: 2, # 'х' - 28: 3, # 'ц' - 22: 2, # 'ч' - 25: 2, # 'ш' - 29: 1, # 'щ' - 54: 2, # 'ъ' - 18: 3, # 'ы' - 17: 3, # 'ь' - 30: 1, # 'э' - 27: 2, # 'ю' - 16: 3, # 'я' - }, - 2: { # 'е' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 2, # 'а' - 21: 3, # 'б' - 10: 3, # 'в' - 19: 3, # 'г' - 13: 3, # 'д' - 2: 3, # 'е' - 24: 3, # 'ж' - 20: 3, # 'з' - 4: 2, # 'и' - 23: 3, # 'й' - 11: 3, # 'к' - 8: 3, # 'л' - 12: 3, # 'м' - 5: 3, # 'н' - 1: 3, # 'о' - 15: 3, # 'п' - 9: 3, # 'р' - 7: 3, # 'с' - 6: 3, # 'т' - 14: 2, # 'у' - 39: 2, # 'ф' - 26: 3, # 'х' - 28: 3, # 'ц' - 22: 3, # 'ч' - 25: 3, # 'ш' - 29: 3, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 1, # 'э' - 27: 2, # 'ю' - 16: 3, # 'я' - }, - 24: { # 'ж' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 2, # 'б' - 10: 1, # 'в' - 19: 2, # 'г' - 13: 3, # 'д' - 2: 3, # 'е' - 24: 2, # 'ж' - 20: 1, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 2, # 'к' - 8: 2, # 'л' - 12: 1, # 'м' - 5: 3, # 'н' - 1: 2, # 'о' - 15: 1, # 'п' - 9: 2, # 'р' - 7: 2, # 'с' - 6: 1, # 'т' - 14: 3, # 'у' - 39: 1, # 'ф' - 26: 0, # 'х' - 28: 1, # 'ц' - 22: 2, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 1, # 'ы' - 17: 2, # 'ь' - 30: 1, # 'э' - 27: 1, # 'ю' - 16: 1, # 'я' - }, - 20: { # 'з' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 3, # 'б' - 10: 3, # 'в' - 19: 3, # 'г' - 13: 3, # 'д' - 2: 3, # 'е' - 24: 2, # 'ж' - 20: 2, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 3, # 'к' - 8: 3, # 'л' - 12: 3, # 'м' - 5: 3, # 'н' - 1: 3, # 'о' - 15: 0, # 'п' - 9: 3, # 'р' - 7: 2, # 'с' - 6: 2, # 'т' - 14: 3, # 'у' - 39: 0, # 'ф' - 26: 0, # 'х' - 28: 1, # 'ц' - 22: 2, # 'ч' - 25: 1, # 'ш' - 29: 0, # 'щ' - 54: 2, # 'ъ' - 18: 3, # 'ы' - 17: 2, # 'ь' - 30: 1, # 'э' - 27: 1, # 'ю' - 16: 3, # 'я' - }, - 4: { # 'и' - 37: 1, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 1, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 3, # 'б' - 10: 3, # 'в' - 19: 3, # 'г' - 13: 3, # 'д' - 2: 3, # 'е' - 24: 3, # 'ж' - 20: 3, # 'з' - 4: 3, # 'и' - 23: 3, # 'й' - 11: 3, # 'к' - 8: 3, # 'л' - 12: 3, # 'м' - 5: 3, # 'н' - 1: 3, # 'о' - 15: 3, # 'п' - 9: 3, # 'р' - 7: 3, # 'с' - 6: 3, # 'т' - 14: 2, # 'у' - 39: 2, # 'ф' - 26: 3, # 'х' - 28: 3, # 'ц' - 22: 3, # 'ч' - 25: 3, # 'ш' - 29: 3, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 2, # 'э' - 27: 3, # 'ю' - 16: 3, # 'я' - }, - 23: { # 'й' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 1, # 'а' - 21: 1, # 'б' - 10: 1, # 'в' - 19: 2, # 'г' - 13: 3, # 'д' - 2: 2, # 'е' - 24: 0, # 'ж' - 20: 2, # 'з' - 4: 1, # 'и' - 23: 0, # 'й' - 11: 2, # 'к' - 8: 2, # 'л' - 12: 2, # 'м' - 5: 3, # 'н' - 1: 2, # 'о' - 15: 1, # 'п' - 9: 2, # 'р' - 7: 3, # 'с' - 6: 3, # 'т' - 14: 1, # 'у' - 39: 2, # 'ф' - 26: 1, # 'х' - 28: 2, # 'ц' - 22: 3, # 'ч' - 25: 2, # 'ш' - 29: 1, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 1, # 'э' - 27: 1, # 'ю' - 16: 2, # 'я' - }, - 11: { # 'к' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 1, # 'б' - 10: 3, # 'в' - 19: 1, # 'г' - 13: 1, # 'д' - 2: 3, # 'е' - 24: 2, # 'ж' - 20: 2, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 2, # 'к' - 8: 3, # 'л' - 12: 1, # 'м' - 5: 3, # 'н' - 1: 3, # 'о' - 15: 0, # 'п' - 9: 3, # 'р' - 7: 3, # 'с' - 6: 3, # 'т' - 14: 3, # 'у' - 39: 1, # 'ф' - 26: 2, # 'х' - 28: 2, # 'ц' - 22: 1, # 'ч' - 25: 2, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 1, # 'ы' - 17: 1, # 'ь' - 30: 1, # 'э' - 27: 1, # 'ю' - 16: 1, # 'я' - }, - 8: { # 'л' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 2, # 'б' - 10: 2, # 'в' - 19: 3, # 'г' - 13: 2, # 'д' - 2: 3, # 'е' - 24: 3, # 'ж' - 20: 2, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 3, # 'к' - 8: 3, # 'л' - 12: 2, # 'м' - 5: 3, # 'н' - 1: 3, # 'о' - 15: 2, # 'п' - 9: 1, # 'р' - 7: 3, # 'с' - 6: 2, # 'т' - 14: 3, # 'у' - 39: 2, # 'ф' - 26: 2, # 'х' - 28: 1, # 'ц' - 22: 3, # 'ч' - 25: 2, # 'ш' - 29: 1, # 'щ' - 54: 0, # 'ъ' - 18: 3, # 'ы' - 17: 3, # 'ь' - 30: 1, # 'э' - 27: 3, # 'ю' - 16: 3, # 'я' - }, - 12: { # 'м' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 2, # 'б' - 10: 2, # 'в' - 19: 2, # 'г' - 13: 1, # 'д' - 2: 3, # 'е' - 24: 1, # 'ж' - 20: 1, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 2, # 'к' - 8: 3, # 'л' - 12: 2, # 'м' - 5: 3, # 'н' - 1: 3, # 'о' - 15: 2, # 'п' - 9: 2, # 'р' - 7: 3, # 'с' - 6: 2, # 'т' - 14: 3, # 'у' - 39: 2, # 'ф' - 26: 2, # 'х' - 28: 2, # 'ц' - 22: 2, # 'ч' - 25: 1, # 'ш' - 29: 1, # 'щ' - 54: 0, # 'ъ' - 18: 3, # 'ы' - 17: 2, # 'ь' - 30: 2, # 'э' - 27: 1, # 'ю' - 16: 3, # 'я' - }, - 5: { # 'н' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 2, # 'б' - 10: 2, # 'в' - 19: 3, # 'г' - 13: 3, # 'д' - 2: 3, # 'е' - 24: 2, # 'ж' - 20: 2, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 3, # 'к' - 8: 2, # 'л' - 12: 1, # 'м' - 5: 3, # 'н' - 1: 3, # 'о' - 15: 1, # 'п' - 9: 2, # 'р' - 7: 3, # 'с' - 6: 3, # 'т' - 14: 3, # 'у' - 39: 2, # 'ф' - 26: 2, # 'х' - 28: 3, # 'ц' - 22: 3, # 'ч' - 25: 2, # 'ш' - 29: 2, # 'щ' - 54: 1, # 'ъ' - 18: 3, # 'ы' - 17: 3, # 'ь' - 30: 1, # 'э' - 27: 3, # 'ю' - 16: 3, # 'я' - }, - 1: { # 'о' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 2, # 'а' - 21: 3, # 'б' - 10: 3, # 'в' - 19: 3, # 'г' - 13: 3, # 'д' - 2: 3, # 'е' - 24: 3, # 'ж' - 20: 3, # 'з' - 4: 3, # 'и' - 23: 3, # 'й' - 11: 3, # 'к' - 8: 3, # 'л' - 12: 3, # 'м' - 5: 3, # 'н' - 1: 3, # 'о' - 15: 3, # 'п' - 9: 3, # 'р' - 7: 3, # 'с' - 6: 3, # 'т' - 14: 2, # 'у' - 39: 2, # 'ф' - 26: 3, # 'х' - 28: 2, # 'ц' - 22: 3, # 'ч' - 25: 3, # 'ш' - 29: 3, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 2, # 'э' - 27: 3, # 'ю' - 16: 3, # 'я' - }, - 15: { # 'п' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 1, # 'б' - 10: 0, # 'в' - 19: 0, # 'г' - 13: 0, # 'д' - 2: 3, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 2, # 'к' - 8: 3, # 'л' - 12: 1, # 'м' - 5: 3, # 'н' - 1: 3, # 'о' - 15: 2, # 'п' - 9: 3, # 'р' - 7: 2, # 'с' - 6: 2, # 'т' - 14: 3, # 'у' - 39: 1, # 'ф' - 26: 0, # 'х' - 28: 2, # 'ц' - 22: 2, # 'ч' - 25: 1, # 'ш' - 29: 1, # 'щ' - 54: 0, # 'ъ' - 18: 3, # 'ы' - 17: 2, # 'ь' - 30: 1, # 'э' - 27: 1, # 'ю' - 16: 3, # 'я' - }, - 9: { # 'р' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 2, # 'б' - 10: 3, # 'в' - 19: 3, # 'г' - 13: 3, # 'д' - 2: 3, # 'е' - 24: 3, # 'ж' - 20: 2, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 3, # 'к' - 8: 2, # 'л' - 12: 3, # 'м' - 5: 3, # 'н' - 1: 3, # 'о' - 15: 2, # 'п' - 9: 2, # 'р' - 7: 3, # 'с' - 6: 3, # 'т' - 14: 3, # 'у' - 39: 2, # 'ф' - 26: 3, # 'х' - 28: 2, # 'ц' - 22: 2, # 'ч' - 25: 3, # 'ш' - 29: 2, # 'щ' - 54: 0, # 'ъ' - 18: 3, # 'ы' - 17: 3, # 'ь' - 30: 2, # 'э' - 27: 2, # 'ю' - 16: 3, # 'я' - }, - 7: { # 'с' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 1, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 2, # 'б' - 10: 3, # 'в' - 19: 2, # 'г' - 13: 3, # 'д' - 2: 3, # 'е' - 24: 2, # 'ж' - 20: 2, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 3, # 'к' - 8: 3, # 'л' - 12: 3, # 'м' - 5: 3, # 'н' - 1: 3, # 'о' - 15: 3, # 'п' - 9: 3, # 'р' - 7: 3, # 'с' - 6: 3, # 'т' - 14: 3, # 'у' - 39: 2, # 'ф' - 26: 3, # 'х' - 28: 2, # 'ц' - 22: 3, # 'ч' - 25: 2, # 'ш' - 29: 1, # 'щ' - 54: 2, # 'ъ' - 18: 3, # 'ы' - 17: 3, # 'ь' - 30: 2, # 'э' - 27: 3, # 'ю' - 16: 3, # 'я' - }, - 6: { # 'т' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 2, # 'б' - 10: 3, # 'в' - 19: 2, # 'г' - 13: 2, # 'д' - 2: 3, # 'е' - 24: 1, # 'ж' - 20: 1, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 3, # 'к' - 8: 3, # 'л' - 12: 2, # 'м' - 5: 3, # 'н' - 1: 3, # 'о' - 15: 2, # 'п' - 9: 3, # 'р' - 7: 3, # 'с' - 6: 2, # 'т' - 14: 3, # 'у' - 39: 2, # 'ф' - 26: 2, # 'х' - 28: 2, # 'ц' - 22: 2, # 'ч' - 25: 2, # 'ш' - 29: 2, # 'щ' - 54: 2, # 'ъ' - 18: 3, # 'ы' - 17: 3, # 'ь' - 30: 2, # 'э' - 27: 2, # 'ю' - 16: 3, # 'я' - }, - 14: { # 'у' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 2, # 'а' - 21: 3, # 'б' - 10: 3, # 'в' - 19: 3, # 'г' - 13: 3, # 'д' - 2: 3, # 'е' - 24: 3, # 'ж' - 20: 3, # 'з' - 4: 2, # 'и' - 23: 2, # 'й' - 11: 3, # 'к' - 8: 3, # 'л' - 12: 3, # 'м' - 5: 3, # 'н' - 1: 2, # 'о' - 15: 3, # 'п' - 9: 3, # 'р' - 7: 3, # 'с' - 6: 3, # 'т' - 14: 1, # 'у' - 39: 2, # 'ф' - 26: 3, # 'х' - 28: 2, # 'ц' - 22: 3, # 'ч' - 25: 3, # 'ш' - 29: 3, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 2, # 'э' - 27: 3, # 'ю' - 16: 2, # 'я' - }, - 39: { # 'ф' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 1, # 'б' - 10: 0, # 'в' - 19: 1, # 'г' - 13: 0, # 'д' - 2: 3, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 1, # 'к' - 8: 2, # 'л' - 12: 1, # 'м' - 5: 1, # 'н' - 1: 3, # 'о' - 15: 1, # 'п' - 9: 2, # 'р' - 7: 2, # 'с' - 6: 2, # 'т' - 14: 2, # 'у' - 39: 2, # 'ф' - 26: 0, # 'х' - 28: 0, # 'ц' - 22: 1, # 'ч' - 25: 1, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 2, # 'ы' - 17: 1, # 'ь' - 30: 2, # 'э' - 27: 1, # 'ю' - 16: 1, # 'я' - }, - 26: { # 'х' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 0, # 'б' - 10: 3, # 'в' - 19: 1, # 'г' - 13: 1, # 'д' - 2: 2, # 'е' - 24: 0, # 'ж' - 20: 1, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 1, # 'к' - 8: 2, # 'л' - 12: 2, # 'м' - 5: 3, # 'н' - 1: 3, # 'о' - 15: 1, # 'п' - 9: 3, # 'р' - 7: 2, # 'с' - 6: 2, # 'т' - 14: 2, # 'у' - 39: 1, # 'ф' - 26: 1, # 'х' - 28: 1, # 'ц' - 22: 1, # 'ч' - 25: 2, # 'ш' - 29: 0, # 'щ' - 54: 1, # 'ъ' - 18: 0, # 'ы' - 17: 1, # 'ь' - 30: 1, # 'э' - 27: 1, # 'ю' - 16: 0, # 'я' - }, - 28: { # 'ц' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 1, # 'б' - 10: 2, # 'в' - 19: 1, # 'г' - 13: 1, # 'д' - 2: 3, # 'е' - 24: 0, # 'ж' - 20: 1, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 2, # 'к' - 8: 1, # 'л' - 12: 1, # 'м' - 5: 1, # 'н' - 1: 3, # 'о' - 15: 0, # 'п' - 9: 1, # 'р' - 7: 0, # 'с' - 6: 1, # 'т' - 14: 3, # 'у' - 39: 0, # 'ф' - 26: 0, # 'х' - 28: 1, # 'ц' - 22: 0, # 'ч' - 25: 1, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 3, # 'ы' - 17: 1, # 'ь' - 30: 0, # 'э' - 27: 1, # 'ю' - 16: 0, # 'я' - }, - 22: { # 'ч' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 1, # 'б' - 10: 1, # 'в' - 19: 0, # 'г' - 13: 0, # 'д' - 2: 3, # 'е' - 24: 1, # 'ж' - 20: 0, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 3, # 'к' - 8: 2, # 'л' - 12: 1, # 'м' - 5: 3, # 'н' - 1: 2, # 'о' - 15: 0, # 'п' - 9: 2, # 'р' - 7: 1, # 'с' - 6: 3, # 'т' - 14: 3, # 'у' - 39: 1, # 'ф' - 26: 1, # 'х' - 28: 0, # 'ц' - 22: 1, # 'ч' - 25: 2, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 3, # 'ь' - 30: 0, # 'э' - 27: 0, # 'ю' - 16: 0, # 'я' - }, - 25: { # 'ш' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 1, # 'б' - 10: 2, # 'в' - 19: 1, # 'г' - 13: 0, # 'д' - 2: 3, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 3, # 'к' - 8: 3, # 'л' - 12: 2, # 'м' - 5: 3, # 'н' - 1: 3, # 'о' - 15: 2, # 'п' - 9: 2, # 'р' - 7: 1, # 'с' - 6: 2, # 'т' - 14: 3, # 'у' - 39: 2, # 'ф' - 26: 1, # 'х' - 28: 1, # 'ц' - 22: 1, # 'ч' - 25: 1, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 3, # 'ь' - 30: 1, # 'э' - 27: 1, # 'ю' - 16: 0, # 'я' - }, - 29: { # 'щ' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 3, # 'а' - 21: 0, # 'б' - 10: 1, # 'в' - 19: 0, # 'г' - 13: 0, # 'д' - 2: 3, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 3, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 0, # 'л' - 12: 1, # 'м' - 5: 2, # 'н' - 1: 1, # 'о' - 15: 0, # 'п' - 9: 2, # 'р' - 7: 0, # 'с' - 6: 0, # 'т' - 14: 2, # 'у' - 39: 0, # 'ф' - 26: 0, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 2, # 'ь' - 30: 0, # 'э' - 27: 0, # 'ю' - 16: 0, # 'я' - }, - 54: { # 'ъ' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 0, # 'а' - 21: 0, # 'б' - 10: 0, # 'в' - 19: 0, # 'г' - 13: 0, # 'д' - 2: 2, # 'е' - 24: 0, # 'ж' - 20: 0, # 'з' - 4: 0, # 'и' - 23: 0, # 'й' - 11: 0, # 'к' - 8: 0, # 'л' - 12: 0, # 'м' - 5: 0, # 'н' - 1: 0, # 'о' - 15: 0, # 'п' - 9: 0, # 'р' - 7: 0, # 'с' - 6: 0, # 'т' - 14: 0, # 'у' - 39: 0, # 'ф' - 26: 0, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 0, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 0, # 'э' - 27: 1, # 'ю' - 16: 2, # 'я' - }, - 18: { # 'ы' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 0, # 'а' - 21: 3, # 'б' - 10: 3, # 'в' - 19: 2, # 'г' - 13: 2, # 'д' - 2: 3, # 'е' - 24: 2, # 'ж' - 20: 2, # 'з' - 4: 2, # 'и' - 23: 3, # 'й' - 11: 3, # 'к' - 8: 3, # 'л' - 12: 3, # 'м' - 5: 3, # 'н' - 1: 1, # 'о' - 15: 3, # 'п' - 9: 3, # 'р' - 7: 3, # 'с' - 6: 3, # 'т' - 14: 1, # 'у' - 39: 0, # 'ф' - 26: 3, # 'х' - 28: 2, # 'ц' - 22: 3, # 'ч' - 25: 3, # 'ш' - 29: 2, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 0, # 'э' - 27: 0, # 'ю' - 16: 2, # 'я' - }, - 17: { # 'ь' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 0, # 'а' - 21: 2, # 'б' - 10: 2, # 'в' - 19: 2, # 'г' - 13: 2, # 'д' - 2: 3, # 'е' - 24: 1, # 'ж' - 20: 3, # 'з' - 4: 2, # 'и' - 23: 0, # 'й' - 11: 3, # 'к' - 8: 0, # 'л' - 12: 3, # 'м' - 5: 3, # 'н' - 1: 2, # 'о' - 15: 2, # 'п' - 9: 1, # 'р' - 7: 3, # 'с' - 6: 2, # 'т' - 14: 0, # 'у' - 39: 2, # 'ф' - 26: 1, # 'х' - 28: 2, # 'ц' - 22: 2, # 'ч' - 25: 3, # 'ш' - 29: 2, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 1, # 'э' - 27: 3, # 'ю' - 16: 3, # 'я' - }, - 30: { # 'э' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 1, # 'М' - 31: 1, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 1, # 'Р' - 32: 1, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 1, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 0, # 'а' - 21: 1, # 'б' - 10: 1, # 'в' - 19: 1, # 'г' - 13: 2, # 'д' - 2: 1, # 'е' - 24: 0, # 'ж' - 20: 1, # 'з' - 4: 0, # 'и' - 23: 2, # 'й' - 11: 2, # 'к' - 8: 2, # 'л' - 12: 2, # 'м' - 5: 2, # 'н' - 1: 0, # 'о' - 15: 2, # 'п' - 9: 2, # 'р' - 7: 2, # 'с' - 6: 3, # 'т' - 14: 1, # 'у' - 39: 2, # 'ф' - 26: 1, # 'х' - 28: 0, # 'ц' - 22: 0, # 'ч' - 25: 1, # 'ш' - 29: 0, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 1, # 'э' - 27: 1, # 'ю' - 16: 1, # 'я' - }, - 27: { # 'ю' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 2, # 'а' - 21: 3, # 'б' - 10: 1, # 'в' - 19: 2, # 'г' - 13: 3, # 'д' - 2: 1, # 'е' - 24: 2, # 'ж' - 20: 2, # 'з' - 4: 1, # 'и' - 23: 1, # 'й' - 11: 2, # 'к' - 8: 2, # 'л' - 12: 2, # 'м' - 5: 2, # 'н' - 1: 1, # 'о' - 15: 2, # 'п' - 9: 2, # 'р' - 7: 3, # 'с' - 6: 3, # 'т' - 14: 0, # 'у' - 39: 1, # 'ф' - 26: 2, # 'х' - 28: 2, # 'ц' - 22: 2, # 'ч' - 25: 2, # 'ш' - 29: 3, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 1, # 'э' - 27: 2, # 'ю' - 16: 1, # 'я' - }, - 16: { # 'я' - 37: 0, # 'А' - 44: 0, # 'Б' - 33: 0, # 'В' - 46: 0, # 'Г' - 41: 0, # 'Д' - 48: 0, # 'Е' - 56: 0, # 'Ж' - 51: 0, # 'З' - 42: 0, # 'И' - 60: 0, # 'Й' - 36: 0, # 'К' - 49: 0, # 'Л' - 38: 0, # 'М' - 31: 0, # 'Н' - 34: 0, # 'О' - 35: 0, # 'П' - 45: 0, # 'Р' - 32: 0, # 'С' - 40: 0, # 'Т' - 52: 0, # 'У' - 53: 0, # 'Ф' - 55: 0, # 'Х' - 58: 0, # 'Ц' - 50: 0, # 'Ч' - 57: 0, # 'Ш' - 63: 0, # 'Щ' - 62: 0, # 'Ы' - 61: 0, # 'Ь' - 47: 0, # 'Э' - 59: 0, # 'Ю' - 43: 0, # 'Я' - 3: 0, # 'а' - 21: 2, # 'б' - 10: 3, # 'в' - 19: 2, # 'г' - 13: 3, # 'д' - 2: 3, # 'е' - 24: 3, # 'ж' - 20: 3, # 'з' - 4: 2, # 'и' - 23: 2, # 'й' - 11: 3, # 'к' - 8: 3, # 'л' - 12: 3, # 'м' - 5: 3, # 'н' - 1: 0, # 'о' - 15: 2, # 'п' - 9: 2, # 'р' - 7: 3, # 'с' - 6: 3, # 'т' - 14: 1, # 'у' - 39: 1, # 'ф' - 26: 3, # 'х' - 28: 2, # 'ц' - 22: 2, # 'ч' - 25: 2, # 'ш' - 29: 3, # 'щ' - 54: 0, # 'ъ' - 18: 0, # 'ы' - 17: 0, # 'ь' - 30: 0, # 'э' - 27: 2, # 'ю' - 16: 2, # 'я' - }, -} - -# 255: Undefined characters that did not exist in training text -# 254: Carriage/Return -# 253: symbol (punctuation) that does not belong to word -# 252: 0 - 9 -# 251: Control characters - -# Character Mapping Table(s): -IBM866_RUSSIAN_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 142, # 'A' - 66: 143, # 'B' - 67: 144, # 'C' - 68: 145, # 'D' - 69: 146, # 'E' - 70: 147, # 'F' - 71: 148, # 'G' - 72: 149, # 'H' - 73: 150, # 'I' - 74: 151, # 'J' - 75: 152, # 'K' - 76: 74, # 'L' - 77: 153, # 'M' - 78: 75, # 'N' - 79: 154, # 'O' - 80: 155, # 'P' - 81: 156, # 'Q' - 82: 157, # 'R' - 83: 158, # 'S' - 84: 159, # 'T' - 85: 160, # 'U' - 86: 161, # 'V' - 87: 162, # 'W' - 88: 163, # 'X' - 89: 164, # 'Y' - 90: 165, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 71, # 'a' - 98: 172, # 'b' - 99: 66, # 'c' - 100: 173, # 'd' - 101: 65, # 'e' - 102: 174, # 'f' - 103: 76, # 'g' - 104: 175, # 'h' - 105: 64, # 'i' - 106: 176, # 'j' - 107: 177, # 'k' - 108: 77, # 'l' - 109: 72, # 'm' - 110: 178, # 'n' - 111: 69, # 'o' - 112: 67, # 'p' - 113: 179, # 'q' - 114: 78, # 'r' - 115: 73, # 's' - 116: 180, # 't' - 117: 181, # 'u' - 118: 79, # 'v' - 119: 182, # 'w' - 120: 183, # 'x' - 121: 184, # 'y' - 122: 185, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 37, # 'А' - 129: 44, # 'Б' - 130: 33, # 'В' - 131: 46, # 'Г' - 132: 41, # 'Д' - 133: 48, # 'Е' - 134: 56, # 'Ж' - 135: 51, # 'З' - 136: 42, # 'И' - 137: 60, # 'Й' - 138: 36, # 'К' - 139: 49, # 'Л' - 140: 38, # 'М' - 141: 31, # 'Н' - 142: 34, # 'О' - 143: 35, # 'П' - 144: 45, # 'Р' - 145: 32, # 'С' - 146: 40, # 'Т' - 147: 52, # 'У' - 148: 53, # 'Ф' - 149: 55, # 'Х' - 150: 58, # 'Ц' - 151: 50, # 'Ч' - 152: 57, # 'Ш' - 153: 63, # 'Щ' - 154: 70, # 'Ъ' - 155: 62, # 'Ы' - 156: 61, # 'Ь' - 157: 47, # 'Э' - 158: 59, # 'Ю' - 159: 43, # 'Я' - 160: 3, # 'а' - 161: 21, # 'б' - 162: 10, # 'в' - 163: 19, # 'г' - 164: 13, # 'д' - 165: 2, # 'е' - 166: 24, # 'ж' - 167: 20, # 'з' - 168: 4, # 'и' - 169: 23, # 'й' - 170: 11, # 'к' - 171: 8, # 'л' - 172: 12, # 'м' - 173: 5, # 'н' - 174: 1, # 'о' - 175: 15, # 'п' - 176: 191, # '░' - 177: 192, # '▒' - 178: 193, # '▓' - 179: 194, # '│' - 180: 195, # '┤' - 181: 196, # '╡' - 182: 197, # '╢' - 183: 198, # '╖' - 184: 199, # '╕' - 185: 200, # '╣' - 186: 201, # '║' - 187: 202, # '╗' - 188: 203, # '╝' - 189: 204, # '╜' - 190: 205, # '╛' - 191: 206, # '┐' - 192: 207, # '└' - 193: 208, # '┴' - 194: 209, # '┬' - 195: 210, # '├' - 196: 211, # '─' - 197: 212, # '┼' - 198: 213, # '╞' - 199: 214, # '╟' - 200: 215, # '╚' - 201: 216, # '╔' - 202: 217, # '╩' - 203: 218, # '╦' - 204: 219, # '╠' - 205: 220, # '═' - 206: 221, # '╬' - 207: 222, # '╧' - 208: 223, # '╨' - 209: 224, # '╤' - 210: 225, # '╥' - 211: 226, # '╙' - 212: 227, # '╘' - 213: 228, # '╒' - 214: 229, # '╓' - 215: 230, # '╫' - 216: 231, # '╪' - 217: 232, # '┘' - 218: 233, # '┌' - 219: 234, # '█' - 220: 235, # '▄' - 221: 236, # '▌' - 222: 237, # '▐' - 223: 238, # '▀' - 224: 9, # 'р' - 225: 7, # 'с' - 226: 6, # 'т' - 227: 14, # 'у' - 228: 39, # 'ф' - 229: 26, # 'х' - 230: 28, # 'ц' - 231: 22, # 'ч' - 232: 25, # 'ш' - 233: 29, # 'щ' - 234: 54, # 'ъ' - 235: 18, # 'ы' - 236: 17, # 'ь' - 237: 30, # 'э' - 238: 27, # 'ю' - 239: 16, # 'я' - 240: 239, # 'Ё' - 241: 68, # 'ё' - 242: 240, # 'Є' - 243: 241, # 'є' - 244: 242, # 'Ї' - 245: 243, # 'ї' - 246: 244, # 'Ў' - 247: 245, # 'ў' - 248: 246, # '°' - 249: 247, # '∙' - 250: 248, # '·' - 251: 249, # '√' - 252: 250, # '№' - 253: 251, # '¤' - 254: 252, # '■' - 255: 255, # '\xa0' -} - -IBM866_RUSSIAN_MODEL = SingleByteCharSetModel(charset_name='IBM866', - language='Russian', - char_to_order_map=IBM866_RUSSIAN_CHAR_TO_ORDER, - language_model=RUSSIAN_LANG_MODEL, - typical_positive_ratio=0.976601, - keep_ascii_letters=False, - alphabet='ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё') - -WINDOWS_1251_RUSSIAN_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 142, # 'A' - 66: 143, # 'B' - 67: 144, # 'C' - 68: 145, # 'D' - 69: 146, # 'E' - 70: 147, # 'F' - 71: 148, # 'G' - 72: 149, # 'H' - 73: 150, # 'I' - 74: 151, # 'J' - 75: 152, # 'K' - 76: 74, # 'L' - 77: 153, # 'M' - 78: 75, # 'N' - 79: 154, # 'O' - 80: 155, # 'P' - 81: 156, # 'Q' - 82: 157, # 'R' - 83: 158, # 'S' - 84: 159, # 'T' - 85: 160, # 'U' - 86: 161, # 'V' - 87: 162, # 'W' - 88: 163, # 'X' - 89: 164, # 'Y' - 90: 165, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 71, # 'a' - 98: 172, # 'b' - 99: 66, # 'c' - 100: 173, # 'd' - 101: 65, # 'e' - 102: 174, # 'f' - 103: 76, # 'g' - 104: 175, # 'h' - 105: 64, # 'i' - 106: 176, # 'j' - 107: 177, # 'k' - 108: 77, # 'l' - 109: 72, # 'm' - 110: 178, # 'n' - 111: 69, # 'o' - 112: 67, # 'p' - 113: 179, # 'q' - 114: 78, # 'r' - 115: 73, # 's' - 116: 180, # 't' - 117: 181, # 'u' - 118: 79, # 'v' - 119: 182, # 'w' - 120: 183, # 'x' - 121: 184, # 'y' - 122: 185, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 191, # 'Ђ' - 129: 192, # 'Ѓ' - 130: 193, # '‚' - 131: 194, # 'ѓ' - 132: 195, # '„' - 133: 196, # '…' - 134: 197, # '†' - 135: 198, # '‡' - 136: 199, # '€' - 137: 200, # '‰' - 138: 201, # 'Љ' - 139: 202, # '‹' - 140: 203, # 'Њ' - 141: 204, # 'Ќ' - 142: 205, # 'Ћ' - 143: 206, # 'Џ' - 144: 207, # 'ђ' - 145: 208, # '‘' - 146: 209, # '’' - 147: 210, # '“' - 148: 211, # '”' - 149: 212, # '•' - 150: 213, # '–' - 151: 214, # '—' - 152: 215, # None - 153: 216, # '™' - 154: 217, # 'љ' - 155: 218, # '›' - 156: 219, # 'њ' - 157: 220, # 'ќ' - 158: 221, # 'ћ' - 159: 222, # 'џ' - 160: 223, # '\xa0' - 161: 224, # 'Ў' - 162: 225, # 'ў' - 163: 226, # 'Ј' - 164: 227, # '¤' - 165: 228, # 'Ґ' - 166: 229, # '¦' - 167: 230, # '§' - 168: 231, # 'Ё' - 169: 232, # '©' - 170: 233, # 'Є' - 171: 234, # '«' - 172: 235, # '¬' - 173: 236, # '\xad' - 174: 237, # '®' - 175: 238, # 'Ї' - 176: 239, # '°' - 177: 240, # '±' - 178: 241, # 'І' - 179: 242, # 'і' - 180: 243, # 'ґ' - 181: 244, # 'µ' - 182: 245, # '¶' - 183: 246, # '·' - 184: 68, # 'ё' - 185: 247, # '№' - 186: 248, # 'є' - 187: 249, # '»' - 188: 250, # 'ј' - 189: 251, # 'Ѕ' - 190: 252, # 'ѕ' - 191: 253, # 'ї' - 192: 37, # 'А' - 193: 44, # 'Б' - 194: 33, # 'В' - 195: 46, # 'Г' - 196: 41, # 'Д' - 197: 48, # 'Е' - 198: 56, # 'Ж' - 199: 51, # 'З' - 200: 42, # 'И' - 201: 60, # 'Й' - 202: 36, # 'К' - 203: 49, # 'Л' - 204: 38, # 'М' - 205: 31, # 'Н' - 206: 34, # 'О' - 207: 35, # 'П' - 208: 45, # 'Р' - 209: 32, # 'С' - 210: 40, # 'Т' - 211: 52, # 'У' - 212: 53, # 'Ф' - 213: 55, # 'Х' - 214: 58, # 'Ц' - 215: 50, # 'Ч' - 216: 57, # 'Ш' - 217: 63, # 'Щ' - 218: 70, # 'Ъ' - 219: 62, # 'Ы' - 220: 61, # 'Ь' - 221: 47, # 'Э' - 222: 59, # 'Ю' - 223: 43, # 'Я' - 224: 3, # 'а' - 225: 21, # 'б' - 226: 10, # 'в' - 227: 19, # 'г' - 228: 13, # 'д' - 229: 2, # 'е' - 230: 24, # 'ж' - 231: 20, # 'з' - 232: 4, # 'и' - 233: 23, # 'й' - 234: 11, # 'к' - 235: 8, # 'л' - 236: 12, # 'м' - 237: 5, # 'н' - 238: 1, # 'о' - 239: 15, # 'п' - 240: 9, # 'р' - 241: 7, # 'с' - 242: 6, # 'т' - 243: 14, # 'у' - 244: 39, # 'ф' - 245: 26, # 'х' - 246: 28, # 'ц' - 247: 22, # 'ч' - 248: 25, # 'ш' - 249: 29, # 'щ' - 250: 54, # 'ъ' - 251: 18, # 'ы' - 252: 17, # 'ь' - 253: 30, # 'э' - 254: 27, # 'ю' - 255: 16, # 'я' -} - -WINDOWS_1251_RUSSIAN_MODEL = SingleByteCharSetModel(charset_name='windows-1251', - language='Russian', - char_to_order_map=WINDOWS_1251_RUSSIAN_CHAR_TO_ORDER, - language_model=RUSSIAN_LANG_MODEL, - typical_positive_ratio=0.976601, - keep_ascii_letters=False, - alphabet='ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё') - -IBM855_RUSSIAN_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 142, # 'A' - 66: 143, # 'B' - 67: 144, # 'C' - 68: 145, # 'D' - 69: 146, # 'E' - 70: 147, # 'F' - 71: 148, # 'G' - 72: 149, # 'H' - 73: 150, # 'I' - 74: 151, # 'J' - 75: 152, # 'K' - 76: 74, # 'L' - 77: 153, # 'M' - 78: 75, # 'N' - 79: 154, # 'O' - 80: 155, # 'P' - 81: 156, # 'Q' - 82: 157, # 'R' - 83: 158, # 'S' - 84: 159, # 'T' - 85: 160, # 'U' - 86: 161, # 'V' - 87: 162, # 'W' - 88: 163, # 'X' - 89: 164, # 'Y' - 90: 165, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 71, # 'a' - 98: 172, # 'b' - 99: 66, # 'c' - 100: 173, # 'd' - 101: 65, # 'e' - 102: 174, # 'f' - 103: 76, # 'g' - 104: 175, # 'h' - 105: 64, # 'i' - 106: 176, # 'j' - 107: 177, # 'k' - 108: 77, # 'l' - 109: 72, # 'm' - 110: 178, # 'n' - 111: 69, # 'o' - 112: 67, # 'p' - 113: 179, # 'q' - 114: 78, # 'r' - 115: 73, # 's' - 116: 180, # 't' - 117: 181, # 'u' - 118: 79, # 'v' - 119: 182, # 'w' - 120: 183, # 'x' - 121: 184, # 'y' - 122: 185, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 191, # 'ђ' - 129: 192, # 'Ђ' - 130: 193, # 'ѓ' - 131: 194, # 'Ѓ' - 132: 68, # 'ё' - 133: 195, # 'Ё' - 134: 196, # 'є' - 135: 197, # 'Є' - 136: 198, # 'ѕ' - 137: 199, # 'Ѕ' - 138: 200, # 'і' - 139: 201, # 'І' - 140: 202, # 'ї' - 141: 203, # 'Ї' - 142: 204, # 'ј' - 143: 205, # 'Ј' - 144: 206, # 'љ' - 145: 207, # 'Љ' - 146: 208, # 'њ' - 147: 209, # 'Њ' - 148: 210, # 'ћ' - 149: 211, # 'Ћ' - 150: 212, # 'ќ' - 151: 213, # 'Ќ' - 152: 214, # 'ў' - 153: 215, # 'Ў' - 154: 216, # 'џ' - 155: 217, # 'Џ' - 156: 27, # 'ю' - 157: 59, # 'Ю' - 158: 54, # 'ъ' - 159: 70, # 'Ъ' - 160: 3, # 'а' - 161: 37, # 'А' - 162: 21, # 'б' - 163: 44, # 'Б' - 164: 28, # 'ц' - 165: 58, # 'Ц' - 166: 13, # 'д' - 167: 41, # 'Д' - 168: 2, # 'е' - 169: 48, # 'Е' - 170: 39, # 'ф' - 171: 53, # 'Ф' - 172: 19, # 'г' - 173: 46, # 'Г' - 174: 218, # '«' - 175: 219, # '»' - 176: 220, # '░' - 177: 221, # '▒' - 178: 222, # '▓' - 179: 223, # '│' - 180: 224, # '┤' - 181: 26, # 'х' - 182: 55, # 'Х' - 183: 4, # 'и' - 184: 42, # 'И' - 185: 225, # '╣' - 186: 226, # '║' - 187: 227, # '╗' - 188: 228, # '╝' - 189: 23, # 'й' - 190: 60, # 'Й' - 191: 229, # '┐' - 192: 230, # '└' - 193: 231, # '┴' - 194: 232, # '┬' - 195: 233, # '├' - 196: 234, # '─' - 197: 235, # '┼' - 198: 11, # 'к' - 199: 36, # 'К' - 200: 236, # '╚' - 201: 237, # '╔' - 202: 238, # '╩' - 203: 239, # '╦' - 204: 240, # '╠' - 205: 241, # '═' - 206: 242, # '╬' - 207: 243, # '¤' - 208: 8, # 'л' - 209: 49, # 'Л' - 210: 12, # 'м' - 211: 38, # 'М' - 212: 5, # 'н' - 213: 31, # 'Н' - 214: 1, # 'о' - 215: 34, # 'О' - 216: 15, # 'п' - 217: 244, # '┘' - 218: 245, # '┌' - 219: 246, # '█' - 220: 247, # '▄' - 221: 35, # 'П' - 222: 16, # 'я' - 223: 248, # '▀' - 224: 43, # 'Я' - 225: 9, # 'р' - 226: 45, # 'Р' - 227: 7, # 'с' - 228: 32, # 'С' - 229: 6, # 'т' - 230: 40, # 'Т' - 231: 14, # 'у' - 232: 52, # 'У' - 233: 24, # 'ж' - 234: 56, # 'Ж' - 235: 10, # 'в' - 236: 33, # 'В' - 237: 17, # 'ь' - 238: 61, # 'Ь' - 239: 249, # '№' - 240: 250, # '\xad' - 241: 18, # 'ы' - 242: 62, # 'Ы' - 243: 20, # 'з' - 244: 51, # 'З' - 245: 25, # 'ш' - 246: 57, # 'Ш' - 247: 30, # 'э' - 248: 47, # 'Э' - 249: 29, # 'щ' - 250: 63, # 'Щ' - 251: 22, # 'ч' - 252: 50, # 'Ч' - 253: 251, # '§' - 254: 252, # '■' - 255: 255, # '\xa0' -} - -IBM855_RUSSIAN_MODEL = SingleByteCharSetModel(charset_name='IBM855', - language='Russian', - char_to_order_map=IBM855_RUSSIAN_CHAR_TO_ORDER, - language_model=RUSSIAN_LANG_MODEL, - typical_positive_ratio=0.976601, - keep_ascii_letters=False, - alphabet='ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё') - -KOI8_R_RUSSIAN_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 142, # 'A' - 66: 143, # 'B' - 67: 144, # 'C' - 68: 145, # 'D' - 69: 146, # 'E' - 70: 147, # 'F' - 71: 148, # 'G' - 72: 149, # 'H' - 73: 150, # 'I' - 74: 151, # 'J' - 75: 152, # 'K' - 76: 74, # 'L' - 77: 153, # 'M' - 78: 75, # 'N' - 79: 154, # 'O' - 80: 155, # 'P' - 81: 156, # 'Q' - 82: 157, # 'R' - 83: 158, # 'S' - 84: 159, # 'T' - 85: 160, # 'U' - 86: 161, # 'V' - 87: 162, # 'W' - 88: 163, # 'X' - 89: 164, # 'Y' - 90: 165, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 71, # 'a' - 98: 172, # 'b' - 99: 66, # 'c' - 100: 173, # 'd' - 101: 65, # 'e' - 102: 174, # 'f' - 103: 76, # 'g' - 104: 175, # 'h' - 105: 64, # 'i' - 106: 176, # 'j' - 107: 177, # 'k' - 108: 77, # 'l' - 109: 72, # 'm' - 110: 178, # 'n' - 111: 69, # 'o' - 112: 67, # 'p' - 113: 179, # 'q' - 114: 78, # 'r' - 115: 73, # 's' - 116: 180, # 't' - 117: 181, # 'u' - 118: 79, # 'v' - 119: 182, # 'w' - 120: 183, # 'x' - 121: 184, # 'y' - 122: 185, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 191, # '─' - 129: 192, # '│' - 130: 193, # '┌' - 131: 194, # '┐' - 132: 195, # '└' - 133: 196, # '┘' - 134: 197, # '├' - 135: 198, # '┤' - 136: 199, # '┬' - 137: 200, # '┴' - 138: 201, # '┼' - 139: 202, # '▀' - 140: 203, # '▄' - 141: 204, # '█' - 142: 205, # '▌' - 143: 206, # '▐' - 144: 207, # '░' - 145: 208, # '▒' - 146: 209, # '▓' - 147: 210, # '⌠' - 148: 211, # '■' - 149: 212, # '∙' - 150: 213, # '√' - 151: 214, # '≈' - 152: 215, # '≤' - 153: 216, # '≥' - 154: 217, # '\xa0' - 155: 218, # '⌡' - 156: 219, # '°' - 157: 220, # '²' - 158: 221, # '·' - 159: 222, # '÷' - 160: 223, # '═' - 161: 224, # '║' - 162: 225, # '╒' - 163: 68, # 'ё' - 164: 226, # '╓' - 165: 227, # '╔' - 166: 228, # '╕' - 167: 229, # '╖' - 168: 230, # '╗' - 169: 231, # '╘' - 170: 232, # '╙' - 171: 233, # '╚' - 172: 234, # '╛' - 173: 235, # '╜' - 174: 236, # '╝' - 175: 237, # '╞' - 176: 238, # '╟' - 177: 239, # '╠' - 178: 240, # '╡' - 179: 241, # 'Ё' - 180: 242, # '╢' - 181: 243, # '╣' - 182: 244, # '╤' - 183: 245, # '╥' - 184: 246, # '╦' - 185: 247, # '╧' - 186: 248, # '╨' - 187: 249, # '╩' - 188: 250, # '╪' - 189: 251, # '╫' - 190: 252, # '╬' - 191: 253, # '©' - 192: 27, # 'ю' - 193: 3, # 'а' - 194: 21, # 'б' - 195: 28, # 'ц' - 196: 13, # 'д' - 197: 2, # 'е' - 198: 39, # 'ф' - 199: 19, # 'г' - 200: 26, # 'х' - 201: 4, # 'и' - 202: 23, # 'й' - 203: 11, # 'к' - 204: 8, # 'л' - 205: 12, # 'м' - 206: 5, # 'н' - 207: 1, # 'о' - 208: 15, # 'п' - 209: 16, # 'я' - 210: 9, # 'р' - 211: 7, # 'с' - 212: 6, # 'т' - 213: 14, # 'у' - 214: 24, # 'ж' - 215: 10, # 'в' - 216: 17, # 'ь' - 217: 18, # 'ы' - 218: 20, # 'з' - 219: 25, # 'ш' - 220: 30, # 'э' - 221: 29, # 'щ' - 222: 22, # 'ч' - 223: 54, # 'ъ' - 224: 59, # 'Ю' - 225: 37, # 'А' - 226: 44, # 'Б' - 227: 58, # 'Ц' - 228: 41, # 'Д' - 229: 48, # 'Е' - 230: 53, # 'Ф' - 231: 46, # 'Г' - 232: 55, # 'Х' - 233: 42, # 'И' - 234: 60, # 'Й' - 235: 36, # 'К' - 236: 49, # 'Л' - 237: 38, # 'М' - 238: 31, # 'Н' - 239: 34, # 'О' - 240: 35, # 'П' - 241: 43, # 'Я' - 242: 45, # 'Р' - 243: 32, # 'С' - 244: 40, # 'Т' - 245: 52, # 'У' - 246: 56, # 'Ж' - 247: 33, # 'В' - 248: 61, # 'Ь' - 249: 62, # 'Ы' - 250: 51, # 'З' - 251: 57, # 'Ш' - 252: 47, # 'Э' - 253: 63, # 'Щ' - 254: 50, # 'Ч' - 255: 70, # 'Ъ' -} - -KOI8_R_RUSSIAN_MODEL = SingleByteCharSetModel(charset_name='KOI8-R', - language='Russian', - char_to_order_map=KOI8_R_RUSSIAN_CHAR_TO_ORDER, - language_model=RUSSIAN_LANG_MODEL, - typical_positive_ratio=0.976601, - keep_ascii_letters=False, - alphabet='ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё') - -MACCYRILLIC_RUSSIAN_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 142, # 'A' - 66: 143, # 'B' - 67: 144, # 'C' - 68: 145, # 'D' - 69: 146, # 'E' - 70: 147, # 'F' - 71: 148, # 'G' - 72: 149, # 'H' - 73: 150, # 'I' - 74: 151, # 'J' - 75: 152, # 'K' - 76: 74, # 'L' - 77: 153, # 'M' - 78: 75, # 'N' - 79: 154, # 'O' - 80: 155, # 'P' - 81: 156, # 'Q' - 82: 157, # 'R' - 83: 158, # 'S' - 84: 159, # 'T' - 85: 160, # 'U' - 86: 161, # 'V' - 87: 162, # 'W' - 88: 163, # 'X' - 89: 164, # 'Y' - 90: 165, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 71, # 'a' - 98: 172, # 'b' - 99: 66, # 'c' - 100: 173, # 'd' - 101: 65, # 'e' - 102: 174, # 'f' - 103: 76, # 'g' - 104: 175, # 'h' - 105: 64, # 'i' - 106: 176, # 'j' - 107: 177, # 'k' - 108: 77, # 'l' - 109: 72, # 'm' - 110: 178, # 'n' - 111: 69, # 'o' - 112: 67, # 'p' - 113: 179, # 'q' - 114: 78, # 'r' - 115: 73, # 's' - 116: 180, # 't' - 117: 181, # 'u' - 118: 79, # 'v' - 119: 182, # 'w' - 120: 183, # 'x' - 121: 184, # 'y' - 122: 185, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 37, # 'А' - 129: 44, # 'Б' - 130: 33, # 'В' - 131: 46, # 'Г' - 132: 41, # 'Д' - 133: 48, # 'Е' - 134: 56, # 'Ж' - 135: 51, # 'З' - 136: 42, # 'И' - 137: 60, # 'Й' - 138: 36, # 'К' - 139: 49, # 'Л' - 140: 38, # 'М' - 141: 31, # 'Н' - 142: 34, # 'О' - 143: 35, # 'П' - 144: 45, # 'Р' - 145: 32, # 'С' - 146: 40, # 'Т' - 147: 52, # 'У' - 148: 53, # 'Ф' - 149: 55, # 'Х' - 150: 58, # 'Ц' - 151: 50, # 'Ч' - 152: 57, # 'Ш' - 153: 63, # 'Щ' - 154: 70, # 'Ъ' - 155: 62, # 'Ы' - 156: 61, # 'Ь' - 157: 47, # 'Э' - 158: 59, # 'Ю' - 159: 43, # 'Я' - 160: 191, # '†' - 161: 192, # '°' - 162: 193, # 'Ґ' - 163: 194, # '£' - 164: 195, # '§' - 165: 196, # '•' - 166: 197, # '¶' - 167: 198, # 'І' - 168: 199, # '®' - 169: 200, # '©' - 170: 201, # '™' - 171: 202, # 'Ђ' - 172: 203, # 'ђ' - 173: 204, # '≠' - 174: 205, # 'Ѓ' - 175: 206, # 'ѓ' - 176: 207, # '∞' - 177: 208, # '±' - 178: 209, # '≤' - 179: 210, # '≥' - 180: 211, # 'і' - 181: 212, # 'µ' - 182: 213, # 'ґ' - 183: 214, # 'Ј' - 184: 215, # 'Є' - 185: 216, # 'є' - 186: 217, # 'Ї' - 187: 218, # 'ї' - 188: 219, # 'Љ' - 189: 220, # 'љ' - 190: 221, # 'Њ' - 191: 222, # 'њ' - 192: 223, # 'ј' - 193: 224, # 'Ѕ' - 194: 225, # '¬' - 195: 226, # '√' - 196: 227, # 'ƒ' - 197: 228, # '≈' - 198: 229, # '∆' - 199: 230, # '«' - 200: 231, # '»' - 201: 232, # '…' - 202: 233, # '\xa0' - 203: 234, # 'Ћ' - 204: 235, # 'ћ' - 205: 236, # 'Ќ' - 206: 237, # 'ќ' - 207: 238, # 'ѕ' - 208: 239, # '–' - 209: 240, # '—' - 210: 241, # '“' - 211: 242, # '”' - 212: 243, # '‘' - 213: 244, # '’' - 214: 245, # '÷' - 215: 246, # '„' - 216: 247, # 'Ў' - 217: 248, # 'ў' - 218: 249, # 'Џ' - 219: 250, # 'џ' - 220: 251, # '№' - 221: 252, # 'Ё' - 222: 68, # 'ё' - 223: 16, # 'я' - 224: 3, # 'а' - 225: 21, # 'б' - 226: 10, # 'в' - 227: 19, # 'г' - 228: 13, # 'д' - 229: 2, # 'е' - 230: 24, # 'ж' - 231: 20, # 'з' - 232: 4, # 'и' - 233: 23, # 'й' - 234: 11, # 'к' - 235: 8, # 'л' - 236: 12, # 'м' - 237: 5, # 'н' - 238: 1, # 'о' - 239: 15, # 'п' - 240: 9, # 'р' - 241: 7, # 'с' - 242: 6, # 'т' - 243: 14, # 'у' - 244: 39, # 'ф' - 245: 26, # 'х' - 246: 28, # 'ц' - 247: 22, # 'ч' - 248: 25, # 'ш' - 249: 29, # 'щ' - 250: 54, # 'ъ' - 251: 18, # 'ы' - 252: 17, # 'ь' - 253: 30, # 'э' - 254: 27, # 'ю' - 255: 255, # '€' -} - -MACCYRILLIC_RUSSIAN_MODEL = SingleByteCharSetModel(charset_name='MacCyrillic', - language='Russian', - char_to_order_map=MACCYRILLIC_RUSSIAN_CHAR_TO_ORDER, - language_model=RUSSIAN_LANG_MODEL, - typical_positive_ratio=0.976601, - keep_ascii_letters=False, - alphabet='ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё') - -ISO_8859_5_RUSSIAN_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 142, # 'A' - 66: 143, # 'B' - 67: 144, # 'C' - 68: 145, # 'D' - 69: 146, # 'E' - 70: 147, # 'F' - 71: 148, # 'G' - 72: 149, # 'H' - 73: 150, # 'I' - 74: 151, # 'J' - 75: 152, # 'K' - 76: 74, # 'L' - 77: 153, # 'M' - 78: 75, # 'N' - 79: 154, # 'O' - 80: 155, # 'P' - 81: 156, # 'Q' - 82: 157, # 'R' - 83: 158, # 'S' - 84: 159, # 'T' - 85: 160, # 'U' - 86: 161, # 'V' - 87: 162, # 'W' - 88: 163, # 'X' - 89: 164, # 'Y' - 90: 165, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 71, # 'a' - 98: 172, # 'b' - 99: 66, # 'c' - 100: 173, # 'd' - 101: 65, # 'e' - 102: 174, # 'f' - 103: 76, # 'g' - 104: 175, # 'h' - 105: 64, # 'i' - 106: 176, # 'j' - 107: 177, # 'k' - 108: 77, # 'l' - 109: 72, # 'm' - 110: 178, # 'n' - 111: 69, # 'o' - 112: 67, # 'p' - 113: 179, # 'q' - 114: 78, # 'r' - 115: 73, # 's' - 116: 180, # 't' - 117: 181, # 'u' - 118: 79, # 'v' - 119: 182, # 'w' - 120: 183, # 'x' - 121: 184, # 'y' - 122: 185, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 191, # '\x80' - 129: 192, # '\x81' - 130: 193, # '\x82' - 131: 194, # '\x83' - 132: 195, # '\x84' - 133: 196, # '\x85' - 134: 197, # '\x86' - 135: 198, # '\x87' - 136: 199, # '\x88' - 137: 200, # '\x89' - 138: 201, # '\x8a' - 139: 202, # '\x8b' - 140: 203, # '\x8c' - 141: 204, # '\x8d' - 142: 205, # '\x8e' - 143: 206, # '\x8f' - 144: 207, # '\x90' - 145: 208, # '\x91' - 146: 209, # '\x92' - 147: 210, # '\x93' - 148: 211, # '\x94' - 149: 212, # '\x95' - 150: 213, # '\x96' - 151: 214, # '\x97' - 152: 215, # '\x98' - 153: 216, # '\x99' - 154: 217, # '\x9a' - 155: 218, # '\x9b' - 156: 219, # '\x9c' - 157: 220, # '\x9d' - 158: 221, # '\x9e' - 159: 222, # '\x9f' - 160: 223, # '\xa0' - 161: 224, # 'Ё' - 162: 225, # 'Ђ' - 163: 226, # 'Ѓ' - 164: 227, # 'Є' - 165: 228, # 'Ѕ' - 166: 229, # 'І' - 167: 230, # 'Ї' - 168: 231, # 'Ј' - 169: 232, # 'Љ' - 170: 233, # 'Њ' - 171: 234, # 'Ћ' - 172: 235, # 'Ќ' - 173: 236, # '\xad' - 174: 237, # 'Ў' - 175: 238, # 'Џ' - 176: 37, # 'А' - 177: 44, # 'Б' - 178: 33, # 'В' - 179: 46, # 'Г' - 180: 41, # 'Д' - 181: 48, # 'Е' - 182: 56, # 'Ж' - 183: 51, # 'З' - 184: 42, # 'И' - 185: 60, # 'Й' - 186: 36, # 'К' - 187: 49, # 'Л' - 188: 38, # 'М' - 189: 31, # 'Н' - 190: 34, # 'О' - 191: 35, # 'П' - 192: 45, # 'Р' - 193: 32, # 'С' - 194: 40, # 'Т' - 195: 52, # 'У' - 196: 53, # 'Ф' - 197: 55, # 'Х' - 198: 58, # 'Ц' - 199: 50, # 'Ч' - 200: 57, # 'Ш' - 201: 63, # 'Щ' - 202: 70, # 'Ъ' - 203: 62, # 'Ы' - 204: 61, # 'Ь' - 205: 47, # 'Э' - 206: 59, # 'Ю' - 207: 43, # 'Я' - 208: 3, # 'а' - 209: 21, # 'б' - 210: 10, # 'в' - 211: 19, # 'г' - 212: 13, # 'д' - 213: 2, # 'е' - 214: 24, # 'ж' - 215: 20, # 'з' - 216: 4, # 'и' - 217: 23, # 'й' - 218: 11, # 'к' - 219: 8, # 'л' - 220: 12, # 'м' - 221: 5, # 'н' - 222: 1, # 'о' - 223: 15, # 'п' - 224: 9, # 'р' - 225: 7, # 'с' - 226: 6, # 'т' - 227: 14, # 'у' - 228: 39, # 'ф' - 229: 26, # 'х' - 230: 28, # 'ц' - 231: 22, # 'ч' - 232: 25, # 'ш' - 233: 29, # 'щ' - 234: 54, # 'ъ' - 235: 18, # 'ы' - 236: 17, # 'ь' - 237: 30, # 'э' - 238: 27, # 'ю' - 239: 16, # 'я' - 240: 239, # '№' - 241: 68, # 'ё' - 242: 240, # 'ђ' - 243: 241, # 'ѓ' - 244: 242, # 'є' - 245: 243, # 'ѕ' - 246: 244, # 'і' - 247: 245, # 'ї' - 248: 246, # 'ј' - 249: 247, # 'љ' - 250: 248, # 'њ' - 251: 249, # 'ћ' - 252: 250, # 'ќ' - 253: 251, # '§' - 254: 252, # 'ў' - 255: 255, # 'џ' -} - -ISO_8859_5_RUSSIAN_MODEL = SingleByteCharSetModel(charset_name='ISO-8859-5', - language='Russian', - char_to_order_map=ISO_8859_5_RUSSIAN_CHAR_TO_ORDER, - language_model=RUSSIAN_LANG_MODEL, - typical_positive_ratio=0.976601, - keep_ascii_letters=False, - alphabet='ЁАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюяё') - diff --git a/venv/lib/python3.8/site-packages/chardet/langthaimodel.py b/venv/lib/python3.8/site-packages/chardet/langthaimodel.py deleted file mode 100644 index d0191f2..0000000 --- a/venv/lib/python3.8/site-packages/chardet/langthaimodel.py +++ /dev/null @@ -1,4383 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from chardet.sbcharsetprober import SingleByteCharSetModel - - -# 3: Positive -# 2: Likely -# 1: Unlikely -# 0: Negative - -THAI_LANG_MODEL = { - 5: { # 'ก' - 5: 2, # 'ก' - 30: 2, # 'ข' - 24: 2, # 'ค' - 8: 2, # 'ง' - 26: 2, # 'จ' - 52: 0, # 'ฉ' - 34: 1, # 'ช' - 51: 1, # 'ซ' - 47: 0, # 'ญ' - 58: 3, # 'ฎ' - 57: 2, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 2, # 'ณ' - 20: 2, # 'ด' - 19: 3, # 'ต' - 44: 0, # 'ถ' - 14: 2, # 'ท' - 48: 0, # 'ธ' - 3: 2, # 'น' - 17: 1, # 'บ' - 25: 2, # 'ป' - 39: 1, # 'ผ' - 62: 1, # 'ฝ' - 31: 1, # 'พ' - 54: 0, # 'ฟ' - 45: 1, # 'ภ' - 9: 2, # 'ม' - 16: 1, # 'ย' - 2: 3, # 'ร' - 61: 2, # 'ฤ' - 15: 3, # 'ล' - 12: 3, # 'ว' - 42: 2, # 'ศ' - 46: 3, # 'ษ' - 18: 2, # 'ส' - 21: 2, # 'ห' - 4: 3, # 'อ' - 63: 1, # 'ฯ' - 22: 2, # 'ะ' - 10: 3, # 'ั' - 1: 3, # 'า' - 36: 3, # 'ำ' - 23: 3, # 'ิ' - 13: 3, # 'ี' - 40: 0, # 'ึ' - 27: 2, # 'ื' - 32: 2, # 'ุ' - 35: 1, # 'ู' - 11: 2, # 'เ' - 28: 2, # 'แ' - 41: 1, # 'โ' - 29: 1, # 'ใ' - 33: 2, # 'ไ' - 50: 1, # 'ๆ' - 37: 3, # '็' - 6: 3, # '่' - 7: 3, # '้' - 38: 2, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 30: { # 'ข' - 5: 1, # 'ก' - 30: 0, # 'ข' - 24: 1, # 'ค' - 8: 1, # 'ง' - 26: 1, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 2, # 'ณ' - 20: 0, # 'ด' - 19: 2, # 'ต' - 44: 0, # 'ถ' - 14: 1, # 'ท' - 48: 0, # 'ธ' - 3: 2, # 'น' - 17: 1, # 'บ' - 25: 1, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 0, # 'ม' - 16: 2, # 'ย' - 2: 1, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 2, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 1, # 'ส' - 21: 1, # 'ห' - 4: 3, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 3, # 'ั' - 1: 3, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 2, # 'ี' - 40: 3, # 'ึ' - 27: 1, # 'ื' - 32: 1, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 1, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 1, # '็' - 6: 2, # '่' - 7: 3, # '้' - 38: 1, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 24: { # 'ค' - 5: 0, # 'ก' - 30: 0, # 'ข' - 24: 2, # 'ค' - 8: 2, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 2, # 'ณ' - 20: 2, # 'ด' - 19: 2, # 'ต' - 44: 0, # 'ถ' - 14: 1, # 'ท' - 48: 0, # 'ธ' - 3: 3, # 'น' - 17: 0, # 'บ' - 25: 1, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 2, # 'ม' - 16: 2, # 'ย' - 2: 3, # 'ร' - 61: 0, # 'ฤ' - 15: 3, # 'ล' - 12: 3, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 1, # 'ส' - 21: 0, # 'ห' - 4: 2, # 'อ' - 63: 0, # 'ฯ' - 22: 2, # 'ะ' - 10: 3, # 'ั' - 1: 2, # 'า' - 36: 3, # 'ำ' - 23: 3, # 'ิ' - 13: 2, # 'ี' - 40: 0, # 'ึ' - 27: 3, # 'ื' - 32: 3, # 'ุ' - 35: 2, # 'ู' - 11: 1, # 'เ' - 28: 0, # 'แ' - 41: 3, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 1, # '็' - 6: 3, # '่' - 7: 3, # '้' - 38: 3, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 8: { # 'ง' - 5: 3, # 'ก' - 30: 2, # 'ข' - 24: 3, # 'ค' - 8: 2, # 'ง' - 26: 2, # 'จ' - 52: 1, # 'ฉ' - 34: 2, # 'ช' - 51: 1, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 2, # 'ด' - 19: 2, # 'ต' - 44: 1, # 'ถ' - 14: 3, # 'ท' - 48: 1, # 'ธ' - 3: 3, # 'น' - 17: 2, # 'บ' - 25: 2, # 'ป' - 39: 2, # 'ผ' - 62: 1, # 'ฝ' - 31: 2, # 'พ' - 54: 0, # 'ฟ' - 45: 1, # 'ภ' - 9: 2, # 'ม' - 16: 1, # 'ย' - 2: 2, # 'ร' - 61: 0, # 'ฤ' - 15: 2, # 'ล' - 12: 2, # 'ว' - 42: 2, # 'ศ' - 46: 1, # 'ษ' - 18: 3, # 'ส' - 21: 3, # 'ห' - 4: 2, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 1, # 'ั' - 1: 3, # 'า' - 36: 0, # 'ำ' - 23: 2, # 'ิ' - 13: 1, # 'ี' - 40: 0, # 'ึ' - 27: 1, # 'ื' - 32: 1, # 'ุ' - 35: 0, # 'ู' - 11: 3, # 'เ' - 28: 2, # 'แ' - 41: 1, # 'โ' - 29: 2, # 'ใ' - 33: 2, # 'ไ' - 50: 3, # 'ๆ' - 37: 0, # '็' - 6: 2, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 26: { # 'จ' - 5: 2, # 'ก' - 30: 1, # 'ข' - 24: 0, # 'ค' - 8: 2, # 'ง' - 26: 3, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 2, # 'ด' - 19: 1, # 'ต' - 44: 1, # 'ถ' - 14: 2, # 'ท' - 48: 0, # 'ธ' - 3: 3, # 'น' - 17: 1, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 1, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 1, # 'ม' - 16: 1, # 'ย' - 2: 3, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 1, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 2, # 'ส' - 21: 1, # 'ห' - 4: 2, # 'อ' - 63: 0, # 'ฯ' - 22: 3, # 'ะ' - 10: 3, # 'ั' - 1: 3, # 'า' - 36: 3, # 'ำ' - 23: 2, # 'ิ' - 13: 1, # 'ี' - 40: 3, # 'ึ' - 27: 1, # 'ื' - 32: 3, # 'ุ' - 35: 2, # 'ู' - 11: 1, # 'เ' - 28: 1, # 'แ' - 41: 0, # 'โ' - 29: 1, # 'ใ' - 33: 1, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 2, # '่' - 7: 2, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 52: { # 'ฉ' - 5: 0, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 0, # 'น' - 17: 3, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 3, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 1, # 'ม' - 16: 1, # 'ย' - 2: 0, # 'ร' - 61: 0, # 'ฤ' - 15: 2, # 'ล' - 12: 1, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 0, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 1, # 'ะ' - 10: 1, # 'ั' - 1: 1, # 'า' - 36: 0, # 'ำ' - 23: 1, # 'ิ' - 13: 1, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 1, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 34: { # 'ช' - 5: 1, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 1, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 1, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 1, # 'ท' - 48: 0, # 'ธ' - 3: 3, # 'น' - 17: 2, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 2, # 'ม' - 16: 1, # 'ย' - 2: 1, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 1, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 0, # 'ห' - 4: 2, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 2, # 'ั' - 1: 3, # 'า' - 36: 1, # 'ำ' - 23: 3, # 'ิ' - 13: 2, # 'ี' - 40: 0, # 'ึ' - 27: 3, # 'ื' - 32: 3, # 'ุ' - 35: 1, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 1, # '็' - 6: 3, # '่' - 7: 3, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 51: { # 'ซ' - 5: 0, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 1, # 'น' - 17: 0, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 0, # 'ม' - 16: 0, # 'ย' - 2: 0, # 'ร' - 61: 0, # 'ฤ' - 15: 1, # 'ล' - 12: 0, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 1, # 'ส' - 21: 0, # 'ห' - 4: 2, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 1, # 'ั' - 1: 1, # 'า' - 36: 0, # 'ำ' - 23: 1, # 'ิ' - 13: 2, # 'ี' - 40: 3, # 'ึ' - 27: 2, # 'ื' - 32: 1, # 'ุ' - 35: 1, # 'ู' - 11: 1, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 1, # '็' - 6: 1, # '่' - 7: 2, # '้' - 38: 1, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 47: { # 'ญ' - 5: 1, # 'ก' - 30: 1, # 'ข' - 24: 0, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 1, # 'ช' - 51: 0, # 'ซ' - 47: 3, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 1, # 'ท' - 48: 0, # 'ธ' - 3: 0, # 'น' - 17: 1, # 'บ' - 25: 1, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 1, # 'ม' - 16: 0, # 'ย' - 2: 0, # 'ร' - 61: 0, # 'ฤ' - 15: 1, # 'ล' - 12: 0, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 1, # 'ส' - 21: 2, # 'ห' - 4: 1, # 'อ' - 63: 0, # 'ฯ' - 22: 1, # 'ะ' - 10: 2, # 'ั' - 1: 3, # 'า' - 36: 0, # 'ำ' - 23: 1, # 'ิ' - 13: 1, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 1, # 'เ' - 28: 1, # 'แ' - 41: 0, # 'โ' - 29: 1, # 'ใ' - 33: 0, # 'ไ' - 50: 1, # 'ๆ' - 37: 0, # '็' - 6: 2, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 58: { # 'ฎ' - 5: 2, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 0, # 'น' - 17: 0, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 0, # 'ม' - 16: 0, # 'ย' - 2: 0, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 0, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 1, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 1, # 'ิ' - 13: 2, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 57: { # 'ฏ' - 5: 0, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 0, # 'น' - 17: 0, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 0, # 'ม' - 16: 0, # 'ย' - 2: 0, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 0, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 0, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 3, # 'ิ' - 13: 1, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 49: { # 'ฐ' - 5: 1, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 0, # 'น' - 17: 2, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 2, # 'ม' - 16: 0, # 'ย' - 2: 0, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 0, # 'ว' - 42: 1, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 0, # 'ห' - 4: 1, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 3, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 1, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 53: { # 'ฑ' - 5: 0, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 0, # 'น' - 17: 0, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 0, # 'ม' - 16: 0, # 'ย' - 2: 0, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 0, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 0, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 2, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 3, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 55: { # 'ฒ' - 5: 0, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 3, # 'น' - 17: 0, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 1, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 0, # 'ม' - 16: 0, # 'ย' - 2: 0, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 0, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 0, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 1, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 43: { # 'ณ' - 5: 1, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 3, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 0, # 'น' - 17: 0, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 3, # 'ภ' - 9: 0, # 'ม' - 16: 0, # 'ย' - 2: 1, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 1, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 1, # 'ส' - 21: 1, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 3, # 'ะ' - 10: 0, # 'ั' - 1: 3, # 'า' - 36: 0, # 'ำ' - 23: 1, # 'ิ' - 13: 2, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 1, # 'เ' - 28: 1, # 'แ' - 41: 0, # 'โ' - 29: 1, # 'ใ' - 33: 1, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 3, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 20: { # 'ด' - 5: 2, # 'ก' - 30: 2, # 'ข' - 24: 2, # 'ค' - 8: 3, # 'ง' - 26: 2, # 'จ' - 52: 0, # 'ฉ' - 34: 1, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 1, # 'ด' - 19: 2, # 'ต' - 44: 1, # 'ถ' - 14: 2, # 'ท' - 48: 0, # 'ธ' - 3: 1, # 'น' - 17: 1, # 'บ' - 25: 1, # 'ป' - 39: 1, # 'ผ' - 62: 0, # 'ฝ' - 31: 1, # 'พ' - 54: 0, # 'ฟ' - 45: 1, # 'ภ' - 9: 2, # 'ม' - 16: 3, # 'ย' - 2: 2, # 'ร' - 61: 0, # 'ฤ' - 15: 2, # 'ล' - 12: 2, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 2, # 'ส' - 21: 2, # 'ห' - 4: 1, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 3, # 'ั' - 1: 2, # 'า' - 36: 2, # 'ำ' - 23: 3, # 'ิ' - 13: 3, # 'ี' - 40: 1, # 'ึ' - 27: 2, # 'ื' - 32: 3, # 'ุ' - 35: 2, # 'ู' - 11: 2, # 'เ' - 28: 2, # 'แ' - 41: 1, # 'โ' - 29: 2, # 'ใ' - 33: 2, # 'ไ' - 50: 2, # 'ๆ' - 37: 2, # '็' - 6: 1, # '่' - 7: 3, # '้' - 38: 1, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 19: { # 'ต' - 5: 2, # 'ก' - 30: 1, # 'ข' - 24: 1, # 'ค' - 8: 0, # 'ง' - 26: 1, # 'จ' - 52: 0, # 'ฉ' - 34: 1, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 1, # 'ด' - 19: 1, # 'ต' - 44: 2, # 'ถ' - 14: 1, # 'ท' - 48: 0, # 'ธ' - 3: 2, # 'น' - 17: 1, # 'บ' - 25: 1, # 'ป' - 39: 1, # 'ผ' - 62: 0, # 'ฝ' - 31: 1, # 'พ' - 54: 0, # 'ฟ' - 45: 2, # 'ภ' - 9: 1, # 'ม' - 16: 1, # 'ย' - 2: 3, # 'ร' - 61: 0, # 'ฤ' - 15: 2, # 'ล' - 12: 1, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 3, # 'ส' - 21: 0, # 'ห' - 4: 3, # 'อ' - 63: 1, # 'ฯ' - 22: 2, # 'ะ' - 10: 3, # 'ั' - 1: 3, # 'า' - 36: 2, # 'ำ' - 23: 3, # 'ิ' - 13: 2, # 'ี' - 40: 1, # 'ึ' - 27: 1, # 'ื' - 32: 3, # 'ุ' - 35: 2, # 'ู' - 11: 1, # 'เ' - 28: 1, # 'แ' - 41: 1, # 'โ' - 29: 1, # 'ใ' - 33: 1, # 'ไ' - 50: 0, # 'ๆ' - 37: 2, # '็' - 6: 3, # '่' - 7: 3, # '้' - 38: 2, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 44: { # 'ถ' - 5: 1, # 'ก' - 30: 0, # 'ข' - 24: 1, # 'ค' - 8: 0, # 'ง' - 26: 1, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 1, # 'ต' - 44: 0, # 'ถ' - 14: 1, # 'ท' - 48: 0, # 'ธ' - 3: 1, # 'น' - 17: 2, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 1, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 0, # 'ม' - 16: 0, # 'ย' - 2: 1, # 'ร' - 61: 0, # 'ฤ' - 15: 1, # 'ล' - 12: 1, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 1, # 'ส' - 21: 0, # 'ห' - 4: 1, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 2, # 'ั' - 1: 3, # 'า' - 36: 0, # 'ำ' - 23: 2, # 'ิ' - 13: 1, # 'ี' - 40: 3, # 'ึ' - 27: 2, # 'ื' - 32: 2, # 'ุ' - 35: 3, # 'ู' - 11: 1, # 'เ' - 28: 1, # 'แ' - 41: 0, # 'โ' - 29: 1, # 'ใ' - 33: 1, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 2, # '่' - 7: 3, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 14: { # 'ท' - 5: 1, # 'ก' - 30: 1, # 'ข' - 24: 3, # 'ค' - 8: 1, # 'ง' - 26: 1, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 2, # 'ด' - 19: 1, # 'ต' - 44: 0, # 'ถ' - 14: 1, # 'ท' - 48: 3, # 'ธ' - 3: 3, # 'น' - 17: 2, # 'บ' - 25: 2, # 'ป' - 39: 1, # 'ผ' - 62: 0, # 'ฝ' - 31: 2, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 1, # 'ม' - 16: 3, # 'ย' - 2: 3, # 'ร' - 61: 1, # 'ฤ' - 15: 1, # 'ล' - 12: 2, # 'ว' - 42: 3, # 'ศ' - 46: 1, # 'ษ' - 18: 1, # 'ส' - 21: 0, # 'ห' - 4: 2, # 'อ' - 63: 0, # 'ฯ' - 22: 2, # 'ะ' - 10: 3, # 'ั' - 1: 3, # 'า' - 36: 3, # 'ำ' - 23: 2, # 'ิ' - 13: 3, # 'ี' - 40: 2, # 'ึ' - 27: 1, # 'ื' - 32: 3, # 'ุ' - 35: 1, # 'ู' - 11: 0, # 'เ' - 28: 1, # 'แ' - 41: 0, # 'โ' - 29: 1, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 1, # '็' - 6: 3, # '่' - 7: 3, # '้' - 38: 2, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 48: { # 'ธ' - 5: 0, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 1, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 1, # 'น' - 17: 0, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 0, # 'ม' - 16: 0, # 'ย' - 2: 2, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 0, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 0, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 2, # 'า' - 36: 0, # 'ำ' - 23: 3, # 'ิ' - 13: 3, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 2, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 3, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 3: { # 'น' - 5: 3, # 'ก' - 30: 2, # 'ข' - 24: 3, # 'ค' - 8: 1, # 'ง' - 26: 2, # 'จ' - 52: 0, # 'ฉ' - 34: 1, # 'ช' - 51: 1, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 1, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 3, # 'ด' - 19: 3, # 'ต' - 44: 2, # 'ถ' - 14: 3, # 'ท' - 48: 3, # 'ธ' - 3: 2, # 'น' - 17: 2, # 'บ' - 25: 2, # 'ป' - 39: 2, # 'ผ' - 62: 0, # 'ฝ' - 31: 2, # 'พ' - 54: 1, # 'ฟ' - 45: 1, # 'ภ' - 9: 2, # 'ม' - 16: 2, # 'ย' - 2: 2, # 'ร' - 61: 1, # 'ฤ' - 15: 2, # 'ล' - 12: 3, # 'ว' - 42: 1, # 'ศ' - 46: 0, # 'ษ' - 18: 2, # 'ส' - 21: 2, # 'ห' - 4: 3, # 'อ' - 63: 1, # 'ฯ' - 22: 2, # 'ะ' - 10: 3, # 'ั' - 1: 3, # 'า' - 36: 3, # 'ำ' - 23: 3, # 'ิ' - 13: 3, # 'ี' - 40: 3, # 'ึ' - 27: 3, # 'ื' - 32: 3, # 'ุ' - 35: 2, # 'ู' - 11: 3, # 'เ' - 28: 2, # 'แ' - 41: 3, # 'โ' - 29: 3, # 'ใ' - 33: 3, # 'ไ' - 50: 2, # 'ๆ' - 37: 1, # '็' - 6: 3, # '่' - 7: 3, # '้' - 38: 2, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 17: { # 'บ' - 5: 3, # 'ก' - 30: 2, # 'ข' - 24: 2, # 'ค' - 8: 1, # 'ง' - 26: 1, # 'จ' - 52: 1, # 'ฉ' - 34: 1, # 'ช' - 51: 1, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 1, # 'ด' - 19: 2, # 'ต' - 44: 1, # 'ถ' - 14: 3, # 'ท' - 48: 0, # 'ธ' - 3: 3, # 'น' - 17: 3, # 'บ' - 25: 2, # 'ป' - 39: 2, # 'ผ' - 62: 0, # 'ฝ' - 31: 1, # 'พ' - 54: 1, # 'ฟ' - 45: 1, # 'ภ' - 9: 1, # 'ม' - 16: 0, # 'ย' - 2: 3, # 'ร' - 61: 0, # 'ฤ' - 15: 2, # 'ล' - 12: 3, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 2, # 'ส' - 21: 2, # 'ห' - 4: 2, # 'อ' - 63: 1, # 'ฯ' - 22: 0, # 'ะ' - 10: 3, # 'ั' - 1: 3, # 'า' - 36: 2, # 'ำ' - 23: 2, # 'ิ' - 13: 2, # 'ี' - 40: 0, # 'ึ' - 27: 2, # 'ื' - 32: 3, # 'ุ' - 35: 2, # 'ู' - 11: 2, # 'เ' - 28: 2, # 'แ' - 41: 1, # 'โ' - 29: 2, # 'ใ' - 33: 2, # 'ไ' - 50: 0, # 'ๆ' - 37: 1, # '็' - 6: 2, # '่' - 7: 2, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 25: { # 'ป' - 5: 2, # 'ก' - 30: 0, # 'ข' - 24: 1, # 'ค' - 8: 0, # 'ง' - 26: 1, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 1, # 'ซ' - 47: 0, # 'ญ' - 58: 1, # 'ฎ' - 57: 3, # 'ฏ' - 49: 1, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 1, # 'ด' - 19: 1, # 'ต' - 44: 1, # 'ถ' - 14: 1, # 'ท' - 48: 0, # 'ธ' - 3: 2, # 'น' - 17: 0, # 'บ' - 25: 1, # 'ป' - 39: 1, # 'ผ' - 62: 1, # 'ฝ' - 31: 1, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 1, # 'ม' - 16: 0, # 'ย' - 2: 3, # 'ร' - 61: 0, # 'ฤ' - 15: 3, # 'ล' - 12: 1, # 'ว' - 42: 0, # 'ศ' - 46: 1, # 'ษ' - 18: 2, # 'ส' - 21: 1, # 'ห' - 4: 2, # 'อ' - 63: 0, # 'ฯ' - 22: 1, # 'ะ' - 10: 3, # 'ั' - 1: 1, # 'า' - 36: 0, # 'ำ' - 23: 2, # 'ิ' - 13: 3, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 1, # 'ุ' - 35: 0, # 'ู' - 11: 1, # 'เ' - 28: 2, # 'แ' - 41: 0, # 'โ' - 29: 1, # 'ใ' - 33: 2, # 'ไ' - 50: 0, # 'ๆ' - 37: 3, # '็' - 6: 1, # '่' - 7: 2, # '้' - 38: 1, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 39: { # 'ผ' - 5: 1, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 1, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 2, # 'น' - 17: 0, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 1, # 'ม' - 16: 2, # 'ย' - 2: 0, # 'ร' - 61: 0, # 'ฤ' - 15: 3, # 'ล' - 12: 0, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 1, # 'ส' - 21: 0, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 1, # 'ะ' - 10: 1, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 2, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 1, # 'ื' - 32: 0, # 'ุ' - 35: 3, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 3, # '่' - 7: 1, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 62: { # 'ฝ' - 5: 0, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 1, # 'น' - 17: 0, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 0, # 'ม' - 16: 0, # 'ย' - 2: 1, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 0, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 0, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 1, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 1, # 'ี' - 40: 2, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 2, # '่' - 7: 1, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 31: { # 'พ' - 5: 1, # 'ก' - 30: 1, # 'ข' - 24: 1, # 'ค' - 8: 1, # 'ง' - 26: 1, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 1, # 'ณ' - 20: 1, # 'ด' - 19: 1, # 'ต' - 44: 0, # 'ถ' - 14: 2, # 'ท' - 48: 1, # 'ธ' - 3: 3, # 'น' - 17: 2, # 'บ' - 25: 0, # 'ป' - 39: 1, # 'ผ' - 62: 0, # 'ฝ' - 31: 1, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 1, # 'ม' - 16: 2, # 'ย' - 2: 3, # 'ร' - 61: 2, # 'ฤ' - 15: 2, # 'ล' - 12: 2, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 1, # 'ส' - 21: 1, # 'ห' - 4: 2, # 'อ' - 63: 1, # 'ฯ' - 22: 0, # 'ะ' - 10: 3, # 'ั' - 1: 3, # 'า' - 36: 0, # 'ำ' - 23: 3, # 'ิ' - 13: 2, # 'ี' - 40: 1, # 'ึ' - 27: 3, # 'ื' - 32: 1, # 'ุ' - 35: 2, # 'ู' - 11: 1, # 'เ' - 28: 1, # 'แ' - 41: 0, # 'โ' - 29: 1, # 'ใ' - 33: 1, # 'ไ' - 50: 0, # 'ๆ' - 37: 1, # '็' - 6: 0, # '่' - 7: 1, # '้' - 38: 3, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 54: { # 'ฟ' - 5: 0, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 1, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 1, # 'ต' - 44: 0, # 'ถ' - 14: 1, # 'ท' - 48: 0, # 'ธ' - 3: 0, # 'น' - 17: 0, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 2, # 'ฟ' - 45: 0, # 'ภ' - 9: 0, # 'ม' - 16: 0, # 'ย' - 2: 1, # 'ร' - 61: 0, # 'ฤ' - 15: 2, # 'ล' - 12: 0, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 1, # 'ส' - 21: 0, # 'ห' - 4: 1, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 2, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 1, # 'ิ' - 13: 1, # 'ี' - 40: 0, # 'ึ' - 27: 1, # 'ื' - 32: 1, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 1, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 2, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 45: { # 'ภ' - 5: 0, # 'ก' - 30: 0, # 'ข' - 24: 1, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 3, # 'ท' - 48: 0, # 'ธ' - 3: 0, # 'น' - 17: 0, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 1, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 0, # 'ม' - 16: 0, # 'ย' - 2: 1, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 0, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 0, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 3, # 'ั' - 1: 3, # 'า' - 36: 0, # 'ำ' - 23: 1, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 2, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 1, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 9: { # 'ม' - 5: 2, # 'ก' - 30: 2, # 'ข' - 24: 2, # 'ค' - 8: 2, # 'ง' - 26: 2, # 'จ' - 52: 0, # 'ฉ' - 34: 1, # 'ช' - 51: 1, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 1, # 'ณ' - 20: 2, # 'ด' - 19: 2, # 'ต' - 44: 1, # 'ถ' - 14: 2, # 'ท' - 48: 1, # 'ธ' - 3: 3, # 'น' - 17: 2, # 'บ' - 25: 2, # 'ป' - 39: 1, # 'ผ' - 62: 0, # 'ฝ' - 31: 3, # 'พ' - 54: 0, # 'ฟ' - 45: 1, # 'ภ' - 9: 2, # 'ม' - 16: 1, # 'ย' - 2: 2, # 'ร' - 61: 2, # 'ฤ' - 15: 2, # 'ล' - 12: 2, # 'ว' - 42: 1, # 'ศ' - 46: 1, # 'ษ' - 18: 3, # 'ส' - 21: 3, # 'ห' - 4: 3, # 'อ' - 63: 0, # 'ฯ' - 22: 1, # 'ะ' - 10: 3, # 'ั' - 1: 3, # 'า' - 36: 0, # 'ำ' - 23: 3, # 'ิ' - 13: 3, # 'ี' - 40: 0, # 'ึ' - 27: 3, # 'ื' - 32: 3, # 'ุ' - 35: 3, # 'ู' - 11: 2, # 'เ' - 28: 2, # 'แ' - 41: 2, # 'โ' - 29: 2, # 'ใ' - 33: 2, # 'ไ' - 50: 1, # 'ๆ' - 37: 1, # '็' - 6: 3, # '่' - 7: 2, # '้' - 38: 1, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 16: { # 'ย' - 5: 3, # 'ก' - 30: 1, # 'ข' - 24: 2, # 'ค' - 8: 3, # 'ง' - 26: 2, # 'จ' - 52: 0, # 'ฉ' - 34: 2, # 'ช' - 51: 0, # 'ซ' - 47: 2, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 2, # 'ด' - 19: 2, # 'ต' - 44: 1, # 'ถ' - 14: 2, # 'ท' - 48: 1, # 'ธ' - 3: 3, # 'น' - 17: 3, # 'บ' - 25: 1, # 'ป' - 39: 1, # 'ผ' - 62: 0, # 'ฝ' - 31: 1, # 'พ' - 54: 0, # 'ฟ' - 45: 1, # 'ภ' - 9: 2, # 'ม' - 16: 0, # 'ย' - 2: 2, # 'ร' - 61: 0, # 'ฤ' - 15: 1, # 'ล' - 12: 3, # 'ว' - 42: 1, # 'ศ' - 46: 0, # 'ษ' - 18: 2, # 'ส' - 21: 1, # 'ห' - 4: 2, # 'อ' - 63: 0, # 'ฯ' - 22: 2, # 'ะ' - 10: 3, # 'ั' - 1: 3, # 'า' - 36: 0, # 'ำ' - 23: 2, # 'ิ' - 13: 3, # 'ี' - 40: 1, # 'ึ' - 27: 2, # 'ื' - 32: 2, # 'ุ' - 35: 3, # 'ู' - 11: 2, # 'เ' - 28: 1, # 'แ' - 41: 1, # 'โ' - 29: 2, # 'ใ' - 33: 2, # 'ไ' - 50: 2, # 'ๆ' - 37: 1, # '็' - 6: 3, # '่' - 7: 2, # '้' - 38: 3, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 2: { # 'ร' - 5: 3, # 'ก' - 30: 2, # 'ข' - 24: 2, # 'ค' - 8: 3, # 'ง' - 26: 2, # 'จ' - 52: 0, # 'ฉ' - 34: 2, # 'ช' - 51: 1, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 3, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 3, # 'ณ' - 20: 2, # 'ด' - 19: 2, # 'ต' - 44: 3, # 'ถ' - 14: 3, # 'ท' - 48: 1, # 'ธ' - 3: 2, # 'น' - 17: 2, # 'บ' - 25: 3, # 'ป' - 39: 2, # 'ผ' - 62: 1, # 'ฝ' - 31: 2, # 'พ' - 54: 1, # 'ฟ' - 45: 1, # 'ภ' - 9: 3, # 'ม' - 16: 2, # 'ย' - 2: 3, # 'ร' - 61: 0, # 'ฤ' - 15: 2, # 'ล' - 12: 3, # 'ว' - 42: 2, # 'ศ' - 46: 2, # 'ษ' - 18: 2, # 'ส' - 21: 2, # 'ห' - 4: 3, # 'อ' - 63: 1, # 'ฯ' - 22: 3, # 'ะ' - 10: 3, # 'ั' - 1: 3, # 'า' - 36: 0, # 'ำ' - 23: 3, # 'ิ' - 13: 3, # 'ี' - 40: 2, # 'ึ' - 27: 3, # 'ื' - 32: 3, # 'ุ' - 35: 3, # 'ู' - 11: 3, # 'เ' - 28: 3, # 'แ' - 41: 1, # 'โ' - 29: 2, # 'ใ' - 33: 1, # 'ไ' - 50: 0, # 'ๆ' - 37: 3, # '็' - 6: 3, # '่' - 7: 3, # '้' - 38: 3, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 61: { # 'ฤ' - 5: 0, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 2, # 'ต' - 44: 0, # 'ถ' - 14: 2, # 'ท' - 48: 0, # 'ธ' - 3: 0, # 'น' - 17: 0, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 1, # 'ม' - 16: 0, # 'ย' - 2: 0, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 0, # 'ว' - 42: 0, # 'ศ' - 46: 2, # 'ษ' - 18: 0, # 'ส' - 21: 0, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 15: { # 'ล' - 5: 2, # 'ก' - 30: 3, # 'ข' - 24: 1, # 'ค' - 8: 3, # 'ง' - 26: 1, # 'จ' - 52: 0, # 'ฉ' - 34: 1, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 2, # 'ด' - 19: 2, # 'ต' - 44: 1, # 'ถ' - 14: 2, # 'ท' - 48: 0, # 'ธ' - 3: 1, # 'น' - 17: 2, # 'บ' - 25: 2, # 'ป' - 39: 1, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 1, # 'ภ' - 9: 1, # 'ม' - 16: 3, # 'ย' - 2: 1, # 'ร' - 61: 0, # 'ฤ' - 15: 1, # 'ล' - 12: 1, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 2, # 'ส' - 21: 1, # 'ห' - 4: 3, # 'อ' - 63: 2, # 'ฯ' - 22: 3, # 'ะ' - 10: 3, # 'ั' - 1: 3, # 'า' - 36: 2, # 'ำ' - 23: 3, # 'ิ' - 13: 3, # 'ี' - 40: 2, # 'ึ' - 27: 3, # 'ื' - 32: 2, # 'ุ' - 35: 3, # 'ู' - 11: 2, # 'เ' - 28: 1, # 'แ' - 41: 1, # 'โ' - 29: 2, # 'ใ' - 33: 1, # 'ไ' - 50: 0, # 'ๆ' - 37: 2, # '็' - 6: 3, # '่' - 7: 3, # '้' - 38: 2, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 12: { # 'ว' - 5: 3, # 'ก' - 30: 2, # 'ข' - 24: 1, # 'ค' - 8: 3, # 'ง' - 26: 2, # 'จ' - 52: 0, # 'ฉ' - 34: 1, # 'ช' - 51: 1, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 1, # 'ณ' - 20: 2, # 'ด' - 19: 1, # 'ต' - 44: 1, # 'ถ' - 14: 1, # 'ท' - 48: 0, # 'ธ' - 3: 3, # 'น' - 17: 2, # 'บ' - 25: 1, # 'ป' - 39: 1, # 'ผ' - 62: 0, # 'ฝ' - 31: 1, # 'พ' - 54: 1, # 'ฟ' - 45: 0, # 'ภ' - 9: 3, # 'ม' - 16: 3, # 'ย' - 2: 3, # 'ร' - 61: 0, # 'ฤ' - 15: 3, # 'ล' - 12: 1, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 2, # 'ส' - 21: 2, # 'ห' - 4: 2, # 'อ' - 63: 0, # 'ฯ' - 22: 2, # 'ะ' - 10: 3, # 'ั' - 1: 3, # 'า' - 36: 0, # 'ำ' - 23: 3, # 'ิ' - 13: 2, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 2, # 'ุ' - 35: 0, # 'ู' - 11: 3, # 'เ' - 28: 2, # 'แ' - 41: 1, # 'โ' - 29: 1, # 'ใ' - 33: 2, # 'ไ' - 50: 1, # 'ๆ' - 37: 0, # '็' - 6: 3, # '่' - 7: 3, # '้' - 38: 1, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 42: { # 'ศ' - 5: 1, # 'ก' - 30: 0, # 'ข' - 24: 1, # 'ค' - 8: 0, # 'ง' - 26: 1, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 1, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 1, # 'ต' - 44: 0, # 'ถ' - 14: 1, # 'ท' - 48: 0, # 'ธ' - 3: 2, # 'น' - 17: 0, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 0, # 'ม' - 16: 0, # 'ย' - 2: 2, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 2, # 'ว' - 42: 1, # 'ศ' - 46: 2, # 'ษ' - 18: 1, # 'ส' - 21: 0, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 2, # 'ั' - 1: 3, # 'า' - 36: 0, # 'ำ' - 23: 2, # 'ิ' - 13: 0, # 'ี' - 40: 3, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 2, # 'ู' - 11: 0, # 'เ' - 28: 1, # 'แ' - 41: 0, # 'โ' - 29: 1, # 'ใ' - 33: 1, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 1, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 46: { # 'ษ' - 5: 0, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 2, # 'ฎ' - 57: 1, # 'ฏ' - 49: 2, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 3, # 'ณ' - 20: 0, # 'ด' - 19: 1, # 'ต' - 44: 0, # 'ถ' - 14: 1, # 'ท' - 48: 0, # 'ธ' - 3: 0, # 'น' - 17: 0, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 1, # 'ภ' - 9: 1, # 'ม' - 16: 2, # 'ย' - 2: 2, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 0, # 'ว' - 42: 1, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 0, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 2, # 'ะ' - 10: 2, # 'ั' - 1: 3, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 1, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 1, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 2, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 18: { # 'ส' - 5: 2, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 2, # 'ง' - 26: 1, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 3, # 'ด' - 19: 3, # 'ต' - 44: 3, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 3, # 'น' - 17: 2, # 'บ' - 25: 1, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 2, # 'ภ' - 9: 3, # 'ม' - 16: 1, # 'ย' - 2: 3, # 'ร' - 61: 0, # 'ฤ' - 15: 1, # 'ล' - 12: 2, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 2, # 'ห' - 4: 3, # 'อ' - 63: 0, # 'ฯ' - 22: 2, # 'ะ' - 10: 3, # 'ั' - 1: 3, # 'า' - 36: 3, # 'ำ' - 23: 3, # 'ิ' - 13: 3, # 'ี' - 40: 2, # 'ึ' - 27: 3, # 'ื' - 32: 3, # 'ุ' - 35: 3, # 'ู' - 11: 2, # 'เ' - 28: 0, # 'แ' - 41: 1, # 'โ' - 29: 0, # 'ใ' - 33: 1, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 3, # '่' - 7: 1, # '้' - 38: 2, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 21: { # 'ห' - 5: 3, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 1, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 2, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 1, # 'ด' - 19: 3, # 'ต' - 44: 0, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 3, # 'น' - 17: 0, # 'บ' - 25: 1, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 1, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 3, # 'ม' - 16: 2, # 'ย' - 2: 3, # 'ร' - 61: 0, # 'ฤ' - 15: 3, # 'ล' - 12: 2, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 0, # 'ห' - 4: 3, # 'อ' - 63: 0, # 'ฯ' - 22: 1, # 'ะ' - 10: 3, # 'ั' - 1: 3, # 'า' - 36: 0, # 'ำ' - 23: 1, # 'ิ' - 13: 1, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 1, # 'ุ' - 35: 1, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 3, # '็' - 6: 3, # '่' - 7: 3, # '้' - 38: 2, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 4: { # 'อ' - 5: 3, # 'ก' - 30: 1, # 'ข' - 24: 2, # 'ค' - 8: 3, # 'ง' - 26: 1, # 'จ' - 52: 0, # 'ฉ' - 34: 1, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 3, # 'ด' - 19: 2, # 'ต' - 44: 1, # 'ถ' - 14: 2, # 'ท' - 48: 1, # 'ธ' - 3: 3, # 'น' - 17: 3, # 'บ' - 25: 1, # 'ป' - 39: 1, # 'ผ' - 62: 0, # 'ฝ' - 31: 1, # 'พ' - 54: 1, # 'ฟ' - 45: 1, # 'ภ' - 9: 3, # 'ม' - 16: 3, # 'ย' - 2: 3, # 'ร' - 61: 0, # 'ฤ' - 15: 2, # 'ล' - 12: 2, # 'ว' - 42: 1, # 'ศ' - 46: 0, # 'ษ' - 18: 2, # 'ส' - 21: 2, # 'ห' - 4: 3, # 'อ' - 63: 0, # 'ฯ' - 22: 2, # 'ะ' - 10: 3, # 'ั' - 1: 3, # 'า' - 36: 2, # 'ำ' - 23: 2, # 'ิ' - 13: 3, # 'ี' - 40: 0, # 'ึ' - 27: 3, # 'ื' - 32: 3, # 'ุ' - 35: 0, # 'ู' - 11: 3, # 'เ' - 28: 1, # 'แ' - 41: 1, # 'โ' - 29: 2, # 'ใ' - 33: 2, # 'ไ' - 50: 1, # 'ๆ' - 37: 1, # '็' - 6: 2, # '่' - 7: 2, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 63: { # 'ฯ' - 5: 0, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 0, # 'น' - 17: 0, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 0, # 'ม' - 16: 0, # 'ย' - 2: 0, # 'ร' - 61: 0, # 'ฤ' - 15: 2, # 'ล' - 12: 0, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 0, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 22: { # 'ะ' - 5: 3, # 'ก' - 30: 1, # 'ข' - 24: 2, # 'ค' - 8: 1, # 'ง' - 26: 2, # 'จ' - 52: 0, # 'ฉ' - 34: 3, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 3, # 'ด' - 19: 3, # 'ต' - 44: 1, # 'ถ' - 14: 3, # 'ท' - 48: 1, # 'ธ' - 3: 2, # 'น' - 17: 3, # 'บ' - 25: 2, # 'ป' - 39: 1, # 'ผ' - 62: 0, # 'ฝ' - 31: 2, # 'พ' - 54: 0, # 'ฟ' - 45: 1, # 'ภ' - 9: 3, # 'ม' - 16: 2, # 'ย' - 2: 2, # 'ร' - 61: 0, # 'ฤ' - 15: 2, # 'ล' - 12: 2, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 3, # 'ส' - 21: 3, # 'ห' - 4: 2, # 'อ' - 63: 1, # 'ฯ' - 22: 1, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 3, # 'เ' - 28: 2, # 'แ' - 41: 1, # 'โ' - 29: 2, # 'ใ' - 33: 2, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 10: { # 'ั' - 5: 3, # 'ก' - 30: 0, # 'ข' - 24: 1, # 'ค' - 8: 3, # 'ง' - 26: 3, # 'จ' - 52: 0, # 'ฉ' - 34: 1, # 'ช' - 51: 0, # 'ซ' - 47: 3, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 2, # 'ฐ' - 53: 0, # 'ฑ' - 55: 3, # 'ฒ' - 43: 3, # 'ณ' - 20: 3, # 'ด' - 19: 3, # 'ต' - 44: 0, # 'ถ' - 14: 2, # 'ท' - 48: 0, # 'ธ' - 3: 3, # 'น' - 17: 3, # 'บ' - 25: 1, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 2, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 3, # 'ม' - 16: 3, # 'ย' - 2: 0, # 'ร' - 61: 0, # 'ฤ' - 15: 2, # 'ล' - 12: 3, # 'ว' - 42: 2, # 'ศ' - 46: 0, # 'ษ' - 18: 3, # 'ส' - 21: 0, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 3, # '่' - 7: 3, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 1: { # 'า' - 5: 3, # 'ก' - 30: 2, # 'ข' - 24: 3, # 'ค' - 8: 3, # 'ง' - 26: 3, # 'จ' - 52: 0, # 'ฉ' - 34: 3, # 'ช' - 51: 1, # 'ซ' - 47: 2, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 3, # 'ณ' - 20: 3, # 'ด' - 19: 3, # 'ต' - 44: 1, # 'ถ' - 14: 3, # 'ท' - 48: 2, # 'ธ' - 3: 3, # 'น' - 17: 3, # 'บ' - 25: 2, # 'ป' - 39: 1, # 'ผ' - 62: 1, # 'ฝ' - 31: 3, # 'พ' - 54: 1, # 'ฟ' - 45: 1, # 'ภ' - 9: 3, # 'ม' - 16: 3, # 'ย' - 2: 3, # 'ร' - 61: 0, # 'ฤ' - 15: 3, # 'ล' - 12: 3, # 'ว' - 42: 2, # 'ศ' - 46: 3, # 'ษ' - 18: 3, # 'ส' - 21: 3, # 'ห' - 4: 2, # 'อ' - 63: 1, # 'ฯ' - 22: 3, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 3, # 'เ' - 28: 2, # 'แ' - 41: 1, # 'โ' - 29: 2, # 'ใ' - 33: 2, # 'ไ' - 50: 1, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 36: { # 'ำ' - 5: 2, # 'ก' - 30: 1, # 'ข' - 24: 3, # 'ค' - 8: 2, # 'ง' - 26: 1, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 1, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 1, # 'ด' - 19: 1, # 'ต' - 44: 1, # 'ถ' - 14: 1, # 'ท' - 48: 0, # 'ธ' - 3: 3, # 'น' - 17: 1, # 'บ' - 25: 1, # 'ป' - 39: 1, # 'ผ' - 62: 0, # 'ฝ' - 31: 1, # 'พ' - 54: 0, # 'ฟ' - 45: 1, # 'ภ' - 9: 1, # 'ม' - 16: 0, # 'ย' - 2: 2, # 'ร' - 61: 0, # 'ฤ' - 15: 2, # 'ล' - 12: 1, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 1, # 'ส' - 21: 3, # 'ห' - 4: 1, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 3, # 'เ' - 28: 2, # 'แ' - 41: 1, # 'โ' - 29: 2, # 'ใ' - 33: 2, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 23: { # 'ิ' - 5: 3, # 'ก' - 30: 1, # 'ข' - 24: 2, # 'ค' - 8: 3, # 'ง' - 26: 3, # 'จ' - 52: 0, # 'ฉ' - 34: 3, # 'ช' - 51: 0, # 'ซ' - 47: 2, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 3, # 'ด' - 19: 3, # 'ต' - 44: 1, # 'ถ' - 14: 3, # 'ท' - 48: 3, # 'ธ' - 3: 3, # 'น' - 17: 3, # 'บ' - 25: 2, # 'ป' - 39: 2, # 'ผ' - 62: 0, # 'ฝ' - 31: 3, # 'พ' - 54: 1, # 'ฟ' - 45: 2, # 'ภ' - 9: 3, # 'ม' - 16: 2, # 'ย' - 2: 2, # 'ร' - 61: 0, # 'ฤ' - 15: 2, # 'ล' - 12: 3, # 'ว' - 42: 3, # 'ศ' - 46: 2, # 'ษ' - 18: 2, # 'ส' - 21: 3, # 'ห' - 4: 1, # 'อ' - 63: 1, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 3, # 'เ' - 28: 1, # 'แ' - 41: 1, # 'โ' - 29: 1, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 3, # '่' - 7: 2, # '้' - 38: 2, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 13: { # 'ี' - 5: 3, # 'ก' - 30: 2, # 'ข' - 24: 2, # 'ค' - 8: 0, # 'ง' - 26: 1, # 'จ' - 52: 0, # 'ฉ' - 34: 1, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 2, # 'ด' - 19: 1, # 'ต' - 44: 0, # 'ถ' - 14: 2, # 'ท' - 48: 0, # 'ธ' - 3: 1, # 'น' - 17: 2, # 'บ' - 25: 2, # 'ป' - 39: 1, # 'ผ' - 62: 0, # 'ฝ' - 31: 2, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 2, # 'ม' - 16: 3, # 'ย' - 2: 2, # 'ร' - 61: 0, # 'ฤ' - 15: 1, # 'ล' - 12: 2, # 'ว' - 42: 1, # 'ศ' - 46: 0, # 'ษ' - 18: 2, # 'ส' - 21: 1, # 'ห' - 4: 2, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 2, # 'เ' - 28: 2, # 'แ' - 41: 1, # 'โ' - 29: 1, # 'ใ' - 33: 1, # 'ไ' - 50: 1, # 'ๆ' - 37: 0, # '็' - 6: 3, # '่' - 7: 3, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 40: { # 'ึ' - 5: 3, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 3, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 1, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 0, # 'น' - 17: 0, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 1, # 'ม' - 16: 0, # 'ย' - 2: 0, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 0, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 0, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 3, # '่' - 7: 3, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 27: { # 'ื' - 5: 0, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 1, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 1, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 2, # 'น' - 17: 3, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 2, # 'ม' - 16: 0, # 'ย' - 2: 0, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 0, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 0, # 'ห' - 4: 3, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 3, # '่' - 7: 3, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 32: { # 'ุ' - 5: 3, # 'ก' - 30: 2, # 'ข' - 24: 3, # 'ค' - 8: 3, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 2, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 1, # 'ฒ' - 43: 3, # 'ณ' - 20: 3, # 'ด' - 19: 3, # 'ต' - 44: 1, # 'ถ' - 14: 2, # 'ท' - 48: 1, # 'ธ' - 3: 2, # 'น' - 17: 2, # 'บ' - 25: 2, # 'ป' - 39: 2, # 'ผ' - 62: 0, # 'ฝ' - 31: 1, # 'พ' - 54: 0, # 'ฟ' - 45: 1, # 'ภ' - 9: 3, # 'ม' - 16: 1, # 'ย' - 2: 2, # 'ร' - 61: 0, # 'ฤ' - 15: 2, # 'ล' - 12: 1, # 'ว' - 42: 1, # 'ศ' - 46: 2, # 'ษ' - 18: 1, # 'ส' - 21: 1, # 'ห' - 4: 1, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 1, # 'เ' - 28: 0, # 'แ' - 41: 1, # 'โ' - 29: 0, # 'ใ' - 33: 1, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 3, # '่' - 7: 2, # '้' - 38: 1, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 35: { # 'ู' - 5: 3, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 2, # 'ง' - 26: 1, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 2, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 1, # 'ณ' - 20: 2, # 'ด' - 19: 2, # 'ต' - 44: 0, # 'ถ' - 14: 1, # 'ท' - 48: 0, # 'ธ' - 3: 2, # 'น' - 17: 0, # 'บ' - 25: 3, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 2, # 'ม' - 16: 0, # 'ย' - 2: 1, # 'ร' - 61: 0, # 'ฤ' - 15: 3, # 'ล' - 12: 1, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 0, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 1, # 'เ' - 28: 1, # 'แ' - 41: 1, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 3, # '่' - 7: 3, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 11: { # 'เ' - 5: 3, # 'ก' - 30: 3, # 'ข' - 24: 3, # 'ค' - 8: 2, # 'ง' - 26: 3, # 'จ' - 52: 3, # 'ฉ' - 34: 3, # 'ช' - 51: 2, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 1, # 'ณ' - 20: 3, # 'ด' - 19: 3, # 'ต' - 44: 1, # 'ถ' - 14: 3, # 'ท' - 48: 1, # 'ธ' - 3: 3, # 'น' - 17: 3, # 'บ' - 25: 3, # 'ป' - 39: 2, # 'ผ' - 62: 1, # 'ฝ' - 31: 3, # 'พ' - 54: 1, # 'ฟ' - 45: 3, # 'ภ' - 9: 3, # 'ม' - 16: 2, # 'ย' - 2: 3, # 'ร' - 61: 0, # 'ฤ' - 15: 3, # 'ล' - 12: 3, # 'ว' - 42: 2, # 'ศ' - 46: 0, # 'ษ' - 18: 3, # 'ส' - 21: 3, # 'ห' - 4: 3, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 28: { # 'แ' - 5: 3, # 'ก' - 30: 2, # 'ข' - 24: 2, # 'ค' - 8: 1, # 'ง' - 26: 2, # 'จ' - 52: 0, # 'ฉ' - 34: 1, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 2, # 'ด' - 19: 3, # 'ต' - 44: 2, # 'ถ' - 14: 3, # 'ท' - 48: 0, # 'ธ' - 3: 3, # 'น' - 17: 3, # 'บ' - 25: 2, # 'ป' - 39: 3, # 'ผ' - 62: 0, # 'ฝ' - 31: 2, # 'พ' - 54: 2, # 'ฟ' - 45: 0, # 'ภ' - 9: 2, # 'ม' - 16: 2, # 'ย' - 2: 2, # 'ร' - 61: 0, # 'ฤ' - 15: 3, # 'ล' - 12: 2, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 3, # 'ส' - 21: 3, # 'ห' - 4: 1, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 41: { # 'โ' - 5: 2, # 'ก' - 30: 1, # 'ข' - 24: 2, # 'ค' - 8: 0, # 'ง' - 26: 1, # 'จ' - 52: 1, # 'ฉ' - 34: 1, # 'ช' - 51: 1, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 3, # 'ด' - 19: 2, # 'ต' - 44: 0, # 'ถ' - 14: 2, # 'ท' - 48: 0, # 'ธ' - 3: 3, # 'น' - 17: 1, # 'บ' - 25: 3, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 1, # 'พ' - 54: 1, # 'ฟ' - 45: 1, # 'ภ' - 9: 1, # 'ม' - 16: 2, # 'ย' - 2: 2, # 'ร' - 61: 0, # 'ฤ' - 15: 3, # 'ล' - 12: 0, # 'ว' - 42: 1, # 'ศ' - 46: 0, # 'ษ' - 18: 2, # 'ส' - 21: 0, # 'ห' - 4: 2, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 29: { # 'ใ' - 5: 2, # 'ก' - 30: 0, # 'ข' - 24: 1, # 'ค' - 8: 0, # 'ง' - 26: 3, # 'จ' - 52: 0, # 'ฉ' - 34: 3, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 3, # 'ด' - 19: 1, # 'ต' - 44: 0, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 3, # 'น' - 17: 2, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 0, # 'ม' - 16: 1, # 'ย' - 2: 0, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 0, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 3, # 'ส' - 21: 3, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 33: { # 'ไ' - 5: 1, # 'ก' - 30: 2, # 'ข' - 24: 0, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 1, # 'ช' - 51: 1, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 3, # 'ด' - 19: 1, # 'ต' - 44: 0, # 'ถ' - 14: 3, # 'ท' - 48: 0, # 'ธ' - 3: 0, # 'น' - 17: 1, # 'บ' - 25: 3, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 2, # 'ฟ' - 45: 0, # 'ภ' - 9: 3, # 'ม' - 16: 0, # 'ย' - 2: 3, # 'ร' - 61: 0, # 'ฤ' - 15: 1, # 'ล' - 12: 3, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 1, # 'ส' - 21: 2, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 50: { # 'ๆ' - 5: 0, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 0, # 'น' - 17: 0, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 0, # 'ม' - 16: 0, # 'ย' - 2: 0, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 0, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 0, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 37: { # '็' - 5: 2, # 'ก' - 30: 1, # 'ข' - 24: 2, # 'ค' - 8: 2, # 'ง' - 26: 3, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 1, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 1, # 'ด' - 19: 2, # 'ต' - 44: 0, # 'ถ' - 14: 1, # 'ท' - 48: 0, # 'ธ' - 3: 3, # 'น' - 17: 3, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 2, # 'ม' - 16: 1, # 'ย' - 2: 0, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 2, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 1, # 'ส' - 21: 0, # 'ห' - 4: 1, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 1, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 1, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 6: { # '่' - 5: 2, # 'ก' - 30: 1, # 'ข' - 24: 2, # 'ค' - 8: 3, # 'ง' - 26: 2, # 'จ' - 52: 0, # 'ฉ' - 34: 1, # 'ช' - 51: 1, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 1, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 1, # 'ด' - 19: 2, # 'ต' - 44: 1, # 'ถ' - 14: 2, # 'ท' - 48: 1, # 'ธ' - 3: 3, # 'น' - 17: 1, # 'บ' - 25: 2, # 'ป' - 39: 2, # 'ผ' - 62: 1, # 'ฝ' - 31: 1, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 3, # 'ม' - 16: 3, # 'ย' - 2: 2, # 'ร' - 61: 0, # 'ฤ' - 15: 2, # 'ล' - 12: 3, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 2, # 'ส' - 21: 1, # 'ห' - 4: 3, # 'อ' - 63: 0, # 'ฯ' - 22: 1, # 'ะ' - 10: 0, # 'ั' - 1: 3, # 'า' - 36: 2, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 3, # 'เ' - 28: 2, # 'แ' - 41: 1, # 'โ' - 29: 2, # 'ใ' - 33: 2, # 'ไ' - 50: 1, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 7: { # '้' - 5: 2, # 'ก' - 30: 1, # 'ข' - 24: 2, # 'ค' - 8: 3, # 'ง' - 26: 2, # 'จ' - 52: 0, # 'ฉ' - 34: 1, # 'ช' - 51: 1, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 1, # 'ด' - 19: 2, # 'ต' - 44: 1, # 'ถ' - 14: 2, # 'ท' - 48: 0, # 'ธ' - 3: 3, # 'น' - 17: 2, # 'บ' - 25: 2, # 'ป' - 39: 2, # 'ผ' - 62: 0, # 'ฝ' - 31: 1, # 'พ' - 54: 1, # 'ฟ' - 45: 0, # 'ภ' - 9: 3, # 'ม' - 16: 2, # 'ย' - 2: 2, # 'ร' - 61: 0, # 'ฤ' - 15: 1, # 'ล' - 12: 3, # 'ว' - 42: 1, # 'ศ' - 46: 0, # 'ษ' - 18: 2, # 'ส' - 21: 2, # 'ห' - 4: 3, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 3, # 'า' - 36: 2, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 2, # 'เ' - 28: 2, # 'แ' - 41: 1, # 'โ' - 29: 2, # 'ใ' - 33: 2, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 38: { # '์' - 5: 2, # 'ก' - 30: 1, # 'ข' - 24: 1, # 'ค' - 8: 0, # 'ง' - 26: 1, # 'จ' - 52: 0, # 'ฉ' - 34: 1, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 2, # 'ด' - 19: 1, # 'ต' - 44: 1, # 'ถ' - 14: 1, # 'ท' - 48: 0, # 'ธ' - 3: 1, # 'น' - 17: 1, # 'บ' - 25: 1, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 1, # 'พ' - 54: 1, # 'ฟ' - 45: 0, # 'ภ' - 9: 2, # 'ม' - 16: 0, # 'ย' - 2: 1, # 'ร' - 61: 1, # 'ฤ' - 15: 1, # 'ล' - 12: 1, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 1, # 'ส' - 21: 1, # 'ห' - 4: 2, # 'อ' - 63: 1, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 2, # 'เ' - 28: 2, # 'แ' - 41: 1, # 'โ' - 29: 1, # 'ใ' - 33: 1, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 0, # '๑' - 59: 0, # '๒' - 60: 0, # '๕' - }, - 56: { # '๑' - 5: 0, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 0, # 'น' - 17: 0, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 0, # 'ม' - 16: 0, # 'ย' - 2: 0, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 0, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 0, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 2, # '๑' - 59: 1, # '๒' - 60: 1, # '๕' - }, - 59: { # '๒' - 5: 0, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 0, # 'น' - 17: 0, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 0, # 'ม' - 16: 0, # 'ย' - 2: 0, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 0, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 0, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 1, # '๑' - 59: 1, # '๒' - 60: 3, # '๕' - }, - 60: { # '๕' - 5: 0, # 'ก' - 30: 0, # 'ข' - 24: 0, # 'ค' - 8: 0, # 'ง' - 26: 0, # 'จ' - 52: 0, # 'ฉ' - 34: 0, # 'ช' - 51: 0, # 'ซ' - 47: 0, # 'ญ' - 58: 0, # 'ฎ' - 57: 0, # 'ฏ' - 49: 0, # 'ฐ' - 53: 0, # 'ฑ' - 55: 0, # 'ฒ' - 43: 0, # 'ณ' - 20: 0, # 'ด' - 19: 0, # 'ต' - 44: 0, # 'ถ' - 14: 0, # 'ท' - 48: 0, # 'ธ' - 3: 0, # 'น' - 17: 0, # 'บ' - 25: 0, # 'ป' - 39: 0, # 'ผ' - 62: 0, # 'ฝ' - 31: 0, # 'พ' - 54: 0, # 'ฟ' - 45: 0, # 'ภ' - 9: 0, # 'ม' - 16: 0, # 'ย' - 2: 0, # 'ร' - 61: 0, # 'ฤ' - 15: 0, # 'ล' - 12: 0, # 'ว' - 42: 0, # 'ศ' - 46: 0, # 'ษ' - 18: 0, # 'ส' - 21: 0, # 'ห' - 4: 0, # 'อ' - 63: 0, # 'ฯ' - 22: 0, # 'ะ' - 10: 0, # 'ั' - 1: 0, # 'า' - 36: 0, # 'ำ' - 23: 0, # 'ิ' - 13: 0, # 'ี' - 40: 0, # 'ึ' - 27: 0, # 'ื' - 32: 0, # 'ุ' - 35: 0, # 'ู' - 11: 0, # 'เ' - 28: 0, # 'แ' - 41: 0, # 'โ' - 29: 0, # 'ใ' - 33: 0, # 'ไ' - 50: 0, # 'ๆ' - 37: 0, # '็' - 6: 0, # '่' - 7: 0, # '้' - 38: 0, # '์' - 56: 2, # '๑' - 59: 1, # '๒' - 60: 0, # '๕' - }, -} - -# 255: Undefined characters that did not exist in training text -# 254: Carriage/Return -# 253: symbol (punctuation) that does not belong to word -# 252: 0 - 9 -# 251: Control characters - -# Character Mapping Table(s): -TIS_620_THAI_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 254, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 254, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 253, # ' ' - 33: 253, # '!' - 34: 253, # '"' - 35: 253, # '#' - 36: 253, # '$' - 37: 253, # '%' - 38: 253, # '&' - 39: 253, # "'" - 40: 253, # '(' - 41: 253, # ')' - 42: 253, # '*' - 43: 253, # '+' - 44: 253, # ',' - 45: 253, # '-' - 46: 253, # '.' - 47: 253, # '/' - 48: 252, # '0' - 49: 252, # '1' - 50: 252, # '2' - 51: 252, # '3' - 52: 252, # '4' - 53: 252, # '5' - 54: 252, # '6' - 55: 252, # '7' - 56: 252, # '8' - 57: 252, # '9' - 58: 253, # ':' - 59: 253, # ';' - 60: 253, # '<' - 61: 253, # '=' - 62: 253, # '>' - 63: 253, # '?' - 64: 253, # '@' - 65: 182, # 'A' - 66: 106, # 'B' - 67: 107, # 'C' - 68: 100, # 'D' - 69: 183, # 'E' - 70: 184, # 'F' - 71: 185, # 'G' - 72: 101, # 'H' - 73: 94, # 'I' - 74: 186, # 'J' - 75: 187, # 'K' - 76: 108, # 'L' - 77: 109, # 'M' - 78: 110, # 'N' - 79: 111, # 'O' - 80: 188, # 'P' - 81: 189, # 'Q' - 82: 190, # 'R' - 83: 89, # 'S' - 84: 95, # 'T' - 85: 112, # 'U' - 86: 113, # 'V' - 87: 191, # 'W' - 88: 192, # 'X' - 89: 193, # 'Y' - 90: 194, # 'Z' - 91: 253, # '[' - 92: 253, # '\\' - 93: 253, # ']' - 94: 253, # '^' - 95: 253, # '_' - 96: 253, # '`' - 97: 64, # 'a' - 98: 72, # 'b' - 99: 73, # 'c' - 100: 114, # 'd' - 101: 74, # 'e' - 102: 115, # 'f' - 103: 116, # 'g' - 104: 102, # 'h' - 105: 81, # 'i' - 106: 201, # 'j' - 107: 117, # 'k' - 108: 90, # 'l' - 109: 103, # 'm' - 110: 78, # 'n' - 111: 82, # 'o' - 112: 96, # 'p' - 113: 202, # 'q' - 114: 91, # 'r' - 115: 79, # 's' - 116: 84, # 't' - 117: 104, # 'u' - 118: 105, # 'v' - 119: 97, # 'w' - 120: 98, # 'x' - 121: 92, # 'y' - 122: 203, # 'z' - 123: 253, # '{' - 124: 253, # '|' - 125: 253, # '}' - 126: 253, # '~' - 127: 253, # '\x7f' - 128: 209, # '\x80' - 129: 210, # '\x81' - 130: 211, # '\x82' - 131: 212, # '\x83' - 132: 213, # '\x84' - 133: 88, # '\x85' - 134: 214, # '\x86' - 135: 215, # '\x87' - 136: 216, # '\x88' - 137: 217, # '\x89' - 138: 218, # '\x8a' - 139: 219, # '\x8b' - 140: 220, # '\x8c' - 141: 118, # '\x8d' - 142: 221, # '\x8e' - 143: 222, # '\x8f' - 144: 223, # '\x90' - 145: 224, # '\x91' - 146: 99, # '\x92' - 147: 85, # '\x93' - 148: 83, # '\x94' - 149: 225, # '\x95' - 150: 226, # '\x96' - 151: 227, # '\x97' - 152: 228, # '\x98' - 153: 229, # '\x99' - 154: 230, # '\x9a' - 155: 231, # '\x9b' - 156: 232, # '\x9c' - 157: 233, # '\x9d' - 158: 234, # '\x9e' - 159: 235, # '\x9f' - 160: 236, # None - 161: 5, # 'ก' - 162: 30, # 'ข' - 163: 237, # 'ฃ' - 164: 24, # 'ค' - 165: 238, # 'ฅ' - 166: 75, # 'ฆ' - 167: 8, # 'ง' - 168: 26, # 'จ' - 169: 52, # 'ฉ' - 170: 34, # 'ช' - 171: 51, # 'ซ' - 172: 119, # 'ฌ' - 173: 47, # 'ญ' - 174: 58, # 'ฎ' - 175: 57, # 'ฏ' - 176: 49, # 'ฐ' - 177: 53, # 'ฑ' - 178: 55, # 'ฒ' - 179: 43, # 'ณ' - 180: 20, # 'ด' - 181: 19, # 'ต' - 182: 44, # 'ถ' - 183: 14, # 'ท' - 184: 48, # 'ธ' - 185: 3, # 'น' - 186: 17, # 'บ' - 187: 25, # 'ป' - 188: 39, # 'ผ' - 189: 62, # 'ฝ' - 190: 31, # 'พ' - 191: 54, # 'ฟ' - 192: 45, # 'ภ' - 193: 9, # 'ม' - 194: 16, # 'ย' - 195: 2, # 'ร' - 196: 61, # 'ฤ' - 197: 15, # 'ล' - 198: 239, # 'ฦ' - 199: 12, # 'ว' - 200: 42, # 'ศ' - 201: 46, # 'ษ' - 202: 18, # 'ส' - 203: 21, # 'ห' - 204: 76, # 'ฬ' - 205: 4, # 'อ' - 206: 66, # 'ฮ' - 207: 63, # 'ฯ' - 208: 22, # 'ะ' - 209: 10, # 'ั' - 210: 1, # 'า' - 211: 36, # 'ำ' - 212: 23, # 'ิ' - 213: 13, # 'ี' - 214: 40, # 'ึ' - 215: 27, # 'ื' - 216: 32, # 'ุ' - 217: 35, # 'ู' - 218: 86, # 'ฺ' - 219: 240, # None - 220: 241, # None - 221: 242, # None - 222: 243, # None - 223: 244, # '฿' - 224: 11, # 'เ' - 225: 28, # 'แ' - 226: 41, # 'โ' - 227: 29, # 'ใ' - 228: 33, # 'ไ' - 229: 245, # 'ๅ' - 230: 50, # 'ๆ' - 231: 37, # '็' - 232: 6, # '่' - 233: 7, # '้' - 234: 67, # '๊' - 235: 77, # '๋' - 236: 38, # '์' - 237: 93, # 'ํ' - 238: 246, # '๎' - 239: 247, # '๏' - 240: 68, # '๐' - 241: 56, # '๑' - 242: 59, # '๒' - 243: 65, # '๓' - 244: 69, # '๔' - 245: 60, # '๕' - 246: 70, # '๖' - 247: 80, # '๗' - 248: 71, # '๘' - 249: 87, # '๙' - 250: 248, # '๚' - 251: 249, # '๛' - 252: 250, # None - 253: 251, # None - 254: 252, # None - 255: 253, # None -} - -TIS_620_THAI_MODEL = SingleByteCharSetModel(charset_name='TIS-620', - language='Thai', - char_to_order_map=TIS_620_THAI_CHAR_TO_ORDER, - language_model=THAI_LANG_MODEL, - typical_positive_ratio=0.926386, - keep_ascii_letters=False, - alphabet='กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛') - diff --git a/venv/lib/python3.8/site-packages/chardet/langturkishmodel.py b/venv/lib/python3.8/site-packages/chardet/langturkishmodel.py deleted file mode 100644 index 8ba9322..0000000 --- a/venv/lib/python3.8/site-packages/chardet/langturkishmodel.py +++ /dev/null @@ -1,4383 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -from chardet.sbcharsetprober import SingleByteCharSetModel - - -# 3: Positive -# 2: Likely -# 1: Unlikely -# 0: Negative - -TURKISH_LANG_MODEL = { - 23: { # 'A' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 0, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 0, # 'b' - 28: 0, # 'c' - 12: 2, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 1, # 'g' - 25: 1, # 'h' - 3: 1, # 'i' - 24: 0, # 'j' - 10: 2, # 'k' - 5: 1, # 'l' - 13: 1, # 'm' - 4: 1, # 'n' - 15: 0, # 'o' - 26: 0, # 'p' - 7: 1, # 'r' - 8: 1, # 's' - 9: 1, # 't' - 14: 1, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 3, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 1, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 0, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 0, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 37: { # 'B' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 2, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 2, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 1, # 'K' - 49: 0, # 'L' - 20: 0, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 1, # 'P' - 44: 0, # 'R' - 35: 1, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 1, # 'V' - 62: 0, # 'W' - 43: 1, # 'Y' - 56: 0, # 'Z' - 1: 2, # 'a' - 21: 0, # 'b' - 28: 2, # 'c' - 12: 0, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 0, # 'i' - 24: 0, # 'j' - 10: 0, # 'k' - 5: 0, # 'l' - 13: 1, # 'm' - 4: 1, # 'n' - 15: 0, # 'o' - 26: 0, # 'p' - 7: 0, # 'r' - 8: 0, # 's' - 9: 0, # 't' - 14: 2, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 1, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 1, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 1, # 'ö' - 17: 0, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 0, # 'ı' - 40: 1, # 'Ş' - 19: 1, # 'ş' - }, - 47: { # 'C' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 1, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 1, # 'L' - 20: 0, # 'M' - 46: 1, # 'N' - 42: 0, # 'O' - 48: 1, # 'P' - 44: 1, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 1, # 'V' - 62: 0, # 'W' - 43: 1, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 0, # 'b' - 28: 2, # 'c' - 12: 0, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 0, # 'i' - 24: 2, # 'j' - 10: 1, # 'k' - 5: 2, # 'l' - 13: 2, # 'm' - 4: 2, # 'n' - 15: 1, # 'o' - 26: 0, # 'p' - 7: 2, # 'r' - 8: 0, # 's' - 9: 0, # 't' - 14: 3, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 2, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 1, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 1, # 'ç' - 61: 0, # 'î' - 34: 1, # 'ö' - 17: 0, # 'ü' - 30: 0, # 'ğ' - 41: 1, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 39: { # 'D' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 1, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 1, # 'K' - 49: 0, # 'L' - 20: 0, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 1, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 2, # 'a' - 21: 0, # 'b' - 28: 2, # 'c' - 12: 0, # 'd' - 2: 2, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 0, # 'i' - 24: 0, # 'j' - 10: 0, # 'k' - 5: 1, # 'l' - 13: 3, # 'm' - 4: 0, # 'n' - 15: 1, # 'o' - 26: 0, # 'p' - 7: 0, # 'r' - 8: 0, # 's' - 9: 0, # 't' - 14: 1, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 1, # 'z' - 63: 0, # '·' - 54: 1, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 1, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 0, # 'ü' - 30: 1, # 'ğ' - 41: 0, # 'İ' - 6: 1, # 'ı' - 40: 1, # 'Ş' - 19: 0, # 'ş' - }, - 29: { # 'E' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 1, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 3, # 'K' - 49: 0, # 'L' - 20: 1, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 0, # 'b' - 28: 0, # 'c' - 12: 2, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 1, # 'g' - 25: 0, # 'h' - 3: 1, # 'i' - 24: 1, # 'j' - 10: 0, # 'k' - 5: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 15: 0, # 'o' - 26: 0, # 'p' - 7: 0, # 'r' - 8: 1, # 's' - 9: 1, # 't' - 14: 1, # 'u' - 32: 1, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 2, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 0, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 52: { # 'F' - 23: 0, # 'A' - 37: 1, # 'B' - 47: 1, # 'C' - 39: 1, # 'D' - 29: 1, # 'E' - 52: 2, # 'F' - 36: 0, # 'G' - 45: 2, # 'H' - 53: 1, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 1, # 'M' - 46: 1, # 'N' - 42: 1, # 'O' - 48: 2, # 'P' - 44: 1, # 'R' - 35: 1, # 'S' - 31: 1, # 'T' - 51: 1, # 'U' - 38: 1, # 'V' - 62: 0, # 'W' - 43: 2, # 'Y' - 56: 0, # 'Z' - 1: 0, # 'a' - 21: 1, # 'b' - 28: 1, # 'c' - 12: 1, # 'd' - 2: 0, # 'e' - 18: 1, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 2, # 'i' - 24: 1, # 'j' - 10: 0, # 'k' - 5: 0, # 'l' - 13: 1, # 'm' - 4: 2, # 'n' - 15: 1, # 'o' - 26: 0, # 'p' - 7: 2, # 'r' - 8: 1, # 's' - 9: 1, # 't' - 14: 1, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 1, # 'y' - 22: 1, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 1, # 'Ö' - 55: 2, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 2, # 'ö' - 17: 0, # 'ü' - 30: 1, # 'ğ' - 41: 1, # 'İ' - 6: 2, # 'ı' - 40: 0, # 'Ş' - 19: 2, # 'ş' - }, - 36: { # 'G' - 23: 1, # 'A' - 37: 0, # 'B' - 47: 1, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 1, # 'F' - 36: 2, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 2, # 'K' - 49: 0, # 'L' - 20: 0, # 'M' - 46: 2, # 'N' - 42: 1, # 'O' - 48: 1, # 'P' - 44: 1, # 'R' - 35: 1, # 'S' - 31: 0, # 'T' - 51: 1, # 'U' - 38: 2, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 0, # 'b' - 28: 1, # 'c' - 12: 0, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 0, # 'i' - 24: 1, # 'j' - 10: 1, # 'k' - 5: 0, # 'l' - 13: 3, # 'm' - 4: 2, # 'n' - 15: 0, # 'o' - 26: 1, # 'p' - 7: 0, # 'r' - 8: 1, # 's' - 9: 1, # 't' - 14: 3, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 1, # 'x' - 11: 0, # 'y' - 22: 2, # 'z' - 63: 0, # '·' - 54: 1, # 'Ç' - 50: 2, # 'Ö' - 55: 0, # 'Ü' - 59: 1, # 'â' - 33: 2, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 0, # 'ü' - 30: 1, # 'ğ' - 41: 1, # 'İ' - 6: 2, # 'ı' - 40: 2, # 'Ş' - 19: 1, # 'ş' - }, - 45: { # 'H' - 23: 0, # 'A' - 37: 1, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 2, # 'F' - 36: 2, # 'G' - 45: 1, # 'H' - 53: 1, # 'I' - 60: 0, # 'J' - 16: 2, # 'K' - 49: 1, # 'L' - 20: 0, # 'M' - 46: 1, # 'N' - 42: 1, # 'O' - 48: 1, # 'P' - 44: 0, # 'R' - 35: 2, # 'S' - 31: 0, # 'T' - 51: 1, # 'U' - 38: 2, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 0, # 'b' - 28: 2, # 'c' - 12: 0, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 2, # 'i' - 24: 0, # 'j' - 10: 1, # 'k' - 5: 0, # 'l' - 13: 2, # 'm' - 4: 0, # 'n' - 15: 1, # 'o' - 26: 1, # 'p' - 7: 1, # 'r' - 8: 0, # 's' - 9: 0, # 't' - 14: 3, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 2, # 'z' - 63: 0, # '·' - 54: 1, # 'Ç' - 50: 1, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 1, # 'ç' - 61: 0, # 'î' - 34: 1, # 'ö' - 17: 0, # 'ü' - 30: 2, # 'ğ' - 41: 1, # 'İ' - 6: 0, # 'ı' - 40: 2, # 'Ş' - 19: 1, # 'ş' - }, - 53: { # 'I' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 1, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 2, # 'K' - 49: 0, # 'L' - 20: 0, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 1, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 2, # 'a' - 21: 0, # 'b' - 28: 2, # 'c' - 12: 0, # 'd' - 2: 2, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 0, # 'i' - 24: 0, # 'j' - 10: 0, # 'k' - 5: 2, # 'l' - 13: 2, # 'm' - 4: 0, # 'n' - 15: 0, # 'o' - 26: 0, # 'p' - 7: 0, # 'r' - 8: 0, # 's' - 9: 0, # 't' - 14: 2, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 2, # 'z' - 63: 0, # '·' - 54: 1, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 2, # 'ç' - 61: 0, # 'î' - 34: 1, # 'ö' - 17: 0, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 0, # 'ı' - 40: 1, # 'Ş' - 19: 1, # 'ş' - }, - 60: { # 'J' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 1, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 0, # 'a' - 21: 1, # 'b' - 28: 0, # 'c' - 12: 1, # 'd' - 2: 0, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 1, # 'i' - 24: 0, # 'j' - 10: 0, # 'k' - 5: 0, # 'l' - 13: 0, # 'm' - 4: 1, # 'n' - 15: 0, # 'o' - 26: 0, # 'p' - 7: 0, # 'r' - 8: 1, # 's' - 9: 0, # 't' - 14: 0, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 0, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 0, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 16: { # 'K' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 3, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 2, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 2, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 2, # 'a' - 21: 3, # 'b' - 28: 0, # 'c' - 12: 3, # 'd' - 2: 1, # 'e' - 18: 3, # 'f' - 27: 3, # 'g' - 25: 3, # 'h' - 3: 3, # 'i' - 24: 2, # 'j' - 10: 3, # 'k' - 5: 0, # 'l' - 13: 0, # 'm' - 4: 3, # 'n' - 15: 0, # 'o' - 26: 1, # 'p' - 7: 3, # 'r' - 8: 3, # 's' - 9: 3, # 't' - 14: 0, # 'u' - 32: 3, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 2, # 'y' - 22: 1, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 2, # 'ü' - 30: 0, # 'ğ' - 41: 1, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 49: { # 'L' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 2, # 'E' - 52: 0, # 'F' - 36: 1, # 'G' - 45: 1, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 1, # 'M' - 46: 0, # 'N' - 42: 2, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 1, # 'Y' - 56: 0, # 'Z' - 1: 0, # 'a' - 21: 3, # 'b' - 28: 0, # 'c' - 12: 2, # 'd' - 2: 0, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 2, # 'i' - 24: 0, # 'j' - 10: 1, # 'k' - 5: 0, # 'l' - 13: 0, # 'm' - 4: 2, # 'n' - 15: 1, # 'o' - 26: 1, # 'p' - 7: 1, # 'r' - 8: 1, # 's' - 9: 1, # 't' - 14: 0, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 2, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 2, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 1, # 'ö' - 17: 1, # 'ü' - 30: 1, # 'ğ' - 41: 0, # 'İ' - 6: 2, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 20: { # 'M' - 23: 1, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 1, # 'J' - 16: 3, # 'K' - 49: 0, # 'L' - 20: 2, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 1, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 2, # 'b' - 28: 0, # 'c' - 12: 3, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 1, # 'g' - 25: 1, # 'h' - 3: 2, # 'i' - 24: 2, # 'j' - 10: 2, # 'k' - 5: 2, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 15: 0, # 'o' - 26: 1, # 'p' - 7: 3, # 'r' - 8: 0, # 's' - 9: 2, # 't' - 14: 3, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 2, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 3, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 0, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 46: { # 'N' - 23: 0, # 'A' - 37: 1, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 1, # 'F' - 36: 1, # 'G' - 45: 1, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 2, # 'K' - 49: 0, # 'L' - 20: 0, # 'M' - 46: 1, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 1, # 'R' - 35: 1, # 'S' - 31: 0, # 'T' - 51: 1, # 'U' - 38: 2, # 'V' - 62: 0, # 'W' - 43: 1, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 0, # 'b' - 28: 2, # 'c' - 12: 0, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 1, # 'g' - 25: 0, # 'h' - 3: 0, # 'i' - 24: 2, # 'j' - 10: 1, # 'k' - 5: 1, # 'l' - 13: 3, # 'm' - 4: 2, # 'n' - 15: 1, # 'o' - 26: 1, # 'p' - 7: 1, # 'r' - 8: 0, # 's' - 9: 0, # 't' - 14: 3, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 1, # 'x' - 11: 1, # 'y' - 22: 2, # 'z' - 63: 0, # '·' - 54: 1, # 'Ç' - 50: 1, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 1, # 'ö' - 17: 0, # 'ü' - 30: 0, # 'ğ' - 41: 1, # 'İ' - 6: 2, # 'ı' - 40: 1, # 'Ş' - 19: 1, # 'ş' - }, - 42: { # 'O' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 1, # 'F' - 36: 0, # 'G' - 45: 1, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 2, # 'K' - 49: 1, # 'L' - 20: 0, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 2, # 'P' - 44: 1, # 'R' - 35: 1, # 'S' - 31: 0, # 'T' - 51: 1, # 'U' - 38: 1, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 0, # 'b' - 28: 2, # 'c' - 12: 0, # 'd' - 2: 2, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 0, # 'i' - 24: 0, # 'j' - 10: 0, # 'k' - 5: 3, # 'l' - 13: 3, # 'm' - 4: 0, # 'n' - 15: 1, # 'o' - 26: 0, # 'p' - 7: 0, # 'r' - 8: 0, # 's' - 9: 0, # 't' - 14: 2, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 2, # 'z' - 63: 0, # '·' - 54: 2, # 'Ç' - 50: 1, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 2, # 'ç' - 61: 0, # 'î' - 34: 1, # 'ö' - 17: 0, # 'ü' - 30: 1, # 'ğ' - 41: 2, # 'İ' - 6: 1, # 'ı' - 40: 1, # 'Ş' - 19: 1, # 'ş' - }, - 48: { # 'P' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 2, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 2, # 'F' - 36: 1, # 'G' - 45: 1, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 2, # 'K' - 49: 0, # 'L' - 20: 0, # 'M' - 46: 1, # 'N' - 42: 1, # 'O' - 48: 1, # 'P' - 44: 0, # 'R' - 35: 1, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 1, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 2, # 'a' - 21: 0, # 'b' - 28: 2, # 'c' - 12: 0, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 0, # 'i' - 24: 0, # 'j' - 10: 1, # 'k' - 5: 0, # 'l' - 13: 2, # 'm' - 4: 0, # 'n' - 15: 2, # 'o' - 26: 0, # 'p' - 7: 0, # 'r' - 8: 0, # 's' - 9: 0, # 't' - 14: 2, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 2, # 'x' - 11: 0, # 'y' - 22: 2, # 'z' - 63: 0, # '·' - 54: 1, # 'Ç' - 50: 2, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 2, # 'ö' - 17: 0, # 'ü' - 30: 1, # 'ğ' - 41: 1, # 'İ' - 6: 0, # 'ı' - 40: 2, # 'Ş' - 19: 1, # 'ş' - }, - 44: { # 'R' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 1, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 1, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 3, # 'K' - 49: 0, # 'L' - 20: 0, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 1, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 1, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 1, # 'b' - 28: 1, # 'c' - 12: 0, # 'd' - 2: 2, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 0, # 'i' - 24: 0, # 'j' - 10: 1, # 'k' - 5: 2, # 'l' - 13: 2, # 'm' - 4: 0, # 'n' - 15: 1, # 'o' - 26: 0, # 'p' - 7: 0, # 'r' - 8: 0, # 's' - 9: 0, # 't' - 14: 2, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 1, # 'y' - 22: 2, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 1, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 1, # 'ç' - 61: 0, # 'î' - 34: 1, # 'ö' - 17: 1, # 'ü' - 30: 1, # 'ğ' - 41: 0, # 'İ' - 6: 2, # 'ı' - 40: 1, # 'Ş' - 19: 1, # 'ş' - }, - 35: { # 'S' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 1, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 1, # 'F' - 36: 1, # 'G' - 45: 1, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 3, # 'K' - 49: 1, # 'L' - 20: 1, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 1, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 1, # 'U' - 38: 1, # 'V' - 62: 0, # 'W' - 43: 1, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 0, # 'b' - 28: 2, # 'c' - 12: 0, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 0, # 'i' - 24: 0, # 'j' - 10: 1, # 'k' - 5: 1, # 'l' - 13: 2, # 'm' - 4: 1, # 'n' - 15: 0, # 'o' - 26: 0, # 'p' - 7: 0, # 'r' - 8: 0, # 's' - 9: 1, # 't' - 14: 2, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 1, # 'z' - 63: 0, # '·' - 54: 2, # 'Ç' - 50: 2, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 3, # 'ç' - 61: 0, # 'î' - 34: 1, # 'ö' - 17: 0, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 3, # 'ı' - 40: 2, # 'Ş' - 19: 1, # 'ş' - }, - 31: { # 'T' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 1, # 'J' - 16: 2, # 'K' - 49: 0, # 'L' - 20: 1, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 2, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 2, # 'b' - 28: 0, # 'c' - 12: 1, # 'd' - 2: 3, # 'e' - 18: 2, # 'f' - 27: 2, # 'g' - 25: 0, # 'h' - 3: 1, # 'i' - 24: 1, # 'j' - 10: 2, # 'k' - 5: 2, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 15: 0, # 'o' - 26: 2, # 'p' - 7: 2, # 'r' - 8: 0, # 's' - 9: 2, # 't' - 14: 2, # 'u' - 32: 1, # 'v' - 57: 1, # 'w' - 58: 1, # 'x' - 11: 2, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 1, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 51: { # 'U' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 1, # 'F' - 36: 1, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 1, # 'K' - 49: 0, # 'L' - 20: 0, # 'M' - 46: 1, # 'N' - 42: 0, # 'O' - 48: 1, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 1, # 'U' - 38: 1, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 0, # 'b' - 28: 1, # 'c' - 12: 0, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 2, # 'g' - 25: 0, # 'h' - 3: 0, # 'i' - 24: 0, # 'j' - 10: 1, # 'k' - 5: 1, # 'l' - 13: 3, # 'm' - 4: 2, # 'n' - 15: 0, # 'o' - 26: 1, # 'p' - 7: 0, # 'r' - 8: 0, # 's' - 9: 0, # 't' - 14: 2, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 2, # 'z' - 63: 0, # '·' - 54: 1, # 'Ç' - 50: 1, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 0, # 'ü' - 30: 1, # 'ğ' - 41: 1, # 'İ' - 6: 2, # 'ı' - 40: 0, # 'Ş' - 19: 1, # 'ş' - }, - 38: { # 'V' - 23: 1, # 'A' - 37: 1, # 'B' - 47: 1, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 2, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 3, # 'K' - 49: 0, # 'L' - 20: 3, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 1, # 'P' - 44: 1, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 1, # 'U' - 38: 1, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 0, # 'b' - 28: 2, # 'c' - 12: 0, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 0, # 'i' - 24: 0, # 'j' - 10: 0, # 'k' - 5: 2, # 'l' - 13: 2, # 'm' - 4: 0, # 'n' - 15: 2, # 'o' - 26: 0, # 'p' - 7: 0, # 'r' - 8: 0, # 's' - 9: 1, # 't' - 14: 3, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 1, # 'y' - 22: 2, # 'z' - 63: 0, # '·' - 54: 1, # 'Ç' - 50: 1, # 'Ö' - 55: 0, # 'Ü' - 59: 1, # 'â' - 33: 2, # 'ç' - 61: 0, # 'î' - 34: 1, # 'ö' - 17: 0, # 'ü' - 30: 1, # 'ğ' - 41: 1, # 'İ' - 6: 3, # 'ı' - 40: 2, # 'Ş' - 19: 1, # 'ş' - }, - 62: { # 'W' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 0, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 0, # 'a' - 21: 0, # 'b' - 28: 0, # 'c' - 12: 0, # 'd' - 2: 0, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 0, # 'i' - 24: 0, # 'j' - 10: 0, # 'k' - 5: 0, # 'l' - 13: 0, # 'm' - 4: 0, # 'n' - 15: 0, # 'o' - 26: 0, # 'p' - 7: 0, # 'r' - 8: 0, # 's' - 9: 0, # 't' - 14: 0, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 0, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 0, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 43: { # 'Y' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 1, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 2, # 'F' - 36: 0, # 'G' - 45: 1, # 'H' - 53: 1, # 'I' - 60: 0, # 'J' - 16: 2, # 'K' - 49: 0, # 'L' - 20: 0, # 'M' - 46: 2, # 'N' - 42: 0, # 'O' - 48: 2, # 'P' - 44: 1, # 'R' - 35: 1, # 'S' - 31: 0, # 'T' - 51: 1, # 'U' - 38: 2, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 0, # 'b' - 28: 2, # 'c' - 12: 0, # 'd' - 2: 2, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 0, # 'i' - 24: 1, # 'j' - 10: 1, # 'k' - 5: 1, # 'l' - 13: 3, # 'm' - 4: 0, # 'n' - 15: 2, # 'o' - 26: 0, # 'p' - 7: 0, # 'r' - 8: 0, # 's' - 9: 0, # 't' - 14: 3, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 1, # 'x' - 11: 0, # 'y' - 22: 2, # 'z' - 63: 0, # '·' - 54: 1, # 'Ç' - 50: 2, # 'Ö' - 55: 1, # 'Ü' - 59: 1, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 1, # 'ö' - 17: 0, # 'ü' - 30: 1, # 'ğ' - 41: 1, # 'İ' - 6: 0, # 'ı' - 40: 2, # 'Ş' - 19: 1, # 'ş' - }, - 56: { # 'Z' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 0, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 2, # 'Z' - 1: 2, # 'a' - 21: 1, # 'b' - 28: 0, # 'c' - 12: 0, # 'd' - 2: 2, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 2, # 'i' - 24: 1, # 'j' - 10: 0, # 'k' - 5: 0, # 'l' - 13: 1, # 'm' - 4: 1, # 'n' - 15: 0, # 'o' - 26: 0, # 'p' - 7: 1, # 'r' - 8: 1, # 's' - 9: 0, # 't' - 14: 2, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 1, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 1, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 1: { # 'a' - 23: 3, # 'A' - 37: 0, # 'B' - 47: 1, # 'C' - 39: 0, # 'D' - 29: 3, # 'E' - 52: 0, # 'F' - 36: 1, # 'G' - 45: 1, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 3, # 'M' - 46: 1, # 'N' - 42: 0, # 'O' - 48: 1, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 3, # 'T' - 51: 0, # 'U' - 38: 1, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 2, # 'Z' - 1: 2, # 'a' - 21: 3, # 'b' - 28: 0, # 'c' - 12: 3, # 'd' - 2: 2, # 'e' - 18: 3, # 'f' - 27: 3, # 'g' - 25: 3, # 'h' - 3: 3, # 'i' - 24: 3, # 'j' - 10: 3, # 'k' - 5: 0, # 'l' - 13: 2, # 'm' - 4: 3, # 'n' - 15: 1, # 'o' - 26: 3, # 'p' - 7: 3, # 'r' - 8: 3, # 's' - 9: 3, # 't' - 14: 3, # 'u' - 32: 3, # 'v' - 57: 2, # 'w' - 58: 0, # 'x' - 11: 3, # 'y' - 22: 0, # 'z' - 63: 1, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 1, # 'ç' - 61: 1, # 'î' - 34: 1, # 'ö' - 17: 3, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 1, # 'ş' - }, - 21: { # 'b' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 1, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 1, # 'J' - 16: 2, # 'K' - 49: 0, # 'L' - 20: 2, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 1, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 1, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 2, # 'b' - 28: 0, # 'c' - 12: 3, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 3, # 'g' - 25: 1, # 'h' - 3: 3, # 'i' - 24: 2, # 'j' - 10: 3, # 'k' - 5: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 15: 0, # 'o' - 26: 3, # 'p' - 7: 1, # 'r' - 8: 2, # 's' - 9: 2, # 't' - 14: 2, # 'u' - 32: 1, # 'v' - 57: 0, # 'w' - 58: 1, # 'x' - 11: 3, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 1, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 0, # 'ü' - 30: 1, # 'ğ' - 41: 0, # 'İ' - 6: 2, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 28: { # 'c' - 23: 0, # 'A' - 37: 1, # 'B' - 47: 1, # 'C' - 39: 1, # 'D' - 29: 2, # 'E' - 52: 0, # 'F' - 36: 2, # 'G' - 45: 2, # 'H' - 53: 1, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 2, # 'M' - 46: 1, # 'N' - 42: 1, # 'O' - 48: 2, # 'P' - 44: 1, # 'R' - 35: 1, # 'S' - 31: 2, # 'T' - 51: 2, # 'U' - 38: 2, # 'V' - 62: 0, # 'W' - 43: 3, # 'Y' - 56: 0, # 'Z' - 1: 1, # 'a' - 21: 1, # 'b' - 28: 2, # 'c' - 12: 2, # 'd' - 2: 1, # 'e' - 18: 1, # 'f' - 27: 2, # 'g' - 25: 2, # 'h' - 3: 3, # 'i' - 24: 1, # 'j' - 10: 3, # 'k' - 5: 0, # 'l' - 13: 2, # 'm' - 4: 3, # 'n' - 15: 2, # 'o' - 26: 2, # 'p' - 7: 3, # 'r' - 8: 3, # 's' - 9: 3, # 't' - 14: 1, # 'u' - 32: 0, # 'v' - 57: 1, # 'w' - 58: 0, # 'x' - 11: 2, # 'y' - 22: 1, # 'z' - 63: 1, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 1, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 1, # 'î' - 34: 2, # 'ö' - 17: 2, # 'ü' - 30: 2, # 'ğ' - 41: 1, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 2, # 'ş' - }, - 12: { # 'd' - 23: 1, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 2, # 'J' - 16: 3, # 'K' - 49: 0, # 'L' - 20: 3, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 1, # 'S' - 31: 1, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 2, # 'b' - 28: 1, # 'c' - 12: 3, # 'd' - 2: 3, # 'e' - 18: 1, # 'f' - 27: 3, # 'g' - 25: 3, # 'h' - 3: 2, # 'i' - 24: 3, # 'j' - 10: 2, # 'k' - 5: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 15: 1, # 'o' - 26: 2, # 'p' - 7: 3, # 'r' - 8: 2, # 's' - 9: 2, # 't' - 14: 3, # 'u' - 32: 1, # 'v' - 57: 0, # 'w' - 58: 1, # 'x' - 11: 3, # 'y' - 22: 1, # 'z' - 63: 1, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 1, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 2, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 2: { # 'e' - 23: 2, # 'A' - 37: 0, # 'B' - 47: 2, # 'C' - 39: 0, # 'D' - 29: 3, # 'E' - 52: 1, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 1, # 'K' - 49: 0, # 'L' - 20: 3, # 'M' - 46: 1, # 'N' - 42: 0, # 'O' - 48: 1, # 'P' - 44: 1, # 'R' - 35: 0, # 'S' - 31: 3, # 'T' - 51: 0, # 'U' - 38: 1, # 'V' - 62: 0, # 'W' - 43: 1, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 3, # 'b' - 28: 0, # 'c' - 12: 3, # 'd' - 2: 2, # 'e' - 18: 3, # 'f' - 27: 3, # 'g' - 25: 3, # 'h' - 3: 3, # 'i' - 24: 3, # 'j' - 10: 3, # 'k' - 5: 0, # 'l' - 13: 2, # 'm' - 4: 3, # 'n' - 15: 1, # 'o' - 26: 3, # 'p' - 7: 3, # 'r' - 8: 3, # 's' - 9: 3, # 't' - 14: 3, # 'u' - 32: 3, # 'v' - 57: 2, # 'w' - 58: 0, # 'x' - 11: 3, # 'y' - 22: 1, # 'z' - 63: 1, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 1, # 'ç' - 61: 0, # 'î' - 34: 1, # 'ö' - 17: 3, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 18: { # 'f' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 2, # 'K' - 49: 0, # 'L' - 20: 2, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 2, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 1, # 'b' - 28: 0, # 'c' - 12: 3, # 'd' - 2: 3, # 'e' - 18: 2, # 'f' - 27: 1, # 'g' - 25: 1, # 'h' - 3: 1, # 'i' - 24: 1, # 'j' - 10: 1, # 'k' - 5: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 15: 0, # 'o' - 26: 2, # 'p' - 7: 1, # 'r' - 8: 3, # 's' - 9: 3, # 't' - 14: 1, # 'u' - 32: 2, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 1, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 1, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 1, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 1, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 27: { # 'g' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 3, # 'K' - 49: 0, # 'L' - 20: 0, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 1, # 'S' - 31: 1, # 'T' - 51: 0, # 'U' - 38: 2, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 1, # 'b' - 28: 0, # 'c' - 12: 1, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 2, # 'g' - 25: 1, # 'h' - 3: 2, # 'i' - 24: 3, # 'j' - 10: 2, # 'k' - 5: 3, # 'l' - 13: 3, # 'm' - 4: 2, # 'n' - 15: 0, # 'o' - 26: 1, # 'p' - 7: 2, # 'r' - 8: 2, # 's' - 9: 3, # 't' - 14: 3, # 'u' - 32: 1, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 1, # 'y' - 22: 0, # 'z' - 63: 1, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 0, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 2, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 25: { # 'h' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 2, # 'K' - 49: 0, # 'L' - 20: 0, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 0, # 'b' - 28: 0, # 'c' - 12: 2, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 1, # 'g' - 25: 2, # 'h' - 3: 2, # 'i' - 24: 3, # 'j' - 10: 3, # 'k' - 5: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 15: 1, # 'o' - 26: 1, # 'p' - 7: 3, # 'r' - 8: 3, # 's' - 9: 2, # 't' - 14: 3, # 'u' - 32: 2, # 'v' - 57: 1, # 'w' - 58: 0, # 'x' - 11: 1, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 0, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 3: { # 'i' - 23: 2, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 1, # 'J' - 16: 3, # 'K' - 49: 0, # 'L' - 20: 3, # 'M' - 46: 0, # 'N' - 42: 1, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 1, # 'S' - 31: 2, # 'T' - 51: 0, # 'U' - 38: 1, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 2, # 'b' - 28: 0, # 'c' - 12: 3, # 'd' - 2: 3, # 'e' - 18: 2, # 'f' - 27: 3, # 'g' - 25: 1, # 'h' - 3: 3, # 'i' - 24: 2, # 'j' - 10: 3, # 'k' - 5: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 15: 1, # 'o' - 26: 3, # 'p' - 7: 3, # 'r' - 8: 3, # 's' - 9: 3, # 't' - 14: 3, # 'u' - 32: 2, # 'v' - 57: 1, # 'w' - 58: 1, # 'x' - 11: 3, # 'y' - 22: 1, # 'z' - 63: 1, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 1, # 'Ü' - 59: 0, # 'â' - 33: 2, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 3, # 'ü' - 30: 0, # 'ğ' - 41: 1, # 'İ' - 6: 2, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 24: { # 'j' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 1, # 'J' - 16: 2, # 'K' - 49: 0, # 'L' - 20: 2, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 1, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 1, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 1, # 'Z' - 1: 3, # 'a' - 21: 1, # 'b' - 28: 1, # 'c' - 12: 3, # 'd' - 2: 3, # 'e' - 18: 2, # 'f' - 27: 1, # 'g' - 25: 1, # 'h' - 3: 2, # 'i' - 24: 1, # 'j' - 10: 2, # 'k' - 5: 2, # 'l' - 13: 3, # 'm' - 4: 2, # 'n' - 15: 0, # 'o' - 26: 1, # 'p' - 7: 2, # 'r' - 8: 3, # 's' - 9: 2, # 't' - 14: 3, # 'u' - 32: 2, # 'v' - 57: 0, # 'w' - 58: 2, # 'x' - 11: 1, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 1, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 1, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 10: { # 'k' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 3, # 'K' - 49: 0, # 'L' - 20: 2, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 3, # 'T' - 51: 0, # 'U' - 38: 1, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 1, # 'Z' - 1: 3, # 'a' - 21: 2, # 'b' - 28: 0, # 'c' - 12: 2, # 'd' - 2: 3, # 'e' - 18: 1, # 'f' - 27: 2, # 'g' - 25: 2, # 'h' - 3: 3, # 'i' - 24: 2, # 'j' - 10: 2, # 'k' - 5: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 15: 0, # 'o' - 26: 3, # 'p' - 7: 2, # 'r' - 8: 2, # 's' - 9: 2, # 't' - 14: 3, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 1, # 'x' - 11: 3, # 'y' - 22: 0, # 'z' - 63: 1, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 3, # 'ç' - 61: 0, # 'î' - 34: 1, # 'ö' - 17: 3, # 'ü' - 30: 1, # 'ğ' - 41: 0, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 1, # 'ş' - }, - 5: { # 'l' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 3, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 2, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 1, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 0, # 'a' - 21: 3, # 'b' - 28: 0, # 'c' - 12: 3, # 'd' - 2: 1, # 'e' - 18: 3, # 'f' - 27: 3, # 'g' - 25: 2, # 'h' - 3: 3, # 'i' - 24: 2, # 'j' - 10: 3, # 'k' - 5: 1, # 'l' - 13: 1, # 'm' - 4: 3, # 'n' - 15: 0, # 'o' - 26: 2, # 'p' - 7: 3, # 'r' - 8: 3, # 's' - 9: 3, # 't' - 14: 2, # 'u' - 32: 2, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 3, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 1, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 2, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 13: { # 'm' - 23: 1, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 3, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 3, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 3, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 1, # 'Y' - 56: 0, # 'Z' - 1: 2, # 'a' - 21: 3, # 'b' - 28: 0, # 'c' - 12: 3, # 'd' - 2: 2, # 'e' - 18: 3, # 'f' - 27: 3, # 'g' - 25: 3, # 'h' - 3: 3, # 'i' - 24: 3, # 'j' - 10: 3, # 'k' - 5: 0, # 'l' - 13: 2, # 'm' - 4: 3, # 'n' - 15: 1, # 'o' - 26: 2, # 'p' - 7: 3, # 'r' - 8: 3, # 's' - 9: 3, # 't' - 14: 2, # 'u' - 32: 2, # 'v' - 57: 1, # 'w' - 58: 0, # 'x' - 11: 3, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 3, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 1, # 'ş' - }, - 4: { # 'n' - 23: 1, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 1, # 'H' - 53: 0, # 'I' - 60: 2, # 'J' - 16: 3, # 'K' - 49: 0, # 'L' - 20: 3, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 2, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 2, # 'b' - 28: 1, # 'c' - 12: 3, # 'd' - 2: 3, # 'e' - 18: 1, # 'f' - 27: 2, # 'g' - 25: 3, # 'h' - 3: 2, # 'i' - 24: 2, # 'j' - 10: 3, # 'k' - 5: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 15: 1, # 'o' - 26: 3, # 'p' - 7: 2, # 'r' - 8: 3, # 's' - 9: 3, # 't' - 14: 3, # 'u' - 32: 2, # 'v' - 57: 0, # 'w' - 58: 2, # 'x' - 11: 3, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 1, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 2, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 1, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 15: { # 'o' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 1, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 2, # 'F' - 36: 1, # 'G' - 45: 1, # 'H' - 53: 1, # 'I' - 60: 0, # 'J' - 16: 3, # 'K' - 49: 2, # 'L' - 20: 0, # 'M' - 46: 2, # 'N' - 42: 1, # 'O' - 48: 2, # 'P' - 44: 1, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 0, # 'b' - 28: 2, # 'c' - 12: 0, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 1, # 'i' - 24: 2, # 'j' - 10: 1, # 'k' - 5: 3, # 'l' - 13: 3, # 'm' - 4: 2, # 'n' - 15: 2, # 'o' - 26: 0, # 'p' - 7: 1, # 'r' - 8: 0, # 's' - 9: 0, # 't' - 14: 3, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 2, # 'x' - 11: 0, # 'y' - 22: 2, # 'z' - 63: 0, # '·' - 54: 1, # 'Ç' - 50: 2, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 3, # 'ç' - 61: 0, # 'î' - 34: 1, # 'ö' - 17: 0, # 'ü' - 30: 2, # 'ğ' - 41: 2, # 'İ' - 6: 3, # 'ı' - 40: 2, # 'Ş' - 19: 2, # 'ş' - }, - 26: { # 'p' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 3, # 'K' - 49: 0, # 'L' - 20: 1, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 1, # 'b' - 28: 0, # 'c' - 12: 1, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 1, # 'g' - 25: 1, # 'h' - 3: 2, # 'i' - 24: 3, # 'j' - 10: 1, # 'k' - 5: 3, # 'l' - 13: 3, # 'm' - 4: 2, # 'n' - 15: 0, # 'o' - 26: 2, # 'p' - 7: 2, # 'r' - 8: 1, # 's' - 9: 1, # 't' - 14: 3, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 1, # 'x' - 11: 1, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 3, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 1, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 7: { # 'r' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 1, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 2, # 'J' - 16: 3, # 'K' - 49: 0, # 'L' - 20: 2, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 2, # 'T' - 51: 1, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 1, # 'Z' - 1: 3, # 'a' - 21: 1, # 'b' - 28: 0, # 'c' - 12: 3, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 2, # 'g' - 25: 3, # 'h' - 3: 2, # 'i' - 24: 2, # 'j' - 10: 3, # 'k' - 5: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 15: 0, # 'o' - 26: 2, # 'p' - 7: 3, # 'r' - 8: 3, # 's' - 9: 3, # 't' - 14: 3, # 'u' - 32: 2, # 'v' - 57: 0, # 'w' - 58: 1, # 'x' - 11: 2, # 'y' - 22: 0, # 'z' - 63: 1, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 2, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 3, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 2, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 8: { # 's' - 23: 1, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 1, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 3, # 'K' - 49: 0, # 'L' - 20: 3, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 2, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 1, # 'Z' - 1: 3, # 'a' - 21: 2, # 'b' - 28: 1, # 'c' - 12: 3, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 2, # 'g' - 25: 2, # 'h' - 3: 2, # 'i' - 24: 3, # 'j' - 10: 3, # 'k' - 5: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 15: 0, # 'o' - 26: 3, # 'p' - 7: 3, # 'r' - 8: 3, # 's' - 9: 3, # 't' - 14: 3, # 'u' - 32: 2, # 'v' - 57: 0, # 'w' - 58: 1, # 'x' - 11: 2, # 'y' - 22: 1, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 2, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 2, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 1, # 'ş' - }, - 9: { # 't' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 1, # 'J' - 16: 3, # 'K' - 49: 0, # 'L' - 20: 2, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 2, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 1, # 'Z' - 1: 3, # 'a' - 21: 3, # 'b' - 28: 0, # 'c' - 12: 3, # 'd' - 2: 3, # 'e' - 18: 2, # 'f' - 27: 2, # 'g' - 25: 2, # 'h' - 3: 2, # 'i' - 24: 2, # 'j' - 10: 3, # 'k' - 5: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 15: 0, # 'o' - 26: 2, # 'p' - 7: 3, # 'r' - 8: 3, # 's' - 9: 3, # 't' - 14: 3, # 'u' - 32: 3, # 'v' - 57: 0, # 'w' - 58: 2, # 'x' - 11: 2, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 3, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 2, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 14: { # 'u' - 23: 3, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 3, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 1, # 'H' - 53: 0, # 'I' - 60: 1, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 3, # 'M' - 46: 2, # 'N' - 42: 0, # 'O' - 48: 1, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 3, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 1, # 'Y' - 56: 2, # 'Z' - 1: 2, # 'a' - 21: 3, # 'b' - 28: 0, # 'c' - 12: 3, # 'd' - 2: 2, # 'e' - 18: 2, # 'f' - 27: 3, # 'g' - 25: 3, # 'h' - 3: 3, # 'i' - 24: 2, # 'j' - 10: 3, # 'k' - 5: 0, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 15: 0, # 'o' - 26: 3, # 'p' - 7: 3, # 'r' - 8: 3, # 's' - 9: 3, # 't' - 14: 3, # 'u' - 32: 2, # 'v' - 57: 2, # 'w' - 58: 0, # 'x' - 11: 3, # 'y' - 22: 0, # 'z' - 63: 1, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 3, # 'ü' - 30: 1, # 'ğ' - 41: 0, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 32: { # 'v' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 3, # 'K' - 49: 0, # 'L' - 20: 1, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 0, # 'b' - 28: 0, # 'c' - 12: 3, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 0, # 'i' - 24: 1, # 'j' - 10: 1, # 'k' - 5: 3, # 'l' - 13: 2, # 'm' - 4: 3, # 'n' - 15: 0, # 'o' - 26: 1, # 'p' - 7: 1, # 'r' - 8: 2, # 's' - 9: 3, # 't' - 14: 3, # 'u' - 32: 1, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 2, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 0, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 1, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 57: { # 'w' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 0, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 1, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 1, # 'a' - 21: 0, # 'b' - 28: 0, # 'c' - 12: 0, # 'd' - 2: 2, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 1, # 'h' - 3: 0, # 'i' - 24: 0, # 'j' - 10: 1, # 'k' - 5: 0, # 'l' - 13: 0, # 'm' - 4: 1, # 'n' - 15: 0, # 'o' - 26: 0, # 'p' - 7: 0, # 'r' - 8: 1, # 's' - 9: 0, # 't' - 14: 1, # 'u' - 32: 0, # 'v' - 57: 2, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 0, # 'z' - 63: 1, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 1, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 0, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 58: { # 'x' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 1, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 1, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 1, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 0, # 'a' - 21: 1, # 'b' - 28: 0, # 'c' - 12: 2, # 'd' - 2: 1, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 2, # 'i' - 24: 2, # 'j' - 10: 1, # 'k' - 5: 0, # 'l' - 13: 0, # 'm' - 4: 2, # 'n' - 15: 0, # 'o' - 26: 0, # 'p' - 7: 1, # 'r' - 8: 2, # 's' - 9: 1, # 't' - 14: 0, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 2, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 1, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 2, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 11: { # 'y' - 23: 1, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 1, # 'J' - 16: 3, # 'K' - 49: 0, # 'L' - 20: 1, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 1, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 1, # 'Y' - 56: 1, # 'Z' - 1: 3, # 'a' - 21: 1, # 'b' - 28: 0, # 'c' - 12: 2, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 2, # 'g' - 25: 2, # 'h' - 3: 2, # 'i' - 24: 1, # 'j' - 10: 2, # 'k' - 5: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 15: 0, # 'o' - 26: 1, # 'p' - 7: 2, # 'r' - 8: 1, # 's' - 9: 2, # 't' - 14: 3, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 1, # 'x' - 11: 3, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 3, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 2, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 22: { # 'z' - 23: 2, # 'A' - 37: 2, # 'B' - 47: 1, # 'C' - 39: 2, # 'D' - 29: 3, # 'E' - 52: 1, # 'F' - 36: 2, # 'G' - 45: 2, # 'H' - 53: 1, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 3, # 'M' - 46: 2, # 'N' - 42: 2, # 'O' - 48: 2, # 'P' - 44: 1, # 'R' - 35: 1, # 'S' - 31: 3, # 'T' - 51: 2, # 'U' - 38: 2, # 'V' - 62: 0, # 'W' - 43: 2, # 'Y' - 56: 1, # 'Z' - 1: 1, # 'a' - 21: 2, # 'b' - 28: 1, # 'c' - 12: 2, # 'd' - 2: 2, # 'e' - 18: 3, # 'f' - 27: 2, # 'g' - 25: 2, # 'h' - 3: 3, # 'i' - 24: 2, # 'j' - 10: 3, # 'k' - 5: 0, # 'l' - 13: 2, # 'm' - 4: 3, # 'n' - 15: 2, # 'o' - 26: 2, # 'p' - 7: 3, # 'r' - 8: 3, # 's' - 9: 3, # 't' - 14: 0, # 'u' - 32: 2, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 3, # 'y' - 22: 2, # 'z' - 63: 1, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 2, # 'Ü' - 59: 1, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 2, # 'ö' - 17: 2, # 'ü' - 30: 2, # 'ğ' - 41: 1, # 'İ' - 6: 3, # 'ı' - 40: 1, # 'Ş' - 19: 2, # 'ş' - }, - 63: { # '·' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 0, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 0, # 'a' - 21: 0, # 'b' - 28: 0, # 'c' - 12: 0, # 'd' - 2: 1, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 0, # 'i' - 24: 0, # 'j' - 10: 0, # 'k' - 5: 0, # 'l' - 13: 2, # 'm' - 4: 0, # 'n' - 15: 0, # 'o' - 26: 0, # 'p' - 7: 0, # 'r' - 8: 0, # 's' - 9: 0, # 't' - 14: 2, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 0, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 0, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 54: { # 'Ç' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 1, # 'C' - 39: 1, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 1, # 'G' - 45: 1, # 'H' - 53: 1, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 0, # 'M' - 46: 0, # 'N' - 42: 1, # 'O' - 48: 1, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 1, # 'U' - 38: 1, # 'V' - 62: 0, # 'W' - 43: 2, # 'Y' - 56: 0, # 'Z' - 1: 0, # 'a' - 21: 1, # 'b' - 28: 0, # 'c' - 12: 1, # 'd' - 2: 0, # 'e' - 18: 0, # 'f' - 27: 1, # 'g' - 25: 0, # 'h' - 3: 3, # 'i' - 24: 0, # 'j' - 10: 1, # 'k' - 5: 0, # 'l' - 13: 0, # 'm' - 4: 2, # 'n' - 15: 1, # 'o' - 26: 0, # 'p' - 7: 2, # 'r' - 8: 0, # 's' - 9: 1, # 't' - 14: 0, # 'u' - 32: 2, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 2, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 1, # 'ö' - 17: 0, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 2, # 'ı' - 40: 0, # 'Ş' - 19: 1, # 'ş' - }, - 50: { # 'Ö' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 1, # 'C' - 39: 1, # 'D' - 29: 2, # 'E' - 52: 0, # 'F' - 36: 1, # 'G' - 45: 2, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 1, # 'M' - 46: 1, # 'N' - 42: 2, # 'O' - 48: 2, # 'P' - 44: 1, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 1, # 'U' - 38: 1, # 'V' - 62: 0, # 'W' - 43: 2, # 'Y' - 56: 0, # 'Z' - 1: 0, # 'a' - 21: 2, # 'b' - 28: 1, # 'c' - 12: 2, # 'd' - 2: 0, # 'e' - 18: 1, # 'f' - 27: 1, # 'g' - 25: 1, # 'h' - 3: 2, # 'i' - 24: 0, # 'j' - 10: 2, # 'k' - 5: 0, # 'l' - 13: 0, # 'm' - 4: 3, # 'n' - 15: 2, # 'o' - 26: 2, # 'p' - 7: 3, # 'r' - 8: 1, # 's' - 9: 2, # 't' - 14: 0, # 'u' - 32: 1, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 1, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 2, # 'ö' - 17: 2, # 'ü' - 30: 1, # 'ğ' - 41: 0, # 'İ' - 6: 2, # 'ı' - 40: 0, # 'Ş' - 19: 1, # 'ş' - }, - 55: { # 'Ü' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 2, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 1, # 'K' - 49: 0, # 'L' - 20: 0, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 1, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 1, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 2, # 'a' - 21: 0, # 'b' - 28: 2, # 'c' - 12: 0, # 'd' - 2: 2, # 'e' - 18: 0, # 'f' - 27: 1, # 'g' - 25: 0, # 'h' - 3: 0, # 'i' - 24: 0, # 'j' - 10: 0, # 'k' - 5: 1, # 'l' - 13: 1, # 'm' - 4: 1, # 'n' - 15: 0, # 'o' - 26: 0, # 'p' - 7: 0, # 'r' - 8: 0, # 's' - 9: 1, # 't' - 14: 2, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 1, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 1, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 1, # 'ö' - 17: 0, # 'ü' - 30: 1, # 'ğ' - 41: 1, # 'İ' - 6: 0, # 'ı' - 40: 0, # 'Ş' - 19: 1, # 'ş' - }, - 59: { # 'â' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 1, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 1, # 'K' - 49: 0, # 'L' - 20: 0, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 2, # 'a' - 21: 0, # 'b' - 28: 0, # 'c' - 12: 0, # 'd' - 2: 2, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 0, # 'i' - 24: 0, # 'j' - 10: 0, # 'k' - 5: 0, # 'l' - 13: 2, # 'm' - 4: 0, # 'n' - 15: 1, # 'o' - 26: 0, # 'p' - 7: 0, # 'r' - 8: 0, # 's' - 9: 0, # 't' - 14: 2, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 1, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 0, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 1, # 'ı' - 40: 1, # 'Ş' - 19: 0, # 'ş' - }, - 33: { # 'ç' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 3, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 1, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 2, # 'T' - 51: 0, # 'U' - 38: 1, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 0, # 'Z' - 1: 0, # 'a' - 21: 3, # 'b' - 28: 0, # 'c' - 12: 2, # 'd' - 2: 0, # 'e' - 18: 2, # 'f' - 27: 1, # 'g' - 25: 3, # 'h' - 3: 3, # 'i' - 24: 0, # 'j' - 10: 3, # 'k' - 5: 0, # 'l' - 13: 0, # 'm' - 4: 3, # 'n' - 15: 0, # 'o' - 26: 1, # 'p' - 7: 3, # 'r' - 8: 2, # 's' - 9: 3, # 't' - 14: 0, # 'u' - 32: 2, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 2, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 1, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 61: { # 'î' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 0, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 0, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 1, # 'Z' - 1: 2, # 'a' - 21: 0, # 'b' - 28: 0, # 'c' - 12: 0, # 'd' - 2: 2, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 0, # 'i' - 24: 1, # 'j' - 10: 0, # 'k' - 5: 0, # 'l' - 13: 1, # 'm' - 4: 1, # 'n' - 15: 0, # 'o' - 26: 0, # 'p' - 7: 0, # 'r' - 8: 0, # 's' - 9: 0, # 't' - 14: 1, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 1, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 1, # 'î' - 34: 0, # 'ö' - 17: 0, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 1, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 34: { # 'ö' - 23: 0, # 'A' - 37: 1, # 'B' - 47: 1, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 2, # 'F' - 36: 1, # 'G' - 45: 1, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 3, # 'K' - 49: 1, # 'L' - 20: 0, # 'M' - 46: 1, # 'N' - 42: 1, # 'O' - 48: 2, # 'P' - 44: 1, # 'R' - 35: 1, # 'S' - 31: 1, # 'T' - 51: 1, # 'U' - 38: 1, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 1, # 'Z' - 1: 3, # 'a' - 21: 1, # 'b' - 28: 2, # 'c' - 12: 1, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 2, # 'g' - 25: 2, # 'h' - 3: 1, # 'i' - 24: 2, # 'j' - 10: 1, # 'k' - 5: 2, # 'l' - 13: 3, # 'm' - 4: 2, # 'n' - 15: 2, # 'o' - 26: 0, # 'p' - 7: 0, # 'r' - 8: 3, # 's' - 9: 1, # 't' - 14: 3, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 1, # 'y' - 22: 2, # 'z' - 63: 0, # '·' - 54: 1, # 'Ç' - 50: 2, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 2, # 'ç' - 61: 0, # 'î' - 34: 2, # 'ö' - 17: 0, # 'ü' - 30: 2, # 'ğ' - 41: 1, # 'İ' - 6: 1, # 'ı' - 40: 2, # 'Ş' - 19: 1, # 'ş' - }, - 17: { # 'ü' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 1, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 0, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 1, # 'J' - 16: 1, # 'K' - 49: 0, # 'L' - 20: 1, # 'M' - 46: 0, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 1, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 0, # 'Y' - 56: 1, # 'Z' - 1: 3, # 'a' - 21: 0, # 'b' - 28: 0, # 'c' - 12: 1, # 'd' - 2: 3, # 'e' - 18: 1, # 'f' - 27: 2, # 'g' - 25: 0, # 'h' - 3: 1, # 'i' - 24: 1, # 'j' - 10: 2, # 'k' - 5: 3, # 'l' - 13: 2, # 'm' - 4: 3, # 'n' - 15: 0, # 'o' - 26: 2, # 'p' - 7: 2, # 'r' - 8: 3, # 's' - 9: 2, # 't' - 14: 3, # 'u' - 32: 1, # 'v' - 57: 1, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 1, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 2, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 2, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 30: { # 'ğ' - 23: 0, # 'A' - 37: 2, # 'B' - 47: 1, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 2, # 'F' - 36: 1, # 'G' - 45: 0, # 'H' - 53: 1, # 'I' - 60: 0, # 'J' - 16: 3, # 'K' - 49: 0, # 'L' - 20: 1, # 'M' - 46: 2, # 'N' - 42: 2, # 'O' - 48: 1, # 'P' - 44: 1, # 'R' - 35: 0, # 'S' - 31: 1, # 'T' - 51: 0, # 'U' - 38: 2, # 'V' - 62: 0, # 'W' - 43: 2, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 0, # 'b' - 28: 2, # 'c' - 12: 0, # 'd' - 2: 2, # 'e' - 18: 0, # 'f' - 27: 0, # 'g' - 25: 0, # 'h' - 3: 0, # 'i' - 24: 3, # 'j' - 10: 1, # 'k' - 5: 2, # 'l' - 13: 3, # 'm' - 4: 0, # 'n' - 15: 1, # 'o' - 26: 0, # 'p' - 7: 1, # 'r' - 8: 0, # 's' - 9: 0, # 't' - 14: 3, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 2, # 'z' - 63: 0, # '·' - 54: 2, # 'Ç' - 50: 2, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 1, # 'ç' - 61: 0, # 'î' - 34: 2, # 'ö' - 17: 0, # 'ü' - 30: 1, # 'ğ' - 41: 2, # 'İ' - 6: 2, # 'ı' - 40: 2, # 'Ş' - 19: 1, # 'ş' - }, - 41: { # 'İ' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 1, # 'C' - 39: 1, # 'D' - 29: 1, # 'E' - 52: 0, # 'F' - 36: 2, # 'G' - 45: 2, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 2, # 'M' - 46: 1, # 'N' - 42: 1, # 'O' - 48: 2, # 'P' - 44: 0, # 'R' - 35: 1, # 'S' - 31: 1, # 'T' - 51: 1, # 'U' - 38: 1, # 'V' - 62: 0, # 'W' - 43: 2, # 'Y' - 56: 0, # 'Z' - 1: 1, # 'a' - 21: 2, # 'b' - 28: 1, # 'c' - 12: 2, # 'd' - 2: 1, # 'e' - 18: 0, # 'f' - 27: 3, # 'g' - 25: 2, # 'h' - 3: 2, # 'i' - 24: 2, # 'j' - 10: 2, # 'k' - 5: 0, # 'l' - 13: 1, # 'm' - 4: 3, # 'n' - 15: 1, # 'o' - 26: 1, # 'p' - 7: 3, # 'r' - 8: 3, # 's' - 9: 2, # 't' - 14: 0, # 'u' - 32: 0, # 'v' - 57: 1, # 'w' - 58: 0, # 'x' - 11: 2, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 1, # 'Ü' - 59: 1, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 1, # 'ö' - 17: 1, # 'ü' - 30: 2, # 'ğ' - 41: 0, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 1, # 'ş' - }, - 6: { # 'ı' - 23: 2, # 'A' - 37: 0, # 'B' - 47: 0, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 0, # 'F' - 36: 1, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 2, # 'J' - 16: 3, # 'K' - 49: 0, # 'L' - 20: 3, # 'M' - 46: 1, # 'N' - 42: 0, # 'O' - 48: 0, # 'P' - 44: 0, # 'R' - 35: 0, # 'S' - 31: 2, # 'T' - 51: 0, # 'U' - 38: 0, # 'V' - 62: 0, # 'W' - 43: 2, # 'Y' - 56: 1, # 'Z' - 1: 3, # 'a' - 21: 2, # 'b' - 28: 1, # 'c' - 12: 3, # 'd' - 2: 3, # 'e' - 18: 3, # 'f' - 27: 3, # 'g' - 25: 2, # 'h' - 3: 3, # 'i' - 24: 3, # 'j' - 10: 3, # 'k' - 5: 3, # 'l' - 13: 3, # 'm' - 4: 3, # 'n' - 15: 0, # 'o' - 26: 3, # 'p' - 7: 3, # 'r' - 8: 3, # 's' - 9: 3, # 't' - 14: 3, # 'u' - 32: 3, # 'v' - 57: 1, # 'w' - 58: 1, # 'x' - 11: 3, # 'y' - 22: 0, # 'z' - 63: 1, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 2, # 'ç' - 61: 0, # 'î' - 34: 0, # 'ö' - 17: 3, # 'ü' - 30: 0, # 'ğ' - 41: 0, # 'İ' - 6: 3, # 'ı' - 40: 0, # 'Ş' - 19: 0, # 'ş' - }, - 40: { # 'Ş' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 1, # 'C' - 39: 1, # 'D' - 29: 1, # 'E' - 52: 0, # 'F' - 36: 1, # 'G' - 45: 2, # 'H' - 53: 1, # 'I' - 60: 0, # 'J' - 16: 0, # 'K' - 49: 0, # 'L' - 20: 2, # 'M' - 46: 1, # 'N' - 42: 1, # 'O' - 48: 2, # 'P' - 44: 2, # 'R' - 35: 1, # 'S' - 31: 1, # 'T' - 51: 0, # 'U' - 38: 1, # 'V' - 62: 0, # 'W' - 43: 2, # 'Y' - 56: 1, # 'Z' - 1: 0, # 'a' - 21: 2, # 'b' - 28: 0, # 'c' - 12: 2, # 'd' - 2: 0, # 'e' - 18: 3, # 'f' - 27: 0, # 'g' - 25: 2, # 'h' - 3: 3, # 'i' - 24: 2, # 'j' - 10: 1, # 'k' - 5: 0, # 'l' - 13: 1, # 'm' - 4: 3, # 'n' - 15: 2, # 'o' - 26: 0, # 'p' - 7: 3, # 'r' - 8: 2, # 's' - 9: 2, # 't' - 14: 1, # 'u' - 32: 3, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 2, # 'y' - 22: 0, # 'z' - 63: 0, # '·' - 54: 0, # 'Ç' - 50: 0, # 'Ö' - 55: 1, # 'Ü' - 59: 0, # 'â' - 33: 0, # 'ç' - 61: 0, # 'î' - 34: 2, # 'ö' - 17: 1, # 'ü' - 30: 2, # 'ğ' - 41: 0, # 'İ' - 6: 2, # 'ı' - 40: 1, # 'Ş' - 19: 2, # 'ş' - }, - 19: { # 'ş' - 23: 0, # 'A' - 37: 0, # 'B' - 47: 1, # 'C' - 39: 0, # 'D' - 29: 0, # 'E' - 52: 2, # 'F' - 36: 1, # 'G' - 45: 0, # 'H' - 53: 0, # 'I' - 60: 0, # 'J' - 16: 3, # 'K' - 49: 2, # 'L' - 20: 0, # 'M' - 46: 1, # 'N' - 42: 1, # 'O' - 48: 1, # 'P' - 44: 1, # 'R' - 35: 1, # 'S' - 31: 0, # 'T' - 51: 1, # 'U' - 38: 1, # 'V' - 62: 0, # 'W' - 43: 1, # 'Y' - 56: 0, # 'Z' - 1: 3, # 'a' - 21: 1, # 'b' - 28: 2, # 'c' - 12: 0, # 'd' - 2: 3, # 'e' - 18: 0, # 'f' - 27: 2, # 'g' - 25: 1, # 'h' - 3: 1, # 'i' - 24: 0, # 'j' - 10: 2, # 'k' - 5: 2, # 'l' - 13: 3, # 'm' - 4: 0, # 'n' - 15: 0, # 'o' - 26: 1, # 'p' - 7: 3, # 'r' - 8: 0, # 's' - 9: 0, # 't' - 14: 3, # 'u' - 32: 0, # 'v' - 57: 0, # 'w' - 58: 0, # 'x' - 11: 0, # 'y' - 22: 2, # 'z' - 63: 0, # '·' - 54: 1, # 'Ç' - 50: 2, # 'Ö' - 55: 0, # 'Ü' - 59: 0, # 'â' - 33: 1, # 'ç' - 61: 1, # 'î' - 34: 2, # 'ö' - 17: 0, # 'ü' - 30: 1, # 'ğ' - 41: 1, # 'İ' - 6: 1, # 'ı' - 40: 1, # 'Ş' - 19: 1, # 'ş' - }, -} - -# 255: Undefined characters that did not exist in training text -# 254: Carriage/Return -# 253: symbol (punctuation) that does not belong to word -# 252: 0 - 9 -# 251: Control characters - -# Character Mapping Table(s): -ISO_8859_9_TURKISH_CHAR_TO_ORDER = { - 0: 255, # '\x00' - 1: 255, # '\x01' - 2: 255, # '\x02' - 3: 255, # '\x03' - 4: 255, # '\x04' - 5: 255, # '\x05' - 6: 255, # '\x06' - 7: 255, # '\x07' - 8: 255, # '\x08' - 9: 255, # '\t' - 10: 255, # '\n' - 11: 255, # '\x0b' - 12: 255, # '\x0c' - 13: 255, # '\r' - 14: 255, # '\x0e' - 15: 255, # '\x0f' - 16: 255, # '\x10' - 17: 255, # '\x11' - 18: 255, # '\x12' - 19: 255, # '\x13' - 20: 255, # '\x14' - 21: 255, # '\x15' - 22: 255, # '\x16' - 23: 255, # '\x17' - 24: 255, # '\x18' - 25: 255, # '\x19' - 26: 255, # '\x1a' - 27: 255, # '\x1b' - 28: 255, # '\x1c' - 29: 255, # '\x1d' - 30: 255, # '\x1e' - 31: 255, # '\x1f' - 32: 255, # ' ' - 33: 255, # '!' - 34: 255, # '"' - 35: 255, # '#' - 36: 255, # '$' - 37: 255, # '%' - 38: 255, # '&' - 39: 255, # "'" - 40: 255, # '(' - 41: 255, # ')' - 42: 255, # '*' - 43: 255, # '+' - 44: 255, # ',' - 45: 255, # '-' - 46: 255, # '.' - 47: 255, # '/' - 48: 255, # '0' - 49: 255, # '1' - 50: 255, # '2' - 51: 255, # '3' - 52: 255, # '4' - 53: 255, # '5' - 54: 255, # '6' - 55: 255, # '7' - 56: 255, # '8' - 57: 255, # '9' - 58: 255, # ':' - 59: 255, # ';' - 60: 255, # '<' - 61: 255, # '=' - 62: 255, # '>' - 63: 255, # '?' - 64: 255, # '@' - 65: 23, # 'A' - 66: 37, # 'B' - 67: 47, # 'C' - 68: 39, # 'D' - 69: 29, # 'E' - 70: 52, # 'F' - 71: 36, # 'G' - 72: 45, # 'H' - 73: 53, # 'I' - 74: 60, # 'J' - 75: 16, # 'K' - 76: 49, # 'L' - 77: 20, # 'M' - 78: 46, # 'N' - 79: 42, # 'O' - 80: 48, # 'P' - 81: 69, # 'Q' - 82: 44, # 'R' - 83: 35, # 'S' - 84: 31, # 'T' - 85: 51, # 'U' - 86: 38, # 'V' - 87: 62, # 'W' - 88: 65, # 'X' - 89: 43, # 'Y' - 90: 56, # 'Z' - 91: 255, # '[' - 92: 255, # '\\' - 93: 255, # ']' - 94: 255, # '^' - 95: 255, # '_' - 96: 255, # '`' - 97: 1, # 'a' - 98: 21, # 'b' - 99: 28, # 'c' - 100: 12, # 'd' - 101: 2, # 'e' - 102: 18, # 'f' - 103: 27, # 'g' - 104: 25, # 'h' - 105: 3, # 'i' - 106: 24, # 'j' - 107: 10, # 'k' - 108: 5, # 'l' - 109: 13, # 'm' - 110: 4, # 'n' - 111: 15, # 'o' - 112: 26, # 'p' - 113: 64, # 'q' - 114: 7, # 'r' - 115: 8, # 's' - 116: 9, # 't' - 117: 14, # 'u' - 118: 32, # 'v' - 119: 57, # 'w' - 120: 58, # 'x' - 121: 11, # 'y' - 122: 22, # 'z' - 123: 255, # '{' - 124: 255, # '|' - 125: 255, # '}' - 126: 255, # '~' - 127: 255, # '\x7f' - 128: 180, # '\x80' - 129: 179, # '\x81' - 130: 178, # '\x82' - 131: 177, # '\x83' - 132: 176, # '\x84' - 133: 175, # '\x85' - 134: 174, # '\x86' - 135: 173, # '\x87' - 136: 172, # '\x88' - 137: 171, # '\x89' - 138: 170, # '\x8a' - 139: 169, # '\x8b' - 140: 168, # '\x8c' - 141: 167, # '\x8d' - 142: 166, # '\x8e' - 143: 165, # '\x8f' - 144: 164, # '\x90' - 145: 163, # '\x91' - 146: 162, # '\x92' - 147: 161, # '\x93' - 148: 160, # '\x94' - 149: 159, # '\x95' - 150: 101, # '\x96' - 151: 158, # '\x97' - 152: 157, # '\x98' - 153: 156, # '\x99' - 154: 155, # '\x9a' - 155: 154, # '\x9b' - 156: 153, # '\x9c' - 157: 152, # '\x9d' - 158: 151, # '\x9e' - 159: 106, # '\x9f' - 160: 150, # '\xa0' - 161: 149, # '¡' - 162: 148, # '¢' - 163: 147, # '£' - 164: 146, # '¤' - 165: 145, # '¥' - 166: 144, # '¦' - 167: 100, # '§' - 168: 143, # '¨' - 169: 142, # '©' - 170: 141, # 'ª' - 171: 140, # '«' - 172: 139, # '¬' - 173: 138, # '\xad' - 174: 137, # '®' - 175: 136, # '¯' - 176: 94, # '°' - 177: 80, # '±' - 178: 93, # '²' - 179: 135, # '³' - 180: 105, # '´' - 181: 134, # 'µ' - 182: 133, # '¶' - 183: 63, # '·' - 184: 132, # '¸' - 185: 131, # '¹' - 186: 130, # 'º' - 187: 129, # '»' - 188: 128, # '¼' - 189: 127, # '½' - 190: 126, # '¾' - 191: 125, # '¿' - 192: 124, # 'À' - 193: 104, # 'Á' - 194: 73, # 'Â' - 195: 99, # 'Ã' - 196: 79, # 'Ä' - 197: 85, # 'Å' - 198: 123, # 'Æ' - 199: 54, # 'Ç' - 200: 122, # 'È' - 201: 98, # 'É' - 202: 92, # 'Ê' - 203: 121, # 'Ë' - 204: 120, # 'Ì' - 205: 91, # 'Í' - 206: 103, # 'Î' - 207: 119, # 'Ï' - 208: 68, # 'Ğ' - 209: 118, # 'Ñ' - 210: 117, # 'Ò' - 211: 97, # 'Ó' - 212: 116, # 'Ô' - 213: 115, # 'Õ' - 214: 50, # 'Ö' - 215: 90, # '×' - 216: 114, # 'Ø' - 217: 113, # 'Ù' - 218: 112, # 'Ú' - 219: 111, # 'Û' - 220: 55, # 'Ü' - 221: 41, # 'İ' - 222: 40, # 'Ş' - 223: 86, # 'ß' - 224: 89, # 'à' - 225: 70, # 'á' - 226: 59, # 'â' - 227: 78, # 'ã' - 228: 71, # 'ä' - 229: 82, # 'å' - 230: 88, # 'æ' - 231: 33, # 'ç' - 232: 77, # 'è' - 233: 66, # 'é' - 234: 84, # 'ê' - 235: 83, # 'ë' - 236: 110, # 'ì' - 237: 75, # 'í' - 238: 61, # 'î' - 239: 96, # 'ï' - 240: 30, # 'ğ' - 241: 67, # 'ñ' - 242: 109, # 'ò' - 243: 74, # 'ó' - 244: 87, # 'ô' - 245: 102, # 'õ' - 246: 34, # 'ö' - 247: 95, # '÷' - 248: 81, # 'ø' - 249: 108, # 'ù' - 250: 76, # 'ú' - 251: 72, # 'û' - 252: 17, # 'ü' - 253: 6, # 'ı' - 254: 19, # 'ş' - 255: 107, # 'ÿ' -} - -ISO_8859_9_TURKISH_MODEL = SingleByteCharSetModel(charset_name='ISO-8859-9', - language='Turkish', - char_to_order_map=ISO_8859_9_TURKISH_CHAR_TO_ORDER, - language_model=TURKISH_LANG_MODEL, - typical_positive_ratio=0.97029, - keep_ascii_letters=True, - alphabet='ABCDEFGHIJKLMNOPRSTUVYZabcdefghijklmnoprstuvyzÂÇÎÖÛÜâçîöûüĞğİıŞş') - diff --git a/venv/lib/python3.8/site-packages/chardet/latin1prober.py b/venv/lib/python3.8/site-packages/chardet/latin1prober.py deleted file mode 100644 index 7d1e8c2..0000000 --- a/venv/lib/python3.8/site-packages/chardet/latin1prober.py +++ /dev/null @@ -1,145 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is Mozilla Universal charset detector code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 2001 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# Shy Shalom - original C code -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -from .charsetprober import CharSetProber -from .enums import ProbingState - -FREQ_CAT_NUM = 4 - -UDF = 0 # undefined -OTH = 1 # other -ASC = 2 # ascii capital letter -ASS = 3 # ascii small letter -ACV = 4 # accent capital vowel -ACO = 5 # accent capital other -ASV = 6 # accent small vowel -ASO = 7 # accent small other -CLASS_NUM = 8 # total classes - -Latin1_CharToClass = ( - OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 00 - 07 - OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 08 - 0F - OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 10 - 17 - OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 18 - 1F - OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 20 - 27 - OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 28 - 2F - OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 30 - 37 - OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 38 - 3F - OTH, ASC, ASC, ASC, ASC, ASC, ASC, ASC, # 40 - 47 - ASC, ASC, ASC, ASC, ASC, ASC, ASC, ASC, # 48 - 4F - ASC, ASC, ASC, ASC, ASC, ASC, ASC, ASC, # 50 - 57 - ASC, ASC, ASC, OTH, OTH, OTH, OTH, OTH, # 58 - 5F - OTH, ASS, ASS, ASS, ASS, ASS, ASS, ASS, # 60 - 67 - ASS, ASS, ASS, ASS, ASS, ASS, ASS, ASS, # 68 - 6F - ASS, ASS, ASS, ASS, ASS, ASS, ASS, ASS, # 70 - 77 - ASS, ASS, ASS, OTH, OTH, OTH, OTH, OTH, # 78 - 7F - OTH, UDF, OTH, ASO, OTH, OTH, OTH, OTH, # 80 - 87 - OTH, OTH, ACO, OTH, ACO, UDF, ACO, UDF, # 88 - 8F - UDF, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # 90 - 97 - OTH, OTH, ASO, OTH, ASO, UDF, ASO, ACO, # 98 - 9F - OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # A0 - A7 - OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # A8 - AF - OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # B0 - B7 - OTH, OTH, OTH, OTH, OTH, OTH, OTH, OTH, # B8 - BF - ACV, ACV, ACV, ACV, ACV, ACV, ACO, ACO, # C0 - C7 - ACV, ACV, ACV, ACV, ACV, ACV, ACV, ACV, # C8 - CF - ACO, ACO, ACV, ACV, ACV, ACV, ACV, OTH, # D0 - D7 - ACV, ACV, ACV, ACV, ACV, ACO, ACO, ACO, # D8 - DF - ASV, ASV, ASV, ASV, ASV, ASV, ASO, ASO, # E0 - E7 - ASV, ASV, ASV, ASV, ASV, ASV, ASV, ASV, # E8 - EF - ASO, ASO, ASV, ASV, ASV, ASV, ASV, OTH, # F0 - F7 - ASV, ASV, ASV, ASV, ASV, ASO, ASO, ASO, # F8 - FF -) - -# 0 : illegal -# 1 : very unlikely -# 2 : normal -# 3 : very likely -Latin1ClassModel = ( -# UDF OTH ASC ASS ACV ACO ASV ASO - 0, 0, 0, 0, 0, 0, 0, 0, # UDF - 0, 3, 3, 3, 3, 3, 3, 3, # OTH - 0, 3, 3, 3, 3, 3, 3, 3, # ASC - 0, 3, 3, 3, 1, 1, 3, 3, # ASS - 0, 3, 3, 3, 1, 2, 1, 2, # ACV - 0, 3, 3, 3, 3, 3, 3, 3, # ACO - 0, 3, 1, 3, 1, 1, 1, 3, # ASV - 0, 3, 1, 3, 1, 1, 3, 3, # ASO -) - - -class Latin1Prober(CharSetProber): - def __init__(self): - super(Latin1Prober, self).__init__() - self._last_char_class = None - self._freq_counter = None - self.reset() - - def reset(self): - self._last_char_class = OTH - self._freq_counter = [0] * FREQ_CAT_NUM - CharSetProber.reset(self) - - @property - def charset_name(self): - return "ISO-8859-1" - - @property - def language(self): - return "" - - def feed(self, byte_str): - byte_str = self.filter_with_english_letters(byte_str) - for c in byte_str: - char_class = Latin1_CharToClass[c] - freq = Latin1ClassModel[(self._last_char_class * CLASS_NUM) - + char_class] - if freq == 0: - self._state = ProbingState.NOT_ME - break - self._freq_counter[freq] += 1 - self._last_char_class = char_class - - return self.state - - def get_confidence(self): - if self.state == ProbingState.NOT_ME: - return 0.01 - - total = sum(self._freq_counter) - if total < 0.01: - confidence = 0.0 - else: - confidence = ((self._freq_counter[3] - self._freq_counter[1] * 20.0) - / total) - if confidence < 0.0: - confidence = 0.0 - # lower the confidence of latin1 so that other more accurate - # detector can take priority. - confidence = confidence * 0.73 - return confidence diff --git a/venv/lib/python3.8/site-packages/chardet/mbcharsetprober.py b/venv/lib/python3.8/site-packages/chardet/mbcharsetprober.py deleted file mode 100644 index 6256ecf..0000000 --- a/venv/lib/python3.8/site-packages/chardet/mbcharsetprober.py +++ /dev/null @@ -1,91 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is Mozilla Universal charset detector code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 2001 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# Shy Shalom - original C code -# Proofpoint, Inc. -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -from .charsetprober import CharSetProber -from .enums import ProbingState, MachineState - - -class MultiByteCharSetProber(CharSetProber): - """ - MultiByteCharSetProber - """ - - def __init__(self, lang_filter=None): - super(MultiByteCharSetProber, self).__init__(lang_filter=lang_filter) - self.distribution_analyzer = None - self.coding_sm = None - self._last_char = [0, 0] - - def reset(self): - super(MultiByteCharSetProber, self).reset() - if self.coding_sm: - self.coding_sm.reset() - if self.distribution_analyzer: - self.distribution_analyzer.reset() - self._last_char = [0, 0] - - @property - def charset_name(self): - raise NotImplementedError - - @property - def language(self): - raise NotImplementedError - - def feed(self, byte_str): - for i in range(len(byte_str)): - coding_state = self.coding_sm.next_state(byte_str[i]) - if coding_state == MachineState.ERROR: - self.logger.debug('%s %s prober hit error at byte %s', - self.charset_name, self.language, i) - self._state = ProbingState.NOT_ME - break - elif coding_state == MachineState.ITS_ME: - self._state = ProbingState.FOUND_IT - break - elif coding_state == MachineState.START: - char_len = self.coding_sm.get_current_charlen() - if i == 0: - self._last_char[1] = byte_str[0] - self.distribution_analyzer.feed(self._last_char, char_len) - else: - self.distribution_analyzer.feed(byte_str[i - 1:i + 1], - char_len) - - self._last_char[0] = byte_str[-1] - - if self.state == ProbingState.DETECTING: - if (self.distribution_analyzer.got_enough_data() and - (self.get_confidence() > self.SHORTCUT_THRESHOLD)): - self._state = ProbingState.FOUND_IT - - return self.state - - def get_confidence(self): - return self.distribution_analyzer.get_confidence() diff --git a/venv/lib/python3.8/site-packages/chardet/mbcsgroupprober.py b/venv/lib/python3.8/site-packages/chardet/mbcsgroupprober.py deleted file mode 100644 index 530abe7..0000000 --- a/venv/lib/python3.8/site-packages/chardet/mbcsgroupprober.py +++ /dev/null @@ -1,54 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is Mozilla Universal charset detector code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 2001 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# Shy Shalom - original C code -# Proofpoint, Inc. -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -from .charsetgroupprober import CharSetGroupProber -from .utf8prober import UTF8Prober -from .sjisprober import SJISProber -from .eucjpprober import EUCJPProber -from .gb2312prober import GB2312Prober -from .euckrprober import EUCKRProber -from .cp949prober import CP949Prober -from .big5prober import Big5Prober -from .euctwprober import EUCTWProber - - -class MBCSGroupProber(CharSetGroupProber): - def __init__(self, lang_filter=None): - super(MBCSGroupProber, self).__init__(lang_filter=lang_filter) - self.probers = [ - UTF8Prober(), - SJISProber(), - EUCJPProber(), - GB2312Prober(), - EUCKRProber(), - CP949Prober(), - Big5Prober(), - EUCTWProber() - ] - self.reset() diff --git a/venv/lib/python3.8/site-packages/chardet/mbcssm.py b/venv/lib/python3.8/site-packages/chardet/mbcssm.py deleted file mode 100644 index 8360d0f..0000000 --- a/venv/lib/python3.8/site-packages/chardet/mbcssm.py +++ /dev/null @@ -1,572 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is mozilla.org code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -from .enums import MachineState - -# BIG5 - -BIG5_CLS = ( - 1,1,1,1,1,1,1,1, # 00 - 07 #allow 0x00 as legal value - 1,1,1,1,1,1,0,0, # 08 - 0f - 1,1,1,1,1,1,1,1, # 10 - 17 - 1,1,1,0,1,1,1,1, # 18 - 1f - 1,1,1,1,1,1,1,1, # 20 - 27 - 1,1,1,1,1,1,1,1, # 28 - 2f - 1,1,1,1,1,1,1,1, # 30 - 37 - 1,1,1,1,1,1,1,1, # 38 - 3f - 2,2,2,2,2,2,2,2, # 40 - 47 - 2,2,2,2,2,2,2,2, # 48 - 4f - 2,2,2,2,2,2,2,2, # 50 - 57 - 2,2,2,2,2,2,2,2, # 58 - 5f - 2,2,2,2,2,2,2,2, # 60 - 67 - 2,2,2,2,2,2,2,2, # 68 - 6f - 2,2,2,2,2,2,2,2, # 70 - 77 - 2,2,2,2,2,2,2,1, # 78 - 7f - 4,4,4,4,4,4,4,4, # 80 - 87 - 4,4,4,4,4,4,4,4, # 88 - 8f - 4,4,4,4,4,4,4,4, # 90 - 97 - 4,4,4,4,4,4,4,4, # 98 - 9f - 4,3,3,3,3,3,3,3, # a0 - a7 - 3,3,3,3,3,3,3,3, # a8 - af - 3,3,3,3,3,3,3,3, # b0 - b7 - 3,3,3,3,3,3,3,3, # b8 - bf - 3,3,3,3,3,3,3,3, # c0 - c7 - 3,3,3,3,3,3,3,3, # c8 - cf - 3,3,3,3,3,3,3,3, # d0 - d7 - 3,3,3,3,3,3,3,3, # d8 - df - 3,3,3,3,3,3,3,3, # e0 - e7 - 3,3,3,3,3,3,3,3, # e8 - ef - 3,3,3,3,3,3,3,3, # f0 - f7 - 3,3,3,3,3,3,3,0 # f8 - ff -) - -BIG5_ST = ( - MachineState.ERROR,MachineState.START,MachineState.START, 3,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#00-07 - MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,#08-0f - MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START#10-17 -) - -BIG5_CHAR_LEN_TABLE = (0, 1, 1, 2, 0) - -BIG5_SM_MODEL = {'class_table': BIG5_CLS, - 'class_factor': 5, - 'state_table': BIG5_ST, - 'char_len_table': BIG5_CHAR_LEN_TABLE, - 'name': 'Big5'} - -# CP949 - -CP949_CLS = ( - 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,0,0, # 00 - 0f - 1,1,1,1,1,1,1,1, 1,1,1,0,1,1,1,1, # 10 - 1f - 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, # 20 - 2f - 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, # 30 - 3f - 1,4,4,4,4,4,4,4, 4,4,4,4,4,4,4,4, # 40 - 4f - 4,4,5,5,5,5,5,5, 5,5,5,1,1,1,1,1, # 50 - 5f - 1,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5, # 60 - 6f - 5,5,5,5,5,5,5,5, 5,5,5,1,1,1,1,1, # 70 - 7f - 0,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6, # 80 - 8f - 6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6, # 90 - 9f - 6,7,7,7,7,7,7,7, 7,7,7,7,7,8,8,8, # a0 - af - 7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7, # b0 - bf - 7,7,7,7,7,7,9,2, 2,3,2,2,2,2,2,2, # c0 - cf - 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, # d0 - df - 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2, # e0 - ef - 2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,0, # f0 - ff -) - -CP949_ST = ( -#cls= 0 1 2 3 4 5 6 7 8 9 # previous state = - MachineState.ERROR,MachineState.START, 3,MachineState.ERROR,MachineState.START,MachineState.START, 4, 5,MachineState.ERROR, 6, # MachineState.START - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, # MachineState.ERROR - MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME, # MachineState.ITS_ME - MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START, # 3 - MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START, # 4 - MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START, # 5 - MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START, # 6 -) - -CP949_CHAR_LEN_TABLE = (0, 1, 2, 0, 1, 1, 2, 2, 0, 2) - -CP949_SM_MODEL = {'class_table': CP949_CLS, - 'class_factor': 10, - 'state_table': CP949_ST, - 'char_len_table': CP949_CHAR_LEN_TABLE, - 'name': 'CP949'} - -# EUC-JP - -EUCJP_CLS = ( - 4,4,4,4,4,4,4,4, # 00 - 07 - 4,4,4,4,4,4,5,5, # 08 - 0f - 4,4,4,4,4,4,4,4, # 10 - 17 - 4,4,4,5,4,4,4,4, # 18 - 1f - 4,4,4,4,4,4,4,4, # 20 - 27 - 4,4,4,4,4,4,4,4, # 28 - 2f - 4,4,4,4,4,4,4,4, # 30 - 37 - 4,4,4,4,4,4,4,4, # 38 - 3f - 4,4,4,4,4,4,4,4, # 40 - 47 - 4,4,4,4,4,4,4,4, # 48 - 4f - 4,4,4,4,4,4,4,4, # 50 - 57 - 4,4,4,4,4,4,4,4, # 58 - 5f - 4,4,4,4,4,4,4,4, # 60 - 67 - 4,4,4,4,4,4,4,4, # 68 - 6f - 4,4,4,4,4,4,4,4, # 70 - 77 - 4,4,4,4,4,4,4,4, # 78 - 7f - 5,5,5,5,5,5,5,5, # 80 - 87 - 5,5,5,5,5,5,1,3, # 88 - 8f - 5,5,5,5,5,5,5,5, # 90 - 97 - 5,5,5,5,5,5,5,5, # 98 - 9f - 5,2,2,2,2,2,2,2, # a0 - a7 - 2,2,2,2,2,2,2,2, # a8 - af - 2,2,2,2,2,2,2,2, # b0 - b7 - 2,2,2,2,2,2,2,2, # b8 - bf - 2,2,2,2,2,2,2,2, # c0 - c7 - 2,2,2,2,2,2,2,2, # c8 - cf - 2,2,2,2,2,2,2,2, # d0 - d7 - 2,2,2,2,2,2,2,2, # d8 - df - 0,0,0,0,0,0,0,0, # e0 - e7 - 0,0,0,0,0,0,0,0, # e8 - ef - 0,0,0,0,0,0,0,0, # f0 - f7 - 0,0,0,0,0,0,0,5 # f8 - ff -) - -EUCJP_ST = ( - 3, 4, 3, 5,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#00-07 - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f - MachineState.ITS_ME,MachineState.ITS_ME,MachineState.START,MachineState.ERROR,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#10-17 - MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 3,MachineState.ERROR,#18-1f - 3,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START#20-27 -) - -EUCJP_CHAR_LEN_TABLE = (2, 2, 2, 3, 1, 0) - -EUCJP_SM_MODEL = {'class_table': EUCJP_CLS, - 'class_factor': 6, - 'state_table': EUCJP_ST, - 'char_len_table': EUCJP_CHAR_LEN_TABLE, - 'name': 'EUC-JP'} - -# EUC-KR - -EUCKR_CLS = ( - 1,1,1,1,1,1,1,1, # 00 - 07 - 1,1,1,1,1,1,0,0, # 08 - 0f - 1,1,1,1,1,1,1,1, # 10 - 17 - 1,1,1,0,1,1,1,1, # 18 - 1f - 1,1,1,1,1,1,1,1, # 20 - 27 - 1,1,1,1,1,1,1,1, # 28 - 2f - 1,1,1,1,1,1,1,1, # 30 - 37 - 1,1,1,1,1,1,1,1, # 38 - 3f - 1,1,1,1,1,1,1,1, # 40 - 47 - 1,1,1,1,1,1,1,1, # 48 - 4f - 1,1,1,1,1,1,1,1, # 50 - 57 - 1,1,1,1,1,1,1,1, # 58 - 5f - 1,1,1,1,1,1,1,1, # 60 - 67 - 1,1,1,1,1,1,1,1, # 68 - 6f - 1,1,1,1,1,1,1,1, # 70 - 77 - 1,1,1,1,1,1,1,1, # 78 - 7f - 0,0,0,0,0,0,0,0, # 80 - 87 - 0,0,0,0,0,0,0,0, # 88 - 8f - 0,0,0,0,0,0,0,0, # 90 - 97 - 0,0,0,0,0,0,0,0, # 98 - 9f - 0,2,2,2,2,2,2,2, # a0 - a7 - 2,2,2,2,2,3,3,3, # a8 - af - 2,2,2,2,2,2,2,2, # b0 - b7 - 2,2,2,2,2,2,2,2, # b8 - bf - 2,2,2,2,2,2,2,2, # c0 - c7 - 2,3,2,2,2,2,2,2, # c8 - cf - 2,2,2,2,2,2,2,2, # d0 - d7 - 2,2,2,2,2,2,2,2, # d8 - df - 2,2,2,2,2,2,2,2, # e0 - e7 - 2,2,2,2,2,2,2,2, # e8 - ef - 2,2,2,2,2,2,2,2, # f0 - f7 - 2,2,2,2,2,2,2,0 # f8 - ff -) - -EUCKR_ST = ( - MachineState.ERROR,MachineState.START, 3,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#00-07 - MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START #08-0f -) - -EUCKR_CHAR_LEN_TABLE = (0, 1, 2, 0) - -EUCKR_SM_MODEL = {'class_table': EUCKR_CLS, - 'class_factor': 4, - 'state_table': EUCKR_ST, - 'char_len_table': EUCKR_CHAR_LEN_TABLE, - 'name': 'EUC-KR'} - -# EUC-TW - -EUCTW_CLS = ( - 2,2,2,2,2,2,2,2, # 00 - 07 - 2,2,2,2,2,2,0,0, # 08 - 0f - 2,2,2,2,2,2,2,2, # 10 - 17 - 2,2,2,0,2,2,2,2, # 18 - 1f - 2,2,2,2,2,2,2,2, # 20 - 27 - 2,2,2,2,2,2,2,2, # 28 - 2f - 2,2,2,2,2,2,2,2, # 30 - 37 - 2,2,2,2,2,2,2,2, # 38 - 3f - 2,2,2,2,2,2,2,2, # 40 - 47 - 2,2,2,2,2,2,2,2, # 48 - 4f - 2,2,2,2,2,2,2,2, # 50 - 57 - 2,2,2,2,2,2,2,2, # 58 - 5f - 2,2,2,2,2,2,2,2, # 60 - 67 - 2,2,2,2,2,2,2,2, # 68 - 6f - 2,2,2,2,2,2,2,2, # 70 - 77 - 2,2,2,2,2,2,2,2, # 78 - 7f - 0,0,0,0,0,0,0,0, # 80 - 87 - 0,0,0,0,0,0,6,0, # 88 - 8f - 0,0,0,0,0,0,0,0, # 90 - 97 - 0,0,0,0,0,0,0,0, # 98 - 9f - 0,3,4,4,4,4,4,4, # a0 - a7 - 5,5,1,1,1,1,1,1, # a8 - af - 1,1,1,1,1,1,1,1, # b0 - b7 - 1,1,1,1,1,1,1,1, # b8 - bf - 1,1,3,1,3,3,3,3, # c0 - c7 - 3,3,3,3,3,3,3,3, # c8 - cf - 3,3,3,3,3,3,3,3, # d0 - d7 - 3,3,3,3,3,3,3,3, # d8 - df - 3,3,3,3,3,3,3,3, # e0 - e7 - 3,3,3,3,3,3,3,3, # e8 - ef - 3,3,3,3,3,3,3,3, # f0 - f7 - 3,3,3,3,3,3,3,0 # f8 - ff -) - -EUCTW_ST = ( - MachineState.ERROR,MachineState.ERROR,MachineState.START, 3, 3, 3, 4,MachineState.ERROR,#00-07 - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f - MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.START,MachineState.ERROR,#10-17 - MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#18-1f - 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.ERROR,MachineState.START,MachineState.START,#20-27 - MachineState.START,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START #28-2f -) - -EUCTW_CHAR_LEN_TABLE = (0, 0, 1, 2, 2, 2, 3) - -EUCTW_SM_MODEL = {'class_table': EUCTW_CLS, - 'class_factor': 7, - 'state_table': EUCTW_ST, - 'char_len_table': EUCTW_CHAR_LEN_TABLE, - 'name': 'x-euc-tw'} - -# GB2312 - -GB2312_CLS = ( - 1,1,1,1,1,1,1,1, # 00 - 07 - 1,1,1,1,1,1,0,0, # 08 - 0f - 1,1,1,1,1,1,1,1, # 10 - 17 - 1,1,1,0,1,1,1,1, # 18 - 1f - 1,1,1,1,1,1,1,1, # 20 - 27 - 1,1,1,1,1,1,1,1, # 28 - 2f - 3,3,3,3,3,3,3,3, # 30 - 37 - 3,3,1,1,1,1,1,1, # 38 - 3f - 2,2,2,2,2,2,2,2, # 40 - 47 - 2,2,2,2,2,2,2,2, # 48 - 4f - 2,2,2,2,2,2,2,2, # 50 - 57 - 2,2,2,2,2,2,2,2, # 58 - 5f - 2,2,2,2,2,2,2,2, # 60 - 67 - 2,2,2,2,2,2,2,2, # 68 - 6f - 2,2,2,2,2,2,2,2, # 70 - 77 - 2,2,2,2,2,2,2,4, # 78 - 7f - 5,6,6,6,6,6,6,6, # 80 - 87 - 6,6,6,6,6,6,6,6, # 88 - 8f - 6,6,6,6,6,6,6,6, # 90 - 97 - 6,6,6,6,6,6,6,6, # 98 - 9f - 6,6,6,6,6,6,6,6, # a0 - a7 - 6,6,6,6,6,6,6,6, # a8 - af - 6,6,6,6,6,6,6,6, # b0 - b7 - 6,6,6,6,6,6,6,6, # b8 - bf - 6,6,6,6,6,6,6,6, # c0 - c7 - 6,6,6,6,6,6,6,6, # c8 - cf - 6,6,6,6,6,6,6,6, # d0 - d7 - 6,6,6,6,6,6,6,6, # d8 - df - 6,6,6,6,6,6,6,6, # e0 - e7 - 6,6,6,6,6,6,6,6, # e8 - ef - 6,6,6,6,6,6,6,6, # f0 - f7 - 6,6,6,6,6,6,6,0 # f8 - ff -) - -GB2312_ST = ( - MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START, 3,MachineState.ERROR,#00-07 - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f - MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.START,#10-17 - 4,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#18-1f - MachineState.ERROR,MachineState.ERROR, 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,#20-27 - MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.START #28-2f -) - -# To be accurate, the length of class 6 can be either 2 or 4. -# But it is not necessary to discriminate between the two since -# it is used for frequency analysis only, and we are validating -# each code range there as well. So it is safe to set it to be -# 2 here. -GB2312_CHAR_LEN_TABLE = (0, 1, 1, 1, 1, 1, 2) - -GB2312_SM_MODEL = {'class_table': GB2312_CLS, - 'class_factor': 7, - 'state_table': GB2312_ST, - 'char_len_table': GB2312_CHAR_LEN_TABLE, - 'name': 'GB2312'} - -# Shift_JIS - -SJIS_CLS = ( - 1,1,1,1,1,1,1,1, # 00 - 07 - 1,1,1,1,1,1,0,0, # 08 - 0f - 1,1,1,1,1,1,1,1, # 10 - 17 - 1,1,1,0,1,1,1,1, # 18 - 1f - 1,1,1,1,1,1,1,1, # 20 - 27 - 1,1,1,1,1,1,1,1, # 28 - 2f - 1,1,1,1,1,1,1,1, # 30 - 37 - 1,1,1,1,1,1,1,1, # 38 - 3f - 2,2,2,2,2,2,2,2, # 40 - 47 - 2,2,2,2,2,2,2,2, # 48 - 4f - 2,2,2,2,2,2,2,2, # 50 - 57 - 2,2,2,2,2,2,2,2, # 58 - 5f - 2,2,2,2,2,2,2,2, # 60 - 67 - 2,2,2,2,2,2,2,2, # 68 - 6f - 2,2,2,2,2,2,2,2, # 70 - 77 - 2,2,2,2,2,2,2,1, # 78 - 7f - 3,3,3,3,3,2,2,3, # 80 - 87 - 3,3,3,3,3,3,3,3, # 88 - 8f - 3,3,3,3,3,3,3,3, # 90 - 97 - 3,3,3,3,3,3,3,3, # 98 - 9f - #0xa0 is illegal in sjis encoding, but some pages does - #contain such byte. We need to be more error forgiven. - 2,2,2,2,2,2,2,2, # a0 - a7 - 2,2,2,2,2,2,2,2, # a8 - af - 2,2,2,2,2,2,2,2, # b0 - b7 - 2,2,2,2,2,2,2,2, # b8 - bf - 2,2,2,2,2,2,2,2, # c0 - c7 - 2,2,2,2,2,2,2,2, # c8 - cf - 2,2,2,2,2,2,2,2, # d0 - d7 - 2,2,2,2,2,2,2,2, # d8 - df - 3,3,3,3,3,3,3,3, # e0 - e7 - 3,3,3,3,3,4,4,4, # e8 - ef - 3,3,3,3,3,3,3,3, # f0 - f7 - 3,3,3,3,3,0,0,0) # f8 - ff - - -SJIS_ST = ( - MachineState.ERROR,MachineState.START,MachineState.START, 3,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#00-07 - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f - MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START #10-17 -) - -SJIS_CHAR_LEN_TABLE = (0, 1, 1, 2, 0, 0) - -SJIS_SM_MODEL = {'class_table': SJIS_CLS, - 'class_factor': 6, - 'state_table': SJIS_ST, - 'char_len_table': SJIS_CHAR_LEN_TABLE, - 'name': 'Shift_JIS'} - -# UCS2-BE - -UCS2BE_CLS = ( - 0,0,0,0,0,0,0,0, # 00 - 07 - 0,0,1,0,0,2,0,0, # 08 - 0f - 0,0,0,0,0,0,0,0, # 10 - 17 - 0,0,0,3,0,0,0,0, # 18 - 1f - 0,0,0,0,0,0,0,0, # 20 - 27 - 0,3,3,3,3,3,0,0, # 28 - 2f - 0,0,0,0,0,0,0,0, # 30 - 37 - 0,0,0,0,0,0,0,0, # 38 - 3f - 0,0,0,0,0,0,0,0, # 40 - 47 - 0,0,0,0,0,0,0,0, # 48 - 4f - 0,0,0,0,0,0,0,0, # 50 - 57 - 0,0,0,0,0,0,0,0, # 58 - 5f - 0,0,0,0,0,0,0,0, # 60 - 67 - 0,0,0,0,0,0,0,0, # 68 - 6f - 0,0,0,0,0,0,0,0, # 70 - 77 - 0,0,0,0,0,0,0,0, # 78 - 7f - 0,0,0,0,0,0,0,0, # 80 - 87 - 0,0,0,0,0,0,0,0, # 88 - 8f - 0,0,0,0,0,0,0,0, # 90 - 97 - 0,0,0,0,0,0,0,0, # 98 - 9f - 0,0,0,0,0,0,0,0, # a0 - a7 - 0,0,0,0,0,0,0,0, # a8 - af - 0,0,0,0,0,0,0,0, # b0 - b7 - 0,0,0,0,0,0,0,0, # b8 - bf - 0,0,0,0,0,0,0,0, # c0 - c7 - 0,0,0,0,0,0,0,0, # c8 - cf - 0,0,0,0,0,0,0,0, # d0 - d7 - 0,0,0,0,0,0,0,0, # d8 - df - 0,0,0,0,0,0,0,0, # e0 - e7 - 0,0,0,0,0,0,0,0, # e8 - ef - 0,0,0,0,0,0,0,0, # f0 - f7 - 0,0,0,0,0,0,4,5 # f8 - ff -) - -UCS2BE_ST = ( - 5, 7, 7,MachineState.ERROR, 4, 3,MachineState.ERROR,MachineState.ERROR,#00-07 - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f - MachineState.ITS_ME,MachineState.ITS_ME, 6, 6, 6, 6,MachineState.ERROR,MachineState.ERROR,#10-17 - 6, 6, 6, 6, 6,MachineState.ITS_ME, 6, 6,#18-1f - 6, 6, 6, 6, 5, 7, 7,MachineState.ERROR,#20-27 - 5, 8, 6, 6,MachineState.ERROR, 6, 6, 6,#28-2f - 6, 6, 6, 6,MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START #30-37 -) - -UCS2BE_CHAR_LEN_TABLE = (2, 2, 2, 0, 2, 2) - -UCS2BE_SM_MODEL = {'class_table': UCS2BE_CLS, - 'class_factor': 6, - 'state_table': UCS2BE_ST, - 'char_len_table': UCS2BE_CHAR_LEN_TABLE, - 'name': 'UTF-16BE'} - -# UCS2-LE - -UCS2LE_CLS = ( - 0,0,0,0,0,0,0,0, # 00 - 07 - 0,0,1,0,0,2,0,0, # 08 - 0f - 0,0,0,0,0,0,0,0, # 10 - 17 - 0,0,0,3,0,0,0,0, # 18 - 1f - 0,0,0,0,0,0,0,0, # 20 - 27 - 0,3,3,3,3,3,0,0, # 28 - 2f - 0,0,0,0,0,0,0,0, # 30 - 37 - 0,0,0,0,0,0,0,0, # 38 - 3f - 0,0,0,0,0,0,0,0, # 40 - 47 - 0,0,0,0,0,0,0,0, # 48 - 4f - 0,0,0,0,0,0,0,0, # 50 - 57 - 0,0,0,0,0,0,0,0, # 58 - 5f - 0,0,0,0,0,0,0,0, # 60 - 67 - 0,0,0,0,0,0,0,0, # 68 - 6f - 0,0,0,0,0,0,0,0, # 70 - 77 - 0,0,0,0,0,0,0,0, # 78 - 7f - 0,0,0,0,0,0,0,0, # 80 - 87 - 0,0,0,0,0,0,0,0, # 88 - 8f - 0,0,0,0,0,0,0,0, # 90 - 97 - 0,0,0,0,0,0,0,0, # 98 - 9f - 0,0,0,0,0,0,0,0, # a0 - a7 - 0,0,0,0,0,0,0,0, # a8 - af - 0,0,0,0,0,0,0,0, # b0 - b7 - 0,0,0,0,0,0,0,0, # b8 - bf - 0,0,0,0,0,0,0,0, # c0 - c7 - 0,0,0,0,0,0,0,0, # c8 - cf - 0,0,0,0,0,0,0,0, # d0 - d7 - 0,0,0,0,0,0,0,0, # d8 - df - 0,0,0,0,0,0,0,0, # e0 - e7 - 0,0,0,0,0,0,0,0, # e8 - ef - 0,0,0,0,0,0,0,0, # f0 - f7 - 0,0,0,0,0,0,4,5 # f8 - ff -) - -UCS2LE_ST = ( - 6, 6, 7, 6, 4, 3,MachineState.ERROR,MachineState.ERROR,#00-07 - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#08-0f - MachineState.ITS_ME,MachineState.ITS_ME, 5, 5, 5,MachineState.ERROR,MachineState.ITS_ME,MachineState.ERROR,#10-17 - 5, 5, 5,MachineState.ERROR, 5,MachineState.ERROR, 6, 6,#18-1f - 7, 6, 8, 8, 5, 5, 5,MachineState.ERROR,#20-27 - 5, 5, 5,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 5, 5,#28-2f - 5, 5, 5,MachineState.ERROR, 5,MachineState.ERROR,MachineState.START,MachineState.START #30-37 -) - -UCS2LE_CHAR_LEN_TABLE = (2, 2, 2, 2, 2, 2) - -UCS2LE_SM_MODEL = {'class_table': UCS2LE_CLS, - 'class_factor': 6, - 'state_table': UCS2LE_ST, - 'char_len_table': UCS2LE_CHAR_LEN_TABLE, - 'name': 'UTF-16LE'} - -# UTF-8 - -UTF8_CLS = ( - 1,1,1,1,1,1,1,1, # 00 - 07 #allow 0x00 as a legal value - 1,1,1,1,1,1,0,0, # 08 - 0f - 1,1,1,1,1,1,1,1, # 10 - 17 - 1,1,1,0,1,1,1,1, # 18 - 1f - 1,1,1,1,1,1,1,1, # 20 - 27 - 1,1,1,1,1,1,1,1, # 28 - 2f - 1,1,1,1,1,1,1,1, # 30 - 37 - 1,1,1,1,1,1,1,1, # 38 - 3f - 1,1,1,1,1,1,1,1, # 40 - 47 - 1,1,1,1,1,1,1,1, # 48 - 4f - 1,1,1,1,1,1,1,1, # 50 - 57 - 1,1,1,1,1,1,1,1, # 58 - 5f - 1,1,1,1,1,1,1,1, # 60 - 67 - 1,1,1,1,1,1,1,1, # 68 - 6f - 1,1,1,1,1,1,1,1, # 70 - 77 - 1,1,1,1,1,1,1,1, # 78 - 7f - 2,2,2,2,3,3,3,3, # 80 - 87 - 4,4,4,4,4,4,4,4, # 88 - 8f - 4,4,4,4,4,4,4,4, # 90 - 97 - 4,4,4,4,4,4,4,4, # 98 - 9f - 5,5,5,5,5,5,5,5, # a0 - a7 - 5,5,5,5,5,5,5,5, # a8 - af - 5,5,5,5,5,5,5,5, # b0 - b7 - 5,5,5,5,5,5,5,5, # b8 - bf - 0,0,6,6,6,6,6,6, # c0 - c7 - 6,6,6,6,6,6,6,6, # c8 - cf - 6,6,6,6,6,6,6,6, # d0 - d7 - 6,6,6,6,6,6,6,6, # d8 - df - 7,8,8,8,8,8,8,8, # e0 - e7 - 8,8,8,8,8,9,8,8, # e8 - ef - 10,11,11,11,11,11,11,11, # f0 - f7 - 12,13,13,13,14,15,0,0 # f8 - ff -) - -UTF8_ST = ( - MachineState.ERROR,MachineState.START,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 12, 10,#00-07 - 9, 11, 8, 7, 6, 5, 4, 3,#08-0f - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#10-17 - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#18-1f - MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#20-27 - MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,MachineState.ITS_ME,#28-2f - MachineState.ERROR,MachineState.ERROR, 5, 5, 5, 5,MachineState.ERROR,MachineState.ERROR,#30-37 - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#38-3f - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 5, 5, 5,MachineState.ERROR,MachineState.ERROR,#40-47 - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#48-4f - MachineState.ERROR,MachineState.ERROR, 7, 7, 7, 7,MachineState.ERROR,MachineState.ERROR,#50-57 - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#58-5f - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 7, 7,MachineState.ERROR,MachineState.ERROR,#60-67 - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#68-6f - MachineState.ERROR,MachineState.ERROR, 9, 9, 9, 9,MachineState.ERROR,MachineState.ERROR,#70-77 - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#78-7f - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 9,MachineState.ERROR,MachineState.ERROR,#80-87 - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#88-8f - MachineState.ERROR,MachineState.ERROR, 12, 12, 12, 12,MachineState.ERROR,MachineState.ERROR,#90-97 - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#98-9f - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR, 12,MachineState.ERROR,MachineState.ERROR,#a0-a7 - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#a8-af - MachineState.ERROR,MachineState.ERROR, 12, 12, 12,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#b0-b7 - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,#b8-bf - MachineState.ERROR,MachineState.ERROR,MachineState.START,MachineState.START,MachineState.START,MachineState.START,MachineState.ERROR,MachineState.ERROR,#c0-c7 - MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR,MachineState.ERROR #c8-cf -) - -UTF8_CHAR_LEN_TABLE = (0, 1, 0, 0, 0, 0, 2, 3, 3, 3, 4, 4, 5, 5, 6, 6) - -UTF8_SM_MODEL = {'class_table': UTF8_CLS, - 'class_factor': 16, - 'state_table': UTF8_ST, - 'char_len_table': UTF8_CHAR_LEN_TABLE, - 'name': 'UTF-8'} diff --git a/venv/lib/python3.8/site-packages/chardet/metadata/__init__.py b/venv/lib/python3.8/site-packages/chardet/metadata/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.8/site-packages/chardet/metadata/languages.py b/venv/lib/python3.8/site-packages/chardet/metadata/languages.py deleted file mode 100644 index 3237d5a..0000000 --- a/venv/lib/python3.8/site-packages/chardet/metadata/languages.py +++ /dev/null @@ -1,310 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" -Metadata about languages used by our model training code for our -SingleByteCharSetProbers. Could be used for other things in the future. - -This code is based on the language metadata from the uchardet project. -""" -from __future__ import absolute_import, print_function - -from string import ascii_letters - - -# TODO: Add Ukranian (KOI8-U) - -class Language(object): - """Metadata about a language useful for training models - - :ivar name: The human name for the language, in English. - :type name: str - :ivar iso_code: 2-letter ISO 639-1 if possible, 3-letter ISO code otherwise, - or use another catalog as a last resort. - :type iso_code: str - :ivar use_ascii: Whether or not ASCII letters should be included in trained - models. - :type use_ascii: bool - :ivar charsets: The charsets we want to support and create data for. - :type charsets: list of str - :ivar alphabet: The characters in the language's alphabet. If `use_ascii` is - `True`, you only need to add those not in the ASCII set. - :type alphabet: str - :ivar wiki_start_pages: The Wikipedia pages to start from if we're crawling - Wikipedia for training data. - :type wiki_start_pages: list of str - """ - def __init__(self, name=None, iso_code=None, use_ascii=True, charsets=None, - alphabet=None, wiki_start_pages=None): - super(Language, self).__init__() - self.name = name - self.iso_code = iso_code - self.use_ascii = use_ascii - self.charsets = charsets - if self.use_ascii: - if alphabet: - alphabet += ascii_letters - else: - alphabet = ascii_letters - elif not alphabet: - raise ValueError('Must supply alphabet if use_ascii is False') - self.alphabet = ''.join(sorted(set(alphabet))) if alphabet else None - self.wiki_start_pages = wiki_start_pages - - def __repr__(self): - return '{}({})'.format(self.__class__.__name__, - ', '.join('{}={!r}'.format(k, v) - for k, v in self.__dict__.items() - if not k.startswith('_'))) - - -LANGUAGES = {'Arabic': Language(name='Arabic', - iso_code='ar', - use_ascii=False, - # We only support encodings that use isolated - # forms, because the current recommendation is - # that the rendering system handles presentation - # forms. This means we purposefully skip IBM864. - charsets=['ISO-8859-6', 'WINDOWS-1256', - 'CP720', 'CP864'], - alphabet=u'ءآأؤإئابةتثجحخدذرزسشصضطظعغػؼؽؾؿـفقكلمنهوىيًٌٍَُِّ', - wiki_start_pages=[u'الصفحة_الرئيسية']), - 'Belarusian': Language(name='Belarusian', - iso_code='be', - use_ascii=False, - charsets=['ISO-8859-5', 'WINDOWS-1251', - 'IBM866', 'MacCyrillic'], - alphabet=(u'АБВГДЕЁЖЗІЙКЛМНОПРСТУЎФХЦЧШЫЬЭЮЯ' - u'абвгдеёжзійклмнопрстуўфхцчшыьэюяʼ'), - wiki_start_pages=[u'Галоўная_старонка']), - 'Bulgarian': Language(name='Bulgarian', - iso_code='bg', - use_ascii=False, - charsets=['ISO-8859-5', 'WINDOWS-1251', - 'IBM855'], - alphabet=(u'АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЬЮЯ' - u'абвгдежзийклмнопрстуфхцчшщъьюя'), - wiki_start_pages=[u'Начална_страница']), - 'Czech': Language(name='Czech', - iso_code='cz', - use_ascii=True, - charsets=['ISO-8859-2', 'WINDOWS-1250'], - alphabet=u'áčďéěíňóřšťúůýžÁČĎÉĚÍŇÓŘŠŤÚŮÝŽ', - wiki_start_pages=[u'Hlavní_strana']), - 'Danish': Language(name='Danish', - iso_code='da', - use_ascii=True, - charsets=['ISO-8859-1', 'ISO-8859-15', - 'WINDOWS-1252'], - alphabet=u'æøåÆØÅ', - wiki_start_pages=[u'Forside']), - 'German': Language(name='German', - iso_code='de', - use_ascii=True, - charsets=['ISO-8859-1', 'WINDOWS-1252'], - alphabet=u'äöüßÄÖÜ', - wiki_start_pages=[u'Wikipedia:Hauptseite']), - 'Greek': Language(name='Greek', - iso_code='el', - use_ascii=False, - charsets=['ISO-8859-7', 'WINDOWS-1253'], - alphabet=(u'αβγδεζηθικλμνξοπρσςτυφχψωάέήίόύώ' - u'ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΣΤΥΦΧΨΩΆΈΉΊΌΎΏ'), - wiki_start_pages=[u'Πύλη:Κύρια']), - 'English': Language(name='English', - iso_code='en', - use_ascii=True, - charsets=['ISO-8859-1', 'WINDOWS-1252'], - wiki_start_pages=[u'Main_Page']), - 'Esperanto': Language(name='Esperanto', - iso_code='eo', - # Q, W, X, and Y not used at all - use_ascii=False, - charsets=['ISO-8859-3'], - alphabet=(u'abcĉdefgĝhĥijĵklmnoprsŝtuŭvz' - u'ABCĈDEFGĜHĤIJĴKLMNOPRSŜTUŬVZ'), - wiki_start_pages=[u'Vikipedio:Ĉefpaĝo']), - 'Spanish': Language(name='Spanish', - iso_code='es', - use_ascii=True, - charsets=['ISO-8859-1', 'ISO-8859-15', - 'WINDOWS-1252'], - alphabet=u'ñáéíóúüÑÁÉÍÓÚÜ', - wiki_start_pages=[u'Wikipedia:Portada']), - 'Estonian': Language(name='Estonian', - iso_code='et', - use_ascii=False, - charsets=['ISO-8859-4', 'ISO-8859-13', - 'WINDOWS-1257'], - # C, F, Š, Q, W, X, Y, Z, Ž are only for - # loanwords - alphabet=(u'ABDEGHIJKLMNOPRSTUVÕÄÖÜ' - u'abdeghijklmnoprstuvõäöü'), - wiki_start_pages=[u'Esileht']), - 'Finnish': Language(name='Finnish', - iso_code='fi', - use_ascii=True, - charsets=['ISO-8859-1', 'ISO-8859-15', - 'WINDOWS-1252'], - alphabet=u'ÅÄÖŠŽåäöšž', - wiki_start_pages=[u'Wikipedia:Etusivu']), - 'French': Language(name='French', - iso_code='fr', - use_ascii=True, - charsets=['ISO-8859-1', 'ISO-8859-15', - 'WINDOWS-1252'], - alphabet=u'œàâçèéîïùûêŒÀÂÇÈÉÎÏÙÛÊ', - wiki_start_pages=[u'Wikipédia:Accueil_principal', - u'Bœuf (animal)']), - 'Hebrew': Language(name='Hebrew', - iso_code='he', - use_ascii=False, - charsets=['ISO-8859-8', 'WINDOWS-1255'], - alphabet=u'אבגדהוזחטיךכלםמןנסעףפץצקרשתװױײ', - wiki_start_pages=[u'עמוד_ראשי']), - 'Croatian': Language(name='Croatian', - iso_code='hr', - # Q, W, X, Y are only used for foreign words. - use_ascii=False, - charsets=['ISO-8859-2', 'WINDOWS-1250'], - alphabet=(u'abcčćdđefghijklmnoprsštuvzž' - u'ABCČĆDĐEFGHIJKLMNOPRSŠTUVZŽ'), - wiki_start_pages=[u'Glavna_stranica']), - 'Hungarian': Language(name='Hungarian', - iso_code='hu', - # Q, W, X, Y are only used for foreign words. - use_ascii=False, - charsets=['ISO-8859-2', 'WINDOWS-1250'], - alphabet=(u'abcdefghijklmnoprstuvzáéíóöőúüű' - u'ABCDEFGHIJKLMNOPRSTUVZÁÉÍÓÖŐÚÜŰ'), - wiki_start_pages=[u'Kezdőlap']), - 'Italian': Language(name='Italian', - iso_code='it', - use_ascii=True, - charsets=['ISO-8859-1', 'ISO-8859-15', - 'WINDOWS-1252'], - alphabet=u'ÀÈÉÌÒÓÙàèéìòóù', - wiki_start_pages=[u'Pagina_principale']), - 'Lithuanian': Language(name='Lithuanian', - iso_code='lt', - use_ascii=False, - charsets=['ISO-8859-13', 'WINDOWS-1257', - 'ISO-8859-4'], - # Q, W, and X not used at all - alphabet=(u'AĄBCČDEĘĖFGHIĮYJKLMNOPRSŠTUŲŪVZŽ' - u'aąbcčdeęėfghiįyjklmnoprsštuųūvzž'), - wiki_start_pages=[u'Pagrindinis_puslapis']), - 'Latvian': Language(name='Latvian', - iso_code='lv', - use_ascii=False, - charsets=['ISO-8859-13', 'WINDOWS-1257', - 'ISO-8859-4'], - # Q, W, X, Y are only for loanwords - alphabet=(u'AĀBCČDEĒFGĢHIĪJKĶLĻMNŅOPRSŠTUŪVZŽ' - u'aābcčdeēfgģhiījkķlļmnņoprsštuūvzž'), - wiki_start_pages=[u'Sākumlapa']), - 'Macedonian': Language(name='Macedonian', - iso_code='mk', - use_ascii=False, - charsets=['ISO-8859-5', 'WINDOWS-1251', - 'MacCyrillic', 'IBM855'], - alphabet=(u'АБВГДЃЕЖЗЅИЈКЛЉМНЊОПРСТЌУФХЦЧЏШ' - u'абвгдѓежзѕијклљмнњопрстќуфхцчџш'), - wiki_start_pages=[u'Главна_страница']), - 'Dutch': Language(name='Dutch', - iso_code='nl', - use_ascii=True, - charsets=['ISO-8859-1', 'WINDOWS-1252'], - wiki_start_pages=[u'Hoofdpagina']), - 'Polish': Language(name='Polish', - iso_code='pl', - # Q and X are only used for foreign words. - use_ascii=False, - charsets=['ISO-8859-2', 'WINDOWS-1250'], - alphabet=(u'AĄBCĆDEĘFGHIJKLŁMNŃOÓPRSŚTUWYZŹŻ' - u'aąbcćdeęfghijklłmnńoóprsśtuwyzźż'), - wiki_start_pages=[u'Wikipedia:Strona_główna']), - 'Portuguese': Language(name='Portuguese', - iso_code='pt', - use_ascii=True, - charsets=['ISO-8859-1', 'ISO-8859-15', - 'WINDOWS-1252'], - alphabet=u'ÁÂÃÀÇÉÊÍÓÔÕÚáâãàçéêíóôõú', - wiki_start_pages=[u'Wikipédia:Página_principal']), - 'Romanian': Language(name='Romanian', - iso_code='ro', - use_ascii=True, - charsets=['ISO-8859-2', 'WINDOWS-1250'], - alphabet=u'ăâîșțĂÂÎȘȚ', - wiki_start_pages=[u'Pagina_principală']), - 'Russian': Language(name='Russian', - iso_code='ru', - use_ascii=False, - charsets=['ISO-8859-5', 'WINDOWS-1251', - 'KOI8-R', 'MacCyrillic', 'IBM866', - 'IBM855'], - alphabet=(u'абвгдеёжзийклмнопрстуфхцчшщъыьэюя' - u'АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ'), - wiki_start_pages=[u'Заглавная_страница']), - 'Slovak': Language(name='Slovak', - iso_code='sk', - use_ascii=True, - charsets=['ISO-8859-2', 'WINDOWS-1250'], - alphabet=u'áäčďéíĺľňóôŕšťúýžÁÄČĎÉÍĹĽŇÓÔŔŠŤÚÝŽ', - wiki_start_pages=[u'Hlavná_stránka']), - 'Slovene': Language(name='Slovene', - iso_code='sl', - # Q, W, X, Y are only used for foreign words. - use_ascii=False, - charsets=['ISO-8859-2', 'WINDOWS-1250'], - alphabet=(u'abcčdefghijklmnoprsštuvzž' - u'ABCČDEFGHIJKLMNOPRSŠTUVZŽ'), - wiki_start_pages=[u'Glavna_stran']), - # Serbian can be written in both Latin and Cyrillic, but there's no - # simple way to get the Latin alphabet pages from Wikipedia through - # the API, so for now we just support Cyrillic. - 'Serbian': Language(name='Serbian', - iso_code='sr', - alphabet=(u'АБВГДЂЕЖЗИЈКЛЉМНЊОПРСТЋУФХЦЧЏШ' - u'абвгдђежзијклљмнњопрстћуфхцчџш'), - charsets=['ISO-8859-5', 'WINDOWS-1251', - 'MacCyrillic', 'IBM855'], - wiki_start_pages=[u'Главна_страна']), - 'Thai': Language(name='Thai', - iso_code='th', - use_ascii=False, - charsets=['ISO-8859-11', 'TIS-620', 'CP874'], - alphabet=u'กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛', - wiki_start_pages=[u'หน้าหลัก']), - 'Turkish': Language(name='Turkish', - iso_code='tr', - # Q, W, and X are not used by Turkish - use_ascii=False, - charsets=['ISO-8859-3', 'ISO-8859-9', - 'WINDOWS-1254'], - alphabet=(u'abcçdefgğhıijklmnoöprsştuüvyzâîû' - u'ABCÇDEFGĞHIİJKLMNOÖPRSŞTUÜVYZÂÎÛ'), - wiki_start_pages=[u'Ana_Sayfa']), - 'Vietnamese': Language(name='Vietnamese', - iso_code='vi', - use_ascii=False, - # Windows-1258 is the only common 8-bit - # Vietnamese encoding supported by Python. - # From Wikipedia: - # For systems that lack support for Unicode, - # dozens of 8-bit Vietnamese code pages are - # available.[1] The most common are VISCII - # (TCVN 5712:1993), VPS, and Windows-1258.[3] - # Where ASCII is required, such as when - # ensuring readability in plain text e-mail, - # Vietnamese letters are often encoded - # according to Vietnamese Quoted-Readable - # (VIQR) or VSCII Mnemonic (VSCII-MNEM),[4] - # though usage of either variable-width - # scheme has declined dramatically following - # the adoption of Unicode on the World Wide - # Web. - charsets=['WINDOWS-1258'], - alphabet=(u'aăâbcdđeêghiklmnoôơpqrstuưvxy' - u'AĂÂBCDĐEÊGHIKLMNOÔƠPQRSTUƯVXY'), - wiki_start_pages=[u'Chữ_Quốc_ngữ']), - } diff --git a/venv/lib/python3.8/site-packages/chardet/sbcharsetprober.py b/venv/lib/python3.8/site-packages/chardet/sbcharsetprober.py deleted file mode 100644 index 46ba835..0000000 --- a/venv/lib/python3.8/site-packages/chardet/sbcharsetprober.py +++ /dev/null @@ -1,145 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is Mozilla Universal charset detector code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 2001 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# Shy Shalom - original C code -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -from collections import namedtuple - -from .charsetprober import CharSetProber -from .enums import CharacterCategory, ProbingState, SequenceLikelihood - - -SingleByteCharSetModel = namedtuple('SingleByteCharSetModel', - ['charset_name', - 'language', - 'char_to_order_map', - 'language_model', - 'typical_positive_ratio', - 'keep_ascii_letters', - 'alphabet']) - - -class SingleByteCharSetProber(CharSetProber): - SAMPLE_SIZE = 64 - SB_ENOUGH_REL_THRESHOLD = 1024 # 0.25 * SAMPLE_SIZE^2 - POSITIVE_SHORTCUT_THRESHOLD = 0.95 - NEGATIVE_SHORTCUT_THRESHOLD = 0.05 - - def __init__(self, model, reversed=False, name_prober=None): - super(SingleByteCharSetProber, self).__init__() - self._model = model - # TRUE if we need to reverse every pair in the model lookup - self._reversed = reversed - # Optional auxiliary prober for name decision - self._name_prober = name_prober - self._last_order = None - self._seq_counters = None - self._total_seqs = None - self._total_char = None - self._freq_char = None - self.reset() - - def reset(self): - super(SingleByteCharSetProber, self).reset() - # char order of last character - self._last_order = 255 - self._seq_counters = [0] * SequenceLikelihood.get_num_categories() - self._total_seqs = 0 - self._total_char = 0 - # characters that fall in our sampling range - self._freq_char = 0 - - @property - def charset_name(self): - if self._name_prober: - return self._name_prober.charset_name - else: - return self._model.charset_name - - @property - def language(self): - if self._name_prober: - return self._name_prober.language - else: - return self._model.language - - def feed(self, byte_str): - # TODO: Make filter_international_words keep things in self.alphabet - if not self._model.keep_ascii_letters: - byte_str = self.filter_international_words(byte_str) - if not byte_str: - return self.state - char_to_order_map = self._model.char_to_order_map - language_model = self._model.language_model - for char in byte_str: - order = char_to_order_map.get(char, CharacterCategory.UNDEFINED) - # XXX: This was SYMBOL_CAT_ORDER before, with a value of 250, but - # CharacterCategory.SYMBOL is actually 253, so we use CONTROL - # to make it closer to the original intent. The only difference - # is whether or not we count digits and control characters for - # _total_char purposes. - if order < CharacterCategory.CONTROL: - self._total_char += 1 - # TODO: Follow uchardet's lead and discount confidence for frequent - # control characters. - # See https://github.com/BYVoid/uchardet/commit/55b4f23971db61 - if order < self.SAMPLE_SIZE: - self._freq_char += 1 - if self._last_order < self.SAMPLE_SIZE: - self._total_seqs += 1 - if not self._reversed: - lm_cat = language_model[self._last_order][order] - else: - lm_cat = language_model[order][self._last_order] - self._seq_counters[lm_cat] += 1 - self._last_order = order - - charset_name = self._model.charset_name - if self.state == ProbingState.DETECTING: - if self._total_seqs > self.SB_ENOUGH_REL_THRESHOLD: - confidence = self.get_confidence() - if confidence > self.POSITIVE_SHORTCUT_THRESHOLD: - self.logger.debug('%s confidence = %s, we have a winner', - charset_name, confidence) - self._state = ProbingState.FOUND_IT - elif confidence < self.NEGATIVE_SHORTCUT_THRESHOLD: - self.logger.debug('%s confidence = %s, below negative ' - 'shortcut threshhold %s', charset_name, - confidence, - self.NEGATIVE_SHORTCUT_THRESHOLD) - self._state = ProbingState.NOT_ME - - return self.state - - def get_confidence(self): - r = 0.01 - if self._total_seqs > 0: - r = ((1.0 * self._seq_counters[SequenceLikelihood.POSITIVE]) / - self._total_seqs / self._model.typical_positive_ratio) - r = r * self._freq_char / self._total_char - if r >= 1.0: - r = 0.99 - return r diff --git a/venv/lib/python3.8/site-packages/chardet/sbcsgroupprober.py b/venv/lib/python3.8/site-packages/chardet/sbcsgroupprober.py deleted file mode 100644 index bdeef4e..0000000 --- a/venv/lib/python3.8/site-packages/chardet/sbcsgroupprober.py +++ /dev/null @@ -1,83 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is Mozilla Universal charset detector code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 2001 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# Shy Shalom - original C code -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -from .charsetgroupprober import CharSetGroupProber -from .hebrewprober import HebrewProber -from .langbulgarianmodel import (ISO_8859_5_BULGARIAN_MODEL, - WINDOWS_1251_BULGARIAN_MODEL) -from .langgreekmodel import ISO_8859_7_GREEK_MODEL, WINDOWS_1253_GREEK_MODEL -from .langhebrewmodel import WINDOWS_1255_HEBREW_MODEL -# from .langhungarianmodel import (ISO_8859_2_HUNGARIAN_MODEL, -# WINDOWS_1250_HUNGARIAN_MODEL) -from .langrussianmodel import (IBM855_RUSSIAN_MODEL, IBM866_RUSSIAN_MODEL, - ISO_8859_5_RUSSIAN_MODEL, KOI8_R_RUSSIAN_MODEL, - MACCYRILLIC_RUSSIAN_MODEL, - WINDOWS_1251_RUSSIAN_MODEL) -from .langthaimodel import TIS_620_THAI_MODEL -from .langturkishmodel import ISO_8859_9_TURKISH_MODEL -from .sbcharsetprober import SingleByteCharSetProber - - -class SBCSGroupProber(CharSetGroupProber): - def __init__(self): - super(SBCSGroupProber, self).__init__() - hebrew_prober = HebrewProber() - logical_hebrew_prober = SingleByteCharSetProber(WINDOWS_1255_HEBREW_MODEL, - False, hebrew_prober) - # TODO: See if using ISO-8859-8 Hebrew model works better here, since - # it's actually the visual one - visual_hebrew_prober = SingleByteCharSetProber(WINDOWS_1255_HEBREW_MODEL, - True, hebrew_prober) - hebrew_prober.set_model_probers(logical_hebrew_prober, - visual_hebrew_prober) - # TODO: ORDER MATTERS HERE. I changed the order vs what was in master - # and several tests failed that did not before. Some thought - # should be put into the ordering, and we should consider making - # order not matter here, because that is very counter-intuitive. - self.probers = [ - SingleByteCharSetProber(WINDOWS_1251_RUSSIAN_MODEL), - SingleByteCharSetProber(KOI8_R_RUSSIAN_MODEL), - SingleByteCharSetProber(ISO_8859_5_RUSSIAN_MODEL), - SingleByteCharSetProber(MACCYRILLIC_RUSSIAN_MODEL), - SingleByteCharSetProber(IBM866_RUSSIAN_MODEL), - SingleByteCharSetProber(IBM855_RUSSIAN_MODEL), - SingleByteCharSetProber(ISO_8859_7_GREEK_MODEL), - SingleByteCharSetProber(WINDOWS_1253_GREEK_MODEL), - SingleByteCharSetProber(ISO_8859_5_BULGARIAN_MODEL), - SingleByteCharSetProber(WINDOWS_1251_BULGARIAN_MODEL), - # TODO: Restore Hungarian encodings (iso-8859-2 and windows-1250) - # after we retrain model. - # SingleByteCharSetProber(ISO_8859_2_HUNGARIAN_MODEL), - # SingleByteCharSetProber(WINDOWS_1250_HUNGARIAN_MODEL), - SingleByteCharSetProber(TIS_620_THAI_MODEL), - SingleByteCharSetProber(ISO_8859_9_TURKISH_MODEL), - hebrew_prober, - logical_hebrew_prober, - visual_hebrew_prober, - ] - self.reset() diff --git a/venv/lib/python3.8/site-packages/chardet/sjisprober.py b/venv/lib/python3.8/site-packages/chardet/sjisprober.py deleted file mode 100644 index 9e29623..0000000 --- a/venv/lib/python3.8/site-packages/chardet/sjisprober.py +++ /dev/null @@ -1,92 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is mozilla.org code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -from .mbcharsetprober import MultiByteCharSetProber -from .codingstatemachine import CodingStateMachine -from .chardistribution import SJISDistributionAnalysis -from .jpcntx import SJISContextAnalysis -from .mbcssm import SJIS_SM_MODEL -from .enums import ProbingState, MachineState - - -class SJISProber(MultiByteCharSetProber): - def __init__(self): - super(SJISProber, self).__init__() - self.coding_sm = CodingStateMachine(SJIS_SM_MODEL) - self.distribution_analyzer = SJISDistributionAnalysis() - self.context_analyzer = SJISContextAnalysis() - self.reset() - - def reset(self): - super(SJISProber, self).reset() - self.context_analyzer.reset() - - @property - def charset_name(self): - return self.context_analyzer.charset_name - - @property - def language(self): - return "Japanese" - - def feed(self, byte_str): - for i in range(len(byte_str)): - coding_state = self.coding_sm.next_state(byte_str[i]) - if coding_state == MachineState.ERROR: - self.logger.debug('%s %s prober hit error at byte %s', - self.charset_name, self.language, i) - self._state = ProbingState.NOT_ME - break - elif coding_state == MachineState.ITS_ME: - self._state = ProbingState.FOUND_IT - break - elif coding_state == MachineState.START: - char_len = self.coding_sm.get_current_charlen() - if i == 0: - self._last_char[1] = byte_str[0] - self.context_analyzer.feed(self._last_char[2 - char_len:], - char_len) - self.distribution_analyzer.feed(self._last_char, char_len) - else: - self.context_analyzer.feed(byte_str[i + 1 - char_len:i + 3 - - char_len], char_len) - self.distribution_analyzer.feed(byte_str[i - 1:i + 1], - char_len) - - self._last_char[0] = byte_str[-1] - - if self.state == ProbingState.DETECTING: - if (self.context_analyzer.got_enough_data() and - (self.get_confidence() > self.SHORTCUT_THRESHOLD)): - self._state = ProbingState.FOUND_IT - - return self.state - - def get_confidence(self): - context_conf = self.context_analyzer.get_confidence() - distrib_conf = self.distribution_analyzer.get_confidence() - return max(context_conf, distrib_conf) diff --git a/venv/lib/python3.8/site-packages/chardet/universaldetector.py b/venv/lib/python3.8/site-packages/chardet/universaldetector.py deleted file mode 100644 index 055a8ac..0000000 --- a/venv/lib/python3.8/site-packages/chardet/universaldetector.py +++ /dev/null @@ -1,286 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is Mozilla Universal charset detector code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 2001 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# Shy Shalom - original C code -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### -""" -Module containing the UniversalDetector detector class, which is the primary -class a user of ``chardet`` should use. - -:author: Mark Pilgrim (initial port to Python) -:author: Shy Shalom (original C code) -:author: Dan Blanchard (major refactoring for 3.0) -:author: Ian Cordasco -""" - - -import codecs -import logging -import re - -from .charsetgroupprober import CharSetGroupProber -from .enums import InputState, LanguageFilter, ProbingState -from .escprober import EscCharSetProber -from .latin1prober import Latin1Prober -from .mbcsgroupprober import MBCSGroupProber -from .sbcsgroupprober import SBCSGroupProber - - -class UniversalDetector(object): - """ - The ``UniversalDetector`` class underlies the ``chardet.detect`` function - and coordinates all of the different charset probers. - - To get a ``dict`` containing an encoding and its confidence, you can simply - run: - - .. code:: - - u = UniversalDetector() - u.feed(some_bytes) - u.close() - detected = u.result - - """ - - MINIMUM_THRESHOLD = 0.20 - HIGH_BYTE_DETECTOR = re.compile(b'[\x80-\xFF]') - ESC_DETECTOR = re.compile(b'(\033|~{)') - WIN_BYTE_DETECTOR = re.compile(b'[\x80-\x9F]') - ISO_WIN_MAP = {'iso-8859-1': 'Windows-1252', - 'iso-8859-2': 'Windows-1250', - 'iso-8859-5': 'Windows-1251', - 'iso-8859-6': 'Windows-1256', - 'iso-8859-7': 'Windows-1253', - 'iso-8859-8': 'Windows-1255', - 'iso-8859-9': 'Windows-1254', - 'iso-8859-13': 'Windows-1257'} - - def __init__(self, lang_filter=LanguageFilter.ALL): - self._esc_charset_prober = None - self._charset_probers = [] - self.result = None - self.done = None - self._got_data = None - self._input_state = None - self._last_char = None - self.lang_filter = lang_filter - self.logger = logging.getLogger(__name__) - self._has_win_bytes = None - self.reset() - - def reset(self): - """ - Reset the UniversalDetector and all of its probers back to their - initial states. This is called by ``__init__``, so you only need to - call this directly in between analyses of different documents. - """ - self.result = {'encoding': None, 'confidence': 0.0, 'language': None} - self.done = False - self._got_data = False - self._has_win_bytes = False - self._input_state = InputState.PURE_ASCII - self._last_char = b'' - if self._esc_charset_prober: - self._esc_charset_prober.reset() - for prober in self._charset_probers: - prober.reset() - - def feed(self, byte_str): - """ - Takes a chunk of a document and feeds it through all of the relevant - charset probers. - - After calling ``feed``, you can check the value of the ``done`` - attribute to see if you need to continue feeding the - ``UniversalDetector`` more data, or if it has made a prediction - (in the ``result`` attribute). - - .. note:: - You should always call ``close`` when you're done feeding in your - document if ``done`` is not already ``True``. - """ - if self.done: - return - - if not len(byte_str): - return - - if not isinstance(byte_str, bytearray): - byte_str = bytearray(byte_str) - - # First check for known BOMs, since these are guaranteed to be correct - if not self._got_data: - # If the data starts with BOM, we know it is UTF - if byte_str.startswith(codecs.BOM_UTF8): - # EF BB BF UTF-8 with BOM - self.result = {'encoding': "UTF-8-SIG", - 'confidence': 1.0, - 'language': ''} - elif byte_str.startswith((codecs.BOM_UTF32_LE, - codecs.BOM_UTF32_BE)): - # FF FE 00 00 UTF-32, little-endian BOM - # 00 00 FE FF UTF-32, big-endian BOM - self.result = {'encoding': "UTF-32", - 'confidence': 1.0, - 'language': ''} - elif byte_str.startswith(b'\xFE\xFF\x00\x00'): - # FE FF 00 00 UCS-4, unusual octet order BOM (3412) - self.result = {'encoding': "X-ISO-10646-UCS-4-3412", - 'confidence': 1.0, - 'language': ''} - elif byte_str.startswith(b'\x00\x00\xFF\xFE'): - # 00 00 FF FE UCS-4, unusual octet order BOM (2143) - self.result = {'encoding': "X-ISO-10646-UCS-4-2143", - 'confidence': 1.0, - 'language': ''} - elif byte_str.startswith((codecs.BOM_LE, codecs.BOM_BE)): - # FF FE UTF-16, little endian BOM - # FE FF UTF-16, big endian BOM - self.result = {'encoding': "UTF-16", - 'confidence': 1.0, - 'language': ''} - - self._got_data = True - if self.result['encoding'] is not None: - self.done = True - return - - # If none of those matched and we've only see ASCII so far, check - # for high bytes and escape sequences - if self._input_state == InputState.PURE_ASCII: - if self.HIGH_BYTE_DETECTOR.search(byte_str): - self._input_state = InputState.HIGH_BYTE - elif self._input_state == InputState.PURE_ASCII and \ - self.ESC_DETECTOR.search(self._last_char + byte_str): - self._input_state = InputState.ESC_ASCII - - self._last_char = byte_str[-1:] - - # If we've seen escape sequences, use the EscCharSetProber, which - # uses a simple state machine to check for known escape sequences in - # HZ and ISO-2022 encodings, since those are the only encodings that - # use such sequences. - if self._input_state == InputState.ESC_ASCII: - if not self._esc_charset_prober: - self._esc_charset_prober = EscCharSetProber(self.lang_filter) - if self._esc_charset_prober.feed(byte_str) == ProbingState.FOUND_IT: - self.result = {'encoding': - self._esc_charset_prober.charset_name, - 'confidence': - self._esc_charset_prober.get_confidence(), - 'language': - self._esc_charset_prober.language} - self.done = True - # If we've seen high bytes (i.e., those with values greater than 127), - # we need to do more complicated checks using all our multi-byte and - # single-byte probers that are left. The single-byte probers - # use character bigram distributions to determine the encoding, whereas - # the multi-byte probers use a combination of character unigram and - # bigram distributions. - elif self._input_state == InputState.HIGH_BYTE: - if not self._charset_probers: - self._charset_probers = [MBCSGroupProber(self.lang_filter)] - # If we're checking non-CJK encodings, use single-byte prober - if self.lang_filter & LanguageFilter.NON_CJK: - self._charset_probers.append(SBCSGroupProber()) - self._charset_probers.append(Latin1Prober()) - for prober in self._charset_probers: - if prober.feed(byte_str) == ProbingState.FOUND_IT: - self.result = {'encoding': prober.charset_name, - 'confidence': prober.get_confidence(), - 'language': prober.language} - self.done = True - break - if self.WIN_BYTE_DETECTOR.search(byte_str): - self._has_win_bytes = True - - def close(self): - """ - Stop analyzing the current document and come up with a final - prediction. - - :returns: The ``result`` attribute, a ``dict`` with the keys - `encoding`, `confidence`, and `language`. - """ - # Don't bother with checks if we're already done - if self.done: - return self.result - self.done = True - - if not self._got_data: - self.logger.debug('no data received!') - - # Default to ASCII if it is all we've seen so far - elif self._input_state == InputState.PURE_ASCII: - self.result = {'encoding': 'ascii', - 'confidence': 1.0, - 'language': ''} - - # If we have seen non-ASCII, return the best that met MINIMUM_THRESHOLD - elif self._input_state == InputState.HIGH_BYTE: - prober_confidence = None - max_prober_confidence = 0.0 - max_prober = None - for prober in self._charset_probers: - if not prober: - continue - prober_confidence = prober.get_confidence() - if prober_confidence > max_prober_confidence: - max_prober_confidence = prober_confidence - max_prober = prober - if max_prober and (max_prober_confidence > self.MINIMUM_THRESHOLD): - charset_name = max_prober.charset_name - lower_charset_name = max_prober.charset_name.lower() - confidence = max_prober.get_confidence() - # Use Windows encoding name instead of ISO-8859 if we saw any - # extra Windows-specific bytes - if lower_charset_name.startswith('iso-8859'): - if self._has_win_bytes: - charset_name = self.ISO_WIN_MAP.get(lower_charset_name, - charset_name) - self.result = {'encoding': charset_name, - 'confidence': confidence, - 'language': max_prober.language} - - # Log all prober confidences if none met MINIMUM_THRESHOLD - if self.logger.getEffectiveLevel() <= logging.DEBUG: - if self.result['encoding'] is None: - self.logger.debug('no probers hit minimum threshold') - for group_prober in self._charset_probers: - if not group_prober: - continue - if isinstance(group_prober, CharSetGroupProber): - for prober in group_prober.probers: - self.logger.debug('%s %s confidence = %s', - prober.charset_name, - prober.language, - prober.get_confidence()) - else: - self.logger.debug('%s %s confidence = %s', - group_prober.charset_name, - group_prober.language, - group_prober.get_confidence()) - return self.result diff --git a/venv/lib/python3.8/site-packages/chardet/utf8prober.py b/venv/lib/python3.8/site-packages/chardet/utf8prober.py deleted file mode 100644 index 6c3196c..0000000 --- a/venv/lib/python3.8/site-packages/chardet/utf8prober.py +++ /dev/null @@ -1,82 +0,0 @@ -######################## BEGIN LICENSE BLOCK ######################## -# The Original Code is mozilla.org code. -# -# The Initial Developer of the Original Code is -# Netscape Communications Corporation. -# Portions created by the Initial Developer are Copyright (C) 1998 -# the Initial Developer. All Rights Reserved. -# -# Contributor(s): -# Mark Pilgrim - port to Python -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA -# 02110-1301 USA -######################### END LICENSE BLOCK ######################### - -from .charsetprober import CharSetProber -from .enums import ProbingState, MachineState -from .codingstatemachine import CodingStateMachine -from .mbcssm import UTF8_SM_MODEL - - - -class UTF8Prober(CharSetProber): - ONE_CHAR_PROB = 0.5 - - def __init__(self): - super(UTF8Prober, self).__init__() - self.coding_sm = CodingStateMachine(UTF8_SM_MODEL) - self._num_mb_chars = None - self.reset() - - def reset(self): - super(UTF8Prober, self).reset() - self.coding_sm.reset() - self._num_mb_chars = 0 - - @property - def charset_name(self): - return "utf-8" - - @property - def language(self): - return "" - - def feed(self, byte_str): - for c in byte_str: - coding_state = self.coding_sm.next_state(c) - if coding_state == MachineState.ERROR: - self._state = ProbingState.NOT_ME - break - elif coding_state == MachineState.ITS_ME: - self._state = ProbingState.FOUND_IT - break - elif coding_state == MachineState.START: - if self.coding_sm.get_current_charlen() >= 2: - self._num_mb_chars += 1 - - if self.state == ProbingState.DETECTING: - if self.get_confidence() > self.SHORTCUT_THRESHOLD: - self._state = ProbingState.FOUND_IT - - return self.state - - def get_confidence(self): - unlike = 0.99 - if self._num_mb_chars < 6: - unlike *= self.ONE_CHAR_PROB ** self._num_mb_chars - return 1.0 - unlike - else: - return unlike diff --git a/venv/lib/python3.8/site-packages/chardet/version.py b/venv/lib/python3.8/site-packages/chardet/version.py deleted file mode 100644 index 70369b9..0000000 --- a/venv/lib/python3.8/site-packages/chardet/version.py +++ /dev/null @@ -1,9 +0,0 @@ -""" -This module exists only to simplify retrieving the version number of chardet -from within setup.py and from chardet subpackages. - -:author: Dan Blanchard (dan.blanchard@gmail.com) -""" - -__version__ = "4.0.0" -VERSION = __version__.split('.') diff --git a/venv/lib/python3.8/site-packages/easy_install.py b/venv/lib/python3.8/site-packages/easy_install.py deleted file mode 100644 index d87e984..0000000 --- a/venv/lib/python3.8/site-packages/easy_install.py +++ /dev/null @@ -1,5 +0,0 @@ -"""Run the EasyInstall command""" - -if __name__ == '__main__': - from setuptools.command.easy_install import main - main() diff --git a/venv/lib/python3.8/site-packages/idna-2.10.dist-info/INSTALLER b/venv/lib/python3.8/site-packages/idna-2.10.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.8/site-packages/idna-2.10.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.8/site-packages/idna-2.10.dist-info/LICENSE.rst b/venv/lib/python3.8/site-packages/idna-2.10.dist-info/LICENSE.rst deleted file mode 100644 index 63664b8..0000000 --- a/venv/lib/python3.8/site-packages/idna-2.10.dist-info/LICENSE.rst +++ /dev/null @@ -1,34 +0,0 @@ -License -------- - -License: bsd-3-clause - -Copyright (c) 2013-2020, Kim Davies. 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 the - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - -#. THIS SOFTWARE IS PROVIDED BY THE 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 HOLDERS OR - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE - USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH - DAMAGE. diff --git a/venv/lib/python3.8/site-packages/idna-2.10.dist-info/METADATA b/venv/lib/python3.8/site-packages/idna-2.10.dist-info/METADATA deleted file mode 100644 index f73c0ff..0000000 --- a/venv/lib/python3.8/site-packages/idna-2.10.dist-info/METADATA +++ /dev/null @@ -1,243 +0,0 @@ -Metadata-Version: 2.1 -Name: idna -Version: 2.10 -Summary: Internationalized Domain Names in Applications (IDNA) -Home-page: https://github.com/kjd/idna -Author: Kim Davies -Author-email: kim@cynosure.com.au -License: BSD-like -Platform: UNKNOWN -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: Intended Audience :: System Administrators -Classifier: License :: OSI Approved :: BSD License -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 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 :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Topic :: Internet :: Name Service (DNS) -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Classifier: Topic :: Utilities -Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.* - -Internationalized Domain Names in Applications (IDNA) -===================================================== - -Support for the Internationalised Domain Names in Applications -(IDNA) protocol as specified in `RFC 5891 <http://tools.ietf.org/html/rfc5891>`_. -This is the latest version of the protocol and is sometimes referred to as -“IDNA 2008”. - -This library also provides support for Unicode Technical Standard 46, -`Unicode IDNA Compatibility Processing <http://unicode.org/reports/tr46/>`_. - -This acts as a suitable replacement for the “encodings.idna” module that -comes with the Python standard library, but only supports the -old, deprecated IDNA specification (`RFC 3490 <http://tools.ietf.org/html/rfc3490>`_). - -Basic functions are simply executed: - -.. code-block:: pycon - - # Python 3 - >>> import idna - >>> idna.encode('ドメイン.テスト') - b'xn--eckwd4c7c.xn--zckzah' - >>> print(idna.decode('xn--eckwd4c7c.xn--zckzah')) - ドメイン.テスト - - # Python 2 - >>> import idna - >>> idna.encode(u'ドメイン.テスト') - 'xn--eckwd4c7c.xn--zckzah' - >>> print idna.decode('xn--eckwd4c7c.xn--zckzah') - ドメイン.テスト - -Packages --------- - -The latest tagged release version is published in the PyPI repository: - -.. image:: https://badge.fury.io/py/idna.svg - :target: http://badge.fury.io/py/idna - - -Installation ------------- - -To install this library, you can use pip: - -.. code-block:: bash - - $ pip install idna - -Alternatively, you can install the package using the bundled setup script: - -.. code-block:: bash - - $ python setup.py install - -This library works with Python 2.7 and Python 3.4 or later. - - -Usage ------ - -For typical usage, the ``encode`` and ``decode`` functions will take a domain -name argument and perform a conversion to A-labels or U-labels respectively. - -.. code-block:: pycon - - # Python 3 - >>> import idna - >>> idna.encode('ドメイン.テスト') - b'xn--eckwd4c7c.xn--zckzah' - >>> print(idna.decode('xn--eckwd4c7c.xn--zckzah')) - ドメイン.テスト - -You may use the codec encoding and decoding methods using the -``idna.codec`` module: - -.. code-block:: pycon - - # Python 2 - >>> import idna.codec - >>> print u'домена.испытание'.encode('idna') - xn--80ahd1agd.xn--80akhbyknj4f - >>> print 'xn--80ahd1agd.xn--80akhbyknj4f'.decode('idna') - домена.испытание - -Conversions can be applied at a per-label basis using the ``ulabel`` or ``alabel`` -functions if necessary: - -.. code-block:: pycon - - # Python 2 - >>> idna.alabel(u'测试') - 'xn--0zwm56d' - -Compatibility Mapping (UTS #46) -+++++++++++++++++++++++++++++++ - -As described in `RFC 5895 <http://tools.ietf.org/html/rfc5895>`_, the IDNA -specification no longer normalizes input from different potential ways a user -may input a domain name. This functionality, known as a “mapping”, is now -considered by the specification to be a local user-interface issue distinct -from IDNA conversion functionality. - -This library provides one such mapping, that was developed by the Unicode -Consortium. Known as `Unicode IDNA Compatibility Processing <http://unicode.org/reports/tr46/>`_, -it provides for both a regular mapping for typical applications, as well as -a transitional mapping to help migrate from older IDNA 2003 applications. - -For example, “Königsgäßchen” is not a permissible label as *LATIN CAPITAL -LETTER K* is not allowed (nor are capital letters in general). UTS 46 will -convert this into lower case prior to applying the IDNA conversion. - -.. code-block:: pycon - - # Python 3 - >>> import idna - >>> idna.encode(u'Königsgäßchen') - ... - idna.core.InvalidCodepoint: Codepoint U+004B at position 1 of 'Königsgäßchen' not allowed - >>> idna.encode('Königsgäßchen', uts46=True) - b'xn--knigsgchen-b4a3dun' - >>> print(idna.decode('xn--knigsgchen-b4a3dun')) - königsgäßchen - -Transitional processing provides conversions to help transition from the older -2003 standard to the current standard. For example, in the original IDNA -specification, the *LATIN SMALL LETTER SHARP S* (ß) was converted into two -*LATIN SMALL LETTER S* (ss), whereas in the current IDNA specification this -conversion is not performed. - -.. code-block:: pycon - - # Python 2 - >>> idna.encode(u'Königsgäßchen', uts46=True, transitional=True) - 'xn--knigsgsschen-lcb0w' - -Implementors should use transitional processing with caution, only in rare -cases where conversion from legacy labels to current labels must be performed -(i.e. IDNA implementations that pre-date 2008). For typical applications -that just need to convert labels, transitional processing is unlikely to be -beneficial and could produce unexpected incompatible results. - -``encodings.idna`` Compatibility -++++++++++++++++++++++++++++++++ - -Function calls from the Python built-in ``encodings.idna`` module are -mapped to their IDNA 2008 equivalents using the ``idna.compat`` module. -Simply substitute the ``import`` clause in your code to refer to the -new module name. - -Exceptions ----------- - -All errors raised during the conversion following the specification should -raise an exception derived from the ``idna.IDNAError`` base class. - -More specific exceptions that may be generated as ``idna.IDNABidiError`` -when the error reflects an illegal combination of left-to-right and right-to-left -characters in a label; ``idna.InvalidCodepoint`` when a specific codepoint is -an illegal character in an IDN label (i.e. INVALID); and ``idna.InvalidCodepointContext`` -when the codepoint is illegal based on its positional context (i.e. it is CONTEXTO -or CONTEXTJ but the contextual requirements are not satisfied.) - -Building and Diagnostics ------------------------- - -The IDNA and UTS 46 functionality relies upon pre-calculated lookup tables for -performance. These tables are derived from computing against eligibility criteria -in the respective standards. These tables are computed using the command-line -script ``tools/idna-data``. - -This tool will fetch relevant tables from the Unicode Consortium and perform the -required calculations to identify eligibility. It has three main modes: - -* ``idna-data make-libdata``. Generates ``idnadata.py`` and ``uts46data.py``, - the pre-calculated lookup tables using for IDNA and UTS 46 conversions. Implementors - who wish to track this library against a different Unicode version may use this tool - to manually generate a different version of the ``idnadata.py`` and ``uts46data.py`` - files. - -* ``idna-data make-table``. Generate a table of the IDNA disposition - (e.g. PVALID, CONTEXTJ, CONTEXTO) in the format found in Appendix B.1 of RFC - 5892 and the pre-computed tables published by `IANA <http://iana.org/>`_. - -* ``idna-data U+0061``. Prints debugging output on the various properties - associated with an individual Unicode codepoint (in this case, U+0061), that are - used to assess the IDNA and UTS 46 status of a codepoint. This is helpful in debugging - or analysis. - -The tool accepts a number of arguments, described using ``idna-data -h``. Most notably, -the ``--version`` argument allows the specification of the version of Unicode to use -in computing the table data. For example, ``idna-data --version 9.0.0 make-libdata`` -will generate library data against Unicode 9.0.0. - -Note that this script requires Python 3, but all generated library data will work -in Python 2.7. - - -Testing -------- - -The library has a test suite based on each rule of the IDNA specification, as -well as tests that are provided as part of the Unicode Technical Standard 46, -`Unicode IDNA Compatibility Processing <http://unicode.org/reports/tr46/>`_. - -The tests are run automatically on each commit at Travis CI: - -.. image:: https://travis-ci.org/kjd/idna.svg?branch=master - :target: https://travis-ci.org/kjd/idna - - diff --git a/venv/lib/python3.8/site-packages/idna-2.10.dist-info/RECORD b/venv/lib/python3.8/site-packages/idna-2.10.dist-info/RECORD deleted file mode 100644 index 67b7cd5..0000000 --- a/venv/lib/python3.8/site-packages/idna-2.10.dist-info/RECORD +++ /dev/null @@ -1,22 +0,0 @@ -idna-2.10.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -idna-2.10.dist-info/LICENSE.rst,sha256=QSAUQg0kc9ugYRfD1Nng7sqm3eDKMM2VH07CvjlCbzI,1565 -idna-2.10.dist-info/METADATA,sha256=ZWCaQDBjdmSvx5EU7Cv6ORC-9NUQ6nXh1eXx38ySe40,9104 -idna-2.10.dist-info/RECORD,, -idna-2.10.dist-info/WHEEL,sha256=8zNYZbwQSXoB9IfXOjPfeNwvAsALAjffgk27FqvCWbo,110 -idna-2.10.dist-info/top_level.txt,sha256=jSag9sEDqvSPftxOQy-ABfGV_RSy7oFh4zZJpODV8k0,5 -idna/__init__.py,sha256=9Nt7xpyet3DmOrPUGooDdAwmHZZu1qUAy2EaJ93kGiQ,58 -idna/__pycache__/__init__.cpython-38.pyc,, -idna/__pycache__/codec.cpython-38.pyc,, -idna/__pycache__/compat.cpython-38.pyc,, -idna/__pycache__/core.cpython-38.pyc,, -idna/__pycache__/idnadata.cpython-38.pyc,, -idna/__pycache__/intranges.cpython-38.pyc,, -idna/__pycache__/package_data.cpython-38.pyc,, -idna/__pycache__/uts46data.cpython-38.pyc,, -idna/codec.py,sha256=lvYb7yu7PhAqFaAIAdWcwgaWI2UmgseUua-1c0AsG0A,3299 -idna/compat.py,sha256=R-h29D-6mrnJzbXxymrWUW7iZUvy-26TQwZ0ij57i4U,232 -idna/core.py,sha256=jCoaLb3bA2tS_DDx9PpGuNTEZZN2jAzB369aP-IHYRE,11951 -idna/idnadata.py,sha256=gmzFwZWjdms3kKZ_M_vwz7-LP_SCgYfSeE03B21Qpsk,42350 -idna/intranges.py,sha256=TY1lpxZIQWEP6tNqjZkFA5hgoMWOj1OBmnUG8ihT87E,1749 -idna/package_data.py,sha256=bxBjpLnE06_1jSYKEy5svOMu1zM3OMztXVUb1tPlcp0,22 -idna/uts46data.py,sha256=lMdw2zdjkH1JUWXPPEfFUSYT3Fyj60bBmfLvvy5m7ko,202084 diff --git a/venv/lib/python3.8/site-packages/idna-2.10.dist-info/WHEEL b/venv/lib/python3.8/site-packages/idna-2.10.dist-info/WHEEL deleted file mode 100644 index 8b701e9..0000000 --- a/venv/lib/python3.8/site-packages/idna-2.10.dist-info/WHEEL +++ /dev/null @@ -1,6 +0,0 @@ -Wheel-Version: 1.0 -Generator: bdist_wheel (0.33.6) -Root-Is-Purelib: true -Tag: py2-none-any -Tag: py3-none-any - diff --git a/venv/lib/python3.8/site-packages/idna-2.10.dist-info/top_level.txt b/venv/lib/python3.8/site-packages/idna-2.10.dist-info/top_level.txt deleted file mode 100644 index c40472e..0000000 --- a/venv/lib/python3.8/site-packages/idna-2.10.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -idna diff --git a/venv/lib/python3.8/site-packages/idna/__init__.py b/venv/lib/python3.8/site-packages/idna/__init__.py deleted file mode 100644 index 847bf93..0000000 --- a/venv/lib/python3.8/site-packages/idna/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -from .package_data import __version__ -from .core import * diff --git a/venv/lib/python3.8/site-packages/idna/codec.py b/venv/lib/python3.8/site-packages/idna/codec.py deleted file mode 100644 index 98c65ea..0000000 --- a/venv/lib/python3.8/site-packages/idna/codec.py +++ /dev/null @@ -1,118 +0,0 @@ -from .core import encode, decode, alabel, ulabel, IDNAError -import codecs -import re - -_unicode_dots_re = re.compile(u'[\u002e\u3002\uff0e\uff61]') - -class Codec(codecs.Codec): - - def encode(self, data, errors='strict'): - - if errors != 'strict': - raise IDNAError("Unsupported error handling \"{0}\"".format(errors)) - - if not data: - return "", 0 - - return encode(data), len(data) - - def decode(self, data, errors='strict'): - - if errors != 'strict': - raise IDNAError("Unsupported error handling \"{0}\"".format(errors)) - - if not data: - return u"", 0 - - return decode(data), len(data) - -class IncrementalEncoder(codecs.BufferedIncrementalEncoder): - def _buffer_encode(self, data, errors, final): - if errors != 'strict': - raise IDNAError("Unsupported error handling \"{0}\"".format(errors)) - - if not data: - return ("", 0) - - labels = _unicode_dots_re.split(data) - trailing_dot = u'' - if labels: - if not labels[-1]: - trailing_dot = '.' - del labels[-1] - elif not final: - # Keep potentially unfinished label until the next call - del labels[-1] - if labels: - trailing_dot = '.' - - result = [] - size = 0 - for label in labels: - result.append(alabel(label)) - if size: - size += 1 - size += len(label) - - # Join with U+002E - result = ".".join(result) + trailing_dot - size += len(trailing_dot) - return (result, size) - -class IncrementalDecoder(codecs.BufferedIncrementalDecoder): - def _buffer_decode(self, data, errors, final): - if errors != 'strict': - raise IDNAError("Unsupported error handling \"{0}\"".format(errors)) - - if not data: - return (u"", 0) - - # IDNA allows decoding to operate on Unicode strings, too. - if isinstance(data, unicode): - labels = _unicode_dots_re.split(data) - else: - # Must be ASCII string - data = str(data) - unicode(data, "ascii") - labels = data.split(".") - - trailing_dot = u'' - if labels: - if not labels[-1]: - trailing_dot = u'.' - del labels[-1] - elif not final: - # Keep potentially unfinished label until the next call - del labels[-1] - if labels: - trailing_dot = u'.' - - result = [] - size = 0 - for label in labels: - result.append(ulabel(label)) - if size: - size += 1 - size += len(label) - - result = u".".join(result) + trailing_dot - size += len(trailing_dot) - return (result, size) - - -class StreamWriter(Codec, codecs.StreamWriter): - pass - -class StreamReader(Codec, codecs.StreamReader): - pass - -def getregentry(): - return codecs.CodecInfo( - name='idna', - encode=Codec().encode, - decode=Codec().decode, - incrementalencoder=IncrementalEncoder, - incrementaldecoder=IncrementalDecoder, - streamwriter=StreamWriter, - streamreader=StreamReader, - ) diff --git a/venv/lib/python3.8/site-packages/idna/compat.py b/venv/lib/python3.8/site-packages/idna/compat.py deleted file mode 100644 index 4d47f33..0000000 --- a/venv/lib/python3.8/site-packages/idna/compat.py +++ /dev/null @@ -1,12 +0,0 @@ -from .core import * -from .codec import * - -def ToASCII(label): - return encode(label) - -def ToUnicode(label): - return decode(label) - -def nameprep(s): - raise NotImplementedError("IDNA 2008 does not utilise nameprep protocol") - diff --git a/venv/lib/python3.8/site-packages/idna/core.py b/venv/lib/python3.8/site-packages/idna/core.py deleted file mode 100644 index 41ec5c7..0000000 --- a/venv/lib/python3.8/site-packages/idna/core.py +++ /dev/null @@ -1,400 +0,0 @@ -from . import idnadata -import bisect -import unicodedata -import re -import sys -from .intranges import intranges_contain - -_virama_combining_class = 9 -_alabel_prefix = b'xn--' -_unicode_dots_re = re.compile(u'[\u002e\u3002\uff0e\uff61]') - -if sys.version_info[0] >= 3: - unicode = str - unichr = chr - -class IDNAError(UnicodeError): - """ Base exception for all IDNA-encoding related problems """ - pass - - -class IDNABidiError(IDNAError): - """ Exception when bidirectional requirements are not satisfied """ - pass - - -class InvalidCodepoint(IDNAError): - """ Exception when a disallowed or unallocated codepoint is used """ - pass - - -class InvalidCodepointContext(IDNAError): - """ Exception when the codepoint is not valid in the context it is used """ - pass - - -def _combining_class(cp): - v = unicodedata.combining(unichr(cp)) - if v == 0: - if not unicodedata.name(unichr(cp)): - raise ValueError("Unknown character in unicodedata") - return v - -def _is_script(cp, script): - return intranges_contain(ord(cp), idnadata.scripts[script]) - -def _punycode(s): - return s.encode('punycode') - -def _unot(s): - return 'U+{0:04X}'.format(s) - - -def valid_label_length(label): - - if len(label) > 63: - return False - return True - - -def valid_string_length(label, trailing_dot): - - if len(label) > (254 if trailing_dot else 253): - return False - return True - - -def check_bidi(label, check_ltr=False): - - # Bidi rules should only be applied if string contains RTL characters - bidi_label = False - for (idx, cp) in enumerate(label, 1): - direction = unicodedata.bidirectional(cp) - if direction == '': - # String likely comes from a newer version of Unicode - raise IDNABidiError('Unknown directionality in label {0} at position {1}'.format(repr(label), idx)) - if direction in ['R', 'AL', 'AN']: - bidi_label = True - if not bidi_label and not check_ltr: - return True - - # Bidi rule 1 - direction = unicodedata.bidirectional(label[0]) - if direction in ['R', 'AL']: - rtl = True - elif direction == 'L': - rtl = False - else: - raise IDNABidiError('First codepoint in label {0} must be directionality L, R or AL'.format(repr(label))) - - valid_ending = False - number_type = False - for (idx, cp) in enumerate(label, 1): - direction = unicodedata.bidirectional(cp) - - if rtl: - # Bidi rule 2 - if not direction in ['R', 'AL', 'AN', 'EN', 'ES', 'CS', 'ET', 'ON', 'BN', 'NSM']: - raise IDNABidiError('Invalid direction for codepoint at position {0} in a right-to-left label'.format(idx)) - # Bidi rule 3 - if direction in ['R', 'AL', 'EN', 'AN']: - valid_ending = True - elif direction != 'NSM': - valid_ending = False - # Bidi rule 4 - if direction in ['AN', 'EN']: - if not number_type: - number_type = direction - else: - if number_type != direction: - raise IDNABidiError('Can not mix numeral types in a right-to-left label') - else: - # Bidi rule 5 - if not direction in ['L', 'EN', 'ES', 'CS', 'ET', 'ON', 'BN', 'NSM']: - raise IDNABidiError('Invalid direction for codepoint at position {0} in a left-to-right label'.format(idx)) - # Bidi rule 6 - if direction in ['L', 'EN']: - valid_ending = True - elif direction != 'NSM': - valid_ending = False - - if not valid_ending: - raise IDNABidiError('Label ends with illegal codepoint directionality') - - return True - - -def check_initial_combiner(label): - - if unicodedata.category(label[0])[0] == 'M': - raise IDNAError('Label begins with an illegal combining character') - return True - - -def check_hyphen_ok(label): - - if label[2:4] == '--': - raise IDNAError('Label has disallowed hyphens in 3rd and 4th position') - if label[0] == '-' or label[-1] == '-': - raise IDNAError('Label must not start or end with a hyphen') - return True - - -def check_nfc(label): - - if unicodedata.normalize('NFC', label) != label: - raise IDNAError('Label must be in Normalization Form C') - - -def valid_contextj(label, pos): - - cp_value = ord(label[pos]) - - if cp_value == 0x200c: - - if pos > 0: - if _combining_class(ord(label[pos - 1])) == _virama_combining_class: - return True - - ok = False - for i in range(pos-1, -1, -1): - joining_type = idnadata.joining_types.get(ord(label[i])) - if joining_type == ord('T'): - continue - if joining_type in [ord('L'), ord('D')]: - ok = True - break - - if not ok: - return False - - ok = False - for i in range(pos+1, len(label)): - joining_type = idnadata.joining_types.get(ord(label[i])) - if joining_type == ord('T'): - continue - if joining_type in [ord('R'), ord('D')]: - ok = True - break - return ok - - if cp_value == 0x200d: - - if pos > 0: - if _combining_class(ord(label[pos - 1])) == _virama_combining_class: - return True - return False - - else: - - return False - - -def valid_contexto(label, pos, exception=False): - - cp_value = ord(label[pos]) - - if cp_value == 0x00b7: - if 0 < pos < len(label)-1: - if ord(label[pos - 1]) == 0x006c and ord(label[pos + 1]) == 0x006c: - return True - return False - - elif cp_value == 0x0375: - if pos < len(label)-1 and len(label) > 1: - return _is_script(label[pos + 1], 'Greek') - return False - - elif cp_value == 0x05f3 or cp_value == 0x05f4: - if pos > 0: - return _is_script(label[pos - 1], 'Hebrew') - return False - - elif cp_value == 0x30fb: - for cp in label: - if cp == u'\u30fb': - continue - if _is_script(cp, 'Hiragana') or _is_script(cp, 'Katakana') or _is_script(cp, 'Han'): - return True - return False - - elif 0x660 <= cp_value <= 0x669: - for cp in label: - if 0x6f0 <= ord(cp) <= 0x06f9: - return False - return True - - elif 0x6f0 <= cp_value <= 0x6f9: - for cp in label: - if 0x660 <= ord(cp) <= 0x0669: - return False - return True - - -def check_label(label): - - if isinstance(label, (bytes, bytearray)): - label = label.decode('utf-8') - if len(label) == 0: - raise IDNAError('Empty Label') - - check_nfc(label) - check_hyphen_ok(label) - check_initial_combiner(label) - - for (pos, cp) in enumerate(label): - cp_value = ord(cp) - if intranges_contain(cp_value, idnadata.codepoint_classes['PVALID']): - continue - elif intranges_contain(cp_value, idnadata.codepoint_classes['CONTEXTJ']): - try: - if not valid_contextj(label, pos): - raise InvalidCodepointContext('Joiner {0} not allowed at position {1} in {2}'.format( - _unot(cp_value), pos+1, repr(label))) - except ValueError: - raise IDNAError('Unknown codepoint adjacent to joiner {0} at position {1} in {2}'.format( - _unot(cp_value), pos+1, repr(label))) - elif intranges_contain(cp_value, idnadata.codepoint_classes['CONTEXTO']): - if not valid_contexto(label, pos): - raise InvalidCodepointContext('Codepoint {0} not allowed at position {1} in {2}'.format(_unot(cp_value), pos+1, repr(label))) - else: - raise InvalidCodepoint('Codepoint {0} at position {1} of {2} not allowed'.format(_unot(cp_value), pos+1, repr(label))) - - check_bidi(label) - - -def alabel(label): - - try: - label = label.encode('ascii') - ulabel(label) - if not valid_label_length(label): - raise IDNAError('Label too long') - return label - except UnicodeEncodeError: - pass - - if not label: - raise IDNAError('No Input') - - label = unicode(label) - check_label(label) - label = _punycode(label) - label = _alabel_prefix + label - - if not valid_label_length(label): - raise IDNAError('Label too long') - - return label - - -def ulabel(label): - - if not isinstance(label, (bytes, bytearray)): - try: - label = label.encode('ascii') - except UnicodeEncodeError: - check_label(label) - return label - - label = label.lower() - if label.startswith(_alabel_prefix): - label = label[len(_alabel_prefix):] - if not label: - raise IDNAError('Malformed A-label, no Punycode eligible content found') - if label.decode('ascii')[-1] == '-': - raise IDNAError('A-label must not end with a hyphen') - else: - check_label(label) - return label.decode('ascii') - - label = label.decode('punycode') - check_label(label) - return label - - -def uts46_remap(domain, std3_rules=True, transitional=False): - """Re-map the characters in the string according to UTS46 processing.""" - from .uts46data import uts46data - output = u"" - try: - for pos, char in enumerate(domain): - code_point = ord(char) - uts46row = uts46data[code_point if code_point < 256 else - bisect.bisect_left(uts46data, (code_point, "Z")) - 1] - status = uts46row[1] - replacement = uts46row[2] if len(uts46row) == 3 else None - if (status == "V" or - (status == "D" and not transitional) or - (status == "3" and not std3_rules and replacement is None)): - output += char - elif replacement is not None and (status == "M" or - (status == "3" and not std3_rules) or - (status == "D" and transitional)): - output += replacement - elif status != "I": - raise IndexError() - return unicodedata.normalize("NFC", output) - except IndexError: - raise InvalidCodepoint( - "Codepoint {0} not allowed at position {1} in {2}".format( - _unot(code_point), pos + 1, repr(domain))) - - -def encode(s, strict=False, uts46=False, std3_rules=False, transitional=False): - - if isinstance(s, (bytes, bytearray)): - s = s.decode("ascii") - if uts46: - s = uts46_remap(s, std3_rules, transitional) - trailing_dot = False - result = [] - if strict: - labels = s.split('.') - else: - labels = _unicode_dots_re.split(s) - if not labels or labels == ['']: - raise IDNAError('Empty domain') - if labels[-1] == '': - del labels[-1] - trailing_dot = True - for label in labels: - s = alabel(label) - if s: - result.append(s) - else: - raise IDNAError('Empty label') - if trailing_dot: - result.append(b'') - s = b'.'.join(result) - if not valid_string_length(s, trailing_dot): - raise IDNAError('Domain too long') - return s - - -def decode(s, strict=False, uts46=False, std3_rules=False): - - if isinstance(s, (bytes, bytearray)): - s = s.decode("ascii") - if uts46: - s = uts46_remap(s, std3_rules, False) - trailing_dot = False - result = [] - if not strict: - labels = _unicode_dots_re.split(s) - else: - labels = s.split(u'.') - if not labels or labels == ['']: - raise IDNAError('Empty domain') - if not labels[-1]: - del labels[-1] - trailing_dot = True - for label in labels: - s = ulabel(label) - if s: - result.append(s) - else: - raise IDNAError('Empty label') - if trailing_dot: - result.append(u'') - return u'.'.join(result) diff --git a/venv/lib/python3.8/site-packages/idna/idnadata.py b/venv/lib/python3.8/site-packages/idna/idnadata.py deleted file mode 100644 index a284e4c..0000000 --- a/venv/lib/python3.8/site-packages/idna/idnadata.py +++ /dev/null @@ -1,2050 +0,0 @@ -# This file is automatically generated by tools/idna-data - -__version__ = "13.0.0" -scripts = { - 'Greek': ( - 0x37000000374, - 0x37500000378, - 0x37a0000037e, - 0x37f00000380, - 0x38400000385, - 0x38600000387, - 0x3880000038b, - 0x38c0000038d, - 0x38e000003a2, - 0x3a3000003e2, - 0x3f000000400, - 0x1d2600001d2b, - 0x1d5d00001d62, - 0x1d6600001d6b, - 0x1dbf00001dc0, - 0x1f0000001f16, - 0x1f1800001f1e, - 0x1f2000001f46, - 0x1f4800001f4e, - 0x1f5000001f58, - 0x1f5900001f5a, - 0x1f5b00001f5c, - 0x1f5d00001f5e, - 0x1f5f00001f7e, - 0x1f8000001fb5, - 0x1fb600001fc5, - 0x1fc600001fd4, - 0x1fd600001fdc, - 0x1fdd00001ff0, - 0x1ff200001ff5, - 0x1ff600001fff, - 0x212600002127, - 0xab650000ab66, - 0x101400001018f, - 0x101a0000101a1, - 0x1d2000001d246, - ), - 'Han': ( - 0x2e8000002e9a, - 0x2e9b00002ef4, - 0x2f0000002fd6, - 0x300500003006, - 0x300700003008, - 0x30210000302a, - 0x30380000303c, - 0x340000004dc0, - 0x4e0000009ffd, - 0xf9000000fa6e, - 0xfa700000fada, - 0x16ff000016ff2, - 0x200000002a6de, - 0x2a7000002b735, - 0x2b7400002b81e, - 0x2b8200002cea2, - 0x2ceb00002ebe1, - 0x2f8000002fa1e, - 0x300000003134b, - ), - 'Hebrew': ( - 0x591000005c8, - 0x5d0000005eb, - 0x5ef000005f5, - 0xfb1d0000fb37, - 0xfb380000fb3d, - 0xfb3e0000fb3f, - 0xfb400000fb42, - 0xfb430000fb45, - 0xfb460000fb50, - ), - 'Hiragana': ( - 0x304100003097, - 0x309d000030a0, - 0x1b0010001b11f, - 0x1b1500001b153, - 0x1f2000001f201, - ), - 'Katakana': ( - 0x30a1000030fb, - 0x30fd00003100, - 0x31f000003200, - 0x32d0000032ff, - 0x330000003358, - 0xff660000ff70, - 0xff710000ff9e, - 0x1b0000001b001, - 0x1b1640001b168, - ), -} -joining_types = { - 0x600: 85, - 0x601: 85, - 0x602: 85, - 0x603: 85, - 0x604: 85, - 0x605: 85, - 0x608: 85, - 0x60b: 85, - 0x620: 68, - 0x621: 85, - 0x622: 82, - 0x623: 82, - 0x624: 82, - 0x625: 82, - 0x626: 68, - 0x627: 82, - 0x628: 68, - 0x629: 82, - 0x62a: 68, - 0x62b: 68, - 0x62c: 68, - 0x62d: 68, - 0x62e: 68, - 0x62f: 82, - 0x630: 82, - 0x631: 82, - 0x632: 82, - 0x633: 68, - 0x634: 68, - 0x635: 68, - 0x636: 68, - 0x637: 68, - 0x638: 68, - 0x639: 68, - 0x63a: 68, - 0x63b: 68, - 0x63c: 68, - 0x63d: 68, - 0x63e: 68, - 0x63f: 68, - 0x640: 67, - 0x641: 68, - 0x642: 68, - 0x643: 68, - 0x644: 68, - 0x645: 68, - 0x646: 68, - 0x647: 68, - 0x648: 82, - 0x649: 68, - 0x64a: 68, - 0x66e: 68, - 0x66f: 68, - 0x671: 82, - 0x672: 82, - 0x673: 82, - 0x674: 85, - 0x675: 82, - 0x676: 82, - 0x677: 82, - 0x678: 68, - 0x679: 68, - 0x67a: 68, - 0x67b: 68, - 0x67c: 68, - 0x67d: 68, - 0x67e: 68, - 0x67f: 68, - 0x680: 68, - 0x681: 68, - 0x682: 68, - 0x683: 68, - 0x684: 68, - 0x685: 68, - 0x686: 68, - 0x687: 68, - 0x688: 82, - 0x689: 82, - 0x68a: 82, - 0x68b: 82, - 0x68c: 82, - 0x68d: 82, - 0x68e: 82, - 0x68f: 82, - 0x690: 82, - 0x691: 82, - 0x692: 82, - 0x693: 82, - 0x694: 82, - 0x695: 82, - 0x696: 82, - 0x697: 82, - 0x698: 82, - 0x699: 82, - 0x69a: 68, - 0x69b: 68, - 0x69c: 68, - 0x69d: 68, - 0x69e: 68, - 0x69f: 68, - 0x6a0: 68, - 0x6a1: 68, - 0x6a2: 68, - 0x6a3: 68, - 0x6a4: 68, - 0x6a5: 68, - 0x6a6: 68, - 0x6a7: 68, - 0x6a8: 68, - 0x6a9: 68, - 0x6aa: 68, - 0x6ab: 68, - 0x6ac: 68, - 0x6ad: 68, - 0x6ae: 68, - 0x6af: 68, - 0x6b0: 68, - 0x6b1: 68, - 0x6b2: 68, - 0x6b3: 68, - 0x6b4: 68, - 0x6b5: 68, - 0x6b6: 68, - 0x6b7: 68, - 0x6b8: 68, - 0x6b9: 68, - 0x6ba: 68, - 0x6bb: 68, - 0x6bc: 68, - 0x6bd: 68, - 0x6be: 68, - 0x6bf: 68, - 0x6c0: 82, - 0x6c1: 68, - 0x6c2: 68, - 0x6c3: 82, - 0x6c4: 82, - 0x6c5: 82, - 0x6c6: 82, - 0x6c7: 82, - 0x6c8: 82, - 0x6c9: 82, - 0x6ca: 82, - 0x6cb: 82, - 0x6cc: 68, - 0x6cd: 82, - 0x6ce: 68, - 0x6cf: 82, - 0x6d0: 68, - 0x6d1: 68, - 0x6d2: 82, - 0x6d3: 82, - 0x6d5: 82, - 0x6dd: 85, - 0x6ee: 82, - 0x6ef: 82, - 0x6fa: 68, - 0x6fb: 68, - 0x6fc: 68, - 0x6ff: 68, - 0x70f: 84, - 0x710: 82, - 0x712: 68, - 0x713: 68, - 0x714: 68, - 0x715: 82, - 0x716: 82, - 0x717: 82, - 0x718: 82, - 0x719: 82, - 0x71a: 68, - 0x71b: 68, - 0x71c: 68, - 0x71d: 68, - 0x71e: 82, - 0x71f: 68, - 0x720: 68, - 0x721: 68, - 0x722: 68, - 0x723: 68, - 0x724: 68, - 0x725: 68, - 0x726: 68, - 0x727: 68, - 0x728: 82, - 0x729: 68, - 0x72a: 82, - 0x72b: 68, - 0x72c: 82, - 0x72d: 68, - 0x72e: 68, - 0x72f: 82, - 0x74d: 82, - 0x74e: 68, - 0x74f: 68, - 0x750: 68, - 0x751: 68, - 0x752: 68, - 0x753: 68, - 0x754: 68, - 0x755: 68, - 0x756: 68, - 0x757: 68, - 0x758: 68, - 0x759: 82, - 0x75a: 82, - 0x75b: 82, - 0x75c: 68, - 0x75d: 68, - 0x75e: 68, - 0x75f: 68, - 0x760: 68, - 0x761: 68, - 0x762: 68, - 0x763: 68, - 0x764: 68, - 0x765: 68, - 0x766: 68, - 0x767: 68, - 0x768: 68, - 0x769: 68, - 0x76a: 68, - 0x76b: 82, - 0x76c: 82, - 0x76d: 68, - 0x76e: 68, - 0x76f: 68, - 0x770: 68, - 0x771: 82, - 0x772: 68, - 0x773: 82, - 0x774: 82, - 0x775: 68, - 0x776: 68, - 0x777: 68, - 0x778: 82, - 0x779: 82, - 0x77a: 68, - 0x77b: 68, - 0x77c: 68, - 0x77d: 68, - 0x77e: 68, - 0x77f: 68, - 0x7ca: 68, - 0x7cb: 68, - 0x7cc: 68, - 0x7cd: 68, - 0x7ce: 68, - 0x7cf: 68, - 0x7d0: 68, - 0x7d1: 68, - 0x7d2: 68, - 0x7d3: 68, - 0x7d4: 68, - 0x7d5: 68, - 0x7d6: 68, - 0x7d7: 68, - 0x7d8: 68, - 0x7d9: 68, - 0x7da: 68, - 0x7db: 68, - 0x7dc: 68, - 0x7dd: 68, - 0x7de: 68, - 0x7df: 68, - 0x7e0: 68, - 0x7e1: 68, - 0x7e2: 68, - 0x7e3: 68, - 0x7e4: 68, - 0x7e5: 68, - 0x7e6: 68, - 0x7e7: 68, - 0x7e8: 68, - 0x7e9: 68, - 0x7ea: 68, - 0x7fa: 67, - 0x840: 82, - 0x841: 68, - 0x842: 68, - 0x843: 68, - 0x844: 68, - 0x845: 68, - 0x846: 82, - 0x847: 82, - 0x848: 68, - 0x849: 82, - 0x84a: 68, - 0x84b: 68, - 0x84c: 68, - 0x84d: 68, - 0x84e: 68, - 0x84f: 68, - 0x850: 68, - 0x851: 68, - 0x852: 68, - 0x853: 68, - 0x854: 82, - 0x855: 68, - 0x856: 82, - 0x857: 82, - 0x858: 82, - 0x860: 68, - 0x861: 85, - 0x862: 68, - 0x863: 68, - 0x864: 68, - 0x865: 68, - 0x866: 85, - 0x867: 82, - 0x868: 68, - 0x869: 82, - 0x86a: 82, - 0x8a0: 68, - 0x8a1: 68, - 0x8a2: 68, - 0x8a3: 68, - 0x8a4: 68, - 0x8a5: 68, - 0x8a6: 68, - 0x8a7: 68, - 0x8a8: 68, - 0x8a9: 68, - 0x8aa: 82, - 0x8ab: 82, - 0x8ac: 82, - 0x8ad: 85, - 0x8ae: 82, - 0x8af: 68, - 0x8b0: 68, - 0x8b1: 82, - 0x8b2: 82, - 0x8b3: 68, - 0x8b4: 68, - 0x8b6: 68, - 0x8b7: 68, - 0x8b8: 68, - 0x8b9: 82, - 0x8ba: 68, - 0x8bb: 68, - 0x8bc: 68, - 0x8bd: 68, - 0x8be: 68, - 0x8bf: 68, - 0x8c0: 68, - 0x8c1: 68, - 0x8c2: 68, - 0x8c3: 68, - 0x8c4: 68, - 0x8c5: 68, - 0x8c6: 68, - 0x8c7: 68, - 0x8e2: 85, - 0x1806: 85, - 0x1807: 68, - 0x180a: 67, - 0x180e: 85, - 0x1820: 68, - 0x1821: 68, - 0x1822: 68, - 0x1823: 68, - 0x1824: 68, - 0x1825: 68, - 0x1826: 68, - 0x1827: 68, - 0x1828: 68, - 0x1829: 68, - 0x182a: 68, - 0x182b: 68, - 0x182c: 68, - 0x182d: 68, - 0x182e: 68, - 0x182f: 68, - 0x1830: 68, - 0x1831: 68, - 0x1832: 68, - 0x1833: 68, - 0x1834: 68, - 0x1835: 68, - 0x1836: 68, - 0x1837: 68, - 0x1838: 68, - 0x1839: 68, - 0x183a: 68, - 0x183b: 68, - 0x183c: 68, - 0x183d: 68, - 0x183e: 68, - 0x183f: 68, - 0x1840: 68, - 0x1841: 68, - 0x1842: 68, - 0x1843: 68, - 0x1844: 68, - 0x1845: 68, - 0x1846: 68, - 0x1847: 68, - 0x1848: 68, - 0x1849: 68, - 0x184a: 68, - 0x184b: 68, - 0x184c: 68, - 0x184d: 68, - 0x184e: 68, - 0x184f: 68, - 0x1850: 68, - 0x1851: 68, - 0x1852: 68, - 0x1853: 68, - 0x1854: 68, - 0x1855: 68, - 0x1856: 68, - 0x1857: 68, - 0x1858: 68, - 0x1859: 68, - 0x185a: 68, - 0x185b: 68, - 0x185c: 68, - 0x185d: 68, - 0x185e: 68, - 0x185f: 68, - 0x1860: 68, - 0x1861: 68, - 0x1862: 68, - 0x1863: 68, - 0x1864: 68, - 0x1865: 68, - 0x1866: 68, - 0x1867: 68, - 0x1868: 68, - 0x1869: 68, - 0x186a: 68, - 0x186b: 68, - 0x186c: 68, - 0x186d: 68, - 0x186e: 68, - 0x186f: 68, - 0x1870: 68, - 0x1871: 68, - 0x1872: 68, - 0x1873: 68, - 0x1874: 68, - 0x1875: 68, - 0x1876: 68, - 0x1877: 68, - 0x1878: 68, - 0x1880: 85, - 0x1881: 85, - 0x1882: 85, - 0x1883: 85, - 0x1884: 85, - 0x1885: 84, - 0x1886: 84, - 0x1887: 68, - 0x1888: 68, - 0x1889: 68, - 0x188a: 68, - 0x188b: 68, - 0x188c: 68, - 0x188d: 68, - 0x188e: 68, - 0x188f: 68, - 0x1890: 68, - 0x1891: 68, - 0x1892: 68, - 0x1893: 68, - 0x1894: 68, - 0x1895: 68, - 0x1896: 68, - 0x1897: 68, - 0x1898: 68, - 0x1899: 68, - 0x189a: 68, - 0x189b: 68, - 0x189c: 68, - 0x189d: 68, - 0x189e: 68, - 0x189f: 68, - 0x18a0: 68, - 0x18a1: 68, - 0x18a2: 68, - 0x18a3: 68, - 0x18a4: 68, - 0x18a5: 68, - 0x18a6: 68, - 0x18a7: 68, - 0x18a8: 68, - 0x18aa: 68, - 0x200c: 85, - 0x200d: 67, - 0x202f: 85, - 0x2066: 85, - 0x2067: 85, - 0x2068: 85, - 0x2069: 85, - 0xa840: 68, - 0xa841: 68, - 0xa842: 68, - 0xa843: 68, - 0xa844: 68, - 0xa845: 68, - 0xa846: 68, - 0xa847: 68, - 0xa848: 68, - 0xa849: 68, - 0xa84a: 68, - 0xa84b: 68, - 0xa84c: 68, - 0xa84d: 68, - 0xa84e: 68, - 0xa84f: 68, - 0xa850: 68, - 0xa851: 68, - 0xa852: 68, - 0xa853: 68, - 0xa854: 68, - 0xa855: 68, - 0xa856: 68, - 0xa857: 68, - 0xa858: 68, - 0xa859: 68, - 0xa85a: 68, - 0xa85b: 68, - 0xa85c: 68, - 0xa85d: 68, - 0xa85e: 68, - 0xa85f: 68, - 0xa860: 68, - 0xa861: 68, - 0xa862: 68, - 0xa863: 68, - 0xa864: 68, - 0xa865: 68, - 0xa866: 68, - 0xa867: 68, - 0xa868: 68, - 0xa869: 68, - 0xa86a: 68, - 0xa86b: 68, - 0xa86c: 68, - 0xa86d: 68, - 0xa86e: 68, - 0xa86f: 68, - 0xa870: 68, - 0xa871: 68, - 0xa872: 76, - 0xa873: 85, - 0x10ac0: 68, - 0x10ac1: 68, - 0x10ac2: 68, - 0x10ac3: 68, - 0x10ac4: 68, - 0x10ac5: 82, - 0x10ac6: 85, - 0x10ac7: 82, - 0x10ac8: 85, - 0x10ac9: 82, - 0x10aca: 82, - 0x10acb: 85, - 0x10acc: 85, - 0x10acd: 76, - 0x10ace: 82, - 0x10acf: 82, - 0x10ad0: 82, - 0x10ad1: 82, - 0x10ad2: 82, - 0x10ad3: 68, - 0x10ad4: 68, - 0x10ad5: 68, - 0x10ad6: 68, - 0x10ad7: 76, - 0x10ad8: 68, - 0x10ad9: 68, - 0x10ada: 68, - 0x10adb: 68, - 0x10adc: 68, - 0x10add: 82, - 0x10ade: 68, - 0x10adf: 68, - 0x10ae0: 68, - 0x10ae1: 82, - 0x10ae2: 85, - 0x10ae3: 85, - 0x10ae4: 82, - 0x10aeb: 68, - 0x10aec: 68, - 0x10aed: 68, - 0x10aee: 68, - 0x10aef: 82, - 0x10b80: 68, - 0x10b81: 82, - 0x10b82: 68, - 0x10b83: 82, - 0x10b84: 82, - 0x10b85: 82, - 0x10b86: 68, - 0x10b87: 68, - 0x10b88: 68, - 0x10b89: 82, - 0x10b8a: 68, - 0x10b8b: 68, - 0x10b8c: 82, - 0x10b8d: 68, - 0x10b8e: 82, - 0x10b8f: 82, - 0x10b90: 68, - 0x10b91: 82, - 0x10ba9: 82, - 0x10baa: 82, - 0x10bab: 82, - 0x10bac: 82, - 0x10bad: 68, - 0x10bae: 68, - 0x10baf: 85, - 0x10d00: 76, - 0x10d01: 68, - 0x10d02: 68, - 0x10d03: 68, - 0x10d04: 68, - 0x10d05: 68, - 0x10d06: 68, - 0x10d07: 68, - 0x10d08: 68, - 0x10d09: 68, - 0x10d0a: 68, - 0x10d0b: 68, - 0x10d0c: 68, - 0x10d0d: 68, - 0x10d0e: 68, - 0x10d0f: 68, - 0x10d10: 68, - 0x10d11: 68, - 0x10d12: 68, - 0x10d13: 68, - 0x10d14: 68, - 0x10d15: 68, - 0x10d16: 68, - 0x10d17: 68, - 0x10d18: 68, - 0x10d19: 68, - 0x10d1a: 68, - 0x10d1b: 68, - 0x10d1c: 68, - 0x10d1d: 68, - 0x10d1e: 68, - 0x10d1f: 68, - 0x10d20: 68, - 0x10d21: 68, - 0x10d22: 82, - 0x10d23: 68, - 0x10f30: 68, - 0x10f31: 68, - 0x10f32: 68, - 0x10f33: 82, - 0x10f34: 68, - 0x10f35: 68, - 0x10f36: 68, - 0x10f37: 68, - 0x10f38: 68, - 0x10f39: 68, - 0x10f3a: 68, - 0x10f3b: 68, - 0x10f3c: 68, - 0x10f3d: 68, - 0x10f3e: 68, - 0x10f3f: 68, - 0x10f40: 68, - 0x10f41: 68, - 0x10f42: 68, - 0x10f43: 68, - 0x10f44: 68, - 0x10f45: 85, - 0x10f51: 68, - 0x10f52: 68, - 0x10f53: 68, - 0x10f54: 82, - 0x10fb0: 68, - 0x10fb1: 85, - 0x10fb2: 68, - 0x10fb3: 68, - 0x10fb4: 82, - 0x10fb5: 82, - 0x10fb6: 82, - 0x10fb7: 85, - 0x10fb8: 68, - 0x10fb9: 82, - 0x10fba: 82, - 0x10fbb: 68, - 0x10fbc: 68, - 0x10fbd: 82, - 0x10fbe: 68, - 0x10fbf: 68, - 0x10fc0: 85, - 0x10fc1: 68, - 0x10fc2: 82, - 0x10fc3: 82, - 0x10fc4: 68, - 0x10fc5: 85, - 0x10fc6: 85, - 0x10fc7: 85, - 0x10fc8: 85, - 0x10fc9: 82, - 0x10fca: 68, - 0x10fcb: 76, - 0x110bd: 85, - 0x110cd: 85, - 0x1e900: 68, - 0x1e901: 68, - 0x1e902: 68, - 0x1e903: 68, - 0x1e904: 68, - 0x1e905: 68, - 0x1e906: 68, - 0x1e907: 68, - 0x1e908: 68, - 0x1e909: 68, - 0x1e90a: 68, - 0x1e90b: 68, - 0x1e90c: 68, - 0x1e90d: 68, - 0x1e90e: 68, - 0x1e90f: 68, - 0x1e910: 68, - 0x1e911: 68, - 0x1e912: 68, - 0x1e913: 68, - 0x1e914: 68, - 0x1e915: 68, - 0x1e916: 68, - 0x1e917: 68, - 0x1e918: 68, - 0x1e919: 68, - 0x1e91a: 68, - 0x1e91b: 68, - 0x1e91c: 68, - 0x1e91d: 68, - 0x1e91e: 68, - 0x1e91f: 68, - 0x1e920: 68, - 0x1e921: 68, - 0x1e922: 68, - 0x1e923: 68, - 0x1e924: 68, - 0x1e925: 68, - 0x1e926: 68, - 0x1e927: 68, - 0x1e928: 68, - 0x1e929: 68, - 0x1e92a: 68, - 0x1e92b: 68, - 0x1e92c: 68, - 0x1e92d: 68, - 0x1e92e: 68, - 0x1e92f: 68, - 0x1e930: 68, - 0x1e931: 68, - 0x1e932: 68, - 0x1e933: 68, - 0x1e934: 68, - 0x1e935: 68, - 0x1e936: 68, - 0x1e937: 68, - 0x1e938: 68, - 0x1e939: 68, - 0x1e93a: 68, - 0x1e93b: 68, - 0x1e93c: 68, - 0x1e93d: 68, - 0x1e93e: 68, - 0x1e93f: 68, - 0x1e940: 68, - 0x1e941: 68, - 0x1e942: 68, - 0x1e943: 68, - 0x1e94b: 84, -} -codepoint_classes = { - 'PVALID': ( - 0x2d0000002e, - 0x300000003a, - 0x610000007b, - 0xdf000000f7, - 0xf800000100, - 0x10100000102, - 0x10300000104, - 0x10500000106, - 0x10700000108, - 0x1090000010a, - 0x10b0000010c, - 0x10d0000010e, - 0x10f00000110, - 0x11100000112, - 0x11300000114, - 0x11500000116, - 0x11700000118, - 0x1190000011a, - 0x11b0000011c, - 0x11d0000011e, - 0x11f00000120, - 0x12100000122, - 0x12300000124, - 0x12500000126, - 0x12700000128, - 0x1290000012a, - 0x12b0000012c, - 0x12d0000012e, - 0x12f00000130, - 0x13100000132, - 0x13500000136, - 0x13700000139, - 0x13a0000013b, - 0x13c0000013d, - 0x13e0000013f, - 0x14200000143, - 0x14400000145, - 0x14600000147, - 0x14800000149, - 0x14b0000014c, - 0x14d0000014e, - 0x14f00000150, - 0x15100000152, - 0x15300000154, - 0x15500000156, - 0x15700000158, - 0x1590000015a, - 0x15b0000015c, - 0x15d0000015e, - 0x15f00000160, - 0x16100000162, - 0x16300000164, - 0x16500000166, - 0x16700000168, - 0x1690000016a, - 0x16b0000016c, - 0x16d0000016e, - 0x16f00000170, - 0x17100000172, - 0x17300000174, - 0x17500000176, - 0x17700000178, - 0x17a0000017b, - 0x17c0000017d, - 0x17e0000017f, - 0x18000000181, - 0x18300000184, - 0x18500000186, - 0x18800000189, - 0x18c0000018e, - 0x19200000193, - 0x19500000196, - 0x1990000019c, - 0x19e0000019f, - 0x1a1000001a2, - 0x1a3000001a4, - 0x1a5000001a6, - 0x1a8000001a9, - 0x1aa000001ac, - 0x1ad000001ae, - 0x1b0000001b1, - 0x1b4000001b5, - 0x1b6000001b7, - 0x1b9000001bc, - 0x1bd000001c4, - 0x1ce000001cf, - 0x1d0000001d1, - 0x1d2000001d3, - 0x1d4000001d5, - 0x1d6000001d7, - 0x1d8000001d9, - 0x1da000001db, - 0x1dc000001de, - 0x1df000001e0, - 0x1e1000001e2, - 0x1e3000001e4, - 0x1e5000001e6, - 0x1e7000001e8, - 0x1e9000001ea, - 0x1eb000001ec, - 0x1ed000001ee, - 0x1ef000001f1, - 0x1f5000001f6, - 0x1f9000001fa, - 0x1fb000001fc, - 0x1fd000001fe, - 0x1ff00000200, - 0x20100000202, - 0x20300000204, - 0x20500000206, - 0x20700000208, - 0x2090000020a, - 0x20b0000020c, - 0x20d0000020e, - 0x20f00000210, - 0x21100000212, - 0x21300000214, - 0x21500000216, - 0x21700000218, - 0x2190000021a, - 0x21b0000021c, - 0x21d0000021e, - 0x21f00000220, - 0x22100000222, - 0x22300000224, - 0x22500000226, - 0x22700000228, - 0x2290000022a, - 0x22b0000022c, - 0x22d0000022e, - 0x22f00000230, - 0x23100000232, - 0x2330000023a, - 0x23c0000023d, - 0x23f00000241, - 0x24200000243, - 0x24700000248, - 0x2490000024a, - 0x24b0000024c, - 0x24d0000024e, - 0x24f000002b0, - 0x2b9000002c2, - 0x2c6000002d2, - 0x2ec000002ed, - 0x2ee000002ef, - 0x30000000340, - 0x34200000343, - 0x3460000034f, - 0x35000000370, - 0x37100000372, - 0x37300000374, - 0x37700000378, - 0x37b0000037e, - 0x39000000391, - 0x3ac000003cf, - 0x3d7000003d8, - 0x3d9000003da, - 0x3db000003dc, - 0x3dd000003de, - 0x3df000003e0, - 0x3e1000003e2, - 0x3e3000003e4, - 0x3e5000003e6, - 0x3e7000003e8, - 0x3e9000003ea, - 0x3eb000003ec, - 0x3ed000003ee, - 0x3ef000003f0, - 0x3f3000003f4, - 0x3f8000003f9, - 0x3fb000003fd, - 0x43000000460, - 0x46100000462, - 0x46300000464, - 0x46500000466, - 0x46700000468, - 0x4690000046a, - 0x46b0000046c, - 0x46d0000046e, - 0x46f00000470, - 0x47100000472, - 0x47300000474, - 0x47500000476, - 0x47700000478, - 0x4790000047a, - 0x47b0000047c, - 0x47d0000047e, - 0x47f00000480, - 0x48100000482, - 0x48300000488, - 0x48b0000048c, - 0x48d0000048e, - 0x48f00000490, - 0x49100000492, - 0x49300000494, - 0x49500000496, - 0x49700000498, - 0x4990000049a, - 0x49b0000049c, - 0x49d0000049e, - 0x49f000004a0, - 0x4a1000004a2, - 0x4a3000004a4, - 0x4a5000004a6, - 0x4a7000004a8, - 0x4a9000004aa, - 0x4ab000004ac, - 0x4ad000004ae, - 0x4af000004b0, - 0x4b1000004b2, - 0x4b3000004b4, - 0x4b5000004b6, - 0x4b7000004b8, - 0x4b9000004ba, - 0x4bb000004bc, - 0x4bd000004be, - 0x4bf000004c0, - 0x4c2000004c3, - 0x4c4000004c5, - 0x4c6000004c7, - 0x4c8000004c9, - 0x4ca000004cb, - 0x4cc000004cd, - 0x4ce000004d0, - 0x4d1000004d2, - 0x4d3000004d4, - 0x4d5000004d6, - 0x4d7000004d8, - 0x4d9000004da, - 0x4db000004dc, - 0x4dd000004de, - 0x4df000004e0, - 0x4e1000004e2, - 0x4e3000004e4, - 0x4e5000004e6, - 0x4e7000004e8, - 0x4e9000004ea, - 0x4eb000004ec, - 0x4ed000004ee, - 0x4ef000004f0, - 0x4f1000004f2, - 0x4f3000004f4, - 0x4f5000004f6, - 0x4f7000004f8, - 0x4f9000004fa, - 0x4fb000004fc, - 0x4fd000004fe, - 0x4ff00000500, - 0x50100000502, - 0x50300000504, - 0x50500000506, - 0x50700000508, - 0x5090000050a, - 0x50b0000050c, - 0x50d0000050e, - 0x50f00000510, - 0x51100000512, - 0x51300000514, - 0x51500000516, - 0x51700000518, - 0x5190000051a, - 0x51b0000051c, - 0x51d0000051e, - 0x51f00000520, - 0x52100000522, - 0x52300000524, - 0x52500000526, - 0x52700000528, - 0x5290000052a, - 0x52b0000052c, - 0x52d0000052e, - 0x52f00000530, - 0x5590000055a, - 0x56000000587, - 0x58800000589, - 0x591000005be, - 0x5bf000005c0, - 0x5c1000005c3, - 0x5c4000005c6, - 0x5c7000005c8, - 0x5d0000005eb, - 0x5ef000005f3, - 0x6100000061b, - 0x62000000640, - 0x64100000660, - 0x66e00000675, - 0x679000006d4, - 0x6d5000006dd, - 0x6df000006e9, - 0x6ea000006f0, - 0x6fa00000700, - 0x7100000074b, - 0x74d000007b2, - 0x7c0000007f6, - 0x7fd000007fe, - 0x8000000082e, - 0x8400000085c, - 0x8600000086b, - 0x8a0000008b5, - 0x8b6000008c8, - 0x8d3000008e2, - 0x8e300000958, - 0x96000000964, - 0x96600000970, - 0x97100000984, - 0x9850000098d, - 0x98f00000991, - 0x993000009a9, - 0x9aa000009b1, - 0x9b2000009b3, - 0x9b6000009ba, - 0x9bc000009c5, - 0x9c7000009c9, - 0x9cb000009cf, - 0x9d7000009d8, - 0x9e0000009e4, - 0x9e6000009f2, - 0x9fc000009fd, - 0x9fe000009ff, - 0xa0100000a04, - 0xa0500000a0b, - 0xa0f00000a11, - 0xa1300000a29, - 0xa2a00000a31, - 0xa3200000a33, - 0xa3500000a36, - 0xa3800000a3a, - 0xa3c00000a3d, - 0xa3e00000a43, - 0xa4700000a49, - 0xa4b00000a4e, - 0xa5100000a52, - 0xa5c00000a5d, - 0xa6600000a76, - 0xa8100000a84, - 0xa8500000a8e, - 0xa8f00000a92, - 0xa9300000aa9, - 0xaaa00000ab1, - 0xab200000ab4, - 0xab500000aba, - 0xabc00000ac6, - 0xac700000aca, - 0xacb00000ace, - 0xad000000ad1, - 0xae000000ae4, - 0xae600000af0, - 0xaf900000b00, - 0xb0100000b04, - 0xb0500000b0d, - 0xb0f00000b11, - 0xb1300000b29, - 0xb2a00000b31, - 0xb3200000b34, - 0xb3500000b3a, - 0xb3c00000b45, - 0xb4700000b49, - 0xb4b00000b4e, - 0xb5500000b58, - 0xb5f00000b64, - 0xb6600000b70, - 0xb7100000b72, - 0xb8200000b84, - 0xb8500000b8b, - 0xb8e00000b91, - 0xb9200000b96, - 0xb9900000b9b, - 0xb9c00000b9d, - 0xb9e00000ba0, - 0xba300000ba5, - 0xba800000bab, - 0xbae00000bba, - 0xbbe00000bc3, - 0xbc600000bc9, - 0xbca00000bce, - 0xbd000000bd1, - 0xbd700000bd8, - 0xbe600000bf0, - 0xc0000000c0d, - 0xc0e00000c11, - 0xc1200000c29, - 0xc2a00000c3a, - 0xc3d00000c45, - 0xc4600000c49, - 0xc4a00000c4e, - 0xc5500000c57, - 0xc5800000c5b, - 0xc6000000c64, - 0xc6600000c70, - 0xc8000000c84, - 0xc8500000c8d, - 0xc8e00000c91, - 0xc9200000ca9, - 0xcaa00000cb4, - 0xcb500000cba, - 0xcbc00000cc5, - 0xcc600000cc9, - 0xcca00000cce, - 0xcd500000cd7, - 0xcde00000cdf, - 0xce000000ce4, - 0xce600000cf0, - 0xcf100000cf3, - 0xd0000000d0d, - 0xd0e00000d11, - 0xd1200000d45, - 0xd4600000d49, - 0xd4a00000d4f, - 0xd5400000d58, - 0xd5f00000d64, - 0xd6600000d70, - 0xd7a00000d80, - 0xd8100000d84, - 0xd8500000d97, - 0xd9a00000db2, - 0xdb300000dbc, - 0xdbd00000dbe, - 0xdc000000dc7, - 0xdca00000dcb, - 0xdcf00000dd5, - 0xdd600000dd7, - 0xdd800000de0, - 0xde600000df0, - 0xdf200000df4, - 0xe0100000e33, - 0xe3400000e3b, - 0xe4000000e4f, - 0xe5000000e5a, - 0xe8100000e83, - 0xe8400000e85, - 0xe8600000e8b, - 0xe8c00000ea4, - 0xea500000ea6, - 0xea700000eb3, - 0xeb400000ebe, - 0xec000000ec5, - 0xec600000ec7, - 0xec800000ece, - 0xed000000eda, - 0xede00000ee0, - 0xf0000000f01, - 0xf0b00000f0c, - 0xf1800000f1a, - 0xf2000000f2a, - 0xf3500000f36, - 0xf3700000f38, - 0xf3900000f3a, - 0xf3e00000f43, - 0xf4400000f48, - 0xf4900000f4d, - 0xf4e00000f52, - 0xf5300000f57, - 0xf5800000f5c, - 0xf5d00000f69, - 0xf6a00000f6d, - 0xf7100000f73, - 0xf7400000f75, - 0xf7a00000f81, - 0xf8200000f85, - 0xf8600000f93, - 0xf9400000f98, - 0xf9900000f9d, - 0xf9e00000fa2, - 0xfa300000fa7, - 0xfa800000fac, - 0xfad00000fb9, - 0xfba00000fbd, - 0xfc600000fc7, - 0x10000000104a, - 0x10500000109e, - 0x10d0000010fb, - 0x10fd00001100, - 0x120000001249, - 0x124a0000124e, - 0x125000001257, - 0x125800001259, - 0x125a0000125e, - 0x126000001289, - 0x128a0000128e, - 0x1290000012b1, - 0x12b2000012b6, - 0x12b8000012bf, - 0x12c0000012c1, - 0x12c2000012c6, - 0x12c8000012d7, - 0x12d800001311, - 0x131200001316, - 0x13180000135b, - 0x135d00001360, - 0x138000001390, - 0x13a0000013f6, - 0x14010000166d, - 0x166f00001680, - 0x16810000169b, - 0x16a0000016eb, - 0x16f1000016f9, - 0x17000000170d, - 0x170e00001715, - 0x172000001735, - 0x174000001754, - 0x17600000176d, - 0x176e00001771, - 0x177200001774, - 0x1780000017b4, - 0x17b6000017d4, - 0x17d7000017d8, - 0x17dc000017de, - 0x17e0000017ea, - 0x18100000181a, - 0x182000001879, - 0x1880000018ab, - 0x18b0000018f6, - 0x19000000191f, - 0x19200000192c, - 0x19300000193c, - 0x19460000196e, - 0x197000001975, - 0x1980000019ac, - 0x19b0000019ca, - 0x19d0000019da, - 0x1a0000001a1c, - 0x1a2000001a5f, - 0x1a6000001a7d, - 0x1a7f00001a8a, - 0x1a9000001a9a, - 0x1aa700001aa8, - 0x1ab000001abe, - 0x1abf00001ac1, - 0x1b0000001b4c, - 0x1b5000001b5a, - 0x1b6b00001b74, - 0x1b8000001bf4, - 0x1c0000001c38, - 0x1c4000001c4a, - 0x1c4d00001c7e, - 0x1cd000001cd3, - 0x1cd400001cfb, - 0x1d0000001d2c, - 0x1d2f00001d30, - 0x1d3b00001d3c, - 0x1d4e00001d4f, - 0x1d6b00001d78, - 0x1d7900001d9b, - 0x1dc000001dfa, - 0x1dfb00001e00, - 0x1e0100001e02, - 0x1e0300001e04, - 0x1e0500001e06, - 0x1e0700001e08, - 0x1e0900001e0a, - 0x1e0b00001e0c, - 0x1e0d00001e0e, - 0x1e0f00001e10, - 0x1e1100001e12, - 0x1e1300001e14, - 0x1e1500001e16, - 0x1e1700001e18, - 0x1e1900001e1a, - 0x1e1b00001e1c, - 0x1e1d00001e1e, - 0x1e1f00001e20, - 0x1e2100001e22, - 0x1e2300001e24, - 0x1e2500001e26, - 0x1e2700001e28, - 0x1e2900001e2a, - 0x1e2b00001e2c, - 0x1e2d00001e2e, - 0x1e2f00001e30, - 0x1e3100001e32, - 0x1e3300001e34, - 0x1e3500001e36, - 0x1e3700001e38, - 0x1e3900001e3a, - 0x1e3b00001e3c, - 0x1e3d00001e3e, - 0x1e3f00001e40, - 0x1e4100001e42, - 0x1e4300001e44, - 0x1e4500001e46, - 0x1e4700001e48, - 0x1e4900001e4a, - 0x1e4b00001e4c, - 0x1e4d00001e4e, - 0x1e4f00001e50, - 0x1e5100001e52, - 0x1e5300001e54, - 0x1e5500001e56, - 0x1e5700001e58, - 0x1e5900001e5a, - 0x1e5b00001e5c, - 0x1e5d00001e5e, - 0x1e5f00001e60, - 0x1e6100001e62, - 0x1e6300001e64, - 0x1e6500001e66, - 0x1e6700001e68, - 0x1e6900001e6a, - 0x1e6b00001e6c, - 0x1e6d00001e6e, - 0x1e6f00001e70, - 0x1e7100001e72, - 0x1e7300001e74, - 0x1e7500001e76, - 0x1e7700001e78, - 0x1e7900001e7a, - 0x1e7b00001e7c, - 0x1e7d00001e7e, - 0x1e7f00001e80, - 0x1e8100001e82, - 0x1e8300001e84, - 0x1e8500001e86, - 0x1e8700001e88, - 0x1e8900001e8a, - 0x1e8b00001e8c, - 0x1e8d00001e8e, - 0x1e8f00001e90, - 0x1e9100001e92, - 0x1e9300001e94, - 0x1e9500001e9a, - 0x1e9c00001e9e, - 0x1e9f00001ea0, - 0x1ea100001ea2, - 0x1ea300001ea4, - 0x1ea500001ea6, - 0x1ea700001ea8, - 0x1ea900001eaa, - 0x1eab00001eac, - 0x1ead00001eae, - 0x1eaf00001eb0, - 0x1eb100001eb2, - 0x1eb300001eb4, - 0x1eb500001eb6, - 0x1eb700001eb8, - 0x1eb900001eba, - 0x1ebb00001ebc, - 0x1ebd00001ebe, - 0x1ebf00001ec0, - 0x1ec100001ec2, - 0x1ec300001ec4, - 0x1ec500001ec6, - 0x1ec700001ec8, - 0x1ec900001eca, - 0x1ecb00001ecc, - 0x1ecd00001ece, - 0x1ecf00001ed0, - 0x1ed100001ed2, - 0x1ed300001ed4, - 0x1ed500001ed6, - 0x1ed700001ed8, - 0x1ed900001eda, - 0x1edb00001edc, - 0x1edd00001ede, - 0x1edf00001ee0, - 0x1ee100001ee2, - 0x1ee300001ee4, - 0x1ee500001ee6, - 0x1ee700001ee8, - 0x1ee900001eea, - 0x1eeb00001eec, - 0x1eed00001eee, - 0x1eef00001ef0, - 0x1ef100001ef2, - 0x1ef300001ef4, - 0x1ef500001ef6, - 0x1ef700001ef8, - 0x1ef900001efa, - 0x1efb00001efc, - 0x1efd00001efe, - 0x1eff00001f08, - 0x1f1000001f16, - 0x1f2000001f28, - 0x1f3000001f38, - 0x1f4000001f46, - 0x1f5000001f58, - 0x1f6000001f68, - 0x1f7000001f71, - 0x1f7200001f73, - 0x1f7400001f75, - 0x1f7600001f77, - 0x1f7800001f79, - 0x1f7a00001f7b, - 0x1f7c00001f7d, - 0x1fb000001fb2, - 0x1fb600001fb7, - 0x1fc600001fc7, - 0x1fd000001fd3, - 0x1fd600001fd8, - 0x1fe000001fe3, - 0x1fe400001fe8, - 0x1ff600001ff7, - 0x214e0000214f, - 0x218400002185, - 0x2c3000002c5f, - 0x2c6100002c62, - 0x2c6500002c67, - 0x2c6800002c69, - 0x2c6a00002c6b, - 0x2c6c00002c6d, - 0x2c7100002c72, - 0x2c7300002c75, - 0x2c7600002c7c, - 0x2c8100002c82, - 0x2c8300002c84, - 0x2c8500002c86, - 0x2c8700002c88, - 0x2c8900002c8a, - 0x2c8b00002c8c, - 0x2c8d00002c8e, - 0x2c8f00002c90, - 0x2c9100002c92, - 0x2c9300002c94, - 0x2c9500002c96, - 0x2c9700002c98, - 0x2c9900002c9a, - 0x2c9b00002c9c, - 0x2c9d00002c9e, - 0x2c9f00002ca0, - 0x2ca100002ca2, - 0x2ca300002ca4, - 0x2ca500002ca6, - 0x2ca700002ca8, - 0x2ca900002caa, - 0x2cab00002cac, - 0x2cad00002cae, - 0x2caf00002cb0, - 0x2cb100002cb2, - 0x2cb300002cb4, - 0x2cb500002cb6, - 0x2cb700002cb8, - 0x2cb900002cba, - 0x2cbb00002cbc, - 0x2cbd00002cbe, - 0x2cbf00002cc0, - 0x2cc100002cc2, - 0x2cc300002cc4, - 0x2cc500002cc6, - 0x2cc700002cc8, - 0x2cc900002cca, - 0x2ccb00002ccc, - 0x2ccd00002cce, - 0x2ccf00002cd0, - 0x2cd100002cd2, - 0x2cd300002cd4, - 0x2cd500002cd6, - 0x2cd700002cd8, - 0x2cd900002cda, - 0x2cdb00002cdc, - 0x2cdd00002cde, - 0x2cdf00002ce0, - 0x2ce100002ce2, - 0x2ce300002ce5, - 0x2cec00002ced, - 0x2cee00002cf2, - 0x2cf300002cf4, - 0x2d0000002d26, - 0x2d2700002d28, - 0x2d2d00002d2e, - 0x2d3000002d68, - 0x2d7f00002d97, - 0x2da000002da7, - 0x2da800002daf, - 0x2db000002db7, - 0x2db800002dbf, - 0x2dc000002dc7, - 0x2dc800002dcf, - 0x2dd000002dd7, - 0x2dd800002ddf, - 0x2de000002e00, - 0x2e2f00002e30, - 0x300500003008, - 0x302a0000302e, - 0x303c0000303d, - 0x304100003097, - 0x30990000309b, - 0x309d0000309f, - 0x30a1000030fb, - 0x30fc000030ff, - 0x310500003130, - 0x31a0000031c0, - 0x31f000003200, - 0x340000004dc0, - 0x4e0000009ffd, - 0xa0000000a48d, - 0xa4d00000a4fe, - 0xa5000000a60d, - 0xa6100000a62c, - 0xa6410000a642, - 0xa6430000a644, - 0xa6450000a646, - 0xa6470000a648, - 0xa6490000a64a, - 0xa64b0000a64c, - 0xa64d0000a64e, - 0xa64f0000a650, - 0xa6510000a652, - 0xa6530000a654, - 0xa6550000a656, - 0xa6570000a658, - 0xa6590000a65a, - 0xa65b0000a65c, - 0xa65d0000a65e, - 0xa65f0000a660, - 0xa6610000a662, - 0xa6630000a664, - 0xa6650000a666, - 0xa6670000a668, - 0xa6690000a66a, - 0xa66b0000a66c, - 0xa66d0000a670, - 0xa6740000a67e, - 0xa67f0000a680, - 0xa6810000a682, - 0xa6830000a684, - 0xa6850000a686, - 0xa6870000a688, - 0xa6890000a68a, - 0xa68b0000a68c, - 0xa68d0000a68e, - 0xa68f0000a690, - 0xa6910000a692, - 0xa6930000a694, - 0xa6950000a696, - 0xa6970000a698, - 0xa6990000a69a, - 0xa69b0000a69c, - 0xa69e0000a6e6, - 0xa6f00000a6f2, - 0xa7170000a720, - 0xa7230000a724, - 0xa7250000a726, - 0xa7270000a728, - 0xa7290000a72a, - 0xa72b0000a72c, - 0xa72d0000a72e, - 0xa72f0000a732, - 0xa7330000a734, - 0xa7350000a736, - 0xa7370000a738, - 0xa7390000a73a, - 0xa73b0000a73c, - 0xa73d0000a73e, - 0xa73f0000a740, - 0xa7410000a742, - 0xa7430000a744, - 0xa7450000a746, - 0xa7470000a748, - 0xa7490000a74a, - 0xa74b0000a74c, - 0xa74d0000a74e, - 0xa74f0000a750, - 0xa7510000a752, - 0xa7530000a754, - 0xa7550000a756, - 0xa7570000a758, - 0xa7590000a75a, - 0xa75b0000a75c, - 0xa75d0000a75e, - 0xa75f0000a760, - 0xa7610000a762, - 0xa7630000a764, - 0xa7650000a766, - 0xa7670000a768, - 0xa7690000a76a, - 0xa76b0000a76c, - 0xa76d0000a76e, - 0xa76f0000a770, - 0xa7710000a779, - 0xa77a0000a77b, - 0xa77c0000a77d, - 0xa77f0000a780, - 0xa7810000a782, - 0xa7830000a784, - 0xa7850000a786, - 0xa7870000a789, - 0xa78c0000a78d, - 0xa78e0000a790, - 0xa7910000a792, - 0xa7930000a796, - 0xa7970000a798, - 0xa7990000a79a, - 0xa79b0000a79c, - 0xa79d0000a79e, - 0xa79f0000a7a0, - 0xa7a10000a7a2, - 0xa7a30000a7a4, - 0xa7a50000a7a6, - 0xa7a70000a7a8, - 0xa7a90000a7aa, - 0xa7af0000a7b0, - 0xa7b50000a7b6, - 0xa7b70000a7b8, - 0xa7b90000a7ba, - 0xa7bb0000a7bc, - 0xa7bd0000a7be, - 0xa7bf0000a7c0, - 0xa7c30000a7c4, - 0xa7c80000a7c9, - 0xa7ca0000a7cb, - 0xa7f60000a7f8, - 0xa7fa0000a828, - 0xa82c0000a82d, - 0xa8400000a874, - 0xa8800000a8c6, - 0xa8d00000a8da, - 0xa8e00000a8f8, - 0xa8fb0000a8fc, - 0xa8fd0000a92e, - 0xa9300000a954, - 0xa9800000a9c1, - 0xa9cf0000a9da, - 0xa9e00000a9ff, - 0xaa000000aa37, - 0xaa400000aa4e, - 0xaa500000aa5a, - 0xaa600000aa77, - 0xaa7a0000aac3, - 0xaadb0000aade, - 0xaae00000aaf0, - 0xaaf20000aaf7, - 0xab010000ab07, - 0xab090000ab0f, - 0xab110000ab17, - 0xab200000ab27, - 0xab280000ab2f, - 0xab300000ab5b, - 0xab600000ab6a, - 0xabc00000abeb, - 0xabec0000abee, - 0xabf00000abfa, - 0xac000000d7a4, - 0xfa0e0000fa10, - 0xfa110000fa12, - 0xfa130000fa15, - 0xfa1f0000fa20, - 0xfa210000fa22, - 0xfa230000fa25, - 0xfa270000fa2a, - 0xfb1e0000fb1f, - 0xfe200000fe30, - 0xfe730000fe74, - 0x100000001000c, - 0x1000d00010027, - 0x100280001003b, - 0x1003c0001003e, - 0x1003f0001004e, - 0x100500001005e, - 0x10080000100fb, - 0x101fd000101fe, - 0x102800001029d, - 0x102a0000102d1, - 0x102e0000102e1, - 0x1030000010320, - 0x1032d00010341, - 0x103420001034a, - 0x103500001037b, - 0x103800001039e, - 0x103a0000103c4, - 0x103c8000103d0, - 0x104280001049e, - 0x104a0000104aa, - 0x104d8000104fc, - 0x1050000010528, - 0x1053000010564, - 0x1060000010737, - 0x1074000010756, - 0x1076000010768, - 0x1080000010806, - 0x1080800010809, - 0x1080a00010836, - 0x1083700010839, - 0x1083c0001083d, - 0x1083f00010856, - 0x1086000010877, - 0x108800001089f, - 0x108e0000108f3, - 0x108f4000108f6, - 0x1090000010916, - 0x109200001093a, - 0x10980000109b8, - 0x109be000109c0, - 0x10a0000010a04, - 0x10a0500010a07, - 0x10a0c00010a14, - 0x10a1500010a18, - 0x10a1900010a36, - 0x10a3800010a3b, - 0x10a3f00010a40, - 0x10a6000010a7d, - 0x10a8000010a9d, - 0x10ac000010ac8, - 0x10ac900010ae7, - 0x10b0000010b36, - 0x10b4000010b56, - 0x10b6000010b73, - 0x10b8000010b92, - 0x10c0000010c49, - 0x10cc000010cf3, - 0x10d0000010d28, - 0x10d3000010d3a, - 0x10e8000010eaa, - 0x10eab00010ead, - 0x10eb000010eb2, - 0x10f0000010f1d, - 0x10f2700010f28, - 0x10f3000010f51, - 0x10fb000010fc5, - 0x10fe000010ff7, - 0x1100000011047, - 0x1106600011070, - 0x1107f000110bb, - 0x110d0000110e9, - 0x110f0000110fa, - 0x1110000011135, - 0x1113600011140, - 0x1114400011148, - 0x1115000011174, - 0x1117600011177, - 0x11180000111c5, - 0x111c9000111cd, - 0x111ce000111db, - 0x111dc000111dd, - 0x1120000011212, - 0x1121300011238, - 0x1123e0001123f, - 0x1128000011287, - 0x1128800011289, - 0x1128a0001128e, - 0x1128f0001129e, - 0x1129f000112a9, - 0x112b0000112eb, - 0x112f0000112fa, - 0x1130000011304, - 0x113050001130d, - 0x1130f00011311, - 0x1131300011329, - 0x1132a00011331, - 0x1133200011334, - 0x113350001133a, - 0x1133b00011345, - 0x1134700011349, - 0x1134b0001134e, - 0x1135000011351, - 0x1135700011358, - 0x1135d00011364, - 0x113660001136d, - 0x1137000011375, - 0x114000001144b, - 0x114500001145a, - 0x1145e00011462, - 0x11480000114c6, - 0x114c7000114c8, - 0x114d0000114da, - 0x11580000115b6, - 0x115b8000115c1, - 0x115d8000115de, - 0x1160000011641, - 0x1164400011645, - 0x116500001165a, - 0x11680000116b9, - 0x116c0000116ca, - 0x117000001171b, - 0x1171d0001172c, - 0x117300001173a, - 0x118000001183b, - 0x118c0000118ea, - 0x118ff00011907, - 0x119090001190a, - 0x1190c00011914, - 0x1191500011917, - 0x1191800011936, - 0x1193700011939, - 0x1193b00011944, - 0x119500001195a, - 0x119a0000119a8, - 0x119aa000119d8, - 0x119da000119e2, - 0x119e3000119e5, - 0x11a0000011a3f, - 0x11a4700011a48, - 0x11a5000011a9a, - 0x11a9d00011a9e, - 0x11ac000011af9, - 0x11c0000011c09, - 0x11c0a00011c37, - 0x11c3800011c41, - 0x11c5000011c5a, - 0x11c7200011c90, - 0x11c9200011ca8, - 0x11ca900011cb7, - 0x11d0000011d07, - 0x11d0800011d0a, - 0x11d0b00011d37, - 0x11d3a00011d3b, - 0x11d3c00011d3e, - 0x11d3f00011d48, - 0x11d5000011d5a, - 0x11d6000011d66, - 0x11d6700011d69, - 0x11d6a00011d8f, - 0x11d9000011d92, - 0x11d9300011d99, - 0x11da000011daa, - 0x11ee000011ef7, - 0x11fb000011fb1, - 0x120000001239a, - 0x1248000012544, - 0x130000001342f, - 0x1440000014647, - 0x1680000016a39, - 0x16a4000016a5f, - 0x16a6000016a6a, - 0x16ad000016aee, - 0x16af000016af5, - 0x16b0000016b37, - 0x16b4000016b44, - 0x16b5000016b5a, - 0x16b6300016b78, - 0x16b7d00016b90, - 0x16e6000016e80, - 0x16f0000016f4b, - 0x16f4f00016f88, - 0x16f8f00016fa0, - 0x16fe000016fe2, - 0x16fe300016fe5, - 0x16ff000016ff2, - 0x17000000187f8, - 0x1880000018cd6, - 0x18d0000018d09, - 0x1b0000001b11f, - 0x1b1500001b153, - 0x1b1640001b168, - 0x1b1700001b2fc, - 0x1bc000001bc6b, - 0x1bc700001bc7d, - 0x1bc800001bc89, - 0x1bc900001bc9a, - 0x1bc9d0001bc9f, - 0x1da000001da37, - 0x1da3b0001da6d, - 0x1da750001da76, - 0x1da840001da85, - 0x1da9b0001daa0, - 0x1daa10001dab0, - 0x1e0000001e007, - 0x1e0080001e019, - 0x1e01b0001e022, - 0x1e0230001e025, - 0x1e0260001e02b, - 0x1e1000001e12d, - 0x1e1300001e13e, - 0x1e1400001e14a, - 0x1e14e0001e14f, - 0x1e2c00001e2fa, - 0x1e8000001e8c5, - 0x1e8d00001e8d7, - 0x1e9220001e94c, - 0x1e9500001e95a, - 0x1fbf00001fbfa, - 0x200000002a6de, - 0x2a7000002b735, - 0x2b7400002b81e, - 0x2b8200002cea2, - 0x2ceb00002ebe1, - 0x300000003134b, - ), - 'CONTEXTJ': ( - 0x200c0000200e, - ), - 'CONTEXTO': ( - 0xb7000000b8, - 0x37500000376, - 0x5f3000005f5, - 0x6600000066a, - 0x6f0000006fa, - 0x30fb000030fc, - ), -} diff --git a/venv/lib/python3.8/site-packages/idna/intranges.py b/venv/lib/python3.8/site-packages/idna/intranges.py deleted file mode 100644 index fa8a735..0000000 --- a/venv/lib/python3.8/site-packages/idna/intranges.py +++ /dev/null @@ -1,53 +0,0 @@ -""" -Given a list of integers, made up of (hopefully) a small number of long runs -of consecutive integers, compute a representation of the form -((start1, end1), (start2, end2) ...). Then answer the question "was x present -in the original list?" in time O(log(# runs)). -""" - -import bisect - -def intranges_from_list(list_): - """Represent a list of integers as a sequence of ranges: - ((start_0, end_0), (start_1, end_1), ...), such that the original - integers are exactly those x such that start_i <= x < end_i for some i. - - Ranges are encoded as single integers (start << 32 | end), not as tuples. - """ - - sorted_list = sorted(list_) - ranges = [] - last_write = -1 - for i in range(len(sorted_list)): - if i+1 < len(sorted_list): - if sorted_list[i] == sorted_list[i+1]-1: - continue - current_range = sorted_list[last_write+1:i+1] - ranges.append(_encode_range(current_range[0], current_range[-1] + 1)) - last_write = i - - return tuple(ranges) - -def _encode_range(start, end): - return (start << 32) | end - -def _decode_range(r): - return (r >> 32), (r & ((1 << 32) - 1)) - - -def intranges_contain(int_, ranges): - """Determine if `int_` falls into one of the ranges in `ranges`.""" - tuple_ = _encode_range(int_, 0) - pos = bisect.bisect_left(ranges, tuple_) - # we could be immediately ahead of a tuple (start, end) - # with start < int_ <= end - if pos > 0: - left, right = _decode_range(ranges[pos-1]) - if left <= int_ < right: - return True - # or we could be immediately behind a tuple (int_, end) - if pos < len(ranges): - left, _ = _decode_range(ranges[pos]) - if left == int_: - return True - return False diff --git a/venv/lib/python3.8/site-packages/idna/package_data.py b/venv/lib/python3.8/site-packages/idna/package_data.py deleted file mode 100644 index ce1c521..0000000 --- a/venv/lib/python3.8/site-packages/idna/package_data.py +++ /dev/null @@ -1,2 +0,0 @@ -__version__ = '2.10' - diff --git a/venv/lib/python3.8/site-packages/idna/uts46data.py b/venv/lib/python3.8/site-packages/idna/uts46data.py deleted file mode 100644 index 3766dd4..0000000 --- a/venv/lib/python3.8/site-packages/idna/uts46data.py +++ /dev/null @@ -1,8357 +0,0 @@ -# This file is automatically generated by tools/idna-data -# vim: set fileencoding=utf-8 : - -"""IDNA Mapping Table from UTS46.""" - - -__version__ = "13.0.0" -def _seg_0(): - return [ - (0x0, '3'), - (0x1, '3'), - (0x2, '3'), - (0x3, '3'), - (0x4, '3'), - (0x5, '3'), - (0x6, '3'), - (0x7, '3'), - (0x8, '3'), - (0x9, '3'), - (0xA, '3'), - (0xB, '3'), - (0xC, '3'), - (0xD, '3'), - (0xE, '3'), - (0xF, '3'), - (0x10, '3'), - (0x11, '3'), - (0x12, '3'), - (0x13, '3'), - (0x14, '3'), - (0x15, '3'), - (0x16, '3'), - (0x17, '3'), - (0x18, '3'), - (0x19, '3'), - (0x1A, '3'), - (0x1B, '3'), - (0x1C, '3'), - (0x1D, '3'), - (0x1E, '3'), - (0x1F, '3'), - (0x20, '3'), - (0x21, '3'), - (0x22, '3'), - (0x23, '3'), - (0x24, '3'), - (0x25, '3'), - (0x26, '3'), - (0x27, '3'), - (0x28, '3'), - (0x29, '3'), - (0x2A, '3'), - (0x2B, '3'), - (0x2C, '3'), - (0x2D, 'V'), - (0x2E, 'V'), - (0x2F, '3'), - (0x30, 'V'), - (0x31, 'V'), - (0x32, 'V'), - (0x33, 'V'), - (0x34, 'V'), - (0x35, 'V'), - (0x36, 'V'), - (0x37, 'V'), - (0x38, 'V'), - (0x39, 'V'), - (0x3A, '3'), - (0x3B, '3'), - (0x3C, '3'), - (0x3D, '3'), - (0x3E, '3'), - (0x3F, '3'), - (0x40, '3'), - (0x41, 'M', u'a'), - (0x42, 'M', u'b'), - (0x43, 'M', u'c'), - (0x44, 'M', u'd'), - (0x45, 'M', u'e'), - (0x46, 'M', u'f'), - (0x47, 'M', u'g'), - (0x48, 'M', u'h'), - (0x49, 'M', u'i'), - (0x4A, 'M', u'j'), - (0x4B, 'M', u'k'), - (0x4C, 'M', u'l'), - (0x4D, 'M', u'm'), - (0x4E, 'M', u'n'), - (0x4F, 'M', u'o'), - (0x50, 'M', u'p'), - (0x51, 'M', u'q'), - (0x52, 'M', u'r'), - (0x53, 'M', u's'), - (0x54, 'M', u't'), - (0x55, 'M', u'u'), - (0x56, 'M', u'v'), - (0x57, 'M', u'w'), - (0x58, 'M', u'x'), - (0x59, 'M', u'y'), - (0x5A, 'M', u'z'), - (0x5B, '3'), - (0x5C, '3'), - (0x5D, '3'), - (0x5E, '3'), - (0x5F, '3'), - (0x60, '3'), - (0x61, 'V'), - (0x62, 'V'), - (0x63, 'V'), - ] - -def _seg_1(): - return [ - (0x64, 'V'), - (0x65, 'V'), - (0x66, 'V'), - (0x67, 'V'), - (0x68, 'V'), - (0x69, 'V'), - (0x6A, 'V'), - (0x6B, 'V'), - (0x6C, 'V'), - (0x6D, 'V'), - (0x6E, 'V'), - (0x6F, 'V'), - (0x70, 'V'), - (0x71, 'V'), - (0x72, 'V'), - (0x73, 'V'), - (0x74, 'V'), - (0x75, 'V'), - (0x76, 'V'), - (0x77, 'V'), - (0x78, 'V'), - (0x79, 'V'), - (0x7A, 'V'), - (0x7B, '3'), - (0x7C, '3'), - (0x7D, '3'), - (0x7E, '3'), - (0x7F, '3'), - (0x80, 'X'), - (0x81, 'X'), - (0x82, 'X'), - (0x83, 'X'), - (0x84, 'X'), - (0x85, 'X'), - (0x86, 'X'), - (0x87, 'X'), - (0x88, 'X'), - (0x89, 'X'), - (0x8A, 'X'), - (0x8B, 'X'), - (0x8C, 'X'), - (0x8D, 'X'), - (0x8E, 'X'), - (0x8F, 'X'), - (0x90, 'X'), - (0x91, 'X'), - (0x92, 'X'), - (0x93, 'X'), - (0x94, 'X'), - (0x95, 'X'), - (0x96, 'X'), - (0x97, 'X'), - (0x98, 'X'), - (0x99, 'X'), - (0x9A, 'X'), - (0x9B, 'X'), - (0x9C, 'X'), - (0x9D, 'X'), - (0x9E, 'X'), - (0x9F, 'X'), - (0xA0, '3', u' '), - (0xA1, 'V'), - (0xA2, 'V'), - (0xA3, 'V'), - (0xA4, 'V'), - (0xA5, 'V'), - (0xA6, 'V'), - (0xA7, 'V'), - (0xA8, '3', u' ̈'), - (0xA9, 'V'), - (0xAA, 'M', u'a'), - (0xAB, 'V'), - (0xAC, 'V'), - (0xAD, 'I'), - (0xAE, 'V'), - (0xAF, '3', u' ̄'), - (0xB0, 'V'), - (0xB1, 'V'), - (0xB2, 'M', u'2'), - (0xB3, 'M', u'3'), - (0xB4, '3', u' ́'), - (0xB5, 'M', u'μ'), - (0xB6, 'V'), - (0xB7, 'V'), - (0xB8, '3', u' ̧'), - (0xB9, 'M', u'1'), - (0xBA, 'M', u'o'), - (0xBB, 'V'), - (0xBC, 'M', u'1⁄4'), - (0xBD, 'M', u'1⁄2'), - (0xBE, 'M', u'3⁄4'), - (0xBF, 'V'), - (0xC0, 'M', u'à'), - (0xC1, 'M', u'á'), - (0xC2, 'M', u'â'), - (0xC3, 'M', u'ã'), - (0xC4, 'M', u'ä'), - (0xC5, 'M', u'å'), - (0xC6, 'M', u'æ'), - (0xC7, 'M', u'ç'), - ] - -def _seg_2(): - return [ - (0xC8, 'M', u'è'), - (0xC9, 'M', u'é'), - (0xCA, 'M', u'ê'), - (0xCB, 'M', u'ë'), - (0xCC, 'M', u'ì'), - (0xCD, 'M', u'í'), - (0xCE, 'M', u'î'), - (0xCF, 'M', u'ï'), - (0xD0, 'M', u'ð'), - (0xD1, 'M', u'ñ'), - (0xD2, 'M', u'ò'), - (0xD3, 'M', u'ó'), - (0xD4, 'M', u'ô'), - (0xD5, 'M', u'õ'), - (0xD6, 'M', u'ö'), - (0xD7, 'V'), - (0xD8, 'M', u'ø'), - (0xD9, 'M', u'ù'), - (0xDA, 'M', u'ú'), - (0xDB, 'M', u'û'), - (0xDC, 'M', u'ü'), - (0xDD, 'M', u'ý'), - (0xDE, 'M', u'þ'), - (0xDF, 'D', u'ss'), - (0xE0, 'V'), - (0xE1, 'V'), - (0xE2, 'V'), - (0xE3, 'V'), - (0xE4, 'V'), - (0xE5, 'V'), - (0xE6, 'V'), - (0xE7, 'V'), - (0xE8, 'V'), - (0xE9, 'V'), - (0xEA, 'V'), - (0xEB, 'V'), - (0xEC, 'V'), - (0xED, 'V'), - (0xEE, 'V'), - (0xEF, 'V'), - (0xF0, 'V'), - (0xF1, 'V'), - (0xF2, 'V'), - (0xF3, 'V'), - (0xF4, 'V'), - (0xF5, 'V'), - (0xF6, 'V'), - (0xF7, 'V'), - (0xF8, 'V'), - (0xF9, 'V'), - (0xFA, 'V'), - (0xFB, 'V'), - (0xFC, 'V'), - (0xFD, 'V'), - (0xFE, 'V'), - (0xFF, 'V'), - (0x100, 'M', u'ā'), - (0x101, 'V'), - (0x102, 'M', u'ă'), - (0x103, 'V'), - (0x104, 'M', u'ą'), - (0x105, 'V'), - (0x106, 'M', u'ć'), - (0x107, 'V'), - (0x108, 'M', u'ĉ'), - (0x109, 'V'), - (0x10A, 'M', u'ċ'), - (0x10B, 'V'), - (0x10C, 'M', u'č'), - (0x10D, 'V'), - (0x10E, 'M', u'ď'), - (0x10F, 'V'), - (0x110, 'M', u'đ'), - (0x111, 'V'), - (0x112, 'M', u'ē'), - (0x113, 'V'), - (0x114, 'M', u'ĕ'), - (0x115, 'V'), - (0x116, 'M', u'ė'), - (0x117, 'V'), - (0x118, 'M', u'ę'), - (0x119, 'V'), - (0x11A, 'M', u'ě'), - (0x11B, 'V'), - (0x11C, 'M', u'ĝ'), - (0x11D, 'V'), - (0x11E, 'M', u'ğ'), - (0x11F, 'V'), - (0x120, 'M', u'ġ'), - (0x121, 'V'), - (0x122, 'M', u'ģ'), - (0x123, 'V'), - (0x124, 'M', u'ĥ'), - (0x125, 'V'), - (0x126, 'M', u'ħ'), - (0x127, 'V'), - (0x128, 'M', u'ĩ'), - (0x129, 'V'), - (0x12A, 'M', u'ī'), - (0x12B, 'V'), - ] - -def _seg_3(): - return [ - (0x12C, 'M', u'ĭ'), - (0x12D, 'V'), - (0x12E, 'M', u'į'), - (0x12F, 'V'), - (0x130, 'M', u'i̇'), - (0x131, 'V'), - (0x132, 'M', u'ij'), - (0x134, 'M', u'ĵ'), - (0x135, 'V'), - (0x136, 'M', u'ķ'), - (0x137, 'V'), - (0x139, 'M', u'ĺ'), - (0x13A, 'V'), - (0x13B, 'M', u'ļ'), - (0x13C, 'V'), - (0x13D, 'M', u'ľ'), - (0x13E, 'V'), - (0x13F, 'M', u'l·'), - (0x141, 'M', u'ł'), - (0x142, 'V'), - (0x143, 'M', u'ń'), - (0x144, 'V'), - (0x145, 'M', u'ņ'), - (0x146, 'V'), - (0x147, 'M', u'ň'), - (0x148, 'V'), - (0x149, 'M', u'ʼn'), - (0x14A, 'M', u'ŋ'), - (0x14B, 'V'), - (0x14C, 'M', u'ō'), - (0x14D, 'V'), - (0x14E, 'M', u'ŏ'), - (0x14F, 'V'), - (0x150, 'M', u'ő'), - (0x151, 'V'), - (0x152, 'M', u'œ'), - (0x153, 'V'), - (0x154, 'M', u'ŕ'), - (0x155, 'V'), - (0x156, 'M', u'ŗ'), - (0x157, 'V'), - (0x158, 'M', u'ř'), - (0x159, 'V'), - (0x15A, 'M', u'ś'), - (0x15B, 'V'), - (0x15C, 'M', u'ŝ'), - (0x15D, 'V'), - (0x15E, 'M', u'ş'), - (0x15F, 'V'), - (0x160, 'M', u'š'), - (0x161, 'V'), - (0x162, 'M', u'ţ'), - (0x163, 'V'), - (0x164, 'M', u'ť'), - (0x165, 'V'), - (0x166, 'M', u'ŧ'), - (0x167, 'V'), - (0x168, 'M', u'ũ'), - (0x169, 'V'), - (0x16A, 'M', u'ū'), - (0x16B, 'V'), - (0x16C, 'M', u'ŭ'), - (0x16D, 'V'), - (0x16E, 'M', u'ů'), - (0x16F, 'V'), - (0x170, 'M', u'ű'), - (0x171, 'V'), - (0x172, 'M', u'ų'), - (0x173, 'V'), - (0x174, 'M', u'ŵ'), - (0x175, 'V'), - (0x176, 'M', u'ŷ'), - (0x177, 'V'), - (0x178, 'M', u'ÿ'), - (0x179, 'M', u'ź'), - (0x17A, 'V'), - (0x17B, 'M', u'ż'), - (0x17C, 'V'), - (0x17D, 'M', u'ž'), - (0x17E, 'V'), - (0x17F, 'M', u's'), - (0x180, 'V'), - (0x181, 'M', u'ɓ'), - (0x182, 'M', u'ƃ'), - (0x183, 'V'), - (0x184, 'M', u'ƅ'), - (0x185, 'V'), - (0x186, 'M', u'ɔ'), - (0x187, 'M', u'ƈ'), - (0x188, 'V'), - (0x189, 'M', u'ɖ'), - (0x18A, 'M', u'ɗ'), - (0x18B, 'M', u'ƌ'), - (0x18C, 'V'), - (0x18E, 'M', u'ǝ'), - (0x18F, 'M', u'ə'), - (0x190, 'M', u'ɛ'), - (0x191, 'M', u'ƒ'), - (0x192, 'V'), - (0x193, 'M', u'ɠ'), - ] - -def _seg_4(): - return [ - (0x194, 'M', u'ɣ'), - (0x195, 'V'), - (0x196, 'M', u'ɩ'), - (0x197, 'M', u'ɨ'), - (0x198, 'M', u'ƙ'), - (0x199, 'V'), - (0x19C, 'M', u'ɯ'), - (0x19D, 'M', u'ɲ'), - (0x19E, 'V'), - (0x19F, 'M', u'ɵ'), - (0x1A0, 'M', u'ơ'), - (0x1A1, 'V'), - (0x1A2, 'M', u'ƣ'), - (0x1A3, 'V'), - (0x1A4, 'M', u'ƥ'), - (0x1A5, 'V'), - (0x1A6, 'M', u'ʀ'), - (0x1A7, 'M', u'ƨ'), - (0x1A8, 'V'), - (0x1A9, 'M', u'ʃ'), - (0x1AA, 'V'), - (0x1AC, 'M', u'ƭ'), - (0x1AD, 'V'), - (0x1AE, 'M', u'ʈ'), - (0x1AF, 'M', u'ư'), - (0x1B0, 'V'), - (0x1B1, 'M', u'ʊ'), - (0x1B2, 'M', u'ʋ'), - (0x1B3, 'M', u'ƴ'), - (0x1B4, 'V'), - (0x1B5, 'M', u'ƶ'), - (0x1B6, 'V'), - (0x1B7, 'M', u'ʒ'), - (0x1B8, 'M', u'ƹ'), - (0x1B9, 'V'), - (0x1BC, 'M', u'ƽ'), - (0x1BD, 'V'), - (0x1C4, 'M', u'dž'), - (0x1C7, 'M', u'lj'), - (0x1CA, 'M', u'nj'), - (0x1CD, 'M', u'ǎ'), - (0x1CE, 'V'), - (0x1CF, 'M', u'ǐ'), - (0x1D0, 'V'), - (0x1D1, 'M', u'ǒ'), - (0x1D2, 'V'), - (0x1D3, 'M', u'ǔ'), - (0x1D4, 'V'), - (0x1D5, 'M', u'ǖ'), - (0x1D6, 'V'), - (0x1D7, 'M', u'ǘ'), - (0x1D8, 'V'), - (0x1D9, 'M', u'ǚ'), - (0x1DA, 'V'), - (0x1DB, 'M', u'ǜ'), - (0x1DC, 'V'), - (0x1DE, 'M', u'ǟ'), - (0x1DF, 'V'), - (0x1E0, 'M', u'ǡ'), - (0x1E1, 'V'), - (0x1E2, 'M', u'ǣ'), - (0x1E3, 'V'), - (0x1E4, 'M', u'ǥ'), - (0x1E5, 'V'), - (0x1E6, 'M', u'ǧ'), - (0x1E7, 'V'), - (0x1E8, 'M', u'ǩ'), - (0x1E9, 'V'), - (0x1EA, 'M', u'ǫ'), - (0x1EB, 'V'), - (0x1EC, 'M', u'ǭ'), - (0x1ED, 'V'), - (0x1EE, 'M', u'ǯ'), - (0x1EF, 'V'), - (0x1F1, 'M', u'dz'), - (0x1F4, 'M', u'ǵ'), - (0x1F5, 'V'), - (0x1F6, 'M', u'ƕ'), - (0x1F7, 'M', u'ƿ'), - (0x1F8, 'M', u'ǹ'), - (0x1F9, 'V'), - (0x1FA, 'M', u'ǻ'), - (0x1FB, 'V'), - (0x1FC, 'M', u'ǽ'), - (0x1FD, 'V'), - (0x1FE, 'M', u'ǿ'), - (0x1FF, 'V'), - (0x200, 'M', u'ȁ'), - (0x201, 'V'), - (0x202, 'M', u'ȃ'), - (0x203, 'V'), - (0x204, 'M', u'ȅ'), - (0x205, 'V'), - (0x206, 'M', u'ȇ'), - (0x207, 'V'), - (0x208, 'M', u'ȉ'), - (0x209, 'V'), - (0x20A, 'M', u'ȋ'), - (0x20B, 'V'), - (0x20C, 'M', u'ȍ'), - ] - -def _seg_5(): - return [ - (0x20D, 'V'), - (0x20E, 'M', u'ȏ'), - (0x20F, 'V'), - (0x210, 'M', u'ȑ'), - (0x211, 'V'), - (0x212, 'M', u'ȓ'), - (0x213, 'V'), - (0x214, 'M', u'ȕ'), - (0x215, 'V'), - (0x216, 'M', u'ȗ'), - (0x217, 'V'), - (0x218, 'M', u'ș'), - (0x219, 'V'), - (0x21A, 'M', u'ț'), - (0x21B, 'V'), - (0x21C, 'M', u'ȝ'), - (0x21D, 'V'), - (0x21E, 'M', u'ȟ'), - (0x21F, 'V'), - (0x220, 'M', u'ƞ'), - (0x221, 'V'), - (0x222, 'M', u'ȣ'), - (0x223, 'V'), - (0x224, 'M', u'ȥ'), - (0x225, 'V'), - (0x226, 'M', u'ȧ'), - (0x227, 'V'), - (0x228, 'M', u'ȩ'), - (0x229, 'V'), - (0x22A, 'M', u'ȫ'), - (0x22B, 'V'), - (0x22C, 'M', u'ȭ'), - (0x22D, 'V'), - (0x22E, 'M', u'ȯ'), - (0x22F, 'V'), - (0x230, 'M', u'ȱ'), - (0x231, 'V'), - (0x232, 'M', u'ȳ'), - (0x233, 'V'), - (0x23A, 'M', u'ⱥ'), - (0x23B, 'M', u'ȼ'), - (0x23C, 'V'), - (0x23D, 'M', u'ƚ'), - (0x23E, 'M', u'ⱦ'), - (0x23F, 'V'), - (0x241, 'M', u'ɂ'), - (0x242, 'V'), - (0x243, 'M', u'ƀ'), - (0x244, 'M', u'ʉ'), - (0x245, 'M', u'ʌ'), - (0x246, 'M', u'ɇ'), - (0x247, 'V'), - (0x248, 'M', u'ɉ'), - (0x249, 'V'), - (0x24A, 'M', u'ɋ'), - (0x24B, 'V'), - (0x24C, 'M', u'ɍ'), - (0x24D, 'V'), - (0x24E, 'M', u'ɏ'), - (0x24F, 'V'), - (0x2B0, 'M', u'h'), - (0x2B1, 'M', u'ɦ'), - (0x2B2, 'M', u'j'), - (0x2B3, 'M', u'r'), - (0x2B4, 'M', u'ɹ'), - (0x2B5, 'M', u'ɻ'), - (0x2B6, 'M', u'ʁ'), - (0x2B7, 'M', u'w'), - (0x2B8, 'M', u'y'), - (0x2B9, 'V'), - (0x2D8, '3', u' ̆'), - (0x2D9, '3', u' ̇'), - (0x2DA, '3', u' ̊'), - (0x2DB, '3', u' ̨'), - (0x2DC, '3', u' ̃'), - (0x2DD, '3', u' ̋'), - (0x2DE, 'V'), - (0x2E0, 'M', u'ɣ'), - (0x2E1, 'M', u'l'), - (0x2E2, 'M', u's'), - (0x2E3, 'M', u'x'), - (0x2E4, 'M', u'ʕ'), - (0x2E5, 'V'), - (0x340, 'M', u'̀'), - (0x341, 'M', u'́'), - (0x342, 'V'), - (0x343, 'M', u'̓'), - (0x344, 'M', u'̈́'), - (0x345, 'M', u'ι'), - (0x346, 'V'), - (0x34F, 'I'), - (0x350, 'V'), - (0x370, 'M', u'ͱ'), - (0x371, 'V'), - (0x372, 'M', u'ͳ'), - (0x373, 'V'), - (0x374, 'M', u'ʹ'), - (0x375, 'V'), - (0x376, 'M', u'ͷ'), - (0x377, 'V'), - ] - -def _seg_6(): - return [ - (0x378, 'X'), - (0x37A, '3', u' ι'), - (0x37B, 'V'), - (0x37E, '3', u';'), - (0x37F, 'M', u'ϳ'), - (0x380, 'X'), - (0x384, '3', u' ́'), - (0x385, '3', u' ̈́'), - (0x386, 'M', u'ά'), - (0x387, 'M', u'·'), - (0x388, 'M', u'έ'), - (0x389, 'M', u'ή'), - (0x38A, 'M', u'ί'), - (0x38B, 'X'), - (0x38C, 'M', u'ό'), - (0x38D, 'X'), - (0x38E, 'M', u'ύ'), - (0x38F, 'M', u'ώ'), - (0x390, 'V'), - (0x391, 'M', u'α'), - (0x392, 'M', u'β'), - (0x393, 'M', u'γ'), - (0x394, 'M', u'δ'), - (0x395, 'M', u'ε'), - (0x396, 'M', u'ζ'), - (0x397, 'M', u'η'), - (0x398, 'M', u'θ'), - (0x399, 'M', u'ι'), - (0x39A, 'M', u'κ'), - (0x39B, 'M', u'λ'), - (0x39C, 'M', u'μ'), - (0x39D, 'M', u'ν'), - (0x39E, 'M', u'ξ'), - (0x39F, 'M', u'ο'), - (0x3A0, 'M', u'π'), - (0x3A1, 'M', u'ρ'), - (0x3A2, 'X'), - (0x3A3, 'M', u'σ'), - (0x3A4, 'M', u'τ'), - (0x3A5, 'M', u'υ'), - (0x3A6, 'M', u'φ'), - (0x3A7, 'M', u'χ'), - (0x3A8, 'M', u'ψ'), - (0x3A9, 'M', u'ω'), - (0x3AA, 'M', u'ϊ'), - (0x3AB, 'M', u'ϋ'), - (0x3AC, 'V'), - (0x3C2, 'D', u'σ'), - (0x3C3, 'V'), - (0x3CF, 'M', u'ϗ'), - (0x3D0, 'M', u'β'), - (0x3D1, 'M', u'θ'), - (0x3D2, 'M', u'υ'), - (0x3D3, 'M', u'ύ'), - (0x3D4, 'M', u'ϋ'), - (0x3D5, 'M', u'φ'), - (0x3D6, 'M', u'π'), - (0x3D7, 'V'), - (0x3D8, 'M', u'ϙ'), - (0x3D9, 'V'), - (0x3DA, 'M', u'ϛ'), - (0x3DB, 'V'), - (0x3DC, 'M', u'ϝ'), - (0x3DD, 'V'), - (0x3DE, 'M', u'ϟ'), - (0x3DF, 'V'), - (0x3E0, 'M', u'ϡ'), - (0x3E1, 'V'), - (0x3E2, 'M', u'ϣ'), - (0x3E3, 'V'), - (0x3E4, 'M', u'ϥ'), - (0x3E5, 'V'), - (0x3E6, 'M', u'ϧ'), - (0x3E7, 'V'), - (0x3E8, 'M', u'ϩ'), - (0x3E9, 'V'), - (0x3EA, 'M', u'ϫ'), - (0x3EB, 'V'), - (0x3EC, 'M', u'ϭ'), - (0x3ED, 'V'), - (0x3EE, 'M', u'ϯ'), - (0x3EF, 'V'), - (0x3F0, 'M', u'κ'), - (0x3F1, 'M', u'ρ'), - (0x3F2, 'M', u'σ'), - (0x3F3, 'V'), - (0x3F4, 'M', u'θ'), - (0x3F5, 'M', u'ε'), - (0x3F6, 'V'), - (0x3F7, 'M', u'ϸ'), - (0x3F8, 'V'), - (0x3F9, 'M', u'σ'), - (0x3FA, 'M', u'ϻ'), - (0x3FB, 'V'), - (0x3FD, 'M', u'ͻ'), - (0x3FE, 'M', u'ͼ'), - (0x3FF, 'M', u'ͽ'), - (0x400, 'M', u'ѐ'), - (0x401, 'M', u'ё'), - (0x402, 'M', u'ђ'), - ] - -def _seg_7(): - return [ - (0x403, 'M', u'ѓ'), - (0x404, 'M', u'є'), - (0x405, 'M', u'ѕ'), - (0x406, 'M', u'і'), - (0x407, 'M', u'ї'), - (0x408, 'M', u'ј'), - (0x409, 'M', u'љ'), - (0x40A, 'M', u'њ'), - (0x40B, 'M', u'ћ'), - (0x40C, 'M', u'ќ'), - (0x40D, 'M', u'ѝ'), - (0x40E, 'M', u'ў'), - (0x40F, 'M', u'џ'), - (0x410, 'M', u'а'), - (0x411, 'M', u'б'), - (0x412, 'M', u'в'), - (0x413, 'M', u'г'), - (0x414, 'M', u'д'), - (0x415, 'M', u'е'), - (0x416, 'M', u'ж'), - (0x417, 'M', u'з'), - (0x418, 'M', u'и'), - (0x419, 'M', u'й'), - (0x41A, 'M', u'к'), - (0x41B, 'M', u'л'), - (0x41C, 'M', u'м'), - (0x41D, 'M', u'н'), - (0x41E, 'M', u'о'), - (0x41F, 'M', u'п'), - (0x420, 'M', u'р'), - (0x421, 'M', u'с'), - (0x422, 'M', u'т'), - (0x423, 'M', u'у'), - (0x424, 'M', u'ф'), - (0x425, 'M', u'х'), - (0x426, 'M', u'ц'), - (0x427, 'M', u'ч'), - (0x428, 'M', u'ш'), - (0x429, 'M', u'щ'), - (0x42A, 'M', u'ъ'), - (0x42B, 'M', u'ы'), - (0x42C, 'M', u'ь'), - (0x42D, 'M', u'э'), - (0x42E, 'M', u'ю'), - (0x42F, 'M', u'я'), - (0x430, 'V'), - (0x460, 'M', u'ѡ'), - (0x461, 'V'), - (0x462, 'M', u'ѣ'), - (0x463, 'V'), - (0x464, 'M', u'ѥ'), - (0x465, 'V'), - (0x466, 'M', u'ѧ'), - (0x467, 'V'), - (0x468, 'M', u'ѩ'), - (0x469, 'V'), - (0x46A, 'M', u'ѫ'), - (0x46B, 'V'), - (0x46C, 'M', u'ѭ'), - (0x46D, 'V'), - (0x46E, 'M', u'ѯ'), - (0x46F, 'V'), - (0x470, 'M', u'ѱ'), - (0x471, 'V'), - (0x472, 'M', u'ѳ'), - (0x473, 'V'), - (0x474, 'M', u'ѵ'), - (0x475, 'V'), - (0x476, 'M', u'ѷ'), - (0x477, 'V'), - (0x478, 'M', u'ѹ'), - (0x479, 'V'), - (0x47A, 'M', u'ѻ'), - (0x47B, 'V'), - (0x47C, 'M', u'ѽ'), - (0x47D, 'V'), - (0x47E, 'M', u'ѿ'), - (0x47F, 'V'), - (0x480, 'M', u'ҁ'), - (0x481, 'V'), - (0x48A, 'M', u'ҋ'), - (0x48B, 'V'), - (0x48C, 'M', u'ҍ'), - (0x48D, 'V'), - (0x48E, 'M', u'ҏ'), - (0x48F, 'V'), - (0x490, 'M', u'ґ'), - (0x491, 'V'), - (0x492, 'M', u'ғ'), - (0x493, 'V'), - (0x494, 'M', u'ҕ'), - (0x495, 'V'), - (0x496, 'M', u'җ'), - (0x497, 'V'), - (0x498, 'M', u'ҙ'), - (0x499, 'V'), - (0x49A, 'M', u'қ'), - (0x49B, 'V'), - (0x49C, 'M', u'ҝ'), - (0x49D, 'V'), - ] - -def _seg_8(): - return [ - (0x49E, 'M', u'ҟ'), - (0x49F, 'V'), - (0x4A0, 'M', u'ҡ'), - (0x4A1, 'V'), - (0x4A2, 'M', u'ң'), - (0x4A3, 'V'), - (0x4A4, 'M', u'ҥ'), - (0x4A5, 'V'), - (0x4A6, 'M', u'ҧ'), - (0x4A7, 'V'), - (0x4A8, 'M', u'ҩ'), - (0x4A9, 'V'), - (0x4AA, 'M', u'ҫ'), - (0x4AB, 'V'), - (0x4AC, 'M', u'ҭ'), - (0x4AD, 'V'), - (0x4AE, 'M', u'ү'), - (0x4AF, 'V'), - (0x4B0, 'M', u'ұ'), - (0x4B1, 'V'), - (0x4B2, 'M', u'ҳ'), - (0x4B3, 'V'), - (0x4B4, 'M', u'ҵ'), - (0x4B5, 'V'), - (0x4B6, 'M', u'ҷ'), - (0x4B7, 'V'), - (0x4B8, 'M', u'ҹ'), - (0x4B9, 'V'), - (0x4BA, 'M', u'һ'), - (0x4BB, 'V'), - (0x4BC, 'M', u'ҽ'), - (0x4BD, 'V'), - (0x4BE, 'M', u'ҿ'), - (0x4BF, 'V'), - (0x4C0, 'X'), - (0x4C1, 'M', u'ӂ'), - (0x4C2, 'V'), - (0x4C3, 'M', u'ӄ'), - (0x4C4, 'V'), - (0x4C5, 'M', u'ӆ'), - (0x4C6, 'V'), - (0x4C7, 'M', u'ӈ'), - (0x4C8, 'V'), - (0x4C9, 'M', u'ӊ'), - (0x4CA, 'V'), - (0x4CB, 'M', u'ӌ'), - (0x4CC, 'V'), - (0x4CD, 'M', u'ӎ'), - (0x4CE, 'V'), - (0x4D0, 'M', u'ӑ'), - (0x4D1, 'V'), - (0x4D2, 'M', u'ӓ'), - (0x4D3, 'V'), - (0x4D4, 'M', u'ӕ'), - (0x4D5, 'V'), - (0x4D6, 'M', u'ӗ'), - (0x4D7, 'V'), - (0x4D8, 'M', u'ә'), - (0x4D9, 'V'), - (0x4DA, 'M', u'ӛ'), - (0x4DB, 'V'), - (0x4DC, 'M', u'ӝ'), - (0x4DD, 'V'), - (0x4DE, 'M', u'ӟ'), - (0x4DF, 'V'), - (0x4E0, 'M', u'ӡ'), - (0x4E1, 'V'), - (0x4E2, 'M', u'ӣ'), - (0x4E3, 'V'), - (0x4E4, 'M', u'ӥ'), - (0x4E5, 'V'), - (0x4E6, 'M', u'ӧ'), - (0x4E7, 'V'), - (0x4E8, 'M', u'ө'), - (0x4E9, 'V'), - (0x4EA, 'M', u'ӫ'), - (0x4EB, 'V'), - (0x4EC, 'M', u'ӭ'), - (0x4ED, 'V'), - (0x4EE, 'M', u'ӯ'), - (0x4EF, 'V'), - (0x4F0, 'M', u'ӱ'), - (0x4F1, 'V'), - (0x4F2, 'M', u'ӳ'), - (0x4F3, 'V'), - (0x4F4, 'M', u'ӵ'), - (0x4F5, 'V'), - (0x4F6, 'M', u'ӷ'), - (0x4F7, 'V'), - (0x4F8, 'M', u'ӹ'), - (0x4F9, 'V'), - (0x4FA, 'M', u'ӻ'), - (0x4FB, 'V'), - (0x4FC, 'M', u'ӽ'), - (0x4FD, 'V'), - (0x4FE, 'M', u'ӿ'), - (0x4FF, 'V'), - (0x500, 'M', u'ԁ'), - (0x501, 'V'), - (0x502, 'M', u'ԃ'), - ] - -def _seg_9(): - return [ - (0x503, 'V'), - (0x504, 'M', u'ԅ'), - (0x505, 'V'), - (0x506, 'M', u'ԇ'), - (0x507, 'V'), - (0x508, 'M', u'ԉ'), - (0x509, 'V'), - (0x50A, 'M', u'ԋ'), - (0x50B, 'V'), - (0x50C, 'M', u'ԍ'), - (0x50D, 'V'), - (0x50E, 'M', u'ԏ'), - (0x50F, 'V'), - (0x510, 'M', u'ԑ'), - (0x511, 'V'), - (0x512, 'M', u'ԓ'), - (0x513, 'V'), - (0x514, 'M', u'ԕ'), - (0x515, 'V'), - (0x516, 'M', u'ԗ'), - (0x517, 'V'), - (0x518, 'M', u'ԙ'), - (0x519, 'V'), - (0x51A, 'M', u'ԛ'), - (0x51B, 'V'), - (0x51C, 'M', u'ԝ'), - (0x51D, 'V'), - (0x51E, 'M', u'ԟ'), - (0x51F, 'V'), - (0x520, 'M', u'ԡ'), - (0x521, 'V'), - (0x522, 'M', u'ԣ'), - (0x523, 'V'), - (0x524, 'M', u'ԥ'), - (0x525, 'V'), - (0x526, 'M', u'ԧ'), - (0x527, 'V'), - (0x528, 'M', u'ԩ'), - (0x529, 'V'), - (0x52A, 'M', u'ԫ'), - (0x52B, 'V'), - (0x52C, 'M', u'ԭ'), - (0x52D, 'V'), - (0x52E, 'M', u'ԯ'), - (0x52F, 'V'), - (0x530, 'X'), - (0x531, 'M', u'ա'), - (0x532, 'M', u'բ'), - (0x533, 'M', u'գ'), - (0x534, 'M', u'դ'), - (0x535, 'M', u'ե'), - (0x536, 'M', u'զ'), - (0x537, 'M', u'է'), - (0x538, 'M', u'ը'), - (0x539, 'M', u'թ'), - (0x53A, 'M', u'ժ'), - (0x53B, 'M', u'ի'), - (0x53C, 'M', u'լ'), - (0x53D, 'M', u'խ'), - (0x53E, 'M', u'ծ'), - (0x53F, 'M', u'կ'), - (0x540, 'M', u'հ'), - (0x541, 'M', u'ձ'), - (0x542, 'M', u'ղ'), - (0x543, 'M', u'ճ'), - (0x544, 'M', u'մ'), - (0x545, 'M', u'յ'), - (0x546, 'M', u'ն'), - (0x547, 'M', u'շ'), - (0x548, 'M', u'ո'), - (0x549, 'M', u'չ'), - (0x54A, 'M', u'պ'), - (0x54B, 'M', u'ջ'), - (0x54C, 'M', u'ռ'), - (0x54D, 'M', u'ս'), - (0x54E, 'M', u'վ'), - (0x54F, 'M', u'տ'), - (0x550, 'M', u'ր'), - (0x551, 'M', u'ց'), - (0x552, 'M', u'ւ'), - (0x553, 'M', u'փ'), - (0x554, 'M', u'ք'), - (0x555, 'M', u'օ'), - (0x556, 'M', u'ֆ'), - (0x557, 'X'), - (0x559, 'V'), - (0x587, 'M', u'եւ'), - (0x588, 'V'), - (0x58B, 'X'), - (0x58D, 'V'), - (0x590, 'X'), - (0x591, 'V'), - (0x5C8, 'X'), - (0x5D0, 'V'), - (0x5EB, 'X'), - (0x5EF, 'V'), - (0x5F5, 'X'), - (0x606, 'V'), - (0x61C, 'X'), - (0x61E, 'V'), - ] - -def _seg_10(): - return [ - (0x675, 'M', u'اٴ'), - (0x676, 'M', u'وٴ'), - (0x677, 'M', u'ۇٴ'), - (0x678, 'M', u'يٴ'), - (0x679, 'V'), - (0x6DD, 'X'), - (0x6DE, 'V'), - (0x70E, 'X'), - (0x710, 'V'), - (0x74B, 'X'), - (0x74D, 'V'), - (0x7B2, 'X'), - (0x7C0, 'V'), - (0x7FB, 'X'), - (0x7FD, 'V'), - (0x82E, 'X'), - (0x830, 'V'), - (0x83F, 'X'), - (0x840, 'V'), - (0x85C, 'X'), - (0x85E, 'V'), - (0x85F, 'X'), - (0x860, 'V'), - (0x86B, 'X'), - (0x8A0, 'V'), - (0x8B5, 'X'), - (0x8B6, 'V'), - (0x8C8, 'X'), - (0x8D3, 'V'), - (0x8E2, 'X'), - (0x8E3, 'V'), - (0x958, 'M', u'क़'), - (0x959, 'M', u'ख़'), - (0x95A, 'M', u'ग़'), - (0x95B, 'M', u'ज़'), - (0x95C, 'M', u'ड़'), - (0x95D, 'M', u'ढ़'), - (0x95E, 'M', u'फ़'), - (0x95F, 'M', u'य़'), - (0x960, 'V'), - (0x984, 'X'), - (0x985, 'V'), - (0x98D, 'X'), - (0x98F, 'V'), - (0x991, 'X'), - (0x993, 'V'), - (0x9A9, 'X'), - (0x9AA, 'V'), - (0x9B1, 'X'), - (0x9B2, 'V'), - (0x9B3, 'X'), - (0x9B6, 'V'), - (0x9BA, 'X'), - (0x9BC, 'V'), - (0x9C5, 'X'), - (0x9C7, 'V'), - (0x9C9, 'X'), - (0x9CB, 'V'), - (0x9CF, 'X'), - (0x9D7, 'V'), - (0x9D8, 'X'), - (0x9DC, 'M', u'ড়'), - (0x9DD, 'M', u'ঢ়'), - (0x9DE, 'X'), - (0x9DF, 'M', u'য়'), - (0x9E0, 'V'), - (0x9E4, 'X'), - (0x9E6, 'V'), - (0x9FF, 'X'), - (0xA01, 'V'), - (0xA04, 'X'), - (0xA05, 'V'), - (0xA0B, 'X'), - (0xA0F, 'V'), - (0xA11, 'X'), - (0xA13, 'V'), - (0xA29, 'X'), - (0xA2A, 'V'), - (0xA31, 'X'), - (0xA32, 'V'), - (0xA33, 'M', u'ਲ਼'), - (0xA34, 'X'), - (0xA35, 'V'), - (0xA36, 'M', u'ਸ਼'), - (0xA37, 'X'), - (0xA38, 'V'), - (0xA3A, 'X'), - (0xA3C, 'V'), - (0xA3D, 'X'), - (0xA3E, 'V'), - (0xA43, 'X'), - (0xA47, 'V'), - (0xA49, 'X'), - (0xA4B, 'V'), - (0xA4E, 'X'), - (0xA51, 'V'), - (0xA52, 'X'), - (0xA59, 'M', u'ਖ਼'), - (0xA5A, 'M', u'ਗ਼'), - (0xA5B, 'M', u'ਜ਼'), - ] - -def _seg_11(): - return [ - (0xA5C, 'V'), - (0xA5D, 'X'), - (0xA5E, 'M', u'ਫ਼'), - (0xA5F, 'X'), - (0xA66, 'V'), - (0xA77, 'X'), - (0xA81, 'V'), - (0xA84, 'X'), - (0xA85, 'V'), - (0xA8E, 'X'), - (0xA8F, 'V'), - (0xA92, 'X'), - (0xA93, 'V'), - (0xAA9, 'X'), - (0xAAA, 'V'), - (0xAB1, 'X'), - (0xAB2, 'V'), - (0xAB4, 'X'), - (0xAB5, 'V'), - (0xABA, 'X'), - (0xABC, 'V'), - (0xAC6, 'X'), - (0xAC7, 'V'), - (0xACA, 'X'), - (0xACB, 'V'), - (0xACE, 'X'), - (0xAD0, 'V'), - (0xAD1, 'X'), - (0xAE0, 'V'), - (0xAE4, 'X'), - (0xAE6, 'V'), - (0xAF2, 'X'), - (0xAF9, 'V'), - (0xB00, 'X'), - (0xB01, 'V'), - (0xB04, 'X'), - (0xB05, 'V'), - (0xB0D, 'X'), - (0xB0F, 'V'), - (0xB11, 'X'), - (0xB13, 'V'), - (0xB29, 'X'), - (0xB2A, 'V'), - (0xB31, 'X'), - (0xB32, 'V'), - (0xB34, 'X'), - (0xB35, 'V'), - (0xB3A, 'X'), - (0xB3C, 'V'), - (0xB45, 'X'), - (0xB47, 'V'), - (0xB49, 'X'), - (0xB4B, 'V'), - (0xB4E, 'X'), - (0xB55, 'V'), - (0xB58, 'X'), - (0xB5C, 'M', u'ଡ଼'), - (0xB5D, 'M', u'ଢ଼'), - (0xB5E, 'X'), - (0xB5F, 'V'), - (0xB64, 'X'), - (0xB66, 'V'), - (0xB78, 'X'), - (0xB82, 'V'), - (0xB84, 'X'), - (0xB85, 'V'), - (0xB8B, 'X'), - (0xB8E, 'V'), - (0xB91, 'X'), - (0xB92, 'V'), - (0xB96, 'X'), - (0xB99, 'V'), - (0xB9B, 'X'), - (0xB9C, 'V'), - (0xB9D, 'X'), - (0xB9E, 'V'), - (0xBA0, 'X'), - (0xBA3, 'V'), - (0xBA5, 'X'), - (0xBA8, 'V'), - (0xBAB, 'X'), - (0xBAE, 'V'), - (0xBBA, 'X'), - (0xBBE, 'V'), - (0xBC3, 'X'), - (0xBC6, 'V'), - (0xBC9, 'X'), - (0xBCA, 'V'), - (0xBCE, 'X'), - (0xBD0, 'V'), - (0xBD1, 'X'), - (0xBD7, 'V'), - (0xBD8, 'X'), - (0xBE6, 'V'), - (0xBFB, 'X'), - (0xC00, 'V'), - (0xC0D, 'X'), - (0xC0E, 'V'), - (0xC11, 'X'), - (0xC12, 'V'), - ] - -def _seg_12(): - return [ - (0xC29, 'X'), - (0xC2A, 'V'), - (0xC3A, 'X'), - (0xC3D, 'V'), - (0xC45, 'X'), - (0xC46, 'V'), - (0xC49, 'X'), - (0xC4A, 'V'), - (0xC4E, 'X'), - (0xC55, 'V'), - (0xC57, 'X'), - (0xC58, 'V'), - (0xC5B, 'X'), - (0xC60, 'V'), - (0xC64, 'X'), - (0xC66, 'V'), - (0xC70, 'X'), - (0xC77, 'V'), - (0xC8D, 'X'), - (0xC8E, 'V'), - (0xC91, 'X'), - (0xC92, 'V'), - (0xCA9, 'X'), - (0xCAA, 'V'), - (0xCB4, 'X'), - (0xCB5, 'V'), - (0xCBA, 'X'), - (0xCBC, 'V'), - (0xCC5, 'X'), - (0xCC6, 'V'), - (0xCC9, 'X'), - (0xCCA, 'V'), - (0xCCE, 'X'), - (0xCD5, 'V'), - (0xCD7, 'X'), - (0xCDE, 'V'), - (0xCDF, 'X'), - (0xCE0, 'V'), - (0xCE4, 'X'), - (0xCE6, 'V'), - (0xCF0, 'X'), - (0xCF1, 'V'), - (0xCF3, 'X'), - (0xD00, 'V'), - (0xD0D, 'X'), - (0xD0E, 'V'), - (0xD11, 'X'), - (0xD12, 'V'), - (0xD45, 'X'), - (0xD46, 'V'), - (0xD49, 'X'), - (0xD4A, 'V'), - (0xD50, 'X'), - (0xD54, 'V'), - (0xD64, 'X'), - (0xD66, 'V'), - (0xD80, 'X'), - (0xD81, 'V'), - (0xD84, 'X'), - (0xD85, 'V'), - (0xD97, 'X'), - (0xD9A, 'V'), - (0xDB2, 'X'), - (0xDB3, 'V'), - (0xDBC, 'X'), - (0xDBD, 'V'), - (0xDBE, 'X'), - (0xDC0, 'V'), - (0xDC7, 'X'), - (0xDCA, 'V'), - (0xDCB, 'X'), - (0xDCF, 'V'), - (0xDD5, 'X'), - (0xDD6, 'V'), - (0xDD7, 'X'), - (0xDD8, 'V'), - (0xDE0, 'X'), - (0xDE6, 'V'), - (0xDF0, 'X'), - (0xDF2, 'V'), - (0xDF5, 'X'), - (0xE01, 'V'), - (0xE33, 'M', u'ํา'), - (0xE34, 'V'), - (0xE3B, 'X'), - (0xE3F, 'V'), - (0xE5C, 'X'), - (0xE81, 'V'), - (0xE83, 'X'), - (0xE84, 'V'), - (0xE85, 'X'), - (0xE86, 'V'), - (0xE8B, 'X'), - (0xE8C, 'V'), - (0xEA4, 'X'), - (0xEA5, 'V'), - (0xEA6, 'X'), - (0xEA7, 'V'), - (0xEB3, 'M', u'ໍາ'), - (0xEB4, 'V'), - ] - -def _seg_13(): - return [ - (0xEBE, 'X'), - (0xEC0, 'V'), - (0xEC5, 'X'), - (0xEC6, 'V'), - (0xEC7, 'X'), - (0xEC8, 'V'), - (0xECE, 'X'), - (0xED0, 'V'), - (0xEDA, 'X'), - (0xEDC, 'M', u'ຫນ'), - (0xEDD, 'M', u'ຫມ'), - (0xEDE, 'V'), - (0xEE0, 'X'), - (0xF00, 'V'), - (0xF0C, 'M', u'་'), - (0xF0D, 'V'), - (0xF43, 'M', u'གྷ'), - (0xF44, 'V'), - (0xF48, 'X'), - (0xF49, 'V'), - (0xF4D, 'M', u'ཌྷ'), - (0xF4E, 'V'), - (0xF52, 'M', u'དྷ'), - (0xF53, 'V'), - (0xF57, 'M', u'བྷ'), - (0xF58, 'V'), - (0xF5C, 'M', u'ཛྷ'), - (0xF5D, 'V'), - (0xF69, 'M', u'ཀྵ'), - (0xF6A, 'V'), - (0xF6D, 'X'), - (0xF71, 'V'), - (0xF73, 'M', u'ཱི'), - (0xF74, 'V'), - (0xF75, 'M', u'ཱུ'), - (0xF76, 'M', u'ྲྀ'), - (0xF77, 'M', u'ྲཱྀ'), - (0xF78, 'M', u'ླྀ'), - (0xF79, 'M', u'ླཱྀ'), - (0xF7A, 'V'), - (0xF81, 'M', u'ཱྀ'), - (0xF82, 'V'), - (0xF93, 'M', u'ྒྷ'), - (0xF94, 'V'), - (0xF98, 'X'), - (0xF99, 'V'), - (0xF9D, 'M', u'ྜྷ'), - (0xF9E, 'V'), - (0xFA2, 'M', u'ྡྷ'), - (0xFA3, 'V'), - (0xFA7, 'M', u'ྦྷ'), - (0xFA8, 'V'), - (0xFAC, 'M', u'ྫྷ'), - (0xFAD, 'V'), - (0xFB9, 'M', u'ྐྵ'), - (0xFBA, 'V'), - (0xFBD, 'X'), - (0xFBE, 'V'), - (0xFCD, 'X'), - (0xFCE, 'V'), - (0xFDB, 'X'), - (0x1000, 'V'), - (0x10A0, 'X'), - (0x10C7, 'M', u'ⴧ'), - (0x10C8, 'X'), - (0x10CD, 'M', u'ⴭ'), - (0x10CE, 'X'), - (0x10D0, 'V'), - (0x10FC, 'M', u'ნ'), - (0x10FD, 'V'), - (0x115F, 'X'), - (0x1161, 'V'), - (0x1249, 'X'), - (0x124A, 'V'), - (0x124E, 'X'), - (0x1250, 'V'), - (0x1257, 'X'), - (0x1258, 'V'), - (0x1259, 'X'), - (0x125A, 'V'), - (0x125E, 'X'), - (0x1260, 'V'), - (0x1289, 'X'), - (0x128A, 'V'), - (0x128E, 'X'), - (0x1290, 'V'), - (0x12B1, 'X'), - (0x12B2, 'V'), - (0x12B6, 'X'), - (0x12B8, 'V'), - (0x12BF, 'X'), - (0x12C0, 'V'), - (0x12C1, 'X'), - (0x12C2, 'V'), - (0x12C6, 'X'), - (0x12C8, 'V'), - (0x12D7, 'X'), - (0x12D8, 'V'), - (0x1311, 'X'), - (0x1312, 'V'), - ] - -def _seg_14(): - return [ - (0x1316, 'X'), - (0x1318, 'V'), - (0x135B, 'X'), - (0x135D, 'V'), - (0x137D, 'X'), - (0x1380, 'V'), - (0x139A, 'X'), - (0x13A0, 'V'), - (0x13F6, 'X'), - (0x13F8, 'M', u'Ᏸ'), - (0x13F9, 'M', u'Ᏹ'), - (0x13FA, 'M', u'Ᏺ'), - (0x13FB, 'M', u'Ᏻ'), - (0x13FC, 'M', u'Ᏼ'), - (0x13FD, 'M', u'Ᏽ'), - (0x13FE, 'X'), - (0x1400, 'V'), - (0x1680, 'X'), - (0x1681, 'V'), - (0x169D, 'X'), - (0x16A0, 'V'), - (0x16F9, 'X'), - (0x1700, 'V'), - (0x170D, 'X'), - (0x170E, 'V'), - (0x1715, 'X'), - (0x1720, 'V'), - (0x1737, 'X'), - (0x1740, 'V'), - (0x1754, 'X'), - (0x1760, 'V'), - (0x176D, 'X'), - (0x176E, 'V'), - (0x1771, 'X'), - (0x1772, 'V'), - (0x1774, 'X'), - (0x1780, 'V'), - (0x17B4, 'X'), - (0x17B6, 'V'), - (0x17DE, 'X'), - (0x17E0, 'V'), - (0x17EA, 'X'), - (0x17F0, 'V'), - (0x17FA, 'X'), - (0x1800, 'V'), - (0x1806, 'X'), - (0x1807, 'V'), - (0x180B, 'I'), - (0x180E, 'X'), - (0x1810, 'V'), - (0x181A, 'X'), - (0x1820, 'V'), - (0x1879, 'X'), - (0x1880, 'V'), - (0x18AB, 'X'), - (0x18B0, 'V'), - (0x18F6, 'X'), - (0x1900, 'V'), - (0x191F, 'X'), - (0x1920, 'V'), - (0x192C, 'X'), - (0x1930, 'V'), - (0x193C, 'X'), - (0x1940, 'V'), - (0x1941, 'X'), - (0x1944, 'V'), - (0x196E, 'X'), - (0x1970, 'V'), - (0x1975, 'X'), - (0x1980, 'V'), - (0x19AC, 'X'), - (0x19B0, 'V'), - (0x19CA, 'X'), - (0x19D0, 'V'), - (0x19DB, 'X'), - (0x19DE, 'V'), - (0x1A1C, 'X'), - (0x1A1E, 'V'), - (0x1A5F, 'X'), - (0x1A60, 'V'), - (0x1A7D, 'X'), - (0x1A7F, 'V'), - (0x1A8A, 'X'), - (0x1A90, 'V'), - (0x1A9A, 'X'), - (0x1AA0, 'V'), - (0x1AAE, 'X'), - (0x1AB0, 'V'), - (0x1AC1, 'X'), - (0x1B00, 'V'), - (0x1B4C, 'X'), - (0x1B50, 'V'), - (0x1B7D, 'X'), - (0x1B80, 'V'), - (0x1BF4, 'X'), - (0x1BFC, 'V'), - (0x1C38, 'X'), - (0x1C3B, 'V'), - (0x1C4A, 'X'), - (0x1C4D, 'V'), - ] - -def _seg_15(): - return [ - (0x1C80, 'M', u'в'), - (0x1C81, 'M', u'д'), - (0x1C82, 'M', u'о'), - (0x1C83, 'M', u'с'), - (0x1C84, 'M', u'т'), - (0x1C86, 'M', u'ъ'), - (0x1C87, 'M', u'ѣ'), - (0x1C88, 'M', u'ꙋ'), - (0x1C89, 'X'), - (0x1C90, 'M', u'ა'), - (0x1C91, 'M', u'ბ'), - (0x1C92, 'M', u'გ'), - (0x1C93, 'M', u'დ'), - (0x1C94, 'M', u'ე'), - (0x1C95, 'M', u'ვ'), - (0x1C96, 'M', u'ზ'), - (0x1C97, 'M', u'თ'), - (0x1C98, 'M', u'ი'), - (0x1C99, 'M', u'კ'), - (0x1C9A, 'M', u'ლ'), - (0x1C9B, 'M', u'მ'), - (0x1C9C, 'M', u'ნ'), - (0x1C9D, 'M', u'ო'), - (0x1C9E, 'M', u'პ'), - (0x1C9F, 'M', u'ჟ'), - (0x1CA0, 'M', u'რ'), - (0x1CA1, 'M', u'ს'), - (0x1CA2, 'M', u'ტ'), - (0x1CA3, 'M', u'უ'), - (0x1CA4, 'M', u'ფ'), - (0x1CA5, 'M', u'ქ'), - (0x1CA6, 'M', u'ღ'), - (0x1CA7, 'M', u'ყ'), - (0x1CA8, 'M', u'შ'), - (0x1CA9, 'M', u'ჩ'), - (0x1CAA, 'M', u'ც'), - (0x1CAB, 'M', u'ძ'), - (0x1CAC, 'M', u'წ'), - (0x1CAD, 'M', u'ჭ'), - (0x1CAE, 'M', u'ხ'), - (0x1CAF, 'M', u'ჯ'), - (0x1CB0, 'M', u'ჰ'), - (0x1CB1, 'M', u'ჱ'), - (0x1CB2, 'M', u'ჲ'), - (0x1CB3, 'M', u'ჳ'), - (0x1CB4, 'M', u'ჴ'), - (0x1CB5, 'M', u'ჵ'), - (0x1CB6, 'M', u'ჶ'), - (0x1CB7, 'M', u'ჷ'), - (0x1CB8, 'M', u'ჸ'), - (0x1CB9, 'M', u'ჹ'), - (0x1CBA, 'M', u'ჺ'), - (0x1CBB, 'X'), - (0x1CBD, 'M', u'ჽ'), - (0x1CBE, 'M', u'ჾ'), - (0x1CBF, 'M', u'ჿ'), - (0x1CC0, 'V'), - (0x1CC8, 'X'), - (0x1CD0, 'V'), - (0x1CFB, 'X'), - (0x1D00, 'V'), - (0x1D2C, 'M', u'a'), - (0x1D2D, 'M', u'æ'), - (0x1D2E, 'M', u'b'), - (0x1D2F, 'V'), - (0x1D30, 'M', u'd'), - (0x1D31, 'M', u'e'), - (0x1D32, 'M', u'ǝ'), - (0x1D33, 'M', u'g'), - (0x1D34, 'M', u'h'), - (0x1D35, 'M', u'i'), - (0x1D36, 'M', u'j'), - (0x1D37, 'M', u'k'), - (0x1D38, 'M', u'l'), - (0x1D39, 'M', u'm'), - (0x1D3A, 'M', u'n'), - (0x1D3B, 'V'), - (0x1D3C, 'M', u'o'), - (0x1D3D, 'M', u'ȣ'), - (0x1D3E, 'M', u'p'), - (0x1D3F, 'M', u'r'), - (0x1D40, 'M', u't'), - (0x1D41, 'M', u'u'), - (0x1D42, 'M', u'w'), - (0x1D43, 'M', u'a'), - (0x1D44, 'M', u'ɐ'), - (0x1D45, 'M', u'ɑ'), - (0x1D46, 'M', u'ᴂ'), - (0x1D47, 'M', u'b'), - (0x1D48, 'M', u'd'), - (0x1D49, 'M', u'e'), - (0x1D4A, 'M', u'ə'), - (0x1D4B, 'M', u'ɛ'), - (0x1D4C, 'M', u'ɜ'), - (0x1D4D, 'M', u'g'), - (0x1D4E, 'V'), - (0x1D4F, 'M', u'k'), - (0x1D50, 'M', u'm'), - (0x1D51, 'M', u'ŋ'), - (0x1D52, 'M', u'o'), - ] - -def _seg_16(): - return [ - (0x1D53, 'M', u'ɔ'), - (0x1D54, 'M', u'ᴖ'), - (0x1D55, 'M', u'ᴗ'), - (0x1D56, 'M', u'p'), - (0x1D57, 'M', u't'), - (0x1D58, 'M', u'u'), - (0x1D59, 'M', u'ᴝ'), - (0x1D5A, 'M', u'ɯ'), - (0x1D5B, 'M', u'v'), - (0x1D5C, 'M', u'ᴥ'), - (0x1D5D, 'M', u'β'), - (0x1D5E, 'M', u'γ'), - (0x1D5F, 'M', u'δ'), - (0x1D60, 'M', u'φ'), - (0x1D61, 'M', u'χ'), - (0x1D62, 'M', u'i'), - (0x1D63, 'M', u'r'), - (0x1D64, 'M', u'u'), - (0x1D65, 'M', u'v'), - (0x1D66, 'M', u'β'), - (0x1D67, 'M', u'γ'), - (0x1D68, 'M', u'ρ'), - (0x1D69, 'M', u'φ'), - (0x1D6A, 'M', u'χ'), - (0x1D6B, 'V'), - (0x1D78, 'M', u'н'), - (0x1D79, 'V'), - (0x1D9B, 'M', u'ɒ'), - (0x1D9C, 'M', u'c'), - (0x1D9D, 'M', u'ɕ'), - (0x1D9E, 'M', u'ð'), - (0x1D9F, 'M', u'ɜ'), - (0x1DA0, 'M', u'f'), - (0x1DA1, 'M', u'ɟ'), - (0x1DA2, 'M', u'ɡ'), - (0x1DA3, 'M', u'ɥ'), - (0x1DA4, 'M', u'ɨ'), - (0x1DA5, 'M', u'ɩ'), - (0x1DA6, 'M', u'ɪ'), - (0x1DA7, 'M', u'ᵻ'), - (0x1DA8, 'M', u'ʝ'), - (0x1DA9, 'M', u'ɭ'), - (0x1DAA, 'M', u'ᶅ'), - (0x1DAB, 'M', u'ʟ'), - (0x1DAC, 'M', u'ɱ'), - (0x1DAD, 'M', u'ɰ'), - (0x1DAE, 'M', u'ɲ'), - (0x1DAF, 'M', u'ɳ'), - (0x1DB0, 'M', u'ɴ'), - (0x1DB1, 'M', u'ɵ'), - (0x1DB2, 'M', u'ɸ'), - (0x1DB3, 'M', u'ʂ'), - (0x1DB4, 'M', u'ʃ'), - (0x1DB5, 'M', u'ƫ'), - (0x1DB6, 'M', u'ʉ'), - (0x1DB7, 'M', u'ʊ'), - (0x1DB8, 'M', u'ᴜ'), - (0x1DB9, 'M', u'ʋ'), - (0x1DBA, 'M', u'ʌ'), - (0x1DBB, 'M', u'z'), - (0x1DBC, 'M', u'ʐ'), - (0x1DBD, 'M', u'ʑ'), - (0x1DBE, 'M', u'ʒ'), - (0x1DBF, 'M', u'θ'), - (0x1DC0, 'V'), - (0x1DFA, 'X'), - (0x1DFB, 'V'), - (0x1E00, 'M', u'ḁ'), - (0x1E01, 'V'), - (0x1E02, 'M', u'ḃ'), - (0x1E03, 'V'), - (0x1E04, 'M', u'ḅ'), - (0x1E05, 'V'), - (0x1E06, 'M', u'ḇ'), - (0x1E07, 'V'), - (0x1E08, 'M', u'ḉ'), - (0x1E09, 'V'), - (0x1E0A, 'M', u'ḋ'), - (0x1E0B, 'V'), - (0x1E0C, 'M', u'ḍ'), - (0x1E0D, 'V'), - (0x1E0E, 'M', u'ḏ'), - (0x1E0F, 'V'), - (0x1E10, 'M', u'ḑ'), - (0x1E11, 'V'), - (0x1E12, 'M', u'ḓ'), - (0x1E13, 'V'), - (0x1E14, 'M', u'ḕ'), - (0x1E15, 'V'), - (0x1E16, 'M', u'ḗ'), - (0x1E17, 'V'), - (0x1E18, 'M', u'ḙ'), - (0x1E19, 'V'), - (0x1E1A, 'M', u'ḛ'), - (0x1E1B, 'V'), - (0x1E1C, 'M', u'ḝ'), - (0x1E1D, 'V'), - (0x1E1E, 'M', u'ḟ'), - (0x1E1F, 'V'), - (0x1E20, 'M', u'ḡ'), - ] - -def _seg_17(): - return [ - (0x1E21, 'V'), - (0x1E22, 'M', u'ḣ'), - (0x1E23, 'V'), - (0x1E24, 'M', u'ḥ'), - (0x1E25, 'V'), - (0x1E26, 'M', u'ḧ'), - (0x1E27, 'V'), - (0x1E28, 'M', u'ḩ'), - (0x1E29, 'V'), - (0x1E2A, 'M', u'ḫ'), - (0x1E2B, 'V'), - (0x1E2C, 'M', u'ḭ'), - (0x1E2D, 'V'), - (0x1E2E, 'M', u'ḯ'), - (0x1E2F, 'V'), - (0x1E30, 'M', u'ḱ'), - (0x1E31, 'V'), - (0x1E32, 'M', u'ḳ'), - (0x1E33, 'V'), - (0x1E34, 'M', u'ḵ'), - (0x1E35, 'V'), - (0x1E36, 'M', u'ḷ'), - (0x1E37, 'V'), - (0x1E38, 'M', u'ḹ'), - (0x1E39, 'V'), - (0x1E3A, 'M', u'ḻ'), - (0x1E3B, 'V'), - (0x1E3C, 'M', u'ḽ'), - (0x1E3D, 'V'), - (0x1E3E, 'M', u'ḿ'), - (0x1E3F, 'V'), - (0x1E40, 'M', u'ṁ'), - (0x1E41, 'V'), - (0x1E42, 'M', u'ṃ'), - (0x1E43, 'V'), - (0x1E44, 'M', u'ṅ'), - (0x1E45, 'V'), - (0x1E46, 'M', u'ṇ'), - (0x1E47, 'V'), - (0x1E48, 'M', u'ṉ'), - (0x1E49, 'V'), - (0x1E4A, 'M', u'ṋ'), - (0x1E4B, 'V'), - (0x1E4C, 'M', u'ṍ'), - (0x1E4D, 'V'), - (0x1E4E, 'M', u'ṏ'), - (0x1E4F, 'V'), - (0x1E50, 'M', u'ṑ'), - (0x1E51, 'V'), - (0x1E52, 'M', u'ṓ'), - (0x1E53, 'V'), - (0x1E54, 'M', u'ṕ'), - (0x1E55, 'V'), - (0x1E56, 'M', u'ṗ'), - (0x1E57, 'V'), - (0x1E58, 'M', u'ṙ'), - (0x1E59, 'V'), - (0x1E5A, 'M', u'ṛ'), - (0x1E5B, 'V'), - (0x1E5C, 'M', u'ṝ'), - (0x1E5D, 'V'), - (0x1E5E, 'M', u'ṟ'), - (0x1E5F, 'V'), - (0x1E60, 'M', u'ṡ'), - (0x1E61, 'V'), - (0x1E62, 'M', u'ṣ'), - (0x1E63, 'V'), - (0x1E64, 'M', u'ṥ'), - (0x1E65, 'V'), - (0x1E66, 'M', u'ṧ'), - (0x1E67, 'V'), - (0x1E68, 'M', u'ṩ'), - (0x1E69, 'V'), - (0x1E6A, 'M', u'ṫ'), - (0x1E6B, 'V'), - (0x1E6C, 'M', u'ṭ'), - (0x1E6D, 'V'), - (0x1E6E, 'M', u'ṯ'), - (0x1E6F, 'V'), - (0x1E70, 'M', u'ṱ'), - (0x1E71, 'V'), - (0x1E72, 'M', u'ṳ'), - (0x1E73, 'V'), - (0x1E74, 'M', u'ṵ'), - (0x1E75, 'V'), - (0x1E76, 'M', u'ṷ'), - (0x1E77, 'V'), - (0x1E78, 'M', u'ṹ'), - (0x1E79, 'V'), - (0x1E7A, 'M', u'ṻ'), - (0x1E7B, 'V'), - (0x1E7C, 'M', u'ṽ'), - (0x1E7D, 'V'), - (0x1E7E, 'M', u'ṿ'), - (0x1E7F, 'V'), - (0x1E80, 'M', u'ẁ'), - (0x1E81, 'V'), - (0x1E82, 'M', u'ẃ'), - (0x1E83, 'V'), - (0x1E84, 'M', u'ẅ'), - ] - -def _seg_18(): - return [ - (0x1E85, 'V'), - (0x1E86, 'M', u'ẇ'), - (0x1E87, 'V'), - (0x1E88, 'M', u'ẉ'), - (0x1E89, 'V'), - (0x1E8A, 'M', u'ẋ'), - (0x1E8B, 'V'), - (0x1E8C, 'M', u'ẍ'), - (0x1E8D, 'V'), - (0x1E8E, 'M', u'ẏ'), - (0x1E8F, 'V'), - (0x1E90, 'M', u'ẑ'), - (0x1E91, 'V'), - (0x1E92, 'M', u'ẓ'), - (0x1E93, 'V'), - (0x1E94, 'M', u'ẕ'), - (0x1E95, 'V'), - (0x1E9A, 'M', u'aʾ'), - (0x1E9B, 'M', u'ṡ'), - (0x1E9C, 'V'), - (0x1E9E, 'M', u'ss'), - (0x1E9F, 'V'), - (0x1EA0, 'M', u'ạ'), - (0x1EA1, 'V'), - (0x1EA2, 'M', u'ả'), - (0x1EA3, 'V'), - (0x1EA4, 'M', u'ấ'), - (0x1EA5, 'V'), - (0x1EA6, 'M', u'ầ'), - (0x1EA7, 'V'), - (0x1EA8, 'M', u'ẩ'), - (0x1EA9, 'V'), - (0x1EAA, 'M', u'ẫ'), - (0x1EAB, 'V'), - (0x1EAC, 'M', u'ậ'), - (0x1EAD, 'V'), - (0x1EAE, 'M', u'ắ'), - (0x1EAF, 'V'), - (0x1EB0, 'M', u'ằ'), - (0x1EB1, 'V'), - (0x1EB2, 'M', u'ẳ'), - (0x1EB3, 'V'), - (0x1EB4, 'M', u'ẵ'), - (0x1EB5, 'V'), - (0x1EB6, 'M', u'ặ'), - (0x1EB7, 'V'), - (0x1EB8, 'M', u'ẹ'), - (0x1EB9, 'V'), - (0x1EBA, 'M', u'ẻ'), - (0x1EBB, 'V'), - (0x1EBC, 'M', u'ẽ'), - (0x1EBD, 'V'), - (0x1EBE, 'M', u'ế'), - (0x1EBF, 'V'), - (0x1EC0, 'M', u'ề'), - (0x1EC1, 'V'), - (0x1EC2, 'M', u'ể'), - (0x1EC3, 'V'), - (0x1EC4, 'M', u'ễ'), - (0x1EC5, 'V'), - (0x1EC6, 'M', u'ệ'), - (0x1EC7, 'V'), - (0x1EC8, 'M', u'ỉ'), - (0x1EC9, 'V'), - (0x1ECA, 'M', u'ị'), - (0x1ECB, 'V'), - (0x1ECC, 'M', u'ọ'), - (0x1ECD, 'V'), - (0x1ECE, 'M', u'ỏ'), - (0x1ECF, 'V'), - (0x1ED0, 'M', u'ố'), - (0x1ED1, 'V'), - (0x1ED2, 'M', u'ồ'), - (0x1ED3, 'V'), - (0x1ED4, 'M', u'ổ'), - (0x1ED5, 'V'), - (0x1ED6, 'M', u'ỗ'), - (0x1ED7, 'V'), - (0x1ED8, 'M', u'ộ'), - (0x1ED9, 'V'), - (0x1EDA, 'M', u'ớ'), - (0x1EDB, 'V'), - (0x1EDC, 'M', u'ờ'), - (0x1EDD, 'V'), - (0x1EDE, 'M', u'ở'), - (0x1EDF, 'V'), - (0x1EE0, 'M', u'ỡ'), - (0x1EE1, 'V'), - (0x1EE2, 'M', u'ợ'), - (0x1EE3, 'V'), - (0x1EE4, 'M', u'ụ'), - (0x1EE5, 'V'), - (0x1EE6, 'M', u'ủ'), - (0x1EE7, 'V'), - (0x1EE8, 'M', u'ứ'), - (0x1EE9, 'V'), - (0x1EEA, 'M', u'ừ'), - (0x1EEB, 'V'), - (0x1EEC, 'M', u'ử'), - (0x1EED, 'V'), - ] - -def _seg_19(): - return [ - (0x1EEE, 'M', u'ữ'), - (0x1EEF, 'V'), - (0x1EF0, 'M', u'ự'), - (0x1EF1, 'V'), - (0x1EF2, 'M', u'ỳ'), - (0x1EF3, 'V'), - (0x1EF4, 'M', u'ỵ'), - (0x1EF5, 'V'), - (0x1EF6, 'M', u'ỷ'), - (0x1EF7, 'V'), - (0x1EF8, 'M', u'ỹ'), - (0x1EF9, 'V'), - (0x1EFA, 'M', u'ỻ'), - (0x1EFB, 'V'), - (0x1EFC, 'M', u'ỽ'), - (0x1EFD, 'V'), - (0x1EFE, 'M', u'ỿ'), - (0x1EFF, 'V'), - (0x1F08, 'M', u'ἀ'), - (0x1F09, 'M', u'ἁ'), - (0x1F0A, 'M', u'ἂ'), - (0x1F0B, 'M', u'ἃ'), - (0x1F0C, 'M', u'ἄ'), - (0x1F0D, 'M', u'ἅ'), - (0x1F0E, 'M', u'ἆ'), - (0x1F0F, 'M', u'ἇ'), - (0x1F10, 'V'), - (0x1F16, 'X'), - (0x1F18, 'M', u'ἐ'), - (0x1F19, 'M', u'ἑ'), - (0x1F1A, 'M', u'ἒ'), - (0x1F1B, 'M', u'ἓ'), - (0x1F1C, 'M', u'ἔ'), - (0x1F1D, 'M', u'ἕ'), - (0x1F1E, 'X'), - (0x1F20, 'V'), - (0x1F28, 'M', u'ἠ'), - (0x1F29, 'M', u'ἡ'), - (0x1F2A, 'M', u'ἢ'), - (0x1F2B, 'M', u'ἣ'), - (0x1F2C, 'M', u'ἤ'), - (0x1F2D, 'M', u'ἥ'), - (0x1F2E, 'M', u'ἦ'), - (0x1F2F, 'M', u'ἧ'), - (0x1F30, 'V'), - (0x1F38, 'M', u'ἰ'), - (0x1F39, 'M', u'ἱ'), - (0x1F3A, 'M', u'ἲ'), - (0x1F3B, 'M', u'ἳ'), - (0x1F3C, 'M', u'ἴ'), - (0x1F3D, 'M', u'ἵ'), - (0x1F3E, 'M', u'ἶ'), - (0x1F3F, 'M', u'ἷ'), - (0x1F40, 'V'), - (0x1F46, 'X'), - (0x1F48, 'M', u'ὀ'), - (0x1F49, 'M', u'ὁ'), - (0x1F4A, 'M', u'ὂ'), - (0x1F4B, 'M', u'ὃ'), - (0x1F4C, 'M', u'ὄ'), - (0x1F4D, 'M', u'ὅ'), - (0x1F4E, 'X'), - (0x1F50, 'V'), - (0x1F58, 'X'), - (0x1F59, 'M', u'ὑ'), - (0x1F5A, 'X'), - (0x1F5B, 'M', u'ὓ'), - (0x1F5C, 'X'), - (0x1F5D, 'M', u'ὕ'), - (0x1F5E, 'X'), - (0x1F5F, 'M', u'ὗ'), - (0x1F60, 'V'), - (0x1F68, 'M', u'ὠ'), - (0x1F69, 'M', u'ὡ'), - (0x1F6A, 'M', u'ὢ'), - (0x1F6B, 'M', u'ὣ'), - (0x1F6C, 'M', u'ὤ'), - (0x1F6D, 'M', u'ὥ'), - (0x1F6E, 'M', u'ὦ'), - (0x1F6F, 'M', u'ὧ'), - (0x1F70, 'V'), - (0x1F71, 'M', u'ά'), - (0x1F72, 'V'), - (0x1F73, 'M', u'έ'), - (0x1F74, 'V'), - (0x1F75, 'M', u'ή'), - (0x1F76, 'V'), - (0x1F77, 'M', u'ί'), - (0x1F78, 'V'), - (0x1F79, 'M', u'ό'), - (0x1F7A, 'V'), - (0x1F7B, 'M', u'ύ'), - (0x1F7C, 'V'), - (0x1F7D, 'M', u'ώ'), - (0x1F7E, 'X'), - (0x1F80, 'M', u'ἀι'), - (0x1F81, 'M', u'ἁι'), - (0x1F82, 'M', u'ἂι'), - (0x1F83, 'M', u'ἃι'), - (0x1F84, 'M', u'ἄι'), - ] - -def _seg_20(): - return [ - (0x1F85, 'M', u'ἅι'), - (0x1F86, 'M', u'ἆι'), - (0x1F87, 'M', u'ἇι'), - (0x1F88, 'M', u'ἀι'), - (0x1F89, 'M', u'ἁι'), - (0x1F8A, 'M', u'ἂι'), - (0x1F8B, 'M', u'ἃι'), - (0x1F8C, 'M', u'ἄι'), - (0x1F8D, 'M', u'ἅι'), - (0x1F8E, 'M', u'ἆι'), - (0x1F8F, 'M', u'ἇι'), - (0x1F90, 'M', u'ἠι'), - (0x1F91, 'M', u'ἡι'), - (0x1F92, 'M', u'ἢι'), - (0x1F93, 'M', u'ἣι'), - (0x1F94, 'M', u'ἤι'), - (0x1F95, 'M', u'ἥι'), - (0x1F96, 'M', u'ἦι'), - (0x1F97, 'M', u'ἧι'), - (0x1F98, 'M', u'ἠι'), - (0x1F99, 'M', u'ἡι'), - (0x1F9A, 'M', u'ἢι'), - (0x1F9B, 'M', u'ἣι'), - (0x1F9C, 'M', u'ἤι'), - (0x1F9D, 'M', u'ἥι'), - (0x1F9E, 'M', u'ἦι'), - (0x1F9F, 'M', u'ἧι'), - (0x1FA0, 'M', u'ὠι'), - (0x1FA1, 'M', u'ὡι'), - (0x1FA2, 'M', u'ὢι'), - (0x1FA3, 'M', u'ὣι'), - (0x1FA4, 'M', u'ὤι'), - (0x1FA5, 'M', u'ὥι'), - (0x1FA6, 'M', u'ὦι'), - (0x1FA7, 'M', u'ὧι'), - (0x1FA8, 'M', u'ὠι'), - (0x1FA9, 'M', u'ὡι'), - (0x1FAA, 'M', u'ὢι'), - (0x1FAB, 'M', u'ὣι'), - (0x1FAC, 'M', u'ὤι'), - (0x1FAD, 'M', u'ὥι'), - (0x1FAE, 'M', u'ὦι'), - (0x1FAF, 'M', u'ὧι'), - (0x1FB0, 'V'), - (0x1FB2, 'M', u'ὰι'), - (0x1FB3, 'M', u'αι'), - (0x1FB4, 'M', u'άι'), - (0x1FB5, 'X'), - (0x1FB6, 'V'), - (0x1FB7, 'M', u'ᾶι'), - (0x1FB8, 'M', u'ᾰ'), - (0x1FB9, 'M', u'ᾱ'), - (0x1FBA, 'M', u'ὰ'), - (0x1FBB, 'M', u'ά'), - (0x1FBC, 'M', u'αι'), - (0x1FBD, '3', u' ̓'), - (0x1FBE, 'M', u'ι'), - (0x1FBF, '3', u' ̓'), - (0x1FC0, '3', u' ͂'), - (0x1FC1, '3', u' ̈͂'), - (0x1FC2, 'M', u'ὴι'), - (0x1FC3, 'M', u'ηι'), - (0x1FC4, 'M', u'ήι'), - (0x1FC5, 'X'), - (0x1FC6, 'V'), - (0x1FC7, 'M', u'ῆι'), - (0x1FC8, 'M', u'ὲ'), - (0x1FC9, 'M', u'έ'), - (0x1FCA, 'M', u'ὴ'), - (0x1FCB, 'M', u'ή'), - (0x1FCC, 'M', u'ηι'), - (0x1FCD, '3', u' ̓̀'), - (0x1FCE, '3', u' ̓́'), - (0x1FCF, '3', u' ̓͂'), - (0x1FD0, 'V'), - (0x1FD3, 'M', u'ΐ'), - (0x1FD4, 'X'), - (0x1FD6, 'V'), - (0x1FD8, 'M', u'ῐ'), - (0x1FD9, 'M', u'ῑ'), - (0x1FDA, 'M', u'ὶ'), - (0x1FDB, 'M', u'ί'), - (0x1FDC, 'X'), - (0x1FDD, '3', u' ̔̀'), - (0x1FDE, '3', u' ̔́'), - (0x1FDF, '3', u' ̔͂'), - (0x1FE0, 'V'), - (0x1FE3, 'M', u'ΰ'), - (0x1FE4, 'V'), - (0x1FE8, 'M', u'ῠ'), - (0x1FE9, 'M', u'ῡ'), - (0x1FEA, 'M', u'ὺ'), - (0x1FEB, 'M', u'ύ'), - (0x1FEC, 'M', u'ῥ'), - (0x1FED, '3', u' ̈̀'), - (0x1FEE, '3', u' ̈́'), - (0x1FEF, '3', u'`'), - (0x1FF0, 'X'), - (0x1FF2, 'M', u'ὼι'), - (0x1FF3, 'M', u'ωι'), - ] - -def _seg_21(): - return [ - (0x1FF4, 'M', u'ώι'), - (0x1FF5, 'X'), - (0x1FF6, 'V'), - (0x1FF7, 'M', u'ῶι'), - (0x1FF8, 'M', u'ὸ'), - (0x1FF9, 'M', u'ό'), - (0x1FFA, 'M', u'ὼ'), - (0x1FFB, 'M', u'ώ'), - (0x1FFC, 'M', u'ωι'), - (0x1FFD, '3', u' ́'), - (0x1FFE, '3', u' ̔'), - (0x1FFF, 'X'), - (0x2000, '3', u' '), - (0x200B, 'I'), - (0x200C, 'D', u''), - (0x200E, 'X'), - (0x2010, 'V'), - (0x2011, 'M', u'‐'), - (0x2012, 'V'), - (0x2017, '3', u' ̳'), - (0x2018, 'V'), - (0x2024, 'X'), - (0x2027, 'V'), - (0x2028, 'X'), - (0x202F, '3', u' '), - (0x2030, 'V'), - (0x2033, 'M', u'′′'), - (0x2034, 'M', u'′′′'), - (0x2035, 'V'), - (0x2036, 'M', u'‵‵'), - (0x2037, 'M', u'‵‵‵'), - (0x2038, 'V'), - (0x203C, '3', u'!!'), - (0x203D, 'V'), - (0x203E, '3', u' ̅'), - (0x203F, 'V'), - (0x2047, '3', u'??'), - (0x2048, '3', u'?!'), - (0x2049, '3', u'!?'), - (0x204A, 'V'), - (0x2057, 'M', u'′′′′'), - (0x2058, 'V'), - (0x205F, '3', u' '), - (0x2060, 'I'), - (0x2061, 'X'), - (0x2064, 'I'), - (0x2065, 'X'), - (0x2070, 'M', u'0'), - (0x2071, 'M', u'i'), - (0x2072, 'X'), - (0x2074, 'M', u'4'), - (0x2075, 'M', u'5'), - (0x2076, 'M', u'6'), - (0x2077, 'M', u'7'), - (0x2078, 'M', u'8'), - (0x2079, 'M', u'9'), - (0x207A, '3', u'+'), - (0x207B, 'M', u'−'), - (0x207C, '3', u'='), - (0x207D, '3', u'('), - (0x207E, '3', u')'), - (0x207F, 'M', u'n'), - (0x2080, 'M', u'0'), - (0x2081, 'M', u'1'), - (0x2082, 'M', u'2'), - (0x2083, 'M', u'3'), - (0x2084, 'M', u'4'), - (0x2085, 'M', u'5'), - (0x2086, 'M', u'6'), - (0x2087, 'M', u'7'), - (0x2088, 'M', u'8'), - (0x2089, 'M', u'9'), - (0x208A, '3', u'+'), - (0x208B, 'M', u'−'), - (0x208C, '3', u'='), - (0x208D, '3', u'('), - (0x208E, '3', u')'), - (0x208F, 'X'), - (0x2090, 'M', u'a'), - (0x2091, 'M', u'e'), - (0x2092, 'M', u'o'), - (0x2093, 'M', u'x'), - (0x2094, 'M', u'ə'), - (0x2095, 'M', u'h'), - (0x2096, 'M', u'k'), - (0x2097, 'M', u'l'), - (0x2098, 'M', u'm'), - (0x2099, 'M', u'n'), - (0x209A, 'M', u'p'), - (0x209B, 'M', u's'), - (0x209C, 'M', u't'), - (0x209D, 'X'), - (0x20A0, 'V'), - (0x20A8, 'M', u'rs'), - (0x20A9, 'V'), - (0x20C0, 'X'), - (0x20D0, 'V'), - (0x20F1, 'X'), - (0x2100, '3', u'a/c'), - (0x2101, '3', u'a/s'), - ] - -def _seg_22(): - return [ - (0x2102, 'M', u'c'), - (0x2103, 'M', u'°c'), - (0x2104, 'V'), - (0x2105, '3', u'c/o'), - (0x2106, '3', u'c/u'), - (0x2107, 'M', u'ɛ'), - (0x2108, 'V'), - (0x2109, 'M', u'°f'), - (0x210A, 'M', u'g'), - (0x210B, 'M', u'h'), - (0x210F, 'M', u'ħ'), - (0x2110, 'M', u'i'), - (0x2112, 'M', u'l'), - (0x2114, 'V'), - (0x2115, 'M', u'n'), - (0x2116, 'M', u'no'), - (0x2117, 'V'), - (0x2119, 'M', u'p'), - (0x211A, 'M', u'q'), - (0x211B, 'M', u'r'), - (0x211E, 'V'), - (0x2120, 'M', u'sm'), - (0x2121, 'M', u'tel'), - (0x2122, 'M', u'tm'), - (0x2123, 'V'), - (0x2124, 'M', u'z'), - (0x2125, 'V'), - (0x2126, 'M', u'ω'), - (0x2127, 'V'), - (0x2128, 'M', u'z'), - (0x2129, 'V'), - (0x212A, 'M', u'k'), - (0x212B, 'M', u'å'), - (0x212C, 'M', u'b'), - (0x212D, 'M', u'c'), - (0x212E, 'V'), - (0x212F, 'M', u'e'), - (0x2131, 'M', u'f'), - (0x2132, 'X'), - (0x2133, 'M', u'm'), - (0x2134, 'M', u'o'), - (0x2135, 'M', u'א'), - (0x2136, 'M', u'ב'), - (0x2137, 'M', u'ג'), - (0x2138, 'M', u'ד'), - (0x2139, 'M', u'i'), - (0x213A, 'V'), - (0x213B, 'M', u'fax'), - (0x213C, 'M', u'π'), - (0x213D, 'M', u'γ'), - (0x213F, 'M', u'π'), - (0x2140, 'M', u'∑'), - (0x2141, 'V'), - (0x2145, 'M', u'd'), - (0x2147, 'M', u'e'), - (0x2148, 'M', u'i'), - (0x2149, 'M', u'j'), - (0x214A, 'V'), - (0x2150, 'M', u'1⁄7'), - (0x2151, 'M', u'1⁄9'), - (0x2152, 'M', u'1⁄10'), - (0x2153, 'M', u'1⁄3'), - (0x2154, 'M', u'2⁄3'), - (0x2155, 'M', u'1⁄5'), - (0x2156, 'M', u'2⁄5'), - (0x2157, 'M', u'3⁄5'), - (0x2158, 'M', u'4⁄5'), - (0x2159, 'M', u'1⁄6'), - (0x215A, 'M', u'5⁄6'), - (0x215B, 'M', u'1⁄8'), - (0x215C, 'M', u'3⁄8'), - (0x215D, 'M', u'5⁄8'), - (0x215E, 'M', u'7⁄8'), - (0x215F, 'M', u'1⁄'), - (0x2160, 'M', u'i'), - (0x2161, 'M', u'ii'), - (0x2162, 'M', u'iii'), - (0x2163, 'M', u'iv'), - (0x2164, 'M', u'v'), - (0x2165, 'M', u'vi'), - (0x2166, 'M', u'vii'), - (0x2167, 'M', u'viii'), - (0x2168, 'M', u'ix'), - (0x2169, 'M', u'x'), - (0x216A, 'M', u'xi'), - (0x216B, 'M', u'xii'), - (0x216C, 'M', u'l'), - (0x216D, 'M', u'c'), - (0x216E, 'M', u'd'), - (0x216F, 'M', u'm'), - (0x2170, 'M', u'i'), - (0x2171, 'M', u'ii'), - (0x2172, 'M', u'iii'), - (0x2173, 'M', u'iv'), - (0x2174, 'M', u'v'), - (0x2175, 'M', u'vi'), - (0x2176, 'M', u'vii'), - (0x2177, 'M', u'viii'), - (0x2178, 'M', u'ix'), - (0x2179, 'M', u'x'), - ] - -def _seg_23(): - return [ - (0x217A, 'M', u'xi'), - (0x217B, 'M', u'xii'), - (0x217C, 'M', u'l'), - (0x217D, 'M', u'c'), - (0x217E, 'M', u'd'), - (0x217F, 'M', u'm'), - (0x2180, 'V'), - (0x2183, 'X'), - (0x2184, 'V'), - (0x2189, 'M', u'0⁄3'), - (0x218A, 'V'), - (0x218C, 'X'), - (0x2190, 'V'), - (0x222C, 'M', u'∫∫'), - (0x222D, 'M', u'∫∫∫'), - (0x222E, 'V'), - (0x222F, 'M', u'∮∮'), - (0x2230, 'M', u'∮∮∮'), - (0x2231, 'V'), - (0x2260, '3'), - (0x2261, 'V'), - (0x226E, '3'), - (0x2270, 'V'), - (0x2329, 'M', u'〈'), - (0x232A, 'M', u'〉'), - (0x232B, 'V'), - (0x2427, 'X'), - (0x2440, 'V'), - (0x244B, 'X'), - (0x2460, 'M', u'1'), - (0x2461, 'M', u'2'), - (0x2462, 'M', u'3'), - (0x2463, 'M', u'4'), - (0x2464, 'M', u'5'), - (0x2465, 'M', u'6'), - (0x2466, 'M', u'7'), - (0x2467, 'M', u'8'), - (0x2468, 'M', u'9'), - (0x2469, 'M', u'10'), - (0x246A, 'M', u'11'), - (0x246B, 'M', u'12'), - (0x246C, 'M', u'13'), - (0x246D, 'M', u'14'), - (0x246E, 'M', u'15'), - (0x246F, 'M', u'16'), - (0x2470, 'M', u'17'), - (0x2471, 'M', u'18'), - (0x2472, 'M', u'19'), - (0x2473, 'M', u'20'), - (0x2474, '3', u'(1)'), - (0x2475, '3', u'(2)'), - (0x2476, '3', u'(3)'), - (0x2477, '3', u'(4)'), - (0x2478, '3', u'(5)'), - (0x2479, '3', u'(6)'), - (0x247A, '3', u'(7)'), - (0x247B, '3', u'(8)'), - (0x247C, '3', u'(9)'), - (0x247D, '3', u'(10)'), - (0x247E, '3', u'(11)'), - (0x247F, '3', u'(12)'), - (0x2480, '3', u'(13)'), - (0x2481, '3', u'(14)'), - (0x2482, '3', u'(15)'), - (0x2483, '3', u'(16)'), - (0x2484, '3', u'(17)'), - (0x2485, '3', u'(18)'), - (0x2486, '3', u'(19)'), - (0x2487, '3', u'(20)'), - (0x2488, 'X'), - (0x249C, '3', u'(a)'), - (0x249D, '3', u'(b)'), - (0x249E, '3', u'(c)'), - (0x249F, '3', u'(d)'), - (0x24A0, '3', u'(e)'), - (0x24A1, '3', u'(f)'), - (0x24A2, '3', u'(g)'), - (0x24A3, '3', u'(h)'), - (0x24A4, '3', u'(i)'), - (0x24A5, '3', u'(j)'), - (0x24A6, '3', u'(k)'), - (0x24A7, '3', u'(l)'), - (0x24A8, '3', u'(m)'), - (0x24A9, '3', u'(n)'), - (0x24AA, '3', u'(o)'), - (0x24AB, '3', u'(p)'), - (0x24AC, '3', u'(q)'), - (0x24AD, '3', u'(r)'), - (0x24AE, '3', u'(s)'), - (0x24AF, '3', u'(t)'), - (0x24B0, '3', u'(u)'), - (0x24B1, '3', u'(v)'), - (0x24B2, '3', u'(w)'), - (0x24B3, '3', u'(x)'), - (0x24B4, '3', u'(y)'), - (0x24B5, '3', u'(z)'), - (0x24B6, 'M', u'a'), - (0x24B7, 'M', u'b'), - (0x24B8, 'M', u'c'), - (0x24B9, 'M', u'd'), - ] - -def _seg_24(): - return [ - (0x24BA, 'M', u'e'), - (0x24BB, 'M', u'f'), - (0x24BC, 'M', u'g'), - (0x24BD, 'M', u'h'), - (0x24BE, 'M', u'i'), - (0x24BF, 'M', u'j'), - (0x24C0, 'M', u'k'), - (0x24C1, 'M', u'l'), - (0x24C2, 'M', u'm'), - (0x24C3, 'M', u'n'), - (0x24C4, 'M', u'o'), - (0x24C5, 'M', u'p'), - (0x24C6, 'M', u'q'), - (0x24C7, 'M', u'r'), - (0x24C8, 'M', u's'), - (0x24C9, 'M', u't'), - (0x24CA, 'M', u'u'), - (0x24CB, 'M', u'v'), - (0x24CC, 'M', u'w'), - (0x24CD, 'M', u'x'), - (0x24CE, 'M', u'y'), - (0x24CF, 'M', u'z'), - (0x24D0, 'M', u'a'), - (0x24D1, 'M', u'b'), - (0x24D2, 'M', u'c'), - (0x24D3, 'M', u'd'), - (0x24D4, 'M', u'e'), - (0x24D5, 'M', u'f'), - (0x24D6, 'M', u'g'), - (0x24D7, 'M', u'h'), - (0x24D8, 'M', u'i'), - (0x24D9, 'M', u'j'), - (0x24DA, 'M', u'k'), - (0x24DB, 'M', u'l'), - (0x24DC, 'M', u'm'), - (0x24DD, 'M', u'n'), - (0x24DE, 'M', u'o'), - (0x24DF, 'M', u'p'), - (0x24E0, 'M', u'q'), - (0x24E1, 'M', u'r'), - (0x24E2, 'M', u's'), - (0x24E3, 'M', u't'), - (0x24E4, 'M', u'u'), - (0x24E5, 'M', u'v'), - (0x24E6, 'M', u'w'), - (0x24E7, 'M', u'x'), - (0x24E8, 'M', u'y'), - (0x24E9, 'M', u'z'), - (0x24EA, 'M', u'0'), - (0x24EB, 'V'), - (0x2A0C, 'M', u'∫∫∫∫'), - (0x2A0D, 'V'), - (0x2A74, '3', u'::='), - (0x2A75, '3', u'=='), - (0x2A76, '3', u'==='), - (0x2A77, 'V'), - (0x2ADC, 'M', u'⫝̸'), - (0x2ADD, 'V'), - (0x2B74, 'X'), - (0x2B76, 'V'), - (0x2B96, 'X'), - (0x2B97, 'V'), - (0x2C00, 'M', u'ⰰ'), - (0x2C01, 'M', u'ⰱ'), - (0x2C02, 'M', u'ⰲ'), - (0x2C03, 'M', u'ⰳ'), - (0x2C04, 'M', u'ⰴ'), - (0x2C05, 'M', u'ⰵ'), - (0x2C06, 'M', u'ⰶ'), - (0x2C07, 'M', u'ⰷ'), - (0x2C08, 'M', u'ⰸ'), - (0x2C09, 'M', u'ⰹ'), - (0x2C0A, 'M', u'ⰺ'), - (0x2C0B, 'M', u'ⰻ'), - (0x2C0C, 'M', u'ⰼ'), - (0x2C0D, 'M', u'ⰽ'), - (0x2C0E, 'M', u'ⰾ'), - (0x2C0F, 'M', u'ⰿ'), - (0x2C10, 'M', u'ⱀ'), - (0x2C11, 'M', u'ⱁ'), - (0x2C12, 'M', u'ⱂ'), - (0x2C13, 'M', u'ⱃ'), - (0x2C14, 'M', u'ⱄ'), - (0x2C15, 'M', u'ⱅ'), - (0x2C16, 'M', u'ⱆ'), - (0x2C17, 'M', u'ⱇ'), - (0x2C18, 'M', u'ⱈ'), - (0x2C19, 'M', u'ⱉ'), - (0x2C1A, 'M', u'ⱊ'), - (0x2C1B, 'M', u'ⱋ'), - (0x2C1C, 'M', u'ⱌ'), - (0x2C1D, 'M', u'ⱍ'), - (0x2C1E, 'M', u'ⱎ'), - (0x2C1F, 'M', u'ⱏ'), - (0x2C20, 'M', u'ⱐ'), - (0x2C21, 'M', u'ⱑ'), - (0x2C22, 'M', u'ⱒ'), - (0x2C23, 'M', u'ⱓ'), - (0x2C24, 'M', u'ⱔ'), - (0x2C25, 'M', u'ⱕ'), - ] - -def _seg_25(): - return [ - (0x2C26, 'M', u'ⱖ'), - (0x2C27, 'M', u'ⱗ'), - (0x2C28, 'M', u'ⱘ'), - (0x2C29, 'M', u'ⱙ'), - (0x2C2A, 'M', u'ⱚ'), - (0x2C2B, 'M', u'ⱛ'), - (0x2C2C, 'M', u'ⱜ'), - (0x2C2D, 'M', u'ⱝ'), - (0x2C2E, 'M', u'ⱞ'), - (0x2C2F, 'X'), - (0x2C30, 'V'), - (0x2C5F, 'X'), - (0x2C60, 'M', u'ⱡ'), - (0x2C61, 'V'), - (0x2C62, 'M', u'ɫ'), - (0x2C63, 'M', u'ᵽ'), - (0x2C64, 'M', u'ɽ'), - (0x2C65, 'V'), - (0x2C67, 'M', u'ⱨ'), - (0x2C68, 'V'), - (0x2C69, 'M', u'ⱪ'), - (0x2C6A, 'V'), - (0x2C6B, 'M', u'ⱬ'), - (0x2C6C, 'V'), - (0x2C6D, 'M', u'ɑ'), - (0x2C6E, 'M', u'ɱ'), - (0x2C6F, 'M', u'ɐ'), - (0x2C70, 'M', u'ɒ'), - (0x2C71, 'V'), - (0x2C72, 'M', u'ⱳ'), - (0x2C73, 'V'), - (0x2C75, 'M', u'ⱶ'), - (0x2C76, 'V'), - (0x2C7C, 'M', u'j'), - (0x2C7D, 'M', u'v'), - (0x2C7E, 'M', u'ȿ'), - (0x2C7F, 'M', u'ɀ'), - (0x2C80, 'M', u'ⲁ'), - (0x2C81, 'V'), - (0x2C82, 'M', u'ⲃ'), - (0x2C83, 'V'), - (0x2C84, 'M', u'ⲅ'), - (0x2C85, 'V'), - (0x2C86, 'M', u'ⲇ'), - (0x2C87, 'V'), - (0x2C88, 'M', u'ⲉ'), - (0x2C89, 'V'), - (0x2C8A, 'M', u'ⲋ'), - (0x2C8B, 'V'), - (0x2C8C, 'M', u'ⲍ'), - (0x2C8D, 'V'), - (0x2C8E, 'M', u'ⲏ'), - (0x2C8F, 'V'), - (0x2C90, 'M', u'ⲑ'), - (0x2C91, 'V'), - (0x2C92, 'M', u'ⲓ'), - (0x2C93, 'V'), - (0x2C94, 'M', u'ⲕ'), - (0x2C95, 'V'), - (0x2C96, 'M', u'ⲗ'), - (0x2C97, 'V'), - (0x2C98, 'M', u'ⲙ'), - (0x2C99, 'V'), - (0x2C9A, 'M', u'ⲛ'), - (0x2C9B, 'V'), - (0x2C9C, 'M', u'ⲝ'), - (0x2C9D, 'V'), - (0x2C9E, 'M', u'ⲟ'), - (0x2C9F, 'V'), - (0x2CA0, 'M', u'ⲡ'), - (0x2CA1, 'V'), - (0x2CA2, 'M', u'ⲣ'), - (0x2CA3, 'V'), - (0x2CA4, 'M', u'ⲥ'), - (0x2CA5, 'V'), - (0x2CA6, 'M', u'ⲧ'), - (0x2CA7, 'V'), - (0x2CA8, 'M', u'ⲩ'), - (0x2CA9, 'V'), - (0x2CAA, 'M', u'ⲫ'), - (0x2CAB, 'V'), - (0x2CAC, 'M', u'ⲭ'), - (0x2CAD, 'V'), - (0x2CAE, 'M', u'ⲯ'), - (0x2CAF, 'V'), - (0x2CB0, 'M', u'ⲱ'), - (0x2CB1, 'V'), - (0x2CB2, 'M', u'ⲳ'), - (0x2CB3, 'V'), - (0x2CB4, 'M', u'ⲵ'), - (0x2CB5, 'V'), - (0x2CB6, 'M', u'ⲷ'), - (0x2CB7, 'V'), - (0x2CB8, 'M', u'ⲹ'), - (0x2CB9, 'V'), - (0x2CBA, 'M', u'ⲻ'), - (0x2CBB, 'V'), - (0x2CBC, 'M', u'ⲽ'), - (0x2CBD, 'V'), - (0x2CBE, 'M', u'ⲿ'), - ] - -def _seg_26(): - return [ - (0x2CBF, 'V'), - (0x2CC0, 'M', u'ⳁ'), - (0x2CC1, 'V'), - (0x2CC2, 'M', u'ⳃ'), - (0x2CC3, 'V'), - (0x2CC4, 'M', u'ⳅ'), - (0x2CC5, 'V'), - (0x2CC6, 'M', u'ⳇ'), - (0x2CC7, 'V'), - (0x2CC8, 'M', u'ⳉ'), - (0x2CC9, 'V'), - (0x2CCA, 'M', u'ⳋ'), - (0x2CCB, 'V'), - (0x2CCC, 'M', u'ⳍ'), - (0x2CCD, 'V'), - (0x2CCE, 'M', u'ⳏ'), - (0x2CCF, 'V'), - (0x2CD0, 'M', u'ⳑ'), - (0x2CD1, 'V'), - (0x2CD2, 'M', u'ⳓ'), - (0x2CD3, 'V'), - (0x2CD4, 'M', u'ⳕ'), - (0x2CD5, 'V'), - (0x2CD6, 'M', u'ⳗ'), - (0x2CD7, 'V'), - (0x2CD8, 'M', u'ⳙ'), - (0x2CD9, 'V'), - (0x2CDA, 'M', u'ⳛ'), - (0x2CDB, 'V'), - (0x2CDC, 'M', u'ⳝ'), - (0x2CDD, 'V'), - (0x2CDE, 'M', u'ⳟ'), - (0x2CDF, 'V'), - (0x2CE0, 'M', u'ⳡ'), - (0x2CE1, 'V'), - (0x2CE2, 'M', u'ⳣ'), - (0x2CE3, 'V'), - (0x2CEB, 'M', u'ⳬ'), - (0x2CEC, 'V'), - (0x2CED, 'M', u'ⳮ'), - (0x2CEE, 'V'), - (0x2CF2, 'M', u'ⳳ'), - (0x2CF3, 'V'), - (0x2CF4, 'X'), - (0x2CF9, 'V'), - (0x2D26, 'X'), - (0x2D27, 'V'), - (0x2D28, 'X'), - (0x2D2D, 'V'), - (0x2D2E, 'X'), - (0x2D30, 'V'), - (0x2D68, 'X'), - (0x2D6F, 'M', u'ⵡ'), - (0x2D70, 'V'), - (0x2D71, 'X'), - (0x2D7F, 'V'), - (0x2D97, 'X'), - (0x2DA0, 'V'), - (0x2DA7, 'X'), - (0x2DA8, 'V'), - (0x2DAF, 'X'), - (0x2DB0, 'V'), - (0x2DB7, 'X'), - (0x2DB8, 'V'), - (0x2DBF, 'X'), - (0x2DC0, 'V'), - (0x2DC7, 'X'), - (0x2DC8, 'V'), - (0x2DCF, 'X'), - (0x2DD0, 'V'), - (0x2DD7, 'X'), - (0x2DD8, 'V'), - (0x2DDF, 'X'), - (0x2DE0, 'V'), - (0x2E53, 'X'), - (0x2E80, 'V'), - (0x2E9A, 'X'), - (0x2E9B, 'V'), - (0x2E9F, 'M', u'母'), - (0x2EA0, 'V'), - (0x2EF3, 'M', u'龟'), - (0x2EF4, 'X'), - (0x2F00, 'M', u'一'), - (0x2F01, 'M', u'丨'), - (0x2F02, 'M', u'丶'), - (0x2F03, 'M', u'丿'), - (0x2F04, 'M', u'乙'), - (0x2F05, 'M', u'亅'), - (0x2F06, 'M', u'二'), - (0x2F07, 'M', u'亠'), - (0x2F08, 'M', u'人'), - (0x2F09, 'M', u'儿'), - (0x2F0A, 'M', u'入'), - (0x2F0B, 'M', u'八'), - (0x2F0C, 'M', u'冂'), - (0x2F0D, 'M', u'冖'), - (0x2F0E, 'M', u'冫'), - (0x2F0F, 'M', u'几'), - (0x2F10, 'M', u'凵'), - (0x2F11, 'M', u'刀'), - ] - -def _seg_27(): - return [ - (0x2F12, 'M', u'力'), - (0x2F13, 'M', u'勹'), - (0x2F14, 'M', u'匕'), - (0x2F15, 'M', u'匚'), - (0x2F16, 'M', u'匸'), - (0x2F17, 'M', u'十'), - (0x2F18, 'M', u'卜'), - (0x2F19, 'M', u'卩'), - (0x2F1A, 'M', u'厂'), - (0x2F1B, 'M', u'厶'), - (0x2F1C, 'M', u'又'), - (0x2F1D, 'M', u'口'), - (0x2F1E, 'M', u'囗'), - (0x2F1F, 'M', u'土'), - (0x2F20, 'M', u'士'), - (0x2F21, 'M', u'夂'), - (0x2F22, 'M', u'夊'), - (0x2F23, 'M', u'夕'), - (0x2F24, 'M', u'大'), - (0x2F25, 'M', u'女'), - (0x2F26, 'M', u'子'), - (0x2F27, 'M', u'宀'), - (0x2F28, 'M', u'寸'), - (0x2F29, 'M', u'小'), - (0x2F2A, 'M', u'尢'), - (0x2F2B, 'M', u'尸'), - (0x2F2C, 'M', u'屮'), - (0x2F2D, 'M', u'山'), - (0x2F2E, 'M', u'巛'), - (0x2F2F, 'M', u'工'), - (0x2F30, 'M', u'己'), - (0x2F31, 'M', u'巾'), - (0x2F32, 'M', u'干'), - (0x2F33, 'M', u'幺'), - (0x2F34, 'M', u'广'), - (0x2F35, 'M', u'廴'), - (0x2F36, 'M', u'廾'), - (0x2F37, 'M', u'弋'), - (0x2F38, 'M', u'弓'), - (0x2F39, 'M', u'彐'), - (0x2F3A, 'M', u'彡'), - (0x2F3B, 'M', u'彳'), - (0x2F3C, 'M', u'心'), - (0x2F3D, 'M', u'戈'), - (0x2F3E, 'M', u'戶'), - (0x2F3F, 'M', u'手'), - (0x2F40, 'M', u'支'), - (0x2F41, 'M', u'攴'), - (0x2F42, 'M', u'文'), - (0x2F43, 'M', u'斗'), - (0x2F44, 'M', u'斤'), - (0x2F45, 'M', u'方'), - (0x2F46, 'M', u'无'), - (0x2F47, 'M', u'日'), - (0x2F48, 'M', u'曰'), - (0x2F49, 'M', u'月'), - (0x2F4A, 'M', u'木'), - (0x2F4B, 'M', u'欠'), - (0x2F4C, 'M', u'止'), - (0x2F4D, 'M', u'歹'), - (0x2F4E, 'M', u'殳'), - (0x2F4F, 'M', u'毋'), - (0x2F50, 'M', u'比'), - (0x2F51, 'M', u'毛'), - (0x2F52, 'M', u'氏'), - (0x2F53, 'M', u'气'), - (0x2F54, 'M', u'水'), - (0x2F55, 'M', u'火'), - (0x2F56, 'M', u'爪'), - (0x2F57, 'M', u'父'), - (0x2F58, 'M', u'爻'), - (0x2F59, 'M', u'爿'), - (0x2F5A, 'M', u'片'), - (0x2F5B, 'M', u'牙'), - (0x2F5C, 'M', u'牛'), - (0x2F5D, 'M', u'犬'), - (0x2F5E, 'M', u'玄'), - (0x2F5F, 'M', u'玉'), - (0x2F60, 'M', u'瓜'), - (0x2F61, 'M', u'瓦'), - (0x2F62, 'M', u'甘'), - (0x2F63, 'M', u'生'), - (0x2F64, 'M', u'用'), - (0x2F65, 'M', u'田'), - (0x2F66, 'M', u'疋'), - (0x2F67, 'M', u'疒'), - (0x2F68, 'M', u'癶'), - (0x2F69, 'M', u'白'), - (0x2F6A, 'M', u'皮'), - (0x2F6B, 'M', u'皿'), - (0x2F6C, 'M', u'目'), - (0x2F6D, 'M', u'矛'), - (0x2F6E, 'M', u'矢'), - (0x2F6F, 'M', u'石'), - (0x2F70, 'M', u'示'), - (0x2F71, 'M', u'禸'), - (0x2F72, 'M', u'禾'), - (0x2F73, 'M', u'穴'), - (0x2F74, 'M', u'立'), - (0x2F75, 'M', u'竹'), - ] - -def _seg_28(): - return [ - (0x2F76, 'M', u'米'), - (0x2F77, 'M', u'糸'), - (0x2F78, 'M', u'缶'), - (0x2F79, 'M', u'网'), - (0x2F7A, 'M', u'羊'), - (0x2F7B, 'M', u'羽'), - (0x2F7C, 'M', u'老'), - (0x2F7D, 'M', u'而'), - (0x2F7E, 'M', u'耒'), - (0x2F7F, 'M', u'耳'), - (0x2F80, 'M', u'聿'), - (0x2F81, 'M', u'肉'), - (0x2F82, 'M', u'臣'), - (0x2F83, 'M', u'自'), - (0x2F84, 'M', u'至'), - (0x2F85, 'M', u'臼'), - (0x2F86, 'M', u'舌'), - (0x2F87, 'M', u'舛'), - (0x2F88, 'M', u'舟'), - (0x2F89, 'M', u'艮'), - (0x2F8A, 'M', u'色'), - (0x2F8B, 'M', u'艸'), - (0x2F8C, 'M', u'虍'), - (0x2F8D, 'M', u'虫'), - (0x2F8E, 'M', u'血'), - (0x2F8F, 'M', u'行'), - (0x2F90, 'M', u'衣'), - (0x2F91, 'M', u'襾'), - (0x2F92, 'M', u'見'), - (0x2F93, 'M', u'角'), - (0x2F94, 'M', u'言'), - (0x2F95, 'M', u'谷'), - (0x2F96, 'M', u'豆'), - (0x2F97, 'M', u'豕'), - (0x2F98, 'M', u'豸'), - (0x2F99, 'M', u'貝'), - (0x2F9A, 'M', u'赤'), - (0x2F9B, 'M', u'走'), - (0x2F9C, 'M', u'足'), - (0x2F9D, 'M', u'身'), - (0x2F9E, 'M', u'車'), - (0x2F9F, 'M', u'辛'), - (0x2FA0, 'M', u'辰'), - (0x2FA1, 'M', u'辵'), - (0x2FA2, 'M', u'邑'), - (0x2FA3, 'M', u'酉'), - (0x2FA4, 'M', u'釆'), - (0x2FA5, 'M', u'里'), - (0x2FA6, 'M', u'金'), - (0x2FA7, 'M', u'長'), - (0x2FA8, 'M', u'門'), - (0x2FA9, 'M', u'阜'), - (0x2FAA, 'M', u'隶'), - (0x2FAB, 'M', u'隹'), - (0x2FAC, 'M', u'雨'), - (0x2FAD, 'M', u'靑'), - (0x2FAE, 'M', u'非'), - (0x2FAF, 'M', u'面'), - (0x2FB0, 'M', u'革'), - (0x2FB1, 'M', u'韋'), - (0x2FB2, 'M', u'韭'), - (0x2FB3, 'M', u'音'), - (0x2FB4, 'M', u'頁'), - (0x2FB5, 'M', u'風'), - (0x2FB6, 'M', u'飛'), - (0x2FB7, 'M', u'食'), - (0x2FB8, 'M', u'首'), - (0x2FB9, 'M', u'香'), - (0x2FBA, 'M', u'馬'), - (0x2FBB, 'M', u'骨'), - (0x2FBC, 'M', u'高'), - (0x2FBD, 'M', u'髟'), - (0x2FBE, 'M', u'鬥'), - (0x2FBF, 'M', u'鬯'), - (0x2FC0, 'M', u'鬲'), - (0x2FC1, 'M', u'鬼'), - (0x2FC2, 'M', u'魚'), - (0x2FC3, 'M', u'鳥'), - (0x2FC4, 'M', u'鹵'), - (0x2FC5, 'M', u'鹿'), - (0x2FC6, 'M', u'麥'), - (0x2FC7, 'M', u'麻'), - (0x2FC8, 'M', u'黃'), - (0x2FC9, 'M', u'黍'), - (0x2FCA, 'M', u'黑'), - (0x2FCB, 'M', u'黹'), - (0x2FCC, 'M', u'黽'), - (0x2FCD, 'M', u'鼎'), - (0x2FCE, 'M', u'鼓'), - (0x2FCF, 'M', u'鼠'), - (0x2FD0, 'M', u'鼻'), - (0x2FD1, 'M', u'齊'), - (0x2FD2, 'M', u'齒'), - (0x2FD3, 'M', u'龍'), - (0x2FD4, 'M', u'龜'), - (0x2FD5, 'M', u'龠'), - (0x2FD6, 'X'), - (0x3000, '3', u' '), - (0x3001, 'V'), - (0x3002, 'M', u'.'), - ] - -def _seg_29(): - return [ - (0x3003, 'V'), - (0x3036, 'M', u'〒'), - (0x3037, 'V'), - (0x3038, 'M', u'十'), - (0x3039, 'M', u'卄'), - (0x303A, 'M', u'卅'), - (0x303B, 'V'), - (0x3040, 'X'), - (0x3041, 'V'), - (0x3097, 'X'), - (0x3099, 'V'), - (0x309B, '3', u' ゙'), - (0x309C, '3', u' ゚'), - (0x309D, 'V'), - (0x309F, 'M', u'より'), - (0x30A0, 'V'), - (0x30FF, 'M', u'コト'), - (0x3100, 'X'), - (0x3105, 'V'), - (0x3130, 'X'), - (0x3131, 'M', u'ᄀ'), - (0x3132, 'M', u'ᄁ'), - (0x3133, 'M', u'ᆪ'), - (0x3134, 'M', u'ᄂ'), - (0x3135, 'M', u'ᆬ'), - (0x3136, 'M', u'ᆭ'), - (0x3137, 'M', u'ᄃ'), - (0x3138, 'M', u'ᄄ'), - (0x3139, 'M', u'ᄅ'), - (0x313A, 'M', u'ᆰ'), - (0x313B, 'M', u'ᆱ'), - (0x313C, 'M', u'ᆲ'), - (0x313D, 'M', u'ᆳ'), - (0x313E, 'M', u'ᆴ'), - (0x313F, 'M', u'ᆵ'), - (0x3140, 'M', u'ᄚ'), - (0x3141, 'M', u'ᄆ'), - (0x3142, 'M', u'ᄇ'), - (0x3143, 'M', u'ᄈ'), - (0x3144, 'M', u'ᄡ'), - (0x3145, 'M', u'ᄉ'), - (0x3146, 'M', u'ᄊ'), - (0x3147, 'M', u'ᄋ'), - (0x3148, 'M', u'ᄌ'), - (0x3149, 'M', u'ᄍ'), - (0x314A, 'M', u'ᄎ'), - (0x314B, 'M', u'ᄏ'), - (0x314C, 'M', u'ᄐ'), - (0x314D, 'M', u'ᄑ'), - (0x314E, 'M', u'ᄒ'), - (0x314F, 'M', u'ᅡ'), - (0x3150, 'M', u'ᅢ'), - (0x3151, 'M', u'ᅣ'), - (0x3152, 'M', u'ᅤ'), - (0x3153, 'M', u'ᅥ'), - (0x3154, 'M', u'ᅦ'), - (0x3155, 'M', u'ᅧ'), - (0x3156, 'M', u'ᅨ'), - (0x3157, 'M', u'ᅩ'), - (0x3158, 'M', u'ᅪ'), - (0x3159, 'M', u'ᅫ'), - (0x315A, 'M', u'ᅬ'), - (0x315B, 'M', u'ᅭ'), - (0x315C, 'M', u'ᅮ'), - (0x315D, 'M', u'ᅯ'), - (0x315E, 'M', u'ᅰ'), - (0x315F, 'M', u'ᅱ'), - (0x3160, 'M', u'ᅲ'), - (0x3161, 'M', u'ᅳ'), - (0x3162, 'M', u'ᅴ'), - (0x3163, 'M', u'ᅵ'), - (0x3164, 'X'), - (0x3165, 'M', u'ᄔ'), - (0x3166, 'M', u'ᄕ'), - (0x3167, 'M', u'ᇇ'), - (0x3168, 'M', u'ᇈ'), - (0x3169, 'M', u'ᇌ'), - (0x316A, 'M', u'ᇎ'), - (0x316B, 'M', u'ᇓ'), - (0x316C, 'M', u'ᇗ'), - (0x316D, 'M', u'ᇙ'), - (0x316E, 'M', u'ᄜ'), - (0x316F, 'M', u'ᇝ'), - (0x3170, 'M', u'ᇟ'), - (0x3171, 'M', u'ᄝ'), - (0x3172, 'M', u'ᄞ'), - (0x3173, 'M', u'ᄠ'), - (0x3174, 'M', u'ᄢ'), - (0x3175, 'M', u'ᄣ'), - (0x3176, 'M', u'ᄧ'), - (0x3177, 'M', u'ᄩ'), - (0x3178, 'M', u'ᄫ'), - (0x3179, 'M', u'ᄬ'), - (0x317A, 'M', u'ᄭ'), - (0x317B, 'M', u'ᄮ'), - (0x317C, 'M', u'ᄯ'), - (0x317D, 'M', u'ᄲ'), - (0x317E, 'M', u'ᄶ'), - (0x317F, 'M', u'ᅀ'), - (0x3180, 'M', u'ᅇ'), - ] - -def _seg_30(): - return [ - (0x3181, 'M', u'ᅌ'), - (0x3182, 'M', u'ᇱ'), - (0x3183, 'M', u'ᇲ'), - (0x3184, 'M', u'ᅗ'), - (0x3185, 'M', u'ᅘ'), - (0x3186, 'M', u'ᅙ'), - (0x3187, 'M', u'ᆄ'), - (0x3188, 'M', u'ᆅ'), - (0x3189, 'M', u'ᆈ'), - (0x318A, 'M', u'ᆑ'), - (0x318B, 'M', u'ᆒ'), - (0x318C, 'M', u'ᆔ'), - (0x318D, 'M', u'ᆞ'), - (0x318E, 'M', u'ᆡ'), - (0x318F, 'X'), - (0x3190, 'V'), - (0x3192, 'M', u'一'), - (0x3193, 'M', u'二'), - (0x3194, 'M', u'三'), - (0x3195, 'M', u'四'), - (0x3196, 'M', u'上'), - (0x3197, 'M', u'中'), - (0x3198, 'M', u'下'), - (0x3199, 'M', u'甲'), - (0x319A, 'M', u'乙'), - (0x319B, 'M', u'丙'), - (0x319C, 'M', u'丁'), - (0x319D, 'M', u'天'), - (0x319E, 'M', u'地'), - (0x319F, 'M', u'人'), - (0x31A0, 'V'), - (0x31E4, 'X'), - (0x31F0, 'V'), - (0x3200, '3', u'(ᄀ)'), - (0x3201, '3', u'(ᄂ)'), - (0x3202, '3', u'(ᄃ)'), - (0x3203, '3', u'(ᄅ)'), - (0x3204, '3', u'(ᄆ)'), - (0x3205, '3', u'(ᄇ)'), - (0x3206, '3', u'(ᄉ)'), - (0x3207, '3', u'(ᄋ)'), - (0x3208, '3', u'(ᄌ)'), - (0x3209, '3', u'(ᄎ)'), - (0x320A, '3', u'(ᄏ)'), - (0x320B, '3', u'(ᄐ)'), - (0x320C, '3', u'(ᄑ)'), - (0x320D, '3', u'(ᄒ)'), - (0x320E, '3', u'(가)'), - (0x320F, '3', u'(나)'), - (0x3210, '3', u'(다)'), - (0x3211, '3', u'(라)'), - (0x3212, '3', u'(마)'), - (0x3213, '3', u'(바)'), - (0x3214, '3', u'(사)'), - (0x3215, '3', u'(아)'), - (0x3216, '3', u'(자)'), - (0x3217, '3', u'(차)'), - (0x3218, '3', u'(카)'), - (0x3219, '3', u'(타)'), - (0x321A, '3', u'(파)'), - (0x321B, '3', u'(하)'), - (0x321C, '3', u'(주)'), - (0x321D, '3', u'(오전)'), - (0x321E, '3', u'(오후)'), - (0x321F, 'X'), - (0x3220, '3', u'(一)'), - (0x3221, '3', u'(二)'), - (0x3222, '3', u'(三)'), - (0x3223, '3', u'(四)'), - (0x3224, '3', u'(五)'), - (0x3225, '3', u'(六)'), - (0x3226, '3', u'(七)'), - (0x3227, '3', u'(八)'), - (0x3228, '3', u'(九)'), - (0x3229, '3', u'(十)'), - (0x322A, '3', u'(月)'), - (0x322B, '3', u'(火)'), - (0x322C, '3', u'(水)'), - (0x322D, '3', u'(木)'), - (0x322E, '3', u'(金)'), - (0x322F, '3', u'(土)'), - (0x3230, '3', u'(日)'), - (0x3231, '3', u'(株)'), - (0x3232, '3', u'(有)'), - (0x3233, '3', u'(社)'), - (0x3234, '3', u'(名)'), - (0x3235, '3', u'(特)'), - (0x3236, '3', u'(財)'), - (0x3237, '3', u'(祝)'), - (0x3238, '3', u'(労)'), - (0x3239, '3', u'(代)'), - (0x323A, '3', u'(呼)'), - (0x323B, '3', u'(学)'), - (0x323C, '3', u'(監)'), - (0x323D, '3', u'(企)'), - (0x323E, '3', u'(資)'), - (0x323F, '3', u'(協)'), - (0x3240, '3', u'(祭)'), - (0x3241, '3', u'(休)'), - (0x3242, '3', u'(自)'), - ] - -def _seg_31(): - return [ - (0x3243, '3', u'(至)'), - (0x3244, 'M', u'問'), - (0x3245, 'M', u'幼'), - (0x3246, 'M', u'文'), - (0x3247, 'M', u'箏'), - (0x3248, 'V'), - (0x3250, 'M', u'pte'), - (0x3251, 'M', u'21'), - (0x3252, 'M', u'22'), - (0x3253, 'M', u'23'), - (0x3254, 'M', u'24'), - (0x3255, 'M', u'25'), - (0x3256, 'M', u'26'), - (0x3257, 'M', u'27'), - (0x3258, 'M', u'28'), - (0x3259, 'M', u'29'), - (0x325A, 'M', u'30'), - (0x325B, 'M', u'31'), - (0x325C, 'M', u'32'), - (0x325D, 'M', u'33'), - (0x325E, 'M', u'34'), - (0x325F, 'M', u'35'), - (0x3260, 'M', u'ᄀ'), - (0x3261, 'M', u'ᄂ'), - (0x3262, 'M', u'ᄃ'), - (0x3263, 'M', u'ᄅ'), - (0x3264, 'M', u'ᄆ'), - (0x3265, 'M', u'ᄇ'), - (0x3266, 'M', u'ᄉ'), - (0x3267, 'M', u'ᄋ'), - (0x3268, 'M', u'ᄌ'), - (0x3269, 'M', u'ᄎ'), - (0x326A, 'M', u'ᄏ'), - (0x326B, 'M', u'ᄐ'), - (0x326C, 'M', u'ᄑ'), - (0x326D, 'M', u'ᄒ'), - (0x326E, 'M', u'가'), - (0x326F, 'M', u'나'), - (0x3270, 'M', u'다'), - (0x3271, 'M', u'라'), - (0x3272, 'M', u'마'), - (0x3273, 'M', u'바'), - (0x3274, 'M', u'사'), - (0x3275, 'M', u'아'), - (0x3276, 'M', u'자'), - (0x3277, 'M', u'차'), - (0x3278, 'M', u'카'), - (0x3279, 'M', u'타'), - (0x327A, 'M', u'파'), - (0x327B, 'M', u'하'), - (0x327C, 'M', u'참고'), - (0x327D, 'M', u'주의'), - (0x327E, 'M', u'우'), - (0x327F, 'V'), - (0x3280, 'M', u'一'), - (0x3281, 'M', u'二'), - (0x3282, 'M', u'三'), - (0x3283, 'M', u'四'), - (0x3284, 'M', u'五'), - (0x3285, 'M', u'六'), - (0x3286, 'M', u'七'), - (0x3287, 'M', u'八'), - (0x3288, 'M', u'九'), - (0x3289, 'M', u'十'), - (0x328A, 'M', u'月'), - (0x328B, 'M', u'火'), - (0x328C, 'M', u'水'), - (0x328D, 'M', u'木'), - (0x328E, 'M', u'金'), - (0x328F, 'M', u'土'), - (0x3290, 'M', u'日'), - (0x3291, 'M', u'株'), - (0x3292, 'M', u'有'), - (0x3293, 'M', u'社'), - (0x3294, 'M', u'名'), - (0x3295, 'M', u'特'), - (0x3296, 'M', u'財'), - (0x3297, 'M', u'祝'), - (0x3298, 'M', u'労'), - (0x3299, 'M', u'秘'), - (0x329A, 'M', u'男'), - (0x329B, 'M', u'女'), - (0x329C, 'M', u'適'), - (0x329D, 'M', u'優'), - (0x329E, 'M', u'印'), - (0x329F, 'M', u'注'), - (0x32A0, 'M', u'項'), - (0x32A1, 'M', u'休'), - (0x32A2, 'M', u'写'), - (0x32A3, 'M', u'正'), - (0x32A4, 'M', u'上'), - (0x32A5, 'M', u'中'), - (0x32A6, 'M', u'下'), - (0x32A7, 'M', u'左'), - (0x32A8, 'M', u'右'), - (0x32A9, 'M', u'医'), - (0x32AA, 'M', u'宗'), - (0x32AB, 'M', u'学'), - (0x32AC, 'M', u'監'), - (0x32AD, 'M', u'企'), - ] - -def _seg_32(): - return [ - (0x32AE, 'M', u'資'), - (0x32AF, 'M', u'協'), - (0x32B0, 'M', u'夜'), - (0x32B1, 'M', u'36'), - (0x32B2, 'M', u'37'), - (0x32B3, 'M', u'38'), - (0x32B4, 'M', u'39'), - (0x32B5, 'M', u'40'), - (0x32B6, 'M', u'41'), - (0x32B7, 'M', u'42'), - (0x32B8, 'M', u'43'), - (0x32B9, 'M', u'44'), - (0x32BA, 'M', u'45'), - (0x32BB, 'M', u'46'), - (0x32BC, 'M', u'47'), - (0x32BD, 'M', u'48'), - (0x32BE, 'M', u'49'), - (0x32BF, 'M', u'50'), - (0x32C0, 'M', u'1月'), - (0x32C1, 'M', u'2月'), - (0x32C2, 'M', u'3月'), - (0x32C3, 'M', u'4月'), - (0x32C4, 'M', u'5月'), - (0x32C5, 'M', u'6月'), - (0x32C6, 'M', u'7月'), - (0x32C7, 'M', u'8月'), - (0x32C8, 'M', u'9月'), - (0x32C9, 'M', u'10月'), - (0x32CA, 'M', u'11月'), - (0x32CB, 'M', u'12月'), - (0x32CC, 'M', u'hg'), - (0x32CD, 'M', u'erg'), - (0x32CE, 'M', u'ev'), - (0x32CF, 'M', u'ltd'), - (0x32D0, 'M', u'ア'), - (0x32D1, 'M', u'イ'), - (0x32D2, 'M', u'ウ'), - (0x32D3, 'M', u'エ'), - (0x32D4, 'M', u'オ'), - (0x32D5, 'M', u'カ'), - (0x32D6, 'M', u'キ'), - (0x32D7, 'M', u'ク'), - (0x32D8, 'M', u'ケ'), - (0x32D9, 'M', u'コ'), - (0x32DA, 'M', u'サ'), - (0x32DB, 'M', u'シ'), - (0x32DC, 'M', u'ス'), - (0x32DD, 'M', u'セ'), - (0x32DE, 'M', u'ソ'), - (0x32DF, 'M', u'タ'), - (0x32E0, 'M', u'チ'), - (0x32E1, 'M', u'ツ'), - (0x32E2, 'M', u'テ'), - (0x32E3, 'M', u'ト'), - (0x32E4, 'M', u'ナ'), - (0x32E5, 'M', u'ニ'), - (0x32E6, 'M', u'ヌ'), - (0x32E7, 'M', u'ネ'), - (0x32E8, 'M', u'ノ'), - (0x32E9, 'M', u'ハ'), - (0x32EA, 'M', u'ヒ'), - (0x32EB, 'M', u'フ'), - (0x32EC, 'M', u'ヘ'), - (0x32ED, 'M', u'ホ'), - (0x32EE, 'M', u'マ'), - (0x32EF, 'M', u'ミ'), - (0x32F0, 'M', u'ム'), - (0x32F1, 'M', u'メ'), - (0x32F2, 'M', u'モ'), - (0x32F3, 'M', u'ヤ'), - (0x32F4, 'M', u'ユ'), - (0x32F5, 'M', u'ヨ'), - (0x32F6, 'M', u'ラ'), - (0x32F7, 'M', u'リ'), - (0x32F8, 'M', u'ル'), - (0x32F9, 'M', u'レ'), - (0x32FA, 'M', u'ロ'), - (0x32FB, 'M', u'ワ'), - (0x32FC, 'M', u'ヰ'), - (0x32FD, 'M', u'ヱ'), - (0x32FE, 'M', u'ヲ'), - (0x32FF, 'M', u'令和'), - (0x3300, 'M', u'アパート'), - (0x3301, 'M', u'アルファ'), - (0x3302, 'M', u'アンペア'), - (0x3303, 'M', u'アール'), - (0x3304, 'M', u'イニング'), - (0x3305, 'M', u'インチ'), - (0x3306, 'M', u'ウォン'), - (0x3307, 'M', u'エスクード'), - (0x3308, 'M', u'エーカー'), - (0x3309, 'M', u'オンス'), - (0x330A, 'M', u'オーム'), - (0x330B, 'M', u'カイリ'), - (0x330C, 'M', u'カラット'), - (0x330D, 'M', u'カロリー'), - (0x330E, 'M', u'ガロン'), - (0x330F, 'M', u'ガンマ'), - (0x3310, 'M', u'ギガ'), - (0x3311, 'M', u'ギニー'), - ] - -def _seg_33(): - return [ - (0x3312, 'M', u'キュリー'), - (0x3313, 'M', u'ギルダー'), - (0x3314, 'M', u'キロ'), - (0x3315, 'M', u'キログラム'), - (0x3316, 'M', u'キロメートル'), - (0x3317, 'M', u'キロワット'), - (0x3318, 'M', u'グラム'), - (0x3319, 'M', u'グラムトン'), - (0x331A, 'M', u'クルゼイロ'), - (0x331B, 'M', u'クローネ'), - (0x331C, 'M', u'ケース'), - (0x331D, 'M', u'コルナ'), - (0x331E, 'M', u'コーポ'), - (0x331F, 'M', u'サイクル'), - (0x3320, 'M', u'サンチーム'), - (0x3321, 'M', u'シリング'), - (0x3322, 'M', u'センチ'), - (0x3323, 'M', u'セント'), - (0x3324, 'M', u'ダース'), - (0x3325, 'M', u'デシ'), - (0x3326, 'M', u'ドル'), - (0x3327, 'M', u'トン'), - (0x3328, 'M', u'ナノ'), - (0x3329, 'M', u'ノット'), - (0x332A, 'M', u'ハイツ'), - (0x332B, 'M', u'パーセント'), - (0x332C, 'M', u'パーツ'), - (0x332D, 'M', u'バーレル'), - (0x332E, 'M', u'ピアストル'), - (0x332F, 'M', u'ピクル'), - (0x3330, 'M', u'ピコ'), - (0x3331, 'M', u'ビル'), - (0x3332, 'M', u'ファラッド'), - (0x3333, 'M', u'フィート'), - (0x3334, 'M', u'ブッシェル'), - (0x3335, 'M', u'フラン'), - (0x3336, 'M', u'ヘクタール'), - (0x3337, 'M', u'ペソ'), - (0x3338, 'M', u'ペニヒ'), - (0x3339, 'M', u'ヘルツ'), - (0x333A, 'M', u'ペンス'), - (0x333B, 'M', u'ページ'), - (0x333C, 'M', u'ベータ'), - (0x333D, 'M', u'ポイント'), - (0x333E, 'M', u'ボルト'), - (0x333F, 'M', u'ホン'), - (0x3340, 'M', u'ポンド'), - (0x3341, 'M', u'ホール'), - (0x3342, 'M', u'ホーン'), - (0x3343, 'M', u'マイクロ'), - (0x3344, 'M', u'マイル'), - (0x3345, 'M', u'マッハ'), - (0x3346, 'M', u'マルク'), - (0x3347, 'M', u'マンション'), - (0x3348, 'M', u'ミクロン'), - (0x3349, 'M', u'ミリ'), - (0x334A, 'M', u'ミリバール'), - (0x334B, 'M', u'メガ'), - (0x334C, 'M', u'メガトン'), - (0x334D, 'M', u'メートル'), - (0x334E, 'M', u'ヤード'), - (0x334F, 'M', u'ヤール'), - (0x3350, 'M', u'ユアン'), - (0x3351, 'M', u'リットル'), - (0x3352, 'M', u'リラ'), - (0x3353, 'M', u'ルピー'), - (0x3354, 'M', u'ルーブル'), - (0x3355, 'M', u'レム'), - (0x3356, 'M', u'レントゲン'), - (0x3357, 'M', u'ワット'), - (0x3358, 'M', u'0点'), - (0x3359, 'M', u'1点'), - (0x335A, 'M', u'2点'), - (0x335B, 'M', u'3点'), - (0x335C, 'M', u'4点'), - (0x335D, 'M', u'5点'), - (0x335E, 'M', u'6点'), - (0x335F, 'M', u'7点'), - (0x3360, 'M', u'8点'), - (0x3361, 'M', u'9点'), - (0x3362, 'M', u'10点'), - (0x3363, 'M', u'11点'), - (0x3364, 'M', u'12点'), - (0x3365, 'M', u'13点'), - (0x3366, 'M', u'14点'), - (0x3367, 'M', u'15点'), - (0x3368, 'M', u'16点'), - (0x3369, 'M', u'17点'), - (0x336A, 'M', u'18点'), - (0x336B, 'M', u'19点'), - (0x336C, 'M', u'20点'), - (0x336D, 'M', u'21点'), - (0x336E, 'M', u'22点'), - (0x336F, 'M', u'23点'), - (0x3370, 'M', u'24点'), - (0x3371, 'M', u'hpa'), - (0x3372, 'M', u'da'), - (0x3373, 'M', u'au'), - (0x3374, 'M', u'bar'), - (0x3375, 'M', u'ov'), - ] - -def _seg_34(): - return [ - (0x3376, 'M', u'pc'), - (0x3377, 'M', u'dm'), - (0x3378, 'M', u'dm2'), - (0x3379, 'M', u'dm3'), - (0x337A, 'M', u'iu'), - (0x337B, 'M', u'平成'), - (0x337C, 'M', u'昭和'), - (0x337D, 'M', u'大正'), - (0x337E, 'M', u'明治'), - (0x337F, 'M', u'株式会社'), - (0x3380, 'M', u'pa'), - (0x3381, 'M', u'na'), - (0x3382, 'M', u'μa'), - (0x3383, 'M', u'ma'), - (0x3384, 'M', u'ka'), - (0x3385, 'M', u'kb'), - (0x3386, 'M', u'mb'), - (0x3387, 'M', u'gb'), - (0x3388, 'M', u'cal'), - (0x3389, 'M', u'kcal'), - (0x338A, 'M', u'pf'), - (0x338B, 'M', u'nf'), - (0x338C, 'M', u'μf'), - (0x338D, 'M', u'μg'), - (0x338E, 'M', u'mg'), - (0x338F, 'M', u'kg'), - (0x3390, 'M', u'hz'), - (0x3391, 'M', u'khz'), - (0x3392, 'M', u'mhz'), - (0x3393, 'M', u'ghz'), - (0x3394, 'M', u'thz'), - (0x3395, 'M', u'μl'), - (0x3396, 'M', u'ml'), - (0x3397, 'M', u'dl'), - (0x3398, 'M', u'kl'), - (0x3399, 'M', u'fm'), - (0x339A, 'M', u'nm'), - (0x339B, 'M', u'μm'), - (0x339C, 'M', u'mm'), - (0x339D, 'M', u'cm'), - (0x339E, 'M', u'km'), - (0x339F, 'M', u'mm2'), - (0x33A0, 'M', u'cm2'), - (0x33A1, 'M', u'm2'), - (0x33A2, 'M', u'km2'), - (0x33A3, 'M', u'mm3'), - (0x33A4, 'M', u'cm3'), - (0x33A5, 'M', u'm3'), - (0x33A6, 'M', u'km3'), - (0x33A7, 'M', u'm∕s'), - (0x33A8, 'M', u'm∕s2'), - (0x33A9, 'M', u'pa'), - (0x33AA, 'M', u'kpa'), - (0x33AB, 'M', u'mpa'), - (0x33AC, 'M', u'gpa'), - (0x33AD, 'M', u'rad'), - (0x33AE, 'M', u'rad∕s'), - (0x33AF, 'M', u'rad∕s2'), - (0x33B0, 'M', u'ps'), - (0x33B1, 'M', u'ns'), - (0x33B2, 'M', u'μs'), - (0x33B3, 'M', u'ms'), - (0x33B4, 'M', u'pv'), - (0x33B5, 'M', u'nv'), - (0x33B6, 'M', u'μv'), - (0x33B7, 'M', u'mv'), - (0x33B8, 'M', u'kv'), - (0x33B9, 'M', u'mv'), - (0x33BA, 'M', u'pw'), - (0x33BB, 'M', u'nw'), - (0x33BC, 'M', u'μw'), - (0x33BD, 'M', u'mw'), - (0x33BE, 'M', u'kw'), - (0x33BF, 'M', u'mw'), - (0x33C0, 'M', u'kω'), - (0x33C1, 'M', u'mω'), - (0x33C2, 'X'), - (0x33C3, 'M', u'bq'), - (0x33C4, 'M', u'cc'), - (0x33C5, 'M', u'cd'), - (0x33C6, 'M', u'c∕kg'), - (0x33C7, 'X'), - (0x33C8, 'M', u'db'), - (0x33C9, 'M', u'gy'), - (0x33CA, 'M', u'ha'), - (0x33CB, 'M', u'hp'), - (0x33CC, 'M', u'in'), - (0x33CD, 'M', u'kk'), - (0x33CE, 'M', u'km'), - (0x33CF, 'M', u'kt'), - (0x33D0, 'M', u'lm'), - (0x33D1, 'M', u'ln'), - (0x33D2, 'M', u'log'), - (0x33D3, 'M', u'lx'), - (0x33D4, 'M', u'mb'), - (0x33D5, 'M', u'mil'), - (0x33D6, 'M', u'mol'), - (0x33D7, 'M', u'ph'), - (0x33D8, 'X'), - (0x33D9, 'M', u'ppm'), - ] - -def _seg_35(): - return [ - (0x33DA, 'M', u'pr'), - (0x33DB, 'M', u'sr'), - (0x33DC, 'M', u'sv'), - (0x33DD, 'M', u'wb'), - (0x33DE, 'M', u'v∕m'), - (0x33DF, 'M', u'a∕m'), - (0x33E0, 'M', u'1日'), - (0x33E1, 'M', u'2日'), - (0x33E2, 'M', u'3日'), - (0x33E3, 'M', u'4日'), - (0x33E4, 'M', u'5日'), - (0x33E5, 'M', u'6日'), - (0x33E6, 'M', u'7日'), - (0x33E7, 'M', u'8日'), - (0x33E8, 'M', u'9日'), - (0x33E9, 'M', u'10日'), - (0x33EA, 'M', u'11日'), - (0x33EB, 'M', u'12日'), - (0x33EC, 'M', u'13日'), - (0x33ED, 'M', u'14日'), - (0x33EE, 'M', u'15日'), - (0x33EF, 'M', u'16日'), - (0x33F0, 'M', u'17日'), - (0x33F1, 'M', u'18日'), - (0x33F2, 'M', u'19日'), - (0x33F3, 'M', u'20日'), - (0x33F4, 'M', u'21日'), - (0x33F5, 'M', u'22日'), - (0x33F6, 'M', u'23日'), - (0x33F7, 'M', u'24日'), - (0x33F8, 'M', u'25日'), - (0x33F9, 'M', u'26日'), - (0x33FA, 'M', u'27日'), - (0x33FB, 'M', u'28日'), - (0x33FC, 'M', u'29日'), - (0x33FD, 'M', u'30日'), - (0x33FE, 'M', u'31日'), - (0x33FF, 'M', u'gal'), - (0x3400, 'V'), - (0x9FFD, 'X'), - (0xA000, 'V'), - (0xA48D, 'X'), - (0xA490, 'V'), - (0xA4C7, 'X'), - (0xA4D0, 'V'), - (0xA62C, 'X'), - (0xA640, 'M', u'ꙁ'), - (0xA641, 'V'), - (0xA642, 'M', u'ꙃ'), - (0xA643, 'V'), - (0xA644, 'M', u'ꙅ'), - (0xA645, 'V'), - (0xA646, 'M', u'ꙇ'), - (0xA647, 'V'), - (0xA648, 'M', u'ꙉ'), - (0xA649, 'V'), - (0xA64A, 'M', u'ꙋ'), - (0xA64B, 'V'), - (0xA64C, 'M', u'ꙍ'), - (0xA64D, 'V'), - (0xA64E, 'M', u'ꙏ'), - (0xA64F, 'V'), - (0xA650, 'M', u'ꙑ'), - (0xA651, 'V'), - (0xA652, 'M', u'ꙓ'), - (0xA653, 'V'), - (0xA654, 'M', u'ꙕ'), - (0xA655, 'V'), - (0xA656, 'M', u'ꙗ'), - (0xA657, 'V'), - (0xA658, 'M', u'ꙙ'), - (0xA659, 'V'), - (0xA65A, 'M', u'ꙛ'), - (0xA65B, 'V'), - (0xA65C, 'M', u'ꙝ'), - (0xA65D, 'V'), - (0xA65E, 'M', u'ꙟ'), - (0xA65F, 'V'), - (0xA660, 'M', u'ꙡ'), - (0xA661, 'V'), - (0xA662, 'M', u'ꙣ'), - (0xA663, 'V'), - (0xA664, 'M', u'ꙥ'), - (0xA665, 'V'), - (0xA666, 'M', u'ꙧ'), - (0xA667, 'V'), - (0xA668, 'M', u'ꙩ'), - (0xA669, 'V'), - (0xA66A, 'M', u'ꙫ'), - (0xA66B, 'V'), - (0xA66C, 'M', u'ꙭ'), - (0xA66D, 'V'), - (0xA680, 'M', u'ꚁ'), - (0xA681, 'V'), - (0xA682, 'M', u'ꚃ'), - (0xA683, 'V'), - (0xA684, 'M', u'ꚅ'), - (0xA685, 'V'), - (0xA686, 'M', u'ꚇ'), - (0xA687, 'V'), - ] - -def _seg_36(): - return [ - (0xA688, 'M', u'ꚉ'), - (0xA689, 'V'), - (0xA68A, 'M', u'ꚋ'), - (0xA68B, 'V'), - (0xA68C, 'M', u'ꚍ'), - (0xA68D, 'V'), - (0xA68E, 'M', u'ꚏ'), - (0xA68F, 'V'), - (0xA690, 'M', u'ꚑ'), - (0xA691, 'V'), - (0xA692, 'M', u'ꚓ'), - (0xA693, 'V'), - (0xA694, 'M', u'ꚕ'), - (0xA695, 'V'), - (0xA696, 'M', u'ꚗ'), - (0xA697, 'V'), - (0xA698, 'M', u'ꚙ'), - (0xA699, 'V'), - (0xA69A, 'M', u'ꚛ'), - (0xA69B, 'V'), - (0xA69C, 'M', u'ъ'), - (0xA69D, 'M', u'ь'), - (0xA69E, 'V'), - (0xA6F8, 'X'), - (0xA700, 'V'), - (0xA722, 'M', u'ꜣ'), - (0xA723, 'V'), - (0xA724, 'M', u'ꜥ'), - (0xA725, 'V'), - (0xA726, 'M', u'ꜧ'), - (0xA727, 'V'), - (0xA728, 'M', u'ꜩ'), - (0xA729, 'V'), - (0xA72A, 'M', u'ꜫ'), - (0xA72B, 'V'), - (0xA72C, 'M', u'ꜭ'), - (0xA72D, 'V'), - (0xA72E, 'M', u'ꜯ'), - (0xA72F, 'V'), - (0xA732, 'M', u'ꜳ'), - (0xA733, 'V'), - (0xA734, 'M', u'ꜵ'), - (0xA735, 'V'), - (0xA736, 'M', u'ꜷ'), - (0xA737, 'V'), - (0xA738, 'M', u'ꜹ'), - (0xA739, 'V'), - (0xA73A, 'M', u'ꜻ'), - (0xA73B, 'V'), - (0xA73C, 'M', u'ꜽ'), - (0xA73D, 'V'), - (0xA73E, 'M', u'ꜿ'), - (0xA73F, 'V'), - (0xA740, 'M', u'ꝁ'), - (0xA741, 'V'), - (0xA742, 'M', u'ꝃ'), - (0xA743, 'V'), - (0xA744, 'M', u'ꝅ'), - (0xA745, 'V'), - (0xA746, 'M', u'ꝇ'), - (0xA747, 'V'), - (0xA748, 'M', u'ꝉ'), - (0xA749, 'V'), - (0xA74A, 'M', u'ꝋ'), - (0xA74B, 'V'), - (0xA74C, 'M', u'ꝍ'), - (0xA74D, 'V'), - (0xA74E, 'M', u'ꝏ'), - (0xA74F, 'V'), - (0xA750, 'M', u'ꝑ'), - (0xA751, 'V'), - (0xA752, 'M', u'ꝓ'), - (0xA753, 'V'), - (0xA754, 'M', u'ꝕ'), - (0xA755, 'V'), - (0xA756, 'M', u'ꝗ'), - (0xA757, 'V'), - (0xA758, 'M', u'ꝙ'), - (0xA759, 'V'), - (0xA75A, 'M', u'ꝛ'), - (0xA75B, 'V'), - (0xA75C, 'M', u'ꝝ'), - (0xA75D, 'V'), - (0xA75E, 'M', u'ꝟ'), - (0xA75F, 'V'), - (0xA760, 'M', u'ꝡ'), - (0xA761, 'V'), - (0xA762, 'M', u'ꝣ'), - (0xA763, 'V'), - (0xA764, 'M', u'ꝥ'), - (0xA765, 'V'), - (0xA766, 'M', u'ꝧ'), - (0xA767, 'V'), - (0xA768, 'M', u'ꝩ'), - (0xA769, 'V'), - (0xA76A, 'M', u'ꝫ'), - (0xA76B, 'V'), - (0xA76C, 'M', u'ꝭ'), - (0xA76D, 'V'), - (0xA76E, 'M', u'ꝯ'), - ] - -def _seg_37(): - return [ - (0xA76F, 'V'), - (0xA770, 'M', u'ꝯ'), - (0xA771, 'V'), - (0xA779, 'M', u'ꝺ'), - (0xA77A, 'V'), - (0xA77B, 'M', u'ꝼ'), - (0xA77C, 'V'), - (0xA77D, 'M', u'ᵹ'), - (0xA77E, 'M', u'ꝿ'), - (0xA77F, 'V'), - (0xA780, 'M', u'ꞁ'), - (0xA781, 'V'), - (0xA782, 'M', u'ꞃ'), - (0xA783, 'V'), - (0xA784, 'M', u'ꞅ'), - (0xA785, 'V'), - (0xA786, 'M', u'ꞇ'), - (0xA787, 'V'), - (0xA78B, 'M', u'ꞌ'), - (0xA78C, 'V'), - (0xA78D, 'M', u'ɥ'), - (0xA78E, 'V'), - (0xA790, 'M', u'ꞑ'), - (0xA791, 'V'), - (0xA792, 'M', u'ꞓ'), - (0xA793, 'V'), - (0xA796, 'M', u'ꞗ'), - (0xA797, 'V'), - (0xA798, 'M', u'ꞙ'), - (0xA799, 'V'), - (0xA79A, 'M', u'ꞛ'), - (0xA79B, 'V'), - (0xA79C, 'M', u'ꞝ'), - (0xA79D, 'V'), - (0xA79E, 'M', u'ꞟ'), - (0xA79F, 'V'), - (0xA7A0, 'M', u'ꞡ'), - (0xA7A1, 'V'), - (0xA7A2, 'M', u'ꞣ'), - (0xA7A3, 'V'), - (0xA7A4, 'M', u'ꞥ'), - (0xA7A5, 'V'), - (0xA7A6, 'M', u'ꞧ'), - (0xA7A7, 'V'), - (0xA7A8, 'M', u'ꞩ'), - (0xA7A9, 'V'), - (0xA7AA, 'M', u'ɦ'), - (0xA7AB, 'M', u'ɜ'), - (0xA7AC, 'M', u'ɡ'), - (0xA7AD, 'M', u'ɬ'), - (0xA7AE, 'M', u'ɪ'), - (0xA7AF, 'V'), - (0xA7B0, 'M', u'ʞ'), - (0xA7B1, 'M', u'ʇ'), - (0xA7B2, 'M', u'ʝ'), - (0xA7B3, 'M', u'ꭓ'), - (0xA7B4, 'M', u'ꞵ'), - (0xA7B5, 'V'), - (0xA7B6, 'M', u'ꞷ'), - (0xA7B7, 'V'), - (0xA7B8, 'M', u'ꞹ'), - (0xA7B9, 'V'), - (0xA7BA, 'M', u'ꞻ'), - (0xA7BB, 'V'), - (0xA7BC, 'M', u'ꞽ'), - (0xA7BD, 'V'), - (0xA7BE, 'M', u'ꞿ'), - (0xA7BF, 'V'), - (0xA7C0, 'X'), - (0xA7C2, 'M', u'ꟃ'), - (0xA7C3, 'V'), - (0xA7C4, 'M', u'ꞔ'), - (0xA7C5, 'M', u'ʂ'), - (0xA7C6, 'M', u'ᶎ'), - (0xA7C7, 'M', u'ꟈ'), - (0xA7C8, 'V'), - (0xA7C9, 'M', u'ꟊ'), - (0xA7CA, 'V'), - (0xA7CB, 'X'), - (0xA7F5, 'M', u'ꟶ'), - (0xA7F6, 'V'), - (0xA7F8, 'M', u'ħ'), - (0xA7F9, 'M', u'œ'), - (0xA7FA, 'V'), - (0xA82D, 'X'), - (0xA830, 'V'), - (0xA83A, 'X'), - (0xA840, 'V'), - (0xA878, 'X'), - (0xA880, 'V'), - (0xA8C6, 'X'), - (0xA8CE, 'V'), - (0xA8DA, 'X'), - (0xA8E0, 'V'), - (0xA954, 'X'), - (0xA95F, 'V'), - (0xA97D, 'X'), - (0xA980, 'V'), - (0xA9CE, 'X'), - (0xA9CF, 'V'), - ] - -def _seg_38(): - return [ - (0xA9DA, 'X'), - (0xA9DE, 'V'), - (0xA9FF, 'X'), - (0xAA00, 'V'), - (0xAA37, 'X'), - (0xAA40, 'V'), - (0xAA4E, 'X'), - (0xAA50, 'V'), - (0xAA5A, 'X'), - (0xAA5C, 'V'), - (0xAAC3, 'X'), - (0xAADB, 'V'), - (0xAAF7, 'X'), - (0xAB01, 'V'), - (0xAB07, 'X'), - (0xAB09, 'V'), - (0xAB0F, 'X'), - (0xAB11, 'V'), - (0xAB17, 'X'), - (0xAB20, 'V'), - (0xAB27, 'X'), - (0xAB28, 'V'), - (0xAB2F, 'X'), - (0xAB30, 'V'), - (0xAB5C, 'M', u'ꜧ'), - (0xAB5D, 'M', u'ꬷ'), - (0xAB5E, 'M', u'ɫ'), - (0xAB5F, 'M', u'ꭒ'), - (0xAB60, 'V'), - (0xAB69, 'M', u'ʍ'), - (0xAB6A, 'V'), - (0xAB6C, 'X'), - (0xAB70, 'M', u'Ꭰ'), - (0xAB71, 'M', u'Ꭱ'), - (0xAB72, 'M', u'Ꭲ'), - (0xAB73, 'M', u'Ꭳ'), - (0xAB74, 'M', u'Ꭴ'), - (0xAB75, 'M', u'Ꭵ'), - (0xAB76, 'M', u'Ꭶ'), - (0xAB77, 'M', u'Ꭷ'), - (0xAB78, 'M', u'Ꭸ'), - (0xAB79, 'M', u'Ꭹ'), - (0xAB7A, 'M', u'Ꭺ'), - (0xAB7B, 'M', u'Ꭻ'), - (0xAB7C, 'M', u'Ꭼ'), - (0xAB7D, 'M', u'Ꭽ'), - (0xAB7E, 'M', u'Ꭾ'), - (0xAB7F, 'M', u'Ꭿ'), - (0xAB80, 'M', u'Ꮀ'), - (0xAB81, 'M', u'Ꮁ'), - (0xAB82, 'M', u'Ꮂ'), - (0xAB83, 'M', u'Ꮃ'), - (0xAB84, 'M', u'Ꮄ'), - (0xAB85, 'M', u'Ꮅ'), - (0xAB86, 'M', u'Ꮆ'), - (0xAB87, 'M', u'Ꮇ'), - (0xAB88, 'M', u'Ꮈ'), - (0xAB89, 'M', u'Ꮉ'), - (0xAB8A, 'M', u'Ꮊ'), - (0xAB8B, 'M', u'Ꮋ'), - (0xAB8C, 'M', u'Ꮌ'), - (0xAB8D, 'M', u'Ꮍ'), - (0xAB8E, 'M', u'Ꮎ'), - (0xAB8F, 'M', u'Ꮏ'), - (0xAB90, 'M', u'Ꮐ'), - (0xAB91, 'M', u'Ꮑ'), - (0xAB92, 'M', u'Ꮒ'), - (0xAB93, 'M', u'Ꮓ'), - (0xAB94, 'M', u'Ꮔ'), - (0xAB95, 'M', u'Ꮕ'), - (0xAB96, 'M', u'Ꮖ'), - (0xAB97, 'M', u'Ꮗ'), - (0xAB98, 'M', u'Ꮘ'), - (0xAB99, 'M', u'Ꮙ'), - (0xAB9A, 'M', u'Ꮚ'), - (0xAB9B, 'M', u'Ꮛ'), - (0xAB9C, 'M', u'Ꮜ'), - (0xAB9D, 'M', u'Ꮝ'), - (0xAB9E, 'M', u'Ꮞ'), - (0xAB9F, 'M', u'Ꮟ'), - (0xABA0, 'M', u'Ꮠ'), - (0xABA1, 'M', u'Ꮡ'), - (0xABA2, 'M', u'Ꮢ'), - (0xABA3, 'M', u'Ꮣ'), - (0xABA4, 'M', u'Ꮤ'), - (0xABA5, 'M', u'Ꮥ'), - (0xABA6, 'M', u'Ꮦ'), - (0xABA7, 'M', u'Ꮧ'), - (0xABA8, 'M', u'Ꮨ'), - (0xABA9, 'M', u'Ꮩ'), - (0xABAA, 'M', u'Ꮪ'), - (0xABAB, 'M', u'Ꮫ'), - (0xABAC, 'M', u'Ꮬ'), - (0xABAD, 'M', u'Ꮭ'), - (0xABAE, 'M', u'Ꮮ'), - (0xABAF, 'M', u'Ꮯ'), - (0xABB0, 'M', u'Ꮰ'), - (0xABB1, 'M', u'Ꮱ'), - (0xABB2, 'M', u'Ꮲ'), - (0xABB3, 'M', u'Ꮳ'), - ] - -def _seg_39(): - return [ - (0xABB4, 'M', u'Ꮴ'), - (0xABB5, 'M', u'Ꮵ'), - (0xABB6, 'M', u'Ꮶ'), - (0xABB7, 'M', u'Ꮷ'), - (0xABB8, 'M', u'Ꮸ'), - (0xABB9, 'M', u'Ꮹ'), - (0xABBA, 'M', u'Ꮺ'), - (0xABBB, 'M', u'Ꮻ'), - (0xABBC, 'M', u'Ꮼ'), - (0xABBD, 'M', u'Ꮽ'), - (0xABBE, 'M', u'Ꮾ'), - (0xABBF, 'M', u'Ꮿ'), - (0xABC0, 'V'), - (0xABEE, 'X'), - (0xABF0, 'V'), - (0xABFA, 'X'), - (0xAC00, 'V'), - (0xD7A4, 'X'), - (0xD7B0, 'V'), - (0xD7C7, 'X'), - (0xD7CB, 'V'), - (0xD7FC, 'X'), - (0xF900, 'M', u'豈'), - (0xF901, 'M', u'更'), - (0xF902, 'M', u'車'), - (0xF903, 'M', u'賈'), - (0xF904, 'M', u'滑'), - (0xF905, 'M', u'串'), - (0xF906, 'M', u'句'), - (0xF907, 'M', u'龜'), - (0xF909, 'M', u'契'), - (0xF90A, 'M', u'金'), - (0xF90B, 'M', u'喇'), - (0xF90C, 'M', u'奈'), - (0xF90D, 'M', u'懶'), - (0xF90E, 'M', u'癩'), - (0xF90F, 'M', u'羅'), - (0xF910, 'M', u'蘿'), - (0xF911, 'M', u'螺'), - (0xF912, 'M', u'裸'), - (0xF913, 'M', u'邏'), - (0xF914, 'M', u'樂'), - (0xF915, 'M', u'洛'), - (0xF916, 'M', u'烙'), - (0xF917, 'M', u'珞'), - (0xF918, 'M', u'落'), - (0xF919, 'M', u'酪'), - (0xF91A, 'M', u'駱'), - (0xF91B, 'M', u'亂'), - (0xF91C, 'M', u'卵'), - (0xF91D, 'M', u'欄'), - (0xF91E, 'M', u'爛'), - (0xF91F, 'M', u'蘭'), - (0xF920, 'M', u'鸞'), - (0xF921, 'M', u'嵐'), - (0xF922, 'M', u'濫'), - (0xF923, 'M', u'藍'), - (0xF924, 'M', u'襤'), - (0xF925, 'M', u'拉'), - (0xF926, 'M', u'臘'), - (0xF927, 'M', u'蠟'), - (0xF928, 'M', u'廊'), - (0xF929, 'M', u'朗'), - (0xF92A, 'M', u'浪'), - (0xF92B, 'M', u'狼'), - (0xF92C, 'M', u'郎'), - (0xF92D, 'M', u'來'), - (0xF92E, 'M', u'冷'), - (0xF92F, 'M', u'勞'), - (0xF930, 'M', u'擄'), - (0xF931, 'M', u'櫓'), - (0xF932, 'M', u'爐'), - (0xF933, 'M', u'盧'), - (0xF934, 'M', u'老'), - (0xF935, 'M', u'蘆'), - (0xF936, 'M', u'虜'), - (0xF937, 'M', u'路'), - (0xF938, 'M', u'露'), - (0xF939, 'M', u'魯'), - (0xF93A, 'M', u'鷺'), - (0xF93B, 'M', u'碌'), - (0xF93C, 'M', u'祿'), - (0xF93D, 'M', u'綠'), - (0xF93E, 'M', u'菉'), - (0xF93F, 'M', u'錄'), - (0xF940, 'M', u'鹿'), - (0xF941, 'M', u'論'), - (0xF942, 'M', u'壟'), - (0xF943, 'M', u'弄'), - (0xF944, 'M', u'籠'), - (0xF945, 'M', u'聾'), - (0xF946, 'M', u'牢'), - (0xF947, 'M', u'磊'), - (0xF948, 'M', u'賂'), - (0xF949, 'M', u'雷'), - (0xF94A, 'M', u'壘'), - (0xF94B, 'M', u'屢'), - (0xF94C, 'M', u'樓'), - (0xF94D, 'M', u'淚'), - (0xF94E, 'M', u'漏'), - ] - -def _seg_40(): - return [ - (0xF94F, 'M', u'累'), - (0xF950, 'M', u'縷'), - (0xF951, 'M', u'陋'), - (0xF952, 'M', u'勒'), - (0xF953, 'M', u'肋'), - (0xF954, 'M', u'凜'), - (0xF955, 'M', u'凌'), - (0xF956, 'M', u'稜'), - (0xF957, 'M', u'綾'), - (0xF958, 'M', u'菱'), - (0xF959, 'M', u'陵'), - (0xF95A, 'M', u'讀'), - (0xF95B, 'M', u'拏'), - (0xF95C, 'M', u'樂'), - (0xF95D, 'M', u'諾'), - (0xF95E, 'M', u'丹'), - (0xF95F, 'M', u'寧'), - (0xF960, 'M', u'怒'), - (0xF961, 'M', u'率'), - (0xF962, 'M', u'異'), - (0xF963, 'M', u'北'), - (0xF964, 'M', u'磻'), - (0xF965, 'M', u'便'), - (0xF966, 'M', u'復'), - (0xF967, 'M', u'不'), - (0xF968, 'M', u'泌'), - (0xF969, 'M', u'數'), - (0xF96A, 'M', u'索'), - (0xF96B, 'M', u'參'), - (0xF96C, 'M', u'塞'), - (0xF96D, 'M', u'省'), - (0xF96E, 'M', u'葉'), - (0xF96F, 'M', u'說'), - (0xF970, 'M', u'殺'), - (0xF971, 'M', u'辰'), - (0xF972, 'M', u'沈'), - (0xF973, 'M', u'拾'), - (0xF974, 'M', u'若'), - (0xF975, 'M', u'掠'), - (0xF976, 'M', u'略'), - (0xF977, 'M', u'亮'), - (0xF978, 'M', u'兩'), - (0xF979, 'M', u'凉'), - (0xF97A, 'M', u'梁'), - (0xF97B, 'M', u'糧'), - (0xF97C, 'M', u'良'), - (0xF97D, 'M', u'諒'), - (0xF97E, 'M', u'量'), - (0xF97F, 'M', u'勵'), - (0xF980, 'M', u'呂'), - (0xF981, 'M', u'女'), - (0xF982, 'M', u'廬'), - (0xF983, 'M', u'旅'), - (0xF984, 'M', u'濾'), - (0xF985, 'M', u'礪'), - (0xF986, 'M', u'閭'), - (0xF987, 'M', u'驪'), - (0xF988, 'M', u'麗'), - (0xF989, 'M', u'黎'), - (0xF98A, 'M', u'力'), - (0xF98B, 'M', u'曆'), - (0xF98C, 'M', u'歷'), - (0xF98D, 'M', u'轢'), - (0xF98E, 'M', u'年'), - (0xF98F, 'M', u'憐'), - (0xF990, 'M', u'戀'), - (0xF991, 'M', u'撚'), - (0xF992, 'M', u'漣'), - (0xF993, 'M', u'煉'), - (0xF994, 'M', u'璉'), - (0xF995, 'M', u'秊'), - (0xF996, 'M', u'練'), - (0xF997, 'M', u'聯'), - (0xF998, 'M', u'輦'), - (0xF999, 'M', u'蓮'), - (0xF99A, 'M', u'連'), - (0xF99B, 'M', u'鍊'), - (0xF99C, 'M', u'列'), - (0xF99D, 'M', u'劣'), - (0xF99E, 'M', u'咽'), - (0xF99F, 'M', u'烈'), - (0xF9A0, 'M', u'裂'), - (0xF9A1, 'M', u'說'), - (0xF9A2, 'M', u'廉'), - (0xF9A3, 'M', u'念'), - (0xF9A4, 'M', u'捻'), - (0xF9A5, 'M', u'殮'), - (0xF9A6, 'M', u'簾'), - (0xF9A7, 'M', u'獵'), - (0xF9A8, 'M', u'令'), - (0xF9A9, 'M', u'囹'), - (0xF9AA, 'M', u'寧'), - (0xF9AB, 'M', u'嶺'), - (0xF9AC, 'M', u'怜'), - (0xF9AD, 'M', u'玲'), - (0xF9AE, 'M', u'瑩'), - (0xF9AF, 'M', u'羚'), - (0xF9B0, 'M', u'聆'), - (0xF9B1, 'M', u'鈴'), - (0xF9B2, 'M', u'零'), - ] - -def _seg_41(): - return [ - (0xF9B3, 'M', u'靈'), - (0xF9B4, 'M', u'領'), - (0xF9B5, 'M', u'例'), - (0xF9B6, 'M', u'禮'), - (0xF9B7, 'M', u'醴'), - (0xF9B8, 'M', u'隸'), - (0xF9B9, 'M', u'惡'), - (0xF9BA, 'M', u'了'), - (0xF9BB, 'M', u'僚'), - (0xF9BC, 'M', u'寮'), - (0xF9BD, 'M', u'尿'), - (0xF9BE, 'M', u'料'), - (0xF9BF, 'M', u'樂'), - (0xF9C0, 'M', u'燎'), - (0xF9C1, 'M', u'療'), - (0xF9C2, 'M', u'蓼'), - (0xF9C3, 'M', u'遼'), - (0xF9C4, 'M', u'龍'), - (0xF9C5, 'M', u'暈'), - (0xF9C6, 'M', u'阮'), - (0xF9C7, 'M', u'劉'), - (0xF9C8, 'M', u'杻'), - (0xF9C9, 'M', u'柳'), - (0xF9CA, 'M', u'流'), - (0xF9CB, 'M', u'溜'), - (0xF9CC, 'M', u'琉'), - (0xF9CD, 'M', u'留'), - (0xF9CE, 'M', u'硫'), - (0xF9CF, 'M', u'紐'), - (0xF9D0, 'M', u'類'), - (0xF9D1, 'M', u'六'), - (0xF9D2, 'M', u'戮'), - (0xF9D3, 'M', u'陸'), - (0xF9D4, 'M', u'倫'), - (0xF9D5, 'M', u'崙'), - (0xF9D6, 'M', u'淪'), - (0xF9D7, 'M', u'輪'), - (0xF9D8, 'M', u'律'), - (0xF9D9, 'M', u'慄'), - (0xF9DA, 'M', u'栗'), - (0xF9DB, 'M', u'率'), - (0xF9DC, 'M', u'隆'), - (0xF9DD, 'M', u'利'), - (0xF9DE, 'M', u'吏'), - (0xF9DF, 'M', u'履'), - (0xF9E0, 'M', u'易'), - (0xF9E1, 'M', u'李'), - (0xF9E2, 'M', u'梨'), - (0xF9E3, 'M', u'泥'), - (0xF9E4, 'M', u'理'), - (0xF9E5, 'M', u'痢'), - (0xF9E6, 'M', u'罹'), - (0xF9E7, 'M', u'裏'), - (0xF9E8, 'M', u'裡'), - (0xF9E9, 'M', u'里'), - (0xF9EA, 'M', u'離'), - (0xF9EB, 'M', u'匿'), - (0xF9EC, 'M', u'溺'), - (0xF9ED, 'M', u'吝'), - (0xF9EE, 'M', u'燐'), - (0xF9EF, 'M', u'璘'), - (0xF9F0, 'M', u'藺'), - (0xF9F1, 'M', u'隣'), - (0xF9F2, 'M', u'鱗'), - (0xF9F3, 'M', u'麟'), - (0xF9F4, 'M', u'林'), - (0xF9F5, 'M', u'淋'), - (0xF9F6, 'M', u'臨'), - (0xF9F7, 'M', u'立'), - (0xF9F8, 'M', u'笠'), - (0xF9F9, 'M', u'粒'), - (0xF9FA, 'M', u'狀'), - (0xF9FB, 'M', u'炙'), - (0xF9FC, 'M', u'識'), - (0xF9FD, 'M', u'什'), - (0xF9FE, 'M', u'茶'), - (0xF9FF, 'M', u'刺'), - (0xFA00, 'M', u'切'), - (0xFA01, 'M', u'度'), - (0xFA02, 'M', u'拓'), - (0xFA03, 'M', u'糖'), - (0xFA04, 'M', u'宅'), - (0xFA05, 'M', u'洞'), - (0xFA06, 'M', u'暴'), - (0xFA07, 'M', u'輻'), - (0xFA08, 'M', u'行'), - (0xFA09, 'M', u'降'), - (0xFA0A, 'M', u'見'), - (0xFA0B, 'M', u'廓'), - (0xFA0C, 'M', u'兀'), - (0xFA0D, 'M', u'嗀'), - (0xFA0E, 'V'), - (0xFA10, 'M', u'塚'), - (0xFA11, 'V'), - (0xFA12, 'M', u'晴'), - (0xFA13, 'V'), - (0xFA15, 'M', u'凞'), - (0xFA16, 'M', u'猪'), - (0xFA17, 'M', u'益'), - (0xFA18, 'M', u'礼'), - ] - -def _seg_42(): - return [ - (0xFA19, 'M', u'神'), - (0xFA1A, 'M', u'祥'), - (0xFA1B, 'M', u'福'), - (0xFA1C, 'M', u'靖'), - (0xFA1D, 'M', u'精'), - (0xFA1E, 'M', u'羽'), - (0xFA1F, 'V'), - (0xFA20, 'M', u'蘒'), - (0xFA21, 'V'), - (0xFA22, 'M', u'諸'), - (0xFA23, 'V'), - (0xFA25, 'M', u'逸'), - (0xFA26, 'M', u'都'), - (0xFA27, 'V'), - (0xFA2A, 'M', u'飯'), - (0xFA2B, 'M', u'飼'), - (0xFA2C, 'M', u'館'), - (0xFA2D, 'M', u'鶴'), - (0xFA2E, 'M', u'郞'), - (0xFA2F, 'M', u'隷'), - (0xFA30, 'M', u'侮'), - (0xFA31, 'M', u'僧'), - (0xFA32, 'M', u'免'), - (0xFA33, 'M', u'勉'), - (0xFA34, 'M', u'勤'), - (0xFA35, 'M', u'卑'), - (0xFA36, 'M', u'喝'), - (0xFA37, 'M', u'嘆'), - (0xFA38, 'M', u'器'), - (0xFA39, 'M', u'塀'), - (0xFA3A, 'M', u'墨'), - (0xFA3B, 'M', u'層'), - (0xFA3C, 'M', u'屮'), - (0xFA3D, 'M', u'悔'), - (0xFA3E, 'M', u'慨'), - (0xFA3F, 'M', u'憎'), - (0xFA40, 'M', u'懲'), - (0xFA41, 'M', u'敏'), - (0xFA42, 'M', u'既'), - (0xFA43, 'M', u'暑'), - (0xFA44, 'M', u'梅'), - (0xFA45, 'M', u'海'), - (0xFA46, 'M', u'渚'), - (0xFA47, 'M', u'漢'), - (0xFA48, 'M', u'煮'), - (0xFA49, 'M', u'爫'), - (0xFA4A, 'M', u'琢'), - (0xFA4B, 'M', u'碑'), - (0xFA4C, 'M', u'社'), - (0xFA4D, 'M', u'祉'), - (0xFA4E, 'M', u'祈'), - (0xFA4F, 'M', u'祐'), - (0xFA50, 'M', u'祖'), - (0xFA51, 'M', u'祝'), - (0xFA52, 'M', u'禍'), - (0xFA53, 'M', u'禎'), - (0xFA54, 'M', u'穀'), - (0xFA55, 'M', u'突'), - (0xFA56, 'M', u'節'), - (0xFA57, 'M', u'練'), - (0xFA58, 'M', u'縉'), - (0xFA59, 'M', u'繁'), - (0xFA5A, 'M', u'署'), - (0xFA5B, 'M', u'者'), - (0xFA5C, 'M', u'臭'), - (0xFA5D, 'M', u'艹'), - (0xFA5F, 'M', u'著'), - (0xFA60, 'M', u'褐'), - (0xFA61, 'M', u'視'), - (0xFA62, 'M', u'謁'), - (0xFA63, 'M', u'謹'), - (0xFA64, 'M', u'賓'), - (0xFA65, 'M', u'贈'), - (0xFA66, 'M', u'辶'), - (0xFA67, 'M', u'逸'), - (0xFA68, 'M', u'難'), - (0xFA69, 'M', u'響'), - (0xFA6A, 'M', u'頻'), - (0xFA6B, 'M', u'恵'), - (0xFA6C, 'M', u'𤋮'), - (0xFA6D, 'M', u'舘'), - (0xFA6E, 'X'), - (0xFA70, 'M', u'並'), - (0xFA71, 'M', u'况'), - (0xFA72, 'M', u'全'), - (0xFA73, 'M', u'侀'), - (0xFA74, 'M', u'充'), - (0xFA75, 'M', u'冀'), - (0xFA76, 'M', u'勇'), - (0xFA77, 'M', u'勺'), - (0xFA78, 'M', u'喝'), - (0xFA79, 'M', u'啕'), - (0xFA7A, 'M', u'喙'), - (0xFA7B, 'M', u'嗢'), - (0xFA7C, 'M', u'塚'), - (0xFA7D, 'M', u'墳'), - (0xFA7E, 'M', u'奄'), - (0xFA7F, 'M', u'奔'), - (0xFA80, 'M', u'婢'), - (0xFA81, 'M', u'嬨'), - ] - -def _seg_43(): - return [ - (0xFA82, 'M', u'廒'), - (0xFA83, 'M', u'廙'), - (0xFA84, 'M', u'彩'), - (0xFA85, 'M', u'徭'), - (0xFA86, 'M', u'惘'), - (0xFA87, 'M', u'慎'), - (0xFA88, 'M', u'愈'), - (0xFA89, 'M', u'憎'), - (0xFA8A, 'M', u'慠'), - (0xFA8B, 'M', u'懲'), - (0xFA8C, 'M', u'戴'), - (0xFA8D, 'M', u'揄'), - (0xFA8E, 'M', u'搜'), - (0xFA8F, 'M', u'摒'), - (0xFA90, 'M', u'敖'), - (0xFA91, 'M', u'晴'), - (0xFA92, 'M', u'朗'), - (0xFA93, 'M', u'望'), - (0xFA94, 'M', u'杖'), - (0xFA95, 'M', u'歹'), - (0xFA96, 'M', u'殺'), - (0xFA97, 'M', u'流'), - (0xFA98, 'M', u'滛'), - (0xFA99, 'M', u'滋'), - (0xFA9A, 'M', u'漢'), - (0xFA9B, 'M', u'瀞'), - (0xFA9C, 'M', u'煮'), - (0xFA9D, 'M', u'瞧'), - (0xFA9E, 'M', u'爵'), - (0xFA9F, 'M', u'犯'), - (0xFAA0, 'M', u'猪'), - (0xFAA1, 'M', u'瑱'), - (0xFAA2, 'M', u'甆'), - (0xFAA3, 'M', u'画'), - (0xFAA4, 'M', u'瘝'), - (0xFAA5, 'M', u'瘟'), - (0xFAA6, 'M', u'益'), - (0xFAA7, 'M', u'盛'), - (0xFAA8, 'M', u'直'), - (0xFAA9, 'M', u'睊'), - (0xFAAA, 'M', u'着'), - (0xFAAB, 'M', u'磌'), - (0xFAAC, 'M', u'窱'), - (0xFAAD, 'M', u'節'), - (0xFAAE, 'M', u'类'), - (0xFAAF, 'M', u'絛'), - (0xFAB0, 'M', u'練'), - (0xFAB1, 'M', u'缾'), - (0xFAB2, 'M', u'者'), - (0xFAB3, 'M', u'荒'), - (0xFAB4, 'M', u'華'), - (0xFAB5, 'M', u'蝹'), - (0xFAB6, 'M', u'襁'), - (0xFAB7, 'M', u'覆'), - (0xFAB8, 'M', u'視'), - (0xFAB9, 'M', u'調'), - (0xFABA, 'M', u'諸'), - (0xFABB, 'M', u'請'), - (0xFABC, 'M', u'謁'), - (0xFABD, 'M', u'諾'), - (0xFABE, 'M', u'諭'), - (0xFABF, 'M', u'謹'), - (0xFAC0, 'M', u'變'), - (0xFAC1, 'M', u'贈'), - (0xFAC2, 'M', u'輸'), - (0xFAC3, 'M', u'遲'), - (0xFAC4, 'M', u'醙'), - (0xFAC5, 'M', u'鉶'), - (0xFAC6, 'M', u'陼'), - (0xFAC7, 'M', u'難'), - (0xFAC8, 'M', u'靖'), - (0xFAC9, 'M', u'韛'), - (0xFACA, 'M', u'響'), - (0xFACB, 'M', u'頋'), - (0xFACC, 'M', u'頻'), - (0xFACD, 'M', u'鬒'), - (0xFACE, 'M', u'龜'), - (0xFACF, 'M', u'𢡊'), - (0xFAD0, 'M', u'𢡄'), - (0xFAD1, 'M', u'𣏕'), - (0xFAD2, 'M', u'㮝'), - (0xFAD3, 'M', u'䀘'), - (0xFAD4, 'M', u'䀹'), - (0xFAD5, 'M', u'𥉉'), - (0xFAD6, 'M', u'𥳐'), - (0xFAD7, 'M', u'𧻓'), - (0xFAD8, 'M', u'齃'), - (0xFAD9, 'M', u'龎'), - (0xFADA, 'X'), - (0xFB00, 'M', u'ff'), - (0xFB01, 'M', u'fi'), - (0xFB02, 'M', u'fl'), - (0xFB03, 'M', u'ffi'), - (0xFB04, 'M', u'ffl'), - (0xFB05, 'M', u'st'), - (0xFB07, 'X'), - (0xFB13, 'M', u'մն'), - (0xFB14, 'M', u'մե'), - (0xFB15, 'M', u'մի'), - (0xFB16, 'M', u'վն'), - ] - -def _seg_44(): - return [ - (0xFB17, 'M', u'մխ'), - (0xFB18, 'X'), - (0xFB1D, 'M', u'יִ'), - (0xFB1E, 'V'), - (0xFB1F, 'M', u'ײַ'), - (0xFB20, 'M', u'ע'), - (0xFB21, 'M', u'א'), - (0xFB22, 'M', u'ד'), - (0xFB23, 'M', u'ה'), - (0xFB24, 'M', u'כ'), - (0xFB25, 'M', u'ל'), - (0xFB26, 'M', u'ם'), - (0xFB27, 'M', u'ר'), - (0xFB28, 'M', u'ת'), - (0xFB29, '3', u'+'), - (0xFB2A, 'M', u'שׁ'), - (0xFB2B, 'M', u'שׂ'), - (0xFB2C, 'M', u'שּׁ'), - (0xFB2D, 'M', u'שּׂ'), - (0xFB2E, 'M', u'אַ'), - (0xFB2F, 'M', u'אָ'), - (0xFB30, 'M', u'אּ'), - (0xFB31, 'M', u'בּ'), - (0xFB32, 'M', u'גּ'), - (0xFB33, 'M', u'דּ'), - (0xFB34, 'M', u'הּ'), - (0xFB35, 'M', u'וּ'), - (0xFB36, 'M', u'זּ'), - (0xFB37, 'X'), - (0xFB38, 'M', u'טּ'), - (0xFB39, 'M', u'יּ'), - (0xFB3A, 'M', u'ךּ'), - (0xFB3B, 'M', u'כּ'), - (0xFB3C, 'M', u'לּ'), - (0xFB3D, 'X'), - (0xFB3E, 'M', u'מּ'), - (0xFB3F, 'X'), - (0xFB40, 'M', u'נּ'), - (0xFB41, 'M', u'סּ'), - (0xFB42, 'X'), - (0xFB43, 'M', u'ףּ'), - (0xFB44, 'M', u'פּ'), - (0xFB45, 'X'), - (0xFB46, 'M', u'צּ'), - (0xFB47, 'M', u'קּ'), - (0xFB48, 'M', u'רּ'), - (0xFB49, 'M', u'שּ'), - (0xFB4A, 'M', u'תּ'), - (0xFB4B, 'M', u'וֹ'), - (0xFB4C, 'M', u'בֿ'), - (0xFB4D, 'M', u'כֿ'), - (0xFB4E, 'M', u'פֿ'), - (0xFB4F, 'M', u'אל'), - (0xFB50, 'M', u'ٱ'), - (0xFB52, 'M', u'ٻ'), - (0xFB56, 'M', u'پ'), - (0xFB5A, 'M', u'ڀ'), - (0xFB5E, 'M', u'ٺ'), - (0xFB62, 'M', u'ٿ'), - (0xFB66, 'M', u'ٹ'), - (0xFB6A, 'M', u'ڤ'), - (0xFB6E, 'M', u'ڦ'), - (0xFB72, 'M', u'ڄ'), - (0xFB76, 'M', u'ڃ'), - (0xFB7A, 'M', u'چ'), - (0xFB7E, 'M', u'ڇ'), - (0xFB82, 'M', u'ڍ'), - (0xFB84, 'M', u'ڌ'), - (0xFB86, 'M', u'ڎ'), - (0xFB88, 'M', u'ڈ'), - (0xFB8A, 'M', u'ژ'), - (0xFB8C, 'M', u'ڑ'), - (0xFB8E, 'M', u'ک'), - (0xFB92, 'M', u'گ'), - (0xFB96, 'M', u'ڳ'), - (0xFB9A, 'M', u'ڱ'), - (0xFB9E, 'M', u'ں'), - (0xFBA0, 'M', u'ڻ'), - (0xFBA4, 'M', u'ۀ'), - (0xFBA6, 'M', u'ہ'), - (0xFBAA, 'M', u'ھ'), - (0xFBAE, 'M', u'ے'), - (0xFBB0, 'M', u'ۓ'), - (0xFBB2, 'V'), - (0xFBC2, 'X'), - (0xFBD3, 'M', u'ڭ'), - (0xFBD7, 'M', u'ۇ'), - (0xFBD9, 'M', u'ۆ'), - (0xFBDB, 'M', u'ۈ'), - (0xFBDD, 'M', u'ۇٴ'), - (0xFBDE, 'M', u'ۋ'), - (0xFBE0, 'M', u'ۅ'), - (0xFBE2, 'M', u'ۉ'), - (0xFBE4, 'M', u'ې'), - (0xFBE8, 'M', u'ى'), - (0xFBEA, 'M', u'ئا'), - (0xFBEC, 'M', u'ئە'), - (0xFBEE, 'M', u'ئو'), - (0xFBF0, 'M', u'ئۇ'), - (0xFBF2, 'M', u'ئۆ'), - ] - -def _seg_45(): - return [ - (0xFBF4, 'M', u'ئۈ'), - (0xFBF6, 'M', u'ئې'), - (0xFBF9, 'M', u'ئى'), - (0xFBFC, 'M', u'ی'), - (0xFC00, 'M', u'ئج'), - (0xFC01, 'M', u'ئح'), - (0xFC02, 'M', u'ئم'), - (0xFC03, 'M', u'ئى'), - (0xFC04, 'M', u'ئي'), - (0xFC05, 'M', u'بج'), - (0xFC06, 'M', u'بح'), - (0xFC07, 'M', u'بخ'), - (0xFC08, 'M', u'بم'), - (0xFC09, 'M', u'بى'), - (0xFC0A, 'M', u'بي'), - (0xFC0B, 'M', u'تج'), - (0xFC0C, 'M', u'تح'), - (0xFC0D, 'M', u'تخ'), - (0xFC0E, 'M', u'تم'), - (0xFC0F, 'M', u'تى'), - (0xFC10, 'M', u'تي'), - (0xFC11, 'M', u'ثج'), - (0xFC12, 'M', u'ثم'), - (0xFC13, 'M', u'ثى'), - (0xFC14, 'M', u'ثي'), - (0xFC15, 'M', u'جح'), - (0xFC16, 'M', u'جم'), - (0xFC17, 'M', u'حج'), - (0xFC18, 'M', u'حم'), - (0xFC19, 'M', u'خج'), - (0xFC1A, 'M', u'خح'), - (0xFC1B, 'M', u'خم'), - (0xFC1C, 'M', u'سج'), - (0xFC1D, 'M', u'سح'), - (0xFC1E, 'M', u'سخ'), - (0xFC1F, 'M', u'سم'), - (0xFC20, 'M', u'صح'), - (0xFC21, 'M', u'صم'), - (0xFC22, 'M', u'ضج'), - (0xFC23, 'M', u'ضح'), - (0xFC24, 'M', u'ضخ'), - (0xFC25, 'M', u'ضم'), - (0xFC26, 'M', u'طح'), - (0xFC27, 'M', u'طم'), - (0xFC28, 'M', u'ظم'), - (0xFC29, 'M', u'عج'), - (0xFC2A, 'M', u'عم'), - (0xFC2B, 'M', u'غج'), - (0xFC2C, 'M', u'غم'), - (0xFC2D, 'M', u'فج'), - (0xFC2E, 'M', u'فح'), - (0xFC2F, 'M', u'فخ'), - (0xFC30, 'M', u'فم'), - (0xFC31, 'M', u'فى'), - (0xFC32, 'M', u'في'), - (0xFC33, 'M', u'قح'), - (0xFC34, 'M', u'قم'), - (0xFC35, 'M', u'قى'), - (0xFC36, 'M', u'قي'), - (0xFC37, 'M', u'كا'), - (0xFC38, 'M', u'كج'), - (0xFC39, 'M', u'كح'), - (0xFC3A, 'M', u'كخ'), - (0xFC3B, 'M', u'كل'), - (0xFC3C, 'M', u'كم'), - (0xFC3D, 'M', u'كى'), - (0xFC3E, 'M', u'كي'), - (0xFC3F, 'M', u'لج'), - (0xFC40, 'M', u'لح'), - (0xFC41, 'M', u'لخ'), - (0xFC42, 'M', u'لم'), - (0xFC43, 'M', u'لى'), - (0xFC44, 'M', u'لي'), - (0xFC45, 'M', u'مج'), - (0xFC46, 'M', u'مح'), - (0xFC47, 'M', u'مخ'), - (0xFC48, 'M', u'مم'), - (0xFC49, 'M', u'مى'), - (0xFC4A, 'M', u'مي'), - (0xFC4B, 'M', u'نج'), - (0xFC4C, 'M', u'نح'), - (0xFC4D, 'M', u'نخ'), - (0xFC4E, 'M', u'نم'), - (0xFC4F, 'M', u'نى'), - (0xFC50, 'M', u'ني'), - (0xFC51, 'M', u'هج'), - (0xFC52, 'M', u'هم'), - (0xFC53, 'M', u'هى'), - (0xFC54, 'M', u'هي'), - (0xFC55, 'M', u'يج'), - (0xFC56, 'M', u'يح'), - (0xFC57, 'M', u'يخ'), - (0xFC58, 'M', u'يم'), - (0xFC59, 'M', u'يى'), - (0xFC5A, 'M', u'يي'), - (0xFC5B, 'M', u'ذٰ'), - (0xFC5C, 'M', u'رٰ'), - (0xFC5D, 'M', u'ىٰ'), - (0xFC5E, '3', u' ٌّ'), - (0xFC5F, '3', u' ٍّ'), - ] - -def _seg_46(): - return [ - (0xFC60, '3', u' َّ'), - (0xFC61, '3', u' ُّ'), - (0xFC62, '3', u' ِّ'), - (0xFC63, '3', u' ّٰ'), - (0xFC64, 'M', u'ئر'), - (0xFC65, 'M', u'ئز'), - (0xFC66, 'M', u'ئم'), - (0xFC67, 'M', u'ئن'), - (0xFC68, 'M', u'ئى'), - (0xFC69, 'M', u'ئي'), - (0xFC6A, 'M', u'بر'), - (0xFC6B, 'M', u'بز'), - (0xFC6C, 'M', u'بم'), - (0xFC6D, 'M', u'بن'), - (0xFC6E, 'M', u'بى'), - (0xFC6F, 'M', u'بي'), - (0xFC70, 'M', u'تر'), - (0xFC71, 'M', u'تز'), - (0xFC72, 'M', u'تم'), - (0xFC73, 'M', u'تن'), - (0xFC74, 'M', u'تى'), - (0xFC75, 'M', u'تي'), - (0xFC76, 'M', u'ثر'), - (0xFC77, 'M', u'ثز'), - (0xFC78, 'M', u'ثم'), - (0xFC79, 'M', u'ثن'), - (0xFC7A, 'M', u'ثى'), - (0xFC7B, 'M', u'ثي'), - (0xFC7C, 'M', u'فى'), - (0xFC7D, 'M', u'في'), - (0xFC7E, 'M', u'قى'), - (0xFC7F, 'M', u'قي'), - (0xFC80, 'M', u'كا'), - (0xFC81, 'M', u'كل'), - (0xFC82, 'M', u'كم'), - (0xFC83, 'M', u'كى'), - (0xFC84, 'M', u'كي'), - (0xFC85, 'M', u'لم'), - (0xFC86, 'M', u'لى'), - (0xFC87, 'M', u'لي'), - (0xFC88, 'M', u'ما'), - (0xFC89, 'M', u'مم'), - (0xFC8A, 'M', u'نر'), - (0xFC8B, 'M', u'نز'), - (0xFC8C, 'M', u'نم'), - (0xFC8D, 'M', u'نن'), - (0xFC8E, 'M', u'نى'), - (0xFC8F, 'M', u'ني'), - (0xFC90, 'M', u'ىٰ'), - (0xFC91, 'M', u'ير'), - (0xFC92, 'M', u'يز'), - (0xFC93, 'M', u'يم'), - (0xFC94, 'M', u'ين'), - (0xFC95, 'M', u'يى'), - (0xFC96, 'M', u'يي'), - (0xFC97, 'M', u'ئج'), - (0xFC98, 'M', u'ئح'), - (0xFC99, 'M', u'ئخ'), - (0xFC9A, 'M', u'ئم'), - (0xFC9B, 'M', u'ئه'), - (0xFC9C, 'M', u'بج'), - (0xFC9D, 'M', u'بح'), - (0xFC9E, 'M', u'بخ'), - (0xFC9F, 'M', u'بم'), - (0xFCA0, 'M', u'به'), - (0xFCA1, 'M', u'تج'), - (0xFCA2, 'M', u'تح'), - (0xFCA3, 'M', u'تخ'), - (0xFCA4, 'M', u'تم'), - (0xFCA5, 'M', u'ته'), - (0xFCA6, 'M', u'ثم'), - (0xFCA7, 'M', u'جح'), - (0xFCA8, 'M', u'جم'), - (0xFCA9, 'M', u'حج'), - (0xFCAA, 'M', u'حم'), - (0xFCAB, 'M', u'خج'), - (0xFCAC, 'M', u'خم'), - (0xFCAD, 'M', u'سج'), - (0xFCAE, 'M', u'سح'), - (0xFCAF, 'M', u'سخ'), - (0xFCB0, 'M', u'سم'), - (0xFCB1, 'M', u'صح'), - (0xFCB2, 'M', u'صخ'), - (0xFCB3, 'M', u'صم'), - (0xFCB4, 'M', u'ضج'), - (0xFCB5, 'M', u'ضح'), - (0xFCB6, 'M', u'ضخ'), - (0xFCB7, 'M', u'ضم'), - (0xFCB8, 'M', u'طح'), - (0xFCB9, 'M', u'ظم'), - (0xFCBA, 'M', u'عج'), - (0xFCBB, 'M', u'عم'), - (0xFCBC, 'M', u'غج'), - (0xFCBD, 'M', u'غم'), - (0xFCBE, 'M', u'فج'), - (0xFCBF, 'M', u'فح'), - (0xFCC0, 'M', u'فخ'), - (0xFCC1, 'M', u'فم'), - (0xFCC2, 'M', u'قح'), - (0xFCC3, 'M', u'قم'), - ] - -def _seg_47(): - return [ - (0xFCC4, 'M', u'كج'), - (0xFCC5, 'M', u'كح'), - (0xFCC6, 'M', u'كخ'), - (0xFCC7, 'M', u'كل'), - (0xFCC8, 'M', u'كم'), - (0xFCC9, 'M', u'لج'), - (0xFCCA, 'M', u'لح'), - (0xFCCB, 'M', u'لخ'), - (0xFCCC, 'M', u'لم'), - (0xFCCD, 'M', u'له'), - (0xFCCE, 'M', u'مج'), - (0xFCCF, 'M', u'مح'), - (0xFCD0, 'M', u'مخ'), - (0xFCD1, 'M', u'مم'), - (0xFCD2, 'M', u'نج'), - (0xFCD3, 'M', u'نح'), - (0xFCD4, 'M', u'نخ'), - (0xFCD5, 'M', u'نم'), - (0xFCD6, 'M', u'نه'), - (0xFCD7, 'M', u'هج'), - (0xFCD8, 'M', u'هم'), - (0xFCD9, 'M', u'هٰ'), - (0xFCDA, 'M', u'يج'), - (0xFCDB, 'M', u'يح'), - (0xFCDC, 'M', u'يخ'), - (0xFCDD, 'M', u'يم'), - (0xFCDE, 'M', u'يه'), - (0xFCDF, 'M', u'ئم'), - (0xFCE0, 'M', u'ئه'), - (0xFCE1, 'M', u'بم'), - (0xFCE2, 'M', u'به'), - (0xFCE3, 'M', u'تم'), - (0xFCE4, 'M', u'ته'), - (0xFCE5, 'M', u'ثم'), - (0xFCE6, 'M', u'ثه'), - (0xFCE7, 'M', u'سم'), - (0xFCE8, 'M', u'سه'), - (0xFCE9, 'M', u'شم'), - (0xFCEA, 'M', u'شه'), - (0xFCEB, 'M', u'كل'), - (0xFCEC, 'M', u'كم'), - (0xFCED, 'M', u'لم'), - (0xFCEE, 'M', u'نم'), - (0xFCEF, 'M', u'نه'), - (0xFCF0, 'M', u'يم'), - (0xFCF1, 'M', u'يه'), - (0xFCF2, 'M', u'ـَّ'), - (0xFCF3, 'M', u'ـُّ'), - (0xFCF4, 'M', u'ـِّ'), - (0xFCF5, 'M', u'طى'), - (0xFCF6, 'M', u'طي'), - (0xFCF7, 'M', u'عى'), - (0xFCF8, 'M', u'عي'), - (0xFCF9, 'M', u'غى'), - (0xFCFA, 'M', u'غي'), - (0xFCFB, 'M', u'سى'), - (0xFCFC, 'M', u'سي'), - (0xFCFD, 'M', u'شى'), - (0xFCFE, 'M', u'شي'), - (0xFCFF, 'M', u'حى'), - (0xFD00, 'M', u'حي'), - (0xFD01, 'M', u'جى'), - (0xFD02, 'M', u'جي'), - (0xFD03, 'M', u'خى'), - (0xFD04, 'M', u'خي'), - (0xFD05, 'M', u'صى'), - (0xFD06, 'M', u'صي'), - (0xFD07, 'M', u'ضى'), - (0xFD08, 'M', u'ضي'), - (0xFD09, 'M', u'شج'), - (0xFD0A, 'M', u'شح'), - (0xFD0B, 'M', u'شخ'), - (0xFD0C, 'M', u'شم'), - (0xFD0D, 'M', u'شر'), - (0xFD0E, 'M', u'سر'), - (0xFD0F, 'M', u'صر'), - (0xFD10, 'M', u'ضر'), - (0xFD11, 'M', u'طى'), - (0xFD12, 'M', u'طي'), - (0xFD13, 'M', u'عى'), - (0xFD14, 'M', u'عي'), - (0xFD15, 'M', u'غى'), - (0xFD16, 'M', u'غي'), - (0xFD17, 'M', u'سى'), - (0xFD18, 'M', u'سي'), - (0xFD19, 'M', u'شى'), - (0xFD1A, 'M', u'شي'), - (0xFD1B, 'M', u'حى'), - (0xFD1C, 'M', u'حي'), - (0xFD1D, 'M', u'جى'), - (0xFD1E, 'M', u'جي'), - (0xFD1F, 'M', u'خى'), - (0xFD20, 'M', u'خي'), - (0xFD21, 'M', u'صى'), - (0xFD22, 'M', u'صي'), - (0xFD23, 'M', u'ضى'), - (0xFD24, 'M', u'ضي'), - (0xFD25, 'M', u'شج'), - (0xFD26, 'M', u'شح'), - (0xFD27, 'M', u'شخ'), - ] - -def _seg_48(): - return [ - (0xFD28, 'M', u'شم'), - (0xFD29, 'M', u'شر'), - (0xFD2A, 'M', u'سر'), - (0xFD2B, 'M', u'صر'), - (0xFD2C, 'M', u'ضر'), - (0xFD2D, 'M', u'شج'), - (0xFD2E, 'M', u'شح'), - (0xFD2F, 'M', u'شخ'), - (0xFD30, 'M', u'شم'), - (0xFD31, 'M', u'سه'), - (0xFD32, 'M', u'شه'), - (0xFD33, 'M', u'طم'), - (0xFD34, 'M', u'سج'), - (0xFD35, 'M', u'سح'), - (0xFD36, 'M', u'سخ'), - (0xFD37, 'M', u'شج'), - (0xFD38, 'M', u'شح'), - (0xFD39, 'M', u'شخ'), - (0xFD3A, 'M', u'طم'), - (0xFD3B, 'M', u'ظم'), - (0xFD3C, 'M', u'اً'), - (0xFD3E, 'V'), - (0xFD40, 'X'), - (0xFD50, 'M', u'تجم'), - (0xFD51, 'M', u'تحج'), - (0xFD53, 'M', u'تحم'), - (0xFD54, 'M', u'تخم'), - (0xFD55, 'M', u'تمج'), - (0xFD56, 'M', u'تمح'), - (0xFD57, 'M', u'تمخ'), - (0xFD58, 'M', u'جمح'), - (0xFD5A, 'M', u'حمي'), - (0xFD5B, 'M', u'حمى'), - (0xFD5C, 'M', u'سحج'), - (0xFD5D, 'M', u'سجح'), - (0xFD5E, 'M', u'سجى'), - (0xFD5F, 'M', u'سمح'), - (0xFD61, 'M', u'سمج'), - (0xFD62, 'M', u'سمم'), - (0xFD64, 'M', u'صحح'), - (0xFD66, 'M', u'صمم'), - (0xFD67, 'M', u'شحم'), - (0xFD69, 'M', u'شجي'), - (0xFD6A, 'M', u'شمخ'), - (0xFD6C, 'M', u'شمم'), - (0xFD6E, 'M', u'ضحى'), - (0xFD6F, 'M', u'ضخم'), - (0xFD71, 'M', u'طمح'), - (0xFD73, 'M', u'طمم'), - (0xFD74, 'M', u'طمي'), - (0xFD75, 'M', u'عجم'), - (0xFD76, 'M', u'عمم'), - (0xFD78, 'M', u'عمى'), - (0xFD79, 'M', u'غمم'), - (0xFD7A, 'M', u'غمي'), - (0xFD7B, 'M', u'غمى'), - (0xFD7C, 'M', u'فخم'), - (0xFD7E, 'M', u'قمح'), - (0xFD7F, 'M', u'قمم'), - (0xFD80, 'M', u'لحم'), - (0xFD81, 'M', u'لحي'), - (0xFD82, 'M', u'لحى'), - (0xFD83, 'M', u'لجج'), - (0xFD85, 'M', u'لخم'), - (0xFD87, 'M', u'لمح'), - (0xFD89, 'M', u'محج'), - (0xFD8A, 'M', u'محم'), - (0xFD8B, 'M', u'محي'), - (0xFD8C, 'M', u'مجح'), - (0xFD8D, 'M', u'مجم'), - (0xFD8E, 'M', u'مخج'), - (0xFD8F, 'M', u'مخم'), - (0xFD90, 'X'), - (0xFD92, 'M', u'مجخ'), - (0xFD93, 'M', u'همج'), - (0xFD94, 'M', u'همم'), - (0xFD95, 'M', u'نحم'), - (0xFD96, 'M', u'نحى'), - (0xFD97, 'M', u'نجم'), - (0xFD99, 'M', u'نجى'), - (0xFD9A, 'M', u'نمي'), - (0xFD9B, 'M', u'نمى'), - (0xFD9C, 'M', u'يمم'), - (0xFD9E, 'M', u'بخي'), - (0xFD9F, 'M', u'تجي'), - (0xFDA0, 'M', u'تجى'), - (0xFDA1, 'M', u'تخي'), - (0xFDA2, 'M', u'تخى'), - (0xFDA3, 'M', u'تمي'), - (0xFDA4, 'M', u'تمى'), - (0xFDA5, 'M', u'جمي'), - (0xFDA6, 'M', u'جحى'), - (0xFDA7, 'M', u'جمى'), - (0xFDA8, 'M', u'سخى'), - (0xFDA9, 'M', u'صحي'), - (0xFDAA, 'M', u'شحي'), - (0xFDAB, 'M', u'ضحي'), - (0xFDAC, 'M', u'لجي'), - (0xFDAD, 'M', u'لمي'), - (0xFDAE, 'M', u'يحي'), - ] - -def _seg_49(): - return [ - (0xFDAF, 'M', u'يجي'), - (0xFDB0, 'M', u'يمي'), - (0xFDB1, 'M', u'ممي'), - (0xFDB2, 'M', u'قمي'), - (0xFDB3, 'M', u'نحي'), - (0xFDB4, 'M', u'قمح'), - (0xFDB5, 'M', u'لحم'), - (0xFDB6, 'M', u'عمي'), - (0xFDB7, 'M', u'كمي'), - (0xFDB8, 'M', u'نجح'), - (0xFDB9, 'M', u'مخي'), - (0xFDBA, 'M', u'لجم'), - (0xFDBB, 'M', u'كمم'), - (0xFDBC, 'M', u'لجم'), - (0xFDBD, 'M', u'نجح'), - (0xFDBE, 'M', u'جحي'), - (0xFDBF, 'M', u'حجي'), - (0xFDC0, 'M', u'مجي'), - (0xFDC1, 'M', u'فمي'), - (0xFDC2, 'M', u'بحي'), - (0xFDC3, 'M', u'كمم'), - (0xFDC4, 'M', u'عجم'), - (0xFDC5, 'M', u'صمم'), - (0xFDC6, 'M', u'سخي'), - (0xFDC7, 'M', u'نجي'), - (0xFDC8, 'X'), - (0xFDF0, 'M', u'صلے'), - (0xFDF1, 'M', u'قلے'), - (0xFDF2, 'M', u'الله'), - (0xFDF3, 'M', u'اكبر'), - (0xFDF4, 'M', u'محمد'), - (0xFDF5, 'M', u'صلعم'), - (0xFDF6, 'M', u'رسول'), - (0xFDF7, 'M', u'عليه'), - (0xFDF8, 'M', u'وسلم'), - (0xFDF9, 'M', u'صلى'), - (0xFDFA, '3', u'صلى الله عليه وسلم'), - (0xFDFB, '3', u'جل جلاله'), - (0xFDFC, 'M', u'ریال'), - (0xFDFD, 'V'), - (0xFDFE, 'X'), - (0xFE00, 'I'), - (0xFE10, '3', u','), - (0xFE11, 'M', u'、'), - (0xFE12, 'X'), - (0xFE13, '3', u':'), - (0xFE14, '3', u';'), - (0xFE15, '3', u'!'), - (0xFE16, '3', u'?'), - (0xFE17, 'M', u'〖'), - (0xFE18, 'M', u'〗'), - (0xFE19, 'X'), - (0xFE20, 'V'), - (0xFE30, 'X'), - (0xFE31, 'M', u'—'), - (0xFE32, 'M', u'–'), - (0xFE33, '3', u'_'), - (0xFE35, '3', u'('), - (0xFE36, '3', u')'), - (0xFE37, '3', u'{'), - (0xFE38, '3', u'}'), - (0xFE39, 'M', u'〔'), - (0xFE3A, 'M', u'〕'), - (0xFE3B, 'M', u'【'), - (0xFE3C, 'M', u'】'), - (0xFE3D, 'M', u'《'), - (0xFE3E, 'M', u'》'), - (0xFE3F, 'M', u'〈'), - (0xFE40, 'M', u'〉'), - (0xFE41, 'M', u'「'), - (0xFE42, 'M', u'」'), - (0xFE43, 'M', u'『'), - (0xFE44, 'M', u'』'), - (0xFE45, 'V'), - (0xFE47, '3', u'['), - (0xFE48, '3', u']'), - (0xFE49, '3', u' ̅'), - (0xFE4D, '3', u'_'), - (0xFE50, '3', u','), - (0xFE51, 'M', u'、'), - (0xFE52, 'X'), - (0xFE54, '3', u';'), - (0xFE55, '3', u':'), - (0xFE56, '3', u'?'), - (0xFE57, '3', u'!'), - (0xFE58, 'M', u'—'), - (0xFE59, '3', u'('), - (0xFE5A, '3', u')'), - (0xFE5B, '3', u'{'), - (0xFE5C, '3', u'}'), - (0xFE5D, 'M', u'〔'), - (0xFE5E, 'M', u'〕'), - (0xFE5F, '3', u'#'), - (0xFE60, '3', u'&'), - (0xFE61, '3', u'*'), - (0xFE62, '3', u'+'), - (0xFE63, 'M', u'-'), - (0xFE64, '3', u'<'), - (0xFE65, '3', u'>'), - (0xFE66, '3', u'='), - ] - -def _seg_50(): - return [ - (0xFE67, 'X'), - (0xFE68, '3', u'\\'), - (0xFE69, '3', u'$'), - (0xFE6A, '3', u'%'), - (0xFE6B, '3', u'@'), - (0xFE6C, 'X'), - (0xFE70, '3', u' ً'), - (0xFE71, 'M', u'ـً'), - (0xFE72, '3', u' ٌ'), - (0xFE73, 'V'), - (0xFE74, '3', u' ٍ'), - (0xFE75, 'X'), - (0xFE76, '3', u' َ'), - (0xFE77, 'M', u'ـَ'), - (0xFE78, '3', u' ُ'), - (0xFE79, 'M', u'ـُ'), - (0xFE7A, '3', u' ِ'), - (0xFE7B, 'M', u'ـِ'), - (0xFE7C, '3', u' ّ'), - (0xFE7D, 'M', u'ـّ'), - (0xFE7E, '3', u' ْ'), - (0xFE7F, 'M', u'ـْ'), - (0xFE80, 'M', u'ء'), - (0xFE81, 'M', u'آ'), - (0xFE83, 'M', u'أ'), - (0xFE85, 'M', u'ؤ'), - (0xFE87, 'M', u'إ'), - (0xFE89, 'M', u'ئ'), - (0xFE8D, 'M', u'ا'), - (0xFE8F, 'M', u'ب'), - (0xFE93, 'M', u'ة'), - (0xFE95, 'M', u'ت'), - (0xFE99, 'M', u'ث'), - (0xFE9D, 'M', u'ج'), - (0xFEA1, 'M', u'ح'), - (0xFEA5, 'M', u'خ'), - (0xFEA9, 'M', u'د'), - (0xFEAB, 'M', u'ذ'), - (0xFEAD, 'M', u'ر'), - (0xFEAF, 'M', u'ز'), - (0xFEB1, 'M', u'س'), - (0xFEB5, 'M', u'ش'), - (0xFEB9, 'M', u'ص'), - (0xFEBD, 'M', u'ض'), - (0xFEC1, 'M', u'ط'), - (0xFEC5, 'M', u'ظ'), - (0xFEC9, 'M', u'ع'), - (0xFECD, 'M', u'غ'), - (0xFED1, 'M', u'ف'), - (0xFED5, 'M', u'ق'), - (0xFED9, 'M', u'ك'), - (0xFEDD, 'M', u'ل'), - (0xFEE1, 'M', u'م'), - (0xFEE5, 'M', u'ن'), - (0xFEE9, 'M', u'ه'), - (0xFEED, 'M', u'و'), - (0xFEEF, 'M', u'ى'), - (0xFEF1, 'M', u'ي'), - (0xFEF5, 'M', u'لآ'), - (0xFEF7, 'M', u'لأ'), - (0xFEF9, 'M', u'لإ'), - (0xFEFB, 'M', u'لا'), - (0xFEFD, 'X'), - (0xFEFF, 'I'), - (0xFF00, 'X'), - (0xFF01, '3', u'!'), - (0xFF02, '3', u'"'), - (0xFF03, '3', u'#'), - (0xFF04, '3', u'$'), - (0xFF05, '3', u'%'), - (0xFF06, '3', u'&'), - (0xFF07, '3', u'\''), - (0xFF08, '3', u'('), - (0xFF09, '3', u')'), - (0xFF0A, '3', u'*'), - (0xFF0B, '3', u'+'), - (0xFF0C, '3', u','), - (0xFF0D, 'M', u'-'), - (0xFF0E, 'M', u'.'), - (0xFF0F, '3', u'/'), - (0xFF10, 'M', u'0'), - (0xFF11, 'M', u'1'), - (0xFF12, 'M', u'2'), - (0xFF13, 'M', u'3'), - (0xFF14, 'M', u'4'), - (0xFF15, 'M', u'5'), - (0xFF16, 'M', u'6'), - (0xFF17, 'M', u'7'), - (0xFF18, 'M', u'8'), - (0xFF19, 'M', u'9'), - (0xFF1A, '3', u':'), - (0xFF1B, '3', u';'), - (0xFF1C, '3', u'<'), - (0xFF1D, '3', u'='), - (0xFF1E, '3', u'>'), - (0xFF1F, '3', u'?'), - (0xFF20, '3', u'@'), - (0xFF21, 'M', u'a'), - (0xFF22, 'M', u'b'), - (0xFF23, 'M', u'c'), - ] - -def _seg_51(): - return [ - (0xFF24, 'M', u'd'), - (0xFF25, 'M', u'e'), - (0xFF26, 'M', u'f'), - (0xFF27, 'M', u'g'), - (0xFF28, 'M', u'h'), - (0xFF29, 'M', u'i'), - (0xFF2A, 'M', u'j'), - (0xFF2B, 'M', u'k'), - (0xFF2C, 'M', u'l'), - (0xFF2D, 'M', u'm'), - (0xFF2E, 'M', u'n'), - (0xFF2F, 'M', u'o'), - (0xFF30, 'M', u'p'), - (0xFF31, 'M', u'q'), - (0xFF32, 'M', u'r'), - (0xFF33, 'M', u's'), - (0xFF34, 'M', u't'), - (0xFF35, 'M', u'u'), - (0xFF36, 'M', u'v'), - (0xFF37, 'M', u'w'), - (0xFF38, 'M', u'x'), - (0xFF39, 'M', u'y'), - (0xFF3A, 'M', u'z'), - (0xFF3B, '3', u'['), - (0xFF3C, '3', u'\\'), - (0xFF3D, '3', u']'), - (0xFF3E, '3', u'^'), - (0xFF3F, '3', u'_'), - (0xFF40, '3', u'`'), - (0xFF41, 'M', u'a'), - (0xFF42, 'M', u'b'), - (0xFF43, 'M', u'c'), - (0xFF44, 'M', u'd'), - (0xFF45, 'M', u'e'), - (0xFF46, 'M', u'f'), - (0xFF47, 'M', u'g'), - (0xFF48, 'M', u'h'), - (0xFF49, 'M', u'i'), - (0xFF4A, 'M', u'j'), - (0xFF4B, 'M', u'k'), - (0xFF4C, 'M', u'l'), - (0xFF4D, 'M', u'm'), - (0xFF4E, 'M', u'n'), - (0xFF4F, 'M', u'o'), - (0xFF50, 'M', u'p'), - (0xFF51, 'M', u'q'), - (0xFF52, 'M', u'r'), - (0xFF53, 'M', u's'), - (0xFF54, 'M', u't'), - (0xFF55, 'M', u'u'), - (0xFF56, 'M', u'v'), - (0xFF57, 'M', u'w'), - (0xFF58, 'M', u'x'), - (0xFF59, 'M', u'y'), - (0xFF5A, 'M', u'z'), - (0xFF5B, '3', u'{'), - (0xFF5C, '3', u'|'), - (0xFF5D, '3', u'}'), - (0xFF5E, '3', u'~'), - (0xFF5F, 'M', u'⦅'), - (0xFF60, 'M', u'⦆'), - (0xFF61, 'M', u'.'), - (0xFF62, 'M', u'「'), - (0xFF63, 'M', u'」'), - (0xFF64, 'M', u'、'), - (0xFF65, 'M', u'・'), - (0xFF66, 'M', u'ヲ'), - (0xFF67, 'M', u'ァ'), - (0xFF68, 'M', u'ィ'), - (0xFF69, 'M', u'ゥ'), - (0xFF6A, 'M', u'ェ'), - (0xFF6B, 'M', u'ォ'), - (0xFF6C, 'M', u'ャ'), - (0xFF6D, 'M', u'ュ'), - (0xFF6E, 'M', u'ョ'), - (0xFF6F, 'M', u'ッ'), - (0xFF70, 'M', u'ー'), - (0xFF71, 'M', u'ア'), - (0xFF72, 'M', u'イ'), - (0xFF73, 'M', u'ウ'), - (0xFF74, 'M', u'エ'), - (0xFF75, 'M', u'オ'), - (0xFF76, 'M', u'カ'), - (0xFF77, 'M', u'キ'), - (0xFF78, 'M', u'ク'), - (0xFF79, 'M', u'ケ'), - (0xFF7A, 'M', u'コ'), - (0xFF7B, 'M', u'サ'), - (0xFF7C, 'M', u'シ'), - (0xFF7D, 'M', u'ス'), - (0xFF7E, 'M', u'セ'), - (0xFF7F, 'M', u'ソ'), - (0xFF80, 'M', u'タ'), - (0xFF81, 'M', u'チ'), - (0xFF82, 'M', u'ツ'), - (0xFF83, 'M', u'テ'), - (0xFF84, 'M', u'ト'), - (0xFF85, 'M', u'ナ'), - (0xFF86, 'M', u'ニ'), - (0xFF87, 'M', u'ヌ'), - ] - -def _seg_52(): - return [ - (0xFF88, 'M', u'ネ'), - (0xFF89, 'M', u'ノ'), - (0xFF8A, 'M', u'ハ'), - (0xFF8B, 'M', u'ヒ'), - (0xFF8C, 'M', u'フ'), - (0xFF8D, 'M', u'ヘ'), - (0xFF8E, 'M', u'ホ'), - (0xFF8F, 'M', u'マ'), - (0xFF90, 'M', u'ミ'), - (0xFF91, 'M', u'ム'), - (0xFF92, 'M', u'メ'), - (0xFF93, 'M', u'モ'), - (0xFF94, 'M', u'ヤ'), - (0xFF95, 'M', u'ユ'), - (0xFF96, 'M', u'ヨ'), - (0xFF97, 'M', u'ラ'), - (0xFF98, 'M', u'リ'), - (0xFF99, 'M', u'ル'), - (0xFF9A, 'M', u'レ'), - (0xFF9B, 'M', u'ロ'), - (0xFF9C, 'M', u'ワ'), - (0xFF9D, 'M', u'ン'), - (0xFF9E, 'M', u'゙'), - (0xFF9F, 'M', u'゚'), - (0xFFA0, 'X'), - (0xFFA1, 'M', u'ᄀ'), - (0xFFA2, 'M', u'ᄁ'), - (0xFFA3, 'M', u'ᆪ'), - (0xFFA4, 'M', u'ᄂ'), - (0xFFA5, 'M', u'ᆬ'), - (0xFFA6, 'M', u'ᆭ'), - (0xFFA7, 'M', u'ᄃ'), - (0xFFA8, 'M', u'ᄄ'), - (0xFFA9, 'M', u'ᄅ'), - (0xFFAA, 'M', u'ᆰ'), - (0xFFAB, 'M', u'ᆱ'), - (0xFFAC, 'M', u'ᆲ'), - (0xFFAD, 'M', u'ᆳ'), - (0xFFAE, 'M', u'ᆴ'), - (0xFFAF, 'M', u'ᆵ'), - (0xFFB0, 'M', u'ᄚ'), - (0xFFB1, 'M', u'ᄆ'), - (0xFFB2, 'M', u'ᄇ'), - (0xFFB3, 'M', u'ᄈ'), - (0xFFB4, 'M', u'ᄡ'), - (0xFFB5, 'M', u'ᄉ'), - (0xFFB6, 'M', u'ᄊ'), - (0xFFB7, 'M', u'ᄋ'), - (0xFFB8, 'M', u'ᄌ'), - (0xFFB9, 'M', u'ᄍ'), - (0xFFBA, 'M', u'ᄎ'), - (0xFFBB, 'M', u'ᄏ'), - (0xFFBC, 'M', u'ᄐ'), - (0xFFBD, 'M', u'ᄑ'), - (0xFFBE, 'M', u'ᄒ'), - (0xFFBF, 'X'), - (0xFFC2, 'M', u'ᅡ'), - (0xFFC3, 'M', u'ᅢ'), - (0xFFC4, 'M', u'ᅣ'), - (0xFFC5, 'M', u'ᅤ'), - (0xFFC6, 'M', u'ᅥ'), - (0xFFC7, 'M', u'ᅦ'), - (0xFFC8, 'X'), - (0xFFCA, 'M', u'ᅧ'), - (0xFFCB, 'M', u'ᅨ'), - (0xFFCC, 'M', u'ᅩ'), - (0xFFCD, 'M', u'ᅪ'), - (0xFFCE, 'M', u'ᅫ'), - (0xFFCF, 'M', u'ᅬ'), - (0xFFD0, 'X'), - (0xFFD2, 'M', u'ᅭ'), - (0xFFD3, 'M', u'ᅮ'), - (0xFFD4, 'M', u'ᅯ'), - (0xFFD5, 'M', u'ᅰ'), - (0xFFD6, 'M', u'ᅱ'), - (0xFFD7, 'M', u'ᅲ'), - (0xFFD8, 'X'), - (0xFFDA, 'M', u'ᅳ'), - (0xFFDB, 'M', u'ᅴ'), - (0xFFDC, 'M', u'ᅵ'), - (0xFFDD, 'X'), - (0xFFE0, 'M', u'¢'), - (0xFFE1, 'M', u'£'), - (0xFFE2, 'M', u'¬'), - (0xFFE3, '3', u' ̄'), - (0xFFE4, 'M', u'¦'), - (0xFFE5, 'M', u'¥'), - (0xFFE6, 'M', u'₩'), - (0xFFE7, 'X'), - (0xFFE8, 'M', u'│'), - (0xFFE9, 'M', u'←'), - (0xFFEA, 'M', u'↑'), - (0xFFEB, 'M', u'→'), - (0xFFEC, 'M', u'↓'), - (0xFFED, 'M', u'■'), - (0xFFEE, 'M', u'○'), - (0xFFEF, 'X'), - (0x10000, 'V'), - (0x1000C, 'X'), - (0x1000D, 'V'), - ] - -def _seg_53(): - return [ - (0x10027, 'X'), - (0x10028, 'V'), - (0x1003B, 'X'), - (0x1003C, 'V'), - (0x1003E, 'X'), - (0x1003F, 'V'), - (0x1004E, 'X'), - (0x10050, 'V'), - (0x1005E, 'X'), - (0x10080, 'V'), - (0x100FB, 'X'), - (0x10100, 'V'), - (0x10103, 'X'), - (0x10107, 'V'), - (0x10134, 'X'), - (0x10137, 'V'), - (0x1018F, 'X'), - (0x10190, 'V'), - (0x1019D, 'X'), - (0x101A0, 'V'), - (0x101A1, 'X'), - (0x101D0, 'V'), - (0x101FE, 'X'), - (0x10280, 'V'), - (0x1029D, 'X'), - (0x102A0, 'V'), - (0x102D1, 'X'), - (0x102E0, 'V'), - (0x102FC, 'X'), - (0x10300, 'V'), - (0x10324, 'X'), - (0x1032D, 'V'), - (0x1034B, 'X'), - (0x10350, 'V'), - (0x1037B, 'X'), - (0x10380, 'V'), - (0x1039E, 'X'), - (0x1039F, 'V'), - (0x103C4, 'X'), - (0x103C8, 'V'), - (0x103D6, 'X'), - (0x10400, 'M', u'𐐨'), - (0x10401, 'M', u'𐐩'), - (0x10402, 'M', u'𐐪'), - (0x10403, 'M', u'𐐫'), - (0x10404, 'M', u'𐐬'), - (0x10405, 'M', u'𐐭'), - (0x10406, 'M', u'𐐮'), - (0x10407, 'M', u'𐐯'), - (0x10408, 'M', u'𐐰'), - (0x10409, 'M', u'𐐱'), - (0x1040A, 'M', u'𐐲'), - (0x1040B, 'M', u'𐐳'), - (0x1040C, 'M', u'𐐴'), - (0x1040D, 'M', u'𐐵'), - (0x1040E, 'M', u'𐐶'), - (0x1040F, 'M', u'𐐷'), - (0x10410, 'M', u'𐐸'), - (0x10411, 'M', u'𐐹'), - (0x10412, 'M', u'𐐺'), - (0x10413, 'M', u'𐐻'), - (0x10414, 'M', u'𐐼'), - (0x10415, 'M', u'𐐽'), - (0x10416, 'M', u'𐐾'), - (0x10417, 'M', u'𐐿'), - (0x10418, 'M', u'𐑀'), - (0x10419, 'M', u'𐑁'), - (0x1041A, 'M', u'𐑂'), - (0x1041B, 'M', u'𐑃'), - (0x1041C, 'M', u'𐑄'), - (0x1041D, 'M', u'𐑅'), - (0x1041E, 'M', u'𐑆'), - (0x1041F, 'M', u'𐑇'), - (0x10420, 'M', u'𐑈'), - (0x10421, 'M', u'𐑉'), - (0x10422, 'M', u'𐑊'), - (0x10423, 'M', u'𐑋'), - (0x10424, 'M', u'𐑌'), - (0x10425, 'M', u'𐑍'), - (0x10426, 'M', u'𐑎'), - (0x10427, 'M', u'𐑏'), - (0x10428, 'V'), - (0x1049E, 'X'), - (0x104A0, 'V'), - (0x104AA, 'X'), - (0x104B0, 'M', u'𐓘'), - (0x104B1, 'M', u'𐓙'), - (0x104B2, 'M', u'𐓚'), - (0x104B3, 'M', u'𐓛'), - (0x104B4, 'M', u'𐓜'), - (0x104B5, 'M', u'𐓝'), - (0x104B6, 'M', u'𐓞'), - (0x104B7, 'M', u'𐓟'), - (0x104B8, 'M', u'𐓠'), - (0x104B9, 'M', u'𐓡'), - (0x104BA, 'M', u'𐓢'), - (0x104BB, 'M', u'𐓣'), - (0x104BC, 'M', u'𐓤'), - (0x104BD, 'M', u'𐓥'), - (0x104BE, 'M', u'𐓦'), - ] - -def _seg_54(): - return [ - (0x104BF, 'M', u'𐓧'), - (0x104C0, 'M', u'𐓨'), - (0x104C1, 'M', u'𐓩'), - (0x104C2, 'M', u'𐓪'), - (0x104C3, 'M', u'𐓫'), - (0x104C4, 'M', u'𐓬'), - (0x104C5, 'M', u'𐓭'), - (0x104C6, 'M', u'𐓮'), - (0x104C7, 'M', u'𐓯'), - (0x104C8, 'M', u'𐓰'), - (0x104C9, 'M', u'𐓱'), - (0x104CA, 'M', u'𐓲'), - (0x104CB, 'M', u'𐓳'), - (0x104CC, 'M', u'𐓴'), - (0x104CD, 'M', u'𐓵'), - (0x104CE, 'M', u'𐓶'), - (0x104CF, 'M', u'𐓷'), - (0x104D0, 'M', u'𐓸'), - (0x104D1, 'M', u'𐓹'), - (0x104D2, 'M', u'𐓺'), - (0x104D3, 'M', u'𐓻'), - (0x104D4, 'X'), - (0x104D8, 'V'), - (0x104FC, 'X'), - (0x10500, 'V'), - (0x10528, 'X'), - (0x10530, 'V'), - (0x10564, 'X'), - (0x1056F, 'V'), - (0x10570, 'X'), - (0x10600, 'V'), - (0x10737, 'X'), - (0x10740, 'V'), - (0x10756, 'X'), - (0x10760, 'V'), - (0x10768, 'X'), - (0x10800, 'V'), - (0x10806, 'X'), - (0x10808, 'V'), - (0x10809, 'X'), - (0x1080A, 'V'), - (0x10836, 'X'), - (0x10837, 'V'), - (0x10839, 'X'), - (0x1083C, 'V'), - (0x1083D, 'X'), - (0x1083F, 'V'), - (0x10856, 'X'), - (0x10857, 'V'), - (0x1089F, 'X'), - (0x108A7, 'V'), - (0x108B0, 'X'), - (0x108E0, 'V'), - (0x108F3, 'X'), - (0x108F4, 'V'), - (0x108F6, 'X'), - (0x108FB, 'V'), - (0x1091C, 'X'), - (0x1091F, 'V'), - (0x1093A, 'X'), - (0x1093F, 'V'), - (0x10940, 'X'), - (0x10980, 'V'), - (0x109B8, 'X'), - (0x109BC, 'V'), - (0x109D0, 'X'), - (0x109D2, 'V'), - (0x10A04, 'X'), - (0x10A05, 'V'), - (0x10A07, 'X'), - (0x10A0C, 'V'), - (0x10A14, 'X'), - (0x10A15, 'V'), - (0x10A18, 'X'), - (0x10A19, 'V'), - (0x10A36, 'X'), - (0x10A38, 'V'), - (0x10A3B, 'X'), - (0x10A3F, 'V'), - (0x10A49, 'X'), - (0x10A50, 'V'), - (0x10A59, 'X'), - (0x10A60, 'V'), - (0x10AA0, 'X'), - (0x10AC0, 'V'), - (0x10AE7, 'X'), - (0x10AEB, 'V'), - (0x10AF7, 'X'), - (0x10B00, 'V'), - (0x10B36, 'X'), - (0x10B39, 'V'), - (0x10B56, 'X'), - (0x10B58, 'V'), - (0x10B73, 'X'), - (0x10B78, 'V'), - (0x10B92, 'X'), - (0x10B99, 'V'), - (0x10B9D, 'X'), - (0x10BA9, 'V'), - (0x10BB0, 'X'), - ] - -def _seg_55(): - return [ - (0x10C00, 'V'), - (0x10C49, 'X'), - (0x10C80, 'M', u'𐳀'), - (0x10C81, 'M', u'𐳁'), - (0x10C82, 'M', u'𐳂'), - (0x10C83, 'M', u'𐳃'), - (0x10C84, 'M', u'𐳄'), - (0x10C85, 'M', u'𐳅'), - (0x10C86, 'M', u'𐳆'), - (0x10C87, 'M', u'𐳇'), - (0x10C88, 'M', u'𐳈'), - (0x10C89, 'M', u'𐳉'), - (0x10C8A, 'M', u'𐳊'), - (0x10C8B, 'M', u'𐳋'), - (0x10C8C, 'M', u'𐳌'), - (0x10C8D, 'M', u'𐳍'), - (0x10C8E, 'M', u'𐳎'), - (0x10C8F, 'M', u'𐳏'), - (0x10C90, 'M', u'𐳐'), - (0x10C91, 'M', u'𐳑'), - (0x10C92, 'M', u'𐳒'), - (0x10C93, 'M', u'𐳓'), - (0x10C94, 'M', u'𐳔'), - (0x10C95, 'M', u'𐳕'), - (0x10C96, 'M', u'𐳖'), - (0x10C97, 'M', u'𐳗'), - (0x10C98, 'M', u'𐳘'), - (0x10C99, 'M', u'𐳙'), - (0x10C9A, 'M', u'𐳚'), - (0x10C9B, 'M', u'𐳛'), - (0x10C9C, 'M', u'𐳜'), - (0x10C9D, 'M', u'𐳝'), - (0x10C9E, 'M', u'𐳞'), - (0x10C9F, 'M', u'𐳟'), - (0x10CA0, 'M', u'𐳠'), - (0x10CA1, 'M', u'𐳡'), - (0x10CA2, 'M', u'𐳢'), - (0x10CA3, 'M', u'𐳣'), - (0x10CA4, 'M', u'𐳤'), - (0x10CA5, 'M', u'𐳥'), - (0x10CA6, 'M', u'𐳦'), - (0x10CA7, 'M', u'𐳧'), - (0x10CA8, 'M', u'𐳨'), - (0x10CA9, 'M', u'𐳩'), - (0x10CAA, 'M', u'𐳪'), - (0x10CAB, 'M', u'𐳫'), - (0x10CAC, 'M', u'𐳬'), - (0x10CAD, 'M', u'𐳭'), - (0x10CAE, 'M', u'𐳮'), - (0x10CAF, 'M', u'𐳯'), - (0x10CB0, 'M', u'𐳰'), - (0x10CB1, 'M', u'𐳱'), - (0x10CB2, 'M', u'𐳲'), - (0x10CB3, 'X'), - (0x10CC0, 'V'), - (0x10CF3, 'X'), - (0x10CFA, 'V'), - (0x10D28, 'X'), - (0x10D30, 'V'), - (0x10D3A, 'X'), - (0x10E60, 'V'), - (0x10E7F, 'X'), - (0x10E80, 'V'), - (0x10EAA, 'X'), - (0x10EAB, 'V'), - (0x10EAE, 'X'), - (0x10EB0, 'V'), - (0x10EB2, 'X'), - (0x10F00, 'V'), - (0x10F28, 'X'), - (0x10F30, 'V'), - (0x10F5A, 'X'), - (0x10FB0, 'V'), - (0x10FCC, 'X'), - (0x10FE0, 'V'), - (0x10FF7, 'X'), - (0x11000, 'V'), - (0x1104E, 'X'), - (0x11052, 'V'), - (0x11070, 'X'), - (0x1107F, 'V'), - (0x110BD, 'X'), - (0x110BE, 'V'), - (0x110C2, 'X'), - (0x110D0, 'V'), - (0x110E9, 'X'), - (0x110F0, 'V'), - (0x110FA, 'X'), - (0x11100, 'V'), - (0x11135, 'X'), - (0x11136, 'V'), - (0x11148, 'X'), - (0x11150, 'V'), - (0x11177, 'X'), - (0x11180, 'V'), - (0x111E0, 'X'), - (0x111E1, 'V'), - (0x111F5, 'X'), - (0x11200, 'V'), - (0x11212, 'X'), - ] - -def _seg_56(): - return [ - (0x11213, 'V'), - (0x1123F, 'X'), - (0x11280, 'V'), - (0x11287, 'X'), - (0x11288, 'V'), - (0x11289, 'X'), - (0x1128A, 'V'), - (0x1128E, 'X'), - (0x1128F, 'V'), - (0x1129E, 'X'), - (0x1129F, 'V'), - (0x112AA, 'X'), - (0x112B0, 'V'), - (0x112EB, 'X'), - (0x112F0, 'V'), - (0x112FA, 'X'), - (0x11300, 'V'), - (0x11304, 'X'), - (0x11305, 'V'), - (0x1130D, 'X'), - (0x1130F, 'V'), - (0x11311, 'X'), - (0x11313, 'V'), - (0x11329, 'X'), - (0x1132A, 'V'), - (0x11331, 'X'), - (0x11332, 'V'), - (0x11334, 'X'), - (0x11335, 'V'), - (0x1133A, 'X'), - (0x1133B, 'V'), - (0x11345, 'X'), - (0x11347, 'V'), - (0x11349, 'X'), - (0x1134B, 'V'), - (0x1134E, 'X'), - (0x11350, 'V'), - (0x11351, 'X'), - (0x11357, 'V'), - (0x11358, 'X'), - (0x1135D, 'V'), - (0x11364, 'X'), - (0x11366, 'V'), - (0x1136D, 'X'), - (0x11370, 'V'), - (0x11375, 'X'), - (0x11400, 'V'), - (0x1145C, 'X'), - (0x1145D, 'V'), - (0x11462, 'X'), - (0x11480, 'V'), - (0x114C8, 'X'), - (0x114D0, 'V'), - (0x114DA, 'X'), - (0x11580, 'V'), - (0x115B6, 'X'), - (0x115B8, 'V'), - (0x115DE, 'X'), - (0x11600, 'V'), - (0x11645, 'X'), - (0x11650, 'V'), - (0x1165A, 'X'), - (0x11660, 'V'), - (0x1166D, 'X'), - (0x11680, 'V'), - (0x116B9, 'X'), - (0x116C0, 'V'), - (0x116CA, 'X'), - (0x11700, 'V'), - (0x1171B, 'X'), - (0x1171D, 'V'), - (0x1172C, 'X'), - (0x11730, 'V'), - (0x11740, 'X'), - (0x11800, 'V'), - (0x1183C, 'X'), - (0x118A0, 'M', u'𑣀'), - (0x118A1, 'M', u'𑣁'), - (0x118A2, 'M', u'𑣂'), - (0x118A3, 'M', u'𑣃'), - (0x118A4, 'M', u'𑣄'), - (0x118A5, 'M', u'𑣅'), - (0x118A6, 'M', u'𑣆'), - (0x118A7, 'M', u'𑣇'), - (0x118A8, 'M', u'𑣈'), - (0x118A9, 'M', u'𑣉'), - (0x118AA, 'M', u'𑣊'), - (0x118AB, 'M', u'𑣋'), - (0x118AC, 'M', u'𑣌'), - (0x118AD, 'M', u'𑣍'), - (0x118AE, 'M', u'𑣎'), - (0x118AF, 'M', u'𑣏'), - (0x118B0, 'M', u'𑣐'), - (0x118B1, 'M', u'𑣑'), - (0x118B2, 'M', u'𑣒'), - (0x118B3, 'M', u'𑣓'), - (0x118B4, 'M', u'𑣔'), - (0x118B5, 'M', u'𑣕'), - (0x118B6, 'M', u'𑣖'), - (0x118B7, 'M', u'𑣗'), - ] - -def _seg_57(): - return [ - (0x118B8, 'M', u'𑣘'), - (0x118B9, 'M', u'𑣙'), - (0x118BA, 'M', u'𑣚'), - (0x118BB, 'M', u'𑣛'), - (0x118BC, 'M', u'𑣜'), - (0x118BD, 'M', u'𑣝'), - (0x118BE, 'M', u'𑣞'), - (0x118BF, 'M', u'𑣟'), - (0x118C0, 'V'), - (0x118F3, 'X'), - (0x118FF, 'V'), - (0x11907, 'X'), - (0x11909, 'V'), - (0x1190A, 'X'), - (0x1190C, 'V'), - (0x11914, 'X'), - (0x11915, 'V'), - (0x11917, 'X'), - (0x11918, 'V'), - (0x11936, 'X'), - (0x11937, 'V'), - (0x11939, 'X'), - (0x1193B, 'V'), - (0x11947, 'X'), - (0x11950, 'V'), - (0x1195A, 'X'), - (0x119A0, 'V'), - (0x119A8, 'X'), - (0x119AA, 'V'), - (0x119D8, 'X'), - (0x119DA, 'V'), - (0x119E5, 'X'), - (0x11A00, 'V'), - (0x11A48, 'X'), - (0x11A50, 'V'), - (0x11AA3, 'X'), - (0x11AC0, 'V'), - (0x11AF9, 'X'), - (0x11C00, 'V'), - (0x11C09, 'X'), - (0x11C0A, 'V'), - (0x11C37, 'X'), - (0x11C38, 'V'), - (0x11C46, 'X'), - (0x11C50, 'V'), - (0x11C6D, 'X'), - (0x11C70, 'V'), - (0x11C90, 'X'), - (0x11C92, 'V'), - (0x11CA8, 'X'), - (0x11CA9, 'V'), - (0x11CB7, 'X'), - (0x11D00, 'V'), - (0x11D07, 'X'), - (0x11D08, 'V'), - (0x11D0A, 'X'), - (0x11D0B, 'V'), - (0x11D37, 'X'), - (0x11D3A, 'V'), - (0x11D3B, 'X'), - (0x11D3C, 'V'), - (0x11D3E, 'X'), - (0x11D3F, 'V'), - (0x11D48, 'X'), - (0x11D50, 'V'), - (0x11D5A, 'X'), - (0x11D60, 'V'), - (0x11D66, 'X'), - (0x11D67, 'V'), - (0x11D69, 'X'), - (0x11D6A, 'V'), - (0x11D8F, 'X'), - (0x11D90, 'V'), - (0x11D92, 'X'), - (0x11D93, 'V'), - (0x11D99, 'X'), - (0x11DA0, 'V'), - (0x11DAA, 'X'), - (0x11EE0, 'V'), - (0x11EF9, 'X'), - (0x11FB0, 'V'), - (0x11FB1, 'X'), - (0x11FC0, 'V'), - (0x11FF2, 'X'), - (0x11FFF, 'V'), - (0x1239A, 'X'), - (0x12400, 'V'), - (0x1246F, 'X'), - (0x12470, 'V'), - (0x12475, 'X'), - (0x12480, 'V'), - (0x12544, 'X'), - (0x13000, 'V'), - (0x1342F, 'X'), - (0x14400, 'V'), - (0x14647, 'X'), - (0x16800, 'V'), - (0x16A39, 'X'), - (0x16A40, 'V'), - (0x16A5F, 'X'), - ] - -def _seg_58(): - return [ - (0x16A60, 'V'), - (0x16A6A, 'X'), - (0x16A6E, 'V'), - (0x16A70, 'X'), - (0x16AD0, 'V'), - (0x16AEE, 'X'), - (0x16AF0, 'V'), - (0x16AF6, 'X'), - (0x16B00, 'V'), - (0x16B46, 'X'), - (0x16B50, 'V'), - (0x16B5A, 'X'), - (0x16B5B, 'V'), - (0x16B62, 'X'), - (0x16B63, 'V'), - (0x16B78, 'X'), - (0x16B7D, 'V'), - (0x16B90, 'X'), - (0x16E40, 'M', u'𖹠'), - (0x16E41, 'M', u'𖹡'), - (0x16E42, 'M', u'𖹢'), - (0x16E43, 'M', u'𖹣'), - (0x16E44, 'M', u'𖹤'), - (0x16E45, 'M', u'𖹥'), - (0x16E46, 'M', u'𖹦'), - (0x16E47, 'M', u'𖹧'), - (0x16E48, 'M', u'𖹨'), - (0x16E49, 'M', u'𖹩'), - (0x16E4A, 'M', u'𖹪'), - (0x16E4B, 'M', u'𖹫'), - (0x16E4C, 'M', u'𖹬'), - (0x16E4D, 'M', u'𖹭'), - (0x16E4E, 'M', u'𖹮'), - (0x16E4F, 'M', u'𖹯'), - (0x16E50, 'M', u'𖹰'), - (0x16E51, 'M', u'𖹱'), - (0x16E52, 'M', u'𖹲'), - (0x16E53, 'M', u'𖹳'), - (0x16E54, 'M', u'𖹴'), - (0x16E55, 'M', u'𖹵'), - (0x16E56, 'M', u'𖹶'), - (0x16E57, 'M', u'𖹷'), - (0x16E58, 'M', u'𖹸'), - (0x16E59, 'M', u'𖹹'), - (0x16E5A, 'M', u'𖹺'), - (0x16E5B, 'M', u'𖹻'), - (0x16E5C, 'M', u'𖹼'), - (0x16E5D, 'M', u'𖹽'), - (0x16E5E, 'M', u'𖹾'), - (0x16E5F, 'M', u'𖹿'), - (0x16E60, 'V'), - (0x16E9B, 'X'), - (0x16F00, 'V'), - (0x16F4B, 'X'), - (0x16F4F, 'V'), - (0x16F88, 'X'), - (0x16F8F, 'V'), - (0x16FA0, 'X'), - (0x16FE0, 'V'), - (0x16FE5, 'X'), - (0x16FF0, 'V'), - (0x16FF2, 'X'), - (0x17000, 'V'), - (0x187F8, 'X'), - (0x18800, 'V'), - (0x18CD6, 'X'), - (0x18D00, 'V'), - (0x18D09, 'X'), - (0x1B000, 'V'), - (0x1B11F, 'X'), - (0x1B150, 'V'), - (0x1B153, 'X'), - (0x1B164, 'V'), - (0x1B168, 'X'), - (0x1B170, 'V'), - (0x1B2FC, 'X'), - (0x1BC00, 'V'), - (0x1BC6B, 'X'), - (0x1BC70, 'V'), - (0x1BC7D, 'X'), - (0x1BC80, 'V'), - (0x1BC89, 'X'), - (0x1BC90, 'V'), - (0x1BC9A, 'X'), - (0x1BC9C, 'V'), - (0x1BCA0, 'I'), - (0x1BCA4, 'X'), - (0x1D000, 'V'), - (0x1D0F6, 'X'), - (0x1D100, 'V'), - (0x1D127, 'X'), - (0x1D129, 'V'), - (0x1D15E, 'M', u'𝅗𝅥'), - (0x1D15F, 'M', u'𝅘𝅥'), - (0x1D160, 'M', u'𝅘𝅥𝅮'), - (0x1D161, 'M', u'𝅘𝅥𝅯'), - (0x1D162, 'M', u'𝅘𝅥𝅰'), - (0x1D163, 'M', u'𝅘𝅥𝅱'), - (0x1D164, 'M', u'𝅘𝅥𝅲'), - (0x1D165, 'V'), - ] - -def _seg_59(): - return [ - (0x1D173, 'X'), - (0x1D17B, 'V'), - (0x1D1BB, 'M', u'𝆹𝅥'), - (0x1D1BC, 'M', u'𝆺𝅥'), - (0x1D1BD, 'M', u'𝆹𝅥𝅮'), - (0x1D1BE, 'M', u'𝆺𝅥𝅮'), - (0x1D1BF, 'M', u'𝆹𝅥𝅯'), - (0x1D1C0, 'M', u'𝆺𝅥𝅯'), - (0x1D1C1, 'V'), - (0x1D1E9, 'X'), - (0x1D200, 'V'), - (0x1D246, 'X'), - (0x1D2E0, 'V'), - (0x1D2F4, 'X'), - (0x1D300, 'V'), - (0x1D357, 'X'), - (0x1D360, 'V'), - (0x1D379, 'X'), - (0x1D400, 'M', u'a'), - (0x1D401, 'M', u'b'), - (0x1D402, 'M', u'c'), - (0x1D403, 'M', u'd'), - (0x1D404, 'M', u'e'), - (0x1D405, 'M', u'f'), - (0x1D406, 'M', u'g'), - (0x1D407, 'M', u'h'), - (0x1D408, 'M', u'i'), - (0x1D409, 'M', u'j'), - (0x1D40A, 'M', u'k'), - (0x1D40B, 'M', u'l'), - (0x1D40C, 'M', u'm'), - (0x1D40D, 'M', u'n'), - (0x1D40E, 'M', u'o'), - (0x1D40F, 'M', u'p'), - (0x1D410, 'M', u'q'), - (0x1D411, 'M', u'r'), - (0x1D412, 'M', u's'), - (0x1D413, 'M', u't'), - (0x1D414, 'M', u'u'), - (0x1D415, 'M', u'v'), - (0x1D416, 'M', u'w'), - (0x1D417, 'M', u'x'), - (0x1D418, 'M', u'y'), - (0x1D419, 'M', u'z'), - (0x1D41A, 'M', u'a'), - (0x1D41B, 'M', u'b'), - (0x1D41C, 'M', u'c'), - (0x1D41D, 'M', u'd'), - (0x1D41E, 'M', u'e'), - (0x1D41F, 'M', u'f'), - (0x1D420, 'M', u'g'), - (0x1D421, 'M', u'h'), - (0x1D422, 'M', u'i'), - (0x1D423, 'M', u'j'), - (0x1D424, 'M', u'k'), - (0x1D425, 'M', u'l'), - (0x1D426, 'M', u'm'), - (0x1D427, 'M', u'n'), - (0x1D428, 'M', u'o'), - (0x1D429, 'M', u'p'), - (0x1D42A, 'M', u'q'), - (0x1D42B, 'M', u'r'), - (0x1D42C, 'M', u's'), - (0x1D42D, 'M', u't'), - (0x1D42E, 'M', u'u'), - (0x1D42F, 'M', u'v'), - (0x1D430, 'M', u'w'), - (0x1D431, 'M', u'x'), - (0x1D432, 'M', u'y'), - (0x1D433, 'M', u'z'), - (0x1D434, 'M', u'a'), - (0x1D435, 'M', u'b'), - (0x1D436, 'M', u'c'), - (0x1D437, 'M', u'd'), - (0x1D438, 'M', u'e'), - (0x1D439, 'M', u'f'), - (0x1D43A, 'M', u'g'), - (0x1D43B, 'M', u'h'), - (0x1D43C, 'M', u'i'), - (0x1D43D, 'M', u'j'), - (0x1D43E, 'M', u'k'), - (0x1D43F, 'M', u'l'), - (0x1D440, 'M', u'm'), - (0x1D441, 'M', u'n'), - (0x1D442, 'M', u'o'), - (0x1D443, 'M', u'p'), - (0x1D444, 'M', u'q'), - (0x1D445, 'M', u'r'), - (0x1D446, 'M', u's'), - (0x1D447, 'M', u't'), - (0x1D448, 'M', u'u'), - (0x1D449, 'M', u'v'), - (0x1D44A, 'M', u'w'), - (0x1D44B, 'M', u'x'), - (0x1D44C, 'M', u'y'), - (0x1D44D, 'M', u'z'), - (0x1D44E, 'M', u'a'), - (0x1D44F, 'M', u'b'), - (0x1D450, 'M', u'c'), - (0x1D451, 'M', u'd'), - ] - -def _seg_60(): - return [ - (0x1D452, 'M', u'e'), - (0x1D453, 'M', u'f'), - (0x1D454, 'M', u'g'), - (0x1D455, 'X'), - (0x1D456, 'M', u'i'), - (0x1D457, 'M', u'j'), - (0x1D458, 'M', u'k'), - (0x1D459, 'M', u'l'), - (0x1D45A, 'M', u'm'), - (0x1D45B, 'M', u'n'), - (0x1D45C, 'M', u'o'), - (0x1D45D, 'M', u'p'), - (0x1D45E, 'M', u'q'), - (0x1D45F, 'M', u'r'), - (0x1D460, 'M', u's'), - (0x1D461, 'M', u't'), - (0x1D462, 'M', u'u'), - (0x1D463, 'M', u'v'), - (0x1D464, 'M', u'w'), - (0x1D465, 'M', u'x'), - (0x1D466, 'M', u'y'), - (0x1D467, 'M', u'z'), - (0x1D468, 'M', u'a'), - (0x1D469, 'M', u'b'), - (0x1D46A, 'M', u'c'), - (0x1D46B, 'M', u'd'), - (0x1D46C, 'M', u'e'), - (0x1D46D, 'M', u'f'), - (0x1D46E, 'M', u'g'), - (0x1D46F, 'M', u'h'), - (0x1D470, 'M', u'i'), - (0x1D471, 'M', u'j'), - (0x1D472, 'M', u'k'), - (0x1D473, 'M', u'l'), - (0x1D474, 'M', u'm'), - (0x1D475, 'M', u'n'), - (0x1D476, 'M', u'o'), - (0x1D477, 'M', u'p'), - (0x1D478, 'M', u'q'), - (0x1D479, 'M', u'r'), - (0x1D47A, 'M', u's'), - (0x1D47B, 'M', u't'), - (0x1D47C, 'M', u'u'), - (0x1D47D, 'M', u'v'), - (0x1D47E, 'M', u'w'), - (0x1D47F, 'M', u'x'), - (0x1D480, 'M', u'y'), - (0x1D481, 'M', u'z'), - (0x1D482, 'M', u'a'), - (0x1D483, 'M', u'b'), - (0x1D484, 'M', u'c'), - (0x1D485, 'M', u'd'), - (0x1D486, 'M', u'e'), - (0x1D487, 'M', u'f'), - (0x1D488, 'M', u'g'), - (0x1D489, 'M', u'h'), - (0x1D48A, 'M', u'i'), - (0x1D48B, 'M', u'j'), - (0x1D48C, 'M', u'k'), - (0x1D48D, 'M', u'l'), - (0x1D48E, 'M', u'm'), - (0x1D48F, 'M', u'n'), - (0x1D490, 'M', u'o'), - (0x1D491, 'M', u'p'), - (0x1D492, 'M', u'q'), - (0x1D493, 'M', u'r'), - (0x1D494, 'M', u's'), - (0x1D495, 'M', u't'), - (0x1D496, 'M', u'u'), - (0x1D497, 'M', u'v'), - (0x1D498, 'M', u'w'), - (0x1D499, 'M', u'x'), - (0x1D49A, 'M', u'y'), - (0x1D49B, 'M', u'z'), - (0x1D49C, 'M', u'a'), - (0x1D49D, 'X'), - (0x1D49E, 'M', u'c'), - (0x1D49F, 'M', u'd'), - (0x1D4A0, 'X'), - (0x1D4A2, 'M', u'g'), - (0x1D4A3, 'X'), - (0x1D4A5, 'M', u'j'), - (0x1D4A6, 'M', u'k'), - (0x1D4A7, 'X'), - (0x1D4A9, 'M', u'n'), - (0x1D4AA, 'M', u'o'), - (0x1D4AB, 'M', u'p'), - (0x1D4AC, 'M', u'q'), - (0x1D4AD, 'X'), - (0x1D4AE, 'M', u's'), - (0x1D4AF, 'M', u't'), - (0x1D4B0, 'M', u'u'), - (0x1D4B1, 'M', u'v'), - (0x1D4B2, 'M', u'w'), - (0x1D4B3, 'M', u'x'), - (0x1D4B4, 'M', u'y'), - (0x1D4B5, 'M', u'z'), - (0x1D4B6, 'M', u'a'), - (0x1D4B7, 'M', u'b'), - (0x1D4B8, 'M', u'c'), - ] - -def _seg_61(): - return [ - (0x1D4B9, 'M', u'd'), - (0x1D4BA, 'X'), - (0x1D4BB, 'M', u'f'), - (0x1D4BC, 'X'), - (0x1D4BD, 'M', u'h'), - (0x1D4BE, 'M', u'i'), - (0x1D4BF, 'M', u'j'), - (0x1D4C0, 'M', u'k'), - (0x1D4C1, 'M', u'l'), - (0x1D4C2, 'M', u'm'), - (0x1D4C3, 'M', u'n'), - (0x1D4C4, 'X'), - (0x1D4C5, 'M', u'p'), - (0x1D4C6, 'M', u'q'), - (0x1D4C7, 'M', u'r'), - (0x1D4C8, 'M', u's'), - (0x1D4C9, 'M', u't'), - (0x1D4CA, 'M', u'u'), - (0x1D4CB, 'M', u'v'), - (0x1D4CC, 'M', u'w'), - (0x1D4CD, 'M', u'x'), - (0x1D4CE, 'M', u'y'), - (0x1D4CF, 'M', u'z'), - (0x1D4D0, 'M', u'a'), - (0x1D4D1, 'M', u'b'), - (0x1D4D2, 'M', u'c'), - (0x1D4D3, 'M', u'd'), - (0x1D4D4, 'M', u'e'), - (0x1D4D5, 'M', u'f'), - (0x1D4D6, 'M', u'g'), - (0x1D4D7, 'M', u'h'), - (0x1D4D8, 'M', u'i'), - (0x1D4D9, 'M', u'j'), - (0x1D4DA, 'M', u'k'), - (0x1D4DB, 'M', u'l'), - (0x1D4DC, 'M', u'm'), - (0x1D4DD, 'M', u'n'), - (0x1D4DE, 'M', u'o'), - (0x1D4DF, 'M', u'p'), - (0x1D4E0, 'M', u'q'), - (0x1D4E1, 'M', u'r'), - (0x1D4E2, 'M', u's'), - (0x1D4E3, 'M', u't'), - (0x1D4E4, 'M', u'u'), - (0x1D4E5, 'M', u'v'), - (0x1D4E6, 'M', u'w'), - (0x1D4E7, 'M', u'x'), - (0x1D4E8, 'M', u'y'), - (0x1D4E9, 'M', u'z'), - (0x1D4EA, 'M', u'a'), - (0x1D4EB, 'M', u'b'), - (0x1D4EC, 'M', u'c'), - (0x1D4ED, 'M', u'd'), - (0x1D4EE, 'M', u'e'), - (0x1D4EF, 'M', u'f'), - (0x1D4F0, 'M', u'g'), - (0x1D4F1, 'M', u'h'), - (0x1D4F2, 'M', u'i'), - (0x1D4F3, 'M', u'j'), - (0x1D4F4, 'M', u'k'), - (0x1D4F5, 'M', u'l'), - (0x1D4F6, 'M', u'm'), - (0x1D4F7, 'M', u'n'), - (0x1D4F8, 'M', u'o'), - (0x1D4F9, 'M', u'p'), - (0x1D4FA, 'M', u'q'), - (0x1D4FB, 'M', u'r'), - (0x1D4FC, 'M', u's'), - (0x1D4FD, 'M', u't'), - (0x1D4FE, 'M', u'u'), - (0x1D4FF, 'M', u'v'), - (0x1D500, 'M', u'w'), - (0x1D501, 'M', u'x'), - (0x1D502, 'M', u'y'), - (0x1D503, 'M', u'z'), - (0x1D504, 'M', u'a'), - (0x1D505, 'M', u'b'), - (0x1D506, 'X'), - (0x1D507, 'M', u'd'), - (0x1D508, 'M', u'e'), - (0x1D509, 'M', u'f'), - (0x1D50A, 'M', u'g'), - (0x1D50B, 'X'), - (0x1D50D, 'M', u'j'), - (0x1D50E, 'M', u'k'), - (0x1D50F, 'M', u'l'), - (0x1D510, 'M', u'm'), - (0x1D511, 'M', u'n'), - (0x1D512, 'M', u'o'), - (0x1D513, 'M', u'p'), - (0x1D514, 'M', u'q'), - (0x1D515, 'X'), - (0x1D516, 'M', u's'), - (0x1D517, 'M', u't'), - (0x1D518, 'M', u'u'), - (0x1D519, 'M', u'v'), - (0x1D51A, 'M', u'w'), - (0x1D51B, 'M', u'x'), - (0x1D51C, 'M', u'y'), - (0x1D51D, 'X'), - ] - -def _seg_62(): - return [ - (0x1D51E, 'M', u'a'), - (0x1D51F, 'M', u'b'), - (0x1D520, 'M', u'c'), - (0x1D521, 'M', u'd'), - (0x1D522, 'M', u'e'), - (0x1D523, 'M', u'f'), - (0x1D524, 'M', u'g'), - (0x1D525, 'M', u'h'), - (0x1D526, 'M', u'i'), - (0x1D527, 'M', u'j'), - (0x1D528, 'M', u'k'), - (0x1D529, 'M', u'l'), - (0x1D52A, 'M', u'm'), - (0x1D52B, 'M', u'n'), - (0x1D52C, 'M', u'o'), - (0x1D52D, 'M', u'p'), - (0x1D52E, 'M', u'q'), - (0x1D52F, 'M', u'r'), - (0x1D530, 'M', u's'), - (0x1D531, 'M', u't'), - (0x1D532, 'M', u'u'), - (0x1D533, 'M', u'v'), - (0x1D534, 'M', u'w'), - (0x1D535, 'M', u'x'), - (0x1D536, 'M', u'y'), - (0x1D537, 'M', u'z'), - (0x1D538, 'M', u'a'), - (0x1D539, 'M', u'b'), - (0x1D53A, 'X'), - (0x1D53B, 'M', u'd'), - (0x1D53C, 'M', u'e'), - (0x1D53D, 'M', u'f'), - (0x1D53E, 'M', u'g'), - (0x1D53F, 'X'), - (0x1D540, 'M', u'i'), - (0x1D541, 'M', u'j'), - (0x1D542, 'M', u'k'), - (0x1D543, 'M', u'l'), - (0x1D544, 'M', u'm'), - (0x1D545, 'X'), - (0x1D546, 'M', u'o'), - (0x1D547, 'X'), - (0x1D54A, 'M', u's'), - (0x1D54B, 'M', u't'), - (0x1D54C, 'M', u'u'), - (0x1D54D, 'M', u'v'), - (0x1D54E, 'M', u'w'), - (0x1D54F, 'M', u'x'), - (0x1D550, 'M', u'y'), - (0x1D551, 'X'), - (0x1D552, 'M', u'a'), - (0x1D553, 'M', u'b'), - (0x1D554, 'M', u'c'), - (0x1D555, 'M', u'd'), - (0x1D556, 'M', u'e'), - (0x1D557, 'M', u'f'), - (0x1D558, 'M', u'g'), - (0x1D559, 'M', u'h'), - (0x1D55A, 'M', u'i'), - (0x1D55B, 'M', u'j'), - (0x1D55C, 'M', u'k'), - (0x1D55D, 'M', u'l'), - (0x1D55E, 'M', u'm'), - (0x1D55F, 'M', u'n'), - (0x1D560, 'M', u'o'), - (0x1D561, 'M', u'p'), - (0x1D562, 'M', u'q'), - (0x1D563, 'M', u'r'), - (0x1D564, 'M', u's'), - (0x1D565, 'M', u't'), - (0x1D566, 'M', u'u'), - (0x1D567, 'M', u'v'), - (0x1D568, 'M', u'w'), - (0x1D569, 'M', u'x'), - (0x1D56A, 'M', u'y'), - (0x1D56B, 'M', u'z'), - (0x1D56C, 'M', u'a'), - (0x1D56D, 'M', u'b'), - (0x1D56E, 'M', u'c'), - (0x1D56F, 'M', u'd'), - (0x1D570, 'M', u'e'), - (0x1D571, 'M', u'f'), - (0x1D572, 'M', u'g'), - (0x1D573, 'M', u'h'), - (0x1D574, 'M', u'i'), - (0x1D575, 'M', u'j'), - (0x1D576, 'M', u'k'), - (0x1D577, 'M', u'l'), - (0x1D578, 'M', u'm'), - (0x1D579, 'M', u'n'), - (0x1D57A, 'M', u'o'), - (0x1D57B, 'M', u'p'), - (0x1D57C, 'M', u'q'), - (0x1D57D, 'M', u'r'), - (0x1D57E, 'M', u's'), - (0x1D57F, 'M', u't'), - (0x1D580, 'M', u'u'), - (0x1D581, 'M', u'v'), - (0x1D582, 'M', u'w'), - (0x1D583, 'M', u'x'), - ] - -def _seg_63(): - return [ - (0x1D584, 'M', u'y'), - (0x1D585, 'M', u'z'), - (0x1D586, 'M', u'a'), - (0x1D587, 'M', u'b'), - (0x1D588, 'M', u'c'), - (0x1D589, 'M', u'd'), - (0x1D58A, 'M', u'e'), - (0x1D58B, 'M', u'f'), - (0x1D58C, 'M', u'g'), - (0x1D58D, 'M', u'h'), - (0x1D58E, 'M', u'i'), - (0x1D58F, 'M', u'j'), - (0x1D590, 'M', u'k'), - (0x1D591, 'M', u'l'), - (0x1D592, 'M', u'm'), - (0x1D593, 'M', u'n'), - (0x1D594, 'M', u'o'), - (0x1D595, 'M', u'p'), - (0x1D596, 'M', u'q'), - (0x1D597, 'M', u'r'), - (0x1D598, 'M', u's'), - (0x1D599, 'M', u't'), - (0x1D59A, 'M', u'u'), - (0x1D59B, 'M', u'v'), - (0x1D59C, 'M', u'w'), - (0x1D59D, 'M', u'x'), - (0x1D59E, 'M', u'y'), - (0x1D59F, 'M', u'z'), - (0x1D5A0, 'M', u'a'), - (0x1D5A1, 'M', u'b'), - (0x1D5A2, 'M', u'c'), - (0x1D5A3, 'M', u'd'), - (0x1D5A4, 'M', u'e'), - (0x1D5A5, 'M', u'f'), - (0x1D5A6, 'M', u'g'), - (0x1D5A7, 'M', u'h'), - (0x1D5A8, 'M', u'i'), - (0x1D5A9, 'M', u'j'), - (0x1D5AA, 'M', u'k'), - (0x1D5AB, 'M', u'l'), - (0x1D5AC, 'M', u'm'), - (0x1D5AD, 'M', u'n'), - (0x1D5AE, 'M', u'o'), - (0x1D5AF, 'M', u'p'), - (0x1D5B0, 'M', u'q'), - (0x1D5B1, 'M', u'r'), - (0x1D5B2, 'M', u's'), - (0x1D5B3, 'M', u't'), - (0x1D5B4, 'M', u'u'), - (0x1D5B5, 'M', u'v'), - (0x1D5B6, 'M', u'w'), - (0x1D5B7, 'M', u'x'), - (0x1D5B8, 'M', u'y'), - (0x1D5B9, 'M', u'z'), - (0x1D5BA, 'M', u'a'), - (0x1D5BB, 'M', u'b'), - (0x1D5BC, 'M', u'c'), - (0x1D5BD, 'M', u'd'), - (0x1D5BE, 'M', u'e'), - (0x1D5BF, 'M', u'f'), - (0x1D5C0, 'M', u'g'), - (0x1D5C1, 'M', u'h'), - (0x1D5C2, 'M', u'i'), - (0x1D5C3, 'M', u'j'), - (0x1D5C4, 'M', u'k'), - (0x1D5C5, 'M', u'l'), - (0x1D5C6, 'M', u'm'), - (0x1D5C7, 'M', u'n'), - (0x1D5C8, 'M', u'o'), - (0x1D5C9, 'M', u'p'), - (0x1D5CA, 'M', u'q'), - (0x1D5CB, 'M', u'r'), - (0x1D5CC, 'M', u's'), - (0x1D5CD, 'M', u't'), - (0x1D5CE, 'M', u'u'), - (0x1D5CF, 'M', u'v'), - (0x1D5D0, 'M', u'w'), - (0x1D5D1, 'M', u'x'), - (0x1D5D2, 'M', u'y'), - (0x1D5D3, 'M', u'z'), - (0x1D5D4, 'M', u'a'), - (0x1D5D5, 'M', u'b'), - (0x1D5D6, 'M', u'c'), - (0x1D5D7, 'M', u'd'), - (0x1D5D8, 'M', u'e'), - (0x1D5D9, 'M', u'f'), - (0x1D5DA, 'M', u'g'), - (0x1D5DB, 'M', u'h'), - (0x1D5DC, 'M', u'i'), - (0x1D5DD, 'M', u'j'), - (0x1D5DE, 'M', u'k'), - (0x1D5DF, 'M', u'l'), - (0x1D5E0, 'M', u'm'), - (0x1D5E1, 'M', u'n'), - (0x1D5E2, 'M', u'o'), - (0x1D5E3, 'M', u'p'), - (0x1D5E4, 'M', u'q'), - (0x1D5E5, 'M', u'r'), - (0x1D5E6, 'M', u's'), - (0x1D5E7, 'M', u't'), - ] - -def _seg_64(): - return [ - (0x1D5E8, 'M', u'u'), - (0x1D5E9, 'M', u'v'), - (0x1D5EA, 'M', u'w'), - (0x1D5EB, 'M', u'x'), - (0x1D5EC, 'M', u'y'), - (0x1D5ED, 'M', u'z'), - (0x1D5EE, 'M', u'a'), - (0x1D5EF, 'M', u'b'), - (0x1D5F0, 'M', u'c'), - (0x1D5F1, 'M', u'd'), - (0x1D5F2, 'M', u'e'), - (0x1D5F3, 'M', u'f'), - (0x1D5F4, 'M', u'g'), - (0x1D5F5, 'M', u'h'), - (0x1D5F6, 'M', u'i'), - (0x1D5F7, 'M', u'j'), - (0x1D5F8, 'M', u'k'), - (0x1D5F9, 'M', u'l'), - (0x1D5FA, 'M', u'm'), - (0x1D5FB, 'M', u'n'), - (0x1D5FC, 'M', u'o'), - (0x1D5FD, 'M', u'p'), - (0x1D5FE, 'M', u'q'), - (0x1D5FF, 'M', u'r'), - (0x1D600, 'M', u's'), - (0x1D601, 'M', u't'), - (0x1D602, 'M', u'u'), - (0x1D603, 'M', u'v'), - (0x1D604, 'M', u'w'), - (0x1D605, 'M', u'x'), - (0x1D606, 'M', u'y'), - (0x1D607, 'M', u'z'), - (0x1D608, 'M', u'a'), - (0x1D609, 'M', u'b'), - (0x1D60A, 'M', u'c'), - (0x1D60B, 'M', u'd'), - (0x1D60C, 'M', u'e'), - (0x1D60D, 'M', u'f'), - (0x1D60E, 'M', u'g'), - (0x1D60F, 'M', u'h'), - (0x1D610, 'M', u'i'), - (0x1D611, 'M', u'j'), - (0x1D612, 'M', u'k'), - (0x1D613, 'M', u'l'), - (0x1D614, 'M', u'm'), - (0x1D615, 'M', u'n'), - (0x1D616, 'M', u'o'), - (0x1D617, 'M', u'p'), - (0x1D618, 'M', u'q'), - (0x1D619, 'M', u'r'), - (0x1D61A, 'M', u's'), - (0x1D61B, 'M', u't'), - (0x1D61C, 'M', u'u'), - (0x1D61D, 'M', u'v'), - (0x1D61E, 'M', u'w'), - (0x1D61F, 'M', u'x'), - (0x1D620, 'M', u'y'), - (0x1D621, 'M', u'z'), - (0x1D622, 'M', u'a'), - (0x1D623, 'M', u'b'), - (0x1D624, 'M', u'c'), - (0x1D625, 'M', u'd'), - (0x1D626, 'M', u'e'), - (0x1D627, 'M', u'f'), - (0x1D628, 'M', u'g'), - (0x1D629, 'M', u'h'), - (0x1D62A, 'M', u'i'), - (0x1D62B, 'M', u'j'), - (0x1D62C, 'M', u'k'), - (0x1D62D, 'M', u'l'), - (0x1D62E, 'M', u'm'), - (0x1D62F, 'M', u'n'), - (0x1D630, 'M', u'o'), - (0x1D631, 'M', u'p'), - (0x1D632, 'M', u'q'), - (0x1D633, 'M', u'r'), - (0x1D634, 'M', u's'), - (0x1D635, 'M', u't'), - (0x1D636, 'M', u'u'), - (0x1D637, 'M', u'v'), - (0x1D638, 'M', u'w'), - (0x1D639, 'M', u'x'), - (0x1D63A, 'M', u'y'), - (0x1D63B, 'M', u'z'), - (0x1D63C, 'M', u'a'), - (0x1D63D, 'M', u'b'), - (0x1D63E, 'M', u'c'), - (0x1D63F, 'M', u'd'), - (0x1D640, 'M', u'e'), - (0x1D641, 'M', u'f'), - (0x1D642, 'M', u'g'), - (0x1D643, 'M', u'h'), - (0x1D644, 'M', u'i'), - (0x1D645, 'M', u'j'), - (0x1D646, 'M', u'k'), - (0x1D647, 'M', u'l'), - (0x1D648, 'M', u'm'), - (0x1D649, 'M', u'n'), - (0x1D64A, 'M', u'o'), - (0x1D64B, 'M', u'p'), - ] - -def _seg_65(): - return [ - (0x1D64C, 'M', u'q'), - (0x1D64D, 'M', u'r'), - (0x1D64E, 'M', u's'), - (0x1D64F, 'M', u't'), - (0x1D650, 'M', u'u'), - (0x1D651, 'M', u'v'), - (0x1D652, 'M', u'w'), - (0x1D653, 'M', u'x'), - (0x1D654, 'M', u'y'), - (0x1D655, 'M', u'z'), - (0x1D656, 'M', u'a'), - (0x1D657, 'M', u'b'), - (0x1D658, 'M', u'c'), - (0x1D659, 'M', u'd'), - (0x1D65A, 'M', u'e'), - (0x1D65B, 'M', u'f'), - (0x1D65C, 'M', u'g'), - (0x1D65D, 'M', u'h'), - (0x1D65E, 'M', u'i'), - (0x1D65F, 'M', u'j'), - (0x1D660, 'M', u'k'), - (0x1D661, 'M', u'l'), - (0x1D662, 'M', u'm'), - (0x1D663, 'M', u'n'), - (0x1D664, 'M', u'o'), - (0x1D665, 'M', u'p'), - (0x1D666, 'M', u'q'), - (0x1D667, 'M', u'r'), - (0x1D668, 'M', u's'), - (0x1D669, 'M', u't'), - (0x1D66A, 'M', u'u'), - (0x1D66B, 'M', u'v'), - (0x1D66C, 'M', u'w'), - (0x1D66D, 'M', u'x'), - (0x1D66E, 'M', u'y'), - (0x1D66F, 'M', u'z'), - (0x1D670, 'M', u'a'), - (0x1D671, 'M', u'b'), - (0x1D672, 'M', u'c'), - (0x1D673, 'M', u'd'), - (0x1D674, 'M', u'e'), - (0x1D675, 'M', u'f'), - (0x1D676, 'M', u'g'), - (0x1D677, 'M', u'h'), - (0x1D678, 'M', u'i'), - (0x1D679, 'M', u'j'), - (0x1D67A, 'M', u'k'), - (0x1D67B, 'M', u'l'), - (0x1D67C, 'M', u'm'), - (0x1D67D, 'M', u'n'), - (0x1D67E, 'M', u'o'), - (0x1D67F, 'M', u'p'), - (0x1D680, 'M', u'q'), - (0x1D681, 'M', u'r'), - (0x1D682, 'M', u's'), - (0x1D683, 'M', u't'), - (0x1D684, 'M', u'u'), - (0x1D685, 'M', u'v'), - (0x1D686, 'M', u'w'), - (0x1D687, 'M', u'x'), - (0x1D688, 'M', u'y'), - (0x1D689, 'M', u'z'), - (0x1D68A, 'M', u'a'), - (0x1D68B, 'M', u'b'), - (0x1D68C, 'M', u'c'), - (0x1D68D, 'M', u'd'), - (0x1D68E, 'M', u'e'), - (0x1D68F, 'M', u'f'), - (0x1D690, 'M', u'g'), - (0x1D691, 'M', u'h'), - (0x1D692, 'M', u'i'), - (0x1D693, 'M', u'j'), - (0x1D694, 'M', u'k'), - (0x1D695, 'M', u'l'), - (0x1D696, 'M', u'm'), - (0x1D697, 'M', u'n'), - (0x1D698, 'M', u'o'), - (0x1D699, 'M', u'p'), - (0x1D69A, 'M', u'q'), - (0x1D69B, 'M', u'r'), - (0x1D69C, 'M', u's'), - (0x1D69D, 'M', u't'), - (0x1D69E, 'M', u'u'), - (0x1D69F, 'M', u'v'), - (0x1D6A0, 'M', u'w'), - (0x1D6A1, 'M', u'x'), - (0x1D6A2, 'M', u'y'), - (0x1D6A3, 'M', u'z'), - (0x1D6A4, 'M', u'ı'), - (0x1D6A5, 'M', u'ȷ'), - (0x1D6A6, 'X'), - (0x1D6A8, 'M', u'α'), - (0x1D6A9, 'M', u'β'), - (0x1D6AA, 'M', u'γ'), - (0x1D6AB, 'M', u'δ'), - (0x1D6AC, 'M', u'ε'), - (0x1D6AD, 'M', u'ζ'), - (0x1D6AE, 'M', u'η'), - (0x1D6AF, 'M', u'θ'), - (0x1D6B0, 'M', u'ι'), - ] - -def _seg_66(): - return [ - (0x1D6B1, 'M', u'κ'), - (0x1D6B2, 'M', u'λ'), - (0x1D6B3, 'M', u'μ'), - (0x1D6B4, 'M', u'ν'), - (0x1D6B5, 'M', u'ξ'), - (0x1D6B6, 'M', u'ο'), - (0x1D6B7, 'M', u'π'), - (0x1D6B8, 'M', u'ρ'), - (0x1D6B9, 'M', u'θ'), - (0x1D6BA, 'M', u'σ'), - (0x1D6BB, 'M', u'τ'), - (0x1D6BC, 'M', u'υ'), - (0x1D6BD, 'M', u'φ'), - (0x1D6BE, 'M', u'χ'), - (0x1D6BF, 'M', u'ψ'), - (0x1D6C0, 'M', u'ω'), - (0x1D6C1, 'M', u'∇'), - (0x1D6C2, 'M', u'α'), - (0x1D6C3, 'M', u'β'), - (0x1D6C4, 'M', u'γ'), - (0x1D6C5, 'M', u'δ'), - (0x1D6C6, 'M', u'ε'), - (0x1D6C7, 'M', u'ζ'), - (0x1D6C8, 'M', u'η'), - (0x1D6C9, 'M', u'θ'), - (0x1D6CA, 'M', u'ι'), - (0x1D6CB, 'M', u'κ'), - (0x1D6CC, 'M', u'λ'), - (0x1D6CD, 'M', u'μ'), - (0x1D6CE, 'M', u'ν'), - (0x1D6CF, 'M', u'ξ'), - (0x1D6D0, 'M', u'ο'), - (0x1D6D1, 'M', u'π'), - (0x1D6D2, 'M', u'ρ'), - (0x1D6D3, 'M', u'σ'), - (0x1D6D5, 'M', u'τ'), - (0x1D6D6, 'M', u'υ'), - (0x1D6D7, 'M', u'φ'), - (0x1D6D8, 'M', u'χ'), - (0x1D6D9, 'M', u'ψ'), - (0x1D6DA, 'M', u'ω'), - (0x1D6DB, 'M', u'∂'), - (0x1D6DC, 'M', u'ε'), - (0x1D6DD, 'M', u'θ'), - (0x1D6DE, 'M', u'κ'), - (0x1D6DF, 'M', u'φ'), - (0x1D6E0, 'M', u'ρ'), - (0x1D6E1, 'M', u'π'), - (0x1D6E2, 'M', u'α'), - (0x1D6E3, 'M', u'β'), - (0x1D6E4, 'M', u'γ'), - (0x1D6E5, 'M', u'δ'), - (0x1D6E6, 'M', u'ε'), - (0x1D6E7, 'M', u'ζ'), - (0x1D6E8, 'M', u'η'), - (0x1D6E9, 'M', u'θ'), - (0x1D6EA, 'M', u'ι'), - (0x1D6EB, 'M', u'κ'), - (0x1D6EC, 'M', u'λ'), - (0x1D6ED, 'M', u'μ'), - (0x1D6EE, 'M', u'ν'), - (0x1D6EF, 'M', u'ξ'), - (0x1D6F0, 'M', u'ο'), - (0x1D6F1, 'M', u'π'), - (0x1D6F2, 'M', u'ρ'), - (0x1D6F3, 'M', u'θ'), - (0x1D6F4, 'M', u'σ'), - (0x1D6F5, 'M', u'τ'), - (0x1D6F6, 'M', u'υ'), - (0x1D6F7, 'M', u'φ'), - (0x1D6F8, 'M', u'χ'), - (0x1D6F9, 'M', u'ψ'), - (0x1D6FA, 'M', u'ω'), - (0x1D6FB, 'M', u'∇'), - (0x1D6FC, 'M', u'α'), - (0x1D6FD, 'M', u'β'), - (0x1D6FE, 'M', u'γ'), - (0x1D6FF, 'M', u'δ'), - (0x1D700, 'M', u'ε'), - (0x1D701, 'M', u'ζ'), - (0x1D702, 'M', u'η'), - (0x1D703, 'M', u'θ'), - (0x1D704, 'M', u'ι'), - (0x1D705, 'M', u'κ'), - (0x1D706, 'M', u'λ'), - (0x1D707, 'M', u'μ'), - (0x1D708, 'M', u'ν'), - (0x1D709, 'M', u'ξ'), - (0x1D70A, 'M', u'ο'), - (0x1D70B, 'M', u'π'), - (0x1D70C, 'M', u'ρ'), - (0x1D70D, 'M', u'σ'), - (0x1D70F, 'M', u'τ'), - (0x1D710, 'M', u'υ'), - (0x1D711, 'M', u'φ'), - (0x1D712, 'M', u'χ'), - (0x1D713, 'M', u'ψ'), - (0x1D714, 'M', u'ω'), - (0x1D715, 'M', u'∂'), - (0x1D716, 'M', u'ε'), - ] - -def _seg_67(): - return [ - (0x1D717, 'M', u'θ'), - (0x1D718, 'M', u'κ'), - (0x1D719, 'M', u'φ'), - (0x1D71A, 'M', u'ρ'), - (0x1D71B, 'M', u'π'), - (0x1D71C, 'M', u'α'), - (0x1D71D, 'M', u'β'), - (0x1D71E, 'M', u'γ'), - (0x1D71F, 'M', u'δ'), - (0x1D720, 'M', u'ε'), - (0x1D721, 'M', u'ζ'), - (0x1D722, 'M', u'η'), - (0x1D723, 'M', u'θ'), - (0x1D724, 'M', u'ι'), - (0x1D725, 'M', u'κ'), - (0x1D726, 'M', u'λ'), - (0x1D727, 'M', u'μ'), - (0x1D728, 'M', u'ν'), - (0x1D729, 'M', u'ξ'), - (0x1D72A, 'M', u'ο'), - (0x1D72B, 'M', u'π'), - (0x1D72C, 'M', u'ρ'), - (0x1D72D, 'M', u'θ'), - (0x1D72E, 'M', u'σ'), - (0x1D72F, 'M', u'τ'), - (0x1D730, 'M', u'υ'), - (0x1D731, 'M', u'φ'), - (0x1D732, 'M', u'χ'), - (0x1D733, 'M', u'ψ'), - (0x1D734, 'M', u'ω'), - (0x1D735, 'M', u'∇'), - (0x1D736, 'M', u'α'), - (0x1D737, 'M', u'β'), - (0x1D738, 'M', u'γ'), - (0x1D739, 'M', u'δ'), - (0x1D73A, 'M', u'ε'), - (0x1D73B, 'M', u'ζ'), - (0x1D73C, 'M', u'η'), - (0x1D73D, 'M', u'θ'), - (0x1D73E, 'M', u'ι'), - (0x1D73F, 'M', u'κ'), - (0x1D740, 'M', u'λ'), - (0x1D741, 'M', u'μ'), - (0x1D742, 'M', u'ν'), - (0x1D743, 'M', u'ξ'), - (0x1D744, 'M', u'ο'), - (0x1D745, 'M', u'π'), - (0x1D746, 'M', u'ρ'), - (0x1D747, 'M', u'σ'), - (0x1D749, 'M', u'τ'), - (0x1D74A, 'M', u'υ'), - (0x1D74B, 'M', u'φ'), - (0x1D74C, 'M', u'χ'), - (0x1D74D, 'M', u'ψ'), - (0x1D74E, 'M', u'ω'), - (0x1D74F, 'M', u'∂'), - (0x1D750, 'M', u'ε'), - (0x1D751, 'M', u'θ'), - (0x1D752, 'M', u'κ'), - (0x1D753, 'M', u'φ'), - (0x1D754, 'M', u'ρ'), - (0x1D755, 'M', u'π'), - (0x1D756, 'M', u'α'), - (0x1D757, 'M', u'β'), - (0x1D758, 'M', u'γ'), - (0x1D759, 'M', u'δ'), - (0x1D75A, 'M', u'ε'), - (0x1D75B, 'M', u'ζ'), - (0x1D75C, 'M', u'η'), - (0x1D75D, 'M', u'θ'), - (0x1D75E, 'M', u'ι'), - (0x1D75F, 'M', u'κ'), - (0x1D760, 'M', u'λ'), - (0x1D761, 'M', u'μ'), - (0x1D762, 'M', u'ν'), - (0x1D763, 'M', u'ξ'), - (0x1D764, 'M', u'ο'), - (0x1D765, 'M', u'π'), - (0x1D766, 'M', u'ρ'), - (0x1D767, 'M', u'θ'), - (0x1D768, 'M', u'σ'), - (0x1D769, 'M', u'τ'), - (0x1D76A, 'M', u'υ'), - (0x1D76B, 'M', u'φ'), - (0x1D76C, 'M', u'χ'), - (0x1D76D, 'M', u'ψ'), - (0x1D76E, 'M', u'ω'), - (0x1D76F, 'M', u'∇'), - (0x1D770, 'M', u'α'), - (0x1D771, 'M', u'β'), - (0x1D772, 'M', u'γ'), - (0x1D773, 'M', u'δ'), - (0x1D774, 'M', u'ε'), - (0x1D775, 'M', u'ζ'), - (0x1D776, 'M', u'η'), - (0x1D777, 'M', u'θ'), - (0x1D778, 'M', u'ι'), - (0x1D779, 'M', u'κ'), - (0x1D77A, 'M', u'λ'), - (0x1D77B, 'M', u'μ'), - ] - -def _seg_68(): - return [ - (0x1D77C, 'M', u'ν'), - (0x1D77D, 'M', u'ξ'), - (0x1D77E, 'M', u'ο'), - (0x1D77F, 'M', u'π'), - (0x1D780, 'M', u'ρ'), - (0x1D781, 'M', u'σ'), - (0x1D783, 'M', u'τ'), - (0x1D784, 'M', u'υ'), - (0x1D785, 'M', u'φ'), - (0x1D786, 'M', u'χ'), - (0x1D787, 'M', u'ψ'), - (0x1D788, 'M', u'ω'), - (0x1D789, 'M', u'∂'), - (0x1D78A, 'M', u'ε'), - (0x1D78B, 'M', u'θ'), - (0x1D78C, 'M', u'κ'), - (0x1D78D, 'M', u'φ'), - (0x1D78E, 'M', u'ρ'), - (0x1D78F, 'M', u'π'), - (0x1D790, 'M', u'α'), - (0x1D791, 'M', u'β'), - (0x1D792, 'M', u'γ'), - (0x1D793, 'M', u'δ'), - (0x1D794, 'M', u'ε'), - (0x1D795, 'M', u'ζ'), - (0x1D796, 'M', u'η'), - (0x1D797, 'M', u'θ'), - (0x1D798, 'M', u'ι'), - (0x1D799, 'M', u'κ'), - (0x1D79A, 'M', u'λ'), - (0x1D79B, 'M', u'μ'), - (0x1D79C, 'M', u'ν'), - (0x1D79D, 'M', u'ξ'), - (0x1D79E, 'M', u'ο'), - (0x1D79F, 'M', u'π'), - (0x1D7A0, 'M', u'ρ'), - (0x1D7A1, 'M', u'θ'), - (0x1D7A2, 'M', u'σ'), - (0x1D7A3, 'M', u'τ'), - (0x1D7A4, 'M', u'υ'), - (0x1D7A5, 'M', u'φ'), - (0x1D7A6, 'M', u'χ'), - (0x1D7A7, 'M', u'ψ'), - (0x1D7A8, 'M', u'ω'), - (0x1D7A9, 'M', u'∇'), - (0x1D7AA, 'M', u'α'), - (0x1D7AB, 'M', u'β'), - (0x1D7AC, 'M', u'γ'), - (0x1D7AD, 'M', u'δ'), - (0x1D7AE, 'M', u'ε'), - (0x1D7AF, 'M', u'ζ'), - (0x1D7B0, 'M', u'η'), - (0x1D7B1, 'M', u'θ'), - (0x1D7B2, 'M', u'ι'), - (0x1D7B3, 'M', u'κ'), - (0x1D7B4, 'M', u'λ'), - (0x1D7B5, 'M', u'μ'), - (0x1D7B6, 'M', u'ν'), - (0x1D7B7, 'M', u'ξ'), - (0x1D7B8, 'M', u'ο'), - (0x1D7B9, 'M', u'π'), - (0x1D7BA, 'M', u'ρ'), - (0x1D7BB, 'M', u'σ'), - (0x1D7BD, 'M', u'τ'), - (0x1D7BE, 'M', u'υ'), - (0x1D7BF, 'M', u'φ'), - (0x1D7C0, 'M', u'χ'), - (0x1D7C1, 'M', u'ψ'), - (0x1D7C2, 'M', u'ω'), - (0x1D7C3, 'M', u'∂'), - (0x1D7C4, 'M', u'ε'), - (0x1D7C5, 'M', u'θ'), - (0x1D7C6, 'M', u'κ'), - (0x1D7C7, 'M', u'φ'), - (0x1D7C8, 'M', u'ρ'), - (0x1D7C9, 'M', u'π'), - (0x1D7CA, 'M', u'ϝ'), - (0x1D7CC, 'X'), - (0x1D7CE, 'M', u'0'), - (0x1D7CF, 'M', u'1'), - (0x1D7D0, 'M', u'2'), - (0x1D7D1, 'M', u'3'), - (0x1D7D2, 'M', u'4'), - (0x1D7D3, 'M', u'5'), - (0x1D7D4, 'M', u'6'), - (0x1D7D5, 'M', u'7'), - (0x1D7D6, 'M', u'8'), - (0x1D7D7, 'M', u'9'), - (0x1D7D8, 'M', u'0'), - (0x1D7D9, 'M', u'1'), - (0x1D7DA, 'M', u'2'), - (0x1D7DB, 'M', u'3'), - (0x1D7DC, 'M', u'4'), - (0x1D7DD, 'M', u'5'), - (0x1D7DE, 'M', u'6'), - (0x1D7DF, 'M', u'7'), - (0x1D7E0, 'M', u'8'), - (0x1D7E1, 'M', u'9'), - (0x1D7E2, 'M', u'0'), - (0x1D7E3, 'M', u'1'), - ] - -def _seg_69(): - return [ - (0x1D7E4, 'M', u'2'), - (0x1D7E5, 'M', u'3'), - (0x1D7E6, 'M', u'4'), - (0x1D7E7, 'M', u'5'), - (0x1D7E8, 'M', u'6'), - (0x1D7E9, 'M', u'7'), - (0x1D7EA, 'M', u'8'), - (0x1D7EB, 'M', u'9'), - (0x1D7EC, 'M', u'0'), - (0x1D7ED, 'M', u'1'), - (0x1D7EE, 'M', u'2'), - (0x1D7EF, 'M', u'3'), - (0x1D7F0, 'M', u'4'), - (0x1D7F1, 'M', u'5'), - (0x1D7F2, 'M', u'6'), - (0x1D7F3, 'M', u'7'), - (0x1D7F4, 'M', u'8'), - (0x1D7F5, 'M', u'9'), - (0x1D7F6, 'M', u'0'), - (0x1D7F7, 'M', u'1'), - (0x1D7F8, 'M', u'2'), - (0x1D7F9, 'M', u'3'), - (0x1D7FA, 'M', u'4'), - (0x1D7FB, 'M', u'5'), - (0x1D7FC, 'M', u'6'), - (0x1D7FD, 'M', u'7'), - (0x1D7FE, 'M', u'8'), - (0x1D7FF, 'M', u'9'), - (0x1D800, 'V'), - (0x1DA8C, 'X'), - (0x1DA9B, 'V'), - (0x1DAA0, 'X'), - (0x1DAA1, 'V'), - (0x1DAB0, 'X'), - (0x1E000, 'V'), - (0x1E007, 'X'), - (0x1E008, 'V'), - (0x1E019, 'X'), - (0x1E01B, 'V'), - (0x1E022, 'X'), - (0x1E023, 'V'), - (0x1E025, 'X'), - (0x1E026, 'V'), - (0x1E02B, 'X'), - (0x1E100, 'V'), - (0x1E12D, 'X'), - (0x1E130, 'V'), - (0x1E13E, 'X'), - (0x1E140, 'V'), - (0x1E14A, 'X'), - (0x1E14E, 'V'), - (0x1E150, 'X'), - (0x1E2C0, 'V'), - (0x1E2FA, 'X'), - (0x1E2FF, 'V'), - (0x1E300, 'X'), - (0x1E800, 'V'), - (0x1E8C5, 'X'), - (0x1E8C7, 'V'), - (0x1E8D7, 'X'), - (0x1E900, 'M', u'𞤢'), - (0x1E901, 'M', u'𞤣'), - (0x1E902, 'M', u'𞤤'), - (0x1E903, 'M', u'𞤥'), - (0x1E904, 'M', u'𞤦'), - (0x1E905, 'M', u'𞤧'), - (0x1E906, 'M', u'𞤨'), - (0x1E907, 'M', u'𞤩'), - (0x1E908, 'M', u'𞤪'), - (0x1E909, 'M', u'𞤫'), - (0x1E90A, 'M', u'𞤬'), - (0x1E90B, 'M', u'𞤭'), - (0x1E90C, 'M', u'𞤮'), - (0x1E90D, 'M', u'𞤯'), - (0x1E90E, 'M', u'𞤰'), - (0x1E90F, 'M', u'𞤱'), - (0x1E910, 'M', u'𞤲'), - (0x1E911, 'M', u'𞤳'), - (0x1E912, 'M', u'𞤴'), - (0x1E913, 'M', u'𞤵'), - (0x1E914, 'M', u'𞤶'), - (0x1E915, 'M', u'𞤷'), - (0x1E916, 'M', u'𞤸'), - (0x1E917, 'M', u'𞤹'), - (0x1E918, 'M', u'𞤺'), - (0x1E919, 'M', u'𞤻'), - (0x1E91A, 'M', u'𞤼'), - (0x1E91B, 'M', u'𞤽'), - (0x1E91C, 'M', u'𞤾'), - (0x1E91D, 'M', u'𞤿'), - (0x1E91E, 'M', u'𞥀'), - (0x1E91F, 'M', u'𞥁'), - (0x1E920, 'M', u'𞥂'), - (0x1E921, 'M', u'𞥃'), - (0x1E922, 'V'), - (0x1E94C, 'X'), - (0x1E950, 'V'), - (0x1E95A, 'X'), - (0x1E95E, 'V'), - (0x1E960, 'X'), - ] - -def _seg_70(): - return [ - (0x1EC71, 'V'), - (0x1ECB5, 'X'), - (0x1ED01, 'V'), - (0x1ED3E, 'X'), - (0x1EE00, 'M', u'ا'), - (0x1EE01, 'M', u'ب'), - (0x1EE02, 'M', u'ج'), - (0x1EE03, 'M', u'د'), - (0x1EE04, 'X'), - (0x1EE05, 'M', u'و'), - (0x1EE06, 'M', u'ز'), - (0x1EE07, 'M', u'ح'), - (0x1EE08, 'M', u'ط'), - (0x1EE09, 'M', u'ي'), - (0x1EE0A, 'M', u'ك'), - (0x1EE0B, 'M', u'ل'), - (0x1EE0C, 'M', u'م'), - (0x1EE0D, 'M', u'ن'), - (0x1EE0E, 'M', u'س'), - (0x1EE0F, 'M', u'ع'), - (0x1EE10, 'M', u'ف'), - (0x1EE11, 'M', u'ص'), - (0x1EE12, 'M', u'ق'), - (0x1EE13, 'M', u'ر'), - (0x1EE14, 'M', u'ش'), - (0x1EE15, 'M', u'ت'), - (0x1EE16, 'M', u'ث'), - (0x1EE17, 'M', u'خ'), - (0x1EE18, 'M', u'ذ'), - (0x1EE19, 'M', u'ض'), - (0x1EE1A, 'M', u'ظ'), - (0x1EE1B, 'M', u'غ'), - (0x1EE1C, 'M', u'ٮ'), - (0x1EE1D, 'M', u'ں'), - (0x1EE1E, 'M', u'ڡ'), - (0x1EE1F, 'M', u'ٯ'), - (0x1EE20, 'X'), - (0x1EE21, 'M', u'ب'), - (0x1EE22, 'M', u'ج'), - (0x1EE23, 'X'), - (0x1EE24, 'M', u'ه'), - (0x1EE25, 'X'), - (0x1EE27, 'M', u'ح'), - (0x1EE28, 'X'), - (0x1EE29, 'M', u'ي'), - (0x1EE2A, 'M', u'ك'), - (0x1EE2B, 'M', u'ل'), - (0x1EE2C, 'M', u'م'), - (0x1EE2D, 'M', u'ن'), - (0x1EE2E, 'M', u'س'), - (0x1EE2F, 'M', u'ع'), - (0x1EE30, 'M', u'ف'), - (0x1EE31, 'M', u'ص'), - (0x1EE32, 'M', u'ق'), - (0x1EE33, 'X'), - (0x1EE34, 'M', u'ش'), - (0x1EE35, 'M', u'ت'), - (0x1EE36, 'M', u'ث'), - (0x1EE37, 'M', u'خ'), - (0x1EE38, 'X'), - (0x1EE39, 'M', u'ض'), - (0x1EE3A, 'X'), - (0x1EE3B, 'M', u'غ'), - (0x1EE3C, 'X'), - (0x1EE42, 'M', u'ج'), - (0x1EE43, 'X'), - (0x1EE47, 'M', u'ح'), - (0x1EE48, 'X'), - (0x1EE49, 'M', u'ي'), - (0x1EE4A, 'X'), - (0x1EE4B, 'M', u'ل'), - (0x1EE4C, 'X'), - (0x1EE4D, 'M', u'ن'), - (0x1EE4E, 'M', u'س'), - (0x1EE4F, 'M', u'ع'), - (0x1EE50, 'X'), - (0x1EE51, 'M', u'ص'), - (0x1EE52, 'M', u'ق'), - (0x1EE53, 'X'), - (0x1EE54, 'M', u'ش'), - (0x1EE55, 'X'), - (0x1EE57, 'M', u'خ'), - (0x1EE58, 'X'), - (0x1EE59, 'M', u'ض'), - (0x1EE5A, 'X'), - (0x1EE5B, 'M', u'غ'), - (0x1EE5C, 'X'), - (0x1EE5D, 'M', u'ں'), - (0x1EE5E, 'X'), - (0x1EE5F, 'M', u'ٯ'), - (0x1EE60, 'X'), - (0x1EE61, 'M', u'ب'), - (0x1EE62, 'M', u'ج'), - (0x1EE63, 'X'), - (0x1EE64, 'M', u'ه'), - (0x1EE65, 'X'), - (0x1EE67, 'M', u'ح'), - (0x1EE68, 'M', u'ط'), - (0x1EE69, 'M', u'ي'), - (0x1EE6A, 'M', u'ك'), - ] - -def _seg_71(): - return [ - (0x1EE6B, 'X'), - (0x1EE6C, 'M', u'م'), - (0x1EE6D, 'M', u'ن'), - (0x1EE6E, 'M', u'س'), - (0x1EE6F, 'M', u'ع'), - (0x1EE70, 'M', u'ف'), - (0x1EE71, 'M', u'ص'), - (0x1EE72, 'M', u'ق'), - (0x1EE73, 'X'), - (0x1EE74, 'M', u'ش'), - (0x1EE75, 'M', u'ت'), - (0x1EE76, 'M', u'ث'), - (0x1EE77, 'M', u'خ'), - (0x1EE78, 'X'), - (0x1EE79, 'M', u'ض'), - (0x1EE7A, 'M', u'ظ'), - (0x1EE7B, 'M', u'غ'), - (0x1EE7C, 'M', u'ٮ'), - (0x1EE7D, 'X'), - (0x1EE7E, 'M', u'ڡ'), - (0x1EE7F, 'X'), - (0x1EE80, 'M', u'ا'), - (0x1EE81, 'M', u'ب'), - (0x1EE82, 'M', u'ج'), - (0x1EE83, 'M', u'د'), - (0x1EE84, 'M', u'ه'), - (0x1EE85, 'M', u'و'), - (0x1EE86, 'M', u'ز'), - (0x1EE87, 'M', u'ح'), - (0x1EE88, 'M', u'ط'), - (0x1EE89, 'M', u'ي'), - (0x1EE8A, 'X'), - (0x1EE8B, 'M', u'ل'), - (0x1EE8C, 'M', u'م'), - (0x1EE8D, 'M', u'ن'), - (0x1EE8E, 'M', u'س'), - (0x1EE8F, 'M', u'ع'), - (0x1EE90, 'M', u'ف'), - (0x1EE91, 'M', u'ص'), - (0x1EE92, 'M', u'ق'), - (0x1EE93, 'M', u'ر'), - (0x1EE94, 'M', u'ش'), - (0x1EE95, 'M', u'ت'), - (0x1EE96, 'M', u'ث'), - (0x1EE97, 'M', u'خ'), - (0x1EE98, 'M', u'ذ'), - (0x1EE99, 'M', u'ض'), - (0x1EE9A, 'M', u'ظ'), - (0x1EE9B, 'M', u'غ'), - (0x1EE9C, 'X'), - (0x1EEA1, 'M', u'ب'), - (0x1EEA2, 'M', u'ج'), - (0x1EEA3, 'M', u'د'), - (0x1EEA4, 'X'), - (0x1EEA5, 'M', u'و'), - (0x1EEA6, 'M', u'ز'), - (0x1EEA7, 'M', u'ح'), - (0x1EEA8, 'M', u'ط'), - (0x1EEA9, 'M', u'ي'), - (0x1EEAA, 'X'), - (0x1EEAB, 'M', u'ل'), - (0x1EEAC, 'M', u'م'), - (0x1EEAD, 'M', u'ن'), - (0x1EEAE, 'M', u'س'), - (0x1EEAF, 'M', u'ع'), - (0x1EEB0, 'M', u'ف'), - (0x1EEB1, 'M', u'ص'), - (0x1EEB2, 'M', u'ق'), - (0x1EEB3, 'M', u'ر'), - (0x1EEB4, 'M', u'ش'), - (0x1EEB5, 'M', u'ت'), - (0x1EEB6, 'M', u'ث'), - (0x1EEB7, 'M', u'خ'), - (0x1EEB8, 'M', u'ذ'), - (0x1EEB9, 'M', u'ض'), - (0x1EEBA, 'M', u'ظ'), - (0x1EEBB, 'M', u'غ'), - (0x1EEBC, 'X'), - (0x1EEF0, 'V'), - (0x1EEF2, 'X'), - (0x1F000, 'V'), - (0x1F02C, 'X'), - (0x1F030, 'V'), - (0x1F094, 'X'), - (0x1F0A0, 'V'), - (0x1F0AF, 'X'), - (0x1F0B1, 'V'), - (0x1F0C0, 'X'), - (0x1F0C1, 'V'), - (0x1F0D0, 'X'), - (0x1F0D1, 'V'), - (0x1F0F6, 'X'), - (0x1F101, '3', u'0,'), - (0x1F102, '3', u'1,'), - (0x1F103, '3', u'2,'), - (0x1F104, '3', u'3,'), - (0x1F105, '3', u'4,'), - (0x1F106, '3', u'5,'), - (0x1F107, '3', u'6,'), - (0x1F108, '3', u'7,'), - ] - -def _seg_72(): - return [ - (0x1F109, '3', u'8,'), - (0x1F10A, '3', u'9,'), - (0x1F10B, 'V'), - (0x1F110, '3', u'(a)'), - (0x1F111, '3', u'(b)'), - (0x1F112, '3', u'(c)'), - (0x1F113, '3', u'(d)'), - (0x1F114, '3', u'(e)'), - (0x1F115, '3', u'(f)'), - (0x1F116, '3', u'(g)'), - (0x1F117, '3', u'(h)'), - (0x1F118, '3', u'(i)'), - (0x1F119, '3', u'(j)'), - (0x1F11A, '3', u'(k)'), - (0x1F11B, '3', u'(l)'), - (0x1F11C, '3', u'(m)'), - (0x1F11D, '3', u'(n)'), - (0x1F11E, '3', u'(o)'), - (0x1F11F, '3', u'(p)'), - (0x1F120, '3', u'(q)'), - (0x1F121, '3', u'(r)'), - (0x1F122, '3', u'(s)'), - (0x1F123, '3', u'(t)'), - (0x1F124, '3', u'(u)'), - (0x1F125, '3', u'(v)'), - (0x1F126, '3', u'(w)'), - (0x1F127, '3', u'(x)'), - (0x1F128, '3', u'(y)'), - (0x1F129, '3', u'(z)'), - (0x1F12A, 'M', u'〔s〕'), - (0x1F12B, 'M', u'c'), - (0x1F12C, 'M', u'r'), - (0x1F12D, 'M', u'cd'), - (0x1F12E, 'M', u'wz'), - (0x1F12F, 'V'), - (0x1F130, 'M', u'a'), - (0x1F131, 'M', u'b'), - (0x1F132, 'M', u'c'), - (0x1F133, 'M', u'd'), - (0x1F134, 'M', u'e'), - (0x1F135, 'M', u'f'), - (0x1F136, 'M', u'g'), - (0x1F137, 'M', u'h'), - (0x1F138, 'M', u'i'), - (0x1F139, 'M', u'j'), - (0x1F13A, 'M', u'k'), - (0x1F13B, 'M', u'l'), - (0x1F13C, 'M', u'm'), - (0x1F13D, 'M', u'n'), - (0x1F13E, 'M', u'o'), - (0x1F13F, 'M', u'p'), - (0x1F140, 'M', u'q'), - (0x1F141, 'M', u'r'), - (0x1F142, 'M', u's'), - (0x1F143, 'M', u't'), - (0x1F144, 'M', u'u'), - (0x1F145, 'M', u'v'), - (0x1F146, 'M', u'w'), - (0x1F147, 'M', u'x'), - (0x1F148, 'M', u'y'), - (0x1F149, 'M', u'z'), - (0x1F14A, 'M', u'hv'), - (0x1F14B, 'M', u'mv'), - (0x1F14C, 'M', u'sd'), - (0x1F14D, 'M', u'ss'), - (0x1F14E, 'M', u'ppv'), - (0x1F14F, 'M', u'wc'), - (0x1F150, 'V'), - (0x1F16A, 'M', u'mc'), - (0x1F16B, 'M', u'md'), - (0x1F16C, 'M', u'mr'), - (0x1F16D, 'V'), - (0x1F190, 'M', u'dj'), - (0x1F191, 'V'), - (0x1F1AE, 'X'), - (0x1F1E6, 'V'), - (0x1F200, 'M', u'ほか'), - (0x1F201, 'M', u'ココ'), - (0x1F202, 'M', u'サ'), - (0x1F203, 'X'), - (0x1F210, 'M', u'手'), - (0x1F211, 'M', u'字'), - (0x1F212, 'M', u'双'), - (0x1F213, 'M', u'デ'), - (0x1F214, 'M', u'二'), - (0x1F215, 'M', u'多'), - (0x1F216, 'M', u'解'), - (0x1F217, 'M', u'天'), - (0x1F218, 'M', u'交'), - (0x1F219, 'M', u'映'), - (0x1F21A, 'M', u'無'), - (0x1F21B, 'M', u'料'), - (0x1F21C, 'M', u'前'), - (0x1F21D, 'M', u'後'), - (0x1F21E, 'M', u'再'), - (0x1F21F, 'M', u'新'), - (0x1F220, 'M', u'初'), - (0x1F221, 'M', u'終'), - (0x1F222, 'M', u'生'), - (0x1F223, 'M', u'販'), - ] - -def _seg_73(): - return [ - (0x1F224, 'M', u'声'), - (0x1F225, 'M', u'吹'), - (0x1F226, 'M', u'演'), - (0x1F227, 'M', u'投'), - (0x1F228, 'M', u'捕'), - (0x1F229, 'M', u'一'), - (0x1F22A, 'M', u'三'), - (0x1F22B, 'M', u'遊'), - (0x1F22C, 'M', u'左'), - (0x1F22D, 'M', u'中'), - (0x1F22E, 'M', u'右'), - (0x1F22F, 'M', u'指'), - (0x1F230, 'M', u'走'), - (0x1F231, 'M', u'打'), - (0x1F232, 'M', u'禁'), - (0x1F233, 'M', u'空'), - (0x1F234, 'M', u'合'), - (0x1F235, 'M', u'満'), - (0x1F236, 'M', u'有'), - (0x1F237, 'M', u'月'), - (0x1F238, 'M', u'申'), - (0x1F239, 'M', u'割'), - (0x1F23A, 'M', u'営'), - (0x1F23B, 'M', u'配'), - (0x1F23C, 'X'), - (0x1F240, 'M', u'〔本〕'), - (0x1F241, 'M', u'〔三〕'), - (0x1F242, 'M', u'〔二〕'), - (0x1F243, 'M', u'〔安〕'), - (0x1F244, 'M', u'〔点〕'), - (0x1F245, 'M', u'〔打〕'), - (0x1F246, 'M', u'〔盗〕'), - (0x1F247, 'M', u'〔勝〕'), - (0x1F248, 'M', u'〔敗〕'), - (0x1F249, 'X'), - (0x1F250, 'M', u'得'), - (0x1F251, 'M', u'可'), - (0x1F252, 'X'), - (0x1F260, 'V'), - (0x1F266, 'X'), - (0x1F300, 'V'), - (0x1F6D8, 'X'), - (0x1F6E0, 'V'), - (0x1F6ED, 'X'), - (0x1F6F0, 'V'), - (0x1F6FD, 'X'), - (0x1F700, 'V'), - (0x1F774, 'X'), - (0x1F780, 'V'), - (0x1F7D9, 'X'), - (0x1F7E0, 'V'), - (0x1F7EC, 'X'), - (0x1F800, 'V'), - (0x1F80C, 'X'), - (0x1F810, 'V'), - (0x1F848, 'X'), - (0x1F850, 'V'), - (0x1F85A, 'X'), - (0x1F860, 'V'), - (0x1F888, 'X'), - (0x1F890, 'V'), - (0x1F8AE, 'X'), - (0x1F8B0, 'V'), - (0x1F8B2, 'X'), - (0x1F900, 'V'), - (0x1F979, 'X'), - (0x1F97A, 'V'), - (0x1F9CC, 'X'), - (0x1F9CD, 'V'), - (0x1FA54, 'X'), - (0x1FA60, 'V'), - (0x1FA6E, 'X'), - (0x1FA70, 'V'), - (0x1FA75, 'X'), - (0x1FA78, 'V'), - (0x1FA7B, 'X'), - (0x1FA80, 'V'), - (0x1FA87, 'X'), - (0x1FA90, 'V'), - (0x1FAA9, 'X'), - (0x1FAB0, 'V'), - (0x1FAB7, 'X'), - (0x1FAC0, 'V'), - (0x1FAC3, 'X'), - (0x1FAD0, 'V'), - (0x1FAD7, 'X'), - (0x1FB00, 'V'), - (0x1FB93, 'X'), - (0x1FB94, 'V'), - (0x1FBCB, 'X'), - (0x1FBF0, 'M', u'0'), - (0x1FBF1, 'M', u'1'), - (0x1FBF2, 'M', u'2'), - (0x1FBF3, 'M', u'3'), - (0x1FBF4, 'M', u'4'), - (0x1FBF5, 'M', u'5'), - (0x1FBF6, 'M', u'6'), - (0x1FBF7, 'M', u'7'), - (0x1FBF8, 'M', u'8'), - (0x1FBF9, 'M', u'9'), - ] - -def _seg_74(): - return [ - (0x1FBFA, 'X'), - (0x20000, 'V'), - (0x2A6DE, 'X'), - (0x2A700, 'V'), - (0x2B735, 'X'), - (0x2B740, 'V'), - (0x2B81E, 'X'), - (0x2B820, 'V'), - (0x2CEA2, 'X'), - (0x2CEB0, 'V'), - (0x2EBE1, 'X'), - (0x2F800, 'M', u'丽'), - (0x2F801, 'M', u'丸'), - (0x2F802, 'M', u'乁'), - (0x2F803, 'M', u'𠄢'), - (0x2F804, 'M', u'你'), - (0x2F805, 'M', u'侮'), - (0x2F806, 'M', u'侻'), - (0x2F807, 'M', u'倂'), - (0x2F808, 'M', u'偺'), - (0x2F809, 'M', u'備'), - (0x2F80A, 'M', u'僧'), - (0x2F80B, 'M', u'像'), - (0x2F80C, 'M', u'㒞'), - (0x2F80D, 'M', u'𠘺'), - (0x2F80E, 'M', u'免'), - (0x2F80F, 'M', u'兔'), - (0x2F810, 'M', u'兤'), - (0x2F811, 'M', u'具'), - (0x2F812, 'M', u'𠔜'), - (0x2F813, 'M', u'㒹'), - (0x2F814, 'M', u'內'), - (0x2F815, 'M', u'再'), - (0x2F816, 'M', u'𠕋'), - (0x2F817, 'M', u'冗'), - (0x2F818, 'M', u'冤'), - (0x2F819, 'M', u'仌'), - (0x2F81A, 'M', u'冬'), - (0x2F81B, 'M', u'况'), - (0x2F81C, 'M', u'𩇟'), - (0x2F81D, 'M', u'凵'), - (0x2F81E, 'M', u'刃'), - (0x2F81F, 'M', u'㓟'), - (0x2F820, 'M', u'刻'), - (0x2F821, 'M', u'剆'), - (0x2F822, 'M', u'割'), - (0x2F823, 'M', u'剷'), - (0x2F824, 'M', u'㔕'), - (0x2F825, 'M', u'勇'), - (0x2F826, 'M', u'勉'), - (0x2F827, 'M', u'勤'), - (0x2F828, 'M', u'勺'), - (0x2F829, 'M', u'包'), - (0x2F82A, 'M', u'匆'), - (0x2F82B, 'M', u'北'), - (0x2F82C, 'M', u'卉'), - (0x2F82D, 'M', u'卑'), - (0x2F82E, 'M', u'博'), - (0x2F82F, 'M', u'即'), - (0x2F830, 'M', u'卽'), - (0x2F831, 'M', u'卿'), - (0x2F834, 'M', u'𠨬'), - (0x2F835, 'M', u'灰'), - (0x2F836, 'M', u'及'), - (0x2F837, 'M', u'叟'), - (0x2F838, 'M', u'𠭣'), - (0x2F839, 'M', u'叫'), - (0x2F83A, 'M', u'叱'), - (0x2F83B, 'M', u'吆'), - (0x2F83C, 'M', u'咞'), - (0x2F83D, 'M', u'吸'), - (0x2F83E, 'M', u'呈'), - (0x2F83F, 'M', u'周'), - (0x2F840, 'M', u'咢'), - (0x2F841, 'M', u'哶'), - (0x2F842, 'M', u'唐'), - (0x2F843, 'M', u'啓'), - (0x2F844, 'M', u'啣'), - (0x2F845, 'M', u'善'), - (0x2F847, 'M', u'喙'), - (0x2F848, 'M', u'喫'), - (0x2F849, 'M', u'喳'), - (0x2F84A, 'M', u'嗂'), - (0x2F84B, 'M', u'圖'), - (0x2F84C, 'M', u'嘆'), - (0x2F84D, 'M', u'圗'), - (0x2F84E, 'M', u'噑'), - (0x2F84F, 'M', u'噴'), - (0x2F850, 'M', u'切'), - (0x2F851, 'M', u'壮'), - (0x2F852, 'M', u'城'), - (0x2F853, 'M', u'埴'), - (0x2F854, 'M', u'堍'), - (0x2F855, 'M', u'型'), - (0x2F856, 'M', u'堲'), - (0x2F857, 'M', u'報'), - (0x2F858, 'M', u'墬'), - (0x2F859, 'M', u'𡓤'), - (0x2F85A, 'M', u'売'), - (0x2F85B, 'M', u'壷'), - ] - -def _seg_75(): - return [ - (0x2F85C, 'M', u'夆'), - (0x2F85D, 'M', u'多'), - (0x2F85E, 'M', u'夢'), - (0x2F85F, 'M', u'奢'), - (0x2F860, 'M', u'𡚨'), - (0x2F861, 'M', u'𡛪'), - (0x2F862, 'M', u'姬'), - (0x2F863, 'M', u'娛'), - (0x2F864, 'M', u'娧'), - (0x2F865, 'M', u'姘'), - (0x2F866, 'M', u'婦'), - (0x2F867, 'M', u'㛮'), - (0x2F868, 'X'), - (0x2F869, 'M', u'嬈'), - (0x2F86A, 'M', u'嬾'), - (0x2F86C, 'M', u'𡧈'), - (0x2F86D, 'M', u'寃'), - (0x2F86E, 'M', u'寘'), - (0x2F86F, 'M', u'寧'), - (0x2F870, 'M', u'寳'), - (0x2F871, 'M', u'𡬘'), - (0x2F872, 'M', u'寿'), - (0x2F873, 'M', u'将'), - (0x2F874, 'X'), - (0x2F875, 'M', u'尢'), - (0x2F876, 'M', u'㞁'), - (0x2F877, 'M', u'屠'), - (0x2F878, 'M', u'屮'), - (0x2F879, 'M', u'峀'), - (0x2F87A, 'M', u'岍'), - (0x2F87B, 'M', u'𡷤'), - (0x2F87C, 'M', u'嵃'), - (0x2F87D, 'M', u'𡷦'), - (0x2F87E, 'M', u'嵮'), - (0x2F87F, 'M', u'嵫'), - (0x2F880, 'M', u'嵼'), - (0x2F881, 'M', u'巡'), - (0x2F882, 'M', u'巢'), - (0x2F883, 'M', u'㠯'), - (0x2F884, 'M', u'巽'), - (0x2F885, 'M', u'帨'), - (0x2F886, 'M', u'帽'), - (0x2F887, 'M', u'幩'), - (0x2F888, 'M', u'㡢'), - (0x2F889, 'M', u'𢆃'), - (0x2F88A, 'M', u'㡼'), - (0x2F88B, 'M', u'庰'), - (0x2F88C, 'M', u'庳'), - (0x2F88D, 'M', u'庶'), - (0x2F88E, 'M', u'廊'), - (0x2F88F, 'M', u'𪎒'), - (0x2F890, 'M', u'廾'), - (0x2F891, 'M', u'𢌱'), - (0x2F893, 'M', u'舁'), - (0x2F894, 'M', u'弢'), - (0x2F896, 'M', u'㣇'), - (0x2F897, 'M', u'𣊸'), - (0x2F898, 'M', u'𦇚'), - (0x2F899, 'M', u'形'), - (0x2F89A, 'M', u'彫'), - (0x2F89B, 'M', u'㣣'), - (0x2F89C, 'M', u'徚'), - (0x2F89D, 'M', u'忍'), - (0x2F89E, 'M', u'志'), - (0x2F89F, 'M', u'忹'), - (0x2F8A0, 'M', u'悁'), - (0x2F8A1, 'M', u'㤺'), - (0x2F8A2, 'M', u'㤜'), - (0x2F8A3, 'M', u'悔'), - (0x2F8A4, 'M', u'𢛔'), - (0x2F8A5, 'M', u'惇'), - (0x2F8A6, 'M', u'慈'), - (0x2F8A7, 'M', u'慌'), - (0x2F8A8, 'M', u'慎'), - (0x2F8A9, 'M', u'慌'), - (0x2F8AA, 'M', u'慺'), - (0x2F8AB, 'M', u'憎'), - (0x2F8AC, 'M', u'憲'), - (0x2F8AD, 'M', u'憤'), - (0x2F8AE, 'M', u'憯'), - (0x2F8AF, 'M', u'懞'), - (0x2F8B0, 'M', u'懲'), - (0x2F8B1, 'M', u'懶'), - (0x2F8B2, 'M', u'成'), - (0x2F8B3, 'M', u'戛'), - (0x2F8B4, 'M', u'扝'), - (0x2F8B5, 'M', u'抱'), - (0x2F8B6, 'M', u'拔'), - (0x2F8B7, 'M', u'捐'), - (0x2F8B8, 'M', u'𢬌'), - (0x2F8B9, 'M', u'挽'), - (0x2F8BA, 'M', u'拼'), - (0x2F8BB, 'M', u'捨'), - (0x2F8BC, 'M', u'掃'), - (0x2F8BD, 'M', u'揤'), - (0x2F8BE, 'M', u'𢯱'), - (0x2F8BF, 'M', u'搢'), - (0x2F8C0, 'M', u'揅'), - (0x2F8C1, 'M', u'掩'), - (0x2F8C2, 'M', u'㨮'), - ] - -def _seg_76(): - return [ - (0x2F8C3, 'M', u'摩'), - (0x2F8C4, 'M', u'摾'), - (0x2F8C5, 'M', u'撝'), - (0x2F8C6, 'M', u'摷'), - (0x2F8C7, 'M', u'㩬'), - (0x2F8C8, 'M', u'敏'), - (0x2F8C9, 'M', u'敬'), - (0x2F8CA, 'M', u'𣀊'), - (0x2F8CB, 'M', u'旣'), - (0x2F8CC, 'M', u'書'), - (0x2F8CD, 'M', u'晉'), - (0x2F8CE, 'M', u'㬙'), - (0x2F8CF, 'M', u'暑'), - (0x2F8D0, 'M', u'㬈'), - (0x2F8D1, 'M', u'㫤'), - (0x2F8D2, 'M', u'冒'), - (0x2F8D3, 'M', u'冕'), - (0x2F8D4, 'M', u'最'), - (0x2F8D5, 'M', u'暜'), - (0x2F8D6, 'M', u'肭'), - (0x2F8D7, 'M', u'䏙'), - (0x2F8D8, 'M', u'朗'), - (0x2F8D9, 'M', u'望'), - (0x2F8DA, 'M', u'朡'), - (0x2F8DB, 'M', u'杞'), - (0x2F8DC, 'M', u'杓'), - (0x2F8DD, 'M', u'𣏃'), - (0x2F8DE, 'M', u'㭉'), - (0x2F8DF, 'M', u'柺'), - (0x2F8E0, 'M', u'枅'), - (0x2F8E1, 'M', u'桒'), - (0x2F8E2, 'M', u'梅'), - (0x2F8E3, 'M', u'𣑭'), - (0x2F8E4, 'M', u'梎'), - (0x2F8E5, 'M', u'栟'), - (0x2F8E6, 'M', u'椔'), - (0x2F8E7, 'M', u'㮝'), - (0x2F8E8, 'M', u'楂'), - (0x2F8E9, 'M', u'榣'), - (0x2F8EA, 'M', u'槪'), - (0x2F8EB, 'M', u'檨'), - (0x2F8EC, 'M', u'𣚣'), - (0x2F8ED, 'M', u'櫛'), - (0x2F8EE, 'M', u'㰘'), - (0x2F8EF, 'M', u'次'), - (0x2F8F0, 'M', u'𣢧'), - (0x2F8F1, 'M', u'歔'), - (0x2F8F2, 'M', u'㱎'), - (0x2F8F3, 'M', u'歲'), - (0x2F8F4, 'M', u'殟'), - (0x2F8F5, 'M', u'殺'), - (0x2F8F6, 'M', u'殻'), - (0x2F8F7, 'M', u'𣪍'), - (0x2F8F8, 'M', u'𡴋'), - (0x2F8F9, 'M', u'𣫺'), - (0x2F8FA, 'M', u'汎'), - (0x2F8FB, 'M', u'𣲼'), - (0x2F8FC, 'M', u'沿'), - (0x2F8FD, 'M', u'泍'), - (0x2F8FE, 'M', u'汧'), - (0x2F8FF, 'M', u'洖'), - (0x2F900, 'M', u'派'), - (0x2F901, 'M', u'海'), - (0x2F902, 'M', u'流'), - (0x2F903, 'M', u'浩'), - (0x2F904, 'M', u'浸'), - (0x2F905, 'M', u'涅'), - (0x2F906, 'M', u'𣴞'), - (0x2F907, 'M', u'洴'), - (0x2F908, 'M', u'港'), - (0x2F909, 'M', u'湮'), - (0x2F90A, 'M', u'㴳'), - (0x2F90B, 'M', u'滋'), - (0x2F90C, 'M', u'滇'), - (0x2F90D, 'M', u'𣻑'), - (0x2F90E, 'M', u'淹'), - (0x2F90F, 'M', u'潮'), - (0x2F910, 'M', u'𣽞'), - (0x2F911, 'M', u'𣾎'), - (0x2F912, 'M', u'濆'), - (0x2F913, 'M', u'瀹'), - (0x2F914, 'M', u'瀞'), - (0x2F915, 'M', u'瀛'), - (0x2F916, 'M', u'㶖'), - (0x2F917, 'M', u'灊'), - (0x2F918, 'M', u'災'), - (0x2F919, 'M', u'灷'), - (0x2F91A, 'M', u'炭'), - (0x2F91B, 'M', u'𠔥'), - (0x2F91C, 'M', u'煅'), - (0x2F91D, 'M', u'𤉣'), - (0x2F91E, 'M', u'熜'), - (0x2F91F, 'X'), - (0x2F920, 'M', u'爨'), - (0x2F921, 'M', u'爵'), - (0x2F922, 'M', u'牐'), - (0x2F923, 'M', u'𤘈'), - (0x2F924, 'M', u'犀'), - (0x2F925, 'M', u'犕'), - (0x2F926, 'M', u'𤜵'), - ] - -def _seg_77(): - return [ - (0x2F927, 'M', u'𤠔'), - (0x2F928, 'M', u'獺'), - (0x2F929, 'M', u'王'), - (0x2F92A, 'M', u'㺬'), - (0x2F92B, 'M', u'玥'), - (0x2F92C, 'M', u'㺸'), - (0x2F92E, 'M', u'瑇'), - (0x2F92F, 'M', u'瑜'), - (0x2F930, 'M', u'瑱'), - (0x2F931, 'M', u'璅'), - (0x2F932, 'M', u'瓊'), - (0x2F933, 'M', u'㼛'), - (0x2F934, 'M', u'甤'), - (0x2F935, 'M', u'𤰶'), - (0x2F936, 'M', u'甾'), - (0x2F937, 'M', u'𤲒'), - (0x2F938, 'M', u'異'), - (0x2F939, 'M', u'𢆟'), - (0x2F93A, 'M', u'瘐'), - (0x2F93B, 'M', u'𤾡'), - (0x2F93C, 'M', u'𤾸'), - (0x2F93D, 'M', u'𥁄'), - (0x2F93E, 'M', u'㿼'), - (0x2F93F, 'M', u'䀈'), - (0x2F940, 'M', u'直'), - (0x2F941, 'M', u'𥃳'), - (0x2F942, 'M', u'𥃲'), - (0x2F943, 'M', u'𥄙'), - (0x2F944, 'M', u'𥄳'), - (0x2F945, 'M', u'眞'), - (0x2F946, 'M', u'真'), - (0x2F948, 'M', u'睊'), - (0x2F949, 'M', u'䀹'), - (0x2F94A, 'M', u'瞋'), - (0x2F94B, 'M', u'䁆'), - (0x2F94C, 'M', u'䂖'), - (0x2F94D, 'M', u'𥐝'), - (0x2F94E, 'M', u'硎'), - (0x2F94F, 'M', u'碌'), - (0x2F950, 'M', u'磌'), - (0x2F951, 'M', u'䃣'), - (0x2F952, 'M', u'𥘦'), - (0x2F953, 'M', u'祖'), - (0x2F954, 'M', u'𥚚'), - (0x2F955, 'M', u'𥛅'), - (0x2F956, 'M', u'福'), - (0x2F957, 'M', u'秫'), - (0x2F958, 'M', u'䄯'), - (0x2F959, 'M', u'穀'), - (0x2F95A, 'M', u'穊'), - (0x2F95B, 'M', u'穏'), - (0x2F95C, 'M', u'𥥼'), - (0x2F95D, 'M', u'𥪧'), - (0x2F95F, 'X'), - (0x2F960, 'M', u'䈂'), - (0x2F961, 'M', u'𥮫'), - (0x2F962, 'M', u'篆'), - (0x2F963, 'M', u'築'), - (0x2F964, 'M', u'䈧'), - (0x2F965, 'M', u'𥲀'), - (0x2F966, 'M', u'糒'), - (0x2F967, 'M', u'䊠'), - (0x2F968, 'M', u'糨'), - (0x2F969, 'M', u'糣'), - (0x2F96A, 'M', u'紀'), - (0x2F96B, 'M', u'𥾆'), - (0x2F96C, 'M', u'絣'), - (0x2F96D, 'M', u'䌁'), - (0x2F96E, 'M', u'緇'), - (0x2F96F, 'M', u'縂'), - (0x2F970, 'M', u'繅'), - (0x2F971, 'M', u'䌴'), - (0x2F972, 'M', u'𦈨'), - (0x2F973, 'M', u'𦉇'), - (0x2F974, 'M', u'䍙'), - (0x2F975, 'M', u'𦋙'), - (0x2F976, 'M', u'罺'), - (0x2F977, 'M', u'𦌾'), - (0x2F978, 'M', u'羕'), - (0x2F979, 'M', u'翺'), - (0x2F97A, 'M', u'者'), - (0x2F97B, 'M', u'𦓚'), - (0x2F97C, 'M', u'𦔣'), - (0x2F97D, 'M', u'聠'), - (0x2F97E, 'M', u'𦖨'), - (0x2F97F, 'M', u'聰'), - (0x2F980, 'M', u'𣍟'), - (0x2F981, 'M', u'䏕'), - (0x2F982, 'M', u'育'), - (0x2F983, 'M', u'脃'), - (0x2F984, 'M', u'䐋'), - (0x2F985, 'M', u'脾'), - (0x2F986, 'M', u'媵'), - (0x2F987, 'M', u'𦞧'), - (0x2F988, 'M', u'𦞵'), - (0x2F989, 'M', u'𣎓'), - (0x2F98A, 'M', u'𣎜'), - (0x2F98B, 'M', u'舁'), - (0x2F98C, 'M', u'舄'), - (0x2F98D, 'M', u'辞'), - ] - -def _seg_78(): - return [ - (0x2F98E, 'M', u'䑫'), - (0x2F98F, 'M', u'芑'), - (0x2F990, 'M', u'芋'), - (0x2F991, 'M', u'芝'), - (0x2F992, 'M', u'劳'), - (0x2F993, 'M', u'花'), - (0x2F994, 'M', u'芳'), - (0x2F995, 'M', u'芽'), - (0x2F996, 'M', u'苦'), - (0x2F997, 'M', u'𦬼'), - (0x2F998, 'M', u'若'), - (0x2F999, 'M', u'茝'), - (0x2F99A, 'M', u'荣'), - (0x2F99B, 'M', u'莭'), - (0x2F99C, 'M', u'茣'), - (0x2F99D, 'M', u'莽'), - (0x2F99E, 'M', u'菧'), - (0x2F99F, 'M', u'著'), - (0x2F9A0, 'M', u'荓'), - (0x2F9A1, 'M', u'菊'), - (0x2F9A2, 'M', u'菌'), - (0x2F9A3, 'M', u'菜'), - (0x2F9A4, 'M', u'𦰶'), - (0x2F9A5, 'M', u'𦵫'), - (0x2F9A6, 'M', u'𦳕'), - (0x2F9A7, 'M', u'䔫'), - (0x2F9A8, 'M', u'蓱'), - (0x2F9A9, 'M', u'蓳'), - (0x2F9AA, 'M', u'蔖'), - (0x2F9AB, 'M', u'𧏊'), - (0x2F9AC, 'M', u'蕤'), - (0x2F9AD, 'M', u'𦼬'), - (0x2F9AE, 'M', u'䕝'), - (0x2F9AF, 'M', u'䕡'), - (0x2F9B0, 'M', u'𦾱'), - (0x2F9B1, 'M', u'𧃒'), - (0x2F9B2, 'M', u'䕫'), - (0x2F9B3, 'M', u'虐'), - (0x2F9B4, 'M', u'虜'), - (0x2F9B5, 'M', u'虧'), - (0x2F9B6, 'M', u'虩'), - (0x2F9B7, 'M', u'蚩'), - (0x2F9B8, 'M', u'蚈'), - (0x2F9B9, 'M', u'蜎'), - (0x2F9BA, 'M', u'蛢'), - (0x2F9BB, 'M', u'蝹'), - (0x2F9BC, 'M', u'蜨'), - (0x2F9BD, 'M', u'蝫'), - (0x2F9BE, 'M', u'螆'), - (0x2F9BF, 'X'), - (0x2F9C0, 'M', u'蟡'), - (0x2F9C1, 'M', u'蠁'), - (0x2F9C2, 'M', u'䗹'), - (0x2F9C3, 'M', u'衠'), - (0x2F9C4, 'M', u'衣'), - (0x2F9C5, 'M', u'𧙧'), - (0x2F9C6, 'M', u'裗'), - (0x2F9C7, 'M', u'裞'), - (0x2F9C8, 'M', u'䘵'), - (0x2F9C9, 'M', u'裺'), - (0x2F9CA, 'M', u'㒻'), - (0x2F9CB, 'M', u'𧢮'), - (0x2F9CC, 'M', u'𧥦'), - (0x2F9CD, 'M', u'䚾'), - (0x2F9CE, 'M', u'䛇'), - (0x2F9CF, 'M', u'誠'), - (0x2F9D0, 'M', u'諭'), - (0x2F9D1, 'M', u'變'), - (0x2F9D2, 'M', u'豕'), - (0x2F9D3, 'M', u'𧲨'), - (0x2F9D4, 'M', u'貫'), - (0x2F9D5, 'M', u'賁'), - (0x2F9D6, 'M', u'贛'), - (0x2F9D7, 'M', u'起'), - (0x2F9D8, 'M', u'𧼯'), - (0x2F9D9, 'M', u'𠠄'), - (0x2F9DA, 'M', u'跋'), - (0x2F9DB, 'M', u'趼'), - (0x2F9DC, 'M', u'跰'), - (0x2F9DD, 'M', u'𠣞'), - (0x2F9DE, 'M', u'軔'), - (0x2F9DF, 'M', u'輸'), - (0x2F9E0, 'M', u'𨗒'), - (0x2F9E1, 'M', u'𨗭'), - (0x2F9E2, 'M', u'邔'), - (0x2F9E3, 'M', u'郱'), - (0x2F9E4, 'M', u'鄑'), - (0x2F9E5, 'M', u'𨜮'), - (0x2F9E6, 'M', u'鄛'), - (0x2F9E7, 'M', u'鈸'), - (0x2F9E8, 'M', u'鋗'), - (0x2F9E9, 'M', u'鋘'), - (0x2F9EA, 'M', u'鉼'), - (0x2F9EB, 'M', u'鏹'), - (0x2F9EC, 'M', u'鐕'), - (0x2F9ED, 'M', u'𨯺'), - (0x2F9EE, 'M', u'開'), - (0x2F9EF, 'M', u'䦕'), - (0x2F9F0, 'M', u'閷'), - (0x2F9F1, 'M', u'𨵷'), - ] - -def _seg_79(): - return [ - (0x2F9F2, 'M', u'䧦'), - (0x2F9F3, 'M', u'雃'), - (0x2F9F4, 'M', u'嶲'), - (0x2F9F5, 'M', u'霣'), - (0x2F9F6, 'M', u'𩅅'), - (0x2F9F7, 'M', u'𩈚'), - (0x2F9F8, 'M', u'䩮'), - (0x2F9F9, 'M', u'䩶'), - (0x2F9FA, 'M', u'韠'), - (0x2F9FB, 'M', u'𩐊'), - (0x2F9FC, 'M', u'䪲'), - (0x2F9FD, 'M', u'𩒖'), - (0x2F9FE, 'M', u'頋'), - (0x2FA00, 'M', u'頩'), - (0x2FA01, 'M', u'𩖶'), - (0x2FA02, 'M', u'飢'), - (0x2FA03, 'M', u'䬳'), - (0x2FA04, 'M', u'餩'), - (0x2FA05, 'M', u'馧'), - (0x2FA06, 'M', u'駂'), - (0x2FA07, 'M', u'駾'), - (0x2FA08, 'M', u'䯎'), - (0x2FA09, 'M', u'𩬰'), - (0x2FA0A, 'M', u'鬒'), - (0x2FA0B, 'M', u'鱀'), - (0x2FA0C, 'M', u'鳽'), - (0x2FA0D, 'M', u'䳎'), - (0x2FA0E, 'M', u'䳭'), - (0x2FA0F, 'M', u'鵧'), - (0x2FA10, 'M', u'𪃎'), - (0x2FA11, 'M', u'䳸'), - (0x2FA12, 'M', u'𪄅'), - (0x2FA13, 'M', u'𪈎'), - (0x2FA14, 'M', u'𪊑'), - (0x2FA15, 'M', u'麻'), - (0x2FA16, 'M', u'䵖'), - (0x2FA17, 'M', u'黹'), - (0x2FA18, 'M', u'黾'), - (0x2FA19, 'M', u'鼅'), - (0x2FA1A, 'M', u'鼏'), - (0x2FA1B, 'M', u'鼖'), - (0x2FA1C, 'M', u'鼻'), - (0x2FA1D, 'M', u'𪘀'), - (0x2FA1E, 'X'), - (0x30000, 'V'), - (0x3134B, 'X'), - (0xE0100, 'I'), - (0xE01F0, 'X'), - ] - -uts46data = tuple( - _seg_0() - + _seg_1() - + _seg_2() - + _seg_3() - + _seg_4() - + _seg_5() - + _seg_6() - + _seg_7() - + _seg_8() - + _seg_9() - + _seg_10() - + _seg_11() - + _seg_12() - + _seg_13() - + _seg_14() - + _seg_15() - + _seg_16() - + _seg_17() - + _seg_18() - + _seg_19() - + _seg_20() - + _seg_21() - + _seg_22() - + _seg_23() - + _seg_24() - + _seg_25() - + _seg_26() - + _seg_27() - + _seg_28() - + _seg_29() - + _seg_30() - + _seg_31() - + _seg_32() - + _seg_33() - + _seg_34() - + _seg_35() - + _seg_36() - + _seg_37() - + _seg_38() - + _seg_39() - + _seg_40() - + _seg_41() - + _seg_42() - + _seg_43() - + _seg_44() - + _seg_45() - + _seg_46() - + _seg_47() - + _seg_48() - + _seg_49() - + _seg_50() - + _seg_51() - + _seg_52() - + _seg_53() - + _seg_54() - + _seg_55() - + _seg_56() - + _seg_57() - + _seg_58() - + _seg_59() - + _seg_60() - + _seg_61() - + _seg_62() - + _seg_63() - + _seg_64() - + _seg_65() - + _seg_66() - + _seg_67() - + _seg_68() - + _seg_69() - + _seg_70() - + _seg_71() - + _seg_72() - + _seg_73() - + _seg_74() - + _seg_75() - + _seg_76() - + _seg_77() - + _seg_78() - + _seg_79() -) diff --git a/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/INSTALLER b/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/LICENSE.txt b/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/LICENSE.txt deleted file mode 100644 index 737fec5..0000000 --- a/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/LICENSE.txt +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2008-2019 The pip developers (see AUTHORS.txt file) - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/METADATA b/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/METADATA deleted file mode 100644 index 1413a04..0000000 --- a/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/METADATA +++ /dev/null @@ -1,87 +0,0 @@ -Metadata-Version: 2.1 -Name: pip -Version: 20.1.1 -Summary: The PyPA recommended tool for installing Python packages. -Home-page: https://pip.pypa.io/ -Author: The pip developers -Author-email: pypa-dev@groups.google.com -License: MIT -Project-URL: Documentation, https://pip.pypa.io -Project-URL: Source, https://github.com/pypa/pip -Keywords: distutils easy_install egg setuptools wheel virtualenv -Platform: UNKNOWN -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: MIT License -Classifier: Topic :: Software Development :: Build Tools -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 :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Requires-Python: >=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.* - -pip - The Python Package Installer -================================== - -.. image:: https://img.shields.io/pypi/v/pip.svg - :target: https://pypi.org/project/pip/ - -.. image:: https://readthedocs.org/projects/pip/badge/?version=latest - :target: https://pip.pypa.io/en/latest - -pip is the `package installer`_ for Python. You can use pip to install packages from the `Python Package Index`_ and other indexes. - -Please take a look at our documentation for how to install and use pip: - -* `Installation`_ -* `Usage`_ - -We release updates regularly, with a new version every 3 months. Find more details in our documentation: - -* `Release notes`_ -* `Release process`_ - -In 2020, we're working on improvements to the heart of pip. Please `learn more and take our survey`_ to help us do it right. - -If you find bugs, need help, or want to talk to the developers, please use our mailing lists or chat rooms: - -* `Issue tracking`_ -* `Discourse channel`_ -* `User IRC`_ - -If you want to get involved head over to GitHub to get the source code, look at our development documentation and feel free to jump on the developer mailing lists and chat rooms: - -* `GitHub page`_ -* `Development documentation`_ -* `Development mailing list`_ -* `Development IRC`_ - -Code of Conduct ---------------- - -Everyone interacting in the pip project's codebases, issue trackers, chat -rooms, and mailing lists is expected to follow the `PyPA Code of Conduct`_. - -.. _package installer: https://packaging.python.org/guides/tool-recommendations/ -.. _Python Package Index: https://pypi.org -.. _Installation: https://pip.pypa.io/en/stable/installing.html -.. _Usage: https://pip.pypa.io/en/stable/ -.. _Release notes: https://pip.pypa.io/en/stable/news.html -.. _Release process: https://pip.pypa.io/en/latest/development/release-process/ -.. _GitHub page: https://github.com/pypa/pip -.. _Development documentation: https://pip.pypa.io/en/latest/development -.. _learn more and take our survey: https://pyfound.blogspot.com/2020/03/new-pip-resolver-to-roll-out-this-year.html -.. _Issue tracking: https://github.com/pypa/pip/issues -.. _Discourse channel: https://discuss.python.org/c/packaging -.. _Development mailing list: https://groups.google.com/forum/#!forum/pypa-dev -.. _User IRC: https://webchat.freenode.net/?channels=%23pypa -.. _Development IRC: https://webchat.freenode.net/?channels=%23pypa-dev -.. _PyPA Code of Conduct: https://www.pypa.io/en/latest/code-of-conduct/ - - diff --git a/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/RECORD b/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/RECORD deleted file mode 100644 index f1a4bc9..0000000 --- a/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/RECORD +++ /dev/null @@ -1,272 +0,0 @@ -../../../bin/pip,sha256=8la4mTr7BY9yuqHo7raN_MZEVPRXD8ILt6zG5VmCPcU,256 -../../../bin/pip3,sha256=8la4mTr7BY9yuqHo7raN_MZEVPRXD8ILt6zG5VmCPcU,256 -../../../bin/pip3.8,sha256=8la4mTr7BY9yuqHo7raN_MZEVPRXD8ILt6zG5VmCPcU,256 -pip-20.1.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -pip-20.1.1.dist-info/LICENSE.txt,sha256=W6Ifuwlk-TatfRU2LR7W1JMcyMj5_y1NkRkOEJvnRDE,1090 -pip-20.1.1.dist-info/METADATA,sha256=dwRFheMvgIBpyZllM4tVlf5TfjoXc1ZxlsJf0ze61_M,3634 -pip-20.1.1.dist-info/RECORD,, -pip-20.1.1.dist-info/WHEEL,sha256=kGT74LWyRUZrL4VgLh6_g12IeVl_9u9ZVhadrgXZUEY,110 -pip-20.1.1.dist-info/entry_points.txt,sha256=HtfDOwpUlr9s73jqLQ6wF9V0_0qvUXJwCBz7Vwx0Ue0,125 -pip-20.1.1.dist-info/top_level.txt,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -pip/__init__.py,sha256=9lnkMA2mCKfgnTkqep7tMbosgEJ4rENcyu2tcqDwUNw,455 -pip/__main__.py,sha256=bqCAM1cj1HwHCDx3WJa-LJxOBXimGxE8OjBqAvnhVg0,911 -pip/__pycache__/__init__.cpython-38.pyc,, -pip/__pycache__/__main__.cpython-38.pyc,, -pip/_internal/__init__.py,sha256=2si23JBW1erg19xIJ8CD6tfGknz0ijtXmzuXjGfGMGE,495 -pip/_internal/__pycache__/__init__.cpython-38.pyc,, -pip/_internal/__pycache__/build_env.cpython-38.pyc,, -pip/_internal/__pycache__/cache.cpython-38.pyc,, -pip/_internal/__pycache__/configuration.cpython-38.pyc,, -pip/_internal/__pycache__/exceptions.cpython-38.pyc,, -pip/_internal/__pycache__/locations.cpython-38.pyc,, -pip/_internal/__pycache__/main.cpython-38.pyc,, -pip/_internal/__pycache__/pyproject.cpython-38.pyc,, -pip/_internal/__pycache__/self_outdated_check.cpython-38.pyc,, -pip/_internal/__pycache__/wheel_builder.cpython-38.pyc,, -pip/_internal/build_env.py,sha256=2P0xaKpDhEfrA5P7cXnbx9QpL52Hc1Uturp8EIcjGRg,7506 -pip/_internal/cache.py,sha256=aXPdcihRKQVH26jl1cxSKTmTnV0_hNMs7cGADMUFi1Y,12334 -pip/_internal/cli/__init__.py,sha256=FkHBgpxxb-_gd6r1FjnNhfMOzAUYyXoXKJ6abijfcFU,132 -pip/_internal/cli/__pycache__/__init__.cpython-38.pyc,, -pip/_internal/cli/__pycache__/autocompletion.cpython-38.pyc,, -pip/_internal/cli/__pycache__/base_command.cpython-38.pyc,, -pip/_internal/cli/__pycache__/cmdoptions.cpython-38.pyc,, -pip/_internal/cli/__pycache__/command_context.cpython-38.pyc,, -pip/_internal/cli/__pycache__/main.cpython-38.pyc,, -pip/_internal/cli/__pycache__/main_parser.cpython-38.pyc,, -pip/_internal/cli/__pycache__/parser.cpython-38.pyc,, -pip/_internal/cli/__pycache__/progress_bars.cpython-38.pyc,, -pip/_internal/cli/__pycache__/req_command.cpython-38.pyc,, -pip/_internal/cli/__pycache__/spinners.cpython-38.pyc,, -pip/_internal/cli/__pycache__/status_codes.cpython-38.pyc,, -pip/_internal/cli/autocompletion.py,sha256=ekGNtcDI0p7rFVc-7s4T9Tbss4Jgb7vsB649XJIblRg,6547 -pip/_internal/cli/base_command.py,sha256=O5fT5HHfc_UYNvhqK0rjfh_13K3fIVQzcKUF4xKbFts,8024 -pip/_internal/cli/cmdoptions.py,sha256=6m_aB70I097DJygO3Uh065ow5Mq1XKsGX-WozPoVX7I,28402 -pip/_internal/cli/command_context.py,sha256=ygMVoTy2jpNilKT-6416gFSQpaBtrKRBbVbi2fy__EU,975 -pip/_internal/cli/main.py,sha256=Hxc9dZyW3xiDsYZX-_J2cGXT5DWNLNn_Y7o9oUme-Ec,2616 -pip/_internal/cli/main_parser.py,sha256=voAtjo4WVPIYeu7Fqabva9SXaB3BjG0gH93GBfe6jHQ,2843 -pip/_internal/cli/parser.py,sha256=4FfwW8xB84CrkLs35ud90ZkhCcWyVkx17XD6j3XCW7c,9480 -pip/_internal/cli/progress_bars.py,sha256=WtKOHkePvHwnlhDUotAmKpjBH6hBdVTOnxSiiuCC2l8,9031 -pip/_internal/cli/req_command.py,sha256=NajtG3IfB3YkiM7LANLttyJTfPtgB-3CTErY0YR0k50,15309 -pip/_internal/cli/spinners.py,sha256=PS9s53LB5aDPelIn8FhKerK3bOdgeefFH5wSWJ2PCzI,5509 -pip/_internal/cli/status_codes.py,sha256=F6uDG6Gj7RNKQJUDnd87QKqI16Us-t-B0wPF_4QMpWc,156 -pip/_internal/commands/__init__.py,sha256=yoLAnmEXjoQgYfDuwsuWG3RzzD19oeHobGEhmpIYsB4,4100 -pip/_internal/commands/__pycache__/__init__.cpython-38.pyc,, -pip/_internal/commands/__pycache__/cache.cpython-38.pyc,, -pip/_internal/commands/__pycache__/check.cpython-38.pyc,, -pip/_internal/commands/__pycache__/completion.cpython-38.pyc,, -pip/_internal/commands/__pycache__/configuration.cpython-38.pyc,, -pip/_internal/commands/__pycache__/debug.cpython-38.pyc,, -pip/_internal/commands/__pycache__/download.cpython-38.pyc,, -pip/_internal/commands/__pycache__/freeze.cpython-38.pyc,, -pip/_internal/commands/__pycache__/hash.cpython-38.pyc,, -pip/_internal/commands/__pycache__/help.cpython-38.pyc,, -pip/_internal/commands/__pycache__/install.cpython-38.pyc,, -pip/_internal/commands/__pycache__/list.cpython-38.pyc,, -pip/_internal/commands/__pycache__/search.cpython-38.pyc,, -pip/_internal/commands/__pycache__/show.cpython-38.pyc,, -pip/_internal/commands/__pycache__/uninstall.cpython-38.pyc,, -pip/_internal/commands/__pycache__/wheel.cpython-38.pyc,, -pip/_internal/commands/cache.py,sha256=LZCLVEYCr5Ugh81Zt07Hz5v6SIt0QQzr2-npj3M44aE,5676 -pip/_internal/commands/check.py,sha256=fqRrz2uKPC8Qsx2rgLygAD2Rbr-qxp1Q55zUoyZzB9Q,1677 -pip/_internal/commands/completion.py,sha256=BoEW3RZQZhsZe5to1aOe245dcBLkf-PTCJL7_u9A-Es,2957 -pip/_internal/commands/configuration.py,sha256=y74Vl2p41dBOE2NwUzW4YqnbGbl9r0lsCyBlHguDAWA,7206 -pip/_internal/commands/debug.py,sha256=e02Tb4jG7RhyrxTjCRGo8J-Oy92Y7AhXp8L9JYJUj5w,8153 -pip/_internal/commands/download.py,sha256=thDfHi0qY6DQ_1GkYPTutwta3tA0RaHJhKycepC4FgA,4740 -pip/_internal/commands/freeze.py,sha256=gtUPVHnJ2qyx1o8E6e1ZkMTRzk8rGD6YJI1olILEYC4,3359 -pip/_internal/commands/hash.py,sha256=KckEd5FeomfsRgZmRzhJRPYSsz-HXbFZGNdrzp12ftQ,1742 -pip/_internal/commands/help.py,sha256=s8bDMJbRVxs9ehLKuD4mXTsv1bTRapy1jDwaTCE90qw,1193 -pip/_internal/commands/install.py,sha256=kKjVLbM30lHb2QmDvTyVHm3RGybaZyGTdE4AESPrd9k,26464 -pip/_internal/commands/list.py,sha256=QKQt4z9hVYYxU7vwHGubR2in2cuS_K-alUvC5WGUJ7s,10238 -pip/_internal/commands/search.py,sha256=KjAz-s9mwkiLfDd-cpQO3pL6KFoOyl1RKlvxnJj3zz8,5191 -pip/_internal/commands/show.py,sha256=RqSX_KvzcZWz1gxIOZEnnk4-VeSkNvr0yWz5jF6JrcY,6791 -pip/_internal/commands/uninstall.py,sha256=D2Otze7J-RJvjfozRq2Yon9NKJrg4cbBGFuXyEwBMR0,3202 -pip/_internal/commands/wheel.py,sha256=oxyo51V1m_Hu4U-HCS53vBx5-82Q6GOhn1doOgAr3KE,6431 -pip/_internal/configuration.py,sha256=k3Y3HMMMm_fzNqX75QoNuHvjX8tplmNBuIJJpDHmf9M,14349 -pip/_internal/distributions/__init__.py,sha256=ECBUW5Gtu9TjJwyFLvim-i6kUMYVuikNh9I5asL6tbA,959 -pip/_internal/distributions/__pycache__/__init__.cpython-38.pyc,, -pip/_internal/distributions/__pycache__/base.cpython-38.pyc,, -pip/_internal/distributions/__pycache__/installed.cpython-38.pyc,, -pip/_internal/distributions/__pycache__/sdist.cpython-38.pyc,, -pip/_internal/distributions/__pycache__/wheel.cpython-38.pyc,, -pip/_internal/distributions/base.py,sha256=ruprpM_L2T2HNi3KLUHlbHimZ1sWVw-3Q0Lb8O7TDAI,1425 -pip/_internal/distributions/installed.py,sha256=YqlkBKr6TVP1MAYS6SG8ojud21wVOYLMZ8jMLJe9MSU,760 -pip/_internal/distributions/sdist.py,sha256=D4XTMlCwgPlK69l62GLYkNSVTVe99fR5iAcVt2EbGok,4086 -pip/_internal/distributions/wheel.py,sha256=95uD-TfaYoq3KiKBdzk9YMN4RRqJ28LNoSTS2K46gek,1294 -pip/_internal/exceptions.py,sha256=B3tSkzheqSfGoGt5OcAOhLhfnWWMzfJ60URvZWwkwHw,10308 -pip/_internal/index/__init__.py,sha256=vpt-JeTZefh8a-FC22ZeBSXFVbuBcXSGiILhQZJaNpQ,30 -pip/_internal/index/__pycache__/__init__.cpython-38.pyc,, -pip/_internal/index/__pycache__/collector.cpython-38.pyc,, -pip/_internal/index/__pycache__/package_finder.cpython-38.pyc,, -pip/_internal/index/collector.py,sha256=tFpQdkBlbNzdwlep7a5_o9unymgWuEmo2WtARsagiao,21547 -pip/_internal/index/package_finder.py,sha256=2Uq4RPSRboyRPj1Zp3-SB8ZFNLAEMrZv6G2yH-wVjIA,37676 -pip/_internal/locations.py,sha256=vXf8886o1_lUY3jnT-0RMG1Puo64TgiuMIzccVawP4A,6873 -pip/_internal/main.py,sha256=IVBnUQ-FG7DK6617uEXRB5_QJqspAsBFmTmTesYkbdQ,437 -pip/_internal/models/__init__.py,sha256=3DHUd_qxpPozfzouoqa9g9ts1Czr5qaHfFxbnxriepM,63 -pip/_internal/models/__pycache__/__init__.cpython-38.pyc,, -pip/_internal/models/__pycache__/candidate.cpython-38.pyc,, -pip/_internal/models/__pycache__/direct_url.cpython-38.pyc,, -pip/_internal/models/__pycache__/format_control.cpython-38.pyc,, -pip/_internal/models/__pycache__/index.cpython-38.pyc,, -pip/_internal/models/__pycache__/link.cpython-38.pyc,, -pip/_internal/models/__pycache__/scheme.cpython-38.pyc,, -pip/_internal/models/__pycache__/search_scope.cpython-38.pyc,, -pip/_internal/models/__pycache__/selection_prefs.cpython-38.pyc,, -pip/_internal/models/__pycache__/target_python.cpython-38.pyc,, -pip/_internal/models/__pycache__/wheel.cpython-38.pyc,, -pip/_internal/models/candidate.py,sha256=Y58Bcm6oXUj0iS-yhmerlGo5CQJI2p0Ww9h6hR9zQDw,1150 -pip/_internal/models/direct_url.py,sha256=MnBLPci1hE9Ndh6d3m0LAqB7hX3ci80CCJTE5eerFaQ,6900 -pip/_internal/models/format_control.py,sha256=ICzVjjGwfZYdX-eLLKHjMHLutEJlAGpfj09OG_eMqac,2673 -pip/_internal/models/index.py,sha256=K59A8-hVhBM20Xkahr4dTwP7OjkJyEqXH11UwHFVgqM,1060 -pip/_internal/models/link.py,sha256=KobEaGViwOzyPBD7kgzpGqyrQfh5zjlonOStCGAhl2U,7302 -pip/_internal/models/scheme.py,sha256=vvhBrrno7eVDXcdKHiZWwxhPHf4VG5uSCEkC0QDR2RU,679 -pip/_internal/models/search_scope.py,sha256=AYbFyfEen5cx0kRZTMgUWUxzcMr5nDk32MO4S67Ror4,4712 -pip/_internal/models/selection_prefs.py,sha256=rPeif2KKjhTPXeMoQYffjqh10oWpXhdkxRDaPT1HO8k,1908 -pip/_internal/models/target_python.py,sha256=bbOSwPmojPMtCW6i2XMNjVJzt_2GQYfx3FcGQY8pL44,3842 -pip/_internal/models/wheel.py,sha256=FTfzVb4WIbfIehxhdlAVvCil_MQ0-W44oyN56cE6NHc,2772 -pip/_internal/network/__init__.py,sha256=jf6Tt5nV_7zkARBrKojIXItgejvoegVJVKUbhAa5Ioc,50 -pip/_internal/network/__pycache__/__init__.cpython-38.pyc,, -pip/_internal/network/__pycache__/auth.cpython-38.pyc,, -pip/_internal/network/__pycache__/cache.cpython-38.pyc,, -pip/_internal/network/__pycache__/download.cpython-38.pyc,, -pip/_internal/network/__pycache__/session.cpython-38.pyc,, -pip/_internal/network/__pycache__/utils.cpython-38.pyc,, -pip/_internal/network/__pycache__/xmlrpc.cpython-38.pyc,, -pip/_internal/network/auth.py,sha256=HJg5peC3gL44H7pmZhCPnu2MrwpAalOSF7d1jmNDqt8,11125 -pip/_internal/network/cache.py,sha256=51CExcRkXWrgMZ7WsrZ6cmijKfViD5tVgKbBvJHO1IE,2394 -pip/_internal/network/download.py,sha256=MIisedL1oFOSrYAN119HDlIuFfw6eL6CNY7oJhHIzUc,6269 -pip/_internal/network/session.py,sha256=Zs0uiyPxTpfpgSv-ZI9hK9TjasmTplBuBivOTcUiJME,15208 -pip/_internal/network/utils.py,sha256=iiixo1OeaQ3niUWiBjg59PN6f1w7vvTww1vFriTD_IU,1959 -pip/_internal/network/xmlrpc.py,sha256=AL115M3vFJ8xiHVJneb8Hi0ZFeRvdPhblC89w25OG5s,1597 -pip/_internal/operations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -pip/_internal/operations/__pycache__/__init__.cpython-38.pyc,, -pip/_internal/operations/__pycache__/check.cpython-38.pyc,, -pip/_internal/operations/__pycache__/freeze.cpython-38.pyc,, -pip/_internal/operations/__pycache__/prepare.cpython-38.pyc,, -pip/_internal/operations/build/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -pip/_internal/operations/build/__pycache__/__init__.cpython-38.pyc,, -pip/_internal/operations/build/__pycache__/metadata.cpython-38.pyc,, -pip/_internal/operations/build/__pycache__/metadata_legacy.cpython-38.pyc,, -pip/_internal/operations/build/__pycache__/wheel.cpython-38.pyc,, -pip/_internal/operations/build/__pycache__/wheel_legacy.cpython-38.pyc,, -pip/_internal/operations/build/metadata.py,sha256=yHMi5gHYXcXyHcvUPWHdO-UyOo3McFWljn_nHfM1O9c,1307 -pip/_internal/operations/build/metadata_legacy.py,sha256=VgzBTk8naIO8-8N_ifEYF7ZAxWUDhphWVIaVlZ2FqYM,2011 -pip/_internal/operations/build/wheel.py,sha256=ntltdNP6D2Tpr4V0agssu6rE0F9LaBpJkYT6zSdhEbw,1469 -pip/_internal/operations/build/wheel_legacy.py,sha256=N1aqNZyGURBX0Bj6wPmB0t4866oMbxoHUpC9pz6FyT0,3356 -pip/_internal/operations/check.py,sha256=a6uHG0daoWpmSPCdL7iYJaGQYZ-CRvPvTnCv2PnIIs0,5353 -pip/_internal/operations/freeze.py,sha256=mGT2OFjMOb0FlVjgedAzJ9GbNOgNwYiL0130xx60pHA,10587 -pip/_internal/operations/install/__init__.py,sha256=mX7hyD2GNBO2mFGokDQ30r_GXv7Y_PLdtxcUv144e-s,51 -pip/_internal/operations/install/__pycache__/__init__.cpython-38.pyc,, -pip/_internal/operations/install/__pycache__/editable_legacy.cpython-38.pyc,, -pip/_internal/operations/install/__pycache__/legacy.cpython-38.pyc,, -pip/_internal/operations/install/__pycache__/wheel.cpython-38.pyc,, -pip/_internal/operations/install/editable_legacy.py,sha256=rJ_xs2qtDUjpY2-n6eYlVyZiNoKbOtZXZrYrcnIELt4,1488 -pip/_internal/operations/install/legacy.py,sha256=YkKdL_tyNwDP2huOGxmopySh5Pz2v_wRVeSTEa6ZUco,4686 -pip/_internal/operations/install/wheel.py,sha256=8IO3GYTtrJ42cqipLOh0rxex4j-PfU8m71HVB0tOQd0,23885 -pip/_internal/operations/prepare.py,sha256=RDwtSetVTfv-nv1-_apYBA3Dez5ngBmOYzcuZy2Q3vk,20030 -pip/_internal/pyproject.py,sha256=VJKsrXORGiGoDPVKCQhuu4tWlQSTOhoiRlVLRNu4rx4,7400 -pip/_internal/req/__init__.py,sha256=UVaYPlHZVGRBQQPjvGC_6jJDQtewXm0ws-8Lxhg_TiY,2671 -pip/_internal/req/__pycache__/__init__.cpython-38.pyc,, -pip/_internal/req/__pycache__/constructors.cpython-38.pyc,, -pip/_internal/req/__pycache__/req_file.cpython-38.pyc,, -pip/_internal/req/__pycache__/req_install.cpython-38.pyc,, -pip/_internal/req/__pycache__/req_set.cpython-38.pyc,, -pip/_internal/req/__pycache__/req_tracker.cpython-38.pyc,, -pip/_internal/req/__pycache__/req_uninstall.cpython-38.pyc,, -pip/_internal/req/constructors.py,sha256=i_dU2sYtSk5GMsad68gBx26tfneRmhPF2sYGe4uPnu8,15441 -pip/_internal/req/req_file.py,sha256=5QlZr36kkw1Jsbr8vFO-fGUEAef9h-AoRRqjx8EYSuQ,19075 -pip/_internal/req/req_install.py,sha256=9yn_fBFTyzHPMjYG5WXBB2WiGQvk3BT6gYl9Khw8ZoE,31713 -pip/_internal/req/req_set.py,sha256=EBHZ9zWSR8arxjcadyU2OotZIECemM8oOFQ0nK-Bb7E,7792 -pip/_internal/req/req_tracker.py,sha256=cAKhSw-QbhGxqPF1Wc0zD6jo932jpdYF3ROfRSH8hes,4744 -pip/_internal/req/req_uninstall.py,sha256=NdErRQBpNScsdwJAo3O_zo2KPPfQyVMJ_Q2mxPWYyOA,23734 -pip/_internal/resolution/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -pip/_internal/resolution/__pycache__/__init__.cpython-38.pyc,, -pip/_internal/resolution/__pycache__/base.cpython-38.pyc,, -pip/_internal/resolution/base.py,sha256=xi72YmIS-lEjyK13PN_3qkGGthA4yGoK0C6qWynyHrE,682 -pip/_internal/resolution/legacy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -pip/_internal/resolution/legacy/__pycache__/__init__.cpython-38.pyc,, -pip/_internal/resolution/legacy/__pycache__/resolver.cpython-38.pyc,, -pip/_internal/resolution/legacy/resolver.py,sha256=56GuGHWcseV24cvTCOuRHMAF_Er1UeDxn5m18XMkHBs,17587 -pip/_internal/resolution/resolvelib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -pip/_internal/resolution/resolvelib/__pycache__/__init__.cpython-38.pyc,, -pip/_internal/resolution/resolvelib/__pycache__/base.cpython-38.pyc,, -pip/_internal/resolution/resolvelib/__pycache__/candidates.cpython-38.pyc,, -pip/_internal/resolution/resolvelib/__pycache__/factory.cpython-38.pyc,, -pip/_internal/resolution/resolvelib/__pycache__/provider.cpython-38.pyc,, -pip/_internal/resolution/resolvelib/__pycache__/requirements.cpython-38.pyc,, -pip/_internal/resolution/resolvelib/__pycache__/resolver.cpython-38.pyc,, -pip/_internal/resolution/resolvelib/base.py,sha256=l2Z3-1Qg243lWzwFbaN17qixA4U8LYr-qMhZTdaHROc,1502 -pip/_internal/resolution/resolvelib/candidates.py,sha256=wzi9t3aX1Twi3xTNEkpG6eWOd0dEg5uKul-QkK3arvw,15173 -pip/_internal/resolution/resolvelib/factory.py,sha256=mDs3p8D9N9zfYvn_iIx0saDLHF1SF7KHBQlA1gWSWVQ,7574 -pip/_internal/resolution/resolvelib/provider.py,sha256=0fKuPuEoD5T7w-YwKgQZc1AmgSnAkrxGnLBOf-_6Kiw,1703 -pip/_internal/resolution/resolvelib/requirements.py,sha256=bu9Y4YINHjvBm-NBKvnxw9IYHW4t6rRlm4-QKVqLDsM,3872 -pip/_internal/resolution/resolvelib/resolver.py,sha256=3LXhhCz6CtIpih8tK2nHeRvVEjVJmXrqxNCM1FQM1U0,6673 -pip/_internal/self_outdated_check.py,sha256=3KO1pTJUuYaiV9X0t87I9PimkGL82HbhLWbocqKZpBU,8009 -pip/_internal/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -pip/_internal/utils/__pycache__/__init__.cpython-38.pyc,, -pip/_internal/utils/__pycache__/appdirs.cpython-38.pyc,, -pip/_internal/utils/__pycache__/compat.cpython-38.pyc,, -pip/_internal/utils/__pycache__/compatibility_tags.cpython-38.pyc,, -pip/_internal/utils/__pycache__/deprecation.cpython-38.pyc,, -pip/_internal/utils/__pycache__/direct_url_helpers.cpython-38.pyc,, -pip/_internal/utils/__pycache__/distutils_args.cpython-38.pyc,, -pip/_internal/utils/__pycache__/encoding.cpython-38.pyc,, -pip/_internal/utils/__pycache__/entrypoints.cpython-38.pyc,, -pip/_internal/utils/__pycache__/filesystem.cpython-38.pyc,, -pip/_internal/utils/__pycache__/filetypes.cpython-38.pyc,, -pip/_internal/utils/__pycache__/glibc.cpython-38.pyc,, -pip/_internal/utils/__pycache__/hashes.cpython-38.pyc,, -pip/_internal/utils/__pycache__/inject_securetransport.cpython-38.pyc,, -pip/_internal/utils/__pycache__/logging.cpython-38.pyc,, -pip/_internal/utils/__pycache__/misc.cpython-38.pyc,, -pip/_internal/utils/__pycache__/models.cpython-38.pyc,, -pip/_internal/utils/__pycache__/packaging.cpython-38.pyc,, -pip/_internal/utils/__pycache__/pkg_resources.cpython-38.pyc,, -pip/_internal/utils/__pycache__/setuptools_build.cpython-38.pyc,, -pip/_internal/utils/__pycache__/subprocess.cpython-38.pyc,, -pip/_internal/utils/__pycache__/temp_dir.cpython-38.pyc,, -pip/_internal/utils/__pycache__/typing.cpython-38.pyc,, -pip/_internal/utils/__pycache__/unpacking.cpython-38.pyc,, -pip/_internal/utils/__pycache__/urls.cpython-38.pyc,, -pip/_internal/utils/__pycache__/virtualenv.cpython-38.pyc,, -pip/_internal/utils/__pycache__/wheel.cpython-38.pyc,, -pip/_internal/utils/appdirs.py,sha256=RZzUG-Bkh2b-miX0DSZ3v703_-bgK-v0PfWCCjwVE9g,1349 -pip/_internal/utils/compat.py,sha256=ZRJsXMjq373p0US54CUkKRkpLH-ioOM3H3yAhmbUPcs,8898 -pip/_internal/utils/compatibility_tags.py,sha256=b2NWEbxfsrB2pBLwJkNVSYUrIAsumQ2IWDoNabbwLPs,5492 -pip/_internal/utils/deprecation.py,sha256=pBnNogoA4UGTxa_JDnPXBRRYpKMbExAhXpBwAwklOBs,3318 -pip/_internal/utils/direct_url_helpers.py,sha256=bZCBNwPQVyZpYGjX_VcomvVvRHvKw-9JzEV-Ft09LQc,4359 -pip/_internal/utils/distutils_args.py,sha256=a56mblNxk9BGifbpEETG61mmBrqhjtjRkJ4HYn-oOEE,1350 -pip/_internal/utils/encoding.py,sha256=hxZz0t3Whw3d4MHQEiofxalTlfKwxFdLc8fpeGfhKo8,1320 -pip/_internal/utils/entrypoints.py,sha256=vHcNpnksCv6mllihU6hfifdsKPEjwcaJ1aLIXEaynaU,1152 -pip/_internal/utils/filesystem.py,sha256=fqpFwT280152rlX1RjJqjoLp_MXVA8HzKTtDmsl15Ps,6813 -pip/_internal/utils/filetypes.py,sha256=R2FwzoeX7b-rZALOXx5cuO8VPPMhUQ4ne7wm3n3IcWA,571 -pip/_internal/utils/glibc.py,sha256=LOeNGgawCKS-4ke9fii78fwXD73dtNav3uxz1Bf-Ab8,3297 -pip/_internal/utils/hashes.py,sha256=LQVOt2LTWAdBJH6WPim1YGdF0J-0AfBBLghIDlY1-80,3986 -pip/_internal/utils/inject_securetransport.py,sha256=M17ZlFVY66ApgeASVjKKLKNz0LAfk-SyU0HZ4ZB6MmI,810 -pip/_internal/utils/logging.py,sha256=YIfuDUEkmdn9cIRQ_Ec8rgXs1m5nOwDECtZqM4CBH5U,13093 -pip/_internal/utils/misc.py,sha256=d6Gvup_5Uus2jBxsUHwnSP1HDiGsb9oBNZKhdgbAMnE,26798 -pip/_internal/utils/models.py,sha256=IA0hw_T4awQzui0kqfIEASm5yLtgZAB08ag59Nip5G8,1148 -pip/_internal/utils/packaging.py,sha256=VtiwcAAL7LBi7tGL2je7LeW4bE11KMHGCsJ1NZY5XtM,3035 -pip/_internal/utils/pkg_resources.py,sha256=ZX-k7V5q_aNWyDse92nN7orN1aCpRLsaxzpkBZ1XKzU,1254 -pip/_internal/utils/setuptools_build.py,sha256=E1KswI7wfNnCDE5R6G8c9ZbByENpu7NqocjY26PCQDw,5058 -pip/_internal/utils/subprocess.py,sha256=vI2QWpNDqM-dkn-z8i1Yrfxnn5sYniPeWn6FhTxX4dY,9902 -pip/_internal/utils/temp_dir.py,sha256=H8yUBrRWqTM83cuUu7jVvw_xKL9eZtg_IIbXQtjMLlA,8185 -pip/_internal/utils/typing.py,sha256=xkYwOeHlf4zsHXBDC4310HtEqwhQcYXFPq2h35Tcrl0,1401 -pip/_internal/utils/unpacking.py,sha256=M944JTSiapBOSKLWu7lbawpVHSE7flfzZTEr3TAG7v8,9438 -pip/_internal/utils/urls.py,sha256=q2rw1kMiiig_XZcoyJSsWMJQqYw-2wUmrMoST4mCW_I,1527 -pip/_internal/utils/virtualenv.py,sha256=iVJ8ZlbNtGon6I4uZFsY2SidrUf1vt3YHrgS5CuU98w,3553 -pip/_internal/utils/wheel.py,sha256=ofsZEN35YhSxRYC4gfzpTtqa_UQ8GF1tl4jtyUdd0gU,7306 -pip/_internal/vcs/__init__.py,sha256=viJxJRqRE_mVScum85bgQIXAd6o0ozFt18VpC-qIJrM,617 -pip/_internal/vcs/__pycache__/__init__.cpython-38.pyc,, -pip/_internal/vcs/__pycache__/bazaar.cpython-38.pyc,, -pip/_internal/vcs/__pycache__/git.cpython-38.pyc,, -pip/_internal/vcs/__pycache__/mercurial.cpython-38.pyc,, -pip/_internal/vcs/__pycache__/subversion.cpython-38.pyc,, -pip/_internal/vcs/__pycache__/versioncontrol.cpython-38.pyc,, -pip/_internal/vcs/bazaar.py,sha256=84q1-kj1_nJ9AMzMu8RmMp-riRZu81M7K9kowcYgi3U,3957 -pip/_internal/vcs/git.py,sha256=wlvvVT-hPRwCvkihEoOCZmkCzMzosmV43_DTPvEVA_M,14165 -pip/_internal/vcs/mercurial.py,sha256=wVdmoFH-RYoaxjtuAqw40b0daMPX-Fr_26W1ME_9HZU,5347 -pip/_internal/vcs/subversion.py,sha256=6shByxeASetbM7WCj6WNoPcuLfBK65DoOEqbkSiWPAI,12331 -pip/_internal/vcs/versioncontrol.py,sha256=RtSrHr96CynqXYBQIC61cVY_9C0e7hk8dXUV-BpHmpI,23591 -pip/_internal/wheel_builder.py,sha256=p9ZFawfCR1GXchTRY6oq7Qx5enLLjs2SouafNFNsAAE,9590 -pip/_vendor/__init__.py,sha256=9W5OMec7OR5iGiLkewOfrMJ9Wt-FjLAezVSYzwHc2ds,5156 -pip/_vendor/__pycache__/__init__.cpython-38.pyc,, diff --git a/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/WHEEL b/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/WHEEL deleted file mode 100644 index ef99c6c..0000000 --- a/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/WHEEL +++ /dev/null @@ -1,6 +0,0 @@ -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/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/entry_points.txt b/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/entry_points.txt deleted file mode 100644 index d48bd8a..0000000 --- a/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/entry_points.txt +++ /dev/null @@ -1,5 +0,0 @@ -[console_scripts] -pip = pip._internal.cli.main:main -pip3 = pip._internal.cli.main:main -pip3.8 = pip._internal.cli.main:main - diff --git a/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/top_level.txt b/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/top_level.txt deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.8/site-packages/pip-20.1.1.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.8/site-packages/pip/__init__.py b/venv/lib/python3.8/site-packages/pip/__init__.py deleted file mode 100644 index 3dcf3a9..0000000 --- a/venv/lib/python3.8/site-packages/pip/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import List, Optional - - -__version__ = "20.1.1" - - -def main(args=None): - # type: (Optional[List[str]]) -> int - """This is an internal API only meant for use by pip's own console scripts. - - For additional details, see https://github.com/pypa/pip/issues/7498. - """ - from pip._internal.utils.entrypoints import _wrapper - - return _wrapper(args) diff --git a/venv/lib/python3.8/site-packages/pip/__main__.py b/venv/lib/python3.8/site-packages/pip/__main__.py deleted file mode 100644 index 7c2505f..0000000 --- a/venv/lib/python3.8/site-packages/pip/__main__.py +++ /dev/null @@ -1,26 +0,0 @@ -from __future__ import absolute_import - -import os -import sys - -# Remove '' and current working directory from the first entry -# of sys.path, if present to avoid using current directory -# in pip commands check, freeze, install, list and show, -# when invoked as python -m pip <command> -if sys.path[0] in ('', os.getcwd()): - sys.path.pop(0) - -# If we are running from a wheel, add the wheel to sys.path -# This allows the usage python pip-*.whl/pip install pip-*.whl -if __package__ == '': - # __file__ is pip-*.whl/pip/__main__.py - # first dirname call strips of '/__main__.py', second strips off '/pip' - # Resulting path is the name of the wheel itself - # Add that to sys.path so we can import pip - path = os.path.dirname(os.path.dirname(__file__)) - sys.path.insert(0, path) - -from pip._internal.cli.main import main as _main # isort:skip # noqa - -if __name__ == '__main__': - sys.exit(_main()) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/__init__.py b/venv/lib/python3.8/site-packages/pip/_internal/__init__.py deleted file mode 100644 index 264c2ca..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -import pip._internal.utils.inject_securetransport # noqa -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import Optional, List - - -def main(args=None): - # type: (Optional[List[str]]) -> int - """This is preserved for old console scripts that may still be referencing - it. - - For additional details, see https://github.com/pypa/pip/issues/7498. - """ - from pip._internal.utils.entrypoints import _wrapper - - return _wrapper(args) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/build_env.py b/venv/lib/python3.8/site-packages/pip/_internal/build_env.py deleted file mode 100644 index b8f005f..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/build_env.py +++ /dev/null @@ -1,219 +0,0 @@ -"""Build Environment used for isolation during sdist building -""" - -# The following comment should be removed at some point in the future. -# mypy: strict-optional=False -# mypy: disallow-untyped-defs=False - -import logging -import os -import sys -import textwrap -from collections import OrderedDict -from distutils.sysconfig import get_python_lib -from sysconfig import get_paths - -from pip._vendor.pkg_resources import Requirement, VersionConflict, WorkingSet - -from pip import __file__ as pip_location -from pip._internal.cli.spinners import open_spinner -from pip._internal.utils.subprocess import call_subprocess -from pip._internal.utils.temp_dir import TempDirectory, tempdir_kinds -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import Tuple, Set, Iterable, Optional, List - from pip._internal.index.package_finder import PackageFinder - -logger = logging.getLogger(__name__) - - -class _Prefix: - - def __init__(self, path): - # type: (str) -> None - self.path = path - self.setup = False - self.bin_dir = get_paths( - 'nt' if os.name == 'nt' else 'posix_prefix', - vars={'base': path, 'platbase': path} - )['scripts'] - # Note: prefer distutils' sysconfig to get the - # library paths so PyPy is correctly supported. - purelib = get_python_lib(plat_specific=False, prefix=path) - platlib = get_python_lib(plat_specific=True, prefix=path) - if purelib == platlib: - self.lib_dirs = [purelib] - else: - self.lib_dirs = [purelib, platlib] - - -class BuildEnvironment(object): - """Creates and manages an isolated environment to install build deps - """ - - def __init__(self): - # type: () -> None - temp_dir = TempDirectory( - kind=tempdir_kinds.BUILD_ENV, globally_managed=True - ) - - self._prefixes = OrderedDict(( - (name, _Prefix(os.path.join(temp_dir.path, name))) - for name in ('normal', 'overlay') - )) - - self._bin_dirs = [] # type: List[str] - self._lib_dirs = [] # type: List[str] - for prefix in reversed(list(self._prefixes.values())): - self._bin_dirs.append(prefix.bin_dir) - self._lib_dirs.extend(prefix.lib_dirs) - - # Customize site to: - # - ensure .pth files are honored - # - prevent access to system site packages - system_sites = { - os.path.normcase(site) for site in ( - get_python_lib(plat_specific=False), - get_python_lib(plat_specific=True), - ) - } - self._site_dir = os.path.join(temp_dir.path, 'site') - if not os.path.exists(self._site_dir): - os.mkdir(self._site_dir) - with open(os.path.join(self._site_dir, 'sitecustomize.py'), 'w') as fp: - fp.write(textwrap.dedent( - ''' - import os, site, sys - - # First, drop system-sites related paths. - original_sys_path = sys.path[:] - known_paths = set() - for path in {system_sites!r}: - site.addsitedir(path, known_paths=known_paths) - system_paths = set( - os.path.normcase(path) - for path in sys.path[len(original_sys_path):] - ) - original_sys_path = [ - path for path in original_sys_path - if os.path.normcase(path) not in system_paths - ] - sys.path = original_sys_path - - # Second, add lib directories. - # ensuring .pth file are processed. - for path in {lib_dirs!r}: - assert not path in sys.path - site.addsitedir(path) - ''' - ).format(system_sites=system_sites, lib_dirs=self._lib_dirs)) - - def __enter__(self): - self._save_env = { - name: os.environ.get(name, None) - for name in ('PATH', 'PYTHONNOUSERSITE', 'PYTHONPATH') - } - - path = self._bin_dirs[:] - old_path = self._save_env['PATH'] - if old_path: - path.extend(old_path.split(os.pathsep)) - - pythonpath = [self._site_dir] - - os.environ.update({ - 'PATH': os.pathsep.join(path), - 'PYTHONNOUSERSITE': '1', - 'PYTHONPATH': os.pathsep.join(pythonpath), - }) - - def __exit__(self, exc_type, exc_val, exc_tb): - for varname, old_value in self._save_env.items(): - if old_value is None: - os.environ.pop(varname, None) - else: - os.environ[varname] = old_value - - def check_requirements(self, reqs): - # type: (Iterable[str]) -> Tuple[Set[Tuple[str, str]], Set[str]] - """Return 2 sets: - - conflicting requirements: set of (installed, wanted) reqs tuples - - missing requirements: set of reqs - """ - missing = set() - conflicting = set() - if reqs: - ws = WorkingSet(self._lib_dirs) - for req in reqs: - try: - if ws.find(Requirement.parse(req)) is None: - missing.add(req) - except VersionConflict as e: - conflicting.add((str(e.args[0].as_requirement()), - str(e.args[1]))) - return conflicting, missing - - def install_requirements( - self, - finder, # type: PackageFinder - requirements, # type: Iterable[str] - prefix_as_string, # type: str - message # type: Optional[str] - ): - # type: (...) -> None - prefix = self._prefixes[prefix_as_string] - assert not prefix.setup - prefix.setup = True - if not requirements: - return - args = [ - sys.executable, os.path.dirname(pip_location), 'install', - '--ignore-installed', '--no-user', '--prefix', prefix.path, - '--no-warn-script-location', - ] # type: List[str] - if logger.getEffectiveLevel() <= logging.DEBUG: - args.append('-v') - for format_control in ('no_binary', 'only_binary'): - formats = getattr(finder.format_control, format_control) - args.extend(('--' + format_control.replace('_', '-'), - ','.join(sorted(formats or {':none:'})))) - - index_urls = finder.index_urls - if index_urls: - args.extend(['-i', index_urls[0]]) - for extra_index in index_urls[1:]: - args.extend(['--extra-index-url', extra_index]) - else: - args.append('--no-index') - for link in finder.find_links: - args.extend(['--find-links', link]) - - for host in finder.trusted_hosts: - args.extend(['--trusted-host', host]) - if finder.allow_all_prereleases: - args.append('--pre') - args.append('--') - args.extend(requirements) - with open_spinner(message) as spinner: - call_subprocess(args, spinner=spinner) - - -class NoOpBuildEnvironment(BuildEnvironment): - """A no-op drop-in replacement for BuildEnvironment - """ - - def __init__(self): - pass - - def __enter__(self): - pass - - def __exit__(self, exc_type, exc_val, exc_tb): - pass - - def cleanup(self): - pass - - def install_requirements(self, finder, requirements, prefix, message): - raise NotImplementedError() diff --git a/venv/lib/python3.8/site-packages/pip/_internal/cache.py b/venv/lib/python3.8/site-packages/pip/_internal/cache.py deleted file mode 100644 index b534f0c..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/cache.py +++ /dev/null @@ -1,349 +0,0 @@ -"""Cache Management -""" - -# The following comment should be removed at some point in the future. -# mypy: strict-optional=False - -import hashlib -import json -import logging -import os - -from pip._vendor.packaging.tags import interpreter_name, interpreter_version -from pip._vendor.packaging.utils import canonicalize_name - -from pip._internal.exceptions import InvalidWheelFilename -from pip._internal.models.link import Link -from pip._internal.models.wheel import Wheel -from pip._internal.utils.temp_dir import TempDirectory, tempdir_kinds -from pip._internal.utils.typing import MYPY_CHECK_RUNNING -from pip._internal.utils.urls import path_to_url - -if MYPY_CHECK_RUNNING: - from typing import Optional, Set, List, Any, Dict - - from pip._vendor.packaging.tags import Tag - - from pip._internal.models.format_control import FormatControl - -logger = logging.getLogger(__name__) - - -def _hash_dict(d): - # type: (Dict[str, str]) -> str - """Return a stable sha224 of a dictionary.""" - s = json.dumps(d, sort_keys=True, separators=(",", ":"), ensure_ascii=True) - return hashlib.sha224(s.encode("ascii")).hexdigest() - - -class Cache(object): - """An abstract class - provides cache directories for data from links - - - :param cache_dir: The root of the cache. - :param format_control: An object of FormatControl class to limit - binaries being read from the cache. - :param allowed_formats: which formats of files the cache should store. - ('binary' and 'source' are the only allowed values) - """ - - def __init__(self, cache_dir, format_control, allowed_formats): - # type: (str, FormatControl, Set[str]) -> None - super(Cache, self).__init__() - assert not cache_dir or os.path.isabs(cache_dir) - self.cache_dir = cache_dir or None - self.format_control = format_control - self.allowed_formats = allowed_formats - - _valid_formats = {"source", "binary"} - assert self.allowed_formats.union(_valid_formats) == _valid_formats - - def _get_cache_path_parts_legacy(self, link): - # type: (Link) -> List[str] - """Get parts of part that must be os.path.joined with cache_dir - - Legacy cache key (pip < 20) for compatibility with older caches. - """ - - # We want to generate an url to use as our cache key, we don't want to - # just re-use the URL because it might have other items in the fragment - # and we don't care about those. - key_parts = [link.url_without_fragment] - if link.hash_name is not None and link.hash is not None: - key_parts.append("=".join([link.hash_name, link.hash])) - key_url = "#".join(key_parts) - - # Encode our key url with sha224, we'll use this because it has similar - # security properties to sha256, but with a shorter total output (and - # thus less secure). However the differences don't make a lot of - # difference for our use case here. - hashed = hashlib.sha224(key_url.encode()).hexdigest() - - # We want to nest the directories some to prevent having a ton of top - # level directories where we might run out of sub directories on some - # FS. - parts = [hashed[:2], hashed[2:4], hashed[4:6], hashed[6:]] - - return parts - - def _get_cache_path_parts(self, link): - # type: (Link) -> List[str] - """Get parts of part that must be os.path.joined with cache_dir - """ - - # We want to generate an url to use as our cache key, we don't want to - # just re-use the URL because it might have other items in the fragment - # and we don't care about those. - key_parts = {"url": link.url_without_fragment} - if link.hash_name is not None and link.hash is not None: - key_parts[link.hash_name] = link.hash - if link.subdirectory_fragment: - key_parts["subdirectory"] = link.subdirectory_fragment - - # Include interpreter name, major and minor version in cache key - # to cope with ill-behaved sdists that build a different wheel - # depending on the python version their setup.py is being run on, - # and don't encode the difference in compatibility tags. - # https://github.com/pypa/pip/issues/7296 - key_parts["interpreter_name"] = interpreter_name() - key_parts["interpreter_version"] = interpreter_version() - - # Encode our key url with sha224, we'll use this because it has similar - # security properties to sha256, but with a shorter total output (and - # thus less secure). However the differences don't make a lot of - # difference for our use case here. - hashed = _hash_dict(key_parts) - - # We want to nest the directories some to prevent having a ton of top - # level directories where we might run out of sub directories on some - # FS. - parts = [hashed[:2], hashed[2:4], hashed[4:6], hashed[6:]] - - return parts - - def _get_candidates(self, link, canonical_package_name): - # type: (Link, Optional[str]) -> List[Any] - can_not_cache = ( - not self.cache_dir or - not canonical_package_name or - not link - ) - if can_not_cache: - return [] - - formats = self.format_control.get_allowed_formats( - canonical_package_name - ) - if not self.allowed_formats.intersection(formats): - return [] - - candidates = [] - path = self.get_path_for_link(link) - if os.path.isdir(path): - for candidate in os.listdir(path): - candidates.append((candidate, path)) - # TODO remove legacy path lookup in pip>=21 - legacy_path = self.get_path_for_link_legacy(link) - if os.path.isdir(legacy_path): - for candidate in os.listdir(legacy_path): - candidates.append((candidate, legacy_path)) - return candidates - - def get_path_for_link_legacy(self, link): - # type: (Link) -> str - raise NotImplementedError() - - def get_path_for_link(self, link): - # type: (Link) -> str - """Return a directory to store cached items in for link. - """ - raise NotImplementedError() - - def get( - self, - link, # type: Link - package_name, # type: Optional[str] - supported_tags, # type: List[Tag] - ): - # type: (...) -> Link - """Returns a link to a cached item if it exists, otherwise returns the - passed link. - """ - raise NotImplementedError() - - -class SimpleWheelCache(Cache): - """A cache of wheels for future installs. - """ - - def __init__(self, cache_dir, format_control): - # type: (str, FormatControl) -> None - super(SimpleWheelCache, self).__init__( - cache_dir, format_control, {"binary"} - ) - - def get_path_for_link_legacy(self, link): - # type: (Link) -> str - parts = self._get_cache_path_parts_legacy(link) - return os.path.join(self.cache_dir, "wheels", *parts) - - def get_path_for_link(self, link): - # type: (Link) -> str - """Return a directory to store cached wheels for link - - Because there are M wheels for any one sdist, we provide a directory - to cache them in, and then consult that directory when looking up - cache hits. - - We only insert things into the cache if they have plausible version - numbers, so that we don't contaminate the cache with things that were - not unique. E.g. ./package might have dozens of installs done for it - and build a version of 0.0...and if we built and cached a wheel, we'd - end up using the same wheel even if the source has been edited. - - :param link: The link of the sdist for which this will cache wheels. - """ - parts = self._get_cache_path_parts(link) - - # Store wheels within the root cache_dir - return os.path.join(self.cache_dir, "wheels", *parts) - - def get( - self, - link, # type: Link - package_name, # type: Optional[str] - supported_tags, # type: List[Tag] - ): - # type: (...) -> Link - candidates = [] - - if not package_name: - return link - - canonical_package_name = canonicalize_name(package_name) - for wheel_name, wheel_dir in self._get_candidates( - link, canonical_package_name - ): - try: - wheel = Wheel(wheel_name) - except InvalidWheelFilename: - continue - if canonicalize_name(wheel.name) != canonical_package_name: - logger.debug( - "Ignoring cached wheel {} for {} as it " - "does not match the expected distribution name {}.".format( - wheel_name, link, package_name - ) - ) - continue - if not wheel.supported(supported_tags): - # Built for a different python/arch/etc - continue - candidates.append( - ( - wheel.support_index_min(supported_tags), - wheel_name, - wheel_dir, - ) - ) - - if not candidates: - return link - - _, wheel_name, wheel_dir = min(candidates) - return Link(path_to_url(os.path.join(wheel_dir, wheel_name))) - - -class EphemWheelCache(SimpleWheelCache): - """A SimpleWheelCache that creates it's own temporary cache directory - """ - - def __init__(self, format_control): - # type: (FormatControl) -> None - self._temp_dir = TempDirectory( - kind=tempdir_kinds.EPHEM_WHEEL_CACHE, - globally_managed=True, - ) - - super(EphemWheelCache, self).__init__( - self._temp_dir.path, format_control - ) - - -class CacheEntry(object): - def __init__( - self, - link, # type: Link - persistent, # type: bool - ): - self.link = link - self.persistent = persistent - - -class WheelCache(Cache): - """Wraps EphemWheelCache and SimpleWheelCache into a single Cache - - This Cache allows for gracefully degradation, using the ephem wheel cache - when a certain link is not found in the simple wheel cache first. - """ - - def __init__(self, cache_dir, format_control): - # type: (str, FormatControl) -> None - super(WheelCache, self).__init__( - cache_dir, format_control, {'binary'} - ) - self._wheel_cache = SimpleWheelCache(cache_dir, format_control) - self._ephem_cache = EphemWheelCache(format_control) - - def get_path_for_link_legacy(self, link): - # type: (Link) -> str - return self._wheel_cache.get_path_for_link_legacy(link) - - def get_path_for_link(self, link): - # type: (Link) -> str - return self._wheel_cache.get_path_for_link(link) - - def get_ephem_path_for_link(self, link): - # type: (Link) -> str - return self._ephem_cache.get_path_for_link(link) - - def get( - self, - link, # type: Link - package_name, # type: Optional[str] - supported_tags, # type: List[Tag] - ): - # type: (...) -> Link - cache_entry = self.get_cache_entry(link, package_name, supported_tags) - if cache_entry is None: - return link - return cache_entry.link - - def get_cache_entry( - self, - link, # type: Link - package_name, # type: Optional[str] - supported_tags, # type: List[Tag] - ): - # type: (...) -> Optional[CacheEntry] - """Returns a CacheEntry with a link to a cached item if it exists or - None. The cache entry indicates if the item was found in the persistent - or ephemeral cache. - """ - retval = self._wheel_cache.get( - link=link, - package_name=package_name, - supported_tags=supported_tags, - ) - if retval is not link: - return CacheEntry(retval, persistent=True) - - retval = self._ephem_cache.get( - link=link, - package_name=package_name, - supported_tags=supported_tags, - ) - if retval is not link: - return CacheEntry(retval, persistent=False) - - return None diff --git a/venv/lib/python3.8/site-packages/pip/_internal/cli/__init__.py b/venv/lib/python3.8/site-packages/pip/_internal/cli/__init__.py deleted file mode 100644 index e589bb9..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/cli/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -"""Subpackage containing all of pip's command line interface related code -""" - -# This file intentionally does not import submodules diff --git a/venv/lib/python3.8/site-packages/pip/_internal/cli/autocompletion.py b/venv/lib/python3.8/site-packages/pip/_internal/cli/autocompletion.py deleted file mode 100644 index 329de60..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/cli/autocompletion.py +++ /dev/null @@ -1,164 +0,0 @@ -"""Logic that powers autocompletion installed by ``pip completion``. -""" - -import optparse -import os -import sys -from itertools import chain - -from pip._internal.cli.main_parser import create_main_parser -from pip._internal.commands import commands_dict, create_command -from pip._internal.utils.misc import get_installed_distributions -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import Any, Iterable, List, Optional - - -def autocomplete(): - # type: () -> None - """Entry Point for completion of main and subcommand options. - """ - # Don't complete if user hasn't sourced bash_completion file. - if 'PIP_AUTO_COMPLETE' not in os.environ: - return - cwords = os.environ['COMP_WORDS'].split()[1:] - cword = int(os.environ['COMP_CWORD']) - try: - current = cwords[cword - 1] - except IndexError: - current = '' - - parser = create_main_parser() - subcommands = list(commands_dict) - options = [] - - # subcommand - subcommand_name = None # type: Optional[str] - for word in cwords: - if word in subcommands: - subcommand_name = word - break - # subcommand options - if subcommand_name is not None: - # special case: 'help' subcommand has no options - if subcommand_name == 'help': - sys.exit(1) - # special case: list locally installed dists for show and uninstall - should_list_installed = ( - subcommand_name in ['show', 'uninstall'] and - not current.startswith('-') - ) - if should_list_installed: - installed = [] - lc = current.lower() - for dist in get_installed_distributions(local_only=True): - if dist.key.startswith(lc) and dist.key not in cwords[1:]: - installed.append(dist.key) - # if there are no dists installed, fall back to option completion - if installed: - for dist in installed: - print(dist) - sys.exit(1) - - subcommand = create_command(subcommand_name) - - for opt in subcommand.parser.option_list_all: - if opt.help != optparse.SUPPRESS_HELP: - for opt_str in opt._long_opts + opt._short_opts: - options.append((opt_str, opt.nargs)) - - # filter out previously specified options from available options - prev_opts = [x.split('=')[0] for x in cwords[1:cword - 1]] - options = [(x, v) for (x, v) in options if x not in prev_opts] - # filter options by current input - options = [(k, v) for k, v in options if k.startswith(current)] - # get completion type given cwords and available subcommand options - completion_type = get_path_completion_type( - cwords, cword, subcommand.parser.option_list_all, - ) - # get completion files and directories if ``completion_type`` is - # ``<file>``, ``<dir>`` or ``<path>`` - if completion_type: - paths = auto_complete_paths(current, completion_type) - options = [(path, 0) for path in paths] - for option in options: - opt_label = option[0] - # append '=' to options which require args - if option[1] and option[0][:2] == "--": - opt_label += '=' - print(opt_label) - else: - # show main parser options only when necessary - - opts = [i.option_list for i in parser.option_groups] - opts.append(parser.option_list) - flattened_opts = chain.from_iterable(opts) - if current.startswith('-'): - for opt in flattened_opts: - if opt.help != optparse.SUPPRESS_HELP: - subcommands += opt._long_opts + opt._short_opts - else: - # get completion type given cwords and all available options - completion_type = get_path_completion_type(cwords, cword, - flattened_opts) - if completion_type: - subcommands = list(auto_complete_paths(current, - completion_type)) - - print(' '.join([x for x in subcommands if x.startswith(current)])) - sys.exit(1) - - -def get_path_completion_type(cwords, cword, opts): - # type: (List[str], int, Iterable[Any]) -> Optional[str] - """Get the type of path completion (``file``, ``dir``, ``path`` or None) - - :param cwords: same as the environmental variable ``COMP_WORDS`` - :param cword: same as the environmental variable ``COMP_CWORD`` - :param opts: The available options to check - :return: path completion type (``file``, ``dir``, ``path`` or None) - """ - if cword < 2 or not cwords[cword - 2].startswith('-'): - return None - for opt in opts: - if opt.help == optparse.SUPPRESS_HELP: - continue - for o in str(opt).split('/'): - if cwords[cword - 2].split('=')[0] == o: - if not opt.metavar or any( - x in ('path', 'file', 'dir') - for x in opt.metavar.split('/')): - return opt.metavar - return None - - -def auto_complete_paths(current, completion_type): - # type: (str, str) -> Iterable[str] - """If ``completion_type`` is ``file`` or ``path``, list all regular files - and directories starting with ``current``; otherwise only list directories - starting with ``current``. - - :param current: The word to be completed - :param completion_type: path completion type(`file`, `path` or `dir`)i - :return: A generator of regular files and/or directories - """ - directory, filename = os.path.split(current) - current_path = os.path.abspath(directory) - # Don't complete paths if they can't be accessed - if not os.access(current_path, os.R_OK): - return - filename = os.path.normcase(filename) - # list all files that start with ``filename`` - file_list = (x for x in os.listdir(current_path) - if os.path.normcase(x).startswith(filename)) - for f in file_list: - opt = os.path.join(current_path, f) - comp_file = os.path.normcase(os.path.join(directory, f)) - # complete regular files when there is not ``<dir>`` after option - # complete directories when there is ``<file>``, ``<path>`` or - # ``<dir>``after option - if completion_type != 'dir' and os.path.isfile(opt): - yield comp_file - elif os.path.isdir(opt): - yield os.path.join(comp_file, '') diff --git a/venv/lib/python3.8/site-packages/pip/_internal/cli/base_command.py b/venv/lib/python3.8/site-packages/pip/_internal/cli/base_command.py deleted file mode 100644 index 1fa5ba0..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/cli/base_command.py +++ /dev/null @@ -1,228 +0,0 @@ -"""Base Command class, and related routines""" - -from __future__ import absolute_import, print_function - -import logging -import logging.config -import optparse -import os -import platform -import sys -import traceback - -from pip._internal.cli import cmdoptions -from pip._internal.cli.command_context import CommandContextMixIn -from pip._internal.cli.parser import ( - ConfigOptionParser, - UpdatingDefaultsHelpFormatter, -) -from pip._internal.cli.status_codes import ( - ERROR, - PREVIOUS_BUILD_DIR_ERROR, - SUCCESS, - UNKNOWN_ERROR, - VIRTUALENV_NOT_FOUND, -) -from pip._internal.exceptions import ( - BadCommand, - CommandError, - InstallationError, - PreviousBuildDirError, - UninstallationError, -) -from pip._internal.utils.deprecation import deprecated -from pip._internal.utils.filesystem import check_path_owner -from pip._internal.utils.logging import BrokenStdoutLoggingError, setup_logging -from pip._internal.utils.misc import get_prog, normalize_path -from pip._internal.utils.temp_dir import ( - global_tempdir_manager, - tempdir_registry, -) -from pip._internal.utils.typing import MYPY_CHECK_RUNNING -from pip._internal.utils.virtualenv import running_under_virtualenv - -if MYPY_CHECK_RUNNING: - from typing import List, Optional, Tuple, Any - from optparse import Values - - from pip._internal.utils.temp_dir import ( - TempDirectoryTypeRegistry as TempDirRegistry - ) - -__all__ = ['Command'] - -logger = logging.getLogger(__name__) - - -class Command(CommandContextMixIn): - usage = None # type: str - ignore_require_venv = False # type: bool - - def __init__(self, name, summary, isolated=False): - # type: (str, str, bool) -> None - super(Command, self).__init__() - parser_kw = { - 'usage': self.usage, - 'prog': '{} {}'.format(get_prog(), name), - 'formatter': UpdatingDefaultsHelpFormatter(), - 'add_help_option': False, - 'name': name, - 'description': self.__doc__, - 'isolated': isolated, - } - - self.name = name - self.summary = summary - self.parser = ConfigOptionParser(**parser_kw) - - self.tempdir_registry = None # type: Optional[TempDirRegistry] - - # Commands should add options to this option group - optgroup_name = '{} Options'.format(self.name.capitalize()) - self.cmd_opts = optparse.OptionGroup(self.parser, optgroup_name) - - # Add the general options - gen_opts = cmdoptions.make_option_group( - cmdoptions.general_group, - self.parser, - ) - self.parser.add_option_group(gen_opts) - - def handle_pip_version_check(self, options): - # type: (Values) -> None - """ - This is a no-op so that commands by default do not do the pip version - check. - """ - # Make sure we do the pip version check if the index_group options - # are present. - assert not hasattr(options, 'no_index') - - def run(self, options, args): - # type: (Values, List[Any]) -> Any - raise NotImplementedError - - def parse_args(self, args): - # type: (List[str]) -> Tuple[Any, Any] - # factored out for testability - return self.parser.parse_args(args) - - def main(self, args): - # type: (List[str]) -> int - try: - with self.main_context(): - return self._main(args) - finally: - logging.shutdown() - - def _main(self, args): - # type: (List[str]) -> int - # We must initialize this before the tempdir manager, otherwise the - # configuration would not be accessible by the time we clean up the - # tempdir manager. - self.tempdir_registry = self.enter_context(tempdir_registry()) - # Intentionally set as early as possible so globally-managed temporary - # directories are available to the rest of the code. - self.enter_context(global_tempdir_manager()) - - options, args = self.parse_args(args) - - # Set verbosity so that it can be used elsewhere. - self.verbosity = options.verbose - options.quiet - - level_number = setup_logging( - verbosity=self.verbosity, - no_color=options.no_color, - user_log_file=options.log, - ) - - if ( - sys.version_info[:2] == (2, 7) and - not options.no_python_version_warning - ): - message = ( - "pip 21.0 will drop support for Python 2.7 in January 2021. " - "More details about Python 2 support in pip, can be found at " - "https://pip.pypa.io/en/latest/development/release-process/#python-2-support" # noqa - ) - if platform.python_implementation() == "CPython": - message = ( - "Python 2.7 reached the end of its life on January " - "1st, 2020. Please upgrade your Python as Python 2.7 " - "is no longer maintained. " - ) + message - deprecated(message, replacement=None, gone_in=None) - - # TODO: Try to get these passing down from the command? - # without resorting to os.environ to hold these. - # This also affects isolated builds and it should. - - if options.no_input: - os.environ['PIP_NO_INPUT'] = '1' - - if options.exists_action: - os.environ['PIP_EXISTS_ACTION'] = ' '.join(options.exists_action) - - if options.require_venv and not self.ignore_require_venv: - # If a venv is required check if it can really be found - if not running_under_virtualenv(): - logger.critical( - 'Could not find an activated virtualenv (required).' - ) - sys.exit(VIRTUALENV_NOT_FOUND) - - if options.cache_dir: - options.cache_dir = normalize_path(options.cache_dir) - if not check_path_owner(options.cache_dir): - logger.warning( - "The directory '%s' or its parent directory is not owned " - "or is not writable by the current user. The cache " - "has been disabled. Check the permissions and owner of " - "that directory. If executing pip with sudo, you may want " - "sudo's -H flag.", - options.cache_dir, - ) - options.cache_dir = None - - try: - status = self.run(options, args) - # FIXME: all commands should return an exit status - # and when it is done, isinstance is not needed anymore - if isinstance(status, int): - return status - except PreviousBuildDirError as exc: - logger.critical(str(exc)) - logger.debug('Exception information:', exc_info=True) - - return PREVIOUS_BUILD_DIR_ERROR - except (InstallationError, UninstallationError, BadCommand) as exc: - logger.critical(str(exc)) - logger.debug('Exception information:', exc_info=True) - - return ERROR - except CommandError as exc: - logger.critical('%s', exc) - logger.debug('Exception information:', exc_info=True) - - return ERROR - except BrokenStdoutLoggingError: - # Bypass our logger and write any remaining messages to stderr - # because stdout no longer works. - print('ERROR: Pipe to stdout was broken', file=sys.stderr) - if level_number <= logging.DEBUG: - traceback.print_exc(file=sys.stderr) - - return ERROR - except KeyboardInterrupt: - logger.critical('Operation cancelled by user') - logger.debug('Exception information:', exc_info=True) - - return ERROR - except BaseException: - logger.critical('Exception:', exc_info=True) - - return UNKNOWN_ERROR - finally: - self.handle_pip_version_check(options) - - return SUCCESS diff --git a/venv/lib/python3.8/site-packages/pip/_internal/cli/cmdoptions.py b/venv/lib/python3.8/site-packages/pip/_internal/cli/cmdoptions.py deleted file mode 100644 index c234784..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/cli/cmdoptions.py +++ /dev/null @@ -1,962 +0,0 @@ -""" -shared options and groups - -The principle here is to define options once, but *not* instantiate them -globally. One reason being that options with action='append' can carry state -between parses. pip parses general options twice internally, and shouldn't -pass on state. To be consistent, all options will follow this design. -""" - -# The following comment should be removed at some point in the future. -# mypy: strict-optional=False - -from __future__ import absolute_import - -import logging -import os -import textwrap -import warnings -from distutils.util import strtobool -from functools import partial -from optparse import SUPPRESS_HELP, Option, OptionGroup -from textwrap import dedent - -from pip._internal.cli.progress_bars import BAR_TYPES -from pip._internal.exceptions import CommandError -from pip._internal.locations import USER_CACHE_DIR, get_src_prefix -from pip._internal.models.format_control import FormatControl -from pip._internal.models.index import PyPI -from pip._internal.models.target_python import TargetPython -from pip._internal.utils.hashes import STRONG_HASHES -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import Any, Callable, Dict, Optional, Tuple - from optparse import OptionParser, Values - from pip._internal.cli.parser import ConfigOptionParser - -logger = logging.getLogger(__name__) - - -def raise_option_error(parser, option, msg): - # type: (OptionParser, Option, str) -> None - """ - Raise an option parsing error using parser.error(). - - Args: - parser: an OptionParser instance. - option: an Option instance. - msg: the error text. - """ - msg = '{} error: {}'.format(option, msg) - msg = textwrap.fill(' '.join(msg.split())) - parser.error(msg) - - -def make_option_group(group, parser): - # type: (Dict[str, Any], ConfigOptionParser) -> OptionGroup - """ - Return an OptionGroup object - group -- assumed to be dict with 'name' and 'options' keys - parser -- an optparse Parser - """ - option_group = OptionGroup(parser, group['name']) - for option in group['options']: - option_group.add_option(option()) - return option_group - - -def check_install_build_global(options, check_options=None): - # type: (Values, Optional[Values]) -> None - """Disable wheels if per-setup.py call options are set. - - :param options: The OptionParser options to update. - :param check_options: The options to check, if not supplied defaults to - options. - """ - if check_options is None: - check_options = options - - def getname(n): - # type: (str) -> Optional[Any] - return getattr(check_options, n, None) - names = ["build_options", "global_options", "install_options"] - if any(map(getname, names)): - control = options.format_control - control.disallow_binaries() - warnings.warn( - 'Disabling all use of wheels due to the use of --build-option ' - '/ --global-option / --install-option.', stacklevel=2, - ) - - -def check_dist_restriction(options, check_target=False): - # type: (Values, bool) -> None - """Function for determining if custom platform options are allowed. - - :param options: The OptionParser options. - :param check_target: Whether or not to check if --target is being used. - """ - dist_restriction_set = any([ - options.python_version, - options.platform, - options.abi, - options.implementation, - ]) - - binary_only = FormatControl(set(), {':all:'}) - sdist_dependencies_allowed = ( - options.format_control != binary_only and - not options.ignore_dependencies - ) - - # Installations or downloads using dist restrictions must not combine - # source distributions and dist-specific wheels, as they are not - # guaranteed to be locally compatible. - if dist_restriction_set and sdist_dependencies_allowed: - raise CommandError( - "When restricting platform and interpreter constraints using " - "--python-version, --platform, --abi, or --implementation, " - "either --no-deps must be set, or --only-binary=:all: must be " - "set and --no-binary must not be set (or must be set to " - ":none:)." - ) - - if check_target: - if dist_restriction_set and not options.target_dir: - raise CommandError( - "Can not use any platform or abi specific options unless " - "installing via '--target'" - ) - - -def _path_option_check(option, opt, value): - # type: (Option, str, str) -> str - return os.path.expanduser(value) - - -class PipOption(Option): - TYPES = Option.TYPES + ("path",) - TYPE_CHECKER = Option.TYPE_CHECKER.copy() - TYPE_CHECKER["path"] = _path_option_check - - -########### -# options # -########### - -help_ = partial( - Option, - '-h', '--help', - dest='help', - action='help', - help='Show help.', -) # type: Callable[..., Option] - -isolated_mode = partial( - Option, - "--isolated", - dest="isolated_mode", - action="store_true", - default=False, - help=( - "Run pip in an isolated mode, ignoring environment variables and user " - "configuration." - ), -) # type: Callable[..., Option] - -require_virtualenv = partial( - Option, - # Run only if inside a virtualenv, bail if not. - '--require-virtualenv', '--require-venv', - dest='require_venv', - action='store_true', - default=False, - help=SUPPRESS_HELP -) # type: Callable[..., Option] - -verbose = partial( - Option, - '-v', '--verbose', - dest='verbose', - action='count', - default=0, - help='Give more output. Option is additive, and can be used up to 3 times.' -) # type: Callable[..., Option] - -no_color = partial( - Option, - '--no-color', - dest='no_color', - action='store_true', - default=False, - help="Suppress colored output", -) # type: Callable[..., Option] - -version = partial( - Option, - '-V', '--version', - dest='version', - action='store_true', - help='Show version and exit.', -) # type: Callable[..., Option] - -quiet = partial( - Option, - '-q', '--quiet', - dest='quiet', - action='count', - default=0, - help=( - 'Give less output. Option is additive, and can be used up to 3' - ' times (corresponding to WARNING, ERROR, and CRITICAL logging' - ' levels).' - ), -) # type: Callable[..., Option] - -progress_bar = partial( - Option, - '--progress-bar', - dest='progress_bar', - type='choice', - choices=list(BAR_TYPES.keys()), - default='on', - help=( - 'Specify type of progress to be displayed [' + - '|'.join(BAR_TYPES.keys()) + '] (default: %default)' - ), -) # type: Callable[..., Option] - -log = partial( - PipOption, - "--log", "--log-file", "--local-log", - dest="log", - metavar="path", - type="path", - help="Path to a verbose appending log." -) # type: Callable[..., Option] - -no_input = partial( - Option, - # Don't ask for input - '--no-input', - dest='no_input', - action='store_true', - default=False, - help=SUPPRESS_HELP -) # type: Callable[..., Option] - -proxy = partial( - Option, - '--proxy', - dest='proxy', - type='str', - default='', - help="Specify a proxy in the form [user:passwd@]proxy.server:port." -) # type: Callable[..., Option] - -retries = partial( - Option, - '--retries', - dest='retries', - type='int', - default=5, - help="Maximum number of retries each connection should attempt " - "(default %default times).", -) # type: Callable[..., Option] - -timeout = partial( - Option, - '--timeout', '--default-timeout', - metavar='sec', - dest='timeout', - type='float', - default=15, - help='Set the socket timeout (default %default seconds).', -) # type: Callable[..., Option] - - -def exists_action(): - # type: () -> Option - return Option( - # Option when path already exist - '--exists-action', - dest='exists_action', - type='choice', - choices=['s', 'i', 'w', 'b', 'a'], - default=[], - action='append', - metavar='action', - help="Default action when a path already exists: " - "(s)witch, (i)gnore, (w)ipe, (b)ackup, (a)bort.", - ) - - -cert = partial( - PipOption, - '--cert', - dest='cert', - type='path', - metavar='path', - help="Path to alternate CA bundle.", -) # type: Callable[..., Option] - -client_cert = partial( - PipOption, - '--client-cert', - dest='client_cert', - type='path', - default=None, - metavar='path', - help="Path to SSL client certificate, a single file containing the " - "private key and the certificate in PEM format.", -) # type: Callable[..., Option] - -index_url = partial( - Option, - '-i', '--index-url', '--pypi-url', - dest='index_url', - metavar='URL', - default=PyPI.simple_url, - help="Base URL of the Python Package Index (default %default). " - "This should point to a repository compliant with PEP 503 " - "(the simple repository API) or a local directory laid out " - "in the same format.", -) # type: Callable[..., Option] - - -def extra_index_url(): - # type: () -> Option - return Option( - '--extra-index-url', - dest='extra_index_urls', - metavar='URL', - action='append', - default=[], - help="Extra URLs of package indexes to use in addition to " - "--index-url. Should follow the same rules as " - "--index-url.", - ) - - -no_index = partial( - Option, - '--no-index', - dest='no_index', - action='store_true', - default=False, - help='Ignore package index (only looking at --find-links URLs instead).', -) # type: Callable[..., Option] - - -def find_links(): - # type: () -> Option - return Option( - '-f', '--find-links', - dest='find_links', - action='append', - default=[], - metavar='url', - help="If a URL or path to an html file, then parse for links to " - "archives such as sdist (.tar.gz) or wheel (.whl) files. " - "If a local path or file:// URL that's a directory, " - "then look for archives in the directory listing. " - "Links to VCS project URLs are not supported.", - ) - - -def trusted_host(): - # type: () -> Option - return Option( - "--trusted-host", - dest="trusted_hosts", - action="append", - metavar="HOSTNAME", - default=[], - help="Mark this host or host:port pair as trusted, even though it " - "does not have valid or any HTTPS.", - ) - - -def constraints(): - # type: () -> Option - return Option( - '-c', '--constraint', - dest='constraints', - action='append', - default=[], - metavar='file', - help='Constrain versions using the given constraints file. ' - 'This option can be used multiple times.' - ) - - -def requirements(): - # type: () -> Option - return Option( - '-r', '--requirement', - dest='requirements', - action='append', - default=[], - metavar='file', - help='Install from the given requirements file. ' - 'This option can be used multiple times.' - ) - - -def editable(): - # type: () -> Option - return Option( - '-e', '--editable', - dest='editables', - action='append', - default=[], - metavar='path/url', - help=('Install a project in editable mode (i.e. setuptools ' - '"develop mode") from a local project path or a VCS url.'), - ) - - -def _handle_src(option, opt_str, value, parser): - # type: (Option, str, str, OptionParser) -> None - value = os.path.abspath(value) - setattr(parser.values, option.dest, value) - - -src = partial( - PipOption, - '--src', '--source', '--source-dir', '--source-directory', - dest='src_dir', - type='path', - metavar='dir', - default=get_src_prefix(), - action='callback', - callback=_handle_src, - help='Directory to check out editable projects into. ' - 'The default in a virtualenv is "<venv path>/src". ' - 'The default for global installs is "<current dir>/src".' -) # type: Callable[..., Option] - - -def _get_format_control(values, option): - # type: (Values, Option) -> Any - """Get a format_control object.""" - return getattr(values, option.dest) - - -def _handle_no_binary(option, opt_str, value, parser): - # type: (Option, str, str, OptionParser) -> None - existing = _get_format_control(parser.values, option) - FormatControl.handle_mutual_excludes( - value, existing.no_binary, existing.only_binary, - ) - - -def _handle_only_binary(option, opt_str, value, parser): - # type: (Option, str, str, OptionParser) -> None - existing = _get_format_control(parser.values, option) - FormatControl.handle_mutual_excludes( - value, existing.only_binary, existing.no_binary, - ) - - -def no_binary(): - # type: () -> Option - format_control = FormatControl(set(), set()) - return Option( - "--no-binary", dest="format_control", action="callback", - callback=_handle_no_binary, type="str", - default=format_control, - help='Do not use binary packages. Can be supplied multiple times, and ' - 'each time adds to the existing value. Accepts either ":all:" to ' - 'disable all binary packages, ":none:" to empty the set (notice ' - 'the colons), or one or more package names with commas between ' - 'them (no colons). Note that some packages are tricky to compile ' - 'and may fail to install when this option is used on them.', - ) - - -def only_binary(): - # type: () -> Option - format_control = FormatControl(set(), set()) - return Option( - "--only-binary", dest="format_control", action="callback", - callback=_handle_only_binary, type="str", - default=format_control, - help='Do not use source packages. Can be supplied multiple times, and ' - 'each time adds to the existing value. Accepts either ":all:" to ' - 'disable all source packages, ":none:" to empty the set, or one ' - 'or more package names with commas between them. Packages ' - 'without binary distributions will fail to install when this ' - 'option is used on them.', - ) - - -platform = partial( - Option, - '--platform', - dest='platform', - metavar='platform', - default=None, - help=("Only use wheels compatible with <platform>. " - "Defaults to the platform of the running system."), -) # type: Callable[..., Option] - - -# This was made a separate function for unit-testing purposes. -def _convert_python_version(value): - # type: (str) -> Tuple[Tuple[int, ...], Optional[str]] - """ - Convert a version string like "3", "37", or "3.7.3" into a tuple of ints. - - :return: A 2-tuple (version_info, error_msg), where `error_msg` is - non-None if and only if there was a parsing error. - """ - if not value: - # The empty string is the same as not providing a value. - return (None, None) - - parts = value.split('.') - if len(parts) > 3: - return ((), 'at most three version parts are allowed') - - if len(parts) == 1: - # Then we are in the case of "3" or "37". - value = parts[0] - if len(value) > 1: - parts = [value[0], value[1:]] - - try: - version_info = tuple(int(part) for part in parts) - except ValueError: - return ((), 'each version part must be an integer') - - return (version_info, None) - - -def _handle_python_version(option, opt_str, value, parser): - # type: (Option, str, str, OptionParser) -> None - """ - Handle a provided --python-version value. - """ - version_info, error_msg = _convert_python_version(value) - if error_msg is not None: - msg = ( - 'invalid --python-version value: {!r}: {}'.format( - value, error_msg, - ) - ) - raise_option_error(parser, option=option, msg=msg) - - parser.values.python_version = version_info - - -python_version = partial( - Option, - '--python-version', - dest='python_version', - metavar='python_version', - action='callback', - callback=_handle_python_version, type='str', - default=None, - help=dedent("""\ - The Python interpreter version to use for wheel and "Requires-Python" - compatibility checks. Defaults to a version derived from the running - interpreter. The version can be specified using up to three dot-separated - integers (e.g. "3" for 3.0.0, "3.7" for 3.7.0, or "3.7.3"). A major-minor - version can also be given as a string without dots (e.g. "37" for 3.7.0). - """), -) # type: Callable[..., Option] - - -implementation = partial( - Option, - '--implementation', - dest='implementation', - metavar='implementation', - default=None, - help=("Only use wheels compatible with Python " - "implementation <implementation>, e.g. 'pp', 'jy', 'cp', " - " or 'ip'. If not specified, then the current " - "interpreter implementation is used. Use 'py' to force " - "implementation-agnostic wheels."), -) # type: Callable[..., Option] - - -abi = partial( - Option, - '--abi', - dest='abi', - metavar='abi', - default=None, - help=("Only use wheels compatible with Python " - "abi <abi>, e.g. 'pypy_41'. If not specified, then the " - "current interpreter abi tag is used. Generally " - "you will need to specify --implementation, " - "--platform, and --python-version when using " - "this option."), -) # type: Callable[..., Option] - - -def add_target_python_options(cmd_opts): - # type: (OptionGroup) -> None - cmd_opts.add_option(platform()) - cmd_opts.add_option(python_version()) - cmd_opts.add_option(implementation()) - cmd_opts.add_option(abi()) - - -def make_target_python(options): - # type: (Values) -> TargetPython - target_python = TargetPython( - platform=options.platform, - py_version_info=options.python_version, - abi=options.abi, - implementation=options.implementation, - ) - - return target_python - - -def prefer_binary(): - # type: () -> Option - return Option( - "--prefer-binary", - dest="prefer_binary", - action="store_true", - default=False, - help="Prefer older binary packages over newer source packages." - ) - - -cache_dir = partial( - PipOption, - "--cache-dir", - dest="cache_dir", - default=USER_CACHE_DIR, - metavar="dir", - type='path', - help="Store the cache data in <dir>." -) # type: Callable[..., Option] - - -def _handle_no_cache_dir(option, opt, value, parser): - # type: (Option, str, str, OptionParser) -> None - """ - Process a value provided for the --no-cache-dir option. - - This is an optparse.Option callback for the --no-cache-dir option. - """ - # The value argument will be None if --no-cache-dir is passed via the - # command-line, since the option doesn't accept arguments. However, - # the value can be non-None if the option is triggered e.g. by an - # environment variable, like PIP_NO_CACHE_DIR=true. - if value is not None: - # Then parse the string value to get argument error-checking. - try: - strtobool(value) - except ValueError as exc: - raise_option_error(parser, option=option, msg=str(exc)) - - # Originally, setting PIP_NO_CACHE_DIR to a value that strtobool() - # converted to 0 (like "false" or "no") caused cache_dir to be disabled - # rather than enabled (logic would say the latter). Thus, we disable - # the cache directory not just on values that parse to True, but (for - # backwards compatibility reasons) also on values that parse to False. - # In other words, always set it to False if the option is provided in - # some (valid) form. - parser.values.cache_dir = False - - -no_cache = partial( - Option, - "--no-cache-dir", - dest="cache_dir", - action="callback", - callback=_handle_no_cache_dir, - help="Disable the cache.", -) # type: Callable[..., Option] - -no_deps = partial( - Option, - '--no-deps', '--no-dependencies', - dest='ignore_dependencies', - action='store_true', - default=False, - help="Don't install package dependencies.", -) # type: Callable[..., Option] - - -def _handle_build_dir(option, opt, value, parser): - # type: (Option, str, str, OptionParser) -> None - if value: - value = os.path.abspath(value) - setattr(parser.values, option.dest, value) - - -build_dir = partial( - PipOption, - '-b', '--build', '--build-dir', '--build-directory', - dest='build_dir', - type='path', - metavar='dir', - action='callback', - callback=_handle_build_dir, - help='Directory to unpack packages into and build in. Note that ' - 'an initial build still takes place in a temporary directory. ' - 'The location of temporary directories can be controlled by setting ' - 'the TMPDIR environment variable (TEMP on Windows) appropriately. ' - 'When passed, build directories are not cleaned in case of failures.' -) # type: Callable[..., Option] - -ignore_requires_python = partial( - Option, - '--ignore-requires-python', - dest='ignore_requires_python', - action='store_true', - help='Ignore the Requires-Python information.' -) # type: Callable[..., Option] - -no_build_isolation = partial( - Option, - '--no-build-isolation', - dest='build_isolation', - action='store_false', - default=True, - help='Disable isolation when building a modern source distribution. ' - 'Build dependencies specified by PEP 518 must be already installed ' - 'if this option is used.' -) # type: Callable[..., Option] - - -def _handle_no_use_pep517(option, opt, value, parser): - # type: (Option, str, str, OptionParser) -> None - """ - Process a value provided for the --no-use-pep517 option. - - This is an optparse.Option callback for the no_use_pep517 option. - """ - # Since --no-use-pep517 doesn't accept arguments, the value argument - # will be None if --no-use-pep517 is passed via the command-line. - # However, the value can be non-None if the option is triggered e.g. - # by an environment variable, for example "PIP_NO_USE_PEP517=true". - if value is not None: - msg = """A value was passed for --no-use-pep517, - probably using either the PIP_NO_USE_PEP517 environment variable - or the "no-use-pep517" config file option. Use an appropriate value - of the PIP_USE_PEP517 environment variable or the "use-pep517" - config file option instead. - """ - raise_option_error(parser, option=option, msg=msg) - - # Otherwise, --no-use-pep517 was passed via the command-line. - parser.values.use_pep517 = False - - -use_pep517 = partial( - Option, - '--use-pep517', - dest='use_pep517', - action='store_true', - default=None, - help='Use PEP 517 for building source distributions ' - '(use --no-use-pep517 to force legacy behaviour).' -) # type: Any - -no_use_pep517 = partial( - Option, - '--no-use-pep517', - dest='use_pep517', - action='callback', - callback=_handle_no_use_pep517, - default=None, - help=SUPPRESS_HELP -) # type: Any - -install_options = partial( - Option, - '--install-option', - dest='install_options', - action='append', - metavar='options', - help="Extra arguments to be supplied to the setup.py install " - "command (use like --install-option=\"--install-scripts=/usr/local/" - "bin\"). Use multiple --install-option options to pass multiple " - "options to setup.py install. If you are using an option with a " - "directory path, be sure to use absolute path.", -) # type: Callable[..., Option] - -global_options = partial( - Option, - '--global-option', - dest='global_options', - action='append', - metavar='options', - help="Extra global options to be supplied to the setup.py " - "call before the install command.", -) # type: Callable[..., Option] - -no_clean = partial( - Option, - '--no-clean', - action='store_true', - default=False, - help="Don't clean up build directories." -) # type: Callable[..., Option] - -pre = partial( - Option, - '--pre', - action='store_true', - default=False, - help="Include pre-release and development versions. By default, " - "pip only finds stable versions.", -) # type: Callable[..., Option] - -disable_pip_version_check = partial( - Option, - "--disable-pip-version-check", - dest="disable_pip_version_check", - action="store_true", - default=True, - help="Don't periodically check PyPI to determine whether a new version " - "of pip is available for download. Implied with --no-index.", -) # type: Callable[..., Option] - - -# Deprecated, Remove later -always_unzip = partial( - Option, - '-Z', '--always-unzip', - dest='always_unzip', - action='store_true', - help=SUPPRESS_HELP, -) # type: Callable[..., Option] - - -def _handle_merge_hash(option, opt_str, value, parser): - # type: (Option, str, str, OptionParser) -> None - """Given a value spelled "algo:digest", append the digest to a list - pointed to in a dict by the algo name.""" - if not parser.values.hashes: - parser.values.hashes = {} - try: - algo, digest = value.split(':', 1) - except ValueError: - parser.error('Arguments to {} must be a hash name ' - 'followed by a value, like --hash=sha256:' - 'abcde...'.format(opt_str)) - if algo not in STRONG_HASHES: - parser.error('Allowed hash algorithms for {} are {}.'.format( - opt_str, ', '.join(STRONG_HASHES))) - parser.values.hashes.setdefault(algo, []).append(digest) - - -hash = partial( - Option, - '--hash', - # Hash values eventually end up in InstallRequirement.hashes due to - # __dict__ copying in process_line(). - dest='hashes', - action='callback', - callback=_handle_merge_hash, - type='string', - help="Verify that the package's archive matches this " - 'hash before installing. Example: --hash=sha256:abcdef...', -) # type: Callable[..., Option] - - -require_hashes = partial( - Option, - '--require-hashes', - dest='require_hashes', - action='store_true', - default=False, - help='Require a hash to check each requirement against, for ' - 'repeatable installs. This option is implied when any package in a ' - 'requirements file has a --hash option.', -) # type: Callable[..., Option] - - -list_path = partial( - PipOption, - '--path', - dest='path', - type='path', - action='append', - help='Restrict to the specified installation path for listing ' - 'packages (can be used multiple times).' -) # type: Callable[..., Option] - - -def check_list_path_option(options): - # type: (Values) -> None - if options.path and (options.user or options.local): - raise CommandError( - "Cannot combine '--path' with '--user' or '--local'" - ) - - -no_python_version_warning = partial( - Option, - '--no-python-version-warning', - dest='no_python_version_warning', - action='store_true', - default=False, - help='Silence deprecation warnings for upcoming unsupported Pythons.', -) # type: Callable[..., Option] - - -unstable_feature = partial( - Option, - '--unstable-feature', - dest='unstable_features', - metavar='feature', - action='append', - default=[], - choices=['resolver'], - help=SUPPRESS_HELP, # TODO: Enable this when the resolver actually works. - # help='Enable unstable feature(s) that may be backward incompatible.', -) # type: Callable[..., Option] - - -########## -# groups # -########## - -general_group = { - 'name': 'General Options', - 'options': [ - help_, - isolated_mode, - require_virtualenv, - verbose, - version, - quiet, - log, - no_input, - proxy, - retries, - timeout, - exists_action, - trusted_host, - cert, - client_cert, - cache_dir, - no_cache, - disable_pip_version_check, - no_color, - no_python_version_warning, - unstable_feature, - ] -} # type: Dict[str, Any] - -index_group = { - 'name': 'Package Index Options', - 'options': [ - index_url, - extra_index_url, - no_index, - find_links, - ] -} # type: Dict[str, Any] diff --git a/venv/lib/python3.8/site-packages/pip/_internal/cli/command_context.py b/venv/lib/python3.8/site-packages/pip/_internal/cli/command_context.py deleted file mode 100644 index d1a64a7..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/cli/command_context.py +++ /dev/null @@ -1,36 +0,0 @@ -from contextlib import contextmanager - -from pip._vendor.contextlib2 import ExitStack - -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import Iterator, ContextManager, TypeVar - - _T = TypeVar('_T', covariant=True) - - -class CommandContextMixIn(object): - def __init__(self): - # type: () -> None - super(CommandContextMixIn, self).__init__() - self._in_main_context = False - self._main_context = ExitStack() - - @contextmanager - def main_context(self): - # type: () -> Iterator[None] - assert not self._in_main_context - - self._in_main_context = True - try: - with self._main_context: - yield - finally: - self._in_main_context = False - - def enter_context(self, context_provider): - # type: (ContextManager[_T]) -> _T - assert self._in_main_context - - return self._main_context.enter_context(context_provider) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/cli/main.py b/venv/lib/python3.8/site-packages/pip/_internal/cli/main.py deleted file mode 100644 index 172f30d..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/cli/main.py +++ /dev/null @@ -1,75 +0,0 @@ -"""Primary application entrypoint. -""" -from __future__ import absolute_import - -import locale -import logging -import os -import sys - -from pip._internal.cli.autocompletion import autocomplete -from pip._internal.cli.main_parser import parse_command -from pip._internal.commands import create_command -from pip._internal.exceptions import PipError -from pip._internal.utils import deprecation -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import List, Optional - -logger = logging.getLogger(__name__) - - -# Do not import and use main() directly! Using it directly is actively -# discouraged by pip's maintainers. The name, location and behavior of -# this function is subject to change, so calling it directly is not -# portable across different pip versions. - -# In addition, running pip in-process is unsupported and unsafe. This is -# elaborated in detail at -# https://pip.pypa.io/en/stable/user_guide/#using-pip-from-your-program. -# That document also provides suggestions that should work for nearly -# all users that are considering importing and using main() directly. - -# However, we know that certain users will still want to invoke pip -# in-process. If you understand and accept the implications of using pip -# in an unsupported manner, the best approach is to use runpy to avoid -# depending on the exact location of this entry point. - -# The following example shows how to use runpy to invoke pip in that -# case: -# -# sys.argv = ["pip", your, args, here] -# runpy.run_module("pip", run_name="__main__") -# -# Note that this will exit the process after running, unlike a direct -# call to main. As it is not safe to do any processing after calling -# main, this should not be an issue in practice. - -def main(args=None): - # type: (Optional[List[str]]) -> int - if args is None: - args = sys.argv[1:] - - # Configure our deprecation warnings to be sent through loggers - deprecation.install_warning_logger() - - autocomplete() - - try: - cmd_name, cmd_args = parse_command(args) - except PipError as exc: - sys.stderr.write("ERROR: {}".format(exc)) - sys.stderr.write(os.linesep) - sys.exit(1) - - # Needed for locale.getpreferredencoding(False) to work - # in pip._internal.utils.encoding.auto_decode - try: - locale.setlocale(locale.LC_ALL, '') - except locale.Error as e: - # setlocale can apparently crash if locale are uninitialized - logger.debug("Ignoring error %s when setting locale", e) - command = create_command(cmd_name, isolated=("--isolated" in cmd_args)) - - return command.main(cmd_args) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/cli/main_parser.py b/venv/lib/python3.8/site-packages/pip/_internal/cli/main_parser.py deleted file mode 100644 index 08c82c1..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/cli/main_parser.py +++ /dev/null @@ -1,99 +0,0 @@ -"""A single place for constructing and exposing the main parser -""" - -import os -import sys - -from pip._internal.cli import cmdoptions -from pip._internal.cli.parser import ( - ConfigOptionParser, - UpdatingDefaultsHelpFormatter, -) -from pip._internal.commands import commands_dict, get_similar_commands -from pip._internal.exceptions import CommandError -from pip._internal.utils.misc import get_pip_version, get_prog -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import Tuple, List - - -__all__ = ["create_main_parser", "parse_command"] - - -def create_main_parser(): - # type: () -> ConfigOptionParser - """Creates and returns the main parser for pip's CLI - """ - - parser_kw = { - 'usage': '\n%prog <command> [options]', - 'add_help_option': False, - 'formatter': UpdatingDefaultsHelpFormatter(), - 'name': 'global', - 'prog': get_prog(), - } - - parser = ConfigOptionParser(**parser_kw) - parser.disable_interspersed_args() - - parser.version = get_pip_version() - - # add the general options - gen_opts = cmdoptions.make_option_group(cmdoptions.general_group, parser) - parser.add_option_group(gen_opts) - - # so the help formatter knows - parser.main = True # type: ignore - - # create command listing for description - description = [''] + [ - '{name:27} {command_info.summary}'.format(**locals()) - for name, command_info in commands_dict.items() - ] - parser.description = '\n'.join(description) - - return parser - - -def parse_command(args): - # type: (List[str]) -> Tuple[str, List[str]] - parser = create_main_parser() - - # Note: parser calls disable_interspersed_args(), so the result of this - # call is to split the initial args into the general options before the - # subcommand and everything else. - # For example: - # args: ['--timeout=5', 'install', '--user', 'INITools'] - # general_options: ['--timeout==5'] - # args_else: ['install', '--user', 'INITools'] - general_options, args_else = parser.parse_args(args) - - # --version - if general_options.version: - sys.stdout.write(parser.version) # type: ignore - sys.stdout.write(os.linesep) - sys.exit() - - # pip || pip help -> print_help() - if not args_else or (args_else[0] == 'help' and len(args_else) == 1): - parser.print_help() - sys.exit() - - # the subcommand name - cmd_name = args_else[0] - - if cmd_name not in commands_dict: - guess = get_similar_commands(cmd_name) - - msg = ['unknown command "{}"'.format(cmd_name)] - if guess: - msg.append('maybe you meant "{}"'.format(guess)) - - raise CommandError(' - '.join(msg)) - - # all the args without the subcommand - cmd_args = args[:] - cmd_args.remove(cmd_name) - - return cmd_name, cmd_args diff --git a/venv/lib/python3.8/site-packages/pip/_internal/cli/parser.py b/venv/lib/python3.8/site-packages/pip/_internal/cli/parser.py deleted file mode 100644 index 04e00b7..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/cli/parser.py +++ /dev/null @@ -1,266 +0,0 @@ -"""Base option parser setup""" - -# The following comment should be removed at some point in the future. -# mypy: disallow-untyped-defs=False - -from __future__ import absolute_import - -import logging -import optparse -import sys -import textwrap -from distutils.util import strtobool - -from pip._vendor.six import string_types - -from pip._internal.cli.status_codes import UNKNOWN_ERROR -from pip._internal.configuration import Configuration, ConfigurationError -from pip._internal.utils.compat import get_terminal_size - -logger = logging.getLogger(__name__) - - -class PrettyHelpFormatter(optparse.IndentedHelpFormatter): - """A prettier/less verbose help formatter for optparse.""" - - def __init__(self, *args, **kwargs): - # help position must be aligned with __init__.parseopts.description - kwargs['max_help_position'] = 30 - kwargs['indent_increment'] = 1 - kwargs['width'] = get_terminal_size()[0] - 2 - optparse.IndentedHelpFormatter.__init__(self, *args, **kwargs) - - def format_option_strings(self, option): - return self._format_option_strings(option) - - def _format_option_strings(self, option, mvarfmt=' <{}>', optsep=', '): - """ - Return a comma-separated list of option strings and metavars. - - :param option: tuple of (short opt, long opt), e.g: ('-f', '--format') - :param mvarfmt: metavar format string - :param optsep: separator - """ - opts = [] - - if option._short_opts: - opts.append(option._short_opts[0]) - if option._long_opts: - opts.append(option._long_opts[0]) - if len(opts) > 1: - opts.insert(1, optsep) - - if option.takes_value(): - metavar = option.metavar or option.dest.lower() - opts.append(mvarfmt.format(metavar.lower())) - - return ''.join(opts) - - def format_heading(self, heading): - if heading == 'Options': - return '' - return heading + ':\n' - - def format_usage(self, usage): - """ - Ensure there is only one newline between usage and the first heading - if there is no description. - """ - msg = '\nUsage: {}\n'.format( - self.indent_lines(textwrap.dedent(usage), " ")) - return msg - - def format_description(self, description): - # leave full control over description to us - if description: - if hasattr(self.parser, 'main'): - label = 'Commands' - else: - label = 'Description' - # some doc strings have initial newlines, some don't - description = description.lstrip('\n') - # some doc strings have final newlines and spaces, some don't - description = description.rstrip() - # dedent, then reindent - description = self.indent_lines(textwrap.dedent(description), " ") - description = '{}:\n{}\n'.format(label, description) - return description - else: - return '' - - def format_epilog(self, epilog): - # leave full control over epilog to us - if epilog: - return epilog - else: - return '' - - def indent_lines(self, text, indent): - new_lines = [indent + line for line in text.split('\n')] - return "\n".join(new_lines) - - -class UpdatingDefaultsHelpFormatter(PrettyHelpFormatter): - """Custom help formatter for use in ConfigOptionParser. - - This is updates the defaults before expanding them, allowing - them to show up correctly in the help listing. - """ - - def expand_default(self, option): - if self.parser is not None: - self.parser._update_defaults(self.parser.defaults) - return optparse.IndentedHelpFormatter.expand_default(self, option) - - -class CustomOptionParser(optparse.OptionParser): - - def insert_option_group(self, idx, *args, **kwargs): - """Insert an OptionGroup at a given position.""" - group = self.add_option_group(*args, **kwargs) - - self.option_groups.pop() - self.option_groups.insert(idx, group) - - return group - - @property - def option_list_all(self): - """Get a list of all options, including those in option groups.""" - res = self.option_list[:] - for i in self.option_groups: - res.extend(i.option_list) - - return res - - -class ConfigOptionParser(CustomOptionParser): - """Custom option parser which updates its defaults by checking the - configuration files and environmental variables""" - - def __init__(self, *args, **kwargs): - self.name = kwargs.pop('name') - - isolated = kwargs.pop("isolated", False) - self.config = Configuration(isolated) - - assert self.name - optparse.OptionParser.__init__(self, *args, **kwargs) - - def check_default(self, option, key, val): - try: - return option.check_value(key, val) - except optparse.OptionValueError as exc: - print("An error occurred during configuration: {}".format(exc)) - sys.exit(3) - - def _get_ordered_configuration_items(self): - # Configuration gives keys in an unordered manner. Order them. - override_order = ["global", self.name, ":env:"] - - # Pool the options into different groups - section_items = {name: [] for name in override_order} - for section_key, val in self.config.items(): - # ignore empty values - if not val: - logger.debug( - "Ignoring configuration key '%s' as it's value is empty.", - section_key - ) - continue - - section, key = section_key.split(".", 1) - if section in override_order: - section_items[section].append((key, val)) - - # Yield each group in their override order - for section in override_order: - for key, val in section_items[section]: - yield key, val - - def _update_defaults(self, defaults): - """Updates the given defaults with values from the config files and - the environ. Does a little special handling for certain types of - options (lists).""" - - # Accumulate complex default state. - self.values = optparse.Values(self.defaults) - late_eval = set() - # Then set the options with those values - for key, val in self._get_ordered_configuration_items(): - # '--' because configuration supports only long names - option = self.get_option('--' + key) - - # Ignore options not present in this parser. E.g. non-globals put - # in [global] by users that want them to apply to all applicable - # commands. - if option is None: - continue - - if option.action in ('store_true', 'store_false', 'count'): - try: - val = strtobool(val) - except ValueError: - error_msg = invalid_config_error_message( - option.action, key, val - ) - self.error(error_msg) - - elif option.action == 'append': - val = val.split() - val = [self.check_default(option, key, v) for v in val] - elif option.action == 'callback': - late_eval.add(option.dest) - opt_str = option.get_opt_string() - val = option.convert_value(opt_str, val) - # From take_action - args = option.callback_args or () - kwargs = option.callback_kwargs or {} - option.callback(option, opt_str, val, self, *args, **kwargs) - else: - val = self.check_default(option, key, val) - - defaults[option.dest] = val - - for key in late_eval: - defaults[key] = getattr(self.values, key) - self.values = None - return defaults - - def get_default_values(self): - """Overriding to make updating the defaults after instantiation of - the option parser possible, _update_defaults() does the dirty work.""" - if not self.process_default_values: - # Old, pre-Optik 1.5 behaviour. - return optparse.Values(self.defaults) - - # Load the configuration, or error out in case of an error - try: - self.config.load() - except ConfigurationError as err: - self.exit(UNKNOWN_ERROR, str(err)) - - defaults = self._update_defaults(self.defaults.copy()) # ours - for option in self._get_all_options(): - default = defaults.get(option.dest) - if isinstance(default, string_types): - opt_str = option.get_opt_string() - defaults[option.dest] = option.check_value(opt_str, default) - return optparse.Values(defaults) - - def error(self, msg): - self.print_usage(sys.stderr) - self.exit(UNKNOWN_ERROR, "{}\n".format(msg)) - - -def invalid_config_error_message(action, key, val): - """Returns a better error message when invalid configuration option - is provided.""" - if action in ('store_true', 'store_false'): - return ("{0} is not a valid value for {1} option, " - "please specify a boolean value like yes/no, " - "true/false or 1/0 instead.").format(val, key) - - return ("{0} is not a valid value for {1} option, " - "please specify a numerical value like 1/0 " - "instead.").format(val, key) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/cli/progress_bars.py b/venv/lib/python3.8/site-packages/pip/_internal/cli/progress_bars.py deleted file mode 100644 index 7ed2247..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/cli/progress_bars.py +++ /dev/null @@ -1,277 +0,0 @@ -from __future__ import division - -import itertools -import sys -from signal import SIGINT, default_int_handler, signal - -from pip._vendor import six -from pip._vendor.progress.bar import Bar, FillingCirclesBar, IncrementalBar -from pip._vendor.progress.spinner import Spinner - -from pip._internal.utils.compat import WINDOWS -from pip._internal.utils.logging import get_indentation -from pip._internal.utils.misc import format_size -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import Any, Dict, List - -try: - from pip._vendor import colorama -# Lots of different errors can come from this, including SystemError and -# ImportError. -except Exception: - colorama = None - - -def _select_progress_class(preferred, fallback): - # type: (Bar, Bar) -> Bar - encoding = getattr(preferred.file, "encoding", None) - - # If we don't know what encoding this file is in, then we'll just assume - # that it doesn't support unicode and use the ASCII bar. - if not encoding: - return fallback - - # Collect all of the possible characters we want to use with the preferred - # bar. - characters = [ - getattr(preferred, "empty_fill", six.text_type()), - getattr(preferred, "fill", six.text_type()), - ] - characters += list(getattr(preferred, "phases", [])) - - # Try to decode the characters we're using for the bar using the encoding - # of the given file, if this works then we'll assume that we can use the - # fancier bar and if not we'll fall back to the plaintext bar. - try: - six.text_type().join(characters).encode(encoding) - except UnicodeEncodeError: - return fallback - else: - return preferred - - -_BaseBar = _select_progress_class(IncrementalBar, Bar) # type: Any - - -class InterruptibleMixin(object): - """ - Helper to ensure that self.finish() gets called on keyboard interrupt. - - This allows downloads to be interrupted without leaving temporary state - (like hidden cursors) behind. - - This class is similar to the progress library's existing SigIntMixin - helper, but as of version 1.2, that helper has the following problems: - - 1. It calls sys.exit(). - 2. It discards the existing SIGINT handler completely. - 3. It leaves its own handler in place even after an uninterrupted finish, - which will have unexpected delayed effects if the user triggers an - unrelated keyboard interrupt some time after a progress-displaying - download has already completed, for example. - """ - - def __init__(self, *args, **kwargs): - # type: (List[Any], Dict[Any, Any]) -> None - """ - Save the original SIGINT handler for later. - """ - super(InterruptibleMixin, self).__init__( # type: ignore - *args, - **kwargs - ) - - self.original_handler = signal(SIGINT, self.handle_sigint) - - # If signal() returns None, the previous handler was not installed from - # Python, and we cannot restore it. This probably should not happen, - # but if it does, we must restore something sensible instead, at least. - # The least bad option should be Python's default SIGINT handler, which - # just raises KeyboardInterrupt. - if self.original_handler is None: - self.original_handler = default_int_handler - - def finish(self): - # type: () -> None - """ - Restore the original SIGINT handler after finishing. - - This should happen regardless of whether the progress display finishes - normally, or gets interrupted. - """ - super(InterruptibleMixin, self).finish() # type: ignore - signal(SIGINT, self.original_handler) - - def handle_sigint(self, signum, frame): # type: ignore - """ - Call self.finish() before delegating to the original SIGINT handler. - - This handler should only be in place while the progress display is - active. - """ - self.finish() - self.original_handler(signum, frame) - - -class SilentBar(Bar): - - def update(self): - # type: () -> None - pass - - -class BlueEmojiBar(IncrementalBar): - - suffix = "%(percent)d%%" - bar_prefix = " " - bar_suffix = " " - phases = (u"\U0001F539", u"\U0001F537", u"\U0001F535") # type: Any - - -class DownloadProgressMixin(object): - - def __init__(self, *args, **kwargs): - # type: (List[Any], Dict[Any, Any]) -> None - super(DownloadProgressMixin, self).__init__( # type: ignore - *args, - **kwargs - ) - self.message = (" " * ( - get_indentation() + 2 - )) + self.message # type: str - - @property - def downloaded(self): - # type: () -> str - return format_size(self.index) # type: ignore - - @property - def download_speed(self): - # type: () -> str - # Avoid zero division errors... - if self.avg == 0.0: # type: ignore - return "..." - return format_size(1 / self.avg) + "/s" # type: ignore - - @property - def pretty_eta(self): - # type: () -> str - if self.eta: # type: ignore - return "eta {}".format(self.eta_td) # type: ignore - return "" - - def iter(self, it): # type: ignore - for x in it: - yield x - self.next(len(x)) - self.finish() - - -class WindowsMixin(object): - - def __init__(self, *args, **kwargs): - # type: (List[Any], Dict[Any, Any]) -> None - # The Windows terminal does not support the hide/show cursor ANSI codes - # even with colorama. So we'll ensure that hide_cursor is False on - # Windows. - # This call needs to go before the super() call, so that hide_cursor - # is set in time. The base progress bar class writes the "hide cursor" - # code to the terminal in its init, so if we don't set this soon - # enough, we get a "hide" with no corresponding "show"... - if WINDOWS and self.hide_cursor: # type: ignore - self.hide_cursor = False - - super(WindowsMixin, self).__init__(*args, **kwargs) # type: ignore - - # Check if we are running on Windows and we have the colorama module, - # if we do then wrap our file with it. - if WINDOWS and colorama: - self.file = colorama.AnsiToWin32(self.file) # type: ignore - # The progress code expects to be able to call self.file.isatty() - # but the colorama.AnsiToWin32() object doesn't have that, so we'll - # add it. - self.file.isatty = lambda: self.file.wrapped.isatty() - # The progress code expects to be able to call self.file.flush() - # but the colorama.AnsiToWin32() object doesn't have that, so we'll - # add it. - self.file.flush = lambda: self.file.wrapped.flush() - - -class BaseDownloadProgressBar(WindowsMixin, InterruptibleMixin, - DownloadProgressMixin): - - file = sys.stdout - message = "%(percent)d%%" - suffix = "%(downloaded)s %(download_speed)s %(pretty_eta)s" - -# NOTE: The "type: ignore" comments on the following classes are there to -# work around https://github.com/python/typing/issues/241 - - -class DefaultDownloadProgressBar(BaseDownloadProgressBar, - _BaseBar): - pass - - -class DownloadSilentBar(BaseDownloadProgressBar, SilentBar): # type: ignore - pass - - -class DownloadBar(BaseDownloadProgressBar, # type: ignore - Bar): - pass - - -class DownloadFillingCirclesBar(BaseDownloadProgressBar, # type: ignore - FillingCirclesBar): - pass - - -class DownloadBlueEmojiProgressBar(BaseDownloadProgressBar, # type: ignore - BlueEmojiBar): - pass - - -class DownloadProgressSpinner(WindowsMixin, InterruptibleMixin, - DownloadProgressMixin, Spinner): - - file = sys.stdout - suffix = "%(downloaded)s %(download_speed)s" - - def next_phase(self): # type: ignore - if not hasattr(self, "_phaser"): - self._phaser = itertools.cycle(self.phases) - return next(self._phaser) - - def update(self): - # type: () -> None - message = self.message % self - phase = self.next_phase() - suffix = self.suffix % self - line = ''.join([ - message, - " " if message else "", - phase, - " " if suffix else "", - suffix, - ]) - - self.writeln(line) - - -BAR_TYPES = { - "off": (DownloadSilentBar, DownloadSilentBar), - "on": (DefaultDownloadProgressBar, DownloadProgressSpinner), - "ascii": (DownloadBar, DownloadProgressSpinner), - "pretty": (DownloadFillingCirclesBar, DownloadProgressSpinner), - "emoji": (DownloadBlueEmojiProgressBar, DownloadProgressSpinner) -} - - -def DownloadProgressProvider(progress_bar, max=None): # type: ignore - if max is None or max == 0: - return BAR_TYPES[progress_bar][1]().iter - else: - return BAR_TYPES[progress_bar][0](max=max).iter diff --git a/venv/lib/python3.8/site-packages/pip/_internal/cli/req_command.py b/venv/lib/python3.8/site-packages/pip/_internal/cli/req_command.py deleted file mode 100644 index 104b033..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/cli/req_command.py +++ /dev/null @@ -1,408 +0,0 @@ -"""Contains the Command base classes that depend on PipSession. - -The classes in this module are in a separate module so the commands not -needing download / PackageFinder capability don't unnecessarily import the -PackageFinder machinery and all its vendored dependencies, etc. -""" - -import logging -import os -from functools import partial - -from pip._internal.cli import cmdoptions -from pip._internal.cli.base_command import Command -from pip._internal.cli.command_context import CommandContextMixIn -from pip._internal.exceptions import CommandError, PreviousBuildDirError -from pip._internal.index.package_finder import PackageFinder -from pip._internal.models.selection_prefs import SelectionPreferences -from pip._internal.network.download import Downloader -from pip._internal.network.session import PipSession -from pip._internal.operations.prepare import RequirementPreparer -from pip._internal.req.constructors import ( - install_req_from_editable, - install_req_from_line, - install_req_from_parsed_requirement, - install_req_from_req_string, -) -from pip._internal.req.req_file import parse_requirements -from pip._internal.req.req_set import RequirementSet -from pip._internal.self_outdated_check import ( - make_link_collector, - pip_self_version_check, -) -from pip._internal.utils.temp_dir import tempdir_kinds -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from optparse import Values - from typing import Any, List, Optional, Tuple - - from pip._internal.cache import WheelCache - from pip._internal.models.target_python import TargetPython - from pip._internal.req.req_install import InstallRequirement - from pip._internal.req.req_tracker import RequirementTracker - from pip._internal.resolution.base import BaseResolver - from pip._internal.utils.temp_dir import ( - TempDirectory, - TempDirectoryTypeRegistry, - ) - - -logger = logging.getLogger(__name__) - - -class SessionCommandMixin(CommandContextMixIn): - - """ - A class mixin for command classes needing _build_session(). - """ - def __init__(self): - # type: () -> None - super(SessionCommandMixin, self).__init__() - self._session = None # Optional[PipSession] - - @classmethod - def _get_index_urls(cls, options): - # type: (Values) -> Optional[List[str]] - """Return a list of index urls from user-provided options.""" - index_urls = [] - if not getattr(options, "no_index", False): - url = getattr(options, "index_url", None) - if url: - index_urls.append(url) - urls = getattr(options, "extra_index_urls", None) - if urls: - index_urls.extend(urls) - # Return None rather than an empty list - return index_urls or None - - def get_default_session(self, options): - # type: (Values) -> PipSession - """Get a default-managed session.""" - if self._session is None: - self._session = self.enter_context(self._build_session(options)) - # there's no type annotation on requests.Session, so it's - # automatically ContextManager[Any] and self._session becomes Any, - # then https://github.com/python/mypy/issues/7696 kicks in - assert self._session is not None - return self._session - - def _build_session(self, options, retries=None, timeout=None): - # type: (Values, Optional[int], Optional[int]) -> PipSession - assert not options.cache_dir or os.path.isabs(options.cache_dir) - session = PipSession( - cache=( - os.path.join(options.cache_dir, "http") - if options.cache_dir else None - ), - retries=retries if retries is not None else options.retries, - trusted_hosts=options.trusted_hosts, - index_urls=self._get_index_urls(options), - ) - - # Handle custom ca-bundles from the user - if options.cert: - session.verify = options.cert - - # Handle SSL client certificate - if options.client_cert: - session.cert = options.client_cert - - # Handle timeouts - if options.timeout or timeout: - session.timeout = ( - timeout if timeout is not None else options.timeout - ) - - # Handle configured proxies - if options.proxy: - session.proxies = { - "http": options.proxy, - "https": options.proxy, - } - - # Determine if we can prompt the user for authentication or not - session.auth.prompting = not options.no_input - - return session - - -class IndexGroupCommand(Command, SessionCommandMixin): - - """ - Abstract base class for commands with the index_group options. - - This also corresponds to the commands that permit the pip version check. - """ - - def handle_pip_version_check(self, options): - # type: (Values) -> None - """ - Do the pip version check if not disabled. - - This overrides the default behavior of not doing the check. - """ - # Make sure the index_group options are present. - assert hasattr(options, 'no_index') - - if options.disable_pip_version_check or options.no_index: - return - - # Otherwise, check if we're using the latest version of pip available. - session = self._build_session( - options, - retries=0, - timeout=min(5, options.timeout) - ) - with session: - pip_self_version_check(session, options) - - -KEEPABLE_TEMPDIR_TYPES = [ - tempdir_kinds.BUILD_ENV, - tempdir_kinds.EPHEM_WHEEL_CACHE, - tempdir_kinds.REQ_BUILD, -] - - -def with_cleanup(func): - # type: (Any) -> Any - """Decorator for common logic related to managing temporary - directories. - """ - def configure_tempdir_registry(registry): - # type: (TempDirectoryTypeRegistry) -> None - for t in KEEPABLE_TEMPDIR_TYPES: - registry.set_delete(t, False) - - def wrapper(self, options, args): - # type: (RequirementCommand, Values, List[Any]) -> Optional[int] - assert self.tempdir_registry is not None - if options.no_clean: - configure_tempdir_registry(self.tempdir_registry) - - try: - return func(self, options, args) - except PreviousBuildDirError: - # This kind of conflict can occur when the user passes an explicit - # build directory with a pre-existing folder. In that case we do - # not want to accidentally remove it. - configure_tempdir_registry(self.tempdir_registry) - raise - - return wrapper - - -class RequirementCommand(IndexGroupCommand): - - def __init__(self, *args, **kw): - # type: (Any, Any) -> None - super(RequirementCommand, self).__init__(*args, **kw) - - self.cmd_opts.add_option(cmdoptions.no_clean()) - - @staticmethod - def make_requirement_preparer( - temp_build_dir, # type: TempDirectory - options, # type: Values - req_tracker, # type: RequirementTracker - session, # type: PipSession - finder, # type: PackageFinder - use_user_site, # type: bool - download_dir=None, # type: str - wheel_download_dir=None, # type: str - ): - # type: (...) -> RequirementPreparer - """ - Create a RequirementPreparer instance for the given parameters. - """ - downloader = Downloader(session, progress_bar=options.progress_bar) - - temp_build_dir_path = temp_build_dir.path - assert temp_build_dir_path is not None - - return RequirementPreparer( - build_dir=temp_build_dir_path, - src_dir=options.src_dir, - download_dir=download_dir, - wheel_download_dir=wheel_download_dir, - build_isolation=options.build_isolation, - req_tracker=req_tracker, - downloader=downloader, - finder=finder, - require_hashes=options.require_hashes, - use_user_site=use_user_site, - ) - - @staticmethod - def make_resolver( - preparer, # type: RequirementPreparer - finder, # type: PackageFinder - options, # type: Values - wheel_cache=None, # type: Optional[WheelCache] - use_user_site=False, # type: bool - ignore_installed=True, # type: bool - ignore_requires_python=False, # type: bool - force_reinstall=False, # type: bool - upgrade_strategy="to-satisfy-only", # type: str - use_pep517=None, # type: Optional[bool] - py_version_info=None # type: Optional[Tuple[int, ...]] - ): - # type: (...) -> BaseResolver - """ - Create a Resolver instance for the given parameters. - """ - make_install_req = partial( - install_req_from_req_string, - isolated=options.isolated_mode, - use_pep517=use_pep517, - ) - # The long import name and duplicated invocation is needed to convince - # Mypy into correctly typechecking. Otherwise it would complain the - # "Resolver" class being redefined. - if 'resolver' in options.unstable_features: - import pip._internal.resolution.resolvelib.resolver - return pip._internal.resolution.resolvelib.resolver.Resolver( - preparer=preparer, - finder=finder, - wheel_cache=wheel_cache, - make_install_req=make_install_req, - use_user_site=use_user_site, - ignore_dependencies=options.ignore_dependencies, - ignore_installed=ignore_installed, - ignore_requires_python=ignore_requires_python, - force_reinstall=force_reinstall, - upgrade_strategy=upgrade_strategy, - py_version_info=py_version_info, - ) - import pip._internal.resolution.legacy.resolver - return pip._internal.resolution.legacy.resolver.Resolver( - preparer=preparer, - finder=finder, - wheel_cache=wheel_cache, - make_install_req=make_install_req, - use_user_site=use_user_site, - ignore_dependencies=options.ignore_dependencies, - ignore_installed=ignore_installed, - ignore_requires_python=ignore_requires_python, - force_reinstall=force_reinstall, - upgrade_strategy=upgrade_strategy, - py_version_info=py_version_info, - ) - - def get_requirements( - self, - args, # type: List[str] - options, # type: Values - finder, # type: PackageFinder - session, # type: PipSession - check_supported_wheels=True, # type: bool - ): - # type: (...) -> List[InstallRequirement] - """ - Parse command-line arguments into the corresponding requirements. - """ - requirement_set = RequirementSet( - check_supported_wheels=check_supported_wheels - ) - for filename in options.constraints: - for parsed_req in parse_requirements( - filename, - constraint=True, finder=finder, options=options, - session=session): - req_to_add = install_req_from_parsed_requirement( - parsed_req, - isolated=options.isolated_mode, - ) - req_to_add.is_direct = True - requirement_set.add_requirement(req_to_add) - - for req in args: - req_to_add = install_req_from_line( - req, None, isolated=options.isolated_mode, - use_pep517=options.use_pep517, - ) - req_to_add.is_direct = True - requirement_set.add_requirement(req_to_add) - - for req in options.editables: - req_to_add = install_req_from_editable( - req, - isolated=options.isolated_mode, - use_pep517=options.use_pep517, - ) - req_to_add.is_direct = True - requirement_set.add_requirement(req_to_add) - - # NOTE: options.require_hashes may be set if --require-hashes is True - for filename in options.requirements: - for parsed_req in parse_requirements( - filename, - finder=finder, options=options, session=session): - req_to_add = install_req_from_parsed_requirement( - parsed_req, - isolated=options.isolated_mode, - use_pep517=options.use_pep517 - ) - req_to_add.is_direct = True - requirement_set.add_requirement(req_to_add) - - # If any requirement has hash options, enable hash checking. - requirements = requirement_set.all_requirements - if any(req.has_hash_options for req in requirements): - options.require_hashes = True - - if not (args or options.editables or options.requirements): - opts = {'name': self.name} - if options.find_links: - raise CommandError( - 'You must give at least one requirement to {name} ' - '(maybe you meant "pip {name} {links}"?)'.format( - **dict(opts, links=' '.join(options.find_links)))) - else: - raise CommandError( - 'You must give at least one requirement to {name} ' - '(see "pip help {name}")'.format(**opts)) - - return requirements - - @staticmethod - def trace_basic_info(finder): - # type: (PackageFinder) -> None - """ - Trace basic information about the provided objects. - """ - # Display where finder is looking for packages - search_scope = finder.search_scope - locations = search_scope.get_formatted_locations() - if locations: - logger.info(locations) - - def _build_package_finder( - self, - options, # type: Values - session, # type: PipSession - target_python=None, # type: Optional[TargetPython] - ignore_requires_python=None, # type: Optional[bool] - ): - # type: (...) -> PackageFinder - """ - Create a package finder appropriate to this requirement command. - - :param ignore_requires_python: Whether to ignore incompatible - "Requires-Python" values in links. Defaults to False. - """ - link_collector = make_link_collector(session, options=options) - selection_prefs = SelectionPreferences( - allow_yanked=True, - format_control=options.format_control, - allow_all_prereleases=options.pre, - prefer_binary=options.prefer_binary, - ignore_requires_python=ignore_requires_python, - ) - - return PackageFinder.create( - link_collector=link_collector, - selection_prefs=selection_prefs, - target_python=target_python, - ) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/cli/spinners.py b/venv/lib/python3.8/site-packages/pip/_internal/cli/spinners.py deleted file mode 100644 index c6c4c5c..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/cli/spinners.py +++ /dev/null @@ -1,173 +0,0 @@ -from __future__ import absolute_import, division - -import contextlib -import itertools -import logging -import sys -import time - -from pip._vendor.progress import HIDE_CURSOR, SHOW_CURSOR - -from pip._internal.utils.compat import WINDOWS -from pip._internal.utils.logging import get_indentation -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import Iterator, IO - -logger = logging.getLogger(__name__) - - -class SpinnerInterface(object): - def spin(self): - # type: () -> None - raise NotImplementedError() - - def finish(self, final_status): - # type: (str) -> None - raise NotImplementedError() - - -class InteractiveSpinner(SpinnerInterface): - def __init__(self, message, file=None, spin_chars="-\\|/", - # Empirically, 8 updates/second looks nice - min_update_interval_seconds=0.125): - # type: (str, IO[str], str, float) -> None - self._message = message - if file is None: - file = sys.stdout - self._file = file - self._rate_limiter = RateLimiter(min_update_interval_seconds) - self._finished = False - - self._spin_cycle = itertools.cycle(spin_chars) - - self._file.write(" " * get_indentation() + self._message + " ... ") - self._width = 0 - - def _write(self, status): - # type: (str) -> None - assert not self._finished - # Erase what we wrote before by backspacing to the beginning, writing - # spaces to overwrite the old text, and then backspacing again - backup = "\b" * self._width - self._file.write(backup + " " * self._width + backup) - # Now we have a blank slate to add our status - self._file.write(status) - self._width = len(status) - self._file.flush() - self._rate_limiter.reset() - - def spin(self): - # type: () -> None - if self._finished: - return - if not self._rate_limiter.ready(): - return - self._write(next(self._spin_cycle)) - - def finish(self, final_status): - # type: (str) -> None - if self._finished: - return - self._write(final_status) - self._file.write("\n") - self._file.flush() - self._finished = True - - -# Used for dumb terminals, non-interactive installs (no tty), etc. -# We still print updates occasionally (once every 60 seconds by default) to -# act as a keep-alive for systems like Travis-CI that take lack-of-output as -# an indication that a task has frozen. -class NonInteractiveSpinner(SpinnerInterface): - def __init__(self, message, min_update_interval_seconds=60): - # type: (str, float) -> None - self._message = message - self._finished = False - self._rate_limiter = RateLimiter(min_update_interval_seconds) - self._update("started") - - def _update(self, status): - # type: (str) -> None - assert not self._finished - self._rate_limiter.reset() - logger.info("%s: %s", self._message, status) - - def spin(self): - # type: () -> None - if self._finished: - return - if not self._rate_limiter.ready(): - return - self._update("still running...") - - def finish(self, final_status): - # type: (str) -> None - if self._finished: - return - self._update( - "finished with status '{final_status}'".format(**locals())) - self._finished = True - - -class RateLimiter(object): - def __init__(self, min_update_interval_seconds): - # type: (float) -> None - self._min_update_interval_seconds = min_update_interval_seconds - self._last_update = 0 # type: float - - def ready(self): - # type: () -> bool - now = time.time() - delta = now - self._last_update - return delta >= self._min_update_interval_seconds - - def reset(self): - # type: () -> None - self._last_update = time.time() - - -@contextlib.contextmanager -def open_spinner(message): - # type: (str) -> Iterator[SpinnerInterface] - # Interactive spinner goes directly to sys.stdout rather than being routed - # through the logging system, but it acts like it has level INFO, - # i.e. it's only displayed if we're at level INFO or better. - # Non-interactive spinner goes through the logging system, so it is always - # in sync with logging configuration. - if sys.stdout.isatty() and logger.getEffectiveLevel() <= logging.INFO: - spinner = InteractiveSpinner(message) # type: SpinnerInterface - else: - spinner = NonInteractiveSpinner(message) - try: - with hidden_cursor(sys.stdout): - yield spinner - except KeyboardInterrupt: - spinner.finish("canceled") - raise - except Exception: - spinner.finish("error") - raise - else: - spinner.finish("done") - - -@contextlib.contextmanager -def hidden_cursor(file): - # type: (IO[str]) -> Iterator[None] - # The Windows terminal does not support the hide/show cursor ANSI codes, - # even via colorama. So don't even try. - if WINDOWS: - yield - # We don't want to clutter the output with control characters if we're - # writing to a file, or if the user is running with --quiet. - # See https://github.com/pypa/pip/issues/3418 - elif not file.isatty() or logger.getEffectiveLevel() > logging.INFO: - yield - else: - file.write(HIDE_CURSOR) - try: - yield - finally: - file.write(SHOW_CURSOR) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/cli/status_codes.py b/venv/lib/python3.8/site-packages/pip/_internal/cli/status_codes.py deleted file mode 100644 index 275360a..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/cli/status_codes.py +++ /dev/null @@ -1,8 +0,0 @@ -from __future__ import absolute_import - -SUCCESS = 0 -ERROR = 1 -UNKNOWN_ERROR = 2 -VIRTUALENV_NOT_FOUND = 3 -PREVIOUS_BUILD_DIR_ERROR = 4 -NO_MATCHES_FOUND = 23 diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/__init__.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/__init__.py deleted file mode 100644 index 6825fa6..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/commands/__init__.py +++ /dev/null @@ -1,122 +0,0 @@ -""" -Package containing all pip commands -""" - -# The following comment should be removed at some point in the future. -# mypy: disallow-untyped-defs=False -# There is currently a bug in python/typeshed mentioned at -# https://github.com/python/typeshed/issues/3906 which causes the -# return type of difflib.get_close_matches to be reported -# as List[Sequence[str]] whereas it should have been List[str] - -from __future__ import absolute_import - -import importlib -from collections import OrderedDict, namedtuple - -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import Any - from pip._internal.cli.base_command import Command - - -CommandInfo = namedtuple('CommandInfo', 'module_path, class_name, summary') - -# The ordering matters for help display. -# Also, even though the module path starts with the same -# "pip._internal.commands" prefix in each case, we include the full path -# because it makes testing easier (specifically when modifying commands_dict -# in test setup / teardown by adding info for a FakeCommand class defined -# in a test-related module). -# Finally, we need to pass an iterable of pairs here rather than a dict -# so that the ordering won't be lost when using Python 2.7. -commands_dict = OrderedDict([ - ('install', CommandInfo( - 'pip._internal.commands.install', 'InstallCommand', - 'Install packages.', - )), - ('download', CommandInfo( - 'pip._internal.commands.download', 'DownloadCommand', - 'Download packages.', - )), - ('uninstall', CommandInfo( - 'pip._internal.commands.uninstall', 'UninstallCommand', - 'Uninstall packages.', - )), - ('freeze', CommandInfo( - 'pip._internal.commands.freeze', 'FreezeCommand', - 'Output installed packages in requirements format.', - )), - ('list', CommandInfo( - 'pip._internal.commands.list', 'ListCommand', - 'List installed packages.', - )), - ('show', CommandInfo( - 'pip._internal.commands.show', 'ShowCommand', - 'Show information about installed packages.', - )), - ('check', CommandInfo( - 'pip._internal.commands.check', 'CheckCommand', - 'Verify installed packages have compatible dependencies.', - )), - ('config', CommandInfo( - 'pip._internal.commands.configuration', 'ConfigurationCommand', - 'Manage local and global configuration.', - )), - ('search', CommandInfo( - 'pip._internal.commands.search', 'SearchCommand', - 'Search PyPI for packages.', - )), - ('cache', CommandInfo( - 'pip._internal.commands.cache', 'CacheCommand', - "Inspect and manage pip's wheel cache.", - )), - ('wheel', CommandInfo( - 'pip._internal.commands.wheel', 'WheelCommand', - 'Build wheels from your requirements.', - )), - ('hash', CommandInfo( - 'pip._internal.commands.hash', 'HashCommand', - 'Compute hashes of package archives.', - )), - ('completion', CommandInfo( - 'pip._internal.commands.completion', 'CompletionCommand', - 'A helper command used for command completion.', - )), - ('debug', CommandInfo( - 'pip._internal.commands.debug', 'DebugCommand', - 'Show information useful for debugging.', - )), - ('help', CommandInfo( - 'pip._internal.commands.help', 'HelpCommand', - 'Show help for commands.', - )), -]) # type: OrderedDict[str, CommandInfo] - - -def create_command(name, **kwargs): - # type: (str, **Any) -> Command - """ - Create an instance of the Command class with the given name. - """ - module_path, class_name, summary = commands_dict[name] - module = importlib.import_module(module_path) - command_class = getattr(module, class_name) - command = command_class(name=name, summary=summary, **kwargs) - - return command - - -def get_similar_commands(name): - """Command name auto-correct.""" - from difflib import get_close_matches - - name = name.lower() - - close_commands = get_close_matches(name, commands_dict.keys()) - - if close_commands: - return close_commands[0] - else: - return False diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/cache.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/cache.py deleted file mode 100644 index ca6d437..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/commands/cache.py +++ /dev/null @@ -1,181 +0,0 @@ -from __future__ import absolute_import - -import logging -import os -import textwrap - -import pip._internal.utils.filesystem as filesystem -from pip._internal.cli.base_command import Command -from pip._internal.cli.status_codes import ERROR, SUCCESS -from pip._internal.exceptions import CommandError, PipError -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from optparse import Values - from typing import Any, List - - -logger = logging.getLogger(__name__) - - -class CacheCommand(Command): - """ - Inspect and manage pip's wheel cache. - - Subcommands: - - dir: Show the cache directory. - info: Show information about the cache. - list: List filenames of packages stored in the cache. - remove: Remove one or more package from the cache. - purge: Remove all items from the cache. - - <pattern> can be a glob expression or a package name. - """ - - ignore_require_venv = True - usage = """ - %prog dir - %prog info - %prog list [<pattern>] - %prog remove <pattern> - %prog purge - """ - - def run(self, options, args): - # type: (Values, List[Any]) -> int - handlers = { - "dir": self.get_cache_dir, - "info": self.get_cache_info, - "list": self.list_cache_items, - "remove": self.remove_cache_items, - "purge": self.purge_cache, - } - - if not options.cache_dir: - logger.error("pip cache commands can not " - "function since cache is disabled.") - return ERROR - - # Determine action - if not args or args[0] not in handlers: - logger.error("Need an action ({}) to perform.".format( - ", ".join(sorted(handlers))) - ) - return ERROR - - action = args[0] - - # Error handling happens here, not in the action-handlers. - try: - handlers[action](options, args[1:]) - except PipError as e: - logger.error(e.args[0]) - return ERROR - - return SUCCESS - - def get_cache_dir(self, options, args): - # type: (Values, List[Any]) -> None - if args: - raise CommandError('Too many arguments') - - logger.info(options.cache_dir) - - def get_cache_info(self, options, args): - # type: (Values, List[Any]) -> None - if args: - raise CommandError('Too many arguments') - - num_packages = len(self._find_wheels(options, '*')) - - cache_location = self._wheels_cache_dir(options) - cache_size = filesystem.format_directory_size(cache_location) - - message = textwrap.dedent(""" - Location: {location} - Size: {size} - Number of wheels: {package_count} - """).format( - location=cache_location, - package_count=num_packages, - size=cache_size, - ).strip() - - logger.info(message) - - def list_cache_items(self, options, args): - # type: (Values, List[Any]) -> None - if len(args) > 1: - raise CommandError('Too many arguments') - - if args: - pattern = args[0] - else: - pattern = '*' - - files = self._find_wheels(options, pattern) - - if not files: - logger.info('Nothing cached.') - return - - results = [] - for filename in files: - wheel = os.path.basename(filename) - size = filesystem.format_file_size(filename) - results.append(' - {} ({})'.format(wheel, size)) - logger.info('Cache contents:\n') - logger.info('\n'.join(sorted(results))) - - def remove_cache_items(self, options, args): - # type: (Values, List[Any]) -> None - if len(args) > 1: - raise CommandError('Too many arguments') - - if not args: - raise CommandError('Please provide a pattern') - - files = self._find_wheels(options, args[0]) - if not files: - raise CommandError('No matching packages') - - for filename in files: - os.unlink(filename) - logger.debug('Removed %s', filename) - logger.info('Files removed: %s', len(files)) - - def purge_cache(self, options, args): - # type: (Values, List[Any]) -> None - if args: - raise CommandError('Too many arguments') - - return self.remove_cache_items(options, ['*']) - - def _wheels_cache_dir(self, options): - # type: (Values) -> str - return os.path.join(options.cache_dir, 'wheels') - - def _find_wheels(self, options, pattern): - # type: (Values, str) -> List[str] - wheel_dir = self._wheels_cache_dir(options) - - # The wheel filename format, as specified in PEP 427, is: - # {distribution}-{version}(-{build})?-{python}-{abi}-{platform}.whl - # - # Additionally, non-alphanumeric values in the distribution are - # normalized to underscores (_), meaning hyphens can never occur - # before `-{version}`. - # - # Given that information: - # - If the pattern we're given contains a hyphen (-), the user is - # providing at least the version. Thus, we can just append `*.whl` - # to match the rest of it. - # - If the pattern we're given doesn't contain a hyphen (-), the - # user is only providing the name. Thus, we append `-*.whl` to - # match the hyphen before the version, followed by anything else. - # - # PEP 427: https://www.python.org/dev/peps/pep-0427/ - pattern = pattern + ("*.whl" if "-" in pattern else "-*.whl") - - return filesystem.find_files(wheel_dir, pattern) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/check.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/check.py deleted file mode 100644 index b557ca6..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/commands/check.py +++ /dev/null @@ -1,51 +0,0 @@ -import logging - -from pip._internal.cli.base_command import Command -from pip._internal.cli.status_codes import ERROR, SUCCESS -from pip._internal.operations.check import ( - check_package_set, - create_package_set_from_installed, -) -from pip._internal.utils.misc import write_output -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -logger = logging.getLogger(__name__) - -if MYPY_CHECK_RUNNING: - from typing import List, Any - from optparse import Values - - -class CheckCommand(Command): - """Verify installed packages have compatible dependencies.""" - - usage = """ - %prog [options]""" - - def run(self, options, args): - # type: (Values, List[Any]) -> int - - package_set, parsing_probs = create_package_set_from_installed() - missing, conflicting = check_package_set(package_set) - - for project_name in missing: - version = package_set[project_name].version - for dependency in missing[project_name]: - write_output( - "%s %s requires %s, which is not installed.", - project_name, version, dependency[0], - ) - - for project_name in conflicting: - version = package_set[project_name].version - for dep_name, dep_version, req in conflicting[project_name]: - write_output( - "%s %s has requirement %s, but you have %s %s.", - project_name, version, req, dep_name, dep_version, - ) - - if missing or conflicting or parsing_probs: - return ERROR - else: - write_output("No broken requirements found.") - return SUCCESS diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/completion.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/completion.py deleted file mode 100644 index 910fcbf..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/commands/completion.py +++ /dev/null @@ -1,95 +0,0 @@ -# The following comment should be removed at some point in the future. -# mypy: disallow-untyped-defs=False - -from __future__ import absolute_import - -import sys -import textwrap - -from pip._internal.cli.base_command import Command -from pip._internal.utils.misc import get_prog - -BASE_COMPLETION = """ -# pip {shell} completion start{script}# pip {shell} completion end -""" - -COMPLETION_SCRIPTS = { - 'bash': """ - _pip_completion() - {{ - COMPREPLY=( $( COMP_WORDS="${{COMP_WORDS[*]}}" \\ - COMP_CWORD=$COMP_CWORD \\ - PIP_AUTO_COMPLETE=1 $1 2>/dev/null ) ) - }} - complete -o default -F _pip_completion {prog} - """, - 'zsh': """ - function _pip_completion {{ - local words cword - read -Ac words - read -cn cword - reply=( $( COMP_WORDS="$words[*]" \\ - COMP_CWORD=$(( cword-1 )) \\ - PIP_AUTO_COMPLETE=1 $words[1] 2>/dev/null )) - }} - compctl -K _pip_completion {prog} - """, - 'fish': """ - function __fish_complete_pip - set -lx COMP_WORDS (commandline -o) "" - set -lx COMP_CWORD ( \\ - math (contains -i -- (commandline -t) $COMP_WORDS)-1 \\ - ) - set -lx PIP_AUTO_COMPLETE 1 - string split \\ -- (eval $COMP_WORDS[1]) - end - complete -fa "(__fish_complete_pip)" -c {prog} - """, -} - - -class CompletionCommand(Command): - """A helper command to be used for command completion.""" - - ignore_require_venv = True - - def __init__(self, *args, **kw): - super(CompletionCommand, self).__init__(*args, **kw) - - cmd_opts = self.cmd_opts - - cmd_opts.add_option( - '--bash', '-b', - action='store_const', - const='bash', - dest='shell', - help='Emit completion code for bash') - cmd_opts.add_option( - '--zsh', '-z', - action='store_const', - const='zsh', - dest='shell', - help='Emit completion code for zsh') - cmd_opts.add_option( - '--fish', '-f', - action='store_const', - const='fish', - dest='shell', - help='Emit completion code for fish') - - self.parser.insert_option_group(0, cmd_opts) - - def run(self, options, args): - """Prints the completion code of the given shell""" - shells = COMPLETION_SCRIPTS.keys() - shell_options = ['--' + shell for shell in sorted(shells)] - if options.shell in shells: - script = textwrap.dedent( - COMPLETION_SCRIPTS.get(options.shell, '').format( - prog=get_prog()) - ) - print(BASE_COMPLETION.format(script=script, shell=options.shell)) - else: - sys.stderr.write( - 'ERROR: You must pass {}\n' .format(' or '.join(shell_options)) - ) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/configuration.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/configuration.py deleted file mode 100644 index b801be6..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/commands/configuration.py +++ /dev/null @@ -1,233 +0,0 @@ -# The following comment should be removed at some point in the future. -# mypy: disallow-untyped-defs=False - -import logging -import os -import subprocess - -from pip._internal.cli.base_command import Command -from pip._internal.cli.status_codes import ERROR, SUCCESS -from pip._internal.configuration import ( - Configuration, - get_configuration_files, - kinds, -) -from pip._internal.exceptions import PipError -from pip._internal.utils.misc import get_prog, write_output - -logger = logging.getLogger(__name__) - - -class ConfigurationCommand(Command): - """Manage local and global configuration. - - Subcommands: - - list: List the active configuration (or from the file specified) - edit: Edit the configuration file in an editor - get: Get the value associated with name - set: Set the name=value - unset: Unset the value associated with name - - If none of --user, --global and --site are passed, a virtual - environment configuration file is used if one is active and the file - exists. Otherwise, all modifications happen on the to the user file by - default. - """ - - ignore_require_venv = True - usage = """ - %prog [<file-option>] list - %prog [<file-option>] [--editor <editor-path>] edit - - %prog [<file-option>] get name - %prog [<file-option>] set name value - %prog [<file-option>] unset name - """ - - def __init__(self, *args, **kwargs): - super(ConfigurationCommand, self).__init__(*args, **kwargs) - - self.configuration = None - - self.cmd_opts.add_option( - '--editor', - dest='editor', - action='store', - default=None, - help=( - 'Editor to use to edit the file. Uses VISUAL or EDITOR ' - 'environment variables if not provided.' - ) - ) - - self.cmd_opts.add_option( - '--global', - dest='global_file', - action='store_true', - default=False, - help='Use the system-wide configuration file only' - ) - - self.cmd_opts.add_option( - '--user', - dest='user_file', - action='store_true', - default=False, - help='Use the user configuration file only' - ) - - self.cmd_opts.add_option( - '--site', - dest='site_file', - action='store_true', - default=False, - help='Use the current environment configuration file only' - ) - - self.parser.insert_option_group(0, self.cmd_opts) - - def run(self, options, args): - handlers = { - "list": self.list_values, - "edit": self.open_in_editor, - "get": self.get_name, - "set": self.set_name_value, - "unset": self.unset_name - } - - # Determine action - if not args or args[0] not in handlers: - logger.error("Need an action ({}) to perform.".format( - ", ".join(sorted(handlers))) - ) - return ERROR - - action = args[0] - - # Determine which configuration files are to be loaded - # Depends on whether the command is modifying. - try: - load_only = self._determine_file( - options, need_value=(action in ["get", "set", "unset", "edit"]) - ) - except PipError as e: - logger.error(e.args[0]) - return ERROR - - # Load a new configuration - self.configuration = Configuration( - isolated=options.isolated_mode, load_only=load_only - ) - self.configuration.load() - - # Error handling happens here, not in the action-handlers. - try: - handlers[action](options, args[1:]) - except PipError as e: - logger.error(e.args[0]) - return ERROR - - return SUCCESS - - def _determine_file(self, options, need_value): - file_options = [key for key, value in ( - (kinds.USER, options.user_file), - (kinds.GLOBAL, options.global_file), - (kinds.SITE, options.site_file), - ) if value] - - if not file_options: - if not need_value: - return None - # Default to user, unless there's a site file. - elif any( - os.path.exists(site_config_file) - for site_config_file in get_configuration_files()[kinds.SITE] - ): - return kinds.SITE - else: - return kinds.USER - elif len(file_options) == 1: - return file_options[0] - - raise PipError( - "Need exactly one file to operate upon " - "(--user, --site, --global) to perform." - ) - - def list_values(self, options, args): - self._get_n_args(args, "list", n=0) - - for key, value in sorted(self.configuration.items()): - write_output("%s=%r", key, value) - - def get_name(self, options, args): - key = self._get_n_args(args, "get [name]", n=1) - value = self.configuration.get_value(key) - - write_output("%s", value) - - def set_name_value(self, options, args): - key, value = self._get_n_args(args, "set [name] [value]", n=2) - self.configuration.set_value(key, value) - - self._save_configuration() - - def unset_name(self, options, args): - key = self._get_n_args(args, "unset [name]", n=1) - self.configuration.unset_value(key) - - self._save_configuration() - - def open_in_editor(self, options, args): - editor = self._determine_editor(options) - - fname = self.configuration.get_file_to_edit() - if fname is None: - raise PipError("Could not determine appropriate file.") - - try: - subprocess.check_call([editor, fname]) - except subprocess.CalledProcessError as e: - raise PipError( - "Editor Subprocess exited with exit code {}" - .format(e.returncode) - ) - - def _get_n_args(self, args, example, n): - """Helper to make sure the command got the right number of arguments - """ - if len(args) != n: - msg = ( - 'Got unexpected number of arguments, expected {}. ' - '(example: "{} config {}")' - ).format(n, get_prog(), example) - raise PipError(msg) - - if n == 1: - return args[0] - else: - return args - - def _save_configuration(self): - # We successfully ran a modifying command. Need to save the - # configuration. - try: - self.configuration.save() - except Exception: - logger.error( - "Unable to save configuration. Please report this as a bug.", - exc_info=1 - ) - raise PipError("Internal Error.") - - def _determine_editor(self, options): - if options.editor is not None: - return options.editor - elif "VISUAL" in os.environ: - return os.environ["VISUAL"] - elif "EDITOR" in os.environ: - return os.environ["EDITOR"] - else: - raise PipError("Could not determine editor to use.") diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/debug.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/debug.py deleted file mode 100644 index 665ffe9..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/commands/debug.py +++ /dev/null @@ -1,258 +0,0 @@ -# The following comment should be removed at some point in the future. -# mypy: disallow-untyped-defs=False - -from __future__ import absolute_import - -import locale -import logging -import os -import sys - -import pip._vendor -from pip._vendor import pkg_resources -from pip._vendor.certifi import where - -from pip import __file__ as pip_location -from pip._internal.cli import cmdoptions -from pip._internal.cli.base_command import Command -from pip._internal.cli.cmdoptions import make_target_python -from pip._internal.cli.status_codes import SUCCESS -from pip._internal.utils.logging import indent_log -from pip._internal.utils.misc import get_pip_version -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from types import ModuleType - from typing import Any, List, Optional, Dict - from optparse import Values - -logger = logging.getLogger(__name__) - - -def show_value(name, value): - # type: (str, Optional[str]) -> None - logger.info('{}: {}'.format(name, value)) - - -def show_sys_implementation(): - # type: () -> None - logger.info('sys.implementation:') - if hasattr(sys, 'implementation'): - implementation = sys.implementation # type: ignore - implementation_name = implementation.name - else: - implementation_name = '' - - with indent_log(): - show_value('name', implementation_name) - - -def create_vendor_txt_map(): - # type: () -> Dict[str, str] - vendor_txt_path = os.path.join( - os.path.dirname(pip_location), - '_vendor', - 'vendor.txt' - ) - - with open(vendor_txt_path) as f: - # Purge non version specifying lines. - # Also, remove any space prefix or suffixes (including comments). - lines = [line.strip().split(' ', 1)[0] - for line in f.readlines() if '==' in line] - - # Transform into "module" -> version dict. - return dict(line.split('==', 1) for line in lines) # type: ignore - -def create_debundle_txt_map(): - # type: () -> Dict[str, str] - wheels = [fn for fn in os.listdir(pip._vendor.WHEEL_DIR)] - # Transform into "module" -> version dict. - return dict((wheel.split('-')[0], wheel.split('-')[1]) for wheel in wheels) # type: ignore - -def get_module_from_module_name(module_name): - # type: (str) -> ModuleType - - # Module name can be uppercase in vendor.txt for some reason... - module_name = module_name.lower() - # PATCH: setuptools is actually only pkg_resources. - if module_name == 'setuptools': - module_name = 'pkg_resources' - - __import__( - 'pip._vendor.{}'.format(module_name), - globals(), - locals(), - level=0 - ) - return getattr(pip._vendor, module_name) - - -def get_vendor_version_from_module(module_name): - # type: (str) -> str - - module = get_module_from_module_name(module_name) - version = getattr(module, '__version__', None) - - if not version: - # Try to find version in debundled module info - pkg_set = pkg_resources.WorkingSet( - [os.path.dirname(getattr(module, '__file__'))] - ) - package = pkg_set.find(pkg_resources.Requirement.parse(module_name)) - version = getattr(package, 'version', None) - - return version - - -def show_actual_vendor_versions(vendor_txt_versions): - # type: (Dict[str, str]) -> None - # Logs the actual version and print extra info - # if there is a conflict or if the actual version could not be imported. - - for module_name, expected_version in vendor_txt_versions.items(): - extra_message = '' - actual_version = get_vendor_version_from_module(module_name) - if not actual_version: - extra_message = ' (Unable to locate actual module version, using'\ - ' vendor.txt specified version)' - actual_version = expected_version - elif actual_version != expected_version: - extra_message = ' (CONFLICT: vendor.txt suggests version should'\ - ' be {})'.format(expected_version) - - logger.info( - '{name}=={actual}{extra}'.format( - name=module_name, - actual=actual_version, - extra=extra_message - ) - ) - - -def show_vendor_versions(): - # type: () -> None - logger.info('vendored library versions:') - - vendor_txt_versions = create_vendor_txt_map() - with indent_log(): - show_actual_vendor_versions(vendor_txt_versions) - -def show_debundled_versions(): - # type: () -> None - logger.info('debundled wheel versions:') - debundle_txt_versions = create_debundle_txt_map() - for module_name, installed_version in sorted(debundle_txt_versions.items()): - with indent_log(): - logger.info( - '{name}=={actual}'.format( - name=module_name, - actual=installed_version, - ) - ) - -def show_tags(options): - # type: (Values) -> None - tag_limit = 10 - - target_python = make_target_python(options) - tags = target_python.get_tags() - - # Display the target options that were explicitly provided. - formatted_target = target_python.format_given() - suffix = '' - if formatted_target: - suffix = ' (target: {})'.format(formatted_target) - - msg = 'Compatible tags: {}{}'.format(len(tags), suffix) - logger.info(msg) - - if options.verbose < 1 and len(tags) > tag_limit: - tags_limited = True - tags = tags[:tag_limit] - else: - tags_limited = False - - with indent_log(): - for tag in tags: - logger.info(str(tag)) - - if tags_limited: - msg = ( - '...\n' - '[First {tag_limit} tags shown. Pass --verbose to show all.]' - ).format(tag_limit=tag_limit) - logger.info(msg) - - -def ca_bundle_info(config): - levels = set() - for key, value in config.items(): - levels.add(key.split('.')[0]) - - if not levels: - return "Not specified" - - levels_that_override_global = ['install', 'wheel', 'download'] - global_overriding_level = [ - level for level in levels if level in levels_that_override_global - ] - if not global_overriding_level: - return 'global' - - if 'global' in levels: - levels.remove('global') - return ", ".join(levels) - - -class DebugCommand(Command): - """ - Display debug information. - """ - - usage = """ - %prog <options>""" - ignore_require_venv = True - - def __init__(self, *args, **kw): - super(DebugCommand, self).__init__(*args, **kw) - - cmd_opts = self.cmd_opts - cmdoptions.add_target_python_options(cmd_opts) - self.parser.insert_option_group(0, cmd_opts) - self.parser.config.load() - - def run(self, options, args): - # type: (Values, List[Any]) -> int - logger.warning( - "This command is only meant for debugging. " - "Do not use this with automation for parsing and getting these " - "details, since the output and options of this command may " - "change without notice." - ) - show_value('pip version', get_pip_version()) - show_value('sys.version', sys.version) - show_value('sys.executable', sys.executable) - show_value('sys.getdefaultencoding', sys.getdefaultencoding()) - show_value('sys.getfilesystemencoding', sys.getfilesystemencoding()) - show_value( - 'locale.getpreferredencoding', locale.getpreferredencoding(), - ) - show_value('sys.platform', sys.platform) - show_sys_implementation() - - show_value("'cert' config value", ca_bundle_info(self.parser.config)) - show_value("REQUESTS_CA_BUNDLE", os.environ.get('REQUESTS_CA_BUNDLE')) - show_value("CURL_CA_BUNDLE", os.environ.get('CURL_CA_BUNDLE')) - show_value("pip._vendor.certifi.where()", where()) - show_value("pip._vendor.DEBUNDLED", pip._vendor.DEBUNDLED) - - if not pip._vendor.DEBUNDLED: - show_vendor_versions() - else: - show_value("pip._vendor.WHEEL_DIR", pip._vendor.WHEEL_DIR) - show_debundled_versions() - - show_tags(options) - - return SUCCESS diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/download.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/download.py deleted file mode 100644 index c829550..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/commands/download.py +++ /dev/null @@ -1,142 +0,0 @@ -# The following comment should be removed at some point in the future. -# mypy: disallow-untyped-defs=False - -from __future__ import absolute_import - -import logging -import os - -from pip._internal.cli import cmdoptions -from pip._internal.cli.cmdoptions import make_target_python -from pip._internal.cli.req_command import RequirementCommand, with_cleanup -from pip._internal.req.req_tracker import get_requirement_tracker -from pip._internal.utils.misc import ensure_dir, normalize_path, write_output -from pip._internal.utils.temp_dir import TempDirectory - -logger = logging.getLogger(__name__) - - -class DownloadCommand(RequirementCommand): - """ - Download packages from: - - - PyPI (and other indexes) using requirement specifiers. - - VCS project urls. - - Local project directories. - - Local or remote source archives. - - pip also supports downloading from "requirements files", which provide - an easy way to specify a whole environment to be downloaded. - """ - - usage = """ - %prog [options] <requirement specifier> [package-index-options] ... - %prog [options] -r <requirements file> [package-index-options] ... - %prog [options] <vcs project url> ... - %prog [options] <local project path> ... - %prog [options] <archive url/path> ...""" - - def __init__(self, *args, **kw): - super(DownloadCommand, self).__init__(*args, **kw) - - cmd_opts = self.cmd_opts - - cmd_opts.add_option(cmdoptions.constraints()) - cmd_opts.add_option(cmdoptions.requirements()) - cmd_opts.add_option(cmdoptions.build_dir()) - cmd_opts.add_option(cmdoptions.no_deps()) - cmd_opts.add_option(cmdoptions.global_options()) - cmd_opts.add_option(cmdoptions.no_binary()) - cmd_opts.add_option(cmdoptions.only_binary()) - cmd_opts.add_option(cmdoptions.prefer_binary()) - cmd_opts.add_option(cmdoptions.src()) - cmd_opts.add_option(cmdoptions.pre()) - cmd_opts.add_option(cmdoptions.require_hashes()) - cmd_opts.add_option(cmdoptions.progress_bar()) - cmd_opts.add_option(cmdoptions.no_build_isolation()) - cmd_opts.add_option(cmdoptions.use_pep517()) - cmd_opts.add_option(cmdoptions.no_use_pep517()) - - cmd_opts.add_option( - '-d', '--dest', '--destination-dir', '--destination-directory', - dest='download_dir', - metavar='dir', - default=os.curdir, - help=("Download packages into <dir>."), - ) - - cmdoptions.add_target_python_options(cmd_opts) - - index_opts = cmdoptions.make_option_group( - cmdoptions.index_group, - self.parser, - ) - - self.parser.insert_option_group(0, index_opts) - self.parser.insert_option_group(0, cmd_opts) - - @with_cleanup - def run(self, options, args): - options.ignore_installed = True - # editable doesn't really make sense for `pip download`, but the bowels - # of the RequirementSet code require that property. - options.editables = [] - - cmdoptions.check_dist_restriction(options) - - options.download_dir = normalize_path(options.download_dir) - - ensure_dir(options.download_dir) - - session = self.get_default_session(options) - - target_python = make_target_python(options) - finder = self._build_package_finder( - options=options, - session=session, - target_python=target_python, - ) - build_delete = (not (options.no_clean or options.build_dir)) - - req_tracker = self.enter_context(get_requirement_tracker()) - - directory = TempDirectory( - options.build_dir, - delete=build_delete, - kind="download", - globally_managed=True, - ) - - reqs = self.get_requirements(args, options, finder, session) - - preparer = self.make_requirement_preparer( - temp_build_dir=directory, - options=options, - req_tracker=req_tracker, - session=session, - finder=finder, - download_dir=options.download_dir, - use_user_site=False, - ) - - resolver = self.make_resolver( - preparer=preparer, - finder=finder, - options=options, - py_version_info=options.python_version, - ) - - self.trace_basic_info(finder) - - requirement_set = resolver.resolve( - reqs, check_supported_wheels=True - ) - - downloaded = ' '.join([ - req.name for req in requirement_set.requirements.values() - if req.successfully_downloaded - ]) - if downloaded: - write_output('Successfully downloaded %s', downloaded) - - return requirement_set diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/freeze.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/freeze.py deleted file mode 100644 index 9e873a9..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/commands/freeze.py +++ /dev/null @@ -1,99 +0,0 @@ -# The following comment should be removed at some point in the future. -# mypy: disallow-untyped-defs=False - -from __future__ import absolute_import - -import sys - -from pip._internal.cache import WheelCache -from pip._internal.cli import cmdoptions -from pip._internal.cli.base_command import Command -from pip._internal.models.format_control import FormatControl -from pip._internal.operations.freeze import freeze -from pip._internal.utils.compat import stdlib_pkgs - -DEV_PKGS = {'pip', 'setuptools', 'distribute', 'wheel', 'pkg-resources'} - - -class FreezeCommand(Command): - """ - Output installed packages in requirements format. - - packages are listed in a case-insensitive sorted order. - """ - - usage = """ - %prog [options]""" - log_streams = ("ext://sys.stderr", "ext://sys.stderr") - - def __init__(self, *args, **kw): - super(FreezeCommand, self).__init__(*args, **kw) - - self.cmd_opts.add_option( - '-r', '--requirement', - dest='requirements', - action='append', - default=[], - metavar='file', - help="Use the order in the given requirements file and its " - "comments when generating output. This option can be " - "used multiple times.") - self.cmd_opts.add_option( - '-f', '--find-links', - dest='find_links', - action='append', - default=[], - metavar='URL', - help='URL for finding packages, which will be added to the ' - 'output.') - self.cmd_opts.add_option( - '-l', '--local', - dest='local', - action='store_true', - default=False, - help='If in a virtualenv that has global access, do not output ' - 'globally-installed packages.') - self.cmd_opts.add_option( - '--user', - dest='user', - action='store_true', - default=False, - help='Only output packages installed in user-site.') - self.cmd_opts.add_option(cmdoptions.list_path()) - self.cmd_opts.add_option( - '--all', - dest='freeze_all', - action='store_true', - help='Do not skip these packages in the output:' - ' {}'.format(', '.join(DEV_PKGS))) - self.cmd_opts.add_option( - '--exclude-editable', - dest='exclude_editable', - action='store_true', - help='Exclude editable package from output.') - - self.parser.insert_option_group(0, self.cmd_opts) - - def run(self, options, args): - format_control = FormatControl(set(), set()) - wheel_cache = WheelCache(options.cache_dir, format_control) - skip = set(stdlib_pkgs) - if not options.freeze_all: - skip.update(DEV_PKGS) - - cmdoptions.check_list_path_option(options) - - freeze_kwargs = dict( - requirement=options.requirements, - find_links=options.find_links, - local_only=options.local, - user_only=options.user, - paths=options.path, - isolated=options.isolated_mode, - wheel_cache=wheel_cache, - skip=skip, - exclude_editable=options.exclude_editable, - ) - - for line in freeze(**freeze_kwargs): - sys.stdout.write(line + '\n') diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/hash.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/hash.py deleted file mode 100644 index f266861..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/commands/hash.py +++ /dev/null @@ -1,58 +0,0 @@ -# The following comment should be removed at some point in the future. -# mypy: disallow-untyped-defs=False - -from __future__ import absolute_import - -import hashlib -import logging -import sys - -from pip._internal.cli.base_command import Command -from pip._internal.cli.status_codes import ERROR -from pip._internal.utils.hashes import FAVORITE_HASH, STRONG_HASHES -from pip._internal.utils.misc import read_chunks, write_output - -logger = logging.getLogger(__name__) - - -class HashCommand(Command): - """ - Compute a hash of a local package archive. - - These can be used with --hash in a requirements file to do repeatable - installs. - """ - - usage = '%prog [options] <file> ...' - ignore_require_venv = True - - def __init__(self, *args, **kw): - super(HashCommand, self).__init__(*args, **kw) - self.cmd_opts.add_option( - '-a', '--algorithm', - dest='algorithm', - choices=STRONG_HASHES, - action='store', - default=FAVORITE_HASH, - help='The hash algorithm to use: one of {}'.format( - ', '.join(STRONG_HASHES))) - self.parser.insert_option_group(0, self.cmd_opts) - - def run(self, options, args): - if not args: - self.parser.print_usage(sys.stderr) - return ERROR - - algorithm = options.algorithm - for path in args: - write_output('%s:\n--hash=%s:%s', - path, algorithm, _hash_of_file(path, algorithm)) - - -def _hash_of_file(path, algorithm): - """Return the hash digest of a file.""" - with open(path, 'rb') as archive: - hash = hashlib.new(algorithm) - for chunk in read_chunks(archive): - hash.update(chunk) - return hash.hexdigest() diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/help.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/help.py deleted file mode 100644 index c17d7a4..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/commands/help.py +++ /dev/null @@ -1,41 +0,0 @@ -# The following comment should be removed at some point in the future. -# mypy: disallow-untyped-defs=False - -from __future__ import absolute_import - -from pip._internal.cli.base_command import Command -from pip._internal.cli.status_codes import SUCCESS -from pip._internal.exceptions import CommandError - - -class HelpCommand(Command): - """Show help for commands""" - - usage = """ - %prog <command>""" - ignore_require_venv = True - - def run(self, options, args): - from pip._internal.commands import ( - commands_dict, create_command, get_similar_commands, - ) - - try: - # 'pip help' with no args is handled by pip.__init__.parseopt() - cmd_name = args[0] # the command we need help for - except IndexError: - return SUCCESS - - if cmd_name not in commands_dict: - guess = get_similar_commands(cmd_name) - - msg = ['unknown command "{}"'.format(cmd_name)] - if guess: - msg.append('maybe you meant "{}"'.format(guess)) - - raise CommandError(' - '.join(msg)) - - command = create_command(cmd_name) - command.parser.print_help() - - return SUCCESS diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/install.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/install.py deleted file mode 100644 index b40f045..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/commands/install.py +++ /dev/null @@ -1,717 +0,0 @@ -# The following comment should be removed at some point in the future. -# It's included for now because without it InstallCommand.run() has a -# couple errors where we have to know req.name is str rather than -# Optional[str] for the InstallRequirement req. -# mypy: strict-optional=False -# mypy: disallow-untyped-defs=False - -from __future__ import absolute_import - -import errno -import logging -import operator -import os -import shutil -import site -from optparse import SUPPRESS_HELP - -from pip._vendor import pkg_resources -from pip._vendor.packaging.utils import canonicalize_name - -from pip._internal.cache import WheelCache -from pip._internal.cli import cmdoptions -from pip._internal.cli.cmdoptions import make_target_python -from pip._internal.cli.req_command import RequirementCommand, with_cleanup -from pip._internal.cli.status_codes import ERROR, SUCCESS -from pip._internal.exceptions import CommandError, InstallationError -from pip._internal.locations import distutils_scheme -from pip._internal.operations.check import check_install_conflicts -from pip._internal.req import install_given_reqs -from pip._internal.req.req_tracker import get_requirement_tracker -from pip._internal.utils.deprecation import deprecated -from pip._internal.utils.distutils_args import parse_distutils_args -from pip._internal.utils.filesystem import test_writable_dir -from pip._internal.utils.misc import ( - ensure_dir, - get_installed_version, - protect_pip_from_modification_on_windows, - write_output, -) -from pip._internal.utils.temp_dir import TempDirectory -from pip._internal.utils.typing import MYPY_CHECK_RUNNING -from pip._internal.utils.virtualenv import virtualenv_no_global -from pip._internal.wheel_builder import build, should_build_for_install_command - -if MYPY_CHECK_RUNNING: - from optparse import Values - from typing import Any, Iterable, List, Optional - - from pip._internal.models.format_control import FormatControl - from pip._internal.req.req_install import InstallRequirement - from pip._internal.wheel_builder import BinaryAllowedPredicate - -from pip._internal.locations import running_under_virtualenv - -logger = logging.getLogger(__name__) - - -def get_check_binary_allowed(format_control): - # type: (FormatControl) -> BinaryAllowedPredicate - def check_binary_allowed(req): - # type: (InstallRequirement) -> bool - if req.use_pep517: - return True - canonical_name = canonicalize_name(req.name) - allowed_formats = format_control.get_allowed_formats(canonical_name) - return "binary" in allowed_formats - - return check_binary_allowed - - -class InstallCommand(RequirementCommand): - """ - Install packages from: - - - PyPI (and other indexes) using requirement specifiers. - - VCS project urls. - - Local project directories. - - Local or remote source archives. - - pip also supports installing from "requirements files", which provide - an easy way to specify a whole environment to be installed. - """ - - usage = """ - %prog [options] <requirement specifier> [package-index-options] ... - %prog [options] -r <requirements file> [package-index-options] ... - %prog [options] [-e] <vcs project url> ... - %prog [options] [-e] <local project path> ... - %prog [options] <archive url/path> ...""" - - def __init__(self, *args, **kw): - super(InstallCommand, self).__init__(*args, **kw) - - cmd_opts = self.cmd_opts - - cmd_opts.add_option(cmdoptions.requirements()) - cmd_opts.add_option(cmdoptions.constraints()) - cmd_opts.add_option(cmdoptions.no_deps()) - cmd_opts.add_option(cmdoptions.pre()) - - cmd_opts.add_option(cmdoptions.editable()) - cmd_opts.add_option( - '-t', '--target', - dest='target_dir', - metavar='dir', - default=None, - help='Install packages into <dir>. ' - 'By default this will not replace existing files/folders in ' - '<dir>. Use --upgrade to replace existing packages in <dir> ' - 'with new versions.' - ) - cmdoptions.add_target_python_options(cmd_opts) - - cmd_opts.add_option( - '--user', - dest='use_user_site', - action='store_true', - help="Install to the Python user install directory for your " - "platform. Typically ~/.local/, or %APPDATA%\\Python on " - "Windows. (See the Python documentation for site.USER_BASE " - "for full details.) On Debian systems, this is the " - "default when running outside of a virtual environment " - "and not as root.") - - cmd_opts.add_option( - '--no-user', - dest='use_system_location', - action='store_true', - help=SUPPRESS_HELP) - cmd_opts.add_option( - '--root', - dest='root_path', - metavar='dir', - default=None, - help="Install everything relative to this alternate root " - "directory.") - cmd_opts.add_option( - '--prefix', - dest='prefix_path', - metavar='dir', - default=None, - help="Installation prefix where lib, bin and other top-level " - "folders are placed") - - cmd_opts.add_option( - '--system', - dest='use_system_location', - action='store_true', - help="Install using the system scheme (overrides --user on " - "Debian systems)") - - cmd_opts.add_option(cmdoptions.build_dir()) - - cmd_opts.add_option(cmdoptions.src()) - - cmd_opts.add_option( - '-U', '--upgrade', - dest='upgrade', - action='store_true', - help='Upgrade all specified packages to the newest available ' - 'version. The handling of dependencies depends on the ' - 'upgrade-strategy used.' - ) - - cmd_opts.add_option( - '--upgrade-strategy', - dest='upgrade_strategy', - default='only-if-needed', - choices=['only-if-needed', 'eager'], - help='Determines how dependency upgrading should be handled ' - '[default: %default]. ' - '"eager" - dependencies are upgraded regardless of ' - 'whether the currently installed version satisfies the ' - 'requirements of the upgraded package(s). ' - '"only-if-needed" - are upgraded only when they do not ' - 'satisfy the requirements of the upgraded package(s).' - ) - - cmd_opts.add_option( - '--force-reinstall', - dest='force_reinstall', - action='store_true', - help='Reinstall all packages even if they are already ' - 'up-to-date.') - - cmd_opts.add_option( - '-I', '--ignore-installed', - dest='ignore_installed', - action='store_true', - help='Ignore the installed packages, overwriting them. ' - 'This can break your system if the existing package ' - 'is of a different version or was installed ' - 'with a different package manager!' - ) - - cmd_opts.add_option(cmdoptions.ignore_requires_python()) - cmd_opts.add_option(cmdoptions.no_build_isolation()) - cmd_opts.add_option(cmdoptions.use_pep517()) - cmd_opts.add_option(cmdoptions.no_use_pep517()) - - cmd_opts.add_option(cmdoptions.install_options()) - cmd_opts.add_option(cmdoptions.global_options()) - - cmd_opts.add_option( - "--compile", - action="store_true", - dest="compile", - default=True, - help="Compile Python source files to bytecode", - ) - - cmd_opts.add_option( - "--no-compile", - action="store_false", - dest="compile", - help="Do not compile Python source files to bytecode", - ) - - cmd_opts.add_option( - "--no-warn-script-location", - action="store_false", - dest="warn_script_location", - default=True, - help="Do not warn when installing scripts outside PATH", - ) - cmd_opts.add_option( - "--no-warn-conflicts", - action="store_false", - dest="warn_about_conflicts", - default=True, - help="Do not warn about broken dependencies", - ) - - cmd_opts.add_option(cmdoptions.no_binary()) - cmd_opts.add_option(cmdoptions.only_binary()) - cmd_opts.add_option(cmdoptions.prefer_binary()) - cmd_opts.add_option(cmdoptions.require_hashes()) - cmd_opts.add_option(cmdoptions.progress_bar()) - - index_opts = cmdoptions.make_option_group( - cmdoptions.index_group, - self.parser, - ) - - self.parser.insert_option_group(0, index_opts) - self.parser.insert_option_group(0, cmd_opts) - - @with_cleanup - def run(self, options, args): - # type: (Values, List[Any]) -> int - if options.use_user_site and options.target_dir is not None: - raise CommandError("Can not combine '--user' and '--target'") - - cmdoptions.check_install_build_global(options) - upgrade_strategy = "to-satisfy-only" - if options.upgrade: - upgrade_strategy = options.upgrade_strategy - - cmdoptions.check_dist_restriction(options, check_target=True) - - if options.python_version: - python_versions = [options.python_version] - else: - python_versions = None - - # compute install location defaults - if (not options.use_user_site and not options.prefix_path and not - options.target_dir and not options.use_system_location): - if not running_under_virtualenv() and os.geteuid() != 0: - options.use_user_site = True - - if options.use_system_location: - options.use_user_site = False - - options.src_dir = os.path.abspath(options.src_dir) - install_options = options.install_options or [] - - options.use_user_site = decide_user_install( - options.use_user_site, - prefix_path=options.prefix_path, - target_dir=options.target_dir, - root_path=options.root_path, - isolated_mode=options.isolated_mode, - ) - - target_temp_dir = None # type: Optional[TempDirectory] - target_temp_dir_path = None # type: Optional[str] - if options.target_dir: - options.ignore_installed = True - options.target_dir = os.path.abspath(options.target_dir) - if (os.path.exists(options.target_dir) and not - os.path.isdir(options.target_dir)): - raise CommandError( - "Target path exists but is not a directory, will not " - "continue." - ) - - # Create a target directory for using with the target option - target_temp_dir = TempDirectory(kind="target") - target_temp_dir_path = target_temp_dir.path - - global_options = options.global_options or [] - - session = self.get_default_session(options) - - target_python = make_target_python(options) - finder = self._build_package_finder( - options=options, - session=session, - target_python=target_python, - ignore_requires_python=options.ignore_requires_python, - ) - build_delete = (not (options.no_clean or options.build_dir)) - wheel_cache = WheelCache(options.cache_dir, options.format_control) - - req_tracker = self.enter_context(get_requirement_tracker()) - - directory = TempDirectory( - options.build_dir, - delete=build_delete, - kind="install", - globally_managed=True, - ) - - try: - reqs = self.get_requirements( - args, options, finder, session, - check_supported_wheels=not options.target_dir, - ) - - warn_deprecated_install_options( - reqs, options.install_options - ) - - preparer = self.make_requirement_preparer( - temp_build_dir=directory, - options=options, - req_tracker=req_tracker, - session=session, - finder=finder, - use_user_site=options.use_user_site, - ) - resolver = self.make_resolver( - preparer=preparer, - finder=finder, - options=options, - wheel_cache=wheel_cache, - use_user_site=options.use_user_site, - ignore_installed=options.ignore_installed, - ignore_requires_python=options.ignore_requires_python, - force_reinstall=options.force_reinstall, - upgrade_strategy=upgrade_strategy, - use_pep517=options.use_pep517, - ) - - self.trace_basic_info(finder) - - requirement_set = resolver.resolve( - reqs, check_supported_wheels=not options.target_dir - ) - - try: - pip_req = requirement_set.get_requirement("pip") - except KeyError: - modifying_pip = None - else: - # If we're not replacing an already installed pip, - # we're not modifying it. - modifying_pip = pip_req.satisfied_by is None - protect_pip_from_modification_on_windows( - modifying_pip=modifying_pip - ) - - check_binary_allowed = get_check_binary_allowed( - finder.format_control - ) - - reqs_to_build = [ - r for r in requirement_set.requirements.values() - if should_build_for_install_command( - r, check_binary_allowed - ) - ] - - _, build_failures = build( - reqs_to_build, - wheel_cache=wheel_cache, - build_options=[], - global_options=[], - ) - - # If we're using PEP 517, we cannot do a direct install - # so we fail here. - # We don't care about failures building legacy - # requirements, as we'll fall through to a direct - # install for those. - pep517_build_failures = [ - r for r in build_failures if r.use_pep517 - ] - if pep517_build_failures: - raise InstallationError( - "Could not build wheels for {} which use" - " PEP 517 and cannot be installed directly".format( - ", ".join(r.name for r in pep517_build_failures))) - - to_install = resolver.get_installation_order( - requirement_set - ) - - # Consistency Checking of the package set we're installing. - should_warn_about_conflicts = ( - not options.ignore_dependencies and - options.warn_about_conflicts - ) - if should_warn_about_conflicts: - self._warn_about_conflicts(to_install) - - # Don't warn about script install locations if - # --target has been specified - warn_script_location = options.warn_script_location - if options.target_dir: - warn_script_location = False - - installed = install_given_reqs( - to_install, - install_options, - global_options, - root=options.root_path, - home=target_temp_dir_path, - prefix=options.prefix_path, - pycompile=options.compile, - warn_script_location=warn_script_location, - use_user_site=options.use_user_site, - ) - - lib_locations = get_lib_location_guesses( - user=options.use_user_site, - home=target_temp_dir_path, - root=options.root_path, - prefix=options.prefix_path, - isolated=options.isolated_mode, - ) - working_set = pkg_resources.WorkingSet(lib_locations) - - installed.sort(key=operator.attrgetter('name')) - items = [] - for result in installed: - item = result.name - try: - installed_version = get_installed_version( - result.name, working_set=working_set - ) - if installed_version: - item += '-' + installed_version - except Exception: - pass - items.append(item) - installed_desc = ' '.join(items) - if installed_desc: - write_output( - 'Successfully installed %s', installed_desc, - ) - except EnvironmentError as error: - show_traceback = (self.verbosity >= 1) - - message = create_env_error_message( - error, show_traceback, options.use_user_site, - ) - logger.error(message, exc_info=show_traceback) - - return ERROR - - if options.target_dir: - self._handle_target_dir( - options.target_dir, target_temp_dir, options.upgrade - ) - - return SUCCESS - - def _handle_target_dir(self, target_dir, target_temp_dir, upgrade): - ensure_dir(target_dir) - - # Checking both purelib and platlib directories for installed - # packages to be moved to target directory - lib_dir_list = [] - - with target_temp_dir: - # Checking both purelib and platlib directories for installed - # packages to be moved to target directory - scheme = distutils_scheme('', home=target_temp_dir.path) - purelib_dir = scheme['purelib'] - platlib_dir = scheme['platlib'] - data_dir = scheme['data'] - - if os.path.exists(purelib_dir): - lib_dir_list.append(purelib_dir) - if os.path.exists(platlib_dir) and platlib_dir != purelib_dir: - lib_dir_list.append(platlib_dir) - if os.path.exists(data_dir): - lib_dir_list.append(data_dir) - - for lib_dir in lib_dir_list: - for item in os.listdir(lib_dir): - if lib_dir == data_dir: - ddir = os.path.join(data_dir, item) - if any(s.startswith(ddir) for s in lib_dir_list[:-1]): - continue - target_item_dir = os.path.join(target_dir, item) - if os.path.exists(target_item_dir): - if not upgrade: - logger.warning( - 'Target directory %s already exists. Specify ' - '--upgrade to force replacement.', - target_item_dir - ) - continue - if os.path.islink(target_item_dir): - logger.warning( - 'Target directory %s already exists and is ' - 'a link. pip will not automatically replace ' - 'links, please remove if replacement is ' - 'desired.', - target_item_dir - ) - continue - if os.path.isdir(target_item_dir): - shutil.rmtree(target_item_dir) - else: - os.remove(target_item_dir) - - shutil.move( - os.path.join(lib_dir, item), - target_item_dir - ) - - def _warn_about_conflicts(self, to_install): - try: - package_set, _dep_info = check_install_conflicts(to_install) - except Exception: - logger.error("Error checking for conflicts.", exc_info=True) - return - missing, conflicting = _dep_info - - # NOTE: There is some duplication here from pip check - for project_name in missing: - version = package_set[project_name][0] - for dependency in missing[project_name]: - logger.critical( - "%s %s requires %s, which is not installed.", - project_name, version, dependency[1], - ) - - for project_name in conflicting: - version = package_set[project_name][0] - for dep_name, dep_version, req in conflicting[project_name]: - logger.critical( - "%s %s has requirement %s, but you'll have %s %s which is " - "incompatible.", - project_name, version, req, dep_name, dep_version, - ) - - -def get_lib_location_guesses(*args, **kwargs): - scheme = distutils_scheme('', *args, **kwargs) - return [scheme['purelib'], scheme['platlib']] - - -def site_packages_writable(**kwargs): - return all( - test_writable_dir(d) for d in set(get_lib_location_guesses(**kwargs)) - ) - - -def decide_user_install( - use_user_site, # type: Optional[bool] - prefix_path=None, # type: Optional[str] - target_dir=None, # type: Optional[str] - root_path=None, # type: Optional[str] - isolated_mode=False, # type: bool -): - # type: (...) -> bool - """Determine whether to do a user install based on the input options. - - If use_user_site is False, no additional checks are done. - If use_user_site is True, it is checked for compatibility with other - options. - If use_user_site is None, the default behaviour depends on the environment, - which is provided by the other arguments. - """ - # In some cases (config from tox), use_user_site can be set to an integer - # rather than a bool, which 'use_user_site is False' wouldn't catch. - if (use_user_site is not None) and (not use_user_site): - logger.debug("Non-user install by explicit request") - return False - - if use_user_site: - if prefix_path: - raise CommandError( - "Can not combine '--user' and '--prefix' as they imply " - "different installation locations" - ) - if virtualenv_no_global(): - raise InstallationError( - "Can not perform a '--user' install. User site-packages " - "are not visible in this virtualenv." - ) - logger.debug("User install by explicit request") - return True - - # If we are here, user installs have not been explicitly requested/avoided - assert use_user_site is None - - # user install incompatible with --prefix/--target - if prefix_path or target_dir: - logger.debug("Non-user install due to --prefix or --target option") - return False - - # If user installs are not enabled, choose a non-user install - if not site.ENABLE_USER_SITE: - logger.debug("Non-user install because user site-packages disabled") - return False - - # If we have permission for a non-user install, do that, - # otherwise do a user install. - if site_packages_writable(root=root_path, isolated=isolated_mode): - logger.debug("Non-user install because site-packages writeable") - return False - - logger.info("Defaulting to user installation because normal site-packages " - "is not writeable") - return True - - -def warn_deprecated_install_options(requirements, options): - # type: (List[InstallRequirement], Optional[List[str]]) -> None - """If any location-changing --install-option arguments were passed for - requirements or on the command-line, then show a deprecation warning. - """ - def format_options(option_names): - # type: (Iterable[str]) -> List[str] - return ["--{}".format(name.replace("_", "-")) for name in option_names] - - offenders = [] - - for requirement in requirements: - install_options = requirement.install_options - location_options = parse_distutils_args(install_options) - if location_options: - offenders.append( - "{!r} from {}".format( - format_options(location_options.keys()), requirement - ) - ) - - if options: - location_options = parse_distutils_args(options) - if location_options: - offenders.append( - "{!r} from command line".format( - format_options(location_options.keys()) - ) - ) - - if not offenders: - return - - deprecated( - reason=( - "Location-changing options found in --install-option: {}. " - "This configuration may cause unexpected behavior and is " - "unsupported.".format( - "; ".join(offenders) - ) - ), - replacement=( - "using pip-level options like --user, --prefix, --root, and " - "--target" - ), - gone_in="20.2", - issue=7309, - ) - - -def create_env_error_message(error, show_traceback, using_user_site): - """Format an error message for an EnvironmentError - - It may occur anytime during the execution of the install command. - """ - parts = [] - - # Mention the error if we are not going to show a traceback - parts.append("Could not install packages due to an EnvironmentError") - if not show_traceback: - parts.append(": ") - parts.append(str(error)) - else: - parts.append(".") - - # Spilt the error indication from a helper message (if any) - parts[-1] += "\n" - - # Suggest useful actions to the user: - # (1) using user site-packages or (2) verifying the permissions - if error.errno == errno.EACCES: - user_option_part = "Consider using the `--user` option" - permissions_part = "Check the permissions" - - if not using_user_site: - parts.extend([ - user_option_part, " or ", - permissions_part.lower(), - ]) - else: - parts.append(permissions_part) - parts.append(".\n") - - return "".join(parts).strip() + "\n" diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/list.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/list.py deleted file mode 100644 index 13715ce..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/commands/list.py +++ /dev/null @@ -1,301 +0,0 @@ -# The following comment should be removed at some point in the future. -# mypy: disallow-untyped-defs=False - -from __future__ import absolute_import - -import json -import logging - -from pip._vendor import six - -from pip._internal.cli import cmdoptions -from pip._internal.cli.req_command import IndexGroupCommand -from pip._internal.exceptions import CommandError -from pip._internal.index.package_finder import PackageFinder -from pip._internal.models.selection_prefs import SelectionPreferences -from pip._internal.self_outdated_check import make_link_collector -from pip._internal.utils.misc import ( - dist_is_editable, - get_installed_distributions, - tabulate, - write_output, -) -from pip._internal.utils.packaging import get_installer - -from pip._vendor.packaging.version import parse - -logger = logging.getLogger(__name__) - - -class ListCommand(IndexGroupCommand): - """ - List installed packages, including editables. - - Packages are listed in a case-insensitive sorted order. - """ - - usage = """ - %prog [options]""" - - def __init__(self, *args, **kw): - super(ListCommand, self).__init__(*args, **kw) - - cmd_opts = self.cmd_opts - - cmd_opts.add_option( - '-o', '--outdated', - action='store_true', - default=False, - help='List outdated packages') - cmd_opts.add_option( - '-u', '--uptodate', - action='store_true', - default=False, - help='List uptodate packages') - cmd_opts.add_option( - '-e', '--editable', - action='store_true', - default=False, - help='List editable projects.') - cmd_opts.add_option( - '-l', '--local', - action='store_true', - default=False, - help=('If in a virtualenv that has global access, do not list ' - 'globally-installed packages.'), - ) - self.cmd_opts.add_option( - '--user', - dest='user', - action='store_true', - default=False, - help='Only output packages installed in user-site.') - cmd_opts.add_option(cmdoptions.list_path()) - cmd_opts.add_option( - '--pre', - action='store_true', - default=False, - help=("Include pre-release and development versions. By default, " - "pip only finds stable versions."), - ) - - cmd_opts.add_option( - '--format', - action='store', - dest='list_format', - default="columns", - choices=('columns', 'freeze', 'json'), - help="Select the output format among: columns (default), freeze, " - "or json", - ) - - cmd_opts.add_option( - '--not-required', - action='store_true', - dest='not_required', - help="List packages that are not dependencies of " - "installed packages.", - ) - - cmd_opts.add_option( - '--exclude-editable', - action='store_false', - dest='include_editable', - help='Exclude editable package from output.', - ) - cmd_opts.add_option( - '--include-editable', - action='store_true', - dest='include_editable', - help='Include editable package from output.', - default=True, - ) - index_opts = cmdoptions.make_option_group( - cmdoptions.index_group, self.parser - ) - - self.parser.insert_option_group(0, index_opts) - self.parser.insert_option_group(0, cmd_opts) - - def _build_package_finder(self, options, session): - """ - Create a package finder appropriate to this list command. - """ - link_collector = make_link_collector(session, options=options) - - # Pass allow_yanked=False to ignore yanked versions. - selection_prefs = SelectionPreferences( - allow_yanked=False, - allow_all_prereleases=options.pre, - ) - - return PackageFinder.create( - link_collector=link_collector, - selection_prefs=selection_prefs, - ) - - def run(self, options, args): - if options.outdated and options.uptodate: - raise CommandError( - "Options --outdated and --uptodate cannot be combined.") - - cmdoptions.check_list_path_option(options) - - packages = get_installed_distributions( - local_only=options.local, - user_only=options.user, - editables_only=options.editable, - include_editables=options.include_editable, - paths=options.path, - ) - - # get_not_required must be called firstly in order to find and - # filter out all dependencies correctly. Otherwise a package - # can't be identified as requirement because some parent packages - # could be filtered out before. - if options.not_required: - packages = self.get_not_required(packages, options) - - if options.outdated: - packages = self.get_outdated(packages, options) - elif options.uptodate: - packages = self.get_uptodate(packages, options) - - self.output_package_listing(packages, options) - - def get_outdated(self, packages, options): - return [ - dist for dist in self.iter_packages_latest_infos(packages, options) - if parse(str(dist.latest_version)) > parse(str(dist.parsed_version)) - ] - - def get_uptodate(self, packages, options): - return [ - dist for dist in self.iter_packages_latest_infos(packages, options) - if parse(str(dist.latest_version)) == parse(str(dist.parsed_version)) - ] - - def get_not_required(self, packages, options): - dep_keys = set() - for dist in packages: - dep_keys.update(requirement.key for requirement in dist.requires()) - return {pkg for pkg in packages if pkg.key not in dep_keys} - - def iter_packages_latest_infos(self, packages, options): - with self._build_session(options) as session: - finder = self._build_package_finder(options, session) - - def latest_info(dist): - typ = 'unknown' - all_candidates = finder.find_all_candidates(dist.key) - if not options.pre: - # Remove prereleases - all_candidates = [candidate for candidate in all_candidates - if not candidate.version.is_prerelease] - - evaluator = finder.make_candidate_evaluator( - project_name=dist.project_name, - ) - best_candidate = evaluator.sort_best_candidate(all_candidates) - if best_candidate is None: - return None - - remote_version = best_candidate.version - if best_candidate.link.is_wheel: - typ = 'wheel' - else: - typ = 'sdist' - # This is dirty but makes the rest of the code much cleaner - dist.latest_version = remote_version - dist.latest_filetype = typ - return dist - - for dist in map(latest_info, packages): - if dist is not None: - yield dist - - def output_package_listing(self, packages, options): - packages = sorted( - packages, - key=lambda dist: dist.project_name.lower(), - ) - if options.list_format == 'columns' and packages: - data, header = format_for_columns(packages, options) - self.output_package_listing_columns(data, header) - elif options.list_format == 'freeze': - for dist in packages: - if options.verbose >= 1: - write_output("%s==%s (%s)", dist.project_name, - dist.version, dist.location) - else: - write_output("%s==%s", dist.project_name, dist.version) - elif options.list_format == 'json': - write_output(format_for_json(packages, options)) - - def output_package_listing_columns(self, data, header): - # insert the header first: we need to know the size of column names - if len(data) > 0: - data.insert(0, header) - - pkg_strings, sizes = tabulate(data) - - # Create and add a separator. - if len(data) > 0: - pkg_strings.insert(1, " ".join(map(lambda x: '-' * x, sizes))) - - for val in pkg_strings: - write_output(val) - - -def format_for_columns(pkgs, options): - """ - Convert the package data into something usable - by output_package_listing_columns. - """ - running_outdated = options.outdated - # Adjust the header for the `pip list --outdated` case. - if running_outdated: - header = ["Package", "Version", "Latest", "Type"] - else: - header = ["Package", "Version"] - - data = [] - if options.verbose >= 1 or any(dist_is_editable(x) for x in pkgs): - header.append("Location") - if options.verbose >= 1: - header.append("Installer") - - for proj in pkgs: - # if we're working on the 'outdated' list, separate out the - # latest_version and type - row = [proj.project_name, proj.version] - - if running_outdated: - row.append(proj.latest_version) - row.append(proj.latest_filetype) - - if options.verbose >= 1 or dist_is_editable(proj): - row.append(proj.location) - if options.verbose >= 1: - row.append(get_installer(proj)) - - data.append(row) - - return data, header - - -def format_for_json(packages, options): - data = [] - for dist in packages: - info = { - 'name': dist.project_name, - 'version': six.text_type(dist.version), - } - if options.verbose >= 1: - info['location'] = dist.location - info['installer'] = get_installer(dist) - if options.outdated: - info['latest_version'] = six.text_type(dist.latest_version) - info['latest_filetype'] = dist.latest_filetype - data.append(info) - return json.dumps(data) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/search.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/search.py deleted file mode 100644 index e5f286e..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/commands/search.py +++ /dev/null @@ -1,146 +0,0 @@ -# The following comment should be removed at some point in the future. -# mypy: disallow-untyped-defs=False - -from __future__ import absolute_import - -import logging -import sys -import textwrap -from collections import OrderedDict - -from pip._vendor import pkg_resources -from pip._vendor.packaging.version import parse as parse_version -# NOTE: XMLRPC Client is not annotated in typeshed as on 2017-07-17, which is -# why we ignore the type on this import -from pip._vendor.six.moves import xmlrpc_client # type: ignore - -from pip._internal.cli.base_command import Command -from pip._internal.cli.req_command import SessionCommandMixin -from pip._internal.cli.status_codes import NO_MATCHES_FOUND, SUCCESS -from pip._internal.exceptions import CommandError -from pip._internal.models.index import PyPI -from pip._internal.network.xmlrpc import PipXmlrpcTransport -from pip._internal.utils.compat import get_terminal_size -from pip._internal.utils.logging import indent_log -from pip._internal.utils.misc import write_output - -logger = logging.getLogger(__name__) - - -class SearchCommand(Command, SessionCommandMixin): - """Search for PyPI packages whose name or summary contains <query>.""" - - usage = """ - %prog [options] <query>""" - ignore_require_venv = True - - def __init__(self, *args, **kw): - super(SearchCommand, self).__init__(*args, **kw) - self.cmd_opts.add_option( - '-i', '--index', - dest='index', - metavar='URL', - default=PyPI.pypi_url, - help='Base URL of Python Package Index (default %default)') - - self.parser.insert_option_group(0, self.cmd_opts) - - def run(self, options, args): - if not args: - raise CommandError('Missing required argument (search query).') - query = args - pypi_hits = self.search(query, options) - hits = transform_hits(pypi_hits) - - terminal_width = None - if sys.stdout.isatty(): - terminal_width = get_terminal_size()[0] - - print_results(hits, terminal_width=terminal_width) - if pypi_hits: - return SUCCESS - return NO_MATCHES_FOUND - - def search(self, query, options): - index_url = options.index - - session = self.get_default_session(options) - - transport = PipXmlrpcTransport(index_url, session) - pypi = xmlrpc_client.ServerProxy(index_url, transport) - hits = pypi.search({'name': query, 'summary': query}, 'or') - return hits - - -def transform_hits(hits): - """ - The list from pypi is really a list of versions. We want a list of - packages with the list of versions stored inline. This converts the - list from pypi into one we can use. - """ - packages = OrderedDict() - for hit in hits: - name = hit['name'] - summary = hit['summary'] - version = hit['version'] - - if name not in packages.keys(): - packages[name] = { - 'name': name, - 'summary': summary, - 'versions': [version], - } - else: - packages[name]['versions'].append(version) - - # if this is the highest version, replace summary and score - if version == highest_version(packages[name]['versions']): - packages[name]['summary'] = summary - - return list(packages.values()) - - -def print_results(hits, name_column_width=None, terminal_width=None): - if not hits: - return - if name_column_width is None: - name_column_width = max([ - len(hit['name']) + len(highest_version(hit.get('versions', ['-']))) - for hit in hits - ]) + 4 - - installed_packages = [p.project_name for p in pkg_resources.working_set] - for hit in hits: - name = hit['name'] - summary = hit['summary'] or '' - latest = highest_version(hit.get('versions', ['-'])) - if terminal_width is not None: - target_width = terminal_width - name_column_width - 5 - if target_width > 10: - # wrap and indent summary to fit terminal - summary = textwrap.wrap(summary, target_width) - summary = ('\n' + ' ' * (name_column_width + 3)).join(summary) - - line = '{name_latest:{name_column_width}} - {summary}'.format( - name_latest='{name} ({latest})'.format(**locals()), - **locals()) - try: - write_output(line) - if name in installed_packages: - dist = pkg_resources.get_distribution(name) - with indent_log(): - if dist.version == latest: - write_output('INSTALLED: %s (latest)', dist.version) - else: - write_output('INSTALLED: %s', dist.version) - if parse_version(latest).pre: - write_output('LATEST: %s (pre-release; install' - ' with "pip install --pre")', latest) - else: - write_output('LATEST: %s', latest) - except UnicodeEncodeError: - pass - - -def highest_version(versions): - return max(versions, key=parse_version) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/show.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/show.py deleted file mode 100644 index a61294b..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/commands/show.py +++ /dev/null @@ -1,180 +0,0 @@ -# The following comment should be removed at some point in the future. -# mypy: disallow-untyped-defs=False - -from __future__ import absolute_import - -import logging -import os -from email.parser import FeedParser - -from pip._vendor import pkg_resources -from pip._vendor.packaging.utils import canonicalize_name - -from pip._internal.cli.base_command import Command -from pip._internal.cli.status_codes import ERROR, SUCCESS -from pip._internal.utils.misc import write_output - -logger = logging.getLogger(__name__) - - -class ShowCommand(Command): - """ - Show information about one or more installed packages. - - The output is in RFC-compliant mail header format. - """ - - usage = """ - %prog [options] <package> ...""" - ignore_require_venv = True - - def __init__(self, *args, **kw): - super(ShowCommand, self).__init__(*args, **kw) - self.cmd_opts.add_option( - '-f', '--files', - dest='files', - action='store_true', - default=False, - help='Show the full list of installed files for each package.') - - self.parser.insert_option_group(0, self.cmd_opts) - - def run(self, options, args): - if not args: - logger.warning('ERROR: Please provide a package name or names.') - return ERROR - query = args - - results = search_packages_info(query) - if not print_results( - results, list_files=options.files, verbose=options.verbose): - return ERROR - return SUCCESS - - -def search_packages_info(query): - """ - Gather details from installed distributions. Print distribution name, - version, location, and installed files. Installed files requires a - pip generated 'installed-files.txt' in the distributions '.egg-info' - directory. - """ - installed = {} - for p in pkg_resources.working_set: - installed[canonicalize_name(p.project_name)] = p - - query_names = [canonicalize_name(name) for name in query] - missing = sorted( - [name for name, pkg in zip(query, query_names) if pkg not in installed] - ) - if missing: - logger.warning('Package(s) not found: %s', ', '.join(missing)) - - def get_requiring_packages(package_name): - canonical_name = canonicalize_name(package_name) - return [ - pkg.project_name for pkg in pkg_resources.working_set - if canonical_name in - [canonicalize_name(required.name) for required in - pkg.requires()] - ] - - for dist in [installed[pkg] for pkg in query_names if pkg in installed]: - package = { - 'name': dist.project_name, - 'version': dist.version, - 'location': dist.location, - 'requires': [dep.project_name for dep in dist.requires()], - 'required_by': get_requiring_packages(dist.project_name) - } - file_list = None - metadata = None - if isinstance(dist, pkg_resources.DistInfoDistribution): - # RECORDs should be part of .dist-info metadatas - if dist.has_metadata('RECORD'): - lines = dist.get_metadata_lines('RECORD') - paths = [l.split(',')[0] for l in lines] - paths = [os.path.join(dist.location, p) for p in paths] - file_list = [os.path.relpath(p, dist.location) for p in paths] - - if dist.has_metadata('METADATA'): - metadata = dist.get_metadata('METADATA') - else: - # Otherwise use pip's log for .egg-info's - if dist.has_metadata('installed-files.txt'): - paths = dist.get_metadata_lines('installed-files.txt') - paths = [os.path.join(dist.egg_info, p) for p in paths] - file_list = [os.path.relpath(p, dist.location) for p in paths] - - if dist.has_metadata('PKG-INFO'): - metadata = dist.get_metadata('PKG-INFO') - - if dist.has_metadata('entry_points.txt'): - entry_points = dist.get_metadata_lines('entry_points.txt') - package['entry_points'] = entry_points - - if dist.has_metadata('INSTALLER'): - for line in dist.get_metadata_lines('INSTALLER'): - if line.strip(): - package['installer'] = line.strip() - break - - # @todo: Should pkg_resources.Distribution have a - # `get_pkg_info` method? - feed_parser = FeedParser() - feed_parser.feed(metadata) - pkg_info_dict = feed_parser.close() - for key in ('metadata-version', 'summary', - 'home-page', 'author', 'author-email', 'license'): - package[key] = pkg_info_dict.get(key) - - # It looks like FeedParser cannot deal with repeated headers - classifiers = [] - for line in metadata.splitlines(): - if line.startswith('Classifier: '): - classifiers.append(line[len('Classifier: '):]) - package['classifiers'] = classifiers - - if file_list: - package['files'] = sorted(file_list) - yield package - - -def print_results(distributions, list_files=False, verbose=False): - """ - Print the information from installed distributions found. - """ - results_printed = False - for i, dist in enumerate(distributions): - results_printed = True - if i > 0: - write_output("---") - - write_output("Name: %s", dist.get('name', '')) - write_output("Version: %s", dist.get('version', '')) - write_output("Summary: %s", dist.get('summary', '')) - write_output("Home-page: %s", dist.get('home-page', '')) - write_output("Author: %s", dist.get('author', '')) - write_output("Author-email: %s", dist.get('author-email', '')) - write_output("License: %s", dist.get('license', '')) - write_output("Location: %s", dist.get('location', '')) - write_output("Requires: %s", ', '.join(dist.get('requires', []))) - write_output("Required-by: %s", ', '.join(dist.get('required_by', []))) - - if verbose: - write_output("Metadata-Version: %s", - dist.get('metadata-version', '')) - write_output("Installer: %s", dist.get('installer', '')) - write_output("Classifiers:") - for classifier in dist.get('classifiers', []): - write_output(" %s", classifier) - write_output("Entry-points:") - for entry in dist.get('entry_points', []): - write_output(" %s", entry.strip()) - if list_files: - write_output("Files:") - for line in dist.get('files', []): - write_output(" %s", line.strip()) - if "files" not in dist: - write_output("Cannot locate installed-files.txt") - return results_printed diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/uninstall.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/uninstall.py deleted file mode 100644 index 5db4fb4..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/commands/uninstall.py +++ /dev/null @@ -1,89 +0,0 @@ -# The following comment should be removed at some point in the future. -# mypy: disallow-untyped-defs=False - -from __future__ import absolute_import - -from pip._vendor.packaging.utils import canonicalize_name - -from pip._internal.cli.base_command import Command -from pip._internal.cli.req_command import SessionCommandMixin -from pip._internal.exceptions import InstallationError -from pip._internal.req import parse_requirements -from pip._internal.req.constructors import ( - install_req_from_line, - install_req_from_parsed_requirement, -) -from pip._internal.utils.misc import protect_pip_from_modification_on_windows - - -class UninstallCommand(Command, SessionCommandMixin): - """ - Uninstall packages. - - pip is able to uninstall most installed packages. Known exceptions are: - - - Pure distutils packages installed with ``python setup.py install``, which - leave behind no metadata to determine what files were installed. - - Script wrappers installed by ``python setup.py develop``. - """ - - usage = """ - %prog [options] <package> ... - %prog [options] -r <requirements file> ...""" - - def __init__(self, *args, **kw): - super(UninstallCommand, self).__init__(*args, **kw) - self.cmd_opts.add_option( - '-r', '--requirement', - dest='requirements', - action='append', - default=[], - metavar='file', - help='Uninstall all the packages listed in the given requirements ' - 'file. This option can be used multiple times.', - ) - self.cmd_opts.add_option( - '-y', '--yes', - dest='yes', - action='store_true', - help="Don't ask for confirmation of uninstall deletions.") - - self.parser.insert_option_group(0, self.cmd_opts) - - def run(self, options, args): - session = self.get_default_session(options) - - reqs_to_uninstall = {} - for name in args: - req = install_req_from_line( - name, isolated=options.isolated_mode, - ) - if req.name: - reqs_to_uninstall[canonicalize_name(req.name)] = req - for filename in options.requirements: - for parsed_req in parse_requirements( - filename, - options=options, - session=session): - req = install_req_from_parsed_requirement( - parsed_req, - isolated=options.isolated_mode - ) - if req.name: - reqs_to_uninstall[canonicalize_name(req.name)] = req - if not reqs_to_uninstall: - raise InstallationError( - 'You must give at least one requirement to {self.name} (see ' - '"pip help {self.name}")'.format(**locals()) - ) - - protect_pip_from_modification_on_windows( - modifying_pip="pip" in reqs_to_uninstall - ) - - for req in reqs_to_uninstall.values(): - uninstall_pathset = req.uninstall( - auto_confirm=options.yes, verbose=self.verbosity > 0, - ) - if uninstall_pathset: - uninstall_pathset.commit() diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/wheel.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/wheel.py deleted file mode 100644 index 48f3bfa..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/commands/wheel.py +++ /dev/null @@ -1,190 +0,0 @@ -# -*- coding: utf-8 -*- - -# The following comment should be removed at some point in the future. -# mypy: disallow-untyped-defs=False - -from __future__ import absolute_import - -import logging -import os -import shutil - -from pip._internal.cache import WheelCache -from pip._internal.cli import cmdoptions -from pip._internal.cli.req_command import RequirementCommand, with_cleanup -from pip._internal.exceptions import CommandError -from pip._internal.req.req_tracker import get_requirement_tracker -from pip._internal.utils.misc import ensure_dir, normalize_path -from pip._internal.utils.temp_dir import TempDirectory -from pip._internal.utils.typing import MYPY_CHECK_RUNNING -from pip._internal.wheel_builder import build, should_build_for_wheel_command - -if MYPY_CHECK_RUNNING: - from optparse import Values - from typing import Any, List - - -logger = logging.getLogger(__name__) - - -class WheelCommand(RequirementCommand): - """ - Build Wheel archives for your requirements and dependencies. - - Wheel is a built-package format, and offers the advantage of not - recompiling your software during every install. For more details, see the - wheel docs: https://wheel.readthedocs.io/en/latest/ - - Requirements: setuptools>=0.8, and wheel. - - 'pip wheel' uses the bdist_wheel setuptools extension from the wheel - package to build individual wheels. - - """ - - usage = """ - %prog [options] <requirement specifier> ... - %prog [options] -r <requirements file> ... - %prog [options] [-e] <vcs project url> ... - %prog [options] [-e] <local project path> ... - %prog [options] <archive url/path> ...""" - - def __init__(self, *args, **kw): - super(WheelCommand, self).__init__(*args, **kw) - - cmd_opts = self.cmd_opts - - cmd_opts.add_option( - '-w', '--wheel-dir', - dest='wheel_dir', - metavar='dir', - default=os.curdir, - help=("Build wheels into <dir>, where the default is the " - "current working directory."), - ) - cmd_opts.add_option(cmdoptions.no_binary()) - cmd_opts.add_option(cmdoptions.only_binary()) - cmd_opts.add_option(cmdoptions.prefer_binary()) - cmd_opts.add_option( - '--build-option', - dest='build_options', - metavar='options', - action='append', - help="Extra arguments to be supplied to 'setup.py bdist_wheel'.", - ) - cmd_opts.add_option(cmdoptions.no_build_isolation()) - cmd_opts.add_option(cmdoptions.use_pep517()) - cmd_opts.add_option(cmdoptions.no_use_pep517()) - cmd_opts.add_option(cmdoptions.constraints()) - cmd_opts.add_option(cmdoptions.editable()) - cmd_opts.add_option(cmdoptions.requirements()) - cmd_opts.add_option(cmdoptions.src()) - cmd_opts.add_option(cmdoptions.ignore_requires_python()) - cmd_opts.add_option(cmdoptions.no_deps()) - cmd_opts.add_option(cmdoptions.build_dir()) - cmd_opts.add_option(cmdoptions.progress_bar()) - - cmd_opts.add_option( - '--global-option', - dest='global_options', - action='append', - metavar='options', - help="Extra global options to be supplied to the setup.py " - "call before the 'bdist_wheel' command.") - - cmd_opts.add_option( - '--pre', - action='store_true', - default=False, - help=("Include pre-release and development versions. By default, " - "pip only finds stable versions."), - ) - - cmd_opts.add_option(cmdoptions.require_hashes()) - - index_opts = cmdoptions.make_option_group( - cmdoptions.index_group, - self.parser, - ) - - self.parser.insert_option_group(0, index_opts) - self.parser.insert_option_group(0, cmd_opts) - - @with_cleanup - def run(self, options, args): - # type: (Values, List[Any]) -> None - cmdoptions.check_install_build_global(options) - - session = self.get_default_session(options) - - finder = self._build_package_finder(options, session) - build_delete = (not (options.no_clean or options.build_dir)) - wheel_cache = WheelCache(options.cache_dir, options.format_control) - - options.wheel_dir = normalize_path(options.wheel_dir) - ensure_dir(options.wheel_dir) - - req_tracker = self.enter_context(get_requirement_tracker()) - - directory = TempDirectory( - options.build_dir, - delete=build_delete, - kind="wheel", - globally_managed=True, - ) - - reqs = self.get_requirements(args, options, finder, session) - - preparer = self.make_requirement_preparer( - temp_build_dir=directory, - options=options, - req_tracker=req_tracker, - session=session, - finder=finder, - wheel_download_dir=options.wheel_dir, - use_user_site=False, - ) - - resolver = self.make_resolver( - preparer=preparer, - finder=finder, - options=options, - wheel_cache=wheel_cache, - ignore_requires_python=options.ignore_requires_python, - use_pep517=options.use_pep517, - ) - - self.trace_basic_info(finder) - - requirement_set = resolver.resolve( - reqs, check_supported_wheels=True - ) - - reqs_to_build = [ - r for r in requirement_set.requirements.values() - if should_build_for_wheel_command(r) - ] - - # build wheels - build_successes, build_failures = build( - reqs_to_build, - wheel_cache=wheel_cache, - build_options=options.build_options or [], - global_options=options.global_options or [], - ) - for req in build_successes: - assert req.link and req.link.is_wheel - assert req.local_file_path - # copy from cache to target directory - try: - shutil.copy(req.local_file_path, options.wheel_dir) - except OSError as e: - logger.warning( - "Building wheel for %s failed: %s", - req.name, e, - ) - build_failures.append(req) - if len(build_failures) != 0: - raise CommandError( - "Failed to build one or more wheels" - ) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/configuration.py b/venv/lib/python3.8/site-packages/pip/_internal/configuration.py deleted file mode 100644 index 2648b8a..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/configuration.py +++ /dev/null @@ -1,426 +0,0 @@ -"""Configuration management setup - -Some terminology: -- name - As written in config files. -- value - Value associated with a name -- key - Name combined with it's section (section.name) -- variant - A single word describing where the configuration key-value pair came from -""" - -# The following comment should be removed at some point in the future. -# mypy: strict-optional=False - -import locale -import logging -import os -import sys - -from pip._vendor.six.moves import configparser - -from pip._internal.exceptions import ( - ConfigurationError, - ConfigurationFileCouldNotBeLoaded, -) -from pip._internal.utils import appdirs -from pip._internal.utils.compat import WINDOWS, expanduser -from pip._internal.utils.misc import ensure_dir, enum -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import ( - Any, Dict, Iterable, List, NewType, Optional, Tuple - ) - - RawConfigParser = configparser.RawConfigParser # Shorthand - Kind = NewType("Kind", str) - -logger = logging.getLogger(__name__) - - -# NOTE: Maybe use the optionx attribute to normalize keynames. -def _normalize_name(name): - # type: (str) -> str - """Make a name consistent regardless of source (environment or file) - """ - name = name.lower().replace('_', '-') - if name.startswith('--'): - name = name[2:] # only prefer long opts - return name - - -def _disassemble_key(name): - # type: (str) -> List[str] - if "." not in name: - error_message = ( - "Key does not contain dot separated section and key. " - "Perhaps you wanted to use 'global.{}' instead?" - ).format(name) - raise ConfigurationError(error_message) - return name.split(".", 1) - - -# The kinds of configurations there are. -kinds = enum( - USER="user", # User Specific - GLOBAL="global", # System Wide - SITE="site", # [Virtual] Environment Specific - ENV="env", # from PIP_CONFIG_FILE - ENV_VAR="env-var", # from Environment Variables -) - - -CONFIG_BASENAME = 'pip.ini' if WINDOWS else 'pip.conf' - - -def get_configuration_files(): - # type: () -> Dict[Kind, List[str]] - global_config_files = [ - os.path.join(path, CONFIG_BASENAME) - for path in appdirs.site_config_dirs('pip') - ] - - site_config_file = os.path.join(sys.prefix, CONFIG_BASENAME) - legacy_config_file = os.path.join( - expanduser('~'), - 'pip' if WINDOWS else '.pip', - CONFIG_BASENAME, - ) - new_config_file = os.path.join( - appdirs.user_config_dir("pip"), CONFIG_BASENAME - ) - return { - kinds.GLOBAL: global_config_files, - kinds.SITE: [site_config_file], - kinds.USER: [legacy_config_file, new_config_file], - } - - -class Configuration(object): - """Handles management of configuration. - - Provides an interface to accessing and managing configuration files. - - This class converts provides an API that takes "section.key-name" style - keys and stores the value associated with it as "key-name" under the - section "section". - - This allows for a clean interface wherein the both the section and the - key-name are preserved in an easy to manage form in the configuration files - and the data stored is also nice. - """ - - def __init__(self, isolated, load_only=None): - # type: (bool, Kind) -> None - super(Configuration, self).__init__() - - _valid_load_only = [kinds.USER, kinds.GLOBAL, kinds.SITE, None] - if load_only not in _valid_load_only: - raise ConfigurationError( - "Got invalid value for load_only - should be one of {}".format( - ", ".join(map(repr, _valid_load_only[:-1])) - ) - ) - self.isolated = isolated # type: bool - self.load_only = load_only # type: Optional[Kind] - - # The order here determines the override order. - self._override_order = [ - kinds.GLOBAL, kinds.USER, kinds.SITE, kinds.ENV, kinds.ENV_VAR - ] - - self._ignore_env_names = ["version", "help"] - - # Because we keep track of where we got the data from - self._parsers = { - variant: [] for variant in self._override_order - } # type: Dict[Kind, List[Tuple[str, RawConfigParser]]] - self._config = { - variant: {} for variant in self._override_order - } # type: Dict[Kind, Dict[str, Any]] - self._modified_parsers = [] # type: List[Tuple[str, RawConfigParser]] - - def load(self): - # type: () -> None - """Loads configuration from configuration files and environment - """ - self._load_config_files() - if not self.isolated: - self._load_environment_vars() - - def get_file_to_edit(self): - # type: () -> Optional[str] - """Returns the file with highest priority in configuration - """ - assert self.load_only is not None, \ - "Need to be specified a file to be editing" - - try: - return self._get_parser_to_modify()[0] - except IndexError: - return None - - def items(self): - # type: () -> Iterable[Tuple[str, Any]] - """Returns key-value pairs like dict.items() representing the loaded - configuration - """ - return self._dictionary.items() - - def get_value(self, key): - # type: (str) -> Any - """Get a value from the configuration. - """ - try: - return self._dictionary[key] - except KeyError: - raise ConfigurationError("No such key - {}".format(key)) - - def set_value(self, key, value): - # type: (str, Any) -> None - """Modify a value in the configuration. - """ - self._ensure_have_load_only() - - fname, parser = self._get_parser_to_modify() - - if parser is not None: - section, name = _disassemble_key(key) - - # Modify the parser and the configuration - if not parser.has_section(section): - parser.add_section(section) - parser.set(section, name, value) - - self._config[self.load_only][key] = value - self._mark_as_modified(fname, parser) - - def unset_value(self, key): - # type: (str) -> None - """Unset a value in the configuration. - """ - self._ensure_have_load_only() - - if key not in self._config[self.load_only]: - raise ConfigurationError("No such key - {}".format(key)) - - fname, parser = self._get_parser_to_modify() - - if parser is not None: - section, name = _disassemble_key(key) - - # Remove the key in the parser - modified_something = False - if parser.has_section(section): - # Returns whether the option was removed or not - modified_something = parser.remove_option(section, name) - - if modified_something: - # name removed from parser, section may now be empty - section_iter = iter(parser.items(section)) - try: - val = next(section_iter) - except StopIteration: - val = None - - if val is None: - parser.remove_section(section) - - self._mark_as_modified(fname, parser) - else: - raise ConfigurationError( - "Fatal Internal error [id=1]. Please report as a bug." - ) - - del self._config[self.load_only][key] - - def save(self): - # type: () -> None - """Save the current in-memory state. - """ - self._ensure_have_load_only() - - for fname, parser in self._modified_parsers: - logger.info("Writing to %s", fname) - - # Ensure directory exists. - ensure_dir(os.path.dirname(fname)) - - with open(fname, "w") as f: - parser.write(f) - - # - # Private routines - # - - def _ensure_have_load_only(self): - # type: () -> None - if self.load_only is None: - raise ConfigurationError("Needed a specific file to be modifying.") - logger.debug("Will be working with %s variant only", self.load_only) - - @property - def _dictionary(self): - # type: () -> Dict[str, Any] - """A dictionary representing the loaded configuration. - """ - # NOTE: Dictionaries are not populated if not loaded. So, conditionals - # are not needed here. - retval = {} - - for variant in self._override_order: - retval.update(self._config[variant]) - - return retval - - def _load_config_files(self): - # type: () -> None - """Loads configuration from configuration files - """ - config_files = dict(self._iter_config_files()) - if config_files[kinds.ENV][0:1] == [os.devnull]: - logger.debug( - "Skipping loading configuration files due to " - "environment's PIP_CONFIG_FILE being os.devnull" - ) - return - - for variant, files in config_files.items(): - for fname in files: - # If there's specific variant set in `load_only`, load only - # that variant, not the others. - if self.load_only is not None and variant != self.load_only: - logger.debug( - "Skipping file '%s' (variant: %s)", fname, variant - ) - continue - - parser = self._load_file(variant, fname) - - # Keeping track of the parsers used - self._parsers[variant].append((fname, parser)) - - def _load_file(self, variant, fname): - # type: (Kind, str) -> RawConfigParser - logger.debug("For variant '%s', will try loading '%s'", variant, fname) - parser = self._construct_parser(fname) - - for section in parser.sections(): - items = parser.items(section) - self._config[variant].update(self._normalized_keys(section, items)) - - return parser - - def _construct_parser(self, fname): - # type: (str) -> RawConfigParser - parser = configparser.RawConfigParser() - # If there is no such file, don't bother reading it but create the - # parser anyway, to hold the data. - # Doing this is useful when modifying and saving files, where we don't - # need to construct a parser. - if os.path.exists(fname): - try: - parser.read(fname) - except UnicodeDecodeError: - # See https://github.com/pypa/pip/issues/4963 - raise ConfigurationFileCouldNotBeLoaded( - reason="contains invalid {} characters".format( - locale.getpreferredencoding(False) - ), - fname=fname, - ) - except configparser.Error as error: - # See https://github.com/pypa/pip/issues/4893 - raise ConfigurationFileCouldNotBeLoaded(error=error) - return parser - - def _load_environment_vars(self): - # type: () -> None - """Loads configuration from environment variables - """ - self._config[kinds.ENV_VAR].update( - self._normalized_keys(":env:", self._get_environ_vars()) - ) - - def _normalized_keys(self, section, items): - # type: (str, Iterable[Tuple[str, Any]]) -> Dict[str, Any] - """Normalizes items to construct a dictionary with normalized keys. - - This routine is where the names become keys and are made the same - regardless of source - configuration files or environment. - """ - normalized = {} - for name, val in items: - key = section + "." + _normalize_name(name) - normalized[key] = val - return normalized - - def _get_environ_vars(self): - # type: () -> Iterable[Tuple[str, str]] - """Returns a generator with all environmental vars with prefix PIP_""" - for key, val in os.environ.items(): - should_be_yielded = ( - key.startswith("PIP_") and - key[4:].lower() not in self._ignore_env_names - ) - if should_be_yielded: - yield key[4:].lower(), val - - # XXX: This is patched in the tests. - def _iter_config_files(self): - # type: () -> Iterable[Tuple[Kind, List[str]]] - """Yields variant and configuration files associated with it. - - This should be treated like items of a dictionary. - """ - # SMELL: Move the conditions out of this function - - # environment variables have the lowest priority - config_file = os.environ.get('PIP_CONFIG_FILE', None) - if config_file is not None: - yield kinds.ENV, [config_file] - else: - yield kinds.ENV, [] - - config_files = get_configuration_files() - - # at the base we have any global configuration - yield kinds.GLOBAL, config_files[kinds.GLOBAL] - - # per-user configuration next - should_load_user_config = not self.isolated and not ( - config_file and os.path.exists(config_file) - ) - if should_load_user_config: - # The legacy config file is overridden by the new config file - yield kinds.USER, config_files[kinds.USER] - - # finally virtualenv configuration first trumping others - yield kinds.SITE, config_files[kinds.SITE] - - def _get_parser_to_modify(self): - # type: () -> Tuple[str, RawConfigParser] - # Determine which parser to modify - parsers = self._parsers[self.load_only] - if not parsers: - # This should not happen if everything works correctly. - raise ConfigurationError( - "Fatal Internal error [id=2]. Please report as a bug." - ) - - # Use the highest priority parser. - return parsers[-1] - - # XXX: This is patched in the tests. - def _mark_as_modified(self, fname, parser): - # type: (str, RawConfigParser) -> None - file_parser_tuple = (fname, parser) - if file_parser_tuple not in self._modified_parsers: - self._modified_parsers.append(file_parser_tuple) - - def __repr__(self): - # type: () -> str - return "{}({!r})".format(self.__class__.__name__, self._dictionary) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/distributions/__init__.py b/venv/lib/python3.8/site-packages/pip/_internal/distributions/__init__.py deleted file mode 100644 index d5c1afc..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/distributions/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -from pip._internal.distributions.sdist import SourceDistribution -from pip._internal.distributions.wheel import WheelDistribution -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from pip._internal.distributions.base import AbstractDistribution - from pip._internal.req.req_install import InstallRequirement - - -def make_distribution_for_install_requirement(install_req): - # type: (InstallRequirement) -> AbstractDistribution - """Returns a Distribution for the given InstallRequirement - """ - # Editable requirements will always be source distributions. They use the - # legacy logic until we create a modern standard for them. - if install_req.editable: - return SourceDistribution(install_req) - - # If it's a wheel, it's a WheelDistribution - if install_req.is_wheel: - return WheelDistribution(install_req) - - # Otherwise, a SourceDistribution - return SourceDistribution(install_req) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/distributions/base.py b/venv/lib/python3.8/site-packages/pip/_internal/distributions/base.py deleted file mode 100644 index b836b98..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/distributions/base.py +++ /dev/null @@ -1,45 +0,0 @@ -import abc - -from pip._vendor.six import add_metaclass - -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import Optional - - from pip._vendor.pkg_resources import Distribution - from pip._internal.req import InstallRequirement - from pip._internal.index.package_finder import PackageFinder - - -@add_metaclass(abc.ABCMeta) -class AbstractDistribution(object): - """A base class for handling installable artifacts. - - The requirements for anything installable are as follows: - - - we must be able to determine the requirement name - (or we can't correctly handle the non-upgrade case). - - - for packages with setup requirements, we must also be able - to determine their requirements without installing additional - packages (for the same reason as run-time dependencies) - - - we must be able to create a Distribution object exposing the - above metadata. - """ - - def __init__(self, req): - # type: (InstallRequirement) -> None - super(AbstractDistribution, self).__init__() - self.req = req - - @abc.abstractmethod - def get_pkg_resources_distribution(self): - # type: () -> Optional[Distribution] - raise NotImplementedError() - - @abc.abstractmethod - def prepare_distribution_metadata(self, finder, build_isolation): - # type: (PackageFinder, bool) -> None - raise NotImplementedError() diff --git a/venv/lib/python3.8/site-packages/pip/_internal/distributions/installed.py b/venv/lib/python3.8/site-packages/pip/_internal/distributions/installed.py deleted file mode 100644 index 0d15bf4..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/distributions/installed.py +++ /dev/null @@ -1,24 +0,0 @@ -from pip._internal.distributions.base import AbstractDistribution -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import Optional - - from pip._vendor.pkg_resources import Distribution - from pip._internal.index.package_finder import PackageFinder - - -class InstalledDistribution(AbstractDistribution): - """Represents an installed package. - - This does not need any preparation as the required information has already - been computed. - """ - - def get_pkg_resources_distribution(self): - # type: () -> Optional[Distribution] - return self.req.satisfied_by - - def prepare_distribution_metadata(self, finder, build_isolation): - # type: (PackageFinder, bool) -> None - pass diff --git a/venv/lib/python3.8/site-packages/pip/_internal/distributions/sdist.py b/venv/lib/python3.8/site-packages/pip/_internal/distributions/sdist.py deleted file mode 100644 index be3d7d9..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/distributions/sdist.py +++ /dev/null @@ -1,104 +0,0 @@ -import logging - -from pip._internal.build_env import BuildEnvironment -from pip._internal.distributions.base import AbstractDistribution -from pip._internal.exceptions import InstallationError -from pip._internal.utils.subprocess import runner_with_spinner_message -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import Set, Tuple - - from pip._vendor.pkg_resources import Distribution - from pip._internal.index.package_finder import PackageFinder - - -logger = logging.getLogger(__name__) - - -class SourceDistribution(AbstractDistribution): - """Represents a source distribution. - - The preparation step for these needs metadata for the packages to be - generated, either using PEP 517 or using the legacy `setup.py egg_info`. - """ - - def get_pkg_resources_distribution(self): - # type: () -> Distribution - return self.req.get_dist() - - def prepare_distribution_metadata(self, finder, build_isolation): - # type: (PackageFinder, bool) -> None - # Load pyproject.toml, to determine whether PEP 517 is to be used - self.req.load_pyproject_toml() - - # Set up the build isolation, if this requirement should be isolated - should_isolate = self.req.use_pep517 and build_isolation - if should_isolate: - self._setup_isolation(finder) - - self.req.prepare_metadata() - - def _setup_isolation(self, finder): - # type: (PackageFinder) -> None - def _raise_conflicts(conflicting_with, conflicting_reqs): - # type: (str, Set[Tuple[str, str]]) -> None - format_string = ( - "Some build dependencies for {requirement} " - "conflict with {conflicting_with}: {description}." - ) - error_message = format_string.format( - requirement=self.req, - conflicting_with=conflicting_with, - description=', '.join( - '{} is incompatible with {}'.format(installed, wanted) - for installed, wanted in sorted(conflicting) - ) - ) - raise InstallationError(error_message) - - # Isolate in a BuildEnvironment and install the build-time - # requirements. - pyproject_requires = self.req.pyproject_requires - assert pyproject_requires is not None - - self.req.build_env = BuildEnvironment() - self.req.build_env.install_requirements( - finder, pyproject_requires, 'overlay', - "Installing build dependencies" - ) - conflicting, missing = self.req.build_env.check_requirements( - self.req.requirements_to_check - ) - if conflicting: - _raise_conflicts("PEP 517/518 supported requirements", - conflicting) - if missing: - logger.warning( - "Missing build requirements in pyproject.toml for %s.", - self.req, - ) - logger.warning( - "The project does not specify a build backend, and " - "pip cannot fall back to setuptools without %s.", - " and ".join(map(repr, sorted(missing))) - ) - # Install any extra build dependencies that the backend requests. - # This must be done in a second pass, as the pyproject.toml - # dependencies must be installed before we can call the backend. - with self.req.build_env: - runner = runner_with_spinner_message( - "Getting requirements to build wheel" - ) - backend = self.req.pep517_backend - assert backend is not None - with backend.subprocess_runner(runner): - reqs = backend.get_requires_for_build_wheel() - - conflicting, missing = self.req.build_env.check_requirements(reqs) - if conflicting: - _raise_conflicts("the backend dependencies", conflicting) - self.req.build_env.install_requirements( - finder, missing, 'normal', - "Installing backend dependencies" - ) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/distributions/wheel.py b/venv/lib/python3.8/site-packages/pip/_internal/distributions/wheel.py deleted file mode 100644 index bf3482b..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/distributions/wheel.py +++ /dev/null @@ -1,36 +0,0 @@ -from zipfile import ZipFile - -from pip._internal.distributions.base import AbstractDistribution -from pip._internal.utils.typing import MYPY_CHECK_RUNNING -from pip._internal.utils.wheel import pkg_resources_distribution_for_wheel - -if MYPY_CHECK_RUNNING: - from pip._vendor.pkg_resources import Distribution - from pip._internal.index.package_finder import PackageFinder - - -class WheelDistribution(AbstractDistribution): - """Represents a wheel distribution. - - This does not need any preparation as wheels can be directly unpacked. - """ - - def get_pkg_resources_distribution(self): - # type: () -> Distribution - """Loads the metadata from the wheel file into memory and returns a - Distribution that uses it, not relying on the wheel file or - requirement. - """ - # Set as part of preparation during download. - assert self.req.local_file_path - # Wheels are never unnamed. - assert self.req.name - - with ZipFile(self.req.local_file_path, allowZip64=True) as z: - return pkg_resources_distribution_for_wheel( - z, self.req.name, self.req.local_file_path - ) - - def prepare_distribution_metadata(self, finder, build_isolation): - # type: (PackageFinder, bool) -> None - pass diff --git a/venv/lib/python3.8/site-packages/pip/_internal/exceptions.py b/venv/lib/python3.8/site-packages/pip/_internal/exceptions.py deleted file mode 100644 index 8ac8548..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/exceptions.py +++ /dev/null @@ -1,308 +0,0 @@ -"""Exceptions used throughout package""" - -# The following comment should be removed at some point in the future. -# mypy: disallow-untyped-defs=False - -from __future__ import absolute_import - -from itertools import chain, groupby, repeat - -from pip._vendor.six import iteritems - -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import Optional - from pip._vendor.pkg_resources import Distribution - from pip._internal.req.req_install import InstallRequirement - - -class PipError(Exception): - """Base pip exception""" - - -class ConfigurationError(PipError): - """General exception in configuration""" - - -class InstallationError(PipError): - """General exception during installation""" - - -class UninstallationError(PipError): - """General exception during uninstallation""" - - -class NoneMetadataError(PipError): - """ - Raised when accessing "METADATA" or "PKG-INFO" metadata for a - pip._vendor.pkg_resources.Distribution object and - `dist.has_metadata('METADATA')` returns True but - `dist.get_metadata('METADATA')` returns None (and similarly for - "PKG-INFO"). - """ - - def __init__(self, dist, metadata_name): - # type: (Distribution, str) -> None - """ - :param dist: A Distribution object. - :param metadata_name: The name of the metadata being accessed - (can be "METADATA" or "PKG-INFO"). - """ - self.dist = dist - self.metadata_name = metadata_name - - def __str__(self): - # type: () -> str - # Use `dist` in the error message because its stringification - # includes more information, like the version and location. - return ( - 'None {} metadata found for distribution: {}'.format( - self.metadata_name, self.dist, - ) - ) - - -class DistributionNotFound(InstallationError): - """Raised when a distribution cannot be found to satisfy a requirement""" - - -class RequirementsFileParseError(InstallationError): - """Raised when a general error occurs parsing a requirements file line.""" - - -class BestVersionAlreadyInstalled(PipError): - """Raised when the most up-to-date version of a package is already - installed.""" - - -class BadCommand(PipError): - """Raised when virtualenv or a command is not found""" - - -class CommandError(PipError): - """Raised when there is an error in command-line arguments""" - - -class PreviousBuildDirError(PipError): - """Raised when there's a previous conflicting build directory""" - - -class InvalidWheelFilename(InstallationError): - """Invalid wheel filename.""" - - -class UnsupportedWheel(InstallationError): - """Unsupported wheel.""" - - -class HashErrors(InstallationError): - """Multiple HashError instances rolled into one for reporting""" - - def __init__(self): - self.errors = [] - - def append(self, error): - self.errors.append(error) - - def __str__(self): - lines = [] - self.errors.sort(key=lambda e: e.order) - for cls, errors_of_cls in groupby(self.errors, lambda e: e.__class__): - lines.append(cls.head) - lines.extend(e.body() for e in errors_of_cls) - if lines: - return '\n'.join(lines) - - def __nonzero__(self): - return bool(self.errors) - - def __bool__(self): - return self.__nonzero__() - - -class HashError(InstallationError): - """ - A failure to verify a package against known-good hashes - - :cvar order: An int sorting hash exception classes by difficulty of - recovery (lower being harder), so the user doesn't bother fretting - about unpinned packages when he has deeper issues, like VCS - dependencies, to deal with. Also keeps error reports in a - deterministic order. - :cvar head: A section heading for display above potentially many - exceptions of this kind - :ivar req: The InstallRequirement that triggered this error. This is - pasted on after the exception is instantiated, because it's not - typically available earlier. - - """ - req = None # type: Optional[InstallRequirement] - head = '' - - def body(self): - """Return a summary of me for display under the heading. - - This default implementation simply prints a description of the - triggering requirement. - - :param req: The InstallRequirement that provoked this error, with - its link already populated by the resolver's _populate_link(). - - """ - return ' {}'.format(self._requirement_name()) - - def __str__(self): - return '{}\n{}'.format(self.head, self.body()) - - def _requirement_name(self): - """Return a description of the requirement that triggered me. - - This default implementation returns long description of the req, with - line numbers - - """ - return str(self.req) if self.req else 'unknown package' - - -class VcsHashUnsupported(HashError): - """A hash was provided for a version-control-system-based requirement, but - we don't have a method for hashing those.""" - - order = 0 - head = ("Can't verify hashes for these requirements because we don't " - "have a way to hash version control repositories:") - - -class DirectoryUrlHashUnsupported(HashError): - """A hash was provided for a version-control-system-based requirement, but - we don't have a method for hashing those.""" - - order = 1 - head = ("Can't verify hashes for these file:// requirements because they " - "point to directories:") - - -class HashMissing(HashError): - """A hash was needed for a requirement but is absent.""" - - order = 2 - head = ('Hashes are required in --require-hashes mode, but they are ' - 'missing from some requirements. Here is a list of those ' - 'requirements along with the hashes their downloaded archives ' - 'actually had. Add lines like these to your requirements files to ' - 'prevent tampering. (If you did not enable --require-hashes ' - 'manually, note that it turns on automatically when any package ' - 'has a hash.)') - - def __init__(self, gotten_hash): - """ - :param gotten_hash: The hash of the (possibly malicious) archive we - just downloaded - """ - self.gotten_hash = gotten_hash - - def body(self): - # Dodge circular import. - from pip._internal.utils.hashes import FAVORITE_HASH - - package = None - if self.req: - # In the case of URL-based requirements, display the original URL - # seen in the requirements file rather than the package name, - # so the output can be directly copied into the requirements file. - package = (self.req.original_link if self.req.original_link - # In case someone feeds something downright stupid - # to InstallRequirement's constructor. - else getattr(self.req, 'req', None)) - return ' {} --hash={}:{}'.format(package or 'unknown package', - FAVORITE_HASH, - self.gotten_hash) - - -class HashUnpinned(HashError): - """A requirement had a hash specified but was not pinned to a specific - version.""" - - order = 3 - head = ('In --require-hashes mode, all requirements must have their ' - 'versions pinned with ==. These do not:') - - -class HashMismatch(HashError): - """ - Distribution file hash values don't match. - - :ivar package_name: The name of the package that triggered the hash - mismatch. Feel free to write to this after the exception is raise to - improve its error message. - - """ - order = 4 - head = ('THESE PACKAGES DO NOT MATCH THE HASHES FROM THE REQUIREMENTS ' - 'FILE. If you have updated the package versions, please update ' - 'the hashes. Otherwise, examine the package contents carefully; ' - 'someone may have tampered with them.') - - def __init__(self, allowed, gots): - """ - :param allowed: A dict of algorithm names pointing to lists of allowed - hex digests - :param gots: A dict of algorithm names pointing to hashes we - actually got from the files under suspicion - """ - self.allowed = allowed - self.gots = gots - - def body(self): - return ' {}:\n{}'.format(self._requirement_name(), - self._hash_comparison()) - - def _hash_comparison(self): - """ - Return a comparison of actual and expected hash values. - - Example:: - - Expected sha256 abcdeabcdeabcdeabcdeabcdeabcdeabcdeabcdeabcde - or 123451234512345123451234512345123451234512345 - Got bcdefbcdefbcdefbcdefbcdefbcdefbcdefbcdefbcdef - - """ - def hash_then_or(hash_name): - # For now, all the decent hashes have 6-char names, so we can get - # away with hard-coding space literals. - return chain([hash_name], repeat(' or')) - - lines = [] - for hash_name, expecteds in iteritems(self.allowed): - prefix = hash_then_or(hash_name) - lines.extend((' Expected {} {}'.format(next(prefix), e)) - for e in expecteds) - lines.append(' Got {}\n'.format( - self.gots[hash_name].hexdigest())) - return '\n'.join(lines) - - -class UnsupportedPythonVersion(InstallationError): - """Unsupported python version according to Requires-Python package - metadata.""" - - -class ConfigurationFileCouldNotBeLoaded(ConfigurationError): - """When there are errors while loading a configuration file - """ - - def __init__(self, reason="could not be loaded", fname=None, error=None): - super(ConfigurationFileCouldNotBeLoaded, self).__init__(error) - self.reason = reason - self.fname = fname - self.error = error - - def __str__(self): - if self.fname is not None: - message_part = " in {}.".format(self.fname) - else: - assert self.error is not None - message_part = ".\n{}\n".format(self.error.message) - return "Configuration file {}{}".format(self.reason, message_part) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/index/__init__.py b/venv/lib/python3.8/site-packages/pip/_internal/index/__init__.py deleted file mode 100644 index 7a17b7b..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/index/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -"""Index interaction code -""" diff --git a/venv/lib/python3.8/site-packages/pip/_internal/index/collector.py b/venv/lib/python3.8/site-packages/pip/_internal/index/collector.py deleted file mode 100644 index e2c800c..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/index/collector.py +++ /dev/null @@ -1,661 +0,0 @@ -""" -The main purpose of this module is to expose LinkCollector.collect_links(). -""" - -import cgi -import functools -import itertools -import logging -import mimetypes -import os -import re -from collections import OrderedDict - -from pip._vendor import html5lib, requests -from pip._vendor.distlib.compat import unescape -from pip._vendor.requests.exceptions import HTTPError, RetryError, SSLError -from pip._vendor.six.moves.urllib import parse as urllib_parse -from pip._vendor.six.moves.urllib import request as urllib_request - -from pip._internal.models.link import Link -from pip._internal.utils.filetypes import ARCHIVE_EXTENSIONS -from pip._internal.utils.misc import pairwise, redact_auth_from_url -from pip._internal.utils.typing import MYPY_CHECK_RUNNING -from pip._internal.utils.urls import path_to_url, url_to_path -from pip._internal.vcs import is_url, vcs - -if MYPY_CHECK_RUNNING: - from typing import ( - Callable, Iterable, List, MutableMapping, Optional, - Protocol, Sequence, Tuple, TypeVar, Union, - ) - import xml.etree.ElementTree - - from pip._vendor.requests import Response - - from pip._internal.models.search_scope import SearchScope - from pip._internal.network.session import PipSession - - HTMLElement = xml.etree.ElementTree.Element - ResponseHeaders = MutableMapping[str, str] - - # Used in the @lru_cache polyfill. - F = TypeVar('F') - - class LruCache(Protocol): - def __call__(self, maxsize=None): - # type: (Optional[int]) -> Callable[[F], F] - raise NotImplementedError - - -logger = logging.getLogger(__name__) - - -# Fallback to noop_lru_cache in Python 2 -# TODO: this can be removed when python 2 support is dropped! -def noop_lru_cache(maxsize=None): - # type: (Optional[int]) -> Callable[[F], F] - def _wrapper(f): - # type: (F) -> F - return f - return _wrapper - - -_lru_cache = getattr(functools, "lru_cache", noop_lru_cache) # type: LruCache - - -def _match_vcs_scheme(url): - # type: (str) -> Optional[str] - """Look for VCS schemes in the URL. - - Returns the matched VCS scheme, or None if there's no match. - """ - for scheme in vcs.schemes: - if url.lower().startswith(scheme) and url[len(scheme)] in '+:': - return scheme - return None - - -def _is_url_like_archive(url): - # type: (str) -> bool - """Return whether the URL looks like an archive. - """ - filename = Link(url).filename - for bad_ext in ARCHIVE_EXTENSIONS: - if filename.endswith(bad_ext): - return True - return False - - -class _NotHTML(Exception): - def __init__(self, content_type, request_desc): - # type: (str, str) -> None - super(_NotHTML, self).__init__(content_type, request_desc) - self.content_type = content_type - self.request_desc = request_desc - - -def _ensure_html_header(response): - # type: (Response) -> None - """Check the Content-Type header to ensure the response contains HTML. - - Raises `_NotHTML` if the content type is not text/html. - """ - content_type = response.headers.get("Content-Type", "") - if not content_type.lower().startswith("text/html"): - raise _NotHTML(content_type, response.request.method) - - -class _NotHTTP(Exception): - pass - - -def _ensure_html_response(url, session): - # type: (str, PipSession) -> None - """Send a HEAD request to the URL, and ensure the response contains HTML. - - Raises `_NotHTTP` if the URL is not available for a HEAD request, or - `_NotHTML` if the content type is not text/html. - """ - scheme, netloc, path, query, fragment = urllib_parse.urlsplit(url) - if scheme not in {'http', 'https'}: - raise _NotHTTP() - - resp = session.head(url, allow_redirects=True) - resp.raise_for_status() - - _ensure_html_header(resp) - - -def _get_html_response(url, session): - # type: (str, PipSession) -> Response - """Access an HTML page with GET, and return the response. - - This consists of three parts: - - 1. If the URL looks suspiciously like an archive, send a HEAD first to - check the Content-Type is HTML, to avoid downloading a large file. - Raise `_NotHTTP` if the content type cannot be determined, or - `_NotHTML` if it is not HTML. - 2. Actually perform the request. Raise HTTP exceptions on network failures. - 3. Check the Content-Type header to make sure we got HTML, and raise - `_NotHTML` otherwise. - """ - if _is_url_like_archive(url): - _ensure_html_response(url, session=session) - - logger.debug('Getting page %s', redact_auth_from_url(url)) - - resp = session.get( - url, - headers={ - "Accept": "text/html", - # We don't want to blindly returned cached data for - # /simple/, because authors generally expecting that - # twine upload && pip install will function, but if - # they've done a pip install in the last ~10 minutes - # it won't. Thus by setting this to zero we will not - # blindly use any cached data, however the benefit of - # using max-age=0 instead of no-cache, is that we will - # still support conditional requests, so we will still - # minimize traffic sent in cases where the page hasn't - # changed at all, we will just always incur the round - # trip for the conditional GET now instead of only - # once per 10 minutes. - # For more information, please see pypa/pip#5670. - "Cache-Control": "max-age=0", - }, - ) - resp.raise_for_status() - - # The check for archives above only works if the url ends with - # something that looks like an archive. However that is not a - # requirement of an url. Unless we issue a HEAD request on every - # url we cannot know ahead of time for sure if something is HTML - # or not. However we can check after we've downloaded it. - _ensure_html_header(resp) - - return resp - - -def _get_encoding_from_headers(headers): - # type: (ResponseHeaders) -> Optional[str] - """Determine if we have any encoding information in our headers. - """ - if headers and "Content-Type" in headers: - content_type, params = cgi.parse_header(headers["Content-Type"]) - if "charset" in params: - return params['charset'] - return None - - -def _determine_base_url(document, page_url): - # type: (HTMLElement, str) -> str - """Determine the HTML document's base URL. - - This looks for a ``<base>`` tag in the HTML document. If present, its href - attribute denotes the base URL of anchor tags in the document. If there is - no such tag (or if it does not have a valid href attribute), the HTML - file's URL is used as the base URL. - - :param document: An HTML document representation. The current - implementation expects the result of ``html5lib.parse()``. - :param page_url: The URL of the HTML document. - """ - for base in document.findall(".//base"): - href = base.get("href") - if href is not None: - return href - return page_url - - -def _clean_url_path_part(part): - # type: (str) -> str - """ - Clean a "part" of a URL path (i.e. after splitting on "@" characters). - """ - # We unquote prior to quoting to make sure nothing is double quoted. - return urllib_parse.quote(urllib_parse.unquote(part)) - - -def _clean_file_url_path(part): - # type: (str) -> str - """ - Clean the first part of a URL path that corresponds to a local - filesystem path (i.e. the first part after splitting on "@" characters). - """ - # We unquote prior to quoting to make sure nothing is double quoted. - # Also, on Windows the path part might contain a drive letter which - # should not be quoted. On Linux where drive letters do not - # exist, the colon should be quoted. We rely on urllib.request - # to do the right thing here. - return urllib_request.pathname2url(urllib_request.url2pathname(part)) - - -# percent-encoded: / -_reserved_chars_re = re.compile('(@|%2F)', re.IGNORECASE) - - -def _clean_url_path(path, is_local_path): - # type: (str, bool) -> str - """ - Clean the path portion of a URL. - """ - if is_local_path: - clean_func = _clean_file_url_path - else: - clean_func = _clean_url_path_part - - # Split on the reserved characters prior to cleaning so that - # revision strings in VCS URLs are properly preserved. - parts = _reserved_chars_re.split(path) - - cleaned_parts = [] - for to_clean, reserved in pairwise(itertools.chain(parts, [''])): - cleaned_parts.append(clean_func(to_clean)) - # Normalize %xx escapes (e.g. %2f -> %2F) - cleaned_parts.append(reserved.upper()) - - return ''.join(cleaned_parts) - - -def _clean_link(url): - # type: (str) -> str - """ - Make sure a link is fully quoted. - For example, if ' ' occurs in the URL, it will be replaced with "%20", - and without double-quoting other characters. - """ - # Split the URL into parts according to the general structure - # `scheme://netloc/path;parameters?query#fragment`. - result = urllib_parse.urlparse(url) - # If the netloc is empty, then the URL refers to a local filesystem path. - is_local_path = not result.netloc - path = _clean_url_path(result.path, is_local_path=is_local_path) - return urllib_parse.urlunparse(result._replace(path=path)) - - -def _create_link_from_element( - anchor, # type: HTMLElement - page_url, # type: str - base_url, # type: str -): - # type: (...) -> Optional[Link] - """ - Convert an anchor element in a simple repository page to a Link. - """ - href = anchor.get("href") - if not href: - return None - - url = _clean_link(urllib_parse.urljoin(base_url, href)) - pyrequire = anchor.get('data-requires-python') - pyrequire = unescape(pyrequire) if pyrequire else None - - yanked_reason = anchor.get('data-yanked') - if yanked_reason: - # This is a unicode string in Python 2 (and 3). - yanked_reason = unescape(yanked_reason) - - link = Link( - url, - comes_from=page_url, - requires_python=pyrequire, - yanked_reason=yanked_reason, - ) - - return link - - -class CacheablePageContent(object): - def __init__(self, page): - # type: (HTMLPage) -> None - assert page.cache_link_parsing - self.page = page - - def __eq__(self, other): - # type: (object) -> bool - return (isinstance(other, type(self)) and - self.page.url == other.page.url) - - def __hash__(self): - # type: () -> int - return hash(self.page.url) - - -def with_cached_html_pages( - fn, # type: Callable[[HTMLPage], Iterable[Link]] -): - # type: (...) -> Callable[[HTMLPage], List[Link]] - """ - Given a function that parses an Iterable[Link] from an HTMLPage, cache the - function's result (keyed by CacheablePageContent), unless the HTMLPage - `page` has `page.cache_link_parsing == False`. - """ - - @_lru_cache(maxsize=None) - def wrapper(cacheable_page): - # type: (CacheablePageContent) -> List[Link] - return list(fn(cacheable_page.page)) - - @functools.wraps(fn) - def wrapper_wrapper(page): - # type: (HTMLPage) -> List[Link] - if page.cache_link_parsing: - return wrapper(CacheablePageContent(page)) - return list(fn(page)) - - return wrapper_wrapper - - -@with_cached_html_pages -def parse_links(page): - # type: (HTMLPage) -> Iterable[Link] - """ - Parse an HTML document, and yield its anchor elements as Link objects. - """ - document = html5lib.parse( - page.content, - transport_encoding=page.encoding, - namespaceHTMLElements=False, - ) - - url = page.url - base_url = _determine_base_url(document, url) - for anchor in document.findall(".//a"): - link = _create_link_from_element( - anchor, - page_url=url, - base_url=base_url, - ) - if link is None: - continue - yield link - - -class HTMLPage(object): - """Represents one page, along with its URL""" - - def __init__( - self, - content, # type: bytes - encoding, # type: Optional[str] - url, # type: str - cache_link_parsing=True, # type: bool - ): - # type: (...) -> None - """ - :param encoding: the encoding to decode the given content. - :param url: the URL from which the HTML was downloaded. - :param cache_link_parsing: whether links parsed from this page's url - should be cached. PyPI index urls should - have this set to False, for example. - """ - self.content = content - self.encoding = encoding - self.url = url - self.cache_link_parsing = cache_link_parsing - - def __str__(self): - # type: () -> str - return redact_auth_from_url(self.url) - - -def _handle_get_page_fail( - link, # type: Link - reason, # type: Union[str, Exception] - meth=None # type: Optional[Callable[..., None]] -): - # type: (...) -> None - if meth is None: - meth = logger.debug - meth("Could not fetch URL %s: %s - skipping", link, reason) - - -def _make_html_page(response, cache_link_parsing=True): - # type: (Response, bool) -> HTMLPage - encoding = _get_encoding_from_headers(response.headers) - return HTMLPage( - response.content, - encoding=encoding, - url=response.url, - cache_link_parsing=cache_link_parsing) - - -def _get_html_page(link, session=None): - # type: (Link, Optional[PipSession]) -> Optional[HTMLPage] - if session is None: - raise TypeError( - "_get_html_page() missing 1 required keyword argument: 'session'" - ) - - url = link.url.split('#', 1)[0] - - # Check for VCS schemes that do not support lookup as web pages. - vcs_scheme = _match_vcs_scheme(url) - if vcs_scheme: - logger.debug('Cannot look at %s URL %s', vcs_scheme, link) - return None - - # Tack index.html onto file:// URLs that point to directories - scheme, _, path, _, _, _ = urllib_parse.urlparse(url) - if (scheme == 'file' and os.path.isdir(urllib_request.url2pathname(path))): - # add trailing slash if not present so urljoin doesn't trim - # final segment - if not url.endswith('/'): - url += '/' - url = urllib_parse.urljoin(url, 'index.html') - logger.debug(' file: URL is directory, getting %s', url) - - try: - resp = _get_html_response(url, session=session) - except _NotHTTP: - logger.debug( - 'Skipping page %s because it looks like an archive, and cannot ' - 'be checked by HEAD.', link, - ) - except _NotHTML as exc: - logger.debug( - 'Skipping page %s because the %s request got Content-Type: %s', - link, exc.request_desc, exc.content_type, - ) - except HTTPError as exc: - _handle_get_page_fail(link, exc) - except RetryError as exc: - _handle_get_page_fail(link, exc) - except SSLError as exc: - reason = "There was a problem confirming the ssl certificate: " - reason += str(exc) - _handle_get_page_fail(link, reason, meth=logger.info) - except requests.ConnectionError as exc: - _handle_get_page_fail(link, "connection error: {}".format(exc)) - except requests.Timeout: - _handle_get_page_fail(link, "timed out") - else: - return _make_html_page(resp, - cache_link_parsing=link.cache_link_parsing) - return None - - -def _remove_duplicate_links(links): - # type: (Iterable[Link]) -> List[Link] - """ - Return a list of links, with duplicates removed and ordering preserved. - """ - # We preserve the ordering when removing duplicates because we can. - return list(OrderedDict.fromkeys(links)) - - -def group_locations(locations, expand_dir=False): - # type: (Sequence[str], bool) -> Tuple[List[str], List[str]] - """ - Divide a list of locations into two groups: "files" (archives) and "urls." - - :return: A pair of lists (files, urls). - """ - files = [] - urls = [] - - # puts the url for the given file path into the appropriate list - def sort_path(path): - # type: (str) -> None - url = path_to_url(path) - if mimetypes.guess_type(url, strict=False)[0] == 'text/html': - urls.append(url) - else: - files.append(url) - - for url in locations: - - is_local_path = os.path.exists(url) - is_file_url = url.startswith('file:') - - if is_local_path or is_file_url: - if is_local_path: - path = url - else: - path = url_to_path(url) - if os.path.isdir(path): - if expand_dir: - path = os.path.realpath(path) - for item in os.listdir(path): - sort_path(os.path.join(path, item)) - elif is_file_url: - urls.append(url) - else: - logger.warning( - "Path '{0}' is ignored: " - "it is a directory.".format(path), - ) - elif os.path.isfile(path): - sort_path(path) - else: - logger.warning( - "Url '%s' is ignored: it is neither a file " - "nor a directory.", url, - ) - elif is_url(url): - # Only add url with clear scheme - urls.append(url) - else: - logger.warning( - "Url '%s' is ignored. It is either a non-existing " - "path or lacks a specific scheme.", url, - ) - - return files, urls - - -class CollectedLinks(object): - - """ - Encapsulates the return value of a call to LinkCollector.collect_links(). - - The return value includes both URLs to project pages containing package - links, as well as individual package Link objects collected from other - sources. - - This info is stored separately as: - - (1) links from the configured file locations, - (2) links from the configured find_links, and - (3) urls to HTML project pages, as described by the PEP 503 simple - repository API. - """ - - def __init__( - self, - files, # type: List[Link] - find_links, # type: List[Link] - project_urls, # type: List[Link] - ): - # type: (...) -> None - """ - :param files: Links from file locations. - :param find_links: Links from find_links. - :param project_urls: URLs to HTML project pages, as described by - the PEP 503 simple repository API. - """ - self.files = files - self.find_links = find_links - self.project_urls = project_urls - - -class LinkCollector(object): - - """ - Responsible for collecting Link objects from all configured locations, - making network requests as needed. - - The class's main method is its collect_links() method. - """ - - def __init__( - self, - session, # type: PipSession - search_scope, # type: SearchScope - ): - # type: (...) -> None - self.search_scope = search_scope - self.session = session - - @property - def find_links(self): - # type: () -> List[str] - return self.search_scope.find_links - - def fetch_page(self, location): - # type: (Link) -> Optional[HTMLPage] - """ - Fetch an HTML page containing package links. - """ - return _get_html_page(location, session=self.session) - - def collect_links(self, project_name): - # type: (str) -> CollectedLinks - """Find all available links for the given project name. - - :return: All the Link objects (unfiltered), as a CollectedLinks object. - """ - search_scope = self.search_scope - index_locations = search_scope.get_index_urls_locations(project_name) - index_file_loc, index_url_loc = group_locations(index_locations) - fl_file_loc, fl_url_loc = group_locations( - self.find_links, expand_dir=True, - ) - - file_links = [ - Link(url) for url in itertools.chain(index_file_loc, fl_file_loc) - ] - - # We trust every directly linked archive in find_links - find_link_links = [Link(url, '-f') for url in self.find_links] - - # We trust every url that the user has given us whether it was given - # via --index-url or --find-links. - # We want to filter out anything that does not have a secure origin. - url_locations = [ - link for link in itertools.chain( - # Mark PyPI indices as "cache_link_parsing == False" -- this - # will avoid caching the result of parsing the page for links. - (Link(url, cache_link_parsing=False) for url in index_url_loc), - (Link(url) for url in fl_url_loc), - ) - if self.session.is_secure_origin(link) - ] - - url_locations = _remove_duplicate_links(url_locations) - lines = [ - '{} location(s) to search for versions of {}:'.format( - len(url_locations), project_name, - ), - ] - for link in url_locations: - lines.append('* {}'.format(link)) - logger.debug('\n'.join(lines)) - - return CollectedLinks( - files=file_links, - find_links=find_link_links, - project_urls=url_locations, - ) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/index/package_finder.py b/venv/lib/python3.8/site-packages/pip/_internal/index/package_finder.py deleted file mode 100644 index e88ad9f..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/index/package_finder.py +++ /dev/null @@ -1,1016 +0,0 @@ -"""Routines related to PyPI, indexes""" - -# The following comment should be removed at some point in the future. -# mypy: strict-optional=False - -from __future__ import absolute_import - -import logging -import re - -from pip._vendor.packaging import specifiers -from pip._vendor.packaging.utils import canonicalize_name -from pip._vendor.packaging.version import parse as parse_version - -from pip._internal.exceptions import ( - BestVersionAlreadyInstalled, - DistributionNotFound, - InvalidWheelFilename, - UnsupportedWheel, -) -from pip._internal.index.collector import parse_links -from pip._internal.models.candidate import InstallationCandidate -from pip._internal.models.format_control import FormatControl -from pip._internal.models.link import Link -from pip._internal.models.selection_prefs import SelectionPreferences -from pip._internal.models.target_python import TargetPython -from pip._internal.models.wheel import Wheel -from pip._internal.utils.filetypes import WHEEL_EXTENSION -from pip._internal.utils.logging import indent_log -from pip._internal.utils.misc import build_netloc -from pip._internal.utils.packaging import check_requires_python -from pip._internal.utils.typing import MYPY_CHECK_RUNNING -from pip._internal.utils.unpacking import SUPPORTED_EXTENSIONS -from pip._internal.utils.urls import url_to_path - -if MYPY_CHECK_RUNNING: - from typing import ( - FrozenSet, Iterable, List, Optional, Set, Text, Tuple, Union, - ) - - from pip._vendor.packaging.tags import Tag - from pip._vendor.packaging.version import _BaseVersion - - from pip._internal.index.collector import LinkCollector - from pip._internal.models.search_scope import SearchScope - from pip._internal.req import InstallRequirement - from pip._internal.utils.hashes import Hashes - - BuildTag = Union[Tuple[()], Tuple[int, str]] - CandidateSortingKey = ( - Tuple[int, int, int, _BaseVersion, BuildTag, Optional[int]] - ) - - -__all__ = ['FormatControl', 'BestCandidateResult', 'PackageFinder'] - - -logger = logging.getLogger(__name__) - - -def _check_link_requires_python( - link, # type: Link - version_info, # type: Tuple[int, int, int] - ignore_requires_python=False, # type: bool -): - # type: (...) -> bool - """ - Return whether the given Python version is compatible with a link's - "Requires-Python" value. - - :param version_info: A 3-tuple of ints representing the Python - major-minor-micro version to check. - :param ignore_requires_python: Whether to ignore the "Requires-Python" - value if the given Python version isn't compatible. - """ - try: - is_compatible = check_requires_python( - link.requires_python, version_info=version_info, - ) - except specifiers.InvalidSpecifier: - logger.debug( - "Ignoring invalid Requires-Python (%r) for link: %s", - link.requires_python, link, - ) - else: - if not is_compatible: - version = '.'.join(map(str, version_info)) - if not ignore_requires_python: - logger.debug( - 'Link requires a different Python (%s not in: %r): %s', - version, link.requires_python, link, - ) - return False - - logger.debug( - 'Ignoring failed Requires-Python check (%s not in: %r) ' - 'for link: %s', - version, link.requires_python, link, - ) - - return True - - -class LinkEvaluator(object): - - """ - Responsible for evaluating links for a particular project. - """ - - _py_version_re = re.compile(r'-py([123]\.?[0-9]?)$') - - # Don't include an allow_yanked default value to make sure each call - # site considers whether yanked releases are allowed. This also causes - # that decision to be made explicit in the calling code, which helps - # people when reading the code. - def __init__( - self, - project_name, # type: str - canonical_name, # type: str - formats, # type: FrozenSet[str] - target_python, # type: TargetPython - allow_yanked, # type: bool - ignore_requires_python=None, # type: Optional[bool] - ): - # type: (...) -> None - """ - :param project_name: The user supplied package name. - :param canonical_name: The canonical package name. - :param formats: The formats allowed for this package. Should be a set - with 'binary' or 'source' or both in it. - :param target_python: The target Python interpreter to use when - evaluating link compatibility. This is used, for example, to - check wheel compatibility, as well as when checking the Python - version, e.g. the Python version embedded in a link filename - (or egg fragment) and against an HTML link's optional PEP 503 - "data-requires-python" attribute. - :param allow_yanked: Whether files marked as yanked (in the sense - of PEP 592) are permitted to be candidates for install. - :param ignore_requires_python: Whether to ignore incompatible - PEP 503 "data-requires-python" values in HTML links. Defaults - to False. - """ - if ignore_requires_python is None: - ignore_requires_python = False - - self._allow_yanked = allow_yanked - self._canonical_name = canonical_name - self._ignore_requires_python = ignore_requires_python - self._formats = formats - self._target_python = target_python - - self.project_name = project_name - - def evaluate_link(self, link): - # type: (Link) -> Tuple[bool, Optional[Text]] - """ - Determine whether a link is a candidate for installation. - - :return: A tuple (is_candidate, result), where `result` is (1) a - version string if `is_candidate` is True, and (2) if - `is_candidate` is False, an optional string to log the reason - the link fails to qualify. - """ - version = None - if link.is_yanked and not self._allow_yanked: - reason = link.yanked_reason or '<none given>' - # Mark this as a unicode string to prevent "UnicodeEncodeError: - # 'ascii' codec can't encode character" in Python 2 when - # the reason contains non-ascii characters. - return (False, u'yanked for reason: {}'.format(reason)) - - if link.egg_fragment: - egg_info = link.egg_fragment - ext = link.ext - else: - egg_info, ext = link.splitext() - if not ext: - return (False, 'not a file') - if ext not in SUPPORTED_EXTENSIONS: - return (False, 'unsupported archive format: {}'.format(ext)) - if "binary" not in self._formats and ext == WHEEL_EXTENSION: - reason = 'No binaries permitted for {}'.format( - self.project_name) - return (False, reason) - if "macosx10" in link.path and ext == '.zip': - return (False, 'macosx10 one') - if ext == WHEEL_EXTENSION: - try: - wheel = Wheel(link.filename) - except InvalidWheelFilename: - return (False, 'invalid wheel filename') - if canonicalize_name(wheel.name) != self._canonical_name: - reason = 'wrong project name (not {})'.format( - self.project_name) - return (False, reason) - - supported_tags = self._target_python.get_tags() - if not wheel.supported(supported_tags): - # Include the wheel's tags in the reason string to - # simplify troubleshooting compatibility issues. - file_tags = wheel.get_formatted_file_tags() - reason = ( - "none of the wheel's tags match: {}".format( - ', '.join(file_tags) - ) - ) - return (False, reason) - - version = wheel.version - - # This should be up by the self.ok_binary check, but see issue 2700. - if "source" not in self._formats and ext != WHEEL_EXTENSION: - reason = 'No sources permitted for {}'.format(self.project_name) - return (False, reason) - - if not version: - version = _extract_version_from_fragment( - egg_info, self._canonical_name, - ) - if not version: - reason = 'Missing project version for {}'.format(self.project_name) - return (False, reason) - - match = self._py_version_re.search(version) - if match: - version = version[:match.start()] - py_version = match.group(1) - if py_version != self._target_python.py_version: - return (False, 'Python version is incorrect') - - supports_python = _check_link_requires_python( - link, version_info=self._target_python.py_version_info, - ignore_requires_python=self._ignore_requires_python, - ) - if not supports_python: - # Return None for the reason text to suppress calling - # _log_skipped_link(). - return (False, None) - - logger.debug('Found link %s, version: %s', link, version) - - return (True, version) - - -def filter_unallowed_hashes( - candidates, # type: List[InstallationCandidate] - hashes, # type: Hashes - project_name, # type: str -): - # type: (...) -> List[InstallationCandidate] - """ - Filter out candidates whose hashes aren't allowed, and return a new - list of candidates. - - If at least one candidate has an allowed hash, then all candidates with - either an allowed hash or no hash specified are returned. Otherwise, - the given candidates are returned. - - Including the candidates with no hash specified when there is a match - allows a warning to be logged if there is a more preferred candidate - with no hash specified. Returning all candidates in the case of no - matches lets pip report the hash of the candidate that would otherwise - have been installed (e.g. permitting the user to more easily update - their requirements file with the desired hash). - """ - if not hashes: - logger.debug( - 'Given no hashes to check %s links for project %r: ' - 'discarding no candidates', - len(candidates), - project_name, - ) - # Make sure we're not returning back the given value. - return list(candidates) - - matches_or_no_digest = [] - # Collect the non-matches for logging purposes. - non_matches = [] - match_count = 0 - for candidate in candidates: - link = candidate.link - if not link.has_hash: - pass - elif link.is_hash_allowed(hashes=hashes): - match_count += 1 - else: - non_matches.append(candidate) - continue - - matches_or_no_digest.append(candidate) - - if match_count: - filtered = matches_or_no_digest - else: - # Make sure we're not returning back the given value. - filtered = list(candidates) - - if len(filtered) == len(candidates): - discard_message = 'discarding no candidates' - else: - discard_message = 'discarding {} non-matches:\n {}'.format( - len(non_matches), - '\n '.join(str(candidate.link) for candidate in non_matches) - ) - - logger.debug( - 'Checked %s links for project %r against %s hashes ' - '(%s matches, %s no digest): %s', - len(candidates), - project_name, - hashes.digest_count, - match_count, - len(matches_or_no_digest) - match_count, - discard_message - ) - - return filtered - - -class CandidatePreferences(object): - - """ - Encapsulates some of the preferences for filtering and sorting - InstallationCandidate objects. - """ - - def __init__( - self, - prefer_binary=False, # type: bool - allow_all_prereleases=False, # type: bool - ): - # type: (...) -> None - """ - :param allow_all_prereleases: Whether to allow all pre-releases. - """ - self.allow_all_prereleases = allow_all_prereleases - self.prefer_binary = prefer_binary - - -class BestCandidateResult(object): - """A collection of candidates, returned by `PackageFinder.find_best_candidate`. - - This class is only intended to be instantiated by CandidateEvaluator's - `compute_best_candidate()` method. - """ - - def __init__( - self, - candidates, # type: List[InstallationCandidate] - applicable_candidates, # type: List[InstallationCandidate] - best_candidate, # type: Optional[InstallationCandidate] - ): - # type: (...) -> None - """ - :param candidates: A sequence of all available candidates found. - :param applicable_candidates: The applicable candidates. - :param best_candidate: The most preferred candidate found, or None - if no applicable candidates were found. - """ - assert set(applicable_candidates) <= set(candidates) - - if best_candidate is None: - assert not applicable_candidates - else: - assert best_candidate in applicable_candidates - - self._applicable_candidates = applicable_candidates - self._candidates = candidates - - self.best_candidate = best_candidate - - def iter_all(self): - # type: () -> Iterable[InstallationCandidate] - """Iterate through all candidates. - """ - return iter(self._candidates) - - def iter_applicable(self): - # type: () -> Iterable[InstallationCandidate] - """Iterate through the applicable candidates. - """ - return iter(self._applicable_candidates) - - -class CandidateEvaluator(object): - - """ - Responsible for filtering and sorting candidates for installation based - on what tags are valid. - """ - - @classmethod - def create( - cls, - project_name, # type: str - target_python=None, # type: Optional[TargetPython] - prefer_binary=False, # type: bool - allow_all_prereleases=False, # type: bool - specifier=None, # type: Optional[specifiers.BaseSpecifier] - hashes=None, # type: Optional[Hashes] - ): - # type: (...) -> CandidateEvaluator - """Create a CandidateEvaluator object. - - :param target_python: The target Python interpreter to use when - checking compatibility. If None (the default), a TargetPython - object will be constructed from the running Python. - :param specifier: An optional object implementing `filter` - (e.g. `packaging.specifiers.SpecifierSet`) to filter applicable - versions. - :param hashes: An optional collection of allowed hashes. - """ - if target_python is None: - target_python = TargetPython() - if specifier is None: - specifier = specifiers.SpecifierSet() - - supported_tags = target_python.get_tags() - - return cls( - project_name=project_name, - supported_tags=supported_tags, - specifier=specifier, - prefer_binary=prefer_binary, - allow_all_prereleases=allow_all_prereleases, - hashes=hashes, - ) - - def __init__( - self, - project_name, # type: str - supported_tags, # type: List[Tag] - specifier, # type: specifiers.BaseSpecifier - prefer_binary=False, # type: bool - allow_all_prereleases=False, # type: bool - hashes=None, # type: Optional[Hashes] - ): - # type: (...) -> None - """ - :param supported_tags: The PEP 425 tags supported by the target - Python in order of preference (most preferred first). - """ - self._allow_all_prereleases = allow_all_prereleases - self._hashes = hashes - self._prefer_binary = prefer_binary - self._project_name = project_name - self._specifier = specifier - self._supported_tags = supported_tags - - def get_applicable_candidates( - self, - candidates, # type: List[InstallationCandidate] - ): - # type: (...) -> List[InstallationCandidate] - """ - Return the applicable candidates from a list of candidates. - """ - # Using None infers from the specifier instead. - allow_prereleases = self._allow_all_prereleases or None - specifier = self._specifier - versions = { - str(v) for v in specifier.filter( - # We turn the version object into a str here because otherwise - # when we're debundled but setuptools isn't, Python will see - # packaging.version.Version and - # pkg_resources._vendor.packaging.version.Version as different - # types. This way we'll use a str as a common data interchange - # format. If we stop using the pkg_resources provided specifier - # and start using our own, we can drop the cast to str(). - (str(c.version) for c in candidates), - prereleases=allow_prereleases, - ) - } - - # Again, converting version to str to deal with debundling. - applicable_candidates = [ - c for c in candidates if str(c.version) in versions - ] - - filtered_applicable_candidates = filter_unallowed_hashes( - candidates=applicable_candidates, - hashes=self._hashes, - project_name=self._project_name, - ) - - return sorted(filtered_applicable_candidates, key=self._sort_key) - - def _sort_key(self, candidate): - # type: (InstallationCandidate) -> CandidateSortingKey - """ - Function to pass as the `key` argument to a call to sorted() to sort - InstallationCandidates by preference. - - Returns a tuple such that tuples sorting as greater using Python's - default comparison operator are more preferred. - - The preference is as follows: - - First and foremost, candidates with allowed (matching) hashes are - always preferred over candidates without matching hashes. This is - because e.g. if the only candidate with an allowed hash is yanked, - we still want to use that candidate. - - Second, excepting hash considerations, candidates that have been - yanked (in the sense of PEP 592) are always less preferred than - candidates that haven't been yanked. Then: - - If not finding wheels, they are sorted by version only. - If finding wheels, then the sort order is by version, then: - 1. existing installs - 2. wheels ordered via Wheel.support_index_min(self._supported_tags) - 3. source archives - If prefer_binary was set, then all wheels are sorted above sources. - - Note: it was considered to embed this logic into the Link - comparison operators, but then different sdist links - with the same version, would have to be considered equal - """ - valid_tags = self._supported_tags - support_num = len(valid_tags) - build_tag = () # type: BuildTag - binary_preference = 0 - link = candidate.link - if link.is_wheel: - # can raise InvalidWheelFilename - wheel = Wheel(link.filename) - if not wheel.supported(valid_tags): - raise UnsupportedWheel( - "{} is not a supported wheel for this platform. It " - "can't be sorted.".format(wheel.filename) - ) - if self._prefer_binary: - binary_preference = 1 - pri = -(wheel.support_index_min(valid_tags)) - if wheel.build_tag is not None: - match = re.match(r'^(\d+)(.*)$', wheel.build_tag) - build_tag_groups = match.groups() - build_tag = (int(build_tag_groups[0]), build_tag_groups[1]) - else: # sdist - pri = -(support_num) - has_allowed_hash = int(link.is_hash_allowed(self._hashes)) - yank_value = -1 * int(link.is_yanked) # -1 for yanked. - return ( - has_allowed_hash, yank_value, binary_preference, candidate.version, - build_tag, pri, - ) - - def sort_best_candidate( - self, - candidates, # type: List[InstallationCandidate] - ): - # type: (...) -> Optional[InstallationCandidate] - """ - Return the best candidate per the instance's sort order, or None if - no candidate is acceptable. - """ - if not candidates: - return None - - best_candidate = max(candidates, key=self._sort_key) - - # Log a warning per PEP 592 if necessary before returning. - link = best_candidate.link - if link.is_yanked: - reason = link.yanked_reason or '<none given>' - msg = ( - # Mark this as a unicode string to prevent - # "UnicodeEncodeError: 'ascii' codec can't encode character" - # in Python 2 when the reason contains non-ascii characters. - u'The candidate selected for download or install is a ' - 'yanked version: {candidate}\n' - 'Reason for being yanked: {reason}' - ).format(candidate=best_candidate, reason=reason) - logger.warning(msg) - - return best_candidate - - def compute_best_candidate( - self, - candidates, # type: List[InstallationCandidate] - ): - # type: (...) -> BestCandidateResult - """ - Compute and return a `BestCandidateResult` instance. - """ - applicable_candidates = self.get_applicable_candidates(candidates) - - best_candidate = self.sort_best_candidate(applicable_candidates) - - return BestCandidateResult( - candidates, - applicable_candidates=applicable_candidates, - best_candidate=best_candidate, - ) - - -class PackageFinder(object): - """This finds packages. - - This is meant to match easy_install's technique for looking for - packages, by reading pages and looking for appropriate links. - """ - - def __init__( - self, - link_collector, # type: LinkCollector - target_python, # type: TargetPython - allow_yanked, # type: bool - format_control=None, # type: Optional[FormatControl] - candidate_prefs=None, # type: CandidatePreferences - ignore_requires_python=None, # type: Optional[bool] - ): - # type: (...) -> None - """ - This constructor is primarily meant to be used by the create() class - method and from tests. - - :param format_control: A FormatControl object, used to control - the selection of source packages / binary packages when consulting - the index and links. - :param candidate_prefs: Options to use when creating a - CandidateEvaluator object. - """ - if candidate_prefs is None: - candidate_prefs = CandidatePreferences() - - format_control = format_control or FormatControl(set(), set()) - - self._allow_yanked = allow_yanked - self._candidate_prefs = candidate_prefs - self._ignore_requires_python = ignore_requires_python - self._link_collector = link_collector - self._target_python = target_python - - self.format_control = format_control - - # These are boring links that have already been logged somehow. - self._logged_links = set() # type: Set[Link] - - # Don't include an allow_yanked default value to make sure each call - # site considers whether yanked releases are allowed. This also causes - # that decision to be made explicit in the calling code, which helps - # people when reading the code. - @classmethod - def create( - cls, - link_collector, # type: LinkCollector - selection_prefs, # type: SelectionPreferences - target_python=None, # type: Optional[TargetPython] - ): - # type: (...) -> PackageFinder - """Create a PackageFinder. - - :param selection_prefs: The candidate selection preferences, as a - SelectionPreferences object. - :param target_python: The target Python interpreter to use when - checking compatibility. If None (the default), a TargetPython - object will be constructed from the running Python. - """ - if target_python is None: - target_python = TargetPython() - - candidate_prefs = CandidatePreferences( - prefer_binary=selection_prefs.prefer_binary, - allow_all_prereleases=selection_prefs.allow_all_prereleases, - ) - - return cls( - candidate_prefs=candidate_prefs, - link_collector=link_collector, - target_python=target_python, - allow_yanked=selection_prefs.allow_yanked, - format_control=selection_prefs.format_control, - ignore_requires_python=selection_prefs.ignore_requires_python, - ) - - @property - def search_scope(self): - # type: () -> SearchScope - return self._link_collector.search_scope - - @search_scope.setter - def search_scope(self, search_scope): - # type: (SearchScope) -> None - self._link_collector.search_scope = search_scope - - @property - def find_links(self): - # type: () -> List[str] - return self._link_collector.find_links - - @property - def index_urls(self): - # type: () -> List[str] - return self.search_scope.index_urls - - @property - def trusted_hosts(self): - # type: () -> Iterable[str] - for host_port in self._link_collector.session.pip_trusted_origins: - yield build_netloc(*host_port) - - @property - def allow_all_prereleases(self): - # type: () -> bool - return self._candidate_prefs.allow_all_prereleases - - def set_allow_all_prereleases(self): - # type: () -> None - self._candidate_prefs.allow_all_prereleases = True - - def make_link_evaluator(self, project_name): - # type: (str) -> LinkEvaluator - canonical_name = canonicalize_name(project_name) - formats = self.format_control.get_allowed_formats(canonical_name) - - return LinkEvaluator( - project_name=project_name, - canonical_name=canonical_name, - formats=formats, - target_python=self._target_python, - allow_yanked=self._allow_yanked, - ignore_requires_python=self._ignore_requires_python, - ) - - def _sort_links(self, links): - # type: (Iterable[Link]) -> List[Link] - """ - Returns elements of links in order, non-egg links first, egg links - second, while eliminating duplicates - """ - eggs, no_eggs = [], [] - seen = set() # type: Set[Link] - for link in links: - if link not in seen: - seen.add(link) - if link.egg_fragment: - eggs.append(link) - else: - no_eggs.append(link) - return no_eggs + eggs - - def _log_skipped_link(self, link, reason): - # type: (Link, Text) -> None - if link not in self._logged_links: - # Mark this as a unicode string to prevent "UnicodeEncodeError: - # 'ascii' codec can't encode character" in Python 2 when - # the reason contains non-ascii characters. - # Also, put the link at the end so the reason is more visible - # and because the link string is usually very long. - logger.debug(u'Skipping link: %s: %s', reason, link) - self._logged_links.add(link) - - def get_install_candidate(self, link_evaluator, link): - # type: (LinkEvaluator, Link) -> Optional[InstallationCandidate] - """ - If the link is a candidate for install, convert it to an - InstallationCandidate and return it. Otherwise, return None. - """ - is_candidate, result = link_evaluator.evaluate_link(link) - if not is_candidate: - if result: - self._log_skipped_link(link, reason=result) - return None - - return InstallationCandidate( - name=link_evaluator.project_name, - link=link, - # Convert the Text result to str since InstallationCandidate - # accepts str. - version=str(result), - ) - - def evaluate_links(self, link_evaluator, links): - # type: (LinkEvaluator, Iterable[Link]) -> List[InstallationCandidate] - """ - Convert links that are candidates to InstallationCandidate objects. - """ - candidates = [] - for link in self._sort_links(links): - candidate = self.get_install_candidate(link_evaluator, link) - if candidate is not None: - candidates.append(candidate) - - return candidates - - def process_project_url(self, project_url, link_evaluator): - # type: (Link, LinkEvaluator) -> List[InstallationCandidate] - logger.debug( - 'Fetching project page and analyzing links: %s', project_url, - ) - html_page = self._link_collector.fetch_page(project_url) - if html_page is None: - return [] - - page_links = list(parse_links(html_page)) - - with indent_log(): - package_links = self.evaluate_links( - link_evaluator, - links=page_links, - ) - - return package_links - - def find_all_candidates(self, project_name): - # type: (str) -> List[InstallationCandidate] - """Find all available InstallationCandidate for project_name - - This checks index_urls and find_links. - All versions found are returned as an InstallationCandidate list. - - See LinkEvaluator.evaluate_link() for details on which files - are accepted. - """ - collected_links = self._link_collector.collect_links(project_name) - - link_evaluator = self.make_link_evaluator(project_name) - - find_links_versions = self.evaluate_links( - link_evaluator, - links=collected_links.find_links, - ) - - page_versions = [] - for project_url in collected_links.project_urls: - package_links = self.process_project_url( - project_url, link_evaluator=link_evaluator, - ) - page_versions.extend(package_links) - - file_versions = self.evaluate_links( - link_evaluator, - links=collected_links.files, - ) - if file_versions: - file_versions.sort(reverse=True) - logger.debug( - 'Local files found: %s', - ', '.join([ - url_to_path(candidate.link.url) - for candidate in file_versions - ]) - ) - - # This is an intentional priority ordering - return file_versions + find_links_versions + page_versions - - def make_candidate_evaluator( - self, - project_name, # type: str - specifier=None, # type: Optional[specifiers.BaseSpecifier] - hashes=None, # type: Optional[Hashes] - ): - # type: (...) -> CandidateEvaluator - """Create a CandidateEvaluator object to use. - """ - candidate_prefs = self._candidate_prefs - return CandidateEvaluator.create( - project_name=project_name, - target_python=self._target_python, - prefer_binary=candidate_prefs.prefer_binary, - allow_all_prereleases=candidate_prefs.allow_all_prereleases, - specifier=specifier, - hashes=hashes, - ) - - def find_best_candidate( - self, - project_name, # type: str - specifier=None, # type: Optional[specifiers.BaseSpecifier] - hashes=None, # type: Optional[Hashes] - ): - # type: (...) -> BestCandidateResult - """Find matches for the given project and specifier. - - :param specifier: An optional object implementing `filter` - (e.g. `packaging.specifiers.SpecifierSet`) to filter applicable - versions. - - :return: A `BestCandidateResult` instance. - """ - candidates = self.find_all_candidates(project_name) - candidate_evaluator = self.make_candidate_evaluator( - project_name=project_name, - specifier=specifier, - hashes=hashes, - ) - return candidate_evaluator.compute_best_candidate(candidates) - - def find_requirement(self, req, upgrade): - # type: (InstallRequirement, bool) -> Optional[Link] - """Try to find a Link matching req - - Expects req, an InstallRequirement and upgrade, a boolean - Returns a Link if found, - Raises DistributionNotFound or BestVersionAlreadyInstalled otherwise - """ - hashes = req.hashes(trust_internet=False) - best_candidate_result = self.find_best_candidate( - req.name, specifier=req.specifier, hashes=hashes, - ) - best_candidate = best_candidate_result.best_candidate - - installed_version = None # type: Optional[_BaseVersion] - if req.satisfied_by is not None: - installed_version = parse_version(req.satisfied_by.version) - - def _format_versions(cand_iter): - # type: (Iterable[InstallationCandidate]) -> str - # This repeated parse_version and str() conversion is needed to - # handle different vendoring sources from pip and pkg_resources. - # If we stop using the pkg_resources provided specifier and start - # using our own, we can drop the cast to str(). - return ", ".join(sorted( - {str(c.version) for c in cand_iter}, - key=parse_version, - )) or "none" - - if installed_version is None and best_candidate is None: - logger.critical( - 'Could not find a version that satisfies the requirement %s ' - '(from versions: %s)', - req, - _format_versions(best_candidate_result.iter_all()), - ) - - raise DistributionNotFound( - 'No matching distribution found for {}'.format( - req) - ) - - best_installed = False - if installed_version and ( - best_candidate is None or - best_candidate.version <= installed_version): - best_installed = True - - if not upgrade and installed_version is not None: - if best_installed: - logger.debug( - 'Existing installed version (%s) is most up-to-date and ' - 'satisfies requirement', - installed_version, - ) - else: - logger.debug( - 'Existing installed version (%s) satisfies requirement ' - '(most up-to-date version is %s)', - installed_version, - best_candidate.version, - ) - return None - - if best_installed: - # We have an existing version, and its the best version - logger.debug( - 'Installed version (%s) is most up-to-date (past versions: ' - '%s)', - installed_version, - _format_versions(best_candidate_result.iter_applicable()), - ) - raise BestVersionAlreadyInstalled - - logger.debug( - 'Using version %s (newest of versions: %s)', - best_candidate.version, - _format_versions(best_candidate_result.iter_applicable()), - ) - return best_candidate.link - - -def _find_name_version_sep(fragment, canonical_name): - # type: (str, str) -> int - """Find the separator's index based on the package's canonical name. - - :param fragment: A <package>+<version> filename "fragment" (stem) or - egg fragment. - :param canonical_name: The package's canonical name. - - This function is needed since the canonicalized name does not necessarily - have the same length as the egg info's name part. An example:: - - >>> fragment = 'foo__bar-1.0' - >>> canonical_name = 'foo-bar' - >>> _find_name_version_sep(fragment, canonical_name) - 8 - """ - # Project name and version must be separated by one single dash. Find all - # occurrences of dashes; if the string in front of it matches the canonical - # name, this is the one separating the name and version parts. - for i, c in enumerate(fragment): - if c != "-": - continue - if canonicalize_name(fragment[:i]) == canonical_name: - return i - raise ValueError("{} does not match {}".format(fragment, canonical_name)) - - -def _extract_version_from_fragment(fragment, canonical_name): - # type: (str, str) -> Optional[str] - """Parse the version string from a <package>+<version> filename - "fragment" (stem) or egg fragment. - - :param fragment: The string to parse. E.g. foo-2.1 - :param canonical_name: The canonicalized name of the package this - belongs to. - """ - try: - version_start = _find_name_version_sep(fragment, canonical_name) + 1 - except ValueError: - return None - version = fragment[version_start:] - if not version: - return None - return version diff --git a/venv/lib/python3.8/site-packages/pip/_internal/locations.py b/venv/lib/python3.8/site-packages/pip/_internal/locations.py deleted file mode 100644 index 5dfcd73..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/locations.py +++ /dev/null @@ -1,200 +0,0 @@ -"""Locations where we look for configs, install stuff, etc""" - -# The following comment should be removed at some point in the future. -# mypy: strict-optional=False - -from __future__ import absolute_import - -import os -import os.path -import platform -import site -import sys -import sysconfig -from distutils import sysconfig as distutils_sysconfig -from distutils.command.install import SCHEME_KEYS # type: ignore -from distutils.command.install import install as distutils_install_command - -from pip._internal.models.scheme import Scheme -from pip._internal.utils import appdirs -from pip._internal.utils.compat import WINDOWS -from pip._internal.utils.typing import MYPY_CHECK_RUNNING, cast -from pip._internal.utils.virtualenv import running_under_virtualenv - -if MYPY_CHECK_RUNNING: - from typing import Dict, List, Optional, Union - - from distutils.cmd import Command as DistutilsCommand - - -# Application Directories -USER_CACHE_DIR = appdirs.user_cache_dir("pip") - - -def get_major_minor_version(): - # type: () -> str - """ - Return the major-minor version of the current Python as a string, e.g. - "3.7" or "3.10". - """ - return '{}.{}'.format(*sys.version_info) - - -def get_src_prefix(): - # type: () -> str - if running_under_virtualenv(): - src_prefix = os.path.join(sys.prefix, 'src') - else: - # FIXME: keep src in cwd for now (it is not a temporary folder) - try: - src_prefix = os.path.join(os.getcwd(), 'src') - except OSError: - # In case the current working directory has been renamed or deleted - sys.exit( - "The folder you are executing pip from can no longer be found." - ) - - # under macOS + virtualenv sys.prefix is not properly resolved - # it is something like /path/to/python/bin/.. - return os.path.abspath(src_prefix) - - -# FIXME doesn't account for venv linked to global site-packages - -# The python2.7 part of this is Debian specific: -# https://github.com/pypa/pip/issues/5193 -# https://bitbucket.org/pypy/pypy/issues/2506/sysconfig-returns-incorrect-paths -can_not_depend_on_purelib = ( - sys.version_info[:2] == (2, 7) or - platform.python_implementation().lower() == "pypy" -) -site_packages = None # type: Optional[str] -if can_not_depend_on_purelib: - site_packages = distutils_sysconfig.get_python_lib() -else: - site_packages = sysconfig.get_path("purelib") - -try: - # Use getusersitepackages if this is present, as it ensures that the - # value is initialised properly. - user_site = site.getusersitepackages() -except AttributeError: - user_site = site.USER_SITE - -if WINDOWS: - bin_py = os.path.join(sys.prefix, 'Scripts') - bin_user = os.path.join(user_site, 'Scripts') - # buildout uses 'bin' on Windows too? - if not os.path.exists(bin_py): - bin_py = os.path.join(sys.prefix, 'bin') - bin_user = os.path.join(user_site, 'bin') -else: - bin_py = os.path.join(sys.prefix, 'bin') - bin_user = os.path.join(user_site, 'bin') - - # Forcing to use /usr/local/bin for standard macOS framework installs - # Also log to ~/Library/Logs/ for use with the Console.app log viewer - if sys.platform[:6] == 'darwin' and sys.prefix[:16] == '/System/Library/': - bin_py = '/usr/local/bin' - - -def distutils_scheme( - dist_name, user=False, home=None, root=None, isolated=False, prefix=None -): - # type:(str, bool, str, str, bool, str) -> Dict[str, str] - """ - Return a distutils install scheme - """ - from distutils.dist import Distribution - - dist_args = {'name': dist_name} # type: Dict[str, Union[str, List[str]]] - if isolated: - dist_args["script_args"] = ["--no-user-cfg"] - - d = Distribution(dist_args) - d.parse_config_files() - obj = None # type: Optional[DistutilsCommand] - obj = d.get_command_obj('install', create=True) - assert obj is not None - i = cast(distutils_install_command, obj) - # NOTE: setting user or home has the side-effect of creating the home dir - # or user base for installations during finalize_options() - # ideally, we'd prefer a scheme class that has no side-effects. - assert not (user and prefix), "user={} prefix={}".format(user, prefix) - assert not (home and prefix), "home={} prefix={}".format(home, prefix) - i.user = user or i.user - if user or home: - i.prefix = "" - i.prefix = prefix or i.prefix - i.home = home or i.home - i.root = root or i.root - i.finalize_options() - - scheme = {} - for key in SCHEME_KEYS: - scheme[key] = getattr(i, 'install_' + key) - - # install_lib specified in setup.cfg should install *everything* - # into there (i.e. it takes precedence over both purelib and - # platlib). Note, i.install_lib is *always* set after - # finalize_options(); we only want to override here if the user - # has explicitly requested it hence going back to the config - if 'install_lib' in d.get_option_dict('install'): - scheme.update(dict(purelib=i.install_lib, platlib=i.install_lib)) - - if running_under_virtualenv(): - scheme['headers'] = os.path.join( - sys.prefix, - 'include', - 'site', - 'python{}'.format(get_major_minor_version()), - dist_name, - ) - - if root is not None: - path_no_drive = os.path.splitdrive( - os.path.abspath(scheme["headers"]))[1] - scheme["headers"] = os.path.join( - root, - path_no_drive[1:], - ) - - return scheme - - -def get_scheme( - dist_name, # type: str - user=False, # type: bool - home=None, # type: Optional[str] - root=None, # type: Optional[str] - isolated=False, # type: bool - prefix=None, # type: Optional[str] -): - # type: (...) -> Scheme - """ - Get the "scheme" corresponding to the input parameters. The distutils - documentation provides the context for the available schemes: - https://docs.python.org/3/install/index.html#alternate-installation - - :param dist_name: the name of the package to retrieve the scheme for, used - in the headers scheme path - :param user: indicates to use the "user" scheme - :param home: indicates to use the "home" scheme and provides the base - directory for the same - :param root: root under which other directories are re-based - :param isolated: equivalent to --no-user-cfg, i.e. do not consider - ~/.pydistutils.cfg (posix) or ~/pydistutils.cfg (non-posix) for - scheme paths - :param prefix: indicates to use the "prefix" scheme and provides the - base directory for the same - """ - scheme = distutils_scheme( - dist_name, user, home, root, isolated, prefix - ) - return Scheme( - platlib=scheme["platlib"], - purelib=scheme["purelib"], - headers=scheme["headers"], - scripts=scheme["scripts"], - data=scheme["data"], - ) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/main.py b/venv/lib/python3.8/site-packages/pip/_internal/main.py deleted file mode 100644 index 3208d5b..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/main.py +++ /dev/null @@ -1,16 +0,0 @@ -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import Optional, List - - -def main(args=None): - # type: (Optional[List[str]]) -> int - """This is preserved for old console scripts that may still be referencing - it. - - For additional details, see https://github.com/pypa/pip/issues/7498. - """ - from pip._internal.utils.entrypoints import _wrapper - - return _wrapper(args) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/models/__init__.py b/venv/lib/python3.8/site-packages/pip/_internal/models/__init__.py deleted file mode 100644 index 7855226..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/models/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -"""A package that contains models that represent entities. -""" diff --git a/venv/lib/python3.8/site-packages/pip/_internal/models/candidate.py b/venv/lib/python3.8/site-packages/pip/_internal/models/candidate.py deleted file mode 100644 index 1dc1a57..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/models/candidate.py +++ /dev/null @@ -1,36 +0,0 @@ -from pip._vendor.packaging.version import parse as parse_version - -from pip._internal.utils.models import KeyBasedCompareMixin -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from pip._vendor.packaging.version import _BaseVersion - from pip._internal.models.link import Link - - -class InstallationCandidate(KeyBasedCompareMixin): - """Represents a potential "candidate" for installation. - """ - - def __init__(self, name, version, link): - # type: (str, str, Link) -> None - self.name = name - self.version = parse_version(version) # type: _BaseVersion - self.link = link - - super(InstallationCandidate, self).__init__( - key=(self.name, self.version, self.link), - defining_class=InstallationCandidate - ) - - def __repr__(self): - # type: () -> str - return "<InstallationCandidate({!r}, {!r}, {!r})>".format( - self.name, self.version, self.link, - ) - - def __str__(self): - # type: () -> str - return '{!r} candidate (version {} at {})'.format( - self.name, self.version, self.link, - ) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/models/direct_url.py b/venv/lib/python3.8/site-packages/pip/_internal/models/direct_url.py deleted file mode 100644 index 87bd9fe..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/models/direct_url.py +++ /dev/null @@ -1,245 +0,0 @@ -""" PEP 610 """ -import json -import re - -from pip._vendor import six -from pip._vendor.six.moves.urllib import parse as urllib_parse - -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import ( - Any, Dict, Iterable, Optional, Type, TypeVar, Union - ) - - T = TypeVar("T") - - -DIRECT_URL_METADATA_NAME = "direct_url.json" -ENV_VAR_RE = re.compile(r"^\$\{[A-Za-z0-9-_]+\}(:\$\{[A-Za-z0-9-_]+\})?$") - -__all__ = [ - "DirectUrl", - "DirectUrlValidationError", - "DirInfo", - "ArchiveInfo", - "VcsInfo", -] - - -class DirectUrlValidationError(Exception): - pass - - -def _get(d, expected_type, key, default=None): - # type: (Dict[str, Any], Type[T], str, Optional[T]) -> Optional[T] - """Get value from dictionary and verify expected type.""" - if key not in d: - return default - value = d[key] - if six.PY2 and expected_type is str: - expected_type = six.string_types # type: ignore - if not isinstance(value, expected_type): - raise DirectUrlValidationError( - "{!r} has unexpected type for {} (expected {})".format( - value, key, expected_type - ) - ) - return value - - -def _get_required(d, expected_type, key, default=None): - # type: (Dict[str, Any], Type[T], str, Optional[T]) -> T - value = _get(d, expected_type, key, default) - if value is None: - raise DirectUrlValidationError("{} must have a value".format(key)) - return value - - -def _exactly_one_of(infos): - # type: (Iterable[Optional[InfoType]]) -> InfoType - infos = [info for info in infos if info is not None] - if not infos: - raise DirectUrlValidationError( - "missing one of archive_info, dir_info, vcs_info" - ) - if len(infos) > 1: - raise DirectUrlValidationError( - "more than one of archive_info, dir_info, vcs_info" - ) - assert infos[0] is not None - return infos[0] - - -def _filter_none(**kwargs): - # type: (Any) -> Dict[str, Any] - """Make dict excluding None values.""" - return {k: v for k, v in kwargs.items() if v is not None} - - -class VcsInfo(object): - name = "vcs_info" - - def __init__( - self, - vcs, # type: str - commit_id, # type: str - requested_revision=None, # type: Optional[str] - resolved_revision=None, # type: Optional[str] - resolved_revision_type=None, # type: Optional[str] - ): - self.vcs = vcs - self.requested_revision = requested_revision - self.commit_id = commit_id - self.resolved_revision = resolved_revision - self.resolved_revision_type = resolved_revision_type - - @classmethod - def _from_dict(cls, d): - # type: (Optional[Dict[str, Any]]) -> Optional[VcsInfo] - if d is None: - return None - return cls( - vcs=_get_required(d, str, "vcs"), - commit_id=_get_required(d, str, "commit_id"), - requested_revision=_get(d, str, "requested_revision"), - resolved_revision=_get(d, str, "resolved_revision"), - resolved_revision_type=_get(d, str, "resolved_revision_type"), - ) - - def _to_dict(self): - # type: () -> Dict[str, Any] - return _filter_none( - vcs=self.vcs, - requested_revision=self.requested_revision, - commit_id=self.commit_id, - resolved_revision=self.resolved_revision, - resolved_revision_type=self.resolved_revision_type, - ) - - -class ArchiveInfo(object): - name = "archive_info" - - def __init__( - self, - hash=None, # type: Optional[str] - ): - self.hash = hash - - @classmethod - def _from_dict(cls, d): - # type: (Optional[Dict[str, Any]]) -> Optional[ArchiveInfo] - if d is None: - return None - return cls(hash=_get(d, str, "hash")) - - def _to_dict(self): - # type: () -> Dict[str, Any] - return _filter_none(hash=self.hash) - - -class DirInfo(object): - name = "dir_info" - - def __init__( - self, - editable=False, # type: bool - ): - self.editable = editable - - @classmethod - def _from_dict(cls, d): - # type: (Optional[Dict[str, Any]]) -> Optional[DirInfo] - if d is None: - return None - return cls( - editable=_get_required(d, bool, "editable", default=False) - ) - - def _to_dict(self): - # type: () -> Dict[str, Any] - return _filter_none(editable=self.editable or None) - - -if MYPY_CHECK_RUNNING: - InfoType = Union[ArchiveInfo, DirInfo, VcsInfo] - - -class DirectUrl(object): - - def __init__( - self, - url, # type: str - info, # type: InfoType - subdirectory=None, # type: Optional[str] - ): - self.url = url - self.info = info - self.subdirectory = subdirectory - - def _remove_auth_from_netloc(self, netloc): - # type: (str) -> str - if "@" not in netloc: - return netloc - user_pass, netloc_no_user_pass = netloc.split("@", 1) - if ( - isinstance(self.info, VcsInfo) and - self.info.vcs == "git" and - user_pass == "git" - ): - return netloc - if ENV_VAR_RE.match(user_pass): - return netloc - return netloc_no_user_pass - - @property - def redacted_url(self): - # type: () -> str - """url with user:password part removed unless it is formed with - environment variables as specified in PEP 610, or it is ``git`` - in the case of a git URL. - """ - purl = urllib_parse.urlsplit(self.url) - netloc = self._remove_auth_from_netloc(purl.netloc) - surl = urllib_parse.urlunsplit( - (purl.scheme, netloc, purl.path, purl.query, purl.fragment) - ) - return surl - - def validate(self): - # type: () -> None - self.from_dict(self.to_dict()) - - @classmethod - def from_dict(cls, d): - # type: (Dict[str, Any]) -> DirectUrl - return DirectUrl( - url=_get_required(d, str, "url"), - subdirectory=_get(d, str, "subdirectory"), - info=_exactly_one_of( - [ - ArchiveInfo._from_dict(_get(d, dict, "archive_info")), - DirInfo._from_dict(_get(d, dict, "dir_info")), - VcsInfo._from_dict(_get(d, dict, "vcs_info")), - ] - ), - ) - - def to_dict(self): - # type: () -> Dict[str, Any] - res = _filter_none( - url=self.redacted_url, - subdirectory=self.subdirectory, - ) - res[self.info.name] = self.info._to_dict() - return res - - @classmethod - def from_json(cls, s): - # type: (str) -> DirectUrl - return cls.from_dict(json.loads(s)) - - def to_json(self): - # type: () -> str - return json.dumps(self.to_dict(), sort_keys=True) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/models/format_control.py b/venv/lib/python3.8/site-packages/pip/_internal/models/format_control.py deleted file mode 100644 index 2e13727..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/models/format_control.py +++ /dev/null @@ -1,84 +0,0 @@ -# The following comment should be removed at some point in the future. -# mypy: strict-optional=False - -from pip._vendor.packaging.utils import canonicalize_name - -from pip._internal.exceptions import CommandError -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import Optional, Set, FrozenSet - - -class FormatControl(object): - """Helper for managing formats from which a package can be installed. - """ - - def __init__(self, no_binary=None, only_binary=None): - # type: (Optional[Set[str]], Optional[Set[str]]) -> None - if no_binary is None: - no_binary = set() - if only_binary is None: - only_binary = set() - - self.no_binary = no_binary - self.only_binary = only_binary - - def __eq__(self, other): - # type: (object) -> bool - return self.__dict__ == other.__dict__ - - def __ne__(self, other): - # type: (object) -> bool - return not self.__eq__(other) - - def __repr__(self): - # type: () -> str - return "{}({}, {})".format( - self.__class__.__name__, - self.no_binary, - self.only_binary - ) - - @staticmethod - def handle_mutual_excludes(value, target, other): - # type: (str, Optional[Set[str]], Optional[Set[str]]) -> None - if value.startswith('-'): - raise CommandError( - "--no-binary / --only-binary option requires 1 argument." - ) - new = value.split(',') - while ':all:' in new: - other.clear() - target.clear() - target.add(':all:') - del new[:new.index(':all:') + 1] - # Without a none, we want to discard everything as :all: covers it - if ':none:' not in new: - return - for name in new: - if name == ':none:': - target.clear() - continue - name = canonicalize_name(name) - other.discard(name) - target.add(name) - - def get_allowed_formats(self, canonical_name): - # type: (str) -> FrozenSet[str] - result = {"binary", "source"} - if canonical_name in self.only_binary: - result.discard('source') - elif canonical_name in self.no_binary: - result.discard('binary') - elif ':all:' in self.only_binary: - result.discard('source') - elif ':all:' in self.no_binary: - result.discard('binary') - return frozenset(result) - - def disallow_binaries(self): - # type: () -> None - self.handle_mutual_excludes( - ':all:', self.no_binary, self.only_binary, - ) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/models/index.py b/venv/lib/python3.8/site-packages/pip/_internal/models/index.py deleted file mode 100644 index ead1efb..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/models/index.py +++ /dev/null @@ -1,31 +0,0 @@ -from pip._vendor.six.moves.urllib import parse as urllib_parse - - -class PackageIndex(object): - """Represents a Package Index and provides easier access to endpoints - """ - - def __init__(self, url, file_storage_domain): - # type: (str, str) -> None - super(PackageIndex, self).__init__() - self.url = url - self.netloc = urllib_parse.urlsplit(url).netloc - self.simple_url = self._url_for_path('simple') - self.pypi_url = self._url_for_path('pypi') - - # This is part of a temporary hack used to block installs of PyPI - # packages which depend on external urls only necessary until PyPI can - # block such packages themselves - self.file_storage_domain = file_storage_domain - - def _url_for_path(self, path): - # type: (str) -> str - return urllib_parse.urljoin(self.url, path) - - -PyPI = PackageIndex( - 'https://pypi.org/', file_storage_domain='files.pythonhosted.org' -) -TestPyPI = PackageIndex( - 'https://test.pypi.org/', file_storage_domain='test-files.pythonhosted.org' -) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/models/link.py b/venv/lib/python3.8/site-packages/pip/_internal/models/link.py deleted file mode 100644 index df4f8f0..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/models/link.py +++ /dev/null @@ -1,236 +0,0 @@ -import os -import posixpath -import re - -from pip._vendor.six.moves.urllib import parse as urllib_parse - -from pip._internal.utils.filetypes import WHEEL_EXTENSION -from pip._internal.utils.misc import ( - redact_auth_from_url, - split_auth_from_netloc, - splitext, -) -from pip._internal.utils.models import KeyBasedCompareMixin -from pip._internal.utils.typing import MYPY_CHECK_RUNNING -from pip._internal.utils.urls import path_to_url, url_to_path - -if MYPY_CHECK_RUNNING: - from typing import Optional, Text, Tuple, Union - from pip._internal.index.collector import HTMLPage - from pip._internal.utils.hashes import Hashes - - -class Link(KeyBasedCompareMixin): - """Represents a parsed link from a Package Index's simple URL - """ - - def __init__( - self, - url, # type: str - comes_from=None, # type: Optional[Union[str, HTMLPage]] - requires_python=None, # type: Optional[str] - yanked_reason=None, # type: Optional[Text] - cache_link_parsing=True, # type: bool - ): - # type: (...) -> None - """ - :param url: url of the resource pointed to (href of the link) - :param comes_from: instance of HTMLPage where the link was found, - or string. - :param requires_python: String containing the `Requires-Python` - metadata field, specified in PEP 345. This may be specified by - a data-requires-python attribute in the HTML link tag, as - described in PEP 503. - :param yanked_reason: the reason the file has been yanked, if the - file has been yanked, or None if the file hasn't been yanked. - This is the value of the "data-yanked" attribute, if present, in - a simple repository HTML link. If the file has been yanked but - no reason was provided, this should be the empty string. See - PEP 592 for more information and the specification. - :param cache_link_parsing: A flag that is used elsewhere to determine - whether resources retrieved from this link - should be cached. PyPI index urls should - generally have this set to False, for - example. - """ - - # url can be a UNC windows share - if url.startswith('\\\\'): - url = path_to_url(url) - - self._parsed_url = urllib_parse.urlsplit(url) - # Store the url as a private attribute to prevent accidentally - # trying to set a new value. - self._url = url - - self.comes_from = comes_from - self.requires_python = requires_python if requires_python else None - self.yanked_reason = yanked_reason - - super(Link, self).__init__(key=url, defining_class=Link) - - self.cache_link_parsing = cache_link_parsing - - def __str__(self): - # type: () -> str - if self.requires_python: - rp = ' (requires-python:{})'.format(self.requires_python) - else: - rp = '' - if self.comes_from: - return '{} (from {}){}'.format( - redact_auth_from_url(self._url), self.comes_from, rp) - else: - return redact_auth_from_url(str(self._url)) - - def __repr__(self): - # type: () -> str - return '<Link {}>'.format(self) - - @property - def url(self): - # type: () -> str - return self._url - - @property - def filename(self): - # type: () -> str - path = self.path.rstrip('/') - name = posixpath.basename(path) - if not name: - # Make sure we don't leak auth information if the netloc - # includes a username and password. - netloc, user_pass = split_auth_from_netloc(self.netloc) - return netloc - - name = urllib_parse.unquote(name) - assert name, ( - 'URL {self._url!r} produced no filename'.format(**locals())) - return name - - @property - def file_path(self): - # type: () -> str - return url_to_path(self.url) - - @property - def scheme(self): - # type: () -> str - return self._parsed_url.scheme - - @property - def netloc(self): - # type: () -> str - """ - This can contain auth information. - """ - return self._parsed_url.netloc - - @property - def path(self): - # type: () -> str - return urllib_parse.unquote(self._parsed_url.path) - - def splitext(self): - # type: () -> Tuple[str, str] - return splitext(posixpath.basename(self.path.rstrip('/'))) - - @property - def ext(self): - # type: () -> str - return self.splitext()[1] - - @property - def url_without_fragment(self): - # type: () -> str - scheme, netloc, path, query, fragment = self._parsed_url - return urllib_parse.urlunsplit((scheme, netloc, path, query, None)) - - _egg_fragment_re = re.compile(r'[#&]egg=([^&]*)') - - @property - def egg_fragment(self): - # type: () -> Optional[str] - match = self._egg_fragment_re.search(self._url) - if not match: - return None - return match.group(1) - - _subdirectory_fragment_re = re.compile(r'[#&]subdirectory=([^&]*)') - - @property - def subdirectory_fragment(self): - # type: () -> Optional[str] - match = self._subdirectory_fragment_re.search(self._url) - if not match: - return None - return match.group(1) - - _hash_re = re.compile( - r'(sha1|sha224|sha384|sha256|sha512|md5)=([a-f0-9]+)' - ) - - @property - def hash(self): - # type: () -> Optional[str] - match = self._hash_re.search(self._url) - if match: - return match.group(2) - return None - - @property - def hash_name(self): - # type: () -> Optional[str] - match = self._hash_re.search(self._url) - if match: - return match.group(1) - return None - - @property - def show_url(self): - # type: () -> str - return posixpath.basename(self._url.split('#', 1)[0].split('?', 1)[0]) - - @property - def is_file(self): - # type: () -> bool - return self.scheme == 'file' - - def is_existing_dir(self): - # type: () -> bool - return self.is_file and os.path.isdir(self.file_path) - - @property - def is_wheel(self): - # type: () -> bool - return self.ext == WHEEL_EXTENSION - - @property - def is_vcs(self): - # type: () -> bool - from pip._internal.vcs import vcs - - return self.scheme in vcs.all_schemes - - @property - def is_yanked(self): - # type: () -> bool - return self.yanked_reason is not None - - @property - def has_hash(self): - # type: () -> bool - return self.hash_name is not None - - def is_hash_allowed(self, hashes): - # type: (Optional[Hashes]) -> bool - """ - Return True if the link has a hash and it is allowed. - """ - if hashes is None or not self.has_hash: - return False - # Assert non-None so mypy knows self.hash_name and self.hash are str. - assert self.hash_name is not None - assert self.hash is not None - - return hashes.is_hash_allowed(self.hash_name, hex_digest=self.hash) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/models/scheme.py b/venv/lib/python3.8/site-packages/pip/_internal/models/scheme.py deleted file mode 100644 index af07b40..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/models/scheme.py +++ /dev/null @@ -1,25 +0,0 @@ -""" -For types associated with installation schemes. - -For a general overview of available schemes and their context, see -https://docs.python.org/3/install/index.html#alternate-installation. -""" - - -class Scheme(object): - """A Scheme holds paths which are used as the base directories for - artifacts associated with a Python package. - """ - def __init__( - self, - platlib, # type: str - purelib, # type: str - headers, # type: str - scripts, # type: str - data, # type: str - ): - self.platlib = platlib - self.purelib = purelib - self.headers = headers - self.scripts = scripts - self.data = data diff --git a/venv/lib/python3.8/site-packages/pip/_internal/models/search_scope.py b/venv/lib/python3.8/site-packages/pip/_internal/models/search_scope.py deleted file mode 100644 index 7a0008e..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/models/search_scope.py +++ /dev/null @@ -1,133 +0,0 @@ -import itertools -import logging -import os -import posixpath - -from pip._vendor.packaging.utils import canonicalize_name -from pip._vendor.six.moves.urllib import parse as urllib_parse - -from pip._internal.models.index import PyPI -from pip._internal.utils.compat import has_tls -from pip._internal.utils.misc import normalize_path, redact_auth_from_url -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import List - - -logger = logging.getLogger(__name__) - - -class SearchScope(object): - - """ - Encapsulates the locations that pip is configured to search. - """ - - @classmethod - def create( - cls, - find_links, # type: List[str] - index_urls, # type: List[str] - ): - # type: (...) -> SearchScope - """ - Create a SearchScope object after normalizing the `find_links`. - """ - # Build find_links. If an argument starts with ~, it may be - # a local file relative to a home directory. So try normalizing - # it and if it exists, use the normalized version. - # This is deliberately conservative - it might be fine just to - # blindly normalize anything starting with a ~... - built_find_links = [] # type: List[str] - for link in find_links: - if link.startswith('~'): - new_link = normalize_path(link) - if os.path.exists(new_link): - link = new_link - built_find_links.append(link) - - # If we don't have TLS enabled, then WARN if anyplace we're looking - # relies on TLS. - if not has_tls(): - for link in itertools.chain(index_urls, built_find_links): - parsed = urllib_parse.urlparse(link) - if parsed.scheme == 'https': - logger.warning( - 'pip is configured with locations that require ' - 'TLS/SSL, however the ssl module in Python is not ' - 'available.' - ) - break - - return cls( - find_links=built_find_links, - index_urls=index_urls, - ) - - def __init__( - self, - find_links, # type: List[str] - index_urls, # type: List[str] - ): - # type: (...) -> None - self.find_links = find_links - self.index_urls = index_urls - - def get_formatted_locations(self): - # type: () -> str - lines = [] - redacted_index_urls = [] - if self.index_urls and self.index_urls != [PyPI.simple_url]: - for url in self.index_urls: - - redacted_index_url = redact_auth_from_url(url) - - # Parse the URL - purl = urllib_parse.urlsplit(redacted_index_url) - - # URL is generally invalid if scheme and netloc is missing - # there are issues with Python and URL parsing, so this test - # is a bit crude. See bpo-20271, bpo-23505. Python doesn't - # always parse invalid URLs correctly - it should raise - # exceptions for malformed URLs - if not purl.scheme and not purl.netloc: - logger.warning( - 'The index url "{}" seems invalid, ' - 'please provide a scheme.'.format(redacted_index_url)) - - redacted_index_urls.append(redacted_index_url) - - lines.append('Looking in indexes: {}'.format( - ', '.join(redacted_index_urls))) - - if self.find_links: - lines.append( - 'Looking in links: {}'.format(', '.join( - redact_auth_from_url(url) for url in self.find_links)) - ) - return '\n'.join(lines) - - def get_index_urls_locations(self, project_name): - # type: (str) -> List[str] - """Returns the locations found via self.index_urls - - Checks the url_name on the main (first in the list) index and - use this url_name to produce all locations - """ - - def mkurl_pypi_url(url): - # type: (str) -> str - loc = posixpath.join( - url, - urllib_parse.quote(canonicalize_name(project_name))) - # For maximum compatibility with easy_install, ensure the path - # ends in a trailing slash. Although this isn't in the spec - # (and PyPI can handle it without the slash) some other index - # implementations might break if they relied on easy_install's - # behavior. - if not loc.endswith('/'): - loc = loc + '/' - return loc - - return [mkurl_pypi_url(url) for url in self.index_urls] diff --git a/venv/lib/python3.8/site-packages/pip/_internal/models/selection_prefs.py b/venv/lib/python3.8/site-packages/pip/_internal/models/selection_prefs.py deleted file mode 100644 index f58fdce..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/models/selection_prefs.py +++ /dev/null @@ -1,47 +0,0 @@ -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import Optional - from pip._internal.models.format_control import FormatControl - - -class SelectionPreferences(object): - - """ - Encapsulates the candidate selection preferences for downloading - and installing files. - """ - - # Don't include an allow_yanked default value to make sure each call - # site considers whether yanked releases are allowed. This also causes - # that decision to be made explicit in the calling code, which helps - # people when reading the code. - def __init__( - self, - allow_yanked, # type: bool - allow_all_prereleases=False, # type: bool - format_control=None, # type: Optional[FormatControl] - prefer_binary=False, # type: bool - ignore_requires_python=None, # type: Optional[bool] - ): - # type: (...) -> None - """Create a SelectionPreferences object. - - :param allow_yanked: Whether files marked as yanked (in the sense - of PEP 592) are permitted to be candidates for install. - :param format_control: A FormatControl object or None. Used to control - the selection of source packages / binary packages when consulting - the index and links. - :param prefer_binary: Whether to prefer an old, but valid, binary - dist over a new source dist. - :param ignore_requires_python: Whether to ignore incompatible - "Requires-Python" values in links. Defaults to False. - """ - if ignore_requires_python is None: - ignore_requires_python = False - - self.allow_yanked = allow_yanked - self.allow_all_prereleases = allow_all_prereleases - self.format_control = format_control - self.prefer_binary = prefer_binary - self.ignore_requires_python = ignore_requires_python diff --git a/venv/lib/python3.8/site-packages/pip/_internal/models/target_python.py b/venv/lib/python3.8/site-packages/pip/_internal/models/target_python.py deleted file mode 100644 index 84f1c20..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/models/target_python.py +++ /dev/null @@ -1,110 +0,0 @@ -import sys - -from pip._internal.utils.compatibility_tags import ( - get_supported, - version_info_to_nodot, -) -from pip._internal.utils.misc import normalize_version_info -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import List, Optional, Tuple - - from pip._vendor.packaging.tags import Tag - - -class TargetPython(object): - - """ - Encapsulates the properties of a Python interpreter one is targeting - for a package install, download, etc. - """ - - def __init__( - self, - platform=None, # type: Optional[str] - py_version_info=None, # type: Optional[Tuple[int, ...]] - abi=None, # type: Optional[str] - implementation=None, # type: Optional[str] - ): - # type: (...) -> None - """ - :param platform: A string or None. If None, searches for packages - that are supported by the current system. Otherwise, will find - packages that can be built on the platform passed in. These - packages will only be downloaded for distribution: they will - not be built locally. - :param py_version_info: An optional tuple of ints representing the - Python version information to use (e.g. `sys.version_info[:3]`). - This can have length 1, 2, or 3 when provided. - :param abi: A string or None. This is passed to compatibility_tags.py's - get_supported() function as is. - :param implementation: A string or None. This is passed to - compatibility_tags.py's get_supported() function as is. - """ - # Store the given py_version_info for when we call get_supported(). - self._given_py_version_info = py_version_info - - if py_version_info is None: - py_version_info = sys.version_info[:3] - else: - py_version_info = normalize_version_info(py_version_info) - - py_version = '.'.join(map(str, py_version_info[:2])) - - self.abi = abi - self.implementation = implementation - self.platform = platform - self.py_version = py_version - self.py_version_info = py_version_info - - # This is used to cache the return value of get_tags(). - self._valid_tags = None # type: Optional[List[Tag]] - - def format_given(self): - # type: () -> str - """ - Format the given, non-None attributes for display. - """ - display_version = None - if self._given_py_version_info is not None: - display_version = '.'.join( - str(part) for part in self._given_py_version_info - ) - - key_values = [ - ('platform', self.platform), - ('version_info', display_version), - ('abi', self.abi), - ('implementation', self.implementation), - ] - return ' '.join( - '{}={!r}'.format(key, value) for key, value in key_values - if value is not None - ) - - def get_tags(self): - # type: () -> List[Tag] - """ - Return the supported PEP 425 tags to check wheel candidates against. - - The tags are returned in order of preference (most preferred first). - """ - if self._valid_tags is None: - # Pass versions=None if no py_version_info was given since - # versions=None uses special default logic. - py_version_info = self._given_py_version_info - if py_version_info is None: - version = None - else: - version = version_info_to_nodot(py_version_info) - - tags = get_supported( - version=version, - platform=self.platform, - abi=self.abi, - impl=self.implementation, - ) - self._valid_tags = tags - - return self._valid_tags diff --git a/venv/lib/python3.8/site-packages/pip/_internal/models/wheel.py b/venv/lib/python3.8/site-packages/pip/_internal/models/wheel.py deleted file mode 100644 index 4d4068f..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/models/wheel.py +++ /dev/null @@ -1,78 +0,0 @@ -"""Represents a wheel file and provides access to the various parts of the -name that have meaning. -""" -import re - -from pip._vendor.packaging.tags import Tag - -from pip._internal.exceptions import InvalidWheelFilename -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import List - - -class Wheel(object): - """A wheel file""" - - wheel_file_re = re.compile( - r"""^(?P<namever>(?P<name>.+?)-(?P<ver>.*?)) - ((-(?P<build>\d[^-]*?))?-(?P<pyver>.+?)-(?P<abi>.+?)-(?P<plat>.+?) - \.whl|\.dist-info)$""", - re.VERBOSE - ) - - def __init__(self, filename): - # type: (str) -> None - """ - :raises InvalidWheelFilename: when the filename is invalid for a wheel - """ - wheel_info = self.wheel_file_re.match(filename) - if not wheel_info: - raise InvalidWheelFilename( - "{} is not a valid wheel filename.".format(filename) - ) - self.filename = filename - self.name = wheel_info.group('name').replace('_', '-') - # we'll assume "_" means "-" due to wheel naming scheme - # (https://github.com/pypa/pip/issues/1150) - self.version = wheel_info.group('ver').replace('_', '-') - self.build_tag = wheel_info.group('build') - self.pyversions = wheel_info.group('pyver').split('.') - self.abis = wheel_info.group('abi').split('.') - self.plats = wheel_info.group('plat').split('.') - - # All the tag combinations from this file - self.file_tags = { - Tag(x, y, z) for x in self.pyversions - for y in self.abis for z in self.plats - } - - def get_formatted_file_tags(self): - # type: () -> List[str] - """Return the wheel's tags as a sorted list of strings.""" - return sorted(str(tag) for tag in self.file_tags) - - def support_index_min(self, tags): - # type: (List[Tag]) -> int - """Return the lowest index that one of the wheel's file_tag combinations - achieves in the given list of supported tags. - - For example, if there are 8 supported tags and one of the file tags - is first in the list, then return 0. - - :param tags: the PEP 425 tags to check the wheel against, in order - with most preferred first. - - :raises ValueError: If none of the wheel's file tags match one of - the supported tags. - """ - return min(tags.index(tag) for tag in self.file_tags if tag in tags) - - def supported(self, tags): - # type: (List[Tag]) -> bool - """Return whether the wheel is compatible with one of the given tags. - - :param tags: the PEP 425 tags to check the wheel against. - """ - return not self.file_tags.isdisjoint(tags) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/network/__init__.py b/venv/lib/python3.8/site-packages/pip/_internal/network/__init__.py deleted file mode 100644 index b51bde9..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/network/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -"""Contains purely network-related utilities. -""" diff --git a/venv/lib/python3.8/site-packages/pip/_internal/network/auth.py b/venv/lib/python3.8/site-packages/pip/_internal/network/auth.py deleted file mode 100644 index 94da3d4..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/network/auth.py +++ /dev/null @@ -1,298 +0,0 @@ -"""Network Authentication Helpers - -Contains interface (MultiDomainBasicAuth) and associated glue code for -providing credentials in the context of network requests. -""" - -# The following comment should be removed at some point in the future. -# mypy: disallow-untyped-defs=False - -import logging - -from pip._vendor.requests.auth import AuthBase, HTTPBasicAuth -from pip._vendor.requests.utils import get_netrc_auth -from pip._vendor.six.moves.urllib import parse as urllib_parse - -from pip._internal.utils.misc import ( - ask, - ask_input, - ask_password, - remove_auth_from_url, - split_auth_netloc_from_url, -) -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from optparse import Values - from typing import Dict, Optional, Tuple - - from pip._internal.vcs.versioncontrol import AuthInfo - - Credentials = Tuple[str, str, str] - -logger = logging.getLogger(__name__) - -try: - import keyring # noqa -except ImportError: - keyring = None -except Exception as exc: - logger.warning( - "Keyring is skipped due to an exception: %s", str(exc), - ) - keyring = None - - -def get_keyring_auth(url, username): - """Return the tuple auth for a given url from keyring.""" - if not url or not keyring: - return None - - try: - try: - get_credential = keyring.get_credential - except AttributeError: - pass - else: - logger.debug("Getting credentials from keyring for %s", url) - cred = get_credential(url, username) - if cred is not None: - return cred.username, cred.password - return None - - if username: - logger.debug("Getting password from keyring for %s", url) - password = keyring.get_password(url, username) - if password: - return username, password - - except Exception as exc: - logger.warning( - "Keyring is skipped due to an exception: %s", str(exc), - ) - - -class MultiDomainBasicAuth(AuthBase): - - def __init__(self, prompting=True, index_urls=None): - # type: (bool, Optional[Values]) -> None - self.prompting = prompting - self.index_urls = index_urls - self.passwords = {} # type: Dict[str, AuthInfo] - # When the user is prompted to enter credentials and keyring is - # available, we will offer to save them. If the user accepts, - # this value is set to the credentials they entered. After the - # request authenticates, the caller should call - # ``save_credentials`` to save these. - self._credentials_to_save = None # type: Optional[Credentials] - - def _get_index_url(self, url): - """Return the original index URL matching the requested URL. - - Cached or dynamically generated credentials may work against - the original index URL rather than just the netloc. - - The provided url should have had its username and password - removed already. If the original index url had credentials then - they will be included in the return value. - - Returns None if no matching index was found, or if --no-index - was specified by the user. - """ - if not url or not self.index_urls: - return None - - for u in self.index_urls: - prefix = remove_auth_from_url(u).rstrip("/") + "/" - if url.startswith(prefix): - return u - - def _get_new_credentials(self, original_url, allow_netrc=True, - allow_keyring=True): - """Find and return credentials for the specified URL.""" - # Split the credentials and netloc from the url. - url, netloc, url_user_password = split_auth_netloc_from_url( - original_url, - ) - - # Start with the credentials embedded in the url - username, password = url_user_password - if username is not None and password is not None: - logger.debug("Found credentials in url for %s", netloc) - return url_user_password - - # Find a matching index url for this request - index_url = self._get_index_url(url) - if index_url: - # Split the credentials from the url. - index_info = split_auth_netloc_from_url(index_url) - if index_info: - index_url, _, index_url_user_password = index_info - logger.debug("Found index url %s", index_url) - - # If an index URL was found, try its embedded credentials - if index_url and index_url_user_password[0] is not None: - username, password = index_url_user_password - if username is not None and password is not None: - logger.debug("Found credentials in index url for %s", netloc) - return index_url_user_password - - # Get creds from netrc if we still don't have them - if allow_netrc: - netrc_auth = get_netrc_auth(original_url) - if netrc_auth: - logger.debug("Found credentials in netrc for %s", netloc) - return netrc_auth - - # If we don't have a password and keyring is available, use it. - if allow_keyring: - # The index url is more specific than the netloc, so try it first - kr_auth = ( - get_keyring_auth(index_url, username) or - get_keyring_auth(netloc, username) - ) - if kr_auth: - logger.debug("Found credentials in keyring for %s", netloc) - return kr_auth - - return username, password - - def _get_url_and_credentials(self, original_url): - """Return the credentials to use for the provided URL. - - If allowed, netrc and keyring may be used to obtain the - correct credentials. - - Returns (url_without_credentials, username, password). Note - that even if the original URL contains credentials, this - function may return a different username and password. - """ - url, netloc, _ = split_auth_netloc_from_url(original_url) - - # Use any stored credentials that we have for this netloc - username, password = self.passwords.get(netloc, (None, None)) - - if username is None and password is None: - # No stored credentials. Acquire new credentials without prompting - # the user. (e.g. from netrc, keyring, or the URL itself) - username, password = self._get_new_credentials(original_url) - - if username is not None or password is not None: - # Convert the username and password if they're None, so that - # this netloc will show up as "cached" in the conditional above. - # Further, HTTPBasicAuth doesn't accept None, so it makes sense to - # cache the value that is going to be used. - username = username or "" - password = password or "" - - # Store any acquired credentials. - self.passwords[netloc] = (username, password) - - assert ( - # Credentials were found - (username is not None and password is not None) or - # Credentials were not found - (username is None and password is None) - ), "Could not load credentials from url: {}".format(original_url) - - return url, username, password - - def __call__(self, req): - # Get credentials for this request - url, username, password = self._get_url_and_credentials(req.url) - - # Set the url of the request to the url without any credentials - req.url = url - - if username is not None and password is not None: - # Send the basic auth with this request - req = HTTPBasicAuth(username, password)(req) - - # Attach a hook to handle 401 responses - req.register_hook("response", self.handle_401) - - return req - - # Factored out to allow for easy patching in tests - def _prompt_for_password(self, netloc): - username = ask_input("User for {}: ".format(netloc)) - if not username: - return None, None - auth = get_keyring_auth(netloc, username) - if auth: - return auth[0], auth[1], False - password = ask_password("Password: ") - return username, password, True - - # Factored out to allow for easy patching in tests - def _should_save_password_to_keyring(self): - if not keyring: - return False - return ask("Save credentials to keyring [y/N]: ", ["y", "n"]) == "y" - - def handle_401(self, resp, **kwargs): - # We only care about 401 responses, anything else we want to just - # pass through the actual response - if resp.status_code != 401: - return resp - - # We are not able to prompt the user so simply return the response - if not self.prompting: - return resp - - parsed = urllib_parse.urlparse(resp.url) - - # Prompt the user for a new username and password - username, password, save = self._prompt_for_password(parsed.netloc) - - # Store the new username and password to use for future requests - self._credentials_to_save = None - if username is not None and password is not None: - self.passwords[parsed.netloc] = (username, password) - - # Prompt to save the password to keyring - if save and self._should_save_password_to_keyring(): - self._credentials_to_save = (parsed.netloc, username, password) - - # Consume content and release the original connection to allow our new - # request to reuse the same one. - resp.content - resp.raw.release_conn() - - # Add our new username and password to the request - req = HTTPBasicAuth(username or "", password or "")(resp.request) - req.register_hook("response", self.warn_on_401) - - # On successful request, save the credentials that were used to - # keyring. (Note that if the user responded "no" above, this member - # is not set and nothing will be saved.) - if self._credentials_to_save: - req.register_hook("response", self.save_credentials) - - # Send our new request - new_resp = resp.connection.send(req, **kwargs) - new_resp.history.append(resp) - - return new_resp - - def warn_on_401(self, resp, **kwargs): - """Response callback to warn about incorrect credentials.""" - if resp.status_code == 401: - logger.warning( - '401 Error, Credentials not correct for %s', resp.request.url, - ) - - def save_credentials(self, resp, **kwargs): - """Response callback to save credentials on success.""" - assert keyring is not None, "should never reach here without keyring" - if not keyring: - return - - creds = self._credentials_to_save - self._credentials_to_save = None - if creds and resp.status_code < 400: - try: - logger.info('Saving credentials to keyring') - keyring.set_password(*creds) - except Exception: - logger.exception('Failed to save credentials') diff --git a/venv/lib/python3.8/site-packages/pip/_internal/network/cache.py b/venv/lib/python3.8/site-packages/pip/_internal/network/cache.py deleted file mode 100644 index c9386e1..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/network/cache.py +++ /dev/null @@ -1,81 +0,0 @@ -"""HTTP cache implementation. -""" - -# The following comment should be removed at some point in the future. -# mypy: disallow-untyped-defs=False - -import os -from contextlib import contextmanager - -from pip._vendor.cachecontrol.cache import BaseCache -from pip._vendor.cachecontrol.caches import FileCache -from pip._vendor.requests.models import Response - -from pip._internal.utils.filesystem import adjacent_tmp_file, replace -from pip._internal.utils.misc import ensure_dir -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import Optional - - -def is_from_cache(response): - # type: (Response) -> bool - return getattr(response, "from_cache", False) - - -@contextmanager -def suppressed_cache_errors(): - """If we can't access the cache then we can just skip caching and process - requests as if caching wasn't enabled. - """ - try: - yield - except (OSError, IOError): - pass - - -class SafeFileCache(BaseCache): - """ - A file based cache which is safe to use even when the target directory may - not be accessible or writable. - """ - - def __init__(self, directory): - # type: (str) -> None - assert directory is not None, "Cache directory must not be None." - super(SafeFileCache, self).__init__() - self.directory = directory - - def _get_cache_path(self, name): - # type: (str) -> str - # From cachecontrol.caches.file_cache.FileCache._fn, brought into our - # class for backwards-compatibility and to avoid using a non-public - # method. - hashed = FileCache.encode(name) - parts = list(hashed[:5]) + [hashed] - return os.path.join(self.directory, *parts) - - def get(self, key): - # type: (str) -> Optional[bytes] - path = self._get_cache_path(key) - with suppressed_cache_errors(): - with open(path, 'rb') as f: - return f.read() - - def set(self, key, value): - # type: (str, bytes) -> None - path = self._get_cache_path(key) - with suppressed_cache_errors(): - ensure_dir(os.path.dirname(path)) - - with adjacent_tmp_file(path) as f: - f.write(value) - - replace(f.name, path) - - def delete(self, key): - # type: (str) -> None - path = self._get_cache_path(key) - with suppressed_cache_errors(): - os.remove(path) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/network/download.py b/venv/lib/python3.8/site-packages/pip/_internal/network/download.py deleted file mode 100644 index 2f3e08a..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/network/download.py +++ /dev/null @@ -1,200 +0,0 @@ -"""Download files with progress indicators. -""" -import cgi -import logging -import mimetypes -import os - -from pip._vendor import requests -from pip._vendor.requests.models import CONTENT_CHUNK_SIZE - -from pip._internal.cli.progress_bars import DownloadProgressProvider -from pip._internal.models.index import PyPI -from pip._internal.network.cache import is_from_cache -from pip._internal.network.utils import response_chunks -from pip._internal.utils.misc import ( - format_size, - redact_auth_from_url, - splitext, -) -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import Iterable, Optional - - from pip._vendor.requests.models import Response - - from pip._internal.models.link import Link - from pip._internal.network.session import PipSession - -logger = logging.getLogger(__name__) - - -def _get_http_response_size(resp): - # type: (Response) -> Optional[int] - try: - return int(resp.headers['content-length']) - except (ValueError, KeyError, TypeError): - return None - - -def _prepare_download( - resp, # type: Response - link, # type: Link - progress_bar # type: str -): - # type: (...) -> Iterable[bytes] - total_length = _get_http_response_size(resp) - - if link.netloc == PyPI.file_storage_domain: - url = link.show_url - else: - url = link.url_without_fragment - - logged_url = redact_auth_from_url(url) - - if total_length: - logged_url = '{} ({})'.format(logged_url, format_size(total_length)) - - if is_from_cache(resp): - logger.info("Using cached %s", logged_url) - else: - logger.info("Downloading %s", logged_url) - - if logger.getEffectiveLevel() > logging.INFO: - show_progress = False - elif is_from_cache(resp): - show_progress = False - elif not total_length: - show_progress = True - elif total_length > (40 * 1000): - show_progress = True - else: - show_progress = False - - chunks = response_chunks(resp, CONTENT_CHUNK_SIZE) - - if not show_progress: - return chunks - - return DownloadProgressProvider( - progress_bar, max=total_length - )(chunks) - - -def sanitize_content_filename(filename): - # type: (str) -> str - """ - Sanitize the "filename" value from a Content-Disposition header. - """ - return os.path.basename(filename) - - -def parse_content_disposition(content_disposition, default_filename): - # type: (str, str) -> str - """ - Parse the "filename" value from a Content-Disposition header, and - return the default filename if the result is empty. - """ - _type, params = cgi.parse_header(content_disposition) - filename = params.get('filename') - if filename: - # We need to sanitize the filename to prevent directory traversal - # in case the filename contains ".." path parts. - filename = sanitize_content_filename(filename) - return filename or default_filename - - -def _get_http_response_filename(resp, link): - # type: (Response, Link) -> str - """Get an ideal filename from the given HTTP response, falling back to - the link filename if not provided. - """ - filename = link.filename # fallback - # Have a look at the Content-Disposition header for a better guess - content_disposition = resp.headers.get('content-disposition') - if content_disposition: - filename = parse_content_disposition(content_disposition, filename) - ext = splitext(filename)[1] # type: Optional[str] - if not ext: - ext = mimetypes.guess_extension( - resp.headers.get('content-type', '') - ) - if ext: - filename += ext - if not ext and link.url != resp.url: - ext = os.path.splitext(resp.url)[1] - if ext: - filename += ext - return filename - - -def _http_get_download(session, link): - # type: (PipSession, Link) -> Response - target_url = link.url.split('#', 1)[0] - resp = session.get( - target_url, - # We use Accept-Encoding: identity here because requests - # defaults to accepting compressed responses. This breaks in - # a variety of ways depending on how the server is configured. - # - Some servers will notice that the file isn't a compressible - # file and will leave the file alone and with an empty - # Content-Encoding - # - Some servers will notice that the file is already - # compressed and will leave the file alone and will add a - # Content-Encoding: gzip header - # - Some servers won't notice anything at all and will take - # a file that's already been compressed and compress it again - # and set the Content-Encoding: gzip header - # By setting this to request only the identity encoding We're - # hoping to eliminate the third case. Hopefully there does not - # exist a server which when given a file will notice it is - # already compressed and that you're not asking for a - # compressed file and will then decompress it before sending - # because if that's the case I don't think it'll ever be - # possible to make this work. - headers={"Accept-Encoding": "identity"}, - stream=True, - ) - resp.raise_for_status() - return resp - - -class Download(object): - def __init__( - self, - response, # type: Response - filename, # type: str - chunks, # type: Iterable[bytes] - ): - # type: (...) -> None - self.response = response - self.filename = filename - self.chunks = chunks - - -class Downloader(object): - def __init__( - self, - session, # type: PipSession - progress_bar, # type: str - ): - # type: (...) -> None - self._session = session - self._progress_bar = progress_bar - - def __call__(self, link): - # type: (Link) -> Download - try: - resp = _http_get_download(self._session, link) - except requests.HTTPError as e: - logger.critical( - "HTTP error %s while getting %s", e.response.status_code, link - ) - raise - - return Download( - resp, - _get_http_response_filename(resp, link), - _prepare_download(resp, link, self._progress_bar), - ) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/network/session.py b/venv/lib/python3.8/site-packages/pip/_internal/network/session.py deleted file mode 100644 index 39a4a54..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/network/session.py +++ /dev/null @@ -1,421 +0,0 @@ -"""PipSession and supporting code, containing all pip-specific -network request configuration and behavior. -""" - -# The following comment should be removed at some point in the future. -# mypy: disallow-untyped-defs=False - -import email.utils -import json -import logging -import mimetypes -import os -import platform -import sys -import warnings - -from pip._vendor import requests, six, urllib3 -from pip._vendor.cachecontrol import CacheControlAdapter -from pip._vendor.requests.adapters import BaseAdapter, HTTPAdapter -from pip._vendor.requests.models import Response -from pip._vendor.requests.structures import CaseInsensitiveDict -from pip._vendor.six.moves.urllib import parse as urllib_parse -from pip._vendor.urllib3.exceptions import InsecureRequestWarning - -from pip import __version__ -from pip._internal.network.auth import MultiDomainBasicAuth -from pip._internal.network.cache import SafeFileCache -# Import ssl from compat so the initial import occurs in only one place. -from pip._internal.utils.compat import has_tls, ipaddress -from pip._internal.utils.glibc import libc_ver -from pip._internal.utils.misc import ( - build_url_from_netloc, - get_installed_version, - parse_netloc, -) -from pip._internal.utils.typing import MYPY_CHECK_RUNNING -from pip._internal.utils.urls import url_to_path - -if MYPY_CHECK_RUNNING: - from typing import ( - Iterator, List, Optional, Tuple, Union, - ) - - from pip._internal.models.link import Link - - SecureOrigin = Tuple[str, str, Optional[Union[int, str]]] - - -logger = logging.getLogger(__name__) - - -# Ignore warning raised when using --trusted-host. -warnings.filterwarnings("ignore", category=InsecureRequestWarning) - - -SECURE_ORIGINS = [ - # protocol, hostname, port - # Taken from Chrome's list of secure origins (See: http://bit.ly/1qrySKC) - ("https", "*", "*"), - ("*", "localhost", "*"), - ("*", "127.0.0.0/8", "*"), - ("*", "::1/128", "*"), - ("file", "*", None), - # ssh is always secure. - ("ssh", "*", "*"), -] # type: List[SecureOrigin] - - -# These are environment variables present when running under various -# CI systems. For each variable, some CI systems that use the variable -# are indicated. The collection was chosen so that for each of a number -# of popular systems, at least one of the environment variables is used. -# This list is used to provide some indication of and lower bound for -# CI traffic to PyPI. Thus, it is okay if the list is not comprehensive. -# For more background, see: https://github.com/pypa/pip/issues/5499 -CI_ENVIRONMENT_VARIABLES = ( - # Azure Pipelines - 'BUILD_BUILDID', - # Jenkins - 'BUILD_ID', - # AppVeyor, CircleCI, Codeship, Gitlab CI, Shippable, Travis CI - 'CI', - # Explicit environment variable. - 'PIP_IS_CI', -) - - -def looks_like_ci(): - # type: () -> bool - """ - Return whether it looks like pip is running under CI. - """ - # We don't use the method of checking for a tty (e.g. using isatty()) - # because some CI systems mimic a tty (e.g. Travis CI). Thus that - # method doesn't provide definitive information in either direction. - return any(name in os.environ for name in CI_ENVIRONMENT_VARIABLES) - - -def user_agent(): - """ - Return a string representing the user agent. - """ - data = { - "installer": {"name": "pip", "version": __version__}, - "python": platform.python_version(), - "implementation": { - "name": platform.python_implementation(), - }, - } - - if data["implementation"]["name"] == 'CPython': - data["implementation"]["version"] = platform.python_version() - elif data["implementation"]["name"] == 'PyPy': - if sys.pypy_version_info.releaselevel == 'final': - pypy_version_info = sys.pypy_version_info[:3] - else: - pypy_version_info = sys.pypy_version_info - data["implementation"]["version"] = ".".join( - [str(x) for x in pypy_version_info] - ) - elif data["implementation"]["name"] == 'Jython': - # Complete Guess - data["implementation"]["version"] = platform.python_version() - elif data["implementation"]["name"] == 'IronPython': - # Complete Guess - data["implementation"]["version"] = platform.python_version() - - if sys.platform.startswith("linux"): - from pip._vendor import distro - distro_infos = dict(filter( - lambda x: x[1], - zip(["name", "version", "id"], distro.linux_distribution()), - )) - libc = dict(filter( - lambda x: x[1], - zip(["lib", "version"], libc_ver()), - )) - if libc: - distro_infos["libc"] = libc - if distro_infos: - data["distro"] = distro_infos - - if sys.platform.startswith("darwin") and platform.mac_ver()[0]: - data["distro"] = {"name": "macOS", "version": platform.mac_ver()[0]} - - if platform.system(): - data.setdefault("system", {})["name"] = platform.system() - - if platform.release(): - data.setdefault("system", {})["release"] = platform.release() - - if platform.machine(): - data["cpu"] = platform.machine() - - if has_tls(): - import _ssl as ssl - data["openssl_version"] = ssl.OPENSSL_VERSION - - setuptools_version = get_installed_version("setuptools") - if setuptools_version is not None: - data["setuptools_version"] = setuptools_version - - # Use None rather than False so as not to give the impression that - # pip knows it is not being run under CI. Rather, it is a null or - # inconclusive result. Also, we include some value rather than no - # value to make it easier to know that the check has been run. - data["ci"] = True if looks_like_ci() else None - - user_data = os.environ.get("PIP_USER_AGENT_USER_DATA") - if user_data is not None: - data["user_data"] = user_data - - return "{data[installer][name]}/{data[installer][version]} {json}".format( - data=data, - json=json.dumps(data, separators=(",", ":"), sort_keys=True), - ) - - -class LocalFSAdapter(BaseAdapter): - - def send(self, request, stream=None, timeout=None, verify=None, cert=None, - proxies=None): - pathname = url_to_path(request.url) - - resp = Response() - resp.status_code = 200 - resp.url = request.url - - try: - stats = os.stat(pathname) - except OSError as exc: - resp.status_code = 404 - resp.raw = exc - else: - modified = email.utils.formatdate(stats.st_mtime, usegmt=True) - content_type = mimetypes.guess_type(pathname)[0] or "text/plain" - resp.headers = CaseInsensitiveDict({ - "Content-Type": content_type, - "Content-Length": stats.st_size, - "Last-Modified": modified, - }) - - resp.raw = open(pathname, "rb") - resp.close = resp.raw.close - - return resp - - def close(self): - pass - - -class InsecureHTTPAdapter(HTTPAdapter): - - def cert_verify(self, conn, url, verify, cert): - super(InsecureHTTPAdapter, self).cert_verify( - conn=conn, url=url, verify=False, cert=cert - ) - - -class InsecureCacheControlAdapter(CacheControlAdapter): - - def cert_verify(self, conn, url, verify, cert): - super(InsecureCacheControlAdapter, self).cert_verify( - conn=conn, url=url, verify=False, cert=cert - ) - - -class PipSession(requests.Session): - - timeout = None # type: Optional[int] - - def __init__(self, *args, **kwargs): - """ - :param trusted_hosts: Domains not to emit warnings for when not using - HTTPS. - """ - retries = kwargs.pop("retries", 0) - cache = kwargs.pop("cache", None) - trusted_hosts = kwargs.pop("trusted_hosts", []) # type: List[str] - index_urls = kwargs.pop("index_urls", None) - - super(PipSession, self).__init__(*args, **kwargs) - - # Namespace the attribute with "pip_" just in case to prevent - # possible conflicts with the base class. - self.pip_trusted_origins = [] # type: List[Tuple[str, Optional[int]]] - - # Attach our User Agent to the request - self.headers["User-Agent"] = user_agent() - - # Attach our Authentication handler to the session - self.auth = MultiDomainBasicAuth(index_urls=index_urls) - - # Create our urllib3.Retry instance which will allow us to customize - # how we handle retries. - retries = urllib3.Retry( - # Set the total number of retries that a particular request can - # have. - total=retries, - - # A 503 error from PyPI typically means that the Fastly -> Origin - # connection got interrupted in some way. A 503 error in general - # is typically considered a transient error so we'll go ahead and - # retry it. - # A 500 may indicate transient error in Amazon S3 - # A 520 or 527 - may indicate transient error in CloudFlare - status_forcelist=[500, 503, 520, 527], - - # Add a small amount of back off between failed requests in - # order to prevent hammering the service. - backoff_factor=0.25, - ) - - # Our Insecure HTTPAdapter disables HTTPS validation. It does not - # support caching so we'll use it for all http:// URLs. - # If caching is disabled, we will also use it for - # https:// hosts that we've marked as ignoring - # TLS errors for (trusted-hosts). - insecure_adapter = InsecureHTTPAdapter(max_retries=retries) - - # We want to _only_ cache responses on securely fetched origins or when - # the host is specified as trusted. We do this because - # we can't validate the response of an insecurely/untrusted fetched - # origin, and we don't want someone to be able to poison the cache and - # require manual eviction from the cache to fix it. - if cache: - secure_adapter = CacheControlAdapter( - cache=SafeFileCache(cache), - max_retries=retries, - ) - self._trusted_host_adapter = InsecureCacheControlAdapter( - cache=SafeFileCache(cache), - max_retries=retries, - ) - else: - secure_adapter = HTTPAdapter(max_retries=retries) - self._trusted_host_adapter = insecure_adapter - - self.mount("https://", secure_adapter) - self.mount("http://", insecure_adapter) - - # Enable file:// urls - self.mount("file://", LocalFSAdapter()) - - for host in trusted_hosts: - self.add_trusted_host(host, suppress_logging=True) - - def add_trusted_host(self, host, source=None, suppress_logging=False): - # type: (str, Optional[str], bool) -> None - """ - :param host: It is okay to provide a host that has previously been - added. - :param source: An optional source string, for logging where the host - string came from. - """ - if not suppress_logging: - msg = 'adding trusted host: {!r}'.format(host) - if source is not None: - msg += ' (from {})'.format(source) - logger.info(msg) - - host_port = parse_netloc(host) - if host_port not in self.pip_trusted_origins: - self.pip_trusted_origins.append(host_port) - - self.mount( - build_url_from_netloc(host) + '/', - self._trusted_host_adapter - ) - if not host_port[1]: - # Mount wildcard ports for the same host. - self.mount( - build_url_from_netloc(host) + ':', - self._trusted_host_adapter - ) - - def iter_secure_origins(self): - # type: () -> Iterator[SecureOrigin] - for secure_origin in SECURE_ORIGINS: - yield secure_origin - for host, port in self.pip_trusted_origins: - yield ('*', host, '*' if port is None else port) - - def is_secure_origin(self, location): - # type: (Link) -> bool - # Determine if this url used a secure transport mechanism - parsed = urllib_parse.urlparse(str(location)) - origin_protocol, origin_host, origin_port = ( - parsed.scheme, parsed.hostname, parsed.port, - ) - - # The protocol to use to see if the protocol matches. - # Don't count the repository type as part of the protocol: in - # cases such as "git+ssh", only use "ssh". (I.e., Only verify against - # the last scheme.) - origin_protocol = origin_protocol.rsplit('+', 1)[-1] - - # Determine if our origin is a secure origin by looking through our - # hardcoded list of secure origins, as well as any additional ones - # configured on this PackageFinder instance. - for secure_origin in self.iter_secure_origins(): - secure_protocol, secure_host, secure_port = secure_origin - if origin_protocol != secure_protocol and secure_protocol != "*": - continue - - try: - addr = ipaddress.ip_address( - None - if origin_host is None - else six.ensure_text(origin_host) - ) - network = ipaddress.ip_network( - six.ensure_text(secure_host) - ) - except ValueError: - # We don't have both a valid address or a valid network, so - # we'll check this origin against hostnames. - if ( - origin_host and - origin_host.lower() != secure_host.lower() and - secure_host != "*" - ): - continue - else: - # We have a valid address and network, so see if the address - # is contained within the network. - if addr not in network: - continue - - # Check to see if the port matches. - if ( - origin_port != secure_port and - secure_port != "*" and - secure_port is not None - ): - continue - - # If we've gotten here, then this origin matches the current - # secure origin and we should return True - return True - - # If we've gotten to this point, then the origin isn't secure and we - # will not accept it as a valid location to search. We will however - # log a warning that we are ignoring it. - logger.warning( - "The repository located at %s is not a trusted or secure host and " - "is being ignored. If this repository is available via HTTPS we " - "recommend you use HTTPS instead, otherwise you may silence " - "this warning and allow it anyway with '--trusted-host %s'.", - origin_host, - origin_host, - ) - - return False - - def request(self, method, url, *args, **kwargs): - # Allow setting a default timeout on a session - kwargs.setdefault("timeout", self.timeout) - - # Dispatch the actual request - return super(PipSession, self).request(method, url, *args, **kwargs) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/network/utils.py b/venv/lib/python3.8/site-packages/pip/_internal/network/utils.py deleted file mode 100644 index a19050b..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/network/utils.py +++ /dev/null @@ -1,48 +0,0 @@ -from pip._vendor.requests.models import CONTENT_CHUNK_SIZE, Response - -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import Iterator - - -def response_chunks(response, chunk_size=CONTENT_CHUNK_SIZE): - # type: (Response, int) -> Iterator[bytes] - """Given a requests Response, provide the data chunks. - """ - try: - # Special case for urllib3. - for chunk in response.raw.stream( - chunk_size, - # We use decode_content=False here because we don't - # want urllib3 to mess with the raw bytes we get - # from the server. If we decompress inside of - # urllib3 then we cannot verify the checksum - # because the checksum will be of the compressed - # file. This breakage will only occur if the - # server adds a Content-Encoding header, which - # depends on how the server was configured: - # - Some servers will notice that the file isn't a - # compressible file and will leave the file alone - # and with an empty Content-Encoding - # - Some servers will notice that the file is - # already compressed and will leave the file - # alone and will add a Content-Encoding: gzip - # header - # - Some servers won't notice anything at all and - # will take a file that's already been compressed - # and compress it again and set the - # Content-Encoding: gzip header - # - # By setting this not to decode automatically we - # hope to eliminate problems with the second case. - decode_content=False, - ): - yield chunk - except AttributeError: - # Standard file-like object. - while True: - chunk = response.raw.read(chunk_size) - if not chunk: - break - yield chunk diff --git a/venv/lib/python3.8/site-packages/pip/_internal/network/xmlrpc.py b/venv/lib/python3.8/site-packages/pip/_internal/network/xmlrpc.py deleted file mode 100644 index 121edd9..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/network/xmlrpc.py +++ /dev/null @@ -1,44 +0,0 @@ -"""xmlrpclib.Transport implementation -""" - -# The following comment should be removed at some point in the future. -# mypy: disallow-untyped-defs=False - -import logging - -from pip._vendor import requests -# NOTE: XMLRPC Client is not annotated in typeshed as on 2017-07-17, which is -# why we ignore the type on this import -from pip._vendor.six.moves import xmlrpc_client # type: ignore -from pip._vendor.six.moves.urllib import parse as urllib_parse - -logger = logging.getLogger(__name__) - - -class PipXmlrpcTransport(xmlrpc_client.Transport): - """Provide a `xmlrpclib.Transport` implementation via a `PipSession` - object. - """ - - def __init__(self, index_url, session, use_datetime=False): - xmlrpc_client.Transport.__init__(self, use_datetime) - index_parts = urllib_parse.urlparse(index_url) - self._scheme = index_parts.scheme - self._session = session - - def request(self, host, handler, request_body, verbose=False): - parts = (self._scheme, host, handler, None, None, None) - url = urllib_parse.urlunparse(parts) - try: - headers = {'Content-Type': 'text/xml'} - response = self._session.post(url, data=request_body, - headers=headers, stream=True) - response.raise_for_status() - self.verbose = verbose - return self.parse_response(response.raw) - except requests.HTTPError as exc: - logger.critical( - "HTTP error %s while getting %s", - exc.response.status_code, url, - ) - raise diff --git a/venv/lib/python3.8/site-packages/pip/_internal/operations/__init__.py b/venv/lib/python3.8/site-packages/pip/_internal/operations/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.8/site-packages/pip/_internal/operations/build/__init__.py b/venv/lib/python3.8/site-packages/pip/_internal/operations/build/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.8/site-packages/pip/_internal/operations/build/metadata.py b/venv/lib/python3.8/site-packages/pip/_internal/operations/build/metadata.py deleted file mode 100644 index b13fbde..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/operations/build/metadata.py +++ /dev/null @@ -1,40 +0,0 @@ -"""Metadata generation logic for source distributions. -""" - -import logging -import os - -from pip._internal.utils.subprocess import runner_with_spinner_message -from pip._internal.utils.temp_dir import TempDirectory -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from pip._internal.build_env import BuildEnvironment - from pip._vendor.pep517.wrappers import Pep517HookCaller - -logger = logging.getLogger(__name__) - - -def generate_metadata(build_env, backend): - # type: (BuildEnvironment, Pep517HookCaller) -> str - """Generate metadata using mechanisms described in PEP 517. - - Returns the generated metadata directory. - """ - metadata_tmpdir = TempDirectory( - kind="modern-metadata", globally_managed=True - ) - - metadata_dir = metadata_tmpdir.path - - with build_env: - # Note that Pep517HookCaller implements a fallback for - # prepare_metadata_for_build_wheel, so we don't have to - # consider the possibility that this hook doesn't exist. - runner = runner_with_spinner_message("Preparing wheel metadata") - with backend.subprocess_runner(runner): - distinfo_dir = backend.prepare_metadata_for_build_wheel( - metadata_dir - ) - - return os.path.join(metadata_dir, distinfo_dir) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/operations/build/metadata_legacy.py b/venv/lib/python3.8/site-packages/pip/_internal/operations/build/metadata_legacy.py deleted file mode 100644 index 14762ae..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/operations/build/metadata_legacy.py +++ /dev/null @@ -1,77 +0,0 @@ -"""Metadata generation logic for legacy source distributions. -""" - -import logging -import os - -from pip._internal.exceptions import InstallationError -from pip._internal.utils.setuptools_build import make_setuptools_egg_info_args -from pip._internal.utils.subprocess import call_subprocess -from pip._internal.utils.temp_dir import TempDirectory -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from pip._internal.build_env import BuildEnvironment - -logger = logging.getLogger(__name__) - - -def _find_egg_info(directory): - # type: (str) -> str - """Find an .egg-info subdirectory in `directory`. - """ - filenames = [ - f for f in os.listdir(directory) if f.endswith(".egg-info") - ] - - if not filenames: - raise InstallationError( - "No .egg-info directory found in {}".format(directory) - ) - - if len(filenames) > 1: - raise InstallationError( - "More than one .egg-info directory found in {}".format( - directory - ) - ) - - return os.path.join(directory, filenames[0]) - - -def generate_metadata( - build_env, # type: BuildEnvironment - setup_py_path, # type: str - source_dir, # type: str - isolated, # type: bool - details, # type: str -): - # type: (...) -> str - """Generate metadata using setup.py-based defacto mechanisms. - - Returns the generated metadata directory. - """ - logger.debug( - 'Running setup.py (path:%s) egg_info for package %s', - setup_py_path, details, - ) - - egg_info_dir = TempDirectory( - kind="pip-egg-info", globally_managed=True - ).path - - args = make_setuptools_egg_info_args( - setup_py_path, - egg_info_dir=egg_info_dir, - no_user_config=isolated, - ) - - with build_env: - call_subprocess( - args, - cwd=source_dir, - command_desc='python setup.py egg_info', - ) - - # Return the .egg-info directory. - return _find_egg_info(egg_info_dir) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/operations/build/wheel.py b/venv/lib/python3.8/site-packages/pip/_internal/operations/build/wheel.py deleted file mode 100644 index 1266ce0..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/operations/build/wheel.py +++ /dev/null @@ -1,46 +0,0 @@ -import logging -import os - -from pip._internal.utils.subprocess import runner_with_spinner_message -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import List, Optional - from pip._vendor.pep517.wrappers import Pep517HookCaller - -logger = logging.getLogger(__name__) - - -def build_wheel_pep517( - name, # type: str - backend, # type: Pep517HookCaller - metadata_directory, # type: str - build_options, # type: List[str] - tempd, # type: str -): - # type: (...) -> Optional[str] - """Build one InstallRequirement using the PEP 517 build process. - - Returns path to wheel if successfully built. Otherwise, returns None. - """ - assert metadata_directory is not None - if build_options: - # PEP 517 does not support --build-options - logger.error('Cannot build wheel for %s using PEP 517 when ' - '--build-option is present' % (name,)) - return None - try: - logger.debug('Destination directory: %s', tempd) - - runner = runner_with_spinner_message( - 'Building wheel for {} (PEP 517)'.format(name) - ) - with backend.subprocess_runner(runner): - wheel_name = backend.build_wheel( - tempd, - metadata_directory=metadata_directory, - ) - except Exception: - logger.error('Failed building wheel for %s', name) - return None - return os.path.join(tempd, wheel_name) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/operations/build/wheel_legacy.py b/venv/lib/python3.8/site-packages/pip/_internal/operations/build/wheel_legacy.py deleted file mode 100644 index 37dc876..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/operations/build/wheel_legacy.py +++ /dev/null @@ -1,115 +0,0 @@ -import logging -import os.path - -from pip._internal.cli.spinners import open_spinner -from pip._internal.utils.setuptools_build import ( - make_setuptools_bdist_wheel_args, -) -from pip._internal.utils.subprocess import ( - LOG_DIVIDER, - call_subprocess, - format_command_args, -) -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import List, Optional, Text - -logger = logging.getLogger(__name__) - - -def format_command_result( - command_args, # type: List[str] - command_output, # type: Text -): - # type: (...) -> str - """Format command information for logging.""" - command_desc = format_command_args(command_args) - text = 'Command arguments: {}\n'.format(command_desc) - - if not command_output: - text += 'Command output: None' - elif logger.getEffectiveLevel() > logging.DEBUG: - text += 'Command output: [use --verbose to show]' - else: - if not command_output.endswith('\n'): - command_output += '\n' - text += 'Command output:\n{}{}'.format(command_output, LOG_DIVIDER) - - return text - - -def get_legacy_build_wheel_path( - names, # type: List[str] - temp_dir, # type: str - name, # type: str - command_args, # type: List[str] - command_output, # type: Text -): - # type: (...) -> Optional[str] - """Return the path to the wheel in the temporary build directory.""" - # Sort for determinism. - names = sorted(names) - if not names: - msg = ( - 'Legacy build of wheel for {!r} created no files.\n' - ).format(name) - msg += format_command_result(command_args, command_output) - logger.warning(msg) - return None - - if len(names) > 1: - msg = ( - 'Legacy build of wheel for {!r} created more than one file.\n' - 'Filenames (choosing first): {}\n' - ).format(name, names) - msg += format_command_result(command_args, command_output) - logger.warning(msg) - - return os.path.join(temp_dir, names[0]) - - -def build_wheel_legacy( - name, # type: str - setup_py_path, # type: str - source_dir, # type: str - global_options, # type: List[str] - build_options, # type: List[str] - tempd, # type: str -): - # type: (...) -> Optional[str] - """Build one unpacked package using the "legacy" build process. - - Returns path to wheel if successfully built. Otherwise, returns None. - """ - wheel_args = make_setuptools_bdist_wheel_args( - setup_py_path, - global_options=global_options, - build_options=build_options, - destination_dir=tempd, - ) - - spin_message = 'Building wheel for {} (setup.py)'.format(name) - with open_spinner(spin_message) as spinner: - logger.debug('Destination directory: %s', tempd) - - try: - output = call_subprocess( - wheel_args, - cwd=source_dir, - spinner=spinner, - ) - except Exception: - spinner.finish("error") - logger.error('Failed building wheel for %s', name) - return None - - names = os.listdir(tempd) - wheel_path = get_legacy_build_wheel_path( - names=names, - temp_dir=tempd, - name=name, - command_args=wheel_args, - command_output=output, - ) - return wheel_path diff --git a/venv/lib/python3.8/site-packages/pip/_internal/operations/check.py b/venv/lib/python3.8/site-packages/pip/_internal/operations/check.py deleted file mode 100644 index b85a123..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/operations/check.py +++ /dev/null @@ -1,163 +0,0 @@ -"""Validation of dependencies of packages -""" - -# The following comment should be removed at some point in the future. -# mypy: strict-optional=False -# mypy: disallow-untyped-defs=False - -import logging -from collections import namedtuple - -from pip._vendor.packaging.utils import canonicalize_name -from pip._vendor.pkg_resources import RequirementParseError - -from pip._internal.distributions import ( - make_distribution_for_install_requirement, -) -from pip._internal.utils.misc import get_installed_distributions -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -logger = logging.getLogger(__name__) - -if MYPY_CHECK_RUNNING: - from pip._internal.req.req_install import InstallRequirement - from typing import ( - Any, Callable, Dict, Optional, Set, Tuple, List - ) - - # Shorthands - PackageSet = Dict[str, 'PackageDetails'] - Missing = Tuple[str, Any] - Conflicting = Tuple[str, str, Any] - - MissingDict = Dict[str, List[Missing]] - ConflictingDict = Dict[str, List[Conflicting]] - CheckResult = Tuple[MissingDict, ConflictingDict] - -PackageDetails = namedtuple('PackageDetails', ['version', 'requires']) - - -def create_package_set_from_installed(**kwargs): - # type: (**Any) -> Tuple[PackageSet, bool] - """Converts a list of distributions into a PackageSet. - """ - # Default to using all packages installed on the system - if kwargs == {}: - kwargs = {"local_only": False, "skip": ()} - - package_set = {} - problems = False - for dist in get_installed_distributions(**kwargs): - name = canonicalize_name(dist.project_name) - try: - package_set[name] = PackageDetails(dist.version, dist.requires()) - except RequirementParseError as e: - # Don't crash on broken metadata - logger.warning("Error parsing requirements for %s: %s", name, e) - problems = True - return package_set, problems - - -def check_package_set(package_set, should_ignore=None): - # type: (PackageSet, Optional[Callable[[str], bool]]) -> CheckResult - """Check if a package set is consistent - - If should_ignore is passed, it should be a callable that takes a - package name and returns a boolean. - """ - if should_ignore is None: - def should_ignore(name): - return False - - missing = {} - conflicting = {} - - for package_name in package_set: - # Info about dependencies of package_name - missing_deps = set() # type: Set[Missing] - conflicting_deps = set() # type: Set[Conflicting] - - if should_ignore(package_name): - continue - - for req in package_set[package_name].requires: - name = canonicalize_name(req.project_name) # type: str - - # Check if it's missing - if name not in package_set: - missed = True - if req.marker is not None: - missed = req.marker.evaluate() - if missed: - missing_deps.add((name, req)) - continue - - # Check if there's a conflict - version = package_set[name].version # type: str - if not req.specifier.contains(version, prereleases=True): - conflicting_deps.add((name, version, req)) - - if missing_deps: - missing[package_name] = sorted(missing_deps, key=str) - if conflicting_deps: - conflicting[package_name] = sorted(conflicting_deps, key=str) - - return missing, conflicting - - -def check_install_conflicts(to_install): - # type: (List[InstallRequirement]) -> Tuple[PackageSet, CheckResult] - """For checking if the dependency graph would be consistent after \ - installing given requirements - """ - # Start from the current state - package_set, _ = create_package_set_from_installed() - # Install packages - would_be_installed = _simulate_installation_of(to_install, package_set) - - # Only warn about directly-dependent packages; create a whitelist of them - whitelist = _create_whitelist(would_be_installed, package_set) - - return ( - package_set, - check_package_set( - package_set, should_ignore=lambda name: name not in whitelist - ) - ) - - -def _simulate_installation_of(to_install, package_set): - # type: (List[InstallRequirement], PackageSet) -> Set[str] - """Computes the version of packages after installing to_install. - """ - - # Keep track of packages that were installed - installed = set() - - # Modify it as installing requirement_set would (assuming no errors) - for inst_req in to_install: - abstract_dist = make_distribution_for_install_requirement(inst_req) - dist = abstract_dist.get_pkg_resources_distribution() - - name = canonicalize_name(dist.key) - package_set[name] = PackageDetails(dist.version, dist.requires()) - - installed.add(name) - - return installed - - -def _create_whitelist(would_be_installed, package_set): - # type: (Set[str], PackageSet) -> Set[str] - packages_affected = set(would_be_installed) - - for package_name in package_set: - if package_name in packages_affected: - continue - - for req in package_set[package_name].requires: - if canonicalize_name(req.name) in packages_affected: - packages_affected.add(package_name) - break - - return packages_affected diff --git a/venv/lib/python3.8/site-packages/pip/_internal/operations/freeze.py b/venv/lib/python3.8/site-packages/pip/_internal/operations/freeze.py deleted file mode 100644 index aa6b052..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/operations/freeze.py +++ /dev/null @@ -1,272 +0,0 @@ -# The following comment should be removed at some point in the future. -# mypy: strict-optional=False -# mypy: disallow-untyped-defs=False - -from __future__ import absolute_import - -import collections -import logging -import os - -from pip._vendor import six -from pip._vendor.packaging.utils import canonicalize_name -from pip._vendor.pkg_resources import RequirementParseError - -from pip._internal.exceptions import BadCommand, InstallationError -from pip._internal.req.constructors import ( - install_req_from_editable, - install_req_from_line, -) -from pip._internal.req.req_file import COMMENT_RE -from pip._internal.utils.direct_url_helpers import ( - direct_url_as_pep440_direct_reference, - dist_get_direct_url, -) -from pip._internal.utils.misc import ( - dist_is_editable, - get_installed_distributions, -) -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import ( - Iterator, Optional, List, Container, Set, Dict, Tuple, Iterable, Union - ) - from pip._internal.cache import WheelCache - from pip._vendor.pkg_resources import ( - Distribution, Requirement - ) - - RequirementInfo = Tuple[Optional[Union[str, Requirement]], bool, List[str]] - - -logger = logging.getLogger(__name__) - - -def freeze( - requirement=None, # type: Optional[List[str]] - find_links=None, # type: Optional[List[str]] - local_only=None, # type: Optional[bool] - user_only=None, # type: Optional[bool] - paths=None, # type: Optional[List[str]] - isolated=False, # type: bool - wheel_cache=None, # type: Optional[WheelCache] - exclude_editable=False, # type: bool - skip=() # type: Container[str] -): - # type: (...) -> Iterator[str] - find_links = find_links or [] - - for link in find_links: - yield '-f {}'.format(link) - installations = {} # type: Dict[str, FrozenRequirement] - for dist in get_installed_distributions(local_only=local_only, - skip=(), - user_only=user_only, - paths=paths): - try: - req = FrozenRequirement.from_dist(dist) - except RequirementParseError as exc: - # We include dist rather than dist.project_name because the - # dist string includes more information, like the version and - # location. We also include the exception message to aid - # troubleshooting. - logger.warning( - 'Could not generate requirement for distribution %r: %s', - dist, exc - ) - continue - if exclude_editable and req.editable: - continue - installations[req.canonical_name] = req - - if requirement: - # the options that don't get turned into an InstallRequirement - # should only be emitted once, even if the same option is in multiple - # requirements files, so we need to keep track of what has been emitted - # so that we don't emit it again if it's seen again - emitted_options = set() # type: Set[str] - # keep track of which files a requirement is in so that we can - # give an accurate warning if a requirement appears multiple times. - req_files = collections.defaultdict(list) # type: Dict[str, List[str]] - for req_file_path in requirement: - with open(req_file_path) as req_file: - for line in req_file: - if (not line.strip() or - line.strip().startswith('#') or - line.startswith(( - '-r', '--requirement', - '-Z', '--always-unzip', - '-f', '--find-links', - '-i', '--index-url', - '--pre', - '--trusted-host', - '--process-dependency-links', - '--extra-index-url'))): - line = line.rstrip() - if line not in emitted_options: - emitted_options.add(line) - yield line - continue - - if line.startswith('-e') or line.startswith('--editable'): - if line.startswith('-e'): - line = line[2:].strip() - else: - line = line[len('--editable'):].strip().lstrip('=') - line_req = install_req_from_editable( - line, - isolated=isolated, - ) - else: - line_req = install_req_from_line( - COMMENT_RE.sub('', line).strip(), - isolated=isolated, - ) - - if not line_req.name: - logger.info( - "Skipping line in requirement file [%s] because " - "it's not clear what it would install: %s", - req_file_path, line.strip(), - ) - logger.info( - " (add #egg=PackageName to the URL to avoid" - " this warning)" - ) - else: - line_req_canonical_name = canonicalize_name( - line_req.name) - if line_req_canonical_name not in installations: - # either it's not installed, or it is installed - # but has been processed already - if not req_files[line_req.name]: - logger.warning( - "Requirement file [%s] contains %s, but " - "package %r is not installed", - req_file_path, - COMMENT_RE.sub('', line).strip(), - line_req.name - ) - else: - req_files[line_req.name].append(req_file_path) - else: - yield str(installations[ - line_req_canonical_name]).rstrip() - del installations[line_req_canonical_name] - req_files[line_req.name].append(req_file_path) - - # Warn about requirements that were included multiple times (in a - # single requirements file or in different requirements files). - for name, files in six.iteritems(req_files): - if len(files) > 1: - logger.warning("Requirement %s included multiple times [%s]", - name, ', '.join(sorted(set(files)))) - - yield( - '## The following requirements were added by ' - 'pip freeze:' - ) - for installation in sorted( - installations.values(), key=lambda x: x.name.lower()): - if installation.canonical_name not in skip: - yield str(installation).rstrip() - - -def get_requirement_info(dist): - # type: (Distribution) -> RequirementInfo - """ - Compute and return values (req, editable, comments) for use in - FrozenRequirement.from_dist(). - """ - if not dist_is_editable(dist): - return (None, False, []) - - location = os.path.normcase(os.path.abspath(dist.location)) - - from pip._internal.vcs import vcs, RemoteNotFoundError - vcs_backend = vcs.get_backend_for_dir(location) - - if vcs_backend is None: - req = dist.as_requirement() - logger.debug( - 'No VCS found for editable requirement "%s" in: %r', req, - location, - ) - comments = [ - '# Editable install with no version control ({})'.format(req) - ] - return (location, True, comments) - - try: - req = vcs_backend.get_src_requirement(location, dist.project_name) - except RemoteNotFoundError: - req = dist.as_requirement() - comments = [ - '# Editable {} install with no remote ({})'.format( - type(vcs_backend).__name__, req, - ) - ] - return (location, True, comments) - - except BadCommand: - logger.warning( - 'cannot determine version of editable source in %s ' - '(%s command not found in path)', - location, - vcs_backend.name, - ) - return (None, True, []) - - except InstallationError as exc: - logger.warning( - "Error when trying to get requirement for VCS system %s, " - "falling back to uneditable format", exc - ) - else: - if req is not None: - return (req, True, []) - - logger.warning( - 'Could not determine repository location of %s', location - ) - comments = ['## !! Could not determine repository location'] - - return (None, False, comments) - - -class FrozenRequirement(object): - def __init__(self, name, req, editable, comments=()): - # type: (str, Union[str, Requirement], bool, Iterable[str]) -> None - self.name = name - self.canonical_name = canonicalize_name(name) - self.req = req - self.editable = editable - self.comments = comments - - @classmethod - def from_dist(cls, dist): - # type: (Distribution) -> FrozenRequirement - # TODO `get_requirement_info` is taking care of editable requirements. - # TODO This should be refactored when we will add detection of - # editable that provide .dist-info metadata. - req, editable, comments = get_requirement_info(dist) - if req is None and not editable: - # if PEP 610 metadata is present, attempt to use it - direct_url = dist_get_direct_url(dist) - if direct_url: - req = direct_url_as_pep440_direct_reference( - direct_url, dist.project_name - ) - comments = [] - if req is None: - # name==version requirement - req = dist.as_requirement() - - return cls(dist.project_name, req, editable, comments=comments) - - def __str__(self): - req = self.req - if self.editable: - req = '-e {}'.format(req) - return '\n'.join(list(self.comments) + [str(req)]) + '\n' diff --git a/venv/lib/python3.8/site-packages/pip/_internal/operations/install/__init__.py b/venv/lib/python3.8/site-packages/pip/_internal/operations/install/__init__.py deleted file mode 100644 index 24d6a5d..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/operations/install/__init__.py +++ /dev/null @@ -1,2 +0,0 @@ -"""For modules related to installing packages. -""" diff --git a/venv/lib/python3.8/site-packages/pip/_internal/operations/install/editable_legacy.py b/venv/lib/python3.8/site-packages/pip/_internal/operations/install/editable_legacy.py deleted file mode 100644 index a668a61..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/operations/install/editable_legacy.py +++ /dev/null @@ -1,52 +0,0 @@ -"""Legacy editable installation process, i.e. `setup.py develop`. -""" -import logging - -from pip._internal.utils.logging import indent_log -from pip._internal.utils.setuptools_build import make_setuptools_develop_args -from pip._internal.utils.subprocess import call_subprocess -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import List, Optional, Sequence - - from pip._internal.build_env import BuildEnvironment - - -logger = logging.getLogger(__name__) - - -def install_editable( - install_options, # type: List[str] - global_options, # type: Sequence[str] - prefix, # type: Optional[str] - home, # type: Optional[str] - use_user_site, # type: bool - name, # type: str - setup_py_path, # type: str - isolated, # type: bool - build_env, # type: BuildEnvironment - unpacked_source_directory, # type: str -): - # type: (...) -> None - """Install a package in editable mode. Most arguments are pass-through - to setuptools. - """ - logger.info('Running setup.py develop for %s', name) - - args = make_setuptools_develop_args( - setup_py_path, - global_options=global_options, - install_options=install_options, - no_user_config=isolated, - prefix=prefix, - home=home, - use_user_site=use_user_site, - ) - - with indent_log(): - with build_env: - call_subprocess( - args, - cwd=unpacked_source_directory, - ) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/operations/install/legacy.py b/venv/lib/python3.8/site-packages/pip/_internal/operations/install/legacy.py deleted file mode 100644 index 0fac905..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/operations/install/legacy.py +++ /dev/null @@ -1,142 +0,0 @@ -"""Legacy installation process, i.e. `setup.py install`. -""" - -import logging -import os -import sys -from distutils.util import change_root - -from pip._internal.utils.deprecation import deprecated -from pip._internal.utils.logging import indent_log -from pip._internal.utils.misc import ensure_dir -from pip._internal.utils.setuptools_build import make_setuptools_install_args -from pip._internal.utils.subprocess import runner_with_spinner_message -from pip._internal.utils.temp_dir import TempDirectory -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import List, Optional, Sequence - - from pip._internal.build_env import BuildEnvironment - from pip._internal.models.scheme import Scheme - - -logger = logging.getLogger(__name__) - - -class LegacyInstallFailure(Exception): - def __init__(self): - # type: () -> None - self.parent = sys.exc_info() - - -def install( - install_options, # type: List[str] - global_options, # type: Sequence[str] - root, # type: Optional[str] - home, # type: Optional[str] - prefix, # type: Optional[str] - use_user_site, # type: bool - pycompile, # type: bool - scheme, # type: Scheme - setup_py_path, # type: str - isolated, # type: bool - req_name, # type: str - build_env, # type: BuildEnvironment - unpacked_source_directory, # type: str - req_description, # type: str -): - # type: (...) -> bool - - header_dir = scheme.headers - - with TempDirectory(kind="record") as temp_dir: - try: - record_filename = os.path.join(temp_dir.path, 'install-record.txt') - install_args = make_setuptools_install_args( - setup_py_path, - global_options=global_options, - install_options=install_options, - record_filename=record_filename, - root=root, - prefix=prefix, - header_dir=header_dir, - home=home, - use_user_site=use_user_site, - no_user_config=isolated, - pycompile=pycompile, - ) - - runner = runner_with_spinner_message( - "Running setup.py install for {}".format(req_name) - ) - with indent_log(), build_env: - runner( - cmd=install_args, - cwd=unpacked_source_directory, - ) - - if not os.path.exists(record_filename): - logger.debug('Record file %s not found', record_filename) - # Signal to the caller that we didn't install the new package - return False - - except Exception: - # Signal to the caller that we didn't install the new package - raise LegacyInstallFailure - - # At this point, we have successfully installed the requirement. - - # We intentionally do not use any encoding to read the file because - # setuptools writes the file using distutils.file_util.write_file, - # which does not specify an encoding. - with open(record_filename) as f: - record_lines = f.read().splitlines() - - def prepend_root(path): - # type: (str) -> str - if root is None or not os.path.isabs(path): - return path - else: - return change_root(root, path) - - for line in record_lines: - directory = os.path.dirname(line) - if directory.endswith('.egg-info'): - egg_info_dir = prepend_root(directory) - break - else: - deprecated( - reason=( - "{} did not indicate that it installed an " - ".egg-info directory. Only setup.py projects " - "generating .egg-info directories are supported." - ).format(req_description), - replacement=( - "for maintainers: updating the setup.py of {0}. " - "For users: contact the maintainers of {0} to let " - "them know to update their setup.py.".format( - req_name - ) - ), - gone_in="20.2", - issue=6998, - ) - # FIXME: put the record somewhere - return True - - new_lines = [] - for line in record_lines: - filename = line.strip() - if os.path.isdir(filename): - filename += os.path.sep - new_lines.append( - os.path.relpath(prepend_root(filename), egg_info_dir) - ) - new_lines.sort() - ensure_dir(egg_info_dir) - inst_files_path = os.path.join(egg_info_dir, 'installed-files.txt') - with open(inst_files_path, 'w') as f: - f.write('\n'.join(new_lines) + '\n') - - return True diff --git a/venv/lib/python3.8/site-packages/pip/_internal/operations/install/wheel.py b/venv/lib/python3.8/site-packages/pip/_internal/operations/install/wheel.py deleted file mode 100644 index 2fb86b8..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/operations/install/wheel.py +++ /dev/null @@ -1,631 +0,0 @@ -"""Support for installing and building the "wheel" binary package format. -""" - -# The following comment should be removed at some point in the future. -# mypy: strict-optional=False - -from __future__ import absolute_import - -import collections -import compileall -import contextlib -import csv -import logging -import os.path -import re -import shutil -import stat -import sys -import warnings -from base64 import urlsafe_b64encode -from itertools import starmap -from zipfile import ZipFile - -from pip._vendor import pkg_resources -from pip._vendor.distlib.scripts import ScriptMaker -from pip._vendor.distlib.util import get_export_entry -from pip._vendor.six import StringIO - -from pip._internal.exceptions import InstallationError -from pip._internal.locations import get_major_minor_version -from pip._internal.models.direct_url import DIRECT_URL_METADATA_NAME, DirectUrl -from pip._internal.utils.filesystem import adjacent_tmp_file, replace -from pip._internal.utils.misc import captured_stdout, ensure_dir, hash_file -from pip._internal.utils.temp_dir import TempDirectory -from pip._internal.utils.typing import MYPY_CHECK_RUNNING -from pip._internal.utils.unpacking import current_umask, unpack_file -from pip._internal.utils.wheel import parse_wheel - -if MYPY_CHECK_RUNNING: - from email.message import Message - from typing import ( - Dict, List, Optional, Sequence, Tuple, Any, - Iterable, Iterator, Callable, Set, - ) - - from pip._internal.models.scheme import Scheme - from pip._internal.utils.filesystem import NamedTemporaryFileResult - - InstalledCSVRow = Tuple[str, ...] - - -logger = logging.getLogger(__name__) - - -def normpath(src, p): - # type: (str, str) -> str - return os.path.relpath(src, p).replace(os.path.sep, '/') - - -def rehash(path, blocksize=1 << 20): - # type: (str, int) -> Tuple[str, str] - """Return (encoded_digest, length) for path using hashlib.sha256()""" - h, length = hash_file(path, blocksize) - digest = 'sha256=' + urlsafe_b64encode( - h.digest() - ).decode('latin1').rstrip('=') - # unicode/str python2 issues - return (digest, str(length)) # type: ignore - - -def csv_io_kwargs(mode): - # type: (str) -> Dict[str, Any] - """Return keyword arguments to properly open a CSV file - in the given mode. - """ - if sys.version_info.major < 3: - return {'mode': '{}b'.format(mode)} - else: - return {'mode': mode, 'newline': ''} - - -def fix_script(path): - # type: (str) -> Optional[bool] - """Replace #!python with #!/path/to/python - Return True if file was changed. - """ - # XXX RECORD hashes will need to be updated - if os.path.isfile(path): - with open(path, 'rb') as script: - firstline = script.readline() - if not firstline.startswith(b'#!python'): - return False - exename = sys.executable.encode(sys.getfilesystemencoding()) - firstline = b'#!' + exename + os.linesep.encode("ascii") - rest = script.read() - with open(path, 'wb') as script: - script.write(firstline) - script.write(rest) - return True - return None - - -def wheel_root_is_purelib(metadata): - # type: (Message) -> bool - return metadata.get("Root-Is-Purelib", "").lower() == "true" - - -def get_entrypoints(filename): - # type: (str) -> Tuple[Dict[str, str], Dict[str, str]] - if not os.path.exists(filename): - return {}, {} - - # This is done because you can pass a string to entry_points wrappers which - # means that they may or may not be valid INI files. The attempt here is to - # strip leading and trailing whitespace in order to make them valid INI - # files. - with open(filename) as fp: - data = StringIO() - for line in fp: - data.write(line.strip()) - data.write("\n") - data.seek(0) - - # get the entry points and then the script names - entry_points = pkg_resources.EntryPoint.parse_map(data) - console = entry_points.get('console_scripts', {}) - gui = entry_points.get('gui_scripts', {}) - - def _split_ep(s): - # type: (pkg_resources.EntryPoint) -> Tuple[str, str] - """get the string representation of EntryPoint, - remove space and split on '=' - """ - split_parts = str(s).replace(" ", "").split("=") - return split_parts[0], split_parts[1] - - # convert the EntryPoint objects into strings with module:function - console = dict(_split_ep(v) for v in console.values()) - gui = dict(_split_ep(v) for v in gui.values()) - return console, gui - - -def message_about_scripts_not_on_PATH(scripts): - # type: (Sequence[str]) -> Optional[str] - """Determine if any scripts are not on PATH and format a warning. - Returns a warning message if one or more scripts are not on PATH, - otherwise None. - """ - if not scripts: - return None - - # Group scripts by the path they were installed in - grouped_by_dir = collections.defaultdict(set) # type: Dict[str, Set[str]] - for destfile in scripts: - parent_dir = os.path.dirname(destfile) - script_name = os.path.basename(destfile) - grouped_by_dir[parent_dir].add(script_name) - - # We don't want to warn for directories that are on PATH. - not_warn_dirs = [ - os.path.normcase(i).rstrip(os.sep) for i in - os.environ.get("PATH", "").split(os.pathsep) - ] - # If an executable sits with sys.executable, we don't warn for it. - # This covers the case of venv invocations without activating the venv. - not_warn_dirs.append(os.path.normcase(os.path.dirname(sys.executable))) - warn_for = { - parent_dir: scripts for parent_dir, scripts in grouped_by_dir.items() - if os.path.normcase(parent_dir) not in not_warn_dirs - } # type: Dict[str, Set[str]] - if not warn_for: - return None - - # Format a message - msg_lines = [] - for parent_dir, dir_scripts in warn_for.items(): - sorted_scripts = sorted(dir_scripts) # type: List[str] - if len(sorted_scripts) == 1: - start_text = "script {} is".format(sorted_scripts[0]) - else: - start_text = "scripts {} are".format( - ", ".join(sorted_scripts[:-1]) + " and " + sorted_scripts[-1] - ) - - msg_lines.append( - "The {} installed in '{}' which is not on PATH." - .format(start_text, parent_dir) - ) - - last_line_fmt = ( - "Consider adding {} to PATH or, if you prefer " - "to suppress this warning, use --no-warn-script-location." - ) - if len(msg_lines) == 1: - msg_lines.append(last_line_fmt.format("this directory")) - else: - msg_lines.append(last_line_fmt.format("these directories")) - - # Add a note if any directory starts with ~ - warn_for_tilde = any( - i[0] == "~" for i in os.environ.get("PATH", "").split(os.pathsep) if i - ) - if warn_for_tilde: - tilde_warning_msg = ( - "NOTE: The current PATH contains path(s) starting with `~`, " - "which may not be expanded by all applications." - ) - msg_lines.append(tilde_warning_msg) - - # Returns the formatted multiline message - return "\n".join(msg_lines) - - -def sorted_outrows(outrows): - # type: (Iterable[InstalledCSVRow]) -> List[InstalledCSVRow] - """Return the given rows of a RECORD file in sorted order. - - Each row is a 3-tuple (path, hash, size) and corresponds to a record of - a RECORD file (see PEP 376 and PEP 427 for details). For the rows - passed to this function, the size can be an integer as an int or string, - or the empty string. - """ - # Normally, there should only be one row per path, in which case the - # second and third elements don't come into play when sorting. - # However, in cases in the wild where a path might happen to occur twice, - # we don't want the sort operation to trigger an error (but still want - # determinism). Since the third element can be an int or string, we - # coerce each element to a string to avoid a TypeError in this case. - # For additional background, see-- - # https://github.com/pypa/pip/issues/5868 - return sorted(outrows, key=lambda row: tuple(str(x) for x in row)) - - -def get_csv_rows_for_installed( - old_csv_rows, # type: Iterable[List[str]] - installed, # type: Dict[str, str] - changed, # type: Set[str] - generated, # type: List[str] - lib_dir, # type: str -): - # type: (...) -> List[InstalledCSVRow] - """ - :param installed: A map from archive RECORD path to installation RECORD - path. - """ - installed_rows = [] # type: List[InstalledCSVRow] - for row in old_csv_rows: - if len(row) > 3: - logger.warning( - 'RECORD line has more than three elements: {}'.format(row) - ) - # Make a copy because we are mutating the row. - row = list(row) - old_path = row[0] - new_path = installed.pop(old_path, old_path) - row[0] = new_path - if new_path in changed: - digest, length = rehash(new_path) - row[1] = digest - row[2] = length - installed_rows.append(tuple(row)) - for f in generated: - digest, length = rehash(f) - installed_rows.append((normpath(f, lib_dir), digest, str(length))) - for f in installed: - installed_rows.append((installed[f], '', '')) - return installed_rows - - -class MissingCallableSuffix(Exception): - pass - - -def _raise_for_invalid_entrypoint(specification): - # type: (str) -> None - entry = get_export_entry(specification) - if entry is not None and entry.suffix is None: - raise MissingCallableSuffix(str(entry)) - - -class PipScriptMaker(ScriptMaker): - def make(self, specification, options=None): - # type: (str, Dict[str, Any]) -> List[str] - _raise_for_invalid_entrypoint(specification) - return super(PipScriptMaker, self).make(specification, options) - - -def install_unpacked_wheel( - name, # type: str - wheeldir, # type: str - wheel_zip, # type: ZipFile - scheme, # type: Scheme - req_description, # type: str - pycompile=True, # type: bool - warn_script_location=True, # type: bool - direct_url=None, # type: Optional[DirectUrl] -): - # type: (...) -> None - """Install a wheel. - - :param name: Name of the project to install - :param wheeldir: Base directory of the unpacked wheel - :param wheel_zip: open ZipFile for wheel being installed - :param scheme: Distutils scheme dictating the install directories - :param req_description: String used in place of the requirement, for - logging - :param pycompile: Whether to byte-compile installed Python files - :param warn_script_location: Whether to check that scripts are installed - into a directory on PATH - :raises UnsupportedWheel: - * when the directory holds an unpacked wheel with incompatible - Wheel-Version - * when the .dist-info dir does not match the wheel - """ - # TODO: Investigate and break this up. - # TODO: Look into moving this into a dedicated class for representing an - # installation. - - source = wheeldir.rstrip(os.path.sep) + os.path.sep - - info_dir, metadata = parse_wheel(wheel_zip, name) - - if wheel_root_is_purelib(metadata): - lib_dir = scheme.purelib - else: - lib_dir = scheme.platlib - - subdirs = os.listdir(source) - data_dirs = [s for s in subdirs if s.endswith('.data')] - - # Record details of the files moved - # installed = files copied from the wheel to the destination - # changed = files changed while installing (scripts #! line typically) - # generated = files newly generated during the install (script wrappers) - installed = {} # type: Dict[str, str] - changed = set() - generated = [] # type: List[str] - - # Compile all of the pyc files that we're going to be installing - if pycompile: - with captured_stdout() as stdout: - with warnings.catch_warnings(): - warnings.filterwarnings('ignore') - compileall.compile_dir(source, force=True, quiet=True) - logger.debug(stdout.getvalue()) - - def record_installed(srcfile, destfile, modified=False): - # type: (str, str, bool) -> None - """Map archive RECORD paths to installation RECORD paths.""" - oldpath = normpath(srcfile, wheeldir) - newpath = normpath(destfile, lib_dir) - installed[oldpath] = newpath - if modified: - changed.add(destfile) - - def clobber( - source, # type: str - dest, # type: str - is_base, # type: bool - fixer=None, # type: Optional[Callable[[str], Any]] - filter=None # type: Optional[Callable[[str], bool]] - ): - # type: (...) -> None - ensure_dir(dest) # common for the 'include' path - - for dir, subdirs, files in os.walk(source): - basedir = dir[len(source):].lstrip(os.path.sep) - destdir = os.path.join(dest, basedir) - if is_base and basedir == '': - subdirs[:] = [s for s in subdirs if not s.endswith('.data')] - for f in files: - # Skip unwanted files - if filter and filter(f): - continue - srcfile = os.path.join(dir, f) - destfile = os.path.join(dest, basedir, f) - # directory creation is lazy and after the file filtering above - # to ensure we don't install empty dirs; empty dirs can't be - # uninstalled. - ensure_dir(destdir) - - # copyfile (called below) truncates the destination if it - # exists and then writes the new contents. This is fine in most - # cases, but can cause a segfault if pip has loaded a shared - # object (e.g. from pyopenssl through its vendored urllib3) - # Since the shared object is mmap'd an attempt to call a - # symbol in it will then cause a segfault. Unlinking the file - # allows writing of new contents while allowing the process to - # continue to use the old copy. - if os.path.exists(destfile): - os.unlink(destfile) - - # We use copyfile (not move, copy, or copy2) to be extra sure - # that we are not moving directories over (copyfile fails for - # directories) as well as to ensure that we are not copying - # over any metadata because we want more control over what - # metadata we actually copy over. - shutil.copyfile(srcfile, destfile) - - # Copy over the metadata for the file, currently this only - # includes the atime and mtime. - st = os.stat(srcfile) - if hasattr(os, "utime"): - os.utime(destfile, (st.st_atime, st.st_mtime)) - - # If our file is executable, then make our destination file - # executable. - if os.access(srcfile, os.X_OK): - st = os.stat(srcfile) - permissions = ( - st.st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH - ) - os.chmod(destfile, permissions) - - changed = False - if fixer: - changed = fixer(destfile) - record_installed(srcfile, destfile, changed) - - clobber(source, lib_dir, True) - - dest_info_dir = os.path.join(lib_dir, info_dir) - - # Get the defined entry points - ep_file = os.path.join(dest_info_dir, 'entry_points.txt') - console, gui = get_entrypoints(ep_file) - - def is_entrypoint_wrapper(name): - # type: (str) -> bool - # EP, EP.exe and EP-script.py are scripts generated for - # entry point EP by setuptools - if name.lower().endswith('.exe'): - matchname = name[:-4] - elif name.lower().endswith('-script.py'): - matchname = name[:-10] - elif name.lower().endswith(".pya"): - matchname = name[:-4] - else: - matchname = name - # Ignore setuptools-generated scripts - return (matchname in console or matchname in gui) - - for datadir in data_dirs: - fixer = None - filter = None - for subdir in os.listdir(os.path.join(wheeldir, datadir)): - fixer = None - if subdir == 'scripts': - fixer = fix_script - filter = is_entrypoint_wrapper - source = os.path.join(wheeldir, datadir, subdir) - dest = getattr(scheme, subdir) - clobber(source, dest, False, fixer=fixer, filter=filter) - - maker = PipScriptMaker(None, scheme.scripts) - - # Ensure old scripts are overwritten. - # See https://github.com/pypa/pip/issues/1800 - maker.clobber = True - - # Ensure we don't generate any variants for scripts because this is almost - # never what somebody wants. - # See https://bitbucket.org/pypa/distlib/issue/35/ - maker.variants = {''} - - # This is required because otherwise distlib creates scripts that are not - # executable. - # See https://bitbucket.org/pypa/distlib/issue/32/ - maker.set_mode = True - - scripts_to_generate = [] - - # Special case pip and setuptools to generate versioned wrappers - # - # The issue is that some projects (specifically, pip and setuptools) use - # code in setup.py to create "versioned" entry points - pip2.7 on Python - # 2.7, pip3.3 on Python 3.3, etc. But these entry points are baked into - # the wheel metadata at build time, and so if the wheel is installed with - # a *different* version of Python the entry points will be wrong. The - # correct fix for this is to enhance the metadata to be able to describe - # such versioned entry points, but that won't happen till Metadata 2.0 is - # available. - # In the meantime, projects using versioned entry points will either have - # incorrect versioned entry points, or they will not be able to distribute - # "universal" wheels (i.e., they will need a wheel per Python version). - # - # Because setuptools and pip are bundled with _ensurepip and virtualenv, - # we need to use universal wheels. So, as a stopgap until Metadata 2.0, we - # override the versioned entry points in the wheel and generate the - # correct ones. This code is purely a short-term measure until Metadata 2.0 - # is available. - # - # To add the level of hack in this section of code, in order to support - # ensurepip this code will look for an ``ENSUREPIP_OPTIONS`` environment - # variable which will control which version scripts get installed. - # - # ENSUREPIP_OPTIONS=altinstall - # - Only pipX.Y and easy_install-X.Y will be generated and installed - # ENSUREPIP_OPTIONS=install - # - pipX.Y, pipX, easy_install-X.Y will be generated and installed. Note - # that this option is technically if ENSUREPIP_OPTIONS is set and is - # not altinstall - # DEFAULT - # - The default behavior is to install pip, pipX, pipX.Y, easy_install - # and easy_install-X.Y. - pip_script = console.pop('pip', None) - if pip_script: - if "ENSUREPIP_OPTIONS" not in os.environ: - scripts_to_generate.append('pip = ' + pip_script) - - if os.environ.get("ENSUREPIP_OPTIONS", "") != "altinstall": - scripts_to_generate.append( - 'pip{} = {}'.format(sys.version_info[0], pip_script) - ) - - scripts_to_generate.append( - 'pip{} = {}'.format(get_major_minor_version(), pip_script) - ) - # Delete any other versioned pip entry points - pip_ep = [k for k in console if re.match(r'pip(\d(\.\d)?)?$', k)] - for k in pip_ep: - del console[k] - easy_install_script = console.pop('easy_install', None) - if easy_install_script: - if "ENSUREPIP_OPTIONS" not in os.environ: - scripts_to_generate.append( - 'easy_install = ' + easy_install_script - ) - - scripts_to_generate.append( - 'easy_install-{} = {}'.format( - get_major_minor_version(), easy_install_script - ) - ) - # Delete any other versioned easy_install entry points - easy_install_ep = [ - k for k in console if re.match(r'easy_install(-\d\.\d)?$', k) - ] - for k in easy_install_ep: - del console[k] - - # Generate the console and GUI entry points specified in the wheel - scripts_to_generate.extend(starmap('{} = {}'.format, console.items())) - - gui_scripts_to_generate = list(starmap('{} = {}'.format, gui.items())) - - generated_console_scripts = [] # type: List[str] - - try: - generated_console_scripts = maker.make_multiple(scripts_to_generate) - generated.extend(generated_console_scripts) - - generated.extend( - maker.make_multiple(gui_scripts_to_generate, {'gui': True}) - ) - except MissingCallableSuffix as e: - entry = e.args[0] - raise InstallationError( - "Invalid script entry point: {} for req: {} - A callable " - "suffix is required. Cf https://packaging.python.org/" - "specifications/entry-points/#use-for-scripts for more " - "information.".format(entry, req_description) - ) - - if warn_script_location: - msg = message_about_scripts_not_on_PATH(generated_console_scripts) - if msg is not None: - logger.warning(msg) - - generated_file_mode = 0o666 & ~current_umask() - - @contextlib.contextmanager - def _generate_file(path, **kwargs): - # type: (str, **Any) -> Iterator[NamedTemporaryFileResult] - with adjacent_tmp_file(path, **kwargs) as f: - yield f - os.chmod(f.name, generated_file_mode) - replace(f.name, path) - - # Record pip as the installer - installer_path = os.path.join(dest_info_dir, 'INSTALLER') - with _generate_file(installer_path) as installer_file: - installer_file.write(b'pip\n') - generated.append(installer_path) - - # Record the PEP 610 direct URL reference - if direct_url is not None: - direct_url_path = os.path.join(dest_info_dir, DIRECT_URL_METADATA_NAME) - with _generate_file(direct_url_path) as direct_url_file: - direct_url_file.write(direct_url.to_json().encode("utf-8")) - generated.append(direct_url_path) - - # Record details of all files installed - record_path = os.path.join(dest_info_dir, 'RECORD') - with open(record_path, **csv_io_kwargs('r')) as record_file: - rows = get_csv_rows_for_installed( - csv.reader(record_file), - installed=installed, - changed=changed, - generated=generated, - lib_dir=lib_dir) - with _generate_file(record_path, **csv_io_kwargs('w')) as record_file: - writer = csv.writer(record_file) - writer.writerows(sorted_outrows(rows)) # sort to simplify testing - - -def install_wheel( - name, # type: str - wheel_path, # type: str - scheme, # type: Scheme - req_description, # type: str - pycompile=True, # type: bool - warn_script_location=True, # type: bool - _temp_dir_for_testing=None, # type: Optional[str] - direct_url=None, # type: Optional[DirectUrl] -): - # type: (...) -> None - with TempDirectory( - path=_temp_dir_for_testing, kind="unpacked-wheel" - ) as unpacked_dir, ZipFile(wheel_path, allowZip64=True) as z: - unpack_file(wheel_path, unpacked_dir.path) - install_unpacked_wheel( - name=name, - wheeldir=unpacked_dir.path, - wheel_zip=z, - scheme=scheme, - req_description=req_description, - pycompile=pycompile, - warn_script_location=warn_script_location, - direct_url=direct_url, - ) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/operations/prepare.py b/venv/lib/python3.8/site-packages/pip/_internal/operations/prepare.py deleted file mode 100644 index 1fcbb77..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/operations/prepare.py +++ /dev/null @@ -1,568 +0,0 @@ -"""Prepares a distribution for installation -""" - -# The following comment should be removed at some point in the future. -# mypy: strict-optional=False - -import logging -import mimetypes -import os -import shutil - -from pip._vendor import requests -from pip._vendor.six import PY2 - -from pip._internal.distributions import ( - make_distribution_for_install_requirement, -) -from pip._internal.distributions.installed import InstalledDistribution -from pip._internal.exceptions import ( - DirectoryUrlHashUnsupported, - HashMismatch, - HashUnpinned, - InstallationError, - PreviousBuildDirError, - VcsHashUnsupported, -) -from pip._internal.utils.filesystem import copy2_fixed -from pip._internal.utils.hashes import MissingHashes -from pip._internal.utils.logging import indent_log -from pip._internal.utils.misc import ( - display_path, - hide_url, - path_to_display, - rmtree, -) -from pip._internal.utils.temp_dir import TempDirectory -from pip._internal.utils.typing import MYPY_CHECK_RUNNING -from pip._internal.utils.unpacking import unpack_file -from pip._internal.vcs import vcs - -if MYPY_CHECK_RUNNING: - from typing import ( - Callable, List, Optional, Tuple, - ) - - from mypy_extensions import TypedDict - - from pip._internal.distributions import AbstractDistribution - from pip._internal.index.package_finder import PackageFinder - from pip._internal.models.link import Link - from pip._internal.network.download import Downloader - from pip._internal.req.req_install import InstallRequirement - from pip._internal.req.req_tracker import RequirementTracker - from pip._internal.utils.hashes import Hashes - - if PY2: - CopytreeKwargs = TypedDict( - 'CopytreeKwargs', - { - 'ignore': Callable[[str, List[str]], List[str]], - 'symlinks': bool, - }, - total=False, - ) - else: - CopytreeKwargs = TypedDict( - 'CopytreeKwargs', - { - 'copy_function': Callable[[str, str], None], - 'ignore': Callable[[str, List[str]], List[str]], - 'ignore_dangling_symlinks': bool, - 'symlinks': bool, - }, - total=False, - ) - -logger = logging.getLogger(__name__) - - -def _get_prepared_distribution( - req, # type: InstallRequirement - req_tracker, # type: RequirementTracker - finder, # type: PackageFinder - build_isolation # type: bool -): - # type: (...) -> AbstractDistribution - """Prepare a distribution for installation. - """ - abstract_dist = make_distribution_for_install_requirement(req) - with req_tracker.track(req): - abstract_dist.prepare_distribution_metadata(finder, build_isolation) - return abstract_dist - - -def unpack_vcs_link(link, location): - # type: (Link, str) -> None - vcs_backend = vcs.get_backend_for_scheme(link.scheme) - assert vcs_backend is not None - vcs_backend.unpack(location, url=hide_url(link.url)) - - -class File(object): - def __init__(self, path, content_type): - # type: (str, str) -> None - self.path = path - self.content_type = content_type - - -def get_http_url( - link, # type: Link - downloader, # type: Downloader - download_dir=None, # type: Optional[str] - hashes=None, # type: Optional[Hashes] -): - # type: (...) -> File - temp_dir = TempDirectory(kind="unpack", globally_managed=True) - # If a download dir is specified, is the file already downloaded there? - already_downloaded_path = None - if download_dir: - already_downloaded_path = _check_download_dir( - link, download_dir, hashes - ) - - if already_downloaded_path: - from_path = already_downloaded_path - content_type = mimetypes.guess_type(from_path)[0] - else: - # let's download to a tmp dir - from_path, content_type = _download_http_url( - link, downloader, temp_dir.path, hashes - ) - - return File(from_path, content_type) - - -def _copy2_ignoring_special_files(src, dest): - # type: (str, str) -> None - """Copying special files is not supported, but as a convenience to users - we skip errors copying them. This supports tools that may create e.g. - socket files in the project source directory. - """ - try: - copy2_fixed(src, dest) - except shutil.SpecialFileError as e: - # SpecialFileError may be raised due to either the source or - # destination. If the destination was the cause then we would actually - # care, but since the destination directory is deleted prior to - # copy we ignore all of them assuming it is caused by the source. - logger.warning( - "Ignoring special file error '%s' encountered copying %s to %s.", - str(e), - path_to_display(src), - path_to_display(dest), - ) - - -def _copy_source_tree(source, target): - # type: (str, str) -> None - target_abspath = os.path.abspath(target) - target_basename = os.path.basename(target_abspath) - target_dirname = os.path.dirname(target_abspath) - - def ignore(d, names): - # type: (str, List[str]) -> List[str] - skipped = [] # type: List[str] - if d == source: - # Pulling in those directories can potentially be very slow, - # exclude the following directories if they appear in the top - # level dir (and only it). - # See discussion at https://github.com/pypa/pip/pull/6770 - skipped += ['.tox', '.nox'] - if os.path.abspath(d) == target_dirname: - # Prevent an infinite recursion if the target is in source. - # This can happen when TMPDIR is set to ${PWD}/... - # and we copy PWD to TMPDIR. - skipped += [target_basename] - return skipped - - kwargs = dict(ignore=ignore, symlinks=True) # type: CopytreeKwargs - - if not PY2: - # Python 2 does not support copy_function, so we only ignore - # errors on special file copy in Python 3. - kwargs['copy_function'] = _copy2_ignoring_special_files - - shutil.copytree(source, target, **kwargs) - - -def get_file_url( - link, # type: Link - download_dir=None, # type: Optional[str] - hashes=None # type: Optional[Hashes] -): - # type: (...) -> File - """Get file and optionally check its hash. - """ - # If a download dir is specified, is the file already there and valid? - already_downloaded_path = None - if download_dir: - already_downloaded_path = _check_download_dir( - link, download_dir, hashes - ) - - if already_downloaded_path: - from_path = already_downloaded_path - else: - from_path = link.file_path - - # If --require-hashes is off, `hashes` is either empty, the - # link's embedded hash, or MissingHashes; it is required to - # match. If --require-hashes is on, we are satisfied by any - # hash in `hashes` matching: a URL-based or an option-based - # one; no internet-sourced hash will be in `hashes`. - if hashes: - hashes.check_against_path(from_path) - - content_type = mimetypes.guess_type(from_path)[0] - - return File(from_path, content_type) - - -def unpack_url( - link, # type: Link - location, # type: str - downloader, # type: Downloader - download_dir=None, # type: Optional[str] - hashes=None, # type: Optional[Hashes] -): - # type: (...) -> Optional[File] - """Unpack link into location, downloading if required. - - :param hashes: A Hashes object, one of whose embedded hashes must match, - or HashMismatch will be raised. If the Hashes is empty, no matches are - required, and unhashable types of requirements (like VCS ones, which - would ordinarily raise HashUnsupported) are allowed. - """ - # non-editable vcs urls - if link.is_vcs: - unpack_vcs_link(link, location) - return None - - # If it's a url to a local directory - if link.is_existing_dir(): - if os.path.isdir(location): - rmtree(location) - _copy_source_tree(link.file_path, location) - return None - - # file urls - if link.is_file: - file = get_file_url(link, download_dir, hashes=hashes) - - # http urls - else: - file = get_http_url( - link, - downloader, - download_dir, - hashes=hashes, - ) - - # unpack the archive to the build dir location. even when only downloading - # archives, they have to be unpacked to parse dependencies - unpack_file(file.path, location, file.content_type) - - return file - - -def _download_http_url( - link, # type: Link - downloader, # type: Downloader - temp_dir, # type: str - hashes, # type: Optional[Hashes] -): - # type: (...) -> Tuple[str, str] - """Download link url into temp_dir using provided session""" - download = downloader(link) - - file_path = os.path.join(temp_dir, download.filename) - with open(file_path, 'wb') as content_file: - for chunk in download.chunks: - content_file.write(chunk) - - if hashes: - hashes.check_against_path(file_path) - - return file_path, download.response.headers.get('content-type', '') - - -def _check_download_dir(link, download_dir, hashes): - # type: (Link, str, Optional[Hashes]) -> Optional[str] - """ Check download_dir for previously downloaded file with correct hash - If a correct file is found return its path else None - """ - download_path = os.path.join(download_dir, link.filename) - - if not os.path.exists(download_path): - return None - - # If already downloaded, does its hash match? - logger.info('File was already downloaded %s', download_path) - if hashes: - try: - hashes.check_against_path(download_path) - except HashMismatch: - logger.warning( - 'Previously-downloaded file %s has bad hash. ' - 'Re-downloading.', - download_path - ) - os.unlink(download_path) - return None - return download_path - - -class RequirementPreparer(object): - """Prepares a Requirement - """ - - def __init__( - self, - build_dir, # type: str - download_dir, # type: Optional[str] - src_dir, # type: str - wheel_download_dir, # type: Optional[str] - build_isolation, # type: bool - req_tracker, # type: RequirementTracker - downloader, # type: Downloader - finder, # type: PackageFinder - require_hashes, # type: bool - use_user_site, # type: bool - ): - # type: (...) -> None - super(RequirementPreparer, self).__init__() - - self.src_dir = src_dir - self.build_dir = build_dir - self.req_tracker = req_tracker - self.downloader = downloader - self.finder = finder - - # Where still-packed archives should be written to. If None, they are - # not saved, and are deleted immediately after unpacking. - self.download_dir = download_dir - - # Where still-packed .whl files should be written to. If None, they are - # written to the download_dir parameter. Separate to download_dir to - # permit only keeping wheel archives for pip wheel. - self.wheel_download_dir = wheel_download_dir - - # NOTE - # download_dir and wheel_download_dir overlap semantically and may - # be combined if we're willing to have non-wheel archives present in - # the wheelhouse output by 'pip wheel'. - - # Is build isolation allowed? - self.build_isolation = build_isolation - - # Should hash-checking be required? - self.require_hashes = require_hashes - - # Should install in user site-packages? - self.use_user_site = use_user_site - - @property - def _download_should_save(self): - # type: () -> bool - if not self.download_dir: - return False - - if os.path.exists(self.download_dir): - return True - - logger.critical('Could not find download directory') - raise InstallationError( - "Could not find or access download directory '{}'" - .format(self.download_dir)) - - def prepare_linked_requirement( - self, - req, # type: InstallRequirement - ): - # type: (...) -> AbstractDistribution - """Prepare a requirement that would be obtained from req.link - """ - assert req.link - link = req.link - - # TODO: Breakup into smaller functions - if link.scheme == 'file': - path = link.file_path - logger.info('Processing %s', display_path(path)) - else: - logger.info('Collecting %s', req.req or req) - - download_dir = self.download_dir - if link.is_wheel and self.wheel_download_dir: - # when doing 'pip wheel` we download wheels to a - # dedicated dir. - download_dir = self.wheel_download_dir - - if link.is_wheel: - if download_dir: - # When downloading, we only unpack wheels to get - # metadata. - autodelete_unpacked = True - else: - # When installing a wheel, we use the unpacked - # wheel. - autodelete_unpacked = False - else: - # We always delete unpacked sdists after pip runs. - autodelete_unpacked = True - - with indent_log(): - # Since source_dir is only set for editable requirements. - assert req.source_dir is None - req.ensure_has_source_dir(self.build_dir, autodelete_unpacked) - # If a checkout exists, it's unwise to keep going. version - # inconsistencies are logged later, but do not fail the - # installation. - # FIXME: this won't upgrade when there's an existing - # package unpacked in `req.source_dir` - if os.path.exists(os.path.join(req.source_dir, 'setup.py')): - raise PreviousBuildDirError( - "pip can't proceed with requirements '{}' due to a" - " pre-existing build directory ({}). This is " - "likely due to a previous installation that failed" - ". pip is being responsible and not assuming it " - "can delete this. Please delete it and try again." - .format(req, req.source_dir) - ) - - # Now that we have the real link, we can tell what kind of - # requirements we have and raise some more informative errors - # than otherwise. (For example, we can raise VcsHashUnsupported - # for a VCS URL rather than HashMissing.) - if self.require_hashes: - # We could check these first 2 conditions inside - # unpack_url and save repetition of conditions, but then - # we would report less-useful error messages for - # unhashable requirements, complaining that there's no - # hash provided. - if link.is_vcs: - raise VcsHashUnsupported() - elif link.is_existing_dir(): - raise DirectoryUrlHashUnsupported() - if not req.original_link and not req.is_pinned: - # Unpinned packages are asking for trouble when a new - # version is uploaded. This isn't a security check, but - # it saves users a surprising hash mismatch in the - # future. - # - # file:/// URLs aren't pinnable, so don't complain - # about them not being pinned. - raise HashUnpinned() - - hashes = req.hashes(trust_internet=not self.require_hashes) - if self.require_hashes and not hashes: - # Known-good hashes are missing for this requirement, so - # shim it with a facade object that will provoke hash - # computation and then raise a HashMissing exception - # showing the user what the hash should be. - hashes = MissingHashes() - - try: - local_file = unpack_url( - link, req.source_dir, self.downloader, download_dir, - hashes=hashes, - ) - except requests.HTTPError as exc: - logger.critical( - 'Could not install requirement %s because of error %s', - req, - exc, - ) - raise InstallationError( - 'Could not install requirement {} because of HTTP ' - 'error {} for URL {}'.format(req, exc, link) - ) - - # For use in later processing, preserve the file path on the - # requirement. - if local_file: - req.local_file_path = local_file.path - - abstract_dist = _get_prepared_distribution( - req, self.req_tracker, self.finder, self.build_isolation, - ) - - if download_dir: - if link.is_existing_dir(): - logger.info('Link is a directory, ignoring download_dir') - elif local_file: - download_location = os.path.join( - download_dir, link.filename - ) - if not os.path.exists(download_location): - shutil.copy(local_file.path, download_location) - logger.info( - 'Saved %s', display_path(download_location) - ) - - if self._download_should_save: - # Make a .zip of the source_dir we already created. - if link.is_vcs: - req.archive(self.download_dir) - return abstract_dist - - def prepare_editable_requirement( - self, - req, # type: InstallRequirement - ): - # type: (...) -> AbstractDistribution - """Prepare an editable requirement - """ - assert req.editable, "cannot prepare a non-editable req as editable" - - logger.info('Obtaining %s', req) - - with indent_log(): - if self.require_hashes: - raise InstallationError( - 'The editable requirement {} cannot be installed when ' - 'requiring hashes, because there is no single file to ' - 'hash.'.format(req) - ) - req.ensure_has_source_dir(self.src_dir) - req.update_editable(not self._download_should_save) - - abstract_dist = _get_prepared_distribution( - req, self.req_tracker, self.finder, self.build_isolation, - ) - - if self._download_should_save: - req.archive(self.download_dir) - req.check_if_exists(self.use_user_site) - - return abstract_dist - - def prepare_installed_requirement( - self, - req, # type: InstallRequirement - skip_reason # type: str - ): - # type: (...) -> AbstractDistribution - """Prepare an already-installed requirement - """ - assert req.satisfied_by, "req should have been satisfied but isn't" - assert skip_reason is not None, ( - "did not get skip reason skipped but req.satisfied_by " - "is set to {}".format(req.satisfied_by) - ) - logger.info( - 'Requirement %s: %s (%s)', - skip_reason, req, req.satisfied_by.version - ) - with indent_log(): - if self.require_hashes: - logger.debug( - 'Since it is already installed, we are trusting this ' - 'package without checking its hash. To ensure a ' - 'completely repeatable environment, install into an ' - 'empty virtualenv.' - ) - abstract_dist = InstalledDistribution(req) - - return abstract_dist diff --git a/venv/lib/python3.8/site-packages/pip/_internal/pyproject.py b/venv/lib/python3.8/site-packages/pip/_internal/pyproject.py deleted file mode 100644 index 6b4faf7..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/pyproject.py +++ /dev/null @@ -1,196 +0,0 @@ -from __future__ import absolute_import - -import io -import os -import sys -from collections import namedtuple - -from pip._vendor import six, toml -from pip._vendor.packaging.requirements import InvalidRequirement, Requirement - -from pip._internal.exceptions import InstallationError -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import Any, Optional, List - - -def _is_list_of_str(obj): - # type: (Any) -> bool - return ( - isinstance(obj, list) and - all(isinstance(item, six.string_types) for item in obj) - ) - - -def make_pyproject_path(unpacked_source_directory): - # type: (str) -> str - path = os.path.join(unpacked_source_directory, 'pyproject.toml') - - # Python2 __file__ should not be unicode - if six.PY2 and isinstance(path, six.text_type): - path = path.encode(sys.getfilesystemencoding()) - - return path - - -BuildSystemDetails = namedtuple('BuildSystemDetails', [ - 'requires', 'backend', 'check', 'backend_path' -]) - - -def load_pyproject_toml( - use_pep517, # type: Optional[bool] - pyproject_toml, # type: str - setup_py, # type: str - req_name # type: str -): - # type: (...) -> Optional[BuildSystemDetails] - """Load the pyproject.toml file. - - Parameters: - use_pep517 - Has the user requested PEP 517 processing? None - means the user hasn't explicitly specified. - pyproject_toml - Location of the project's pyproject.toml file - setup_py - Location of the project's setup.py file - req_name - The name of the requirement we're processing (for - error reporting) - - Returns: - None if we should use the legacy code path, otherwise a tuple - ( - requirements from pyproject.toml, - name of PEP 517 backend, - requirements we should check are installed after setting - up the build environment - directory paths to import the backend from (backend-path), - relative to the project root. - ) - """ - has_pyproject = os.path.isfile(pyproject_toml) - has_setup = os.path.isfile(setup_py) - - if has_pyproject: - with io.open(pyproject_toml, encoding="utf-8") as f: - pp_toml = toml.load(f) - build_system = pp_toml.get("build-system") - else: - build_system = None - - # The following cases must use PEP 517 - # We check for use_pep517 being non-None and falsey because that means - # the user explicitly requested --no-use-pep517. The value 0 as - # opposed to False can occur when the value is provided via an - # environment variable or config file option (due to the quirk of - # strtobool() returning an integer in pip's configuration code). - if has_pyproject and not has_setup: - if use_pep517 is not None and not use_pep517: - raise InstallationError( - "Disabling PEP 517 processing is invalid: " - "project does not have a setup.py" - ) - use_pep517 = True - elif build_system and "build-backend" in build_system: - if use_pep517 is not None and not use_pep517: - raise InstallationError( - "Disabling PEP 517 processing is invalid: " - "project specifies a build backend of {} " - "in pyproject.toml".format( - build_system["build-backend"] - ) - ) - use_pep517 = True - - # If we haven't worked out whether to use PEP 517 yet, - # and the user hasn't explicitly stated a preference, - # we do so if the project has a pyproject.toml file. - elif use_pep517 is None: - use_pep517 = has_pyproject - - # At this point, we know whether we're going to use PEP 517. - assert use_pep517 is not None - - # If we're using the legacy code path, there is nothing further - # for us to do here. - if not use_pep517: - return None - - if build_system is None: - # Either the user has a pyproject.toml with no build-system - # section, or the user has no pyproject.toml, but has opted in - # explicitly via --use-pep517. - # In the absence of any explicit backend specification, we - # assume the setuptools backend that most closely emulates the - # traditional direct setup.py execution, and require wheel and - # a version of setuptools that supports that backend. - - build_system = { - "requires": ["setuptools>=40.8.0", "wheel"], - "build-backend": "setuptools.build_meta:__legacy__", - } - - # If we're using PEP 517, we have build system information (either - # from pyproject.toml, or defaulted by the code above). - # Note that at this point, we do not know if the user has actually - # specified a backend, though. - assert build_system is not None - - # Ensure that the build-system section in pyproject.toml conforms - # to PEP 518. - error_template = ( - "{package} has a pyproject.toml file that does not comply " - "with PEP 518: {reason}" - ) - - # Specifying the build-system table but not the requires key is invalid - if "requires" not in build_system: - raise InstallationError( - error_template.format(package=req_name, reason=( - "it has a 'build-system' table but not " - "'build-system.requires' which is mandatory in the table" - )) - ) - - # Error out if requires is not a list of strings - requires = build_system["requires"] - if not _is_list_of_str(requires): - raise InstallationError(error_template.format( - package=req_name, - reason="'build-system.requires' is not a list of strings.", - )) - - # Each requirement must be valid as per PEP 508 - for requirement in requires: - try: - Requirement(requirement) - except InvalidRequirement: - raise InstallationError( - error_template.format( - package=req_name, - reason=( - "'build-system.requires' contains an invalid " - "requirement: {!r}".format(requirement) - ), - ) - ) - - backend = build_system.get("build-backend") - backend_path = build_system.get("backend-path", []) - check = [] # type: List[str] - if backend is None: - # If the user didn't specify a backend, we assume they want to use - # the setuptools backend. But we can't be sure they have included - # a version of setuptools which supplies the backend, or wheel - # (which is needed by the backend) in their requirements. So we - # make a note to check that those requirements are present once - # we have set up the environment. - # This is quite a lot of work to check for a very specific case. But - # the problem is, that case is potentially quite common - projects that - # adopted PEP 518 early for the ability to specify requirements to - # execute setup.py, but never considered needing to mention the build - # tools themselves. The original PEP 518 code had a similar check (but - # implemented in a different way). - backend = "setuptools.build_meta:__legacy__" - check = ["setuptools>=40.8.0", "wheel"] - - return BuildSystemDetails(requires, backend, check, backend_path) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/req/__init__.py b/venv/lib/python3.8/site-packages/pip/_internal/req/__init__.py deleted file mode 100644 index d2d027a..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/req/__init__.py +++ /dev/null @@ -1,92 +0,0 @@ -# The following comment should be removed at some point in the future. -# mypy: strict-optional=False - -from __future__ import absolute_import - -import logging - -from pip._internal.utils.logging import indent_log -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -from .req_file import parse_requirements -from .req_install import InstallRequirement -from .req_set import RequirementSet - -if MYPY_CHECK_RUNNING: - from typing import Any, List, Sequence - -__all__ = [ - "RequirementSet", "InstallRequirement", - "parse_requirements", "install_given_reqs", -] - -logger = logging.getLogger(__name__) - - -class InstallationResult(object): - def __init__(self, name): - # type: (str) -> None - self.name = name - - def __repr__(self): - # type: () -> str - return "InstallationResult(name={!r})".format(self.name) - - -def install_given_reqs( - to_install, # type: List[InstallRequirement] - install_options, # type: List[str] - global_options=(), # type: Sequence[str] - *args, # type: Any - **kwargs # type: Any -): - # type: (...) -> List[InstallationResult] - """ - Install everything in the given list. - - (to be called after having downloaded and unpacked the packages) - """ - - if to_install: - logger.info( - 'Installing collected packages: %s', - ', '.join([req.name for req in to_install]), - ) - - installed = [] - - with indent_log(): - for requirement in to_install: - if requirement.should_reinstall: - logger.info('Attempting uninstall: %s', requirement.name) - with indent_log(): - uninstalled_pathset = requirement.uninstall( - auto_confirm=True - ) - try: - requirement.install( - install_options, - global_options, - *args, - **kwargs - ) - except Exception: - should_rollback = ( - requirement.should_reinstall and - not requirement.install_succeeded - ) - # if install did not succeed, rollback previous uninstall - if should_rollback: - uninstalled_pathset.rollback() - raise - else: - should_commit = ( - requirement.should_reinstall and - requirement.install_succeeded - ) - if should_commit: - uninstalled_pathset.commit() - - installed.append(InstallationResult(requirement.name)) - - return installed diff --git a/venv/lib/python3.8/site-packages/pip/_internal/req/constructors.py b/venv/lib/python3.8/site-packages/pip/_internal/req/constructors.py deleted file mode 100644 index c9f1fe7..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/req/constructors.py +++ /dev/null @@ -1,464 +0,0 @@ -"""Backing implementation for InstallRequirement's various constructors - -The idea here is that these formed a major chunk of InstallRequirement's size -so, moving them and support code dedicated to them outside of that class -helps creates for better understandability for the rest of the code. - -These are meant to be used elsewhere within pip to create instances of -InstallRequirement. -""" - -# The following comment should be removed at some point in the future. -# mypy: strict-optional=False - -import logging -import os -import re - -from pip._vendor.packaging.markers import Marker -from pip._vendor.packaging.requirements import InvalidRequirement, Requirement -from pip._vendor.packaging.specifiers import Specifier -from pip._vendor.pkg_resources import RequirementParseError, parse_requirements - -from pip._internal.exceptions import InstallationError -from pip._internal.models.index import PyPI, TestPyPI -from pip._internal.models.link import Link -from pip._internal.models.wheel import Wheel -from pip._internal.pyproject import make_pyproject_path -from pip._internal.req.req_install import InstallRequirement -from pip._internal.utils.filetypes import ARCHIVE_EXTENSIONS -from pip._internal.utils.misc import is_installable_dir, splitext -from pip._internal.utils.typing import MYPY_CHECK_RUNNING -from pip._internal.utils.urls import path_to_url -from pip._internal.vcs import is_url, vcs - -if MYPY_CHECK_RUNNING: - from typing import ( - Any, Dict, Optional, Set, Tuple, Union, - ) - from pip._internal.req.req_file import ParsedRequirement - - -__all__ = [ - "install_req_from_editable", "install_req_from_line", - "parse_editable" -] - -logger = logging.getLogger(__name__) -operators = Specifier._operators.keys() - - -def is_archive_file(name): - # type: (str) -> bool - """Return True if `name` is a considered as an archive file.""" - ext = splitext(name)[1].lower() - if ext in ARCHIVE_EXTENSIONS: - return True - return False - - -def _strip_extras(path): - # type: (str) -> Tuple[str, Optional[str]] - m = re.match(r'^(.+)(\[[^\]]+\])$', path) - extras = None - if m: - path_no_extras = m.group(1) - extras = m.group(2) - else: - path_no_extras = path - - return path_no_extras, extras - - -def convert_extras(extras): - # type: (Optional[str]) -> Set[str] - if not extras: - return set() - return Requirement("placeholder" + extras.lower()).extras - - -def parse_editable(editable_req): - # type: (str) -> Tuple[Optional[str], str, Optional[Set[str]]] - """Parses an editable requirement into: - - a requirement name - - an URL - - extras - - editable options - Accepted requirements: - svn+http://blahblah@rev#egg=Foobar[baz]&subdirectory=version_subdir - .[some_extra] - """ - - url = editable_req - - # If a file path is specified with extras, strip off the extras. - url_no_extras, extras = _strip_extras(url) - - if os.path.isdir(url_no_extras): - if not os.path.exists(os.path.join(url_no_extras, 'setup.py')): - msg = ( - 'File "setup.py" not found. Directory cannot be installed ' - 'in editable mode: {}'.format(os.path.abspath(url_no_extras)) - ) - pyproject_path = make_pyproject_path(url_no_extras) - if os.path.isfile(pyproject_path): - msg += ( - '\n(A "pyproject.toml" file was found, but editable ' - 'mode currently requires a setup.py based build.)' - ) - raise InstallationError(msg) - - # Treating it as code that has already been checked out - url_no_extras = path_to_url(url_no_extras) - - if url_no_extras.lower().startswith('file:'): - package_name = Link(url_no_extras).egg_fragment - if extras: - return ( - package_name, - url_no_extras, - Requirement("placeholder" + extras.lower()).extras, - ) - else: - return package_name, url_no_extras, None - - for version_control in vcs: - if url.lower().startswith('{}:'.format(version_control)): - url = '{}+{}'.format(version_control, url) - break - - if '+' not in url: - raise InstallationError( - '{} is not a valid editable requirement. ' - 'It should either be a path to a local project or a VCS URL ' - '(beginning with svn+, git+, hg+, or bzr+).'.format(editable_req) - ) - - vc_type = url.split('+', 1)[0].lower() - - if not vcs.get_backend(vc_type): - backends = ", ".join([bends.name + '+URL' for bends in vcs.backends]) - error_message = "For --editable={}, " \ - "only {} are currently supported".format( - editable_req, backends) - raise InstallationError(error_message) - - package_name = Link(url).egg_fragment - if not package_name: - raise InstallationError( - "Could not detect requirement name for '{}', please specify one " - "with #egg=your_package_name".format(editable_req) - ) - return package_name, url, None - - -def deduce_helpful_msg(req): - # type: (str) -> str - """Returns helpful msg in case requirements file does not exist, - or cannot be parsed. - - :params req: Requirements file path - """ - msg = "" - if os.path.exists(req): - msg = " It does exist." - # Try to parse and check if it is a requirements file. - try: - with open(req, 'r') as fp: - # parse first line only - next(parse_requirements(fp.read())) - msg += ( - "The argument you provided " - "({}) appears to be a" - " requirements file. If that is the" - " case, use the '-r' flag to install" - " the packages specified within it." - ).format(req) - except RequirementParseError: - logger.debug("Cannot parse '{}' as requirements \ - file".format(req), exc_info=True) - else: - msg += " File '{}' does not exist.".format(req) - return msg - - -class RequirementParts(object): - def __init__( - self, - requirement, # type: Optional[Requirement] - link, # type: Optional[Link] - markers, # type: Optional[Marker] - extras, # type: Set[str] - ): - self.requirement = requirement - self.link = link - self.markers = markers - self.extras = extras - - -def parse_req_from_editable(editable_req): - # type: (str) -> RequirementParts - name, url, extras_override = parse_editable(editable_req) - - if name is not None: - try: - req = Requirement(name) - except InvalidRequirement: - raise InstallationError("Invalid requirement: '{}'".format(name)) - else: - req = None - - link = Link(url) - - return RequirementParts(req, link, None, extras_override) - - -# ---- The actual constructors follow ---- - - -def install_req_from_editable( - editable_req, # type: str - comes_from=None, # type: Optional[Union[InstallRequirement, str]] - use_pep517=None, # type: Optional[bool] - isolated=False, # type: bool - options=None, # type: Optional[Dict[str, Any]] - constraint=False # type: bool -): - # type: (...) -> InstallRequirement - - parts = parse_req_from_editable(editable_req) - - return InstallRequirement( - parts.requirement, - comes_from=comes_from, - editable=True, - link=parts.link, - constraint=constraint, - use_pep517=use_pep517, - isolated=isolated, - install_options=options.get("install_options", []) if options else [], - global_options=options.get("global_options", []) if options else [], - hash_options=options.get("hashes", {}) if options else {}, - extras=parts.extras, - ) - - -def _looks_like_path(name): - # type: (str) -> bool - """Checks whether the string "looks like" a path on the filesystem. - - This does not check whether the target actually exists, only judge from the - appearance. - - Returns true if any of the following conditions is true: - * a path separator is found (either os.path.sep or os.path.altsep); - * a dot is found (which represents the current directory). - """ - if os.path.sep in name: - return True - if os.path.altsep is not None and os.path.altsep in name: - return True - if name.startswith("."): - return True - return False - - -def _get_url_from_path(path, name): - # type: (str, str) -> str - """ - First, it checks whether a provided path is an installable directory - (e.g. it has a setup.py). If it is, returns the path. - - If false, check if the path is an archive file (such as a .whl). - The function checks if the path is a file. If false, if the path has - an @, it will treat it as a PEP 440 URL requirement and return the path. - """ - if _looks_like_path(name) and os.path.isdir(path): - if is_installable_dir(path): - return path_to_url(path) - raise InstallationError( - "Directory {name!r} is not installable. Neither 'setup.py' " - "nor 'pyproject.toml' found.".format(**locals()) - ) - if not is_archive_file(path): - return None - if os.path.isfile(path): - return path_to_url(path) - urlreq_parts = name.split('@', 1) - if len(urlreq_parts) >= 2 and not _looks_like_path(urlreq_parts[0]): - # If the path contains '@' and the part before it does not look - # like a path, try to treat it as a PEP 440 URL req instead. - return None - logger.warning( - 'Requirement %r looks like a filename, but the ' - 'file does not exist', - name - ) - return path_to_url(path) - - -def parse_req_from_line(name, line_source): - # type: (str, Optional[str]) -> RequirementParts - if is_url(name): - marker_sep = '; ' - else: - marker_sep = ';' - if marker_sep in name: - name, markers_as_string = name.split(marker_sep, 1) - markers_as_string = markers_as_string.strip() - if not markers_as_string: - markers = None - else: - markers = Marker(markers_as_string) - else: - markers = None - name = name.strip() - req_as_string = None - path = os.path.normpath(os.path.abspath(name)) - link = None - extras_as_string = None - - if is_url(name): - link = Link(name) - else: - p, extras_as_string = _strip_extras(path) - url = _get_url_from_path(p, name) - if url is not None: - link = Link(url) - - # it's a local file, dir, or url - if link: - # Handle relative file URLs - if link.scheme == 'file' and re.search(r'\.\./', link.url): - link = Link( - path_to_url(os.path.normpath(os.path.abspath(link.path)))) - # wheel file - if link.is_wheel: - wheel = Wheel(link.filename) # can raise InvalidWheelFilename - req_as_string = "{wheel.name}=={wheel.version}".format(**locals()) - else: - # set the req to the egg fragment. when it's not there, this - # will become an 'unnamed' requirement - req_as_string = link.egg_fragment - - # a requirement specifier - else: - req_as_string = name - - extras = convert_extras(extras_as_string) - - def with_source(text): - # type: (str) -> str - if not line_source: - return text - return '{} (from {})'.format(text, line_source) - - if req_as_string is not None: - try: - req = Requirement(req_as_string) - except InvalidRequirement: - if os.path.sep in req_as_string: - add_msg = "It looks like a path." - add_msg += deduce_helpful_msg(req_as_string) - elif ('=' in req_as_string and - not any(op in req_as_string for op in operators)): - add_msg = "= is not a valid operator. Did you mean == ?" - else: - add_msg = '' - msg = with_source( - 'Invalid requirement: {!r}'.format(req_as_string) - ) - if add_msg: - msg += '\nHint: {}'.format(add_msg) - raise InstallationError(msg) - else: - req = None - - return RequirementParts(req, link, markers, extras) - - -def install_req_from_line( - name, # type: str - comes_from=None, # type: Optional[Union[str, InstallRequirement]] - use_pep517=None, # type: Optional[bool] - isolated=False, # type: bool - options=None, # type: Optional[Dict[str, Any]] - constraint=False, # type: bool - line_source=None, # type: Optional[str] -): - # type: (...) -> InstallRequirement - """Creates an InstallRequirement from a name, which might be a - requirement, directory containing 'setup.py', filename, or URL. - - :param line_source: An optional string describing where the line is from, - for logging purposes in case of an error. - """ - parts = parse_req_from_line(name, line_source) - - return InstallRequirement( - parts.requirement, comes_from, link=parts.link, markers=parts.markers, - use_pep517=use_pep517, isolated=isolated, - install_options=options.get("install_options", []) if options else [], - global_options=options.get("global_options", []) if options else [], - hash_options=options.get("hashes", {}) if options else {}, - constraint=constraint, - extras=parts.extras, - ) - - -def install_req_from_req_string( - req_string, # type: str - comes_from=None, # type: Optional[InstallRequirement] - isolated=False, # type: bool - use_pep517=None # type: Optional[bool] -): - # type: (...) -> InstallRequirement - try: - req = Requirement(req_string) - except InvalidRequirement: - raise InstallationError("Invalid requirement: '{}'".format(req_string)) - - domains_not_allowed = [ - PyPI.file_storage_domain, - TestPyPI.file_storage_domain, - ] - if (req.url and comes_from and comes_from.link and - comes_from.link.netloc in domains_not_allowed): - # Explicitly disallow pypi packages that depend on external urls - raise InstallationError( - "Packages installed from PyPI cannot depend on packages " - "which are not also hosted on PyPI.\n" - "{} depends on {} ".format(comes_from.name, req) - ) - - return InstallRequirement( - req, comes_from, isolated=isolated, use_pep517=use_pep517 - ) - - -def install_req_from_parsed_requirement( - parsed_req, # type: ParsedRequirement - isolated=False, # type: bool - use_pep517=None # type: Optional[bool] -): - # type: (...) -> InstallRequirement - if parsed_req.is_editable: - req = install_req_from_editable( - parsed_req.requirement, - comes_from=parsed_req.comes_from, - use_pep517=use_pep517, - constraint=parsed_req.constraint, - isolated=isolated, - ) - - else: - req = install_req_from_line( - parsed_req.requirement, - comes_from=parsed_req.comes_from, - use_pep517=use_pep517, - isolated=isolated, - options=parsed_req.options, - constraint=parsed_req.constraint, - line_source=parsed_req.line_source, - ) - return req diff --git a/venv/lib/python3.8/site-packages/pip/_internal/req/req_file.py b/venv/lib/python3.8/site-packages/pip/_internal/req/req_file.py deleted file mode 100644 index 63cab76..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/req/req_file.py +++ /dev/null @@ -1,582 +0,0 @@ -""" -Requirements file parsing -""" - -# The following comment should be removed at some point in the future. -# mypy: strict-optional=False - -from __future__ import absolute_import - -import optparse -import os -import re -import shlex -import sys - -from pip._vendor.six.moves.urllib import parse as urllib_parse - -from pip._internal.cli import cmdoptions -from pip._internal.exceptions import ( - InstallationError, - RequirementsFileParseError, -) -from pip._internal.models.search_scope import SearchScope -from pip._internal.utils.encoding import auto_decode -from pip._internal.utils.typing import MYPY_CHECK_RUNNING -from pip._internal.utils.urls import get_url_scheme - -if MYPY_CHECK_RUNNING: - from optparse import Values - from typing import ( - Any, Callable, Dict, Iterator, List, NoReturn, Optional, Text, Tuple, - ) - - from pip._internal.index.package_finder import PackageFinder - from pip._internal.network.session import PipSession - - ReqFileLines = Iterator[Tuple[int, Text]] - - LineParser = Callable[[Text], Tuple[str, Values]] - - -__all__ = ['parse_requirements'] - -SCHEME_RE = re.compile(r'^(http|https|file):', re.I) -COMMENT_RE = re.compile(r'(^|\s+)#.*$') - -# Matches environment variable-style values in '${MY_VARIABLE_1}' with the -# variable name consisting of only uppercase letters, digits or the '_' -# (underscore). This follows the POSIX standard defined in IEEE Std 1003.1, -# 2013 Edition. -ENV_VAR_RE = re.compile(r'(?P<var>\$\{(?P<name>[A-Z0-9_]+)\})') - -SUPPORTED_OPTIONS = [ - cmdoptions.index_url, - cmdoptions.extra_index_url, - cmdoptions.no_index, - cmdoptions.constraints, - cmdoptions.requirements, - cmdoptions.editable, - cmdoptions.find_links, - cmdoptions.no_binary, - cmdoptions.only_binary, - cmdoptions.require_hashes, - cmdoptions.pre, - cmdoptions.trusted_host, - cmdoptions.always_unzip, # Deprecated -] # type: List[Callable[..., optparse.Option]] - -# options to be passed to requirements -SUPPORTED_OPTIONS_REQ = [ - cmdoptions.install_options, - cmdoptions.global_options, - cmdoptions.hash, -] # type: List[Callable[..., optparse.Option]] - -# the 'dest' string values -SUPPORTED_OPTIONS_REQ_DEST = [str(o().dest) for o in SUPPORTED_OPTIONS_REQ] - - -class ParsedRequirement(object): - def __init__( - self, - requirement, # type:str - is_editable, # type: bool - comes_from, # type: str - constraint, # type: bool - options=None, # type: Optional[Dict[str, Any]] - line_source=None, # type: Optional[str] - ): - # type: (...) -> None - self.requirement = requirement - self.is_editable = is_editable - self.comes_from = comes_from - self.options = options - self.constraint = constraint - self.line_source = line_source - - -class ParsedLine(object): - def __init__( - self, - filename, # type: str - lineno, # type: int - comes_from, # type: str - args, # type: str - opts, # type: Values - constraint, # type: bool - ): - # type: (...) -> None - self.filename = filename - self.lineno = lineno - self.comes_from = comes_from - self.opts = opts - self.constraint = constraint - - if args: - self.is_requirement = True - self.is_editable = False - self.requirement = args - elif opts.editables: - self.is_requirement = True - self.is_editable = True - # We don't support multiple -e on one line - self.requirement = opts.editables[0] - else: - self.is_requirement = False - - -def parse_requirements( - filename, # type: str - session, # type: PipSession - finder=None, # type: Optional[PackageFinder] - comes_from=None, # type: Optional[str] - options=None, # type: Optional[optparse.Values] - constraint=False, # type: bool -): - # type: (...) -> Iterator[ParsedRequirement] - """Parse a requirements file and yield InstallRequirement instances. - - :param filename: Path or url of requirements file. - :param session: PipSession instance. - :param finder: Instance of pip.index.PackageFinder. - :param comes_from: Origin description of requirements. - :param options: cli options. - :param constraint: If true, parsing a constraint file rather than - requirements file. - """ - line_parser = get_line_parser(finder) - parser = RequirementsFileParser(session, line_parser, comes_from) - - for parsed_line in parser.parse(filename, constraint): - parsed_req = handle_line( - parsed_line, - options=options, - finder=finder, - session=session - ) - if parsed_req is not None: - yield parsed_req - - -def preprocess(content): - # type: (Text) -> ReqFileLines - """Split, filter, and join lines, and return a line iterator - - :param content: the content of the requirements file - """ - lines_enum = enumerate(content.splitlines(), start=1) # type: ReqFileLines - lines_enum = join_lines(lines_enum) - lines_enum = ignore_comments(lines_enum) - lines_enum = expand_env_variables(lines_enum) - return lines_enum - - -def handle_requirement_line( - line, # type: ParsedLine - options=None, # type: Optional[optparse.Values] -): - # type: (...) -> ParsedRequirement - - # preserve for the nested code path - line_comes_from = '{} {} (line {})'.format( - '-c' if line.constraint else '-r', line.filename, line.lineno, - ) - - assert line.is_requirement - - if line.is_editable: - # For editable requirements, we don't support per-requirement - # options, so just return the parsed requirement. - return ParsedRequirement( - requirement=line.requirement, - is_editable=line.is_editable, - comes_from=line_comes_from, - constraint=line.constraint, - ) - else: - if options: - # Disable wheels if the user has specified build options - cmdoptions.check_install_build_global(options, line.opts) - - # get the options that apply to requirements - req_options = {} - for dest in SUPPORTED_OPTIONS_REQ_DEST: - if dest in line.opts.__dict__ and line.opts.__dict__[dest]: - req_options[dest] = line.opts.__dict__[dest] - - line_source = 'line {} of {}'.format(line.lineno, line.filename) - return ParsedRequirement( - requirement=line.requirement, - is_editable=line.is_editable, - comes_from=line_comes_from, - constraint=line.constraint, - options=req_options, - line_source=line_source, - ) - - -def handle_option_line( - opts, # type: Values - filename, # type: str - lineno, # type: int - finder=None, # type: Optional[PackageFinder] - options=None, # type: Optional[optparse.Values] - session=None, # type: Optional[PipSession] -): - # type: (...) -> None - - # percolate hash-checking option upward - if opts.require_hashes: - options.require_hashes = opts.require_hashes - - # set finder options - elif finder: - find_links = finder.find_links - index_urls = finder.index_urls - if opts.index_url: - index_urls = [opts.index_url] - if opts.no_index is True: - index_urls = [] - if opts.extra_index_urls: - index_urls.extend(opts.extra_index_urls) - if opts.find_links: - # FIXME: it would be nice to keep track of the source - # of the find_links: support a find-links local path - # relative to a requirements file. - value = opts.find_links[0] - req_dir = os.path.dirname(os.path.abspath(filename)) - relative_to_reqs_file = os.path.join(req_dir, value) - if os.path.exists(relative_to_reqs_file): - value = relative_to_reqs_file - find_links.append(value) - - search_scope = SearchScope( - find_links=find_links, - index_urls=index_urls, - ) - finder.search_scope = search_scope - - if opts.pre: - finder.set_allow_all_prereleases() - - if session: - for host in opts.trusted_hosts or []: - source = 'line {} of {}'.format(lineno, filename) - session.add_trusted_host(host, source=source) - - -def handle_line( - line, # type: ParsedLine - options=None, # type: Optional[optparse.Values] - finder=None, # type: Optional[PackageFinder] - session=None, # type: Optional[PipSession] -): - # type: (...) -> Optional[ParsedRequirement] - """Handle a single parsed requirements line; This can result in - creating/yielding requirements, or updating the finder. - - :param line: The parsed line to be processed. - :param options: CLI options. - :param finder: The finder - updated by non-requirement lines. - :param session: The session - updated by non-requirement lines. - - Returns a ParsedRequirement object if the line is a requirement line, - otherwise returns None. - - For lines that contain requirements, the only options that have an effect - are from SUPPORTED_OPTIONS_REQ, and they are scoped to the - requirement. Other options from SUPPORTED_OPTIONS may be present, but are - ignored. - - For lines that do not contain requirements, the only options that have an - effect are from SUPPORTED_OPTIONS. Options from SUPPORTED_OPTIONS_REQ may - be present, but are ignored. These lines may contain multiple options - (although our docs imply only one is supported), and all our parsed and - affect the finder. - """ - - if line.is_requirement: - parsed_req = handle_requirement_line(line, options) - return parsed_req - else: - handle_option_line( - line.opts, - line.filename, - line.lineno, - finder, - options, - session, - ) - return None - - -class RequirementsFileParser(object): - def __init__( - self, - session, # type: PipSession - line_parser, # type: LineParser - comes_from, # type: str - ): - # type: (...) -> None - self._session = session - self._line_parser = line_parser - self._comes_from = comes_from - - def parse(self, filename, constraint): - # type: (str, bool) -> Iterator[ParsedLine] - """Parse a given file, yielding parsed lines. - """ - for line in self._parse_and_recurse(filename, constraint): - yield line - - def _parse_and_recurse(self, filename, constraint): - # type: (str, bool) -> Iterator[ParsedLine] - for line in self._parse_file(filename, constraint): - if ( - not line.is_requirement and - (line.opts.requirements or line.opts.constraints) - ): - # parse a nested requirements file - if line.opts.requirements: - req_path = line.opts.requirements[0] - nested_constraint = False - else: - req_path = line.opts.constraints[0] - nested_constraint = True - - # original file is over http - if SCHEME_RE.search(filename): - # do a url join so relative paths work - req_path = urllib_parse.urljoin(filename, req_path) - # original file and nested file are paths - elif not SCHEME_RE.search(req_path): - # do a join so relative paths work - req_path = os.path.join( - os.path.dirname(filename), req_path, - ) - - for inner_line in self._parse_and_recurse( - req_path, nested_constraint, - ): - yield inner_line - else: - yield line - - def _parse_file(self, filename, constraint): - # type: (str, bool) -> Iterator[ParsedLine] - _, content = get_file_content( - filename, self._session, comes_from=self._comes_from - ) - - lines_enum = preprocess(content) - - for line_number, line in lines_enum: - try: - args_str, opts = self._line_parser(line) - except OptionParsingError as e: - # add offending line - msg = 'Invalid requirement: {}\n{}'.format(line, e.msg) - raise RequirementsFileParseError(msg) - - yield ParsedLine( - filename, - line_number, - self._comes_from, - args_str, - opts, - constraint, - ) - - -def get_line_parser(finder): - # type: (Optional[PackageFinder]) -> LineParser - def parse_line(line): - # type: (Text) -> Tuple[str, Values] - # Build new parser for each line since it accumulates appendable - # options. - parser = build_parser() - defaults = parser.get_default_values() - defaults.index_url = None - if finder: - defaults.format_control = finder.format_control - - args_str, options_str = break_args_options(line) - # Prior to 2.7.3, shlex cannot deal with unicode entries - if sys.version_info < (2, 7, 3): - # https://github.com/python/mypy/issues/1174 - options_str = options_str.encode('utf8') # type: ignore - - # https://github.com/python/mypy/issues/1174 - opts, _ = parser.parse_args( - shlex.split(options_str), defaults) # type: ignore - - return args_str, opts - - return parse_line - - -def break_args_options(line): - # type: (Text) -> Tuple[str, Text] - """Break up the line into an args and options string. We only want to shlex - (and then optparse) the options, not the args. args can contain markers - which are corrupted by shlex. - """ - tokens = line.split(' ') - args = [] - options = tokens[:] - for token in tokens: - if token.startswith('-') or token.startswith('--'): - break - else: - args.append(token) - options.pop(0) - return ' '.join(args), ' '.join(options) # type: ignore - - -class OptionParsingError(Exception): - def __init__(self, msg): - # type: (str) -> None - self.msg = msg - - -def build_parser(): - # type: () -> optparse.OptionParser - """ - Return a parser for parsing requirement lines - """ - parser = optparse.OptionParser(add_help_option=False) - - option_factories = SUPPORTED_OPTIONS + SUPPORTED_OPTIONS_REQ - for option_factory in option_factories: - option = option_factory() - parser.add_option(option) - - # By default optparse sys.exits on parsing errors. We want to wrap - # that in our own exception. - def parser_exit(self, msg): - # type: (Any, str) -> NoReturn - raise OptionParsingError(msg) - # NOTE: mypy disallows assigning to a method - # https://github.com/python/mypy/issues/2427 - parser.exit = parser_exit # type: ignore - - return parser - - -def join_lines(lines_enum): - # type: (ReqFileLines) -> ReqFileLines - """Joins a line ending in '\' with the previous line (except when following - comments). The joined line takes on the index of the first line. - """ - primary_line_number = None - new_line = [] # type: List[Text] - for line_number, line in lines_enum: - if not line.endswith('\\') or COMMENT_RE.match(line): - if COMMENT_RE.match(line): - # this ensures comments are always matched later - line = ' ' + line - if new_line: - new_line.append(line) - yield primary_line_number, ''.join(new_line) - new_line = [] - else: - yield line_number, line - else: - if not new_line: - primary_line_number = line_number - new_line.append(line.strip('\\')) - - # last line contains \ - if new_line: - yield primary_line_number, ''.join(new_line) - - # TODO: handle space after '\'. - - -def ignore_comments(lines_enum): - # type: (ReqFileLines) -> ReqFileLines - """ - Strips comments and filter empty lines. - """ - for line_number, line in lines_enum: - line = COMMENT_RE.sub('', line) - line = line.strip() - if line: - yield line_number, line - - -def expand_env_variables(lines_enum): - # type: (ReqFileLines) -> ReqFileLines - """Replace all environment variables that can be retrieved via `os.getenv`. - - The only allowed format for environment variables defined in the - requirement file is `${MY_VARIABLE_1}` to ensure two things: - - 1. Strings that contain a `$` aren't accidentally (partially) expanded. - 2. Ensure consistency across platforms for requirement files. - - These points are the result of a discussion on the `github pull - request #3514 <https://github.com/pypa/pip/pull/3514>`_. - - Valid characters in variable names follow the `POSIX standard - <http://pubs.opengroup.org/onlinepubs/9699919799/>`_ and are limited - to uppercase letter, digits and the `_` (underscore). - """ - for line_number, line in lines_enum: - for env_var, var_name in ENV_VAR_RE.findall(line): - value = os.getenv(var_name) - if not value: - continue - - line = line.replace(env_var, value) - - yield line_number, line - - -def get_file_content(url, session, comes_from=None): - # type: (str, PipSession, Optional[str]) -> Tuple[str, Text] - """Gets the content of a file; it may be a filename, file: URL, or - http: URL. Returns (location, content). Content is unicode. - Respects # -*- coding: declarations on the retrieved files. - - :param url: File path or url. - :param session: PipSession instance. - :param comes_from: Origin description of requirements. - """ - scheme = get_url_scheme(url) - - if scheme in ['http', 'https']: - # FIXME: catch some errors - resp = session.get(url) - resp.raise_for_status() - return resp.url, resp.text - - elif scheme == 'file': - if comes_from and comes_from.startswith('http'): - raise InstallationError( - 'Requirements file {} references URL {}, ' - 'which is local'.format(comes_from, url) - ) - - path = url.split(':', 1)[1] - path = path.replace('\\', '/') - match = _url_slash_drive_re.match(path) - if match: - path = match.group(1) + ':' + path.split('|', 1)[1] - path = urllib_parse.unquote(path) - if path.startswith('/'): - path = '/' + path.lstrip('/') - url = path - - try: - with open(url, 'rb') as f: - content = auto_decode(f.read()) - except IOError as exc: - raise InstallationError( - 'Could not open requirements file: {}'.format(exc) - ) - return url, content - - -_url_slash_drive_re = re.compile(r'/*([a-z])\|', re.I) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/req/req_install.py b/venv/lib/python3.8/site-packages/pip/_internal/req/req_install.py deleted file mode 100644 index 3b28209..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/req/req_install.py +++ /dev/null @@ -1,850 +0,0 @@ -# The following comment should be removed at some point in the future. -# mypy: strict-optional=False - -from __future__ import absolute_import - -import logging -import os -import shutil -import sys -import zipfile - -from pip._vendor import pkg_resources, six -from pip._vendor.packaging.requirements import Requirement -from pip._vendor.packaging.utils import canonicalize_name -from pip._vendor.packaging.version import Version -from pip._vendor.packaging.version import parse as parse_version -from pip._vendor.pep517.wrappers import Pep517HookCaller - -from pip._internal.build_env import NoOpBuildEnvironment -from pip._internal.exceptions import InstallationError -from pip._internal.locations import get_scheme -from pip._internal.models.link import Link -from pip._internal.operations.build.metadata import generate_metadata -from pip._internal.operations.build.metadata_legacy import \ - generate_metadata as generate_metadata_legacy -from pip._internal.operations.install.editable_legacy import \ - install_editable as install_editable_legacy -from pip._internal.operations.install.legacy import LegacyInstallFailure -from pip._internal.operations.install.legacy import install as install_legacy -from pip._internal.operations.install.wheel import install_wheel -from pip._internal.pyproject import load_pyproject_toml, make_pyproject_path -from pip._internal.req.req_uninstall import UninstallPathSet -from pip._internal.utils.deprecation import deprecated -from pip._internal.utils.direct_url_helpers import direct_url_from_link -from pip._internal.utils.hashes import Hashes -from pip._internal.utils.logging import indent_log -from pip._internal.utils.misc import ( - ask_path_exists, - backup_dir, - display_path, - dist_in_site_packages, - dist_in_usersite, - get_installed_version, - hide_url, - redact_auth_from_url, -) -from pip._internal.utils.packaging import get_metadata -from pip._internal.utils.temp_dir import TempDirectory, tempdir_kinds -from pip._internal.utils.typing import MYPY_CHECK_RUNNING -from pip._internal.utils.virtualenv import running_under_virtualenv -from pip._internal.vcs import vcs - -if MYPY_CHECK_RUNNING: - from typing import ( - Any, Dict, Iterable, List, Optional, Sequence, Union, - ) - from pip._internal.build_env import BuildEnvironment - from pip._vendor.pkg_resources import Distribution - from pip._vendor.packaging.specifiers import SpecifierSet - from pip._vendor.packaging.markers import Marker - - -logger = logging.getLogger(__name__) - - -def _get_dist(metadata_directory): - # type: (str) -> Distribution - """Return a pkg_resources.Distribution for the provided - metadata directory. - """ - dist_dir = metadata_directory.rstrip(os.sep) - - # Build a PathMetadata object, from path to metadata. :wink: - base_dir, dist_dir_name = os.path.split(dist_dir) - metadata = pkg_resources.PathMetadata(base_dir, dist_dir) - - # Determine the correct Distribution object type. - if dist_dir.endswith(".egg-info"): - dist_cls = pkg_resources.Distribution - dist_name = os.path.splitext(dist_dir_name)[0] - else: - assert dist_dir.endswith(".dist-info") - dist_cls = pkg_resources.DistInfoDistribution - dist_name = os.path.splitext(dist_dir_name)[0].split("-")[0] - - return dist_cls( - base_dir, - project_name=dist_name, - metadata=metadata, - ) - - -class InstallRequirement(object): - """ - Represents something that may be installed later on, may have information - about where to fetch the relevant requirement and also contains logic for - installing the said requirement. - """ - - def __init__( - self, - req, # type: Optional[Requirement] - comes_from, # type: Optional[Union[str, InstallRequirement]] - editable=False, # type: bool - link=None, # type: Optional[Link] - markers=None, # type: Optional[Marker] - use_pep517=None, # type: Optional[bool] - isolated=False, # type: bool - install_options=None, # type: Optional[List[str]] - global_options=None, # type: Optional[List[str]] - hash_options=None, # type: Optional[Dict[str, List[str]]] - constraint=False, # type: bool - extras=() # type: Iterable[str] - ): - # type: (...) -> None - assert req is None or isinstance(req, Requirement), req - self.req = req - self.comes_from = comes_from - self.constraint = constraint - self.editable = editable - - # source_dir is the local directory where the linked requirement is - # located, or unpacked. In case unpacking is needed, creating and - # populating source_dir is done by the RequirementPreparer. Note this - # is not necessarily the directory where pyproject.toml or setup.py is - # located - that one is obtained via unpacked_source_directory. - self.source_dir = None # type: Optional[str] - if self.editable: - assert link - if link.is_file: - self.source_dir = os.path.normpath( - os.path.abspath(link.file_path) - ) - - if link is None and req and req.url: - # PEP 508 URL requirement - link = Link(req.url) - self.link = self.original_link = link - self.original_link_is_in_wheel_cache = False - - # Path to any downloaded or already-existing package. - self.local_file_path = None # type: Optional[str] - if self.link and self.link.is_file: - self.local_file_path = self.link.file_path - - if extras: - self.extras = extras - elif req: - self.extras = { - pkg_resources.safe_extra(extra) for extra in req.extras - } - else: - self.extras = set() - if markers is None and req: - markers = req.marker - self.markers = markers - - # This holds the pkg_resources.Distribution object if this requirement - # is already available: - self.satisfied_by = None # type: Optional[Distribution] - # Whether the installation process should try to uninstall an existing - # distribution before installing this requirement. - self.should_reinstall = False - # Temporary build location - self._temp_build_dir = None # type: Optional[TempDirectory] - # Set to True after successful installation - self.install_succeeded = None # type: Optional[bool] - # Supplied options - self.install_options = install_options if install_options else [] - self.global_options = global_options if global_options else [] - self.hash_options = hash_options if hash_options else {} - # Set to True after successful preparation of this requirement - self.prepared = False - self.is_direct = False - - # Set by the legacy resolver when the requirement has been downloaded - # TODO: This introduces a strong coupling between the resolver and the - # requirement (the coupling was previously between the resolver - # and the requirement set). This should be refactored to allow - # the requirement to decide for itself when it has been - # successfully downloaded - but that is more tricky to get right, - # se we are making the change in stages. - self.successfully_downloaded = False - - self.isolated = isolated - self.build_env = NoOpBuildEnvironment() # type: BuildEnvironment - - # For PEP 517, the directory where we request the project metadata - # gets stored. We need this to pass to build_wheel, so the backend - # can ensure that the wheel matches the metadata (see the PEP for - # details). - self.metadata_directory = None # type: Optional[str] - - # The static build requirements (from pyproject.toml) - self.pyproject_requires = None # type: Optional[List[str]] - - # Build requirements that we will check are available - self.requirements_to_check = [] # type: List[str] - - # The PEP 517 backend we should use to build the project - self.pep517_backend = None # type: Optional[Pep517HookCaller] - - # Are we using PEP 517 for this requirement? - # After pyproject.toml has been loaded, the only valid values are True - # and False. Before loading, None is valid (meaning "use the default"). - # Setting an explicit value before loading pyproject.toml is supported, - # but after loading this flag should be treated as read only. - self.use_pep517 = use_pep517 - - def __str__(self): - # type: () -> str - if self.req: - s = str(self.req) - if self.link: - s += ' from {}'.format(redact_auth_from_url(self.link.url)) - elif self.link: - s = redact_auth_from_url(self.link.url) - else: - s = '<InstallRequirement>' - if self.satisfied_by is not None: - s += ' in {}'.format(display_path(self.satisfied_by.location)) - if self.comes_from: - if isinstance(self.comes_from, six.string_types): - comes_from = self.comes_from # type: Optional[str] - else: - comes_from = self.comes_from.from_path() - if comes_from: - s += ' (from {})'.format(comes_from) - return s - - def __repr__(self): - # type: () -> str - return '<{} object: {} editable={!r}>'.format( - self.__class__.__name__, str(self), self.editable) - - def format_debug(self): - # type: () -> str - """An un-tested helper for getting state, for debugging. - """ - attributes = vars(self) - names = sorted(attributes) - - state = ( - "{}={!r}".format(attr, attributes[attr]) for attr in sorted(names) - ) - return '<{name} object: {{{state}}}>'.format( - name=self.__class__.__name__, - state=", ".join(state), - ) - - # Things that are valid for all kinds of requirements? - @property - def name(self): - # type: () -> Optional[str] - if self.req is None: - return None - return six.ensure_str(pkg_resources.safe_name(self.req.name)) - - @property - def specifier(self): - # type: () -> SpecifierSet - return self.req.specifier - - @property - def is_pinned(self): - # type: () -> bool - """Return whether I am pinned to an exact version. - - For example, some-package==1.2 is pinned; some-package>1.2 is not. - """ - specifiers = self.specifier - return (len(specifiers) == 1 and - next(iter(specifiers)).operator in {'==', '==='}) - - @property - def installed_version(self): - # type: () -> Optional[str] - return get_installed_version(self.name) - - def match_markers(self, extras_requested=None): - # type: (Optional[Iterable[str]]) -> bool - if not extras_requested: - # Provide an extra to safely evaluate the markers - # without matching any extra - extras_requested = ('',) - if self.markers is not None: - return any( - self.markers.evaluate({'extra': extra}) - for extra in extras_requested) - else: - return True - - @property - def has_hash_options(self): - # type: () -> bool - """Return whether any known-good hashes are specified as options. - - These activate --require-hashes mode; hashes specified as part of a - URL do not. - - """ - return bool(self.hash_options) - - def hashes(self, trust_internet=True): - # type: (bool) -> Hashes - """Return a hash-comparer that considers my option- and URL-based - hashes to be known-good. - - Hashes in URLs--ones embedded in the requirements file, not ones - downloaded from an index server--are almost peers with ones from - flags. They satisfy --require-hashes (whether it was implicitly or - explicitly activated) but do not activate it. md5 and sha224 are not - allowed in flags, which should nudge people toward good algos. We - always OR all hashes together, even ones from URLs. - - :param trust_internet: Whether to trust URL-based (#md5=...) hashes - downloaded from the internet, as by populate_link() - - """ - good_hashes = self.hash_options.copy() - link = self.link if trust_internet else self.original_link - if link and link.hash: - good_hashes.setdefault(link.hash_name, []).append(link.hash) - return Hashes(good_hashes) - - def from_path(self): - # type: () -> Optional[str] - """Format a nice indicator to show where this "comes from" - """ - if self.req is None: - return None - s = str(self.req) - if self.comes_from: - if isinstance(self.comes_from, six.string_types): - comes_from = self.comes_from - else: - comes_from = self.comes_from.from_path() - if comes_from: - s += '->' + comes_from - return s - - def ensure_build_location(self, build_dir, autodelete): - # type: (str, bool) -> str - assert build_dir is not None - if self._temp_build_dir is not None: - assert self._temp_build_dir.path - return self._temp_build_dir.path - if self.req is None: - # Some systems have /tmp as a symlink which confuses custom - # builds (such as numpy). Thus, we ensure that the real path - # is returned. - self._temp_build_dir = TempDirectory( - kind=tempdir_kinds.REQ_BUILD, globally_managed=True - ) - - return self._temp_build_dir.path - if self.editable: - name = self.name.lower() - else: - name = self.name - # FIXME: Is there a better place to create the build_dir? (hg and bzr - # need this) - if not os.path.exists(build_dir): - logger.debug('Creating directory %s', build_dir) - os.makedirs(build_dir) - actual_build_dir = os.path.join(build_dir, name) - # `None` indicates that we respect the globally-configured deletion - # settings, which is what we actually want when auto-deleting. - delete_arg = None if autodelete else False - return TempDirectory( - path=actual_build_dir, - delete=delete_arg, - kind=tempdir_kinds.REQ_BUILD, - globally_managed=True, - ).path - - def _set_requirement(self): - # type: () -> None - """Set requirement after generating metadata. - """ - assert self.req is None - assert self.metadata is not None - assert self.source_dir is not None - - # Construct a Requirement object from the generated metadata - if isinstance(parse_version(self.metadata["Version"]), Version): - op = "==" - else: - op = "===" - - self.req = Requirement( - "".join([ - self.metadata["Name"], - op, - self.metadata["Version"], - ]) - ) - - def warn_on_mismatching_name(self): - # type: () -> None - metadata_name = canonicalize_name(self.metadata["Name"]) - if canonicalize_name(self.req.name) == metadata_name: - # Everything is fine. - return - - # If we're here, there's a mismatch. Log a warning about it. - logger.warning( - 'Generating metadata for package %s ' - 'produced metadata for project name %s. Fix your ' - '#egg=%s fragments.', - self.name, metadata_name, self.name - ) - self.req = Requirement(metadata_name) - - def check_if_exists(self, use_user_site): - # type: (bool) -> None - """Find an installed distribution that satisfies or conflicts - with this requirement, and set self.satisfied_by or - self.should_reinstall appropriately. - """ - if self.req is None: - return - # get_distribution() will resolve the entire list of requirements - # anyway, and we've already determined that we need the requirement - # in question, so strip the marker so that we don't try to - # evaluate it. - no_marker = Requirement(str(self.req)) - no_marker.marker = None - try: - self.satisfied_by = pkg_resources.get_distribution(str(no_marker)) - except pkg_resources.DistributionNotFound: - return - except pkg_resources.VersionConflict: - existing_dist = pkg_resources.get_distribution( - self.req.name - ) - if use_user_site: - if dist_in_usersite(existing_dist): - self.should_reinstall = True - elif (running_under_virtualenv() and - dist_in_site_packages(existing_dist)): - raise InstallationError( - "Will not install to the user site because it will " - "lack sys.path precedence to {} in {}".format( - existing_dist.project_name, existing_dist.location) - ) - else: - self.should_reinstall = True - else: - if self.editable and self.satisfied_by: - self.should_reinstall = True - # when installing editables, nothing pre-existing should ever - # satisfy - self.satisfied_by = None - - # Things valid for wheels - @property - def is_wheel(self): - # type: () -> bool - if not self.link: - return False - return self.link.is_wheel - - # Things valid for sdists - @property - def unpacked_source_directory(self): - # type: () -> str - return os.path.join( - self.source_dir, - self.link and self.link.subdirectory_fragment or '') - - @property - def setup_py_path(self): - # type: () -> str - assert self.source_dir, "No source dir for {}".format(self) - setup_py = os.path.join(self.unpacked_source_directory, 'setup.py') - - # Python2 __file__ should not be unicode - if six.PY2 and isinstance(setup_py, six.text_type): - setup_py = setup_py.encode(sys.getfilesystemencoding()) - - return setup_py - - @property - def pyproject_toml_path(self): - # type: () -> str - assert self.source_dir, "No source dir for {}".format(self) - return make_pyproject_path(self.unpacked_source_directory) - - def load_pyproject_toml(self): - # type: () -> None - """Load the pyproject.toml file. - - After calling this routine, all of the attributes related to PEP 517 - processing for this requirement have been set. In particular, the - use_pep517 attribute can be used to determine whether we should - follow the PEP 517 or legacy (setup.py) code path. - """ - pyproject_toml_data = load_pyproject_toml( - self.use_pep517, - self.pyproject_toml_path, - self.setup_py_path, - str(self) - ) - - if pyproject_toml_data is None: - self.use_pep517 = False - return - - self.use_pep517 = True - requires, backend, check, backend_path = pyproject_toml_data - self.requirements_to_check = check - self.pyproject_requires = requires - self.pep517_backend = Pep517HookCaller( - self.unpacked_source_directory, backend, backend_path=backend_path, - ) - - def _generate_metadata(self): - # type: () -> str - """Invokes metadata generator functions, with the required arguments. - """ - if not self.use_pep517: - assert self.unpacked_source_directory - - return generate_metadata_legacy( - build_env=self.build_env, - setup_py_path=self.setup_py_path, - source_dir=self.unpacked_source_directory, - isolated=self.isolated, - details=self.name or "from {}".format(self.link) - ) - - assert self.pep517_backend is not None - - return generate_metadata( - build_env=self.build_env, - backend=self.pep517_backend, - ) - - def prepare_metadata(self): - # type: () -> None - """Ensure that project metadata is available. - - Under PEP 517, call the backend hook to prepare the metadata. - Under legacy processing, call setup.py egg-info. - """ - assert self.source_dir - - with indent_log(): - self.metadata_directory = self._generate_metadata() - - # Act on the newly generated metadata, based on the name and version. - if not self.name: - self._set_requirement() - else: - self.warn_on_mismatching_name() - - self.assert_source_matches_version() - - @property - def metadata(self): - # type: () -> Any - if not hasattr(self, '_metadata'): - self._metadata = get_metadata(self.get_dist()) - - return self._metadata - - def get_dist(self): - # type: () -> Distribution - return _get_dist(self.metadata_directory) - - def assert_source_matches_version(self): - # type: () -> None - assert self.source_dir - version = self.metadata['version'] - if self.req.specifier and version not in self.req.specifier: - logger.warning( - 'Requested %s, but installing version %s', - self, - version, - ) - else: - logger.debug( - 'Source in %s has version %s, which satisfies requirement %s', - display_path(self.source_dir), - version, - self, - ) - - # For both source distributions and editables - def ensure_has_source_dir(self, parent_dir, autodelete=False): - # type: (str, bool) -> None - """Ensure that a source_dir is set. - - This will create a temporary build dir if the name of the requirement - isn't known yet. - - :param parent_dir: The ideal pip parent_dir for the source_dir. - Generally src_dir for editables and build_dir for sdists. - :return: self.source_dir - """ - if self.source_dir is None: - self.source_dir = self.ensure_build_location( - parent_dir, autodelete - ) - - # For editable installations - def update_editable(self, obtain=True): - # type: (bool) -> None - if not self.link: - logger.debug( - "Cannot update repository at %s; repository location is " - "unknown", - self.source_dir, - ) - return - assert self.editable - assert self.source_dir - if self.link.scheme == 'file': - # Static paths don't get updated - return - assert '+' in self.link.url, \ - "bad url: {self.link.url!r}".format(**locals()) - vc_type, url = self.link.url.split('+', 1) - vcs_backend = vcs.get_backend(vc_type) - if vcs_backend: - if not self.link.is_vcs: - reason = ( - "This form of VCS requirement is being deprecated: {}." - ).format( - self.link.url - ) - replacement = None - if self.link.url.startswith("git+git@"): - replacement = ( - "git+https://git@example.com/..., " - "git+ssh://git@example.com/..., " - "or the insecure git+git://git@example.com/..." - ) - deprecated(reason, replacement, gone_in="21.0", issue=7554) - hidden_url = hide_url(self.link.url) - if obtain: - vcs_backend.obtain(self.source_dir, url=hidden_url) - else: - vcs_backend.export(self.source_dir, url=hidden_url) - else: - assert 0, ( - 'Unexpected version control type (in {}): {}'.format( - self.link, vc_type)) - - # Top-level Actions - def uninstall(self, auto_confirm=False, verbose=False): - # type: (bool, bool) -> Optional[UninstallPathSet] - """ - Uninstall the distribution currently satisfying this requirement. - - Prompts before removing or modifying files unless - ``auto_confirm`` is True. - - Refuses to delete or modify files outside of ``sys.prefix`` - - thus uninstallation within a virtual environment can only - modify that virtual environment, even if the virtualenv is - linked to global site-packages. - - """ - assert self.req - try: - dist = pkg_resources.get_distribution(self.req.name) - except pkg_resources.DistributionNotFound: - logger.warning("Skipping %s as it is not installed.", self.name) - return None - else: - logger.info('Found existing installation: %s', dist) - - uninstalled_pathset = UninstallPathSet.from_dist(dist) - uninstalled_pathset.remove(auto_confirm, verbose) - return uninstalled_pathset - - def _get_archive_name(self, path, parentdir, rootdir): - # type: (str, str, str) -> str - - def _clean_zip_name(name, prefix): - # type: (str, str) -> str - assert name.startswith(prefix + os.path.sep), ( - "name {name!r} doesn't start with prefix {prefix!r}" - .format(**locals()) - ) - name = name[len(prefix) + 1:] - name = name.replace(os.path.sep, '/') - return name - - path = os.path.join(parentdir, path) - name = _clean_zip_name(path, rootdir) - return self.name + '/' + name - - def archive(self, build_dir): - # type: (str) -> None - """Saves archive to provided build_dir. - - Used for saving downloaded VCS requirements as part of `pip download`. - """ - assert self.source_dir - - create_archive = True - archive_name = '{}-{}.zip'.format(self.name, self.metadata["version"]) - archive_path = os.path.join(build_dir, archive_name) - - if os.path.exists(archive_path): - response = ask_path_exists( - 'The file {} exists. (i)gnore, (w)ipe, ' - '(b)ackup, (a)bort '.format( - display_path(archive_path)), - ('i', 'w', 'b', 'a')) - if response == 'i': - create_archive = False - elif response == 'w': - logger.warning('Deleting %s', display_path(archive_path)) - os.remove(archive_path) - elif response == 'b': - dest_file = backup_dir(archive_path) - logger.warning( - 'Backing up %s to %s', - display_path(archive_path), - display_path(dest_file), - ) - shutil.move(archive_path, dest_file) - elif response == 'a': - sys.exit(-1) - - if not create_archive: - return - - zip_output = zipfile.ZipFile( - archive_path, 'w', zipfile.ZIP_DEFLATED, allowZip64=True, - ) - with zip_output: - dir = os.path.normcase( - os.path.abspath(self.unpacked_source_directory) - ) - for dirpath, dirnames, filenames in os.walk(dir): - for dirname in dirnames: - dir_arcname = self._get_archive_name( - dirname, parentdir=dirpath, rootdir=dir, - ) - zipdir = zipfile.ZipInfo(dir_arcname + '/') - zipdir.external_attr = 0x1ED << 16 # 0o755 - zip_output.writestr(zipdir, '') - for filename in filenames: - file_arcname = self._get_archive_name( - filename, parentdir=dirpath, rootdir=dir, - ) - filename = os.path.join(dirpath, filename) - zip_output.write(filename, file_arcname) - - logger.info('Saved %s', display_path(archive_path)) - - def install( - self, - install_options, # type: List[str] - global_options=None, # type: Optional[Sequence[str]] - root=None, # type: Optional[str] - home=None, # type: Optional[str] - prefix=None, # type: Optional[str] - warn_script_location=True, # type: bool - use_user_site=False, # type: bool - pycompile=True # type: bool - ): - # type: (...) -> None - scheme = get_scheme( - self.name, - user=use_user_site, - home=home, - root=root, - isolated=self.isolated, - prefix=prefix, - ) - - global_options = global_options if global_options is not None else [] - if self.editable: - install_editable_legacy( - install_options, - global_options, - prefix=prefix, - home=home, - use_user_site=use_user_site, - name=self.name, - setup_py_path=self.setup_py_path, - isolated=self.isolated, - build_env=self.build_env, - unpacked_source_directory=self.unpacked_source_directory, - ) - self.install_succeeded = True - return - - if self.is_wheel: - assert self.local_file_path - direct_url = None - if self.original_link: - direct_url = direct_url_from_link( - self.original_link, - self.source_dir, - self.original_link_is_in_wheel_cache, - ) - install_wheel( - self.name, - self.local_file_path, - scheme=scheme, - req_description=str(self.req), - pycompile=pycompile, - warn_script_location=warn_script_location, - direct_url=direct_url, - ) - self.install_succeeded = True - return - - # TODO: Why don't we do this for editable installs? - - # Extend the list of global and install options passed on to - # the setup.py call with the ones from the requirements file. - # Options specified in requirements file override those - # specified on the command line, since the last option given - # to setup.py is the one that is used. - global_options = list(global_options) + self.global_options - install_options = list(install_options) + self.install_options - - try: - success = install_legacy( - install_options=install_options, - global_options=global_options, - root=root, - home=home, - prefix=prefix, - use_user_site=use_user_site, - pycompile=pycompile, - scheme=scheme, - setup_py_path=self.setup_py_path, - isolated=self.isolated, - req_name=self.name, - build_env=self.build_env, - unpacked_source_directory=self.unpacked_source_directory, - req_description=str(self.req), - ) - except LegacyInstallFailure as exc: - self.install_succeeded = False - six.reraise(*exc.parent) - except Exception: - self.install_succeeded = True - raise - - self.install_succeeded = success diff --git a/venv/lib/python3.8/site-packages/pip/_internal/req/req_set.py b/venv/lib/python3.8/site-packages/pip/_internal/req/req_set.py deleted file mode 100644 index f168ce1..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/req/req_set.py +++ /dev/null @@ -1,202 +0,0 @@ -# The following comment should be removed at some point in the future. -# mypy: strict-optional=False - -from __future__ import absolute_import - -import logging -from collections import OrderedDict - -from pip._vendor.packaging.utils import canonicalize_name - -from pip._internal.exceptions import InstallationError -from pip._internal.models.wheel import Wheel -from pip._internal.utils import compatibility_tags -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import Dict, Iterable, List, Optional, Tuple - from pip._internal.req.req_install import InstallRequirement - - -logger = logging.getLogger(__name__) - - -class RequirementSet(object): - - def __init__(self, check_supported_wheels=True): - # type: (bool) -> None - """Create a RequirementSet. - """ - - self.requirements = OrderedDict() # type: Dict[str, InstallRequirement] # noqa: E501 - self.check_supported_wheels = check_supported_wheels - - self.unnamed_requirements = [] # type: List[InstallRequirement] - - def __str__(self): - # type: () -> str - requirements = sorted( - (req for req in self.requirements.values() if not req.comes_from), - key=lambda req: canonicalize_name(req.name), - ) - return ' '.join(str(req.req) for req in requirements) - - def __repr__(self): - # type: () -> str - requirements = sorted( - self.requirements.values(), - key=lambda req: canonicalize_name(req.name), - ) - - format_string = '<{classname} object; {count} requirement(s): {reqs}>' - return format_string.format( - classname=self.__class__.__name__, - count=len(requirements), - reqs=', '.join(str(req.req) for req in requirements), - ) - - def add_unnamed_requirement(self, install_req): - # type: (InstallRequirement) -> None - assert not install_req.name - self.unnamed_requirements.append(install_req) - - def add_named_requirement(self, install_req): - # type: (InstallRequirement) -> None - assert install_req.name - - project_name = canonicalize_name(install_req.name) - self.requirements[project_name] = install_req - - def add_requirement( - self, - install_req, # type: InstallRequirement - parent_req_name=None, # type: Optional[str] - extras_requested=None # type: Optional[Iterable[str]] - ): - # type: (...) -> Tuple[List[InstallRequirement], Optional[InstallRequirement]] # noqa: E501 - """Add install_req as a requirement to install. - - :param parent_req_name: The name of the requirement that needed this - added. The name is used because when multiple unnamed requirements - resolve to the same name, we could otherwise end up with dependency - links that point outside the Requirements set. parent_req must - already be added. Note that None implies that this is a user - supplied requirement, vs an inferred one. - :param extras_requested: an iterable of extras used to evaluate the - environment markers. - :return: Additional requirements to scan. That is either [] if - the requirement is not applicable, or [install_req] if the - requirement is applicable and has just been added. - """ - # If the markers do not match, ignore this requirement. - if not install_req.match_markers(extras_requested): - logger.info( - "Ignoring %s: markers '%s' don't match your environment", - install_req.name, install_req.markers, - ) - return [], None - - # If the wheel is not supported, raise an error. - # Should check this after filtering out based on environment markers to - # allow specifying different wheels based on the environment/OS, in a - # single requirements file. - if install_req.link and install_req.link.is_wheel: - wheel = Wheel(install_req.link.filename) - tags = compatibility_tags.get_supported() - if (self.check_supported_wheels and not wheel.supported(tags)): - raise InstallationError( - "{} is not a supported wheel on this platform.".format( - wheel.filename) - ) - - # This next bit is really a sanity check. - assert install_req.is_direct == (parent_req_name is None), ( - "a direct req shouldn't have a parent and also, " - "a non direct req should have a parent" - ) - - # Unnamed requirements are scanned again and the requirement won't be - # added as a dependency until after scanning. - if not install_req.name: - self.add_unnamed_requirement(install_req) - return [install_req], None - - try: - existing_req = self.get_requirement(install_req.name) - except KeyError: - existing_req = None - - has_conflicting_requirement = ( - parent_req_name is None and - existing_req and - not existing_req.constraint and - existing_req.extras == install_req.extras and - existing_req.req.specifier != install_req.req.specifier - ) - if has_conflicting_requirement: - raise InstallationError( - "Double requirement given: {} (already in {}, name={!r})" - .format(install_req, existing_req, install_req.name) - ) - - # When no existing requirement exists, add the requirement as a - # dependency and it will be scanned again after. - if not existing_req: - self.add_named_requirement(install_req) - # We'd want to rescan this requirement later - return [install_req], install_req - - # Assume there's no need to scan, and that we've already - # encountered this for scanning. - if install_req.constraint or not existing_req.constraint: - return [], existing_req - - does_not_satisfy_constraint = ( - install_req.link and - not ( - existing_req.link and - install_req.link.path == existing_req.link.path - ) - ) - if does_not_satisfy_constraint: - raise InstallationError( - "Could not satisfy constraints for '{}': " - "installation from path or url cannot be " - "constrained to a version".format(install_req.name) - ) - # If we're now installing a constraint, mark the existing - # object for real installation. - existing_req.constraint = False - existing_req.extras = tuple(sorted( - set(existing_req.extras) | set(install_req.extras) - )) - logger.debug( - "Setting %s extras to: %s", - existing_req, existing_req.extras, - ) - # Return the existing requirement for addition to the parent and - # scanning again. - return [existing_req], existing_req - - def has_requirement(self, name): - # type: (str) -> bool - project_name = canonicalize_name(name) - - return ( - project_name in self.requirements and - not self.requirements[project_name].constraint - ) - - def get_requirement(self, name): - # type: (str) -> InstallRequirement - project_name = canonicalize_name(name) - - if project_name in self.requirements: - return self.requirements[project_name] - - raise KeyError("No project with the name {name!r}".format(**locals())) - - @property - def all_requirements(self): - # type: () -> List[InstallRequirement] - return self.unnamed_requirements + list(self.requirements.values()) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/req/req_tracker.py b/venv/lib/python3.8/site-packages/pip/_internal/req/req_tracker.py deleted file mode 100644 index 14adeab..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/req/req_tracker.py +++ /dev/null @@ -1,151 +0,0 @@ -# The following comment should be removed at some point in the future. -# mypy: strict-optional=False - -from __future__ import absolute_import - -import contextlib -import errno -import hashlib -import logging -import os - -from pip._vendor import contextlib2 - -from pip._internal.utils.temp_dir import TempDirectory -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from types import TracebackType - from typing import Dict, Iterator, Optional, Set, Type, Union - from pip._internal.req.req_install import InstallRequirement - from pip._internal.models.link import Link - -logger = logging.getLogger(__name__) - - -@contextlib.contextmanager -def update_env_context_manager(**changes): - # type: (str) -> Iterator[None] - target = os.environ - - # Save values from the target and change them. - non_existent_marker = object() - saved_values = {} # type: Dict[str, Union[object, str]] - for name, new_value in changes.items(): - try: - saved_values[name] = target[name] - except KeyError: - saved_values[name] = non_existent_marker - target[name] = new_value - - try: - yield - finally: - # Restore original values in the target. - for name, original_value in saved_values.items(): - if original_value is non_existent_marker: - del target[name] - else: - assert isinstance(original_value, str) # for mypy - target[name] = original_value - - -@contextlib.contextmanager -def get_requirement_tracker(): - # type: () -> Iterator[RequirementTracker] - root = os.environ.get('PIP_REQ_TRACKER') - with contextlib2.ExitStack() as ctx: - if root is None: - root = ctx.enter_context( - TempDirectory(kind='req-tracker') - ).path - ctx.enter_context(update_env_context_manager(PIP_REQ_TRACKER=root)) - logger.debug("Initialized build tracking at %s", root) - - with RequirementTracker(root) as tracker: - yield tracker - - -class RequirementTracker(object): - - def __init__(self, root): - # type: (str) -> None - self._root = root - self._entries = set() # type: Set[InstallRequirement] - logger.debug("Created build tracker: %s", self._root) - - def __enter__(self): - # type: () -> RequirementTracker - logger.debug("Entered build tracker: %s", self._root) - return self - - def __exit__( - self, - exc_type, # type: Optional[Type[BaseException]] - exc_val, # type: Optional[BaseException] - exc_tb # type: Optional[TracebackType] - ): - # type: (...) -> None - self.cleanup() - - def _entry_path(self, link): - # type: (Link) -> str - hashed = hashlib.sha224(link.url_without_fragment.encode()).hexdigest() - return os.path.join(self._root, hashed) - - def add(self, req): - # type: (InstallRequirement) -> None - """Add an InstallRequirement to build tracking. - """ - - # Get the file to write information about this requirement. - entry_path = self._entry_path(req.link) - - # Try reading from the file. If it exists and can be read from, a build - # is already in progress, so a LookupError is raised. - try: - with open(entry_path) as fp: - contents = fp.read() - except IOError as e: - # if the error is anything other than "file does not exist", raise. - if e.errno != errno.ENOENT: - raise - else: - message = '{} is already being built: {}'.format( - req.link, contents) - raise LookupError(message) - - # If we're here, req should really not be building already. - assert req not in self._entries - - # Start tracking this requirement. - with open(entry_path, 'w') as fp: - fp.write(str(req)) - self._entries.add(req) - - logger.debug('Added %s to build tracker %r', req, self._root) - - def remove(self, req): - # type: (InstallRequirement) -> None - """Remove an InstallRequirement from build tracking. - """ - - # Delete the created file and the corresponding entries. - os.unlink(self._entry_path(req.link)) - self._entries.remove(req) - - logger.debug('Removed %s from build tracker %r', req, self._root) - - def cleanup(self): - # type: () -> None - for req in set(self._entries): - self.remove(req) - - logger.debug("Removed build tracker: %r", self._root) - - @contextlib.contextmanager - def track(self, req): - # type: (InstallRequirement) -> Iterator[None] - self.add(req) - yield - self.remove(req) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/req/req_uninstall.py b/venv/lib/python3.8/site-packages/pip/_internal/req/req_uninstall.py deleted file mode 100644 index 559061a..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/req/req_uninstall.py +++ /dev/null @@ -1,649 +0,0 @@ -from __future__ import absolute_import - -import csv -import functools -import logging -import os -import sys -import sysconfig - -from pip._vendor import pkg_resources - -from pip._internal.exceptions import UninstallationError -from pip._internal.locations import bin_py, bin_user -from pip._internal.utils.compat import WINDOWS, cache_from_source, uses_pycache -from pip._internal.utils.logging import indent_log -from pip._internal.utils.misc import ( - FakeFile, - ask, - dist_in_usersite, - dist_is_local, - egg_link_path, - is_local, - normalize_path, - renames, - rmtree, -) -from pip._internal.utils.temp_dir import AdjacentTempDirectory, TempDirectory -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import ( - Any, Callable, Dict, Iterable, Iterator, List, Optional, Set, Tuple, - ) - from pip._vendor.pkg_resources import Distribution - -logger = logging.getLogger(__name__) - - -def _script_names(dist, script_name, is_gui): - # type: (Distribution, str, bool) -> List[str] - """Create the fully qualified name of the files created by - {console,gui}_scripts for the given ``dist``. - Returns the list of file names - """ - if dist_in_usersite(dist): - bin_dir = bin_user - else: - bin_dir = bin_py - exe_name = os.path.join(bin_dir, script_name) - paths_to_remove = [exe_name] - if WINDOWS: - paths_to_remove.append(exe_name + '.exe') - paths_to_remove.append(exe_name + '.exe.manifest') - if is_gui: - paths_to_remove.append(exe_name + '-script.pyw') - else: - paths_to_remove.append(exe_name + '-script.py') - return paths_to_remove - - -def _unique(fn): - # type: (Callable[..., Iterator[Any]]) -> Callable[..., Iterator[Any]] - @functools.wraps(fn) - def unique(*args, **kw): - # type: (Any, Any) -> Iterator[Any] - seen = set() # type: Set[Any] - for item in fn(*args, **kw): - if item not in seen: - seen.add(item) - yield item - return unique - - -@_unique -def uninstallation_paths(dist): - # type: (Distribution) -> Iterator[str] - """ - Yield all the uninstallation paths for dist based on RECORD-without-.py[co] - - Yield paths to all the files in RECORD. For each .py file in RECORD, add - the .pyc and .pyo in the same directory. - - UninstallPathSet.add() takes care of the __pycache__ .py[co]. - """ - r = csv.reader(FakeFile(dist.get_metadata_lines('RECORD'))) - for row in r: - path = os.path.join(dist.location, row[0]) - yield path - if path.endswith('.py'): - dn, fn = os.path.split(path) - base = fn[:-3] - path = os.path.join(dn, base + '.pyc') - yield path - path = os.path.join(dn, base + '.pyo') - yield path - - -def compact(paths): - # type: (Iterable[str]) -> Set[str] - """Compact a path set to contain the minimal number of paths - necessary to contain all paths in the set. If /a/path/ and - /a/path/to/a/file.txt are both in the set, leave only the - shorter path.""" - - sep = os.path.sep - short_paths = set() # type: Set[str] - for path in sorted(paths, key=len): - should_skip = any( - path.startswith(shortpath.rstrip("*")) and - path[len(shortpath.rstrip("*").rstrip(sep))] == sep - for shortpath in short_paths - ) - if not should_skip: - short_paths.add(path) - return short_paths - - -def compress_for_rename(paths): - # type: (Iterable[str]) -> Set[str] - """Returns a set containing the paths that need to be renamed. - - This set may include directories when the original sequence of paths - included every file on disk. - """ - case_map = dict((os.path.normcase(p), p) for p in paths) - remaining = set(case_map) - unchecked = sorted(set(os.path.split(p)[0] - for p in case_map.values()), key=len) - wildcards = set() # type: Set[str] - - def norm_join(*a): - # type: (str) -> str - return os.path.normcase(os.path.join(*a)) - - for root in unchecked: - if any(os.path.normcase(root).startswith(w) - for w in wildcards): - # This directory has already been handled. - continue - - all_files = set() # type: Set[str] - all_subdirs = set() # type: Set[str] - for dirname, subdirs, files in os.walk(root): - all_subdirs.update(norm_join(root, dirname, d) - for d in subdirs) - all_files.update(norm_join(root, dirname, f) - for f in files) - # If all the files we found are in our remaining set of files to - # remove, then remove them from the latter set and add a wildcard - # for the directory. - if not (all_files - remaining): - remaining.difference_update(all_files) - wildcards.add(root + os.sep) - - return set(map(case_map.__getitem__, remaining)) | wildcards - - -def compress_for_output_listing(paths): - # type: (Iterable[str]) -> Tuple[Set[str], Set[str]] - """Returns a tuple of 2 sets of which paths to display to user - - The first set contains paths that would be deleted. Files of a package - are not added and the top-level directory of the package has a '*' added - at the end - to signify that all it's contents are removed. - - The second set contains files that would have been skipped in the above - folders. - """ - - will_remove = set(paths) - will_skip = set() - - # Determine folders and files - folders = set() - files = set() - for path in will_remove: - if path.endswith(".pyc"): - continue - if path.endswith("__init__.py") or ".dist-info" in path: - folders.add(os.path.dirname(path)) - files.add(path) - - # probably this one https://github.com/python/mypy/issues/390 - _normcased_files = set(map(os.path.normcase, files)) # type: ignore - - folders = compact(folders) - - # This walks the tree using os.walk to not miss extra folders - # that might get added. - for folder in folders: - for dirpath, _, dirfiles in os.walk(folder): - for fname in dirfiles: - if fname.endswith(".pyc"): - continue - - file_ = os.path.join(dirpath, fname) - if (os.path.isfile(file_) and - os.path.normcase(file_) not in _normcased_files): - # We are skipping this file. Add it to the set. - will_skip.add(file_) - - will_remove = files | { - os.path.join(folder, "*") for folder in folders - } - - return will_remove, will_skip - - -class StashedUninstallPathSet(object): - """A set of file rename operations to stash files while - tentatively uninstalling them.""" - def __init__(self): - # type: () -> None - # Mapping from source file root to [Adjacent]TempDirectory - # for files under that directory. - self._save_dirs = {} # type: Dict[str, TempDirectory] - # (old path, new path) tuples for each move that may need - # to be undone. - self._moves = [] # type: List[Tuple[str, str]] - - def _get_directory_stash(self, path): - # type: (str) -> str - """Stashes a directory. - - Directories are stashed adjacent to their original location if - possible, or else moved/copied into the user's temp dir.""" - - try: - save_dir = AdjacentTempDirectory(path) # type: TempDirectory - except OSError: - save_dir = TempDirectory(kind="uninstall") - self._save_dirs[os.path.normcase(path)] = save_dir - - return save_dir.path - - def _get_file_stash(self, path): - # type: (str) -> str - """Stashes a file. - - If no root has been provided, one will be created for the directory - in the user's temp directory.""" - path = os.path.normcase(path) - head, old_head = os.path.dirname(path), None - save_dir = None - - while head != old_head: - try: - save_dir = self._save_dirs[head] - break - except KeyError: - pass - head, old_head = os.path.dirname(head), head - else: - # Did not find any suitable root - head = os.path.dirname(path) - save_dir = TempDirectory(kind='uninstall') - self._save_dirs[head] = save_dir - - relpath = os.path.relpath(path, head) - if relpath and relpath != os.path.curdir: - return os.path.join(save_dir.path, relpath) - return save_dir.path - - def stash(self, path): - # type: (str) -> str - """Stashes the directory or file and returns its new location. - Handle symlinks as files to avoid modifying the symlink targets. - """ - path_is_dir = os.path.isdir(path) and not os.path.islink(path) - if path_is_dir: - new_path = self._get_directory_stash(path) - else: - new_path = self._get_file_stash(path) - - self._moves.append((path, new_path)) - if (path_is_dir and os.path.isdir(new_path)): - # If we're moving a directory, we need to - # remove the destination first or else it will be - # moved to inside the existing directory. - # We just created new_path ourselves, so it will - # be removable. - os.rmdir(new_path) - renames(path, new_path) - return new_path - - def commit(self): - # type: () -> None - """Commits the uninstall by removing stashed files.""" - for _, save_dir in self._save_dirs.items(): - save_dir.cleanup() - self._moves = [] - self._save_dirs = {} - - def rollback(self): - # type: () -> None - """Undoes the uninstall by moving stashed files back.""" - for p in self._moves: - logger.info("Moving to %s\n from %s", *p) - - for new_path, path in self._moves: - try: - logger.debug('Replacing %s from %s', new_path, path) - if os.path.isfile(new_path) or os.path.islink(new_path): - os.unlink(new_path) - elif os.path.isdir(new_path): - rmtree(new_path) - renames(path, new_path) - except OSError as ex: - logger.error("Failed to restore %s", new_path) - logger.debug("Exception: %s", ex) - - self.commit() - - @property - def can_rollback(self): - # type: () -> bool - return bool(self._moves) - - -class UninstallPathSet(object): - """A set of file paths to be removed in the uninstallation of a - requirement.""" - def __init__(self, dist): - # type: (Distribution) -> None - self.paths = set() # type: Set[str] - self._refuse = set() # type: Set[str] - self.pth = {} # type: Dict[str, UninstallPthEntries] - self.dist = dist - self._moved_paths = StashedUninstallPathSet() - - def _permitted(self, path): - # type: (str) -> bool - """ - Return True if the given path is one we are permitted to - remove/modify, False otherwise. - - """ - return is_local(path) - - def add(self, path): - # type: (str) -> None - head, tail = os.path.split(path) - - # we normalize the head to resolve parent directory symlinks, but not - # the tail, since we only want to uninstall symlinks, not their targets - path = os.path.join(normalize_path(head), os.path.normcase(tail)) - - if not os.path.exists(path): - return - if self._permitted(path): - self.paths.add(path) - else: - self._refuse.add(path) - - # __pycache__ files can show up after 'installed-files.txt' is created, - # due to imports - if os.path.splitext(path)[1] == '.py' and uses_pycache: - self.add(cache_from_source(path)) - - def add_pth(self, pth_file, entry): - # type: (str, str) -> None - pth_file = normalize_path(pth_file) - if self._permitted(pth_file): - if pth_file not in self.pth: - self.pth[pth_file] = UninstallPthEntries(pth_file) - self.pth[pth_file].add(entry) - else: - self._refuse.add(pth_file) - - def remove(self, auto_confirm=False, verbose=False): - # type: (bool, bool) -> None - """Remove paths in ``self.paths`` with confirmation (unless - ``auto_confirm`` is True).""" - - if not self.paths: - logger.info( - "Can't uninstall '%s'. No files were found to uninstall.", - self.dist.project_name, - ) - return - - dist_name_version = ( - self.dist.project_name + "-" + self.dist.version - ) - logger.info('Uninstalling %s:', dist_name_version) - - with indent_log(): - if auto_confirm or self._allowed_to_proceed(verbose): - moved = self._moved_paths - - for_rename = compress_for_rename(self.paths) - - for path in sorted(compact(for_rename)): - moved.stash(path) - logger.debug('Removing file or directory %s', path) - - for pth in self.pth.values(): - pth.remove() - - logger.info('Successfully uninstalled %s', dist_name_version) - - def _allowed_to_proceed(self, verbose): - # type: (bool) -> bool - """Display which files would be deleted and prompt for confirmation - """ - - def _display(msg, paths): - # type: (str, Iterable[str]) -> None - if not paths: - return - - logger.info(msg) - with indent_log(): - for path in sorted(compact(paths)): - logger.info(path) - - if not verbose: - will_remove, will_skip = compress_for_output_listing(self.paths) - else: - # In verbose mode, display all the files that are going to be - # deleted. - will_remove = set(self.paths) - will_skip = set() - - _display('Would remove:', will_remove) - _display('Would not remove (might be manually added):', will_skip) - _display('Would not remove (outside of prefix):', self._refuse) - if verbose: - _display('Will actually move:', compress_for_rename(self.paths)) - - return ask('Proceed (y/n)? ', ('y', 'n')) == 'y' - - def rollback(self): - # type: () -> None - """Rollback the changes previously made by remove().""" - if not self._moved_paths.can_rollback: - logger.error( - "Can't roll back %s; was not uninstalled", - self.dist.project_name, - ) - return - logger.info('Rolling back uninstall of %s', self.dist.project_name) - self._moved_paths.rollback() - for pth in self.pth.values(): - pth.rollback() - - def commit(self): - # type: () -> None - """Remove temporary save dir: rollback will no longer be possible.""" - self._moved_paths.commit() - - @classmethod - def from_dist(cls, dist): - # type: (Distribution) -> UninstallPathSet - dist_path = normalize_path(dist.location) - if not dist_is_local(dist): - logger.info( - "Not uninstalling %s at %s, outside environment %s", - dist.key, - dist_path, - sys.prefix, - ) - return cls(dist) - - if dist_path in {p for p in {sysconfig.get_path("stdlib"), - sysconfig.get_path("platstdlib")} - if p}: - logger.info( - "Not uninstalling %s at %s, as it is in the standard library.", - dist.key, - dist_path, - ) - return cls(dist) - - paths_to_remove = cls(dist) - develop_egg_link = egg_link_path(dist) - develop_egg_link_egg_info = '{}.egg-info'.format( - pkg_resources.to_filename(dist.project_name)) - egg_info_exists = dist.egg_info and os.path.exists(dist.egg_info) - # Special case for distutils installed package - distutils_egg_info = getattr(dist._provider, 'path', None) - - # Uninstall cases order do matter as in the case of 2 installs of the - # same package, pip needs to uninstall the currently detected version - if (egg_info_exists and dist.egg_info.endswith('.egg-info') and - not dist.egg_info.endswith(develop_egg_link_egg_info)): - # if dist.egg_info.endswith(develop_egg_link_egg_info), we - # are in fact in the develop_egg_link case - paths_to_remove.add(dist.egg_info) - if dist.has_metadata('installed-files.txt'): - for installed_file in dist.get_metadata( - 'installed-files.txt').splitlines(): - path = os.path.normpath( - os.path.join(dist.egg_info, installed_file) - ) - paths_to_remove.add(path) - # FIXME: need a test for this elif block - # occurs with --single-version-externally-managed/--record outside - # of pip - elif dist.has_metadata('top_level.txt'): - if dist.has_metadata('namespace_packages.txt'): - namespaces = dist.get_metadata('namespace_packages.txt') - else: - namespaces = [] - for top_level_pkg in [ - p for p - in dist.get_metadata('top_level.txt').splitlines() - if p and p not in namespaces]: - path = os.path.join(dist.location, top_level_pkg) - paths_to_remove.add(path) - paths_to_remove.add(path + '.py') - paths_to_remove.add(path + '.pyc') - paths_to_remove.add(path + '.pyo') - - elif distutils_egg_info: - raise UninstallationError( - "Cannot uninstall {!r}. It is a distutils installed project " - "and thus we cannot accurately determine which files belong " - "to it which would lead to only a partial uninstall.".format( - dist.project_name, - ) - ) - - elif dist.location.endswith('.egg'): - # package installed by easy_install - # We cannot match on dist.egg_name because it can slightly vary - # i.e. setuptools-0.6c11-py2.6.egg vs setuptools-0.6rc11-py2.6.egg - paths_to_remove.add(dist.location) - easy_install_egg = os.path.split(dist.location)[1] - easy_install_pth = os.path.join(os.path.dirname(dist.location), - 'easy-install.pth') - paths_to_remove.add_pth(easy_install_pth, './' + easy_install_egg) - - elif egg_info_exists and dist.egg_info.endswith('.dist-info'): - for path in uninstallation_paths(dist): - paths_to_remove.add(path) - - elif develop_egg_link: - # develop egg - with open(develop_egg_link, 'r') as fh: - link_pointer = os.path.normcase(fh.readline().strip()) - assert (link_pointer == dist.location), ( - 'Egg-link {} does not match installed location of {} ' - '(at {})'.format( - link_pointer, dist.project_name, dist.location) - ) - paths_to_remove.add(develop_egg_link) - easy_install_pth = os.path.join(os.path.dirname(develop_egg_link), - 'easy-install.pth') - paths_to_remove.add_pth(easy_install_pth, dist.location) - - else: - logger.debug( - 'Not sure how to uninstall: %s - Check: %s', - dist, dist.location, - ) - - # find distutils scripts= scripts - if dist.has_metadata('scripts') and dist.metadata_isdir('scripts'): - for script in dist.metadata_listdir('scripts'): - if dist_in_usersite(dist): - bin_dir = bin_user - else: - bin_dir = bin_py - paths_to_remove.add(os.path.join(bin_dir, script)) - if WINDOWS: - paths_to_remove.add(os.path.join(bin_dir, script) + '.bat') - - # find console_scripts - _scripts_to_remove = [] - console_scripts = dist.get_entry_map(group='console_scripts') - for name in console_scripts.keys(): - _scripts_to_remove.extend(_script_names(dist, name, False)) - # find gui_scripts - gui_scripts = dist.get_entry_map(group='gui_scripts') - for name in gui_scripts.keys(): - _scripts_to_remove.extend(_script_names(dist, name, True)) - - for s in _scripts_to_remove: - paths_to_remove.add(s) - - return paths_to_remove - - -class UninstallPthEntries(object): - def __init__(self, pth_file): - # type: (str) -> None - self.file = pth_file - self.entries = set() # type: Set[str] - self._saved_lines = None # type: Optional[List[bytes]] - - def add(self, entry): - # type: (str) -> None - entry = os.path.normcase(entry) - # On Windows, os.path.normcase converts the entry to use - # backslashes. This is correct for entries that describe absolute - # paths outside of site-packages, but all the others use forward - # slashes. - # os.path.splitdrive is used instead of os.path.isabs because isabs - # treats non-absolute paths with drive letter markings like c:foo\bar - # as absolute paths. It also does not recognize UNC paths if they don't - # have more than "\\sever\share". Valid examples: "\\server\share\" or - # "\\server\share\folder". Python 2.7.8+ support UNC in splitdrive. - if WINDOWS and not os.path.splitdrive(entry)[0]: - entry = entry.replace('\\', '/') - self.entries.add(entry) - - def remove(self): - # type: () -> None - logger.debug('Removing pth entries from %s:', self.file) - - # If the file doesn't exist, log a warning and return - if not os.path.isfile(self.file): - logger.warning( - "Cannot remove entries from nonexistent file {}".format( - self.file) - ) - return - with open(self.file, 'rb') as fh: - # windows uses '\r\n' with py3k, but uses '\n' with py2.x - lines = fh.readlines() - self._saved_lines = lines - if any(b'\r\n' in line for line in lines): - endline = '\r\n' - else: - endline = '\n' - # handle missing trailing newline - if lines and not lines[-1].endswith(endline.encode("utf-8")): - lines[-1] = lines[-1] + endline.encode("utf-8") - for entry in self.entries: - try: - logger.debug('Removing entry: %s', entry) - lines.remove((entry + endline).encode("utf-8")) - except ValueError: - pass - with open(self.file, 'wb') as fh: - fh.writelines(lines) - - def rollback(self): - # type: () -> bool - if self._saved_lines is None: - logger.error( - 'Cannot roll back changes to %s, none were made', self.file - ) - return False - logger.debug('Rolling %s back to previous state', self.file) - with open(self.file, 'wb') as fh: - fh.writelines(self._saved_lines) - return True diff --git a/venv/lib/python3.8/site-packages/pip/_internal/resolution/__init__.py b/venv/lib/python3.8/site-packages/pip/_internal/resolution/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.8/site-packages/pip/_internal/resolution/base.py b/venv/lib/python3.8/site-packages/pip/_internal/resolution/base.py deleted file mode 100644 index 2fa118b..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/resolution/base.py +++ /dev/null @@ -1,20 +0,0 @@ -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import Callable, List - from pip._internal.req.req_install import InstallRequirement - from pip._internal.req.req_set import RequirementSet - - InstallRequirementProvider = Callable[ - [str, InstallRequirement], InstallRequirement - ] - - -class BaseResolver(object): - def resolve(self, root_reqs, check_supported_wheels): - # type: (List[InstallRequirement], bool) -> RequirementSet - raise NotImplementedError() - - def get_installation_order(self, req_set): - # type: (RequirementSet) -> List[InstallRequirement] - raise NotImplementedError() diff --git a/venv/lib/python3.8/site-packages/pip/_internal/resolution/legacy/__init__.py b/venv/lib/python3.8/site-packages/pip/_internal/resolution/legacy/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.8/site-packages/pip/_internal/resolution/legacy/resolver.py b/venv/lib/python3.8/site-packages/pip/_internal/resolution/legacy/resolver.py deleted file mode 100644 index cdb44d1..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/resolution/legacy/resolver.py +++ /dev/null @@ -1,459 +0,0 @@ -"""Dependency Resolution - -The dependency resolution in pip is performed as follows: - -for top-level requirements: - a. only one spec allowed per project, regardless of conflicts or not. - otherwise a "double requirement" exception is raised - b. they override sub-dependency requirements. -for sub-dependencies - a. "first found, wins" (where the order is breadth first) -""" - -# The following comment should be removed at some point in the future. -# mypy: strict-optional=False -# mypy: disallow-untyped-defs=False - -import logging -import sys -from collections import defaultdict -from itertools import chain - -from pip._vendor.packaging import specifiers - -from pip._internal.exceptions import ( - BestVersionAlreadyInstalled, - DistributionNotFound, - HashError, - HashErrors, - UnsupportedPythonVersion, -) -from pip._internal.req.req_set import RequirementSet -from pip._internal.resolution.base import BaseResolver -from pip._internal.utils.compatibility_tags import get_supported -from pip._internal.utils.logging import indent_log -from pip._internal.utils.misc import dist_in_usersite, normalize_version_info -from pip._internal.utils.packaging import ( - check_requires_python, - get_requires_python, -) -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import DefaultDict, List, Optional, Set, Tuple - from pip._vendor import pkg_resources - - from pip._internal.cache import WheelCache - from pip._internal.distributions import AbstractDistribution - from pip._internal.index.package_finder import PackageFinder - from pip._internal.operations.prepare import RequirementPreparer - from pip._internal.req.req_install import InstallRequirement - from pip._internal.resolution.base import InstallRequirementProvider - - DiscoveredDependencies = DefaultDict[str, List[InstallRequirement]] - -logger = logging.getLogger(__name__) - - -def _check_dist_requires_python( - dist, # type: pkg_resources.Distribution - version_info, # type: Tuple[int, int, int] - ignore_requires_python=False, # type: bool -): - # type: (...) -> None - """ - Check whether the given Python version is compatible with a distribution's - "Requires-Python" value. - - :param version_info: A 3-tuple of ints representing the Python - major-minor-micro version to check. - :param ignore_requires_python: Whether to ignore the "Requires-Python" - value if the given Python version isn't compatible. - - :raises UnsupportedPythonVersion: When the given Python version isn't - compatible. - """ - requires_python = get_requires_python(dist) - try: - is_compatible = check_requires_python( - requires_python, version_info=version_info, - ) - except specifiers.InvalidSpecifier as exc: - logger.warning( - "Package %r has an invalid Requires-Python: %s", - dist.project_name, exc, - ) - return - - if is_compatible: - return - - version = '.'.join(map(str, version_info)) - if ignore_requires_python: - logger.debug( - 'Ignoring failed Requires-Python check for package %r: ' - '%s not in %r', - dist.project_name, version, requires_python, - ) - return - - raise UnsupportedPythonVersion( - 'Package {!r} requires a different Python: {} not in {!r}'.format( - dist.project_name, version, requires_python, - )) - - -class Resolver(BaseResolver): - """Resolves which packages need to be installed/uninstalled to perform \ - the requested operation without breaking the requirements of any package. - """ - - _allowed_strategies = {"eager", "only-if-needed", "to-satisfy-only"} - - def __init__( - self, - preparer, # type: RequirementPreparer - finder, # type: PackageFinder - wheel_cache, # type: Optional[WheelCache] - make_install_req, # type: InstallRequirementProvider - use_user_site, # type: bool - ignore_dependencies, # type: bool - ignore_installed, # type: bool - ignore_requires_python, # type: bool - force_reinstall, # type: bool - upgrade_strategy, # type: str - py_version_info=None, # type: Optional[Tuple[int, ...]] - ): - # type: (...) -> None - super(Resolver, self).__init__() - assert upgrade_strategy in self._allowed_strategies - - if py_version_info is None: - py_version_info = sys.version_info[:3] - else: - py_version_info = normalize_version_info(py_version_info) - - self._py_version_info = py_version_info - - self.preparer = preparer - self.finder = finder - self.wheel_cache = wheel_cache - - self.upgrade_strategy = upgrade_strategy - self.force_reinstall = force_reinstall - self.ignore_dependencies = ignore_dependencies - self.ignore_installed = ignore_installed - self.ignore_requires_python = ignore_requires_python - self.use_user_site = use_user_site - self._make_install_req = make_install_req - - self._discovered_dependencies = \ - defaultdict(list) # type: DiscoveredDependencies - - def resolve(self, root_reqs, check_supported_wheels): - # type: (List[InstallRequirement], bool) -> RequirementSet - """Resolve what operations need to be done - - As a side-effect of this method, the packages (and their dependencies) - are downloaded, unpacked and prepared for installation. This - preparation is done by ``pip.operations.prepare``. - - Once PyPI has static dependency metadata available, it would be - possible to move the preparation to become a step separated from - dependency resolution. - """ - requirement_set = RequirementSet( - check_supported_wheels=check_supported_wheels - ) - for req in root_reqs: - requirement_set.add_requirement(req) - - # Actually prepare the files, and collect any exceptions. Most hash - # exceptions cannot be checked ahead of time, because - # _populate_link() needs to be called before we can make decisions - # based on link type. - discovered_reqs = [] # type: List[InstallRequirement] - hash_errors = HashErrors() - for req in chain(root_reqs, discovered_reqs): - try: - discovered_reqs.extend(self._resolve_one(requirement_set, req)) - except HashError as exc: - exc.req = req - hash_errors.append(exc) - - if hash_errors: - raise hash_errors - - return requirement_set - - def _is_upgrade_allowed(self, req): - # type: (InstallRequirement) -> bool - if self.upgrade_strategy == "to-satisfy-only": - return False - elif self.upgrade_strategy == "eager": - return True - else: - assert self.upgrade_strategy == "only-if-needed" - return req.is_direct - - def _set_req_to_reinstall(self, req): - # type: (InstallRequirement) -> None - """ - Set a requirement to be installed. - """ - # Don't uninstall the conflict if doing a user install and the - # conflict is not a user install. - if not self.use_user_site or dist_in_usersite(req.satisfied_by): - req.should_reinstall = True - req.satisfied_by = None - - def _check_skip_installed(self, req_to_install): - # type: (InstallRequirement) -> Optional[str] - """Check if req_to_install should be skipped. - - This will check if the req is installed, and whether we should upgrade - or reinstall it, taking into account all the relevant user options. - - After calling this req_to_install will only have satisfied_by set to - None if the req_to_install is to be upgraded/reinstalled etc. Any - other value will be a dist recording the current thing installed that - satisfies the requirement. - - Note that for vcs urls and the like we can't assess skipping in this - routine - we simply identify that we need to pull the thing down, - then later on it is pulled down and introspected to assess upgrade/ - reinstalls etc. - - :return: A text reason for why it was skipped, or None. - """ - if self.ignore_installed: - return None - - req_to_install.check_if_exists(self.use_user_site) - if not req_to_install.satisfied_by: - return None - - if self.force_reinstall: - self._set_req_to_reinstall(req_to_install) - return None - - if not self._is_upgrade_allowed(req_to_install): - if self.upgrade_strategy == "only-if-needed": - return 'already satisfied, skipping upgrade' - return 'already satisfied' - - # Check for the possibility of an upgrade. For link-based - # requirements we have to pull the tree down and inspect to assess - # the version #, so it's handled way down. - if not req_to_install.link: - try: - self.finder.find_requirement(req_to_install, upgrade=True) - except BestVersionAlreadyInstalled: - # Then the best version is installed. - return 'already up-to-date' - except DistributionNotFound: - # No distribution found, so we squash the error. It will - # be raised later when we re-try later to do the install. - # Why don't we just raise here? - pass - - self._set_req_to_reinstall(req_to_install) - return None - - def _populate_link(self, req): - # type: (InstallRequirement) -> None - """Ensure that if a link can be found for this, that it is found. - - Note that req.link may still be None - if the requirement is already - installed and not needed to be upgraded based on the return value of - _is_upgrade_allowed(). - - If preparer.require_hashes is True, don't use the wheel cache, because - cached wheels, always built locally, have different hashes than the - files downloaded from the index server and thus throw false hash - mismatches. Furthermore, cached wheels at present have undeterministic - contents due to file modification times. - """ - upgrade = self._is_upgrade_allowed(req) - if req.link is None: - req.link = self.finder.find_requirement(req, upgrade) - - if self.wheel_cache is None or self.preparer.require_hashes: - return - cache_entry = self.wheel_cache.get_cache_entry( - link=req.link, - package_name=req.name, - supported_tags=get_supported(), - ) - if cache_entry is not None: - logger.debug('Using cached wheel link: %s', cache_entry.link) - if req.link is req.original_link and cache_entry.persistent: - req.original_link_is_in_wheel_cache = True - req.link = cache_entry.link - - def _get_abstract_dist_for(self, req): - # type: (InstallRequirement) -> AbstractDistribution - """Takes a InstallRequirement and returns a single AbstractDist \ - representing a prepared variant of the same. - """ - if req.editable: - return self.preparer.prepare_editable_requirement(req) - - # satisfied_by is only evaluated by calling _check_skip_installed, - # so it must be None here. - assert req.satisfied_by is None - skip_reason = self._check_skip_installed(req) - - if req.satisfied_by: - return self.preparer.prepare_installed_requirement( - req, skip_reason - ) - - # We eagerly populate the link, since that's our "legacy" behavior. - self._populate_link(req) - abstract_dist = self.preparer.prepare_linked_requirement(req) - - # NOTE - # The following portion is for determining if a certain package is - # going to be re-installed/upgraded or not and reporting to the user. - # This should probably get cleaned up in a future refactor. - - # req.req is only avail after unpack for URL - # pkgs repeat check_if_exists to uninstall-on-upgrade - # (#14) - if not self.ignore_installed: - req.check_if_exists(self.use_user_site) - - if req.satisfied_by: - should_modify = ( - self.upgrade_strategy != "to-satisfy-only" or - self.force_reinstall or - self.ignore_installed or - req.link.scheme == 'file' - ) - if should_modify: - self._set_req_to_reinstall(req) - else: - logger.info( - 'Requirement already satisfied (use --upgrade to upgrade):' - ' %s', req, - ) - - return abstract_dist - - def _resolve_one( - self, - requirement_set, # type: RequirementSet - req_to_install, # type: InstallRequirement - ): - # type: (...) -> List[InstallRequirement] - """Prepare a single requirements file. - - :return: A list of additional InstallRequirements to also install. - """ - # Tell user what we are doing for this requirement: - # obtain (editable), skipping, processing (local url), collecting - # (remote url or package name) - if req_to_install.constraint or req_to_install.prepared: - return [] - - req_to_install.prepared = True - - abstract_dist = self._get_abstract_dist_for(req_to_install) - - # Parse and return dependencies - dist = abstract_dist.get_pkg_resources_distribution() - # This will raise UnsupportedPythonVersion if the given Python - # version isn't compatible with the distribution's Requires-Python. - _check_dist_requires_python( - dist, version_info=self._py_version_info, - ignore_requires_python=self.ignore_requires_python, - ) - - more_reqs = [] # type: List[InstallRequirement] - - def add_req(subreq, extras_requested): - sub_install_req = self._make_install_req( - str(subreq), - req_to_install, - ) - parent_req_name = req_to_install.name - to_scan_again, add_to_parent = requirement_set.add_requirement( - sub_install_req, - parent_req_name=parent_req_name, - extras_requested=extras_requested, - ) - if parent_req_name and add_to_parent: - self._discovered_dependencies[parent_req_name].append( - add_to_parent - ) - more_reqs.extend(to_scan_again) - - with indent_log(): - # We add req_to_install before its dependencies, so that we - # can refer to it when adding dependencies. - if not requirement_set.has_requirement(req_to_install.name): - # 'unnamed' requirements will get added here - # 'unnamed' requirements can only come from being directly - # provided by the user. - assert req_to_install.is_direct - requirement_set.add_requirement( - req_to_install, parent_req_name=None, - ) - - if not self.ignore_dependencies: - if req_to_install.extras: - logger.debug( - "Installing extra requirements: %r", - ','.join(req_to_install.extras), - ) - missing_requested = sorted( - set(req_to_install.extras) - set(dist.extras) - ) - for missing in missing_requested: - logger.warning( - '%s does not provide the extra \'%s\'', - dist, missing - ) - - available_requested = sorted( - set(dist.extras) & set(req_to_install.extras) - ) - for subreq in dist.requires(available_requested): - add_req(subreq, extras_requested=available_requested) - - if not req_to_install.editable and not req_to_install.satisfied_by: - # XXX: --no-install leads this to report 'Successfully - # downloaded' for only non-editable reqs, even though we took - # action on them. - req_to_install.successfully_downloaded = True - - return more_reqs - - def get_installation_order(self, req_set): - # type: (RequirementSet) -> List[InstallRequirement] - """Create the installation order. - - The installation order is topological - requirements are installed - before the requiring thing. We break cycles at an arbitrary point, - and make no other guarantees. - """ - # The current implementation, which we may change at any point - # installs the user specified things in the order given, except when - # dependencies must come earlier to achieve topological order. - order = [] - ordered_reqs = set() # type: Set[InstallRequirement] - - def schedule(req): - if req.satisfied_by or req in ordered_reqs: - return - if req.constraint: - return - ordered_reqs.add(req) - for dep in self._discovered_dependencies[req.name]: - schedule(dep) - order.append(req) - - for install_req in req_set.requirements.values(): - schedule(install_req) - return order diff --git a/venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/__init__.py b/venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/base.py b/venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/base.py deleted file mode 100644 index 5f99618..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/base.py +++ /dev/null @@ -1,52 +0,0 @@ -from pip._vendor.packaging.utils import canonicalize_name - -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import Optional, Sequence, Set - - from pip._internal.req.req_install import InstallRequirement - from pip._vendor.packaging.version import _BaseVersion - - -def format_name(project, extras): - # type: (str, Set[str]) -> str - if not extras: - return project - canonical_extras = sorted(canonicalize_name(e) for e in extras) - return "{}[{}]".format(project, ",".join(canonical_extras)) - - -class Requirement(object): - @property - def name(self): - # type: () -> str - raise NotImplementedError("Subclass should override") - - def find_matches(self): - # type: () -> Sequence[Candidate] - raise NotImplementedError("Subclass should override") - - def is_satisfied_by(self, candidate): - # type: (Candidate) -> bool - return False - - -class Candidate(object): - @property - def name(self): - # type: () -> str - raise NotImplementedError("Override in subclass") - - @property - def version(self): - # type: () -> _BaseVersion - raise NotImplementedError("Override in subclass") - - def get_dependencies(self): - # type: () -> Sequence[Requirement] - raise NotImplementedError("Override in subclass") - - def get_install_requirement(self): - # type: () -> Optional[InstallRequirement] - raise NotImplementedError("Override in subclass") diff --git a/venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/candidates.py b/venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/candidates.py deleted file mode 100644 index f8461ad..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/candidates.py +++ /dev/null @@ -1,450 +0,0 @@ -import logging -import sys - -from pip._vendor.packaging.specifiers import InvalidSpecifier, SpecifierSet -from pip._vendor.packaging.utils import canonicalize_name -from pip._vendor.packaging.version import Version - -from pip._internal.req.constructors import ( - install_req_from_editable, - install_req_from_line, -) -from pip._internal.req.req_install import InstallRequirement -from pip._internal.utils.misc import normalize_version_info -from pip._internal.utils.packaging import get_requires_python -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -from .base import Candidate, format_name - -if MYPY_CHECK_RUNNING: - from typing import Any, Optional, Sequence, Set, Tuple, Union - - from pip._vendor.packaging.version import _BaseVersion - from pip._vendor.pkg_resources import Distribution - - from pip._internal.distributions import AbstractDistribution - from pip._internal.models.link import Link - - from .base import Requirement - from .factory import Factory - - BaseCandidate = Union[ - "AlreadyInstalledCandidate", - "EditableCandidate", - "LinkCandidate", - ] - - -logger = logging.getLogger(__name__) - - -def make_install_req_from_link(link, parent): - # type: (Link, InstallRequirement) -> InstallRequirement - assert not parent.editable, "parent is editable" - return install_req_from_line( - link.url, - comes_from=parent.comes_from, - use_pep517=parent.use_pep517, - isolated=parent.isolated, - constraint=parent.constraint, - options=dict( - install_options=parent.install_options, - global_options=parent.global_options, - hashes=parent.hash_options - ), - ) - - -def make_install_req_from_editable(link, parent): - # type: (Link, InstallRequirement) -> InstallRequirement - assert parent.editable, "parent not editable" - return install_req_from_editable( - link.url, - comes_from=parent.comes_from, - use_pep517=parent.use_pep517, - isolated=parent.isolated, - constraint=parent.constraint, - options=dict( - install_options=parent.install_options, - global_options=parent.global_options, - hashes=parent.hash_options - ), - ) - - -def make_install_req_from_dist(dist, parent): - # type: (Distribution, InstallRequirement) -> InstallRequirement - ireq = install_req_from_line( - "{}=={}".format( - canonicalize_name(dist.project_name), - dist.parsed_version, - ), - comes_from=parent.comes_from, - use_pep517=parent.use_pep517, - isolated=parent.isolated, - constraint=parent.constraint, - options=dict( - install_options=parent.install_options, - global_options=parent.global_options, - hashes=parent.hash_options - ), - ) - ireq.satisfied_by = dist - return ireq - - -class _InstallRequirementBackedCandidate(Candidate): - def __init__( - self, - link, # type: Link - ireq, # type: InstallRequirement - factory, # type: Factory - name=None, # type: Optional[str] - version=None, # type: Optional[_BaseVersion] - ): - # type: (...) -> None - self.link = link - self._factory = factory - self._ireq = ireq - self._name = name - self._version = version - self._dist = None # type: Optional[Distribution] - - def __repr__(self): - # type: () -> str - return "{class_name}({link!r})".format( - class_name=self.__class__.__name__, - link=str(self.link), - ) - - def __eq__(self, other): - # type: (Any) -> bool - if isinstance(other, self.__class__): - return self.link == other.link - return False - - # Needed for Python 2, which does not implement this by default - def __ne__(self, other): - # type: (Any) -> bool - return not self.__eq__(other) - - @property - def name(self): - # type: () -> str - """The normalised name of the project the candidate refers to""" - if self._name is None: - self._name = canonicalize_name(self.dist.project_name) - return self._name - - @property - def version(self): - # type: () -> _BaseVersion - if self._version is None: - self._version = self.dist.parsed_version - return self._version - - def _prepare_abstract_distribution(self): - # type: () -> AbstractDistribution - raise NotImplementedError("Override in subclass") - - def _prepare(self): - # type: () -> None - if self._dist is not None: - return - - abstract_dist = self._prepare_abstract_distribution() - self._dist = abstract_dist.get_pkg_resources_distribution() - assert self._dist is not None, "Distribution already installed" - - # TODO: Abort cleanly here, as the resolution has been - # based on the wrong name/version until now, and - # so is wrong. - # TODO: (Longer term) Rather than abort, reject this candidate - # and backtrack. This would need resolvelib support. - # These should be "proper" errors, not just asserts, as they - # can result from user errors like a requirement "foo @ URL" - # when the project at URL has a name of "bar" in its metadata. - assert ( - self._name is None or - self._name == canonicalize_name(self._dist.project_name) - ), "Name mismatch: {!r} vs {!r}".format( - self._name, canonicalize_name(self._dist.project_name), - ) - assert ( - self._version is None or - self._version == self._dist.parsed_version - ), "Version mismatch: {!r} vs {!r}".format( - self._version, self._dist.parsed_version, - ) - - @property - def dist(self): - # type: () -> Distribution - self._prepare() - return self._dist - - def _get_requires_python_specifier(self): - # type: () -> Optional[SpecifierSet] - requires_python = get_requires_python(self.dist) - if requires_python is None: - return None - try: - spec = SpecifierSet(requires_python) - except InvalidSpecifier as e: - logger.warning( - "Package %r has an invalid Requires-Python: %s", self.name, e, - ) - return None - return spec - - def get_dependencies(self): - # type: () -> Sequence[Requirement] - deps = [ - self._factory.make_requirement_from_spec(str(r), self._ireq) - for r in self.dist.requires() - ] - python_dep = self._factory.make_requires_python_requirement( - self._get_requires_python_specifier(), - ) - if python_dep: - deps.append(python_dep) - return deps - - def get_install_requirement(self): - # type: () -> Optional[InstallRequirement] - self._prepare() - return self._ireq - - -class LinkCandidate(_InstallRequirementBackedCandidate): - def __init__( - self, - link, # type: Link - parent, # type: InstallRequirement - factory, # type: Factory - name=None, # type: Optional[str] - version=None, # type: Optional[_BaseVersion] - ): - # type: (...) -> None - super(LinkCandidate, self).__init__( - link=link, - ireq=make_install_req_from_link(link, parent), - factory=factory, - name=name, - version=version, - ) - - def _prepare_abstract_distribution(self): - # type: () -> AbstractDistribution - return self._factory.preparer.prepare_linked_requirement(self._ireq) - - -class EditableCandidate(_InstallRequirementBackedCandidate): - def __init__( - self, - link, # type: Link - parent, # type: InstallRequirement - factory, # type: Factory - name=None, # type: Optional[str] - version=None, # type: Optional[_BaseVersion] - ): - # type: (...) -> None - super(EditableCandidate, self).__init__( - link=link, - ireq=make_install_req_from_editable(link, parent), - factory=factory, - name=name, - version=version, - ) - - def _prepare_abstract_distribution(self): - # type: () -> AbstractDistribution - return self._factory.preparer.prepare_editable_requirement(self._ireq) - - -class AlreadyInstalledCandidate(Candidate): - def __init__( - self, - dist, # type: Distribution - parent, # type: InstallRequirement - factory, # type: Factory - ): - # type: (...) -> None - self.dist = dist - self._ireq = make_install_req_from_dist(dist, parent) - self._factory = factory - - # This is just logging some messages, so we can do it eagerly. - # The returned dist would be exactly the same as self.dist because we - # set satisfied_by in make_install_req_from_dist. - # TODO: Supply reason based on force_reinstall and upgrade_strategy. - skip_reason = "already satisfied" - factory.preparer.prepare_installed_requirement(self._ireq, skip_reason) - - def __repr__(self): - # type: () -> str - return "{class_name}({distribution!r})".format( - class_name=self.__class__.__name__, - distribution=self.dist, - ) - - def __eq__(self, other): - # type: (Any) -> bool - if isinstance(other, self.__class__): - return self.name == other.name and self.version == other.version - return False - - # Needed for Python 2, which does not implement this by default - def __ne__(self, other): - # type: (Any) -> bool - return not self.__eq__(other) - - @property - def name(self): - # type: () -> str - return canonicalize_name(self.dist.project_name) - - @property - def version(self): - # type: () -> _BaseVersion - return self.dist.parsed_version - - def get_dependencies(self): - # type: () -> Sequence[Requirement] - return [ - self._factory.make_requirement_from_spec(str(r), self._ireq) - for r in self.dist.requires() - ] - - def get_install_requirement(self): - # type: () -> Optional[InstallRequirement] - return None - - -class ExtrasCandidate(Candidate): - """A candidate that has 'extras', indicating additional dependencies. - - Requirements can be for a project with dependencies, something like - foo[extra]. The extras don't affect the project/version being installed - directly, but indicate that we need additional dependencies. We model that - by having an artificial ExtrasCandidate that wraps the "base" candidate. - - The ExtrasCandidate differs from the base in the following ways: - - 1. It has a unique name, of the form foo[extra]. This causes the resolver - to treat it as a separate node in the dependency graph. - 2. When we're getting the candidate's dependencies, - a) We specify that we want the extra dependencies as well. - b) We add a dependency on the base candidate (matching the name and - version). See below for why this is needed. - 3. We return None for the underlying InstallRequirement, as the base - candidate will provide it, and we don't want to end up with duplicates. - - The dependency on the base candidate is needed so that the resolver can't - decide that it should recommend foo[extra1] version 1.0 and foo[extra2] - version 2.0. Having those candidates depend on foo=1.0 and foo=2.0 - respectively forces the resolver to recognise that this is a conflict. - """ - def __init__( - self, - base, # type: BaseCandidate - extras, # type: Set[str] - ): - # type: (...) -> None - self.base = base - self.extras = extras - - def __repr__(self): - # type: () -> str - return "{class_name}(base={base!r}, extras={extras!r})".format( - class_name=self.__class__.__name__, - base=self.base, - extras=self.extras, - ) - - def __eq__(self, other): - # type: (Any) -> bool - if isinstance(other, self.__class__): - return self.base == other.base and self.extras == other.extras - return False - - # Needed for Python 2, which does not implement this by default - def __ne__(self, other): - # type: (Any) -> bool - return not self.__eq__(other) - - @property - def name(self): - # type: () -> str - """The normalised name of the project the candidate refers to""" - return format_name(self.base.name, self.extras) - - @property - def version(self): - # type: () -> _BaseVersion - return self.base.version - - def get_dependencies(self): - # type: () -> Sequence[Requirement] - factory = self.base._factory - - # The user may have specified extras that the candidate doesn't - # support. We ignore any unsupported extras here. - valid_extras = self.extras.intersection(self.base.dist.extras) - invalid_extras = self.extras.difference(self.base.dist.extras) - if invalid_extras: - logger.warning( - "Invalid extras specified in %s: %s", - self.name, - ','.join(sorted(invalid_extras)) - ) - - deps = [ - factory.make_requirement_from_spec(str(r), self.base._ireq) - for r in self.base.dist.requires(valid_extras) - ] - # Add a dependency on the exact base. - # (See note 2b in the class docstring) - spec = "{}=={}".format(self.base.name, self.base.version) - deps.append(factory.make_requirement_from_spec(spec, self.base._ireq)) - return deps - - def get_install_requirement(self): - # type: () -> Optional[InstallRequirement] - # We don't return anything here, because we always - # depend on the base candidate, and we'll get the - # install requirement from that. - return None - - -class RequiresPythonCandidate(Candidate): - def __init__(self, py_version_info): - # type: (Optional[Tuple[int, ...]]) -> None - if py_version_info is not None: - version_info = normalize_version_info(py_version_info) - else: - version_info = sys.version_info[:3] - self._version = Version(".".join(str(c) for c in version_info)) - - # We don't need to implement __eq__() and __ne__() since there is always - # only one RequiresPythonCandidate in a resolution, i.e. the host Python. - # The built-in object.__eq__() and object.__ne__() do exactly what we want. - - @property - def name(self): - # type: () -> str - # Avoid conflicting with the PyPI package "Python". - return "<Python fom Requires-Python>" - - @property - def version(self): - # type: () -> _BaseVersion - return self._version - - def get_dependencies(self): - # type: () -> Sequence[Requirement] - return [] - - def get_install_requirement(self): - # type: () -> Optional[InstallRequirement] - return None diff --git a/venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/factory.py b/venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/factory.py deleted file mode 100644 index 23686f7..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/factory.py +++ /dev/null @@ -1,201 +0,0 @@ -from pip._vendor.packaging.utils import canonicalize_name - -from pip._internal.exceptions import ( - InstallationError, - UnsupportedPythonVersion, -) -from pip._internal.utils.misc import get_installed_distributions -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -from .candidates import ( - AlreadyInstalledCandidate, - EditableCandidate, - ExtrasCandidate, - LinkCandidate, - RequiresPythonCandidate, -) -from .requirements import ( - ExplicitRequirement, - RequiresPythonRequirement, - SpecifierRequirement, -) - -if MYPY_CHECK_RUNNING: - from typing import Dict, Iterator, Optional, Set, Tuple, TypeVar - - from pip._vendor.packaging.specifiers import SpecifierSet - from pip._vendor.packaging.version import _BaseVersion - from pip._vendor.pkg_resources import Distribution - from pip._vendor.resolvelib import ResolutionImpossible - - from pip._internal.index.package_finder import PackageFinder - from pip._internal.models.link import Link - from pip._internal.operations.prepare import RequirementPreparer - from pip._internal.req.req_install import InstallRequirement - from pip._internal.resolution.base import InstallRequirementProvider - - from .base import Candidate, Requirement - from .candidates import BaseCandidate - - C = TypeVar("C") - Cache = Dict[Link, C] - - -class Factory(object): - def __init__( - self, - finder, # type: PackageFinder - preparer, # type: RequirementPreparer - make_install_req, # type: InstallRequirementProvider - force_reinstall, # type: bool - ignore_installed, # type: bool - ignore_requires_python, # type: bool - py_version_info=None, # type: Optional[Tuple[int, ...]] - ): - # type: (...) -> None - self.finder = finder - self.preparer = preparer - self._python_candidate = RequiresPythonCandidate(py_version_info) - self._make_install_req_from_spec = make_install_req - self._force_reinstall = force_reinstall - self._ignore_requires_python = ignore_requires_python - - self._link_candidate_cache = {} # type: Cache[LinkCandidate] - self._editable_candidate_cache = {} # type: Cache[EditableCandidate] - - if not ignore_installed: - self._installed_dists = { - canonicalize_name(dist.project_name): dist - for dist in get_installed_distributions() - } - else: - self._installed_dists = {} - - def _make_candidate_from_dist( - self, - dist, # type: Distribution - extras, # type: Set[str] - parent, # type: InstallRequirement - ): - # type: (...) -> Candidate - base = AlreadyInstalledCandidate(dist, parent, factory=self) - if extras: - return ExtrasCandidate(base, extras) - return base - - def _make_candidate_from_link( - self, - link, # type: Link - extras, # type: Set[str] - parent, # type: InstallRequirement - name=None, # type: Optional[str] - version=None, # type: Optional[_BaseVersion] - ): - # type: (...) -> Candidate - # TODO: Check already installed candidate, and use it if the link and - # editable flag match. - if parent.editable: - if link not in self._editable_candidate_cache: - self._editable_candidate_cache[link] = EditableCandidate( - link, parent, factory=self, name=name, version=version, - ) - base = self._editable_candidate_cache[link] # type: BaseCandidate - else: - if link not in self._link_candidate_cache: - self._link_candidate_cache[link] = LinkCandidate( - link, parent, factory=self, name=name, version=version, - ) - base = self._link_candidate_cache[link] - if extras: - return ExtrasCandidate(base, extras) - return base - - def iter_found_candidates(self, ireq, extras): - # type: (InstallRequirement, Set[str]) -> Iterator[Candidate] - name = canonicalize_name(ireq.req.name) - if not self._force_reinstall: - installed_dist = self._installed_dists.get(name) - else: - installed_dist = None - - found = self.finder.find_best_candidate( - project_name=ireq.req.name, - specifier=ireq.req.specifier, - hashes=ireq.hashes(trust_internet=False), - ) - for ican in found.iter_applicable(): - if (installed_dist is not None and - installed_dist.parsed_version == ican.version): - continue - yield self._make_candidate_from_link( - link=ican.link, - extras=extras, - parent=ireq, - name=name, - version=ican.version, - ) - - # Return installed distribution if it matches the specifier. This is - # done last so the resolver will prefer it over downloading links. - if (installed_dist is not None and - installed_dist.parsed_version in ireq.req.specifier): - yield self._make_candidate_from_dist( - dist=installed_dist, - extras=extras, - parent=ireq, - ) - - def make_requirement_from_install_req(self, ireq): - # type: (InstallRequirement) -> Requirement - if ireq.link: - # TODO: Get name and version from ireq, if possible? - # Specifically, this might be needed in "name @ URL" - # syntax - need to check where that syntax is handled. - cand = self._make_candidate_from_link( - ireq.link, extras=set(), parent=ireq, - ) - return ExplicitRequirement(cand) - return SpecifierRequirement(ireq, factory=self) - - def make_requirement_from_spec(self, specifier, comes_from): - # type: (str, InstallRequirement) -> Requirement - ireq = self._make_install_req_from_spec(specifier, comes_from) - return self.make_requirement_from_install_req(ireq) - - def make_requires_python_requirement(self, specifier): - # type: (Optional[SpecifierSet]) -> Optional[Requirement] - if self._ignore_requires_python or specifier is None: - return None - return RequiresPythonRequirement(specifier, self._python_candidate) - - def should_reinstall(self, candidate): - # type: (Candidate) -> bool - # TODO: Are there more cases this needs to return True? Editable? - return candidate.name in self._installed_dists - - def _report_requires_python_error( - self, - requirement, # type: RequiresPythonRequirement - parent, # type: Candidate - ): - # type: (...) -> UnsupportedPythonVersion - template = ( - "Package {package!r} requires a different Python: " - "{version} not in {specifier!r}" - ) - message = template.format( - package=parent.name, - version=self._python_candidate.version, - specifier=str(requirement.specifier), - ) - return UnsupportedPythonVersion(message) - - def get_installation_error(self, e): - # type: (ResolutionImpossible) -> Optional[InstallationError] - for cause in e.causes: - if isinstance(cause.requirement, RequiresPythonRequirement): - return self._report_requires_python_error( - cause.requirement, - cause.parent, - ) - return None diff --git a/venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/provider.py b/venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/provider.py deleted file mode 100644 index 5c3d210..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/provider.py +++ /dev/null @@ -1,54 +0,0 @@ -from pip._vendor.resolvelib.providers import AbstractProvider - -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import Any, Optional, Sequence, Tuple, Union - - from pip._internal.req.req_install import InstallRequirement - - from .base import Requirement, Candidate - from .factory import Factory - - -class PipProvider(AbstractProvider): - def __init__( - self, - factory, # type: Factory - ignore_dependencies, # type: bool - ): - # type: (...) -> None - self._factory = factory - self._ignore_dependencies = ignore_dependencies - - def get_install_requirement(self, c): - # type: (Candidate) -> Optional[InstallRequirement] - return c.get_install_requirement() - - def identify(self, dependency): - # type: (Union[Requirement, Candidate]) -> str - return dependency.name - - def get_preference( - self, - resolution, # type: Optional[Candidate] - candidates, # type: Sequence[Candidate] - information # type: Sequence[Tuple[Requirement, Candidate]] - ): - # type: (...) -> Any - # Use the "usual" value for now - return len(candidates) - - def find_matches(self, requirement): - # type: (Requirement) -> Sequence[Candidate] - return requirement.find_matches() - - def is_satisfied_by(self, requirement, candidate): - # type: (Requirement, Candidate) -> bool - return requirement.is_satisfied_by(candidate) - - def get_dependencies(self, candidate): - # type: (Candidate) -> Sequence[Requirement] - if self._ignore_dependencies: - return [] - return candidate.get_dependencies() diff --git a/venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/requirements.py b/venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/requirements.py deleted file mode 100644 index d2e4479..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/requirements.py +++ /dev/null @@ -1,119 +0,0 @@ -from pip._vendor.packaging.utils import canonicalize_name - -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -from .base import Requirement, format_name - -if MYPY_CHECK_RUNNING: - from typing import Sequence - - from pip._vendor.packaging.specifiers import SpecifierSet - - from pip._internal.req.req_install import InstallRequirement - - from .base import Candidate - from .factory import Factory - - -class ExplicitRequirement(Requirement): - def __init__(self, candidate): - # type: (Candidate) -> None - self.candidate = candidate - - def __repr__(self): - # type: () -> str - return "{class_name}({candidate!r})".format( - class_name=self.__class__.__name__, - candidate=self.candidate, - ) - - @property - def name(self): - # type: () -> str - # No need to canonicalise - the candidate did this - return self.candidate.name - - def find_matches(self): - # type: () -> Sequence[Candidate] - return [self.candidate] - - def is_satisfied_by(self, candidate): - # type: (Candidate) -> bool - return candidate == self.candidate - - -class SpecifierRequirement(Requirement): - def __init__(self, ireq, factory): - # type: (InstallRequirement, Factory) -> None - assert ireq.link is None, "This is a link, not a specifier" - self._ireq = ireq - self._factory = factory - self.extras = ireq.req.extras - - def __str__(self): - # type: () -> str - return str(self._ireq.req) - - def __repr__(self): - # type: () -> str - return "{class_name}({requirement!r})".format( - class_name=self.__class__.__name__, - requirement=str(self._ireq.req), - ) - - @property - def name(self): - # type: () -> str - canonical_name = canonicalize_name(self._ireq.req.name) - return format_name(canonical_name, self.extras) - - def find_matches(self): - # type: () -> Sequence[Candidate] - it = self._factory.iter_found_candidates(self._ireq, self.extras) - return list(it) - - def is_satisfied_by(self, candidate): - # type: (Candidate) -> bool - assert candidate.name == self.name, \ - "Internal issue: Candidate is not for this requirement " \ - " {} vs {}".format(candidate.name, self.name) - # We can safely always allow prereleases here since PackageFinder - # already implements the prerelease logic, and would have filtered out - # prerelease candidates if the user does not expect them. - spec = self._ireq.req.specifier - return spec.contains(candidate.version, prereleases=True) - - -class RequiresPythonRequirement(Requirement): - """A requirement representing Requires-Python metadata. - """ - def __init__(self, specifier, match): - # type: (SpecifierSet, Candidate) -> None - self.specifier = specifier - self._candidate = match - - def __repr__(self): - # type: () -> str - return "{class_name}({specifier!r})".format( - class_name=self.__class__.__name__, - specifier=str(self.specifier), - ) - - @property - def name(self): - # type: () -> str - return self._candidate.name - - def find_matches(self): - # type: () -> Sequence[Candidate] - if self._candidate.version in self.specifier: - return [self._candidate] - return [] - - def is_satisfied_by(self, candidate): - # type: (Candidate) -> bool - assert candidate.name == self._candidate.name, "Not Python candidate" - # We can safely always allow prereleases here since PackageFinder - # already implements the prerelease logic, and would have filtered out - # prerelease candidates if the user does not expect them. - return self.specifier.contains(candidate.version, prereleases=True) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/resolver.py b/venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/resolver.py deleted file mode 100644 index cba5a49..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/resolution/resolvelib/resolver.py +++ /dev/null @@ -1,174 +0,0 @@ -import functools -import logging - -from pip._vendor import six -from pip._vendor.packaging.utils import canonicalize_name -from pip._vendor.resolvelib import BaseReporter, ResolutionImpossible -from pip._vendor.resolvelib import Resolver as RLResolver - -from pip._internal.exceptions import InstallationError -from pip._internal.req.req_set import RequirementSet -from pip._internal.resolution.base import BaseResolver -from pip._internal.resolution.resolvelib.provider import PipProvider -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -from .factory import Factory - -if MYPY_CHECK_RUNNING: - from typing import Dict, List, Optional, Tuple - - from pip._vendor.resolvelib.resolvers import Result - - from pip._internal.cache import WheelCache - from pip._internal.index.package_finder import PackageFinder - from pip._internal.operations.prepare import RequirementPreparer - from pip._internal.req.req_install import InstallRequirement - from pip._internal.resolution.base import InstallRequirementProvider - - -logger = logging.getLogger(__name__) - - -class Resolver(BaseResolver): - def __init__( - self, - preparer, # type: RequirementPreparer - finder, # type: PackageFinder - wheel_cache, # type: Optional[WheelCache] - make_install_req, # type: InstallRequirementProvider - use_user_site, # type: bool - ignore_dependencies, # type: bool - ignore_installed, # type: bool - ignore_requires_python, # type: bool - force_reinstall, # type: bool - upgrade_strategy, # type: str - py_version_info=None, # type: Optional[Tuple[int, ...]] - ): - super(Resolver, self).__init__() - self.factory = Factory( - finder=finder, - preparer=preparer, - make_install_req=make_install_req, - force_reinstall=force_reinstall, - ignore_installed=ignore_installed, - ignore_requires_python=ignore_requires_python, - py_version_info=py_version_info, - ) - self.ignore_dependencies = ignore_dependencies - self._result = None # type: Optional[Result] - - def resolve(self, root_reqs, check_supported_wheels): - # type: (List[InstallRequirement], bool) -> RequirementSet - - # FIXME: Implement constraints. - if any(r.constraint for r in root_reqs): - raise InstallationError("Constraints are not yet supported.") - - provider = PipProvider( - factory=self.factory, - ignore_dependencies=self.ignore_dependencies, - ) - reporter = BaseReporter() - resolver = RLResolver(provider, reporter) - - requirements = [ - self.factory.make_requirement_from_install_req(r) - for r in root_reqs - ] - - try: - self._result = resolver.resolve(requirements) - - except ResolutionImpossible as e: - error = self.factory.get_installation_error(e) - if not error: - # TODO: This needs fixing, we need to look at the - # factory.get_installation_error infrastructure, as that - # doesn't really allow for the logger.critical calls I'm - # using here. - for req, parent in e.causes: - logger.critical( - "Could not find a version that satisfies " + - "the requirement " + - str(req) + - ("" if parent is None else " (from {})".format( - parent.name - )) - ) - raise InstallationError( - "No matching distribution found for " + - ", ".join([r.name for r, _ in e.causes]) - ) - raise - six.raise_from(error, e) - - req_set = RequirementSet(check_supported_wheels=check_supported_wheels) - for candidate in self._result.mapping.values(): - ireq = provider.get_install_requirement(candidate) - if ireq is None: - continue - ireq.should_reinstall = self.factory.should_reinstall(candidate) - req_set.add_named_requirement(ireq) - - return req_set - - def get_installation_order(self, req_set): - # type: (RequirementSet) -> List[InstallRequirement] - """Create a list that orders given requirements for installation. - - The returned list should contain all requirements in ``req_set``, - so the caller can loop through it and have a requirement installed - before the requiring thing. - - The current implementation walks the resolved dependency graph, and - make sure every node has a greater "weight" than all its parents. - """ - assert self._result is not None, "must call resolve() first" - weights = {} # type: Dict[Optional[str], int] - - graph = self._result.graph - key_count = len(self._result.mapping) + 1 # Packages plus sentinal. - while len(weights) < key_count: - progressed = False - for key in graph: - if key in weights: - continue - parents = list(graph.iter_parents(key)) - if not all(p in weights for p in parents): - continue - if parents: - weight = max(weights[p] for p in parents) + 1 - else: - weight = 0 - weights[key] = weight - progressed = True - - # FIXME: This check will fail if there are unbreakable cycles. - # Implement something to forcifully break them up to continue. - if not progressed: - raise InstallationError( - "Could not determine installation order due to cicular " - "dependency." - ) - - sorted_items = sorted( - req_set.requirements.items(), - key=functools.partial(_req_set_item_sorter, weights=weights), - reverse=True, - ) - return [ireq for _, ireq in sorted_items] - - -def _req_set_item_sorter( - item, # type: Tuple[str, InstallRequirement] - weights, # type: Dict[Optional[str], int] -): - # type: (...) -> Tuple[int, str] - """Key function used to sort install requirements for installation. - - Based on the "weight" mapping calculated in ``get_installation_order()``. - The canonical package name is returned as the second member as a tie- - breaker to ensure the result is predictable, which is useful in tests. - """ - name = canonicalize_name(item[0]) - return weights[name], name diff --git a/venv/lib/python3.8/site-packages/pip/_internal/self_outdated_check.py b/venv/lib/python3.8/site-packages/pip/_internal/self_outdated_check.py deleted file mode 100644 index 8fc3c59..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/self_outdated_check.py +++ /dev/null @@ -1,242 +0,0 @@ -# The following comment should be removed at some point in the future. -# mypy: disallow-untyped-defs=False - -from __future__ import absolute_import - -import datetime -import hashlib -import json -import logging -import os.path -import sys - -from pip._vendor import pkg_resources -from pip._vendor.packaging import version as packaging_version -from pip._vendor.six import ensure_binary - -from pip._internal.index.collector import LinkCollector -from pip._internal.index.package_finder import PackageFinder -from pip._internal.models.search_scope import SearchScope -from pip._internal.models.selection_prefs import SelectionPreferences -from pip._internal.utils.filesystem import ( - adjacent_tmp_file, - check_path_owner, - replace, -) -from pip._internal.utils.misc import ( - ensure_dir, - get_installed_version, - redact_auth_from_url, -) -from pip._internal.utils.packaging import get_installer -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - import optparse - from optparse import Values - from typing import Any, Dict, Text, Union - - from pip._internal.network.session import PipSession - - -SELFCHECK_DATE_FMT = "%Y-%m-%dT%H:%M:%SZ" - - -logger = logging.getLogger(__name__) - - -def make_link_collector( - session, # type: PipSession - options, # type: Values - suppress_no_index=False, # type: bool -): - # type: (...) -> LinkCollector - """ - :param session: The Session to use to make requests. - :param suppress_no_index: Whether to ignore the --no-index option - when constructing the SearchScope object. - """ - index_urls = [options.index_url] + options.extra_index_urls - if options.no_index and not suppress_no_index: - logger.debug( - 'Ignoring indexes: %s', - ','.join(redact_auth_from_url(url) for url in index_urls), - ) - index_urls = [] - - # Make sure find_links is a list before passing to create(). - find_links = options.find_links or [] - - search_scope = SearchScope.create( - find_links=find_links, index_urls=index_urls, - ) - - link_collector = LinkCollector(session=session, search_scope=search_scope) - - return link_collector - - -def _get_statefile_name(key): - # type: (Union[str, Text]) -> str - key_bytes = ensure_binary(key) - name = hashlib.sha224(key_bytes).hexdigest() - return name - - -class SelfCheckState(object): - def __init__(self, cache_dir): - # type: (str) -> None - self.state = {} # type: Dict[str, Any] - self.statefile_path = None - - # Try to load the existing state - if cache_dir: - self.statefile_path = os.path.join( - cache_dir, "selfcheck", _get_statefile_name(self.key) - ) - try: - with open(self.statefile_path) as statefile: - self.state = json.load(statefile) - except (IOError, ValueError, KeyError): - # Explicitly suppressing exceptions, since we don't want to - # error out if the cache file is invalid. - pass - - @property - def key(self): - return sys.prefix - - def save(self, pypi_version, current_time): - # type: (str, datetime.datetime) -> None - # If we do not have a path to cache in, don't bother saving. - if not self.statefile_path: - return - - # Check to make sure that we own the directory - if not check_path_owner(os.path.dirname(self.statefile_path)): - return - - # Now that we've ensured the directory is owned by this user, we'll go - # ahead and make sure that all our directories are created. - ensure_dir(os.path.dirname(self.statefile_path)) - - state = { - # Include the key so it's easy to tell which pip wrote the - # file. - "key": self.key, - "last_check": current_time.strftime(SELFCHECK_DATE_FMT), - "pypi_version": pypi_version, - } - - text = json.dumps(state, sort_keys=True, separators=(",", ":")) - - with adjacent_tmp_file(self.statefile_path) as f: - f.write(ensure_binary(text)) - - try: - # Since we have a prefix-specific state file, we can just - # overwrite whatever is there, no need to check. - replace(f.name, self.statefile_path) - except OSError: - # Best effort. - pass - - -def was_installed_by_pip(pkg): - # type: (str) -> bool - """Checks whether pkg was installed by pip - - This is used not to display the upgrade message when pip is in fact - installed by system package manager, such as dnf on Fedora. - """ - try: - dist = pkg_resources.get_distribution(pkg) - return "pip" == get_installer(dist) - except pkg_resources.DistributionNotFound: - return False - - -def pip_self_version_check(session, options): - # type: (PipSession, optparse.Values) -> None - """Check for an update for pip. - - Limit the frequency of checks to once per week. State is stored either in - the active virtualenv or in the user's USER_CACHE_DIR keyed off the prefix - of the pip script path. - """ - installed_version = get_installed_version("pip") - if not installed_version: - return - - pip_version = packaging_version.parse(installed_version) - pypi_version = None - - try: - state = SelfCheckState(cache_dir=options.cache_dir) - - current_time = datetime.datetime.utcnow() - # Determine if we need to refresh the state - if "last_check" in state.state and "pypi_version" in state.state: - last_check = datetime.datetime.strptime( - state.state["last_check"], - SELFCHECK_DATE_FMT - ) - if (current_time - last_check).total_seconds() < 7 * 24 * 60 * 60: - pypi_version = state.state["pypi_version"] - - # Refresh the version if we need to or just see if we need to warn - if pypi_version is None: - # Lets use PackageFinder to see what the latest pip version is - link_collector = make_link_collector( - session, - options=options, - suppress_no_index=True, - ) - - # Pass allow_yanked=False so we don't suggest upgrading to a - # yanked version. - selection_prefs = SelectionPreferences( - allow_yanked=False, - allow_all_prereleases=False, # Explicitly set to False - ) - - finder = PackageFinder.create( - link_collector=link_collector, - selection_prefs=selection_prefs, - ) - best_candidate = finder.find_best_candidate("pip").best_candidate - if best_candidate is None: - return - pypi_version = str(best_candidate.version) - - # save that we've performed a check - state.save(pypi_version, current_time) - - remote_version = packaging_version.parse(pypi_version) - - local_version_is_older = ( - pip_version < remote_version and - pip_version.base_version != remote_version.base_version and - was_installed_by_pip('pip') - ) - - # Determine if our pypi_version is older - if not local_version_is_older: - return - - # We cannot tell how the current pip is available in the current - # command context, so be pragmatic here and suggest the command - # that's always available. This does not accommodate spaces in - # `sys.executable`. - pip_cmd = "{} -m pip".format(sys.executable) - logger.warning( - "You are using pip version %s; however, version %s is " - "available.\nYou should consider upgrading via the " - "'%s install --upgrade pip' command.", - pip_version, pypi_version, pip_cmd - ) - except Exception: - logger.debug( - "There was an error checking the latest version of pip", - exc_info=True, - ) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/__init__.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/appdirs.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/appdirs.py deleted file mode 100644 index 3989ed3..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/utils/appdirs.py +++ /dev/null @@ -1,44 +0,0 @@ -""" -This code wraps the vendored appdirs module to so the return values are -compatible for the current pip code base. - -The intention is to rewrite current usages gradually, keeping the tests pass, -and eventually drop this after all usages are changed. -""" - -from __future__ import absolute_import - -import os - -from pip._vendor import appdirs as _appdirs - -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import List - - -def user_cache_dir(appname): - # type: (str) -> str - return _appdirs.user_cache_dir(appname, appauthor=False) - - -def user_config_dir(appname, roaming=True): - # type: (str, bool) -> str - path = _appdirs.user_config_dir(appname, appauthor=False, roaming=roaming) - if _appdirs.system == "darwin" and not os.path.isdir(path): - path = os.path.expanduser('~/.config/') - if appname: - path = os.path.join(path, appname) - return path - - -# for the discussion regarding site_config_dir locations -# see <https://github.com/pypa/pip/issues/1733> -def site_config_dirs(appname): - # type: (str) -> List[str] - dirval = _appdirs.site_config_dir(appname, appauthor=False, multipath=True) - if _appdirs.system not in ["win32", "darwin"]: - # always look in /etc directly as well - return dirval.split(os.pathsep) + ['/etc'] - return [dirval] diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/compat.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/compat.py deleted file mode 100644 index d939e21..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/utils/compat.py +++ /dev/null @@ -1,270 +0,0 @@ -"""Stuff that differs in different Python versions and platform -distributions.""" - -# The following comment should be removed at some point in the future. -# mypy: disallow-untyped-defs=False - -from __future__ import absolute_import, division - -import codecs -import locale -import logging -import os -import shutil -import sys - -from pip._vendor.six import PY2, text_type - -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import Optional, Text, Tuple, Union - -try: - import ipaddress -except ImportError: - try: - from pip._vendor import ipaddress # type: ignore - except ImportError: - import ipaddr as ipaddress # type: ignore - ipaddress.ip_address = ipaddress.IPAddress # type: ignore - ipaddress.ip_network = ipaddress.IPNetwork # type: ignore - - -__all__ = [ - "ipaddress", "uses_pycache", "console_to_str", - "get_path_uid", "stdlib_pkgs", "WINDOWS", "samefile", "get_terminal_size", -] - - -logger = logging.getLogger(__name__) - -if PY2: - import imp - - try: - cache_from_source = imp.cache_from_source # type: ignore - except AttributeError: - # does not use __pycache__ - cache_from_source = None - - uses_pycache = cache_from_source is not None -else: - uses_pycache = True - from importlib.util import cache_from_source - - -if PY2: - # In Python 2.7, backslashreplace exists - # but does not support use for decoding. - # We implement our own replace handler for this - # situation, so that we can consistently use - # backslash replacement for all versions. - def backslashreplace_decode_fn(err): - raw_bytes = (err.object[i] for i in range(err.start, err.end)) - # Python 2 gave us characters - convert to numeric bytes - raw_bytes = (ord(b) for b in raw_bytes) - return u"".join(map(u"\\x{:x}".format, raw_bytes)), err.end - codecs.register_error( - "backslashreplace_decode", - backslashreplace_decode_fn, - ) - backslashreplace_decode = "backslashreplace_decode" -else: - backslashreplace_decode = "backslashreplace" - - -def has_tls(): - # type: () -> bool - try: - import _ssl # noqa: F401 # ignore unused - return True - except ImportError: - pass - - from pip._vendor.urllib3.util import IS_PYOPENSSL - return IS_PYOPENSSL - - -def str_to_display(data, desc=None): - # type: (Union[bytes, Text], Optional[str]) -> Text - """ - For display or logging purposes, convert a bytes object (or text) to - text (e.g. unicode in Python 2) safe for output. - - :param desc: An optional phrase describing the input data, for use in - the log message if a warning is logged. Defaults to "Bytes object". - - This function should never error out and so can take a best effort - approach. It is okay to be lossy if needed since the return value is - just for display. - - We assume the data is in the locale preferred encoding. If it won't - decode properly, we warn the user but decode as best we can. - - We also ensure that the output can be safely written to standard output - without encoding errors. - """ - if isinstance(data, text_type): - return data - - # Otherwise, data is a bytes object (str in Python 2). - # First, get the encoding we assume. This is the preferred - # encoding for the locale, unless that is not found, or - # it is ASCII, in which case assume UTF-8 - encoding = locale.getpreferredencoding() - if (not encoding) or codecs.lookup(encoding).name == "ascii": - encoding = "utf-8" - - # Now try to decode the data - if we fail, warn the user and - # decode with replacement. - try: - decoded_data = data.decode(encoding) - except UnicodeDecodeError: - if desc is None: - desc = 'Bytes object' - msg_format = '{} does not appear to be encoded as %s'.format(desc) - logger.warning(msg_format, encoding) - decoded_data = data.decode(encoding, errors=backslashreplace_decode) - - # Make sure we can print the output, by encoding it to the output - # encoding with replacement of unencodable characters, and then - # decoding again. - # We use stderr's encoding because it's less likely to be - # redirected and if we don't find an encoding we skip this - # step (on the assumption that output is wrapped by something - # that won't fail). - # The double getattr is to deal with the possibility that we're - # being called in a situation where sys.__stderr__ doesn't exist, - # or doesn't have an encoding attribute. Neither of these cases - # should occur in normal pip use, but there's no harm in checking - # in case people use pip in (unsupported) unusual situations. - output_encoding = getattr(getattr(sys, "__stderr__", None), - "encoding", None) - - if output_encoding: - output_encoded = decoded_data.encode( - output_encoding, - errors="backslashreplace" - ) - decoded_data = output_encoded.decode(output_encoding) - - return decoded_data - - -def console_to_str(data): - # type: (bytes) -> Text - """Return a string, safe for output, of subprocess output. - """ - return str_to_display(data, desc='Subprocess output') - - -def get_path_uid(path): - # type: (str) -> int - """ - Return path's uid. - - Does not follow symlinks: - https://github.com/pypa/pip/pull/935#discussion_r5307003 - - Placed this function in compat due to differences on AIX and - Jython, that should eventually go away. - - :raises OSError: When path is a symlink or can't be read. - """ - if hasattr(os, 'O_NOFOLLOW'): - fd = os.open(path, os.O_RDONLY | os.O_NOFOLLOW) - file_uid = os.fstat(fd).st_uid - os.close(fd) - else: # AIX and Jython - # WARNING: time of check vulnerability, but best we can do w/o NOFOLLOW - if not os.path.islink(path): - # older versions of Jython don't have `os.fstat` - file_uid = os.stat(path).st_uid - else: - # raise OSError for parity with os.O_NOFOLLOW above - raise OSError( - "{} is a symlink; Will not return uid for symlinks".format( - path) - ) - return file_uid - - -def expanduser(path): - # type: (str) -> str - """ - Expand ~ and ~user constructions. - - Includes a workaround for https://bugs.python.org/issue14768 - """ - expanded = os.path.expanduser(path) - if path.startswith('~/') and expanded.startswith('//'): - expanded = expanded[1:] - return expanded - - -# packages in the stdlib that may have installation metadata, but should not be -# considered 'installed'. this theoretically could be determined based on -# dist.location (py27:`sysconfig.get_paths()['stdlib']`, -# py26:sysconfig.get_config_vars('LIBDEST')), but fear platform variation may -# make this ineffective, so hard-coding -stdlib_pkgs = {"python", "wsgiref", "argparse"} - - -# windows detection, covers cpython and ironpython -WINDOWS = (sys.platform.startswith("win") or - (sys.platform == 'cli' and os.name == 'nt')) - - -def samefile(file1, file2): - # type: (str, str) -> bool - """Provide an alternative for os.path.samefile on Windows/Python2""" - if hasattr(os.path, 'samefile'): - return os.path.samefile(file1, file2) - else: - path1 = os.path.normcase(os.path.abspath(file1)) - path2 = os.path.normcase(os.path.abspath(file2)) - return path1 == path2 - - -if hasattr(shutil, 'get_terminal_size'): - def get_terminal_size(): - # type: () -> Tuple[int, int] - """ - Returns a tuple (x, y) representing the width(x) and the height(y) - in characters of the terminal window. - """ - return tuple(shutil.get_terminal_size()) # type: ignore -else: - def get_terminal_size(): - # type: () -> Tuple[int, int] - """ - Returns a tuple (x, y) representing the width(x) and the height(y) - in characters of the terminal window. - """ - def ioctl_GWINSZ(fd): - try: - import fcntl - import termios - import struct - cr = struct.unpack_from( - 'hh', - fcntl.ioctl(fd, termios.TIOCGWINSZ, '12345678') - ) - except Exception: - return None - if cr == (0, 0): - return None - return cr - cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2) - if not cr: - if sys.platform != "win32": - try: - fd = os.open(os.ctermid(), os.O_RDONLY) - cr = ioctl_GWINSZ(fd) - os.close(fd) - except Exception: - pass - if not cr: - cr = (os.environ.get('LINES', 25), os.environ.get('COLUMNS', 80)) - return int(cr[1]), int(cr[0]) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/compatibility_tags.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/compatibility_tags.py deleted file mode 100644 index 47d04f0..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/utils/compatibility_tags.py +++ /dev/null @@ -1,169 +0,0 @@ -"""Generate and work with PEP 425 Compatibility Tags. -""" - -from __future__ import absolute_import - -import logging -import re - -from pip._vendor.packaging.tags import ( - Tag, - compatible_tags, - cpython_tags, - generic_tags, - interpreter_name, - interpreter_version, - mac_platforms, -) - -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import List, Optional, Tuple - - from pip._vendor.packaging.tags import PythonVersion - -logger = logging.getLogger(__name__) - -_osx_arch_pat = re.compile(r'(.+)_(\d+)_(\d+)_(.+)') - - -def version_info_to_nodot(version_info): - # type: (Tuple[int, ...]) -> str - # Only use up to the first two numbers. - return ''.join(map(str, version_info[:2])) - - -def _mac_platforms(arch): - # type: (str) -> List[str] - match = _osx_arch_pat.match(arch) - if match: - name, major, minor, actual_arch = match.groups() - mac_version = (int(major), int(minor)) - arches = [ - # Since we have always only checked that the platform starts - # with "macosx", for backwards-compatibility we extract the - # actual prefix provided by the user in case they provided - # something like "macosxcustom_". It may be good to remove - # this as undocumented or deprecate it in the future. - '{}_{}'.format(name, arch[len('macosx_'):]) - for arch in mac_platforms(mac_version, actual_arch) - ] - else: - # arch pattern didn't match (?!) - arches = [arch] - return arches - - -def _custom_manylinux_platforms(arch): - # type: (str) -> List[str] - arches = [arch] - arch_prefix, arch_sep, arch_suffix = arch.partition('_') - if arch_prefix == 'manylinux2014': - # manylinux1/manylinux2010 wheels run on most manylinux2014 systems - # with the exception of wheels depending on ncurses. PEP 599 states - # manylinux1/manylinux2010 wheels should be considered - # manylinux2014 wheels: - # https://www.python.org/dev/peps/pep-0599/#backwards-compatibility-with-manylinux2010-wheels - if arch_suffix in {'i686', 'x86_64'}: - arches.append('manylinux2010' + arch_sep + arch_suffix) - arches.append('manylinux1' + arch_sep + arch_suffix) - elif arch_prefix == 'manylinux2010': - # manylinux1 wheels run on most manylinux2010 systems with the - # exception of wheels depending on ncurses. PEP 571 states - # manylinux1 wheels should be considered manylinux2010 wheels: - # https://www.python.org/dev/peps/pep-0571/#backwards-compatibility-with-manylinux1-wheels - arches.append('manylinux1' + arch_sep + arch_suffix) - return arches - - -def _get_custom_platforms(arch): - # type: (str) -> List[str] - arch_prefix, arch_sep, arch_suffix = arch.partition('_') - if arch.startswith('macosx'): - arches = _mac_platforms(arch) - elif arch_prefix in ['manylinux2014', 'manylinux2010']: - arches = _custom_manylinux_platforms(arch) - else: - arches = [arch] - return arches - - -def _get_python_version(version): - # type: (str) -> PythonVersion - if len(version) > 1: - return int(version[0]), int(version[1:]) - else: - return (int(version[0]),) - - -def _get_custom_interpreter(implementation=None, version=None): - # type: (Optional[str], Optional[str]) -> str - if implementation is None: - implementation = interpreter_name() - if version is None: - version = interpreter_version() - return "{}{}".format(implementation, version) - - -def get_supported( - version=None, # type: Optional[str] - platform=None, # type: Optional[str] - impl=None, # type: Optional[str] - abi=None # type: Optional[str] -): - # type: (...) -> List[Tag] - """Return a list of supported tags for each version specified in - `versions`. - - :param version: a string version, of the form "33" or "32", - or None. The version will be assumed to support our ABI. - :param platform: specify the exact platform you want valid - tags for, or None. If None, use the local system platform. - :param impl: specify the exact implementation you want valid - tags for, or None. If None, use the local interpreter impl. - :param abi: specify the exact abi you want valid - tags for, or None. If None, use the local interpreter abi. - """ - supported = [] # type: List[Tag] - - python_version = None # type: Optional[PythonVersion] - if version is not None: - python_version = _get_python_version(version) - - interpreter = _get_custom_interpreter(impl, version) - - abis = None # type: Optional[List[str]] - if abi is not None: - abis = [abi] - - platforms = None # type: Optional[List[str]] - if platform is not None: - platforms = _get_custom_platforms(platform) - - is_cpython = (impl or interpreter_name()) == "cp" - if is_cpython: - supported.extend( - cpython_tags( - python_version=python_version, - abis=abis, - platforms=platforms, - ) - ) - else: - supported.extend( - generic_tags( - interpreter=interpreter, - abis=abis, - platforms=platforms, - ) - ) - supported.extend( - compatible_tags( - python_version=python_version, - interpreter=interpreter, - platforms=platforms, - ) - ) - - return supported diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/deprecation.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/deprecation.py deleted file mode 100644 index 2f20cfd..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/utils/deprecation.py +++ /dev/null @@ -1,104 +0,0 @@ -""" -A module that implements tooling to enable easy warnings about deprecations. -""" - -# The following comment should be removed at some point in the future. -# mypy: disallow-untyped-defs=False - -from __future__ import absolute_import - -import logging -import warnings - -from pip._vendor.packaging.version import parse - -from pip import __version__ as current_version -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import Any, Optional - - -DEPRECATION_MSG_PREFIX = "DEPRECATION: " - - -class PipDeprecationWarning(Warning): - pass - - -_original_showwarning = None # type: Any - - -# Warnings <-> Logging Integration -def _showwarning(message, category, filename, lineno, file=None, line=None): - if file is not None: - if _original_showwarning is not None: - _original_showwarning( - message, category, filename, lineno, file, line, - ) - elif issubclass(category, PipDeprecationWarning): - # We use a specially named logger which will handle all of the - # deprecation messages for pip. - logger = logging.getLogger("pip._internal.deprecations") - logger.warning(message) - else: - _original_showwarning( - message, category, filename, lineno, file, line, - ) - - -def install_warning_logger(): - # type: () -> None - # Enable our Deprecation Warnings - warnings.simplefilter("default", PipDeprecationWarning, append=True) - - global _original_showwarning - - if _original_showwarning is None: - _original_showwarning = warnings.showwarning - warnings.showwarning = _showwarning - - -def deprecated(reason, replacement, gone_in, issue=None): - # type: (str, Optional[str], Optional[str], Optional[int]) -> None - """Helper to deprecate existing functionality. - - reason: - Textual reason shown to the user about why this functionality has - been deprecated. - replacement: - Textual suggestion shown to the user about what alternative - functionality they can use. - gone_in: - The version of pip does this functionality should get removed in. - Raises errors if pip's current version is greater than or equal to - this. - issue: - Issue number on the tracker that would serve as a useful place for - users to find related discussion and provide feedback. - - Always pass replacement, gone_in and issue as keyword arguments for clarity - at the call site. - """ - - # Construct a nice message. - # This is eagerly formatted as we want it to get logged as if someone - # typed this entire message out. - sentences = [ - (reason, DEPRECATION_MSG_PREFIX + "{}"), - (gone_in, "pip {} will remove support for this functionality."), - (replacement, "A possible replacement is {}."), - (issue, ( - "You can find discussion regarding this at " - "https://github.com/pypa/pip/issues/{}." - )), - ] - message = " ".join( - template.format(val) for val, template in sentences if val is not None - ) - - # Raise as an error if it has to be removed. - if gone_in is not None and parse(current_version) >= parse(gone_in): - raise PipDeprecationWarning(message) - - warnings.warn(message, category=PipDeprecationWarning, stacklevel=2) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/direct_url_helpers.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/direct_url_helpers.py deleted file mode 100644 index f1fe209..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/utils/direct_url_helpers.py +++ /dev/null @@ -1,130 +0,0 @@ -import logging - -from pip._internal.models.direct_url import ( - DIRECT_URL_METADATA_NAME, - ArchiveInfo, - DirectUrl, - DirectUrlValidationError, - DirInfo, - VcsInfo, -) -from pip._internal.utils.typing import MYPY_CHECK_RUNNING -from pip._internal.vcs import vcs - -try: - from json import JSONDecodeError -except ImportError: - # PY2 - JSONDecodeError = ValueError # type: ignore - -if MYPY_CHECK_RUNNING: - from typing import Optional - - from pip._internal.models.link import Link - - from pip._vendor.pkg_resources import Distribution - -logger = logging.getLogger(__name__) - - -def direct_url_as_pep440_direct_reference(direct_url, name): - # type: (DirectUrl, str) -> str - """Convert a DirectUrl to a pip requirement string.""" - direct_url.validate() # if invalid, this is a pip bug - requirement = name + " @ " - fragments = [] - if isinstance(direct_url.info, VcsInfo): - requirement += "{}+{}@{}".format( - direct_url.info.vcs, direct_url.url, direct_url.info.commit_id - ) - elif isinstance(direct_url.info, ArchiveInfo): - requirement += direct_url.url - if direct_url.info.hash: - fragments.append(direct_url.info.hash) - else: - assert isinstance(direct_url.info, DirInfo) - # pip should never reach this point for editables, since - # pip freeze inspects the editable project location to produce - # the requirement string - assert not direct_url.info.editable - requirement += direct_url.url - if direct_url.subdirectory: - fragments.append("subdirectory=" + direct_url.subdirectory) - if fragments: - requirement += "#" + "&".join(fragments) - return requirement - - -def direct_url_from_link(link, source_dir=None, link_is_in_wheel_cache=False): - # type: (Link, Optional[str], bool) -> DirectUrl - if link.is_vcs: - vcs_backend = vcs.get_backend_for_scheme(link.scheme) - assert vcs_backend - url, requested_revision, _ = ( - vcs_backend.get_url_rev_and_auth(link.url_without_fragment) - ) - # For VCS links, we need to find out and add commit_id. - if link_is_in_wheel_cache: - # If the requested VCS link corresponds to a cached - # wheel, it means the requested revision was an - # immutable commit hash, otherwise it would not have - # been cached. In that case we don't have a source_dir - # with the VCS checkout. - assert requested_revision - commit_id = requested_revision - else: - # If the wheel was not in cache, it means we have - # had to checkout from VCS to build and we have a source_dir - # which we can inspect to find out the commit id. - assert source_dir - commit_id = vcs_backend.get_revision(source_dir) - return DirectUrl( - url=url, - info=VcsInfo( - vcs=vcs_backend.name, - commit_id=commit_id, - requested_revision=requested_revision, - ), - subdirectory=link.subdirectory_fragment, - ) - elif link.is_existing_dir(): - return DirectUrl( - url=link.url_without_fragment, - info=DirInfo(), - subdirectory=link.subdirectory_fragment, - ) - else: - hash = None - hash_name = link.hash_name - if hash_name: - hash = "{}={}".format(hash_name, link.hash) - return DirectUrl( - url=link.url_without_fragment, - info=ArchiveInfo(hash=hash), - subdirectory=link.subdirectory_fragment, - ) - - -def dist_get_direct_url(dist): - # type: (Distribution) -> Optional[DirectUrl] - """Obtain a DirectUrl from a pkg_resource.Distribution. - - Returns None if the distribution has no `direct_url.json` metadata, - or if `direct_url.json` is invalid. - """ - if not dist.has_metadata(DIRECT_URL_METADATA_NAME): - return None - try: - return DirectUrl.from_json(dist.get_metadata(DIRECT_URL_METADATA_NAME)) - except ( - DirectUrlValidationError, - JSONDecodeError, - UnicodeDecodeError - ) as e: - logger.warning( - "Error parsing %s for %s: %s", - DIRECT_URL_METADATA_NAME, - dist.project_name, - e, - ) - return None diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/distutils_args.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/distutils_args.py deleted file mode 100644 index e38e402..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/utils/distutils_args.py +++ /dev/null @@ -1,48 +0,0 @@ -from distutils.errors import DistutilsArgError -from distutils.fancy_getopt import FancyGetopt - -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import Dict, List - - -_options = [ - ("exec-prefix=", None, ""), - ("home=", None, ""), - ("install-base=", None, ""), - ("install-data=", None, ""), - ("install-headers=", None, ""), - ("install-lib=", None, ""), - ("install-platlib=", None, ""), - ("install-purelib=", None, ""), - ("install-scripts=", None, ""), - ("prefix=", None, ""), - ("root=", None, ""), - ("user", None, ""), -] - - -# typeshed doesn't permit Tuple[str, None, str], see python/typeshed#3469. -_distutils_getopt = FancyGetopt(_options) # type: ignore - - -def parse_distutils_args(args): - # type: (List[str]) -> Dict[str, str] - """Parse provided arguments, returning an object that has the - matched arguments. - - Any unknown arguments are ignored. - """ - result = {} - for arg in args: - try: - _, match = _distutils_getopt.getopt(args=[arg]) - except DistutilsArgError: - # We don't care about any other options, which here may be - # considered unrecognized since our option list is not - # exhaustive. - pass - else: - result.update(match.__dict__) - return result diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/encoding.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/encoding.py deleted file mode 100644 index ab4d4b9..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/utils/encoding.py +++ /dev/null @@ -1,42 +0,0 @@ -# The following comment should be removed at some point in the future. -# mypy: strict-optional=False - -import codecs -import locale -import re -import sys - -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import List, Tuple, Text - -BOMS = [ - (codecs.BOM_UTF8, 'utf-8'), - (codecs.BOM_UTF16, 'utf-16'), - (codecs.BOM_UTF16_BE, 'utf-16-be'), - (codecs.BOM_UTF16_LE, 'utf-16-le'), - (codecs.BOM_UTF32, 'utf-32'), - (codecs.BOM_UTF32_BE, 'utf-32-be'), - (codecs.BOM_UTF32_LE, 'utf-32-le'), -] # type: List[Tuple[bytes, Text]] - -ENCODING_RE = re.compile(br'coding[:=]\s*([-\w.]+)') - - -def auto_decode(data): - # type: (bytes) -> Text - """Check a bytes string for a BOM to correctly detect the encoding - - Fallback to locale.getpreferredencoding(False) like open() on Python3""" - for bom, encoding in BOMS: - if data.startswith(bom): - return data[len(bom):].decode(encoding) - # Lets check the first two lines as in PEP263 - for line in data.split(b'\n')[:2]: - if line[0:1] == b'#' and ENCODING_RE.search(line): - encoding = ENCODING_RE.search(line).groups()[0].decode('ascii') - return data.decode(encoding) - return data.decode( - locale.getpreferredencoding(False) or sys.getdefaultencoding(), - ) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/entrypoints.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/entrypoints.py deleted file mode 100644 index befd01c..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/utils/entrypoints.py +++ /dev/null @@ -1,31 +0,0 @@ -import sys - -from pip._internal.cli.main import main -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import Optional, List - - -def _wrapper(args=None): - # type: (Optional[List[str]]) -> int - """Central wrapper for all old entrypoints. - - Historically pip has had several entrypoints defined. Because of issues - arising from PATH, sys.path, multiple Pythons, their interactions, and most - of them having a pip installed, users suffer every time an entrypoint gets - moved. - - To alleviate this pain, and provide a mechanism for warning users and - directing them to an appropriate place for help, we now define all of - our old entrypoints as wrappers for the current one. - """ - sys.stderr.write( - "WARNING: pip is being invoked by an old script wrapper. This will " - "fail in a future version of pip.\n" - "Please see https://github.com/pypa/pip/issues/5599 for advice on " - "fixing the underlying issue.\n" - "To avoid this problem you can invoke Python with '-m pip' instead of " - "running pip directly.\n" - ) - return main(args) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/filesystem.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/filesystem.py deleted file mode 100644 index 437a7fd..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/utils/filesystem.py +++ /dev/null @@ -1,222 +0,0 @@ -import errno -import fnmatch -import os -import os.path -import random -import shutil -import stat -import sys -from contextlib import contextmanager -from tempfile import NamedTemporaryFile - -# NOTE: retrying is not annotated in typeshed as on 2017-07-17, which is -# why we ignore the type on this import. -from pip._vendor.retrying import retry # type: ignore -from pip._vendor.six import PY2 - -from pip._internal.utils.compat import get_path_uid -from pip._internal.utils.misc import format_size -from pip._internal.utils.typing import MYPY_CHECK_RUNNING, cast - -if MYPY_CHECK_RUNNING: - from typing import Any, BinaryIO, Iterator, List, Union - - class NamedTemporaryFileResult(BinaryIO): - @property - def file(self): - # type: () -> BinaryIO - pass - - -def check_path_owner(path): - # type: (str) -> bool - # If we don't have a way to check the effective uid of this process, then - # we'll just assume that we own the directory. - if sys.platform == "win32" or not hasattr(os, "geteuid"): - return True - - assert os.path.isabs(path) - - previous = None - while path != previous: - if os.path.lexists(path): - # Check if path is writable by current user. - if os.geteuid() == 0: - # Special handling for root user in order to handle properly - # cases where users use sudo without -H flag. - try: - path_uid = get_path_uid(path) - except OSError: - return False - return path_uid == 0 - else: - return os.access(path, os.W_OK) - else: - previous, path = path, os.path.dirname(path) - return False # assume we don't own the path - - -def copy2_fixed(src, dest): - # type: (str, str) -> None - """Wrap shutil.copy2() but map errors copying socket files to - SpecialFileError as expected. - - See also https://bugs.python.org/issue37700. - """ - try: - shutil.copy2(src, dest) - except (OSError, IOError): - for f in [src, dest]: - try: - is_socket_file = is_socket(f) - except OSError: - # An error has already occurred. Another error here is not - # a problem and we can ignore it. - pass - else: - if is_socket_file: - raise shutil.SpecialFileError( - "`{f}` is a socket".format(**locals())) - - raise - - -def is_socket(path): - # type: (str) -> bool - return stat.S_ISSOCK(os.lstat(path).st_mode) - - -@contextmanager -def adjacent_tmp_file(path, **kwargs): - # type: (str, **Any) -> Iterator[NamedTemporaryFileResult] - """Return a file-like object pointing to a tmp file next to path. - - The file is created securely and is ensured to be written to disk - after the context reaches its end. - - kwargs will be passed to tempfile.NamedTemporaryFile to control - the way the temporary file will be opened. - """ - with NamedTemporaryFile( - delete=False, - dir=os.path.dirname(path), - prefix=os.path.basename(path), - suffix='.tmp', - **kwargs - ) as f: - result = cast('NamedTemporaryFileResult', f) - try: - yield result - finally: - result.file.flush() - os.fsync(result.file.fileno()) - - -_replace_retry = retry(stop_max_delay=1000, wait_fixed=250) - -if PY2: - @_replace_retry - def replace(src, dest): - # type: (str, str) -> None - try: - os.rename(src, dest) - except OSError: - os.remove(dest) - os.rename(src, dest) - -else: - replace = _replace_retry(os.replace) - - -# test_writable_dir and _test_writable_dir_win are copied from Flit, -# with the author's agreement to also place them under pip's license. -def test_writable_dir(path): - # type: (str) -> bool - """Check if a directory is writable. - - Uses os.access() on POSIX, tries creating files on Windows. - """ - # If the directory doesn't exist, find the closest parent that does. - while not os.path.isdir(path): - parent = os.path.dirname(path) - if parent == path: - break # Should never get here, but infinite loops are bad - path = parent - - if os.name == 'posix': - return os.access(path, os.W_OK) - - return _test_writable_dir_win(path) - - -def _test_writable_dir_win(path): - # type: (str) -> bool - # os.access doesn't work on Windows: http://bugs.python.org/issue2528 - # and we can't use tempfile: http://bugs.python.org/issue22107 - basename = 'accesstest_deleteme_fishfingers_custard_' - alphabet = 'abcdefghijklmnopqrstuvwxyz0123456789' - for i in range(10): - name = basename + ''.join(random.choice(alphabet) for _ in range(6)) - file = os.path.join(path, name) - try: - fd = os.open(file, os.O_RDWR | os.O_CREAT | os.O_EXCL) - # Python 2 doesn't support FileExistsError and PermissionError. - except OSError as e: - # exception FileExistsError - if e.errno == errno.EEXIST: - continue - # exception PermissionError - if e.errno == errno.EPERM or e.errno == errno.EACCES: - # This could be because there's a directory with the same name. - # But it's highly unlikely there's a directory called that, - # so we'll assume it's because the parent dir is not writable. - return False - raise - else: - os.close(fd) - os.unlink(file) - return True - - # This should never be reached - raise EnvironmentError( - 'Unexpected condition testing for writable directory' - ) - - -def find_files(path, pattern): - # type: (str, str) -> List[str] - """Returns a list of absolute paths of files beneath path, recursively, - with filenames which match the UNIX-style shell glob pattern.""" - result = [] # type: List[str] - for root, dirs, files in os.walk(path): - matches = fnmatch.filter(files, pattern) - result.extend(os.path.join(root, f) for f in matches) - return result - - -def file_size(path): - # type: (str) -> Union[int, float] - # If it's a symlink, return 0. - if os.path.islink(path): - return 0 - return os.path.getsize(path) - - -def format_file_size(path): - # type: (str) -> str - return format_size(file_size(path)) - - -def directory_size(path): - # type: (str) -> Union[int, float] - size = 0.0 - for root, _dirs, files in os.walk(path): - for filename in files: - file_path = os.path.join(root, filename) - size += file_size(file_path) - return size - - -def format_directory_size(path): - # type: (str) -> str - return format_size(directory_size(path)) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/filetypes.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/filetypes.py deleted file mode 100644 index daa0ca7..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/utils/filetypes.py +++ /dev/null @@ -1,16 +0,0 @@ -"""Filetype information. -""" -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import Tuple - -WHEEL_EXTENSION = '.whl' -BZ2_EXTENSIONS = ('.tar.bz2', '.tbz') # type: Tuple[str, ...] -XZ_EXTENSIONS = ('.tar.xz', '.txz', '.tlz', - '.tar.lz', '.tar.lzma') # type: Tuple[str, ...] -ZIP_EXTENSIONS = ('.zip', WHEEL_EXTENSION) # type: Tuple[str, ...] -TAR_EXTENSIONS = ('.tar.gz', '.tgz', '.tar') # type: Tuple[str, ...] -ARCHIVE_EXTENSIONS = ( - ZIP_EXTENSIONS + BZ2_EXTENSIONS + TAR_EXTENSIONS + XZ_EXTENSIONS -) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/glibc.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/glibc.py deleted file mode 100644 index 3610424..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/utils/glibc.py +++ /dev/null @@ -1,98 +0,0 @@ -# The following comment should be removed at some point in the future. -# mypy: strict-optional=False - -from __future__ import absolute_import - -import os -import sys - -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import Optional, Tuple - - -def glibc_version_string(): - # type: () -> Optional[str] - "Returns glibc version string, or None if not using glibc." - return glibc_version_string_confstr() or glibc_version_string_ctypes() - - -def glibc_version_string_confstr(): - # type: () -> Optional[str] - "Primary implementation of glibc_version_string using os.confstr." - # os.confstr is quite a bit faster than ctypes.DLL. It's also less likely - # to be broken or missing. This strategy is used in the standard library - # platform module: - # https://github.com/python/cpython/blob/fcf1d003bf4f0100c9d0921ff3d70e1127ca1b71/Lib/platform.py#L175-L183 - if sys.platform == "win32": - return None - try: - # os.confstr("CS_GNU_LIBC_VERSION") returns a string like "glibc 2.17": - _, version = os.confstr("CS_GNU_LIBC_VERSION").split() - except (AttributeError, OSError, ValueError): - # os.confstr() or CS_GNU_LIBC_VERSION not available (or a bad value)... - return None - return version - - -def glibc_version_string_ctypes(): - # type: () -> Optional[str] - "Fallback implementation of glibc_version_string using ctypes." - - try: - import ctypes - except ImportError: - return None - - # ctypes.CDLL(None) internally calls dlopen(NULL), and as the dlopen - # manpage says, "If filename is NULL, then the returned handle is for the - # main program". This way we can let the linker do the work to figure out - # which libc our process is actually using. - process_namespace = ctypes.CDLL(None) - try: - gnu_get_libc_version = process_namespace.gnu_get_libc_version - except AttributeError: - # Symbol doesn't exist -> therefore, we are not linked to - # glibc. - return None - - # Call gnu_get_libc_version, which returns a string like "2.5" - gnu_get_libc_version.restype = ctypes.c_char_p - version_str = gnu_get_libc_version() - # py2 / py3 compatibility: - if not isinstance(version_str, str): - version_str = version_str.decode("ascii") - - return version_str - - -# platform.libc_ver regularly returns completely nonsensical glibc -# versions. E.g. on my computer, platform says: -# -# ~$ python2.7 -c 'import platform; print(platform.libc_ver())' -# ('glibc', '2.7') -# ~$ python3.5 -c 'import platform; print(platform.libc_ver())' -# ('glibc', '2.9') -# -# But the truth is: -# -# ~$ ldd --version -# ldd (Debian GLIBC 2.22-11) 2.22 -# -# This is unfortunate, because it means that the linehaul data on libc -# versions that was generated by pip 8.1.2 and earlier is useless and -# misleading. Solution: instead of using platform, use our code that actually -# works. -def libc_ver(): - # type: () -> Tuple[str, str] - """Try to determine the glibc version - - Returns a tuple of strings (lib, version) which default to empty strings - in case the lookup fails. - """ - glibc_version = glibc_version_string() - if glibc_version is None: - return ("", "") - else: - return ("glibc", glibc_version) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/hashes.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/hashes.py deleted file mode 100644 index 396cf82..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/utils/hashes.py +++ /dev/null @@ -1,133 +0,0 @@ -from __future__ import absolute_import - -import hashlib - -from pip._vendor.six import iteritems, iterkeys, itervalues - -from pip._internal.exceptions import ( - HashMismatch, - HashMissing, - InstallationError, -) -from pip._internal.utils.misc import read_chunks -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import ( - Dict, List, BinaryIO, NoReturn, Iterator - ) - from pip._vendor.six import PY3 - if PY3: - from hashlib import _Hash - else: - from hashlib import _hash as _Hash - - -# The recommended hash algo of the moment. Change this whenever the state of -# the art changes; it won't hurt backward compatibility. -FAVORITE_HASH = 'sha256' - - -# Names of hashlib algorithms allowed by the --hash option and ``pip hash`` -# Currently, those are the ones at least as collision-resistant as sha256. -STRONG_HASHES = ['sha256', 'sha384', 'sha512'] - - -class Hashes(object): - """A wrapper that builds multiple hashes at once and checks them against - known-good values - - """ - def __init__(self, hashes=None): - # type: (Dict[str, List[str]]) -> None - """ - :param hashes: A dict of algorithm names pointing to lists of allowed - hex digests - """ - self._allowed = {} if hashes is None else hashes - - @property - def digest_count(self): - # type: () -> int - return sum(len(digests) for digests in self._allowed.values()) - - def is_hash_allowed( - self, - hash_name, # type: str - hex_digest, # type: str - ): - # type: (...) -> bool - """Return whether the given hex digest is allowed.""" - return hex_digest in self._allowed.get(hash_name, []) - - def check_against_chunks(self, chunks): - # type: (Iterator[bytes]) -> None - """Check good hashes against ones built from iterable of chunks of - data. - - Raise HashMismatch if none match. - - """ - gots = {} - for hash_name in iterkeys(self._allowed): - try: - gots[hash_name] = hashlib.new(hash_name) - except (ValueError, TypeError): - raise InstallationError( - 'Unknown hash name: {}'.format(hash_name) - ) - - for chunk in chunks: - for hash in itervalues(gots): - hash.update(chunk) - - for hash_name, got in iteritems(gots): - if got.hexdigest() in self._allowed[hash_name]: - return - self._raise(gots) - - def _raise(self, gots): - # type: (Dict[str, _Hash]) -> NoReturn - raise HashMismatch(self._allowed, gots) - - def check_against_file(self, file): - # type: (BinaryIO) -> None - """Check good hashes against a file-like object - - Raise HashMismatch if none match. - - """ - return self.check_against_chunks(read_chunks(file)) - - def check_against_path(self, path): - # type: (str) -> None - with open(path, 'rb') as file: - return self.check_against_file(file) - - def __nonzero__(self): - # type: () -> bool - """Return whether I know any known-good hashes.""" - return bool(self._allowed) - - def __bool__(self): - # type: () -> bool - return self.__nonzero__() - - -class MissingHashes(Hashes): - """A workalike for Hashes used when we're missing a hash for a requirement - - It computes the actual hash of the requirement and raises a HashMissing - exception showing it to the user. - - """ - def __init__(self): - # type: () -> None - """Don't offer the ``hashes`` kwarg.""" - # Pass our favorite hash in to generate a "gotten hash". With the - # empty list, it will never match, so an error will always raise. - super(MissingHashes, self).__init__(hashes={FAVORITE_HASH: []}) - - def _raise(self, gots): - # type: (Dict[str, _Hash]) -> NoReturn - raise HashMissing(gots[FAVORITE_HASH].hexdigest()) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/inject_securetransport.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/inject_securetransport.py deleted file mode 100644 index 5b93b1d..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/utils/inject_securetransport.py +++ /dev/null @@ -1,36 +0,0 @@ -"""A helper module that injects SecureTransport, on import. - -The import should be done as early as possible, to ensure all requests and -sessions (or whatever) are created after injecting SecureTransport. - -Note that we only do the injection on macOS, when the linked OpenSSL is too -old to handle TLSv1.2. -""" - -import sys - - -def inject_securetransport(): - # type: () -> None - # Only relevant on macOS - if sys.platform != "darwin": - return - - try: - import ssl - except ImportError: - return - - # Checks for OpenSSL 1.0.1 - if ssl.OPENSSL_VERSION_NUMBER >= 0x1000100f: - return - - try: - from pip._vendor.urllib3.contrib import securetransport - except (ImportError, OSError): - return - - securetransport.inject_into_urllib3() - - -inject_securetransport() diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/logging.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/logging.py deleted file mode 100644 index 9a017cf..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/utils/logging.py +++ /dev/null @@ -1,399 +0,0 @@ -# The following comment should be removed at some point in the future. -# mypy: disallow-untyped-defs=False - -from __future__ import absolute_import - -import contextlib -import errno -import logging -import logging.handlers -import os -import sys -from logging import Filter, getLogger - -from pip._vendor.six import PY2 - -from pip._internal.utils.compat import WINDOWS -from pip._internal.utils.deprecation import DEPRECATION_MSG_PREFIX -from pip._internal.utils.misc import ensure_dir - -try: - import threading -except ImportError: - import dummy_threading as threading # type: ignore - - -try: - # Use "import as" and set colorama in the else clause to avoid mypy - # errors and get the following correct revealed type for colorama: - # `Union[_importlib_modulespec.ModuleType, None]` - # Otherwise, we get an error like the following in the except block: - # > Incompatible types in assignment (expression has type "None", - # variable has type Module) - # TODO: eliminate the need to use "import as" once mypy addresses some - # of its issues with conditional imports. Here is an umbrella issue: - # https://github.com/python/mypy/issues/1297 - from pip._vendor import colorama as _colorama -# Lots of different errors can come from this, including SystemError and -# ImportError. -except Exception: - colorama = None -else: - # Import Fore explicitly rather than accessing below as colorama.Fore - # to avoid the following error running mypy: - # > Module has no attribute "Fore" - # TODO: eliminate the need to import Fore once mypy addresses some of its - # issues with conditional imports. This particular case could be an - # instance of the following issue (but also see the umbrella issue above): - # https://github.com/python/mypy/issues/3500 - from pip._vendor.colorama import Fore - - colorama = _colorama - - -_log_state = threading.local() -subprocess_logger = getLogger('pip.subprocessor') - - -class BrokenStdoutLoggingError(Exception): - """ - Raised if BrokenPipeError occurs for the stdout stream while logging. - """ - pass - - -# BrokenPipeError does not exist in Python 2 and, in addition, manifests -# differently in Windows and non-Windows. -if WINDOWS: - # In Windows, a broken pipe can show up as EINVAL rather than EPIPE: - # https://bugs.python.org/issue19612 - # https://bugs.python.org/issue30418 - if PY2: - def _is_broken_pipe_error(exc_class, exc): - """See the docstring for non-Windows Python 3 below.""" - return (exc_class is IOError and - exc.errno in (errno.EINVAL, errno.EPIPE)) - else: - # In Windows, a broken pipe IOError became OSError in Python 3. - def _is_broken_pipe_error(exc_class, exc): - """See the docstring for non-Windows Python 3 below.""" - return ((exc_class is BrokenPipeError) or # noqa: F821 - (exc_class is OSError and - exc.errno in (errno.EINVAL, errno.EPIPE))) -elif PY2: - def _is_broken_pipe_error(exc_class, exc): - """See the docstring for non-Windows Python 3 below.""" - return (exc_class is IOError and exc.errno == errno.EPIPE) -else: - # Then we are in the non-Windows Python 3 case. - def _is_broken_pipe_error(exc_class, exc): - """ - Return whether an exception is a broken pipe error. - - Args: - exc_class: an exception class. - exc: an exception instance. - """ - return (exc_class is BrokenPipeError) # noqa: F821 - - -@contextlib.contextmanager -def indent_log(num=2): - """ - A context manager which will cause the log output to be indented for any - log messages emitted inside it. - """ - # For thread-safety - _log_state.indentation = get_indentation() - _log_state.indentation += num - try: - yield - finally: - _log_state.indentation -= num - - -def get_indentation(): - return getattr(_log_state, 'indentation', 0) - - -class IndentingFormatter(logging.Formatter): - - def __init__(self, *args, **kwargs): - """ - A logging.Formatter that obeys the indent_log() context manager. - - :param add_timestamp: A bool indicating output lines should be prefixed - with their record's timestamp. - """ - self.add_timestamp = kwargs.pop("add_timestamp", False) - super(IndentingFormatter, self).__init__(*args, **kwargs) - - def get_message_start(self, formatted, levelno): - """ - Return the start of the formatted log message (not counting the - prefix to add to each line). - """ - if levelno < logging.WARNING: - return '' - if formatted.startswith(DEPRECATION_MSG_PREFIX): - # Then the message already has a prefix. We don't want it to - # look like "WARNING: DEPRECATION: ...." - return '' - if levelno < logging.ERROR: - return 'WARNING: ' - - return 'ERROR: ' - - def format(self, record): - """ - Calls the standard formatter, but will indent all of the log message - lines by our current indentation level. - """ - formatted = super(IndentingFormatter, self).format(record) - message_start = self.get_message_start(formatted, record.levelno) - formatted = message_start + formatted - - prefix = '' - if self.add_timestamp: - # TODO: Use Formatter.default_time_format after dropping PY2. - t = self.formatTime(record, "%Y-%m-%dT%H:%M:%S") - prefix = '{t},{record.msecs:03.0f} '.format(**locals()) - prefix += " " * get_indentation() - formatted = "".join([ - prefix + line - for line in formatted.splitlines(True) - ]) - return formatted - - -def _color_wrap(*colors): - def wrapped(inp): - return "".join(list(colors) + [inp, colorama.Style.RESET_ALL]) - return wrapped - - -class ColorizedStreamHandler(logging.StreamHandler): - - # Don't build up a list of colors if we don't have colorama - if colorama: - COLORS = [ - # This needs to be in order from highest logging level to lowest. - (logging.ERROR, _color_wrap(Fore.RED)), - (logging.WARNING, _color_wrap(Fore.YELLOW)), - ] - else: - COLORS = [] - - def __init__(self, stream=None, no_color=None): - logging.StreamHandler.__init__(self, stream) - self._no_color = no_color - - if WINDOWS and colorama: - self.stream = colorama.AnsiToWin32(self.stream) - - def _using_stdout(self): - """ - Return whether the handler is using sys.stdout. - """ - if WINDOWS and colorama: - # Then self.stream is an AnsiToWin32 object. - return self.stream.wrapped is sys.stdout - - return self.stream is sys.stdout - - def should_color(self): - # Don't colorize things if we do not have colorama or if told not to - if not colorama or self._no_color: - return False - - real_stream = ( - self.stream if not isinstance(self.stream, colorama.AnsiToWin32) - else self.stream.wrapped - ) - - # If the stream is a tty we should color it - if hasattr(real_stream, "isatty") and real_stream.isatty(): - return True - - # If we have an ANSI term we should color it - if os.environ.get("TERM") == "ANSI": - return True - - # If anything else we should not color it - return False - - def format(self, record): - msg = logging.StreamHandler.format(self, record) - - if self.should_color(): - for level, color in self.COLORS: - if record.levelno >= level: - msg = color(msg) - break - - return msg - - # The logging module says handleError() can be customized. - def handleError(self, record): - exc_class, exc = sys.exc_info()[:2] - # If a broken pipe occurred while calling write() or flush() on the - # stdout stream in logging's Handler.emit(), then raise our special - # exception so we can handle it in main() instead of logging the - # broken pipe error and continuing. - if (exc_class and self._using_stdout() and - _is_broken_pipe_error(exc_class, exc)): - raise BrokenStdoutLoggingError() - - return super(ColorizedStreamHandler, self).handleError(record) - - -class BetterRotatingFileHandler(logging.handlers.RotatingFileHandler): - - def _open(self): - ensure_dir(os.path.dirname(self.baseFilename)) - return logging.handlers.RotatingFileHandler._open(self) - - -class MaxLevelFilter(Filter): - - def __init__(self, level): - self.level = level - - def filter(self, record): - return record.levelno < self.level - - -class ExcludeLoggerFilter(Filter): - - """ - A logging Filter that excludes records from a logger (or its children). - """ - - def filter(self, record): - # The base Filter class allows only records from a logger (or its - # children). - return not super(ExcludeLoggerFilter, self).filter(record) - - -def setup_logging(verbosity, no_color, user_log_file): - """Configures and sets up all of the logging - - Returns the requested logging level, as its integer value. - """ - - # Determine the level to be logging at. - if verbosity >= 1: - level = "DEBUG" - elif verbosity == -1: - level = "WARNING" - elif verbosity == -2: - level = "ERROR" - elif verbosity <= -3: - level = "CRITICAL" - else: - level = "INFO" - - level_number = getattr(logging, level) - - # The "root" logger should match the "console" level *unless* we also need - # to log to a user log file. - include_user_log = user_log_file is not None - if include_user_log: - additional_log_file = user_log_file - root_level = "DEBUG" - else: - additional_log_file = "/dev/null" - root_level = level - - # Disable any logging besides WARNING unless we have DEBUG level logging - # enabled for vendored libraries. - vendored_log_level = "WARNING" if level in ["INFO", "ERROR"] else "DEBUG" - - # Shorthands for clarity - log_streams = { - "stdout": "ext://sys.stdout", - "stderr": "ext://sys.stderr", - } - handler_classes = { - "stream": "pip._internal.utils.logging.ColorizedStreamHandler", - "file": "pip._internal.utils.logging.BetterRotatingFileHandler", - } - handlers = ["console", "console_errors", "console_subprocess"] + ( - ["user_log"] if include_user_log else [] - ) - - logging.config.dictConfig({ - "version": 1, - "disable_existing_loggers": False, - "filters": { - "exclude_warnings": { - "()": "pip._internal.utils.logging.MaxLevelFilter", - "level": logging.WARNING, - }, - "restrict_to_subprocess": { - "()": "logging.Filter", - "name": subprocess_logger.name, - }, - "exclude_subprocess": { - "()": "pip._internal.utils.logging.ExcludeLoggerFilter", - "name": subprocess_logger.name, - }, - }, - "formatters": { - "indent": { - "()": IndentingFormatter, - "format": "%(message)s", - }, - "indent_with_timestamp": { - "()": IndentingFormatter, - "format": "%(message)s", - "add_timestamp": True, - }, - }, - "handlers": { - "console": { - "level": level, - "class": handler_classes["stream"], - "no_color": no_color, - "stream": log_streams["stdout"], - "filters": ["exclude_subprocess", "exclude_warnings"], - "formatter": "indent", - }, - "console_errors": { - "level": "WARNING", - "class": handler_classes["stream"], - "no_color": no_color, - "stream": log_streams["stderr"], - "filters": ["exclude_subprocess"], - "formatter": "indent", - }, - # A handler responsible for logging to the console messages - # from the "subprocessor" logger. - "console_subprocess": { - "level": level, - "class": handler_classes["stream"], - "no_color": no_color, - "stream": log_streams["stderr"], - "filters": ["restrict_to_subprocess"], - "formatter": "indent", - }, - "user_log": { - "level": "DEBUG", - "class": handler_classes["file"], - "filename": additional_log_file, - "delay": True, - "formatter": "indent_with_timestamp", - }, - }, - "root": { - "level": root_level, - "handlers": handlers, - }, - "loggers": { - "pip._vendor": { - "level": vendored_log_level - } - }, - }) - - return level_number diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/misc.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/misc.py deleted file mode 100644 index 0f388eb..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/utils/misc.py +++ /dev/null @@ -1,927 +0,0 @@ -# The following comment should be removed at some point in the future. -# mypy: strict-optional=False -# mypy: disallow-untyped-defs=False - -from __future__ import absolute_import - -import contextlib -import errno -import getpass -import hashlib -import io -import logging -import os -import posixpath -import shutil -import stat -import sys -from collections import deque - -from pip._vendor import pkg_resources -# NOTE: retrying is not annotated in typeshed as on 2017-07-17, which is -# why we ignore the type on this import. -from pip._vendor.retrying import retry # type: ignore -from pip._vendor.six import PY2, text_type -from pip._vendor.six.moves import input, map, zip_longest -from pip._vendor.six.moves.urllib import parse as urllib_parse -from pip._vendor.six.moves.urllib.parse import unquote as urllib_unquote - -from pip import __version__ -from pip._internal.exceptions import CommandError -from pip._internal.locations import ( - get_major_minor_version, - site_packages, - user_site, -) -from pip._internal.utils.compat import ( - WINDOWS, - expanduser, - stdlib_pkgs, - str_to_display, -) -from pip._internal.utils.typing import MYPY_CHECK_RUNNING, cast -from pip._internal.utils.virtualenv import ( - running_under_virtualenv, - virtualenv_no_global, -) - -if PY2: - from io import BytesIO as StringIO -else: - from io import StringIO - -if MYPY_CHECK_RUNNING: - from typing import ( - Any, AnyStr, Container, Iterable, Iterator, List, Optional, Text, - Tuple, Union, - ) - from pip._vendor.pkg_resources import Distribution - - VersionInfo = Tuple[int, int, int] - - -__all__ = ['rmtree', 'display_path', 'backup_dir', - 'ask', 'splitext', - 'format_size', 'is_installable_dir', - 'normalize_path', - 'renames', 'get_prog', - 'captured_stdout', 'ensure_dir', - 'get_installed_version', 'remove_auth_from_url'] - - -logger = logging.getLogger(__name__) - - -def get_pip_version(): - # type: () -> str - pip_pkg_dir = os.path.join(os.path.dirname(__file__), "..", "..") - pip_pkg_dir = os.path.abspath(pip_pkg_dir) - - return ( - 'pip {} from {} (python {})'.format( - __version__, pip_pkg_dir, get_major_minor_version(), - ) - ) - - -def normalize_version_info(py_version_info): - # type: (Tuple[int, ...]) -> Tuple[int, int, int] - """ - Convert a tuple of ints representing a Python version to one of length - three. - - :param py_version_info: a tuple of ints representing a Python version, - or None to specify no version. The tuple can have any length. - - :return: a tuple of length three if `py_version_info` is non-None. - Otherwise, return `py_version_info` unchanged (i.e. None). - """ - if len(py_version_info) < 3: - py_version_info += (3 - len(py_version_info)) * (0,) - elif len(py_version_info) > 3: - py_version_info = py_version_info[:3] - - return cast('VersionInfo', py_version_info) - - -def ensure_dir(path): - # type: (AnyStr) -> None - """os.path.makedirs without EEXIST.""" - try: - os.makedirs(path) - except OSError as e: - # Windows can raise spurious ENOTEMPTY errors. See #6426. - if e.errno != errno.EEXIST and e.errno != errno.ENOTEMPTY: - raise - - -def get_prog(): - # type: () -> str - try: - prog = os.path.basename(sys.argv[0]) - if prog in ('__main__.py', '-c'): - return "{} -m pip".format(sys.executable) - else: - return prog - except (AttributeError, TypeError, IndexError): - pass - return 'pip' - - -# Retry every half second for up to 3 seconds -@retry(stop_max_delay=3000, wait_fixed=500) -def rmtree(dir, ignore_errors=False): - # type: (str, bool) -> None - shutil.rmtree(dir, ignore_errors=ignore_errors, - onerror=rmtree_errorhandler) - - -def rmtree_errorhandler(func, path, exc_info): - """On Windows, the files in .svn are read-only, so when rmtree() tries to - remove them, an exception is thrown. We catch that here, remove the - read-only attribute, and hopefully continue without problems.""" - try: - has_attr_readonly = not (os.stat(path).st_mode & stat.S_IWRITE) - except (IOError, OSError): - # it's equivalent to os.path.exists - return - - if has_attr_readonly: - # convert to read/write - os.chmod(path, stat.S_IWRITE) - # use the original function to repeat the operation - func(path) - return - else: - raise - - -def path_to_display(path): - # type: (Optional[Union[str, Text]]) -> Optional[Text] - """ - Convert a bytes (or text) path to text (unicode in Python 2) for display - and logging purposes. - - This function should never error out. Also, this function is mainly needed - for Python 2 since in Python 3 str paths are already text. - """ - if path is None: - return None - if isinstance(path, text_type): - return path - # Otherwise, path is a bytes object (str in Python 2). - try: - display_path = path.decode(sys.getfilesystemencoding(), 'strict') - except UnicodeDecodeError: - # Include the full bytes to make troubleshooting easier, even though - # it may not be very human readable. - if PY2: - # Convert the bytes to a readable str representation using - # repr(), and then convert the str to unicode. - # Also, we add the prefix "b" to the repr() return value both - # to make the Python 2 output look like the Python 3 output, and - # to signal to the user that this is a bytes representation. - display_path = str_to_display('b{!r}'.format(path)) - else: - # Silence the "F821 undefined name 'ascii'" flake8 error since - # in Python 3 ascii() is a built-in. - display_path = ascii(path) # noqa: F821 - - return display_path - - -def display_path(path): - # type: (Union[str, Text]) -> str - """Gives the display value for a given path, making it relative to cwd - if possible.""" - path = os.path.normcase(os.path.abspath(path)) - if sys.version_info[0] == 2: - path = path.decode(sys.getfilesystemencoding(), 'replace') - path = path.encode(sys.getdefaultencoding(), 'replace') - if path.startswith(os.getcwd() + os.path.sep): - path = '.' + path[len(os.getcwd()):] - return path - - -def backup_dir(dir, ext='.bak'): - # type: (str, str) -> str - """Figure out the name of a directory to back up the given dir to - (adding .bak, .bak2, etc)""" - n = 1 - extension = ext - while os.path.exists(dir + extension): - n += 1 - extension = ext + str(n) - return dir + extension - - -def ask_path_exists(message, options): - # type: (str, Iterable[str]) -> str - for action in os.environ.get('PIP_EXISTS_ACTION', '').split(): - if action in options: - return action - return ask(message, options) - - -def _check_no_input(message): - # type: (str) -> None - """Raise an error if no input is allowed.""" - if os.environ.get('PIP_NO_INPUT'): - raise Exception( - 'No input was expected ($PIP_NO_INPUT set); question: {}'.format( - message) - ) - - -def ask(message, options): - # type: (str, Iterable[str]) -> str - """Ask the message interactively, with the given possible responses""" - while 1: - _check_no_input(message) - response = input(message) - response = response.strip().lower() - if response not in options: - print( - 'Your response ({!r}) was not one of the expected responses: ' - '{}'.format(response, ', '.join(options)) - ) - else: - return response - - -def ask_input(message): - # type: (str) -> str - """Ask for input interactively.""" - _check_no_input(message) - return input(message) - - -def ask_password(message): - # type: (str) -> str - """Ask for a password interactively.""" - _check_no_input(message) - return getpass.getpass(message) - - -def format_size(bytes): - # type: (float) -> str - if bytes > 1000 * 1000: - return '{:.1f} MB'.format(bytes / 1000.0 / 1000) - elif bytes > 10 * 1000: - return '{} kB'.format(int(bytes / 1000)) - elif bytes > 1000: - return '{:.1f} kB'.format(bytes / 1000.0) - else: - return '{} bytes'.format(int(bytes)) - - -def tabulate(rows): - # type: (Iterable[Iterable[Any]]) -> Tuple[List[str], List[int]] - """Return a list of formatted rows and a list of column sizes. - - For example:: - - >>> tabulate([['foobar', 2000], [0xdeadbeef]]) - (['foobar 2000', '3735928559'], [10, 4]) - """ - rows = [tuple(map(str, row)) for row in rows] - sizes = [max(map(len, col)) for col in zip_longest(*rows, fillvalue='')] - table = [" ".join(map(str.ljust, row, sizes)).rstrip() for row in rows] - return table, sizes - - -def is_installable_dir(path): - # type: (str) -> bool - """Is path is a directory containing setup.py or pyproject.toml? - """ - if not os.path.isdir(path): - return False - setup_py = os.path.join(path, 'setup.py') - if os.path.isfile(setup_py): - return True - pyproject_toml = os.path.join(path, 'pyproject.toml') - if os.path.isfile(pyproject_toml): - return True - return False - - -def read_chunks(file, size=io.DEFAULT_BUFFER_SIZE): - """Yield pieces of data from a file-like object until EOF.""" - while True: - chunk = file.read(size) - if not chunk: - break - yield chunk - - -def normalize_path(path, resolve_symlinks=True): - # type: (str, bool) -> str - """ - Convert a path to its canonical, case-normalized, absolute version. - - """ - path = expanduser(path) - if resolve_symlinks: - path = os.path.realpath(path) - else: - path = os.path.abspath(path) - return os.path.normcase(path) - - -def splitext(path): - # type: (str) -> Tuple[str, str] - """Like os.path.splitext, but take off .tar too""" - base, ext = posixpath.splitext(path) - if base.lower().endswith('.tar'): - ext = base[-4:] + ext - base = base[:-4] - return base, ext - - -def renames(old, new): - # type: (str, str) -> None - """Like os.renames(), but handles renaming across devices.""" - # Implementation borrowed from os.renames(). - head, tail = os.path.split(new) - if head and tail and not os.path.exists(head): - os.makedirs(head) - - shutil.move(old, new) - - head, tail = os.path.split(old) - if head and tail: - try: - os.removedirs(head) - except OSError: - pass - - -def is_local(path): - # type: (str) -> bool - """ - Return True if this is a path pip is allowed to modify. - - If we're in a virtualenv, sys.prefix points to the virtualenv's - prefix; only sys.prefix is considered local. - - If we're not in a virtualenv, in general we can modify anything. - However, if the OS vendor has configured distutils to install - somewhere other than sys.prefix (which could be a subdirectory of - sys.prefix, e.g. /usr/local), we consider sys.prefix itself nonlocal - and the domain of the OS vendor. (In other words, everything _other - than_ sys.prefix is considered local.) - - Caution: this function assumes the head of path has been normalized - with normalize_path. - """ - - path = normalize_path(path) - prefix = normalize_path(sys.prefix) - - if running_under_virtualenv(): - return path.startswith(normalize_path(sys.prefix)) - else: - from pip._internal.locations import distutils_scheme - if path.startswith(prefix): - for local_path in distutils_scheme("").values(): - if path.startswith(normalize_path(local_path)): - return True - return False - else: - return True - - -def dist_is_local(dist): - # type: (Distribution) -> bool - """ - Return True if given Distribution object is installed somewhere pip - is allowed to modify. - - """ - return is_local(dist_location(dist)) - - -def dist_in_usersite(dist): - # type: (Distribution) -> bool - """ - Return True if given Distribution is installed in user site. - """ - return dist_location(dist).startswith(normalize_path(user_site)) - - -def dist_in_site_packages(dist): - # type: (Distribution) -> bool - """ - Return True if given Distribution is installed in - sysconfig.get_python_lib(). - """ - return dist_location(dist).startswith(normalize_path(site_packages)) - - -def dist_is_editable(dist): - # type: (Distribution) -> bool - """ - Return True if given Distribution is an editable install. - """ - return bool(egg_link_path(dist)) - - -def get_installed_distributions( - local_only=True, # type: bool - skip=stdlib_pkgs, # type: Container[str] - include_editables=True, # type: bool - editables_only=False, # type: bool - user_only=False, # type: bool - paths=None # type: Optional[List[str]] -): - # type: (...) -> List[Distribution] - """ - Return a list of installed Distribution objects. - - If ``local_only`` is True (default), only return installations - local to the current virtualenv, if in a virtualenv. - - ``skip`` argument is an iterable of lower-case project names to - ignore; defaults to stdlib_pkgs - - If ``include_editables`` is False, don't report editables. - - If ``editables_only`` is True , only report editables. - - If ``user_only`` is True , only report installations in the user - site directory. - - If ``paths`` is set, only report the distributions present at the - specified list of locations. - """ - if paths: - working_set = pkg_resources.WorkingSet(paths) - else: - working_set = pkg_resources.working_set - - if local_only: - local_test = dist_is_local - else: - def local_test(d): - return True - - if include_editables: - def editable_test(d): - return True - else: - def editable_test(d): - return not dist_is_editable(d) - - if editables_only: - def editables_only_test(d): - return dist_is_editable(d) - else: - def editables_only_test(d): - return True - - if user_only: - user_test = dist_in_usersite - else: - def user_test(d): - return True - - return [d for d in working_set - if local_test(d) and - d.key not in skip and - editable_test(d) and - editables_only_test(d) and - user_test(d) - ] - - -def egg_link_path(dist): - # type: (Distribution) -> Optional[str] - """ - Return the path for the .egg-link file if it exists, otherwise, None. - - There's 3 scenarios: - 1) not in a virtualenv - try to find in site.USER_SITE, then site_packages - 2) in a no-global virtualenv - try to find in site_packages - 3) in a yes-global virtualenv - try to find in site_packages, then site.USER_SITE - (don't look in global location) - - For #1 and #3, there could be odd cases, where there's an egg-link in 2 - locations. - - This method will just return the first one found. - """ - sites = [] - if running_under_virtualenv(): - sites.append(site_packages) - if not virtualenv_no_global() and user_site: - sites.append(user_site) - else: - if user_site: - sites.append(user_site) - sites.append(site_packages) - - for site in sites: - egglink = os.path.join(site, dist.project_name) + '.egg-link' - if os.path.isfile(egglink): - return egglink - return None - - -def dist_location(dist): - # type: (Distribution) -> str - """ - Get the site-packages location of this distribution. Generally - this is dist.location, except in the case of develop-installed - packages, where dist.location is the source code location, and we - want to know where the egg-link file is. - - The returned location is normalized (in particular, with symlinks removed). - """ - egg_link = egg_link_path(dist) - if egg_link: - return normalize_path(egg_link) - return normalize_path(dist.location) - - -def write_output(msg, *args): - # type: (str, str) -> None - logger.info(msg, *args) - - -class FakeFile(object): - """Wrap a list of lines in an object with readline() to make - ConfigParser happy.""" - def __init__(self, lines): - self._gen = (l for l in lines) - - def readline(self): - try: - try: - return next(self._gen) - except NameError: - return self._gen.next() - except StopIteration: - return '' - - def __iter__(self): - return self._gen - - -class StreamWrapper(StringIO): - - @classmethod - def from_stream(cls, orig_stream): - cls.orig_stream = orig_stream - return cls() - - # compileall.compile_dir() needs stdout.encoding to print to stdout - @property - def encoding(self): - return self.orig_stream.encoding - - -@contextlib.contextmanager -def captured_output(stream_name): - """Return a context manager used by captured_stdout/stdin/stderr - that temporarily replaces the sys stream *stream_name* with a StringIO. - - Taken from Lib/support/__init__.py in the CPython repo. - """ - orig_stdout = getattr(sys, stream_name) - setattr(sys, stream_name, StreamWrapper.from_stream(orig_stdout)) - try: - yield getattr(sys, stream_name) - finally: - setattr(sys, stream_name, orig_stdout) - - -def captured_stdout(): - """Capture the output of sys.stdout: - - with captured_stdout() as stdout: - print('hello') - self.assertEqual(stdout.getvalue(), 'hello\n') - - Taken from Lib/support/__init__.py in the CPython repo. - """ - return captured_output('stdout') - - -def captured_stderr(): - """ - See captured_stdout(). - """ - return captured_output('stderr') - - -class cached_property(object): - """A property that is only computed once per instance and then replaces - itself with an ordinary attribute. Deleting the attribute resets the - property. - - Source: https://github.com/bottlepy/bottle/blob/0.11.5/bottle.py#L175 - """ - - def __init__(self, func): - self.__doc__ = getattr(func, '__doc__') - self.func = func - - def __get__(self, obj, cls): - if obj is None: - # We're being accessed from the class itself, not from an object - return self - value = obj.__dict__[self.func.__name__] = self.func(obj) - return value - - -def get_installed_version(dist_name, working_set=None): - """Get the installed version of dist_name avoiding pkg_resources cache""" - # Create a requirement that we'll look for inside of setuptools. - req = pkg_resources.Requirement.parse(dist_name) - - if working_set is None: - # We want to avoid having this cached, so we need to construct a new - # working set each time. - working_set = pkg_resources.WorkingSet() - - # Get the installed distribution from our working set - dist = working_set.find(req) - - # Check to see if we got an installed distribution or not, if we did - # we want to return it's version. - return dist.version if dist else None - - -def consume(iterator): - """Consume an iterable at C speed.""" - deque(iterator, maxlen=0) - - -# Simulates an enum -def enum(*sequential, **named): - enums = dict(zip(sequential, range(len(sequential))), **named) - reverse = {value: key for key, value in enums.items()} - enums['reverse_mapping'] = reverse - return type('Enum', (), enums) - - -def build_netloc(host, port): - # type: (str, Optional[int]) -> str - """ - Build a netloc from a host-port pair - """ - if port is None: - return host - if ':' in host: - # Only wrap host with square brackets when it is IPv6 - host = '[{}]'.format(host) - return '{}:{}'.format(host, port) - - -def build_url_from_netloc(netloc, scheme='https'): - # type: (str, str) -> str - """ - Build a full URL from a netloc. - """ - if netloc.count(':') >= 2 and '@' not in netloc and '[' not in netloc: - # It must be a bare IPv6 address, so wrap it with brackets. - netloc = '[{}]'.format(netloc) - return '{}://{}'.format(scheme, netloc) - - -def parse_netloc(netloc): - # type: (str) -> Tuple[str, Optional[int]] - """ - Return the host-port pair from a netloc. - """ - url = build_url_from_netloc(netloc) - parsed = urllib_parse.urlparse(url) - return parsed.hostname, parsed.port - - -def split_auth_from_netloc(netloc): - """ - Parse out and remove the auth information from a netloc. - - Returns: (netloc, (username, password)). - """ - if '@' not in netloc: - return netloc, (None, None) - - # Split from the right because that's how urllib.parse.urlsplit() - # behaves if more than one @ is present (which can be checked using - # the password attribute of urlsplit()'s return value). - auth, netloc = netloc.rsplit('@', 1) - if ':' in auth: - # Split from the left because that's how urllib.parse.urlsplit() - # behaves if more than one : is present (which again can be checked - # using the password attribute of the return value) - user_pass = auth.split(':', 1) - else: - user_pass = auth, None - - user_pass = tuple( - None if x is None else urllib_unquote(x) for x in user_pass - ) - - return netloc, user_pass - - -def redact_netloc(netloc): - # type: (str) -> str - """ - Replace the sensitive data in a netloc with "****", if it exists. - - For example: - - "user:pass@example.com" returns "user:****@example.com" - - "accesstoken@example.com" returns "****@example.com" - """ - netloc, (user, password) = split_auth_from_netloc(netloc) - if user is None: - return netloc - if password is None: - user = '****' - password = '' - else: - user = urllib_parse.quote(user) - password = ':****' - return '{user}{password}@{netloc}'.format(user=user, - password=password, - netloc=netloc) - - -def _transform_url(url, transform_netloc): - """Transform and replace netloc in a url. - - transform_netloc is a function taking the netloc and returning a - tuple. The first element of this tuple is the new netloc. The - entire tuple is returned. - - Returns a tuple containing the transformed url as item 0 and the - original tuple returned by transform_netloc as item 1. - """ - purl = urllib_parse.urlsplit(url) - netloc_tuple = transform_netloc(purl.netloc) - # stripped url - url_pieces = ( - purl.scheme, netloc_tuple[0], purl.path, purl.query, purl.fragment - ) - surl = urllib_parse.urlunsplit(url_pieces) - return surl, netloc_tuple - - -def _get_netloc(netloc): - return split_auth_from_netloc(netloc) - - -def _redact_netloc(netloc): - return (redact_netloc(netloc),) - - -def split_auth_netloc_from_url(url): - # type: (str) -> Tuple[str, str, Tuple[str, str]] - """ - Parse a url into separate netloc, auth, and url with no auth. - - Returns: (url_without_auth, netloc, (username, password)) - """ - url_without_auth, (netloc, auth) = _transform_url(url, _get_netloc) - return url_without_auth, netloc, auth - - -def remove_auth_from_url(url): - # type: (str) -> str - """Return a copy of url with 'username:password@' removed.""" - # username/pass params are passed to subversion through flags - # and are not recognized in the url. - return _transform_url(url, _get_netloc)[0] - - -def redact_auth_from_url(url): - # type: (str) -> str - """Replace the password in a given url with ****.""" - return _transform_url(url, _redact_netloc)[0] - - -class HiddenText(object): - def __init__( - self, - secret, # type: str - redacted, # type: str - ): - # type: (...) -> None - self.secret = secret - self.redacted = redacted - - def __repr__(self): - # type: (...) -> str - return '<HiddenText {!r}>'.format(str(self)) - - def __str__(self): - # type: (...) -> str - return self.redacted - - # This is useful for testing. - def __eq__(self, other): - # type: (Any) -> bool - if type(self) != type(other): - return False - - # The string being used for redaction doesn't also have to match, - # just the raw, original string. - return (self.secret == other.secret) - - # We need to provide an explicit __ne__ implementation for Python 2. - # TODO: remove this when we drop PY2 support. - def __ne__(self, other): - # type: (Any) -> bool - return not self == other - - -def hide_value(value): - # type: (str) -> HiddenText - return HiddenText(value, redacted='****') - - -def hide_url(url): - # type: (str) -> HiddenText - redacted = redact_auth_from_url(url) - return HiddenText(url, redacted=redacted) - - -def protect_pip_from_modification_on_windows(modifying_pip): - # type: (bool) -> None - """Protection of pip.exe from modification on Windows - - On Windows, any operation modifying pip should be run as: - python -m pip ... - """ - pip_names = [ - "pip.exe", - "pip{}.exe".format(sys.version_info[0]), - "pip{}.{}.exe".format(*sys.version_info[:2]) - ] - - # See https://github.com/pypa/pip/issues/1299 for more discussion - should_show_use_python_msg = ( - modifying_pip and - WINDOWS and - os.path.basename(sys.argv[0]) in pip_names - ) - - if should_show_use_python_msg: - new_command = [ - sys.executable, "-m", "pip" - ] + sys.argv[1:] - raise CommandError( - 'To modify pip, please run the following command:\n{}' - .format(" ".join(new_command)) - ) - - -def is_console_interactive(): - # type: () -> bool - """Is this console interactive? - """ - return sys.stdin is not None and sys.stdin.isatty() - - -def hash_file(path, blocksize=1 << 20): - # type: (str, int) -> Tuple[Any, int] - """Return (hash, length) for path using hashlib.sha256() - """ - - h = hashlib.sha256() - length = 0 - with open(path, 'rb') as f: - for block in read_chunks(f, size=blocksize): - length += len(block) - h.update(block) - return h, length - - -def is_wheel_installed(): - """ - Return whether the wheel package is installed. - """ - try: - import wheel # noqa: F401 - except ImportError: - return False - - return True - - -def pairwise(iterable): - # type: (Iterable[Any]) -> Iterator[Tuple[Any, Any]] - """ - Return paired elements. - - For example: - s -> (s0, s1), (s2, s3), (s4, s5), ... - """ - iterable = iter(iterable) - return zip_longest(iterable, iterable) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/models.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/models.py deleted file mode 100644 index 29e1441..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/utils/models.py +++ /dev/null @@ -1,42 +0,0 @@ -"""Utilities for defining models -""" -# The following comment should be removed at some point in the future. -# mypy: disallow-untyped-defs=False - -import operator - - -class KeyBasedCompareMixin(object): - """Provides comparison capabilities that is based on a key - """ - - def __init__(self, key, defining_class): - self._compare_key = key - self._defining_class = defining_class - - def __hash__(self): - return hash(self._compare_key) - - def __lt__(self, other): - return self._compare(other, operator.__lt__) - - def __le__(self, other): - return self._compare(other, operator.__le__) - - def __gt__(self, other): - return self._compare(other, operator.__gt__) - - def __ge__(self, other): - return self._compare(other, operator.__ge__) - - def __eq__(self, other): - return self._compare(other, operator.__eq__) - - def __ne__(self, other): - return self._compare(other, operator.__ne__) - - def _compare(self, other, method): - if not isinstance(other, self._defining_class): - return NotImplemented - - return method(self._compare_key, other._compare_key) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/packaging.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/packaging.py deleted file mode 100644 index 68aa86e..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/utils/packaging.py +++ /dev/null @@ -1,94 +0,0 @@ -from __future__ import absolute_import - -import logging -from email.parser import FeedParser - -from pip._vendor import pkg_resources -from pip._vendor.packaging import specifiers, version - -from pip._internal.exceptions import NoneMetadataError -from pip._internal.utils.misc import display_path -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import Optional, Tuple - from email.message import Message - from pip._vendor.pkg_resources import Distribution - - -logger = logging.getLogger(__name__) - - -def check_requires_python(requires_python, version_info): - # type: (Optional[str], Tuple[int, ...]) -> bool - """ - Check if the given Python version matches a "Requires-Python" specifier. - - :param version_info: A 3-tuple of ints representing a Python - major-minor-micro version to check (e.g. `sys.version_info[:3]`). - - :return: `True` if the given Python version satisfies the requirement. - Otherwise, return `False`. - - :raises InvalidSpecifier: If `requires_python` has an invalid format. - """ - if requires_python is None: - # The package provides no information - return True - requires_python_specifier = specifiers.SpecifierSet(requires_python) - - python_version = version.parse('.'.join(map(str, version_info))) - return python_version in requires_python_specifier - - -def get_metadata(dist): - # type: (Distribution) -> Message - """ - :raises NoneMetadataError: if the distribution reports `has_metadata()` - True but `get_metadata()` returns None. - """ - metadata_name = 'METADATA' - if (isinstance(dist, pkg_resources.DistInfoDistribution) and - dist.has_metadata(metadata_name)): - metadata = dist.get_metadata(metadata_name) - elif dist.has_metadata('PKG-INFO'): - metadata_name = 'PKG-INFO' - metadata = dist.get_metadata(metadata_name) - else: - logger.warning("No metadata found in %s", display_path(dist.location)) - metadata = '' - - if metadata is None: - raise NoneMetadataError(dist, metadata_name) - - feed_parser = FeedParser() - # The following line errors out if with a "NoneType" TypeError if - # passed metadata=None. - feed_parser.feed(metadata) - return feed_parser.close() - - -def get_requires_python(dist): - # type: (pkg_resources.Distribution) -> Optional[str] - """ - Return the "Requires-Python" metadata for a distribution, or None - if not present. - """ - pkg_info_dict = get_metadata(dist) - requires_python = pkg_info_dict.get('Requires-Python') - - if requires_python is not None: - # Convert to a str to satisfy the type checker, since requires_python - # can be a Header object. - requires_python = str(requires_python) - - return requires_python - - -def get_installer(dist): - # type: (Distribution) -> str - if dist.has_metadata('INSTALLER'): - for line in dist.get_metadata_lines('INSTALLER'): - if line.strip(): - return line.strip() - return '' diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/pkg_resources.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/pkg_resources.py deleted file mode 100644 index 0bc129a..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/utils/pkg_resources.py +++ /dev/null @@ -1,44 +0,0 @@ -from pip._vendor.pkg_resources import yield_lines -from pip._vendor.six import ensure_str - -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import Dict, Iterable, List - - -class DictMetadata(object): - """IMetadataProvider that reads metadata files from a dictionary. - """ - def __init__(self, metadata): - # type: (Dict[str, bytes]) -> None - self._metadata = metadata - - def has_metadata(self, name): - # type: (str) -> bool - return name in self._metadata - - def get_metadata(self, name): - # type: (str) -> str - try: - return ensure_str(self._metadata[name]) - except UnicodeDecodeError as e: - # Mirrors handling done in pkg_resources.NullProvider. - e.reason += " in {} file".format(name) - raise - - def get_metadata_lines(self, name): - # type: (str) -> Iterable[str] - return yield_lines(self.get_metadata(name)) - - def metadata_isdir(self, name): - # type: (str) -> bool - return False - - def metadata_listdir(self, name): - # type: (str) -> List[str] - return [] - - def run_script(self, script_name, namespace): - # type: (str, str) -> None - pass diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/setuptools_build.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/setuptools_build.py deleted file mode 100644 index 2a664b0..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/utils/setuptools_build.py +++ /dev/null @@ -1,181 +0,0 @@ -import sys - -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import List, Optional, Sequence - -# Shim to wrap setup.py invocation with setuptools -# -# We set sys.argv[0] to the path to the underlying setup.py file so -# setuptools / distutils don't take the path to the setup.py to be "-c" when -# invoking via the shim. This avoids e.g. the following manifest_maker -# warning: "warning: manifest_maker: standard file '-c' not found". -_SETUPTOOLS_SHIM = ( - "import sys, setuptools, tokenize; sys.argv[0] = {0!r}; __file__={0!r};" - "f=getattr(tokenize, 'open', open)(__file__);" - "code=f.read().replace('\\r\\n', '\\n');" - "f.close();" - "exec(compile(code, __file__, 'exec'))" -) - - -def make_setuptools_shim_args( - setup_py_path, # type: str - global_options=None, # type: Sequence[str] - no_user_config=False, # type: bool - unbuffered_output=False # type: bool -): - # type: (...) -> List[str] - """ - Get setuptools command arguments with shim wrapped setup file invocation. - - :param setup_py_path: The path to setup.py to be wrapped. - :param global_options: Additional global options. - :param no_user_config: If True, disables personal user configuration. - :param unbuffered_output: If True, adds the unbuffered switch to the - argument list. - """ - args = [sys.executable] - if unbuffered_output: - args += ["-u"] - args += ["-c", _SETUPTOOLS_SHIM.format(setup_py_path)] - if global_options: - args += global_options - if no_user_config: - args += ["--no-user-cfg"] - return args - - -def make_setuptools_bdist_wheel_args( - setup_py_path, # type: str - global_options, # type: Sequence[str] - build_options, # type: Sequence[str] - destination_dir, # type: str -): - # type: (...) -> List[str] - # NOTE: Eventually, we'd want to also -S to the flags here, when we're - # isolating. Currently, it breaks Python in virtualenvs, because it - # relies on site.py to find parts of the standard library outside the - # virtualenv. - args = make_setuptools_shim_args( - setup_py_path, - global_options=global_options, - unbuffered_output=True - ) - args += ["bdist_wheel", "-d", destination_dir] - args += build_options - return args - - -def make_setuptools_clean_args( - setup_py_path, # type: str - global_options, # type: Sequence[str] -): - # type: (...) -> List[str] - args = make_setuptools_shim_args( - setup_py_path, - global_options=global_options, - unbuffered_output=True - ) - args += ["clean", "--all"] - return args - - -def make_setuptools_develop_args( - setup_py_path, # type: str - global_options, # type: Sequence[str] - install_options, # type: Sequence[str] - no_user_config, # type: bool - prefix, # type: Optional[str] - home, # type: Optional[str] - use_user_site, # type: bool -): - # type: (...) -> List[str] - assert not (use_user_site and prefix) - - args = make_setuptools_shim_args( - setup_py_path, - global_options=global_options, - no_user_config=no_user_config, - ) - - args += ["develop", "--no-deps"] - - args += install_options - - if prefix: - args += ["--prefix", prefix] - if home is not None: - args += ["--home", home] - - if use_user_site: - args += ["--user", "--prefix="] - - return args - - -def make_setuptools_egg_info_args( - setup_py_path, # type: str - egg_info_dir, # type: Optional[str] - no_user_config, # type: bool -): - # type: (...) -> List[str] - args = make_setuptools_shim_args( - setup_py_path, no_user_config=no_user_config - ) - - args += ["egg_info"] - - if egg_info_dir: - args += ["--egg-base", egg_info_dir] - - return args - - -def make_setuptools_install_args( - setup_py_path, # type: str - global_options, # type: Sequence[str] - install_options, # type: Sequence[str] - record_filename, # type: str - root, # type: Optional[str] - prefix, # type: Optional[str] - header_dir, # type: Optional[str] - home, # type: Optional[str] - use_user_site, # type: bool - no_user_config, # type: bool - pycompile # type: bool -): - # type: (...) -> List[str] - assert not (use_user_site and prefix) - assert not (use_user_site and root) - - args = make_setuptools_shim_args( - setup_py_path, - global_options=global_options, - no_user_config=no_user_config, - unbuffered_output=True - ) - args += ["install", "--record", record_filename] - args += ["--single-version-externally-managed"] - - if root is not None: - args += ["--root", root] - if prefix is not None: - args += ["--prefix", prefix] - if home is not None: - args += ["--home", home] - if use_user_site: - args += ["--user", "--prefix="] - - if pycompile: - args += ["--compile"] - else: - args += ["--no-compile"] - - if header_dir: - args += ["--install-headers", header_dir] - - args += install_options - - return args diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/subprocess.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/subprocess.py deleted file mode 100644 index 55c82da..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/utils/subprocess.py +++ /dev/null @@ -1,277 +0,0 @@ -# The following comment should be removed at some point in the future. -# mypy: strict-optional=False - -from __future__ import absolute_import - -import logging -import os -import subprocess - -from pip._vendor.six.moves import shlex_quote - -from pip._internal.cli.spinners import SpinnerInterface, open_spinner -from pip._internal.exceptions import InstallationError -from pip._internal.utils.compat import console_to_str, str_to_display -from pip._internal.utils.logging import subprocess_logger -from pip._internal.utils.misc import HiddenText, path_to_display -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import ( - Any, Callable, Iterable, List, Mapping, Optional, Text, Union, - ) - - CommandArgs = List[Union[str, HiddenText]] - - -LOG_DIVIDER = '----------------------------------------' - - -def make_command(*args): - # type: (Union[str, HiddenText, CommandArgs]) -> CommandArgs - """ - Create a CommandArgs object. - """ - command_args = [] # type: CommandArgs - for arg in args: - # Check for list instead of CommandArgs since CommandArgs is - # only known during type-checking. - if isinstance(arg, list): - command_args.extend(arg) - else: - # Otherwise, arg is str or HiddenText. - command_args.append(arg) - - return command_args - - -def format_command_args(args): - # type: (Union[List[str], CommandArgs]) -> str - """ - Format command arguments for display. - """ - # For HiddenText arguments, display the redacted form by calling str(). - # Also, we don't apply str() to arguments that aren't HiddenText since - # this can trigger a UnicodeDecodeError in Python 2 if the argument - # has type unicode and includes a non-ascii character. (The type - # checker doesn't ensure the annotations are correct in all cases.) - return ' '.join( - shlex_quote(str(arg)) if isinstance(arg, HiddenText) - else shlex_quote(arg) for arg in args - ) - - -def reveal_command_args(args): - # type: (Union[List[str], CommandArgs]) -> List[str] - """ - Return the arguments in their raw, unredacted form. - """ - return [ - arg.secret if isinstance(arg, HiddenText) else arg for arg in args - ] - - -def make_subprocess_output_error( - cmd_args, # type: Union[List[str], CommandArgs] - cwd, # type: Optional[str] - lines, # type: List[Text] - exit_status, # type: int -): - # type: (...) -> Text - """ - Create and return the error message to use to log a subprocess error - with command output. - - :param lines: A list of lines, each ending with a newline. - """ - command = format_command_args(cmd_args) - # Convert `command` and `cwd` to text (unicode in Python 2) so we can use - # them as arguments in the unicode format string below. This avoids - # "UnicodeDecodeError: 'ascii' codec can't decode byte ..." in Python 2 - # if either contains a non-ascii character. - command_display = str_to_display(command, desc='command bytes') - cwd_display = path_to_display(cwd) - - # We know the joined output value ends in a newline. - output = ''.join(lines) - msg = ( - # Use a unicode string to avoid "UnicodeEncodeError: 'ascii' - # codec can't encode character ..." in Python 2 when a format - # argument (e.g. `output`) has a non-ascii character. - u'Command errored out with exit status {exit_status}:\n' - ' command: {command_display}\n' - ' cwd: {cwd_display}\n' - 'Complete output ({line_count} lines):\n{output}{divider}' - ).format( - exit_status=exit_status, - command_display=command_display, - cwd_display=cwd_display, - line_count=len(lines), - output=output, - divider=LOG_DIVIDER, - ) - return msg - - -def call_subprocess( - cmd, # type: Union[List[str], CommandArgs] - show_stdout=False, # type: bool - cwd=None, # type: Optional[str] - on_returncode='raise', # type: str - extra_ok_returncodes=None, # type: Optional[Iterable[int]] - command_desc=None, # type: Optional[str] - extra_environ=None, # type: Optional[Mapping[str, Any]] - unset_environ=None, # type: Optional[Iterable[str]] - spinner=None, # type: Optional[SpinnerInterface] - log_failed_cmd=True # type: Optional[bool] -): - # type: (...) -> Text - """ - Args: - show_stdout: if true, use INFO to log the subprocess's stderr and - stdout streams. Otherwise, use DEBUG. Defaults to False. - extra_ok_returncodes: an iterable of integer return codes that are - acceptable, in addition to 0. Defaults to None, which means []. - unset_environ: an iterable of environment variable names to unset - prior to calling subprocess.Popen(). - log_failed_cmd: if false, failed commands are not logged, only raised. - """ - if extra_ok_returncodes is None: - extra_ok_returncodes = [] - if unset_environ is None: - unset_environ = [] - # Most places in pip use show_stdout=False. What this means is-- - # - # - We connect the child's output (combined stderr and stdout) to a - # single pipe, which we read. - # - We log this output to stderr at DEBUG level as it is received. - # - If DEBUG logging isn't enabled (e.g. if --verbose logging wasn't - # requested), then we show a spinner so the user can still see the - # subprocess is in progress. - # - If the subprocess exits with an error, we log the output to stderr - # at ERROR level if it hasn't already been displayed to the console - # (e.g. if --verbose logging wasn't enabled). This way we don't log - # the output to the console twice. - # - # If show_stdout=True, then the above is still done, but with DEBUG - # replaced by INFO. - if show_stdout: - # Then log the subprocess output at INFO level. - log_subprocess = subprocess_logger.info - used_level = logging.INFO - else: - # Then log the subprocess output using DEBUG. This also ensures - # it will be logged to the log file (aka user_log), if enabled. - log_subprocess = subprocess_logger.debug - used_level = logging.DEBUG - - # Whether the subprocess will be visible in the console. - showing_subprocess = subprocess_logger.getEffectiveLevel() <= used_level - - # Only use the spinner if we're not showing the subprocess output - # and we have a spinner. - use_spinner = not showing_subprocess and spinner is not None - - if command_desc is None: - command_desc = format_command_args(cmd) - - log_subprocess("Running command %s", command_desc) - env = os.environ.copy() - if extra_environ: - env.update(extra_environ) - for name in unset_environ: - env.pop(name, None) - try: - proc = subprocess.Popen( - # Convert HiddenText objects to the underlying str. - reveal_command_args(cmd), - stderr=subprocess.STDOUT, stdin=subprocess.PIPE, - stdout=subprocess.PIPE, cwd=cwd, env=env, - ) - proc.stdin.close() - except Exception as exc: - if log_failed_cmd: - subprocess_logger.critical( - "Error %s while executing command %s", exc, command_desc, - ) - raise - all_output = [] - while True: - # The "line" value is a unicode string in Python 2. - line = console_to_str(proc.stdout.readline()) - if not line: - break - line = line.rstrip() - all_output.append(line + '\n') - - # Show the line immediately. - log_subprocess(line) - # Update the spinner. - if use_spinner: - spinner.spin() - try: - proc.wait() - finally: - if proc.stdout: - proc.stdout.close() - proc_had_error = ( - proc.returncode and proc.returncode not in extra_ok_returncodes - ) - if use_spinner: - if proc_had_error: - spinner.finish("error") - else: - spinner.finish("done") - if proc_had_error: - if on_returncode == 'raise': - if not showing_subprocess and log_failed_cmd: - # Then the subprocess streams haven't been logged to the - # console yet. - msg = make_subprocess_output_error( - cmd_args=cmd, - cwd=cwd, - lines=all_output, - exit_status=proc.returncode, - ) - subprocess_logger.error(msg) - exc_msg = ( - 'Command errored out with exit status {}: {} ' - 'Check the logs for full command output.' - ).format(proc.returncode, command_desc) - raise InstallationError(exc_msg) - elif on_returncode == 'warn': - subprocess_logger.warning( - 'Command "{}" had error code {} in {}'.format( - command_desc, proc.returncode, cwd) - ) - elif on_returncode == 'ignore': - pass - else: - raise ValueError('Invalid value: on_returncode={!r}'.format( - on_returncode)) - return ''.join(all_output) - - -def runner_with_spinner_message(message): - # type: (str) -> Callable[..., None] - """Provide a subprocess_runner that shows a spinner message. - - Intended for use with for pep517's Pep517HookCaller. Thus, the runner has - an API that matches what's expected by Pep517HookCaller.subprocess_runner. - """ - - def runner( - cmd, # type: List[str] - cwd=None, # type: Optional[str] - extra_environ=None # type: Optional[Mapping[str, Any]] - ): - # type: (...) -> None - with open_spinner(message) as spinner: - call_subprocess( - cmd, - cwd=cwd, - extra_environ=extra_environ, - spinner=spinner, - ) - - return runner diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/temp_dir.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/temp_dir.py deleted file mode 100644 index 201ba6d..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/utils/temp_dir.py +++ /dev/null @@ -1,271 +0,0 @@ -from __future__ import absolute_import - -import errno -import itertools -import logging -import os.path -import tempfile -from contextlib import contextmanager - -from pip._vendor.contextlib2 import ExitStack - -from pip._internal.utils.misc import enum, rmtree -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import Any, Dict, Iterator, Optional, TypeVar, Union - - _T = TypeVar('_T', bound='TempDirectory') - - -logger = logging.getLogger(__name__) - - -# Kinds of temporary directories. Only needed for ones that are -# globally-managed. -tempdir_kinds = enum( - BUILD_ENV="build-env", - EPHEM_WHEEL_CACHE="ephem-wheel-cache", - REQ_BUILD="req-build", -) - - -_tempdir_manager = None # type: Optional[ExitStack] - - -@contextmanager -def global_tempdir_manager(): - # type: () -> Iterator[None] - global _tempdir_manager - with ExitStack() as stack: - old_tempdir_manager, _tempdir_manager = _tempdir_manager, stack - try: - yield - finally: - _tempdir_manager = old_tempdir_manager - - -class TempDirectoryTypeRegistry(object): - """Manages temp directory behavior - """ - - def __init__(self): - # type: () -> None - self._should_delete = {} # type: Dict[str, bool] - - def set_delete(self, kind, value): - # type: (str, bool) -> None - """Indicate whether a TempDirectory of the given kind should be - auto-deleted. - """ - self._should_delete[kind] = value - - def get_delete(self, kind): - # type: (str) -> bool - """Get configured auto-delete flag for a given TempDirectory type, - default True. - """ - return self._should_delete.get(kind, True) - - -_tempdir_registry = None # type: Optional[TempDirectoryTypeRegistry] - - -@contextmanager -def tempdir_registry(): - # type: () -> Iterator[TempDirectoryTypeRegistry] - """Provides a scoped global tempdir registry that can be used to dictate - whether directories should be deleted. - """ - global _tempdir_registry - old_tempdir_registry = _tempdir_registry - _tempdir_registry = TempDirectoryTypeRegistry() - try: - yield _tempdir_registry - finally: - _tempdir_registry = old_tempdir_registry - - -class _Default(object): - pass - - -_default = _Default() - - -class TempDirectory(object): - """Helper class that owns and cleans up a temporary directory. - - This class can be used as a context manager or as an OO representation of a - temporary directory. - - Attributes: - path - Location to the created temporary directory - delete - Whether the directory should be deleted when exiting - (when used as a contextmanager) - - Methods: - cleanup() - Deletes the temporary directory - - When used as a context manager, if the delete attribute is True, on - exiting the context the temporary directory is deleted. - """ - - def __init__( - self, - path=None, # type: Optional[str] - delete=_default, # type: Union[bool, None, _Default] - kind="temp", # type: str - globally_managed=False, # type: bool - ): - super(TempDirectory, self).__init__() - - if delete is _default: - if path is not None: - # If we were given an explicit directory, resolve delete option - # now. - delete = False - else: - # Otherwise, we wait until cleanup and see what - # tempdir_registry says. - delete = None - - if path is None: - path = self._create(kind) - - self._path = path - self._deleted = False - self.delete = delete - self.kind = kind - - if globally_managed: - assert _tempdir_manager is not None - _tempdir_manager.enter_context(self) - - @property - def path(self): - # type: () -> str - assert not self._deleted, ( - "Attempted to access deleted path: {}".format(self._path) - ) - return self._path - - def __repr__(self): - # type: () -> str - return "<{} {!r}>".format(self.__class__.__name__, self.path) - - def __enter__(self): - # type: (_T) -> _T - return self - - def __exit__(self, exc, value, tb): - # type: (Any, Any, Any) -> None - if self.delete is not None: - delete = self.delete - elif _tempdir_registry: - delete = _tempdir_registry.get_delete(self.kind) - else: - delete = True - - if delete: - self.cleanup() - - def _create(self, kind): - # type: (str) -> str - """Create a temporary directory and store its path in self.path - """ - # We realpath here because some systems have their default tmpdir - # symlinked to another directory. This tends to confuse build - # scripts, so we canonicalize the path by traversing potential - # symlinks here. - path = os.path.realpath( - tempfile.mkdtemp(prefix="pip-{}-".format(kind)) - ) - logger.debug("Created temporary directory: {}".format(path)) - return path - - def cleanup(self): - # type: () -> None - """Remove the temporary directory created and reset state - """ - self._deleted = True - if os.path.exists(self._path): - rmtree(self._path) - - -class AdjacentTempDirectory(TempDirectory): - """Helper class that creates a temporary directory adjacent to a real one. - - Attributes: - original - The original directory to create a temp directory for. - path - After calling create() or entering, contains the full - path to the temporary directory. - delete - Whether the directory should be deleted when exiting - (when used as a contextmanager) - - """ - # The characters that may be used to name the temp directory - # We always prepend a ~ and then rotate through these until - # a usable name is found. - # pkg_resources raises a different error for .dist-info folder - # with leading '-' and invalid metadata - LEADING_CHARS = "-~.=%0123456789" - - def __init__(self, original, delete=None): - # type: (str, Optional[bool]) -> None - self.original = original.rstrip('/\\') - super(AdjacentTempDirectory, self).__init__(delete=delete) - - @classmethod - def _generate_names(cls, name): - # type: (str) -> Iterator[str] - """Generates a series of temporary names. - - The algorithm replaces the leading characters in the name - with ones that are valid filesystem characters, but are not - valid package names (for both Python and pip definitions of - package). - """ - for i in range(1, len(name)): - for candidate in itertools.combinations_with_replacement( - cls.LEADING_CHARS, i - 1): - new_name = '~' + ''.join(candidate) + name[i:] - if new_name != name: - yield new_name - - # If we make it this far, we will have to make a longer name - for i in range(len(cls.LEADING_CHARS)): - for candidate in itertools.combinations_with_replacement( - cls.LEADING_CHARS, i): - new_name = '~' + ''.join(candidate) + name - if new_name != name: - yield new_name - - def _create(self, kind): - # type: (str) -> str - root, name = os.path.split(self.original) - for candidate in self._generate_names(name): - path = os.path.join(root, candidate) - try: - os.mkdir(path) - except OSError as ex: - # Continue if the name exists already - if ex.errno != errno.EEXIST: - raise - else: - path = os.path.realpath(path) - break - else: - # Final fallback on the default behavior. - path = os.path.realpath( - tempfile.mkdtemp(prefix="pip-{}-".format(kind)) - ) - - logger.debug("Created temporary directory: {}".format(path)) - return path diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/typing.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/typing.py deleted file mode 100644 index 8505a29..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/utils/typing.py +++ /dev/null @@ -1,38 +0,0 @@ -"""For neatly implementing static typing in pip. - -`mypy` - the static type analysis tool we use - uses the `typing` module, which -provides core functionality fundamental to mypy's functioning. - -Generally, `typing` would be imported at runtime and used in that fashion - -it acts as a no-op at runtime and does not have any run-time overhead by -design. - -As it turns out, `typing` is not vendorable - it uses separate sources for -Python 2/Python 3. Thus, this codebase can not expect it to be present. -To work around this, mypy allows the typing import to be behind a False-y -optional to prevent it from running at runtime and type-comments can be used -to remove the need for the types to be accessible directly during runtime. - -This module provides the False-y guard in a nicely named fashion so that a -curious maintainer can reach here to read this. - -In pip, all static-typing related imports should be guarded as follows: - - from pip._internal.utils.typing import MYPY_CHECK_RUNNING - - if MYPY_CHECK_RUNNING: - from typing import ... - -Ref: https://github.com/python/mypy/issues/3216 -""" - -MYPY_CHECK_RUNNING = False - - -if MYPY_CHECK_RUNNING: - from typing import cast -else: - # typing's cast() is needed at runtime, but we don't want to import typing. - # Thus, we use a dummy no-op version, which we tell mypy to ignore. - def cast(type_, value): # type: ignore - return value diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/unpacking.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/unpacking.py deleted file mode 100644 index 7252dc2..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/utils/unpacking.py +++ /dev/null @@ -1,272 +0,0 @@ -"""Utilities related archives. -""" - -# The following comment should be removed at some point in the future. -# mypy: strict-optional=False -# mypy: disallow-untyped-defs=False - -from __future__ import absolute_import - -import logging -import os -import shutil -import stat -import tarfile -import zipfile - -from pip._internal.exceptions import InstallationError -from pip._internal.utils.filetypes import ( - BZ2_EXTENSIONS, - TAR_EXTENSIONS, - XZ_EXTENSIONS, - ZIP_EXTENSIONS, -) -from pip._internal.utils.misc import ensure_dir -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import Iterable, List, Optional, Text, Union - - -logger = logging.getLogger(__name__) - - -SUPPORTED_EXTENSIONS = ZIP_EXTENSIONS + TAR_EXTENSIONS - -try: - import bz2 # noqa - SUPPORTED_EXTENSIONS += BZ2_EXTENSIONS -except ImportError: - logger.debug('bz2 module is not available') - -try: - # Only for Python 3.3+ - import lzma # noqa - SUPPORTED_EXTENSIONS += XZ_EXTENSIONS -except ImportError: - logger.debug('lzma module is not available') - - -def current_umask(): - """Get the current umask which involves having to set it temporarily.""" - mask = os.umask(0) - os.umask(mask) - return mask - - -def split_leading_dir(path): - # type: (Union[str, Text]) -> List[Union[str, Text]] - path = path.lstrip('/').lstrip('\\') - if ( - '/' in path and ( - ('\\' in path and path.find('/') < path.find('\\')) or - '\\' not in path - ) - ): - return path.split('/', 1) - elif '\\' in path: - return path.split('\\', 1) - else: - return [path, ''] - - -def has_leading_dir(paths): - # type: (Iterable[Union[str, Text]]) -> bool - """Returns true if all the paths have the same leading path name - (i.e., everything is in one subdirectory in an archive)""" - common_prefix = None - for path in paths: - prefix, rest = split_leading_dir(path) - if not prefix: - return False - elif common_prefix is None: - common_prefix = prefix - elif prefix != common_prefix: - return False - return True - - -def is_within_directory(directory, target): - # type: ((Union[str, Text]), (Union[str, Text])) -> bool - """ - Return true if the absolute path of target is within the directory - """ - abs_directory = os.path.abspath(directory) - abs_target = os.path.abspath(target) - - prefix = os.path.commonprefix([abs_directory, abs_target]) - return prefix == abs_directory - - -def unzip_file(filename, location, flatten=True): - # type: (str, str, bool) -> None - """ - Unzip the file (with path `filename`) to the destination `location`. All - files are written based on system defaults and umask (i.e. permissions are - not preserved), except that regular file members with any execute - permissions (user, group, or world) have "chmod +x" applied after being - written. Note that for windows, any execute changes using os.chmod are - no-ops per the python docs. - """ - ensure_dir(location) - zipfp = open(filename, 'rb') - try: - zip = zipfile.ZipFile(zipfp, allowZip64=True) - leading = has_leading_dir(zip.namelist()) and flatten - for info in zip.infolist(): - name = info.filename - fn = name - if leading: - fn = split_leading_dir(name)[1] - fn = os.path.join(location, fn) - dir = os.path.dirname(fn) - if not is_within_directory(location, fn): - message = ( - 'The zip file ({}) has a file ({}) trying to install ' - 'outside target directory ({})' - ) - raise InstallationError(message.format(filename, fn, location)) - if fn.endswith('/') or fn.endswith('\\'): - # A directory - ensure_dir(fn) - else: - ensure_dir(dir) - # Don't use read() to avoid allocating an arbitrarily large - # chunk of memory for the file's content - fp = zip.open(name) - try: - with open(fn, 'wb') as destfp: - shutil.copyfileobj(fp, destfp) - finally: - fp.close() - mode = info.external_attr >> 16 - # if mode and regular file and any execute permissions for - # user/group/world? - if mode and stat.S_ISREG(mode) and mode & 0o111: - # make dest file have execute for user/group/world - # (chmod +x) no-op on windows per python docs - os.chmod(fn, (0o777 - current_umask() | 0o111)) - finally: - zipfp.close() - - -def untar_file(filename, location): - # type: (str, str) -> None - """ - Untar the file (with path `filename`) to the destination `location`. - All files are written based on system defaults and umask (i.e. permissions - are not preserved), except that regular file members with any execute - permissions (user, group, or world) have "chmod +x" applied after being - written. Note that for windows, any execute changes using os.chmod are - no-ops per the python docs. - """ - ensure_dir(location) - if filename.lower().endswith('.gz') or filename.lower().endswith('.tgz'): - mode = 'r:gz' - elif filename.lower().endswith(BZ2_EXTENSIONS): - mode = 'r:bz2' - elif filename.lower().endswith(XZ_EXTENSIONS): - mode = 'r:xz' - elif filename.lower().endswith('.tar'): - mode = 'r' - else: - logger.warning( - 'Cannot determine compression type for file %s', filename, - ) - mode = 'r:*' - tar = tarfile.open(filename, mode) - try: - leading = has_leading_dir([ - member.name for member in tar.getmembers() - ]) - for member in tar.getmembers(): - fn = member.name - if leading: - # https://github.com/python/mypy/issues/1174 - fn = split_leading_dir(fn)[1] # type: ignore - path = os.path.join(location, fn) - if not is_within_directory(location, path): - message = ( - 'The tar file ({}) has a file ({}) trying to install ' - 'outside target directory ({})' - ) - raise InstallationError( - message.format(filename, path, location) - ) - if member.isdir(): - ensure_dir(path) - elif member.issym(): - try: - # https://github.com/python/typeshed/issues/2673 - tar._extract_member(member, path) # type: ignore - except Exception as exc: - # Some corrupt tar files seem to produce this - # (specifically bad symlinks) - logger.warning( - 'In the tar file %s the member %s is invalid: %s', - filename, member.name, exc, - ) - continue - else: - try: - fp = tar.extractfile(member) - except (KeyError, AttributeError) as exc: - # Some corrupt tar files seem to produce this - # (specifically bad symlinks) - logger.warning( - 'In the tar file %s the member %s is invalid: %s', - filename, member.name, exc, - ) - continue - ensure_dir(os.path.dirname(path)) - with open(path, 'wb') as destfp: - shutil.copyfileobj(fp, destfp) - fp.close() - # Update the timestamp (useful for cython compiled files) - # https://github.com/python/typeshed/issues/2673 - tar.utime(member, path) # type: ignore - # member have any execute permissions for user/group/world? - if member.mode & 0o111: - # make dest file have execute for user/group/world - # no-op on windows per python docs - os.chmod(path, (0o777 - current_umask() | 0o111)) - finally: - tar.close() - - -def unpack_file( - filename, # type: str - location, # type: str - content_type=None, # type: Optional[str] -): - # type: (...) -> None - filename = os.path.realpath(filename) - if ( - content_type == 'application/zip' or - filename.lower().endswith(ZIP_EXTENSIONS) or - zipfile.is_zipfile(filename) - ): - unzip_file( - filename, - location, - flatten=not filename.endswith('.whl') - ) - elif ( - content_type == 'application/x-gzip' or - tarfile.is_tarfile(filename) or - filename.lower().endswith( - TAR_EXTENSIONS + BZ2_EXTENSIONS + XZ_EXTENSIONS - ) - ): - untar_file(filename, location) - else: - # FIXME: handle? - # FIXME: magic signatures? - logger.critical( - 'Cannot unpack file %s (downloaded from %s, content-type: %s); ' - 'cannot detect archive format', - filename, location, content_type, - ) - raise InstallationError( - 'Cannot determine archive format of {}'.format(location) - ) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/urls.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/urls.py deleted file mode 100644 index f37bc8f..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/utils/urls.py +++ /dev/null @@ -1,55 +0,0 @@ -import os -import sys - -from pip._vendor.six.moves.urllib import parse as urllib_parse -from pip._vendor.six.moves.urllib import request as urllib_request - -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import Optional, Text, Union - - -def get_url_scheme(url): - # type: (Union[str, Text]) -> Optional[Text] - if ':' not in url: - return None - return url.split(':', 1)[0].lower() - - -def path_to_url(path): - # type: (Union[str, Text]) -> str - """ - Convert a path to a file: URL. The path will be made absolute and have - quoted path parts. - """ - path = os.path.normpath(os.path.abspath(path)) - url = urllib_parse.urljoin('file:', urllib_request.pathname2url(path)) - return url - - -def url_to_path(url): - # type: (str) -> str - """ - Convert a file: URL to a path. - """ - assert url.startswith('file:'), ( - "You can only turn file: urls into filenames (not {url!r})" - .format(**locals())) - - _, netloc, path, _, _ = urllib_parse.urlsplit(url) - - if not netloc or netloc == 'localhost': - # According to RFC 8089, same as empty authority. - netloc = '' - elif sys.platform == 'win32': - # If we have a UNC path, prepend UNC share notation. - netloc = '\\\\' + netloc - else: - raise ValueError( - 'non-local file URIs are not supported on this platform: {url!r}' - .format(**locals()) - ) - - path = urllib_request.url2pathname(netloc + path) - return path diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/virtualenv.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/virtualenv.py deleted file mode 100644 index 596a69a..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/utils/virtualenv.py +++ /dev/null @@ -1,116 +0,0 @@ -from __future__ import absolute_import - -import logging -import os -import re -import site -import sys - -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from typing import List, Optional - -logger = logging.getLogger(__name__) -_INCLUDE_SYSTEM_SITE_PACKAGES_REGEX = re.compile( - r"include-system-site-packages\s*=\s*(?P<value>true|false)" -) - - -def _running_under_venv(): - # type: () -> bool - """Checks if sys.base_prefix and sys.prefix match. - - This handles PEP 405 compliant virtual environments. - """ - return sys.prefix != getattr(sys, "base_prefix", sys.prefix) - - -def _running_under_regular_virtualenv(): - # type: () -> bool - """Checks if sys.real_prefix is set. - - This handles virtual environments created with pypa's virtualenv. - """ - # pypa/virtualenv case - return hasattr(sys, 'real_prefix') - - -def running_under_virtualenv(): - # type: () -> bool - """Return True if we're running inside a virtualenv, False otherwise. - """ - return _running_under_venv() or _running_under_regular_virtualenv() - - -def _get_pyvenv_cfg_lines(): - # type: () -> Optional[List[str]] - """Reads {sys.prefix}/pyvenv.cfg and returns its contents as list of lines - - Returns None, if it could not read/access the file. - """ - pyvenv_cfg_file = os.path.join(sys.prefix, 'pyvenv.cfg') - try: - with open(pyvenv_cfg_file) as f: - return f.read().splitlines() # avoids trailing newlines - except IOError: - return None - - -def _no_global_under_venv(): - # type: () -> bool - """Check `{sys.prefix}/pyvenv.cfg` for system site-packages inclusion - - PEP 405 specifies that when system site-packages are not supposed to be - visible from a virtual environment, `pyvenv.cfg` must contain the following - line: - - include-system-site-packages = false - - Additionally, log a warning if accessing the file fails. - """ - cfg_lines = _get_pyvenv_cfg_lines() - if cfg_lines is None: - # We're not in a "sane" venv, so assume there is no system - # site-packages access (since that's PEP 405's default state). - logger.warning( - "Could not access 'pyvenv.cfg' despite a virtual environment " - "being active. Assuming global site-packages is not accessible " - "in this environment." - ) - return True - - for line in cfg_lines: - match = _INCLUDE_SYSTEM_SITE_PACKAGES_REGEX.match(line) - if match is not None and match.group('value') == 'false': - return True - return False - - -def _no_global_under_regular_virtualenv(): - # type: () -> bool - """Check if "no-global-site-packages.txt" exists beside site.py - - This mirrors logic in pypa/virtualenv for determining whether system - site-packages are visible in the virtual environment. - """ - site_mod_dir = os.path.dirname(os.path.abspath(site.__file__)) - no_global_site_packages_file = os.path.join( - site_mod_dir, 'no-global-site-packages.txt', - ) - return os.path.exists(no_global_site_packages_file) - - -def virtualenv_no_global(): - # type: () -> bool - """Returns a boolean, whether running in venv with no system site-packages. - """ - # PEP 405 compliance needs to be checked first since virtualenv >=20 would - # return True for both checks, but is only able to use the PEP 405 config. - if _running_under_venv(): - return _no_global_under_venv() - - if _running_under_regular_virtualenv(): - return _no_global_under_regular_virtualenv() - - return False diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/wheel.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/wheel.py deleted file mode 100644 index 3ebb771..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/utils/wheel.py +++ /dev/null @@ -1,225 +0,0 @@ -"""Support functions for working with wheel files. -""" - -from __future__ import absolute_import - -import logging -from email.parser import Parser -from zipfile import ZipFile - -from pip._vendor.packaging.utils import canonicalize_name -from pip._vendor.pkg_resources import DistInfoDistribution -from pip._vendor.six import PY2, ensure_str - -from pip._internal.exceptions import UnsupportedWheel -from pip._internal.utils.pkg_resources import DictMetadata -from pip._internal.utils.typing import MYPY_CHECK_RUNNING - -if MYPY_CHECK_RUNNING: - from email.message import Message - from typing import Dict, Tuple - - from pip._vendor.pkg_resources import Distribution - -if PY2: - from zipfile import BadZipfile as BadZipFile -else: - from zipfile import BadZipFile - - -VERSION_COMPATIBLE = (1, 0) - - -logger = logging.getLogger(__name__) - - -class WheelMetadata(DictMetadata): - """Metadata provider that maps metadata decoding exceptions to our - internal exception type. - """ - def __init__(self, metadata, wheel_name): - # type: (Dict[str, bytes], str) -> None - super(WheelMetadata, self).__init__(metadata) - self._wheel_name = wheel_name - - def get_metadata(self, name): - # type: (str) -> str - try: - return super(WheelMetadata, self).get_metadata(name) - except UnicodeDecodeError as e: - # Augment the default error with the origin of the file. - raise UnsupportedWheel( - "Error decoding metadata for {}: {}".format( - self._wheel_name, e - ) - ) - - -def pkg_resources_distribution_for_wheel(wheel_zip, name, location): - # type: (ZipFile, str, str) -> Distribution - """Get a pkg_resources distribution given a wheel. - - :raises UnsupportedWheel: on any errors - """ - info_dir, _ = parse_wheel(wheel_zip, name) - - metadata_files = [ - p for p in wheel_zip.namelist() if p.startswith("{}/".format(info_dir)) - ] - - metadata_text = {} # type: Dict[str, bytes] - for path in metadata_files: - # If a flag is set, namelist entries may be unicode in Python 2. - # We coerce them to native str type to match the types used in the rest - # of the code. This cannot fail because unicode can always be encoded - # with UTF-8. - full_path = ensure_str(path) - _, metadata_name = full_path.split("/", 1) - - try: - metadata_text[metadata_name] = read_wheel_metadata_file( - wheel_zip, full_path - ) - except UnsupportedWheel as e: - raise UnsupportedWheel( - "{} has an invalid wheel, {}".format(name, str(e)) - ) - - metadata = WheelMetadata(metadata_text, location) - - return DistInfoDistribution( - location=location, metadata=metadata, project_name=name - ) - - -def parse_wheel(wheel_zip, name): - # type: (ZipFile, str) -> Tuple[str, Message] - """Extract information from the provided wheel, ensuring it meets basic - standards. - - Returns the name of the .dist-info directory and the parsed WHEEL metadata. - """ - try: - info_dir = wheel_dist_info_dir(wheel_zip, name) - metadata = wheel_metadata(wheel_zip, info_dir) - version = wheel_version(metadata) - except UnsupportedWheel as e: - raise UnsupportedWheel( - "{} has an invalid wheel, {}".format(name, str(e)) - ) - - check_compatibility(version, name) - - return info_dir, metadata - - -def wheel_dist_info_dir(source, name): - # type: (ZipFile, str) -> str - """Returns the name of the contained .dist-info directory. - - Raises AssertionError or UnsupportedWheel if not found, >1 found, or - it doesn't match the provided name. - """ - # Zip file path separators must be / - subdirs = list(set(p.split("/")[0] for p in source.namelist())) - - info_dirs = [s for s in subdirs if s.endswith('.dist-info')] - - if not info_dirs: - raise UnsupportedWheel(".dist-info directory not found") - - if len(info_dirs) > 1: - raise UnsupportedWheel( - "multiple .dist-info directories found: {}".format( - ", ".join(info_dirs) - ) - ) - - info_dir = info_dirs[0] - - info_dir_name = canonicalize_name(info_dir) - canonical_name = canonicalize_name(name) - if not info_dir_name.startswith(canonical_name): - raise UnsupportedWheel( - ".dist-info directory {!r} does not start with {!r}".format( - info_dir, canonical_name - ) - ) - - # Zip file paths can be unicode or str depending on the zip entry flags, - # so normalize it. - return ensure_str(info_dir) - - -def read_wheel_metadata_file(source, path): - # type: (ZipFile, str) -> bytes - try: - return source.read(path) - # BadZipFile for general corruption, KeyError for missing entry, - # and RuntimeError for password-protected files - except (BadZipFile, KeyError, RuntimeError) as e: - raise UnsupportedWheel( - "could not read {!r} file: {!r}".format(path, e) - ) - - -def wheel_metadata(source, dist_info_dir): - # type: (ZipFile, str) -> Message - """Return the WHEEL metadata of an extracted wheel, if possible. - Otherwise, raise UnsupportedWheel. - """ - path = "{}/WHEEL".format(dist_info_dir) - # Zip file path separators must be / - wheel_contents = read_wheel_metadata_file(source, path) - - try: - wheel_text = ensure_str(wheel_contents) - except UnicodeDecodeError as e: - raise UnsupportedWheel("error decoding {!r}: {!r}".format(path, e)) - - # FeedParser (used by Parser) does not raise any exceptions. The returned - # message may have .defects populated, but for backwards-compatibility we - # currently ignore them. - return Parser().parsestr(wheel_text) - - -def wheel_version(wheel_data): - # type: (Message) -> Tuple[int, ...] - """Given WHEEL metadata, return the parsed Wheel-Version. - Otherwise, raise UnsupportedWheel. - """ - version_text = wheel_data["Wheel-Version"] - if version_text is None: - raise UnsupportedWheel("WHEEL is missing Wheel-Version") - - version = version_text.strip() - - try: - return tuple(map(int, version.split('.'))) - except ValueError: - raise UnsupportedWheel("invalid Wheel-Version: {!r}".format(version)) - - -def check_compatibility(version, name): - # type: (Tuple[int, ...], str) -> None - """Raises errors or warns if called with an incompatible Wheel-Version. - - pip should refuse to install a Wheel-Version that's a major series - ahead of what it's compatible with (e.g 2.0 > 1.1); and warn when - installing a version only minor version ahead (e.g 1.2 > 1.1). - - version: a 2-tuple representing a Wheel-Version (Major, Minor) - name: name of wheel or package to raise exception about - - :raises UnsupportedWheel: when an incompatible Wheel-Version is given - """ - if version[0] > VERSION_COMPATIBLE[0]: - raise UnsupportedWheel( - "{}'s Wheel-Version ({}) is not compatible with this version " - "of pip".format(name, '.'.join(map(str, version))) - ) - elif version > VERSION_COMPATIBLE: - logger.warning( - 'Installing from a newer Wheel-Version (%s)', - '.'.join(map(str, version)), - ) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/vcs/__init__.py b/venv/lib/python3.8/site-packages/pip/_internal/vcs/__init__.py deleted file mode 100644 index 2a4eb13..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/vcs/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -# Expose a limited set of classes and functions so callers outside of -# the vcs package don't need to import deeper than `pip._internal.vcs`. -# (The test directory and imports protected by MYPY_CHECK_RUNNING may -# still need to import from a vcs sub-package.) -# Import all vcs modules to register each VCS in the VcsSupport object. -import pip._internal.vcs.bazaar -import pip._internal.vcs.git -import pip._internal.vcs.mercurial -import pip._internal.vcs.subversion # noqa: F401 -from pip._internal.vcs.versioncontrol import ( # noqa: F401 - RemoteNotFoundError, - is_url, - make_vcs_requirement_url, - vcs, -) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/vcs/bazaar.py b/venv/lib/python3.8/site-packages/pip/_internal/vcs/bazaar.py deleted file mode 100644 index 347c06f..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/vcs/bazaar.py +++ /dev/null @@ -1,120 +0,0 @@ -# The following comment should be removed at some point in the future. -# mypy: disallow-untyped-defs=False - -from __future__ import absolute_import - -import logging -import os - -from pip._vendor.six.moves.urllib import parse as urllib_parse - -from pip._internal.utils.misc import display_path, rmtree -from pip._internal.utils.subprocess import make_command -from pip._internal.utils.typing import MYPY_CHECK_RUNNING -from pip._internal.utils.urls import path_to_url -from pip._internal.vcs.versioncontrol import VersionControl, vcs - -if MYPY_CHECK_RUNNING: - from typing import Optional, Tuple - from pip._internal.utils.misc import HiddenText - from pip._internal.vcs.versioncontrol import AuthInfo, RevOptions - - -logger = logging.getLogger(__name__) - - -class Bazaar(VersionControl): - name = 'bzr' - dirname = '.bzr' - repo_name = 'branch' - schemes = ( - 'bzr', 'bzr+http', 'bzr+https', 'bzr+ssh', 'bzr+sftp', 'bzr+ftp', - 'bzr+lp', - ) - - def __init__(self, *args, **kwargs): - super(Bazaar, self).__init__(*args, **kwargs) - # This is only needed for python <2.7.5 - # Register lp but do not expose as a scheme to support bzr+lp. - if getattr(urllib_parse, 'uses_fragment', None): - urllib_parse.uses_fragment.extend(['lp']) - - @staticmethod - def get_base_rev_args(rev): - return ['-r', rev] - - def export(self, location, url): - # type: (str, HiddenText) -> None - """ - Export the Bazaar repository at the url to the destination location - """ - # Remove the location to make sure Bazaar can export it correctly - if os.path.exists(location): - rmtree(location) - - url, rev_options = self.get_url_rev_options(url) - self.run_command( - make_command('export', location, url, rev_options.to_args()), - show_stdout=False, - ) - - def fetch_new(self, dest, url, rev_options): - # type: (str, HiddenText, RevOptions) -> None - rev_display = rev_options.to_display() - logger.info( - 'Checking out %s%s to %s', - url, - rev_display, - display_path(dest), - ) - cmd_args = ( - make_command('branch', '-q', rev_options.to_args(), url, dest) - ) - self.run_command(cmd_args) - - def switch(self, dest, url, rev_options): - # type: (str, HiddenText, RevOptions) -> None - self.run_command(make_command('switch', url), cwd=dest) - - def update(self, dest, url, rev_options): - # type: (str, HiddenText, RevOptions) -> None - cmd_args = make_command('pull', '-q', rev_options.to_args()) - self.run_command(cmd_args, cwd=dest) - - @classmethod - def get_url_rev_and_auth(cls, url): - # type: (str) -> Tuple[str, Optional[str], AuthInfo] - # hotfix the URL scheme after removing bzr+ from bzr+ssh:// readd it - url, rev, user_pass = super(Bazaar, cls).get_url_rev_and_auth(url) - if url.startswith('ssh://'): - url = 'bzr+' + url - return url, rev, user_pass - - @classmethod - def get_remote_url(cls, location): - urls = cls.run_command(['info'], show_stdout=False, cwd=location) - for line in urls.splitlines(): - line = line.strip() - for x in ('checkout of branch: ', - 'parent branch: '): - if line.startswith(x): - repo = line.split(x)[1] - if cls._is_local_repository(repo): - return path_to_url(repo) - return repo - return None - - @classmethod - def get_revision(cls, location): - revision = cls.run_command( - ['revno'], show_stdout=False, cwd=location, - ) - return revision.splitlines()[-1] - - @classmethod - def is_commit_id_equal(cls, dest, name): - """Always assume the versions don't match""" - return False - - -vcs.register(Bazaar) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/vcs/git.py b/venv/lib/python3.8/site-packages/pip/_internal/vcs/git.py deleted file mode 100644 index e173ec8..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/vcs/git.py +++ /dev/null @@ -1,394 +0,0 @@ -# The following comment should be removed at some point in the future. -# mypy: disallow-untyped-defs=False - -from __future__ import absolute_import - -import logging -import os.path -import re - -from pip._vendor.packaging.version import parse as parse_version -from pip._vendor.six.moves.urllib import parse as urllib_parse -from pip._vendor.six.moves.urllib import request as urllib_request - -from pip._internal.exceptions import BadCommand, InstallationError -from pip._internal.utils.misc import display_path, hide_url -from pip._internal.utils.subprocess import make_command -from pip._internal.utils.temp_dir import TempDirectory -from pip._internal.utils.typing import MYPY_CHECK_RUNNING -from pip._internal.vcs.versioncontrol import ( - RemoteNotFoundError, - VersionControl, - find_path_to_setup_from_repo_root, - vcs, -) - -if MYPY_CHECK_RUNNING: - from typing import Optional, Tuple - from pip._internal.utils.misc import HiddenText - from pip._internal.vcs.versioncontrol import AuthInfo, RevOptions - - -urlsplit = urllib_parse.urlsplit -urlunsplit = urllib_parse.urlunsplit - - -logger = logging.getLogger(__name__) - - -HASH_REGEX = re.compile('^[a-fA-F0-9]{40}$') - - -def looks_like_hash(sha): - return bool(HASH_REGEX.match(sha)) - - -class Git(VersionControl): - name = 'git' - dirname = '.git' - repo_name = 'clone' - schemes = ( - 'git', 'git+http', 'git+https', 'git+ssh', 'git+git', 'git+file', - ) - # Prevent the user's environment variables from interfering with pip: - # https://github.com/pypa/pip/issues/1130 - unset_environ = ('GIT_DIR', 'GIT_WORK_TREE') - default_arg_rev = 'HEAD' - - @staticmethod - def get_base_rev_args(rev): - return [rev] - - def is_immutable_rev_checkout(self, url, dest): - # type: (str, str) -> bool - _, rev_options = self.get_url_rev_options(hide_url(url)) - if not rev_options.rev: - return False - if not self.is_commit_id_equal(dest, rev_options.rev): - # the current commit is different from rev, - # which means rev was something else than a commit hash - return False - # return False in the rare case rev is both a commit hash - # and a tag or a branch; we don't want to cache in that case - # because that branch/tag could point to something else in the future - is_tag_or_branch = bool( - self.get_revision_sha(dest, rev_options.rev)[0] - ) - return not is_tag_or_branch - - def get_git_version(self): - VERSION_PFX = 'git version ' - version = self.run_command(['version'], show_stdout=False) - if version.startswith(VERSION_PFX): - version = version[len(VERSION_PFX):].split()[0] - else: - version = '' - # get first 3 positions of the git version because - # on windows it is x.y.z.windows.t, and this parses as - # LegacyVersion which always smaller than a Version. - version = '.'.join(version.split('.')[:3]) - return parse_version(version) - - @classmethod - def get_current_branch(cls, location): - """ - Return the current branch, or None if HEAD isn't at a branch - (e.g. detached HEAD). - """ - # git-symbolic-ref exits with empty stdout if "HEAD" is a detached - # HEAD rather than a symbolic ref. In addition, the -q causes the - # command to exit with status code 1 instead of 128 in this case - # and to suppress the message to stderr. - args = ['symbolic-ref', '-q', 'HEAD'] - output = cls.run_command( - args, extra_ok_returncodes=(1, ), show_stdout=False, cwd=location, - ) - ref = output.strip() - - if ref.startswith('refs/heads/'): - return ref[len('refs/heads/'):] - - return None - - def export(self, location, url): - # type: (str, HiddenText) -> None - """Export the Git repository at the url to the destination location""" - if not location.endswith('/'): - location = location + '/' - - with TempDirectory(kind="export") as temp_dir: - self.unpack(temp_dir.path, url=url) - self.run_command( - ['checkout-index', '-a', '-f', '--prefix', location], - show_stdout=False, cwd=temp_dir.path - ) - - @classmethod - def get_revision_sha(cls, dest, rev): - """ - Return (sha_or_none, is_branch), where sha_or_none is a commit hash - if the revision names a remote branch or tag, otherwise None. - - Args: - dest: the repository directory. - rev: the revision name. - """ - # Pass rev to pre-filter the list. - output = cls.run_command(['show-ref', rev], cwd=dest, - show_stdout=False, on_returncode='ignore') - refs = {} - for line in output.strip().splitlines(): - try: - sha, ref = line.split() - except ValueError: - # Include the offending line to simplify troubleshooting if - # this error ever occurs. - raise ValueError('unexpected show-ref line: {!r}'.format(line)) - - refs[ref] = sha - - branch_ref = 'refs/remotes/origin/{}'.format(rev) - tag_ref = 'refs/tags/{}'.format(rev) - - sha = refs.get(branch_ref) - if sha is not None: - return (sha, True) - - sha = refs.get(tag_ref) - - return (sha, False) - - @classmethod - def resolve_revision(cls, dest, url, rev_options): - # type: (str, HiddenText, RevOptions) -> RevOptions - """ - Resolve a revision to a new RevOptions object with the SHA1 of the - branch, tag, or ref if found. - - Args: - rev_options: a RevOptions object. - """ - rev = rev_options.arg_rev - # The arg_rev property's implementation for Git ensures that the - # rev return value is always non-None. - assert rev is not None - - sha, is_branch = cls.get_revision_sha(dest, rev) - - if sha is not None: - rev_options = rev_options.make_new(sha) - rev_options.branch_name = rev if is_branch else None - - return rev_options - - # Do not show a warning for the common case of something that has - # the form of a Git commit hash. - if not looks_like_hash(rev): - logger.warning( - "Did not find branch or tag '%s', assuming revision or ref.", - rev, - ) - - if not rev.startswith('refs/'): - return rev_options - - # If it looks like a ref, we have to fetch it explicitly. - cls.run_command( - make_command('fetch', '-q', url, rev_options.to_args()), - cwd=dest, - ) - # Change the revision to the SHA of the ref we fetched - sha = cls.get_revision(dest, rev='FETCH_HEAD') - rev_options = rev_options.make_new(sha) - - return rev_options - - @classmethod - def is_commit_id_equal(cls, dest, name): - """ - Return whether the current commit hash equals the given name. - - Args: - dest: the repository directory. - name: a string name. - """ - if not name: - # Then avoid an unnecessary subprocess call. - return False - - return cls.get_revision(dest) == name - - def fetch_new(self, dest, url, rev_options): - # type: (str, HiddenText, RevOptions) -> None - rev_display = rev_options.to_display() - logger.info('Cloning %s%s to %s', url, rev_display, display_path(dest)) - self.run_command(make_command('clone', '-q', url, dest)) - - if rev_options.rev: - # Then a specific revision was requested. - rev_options = self.resolve_revision(dest, url, rev_options) - branch_name = getattr(rev_options, 'branch_name', None) - if branch_name is None: - # Only do a checkout if the current commit id doesn't match - # the requested revision. - if not self.is_commit_id_equal(dest, rev_options.rev): - cmd_args = make_command( - 'checkout', '-q', rev_options.to_args(), - ) - self.run_command(cmd_args, cwd=dest) - elif self.get_current_branch(dest) != branch_name: - # Then a specific branch was requested, and that branch - # is not yet checked out. - track_branch = 'origin/{}'.format(branch_name) - cmd_args = [ - 'checkout', '-b', branch_name, '--track', track_branch, - ] - self.run_command(cmd_args, cwd=dest) - - #: repo may contain submodules - self.update_submodules(dest) - - def switch(self, dest, url, rev_options): - # type: (str, HiddenText, RevOptions) -> None - self.run_command( - make_command('config', 'remote.origin.url', url), - cwd=dest, - ) - cmd_args = make_command('checkout', '-q', rev_options.to_args()) - self.run_command(cmd_args, cwd=dest) - - self.update_submodules(dest) - - def update(self, dest, url, rev_options): - # type: (str, HiddenText, RevOptions) -> None - # First fetch changes from the default remote - if self.get_git_version() >= parse_version('1.9.0'): - # fetch tags in addition to everything else - self.run_command(['fetch', '-q', '--tags'], cwd=dest) - else: - self.run_command(['fetch', '-q'], cwd=dest) - # Then reset to wanted revision (maybe even origin/master) - rev_options = self.resolve_revision(dest, url, rev_options) - cmd_args = make_command('reset', '--hard', '-q', rev_options.to_args()) - self.run_command(cmd_args, cwd=dest) - #: update submodules - self.update_submodules(dest) - - @classmethod - def get_remote_url(cls, location): - """ - Return URL of the first remote encountered. - - Raises RemoteNotFoundError if the repository does not have a remote - url configured. - """ - # We need to pass 1 for extra_ok_returncodes since the command - # exits with return code 1 if there are no matching lines. - stdout = cls.run_command( - ['config', '--get-regexp', r'remote\..*\.url'], - extra_ok_returncodes=(1, ), show_stdout=False, cwd=location, - ) - remotes = stdout.splitlines() - try: - found_remote = remotes[0] - except IndexError: - raise RemoteNotFoundError - - for remote in remotes: - if remote.startswith('remote.origin.url '): - found_remote = remote - break - url = found_remote.split(' ')[1] - return url.strip() - - @classmethod - def get_revision(cls, location, rev=None): - if rev is None: - rev = 'HEAD' - current_rev = cls.run_command( - ['rev-parse', rev], show_stdout=False, cwd=location, - ) - return current_rev.strip() - - @classmethod - def get_subdirectory(cls, location): - """ - Return the path to setup.py, relative to the repo root. - Return None if setup.py is in the repo root. - """ - # find the repo root - git_dir = cls.run_command( - ['rev-parse', '--git-dir'], - show_stdout=False, cwd=location).strip() - if not os.path.isabs(git_dir): - git_dir = os.path.join(location, git_dir) - repo_root = os.path.abspath(os.path.join(git_dir, '..')) - return find_path_to_setup_from_repo_root(location, repo_root) - - @classmethod - def get_url_rev_and_auth(cls, url): - # type: (str) -> Tuple[str, Optional[str], AuthInfo] - """ - Prefixes stub URLs like 'user@hostname:user/repo.git' with 'ssh://'. - That's required because although they use SSH they sometimes don't - work with a ssh:// scheme (e.g. GitHub). But we need a scheme for - parsing. Hence we remove it again afterwards and return it as a stub. - """ - # Works around an apparent Git bug - # (see https://article.gmane.org/gmane.comp.version-control.git/146500) - scheme, netloc, path, query, fragment = urlsplit(url) - if scheme.endswith('file'): - initial_slashes = path[:-len(path.lstrip('/'))] - newpath = ( - initial_slashes + - urllib_request.url2pathname(path) - .replace('\\', '/').lstrip('/') - ) - url = urlunsplit((scheme, netloc, newpath, query, fragment)) - after_plus = scheme.find('+') + 1 - url = scheme[:after_plus] + urlunsplit( - (scheme[after_plus:], netloc, newpath, query, fragment), - ) - - if '://' not in url: - assert 'file:' not in url - url = url.replace('git+', 'git+ssh://') - url, rev, user_pass = super(Git, cls).get_url_rev_and_auth(url) - url = url.replace('ssh://', '') - else: - url, rev, user_pass = super(Git, cls).get_url_rev_and_auth(url) - - return url, rev, user_pass - - @classmethod - def update_submodules(cls, location): - if not os.path.exists(os.path.join(location, '.gitmodules')): - return - cls.run_command( - ['submodule', 'update', '--init', '--recursive', '-q'], - cwd=location, - ) - - @classmethod - def get_repository_root(cls, location): - loc = super(Git, cls).get_repository_root(location) - if loc: - return loc - try: - r = cls.run_command( - ['rev-parse', '--show-toplevel'], - cwd=location, - show_stdout=False, - on_returncode='raise', - log_failed_cmd=False, - ) - except BadCommand: - logger.debug("could not determine if %s is under git control " - "because git is not available", location) - return None - except InstallationError: - return None - return os.path.normpath(r.rstrip('\r\n')) - - -vcs.register(Git) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/vcs/mercurial.py b/venv/lib/python3.8/site-packages/pip/_internal/vcs/mercurial.py deleted file mode 100644 index 75e903c..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/vcs/mercurial.py +++ /dev/null @@ -1,161 +0,0 @@ -# The following comment should be removed at some point in the future. -# mypy: disallow-untyped-defs=False - -from __future__ import absolute_import - -import logging -import os - -from pip._vendor.six.moves import configparser - -from pip._internal.exceptions import BadCommand, InstallationError -from pip._internal.utils.misc import display_path -from pip._internal.utils.subprocess import make_command -from pip._internal.utils.temp_dir import TempDirectory -from pip._internal.utils.typing import MYPY_CHECK_RUNNING -from pip._internal.utils.urls import path_to_url -from pip._internal.vcs.versioncontrol import ( - VersionControl, - find_path_to_setup_from_repo_root, - vcs, -) - -if MYPY_CHECK_RUNNING: - from pip._internal.utils.misc import HiddenText - from pip._internal.vcs.versioncontrol import RevOptions - - -logger = logging.getLogger(__name__) - - -class Mercurial(VersionControl): - name = 'hg' - dirname = '.hg' - repo_name = 'clone' - schemes = ( - 'hg', 'hg+file', 'hg+http', 'hg+https', 'hg+ssh', 'hg+static-http', - ) - - @staticmethod - def get_base_rev_args(rev): - return [rev] - - def export(self, location, url): - # type: (str, HiddenText) -> None - """Export the Hg repository at the url to the destination location""" - with TempDirectory(kind="export") as temp_dir: - self.unpack(temp_dir.path, url=url) - - self.run_command( - ['archive', location], show_stdout=False, cwd=temp_dir.path - ) - - def fetch_new(self, dest, url, rev_options): - # type: (str, HiddenText, RevOptions) -> None - rev_display = rev_options.to_display() - logger.info( - 'Cloning hg %s%s to %s', - url, - rev_display, - display_path(dest), - ) - self.run_command(make_command('clone', '--noupdate', '-q', url, dest)) - self.run_command( - make_command('update', '-q', rev_options.to_args()), - cwd=dest, - ) - - def switch(self, dest, url, rev_options): - # type: (str, HiddenText, RevOptions) -> None - repo_config = os.path.join(dest, self.dirname, 'hgrc') - config = configparser.RawConfigParser() - try: - config.read(repo_config) - config.set('paths', 'default', url.secret) - with open(repo_config, 'w') as config_file: - config.write(config_file) - except (OSError, configparser.NoSectionError) as exc: - logger.warning( - 'Could not switch Mercurial repository to %s: %s', url, exc, - ) - else: - cmd_args = make_command('update', '-q', rev_options.to_args()) - self.run_command(cmd_args, cwd=dest) - - def update(self, dest, url, rev_options): - # type: (str, HiddenText, RevOptions) -> None - self.run_command(['pull', '-q'], cwd=dest) - cmd_args = make_command('update', '-q', rev_options.to_args()) - self.run_command(cmd_args, cwd=dest) - - @classmethod - def get_remote_url(cls, location): - url = cls.run_command( - ['showconfig', 'paths.default'], - show_stdout=False, cwd=location).strip() - if cls._is_local_repository(url): - url = path_to_url(url) - return url.strip() - - @classmethod - def get_revision(cls, location): - """ - Return the repository-local changeset revision number, as an integer. - """ - current_revision = cls.run_command( - ['parents', '--template={rev}'], - show_stdout=False, cwd=location).strip() - return current_revision - - @classmethod - def get_requirement_revision(cls, location): - """ - Return the changeset identification hash, as a 40-character - hexadecimal string - """ - current_rev_hash = cls.run_command( - ['parents', '--template={node}'], - show_stdout=False, cwd=location).strip() - return current_rev_hash - - @classmethod - def is_commit_id_equal(cls, dest, name): - """Always assume the versions don't match""" - return False - - @classmethod - def get_subdirectory(cls, location): - """ - Return the path to setup.py, relative to the repo root. - Return None if setup.py is in the repo root. - """ - # find the repo root - repo_root = cls.run_command( - ['root'], show_stdout=False, cwd=location).strip() - if not os.path.isabs(repo_root): - repo_root = os.path.abspath(os.path.join(location, repo_root)) - return find_path_to_setup_from_repo_root(location, repo_root) - - @classmethod - def get_repository_root(cls, location): - loc = super(Mercurial, cls).get_repository_root(location) - if loc: - return loc - try: - r = cls.run_command( - ['root'], - cwd=location, - show_stdout=False, - on_returncode='raise', - log_failed_cmd=False, - ) - except BadCommand: - logger.debug("could not determine if %s is under hg control " - "because hg is not available", location) - return None - except InstallationError: - return None - return os.path.normpath(r.rstrip('\r\n')) - - -vcs.register(Mercurial) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/vcs/subversion.py b/venv/lib/python3.8/site-packages/pip/_internal/vcs/subversion.py deleted file mode 100644 index 0ec6597..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/vcs/subversion.py +++ /dev/null @@ -1,334 +0,0 @@ -# The following comment should be removed at some point in the future. -# mypy: disallow-untyped-defs=False - -from __future__ import absolute_import - -import logging -import os -import re - -from pip._internal.utils.logging import indent_log -from pip._internal.utils.misc import ( - display_path, - is_console_interactive, - rmtree, - split_auth_from_netloc, -) -from pip._internal.utils.subprocess import make_command -from pip._internal.utils.typing import MYPY_CHECK_RUNNING -from pip._internal.vcs.versioncontrol import VersionControl, vcs - -_svn_xml_url_re = re.compile('url="([^"]+)"') -_svn_rev_re = re.compile(r'committed-rev="(\d+)"') -_svn_info_xml_rev_re = re.compile(r'\s*revision="(\d+)"') -_svn_info_xml_url_re = re.compile(r'<url>(.*)</url>') - - -if MYPY_CHECK_RUNNING: - from typing import Optional, Tuple - from pip._internal.utils.subprocess import CommandArgs - from pip._internal.utils.misc import HiddenText - from pip._internal.vcs.versioncontrol import AuthInfo, RevOptions - - -logger = logging.getLogger(__name__) - - -class Subversion(VersionControl): - name = 'svn' - dirname = '.svn' - repo_name = 'checkout' - schemes = ('svn', 'svn+ssh', 'svn+http', 'svn+https', 'svn+svn') - - @classmethod - def should_add_vcs_url_prefix(cls, remote_url): - return True - - @staticmethod - def get_base_rev_args(rev): - return ['-r', rev] - - @classmethod - def get_revision(cls, location): - """ - Return the maximum revision for all files under a given location - """ - # Note: taken from setuptools.command.egg_info - revision = 0 - - for base, dirs, files in os.walk(location): - if cls.dirname not in dirs: - dirs[:] = [] - continue # no sense walking uncontrolled subdirs - dirs.remove(cls.dirname) - entries_fn = os.path.join(base, cls.dirname, 'entries') - if not os.path.exists(entries_fn): - # FIXME: should we warn? - continue - - dirurl, localrev = cls._get_svn_url_rev(base) - - if base == location: - base = dirurl + '/' # save the root url - elif not dirurl or not dirurl.startswith(base): - dirs[:] = [] - continue # not part of the same svn tree, skip it - revision = max(revision, localrev) - return revision - - @classmethod - def get_netloc_and_auth(cls, netloc, scheme): - """ - This override allows the auth information to be passed to svn via the - --username and --password options instead of via the URL. - """ - if scheme == 'ssh': - # The --username and --password options can't be used for - # svn+ssh URLs, so keep the auth information in the URL. - return super(Subversion, cls).get_netloc_and_auth(netloc, scheme) - - return split_auth_from_netloc(netloc) - - @classmethod - def get_url_rev_and_auth(cls, url): - # type: (str) -> Tuple[str, Optional[str], AuthInfo] - # hotfix the URL scheme after removing svn+ from svn+ssh:// readd it - url, rev, user_pass = super(Subversion, cls).get_url_rev_and_auth(url) - if url.startswith('ssh://'): - url = 'svn+' + url - return url, rev, user_pass - - @staticmethod - def make_rev_args(username, password): - # type: (Optional[str], Optional[HiddenText]) -> CommandArgs - extra_args = [] # type: CommandArgs - if username: - extra_args += ['--username', username] - if password: - extra_args += ['--password', password] - - return extra_args - - @classmethod - def get_remote_url(cls, location): - # In cases where the source is in a subdirectory, not alongside - # setup.py we have to look up in the location until we find a real - # setup.py - orig_location = location - while not os.path.exists(os.path.join(location, 'setup.py')): - last_location = location - location = os.path.dirname(location) - if location == last_location: - # We've traversed up to the root of the filesystem without - # finding setup.py - logger.warning( - "Could not find setup.py for directory %s (tried all " - "parent directories)", - orig_location, - ) - return None - - return cls._get_svn_url_rev(location)[0] - - @classmethod - def _get_svn_url_rev(cls, location): - from pip._internal.exceptions import InstallationError - - entries_path = os.path.join(location, cls.dirname, 'entries') - if os.path.exists(entries_path): - with open(entries_path) as f: - data = f.read() - else: # subversion >= 1.7 does not have the 'entries' file - data = '' - - if (data.startswith('8') or - data.startswith('9') or - data.startswith('10')): - data = list(map(str.splitlines, data.split('\n\x0c\n'))) - del data[0][0] # get rid of the '8' - url = data[0][3] - revs = [int(d[9]) for d in data if len(d) > 9 and d[9]] + [0] - elif data.startswith('<?xml'): - match = _svn_xml_url_re.search(data) - if not match: - raise ValueError( - 'Badly formatted data: {data!r}'.format(**locals())) - url = match.group(1) # get repository URL - revs = [int(m.group(1)) for m in _svn_rev_re.finditer(data)] + [0] - else: - try: - # subversion >= 1.7 - # Note that using get_remote_call_options is not necessary here - # because `svn info` is being run against a local directory. - # We don't need to worry about making sure interactive mode - # is being used to prompt for passwords, because passwords - # are only potentially needed for remote server requests. - xml = cls.run_command( - ['info', '--xml', location], - show_stdout=False, - ) - url = _svn_info_xml_url_re.search(xml).group(1) - revs = [ - int(m.group(1)) for m in _svn_info_xml_rev_re.finditer(xml) - ] - except InstallationError: - url, revs = None, [] - - if revs: - rev = max(revs) - else: - rev = 0 - - return url, rev - - @classmethod - def is_commit_id_equal(cls, dest, name): - """Always assume the versions don't match""" - return False - - def __init__(self, use_interactive=None): - # type: (bool) -> None - if use_interactive is None: - use_interactive = is_console_interactive() - self.use_interactive = use_interactive - - # This member is used to cache the fetched version of the current - # ``svn`` client. - # Special value definitions: - # None: Not evaluated yet. - # Empty tuple: Could not parse version. - self._vcs_version = None # type: Optional[Tuple[int, ...]] - - super(Subversion, self).__init__() - - def call_vcs_version(self): - # type: () -> Tuple[int, ...] - """Query the version of the currently installed Subversion client. - - :return: A tuple containing the parts of the version information or - ``()`` if the version returned from ``svn`` could not be parsed. - :raises: BadCommand: If ``svn`` is not installed. - """ - # Example versions: - # svn, version 1.10.3 (r1842928) - # compiled Feb 25 2019, 14:20:39 on x86_64-apple-darwin17.0.0 - # svn, version 1.7.14 (r1542130) - # compiled Mar 28 2018, 08:49:13 on x86_64-pc-linux-gnu - version_prefix = 'svn, version ' - version = self.run_command(['--version'], show_stdout=False) - if not version.startswith(version_prefix): - return () - - version = version[len(version_prefix):].split()[0] - version_list = version.split('.') - try: - parsed_version = tuple(map(int, version_list)) - except ValueError: - return () - - return parsed_version - - def get_vcs_version(self): - # type: () -> Tuple[int, ...] - """Return the version of the currently installed Subversion client. - - If the version of the Subversion client has already been queried, - a cached value will be used. - - :return: A tuple containing the parts of the version information or - ``()`` if the version returned from ``svn`` could not be parsed. - :raises: BadCommand: If ``svn`` is not installed. - """ - if self._vcs_version is not None: - # Use cached version, if available. - # If parsing the version failed previously (empty tuple), - # do not attempt to parse it again. - return self._vcs_version - - vcs_version = self.call_vcs_version() - self._vcs_version = vcs_version - return vcs_version - - def get_remote_call_options(self): - # type: () -> CommandArgs - """Return options to be used on calls to Subversion that contact the server. - - These options are applicable for the following ``svn`` subcommands used - in this class. - - - checkout - - export - - switch - - update - - :return: A list of command line arguments to pass to ``svn``. - """ - if not self.use_interactive: - # --non-interactive switch is available since Subversion 0.14.4. - # Subversion < 1.8 runs in interactive mode by default. - return ['--non-interactive'] - - svn_version = self.get_vcs_version() - # By default, Subversion >= 1.8 runs in non-interactive mode if - # stdin is not a TTY. Since that is how pip invokes SVN, in - # call_subprocess(), pip must pass --force-interactive to ensure - # the user can be prompted for a password, if required. - # SVN added the --force-interactive option in SVN 1.8. Since - # e.g. RHEL/CentOS 7, which is supported until 2024, ships with - # SVN 1.7, pip should continue to support SVN 1.7. Therefore, pip - # can't safely add the option if the SVN version is < 1.8 (or unknown). - if svn_version >= (1, 8): - return ['--force-interactive'] - - return [] - - def export(self, location, url): - # type: (str, HiddenText) -> None - """Export the svn repository at the url to the destination location""" - url, rev_options = self.get_url_rev_options(url) - - logger.info('Exporting svn repository %s to %s', url, location) - with indent_log(): - if os.path.exists(location): - # Subversion doesn't like to check out over an existing - # directory --force fixes this, but was only added in svn 1.5 - rmtree(location) - cmd_args = make_command( - 'export', self.get_remote_call_options(), - rev_options.to_args(), url, location, - ) - self.run_command(cmd_args, show_stdout=False) - - def fetch_new(self, dest, url, rev_options): - # type: (str, HiddenText, RevOptions) -> None - rev_display = rev_options.to_display() - logger.info( - 'Checking out %s%s to %s', - url, - rev_display, - display_path(dest), - ) - cmd_args = make_command( - 'checkout', '-q', self.get_remote_call_options(), - rev_options.to_args(), url, dest, - ) - self.run_command(cmd_args) - - def switch(self, dest, url, rev_options): - # type: (str, HiddenText, RevOptions) -> None - cmd_args = make_command( - 'switch', self.get_remote_call_options(), rev_options.to_args(), - url, dest, - ) - self.run_command(cmd_args) - - def update(self, dest, url, rev_options): - # type: (str, HiddenText, RevOptions) -> None - cmd_args = make_command( - 'update', self.get_remote_call_options(), rev_options.to_args(), - dest, - ) - self.run_command(cmd_args) - - -vcs.register(Subversion) diff --git a/venv/lib/python3.8/site-packages/pip/_internal/vcs/versioncontrol.py b/venv/lib/python3.8/site-packages/pip/_internal/vcs/versioncontrol.py deleted file mode 100644 index 71b4650..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/vcs/versioncontrol.py +++ /dev/null @@ -1,723 +0,0 @@ -"""Handles all VCS (version control) support""" - -from __future__ import absolute_import - -import errno -import logging -import os -import shutil -import sys - -from pip._vendor import pkg_resources -from pip._vendor.six.moves.urllib import parse as urllib_parse - -from pip._internal.exceptions import BadCommand, InstallationError -from pip._internal.utils.compat import samefile -from pip._internal.utils.misc import ( - ask_path_exists, - backup_dir, - display_path, - hide_url, - hide_value, - rmtree, -) -from pip._internal.utils.subprocess import call_subprocess, make_command -from pip._internal.utils.typing import MYPY_CHECK_RUNNING -from pip._internal.utils.urls import get_url_scheme - -if MYPY_CHECK_RUNNING: - from typing import ( - Any, Dict, Iterable, Iterator, List, Mapping, Optional, Text, Tuple, - Type, Union - ) - from pip._internal.cli.spinners import SpinnerInterface - from pip._internal.utils.misc import HiddenText - from pip._internal.utils.subprocess import CommandArgs - - AuthInfo = Tuple[Optional[str], Optional[str]] - - -__all__ = ['vcs'] - - -logger = logging.getLogger(__name__) - - -def is_url(name): - # type: (Union[str, Text]) -> bool - """ - Return true if the name looks like a URL. - """ - scheme = get_url_scheme(name) - if scheme is None: - return False - return scheme in ['http', 'https', 'file', 'ftp'] + vcs.all_schemes - - -def make_vcs_requirement_url(repo_url, rev, project_name, subdir=None): - # type: (str, str, str, Optional[str]) -> str - """ - Return the URL for a VCS requirement. - - Args: - repo_url: the remote VCS url, with any needed VCS prefix (e.g. "git+"). - project_name: the (unescaped) project name. - """ - egg_project_name = pkg_resources.to_filename(project_name) - req = '{}@{}#egg={}'.format(repo_url, rev, egg_project_name) - if subdir: - req += '&subdirectory={}'.format(subdir) - - return req - - -def find_path_to_setup_from_repo_root(location, repo_root): - # type: (str, str) -> Optional[str] - """ - Find the path to `setup.py` by searching up the filesystem from `location`. - Return the path to `setup.py` relative to `repo_root`. - Return None if `setup.py` is in `repo_root` or cannot be found. - """ - # find setup.py - orig_location = location - while not os.path.exists(os.path.join(location, 'setup.py')): - last_location = location - location = os.path.dirname(location) - if location == last_location: - # We've traversed up to the root of the filesystem without - # finding setup.py - logger.warning( - "Could not find setup.py for directory %s (tried all " - "parent directories)", - orig_location, - ) - return None - - if samefile(repo_root, location): - return None - - return os.path.relpath(location, repo_root) - - -class RemoteNotFoundError(Exception): - pass - - -class RevOptions(object): - - """ - Encapsulates a VCS-specific revision to install, along with any VCS - install options. - - Instances of this class should be treated as if immutable. - """ - - def __init__( - self, - vc_class, # type: Type[VersionControl] - rev=None, # type: Optional[str] - extra_args=None, # type: Optional[CommandArgs] - ): - # type: (...) -> None - """ - Args: - vc_class: a VersionControl subclass. - rev: the name of the revision to install. - extra_args: a list of extra options. - """ - if extra_args is None: - extra_args = [] - - self.extra_args = extra_args - self.rev = rev - self.vc_class = vc_class - self.branch_name = None # type: Optional[str] - - def __repr__(self): - # type: () -> str - return '<RevOptions {}: rev={!r}>'.format(self.vc_class.name, self.rev) - - @property - def arg_rev(self): - # type: () -> Optional[str] - if self.rev is None: - return self.vc_class.default_arg_rev - - return self.rev - - def to_args(self): - # type: () -> CommandArgs - """ - Return the VCS-specific command arguments. - """ - args = [] # type: CommandArgs - rev = self.arg_rev - if rev is not None: - args += self.vc_class.get_base_rev_args(rev) - args += self.extra_args - - return args - - def to_display(self): - # type: () -> str - if not self.rev: - return '' - - return ' (to revision {})'.format(self.rev) - - def make_new(self, rev): - # type: (str) -> RevOptions - """ - Make a copy of the current instance, but with a new rev. - - Args: - rev: the name of the revision for the new object. - """ - return self.vc_class.make_rev_options(rev, extra_args=self.extra_args) - - -class VcsSupport(object): - _registry = {} # type: Dict[str, VersionControl] - schemes = ['ssh', 'git', 'hg', 'bzr', 'sftp', 'svn'] - - def __init__(self): - # type: () -> None - # Register more schemes with urlparse for various version control - # systems - urllib_parse.uses_netloc.extend(self.schemes) - # Python >= 2.7.4, 3.3 doesn't have uses_fragment - if getattr(urllib_parse, 'uses_fragment', None): - urllib_parse.uses_fragment.extend(self.schemes) - super(VcsSupport, self).__init__() - - def __iter__(self): - # type: () -> Iterator[str] - return self._registry.__iter__() - - @property - def backends(self): - # type: () -> List[VersionControl] - return list(self._registry.values()) - - @property - def dirnames(self): - # type: () -> List[str] - return [backend.dirname for backend in self.backends] - - @property - def all_schemes(self): - # type: () -> List[str] - schemes = [] # type: List[str] - for backend in self.backends: - schemes.extend(backend.schemes) - return schemes - - def register(self, cls): - # type: (Type[VersionControl]) -> None - if not hasattr(cls, 'name'): - logger.warning('Cannot register VCS %s', cls.__name__) - return - if cls.name not in self._registry: - self._registry[cls.name] = cls() - logger.debug('Registered VCS backend: %s', cls.name) - - def unregister(self, name): - # type: (str) -> None - if name in self._registry: - del self._registry[name] - - def get_backend_for_dir(self, location): - # type: (str) -> Optional[VersionControl] - """ - Return a VersionControl object if a repository of that type is found - at the given directory. - """ - vcs_backends = {} - for vcs_backend in self._registry.values(): - repo_path = vcs_backend.get_repository_root(location) - if not repo_path: - continue - logger.debug('Determine that %s uses VCS: %s', - location, vcs_backend.name) - vcs_backends[repo_path] = vcs_backend - - if not vcs_backends: - return None - - # Choose the VCS in the inner-most directory. Since all repository - # roots found here would be either `location` or one of its - # parents, the longest path should have the most path components, - # i.e. the backend representing the inner-most repository. - inner_most_repo_path = max(vcs_backends, key=len) - return vcs_backends[inner_most_repo_path] - - def get_backend_for_scheme(self, scheme): - # type: (str) -> Optional[VersionControl] - """ - Return a VersionControl object or None. - """ - for vcs_backend in self._registry.values(): - if scheme in vcs_backend.schemes: - return vcs_backend - return None - - def get_backend(self, name): - # type: (str) -> Optional[VersionControl] - """ - Return a VersionControl object or None. - """ - name = name.lower() - return self._registry.get(name) - - -vcs = VcsSupport() - - -class VersionControl(object): - name = '' - dirname = '' - repo_name = '' - # List of supported schemes for this Version Control - schemes = () # type: Tuple[str, ...] - # Iterable of environment variable names to pass to call_subprocess(). - unset_environ = () # type: Tuple[str, ...] - default_arg_rev = None # type: Optional[str] - - @classmethod - def should_add_vcs_url_prefix(cls, remote_url): - # type: (str) -> bool - """ - Return whether the vcs prefix (e.g. "git+") should be added to a - repository's remote url when used in a requirement. - """ - return not remote_url.lower().startswith('{}:'.format(cls.name)) - - @classmethod - def get_subdirectory(cls, location): - # type: (str) -> Optional[str] - """ - Return the path to setup.py, relative to the repo root. - Return None if setup.py is in the repo root. - """ - return None - - @classmethod - def get_requirement_revision(cls, repo_dir): - # type: (str) -> str - """ - Return the revision string that should be used in a requirement. - """ - return cls.get_revision(repo_dir) - - @classmethod - def get_src_requirement(cls, repo_dir, project_name): - # type: (str, str) -> Optional[str] - """ - Return the requirement string to use to redownload the files - currently at the given repository directory. - - Args: - project_name: the (unescaped) project name. - - The return value has a form similar to the following: - - {repository_url}@{revision}#egg={project_name} - """ - repo_url = cls.get_remote_url(repo_dir) - if repo_url is None: - return None - - if cls.should_add_vcs_url_prefix(repo_url): - repo_url = '{}+{}'.format(cls.name, repo_url) - - revision = cls.get_requirement_revision(repo_dir) - subdir = cls.get_subdirectory(repo_dir) - req = make_vcs_requirement_url(repo_url, revision, project_name, - subdir=subdir) - - return req - - @staticmethod - def get_base_rev_args(rev): - # type: (str) -> List[str] - """ - Return the base revision arguments for a vcs command. - - Args: - rev: the name of a revision to install. Cannot be None. - """ - raise NotImplementedError - - def is_immutable_rev_checkout(self, url, dest): - # type: (str, str) -> bool - """ - Return true if the commit hash checked out at dest matches - the revision in url. - - Always return False, if the VCS does not support immutable commit - hashes. - - This method does not check if there are local uncommitted changes - in dest after checkout, as pip currently has no use case for that. - """ - return False - - @classmethod - def make_rev_options(cls, rev=None, extra_args=None): - # type: (Optional[str], Optional[CommandArgs]) -> RevOptions - """ - Return a RevOptions object. - - Args: - rev: the name of a revision to install. - extra_args: a list of extra options. - """ - return RevOptions(cls, rev, extra_args=extra_args) - - @classmethod - def _is_local_repository(cls, repo): - # type: (str) -> bool - """ - posix absolute paths start with os.path.sep, - win32 ones start with drive (like c:\\folder) - """ - drive, tail = os.path.splitdrive(repo) - return repo.startswith(os.path.sep) or bool(drive) - - def export(self, location, url): - # type: (str, HiddenText) -> None - """ - Export the repository at the url to the destination location - i.e. only download the files, without vcs informations - - :param url: the repository URL starting with a vcs prefix. - """ - raise NotImplementedError - - @classmethod - def get_netloc_and_auth(cls, netloc, scheme): - # type: (str, str) -> Tuple[str, Tuple[Optional[str], Optional[str]]] - """ - Parse the repository URL's netloc, and return the new netloc to use - along with auth information. - - Args: - netloc: the original repository URL netloc. - scheme: the repository URL's scheme without the vcs prefix. - - This is mainly for the Subversion class to override, so that auth - information can be provided via the --username and --password options - instead of through the URL. For other subclasses like Git without - such an option, auth information must stay in the URL. - - Returns: (netloc, (username, password)). - """ - return netloc, (None, None) - - @classmethod - def get_url_rev_and_auth(cls, url): - # type: (str) -> Tuple[str, Optional[str], AuthInfo] - """ - Parse the repository URL to use, and return the URL, revision, - and auth info to use. - - Returns: (url, rev, (username, password)). - """ - scheme, netloc, path, query, frag = urllib_parse.urlsplit(url) - if '+' not in scheme: - raise ValueError( - "Sorry, {!r} is a malformed VCS url. " - "The format is <vcs>+<protocol>://<url>, " - "e.g. svn+http://myrepo/svn/MyApp#egg=MyApp".format(url) - ) - # Remove the vcs prefix. - scheme = scheme.split('+', 1)[1] - netloc, user_pass = cls.get_netloc_and_auth(netloc, scheme) - rev = None - if '@' in path: - path, rev = path.rsplit('@', 1) - if not rev: - raise InstallationError( - "The URL {!r} has an empty revision (after @) " - "which is not supported. Include a revision after @ " - "or remove @ from the URL.".format(url) - ) - url = urllib_parse.urlunsplit((scheme, netloc, path, query, '')) - return url, rev, user_pass - - @staticmethod - def make_rev_args(username, password): - # type: (Optional[str], Optional[HiddenText]) -> CommandArgs - """ - Return the RevOptions "extra arguments" to use in obtain(). - """ - return [] - - def get_url_rev_options(self, url): - # type: (HiddenText) -> Tuple[HiddenText, RevOptions] - """ - Return the URL and RevOptions object to use in obtain() and in - some cases export(), as a tuple (url, rev_options). - """ - secret_url, rev, user_pass = self.get_url_rev_and_auth(url.secret) - username, secret_password = user_pass - password = None # type: Optional[HiddenText] - if secret_password is not None: - password = hide_value(secret_password) - extra_args = self.make_rev_args(username, password) - rev_options = self.make_rev_options(rev, extra_args=extra_args) - - return hide_url(secret_url), rev_options - - @staticmethod - def normalize_url(url): - # type: (str) -> str - """ - Normalize a URL for comparison by unquoting it and removing any - trailing slash. - """ - return urllib_parse.unquote(url).rstrip('/') - - @classmethod - def compare_urls(cls, url1, url2): - # type: (str, str) -> bool - """ - Compare two repo URLs for identity, ignoring incidental differences. - """ - return (cls.normalize_url(url1) == cls.normalize_url(url2)) - - def fetch_new(self, dest, url, rev_options): - # type: (str, HiddenText, RevOptions) -> None - """ - Fetch a revision from a repository, in the case that this is the - first fetch from the repository. - - Args: - dest: the directory to fetch the repository to. - rev_options: a RevOptions object. - """ - raise NotImplementedError - - def switch(self, dest, url, rev_options): - # type: (str, HiddenText, RevOptions) -> None - """ - Switch the repo at ``dest`` to point to ``URL``. - - Args: - rev_options: a RevOptions object. - """ - raise NotImplementedError - - def update(self, dest, url, rev_options): - # type: (str, HiddenText, RevOptions) -> None - """ - Update an already-existing repo to the given ``rev_options``. - - Args: - rev_options: a RevOptions object. - """ - raise NotImplementedError - - @classmethod - def is_commit_id_equal(cls, dest, name): - # type: (str, Optional[str]) -> bool - """ - Return whether the id of the current commit equals the given name. - - Args: - dest: the repository directory. - name: a string name. - """ - raise NotImplementedError - - def obtain(self, dest, url): - # type: (str, HiddenText) -> None - """ - Install or update in editable mode the package represented by this - VersionControl object. - - :param dest: the repository directory in which to install or update. - :param url: the repository URL starting with a vcs prefix. - """ - url, rev_options = self.get_url_rev_options(url) - - if not os.path.exists(dest): - self.fetch_new(dest, url, rev_options) - return - - rev_display = rev_options.to_display() - if self.is_repository_directory(dest): - existing_url = self.get_remote_url(dest) - if self.compare_urls(existing_url, url.secret): - logger.debug( - '%s in %s exists, and has correct URL (%s)', - self.repo_name.title(), - display_path(dest), - url, - ) - if not self.is_commit_id_equal(dest, rev_options.rev): - logger.info( - 'Updating %s %s%s', - display_path(dest), - self.repo_name, - rev_display, - ) - self.update(dest, url, rev_options) - else: - logger.info('Skipping because already up-to-date.') - return - - logger.warning( - '%s %s in %s exists with URL %s', - self.name, - self.repo_name, - display_path(dest), - existing_url, - ) - prompt = ('(s)witch, (i)gnore, (w)ipe, (b)ackup ', - ('s', 'i', 'w', 'b')) - else: - logger.warning( - 'Directory %s already exists, and is not a %s %s.', - dest, - self.name, - self.repo_name, - ) - # https://github.com/python/mypy/issues/1174 - prompt = ('(i)gnore, (w)ipe, (b)ackup ', # type: ignore - ('i', 'w', 'b')) - - logger.warning( - 'The plan is to install the %s repository %s', - self.name, - url, - ) - response = ask_path_exists('What to do? {}'.format( - prompt[0]), prompt[1]) - - if response == 'a': - sys.exit(-1) - - if response == 'w': - logger.warning('Deleting %s', display_path(dest)) - rmtree(dest) - self.fetch_new(dest, url, rev_options) - return - - if response == 'b': - dest_dir = backup_dir(dest) - logger.warning( - 'Backing up %s to %s', display_path(dest), dest_dir, - ) - shutil.move(dest, dest_dir) - self.fetch_new(dest, url, rev_options) - return - - # Do nothing if the response is "i". - if response == 's': - logger.info( - 'Switching %s %s to %s%s', - self.repo_name, - display_path(dest), - url, - rev_display, - ) - self.switch(dest, url, rev_options) - - def unpack(self, location, url): - # type: (str, HiddenText) -> None - """ - Clean up current location and download the url repository - (and vcs infos) into location - - :param url: the repository URL starting with a vcs prefix. - """ - if os.path.exists(location): - rmtree(location) - self.obtain(location, url=url) - - @classmethod - def get_remote_url(cls, location): - # type: (str) -> str - """ - Return the url used at location - - Raises RemoteNotFoundError if the repository does not have a remote - url configured. - """ - raise NotImplementedError - - @classmethod - def get_revision(cls, location): - # type: (str) -> str - """ - Return the current commit id of the files at the given location. - """ - raise NotImplementedError - - @classmethod - def run_command( - cls, - cmd, # type: Union[List[str], CommandArgs] - show_stdout=True, # type: bool - cwd=None, # type: Optional[str] - on_returncode='raise', # type: str - extra_ok_returncodes=None, # type: Optional[Iterable[int]] - command_desc=None, # type: Optional[str] - extra_environ=None, # type: Optional[Mapping[str, Any]] - spinner=None, # type: Optional[SpinnerInterface] - log_failed_cmd=True # type: bool - ): - # type: (...) -> Text - """ - Run a VCS subcommand - This is simply a wrapper around call_subprocess that adds the VCS - command name, and checks that the VCS is available - """ - cmd = make_command(cls.name, *cmd) - try: - return call_subprocess(cmd, show_stdout, cwd, - on_returncode=on_returncode, - extra_ok_returncodes=extra_ok_returncodes, - command_desc=command_desc, - extra_environ=extra_environ, - unset_environ=cls.unset_environ, - spinner=spinner, - log_failed_cmd=log_failed_cmd) - except OSError as e: - # errno.ENOENT = no such file or directory - # In other words, the VCS executable isn't available - if e.errno == errno.ENOENT: - raise BadCommand( - 'Cannot find command {cls.name!r} - do you have ' - '{cls.name!r} installed and in your ' - 'PATH?'.format(**locals())) - else: - raise # re-raise exception if a different error occurred - - @classmethod - def is_repository_directory(cls, path): - # type: (str) -> bool - """ - Return whether a directory path is a repository directory. - """ - logger.debug('Checking in %s for %s (%s)...', - path, cls.dirname, cls.name) - return os.path.exists(os.path.join(path, cls.dirname)) - - @classmethod - def get_repository_root(cls, location): - # type: (str) -> Optional[str] - """ - Return the "root" (top-level) directory controlled by the vcs, - or `None` if the directory is not in any. - - It is meant to be overridden to implement smarter detection - mechanisms for specific vcs. - - This can do more than is_repository_directory() alone. For - example, the Git override checks that Git is actually available. - """ - if cls.is_repository_directory(location): - return location - return None diff --git a/venv/lib/python3.8/site-packages/pip/_internal/wheel_builder.py b/venv/lib/python3.8/site-packages/pip/_internal/wheel_builder.py deleted file mode 100644 index fcaeeb6..0000000 --- a/venv/lib/python3.8/site-packages/pip/_internal/wheel_builder.py +++ /dev/null @@ -1,309 +0,0 @@ -"""Orchestrator for building wheels from InstallRequirements. -""" - -# The following comment should be removed at some point in the future. -# mypy: strict-optional=False - -import logging -import os.path -import re -import shutil - -from pip._internal.models.link import Link -from pip._internal.operations.build.wheel import build_wheel_pep517 -from pip._internal.operations.build.wheel_legacy import build_wheel_legacy -from pip._internal.utils.logging import indent_log -from pip._internal.utils.misc import ensure_dir, hash_file, is_wheel_installed -from pip._internal.utils.setuptools_build import make_setuptools_clean_args -from pip._internal.utils.subprocess import call_subprocess -from pip._internal.utils.temp_dir import TempDirectory -from pip._internal.utils.typing import MYPY_CHECK_RUNNING -from pip._internal.utils.urls import path_to_url -from pip._internal.vcs import vcs - -if MYPY_CHECK_RUNNING: - from typing import ( - Any, Callable, Iterable, List, Optional, Pattern, Tuple, - ) - - from pip._internal.cache import WheelCache - from pip._internal.req.req_install import InstallRequirement - - BinaryAllowedPredicate = Callable[[InstallRequirement], bool] - BuildResult = Tuple[List[InstallRequirement], List[InstallRequirement]] - -logger = logging.getLogger(__name__) - - -def _contains_egg_info( - s, _egg_info_re=re.compile(r'([a-z0-9_.]+)-([a-z0-9_.!+-]+)', re.I)): - # type: (str, Pattern[str]) -> bool - """Determine whether the string looks like an egg_info. - - :param s: The string to parse. E.g. foo-2.1 - """ - return bool(_egg_info_re.search(s)) - - -def _should_build( - req, # type: InstallRequirement - need_wheel, # type: bool - check_binary_allowed, # type: BinaryAllowedPredicate -): - # type: (...) -> bool - """Return whether an InstallRequirement should be built into a wheel.""" - if req.constraint: - # never build requirements that are merely constraints - return False - if req.is_wheel: - if need_wheel: - logger.info( - 'Skipping %s, due to already being wheel.', req.name, - ) - return False - - if need_wheel: - # i.e. pip wheel, not pip install - return True - - # From this point, this concerns the pip install command only - # (need_wheel=False). - - if req.editable or not req.source_dir: - return False - - if not check_binary_allowed(req): - logger.info( - "Skipping wheel build for %s, due to binaries " - "being disabled for it.", req.name, - ) - return False - - if not req.use_pep517 and not is_wheel_installed(): - # we don't build legacy requirements if wheel is not installed - logger.info( - "Using legacy setup.py install for %s, " - "since package 'wheel' is not installed.", req.name, - ) - return False - - return True - - -def should_build_for_wheel_command( - req, # type: InstallRequirement -): - # type: (...) -> bool - return _should_build( - req, need_wheel=True, check_binary_allowed=_always_true - ) - - -def should_build_for_install_command( - req, # type: InstallRequirement - check_binary_allowed, # type: BinaryAllowedPredicate -): - # type: (...) -> bool - return _should_build( - req, need_wheel=False, check_binary_allowed=check_binary_allowed - ) - - -def _should_cache( - req, # type: InstallRequirement -): - # type: (...) -> Optional[bool] - """ - Return whether a built InstallRequirement can be stored in the persistent - wheel cache, assuming the wheel cache is available, and _should_build() - has determined a wheel needs to be built. - """ - if not should_build_for_install_command( - req, check_binary_allowed=_always_true - ): - # never cache if pip install would not have built - # (editable mode, etc) - return False - - if req.link and req.link.is_vcs: - # VCS checkout. Do not cache - # unless it points to an immutable commit hash. - assert not req.editable - assert req.source_dir - vcs_backend = vcs.get_backend_for_scheme(req.link.scheme) - assert vcs_backend - if vcs_backend.is_immutable_rev_checkout(req.link.url, req.source_dir): - return True - return False - - base, ext = req.link.splitext() - if _contains_egg_info(base): - return True - - # Otherwise, do not cache. - return False - - -def _get_cache_dir( - req, # type: InstallRequirement - wheel_cache, # type: WheelCache -): - # type: (...) -> str - """Return the persistent or temporary cache directory where the built - wheel need to be stored. - """ - cache_available = bool(wheel_cache.cache_dir) - if cache_available and _should_cache(req): - cache_dir = wheel_cache.get_path_for_link(req.link) - else: - cache_dir = wheel_cache.get_ephem_path_for_link(req.link) - return cache_dir - - -def _always_true(_): - # type: (Any) -> bool - return True - - -def _build_one( - req, # type: InstallRequirement - output_dir, # type: str - build_options, # type: List[str] - global_options, # type: List[str] -): - # type: (...) -> Optional[str] - """Build one wheel. - - :return: The filename of the built wheel, or None if the build failed. - """ - try: - ensure_dir(output_dir) - except OSError as e: - logger.warning( - "Building wheel for %s failed: %s", - req.name, e, - ) - return None - - # Install build deps into temporary directory (PEP 518) - with req.build_env: - return _build_one_inside_env( - req, output_dir, build_options, global_options - ) - - -def _build_one_inside_env( - req, # type: InstallRequirement - output_dir, # type: str - build_options, # type: List[str] - global_options, # type: List[str] -): - # type: (...) -> Optional[str] - with TempDirectory(kind="wheel") as temp_dir: - if req.use_pep517: - wheel_path = build_wheel_pep517( - name=req.name, - backend=req.pep517_backend, - metadata_directory=req.metadata_directory, - build_options=build_options, - tempd=temp_dir.path, - ) - else: - wheel_path = build_wheel_legacy( - name=req.name, - setup_py_path=req.setup_py_path, - source_dir=req.unpacked_source_directory, - global_options=global_options, - build_options=build_options, - tempd=temp_dir.path, - ) - - if wheel_path is not None: - wheel_name = os.path.basename(wheel_path) - dest_path = os.path.join(output_dir, wheel_name) - try: - wheel_hash, length = hash_file(wheel_path) - shutil.move(wheel_path, dest_path) - logger.info('Created wheel for %s: ' - 'filename=%s size=%d sha256=%s', - req.name, wheel_name, length, - wheel_hash.hexdigest()) - logger.info('Stored in directory: %s', output_dir) - return dest_path - except Exception as e: - logger.warning( - "Building wheel for %s failed: %s", - req.name, e, - ) - # Ignore return, we can't do anything else useful. - if not req.use_pep517: - _clean_one_legacy(req, global_options) - return None - - -def _clean_one_legacy(req, global_options): - # type: (InstallRequirement, List[str]) -> bool - clean_args = make_setuptools_clean_args( - req.setup_py_path, - global_options=global_options, - ) - - logger.info('Running setup.py clean for %s', req.name) - try: - call_subprocess(clean_args, cwd=req.source_dir) - return True - except Exception: - logger.error('Failed cleaning build dir for %s', req.name) - return False - - -def build( - requirements, # type: Iterable[InstallRequirement] - wheel_cache, # type: WheelCache - build_options, # type: List[str] - global_options, # type: List[str] -): - # type: (...) -> BuildResult - """Build wheels. - - :return: The list of InstallRequirement that succeeded to build and - the list of InstallRequirement that failed to build. - """ - if not requirements: - return [], [] - - # Build the wheels. - logger.info( - 'Building wheels for collected packages: %s', - ', '.join(req.name for req in requirements), - ) - - with indent_log(): - build_successes, build_failures = [], [] - for req in requirements: - cache_dir = _get_cache_dir(req, wheel_cache) - wheel_file = _build_one( - req, cache_dir, build_options, global_options - ) - if wheel_file: - # Update the link for this. - req.link = Link(path_to_url(wheel_file)) - req.local_file_path = req.link.file_path - assert req.link.is_wheel - build_successes.append(req) - else: - build_failures.append(req) - - # notify success/failure - if build_successes: - logger.info( - 'Successfully built %s', - ' '.join([req.name for req in build_successes]), - ) - if build_failures: - logger.info( - 'Failed to build %s', - ' '.join([req.name for req in build_failures]), - ) - # Return a list of requirements that failed to build - return build_successes, build_failures diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/__init__.py b/venv/lib/python3.8/site-packages/pip/_vendor/__init__.py deleted file mode 100644 index d4e20fe..0000000 --- a/venv/lib/python3.8/site-packages/pip/_vendor/__init__.py +++ /dev/null @@ -1,123 +0,0 @@ -""" -pip._vendor is for vendoring dependencies of pip to prevent needing pip to -depend on something external. - -Files inside of pip._vendor should be considered immutable and should only be -updated to versions from upstream. -""" -from __future__ import absolute_import - -import glob -import os.path -import sys - -# Downstream redistributors which have debundled our dependencies should also -# patch this value to be true. This will trigger the additional patching -# to cause things like "six" to be available as pip. -DEBUNDLED = True - -# By default, look in this directory for a bunch of .whl files which we will -# add to the beginning of sys.path before attempting to import anything. This -# is done to support downstream re-distributors like Debian and Fedora who -# wish to create their own Wheels for our dependencies to aid in debundling. -prefix = getattr(sys, "base_prefix", sys.prefix) -if prefix.startswith('/usr/lib/pypy'): - prefix = '/usr' -WHEEL_DIR = os.path.abspath(os.path.join(prefix, 'share', 'python-wheels')) - - -# Define a small helper function to alias our vendored modules to the real ones -# if the vendored ones do not exist. This idea of this was taken from -# https://github.com/kennethreitz/requests/pull/2567. -def vendored(modulename): - vendored_name = "{0}.{1}".format(__name__, modulename) - - try: - __import__(modulename, globals(), locals(), level=0) - except ImportError: - # We can just silently allow import failures to pass here. If we - # got to this point it means that ``import pip._vendor.whatever`` - # failed and so did ``import whatever``. Since we're importing this - # upfront in an attempt to alias imports, not erroring here will - # just mean we get a regular import error whenever pip *actually* - # tries to import one of these modules to use it, which actually - # gives us a better error message than we would have otherwise - # gotten. - pass - else: - sys.modules[vendored_name] = sys.modules[modulename] - base, head = vendored_name.rsplit(".", 1) - setattr(sys.modules[base], head, sys.modules[modulename]) - - -# If we're operating in a debundled setup, then we want to go ahead and trigger -# the aliasing of our vendored libraries as well as looking for wheels to add -# to our sys.path. This will cause all of this code to be a no-op typically -# however downstream redistributors can enable it in a consistent way across -# all platforms. -if DEBUNDLED: - # Actually look inside of WHEEL_DIR to find .whl files and add them to the - # front of our sys.path. - sys.path[:] = [fn for fn in glob.iglob(os.path.join(WHEEL_DIR, '*.whl')) - if not (os.path.basename(fn).startswith('wheel') or - os.path.basename(fn).startswith('pip'))] + sys.path - - # Actually alias all of our vendored dependencies. - vendored("appdirs") - vendored("cachecontrol") - vendored("certifi") - vendored("colorama") - vendored("contextlib2") - vendored("distlib") - vendored("distro") - vendored("html5lib") - vendored("six") - vendored("six.moves") - vendored("six.moves.urllib") - vendored("six.moves.urllib.parse") - vendored("packaging") - vendored("packaging.version") - vendored("packaging.specifiers") - vendored("pep517") - vendored("pkg_resources") - vendored("progress") - vendored("retrying") - vendored("requests") - vendored("requests.exceptions") - vendored("requests.packages") - vendored("requests.packages.urllib3") - vendored("requests.packages.urllib3._collections") - vendored("requests.packages.urllib3.connection") - vendored("requests.packages.urllib3.connectionpool") - vendored("requests.packages.urllib3.contrib") - vendored("requests.packages.urllib3.contrib.ntlmpool") - vendored("requests.packages.urllib3.contrib.pyopenssl") - vendored("requests.packages.urllib3.exceptions") - vendored("requests.packages.urllib3.fields") - vendored("requests.packages.urllib3.filepost") - vendored("requests.packages.urllib3.packages") - try: - vendored("requests.packages.urllib3.packages.ordered_dict") - vendored("requests.packages.urllib3.packages.six") - except ImportError: - # Debian already unbundles these from requests. - pass - vendored("requests.packages.urllib3.packages.ssl_match_hostname") - vendored("requests.packages.urllib3.packages.ssl_match_hostname." - "_implementation") - vendored("requests.packages.urllib3.poolmanager") - vendored("requests.packages.urllib3.request") - vendored("requests.packages.urllib3.response") - vendored("requests.packages.urllib3.util") - vendored("requests.packages.urllib3.util.connection") - vendored("requests.packages.urllib3.util.request") - vendored("requests.packages.urllib3.util.response") - vendored("requests.packages.urllib3.util.retry") - vendored("requests.packages.urllib3.util.ssl_") - vendored("requests.packages.urllib3.util.timeout") - vendored("requests.packages.urllib3.util.url") - vendored("resolvelib") - vendored("toml") - vendored("toml.encoder") - vendored("toml.decoder") - vendored("urllib3") diff --git a/venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/AUTHORS.txt b/venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/AUTHORS.txt deleted file mode 100644 index 04c42fc..0000000 --- a/venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/AUTHORS.txt +++ /dev/null @@ -1,566 +0,0 @@ -@Switch01 -A_Rog -Aakanksha Agrawal -Abhinav Sagar -ABHYUDAY PRATAP SINGH -abs51295 -AceGentile -Adam Chainz -Adam Tse -Adam Wentz -admin -Adrien Morison -ahayrapetyan -Ahilya -AinsworthK -Akash Srivastava -Alan Yee -Albert Tugushev -Albert-Guan -albertg -Aleks Bunin -Alethea Flowers -Alex Gaynor -Alex Grönholm -Alex Loosley -Alex Morega -Alex Stachowiak -Alexander Shtyrov -Alexandre Conrad -Alexey Popravka -Alli -Ami Fischman -Ananya Maiti -Anatoly Techtonik -Anders Kaseorg -Andre Aguiar -Andreas Lutro -Andrei Geacar -Andrew Gaul -Andrey Bulgakov -Andrés Delfino -Andy Freeland -Andy Kluger -Ani Hayrapetyan -Aniruddha Basak -Anish Tambe -Anrs Hu -Anthony Sottile -Antoine Musso -Anton Ovchinnikov -Anton Patrushev -Antonio Alvarado Hernandez -Antony Lee -Antti Kaihola -Anubhav Patel -Anudit Nagar -Anuj Godase -AQNOUCH Mohammed -AraHaan -Arindam Choudhury -Armin Ronacher -Artem -Ashley Manton -Ashwin Ramaswami -atse -Atsushi Odagiri -Avner Cohen -Baptiste Mispelon -Barney Gale -barneygale -Bartek Ogryczak -Bastian Venthur -Ben Darnell -Ben Hoyt -Ben Rosser -Bence Nagy -Benjamin Peterson -Benjamin VanEvery -Benoit Pierre -Berker Peksag -Bernardo B. Marques -Bernhard M. Wiedemann -Bertil Hatt -Bhavam Vidyarthi -Bogdan Opanchuk -BorisZZZ -Brad Erickson -Bradley Ayers -Brandon L. Reiss -Brandt Bucher -Brett Randall -Brian Cristante -Brian Rosner -BrownTruck -Bruno Oliveira -Bruno Renié -Bstrdsmkr -Buck Golemon -burrows -Bussonnier Matthias -c22 -Caleb Martinez -Calvin Smith -Carl Meyer -Carlos Liam -Carol Willing -Carter Thayer -Cass -Chandrasekhar Atina -Chih-Hsuan Yen -Chris Brinker -Chris Hunt -Chris Jerdonek -Chris McDonough -Chris Wolfe -Christian Clauss -Christian Heimes -Christian Oudard -Christoph Reiter -Christopher Hunt -Christopher Snyder -cjc7373 -Clark Boylan -Clay McClure -Cody -Cody Soyland -Colin Watson -Connor Osborn -Cooper Lees -Cooper Ry Lees -Cory Benfield -Cory Wright -Craig Kerstiens -Cristian Sorinel -Curtis Doty -cytolentino -Damian Quiroga -Dan Black -Dan Savilonis -Dan Sully -daniel -Daniel Collins -Daniel Hahler -Daniel Holth -Daniel Jost -Daniel Shaulov -Daniele Esposti -Daniele Procida -Danny Hermes -Danny McClanahan -Dav Clark -Dave Abrahams -Dave Jones -David Aguilar -David Black -David Bordeynik -David Caro -David Evans -David Linke -David Pursehouse -David Tucker -David Wales -Davidovich -Deepak Sharma -derwolfe -Desetude -Devesh Kumar Singh -Diego Caraballo -DiegoCaraballo -Dmitry Gladkov -Domen Kožar -Donald Stufft -Dongweiming -Douglas Thor -DrFeathers -Dustin Ingram -Dwayne Bailey -Ed Morley -Eitan Adler -ekristina -elainechan -Eli Schwartz -Ellen Marie Dash -Emil Burzo -Emil Styrke -Endoh Takanao -enoch -Erdinc Mutlu -Eric Gillingham -Eric Hanchrow -Eric Hopper -Erik M. Bray -Erik Rose -Ernest W Durbin III -Ernest W. Durbin III -Erwin Janssen -Eugene Vereshchagin -everdimension -Felix Yan -fiber-space -Filip Kokosiński -Florian Briand -Florian Rathgeber -Francesco -Francesco Montesano -Frost Ming -Gabriel Curio -Gabriel de Perthuis -Garry Polley -gdanielson -Geoffrey Lehée -Geoffrey Sneddon -George Song -Georgi Valkov -ghost -Giftlin Rajaiah -gizmoguy1 -gkdoc -Gopinath M -GOTO Hayato -gpiks -Guilherme Espada -gutsytechster -Guy Rozendorn -gzpan123 -Hanjun Kim -Hari Charan -Harsh Vardhan -Herbert Pfennig -Hsiaoming Yang -Hugo -Hugo Lopes Tavares -Hugo van Kemenade -hugovk -Hynek Schlawack -Ian Bicking -Ian Cordasco -Ian Lee -Ian Stapleton Cordasco -Ian Wienand -Igor Kuzmitshov -Igor Sobreira -Ilan Schnell -Ilya Baryshev -INADA Naoki -Ionel Cristian Mărieș -Ionel Maries Cristian -Ivan Pozdeev -Jacob Kim -jakirkham -Jakub Stasiak -Jakub Vysoky -Jakub Wilk -James Cleveland -James Firth -James Polley -Jan Pokorný -Jannis Leidel -jarondl -Jason R. Coombs -Jay Graves -Jean-Christophe Fillion-Robin -Jeff Barber -Jeff Dairiki -Jelmer Vernooij -jenix21 -Jeremy Stanley -Jeremy Zafran -Jiashuo Li -Jim Garrison -Jivan Amara -John Paton -John T. Wodder II -John-Scott Atlakson -johnthagen -Jon Banafato -Jon Dufresne -Jon Parise -Jonas Nockert -Jonathan Herbert -Joost Molenaar -Jorge Niedbalski -Joseph Long -Josh Bronson -Josh Hansen -Josh Schneier -Juanjo Bazán -Julian Berman -Julian Gethmann -Julien Demoor -jwg4 -Jyrki Pulliainen -Kai Chen -Kamal Bin Mustafa -kaustav haldar -keanemind -Keith Maxwell -Kelsey Hightower -Kenneth Belitzky -Kenneth Reitz -Kevin Burke -Kevin Carter -Kevin Frommelt -Kevin R Patterson -Kexuan Sun -Kit Randel -KOLANICH -kpinc -Krishna Oza -Kumar McMillan -Kyle Persohn -lakshmanaram -Laszlo Kiss-Kollar -Laurent Bristiel -Laurie Opperman -Leon Sasson -Lev Givon -Lincoln de Sousa -Lipis -Loren Carvalho -Lucas Cimon -Ludovic Gasc -Luke Macken -Luo Jiebin -luojiebin -luz.paz -László Kiss Kollár -Marc Abramowitz -Marc Tamlyn -Marcus Smith -Mariatta -Mark Kohler -Mark Williams -Markus Hametner -Masaki -Masklinn -Matej Stuchlik -Mathew Jennings -Mathieu Bridon -Matt Good -Matt Maker -Matt Robenolt -matthew -Matthew Einhorn -Matthew Gilliard -Matthew Iversen -Matthew Trumbell -Matthew Willson -Matthias Bussonnier -mattip -Maxim Kurnikov -Maxime Rouyrre -mayeut -mbaluna -mdebi -memoselyk -Michael -Michael Aquilina -Michael E. Karpeles -Michael Klich -Michael Williamson -michaelpacer -Mickaël Schoentgen -Miguel Araujo Perez -Mihir Singh -Mike -Mike Hendricks -Min RK -MinRK -Miro Hrončok -Monica Baluna -montefra -Monty Taylor -Nate Coraor -Nathaniel J. Smith -Nehal J Wani -Neil Botelho -Nguyễn Gia Phong -Nick Coghlan -Nick Stenning -Nick Timkovich -Nicolas Bock -Nikhil Benesch -Nikolay Korolev -Nitesh Sharma -Noah Gorny -Nowell Strite -NtaleGrey -nvdv -Ofekmeister -ofrinevo -Oliver Jeeves -Oliver Tonnhofer -Olivier Girardot -Olivier Grisel -Ollie Rutherfurd -OMOTO Kenji -Omry Yadan -onlinejudge95 -Oren Held -Oscar Benjamin -Oz N Tiram -Pachwenko -Patrick Dubroy -Patrick Jenkins -Patrick Lawson -patricktokeeffe -Patrik Kopkan -Paul Kehrer -Paul Moore -Paul Nasrat -Paul Oswald -Paul van der Linden -Paulus Schoutsen -Pavithra Eswaramoorthy -Pawel Jasinski -Pekka Klärck -Peter Lisák -Peter Waller -petr-tik -Phaneendra Chiruvella -Phil Freo -Phil Pennock -Phil Whelan -Philip Jägenstedt -Philip Molloy -Philippe Ombredanne -Pi Delport -Pierre-Yves Rofes -pip -Prabakaran Kumaresshan -Prabhjyotsing Surjit Singh Sodhi -Prabhu Marappan -Pradyun Gedam -Prashant Sharma -Pratik Mallya -Preet Thakkar -Preston Holmes -Przemek Wrzos -Pulkit Goyal -Qiangning Hong -Quentin Pradet -R. David Murray -Rafael Caricio -Ralf Schmitt -Razzi Abuissa -rdb -Reece Dunham -Remi Rampin -Rene Dudfield -Riccardo Magliocchetti -Richard Jones -Ricky Ng-Adam -RobberPhex -Robert Collins -Robert McGibbon -Robert T. McGibbon -robin elisha robinson -Roey Berman -Rohan Jain -Roman Bogorodskiy -Romuald Brunet -Ronny Pfannschmidt -Rory McCann -Ross Brattain -Roy Wellington Ⅳ -Ryan Wooden -ryneeverett -Sachi King -Salvatore Rinchiera -Savio Jomton -schlamar -Scott Kitterman -Sean -seanj -Sebastian Jordan -Sebastian Schaetz -Segev Finer -SeongSoo Cho -Sergey Vasilyev -Seth Woodworth -Shlomi Fish -Shovan Maity -Simeon Visser -Simon Cross -Simon Pichugin -sinoroc -sinscary -Sorin Sbarnea -Stavros Korokithakis -Stefan Scherfke -Stefano Rivera -Stephan Erb -stepshal -Steve (Gadget) Barnes -Steve Barnes -Steve Dower -Steve Kowalik -Steven Myint -stonebig -Stéphane Bidoul -Stéphane Bidoul (ACSONE) -Stéphane Klein -Sumana Harihareswara -Sviatoslav Sydorenko -Swat009 -Takayuki SHIMIZUKAWA -tbeswick -Thijs Triemstra -Thomas Fenzl -Thomas Grainger -Thomas Guettler -Thomas Johansson -Thomas Kluyver -Thomas Smith -Tim D. Smith -Tim Gates -Tim Harder -Tim Heap -tim smith -tinruufu -Tom Forbes -Tom Freudenheim -Tom V -Tomas Hrnciar -Tomas Orsava -Tomer Chachamu -Tony Beswick -Tony Zhaocheng Tan -TonyBeswick -toonarmycaptain -Toshio Kuratomi -Travis Swicegood -Tzu-ping Chung -Valentin Haenel -Victor Stinner -victorvpaulo -Viktor Szépe -Ville Skyttä -Vinay Sajip -Vincent Philippon -Vinicyus Macedo -Vitaly Babiy -Vladimir Rutsky -W. Trevor King -Wil Tan -Wilfred Hughes -William ML Leslie -William T Olson -Wilson Mo -wim glenn -Wolfgang Maier -Xavier Fernandez -xoviat -xtreak -YAMAMOTO Takashi -Yen Chi Hsuan -Yeray Diaz Diaz -Yoval P -Yu Jian -Yuan Jing Vincent Yan -Zearin -Zhiping Deng -Zvezdan Petkovic -Łukasz Langa -Семён Марьясин diff --git a/venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/INSTALLER b/venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/LICENSE.txt b/venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/LICENSE.txt deleted file mode 100644 index 737fec5..0000000 --- a/venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/LICENSE.txt +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2008-2019 The pip developers (see AUTHORS.txt file) - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/METADATA b/venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/METADATA deleted file mode 100644 index cf6c930..0000000 --- a/venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/METADATA +++ /dev/null @@ -1,13 +0,0 @@ -Metadata-Version: 2.1 -Name: pkg_resources -Version: 0.0.0 -Summary: UNKNOWN -Home-page: UNKNOWN -Author: UNKNOWN -Author-email: UNKNOWN -License: UNKNOWN -Platform: UNKNOWN - -UNKNOWN - - diff --git a/venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/RECORD b/venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/RECORD deleted file mode 100644 index 562db11..0000000 --- a/venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/RECORD +++ /dev/null @@ -1,38 +0,0 @@ -pkg_resources-0.0.0.dist-info/AUTHORS.txt,sha256=RnTFYKrTgbpfWnZMizLRq0u31iGDJMbs-iqvafo1CcA,7734 -pkg_resources-0.0.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -pkg_resources-0.0.0.dist-info/LICENSE.txt,sha256=W6Ifuwlk-TatfRU2LR7W1JMcyMj5_y1NkRkOEJvnRDE,1090 -pkg_resources-0.0.0.dist-info/METADATA,sha256=V9_WPOtD1FnuKrTGv6Ique7kAOn2lasvT8W0_iMCCCk,177 -pkg_resources-0.0.0.dist-info/RECORD,, -pkg_resources-0.0.0.dist-info/WHEEL,sha256=kGT74LWyRUZrL4VgLh6_g12IeVl_9u9ZVhadrgXZUEY,110 -pkg_resources/__init__.py,sha256=0IssxXPnaDKpYZRra8Ime0JG4hwosQljItGD0bnIkGk,108349 -pkg_resources/__pycache__/__init__.cpython-38.pyc,, -pkg_resources/__pycache__/py31compat.cpython-38.pyc,, -pkg_resources/_vendor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -pkg_resources/_vendor/__pycache__/__init__.cpython-38.pyc,, -pkg_resources/_vendor/__pycache__/appdirs.cpython-38.pyc,, -pkg_resources/_vendor/__pycache__/pyparsing.cpython-38.pyc,, -pkg_resources/_vendor/__pycache__/six.cpython-38.pyc,, -pkg_resources/_vendor/appdirs.py,sha256=MievUEuv3l_mQISH5SF0shDk_BNhHHzYiAPrT3ITN4I,24701 -pkg_resources/_vendor/packaging/__about__.py,sha256=zkcCPTN_6TcLW0Nrlg0176-R1QQ_WVPTm8sz1R4-HjM,720 -pkg_resources/_vendor/packaging/__init__.py,sha256=_vNac5TrzwsrzbOFIbF-5cHqc_Y2aPT2D7zrIR06BOo,513 -pkg_resources/_vendor/packaging/__pycache__/__about__.cpython-38.pyc,, -pkg_resources/_vendor/packaging/__pycache__/__init__.cpython-38.pyc,, -pkg_resources/_vendor/packaging/__pycache__/_compat.cpython-38.pyc,, -pkg_resources/_vendor/packaging/__pycache__/_structures.cpython-38.pyc,, -pkg_resources/_vendor/packaging/__pycache__/markers.cpython-38.pyc,, -pkg_resources/_vendor/packaging/__pycache__/requirements.cpython-38.pyc,, -pkg_resources/_vendor/packaging/__pycache__/specifiers.cpython-38.pyc,, -pkg_resources/_vendor/packaging/__pycache__/utils.cpython-38.pyc,, -pkg_resources/_vendor/packaging/__pycache__/version.cpython-38.pyc,, -pkg_resources/_vendor/packaging/_compat.py,sha256=Vi_A0rAQeHbU-a9X0tt1yQm9RqkgQbDSxzRw8WlU9kA,860 -pkg_resources/_vendor/packaging/_structures.py,sha256=RImECJ4c_wTlaTYYwZYLHEiebDMaAJmK1oPARhw1T5o,1416 -pkg_resources/_vendor/packaging/markers.py,sha256=uEcBBtGvzqltgnArqb9c4RrcInXezDLos14zbBHhWJo,8248 -pkg_resources/_vendor/packaging/requirements.py,sha256=SikL2UynbsT0qtY9ltqngndha_sfo0w6XGFhAhoSoaQ,4355 -pkg_resources/_vendor/packaging/specifiers.py,sha256=SAMRerzO3fK2IkFZCaZkuwZaL_EGqHNOz4pni4vhnN0,28025 -pkg_resources/_vendor/packaging/utils.py,sha256=3m6WvPm6NNxE8rkTGmn0r75B_GZSGg7ikafxHsBN1WA,421 -pkg_resources/_vendor/packaging/version.py,sha256=OwGnxYfr2ghNzYx59qWIBkrK3SnB6n-Zfd1XaLpnnM0,11556 -pkg_resources/_vendor/pyparsing.py,sha256=tmrp-lu-qO1i75ZzIN5A12nKRRD1Cm4Vpk-5LR9rims,232055 -pkg_resources/_vendor/six.py,sha256=A6hdJZVjI3t_geebZ9BzUvwRrIXo0lfwzQlM2LcKyas,30098 -pkg_resources/extern/__init__.py,sha256=cHiEfHuLmm6rs5Ve_ztBfMI7Lr31vss-D4wkqF5xzlI,2498 -pkg_resources/extern/__pycache__/__init__.cpython-38.pyc,, -pkg_resources/py31compat.py,sha256=-WQ0e4c3RG_acdhwC3gLiXhP_lg4G5q7XYkZkQg0gxU,558 diff --git a/venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/WHEEL b/venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/WHEEL deleted file mode 100644 index ef99c6c..0000000 --- a/venv/lib/python3.8/site-packages/pkg_resources-0.0.0.dist-info/WHEEL +++ /dev/null @@ -1,6 +0,0 @@ -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/venv/lib/python3.8/site-packages/pkg_resources/__init__.py b/venv/lib/python3.8/site-packages/pkg_resources/__init__.py deleted file mode 100644 index 2f5aa64..0000000 --- a/venv/lib/python3.8/site-packages/pkg_resources/__init__.py +++ /dev/null @@ -1,3296 +0,0 @@ -# coding: utf-8 -""" -Package resource API --------------------- - -A resource is a logical file contained within a package, or a logical -subdirectory thereof. The package resource API expects resource names -to have their path parts separated with ``/``, *not* whatever the local -path separator is. Do not use os.path operations to manipulate resource -names being passed into the API. - -The package resource API is designed to work with normal filesystem packages, -.egg files, and unpacked .egg files. It can also work in a limited way with -.zip files and with custom PEP 302 loaders that support the ``get_data()`` -method. -""" - -from __future__ import absolute_import - -import sys -import os -import io -import time -import re -import types -import zipfile -import zipimport -import warnings -import stat -import functools -import pkgutil -import operator -import platform -import collections -import plistlib -import email.parser -import errno -import tempfile -import textwrap -import itertools -import inspect -import ntpath -import posixpath -from pkgutil import get_importer - -try: - import _imp -except ImportError: - # Python 3.2 compatibility - import imp as _imp - -try: - FileExistsError -except NameError: - FileExistsError = OSError - -from pkg_resources.extern import six -from pkg_resources.extern.six.moves import urllib, map, filter - -# capture these to bypass sandboxing -from os import utime -try: - from os import mkdir, rename, unlink - WRITE_SUPPORT = True -except ImportError: - # no write support, probably under GAE - WRITE_SUPPORT = False - -from os import open as os_open -from os.path import isdir, split - -try: - import importlib.machinery as importlib_machinery - # access attribute to force import under delayed import mechanisms. - importlib_machinery.__name__ -except ImportError: - importlib_machinery = None - -from . import py31compat -from pkg_resources.extern import appdirs -from pkg_resources.extern import packaging -__import__('pkg_resources.extern.packaging.version') -__import__('pkg_resources.extern.packaging.specifiers') -__import__('pkg_resources.extern.packaging.requirements') -__import__('pkg_resources.extern.packaging.markers') - - -__metaclass__ = type - - -if (3, 0) < sys.version_info < (3, 5): - raise RuntimeError("Python 3.5 or later is required") - -if six.PY2: - # Those builtin exceptions are only defined in Python 3 - PermissionError = None - NotADirectoryError = None - -# declare some globals that will be defined later to -# satisfy the linters. -require = None -working_set = None -add_activation_listener = None -resources_stream = None -cleanup_resources = None -resource_dir = None -resource_stream = None -set_extraction_path = None -resource_isdir = None -resource_string = None -iter_entry_points = None -resource_listdir = None -resource_filename = None -resource_exists = None -_distribution_finders = None -_namespace_handlers = None -_namespace_packages = None - - -class PEP440Warning(RuntimeWarning): - """ - Used when there is an issue with a version or specifier not complying with - PEP 440. - """ - - -def parse_version(v): - try: - return packaging.version.Version(v) - except packaging.version.InvalidVersion: - return packaging.version.LegacyVersion(v) - - -_state_vars = {} - - -def _declare_state(vartype, **kw): - globals().update(kw) - _state_vars.update(dict.fromkeys(kw, vartype)) - - -def __getstate__(): - state = {} - g = globals() - for k, v in _state_vars.items(): - state[k] = g['_sget_' + v](g[k]) - return state - - -def __setstate__(state): - g = globals() - for k, v in state.items(): - g['_sset_' + _state_vars[k]](k, g[k], v) - return state - - -def _sget_dict(val): - return val.copy() - - -def _sset_dict(key, ob, state): - ob.clear() - ob.update(state) - - -def _sget_object(val): - return val.__getstate__() - - -def _sset_object(key, ob, state): - ob.__setstate__(state) - - -_sget_none = _sset_none = lambda *args: None - - -def get_supported_platform(): - """Return this platform's maximum compatible version. - - distutils.util.get_platform() normally reports the minimum version - of Mac OS X that would be required to *use* extensions produced by - distutils. But what we want when checking compatibility is to know the - version of Mac OS X that we are *running*. To allow usage of packages that - explicitly require a newer version of Mac OS X, we must also know the - current version of the OS. - - If this condition occurs for any other platform with a version in its - platform strings, this function should be extended accordingly. - """ - plat = get_build_platform() - m = macosVersionString.match(plat) - if m is not None and sys.platform == "darwin": - try: - plat = 'macosx-%s-%s' % ('.'.join(_macosx_vers()[:2]), m.group(3)) - except ValueError: - # not Mac OS X - pass - return plat - - -__all__ = [ - # Basic resource access and distribution/entry point discovery - 'require', 'run_script', 'get_provider', 'get_distribution', - 'load_entry_point', 'get_entry_map', 'get_entry_info', - 'iter_entry_points', - 'resource_string', 'resource_stream', 'resource_filename', - 'resource_listdir', 'resource_exists', 'resource_isdir', - - # Environmental control - 'declare_namespace', 'working_set', 'add_activation_listener', - 'find_distributions', 'set_extraction_path', 'cleanup_resources', - 'get_default_cache', - - # Primary implementation classes - 'Environment', 'WorkingSet', 'ResourceManager', - 'Distribution', 'Requirement', 'EntryPoint', - - # Exceptions - 'ResolutionError', 'VersionConflict', 'DistributionNotFound', - 'UnknownExtra', 'ExtractionError', - - # Warnings - 'PEP440Warning', - - # Parsing functions and string utilities - 'parse_requirements', 'parse_version', 'safe_name', 'safe_version', - 'get_platform', 'compatible_platforms', 'yield_lines', 'split_sections', - 'safe_extra', 'to_filename', 'invalid_marker', 'evaluate_marker', - - # filesystem utilities - 'ensure_directory', 'normalize_path', - - # Distribution "precedence" constants - 'EGG_DIST', 'BINARY_DIST', 'SOURCE_DIST', 'CHECKOUT_DIST', 'DEVELOP_DIST', - - # "Provider" interfaces, implementations, and registration/lookup APIs - 'IMetadataProvider', 'IResourceProvider', 'FileMetadata', - 'PathMetadata', 'EggMetadata', 'EmptyProvider', 'empty_provider', - 'NullProvider', 'EggProvider', 'DefaultProvider', 'ZipProvider', - 'register_finder', 'register_namespace_handler', 'register_loader_type', - 'fixup_namespace_packages', 'get_importer', - - # Warnings - 'PkgResourcesDeprecationWarning', - - # Deprecated/backward compatibility only - 'run_main', 'AvailableDistributions', -] - - -class ResolutionError(Exception): - """Abstract base for dependency resolution errors""" - - def __repr__(self): - return self.__class__.__name__ + repr(self.args) - - -class VersionConflict(ResolutionError): - """ - An already-installed version conflicts with the requested version. - - Should be initialized with the installed Distribution and the requested - Requirement. - """ - - _template = "{self.dist} is installed but {self.req} is required" - - @property - def dist(self): - return self.args[0] - - @property - def req(self): - return self.args[1] - - def report(self): - return self._template.format(**locals()) - - def with_context(self, required_by): - """ - If required_by is non-empty, return a version of self that is a - ContextualVersionConflict. - """ - if not required_by: - return self - args = self.args + (required_by,) - return ContextualVersionConflict(*args) - - -class ContextualVersionConflict(VersionConflict): - """ - A VersionConflict that accepts a third parameter, the set of the - requirements that required the installed Distribution. - """ - - _template = VersionConflict._template + ' by {self.required_by}' - - @property - def required_by(self): - return self.args[2] - - -class DistributionNotFound(ResolutionError): - """A requested distribution was not found""" - - _template = ("The '{self.req}' distribution was not found " - "and is required by {self.requirers_str}") - - @property - def req(self): - return self.args[0] - - @property - def requirers(self): - return self.args[1] - - @property - def requirers_str(self): - if not self.requirers: - return 'the application' - return ', '.join(self.requirers) - - def report(self): - return self._template.format(**locals()) - - def __str__(self): - return self.report() - - -class UnknownExtra(ResolutionError): - """Distribution doesn't have an "extra feature" of the given name""" - - -_provider_factories = {} - -PY_MAJOR = '{}.{}'.format(*sys.version_info) -EGG_DIST = 3 -BINARY_DIST = 2 -SOURCE_DIST = 1 -CHECKOUT_DIST = 0 -DEVELOP_DIST = -1 - - -def register_loader_type(loader_type, provider_factory): - """Register `provider_factory` to make providers for `loader_type` - - `loader_type` is the type or class of a PEP 302 ``module.__loader__``, - and `provider_factory` is a function that, passed a *module* object, - returns an ``IResourceProvider`` for that module. - """ - _provider_factories[loader_type] = provider_factory - - -def get_provider(moduleOrReq): - """Return an IResourceProvider for the named module or requirement""" - if isinstance(moduleOrReq, Requirement): - return working_set.find(moduleOrReq) or require(str(moduleOrReq))[0] - try: - module = sys.modules[moduleOrReq] - except KeyError: - __import__(moduleOrReq) - module = sys.modules[moduleOrReq] - loader = getattr(module, '__loader__', None) - return _find_adapter(_provider_factories, loader)(module) - - -def _macosx_vers(_cache=[]): - if not _cache: - version = platform.mac_ver()[0] - # fallback for MacPorts - if version == '': - plist = '/System/Library/CoreServices/SystemVersion.plist' - if os.path.exists(plist): - if hasattr(plistlib, 'readPlist'): - plist_content = plistlib.readPlist(plist) - if 'ProductVersion' in plist_content: - version = plist_content['ProductVersion'] - - _cache.append(version.split('.')) - return _cache[0] - - -def _macosx_arch(machine): - return {'PowerPC': 'ppc', 'Power_Macintosh': 'ppc'}.get(machine, machine) - - -def get_build_platform(): - """Return this platform's string for platform-specific distributions - - XXX Currently this is the same as ``distutils.util.get_platform()``, but it - needs some hacks for Linux and Mac OS X. - """ - from sysconfig import get_platform - - plat = get_platform() - if sys.platform == "darwin" and not plat.startswith('macosx-'): - try: - version = _macosx_vers() - machine = os.uname()[4].replace(" ", "_") - return "macosx-%d.%d-%s" % ( - int(version[0]), int(version[1]), - _macosx_arch(machine), - ) - except ValueError: - # if someone is running a non-Mac darwin system, this will fall - # through to the default implementation - pass - return plat - - -macosVersionString = re.compile(r"macosx-(\d+)\.(\d+)-(.*)") -darwinVersionString = re.compile(r"darwin-(\d+)\.(\d+)\.(\d+)-(.*)") -# XXX backward compat -get_platform = get_build_platform - - -def compatible_platforms(provided, required): - """Can code for the `provided` platform run on the `required` platform? - - Returns true if either platform is ``None``, or the platforms are equal. - - XXX Needs compatibility checks for Linux and other unixy OSes. - """ - if provided is None or required is None or provided == required: - # easy case - return True - - # Mac OS X special cases - reqMac = macosVersionString.match(required) - if reqMac: - provMac = macosVersionString.match(provided) - - # is this a Mac package? - if not provMac: - # this is backwards compatibility for packages built before - # setuptools 0.6. All packages built after this point will - # use the new macosx designation. - provDarwin = darwinVersionString.match(provided) - if provDarwin: - dversion = int(provDarwin.group(1)) - macosversion = "%s.%s" % (reqMac.group(1), reqMac.group(2)) - if dversion == 7 and macosversion >= "10.3" or \ - dversion == 8 and macosversion >= "10.4": - return True - # egg isn't macosx or legacy darwin - return False - - # are they the same major version and machine type? - if provMac.group(1) != reqMac.group(1) or \ - provMac.group(3) != reqMac.group(3): - return False - - # is the required OS major update >= the provided one? - if int(provMac.group(2)) > int(reqMac.group(2)): - return False - - return True - - # XXX Linux and other platforms' special cases should go here - return False - - -def run_script(dist_spec, script_name): - """Locate distribution `dist_spec` and run its `script_name` script""" - ns = sys._getframe(1).f_globals - name = ns['__name__'] - ns.clear() - ns['__name__'] = name - require(dist_spec)[0].run_script(script_name, ns) - - -# backward compatibility -run_main = run_script - - -def get_distribution(dist): - """Return a current distribution object for a Requirement or string""" - if isinstance(dist, six.string_types): - dist = Requirement.parse(dist) - if isinstance(dist, Requirement): - dist = get_provider(dist) - if not isinstance(dist, Distribution): - raise TypeError("Expected string, Requirement, or Distribution", dist) - return dist - - -def load_entry_point(dist, group, name): - """Return `name` entry point of `group` for `dist` or raise ImportError""" - return get_distribution(dist).load_entry_point(group, name) - - -def get_entry_map(dist, group=None): - """Return the entry point map for `group`, or the full entry map""" - return get_distribution(dist).get_entry_map(group) - - -def get_entry_info(dist, group, name): - """Return the EntryPoint object for `group`+`name`, or ``None``""" - return get_distribution(dist).get_entry_info(group, name) - - -class IMetadataProvider: - def has_metadata(name): - """Does the package's distribution contain the named metadata?""" - - def get_metadata(name): - """The named metadata resource as a string""" - - def get_metadata_lines(name): - """Yield named metadata resource as list of non-blank non-comment lines - - Leading and trailing whitespace is stripped from each line, and lines - with ``#`` as the first non-blank character are omitted.""" - - def metadata_isdir(name): - """Is the named metadata a directory? (like ``os.path.isdir()``)""" - - def metadata_listdir(name): - """List of metadata names in the directory (like ``os.listdir()``)""" - - def run_script(script_name, namespace): - """Execute the named script in the supplied namespace dictionary""" - - -class IResourceProvider(IMetadataProvider): - """An object that provides access to package resources""" - - def get_resource_filename(manager, resource_name): - """Return a true filesystem path for `resource_name` - - `manager` must be an ``IResourceManager``""" - - def get_resource_stream(manager, resource_name): - """Return a readable file-like object for `resource_name` - - `manager` must be an ``IResourceManager``""" - - def get_resource_string(manager, resource_name): - """Return a string containing the contents of `resource_name` - - `manager` must be an ``IResourceManager``""" - - def has_resource(resource_name): - """Does the package contain the named resource?""" - - def resource_isdir(resource_name): - """Is the named resource a directory? (like ``os.path.isdir()``)""" - - def resource_listdir(resource_name): - """List of resource names in the directory (like ``os.listdir()``)""" - - -class WorkingSet: - """A collection of active distributions on sys.path (or a similar list)""" - - def __init__(self, entries=None): - """Create working set from list of path entries (default=sys.path)""" - self.entries = [] - self.entry_keys = {} - self.by_key = {} - self.callbacks = [] - - if entries is None: - entries = sys.path - - for entry in entries: - self.add_entry(entry) - - @classmethod - def _build_master(cls): - """ - Prepare the master working set. - """ - ws = cls() - try: - from __main__ import __requires__ - except ImportError: - # The main program does not list any requirements - return ws - - # ensure the requirements are met - try: - ws.require(__requires__) - except VersionConflict: - return cls._build_from_requirements(__requires__) - - return ws - - @classmethod - def _build_from_requirements(cls, req_spec): - """ - Build a working set from a requirement spec. Rewrites sys.path. - """ - # try it without defaults already on sys.path - # by starting with an empty path - ws = cls([]) - reqs = parse_requirements(req_spec) - dists = ws.resolve(reqs, Environment()) - for dist in dists: - ws.add(dist) - - # add any missing entries from sys.path - for entry in sys.path: - if entry not in ws.entries: - ws.add_entry(entry) - - # then copy back to sys.path - sys.path[:] = ws.entries - return ws - - def add_entry(self, entry): - """Add a path item to ``.entries``, finding any distributions on it - - ``find_distributions(entry, True)`` is used to find distributions - corresponding to the path entry, and they are added. `entry` is - always appended to ``.entries``, even if it is already present. - (This is because ``sys.path`` can contain the same value more than - once, and the ``.entries`` of the ``sys.path`` WorkingSet should always - equal ``sys.path``.) - """ - self.entry_keys.setdefault(entry, []) - self.entries.append(entry) - for dist in find_distributions(entry, True): - self.add(dist, entry, False) - - def __contains__(self, dist): - """True if `dist` is the active distribution for its project""" - return self.by_key.get(dist.key) == dist - - def find(self, req): - """Find a distribution matching requirement `req` - - If there is an active distribution for the requested project, this - returns it as long as it meets the version requirement specified by - `req`. But, if there is an active distribution for the project and it - does *not* meet the `req` requirement, ``VersionConflict`` is raised. - If there is no active distribution for the requested project, ``None`` - is returned. - """ - dist = self.by_key.get(req.key) - if dist is not None and dist not in req: - # XXX add more info - raise VersionConflict(dist, req) - return dist - - def iter_entry_points(self, group, name=None): - """Yield entry point objects from `group` matching `name` - - If `name` is None, yields all entry points in `group` from all - distributions in the working set, otherwise only ones matching - both `group` and `name` are yielded (in distribution order). - """ - return ( - entry - for dist in self - for entry in dist.get_entry_map(group).values() - if name is None or name == entry.name - ) - - def run_script(self, requires, script_name): - """Locate distribution for `requires` and run `script_name` script""" - ns = sys._getframe(1).f_globals - name = ns['__name__'] - ns.clear() - ns['__name__'] = name - self.require(requires)[0].run_script(script_name, ns) - - def __iter__(self): - """Yield distributions for non-duplicate projects in the working set - - The yield order is the order in which the items' path entries were - added to the working set. - """ - seen = {} - for item in self.entries: - if item not in self.entry_keys: - # workaround a cache issue - continue - - for key in self.entry_keys[item]: - if key not in seen: - seen[key] = 1 - yield self.by_key[key] - - def add(self, dist, entry=None, insert=True, replace=False): - """Add `dist` to working set, associated with `entry` - - If `entry` is unspecified, it defaults to the ``.location`` of `dist`. - On exit from this routine, `entry` is added to the end of the working - set's ``.entries`` (if it wasn't already present). - - `dist` is only added to the working set if it's for a project that - doesn't already have a distribution in the set, unless `replace=True`. - If it's added, any callbacks registered with the ``subscribe()`` method - will be called. - """ - if insert: - dist.insert_on(self.entries, entry, replace=replace) - - if entry is None: - entry = dist.location - keys = self.entry_keys.setdefault(entry, []) - keys2 = self.entry_keys.setdefault(dist.location, []) - if not replace and dist.key in self.by_key: - # ignore hidden distros - return - - self.by_key[dist.key] = dist - if dist.key not in keys: - keys.append(dist.key) - if dist.key not in keys2: - keys2.append(dist.key) - self._added_new(dist) - - def resolve(self, requirements, env=None, installer=None, - replace_conflicting=False, extras=None): - """List all distributions needed to (recursively) meet `requirements` - - `requirements` must be a sequence of ``Requirement`` objects. `env`, - if supplied, should be an ``Environment`` instance. If - not supplied, it defaults to all distributions available within any - entry or distribution in the working set. `installer`, if supplied, - will be invoked with each requirement that cannot be met by an - already-installed distribution; it should return a ``Distribution`` or - ``None``. - - Unless `replace_conflicting=True`, raises a VersionConflict exception - if - any requirements are found on the path that have the correct name but - the wrong version. Otherwise, if an `installer` is supplied it will be - invoked to obtain the correct version of the requirement and activate - it. - - `extras` is a list of the extras to be used with these requirements. - This is important because extra requirements may look like `my_req; - extra = "my_extra"`, which would otherwise be interpreted as a purely - optional requirement. Instead, we want to be able to assert that these - requirements are truly required. - """ - - # set up the stack - requirements = list(requirements)[::-1] - # set of processed requirements - processed = {} - # key -> dist - best = {} - to_activate = [] - - req_extras = _ReqExtras() - - # Mapping of requirement to set of distributions that required it; - # useful for reporting info about conflicts. - required_by = collections.defaultdict(set) - - while requirements: - # process dependencies breadth-first - req = requirements.pop(0) - if req in processed: - # Ignore cyclic or redundant dependencies - continue - - if not req_extras.markers_pass(req, extras): - continue - - dist = best.get(req.key) - if dist is None: - # Find the best distribution and add it to the map - dist = self.by_key.get(req.key) - if dist is None or (dist not in req and replace_conflicting): - ws = self - if env is None: - if dist is None: - env = Environment(self.entries) - else: - # Use an empty environment and workingset to avoid - # any further conflicts with the conflicting - # distribution - env = Environment([]) - ws = WorkingSet([]) - dist = best[req.key] = env.best_match( - req, ws, installer, - replace_conflicting=replace_conflicting - ) - if dist is None: - requirers = required_by.get(req, None) - raise DistributionNotFound(req, requirers) - to_activate.append(dist) - if dist not in req: - # Oops, the "best" so far conflicts with a dependency - dependent_req = required_by[req] - raise VersionConflict(dist, req).with_context(dependent_req) - - # push the new requirements onto the stack - new_requirements = dist.requires(req.extras)[::-1] - requirements.extend(new_requirements) - - # Register the new requirements needed by req - for new_requirement in new_requirements: - required_by[new_requirement].add(req.project_name) - req_extras[new_requirement] = req.extras - - processed[req] = True - - # return list of distros to activate - return to_activate - - def find_plugins( - self, plugin_env, full_env=None, installer=None, fallback=True): - """Find all activatable distributions in `plugin_env` - - Example usage:: - - distributions, errors = working_set.find_plugins( - Environment(plugin_dirlist) - ) - # add plugins+libs to sys.path - map(working_set.add, distributions) - # display errors - print('Could not load', errors) - - The `plugin_env` should be an ``Environment`` instance that contains - only distributions that are in the project's "plugin directory" or - directories. The `full_env`, if supplied, should be an ``Environment`` - contains all currently-available distributions. If `full_env` is not - supplied, one is created automatically from the ``WorkingSet`` this - method is called on, which will typically mean that every directory on - ``sys.path`` will be scanned for distributions. - - `installer` is a standard installer callback as used by the - ``resolve()`` method. The `fallback` flag indicates whether we should - attempt to resolve older versions of a plugin if the newest version - cannot be resolved. - - This method returns a 2-tuple: (`distributions`, `error_info`), where - `distributions` is a list of the distributions found in `plugin_env` - that were loadable, along with any other distributions that are needed - to resolve their dependencies. `error_info` is a dictionary mapping - unloadable plugin distributions to an exception instance describing the - error that occurred. Usually this will be a ``DistributionNotFound`` or - ``VersionConflict`` instance. - """ - - plugin_projects = list(plugin_env) - # scan project names in alphabetic order - plugin_projects.sort() - - error_info = {} - distributions = {} - - if full_env is None: - env = Environment(self.entries) - env += plugin_env - else: - env = full_env + plugin_env - - shadow_set = self.__class__([]) - # put all our entries in shadow_set - list(map(shadow_set.add, self)) - - for project_name in plugin_projects: - - for dist in plugin_env[project_name]: - - req = [dist.as_requirement()] - - try: - resolvees = shadow_set.resolve(req, env, installer) - - except ResolutionError as v: - # save error info - error_info[dist] = v - if fallback: - # try the next older version of project - continue - else: - # give up on this project, keep going - break - - else: - list(map(shadow_set.add, resolvees)) - distributions.update(dict.fromkeys(resolvees)) - - # success, no need to try any more versions of this project - break - - distributions = list(distributions) - distributions.sort() - - return distributions, error_info - - def require(self, *requirements): - """Ensure that distributions matching `requirements` are activated - - `requirements` must be a string or a (possibly-nested) sequence - thereof, specifying the distributions and versions required. The - return value is a sequence of the distributions that needed to be - activated to fulfill the requirements; all relevant distributions are - included, even if they were already activated in this working set. - """ - needed = self.resolve(parse_requirements(requirements)) - - for dist in needed: - self.add(dist) - - return needed - - def subscribe(self, callback, existing=True): - """Invoke `callback` for all distributions - - If `existing=True` (default), - call on all existing ones, as well. - """ - if callback in self.callbacks: - return - self.callbacks.append(callback) - if not existing: - return - for dist in self: - callback(dist) - - def _added_new(self, dist): - for callback in self.callbacks: - callback(dist) - - def __getstate__(self): - return ( - self.entries[:], self.entry_keys.copy(), self.by_key.copy(), - self.callbacks[:] - ) - - def __setstate__(self, e_k_b_c): - entries, keys, by_key, callbacks = e_k_b_c - self.entries = entries[:] - self.entry_keys = keys.copy() - self.by_key = by_key.copy() - self.callbacks = callbacks[:] - - -class _ReqExtras(dict): - """ - Map each requirement to the extras that demanded it. - """ - - def markers_pass(self, req, extras=None): - """ - Evaluate markers for req against each extra that - demanded it. - - Return False if the req has a marker and fails - evaluation. Otherwise, return True. - """ - extra_evals = ( - req.marker.evaluate({'extra': extra}) - for extra in self.get(req, ()) + (extras or (None,)) - ) - return not req.marker or any(extra_evals) - - -class Environment: - """Searchable snapshot of distributions on a search path""" - - def __init__( - self, search_path=None, platform=get_supported_platform(), - python=PY_MAJOR): - """Snapshot distributions available on a search path - - Any distributions found on `search_path` are added to the environment. - `search_path` should be a sequence of ``sys.path`` items. If not - supplied, ``sys.path`` is used. - - `platform` is an optional string specifying the name of the platform - that platform-specific distributions must be compatible with. If - unspecified, it defaults to the current platform. `python` is an - optional string naming the desired version of Python (e.g. ``'3.6'``); - it defaults to the current version. - - You may explicitly set `platform` (and/or `python`) to ``None`` if you - wish to map *all* distributions, not just those compatible with the - running platform or Python version. - """ - self._distmap = {} - self.platform = platform - self.python = python - self.scan(search_path) - - def can_add(self, dist): - """Is distribution `dist` acceptable for this environment? - - The distribution must match the platform and python version - requirements specified when this environment was created, or False - is returned. - """ - py_compat = ( - self.python is None - or dist.py_version is None - or dist.py_version == self.python - ) - return py_compat and compatible_platforms(dist.platform, self.platform) - - def remove(self, dist): - """Remove `dist` from the environment""" - self._distmap[dist.key].remove(dist) - - def scan(self, search_path=None): - """Scan `search_path` for distributions usable in this environment - - Any distributions found are added to the environment. - `search_path` should be a sequence of ``sys.path`` items. If not - supplied, ``sys.path`` is used. Only distributions conforming to - the platform/python version defined at initialization are added. - """ - if search_path is None: - search_path = sys.path - - for item in search_path: - for dist in find_distributions(item): - self.add(dist) - - def __getitem__(self, project_name): - """Return a newest-to-oldest list of distributions for `project_name` - - Uses case-insensitive `project_name` comparison, assuming all the - project's distributions use their project's name converted to all - lowercase as their key. - - """ - distribution_key = project_name.lower() - return self._distmap.get(distribution_key, []) - - def add(self, dist): - """Add `dist` if we ``can_add()`` it and it has not already been added - """ - if self.can_add(dist) and dist.has_version(): - dists = self._distmap.setdefault(dist.key, []) - if dist not in dists: - dists.append(dist) - dists.sort(key=operator.attrgetter('hashcmp'), reverse=True) - - def best_match( - self, req, working_set, installer=None, replace_conflicting=False): - """Find distribution best matching `req` and usable on `working_set` - - This calls the ``find(req)`` method of the `working_set` to see if a - suitable distribution is already active. (This may raise - ``VersionConflict`` if an unsuitable version of the project is already - active in the specified `working_set`.) If a suitable distribution - isn't active, this method returns the newest distribution in the - environment that meets the ``Requirement`` in `req`. If no suitable - distribution is found, and `installer` is supplied, then the result of - calling the environment's ``obtain(req, installer)`` method will be - returned. - """ - try: - dist = working_set.find(req) - except VersionConflict: - if not replace_conflicting: - raise - dist = None - if dist is not None: - return dist - for dist in self[req.key]: - if dist in req: - return dist - # try to download/install - return self.obtain(req, installer) - - def obtain(self, requirement, installer=None): - """Obtain a distribution matching `requirement` (e.g. via download) - - Obtain a distro that matches requirement (e.g. via download). In the - base ``Environment`` class, this routine just returns - ``installer(requirement)``, unless `installer` is None, in which case - None is returned instead. This method is a hook that allows subclasses - to attempt other ways of obtaining a distribution before falling back - to the `installer` argument.""" - if installer is not None: - return installer(requirement) - - def __iter__(self): - """Yield the unique project names of the available distributions""" - for key in self._distmap.keys(): - if self[key]: - yield key - - def __iadd__(self, other): - """In-place addition of a distribution or environment""" - if isinstance(other, Distribution): - self.add(other) - elif isinstance(other, Environment): - for project in other: - for dist in other[project]: - self.add(dist) - else: - raise TypeError("Can't add %r to environment" % (other,)) - return self - - def __add__(self, other): - """Add an environment or distribution to an environment""" - new = self.__class__([], platform=None, python=None) - for env in self, other: - new += env - return new - - -# XXX backward compatibility -AvailableDistributions = Environment - - -class ExtractionError(RuntimeError): - """An error occurred extracting a resource - - The following attributes are available from instances of this exception: - - manager - The resource manager that raised this exception - - cache_path - The base directory for resource extraction - - original_error - The exception instance that caused extraction to fail - """ - - -class ResourceManager: - """Manage resource extraction and packages""" - extraction_path = None - - def __init__(self): - self.cached_files = {} - - def resource_exists(self, package_or_requirement, resource_name): - """Does the named resource exist?""" - return get_provider(package_or_requirement).has_resource(resource_name) - - def resource_isdir(self, package_or_requirement, resource_name): - """Is the named resource an existing directory?""" - return get_provider(package_or_requirement).resource_isdir( - resource_name - ) - - def resource_filename(self, package_or_requirement, resource_name): - """Return a true filesystem path for specified resource""" - return get_provider(package_or_requirement).get_resource_filename( - self, resource_name - ) - - def resource_stream(self, package_or_requirement, resource_name): - """Return a readable file-like object for specified resource""" - return get_provider(package_or_requirement).get_resource_stream( - self, resource_name - ) - - def resource_string(self, package_or_requirement, resource_name): - """Return specified resource as a string""" - return get_provider(package_or_requirement).get_resource_string( - self, resource_name - ) - - def resource_listdir(self, package_or_requirement, resource_name): - """List the contents of the named resource directory""" - return get_provider(package_or_requirement).resource_listdir( - resource_name - ) - - def extraction_error(self): - """Give an error message for problems extracting file(s)""" - - old_exc = sys.exc_info()[1] - cache_path = self.extraction_path or get_default_cache() - - tmpl = textwrap.dedent(""" - Can't extract file(s) to egg cache - - The following error occurred while trying to extract file(s) - to the Python egg cache: - - {old_exc} - - The Python egg cache directory is currently set to: - - {cache_path} - - Perhaps your account does not have write access to this directory? - You can change the cache directory by setting the PYTHON_EGG_CACHE - environment variable to point to an accessible directory. - """).lstrip() - err = ExtractionError(tmpl.format(**locals())) - err.manager = self - err.cache_path = cache_path - err.original_error = old_exc - raise err - - def get_cache_path(self, archive_name, names=()): - """Return absolute location in cache for `archive_name` and `names` - - The parent directory of the resulting path will be created if it does - not already exist. `archive_name` should be the base filename of the - enclosing egg (which may not be the name of the enclosing zipfile!), - including its ".egg" extension. `names`, if provided, should be a - sequence of path name parts "under" the egg's extraction location. - - This method should only be called by resource providers that need to - obtain an extraction location, and only for names they intend to - extract, as it tracks the generated names for possible cleanup later. - """ - extract_path = self.extraction_path or get_default_cache() - target_path = os.path.join(extract_path, archive_name + '-tmp', *names) - try: - _bypass_ensure_directory(target_path) - except Exception: - self.extraction_error() - - self._warn_unsafe_extraction_path(extract_path) - - self.cached_files[target_path] = 1 - return target_path - - @staticmethod - def _warn_unsafe_extraction_path(path): - """ - If the default extraction path is overridden and set to an insecure - location, such as /tmp, it opens up an opportunity for an attacker to - replace an extracted file with an unauthorized payload. Warn the user - if a known insecure location is used. - - See Distribute #375 for more details. - """ - if os.name == 'nt' and not path.startswith(os.environ['windir']): - # On Windows, permissions are generally restrictive by default - # and temp directories are not writable by other users, so - # bypass the warning. - return - mode = os.stat(path).st_mode - if mode & stat.S_IWOTH or mode & stat.S_IWGRP: - msg = ( - "%s is writable by group/others and vulnerable to attack " - "when " - "used with get_resource_filename. Consider a more secure " - "location (set with .set_extraction_path or the " - "PYTHON_EGG_CACHE environment variable)." % path - ) - warnings.warn(msg, UserWarning) - - def postprocess(self, tempname, filename): - """Perform any platform-specific postprocessing of `tempname` - - This is where Mac header rewrites should be done; other platforms don't - have anything special they should do. - - Resource providers should call this method ONLY after successfully - extracting a compressed resource. They must NOT call it on resources - that are already in the filesystem. - - `tempname` is the current (temporary) name of the file, and `filename` - is the name it will be renamed to by the caller after this routine - returns. - """ - - if os.name == 'posix': - # Make the resource executable - mode = ((os.stat(tempname).st_mode) | 0o555) & 0o7777 - os.chmod(tempname, mode) - - def set_extraction_path(self, path): - """Set the base path where resources will be extracted to, if needed. - - If you do not call this routine before any extractions take place, the - path defaults to the return value of ``get_default_cache()``. (Which - is based on the ``PYTHON_EGG_CACHE`` environment variable, with various - platform-specific fallbacks. See that routine's documentation for more - details.) - - Resources are extracted to subdirectories of this path based upon - information given by the ``IResourceProvider``. You may set this to a - temporary directory, but then you must call ``cleanup_resources()`` to - delete the extracted files when done. There is no guarantee that - ``cleanup_resources()`` will be able to remove all extracted files. - - (Note: you may not change the extraction path for a given resource - manager once resources have been extracted, unless you first call - ``cleanup_resources()``.) - """ - if self.cached_files: - raise ValueError( - "Can't change extraction path, files already extracted" - ) - - self.extraction_path = path - - def cleanup_resources(self, force=False): - """ - Delete all extracted resource files and directories, returning a list - of the file and directory names that could not be successfully removed. - This function does not have any concurrency protection, so it should - generally only be called when the extraction path is a temporary - directory exclusive to a single process. This method is not - automatically called; you must call it explicitly or register it as an - ``atexit`` function if you wish to ensure cleanup of a temporary - directory used for extractions. - """ - # XXX - - -def get_default_cache(): - """ - Return the ``PYTHON_EGG_CACHE`` environment variable - or a platform-relevant user cache dir for an app - named "Python-Eggs". - """ - return ( - os.environ.get('PYTHON_EGG_CACHE') - or appdirs.user_cache_dir(appname='Python-Eggs') - ) - - -def safe_name(name): - """Convert an arbitrary string to a standard distribution name - - Any runs of non-alphanumeric/. characters are replaced with a single '-'. - """ - return re.sub('[^A-Za-z0-9.]+', '-', name) - - -def safe_version(version): - """ - Convert an arbitrary string to a standard version string - """ - try: - # normalize the version - return str(packaging.version.Version(version)) - except packaging.version.InvalidVersion: - version = version.replace(' ', '.') - return re.sub('[^A-Za-z0-9.]+', '-', version) - - -def safe_extra(extra): - """Convert an arbitrary string to a standard 'extra' name - - Any runs of non-alphanumeric characters are replaced with a single '_', - and the result is always lowercased. - """ - return re.sub('[^A-Za-z0-9.-]+', '_', extra).lower() - - -def to_filename(name): - """Convert a project or version name to its filename-escaped form - - Any '-' characters are currently replaced with '_'. - """ - return name.replace('-', '_') - - -def invalid_marker(text): - """ - Validate text as a PEP 508 environment marker; return an exception - if invalid or False otherwise. - """ - try: - evaluate_marker(text) - except SyntaxError as e: - e.filename = None - e.lineno = None - return e - return False - - -def evaluate_marker(text, extra=None): - """ - Evaluate a PEP 508 environment marker. - Return a boolean indicating the marker result in this environment. - Raise SyntaxError if marker is invalid. - - This implementation uses the 'pyparsing' module. - """ - try: - marker = packaging.markers.Marker(text) - return marker.evaluate() - except packaging.markers.InvalidMarker as e: - raise SyntaxError(e) - - -class NullProvider: - """Try to implement resources and metadata for arbitrary PEP 302 loaders""" - - egg_name = None - egg_info = None - loader = None - - def __init__(self, module): - self.loader = getattr(module, '__loader__', None) - self.module_path = os.path.dirname(getattr(module, '__file__', '')) - - def get_resource_filename(self, manager, resource_name): - return self._fn(self.module_path, resource_name) - - def get_resource_stream(self, manager, resource_name): - return io.BytesIO(self.get_resource_string(manager, resource_name)) - - def get_resource_string(self, manager, resource_name): - return self._get(self._fn(self.module_path, resource_name)) - - def has_resource(self, resource_name): - return self._has(self._fn(self.module_path, resource_name)) - - def _get_metadata_path(self, name): - return self._fn(self.egg_info, name) - - def has_metadata(self, name): - if not self.egg_info: - return self.egg_info - - path = self._get_metadata_path(name) - return self._has(path) - - def get_metadata(self, name): - if not self.egg_info: - return "" - path = self._get_metadata_path(name) - value = self._get(path) - if six.PY2: - return value - try: - return value.decode('utf-8') - except UnicodeDecodeError as exc: - # Include the path in the error message to simplify - # troubleshooting, and without changing the exception type. - exc.reason += ' in {} file at path: {}'.format(name, path) - raise - - def get_metadata_lines(self, name): - return yield_lines(self.get_metadata(name)) - - def resource_isdir(self, resource_name): - return self._isdir(self._fn(self.module_path, resource_name)) - - def metadata_isdir(self, name): - return self.egg_info and self._isdir(self._fn(self.egg_info, name)) - - def resource_listdir(self, resource_name): - return self._listdir(self._fn(self.module_path, resource_name)) - - def metadata_listdir(self, name): - if self.egg_info: - return self._listdir(self._fn(self.egg_info, name)) - return [] - - def run_script(self, script_name, namespace): - script = 'scripts/' + script_name - if not self.has_metadata(script): - raise ResolutionError( - "Script {script!r} not found in metadata at {self.egg_info!r}" - .format(**locals()), - ) - script_text = self.get_metadata(script).replace('\r\n', '\n') - script_text = script_text.replace('\r', '\n') - script_filename = self._fn(self.egg_info, script) - namespace['__file__'] = script_filename - if os.path.exists(script_filename): - source = open(script_filename).read() - code = compile(source, script_filename, 'exec') - exec(code, namespace, namespace) - else: - from linecache import cache - cache[script_filename] = ( - len(script_text), 0, script_text.split('\n'), script_filename - ) - script_code = compile(script_text, script_filename, 'exec') - exec(script_code, namespace, namespace) - - def _has(self, path): - raise NotImplementedError( - "Can't perform this operation for unregistered loader type" - ) - - def _isdir(self, path): - raise NotImplementedError( - "Can't perform this operation for unregistered loader type" - ) - - def _listdir(self, path): - raise NotImplementedError( - "Can't perform this operation for unregistered loader type" - ) - - def _fn(self, base, resource_name): - self._validate_resource_path(resource_name) - if resource_name: - return os.path.join(base, *resource_name.split('/')) - return base - - @staticmethod - def _validate_resource_path(path): - """ - Validate the resource paths according to the docs. - https://setuptools.readthedocs.io/en/latest/pkg_resources.html#basic-resource-access - - >>> warned = getfixture('recwarn') - >>> warnings.simplefilter('always') - >>> vrp = NullProvider._validate_resource_path - >>> vrp('foo/bar.txt') - >>> bool(warned) - False - >>> vrp('../foo/bar.txt') - >>> bool(warned) - True - >>> warned.clear() - >>> vrp('/foo/bar.txt') - >>> bool(warned) - True - >>> vrp('foo/../../bar.txt') - >>> bool(warned) - True - >>> warned.clear() - >>> vrp('foo/f../bar.txt') - >>> bool(warned) - False - - Windows path separators are straight-up disallowed. - >>> vrp(r'\\foo/bar.txt') - Traceback (most recent call last): - ... - ValueError: Use of .. or absolute path in a resource path \ -is not allowed. - - >>> vrp(r'C:\\foo/bar.txt') - Traceback (most recent call last): - ... - ValueError: Use of .. or absolute path in a resource path \ -is not allowed. - - Blank values are allowed - - >>> vrp('') - >>> bool(warned) - False - - Non-string values are not. - - >>> vrp(None) - Traceback (most recent call last): - ... - AttributeError: ... - """ - invalid = ( - os.path.pardir in path.split(posixpath.sep) or - posixpath.isabs(path) or - ntpath.isabs(path) - ) - if not invalid: - return - - msg = "Use of .. or absolute path in a resource path is not allowed." - - # Aggressively disallow Windows absolute paths - if ntpath.isabs(path) and not posixpath.isabs(path): - raise ValueError(msg) - - # for compatibility, warn; in future - # raise ValueError(msg) - warnings.warn( - msg[:-1] + " and will raise exceptions in a future release.", - DeprecationWarning, - stacklevel=4, - ) - - def _get(self, path): - if hasattr(self.loader, 'get_data'): - return self.loader.get_data(path) - raise NotImplementedError( - "Can't perform this operation for loaders without 'get_data()'" - ) - - -register_loader_type(object, NullProvider) - - -class EggProvider(NullProvider): - """Provider based on a virtual filesystem""" - - def __init__(self, module): - NullProvider.__init__(self, module) - self._setup_prefix() - - def _setup_prefix(self): - # we assume here that our metadata may be nested inside a "basket" - # of multiple eggs; that's why we use module_path instead of .archive - path = self.module_path - old = None - while path != old: - if _is_egg_path(path): - self.egg_name = os.path.basename(path) - self.egg_info = os.path.join(path, 'EGG-INFO') - self.egg_root = path - break - old = path - path, base = os.path.split(path) - - -class DefaultProvider(EggProvider): - """Provides access to package resources in the filesystem""" - - def _has(self, path): - return os.path.exists(path) - - def _isdir(self, path): - return os.path.isdir(path) - - def _listdir(self, path): - return os.listdir(path) - - def get_resource_stream(self, manager, resource_name): - return open(self._fn(self.module_path, resource_name), 'rb') - - def _get(self, path): - with open(path, 'rb') as stream: - return stream.read() - - @classmethod - def _register(cls): - loader_names = 'SourceFileLoader', 'SourcelessFileLoader', - for name in loader_names: - loader_cls = getattr(importlib_machinery, name, type(None)) - register_loader_type(loader_cls, cls) - - -DefaultProvider._register() - - -class EmptyProvider(NullProvider): - """Provider that returns nothing for all requests""" - - module_path = None - - _isdir = _has = lambda self, path: False - - def _get(self, path): - return '' - - def _listdir(self, path): - return [] - - def __init__(self): - pass - - -empty_provider = EmptyProvider() - - -class ZipManifests(dict): - """ - zip manifest builder - """ - - @classmethod - def build(cls, path): - """ - Build a dictionary similar to the zipimport directory - caches, except instead of tuples, store ZipInfo objects. - - Use a platform-specific path separator (os.sep) for the path keys - for compatibility with pypy on Windows. - """ - with zipfile.ZipFile(path) as zfile: - items = ( - ( - name.replace('/', os.sep), - zfile.getinfo(name), - ) - for name in zfile.namelist() - ) - return dict(items) - - load = build - - -class MemoizedZipManifests(ZipManifests): - """ - Memoized zipfile manifests. - """ - manifest_mod = collections.namedtuple('manifest_mod', 'manifest mtime') - - def load(self, path): - """ - Load a manifest at path or return a suitable manifest already loaded. - """ - path = os.path.normpath(path) - mtime = os.stat(path).st_mtime - - if path not in self or self[path].mtime != mtime: - manifest = self.build(path) - self[path] = self.manifest_mod(manifest, mtime) - - return self[path].manifest - - -class ZipProvider(EggProvider): - """Resource support for zips and eggs""" - - eagers = None - _zip_manifests = MemoizedZipManifests() - - def __init__(self, module): - EggProvider.__init__(self, module) - self.zip_pre = self.loader.archive + os.sep - - def _zipinfo_name(self, fspath): - # Convert a virtual filename (full path to file) into a zipfile subpath - # usable with the zipimport directory cache for our target archive - fspath = fspath.rstrip(os.sep) - if fspath == self.loader.archive: - return '' - if fspath.startswith(self.zip_pre): - return fspath[len(self.zip_pre):] - raise AssertionError( - "%s is not a subpath of %s" % (fspath, self.zip_pre) - ) - - def _parts(self, zip_path): - # Convert a zipfile subpath into an egg-relative path part list. - # pseudo-fs path - fspath = self.zip_pre + zip_path - if fspath.startswith(self.egg_root + os.sep): - return fspath[len(self.egg_root) + 1:].split(os.sep) - raise AssertionError( - "%s is not a subpath of %s" % (fspath, self.egg_root) - ) - - @property - def zipinfo(self): - return self._zip_manifests.load(self.loader.archive) - - def get_resource_filename(self, manager, resource_name): - if not self.egg_name: - raise NotImplementedError( - "resource_filename() only supported for .egg, not .zip" - ) - # no need to lock for extraction, since we use temp names - zip_path = self._resource_to_zip(resource_name) - eagers = self._get_eager_resources() - if '/'.join(self._parts(zip_path)) in eagers: - for name in eagers: - self._extract_resource(manager, self._eager_to_zip(name)) - return self._extract_resource(manager, zip_path) - - @staticmethod - def _get_date_and_size(zip_stat): - size = zip_stat.file_size - # ymdhms+wday, yday, dst - date_time = zip_stat.date_time + (0, 0, -1) - # 1980 offset already done - timestamp = time.mktime(date_time) - return timestamp, size - - def _extract_resource(self, manager, zip_path): - - if zip_path in self._index(): - for name in self._index()[zip_path]: - last = self._extract_resource( - manager, os.path.join(zip_path, name) - ) - # return the extracted directory name - return os.path.dirname(last) - - timestamp, size = self._get_date_and_size(self.zipinfo[zip_path]) - - if not WRITE_SUPPORT: - raise IOError('"os.rename" and "os.unlink" are not supported ' - 'on this platform') - try: - - real_path = manager.get_cache_path( - self.egg_name, self._parts(zip_path) - ) - - if self._is_current(real_path, zip_path): - return real_path - - outf, tmpnam = _mkstemp( - ".$extract", - dir=os.path.dirname(real_path), - ) - os.write(outf, self.loader.get_data(zip_path)) - os.close(outf) - utime(tmpnam, (timestamp, timestamp)) - manager.postprocess(tmpnam, real_path) - - try: - rename(tmpnam, real_path) - - except os.error: - if os.path.isfile(real_path): - if self._is_current(real_path, zip_path): - # the file became current since it was checked above, - # so proceed. - return real_path - # Windows, del old file and retry - elif os.name == 'nt': - unlink(real_path) - rename(tmpnam, real_path) - return real_path - raise - - except os.error: - # report a user-friendly error - manager.extraction_error() - - return real_path - - def _is_current(self, file_path, zip_path): - """ - Return True if the file_path is current for this zip_path - """ - timestamp, size = self._get_date_and_size(self.zipinfo[zip_path]) - if not os.path.isfile(file_path): - return False - stat = os.stat(file_path) - if stat.st_size != size or stat.st_mtime != timestamp: - return False - # check that the contents match - zip_contents = self.loader.get_data(zip_path) - with open(file_path, 'rb') as f: - file_contents = f.read() - return zip_contents == file_contents - - def _get_eager_resources(self): - if self.eagers is None: - eagers = [] - for name in ('native_libs.txt', 'eager_resources.txt'): - if self.has_metadata(name): - eagers.extend(self.get_metadata_lines(name)) - self.eagers = eagers - return self.eagers - - def _index(self): - try: - return self._dirindex - except AttributeError: - ind = {} - for path in self.zipinfo: - parts = path.split(os.sep) - while parts: - parent = os.sep.join(parts[:-1]) - if parent in ind: - ind[parent].append(parts[-1]) - break - else: - ind[parent] = [parts.pop()] - self._dirindex = ind - return ind - - def _has(self, fspath): - zip_path = self._zipinfo_name(fspath) - return zip_path in self.zipinfo or zip_path in self._index() - - def _isdir(self, fspath): - return self._zipinfo_name(fspath) in self._index() - - def _listdir(self, fspath): - return list(self._index().get(self._zipinfo_name(fspath), ())) - - def _eager_to_zip(self, resource_name): - return self._zipinfo_name(self._fn(self.egg_root, resource_name)) - - def _resource_to_zip(self, resource_name): - return self._zipinfo_name(self._fn(self.module_path, resource_name)) - - -register_loader_type(zipimport.zipimporter, ZipProvider) - - -class FileMetadata(EmptyProvider): - """Metadata handler for standalone PKG-INFO files - - Usage:: - - metadata = FileMetadata("/path/to/PKG-INFO") - - This provider rejects all data and metadata requests except for PKG-INFO, - which is treated as existing, and will be the contents of the file at - the provided location. - """ - - def __init__(self, path): - self.path = path - - def _get_metadata_path(self, name): - return self.path - - def has_metadata(self, name): - return name == 'PKG-INFO' and os.path.isfile(self.path) - - def get_metadata(self, name): - if name != 'PKG-INFO': - raise KeyError("No metadata except PKG-INFO is available") - - with io.open(self.path, encoding='utf-8', errors="replace") as f: - metadata = f.read() - self._warn_on_replacement(metadata) - return metadata - - def _warn_on_replacement(self, metadata): - # Python 2.7 compat for: replacement_char = '�' - replacement_char = b'\xef\xbf\xbd'.decode('utf-8') - if replacement_char in metadata: - tmpl = "{self.path} could not be properly decoded in UTF-8" - msg = tmpl.format(**locals()) - warnings.warn(msg) - - def get_metadata_lines(self, name): - return yield_lines(self.get_metadata(name)) - - -class PathMetadata(DefaultProvider): - """Metadata provider for egg directories - - Usage:: - - # Development eggs: - - egg_info = "/path/to/PackageName.egg-info" - base_dir = os.path.dirname(egg_info) - metadata = PathMetadata(base_dir, egg_info) - dist_name = os.path.splitext(os.path.basename(egg_info))[0] - dist = Distribution(basedir, project_name=dist_name, metadata=metadata) - - # Unpacked egg directories: - - egg_path = "/path/to/PackageName-ver-pyver-etc.egg" - metadata = PathMetadata(egg_path, os.path.join(egg_path,'EGG-INFO')) - dist = Distribution.from_filename(egg_path, metadata=metadata) - """ - - def __init__(self, path, egg_info): - self.module_path = path - self.egg_info = egg_info - - -class EggMetadata(ZipProvider): - """Metadata provider for .egg files""" - - def __init__(self, importer): - """Create a metadata provider from a zipimporter""" - - self.zip_pre = importer.archive + os.sep - self.loader = importer - if importer.prefix: - self.module_path = os.path.join(importer.archive, importer.prefix) - else: - self.module_path = importer.archive - self._setup_prefix() - - -_declare_state('dict', _distribution_finders={}) - - -def register_finder(importer_type, distribution_finder): - """Register `distribution_finder` to find distributions in sys.path items - - `importer_type` is the type or class of a PEP 302 "Importer" (sys.path item - handler), and `distribution_finder` is a callable that, passed a path - item and the importer instance, yields ``Distribution`` instances found on - that path item. See ``pkg_resources.find_on_path`` for an example.""" - _distribution_finders[importer_type] = distribution_finder - - -def find_distributions(path_item, only=False): - """Yield distributions accessible via `path_item`""" - importer = get_importer(path_item) - finder = _find_adapter(_distribution_finders, importer) - return finder(importer, path_item, only) - - -def find_eggs_in_zip(importer, path_item, only=False): - """ - Find eggs in zip files; possibly multiple nested eggs. - """ - if importer.archive.endswith('.whl'): - # wheels are not supported with this finder - # they don't have PKG-INFO metadata, and won't ever contain eggs - return - metadata = EggMetadata(importer) - if metadata.has_metadata('PKG-INFO'): - yield Distribution.from_filename(path_item, metadata=metadata) - if only: - # don't yield nested distros - return - for subitem in metadata.resource_listdir(''): - if _is_egg_path(subitem): - subpath = os.path.join(path_item, subitem) - dists = find_eggs_in_zip(zipimport.zipimporter(subpath), subpath) - for dist in dists: - yield dist - elif subitem.lower().endswith('.dist-info'): - subpath = os.path.join(path_item, subitem) - submeta = EggMetadata(zipimport.zipimporter(subpath)) - submeta.egg_info = subpath - yield Distribution.from_location(path_item, subitem, submeta) - - -register_finder(zipimport.zipimporter, find_eggs_in_zip) - - -def find_nothing(importer, path_item, only=False): - return () - - -register_finder(object, find_nothing) - - -def _by_version_descending(names): - """ - Given a list of filenames, return them in descending order - by version number. - - >>> names = 'bar', 'foo', 'Python-2.7.10.egg', 'Python-2.7.2.egg' - >>> _by_version_descending(names) - ['Python-2.7.10.egg', 'Python-2.7.2.egg', 'foo', 'bar'] - >>> names = 'Setuptools-1.2.3b1.egg', 'Setuptools-1.2.3.egg' - >>> _by_version_descending(names) - ['Setuptools-1.2.3.egg', 'Setuptools-1.2.3b1.egg'] - >>> names = 'Setuptools-1.2.3b1.egg', 'Setuptools-1.2.3.post1.egg' - >>> _by_version_descending(names) - ['Setuptools-1.2.3.post1.egg', 'Setuptools-1.2.3b1.egg'] - """ - def _by_version(name): - """ - Parse each component of the filename - """ - name, ext = os.path.splitext(name) - parts = itertools.chain(name.split('-'), [ext]) - return [packaging.version.parse(part) for part in parts] - - return sorted(names, key=_by_version, reverse=True) - - -def find_on_path(importer, path_item, only=False): - """Yield distributions accessible on a sys.path directory""" - path_item = _normalize_cached(path_item) - - if _is_unpacked_egg(path_item): - yield Distribution.from_filename( - path_item, metadata=PathMetadata( - path_item, os.path.join(path_item, 'EGG-INFO') - ) - ) - return - - entries = safe_listdir(path_item) - - # for performance, before sorting by version, - # screen entries for only those that will yield - # distributions - filtered = ( - entry - for entry in entries - if dist_factory(path_item, entry, only) - ) - - # scan for .egg and .egg-info in directory - path_item_entries = _by_version_descending(filtered) - for entry in path_item_entries: - fullpath = os.path.join(path_item, entry) - factory = dist_factory(path_item, entry, only) - for dist in factory(fullpath): - yield dist - - -def dist_factory(path_item, entry, only): - """ - Return a dist_factory for a path_item and entry - """ - lower = entry.lower() - is_meta = any(map(lower.endswith, ('.egg-info', '.dist-info'))) - return ( - distributions_from_metadata - if is_meta else - find_distributions - if not only and _is_egg_path(entry) else - resolve_egg_link - if not only and lower.endswith('.egg-link') else - NoDists() - ) - - -class NoDists: - """ - >>> bool(NoDists()) - False - - >>> list(NoDists()('anything')) - [] - """ - def __bool__(self): - return False - if six.PY2: - __nonzero__ = __bool__ - - def __call__(self, fullpath): - return iter(()) - - -def safe_listdir(path): - """ - Attempt to list contents of path, but suppress some exceptions. - """ - try: - return os.listdir(path) - except (PermissionError, NotADirectoryError): - pass - except OSError as e: - # Ignore the directory if does not exist, not a directory or - # permission denied - ignorable = ( - e.errno in (errno.ENOTDIR, errno.EACCES, errno.ENOENT) - # Python 2 on Windows needs to be handled this way :( - or getattr(e, "winerror", None) == 267 - ) - if not ignorable: - raise - return () - - -def distributions_from_metadata(path): - root = os.path.dirname(path) - if os.path.isdir(path): - if len(os.listdir(path)) == 0: - # empty metadata dir; skip - return - metadata = PathMetadata(root, path) - else: - metadata = FileMetadata(path) - entry = os.path.basename(path) - yield Distribution.from_location( - root, entry, metadata, precedence=DEVELOP_DIST, - ) - - -def non_empty_lines(path): - """ - Yield non-empty lines from file at path - """ - with open(path) as f: - for line in f: - line = line.strip() - if line: - yield line - - -def resolve_egg_link(path): - """ - Given a path to an .egg-link, resolve distributions - present in the referenced path. - """ - referenced_paths = non_empty_lines(path) - resolved_paths = ( - os.path.join(os.path.dirname(path), ref) - for ref in referenced_paths - ) - dist_groups = map(find_distributions, resolved_paths) - return next(dist_groups, ()) - - -register_finder(pkgutil.ImpImporter, find_on_path) - -if hasattr(importlib_machinery, 'FileFinder'): - register_finder(importlib_machinery.FileFinder, find_on_path) - -_declare_state('dict', _namespace_handlers={}) -_declare_state('dict', _namespace_packages={}) - - -def register_namespace_handler(importer_type, namespace_handler): - """Register `namespace_handler` to declare namespace packages - - `importer_type` is the type or class of a PEP 302 "Importer" (sys.path item - handler), and `namespace_handler` is a callable like this:: - - def namespace_handler(importer, path_entry, moduleName, module): - # return a path_entry to use for child packages - - Namespace handlers are only called if the importer object has already - agreed that it can handle the relevant path item, and they should only - return a subpath if the module __path__ does not already contain an - equivalent subpath. For an example namespace handler, see - ``pkg_resources.file_ns_handler``. - """ - _namespace_handlers[importer_type] = namespace_handler - - -def _handle_ns(packageName, path_item): - """Ensure that named package includes a subpath of path_item (if needed)""" - - importer = get_importer(path_item) - if importer is None: - return None - - # capture warnings due to #1111 - with warnings.catch_warnings(): - warnings.simplefilter("ignore") - loader = importer.find_module(packageName) - - if loader is None: - return None - module = sys.modules.get(packageName) - if module is None: - module = sys.modules[packageName] = types.ModuleType(packageName) - module.__path__ = [] - _set_parent_ns(packageName) - elif not hasattr(module, '__path__'): - raise TypeError("Not a package:", packageName) - handler = _find_adapter(_namespace_handlers, importer) - subpath = handler(importer, path_item, packageName, module) - if subpath is not None: - path = module.__path__ - path.append(subpath) - loader.load_module(packageName) - _rebuild_mod_path(path, packageName, module) - return subpath - - -def _rebuild_mod_path(orig_path, package_name, module): - """ - Rebuild module.__path__ ensuring that all entries are ordered - corresponding to their sys.path order - """ - sys_path = [_normalize_cached(p) for p in sys.path] - - def safe_sys_path_index(entry): - """ - Workaround for #520 and #513. - """ - try: - return sys_path.index(entry) - except ValueError: - return float('inf') - - def position_in_sys_path(path): - """ - Return the ordinal of the path based on its position in sys.path - """ - path_parts = path.split(os.sep) - module_parts = package_name.count('.') + 1 - parts = path_parts[:-module_parts] - return safe_sys_path_index(_normalize_cached(os.sep.join(parts))) - - new_path = sorted(orig_path, key=position_in_sys_path) - new_path = [_normalize_cached(p) for p in new_path] - - if isinstance(module.__path__, list): - module.__path__[:] = new_path - else: - module.__path__ = new_path - - -def declare_namespace(packageName): - """Declare that package 'packageName' is a namespace package""" - - _imp.acquire_lock() - try: - if packageName in _namespace_packages: - return - - path = sys.path - parent, _, _ = packageName.rpartition('.') - - if parent: - declare_namespace(parent) - if parent not in _namespace_packages: - __import__(parent) - try: - path = sys.modules[parent].__path__ - except AttributeError: - raise TypeError("Not a package:", parent) - - # Track what packages are namespaces, so when new path items are added, - # they can be updated - _namespace_packages.setdefault(parent or None, []).append(packageName) - _namespace_packages.setdefault(packageName, []) - - for path_item in path: - # Ensure all the parent's path items are reflected in the child, - # if they apply - _handle_ns(packageName, path_item) - - finally: - _imp.release_lock() - - -def fixup_namespace_packages(path_item, parent=None): - """Ensure that previously-declared namespace packages include path_item""" - _imp.acquire_lock() - try: - for package in _namespace_packages.get(parent, ()): - subpath = _handle_ns(package, path_item) - if subpath: - fixup_namespace_packages(subpath, package) - finally: - _imp.release_lock() - - -def file_ns_handler(importer, path_item, packageName, module): - """Compute an ns-package subpath for a filesystem or zipfile importer""" - - subpath = os.path.join(path_item, packageName.split('.')[-1]) - normalized = _normalize_cached(subpath) - for item in module.__path__: - if _normalize_cached(item) == normalized: - break - else: - # Only return the path if it's not already there - return subpath - - -register_namespace_handler(pkgutil.ImpImporter, file_ns_handler) -register_namespace_handler(zipimport.zipimporter, file_ns_handler) - -if hasattr(importlib_machinery, 'FileFinder'): - register_namespace_handler(importlib_machinery.FileFinder, file_ns_handler) - - -def null_ns_handler(importer, path_item, packageName, module): - return None - - -register_namespace_handler(object, null_ns_handler) - - -def normalize_path(filename): - """Normalize a file/dir name for comparison purposes""" - return os.path.normcase(os.path.realpath(os.path.normpath(_cygwin_patch(filename)))) - - -def _cygwin_patch(filename): # pragma: nocover - """ - Contrary to POSIX 2008, on Cygwin, getcwd (3) contains - symlink components. Using - os.path.abspath() works around this limitation. A fix in os.getcwd() - would probably better, in Cygwin even more so, except - that this seems to be by design... - """ - return os.path.abspath(filename) if sys.platform == 'cygwin' else filename - - -def _normalize_cached(filename, _cache={}): - try: - return _cache[filename] - except KeyError: - _cache[filename] = result = normalize_path(filename) - return result - - -def _is_egg_path(path): - """ - Determine if given path appears to be an egg. - """ - return path.lower().endswith('.egg') - - -def _is_unpacked_egg(path): - """ - Determine if given path appears to be an unpacked egg. - """ - return ( - _is_egg_path(path) and - os.path.isfile(os.path.join(path, 'EGG-INFO', 'PKG-INFO')) - ) - - -def _set_parent_ns(packageName): - parts = packageName.split('.') - name = parts.pop() - if parts: - parent = '.'.join(parts) - setattr(sys.modules[parent], name, sys.modules[packageName]) - - -def yield_lines(strs): - """Yield non-empty/non-comment lines of a string or sequence""" - if isinstance(strs, six.string_types): - for s in strs.splitlines(): - s = s.strip() - # skip blank lines/comments - if s and not s.startswith('#'): - yield s - else: - for ss in strs: - for s in yield_lines(ss): - yield s - - -MODULE = re.compile(r"\w+(\.\w+)*$").match -EGG_NAME = re.compile( - r""" - (?P<name>[^-]+) ( - -(?P<ver>[^-]+) ( - -py(?P<pyver>[^-]+) ( - -(?P<plat>.+) - )? - )? - )? - """, - re.VERBOSE | re.IGNORECASE, -).match - - -class EntryPoint: - """Object representing an advertised importable object""" - - def __init__(self, name, module_name, attrs=(), extras=(), dist=None): - if not MODULE(module_name): - raise ValueError("Invalid module name", module_name) - self.name = name - self.module_name = module_name - self.attrs = tuple(attrs) - self.extras = tuple(extras) - self.dist = dist - - def __str__(self): - s = "%s = %s" % (self.name, self.module_name) - if self.attrs: - s += ':' + '.'.join(self.attrs) - if self.extras: - s += ' [%s]' % ','.join(self.extras) - return s - - def __repr__(self): - return "EntryPoint.parse(%r)" % str(self) - - def load(self, require=True, *args, **kwargs): - """ - Require packages for this EntryPoint, then resolve it. - """ - if not require or args or kwargs: - warnings.warn( - "Parameters to load are deprecated. Call .resolve and " - ".require separately.", - PkgResourcesDeprecationWarning, - stacklevel=2, - ) - if require: - self.require(*args, **kwargs) - return self.resolve() - - def resolve(self): - """ - Resolve the entry point from its module and attrs. - """ - module = __import__(self.module_name, fromlist=['__name__'], level=0) - try: - return functools.reduce(getattr, self.attrs, module) - except AttributeError as exc: - raise ImportError(str(exc)) - - def require(self, env=None, installer=None): - if self.extras and not self.dist: - raise UnknownExtra("Can't require() without a distribution", self) - - # Get the requirements for this entry point with all its extras and - # then resolve them. We have to pass `extras` along when resolving so - # that the working set knows what extras we want. Otherwise, for - # dist-info distributions, the working set will assume that the - # requirements for that extra are purely optional and skip over them. - reqs = self.dist.requires(self.extras) - items = working_set.resolve(reqs, env, installer, extras=self.extras) - list(map(working_set.add, items)) - - pattern = re.compile( - r'\s*' - r'(?P<name>.+?)\s*' - r'=\s*' - r'(?P<module>[\w.]+)\s*' - r'(:\s*(?P<attr>[\w.]+))?\s*' - r'(?P<extras>\[.*\])?\s*$' - ) - - @classmethod - def parse(cls, src, dist=None): - """Parse a single entry point from string `src` - - Entry point syntax follows the form:: - - name = some.module:some.attr [extra1, extra2] - - The entry name and module name are required, but the ``:attrs`` and - ``[extras]`` parts are optional - """ - m = cls.pattern.match(src) - if not m: - msg = "EntryPoint must be in 'name=module:attrs [extras]' format" - raise ValueError(msg, src) - res = m.groupdict() - extras = cls._parse_extras(res['extras']) - attrs = res['attr'].split('.') if res['attr'] else () - return cls(res['name'], res['module'], attrs, extras, dist) - - @classmethod - def _parse_extras(cls, extras_spec): - if not extras_spec: - return () - req = Requirement.parse('x' + extras_spec) - if req.specs: - raise ValueError() - return req.extras - - @classmethod - def parse_group(cls, group, lines, dist=None): - """Parse an entry point group""" - if not MODULE(group): - raise ValueError("Invalid group name", group) - this = {} - for line in yield_lines(lines): - ep = cls.parse(line, dist) - if ep.name in this: - raise ValueError("Duplicate entry point", group, ep.name) - this[ep.name] = ep - return this - - @classmethod - def parse_map(cls, data, dist=None): - """Parse a map of entry point groups""" - if isinstance(data, dict): - data = data.items() - else: - data = split_sections(data) - maps = {} - for group, lines in data: - if group is None: - if not lines: - continue - raise ValueError("Entry points must be listed in groups") - group = group.strip() - if group in maps: - raise ValueError("Duplicate group name", group) - maps[group] = cls.parse_group(group, lines, dist) - return maps - - -def _remove_md5_fragment(location): - if not location: - return '' - parsed = urllib.parse.urlparse(location) - if parsed[-1].startswith('md5='): - return urllib.parse.urlunparse(parsed[:-1] + ('',)) - return location - - -def _version_from_file(lines): - """ - Given an iterable of lines from a Metadata file, return - the value of the Version field, if present, or None otherwise. - """ - def is_version_line(line): - return line.lower().startswith('version:') - version_lines = filter(is_version_line, lines) - line = next(iter(version_lines), '') - _, _, value = line.partition(':') - return safe_version(value.strip()) or None - - -class Distribution: - """Wrap an actual or potential sys.path entry w/metadata""" - PKG_INFO = 'PKG-INFO' - - def __init__( - self, location=None, metadata=None, project_name=None, - version=None, py_version=PY_MAJOR, platform=None, - precedence=EGG_DIST): - self.project_name = safe_name(project_name or 'Unknown') - if version is not None: - self._version = safe_version(version) - self.py_version = py_version - self.platform = platform - self.location = location - self.precedence = precedence - self._provider = metadata or empty_provider - - @classmethod - def from_location(cls, location, basename, metadata=None, **kw): - project_name, version, py_version, platform = [None] * 4 - basename, ext = os.path.splitext(basename) - if ext.lower() in _distributionImpl: - cls = _distributionImpl[ext.lower()] - - match = EGG_NAME(basename) - if match: - project_name, version, py_version, platform = match.group( - 'name', 'ver', 'pyver', 'plat' - ) - return cls( - location, metadata, project_name=project_name, version=version, - py_version=py_version, platform=platform, **kw - )._reload_version() - - def _reload_version(self): - return self - - @property - def hashcmp(self): - return ( - self.parsed_version, - self.precedence, - self.key, - _remove_md5_fragment(self.location), - self.py_version or '', - self.platform or '', - ) - - def __hash__(self): - return hash(self.hashcmp) - - def __lt__(self, other): - return self.hashcmp < other.hashcmp - - def __le__(self, other): - return self.hashcmp <= other.hashcmp - - def __gt__(self, other): - return self.hashcmp > other.hashcmp - - def __ge__(self, other): - return self.hashcmp >= other.hashcmp - - def __eq__(self, other): - if not isinstance(other, self.__class__): - # It's not a Distribution, so they are not equal - return False - return self.hashcmp == other.hashcmp - - def __ne__(self, other): - return not self == other - - # These properties have to be lazy so that we don't have to load any - # metadata until/unless it's actually needed. (i.e., some distributions - # may not know their name or version without loading PKG-INFO) - - @property - def key(self): - try: - return self._key - except AttributeError: - self._key = key = self.project_name.lower() - return key - - @property - def parsed_version(self): - if not hasattr(self, "_parsed_version"): - self._parsed_version = parse_version(self.version) - - return self._parsed_version - - def _warn_legacy_version(self): - LV = packaging.version.LegacyVersion - is_legacy = isinstance(self._parsed_version, LV) - if not is_legacy: - return - - # While an empty version is technically a legacy version and - # is not a valid PEP 440 version, it's also unlikely to - # actually come from someone and instead it is more likely that - # it comes from setuptools attempting to parse a filename and - # including it in the list. So for that we'll gate this warning - # on if the version is anything at all or not. - if not self.version: - return - - tmpl = textwrap.dedent(""" - '{project_name} ({version})' is being parsed as a legacy, - non PEP 440, - version. You may find odd behavior and sort order. - In particular it will be sorted as less than 0.0. It - is recommended to migrate to PEP 440 compatible - versions. - """).strip().replace('\n', ' ') - - warnings.warn(tmpl.format(**vars(self)), PEP440Warning) - - @property - def version(self): - try: - return self._version - except AttributeError: - version = self._get_version() - if version is None: - path = self._get_metadata_path_for_display(self.PKG_INFO) - msg = ( - "Missing 'Version:' header and/or {} file at path: {}" - ).format(self.PKG_INFO, path) - raise ValueError(msg, self) - - return version - - @property - def _dep_map(self): - """ - A map of extra to its list of (direct) requirements - for this distribution, including the null extra. - """ - try: - return self.__dep_map - except AttributeError: - self.__dep_map = self._filter_extras(self._build_dep_map()) - return self.__dep_map - - @staticmethod - def _filter_extras(dm): - """ - Given a mapping of extras to dependencies, strip off - environment markers and filter out any dependencies - not matching the markers. - """ - for extra in list(filter(None, dm)): - new_extra = extra - reqs = dm.pop(extra) - new_extra, _, marker = extra.partition(':') - fails_marker = marker and ( - invalid_marker(marker) - or not evaluate_marker(marker) - ) - if fails_marker: - reqs = [] - new_extra = safe_extra(new_extra) or None - - dm.setdefault(new_extra, []).extend(reqs) - return dm - - def _build_dep_map(self): - dm = {} - for name in 'requires.txt', 'depends.txt': - for extra, reqs in split_sections(self._get_metadata(name)): - dm.setdefault(extra, []).extend(parse_requirements(reqs)) - return dm - - def requires(self, extras=()): - """List of Requirements needed for this distro if `extras` are used""" - dm = self._dep_map - deps = [] - deps.extend(dm.get(None, ())) - for ext in extras: - try: - deps.extend(dm[safe_extra(ext)]) - except KeyError: - raise UnknownExtra( - "%s has no such extra feature %r" % (self, ext) - ) - return deps - - def _get_metadata_path_for_display(self, name): - """ - Return the path to the given metadata file, if available. - """ - try: - # We need to access _get_metadata_path() on the provider object - # directly rather than through this class's __getattr__() - # since _get_metadata_path() is marked private. - path = self._provider._get_metadata_path(name) - - # Handle exceptions e.g. in case the distribution's metadata - # provider doesn't support _get_metadata_path(). - except Exception: - return '[could not detect]' - - return path - - def _get_metadata(self, name): - if self.has_metadata(name): - for line in self.get_metadata_lines(name): - yield line - - def _get_version(self): - lines = self._get_metadata(self.PKG_INFO) - version = _version_from_file(lines) - - return version - - def activate(self, path=None, replace=False): - """Ensure distribution is importable on `path` (default=sys.path)""" - if path is None: - path = sys.path - self.insert_on(path, replace=replace) - if path is sys.path: - fixup_namespace_packages(self.location) - for pkg in self._get_metadata('namespace_packages.txt'): - if pkg in sys.modules: - declare_namespace(pkg) - - def egg_name(self): - """Return what this distribution's standard .egg filename should be""" - filename = "%s-%s-py%s" % ( - to_filename(self.project_name), to_filename(self.version), - self.py_version or PY_MAJOR - ) - - if self.platform: - filename += '-' + self.platform - return filename - - def __repr__(self): - if self.location: - return "%s (%s)" % (self, self.location) - else: - return str(self) - - def __str__(self): - try: - version = getattr(self, 'version', None) - except ValueError: - version = None - version = version or "[unknown version]" - return "%s %s" % (self.project_name, version) - - def __getattr__(self, attr): - """Delegate all unrecognized public attributes to .metadata provider""" - if attr.startswith('_'): - raise AttributeError(attr) - return getattr(self._provider, attr) - - def __dir__(self): - return list( - set(super(Distribution, self).__dir__()) - | set( - attr for attr in self._provider.__dir__() - if not attr.startswith('_') - ) - ) - - if not hasattr(object, '__dir__'): - # python 2.7 not supported - del __dir__ - - @classmethod - def from_filename(cls, filename, metadata=None, **kw): - return cls.from_location( - _normalize_cached(filename), os.path.basename(filename), metadata, - **kw - ) - - def as_requirement(self): - """Return a ``Requirement`` that matches this distribution exactly""" - if isinstance(self.parsed_version, packaging.version.Version): - spec = "%s==%s" % (self.project_name, self.parsed_version) - else: - spec = "%s===%s" % (self.project_name, self.parsed_version) - - return Requirement.parse(spec) - - def load_entry_point(self, group, name): - """Return the `name` entry point of `group` or raise ImportError""" - ep = self.get_entry_info(group, name) - if ep is None: - raise ImportError("Entry point %r not found" % ((group, name),)) - return ep.load() - - def get_entry_map(self, group=None): - """Return the entry point map for `group`, or the full entry map""" - try: - ep_map = self._ep_map - except AttributeError: - ep_map = self._ep_map = EntryPoint.parse_map( - self._get_metadata('entry_points.txt'), self - ) - if group is not None: - return ep_map.get(group, {}) - return ep_map - - def get_entry_info(self, group, name): - """Return the EntryPoint object for `group`+`name`, or ``None``""" - return self.get_entry_map(group).get(name) - - def insert_on(self, path, loc=None, replace=False): - """Ensure self.location is on path - - If replace=False (default): - - If location is already in path anywhere, do nothing. - - Else: - - If it's an egg and its parent directory is on path, - insert just ahead of the parent. - - Else: add to the end of path. - If replace=True: - - If location is already on path anywhere (not eggs) - or higher priority than its parent (eggs) - do nothing. - - Else: - - If it's an egg and its parent directory is on path, - insert just ahead of the parent, - removing any lower-priority entries. - - Else: add it to the front of path. - """ - - loc = loc or self.location - if not loc: - return - - nloc = _normalize_cached(loc) - bdir = os.path.dirname(nloc) - npath = [(p and _normalize_cached(p) or p) for p in path] - - for p, item in enumerate(npath): - if item == nloc: - if replace: - break - else: - # don't modify path (even removing duplicates) if - # found and not replace - return - elif item == bdir and self.precedence == EGG_DIST: - # if it's an .egg, give it precedence over its directory - # UNLESS it's already been added to sys.path and replace=False - if (not replace) and nloc in npath[p:]: - return - if path is sys.path: - self.check_version_conflict() - path.insert(p, loc) - npath.insert(p, nloc) - break - else: - if path is sys.path: - self.check_version_conflict() - if replace: - path.insert(0, loc) - else: - path.append(loc) - return - - # p is the spot where we found or inserted loc; now remove duplicates - while True: - try: - np = npath.index(nloc, p + 1) - except ValueError: - break - else: - del npath[np], path[np] - # ha! - p = np - - return - - def check_version_conflict(self): - if self.key == 'setuptools': - # ignore the inevitable setuptools self-conflicts :( - return - - nsp = dict.fromkeys(self._get_metadata('namespace_packages.txt')) - loc = normalize_path(self.location) - for modname in self._get_metadata('top_level.txt'): - if (modname not in sys.modules or modname in nsp - or modname in _namespace_packages): - continue - if modname in ('pkg_resources', 'setuptools', 'site'): - continue - fn = getattr(sys.modules[modname], '__file__', None) - if fn and (normalize_path(fn).startswith(loc) or - fn.startswith(self.location)): - continue - issue_warning( - "Module %s was already imported from %s, but %s is being added" - " to sys.path" % (modname, fn, self.location), - ) - - def has_version(self): - try: - self.version - except ValueError: - issue_warning("Unbuilt egg for " + repr(self)) - return False - return True - - def clone(self, **kw): - """Copy this distribution, substituting in any changed keyword args""" - names = 'project_name version py_version platform location precedence' - for attr in names.split(): - kw.setdefault(attr, getattr(self, attr, None)) - kw.setdefault('metadata', self._provider) - return self.__class__(**kw) - - @property - def extras(self): - return [dep for dep in self._dep_map if dep] - - -class EggInfoDistribution(Distribution): - def _reload_version(self): - """ - Packages installed by distutils (e.g. numpy or scipy), - which uses an old safe_version, and so - their version numbers can get mangled when - converted to filenames (e.g., 1.11.0.dev0+2329eae to - 1.11.0.dev0_2329eae). These distributions will not be - parsed properly - downstream by Distribution and safe_version, so - take an extra step and try to get the version number from - the metadata file itself instead of the filename. - """ - md_version = self._get_version() - if md_version: - self._version = md_version - return self - - -class DistInfoDistribution(Distribution): - """ - Wrap an actual or potential sys.path entry - w/metadata, .dist-info style. - """ - PKG_INFO = 'METADATA' - EQEQ = re.compile(r"([\(,])\s*(\d.*?)\s*([,\)])") - - @property - def _parsed_pkg_info(self): - """Parse and cache metadata""" - try: - return self._pkg_info - except AttributeError: - metadata = self.get_metadata(self.PKG_INFO) - self._pkg_info = email.parser.Parser().parsestr(metadata) - return self._pkg_info - - @property - def _dep_map(self): - try: - return self.__dep_map - except AttributeError: - self.__dep_map = self._compute_dependencies() - return self.__dep_map - - def _compute_dependencies(self): - """Recompute this distribution's dependencies.""" - dm = self.__dep_map = {None: []} - - reqs = [] - # Including any condition expressions - for req in self._parsed_pkg_info.get_all('Requires-Dist') or []: - reqs.extend(parse_requirements(req)) - - def reqs_for_extra(extra): - for req in reqs: - if not req.marker or req.marker.evaluate({'extra': extra}): - yield req - - common = frozenset(reqs_for_extra(None)) - dm[None].extend(common) - - for extra in self._parsed_pkg_info.get_all('Provides-Extra') or []: - s_extra = safe_extra(extra.strip()) - dm[s_extra] = list(frozenset(reqs_for_extra(extra)) - common) - - return dm - - -_distributionImpl = { - '.egg': Distribution, - '.egg-info': EggInfoDistribution, - '.dist-info': DistInfoDistribution, -} - - -def issue_warning(*args, **kw): - level = 1 - g = globals() - try: - # find the first stack frame that is *not* code in - # the pkg_resources module, to use for the warning - while sys._getframe(level).f_globals is g: - level += 1 - except ValueError: - pass - warnings.warn(stacklevel=level + 1, *args, **kw) - - -class RequirementParseError(ValueError): - def __str__(self): - return ' '.join(self.args) - - -def parse_requirements(strs): - """Yield ``Requirement`` objects for each specification in `strs` - - `strs` must be a string, or a (possibly-nested) iterable thereof. - """ - # create a steppable iterator, so we can handle \-continuations - lines = iter(yield_lines(strs)) - - for line in lines: - # Drop comments -- a hash without a space may be in a URL. - if ' #' in line: - line = line[:line.find(' #')] - # If there is a line continuation, drop it, and append the next line. - if line.endswith('\\'): - line = line[:-2].strip() - try: - line += next(lines) - except StopIteration: - return - yield Requirement(line) - - -class Requirement(packaging.requirements.Requirement): - def __init__(self, requirement_string): - """DO NOT CALL THIS UNDOCUMENTED METHOD; use Requirement.parse()!""" - try: - super(Requirement, self).__init__(requirement_string) - except packaging.requirements.InvalidRequirement as e: - raise RequirementParseError(str(e)) - self.unsafe_name = self.name - project_name = safe_name(self.name) - self.project_name, self.key = project_name, project_name.lower() - self.specs = [ - (spec.operator, spec.version) for spec in self.specifier] - self.extras = tuple(map(safe_extra, self.extras)) - self.hashCmp = ( - self.key, - self.url, - self.specifier, - frozenset(self.extras), - str(self.marker) if self.marker else None, - ) - self.__hash = hash(self.hashCmp) - - def __eq__(self, other): - return ( - isinstance(other, Requirement) and - self.hashCmp == other.hashCmp - ) - - def __ne__(self, other): - return not self == other - - def __contains__(self, item): - if isinstance(item, Distribution): - if item.key != self.key: - return False - - item = item.version - - # Allow prereleases always in order to match the previous behavior of - # this method. In the future this should be smarter and follow PEP 440 - # more accurately. - return self.specifier.contains(item, prereleases=True) - - def __hash__(self): - return self.__hash - - def __repr__(self): - return "Requirement.parse(%r)" % str(self) - - @staticmethod - def parse(s): - req, = parse_requirements(s) - return req - - -def _always_object(classes): - """ - Ensure object appears in the mro even - for old-style classes. - """ - if object not in classes: - return classes + (object,) - return classes - - -def _find_adapter(registry, ob): - """Return an adapter factory for `ob` from `registry`""" - types = _always_object(inspect.getmro(getattr(ob, '__class__', type(ob)))) - for t in types: - if t in registry: - return registry[t] - - -def ensure_directory(path): - """Ensure that the parent directory of `path` exists""" - dirname = os.path.dirname(path) - py31compat.makedirs(dirname, exist_ok=True) - - -def _bypass_ensure_directory(path): - """Sandbox-bypassing version of ensure_directory()""" - if not WRITE_SUPPORT: - raise IOError('"os.mkdir" not supported on this platform.') - dirname, filename = split(path) - if dirname and filename and not isdir(dirname): - _bypass_ensure_directory(dirname) - try: - mkdir(dirname, 0o755) - except FileExistsError: - pass - - -def split_sections(s): - """Split a string or iterable thereof into (section, content) pairs - - Each ``section`` is a stripped version of the section header ("[section]") - and each ``content`` is a list of stripped lines excluding blank lines and - comment-only lines. If there are any such lines before the first section - header, they're returned in a first ``section`` of ``None``. - """ - section = None - content = [] - for line in yield_lines(s): - if line.startswith("["): - if line.endswith("]"): - if section or content: - yield section, content - section = line[1:-1].strip() - content = [] - else: - raise ValueError("Invalid section heading", line) - else: - content.append(line) - - # wrap up last segment - yield section, content - - -def _mkstemp(*args, **kw): - old_open = os.open - try: - # temporarily bypass sandboxing - os.open = os_open - return tempfile.mkstemp(*args, **kw) - finally: - # and then put it back - os.open = old_open - - -# Silence the PEP440Warning by default, so that end users don't get hit by it -# randomly just because they use pkg_resources. We want to append the rule -# because we want earlier uses of filterwarnings to take precedence over this -# one. -warnings.filterwarnings("ignore", category=PEP440Warning, append=True) - - -# from jaraco.functools 1.3 -def _call_aside(f, *args, **kwargs): - f(*args, **kwargs) - return f - - -@_call_aside -def _initialize(g=globals()): - "Set up global resource manager (deliberately not state-saved)" - manager = ResourceManager() - g['_manager'] = manager - g.update( - (name, getattr(manager, name)) - for name in dir(manager) - if not name.startswith('_') - ) - - -@_call_aside -def _initialize_master_working_set(): - """ - Prepare the master working set and make the ``require()`` - API available. - - This function has explicit effects on the global state - of pkg_resources. It is intended to be invoked once at - the initialization of this module. - - Invocation by other packages is unsupported and done - at their own risk. - """ - working_set = WorkingSet._build_master() - _declare_state('object', working_set=working_set) - - require = working_set.require - iter_entry_points = working_set.iter_entry_points - add_activation_listener = working_set.subscribe - run_script = working_set.run_script - # backward compatibility - run_main = run_script - # Activate all distributions already on sys.path with replace=False and - # ensure that all distributions added to the working set in the future - # (e.g. by calling ``require()``) will get activated as well, - # with higher priority (replace=True). - tuple( - dist.activate(replace=False) - for dist in working_set - ) - add_activation_listener( - lambda dist: dist.activate(replace=True), - existing=False, - ) - working_set.entries = [] - # match order - list(map(working_set.add_entry, sys.path)) - globals().update(locals()) - -class PkgResourcesDeprecationWarning(Warning): - """ - Base class for warning about deprecations in ``pkg_resources`` - - This class is not derived from ``DeprecationWarning``, and as such is - visible by default. - """ diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/__init__.py b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/appdirs.py b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/appdirs.py deleted file mode 100644 index ae67001..0000000 --- a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/appdirs.py +++ /dev/null @@ -1,608 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# Copyright (c) 2005-2010 ActiveState Software Inc. -# Copyright (c) 2013 Eddy Petrișor - -"""Utilities for determining application-specific dirs. - -See <http://github.com/ActiveState/appdirs> for details and usage. -""" -# Dev Notes: -# - MSDN on where to store app data files: -# http://support.microsoft.com/default.aspx?scid=kb;en-us;310294#XSLTH3194121123120121120120 -# - Mac OS X: http://developer.apple.com/documentation/MacOSX/Conceptual/BPFileSystem/index.html -# - XDG spec for Un*x: http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html - -__version_info__ = (1, 4, 3) -__version__ = '.'.join(map(str, __version_info__)) - - -import sys -import os - -PY3 = sys.version_info[0] == 3 - -if PY3: - unicode = str - -if sys.platform.startswith('java'): - import platform - os_name = platform.java_ver()[3][0] - if os_name.startswith('Windows'): # "Windows XP", "Windows 7", etc. - system = 'win32' - elif os_name.startswith('Mac'): # "Mac OS X", etc. - system = 'darwin' - else: # "Linux", "SunOS", "FreeBSD", etc. - # Setting this to "linux2" is not ideal, but only Windows or Mac - # are actually checked for and the rest of the module expects - # *sys.platform* style strings. - system = 'linux2' -else: - system = sys.platform - - - -def user_data_dir(appname=None, appauthor=None, version=None, roaming=False): - r"""Return full path to the user-specific data dir for this application. - - "appname" is the name of application. - If None, just the system directory is returned. - "appauthor" (only used on Windows) is the name of the - appauthor or distributing body for this application. Typically - it is the owning company name. This falls back to appname. You may - pass False to disable it. - "version" is an optional version path element to append to the - path. You might want to use this if you want multiple versions - of your app to be able to run independently. If used, this - would typically be "<major>.<minor>". - Only applied when appname is present. - "roaming" (boolean, default False) can be set True to use the Windows - roaming appdata directory. That means that for users on a Windows - network setup for roaming profiles, this user data will be - sync'd on login. See - <http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx> - for a discussion of issues. - - Typical user data directories are: - Mac OS X: ~/Library/Application Support/<AppName> - Unix: ~/.local/share/<AppName> # or in $XDG_DATA_HOME, if defined - Win XP (not roaming): C:\Documents and Settings\<username>\Application Data\<AppAuthor>\<AppName> - Win XP (roaming): C:\Documents and Settings\<username>\Local Settings\Application Data\<AppAuthor>\<AppName> - Win 7 (not roaming): C:\Users\<username>\AppData\Local\<AppAuthor>\<AppName> - Win 7 (roaming): C:\Users\<username>\AppData\Roaming\<AppAuthor>\<AppName> - - For Unix, we follow the XDG spec and support $XDG_DATA_HOME. - That means, by default "~/.local/share/<AppName>". - """ - if system == "win32": - if appauthor is None: - appauthor = appname - const = roaming and "CSIDL_APPDATA" or "CSIDL_LOCAL_APPDATA" - path = os.path.normpath(_get_win_folder(const)) - if appname: - if appauthor is not False: - path = os.path.join(path, appauthor, appname) - else: - path = os.path.join(path, appname) - elif system == 'darwin': - path = os.path.expanduser('~/Library/Application Support/') - if appname: - path = os.path.join(path, appname) - else: - path = os.getenv('XDG_DATA_HOME', os.path.expanduser("~/.local/share")) - if appname: - path = os.path.join(path, appname) - if appname and version: - path = os.path.join(path, version) - return path - - -def site_data_dir(appname=None, appauthor=None, version=None, multipath=False): - r"""Return full path to the user-shared data dir for this application. - - "appname" is the name of application. - If None, just the system directory is returned. - "appauthor" (only used on Windows) is the name of the - appauthor or distributing body for this application. Typically - it is the owning company name. This falls back to appname. You may - pass False to disable it. - "version" is an optional version path element to append to the - path. You might want to use this if you want multiple versions - of your app to be able to run independently. If used, this - would typically be "<major>.<minor>". - Only applied when appname is present. - "multipath" is an optional parameter only applicable to *nix - which indicates that the entire list of data dirs should be - returned. By default, the first item from XDG_DATA_DIRS is - returned, or '/usr/local/share/<AppName>', - if XDG_DATA_DIRS is not set - - Typical site data directories are: - Mac OS X: /Library/Application Support/<AppName> - Unix: /usr/local/share/<AppName> or /usr/share/<AppName> - Win XP: C:\Documents and Settings\All Users\Application Data\<AppAuthor>\<AppName> - Vista: (Fail! "C:\ProgramData" is a hidden *system* directory on Vista.) - Win 7: C:\ProgramData\<AppAuthor>\<AppName> # Hidden, but writeable on Win 7. - - For Unix, this is using the $XDG_DATA_DIRS[0] default. - - WARNING: Do not use this on Windows. See the Vista-Fail note above for why. - """ - if system == "win32": - if appauthor is None: - appauthor = appname - path = os.path.normpath(_get_win_folder("CSIDL_COMMON_APPDATA")) - if appname: - if appauthor is not False: - path = os.path.join(path, appauthor, appname) - else: - path = os.path.join(path, appname) - elif system == 'darwin': - path = os.path.expanduser('/Library/Application Support') - if appname: - path = os.path.join(path, appname) - else: - # XDG default for $XDG_DATA_DIRS - # only first, if multipath is False - path = os.getenv('XDG_DATA_DIRS', - os.pathsep.join(['/usr/local/share', '/usr/share'])) - pathlist = [os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep)] - if appname: - if version: - appname = os.path.join(appname, version) - pathlist = [os.sep.join([x, appname]) for x in pathlist] - - if multipath: - path = os.pathsep.join(pathlist) - else: - path = pathlist[0] - return path - - if appname and version: - path = os.path.join(path, version) - return path - - -def user_config_dir(appname=None, appauthor=None, version=None, roaming=False): - r"""Return full path to the user-specific config dir for this application. - - "appname" is the name of application. - If None, just the system directory is returned. - "appauthor" (only used on Windows) is the name of the - appauthor or distributing body for this application. Typically - it is the owning company name. This falls back to appname. You may - pass False to disable it. - "version" is an optional version path element to append to the - path. You might want to use this if you want multiple versions - of your app to be able to run independently. If used, this - would typically be "<major>.<minor>". - Only applied when appname is present. - "roaming" (boolean, default False) can be set True to use the Windows - roaming appdata directory. That means that for users on a Windows - network setup for roaming profiles, this user data will be - sync'd on login. See - <http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx> - for a discussion of issues. - - Typical user config directories are: - Mac OS X: same as user_data_dir - Unix: ~/.config/<AppName> # or in $XDG_CONFIG_HOME, if defined - Win *: same as user_data_dir - - For Unix, we follow the XDG spec and support $XDG_CONFIG_HOME. - That means, by default "~/.config/<AppName>". - """ - if system in ["win32", "darwin"]: - path = user_data_dir(appname, appauthor, None, roaming) - else: - path = os.getenv('XDG_CONFIG_HOME', os.path.expanduser("~/.config")) - if appname: - path = os.path.join(path, appname) - if appname and version: - path = os.path.join(path, version) - return path - - -def site_config_dir(appname=None, appauthor=None, version=None, multipath=False): - r"""Return full path to the user-shared data dir for this application. - - "appname" is the name of application. - If None, just the system directory is returned. - "appauthor" (only used on Windows) is the name of the - appauthor or distributing body for this application. Typically - it is the owning company name. This falls back to appname. You may - pass False to disable it. - "version" is an optional version path element to append to the - path. You might want to use this if you want multiple versions - of your app to be able to run independently. If used, this - would typically be "<major>.<minor>". - Only applied when appname is present. - "multipath" is an optional parameter only applicable to *nix - which indicates that the entire list of config dirs should be - returned. By default, the first item from XDG_CONFIG_DIRS is - returned, or '/etc/xdg/<AppName>', if XDG_CONFIG_DIRS is not set - - Typical site config directories are: - Mac OS X: same as site_data_dir - Unix: /etc/xdg/<AppName> or $XDG_CONFIG_DIRS[i]/<AppName> for each value in - $XDG_CONFIG_DIRS - Win *: same as site_data_dir - Vista: (Fail! "C:\ProgramData" is a hidden *system* directory on Vista.) - - For Unix, this is using the $XDG_CONFIG_DIRS[0] default, if multipath=False - - WARNING: Do not use this on Windows. See the Vista-Fail note above for why. - """ - if system in ["win32", "darwin"]: - path = site_data_dir(appname, appauthor) - if appname and version: - path = os.path.join(path, version) - else: - # XDG default for $XDG_CONFIG_DIRS - # only first, if multipath is False - path = os.getenv('XDG_CONFIG_DIRS', '/etc/xdg') - pathlist = [os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep)] - if appname: - if version: - appname = os.path.join(appname, version) - pathlist = [os.sep.join([x, appname]) for x in pathlist] - - if multipath: - path = os.pathsep.join(pathlist) - else: - path = pathlist[0] - return path - - -def user_cache_dir(appname=None, appauthor=None, version=None, opinion=True): - r"""Return full path to the user-specific cache dir for this application. - - "appname" is the name of application. - If None, just the system directory is returned. - "appauthor" (only used on Windows) is the name of the - appauthor or distributing body for this application. Typically - it is the owning company name. This falls back to appname. You may - pass False to disable it. - "version" is an optional version path element to append to the - path. You might want to use this if you want multiple versions - of your app to be able to run independently. If used, this - would typically be "<major>.<minor>". - Only applied when appname is present. - "opinion" (boolean) can be False to disable the appending of - "Cache" to the base app data dir for Windows. See - discussion below. - - Typical user cache directories are: - Mac OS X: ~/Library/Caches/<AppName> - Unix: ~/.cache/<AppName> (XDG default) - Win XP: C:\Documents and Settings\<username>\Local Settings\Application Data\<AppAuthor>\<AppName>\Cache - Vista: C:\Users\<username>\AppData\Local\<AppAuthor>\<AppName>\Cache - - On Windows the only suggestion in the MSDN docs is that local settings go in - the `CSIDL_LOCAL_APPDATA` directory. This is identical to the non-roaming - app data dir (the default returned by `user_data_dir` above). Apps typically - put cache data somewhere *under* the given dir here. Some examples: - ...\Mozilla\Firefox\Profiles\<ProfileName>\Cache - ...\Acme\SuperApp\Cache\1.0 - OPINION: This function appends "Cache" to the `CSIDL_LOCAL_APPDATA` value. - This can be disabled with the `opinion=False` option. - """ - if system == "win32": - if appauthor is None: - appauthor = appname - path = os.path.normpath(_get_win_folder("CSIDL_LOCAL_APPDATA")) - if appname: - if appauthor is not False: - path = os.path.join(path, appauthor, appname) - else: - path = os.path.join(path, appname) - if opinion: - path = os.path.join(path, "Cache") - elif system == 'darwin': - path = os.path.expanduser('~/Library/Caches') - if appname: - path = os.path.join(path, appname) - else: - path = os.getenv('XDG_CACHE_HOME', os.path.expanduser('~/.cache')) - if appname: - path = os.path.join(path, appname) - if appname and version: - path = os.path.join(path, version) - return path - - -def user_state_dir(appname=None, appauthor=None, version=None, roaming=False): - r"""Return full path to the user-specific state dir for this application. - - "appname" is the name of application. - If None, just the system directory is returned. - "appauthor" (only used on Windows) is the name of the - appauthor or distributing body for this application. Typically - it is the owning company name. This falls back to appname. You may - pass False to disable it. - "version" is an optional version path element to append to the - path. You might want to use this if you want multiple versions - of your app to be able to run independently. If used, this - would typically be "<major>.<minor>". - Only applied when appname is present. - "roaming" (boolean, default False) can be set True to use the Windows - roaming appdata directory. That means that for users on a Windows - network setup for roaming profiles, this user data will be - sync'd on login. See - <http://technet.microsoft.com/en-us/library/cc766489(WS.10).aspx> - for a discussion of issues. - - Typical user state directories are: - Mac OS X: same as user_data_dir - Unix: ~/.local/state/<AppName> # or in $XDG_STATE_HOME, if defined - Win *: same as user_data_dir - - For Unix, we follow this Debian proposal <https://wiki.debian.org/XDGBaseDirectorySpecification#state> - to extend the XDG spec and support $XDG_STATE_HOME. - - That means, by default "~/.local/state/<AppName>". - """ - if system in ["win32", "darwin"]: - path = user_data_dir(appname, appauthor, None, roaming) - else: - path = os.getenv('XDG_STATE_HOME', os.path.expanduser("~/.local/state")) - if appname: - path = os.path.join(path, appname) - if appname and version: - path = os.path.join(path, version) - return path - - -def user_log_dir(appname=None, appauthor=None, version=None, opinion=True): - r"""Return full path to the user-specific log dir for this application. - - "appname" is the name of application. - If None, just the system directory is returned. - "appauthor" (only used on Windows) is the name of the - appauthor or distributing body for this application. Typically - it is the owning company name. This falls back to appname. You may - pass False to disable it. - "version" is an optional version path element to append to the - path. You might want to use this if you want multiple versions - of your app to be able to run independently. If used, this - would typically be "<major>.<minor>". - Only applied when appname is present. - "opinion" (boolean) can be False to disable the appending of - "Logs" to the base app data dir for Windows, and "log" to the - base cache dir for Unix. See discussion below. - - Typical user log directories are: - Mac OS X: ~/Library/Logs/<AppName> - Unix: ~/.cache/<AppName>/log # or under $XDG_CACHE_HOME if defined - Win XP: C:\Documents and Settings\<username>\Local Settings\Application Data\<AppAuthor>\<AppName>\Logs - Vista: C:\Users\<username>\AppData\Local\<AppAuthor>\<AppName>\Logs - - On Windows the only suggestion in the MSDN docs is that local settings - go in the `CSIDL_LOCAL_APPDATA` directory. (Note: I'm interested in - examples of what some windows apps use for a logs dir.) - - OPINION: This function appends "Logs" to the `CSIDL_LOCAL_APPDATA` - value for Windows and appends "log" to the user cache dir for Unix. - This can be disabled with the `opinion=False` option. - """ - if system == "darwin": - path = os.path.join( - os.path.expanduser('~/Library/Logs'), - appname) - elif system == "win32": - path = user_data_dir(appname, appauthor, version) - version = False - if opinion: - path = os.path.join(path, "Logs") - else: - path = user_cache_dir(appname, appauthor, version) - version = False - if opinion: - path = os.path.join(path, "log") - if appname and version: - path = os.path.join(path, version) - return path - - -class AppDirs(object): - """Convenience wrapper for getting application dirs.""" - def __init__(self, appname=None, appauthor=None, version=None, - roaming=False, multipath=False): - self.appname = appname - self.appauthor = appauthor - self.version = version - self.roaming = roaming - self.multipath = multipath - - @property - def user_data_dir(self): - return user_data_dir(self.appname, self.appauthor, - version=self.version, roaming=self.roaming) - - @property - def site_data_dir(self): - return site_data_dir(self.appname, self.appauthor, - version=self.version, multipath=self.multipath) - - @property - def user_config_dir(self): - return user_config_dir(self.appname, self.appauthor, - version=self.version, roaming=self.roaming) - - @property - def site_config_dir(self): - return site_config_dir(self.appname, self.appauthor, - version=self.version, multipath=self.multipath) - - @property - def user_cache_dir(self): - return user_cache_dir(self.appname, self.appauthor, - version=self.version) - - @property - def user_state_dir(self): - return user_state_dir(self.appname, self.appauthor, - version=self.version) - - @property - def user_log_dir(self): - return user_log_dir(self.appname, self.appauthor, - version=self.version) - - -#---- internal support stuff - -def _get_win_folder_from_registry(csidl_name): - """This is a fallback technique at best. I'm not sure if using the - registry for this guarantees us the correct answer for all CSIDL_* - names. - """ - if PY3: - import winreg as _winreg - else: - import _winreg - - shell_folder_name = { - "CSIDL_APPDATA": "AppData", - "CSIDL_COMMON_APPDATA": "Common AppData", - "CSIDL_LOCAL_APPDATA": "Local AppData", - }[csidl_name] - - key = _winreg.OpenKey( - _winreg.HKEY_CURRENT_USER, - r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders" - ) - dir, type = _winreg.QueryValueEx(key, shell_folder_name) - return dir - - -def _get_win_folder_with_pywin32(csidl_name): - from win32com.shell import shellcon, shell - dir = shell.SHGetFolderPath(0, getattr(shellcon, csidl_name), 0, 0) - # Try to make this a unicode path because SHGetFolderPath does - # not return unicode strings when there is unicode data in the - # path. - try: - dir = unicode(dir) - - # Downgrade to short path name if have highbit chars. See - # <http://bugs.activestate.com/show_bug.cgi?id=85099>. - has_high_char = False - for c in dir: - if ord(c) > 255: - has_high_char = True - break - if has_high_char: - try: - import win32api - dir = win32api.GetShortPathName(dir) - except ImportError: - pass - except UnicodeError: - pass - return dir - - -def _get_win_folder_with_ctypes(csidl_name): - import ctypes - - csidl_const = { - "CSIDL_APPDATA": 26, - "CSIDL_COMMON_APPDATA": 35, - "CSIDL_LOCAL_APPDATA": 28, - }[csidl_name] - - buf = ctypes.create_unicode_buffer(1024) - ctypes.windll.shell32.SHGetFolderPathW(None, csidl_const, None, 0, buf) - - # Downgrade to short path name if have highbit chars. See - # <http://bugs.activestate.com/show_bug.cgi?id=85099>. - has_high_char = False - for c in buf: - if ord(c) > 255: - has_high_char = True - break - if has_high_char: - buf2 = ctypes.create_unicode_buffer(1024) - if ctypes.windll.kernel32.GetShortPathNameW(buf.value, buf2, 1024): - buf = buf2 - - return buf.value - -def _get_win_folder_with_jna(csidl_name): - import array - from com.sun import jna - from com.sun.jna.platform import win32 - - buf_size = win32.WinDef.MAX_PATH * 2 - buf = array.zeros('c', buf_size) - shell = win32.Shell32.INSTANCE - shell.SHGetFolderPath(None, getattr(win32.ShlObj, csidl_name), None, win32.ShlObj.SHGFP_TYPE_CURRENT, buf) - dir = jna.Native.toString(buf.tostring()).rstrip("\0") - - # Downgrade to short path name if have highbit chars. See - # <http://bugs.activestate.com/show_bug.cgi?id=85099>. - has_high_char = False - for c in dir: - if ord(c) > 255: - has_high_char = True - break - if has_high_char: - buf = array.zeros('c', buf_size) - kernel = win32.Kernel32.INSTANCE - if kernel.GetShortPathName(dir, buf, buf_size): - dir = jna.Native.toString(buf.tostring()).rstrip("\0") - - return dir - -if system == "win32": - try: - import win32com.shell - _get_win_folder = _get_win_folder_with_pywin32 - except ImportError: - try: - from ctypes import windll - _get_win_folder = _get_win_folder_with_ctypes - except ImportError: - try: - import com.sun.jna - _get_win_folder = _get_win_folder_with_jna - except ImportError: - _get_win_folder = _get_win_folder_from_registry - - -#---- self test code - -if __name__ == "__main__": - appname = "MyApp" - appauthor = "MyCompany" - - props = ("user_data_dir", - "user_config_dir", - "user_cache_dir", - "user_state_dir", - "user_log_dir", - "site_data_dir", - "site_config_dir") - - print("-- app dirs %s --" % __version__) - - print("-- app dirs (with optional 'version')") - dirs = AppDirs(appname, appauthor, version="1.0") - for prop in props: - print("%s: %s" % (prop, getattr(dirs, prop))) - - print("\n-- app dirs (without optional 'version')") - dirs = AppDirs(appname, appauthor) - for prop in props: - print("%s: %s" % (prop, getattr(dirs, prop))) - - print("\n-- app dirs (without optional 'appauthor')") - dirs = AppDirs(appname) - for prop in props: - print("%s: %s" % (prop, getattr(dirs, prop))) - - print("\n-- app dirs (with disabled 'appauthor')") - dirs = AppDirs(appname, appauthor=False) - for prop in props: - print("%s: %s" % (prop, getattr(dirs, prop))) diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__about__.py b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__about__.py deleted file mode 100644 index 95d330e..0000000 --- a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__about__.py +++ /dev/null @@ -1,21 +0,0 @@ -# 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 __future__ import absolute_import, division, print_function - -__all__ = [ - "__title__", "__summary__", "__uri__", "__version__", "__author__", - "__email__", "__license__", "__copyright__", -] - -__title__ = "packaging" -__summary__ = "Core utilities for Python packages" -__uri__ = "https://github.com/pypa/packaging" - -__version__ = "16.8" - -__author__ = "Donald Stufft and individual contributors" -__email__ = "donald@stufft.io" - -__license__ = "BSD or Apache License, Version 2.0" -__copyright__ = "Copyright 2014-2016 %s" % __author__ diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__init__.py b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__init__.py deleted file mode 100644 index 5ee6220..0000000 --- a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -# 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 __future__ import absolute_import, division, print_function - -from .__about__ import ( - __author__, __copyright__, __email__, __license__, __summary__, __title__, - __uri__, __version__ -) - -__all__ = [ - "__title__", "__summary__", "__uri__", "__version__", "__author__", - "__email__", "__license__", "__copyright__", -] diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/_compat.py b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/_compat.py deleted file mode 100644 index 210bb80..0000000 --- a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/_compat.py +++ /dev/null @@ -1,30 +0,0 @@ -# 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 __future__ import absolute_import, division, print_function - -import sys - - -PY2 = sys.version_info[0] == 2 -PY3 = sys.version_info[0] == 3 - -# flake8: noqa - -if PY3: - string_types = str, -else: - string_types = basestring, - - -def with_metaclass(meta, *bases): - """ - Create a base class with a metaclass. - """ - # This requires a bit of explanation: the basic idea is to make a dummy - # metaclass for one level of class instantiation that replaces itself with - # the actual metaclass. - class metaclass(meta): - def __new__(cls, name, this_bases, d): - return meta(name, bases, d) - return type.__new__(metaclass, 'temporary_class', (), {}) diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/_structures.py b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/_structures.py deleted file mode 100644 index ccc2786..0000000 --- a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/_structures.py +++ /dev/null @@ -1,68 +0,0 @@ -# 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 __future__ import absolute_import, division, print_function - - -class Infinity(object): - - def __repr__(self): - return "Infinity" - - def __hash__(self): - return hash(repr(self)) - - def __lt__(self, other): - return False - - def __le__(self, other): - return False - - def __eq__(self, other): - return isinstance(other, self.__class__) - - def __ne__(self, other): - return not isinstance(other, self.__class__) - - def __gt__(self, other): - return True - - def __ge__(self, other): - return True - - def __neg__(self): - return NegativeInfinity - -Infinity = Infinity() - - -class NegativeInfinity(object): - - def __repr__(self): - return "-Infinity" - - def __hash__(self): - return hash(repr(self)) - - def __lt__(self, other): - return True - - def __le__(self, other): - return True - - def __eq__(self, other): - return isinstance(other, self.__class__) - - def __ne__(self, other): - return not isinstance(other, self.__class__) - - def __gt__(self, other): - return False - - def __ge__(self, other): - return False - - def __neg__(self): - return Infinity - -NegativeInfinity = NegativeInfinity() diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/markers.py b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/markers.py deleted file mode 100644 index 892e578..0000000 --- a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/markers.py +++ /dev/null @@ -1,301 +0,0 @@ -# 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 __future__ import absolute_import, division, print_function - -import operator -import os -import platform -import sys - -from pkg_resources.extern.pyparsing import ParseException, ParseResults, stringStart, stringEnd -from pkg_resources.extern.pyparsing import ZeroOrMore, Group, Forward, QuotedString -from pkg_resources.extern.pyparsing import Literal as L # noqa - -from ._compat import string_types -from .specifiers import Specifier, InvalidSpecifier - - -__all__ = [ - "InvalidMarker", "UndefinedComparison", "UndefinedEnvironmentName", - "Marker", "default_environment", -] - - -class InvalidMarker(ValueError): - """ - An invalid marker was found, users should refer to PEP 508. - """ - - -class UndefinedComparison(ValueError): - """ - An invalid operation was attempted on a value that doesn't support it. - """ - - -class UndefinedEnvironmentName(ValueError): - """ - A name was attempted to be used that does not exist inside of the - environment. - """ - - -class Node(object): - - def __init__(self, value): - self.value = value - - def __str__(self): - return str(self.value) - - def __repr__(self): - return "<{0}({1!r})>".format(self.__class__.__name__, str(self)) - - def serialize(self): - raise NotImplementedError - - -class Variable(Node): - - def serialize(self): - return str(self) - - -class Value(Node): - - def serialize(self): - return '"{0}"'.format(self) - - -class Op(Node): - - def serialize(self): - return str(self) - - -VARIABLE = ( - L("implementation_version") | - L("platform_python_implementation") | - L("implementation_name") | - L("python_full_version") | - L("platform_release") | - L("platform_version") | - L("platform_machine") | - L("platform_system") | - L("python_version") | - L("sys_platform") | - L("os_name") | - L("os.name") | # PEP-345 - L("sys.platform") | # PEP-345 - L("platform.version") | # PEP-345 - L("platform.machine") | # PEP-345 - L("platform.python_implementation") | # PEP-345 - L("python_implementation") | # undocumented setuptools legacy - L("extra") -) -ALIASES = { - 'os.name': 'os_name', - 'sys.platform': 'sys_platform', - 'platform.version': 'platform_version', - 'platform.machine': 'platform_machine', - 'platform.python_implementation': 'platform_python_implementation', - 'python_implementation': 'platform_python_implementation' -} -VARIABLE.setParseAction(lambda s, l, t: Variable(ALIASES.get(t[0], t[0]))) - -VERSION_CMP = ( - L("===") | - L("==") | - L(">=") | - L("<=") | - L("!=") | - L("~=") | - L(">") | - L("<") -) - -MARKER_OP = VERSION_CMP | L("not in") | L("in") -MARKER_OP.setParseAction(lambda s, l, t: Op(t[0])) - -MARKER_VALUE = QuotedString("'") | QuotedString('"') -MARKER_VALUE.setParseAction(lambda s, l, t: Value(t[0])) - -BOOLOP = L("and") | L("or") - -MARKER_VAR = VARIABLE | MARKER_VALUE - -MARKER_ITEM = Group(MARKER_VAR + MARKER_OP + MARKER_VAR) -MARKER_ITEM.setParseAction(lambda s, l, t: tuple(t[0])) - -LPAREN = L("(").suppress() -RPAREN = L(")").suppress() - -MARKER_EXPR = Forward() -MARKER_ATOM = MARKER_ITEM | Group(LPAREN + MARKER_EXPR + RPAREN) -MARKER_EXPR << MARKER_ATOM + ZeroOrMore(BOOLOP + MARKER_EXPR) - -MARKER = stringStart + MARKER_EXPR + stringEnd - - -def _coerce_parse_result(results): - if isinstance(results, ParseResults): - return [_coerce_parse_result(i) for i in results] - else: - return results - - -def _format_marker(marker, first=True): - assert isinstance(marker, (list, tuple, string_types)) - - # Sometimes we have a structure like [[...]] which is a single item list - # where the single item is itself it's own list. In that case we want skip - # the rest of this function so that we don't get extraneous () on the - # outside. - if (isinstance(marker, list) and len(marker) == 1 and - isinstance(marker[0], (list, tuple))): - return _format_marker(marker[0]) - - if isinstance(marker, list): - inner = (_format_marker(m, first=False) for m in marker) - if first: - return " ".join(inner) - else: - return "(" + " ".join(inner) + ")" - elif isinstance(marker, tuple): - return " ".join([m.serialize() for m in marker]) - else: - return marker - - -_operators = { - "in": lambda lhs, rhs: lhs in rhs, - "not in": lambda lhs, rhs: lhs not in rhs, - "<": operator.lt, - "<=": operator.le, - "==": operator.eq, - "!=": operator.ne, - ">=": operator.ge, - ">": operator.gt, -} - - -def _eval_op(lhs, op, rhs): - try: - spec = Specifier("".join([op.serialize(), rhs])) - except InvalidSpecifier: - pass - else: - return spec.contains(lhs) - - oper = _operators.get(op.serialize()) - if oper is None: - raise UndefinedComparison( - "Undefined {0!r} on {1!r} and {2!r}.".format(op, lhs, rhs) - ) - - return oper(lhs, rhs) - - -_undefined = object() - - -def _get_env(environment, name): - value = environment.get(name, _undefined) - - if value is _undefined: - raise UndefinedEnvironmentName( - "{0!r} does not exist in evaluation environment.".format(name) - ) - - return value - - -def _evaluate_markers(markers, environment): - groups = [[]] - - for marker in markers: - assert isinstance(marker, (list, tuple, string_types)) - - if isinstance(marker, list): - groups[-1].append(_evaluate_markers(marker, environment)) - elif isinstance(marker, tuple): - lhs, op, rhs = marker - - if isinstance(lhs, Variable): - lhs_value = _get_env(environment, lhs.value) - rhs_value = rhs.value - else: - lhs_value = lhs.value - rhs_value = _get_env(environment, rhs.value) - - groups[-1].append(_eval_op(lhs_value, op, rhs_value)) - else: - assert marker in ["and", "or"] - if marker == "or": - groups.append([]) - - return any(all(item) for item in groups) - - -def format_full_version(info): - version = '{0.major}.{0.minor}.{0.micro}'.format(info) - kind = info.releaselevel - if kind != 'final': - version += kind[0] + str(info.serial) - return version - - -def default_environment(): - if hasattr(sys, 'implementation'): - iver = format_full_version(sys.implementation.version) - implementation_name = sys.implementation.name - else: - iver = '0' - implementation_name = '' - - return { - "implementation_name": implementation_name, - "implementation_version": iver, - "os_name": os.name, - "platform_machine": platform.machine(), - "platform_release": platform.release(), - "platform_system": platform.system(), - "platform_version": platform.version(), - "python_full_version": platform.python_version(), - "platform_python_implementation": platform.python_implementation(), - "python_version": platform.python_version()[:3], - "sys_platform": sys.platform, - } - - -class Marker(object): - - def __init__(self, marker): - try: - self._markers = _coerce_parse_result(MARKER.parseString(marker)) - except ParseException as e: - err_str = "Invalid marker: {0!r}, parse error at {1!r}".format( - marker, marker[e.loc:e.loc + 8]) - raise InvalidMarker(err_str) - - def __str__(self): - return _format_marker(self._markers) - - def __repr__(self): - return "<Marker({0!r})>".format(str(self)) - - def evaluate(self, environment=None): - """Evaluate a marker. - - Return the boolean from evaluating the given marker against the - environment. environment is an optional argument to override all or - part of the determined environment. - - The environment is determined from the current Python process. - """ - current_environment = default_environment() - if environment is not None: - current_environment.update(environment) - - return _evaluate_markers(self._markers, current_environment) diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/requirements.py b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/requirements.py deleted file mode 100644 index 0c8c4a3..0000000 --- a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/requirements.py +++ /dev/null @@ -1,127 +0,0 @@ -# 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 __future__ import absolute_import, division, print_function - -import string -import re - -from pkg_resources.extern.pyparsing import stringStart, stringEnd, originalTextFor, ParseException -from pkg_resources.extern.pyparsing import ZeroOrMore, Word, Optional, Regex, Combine -from pkg_resources.extern.pyparsing import Literal as L # noqa -from pkg_resources.extern.six.moves.urllib import parse as urlparse - -from .markers import MARKER_EXPR, Marker -from .specifiers import LegacySpecifier, Specifier, SpecifierSet - - -class InvalidRequirement(ValueError): - """ - An invalid requirement was found, users should refer to PEP 508. - """ - - -ALPHANUM = Word(string.ascii_letters + string.digits) - -LBRACKET = L("[").suppress() -RBRACKET = L("]").suppress() -LPAREN = L("(").suppress() -RPAREN = L(")").suppress() -COMMA = L(",").suppress() -SEMICOLON = L(";").suppress() -AT = L("@").suppress() - -PUNCTUATION = Word("-_.") -IDENTIFIER_END = ALPHANUM | (ZeroOrMore(PUNCTUATION) + ALPHANUM) -IDENTIFIER = Combine(ALPHANUM + ZeroOrMore(IDENTIFIER_END)) - -NAME = IDENTIFIER("name") -EXTRA = IDENTIFIER - -URI = Regex(r'[^ ]+')("url") -URL = (AT + URI) - -EXTRAS_LIST = EXTRA + ZeroOrMore(COMMA + EXTRA) -EXTRAS = (LBRACKET + Optional(EXTRAS_LIST) + RBRACKET)("extras") - -VERSION_PEP440 = Regex(Specifier._regex_str, re.VERBOSE | re.IGNORECASE) -VERSION_LEGACY = Regex(LegacySpecifier._regex_str, re.VERBOSE | re.IGNORECASE) - -VERSION_ONE = VERSION_PEP440 ^ VERSION_LEGACY -VERSION_MANY = Combine(VERSION_ONE + ZeroOrMore(COMMA + VERSION_ONE), - joinString=",", adjacent=False)("_raw_spec") -_VERSION_SPEC = Optional(((LPAREN + VERSION_MANY + RPAREN) | VERSION_MANY)) -_VERSION_SPEC.setParseAction(lambda s, l, t: t._raw_spec or '') - -VERSION_SPEC = originalTextFor(_VERSION_SPEC)("specifier") -VERSION_SPEC.setParseAction(lambda s, l, t: t[1]) - -MARKER_EXPR = originalTextFor(MARKER_EXPR())("marker") -MARKER_EXPR.setParseAction( - lambda s, l, t: Marker(s[t._original_start:t._original_end]) -) -MARKER_SEPERATOR = SEMICOLON -MARKER = MARKER_SEPERATOR + MARKER_EXPR - -VERSION_AND_MARKER = VERSION_SPEC + Optional(MARKER) -URL_AND_MARKER = URL + Optional(MARKER) - -NAMED_REQUIREMENT = \ - NAME + Optional(EXTRAS) + (URL_AND_MARKER | VERSION_AND_MARKER) - -REQUIREMENT = stringStart + NAMED_REQUIREMENT + stringEnd - - -class Requirement(object): - """Parse a requirement. - - Parse a given requirement string into its parts, such as name, specifier, - URL, and extras. Raises InvalidRequirement on a badly-formed requirement - string. - """ - - # TODO: Can we test whether something is contained within a requirement? - # If so how do we do that? Do we need to test against the _name_ of - # the thing as well as the version? What about the markers? - # TODO: Can we normalize the name and extra name? - - def __init__(self, requirement_string): - try: - req = REQUIREMENT.parseString(requirement_string) - except ParseException as e: - raise InvalidRequirement( - "Invalid requirement, parse error at \"{0!r}\"".format( - requirement_string[e.loc:e.loc + 8])) - - self.name = req.name - if req.url: - parsed_url = urlparse.urlparse(req.url) - if not (parsed_url.scheme and parsed_url.netloc) or ( - not parsed_url.scheme and not parsed_url.netloc): - raise InvalidRequirement("Invalid URL given") - self.url = req.url - else: - self.url = None - self.extras = set(req.extras.asList() if req.extras else []) - self.specifier = SpecifierSet(req.specifier) - self.marker = req.marker if req.marker else None - - def __str__(self): - parts = [self.name] - - if self.extras: - parts.append("[{0}]".format(",".join(sorted(self.extras)))) - - if self.specifier: - parts.append(str(self.specifier)) - - if self.url: - parts.append("@ {0}".format(self.url)) - - if self.marker: - parts.append("; {0}".format(self.marker)) - - return "".join(parts) - - def __repr__(self): - return "<Requirement({0!r})>".format(str(self)) diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/specifiers.py b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/specifiers.py deleted file mode 100644 index 7f5a76c..0000000 --- a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/specifiers.py +++ /dev/null @@ -1,774 +0,0 @@ -# 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 __future__ import absolute_import, division, print_function - -import abc -import functools -import itertools -import re - -from ._compat import string_types, with_metaclass -from .version import Version, LegacyVersion, parse - - -class InvalidSpecifier(ValueError): - """ - An invalid specifier was found, users should refer to PEP 440. - """ - - -class BaseSpecifier(with_metaclass(abc.ABCMeta, object)): - - @abc.abstractmethod - def __str__(self): - """ - Returns the str representation of this Specifier like object. This - should be representative of the Specifier itself. - """ - - @abc.abstractmethod - def __hash__(self): - """ - Returns a hash value for this Specifier like object. - """ - - @abc.abstractmethod - def __eq__(self, other): - """ - Returns a boolean representing whether or not the two Specifier like - objects are equal. - """ - - @abc.abstractmethod - def __ne__(self, other): - """ - Returns a boolean representing whether or not the two Specifier like - objects are not equal. - """ - - @abc.abstractproperty - def prereleases(self): - """ - Returns whether or not pre-releases as a whole are allowed by this - specifier. - """ - - @prereleases.setter - def prereleases(self, value): - """ - Sets whether or not pre-releases as a whole are allowed by this - specifier. - """ - - @abc.abstractmethod - def contains(self, item, prereleases=None): - """ - Determines if the given item is contained within this specifier. - """ - - @abc.abstractmethod - def filter(self, iterable, prereleases=None): - """ - Takes an iterable of items and filters them so that only items which - are contained within this specifier are allowed in it. - """ - - -class _IndividualSpecifier(BaseSpecifier): - - _operators = {} - - def __init__(self, spec="", prereleases=None): - match = self._regex.search(spec) - if not match: - raise InvalidSpecifier("Invalid specifier: '{0}'".format(spec)) - - self._spec = ( - match.group("operator").strip(), - match.group("version").strip(), - ) - - # Store whether or not this Specifier should accept prereleases - self._prereleases = prereleases - - def __repr__(self): - pre = ( - ", prereleases={0!r}".format(self.prereleases) - if self._prereleases is not None - else "" - ) - - return "<{0}({1!r}{2})>".format( - self.__class__.__name__, - str(self), - pre, - ) - - def __str__(self): - return "{0}{1}".format(*self._spec) - - def __hash__(self): - return hash(self._spec) - - def __eq__(self, other): - if isinstance(other, string_types): - try: - other = self.__class__(other) - except InvalidSpecifier: - return NotImplemented - elif not isinstance(other, self.__class__): - return NotImplemented - - return self._spec == other._spec - - def __ne__(self, other): - if isinstance(other, string_types): - try: - other = self.__class__(other) - except InvalidSpecifier: - return NotImplemented - elif not isinstance(other, self.__class__): - return NotImplemented - - return self._spec != other._spec - - def _get_operator(self, op): - return getattr(self, "_compare_{0}".format(self._operators[op])) - - def _coerce_version(self, version): - if not isinstance(version, (LegacyVersion, Version)): - version = parse(version) - return version - - @property - def operator(self): - return self._spec[0] - - @property - def version(self): - return self._spec[1] - - @property - def prereleases(self): - return self._prereleases - - @prereleases.setter - def prereleases(self, value): - self._prereleases = value - - def __contains__(self, item): - return self.contains(item) - - def contains(self, item, prereleases=None): - # Determine if prereleases are to be allowed or not. - if prereleases is None: - prereleases = self.prereleases - - # Normalize item to a Version or LegacyVersion, this allows us to have - # a shortcut for ``"2.0" in Specifier(">=2") - item = self._coerce_version(item) - - # Determine if we should be supporting prereleases in this specifier - # or not, if we do not support prereleases than we can short circuit - # logic if this version is a prereleases. - if item.is_prerelease and not prereleases: - return False - - # Actually do the comparison to determine if this item is contained - # within this Specifier or not. - return self._get_operator(self.operator)(item, self.version) - - def filter(self, iterable, prereleases=None): - yielded = False - found_prereleases = [] - - kw = {"prereleases": prereleases if prereleases is not None else True} - - # Attempt to iterate over all the values in the iterable and if any of - # them match, yield them. - for version in iterable: - parsed_version = self._coerce_version(version) - - if self.contains(parsed_version, **kw): - # If our version is a prerelease, and we were not set to allow - # prereleases, then we'll store it for later incase nothing - # else matches this specifier. - if (parsed_version.is_prerelease and not - (prereleases or self.prereleases)): - found_prereleases.append(version) - # Either this is not a prerelease, or we should have been - # accepting prereleases from the begining. - else: - yielded = True - yield version - - # Now that we've iterated over everything, determine if we've yielded - # any values, and if we have not and we have any prereleases stored up - # then we will go ahead and yield the prereleases. - if not yielded and found_prereleases: - for version in found_prereleases: - yield version - - -class LegacySpecifier(_IndividualSpecifier): - - _regex_str = ( - r""" - (?P<operator>(==|!=|<=|>=|<|>)) - \s* - (?P<version> - [^,;\s)]* # Since this is a "legacy" specifier, and the version - # string can be just about anything, we match everything - # except for whitespace, a semi-colon for marker support, - # a closing paren since versions can be enclosed in - # them, and a comma since it's a version separator. - ) - """ - ) - - _regex = re.compile( - r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE) - - _operators = { - "==": "equal", - "!=": "not_equal", - "<=": "less_than_equal", - ">=": "greater_than_equal", - "<": "less_than", - ">": "greater_than", - } - - def _coerce_version(self, version): - if not isinstance(version, LegacyVersion): - version = LegacyVersion(str(version)) - return version - - def _compare_equal(self, prospective, spec): - return prospective == self._coerce_version(spec) - - def _compare_not_equal(self, prospective, spec): - return prospective != self._coerce_version(spec) - - def _compare_less_than_equal(self, prospective, spec): - return prospective <= self._coerce_version(spec) - - def _compare_greater_than_equal(self, prospective, spec): - return prospective >= self._coerce_version(spec) - - def _compare_less_than(self, prospective, spec): - return prospective < self._coerce_version(spec) - - def _compare_greater_than(self, prospective, spec): - return prospective > self._coerce_version(spec) - - -def _require_version_compare(fn): - @functools.wraps(fn) - def wrapped(self, prospective, spec): - if not isinstance(prospective, Version): - return False - return fn(self, prospective, spec) - return wrapped - - -class Specifier(_IndividualSpecifier): - - _regex_str = ( - r""" - (?P<operator>(~=|==|!=|<=|>=|<|>|===)) - (?P<version> - (?: - # The identity operators allow for an escape hatch that will - # do an exact string match of the version you wish to install. - # This will not be parsed by PEP 440 and we cannot determine - # any semantic meaning from it. This operator is discouraged - # but included entirely as an escape hatch. - (?<====) # Only match for the identity operator - \s* - [^\s]* # We just match everything, except for whitespace - # since we are only testing for strict identity. - ) - | - (?: - # The (non)equality operators allow for wild card and local - # versions to be specified so we have to define these two - # operators separately to enable that. - (?<===|!=) # Only match for equals and not equals - - \s* - v? - (?:[0-9]+!)? # epoch - [0-9]+(?:\.[0-9]+)* # release - (?: # pre release - [-_\.]? - (a|b|c|rc|alpha|beta|pre|preview) - [-_\.]? - [0-9]* - )? - (?: # post release - (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*) - )? - - # You cannot use a wild card and a dev or local version - # together so group them with a | and make them optional. - (?: - (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release - (?:\+[a-z0-9]+(?:[-_\.][a-z0-9]+)*)? # local - | - \.\* # Wild card syntax of .* - )? - ) - | - (?: - # The compatible operator requires at least two digits in the - # release segment. - (?<=~=) # Only match for the compatible operator - - \s* - v? - (?:[0-9]+!)? # epoch - [0-9]+(?:\.[0-9]+)+ # release (We have a + instead of a *) - (?: # pre release - [-_\.]? - (a|b|c|rc|alpha|beta|pre|preview) - [-_\.]? - [0-9]* - )? - (?: # post release - (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*) - )? - (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release - ) - | - (?: - # All other operators only allow a sub set of what the - # (non)equality operators do. Specifically they do not allow - # local versions to be specified nor do they allow the prefix - # matching wild cards. - (?<!==|!=|~=) # We have special cases for these - # operators so we want to make sure they - # don't match here. - - \s* - v? - (?:[0-9]+!)? # epoch - [0-9]+(?:\.[0-9]+)* # release - (?: # pre release - [-_\.]? - (a|b|c|rc|alpha|beta|pre|preview) - [-_\.]? - [0-9]* - )? - (?: # post release - (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*) - )? - (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release - ) - ) - """ - ) - - _regex = re.compile( - r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE) - - _operators = { - "~=": "compatible", - "==": "equal", - "!=": "not_equal", - "<=": "less_than_equal", - ">=": "greater_than_equal", - "<": "less_than", - ">": "greater_than", - "===": "arbitrary", - } - - @_require_version_compare - def _compare_compatible(self, prospective, spec): - # Compatible releases have an equivalent combination of >= and ==. That - # is that ~=2.2 is equivalent to >=2.2,==2.*. This allows us to - # implement this in terms of the other specifiers instead of - # implementing it ourselves. The only thing we need to do is construct - # the other specifiers. - - # We want everything but the last item in the version, but we want to - # ignore post and dev releases and we want to treat the pre-release as - # it's own separate segment. - prefix = ".".join( - list( - itertools.takewhile( - lambda x: (not x.startswith("post") and not - x.startswith("dev")), - _version_split(spec), - ) - )[:-1] - ) - - # Add the prefix notation to the end of our string - prefix += ".*" - - return (self._get_operator(">=")(prospective, spec) and - self._get_operator("==")(prospective, prefix)) - - @_require_version_compare - def _compare_equal(self, prospective, spec): - # We need special logic to handle prefix matching - if spec.endswith(".*"): - # In the case of prefix matching we want to ignore local segment. - prospective = Version(prospective.public) - # Split the spec out by dots, and pretend that there is an implicit - # dot in between a release segment and a pre-release segment. - spec = _version_split(spec[:-2]) # Remove the trailing .* - - # Split the prospective version out by dots, and pretend that there - # is an implicit dot in between a release segment and a pre-release - # segment. - prospective = _version_split(str(prospective)) - - # Shorten the prospective version to be the same length as the spec - # so that we can determine if the specifier is a prefix of the - # prospective version or not. - prospective = prospective[:len(spec)] - - # Pad out our two sides with zeros so that they both equal the same - # length. - spec, prospective = _pad_version(spec, prospective) - else: - # Convert our spec string into a Version - spec = Version(spec) - - # If the specifier does not have a local segment, then we want to - # act as if the prospective version also does not have a local - # segment. - if not spec.local: - prospective = Version(prospective.public) - - return prospective == spec - - @_require_version_compare - def _compare_not_equal(self, prospective, spec): - return not self._compare_equal(prospective, spec) - - @_require_version_compare - def _compare_less_than_equal(self, prospective, spec): - return prospective <= Version(spec) - - @_require_version_compare - def _compare_greater_than_equal(self, prospective, spec): - return prospective >= Version(spec) - - @_require_version_compare - def _compare_less_than(self, prospective, spec): - # Convert our spec to a Version instance, since we'll want to work with - # it as a version. - spec = Version(spec) - - # Check to see if the prospective version is less than the spec - # version. If it's not we can short circuit and just return False now - # instead of doing extra unneeded work. - if not prospective < spec: - return False - - # This special case is here so that, unless the specifier itself - # includes is a pre-release version, that we do not accept pre-release - # versions for the version mentioned in the specifier (e.g. <3.1 should - # not match 3.1.dev0, but should match 3.0.dev0). - if not spec.is_prerelease and prospective.is_prerelease: - if Version(prospective.base_version) == Version(spec.base_version): - return False - - # If we've gotten to here, it means that prospective version is both - # less than the spec version *and* it's not a pre-release of the same - # version in the spec. - return True - - @_require_version_compare - def _compare_greater_than(self, prospective, spec): - # Convert our spec to a Version instance, since we'll want to work with - # it as a version. - spec = Version(spec) - - # Check to see if the prospective version is greater than the spec - # version. If it's not we can short circuit and just return False now - # instead of doing extra unneeded work. - if not prospective > spec: - return False - - # This special case is here so that, unless the specifier itself - # includes is a post-release version, that we do not accept - # post-release versions for the version mentioned in the specifier - # (e.g. >3.1 should not match 3.0.post0, but should match 3.2.post0). - if not spec.is_postrelease and prospective.is_postrelease: - if Version(prospective.base_version) == Version(spec.base_version): - return False - - # Ensure that we do not allow a local version of the version mentioned - # in the specifier, which is techincally greater than, to match. - if prospective.local is not None: - if Version(prospective.base_version) == Version(spec.base_version): - return False - - # If we've gotten to here, it means that prospective version is both - # greater than the spec version *and* it's not a pre-release of the - # same version in the spec. - return True - - def _compare_arbitrary(self, prospective, spec): - return str(prospective).lower() == str(spec).lower() - - @property - def prereleases(self): - # If there is an explicit prereleases set for this, then we'll just - # blindly use that. - if self._prereleases is not None: - return self._prereleases - - # Look at all of our specifiers and determine if they are inclusive - # operators, and if they are if they are including an explicit - # prerelease. - operator, version = self._spec - if operator in ["==", ">=", "<=", "~=", "==="]: - # The == specifier can include a trailing .*, if it does we - # want to remove before parsing. - if operator == "==" and version.endswith(".*"): - version = version[:-2] - - # Parse the version, and if it is a pre-release than this - # specifier allows pre-releases. - if parse(version).is_prerelease: - return True - - return False - - @prereleases.setter - def prereleases(self, value): - self._prereleases = value - - -_prefix_regex = re.compile(r"^([0-9]+)((?:a|b|c|rc)[0-9]+)$") - - -def _version_split(version): - result = [] - for item in version.split("."): - match = _prefix_regex.search(item) - if match: - result.extend(match.groups()) - else: - result.append(item) - return result - - -def _pad_version(left, right): - left_split, right_split = [], [] - - # Get the release segment of our versions - left_split.append(list(itertools.takewhile(lambda x: x.isdigit(), left))) - right_split.append(list(itertools.takewhile(lambda x: x.isdigit(), right))) - - # Get the rest of our versions - left_split.append(left[len(left_split[0]):]) - right_split.append(right[len(right_split[0]):]) - - # Insert our padding - left_split.insert( - 1, - ["0"] * max(0, len(right_split[0]) - len(left_split[0])), - ) - right_split.insert( - 1, - ["0"] * max(0, len(left_split[0]) - len(right_split[0])), - ) - - return ( - list(itertools.chain(*left_split)), - list(itertools.chain(*right_split)), - ) - - -class SpecifierSet(BaseSpecifier): - - def __init__(self, specifiers="", prereleases=None): - # Split on , to break each indidivual specifier into it's own item, and - # strip each item to remove leading/trailing whitespace. - specifiers = [s.strip() for s in specifiers.split(",") if s.strip()] - - # Parsed each individual specifier, attempting first to make it a - # Specifier and falling back to a LegacySpecifier. - parsed = set() - for specifier in specifiers: - try: - parsed.add(Specifier(specifier)) - except InvalidSpecifier: - parsed.add(LegacySpecifier(specifier)) - - # Turn our parsed specifiers into a frozen set and save them for later. - self._specs = frozenset(parsed) - - # Store our prereleases value so we can use it later to determine if - # we accept prereleases or not. - self._prereleases = prereleases - - def __repr__(self): - pre = ( - ", prereleases={0!r}".format(self.prereleases) - if self._prereleases is not None - else "" - ) - - return "<SpecifierSet({0!r}{1})>".format(str(self), pre) - - def __str__(self): - return ",".join(sorted(str(s) for s in self._specs)) - - def __hash__(self): - return hash(self._specs) - - def __and__(self, other): - if isinstance(other, string_types): - other = SpecifierSet(other) - elif not isinstance(other, SpecifierSet): - return NotImplemented - - specifier = SpecifierSet() - specifier._specs = frozenset(self._specs | other._specs) - - if self._prereleases is None and other._prereleases is not None: - specifier._prereleases = other._prereleases - elif self._prereleases is not None and other._prereleases is None: - specifier._prereleases = self._prereleases - elif self._prereleases == other._prereleases: - specifier._prereleases = self._prereleases - else: - raise ValueError( - "Cannot combine SpecifierSets with True and False prerelease " - "overrides." - ) - - return specifier - - def __eq__(self, other): - if isinstance(other, string_types): - other = SpecifierSet(other) - elif isinstance(other, _IndividualSpecifier): - other = SpecifierSet(str(other)) - elif not isinstance(other, SpecifierSet): - return NotImplemented - - return self._specs == other._specs - - def __ne__(self, other): - if isinstance(other, string_types): - other = SpecifierSet(other) - elif isinstance(other, _IndividualSpecifier): - other = SpecifierSet(str(other)) - elif not isinstance(other, SpecifierSet): - return NotImplemented - - return self._specs != other._specs - - def __len__(self): - return len(self._specs) - - def __iter__(self): - return iter(self._specs) - - @property - def prereleases(self): - # If we have been given an explicit prerelease modifier, then we'll - # pass that through here. - if self._prereleases is not None: - return self._prereleases - - # If we don't have any specifiers, and we don't have a forced value, - # then we'll just return None since we don't know if this should have - # pre-releases or not. - if not self._specs: - return None - - # Otherwise we'll see if any of the given specifiers accept - # prereleases, if any of them do we'll return True, otherwise False. - return any(s.prereleases for s in self._specs) - - @prereleases.setter - def prereleases(self, value): - self._prereleases = value - - def __contains__(self, item): - return self.contains(item) - - def contains(self, item, prereleases=None): - # Ensure that our item is a Version or LegacyVersion instance. - if not isinstance(item, (LegacyVersion, Version)): - item = parse(item) - - # Determine if we're forcing a prerelease or not, if we're not forcing - # one for this particular filter call, then we'll use whatever the - # SpecifierSet thinks for whether or not we should support prereleases. - if prereleases is None: - prereleases = self.prereleases - - # We can determine if we're going to allow pre-releases by looking to - # see if any of the underlying items supports them. If none of them do - # and this item is a pre-release then we do not allow it and we can - # short circuit that here. - # Note: This means that 1.0.dev1 would not be contained in something - # like >=1.0.devabc however it would be in >=1.0.debabc,>0.0.dev0 - if not prereleases and item.is_prerelease: - return False - - # We simply dispatch to the underlying specs here to make sure that the - # given version is contained within all of them. - # Note: This use of all() here means that an empty set of specifiers - # will always return True, this is an explicit design decision. - return all( - s.contains(item, prereleases=prereleases) - for s in self._specs - ) - - def filter(self, iterable, prereleases=None): - # Determine if we're forcing a prerelease or not, if we're not forcing - # one for this particular filter call, then we'll use whatever the - # SpecifierSet thinks for whether or not we should support prereleases. - if prereleases is None: - prereleases = self.prereleases - - # If we have any specifiers, then we want to wrap our iterable in the - # filter method for each one, this will act as a logical AND amongst - # each specifier. - if self._specs: - for spec in self._specs: - iterable = spec.filter(iterable, prereleases=bool(prereleases)) - return iterable - # If we do not have any specifiers, then we need to have a rough filter - # which will filter out any pre-releases, unless there are no final - # releases, and which will filter out LegacyVersion in general. - else: - filtered = [] - found_prereleases = [] - - for item in iterable: - # Ensure that we some kind of Version class for this item. - if not isinstance(item, (LegacyVersion, Version)): - parsed_version = parse(item) - else: - parsed_version = item - - # Filter out any item which is parsed as a LegacyVersion - if isinstance(parsed_version, LegacyVersion): - continue - - # Store any item which is a pre-release for later unless we've - # already found a final version or we are accepting prereleases - if parsed_version.is_prerelease and not prereleases: - if not filtered: - found_prereleases.append(item) - else: - filtered.append(item) - - # If we've found no items except for pre-releases, then we'll go - # ahead and use the pre-releases - if not filtered and found_prereleases and prereleases is None: - return found_prereleases - - return filtered diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/utils.py b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/utils.py deleted file mode 100644 index 942387c..0000000 --- a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/utils.py +++ /dev/null @@ -1,14 +0,0 @@ -# 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 __future__ import absolute_import, division, print_function - -import re - - -_canonicalize_regex = re.compile(r"[-_.]+") - - -def canonicalize_name(name): - # This is taken from PEP 503. - return _canonicalize_regex.sub("-", name).lower() diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/version.py b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/version.py deleted file mode 100644 index 83b5ee8..0000000 --- a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/version.py +++ /dev/null @@ -1,393 +0,0 @@ -# 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 __future__ import absolute_import, division, print_function - -import collections -import itertools -import re - -from ._structures import Infinity - - -__all__ = [ - "parse", "Version", "LegacyVersion", "InvalidVersion", "VERSION_PATTERN" -] - - -_Version = collections.namedtuple( - "_Version", - ["epoch", "release", "dev", "pre", "post", "local"], -) - - -def parse(version): - """ - Parse the given version string and return either a :class:`Version` object - or a :class:`LegacyVersion` object depending on if the given version is - a valid PEP 440 version or a legacy version. - """ - try: - return Version(version) - except InvalidVersion: - return LegacyVersion(version) - - -class InvalidVersion(ValueError): - """ - An invalid version was found, users should refer to PEP 440. - """ - - -class _BaseVersion(object): - - def __hash__(self): - return hash(self._key) - - def __lt__(self, other): - return self._compare(other, lambda s, o: s < o) - - def __le__(self, other): - return self._compare(other, lambda s, o: s <= o) - - def __eq__(self, other): - return self._compare(other, lambda s, o: s == o) - - def __ge__(self, other): - return self._compare(other, lambda s, o: s >= o) - - def __gt__(self, other): - return self._compare(other, lambda s, o: s > o) - - def __ne__(self, other): - return self._compare(other, lambda s, o: s != o) - - def _compare(self, other, method): - if not isinstance(other, _BaseVersion): - return NotImplemented - - return method(self._key, other._key) - - -class LegacyVersion(_BaseVersion): - - def __init__(self, version): - self._version = str(version) - self._key = _legacy_cmpkey(self._version) - - def __str__(self): - return self._version - - def __repr__(self): - return "<LegacyVersion({0})>".format(repr(str(self))) - - @property - def public(self): - return self._version - - @property - def base_version(self): - return self._version - - @property - def local(self): - return None - - @property - def is_prerelease(self): - return False - - @property - def is_postrelease(self): - return False - - -_legacy_version_component_re = re.compile( - r"(\d+ | [a-z]+ | \.| -)", re.VERBOSE, -) - -_legacy_version_replacement_map = { - "pre": "c", "preview": "c", "-": "final-", "rc": "c", "dev": "@", -} - - -def _parse_version_parts(s): - for part in _legacy_version_component_re.split(s): - part = _legacy_version_replacement_map.get(part, part) - - if not part or part == ".": - continue - - if part[:1] in "0123456789": - # pad for numeric comparison - yield part.zfill(8) - else: - yield "*" + part - - # ensure that alpha/beta/candidate are before final - yield "*final" - - -def _legacy_cmpkey(version): - # We hardcode an epoch of -1 here. A PEP 440 version can only have a epoch - # greater than or equal to 0. This will effectively put the LegacyVersion, - # which uses the defacto standard originally implemented by setuptools, - # as before all PEP 440 versions. - epoch = -1 - - # This scheme is taken from pkg_resources.parse_version setuptools prior to - # it's adoption of the packaging library. - parts = [] - for part in _parse_version_parts(version.lower()): - if part.startswith("*"): - # remove "-" before a prerelease tag - if part < "*final": - while parts and parts[-1] == "*final-": - parts.pop() - - # remove trailing zeros from each series of numeric parts - while parts and parts[-1] == "00000000": - parts.pop() - - parts.append(part) - parts = tuple(parts) - - return epoch, parts - -# Deliberately not anchored to the start and end of the string, to make it -# easier for 3rd party code to reuse -VERSION_PATTERN = r""" - v? - (?: - (?:(?P<epoch>[0-9]+)!)? # epoch - (?P<release>[0-9]+(?:\.[0-9]+)*) # release segment - (?P<pre> # pre-release - [-_\.]? - (?P<pre_l>(a|b|c|rc|alpha|beta|pre|preview)) - [-_\.]? - (?P<pre_n>[0-9]+)? - )? - (?P<post> # post release - (?:-(?P<post_n1>[0-9]+)) - | - (?: - [-_\.]? - (?P<post_l>post|rev|r) - [-_\.]? - (?P<post_n2>[0-9]+)? - ) - )? - (?P<dev> # dev release - [-_\.]? - (?P<dev_l>dev) - [-_\.]? - (?P<dev_n>[0-9]+)? - )? - ) - (?:\+(?P<local>[a-z0-9]+(?:[-_\.][a-z0-9]+)*))? # local version -""" - - -class Version(_BaseVersion): - - _regex = re.compile( - r"^\s*" + VERSION_PATTERN + r"\s*$", - re.VERBOSE | re.IGNORECASE, - ) - - def __init__(self, version): - # Validate the version and parse it into pieces - match = self._regex.search(version) - if not match: - raise InvalidVersion("Invalid version: '{0}'".format(version)) - - # Store the parsed out pieces of the version - self._version = _Version( - epoch=int(match.group("epoch")) if match.group("epoch") else 0, - release=tuple(int(i) for i in match.group("release").split(".")), - pre=_parse_letter_version( - match.group("pre_l"), - match.group("pre_n"), - ), - post=_parse_letter_version( - match.group("post_l"), - match.group("post_n1") or match.group("post_n2"), - ), - dev=_parse_letter_version( - match.group("dev_l"), - match.group("dev_n"), - ), - local=_parse_local_version(match.group("local")), - ) - - # Generate a key which will be used for sorting - self._key = _cmpkey( - self._version.epoch, - self._version.release, - self._version.pre, - self._version.post, - self._version.dev, - self._version.local, - ) - - def __repr__(self): - return "<Version({0})>".format(repr(str(self))) - - def __str__(self): - parts = [] - - # Epoch - if self._version.epoch != 0: - parts.append("{0}!".format(self._version.epoch)) - - # Release segment - parts.append(".".join(str(x) for x in self._version.release)) - - # Pre-release - if self._version.pre is not None: - parts.append("".join(str(x) for x in self._version.pre)) - - # Post-release - if self._version.post is not None: - parts.append(".post{0}".format(self._version.post[1])) - - # Development release - if self._version.dev is not None: - parts.append(".dev{0}".format(self._version.dev[1])) - - # Local version segment - if self._version.local is not None: - parts.append( - "+{0}".format(".".join(str(x) for x in self._version.local)) - ) - - return "".join(parts) - - @property - def public(self): - return str(self).split("+", 1)[0] - - @property - def base_version(self): - parts = [] - - # Epoch - if self._version.epoch != 0: - parts.append("{0}!".format(self._version.epoch)) - - # Release segment - parts.append(".".join(str(x) for x in self._version.release)) - - return "".join(parts) - - @property - def local(self): - version_string = str(self) - if "+" in version_string: - return version_string.split("+", 1)[1] - - @property - def is_prerelease(self): - return bool(self._version.dev or self._version.pre) - - @property - def is_postrelease(self): - return bool(self._version.post) - - -def _parse_letter_version(letter, number): - if letter: - # We consider there to be an implicit 0 in a pre-release if there is - # not a numeral associated with it. - if number is None: - number = 0 - - # We normalize any letters to their lower case form - letter = letter.lower() - - # We consider some words to be alternate spellings of other words and - # in those cases we want to normalize the spellings to our preferred - # spelling. - if letter == "alpha": - letter = "a" - elif letter == "beta": - letter = "b" - elif letter in ["c", "pre", "preview"]: - letter = "rc" - elif letter in ["rev", "r"]: - letter = "post" - - return letter, int(number) - if not letter and number: - # We assume if we are given a number, but we are not given a letter - # then this is using the implicit post release syntax (e.g. 1.0-1) - letter = "post" - - return letter, int(number) - - -_local_version_seperators = re.compile(r"[\._-]") - - -def _parse_local_version(local): - """ - Takes a string like abc.1.twelve and turns it into ("abc", 1, "twelve"). - """ - if local is not None: - return tuple( - part.lower() if not part.isdigit() else int(part) - for part in _local_version_seperators.split(local) - ) - - -def _cmpkey(epoch, release, pre, post, dev, local): - # When we compare a release version, we want to compare it with all of the - # trailing zeros removed. So we'll use a reverse the list, drop all the now - # leading zeros until we come to something non zero, then take the rest - # re-reverse it back into the correct order and make it a tuple and use - # that for our sorting key. - release = tuple( - reversed(list( - itertools.dropwhile( - lambda x: x == 0, - reversed(release), - ) - )) - ) - - # We need to "trick" the sorting algorithm to put 1.0.dev0 before 1.0a0. - # We'll do this by abusing the pre segment, but we _only_ want to do this - # if there is not a pre or a post segment. If we have one of those then - # the normal sorting rules will handle this case correctly. - if pre is None and post is None and dev is not None: - pre = -Infinity - # Versions without a pre-release (except as noted above) should sort after - # those with one. - elif pre is None: - pre = Infinity - - # Versions without a post segment should sort before those with one. - if post is None: - post = -Infinity - - # Versions without a development segment should sort after those with one. - if dev is None: - dev = Infinity - - if local is None: - # Versions without a local segment should sort before those with one. - local = -Infinity - else: - # Versions with a local segment need that segment parsed to implement - # the sorting rules in PEP440. - # - Alpha numeric segments sort before numeric segments - # - Alpha numeric segments sort lexicographically - # - Numeric segments sort numerically - # - Shorter versions sort before longer versions when the prefixes - # match exactly - local = tuple( - (i, "") if isinstance(i, int) else (-Infinity, i) - for i in local - ) - - return epoch, release, pre, post, dev, local diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/pyparsing.py b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/pyparsing.py deleted file mode 100644 index cf75e1e..0000000 --- a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/pyparsing.py +++ /dev/null @@ -1,5742 +0,0 @@ -# module pyparsing.py -# -# Copyright (c) 2003-2018 Paul T. McGuire -# -# 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. -# - -__doc__ = \ -""" -pyparsing module - Classes and methods to define and execute parsing grammars -============================================================================= - -The pyparsing module is an alternative approach to creating and executing simple grammars, -vs. the traditional lex/yacc approach, or the use of regular expressions. With pyparsing, you -don't need to learn a new syntax for defining grammars or matching expressions - the parsing module -provides a library of classes that you use to construct the grammar directly in Python. - -Here is a program to parse "Hello, World!" (or any greeting of the form -C{"<salutation>, <addressee>!"}), built up using L{Word}, L{Literal}, and L{And} elements -(L{'+'<ParserElement.__add__>} operator gives L{And} expressions, strings are auto-converted to -L{Literal} expressions):: - - from pyparsing import Word, alphas - - # define grammar of a greeting - greet = Word(alphas) + "," + Word(alphas) + "!" - - hello = "Hello, World!" - print (hello, "->", greet.parseString(hello)) - -The program outputs the following:: - - Hello, World! -> ['Hello', ',', 'World', '!'] - -The Python representation of the grammar is quite readable, owing to the self-explanatory -class names, and the use of '+', '|' and '^' operators. - -The L{ParseResults} object returned from L{ParserElement.parseString<ParserElement.parseString>} can be accessed as a nested list, a dictionary, or an -object with named attributes. - -The pyparsing module handles some of the problems that are typically vexing when writing text parsers: - - extra or missing whitespace (the above program will also handle "Hello,World!", "Hello , World !", etc.) - - quoted strings - - embedded comments - - -Getting Started - ------------------ -Visit the classes L{ParserElement} and L{ParseResults} to see the base classes that most other pyparsing -classes inherit from. Use the docstrings for examples of how to: - - construct literal match expressions from L{Literal} and L{CaselessLiteral} classes - - construct character word-group expressions using the L{Word} class - - see how to create repetitive expressions using L{ZeroOrMore} and L{OneOrMore} classes - - use L{'+'<And>}, L{'|'<MatchFirst>}, L{'^'<Or>}, and L{'&'<Each>} operators to combine simple expressions into more complex ones - - associate names with your parsed results using L{ParserElement.setResultsName} - - find some helpful expression short-cuts like L{delimitedList} and L{oneOf} - - find more useful common expressions in the L{pyparsing_common} namespace class -""" - -__version__ = "2.2.1" -__versionTime__ = "18 Sep 2018 00:49 UTC" -__author__ = "Paul McGuire <ptmcg@users.sourceforge.net>" - -import string -from weakref import ref as wkref -import copy -import sys -import warnings -import re -import sre_constants -import collections -import pprint -import traceback -import types -from datetime import datetime - -try: - from _thread import RLock -except ImportError: - from threading import RLock - -try: - # Python 3 - from collections.abc import Iterable - from collections.abc import MutableMapping -except ImportError: - # Python 2.7 - from collections import Iterable - from collections import MutableMapping - -try: - from collections import OrderedDict as _OrderedDict -except ImportError: - try: - from ordereddict import OrderedDict as _OrderedDict - except ImportError: - _OrderedDict = None - -#~ sys.stderr.write( "testing pyparsing module, version %s, %s\n" % (__version__,__versionTime__ ) ) - -__all__ = [ -'And', 'CaselessKeyword', 'CaselessLiteral', 'CharsNotIn', 'Combine', 'Dict', 'Each', 'Empty', -'FollowedBy', 'Forward', 'GoToColumn', 'Group', 'Keyword', 'LineEnd', 'LineStart', 'Literal', -'MatchFirst', 'NoMatch', 'NotAny', 'OneOrMore', 'OnlyOnce', 'Optional', 'Or', -'ParseBaseException', 'ParseElementEnhance', 'ParseException', 'ParseExpression', 'ParseFatalException', -'ParseResults', 'ParseSyntaxException', 'ParserElement', 'QuotedString', 'RecursiveGrammarException', -'Regex', 'SkipTo', 'StringEnd', 'StringStart', 'Suppress', 'Token', 'TokenConverter', -'White', 'Word', 'WordEnd', 'WordStart', 'ZeroOrMore', -'alphanums', 'alphas', 'alphas8bit', 'anyCloseTag', 'anyOpenTag', 'cStyleComment', 'col', -'commaSeparatedList', 'commonHTMLEntity', 'countedArray', 'cppStyleComment', 'dblQuotedString', -'dblSlashComment', 'delimitedList', 'dictOf', 'downcaseTokens', 'empty', 'hexnums', -'htmlComment', 'javaStyleComment', 'line', 'lineEnd', 'lineStart', 'lineno', -'makeHTMLTags', 'makeXMLTags', 'matchOnlyAtCol', 'matchPreviousExpr', 'matchPreviousLiteral', -'nestedExpr', 'nullDebugAction', 'nums', 'oneOf', 'opAssoc', 'operatorPrecedence', 'printables', -'punc8bit', 'pythonStyleComment', 'quotedString', 'removeQuotes', 'replaceHTMLEntity', -'replaceWith', 'restOfLine', 'sglQuotedString', 'srange', 'stringEnd', -'stringStart', 'traceParseAction', 'unicodeString', 'upcaseTokens', 'withAttribute', -'indentedBlock', 'originalTextFor', 'ungroup', 'infixNotation','locatedExpr', 'withClass', -'CloseMatch', 'tokenMap', 'pyparsing_common', -] - -system_version = tuple(sys.version_info)[:3] -PY_3 = system_version[0] == 3 -if PY_3: - _MAX_INT = sys.maxsize - basestring = str - unichr = chr - _ustr = str - - # build list of single arg builtins, that can be used as parse actions - singleArgBuiltins = [sum, len, sorted, reversed, list, tuple, set, any, all, min, max] - -else: - _MAX_INT = sys.maxint - range = xrange - - def _ustr(obj): - """Drop-in replacement for str(obj) that tries to be Unicode friendly. It first tries - str(obj). If that fails with a UnicodeEncodeError, then it tries unicode(obj). It - then < returns the unicode object | encodes it with the default encoding | ... >. - """ - if isinstance(obj,unicode): - return obj - - try: - # If this works, then _ustr(obj) has the same behaviour as str(obj), so - # it won't break any existing code. - return str(obj) - - except UnicodeEncodeError: - # Else encode it - ret = unicode(obj).encode(sys.getdefaultencoding(), 'xmlcharrefreplace') - xmlcharref = Regex(r'&#\d+;') - xmlcharref.setParseAction(lambda t: '\\u' + hex(int(t[0][2:-1]))[2:]) - return xmlcharref.transformString(ret) - - # build list of single arg builtins, tolerant of Python version, that can be used as parse actions - singleArgBuiltins = [] - import __builtin__ - for fname in "sum len sorted reversed list tuple set any all min max".split(): - try: - singleArgBuiltins.append(getattr(__builtin__,fname)) - except AttributeError: - continue - -_generatorType = type((y for y in range(1))) - -def _xml_escape(data): - """Escape &, <, >, ", ', etc. in a string of data.""" - - # ampersand must be replaced first - from_symbols = '&><"\'' - to_symbols = ('&'+s+';' for s in "amp gt lt quot apos".split()) - for from_,to_ in zip(from_symbols, to_symbols): - data = data.replace(from_, to_) - return data - -class _Constants(object): - pass - -alphas = string.ascii_uppercase + string.ascii_lowercase -nums = "0123456789" -hexnums = nums + "ABCDEFabcdef" -alphanums = alphas + nums -_bslash = chr(92) -printables = "".join(c for c in string.printable if c not in string.whitespace) - -class ParseBaseException(Exception): - """base exception class for all parsing runtime exceptions""" - # Performance tuning: we construct a *lot* of these, so keep this - # constructor as small and fast as possible - def __init__( self, pstr, loc=0, msg=None, elem=None ): - self.loc = loc - if msg is None: - self.msg = pstr - self.pstr = "" - else: - self.msg = msg - self.pstr = pstr - self.parserElement = elem - self.args = (pstr, loc, msg) - - @classmethod - def _from_exception(cls, pe): - """ - internal factory method to simplify creating one type of ParseException - from another - avoids having __init__ signature conflicts among subclasses - """ - return cls(pe.pstr, pe.loc, pe.msg, pe.parserElement) - - def __getattr__( self, aname ): - """supported attributes by name are: - - lineno - returns the line number of the exception text - - col - returns the column number of the exception text - - line - returns the line containing the exception text - """ - if( aname == "lineno" ): - return lineno( self.loc, self.pstr ) - elif( aname in ("col", "column") ): - return col( self.loc, self.pstr ) - elif( aname == "line" ): - return line( self.loc, self.pstr ) - else: - raise AttributeError(aname) - - def __str__( self ): - return "%s (at char %d), (line:%d, col:%d)" % \ - ( self.msg, self.loc, self.lineno, self.column ) - def __repr__( self ): - return _ustr(self) - def markInputline( self, markerString = ">!<" ): - """Extracts the exception line from the input string, and marks - the location of the exception with a special symbol. - """ - line_str = self.line - line_column = self.column - 1 - if markerString: - line_str = "".join((line_str[:line_column], - markerString, line_str[line_column:])) - return line_str.strip() - def __dir__(self): - return "lineno col line".split() + dir(type(self)) - -class ParseException(ParseBaseException): - """ - Exception thrown when parse expressions don't match class; - supported attributes by name are: - - lineno - returns the line number of the exception text - - col - returns the column number of the exception text - - line - returns the line containing the exception text - - Example:: - try: - Word(nums).setName("integer").parseString("ABC") - except ParseException as pe: - print(pe) - print("column: {}".format(pe.col)) - - prints:: - Expected integer (at char 0), (line:1, col:1) - column: 1 - """ - pass - -class ParseFatalException(ParseBaseException): - """user-throwable exception thrown when inconsistent parse content - is found; stops all parsing immediately""" - pass - -class ParseSyntaxException(ParseFatalException): - """just like L{ParseFatalException}, but thrown internally when an - L{ErrorStop<And._ErrorStop>} ('-' operator) indicates that parsing is to stop - immediately because an unbacktrackable syntax error has been found""" - pass - -#~ class ReparseException(ParseBaseException): - #~ """Experimental class - parse actions can raise this exception to cause - #~ pyparsing to reparse the input string: - #~ - with a modified input string, and/or - #~ - with a modified start location - #~ Set the values of the ReparseException in the constructor, and raise the - #~ exception in a parse action to cause pyparsing to use the new string/location. - #~ Setting the values as None causes no change to be made. - #~ """ - #~ def __init_( self, newstring, restartLoc ): - #~ self.newParseText = newstring - #~ self.reparseLoc = restartLoc - -class RecursiveGrammarException(Exception): - """exception thrown by L{ParserElement.validate} if the grammar could be improperly recursive""" - def __init__( self, parseElementList ): - self.parseElementTrace = parseElementList - - def __str__( self ): - return "RecursiveGrammarException: %s" % self.parseElementTrace - -class _ParseResultsWithOffset(object): - def __init__(self,p1,p2): - self.tup = (p1,p2) - def __getitem__(self,i): - return self.tup[i] - def __repr__(self): - return repr(self.tup[0]) - def setOffset(self,i): - self.tup = (self.tup[0],i) - -class ParseResults(object): - """ - Structured parse results, to provide multiple means of access to the parsed data: - - as a list (C{len(results)}) - - by list index (C{results[0], results[1]}, etc.) - - by attribute (C{results.<resultsName>} - see L{ParserElement.setResultsName}) - - Example:: - integer = Word(nums) - date_str = (integer.setResultsName("year") + '/' - + integer.setResultsName("month") + '/' - + integer.setResultsName("day")) - # equivalent form: - # date_str = integer("year") + '/' + integer("month") + '/' + integer("day") - - # parseString returns a ParseResults object - result = date_str.parseString("1999/12/31") - - def test(s, fn=repr): - print("%s -> %s" % (s, fn(eval(s)))) - test("list(result)") - test("result[0]") - test("result['month']") - test("result.day") - test("'month' in result") - test("'minutes' in result") - test("result.dump()", str) - prints:: - list(result) -> ['1999', '/', '12', '/', '31'] - result[0] -> '1999' - result['month'] -> '12' - result.day -> '31' - 'month' in result -> True - 'minutes' in result -> False - result.dump() -> ['1999', '/', '12', '/', '31'] - - day: 31 - - month: 12 - - year: 1999 - """ - def __new__(cls, toklist=None, name=None, asList=True, modal=True ): - if isinstance(toklist, cls): - return toklist - retobj = object.__new__(cls) - retobj.__doinit = True - return retobj - - # Performance tuning: we construct a *lot* of these, so keep this - # constructor as small and fast as possible - def __init__( self, toklist=None, name=None, asList=True, modal=True, isinstance=isinstance ): - if self.__doinit: - self.__doinit = False - self.__name = None - self.__parent = None - self.__accumNames = {} - self.__asList = asList - self.__modal = modal - if toklist is None: - toklist = [] - if isinstance(toklist, list): - self.__toklist = toklist[:] - elif isinstance(toklist, _generatorType): - self.__toklist = list(toklist) - else: - self.__toklist = [toklist] - self.__tokdict = dict() - - if name is not None and name: - if not modal: - self.__accumNames[name] = 0 - if isinstance(name,int): - name = _ustr(name) # will always return a str, but use _ustr for consistency - self.__name = name - if not (isinstance(toklist, (type(None), basestring, list)) and toklist in (None,'',[])): - if isinstance(toklist,basestring): - toklist = [ toklist ] - if asList: - if isinstance(toklist,ParseResults): - self[name] = _ParseResultsWithOffset(toklist.copy(),0) - else: - self[name] = _ParseResultsWithOffset(ParseResults(toklist[0]),0) - self[name].__name = name - else: - try: - self[name] = toklist[0] - except (KeyError,TypeError,IndexError): - self[name] = toklist - - def __getitem__( self, i ): - if isinstance( i, (int,slice) ): - return self.__toklist[i] - else: - if i not in self.__accumNames: - return self.__tokdict[i][-1][0] - else: - return ParseResults([ v[0] for v in self.__tokdict[i] ]) - - def __setitem__( self, k, v, isinstance=isinstance ): - if isinstance(v,_ParseResultsWithOffset): - self.__tokdict[k] = self.__tokdict.get(k,list()) + [v] - sub = v[0] - elif isinstance(k,(int,slice)): - self.__toklist[k] = v - sub = v - else: - self.__tokdict[k] = self.__tokdict.get(k,list()) + [_ParseResultsWithOffset(v,0)] - sub = v - if isinstance(sub,ParseResults): - sub.__parent = wkref(self) - - def __delitem__( self, i ): - if isinstance(i,(int,slice)): - mylen = len( self.__toklist ) - del self.__toklist[i] - - # convert int to slice - if isinstance(i, int): - if i < 0: - i += mylen - i = slice(i, i+1) - # get removed indices - removed = list(range(*i.indices(mylen))) - removed.reverse() - # fixup indices in token dictionary - for name,occurrences in self.__tokdict.items(): - for j in removed: - for k, (value, position) in enumerate(occurrences): - occurrences[k] = _ParseResultsWithOffset(value, position - (position > j)) - else: - del self.__tokdict[i] - - def __contains__( self, k ): - return k in self.__tokdict - - def __len__( self ): return len( self.__toklist ) - def __bool__(self): return ( not not self.__toklist ) - __nonzero__ = __bool__ - def __iter__( self ): return iter( self.__toklist ) - def __reversed__( self ): return iter( self.__toklist[::-1] ) - def _iterkeys( self ): - if hasattr(self.__tokdict, "iterkeys"): - return self.__tokdict.iterkeys() - else: - return iter(self.__tokdict) - - def _itervalues( self ): - return (self[k] for k in self._iterkeys()) - - def _iteritems( self ): - return ((k, self[k]) for k in self._iterkeys()) - - if PY_3: - keys = _iterkeys - """Returns an iterator of all named result keys (Python 3.x only).""" - - values = _itervalues - """Returns an iterator of all named result values (Python 3.x only).""" - - items = _iteritems - """Returns an iterator of all named result key-value tuples (Python 3.x only).""" - - else: - iterkeys = _iterkeys - """Returns an iterator of all named result keys (Python 2.x only).""" - - itervalues = _itervalues - """Returns an iterator of all named result values (Python 2.x only).""" - - iteritems = _iteritems - """Returns an iterator of all named result key-value tuples (Python 2.x only).""" - - def keys( self ): - """Returns all named result keys (as a list in Python 2.x, as an iterator in Python 3.x).""" - return list(self.iterkeys()) - - def values( self ): - """Returns all named result values (as a list in Python 2.x, as an iterator in Python 3.x).""" - return list(self.itervalues()) - - def items( self ): - """Returns all named result key-values (as a list of tuples in Python 2.x, as an iterator in Python 3.x).""" - return list(self.iteritems()) - - def haskeys( self ): - """Since keys() returns an iterator, this method is helpful in bypassing - code that looks for the existence of any defined results names.""" - return bool(self.__tokdict) - - def pop( self, *args, **kwargs): - """ - Removes and returns item at specified index (default=C{last}). - Supports both C{list} and C{dict} semantics for C{pop()}. If passed no - argument or an integer argument, it will use C{list} semantics - and pop tokens from the list of parsed tokens. If passed a - non-integer argument (most likely a string), it will use C{dict} - semantics and pop the corresponding value from any defined - results names. A second default return value argument is - supported, just as in C{dict.pop()}. - - Example:: - def remove_first(tokens): - tokens.pop(0) - print(OneOrMore(Word(nums)).parseString("0 123 321")) # -> ['0', '123', '321'] - print(OneOrMore(Word(nums)).addParseAction(remove_first).parseString("0 123 321")) # -> ['123', '321'] - - label = Word(alphas) - patt = label("LABEL") + OneOrMore(Word(nums)) - print(patt.parseString("AAB 123 321").dump()) - - # Use pop() in a parse action to remove named result (note that corresponding value is not - # removed from list form of results) - def remove_LABEL(tokens): - tokens.pop("LABEL") - return tokens - patt.addParseAction(remove_LABEL) - print(patt.parseString("AAB 123 321").dump()) - prints:: - ['AAB', '123', '321'] - - LABEL: AAB - - ['AAB', '123', '321'] - """ - if not args: - args = [-1] - for k,v in kwargs.items(): - if k == 'default': - args = (args[0], v) - else: - raise TypeError("pop() got an unexpected keyword argument '%s'" % k) - if (isinstance(args[0], int) or - len(args) == 1 or - args[0] in self): - index = args[0] - ret = self[index] - del self[index] - return ret - else: - defaultvalue = args[1] - return defaultvalue - - def get(self, key, defaultValue=None): - """ - Returns named result matching the given key, or if there is no - such name, then returns the given C{defaultValue} or C{None} if no - C{defaultValue} is specified. - - Similar to C{dict.get()}. - - Example:: - integer = Word(nums) - date_str = integer("year") + '/' + integer("month") + '/' + integer("day") - - result = date_str.parseString("1999/12/31") - print(result.get("year")) # -> '1999' - print(result.get("hour", "not specified")) # -> 'not specified' - print(result.get("hour")) # -> None - """ - if key in self: - return self[key] - else: - return defaultValue - - def insert( self, index, insStr ): - """ - Inserts new element at location index in the list of parsed tokens. - - Similar to C{list.insert()}. - - Example:: - print(OneOrMore(Word(nums)).parseString("0 123 321")) # -> ['0', '123', '321'] - - # use a parse action to insert the parse location in the front of the parsed results - def insert_locn(locn, tokens): - tokens.insert(0, locn) - print(OneOrMore(Word(nums)).addParseAction(insert_locn).parseString("0 123 321")) # -> [0, '0', '123', '321'] - """ - self.__toklist.insert(index, insStr) - # fixup indices in token dictionary - for name,occurrences in self.__tokdict.items(): - for k, (value, position) in enumerate(occurrences): - occurrences[k] = _ParseResultsWithOffset(value, position + (position > index)) - - def append( self, item ): - """ - Add single element to end of ParseResults list of elements. - - Example:: - print(OneOrMore(Word(nums)).parseString("0 123 321")) # -> ['0', '123', '321'] - - # use a parse action to compute the sum of the parsed integers, and add it to the end - def append_sum(tokens): - tokens.append(sum(map(int, tokens))) - print(OneOrMore(Word(nums)).addParseAction(append_sum).parseString("0 123 321")) # -> ['0', '123', '321', 444] - """ - self.__toklist.append(item) - - def extend( self, itemseq ): - """ - Add sequence of elements to end of ParseResults list of elements. - - Example:: - patt = OneOrMore(Word(alphas)) - - # use a parse action to append the reverse of the matched strings, to make a palindrome - def make_palindrome(tokens): - tokens.extend(reversed([t[::-1] for t in tokens])) - return ''.join(tokens) - print(patt.addParseAction(make_palindrome).parseString("lskdj sdlkjf lksd")) # -> 'lskdjsdlkjflksddsklfjkldsjdksl' - """ - if isinstance(itemseq, ParseResults): - self += itemseq - else: - self.__toklist.extend(itemseq) - - def clear( self ): - """ - Clear all elements and results names. - """ - del self.__toklist[:] - self.__tokdict.clear() - - def __getattr__( self, name ): - try: - return self[name] - except KeyError: - return "" - - if name in self.__tokdict: - if name not in self.__accumNames: - return self.__tokdict[name][-1][0] - else: - return ParseResults([ v[0] for v in self.__tokdict[name] ]) - else: - return "" - - def __add__( self, other ): - ret = self.copy() - ret += other - return ret - - def __iadd__( self, other ): - if other.__tokdict: - offset = len(self.__toklist) - addoffset = lambda a: offset if a<0 else a+offset - otheritems = other.__tokdict.items() - otherdictitems = [(k, _ParseResultsWithOffset(v[0],addoffset(v[1])) ) - for (k,vlist) in otheritems for v in vlist] - for k,v in otherdictitems: - self[k] = v - if isinstance(v[0],ParseResults): - v[0].__parent = wkref(self) - - self.__toklist += other.__toklist - self.__accumNames.update( other.__accumNames ) - return self - - def __radd__(self, other): - if isinstance(other,int) and other == 0: - # useful for merging many ParseResults using sum() builtin - return self.copy() - else: - # this may raise a TypeError - so be it - return other + self - - def __repr__( self ): - return "(%s, %s)" % ( repr( self.__toklist ), repr( self.__tokdict ) ) - - def __str__( self ): - return '[' + ', '.join(_ustr(i) if isinstance(i, ParseResults) else repr(i) for i in self.__toklist) + ']' - - def _asStringList( self, sep='' ): - out = [] - for item in self.__toklist: - if out and sep: - out.append(sep) - if isinstance( item, ParseResults ): - out += item._asStringList() - else: - out.append( _ustr(item) ) - return out - - def asList( self ): - """ - Returns the parse results as a nested list of matching tokens, all converted to strings. - - Example:: - patt = OneOrMore(Word(alphas)) - result = patt.parseString("sldkj lsdkj sldkj") - # even though the result prints in string-like form, it is actually a pyparsing ParseResults - print(type(result), result) # -> <class 'pyparsing.ParseResults'> ['sldkj', 'lsdkj', 'sldkj'] - - # Use asList() to create an actual list - result_list = result.asList() - print(type(result_list), result_list) # -> <class 'list'> ['sldkj', 'lsdkj', 'sldkj'] - """ - return [res.asList() if isinstance(res,ParseResults) else res for res in self.__toklist] - - def asDict( self ): - """ - Returns the named parse results as a nested dictionary. - - Example:: - integer = Word(nums) - date_str = integer("year") + '/' + integer("month") + '/' + integer("day") - - result = date_str.parseString('12/31/1999') - print(type(result), repr(result)) # -> <class 'pyparsing.ParseResults'> (['12', '/', '31', '/', '1999'], {'day': [('1999', 4)], 'year': [('12', 0)], 'month': [('31', 2)]}) - - result_dict = result.asDict() - print(type(result_dict), repr(result_dict)) # -> <class 'dict'> {'day': '1999', 'year': '12', 'month': '31'} - - # even though a ParseResults supports dict-like access, sometime you just need to have a dict - import json - print(json.dumps(result)) # -> Exception: TypeError: ... is not JSON serializable - print(json.dumps(result.asDict())) # -> {"month": "31", "day": "1999", "year": "12"} - """ - if PY_3: - item_fn = self.items - else: - item_fn = self.iteritems - - def toItem(obj): - if isinstance(obj, ParseResults): - if obj.haskeys(): - return obj.asDict() - else: - return [toItem(v) for v in obj] - else: - return obj - - return dict((k,toItem(v)) for k,v in item_fn()) - - def copy( self ): - """ - Returns a new copy of a C{ParseResults} object. - """ - ret = ParseResults( self.__toklist ) - ret.__tokdict = self.__tokdict.copy() - ret.__parent = self.__parent - ret.__accumNames.update( self.__accumNames ) - ret.__name = self.__name - return ret - - def asXML( self, doctag=None, namedItemsOnly=False, indent="", formatted=True ): - """ - (Deprecated) Returns the parse results as XML. Tags are created for tokens and lists that have defined results names. - """ - nl = "\n" - out = [] - namedItems = dict((v[1],k) for (k,vlist) in self.__tokdict.items() - for v in vlist) - nextLevelIndent = indent + " " - - # collapse out indents if formatting is not desired - if not formatted: - indent = "" - nextLevelIndent = "" - nl = "" - - selfTag = None - if doctag is not None: - selfTag = doctag - else: - if self.__name: - selfTag = self.__name - - if not selfTag: - if namedItemsOnly: - return "" - else: - selfTag = "ITEM" - - out += [ nl, indent, "<", selfTag, ">" ] - - for i,res in enumerate(self.__toklist): - if isinstance(res,ParseResults): - if i in namedItems: - out += [ res.asXML(namedItems[i], - namedItemsOnly and doctag is None, - nextLevelIndent, - formatted)] - else: - out += [ res.asXML(None, - namedItemsOnly and doctag is None, - nextLevelIndent, - formatted)] - else: - # individual token, see if there is a name for it - resTag = None - if i in namedItems: - resTag = namedItems[i] - if not resTag: - if namedItemsOnly: - continue - else: - resTag = "ITEM" - xmlBodyText = _xml_escape(_ustr(res)) - out += [ nl, nextLevelIndent, "<", resTag, ">", - xmlBodyText, - "</", resTag, ">" ] - - out += [ nl, indent, "</", selfTag, ">" ] - return "".join(out) - - def __lookup(self,sub): - for k,vlist in self.__tokdict.items(): - for v,loc in vlist: - if sub is v: - return k - return None - - def getName(self): - r""" - Returns the results name for this token expression. Useful when several - different expressions might match at a particular location. - - Example:: - integer = Word(nums) - ssn_expr = Regex(r"\d\d\d-\d\d-\d\d\d\d") - house_number_expr = Suppress('#') + Word(nums, alphanums) - user_data = (Group(house_number_expr)("house_number") - | Group(ssn_expr)("ssn") - | Group(integer)("age")) - user_info = OneOrMore(user_data) - - result = user_info.parseString("22 111-22-3333 #221B") - for item in result: - print(item.getName(), ':', item[0]) - prints:: - age : 22 - ssn : 111-22-3333 - house_number : 221B - """ - if self.__name: - return self.__name - elif self.__parent: - par = self.__parent() - if par: - return par.__lookup(self) - else: - return None - elif (len(self) == 1 and - len(self.__tokdict) == 1 and - next(iter(self.__tokdict.values()))[0][1] in (0,-1)): - return next(iter(self.__tokdict.keys())) - else: - return None - - def dump(self, indent='', depth=0, full=True): - """ - Diagnostic method for listing out the contents of a C{ParseResults}. - Accepts an optional C{indent} argument so that this string can be embedded - in a nested display of other data. - - Example:: - integer = Word(nums) - date_str = integer("year") + '/' + integer("month") + '/' + integer("day") - - result = date_str.parseString('12/31/1999') - print(result.dump()) - prints:: - ['12', '/', '31', '/', '1999'] - - day: 1999 - - month: 31 - - year: 12 - """ - out = [] - NL = '\n' - out.append( indent+_ustr(self.asList()) ) - if full: - if self.haskeys(): - items = sorted((str(k), v) for k,v in self.items()) - for k,v in items: - if out: - out.append(NL) - out.append( "%s%s- %s: " % (indent,(' '*depth), k) ) - if isinstance(v,ParseResults): - if v: - out.append( v.dump(indent,depth+1) ) - else: - out.append(_ustr(v)) - else: - out.append(repr(v)) - elif any(isinstance(vv,ParseResults) for vv in self): - v = self - for i,vv in enumerate(v): - if isinstance(vv,ParseResults): - out.append("\n%s%s[%d]:\n%s%s%s" % (indent,(' '*(depth)),i,indent,(' '*(depth+1)),vv.dump(indent,depth+1) )) - else: - out.append("\n%s%s[%d]:\n%s%s%s" % (indent,(' '*(depth)),i,indent,(' '*(depth+1)),_ustr(vv))) - - return "".join(out) - - def pprint(self, *args, **kwargs): - """ - Pretty-printer for parsed results as a list, using the C{pprint} module. - Accepts additional positional or keyword args as defined for the - C{pprint.pprint} method. (U{http://docs.python.org/3/library/pprint.html#pprint.pprint}) - - Example:: - ident = Word(alphas, alphanums) - num = Word(nums) - func = Forward() - term = ident | num | Group('(' + func + ')') - func <<= ident + Group(Optional(delimitedList(term))) - result = func.parseString("fna a,b,(fnb c,d,200),100") - result.pprint(width=40) - prints:: - ['fna', - ['a', - 'b', - ['(', 'fnb', ['c', 'd', '200'], ')'], - '100']] - """ - pprint.pprint(self.asList(), *args, **kwargs) - - # add support for pickle protocol - def __getstate__(self): - return ( self.__toklist, - ( self.__tokdict.copy(), - self.__parent is not None and self.__parent() or None, - self.__accumNames, - self.__name ) ) - - def __setstate__(self,state): - self.__toklist = state[0] - (self.__tokdict, - par, - inAccumNames, - self.__name) = state[1] - self.__accumNames = {} - self.__accumNames.update(inAccumNames) - if par is not None: - self.__parent = wkref(par) - else: - self.__parent = None - - def __getnewargs__(self): - return self.__toklist, self.__name, self.__asList, self.__modal - - def __dir__(self): - return (dir(type(self)) + list(self.keys())) - -MutableMapping.register(ParseResults) - -def col (loc,strg): - """Returns current column within a string, counting newlines as line separators. - The first column is number 1. - - Note: the default parsing behavior is to expand tabs in the input string - before starting the parsing process. See L{I{ParserElement.parseString}<ParserElement.parseString>} for more information - on parsing strings containing C{<TAB>}s, and suggested methods to maintain a - consistent view of the parsed string, the parse location, and line and column - positions within the parsed string. - """ - s = strg - return 1 if 0<loc<len(s) and s[loc-1] == '\n' else loc - s.rfind("\n", 0, loc) - -def lineno(loc,strg): - """Returns current line number within a string, counting newlines as line separators. - The first line is number 1. - - Note: the default parsing behavior is to expand tabs in the input string - before starting the parsing process. See L{I{ParserElement.parseString}<ParserElement.parseString>} for more information - on parsing strings containing C{<TAB>}s, and suggested methods to maintain a - consistent view of the parsed string, the parse location, and line and column - positions within the parsed string. - """ - return strg.count("\n",0,loc) + 1 - -def line( loc, strg ): - """Returns the line of text containing loc within a string, counting newlines as line separators. - """ - lastCR = strg.rfind("\n", 0, loc) - nextCR = strg.find("\n", loc) - if nextCR >= 0: - return strg[lastCR+1:nextCR] - else: - return strg[lastCR+1:] - -def _defaultStartDebugAction( instring, loc, expr ): - print (("Match " + _ustr(expr) + " at loc " + _ustr(loc) + "(%d,%d)" % ( lineno(loc,instring), col(loc,instring) ))) - -def _defaultSuccessDebugAction( instring, startloc, endloc, expr, toks ): - print ("Matched " + _ustr(expr) + " -> " + str(toks.asList())) - -def _defaultExceptionDebugAction( instring, loc, expr, exc ): - print ("Exception raised:" + _ustr(exc)) - -def nullDebugAction(*args): - """'Do-nothing' debug action, to suppress debugging output during parsing.""" - pass - -# Only works on Python 3.x - nonlocal is toxic to Python 2 installs -#~ 'decorator to trim function calls to match the arity of the target' -#~ def _trim_arity(func, maxargs=3): - #~ if func in singleArgBuiltins: - #~ return lambda s,l,t: func(t) - #~ limit = 0 - #~ foundArity = False - #~ def wrapper(*args): - #~ nonlocal limit,foundArity - #~ while 1: - #~ try: - #~ ret = func(*args[limit:]) - #~ foundArity = True - #~ return ret - #~ except TypeError: - #~ if limit == maxargs or foundArity: - #~ raise - #~ limit += 1 - #~ continue - #~ return wrapper - -# this version is Python 2.x-3.x cross-compatible -'decorator to trim function calls to match the arity of the target' -def _trim_arity(func, maxargs=2): - if func in singleArgBuiltins: - return lambda s,l,t: func(t) - limit = [0] - foundArity = [False] - - # traceback return data structure changed in Py3.5 - normalize back to plain tuples - if system_version[:2] >= (3,5): - def extract_stack(limit=0): - # special handling for Python 3.5.0 - extra deep call stack by 1 - offset = -3 if system_version == (3,5,0) else -2 - frame_summary = traceback.extract_stack(limit=-offset+limit-1)[offset] - return [frame_summary[:2]] - def extract_tb(tb, limit=0): - frames = traceback.extract_tb(tb, limit=limit) - frame_summary = frames[-1] - return [frame_summary[:2]] - else: - extract_stack = traceback.extract_stack - extract_tb = traceback.extract_tb - - # synthesize what would be returned by traceback.extract_stack at the call to - # user's parse action 'func', so that we don't incur call penalty at parse time - - LINE_DIFF = 6 - # IF ANY CODE CHANGES, EVEN JUST COMMENTS OR BLANK LINES, BETWEEN THE NEXT LINE AND - # THE CALL TO FUNC INSIDE WRAPPER, LINE_DIFF MUST BE MODIFIED!!!! - this_line = extract_stack(limit=2)[-1] - pa_call_line_synth = (this_line[0], this_line[1]+LINE_DIFF) - - def wrapper(*args): - while 1: - try: - ret = func(*args[limit[0]:]) - foundArity[0] = True - return ret - except TypeError: - # re-raise TypeErrors if they did not come from our arity testing - if foundArity[0]: - raise - else: - try: - tb = sys.exc_info()[-1] - if not extract_tb(tb, limit=2)[-1][:2] == pa_call_line_synth: - raise - finally: - del tb - - if limit[0] <= maxargs: - limit[0] += 1 - continue - raise - - # copy func name to wrapper for sensible debug output - func_name = "<parse action>" - try: - func_name = getattr(func, '__name__', - getattr(func, '__class__').__name__) - except Exception: - func_name = str(func) - wrapper.__name__ = func_name - - return wrapper - -class ParserElement(object): - """Abstract base level parser element class.""" - DEFAULT_WHITE_CHARS = " \n\t\r" - verbose_stacktrace = False - - @staticmethod - def setDefaultWhitespaceChars( chars ): - r""" - Overrides the default whitespace chars - - Example:: - # default whitespace chars are space, <TAB> and newline - OneOrMore(Word(alphas)).parseString("abc def\nghi jkl") # -> ['abc', 'def', 'ghi', 'jkl'] - - # change to just treat newline as significant - ParserElement.setDefaultWhitespaceChars(" \t") - OneOrMore(Word(alphas)).parseString("abc def\nghi jkl") # -> ['abc', 'def'] - """ - ParserElement.DEFAULT_WHITE_CHARS = chars - - @staticmethod - def inlineLiteralsUsing(cls): - """ - Set class to be used for inclusion of string literals into a parser. - - Example:: - # default literal class used is Literal - integer = Word(nums) - date_str = integer("year") + '/' + integer("month") + '/' + integer("day") - - date_str.parseString("1999/12/31") # -> ['1999', '/', '12', '/', '31'] - - - # change to Suppress - ParserElement.inlineLiteralsUsing(Suppress) - date_str = integer("year") + '/' + integer("month") + '/' + integer("day") - - date_str.parseString("1999/12/31") # -> ['1999', '12', '31'] - """ - ParserElement._literalStringClass = cls - - def __init__( self, savelist=False ): - self.parseAction = list() - self.failAction = None - #~ self.name = "<unknown>" # don't define self.name, let subclasses try/except upcall - self.strRepr = None - self.resultsName = None - self.saveAsList = savelist - self.skipWhitespace = True - self.whiteChars = ParserElement.DEFAULT_WHITE_CHARS - self.copyDefaultWhiteChars = True - self.mayReturnEmpty = False # used when checking for left-recursion - self.keepTabs = False - self.ignoreExprs = list() - self.debug = False - self.streamlined = False - self.mayIndexError = True # used to optimize exception handling for subclasses that don't advance parse index - self.errmsg = "" - self.modalResults = True # used to mark results names as modal (report only last) or cumulative (list all) - self.debugActions = ( None, None, None ) #custom debug actions - self.re = None - self.callPreparse = True # used to avoid redundant calls to preParse - self.callDuringTry = False - - def copy( self ): - """ - Make a copy of this C{ParserElement}. Useful for defining different parse actions - for the same parsing pattern, using copies of the original parse element. - - Example:: - integer = Word(nums).setParseAction(lambda toks: int(toks[0])) - integerK = integer.copy().addParseAction(lambda toks: toks[0]*1024) + Suppress("K") - integerM = integer.copy().addParseAction(lambda toks: toks[0]*1024*1024) + Suppress("M") - - print(OneOrMore(integerK | integerM | integer).parseString("5K 100 640K 256M")) - prints:: - [5120, 100, 655360, 268435456] - Equivalent form of C{expr.copy()} is just C{expr()}:: - integerM = integer().addParseAction(lambda toks: toks[0]*1024*1024) + Suppress("M") - """ - cpy = copy.copy( self ) - cpy.parseAction = self.parseAction[:] - cpy.ignoreExprs = self.ignoreExprs[:] - if self.copyDefaultWhiteChars: - cpy.whiteChars = ParserElement.DEFAULT_WHITE_CHARS - return cpy - - def setName( self, name ): - """ - Define name for this expression, makes debugging and exception messages clearer. - - Example:: - Word(nums).parseString("ABC") # -> Exception: Expected W:(0123...) (at char 0), (line:1, col:1) - Word(nums).setName("integer").parseString("ABC") # -> Exception: Expected integer (at char 0), (line:1, col:1) - """ - self.name = name - self.errmsg = "Expected " + self.name - if hasattr(self,"exception"): - self.exception.msg = self.errmsg - return self - - def setResultsName( self, name, listAllMatches=False ): - """ - Define name for referencing matching tokens as a nested attribute - of the returned parse results. - NOTE: this returns a *copy* of the original C{ParserElement} object; - this is so that the client can define a basic element, such as an - integer, and reference it in multiple places with different names. - - You can also set results names using the abbreviated syntax, - C{expr("name")} in place of C{expr.setResultsName("name")} - - see L{I{__call__}<__call__>}. - - Example:: - date_str = (integer.setResultsName("year") + '/' - + integer.setResultsName("month") + '/' - + integer.setResultsName("day")) - - # equivalent form: - date_str = integer("year") + '/' + integer("month") + '/' + integer("day") - """ - newself = self.copy() - if name.endswith("*"): - name = name[:-1] - listAllMatches=True - newself.resultsName = name - newself.modalResults = not listAllMatches - return newself - - def setBreak(self,breakFlag = True): - """Method to invoke the Python pdb debugger when this element is - about to be parsed. Set C{breakFlag} to True to enable, False to - disable. - """ - if breakFlag: - _parseMethod = self._parse - def breaker(instring, loc, doActions=True, callPreParse=True): - import pdb - pdb.set_trace() - return _parseMethod( instring, loc, doActions, callPreParse ) - breaker._originalParseMethod = _parseMethod - self._parse = breaker - else: - if hasattr(self._parse,"_originalParseMethod"): - self._parse = self._parse._originalParseMethod - return self - - def setParseAction( self, *fns, **kwargs ): - """ - Define one or more actions to perform when successfully matching parse element definition. - Parse action fn is a callable method with 0-3 arguments, called as C{fn(s,loc,toks)}, - C{fn(loc,toks)}, C{fn(toks)}, or just C{fn()}, where: - - s = the original string being parsed (see note below) - - loc = the location of the matching substring - - toks = a list of the matched tokens, packaged as a C{L{ParseResults}} object - If the functions in fns modify the tokens, they can return them as the return - value from fn, and the modified list of tokens will replace the original. - Otherwise, fn does not need to return any value. - - Optional keyword arguments: - - callDuringTry = (default=C{False}) indicate if parse action should be run during lookaheads and alternate testing - - Note: the default parsing behavior is to expand tabs in the input string - before starting the parsing process. See L{I{parseString}<parseString>} for more information - on parsing strings containing C{<TAB>}s, and suggested methods to maintain a - consistent view of the parsed string, the parse location, and line and column - positions within the parsed string. - - Example:: - integer = Word(nums) - date_str = integer + '/' + integer + '/' + integer - - date_str.parseString("1999/12/31") # -> ['1999', '/', '12', '/', '31'] - - # use parse action to convert to ints at parse time - integer = Word(nums).setParseAction(lambda toks: int(toks[0])) - date_str = integer + '/' + integer + '/' + integer - - # note that integer fields are now ints, not strings - date_str.parseString("1999/12/31") # -> [1999, '/', 12, '/', 31] - """ - self.parseAction = list(map(_trim_arity, list(fns))) - self.callDuringTry = kwargs.get("callDuringTry", False) - return self - - def addParseAction( self, *fns, **kwargs ): - """ - Add one or more parse actions to expression's list of parse actions. See L{I{setParseAction}<setParseAction>}. - - See examples in L{I{copy}<copy>}. - """ - self.parseAction += list(map(_trim_arity, list(fns))) - self.callDuringTry = self.callDuringTry or kwargs.get("callDuringTry", False) - return self - - def addCondition(self, *fns, **kwargs): - """Add a boolean predicate function to expression's list of parse actions. See - L{I{setParseAction}<setParseAction>} for function call signatures. Unlike C{setParseAction}, - functions passed to C{addCondition} need to return boolean success/fail of the condition. - - Optional keyword arguments: - - message = define a custom message to be used in the raised exception - - fatal = if True, will raise ParseFatalException to stop parsing immediately; otherwise will raise ParseException - - Example:: - integer = Word(nums).setParseAction(lambda toks: int(toks[0])) - year_int = integer.copy() - year_int.addCondition(lambda toks: toks[0] >= 2000, message="Only support years 2000 and later") - date_str = year_int + '/' + integer + '/' + integer - - result = date_str.parseString("1999/12/31") # -> Exception: Only support years 2000 and later (at char 0), (line:1, col:1) - """ - msg = kwargs.get("message", "failed user-defined condition") - exc_type = ParseFatalException if kwargs.get("fatal", False) else ParseException - for fn in fns: - def pa(s,l,t): - if not bool(_trim_arity(fn)(s,l,t)): - raise exc_type(s,l,msg) - self.parseAction.append(pa) - self.callDuringTry = self.callDuringTry or kwargs.get("callDuringTry", False) - return self - - def setFailAction( self, fn ): - """Define action to perform if parsing fails at this expression. - Fail acton fn is a callable function that takes the arguments - C{fn(s,loc,expr,err)} where: - - s = string being parsed - - loc = location where expression match was attempted and failed - - expr = the parse expression that failed - - err = the exception thrown - The function returns no value. It may throw C{L{ParseFatalException}} - if it is desired to stop parsing immediately.""" - self.failAction = fn - return self - - def _skipIgnorables( self, instring, loc ): - exprsFound = True - while exprsFound: - exprsFound = False - for e in self.ignoreExprs: - try: - while 1: - loc,dummy = e._parse( instring, loc ) - exprsFound = True - except ParseException: - pass - return loc - - def preParse( self, instring, loc ): - if self.ignoreExprs: - loc = self._skipIgnorables( instring, loc ) - - if self.skipWhitespace: - wt = self.whiteChars - instrlen = len(instring) - while loc < instrlen and instring[loc] in wt: - loc += 1 - - return loc - - def parseImpl( self, instring, loc, doActions=True ): - return loc, [] - - def postParse( self, instring, loc, tokenlist ): - return tokenlist - - #~ @profile - def _parseNoCache( self, instring, loc, doActions=True, callPreParse=True ): - debugging = ( self.debug ) #and doActions ) - - if debugging or self.failAction: - #~ print ("Match",self,"at loc",loc,"(%d,%d)" % ( lineno(loc,instring), col(loc,instring) )) - if (self.debugActions[0] ): - self.debugActions[0]( instring, loc, self ) - if callPreParse and self.callPreparse: - preloc = self.preParse( instring, loc ) - else: - preloc = loc - tokensStart = preloc - try: - try: - loc,tokens = self.parseImpl( instring, preloc, doActions ) - except IndexError: - raise ParseException( instring, len(instring), self.errmsg, self ) - except ParseBaseException as err: - #~ print ("Exception raised:", err) - if self.debugActions[2]: - self.debugActions[2]( instring, tokensStart, self, err ) - if self.failAction: - self.failAction( instring, tokensStart, self, err ) - raise - else: - if callPreParse and self.callPreparse: - preloc = self.preParse( instring, loc ) - else: - preloc = loc - tokensStart = preloc - if self.mayIndexError or preloc >= len(instring): - try: - loc,tokens = self.parseImpl( instring, preloc, doActions ) - except IndexError: - raise ParseException( instring, len(instring), self.errmsg, self ) - else: - loc,tokens = self.parseImpl( instring, preloc, doActions ) - - tokens = self.postParse( instring, loc, tokens ) - - retTokens = ParseResults( tokens, self.resultsName, asList=self.saveAsList, modal=self.modalResults ) - if self.parseAction and (doActions or self.callDuringTry): - if debugging: - try: - for fn in self.parseAction: - tokens = fn( instring, tokensStart, retTokens ) - if tokens is not None: - retTokens = ParseResults( tokens, - self.resultsName, - asList=self.saveAsList and isinstance(tokens,(ParseResults,list)), - modal=self.modalResults ) - except ParseBaseException as err: - #~ print "Exception raised in user parse action:", err - if (self.debugActions[2] ): - self.debugActions[2]( instring, tokensStart, self, err ) - raise - else: - for fn in self.parseAction: - tokens = fn( instring, tokensStart, retTokens ) - if tokens is not None: - retTokens = ParseResults( tokens, - self.resultsName, - asList=self.saveAsList and isinstance(tokens,(ParseResults,list)), - modal=self.modalResults ) - if debugging: - #~ print ("Matched",self,"->",retTokens.asList()) - if (self.debugActions[1] ): - self.debugActions[1]( instring, tokensStart, loc, self, retTokens ) - - return loc, retTokens - - def tryParse( self, instring, loc ): - try: - return self._parse( instring, loc, doActions=False )[0] - except ParseFatalException: - raise ParseException( instring, loc, self.errmsg, self) - - def canParseNext(self, instring, loc): - try: - self.tryParse(instring, loc) - except (ParseException, IndexError): - return False - else: - return True - - class _UnboundedCache(object): - def __init__(self): - cache = {} - self.not_in_cache = not_in_cache = object() - - def get(self, key): - return cache.get(key, not_in_cache) - - def set(self, key, value): - cache[key] = value - - def clear(self): - cache.clear() - - def cache_len(self): - return len(cache) - - self.get = types.MethodType(get, self) - self.set = types.MethodType(set, self) - self.clear = types.MethodType(clear, self) - self.__len__ = types.MethodType(cache_len, self) - - if _OrderedDict is not None: - class _FifoCache(object): - def __init__(self, size): - self.not_in_cache = not_in_cache = object() - - cache = _OrderedDict() - - def get(self, key): - return cache.get(key, not_in_cache) - - def set(self, key, value): - cache[key] = value - while len(cache) > size: - try: - cache.popitem(False) - except KeyError: - pass - - def clear(self): - cache.clear() - - def cache_len(self): - return len(cache) - - self.get = types.MethodType(get, self) - self.set = types.MethodType(set, self) - self.clear = types.MethodType(clear, self) - self.__len__ = types.MethodType(cache_len, self) - - else: - class _FifoCache(object): - def __init__(self, size): - self.not_in_cache = not_in_cache = object() - - cache = {} - key_fifo = collections.deque([], size) - - def get(self, key): - return cache.get(key, not_in_cache) - - def set(self, key, value): - cache[key] = value - while len(key_fifo) > size: - cache.pop(key_fifo.popleft(), None) - key_fifo.append(key) - - def clear(self): - cache.clear() - key_fifo.clear() - - def cache_len(self): - return len(cache) - - self.get = types.MethodType(get, self) - self.set = types.MethodType(set, self) - self.clear = types.MethodType(clear, self) - self.__len__ = types.MethodType(cache_len, self) - - # argument cache for optimizing repeated calls when backtracking through recursive expressions - packrat_cache = {} # this is set later by enabledPackrat(); this is here so that resetCache() doesn't fail - packrat_cache_lock = RLock() - packrat_cache_stats = [0, 0] - - # this method gets repeatedly called during backtracking with the same arguments - - # we can cache these arguments and save ourselves the trouble of re-parsing the contained expression - def _parseCache( self, instring, loc, doActions=True, callPreParse=True ): - HIT, MISS = 0, 1 - lookup = (self, instring, loc, callPreParse, doActions) - with ParserElement.packrat_cache_lock: - cache = ParserElement.packrat_cache - value = cache.get(lookup) - if value is cache.not_in_cache: - ParserElement.packrat_cache_stats[MISS] += 1 - try: - value = self._parseNoCache(instring, loc, doActions, callPreParse) - except ParseBaseException as pe: - # cache a copy of the exception, without the traceback - cache.set(lookup, pe.__class__(*pe.args)) - raise - else: - cache.set(lookup, (value[0], value[1].copy())) - return value - else: - ParserElement.packrat_cache_stats[HIT] += 1 - if isinstance(value, Exception): - raise value - return (value[0], value[1].copy()) - - _parse = _parseNoCache - - @staticmethod - def resetCache(): - ParserElement.packrat_cache.clear() - ParserElement.packrat_cache_stats[:] = [0] * len(ParserElement.packrat_cache_stats) - - _packratEnabled = False - @staticmethod - def enablePackrat(cache_size_limit=128): - """Enables "packrat" parsing, which adds memoizing to the parsing logic. - Repeated parse attempts at the same string location (which happens - often in many complex grammars) can immediately return a cached value, - instead of re-executing parsing/validating code. Memoizing is done of - both valid results and parsing exceptions. - - Parameters: - - cache_size_limit - (default=C{128}) - if an integer value is provided - will limit the size of the packrat cache; if None is passed, then - the cache size will be unbounded; if 0 is passed, the cache will - be effectively disabled. - - This speedup may break existing programs that use parse actions that - have side-effects. For this reason, packrat parsing is disabled when - you first import pyparsing. To activate the packrat feature, your - program must call the class method C{ParserElement.enablePackrat()}. If - your program uses C{psyco} to "compile as you go", you must call - C{enablePackrat} before calling C{psyco.full()}. If you do not do this, - Python will crash. For best results, call C{enablePackrat()} immediately - after importing pyparsing. - - Example:: - import pyparsing - pyparsing.ParserElement.enablePackrat() - """ - if not ParserElement._packratEnabled: - ParserElement._packratEnabled = True - if cache_size_limit is None: - ParserElement.packrat_cache = ParserElement._UnboundedCache() - else: - ParserElement.packrat_cache = ParserElement._FifoCache(cache_size_limit) - ParserElement._parse = ParserElement._parseCache - - def parseString( self, instring, parseAll=False ): - """ - Execute the parse expression with the given string. - This is the main interface to the client code, once the complete - expression has been built. - - If you want the grammar to require that the entire input string be - successfully parsed, then set C{parseAll} to True (equivalent to ending - the grammar with C{L{StringEnd()}}). - - Note: C{parseString} implicitly calls C{expandtabs()} on the input string, - in order to report proper column numbers in parse actions. - If the input string contains tabs and - the grammar uses parse actions that use the C{loc} argument to index into the - string being parsed, you can ensure you have a consistent view of the input - string by: - - calling C{parseWithTabs} on your grammar before calling C{parseString} - (see L{I{parseWithTabs}<parseWithTabs>}) - - define your parse action using the full C{(s,loc,toks)} signature, and - reference the input string using the parse action's C{s} argument - - explictly expand the tabs in your input string before calling - C{parseString} - - Example:: - Word('a').parseString('aaaaabaaa') # -> ['aaaaa'] - Word('a').parseString('aaaaabaaa', parseAll=True) # -> Exception: Expected end of text - """ - ParserElement.resetCache() - if not self.streamlined: - self.streamline() - #~ self.saveAsList = True - for e in self.ignoreExprs: - e.streamline() - if not self.keepTabs: - instring = instring.expandtabs() - try: - loc, tokens = self._parse( instring, 0 ) - if parseAll: - loc = self.preParse( instring, loc ) - se = Empty() + StringEnd() - se._parse( instring, loc ) - except ParseBaseException as exc: - if ParserElement.verbose_stacktrace: - raise - else: - # catch and re-raise exception from here, clears out pyparsing internal stack trace - raise exc - else: - return tokens - - def scanString( self, instring, maxMatches=_MAX_INT, overlap=False ): - """ - Scan the input string for expression matches. Each match will return the - matching tokens, start location, and end location. May be called with optional - C{maxMatches} argument, to clip scanning after 'n' matches are found. If - C{overlap} is specified, then overlapping matches will be reported. - - Note that the start and end locations are reported relative to the string - being parsed. See L{I{parseString}<parseString>} for more information on parsing - strings with embedded tabs. - - Example:: - source = "sldjf123lsdjjkf345sldkjf879lkjsfd987" - print(source) - for tokens,start,end in Word(alphas).scanString(source): - print(' '*start + '^'*(end-start)) - print(' '*start + tokens[0]) - - prints:: - - sldjf123lsdjjkf345sldkjf879lkjsfd987 - ^^^^^ - sldjf - ^^^^^^^ - lsdjjkf - ^^^^^^ - sldkjf - ^^^^^^ - lkjsfd - """ - if not self.streamlined: - self.streamline() - for e in self.ignoreExprs: - e.streamline() - - if not self.keepTabs: - instring = _ustr(instring).expandtabs() - instrlen = len(instring) - loc = 0 - preparseFn = self.preParse - parseFn = self._parse - ParserElement.resetCache() - matches = 0 - try: - while loc <= instrlen and matches < maxMatches: - try: - preloc = preparseFn( instring, loc ) - nextLoc,tokens = parseFn( instring, preloc, callPreParse=False ) - except ParseException: - loc = preloc+1 - else: - if nextLoc > loc: - matches += 1 - yield tokens, preloc, nextLoc - if overlap: - nextloc = preparseFn( instring, loc ) - if nextloc > loc: - loc = nextLoc - else: - loc += 1 - else: - loc = nextLoc - else: - loc = preloc+1 - except ParseBaseException as exc: - if ParserElement.verbose_stacktrace: - raise - else: - # catch and re-raise exception from here, clears out pyparsing internal stack trace - raise exc - - def transformString( self, instring ): - """ - Extension to C{L{scanString}}, to modify matching text with modified tokens that may - be returned from a parse action. To use C{transformString}, define a grammar and - attach a parse action to it that modifies the returned token list. - Invoking C{transformString()} on a target string will then scan for matches, - and replace the matched text patterns according to the logic in the parse - action. C{transformString()} returns the resulting transformed string. - - Example:: - wd = Word(alphas) - wd.setParseAction(lambda toks: toks[0].title()) - - print(wd.transformString("now is the winter of our discontent made glorious summer by this sun of york.")) - Prints:: - Now Is The Winter Of Our Discontent Made Glorious Summer By This Sun Of York. - """ - out = [] - lastE = 0 - # force preservation of <TAB>s, to minimize unwanted transformation of string, and to - # keep string locs straight between transformString and scanString - self.keepTabs = True - try: - for t,s,e in self.scanString( instring ): - out.append( instring[lastE:s] ) - if t: - if isinstance(t,ParseResults): - out += t.asList() - elif isinstance(t,list): - out += t - else: - out.append(t) - lastE = e - out.append(instring[lastE:]) - out = [o for o in out if o] - return "".join(map(_ustr,_flatten(out))) - except ParseBaseException as exc: - if ParserElement.verbose_stacktrace: - raise - else: - # catch and re-raise exception from here, clears out pyparsing internal stack trace - raise exc - - def searchString( self, instring, maxMatches=_MAX_INT ): - """ - Another extension to C{L{scanString}}, simplifying the access to the tokens found - to match the given parse expression. May be called with optional - C{maxMatches} argument, to clip searching after 'n' matches are found. - - Example:: - # a capitalized word starts with an uppercase letter, followed by zero or more lowercase letters - cap_word = Word(alphas.upper(), alphas.lower()) - - print(cap_word.searchString("More than Iron, more than Lead, more than Gold I need Electricity")) - - # the sum() builtin can be used to merge results into a single ParseResults object - print(sum(cap_word.searchString("More than Iron, more than Lead, more than Gold I need Electricity"))) - prints:: - [['More'], ['Iron'], ['Lead'], ['Gold'], ['I'], ['Electricity']] - ['More', 'Iron', 'Lead', 'Gold', 'I', 'Electricity'] - """ - try: - return ParseResults([ t for t,s,e in self.scanString( instring, maxMatches ) ]) - except ParseBaseException as exc: - if ParserElement.verbose_stacktrace: - raise - else: - # catch and re-raise exception from here, clears out pyparsing internal stack trace - raise exc - - def split(self, instring, maxsplit=_MAX_INT, includeSeparators=False): - """ - Generator method to split a string using the given expression as a separator. - May be called with optional C{maxsplit} argument, to limit the number of splits; - and the optional C{includeSeparators} argument (default=C{False}), if the separating - matching text should be included in the split results. - - Example:: - punc = oneOf(list(".,;:/-!?")) - print(list(punc.split("This, this?, this sentence, is badly punctuated!"))) - prints:: - ['This', ' this', '', ' this sentence', ' is badly punctuated', ''] - """ - splits = 0 - last = 0 - for t,s,e in self.scanString(instring, maxMatches=maxsplit): - yield instring[last:s] - if includeSeparators: - yield t[0] - last = e - yield instring[last:] - - def __add__(self, other ): - """ - Implementation of + operator - returns C{L{And}}. Adding strings to a ParserElement - converts them to L{Literal}s by default. - - Example:: - greet = Word(alphas) + "," + Word(alphas) + "!" - hello = "Hello, World!" - print (hello, "->", greet.parseString(hello)) - Prints:: - Hello, World! -> ['Hello', ',', 'World', '!'] - """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return And( [ self, other ] ) - - def __radd__(self, other ): - """ - Implementation of + operator when left operand is not a C{L{ParserElement}} - """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return other + self - - def __sub__(self, other): - """ - Implementation of - operator, returns C{L{And}} with error stop - """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return self + And._ErrorStop() + other - - def __rsub__(self, other ): - """ - Implementation of - operator when left operand is not a C{L{ParserElement}} - """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return other - self - - def __mul__(self,other): - """ - Implementation of * operator, allows use of C{expr * 3} in place of - C{expr + expr + expr}. Expressions may also me multiplied by a 2-integer - tuple, similar to C{{min,max}} multipliers in regular expressions. Tuples - may also include C{None} as in: - - C{expr*(n,None)} or C{expr*(n,)} is equivalent - to C{expr*n + L{ZeroOrMore}(expr)} - (read as "at least n instances of C{expr}") - - C{expr*(None,n)} is equivalent to C{expr*(0,n)} - (read as "0 to n instances of C{expr}") - - C{expr*(None,None)} is equivalent to C{L{ZeroOrMore}(expr)} - - C{expr*(1,None)} is equivalent to C{L{OneOrMore}(expr)} - - Note that C{expr*(None,n)} does not raise an exception if - more than n exprs exist in the input stream; that is, - C{expr*(None,n)} does not enforce a maximum number of expr - occurrences. If this behavior is desired, then write - C{expr*(None,n) + ~expr} - """ - if isinstance(other,int): - minElements, optElements = other,0 - elif isinstance(other,tuple): - other = (other + (None, None))[:2] - if other[0] is None: - other = (0, other[1]) - if isinstance(other[0],int) and other[1] is None: - if other[0] == 0: - return ZeroOrMore(self) - if other[0] == 1: - return OneOrMore(self) - else: - return self*other[0] + ZeroOrMore(self) - elif isinstance(other[0],int) and isinstance(other[1],int): - minElements, optElements = other - optElements -= minElements - else: - raise TypeError("cannot multiply 'ParserElement' and ('%s','%s') objects", type(other[0]),type(other[1])) - else: - raise TypeError("cannot multiply 'ParserElement' and '%s' objects", type(other)) - - if minElements < 0: - raise ValueError("cannot multiply ParserElement by negative value") - if optElements < 0: - raise ValueError("second tuple value must be greater or equal to first tuple value") - if minElements == optElements == 0: - raise ValueError("cannot multiply ParserElement by 0 or (0,0)") - - if (optElements): - def makeOptionalList(n): - if n>1: - return Optional(self + makeOptionalList(n-1)) - else: - return Optional(self) - if minElements: - if minElements == 1: - ret = self + makeOptionalList(optElements) - else: - ret = And([self]*minElements) + makeOptionalList(optElements) - else: - ret = makeOptionalList(optElements) - else: - if minElements == 1: - ret = self - else: - ret = And([self]*minElements) - return ret - - def __rmul__(self, other): - return self.__mul__(other) - - def __or__(self, other ): - """ - Implementation of | operator - returns C{L{MatchFirst}} - """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return MatchFirst( [ self, other ] ) - - def __ror__(self, other ): - """ - Implementation of | operator when left operand is not a C{L{ParserElement}} - """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return other | self - - def __xor__(self, other ): - """ - Implementation of ^ operator - returns C{L{Or}} - """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return Or( [ self, other ] ) - - def __rxor__(self, other ): - """ - Implementation of ^ operator when left operand is not a C{L{ParserElement}} - """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return other ^ self - - def __and__(self, other ): - """ - Implementation of & operator - returns C{L{Each}} - """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return Each( [ self, other ] ) - - def __rand__(self, other ): - """ - Implementation of & operator when left operand is not a C{L{ParserElement}} - """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return other & self - - def __invert__( self ): - """ - Implementation of ~ operator - returns C{L{NotAny}} - """ - return NotAny( self ) - - def __call__(self, name=None): - """ - Shortcut for C{L{setResultsName}}, with C{listAllMatches=False}. - - If C{name} is given with a trailing C{'*'} character, then C{listAllMatches} will be - passed as C{True}. - - If C{name} is omitted, same as calling C{L{copy}}. - - Example:: - # these are equivalent - userdata = Word(alphas).setResultsName("name") + Word(nums+"-").setResultsName("socsecno") - userdata = Word(alphas)("name") + Word(nums+"-")("socsecno") - """ - if name is not None: - return self.setResultsName(name) - else: - return self.copy() - - def suppress( self ): - """ - Suppresses the output of this C{ParserElement}; useful to keep punctuation from - cluttering up returned output. - """ - return Suppress( self ) - - def leaveWhitespace( self ): - """ - Disables the skipping of whitespace before matching the characters in the - C{ParserElement}'s defined pattern. This is normally only used internally by - the pyparsing module, but may be needed in some whitespace-sensitive grammars. - """ - self.skipWhitespace = False - return self - - def setWhitespaceChars( self, chars ): - """ - Overrides the default whitespace chars - """ - self.skipWhitespace = True - self.whiteChars = chars - self.copyDefaultWhiteChars = False - return self - - def parseWithTabs( self ): - """ - Overrides default behavior to expand C{<TAB>}s to spaces before parsing the input string. - Must be called before C{parseString} when the input grammar contains elements that - match C{<TAB>} characters. - """ - self.keepTabs = True - return self - - def ignore( self, other ): - """ - Define expression to be ignored (e.g., comments) while doing pattern - matching; may be called repeatedly, to define multiple comment or other - ignorable patterns. - - Example:: - patt = OneOrMore(Word(alphas)) - patt.parseString('ablaj /* comment */ lskjd') # -> ['ablaj'] - - patt.ignore(cStyleComment) - patt.parseString('ablaj /* comment */ lskjd') # -> ['ablaj', 'lskjd'] - """ - if isinstance(other, basestring): - other = Suppress(other) - - if isinstance( other, Suppress ): - if other not in self.ignoreExprs: - self.ignoreExprs.append(other) - else: - self.ignoreExprs.append( Suppress( other.copy() ) ) - return self - - def setDebugActions( self, startAction, successAction, exceptionAction ): - """ - Enable display of debugging messages while doing pattern matching. - """ - self.debugActions = (startAction or _defaultStartDebugAction, - successAction or _defaultSuccessDebugAction, - exceptionAction or _defaultExceptionDebugAction) - self.debug = True - return self - - def setDebug( self, flag=True ): - """ - Enable display of debugging messages while doing pattern matching. - Set C{flag} to True to enable, False to disable. - - Example:: - wd = Word(alphas).setName("alphaword") - integer = Word(nums).setName("numword") - term = wd | integer - - # turn on debugging for wd - wd.setDebug() - - OneOrMore(term).parseString("abc 123 xyz 890") - - prints:: - Match alphaword at loc 0(1,1) - Matched alphaword -> ['abc'] - Match alphaword at loc 3(1,4) - Exception raised:Expected alphaword (at char 4), (line:1, col:5) - Match alphaword at loc 7(1,8) - Matched alphaword -> ['xyz'] - Match alphaword at loc 11(1,12) - Exception raised:Expected alphaword (at char 12), (line:1, col:13) - Match alphaword at loc 15(1,16) - Exception raised:Expected alphaword (at char 15), (line:1, col:16) - - The output shown is that produced by the default debug actions - custom debug actions can be - specified using L{setDebugActions}. Prior to attempting - to match the C{wd} expression, the debugging message C{"Match <exprname> at loc <n>(<line>,<col>)"} - is shown. Then if the parse succeeds, a C{"Matched"} message is shown, or an C{"Exception raised"} - message is shown. Also note the use of L{setName} to assign a human-readable name to the expression, - which makes debugging and exception messages easier to understand - for instance, the default - name created for the C{Word} expression without calling C{setName} is C{"W:(ABCD...)"}. - """ - if flag: - self.setDebugActions( _defaultStartDebugAction, _defaultSuccessDebugAction, _defaultExceptionDebugAction ) - else: - self.debug = False - return self - - def __str__( self ): - return self.name - - def __repr__( self ): - return _ustr(self) - - def streamline( self ): - self.streamlined = True - self.strRepr = None - return self - - def checkRecursion( self, parseElementList ): - pass - - def validate( self, validateTrace=[] ): - """ - Check defined expressions for valid structure, check for infinite recursive definitions. - """ - self.checkRecursion( [] ) - - def parseFile( self, file_or_filename, parseAll=False ): - """ - Execute the parse expression on the given file or filename. - If a filename is specified (instead of a file object), - the entire file is opened, read, and closed before parsing. - """ - try: - file_contents = file_or_filename.read() - except AttributeError: - with open(file_or_filename, "r") as f: - file_contents = f.read() - try: - return self.parseString(file_contents, parseAll) - except ParseBaseException as exc: - if ParserElement.verbose_stacktrace: - raise - else: - # catch and re-raise exception from here, clears out pyparsing internal stack trace - raise exc - - def __eq__(self,other): - if isinstance(other, ParserElement): - return self is other or vars(self) == vars(other) - elif isinstance(other, basestring): - return self.matches(other) - else: - return super(ParserElement,self)==other - - def __ne__(self,other): - return not (self == other) - - def __hash__(self): - return hash(id(self)) - - def __req__(self,other): - return self == other - - def __rne__(self,other): - return not (self == other) - - def matches(self, testString, parseAll=True): - """ - Method for quick testing of a parser against a test string. Good for simple - inline microtests of sub expressions while building up larger parser. - - Parameters: - - testString - to test against this expression for a match - - parseAll - (default=C{True}) - flag to pass to C{L{parseString}} when running tests - - Example:: - expr = Word(nums) - assert expr.matches("100") - """ - try: - self.parseString(_ustr(testString), parseAll=parseAll) - return True - except ParseBaseException: - return False - - def runTests(self, tests, parseAll=True, comment='#', fullDump=True, printResults=True, failureTests=False): - """ - Execute the parse expression on a series of test strings, showing each - test, the parsed results or where the parse failed. Quick and easy way to - run a parse expression against a list of sample strings. - - Parameters: - - tests - a list of separate test strings, or a multiline string of test strings - - parseAll - (default=C{True}) - flag to pass to C{L{parseString}} when running tests - - comment - (default=C{'#'}) - expression for indicating embedded comments in the test - string; pass None to disable comment filtering - - fullDump - (default=C{True}) - dump results as list followed by results names in nested outline; - if False, only dump nested list - - printResults - (default=C{True}) prints test output to stdout - - failureTests - (default=C{False}) indicates if these tests are expected to fail parsing - - Returns: a (success, results) tuple, where success indicates that all tests succeeded - (or failed if C{failureTests} is True), and the results contain a list of lines of each - test's output - - Example:: - number_expr = pyparsing_common.number.copy() - - result = number_expr.runTests(''' - # unsigned integer - 100 - # negative integer - -100 - # float with scientific notation - 6.02e23 - # integer with scientific notation - 1e-12 - ''') - print("Success" if result[0] else "Failed!") - - result = number_expr.runTests(''' - # stray character - 100Z - # missing leading digit before '.' - -.100 - # too many '.' - 3.14.159 - ''', failureTests=True) - print("Success" if result[0] else "Failed!") - prints:: - # unsigned integer - 100 - [100] - - # negative integer - -100 - [-100] - - # float with scientific notation - 6.02e23 - [6.02e+23] - - # integer with scientific notation - 1e-12 - [1e-12] - - Success - - # stray character - 100Z - ^ - FAIL: Expected end of text (at char 3), (line:1, col:4) - - # missing leading digit before '.' - -.100 - ^ - FAIL: Expected {real number with scientific notation | real number | signed integer} (at char 0), (line:1, col:1) - - # too many '.' - 3.14.159 - ^ - FAIL: Expected end of text (at char 4), (line:1, col:5) - - Success - - Each test string must be on a single line. If you want to test a string that spans multiple - lines, create a test like this:: - - expr.runTest(r"this is a test\\n of strings that spans \\n 3 lines") - - (Note that this is a raw string literal, you must include the leading 'r'.) - """ - if isinstance(tests, basestring): - tests = list(map(str.strip, tests.rstrip().splitlines())) - if isinstance(comment, basestring): - comment = Literal(comment) - allResults = [] - comments = [] - success = True - for t in tests: - if comment is not None and comment.matches(t, False) or comments and not t: - comments.append(t) - continue - if not t: - continue - out = ['\n'.join(comments), t] - comments = [] - try: - t = t.replace(r'\n','\n') - result = self.parseString(t, parseAll=parseAll) - out.append(result.dump(full=fullDump)) - success = success and not failureTests - except ParseBaseException as pe: - fatal = "(FATAL)" if isinstance(pe, ParseFatalException) else "" - if '\n' in t: - out.append(line(pe.loc, t)) - out.append(' '*(col(pe.loc,t)-1) + '^' + fatal) - else: - out.append(' '*pe.loc + '^' + fatal) - out.append("FAIL: " + str(pe)) - success = success and failureTests - result = pe - except Exception as exc: - out.append("FAIL-EXCEPTION: " + str(exc)) - success = success and failureTests - result = exc - - if printResults: - if fullDump: - out.append('') - print('\n'.join(out)) - - allResults.append((t, result)) - - return success, allResults - - -class Token(ParserElement): - """ - Abstract C{ParserElement} subclass, for defining atomic matching patterns. - """ - def __init__( self ): - super(Token,self).__init__( savelist=False ) - - -class Empty(Token): - """ - An empty token, will always match. - """ - def __init__( self ): - super(Empty,self).__init__() - self.name = "Empty" - self.mayReturnEmpty = True - self.mayIndexError = False - - -class NoMatch(Token): - """ - A token that will never match. - """ - def __init__( self ): - super(NoMatch,self).__init__() - self.name = "NoMatch" - self.mayReturnEmpty = True - self.mayIndexError = False - self.errmsg = "Unmatchable token" - - def parseImpl( self, instring, loc, doActions=True ): - raise ParseException(instring, loc, self.errmsg, self) - - -class Literal(Token): - """ - Token to exactly match a specified string. - - Example:: - Literal('blah').parseString('blah') # -> ['blah'] - Literal('blah').parseString('blahfooblah') # -> ['blah'] - Literal('blah').parseString('bla') # -> Exception: Expected "blah" - - For case-insensitive matching, use L{CaselessLiteral}. - - For keyword matching (force word break before and after the matched string), - use L{Keyword} or L{CaselessKeyword}. - """ - def __init__( self, matchString ): - super(Literal,self).__init__() - self.match = matchString - self.matchLen = len(matchString) - try: - self.firstMatchChar = matchString[0] - except IndexError: - warnings.warn("null string passed to Literal; use Empty() instead", - SyntaxWarning, stacklevel=2) - self.__class__ = Empty - self.name = '"%s"' % _ustr(self.match) - self.errmsg = "Expected " + self.name - self.mayReturnEmpty = False - self.mayIndexError = False - - # Performance tuning: this routine gets called a *lot* - # if this is a single character match string and the first character matches, - # short-circuit as quickly as possible, and avoid calling startswith - #~ @profile - def parseImpl( self, instring, loc, doActions=True ): - if (instring[loc] == self.firstMatchChar and - (self.matchLen==1 or instring.startswith(self.match,loc)) ): - return loc+self.matchLen, self.match - raise ParseException(instring, loc, self.errmsg, self) -_L = Literal -ParserElement._literalStringClass = Literal - -class Keyword(Token): - """ - Token to exactly match a specified string as a keyword, that is, it must be - immediately followed by a non-keyword character. Compare with C{L{Literal}}: - - C{Literal("if")} will match the leading C{'if'} in C{'ifAndOnlyIf'}. - - C{Keyword("if")} will not; it will only match the leading C{'if'} in C{'if x=1'}, or C{'if(y==2)'} - Accepts two optional constructor arguments in addition to the keyword string: - - C{identChars} is a string of characters that would be valid identifier characters, - defaulting to all alphanumerics + "_" and "$" - - C{caseless} allows case-insensitive matching, default is C{False}. - - Example:: - Keyword("start").parseString("start") # -> ['start'] - Keyword("start").parseString("starting") # -> Exception - - For case-insensitive matching, use L{CaselessKeyword}. - """ - DEFAULT_KEYWORD_CHARS = alphanums+"_$" - - def __init__( self, matchString, identChars=None, caseless=False ): - super(Keyword,self).__init__() - if identChars is None: - identChars = Keyword.DEFAULT_KEYWORD_CHARS - self.match = matchString - self.matchLen = len(matchString) - try: - self.firstMatchChar = matchString[0] - except IndexError: - warnings.warn("null string passed to Keyword; use Empty() instead", - SyntaxWarning, stacklevel=2) - self.name = '"%s"' % self.match - self.errmsg = "Expected " + self.name - self.mayReturnEmpty = False - self.mayIndexError = False - self.caseless = caseless - if caseless: - self.caselessmatch = matchString.upper() - identChars = identChars.upper() - self.identChars = set(identChars) - - def parseImpl( self, instring, loc, doActions=True ): - if self.caseless: - if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and - (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) and - (loc == 0 or instring[loc-1].upper() not in self.identChars) ): - return loc+self.matchLen, self.match - else: - if (instring[loc] == self.firstMatchChar and - (self.matchLen==1 or instring.startswith(self.match,loc)) and - (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen] not in self.identChars) and - (loc == 0 or instring[loc-1] not in self.identChars) ): - return loc+self.matchLen, self.match - raise ParseException(instring, loc, self.errmsg, self) - - def copy(self): - c = super(Keyword,self).copy() - c.identChars = Keyword.DEFAULT_KEYWORD_CHARS - return c - - @staticmethod - def setDefaultKeywordChars( chars ): - """Overrides the default Keyword chars - """ - Keyword.DEFAULT_KEYWORD_CHARS = chars - -class CaselessLiteral(Literal): - """ - Token to match a specified string, ignoring case of letters. - Note: the matched results will always be in the case of the given - match string, NOT the case of the input text. - - Example:: - OneOrMore(CaselessLiteral("CMD")).parseString("cmd CMD Cmd10") # -> ['CMD', 'CMD', 'CMD'] - - (Contrast with example for L{CaselessKeyword}.) - """ - def __init__( self, matchString ): - super(CaselessLiteral,self).__init__( matchString.upper() ) - # Preserve the defining literal. - self.returnString = matchString - self.name = "'%s'" % self.returnString - self.errmsg = "Expected " + self.name - - def parseImpl( self, instring, loc, doActions=True ): - if instring[ loc:loc+self.matchLen ].upper() == self.match: - return loc+self.matchLen, self.returnString - raise ParseException(instring, loc, self.errmsg, self) - -class CaselessKeyword(Keyword): - """ - Caseless version of L{Keyword}. - - Example:: - OneOrMore(CaselessKeyword("CMD")).parseString("cmd CMD Cmd10") # -> ['CMD', 'CMD'] - - (Contrast with example for L{CaselessLiteral}.) - """ - def __init__( self, matchString, identChars=None ): - super(CaselessKeyword,self).__init__( matchString, identChars, caseless=True ) - - def parseImpl( self, instring, loc, doActions=True ): - if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and - (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) ): - return loc+self.matchLen, self.match - raise ParseException(instring, loc, self.errmsg, self) - -class CloseMatch(Token): - """ - A variation on L{Literal} which matches "close" matches, that is, - strings with at most 'n' mismatching characters. C{CloseMatch} takes parameters: - - C{match_string} - string to be matched - - C{maxMismatches} - (C{default=1}) maximum number of mismatches allowed to count as a match - - The results from a successful parse will contain the matched text from the input string and the following named results: - - C{mismatches} - a list of the positions within the match_string where mismatches were found - - C{original} - the original match_string used to compare against the input string - - If C{mismatches} is an empty list, then the match was an exact match. - - Example:: - patt = CloseMatch("ATCATCGAATGGA") - patt.parseString("ATCATCGAAXGGA") # -> (['ATCATCGAAXGGA'], {'mismatches': [[9]], 'original': ['ATCATCGAATGGA']}) - patt.parseString("ATCAXCGAAXGGA") # -> Exception: Expected 'ATCATCGAATGGA' (with up to 1 mismatches) (at char 0), (line:1, col:1) - - # exact match - patt.parseString("ATCATCGAATGGA") # -> (['ATCATCGAATGGA'], {'mismatches': [[]], 'original': ['ATCATCGAATGGA']}) - - # close match allowing up to 2 mismatches - patt = CloseMatch("ATCATCGAATGGA", maxMismatches=2) - patt.parseString("ATCAXCGAAXGGA") # -> (['ATCAXCGAAXGGA'], {'mismatches': [[4, 9]], 'original': ['ATCATCGAATGGA']}) - """ - def __init__(self, match_string, maxMismatches=1): - super(CloseMatch,self).__init__() - self.name = match_string - self.match_string = match_string - self.maxMismatches = maxMismatches - self.errmsg = "Expected %r (with up to %d mismatches)" % (self.match_string, self.maxMismatches) - self.mayIndexError = False - self.mayReturnEmpty = False - - def parseImpl( self, instring, loc, doActions=True ): - start = loc - instrlen = len(instring) - maxloc = start + len(self.match_string) - - if maxloc <= instrlen: - match_string = self.match_string - match_stringloc = 0 - mismatches = [] - maxMismatches = self.maxMismatches - - for match_stringloc,s_m in enumerate(zip(instring[loc:maxloc], self.match_string)): - src,mat = s_m - if src != mat: - mismatches.append(match_stringloc) - if len(mismatches) > maxMismatches: - break - else: - loc = match_stringloc + 1 - results = ParseResults([instring[start:loc]]) - results['original'] = self.match_string - results['mismatches'] = mismatches - return loc, results - - raise ParseException(instring, loc, self.errmsg, self) - - -class Word(Token): - """ - Token for matching words composed of allowed character sets. - Defined with string containing all allowed initial characters, - an optional string containing allowed body characters (if omitted, - defaults to the initial character set), and an optional minimum, - maximum, and/or exact length. The default value for C{min} is 1 (a - minimum value < 1 is not valid); the default values for C{max} and C{exact} - are 0, meaning no maximum or exact length restriction. An optional - C{excludeChars} parameter can list characters that might be found in - the input C{bodyChars} string; useful to define a word of all printables - except for one or two characters, for instance. - - L{srange} is useful for defining custom character set strings for defining - C{Word} expressions, using range notation from regular expression character sets. - - A common mistake is to use C{Word} to match a specific literal string, as in - C{Word("Address")}. Remember that C{Word} uses the string argument to define - I{sets} of matchable characters. This expression would match "Add", "AAA", - "dAred", or any other word made up of the characters 'A', 'd', 'r', 'e', and 's'. - To match an exact literal string, use L{Literal} or L{Keyword}. - - pyparsing includes helper strings for building Words: - - L{alphas} - - L{nums} - - L{alphanums} - - L{hexnums} - - L{alphas8bit} (alphabetic characters in ASCII range 128-255 - accented, tilded, umlauted, etc.) - - L{punc8bit} (non-alphabetic characters in ASCII range 128-255 - currency, symbols, superscripts, diacriticals, etc.) - - L{printables} (any non-whitespace character) - - Example:: - # a word composed of digits - integer = Word(nums) # equivalent to Word("0123456789") or Word(srange("0-9")) - - # a word with a leading capital, and zero or more lowercase - capital_word = Word(alphas.upper(), alphas.lower()) - - # hostnames are alphanumeric, with leading alpha, and '-' - hostname = Word(alphas, alphanums+'-') - - # roman numeral (not a strict parser, accepts invalid mix of characters) - roman = Word("IVXLCDM") - - # any string of non-whitespace characters, except for ',' - csv_value = Word(printables, excludeChars=",") - """ - def __init__( self, initChars, bodyChars=None, min=1, max=0, exact=0, asKeyword=False, excludeChars=None ): - super(Word,self).__init__() - if excludeChars: - initChars = ''.join(c for c in initChars if c not in excludeChars) - if bodyChars: - bodyChars = ''.join(c for c in bodyChars if c not in excludeChars) - self.initCharsOrig = initChars - self.initChars = set(initChars) - if bodyChars : - self.bodyCharsOrig = bodyChars - self.bodyChars = set(bodyChars) - else: - self.bodyCharsOrig = initChars - self.bodyChars = set(initChars) - - self.maxSpecified = max > 0 - - if min < 1: - raise ValueError("cannot specify a minimum length < 1; use Optional(Word()) if zero-length word is permitted") - - self.minLen = min - - if max > 0: - self.maxLen = max - else: - self.maxLen = _MAX_INT - - if exact > 0: - self.maxLen = exact - self.minLen = exact - - self.name = _ustr(self) - self.errmsg = "Expected " + self.name - self.mayIndexError = False - self.asKeyword = asKeyword - - if ' ' not in self.initCharsOrig+self.bodyCharsOrig and (min==1 and max==0 and exact==0): - if self.bodyCharsOrig == self.initCharsOrig: - self.reString = "[%s]+" % _escapeRegexRangeChars(self.initCharsOrig) - elif len(self.initCharsOrig) == 1: - self.reString = "%s[%s]*" % \ - (re.escape(self.initCharsOrig), - _escapeRegexRangeChars(self.bodyCharsOrig),) - else: - self.reString = "[%s][%s]*" % \ - (_escapeRegexRangeChars(self.initCharsOrig), - _escapeRegexRangeChars(self.bodyCharsOrig),) - if self.asKeyword: - self.reString = r"\b"+self.reString+r"\b" - try: - self.re = re.compile( self.reString ) - except Exception: - self.re = None - - def parseImpl( self, instring, loc, doActions=True ): - if self.re: - result = self.re.match(instring,loc) - if not result: - raise ParseException(instring, loc, self.errmsg, self) - - loc = result.end() - return loc, result.group() - - if not(instring[ loc ] in self.initChars): - raise ParseException(instring, loc, self.errmsg, self) - - start = loc - loc += 1 - instrlen = len(instring) - bodychars = self.bodyChars - maxloc = start + self.maxLen - maxloc = min( maxloc, instrlen ) - while loc < maxloc and instring[loc] in bodychars: - loc += 1 - - throwException = False - if loc - start < self.minLen: - throwException = True - if self.maxSpecified and loc < instrlen and instring[loc] in bodychars: - throwException = True - if self.asKeyword: - if (start>0 and instring[start-1] in bodychars) or (loc<instrlen and instring[loc] in bodychars): - throwException = True - - if throwException: - raise ParseException(instring, loc, self.errmsg, self) - - return loc, instring[start:loc] - - def __str__( self ): - try: - return super(Word,self).__str__() - except Exception: - pass - - - if self.strRepr is None: - - def charsAsStr(s): - if len(s)>4: - return s[:4]+"..." - else: - return s - - if ( self.initCharsOrig != self.bodyCharsOrig ): - self.strRepr = "W:(%s,%s)" % ( charsAsStr(self.initCharsOrig), charsAsStr(self.bodyCharsOrig) ) - else: - self.strRepr = "W:(%s)" % charsAsStr(self.initCharsOrig) - - return self.strRepr - - -class Regex(Token): - r""" - Token for matching strings that match a given regular expression. - Defined with string specifying the regular expression in a form recognized by the inbuilt Python re module. - If the given regex contains named groups (defined using C{(?P<name>...)}), these will be preserved as - named parse results. - - Example:: - realnum = Regex(r"[+-]?\d+\.\d*") - date = Regex(r'(?P<year>\d{4})-(?P<month>\d\d?)-(?P<day>\d\d?)') - # ref: http://stackoverflow.com/questions/267399/how-do-you-match-only-valid-roman-numerals-with-a-regular-expression - roman = Regex(r"M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})") - """ - compiledREtype = type(re.compile("[A-Z]")) - def __init__( self, pattern, flags=0): - """The parameters C{pattern} and C{flags} are passed to the C{re.compile()} function as-is. See the Python C{re} module for an explanation of the acceptable patterns and flags.""" - super(Regex,self).__init__() - - if isinstance(pattern, basestring): - if not pattern: - warnings.warn("null string passed to Regex; use Empty() instead", - SyntaxWarning, stacklevel=2) - - self.pattern = pattern - self.flags = flags - - try: - self.re = re.compile(self.pattern, self.flags) - self.reString = self.pattern - except sre_constants.error: - warnings.warn("invalid pattern (%s) passed to Regex" % pattern, - SyntaxWarning, stacklevel=2) - raise - - elif isinstance(pattern, Regex.compiledREtype): - self.re = pattern - self.pattern = \ - self.reString = str(pattern) - self.flags = flags - - else: - raise ValueError("Regex may only be constructed with a string or a compiled RE object") - - self.name = _ustr(self) - self.errmsg = "Expected " + self.name - self.mayIndexError = False - self.mayReturnEmpty = True - - def parseImpl( self, instring, loc, doActions=True ): - result = self.re.match(instring,loc) - if not result: - raise ParseException(instring, loc, self.errmsg, self) - - loc = result.end() - d = result.groupdict() - ret = ParseResults(result.group()) - if d: - for k in d: - ret[k] = d[k] - return loc,ret - - def __str__( self ): - try: - return super(Regex,self).__str__() - except Exception: - pass - - if self.strRepr is None: - self.strRepr = "Re:(%s)" % repr(self.pattern) - - return self.strRepr - - -class QuotedString(Token): - r""" - Token for matching strings that are delimited by quoting characters. - - Defined with the following parameters: - - quoteChar - string of one or more characters defining the quote delimiting string - - escChar - character to escape quotes, typically backslash (default=C{None}) - - escQuote - special quote sequence to escape an embedded quote string (such as SQL's "" to escape an embedded ") (default=C{None}) - - multiline - boolean indicating whether quotes can span multiple lines (default=C{False}) - - unquoteResults - boolean indicating whether the matched text should be unquoted (default=C{True}) - - endQuoteChar - string of one or more characters defining the end of the quote delimited string (default=C{None} => same as quoteChar) - - convertWhitespaceEscapes - convert escaped whitespace (C{'\t'}, C{'\n'}, etc.) to actual whitespace (default=C{True}) - - Example:: - qs = QuotedString('"') - print(qs.searchString('lsjdf "This is the quote" sldjf')) - complex_qs = QuotedString('{{', endQuoteChar='}}') - print(complex_qs.searchString('lsjdf {{This is the "quote"}} sldjf')) - sql_qs = QuotedString('"', escQuote='""') - print(sql_qs.searchString('lsjdf "This is the quote with ""embedded"" quotes" sldjf')) - prints:: - [['This is the quote']] - [['This is the "quote"']] - [['This is the quote with "embedded" quotes']] - """ - def __init__( self, quoteChar, escChar=None, escQuote=None, multiline=False, unquoteResults=True, endQuoteChar=None, convertWhitespaceEscapes=True): - super(QuotedString,self).__init__() - - # remove white space from quote chars - wont work anyway - quoteChar = quoteChar.strip() - if not quoteChar: - warnings.warn("quoteChar cannot be the empty string",SyntaxWarning,stacklevel=2) - raise SyntaxError() - - if endQuoteChar is None: - endQuoteChar = quoteChar - else: - endQuoteChar = endQuoteChar.strip() - if not endQuoteChar: - warnings.warn("endQuoteChar cannot be the empty string",SyntaxWarning,stacklevel=2) - raise SyntaxError() - - self.quoteChar = quoteChar - self.quoteCharLen = len(quoteChar) - self.firstQuoteChar = quoteChar[0] - self.endQuoteChar = endQuoteChar - self.endQuoteCharLen = len(endQuoteChar) - self.escChar = escChar - self.escQuote = escQuote - self.unquoteResults = unquoteResults - self.convertWhitespaceEscapes = convertWhitespaceEscapes - - if multiline: - self.flags = re.MULTILINE | re.DOTALL - self.pattern = r'%s(?:[^%s%s]' % \ - ( re.escape(self.quoteChar), - _escapeRegexRangeChars(self.endQuoteChar[0]), - (escChar is not None and _escapeRegexRangeChars(escChar) or '') ) - else: - self.flags = 0 - self.pattern = r'%s(?:[^%s\n\r%s]' % \ - ( re.escape(self.quoteChar), - _escapeRegexRangeChars(self.endQuoteChar[0]), - (escChar is not None and _escapeRegexRangeChars(escChar) or '') ) - if len(self.endQuoteChar) > 1: - self.pattern += ( - '|(?:' + ')|(?:'.join("%s[^%s]" % (re.escape(self.endQuoteChar[:i]), - _escapeRegexRangeChars(self.endQuoteChar[i])) - for i in range(len(self.endQuoteChar)-1,0,-1)) + ')' - ) - if escQuote: - self.pattern += (r'|(?:%s)' % re.escape(escQuote)) - if escChar: - self.pattern += (r'|(?:%s.)' % re.escape(escChar)) - self.escCharReplacePattern = re.escape(self.escChar)+"(.)" - self.pattern += (r')*%s' % re.escape(self.endQuoteChar)) - - try: - self.re = re.compile(self.pattern, self.flags) - self.reString = self.pattern - except sre_constants.error: - warnings.warn("invalid pattern (%s) passed to Regex" % self.pattern, - SyntaxWarning, stacklevel=2) - raise - - self.name = _ustr(self) - self.errmsg = "Expected " + self.name - self.mayIndexError = False - self.mayReturnEmpty = True - - def parseImpl( self, instring, loc, doActions=True ): - result = instring[loc] == self.firstQuoteChar and self.re.match(instring,loc) or None - if not result: - raise ParseException(instring, loc, self.errmsg, self) - - loc = result.end() - ret = result.group() - - if self.unquoteResults: - - # strip off quotes - ret = ret[self.quoteCharLen:-self.endQuoteCharLen] - - if isinstance(ret,basestring): - # replace escaped whitespace - if '\\' in ret and self.convertWhitespaceEscapes: - ws_map = { - r'\t' : '\t', - r'\n' : '\n', - r'\f' : '\f', - r'\r' : '\r', - } - for wslit,wschar in ws_map.items(): - ret = ret.replace(wslit, wschar) - - # replace escaped characters - if self.escChar: - ret = re.sub(self.escCharReplacePattern, r"\g<1>", ret) - - # replace escaped quotes - if self.escQuote: - ret = ret.replace(self.escQuote, self.endQuoteChar) - - return loc, ret - - def __str__( self ): - try: - return super(QuotedString,self).__str__() - except Exception: - pass - - if self.strRepr is None: - self.strRepr = "quoted string, starting with %s ending with %s" % (self.quoteChar, self.endQuoteChar) - - return self.strRepr - - -class CharsNotIn(Token): - """ - Token for matching words composed of characters I{not} in a given set (will - include whitespace in matched characters if not listed in the provided exclusion set - see example). - Defined with string containing all disallowed characters, and an optional - minimum, maximum, and/or exact length. The default value for C{min} is 1 (a - minimum value < 1 is not valid); the default values for C{max} and C{exact} - are 0, meaning no maximum or exact length restriction. - - Example:: - # define a comma-separated-value as anything that is not a ',' - csv_value = CharsNotIn(',') - print(delimitedList(csv_value).parseString("dkls,lsdkjf,s12 34,@!#,213")) - prints:: - ['dkls', 'lsdkjf', 's12 34', '@!#', '213'] - """ - def __init__( self, notChars, min=1, max=0, exact=0 ): - super(CharsNotIn,self).__init__() - self.skipWhitespace = False - self.notChars = notChars - - if min < 1: - raise ValueError("cannot specify a minimum length < 1; use Optional(CharsNotIn()) if zero-length char group is permitted") - - self.minLen = min - - if max > 0: - self.maxLen = max - else: - self.maxLen = _MAX_INT - - if exact > 0: - self.maxLen = exact - self.minLen = exact - - self.name = _ustr(self) - self.errmsg = "Expected " + self.name - self.mayReturnEmpty = ( self.minLen == 0 ) - self.mayIndexError = False - - def parseImpl( self, instring, loc, doActions=True ): - if instring[loc] in self.notChars: - raise ParseException(instring, loc, self.errmsg, self) - - start = loc - loc += 1 - notchars = self.notChars - maxlen = min( start+self.maxLen, len(instring) ) - while loc < maxlen and \ - (instring[loc] not in notchars): - loc += 1 - - if loc - start < self.minLen: - raise ParseException(instring, loc, self.errmsg, self) - - return loc, instring[start:loc] - - def __str__( self ): - try: - return super(CharsNotIn, self).__str__() - except Exception: - pass - - if self.strRepr is None: - if len(self.notChars) > 4: - self.strRepr = "!W:(%s...)" % self.notChars[:4] - else: - self.strRepr = "!W:(%s)" % self.notChars - - return self.strRepr - -class White(Token): - """ - Special matching class for matching whitespace. Normally, whitespace is ignored - by pyparsing grammars. This class is included when some whitespace structures - are significant. Define with a string containing the whitespace characters to be - matched; default is C{" \\t\\r\\n"}. Also takes optional C{min}, C{max}, and C{exact} arguments, - as defined for the C{L{Word}} class. - """ - whiteStrs = { - " " : "<SPC>", - "\t": "<TAB>", - "\n": "<LF>", - "\r": "<CR>", - "\f": "<FF>", - } - def __init__(self, ws=" \t\r\n", min=1, max=0, exact=0): - super(White,self).__init__() - self.matchWhite = ws - self.setWhitespaceChars( "".join(c for c in self.whiteChars if c not in self.matchWhite) ) - #~ self.leaveWhitespace() - self.name = ("".join(White.whiteStrs[c] for c in self.matchWhite)) - self.mayReturnEmpty = True - self.errmsg = "Expected " + self.name - - self.minLen = min - - if max > 0: - self.maxLen = max - else: - self.maxLen = _MAX_INT - - if exact > 0: - self.maxLen = exact - self.minLen = exact - - def parseImpl( self, instring, loc, doActions=True ): - if not(instring[ loc ] in self.matchWhite): - raise ParseException(instring, loc, self.errmsg, self) - start = loc - loc += 1 - maxloc = start + self.maxLen - maxloc = min( maxloc, len(instring) ) - while loc < maxloc and instring[loc] in self.matchWhite: - loc += 1 - - if loc - start < self.minLen: - raise ParseException(instring, loc, self.errmsg, self) - - return loc, instring[start:loc] - - -class _PositionToken(Token): - def __init__( self ): - super(_PositionToken,self).__init__() - self.name=self.__class__.__name__ - self.mayReturnEmpty = True - self.mayIndexError = False - -class GoToColumn(_PositionToken): - """ - Token to advance to a specific column of input text; useful for tabular report scraping. - """ - def __init__( self, colno ): - super(GoToColumn,self).__init__() - self.col = colno - - def preParse( self, instring, loc ): - if col(loc,instring) != self.col: - instrlen = len(instring) - if self.ignoreExprs: - loc = self._skipIgnorables( instring, loc ) - while loc < instrlen and instring[loc].isspace() and col( loc, instring ) != self.col : - loc += 1 - return loc - - def parseImpl( self, instring, loc, doActions=True ): - thiscol = col( loc, instring ) - if thiscol > self.col: - raise ParseException( instring, loc, "Text not in expected column", self ) - newloc = loc + self.col - thiscol - ret = instring[ loc: newloc ] - return newloc, ret - - -class LineStart(_PositionToken): - """ - Matches if current position is at the beginning of a line within the parse string - - Example:: - - test = '''\ - AAA this line - AAA and this line - AAA but not this one - B AAA and definitely not this one - ''' - - for t in (LineStart() + 'AAA' + restOfLine).searchString(test): - print(t) - - Prints:: - ['AAA', ' this line'] - ['AAA', ' and this line'] - - """ - def __init__( self ): - super(LineStart,self).__init__() - self.errmsg = "Expected start of line" - - def parseImpl( self, instring, loc, doActions=True ): - if col(loc, instring) == 1: - return loc, [] - raise ParseException(instring, loc, self.errmsg, self) - -class LineEnd(_PositionToken): - """ - Matches if current position is at the end of a line within the parse string - """ - def __init__( self ): - super(LineEnd,self).__init__() - self.setWhitespaceChars( ParserElement.DEFAULT_WHITE_CHARS.replace("\n","") ) - self.errmsg = "Expected end of line" - - def parseImpl( self, instring, loc, doActions=True ): - if loc<len(instring): - if instring[loc] == "\n": - return loc+1, "\n" - else: - raise ParseException(instring, loc, self.errmsg, self) - elif loc == len(instring): - return loc+1, [] - else: - raise ParseException(instring, loc, self.errmsg, self) - -class StringStart(_PositionToken): - """ - Matches if current position is at the beginning of the parse string - """ - def __init__( self ): - super(StringStart,self).__init__() - self.errmsg = "Expected start of text" - - def parseImpl( self, instring, loc, doActions=True ): - if loc != 0: - # see if entire string up to here is just whitespace and ignoreables - if loc != self.preParse( instring, 0 ): - raise ParseException(instring, loc, self.errmsg, self) - return loc, [] - -class StringEnd(_PositionToken): - """ - Matches if current position is at the end of the parse string - """ - def __init__( self ): - super(StringEnd,self).__init__() - self.errmsg = "Expected end of text" - - def parseImpl( self, instring, loc, doActions=True ): - if loc < len(instring): - raise ParseException(instring, loc, self.errmsg, self) - elif loc == len(instring): - return loc+1, [] - elif loc > len(instring): - return loc, [] - else: - raise ParseException(instring, loc, self.errmsg, self) - -class WordStart(_PositionToken): - """ - Matches if the current position is at the beginning of a Word, and - is not preceded by any character in a given set of C{wordChars} - (default=C{printables}). To emulate the C{\b} behavior of regular expressions, - use C{WordStart(alphanums)}. C{WordStart} will also match at the beginning of - the string being parsed, or at the beginning of a line. - """ - def __init__(self, wordChars = printables): - super(WordStart,self).__init__() - self.wordChars = set(wordChars) - self.errmsg = "Not at the start of a word" - - def parseImpl(self, instring, loc, doActions=True ): - if loc != 0: - if (instring[loc-1] in self.wordChars or - instring[loc] not in self.wordChars): - raise ParseException(instring, loc, self.errmsg, self) - return loc, [] - -class WordEnd(_PositionToken): - """ - Matches if the current position is at the end of a Word, and - is not followed by any character in a given set of C{wordChars} - (default=C{printables}). To emulate the C{\b} behavior of regular expressions, - use C{WordEnd(alphanums)}. C{WordEnd} will also match at the end of - the string being parsed, or at the end of a line. - """ - def __init__(self, wordChars = printables): - super(WordEnd,self).__init__() - self.wordChars = set(wordChars) - self.skipWhitespace = False - self.errmsg = "Not at the end of a word" - - def parseImpl(self, instring, loc, doActions=True ): - instrlen = len(instring) - if instrlen>0 and loc<instrlen: - if (instring[loc] in self.wordChars or - instring[loc-1] not in self.wordChars): - raise ParseException(instring, loc, self.errmsg, self) - return loc, [] - - -class ParseExpression(ParserElement): - """ - Abstract subclass of ParserElement, for combining and post-processing parsed tokens. - """ - def __init__( self, exprs, savelist = False ): - super(ParseExpression,self).__init__(savelist) - if isinstance( exprs, _generatorType ): - exprs = list(exprs) - - if isinstance( exprs, basestring ): - self.exprs = [ ParserElement._literalStringClass( exprs ) ] - elif isinstance( exprs, Iterable ): - exprs = list(exprs) - # if sequence of strings provided, wrap with Literal - if all(isinstance(expr, basestring) for expr in exprs): - exprs = map(ParserElement._literalStringClass, exprs) - self.exprs = list(exprs) - else: - try: - self.exprs = list( exprs ) - except TypeError: - self.exprs = [ exprs ] - self.callPreparse = False - - def __getitem__( self, i ): - return self.exprs[i] - - def append( self, other ): - self.exprs.append( other ) - self.strRepr = None - return self - - def leaveWhitespace( self ): - """Extends C{leaveWhitespace} defined in base class, and also invokes C{leaveWhitespace} on - all contained expressions.""" - self.skipWhitespace = False - self.exprs = [ e.copy() for e in self.exprs ] - for e in self.exprs: - e.leaveWhitespace() - return self - - def ignore( self, other ): - if isinstance( other, Suppress ): - if other not in self.ignoreExprs: - super( ParseExpression, self).ignore( other ) - for e in self.exprs: - e.ignore( self.ignoreExprs[-1] ) - else: - super( ParseExpression, self).ignore( other ) - for e in self.exprs: - e.ignore( self.ignoreExprs[-1] ) - return self - - def __str__( self ): - try: - return super(ParseExpression,self).__str__() - except Exception: - pass - - if self.strRepr is None: - self.strRepr = "%s:(%s)" % ( self.__class__.__name__, _ustr(self.exprs) ) - return self.strRepr - - def streamline( self ): - super(ParseExpression,self).streamline() - - for e in self.exprs: - e.streamline() - - # collapse nested And's of the form And( And( And( a,b), c), d) to And( a,b,c,d ) - # but only if there are no parse actions or resultsNames on the nested And's - # (likewise for Or's and MatchFirst's) - if ( len(self.exprs) == 2 ): - other = self.exprs[0] - if ( isinstance( other, self.__class__ ) and - not(other.parseAction) and - other.resultsName is None and - not other.debug ): - self.exprs = other.exprs[:] + [ self.exprs[1] ] - self.strRepr = None - self.mayReturnEmpty |= other.mayReturnEmpty - self.mayIndexError |= other.mayIndexError - - other = self.exprs[-1] - if ( isinstance( other, self.__class__ ) and - not(other.parseAction) and - other.resultsName is None and - not other.debug ): - self.exprs = self.exprs[:-1] + other.exprs[:] - self.strRepr = None - self.mayReturnEmpty |= other.mayReturnEmpty - self.mayIndexError |= other.mayIndexError - - self.errmsg = "Expected " + _ustr(self) - - return self - - def setResultsName( self, name, listAllMatches=False ): - ret = super(ParseExpression,self).setResultsName(name,listAllMatches) - return ret - - def validate( self, validateTrace=[] ): - tmp = validateTrace[:]+[self] - for e in self.exprs: - e.validate(tmp) - self.checkRecursion( [] ) - - def copy(self): - ret = super(ParseExpression,self).copy() - ret.exprs = [e.copy() for e in self.exprs] - return ret - -class And(ParseExpression): - """ - Requires all given C{ParseExpression}s to be found in the given order. - Expressions may be separated by whitespace. - May be constructed using the C{'+'} operator. - May also be constructed using the C{'-'} operator, which will suppress backtracking. - - Example:: - integer = Word(nums) - name_expr = OneOrMore(Word(alphas)) - - expr = And([integer("id"),name_expr("name"),integer("age")]) - # more easily written as: - expr = integer("id") + name_expr("name") + integer("age") - """ - - class _ErrorStop(Empty): - def __init__(self, *args, **kwargs): - super(And._ErrorStop,self).__init__(*args, **kwargs) - self.name = '-' - self.leaveWhitespace() - - def __init__( self, exprs, savelist = True ): - super(And,self).__init__(exprs, savelist) - self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs) - self.setWhitespaceChars( self.exprs[0].whiteChars ) - self.skipWhitespace = self.exprs[0].skipWhitespace - self.callPreparse = True - - def parseImpl( self, instring, loc, doActions=True ): - # pass False as last arg to _parse for first element, since we already - # pre-parsed the string as part of our And pre-parsing - loc, resultlist = self.exprs[0]._parse( instring, loc, doActions, callPreParse=False ) - errorStop = False - for e in self.exprs[1:]: - if isinstance(e, And._ErrorStop): - errorStop = True - continue - if errorStop: - try: - loc, exprtokens = e._parse( instring, loc, doActions ) - except ParseSyntaxException: - raise - except ParseBaseException as pe: - pe.__traceback__ = None - raise ParseSyntaxException._from_exception(pe) - except IndexError: - raise ParseSyntaxException(instring, len(instring), self.errmsg, self) - else: - loc, exprtokens = e._parse( instring, loc, doActions ) - if exprtokens or exprtokens.haskeys(): - resultlist += exprtokens - return loc, resultlist - - def __iadd__(self, other ): - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - return self.append( other ) #And( [ self, other ] ) - - def checkRecursion( self, parseElementList ): - subRecCheckList = parseElementList[:] + [ self ] - for e in self.exprs: - e.checkRecursion( subRecCheckList ) - if not e.mayReturnEmpty: - break - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "{" + " ".join(_ustr(e) for e in self.exprs) + "}" - - return self.strRepr - - -class Or(ParseExpression): - """ - Requires that at least one C{ParseExpression} is found. - If two expressions match, the expression that matches the longest string will be used. - May be constructed using the C{'^'} operator. - - Example:: - # construct Or using '^' operator - - number = Word(nums) ^ Combine(Word(nums) + '.' + Word(nums)) - print(number.searchString("123 3.1416 789")) - prints:: - [['123'], ['3.1416'], ['789']] - """ - def __init__( self, exprs, savelist = False ): - super(Or,self).__init__(exprs, savelist) - if self.exprs: - self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs) - else: - self.mayReturnEmpty = True - - def parseImpl( self, instring, loc, doActions=True ): - maxExcLoc = -1 - maxException = None - matches = [] - for e in self.exprs: - try: - loc2 = e.tryParse( instring, loc ) - except ParseException as err: - err.__traceback__ = None - if err.loc > maxExcLoc: - maxException = err - maxExcLoc = err.loc - except IndexError: - if len(instring) > maxExcLoc: - maxException = ParseException(instring,len(instring),e.errmsg,self) - maxExcLoc = len(instring) - else: - # save match among all matches, to retry longest to shortest - matches.append((loc2, e)) - - if matches: - matches.sort(key=lambda x: -x[0]) - for _,e in matches: - try: - return e._parse( instring, loc, doActions ) - except ParseException as err: - err.__traceback__ = None - if err.loc > maxExcLoc: - maxException = err - maxExcLoc = err.loc - - if maxException is not None: - maxException.msg = self.errmsg - raise maxException - else: - raise ParseException(instring, loc, "no defined alternatives to match", self) - - - def __ixor__(self, other ): - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - return self.append( other ) #Or( [ self, other ] ) - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "{" + " ^ ".join(_ustr(e) for e in self.exprs) + "}" - - return self.strRepr - - def checkRecursion( self, parseElementList ): - subRecCheckList = parseElementList[:] + [ self ] - for e in self.exprs: - e.checkRecursion( subRecCheckList ) - - -class MatchFirst(ParseExpression): - """ - Requires that at least one C{ParseExpression} is found. - If two expressions match, the first one listed is the one that will match. - May be constructed using the C{'|'} operator. - - Example:: - # construct MatchFirst using '|' operator - - # watch the order of expressions to match - number = Word(nums) | Combine(Word(nums) + '.' + Word(nums)) - print(number.searchString("123 3.1416 789")) # Fail! -> [['123'], ['3'], ['1416'], ['789']] - - # put more selective expression first - number = Combine(Word(nums) + '.' + Word(nums)) | Word(nums) - print(number.searchString("123 3.1416 789")) # Better -> [['123'], ['3.1416'], ['789']] - """ - def __init__( self, exprs, savelist = False ): - super(MatchFirst,self).__init__(exprs, savelist) - if self.exprs: - self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs) - else: - self.mayReturnEmpty = True - - def parseImpl( self, instring, loc, doActions=True ): - maxExcLoc = -1 - maxException = None - for e in self.exprs: - try: - ret = e._parse( instring, loc, doActions ) - return ret - except ParseException as err: - if err.loc > maxExcLoc: - maxException = err - maxExcLoc = err.loc - except IndexError: - if len(instring) > maxExcLoc: - maxException = ParseException(instring,len(instring),e.errmsg,self) - maxExcLoc = len(instring) - - # only got here if no expression matched, raise exception for match that made it the furthest - else: - if maxException is not None: - maxException.msg = self.errmsg - raise maxException - else: - raise ParseException(instring, loc, "no defined alternatives to match", self) - - def __ior__(self, other ): - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - return self.append( other ) #MatchFirst( [ self, other ] ) - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "{" + " | ".join(_ustr(e) for e in self.exprs) + "}" - - return self.strRepr - - def checkRecursion( self, parseElementList ): - subRecCheckList = parseElementList[:] + [ self ] - for e in self.exprs: - e.checkRecursion( subRecCheckList ) - - -class Each(ParseExpression): - """ - Requires all given C{ParseExpression}s to be found, but in any order. - Expressions may be separated by whitespace. - May be constructed using the C{'&'} operator. - - Example:: - color = oneOf("RED ORANGE YELLOW GREEN BLUE PURPLE BLACK WHITE BROWN") - shape_type = oneOf("SQUARE CIRCLE TRIANGLE STAR HEXAGON OCTAGON") - integer = Word(nums) - shape_attr = "shape:" + shape_type("shape") - posn_attr = "posn:" + Group(integer("x") + ',' + integer("y"))("posn") - color_attr = "color:" + color("color") - size_attr = "size:" + integer("size") - - # use Each (using operator '&') to accept attributes in any order - # (shape and posn are required, color and size are optional) - shape_spec = shape_attr & posn_attr & Optional(color_attr) & Optional(size_attr) - - shape_spec.runTests(''' - shape: SQUARE color: BLACK posn: 100, 120 - shape: CIRCLE size: 50 color: BLUE posn: 50,80 - color:GREEN size:20 shape:TRIANGLE posn:20,40 - ''' - ) - prints:: - shape: SQUARE color: BLACK posn: 100, 120 - ['shape:', 'SQUARE', 'color:', 'BLACK', 'posn:', ['100', ',', '120']] - - color: BLACK - - posn: ['100', ',', '120'] - - x: 100 - - y: 120 - - shape: SQUARE - - - shape: CIRCLE size: 50 color: BLUE posn: 50,80 - ['shape:', 'CIRCLE', 'size:', '50', 'color:', 'BLUE', 'posn:', ['50', ',', '80']] - - color: BLUE - - posn: ['50', ',', '80'] - - x: 50 - - y: 80 - - shape: CIRCLE - - size: 50 - - - color: GREEN size: 20 shape: TRIANGLE posn: 20,40 - ['color:', 'GREEN', 'size:', '20', 'shape:', 'TRIANGLE', 'posn:', ['20', ',', '40']] - - color: GREEN - - posn: ['20', ',', '40'] - - x: 20 - - y: 40 - - shape: TRIANGLE - - size: 20 - """ - def __init__( self, exprs, savelist = True ): - super(Each,self).__init__(exprs, savelist) - self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs) - self.skipWhitespace = True - self.initExprGroups = True - - def parseImpl( self, instring, loc, doActions=True ): - if self.initExprGroups: - self.opt1map = dict((id(e.expr),e) for e in self.exprs if isinstance(e,Optional)) - opt1 = [ e.expr for e in self.exprs if isinstance(e,Optional) ] - opt2 = [ e for e in self.exprs if e.mayReturnEmpty and not isinstance(e,Optional)] - self.optionals = opt1 + opt2 - self.multioptionals = [ e.expr for e in self.exprs if isinstance(e,ZeroOrMore) ] - self.multirequired = [ e.expr for e in self.exprs if isinstance(e,OneOrMore) ] - self.required = [ e for e in self.exprs if not isinstance(e,(Optional,ZeroOrMore,OneOrMore)) ] - self.required += self.multirequired - self.initExprGroups = False - tmpLoc = loc - tmpReqd = self.required[:] - tmpOpt = self.optionals[:] - matchOrder = [] - - keepMatching = True - while keepMatching: - tmpExprs = tmpReqd + tmpOpt + self.multioptionals + self.multirequired - failed = [] - for e in tmpExprs: - try: - tmpLoc = e.tryParse( instring, tmpLoc ) - except ParseException: - failed.append(e) - else: - matchOrder.append(self.opt1map.get(id(e),e)) - if e in tmpReqd: - tmpReqd.remove(e) - elif e in tmpOpt: - tmpOpt.remove(e) - if len(failed) == len(tmpExprs): - keepMatching = False - - if tmpReqd: - missing = ", ".join(_ustr(e) for e in tmpReqd) - raise ParseException(instring,loc,"Missing one or more required elements (%s)" % missing ) - - # add any unmatched Optionals, in case they have default values defined - matchOrder += [e for e in self.exprs if isinstance(e,Optional) and e.expr in tmpOpt] - - resultlist = [] - for e in matchOrder: - loc,results = e._parse(instring,loc,doActions) - resultlist.append(results) - - finalResults = sum(resultlist, ParseResults([])) - return loc, finalResults - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "{" + " & ".join(_ustr(e) for e in self.exprs) + "}" - - return self.strRepr - - def checkRecursion( self, parseElementList ): - subRecCheckList = parseElementList[:] + [ self ] - for e in self.exprs: - e.checkRecursion( subRecCheckList ) - - -class ParseElementEnhance(ParserElement): - """ - Abstract subclass of C{ParserElement}, for combining and post-processing parsed tokens. - """ - def __init__( self, expr, savelist=False ): - super(ParseElementEnhance,self).__init__(savelist) - if isinstance( expr, basestring ): - if issubclass(ParserElement._literalStringClass, Token): - expr = ParserElement._literalStringClass(expr) - else: - expr = ParserElement._literalStringClass(Literal(expr)) - self.expr = expr - self.strRepr = None - if expr is not None: - self.mayIndexError = expr.mayIndexError - self.mayReturnEmpty = expr.mayReturnEmpty - self.setWhitespaceChars( expr.whiteChars ) - self.skipWhitespace = expr.skipWhitespace - self.saveAsList = expr.saveAsList - self.callPreparse = expr.callPreparse - self.ignoreExprs.extend(expr.ignoreExprs) - - def parseImpl( self, instring, loc, doActions=True ): - if self.expr is not None: - return self.expr._parse( instring, loc, doActions, callPreParse=False ) - else: - raise ParseException("",loc,self.errmsg,self) - - def leaveWhitespace( self ): - self.skipWhitespace = False - self.expr = self.expr.copy() - if self.expr is not None: - self.expr.leaveWhitespace() - return self - - def ignore( self, other ): - if isinstance( other, Suppress ): - if other not in self.ignoreExprs: - super( ParseElementEnhance, self).ignore( other ) - if self.expr is not None: - self.expr.ignore( self.ignoreExprs[-1] ) - else: - super( ParseElementEnhance, self).ignore( other ) - if self.expr is not None: - self.expr.ignore( self.ignoreExprs[-1] ) - return self - - def streamline( self ): - super(ParseElementEnhance,self).streamline() - if self.expr is not None: - self.expr.streamline() - return self - - def checkRecursion( self, parseElementList ): - if self in parseElementList: - raise RecursiveGrammarException( parseElementList+[self] ) - subRecCheckList = parseElementList[:] + [ self ] - if self.expr is not None: - self.expr.checkRecursion( subRecCheckList ) - - def validate( self, validateTrace=[] ): - tmp = validateTrace[:]+[self] - if self.expr is not None: - self.expr.validate(tmp) - self.checkRecursion( [] ) - - def __str__( self ): - try: - return super(ParseElementEnhance,self).__str__() - except Exception: - pass - - if self.strRepr is None and self.expr is not None: - self.strRepr = "%s:(%s)" % ( self.__class__.__name__, _ustr(self.expr) ) - return self.strRepr - - -class FollowedBy(ParseElementEnhance): - """ - Lookahead matching of the given parse expression. C{FollowedBy} - does I{not} advance the parsing position within the input string, it only - verifies that the specified parse expression matches at the current - position. C{FollowedBy} always returns a null token list. - - Example:: - # use FollowedBy to match a label only if it is followed by a ':' - data_word = Word(alphas) - label = data_word + FollowedBy(':') - attr_expr = Group(label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join)) - - OneOrMore(attr_expr).parseString("shape: SQUARE color: BLACK posn: upper left").pprint() - prints:: - [['shape', 'SQUARE'], ['color', 'BLACK'], ['posn', 'upper left']] - """ - def __init__( self, expr ): - super(FollowedBy,self).__init__(expr) - self.mayReturnEmpty = True - - def parseImpl( self, instring, loc, doActions=True ): - self.expr.tryParse( instring, loc ) - return loc, [] - - -class NotAny(ParseElementEnhance): - """ - Lookahead to disallow matching with the given parse expression. C{NotAny} - does I{not} advance the parsing position within the input string, it only - verifies that the specified parse expression does I{not} match at the current - position. Also, C{NotAny} does I{not} skip over leading whitespace. C{NotAny} - always returns a null token list. May be constructed using the '~' operator. - - Example:: - - """ - def __init__( self, expr ): - super(NotAny,self).__init__(expr) - #~ self.leaveWhitespace() - self.skipWhitespace = False # do NOT use self.leaveWhitespace(), don't want to propagate to exprs - self.mayReturnEmpty = True - self.errmsg = "Found unwanted token, "+_ustr(self.expr) - - def parseImpl( self, instring, loc, doActions=True ): - if self.expr.canParseNext(instring, loc): - raise ParseException(instring, loc, self.errmsg, self) - return loc, [] - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "~{" + _ustr(self.expr) + "}" - - return self.strRepr - -class _MultipleMatch(ParseElementEnhance): - def __init__( self, expr, stopOn=None): - super(_MultipleMatch, self).__init__(expr) - self.saveAsList = True - ender = stopOn - if isinstance(ender, basestring): - ender = ParserElement._literalStringClass(ender) - self.not_ender = ~ender if ender is not None else None - - def parseImpl( self, instring, loc, doActions=True ): - self_expr_parse = self.expr._parse - self_skip_ignorables = self._skipIgnorables - check_ender = self.not_ender is not None - if check_ender: - try_not_ender = self.not_ender.tryParse - - # must be at least one (but first see if we are the stopOn sentinel; - # if so, fail) - if check_ender: - try_not_ender(instring, loc) - loc, tokens = self_expr_parse( instring, loc, doActions, callPreParse=False ) - try: - hasIgnoreExprs = (not not self.ignoreExprs) - while 1: - if check_ender: - try_not_ender(instring, loc) - if hasIgnoreExprs: - preloc = self_skip_ignorables( instring, loc ) - else: - preloc = loc - loc, tmptokens = self_expr_parse( instring, preloc, doActions ) - if tmptokens or tmptokens.haskeys(): - tokens += tmptokens - except (ParseException,IndexError): - pass - - return loc, tokens - -class OneOrMore(_MultipleMatch): - """ - Repetition of one or more of the given expression. - - Parameters: - - expr - expression that must match one or more times - - stopOn - (default=C{None}) - expression for a terminating sentinel - (only required if the sentinel would ordinarily match the repetition - expression) - - Example:: - data_word = Word(alphas) - label = data_word + FollowedBy(':') - attr_expr = Group(label + Suppress(':') + OneOrMore(data_word).setParseAction(' '.join)) - - text = "shape: SQUARE posn: upper left color: BLACK" - OneOrMore(attr_expr).parseString(text).pprint() # Fail! read 'color' as data instead of next label -> [['shape', 'SQUARE color']] - - # use stopOn attribute for OneOrMore to avoid reading label string as part of the data - attr_expr = Group(label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join)) - OneOrMore(attr_expr).parseString(text).pprint() # Better -> [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'BLACK']] - - # could also be written as - (attr_expr * (1,)).parseString(text).pprint() - """ - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "{" + _ustr(self.expr) + "}..." - - return self.strRepr - -class ZeroOrMore(_MultipleMatch): - """ - Optional repetition of zero or more of the given expression. - - Parameters: - - expr - expression that must match zero or more times - - stopOn - (default=C{None}) - expression for a terminating sentinel - (only required if the sentinel would ordinarily match the repetition - expression) - - Example: similar to L{OneOrMore} - """ - def __init__( self, expr, stopOn=None): - super(ZeroOrMore,self).__init__(expr, stopOn=stopOn) - self.mayReturnEmpty = True - - def parseImpl( self, instring, loc, doActions=True ): - try: - return super(ZeroOrMore, self).parseImpl(instring, loc, doActions) - except (ParseException,IndexError): - return loc, [] - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "[" + _ustr(self.expr) + "]..." - - return self.strRepr - -class _NullToken(object): - def __bool__(self): - return False - __nonzero__ = __bool__ - def __str__(self): - return "" - -_optionalNotMatched = _NullToken() -class Optional(ParseElementEnhance): - """ - Optional matching of the given expression. - - Parameters: - - expr - expression that must match zero or more times - - default (optional) - value to be returned if the optional expression is not found. - - Example:: - # US postal code can be a 5-digit zip, plus optional 4-digit qualifier - zip = Combine(Word(nums, exact=5) + Optional('-' + Word(nums, exact=4))) - zip.runTests(''' - # traditional ZIP code - 12345 - - # ZIP+4 form - 12101-0001 - - # invalid ZIP - 98765- - ''') - prints:: - # traditional ZIP code - 12345 - ['12345'] - - # ZIP+4 form - 12101-0001 - ['12101-0001'] - - # invalid ZIP - 98765- - ^ - FAIL: Expected end of text (at char 5), (line:1, col:6) - """ - def __init__( self, expr, default=_optionalNotMatched ): - super(Optional,self).__init__( expr, savelist=False ) - self.saveAsList = self.expr.saveAsList - self.defaultValue = default - self.mayReturnEmpty = True - - def parseImpl( self, instring, loc, doActions=True ): - try: - loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False ) - except (ParseException,IndexError): - if self.defaultValue is not _optionalNotMatched: - if self.expr.resultsName: - tokens = ParseResults([ self.defaultValue ]) - tokens[self.expr.resultsName] = self.defaultValue - else: - tokens = [ self.defaultValue ] - else: - tokens = [] - return loc, tokens - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "[" + _ustr(self.expr) + "]" - - return self.strRepr - -class SkipTo(ParseElementEnhance): - """ - Token for skipping over all undefined text until the matched expression is found. - - Parameters: - - expr - target expression marking the end of the data to be skipped - - include - (default=C{False}) if True, the target expression is also parsed - (the skipped text and target expression are returned as a 2-element list). - - ignore - (default=C{None}) used to define grammars (typically quoted strings and - comments) that might contain false matches to the target expression - - failOn - (default=C{None}) define expressions that are not allowed to be - included in the skipped test; if found before the target expression is found, - the SkipTo is not a match - - Example:: - report = ''' - Outstanding Issues Report - 1 Jan 2000 - - # | Severity | Description | Days Open - -----+----------+-------------------------------------------+----------- - 101 | Critical | Intermittent system crash | 6 - 94 | Cosmetic | Spelling error on Login ('log|n') | 14 - 79 | Minor | System slow when running too many reports | 47 - ''' - integer = Word(nums) - SEP = Suppress('|') - # use SkipTo to simply match everything up until the next SEP - # - ignore quoted strings, so that a '|' character inside a quoted string does not match - # - parse action will call token.strip() for each matched token, i.e., the description body - string_data = SkipTo(SEP, ignore=quotedString) - string_data.setParseAction(tokenMap(str.strip)) - ticket_expr = (integer("issue_num") + SEP - + string_data("sev") + SEP - + string_data("desc") + SEP - + integer("days_open")) - - for tkt in ticket_expr.searchString(report): - print tkt.dump() - prints:: - ['101', 'Critical', 'Intermittent system crash', '6'] - - days_open: 6 - - desc: Intermittent system crash - - issue_num: 101 - - sev: Critical - ['94', 'Cosmetic', "Spelling error on Login ('log|n')", '14'] - - days_open: 14 - - desc: Spelling error on Login ('log|n') - - issue_num: 94 - - sev: Cosmetic - ['79', 'Minor', 'System slow when running too many reports', '47'] - - days_open: 47 - - desc: System slow when running too many reports - - issue_num: 79 - - sev: Minor - """ - def __init__( self, other, include=False, ignore=None, failOn=None ): - super( SkipTo, self ).__init__( other ) - self.ignoreExpr = ignore - self.mayReturnEmpty = True - self.mayIndexError = False - self.includeMatch = include - self.asList = False - if isinstance(failOn, basestring): - self.failOn = ParserElement._literalStringClass(failOn) - else: - self.failOn = failOn - self.errmsg = "No match found for "+_ustr(self.expr) - - def parseImpl( self, instring, loc, doActions=True ): - startloc = loc - instrlen = len(instring) - expr = self.expr - expr_parse = self.expr._parse - self_failOn_canParseNext = self.failOn.canParseNext if self.failOn is not None else None - self_ignoreExpr_tryParse = self.ignoreExpr.tryParse if self.ignoreExpr is not None else None - - tmploc = loc - while tmploc <= instrlen: - if self_failOn_canParseNext is not None: - # break if failOn expression matches - if self_failOn_canParseNext(instring, tmploc): - break - - if self_ignoreExpr_tryParse is not None: - # advance past ignore expressions - while 1: - try: - tmploc = self_ignoreExpr_tryParse(instring, tmploc) - except ParseBaseException: - break - - try: - expr_parse(instring, tmploc, doActions=False, callPreParse=False) - except (ParseException, IndexError): - # no match, advance loc in string - tmploc += 1 - else: - # matched skipto expr, done - break - - else: - # ran off the end of the input string without matching skipto expr, fail - raise ParseException(instring, loc, self.errmsg, self) - - # build up return values - loc = tmploc - skiptext = instring[startloc:loc] - skipresult = ParseResults(skiptext) - - if self.includeMatch: - loc, mat = expr_parse(instring,loc,doActions,callPreParse=False) - skipresult += mat - - return loc, skipresult - -class Forward(ParseElementEnhance): - """ - Forward declaration of an expression to be defined later - - used for recursive grammars, such as algebraic infix notation. - When the expression is known, it is assigned to the C{Forward} variable using the '<<' operator. - - Note: take care when assigning to C{Forward} not to overlook precedence of operators. - Specifically, '|' has a lower precedence than '<<', so that:: - fwdExpr << a | b | c - will actually be evaluated as:: - (fwdExpr << a) | b | c - thereby leaving b and c out as parseable alternatives. It is recommended that you - explicitly group the values inserted into the C{Forward}:: - fwdExpr << (a | b | c) - Converting to use the '<<=' operator instead will avoid this problem. - - See L{ParseResults.pprint} for an example of a recursive parser created using - C{Forward}. - """ - def __init__( self, other=None ): - super(Forward,self).__init__( other, savelist=False ) - - def __lshift__( self, other ): - if isinstance( other, basestring ): - other = ParserElement._literalStringClass(other) - self.expr = other - self.strRepr = None - self.mayIndexError = self.expr.mayIndexError - self.mayReturnEmpty = self.expr.mayReturnEmpty - self.setWhitespaceChars( self.expr.whiteChars ) - self.skipWhitespace = self.expr.skipWhitespace - self.saveAsList = self.expr.saveAsList - self.ignoreExprs.extend(self.expr.ignoreExprs) - return self - - def __ilshift__(self, other): - return self << other - - def leaveWhitespace( self ): - self.skipWhitespace = False - return self - - def streamline( self ): - if not self.streamlined: - self.streamlined = True - if self.expr is not None: - self.expr.streamline() - return self - - def validate( self, validateTrace=[] ): - if self not in validateTrace: - tmp = validateTrace[:]+[self] - if self.expr is not None: - self.expr.validate(tmp) - self.checkRecursion([]) - - def __str__( self ): - if hasattr(self,"name"): - return self.name - return self.__class__.__name__ + ": ..." - - # stubbed out for now - creates awful memory and perf issues - self._revertClass = self.__class__ - self.__class__ = _ForwardNoRecurse - try: - if self.expr is not None: - retString = _ustr(self.expr) - else: - retString = "None" - finally: - self.__class__ = self._revertClass - return self.__class__.__name__ + ": " + retString - - def copy(self): - if self.expr is not None: - return super(Forward,self).copy() - else: - ret = Forward() - ret <<= self - return ret - -class _ForwardNoRecurse(Forward): - def __str__( self ): - return "..." - -class TokenConverter(ParseElementEnhance): - """ - Abstract subclass of C{ParseExpression}, for converting parsed results. - """ - def __init__( self, expr, savelist=False ): - super(TokenConverter,self).__init__( expr )#, savelist ) - self.saveAsList = False - -class Combine(TokenConverter): - """ - Converter to concatenate all matching tokens to a single string. - By default, the matching patterns must also be contiguous in the input string; - this can be disabled by specifying C{'adjacent=False'} in the constructor. - - Example:: - real = Word(nums) + '.' + Word(nums) - print(real.parseString('3.1416')) # -> ['3', '.', '1416'] - # will also erroneously match the following - print(real.parseString('3. 1416')) # -> ['3', '.', '1416'] - - real = Combine(Word(nums) + '.' + Word(nums)) - print(real.parseString('3.1416')) # -> ['3.1416'] - # no match when there are internal spaces - print(real.parseString('3. 1416')) # -> Exception: Expected W:(0123...) - """ - def __init__( self, expr, joinString="", adjacent=True ): - super(Combine,self).__init__( expr ) - # suppress whitespace-stripping in contained parse expressions, but re-enable it on the Combine itself - if adjacent: - self.leaveWhitespace() - self.adjacent = adjacent - self.skipWhitespace = True - self.joinString = joinString - self.callPreparse = True - - def ignore( self, other ): - if self.adjacent: - ParserElement.ignore(self, other) - else: - super( Combine, self).ignore( other ) - return self - - def postParse( self, instring, loc, tokenlist ): - retToks = tokenlist.copy() - del retToks[:] - retToks += ParseResults([ "".join(tokenlist._asStringList(self.joinString)) ], modal=self.modalResults) - - if self.resultsName and retToks.haskeys(): - return [ retToks ] - else: - return retToks - -class Group(TokenConverter): - """ - Converter to return the matched tokens as a list - useful for returning tokens of C{L{ZeroOrMore}} and C{L{OneOrMore}} expressions. - - Example:: - ident = Word(alphas) - num = Word(nums) - term = ident | num - func = ident + Optional(delimitedList(term)) - print(func.parseString("fn a,b,100")) # -> ['fn', 'a', 'b', '100'] - - func = ident + Group(Optional(delimitedList(term))) - print(func.parseString("fn a,b,100")) # -> ['fn', ['a', 'b', '100']] - """ - def __init__( self, expr ): - super(Group,self).__init__( expr ) - self.saveAsList = True - - def postParse( self, instring, loc, tokenlist ): - return [ tokenlist ] - -class Dict(TokenConverter): - """ - Converter to return a repetitive expression as a list, but also as a dictionary. - Each element can also be referenced using the first token in the expression as its key. - Useful for tabular report scraping when the first column can be used as a item key. - - Example:: - data_word = Word(alphas) - label = data_word + FollowedBy(':') - attr_expr = Group(label + Suppress(':') + OneOrMore(data_word).setParseAction(' '.join)) - - text = "shape: SQUARE posn: upper left color: light blue texture: burlap" - attr_expr = (label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join)) - - # print attributes as plain groups - print(OneOrMore(attr_expr).parseString(text).dump()) - - # instead of OneOrMore(expr), parse using Dict(OneOrMore(Group(expr))) - Dict will auto-assign names - result = Dict(OneOrMore(Group(attr_expr))).parseString(text) - print(result.dump()) - - # access named fields as dict entries, or output as dict - print(result['shape']) - print(result.asDict()) - prints:: - ['shape', 'SQUARE', 'posn', 'upper left', 'color', 'light blue', 'texture', 'burlap'] - - [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'light blue'], ['texture', 'burlap']] - - color: light blue - - posn: upper left - - shape: SQUARE - - texture: burlap - SQUARE - {'color': 'light blue', 'posn': 'upper left', 'texture': 'burlap', 'shape': 'SQUARE'} - See more examples at L{ParseResults} of accessing fields by results name. - """ - def __init__( self, expr ): - super(Dict,self).__init__( expr ) - self.saveAsList = True - - def postParse( self, instring, loc, tokenlist ): - for i,tok in enumerate(tokenlist): - if len(tok) == 0: - continue - ikey = tok[0] - if isinstance(ikey,int): - ikey = _ustr(tok[0]).strip() - if len(tok)==1: - tokenlist[ikey] = _ParseResultsWithOffset("",i) - elif len(tok)==2 and not isinstance(tok[1],ParseResults): - tokenlist[ikey] = _ParseResultsWithOffset(tok[1],i) - else: - dictvalue = tok.copy() #ParseResults(i) - del dictvalue[0] - if len(dictvalue)!= 1 or (isinstance(dictvalue,ParseResults) and dictvalue.haskeys()): - tokenlist[ikey] = _ParseResultsWithOffset(dictvalue,i) - else: - tokenlist[ikey] = _ParseResultsWithOffset(dictvalue[0],i) - - if self.resultsName: - return [ tokenlist ] - else: - return tokenlist - - -class Suppress(TokenConverter): - """ - Converter for ignoring the results of a parsed expression. - - Example:: - source = "a, b, c,d" - wd = Word(alphas) - wd_list1 = wd + ZeroOrMore(',' + wd) - print(wd_list1.parseString(source)) - - # often, delimiters that are useful during parsing are just in the - # way afterward - use Suppress to keep them out of the parsed output - wd_list2 = wd + ZeroOrMore(Suppress(',') + wd) - print(wd_list2.parseString(source)) - prints:: - ['a', ',', 'b', ',', 'c', ',', 'd'] - ['a', 'b', 'c', 'd'] - (See also L{delimitedList}.) - """ - def postParse( self, instring, loc, tokenlist ): - return [] - - def suppress( self ): - return self - - -class OnlyOnce(object): - """ - Wrapper for parse actions, to ensure they are only called once. - """ - def __init__(self, methodCall): - self.callable = _trim_arity(methodCall) - self.called = False - def __call__(self,s,l,t): - if not self.called: - results = self.callable(s,l,t) - self.called = True - return results - raise ParseException(s,l,"") - def reset(self): - self.called = False - -def traceParseAction(f): - """ - Decorator for debugging parse actions. - - When the parse action is called, this decorator will print C{">> entering I{method-name}(line:I{current_source_line}, I{parse_location}, I{matched_tokens})".} - When the parse action completes, the decorator will print C{"<<"} followed by the returned value, or any exception that the parse action raised. - - Example:: - wd = Word(alphas) - - @traceParseAction - def remove_duplicate_chars(tokens): - return ''.join(sorted(set(''.join(tokens)))) - - wds = OneOrMore(wd).setParseAction(remove_duplicate_chars) - print(wds.parseString("slkdjs sld sldd sdlf sdljf")) - prints:: - >>entering remove_duplicate_chars(line: 'slkdjs sld sldd sdlf sdljf', 0, (['slkdjs', 'sld', 'sldd', 'sdlf', 'sdljf'], {})) - <<leaving remove_duplicate_chars (ret: 'dfjkls') - ['dfjkls'] - """ - f = _trim_arity(f) - def z(*paArgs): - thisFunc = f.__name__ - s,l,t = paArgs[-3:] - if len(paArgs)>3: - thisFunc = paArgs[0].__class__.__name__ + '.' + thisFunc - sys.stderr.write( ">>entering %s(line: '%s', %d, %r)\n" % (thisFunc,line(l,s),l,t) ) - try: - ret = f(*paArgs) - except Exception as exc: - sys.stderr.write( "<<leaving %s (exception: %s)\n" % (thisFunc,exc) ) - raise - sys.stderr.write( "<<leaving %s (ret: %r)\n" % (thisFunc,ret) ) - return ret - try: - z.__name__ = f.__name__ - except AttributeError: - pass - return z - -# -# global helpers -# -def delimitedList( expr, delim=",", combine=False ): - """ - Helper to define a delimited list of expressions - the delimiter defaults to ','. - By default, the list elements and delimiters can have intervening whitespace, and - comments, but this can be overridden by passing C{combine=True} in the constructor. - If C{combine} is set to C{True}, the matching tokens are returned as a single token - string, with the delimiters included; otherwise, the matching tokens are returned - as a list of tokens, with the delimiters suppressed. - - Example:: - delimitedList(Word(alphas)).parseString("aa,bb,cc") # -> ['aa', 'bb', 'cc'] - delimitedList(Word(hexnums), delim=':', combine=True).parseString("AA:BB:CC:DD:EE") # -> ['AA:BB:CC:DD:EE'] - """ - dlName = _ustr(expr)+" ["+_ustr(delim)+" "+_ustr(expr)+"]..." - if combine: - return Combine( expr + ZeroOrMore( delim + expr ) ).setName(dlName) - else: - return ( expr + ZeroOrMore( Suppress( delim ) + expr ) ).setName(dlName) - -def countedArray( expr, intExpr=None ): - """ - Helper to define a counted list of expressions. - This helper defines a pattern of the form:: - integer expr expr expr... - where the leading integer tells how many expr expressions follow. - The matched tokens returns the array of expr tokens as a list - the leading count token is suppressed. - - If C{intExpr} is specified, it should be a pyparsing expression that produces an integer value. - - Example:: - countedArray(Word(alphas)).parseString('2 ab cd ef') # -> ['ab', 'cd'] - - # in this parser, the leading integer value is given in binary, - # '10' indicating that 2 values are in the array - binaryConstant = Word('01').setParseAction(lambda t: int(t[0], 2)) - countedArray(Word(alphas), intExpr=binaryConstant).parseString('10 ab cd ef') # -> ['ab', 'cd'] - """ - arrayExpr = Forward() - def countFieldParseAction(s,l,t): - n = t[0] - arrayExpr << (n and Group(And([expr]*n)) or Group(empty)) - return [] - if intExpr is None: - intExpr = Word(nums).setParseAction(lambda t:int(t[0])) - else: - intExpr = intExpr.copy() - intExpr.setName("arrayLen") - intExpr.addParseAction(countFieldParseAction, callDuringTry=True) - return ( intExpr + arrayExpr ).setName('(len) ' + _ustr(expr) + '...') - -def _flatten(L): - ret = [] - for i in L: - if isinstance(i,list): - ret.extend(_flatten(i)) - else: - ret.append(i) - return ret - -def matchPreviousLiteral(expr): - """ - Helper to define an expression that is indirectly defined from - the tokens matched in a previous expression, that is, it looks - for a 'repeat' of a previous expression. For example:: - first = Word(nums) - second = matchPreviousLiteral(first) - matchExpr = first + ":" + second - will match C{"1:1"}, but not C{"1:2"}. Because this matches a - previous literal, will also match the leading C{"1:1"} in C{"1:10"}. - If this is not desired, use C{matchPreviousExpr}. - Do I{not} use with packrat parsing enabled. - """ - rep = Forward() - def copyTokenToRepeater(s,l,t): - if t: - if len(t) == 1: - rep << t[0] - else: - # flatten t tokens - tflat = _flatten(t.asList()) - rep << And(Literal(tt) for tt in tflat) - else: - rep << Empty() - expr.addParseAction(copyTokenToRepeater, callDuringTry=True) - rep.setName('(prev) ' + _ustr(expr)) - return rep - -def matchPreviousExpr(expr): - """ - Helper to define an expression that is indirectly defined from - the tokens matched in a previous expression, that is, it looks - for a 'repeat' of a previous expression. For example:: - first = Word(nums) - second = matchPreviousExpr(first) - matchExpr = first + ":" + second - will match C{"1:1"}, but not C{"1:2"}. Because this matches by - expressions, will I{not} match the leading C{"1:1"} in C{"1:10"}; - the expressions are evaluated first, and then compared, so - C{"1"} is compared with C{"10"}. - Do I{not} use with packrat parsing enabled. - """ - rep = Forward() - e2 = expr.copy() - rep <<= e2 - def copyTokenToRepeater(s,l,t): - matchTokens = _flatten(t.asList()) - def mustMatchTheseTokens(s,l,t): - theseTokens = _flatten(t.asList()) - if theseTokens != matchTokens: - raise ParseException("",0,"") - rep.setParseAction( mustMatchTheseTokens, callDuringTry=True ) - expr.addParseAction(copyTokenToRepeater, callDuringTry=True) - rep.setName('(prev) ' + _ustr(expr)) - return rep - -def _escapeRegexRangeChars(s): - #~ escape these chars: ^-] - for c in r"\^-]": - s = s.replace(c,_bslash+c) - s = s.replace("\n",r"\n") - s = s.replace("\t",r"\t") - return _ustr(s) - -def oneOf( strs, caseless=False, useRegex=True ): - """ - Helper to quickly define a set of alternative Literals, and makes sure to do - longest-first testing when there is a conflict, regardless of the input order, - but returns a C{L{MatchFirst}} for best performance. - - Parameters: - - strs - a string of space-delimited literals, or a collection of string literals - - caseless - (default=C{False}) - treat all literals as caseless - - useRegex - (default=C{True}) - as an optimization, will generate a Regex - object; otherwise, will generate a C{MatchFirst} object (if C{caseless=True}, or - if creating a C{Regex} raises an exception) - - Example:: - comp_oper = oneOf("< = > <= >= !=") - var = Word(alphas) - number = Word(nums) - term = var | number - comparison_expr = term + comp_oper + term - print(comparison_expr.searchString("B = 12 AA=23 B<=AA AA>12")) - prints:: - [['B', '=', '12'], ['AA', '=', '23'], ['B', '<=', 'AA'], ['AA', '>', '12']] - """ - if caseless: - isequal = ( lambda a,b: a.upper() == b.upper() ) - masks = ( lambda a,b: b.upper().startswith(a.upper()) ) - parseElementClass = CaselessLiteral - else: - isequal = ( lambda a,b: a == b ) - masks = ( lambda a,b: b.startswith(a) ) - parseElementClass = Literal - - symbols = [] - if isinstance(strs,basestring): - symbols = strs.split() - elif isinstance(strs, Iterable): - symbols = list(strs) - else: - warnings.warn("Invalid argument to oneOf, expected string or iterable", - SyntaxWarning, stacklevel=2) - if not symbols: - return NoMatch() - - i = 0 - while i < len(symbols)-1: - cur = symbols[i] - for j,other in enumerate(symbols[i+1:]): - if ( isequal(other, cur) ): - del symbols[i+j+1] - break - elif ( masks(cur, other) ): - del symbols[i+j+1] - symbols.insert(i,other) - cur = other - break - else: - i += 1 - - if not caseless and useRegex: - #~ print (strs,"->", "|".join( [ _escapeRegexChars(sym) for sym in symbols] )) - try: - if len(symbols)==len("".join(symbols)): - return Regex( "[%s]" % "".join(_escapeRegexRangeChars(sym) for sym in symbols) ).setName(' | '.join(symbols)) - else: - return Regex( "|".join(re.escape(sym) for sym in symbols) ).setName(' | '.join(symbols)) - except Exception: - warnings.warn("Exception creating Regex for oneOf, building MatchFirst", - SyntaxWarning, stacklevel=2) - - - # last resort, just use MatchFirst - return MatchFirst(parseElementClass(sym) for sym in symbols).setName(' | '.join(symbols)) - -def dictOf( key, value ): - """ - Helper to easily and clearly define a dictionary by specifying the respective patterns - for the key and value. Takes care of defining the C{L{Dict}}, C{L{ZeroOrMore}}, and C{L{Group}} tokens - in the proper order. The key pattern can include delimiting markers or punctuation, - as long as they are suppressed, thereby leaving the significant key text. The value - pattern can include named results, so that the C{Dict} results can include named token - fields. - - Example:: - text = "shape: SQUARE posn: upper left color: light blue texture: burlap" - attr_expr = (label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join)) - print(OneOrMore(attr_expr).parseString(text).dump()) - - attr_label = label - attr_value = Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join) - - # similar to Dict, but simpler call format - result = dictOf(attr_label, attr_value).parseString(text) - print(result.dump()) - print(result['shape']) - print(result.shape) # object attribute access works too - print(result.asDict()) - prints:: - [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'light blue'], ['texture', 'burlap']] - - color: light blue - - posn: upper left - - shape: SQUARE - - texture: burlap - SQUARE - SQUARE - {'color': 'light blue', 'shape': 'SQUARE', 'posn': 'upper left', 'texture': 'burlap'} - """ - return Dict( ZeroOrMore( Group ( key + value ) ) ) - -def originalTextFor(expr, asString=True): - """ - Helper to return the original, untokenized text for a given expression. Useful to - restore the parsed fields of an HTML start tag into the raw tag text itself, or to - revert separate tokens with intervening whitespace back to the original matching - input text. By default, returns astring containing the original parsed text. - - If the optional C{asString} argument is passed as C{False}, then the return value is a - C{L{ParseResults}} containing any results names that were originally matched, and a - single token containing the original matched text from the input string. So if - the expression passed to C{L{originalTextFor}} contains expressions with defined - results names, you must set C{asString} to C{False} if you want to preserve those - results name values. - - Example:: - src = "this is test <b> bold <i>text</i> </b> normal text " - for tag in ("b","i"): - opener,closer = makeHTMLTags(tag) - patt = originalTextFor(opener + SkipTo(closer) + closer) - print(patt.searchString(src)[0]) - prints:: - ['<b> bold <i>text</i> </b>'] - ['<i>text</i>'] - """ - locMarker = Empty().setParseAction(lambda s,loc,t: loc) - endlocMarker = locMarker.copy() - endlocMarker.callPreparse = False - matchExpr = locMarker("_original_start") + expr + endlocMarker("_original_end") - if asString: - extractText = lambda s,l,t: s[t._original_start:t._original_end] - else: - def extractText(s,l,t): - t[:] = [s[t.pop('_original_start'):t.pop('_original_end')]] - matchExpr.setParseAction(extractText) - matchExpr.ignoreExprs = expr.ignoreExprs - return matchExpr - -def ungroup(expr): - """ - Helper to undo pyparsing's default grouping of And expressions, even - if all but one are non-empty. - """ - return TokenConverter(expr).setParseAction(lambda t:t[0]) - -def locatedExpr(expr): - """ - Helper to decorate a returned token with its starting and ending locations in the input string. - This helper adds the following results names: - - locn_start = location where matched expression begins - - locn_end = location where matched expression ends - - value = the actual parsed results - - Be careful if the input text contains C{<TAB>} characters, you may want to call - C{L{ParserElement.parseWithTabs}} - - Example:: - wd = Word(alphas) - for match in locatedExpr(wd).searchString("ljsdf123lksdjjf123lkkjj1222"): - print(match) - prints:: - [[0, 'ljsdf', 5]] - [[8, 'lksdjjf', 15]] - [[18, 'lkkjj', 23]] - """ - locator = Empty().setParseAction(lambda s,l,t: l) - return Group(locator("locn_start") + expr("value") + locator.copy().leaveWhitespace()("locn_end")) - - -# convenience constants for positional expressions -empty = Empty().setName("empty") -lineStart = LineStart().setName("lineStart") -lineEnd = LineEnd().setName("lineEnd") -stringStart = StringStart().setName("stringStart") -stringEnd = StringEnd().setName("stringEnd") - -_escapedPunc = Word( _bslash, r"\[]-*.$+^?()~ ", exact=2 ).setParseAction(lambda s,l,t:t[0][1]) -_escapedHexChar = Regex(r"\\0?[xX][0-9a-fA-F]+").setParseAction(lambda s,l,t:unichr(int(t[0].lstrip(r'\0x'),16))) -_escapedOctChar = Regex(r"\\0[0-7]+").setParseAction(lambda s,l,t:unichr(int(t[0][1:],8))) -_singleChar = _escapedPunc | _escapedHexChar | _escapedOctChar | CharsNotIn(r'\]', exact=1) -_charRange = Group(_singleChar + Suppress("-") + _singleChar) -_reBracketExpr = Literal("[") + Optional("^").setResultsName("negate") + Group( OneOrMore( _charRange | _singleChar ) ).setResultsName("body") + "]" - -def srange(s): - r""" - Helper to easily define string ranges for use in Word construction. Borrows - syntax from regexp '[]' string range definitions:: - srange("[0-9]") -> "0123456789" - srange("[a-z]") -> "abcdefghijklmnopqrstuvwxyz" - srange("[a-z$_]") -> "abcdefghijklmnopqrstuvwxyz$_" - The input string must be enclosed in []'s, and the returned string is the expanded - character set joined into a single string. - The values enclosed in the []'s may be: - - a single character - - an escaped character with a leading backslash (such as C{\-} or C{\]}) - - an escaped hex character with a leading C{'\x'} (C{\x21}, which is a C{'!'} character) - (C{\0x##} is also supported for backwards compatibility) - - an escaped octal character with a leading C{'\0'} (C{\041}, which is a C{'!'} character) - - a range of any of the above, separated by a dash (C{'a-z'}, etc.) - - any combination of the above (C{'aeiouy'}, C{'a-zA-Z0-9_$'}, etc.) - """ - _expanded = lambda p: p if not isinstance(p,ParseResults) else ''.join(unichr(c) for c in range(ord(p[0]),ord(p[1])+1)) - try: - return "".join(_expanded(part) for part in _reBracketExpr.parseString(s).body) - except Exception: - return "" - -def matchOnlyAtCol(n): - """ - Helper method for defining parse actions that require matching at a specific - column in the input text. - """ - def verifyCol(strg,locn,toks): - if col(locn,strg) != n: - raise ParseException(strg,locn,"matched token not at column %d" % n) - return verifyCol - -def replaceWith(replStr): - """ - Helper method for common parse actions that simply return a literal value. Especially - useful when used with C{L{transformString<ParserElement.transformString>}()}. - - Example:: - num = Word(nums).setParseAction(lambda toks: int(toks[0])) - na = oneOf("N/A NA").setParseAction(replaceWith(math.nan)) - term = na | num - - OneOrMore(term).parseString("324 234 N/A 234") # -> [324, 234, nan, 234] - """ - return lambda s,l,t: [replStr] - -def removeQuotes(s,l,t): - """ - Helper parse action for removing quotation marks from parsed quoted strings. - - Example:: - # by default, quotation marks are included in parsed results - quotedString.parseString("'Now is the Winter of our Discontent'") # -> ["'Now is the Winter of our Discontent'"] - - # use removeQuotes to strip quotation marks from parsed results - quotedString.setParseAction(removeQuotes) - quotedString.parseString("'Now is the Winter of our Discontent'") # -> ["Now is the Winter of our Discontent"] - """ - return t[0][1:-1] - -def tokenMap(func, *args): - """ - Helper to define a parse action by mapping a function to all elements of a ParseResults list.If any additional - args are passed, they are forwarded to the given function as additional arguments after - the token, as in C{hex_integer = Word(hexnums).setParseAction(tokenMap(int, 16))}, which will convert the - parsed data to an integer using base 16. - - Example (compare the last to example in L{ParserElement.transformString}:: - hex_ints = OneOrMore(Word(hexnums)).setParseAction(tokenMap(int, 16)) - hex_ints.runTests(''' - 00 11 22 aa FF 0a 0d 1a - ''') - - upperword = Word(alphas).setParseAction(tokenMap(str.upper)) - OneOrMore(upperword).runTests(''' - my kingdom for a horse - ''') - - wd = Word(alphas).setParseAction(tokenMap(str.title)) - OneOrMore(wd).setParseAction(' '.join).runTests(''' - now is the winter of our discontent made glorious summer by this sun of york - ''') - prints:: - 00 11 22 aa FF 0a 0d 1a - [0, 17, 34, 170, 255, 10, 13, 26] - - my kingdom for a horse - ['MY', 'KINGDOM', 'FOR', 'A', 'HORSE'] - - now is the winter of our discontent made glorious summer by this sun of york - ['Now Is The Winter Of Our Discontent Made Glorious Summer By This Sun Of York'] - """ - def pa(s,l,t): - return [func(tokn, *args) for tokn in t] - - try: - func_name = getattr(func, '__name__', - getattr(func, '__class__').__name__) - except Exception: - func_name = str(func) - pa.__name__ = func_name - - return pa - -upcaseTokens = tokenMap(lambda t: _ustr(t).upper()) -"""(Deprecated) Helper parse action to convert tokens to upper case. Deprecated in favor of L{pyparsing_common.upcaseTokens}""" - -downcaseTokens = tokenMap(lambda t: _ustr(t).lower()) -"""(Deprecated) Helper parse action to convert tokens to lower case. Deprecated in favor of L{pyparsing_common.downcaseTokens}""" - -def _makeTags(tagStr, xml): - """Internal helper to construct opening and closing tag expressions, given a tag name""" - if isinstance(tagStr,basestring): - resname = tagStr - tagStr = Keyword(tagStr, caseless=not xml) - else: - resname = tagStr.name - - tagAttrName = Word(alphas,alphanums+"_-:") - if (xml): - tagAttrValue = dblQuotedString.copy().setParseAction( removeQuotes ) - openTag = Suppress("<") + tagStr("tag") + \ - Dict(ZeroOrMore(Group( tagAttrName + Suppress("=") + tagAttrValue ))) + \ - Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">") - else: - printablesLessRAbrack = "".join(c for c in printables if c not in ">") - tagAttrValue = quotedString.copy().setParseAction( removeQuotes ) | Word(printablesLessRAbrack) - openTag = Suppress("<") + tagStr("tag") + \ - Dict(ZeroOrMore(Group( tagAttrName.setParseAction(downcaseTokens) + \ - Optional( Suppress("=") + tagAttrValue ) ))) + \ - Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">") - closeTag = Combine(_L("</") + tagStr + ">") - - openTag = openTag.setResultsName("start"+"".join(resname.replace(":"," ").title().split())).setName("<%s>" % resname) - closeTag = closeTag.setResultsName("end"+"".join(resname.replace(":"," ").title().split())).setName("</%s>" % resname) - openTag.tag = resname - closeTag.tag = resname - return openTag, closeTag - -def makeHTMLTags(tagStr): - """ - Helper to construct opening and closing tag expressions for HTML, given a tag name. Matches - tags in either upper or lower case, attributes with namespaces and with quoted or unquoted values. - - Example:: - text = '<td>More info at the <a href="http://pyparsing.wikispaces.com">pyparsing</a> wiki page</td>' - # makeHTMLTags returns pyparsing expressions for the opening and closing tags as a 2-tuple - a,a_end = makeHTMLTags("A") - link_expr = a + SkipTo(a_end)("link_text") + a_end - - for link in link_expr.searchString(text): - # attributes in the <A> tag (like "href" shown here) are also accessible as named results - print(link.link_text, '->', link.href) - prints:: - pyparsing -> http://pyparsing.wikispaces.com - """ - return _makeTags( tagStr, False ) - -def makeXMLTags(tagStr): - """ - Helper to construct opening and closing tag expressions for XML, given a tag name. Matches - tags only in the given upper/lower case. - - Example: similar to L{makeHTMLTags} - """ - return _makeTags( tagStr, True ) - -def withAttribute(*args,**attrDict): - """ - Helper to create a validating parse action to be used with start tags created - with C{L{makeXMLTags}} or C{L{makeHTMLTags}}. Use C{withAttribute} to qualify a starting tag - with a required attribute value, to avoid false matches on common tags such as - C{<TD>} or C{<DIV>}. - - Call C{withAttribute} with a series of attribute names and values. Specify the list - of filter attributes names and values as: - - keyword arguments, as in C{(align="right")}, or - - as an explicit dict with C{**} operator, when an attribute name is also a Python - reserved word, as in C{**{"class":"Customer", "align":"right"}} - - a list of name-value tuples, as in ( ("ns1:class", "Customer"), ("ns2:align","right") ) - For attribute names with a namespace prefix, you must use the second form. Attribute - names are matched insensitive to upper/lower case. - - If just testing for C{class} (with or without a namespace), use C{L{withClass}}. - - To verify that the attribute exists, but without specifying a value, pass - C{withAttribute.ANY_VALUE} as the value. - - Example:: - html = ''' - <div> - Some text - <div type="grid">1 4 0 1 0</div> - <div type="graph">1,3 2,3 1,1</div> - <div>this has no type</div> - </div> - - ''' - div,div_end = makeHTMLTags("div") - - # only match div tag having a type attribute with value "grid" - div_grid = div().setParseAction(withAttribute(type="grid")) - grid_expr = div_grid + SkipTo(div | div_end)("body") - for grid_header in grid_expr.searchString(html): - print(grid_header.body) - - # construct a match with any div tag having a type attribute, regardless of the value - div_any_type = div().setParseAction(withAttribute(type=withAttribute.ANY_VALUE)) - div_expr = div_any_type + SkipTo(div | div_end)("body") - for div_header in div_expr.searchString(html): - print(div_header.body) - prints:: - 1 4 0 1 0 - - 1 4 0 1 0 - 1,3 2,3 1,1 - """ - if args: - attrs = args[:] - else: - attrs = attrDict.items() - attrs = [(k,v) for k,v in attrs] - def pa(s,l,tokens): - for attrName,attrValue in attrs: - if attrName not in tokens: - raise ParseException(s,l,"no matching attribute " + attrName) - if attrValue != withAttribute.ANY_VALUE and tokens[attrName] != attrValue: - raise ParseException(s,l,"attribute '%s' has value '%s', must be '%s'" % - (attrName, tokens[attrName], attrValue)) - return pa -withAttribute.ANY_VALUE = object() - -def withClass(classname, namespace=''): - """ - Simplified version of C{L{withAttribute}} when matching on a div class - made - difficult because C{class} is a reserved word in Python. - - Example:: - html = ''' - <div> - Some text - <div class="grid">1 4 0 1 0</div> - <div class="graph">1,3 2,3 1,1</div> - <div>this &lt;div&gt; has no class</div> - </div> - - ''' - div,div_end = makeHTMLTags("div") - div_grid = div().setParseAction(withClass("grid")) - - grid_expr = div_grid + SkipTo(div | div_end)("body") - for grid_header in grid_expr.searchString(html): - print(grid_header.body) - - div_any_type = div().setParseAction(withClass(withAttribute.ANY_VALUE)) - div_expr = div_any_type + SkipTo(div | div_end)("body") - for div_header in div_expr.searchString(html): - print(div_header.body) - prints:: - 1 4 0 1 0 - - 1 4 0 1 0 - 1,3 2,3 1,1 - """ - classattr = "%s:class" % namespace if namespace else "class" - return withAttribute(**{classattr : classname}) - -opAssoc = _Constants() -opAssoc.LEFT = object() -opAssoc.RIGHT = object() - -def infixNotation( baseExpr, opList, lpar=Suppress('('), rpar=Suppress(')') ): - """ - Helper method for constructing grammars of expressions made up of - operators working in a precedence hierarchy. Operators may be unary or - binary, left- or right-associative. Parse actions can also be attached - to operator expressions. The generated parser will also recognize the use - of parentheses to override operator precedences (see example below). - - Note: if you define a deep operator list, you may see performance issues - when using infixNotation. See L{ParserElement.enablePackrat} for a - mechanism to potentially improve your parser performance. - - Parameters: - - baseExpr - expression representing the most basic element for the nested - - opList - list of tuples, one for each operator precedence level in the - expression grammar; each tuple is of the form - (opExpr, numTerms, rightLeftAssoc, parseAction), where: - - opExpr is the pyparsing expression for the operator; - may also be a string, which will be converted to a Literal; - if numTerms is 3, opExpr is a tuple of two expressions, for the - two operators separating the 3 terms - - numTerms is the number of terms for this operator (must - be 1, 2, or 3) - - rightLeftAssoc is the indicator whether the operator is - right or left associative, using the pyparsing-defined - constants C{opAssoc.RIGHT} and C{opAssoc.LEFT}. - - parseAction is the parse action to be associated with - expressions matching this operator expression (the - parse action tuple member may be omitted); if the parse action - is passed a tuple or list of functions, this is equivalent to - calling C{setParseAction(*fn)} (L{ParserElement.setParseAction}) - - lpar - expression for matching left-parentheses (default=C{Suppress('(')}) - - rpar - expression for matching right-parentheses (default=C{Suppress(')')}) - - Example:: - # simple example of four-function arithmetic with ints and variable names - integer = pyparsing_common.signed_integer - varname = pyparsing_common.identifier - - arith_expr = infixNotation(integer | varname, - [ - ('-', 1, opAssoc.RIGHT), - (oneOf('* /'), 2, opAssoc.LEFT), - (oneOf('+ -'), 2, opAssoc.LEFT), - ]) - - arith_expr.runTests(''' - 5+3*6 - (5+3)*6 - -2--11 - ''', fullDump=False) - prints:: - 5+3*6 - [[5, '+', [3, '*', 6]]] - - (5+3)*6 - [[[5, '+', 3], '*', 6]] - - -2--11 - [[['-', 2], '-', ['-', 11]]] - """ - ret = Forward() - lastExpr = baseExpr | ( lpar + ret + rpar ) - for i,operDef in enumerate(opList): - opExpr,arity,rightLeftAssoc,pa = (operDef + (None,))[:4] - termName = "%s term" % opExpr if arity < 3 else "%s%s term" % opExpr - if arity == 3: - if opExpr is None or len(opExpr) != 2: - raise ValueError("if numterms=3, opExpr must be a tuple or list of two expressions") - opExpr1, opExpr2 = opExpr - thisExpr = Forward().setName(termName) - if rightLeftAssoc == opAssoc.LEFT: - if arity == 1: - matchExpr = FollowedBy(lastExpr + opExpr) + Group( lastExpr + OneOrMore( opExpr ) ) - elif arity == 2: - if opExpr is not None: - matchExpr = FollowedBy(lastExpr + opExpr + lastExpr) + Group( lastExpr + OneOrMore( opExpr + lastExpr ) ) - else: - matchExpr = FollowedBy(lastExpr+lastExpr) + Group( lastExpr + OneOrMore(lastExpr) ) - elif arity == 3: - matchExpr = FollowedBy(lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr) + \ - Group( lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr ) - else: - raise ValueError("operator must be unary (1), binary (2), or ternary (3)") - elif rightLeftAssoc == opAssoc.RIGHT: - if arity == 1: - # try to avoid LR with this extra test - if not isinstance(opExpr, Optional): - opExpr = Optional(opExpr) - matchExpr = FollowedBy(opExpr.expr + thisExpr) + Group( opExpr + thisExpr ) - elif arity == 2: - if opExpr is not None: - matchExpr = FollowedBy(lastExpr + opExpr + thisExpr) + Group( lastExpr + OneOrMore( opExpr + thisExpr ) ) - else: - matchExpr = FollowedBy(lastExpr + thisExpr) + Group( lastExpr + OneOrMore( thisExpr ) ) - elif arity == 3: - matchExpr = FollowedBy(lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr) + \ - Group( lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr ) - else: - raise ValueError("operator must be unary (1), binary (2), or ternary (3)") - else: - raise ValueError("operator must indicate right or left associativity") - if pa: - if isinstance(pa, (tuple, list)): - matchExpr.setParseAction(*pa) - else: - matchExpr.setParseAction(pa) - thisExpr <<= ( matchExpr.setName(termName) | lastExpr ) - lastExpr = thisExpr - ret <<= lastExpr - return ret - -operatorPrecedence = infixNotation -"""(Deprecated) Former name of C{L{infixNotation}}, will be dropped in a future release.""" - -dblQuotedString = Combine(Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*')+'"').setName("string enclosed in double quotes") -sglQuotedString = Combine(Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*")+"'").setName("string enclosed in single quotes") -quotedString = Combine(Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*')+'"'| - Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*")+"'").setName("quotedString using single or double quotes") -unicodeString = Combine(_L('u') + quotedString.copy()).setName("unicode string literal") - -def nestedExpr(opener="(", closer=")", content=None, ignoreExpr=quotedString.copy()): - """ - Helper method for defining nested lists enclosed in opening and closing - delimiters ("(" and ")" are the default). - - Parameters: - - opener - opening character for a nested list (default=C{"("}); can also be a pyparsing expression - - closer - closing character for a nested list (default=C{")"}); can also be a pyparsing expression - - content - expression for items within the nested lists (default=C{None}) - - ignoreExpr - expression for ignoring opening and closing delimiters (default=C{quotedString}) - - If an expression is not provided for the content argument, the nested - expression will capture all whitespace-delimited content between delimiters - as a list of separate values. - - Use the C{ignoreExpr} argument to define expressions that may contain - opening or closing characters that should not be treated as opening - or closing characters for nesting, such as quotedString or a comment - expression. Specify multiple expressions using an C{L{Or}} or C{L{MatchFirst}}. - The default is L{quotedString}, but if no expressions are to be ignored, - then pass C{None} for this argument. - - Example:: - data_type = oneOf("void int short long char float double") - decl_data_type = Combine(data_type + Optional(Word('*'))) - ident = Word(alphas+'_', alphanums+'_') - number = pyparsing_common.number - arg = Group(decl_data_type + ident) - LPAR,RPAR = map(Suppress, "()") - - code_body = nestedExpr('{', '}', ignoreExpr=(quotedString | cStyleComment)) - - c_function = (decl_data_type("type") - + ident("name") - + LPAR + Optional(delimitedList(arg), [])("args") + RPAR - + code_body("body")) - c_function.ignore(cStyleComment) - - source_code = ''' - int is_odd(int x) { - return (x%2); - } - - int dec_to_hex(char hchar) { - if (hchar >= '0' && hchar <= '9') { - return (ord(hchar)-ord('0')); - } else { - return (10+ord(hchar)-ord('A')); - } - } - ''' - for func in c_function.searchString(source_code): - print("%(name)s (%(type)s) args: %(args)s" % func) - - prints:: - is_odd (int) args: [['int', 'x']] - dec_to_hex (int) args: [['char', 'hchar']] - """ - if opener == closer: - raise ValueError("opening and closing strings cannot be the same") - if content is None: - if isinstance(opener,basestring) and isinstance(closer,basestring): - if len(opener) == 1 and len(closer)==1: - if ignoreExpr is not None: - content = (Combine(OneOrMore(~ignoreExpr + - CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS,exact=1)) - ).setParseAction(lambda t:t[0].strip())) - else: - content = (empty.copy()+CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS - ).setParseAction(lambda t:t[0].strip())) - else: - if ignoreExpr is not None: - content = (Combine(OneOrMore(~ignoreExpr + - ~Literal(opener) + ~Literal(closer) + - CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1)) - ).setParseAction(lambda t:t[0].strip())) - else: - content = (Combine(OneOrMore(~Literal(opener) + ~Literal(closer) + - CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1)) - ).setParseAction(lambda t:t[0].strip())) - else: - raise ValueError("opening and closing arguments must be strings if no content expression is given") - ret = Forward() - if ignoreExpr is not None: - ret <<= Group( Suppress(opener) + ZeroOrMore( ignoreExpr | ret | content ) + Suppress(closer) ) - else: - ret <<= Group( Suppress(opener) + ZeroOrMore( ret | content ) + Suppress(closer) ) - ret.setName('nested %s%s expression' % (opener,closer)) - return ret - -def indentedBlock(blockStatementExpr, indentStack, indent=True): - """ - Helper method for defining space-delimited indentation blocks, such as - those used to define block statements in Python source code. - - Parameters: - - blockStatementExpr - expression defining syntax of statement that - is repeated within the indented block - - indentStack - list created by caller to manage indentation stack - (multiple statementWithIndentedBlock expressions within a single grammar - should share a common indentStack) - - indent - boolean indicating whether block must be indented beyond the - the current level; set to False for block of left-most statements - (default=C{True}) - - A valid block must contain at least one C{blockStatement}. - - Example:: - data = ''' - def A(z): - A1 - B = 100 - G = A2 - A2 - A3 - B - def BB(a,b,c): - BB1 - def BBA(): - bba1 - bba2 - bba3 - C - D - def spam(x,y): - def eggs(z): - pass - ''' - - - indentStack = [1] - stmt = Forward() - - identifier = Word(alphas, alphanums) - funcDecl = ("def" + identifier + Group( "(" + Optional( delimitedList(identifier) ) + ")" ) + ":") - func_body = indentedBlock(stmt, indentStack) - funcDef = Group( funcDecl + func_body ) - - rvalue = Forward() - funcCall = Group(identifier + "(" + Optional(delimitedList(rvalue)) + ")") - rvalue << (funcCall | identifier | Word(nums)) - assignment = Group(identifier + "=" + rvalue) - stmt << ( funcDef | assignment | identifier ) - - module_body = OneOrMore(stmt) - - parseTree = module_body.parseString(data) - parseTree.pprint() - prints:: - [['def', - 'A', - ['(', 'z', ')'], - ':', - [['A1'], [['B', '=', '100']], [['G', '=', 'A2']], ['A2'], ['A3']]], - 'B', - ['def', - 'BB', - ['(', 'a', 'b', 'c', ')'], - ':', - [['BB1'], [['def', 'BBA', ['(', ')'], ':', [['bba1'], ['bba2'], ['bba3']]]]]], - 'C', - 'D', - ['def', - 'spam', - ['(', 'x', 'y', ')'], - ':', - [[['def', 'eggs', ['(', 'z', ')'], ':', [['pass']]]]]]] - """ - def checkPeerIndent(s,l,t): - if l >= len(s): return - curCol = col(l,s) - if curCol != indentStack[-1]: - if curCol > indentStack[-1]: - raise ParseFatalException(s,l,"illegal nesting") - raise ParseException(s,l,"not a peer entry") - - def checkSubIndent(s,l,t): - curCol = col(l,s) - if curCol > indentStack[-1]: - indentStack.append( curCol ) - else: - raise ParseException(s,l,"not a subentry") - - def checkUnindent(s,l,t): - if l >= len(s): return - curCol = col(l,s) - if not(indentStack and curCol < indentStack[-1] and curCol <= indentStack[-2]): - raise ParseException(s,l,"not an unindent") - indentStack.pop() - - NL = OneOrMore(LineEnd().setWhitespaceChars("\t ").suppress()) - INDENT = (Empty() + Empty().setParseAction(checkSubIndent)).setName('INDENT') - PEER = Empty().setParseAction(checkPeerIndent).setName('') - UNDENT = Empty().setParseAction(checkUnindent).setName('UNINDENT') - if indent: - smExpr = Group( Optional(NL) + - #~ FollowedBy(blockStatementExpr) + - INDENT + (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) + UNDENT) - else: - smExpr = Group( Optional(NL) + - (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) ) - blockStatementExpr.ignore(_bslash + LineEnd()) - return smExpr.setName('indented block') - -alphas8bit = srange(r"[\0xc0-\0xd6\0xd8-\0xf6\0xf8-\0xff]") -punc8bit = srange(r"[\0xa1-\0xbf\0xd7\0xf7]") - -anyOpenTag,anyCloseTag = makeHTMLTags(Word(alphas,alphanums+"_:").setName('any tag')) -_htmlEntityMap = dict(zip("gt lt amp nbsp quot apos".split(),'><& "\'')) -commonHTMLEntity = Regex('&(?P<entity>' + '|'.join(_htmlEntityMap.keys()) +");").setName("common HTML entity") -def replaceHTMLEntity(t): - """Helper parser action to replace common HTML entities with their special characters""" - return _htmlEntityMap.get(t.entity) - -# it's easy to get these comment structures wrong - they're very common, so may as well make them available -cStyleComment = Combine(Regex(r"/\*(?:[^*]|\*(?!/))*") + '*/').setName("C style comment") -"Comment of the form C{/* ... */}" - -htmlComment = Regex(r"<!--[\s\S]*?-->").setName("HTML comment") -"Comment of the form C{<!-- ... -->}" - -restOfLine = Regex(r".*").leaveWhitespace().setName("rest of line") -dblSlashComment = Regex(r"//(?:\\\n|[^\n])*").setName("// comment") -"Comment of the form C{// ... (to end of line)}" - -cppStyleComment = Combine(Regex(r"/\*(?:[^*]|\*(?!/))*") + '*/'| dblSlashComment).setName("C++ style comment") -"Comment of either form C{L{cStyleComment}} or C{L{dblSlashComment}}" - -javaStyleComment = cppStyleComment -"Same as C{L{cppStyleComment}}" - -pythonStyleComment = Regex(r"#.*").setName("Python style comment") -"Comment of the form C{# ... (to end of line)}" - -_commasepitem = Combine(OneOrMore(Word(printables, excludeChars=',') + - Optional( Word(" \t") + - ~Literal(",") + ~LineEnd() ) ) ).streamline().setName("commaItem") -commaSeparatedList = delimitedList( Optional( quotedString.copy() | _commasepitem, default="") ).setName("commaSeparatedList") -"""(Deprecated) Predefined expression of 1 or more printable words or quoted strings, separated by commas. - This expression is deprecated in favor of L{pyparsing_common.comma_separated_list}.""" - -# some other useful expressions - using lower-case class name since we are really using this as a namespace -class pyparsing_common: - """ - Here are some common low-level expressions that may be useful in jump-starting parser development: - - numeric forms (L{integers<integer>}, L{reals<real>}, L{scientific notation<sci_real>}) - - common L{programming identifiers<identifier>} - - network addresses (L{MAC<mac_address>}, L{IPv4<ipv4_address>}, L{IPv6<ipv6_address>}) - - ISO8601 L{dates<iso8601_date>} and L{datetime<iso8601_datetime>} - - L{UUID<uuid>} - - L{comma-separated list<comma_separated_list>} - Parse actions: - - C{L{convertToInteger}} - - C{L{convertToFloat}} - - C{L{convertToDate}} - - C{L{convertToDatetime}} - - C{L{stripHTMLTags}} - - C{L{upcaseTokens}} - - C{L{downcaseTokens}} - - Example:: - pyparsing_common.number.runTests(''' - # any int or real number, returned as the appropriate type - 100 - -100 - +100 - 3.14159 - 6.02e23 - 1e-12 - ''') - - pyparsing_common.fnumber.runTests(''' - # any int or real number, returned as float - 100 - -100 - +100 - 3.14159 - 6.02e23 - 1e-12 - ''') - - pyparsing_common.hex_integer.runTests(''' - # hex numbers - 100 - FF - ''') - - pyparsing_common.fraction.runTests(''' - # fractions - 1/2 - -3/4 - ''') - - pyparsing_common.mixed_integer.runTests(''' - # mixed fractions - 1 - 1/2 - -3/4 - 1-3/4 - ''') - - import uuid - pyparsing_common.uuid.setParseAction(tokenMap(uuid.UUID)) - pyparsing_common.uuid.runTests(''' - # uuid - 12345678-1234-5678-1234-567812345678 - ''') - prints:: - # any int or real number, returned as the appropriate type - 100 - [100] - - -100 - [-100] - - +100 - [100] - - 3.14159 - [3.14159] - - 6.02e23 - [6.02e+23] - - 1e-12 - [1e-12] - - # any int or real number, returned as float - 100 - [100.0] - - -100 - [-100.0] - - +100 - [100.0] - - 3.14159 - [3.14159] - - 6.02e23 - [6.02e+23] - - 1e-12 - [1e-12] - - # hex numbers - 100 - [256] - - FF - [255] - - # fractions - 1/2 - [0.5] - - -3/4 - [-0.75] - - # mixed fractions - 1 - [1] - - 1/2 - [0.5] - - -3/4 - [-0.75] - - 1-3/4 - [1.75] - - # uuid - 12345678-1234-5678-1234-567812345678 - [UUID('12345678-1234-5678-1234-567812345678')] - """ - - convertToInteger = tokenMap(int) - """ - Parse action for converting parsed integers to Python int - """ - - convertToFloat = tokenMap(float) - """ - Parse action for converting parsed numbers to Python float - """ - - integer = Word(nums).setName("integer").setParseAction(convertToInteger) - """expression that parses an unsigned integer, returns an int""" - - hex_integer = Word(hexnums).setName("hex integer").setParseAction(tokenMap(int,16)) - """expression that parses a hexadecimal integer, returns an int""" - - signed_integer = Regex(r'[+-]?\d+').setName("signed integer").setParseAction(convertToInteger) - """expression that parses an integer with optional leading sign, returns an int""" - - fraction = (signed_integer().setParseAction(convertToFloat) + '/' + signed_integer().setParseAction(convertToFloat)).setName("fraction") - """fractional expression of an integer divided by an integer, returns a float""" - fraction.addParseAction(lambda t: t[0]/t[-1]) - - mixed_integer = (fraction | signed_integer + Optional(Optional('-').suppress() + fraction)).setName("fraction or mixed integer-fraction") - """mixed integer of the form 'integer - fraction', with optional leading integer, returns float""" - mixed_integer.addParseAction(sum) - - real = Regex(r'[+-]?\d+\.\d*').setName("real number").setParseAction(convertToFloat) - """expression that parses a floating point number and returns a float""" - - sci_real = Regex(r'[+-]?\d+([eE][+-]?\d+|\.\d*([eE][+-]?\d+)?)').setName("real number with scientific notation").setParseAction(convertToFloat) - """expression that parses a floating point number with optional scientific notation and returns a float""" - - # streamlining this expression makes the docs nicer-looking - number = (sci_real | real | signed_integer).streamline() - """any numeric expression, returns the corresponding Python type""" - - fnumber = Regex(r'[+-]?\d+\.?\d*([eE][+-]?\d+)?').setName("fnumber").setParseAction(convertToFloat) - """any int or real number, returned as float""" - - identifier = Word(alphas+'_', alphanums+'_').setName("identifier") - """typical code identifier (leading alpha or '_', followed by 0 or more alphas, nums, or '_')""" - - ipv4_address = Regex(r'(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})(\.(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})){3}').setName("IPv4 address") - "IPv4 address (C{0.0.0.0 - 255.255.255.255})" - - _ipv6_part = Regex(r'[0-9a-fA-F]{1,4}').setName("hex_integer") - _full_ipv6_address = (_ipv6_part + (':' + _ipv6_part)*7).setName("full IPv6 address") - _short_ipv6_address = (Optional(_ipv6_part + (':' + _ipv6_part)*(0,6)) + "::" + Optional(_ipv6_part + (':' + _ipv6_part)*(0,6))).setName("short IPv6 address") - _short_ipv6_address.addCondition(lambda t: sum(1 for tt in t if pyparsing_common._ipv6_part.matches(tt)) < 8) - _mixed_ipv6_address = ("::ffff:" + ipv4_address).setName("mixed IPv6 address") - ipv6_address = Combine((_full_ipv6_address | _mixed_ipv6_address | _short_ipv6_address).setName("IPv6 address")).setName("IPv6 address") - "IPv6 address (long, short, or mixed form)" - - mac_address = Regex(r'[0-9a-fA-F]{2}([:.-])[0-9a-fA-F]{2}(?:\1[0-9a-fA-F]{2}){4}').setName("MAC address") - "MAC address xx:xx:xx:xx:xx (may also have '-' or '.' delimiters)" - - @staticmethod - def convertToDate(fmt="%Y-%m-%d"): - """ - Helper to create a parse action for converting parsed date string to Python datetime.date - - Params - - - fmt - format to be passed to datetime.strptime (default=C{"%Y-%m-%d"}) - - Example:: - date_expr = pyparsing_common.iso8601_date.copy() - date_expr.setParseAction(pyparsing_common.convertToDate()) - print(date_expr.parseString("1999-12-31")) - prints:: - [datetime.date(1999, 12, 31)] - """ - def cvt_fn(s,l,t): - try: - return datetime.strptime(t[0], fmt).date() - except ValueError as ve: - raise ParseException(s, l, str(ve)) - return cvt_fn - - @staticmethod - def convertToDatetime(fmt="%Y-%m-%dT%H:%M:%S.%f"): - """ - Helper to create a parse action for converting parsed datetime string to Python datetime.datetime - - Params - - - fmt - format to be passed to datetime.strptime (default=C{"%Y-%m-%dT%H:%M:%S.%f"}) - - Example:: - dt_expr = pyparsing_common.iso8601_datetime.copy() - dt_expr.setParseAction(pyparsing_common.convertToDatetime()) - print(dt_expr.parseString("1999-12-31T23:59:59.999")) - prints:: - [datetime.datetime(1999, 12, 31, 23, 59, 59, 999000)] - """ - def cvt_fn(s,l,t): - try: - return datetime.strptime(t[0], fmt) - except ValueError as ve: - raise ParseException(s, l, str(ve)) - return cvt_fn - - iso8601_date = Regex(r'(?P<year>\d{4})(?:-(?P<month>\d\d)(?:-(?P<day>\d\d))?)?').setName("ISO8601 date") - "ISO8601 date (C{yyyy-mm-dd})" - - iso8601_datetime = Regex(r'(?P<year>\d{4})-(?P<month>\d\d)-(?P<day>\d\d)[T ](?P<hour>\d\d):(?P<minute>\d\d)(:(?P<second>\d\d(\.\d*)?)?)?(?P<tz>Z|[+-]\d\d:?\d\d)?').setName("ISO8601 datetime") - "ISO8601 datetime (C{yyyy-mm-ddThh:mm:ss.s(Z|+-00:00)}) - trailing seconds, milliseconds, and timezone optional; accepts separating C{'T'} or C{' '}" - - uuid = Regex(r'[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}').setName("UUID") - "UUID (C{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx})" - - _html_stripper = anyOpenTag.suppress() | anyCloseTag.suppress() - @staticmethod - def stripHTMLTags(s, l, tokens): - """ - Parse action to remove HTML tags from web page HTML source - - Example:: - # strip HTML links from normal text - text = '<td>More info at the <a href="http://pyparsing.wikispaces.com">pyparsing</a> wiki page</td>' - td,td_end = makeHTMLTags("TD") - table_text = td + SkipTo(td_end).setParseAction(pyparsing_common.stripHTMLTags)("body") + td_end - - print(table_text.parseString(text).body) # -> 'More info at the pyparsing wiki page' - """ - return pyparsing_common._html_stripper.transformString(tokens[0]) - - _commasepitem = Combine(OneOrMore(~Literal(",") + ~LineEnd() + Word(printables, excludeChars=',') - + Optional( White(" \t") ) ) ).streamline().setName("commaItem") - comma_separated_list = delimitedList( Optional( quotedString.copy() | _commasepitem, default="") ).setName("comma separated list") - """Predefined expression of 1 or more printable words or quoted strings, separated by commas.""" - - upcaseTokens = staticmethod(tokenMap(lambda t: _ustr(t).upper())) - """Parse action to convert tokens to upper case.""" - - downcaseTokens = staticmethod(tokenMap(lambda t: _ustr(t).lower())) - """Parse action to convert tokens to lower case.""" - - -if __name__ == "__main__": - - selectToken = CaselessLiteral("select") - fromToken = CaselessLiteral("from") - - ident = Word(alphas, alphanums + "_$") - - columnName = delimitedList(ident, ".", combine=True).setParseAction(upcaseTokens) - columnNameList = Group(delimitedList(columnName)).setName("columns") - columnSpec = ('*' | columnNameList) - - tableName = delimitedList(ident, ".", combine=True).setParseAction(upcaseTokens) - tableNameList = Group(delimitedList(tableName)).setName("tables") - - simpleSQL = selectToken("command") + columnSpec("columns") + fromToken + tableNameList("tables") - - # demo runTests method, including embedded comments in test string - simpleSQL.runTests(""" - # '*' as column list and dotted table name - select * from SYS.XYZZY - - # caseless match on "SELECT", and casts back to "select" - SELECT * from XYZZY, ABC - - # list of column names, and mixed case SELECT keyword - Select AA,BB,CC from Sys.dual - - # multiple tables - Select A, B, C from Sys.dual, Table2 - - # invalid SELECT keyword - should fail - Xelect A, B, C from Sys.dual - - # incomplete command - should fail - Select - - # invalid column name - should fail - Select ^^^ frox Sys.dual - - """) - - pyparsing_common.number.runTests(""" - 100 - -100 - +100 - 3.14159 - 6.02e23 - 1e-12 - """) - - # any int or real number, returned as float - pyparsing_common.fnumber.runTests(""" - 100 - -100 - +100 - 3.14159 - 6.02e23 - 1e-12 - """) - - pyparsing_common.hex_integer.runTests(""" - 100 - FF - """) - - import uuid - pyparsing_common.uuid.setParseAction(tokenMap(uuid.UUID)) - pyparsing_common.uuid.runTests(""" - 12345678-1234-5678-1234-567812345678 - """) diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/six.py b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/six.py deleted file mode 100644 index 190c023..0000000 --- a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/six.py +++ /dev/null @@ -1,868 +0,0 @@ -"""Utilities for writing code that runs on Python 2 and 3""" - -# Copyright (c) 2010-2015 Benjamin Peterson -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -from __future__ import absolute_import - -import functools -import itertools -import operator -import sys -import types - -__author__ = "Benjamin Peterson <benjamin@python.org>" -__version__ = "1.10.0" - - -# Useful for very coarse version differentiation. -PY2 = sys.version_info[0] == 2 -PY3 = sys.version_info[0] == 3 -PY34 = sys.version_info[0:2] >= (3, 4) - -if PY3: - string_types = str, - integer_types = int, - class_types = type, - text_type = str - binary_type = bytes - - MAXSIZE = sys.maxsize -else: - string_types = basestring, - integer_types = (int, long) - class_types = (type, types.ClassType) - text_type = unicode - binary_type = str - - if sys.platform.startswith("java"): - # Jython always uses 32 bits. - MAXSIZE = int((1 << 31) - 1) - else: - # It's possible to have sizeof(long) != sizeof(Py_ssize_t). - class X(object): - - def __len__(self): - return 1 << 31 - try: - len(X()) - except OverflowError: - # 32-bit - MAXSIZE = int((1 << 31) - 1) - else: - # 64-bit - MAXSIZE = int((1 << 63) - 1) - del X - - -def _add_doc(func, doc): - """Add documentation to a function.""" - func.__doc__ = doc - - -def _import_module(name): - """Import module, returning the module after the last dot.""" - __import__(name) - return sys.modules[name] - - -class _LazyDescr(object): - - def __init__(self, name): - self.name = name - - def __get__(self, obj, tp): - result = self._resolve() - setattr(obj, self.name, result) # Invokes __set__. - try: - # This is a bit ugly, but it avoids running this again by - # removing this descriptor. - delattr(obj.__class__, self.name) - except AttributeError: - pass - return result - - -class MovedModule(_LazyDescr): - - def __init__(self, name, old, new=None): - super(MovedModule, self).__init__(name) - if PY3: - if new is None: - new = name - self.mod = new - else: - self.mod = old - - def _resolve(self): - return _import_module(self.mod) - - def __getattr__(self, attr): - _module = self._resolve() - value = getattr(_module, attr) - setattr(self, attr, value) - return value - - -class _LazyModule(types.ModuleType): - - def __init__(self, name): - super(_LazyModule, self).__init__(name) - self.__doc__ = self.__class__.__doc__ - - def __dir__(self): - attrs = ["__doc__", "__name__"] - attrs += [attr.name for attr in self._moved_attributes] - return attrs - - # Subclasses should override this - _moved_attributes = [] - - -class MovedAttribute(_LazyDescr): - - def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None): - super(MovedAttribute, self).__init__(name) - if PY3: - if new_mod is None: - new_mod = name - self.mod = new_mod - if new_attr is None: - if old_attr is None: - new_attr = name - else: - new_attr = old_attr - self.attr = new_attr - else: - self.mod = old_mod - if old_attr is None: - old_attr = name - self.attr = old_attr - - def _resolve(self): - module = _import_module(self.mod) - return getattr(module, self.attr) - - -class _SixMetaPathImporter(object): - - """ - A meta path importer to import six.moves and its submodules. - - This class implements a PEP302 finder and loader. It should be compatible - with Python 2.5 and all existing versions of Python3 - """ - - def __init__(self, six_module_name): - self.name = six_module_name - self.known_modules = {} - - def _add_module(self, mod, *fullnames): - for fullname in fullnames: - self.known_modules[self.name + "." + fullname] = mod - - def _get_module(self, fullname): - return self.known_modules[self.name + "." + fullname] - - def find_module(self, fullname, path=None): - if fullname in self.known_modules: - return self - return None - - def __get_module(self, fullname): - try: - return self.known_modules[fullname] - except KeyError: - raise ImportError("This loader does not know module " + fullname) - - def load_module(self, fullname): - try: - # in case of a reload - return sys.modules[fullname] - except KeyError: - pass - mod = self.__get_module(fullname) - if isinstance(mod, MovedModule): - mod = mod._resolve() - else: - mod.__loader__ = self - sys.modules[fullname] = mod - return mod - - def is_package(self, fullname): - """ - Return true, if the named module is a package. - - We need this method to get correct spec objects with - Python 3.4 (see PEP451) - """ - return hasattr(self.__get_module(fullname), "__path__") - - def get_code(self, fullname): - """Return None - - Required, if is_package is implemented""" - self.__get_module(fullname) # eventually raises ImportError - return None - get_source = get_code # same as get_code - -_importer = _SixMetaPathImporter(__name__) - - -class _MovedItems(_LazyModule): - - """Lazy loading of moved objects""" - __path__ = [] # mark as package - - -_moved_attributes = [ - MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"), - MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"), - MovedAttribute("filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"), - MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"), - MovedAttribute("intern", "__builtin__", "sys"), - MovedAttribute("map", "itertools", "builtins", "imap", "map"), - MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"), - MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"), - MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"), - MovedAttribute("reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload"), - MovedAttribute("reduce", "__builtin__", "functools"), - MovedAttribute("shlex_quote", "pipes", "shlex", "quote"), - MovedAttribute("StringIO", "StringIO", "io"), - MovedAttribute("UserDict", "UserDict", "collections"), - MovedAttribute("UserList", "UserList", "collections"), - MovedAttribute("UserString", "UserString", "collections"), - MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"), - MovedAttribute("zip", "itertools", "builtins", "izip", "zip"), - MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"), - MovedModule("builtins", "__builtin__"), - MovedModule("configparser", "ConfigParser"), - MovedModule("copyreg", "copy_reg"), - MovedModule("dbm_gnu", "gdbm", "dbm.gnu"), - MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread"), - MovedModule("http_cookiejar", "cookielib", "http.cookiejar"), - MovedModule("http_cookies", "Cookie", "http.cookies"), - MovedModule("html_entities", "htmlentitydefs", "html.entities"), - MovedModule("html_parser", "HTMLParser", "html.parser"), - MovedModule("http_client", "httplib", "http.client"), - MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"), - MovedModule("email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart"), - MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"), - MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"), - MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"), - MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"), - MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"), - MovedModule("cPickle", "cPickle", "pickle"), - MovedModule("queue", "Queue"), - MovedModule("reprlib", "repr"), - MovedModule("socketserver", "SocketServer"), - MovedModule("_thread", "thread", "_thread"), - MovedModule("tkinter", "Tkinter"), - MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"), - MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"), - MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"), - MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"), - MovedModule("tkinter_tix", "Tix", "tkinter.tix"), - MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"), - MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"), - MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"), - MovedModule("tkinter_colorchooser", "tkColorChooser", - "tkinter.colorchooser"), - MovedModule("tkinter_commondialog", "tkCommonDialog", - "tkinter.commondialog"), - MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"), - MovedModule("tkinter_font", "tkFont", "tkinter.font"), - MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"), - MovedModule("tkinter_tksimpledialog", "tkSimpleDialog", - "tkinter.simpledialog"), - MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"), - MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"), - MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"), - MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"), - MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"), - MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"), -] -# Add windows specific modules. -if sys.platform == "win32": - _moved_attributes += [ - MovedModule("winreg", "_winreg"), - ] - -for attr in _moved_attributes: - setattr(_MovedItems, attr.name, attr) - if isinstance(attr, MovedModule): - _importer._add_module(attr, "moves." + attr.name) -del attr - -_MovedItems._moved_attributes = _moved_attributes - -moves = _MovedItems(__name__ + ".moves") -_importer._add_module(moves, "moves") - - -class Module_six_moves_urllib_parse(_LazyModule): - - """Lazy loading of moved objects in six.moves.urllib_parse""" - - -_urllib_parse_moved_attributes = [ - MovedAttribute("ParseResult", "urlparse", "urllib.parse"), - MovedAttribute("SplitResult", "urlparse", "urllib.parse"), - MovedAttribute("parse_qs", "urlparse", "urllib.parse"), - MovedAttribute("parse_qsl", "urlparse", "urllib.parse"), - MovedAttribute("urldefrag", "urlparse", "urllib.parse"), - MovedAttribute("urljoin", "urlparse", "urllib.parse"), - MovedAttribute("urlparse", "urlparse", "urllib.parse"), - MovedAttribute("urlsplit", "urlparse", "urllib.parse"), - MovedAttribute("urlunparse", "urlparse", "urllib.parse"), - MovedAttribute("urlunsplit", "urlparse", "urllib.parse"), - MovedAttribute("quote", "urllib", "urllib.parse"), - MovedAttribute("quote_plus", "urllib", "urllib.parse"), - MovedAttribute("unquote", "urllib", "urllib.parse"), - MovedAttribute("unquote_plus", "urllib", "urllib.parse"), - MovedAttribute("urlencode", "urllib", "urllib.parse"), - MovedAttribute("splitquery", "urllib", "urllib.parse"), - MovedAttribute("splittag", "urllib", "urllib.parse"), - MovedAttribute("splituser", "urllib", "urllib.parse"), - MovedAttribute("uses_fragment", "urlparse", "urllib.parse"), - MovedAttribute("uses_netloc", "urlparse", "urllib.parse"), - MovedAttribute("uses_params", "urlparse", "urllib.parse"), - MovedAttribute("uses_query", "urlparse", "urllib.parse"), - MovedAttribute("uses_relative", "urlparse", "urllib.parse"), -] -for attr in _urllib_parse_moved_attributes: - setattr(Module_six_moves_urllib_parse, attr.name, attr) -del attr - -Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes - -_importer._add_module(Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"), - "moves.urllib_parse", "moves.urllib.parse") - - -class Module_six_moves_urllib_error(_LazyModule): - - """Lazy loading of moved objects in six.moves.urllib_error""" - - -_urllib_error_moved_attributes = [ - MovedAttribute("URLError", "urllib2", "urllib.error"), - MovedAttribute("HTTPError", "urllib2", "urllib.error"), - MovedAttribute("ContentTooShortError", "urllib", "urllib.error"), -] -for attr in _urllib_error_moved_attributes: - setattr(Module_six_moves_urllib_error, attr.name, attr) -del attr - -Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes - -_importer._add_module(Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"), - "moves.urllib_error", "moves.urllib.error") - - -class Module_six_moves_urllib_request(_LazyModule): - - """Lazy loading of moved objects in six.moves.urllib_request""" - - -_urllib_request_moved_attributes = [ - MovedAttribute("urlopen", "urllib2", "urllib.request"), - MovedAttribute("install_opener", "urllib2", "urllib.request"), - MovedAttribute("build_opener", "urllib2", "urllib.request"), - MovedAttribute("pathname2url", "urllib", "urllib.request"), - MovedAttribute("url2pathname", "urllib", "urllib.request"), - MovedAttribute("getproxies", "urllib", "urllib.request"), - MovedAttribute("Request", "urllib2", "urllib.request"), - MovedAttribute("OpenerDirector", "urllib2", "urllib.request"), - MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"), - MovedAttribute("ProxyHandler", "urllib2", "urllib.request"), - MovedAttribute("BaseHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"), - MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"), - MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"), - MovedAttribute("FileHandler", "urllib2", "urllib.request"), - MovedAttribute("FTPHandler", "urllib2", "urllib.request"), - MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"), - MovedAttribute("UnknownHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"), - MovedAttribute("urlretrieve", "urllib", "urllib.request"), - MovedAttribute("urlcleanup", "urllib", "urllib.request"), - MovedAttribute("URLopener", "urllib", "urllib.request"), - MovedAttribute("FancyURLopener", "urllib", "urllib.request"), - MovedAttribute("proxy_bypass", "urllib", "urllib.request"), -] -for attr in _urllib_request_moved_attributes: - setattr(Module_six_moves_urllib_request, attr.name, attr) -del attr - -Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes - -_importer._add_module(Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"), - "moves.urllib_request", "moves.urllib.request") - - -class Module_six_moves_urllib_response(_LazyModule): - - """Lazy loading of moved objects in six.moves.urllib_response""" - - -_urllib_response_moved_attributes = [ - MovedAttribute("addbase", "urllib", "urllib.response"), - MovedAttribute("addclosehook", "urllib", "urllib.response"), - MovedAttribute("addinfo", "urllib", "urllib.response"), - MovedAttribute("addinfourl", "urllib", "urllib.response"), -] -for attr in _urllib_response_moved_attributes: - setattr(Module_six_moves_urllib_response, attr.name, attr) -del attr - -Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes - -_importer._add_module(Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"), - "moves.urllib_response", "moves.urllib.response") - - -class Module_six_moves_urllib_robotparser(_LazyModule): - - """Lazy loading of moved objects in six.moves.urllib_robotparser""" - - -_urllib_robotparser_moved_attributes = [ - MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"), -] -for attr in _urllib_robotparser_moved_attributes: - setattr(Module_six_moves_urllib_robotparser, attr.name, attr) -del attr - -Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes - -_importer._add_module(Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"), - "moves.urllib_robotparser", "moves.urllib.robotparser") - - -class Module_six_moves_urllib(types.ModuleType): - - """Create a six.moves.urllib namespace that resembles the Python 3 namespace""" - __path__ = [] # mark as package - parse = _importer._get_module("moves.urllib_parse") - error = _importer._get_module("moves.urllib_error") - request = _importer._get_module("moves.urllib_request") - response = _importer._get_module("moves.urllib_response") - robotparser = _importer._get_module("moves.urllib_robotparser") - - def __dir__(self): - return ['parse', 'error', 'request', 'response', 'robotparser'] - -_importer._add_module(Module_six_moves_urllib(__name__ + ".moves.urllib"), - "moves.urllib") - - -def add_move(move): - """Add an item to six.moves.""" - setattr(_MovedItems, move.name, move) - - -def remove_move(name): - """Remove item from six.moves.""" - try: - delattr(_MovedItems, name) - except AttributeError: - try: - del moves.__dict__[name] - except KeyError: - raise AttributeError("no such move, %r" % (name,)) - - -if PY3: - _meth_func = "__func__" - _meth_self = "__self__" - - _func_closure = "__closure__" - _func_code = "__code__" - _func_defaults = "__defaults__" - _func_globals = "__globals__" -else: - _meth_func = "im_func" - _meth_self = "im_self" - - _func_closure = "func_closure" - _func_code = "func_code" - _func_defaults = "func_defaults" - _func_globals = "func_globals" - - -try: - advance_iterator = next -except NameError: - def advance_iterator(it): - return it.next() -next = advance_iterator - - -try: - callable = callable -except NameError: - def callable(obj): - return any("__call__" in klass.__dict__ for klass in type(obj).__mro__) - - -if PY3: - def get_unbound_function(unbound): - return unbound - - create_bound_method = types.MethodType - - def create_unbound_method(func, cls): - return func - - Iterator = object -else: - def get_unbound_function(unbound): - return unbound.im_func - - def create_bound_method(func, obj): - return types.MethodType(func, obj, obj.__class__) - - def create_unbound_method(func, cls): - return types.MethodType(func, None, cls) - - class Iterator(object): - - def next(self): - return type(self).__next__(self) - - callable = callable -_add_doc(get_unbound_function, - """Get the function out of a possibly unbound function""") - - -get_method_function = operator.attrgetter(_meth_func) -get_method_self = operator.attrgetter(_meth_self) -get_function_closure = operator.attrgetter(_func_closure) -get_function_code = operator.attrgetter(_func_code) -get_function_defaults = operator.attrgetter(_func_defaults) -get_function_globals = operator.attrgetter(_func_globals) - - -if PY3: - def iterkeys(d, **kw): - return iter(d.keys(**kw)) - - def itervalues(d, **kw): - return iter(d.values(**kw)) - - def iteritems(d, **kw): - return iter(d.items(**kw)) - - def iterlists(d, **kw): - return iter(d.lists(**kw)) - - viewkeys = operator.methodcaller("keys") - - viewvalues = operator.methodcaller("values") - - viewitems = operator.methodcaller("items") -else: - def iterkeys(d, **kw): - return d.iterkeys(**kw) - - def itervalues(d, **kw): - return d.itervalues(**kw) - - def iteritems(d, **kw): - return d.iteritems(**kw) - - def iterlists(d, **kw): - return d.iterlists(**kw) - - viewkeys = operator.methodcaller("viewkeys") - - viewvalues = operator.methodcaller("viewvalues") - - viewitems = operator.methodcaller("viewitems") - -_add_doc(iterkeys, "Return an iterator over the keys of a dictionary.") -_add_doc(itervalues, "Return an iterator over the values of a dictionary.") -_add_doc(iteritems, - "Return an iterator over the (key, value) pairs of a dictionary.") -_add_doc(iterlists, - "Return an iterator over the (key, [values]) pairs of a dictionary.") - - -if PY3: - def b(s): - return s.encode("latin-1") - - def u(s): - return s - unichr = chr - import struct - int2byte = struct.Struct(">B").pack - del struct - byte2int = operator.itemgetter(0) - indexbytes = operator.getitem - iterbytes = iter - import io - StringIO = io.StringIO - BytesIO = io.BytesIO - _assertCountEqual = "assertCountEqual" - if sys.version_info[1] <= 1: - _assertRaisesRegex = "assertRaisesRegexp" - _assertRegex = "assertRegexpMatches" - else: - _assertRaisesRegex = "assertRaisesRegex" - _assertRegex = "assertRegex" -else: - def b(s): - return s - # Workaround for standalone backslash - - def u(s): - return unicode(s.replace(r'\\', r'\\\\'), "unicode_escape") - unichr = unichr - int2byte = chr - - def byte2int(bs): - return ord(bs[0]) - - def indexbytes(buf, i): - return ord(buf[i]) - iterbytes = functools.partial(itertools.imap, ord) - import StringIO - StringIO = BytesIO = StringIO.StringIO - _assertCountEqual = "assertItemsEqual" - _assertRaisesRegex = "assertRaisesRegexp" - _assertRegex = "assertRegexpMatches" -_add_doc(b, """Byte literal""") -_add_doc(u, """Text literal""") - - -def assertCountEqual(self, *args, **kwargs): - return getattr(self, _assertCountEqual)(*args, **kwargs) - - -def assertRaisesRegex(self, *args, **kwargs): - return getattr(self, _assertRaisesRegex)(*args, **kwargs) - - -def assertRegex(self, *args, **kwargs): - return getattr(self, _assertRegex)(*args, **kwargs) - - -if PY3: - exec_ = getattr(moves.builtins, "exec") - - def reraise(tp, value, tb=None): - if value is None: - value = tp() - if value.__traceback__ is not tb: - raise value.with_traceback(tb) - raise value - -else: - def exec_(_code_, _globs_=None, _locs_=None): - """Execute code in a namespace.""" - if _globs_ is None: - frame = sys._getframe(1) - _globs_ = frame.f_globals - if _locs_ is None: - _locs_ = frame.f_locals - del frame - elif _locs_ is None: - _locs_ = _globs_ - exec("""exec _code_ in _globs_, _locs_""") - - exec_("""def reraise(tp, value, tb=None): - raise tp, value, tb -""") - - -if sys.version_info[:2] == (3, 2): - exec_("""def raise_from(value, from_value): - if from_value is None: - raise value - raise value from from_value -""") -elif sys.version_info[:2] > (3, 2): - exec_("""def raise_from(value, from_value): - raise value from from_value -""") -else: - def raise_from(value, from_value): - raise value - - -print_ = getattr(moves.builtins, "print", None) -if print_ is None: - def print_(*args, **kwargs): - """The new-style print function for Python 2.4 and 2.5.""" - fp = kwargs.pop("file", sys.stdout) - if fp is None: - return - - def write(data): - if not isinstance(data, basestring): - data = str(data) - # If the file has an encoding, encode unicode with it. - if (isinstance(fp, file) and - isinstance(data, unicode) and - fp.encoding is not None): - errors = getattr(fp, "errors", None) - if errors is None: - errors = "strict" - data = data.encode(fp.encoding, errors) - fp.write(data) - want_unicode = False - sep = kwargs.pop("sep", None) - if sep is not None: - if isinstance(sep, unicode): - want_unicode = True - elif not isinstance(sep, str): - raise TypeError("sep must be None or a string") - end = kwargs.pop("end", None) - if end is not None: - if isinstance(end, unicode): - want_unicode = True - elif not isinstance(end, str): - raise TypeError("end must be None or a string") - if kwargs: - raise TypeError("invalid keyword arguments to print()") - if not want_unicode: - for arg in args: - if isinstance(arg, unicode): - want_unicode = True - break - if want_unicode: - newline = unicode("\n") - space = unicode(" ") - else: - newline = "\n" - space = " " - if sep is None: - sep = space - if end is None: - end = newline - for i, arg in enumerate(args): - if i: - write(sep) - write(arg) - write(end) -if sys.version_info[:2] < (3, 3): - _print = print_ - - def print_(*args, **kwargs): - fp = kwargs.get("file", sys.stdout) - flush = kwargs.pop("flush", False) - _print(*args, **kwargs) - if flush and fp is not None: - fp.flush() - -_add_doc(reraise, """Reraise an exception.""") - -if sys.version_info[0:2] < (3, 4): - def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS, - updated=functools.WRAPPER_UPDATES): - def wrapper(f): - f = functools.wraps(wrapped, assigned, updated)(f) - f.__wrapped__ = wrapped - return f - return wrapper -else: - wraps = functools.wraps - - -def with_metaclass(meta, *bases): - """Create a base class with a metaclass.""" - # This requires a bit of explanation: the basic idea is to make a dummy - # metaclass for one level of class instantiation that replaces itself with - # the actual metaclass. - class metaclass(meta): - - def __new__(cls, name, this_bases, d): - return meta(name, bases, d) - return type.__new__(metaclass, 'temporary_class', (), {}) - - -def add_metaclass(metaclass): - """Class decorator for creating a class with a metaclass.""" - def wrapper(cls): - orig_vars = cls.__dict__.copy() - slots = orig_vars.get('__slots__') - if slots is not None: - if isinstance(slots, str): - slots = [slots] - for slots_var in slots: - orig_vars.pop(slots_var) - orig_vars.pop('__dict__', None) - orig_vars.pop('__weakref__', None) - return metaclass(cls.__name__, cls.__bases__, orig_vars) - return wrapper - - -def python_2_unicode_compatible(klass): - """ - A decorator that defines __unicode__ and __str__ methods under Python 2. - Under Python 3 it does nothing. - - To support Python 2 and 3 with a single code base, define a __str__ method - returning text and apply this decorator to the class. - """ - if PY2: - if '__str__' not in klass.__dict__: - raise ValueError("@python_2_unicode_compatible cannot be applied " - "to %s because it doesn't define __str__()." % - klass.__name__) - klass.__unicode__ = klass.__str__ - klass.__str__ = lambda self: self.__unicode__().encode('utf-8') - return klass - - -# Complete the moves implementation. -# This code is at the end of this module to speed up module loading. -# Turn this module into a package. -__path__ = [] # required for PEP 302 and PEP 451 -__package__ = __name__ # see PEP 366 @ReservedAssignment -if globals().get("__spec__") is not None: - __spec__.submodule_search_locations = [] # PEP 451 @UndefinedVariable -# Remove other six meta path importers, since they cause problems. This can -# happen if six is removed from sys.modules and then reloaded. (Setuptools does -# this for some reason.) -if sys.meta_path: - for i, importer in enumerate(sys.meta_path): - # Here's some real nastiness: Another "instance" of the six module might - # be floating around. Therefore, we can't use isinstance() to check for - # the six meta path importer, since the other six instance will have - # inserted an importer with different class. - if (type(importer).__name__ == "_SixMetaPathImporter" and - importer.name == __name__): - del sys.meta_path[i] - break - del i, importer -# Finally, add the importer to the meta path import hook. -sys.meta_path.append(_importer) diff --git a/venv/lib/python3.8/site-packages/pkg_resources/extern/__init__.py b/venv/lib/python3.8/site-packages/pkg_resources/extern/__init__.py deleted file mode 100644 index c1eb9e9..0000000 --- a/venv/lib/python3.8/site-packages/pkg_resources/extern/__init__.py +++ /dev/null @@ -1,73 +0,0 @@ -import sys - - -class VendorImporter: - """ - A PEP 302 meta path importer for finding optionally-vendored - or otherwise naturally-installed packages from root_name. - """ - - def __init__(self, root_name, vendored_names=(), vendor_pkg=None): - self.root_name = root_name - self.vendored_names = set(vendored_names) - self.vendor_pkg = vendor_pkg or root_name.replace('extern', '_vendor') - - @property - def search_path(self): - """ - Search first the vendor package then as a natural package. - """ - yield self.vendor_pkg + '.' - yield '' - - def find_module(self, fullname, path=None): - """ - Return self when fullname starts with root_name and the - target module is one vendored through this importer. - """ - root, base, target = fullname.partition(self.root_name + '.') - if root: - return - if not any(map(target.startswith, self.vendored_names)): - return - return self - - def load_module(self, fullname): - """ - Iterate over the search path to locate and load fullname. - """ - root, base, target = fullname.partition(self.root_name + '.') - for prefix in self.search_path: - try: - extant = prefix + target - __import__(extant) - mod = sys.modules[extant] - sys.modules[fullname] = mod - # mysterious hack: - # Remove the reference to the extant package/module - # on later Python versions to cause relative imports - # in the vendor package to resolve the same modules - # as those going through this importer. - if prefix and sys.version_info > (3, 3): - del sys.modules[extant] - return mod - except ImportError: - pass - else: - raise ImportError( - "The '{target}' package is required; " - "normally this is bundled with this package so if you get " - "this warning, consult the packager of your " - "distribution.".format(**locals()) - ) - - def install(self): - """ - Install this importer into sys.meta_path if not already present. - """ - if self not in sys.meta_path: - sys.meta_path.append(self) - - -names = 'packaging', 'pyparsing', 'six', 'appdirs' -VendorImporter(__name__, names).install() diff --git a/venv/lib/python3.8/site-packages/pkg_resources/py31compat.py b/venv/lib/python3.8/site-packages/pkg_resources/py31compat.py deleted file mode 100644 index a381c42..0000000 --- a/venv/lib/python3.8/site-packages/pkg_resources/py31compat.py +++ /dev/null @@ -1,23 +0,0 @@ -import os -import errno -import sys - -from .extern import six - - -def _makedirs_31(path, exist_ok=False): - try: - os.makedirs(path) - except OSError as exc: - if not exist_ok or exc.errno != errno.EEXIST: - raise - - -# rely on compatibility behavior until mode considerations -# and exists_ok considerations are disentangled. -# See https://github.com/pypa/setuptools/pull/1083#issuecomment-315168663 -needs_makedirs = ( - six.PY2 or - (3, 4) <= sys.version_info < (3, 4, 1) -) -makedirs = _makedirs_31 if needs_makedirs else os.makedirs diff --git a/venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/INSTALLER b/venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/LICENSE.dual b/venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/LICENSE.dual deleted file mode 100644 index c2730fd..0000000 --- a/venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/LICENSE.dual +++ /dev/null @@ -1,792 +0,0 @@ - NOTICE: You can find here the GPLv3 license and after the Lesser GPLv3 license. -You may choose either license. - - - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. [http://fsf.org/] - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - - This version of the GNU Lesser General Public License incorporates -the terms and conditions of version 3 of the GNU General Public -License, supplemented by the additional permissions listed below. - - 0. Additional Definitions. - - As used herein, "this License" refers to version 3 of the GNU Lesser -General Public License, and the "GNU GPL" refers to version 3 of the GNU -General Public License. - - "The Library" refers to a covered work governed by this License, -other than an Application or a Combined Work as defined below. - - An "Application" is any work that makes use of an interface provided -by the Library, but which is not otherwise based on the Library. -Defining a subclass of a class defined by the Library is deemed a mode -of using an interface provided by the Library. - - A "Combined Work" is a work produced by combining or linking an -Application with the Library. The particular version of the Library -with which the Combined Work was made is also called the "Linked -Version". - - The "Minimal Corresponding Source" for a Combined Work means the -Corresponding Source for the Combined Work, excluding any source code -for portions of the Combined Work that, considered in isolation, are -based on the Application, and not on the Linked Version. - - The "Corresponding Application Code" for a Combined Work means the -object code and/or source code for the Application, including any data -and utility programs needed for reproducing the Combined Work from the -Application, but excluding the System Libraries of the Combined Work. - - 1. Exception to Section 3 of the GNU GPL. - - You may convey a covered work under sections 3 and 4 of this License -without being bound by section 3 of the GNU GPL. - - 2. Conveying Modified Versions. - - If you modify a copy of the Library, and, in your modifications, a -facility refers to a function or data to be supplied by an Application -that uses the facility (other than as an argument passed when the -facility is invoked), then you may convey a copy of the modified -version: - - a) under this License, provided that you make a good faith effort to - ensure that, in the event an Application does not supply the - function or data, the facility still operates, and performs - whatever part of its purpose remains meaningful, or - - b) under the GNU GPL, with none of the additional permissions of - this License applicable to that copy. - - 3. Object Code Incorporating Material from Library Header Files. - - The object code form of an Application may incorporate material from -a header file that is part of the Library. You may convey such object -code under terms of your choice, provided that, if the incorporated -material is not limited to numerical parameters, data structure -layouts and accessors, or small macros, inline functions and templates -(ten or fewer lines in length), you do both of the following: - - a) Give prominent notice with each copy of the object code that the - Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the object code with a copy of the GNU GPL and this license - document. - - 4. Combined Works. - - You may convey a Combined Work under terms of your choice that, -taken together, effectively do not restrict modification of the -portions of the Library contained in the Combined Work and reverse -engineering for debugging such modifications, if you also do each of -the following: - - a) Give prominent notice with each copy of the Combined Work that - the Library is used in it and that the Library and its use are - covered by this License. - - b) Accompany the Combined Work with a copy of the GNU GPL and this license - document. - - c) For a Combined Work that displays copyright notices during - execution, include the copyright notice for the Library among - these notices, as well as a reference directing the user to the - copies of the GNU GPL and this license document. - - d) Do one of the following: - - 0) Convey the Minimal Corresponding Source under the terms of this - License, and the Corresponding Application Code in a form - suitable for, and under terms that permit, the user to - recombine or relink the Application with a modified version of - the Linked Version to produce a modified Combined Work, in the - manner specified by section 6 of the GNU GPL for conveying - Corresponding Source. - - 1) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (a) uses at run time - a copy of the Library already present on the user's computer - system, and (b) will operate properly with a modified version - of the Library that is interface-compatible with the Linked - Version. - - e) Provide Installation Information, but only if you would otherwise - be required to provide such information under section 6 of the - GNU GPL, and only to the extent that such information is - necessary to install and execute a modified version of the - Combined Work produced by recombining or relinking the - Application with a modified version of the Linked Version. (If - you use option 4d0, the Installation Information must accompany - the Minimal Corresponding Source and Corresponding Application - Code. If you use option 4d1, you must provide the Installation - Information in the manner specified by section 6 of the GNU GPL - for conveying Corresponding Source.) - - 5. Combined Libraries. - - You may place library facilities that are a work based on the -Library side by side in a single library together with other library -facilities that are not Applications and are not covered by this -License, and convey such a combined library under terms of your -choice, if you do both of the following: - - a) Accompany the combined library with a copy of the same work based - on the Library, uncombined with any other library facilities, - conveyed under the terms of this License. - - b) Give prominent notice with the combined library that part of it - is a work based on the Library, and explaining where to find the - accompanying uncombined form of the same work. - - 6. Revised Versions of the GNU Lesser General Public License. - - The Free Software Foundation may publish revised and/or new versions -of the GNU Lesser General Public License from time to time. Such new -versions will be similar in spirit to the present version, but may -differ in detail to address new problems or concerns. - - Each version is given a distinguishing version number. If the -Library as you received it specifies that a certain numbered version -of the GNU Lesser General Public License "or any later version" -applies to it, you have the option of following the terms and -conditions either of that published version or of any later version -published by the Free Software Foundation. If the Library as you -received it does not specify a version number of the GNU Lesser -General Public License, you may choose any version of the GNU Lesser -General Public License ever published by the Free Software Foundation. - - If the Library as you received it specifies that a proxy can decide -whether future versions of the GNU Lesser General Public License shall -apply, that proxy's public statement of acceptance of any version is -permanent authorization for you to choose that version for the -Library. - - - - - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. [http://fsf.org/] - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. diff --git a/venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/METADATA b/venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/METADATA deleted file mode 100644 index 7007758..0000000 --- a/venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/METADATA +++ /dev/null @@ -1,285 +0,0 @@ -Metadata-Version: 2.1 -Name: python-telegram-bot -Version: 13.6 -Summary: We have made you a wrapper you can't refuse -Home-page: https://python-telegram-bot.org/ -Author: Leandro Toledo -Author-email: devs@python-telegram-bot.org -License: LGPLv3 -Download-URL: https://pypi.org/project/python-telegram-bot/ -Project-URL: Documentation, https://python-telegram-bot.readthedocs.io -Project-URL: Bug Tracker, https://github.com/python-telegram-bot/python-telegram-bot/issues -Project-URL: Source Code, https://github.com/python-telegram-bot/python-telegram-bot -Project-URL: News, https://t.me/pythontelegrambotchannel -Project-URL: Changelog, https://python-telegram-bot.readthedocs.io/en/stable/changelog.html -Keywords: python telegram bot api wrapper -Platform: UNKNOWN -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: GNU Lesser General Public License v3 (LGPLv3) -Classifier: Operating System :: OS Independent -Classifier: Topic :: Software Development :: Libraries :: Python Modules -Classifier: Topic :: Communications :: Chat -Classifier: Topic :: Internet -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/x-rst -Requires-Dist: certifi -Requires-Dist: tornado (>=6.1) -Requires-Dist: APScheduler (==3.6.3) -Requires-Dist: pytz (>=2018.6) -Requires-Dist: cachetools (==4.2.2) -Provides-Extra: json -Requires-Dist: ujson ; extra == 'json' -Provides-Extra: passport -Requires-Dist: cryptography (!=3.4,!=3.4.1,!=3.4.2,!=3.4.3) ; extra == 'passport' -Provides-Extra: socks -Requires-Dist: PySocks ; extra == 'socks' - -.. - Make user to apply any changes to this file to README_RAW.rst as well! - -.. image:: https://github.com/python-telegram-bot/logos/blob/master/logo-text/png/ptb-logo-text_768.png?raw=true - :align: center - :target: https://python-telegram-bot.org - :alt: python-telegram-bot Logo - -We have made you a wrapper you can't refuse - -We have a vibrant community of developers helping each other in our `Telegram group <https://telegram.me/pythontelegrambotgroup>`_. Join us! - -*Stay tuned for library updates and new releases on our* `Telegram Channel <https://telegram.me/pythontelegrambotchannel>`_. - -.. image:: https://img.shields.io/pypi/v/python-telegram-bot.svg - :target: https://pypi.org/project/python-telegram-bot/ - :alt: PyPi Package Version - -.. image:: https://img.shields.io/pypi/pyversions/python-telegram-bot.svg - :target: https://pypi.org/project/python-telegram-bot/ - :alt: Supported Python versions - -.. image:: https://img.shields.io/badge/Bot%20API-5.2-blue?logo=telegram - :target: https://core.telegram.org/bots/api-changelog - :alt: Supported Bot API versions - -.. image:: https://img.shields.io/pypi/dm/python-telegram-bot - :target: https://pypistats.org/packages/python-telegram-bot - :alt: PyPi Package Monthly Download - -.. image:: https://readthedocs.org/projects/python-telegram-bot/badge/?version=stable - :target: https://python-telegram-bot.readthedocs.io/en/stable/?badge=stable - :alt: Documentation Status - -.. image:: https://img.shields.io/pypi/l/python-telegram-bot.svg - :target: https://www.gnu.org/licenses/lgpl-3.0.html - :alt: LGPLv3 License - -.. image:: https://github.com/python-telegram-bot/python-telegram-bot/workflows/GitHub%20Actions/badge.svg - :target: https://github.com/python-telegram-bot/python-telegram-bot/ - :alt: Github Actions workflow - -.. image:: https://codecov.io/gh/python-telegram-bot/python-telegram-bot/branch/master/graph/badge.svg - :target: https://codecov.io/gh/python-telegram-bot/python-telegram-bot - :alt: Code coverage - -.. image:: http://isitmaintained.com/badge/resolution/python-telegram-bot/python-telegram-bot.svg - :target: http://isitmaintained.com/project/python-telegram-bot/python-telegram-bot - :alt: Median time to resolve an issue - -.. image:: https://api.codacy.com/project/badge/Grade/99d901eaa09b44b4819aec05c330c968 - :target: https://www.codacy.com/app/python-telegram-bot/python-telegram-bot?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=python-telegram-bot/python-telegram-bot&amp;utm_campaign=Badge_Grade - :alt: Code quality: Codacy - -.. image:: https://deepsource.io/gh/python-telegram-bot/python-telegram-bot.svg/?label=active+issues - :target: https://deepsource.io/gh/python-telegram-bot/python-telegram-bot/?ref=repository-badge - :alt: Code quality: DeepSource - -.. image:: https://img.shields.io/badge/code%20style-black-000000.svg - :target: https://github.com/psf/black - -.. image:: https://img.shields.io/badge/Telegram-Group-blue.svg?logo=telegram - :target: https://telegram.me/pythontelegrambotgroup - :alt: Telegram Group - -================= -Table of contents -================= - -- `Introduction`_ - -- `Telegram API support`_ - -- `Installing`_ - -- `Getting started`_ - - #. `Learning by example`_ - - #. `Logging`_ - - #. `Documentation`_ - -- `Getting help`_ - -- `Contributing`_ - -- `License`_ - -============ -Introduction -============ - -This library provides a pure Python interface for the -`Telegram Bot API <https://core.telegram.org/bots/api>`_. -It's compatible with Python versions 3.6.2+. PTB might also work on `PyPy <http://pypy.org/>`_, though there have been a lot of issues before. Hence, PyPy is not officially supported. - -In addition to the pure API implementation, this library features a number of high-level classes to -make the development of bots easy and straightforward. These classes are contained in the -``telegram.ext`` submodule. - -A pure API implementation *without* ``telegram.ext`` is available as the standalone package ``python-telegram-bot-raw``. `See here for details. <https://github.com/python-telegram-bot/python-telegram-bot/blob/master/README_RAW.rst>`_ - ----- -Note ----- - -Installing both ``python-telegram-bot`` and ``python-telegram-bot-raw`` in conjunction will result in undesired side-effects, so only install *one* of both. - -==================== -Telegram API support -==================== - -All types and methods of the Telegram Bot API **5.2** are supported. - -========== -Installing -========== - -You can install or upgrade python-telegram-bot with: - -.. code:: shell - - $ pip install python-telegram-bot --upgrade - -Or you can install from source with: - -.. code:: shell - - $ git clone https://github.com/python-telegram-bot/python-telegram-bot --recursive - $ cd python-telegram-bot - $ python setup.py install - -In case you have a previously cloned local repository already, you should initialize the added urllib3 submodule before installing with: - -.. code:: shell - - $ git submodule update --init --recursive - ---------------------- -Optional Dependencies ---------------------- - -PTB can be installed with optional dependencies: - -* ``pip install python-telegram-bot[passport]`` installs the `cryptography <https://cryptography.io>`_ library. Use this, if you want to use Telegram Passport related functionality. -* ``pip install python-telegram-bot[ujson]`` installs the `ujson <https://pypi.org/project/ujson/>`_ library. It will then be used for JSON de- & encoding, which can bring speed up compared to the standard `json <https://docs.python.org/3/library/json.html>`_ library. -* ``pip install python-telegram-bot[socks]`` installs the `PySocks <https://pypi.org/project/PySocks/>`_ library. Use this, if you want to work behind a Socks5 server. - -=============== -Getting started -=============== - -Our Wiki contains a lot of resources to get you started with ``python-telegram-bot``: - -- `Introduction to the API <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Introduction-to-the-API>`_ -- Tutorial: `Your first Bot <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Extensions-%E2%80%93-Your-first-Bot>`_ - -Other references: - -- `Telegram API documentation <https://core.telegram.org/bots/api>`_ -- `python-telegram-bot documentation <https://python-telegram-bot.readthedocs.io/>`_ - -------------------- -Learning by example -------------------- - -We believe that the best way to learn this package is by example. Here -are some examples for you to review. Even if it is not your approach for learning, please take a -look at ``echobot.py``, it is the de facto base for most of the bots out there. Best of all, -the code for these examples are released to the public domain, so you can start by grabbing the -code and building on top of it. - -Visit `this page <https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples/README.md>`_ to discover the official examples or look at the examples on the `wiki <https://github.com/python-telegram-bot/python-telegram-bot/wiki/Examples>`_ to see other bots the community has built. - -------- -Logging -------- - -This library uses the ``logging`` module. To set up logging to standard output, put: - -.. code:: python - - import logging - logging.basicConfig(level=logging.DEBUG, - format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') - -at the beginning of your script. - -You can also use logs in your application by calling ``logging.getLogger()`` and setting the log level you want: - -.. code:: python - - logger = logging.getLogger() - logger.setLevel(logging.INFO) - -If you want DEBUG logs instead: - -.. code:: python - - logger.setLevel(logging.DEBUG) - - -============= -Documentation -============= - -``python-telegram-bot``'s documentation lives at `readthedocs.io <https://python-telegram-bot.readthedocs.io/>`_. - -============ -Getting help -============ - -You can get help in several ways: - -1. We have a vibrant community of developers helping each other in our `Telegram group <https://telegram.me/pythontelegrambotgroup>`_. Join us! - -2. Report bugs, request new features or ask questions by `creating an issue <https://github.com/python-telegram-bot/python-telegram-bot/issues/new/choose>`_ or `a discussion <https://github.com/python-telegram-bot/python-telegram-bot/discussions/new>`_. - -3. Our `Wiki pages <https://github.com/python-telegram-bot/python-telegram-bot/wiki/>`_ offer a growing amount of resources. - -4. You can even ask for help on Stack Overflow using the `python-telegram-bot tag <https://stackoverflow.com/questions/tagged/python-telegram-bot>`_. - - -============ -Contributing -============ - -Contributions of all sizes are welcome. Please review our `contribution guidelines <https://github.com/python-telegram-bot/python-telegram-bot/blob/master/.github/CONTRIBUTING.rst>`_ to get started. You can also help by `reporting bugs <https://github.com/python-telegram-bot/python-telegram-bot/issues/new>`_. - -======== -Donating -======== -Occasionally we are asked if we accept donations to support the development. While we appreciate the thought, maintaining PTB is our hobby and we have almost no running costs for it. We therefore have nothing set up to accept donations. If you still want to donate, we kindly ask you to donate to another open source project/initiative of your choice instead. - -======= -License -======= - -You may copy, distribute and modify the software provided that modifications are described and licensed for free under `LGPL-3 <https://www.gnu.org/licenses/lgpl-3.0.html>`_. Derivatives works (including modifications or anything statically linked to the library) can only be redistributed under LGPL-3, but applications that use the library don't have to be. - - diff --git a/venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/RECORD b/venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/RECORD deleted file mode 100644 index 6aaf6ff..0000000 --- a/venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/RECORD +++ /dev/null @@ -1,365 +0,0 @@ -python_telegram_bot-13.6.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -python_telegram_bot-13.6.dist-info/LICENSE.dual,sha256=eblsAdLmpvSxNh8leJceEVCwU7rNitnIgMs8X_kIEd8,40192 -python_telegram_bot-13.6.dist-info/METADATA,sha256=B8PggedtxXvPXZ0BrmN10TXhZgI26UXIRmvpALLSkac,11561 -python_telegram_bot-13.6.dist-info/RECORD,, -python_telegram_bot-13.6.dist-info/WHEEL,sha256=OqRkF0eY5GHssMorFjlbTIq072vpHpF60fIQA6lS9xA,92 -python_telegram_bot-13.6.dist-info/top_level.txt,sha256=tfrh9q1x_2mn166E6RftggS4sc4T_5C1BYamJkSoWg0,9 -telegram/__init__.py,sha256=N_TlcPZ2dH5XsqLHi69EiuN9gBeRpWsppreNYoyHZpI,10121 -telegram/__main__.py,sha256=9NpdO-07LdnbowBaEn2e2W6FwQVJrrARQ0KKF3_9FjM,1779 -telegram/__pycache__/__init__.cpython-38.pyc,, -telegram/__pycache__/__main__.cpython-38.pyc,, -telegram/__pycache__/base.cpython-38.pyc,, -telegram/__pycache__/bot.cpython-38.pyc,, -telegram/__pycache__/botcommand.cpython-38.pyc,, -telegram/__pycache__/callbackquery.cpython-38.pyc,, -telegram/__pycache__/chat.cpython-38.pyc,, -telegram/__pycache__/chataction.cpython-38.pyc,, -telegram/__pycache__/chatinvitelink.cpython-38.pyc,, -telegram/__pycache__/chatlocation.cpython-38.pyc,, -telegram/__pycache__/chatmember.cpython-38.pyc,, -telegram/__pycache__/chatmemberupdated.cpython-38.pyc,, -telegram/__pycache__/chatpermissions.cpython-38.pyc,, -telegram/__pycache__/choseninlineresult.cpython-38.pyc,, -telegram/__pycache__/constants.cpython-38.pyc,, -telegram/__pycache__/dice.cpython-38.pyc,, -telegram/__pycache__/error.cpython-38.pyc,, -telegram/__pycache__/forcereply.cpython-38.pyc,, -telegram/__pycache__/keyboardbutton.cpython-38.pyc,, -telegram/__pycache__/keyboardbuttonpolltype.cpython-38.pyc,, -telegram/__pycache__/loginurl.cpython-38.pyc,, -telegram/__pycache__/message.cpython-38.pyc,, -telegram/__pycache__/messageautodeletetimerchanged.cpython-38.pyc,, -telegram/__pycache__/messageentity.cpython-38.pyc,, -telegram/__pycache__/messageid.cpython-38.pyc,, -telegram/__pycache__/parsemode.cpython-38.pyc,, -telegram/__pycache__/poll.cpython-38.pyc,, -telegram/__pycache__/proximityalerttriggered.cpython-38.pyc,, -telegram/__pycache__/replykeyboardmarkup.cpython-38.pyc,, -telegram/__pycache__/replykeyboardremove.cpython-38.pyc,, -telegram/__pycache__/replymarkup.cpython-38.pyc,, -telegram/__pycache__/update.cpython-38.pyc,, -telegram/__pycache__/user.cpython-38.pyc,, -telegram/__pycache__/userprofilephotos.cpython-38.pyc,, -telegram/__pycache__/version.cpython-38.pyc,, -telegram/__pycache__/voicechat.cpython-38.pyc,, -telegram/__pycache__/webhookinfo.cpython-38.pyc,, -telegram/base.py,sha256=f1TSIMJTVpnoy0yZkyk4LwcNK5nacOKSYl26gYV1Q94,5148 -telegram/bot.py,sha256=x6fFEqq__TWT1K-hCHGOZSlNTx8sDgioMxw86-hH2t4,239317 -telegram/botcommand.py,sha256=bgKiJEvPaUI5p00zuegf60H_C0aQSPbgE08iNYvICXw,1869 -telegram/callbackquery.py,sha256=Iph4EsFAFyTn-oHYylCLj9r1jVTF_a5IWjq6jm_fhrg,23195 -telegram/chat.py,sha256=_NnCfjxOLiCwMWTjsLDmFAKPp3rFuAp21IUeR-j_rm8,55782 -telegram/chataction.py,sha256=jViLHxzfZcm05tCVG_eFG_XOK7UO2fkPwEIiuuS4Lkk,3198 -telegram/chatinvitelink.py,sha256=1zS2R9uOCJf-Wd18XinK6achbsHgKMj83-dkHBaZ9EA,4245 -telegram/chatlocation.py,sha256=WgqFNGY-xK-bjVSOrliiAQJR4adG_pLJSykAaob--ug,2513 -telegram/chatmember.py,sha256=39wU5kcPQ54J8wuhG3vgVByVxkDdX7qDjPZxVOqQZOQ,12103 -telegram/chatmemberupdated.py,sha256=vzyCiH_j3rkf8Kpx_It6_LDxhe33q_81uzotf2s7E2Q,6597 -telegram/chatpermissions.py,sha256=6VOGVVkb0GHT-TIJR3tJragH78Y5UuCyAEPGD3Voq5Q,6007 -telegram/choseninlineresult.py,sha256=m8pDt1h5PSKCT8SQctxzpZn3PLlVQ8WrLWO3NyxWphE,3816 -telegram/constants.py,sha256=1O8I4rwW5aaPERb9iafFFsypFKGn-fsnXw1xPitSyPI,11889 -telegram/dice.py,sha256=IkQwhw2ybsTv1cMstYMinQTRBtYk1cQxpDTKoCRzEjc,4002 -telegram/error.py,sha256=CIz8GVcw33b5rCeg8yjQm-TUicaWq8J4jHek-JcBe7s,4255 -telegram/ext/__init__.py,sha256=GHh7agiC9e7z55uVEZt9Jwv8jVkbpATRZBI4VDbe5IA,3573 -telegram/ext/__pycache__/__init__.cpython-38.pyc,, -telegram/ext/__pycache__/basepersistence.cpython-38.pyc,, -telegram/ext/__pycache__/callbackcontext.cpython-38.pyc,, -telegram/ext/__pycache__/callbackdatacache.cpython-38.pyc,, -telegram/ext/__pycache__/callbackqueryhandler.cpython-38.pyc,, -telegram/ext/__pycache__/chatmemberhandler.cpython-38.pyc,, -telegram/ext/__pycache__/choseninlineresulthandler.cpython-38.pyc,, -telegram/ext/__pycache__/commandhandler.cpython-38.pyc,, -telegram/ext/__pycache__/contexttypes.cpython-38.pyc,, -telegram/ext/__pycache__/conversationhandler.cpython-38.pyc,, -telegram/ext/__pycache__/defaults.cpython-38.pyc,, -telegram/ext/__pycache__/dictpersistence.cpython-38.pyc,, -telegram/ext/__pycache__/dispatcher.cpython-38.pyc,, -telegram/ext/__pycache__/extbot.cpython-38.pyc,, -telegram/ext/__pycache__/filters.cpython-38.pyc,, -telegram/ext/__pycache__/handler.cpython-38.pyc,, -telegram/ext/__pycache__/inlinequeryhandler.cpython-38.pyc,, -telegram/ext/__pycache__/jobqueue.cpython-38.pyc,, -telegram/ext/__pycache__/messagehandler.cpython-38.pyc,, -telegram/ext/__pycache__/messagequeue.cpython-38.pyc,, -telegram/ext/__pycache__/picklepersistence.cpython-38.pyc,, -telegram/ext/__pycache__/pollanswerhandler.cpython-38.pyc,, -telegram/ext/__pycache__/pollhandler.cpython-38.pyc,, -telegram/ext/__pycache__/precheckoutqueryhandler.cpython-38.pyc,, -telegram/ext/__pycache__/regexhandler.cpython-38.pyc,, -telegram/ext/__pycache__/shippingqueryhandler.cpython-38.pyc,, -telegram/ext/__pycache__/stringcommandhandler.cpython-38.pyc,, -telegram/ext/__pycache__/stringregexhandler.cpython-38.pyc,, -telegram/ext/__pycache__/typehandler.cpython-38.pyc,, -telegram/ext/__pycache__/updater.cpython-38.pyc,, -telegram/ext/basepersistence.py,sha256=NBiKFM459u9alDsZ5bqcWXNUwKhT9oowLFNVT61dWro,22470 -telegram/ext/callbackcontext.py,sha256=qWpfL3XNou8UqINMOINOKykhHMVF1sPIIHBszYcnX8g,14479 -telegram/ext/callbackdatacache.py,sha256=XC2TzHv3m2c_pEIMWu8topAkK-6tSD139eK2ntDyxL0,17176 -telegram/ext/callbackqueryhandler.py,sha256=esS6E2tnjh33VkNpRMMzzQAhwWjQeqnvZ5n3rwuQWAI,10842 -telegram/ext/chatmemberhandler.py,sha256=z963kWStcZvIUhozMHVC-nH31XBQJx5y4tQjFxFtWV0,7034 -telegram/ext/choseninlineresulthandler.py,sha256=7Qz6BXq8bWqXo0N8eyYvOsdVkW5RWcOztw7ZOUmbtu4,7130 -telegram/ext/commandhandler.py,sha256=s8OmFtEJf3n5IrDj32D22L8NTU7i1aeGoAYZbW4utBQ,20693 -telegram/ext/contexttypes.py,sha256=vVsQHu9CptNlpgY68ZXithJ-L0mNlVxQ9hX3NW6S5wM,5801 -telegram/ext/conversationhandler.py,sha256=aHxPSynyJlcq4Wr_4EHMnW3EnfiSaKBVThFDCKnjl9U,31360 -telegram/ext/defaults.py,sha256=t5VJGJQAHuQbFY-Opp_3a4cC8NWwEw3Td5f1vAieYts,10386 -telegram/ext/dictpersistence.py,sha256=DVlhmZwY9MbI_iinqPlip5W9PkXSEvaXdysgvc7pF9w,15999 -telegram/ext/dispatcher.py,sha256=PXIadx5GpZfjRuejKC3x7KhXVuaWKbr56XrRUCaue5k,33944 -telegram/ext/extbot.py,sha256=-mXD03mEy8yq9LAAesrNCww7hpz1rgEzn6bezl2IvOI,13322 -telegram/ext/filters.py,sha256=BTayVEqP7e39wJk6wOhHJBH3diYPk_ZGWFHoXFbMwJg,86691 -telegram/ext/handler.py,sha256=55ym84weyrctws7DyJxmgDqbN783XYPBjI9SNqvtG3o,11226 -telegram/ext/inlinequeryhandler.py,sha256=XoQpqYO4Iqbd-eu4pLXlRH77LARHpViv72_eAcOI2lc,9794 -telegram/ext/jobqueue.py,sha256=PFDtgA52Nqg7JczdULQqQeVi6t9QtNiMg46Omd8o4qo,26886 -telegram/ext/messagehandler.py,sha256=ja7kp2X9R4n3RYGWR1ZCWUvCKjjxrRQbVFaPVbnXV30,9710 -telegram/ext/messagequeue.py,sha256=3CWaqCFZFrSEz4qw9To6sBm5nUckzmduMgqvUp17ylg,14773 -telegram/ext/picklepersistence.py,sha256=ICPpzyQOtpQgstFtaCA79ZmIxzsTmpXiMSKNnuYPHTk,18675 -telegram/ext/pollanswerhandler.py,sha256=rlxyHBkAvXKRjCvb36LGFzbJgHKr-F2HtVQT3dcZ6Wo,4832 -telegram/ext/pollhandler.py,sha256=U2COPncVo5M0kVMCi0UOFVV4734GTr7UOEu1GhFFUUg,4808 -telegram/ext/precheckoutqueryhandler.py,sha256=bEPlYbCZ2idBH2dsmXvlzkIuqkeW-3blAZrAyfMIz10,4845 -telegram/ext/regexhandler.py,sha256=MpxYTTkB_3XrjWryGSFNG_Tj_jzCNBTGDJCbk1deKcw,7823 -telegram/ext/shippingqueryhandler.py,sha256=RW75T7EP-0BohJ3QCa2TwJixcRhs0GOBdeeOqhgh3Lo,4831 -telegram/ext/stringcommandhandler.py,sha256=UxC59oVahZoUpxW4vDSv2XG8LU8cRc7FQmpSgdtojVs,6445 -telegram/ext/stringregexhandler.py,sha256=IwpbnDlL3FKVBwtm9zx7gH0_SqWUjwgIFQOBGMIIBOs,7164 -telegram/ext/typehandler.py,sha256=OmNsYXq30XnNXFJ6ZAt_GH1qHTg-hSOOS8OjplGhq4g,4743 -telegram/ext/updater.py,sha256=y1OUfzzzi6_0wm7Pc8bXX42l_UASrwIiSCe_q_U2uYw,35830 -telegram/ext/utils/__init__.py,sha256=YtDH89cdcr4SOQDEiTOonwD8c3Mn7vSQEBEIJ2gjVGE,800 -telegram/ext/utils/__pycache__/__init__.cpython-38.pyc,, -telegram/ext/utils/__pycache__/promise.cpython-38.pyc,, -telegram/ext/utils/__pycache__/types.cpython-38.pyc,, -telegram/ext/utils/__pycache__/webhookhandler.cpython-38.pyc,, -telegram/ext/utils/promise.py,sha256=zDZ4WQLKYTNbBj8KB4OoKS3AiqhYySIE-X-bE4u92zM,5804 -telegram/ext/utils/types.py,sha256=0v13OdC53ez3k3OL6XiM6vLQ2af2z0h5TmQ1stRc_E4,1905 -telegram/ext/utils/webhookhandler.py,sha256=xw4HEPyI5ZCVpEj2NiQXbOiDnzQ1R_ZpXx741coYX4o,6101 -telegram/files/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -telegram/files/__pycache__/__init__.cpython-38.pyc,, -telegram/files/__pycache__/animation.cpython-38.pyc,, -telegram/files/__pycache__/audio.cpython-38.pyc,, -telegram/files/__pycache__/chatphoto.cpython-38.pyc,, -telegram/files/__pycache__/contact.cpython-38.pyc,, -telegram/files/__pycache__/document.cpython-38.pyc,, -telegram/files/__pycache__/file.cpython-38.pyc,, -telegram/files/__pycache__/inputfile.cpython-38.pyc,, -telegram/files/__pycache__/inputmedia.cpython-38.pyc,, -telegram/files/__pycache__/location.cpython-38.pyc,, -telegram/files/__pycache__/photosize.cpython-38.pyc,, -telegram/files/__pycache__/sticker.cpython-38.pyc,, -telegram/files/__pycache__/venue.cpython-38.pyc,, -telegram/files/__pycache__/video.cpython-38.pyc,, -telegram/files/__pycache__/videonote.cpython-38.pyc,, -telegram/files/__pycache__/voice.cpython-38.pyc,, -telegram/files/animation.py,sha256=MiDxXbqRTLyc5b5Hqif2jb7iGFfrcgHUJjB9QDkDZG4,5198 -telegram/files/audio.py,sha256=-pPB_qQX1m62nau4s4W2TEYeXdiqQ9Ti1Ndad8cz3LY,5397 -telegram/files/chatphoto.py,sha256=J8XTGbf3KZauYIdMqjR33_VhHIx4SKMPW-VCYH0M6xo,5179 -telegram/files/contact.py,sha256=ETMl2rm7Lh-AvZ9f7Jkg3HKBJ5ouFZLjhX33npOjJ60,2540 -telegram/files/document.py,sha256=wk0Kz-3wsb2JfxaE9X3JJOYFtoeYdj5wu8CJHOhO8wo,4486 -telegram/files/file.py,sha256=0818-6TUkbtFm2UdDHwLUxF4NVBpy0-DrAwzjJAZsgY,8343 -telegram/files/inputfile.py,sha256=AbYIBOoe6ua0-C-ZWOPDR38aBdfnuZQzEzyUF9dvVlQ,4251 -telegram/files/inputmedia.py,sha256=dzX1_Q3ca9nxY0esabKHPxmyb5HFjICY8DTlGrkMKJg,22605 -telegram/files/location.py,sha256=yjccX_saJOgm5kxcZyH8nVf3DiCUaYZk0cjWT8ClWPM,3831 -telegram/files/photosize.py,sha256=j1z9wKd-K0ViwqhPwsOLEDLql2ViIrXXsPIgueMwbCM,3626 -telegram/files/sticker.py,sha256=oVEt_WDQ1HsgW2e_aElSnCiU9Qcx6w19QpbrWhvNBU4,10869 -telegram/files/venue.py,sha256=CHuBeNtK01qZtJpW0FNYjndbI668XVzPwfyPzvoBYgE,3970 -telegram/files/video.py,sha256=IAGDMTvc-11ng5JtKYT9tTtfo5cu9RJfbt6ljfLBJZY,5076 -telegram/files/videonote.py,sha256=Kr0weVSSRc0NOR95WAvCexqy9FRmFXrtHh28W0-ayDk,4497 -telegram/files/voice.py,sha256=lyUqA5eXTn-OObOklPmKGVVgYxbejyKyllvZYD4jw5k,3858 -telegram/forcereply.py,sha256=voUc7RP-ftOucMK5oO8XTS-P3jv7RLa33qtqO5Dnc9k,2441 -telegram/games/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -telegram/games/__pycache__/__init__.cpython-38.pyc,, -telegram/games/__pycache__/callbackgame.cpython-38.pyc,, -telegram/games/__pycache__/game.cpython-38.pyc,, -telegram/games/__pycache__/gamehighscore.cpython-38.pyc,, -telegram/games/callbackgame.py,sha256=mQBXmlXtFcXTl_IzKIudmj5uLM6ZV44aN437SCTOjmg,1074 -telegram/games/game.py,sha256=aiD63lDhG3iWih_iuYZecH78mcq8s8Y4IMp04CcwPhs,7698 -telegram/games/gamehighscore.py,sha256=frQay4m5ImX3f5iY5k6gUr66tgVCtMYaQR_VJwHN5nE,2320 -telegram/inline/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -telegram/inline/__pycache__/__init__.cpython-38.pyc,, -telegram/inline/__pycache__/inlinekeyboardbutton.cpython-38.pyc,, -telegram/inline/__pycache__/inlinekeyboardmarkup.cpython-38.pyc,, -telegram/inline/__pycache__/inlinequery.cpython-38.pyc,, -telegram/inline/__pycache__/inlinequeryresult.cpython-38.pyc,, -telegram/inline/__pycache__/inlinequeryresultarticle.cpython-38.pyc,, -telegram/inline/__pycache__/inlinequeryresultaudio.cpython-38.pyc,, -telegram/inline/__pycache__/inlinequeryresultcachedaudio.cpython-38.pyc,, -telegram/inline/__pycache__/inlinequeryresultcacheddocument.cpython-38.pyc,, -telegram/inline/__pycache__/inlinequeryresultcachedgif.cpython-38.pyc,, -telegram/inline/__pycache__/inlinequeryresultcachedmpeg4gif.cpython-38.pyc,, -telegram/inline/__pycache__/inlinequeryresultcachedphoto.cpython-38.pyc,, -telegram/inline/__pycache__/inlinequeryresultcachedsticker.cpython-38.pyc,, -telegram/inline/__pycache__/inlinequeryresultcachedvideo.cpython-38.pyc,, -telegram/inline/__pycache__/inlinequeryresultcachedvoice.cpython-38.pyc,, -telegram/inline/__pycache__/inlinequeryresultcontact.cpython-38.pyc,, -telegram/inline/__pycache__/inlinequeryresultdocument.cpython-38.pyc,, -telegram/inline/__pycache__/inlinequeryresultgame.cpython-38.pyc,, -telegram/inline/__pycache__/inlinequeryresultgif.cpython-38.pyc,, -telegram/inline/__pycache__/inlinequeryresultlocation.cpython-38.pyc,, -telegram/inline/__pycache__/inlinequeryresultmpeg4gif.cpython-38.pyc,, -telegram/inline/__pycache__/inlinequeryresultphoto.cpython-38.pyc,, -telegram/inline/__pycache__/inlinequeryresultvenue.cpython-38.pyc,, -telegram/inline/__pycache__/inlinequeryresultvideo.cpython-38.pyc,, -telegram/inline/__pycache__/inlinequeryresultvoice.cpython-38.pyc,, -telegram/inline/__pycache__/inputcontactmessagecontent.cpython-38.pyc,, -telegram/inline/__pycache__/inputinvoicemessagecontent.cpython-38.pyc,, -telegram/inline/__pycache__/inputlocationmessagecontent.cpython-38.pyc,, -telegram/inline/__pycache__/inputmessagecontent.cpython-38.pyc,, -telegram/inline/__pycache__/inputtextmessagecontent.cpython-38.pyc,, -telegram/inline/__pycache__/inputvenuemessagecontent.cpython-38.pyc,, -telegram/inline/inlinekeyboardbutton.py,sha256=2MrCxkNUIieGPkjqUb5TXAMWp_lpJFBfx_L-959UuLo,7533 -telegram/inline/inlinekeyboardmarkup.py,sha256=83BXE_ciG1-fF3ShTuZoHgCS4ZhkGkcrf3h_brR3rcY,4862 -telegram/inline/inlinequery.py,sha256=wTudQMAAlMNbYTcb7OiVpiAsbVj62qezBV_LK5rlsHw,6662 -telegram/inline/inlinequeryresult.py,sha256=OqC6oXJGzhrvUT67LpFFicX29sW45xuMtuSsS78XPAo,2449 -telegram/inline/inlinequeryresultarticle.py,sha256=TFv89JZJvjZ2qcruVBJEMFw2QmJS4Wn99Z9Xq7FXGL0,3996 -telegram/inline/inlinequeryresultaudio.py,sha256=XUaInEkm2XfJCnjD8LH7Sp2hR07F37pb6vr-pmlmvoE,5037 -telegram/inline/inlinequeryresultcachedaudio.py,sha256=Yiwg-c0n_XzzwgiPY8XYHfPy3DgLrtGdjERIAcMgQ-Q,4545 -telegram/inline/inlinequeryresultcacheddocument.py,sha256=2IU_1GnOLI-TXDSJQvKdULpqYggT0cfuT3vuT3iKg-Q,5085 -telegram/inline/inlinequeryresultcachedgif.py,sha256=tCEXNh1ixoXLHb9xrLekFXAzqrhSoKRRG0RUkbxO0v4,4856 -telegram/inline/inlinequeryresultcachedmpeg4gif.py,sha256=pxQxmbmHCvWQsNHoNo02yRsuIMLNkLaq5D0791eAYU4,4918 -telegram/inline/inlinequeryresultcachedphoto.py,sha256=pxfVtchG5UIcH0GN_I9BHdonAQAYlCrITLUeO4_Ecjw,5076 -telegram/inline/inlinequeryresultcachedsticker.py,sha256=-VWXhDCLJa4xNhPZdy-aZC1s8Tx36mvGolGfAqTaBkU,2915 -telegram/inline/inlinequeryresultcachedvideo.py,sha256=Z7aitBF-uJhq5d2fiZGcWEeIDsiHSUzWEDSB7dVBzC4,5054 -telegram/inline/inlinequeryresultcachedvoice.py,sha256=g0Dv0T--yAuivRBYwXNlyy7EmiGSjX-X5dWf81Bl_W4,4738 -telegram/inline/inlinequeryresultcontact.py,sha256=tnkIXR4hct850i5tj3BiFSZAJXoAbQ7I8fKK3BQHdic,4272 -telegram/inline/inlinequeryresultdocument.py,sha256=vaJ721JP8xU6akJ57u56rC6Vtmkv1JhZf9PxkCE1CHo,6083 -telegram/inline/inlinequeryresultgame.py,sha256=h3_9yMc9rLIu41iz9NE1bR0ypJTmfCjDs3QKxmO0Q8A,2201 -telegram/inline/inlinequeryresultgif.py,sha256=OUPkWmRy8OVlhFEtVGFGbGAinh6Kj2Y5O3ueEE0wjYs,6189 -telegram/inline/inlinequeryresultlocation.py,sha256=t7B_9C7Np5F-P15KUMVxqtqUl_e5d7PgzXeO6o34Uns,5749 -telegram/inline/inlinequeryresultmpeg4gif.py,sha256=fVcN4kHK97ZIWzwBNjnJBEHcm73rkEadn7bFN-9nds4,6226 -telegram/inline/inlinequeryresultphoto.py,sha256=7db_Z4xX2M0AZxDxbM-7qPb46tqjF2s2RvrNnS6yQaw,5864 -telegram/inline/inlinequeryresultvenue.py,sha256=Tr6A8pEWhGp2m4r_zAzdVO3aiNsPxIO7731ELBzz1SU,5638 -telegram/inline/inlinequeryresultvideo.py,sha256=iMOeCdLgzl5Yzbz6HqFVaOuFgxk6d2Pp51wHoiBdLoc,6674 -telegram/inline/inlinequeryresultvoice.py,sha256=ZxeuwSvtPI14kq9ZpKeb33YcXMOrQNHonM_AgQVqF3E,4961 -telegram/inline/inputcontactmessagecontent.py,sha256=-tMq8mbCfWtcUPM45AL7TkTSQD9kgjbfyEVnZbqE0eA,2454 -telegram/inline/inputinvoicemessagecontent.py,sha256=gZgu7C5bckjnf6o53kXED4oVzWDVzMlp7dmB-EkWRIc,11009 -telegram/inline/inputlocationmessagecontent.py,sha256=FFXOULbhPsAHdHaf3R4RiNvYnwxEYV5vAdS2lRt5au0,3863 -telegram/inline/inputmessagecontent.py,sha256=LSwjSkgQBCUXM8P3fskqKC_XeVwntnhVADahhFef1ec,1332 -telegram/inline/inputtextmessagecontent.py,sha256=MBQPMJP56dPk0ShlZjPEwJJq7bR5-rdpDc10eVqAh9k,3882 -telegram/inline/inputvenuemessagecontent.py,sha256=iNhMa_Byw3fLLMXYYEDUTU46CK8oCkEifMmls9eNk0Y,3981 -telegram/keyboardbutton.py,sha256=dMnONHaACh_82UkBn0pLoEkzn2_u5_4OERQMgzpxfnQ,3614 -telegram/keyboardbuttonpolltype.py,sha256=khznebYXZEBIkC7hiE6dV_kOeDkqLRD15eSVq3r5JFY,1837 -telegram/loginurl.py,sha256=aTwonylgx2GAT1VNBxZ-VcValRb3bV5ukXBj7pIPuGA,4093 -telegram/message.py,sha256=U2LLQPU1nqSXTZvdAa7wocjhg3wR3-3kgcnt3Bpzlvs,118913 -telegram/messageautodeletetimerchanged.py,sha256=VwOzVTEIwfOuyYMYZMWK9lSU9EqiAW-jdVKJe8_NbO4,1913 -telegram/messageentity.py,sha256=EVF3GmlsZF8nCrIbYrvegfOdAGiVR4cqO81-P6lR1bY,5705 -telegram/messageid.py,sha256=j5FbZweDWc5BtDwP7isMXeVJwPXjB05crfX5oGqx9Bw,1481 -telegram/parsemode.py,sha256=3wfYxMmkLe2VDlwwi1vEODOPH-pqavwLZzZdziX_pHA,1783 -telegram/passport/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -telegram/passport/__pycache__/__init__.cpython-38.pyc,, -telegram/passport/__pycache__/credentials.cpython-38.pyc,, -telegram/passport/__pycache__/data.cpython-38.pyc,, -telegram/passport/__pycache__/encryptedpassportelement.cpython-38.pyc,, -telegram/passport/__pycache__/passportdata.cpython-38.pyc,, -telegram/passport/__pycache__/passportelementerrors.cpython-38.pyc,, -telegram/passport/__pycache__/passportfile.cpython-38.pyc,, -telegram/passport/credentials.py,sha256=uZOfAn4wwO2BTmZuK464PftcoWH7V8ZAmOJnpLXXlQQ,19374 -telegram/passport/data.py,sha256=U2ML0fQRj5FeWYq7SjYxtvirgncLR_piUPF3fNRoGJY,4692 -telegram/passport/encryptedpassportelement.py,sha256=LfyLTZLSC2kNG2PPJIV4NtIjUTECKPNitTngmaal_p0,12172 -telegram/passport/passportdata.py,sha256=sUpEpIgpNCjNy96AOt2YKcBVicOhajW99xiUQfiBi3Y,4938 -telegram/passport/passportelementerrors.py,sha256=D0bPvBqJ9zDmZOz73B8NFOPIq41tD8GmGie-cq2-gF8,16267 -telegram/passport/passportfile.py,sha256=7ez3MkDij2t-Yx_50qp0ZnsCIjI0-s5qBTexxUEfSyo,5601 -telegram/payment/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -telegram/payment/__pycache__/__init__.cpython-38.pyc,, -telegram/payment/__pycache__/invoice.cpython-38.pyc,, -telegram/payment/__pycache__/labeledprice.cpython-38.pyc,, -telegram/payment/__pycache__/orderinfo.cpython-38.pyc,, -telegram/payment/__pycache__/precheckoutquery.cpython-38.pyc,, -telegram/payment/__pycache__/shippingaddress.cpython-38.pyc,, -telegram/payment/__pycache__/shippingoption.cpython-38.pyc,, -telegram/payment/__pycache__/shippingquery.cpython-38.pyc,, -telegram/payment/__pycache__/successfulpayment.cpython-38.pyc,, -telegram/payment/invoice.py,sha256=H7jODpfFqnwM-xARAaYHFfkoGJh0mPWj3sXbM2U6rBo,3166 -telegram/payment/labeledprice.py,sha256=O6J1HcTXJabd59mfcUVriJaPeLaN7jpAP13vFa1P3ac,2182 -telegram/payment/orderinfo.py,sha256=0LDmlGgOUcHmbvHBHv2kR5OUWTOwi3kUYfLohCc1tIY,2881 -telegram/payment/precheckoutquery.py,sha256=A0OjB5MiazpEguqMo95RTThXWD_gQmMtiWpq9rtVmdk,5229 -telegram/payment/shippingaddress.py,sha256=kU5r3z_IsCzHCIIOxt6jKJFuZrErW7b8ITlfLJGHn0c,2858 -telegram/payment/shippingoption.py,sha256=D5zoKG-9_Ck5QxLrhE62vnBlRBebhS9xEzhIkGzMY5M,2330 -telegram/payment/shippingquery.py,sha256=JZXVUgjMzgp5YUjRcJ0dw35eaogv90pWlW1kCtiZ2Ok,4118 -telegram/payment/successfulpayment.py,sha256=SlEQNz9c0eyUpyWwOcdz9SsFsq-OykOLv9YHbJfZqlU,4400 -telegram/poll.py,sha256=0em8JTuq3-VsADHKWB0q9NaKcgjGvVtMmpoB5Wa3hEM,12268 -telegram/proximityalerttriggered.py,sha256=lHcbWyTK9tdRDA3M95xda1L-Y5eoNI8EswH1e7NGrZY,2654 -telegram/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -telegram/replykeyboardmarkup.py,sha256=zwhQ188D22COkzCToQRydECt4MQbc0zYa7ePi4dyUco,11030 -telegram/replykeyboardremove.py,sha256=_UBdjJM5C6wT49sSi_6as-6Ds8umCCV-HMb4eC8GWjk,2743 -telegram/replymarkup.py,sha256=uLMNo9tBHTF8nntypyj4-8GqjTCNL_RuQcTt1GlZmT8,1200 -telegram/update.py,sha256=8V8-X19fjcTV0rL7rRfGKLKB3YUE7FdL3EVGR0PY4mY,15537 -telegram/user.py,sha256=CS2qMeJKQRamPK2on3gI1tgYjo82bZQtt22vE02mM9M,40818 -telegram/userprofilephotos.py,sha256=1rphFGeYc3KDFRyanaXLa9e_J2U8IjCFja6Xx-8WlXs,2808 -telegram/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -telegram/utils/__pycache__/__init__.cpython-38.pyc,, -telegram/utils/__pycache__/deprecate.cpython-38.pyc,, -telegram/utils/__pycache__/helpers.cpython-38.pyc,, -telegram/utils/__pycache__/promise.cpython-38.pyc,, -telegram/utils/__pycache__/request.cpython-38.pyc,, -telegram/utils/__pycache__/types.cpython-38.pyc,, -telegram/utils/__pycache__/webhookhandler.cpython-38.pyc,, -telegram/utils/deprecate.py,sha256=FRNL22xXKuxuRwtvKbRVnaIxqW9ZPcws-fOc9bBNGcE,1934 -telegram/utils/helpers.py,sha256=3XcMeYB-rvJNiGn39S51wrNOAmQPB_rcvbqep_-30ak,20674 -telegram/utils/promise.py,sha256=1KHB0dSGQ-blNFpvoKTVtYP6zsECnbItWh-IH1t06s4,1350 -telegram/utils/request.py,sha256=u5BsS_0AiVD872PmZJrWA0i00KnYBw163T0y8EU8DoA,15475 -telegram/utils/types.py,sha256=K73MKOxQz5-FX--6ZtUb3nD6EUO1LYv0IUWiTEj2fhI,2114 -telegram/utils/webhookhandler.py,sha256=Ujxsba_gr15yJcA45HsW9kzJDW1z8ezIjh7BIRLORXo,1383 -telegram/vendor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -telegram/vendor/__pycache__/__init__.cpython-38.pyc,, -telegram/vendor/ptb_urllib3/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -telegram/vendor/ptb_urllib3/__pycache__/__init__.cpython-38.pyc,, -telegram/vendor/ptb_urllib3/urllib3/__init__.py,sha256=jut63xC48t8AA78QgpglAJnVynOfmBCa5E9DdlDq9Jk,2851 -telegram/vendor/ptb_urllib3/urllib3/__pycache__/__init__.cpython-38.pyc,, -telegram/vendor/ptb_urllib3/urllib3/__pycache__/_collections.cpython-38.pyc,, -telegram/vendor/ptb_urllib3/urllib3/__pycache__/connection.cpython-38.pyc,, -telegram/vendor/ptb_urllib3/urllib3/__pycache__/connectionpool.cpython-38.pyc,, -telegram/vendor/ptb_urllib3/urllib3/__pycache__/exceptions.cpython-38.pyc,, -telegram/vendor/ptb_urllib3/urllib3/__pycache__/fields.cpython-38.pyc,, -telegram/vendor/ptb_urllib3/urllib3/__pycache__/filepost.cpython-38.pyc,, -telegram/vendor/ptb_urllib3/urllib3/__pycache__/poolmanager.cpython-38.pyc,, -telegram/vendor/ptb_urllib3/urllib3/__pycache__/request.cpython-38.pyc,, -telegram/vendor/ptb_urllib3/urllib3/__pycache__/response.cpython-38.pyc,, -telegram/vendor/ptb_urllib3/urllib3/_collections.py,sha256=zzeg3Qqib_rTpTRwkAd1RVS68bBJbQiGRdH7TthOr-U,10638 -telegram/vendor/ptb_urllib3/urllib3/connection.py,sha256=nz3JRA97jiEjuiGccBEPDD4OaxdGssZWbQJnnwGSF14,12709 -telegram/vendor/ptb_urllib3/urllib3/connectionpool.py,sha256=jeEgyqFevm4u8b40HsEy3xkItJ0-MgSeLQRtmB8Eu9Y,35475 -telegram/vendor/ptb_urllib3/urllib3/contrib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -telegram/vendor/ptb_urllib3/urllib3/contrib/__pycache__/__init__.cpython-38.pyc,, -telegram/vendor/ptb_urllib3/urllib3/contrib/__pycache__/appengine.cpython-38.pyc,, -telegram/vendor/ptb_urllib3/urllib3/contrib/__pycache__/ntlmpool.cpython-38.pyc,, -telegram/vendor/ptb_urllib3/urllib3/contrib/__pycache__/pyopenssl.cpython-38.pyc,, -telegram/vendor/ptb_urllib3/urllib3/contrib/__pycache__/socks.cpython-38.pyc,, -telegram/vendor/ptb_urllib3/urllib3/contrib/appengine.py,sha256=41l3arTy-kBBpOdVpSPYVC64Qo7RLnXnDED6hcIthA0,10865 -telegram/vendor/ptb_urllib3/urllib3/contrib/ntlmpool.py,sha256=Q9-rO5Rh2-IqyEd4ZicpTDfMnOlf0IPPCkjhChBCjV4,4478 -telegram/vendor/ptb_urllib3/urllib3/contrib/pyopenssl.py,sha256=qjfb01ERFADeSS8FZI28tMEf2RWveUZ6fYxwoNG8qcI,15139 -telegram/vendor/ptb_urllib3/urllib3/contrib/socks.py,sha256=Iom0snbHkCuZbZ7Sle2Kueha1W0jYAJ0SyCOtePLaio,6391 -telegram/vendor/ptb_urllib3/urllib3/exceptions.py,sha256=dz1gBEgtROnLrW8V911KhVZWeAn3H2OhDGztWNXQpr0,6603 -telegram/vendor/ptb_urllib3/urllib3/fields.py,sha256=YrNRM8RBUmM8guXKUQFa3kwj6XvQZ78Z8inE6l-YK-E,5943 -telegram/vendor/ptb_urllib3/urllib3/filepost.py,sha256=NF6Rly66bilWU-sdULXjCdQgN1uRxfFRedeifcRLzkU,2321 -telegram/vendor/ptb_urllib3/urllib3/packages/__init__.py,sha256=nlChrGzkjCkmhCX9HrF_qHPUgosfsPQkVIJxiiLhk9g,109 -telegram/vendor/ptb_urllib3/urllib3/packages/__pycache__/__init__.cpython-38.pyc,, -telegram/vendor/ptb_urllib3/urllib3/packages/__pycache__/ordered_dict.cpython-38.pyc,, -telegram/vendor/ptb_urllib3/urllib3/packages/__pycache__/six.cpython-38.pyc,, -telegram/vendor/ptb_urllib3/urllib3/packages/backports/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -telegram/vendor/ptb_urllib3/urllib3/packages/backports/__pycache__/__init__.cpython-38.pyc,, -telegram/vendor/ptb_urllib3/urllib3/packages/backports/__pycache__/makefile.cpython-38.pyc,, -telegram/vendor/ptb_urllib3/urllib3/packages/backports/makefile.py,sha256=r1IADol_pBBq2Y1ub4CPyuS2hXuShK47nfFngZRcRhI,1461 -telegram/vendor/ptb_urllib3/urllib3/packages/ordered_dict.py,sha256=VQaPONfhVMsb8B63Xg7ZOydJqIE_jzeMhVN3Pec6ogw,8935 -telegram/vendor/ptb_urllib3/urllib3/packages/six.py,sha256=A6hdJZVjI3t_geebZ9BzUvwRrIXo0lfwzQlM2LcKyas,30098 -telegram/vendor/ptb_urllib3/urllib3/packages/ssl_match_hostname/__init__.py,sha256=WBVbxQBojNAxfZwNavkox3BgJiMA9BJmm-_fwd0jD_o,688 -telegram/vendor/ptb_urllib3/urllib3/packages/ssl_match_hostname/__pycache__/__init__.cpython-38.pyc,, -telegram/vendor/ptb_urllib3/urllib3/packages/ssl_match_hostname/__pycache__/_implementation.cpython-38.pyc,, -telegram/vendor/ptb_urllib3/urllib3/packages/ssl_match_hostname/_implementation.py,sha256=lAj7qGCZLOldhn8gZDY6Tqp4mvgkbTfy4k4gDIDRo8g,5702 -telegram/vendor/ptb_urllib3/urllib3/poolmanager.py,sha256=XiePLnfcp7MrVijdmsK_icTO_NqIeV8Q-A3RjE-CvW8,13053 -telegram/vendor/ptb_urllib3/urllib3/request.py,sha256=wrt2D0SWLLgTRKrRnaZophq2xXpCvNRd7RMT6F5o5hY,5946 -telegram/vendor/ptb_urllib3/urllib3/response.py,sha256=Adir6jrilGFwEq6EP2IrBGxzGf3CjengxFq5qqF_2P8,22662 -telegram/vendor/ptb_urllib3/urllib3/util/__init__.py,sha256=3UlYoBSPyTrRiuTCmDNOYiBagiS9pJ665VrxoAAKCsc,994 -telegram/vendor/ptb_urllib3/urllib3/util/__pycache__/__init__.cpython-38.pyc,, -telegram/vendor/ptb_urllib3/urllib3/util/__pycache__/connection.cpython-38.pyc,, -telegram/vendor/ptb_urllib3/urllib3/util/__pycache__/request.cpython-38.pyc,, -telegram/vendor/ptb_urllib3/urllib3/util/__pycache__/response.cpython-38.pyc,, -telegram/vendor/ptb_urllib3/urllib3/util/__pycache__/retry.cpython-38.pyc,, -telegram/vendor/ptb_urllib3/urllib3/util/__pycache__/selectors.cpython-38.pyc,, -telegram/vendor/ptb_urllib3/urllib3/util/__pycache__/ssl_.cpython-38.pyc,, -telegram/vendor/ptb_urllib3/urllib3/util/__pycache__/timeout.cpython-38.pyc,, -telegram/vendor/ptb_urllib3/urllib3/util/__pycache__/url.cpython-38.pyc,, -telegram/vendor/ptb_urllib3/urllib3/util/__pycache__/wait.cpython-38.pyc,, -telegram/vendor/ptb_urllib3/urllib3/util/connection.py,sha256=_6_5JZJF3HHRXR7HaxHg3mk7qMKK3N0nl3DL8gFAfo4,4237 -telegram/vendor/ptb_urllib3/urllib3/util/request.py,sha256=UBgRm7xqZU1ybd_Eo0ExdDhFk1AzAl_Z7iuCMIL6SYI,3704 -telegram/vendor/ptb_urllib3/urllib3/util/response.py,sha256=SSNL888W-MQ8t3HAi44kNGgF682p6H__ytEXzBYxV_M,2343 -telegram/vendor/ptb_urllib3/urllib3/util/retry.py,sha256=zxU3zfwglKT0mKwpSzw3aYyug6mumuDfFVBCZCNVQ6A,14123 -telegram/vendor/ptb_urllib3/urllib3/util/selectors.py,sha256=D29bI1M9WAkHoalIQFDN638Y-L0WVLOOfYC7bjNbaZY,18929 -telegram/vendor/ptb_urllib3/urllib3/util/ssl_.py,sha256=4f7gDIXTKnmnPoWPq-yG18a-pipOCnYQeJyU4zNjlss,12046 -telegram/vendor/ptb_urllib3/urllib3/util/timeout.py,sha256=7lHNrgL5YH2cI1j-yZnzV_J8jBlRVdmFhQaNyM1_2b8,9757 -telegram/vendor/ptb_urllib3/urllib3/util/url.py,sha256=91q1Ap45PqXfRuff5Qnx7Xz2TXalp7axXxjbEB67N6w,6289 -telegram/vendor/ptb_urllib3/urllib3/util/wait.py,sha256=Q_pd_bD6iaPgRKwEmcjTYDrSPj4Dd4ojykmqA398b8o,1451 -telegram/version.py,sha256=nCPjK3yUyceutls8PHAD26qUjwu_tuMChogdPkYwiG8,956 -telegram/voicechat.py,sha256=AbpdZ6zrViwTd-3F8mUH5BGMRObGCbN6sUmssKIlXoE,5209 -telegram/webhookinfo.py,sha256=EHVB03pTveBVpbMUvBoNVXG-YNX39Q6U_WiBHz5Pt6k,4665 diff --git a/venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/WHEEL b/venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/WHEEL deleted file mode 100644 index 385faab..0000000 --- a/venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: bdist_wheel (0.36.2) -Root-Is-Purelib: true -Tag: py3-none-any - diff --git a/venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/top_level.txt b/venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/top_level.txt deleted file mode 100644 index 51e6be6..0000000 --- a/venv/lib/python3.8/site-packages/python_telegram_bot-13.6.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -telegram diff --git a/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/DESCRIPTION.rst b/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/DESCRIPTION.rst deleted file mode 100644 index 1729548..0000000 --- a/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/DESCRIPTION.rst +++ /dev/null @@ -1,598 +0,0 @@ -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+0020' - -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) -datetime.timedelta(0, 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. 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: -http://www.twinsun.com/tz/tz-link.htm - - -Contact -~~~~~~~ - -Stuart Bishop <stuart@stuartbishop.net> - - - - diff --git a/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/INSTALLER b/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/LICENSE.txt b/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/LICENSE.txt deleted file mode 100644 index 5f1c112..0000000 --- a/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/LICENSE.txt +++ /dev/null @@ -1,19 +0,0 @@ -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/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/METADATA b/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/METADATA deleted file mode 100644 index 2fcd986..0000000 --- a/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/METADATA +++ /dev/null @@ -1,634 +0,0 @@ -Metadata-Version: 2.0 -Name: pytz -Version: 2021.1 -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: 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+0020' - -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) -datetime.timedelta(0, 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. 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: -http://www.twinsun.com/tz/tz-link.htm - - -Contact -~~~~~~~ - -Stuart Bishop <stuart@stuartbishop.net> - - - - diff --git a/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/RECORD b/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/RECORD deleted file mode 100644 index fcf52aa..0000000 --- a/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/RECORD +++ /dev/null @@ -1,620 +0,0 @@ -pytz-2021.1.dist-info/DESCRIPTION.rst,sha256=ovmwqIt48fGpf9TczEWesZm0IiGilc_OZOjBt_tim30,19920 -pytz-2021.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -pytz-2021.1.dist-info/LICENSE.txt,sha256=vosaN-vibFkqkPbA6zMQOn84POL010mMCvmlJpkKB7g,1088 -pytz-2021.1.dist-info/METADATA,sha256=kTNHa1f5tk5725uGfhpiJEY6J6m2fcDDXD62EBk3DNI,21412 -pytz-2021.1.dist-info/RECORD,, -pytz-2021.1.dist-info/WHEEL,sha256=kdsN-5OJAZIiHN-iO4Rhl82KyS0bDWf4uBwMbkNafr8,110 -pytz-2021.1.dist-info/metadata.json,sha256=E_bzRXeDscpn48NauiutB0Z_tAPTWdw-bvwTjz3pzLc,1587 -pytz-2021.1.dist-info/top_level.txt,sha256=6xRYlt934v1yHb1JIrXgHyGxn3cqACvd-yE8ski_kcc,5 -pytz-2021.1.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1 -pytz/__init__.py,sha256=kA0Hlp5D5MTPPuf88KVg8pYRwJRGxTQJJuVN794hwsU,35147 -pytz/__pycache__/__init__.cpython-38.pyc,, -pytz/__pycache__/exceptions.cpython-38.pyc,, -pytz/__pycache__/lazy.cpython-38.pyc,, -pytz/__pycache__/reference.cpython-38.pyc,, -pytz/__pycache__/tzfile.cpython-38.pyc,, -pytz/__pycache__/tzinfo.cpython-38.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=c0Z3DcevVpxyT9HOgW1xSf_f8-MDQgBZ-qFVfMlZ4RU,1060 -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=L6zLQLnQtLkEELOGfm6USaHY33qAEPgGV822-iU1vxc,1955 -pytz/zoneinfo/Africa/Casablanca,sha256=qzlDyFvkLZWy8Bydogdx_cxZCkWzRwEEsuVWstJI_-s,2429 -pytz/zoneinfo/Africa/Ceuta,sha256=jp7xqONgZ3NPnElHzJEVusHKM9rxDK1nxJm4-i7Ln8o,2036 -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=Ja0t5t3QHHrvY0EGgxadypAabj4GjMLuQTTbOAur5M0,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=17gT2eOVMFKJF_sypwDPudkFwGEijrRfkBU-aK3FL60,148 -pytz/zoneinfo/America/Antigua,sha256=17gT2eOVMFKJF_sypwDPudkFwGEijrRfkBU-aK3FL60,148 -pytz/zoneinfo/America/Araguaina,sha256=kppiiytmSQeesflyNGYM3r8NVUl1C-ggu08s9_Tt-co,884 -pytz/zoneinfo/America/Argentina/Buenos_Aires,sha256=ntn_GFHadbrFJ4ZuhU6h2uzbFwmDyS9mXV5S28pkGF8,1076 -pytz/zoneinfo/America/Argentina/Catamarca,sha256=diH1f96kbbY-7gJYQnSCNHs3n9dwHJqUhSdGNx1L7I0,1076 -pytz/zoneinfo/America/Argentina/ComodRivadavia,sha256=diH1f96kbbY-7gJYQnSCNHs3n9dwHJqUhSdGNx1L7I0,1076 -pytz/zoneinfo/America/Argentina/Cordoba,sha256=1XqIP8Qo2bPR7909hrAI-qAttybmwEW4ms7FjZA5Yfw,1076 -pytz/zoneinfo/America/Argentina/Jujuy,sha256=5HR0TlZFifwJ5nLTmg7yWXgCTx9mRhahfs4_Wq70wOY,1048 -pytz/zoneinfo/America/Argentina/La_Rioja,sha256=Zf_E3akFE1YUt9MZ4xxbRnOrp2bH1D-Bjsc0SLFfRyU,1090 -pytz/zoneinfo/America/Argentina/Mendoza,sha256=5DJiYYeQpcLBR_IoIJtk43IswJeGYawx5GykszuJ-Nw,1076 -pytz/zoneinfo/America/Argentina/Rio_Gallegos,sha256=T97WADwva6JbxICviNQUt_7iw9c-nloI4QJCscENSck,1076 -pytz/zoneinfo/America/Argentina/Salta,sha256=ATw0uR6szWKPs6jzdn6revS7UxCXD26ORK6jlmsjL18,1048 -pytz/zoneinfo/America/Argentina/San_Juan,sha256=qlW693a0Tnofy-RdcVBuWY3DvTTGxWwcYdKU3Y98pX8,1090 -pytz/zoneinfo/America/Argentina/San_Luis,sha256=WYdcro5-Fe-N6LkQsKwx_1tVozmnBp58DO1-BJs2suo,1102 -pytz/zoneinfo/America/Argentina/Tucuman,sha256=wsjg1a5AM1dP2gjr112k3vt54trcOOM_StF74xzvBJc,1104 -pytz/zoneinfo/America/Argentina/Ushuaia,sha256=9548Vvq_kpw_NX5s65vYuIbqvwGV-PBxqwmcrflLI0U,1076 -pytz/zoneinfo/America/Aruba,sha256=ZGEIylAZ5iy_rIBsXREtH_ZfWRIkLI9dQjP_EIyn3sY,186 -pytz/zoneinfo/America/Asuncion,sha256=FTLtFk6MjJoh5VIDgJ2Sf4B_iNeCDxrV0MWwQL-sOVM,2044 -pytz/zoneinfo/America/Atikokan,sha256=4a94GtPHUdQ-2sdz9WinsKn9V_QiM4XmFj48FTPMeSA,336 -pytz/zoneinfo/America/Atka,sha256=IB1DhwJQAKbhPJ9jHLf8zW5Dad7HIkBS-dhv64E1OlM,2356 -pytz/zoneinfo/America/Bahia,sha256=cmLkSAAzINlzYGXBqADEU3uPgA9S5nt-p1AV3Zy86VY,1024 -pytz/zoneinfo/America/Bahia_Banderas,sha256=BNjbcHSlPsJ4UpJx-gs1hpIyx2ScBieh1nyDuGb0PcE,1546 -pytz/zoneinfo/America/Barbados,sha256=Y0XwBAv5eSAZHNixVIhRvPxNWqP2a1FCH2_z2Vrd-sc,314 -pytz/zoneinfo/America/Belem,sha256=_258hQZLCEXBX8xRLyQSw-AE-jiDmjVwJX32mN5UUEk,576 -pytz/zoneinfo/America/Belize,sha256=pkfLY2KfPchbeJa1pWcXmWAwp4ZlRvxWLVezXnrbkws,1614 -pytz/zoneinfo/America/Blanc-Sablon,sha256=tVN5ZPmIO3vc3_ayowg6qbvjheg4OJtDFT9y8IuW334,298 -pytz/zoneinfo/America/Boa_Vista,sha256=V4VVOkrFUV1qUfVp9E974IOJFmA5QxQrctatTBEb-hs,632 -pytz/zoneinfo/America/Bogota,sha256=ZaQKTZi35AMdlROs0vjEDA_phR8ztJOnjA8aLJZ5tHw,246 -pytz/zoneinfo/America/Boise,sha256=Yv4AXa2nSH_oVo3FZqZCR7V7z7c6WnQgKIUyNUpzGXA,2394 -pytz/zoneinfo/America/Buenos_Aires,sha256=ntn_GFHadbrFJ4ZuhU6h2uzbFwmDyS9mXV5S28pkGF8,1076 -pytz/zoneinfo/America/Cambridge_Bay,sha256=Nanl8yH4SshljhEjDe-PZCYEXbUuuZGmkbAAt2dB-bk,2084 -pytz/zoneinfo/America/Campo_Grande,sha256=5BBENR3_8gJp4F_Uj2RRknvRc4JJWNRPnZU9E7tb8QI,1444 -pytz/zoneinfo/America/Cancun,sha256=YR2U5T6mDGd5xm8EVA_TM1NwSRMYPNYWvV7wuthnX0I,782 -pytz/zoneinfo/America/Caracas,sha256=2NpwXPEtQkI82WCZuQWHXf66VCADcawMpfhKTsuA0x4,264 -pytz/zoneinfo/America/Catamarca,sha256=diH1f96kbbY-7gJYQnSCNHs3n9dwHJqUhSdGNx1L7I0,1076 -pytz/zoneinfo/America/Cayenne,sha256=atVbW5ChJiKQ_q-3kFs-DLTTZa9ptkiHkmJlq4AXoY4,198 -pytz/zoneinfo/America/Cayman,sha256=kayA_pdpMcSQ0FjIzotdcf-m1JYfbKE-qcFT8LC8zqA,182 -pytz/zoneinfo/America/Chicago,sha256=4aZFw-svkMyXmSpNufqzK-xveos-oVJDpEyI8Yu9HQE,3576 -pytz/zoneinfo/America/Chihuahua,sha256=cewXJyEw4KCoz33yl8o2tUJZmugBWH4R0Aovdmuqf-o,1484 -pytz/zoneinfo/America/Coral_Harbour,sha256=4a94GtPHUdQ-2sdz9WinsKn9V_QiM4XmFj48FTPMeSA,336 -pytz/zoneinfo/America/Cordoba,sha256=1XqIP8Qo2bPR7909hrAI-qAttybmwEW4ms7FjZA5Yfw,1076 -pytz/zoneinfo/America/Costa_Rica,sha256=74rYa6lrgIkyls9PkHo8SCYl9oOqiuG5S7MWdnJelP4,316 -pytz/zoneinfo/America/Creston,sha256=dNOa71QgQ2d5uh7cl-xZme-8u3nMR9GJ7PSktWIDORQ,208 -pytz/zoneinfo/America/Cuiaba,sha256=M0FsR8T9s4jFSuzD8Qi6pqtb6Rf2NTzyVHKGZrn56n4,1416 -pytz/zoneinfo/America/Curacao,sha256=ZGEIylAZ5iy_rIBsXREtH_ZfWRIkLI9dQjP_EIyn3sY,186 -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=6_yPo1_mvnt9DgpPzr0QdHsjdsfUG6ALnagQLML1DSM,2444 -pytz/zoneinfo/America/Detroit,sha256=hecz8yqY2Cj5B61G3gLZdAVZvRgK9l0P90c_gN-uD5g,2230 -pytz/zoneinfo/America/Dominica,sha256=17gT2eOVMFKJF_sypwDPudkFwGEijrRfkBU-aK3FL60,148 -pytz/zoneinfo/America/Edmonton,sha256=-TkIfc3QlvaCf0p8COZ43Y1HRBAl-nARUi-JdXeK1vE,2332 -pytz/zoneinfo/America/Eirunepe,sha256=pS90HZzRwH4Tf8ugmKHfiphX7zCPqZkh_0CNb-fEMAM,656 -pytz/zoneinfo/America/El_Salvador,sha256=gvGN8Lkj-sGm2_rs8OUjAMf1oMtKp2Xes6UfWT0WqgU,224 -pytz/zoneinfo/America/Ensenada,sha256=OHHtvy3J70z6wvKBHgPqMEnGs6SXp8fkf0WX9ZiOODk,2342 -pytz/zoneinfo/America/Fort_Nelson,sha256=erfODr3DrSpz65kAdO7Ts2dGbZxvddEP6gx4BX3y2J0,2240 -pytz/zoneinfo/America/Fort_Wayne,sha256=GrNub1_3Um5Qh67wOx58_TEAz4fwAeAlk2AlMTVA_sI,1666 -pytz/zoneinfo/America/Fortaleza,sha256=mITuMrRLRTWyoiF04Oy_UZ8gxZofTpXDblM8t7ch7Sg,716 -pytz/zoneinfo/America/Glace_Bay,sha256=G8DGLGCapH_aYCF_OhaL5Qonf7FOAgAPwelO5htCWBc,2192 -pytz/zoneinfo/America/Godthab,sha256=FtlXWP_hBNuwBHkI2b1yne_tSUJpwLtWLyTHZoFZkmM,1878 -pytz/zoneinfo/America/Goose_Bay,sha256=JgaLueghSvX2g725FOfIgpgvsqxZGykWOhAZWGpQZRY,3210 -pytz/zoneinfo/America/Grand_Turk,sha256=4YOFEPK60Bel2_fCsY6vSZxUcMJKjiKtyOf_Q0khEwU,1834 -pytz/zoneinfo/America/Grenada,sha256=17gT2eOVMFKJF_sypwDPudkFwGEijrRfkBU-aK3FL60,148 -pytz/zoneinfo/America/Guadeloupe,sha256=17gT2eOVMFKJF_sypwDPudkFwGEijrRfkBU-aK3FL60,148 -pytz/zoneinfo/America/Guatemala,sha256=dugUgCd6QY52yHkHuUP4jRWzo5x439IQigaYCvEF46Q,280 -pytz/zoneinfo/America/Guayaquil,sha256=PbcF4bvGAm-aFwdtGPotJy3kb4NwoyWwxgwL98BeUWA,246 -pytz/zoneinfo/America/Guyana,sha256=mDyb0FtGOpwGPq864vAHX22LY0Pxex94f1wVMyo36d0,236 -pytz/zoneinfo/America/Halifax,sha256=TZpmc5PwWoLfTfQoQ_b3U17BE2iVKSeNkR0Ho8mbTn8,3424 -pytz/zoneinfo/America/Havana,sha256=HUQeAuKBsEkI5SLZjqynXICOUVOajkKzKH5r-Ov5Odc,2416 -pytz/zoneinfo/America/Hermosillo,sha256=9Ij30JYmMscC1XHi4o9v-uSXoUuE8V9zhGz2iV5hVFI,416 -pytz/zoneinfo/America/Indiana/Indianapolis,sha256=GrNub1_3Um5Qh67wOx58_TEAz4fwAeAlk2AlMTVA_sI,1666 -pytz/zoneinfo/America/Indiana/Knox,sha256=BiALShjiOLg1o8mMRWJ1jyTlJkgvwzte7B9WSOvTUNg,2428 -pytz/zoneinfo/America/Indiana/Marengo,sha256=CPYY3XgJFNEzONxei7x04wOGI_b86RAn4jBPewi1HZw,1722 -pytz/zoneinfo/America/Indiana/Petersburg,sha256=axot1SloP27ZWjezmo7kldu9qA2frEtPVqWngcXtft0,1904 -pytz/zoneinfo/America/Indiana/Tell_City,sha256=GrWNjb1i4sbIYlJ8fU0viJ2Q5JmrlvLgcLQILnk3El8,1684 -pytz/zoneinfo/America/Indiana/Vevay,sha256=GGosHbQUoIDOKPZxdal42X40veEITMmrnlKOnLUhb-c,1414 -pytz/zoneinfo/America/Indiana/Vincennes,sha256=gh7LAbHbMD92eo9C_c5IiwQ1fJvxhdJN402Q_4YJdLg,1694 -pytz/zoneinfo/America/Indiana/Winamac,sha256=yS-_aKSC4crd0WdNutkHRHxUjmBCU56QVQcqy7kYpbQ,1778 -pytz/zoneinfo/America/Indianapolis,sha256=GrNub1_3Um5Qh67wOx58_TEAz4fwAeAlk2AlMTVA_sI,1666 -pytz/zoneinfo/America/Inuvik,sha256=MU_oDiidQaijt1KV0B5h9LqHoCrJ8ieldD9tsiJiX5o,1894 -pytz/zoneinfo/America/Iqaluit,sha256=6PitEMSFWcSb-Io8fvm4oQ_7v39G_qANc6reTjXoZJ0,2032 -pytz/zoneinfo/America/Jamaica,sha256=wlagieUPRf5-beie-h7QsONbNzjGsm8vMs8uf28pw28,482 -pytz/zoneinfo/America/Jujuy,sha256=5HR0TlZFifwJ5nLTmg7yWXgCTx9mRhahfs4_Wq70wOY,1048 -pytz/zoneinfo/America/Juneau,sha256=k7hxb0aGRnfnE-DBi3LkcjAzRPyAf0_Hw0vVFfjGeb0,2353 -pytz/zoneinfo/America/Kentucky/Louisville,sha256=-yqgeeHZdq6oP3_WzVvYOmqV9HQv8y7ZWmc9bzHvJAY,2772 -pytz/zoneinfo/America/Kentucky/Monticello,sha256=NJMKjG7jjlRzZhndMPw51bYW0D3jviW2Qbl70YcU0Gg,2352 -pytz/zoneinfo/America/Knox_IN,sha256=BiALShjiOLg1o8mMRWJ1jyTlJkgvwzte7B9WSOvTUNg,2428 -pytz/zoneinfo/America/Kralendijk,sha256=ZGEIylAZ5iy_rIBsXREtH_ZfWRIkLI9dQjP_EIyn3sY,186 -pytz/zoneinfo/America/La_Paz,sha256=PAGF2VU_QOw2xT1Cqdp2P8Aj9hXMVWlCByV7cvfIQ_k,232 -pytz/zoneinfo/America/Lima,sha256=JHDCg95uw6BEu4a4Gfyikm1s8rm8AsYPG8dJxQQNZFs,406 -pytz/zoneinfo/America/Los_Angeles,sha256=VOy1PikdjiVdJ7lukVGzwl8uDxV_KYqznkTm5BLEiDM,2836 -pytz/zoneinfo/America/Louisville,sha256=-yqgeeHZdq6oP3_WzVvYOmqV9HQv8y7ZWmc9bzHvJAY,2772 -pytz/zoneinfo/America/Lower_Princes,sha256=ZGEIylAZ5iy_rIBsXREtH_ZfWRIkLI9dQjP_EIyn3sY,186 -pytz/zoneinfo/America/Maceio,sha256=pzjNghmeHhvF4aI3cDq2G_5t71BSNGIbRAF5NmJyDmw,744 -pytz/zoneinfo/America/Managua,sha256=xBzF01AHn2E2fD8Qdy-DHFe36UqoeNpKPfChduBKWdk,430 -pytz/zoneinfo/America/Manaus,sha256=lp6RlkcXJQ7mSsKqnEgC8svJVrFDJk_16xxvfpNSpK4,604 -pytz/zoneinfo/America/Marigot,sha256=17gT2eOVMFKJF_sypwDPudkFwGEijrRfkBU-aK3FL60,148 -pytz/zoneinfo/America/Martinique,sha256=fMs80kOU2YFvC0f9y2eje97JeAtTYBamXrnlTunNLzQ,232 -pytz/zoneinfo/America/Matamoros,sha256=RlEMOT_zvCLQ8s7TNvRE2PnC4H9JrxO7MGxmfu5xPPI,1390 -pytz/zoneinfo/America/Mazatlan,sha256=aIyre-8trAXSHtqxbuu6gDDkWCUjI_SdAKPIjz74M2E,1526 -pytz/zoneinfo/America/Mendoza,sha256=5DJiYYeQpcLBR_IoIJtk43IswJeGYawx5GykszuJ-Nw,1076 -pytz/zoneinfo/America/Menominee,sha256=Arv9WLbfhNcpRsUjHDU757BEdwlp08Gt30AixG3gZ04,2274 -pytz/zoneinfo/America/Merida,sha256=BJQ5mzAT-akb_EA7WqGdNheCorDqLBnDS_4X3YJz0rc,1422 -pytz/zoneinfo/America/Metlakatla,sha256=twmieGTVY2V-U8nFxqvx7asYv8GVjeWdLtrOI7UApVI,1423 -pytz/zoneinfo/America/Mexico_City,sha256=DSpTe5TT0KBsxGx79Rs7ah-zJpiGOJKwPjztovRN0b4,1584 -pytz/zoneinfo/America/Miquelon,sha256=LNbkN87EnZUa41Xizko5VIN55EyQvf5Kk5b5AfNQG8Q,1666 -pytz/zoneinfo/America/Moncton,sha256=Wmv-bk9aKKcWWzOpc1UFu67HOfwaIk2Wmh3LgqGctys,3154 -pytz/zoneinfo/America/Monterrey,sha256=HA4yn9jQHk9i0PqiB7fSoFdzXtB1DT1cheGRPXrQNdQ,1390 -pytz/zoneinfo/America/Montevideo,sha256=4jcgTegK5X8F0yNYzk-3oySZ4U9XQ09UbTJ_mlu8N70,1510 -pytz/zoneinfo/America/Montreal,sha256=ggOSzbHkmfgu9wTQzP0MUKsrKMbgveuAeThh1eFl1a0,3494 -pytz/zoneinfo/America/Montserrat,sha256=17gT2eOVMFKJF_sypwDPudkFwGEijrRfkBU-aK3FL60,148 -pytz/zoneinfo/America/Nassau,sha256=MEpB_L1x3UnwwqjOwNqDvCfgQYPOnhB2jewLwiOxV4g,2388 -pytz/zoneinfo/America/New_York,sha256=7AoiEGjr3wV4P7C4Qs35COZqwr2mjNDq7ocpsSPFOM8,3536 -pytz/zoneinfo/America/Nipigon,sha256=EGPXcOin8mfzFTkYJm4ICpY7fyE24I2pXg4ejafSMyU,2122 -pytz/zoneinfo/America/Nome,sha256=2izM3-P-PqJ9za6MdhzFfMvPFNq7Gim69tAvEwPeY2s,2367 -pytz/zoneinfo/America/Noronha,sha256=3R4lLV8jg5SljhC5OVVCk51Y77Efjo6zCe-oppg_FFo,716 -pytz/zoneinfo/America/North_Dakota/Beulah,sha256=PHlzEk3wsNXYsfMZZSio7ZfdnyxPFpOhK3dS-1AJKGg,2380 -pytz/zoneinfo/America/North_Dakota/Center,sha256=PaM52_JOVMEpVdw5qiOlhkp3qA0xp0d6Z9neOatmLKo,2380 -pytz/zoneinfo/America/North_Dakota/New_Salem,sha256=o0xmH1FUh3lVFLtP5Lb9c0PfSyaPTsRvQSQYwnn_yls,2380 -pytz/zoneinfo/America/Nuuk,sha256=FtlXWP_hBNuwBHkI2b1yne_tSUJpwLtWLyTHZoFZkmM,1878 -pytz/zoneinfo/America/Ojinaga,sha256=cO3V-x_1Q-mpbJgKNd6-WTfxDEHBV1aqS4wzVl5A0Q4,1484 -pytz/zoneinfo/America/Panama,sha256=kayA_pdpMcSQ0FjIzotdcf-m1JYfbKE-qcFT8LC8zqA,182 -pytz/zoneinfo/America/Pangnirtung,sha256=P9Kw_I-NxcUYJIr1j40jTn9q7F8TPAE_FqXsfLYF86A,2094 -pytz/zoneinfo/America/Paramaribo,sha256=Hm5tDwUmnoTrTUPEO4WArfSF74ZjywVEocy4kL51FzA,262 -pytz/zoneinfo/America/Phoenix,sha256=nEOwYOnGxENw9zW8m50PGxbtVfTrX3QYAo4x4LgOLfI,328 -pytz/zoneinfo/America/Port-au-Prince,sha256=09ZAJd4IOiMpfdpUuF1U44R_hRt6BvpAkFXOnYO9yOM,1434 -pytz/zoneinfo/America/Port_of_Spain,sha256=17gT2eOVMFKJF_sypwDPudkFwGEijrRfkBU-aK3FL60,148 -pytz/zoneinfo/America/Porto_Acre,sha256=17onkm8P_VgMkErjK9rr0qwNni7qp9tgcUZ93g3ltOs,628 -pytz/zoneinfo/America/Porto_Velho,sha256=ZRfzgGEu26hnl3JPtiZLOSFGj_WBSbOKdiLC1xIyc5c,576 -pytz/zoneinfo/America/Puerto_Rico,sha256=hJHlV_-AGoMGUWuMpZRv9fLmghrzFHfrR9fRkcxaZJc,246 -pytz/zoneinfo/America/Punta_Arenas,sha256=kpqStczF3X0yK0lwOcxmwbQM8ZV9MrNktm7orJF-EJc,1902 -pytz/zoneinfo/America/Rainy_River,sha256=r6kx6lD2IzCdygkj-DKyL2tPSn7k0Zil7PSHCBFKOa0,2122 -pytz/zoneinfo/America/Rankin_Inlet,sha256=KpQX97-EuF4MNyxQrtOKP616CK_vjniM-lo14WGVz0c,1892 -pytz/zoneinfo/America/Recife,sha256=ijFN2ZzZe5oBYdl8Ag3SwmGjj2JeVYYX2Vo767g2s6I,716 -pytz/zoneinfo/America/Regina,sha256=yjqT08pHbICYe83H8JmtaDBvCFqRv7Tfze3Y8xuXukw,980 -pytz/zoneinfo/America/Resolute,sha256=VP_u5XsepfSwx7Ou9zjGw2p5Qi10AIA54sP1J2DkppM,1892 -pytz/zoneinfo/America/Rio_Branco,sha256=17onkm8P_VgMkErjK9rr0qwNni7qp9tgcUZ93g3ltOs,628 -pytz/zoneinfo/America/Rosario,sha256=1XqIP8Qo2bPR7909hrAI-qAttybmwEW4ms7FjZA5Yfw,1076 -pytz/zoneinfo/America/Santa_Isabel,sha256=OHHtvy3J70z6wvKBHgPqMEnGs6SXp8fkf0WX9ZiOODk,2342 -pytz/zoneinfo/America/Santarem,sha256=Gl_lI3pPZ57UIYXWcmaTpFqWDA5re6bHh1nWs_Z0-Nc,602 -pytz/zoneinfo/America/Santiago,sha256=GB14PW0xABV283dXc8qL-nnDW-ViFUR3bne7sg0Aido,2529 -pytz/zoneinfo/America/Santo_Domingo,sha256=DKtaEj8fQ92ybITTWU4Bm160S9pzJmUVbjaWRnenxU4,458 -pytz/zoneinfo/America/Sao_Paulo,sha256=cO3VGekMGdSf1y4f_UgkpDMRes26-l1oGUoDglIiUQg,1444 -pytz/zoneinfo/America/Scoresbysund,sha256=dfHb86egoiNykb3bR3OHXpGFPm_Apck8BLiVTCqVAVc,1916 -pytz/zoneinfo/America/Shiprock,sha256=6_yPo1_mvnt9DgpPzr0QdHsjdsfUG6ALnagQLML1DSM,2444 -pytz/zoneinfo/America/Sitka,sha256=aiS7Fk37hZpzZ9VkeJQeF-BqTLRC1QOTCgMAJwT8UxA,2329 -pytz/zoneinfo/America/St_Barthelemy,sha256=17gT2eOVMFKJF_sypwDPudkFwGEijrRfkBU-aK3FL60,148 -pytz/zoneinfo/America/St_Johns,sha256=r1-17uKv27eZ3JsVkw_DLZQbo6wvjuuVu7C2pDsmOgI,3655 -pytz/zoneinfo/America/St_Kitts,sha256=17gT2eOVMFKJF_sypwDPudkFwGEijrRfkBU-aK3FL60,148 -pytz/zoneinfo/America/St_Lucia,sha256=17gT2eOVMFKJF_sypwDPudkFwGEijrRfkBU-aK3FL60,148 -pytz/zoneinfo/America/St_Thomas,sha256=17gT2eOVMFKJF_sypwDPudkFwGEijrRfkBU-aK3FL60,148 -pytz/zoneinfo/America/St_Vincent,sha256=17gT2eOVMFKJF_sypwDPudkFwGEijrRfkBU-aK3FL60,148 -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=cJ9lcf2mDZttEx_ttYYoZAJfuGhSsDgNV2PI-ggWdPE,2202 -pytz/zoneinfo/America/Tijuana,sha256=OHHtvy3J70z6wvKBHgPqMEnGs6SXp8fkf0WX9ZiOODk,2342 -pytz/zoneinfo/America/Toronto,sha256=ggOSzbHkmfgu9wTQzP0MUKsrKMbgveuAeThh1eFl1a0,3494 -pytz/zoneinfo/America/Tortola,sha256=17gT2eOVMFKJF_sypwDPudkFwGEijrRfkBU-aK3FL60,148 -pytz/zoneinfo/America/Vancouver,sha256=sknKH0jSPWam-DHfM35qXs8Nam7d5TFlkUI9Sgxryyg,2892 -pytz/zoneinfo/America/Virgin,sha256=17gT2eOVMFKJF_sypwDPudkFwGEijrRfkBU-aK3FL60,148 -pytz/zoneinfo/America/Whitehorse,sha256=Kfv607qGHJxXGBP1nPJyNg2_duWrmxhZGFQr82ukgq8,1614 -pytz/zoneinfo/America/Winnipeg,sha256=7P-_YQrneFcon7QKSTOnkiGjEppFDn3Z48MJ1qq8VBw,2868 -pytz/zoneinfo/America/Yakutat,sha256=tFwnKbvwhyyn4LNTAn5ye_JWDdxjCerNDt7oOwUwO2M,2305 -pytz/zoneinfo/America/Yellowknife,sha256=pfFvC8NEy373KbO6r6ec-Gw_O0D2h64mXU1X1AsUDgE,1966 -pytz/zoneinfo/Antarctica/Casey,sha256=a_ShNA5q27F-GNPiFPttIhhdHc1MP485jX6pwRjZ_t0,384 -pytz/zoneinfo/Antarctica/Davis,sha256=6PokyOaaISRTN13sisuGgdt5vG5A2YqNooJpfLTb5SQ,297 -pytz/zoneinfo/Antarctica/DumontDUrville,sha256=g8HQLY-aN3p6az-04KdHOdZYFnN__-8ltHRuY9eQX-I,194 -pytz/zoneinfo/Antarctica/Macquarie,sha256=ie7RlaU8RHTorVVj-MX8StKMqx_oXf4UH2PUqpzcwe0,2260 -pytz/zoneinfo/Antarctica/Mawson,sha256=9TW1g_z0tk5EfeB7K69VJo8agO7-K9ZxWbiqNKnUZNE,199 -pytz/zoneinfo/Antarctica/McMurdo,sha256=gADjoyPo_QISQU6UJrAgcHp3HDaMoOFRdH-d23uBSyc,2437 -pytz/zoneinfo/Antarctica/Palmer,sha256=DW_DXByXg5MnMZ-w1bNdu8b0lKOYD_EgrPRd5EcyEm4,1418 -pytz/zoneinfo/Antarctica/Rothera,sha256=QQI1m1IN4_2e6Bb0z-rOYaOwxp4XjMJDOKM9SFDUPKg,164 -pytz/zoneinfo/Antarctica/South_Pole,sha256=gADjoyPo_QISQU6UJrAgcHp3HDaMoOFRdH-d23uBSyc,2437 -pytz/zoneinfo/Antarctica/Syowa,sha256=VnmdVypdJUhsBw1XuXZEcEQIFmoiqoYcdpl8ht37QgY,165 -pytz/zoneinfo/Antarctica/Troll,sha256=3zrh-P_jMCss9GGwHJJHkypZZydq4mkgo_TDqctn3c4,1162 -pytz/zoneinfo/Antarctica/Vostok,sha256=6tx86WD3MVGJBCbOJUCoA6YlGwCn2BT4B85Zss0vz4Y,165 -pytz/zoneinfo/Arctic/Longyearbyen,sha256=UdCERhj1JYpx3ojmilaRoyVoR4qMA1-PEv6hGwnpsJA,2228 -pytz/zoneinfo/Asia/Aden,sha256=rq9KPj8l0FBnnKn93WkMeA1IngNtTzk5_oV4sEZhc4w,165 -pytz/zoneinfo/Asia/Almaty,sha256=rBIl_pqZNmKZabjEa4mcsLahl9PbAdZJpQMQLVmcfBU,997 -pytz/zoneinfo/Asia/Amman,sha256=bvwhc1hPCGvQMqWzaoCHrCA_y78n3H-Z2t4wHSocuAw,1853 -pytz/zoneinfo/Asia/Anadyr,sha256=hDDTly45ejoVVP9Al07TmKpTACNGJaIPlcXLRbsG_4g,1188 -pytz/zoneinfo/Asia/Aqtau,sha256=A5exZN256JagFJTcasgdCrQ8giOqZ2EFMRVYBWTaqZA,983 -pytz/zoneinfo/Asia/Aqtobe,sha256=LQ7P5LEEe7jbWbjqvzmM79c0o6AdZeCExQS-fOWp8yw,1011 -pytz/zoneinfo/Asia/Ashgabat,sha256=L4DYV2mZWycsYeHIypXzO6ZNY3tD8wjgxfPR2ZPW26c,619 -pytz/zoneinfo/Asia/Ashkhabad,sha256=L4DYV2mZWycsYeHIypXzO6ZNY3tD8wjgxfPR2ZPW26c,619 -pytz/zoneinfo/Asia/Atyrau,sha256=3uEo89ORyDJqQ_TtaQdIf9UPaB8WqIRQVi0geeY9gVE,991 -pytz/zoneinfo/Asia/Baghdad,sha256=lQMSUnOuijbcoTaCqMNnYhnvKtS2IVP_kXFAzePVNDU,983 -pytz/zoneinfo/Asia/Bahrain,sha256=V0rFJdLHIrToJ5Wl28VzVowwCVZoY8ZZSeNp-7kOvjY,199 -pytz/zoneinfo/Asia/Baku,sha256=vhHnliaOdRyNudl0sFJFdLynEg0Hc0I-IiZNfbDeCbM,1227 -pytz/zoneinfo/Asia/Bangkok,sha256=eYq0vh89N1j069URoQvtBu0ndEal6FPrtbF8WCKKpDw,199 -pytz/zoneinfo/Asia/Barnaul,sha256=2c1Cq8XYlBgybRQMP8w0NCf7kaLDrPZtGn4M5iJZbJo,1221 -pytz/zoneinfo/Asia/Beirut,sha256=_Z_2ZAg_iL9vU51JDB8CB04uXBDrf1kLIis-JnXaS2o,2154 -pytz/zoneinfo/Asia/Bishkek,sha256=do_4ki1JvSKupUrvlz9jRkHspDhdvk1D2IkByFskjJM,983 -pytz/zoneinfo/Asia/Brunei,sha256=BMMjwEmZ9rMoNpWfg8IrlLhRbMKbdW48padRF-FGolc,203 -pytz/zoneinfo/Asia/Calcutta,sha256=6Qw0EDbLcgMgDik8s7UTJn4QSjmllPNeGVJU5rwKF88,285 -pytz/zoneinfo/Asia/Chita,sha256=4ICOcAVAEWnP-cdf_YJu1_kCYnYPG2_vYfSbuNI-VwI,1221 -pytz/zoneinfo/Asia/Choibalsan,sha256=sJQAAjiT9VyG73dYhpYkq4tcmfITcPpiAa8YXsDlKag,949 -pytz/zoneinfo/Asia/Chongqing,sha256=ZP_C5DqUQ1oEPAQNHTr36S0DGtx453N68YYbqk7u8-Y,561 -pytz/zoneinfo/Asia/Chungking,sha256=ZP_C5DqUQ1oEPAQNHTr36S0DGtx453N68YYbqk7u8-Y,561 -pytz/zoneinfo/Asia/Colombo,sha256=HGea9jswIIgz7k20LTzbKtQyUun67IP5HvsZrmAJZJY,372 -pytz/zoneinfo/Asia/Dacca,sha256=3K5llGhcpCdZMMcJuomICVv7lZlDRpU4PUb5DtFx8l4,337 -pytz/zoneinfo/Asia/Damascus,sha256=6mcB6bxH1KsLqzb_LmJUT3tUDnq9_ScLFKoMFkcZy3A,2294 -pytz/zoneinfo/Asia/Dhaka,sha256=3K5llGhcpCdZMMcJuomICVv7lZlDRpU4PUb5DtFx8l4,337 -pytz/zoneinfo/Asia/Dili,sha256=ptjbacc9JK0pv2JpD-gHMglrwYNj9LMMIua0U0ZTMUc,227 -pytz/zoneinfo/Asia/Dubai,sha256=-ga0m3ua9Y6kSWREz2_VdtcVAkq83WrW3vxjBI7WNGs,165 -pytz/zoneinfo/Asia/Dushanbe,sha256=FUk9Tt_GimfRulcWamEvuOvA7FQ52YfZqQ2w88qMx6M,591 -pytz/zoneinfo/Asia/Famagusta,sha256=CFrcygd8ude5x6OEtfM_Dw0KYHoxpPPzq46KoHVxjjc,2028 -pytz/zoneinfo/Asia/Gaza,sha256=LPrVQ4DY43CC-2CnMLx6VEt4IP26P6Jw0HRlhbEbXHo,2422 -pytz/zoneinfo/Asia/Harbin,sha256=ZP_C5DqUQ1oEPAQNHTr36S0DGtx453N68YYbqk7u8-Y,561 -pytz/zoneinfo/Asia/Hebron,sha256=dXAP5ZeuPWJZLh6Y41hEz3owiuqElZxn1SKtdWaeKtw,2450 -pytz/zoneinfo/Asia/Ho_Chi_Minh,sha256=L5TXNg6-odIIn-JAyLTR8fKFiUFBNFwy0HzwZchbnm4,351 -pytz/zoneinfo/Asia/Hong_Kong,sha256=UcnFEc9S8hMWl9giVXni4TAhLPWX0H12XvwSt4AJHew,1203 -pytz/zoneinfo/Asia/Hovd,sha256=JUnOos7PNTi2VRKxD6XnaVR3NpuhsX_Pi18rIzVe1xw,891 -pytz/zoneinfo/Asia/Irkutsk,sha256=iUJZCVBjpfB4rNKJOr6g0zUZtccYYk_Gk0wTklx8Yj0,1243 -pytz/zoneinfo/Asia/Istanbul,sha256=2S0A_f7VxvyErJMMCPqK33AChA29IVkMr1o-SpMtMxk,1947 -pytz/zoneinfo/Asia/Jakarta,sha256=_WRgz6Zb6wxIXtMwpKjG4w4PJtDRzkhdrw-3a4NCBFA,355 -pytz/zoneinfo/Asia/Jayapura,sha256=ihzUd-L8HUVqG-Na10MyPE-YYwjVFj-xerqjTN4EJZs,221 -pytz/zoneinfo/Asia/Jerusalem,sha256=JUuWQmW5Tha0pJjw61Q5aN7CX0z4D7ops9OOSnda6Dc,2388 -pytz/zoneinfo/Asia/Kabul,sha256=ial7SvweHTQXDl79MnXm6QHtiw2i7Zt1e5urLXU8Sq8,208 -pytz/zoneinfo/Asia/Kamchatka,sha256=pBA0RbynKTKsMCmf2hJMZ_hgVUPemms-VceMMJ7QC64,1166 -pytz/zoneinfo/Asia/Karachi,sha256=iB-mWMTXUyfBwAkZdz8_UmEw0xsgxIub-KNI7akzhkk,379 -pytz/zoneinfo/Asia/Kashgar,sha256=AEXDJ5PxQOhePZZw1QZl98moDNa-bW3I3WVNQZHBPYA,165 -pytz/zoneinfo/Asia/Kathmandu,sha256=TUeW7rDSifOTSsNxvo9igIYZfGITEZUf-0EjglyRDWs,212 -pytz/zoneinfo/Asia/Katmandu,sha256=TUeW7rDSifOTSsNxvo9igIYZfGITEZUf-0EjglyRDWs,212 -pytz/zoneinfo/Asia/Khandyga,sha256=XYzE2tsE5Say9pg0cHDQkEE9aTuy2piFSLAGx_d-dmM,1271 -pytz/zoneinfo/Asia/Kolkata,sha256=6Qw0EDbLcgMgDik8s7UTJn4QSjmllPNeGVJU5rwKF88,285 -pytz/zoneinfo/Asia/Krasnoyarsk,sha256=nzRw4PI2AiK_Ge854b8U7TSDw0LGQy3ca5YuOOU2XwI,1207 -pytz/zoneinfo/Asia/Kuala_Lumpur,sha256=RfiIYo6sMEkSA8m5iUmyOyJzKZrgRs8ehGuDZwoq88k,383 -pytz/zoneinfo/Asia/Kuching,sha256=KsAtQ0aocINozixwW7CkorY-1PTLlsj7UUnQGQMEYTQ,483 -pytz/zoneinfo/Asia/Kuwait,sha256=rq9KPj8l0FBnnKn93WkMeA1IngNtTzk5_oV4sEZhc4w,165 -pytz/zoneinfo/Asia/Macao,sha256=MvAkRyRsrA2r052ItlyF5bh2FheRjI0jPwg0uIiH2Yk,1227 -pytz/zoneinfo/Asia/Macau,sha256=MvAkRyRsrA2r052ItlyF5bh2FheRjI0jPwg0uIiH2Yk,1227 -pytz/zoneinfo/Asia/Magadan,sha256=cqwjKQt8TlznM1w2DezAZuz1EjeOfLxPeSY19i9zkfQ,1222 -pytz/zoneinfo/Asia/Makassar,sha256=OhJtCqSTEU-u5n0opBVO5Bu-wQzcYPy9S_6aAhJXgOw,254 -pytz/zoneinfo/Asia/Manila,sha256=ujfq0kl1EhxcYSOrG-FS750aNaYUt1TT4bFuK4EcL_c,328 -pytz/zoneinfo/Asia/Muscat,sha256=-ga0m3ua9Y6kSWREz2_VdtcVAkq83WrW3vxjBI7WNGs,165 -pytz/zoneinfo/Asia/Nicosia,sha256=0Unm0IFT7HyGeQ7F3vTa_-klfysCgrulqFO6BD1plZU,2002 -pytz/zoneinfo/Asia/Novokuznetsk,sha256=vQGcqKdmYmWDdl73QPZTcyadnope1RPJ4oBgZelQu90,1165 -pytz/zoneinfo/Asia/Novosibirsk,sha256=ApL3s20HX2eIAno03HCa2RXdlLotVb9JvnZl7W1sM00,1221 -pytz/zoneinfo/Asia/Omsk,sha256=wxbEesfe7dJOkNPffqTwT6wuTSSTM6E9f0uFMAyzMCM,1207 -pytz/zoneinfo/Asia/Oral,sha256=iMjqD4LvDgyxN15v7CqyEdBDyBFaOlChwX1wHz2JiVQ,1005 -pytz/zoneinfo/Asia/Phnom_Penh,sha256=eYq0vh89N1j069URoQvtBu0ndEal6FPrtbF8WCKKpDw,199 -pytz/zoneinfo/Asia/Pontianak,sha256=inOXwuKtjKv1z_eliPZSIqjSt6whtuxhPeG1YpjU_BQ,353 -pytz/zoneinfo/Asia/Pyongyang,sha256=_-g3GnDAtfDX4XAktXH9jFouLUDmOovnjoOfvRpUDsE,237 -pytz/zoneinfo/Asia/Qatar,sha256=V0rFJdLHIrToJ5Wl28VzVowwCVZoY8ZZSeNp-7kOvjY,199 -pytz/zoneinfo/Asia/Qostanay,sha256=UGYEvmZfAAS9D6EMGd0n6-r_Az_zgTDSWLPeHzFLfu0,1011 -pytz/zoneinfo/Asia/Qyzylorda,sha256=aiSRxwoUbQ-TBHf2wcyaOhQb86j3jQpXwcQaSPnAtwU,1025 -pytz/zoneinfo/Asia/Rangoon,sha256=ZHuX-XVHr8dGJjrPQ5cW7b8jQUv3ihyd-VzN545mlMA,268 -pytz/zoneinfo/Asia/Riyadh,sha256=rq9KPj8l0FBnnKn93WkMeA1IngNtTzk5_oV4sEZhc4w,165 -pytz/zoneinfo/Asia/Saigon,sha256=L5TXNg6-odIIn-JAyLTR8fKFiUFBNFwy0HzwZchbnm4,351 -pytz/zoneinfo/Asia/Sakhalin,sha256=95AdPwOgSe0g9wdx67kKLDbjvY3FtpeVBoAWbJVco0w,1202 -pytz/zoneinfo/Asia/Samarkand,sha256=BBe6Gg_KlSQuS5hAyvvhZWmClcLJaFjnCNGC391HHQM,577 -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=hIgr_LHMTWh3GgeG-MmLHBp-9anUxQcfMlKFtX8WvmU,383 -pytz/zoneinfo/Asia/Srednekolymsk,sha256=0DllW8q5VgXEMV5c_nLJElZsNpauvNhNACQpcgdqEl0,1208 -pytz/zoneinfo/Asia/Taipei,sha256=DMmQwOpPql25ue3Nf8vAKKT4em06D1Z9rHbLIitxixk,761 -pytz/zoneinfo/Asia/Tashkent,sha256=LS-yTxh0v1vmJoQ9I6fY-IERk7ukPmovVx2Ut_-b-Ig,591 -pytz/zoneinfo/Asia/Tbilisi,sha256=w6UNxgyn4BVVTF5WkAtxo_u7nnIY26makKQ5nRgifds,1035 -pytz/zoneinfo/Asia/Tehran,sha256=ATT50Q0hK6uSba5_WnOE3Px0OWxIwxaqK5Oi10P2A-M,2582 -pytz/zoneinfo/Asia/Tel_Aviv,sha256=JUuWQmW5Tha0pJjw61Q5aN7CX0z4D7ops9OOSnda6Dc,2388 -pytz/zoneinfo/Asia/Thimbu,sha256=uia8or5dtDkxVUZrcLwkjbTz9C7ZhLq0T4jlE4YvuvQ,203 -pytz/zoneinfo/Asia/Thimphu,sha256=uia8or5dtDkxVUZrcLwkjbTz9C7ZhLq0T4jlE4YvuvQ,203 -pytz/zoneinfo/Asia/Tokyo,sha256=oCueZgRNxcNcX3ZGdif9y6Su4cyVhga4XHdwlcrYLOs,309 -pytz/zoneinfo/Asia/Tomsk,sha256=77YgdJLxETRKjQjnaHHf54xBAqNywTDwQQmZ5v6Aq28,1221 -pytz/zoneinfo/Asia/Ujung_Pandang,sha256=OhJtCqSTEU-u5n0opBVO5Bu-wQzcYPy9S_6aAhJXgOw,254 -pytz/zoneinfo/Asia/Ulaanbaatar,sha256=uyQSzIBl0f2TXHrmUm3VPs1C9ro013hYmAlx6yUjh3Y,891 -pytz/zoneinfo/Asia/Ulan_Bator,sha256=uyQSzIBl0f2TXHrmUm3VPs1C9ro013hYmAlx6yUjh3Y,891 -pytz/zoneinfo/Asia/Urumqi,sha256=AEXDJ5PxQOhePZZw1QZl98moDNa-bW3I3WVNQZHBPYA,165 -pytz/zoneinfo/Asia/Ust-Nera,sha256=JAZhRAPdbOL9AL-WHOL8aZjxdZxLmGDNBGMCw9TKtR8,1252 -pytz/zoneinfo/Asia/Vientiane,sha256=eYq0vh89N1j069URoQvtBu0ndEal6FPrtbF8WCKKpDw,199 -pytz/zoneinfo/Asia/Vladivostok,sha256=Wokhgtj2nwUj992h7SyfB_fRNHAKfPNzhsf_oZpim8c,1208 -pytz/zoneinfo/Asia/Yakutsk,sha256=RVCIl52EvMrp2RG2hg2cjDSr9QhsscaAT-NV81xw7zc,1207 -pytz/zoneinfo/Asia/Yangon,sha256=ZHuX-XVHr8dGJjrPQ5cW7b8jQUv3ihyd-VzN545mlMA,268 -pytz/zoneinfo/Asia/Yekaterinburg,sha256=NzVc2DiPeyw0FdMHwSPQJF9k3tvWdtrETZiN58pyxLk,1243 -pytz/zoneinfo/Asia/Yerevan,sha256=k0WHtWQW_cBCjcEv8nP01cVPeTVDlf18lQ0_u6cin1o,1151 -pytz/zoneinfo/Atlantic/Azores,sha256=ut7TdE-xiQNjRybg56Tt5b7Zo5zqbuF5IFci2aDMs1Q,3484 -pytz/zoneinfo/Atlantic/Bermuda,sha256=LNGKfMsnYvwImjTyzXrLhMOHHDu7qI67RbYNKvvI15I,2396 -pytz/zoneinfo/Atlantic/Canary,sha256=ymK9ufqphvNjDK3hzikN4GfkcR3QeCBiPKyVc6FjlbA,1897 -pytz/zoneinfo/Atlantic/Cape_Verde,sha256=ESQvE3deMI-lx9mG0yJLEsFX5KRl-7c6gD5O2h0Zm9Q,270 -pytz/zoneinfo/Atlantic/Faeroe,sha256=NibdZPZtapnYR_myIZnMdTaSKGsOBGgujj0_T2NvAzs,1815 -pytz/zoneinfo/Atlantic/Faroe,sha256=NibdZPZtapnYR_myIZnMdTaSKGsOBGgujj0_T2NvAzs,1815 -pytz/zoneinfo/Atlantic/Jan_Mayen,sha256=UdCERhj1JYpx3ojmilaRoyVoR4qMA1-PEv6hGwnpsJA,2228 -pytz/zoneinfo/Atlantic/Madeira,sha256=e1K2l8ykd8xpznQNs3SSuIZ1ZfVx2Y69EXrhvYV3P14,3475 -pytz/zoneinfo/Atlantic/Reykjavik,sha256=mSkaRBGZLeUrm88EeHcaWnEd35Wn-Ag2G10HtI3G2fg,1162 -pytz/zoneinfo/Atlantic/South_Georgia,sha256=QZ72fRKp6Kgvy7DfyHGht1MVnzGgSPujLQd4XMjNrrc,164 -pytz/zoneinfo/Atlantic/St_Helena,sha256=0u-sTl8j2IyV1ywdtCgHFw9S9D3ZiiBa9akqkbny2Zc,148 -pytz/zoneinfo/Atlantic/Stanley,sha256=exKMLw-P952wS1FTxVjnUU1mkD2OvKUDwtDt8IGgf8w,1214 -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=LxEuFWyMse_cALVtRWCkf6sIIEk13jQ4JXW8k2agSd8,470 -pytz/zoneinfo/Australia/Hobart,sha256=GLQSzgIfsWxOvmKOrhpfofWqINQf6h36NYy3mcq6gcg,2358 -pytz/zoneinfo/Australia/LHI,sha256=Luf0Lx_iJHuh3kZd4LxRjf36tLF5-wW2UFMVNKNT7gg,1860 -pytz/zoneinfo/Australia/Lindeman,sha256=xM6Udx22oLNoLR1Y7GQhHOYov8nw3xQNqgc_NVQ2JK4,475 -pytz/zoneinfo/Australia/Lord_Howe,sha256=Luf0Lx_iJHuh3kZd4LxRjf36tLF5-wW2UFMVNKNT7gg,1860 -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=17onkm8P_VgMkErjK9rr0qwNni7qp9tgcUZ93g3ltOs,628 -pytz/zoneinfo/Brazil/DeNoronha,sha256=3R4lLV8jg5SljhC5OVVCk51Y77Efjo6zCe-oppg_FFo,716 -pytz/zoneinfo/Brazil/East,sha256=cO3VGekMGdSf1y4f_UgkpDMRes26-l1oGUoDglIiUQg,1444 -pytz/zoneinfo/Brazil/West,sha256=lp6RlkcXJQ7mSsKqnEgC8svJVrFDJk_16xxvfpNSpK4,604 -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=Kfv607qGHJxXGBP1nPJyNg2_duWrmxhZGFQr82ukgq8,1614 -pytz/zoneinfo/Chile/Continental,sha256=GB14PW0xABV283dXc8qL-nnDW-ViFUR3bne7sg0Aido,2529 -pytz/zoneinfo/Chile/EasterIsland,sha256=paHp1QRXIa02kgd0-4V6vWXdqcwheow-hJQD9VqacfQ,2233 -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=L6zLQLnQtLkEELOGfm6USaHY33qAEPgGV822-iU1vxc,1955 -pytz/zoneinfo/Eire,sha256=-JSA3vsi44F1DE8supVjSppH2Vpp12WjJI0_COtAmqU,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=pw8HngVt3bU5QrRzu70qOmf69TIyklkglvVUte9ntKo,2910 -pytz/zoneinfo/Europe/Andorra,sha256=gTB5jCQmvIw3JJi1_vAcOYuhtzPBR6RXUx9gVV6p6ug,1742 -pytz/zoneinfo/Europe/Astrakhan,sha256=ywtzL92KVfoybOmAhE9eHqmMcvJZm5b0js5GDdWIJEQ,1165 -pytz/zoneinfo/Europe/Athens,sha256=XDY-FBUddRyQHN8GxQLZ4awjuOlWlzlUdjv7OdXFNzA,2262 -pytz/zoneinfo/Europe/Belfast,sha256=xp08wV44TZMmAdBqppttDChQAb8tRN03GcEht99RYtY,3648 -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=q7iAbkd7y9QvbAi6XGZEUOTwNDCRYWRu9VQCxUrZ01U,2137 -pytz/zoneinfo/Europe/Dublin,sha256=-JSA3vsi44F1DE8supVjSppH2Vpp12WjJI0_COtAmqU,3492 -pytz/zoneinfo/Europe/Gibraltar,sha256=egOcazf2u1njGZ0tDj-f1NzZT_K5rpUKSqtShxO7U6c,3052 -pytz/zoneinfo/Europe/Guernsey,sha256=xp08wV44TZMmAdBqppttDChQAb8tRN03GcEht99RYtY,3648 -pytz/zoneinfo/Europe/Helsinki,sha256=GEkB7LsVhmegt7YuuWheCDvDGC7b7Nw9bTdDGS9qkJc,1900 -pytz/zoneinfo/Europe/Isle_of_Man,sha256=xp08wV44TZMmAdBqppttDChQAb8tRN03GcEht99RYtY,3648 -pytz/zoneinfo/Europe/Istanbul,sha256=2S0A_f7VxvyErJMMCPqK33AChA29IVkMr1o-SpMtMxk,1947 -pytz/zoneinfo/Europe/Jersey,sha256=xp08wV44TZMmAdBqppttDChQAb8tRN03GcEht99RYtY,3648 -pytz/zoneinfo/Europe/Kaliningrad,sha256=s7GXSe1YvMcs7AiUhHNTA6I4nAOQn_Kmz_ZqJYO-LMM,1493 -pytz/zoneinfo/Europe/Kiev,sha256=iVkTPFkl2tADYapa1HASlaV3tT2VsJpTPTTJC_9HtAk,2088 -pytz/zoneinfo/Europe/Kirov,sha256=Sr4HEUwk3tPTXioeCLhvlgKbCAFU7Gy2UB3f--uWLDc,1153 -pytz/zoneinfo/Europe/Lisbon,sha256=L6n3snx6pNHHJIL6JOLFOAlYkQ2J5uB_y5MG_Ic_PDU,3469 -pytz/zoneinfo/Europe/Ljubljana,sha256=OpWtsGFWBE_S-mYoQcAmjCta9HwbGQANnSmVY9OHCTo,1920 -pytz/zoneinfo/Europe/London,sha256=xp08wV44TZMmAdBqppttDChQAb8tRN03GcEht99RYtY,3648 -pytz/zoneinfo/Europe/Luxembourg,sha256=974Dvf_X1QISKG1zIiTJJIfGavobO21HUVS-HfysOcY,2946 -pytz/zoneinfo/Europe/Madrid,sha256=MTTMnrbDDtexRikd72-FbQEpCZjc63_UtBIiDomD95c,2614 -pytz/zoneinfo/Europe/Malta,sha256=xRwBfrV8hOihGtqcek5_B6l5hjc206g3yfbEWXIaUis,2620 -pytz/zoneinfo/Europe/Mariehamn,sha256=GEkB7LsVhmegt7YuuWheCDvDGC7b7Nw9bTdDGS9qkJc,1900 -pytz/zoneinfo/Europe/Minsk,sha256=mn86zdrNWpJYDfE51Iy9n1-Zi2piTyb9EPaS2A-uGJQ,1321 -pytz/zoneinfo/Europe/Monaco,sha256=50uVZXYXXqfnr-K4tsSNl26CZbRju65C-STp818wX84,2944 -pytz/zoneinfo/Europe/Moscow,sha256=KmkofRcj6T8Ph28PJChm8JVp13uRvef6TZ0GuPzUiDw,1535 -pytz/zoneinfo/Europe/Nicosia,sha256=0Unm0IFT7HyGeQ7F3vTa_-klfysCgrulqFO6BD1plZU,2002 -pytz/zoneinfo/Europe/Oslo,sha256=UdCERhj1JYpx3ojmilaRoyVoR4qMA1-PEv6hGwnpsJA,2228 -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=-X5F_d3Dz0kBRWiUTXUN-fgeCHbUEHLaaHIwEPZEdUQ,2641 -pytz/zoneinfo/Europe/Samara,sha256=z2innqSZ8_lkEy8cIyF9JM_FfnO2sWZaqeFqOh8pD7M,1215 -pytz/zoneinfo/Europe/San_Marino,sha256=-X5F_d3Dz0kBRWiUTXUN-fgeCHbUEHLaaHIwEPZEdUQ,2641 -pytz/zoneinfo/Europe/Sarajevo,sha256=OpWtsGFWBE_S-mYoQcAmjCta9HwbGQANnSmVY9OHCTo,1920 -pytz/zoneinfo/Europe/Saratov,sha256=BMej49HlQG24CWCh5VOENrB3jPuJPScPszRtb7MrJ3I,1183 -pytz/zoneinfo/Europe/Simferopol,sha256=_M6LXB5Rqh932nKIJotGjT8YNszAOb7RjHN5ng-uW1Y,1453 -pytz/zoneinfo/Europe/Skopje,sha256=OpWtsGFWBE_S-mYoQcAmjCta9HwbGQANnSmVY9OHCTo,1920 -pytz/zoneinfo/Europe/Sofia,sha256=hCQKXfMNrnA5xHNw_uzTjKzVw4-Bvsq5oGO4yUCv5tY,2077 -pytz/zoneinfo/Europe/Stockholm,sha256=Xgp4GSh8-pzdeJeP8TQ20jWDDUj17R69h6RYTbLYd2g,1909 -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=nFsgcVTmTiiFzHtyJDRnO-3H4GRAfAeceb6b2jFHLUQ,1267 -pytz/zoneinfo/Europe/Uzhgorod,sha256=TIG1rC4QR7nz-vO1VtmN9mDMVjKPDKi7mEB9KpfJOBA,2050 -pytz/zoneinfo/Europe/Vaduz,sha256=K5QY7Ujj2VUchKR4bhhb0hgdAJhmwED71ykXDQOGKe8,1909 -pytz/zoneinfo/Europe/Vatican,sha256=-X5F_d3Dz0kBRWiUTXUN-fgeCHbUEHLaaHIwEPZEdUQ,2641 -pytz/zoneinfo/Europe/Vienna,sha256=ZmI3kADE6bnrJEccqh73XXBY36L1G4DkpiTQImtNrUk,2200 -pytz/zoneinfo/Europe/Vilnius,sha256=UFzRX3orCTB8d9IzlxJPy5eUA2oBPuCu1UJl-2D7C3U,2162 -pytz/zoneinfo/Europe/Volgograd,sha256=XZNEUXwnmGdOTld_9Lug2CFfXbFCJFZC45nOMb59FRk,1165 -pytz/zoneinfo/Europe/Warsaw,sha256=TiLDPbeVF0ckgLVEkaSeDaKZ8wctdJDOl_HE_Wd5rKs,2654 -pytz/zoneinfo/Europe/Zagreb,sha256=OpWtsGFWBE_S-mYoQcAmjCta9HwbGQANnSmVY9OHCTo,1920 -pytz/zoneinfo/Europe/Zaporozhye,sha256=V0dhGl3gET8OftMezf8CVy-W00Z7FtuEev5TjI2Rnyw,2106 -pytz/zoneinfo/Europe/Zurich,sha256=K5QY7Ujj2VUchKR4bhhb0hgdAJhmwED71ykXDQOGKe8,1909 -pytz/zoneinfo/Factory,sha256=aFFlKx93HXoJoF4SSuTlD8cZtJA-ne5oKzAa6eX2V4k,116 -pytz/zoneinfo/GB,sha256=xp08wV44TZMmAdBqppttDChQAb8tRN03GcEht99RYtY,3648 -pytz/zoneinfo/GB-Eire,sha256=xp08wV44TZMmAdBqppttDChQAb8tRN03GcEht99RYtY,3648 -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=UcnFEc9S8hMWl9giVXni4TAhLPWX0H12XvwSt4AJHew,1203 -pytz/zoneinfo/Iceland,sha256=mSkaRBGZLeUrm88EeHcaWnEd35Wn-Ag2G10HtI3G2fg,1162 -pytz/zoneinfo/Indian/Antananarivo,sha256=yJsuJTqJJqbOz37_NOS_zbf-JNr_IthHGMMN7sDqSWg,265 -pytz/zoneinfo/Indian/Chagos,sha256=23B26pwwK0gxW7TP76GltyY-RU_o6RGGSrF93pF7S1E,199 -pytz/zoneinfo/Indian/Christmas,sha256=J4I0WDX_LYAJxsx2vU0EdxFJQKRE-rRL1UvNQv09pCs,165 -pytz/zoneinfo/Indian/Cocos,sha256=PX-k8JpghajjvhljtBjWozaiu9NhUSpVeoACy2cAxN8,174 -pytz/zoneinfo/Indian/Comoro,sha256=yJsuJTqJJqbOz37_NOS_zbf-JNr_IthHGMMN7sDqSWg,265 -pytz/zoneinfo/Indian/Kerguelen,sha256=oIvd6bmQFMLUefoBn4c1fQTOAawGcrPcmge2jU7BsYo,165 -pytz/zoneinfo/Indian/Mahe,sha256=ZNXjaoL_o6572xXgsgSmbd5D_SkaCaayolpSN1je82w,165 -pytz/zoneinfo/Indian/Maldives,sha256=dUQBbrmoB3odWsMt3K1YUnB447A6nkW3aR1aHzdLF7M,199 -pytz/zoneinfo/Indian/Mauritius,sha256=k6vWUVcfU3gS1K12e_aMw6BeSdMvdLyCJRCAL7CD0go,241 -pytz/zoneinfo/Indian/Mayotte,sha256=yJsuJTqJJqbOz37_NOS_zbf-JNr_IthHGMMN7sDqSWg,265 -pytz/zoneinfo/Indian/Reunion,sha256=lHnSVh7CYCuDBEM4dYsWDk006BSAznkCPxjiTtL_WiI,165 -pytz/zoneinfo/Iran,sha256=ATT50Q0hK6uSba5_WnOE3Px0OWxIwxaqK5Oi10P2A-M,2582 -pytz/zoneinfo/Israel,sha256=JUuWQmW5Tha0pJjw61Q5aN7CX0z4D7ops9OOSnda6Dc,2388 -pytz/zoneinfo/Jamaica,sha256=wlagieUPRf5-beie-h7QsONbNzjGsm8vMs8uf28pw28,482 -pytz/zoneinfo/Japan,sha256=oCueZgRNxcNcX3ZGdif9y6Su4cyVhga4XHdwlcrYLOs,309 -pytz/zoneinfo/Kwajalein,sha256=L4nH3qxv5EBKVRxYt67b9IfZfBzg5KJk19iu7x3oBMk,316 -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=OHHtvy3J70z6wvKBHgPqMEnGs6SXp8fkf0WX9ZiOODk,2342 -pytz/zoneinfo/Mexico/BajaSur,sha256=aIyre-8trAXSHtqxbuu6gDDkWCUjI_SdAKPIjz74M2E,1526 -pytz/zoneinfo/Mexico/General,sha256=DSpTe5TT0KBsxGx79Rs7ah-zJpiGOJKwPjztovRN0b4,1584 -pytz/zoneinfo/NZ,sha256=gADjoyPo_QISQU6UJrAgcHp3HDaMoOFRdH-d23uBSyc,2437 -pytz/zoneinfo/NZ-CHAT,sha256=lkVqaSF1WWpv_B2K-k2uJp2setRVK6XbjsQ38gDGVEg,2068 -pytz/zoneinfo/Navajo,sha256=6_yPo1_mvnt9DgpPzr0QdHsjdsfUG6ALnagQLML1DSM,2444 -pytz/zoneinfo/PRC,sha256=ZP_C5DqUQ1oEPAQNHTr36S0DGtx453N68YYbqk7u8-Y,561 -pytz/zoneinfo/PST8PDT,sha256=Q7TCLkE69a6g7mPoPAkqhg-0dStyiAC0jVlM72KG_R8,2310 -pytz/zoneinfo/Pacific/Apia,sha256=p1vFsjfezDCHmPOnmgG47q7wTPM5feosoWN3ucgGnrw,1097 -pytz/zoneinfo/Pacific/Auckland,sha256=gADjoyPo_QISQU6UJrAgcHp3HDaMoOFRdH-d23uBSyc,2437 -pytz/zoneinfo/Pacific/Bougainville,sha256=ZKDa_S_2gSlmOWizV1DqxH3wbE58rfK1vKZHZqrrtjI,268 -pytz/zoneinfo/Pacific/Chatham,sha256=lkVqaSF1WWpv_B2K-k2uJp2setRVK6XbjsQ38gDGVEg,2068 -pytz/zoneinfo/Pacific/Chuuk,sha256=6IYDKViuRDC_RVx1AJOxazVET6cZtdv_LFE6xbtGItI,269 -pytz/zoneinfo/Pacific/Easter,sha256=paHp1QRXIa02kgd0-4V6vWXdqcwheow-hJQD9VqacfQ,2233 -pytz/zoneinfo/Pacific/Efate,sha256=pG4NMVeM3hBJTZnZmqeLqz3Q5oCggTW4HO-R9Fe926A,538 -pytz/zoneinfo/Pacific/Enderbury,sha256=zqW7qAC_6FTcgrGEMhpIsl1oV9I46gY2nH3pwadll68,234 -pytz/zoneinfo/Pacific/Fakaofo,sha256=gow-SgE5r5c8J_Ag5nvJ5SUPDg6yH8pth_a-QLDcPv8,200 -pytz/zoneinfo/Pacific/Fiji,sha256=W6rxVK44zQaoLWLexVRoav16jMcuWYbNskIa5Ld9H-Q,1077 -pytz/zoneinfo/Pacific/Funafuti,sha256=P-XYwlWQpWvS3Q_TYFe37BrgxKJy5tg7PHEQNCDGv5U,166 -pytz/zoneinfo/Pacific/Galapagos,sha256=MdtlC-ffp8reICzDxsQ8tWMsTkq5ZcN-j3OyyhjokV8,238 -pytz/zoneinfo/Pacific/Gambier,sha256=z6eYF8sszLjkfpqmWnbBBAUB-ibaR5nodKaAYbvXOe0,164 -pytz/zoneinfo/Pacific/Guadalcanal,sha256=6GX-XpxcCyA64qUMdxJMFMq4sPk0ZjhexqGbryzfgjE,166 -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/Kiritimati,sha256=VHR3iuwiv3tx65WtitVHCoQEg3VJd812VZ5djuSyUxc,238 -pytz/zoneinfo/Pacific/Kosrae,sha256=Vm5AKI6NvuYSz58s8922WNIiWoqPcix2JOJOix1mlSU,351 -pytz/zoneinfo/Pacific/Kwajalein,sha256=L4nH3qxv5EBKVRxYt67b9IfZfBzg5KJk19iu7x3oBMk,316 -pytz/zoneinfo/Pacific/Majuro,sha256=Dwqh7gXoz7Duwu1n7XF8yEjhM4ULEs42LSQyy7F-qzQ,310 -pytz/zoneinfo/Pacific/Marquesas,sha256=uzsjVolutGRXp_FRnvXoU0ApDEb4ZaYoz_r60D7jufg,173 -pytz/zoneinfo/Pacific/Midway,sha256=fCYrYphYY6rUfxOw712y5cyRe104AC3pouqD3bCINFg,175 -pytz/zoneinfo/Pacific/Nauru,sha256=oGxocYsqssZ_EeQHf3cUP5cg0qtqzx1BzoEjVWjE_7g,252 -pytz/zoneinfo/Pacific/Niue,sha256=lSsVlJJ458vNuIgjZESQyatsJV3LpWGyHqbYXMXPjZ4,241 -pytz/zoneinfo/Pacific/Norfolk,sha256=CdEXM9SKYC9Wn7aMxD2sV5i8zE88NQo25Z_L874JthI,880 -pytz/zoneinfo/Pacific/Noumea,sha256=FSanpAOCE7WHQeiop4QErKV9ZC3Tzu2GxkH8-tIXsHY,304 -pytz/zoneinfo/Pacific/Pago_Pago,sha256=fCYrYphYY6rUfxOw712y5cyRe104AC3pouqD3bCINFg,175 -pytz/zoneinfo/Pacific/Palau,sha256=CRW__McXPlOaxo2S9kHMHaBdjv7u59ZWEwYuJConzmQ,180 -pytz/zoneinfo/Pacific/Pitcairn,sha256=O65Ed1FOCF_0rEjpYPAquDwtAF3hxyJNiujgpgZV0kc,202 -pytz/zoneinfo/Pacific/Pohnpei,sha256=YqXrKwjhUnxWyV6PFg1L6_zu84MfPW82dypf0S7pHtQ,303 -pytz/zoneinfo/Pacific/Ponape,sha256=YqXrKwjhUnxWyV6PFg1L6_zu84MfPW82dypf0S7pHtQ,303 -pytz/zoneinfo/Pacific/Port_Moresby,sha256=ei_XjmiRDLh-RU94uvz9CCIIRFH1r0X7WL-sB-6DF60,186 -pytz/zoneinfo/Pacific/Rarotonga,sha256=UfUhlaG0u7yOlzoKnHE9pRiHqQ2N_M9n5WHaCCwtbV4,577 -pytz/zoneinfo/Pacific/Saipan,sha256=Ex9znmf6rNfGze6gNpZJCMr1TT4rkl2SnrhecrdJufI,494 -pytz/zoneinfo/Pacific/Samoa,sha256=fCYrYphYY6rUfxOw712y5cyRe104AC3pouqD3bCINFg,175 -pytz/zoneinfo/Pacific/Tahiti,sha256=9iozXRFYDhBOLijmDk2mRS4Mb-LXWW1u7n790jBNKxM,165 -pytz/zoneinfo/Pacific/Tarawa,sha256=vT6UxW7KeGptdh80Fj9ASATGmLx8Wai630lML4mwg80,166 -pytz/zoneinfo/Pacific/Tongatapu,sha256=ht8ZhdveQXJqsxYtSEcqmRTzXA3OtqYoi4WVBvOPGhw,372 -pytz/zoneinfo/Pacific/Truk,sha256=6IYDKViuRDC_RVx1AJOxazVET6cZtdv_LFE6xbtGItI,269 -pytz/zoneinfo/Pacific/Wake,sha256=dTJxldgcad-kGrODwo4cAHGRSsS-K3fjeZ62WEUhmFk,166 -pytz/zoneinfo/Pacific/Wallis,sha256=CAlw1H5gkER5lkvtmHY-ppoGL3hNmYxfMaXQpI0fTOE,166 -pytz/zoneinfo/Pacific/Yap,sha256=6IYDKViuRDC_RVx1AJOxazVET6cZtdv_LFE6xbtGItI,269 -pytz/zoneinfo/Poland,sha256=TiLDPbeVF0ckgLVEkaSeDaKZ8wctdJDOl_HE_Wd5rKs,2654 -pytz/zoneinfo/Portugal,sha256=L6n3snx6pNHHJIL6JOLFOAlYkQ2J5uB_y5MG_Ic_PDU,3469 -pytz/zoneinfo/ROC,sha256=DMmQwOpPql25ue3Nf8vAKKT4em06D1Z9rHbLIitxixk,761 -pytz/zoneinfo/ROK,sha256=LI9LsV3XcJC0l-KoQf8zI-y7rk-du57erS-N2Ptdi7Q,617 -pytz/zoneinfo/Singapore,sha256=hIgr_LHMTWh3GgeG-MmLHBp-9anUxQcfMlKFtX8WvmU,383 -pytz/zoneinfo/Turkey,sha256=2S0A_f7VxvyErJMMCPqK33AChA29IVkMr1o-SpMtMxk,1947 -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=nEOwYOnGxENw9zW8m50PGxbtVfTrX3QYAo4x4LgOLfI,328 -pytz/zoneinfo/US/Central,sha256=4aZFw-svkMyXmSpNufqzK-xveos-oVJDpEyI8Yu9HQE,3576 -pytz/zoneinfo/US/East-Indiana,sha256=GrNub1_3Um5Qh67wOx58_TEAz4fwAeAlk2AlMTVA_sI,1666 -pytz/zoneinfo/US/Eastern,sha256=7AoiEGjr3wV4P7C4Qs35COZqwr2mjNDq7ocpsSPFOM8,3536 -pytz/zoneinfo/US/Hawaii,sha256=fwPRv1Jk56sCOi75uZfd_Iy2k2aSQHx3B2K5xUlSPzM,329 -pytz/zoneinfo/US/Indiana-Starke,sha256=BiALShjiOLg1o8mMRWJ1jyTlJkgvwzte7B9WSOvTUNg,2428 -pytz/zoneinfo/US/Michigan,sha256=hecz8yqY2Cj5B61G3gLZdAVZvRgK9l0P90c_gN-uD5g,2230 -pytz/zoneinfo/US/Mountain,sha256=6_yPo1_mvnt9DgpPzr0QdHsjdsfUG6ALnagQLML1DSM,2444 -pytz/zoneinfo/US/Pacific,sha256=VOy1PikdjiVdJ7lukVGzwl8uDxV_KYqznkTm5BLEiDM,2836 -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=BMh_yY7MXp8DMEy71jarFX3IJSNpwuEyIjIo2HKUXD4,4463 -pytz/zoneinfo/leapseconds,sha256=WFKV3wNak8BTFEaUwFFeLO5bUOa0moZ3S-255JLAank,3392 -pytz/zoneinfo/tzdata.zi,sha256=35McqINLMRv5Nhy80Nw8u3IhmB4nL9cSWWhZiSl3_nk,113161 -pytz/zoneinfo/zone.tab,sha256=2wzsaOCfYuhhMxZsFO9y1ckAPgD4uzBfbff64XV1qWU,19321 -pytz/zoneinfo/zone1970.tab,sha256=EBkiCpmeio73EQXCl7T9lGFBT19NJwWPw8tqkCc0QRI,17835 diff --git a/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/WHEEL b/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/WHEEL deleted file mode 100644 index 7332a41..0000000 --- a/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/WHEEL +++ /dev/null @@ -1,6 +0,0 @@ -Wheel-Version: 1.0 -Generator: bdist_wheel (0.30.0) -Root-Is-Purelib: true -Tag: py2-none-any -Tag: py3-none-any - diff --git a/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/metadata.json b/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/metadata.json deleted file mode 100644 index 1a0df75..0000000 --- a/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/metadata.json +++ /dev/null @@ -1 +0,0 @@ -{"classifiers": ["Development Status :: 6 - Mature", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 2", "Programming Language :: Python :: 2.4", "Programming Language :: Python :: 2.5", "Programming Language :: Python :: 2.6", "Programming Language :: Python :: 2.7", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3.1", "Programming Language :: Python :: 3.2", "Programming Language :: Python :: 3.3", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Topic :: Software Development :: Libraries :: Python Modules"], "download_url": "https://pypi.org/project/pytz/", "extensions": {"python.details": {"contacts": [{"email": "stuart@stuartbishop.net", "name": "Stuart Bishop", "role": "author"}, {"email": "stuart@stuartbishop.net", "name": "Stuart Bishop", "role": "maintainer"}], "document_names": {"description": "DESCRIPTION.rst", "license": "LICENSE.txt"}, "project_urls": {"Home": "http://pythonhosted.org/pytz"}}}, "generator": "bdist_wheel (0.30.0)", "keywords": ["timezone", "tzinfo", "datetime", "olson", "time"], "license": "MIT", "metadata_version": "2.0", "name": "pytz", "platform": "Independent", "summary": "World timezone definitions, modern and historical", "version": "2021.1"} \ No newline at end of file diff --git a/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/top_level.txt b/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/top_level.txt deleted file mode 100644 index af44f19..0000000 --- a/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -pytz diff --git a/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/zip-safe b/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/zip-safe deleted file mode 100644 index 8b13789..0000000 --- a/venv/lib/python3.8/site-packages/pytz-2021.1.dist-info/zip-safe +++ /dev/null @@ -1 +0,0 @@ - diff --git a/venv/lib/python3.8/site-packages/pytz/__init__.py b/venv/lib/python3.8/site-packages/pytz/__init__.py deleted file mode 100644 index e2f49fa..0000000 --- a/venv/lib/python3.8/site-packages/pytz/__init__.py +++ /dev/null @@ -1,1558 +0,0 @@ -''' -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 = '2021a' -VERSION = '2021.1' # 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.path.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) # 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 = \ -['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/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/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/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 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/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/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_Velho', - 'America/Puerto_Rico', - 'America/Punta_Arenas', - 'America/Rainy_River', - '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/Thunder_Bay', - 'America/Tijuana', - 'America/Toronto', - 'America/Tortola', - 'America/Vancouver', - '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/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/Kiev', - 'Europe/Kirov', - '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/Uzhgorod', - 'Europe/Vaduz', - 'Europe/Vatican', - 'Europe/Vienna', - 'Europe/Vilnius', - 'Europe/Volgograd', - 'Europe/Warsaw', - 'Europe/Zagreb', - 'Europe/Zaporozhye', - '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/Enderbury', - 'Pacific/Fakaofo', - 'Pacific/Fiji', - 'Pacific/Funafuti', - 'Pacific/Galapagos', - 'Pacific/Gambier', - 'Pacific/Guadalcanal', - 'Pacific/Guam', - 'Pacific/Honolulu', - '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/venv/lib/python3.8/site-packages/pytz/exceptions.py b/venv/lib/python3.8/site-packages/pytz/exceptions.py deleted file mode 100644 index 4b20bde..0000000 --- a/venv/lib/python3.8/site-packages/pytz/exceptions.py +++ /dev/null @@ -1,59 +0,0 @@ -''' -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/venv/lib/python3.8/site-packages/pytz/lazy.py b/venv/lib/python3.8/site-packages/pytz/lazy.py deleted file mode 100644 index 39344fc..0000000 --- a/venv/lib/python3.8/site-packages/pytz/lazy.py +++ /dev/null @@ -1,172 +0,0 @@ -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/venv/lib/python3.8/site-packages/pytz/reference.py b/venv/lib/python3.8/site-packages/pytz/reference.py deleted file mode 100644 index f765ca0..0000000 --- a/venv/lib/python3.8/site-packages/pytz/reference.py +++ /dev/null @@ -1,140 +0,0 @@ -''' -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/venv/lib/python3.8/site-packages/pytz/tzfile.py b/venv/lib/python3.8/site-packages/pytz/tzfile.py deleted file mode 100644 index 99e7448..0000000 --- a/venv/lib/python3.8/site-packages/pytz/tzfile.py +++ /dev/null @@ -1,133 +0,0 @@ -''' -$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/venv/lib/python3.8/site-packages/pytz/tzinfo.py b/venv/lib/python3.8/site-packages/pytz/tzinfo.py deleted file mode 100644 index 725978d..0000000 --- a/venv/lib/python3.8/site-packages/pytz/tzinfo.py +++ /dev/null @@ -1,577 +0,0 @@ -'''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/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Abidjan b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Abidjan deleted file mode 100644 index 28b32ab2e0b9053f39a91d9f28b6072e41423954..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 148 zcmWHE%1kq2zzZ0GvP?kCG3nVP561uh|5!kkv-tRiFt`J82nmM#2LhZ1aRE&;-~s@2 CSQl9U diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Accra b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Accra deleted file mode 100644 index d0083ed886487a1594af7f5f8897cf45885aeb71..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1060 zcmc)IO-K}B9LMolU9`4Ph=heO9`X<s*tB^H1u5tSG6=RyQHP?!PLI%`KtYNKZ$-f_ zMer<Ut=Y>U%UWioiMqK#Q51n@Eh<6~Jaq6-;Pn4KT{;Dxnqi*LvU6D2-#2-<^;E+9 z=hY-{E96;wqxO13W;oZG`7vj^8&anGL#yqnDXO0QEq!Nk$=pr7wb@Sz)q6gw?+p&9 zz9U`w{>^XZLF15p*s)$cs<k>ecF+W2o$YV_X!=W8o7)gmxtG&AU*2T$x2x^IT$_4) zX_tO7zNiLI7xdHYCNs46mwncCR6XCkRlhiM#SE`HZbw>b%*gizJ6gX_jlNl@$Ew@S zSa86O+dxfRy`T%*R-0F6EA`}>W>q}2!xk?$cD^gUKR1<`Qqw#8;-4>8nVGto^p}&@ z%-4z&>C)~ARa!{JXE**dvxUj@{K|SY-@6nqi!AFdFN^+lhhg}dzcv~~qUgmuuX2S~ z#Tk*4Z}zt&y)C|<@Vz~MK5h5C<T6H)-v}878OJFDAtO0uC}b?B42Fz`42O(|42X<~ z42g`142q1342z8Gl!1|voia2swo?X2Mt92a$oNPANCZd-NDN32NEApINE}EYNF+`P z1&PHe!64B%B^)FkBp@UrBqSszBq*mug@lE~g#?B~hJ=R1h6IO1=ale}_?!|T5~1^d Kg&312{n&46P#a+Y diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Addis_Ababa b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Addis_Ababa deleted file mode 100644 index 9dcfc19c56e62b12b730f4335b34479695f273f5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 265 zcmWHE%1kq2zzbM`vLGzd{r}>hjqh$nY&rhm!ojy|BhKVhU14NmWM*PuP-+1gp{&8c z!oZ+qz`(`8ptgpA55o5G4PnqWFfuk^aCHQ;OiUR<NU-)l5P+-((ID$VG{^}c8srQR OO@ULmfUeRt<^llo>q3(N diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Algiers b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Algiers deleted file mode 100644 index 6cfd8a16e16ec08c7cd83e6c0e1f9e1bbc5dc18a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 735 zcmc(cy)Q#y6o=1kuUi`BDmsWkq>~`2@DC^<QQAZkG?I2|h~>s0jTmZVtF=Cg8YM;% z1B<e#ucV1s?QddN@6#F#7L)Vlp6BG;+~mH`FP>OV56Q39_`U7bWbVr9mP^H=`H76m zSNfgZ%bc@!HL3QuKAnR?pDLtI)M2(+9S!=`@p?oRM>bXQ+;VQJmQ$L)$d+E43gw+) z`(az;aW!B+%><p7DUb7h|12MiXUdhiR_^ev@|7#nayq73GYPSm7Ht1o*lACXW;>D_ zc4ssxhUs$uIHuL0k7?<xhrwf7BCa?6v*HSgDbiva^}G1kiSFG!MjLwx)Za#?;}X-) z-1salE@6hS9z+a-kK%vuRMoX|mk&aGL7dg7y+PbT{6QQ-JVIPTd_tT;yh7a8sQp45 zLp;~0T|<0BoI|`r+(Z0BGJxd3eaQln2P6}UTp-y{<O9hFk`p8=_+NQ>b$A0I?-yD7 B^{M~> diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Asmara b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Asmara deleted file mode 100644 index 9dcfc19c56e62b12b730f4335b34479695f273f5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 265 zcmWHE%1kq2zzbM`vLGzd{r}>hjqh$nY&rhm!ojy|BhKVhU14NmWM*PuP-+1gp{&8c z!oZ+qz`(`8ptgpA55o5G4PnqWFfuk^aCHQ;OiUR<NU-)l5P+-((ID$VG{^}c8srQR OO@ULmfUeRt<^llo>q3(N diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Asmera b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Asmera deleted file mode 100644 index 9dcfc19c56e62b12b730f4335b34479695f273f5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 265 zcmWHE%1kq2zzbM`vLGzd{r}>hjqh$nY&rhm!ojy|BhKVhU14NmWM*PuP-+1gp{&8c z!oZ+qz`(`8ptgpA55o5G4PnqWFfuk^aCHQ;OiUR<NU-)l5P+-((ID$VG{^}c8srQR OO@ULmfUeRt<^llo>q3(N diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Bamako b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Bamako deleted file mode 100644 index 28b32ab2e0b9053f39a91d9f28b6072e41423954..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 148 zcmWHE%1kq2zzZ0GvP?kCG3nVP561uh|5!kkv-tRiFt`J82nmM#2LhZ1aRE&;-~s@2 CSQl9U diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Bangui b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Bangui deleted file mode 100644 index afb6a4a8fb17b0d4670b8ea1b38f5cc6100244e4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 235 zcmWHE%1kq2zzbM_vLGzfwz}YAPe200v{lX*7Y4qsU}RuoW?*2}hw28ZVdr4rU|`@A xVBqud4PkHxVr>HhV*`e8#}I}P5^VYp1R&c$G{{B}4YCzPlWsE?(0W}%E&#<UE%N{X diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Banjul b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Banjul deleted file mode 100644 index 28b32ab2e0b9053f39a91d9f28b6072e41423954..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 148 zcmWHE%1kq2zzZ0GvP?kCG3nVP561uh|5!kkv-tRiFt`J82nmM#2LhZ1aRE&;-~s@2 CSQl9U diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Bissau b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Bissau deleted file mode 100644 index 82ea5aaf0c6ae2b3ec582013b6d16e6d6f29eb0a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 194 zcmWHE%1kq2zyQoZ5fBCeCLji}c_uxZGl4TbQGk)@|NoCE3=BZ>0|N_42?K|ZZwP~~ ffgyuCkY->6p%4;G{tpBo(?LcNZvz+5G6OCE+{Pmd diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Blantyre b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Blantyre deleted file mode 100644 index 52753c0f87bbfa457ada89d400908a3d6537ac0e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 149 zcmWHE%1kq2zzZ0GvP?kC(d2gY3y>q%15z%dz`)|;8^Yl17{U-jf+7Eb0H;A*K+|-M FxBzz~6CMBn diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Brazzaville b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Brazzaville deleted file mode 100644 index afb6a4a8fb17b0d4670b8ea1b38f5cc6100244e4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 235 zcmWHE%1kq2zzbM_vLGzfwz}YAPe200v{lX*7Y4qsU}RuoW?*2}hw28ZVdr4rU|`@A xVBqud4PkHxVr>HhV*`e8#}I}P5^VYp1R&c$G{{B}4YCzPlWsE?(0W}%E&#<UE%N{X diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Bujumbura b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Bujumbura deleted file mode 100644 index 52753c0f87bbfa457ada89d400908a3d6537ac0e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 149 zcmWHE%1kq2zzZ0GvP?kC(d2gY3y>q%15z%dz`)|;8^Yl17{U-jf+7Eb0H;A*K+|-M FxBzz~6CMBn diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Cairo b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Cairo deleted file mode 100644 index d3f819623fc9ef90d327380fad15341ec1a0e202..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1955 zcmdVaZ)nw39LMo<r_Onu>Ge-G^V-ra*L3BUZ7pvu|6G|i=@<8oQbzt(p;QznmXNO4 zL87pXustvmRJ5YhGPA6O3K`U#)lS9~6!a`2m)ShcP1()0&imNI2zt<iz8ChoY!CM2 zyg%vXkFG2ee|tm!`fZbw@1vCa(c1ixY0Wh1BUdh%wy(PM(WCE&U!S>If3v&OeEVgu zZhv*9(eJL&-#s6iV=uiIbd^6GcJ-D7=SH@K=Q=|D%lV8w|M3&z*Y+mcy{SiB_+X#3 zYYNqG8-KDr%a@6Z4U=T=oDHh4cB{NJC8jQyAG4PSlcN8+Y}w!0CNlk%_V>dB>dL7@ zcHpgb>W>3Ga`1)yLTo9tkySsdtfpmh$l|ydT7Oy&o3UMFFNoRUxg9E}ASrXYM~LXK zXKb`Rp+=q^u(^9bSEG)U%4=Th6Qg%NV#hpPq+&0>F2~l^iE&TH<@kzDG2!08UYj>w zP2AROCuXWep4?&cPBp4Yy$O5$A)zLBNEzQcTTI!%!``4)sr*eR<c;;4#niQRa@xXt zQSi`oSy-4-HzmH1)3aX`Me$3v=<H{zSTx$=wkkEFbB~<4t3i|;{=wd|;ca#6wsB_G z<GH%Dsn3)x>DITcIALZNYkhlFiz$zOs4I$&hZPswgUXyw!^-dX26uM75zg7y93)zw z4ex4R9n5{_!LX{~{^0J7Yt6j620j0&I<p{As~6rk*CfXd1dB@Z%_8$yP#w!M)t|)l zV*8_6@=8l^&&fzwQ-4s`tbf4NyqO77tM4$W-RpJg<bg0<urA1o{70W5S^xaG`hSIp z*Sgmyif2XKQ=FVHMqK?~votM|$rL}*{5_KX7w>t{-E#+*?n2(R*S&4zeIsuidFRMm zN8UT~=8<=gynW>TBMl%OcwGxf4_?;<(go56(g)HA(h1TE(hJfI(hbrM(ht%Q(vjD- zg!JTfO(9(&Z6SRjjiK+1FSN$F-hk$i?vVC4`a>Gz=n!cU>Cx+&<ml4t+C=(98bvxq zTIJ{!X%^`gX_up4q+yPZk(QC3y{>7FuDz~pq;I5gq;sToj^2^xk?xW9Ir>L7fMW-c zEkO1F*#wSV@Vae4_QC5m0@(><D>(K7*$iYiknKSB1KAK{N02Q+_5|4!WLLayTabP6 zx{X102H6^9Z;;JFb_dxWWPgwiLUst*B4m${O+t3b>$VBmC$HNmWT%j=LiP&TEU()w auiGwUzr1e4yl%(v|FmUMH)<ti(LVwBTA^S7 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Casablanca b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Casablanca deleted file mode 100644 index 17e0d1b89f093e1e4452a8921ffff9a91287eb4c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2429 zcmcJQZA{f=7{(6@js%r8B1c<28Kg-Lahh2PIb5j$fd}w_h{lYUfN?xIBExYAK?j5~ zN2HwLok)yOU`q0qqQ<KdDvSY2jhRMUQOIoQu+ekf_cuNiTkC&z_B;1;KZji(eitV+ zG9h-A;UAx!dh4Ly&Yy=ovb9gUT02aq%^gEy*4{5yjo)5#%5eMlrQ=hcmN%!a{9$%X zJYaQfPab#r#o6He-rM5~y8NsQ3nt8q`a-NOOUume^<NpDU7Rw$X~WOfP0dTpTV8NC zZ27F;{Lb(tYru|s=D^|xYtZWa@po-R!H&%o>~mZN$5l{B`ll2!c#XC?l+xCu56QT8 z9~rBkC*$y2Dl{OB!k&(zu=EiXR%K7&FR!KWNnhG#JV@IzPb<??p~^I%C_+7;2$PW_ z{(MD6*3Y5HNt@d4d5O07FIG`K{uK2%UPYJGQgq)U+GR1RU6f8Ser+n|BM-IPEs1sq zUZeNNTvhBduTor7ri!~iq7n+1Q9?_gN{qXq5{n*C@|yK3ImxC{obFP}YfmWiPzddD zsU=IzBV`#isl7Qwd+XX%YUlz=%}b)R<=?0@(-3|9aEaRIovA+Q>7w*`%V>Z39<{%( zh%zics*JDKt2uTvUUO&6Gxt2twV&l{divpANU+ew&K@*4;<JH2+c^dVh8nz9`snvc zL+HN?)26@A!c6N2(tr>Lggi_w5D1Ath{V(~fe?zRrQ$$ZET)zVgkX3e83@rp$Ob|< z5YmAV4-e!6As|yr2tq`rmJx)IAfyB#CI~q}2ns?{rWTc{Wd$KDQ%eg%T&9*6guqNK zF;j~SLS_&`Gqu!AEj9?bnOblVk~6jFAY^B1;Xz2x)Z#O>{2&Uz)Fl8>1g0(nh(a)R zDL@p1smlSPAWU5n5Jh3?vVbTIQ<nxraX^#@M1h#PL?DX9)MWxuD5fqIh+;8yxj+<* zsY?c;Xduc4qHs)IIuONU>hggoAXAqRL=l;~j35dLqLd(t38I`J3d+<a1yNL{E-RS1 zIh&YP$(f~AD9l+wlJmfr_>%1*IdfV!5cW9}u?jp?SWV0>$(b7;t}y4GkevCxe-Y;V zWXW0J`~lAe{*v?XPfsfBkGM<D!p2747miBKqX%E)`RK)LX3>rwWzbJi-UQFZUa#|9 z93wf8+1=suW9ua6@xff)m&}u#w(?1yZ9hoP(sc2?^qk}*qxemklJlfG$M;W~Bxl)V zB>(+Wo*8^z-rB))`D4jhQIf*v6}^(P(&EPZN|Kyaepx(MrAp2-ZeD!<OrYef{;iky zHSUtLw#kp@+WV68?2%Evf40Sm&+DS4M|DM#^Ze>5K0lu%IUAhH_<qAW$=NvM!gG_0 z<ZP~~=ljj0lJi2&PTpUrlbkKaZk}86B<JPj@_*s7=?gx;GC9KE|IS--w)Pz2^EL;` z*<S9=`}RJ`*=e!y+*v6(uWsJR_pe$dXZLfz^1eGra(+K%;<?8|a$avW@cru(9(;bY zFq!9@oszRJ-j&b$PDsvv-*0)}pCma4oL}O3z+Z9>-nqf|hukISt;RIo-x`&i!#VeO f9=^Eo|Ne2C?T_GpyEprv(D`rZA5-5IKJ)(u0)S^{ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Ceuta b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Ceuta deleted file mode 100644 index 850c8f06fa7918684e67e9ab8192ac933dac90b3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2036 zcmdtiUr3dA9LMqJsm>Iq?(0}J%Ca)EKPNqEx@wx$Nu^C|=BezDnPpbX&Q50~+DcC( z{X^t?Aw@)+QCP@wZP>c7h@v7XBnXR&2#WqPN>))r#Qok6gI(-uH@n#H;W@8|0|(B< z^ZxjjuCGY7{&B+0H{6_BbMrhTWIn#XwI%Sw5&z0o*Q-G5Q@?ex^LS6&@l@-l=J|nB zyFamh-n-TMCEyA5CIn~pUVIe@-%uY4zp}CC!)K9JWLaKMRA+W5y7BkGM>h*Yl6W*Q z>`aR_vOy(o+YT938I;k>SId}upTuY8$XIuVB*Z4lxX4c>(dE^|w^MZd;{=`1Jwzv7 z4%12P@6~<mxlV4nt4a0OG<ow`^^~8~l#)A=8f=%etPYv7V85h~I4l{d)soRyCsT(v z>D2pWGOf2tr=Ro6=l6;=v!ztCI;QK4U9&X%P^`|Zh}T*5(`0t8OTFd8Wlq9V&GGh0 zuB%h?;vY!f%O^5-;02l6bydE2bX2}<YnA-#=e3}*LFWB<MCbec@>Ro5EnK`$7gVm% zqR%STm!GE#htAVQ?g_f+okxoY=SuPIk9Eo0@v`*SH@d7lLY6njNJ;x|vZC&_ls0wA z%F=Er+x|jVWuKANCD*k)?x3v6YSW7F)4Fzq>e^=qbX{Li*I%vCukZVG!--{Dd1aGq z+>@pLmLmCPU7QAXrOT$mObJ#Dm2Xo<%I2IuWJ`=CRmp?3s^_6pN59kR8<(W!<sIF6 zsztu*>d<WmFY5NT!&+N&OzRr!)E;0D82H!4vvUn{eemC0{r$az%!|h{MvEQ(_p=pc zS+S$+7{0fn@(X;{;vDWGpXD_VULMS`E!%c}WZS-f@xJ$)Q=4(xLf(7i-ACSkN7De( z0n!4}1JVT21=0r6hofnPzeXpHrWK?Y4$UClAnhRiAPpfMacBwY326%H3TX@J3uz4L z3~3GN&CxW6bceKu^oKNvbcnQw^oTTxbcwWy^ocZzbc(c!^y+AuMY?q~?IQgm4I>>R zEh9Z6O(R_+Z6kdnjU$~Sts}i7%_H4An)Z?Y9nA(HJAiBfvIoc}AiIEU1F{duMj$(Z zYz49x$YvnB;b^u4*$+pvA;^v(TY~HfvMI=}AlriM3$iiD&LCTZ><zLx$nGH9gY1u^ z*&t+xkS#*?2-zfLmym5j_6gZ2WT%j=LiP&TEM&Kk?Lzj;(QFv9V~%FakUc{-4cRqh j+mL-jHV*%9I~QU0Z*mF)=q^Z0N>B2*3sO9ooEGsXevbCe diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Conakry b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Conakry deleted file mode 100644 index 28b32ab2e0b9053f39a91d9f28b6072e41423954..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 148 zcmWHE%1kq2zzZ0GvP?kCG3nVP561uh|5!kkv-tRiFt`J82nmM#2LhZ1aRE&;-~s@2 CSQl9U diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Dakar b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Dakar deleted file mode 100644 index 28b32ab2e0b9053f39a91d9f28b6072e41423954..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 148 zcmWHE%1kq2zzZ0GvP?kCG3nVP561uh|5!kkv-tRiFt`J82nmM#2LhZ1aRE&;-~s@2 CSQl9U diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Dar_es_Salaam b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Dar_es_Salaam deleted file mode 100644 index 9dcfc19c56e62b12b730f4335b34479695f273f5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 265 zcmWHE%1kq2zzbM`vLGzd{r}>hjqh$nY&rhm!ojy|BhKVhU14NmWM*PuP-+1gp{&8c z!oZ+qz`(`8ptgpA55o5G4PnqWFfuk^aCHQ;OiUR<NU-)l5P+-((ID$VG{^}c8srQR OO@ULmfUeRt<^llo>q3(N diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Djibouti b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Djibouti deleted file mode 100644 index 9dcfc19c56e62b12b730f4335b34479695f273f5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 265 zcmWHE%1kq2zzbM`vLGzd{r}>hjqh$nY&rhm!ojy|BhKVhU14NmWM*PuP-+1gp{&8c z!oZ+qz`(`8ptgpA55o5G4PnqWFfuk^aCHQ;OiUR<NU-)l5P+-((ID$VG{^}c8srQR OO@ULmfUeRt<^llo>q3(N diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Douala b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Douala deleted file mode 100644 index afb6a4a8fb17b0d4670b8ea1b38f5cc6100244e4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 235 zcmWHE%1kq2zzbM_vLGzfwz}YAPe200v{lX*7Y4qsU}RuoW?*2}hw28ZVdr4rU|`@A xVBqud4PkHxVr>HhV*`e8#}I}P5^VYp1R&c$G{{B}4YCzPlWsE?(0W}%E&#<UE%N{X diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/El_Aaiun b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/El_Aaiun deleted file mode 100644 index 64f1b7694418a8c284febe195659c4dd53359b1a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2295 zcmcJQe@xV69LK*HFcQRDGivllPlja@Lz-n)!W^#9fWSNOKqO<vk37bCIU>VxM4$sA zZjO<1!_Oqfhy<pj{7}&X10@u13~<z#WwaF=kd0b4dfuPU|HW#3Z})xe^E}Vp-rK$2 z_qC+vWIkj3?PbxszWQxCA2U1UKhj?9|6_m=@Wv~%D+Z&SfmQSNm7YYW>B$Cr%$6UV zF+Hp8+aC`$wtqNke|7SbGj{hKdt7a&Gk!zm>}zhK1iv0ih&ZkivYIHd@O?@gzeYQJ z>S>4VZ8C2>NaohZ$UOP7vcx7)(nD#KR5+!QTD&Rw>5Y`U5J@}DhiPZ=XUh7ZMOnub zrKr1<Vl`9Bug|H}bIT}o!L4?!xkS50A699@(Uf*CTcy{vQ@Up*?QvMu9x9}asD734 zPKeqYWTU-t*XYfeRVwq5=P9eZSY^#ksT|i@%IS?$`?7AReKmI}_u0)V*XCAv{@+vH z3->GgL?Z1swUeXmcjcJ2ssm+22RiyyzGVgFSJ<dv-RG*nIzjLLwptwwFIMjj4^pA; zS~}FYUmfz)P?6(XRrKj*<#pe(rM`T;m-t#-{Dll-adB?e@HUJ<lb0X=wgI?%>3g8b z@QaPJ7-8!pj8J~BH!T0`K)3!lJFuuPc!2MN3ry_;E;s?g3lMIA@B@S+AUt7eS3vl} z)XsqL2825x`~l$*2#-Lx#MC}9wNoIxVrsWQ_{G$Yf$)r}U1MtBKsX1&JEnGzsr>`t zAX9q?!bPU`5rmUW?Ij2|nc7dLb`*rCOzkQNUzyrj5Z*GiyCD2!YKK91%+xM}@R_Nd z2H`bRyA8r`5RQZJoT*(0;X6}155jw<b{~ZQOx*zxJz(lCfan8=PJrkIQ+ESIKbX2B zAbP^oT>;S-rtS=g-hk*1i2i`+5QrWzb(cW&iK#mU7H=yhrc-j3s4#`OBwliUFeAQ{ zhDgq`zAc3PviVE}9&xo2b5L@YXD2Jn<tHR(W#pfPxiVLBRt3Dpb5*qD{OG#}6!xow zC8w*ai}zjAlJn@{CwM-3v6NY}dsrFzs;QXgxi<7go@+BC=P|F_ynbwx<UBrJ&ii$~ zlGEL|z_a@s$yr}0zSp0ToMaZisaSHJRA>17Nvq^+SV-mX|71-OuQ&F6#dG65$=Otw z$LmcuC1<lEi1(XGa<)X3@Z6FwIZp+J^7&J7lC$;ao4nr^EIHe|qj+wglbolkr}_Np zUVmQiNS7XU)JV>=8~)(+vo^`u>EFQTJ2y$rt_c&*-6qM|({_%}_e@L93uUkK{)G<7 z*=ru+xwk@cUS22v3zw}Q^ZFMHQ~dca!zE|m@DX0`_mP}e8pC=2ibrw|INUrBG)vB_ z+qUxgt4_%|^yp8#KNK%Hzn-!3JRBl9ulE^z{`!0fuaCHLc^(;%oSy7eyzV(6IY%SU z^Zuw!a*hQ&#q(IS<Q%_!gU?R{OU_$e1-yT2T5?X7-Qjui;@1D=8MM@A)qgwpZ=Q6^ NU((OK$gqgze*t`MAnyPG diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Freetown b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Freetown deleted file mode 100644 index 28b32ab2e0b9053f39a91d9f28b6072e41423954..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 148 zcmWHE%1kq2zzZ0GvP?kCG3nVP561uh|5!kkv-tRiFt`J82nmM#2LhZ1aRE&;-~s@2 CSQl9U diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Gaborone b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Gaborone deleted file mode 100644 index 52753c0f87bbfa457ada89d400908a3d6537ac0e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 149 zcmWHE%1kq2zzZ0GvP?kC(d2gY3y>q%15z%dz`)|;8^Yl17{U-jf+7Eb0H;A*K+|-M FxBzz~6CMBn diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Harare b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Harare deleted file mode 100644 index 52753c0f87bbfa457ada89d400908a3d6537ac0e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 149 zcmWHE%1kq2zzZ0GvP?kC(d2gY3y>q%15z%dz`)|;8^Yl17{U-jf+7Eb0H;A*K+|-M FxBzz~6CMBn diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Johannesburg b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Johannesburg deleted file mode 100644 index b1c425daced454f53d7d18fea807bf8d081cf97e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 246 zcmWHE%1kq2zzf)bvMfN%*#IP(+|Fm5S=ZBWc3ytLxxT!H^L2p*jLb|x$iN`w093#r zDgjchWxxm|WfT}#e0)O~f*pfH7(z&}>OT<VRy#U?Xpog48e}bq23ZZFLDqw45}d#V Ja)_=G7XY`-JQ4r^ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Juba b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Juba deleted file mode 100644 index 06482943a45a58a02a43b9e2b6a3f215b21b045f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 679 zcmcK1IZFdU7=Yo~TqbLx#%oPXa6t<(2ofx8#EXD<z(BUr!l{fFVqqs3tW*#ie}Ih# zh?R}4jR<yQD;8s=g%*}pI`7&m7S1yJ3@i-n`vnWD%VqK7>a}0vc4x1SA0EY#XPnJp z8QJ<U(Z!mMsk(`ezUsudG7UYxO!|{1C92vLea3y-m5nB0(l=?DxqdNCr(?SLJg!=H zHe`11S+&;Ablb|EYM&|Tj_C{4Sz3}_|AFdCAL?9kUFF_xW&VBNbn97JxL-5H%eo%f zuK3E!%ZT&K6O9N_JmJR%hMbrX1z)5%i_G_VZaxrG6IEV;sMsC+p~R<MVGZuLMSv<u z8Ke$U2&sgWLTVw!kZMS|P+Jcvh*U&MA~lhsNL8dPQWq(VR7Of8wUOdTb)<Z#t&dCq VnF2BiWE#js@PDS_+VKpQ-7oqQgq8pR diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Kampala b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Kampala deleted file mode 100644 index 9dcfc19c56e62b12b730f4335b34479695f273f5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 265 zcmWHE%1kq2zzbM`vLGzd{r}>hjqh$nY&rhm!ojy|BhKVhU14NmWM*PuP-+1gp{&8c z!oZ+qz`(`8ptgpA55o5G4PnqWFfuk^aCHQ;OiUR<NU-)l5P+-((ID$VG{^}c8srQR OO@ULmfUeRt<^llo>q3(N diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Khartoum b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Khartoum deleted file mode 100644 index 8ee8cb92e72d9c507ad0ee06dc6a38406ab06f34..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 679 zcmcK1yDtPm9Ki9}d%0V8IInXYHlYv~iCh#K@yaFQkxX*ipfJ@Pg(!3qm#dJ7#vh;& z5>aWi8j<Kms~U-ff<i~dd{<8tW;6SlWRpqu`}3F9$_4S`>a$;?cBe0o?}a$Z7-wrl zhPFRUc)6k@s%oNRFFH1%OkJ-h<KC1>h>~_izi}USWxa`+<aJV}uAWW9$+&Jji>jub zO_|<%Qq7f9-LiVCT4(dRZRT9H=T~HA;6QaG4|O)ap|Y<xvh!`<bm=*nyIVKi7gar4 zD|(CXk22)^@`OV|^wjvV!C@yNM9vcl&LZ`Fo?r0A^kj*bFN${ie<<;3S5SldZ4saf zQU<Am6hbN?rI1=kF{Bz&F3{FP3L+Jel1NRYC{h(Ei_}F5BbAZTNNuDzQXMHDXzL>r WK&F690+|Lf5&WO2xOO~41@{Xi&4u6q diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Kigali b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Kigali deleted file mode 100644 index 52753c0f87bbfa457ada89d400908a3d6537ac0e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 149 zcmWHE%1kq2zzZ0GvP?kC(d2gY3y>q%15z%dz`)|;8^Yl17{U-jf+7Eb0H;A*K+|-M FxBzz~6CMBn diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Kinshasa b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Kinshasa deleted file mode 100644 index afb6a4a8fb17b0d4670b8ea1b38f5cc6100244e4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 235 zcmWHE%1kq2zzbM_vLGzfwz}YAPe200v{lX*7Y4qsU}RuoW?*2}hw28ZVdr4rU|`@A xVBqud4PkHxVr>HhV*`e8#}I}P5^VYp1R&c$G{{B}4YCzPlWsE?(0W}%E&#<UE%N{X diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Lagos b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Lagos deleted file mode 100644 index afb6a4a8fb17b0d4670b8ea1b38f5cc6100244e4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 235 zcmWHE%1kq2zzbM_vLGzfwz}YAPe200v{lX*7Y4qsU}RuoW?*2}hw28ZVdr4rU|`@A xVBqud4PkHxVr>HhV*`e8#}I}P5^VYp1R&c$G{{B}4YCzPlWsE?(0W}%E&#<UE%N{X diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Libreville b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Libreville deleted file mode 100644 index afb6a4a8fb17b0d4670b8ea1b38f5cc6100244e4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 235 zcmWHE%1kq2zzbM_vLGzfwz}YAPe200v{lX*7Y4qsU}RuoW?*2}hw28ZVdr4rU|`@A xVBqud4PkHxVr>HhV*`e8#}I}P5^VYp1R&c$G{{B}4YCzPlWsE?(0W}%E&#<UE%N{X diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Lome b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Lome deleted file mode 100644 index 28b32ab2e0b9053f39a91d9f28b6072e41423954..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 148 zcmWHE%1kq2zzZ0GvP?kCG3nVP561uh|5!kkv-tRiFt`J82nmM#2LhZ1aRE&;-~s@2 CSQl9U diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Luanda b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Luanda deleted file mode 100644 index afb6a4a8fb17b0d4670b8ea1b38f5cc6100244e4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 235 zcmWHE%1kq2zzbM_vLGzfwz}YAPe200v{lX*7Y4qsU}RuoW?*2}hw28ZVdr4rU|`@A xVBqud4PkHxVr>HhV*`e8#}I}P5^VYp1R&c$G{{B}4YCzPlWsE?(0W}%E&#<UE%N{X diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Lubumbashi b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Lubumbashi deleted file mode 100644 index 52753c0f87bbfa457ada89d400908a3d6537ac0e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 149 zcmWHE%1kq2zzZ0GvP?kC(d2gY3y>q%15z%dz`)|;8^Yl17{U-jf+7Eb0H;A*K+|-M FxBzz~6CMBn diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Lusaka b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Lusaka deleted file mode 100644 index 52753c0f87bbfa457ada89d400908a3d6537ac0e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 149 zcmWHE%1kq2zzZ0GvP?kC(d2gY3y>q%15z%dz`)|;8^Yl17{U-jf+7Eb0H;A*K+|-M FxBzz~6CMBn diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Malabo b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Malabo deleted file mode 100644 index afb6a4a8fb17b0d4670b8ea1b38f5cc6100244e4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 235 zcmWHE%1kq2zzbM_vLGzfwz}YAPe200v{lX*7Y4qsU}RuoW?*2}hw28ZVdr4rU|`@A xVBqud4PkHxVr>HhV*`e8#}I}P5^VYp1R&c$G{{B}4YCzPlWsE?(0W}%E&#<UE%N{X diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Maputo b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Maputo deleted file mode 100644 index 52753c0f87bbfa457ada89d400908a3d6537ac0e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 149 zcmWHE%1kq2zzZ0GvP?kC(d2gY3y>q%15z%dz`)|;8^Yl17{U-jf+7Eb0H;A*K+|-M FxBzz~6CMBn diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Maseru b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Maseru deleted file mode 100644 index b1c425daced454f53d7d18fea807bf8d081cf97e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 246 zcmWHE%1kq2zzf)bvMfN%*#IP(+|Fm5S=ZBWc3ytLxxT!H^L2p*jLb|x$iN`w093#r zDgjchWxxm|WfT}#e0)O~f*pfH7(z&}>OT<VRy#U?Xpog48e}bq23ZZFLDqw45}d#V Ja)_=G7XY`-JQ4r^ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Mbabane b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Mbabane deleted file mode 100644 index b1c425daced454f53d7d18fea807bf8d081cf97e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 246 zcmWHE%1kq2zzf)bvMfN%*#IP(+|Fm5S=ZBWc3ytLxxT!H^L2p*jLb|x$iN`w093#r zDgjchWxxm|WfT}#e0)O~f*pfH7(z&}>OT<VRy#U?Xpog48e}bq23ZZFLDqw45}d#V Ja)_=G7XY`-JQ4r^ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Mogadishu b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Mogadishu deleted file mode 100644 index 9dcfc19c56e62b12b730f4335b34479695f273f5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 265 zcmWHE%1kq2zzbM`vLGzd{r}>hjqh$nY&rhm!ojy|BhKVhU14NmWM*PuP-+1gp{&8c z!oZ+qz`(`8ptgpA55o5G4PnqWFfuk^aCHQ;OiUR<NU-)l5P+-((ID$VG{^}c8srQR OO@ULmfUeRt<^llo>q3(N diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Monrovia b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Monrovia deleted file mode 100644 index 6d688502a1ca80f2e57a6de2790ac3193879d248..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 208 zcmWHE%1kq2zzdjxvMfN%(*PtE#OKUmJ{6V6$i)2r|JNrB3}BK4NKOJPVqoC#@eN_{ i1!8v~4k5w#|3DB`wQLTE23Z5Nje!KKxPbN<Z~*`$;xdl_ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Nairobi b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Nairobi deleted file mode 100644 index 9dcfc19c56e62b12b730f4335b34479695f273f5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 265 zcmWHE%1kq2zzbM`vLGzd{r}>hjqh$nY&rhm!ojy|BhKVhU14NmWM*PuP-+1gp{&8c z!oZ+qz`(`8ptgpA55o5G4PnqWFfuk^aCHQ;OiUR<NU-)l5P+-((ID$VG{^}c8srQR OO@ULmfUeRt<^llo>q3(N diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Ndjamena b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Ndjamena deleted file mode 100644 index a968845e29b8b2b47d4a73f74ae04ef681d7d485..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 199 zcmWHE%1kq2zzdjxvLMVm=~+XHP+DPuu-d%@MkYoE20j^(Mm_-s76t|x1x5}Z-w=jy gM-UDUVF)3?<o`ebG96?b$OaHioGn~H`*aPt03MDSkpKVy diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Niamey b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Niamey deleted file mode 100644 index afb6a4a8fb17b0d4670b8ea1b38f5cc6100244e4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 235 zcmWHE%1kq2zzbM_vLGzfwz}YAPe200v{lX*7Y4qsU}RuoW?*2}hw28ZVdr4rU|`@A xVBqud4PkHxVr>HhV*`e8#}I}P5^VYp1R&c$G{{B}4YCzPlWsE?(0W}%E&#<UE%N{X diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Nouakchott b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Nouakchott deleted file mode 100644 index 28b32ab2e0b9053f39a91d9f28b6072e41423954..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 148 zcmWHE%1kq2zzZ0GvP?kCG3nVP561uh|5!kkv-tRiFt`J82nmM#2LhZ1aRE&;-~s@2 CSQl9U diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Ouagadougou b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Ouagadougou deleted file mode 100644 index 28b32ab2e0b9053f39a91d9f28b6072e41423954..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 148 zcmWHE%1kq2zzZ0GvP?kCG3nVP561uh|5!kkv-tRiFt`J82nmM#2LhZ1aRE&;-~s@2 CSQl9U diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Porto-Novo b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Porto-Novo deleted file mode 100644 index afb6a4a8fb17b0d4670b8ea1b38f5cc6100244e4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 235 zcmWHE%1kq2zzbM_vLGzfwz}YAPe200v{lX*7Y4qsU}RuoW?*2}hw28ZVdr4rU|`@A xVBqud4PkHxVr>HhV*`e8#}I}P5^VYp1R&c$G{{B}4YCzPlWsE?(0W}%E&#<UE%N{X diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Sao_Tome b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Sao_Tome deleted file mode 100644 index 59f3759c409a1fb50e632ef5ef613d3fee7af7ef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 254 zcmWHE%1kq2zyPd35fBCe79a+(c^ZJkq-T8%QJx(FF<QGPFfuU%<=6rk82<nNo(z-( z0iXz<00Rev?c*E5;10y$jv+t+Mvx$o2qD4F|3DCD^Va}GgX{(w0kR)NQ{o0LptB6P E0Q0IRegFUf diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Timbuktu b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Timbuktu deleted file mode 100644 index 28b32ab2e0b9053f39a91d9f28b6072e41423954..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 148 zcmWHE%1kq2zzZ0GvP?kCG3nVP561uh|5!kkv-tRiFt`J82nmM#2LhZ1aRE&;-~s@2 CSQl9U diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Tripoli b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Tripoli deleted file mode 100644 index 07b393bb7db14cef1e906ebe63cfbbe8cddc79d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 625 zcmb`@&nrYh0KoCtT?f{Wo{Q(l;<399B=szg#O_6Gtap+!4%F^xj&jiEPvGPrIXXyc z%Rvq<PFu=NqS>-3N{@?jVZM*EQs%vx@B49?`FM-@HCOyP9P_uv%;tl)i^Sd8iFF@8 zl9lyqtMa(2t3%_edRW%a*-O7=ds5o9@5=rd(5+AXe%tM`Y%d@C9p?`+R@(48_if#^ zQ?I(WUZkU@RnN+%?#*4PcsimJsj#0+j>*1>Q{T<L%Hi~=N{tls+}^I3_il>0e5n`? z1y|&!-*2qu3%3vrOPnO;gv@@MEK$d^Xq=h##8hU1#S<Aby+0iK(+mzyIXne`f)La| zP%wfT5DE$#0)~PU)BsVCC{PqE3K#{A0!P8408$VskQ7V`C<T=QOTnc8Q;;dp6l@0I N^k31VMt;zZegQ-UsTu$P diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Tunis b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Tunis deleted file mode 100644 index 427fa563033fdd8533ae56337fa20befe9719b42..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 689 zcmcK1J4?e*7=Ym~y@(cCj|df|gS6H<=upw6bh5TZycNu#P8~$(7NkGG(Sk$u2RP`Y zDEJptu&AxK)uBPbZj!-O^t?eG#KplAa-Jk)NZ!v}F0GErudD6zX;jN~*Sg-eiiP>} z)P`MK+$q)`qW0yZX<r?coO)|oHTHX|jnl9+>c{GOcU*3^$JA}*$-Y|)tNXcdF<5Il zp~|7vd9dQBa-S95OF6OhkTWpc>%=1gXE1$cCHx6%q8xNG>2;Zmx2oC9o67kws`*$` z<zJrFl=nm#K9ASq^M4=u?#Ch0v8g{+JW271MEZ?(k&u$$*UpofSyKx7%w!kXO#QlH zh?su}@~+oXuKN`UgTz4sx#~zrC?pmV42kBd!@25sNI)ba5)z4t1mzcriiAbtB7u>} nNN6NB5*&$+gh%2d17I-(WDv+Okb$`Bq2Rv{CZK0Dk_>zRbScYW diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Windhoek b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Africa/Windhoek deleted file mode 100644 index abecd137b1fc3220637b22ffea0e7256a58e9377..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 955 zcmc)I!AsL&9LMqR%nh5Mk6I|<VR$f2rgLkUR=TN7OHFe>nF@gftvuMYOMwIr)^XzF zN$lXk4jlx=lO6@32$Sei&_Q-G!c!0-BI)z~{Q-g}zp}kRFY>%U&gghLEN5QS{?%tc z<=TGDB)&fTvYOSqOPR@P--lc<`)RCxyizs1{w<;I|Elq+SBGnIDw6o6Z<ZXJX!U0u z{j+D9d@H)?+m^YtKdYP9mrcvZjJ`ep*4$ak%H657X`Op6ZKH2gEHfbSmM5ycKP(;B zx>RSw73n;xRf(d1lK5Gux(-Wq_x5#j@5f(#|NUjtv+-T`&K#J&g-!k7@viBA`A!eC zubGEq8!}imZ<4V^aSB(}P+(ey4vb34BT4PNP{X-48Ch|ZC+||8H~*YJBC5c?g<P$W ze38n4_(g7nJodXtd5YcNl=b#GQWt8Bgd`bHI+BVz(qTW&Io|uk-o$jzE9Bjgw@2Qe ze}M)_2c!kkgQE%31!;ryK^h^QTx~0)m#b}tbVJ%9{g8%8M~;?APmZQYSB|zwUyjB| zXII-A>FsKpBi)hqNPlDl$PSP#AbUVIf$Rd=2C@&1jUYSW*b1^2SGyTxH?DR&$bPts M*pS~2DH!&j0&cX-R{#J2 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Adak b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Adak deleted file mode 100644 index 43236498f681cc06f64ca2afa613880331fe6fbb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2356 zcmciCZ%ma{0LSsm-|Iy&Dj-Bm!Hl7RhrdBt9tc86<UwwrWC#iolmVg)3ox8hdC|nN zoE0&9(I3~SV{FZ&u`@U43+KAv*1#M!H|MM|UA1J6yq)jK){C0&@;rN<&)MC5`}=yU zn_f<L{p)zlFT9+7^Ky@W%Y4rF75FBW|JFKD=g8X=FQ_}G+8qC<Ug<hk;RGDYmVupF zPEgxM9b8xL3n|akp?MiTcUrV|zrDlfiI~-%;p<M=%}aXzk5j${Q@3Qe9`!B!dP+WU zV$z9tcT_&uciMSq&j<41ra>oi^IjQM+~Y*&*2zbbYMq#bZoSBp@5Baf)v>D*mc{<! z=*3quRNO?mUUDW%J^E#&Ui#rJwXCB^#`jLCgvunjy!m(WSoVCmqGVD$9yKEqSDqG$ zeveKH8x%>?KkJo0^@vqt7j*K)_f*Qz7dmyMORerXqQyXsN^AUFrngI#QPeLpD-u*z z;!c^J5v-nYdu2{syvVthEpz9B#FOV@<Wt{Y6>C(cetPtrc&0yEuYLc7kS()1Z~s}9 zUv^19TmOkFSpAJIEa+2(zuu5VDIbfXi{r95{E#Rf8IdJ3&EomNZ}s}`4ye+ulX}Bf zuc)#u1KK%SqRQ9o)*CyLRYhEt_Es)b-nm>|nRQcDUagdymWGQ>XLID{J2yo2N3rt7 z>2a}T|D1ejY(&)5Ps^=C?}*yc+q&-HNwqEIvfkb}pz6cNbVJc@)i85hHzro8#tZv& zlRH;64cF`DYm3#ZM|<UKz8tZmW4nA^#fp~7LfLwFPPAnw%AGCKqCMIpca>?e%fCW* z<Xl!AKe%;g%$VvNyRP@l9#?M+o!4(p?o(Yo!@B!az3QnstoI&!P6Y%81q6rO>j|Cb zzK@T~_1P7d%kOV+T)}>Sdu_lx`(0pviLm!bzOER*zqd7DiM=mcU+Q&js4#Dpc^$7S z-`w*Hyso@;=CaOQ%n9Jb`Rn5S?~#R>Kk#ynn3sFJ-<-8){usyZgVi<2=#b%A&G?W3 zq8%X@hR88v1O|zW5*a2kPGq3SNRgph%~+AaTFq#Y;UeQj28@gt88R|vWYEZ{kzpg_ zMh1?I92q(?c4Y9#=#k-D&G@Y*07wLo5Fjx?f`CK;2?G)bBoIg>kWe78K!Slp!)n5T z#KUR=f<y!f2@(?|C`eS0upn_k0)s>b2@Mh(BsfTPknkY!v6=uO5kf+Q#0Uuz5+x)| zNSu&BA(28tg~SR877{J12^SJCs|gqqF{=p~5;G)dNYs$9A#p<jheQqu9TGbvcu4fD zCVWWztR{d+1g$27NDPr6B2h%bh{O>IBoav^lt?U*U?R~(!imJwY66Nx)M`SC#MEkn zibNF&D-u^Eut;Q)&?2!#f{R2K2`>^~s|hd?VXFx-5@V|gG7@DZ%t)M(KqHYxLXCH0 z9UK@EdauXrnRg$bziVB+?f+@^KheH>3o}7a6Q=0Nr5UN|sUo>FEiE-IRfPQs4Q6_I diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Anchorage b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Anchorage deleted file mode 100644 index 9bbb2fd3b361ea8aa4c126d14df5fa370343a63f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2371 zcmciCZA{fw0LSqQ0v8C15>k=qB=Y>=0R^EbF9-r60dl(ukxF8BSP2AU_(W1Vaw{?0 z9L`3^IkwuQo#|G(7TvVgCgupY9>$_{YbHzAdYVOYJKvM57d7AI|G)G99PW7g`??!i zp3HIl>j^WzaCr8a!#!oE`Hb$#^NlC`+&11+EPo#_Q!^(vxcqOdkdA>;SHO!YGO#<@ zHLJZu2Q@AC1=l9&kfKDNGdol}UtZ@6i<;75!xOIXAI|FAz8UpJe0f<$`i6bCpB$BU zym`hIb#PeTx#y_st}Xp?cFSH@bbY&wsc3WET~H_Iq^@?&UC^rMg)MQ#2G;7>^ysMA zAB*+;i-{_3e4)PQlvBkY3(@x;zN|!7fxNGGR4wq#mkFD`6AN>%%fyvuL{iMxGCA$2 zNS>M2so{G?>f~2CZK_SAkG!ul&cCEG2M_D4<D1o@o)@%ywMJ!omCWhLQH#r-mrLrR zRc>;#%***zEp@Jt`Ej#F{-qRIF#U_T|Ko7^z{KaGP$%gJ-#sZF+83&q9Xcdjty8*a z*E_1X`mA2wd{C7vdP|p<Y*VE_U65s&1ETEwX;~4uRa6`wk}Iz?iptkM(5pV{R#n@N z=!f5KP}PmQb<Kf7Ra@xQtGnV=U0j8BdmPIBN4oapUR0iM%jKGQzgY88nyjC>AR2}u z<YSYkMdPlk^6`-&v9@_kt{dzV>#M%kO?^ky6Pf4q2Jddw9I5rjGOyZrWxw_&S19i% zow~)Du3CmYdefyy_0)k5`Se(tc&6(SxmibuR?kw|)_+yB=gpJPwvLI8m}%KreN1%v z=jg8dbE<3dH{Cr~tL~8rz2(||wRP}4z3q!mwY}$cz2k&O^{nmH&kf|OfWTP+LBThB zLqeUm@O3yoyykHD{T=HaL4JR4TR^D&M%Z7X>^+9BBi8Tl-x&~Z?+L4_+>W9;a~?IP z#+-8gC@*n4>bX>!OHrk{nJ0h`&tDh!e{U_^`~!#Q6?3?!_|3EI)b&qsM_*AnvOQ#f zR<l85hiJFRg+20^O#-__wu$T$*(kD8WUI(tt!A^xZmnj!$bOLxBRfX6jO-cNG_q@C z+sM9=jUzipwvOx_**vm)Wc$eet)>B1(*dLfNDq)EAYDM(fb;=r1kwql6-Y0TW+2@_ z+F>>QKpJ8-9YI=x^aN=N(iNmFNMDe~Ae}*4gY*Vz4$>W@JxG6$23bvqkQO05LYjnh z32773C!|qGr;t`5y+WFWbPH*h)$|K#nALO)X_?jZ3~3tDHKc7w-;l;3okLoO^bTnr z(mkYoR?|PEfmYK&q=i<~L!^mF7m+q1eMB0GbP{PL(o3Y7NH>voBK<@fYBe22T52^t zMVe|gT}9f8^c86=(pjXnNN<tmBHcyWi}V+1u+?-JX|dJx7-_QAbQx(g(r2X6NT-oj zBfZ8O%?=6-4!POu3=6%5@88kx{$JDmPrGm2!ijnTdC#a?oRyO$Gpe$)v$C^f_@5Pu BZASnA diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Anguilla b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Anguilla deleted file mode 100644 index 697cf5bcf7f151ffc1c1fc4247e4e9c7e3ff01a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 148 zcmWHE%1kq2zzZ0GvP?kCG1=UB4deg+$3hqw{{KIIfPuxwH-y14ID{dD1VjD<0ZxOs JfTo#n0RWR(9N_=} diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Antigua b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Antigua deleted file mode 100644 index 697cf5bcf7f151ffc1c1fc4247e4e9c7e3ff01a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 148 zcmWHE%1kq2zzZ0GvP?kCG1=UB4deg+$3hqw{{KIIfPuxwH-y14ID{dD1VjD<0ZxOs JfTo#n0RWR(9N_=} diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Araguaina b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Araguaina deleted file mode 100644 index 49381b4108b1827f24ad7d2c18064a22624092e7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 884 zcmb8ty-QnB7{~FOXhl-7E*(0kr;3}xV{WRkwc=V(QMl07p;Hxgse^+K#g^hESh}>J z%NeDEoH2H4!Pm(kN<lP69oxYcUqY;$p6~eslq6g}!(Ec!_lX8ahm*mLpOkxB=ANq0 zUneAU?^!-`-L04Zq~u#}LhYrOWbao|_8%OX{pFYH;Of5Q7INzFU|#Z3sLsAvbAIQQ zy7>NDF01QwVW3$G>#M4m*fzz*g1-7)A^&FI>e|gYshj+%>-8g}!Y%#q{irnD-O!CM zYE0wtxN2(uYnpb}mAsph*4kd3e6CDbF{V=KNK%C#s!i2P+t!F~zgRQr%#7+dJdwvA zoAr|oYdYUl>!&N9q^s{#_kS3Y0o9?Wt+nx3$=|rO+u0zn_9P!Gw{|xhRQB{nL5n2a z69!QUYq}p`Srl2->y|~<MHWU@_PV8!wY_d}WOZbDWPPLnQUNJ})If?LRlKeYQpf8G zA(fC)+zPdjVn{Wl98wP{h*b2tl1NRjD~eP_$|7}<!boMWD~;6ly5dN6q&!j|xd7w} ikV`<W0l5g|Dv-;-Y4=}CzKvM?mg`7#x*O>V6aN9y?nXxd diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Buenos_Aires b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Buenos_Aires deleted file mode 100644 index 260f86a9180677d86fc3280b06f01d6a6cd91c94..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1076 zcmc)IKWLLd9Eb5YHqjUg1{4$#sn}8y5sox5;-B(LhN`qn4Je%yL?{S~gB3)hi<1zL zAP6mu?cyMK4%O0Ddm3wOhZ0Cd1c!j)rl`aatM>doH#vz;=H=ecL6#T3Pj+DNRKok? zuUr0IEoZ|Od5zu3s|OeR{fC?9_2kyPKe=>PO>MknrY6Sqbo0JHbMuvY^!lB7d?BJ| zr#Ja#Ag`Z{jQCIYmQ?9-#XQ^6&~wLw{@hAjl@Fv%xpq&zxLWWR`flrmkJrp%pH++c zgQ><+dMR_#)c1!~eY9b|hEA(SBI-BZkLu?7jA@pu>RWxtU#{-b-%Ba;W9EqZdAHwR z8BQsCJ?XC*Kdi&;XNubk6S_TGD0Za3=#Ee4i=Ernsm{u=V$A!jVtP+8UaP7dw~n@@ z8_)Ib*|_c*TC02B<k}7{kLg1*C)#q>+Q6!ozkEW$-<}qC4_P~(^gL@z6)$LQ*?3`V zUseLG*1oL;qTIdK-oC7tk+V}J<#fqOc-engMn2M>8@|(vEQG9tEQPG)l*N$MoU$CU z9<m^^BC;g1CbB59DzYrHF0wGPvQw5u)^^I`$m+=QPFWu*z$q0VB_K5*ML4Ajqzt4E zrxb!z;*?U5T99IpYLIe}de9ZbMJkfuJxW4qLW)AFLdtSVT}WY0sSGL2DYYTRA=M$} cA@v~zI;BFSM5IQ{$*29FA|v~x&F-$qFP|Oj6951J diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Catamarca b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Catamarca deleted file mode 100644 index 0ae222a2f8bb2fb1b7abe17d08e076674c51541d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1076 zcmc)IJ!n%=9ES1RG|?Cf78Dc_sn}9d6%J`*#E)_$LqW_^14<_c5rl%`U<J|W;v@tl z2trGvU4<TpYH6!IHr8l|5=e^(4gtkYQK=z*_4t2|yXfS-ocp_QmkaNc9XNA35&ZG$ zm9J~$Y`Q9syEpUd!KHrvaO(>*xjnBZm(HoF&6n-e#F&|G+}AU=UaCj0-rC0(V`g@G zi?#!K^JHX1&mAbK(v^yRx~*>JPlomUYL_Y>PT6v8Ts^;5&<mM6X5qtiyO?om(Y&|S zc+xDTPuZ12QMEE!w_hTIs-9@o^>?GDu`z8M<*NF+GNiv%_nPmer2R2-O#QsquUChY z%H8PEYsZe5X#3gX&ccLgZ!Hu%QlCx7#|y>I9UD|<<wP+aI2||pi(R#<+I9PQTdMxd z?3?W}dis;n%j<35&^puiI@gwS&NYRa|MHH6f8QZ&j)deHac(Xf1kRNzLD;#n4WiC1 zSDIR!dsAy_<vnOQn#l%fIeS!(oNhUZAo~x?$WOZS!{fV=g^-nyrI59}vKX?OSC&K8 zLl#6<M3zL>L>5I>MV3X@MHWU@_R7-8+Fn^4Sshv4E9)Z#c%=fQ1f&L}2(MIul!4UY zl|qn8yiy8M3sMYH4N?wL5Bh?5k%}bvfRd1!kfM;Pkg~i|7gCs4Dnm;1N^MASNOeeg dNPS3wUa1f%(JM7#PJZqG6d5}xZT5D@egU`L>mmRE diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/ComodRivadavia b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/ComodRivadavia deleted file mode 100644 index 0ae222a2f8bb2fb1b7abe17d08e076674c51541d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1076 zcmc)IJ!n%=9ES1RG|?Cf78Dc_sn}9d6%J`*#E)_$LqW_^14<_c5rl%`U<J|W;v@tl z2trGvU4<TpYH6!IHr8l|5=e^(4gtkYQK=z*_4t2|yXfS-ocp_QmkaNc9XNA35&ZG$ zm9J~$Y`Q9syEpUd!KHrvaO(>*xjnBZm(HoF&6n-e#F&|G+}AU=UaCj0-rC0(V`g@G zi?#!K^JHX1&mAbK(v^yRx~*>JPlomUYL_Y>PT6v8Ts^;5&<mM6X5qtiyO?om(Y&|S zc+xDTPuZ12QMEE!w_hTIs-9@o^>?GDu`z8M<*NF+GNiv%_nPmer2R2-O#QsquUChY z%H8PEYsZe5X#3gX&ccLgZ!Hu%QlCx7#|y>I9UD|<<wP+aI2||pi(R#<+I9PQTdMxd z?3?W}dis;n%j<35&^puiI@gwS&NYRa|MHH6f8QZ&j)deHac(Xf1kRNzLD;#n4WiC1 zSDIR!dsAy_<vnOQn#l%fIeS!(oNhUZAo~x?$WOZS!{fV=g^-nyrI59}vKX?OSC&K8 zLl#6<M3zL>L>5I>MV3X@MHWU@_R7-8+Fn^4Sshv4E9)Z#c%=fQ1f&L}2(MIul!4UY zl|qn8yiy8M3sMYH4N?wL5Bh?5k%}bvfRd1!kfM;Pkg~i|7gCs4Dnm;1N^MASNOeeg dNPS3wUa1f%(JM7#PJZqG6d5}xZT5D@egU`L>mmRE diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Cordoba b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Cordoba deleted file mode 100644 index da4c23a545b3603bcdd4555ba8feba117802e7b4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1076 zcmc)IKWLLd9Eb5YZK5$03@9if60xNuA{=RB#6RVg4plKr4Je%yL?{S~gB3)hi<1zL zAP6mu?W%YV)zU_L8f&ye38W%|LqKs;L}G|ld;Xqt7oE(@y`O_DFMOZu(D13G_s3tK z{JTod`YZC9xRF;6E)Mz+H@(!;Tk`(&(pfdL;gXq|n$)wc`+n)>YxU^Od-M20M9<A` z^vzISKN%bIpYAEE^5v>|wz;Y2j|ctvm4vG7Pn$~po_cY$;4fru>xEC(%woo>Mg7s# z;win<f6_Geg;is`X}*R|t7bClH$RN)*1CSvs?^lC#)!XM+o`{oQ|3qMi28YF&|eu% zDSN%wUp;w9hda*{w-u&zXS7i4N`KK^pU)S&x2{#))nmoDXZ^U|T};$#YWuCDv2^pf z-Zhud10!qnz}sBx!19DXSUM5QS!)Ar?SJ`%g1?_OY<KsNwdJbkxp&aoit)nMzN!W~ ztbJDxM7et%hcj8PU(OEIE2l?J(#!tCGV+o3+~{46EQG9tEQPG)l*N$MoU$CU9<m^^ zBC;g1CbB59DzYrHF0wGPvQw5u)^^I`$m+=QPFWu*z$q0VB_K5*ML4Ajqzt4Erxb!z z;*?U5T99IpYLIe}de9ZbMJkfuJxW4qLW)AFLdtSVT}WY0sSGL2DYYTRA=M$}A@v~z YI;BFSM5IQ{$*29FA|rdH&Ay(<FVq<9-T(jq diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Jujuy b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Jujuy deleted file mode 100644 index 604b85663672d83658f331a69cc8f41cf2a2b5a1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1048 zcmc)IziU%b9ER~5+h`0O0t$+V6l|%D2#2&WqE(J$D2Q2Vq0q@e1VK<7T0u0rIEWCC zAP6mub`?Di)zDUZY^<prN+1;x9fFFRMI?s!tH<wi{s7U*dpY@BxEU_I&*1Q>lZoJu zSD(CHFK6>*`MGl=rygDy(2usgFvT4?U0gY<rng+Q(^HdXrujh6-h8DVzy4sKoR6Bh znXTFm=giabaXo*aq)L}6_SyD^SvcOR7uMpcd^lyxwfk!EN?tEzZkwgmt9Ci#)Ux?x ztKCVnl0ISU2P3LJ(Xd~`r&S{n(~XZ4rnxC?o8_wdRv*>ht9#9lQqumMJ*Ix$9nfoI zN#(Bh>J5`eOr+yXVP}5Ibj0$7&eRvv`FW(!6(6!)@7|bQtJie5*<Xm)s%rPGq4rec zx!E@tH~pg<P5;|$d)7G@TG#TIces^X{){bh!p_Yv27z;>O3><D*#;5kURFYF&b_aN zVmt?JM>B&#TFxHTE2l?JA{hLKJ>(PJxv_giWEW%`WFKTBuk3_u<(0jV&5+%Y?U4PD z4Urv@Es;HuO_5!ZZN0KDvawfoMz%)w_R8kS?q1m**&k^D>A)*3AUz;Wc%=)Z4X^Zp zG=g-3w1V`4G=shy9;6+~JfI(>A*3UuC8Q^>G=+5Km9~(+kj9YCkk*jikmiu?ywV<K Q<x~Dgf6+cE@la3nH;<a=e*gdg diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/La_Rioja b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/La_Rioja deleted file mode 100644 index 2218e36bfdb95ea041b166f183895a6ca4871ab1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1090 zcmc)IO=uHA9ER~tn`n#$0}6_WRP2YT3Pal%@pGhyg4jz92t9caK@b!VRuGL|JP82_ zg3!`vuY%(tTH0!-#u_bH3TY9+LqPGSScxHib^Jf$UG(HGv%iJCEWA&8;MB>^;E&fq z`MN^Rx-0Uyb0e!BT<q5mH@+}qo3nas;j9{8f60y)M$JV1zMj1KN<Di0&OW{nGgA{A zv>nKr>EU7hWN%RwFVEYjn`&m}cv#OYcc{{#lr2^6spnU7dbaPjnf-Xp&h<GpXFk|+ zB54+SPT1=HsH%?C?3c)CRqKrF+WQexU)y8rrLy{39n{~-yUh1u(*Bq{s(#+>*ULjm z<*s+@m7|AEwB<~GYp!5g;<<cl>a%J6bUxp{WsPcoS;%i|YtxBfNhQpld`G3Mw%<C| zoT@!DyQeygo>)?PakcFoTxELSWSTS1xllvnU*3`M@4La%7{Q2h)9D~^t~eiroh#WO z>fGXdsL8pvl~A1bpy^0oI_QzJQ+3PflG7Qa|6v~aOLuO_>_BEhrb6aICiBW{$aG$r z519~|5t$O16PXm56`2;97nvBD8JXHEb0d>`Wp-qGWPYzCfMnp66p$Q{B#<n;k_M6o zl89F_K~nKbE=V#+Hb^>1K1f37GvY;3lIjC;LXtwVLefI=@=9VzW?o4R$qh-)E7>9G hA^9N*A{inndL>6BNv~vy8TrNklxA$7M0%hr_6wX??F|3` diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Mendoza b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Mendoza deleted file mode 100644 index f9e677f171b3900dfd978eb8ea2aa226557d2c5b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1076 zcmc)I&r8#B9LMpmy44a71A~4LA*7g#;KSTnP{~I;7||{^3Osd)A_$5O8T4ay=@blN z1cBnpYtW~_61DcJWh)^W%!r`FqUcsctYKDudOtsZK-8&y`Rwr>8{-SFXJ+{L(RlF3 zSD$>lO3vC#@^<T5PTfB@q#ta2VWu|c^wi=hHNEbFot~U9GfQ{%?Df~`;hPWk(b-m0 zoLR5!aLzm)8`DpAl~n0s#XjBCFms1PdTu4A%Ka%@uH8}3FX#1q`lgxxe8n!Lomw!T zY_%t876*>l`ksiYk2mbM@Cnt3M|I=lxLIl+uuJ8t`d%N=%hes`M=5E4&K^*|ZV%~| z(WG)$6MFT;J`?FYS=f@FG@a3Wp)2*(bbUEf=-!af-7iaK>+&(%WA>U@?Va9s<4{Mc z@yzTj#*8-YrvG4{9UNI>2H$2ovd+1t=9a&_!XYmI<50LI+$^8M&K1uGfpeuw5OS_; zgNSplDot(9y{|Pzxewa*r!&ETob4(hr&mrq$o#`H@{sQI=so#==U50?30VqR%PWf^ zt9fNPWIbd-WJP32WKCpIWL0EYWL;!oWM!``jjZjJ#gWyK<-M{#Qh-+~KuSPrK#K56 z6-XIK9bPE}sl+R#AhjUHAk`q{AoZXxh#RR$f)6MOsR=0xsR}8}D|I1-d8IO>G^949 hIHWqHJfuFPK%_#XM6c9{S$VYoQ)KIIX|u1l^*1v}?Na~% diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Rio_Gallegos b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Rio_Gallegos deleted file mode 100644 index c36587e1c292673fa537cecf729f4c873d375c9a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1076 zcmc)IPe{{Y9LMqBbgN}TgMuO?j1-v>JWSW3Kk|eJA@X8_!czwcf}rS-LDcHfDHy~E z0>zcrpr^nRXZh5!l?NG2iJ-%v=vHK`vHtn=eLts8QKx=Cp1poQcKN~QogO}UA`$%Y z>XU!h$k}vRer{jSss|T_^uw($&Gfdco?bemW;S26GgFhM(72~(Z@f~EUca-C&$pPl z!WM0Zv*yY8xPH2?sEU`$_E}rq%pVWy`PFV!I+(Jh>Rt8XN=`2f-ZBdxuiC{yrxwiz zTZt#lQvZmp9f+#hMBRRgoKp2fOxNE}n8wC_+bC7k*V?H5R@rU77nAnK>=E_z&X8Um zODcD*SFfEsWTG9X^E+}=rX!Ziccwm@&QIs^UE4RPuJW;bJXle2vp3&et*D(hkG7}k z&&{5>Zlen;N-wXs1EcHAz?)2a#yJ;iYW~YR68`OOjx@<z#JRb)AaJf&4#LirY!G#B zxg2VB?rk*`<2h(OJeUsp<?K?ua(d(>g7iNuBOmF`j@=(Y7D84+mO|F@%3{cBURe%V z4_Odd5m^#h6Im2l6<HQp7g-ot*(*yUYkOsJWOZbDudI(0;FSuH5|A2@BD_)sQU+3o zR|-KY@k%L3El4p)HAp!~J?IPKK`N5q14=?_LW)AFLdx<=T}WYGsSGL2E43lTA=M$} dA@v~zdZj|7M6c9{8TqvTQ)J72X|u1V<rgAF>ahR- diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Salta b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Salta deleted file mode 100644 index 0e797f2215ab398bc59b8e4d60e5260fcb365c3b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1048 zcmc)IKWLLd9Eb5YZK5$03@9ifQn95ZA{=RBM5~-+D2Q2VK<VTlf*>dkRuHW&PC`I} zAha~vwdgriOIz*PSfd?EAQ2H93W}Q|5<~pg^Y@&)=;Zry@8^YgdExuyhfbYL1%JHy z<?9+b8?VUY&W(b4aB)yS-15RqZ!75O`dKxz>5`q9nlQ7i`+Dx?EA{C0JNx)T%*@Yj z)^@01o{Wv@g?(jJzFf6Ww>Hh<@vvT8O{&VljIFHPQ_rs!^-}J(S^9X*F6W$DHXm#) zkv8@03ES8oRgLkc{SrB?nyI*Mz8^QO4O!c&)YR9;u>MxtZN8V&_Q%{2^>cDiua2gb zyWXeQP8>4Pt}~?_#VOMjFP6G9pH26t^QE5c>s3$nSSb-WoiKY#$(5SgdFyCrruoe5 znNOO5;dN%<%}D2nb1u}@{+D+o{QGXhb~zE}7AAwhxpFlKJ6Ewm)VY_{P=|AGS3+^# zgO0<we2|s1OZCa=m6Hnc|FDPrqB}Qww~p+BY=i8BY~+=lkgdG37qS_$8?qg;AF?5` zBeEs3C$cHBE3&Ou_C+@K%Ff8v$lhMr9NFC~+avoU4ImwOr3Iu1qzSKdfwbY3K9EL` zPLNiRUXW(ccf*UcBbf*EgEWM6gtUb8<dvq7uDsF~(wA2nLpnoRLwZA+L%Q=ydpIJ$ P@;~~E^-GBddSkx;yNcv* diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/San_Juan b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/San_Juan deleted file mode 100644 index 2698495bb3f953685e45edb916798cd24f772664..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1090 zcmc)IOK1~80Eh8SlV}VD0}6_WRP4h>gduH=_?(hMLCmEFgq}QzAP9;FD~Lufo`iq| zL1;;|SHbBaTGD7n(;6*U0;!1LA)t6uRAPv)j`NLo(UZH({ucJK@c+`|Cr`w@KVApz z*H!kczic13uV=-*3uE&Bre|t)OIFS<pAn@E7j>yPt>!v2vV7yEc<}12et15tDsvm9 z9?z;rQ&aNs-m0ixs_Xg9ZMASLAQx7mqBfGywdP&%^h!=Hrf#Xl4_Eb4%7`WPUN;8g zYB_maxAuobE8o^%f~Q0~7Lo0DdDU5$)SX&Gd~Hq0Z;f5*do`|ql#hs?cgEz(WL%hQ z!*ccXAr<O9UD%c@s@_Ph(3kkE`aYg33~XI12A&rS+xz?Fp!Z1(sy&5hvmtieJld0J zKT*3YQ6)=xHR2a?bYhJfeVysa7-M{0{=d9~f!}wR!ym+;F_n4GGp1Vi0>;#|7c%BW z-Pdi*o2D<qyVrd<mG+YM>=eWH4A~R&(*H1z{Y!Ipa;A*TgiM9Zg-qtOvmw(t?R?0D z$c)I8$ehTe$gIe;$h^qJ$jr#pPCGX;xzo;$Opna(v<V;?IBg0@4oDJ67EYT6k_VEA z(`JIC;<ULS$spMv=^*(a38Bk~7n_o;-XkX@DI_Z-EhI0eO$^D*X;VXTLy~ja?2z=3 g{E!5Z43QL(9FZiQHcQOdU;IyLhWFV>4-AEW0h9Oad;kCd diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/San_Luis b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/San_Luis deleted file mode 100644 index fe50f6211cff908f21257cb42259fe2692abdc4e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1102 zcmc)I&r8#B9LMqR+`ed|!=Rv_bV;#<;KST9=+{SfSV_B>hw#)Pf*>e7WDsRtIt7Co zos_MlTi_?kl4<#|Wh*H$W<)ok=vGkJuu?z0pPxS<>eRk`_V}_N@P*g2r}xy!Wbnt= zLHV{(&ic#pcKdo>J-pDZA8meV#<u14*!)>l-f+>DM~BV$(mg$K^PPJ9{-b?zK5iz* zH)`9PH&a7H`sv<^s$810&$iah^zoRUUTss=&JJ5$7*Q{-6!c8)mYMl-)z0Renl+zo zZD-odXHM9~{Y`4IShwH9)2g0K==!IkSz4E|OVyhCvDmMF)^?j;m9$-+II33ecI(x_ zv~t%{x^cM6G&P?oZ7+<P=0u^?((%o-tlTNJZc6Fa*A=rPyTx|YpPN0CZAO=irZcK^ zwttPu-dHYWYu)D1*K_*t{gml?b4(97=OPW!zr4a2m;5-4h7DnizlEW5Q?G)+xyoD+ zbFONGCg<MHMb<j^VIh*>K9GApIg;xMGIDmQl$>@s$)M*SMv`ZBeS;$pkg<@#kkOFg zyfPj#pjSpjhD63h21Q0ihDF9j21Z6khDOFl2KUP7$nahn9|-`7z$+mjF?b~iBnl)9 zBo40xf<%IZ;+0sCV7w9y5)Kj%5)cv*5)%5DxRIcw{eY;Du#mWrz>vti5*iYlSAs*L nL&8JiLjpu1L_+jRj9v*6i4qADi4zCp5&vtT@qLo&f%f=s5oP)$ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Tucuman b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Tucuman deleted file mode 100644 index c954000ba9b28204cc3223628d13e9dcfa4b6eb0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1104 zcmc)IO=uHA9ER~tnrI9K0}6_WRBS1U2tz-N_{B&LRWX+uP<m1jK@b!VRuGL|JP83Q zg3!{~dK4WG)zVbEHr8l`5=ljb9s-ItMJ0w<wd4O8@1iGnnf!LiW#N4?eJ750cz?XK z{JTuf>Pzx7axJIspYPQV);%}l8*+Ml{<NA{bHSe&8#RT-Jw18-wR-sGo&V@u)JzrD zYQHaM9uE!a=^aH?yjb?1tgoAyBOyJrlu)HTNxxLRtDapR(6i~AX7=M1e=cp+ocZ8a z;@xIGb<D5rim2Lf-TxXssp=guU4K7p8mm%%qf}AfYW;e#vekSqcKbgj52~NHd-c*_ zx3X8e^zzaDCenH;ziD91w8jSVZOJdD?bF$O`^J^3y?i(y_pFYa?fFEtqBh?+)RL?} zHQS~VMi)LS{o<wW>0e=b7P2jS7e~y#$)hb<Yi%Id^p|%y^!pBCQ#k0}!q!eNc%HSz zvKO+p<a-foUzG#R*1oL<Vmy1z2htfYC1;E3lG7=t!^`}`M)H~V%;23{$X3W+$Y#iH zPT3CG&nX)sJ0e>mdm@`6yCT~n`yv}7J0n{odpl)wWOt`*kL-^$;FJ!K7M#)p(ge~4 z(uPy|KpH_haY`#lFHUI&=>};B=?7^D=?Gm*JV;NHzDH9?S4dk(Ur1w4=?rPjDZL@h qIi)+KJ)}RRL8L>ZMW^(LH0hKskv5S&F)N??zZ#A1lv;OpMt=cv@bzl| diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Ushuaia b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Argentina/Ushuaia deleted file mode 100644 index 3643628a24723239a13d61b2215c907cdba03985..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1076 zcmc)IJ!n%=9ES0mHqjUh1{4$#sn}8)5e{i%#E)_$LqUu~4Je%)L=XhU!3v_)MI3~J z1VLzNw5#ChP_1n>M`Mk4D1o$y;80N96qOj_SC9YaOirSc_j2;Pmn;|FC)a=Ccry6o z)g%9|khAWR{M^1ir0$*X)Au*NFq4~y^yI>6HMRbNothXk(~WUGbK|9Y`0A~FbS`F! z(;KwyA2N?eM)Z^2B~`juu}?SE&Fs;zo?T9;^1ie!FWptoFX#1K_LiCZaK+ANotiiA zZM8FH7Ba_dZEsZ7M(g%V<fN)6<GTKC)HK#+Y@=LNUuy&UTXl!|UP{>?Gl$gAJAHb2 zIHlaRZoP7BzlpY;Ds0V9n6`Mn(4PKm+CQExbZl9pIx0sBoxvy7X?7J7OI5Y)=Hb?K z{h8TWOc?#(pwf%0ZSTM;)BAd`b<jB%YHI$=I}-lwZjLm`Tg16yBM6);Rf4c{WgA4D zTdagyoO`nrit`+_9LVN^jGXPNTTYjpWRUxZW#l8>nc?xP$U?|U$Wq8!URexT%`3|x z>mdswD<VrGYa)vxt0K!H>mmyyD|=;WWNoi3j;xL>@0InD0=!ZIQUX!~QiNBkK*~Vs z@Jb;_C0;27sRbzpsRk(rsRw;QJV-?nd_YM^O-NBlRY+N0sS7F0E0rOod8Ia_IHWqH eJfuFPK(ADYl<1WjaZo<({}dV9BW?C{#eM;(o9jXV diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Aruba b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Aruba deleted file mode 100644 index f7ab6efcc0f5bfd5c4172cbe32c03a8e08b0099c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 186 zcmWHE%1kq2zzdjwvdlotH(5?k`P+;)9*j)?|L>1wVEF(4zzznM|NoC4VBqrc4PnqV eFfle@a10J%2qD4L|3CmT8AKCjIv3Ci6D|O%z%CO2 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Asuncion b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Asuncion deleted file mode 100644 index 2f3bbda6d3586a2ef5b94bc28ff37906fbc758f5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2044 zcmdVa`%l$%9LMn^nI@7RGzC<&>_Q<N-p6wW*irnDH!?0>Kn3%bH!#A35{g%JO`U5= z;k^9hXl}Jx@m7}Q55)(6saypcR-0}nzcrnVY*{hKx6kwY2ekE5>zsW*kF#@rI@{;@ zDzB>9GBfaxufy)w5$*{#yW{he-&-D?al?#!IG~B$4R-YDYnpWNFZ=lJAsN$}ZN^rG zHQ2D;CU2Uj<0?*?@e9A!C-T$Ggp7wWF|F99jLOlJ!Df?sXQQOu?68x*{Y55!nQy0j zGFj8l)tad%%4AyeIs0V%us*e+*GykNQlFl`$~+T|$+Lwq^W20w%^1;XG9J7y&-WiU zFKCfwc7I`KTp1-<7cQ9Wc#?+RzGZXD`c>-2nQ(5k%v>3=k+GLFnisUuKf5J&;(eRj zcUSWsT(|jM-|4I$FWVQ}+BMeMYi74!mO1q;w&27WnOpU-G28b@VST@ODe{rdTiRph zkAFuOgfE!|zr}UYr0?yb-ep=esP^TKs4l+oo_(b&CdD6kwxlgxN{{y0vSv?~#D~n% z(pp)z<hEHJDwT4%YAVKvtO%YrEB+|fl><l2s-Hqy*;8$*J`3vVD{t9XPu<rwXSdk3 zjn{QuQ;}W2?pN7RnQ32}+bbJqCD~2WK9$X>{dTi=TDB&PHd}vglIp&DrlxbXZ0qVa zuYb5pYuhfGH;z?m-Jw>qy*j4xZSA(cC|!3fe%J2I@U$Uwr+qVdiZmux*v5e&*>xw+ z?(VrQP1n-w9=$4iJ95pwmh-Z|HPsx5ACZGQ2F*dw^M)lnk}&+gd=K}$Zw3MZ|8$?f zvVq4u?}wg166Y{?@=b9`d7#ie*%Eb6BvAe@Zo2!EUd_?u7Uageiyz?DBR3zp{YU{w z1xN`<4M-746-XIK9Y`TaB}geqEl4rGt{S8qq#mRoq#~pwq$Z>&q$;E=q%Nc|q%x#5 zq&B2Dq&i<$9#S7tAW|VxB2pt#BvK_(CQ>I-C{ig>DpISjD;BBN*OiOZixiAhjFgPj zj1-Mjjg*bljTDYlj+Bnnjuekn@9WA(>i2aEfUE$r1jrg7i-4>GvJA*NAPa%41hN#! zS|E#otOl|i$a?s?1wmE>SrTMTkVQdO1z8qkU66%ARt8xbWNnbeK~@J@9%Oxd-2x#i z<m;9QStDeTkX1sK30Ws(p^%kAmI_%bWU-LdLY50zFJ!@x74vmVhO8N~XvnG|%Z98Q svT(@CAxnp>ov+(~|L5W*&UV{Z5OrsyAgd%Sp>RlYB&#G6it-`xZ(B1OTmS$7 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Atikokan b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Atikokan deleted file mode 100644 index 629ed4231944255aaa0725f807517df48b39e135..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 336 zcmWHE%1kq2zyNGO5fBCeb|40^B^rRlyd4W0=I{DhaN<XJ!s(8G4VRR^6kJN={J_M> z#K_FT`v3nb83u;`|95U+WcmMp^#TSCFq;QV3V=uk5g*?W24@!_4hG_IAPxv&a0RkK vfDuZDkl?KUKv49qB?Ux-oCl&oP6W{)XM$*uQ$aMyxnP?5PUZso!ITRCV)1m0 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Atka b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Atka deleted file mode 100644 index 43236498f681cc06f64ca2afa613880331fe6fbb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2356 zcmciCZ%ma{0LSsm-|Iy&Dj-Bm!Hl7RhrdBt9tc86<UwwrWC#iolmVg)3ox8hdC|nN zoE0&9(I3~SV{FZ&u`@U43+KAv*1#M!H|MM|UA1J6yq)jK){C0&@;rN<&)MC5`}=yU zn_f<L{p)zlFT9+7^Ky@W%Y4rF75FBW|JFKD=g8X=FQ_}G+8qC<Ug<hk;RGDYmVupF zPEgxM9b8xL3n|akp?MiTcUrV|zrDlfiI~-%;p<M=%}aXzk5j${Q@3Qe9`!B!dP+WU zV$z9tcT_&uciMSq&j<41ra>oi^IjQM+~Y*&*2zbbYMq#bZoSBp@5Baf)v>D*mc{<! z=*3quRNO?mUUDW%J^E#&Ui#rJwXCB^#`jLCgvunjy!m(WSoVCmqGVD$9yKEqSDqG$ zeveKH8x%>?KkJo0^@vqt7j*K)_f*Qz7dmyMORerXqQyXsN^AUFrngI#QPeLpD-u*z z;!c^J5v-nYdu2{syvVthEpz9B#FOV@<Wt{Y6>C(cetPtrc&0yEuYLc7kS()1Z~s}9 zUv^19TmOkFSpAJIEa+2(zuu5VDIbfXi{r95{E#Rf8IdJ3&EomNZ}s}`4ye+ulX}Bf zuc)#u1KK%SqRQ9o)*CyLRYhEt_Es)b-nm>|nRQcDUagdymWGQ>XLID{J2yo2N3rt7 z>2a}T|D1ejY(&)5Ps^=C?}*yc+q&-HNwqEIvfkb}pz6cNbVJc@)i85hHzro8#tZv& zlRH;64cF`DYm3#ZM|<UKz8tZmW4nA^#fp~7LfLwFPPAnw%AGCKqCMIpca>?e%fCW* z<Xl!AKe%;g%$VvNyRP@l9#?M+o!4(p?o(Yo!@B!az3QnstoI&!P6Y%81q6rO>j|Cb zzK@T~_1P7d%kOV+T)}>Sdu_lx`(0pviLm!bzOER*zqd7DiM=mcU+Q&js4#Dpc^$7S z-`w*Hyso@;=CaOQ%n9Jb`Rn5S?~#R>Kk#ynn3sFJ-<-8){usyZgVi<2=#b%A&G?W3 zq8%X@hR88v1O|zW5*a2kPGq3SNRgph%~+AaTFq#Y;UeQj28@gt88R|vWYEZ{kzpg_ zMh1?I92q(?c4Y9#=#k-D&G@Y*07wLo5Fjx?f`CK;2?G)bBoIg>kWe78K!Slp!)n5T z#KUR=f<y!f2@(?|C`eS0upn_k0)s>b2@Mh(BsfTPknkY!v6=uO5kf+Q#0Uuz5+x)| zNSu&BA(28tg~SR877{J12^SJCs|gqqF{=p~5;G)dNYs$9A#p<jheQqu9TGbvcu4fD zCVWWztR{d+1g$27NDPr6B2h%bh{O>IBoav^lt?U*U?R~(!imJwY66Nx)M`SC#MEkn zibNF&D-u^Eut;Q)&?2!#f{R2K2`>^~s|hd?VXFx-5@V|gG7@DZ%t)M(KqHYxLXCH0 z9UK@EdauXrnRg$bziVB+?f+@^KheH>3o}7a6Q=0Nr5UN|sUo>FEiE-IRfPQs4Q6_I diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Bahia b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Bahia deleted file mode 100644 index 15808d30fb1bb250cce195a00a2d7dca321df7d3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1024 zcmbu-&r4KM7>DsYQ%OvvZCV7WuZf5?*4x}kr?R0{B%~1x^kdN~By&-V7PSa#(Ml+a zNU+UWMYM>s3C18Wu(XvCMPNEkO{;2=Q8tXl={)BTD8hR=d=__eIp3#na&RCM{q@QF zudDo7f9Ju_mSRJ1x%m5l8DGrm<I)A0%{|oF&o!Of{NB!upOE?GO<KBJl7;y(Ef-?> zKI-g`HK$~0;<Wy(Z!*=RX{}B@lUnMPt=+Gh<u7&mYvi(Nd~scyF1|I*X1A4i#<W}= z)UE5LP3!TEw)Mk#Y3u%G+g?vedrO11KdG3GXi+<EkI1%98|?O>j7d*C($0ZN*<nU? z=fQiTS1#$U#y*odCN{1+E7@E@v(=~4CC%D3bH;QpJ-4~yHQBRJ(Y-g)X5X~4J?HAp z{>ht~@BeE0#}3&ey|-l8IhRbV;7vOB?qd`=S1Bh}JNM>gwDxdcA?nnOKXFv}kNfw( z;@AM$A?UY2_CPj4b_x1zkbQ!FBV;FJD`YQZGh{bpJ7hm(LuALG-xAp~=r=`nMYg3b z_C+>Ec1E^F_C_{Gb`SdPk^O_d0i=VVZvp8c=$k;gK-xh1KpH_hL0Un2L7G9jLE1t3 x3HpYRj)J}=q$i{)q${K?q%Wi~q%)*7q&K8F9QJp&g6a~<e{`4X@%827)E_YZWlI16 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Bahia_Banderas b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Bahia_Banderas deleted file mode 100644 index 896af3f56abd712e2fa85d69592bd33b88d364bc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1546 zcmdUuOGp+`07kE-SSC31kSGGFAPn=BnY~QYG}Av#f6c7)x9m65bbKWCP%k8c5IF`x zBtj6qDAb@#vqhWSghfWALf}FuD(EIiQpj}Av=?gEce!(hne935!g6nnn0H6@-vE7A z-0J^i_D)w#_IvX^Pm)JH13__~fw?yI@^g)6tn-l)!j#cvtwu~;h}@LsHDYsS<>vK! zjkuTzxg}tO5x?q(i2oR5Z2dJZw#_WDw)ejgJNg2xokQIsq2sHytE)vMR=={6TD#=# ztUfEbv`MB!Ua|J16wB1$dMj;Rl1!WJG}8Un%Ji{1W8aj&%oxZsGDnsw*R?RQ|G|vP zYFsR`FTGa>O4iGq%0ZQzv`D%$yHsB27nvX4qz;M^S+M-NSuoiv56xUK3!it&!|#gB zBlmj5(Z`8qQM)CIudXpY<+Y-uIYAvucZ=gip{g`2PMk>aRo*2zvTXH~Dw~d#C+CJ$ z`Dlnd_2I6ncsMI7hhLbdJ11n-?K@_5%`<7XwVO4C<D%AEVb*OM67{Jr^UTU_(GXd# z8h*Bj#^4OqI8h?be%q+dJxvzpUk9rTH;ZLc&v(^)F-f*ueye<ZowLBlZ=U1t`)|j# zyWK+QrzQMs`~D5F(6&3I2;$wxu<gM<pJji(XS&?NmFpJC`ey6vO40B7y8l8STMvaG z8bMTo=mb&9q1Fnb7W|_ZnwpX)nn6^9=mt>^q8&s%h<*?S9cm3BDl&A0D9O+gq9#L6 zh@uQlA*w=jg(wTr7NRahUx>mEwZ;&Y9crB+N<*}Us14DZp*TcyhUyUAA<9Fvho}$H zACdqh14s%Ebq<guAXz}tfaJkQ1d<6O6-X|OWFXlv(t+f|NC=V<BqfJBCrDC|tRQJY z@`5A=$qbSjBsWNMkn9-gLGoiH2+5F<qC=e{BT0ukOGcWIJQ;~XGKHiH$rb(w$p-3% X<8-^>uGom^h^TN^bX3IVh^WBdO?$QU diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Barbados b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Barbados deleted file mode 100644 index 9b90e306a68c3285f6cd2de26d02cf8e7106ae8e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 314 zcmWHE%1kq2zzev5vMfL>u(DF+>5kUqr+f^b9`H@+xxhc2;ekL&-UY$3M-PNT0xk&0 z|4$GxunS;hW`e^1|4&FWFn~#x|NpOEVC4A!|M&q09v|Nj1}7kPbOGYv5QY#ET=5?W wKrR8%AlHE04ssEg2D%DFgIorpL9PSQAQysYkSjqn$fY2fJlApooovDd0N7|!s{jB1 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Belem b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Belem deleted file mode 100644 index 60b5924dc12f14c274073b1fe4ccc590b742da5a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 576 zcmb8sy-UMD0EY2P{6M1U<ltaEofVEo!9m1T&_T$egOdo|Gq^}`RvZ;{xltS>W9#H1 z>ZBAzC~b^5>LU0NQsulSe?Y{9<2Qs5-Y3CYWwR^_uabS*WzWFDX&Baq7L(e~g08<! ztMfRN&Dk^6e92U6<SA;^S7p01tm5NXKDLik68Q4{&_o|S>+<trLwyaFbh<LB(yL3E zd5tJLNp<J7SAFkp>(QHiRoZ&cV|pf%{;eM0si=wmYh5+QxK6?C8q?Sl!kFj8={Dy6 zPV_A;2VzQ<?eRtMkA3!2hK<P1T)P$7i)==A=i2Sa{#@Gt>43CAdLT`ZE=U`s57G$f slxtfdy>e|cq#M$Xzehi$A<_|PiS$I8V%5G|P}On&=<3bcy7RvG3)4mZiU0rr diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Belize b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Belize deleted file mode 100644 index e6f5dfa6a8d82523e8cb12f17cf73560bc09a383..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1614 zcmdVaZD`F=0LSrr_h2?!T3U;wk(kh$3@M{aNz}!SLz!brc)>;<ikcUT66GOzcwsiv z#WkCec5ODp+{W^7U#znScCOJi4>PPakALTT^3JQh^uL|+x!wA|`+cu(&E}0+u792( z<`)i6o;iFUbt1R5vbcDTKEH68Dk&VJOQ&rW7jhk4mh2T5=SK9!o-E;?_*?p)j1-p> zw7gv2FRn!I$-t=;bv0Bb%XjsuYyJbWVr7e}Jh(|-&#qQg`9=Ch>RENuyHVfl-=}V6 zF4DI;&xq;~lXZ3dUJ>jau5TBw6*a9HvbHcs+zAeob?eea{ppYLZceOd*z;80n>1G4 z7uV&3p>EYU>x68KcBxQ$g${)pRg?ReZu0xpqsR{Z_~--CJa3#1kMGM5KP>RJWPFz` zt&5dP?2sxrMYVR<$+k1esy*DMJNERd7ge?Tr3kCe<L9)V|4Br)@7J%=pNp>LdHS{c zhIo^;K);Ec6w%S^Wwc?pc>BX6yGvG!ckL78`$Id`hnfWWamy;zbGBQ4T0C3z7RBq& zlSivB8>0Ga;xE<bY0`b&ovMF)K=+4#ih<Z8dZ6m1_|~;ee?NX#{AfNbe{L@o33=@@ zA^6Ojw!T271!j6<+=KkY#tq_y_?Y+@$0_%^T#i$9$sOl7f%C2;#|c)tlkJ^i@6;tr zeXgmQGp1*{JS%)I&nk1g<}C2B8JGL-?Hk0t9P_X-WM|0Mki8+BLw1L3580p9Y!KO@ z)oc;jqt$E@*(I_~WS_`Jk)0x2MfQqp7TGPbU1YyjvteY%R<mVf&sMW(WY@^Hk$oc@ zM|O^E9oajwd1Uv<_L2P~4Imv@O$$g5R?`I1h1Ily^no;jbb_>EHN7CsSWP!bJ66*V z(h$-S(h|}W(iGAa(iYMe(iqYi(i+km(wx<FhqPxk{UHq^9U?6vJt9paT_SBFeIkt_ xog%Fwy&}z8O}9w9R?{!iu+?;ow2btOG>vpkBD8HaeIt!q|Fh1M%%4DZ(jQ<bhExCm diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Blanc-Sablon b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Blanc-Sablon deleted file mode 100644 index f9f13a1679fa9ca7cee6a41bf094a861d4c6824a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 298 zcmWHE%1kq2zyPd35fBCeHXsJEMH+y_ydA9x^LO11INk9m;ga%~f=dZ+FEBAOF|#oJ z|9`54f#LuEs}~qq{{KIIfPn+d<^hueKE5FgjxInP48-9;91sFDje&s?OoWi&ivK_m jXKM*G_y2#8Yd|!}MIajFDi95F8JMPu>$rf9HsJyQxN&4H diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Boa_Vista b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Boa_Vista deleted file mode 100644 index 978c33100fb2d9b14c1faa581890c16c8747b42b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 632 zcmb8syGjE=7(n6Ocp=1FV`CAGu~isMz(hnwZB-B!1Rp>VtZcLk+NKml(84lWO}P<^ z>4Kf$r3kq-7D7M+8bhLtbM^rY?l7E%fnEM@ysh2sS?A9uZclsc9z4Cy)cldncmHQy z<r~ZLrgAKbsasjBhh=H(O_%aJqTHF1mGio&mUFV^Es2k_A^q96Cz^U+ehp8n*2cVS z6&^%8Qq%3Le$}au%I|DeMei=;_~DD1xLnb(L|IK99mx2=vzlu@>Xd&X($$7czeZKY z7!z{4tdKE<nBy4pbno`sckP5%*F0xNB<xN)-alrxzcb8DnLVhTpJG69pjZU89u$+H z)`en2@u3(|oG4ZlFNzt(jbazn`cVvnT1Sc{#giMwl;TRUrT9{eDb5sYiZ{hPsCB0q T`|U3BZm5fWWWnCRVlwgzaZV5^ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Bogota b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Bogota deleted file mode 100644 index b2647d7a837637d3b85d4bc85f83c88982597faf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 246 zcmWHE%1kq2zzbM`vMfL>&;TT6M1&S-F&77D?~8S)|Ns9#BQp~-^Z)<5CNMC7NtXZr zj~`&<`2T<B1_mA<-w*~TAl5Z70b)~z5E3i{n*Bd+j>!iQ4YCwyHv`CG5Dl^%MArl5 ONOAy|4bT~Ord$Be(?9Y6 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Boise b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Boise deleted file mode 100644 index f8d54e27479149d35f6ddff12f709096f08bfac3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2394 zcmd_qeN5F=9LMnkf>&-loJtG<m9!*?i-3|qW>g>|+#tLH8etT8ceMf^x@jSvf@1u| zSvs;zy7Z*2nToF2*bvunZDn(~HLZm`*DM=7Y_fRxb>8RS{_4NBzIVUh>$m&==k41N z*pwswaW3-@5BHLJ_)b>l)%*79&}#$nI`l$%sPC0)`tYjql#jcj^~j<>TSgiZ#9!l2 z%88$9#pJ~rIrUM2m_C&+ox{mO>`#(mozo)xsVO;QYody1n5!czC)Lct3GK=nRj&R8 zI!X?ys3XUvd+c>}-B*1&`qF6;Gt{nQKj;&2?}Vg$xm{e}^_;w6SChCg&?slGFA?#j ztK^*gG;vefZ8BkDv6>s@mWko1D)INlI_aAzl{_*_&pY$8nt%L?UeI?=r3B~6o1Z<Z z7Or#TqRpR(TXMgax2}0lERO$BrlxC=I(=EExwnb5(K9;zicj1=_=e87(4suO&+E(+ zRcc9_UuW%Irn3DVGH3f7wX|fDTvj!%a#L5!J90i(%U$U*FX@`d`!QPPPh1iOXMdG< zelZ|c9CPct1`djq-M{F&59|?z&7bOfIu59ND~{>=8h5LrB`@mYqK&Hfk6~HjX%!_G z4$0D(dQp0!ORl+ED9T=aOP7CEr@XD5`u_J<s*1XRuIx!s53DHDRl#tzHrb<n>%LRI z$v9n|dsbC{pCN1Ke=BN-W99nkVX@)OG5O%=AyL;cA|D#;67`KI<;LDE;$iQ3-O$;o z9`W?+NBsfS7_(0|m6WNbt3mBg^(g<jS{-o3slbr}z4?dV)Rvwa`Plhb@pv#_K5=wR zG*>6dmhKU;HFrvGYd$Hq$6uB^Dtg3@=?NXo>sP_iFZIrZeQM|6X}xPasGjca)6ZP2 zRjqC9diSXU)mGo6_v}wr;bG<%IU^!+=6~wvID6xSaGZlWEW&ZRm6+u??}oyn?OXD{ zm~Fok%Dp~OS!ABIKH;q~Po;VIHve&9_6@#&F*(OveMI6AGCgE|$OMrYB2z@>h)mLI zW{FG_nI|$)WTt4R$_I1h%w&Pta!ePQFEU|d#>kYBIa|%7ky%^Kw2^ru6GvvwF?D3_ z9Fs?8&oO;u{u~KFGQg1nBnKQxK(c_O0m*~aBm&6<k_sdjNHUOYAn8Ezfg}XU2uDhg zoNy!s$%@sa1<8xmBnHV0M{1DVAjv_pgQN$^50W4xLr98{93e?UvV^1w$&=M23ds~l zs*qf9Bn!zFN4k)FaU=}M7?Lt1XGqeJtXWOkki1z<;*iW)P3n-`aU>7P9+EyJe@Ft6 z3?eB+a)=}m$)eSy5y_*~BofJ_)ua;1B}X!mY;vR%$tOobk&JSr6v-))R3xiNT9Le3 zO=6MET1{$^+*(a?k?bPrMe@s$U?jsFDMoV4kz^#x9BD@KY&D5SGHo@fMsjU6$wsn` oq#MaMl5iyBNXqelmUFkM{Bl$I4DZs+oXo5YZ+3QOc4n6QZ`ww0CjbBd diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Buenos_Aires b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Buenos_Aires deleted file mode 100644 index 260f86a9180677d86fc3280b06f01d6a6cd91c94..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1076 zcmc)IKWLLd9Eb5YHqjUg1{4$#sn}8y5sox5;-B(LhN`qn4Je%yL?{S~gB3)hi<1zL zAP6mu?cyMK4%O0Ddm3wOhZ0Cd1c!j)rl`aatM>doH#vz;=H=ecL6#T3Pj+DNRKok? zuUr0IEoZ|Od5zu3s|OeR{fC?9_2kyPKe=>PO>MknrY6Sqbo0JHbMuvY^!lB7d?BJ| zr#Ja#Ag`Z{jQCIYmQ?9-#XQ^6&~wLw{@hAjl@Fv%xpq&zxLWWR`flrmkJrp%pH++c zgQ><+dMR_#)c1!~eY9b|hEA(SBI-BZkLu?7jA@pu>RWxtU#{-b-%Ba;W9EqZdAHwR z8BQsCJ?XC*Kdi&;XNubk6S_TGD0Za3=#Ee4i=Ernsm{u=V$A!jVtP+8UaP7dw~n@@ z8_)Ib*|_c*TC02B<k}7{kLg1*C)#q>+Q6!ozkEW$-<}qC4_P~(^gL@z6)$LQ*?3`V zUseLG*1oL;qTIdK-oC7tk+V}J<#fqOc-engMn2M>8@|(vEQG9tEQPG)l*N$MoU$CU z9<m^^BC;g1CbB59DzYrHF0wGPvQw5u)^^I`$m+=QPFWu*z$q0VB_K5*ML4Ajqzt4E zrxb!z;*?U5T99IpYLIe}de9ZbMJkfuJxW4qLW)AFLdtSVT}WY0sSGL2DYYTRA=M$} cA@v~zI;BFSM5IQ{$*29FA|v~x&F-$qFP|Oj6951J diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Cambridge_Bay b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Cambridge_Bay deleted file mode 100644 index f8db4b6ebf5b66d3d566fc3975d6151783f6e645..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2084 zcmd^<Z%ov69LGQWDe&^ocQX_P%s=S~a>s#^KxUfIg>*r9A|hfIcss2ibvH}IZwtqG z<ag<qo5^C;eBey{vsQD%IfoBQoI5wyYT^95W!cEuWV5)wukTh*dP0wTv+wWq-EX(M zC%j(ahUk_e`PZJXZ#ZnXJ>2K_Js8s8bWb$#dB3;CH)qPjf`+!yh5JUPMw``>>w}U} z`J$Runk&<D7ply;6?(=5kD8h6)iWO~Fj+Sz=<Im9$vOX%o^|q`d8%(n&yMA&Iq#p) zbJr%+yseky>Eat|{_4+VLB<8;%`@U1yKZtl+a-7Syve&4mPG@fnEb14+Sj|!_)pjB zf{us@99W_YBb};f$27e-xJ50g9o5C&m((*w-|3}kd8#Dqp_JSmlhQ|DkCdhUSW|ZK z7xnD-XJuKx$2@oTh%Dd#vw8mTURlw4*{tk5tY4_^H>;ZW=<<ROO-1=8UGdwX3i{e5 zc=f2NoYW+hr@Pha`zxgCqtDFC*BW)Gz017v#d2NU7&SFLv-PXXs!VMxS+B|Vnef`% zI{e2JQ&)UZ*WJli^|NkC{orJ^er!-0J{?gThL1{PXIyO@=$5ADGip=sHhC>{#cb~C z(y#kYnKvR)-8|`_X$e;8misXi@%nURsNO`=rs(MLGPCvWuX<b0I`!t2$?{gLRK0y- zL|W^zRNMZzyi@$A+TMCbc4S;vJF9zS=h!0?D><cO!#|i^nFsZ*fpg~F(U^X(x6kbU zwqCb)d|>u`S*AOhTFl-<**YaDIVCmavGM(-J)WL6&X11c3;CZDNhFSaoRsRG>50S< zBNG#eulkdedz0brGq_6*cbW6|dp_w41SGUBETI~E*4R^C&Lb?VIQB(_Jt9f&huq_z zYxqC-kg&rEh!+qy9IYP^M<AZ?OSl5@h2adu8-_a&e;^J)JaV)yL41NZ1@Q{v7Q`=z zV-U|Eu0ecbI0x~L;U2_4N9!QOLr3c(#7Bmc5HBHaLi~g{3h@-;D#TZavk-3~?n3;9 zI1KUF(Ynm=8RE2~^%~+f!*7V=49_91Gkk|Q5Ah!2KE!`W0~~D!AT4mTJ%BX9(RKmS z21Xwsjev9l(h5i~AkBbu1JVviKOhZpv>k!8#L@Ny(iBJA6-ZkceStKF(HTf<7`=fs zhtVBKdm#ORGziimNQ)e8k04EQv|WO<$<g)+(kMu$AgyBb3eqe_w;=6e^b683M#ms6 zbF@8!G|ka=4bnD8+c!w#Af1D>4$?bF^B~=W|L693Y%7=AOy-9c`-}X6{7_+`ztA7> F`~~dE4qX5M diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Campo_Grande b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Campo_Grande deleted file mode 100644 index 81206247d9efa7d3dd10dd9e88c669718d86cc50..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1444 zcmcK3%}bO)0LSsitwc60f*_<cZ4tB7CSBCbY;;kx)Uq};_0S7gQ4~~^bVy6Wz(Zit zJ7h#qo#qgvQZP^;f~1so5LZR$PzWWIikm&ncm9B)gYz(a4$ox{-(RryWJ8AY*Hdr) zE-^Ry_KVB@u9el_yA~=`_jIA`8M`J%a$d`ksVF%b`%RB_9~YspPmVp9662v~aw1qD ze%y`GKbM^rGy0sIU6HEhDs$yr??*B3ozU~oBUN~6wfxoArsDb@%J|05YJF!wCuD|H z;?+xX!}3qcR}-&&lUGDij-!)?hDCB>oJ@W*tx_CUrgYpBo4&5qn@>rVs^7}Ah7TgW z^QqiY{8EVKR=G8<PGwZ5>&(bT;m<iL{c{5%D<Ms04O~>&GebJ3>z3FyJ}q-^=Bn*| zF*@(;I<@27Bbi_ETkUL*mNI=p6|_dm!ZiybP&p_Av*V(u{D>}^2&<A+9kS%r6R~Sv z>C!vb#qN=Iy{GxHD(ktR%MZ7xiu+Z1Z)vC4*K%G~CX}fC#}3K^PKpW!vSsi~v8eLJ z%BsGNqQ(=JHP5}`&}2x~-k1_~V`p^ziT9$(bzM)yqJ19M?eBLS*Bu^=Sn9gH+KDPF z4?1Zg(_Ft3{EsTkLtV;1>adzZkV=qJkXo#!7^E7jDF>+sDF~?uDG8|wDGI3yDGRB~ zY6?RtvzpS7+K}RCp6ZbDkou4UkqVI#ks7V0NTf=uDHEyFY6?XvwVG0qT9IOrYLRl0 zdXa*Wijk6$nvtTBs;#DMq;9Jz9H|^B9jP5D9;qHFAE_T%0I~vP3CJ3dMIfuNnq?sC zu$qM+E3ulTAZtMugRBNw4zeC(LCA`bB_V4<7KN+|Sr)P`t63PbGOJk{vNo$(9I`rO bdC2;Z1!9wFWzjYm;rYi3y?JJf`F`&oyD`xr diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Cancun b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Cancun deleted file mode 100644 index f907f0a5ba77b9ec845c450cd535ee589b46c5ad..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 782 zcmcJM%PWLY07vhbk!MjJ8<t8~$S{oeV}@xM?{8)GDUXzzFDuJiCM%DvvXN4Xu#(AU zl2T$R5;jVfcOycsd%iz_Ec|Zwp2gjrV~x#B`NfZ`G{5QQ7H%Eh+Qo}kcFpv(^3T27 zwUMZ*8@aOs<y9(hD(rgyh0~BxDuN}?D){sz8b8ie(~D0wAD*a|{ZH9?yrSAxA7uNw zqdMX#*_l{&x&}98Xd>=}s}r(2JnZ!3P02`EtrK}$5K&)|6TO)fy^pU>-%&)wE(=uu zT7?+ceNlt+Ibvw(S`Ckv%aPfn8tu%IR%~5am-oWsP2>1Hza6jEd)q>2y|W>FTA!sn znOY|gL@uu<Kh|%F(5NN4!{!=>46Q%-(q=frF5V#SApRf@As!(vT^gSdrx33Uw=Rue zhGU3lh--*%h;xW{h<k{CNCQX*NDD|0NE1jGNE?@?52KMw(}~dv(u>gy(v8s$(vQ&) U(h<@U(i76u<v(}LHh}}#-^<I)wg3PC diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Caracas b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Caracas deleted file mode 100644 index eedf725e8de1a61c4db886ce8b8b60fb4ee91c77..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 264 zcmWHE%1kq2zzf)bvMfL>)Bq$V%jwvBoAJiOJ$h0>xa!J+`v3p`GcqwVF*E=Ff6#$} z0Z6(qu>AjjU<U)o|NqAiF!1^KhA=n-v95uMu>pu=2qD2vpz;4R+oc>pG{|lc4YD8T b6b6tRKs3l5Ai5qXN2*)6Y=ADZGvNXNDu777 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Catamarca b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Catamarca deleted file mode 100644 index 0ae222a2f8bb2fb1b7abe17d08e076674c51541d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1076 zcmc)IJ!n%=9ES1RG|?Cf78Dc_sn}9d6%J`*#E)_$LqW_^14<_c5rl%`U<J|W;v@tl z2trGvU4<TpYH6!IHr8l|5=e^(4gtkYQK=z*_4t2|yXfS-ocp_QmkaNc9XNA35&ZG$ zm9J~$Y`Q9syEpUd!KHrvaO(>*xjnBZm(HoF&6n-e#F&|G+}AU=UaCj0-rC0(V`g@G zi?#!K^JHX1&mAbK(v^yRx~*>JPlomUYL_Y>PT6v8Ts^;5&<mM6X5qtiyO?om(Y&|S zc+xDTPuZ12QMEE!w_hTIs-9@o^>?GDu`z8M<*NF+GNiv%_nPmer2R2-O#QsquUChY z%H8PEYsZe5X#3gX&ccLgZ!Hu%QlCx7#|y>I9UD|<<wP+aI2||pi(R#<+I9PQTdMxd z?3?W}dis;n%j<35&^puiI@gwS&NYRa|MHH6f8QZ&j)deHac(Xf1kRNzLD;#n4WiC1 zSDIR!dsAy_<vnOQn#l%fIeS!(oNhUZAo~x?$WOZS!{fV=g^-nyrI59}vKX?OSC&K8 zLl#6<M3zL>L>5I>MV3X@MHWU@_R7-8+Fn^4Sshv4E9)Z#c%=fQ1f&L}2(MIul!4UY zl|qn8yiy8M3sMYH4N?wL5Bh?5k%}bvfRd1!kfM;Pkg~i|7gCs4Dnm;1N^MASNOeeg dNPS3wUa1f%(JM7#PJZqG6d5}xZT5D@egU`L>mmRE diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Cayenne b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Cayenne deleted file mode 100644 index e5bc06fdbe5a3062f90274a6b5cc5c56e2d74d5f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 198 zcmWHE%1kq2zzdjxvLMVe@r(9^--k^P)c^ngpOJ~_|NnCz7#RNlKYoCL<^TVy7Z^Bv pd_x#?4NQR8m?4A&gMsG#2N@2cK^B0VQx9Ylw1mqBXqBBY7XW&PH?RNz diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Cayman b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Cayman deleted file mode 100644 index 9964b9a33452f4b636f43703b7cdec4891cbda5f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 182 zcmWHE%1kq2zzdjwvdlot(*Pv8za+k3WcvSqYXJiTkd$Cx`Tu|C1_llv-w+08Aa)H7 ZVF)3?%>O`;*{&u4qKPq^3uu8U7XX0%EG7T| diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Chicago b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Chicago deleted file mode 100644 index a5b1617c7f70bfc77b7d504aaa3f23603082c3cb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3576 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 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Chihuahua b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Chihuahua deleted file mode 100644 index 8ed5f93b02001a63ce43dd221ff48cc5faa6752e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1484 zcmd6mduYvJ9EZP$<I-B~B@!aB60Nhd*@c<0?J#3!V>_EU!;az1*wtoj*t|t68r~^U zb1M;+w$v_e<u9R-Y2}iV#F8RfZmpl+bNsKAKYZTap10rc-{<l9%Yw1;$NBBQqwPE4 ze9vHY=jX~-J;8!NZ+d^AFFYa8H{9|mrnFvSYsXg4%P5q%-1pV-vzM!c*ylQN%v?2p z>Q|ZnE?h16`Am|A#+!vbk0rS)%q+TbN>Yw|FpJyw%95&wCUt+iPRr>s>6@FhC;F&a z>M7RCBI-;=WU9{i)}}I@vvlUuTD9WMD7~^TUu8X*Dc%!_D*K94avCP9RjqGj^~QLU zTYgvaQYRT-)@8|`@!b?ewaOZKVG1W+)P=8ZnYBX)wg2`RQ#4Sn*Il}))^}&?4F^uE z;$v<dDAQ_VvsX$oOVp+f(Xx4tM{P+NC&BRnQ#$R7lzvV#TZadvtUuChd)X`7uZ}k5 zcb@2qwn0;Qp<7qg+&9%N$90YWo!Sv>)U`?XRNb;7y>m*3s*i4v`X7f>Lxf)%o>!^H zkIAy@`f9cN(RA5!uEI2RiZt)bF?$cc7RLzANc%V)|Mpnc$yO1|I%ULZSsiC(tYuy6 za)k4CsNdhSygu>f`6Qj|vETOf{e>l#Jxqbv0x<?+4aA%fZF_JJgBTV;Ok&ssF$!W8 z#4LziA=-vPEMu4kv5jFI#5#s~5c?PgLM()s2(b}jB*aRHnGicev<-z=8lr6~#8!y0 z5NjFcLhNN246&GDGQ?(v(GaT{W<%^|7!I*KMB8+T?GWQ3)<evP*bgZHQURm{NDYi4 zAXPBRfYiY#1X4+eb}5ir7{x%UVUz=@2T~BEB1lP)njl3%s)CdSsS8pVq_Pn0(jc{k sXcq^mj!_<@K1P9%3K=EB|Fgz0JI_Qr%P4Q0E5_xH^2WGb@h*4RFJJn4nE(I) diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Coral_Harbour b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Coral_Harbour deleted file mode 100644 index 629ed4231944255aaa0725f807517df48b39e135..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 336 zcmWHE%1kq2zyNGO5fBCeb|40^B^rRlyd4W0=I{DhaN<XJ!s(8G4VRR^6kJN={J_M> z#K_FT`v3nb83u;`|95U+WcmMp^#TSCFq;QV3V=uk5g*?W24@!_4hG_IAPxv&a0RkK vfDuZDkl?KUKv49qB?Ux-oCl&oP6W{)XM$*uQ$aMyxnP?5PUZso!ITRCV)1m0 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Cordoba b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Cordoba deleted file mode 100644 index da4c23a545b3603bcdd4555ba8feba117802e7b4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1076 zcmc)IKWLLd9Eb5YZK5$03@9if60xNuA{=RB#6RVg4plKr4Je%yL?{S~gB3)hi<1zL zAP6mu?W%YV)zU_L8f&ye38W%|LqKs;L}G|ld;Xqt7oE(@y`O_DFMOZu(D13G_s3tK z{JTod`YZC9xRF;6E)Mz+H@(!;Tk`(&(pfdL;gXq|n$)wc`+n)>YxU^Od-M20M9<A` z^vzISKN%bIpYAEE^5v>|wz;Y2j|ctvm4vG7Pn$~po_cY$;4fru>xEC(%woo>Mg7s# z;win<f6_Geg;is`X}*R|t7bClH$RN)*1CSvs?^lC#)!XM+o`{oQ|3qMi28YF&|eu% zDSN%wUp;w9hda*{w-u&zXS7i4N`KK^pU)S&x2{#))nmoDXZ^U|T};$#YWuCDv2^pf z-Zhud10!qnz}sBx!19DXSUM5QS!)Ar?SJ`%g1?_OY<KsNwdJbkxp&aoit)nMzN!W~ ztbJDxM7et%hcj8PU(OEIE2l?J(#!tCGV+o3+~{46EQG9tEQPG)l*N$MoU$CU9<m^^ zBC;g1CbB59DzYrHF0wGPvQw5u)^^I`$m+=QPFWu*z$q0VB_K5*ML4Ajqzt4Erxb!z z;*?U5T99IpYLIe}de9ZbMJkfuJxW4qLW)AFLdtSVT}WY0sSGL2DYYTRA=M$}A@v~z YI;BFSM5IQ{$*29FA|rdH&Ay(<FVq<9-T(jq diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Costa_Rica b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Costa_Rica deleted file mode 100644 index 37cb85e4dbfb7ac9c01eecf584a1a721ed251e93..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 316 zcmWHE%1kq2zzev5vMfL>*Z?FJzYy~kH1kXl+@2R8ET)|xJUt*lefon0jl69aG|LYq zXdb$GfsvUB3jhD#Xw1L>CRzUf-?@R2^Z)<V3mABPd_x$5y?}(X3lIl~FoclcjQ>E8 y*{<aaqCw69x{3khBrpwh7KjEp4NL=_2ckhv1koU8f@qLa!8Cc!<pR3dj0*s%0!@Md diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Creston b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Creston deleted file mode 100644 index ca648573e483c86c1ca09d6d5be131877398c8f9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 208 zcmWHE%1kq2zzdjxvMfN%(*Pu9U-K@Q_tTnzk%{sD|4By}82<mCJAr}a|Ns651`Y_@ m$2Ww*H#meL0Ek0KF#bOf#Mu_?0ns39Kr{(faRKc#=K=uz?m9sL diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Cuiaba b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Cuiaba deleted file mode 100644 index 9bea3d4079f4449d5bed22b81404b5ee2ab6394a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1416 zcmcK3%}bO)0LSsitwgpgf*_<cZ4tB7CS7zhlhH-ZO3T{Rv_mgoMN&{vLXeh(frp@^ zcgTn!JIx_TrC^{yBuFXkAg+qgp;#!PRNU-ozVinZ9h`^Zb9gRu`2Iq5CmXVzzn(ht zcagcvZa=@&(Y>PPd-r^$>X|B*y<=C!NZ^$miNwj#gl~GZ=eP(*eRAwUM2v@@$%#;r z_;EL0|6I~2ruA7lvphr1R^`jtzK>$gJE7;gVpTM<O8#nZSBd=(Wm3~;wXQR$lXJo< z<;q35e(5LWt4-3r$;%=&;ONw$VUd=SDAQg~sdUGc=^gjP#;<Girc+X7=r=O6;e*KP zd@47Wz7V3NO>Rl7SJ^dLIw!VC_yb3!e|A9RCTGgrfeR{cdPoPlZ;7qrQ!@WXzS`Cw zuM5tsRomY_l7*GORZ&~4EM7e?f>nbuI5RFvDvs!qiKr@D*&)kbJ`p?SlrFz>P3#=G zsdu$JR=a!8>x#pzs`7rd-c#Nw_O_mrRmo*)-?0O7zmu*)!8{rIQYxx_39`C>gQ)dH zWo?&N9Gncxy6X{9KXzIlI`LjKyRPerS)kA3y6+kt$90DXV-~w^pLXJQSA?8Qkz=mk z3H?V4=9w-%AWc|J7f2gOA4nrs(+Sdw)%1cigLH$mgY<(mgmi?og!F_oWi?$PZCOoU zNMlH6lum0%Z%A`UcSw6ke@KH?(;?EL)%1uoX*FFUZCXvANTW!nNUKP%NV7<{NV`bC zNW)0SNXu5!Gt#uxbd9u)^o=x*bdI!+^o}%-bdR);^p9-7YIcBZ!D{w^Y{F`GfoucW z2eJ`lC&*Tiy&#)Gc7tpO*$=WIWJk!BtY%NhrmSXH$hNFzU&zLgogrI8_J+--jRjg< QjOQPl^A?!p75cq@02#u{;Q#;t diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Curacao b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Curacao deleted file mode 100644 index f7ab6efcc0f5bfd5c4172cbe32c03a8e08b0099c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 186 zcmWHE%1kq2zzdjwvdlotH(5?k`P+;)9*j)?|L>1wVEF(4zzznM|NoC4VBqrc4PnqV eFfle@a10J%2qD4L|3CmT8AKCjIv3Ci6D|O%z%CO2 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Danmarkshavn b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Danmarkshavn deleted file mode 100644 index 9549adcb657569ea304592a4070ceecb4550a4db..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 698 zcmci9JxD@P7=Yn(Q!B*bfTdRUr<MI^T{N27A|lXexKp$hLC_S94hD@4U(i-iLt{Tn zqqRg+1VOk&Lm&|mv_udsr}GL;LD15<obw#+o$mX2bIVIv^<&lBH*8kIZti-gG_Asg z;%rmyQ<{@65((c+)ORh>w{wYAPo(8`Us^A=q^*3W<A=w(eRofHY>MtIuIsLqRoy+m zpc8pdC&wpsPkK!E##6d46w|4|grwd_rT?*41}YI5yljx6(+^1>JWFQ#PKGzGWMr)@ z?&6WSPcyFLuk-!-1dMqtDP>IMM)|+b>Vwm045$4Ur9%0Fr!sEN?yQ=!ccmPM51if~ zsu;T{!=esS2&sgWLTc5t#gJ-9Iiwy^5UGfiL~0^Mk*Y{pq%Kkzsf?6HY9qyK+UiJo eq&_kMWD3Y6kZB+jL8gLCrsls)Cuqmz2EPDo&71K6 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Dawson b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Dawson deleted file mode 100644 index 343b63227d2185863cd720bf449de000bbc794d0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1614 zcmdthNk~;u0Eh9XIix5YNKNf&$0>($$Q;uqQ$%wrpQffwNTC!-gKbI_B&aA4Nx7)( zC~cyRVn$#I1qI=v(rA$(5rh#*WkFWr?R*znwF+8wALss#cje;$x$2tsr8@q2e9RXP zPlGw!W7^HD_s-bBwUH>TpZX2-^^doYosJtAkNVm&z9&t7OKw$jas9$O<%3$%bXW$| zR*AqOmki3z6ieeXWN>7q3h@b+q3-D_bT&;dd$UwI$Afg({qHJ#a857pn^dxOrHtsf zry{HUWmNM^5uN@~#uVQbD*~U%*o0mYyD+2UecMI+)DxZXey><LI;dAow5i12Zk;r= zTP3$0(<$9~YW4mLGWAHbT2pvbrd4{W^w?^dk@`+$dS}Tjr>Dr84wczIr^VVw^D<}h zvB(_=*6T)YiuGMT^oGml#KuFf^rp@mDzAK0Z*DxR@{_eL$UmqGzD&r%#51CBVptaW z9}q=DJ+gSFOl-L_q)T2jtI`t}b=mC_RbGEwS6oU`TXSpmwpO7kojKZ7HLG0nVY)i~ zxvGA<R@Q`n7Bvr@vUXuY)LmbYJEn$3edlZ0Fxn$_Ha?KMdh0*AyP4l24|h*@FYkZ- zTWnb;OB@c%>S}lMu&j<2hxuaee)d~f)>Y*ez}*pI-@|x2B1%eKj@o>4D$Ut$P6dCP z4;AJ^g|XDg<7U5qUtE8&G|N0EPo2MoEDl*6vOHvc$O4fS+L|RIYeW{wKf)@JWg_cD z7K*GCSt_ztWU<I<ZOw9#^&$&KR*WneSu?U|WYx&Bk#!>rM^=t39a+1rSv<0OTeEy* z{YU{w1xN`<4M-746-XIK9Y`TaB}geqEl4p)HMXW4q#mRoq#~pwq$Z>&q$;E=q%Nc| zq%x#5q&8bq98#UFDG#a7))a_Th?I!bh!lxbiIj=di4=-dij<1fYHNx`s<k!cBK6vu af{}`ml98H`qLHeRvhn|_+t);&>H7<YSFbJr diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Dawson_Creek b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Dawson_Creek deleted file mode 100644 index db9e3396557652707c0c2232e119e13a2dd172fb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1050 zcmd7QOGuPa7>Dumjbn)ly@Uf1E)E1<+6Y}RjA#>RkYqK{Wudrez*P!CtxCusH+fnF zZM1`J3L=RJ1SxD2L2a6-oG#OJvti0ovoy2$dY_MWt=#nu=ll+{{XfaWU8xP`pKpc! z!{KYv!+TAyUPGg|{iU&ld(gkur`OGOr#oxp$^IGp)E4B~=EruzJd{l0md)g@%k$zR z|6<(9%j`}6>gqL@y>r38?my>pL&yD_u5S1C<RSlV=U(@|eXIXazsXHDAG9A=?~#0M zlg-a=l)}ntTSzD5(`3<pzA-OT_j2~j`HXxWS@P38V=^<4^|Pn$x^G9v{anXo_kH)U z|FQjyn{Vjz3w6Wtb5+VOmi5Wv!fE>}pOU4CBlh?G7AcN4+wjVIF&FD?aJEunCn{`7 zPo0Z**80+5+QoucNnEdG|4PGfpv9Ol9CSfk-@T?RdRIobaGR=Ktx40iL(e`v2lTWh zO{>27g1>ii8LNc)wQoDN1z87K2w4ePDpJ=%7DHA;mP6J<7L3#tktLBekwuYJk!6u} zk%f_!k)@Hfk;ReKk>!!~kpd#M0;GgUtpO<lsRAhjsRJnlsRStnsRbzpsRk(rsRt<t rsR$_vsVP#6LaIW_Lh8b(FdkIKr=<b4A;lrpA?4x!QD3>{*jWAtB*Xe_ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Denver b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Denver deleted file mode 100644 index 5fbe26b1d93d1acb2561c390c1e097d07f1a262e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2444 zcmdtjeN5F=9LMnkqQH%ZQ;8v<nU)CgtR#>b6-0<P2(NH8!YHnHS1a(Ln-=0RD8?U+ zvtrCL36!+fOng|gv7xTv+REl|Yg!BKxhxw!Y?8peo%dPwPk;4STVM9OuOIjS&-=Po z`_|@&f812_4G-6C9^R)b{@GWcUmFNlJ<liU-dDa?dprTXw{@E6E54}vI`*j#+N1RF zyx$s!>*B?gOursm&?$b8b?d7UesOi|Njd(VTTGm*mXq%nh`_OY8GIv2h@FWtq%9yq zpPH0YHYBL9x|w=v#e|wxIIhF9MpXC<xjIswP>}}?Nyq3Ob<M?I9d-V=h(6JxW8Uo* zv2XTB`ErZ6w*6Uo-Bypd-d8WDuPPC7rT5Ai`6=Rtlm#+=Zn2sf>5vJb$tvNO`8x57 zNR>1kp=X`^LCrpNN#EFeTFvp#k~i%*sOGK=%6aQP6gTI7E^k@(wwNFHo=i^FA~|qD zr#Lo>l#!D<^^!~6I=EM-oo!U<-OuTaBb6$%*{ic&TBNeQtuklR47IRitz1+&rgD?- zlegu3q85jz%DluYBJbNMnLmDB6rB1=-u~%;Skmv%cMR+nOFMqlckbFQ3L8GsceU<P zcbE6;d+N8TqRba{anTx8{Ogb`NpBJ*XZOp}=vq;Fq+Kq%Tqw$3eO)jAxJEgf+VuVJ zELG(-K3&l@M?J8lOjr6t)rzEa?OOSja!thQs@zkm>gzP=p8ch855>q;fg!QFZ&W@w zvR~A+4$FrI+eK~tQMsmjy?EGpM%T5qsYlWe>qoslRUh4{JtbwzbJ?%G$?3{_+O2)z zvC4O#K(G7eXSKeoT0V9rMm+A%mrooV6%AF1vaw@WY{;FI8yk*_O>r0G=JGDFIWVsM zd54vM<TJe`zEf=(Jg&En`PI|iz51DRZq?M>qPHC@P|dX-y?tkr3Jv-5Z%WwTuYY~@ z-y00>?i3;ze5)rU%)Dz6Vc(<dr(EuI31^XcR+y*SJQXgpA|XQThwERgFKDhdEUF(_ zA+khdjmRRARU*qo)@d~hMOKO|)oRv?EEZWUvRq`nR<mGa#mJJ8HKScLFRYp~%LdlX zv2bMN$kLIuBa25?Z#BzD)^9ZhKq`Qg0I2~-5s)fylmV#&M<I|(aFhb61xGQEYH*YT zsRvRJq#{;R5~L<bQIM)2WkKqK6b7jbQW~T-9K}JZ!%-fjK2}p8q(W9xBBVwfMMA2C zlnJR5QYfTSNU4xoA;m(fg_H}a7g8{!VpdZ!q-GpNL#oD6Hl%JGg+nUGQ97h{Nb!*B zA>~8rXEg;xDrhw&L~3X?MMSE|QAVVWNFk9*BBexXi4+s5CQ?qMo>o&(q@q?+QlzF< zQ&gm?9A!o7%28OPvK*yFYRgevq`F9Xk@_M9Mk;JIB}Qs&HAP0MY&B&@>WmZ`sWeBa zky>*U8>u!&xsiHv6db9z)s!5mxz!XMsk+sa9jQA~c%<@3>5<wa#mE15^&RHNV6pj8 VNOLaC$jQh`b7p5}WM^bK{s0D?lEVN1 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Detroit b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Detroit deleted file mode 100644 index e104faa46545ee873295cde34e1d46bccad8647c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2230 zcmdtie@xV60LSq!L|_Lbm=r2fLCOx{_|+-mRT!}A)DzRg6ipuuyq!=ysokIqYk{WA zS<_*z#xkvuu92E8S1~nbZmmpNML&j5ZL!v(9-}{6S6t8gS^xD{|Fxdm^So~N*ZuQ( zhZ-Xr%AJ3lWb+G`v)f$0XLrAsx9WgzpY!3<T3*ioRbCb`^|`lC4><=_tm4^cV&BhG ze+*UWKQByI$<<e6O6ggVvU`fWF5|FpIftZ6Zx^YmTc&;SvPwT4me-%^QWIZ$N@pC{ zpfYzh>q#B=s2d`FJ$YrJ$_lvkjdRn~P3}~ko#z%)CXDK-iK$}hFD^Oln^BQ-=|?&J z%teuV>|=TJ!DHf<sH1Ova<9m1_*Um{>{qvW&*>Qpo>MckUeyJKn^nR1`_k=dQ10PZ zWZ@5U)U1IWvS=_QihCo{b7HnA>0BsF_hyT-a9Edb`dw7`1N!!*Ukh)+EIqq?K+H)= z*Ok-0RFxw?>$$OaRn_@Rdfr#P%GdvsyyKlG)SY`ik$1hYURAdpm-D-}iM#9f$(p8h zqP8R|>uPI6-B_RY7q3<R!Cg9#K3@e+wCV+;`D)>dJLRI!szq>Xi(LFxo~U0PluLS& z#J#=}x%80{u`DN3h8ix2P;5*t_Z|_;zniF6<epb6&Rx|j$NN;{;X%D>c$Zq;byD9y z(5lun?bmC27b_8bQ?A?5BGwo8$Opnf(UjgUoBbuCd9+c63o=FcBcF^UkBP|ZxpL#k zr=q2&O1ECTsveBy=!g0TRa?WjmU~XBhrLQ~YTK_iXPwns>O0hy@hdV~*(0LEXJmVJ zyJ#OcBs+d<6p!|H%g2U%VryquKK^#D=v)(!+n#qsLgF<^iP!!|KJobR8IBW=AAQM5 zipNjA;Y^6fKRBI`X5S3^PF@rYIW@~dP966?bC;M~8)67f!ryP`UyLSh4#PplgA526 zk<|<d851%nWK>o&EM#2B!1ybS3>li$j13taGCHdn9x^^;fXE1uAtGZ$28oOk874AL zWT41Mk)a}EMFxwE78$P9j29U&GGb)N$e58qBcn!!jf@)^I5Ki%=*ZZS!CTGfk>Oj- z_>ll05kNwK!~h8b5(Oj-NF0zrAdx^qfy4p{1`-V<999z#Bp^sckdPoTL4txr1qllh z7bGx9WRTDxu|a}kHPJ!BV>R(X0%SE2LPCVZ2niArB_vEpoRB~vkwQX+#0m+P)kF&k zm(|1z37FMH3<(($GbCt8)R3?taYF)!L=FiZ5<4V#Nc52KSxx+q09s81kq}x<43Qur zQAEOs#1RQ35=kVKNGy?HBGE*`X*Kag0%|o8MM7#dF-3xkL=_1u5?3U!NM!MU8(NpC Xu-DYLC|Kbs_mma|%gQ`uo>JFeUM!I( diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Dominica b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Dominica deleted file mode 100644 index 697cf5bcf7f151ffc1c1fc4247e4e9c7e3ff01a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 148 zcmWHE%1kq2zzZ0GvP?kCG1=UB4deg+$3hqw{{KIIfPuxwH-y14ID{dD1VjD<0ZxOs JfTo#n0RWR(9N_=} diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Edmonton b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Edmonton deleted file mode 100644 index cd78a6f8be1dd55ac5afd25bbae39bd5706e42d1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2332 zcmdtiT};(=9LMn=gaRiXew7#s8fi%oAP<s2W>gR%o+LOR8etU34pxx5GcCklf+M=| zTN$&N1S(-`g{f;cHqabyJ?PwVxvWIX%4XT<VapBU^n3rW*t+Vbi@s<7^ZFmS{=7Xa zy{j|TKW>Ws3lG<2AKs_EIC}Cz_u&C~b1>BO?08vv{9DcLmwuEz?Nim>#!sX#`<QvF z{F3gE=`;JXKGyptK2o1{Mu>mzAI<*SSoL|uMSUjWYZX#EL#C8oGgI@&B{Y51ge9Dl zaDBwM)Ude5cAM)j^h(6pVHJ6#O`<;RRnc$vX#IMdx}kH6zHwu{y2)For>!VbF~tw+ z>A6Yj=A=7x?3_X~BiyBD1}B=Czs-}lZ^KQzKTKvF{mIOJ|FYcDd%`66X6ajB7%+1x z0(x%aXX>`>Z}ja;-c$2pj_Jf?QHc}hCCRl`C5;}H<jWp)=g=NWIo)hhySGZ(!7?+y zwL#KfU0^aA+I8l-=_adawO&wm)nq3=r0>f7(ku*3);V#1s+>y^I(Pi6$~*pxzWb{| zwP?Rf?it*r7H|7m?%lar<u{#_``UM!`<LyP2kJJNg88pVVZka>`1^=1N^Ma^r~7qr zWQ{65*r}IX$yX(B^vTjQ)yCb@ArF7B*et8|N@-Vud1O(El=*^9d3>sPD!wzGYtd4f zecV)jpQ5W~UsP2iQF_J1h+4UKOg}o>ud3Vq`mv!-Ra19Juj*c-9(SLT+KvwMMCt)~ zvcYTWBDYI@QHiO);**BNRMT*xO1z=b#`|ubH2(0bS<|&#KXocfJ?+cY&kT&Irph?o zyv?tk&HhWTZ91gZ#hlmcmvyQ26XW8`IbeLF=VU|dcC%q<ST<hundiED<@qnFOiOE< zY&x80T5IZM^Nx5E95m^3UC5*#lmGEwzXt-Z^(YkxywejD5(w-P73RE0INy4y+oRkC z_9?f|a{H8e>_n6ba=twOVpRcqEDKo|vM^+2j&^Ct+K|N|t3#HDtPfcrvO-6@L}ZP~ zA|352k!2$5<X9-OQe>&fT9L&ft3{UUXxED@7+EpLl94rYEE-ug$Fh-ib1WQLImgnG zwR0>USv|6RWc`k|07wOp5+F4|ihxuBDFadmq!36YI7)%kf}<EnH5_d@ka{@Uf*=*) zC<#&%q$o&Lkg_0kK?;LZ1}P0v8>Bc$b&&EP^>MTXLMp^jBBVwfMMA2?Q6{8L9ECzE zg_H`Z6;dpuT8_3{NWC0w!H|kM+L9qP<0u+ZHKc4v-H^f|l|xF0)D9^gQawjoKBRt* zwtz?l9c>Ab8gdj7sUk-ikveh|5~(CdDUn(t#YC!!loP3^qb(>>QAb-+q^6Fxs7O_j zvLbcmC@fN0j?yBv<tQ#vU5@f1^>wrbMk?%RON`Xm(H0r0GE!!w&Pbt=N+YGl|7WdT ZHsT9y%v0Q1X_;y1DejDnw2ZWL*WZc*ZxH|h diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Eirunepe b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Eirunepe deleted file mode 100644 index 39d6daeb9b6dd3b225b0ddacceb6984e8204ac7d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 656 zcmb8sy-Ncz7=ZEgY(Y-ZMFbJQI$Q9oAR>~ngJLQ-iGx$YKR^(dtAil8IEmuoY9}XY z9VA=P>0C=&E4Wz%@vF3!nCEaV^g?(7fjjQ^dYe0$InnWn+uNAk{inI3Y<@5!^6f2M zcvtGSdLm1U52{ojR^^d)P%iAsN^4eCFPieHa-(YAy8JvF4ZdRg@>^%s&%lyyq*JO< ze3ni3Eofd1=~g|ievi-f*nLio?|tZr%XBa~|Ei}B4pqGGMNjKTmB`d&YTH*EepLI$ z7$?$k^*D|(cUd8fDe6enn8LN_<t+Zst81P}%q-ZQ6kZqqZ$E7?pg4rJ78DPP3B@I> zwW0WgwMG;tiWS9+Vn%VJ*irl_h7`xJ){^2G)|ygWDYkZY0$++T#hGGF@urwl+$r`H Yf65G~Z{OW<3K6HPIk?Mq8Y@Zn4_D+KfdBvi diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/El_Salvador b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/El_Salvador deleted file mode 100644 index e2f22304aad56062cfb66d23f3a8c296689286ed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 224 zcmWHE%1kq2zzbM`vdlotv-s*V1%+969w^4l4p6Gv_dwaEHh_r{2><_Ilfc06|NqVn zj4c2EuU^2w;o}>^;Oqj#!66JGBv|nu2td{Vtz!UL1)@RLfoPDGAeu;Pxqx<?aRC5^ CcQm~K diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Ensenada b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Ensenada deleted file mode 100644 index ada6bf78b2815d3d99c97d521ab9a6b35c8af8c3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2342 zcmdtiUrg0y9LMn=gpw%wq@u(hds2#laOA%z_Rpvz$O)7qi5Z#kXHW)-p%f81w$_^C ziw?_G^yKV<wIXJb{bS^oTWhSsR+x=3Q(zcHtQD2x^t^vvcGX?$clJE5-_G6d;`8?J zsIE+N{_)JU|8RIZ?BPA~wccM_x*7}Xx~H3_dMnH8-i=ny>9Fak&n6DH46gd6Zt(c~ zb>BpnIz#PmPhD)@EZ^sCl}lyGaycPGM!orJZ1EN~9-pMfr_<F$=t4Cy7@@9=PN^Sy zep8cY2i1@5=hgg?ZnNP0fC}$#Hw)kER*Smc)arP<y6#!giyQ0JlIp#BY3Vi<k>}UT z)~!{`6S8#V%3`^GUZjo+&XlO>3=@5Exx@@EGqE54E-QLw%nh$z5Z$m^-+1sNSy>XU zSJiy0;xd2IH|2k*ZjSg;$0v5G_}NL55Z0m+hCern6T8*wz8;fwu33^hj~dUZU9zV6 zag%a%qoh_H(P{N@lJ4E7Gm7U*W_*dxN*kB8q1ie+W{%1pi_+`<98>GhUe!4lK2;mu ziZr);@VdIS?GJO?i-*<iwcnXLTDxRpVV}9P{5i>8W6WK-d*tp#hm1F_P`op*=)90r z$s0PT^Dixt%`crY1z*>Quc^b_(_0{gJNKKSV;<SEq10?`P*NO|WBl8u#eX%{lw^J- zC70Lh?JIs(+dqlXrL*VMj+3+czTtP&&ejoqf8X<}to)3AptDi!@(r5@pXrd@$^GV` zs{K+Pe!^6EOQmA6)l|jjNYy~4sSb^m>Nhr-n$dtfe5^u0@<oi=)8N&QcF(HXk_27X zHliNOny>fPo>BD?lX_p_NwqI9&opHBOT+LLb0G4B9OxS`jWezCL}#~oa;Q?8n%m7& zr#DG+S-pAsg+vJo4hp^|IAo5!{yV=w;7Ebv1OhLM6A}otwK&)E9<;!{m3uEO@cA8I zvEM1;<l1wuJw<*7<2XTo-~N9wu7G_Q7&0<sXvo-*!6BnVhKG#L)eaCDAu>c{jL0C7 zQ6j@c#)%9R8L6usDl%4AJ6L42$Z(PIA_L~j88I?sWX#B*kx?VVM#hZ{92q$>bY$$v z;E~ZI!$-!C1i;ls00{vS10)DY6p%0=aX<orL;?u~5(^|4NHmaexY~Fi0dchvK|+GW z1PKZf6(lT3T#&#ZkwHR(#0Cit5*;KwNPLh0x!MRJAwpt=1PO@}5+)>0NT85NA)!KI zg#-(U77{KbUP!=PZN!j}x!RZ^K|`X3gbj%s5;!DsNa&E*A;CkUhlJ17#t#XgtBoKM zLRT9@B#1~9kuV~0L;{IK5(y;|OC*>`G?8#3@k9dZY9oq-)YZlm3974&DiT&Cu1H{! z$ReRdVv7V9i7paeB)&+1U2TMs5WCtKBSChxQAWay#2E=R5@{sVNUZUHAM7w&^K4u5 UBwxBG&6ASkOHK8pdQ!sv0^LWd&Hw-a diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Fort_Nelson b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Fort_Nelson deleted file mode 100644 index 5a0b7f1ca032be1adf8ba91f863e727c5ec6a026..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2240 zcmdtiUrg0y9LMnk^7jb&%{)qk^`s_(DTW{@nyEO#KtK)_ty#9B;c99Y*4Bs?t>_;Q zI{UMVzS&KzCNgHTkqmEKt*i;lM2yHv7)mNy0ura^{abfkb=P{%p6B)3x&OR__f}S< z`~GpF+&^4Sy}NuT)VQbd;30j#EnvT@OVrNUm$!9po-5y#T{OqdpnRX%Wls3MmhQj- z)7`gEPEH)to(?OgdRz5}rcZ2d`yTzV?sePOxKn?s+-6T#m+Q~@8|*Kea`e}f40|T; z9@9UyL<W+VnStTOG8mm?20H_C_RNGi*K$RMj`W$|8oK3t^SEBv-X<68dv*BP!}ikF z4!wN;hxYfPz52(>7wna^S{<3US4O8)=vYjxjEy{Rt`1bl_=$(jpI_W569@B5=%ZBe zy_I6ZUW$|OrzV?8+vnMc&B+>B;<r(&Vl{fvIU8fnYOH)?{l25>zp&p<?rYY#?xPal z(V*9S)+|$+_8ED*L9VT{X6n;B<hsho&9w3|3FHUO^rcxcBV~z6m{n@8k4-R%;h8pZ zI74qZJ;Nq-PS=@-N9~O*BYM*ZJ=RpsH#a|b$j;grZ)R^fDRVN<n_Jd>E^`CNOmb?Y zBu@-!ioZrudcW1w!3Sl2dyC%MRc#kE?$(8^57@NoCw0;8)%LbWcA4}YbL`^0Crn0Z zl+8@uXqKc8*sSPmlbsYP+5L%T>D7K&c4XY-^n5AH_b2FzwvXlZ`Y~Pk&TDeV)>FEw zw#lw8YS%Rny<&6IRM+M{X4hWoGI<MLmb|V5CO`gB$!~qrtQ%S{cfH%H1;@A8!e{pA z`cDgN(S19$_>G0OWO=!6s1jS6l%v72VH+Huso`PalOo*n-}ps_La&bce4)^LHY_3( zs;}|Ic;9i}E4;pG1%*Lhajv_i?%wTganM)jzByrkzrlYopO8D7R#d%+%m|qhGACqG zo^Dpiw2*lr6GLW(OwH5H4VfG=J7jvu{E!JEGeo9{%n_L+GD~Ed$UKpWA~Qv%>gnc+ zOxDxQ7MU(GUu43_jFBlLb4DhO%o>?CGH+z!$jp(cBXdV4kIdfFO&^&*k^m$F=%s)U za=>v(0J4Cj0m%cB2qY6oDv(?t$w0D!q{GwY14#&y5hNu@PLQM^SwYf*<ON9#k{Kj5 zNN$kiAlX6EgXG84B?!q7k|HEWNRp5&A!$PLgd_^d6p|_=S4gsuY<aqLA^Gxj2}3f5 zqzuU!k~Ac1NZOFRA&EmWholb49g;jGdr10_{CT<rA{j(dh~yASB9cWUjYuAmL?W3) zQi<deNhXp_PnS+4pPnwENJc$fN|Br*Nky`Xq!r04l2|0ONNSPXBFROv>-qmpuiv#e G%l{V~?gk?O diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Fort_Wayne b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Fort_Wayne deleted file mode 100644 index 09511ccdcf97a5baa8e1b0eb75e040eee6b6e0c4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1666 zcmdVaT};kV0LStFL*AOuCUenZx^UBrvdmhxOs$2dygYfS)X7^*(Gj&G`CoXy!A)V7 zj1gwph`4Am!&tLPDN)B;GiE#Fg4v$G^F7?Tvbk}do&V?GbJNZ5`vh`JHYPfMoH6Db zE@z#&yhpm`(ReP#J$385Y}z-$J$<5IK3qA&eb}2J9~}s~PolrdCq?6QSLLwtH1(tI z&gph~rg!RRNjIEcr$zTg9C!NEQT;sF>h^bR(=P@Z+?N-Q$bt46ckp0^RE>G=tCE0x zT{q8tlQ~DeEtuxM|1w2?F#kQ+7OB1So^l$3+PD9eN{g?O>1hi@`f#((h%HnZU59jL z*nE|FwM;Mk6s;DWJSZ3UqzZp+sm!`QLuBXs<&ydku{0%KE~^|8%Ok^OAm@Py{1}!i zk}irB?<VS1QTNoUyPx&yV6)0S+okgc4ypV-t$Iy+nJQS{pbHzbl<;4ZMf*#|+Sq!z zuGlZuhgHiB8S!Gnr(9V)Gh7sRrpS`f!=mJJl-xAbElTT?b=l+3YI9Yj-qO;g%5#ER z9&S}zla#I~Z&2GJ?&$5=HEMfsP*%;Y7gYndW%bl*QQdw<)_ltqI~w=OoxLfdwys$2 zYKsze1(|a9F-MH>+0V$3-!H%Z{Pi3)V$|q=@bSEsWXJKmn^$}xo_DFq8EfCi+vg;n z&ScNK-{G6O*dK5fq?x<i+?D1o2{`HIJ>7iA@!2N?{$g&PIRztwO~~w!=^^t&CWy?? zYNm+H5t*db%o3R<GEZcp$V`!`B6CG1Yc;b)ri;uMnJ_YAWXi~#kx3)7My8F-8<{vV zb7bmh=gte0=a|_8(?{lyBw#feASqZ)4oDJKlLe9nk_VCqk_nOuk_(ayk`0m$k`I!Q z)ntUEWHmV<Nm)%+NLol<NMcB4NNPxKNODMaNP0+qNP<X)NQzdIBa)=mWQn9{HF+Y5 zBAFtoBDo^TBH1G8BKaZ-BN-zpTTRYL(pHl-lD5_4jU<j_j--y{jwFv{kN<J{q2?DM Y$^0V3_-Dr@#?6ZHCnUrr#LWu*39tolUH||9 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Fortaleza b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Fortaleza deleted file mode 100644 index be57dc20b46142787cbd820e0d1c927d2f02f046..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 716 zcmb8sy)Q#i0EY3~`iPX2MZ%yCO%nsjiITR_h?Ou%I$$t~L<|fDi-^G_F_N&HQ4Dg& z)?}eI5h0T57hNPQ8mcLBoag=lKJLxQZ#cufdEVH}!hFB=<I`hqYs_idIb3XuH;)$L zUn45<G9Zt0D<T~}lIf?a%(UOznZ&fnezeNmeoo}Gd$JG<iq~Cjztzo(^2wZh_xe<2 zvR77;r=se)va1Ib_3>OUKeyIY$N9GOt=_6mHE4_Ah3eW^kll?b<)3P?{SV6`5GvV$ z>!b*k&+Kq~Q$+Gb87Ym4p_I0xOJ23EwRXGy^t!dad$cUAiv?G$);E_{!}vtZ>XZHE z1g+RVikOdTsvu<?O&z2VQVA*LXlfzF98EQ(98wP{h*U&MA~lhsNL8e)qp6D&b~Kfd z(nxLgrZ`d^DUZ}g7C=@&mT)v{Ad5JfRgh(nb&!P|%}U5p$Xd8={^d`5x!k`j=82l! HhJ&7OZnY#W diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Glace_Bay b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Glace_Bay deleted file mode 100644 index 48412a4cbf9241ea83887876b1b8b22c367ff4fd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2192 zcmdtiUrg0y9LMp4Akj&T3d#gcv_cGy{5y3N4J?dd5MSk>92NRj5P=m+f{;YDv|wwq zt<W+@bGfXGvW7XbjbUY8Wc7g6Y%P4q;YEw3)>@m%>3RQdyXvm>JA0njZ|CORoX<PF zzUkpS-#?z|?i&uzi|+8A{LF>73;G9l>KjLYlrMUI($NLKZywc2WBZGAyeTAc`m0Wt zQHd`e(JOKeOTxSXy)tRH_<eoqKi?r&*=;)G`&Ufja71T*)NZbRr_Cn4R%5Q|U1zWD zTxzasT4IwUX(pvC)m|T(GB+%|Y-i0+l^YYz*x50cW%h-?G<E!pq>YT}oMXpi?gztq z)BZPQUfV^R{_IYfU;T|;(7fN=96VxgS@oQ`HRV;Cv8cghOns=C{!)`UwnrEJoM~<w z>eQ@L_eggC1`P}>l*Qf4HRol&<TgfZUh6NCUs`Aj)_f(wj5+r9y!Yjf_^1t~o;0Cz z<95lV_sr7IKedHFykwRgvby}^R&(dBPqgUuuqkdipeuH4k-I9N*SqVhq-60Uy0RoF zD}UQ-OS4y-(o<cwEHU4d4b<6HlPTujecQGCyF97rs@40BBunMSB9*>BWc9LiUDI}2 zs?uULTzyo+mnL*=aG$K5h_N+u2TjdqXKiF^uUUWKxZN<;Wj5|OXlsY+OkI7iy}!TM zXvJIlzzenVV0Mo_)L10-iOt$jnl25K<=U7LD~(?Uv?+c<n%+&)=5r@x)9x($=+|e> zW9>8T<A;u$mg@6%^R9ztOK{Y-w)C1OQV!d#m7C1gsS#}t^+@~JfOgDkmX4u5?fkP` zp6uVI+fN6it2?4k4JJu<U7<d`=b}uDnHC%8uK&U(8a;8+=Zi+aH8FASeb|@az0dIO zr1FZeZ$*haRqm{FN5cH`eKFn@{udjGx`&-0TS4}MYzEnlr`ry)A7n%PAUi^~gzO2~ z6tXL1TgbjV-NuleAzMTChHMVm9kM-Sf5--r9U@yq_K0i}*(I_~WS_`JJ>5=`ts;9x zHjC^Q*)FnQWW&ggku4*8MmCM?8rim|+c&atPq%Yq>&V`b%_F-<wvX%|X#mmzqy<P1 zkR~8qK-z%x0cnJ%>jcsYq!&mtkZvIDK>C3+1nCIU5~L?cQ;@D8ZSiz{K^o)fI)k*v z)Aa^v4$>W@JxG6$1|c0nT7>inX%f;Uq)nc#Pe`LYU8j&%dAeR9%|g0`v<vAM(lDfB zNXw9(Ax%TNhO`ao8`3yW*Eythp00OD^E_SmkoF<{LmG&55NRROL!^mF7m+q1eMB1R z={kwD($n=4X{M*^Celu%pGZTIjv_5ZdW!$2rutoK3tV!uD)Iw)ft;+0+}uEJAjkhV DRnuf1 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Godthab b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Godthab deleted file mode 100644 index 0160308bf63690a6dee51c3c8849f494a47186c2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1878 zcmdVaYfQ~?9LMpKG}g?%E(w*86i#(IN4ZrlsfLd0K`zN92??PUaTqhR*1opJ48yc$ zMmz`)a+&KGVzXv$W172}4Rc%j`@R3>kw>1`{M-4z&U$vX@B8DMxwydN_~QvO|KY<^ zYCe2#w`XIaqm#E{VrS2H4T*ZIT{=C|(7;<7`th80Z9cBu?jF$Ymv(5_nX?jpv`!-S z?w1~wDv=eNq-Rly^qRdudT0A2DkVeuIFlthJVyGq>nbrp=^FESpvFFr)_zT0wEvYh zI-vfmI%{5QT=fHu-*Q6}R-aK<{xMC=y)W*Pdhw(-$iT@vB`IQ`B)iKbxy3Jo!>V=g z<9RaVN2v}yn=Zp1=4eW7o~AYo)wHc6b@-le9Z?XaBex8ZQJF!So*yQoqhD%9dW&QR zUDvFrCzAF4g^UTjAY&S@$=K#YGOq53WZyim-l|F&fApYEC@z+Xm78_a^zAyiXrWFS zRHVM_ES(xUUZ*+x>9j8{%?ZhroO>O0#^+d>dFqqSY6_Ow2RcY@{X3cC|0sFYjWRc{ zN#?D8qw|NKmIb*tH9vB<EKIG_g0?4hQH1KESG%;Zr9>BBE7v8DeY*7UEG@daQkHE? z)#BPIvb-=-S8Pp^m6KAWq##sQCH9cj8Q)}02Zxj<glOr9XHwSwi<aHFEamU->)I2w zvaYc~D|TPh^>zDnLwSw*tNiM>EGwXOtH6K$*UGYPZ*({;tLcuT_3wA{(}1>?#XH;U zbHuqk=HoV}7ZC94<@<|kH9ySaVtKe)<Z_YgMJ^b*Vq0^`$TcGuja)Ty*~oPx7mi#x za_PvmBNvZcJ#zWT^&<r!6(A+pni`NIkSdTekUEe;kV=qJkXn#pkZO=}kb01UkcyC! zY)wr_QMRTkq%5Q^q%fp1q%@>9q&TEHq&%cPq(G!Xq(r1fq)1y+B~qrXsS_y_sT3&{ zsTC;}sTL_0sTV02sTe64sTnES)>Ms@ZENaA3P&nON=Ir(ibtwP%17!)764fRWC@Tp zKo$X61!Ng)%{m|pfvg0w6v$d2i-D{LvK+{IAPa)52(l!|njnjUtO~L$wq{+Bg|Rg& zgDefQHpt>2tAi{LvOdTH+5T566r5s~Da~Wv?lh;@6Q30CN{Dkiy@{@0UlW6W0s=0- ADF6Tf diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Goose_Bay b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Goose_Bay deleted file mode 100644 index a3f299079aebb8524bf77e7f92e0a7e6d0a7b6fb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3210 zcmeIzZBP_-0LSq=QA894A5kbpO;7;=CC{f2!#EIRQ_#Z{SH%cC(+ov(!)%-pW}0!v z0ZntzCP(o_V~UfPO@t+SIaUiKok_S#kkP5&Q>ZJ~|GU0n##hYrvc1{;{MozV<?oxm zB=^l2({oo}@rIl0lDIjCd>|fWj>3-)o~c(V%Tn!Cj%dr-EqBVl`*@J$`^=j1a|I79 z)zd1<&#wq@To_(j?wozk@k5W3VHZbTc3iws5_ZXS+EF{^{`y+E#aUOB;QA%m%X;~( zajyFD&DLM7J}y_E3)U;4t*$G79kX5y=xw`NTkULU%(wl1Y^}Aia*^#?ahg>tv)HcZ zMq6(bj<7W)4YK~ROt&?MJ+QVU2D<(n7~s4)?y>7;`#oo?cY~|7=CbqemP(iV#A)ZP z^M_owzpb?1IsT2U?cgD6`>unwyW2jr-dnfbc7J)c^+DPy+rzlmtp7}!YwHMG>FoGz zjqTBZNcpkPJoRx$vi9U=gsQv3wWrPjYNw;W<~iD~n)bG7=ACtFkAhmwYkiy4Q@$hj zl4>RI*)?+Ss8f>9s0z7{{~pQLR4V(nZI=3K1#-VDC8}RlrriIlP3nMS8#VuZHZ`Dl zu{LnabahbfG;MHZusS3uNE>SDRELE<)dEKcNyB}vX(P-}r4jAA9CZDf6kO9Nzi{@f z^x}ysdE}>`NuxH_>ml27?V~ds`k1_ehOx2x^_P-!+~bBQdgz2CcWCE6WxVf1_xQ%G z%7j)w_r%I&N_gD_dqi2B5?RsDKB+K7iQ0YJ9-T8wkJ+HwCnt{7rz|*Wj}0~JFUOSF zr+PQ(mY^@(mX>OL+LPVx>F1B?Gp^>lXC6PN%=&tf`;}csl(<hU?%C^#l=vMP_Bm;J z%B$H^?Fo}ol(`AR?Q`!H>WLAt?!-D-Px2e)PO6xrC%YfH=N(wCq|^_!rz-Kv{4WPf zX-nf|sq~@r`pgh{!A6&~FxX2@&p0EcKWUa1#U79rHJdftiw@Oxu1U-6+^;S<T&=y) zsHjVK9MzUpW~o`(#oF?+*{Ym+L|(CTnY1#ZNM4l_CuRHP$*U7Xq}8`l<eX41Dd)#X zIoG>c%KhA5&TF|Kt=SW<*?(?Q*KX>sy?wk|U6;|Ot>1N2eJ8e7+pw-!eRs$yEkA9I zn%`L?Z?Y6gn;I+R&4GE+=E_oeOGk?IURi;>)fFizg_-jE4u7dIYlggS?_J5<!|c_w z%g4J{mp{6G@%-7RcQ-zLy7AlY{NJv>^>{8UHJLn~pGr(UJ)VZcW*>2O8fO>h2A8>? z@$~n2F01Cj;`ddiK#!+MGY3C=laiWln!ixo3F4N-y*S+zFV6AeU3`K#7?=4OJf9uY zyD?B6ab?Y#ITjfzWUP?ELPiT2E@Zrr0YgR%88T$dkU>L64H-6M+ziFQAtQ$jouL>z zWblyDLxv9-KV$%r5k!X2P>dlmh=yVmkzqu}5gABiB$1&+#u6D!WHgcCM8*>tP-H}r zAvF|ZiVUiu7*%9gk#R)^78zM&Xpyl+1{WD!WO$MBMFtodVPuGrF*X!~jEpie%!Xo| zk%2}=8X0Od#+n0z%_T+~7;a>|kpV|W92s(C%#lGyMjaV;WZVtKz#}7%3_UXT$lxQR zj|@LD{zw3j2p}OqVt@nzi2@P^Bo0U*3`Hc6P$02Df`LQ>2?r7nBp^sckdPoTL4txr z1qq9xhzk-JLlGGyG)Qca;2_aK!h^&I2@nz?Bt%GzkRTyZLc)Z^2?>;;h!hekBvweU zkZ2*{LgIx442c*LG9+e5(2%GhVKWqQLjq?gB8P;|P{a-i9uhqyd`SF|03s1YLWsl= z2_h0jB#ee4jz}O4MI@0>8j4sV!9=2ogcFG;5>O<fNJx>GB0)u>ii8!3D-u{k5m_X( zh9b5|a1BLtk?<n%MFNaO7zr^FV<gB(l#wtaaYh1dC?bu7+EBzA3AUk#HWF?m-blca nh$A6KVvhd@{XYu2uL%AW5&rPh$&oRUQQ@i4(UH-SQNI5ILTbFl diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Grand_Turk b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Grand_Turk deleted file mode 100644 index 06da1a6d7a3eeec0e82f7c5815a8fed4252e16b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1834 zcmdVaOH7nk7>DssBuY?HQK+aC6}4m#hKr(T@q$3c0Y<0{i&8JI7MzS=ITbsBR#6iT z(Ty<}G|`Y4FL7hgs*R17c#FDets!lU8hYx2g(>Y(HbxUZ&+~O}YSK+-^35-qNoMsv z|8PTeOQG}5SDXEHoPARE*pKcHE{`T3Xfl&KR_iIzfJyl*Tc-wn=EEfu^;F*kla}d| zX$iw-dfWt={xVU`_+wboAO5L6y7@pdF8-`$p1dftVvd=;w_7snpP4yZ`}EwRJ7!+x zVf}IHS(BCBrn5$GD_>&0_6?p<+0Pg2`TbogXCN%Oy;0@Av`F$gt5kk>niNDLrf~af zSr7=Cg=?QmQPzC3sIXrak54kiGal>Wp})<NH`n#jyARDLPkMDp-(PCkwLN<Ip<mRB z<D2!$*6&p5zTL8_=7=h5+$80BF;!7sCKV&+Odxlo4h$SL!K6|hywqYUhv(?369-iF zZ!0CVvstbAK2vJeg;Z@%ynI@cr`CQwBz5V@DqMeG!f!@Y!|4I@`QSmlZr>HNzQ09p zXgq2*_O8(qx~w*JHOuDQ9`!{eB#lY!swt2sO~VZ;l9eoxpGs78+=xWaXQ-`1ze;n@ zQq%I_h29oRH(&M*=+^pCqYhosUlnPyz4fSWOTA@w)O6?_qra<IagW3XZ>sjRc4_ZF zr8-_U$Tz+F)whpIWM^kY?Yf#Fog0E`_c2Gt#Et!r-tqtTk6ic1TE}tSt8q@e>;7=T zNpRhJH^xll)0y<oH`SrAQ)QouI{TD|ol<M~Jx<iMuV`0BK60w|Vja#EIa%avk<&%a z7dc_%jFD4D&KWsrPkYwLX(Q*2oH%mk$f+aej+{Jl_Q>fY=Z_?SWPqgLX>&l5@U&SV zX&`wZi6EIEsUW!^$spMv=^*(a2_YFFDIqx_NqO3=khGAzki?M8kkpXekmQi;ko1uJ zkOYwokrX{`j!2T8HcKQ;Pn#!_D3U3XDv~RbERrpfE|M>jFp@EnvZu`%NgBx-NgK%< zNgT->Ngc@@Ngl}_Ngv7I(@p>~1D<vYkU8+QlYq<uG7ZQ)AQOSi1Tq!KTp*Ky%my+Y z$b5L(2|;GW(@qI8C!TgvkXb>d1(_FQVvw0ZrUw6KbCYPdr^s$kPH2I@(4U_ZDk$(5 I`12Fr0@ri+2mk;8 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Grenada b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Grenada deleted file mode 100644 index 697cf5bcf7f151ffc1c1fc4247e4e9c7e3ff01a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 148 zcmWHE%1kq2zzZ0GvP?kCG1=UB4deg+$3hqw{{KIIfPuxwH-y14ID{dD1VjD<0ZxOs JfTo#n0RWR(9N_=} diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Guadeloupe b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Guadeloupe deleted file mode 100644 index 697cf5bcf7f151ffc1c1fc4247e4e9c7e3ff01a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 148 zcmWHE%1kq2zzZ0GvP?kCG1=UB4deg+$3hqw{{KIIfPuxwH-y14ID{dD1VjD<0ZxOs JfTo#n0RWR(9N_=} diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Guatemala b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Guatemala deleted file mode 100644 index 407138caf94e467b52d925f96ad80b506e16d9ec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 280 zcmWHE%1kq2zzaBmvdlotGk@-@JM5ur64=j9yCA7kksx{gNr3vRcMmj9#9VL*2}*F4 z_YPoUgu?&-SF12E{Qtjm10xHNy?}wk$2Ww**#(G$Ll{Cxu=YO?fUE{N5@bD?208&m ggPZ}TfldL@Am@N+kdr_($XOto1gCKU-Dk!H0Ozwql>h($ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Guayaquil b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Guayaquil deleted file mode 100644 index 0559a7a4a4288d7e3c3b1bcf47c57a7ea82be2ef..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 246 zcmWHE%1kq2zzbM`vMfL>&;TU1Epd|27W;ESyYQJq{r~^}8JU@wng9Ras=>hU|NpiO z2A2Q-j~`&<`2T<B1_mA<-w=jCAl5Z70b)~z5E3i{n*BesT`dAcgDeHw%>c3(Oam<k S(e*$%k{rNg19XO+DHi~Ii9p@} diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Guyana b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Guyana deleted file mode 100644 index d5dab14969306692ae95a1e9434252737b6c4b9d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 236 zcmWHE%1kq2zzbM_vLGxp<7Q<CSM3%X_4?li_5c6>XJle#{{R1E1p~wX|EFCTSpNUN zdVzuK|Nr9$82EgALl|@oj7>~IBoLc0gpgnp(D45t+d%FD*$ARRwt{HVZRWB8+HYsV F1psIVJdOYW diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Halifax b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Halifax deleted file mode 100644 index 756099abe6cee44295a5566ad6cd0c352fb82e64..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3424 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 VBH;<`BBCOk@Px?7h{y;h=x;6=LMH$K diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Havana b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Havana deleted file mode 100644 index b69ac4510784f23ee794cd6d11e62315a7318e5e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2416 zcmdtiUrbhY9LMp8zcJLJ6#qmLCJ7b)9_Vot3TG2VL*Pq1n({9)1c3-M69XaFN}{#V zMQJAEqB7=IVPpfV(OH5rNAnxxu+f--ana`1az;e*^n0Jx)<rk1uKJyw^ZM=Ff8O50 zs)}US-=5$<{<a&rhaEJZ_jY`7@WYYUq<e3PHCR-kgCqIY`LvCC{<B(pD0-(1wddJi z_0N;xwCncB+gIi5h*5jGEJ&w)P1elXOr4o5uzwv()7j2L)^7tR^hV1rYp&O&zRpS8 zb!0;QS_W+Y`hE@AJz)iweJ4SlMRu@tMs8ZX(F%z=E+Ny6cBrdGLVv8b=3TCm`QIF} z7ueZy^XXmoE!}TPSkp1<*8Cszwu&Bmp?gRdZ8&O&7d@|wS2fy8(#mydaEZMvVuLQ5 z%CK*rjn#+?#nv5Tp}M>)-HL1|kUQI=tf)edtf=$1?pl|xD|4?{(JNE*?u4_}s_>UJ zX32ydGuJ7x)5Chtc&pqydP?u>tC6^#!y4a_BMC?LYhrVvB-IzHyE0poA6cU*S@C+m zwOu^RFUsoVld}3okEBKnY3kI7J}~=%K6v(HO&fbv*K`fb+E4drdfO?<IObKWqDa?g zdSv~zS2QbniDZ3yLN*1=$fl1(ADSGK?DksOJT$F2FScs#=ee3!e_7@ApCy0ILV5U^ zOHvSVUA$X95%27%Z1uFu)+^U^TV$_p>%XYm=ib!9cY3sF{D2m}a8yhBO0~4SQ6KHF zv@GWhd90;GcEmTx<CPgwzMxokX04E&SJS03CO|5`jFPJ0@1^Q}f2p22CpCv7^@$6U zTD#AsPj(Gx-IfX6-PWm3dHQuvU8_DF{;uxLtI@r4XJlXMOR{hLxa?nAE&Kag<k?>~ zOG8JMG+s)O1I^je)Eg$vrSbCIk)Omb!2jPqf&PDaf&%}$$LH%Fbh*seb_M!;=WM?a zpYQZZ*Ze=f{Mnr2b!{~7x=iyHc+GlTE<Zo-KUkd4oT`@CUSxU5`j7=8D|9qVMAqnN z7KyCV(JT{LC$dmvrN~l|wK|%`BCB;Y%SG0UEEriavSf7D%!NgB%&LK9BkM*Mj;tJ6 zI<j_T@yO~O&GM1;JDLI@6+lXW)Bq_0QU#<8NF9(uAeBH$fz$#i22u^A97sJJO+k=~ zASFR+f)oX*3Q`uNE=XaJ${?jdYJ(I9sSZ*eM^hi9KuCp<5+OB0iiA`NDHBpBq)<qu zkWwMFLW+e{3n`bQsTWc(M^iDRWJt}Bq9Ij7%7)YpDI8Kcq;!s^c1ZCYP4$rSIhy(* z1w<-{ln|*QQbeSRNEwkjB85aMiImdO)DkJCqp2oRPDfKuq@YMek&+@cMT&}46)7uH zSER5=Ws%Y%wMB~SXsU~p*U{7$DX^odFj8Wq#z>KoDkEh^>WmZ`sWeh*q}E8W9Zj{7 zayy!OBL#Of6-P>r)Ep@~Qgx*4NZs-OTli2Ddyk2JTuw?tazavKQe2MPo!~Y%cj)ib CX!a@q diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Hermosillo b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Hermosillo deleted file mode 100644 index 791a9fa2b38729ff10032f9e1f021754c76c87f5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 416 zcmWHE%1kq2zzg_+vTQ&svUJ;vg7u&B9&AesOW5vwDPaeXS;CILZ68j*DonUBamxn= zhJpse^cDf5VzCBe_cQ^MpdSsU>K+1SMz<OmnZS^lkp&F@|DXPYf#LuExf2*z{{LUS zfPv%x|NaIB9uS*R03z<=8^Yil9KzrX!~sC;>k`5cLV|Pu0|Cg%AR6Rs5DjuVhz2<y zM1#Blrh(o7(IBsYXoz<}!BWrwB0=5)(IBsZXpr|nG{}n}8stq7O+~MA0sU^y1pq}$ Bj+_7h diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Indianapolis b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Indianapolis deleted file mode 100644 index 09511ccdcf97a5baa8e1b0eb75e040eee6b6e0c4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1666 zcmdVaT};kV0LStFL*AOuCUenZx^UBrvdmhxOs$2dygYfS)X7^*(Gj&G`CoXy!A)V7 zj1gwph`4Am!&tLPDN)B;GiE#Fg4v$G^F7?Tvbk}do&V?GbJNZ5`vh`JHYPfMoH6Db zE@z#&yhpm`(ReP#J$385Y}z-$J$<5IK3qA&eb}2J9~}s~PolrdCq?6QSLLwtH1(tI z&gph~rg!RRNjIEcr$zTg9C!NEQT;sF>h^bR(=P@Z+?N-Q$bt46ckp0^RE>G=tCE0x zT{q8tlQ~DeEtuxM|1w2?F#kQ+7OB1So^l$3+PD9eN{g?O>1hi@`f#((h%HnZU59jL z*nE|FwM;Mk6s;DWJSZ3UqzZp+sm!`QLuBXs<&ydku{0%KE~^|8%Ok^OAm@Py{1}!i zk}irB?<VS1QTNoUyPx&yV6)0S+okgc4ypV-t$Iy+nJQS{pbHzbl<;4ZMf*#|+Sq!z zuGlZuhgHiB8S!Gnr(9V)Gh7sRrpS`f!=mJJl-xAbElTT?b=l+3YI9Yj-qO;g%5#ER z9&S}zla#I~Z&2GJ?&$5=HEMfsP*%;Y7gYndW%bl*QQdw<)_ltqI~w=OoxLfdwys$2 zYKsze1(|a9F-MH>+0V$3-!H%Z{Pi3)V$|q=@bSEsWXJKmn^$}xo_DFq8EfCi+vg;n z&ScNK-{G6O*dK5fq?x<i+?D1o2{`HIJ>7iA@!2N?{$g&PIRztwO~~w!=^^t&CWy?? zYNm+H5t*db%o3R<GEZcp$V`!`B6CG1Yc;b)ri;uMnJ_YAWXi~#kx3)7My8F-8<{vV zb7bmh=gte0=a|_8(?{lyBw#feASqZ)4oDJKlLe9nk_VCqk_nOuk_(ayk`0m$k`I!Q z)ntUEWHmV<Nm)%+NLol<NMcB4NNPxKNODMaNP0+qNP<X)NQzdIBa)=mWQn9{HF+Y5 zBAFtoBDo^TBH1G8BKaZ-BN-zpTTRYL(pHl-lD5_4jU<j_j--y{jwFv{kN<J{q2?DM Y$^0V3_-Dr@#?6ZHCnUrr#LWu*39tolUH||9 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Knox b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Knox deleted file mode 100644 index fcd408d74df43310a9a85c475f83d545f6d75911..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2428 zcmd_rQB2ik7{~Dkfe-{G6GJjEt(buXHk3Bl+S0K@BA5qIA&k@z%Y0QJQKQ$bL0&XV zn~G})i(IZ5T2rwtG^N&R&d?-CCBP(SA+N>-DV@{%eY?zBUH7p6`TTcudiDF_T~hY^ zO!>=&*l&2aJ@(-}THBBMeTjPSC%>tNnz6cZ&jt1M>pp#U+K@V15^B!potKU&r_Fb% zN2ODmO;=Q%boIPtzV{v07f!4<7rS@qOZ(qc-K|ynhpp>WPko{8E%U0r>I{9^GfVwg z9H*}oq?`WCbops^thpK=D_3t$G}r9^eyx4j{M_FszjU;jfiK$R`te>h*xaMd-c#zv zwv&2jX|1|7Tq?J(ddx_tM}Ge@!T4Gd#Q%PTk=+pzP&;Twy*wy^Yr|Dg$rv4+dtKf2 z#DES-{ziqo5wAldKT@Fw-jy)(wi?s3Lx*=AG!Z8%^w?wD&A9#BC9<yE+`YA2##iN= zd&=@<!s0X&<w=u?kH?sMr^iV2)Y)p%=n;t-HA%(XjMn${-d2;_Z|VC#yQE?dUDR=n z$JLa|aq_^HMm06>hD=-asd+H<oII4Z*E}3`SmGbqV&Z-6dV1J0Gw0DtHFwSeHTTz} zk~w3w$vjslo`@Xd`FN9L4WyW--r1$+b<9`Uo2&HvBgrbKs8Hwb9IqCnXXvLZhSb8z zaoU^Lp}ZpjIzP2V<zI=FMX}$SMW2f-_8l=xn);-$d$%citxcY3-DrxJ?~|qVMdsP; zle(m~N<BBDNiQocRLdi3^oq<3wPIkUE{%^<rKhuWSxA5?JCLYX^<P#m?DWWsXZ&V$ zWrDoa+-uh4M~K>X%B)Qtlyz&~GwY+;r97wBl=}vBWm=P}>^`G6MAxVdt%r2g@Jh9@ zeuv)FnWZ*YSLjz-5><6^fqr%OST!oZ{saa&c)jya@ZWrY=fCZ~4gQBe`&a*(-~ZuP zB7Xm|g8@N){|5~++P#On&qzLH!k^#I%l68XbL_LwJ_Yv4^~zlP&IPzn@cxJO`Rx@4 z`WlcGB1=Tph%6FWC9+JXT_>_oWTnVbk+mX=b=uV;%SG0UEEriavSeh<$fA)|Bg;nC zjVv5lIkI$Q?a1PtcJ;{eop$|50gwtHB|vI`6alFMQU;_BNFk6)Af-TRfvy<5Pz}zO zgQFfuK{zUclmw{>QWT^rPFohFE>2q*j>;gVL282(2dNHH9*+7T1>&d>QX-BTAw}Y- z5>h6PIw6JPsFc%|3aJ%RETmdUxsZAx1>>j~QZkO3Aw}b;8d5fnx;bs(kjf#YLu%)= z#p9@+)0U5;eok9JjtU|rL~4i>5vd|lMx>5NA(2WVr9^7!w8ccK>9pnKsHf8wl%t|Z zNjYkY6qTc@NLe}RiWC;9EK*vewn%Z2>N;(Ck@`AqfsqP3ZHbW@BSq$@GE!!aIwOVV zs5DY)j#?wd=BT#QmK&+J(-s`5xYL##sX0<~r0Pi7k-8&=$NyL5!|X4CS@xGfV)kQ6 RGn0}Nvr|%%Qj(Ix{s3RXO|k$0 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Marengo b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Marengo deleted file mode 100644 index 1abf75e7e864625b975feebdd0b232d0de624b27..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1722 zcmdVaUucbC0LSt7*lf0p5t>?4b|E$U$0SXWtu-8mgBj)-o6~G~Ff;$=T==^ZN}Hsa z$lo;oLt03qB-tYQvpvQ}7|+ZF$$35Br*PrQrT6W9KX2#aT>ZX}FRyq>s`J+sZhqn6 z@|%b6*noM}9!m%uy7o=hZR-;_eBhb9w<8#6ivJ>;3L^CLmYTqelY3-a<+#AB?9uXd z{*XZX@EF;VmF~RhKT5wH7U#VEJV?JY|Mu?TSN*=D&G~TdsqSpN?R?yOU4N=qf#8)` z?H+fPQxnvl?Jrf2wMvJ`pa>N|WX~KW!p67C@Z?(}eAi$Z5q(}poY|)%^)``_R4y|! zCW_4N6FO_eLY38ArL&_ZsO$@+dQxY+ntX7lobq_Q@NO)TQ!ft{)8>0+PIai5o}MIU ztmzOlWBW<pth>VZy<5&sJ0)hf_tm*^jVkwcm!2Cuq4JJ4>v=6zYW|i>dO<^}$}g<Z z3u~t;;k_sewwH)SBdX<MzgHASRmh^OBvI6vC;h|v3IF|cSsd0aiqFK!r5%q%N%dG= z`k+fKE05L7>zmbzSwSs#Us5a6lwP%>My(!rOP5Vsr^<q@vV2UnC~vtbD`F}{MZ*!f z?rWY{U%ORqc#<wQR{G_pD{-PSKU;3z?}#2AbBBal`22PE4Eue1et-S>?O(rKw?4{o zT=(i(PpIpju5)_X@80$u&D$B^x_54PVy1X~&cqD!%rws&^W^xPO!J*-e&h1kH~9Wx zg08vpLxOe46p=Y1lSF2TOcR->)l3wbDKb@LuE=DO*&@?L=8H@inX%PO8JV-yOd6Rr zGHqnu$i$JEqn$b*%$>_j9+*8cePsSf0!Ri(3P=uClLV55)ue&sfh2-tVl}BCxmZmy zNH$iJ4w4U&5Rws+5|R^=6p|H^7Lpf|7?PRQq=w{XHOV2_SxtIKen^5yhDeG?j!2S7 zmPndNo=Bodrbwztu2z#QlC9OGi{xuH2_qRJDI+-}Nh4V!X(M?fi6faKsUx{tP4Y<g zR+B!GzttQ8$T5H%1;}xL90|y=fE*3@pC1pA=F~_tr$&NzWMXP!a)LJ{B{3y2Ir1lW C{a*3_ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Petersburg b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Petersburg deleted file mode 100644 index 0133548ecac014f4b37f0abcd471a5a6b4e7ed5f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1904 zcmdtiUue~39LMqJxPNZ$m`24e#xC+=i2JJzA{H5Kj8h&r^JungJ~QpOHrv;lYnJKn zqFf0frA&#K3oWED?T@7qVkRa;l#ap*>__Ap*4#5^wY1K!@B6uk#4G8p=kPnP-!^vl zyg#Ytwufh%t4^N&hKJLo5AVf+e)Ydz7VP}+4;k1rHF)*q@8q-RGQp`C7v)rIzWXtK zdw6zckqkA|nxC$}#SNF1nBfaIxpVs8=T1(zpND=hzr6je8##W=oPY5nH@Ytj+|EyA zY|GK$!p7HRymNPOaaphY+PEqB?T$A2y>eA>X>!_Knn;_=!wL82>4f>~#4MLNILkzP z;?C@dn^^CtoAkt}$y!q=*{xH8oTl@VJ9i|=tNK#%UMLOnr@bTjdv}=vw@s#mTZ6)H z_Ph9zwZYUwFS)wPZmF+ZAob%Pn1=Gzu3>PqOT_OC6YqAoyGLe(_q_7F%=>z-O|Ea3 z`S0Is8<!@fsW00usI8QH*ACf*#nUCV=!8vO9+$;6Z`j3WuX9UEj)zN*jk)_Xd&1`3 zgYJPdo5Q8g9B>aF?g(2}Y<J80=Z7}=p0xJ1+vVkb@=!WySHyc{WkaQ1InpfY(&;w+ zd9AeNj@!1qCGyD7SGK+HHrMgRSh%{o*gd*$Fzj5EakAw=xTYp_k9BSjAHVUa>uOvV zc4fYo?pyn8_nD8Sr>MvF9Ns1CCYtS&{m;r%r)%x{4QYA$V2Rz(l8}u%jGYwIPgb^v z*MEO<uK4MnzvSp!PVRsBMA2L2#zfJf{juyQdUL=`_V0!Mdm7*7hA8^<NUUgHGG*?n z(`TVR_vzD=GWGgiufOBO{5Pbo;SNW7TCy?&$X!P6GjgYqdyU*}<bHegjwAORx$DS% zNA5gw@4b5Wk^Aq}29OSr7LXp0CXg<WHjqA$MvzXBR*+thW{_@>cD&jT(h$-S(h~Zf zc%dndcEzDBq%RJQA)O(uA-y5Zd9^#FJ+Jo1p+TfWq(!7hq)DVpq)o5($)QoNc8av> z)n1Wik#3Q8k$#bek&cm;k)DyJk*<-pz1la@xK}$zTK8)2Nb^YdNc%|t$Oa%gfNTM> z2goKMyMSy1vJc2ccy%X`t?=qzAe-UU-9WYj*$-qxkR3s`1lbd0Q;=OjwguT2WMjO# zGsxC>b#IW(@#^j%+k@;6vO&lWAzOs(5&oYxsX(WyMyIMQIj3TFMO9g{y1JseqN?C; Daf7s4 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Tell_City b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Tell_City deleted file mode 100644 index 7bbb653cd7ce09d88f8a1701853bfe92ac7db0c4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1684 zcmdtiOGuPa9ER~TnU<0gQsF{u(IUdp9Ls2-s}vb?vdd(pre&Ji%~PqQm7YatyNIA0 zp$1k&bdkU;LPG5V5z&Q^f-p;yYVxE8Mm1mOIS>V{YS~}D`F#v7-)H=J6`PaA9~W-E z;o*wS!+WeUAI)dos^!KP+1ePTPM>@s?;i}R$8*Nz<Bj3^O<7w1;Jg?)l$k2tMlaOE zbK}JD=q&wiiV*J}P3ZSS1L8yba~-(TD?T2+sYfpNE8Wr~KOO2;qYY=|SY?|UFKUvX za~jpxVXywy=M~@Y#p_^ayl~Dr{o+_qyP970r_ZmE8R;uz#@IEHnXp}FJ~<)0kvZCX zb+5<@c=Xa!$5i&SWzx5=RxRsDk~szWYWdM<xgs@9t*joGt72y>|LSMb|IMXxQ#xht zV4PSR_f)UFEyTKDht6vo5cw~U>w*KlVtrSgE-X1Kikb`b24A<@*i<Wv6WY|KvV2(* z*{Di0(`0F&T$Rn8Ez2HcsfsBsS#i;=whX<NTaS9hwug@1UK1~NTz;i1b0dX3)T4K% zjEG&8XY}rwk3>~YldcK|RL$ZxS@ZIt+7r_#_jI+Z+KF;m*L+0n?aPw;>Z{fMPPeQt zT%#I}N6ASp^A|GN!t1ZUQ1c!Z8W#HNn}2(AoJ;40aGdK`T$3H=LaUf+->2En>3oVA zj&t{xE9UqA$@clhl63Q|GS3?GEcc5H^PXY8<6QRh=ZpU@mgkr&3<<U(3q)3kED>2F zvPfi=R<lfGoybCwl_E<;)@n72MOJGy%SG0UEEriavSeh<$fA)|Bg;nCjVv5lIkI$Q z?a1QMuAUc`&zbcD1t1k5C0I=j97R}76&z()O&uJCAeA7cAhjUHAk`q{AoU;xAr&Dd zSxrqyQC3qGM_E==7e`@8WgMj;wQ&@ORL4;sQXf(vQXx_zQX^8N)l`X;X*G2sg<4Ie zNU2Dz9K|Bla+HhI%TX{=F-OTr%^XErP1Q)*R#P`pxYbmSl#bMn6pvJol#kSp|IaT# bg!!RZWPUK*z6FWNiAips$CKzuOp5pcEUIOh diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Vevay b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Vevay deleted file mode 100644 index d236b7c07726828984d3afbfa872b3abeae3e809..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1414 zcmdVZPe@cj0LSsSx>`wALV<_HLms;5`X_`4149?FT>s>1wwaElEvDsEwykBhhsyHO zZH)*sijpD{%CHVn5fwxPN)ZG$1$h%j>`+Aen(tgY1znoQywBsEzrRqpYk#rx$603n za5?qn^6iV8*XYf>_|?Zh<k-1Y@oSeq%Gc+U@tNFja;ANS{xY~Fo}BV&_m-=ik)-wv zeO4*Ql}?pO;T6ARTAdOV1yLEOC>MdHab20;rYdKLbyen8Rdv5dZ(GP!+pk=Z)$hwh zaG+b(JX|koTY|DK;T83z1#-u+dC}m@lA*>|BJ^`fHkI5KO<z~*=A0L*`T3&Wl^j>$ z8?$=%+^}jnGpYAX_o&v65#2UgqeSq5Y#-_td-D@=UnD3xGGnr{vOsh$gk@wymWaG5 zm0jseqU&ysJTU)GbSF0Jp0|tYVAQ7%-J4atjY%ypPO8HtN+0PRQAgK3(|xu5sxSFT zMmHrybndB)WyeHp`nv4@9u_A?&&rb@O2xonM4p<;5reH&^7JJ~q<GAe>P<;Y|3{DO zPLw&0>pq(BcwP6-n6un|ue9$qyq&eK`|^n=yE+(h$}7xmFn6c9bs;BUz60hT$7A0R z`im%Bb6QiAV@MoGAV?%gC`c?wFjf-{5)RsU_#hyTi3kV@i3te`i3$k|i3<tLY9d2I zvzpkD;H)M(Bs?TOBtRrWBt#@eBuFGmBupeuBv7k~6baR8Vnu?rnrM-5k$91Sk%*Cy zk(iO7k*JZdk+_k-k;swIttNIPc&mvX3EyhsM+Sh502u-@24oP(D3D<w<3I+2j072q z)r<uhjMa<=8IIMA2N@7DB4kL&n2<psqr(4YSQ%z-C1!7V!Hxc6e_>v*sK{UBFU<H2 D;2*&? diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Vincennes b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Vincennes deleted file mode 100644 index c818929d19b2ca5925c181696f02a2ba93a7009a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1694 zcmdVaT}+K}0LSs?D6jLDVO_K?xG-CKBQvXwskP|H%kfspKjbWx{*jiqdM+s3xGOU| zGOuF|BjO@2v)IgxFk{O<6hr)T*qH4+{@?#4SKRqOd!Em;b8)VI-zSh?x*^s1;|w*w zaC1t`&3l|{9-)&7?vZOhWJ|+n_voP)^4{Kv`)Kl4`KWlf?%Eo59?$upRj9!2DGkV1 zbs6sKoSE`XFhliDjg@`b>CW46GxWPD@y@$16ZL!ZukRmz*B|;`IUg@P*ZrNholn<$ z<mYqB)m0%qaNw5vrT&BrR~~o2u4$Ct@*3Podz|)8dCF;yXkTNG%1o+}S(%GvR``mO zJ*`4#ckS0Xqvoodi{*NL|75k`@IIOQbdK=vERzc_PZD{Bez~YAS}aaal1sMsiKTHd zGO+Bf2>cAo<!NWc^4>9eWqhYvd3!*wikw#Y$Gdbv_kLBlyG^g|C|5=6oAsK|LM8l{ zWN~AeSUasrt_%9b`cbvABs)oz^ykaqlo%1bpDs&>ghgp<yxiFLM3gnn*5wZdR7Fjk z-gK@@RW6HYd7w>Ir769+vRQ4Ja7$O`ZBx~em$GJ7lc?#wDQjbEMQz71x$S$t*dE#= zcRWiMJL`gSS9`puE6S1e2OTlUXRfGd3$MRlgNK;Q{AlI<UoOvU9dI1ayL#Ri?RjTg zoMHBTq<xO%>5TWhJ2!l>x&DANFVoyh&Ar0hivmuTdCxMxaeVd(fxj4@XHHR6qy-ru zGD2jC$QY49BBQjLVIt#128xUn87eYXWU$C+k>MiaMFxzF*lLE1jM-`ijf@%@HZpEx z;K<04p(A5Q29Jy$89p+8v;pu!1RN6r5Cakf5{1=-!66Q-2?UA6YC=I`L4rY|LBc`e zK>|V|LPA1fLV`k~vYN1vxU42HBr>ZB4T%j24v7v44~Y*65Qz{85s48A5{VKC6N%Gm z0!1RVnoyBgttMC`S|nT~UL;^7VkBfFW+Z4NY9wqVZmS6#iQH;JM`E{{;F0K&@R9hD n4*>EJKt2TcUw;fnm~TXy`9>u8rzfT+CMWn)QW8@VlSljl+LDCq diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Winamac b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indiana/Winamac deleted file mode 100644 index 630935c1e1a8c1a87e728fc1dcc4c930e81b30e9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1778 zcmdtiNo-9~7{KxKsHrhEK`fd_SlCpnq=-BT(WWV$@zqe&F*eoW&>^j%?!vsmrbVPG z#28AbBGMp&L`0~X)iIT*a;g?Y@~-ngTQ)46n|ppYZ}k@6|BGbhE*&a<JDuz=yqrAy z@*VHltMYJyxBt=)RkgXhcVO=`b$e^nyFc)oy1$@{sV{0155_c`hRg=>u>T$ND5X|B z7S-lS?>*v)-esOfYrJPy3e5Ay3h%|SovN{})O)#YwbGSyyjQsq^}1}d_a<YwdYj$P zdp9#=n$kn!{fMCXFeoTKeC=aC+JEu!-gnd7^jds6^VGE5xGp~Lx@^8wYcF~s-uOp+ zEh?fWu;rCbO)6GtsZ&*2TdhbRJYT2RZ#Nm;#_Ei-`DT2}Ks{mKHZ}3#7#UudrzV{r zAScfat10C%a%w0^O)F}W)8pe*B=eSx{A^P*QjW_R?|PV7!5ezk^;R=GdQ@i}syA~Q zx9hnZYs|d5e4V|x!pyInq-FS=TCgQgE*xC07UhKH;%+5sNqUl8(vqce2F1yoJ0X?Z zu}$Wl460>K4KlBMl*zx_s+SkXn-$gddSzzRs2w$WRf;yNS61kP-q%dw<WgN2eW{8^ zmdoPCtE!}Li7cr*s7k+Q$u*Um)Y``(xvnfnt-lbIW!V{O!)_tl1?<y4#=+;GpAH@E z6KKc%?~m`Fx+{e5UpyU%@%<B3qO<$%>h7N0qL=UAyb|a;F&q)&Qtdn4zBBDRB_h)7 zcbff;6L2>~{$ebBd$QX{tB~<TMid!SWK@xHMMl<X#}*k~WPFhkM#dN!Wn`R@k#^d# zMn)SMZ)C)gF-Jxn8Fyslk+DZc9~pln0VD$?1tbR~38&2hNyBOLKoUVRK~h0-L6Sk2 z4IiY#vH1WAAsHblIc-iHl5*OtkhGjOFC;M}GbA-6HzYYEJ0v|MKO{jULnK9~%@Ik` zX|qJqblN<TM3GF9RFPbfWRYx<bdh|KgprJql#!f~q@6ZvByFe78%f-0Ge=TKaz~O! zvPaTK@<&zxvIdY<fUE;#B{=O`Kvsj(t_NgAIPIE1Rt2&ykd=X~4P<p7>jVFT6%uPV ZON!kr3E^RhLlcK2gp-pKlM{!;{sIlvy2bzi diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indianapolis b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Indianapolis deleted file mode 100644 index 09511ccdcf97a5baa8e1b0eb75e040eee6b6e0c4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1666 zcmdVaT};kV0LStFL*AOuCUenZx^UBrvdmhxOs$2dygYfS)X7^*(Gj&G`CoXy!A)V7 zj1gwph`4Am!&tLPDN)B;GiE#Fg4v$G^F7?Tvbk}do&V?GbJNZ5`vh`JHYPfMoH6Db zE@z#&yhpm`(ReP#J$385Y}z-$J$<5IK3qA&eb}2J9~}s~PolrdCq?6QSLLwtH1(tI z&gph~rg!RRNjIEcr$zTg9C!NEQT;sF>h^bR(=P@Z+?N-Q$bt46ckp0^RE>G=tCE0x zT{q8tlQ~DeEtuxM|1w2?F#kQ+7OB1So^l$3+PD9eN{g?O>1hi@`f#((h%HnZU59jL z*nE|FwM;Mk6s;DWJSZ3UqzZp+sm!`QLuBXs<&ydku{0%KE~^|8%Ok^OAm@Py{1}!i zk}irB?<VS1QTNoUyPx&yV6)0S+okgc4ypV-t$Iy+nJQS{pbHzbl<;4ZMf*#|+Sq!z zuGlZuhgHiB8S!Gnr(9V)Gh7sRrpS`f!=mJJl-xAbElTT?b=l+3YI9Yj-qO;g%5#ER z9&S}zla#I~Z&2GJ?&$5=HEMfsP*%;Y7gYndW%bl*QQdw<)_ltqI~w=OoxLfdwys$2 zYKsze1(|a9F-MH>+0V$3-!H%Z{Pi3)V$|q=@bSEsWXJKmn^$}xo_DFq8EfCi+vg;n z&ScNK-{G6O*dK5fq?x<i+?D1o2{`HIJ>7iA@!2N?{$g&PIRztwO~~w!=^^t&CWy?? zYNm+H5t*db%o3R<GEZcp$V`!`B6CG1Yc;b)ri;uMnJ_YAWXi~#kx3)7My8F-8<{vV zb7bmh=gte0=a|_8(?{lyBw#feASqZ)4oDJKlLe9nk_VCqk_nOuk_(ayk`0m$k`I!Q z)ntUEWHmV<Nm)%+NLol<NMcB4NNPxKNODMaNP0+qNP<X)NQzdIBa)=mWQn9{HF+Y5 zBAFtoBDo^TBH1G8BKaZ-BN-zpTTRYL(pHl-lD5_4jU<j_j--y{jwFv{kN<J{q2?DM Y$^0V3_-Dr@#?6ZHCnUrr#LWu*39tolUH||9 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Inuvik b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Inuvik deleted file mode 100644 index 87bb355295a3efcacd4baecb5a8bfa3fb9ce9c54..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1894 zcmdVaZ%h<)9LMpWWEwZopDWA+6|Fo$?l@2q@NWiPNGF6Rp%IpW*Qtg7cB4f6HffAU zd{>OMnJib$2dy-9&dm+y96rkCaC7}x*#9=m=AQ?$SzN#O&*yDDYJS=6#qOT|-k<n} z<mM9duh;H=z2AMZzn`#1ZWp~Oqx1XB)E>=yFxg@sS|2sp)lb`L<@x5}{P}kJ+$wn_ zGhk<A1ZBp}d7ATMrsNJkpfk_@F0($rs<RJWki67PJLjz<GIw3tKDy-#^H}K*_VLx9 znR(ggY_LF0aO{fa2X>nLk+WKGHEtFReyD|)wo7Q>Z4Do<m!i&uM&4Z{#fdIkvTK?w zjBd7z>PMwC_>6s`<QrK$vA~w)+%{#uO|s>8zBU!-|FlcKJ#CgA4d}Ad2hH-{KXk=` zeP(6bm-=Ma0a;ahRG(_uE0sm>XjSD#sk${}qoEEHy>!@CXEmGZ<2`ouwUwsk{g3t8 z%S{sN=+-qSmrHF^QtSHj<hi9aTA#|0wYedUulrfze@)Sb((}^rOQCI?^^<8FnrzpP z4VeueUAHfc95zi|!}i6&9@E@%!fqVcYF>(6)R()vWmD*wzLH2vOIDw@Mr)+?T1pea zkR&cNYI5QfNq$<PTYkMETl=54+b&KvucgZE>qoAewuT(Ly?5B`DE-^+Y&&6gWnZzo zYx~Xau{)Y7J0_`-@3eh-pR^C2(Kkj@^5(!H-SbtWbad|5y{9Uqv$<9Gy_YK)<1+3W z|3CcQeSPWlCm)O(pHBCR$xNpYs>$--ObtaMrmnIwZtB*?O^lEGKmH${ZQ31A7kR$O z6Xtlv$Wun1Gslxgo;AnQMxHnF#F1z2bx$36?#Pozo;~vPk>`&jfMkHAfaJiD1d;_u z8b}^qmk5%H*QJ8w!jTM;4U!I$50Vg)5t0&;6Ot5?6_OT`7m^r~nb)O;<i?R4k{w5S zNPZj%A{la|h~$VQiDZeSiR9^Zi6WVLU8+c~UY9JAEl0XYzDUAI#z@LY&PdWo)=1h& z-d>kDlDXHVj^yrj$s^fwq>tp!F#*U7a7+O*2ON`t%mOkE$UGnufy{*0O$9O+UN;%Y zY<S&tAoGDt2r?raQ-aJ1$D|;$!Z9t#yl_kmGBaK`HOSm}-Q*y%<8{-6%nvd_$P6J< jgv=2#NqCRVQo!xgVz*C)v4!E1aHKF+TpTVAM*{x<;7Gl; diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Iqaluit b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Iqaluit deleted file mode 100644 index c8138bdbb3cf141ad42ace037e144bee98d81481..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2032 zcmd_qZ)jC@9LMo<*HXDUV$^EtT)9>2&h6g2+0|*wv~66jcHPoD(`EYAW|!+$`=xf- z%BF!K`9#E+K{1m4AVthS8AUMi4;ErM9Y$2FUqO2iEq=BjX>d=!_b>EGPuAnkIOlaZ zJ8VzR`;%(RJXP!c>j>H>oE$y&<bLjj&cnMem;a$I%Y^<jvZUqOeVL(KGjVg<x=LM? z2$|a#&Cqv*rkmojkj$JmW@hD0ms!6D)$AX~q~y}CYR;*PQhMwwb?4z@a#z+fb6+|r zWvxG%@~s2<?$}v#&+-HM-lBI+Mdfx~kvpS8!B!m_c}G?LvQW<(+^edFQ&QcZQQ;E{ zB+|P=MGqEBO*(CAxBVsa;|X*Bs_!LMG0!Zh9h8Mr3ryYYZ*|>h&RaBb-Yh<M$vp5~ zzpfwnO+EPOZoOpxkb3C#&3b9qakXsEE_t~5Rn^eGNg5+r)zsJ^P2)#Qyn3UK5AQRH zf@L~!qSGuNE7vRDctt((^-@Xh>`*H|DwF2*N!8MqFOSwo)T-x3WpzoRO0|9=sfls5 zCib4J`S}*Jw)C7{d-keXmph`{-X1oOkL=Uy_nb6O40h@b?T5_9{*_viAF54zJ7jZp zpL#N#l=gydwIv>rEn{seT~R3MFY8ri%D7}cC{<fWuSiGVV$*r?s(w0KVxAco)?KYR zqxPTF&&IUb)^$j4FFI{@H23HoxgS)vu1~Tfr&M=ww{#D_rFyQl$@Bd$s~5hhmz}+7 z_2S2+(z_v{cD?4w&4Ij|^71G5GiB=J-ka20d}*HN`=5Un$oKtEj(XF4|H@EchI>-z zu0_88{+r%RejAu`{W)(|N26X-OUi3nZO_I=F7|vZ<u%v`4ffs({PXAS^~PQ5KYaPV zJ^1>O0-Ux2qy(e}{tHDQRUl;`bs&Wxl^~@cwK#1tNHs_~NIghFNJU6VNKHslNL5H# zNL@%_NM%l28d96n7Kc=al!w%Z6o^!al!(-b6p2)cl!?@d6pB=el#0~qw8e5zEmAI0 zFH$g4F;X&8Gg35CHBvTGH&QrKxzm=8)b6y!Bh@=?`AGf90w61ZECI3x$RZ%CfGh*D z4#+|vE8(<DfvknoE(Wq1PP-h)dLRpetO&9s$eJLFf~*R%EXcYb3xli-vNXurIPKyf ztK+oGgRGC!E)cRp$PyuIge(%WO2{%H>x3*6vQo%WA#3Hdi-oL~(=HdXUQWAU$ciCL nhO8N~XvnG|%ZC52bqm@pjM*8iO3n}0hND%<nwoG;I2!yL>(@dH diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Jamaica b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Jamaica deleted file mode 100644 index 2a9b7fd52d37a1ffe9fc589daa04d88c6c71a6e0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 482 zcmbu*F;Buk9ES0uk_c^)3WDIMQyobh+%-Uyi7q;I5!0=!3o!vT4otAP8W#r=1_s#J z{0waO1x)S}c>W(|V`9AK?l*LL-sn2%HPo-CDu1(bgL`?##rfCvsGjD7w>UqY7}q?; zo_<LE^{XzdZquFRP#50^CV1)T-RB!qx@+lj(lmQl$GXxEP4(2*`=MuQhhbdLeVPNu zi!;vF51+LQN2$%5wRSmEIcq;w8UL~qsSCO1UAbqGivCbw<s?r>eWXN!6g5cEMyW!| okUFFgsYFVVTBI1MM#_<TWC3IaWC>&qWD#T){QokpOmyOY16WpdI{*Lx diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Jujuy b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Jujuy deleted file mode 100644 index 604b85663672d83658f331a69cc8f41cf2a2b5a1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1048 zcmc)IziU%b9ER~5+h`0O0t$+V6l|%D2#2&WqE(J$D2Q2Vq0q@e1VK<7T0u0rIEWCC zAP6mub`?Di)zDUZY^<prN+1;x9fFFRMI?s!tH<wi{s7U*dpY@BxEU_I&*1Q>lZoJu zSD(CHFK6>*`MGl=rygDy(2usgFvT4?U0gY<rng+Q(^HdXrujh6-h8DVzy4sKoR6Bh znXTFm=giabaXo*aq)L}6_SyD^SvcOR7uMpcd^lyxwfk!EN?tEzZkwgmt9Ci#)Ux?x ztKCVnl0ISU2P3LJ(Xd~`r&S{n(~XZ4rnxC?o8_wdRv*>ht9#9lQqumMJ*Ix$9nfoI zN#(Bh>J5`eOr+yXVP}5Ibj0$7&eRvv`FW(!6(6!)@7|bQtJie5*<Xm)s%rPGq4rec zx!E@tH~pg<P5;|$d)7G@TG#TIces^X{){bh!p_Yv27z;>O3><D*#;5kURFYF&b_aN zVmt?JM>B&#TFxHTE2l?JA{hLKJ>(PJxv_giWEW%`WFKTBuk3_u<(0jV&5+%Y?U4PD z4Urv@Es;HuO_5!ZZN0KDvawfoMz%)w_R8kS?q1m**&k^D>A)*3AUz;Wc%=)Z4X^Zp zG=g-3w1V`4G=shy9;6+~JfI(>A*3UuC8Q^>G=+5Km9~(+kj9YCkk*jikmiu?ywV<K Q<x~Dgf6+cE@la3nH;<a=e*gdg diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Juneau b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Juneau deleted file mode 100644 index 451f3490096338f40e601628ac70f04112ace51d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2353 zcmciCZA{fw0LSrr5xCqd)GZ+qiH=Voj~=e^RFt6@Arct3n-Ezfc88UqFovQer6aeB zt8ETv(Q%Hgw$wA-O4q{DxwcG3u=Ow(rCYO{y4KTbB)9WD*m@Cf^M7~#pR@n&+uzq; z*Yu3f@t?<SzHoSY&EcN9-Mr53N>U^9er*|PNcBz}FB9RnGrW$zbm4qC)*I0=T}<1! zFcjI4rlMAPLeV8|<&sxIu2+{Sw|6MyK6Fxee$t`o-yKo0U!U{FeY9KMa^i^h)^`pI z@4nsM+jfP-?VDS@GnzJu_}aB1q1-R-C@S#IOwSjIb8AAg+=(J7A}^Gb8ShQ{d8wX# zae+!6nXm6W<x(j}qxD?}epI5pNY3d#tL6q~%X#a65cBh{%LOYw6{!i|%CwAkMcTx; zPWQYf(#O8h8JAl`=HN-4HTsIm?mwV&j%`qjx?a-q^=g$HRMOY#Q;W-9ly}#}tGu*E zneY2u6}TRhg~>BS;iZMLX#6*E&nF&v@A)r9u};<ZeQ-kDABxdS_U{)DG+)*wJKk4I zt3K1q8uzKvMThnB(oVJfmkY8iyHAvjo|fftTSWP>0lDI8y{LHOW4-c=4pq7Jpnmwh zI#pG_Q&;aTR;!AG`jPe&Rg+w<{Q-ya|COl&c^6gS`-kM}l(1NRCPUUvTo82wvGVb; z)1rRIHTlHgfLPNwET8P}5l>ZK(G5KZ)zjHSdTns0YK+r*U0G1AyShgQ)5=xwT$^rk zWvZq_0lofGoO*U|t9))aLp<O9sNA4qMRTA)w)9>T8}nz$P0hoiHDO$~RUH*=;hDO< za7eX}{i!<=wdxo=uQ&g(M{Vi<P<MXSrnYvyrMDdqsIE2L`h~ti<&2o-jGXcpHTg9< z#&r{a4##Mx!x0YmZg)h6!*7P1G4>s6-(J2u<HO<Z7DuAJC)@j+m6d)+b&WZXnNw{} zsozn{G2com%%!Bl+|1+T#WQ*FPdze^`2&Y1WDfV#uz8l8y8bzC>+zjIMu!Z~YQ~3l zfLs_Mj~OB`Mr4r4D3M_z<3t9EjMQp|ij38228)aq87?wjWWdOXks%{vMh1<H8W}b+ zZe-xd$dREVV@C#$jNWR7Z#Cmb0)RvS2>}uVBnU_pkT4)|Kmvh80tp2Y3nUm;6AdIB zRuc~-AV@@zkRUNZf`UW^2@4VzBrr&1kkBBpL4t!s2MLeW#0Low5+Ni+NQ{smAyGoY zgv1F66cQ;UR7k9lU|CJHkZ@T|ypVudO~jCpAu&UOhC~es8xl7pa7g5k&>^uyf@d|+ zL&9e@@k0V=H4#KYh{O;HA`(R;j7S`jKq8SuLW#r@2__OvB%D?gPb8pL6Hz3jRufYs zs7O?iup)6q0*gcz2`v&^B)CX)k?>kge31ZKO@xsUTTP6SAR|#m!i>Zj2{aOEyb<ci yh^Q%l(UV_Y?wFhS`=`|1<Nsr?{|)wyn}?DY(e$j!#W}tlnN^vao0FR(J%0nEhFEz3 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Kentucky/Louisville b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Kentucky/Louisville deleted file mode 100644 index 177836e4fd98399bd4cdda410648cc286408b95b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2772 zcmeIze@s<n9LMp4q6kV#`2!WNr4>VwUxvTJ(v;m$ubN&=(eTmKJJj-<C_x#XmOs+1 zY12VjBP}(pIa0G}HBw{dY-P$aQ^N;JDieLo)-Utkp7&WfxBlv%{_5PF^Llpvx!c|D z`x7iEnv>=H<BG9wxVd)On{$$DA5~jZ-B;fIO*XE$$=$T!v}`W^#o5w1L5{?ab&s6% z%g4`#-Q&G~lH)UCP2J)zlIk|c%Bk=k_w@c^bEdx1{c8JKsjn$>&#qc1x@xN1P!yEL z@}ch6c?0B|!k+HAltgLr=Q!UE^qKFHea`n?9CO}&`}v<6%@0kD&V>`Truk5<bMb=) zxm2xP<6A3#oE&1V9qysSdy`D$^@w&V!zOBFgKqJ-HZ3KrqSZBNHD0UM!_G=f#z7VH zTvv(huuEchtT%CHg=(vpOS>;$)$#j7a?`$Ly8ZTNOotce=!8|X&CO-^>syNarsI@8 zx>H_?={&fd?vm2hB=$;CUE4I9ZY|oXZa>CJ_l9PbbnJrkIB-<?c77^7H|<onmN@3N zr`M@o`HiOc+-iM$cCEQ%)bskzPFqcKpJJUH{!mil@^wo67U^?-pzd3<Qc~-Js$W%+ zr0pJ{(#uCn#=1n6848)Kg}<x*{ycNngfl8Txvv?JRig&R#G66gPw7ETm(1X+@9QCl zj+whpSLvMUi!$^*SKqVdGr9MrnR?iQT{3*xQgz?B^)h1C3^g*nL~=)tP`OvO8Gpa& z+F!TY<i!uydAsMEQO&*e=$BW?m=nWPV97ig`%W)4ZdyRbS467^a?)kO;wCjQDM5ny zhgI<E6`7R%hMIJ)y_xJgq$k&2HdDgebiw92GqrxTp0;d{d8lT-E}T_qrdN&CD)6?< zSUFG4>{lTVhXQI=e5uU#r>oh`1rkb5P@zw9q^R{3RkXt=bDKU_^D2gz`A0A7M@o{+ zqt$hKL4MfCnmzilY;6`UsMN)s4w^;d%Jib}St%J*p-SoxNNHlJDy?}<%6=_SPgE_J zCr{?6CFLP`YOha~7v{;*7aY|h>aS1B=<CP7UtPCV>l;2%H=J*L|6iRWk?IYO6N&75 zD=In?d2^%F#yhw3o*j5P9V3yC_D3a-2?U)HBkeuW-VfS)e9+0Y=Un@aE6RI9@L&A% zBlaq68QzE#0I2{{0;C2=5s)e%W$?6hKnj6W!qb)lsfDL422u^A97sKof*=(^N`lk` zDGE{*q%25XkisC9K}v(v1}P3w9Zy>xq&`T2kP0CsLTZE*38@lNCiLpWfkJWFN&%%p zYK0UFsTNW$q+UqDJZ;60l6l&iAw@%~hLjDd8&Wu=a!Bcr+9Ab5s)v*hsUK26q=HBZ zks2aJ^t4q(%81kvDI`)!q?AZ4kzyj%M9PWO6DcTCQKY1vwx&o?J#AHyvLbaw3X4=0 zDJ@c4q_{|Rk@6z-MGA~m7%4GQW2DHQw#rDEkvb!VMk<Yz8mTo>Y^2&qxsiG!1xG55 zl-$$S94We|tvXV6Pg{4S@JQv6(j&D;ijPzuDL+zwWC4&BK$gJMt^u+Lo^}<GW$?7? zfGh;E639{@Yk@2VvKq*8AnSoF2(lu`k|1k>EQ+UH6=YdF?YbZf<7rn0SsG+*ki|h( z2U#9ueUJr0RtQ-lWQ~wT^0cdjER&~QCuE^K?Mfj_g{&2_SjcK2%Z02L{=Z=S3M^Qh a9ky&cY^j0%X<2C*se#PQw9K@OxIY1Es=sdl diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Kentucky/Monticello b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Kentucky/Monticello deleted file mode 100644 index 438e3eab4a6e581c6f5e7661098bf07b1a000593..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2352 zcmd_qUrg0y9LMp8Kk`oyC@Dmuf|4QsF%pRi1I93qkRAxg@BuM~P&_6gl;O`!Gu@h- z655|3%+{>tB#EZANLw@4pCz)I&7xlyvF3(8L>CoyPS5+f?W)#Y-?QI&{m!}nyuJ0U zPvnWeU8wnohwC#B?}?828h9haIr{$ZYVi35&d@7Y)aNhwoJ%Rcs!NUG`o`r7@#lqf z?K_<={KuoTI1(iS_FmV4+pmkDEs-j?alSLJ>Y55Eo_0cWE~?NMQ=RabQ!4z#F%hBr z)O`1l6Z!41jyk)|S#ai{j(+o?h<UkF$L{MCH}%x$n_Fwd!ny(-S5Y8tS&^V`O-m5* z$;;KEup1&FaFI&*CEi*5<D5zy|HHZM-1jQ!o$s96hdxqwbVZ9hcMYlJ>KT!;`9pnI z{)D)D)lt19Zd9Z$-KA4~<4#({Mx8b};w-&drqjn>axx~GROY~TCu^isW%t%OIfs_0 z+?Fnpw>3;HE3Xyzti7u8Qwzntd0(jIp^2hk@z1(o$|qLLeWnY~kL&xc47f!nuc`Y# zaNGwDTvQLf+T<2@oKh=y@01T!_NkKQMp>HOrOHZ6WZCR-U7oqYEuYx0E237q6(j9> z)pUyc@N4_j>TimrXGfb_^Io#7T<=j;{lW5)qHMKx+mu|F7^}S17o>M?R@LOcC2M|) z*0o9J-P%uPbe-?GTmSlmer$5TyMFhmetfLmZD>BMHw>(CrRQDMxVKF<W%jF$Egsn% z)vY#_XUk2~^{OQ`R<?Xuq*_B}W$TF~wR!4m+16jE+rOG|pX^H1Po11_JF0zJ9T;`D z<h%Omj>GQOxQ}&bWslqG`$2UT^vkZvbE-SOTXv5fQ$4@c%V!4msAn%1$sN5d>bcWN zvbUi^?K~o6V1W4q1zULi*PoDi|JldyAMO;w?>{pf5bXEAJt)HLd!+r2@%ukL8?caf z5x?5w6(yzSS!bR{%~RzSW#)I8`OO8`Z}9$ujrq+r1o;M$ts#3uHizsE*&eb#tJxs3 zLu89+_s9#I<jgKPwu$VMW24AUk*y+oMK)_SyG6EZHT&h*FtTH0%gCOQO(VPJ*fz3n zj*TNb=h!;3caF^?yXV+GvVV>SSWO3z79c%9nt*fxX#>&+jz%Dz;AjQX3yx+W-QZ}4 z)${{th}CoiX$jI3q$x;OkhUOwK^lW}hNCq|Z#bHRbcdroNPjpQWHlY)Xc5vQq)AAZ zkTxNGLK=m13TYM6E2LRSw~%&OO}~(aSxv`~mRU{DkftGBL)wP)4QU+GIiz(+?~vvp z-9y@EHT^>xXf+)~T4*&rM4E_n5osgRN2HNRCy`bny+oRcbQ5VO(odwJR?|_WrB>5Z zq^VZZRiv#*Uy;Tlokd!U^cHC@(p{vzNPm$ATTO?N7F$h^ktSPBmytFjeMTCMbQ)<j g(rf%bH9Nv&Jm2Iz!?P?aFDoa*lbf5Bo0Svs7o2gMVgLXD diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Knox_IN b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Knox_IN deleted file mode 100644 index fcd408d74df43310a9a85c475f83d545f6d75911..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2428 zcmd_rQB2ik7{~Dkfe-{G6GJjEt(buXHk3Bl+S0K@BA5qIA&k@z%Y0QJQKQ$bL0&XV zn~G})i(IZ5T2rwtG^N&R&d?-CCBP(SA+N>-DV@{%eY?zBUH7p6`TTcudiDF_T~hY^ zO!>=&*l&2aJ@(-}THBBMeTjPSC%>tNnz6cZ&jt1M>pp#U+K@V15^B!potKU&r_Fb% zN2ODmO;=Q%boIPtzV{v07f!4<7rS@qOZ(qc-K|ynhpp>WPko{8E%U0r>I{9^GfVwg z9H*}oq?`WCbops^thpK=D_3t$G}r9^eyx4j{M_FszjU;jfiK$R`te>h*xaMd-c#zv zwv&2jX|1|7Tq?J(ddx_tM}Ge@!T4Gd#Q%PTk=+pzP&;Twy*wy^Yr|Dg$rv4+dtKf2 z#DES-{ziqo5wAldKT@Fw-jy)(wi?s3Lx*=AG!Z8%^w?wD&A9#BC9<yE+`YA2##iN= zd&=@<!s0X&<w=u?kH?sMr^iV2)Y)p%=n;t-HA%(XjMn${-d2;_Z|VC#yQE?dUDR=n z$JLa|aq_^HMm06>hD=-asd+H<oII4Z*E}3`SmGbqV&Z-6dV1J0Gw0DtHFwSeHTTz} zk~w3w$vjslo`@Xd`FN9L4WyW--r1$+b<9`Uo2&HvBgrbKs8Hwb9IqCnXXvLZhSb8z zaoU^Lp}ZpjIzP2V<zI=FMX}$SMW2f-_8l=xn);-$d$%citxcY3-DrxJ?~|qVMdsP; zle(m~N<BBDNiQocRLdi3^oq<3wPIkUE{%^<rKhuWSxA5?JCLYX^<P#m?DWWsXZ&V$ zWrDoa+-uh4M~K>X%B)Qtlyz&~GwY+;r97wBl=}vBWm=P}>^`G6MAxVdt%r2g@Jh9@ zeuv)FnWZ*YSLjz-5><6^fqr%OST!oZ{saa&c)jya@ZWrY=fCZ~4gQBe`&a*(-~ZuP zB7Xm|g8@N){|5~++P#On&qzLH!k^#I%l68XbL_LwJ_Yv4^~zlP&IPzn@cxJO`Rx@4 z`WlcGB1=Tph%6FWC9+JXT_>_oWTnVbk+mX=b=uV;%SG0UEEriavSeh<$fA)|Bg;nC zjVv5lIkI$Q?a1PtcJ;{eop$|50gwtHB|vI`6alFMQU;_BNFk6)Af-TRfvy<5Pz}zO zgQFfuK{zUclmw{>QWT^rPFohFE>2q*j>;gVL282(2dNHH9*+7T1>&d>QX-BTAw}Y- z5>h6PIw6JPsFc%|3aJ%RETmdUxsZAx1>>j~QZkO3Aw}b;8d5fnx;bs(kjf#YLu%)= z#p9@+)0U5;eok9JjtU|rL~4i>5vd|lMx>5NA(2WVr9^7!w8ccK>9pnKsHf8wl%t|Z zNjYkY6qTc@NLe}RiWC;9EK*vewn%Z2>N;(Ck@`AqfsqP3ZHbW@BSq$@GE!!aIwOVV zs5DY)j#?wd=BT#QmK&+J(-s`5xYL##sX0<~r0Pi7k-8&=$NyL5!|X4CS@xGfV)kQ6 RGn0}Nvr|%%Qj(Ix{s3RXO|k$0 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Kralendijk b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Kralendijk deleted file mode 100644 index f7ab6efcc0f5bfd5c4172cbe32c03a8e08b0099c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 186 zcmWHE%1kq2zzdjwvdlotH(5?k`P+;)9*j)?|L>1wVEF(4zzznM|NoC4VBqrc4PnqV eFfle@a10J%2qD4L|3CmT8AKCjIv3Ci6D|O%z%CO2 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/La_Paz b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/La_Paz deleted file mode 100644 index a10137243577a8b312dc463571c4c94ecd3bf1f1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 232 zcmWHE%1kq2zzbM_vLGzb03>$EO?$HA-PJ4g|NsAIWMXFi|Nnpt0|S_3`Tzf%4kO3^ z|Hlt7@c8(KFgOFTQ*a1_u7L?d2nqH8jsBn6E}a6RLH2=Zpq)VL8R~%?Qtaij0orb7 G!UX`MNklgQ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Lima b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Lima deleted file mode 100644 index 3c6529b7567f032882863fcd48b790e0988261bf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 406 zcmWHE%1kq2zzYO{vMfN%(*PuTN*t~nKJOK9#PzYmQGKrq$K-Vn9Ou`$aQr|20Xc~y z0doDZ4)Q<0Ur;ERa6on5;|pq{H3xK6nFDlZ&vB^#|NlQDGZPAA{{Mgb5e5bzxducY zKfuWH|NqVn3>-ebAq=_(CO~Y;5JG|@fp+}QY**d`qCt)Y(I5wdXpo~pG|1r~8svBo z4e|h(26_VMM+T5bz%<Y^AR6Q$5DoGahz5BKM1wpBqCp-6(?Cyx=z5@GWO<a!2IyTo GQ!W6}riQNo diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Los_Angeles b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Los_Angeles deleted file mode 100644 index 9dad4f4c75b373635ccbe634798f8d9e587e36c1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2836 zcmd_rX;76_9LMpCq6mtfOq2-iq$YxZfTFmRxecHqDoA36O9F#ws1Rxy(nOgx#-Gfk zjgDqbP8phGV_AeYIW>)C&^T@pSt6t2f|j^+Z|8g7_Ntdn&ok%woVoAs_m?@lATPo5 zkEetEg~RiiJ=}Yg*-zDbDdz3{A!447GFxB2F5j&SGj;v0Ev=hBKppiK&pB4MQ%-ol zl9RQfPBpwMKkxWZ8fw<cFY8{G#;OAOwP2~7E}bmDrOuGwb7JI7<WOl!o}|uppRSrC zqE&P25Opq~t2$Q~qRuy6Ru^_(S1pI?)Wyo<>QePZxx8$@x>9jOTGt$qtA!uSwYl%e zAL*~kpJSer>w`<AZQwR_quVUG*{NLJY<pJUYR*%)kLBvWzDZHueaYJQew6ZTiPU~C zbW!bAcGm5e4HW<R5vIfRAn7<Z&;-O?kbw2$O`!T-0(X9?gD&rq&W+Wk%kjf1xVF-C z{j^$j+wqZBuT`o$)`{-Esz}{guw3`Zo~c4oGj-1q!&R@yVLG&LhTIhxs>9kPN?7Yq zbNA_95?<HS^geJy`s{8q_iQ~Wx@3^P_n9xGZ&tAGx9EiGpLj{%H|cXVAmm3K5mluk zye%d&s7ysR{9vNaEl`7McAMz>Qi-YBU}E>olfk7=n79q&BtHKYolw+Yh9np3p&1<| zF(OM3OK6ti0ZBS3yn{+Q8>UCxI;%z=x~)f@{8o+L6>9F^|ABg-;-(q%#(MQ&;VCn= ze20unuQB5nz9bU{8#8gj5}A0lUMI)AsFLgV>eS%HDs|6hJ*j1?n*8P-Gv(+aNn5?q zO#Nhvq|aGlrfrIq>7%pFj1nao;iF9E%vQ;~-P>d({v=svM(SC8uBcgGhwE%_y_&t< zs~>LItLBt9>PKoetDJ=g_1vmeYF=7{nZI_UEQqN!kLItCg~8iQZgRHdwv?Ovh*6S% zIL{OW^p=91DP~cVPafNps}~;$S4&Eg_2boERhSj2msT{YWy3n_<%I`TQAmp}PT#JI zeSxMVsa8rF&YP8?+hk?UVY8~OT%N3|HcuVPlhvh_=IMPYQkqj_)@+HAc7FD4@9*IH z-+6t$$^jma&-a%2`TKkoWu8v%-o<^@l(bCGv<dcP*z=G*(=zQp+T-zapUi(z0-t?y z{KIOIA|O>j%7D}XDFjjpr!56i3#1rGHIQ;3^*{=OR0JsrQWK;oNL7%sAay|sgH#47 z4N@DYEe=v0r!5asAEZD?g^&^<HA0GnR0$~)QYWNPNTrZcA+<t^g;WbEm($h@DHu{Q zq-5x7#)YEs*s1|#L+XYU4yhbcI;3_;@tn4LNco($en<h43L+&$YKRmOsUlKFq>e}- zkxC+^L~4l?6R9RrPNbelL7lduNJ){JB1J{2ij)<pD^ggbvPfx>+9Jh8s*9A@Y3qv= z*l8<_lo+WoQe>pcNSTp3BZWpPjg%UxHBxM(+DN&PdLspQ+KMA3M{14~9jQ7}cBJk| z;gQNCrAKOy6d$QRQhukcKe7N$y8_4(IPDrBi-4>GvJA*NAPa%41hN#!S|E#otOl|i zPP-n+f;jDpAWP!3Yl18avMR{3AnSrG46-uF(jaStEDo|d$nqfTgDjBKt`M?BPP<0P zB023UA<KlU6S7dqN+C;ytQE3Y$Z8?Wg{&8{U{1SY$dWnjnjwqkw5x_J8?tW5!XYb% jEFH3T`2StJAUlLfb`Yb}hQubs#zm*a$H&IU#s&Qiukn{d diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Louisville b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Louisville deleted file mode 100644 index 177836e4fd98399bd4cdda410648cc286408b95b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2772 zcmeIze@s<n9LMp4q6kV#`2!WNr4>VwUxvTJ(v;m$ubN&=(eTmKJJj-<C_x#XmOs+1 zY12VjBP}(pIa0G}HBw{dY-P$aQ^N;JDieLo)-Utkp7&WfxBlv%{_5PF^Llpvx!c|D z`x7iEnv>=H<BG9wxVd)On{$$DA5~jZ-B;fIO*XE$$=$T!v}`W^#o5w1L5{?ab&s6% z%g4`#-Q&G~lH)UCP2J)zlIk|c%Bk=k_w@c^bEdx1{c8JKsjn$>&#qc1x@xN1P!yEL z@}ch6c?0B|!k+HAltgLr=Q!UE^qKFHea`n?9CO}&`}v<6%@0kD&V>`Truk5<bMb=) zxm2xP<6A3#oE&1V9qysSdy`D$^@w&V!zOBFgKqJ-HZ3KrqSZBNHD0UM!_G=f#z7VH zTvv(huuEchtT%CHg=(vpOS>;$)$#j7a?`$Ly8ZTNOotce=!8|X&CO-^>syNarsI@8 zx>H_?={&fd?vm2hB=$;CUE4I9ZY|oXZa>CJ_l9PbbnJrkIB-<?c77^7H|<onmN@3N zr`M@o`HiOc+-iM$cCEQ%)bskzPFqcKpJJUH{!mil@^wo67U^?-pzd3<Qc~-Js$W%+ zr0pJ{(#uCn#=1n6848)Kg}<x*{ycNngfl8Txvv?JRig&R#G66gPw7ETm(1X+@9QCl zj+whpSLvMUi!$^*SKqVdGr9MrnR?iQT{3*xQgz?B^)h1C3^g*nL~=)tP`OvO8Gpa& z+F!TY<i!uydAsMEQO&*e=$BW?m=nWPV97ig`%W)4ZdyRbS467^a?)kO;wCjQDM5ny zhgI<E6`7R%hMIJ)y_xJgq$k&2HdDgebiw92GqrxTp0;d{d8lT-E}T_qrdN&CD)6?< zSUFG4>{lTVhXQI=e5uU#r>oh`1rkb5P@zw9q^R{3RkXt=bDKU_^D2gz`A0A7M@o{+ zqt$hKL4MfCnmzilY;6`UsMN)s4w^;d%Jib}St%J*p-SoxNNHlJDy?}<%6=_SPgE_J zCr{?6CFLP`YOha~7v{;*7aY|h>aS1B=<CP7UtPCV>l;2%H=J*L|6iRWk?IYO6N&75 zD=In?d2^%F#yhw3o*j5P9V3yC_D3a-2?U)HBkeuW-VfS)e9+0Y=Un@aE6RI9@L&A% zBlaq68QzE#0I2{{0;C2=5s)e%W$?6hKnj6W!qb)lsfDL422u^A97sKof*=(^N`lk` zDGE{*q%25XkisC9K}v(v1}P3w9Zy>xq&`T2kP0CsLTZE*38@lNCiLpWfkJWFN&%%p zYK0UFsTNW$q+UqDJZ;60l6l&iAw@%~hLjDd8&Wu=a!Bcr+9Ab5s)v*hsUK26q=HBZ zks2aJ^t4q(%81kvDI`)!q?AZ4kzyj%M9PWO6DcTCQKY1vwx&o?J#AHyvLbaw3X4=0 zDJ@c4q_{|Rk@6z-MGA~m7%4GQW2DHQw#rDEkvb!VMk<Yz8mTo>Y^2&qxsiG!1xG55 zl-$$S94We|tvXV6Pg{4S@JQv6(j&D;ijPzuDL+zwWC4&BK$gJMt^u+Lo^}<GW$?7? zfGh;E639{@Yk@2VvKq*8AnSoF2(lu`k|1k>EQ+UH6=YdF?YbZf<7rn0SsG+*ki|h( z2U#9ueUJr0RtQ-lWQ~wT^0cdjER&~QCuE^K?Mfj_g{&2_SjcK2%Z02L{=Z=S3M^Qh a9ky&cY^j0%X<2C*se#PQw9K@OxIY1Es=sdl diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Lower_Princes b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Lower_Princes deleted file mode 100644 index f7ab6efcc0f5bfd5c4172cbe32c03a8e08b0099c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 186 zcmWHE%1kq2zzdjwvdlotH(5?k`P+;)9*j)?|L>1wVEF(4zzznM|NoC4VBqrc4PnqV eFfle@a10J%2qD4L|3CmT8AKCjIv3Ci6D|O%z%CO2 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Maceio b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Maceio deleted file mode 100644 index bc8b951d2e880182a369cba8fae1270e40694aaa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 744 zcmb8sy)Q#i0EY3~`iPX2#b9V18jFw|EomE#SP6rq0|t`_6N7<-AYqaiNm$M(2DxKv zvQQ=>MAEcXI<gQSO_Ad~_Ya`%&B<>#!@YUl`1s6J(E9ahH@6k$)NLP3FD2>+@`>+$ zm3;1&N4a^CjvUJLV@YP3?(Ix+Ok_VBWo|Dg?y|cw9}kJw9c{l=O^Em7N%`URtKvw9 zET&FG$#Z3w_KWKCsak$*E-T;pmh>;&s%F(=i_nE?S(}lqwPz|Y+F%DB=0scg#csP! z3Awr`yL`hc{C;Xj5*s3VSCG+{LD74r?bxhWt!S;?t}<V@*12`d(z=j$Rcd{6Y1Ir3 z$E{8oG$&-m|Ix;LR?`P*<Y+n}t&m<wGe^@6Y3FGAAq|m^NK2$A(iG{6v_<+NjU7#A zq_v~zjWkEPvpnsQ{>TQ%4#*bB9>^w+W*1}|N3##I5wa7q6|xtynWNba*$&wcSIoba RxuDDa$A+GmS+XzW`2pmRDPI5p diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Managua b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Managua deleted file mode 100644 index e0242bff6e5df45de8b235abb4a8405fbb8ba6a6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 430 zcmWHE%1kq2zzYO`vTQ&s(f}m(>Uz9jb1q5XTw)g>82ICX;FbIUVZ&Pwgtr6+XeLfn z&^qWHpzVD3fziqL0ZtJI9yr@)2DpUeHMq)0CNMHFGqC_6GnD@Sf4vL?1CW$pVEO-l z^#TTt|NnPxVBi6fi~<l5AKwrLUm$i44q<QwVrQ2Sh7c0m{2vH1+jUYvG|25hFED`I z528VS0MQ_SfN7v#Ks3ldU>fKr5DoGdhz9u$M1%YXqCtKH(I9_<Xpmn)G|0aonwoy* J0tSE?7XaekaB%<t diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Manaus b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Manaus deleted file mode 100644 index 63d58f80f556e1c3135d6dbcb2a2dfc6f61b4fc9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 604 zcmb8sJ4?e*0EXctUMTUlxHza)*A@=8gNVrSGO8d11b;w9aB|VD=-OQb9URr^jIDGy z;85H|(V?`pi(5biFQrwE=gkj@m=K;oAmMuxY;NbKo!BF3pLW@+|L8KmTpZeXE&i;j z(%YiEY8;B{Oj%aLgshFc=vrw@)H_qMaT1EB`nhZd3*!BFK!5b?h)=yMzXnsPwLU9b zm3z_lo4S3`t2*JZ{4NyK=*_7d+kaN$XG=PnsjG>DJvrI;s8ae`rgL{9Z;bKW*wZtn zQg$3;9&X)kd#|0u%4*=GMaEuPC-}!w`!T~>WO1ZjjVwpjBLyOD1*Alzt$`Flsvu>M zI!Ga;5>g7Og%pdl)sS+LwjNRtsmOn%BvKP8id03)B6X3%NM+31cg1#gy+2C(bGG+< G*8c@X3<b{s diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Marigot b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Marigot deleted file mode 100644 index 697cf5bcf7f151ffc1c1fc4247e4e9c7e3ff01a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 148 zcmWHE%1kq2zzZ0GvP?kCG1=UB4deg+$3hqw{{KIIfPuxwH-y14ID{dD1VjD<0ZxOs JfTo#n0RWR(9N_=} diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Martinique b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Martinique deleted file mode 100644 index 8df43dcf1c9f63d3ea9f056f062ea97e5c7c0b57..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 232 zcmWHE%1kq2zzbM_vLGzj03;?ZKH(zlo97^6BDR5%iJ9sD|6_X?7{DaU|NqAiFmV3= zfAs<*ua9pCgPR+Wa0~`wmk@>!5-j=;1ext3M?f^lLZH12AWK0s$rf_~U0}im01JaW A1poj5 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Matamoros b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Matamoros deleted file mode 100644 index 047968dfff4dba196d5c9695e79cf28395d9a0aa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1390 zcmc)J%}Z2K9Eb5UB`A^wfe<7L6}V`coH5Nz%W`Va98DcxQZp-c)L!P4Iyh!_AkkI1 z2uvs>MB9W|o56@AtTs_d5F#yvk|YA@1VuvP?L7An2wFtH%jL7U%lmu-HLcAa@yDw& zU)P&=!+7+4!?ucVVtd<D?GA>8r#()l`>MsBvM(|tHCtqQUdz3)Ng`|OXPvdQCieY$ zrL%v;sQu9yoin+ra-ZDP2L>0^!8=mtg`TNHeK+Lcl2Mi47?R%Ied>s}R36>btb9At zrElfBD2Pdv1@ld!aPg-+cK5a_nk$z6o`@=rrpc1JT6KJAvn<WYRb`#uWqDGH3RKL= zz^X%4W=zS-PsyS>`JJwQDa47jsID3NC~6mmbzR>JadNs_*Eil5r$*{@gMUVy9*D>@ zyT;VnV6ALS=vPg?T-mhTqJpU@GWe!YwZ=MR>x5IaEiKA(Lj~getfeo6cZ!RXA9ScP zLCC@9`clSMaXB=u+Y{f4j*<c0v9_$jSz|K1Fsr(@^vka4M=G+?BD+U!sVnn^vZuFG zU7d2u-ufzaZFr+}totXAWsT+uVObCEi5Saz{Lm3s<PV7aa`SovBJdYK-!ex4CImqQ z93dbva0G!w!4U=$2S*@CBpjjGnpil3L83vzLE=FILLx#!LSjOKLZU*#LgGRKLn1>$ zvo*1C1ZQia;|LFl4+#*75D5{95eX8B5(yKD6A9GTM2duJYhvXH*49MJ5iSxhN5DwL z93dkya|De<jf9QFjRcNFj)ZP&Vn>3vHPIvC+nV^10U#sb7y>c|jzJ)!;1~un4vv8! zBjFf|tr-h47+W(MWH`2FJjj5M5g|iD#)J$C85RDwVa1z;WtxRK{pl``E6wS5yIpQq GTKsS6)nhdP diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Mazatlan b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Mazatlan deleted file mode 100644 index e4a785743d75f939c3e4798ebe7c79d38e4cfd08..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1526 zcmd6mduUH#9EZPSF0IvGatV=GiPmn+W@hYSGxpoYew!J#-)4R@cC}d>w!LL3a(Smj z%}^pNZHZYf<uAE}keW#?$(EEgEko-#&+)(Vhw^!Q&vQEG-{*1XmUzSEkK1bh9dF+$ z7rO>3JBG^py1dz*TL~{c-Tq5G-J=HwpM0wF^t9X<6sgo<#my?bdYWFG>{UxPjOd63 zYt+*4UL84Mk&2r2O``h!)v}*&BzkzVS>E+RVmkfIiaTu*d;GIm+1ezlDxR6R=2jh_ z-f0qw8gydF39~veUnd3BnB>4XojlT_Qhev@l%8s}_QN>6t~*PmKAk77(~&Ceny;kS z%}^OfKFa!n2(zK|p=8EQH}2G{k~R0c$qqUq8|AIZnR;30^xZR?h7ar9`{&H&*QI*P zmAh)|%`}~N=&Z^=8LB-cS`{?9q%fsWZOaRhqJ@cSd+a3fPWG7M*<Yo2DBkQCeJv#~ z1I^BNw`AA#@uu{_D_zzyV9GDu)D=~aP36H;x+=F{?e^B|>gY$RCTX+YGqYXQhSW*z zkE5zCAXn;oD^&fL7}<M!z1sJDj_kisW*Ry~8V{tKrep8LXN+^k`uP5XV_9cnL@cY# zh_7X}pO=Z2bzF--?>_4H_f(f#T$yf3uy2NaU5RdS|AjP`J;Z^?0}%)!5kw@1woDMA z;BTprvr_X!E{I?d$snRZWP=C?kq#oBLt8$GfD8#CA~Ixz2+5EVA|^vlh@cQjA)-QL zg$N6g79y@gTV9C34sD4cB12?`2+fchA~r*Ah~Ny#A)+&6hX~J*9wI(Nen<cg?Fb+t zKw^Ld0f_<<1|$whAdpBPp)g{B1jC315)LCCNI(wlh#(;`VuA$4hzb%GBrZr`kjNmR zL1Kdh2Z;_69wa_UfDY{lAt5@nV}u0Bh!PSeBTh)5j7Z^s8>*jOZlqmokZVbBSa4{N MD=aiPA~@9V7s`x}c>n+a diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Mendoza b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Mendoza deleted file mode 100644 index f9e677f171b3900dfd978eb8ea2aa226557d2c5b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1076 zcmc)I&r8#B9LMpmy44a71A~4LA*7g#;KSTnP{~I;7||{^3Osd)A_$5O8T4ay=@blN z1cBnpYtW~_61DcJWh)^W%!r`FqUcsctYKDudOtsZK-8&y`Rwr>8{-SFXJ+{L(RlF3 zSD$>lO3vC#@^<T5PTfB@q#ta2VWu|c^wi=hHNEbFot~U9GfQ{%?Df~`;hPWk(b-m0 zoLR5!aLzm)8`DpAl~n0s#XjBCFms1PdTu4A%Ka%@uH8}3FX#1q`lgxxe8n!Lomw!T zY_%t876*>l`ksiYk2mbM@Cnt3M|I=lxLIl+uuJ8t`d%N=%hes`M=5E4&K^*|ZV%~| z(WG)$6MFT;J`?FYS=f@FG@a3Wp)2*(bbUEf=-!af-7iaK>+&(%WA>U@?Va9s<4{Mc z@yzTj#*8-YrvG4{9UNI>2H$2ovd+1t=9a&_!XYmI<50LI+$^8M&K1uGfpeuw5OS_; zgNSplDot(9y{|Pzxewa*r!&ETob4(hr&mrq$o#`H@{sQI=so#==U50?30VqR%PWf^ zt9fNPWIbd-WJP32WKCpIWL0EYWL;!oWM!``jjZjJ#gWyK<-M{#Qh-+~KuSPrK#K56 z6-XIK9bPE}sl+R#AhjUHAk`q{AoZXxh#RR$f)6MOsR=0xsR}8}D|I1-d8IO>G^949 hIHWqHJfuFPK%_#XM6c9{S$VYoQ)KIIX|u1l^*1v}?Na~% diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Menominee b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Menominee deleted file mode 100644 index 314613866de53e1457f6cbf2fb617be7e4955edf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2274 zcmd_qT};(=9LMn=X7P|bWKxI(r6ofSN5IgdNm0TW<Pjf^2tpQu9kGmW2}e<*pBqEF zFg7XEYA8i+t(Y3iuol_lMGrH?xtd8nEZ1zTU+G0EJE!0K*JW2-b<y|i|9|~=?mzFq z%Erg@)juxU{=>s{+K2BHZC~97JbK>;S7m=kg6?_cw0ylItWQk4A}8u%&2Y<Qb+YJJ zb2YJCUyBKv@Ibb@spuz(&iziJcV_C?q<1B@?+q1aUX+{9cIgQ}95V68T6DtET_*9Z zT`FmBv$^H@W;L<3(%jlusU}tXOmdk|-8MJX+@6)HQl`$4$uVOpb=+i0{Ub$BId@&s zhOX&5J~<=lhkw)=Js-=Rp+t4pwjP<f{C72N-ACr`f?;(}`93o}`8}06W1Gng59zG9 zdXqKMuV-8;G1-GJY0vO#$?4vxz5T^9v#na^c1@SOU`XX}h>=;PRqEcQm!u$bo|>Ki zjm(KoQ@$y`7~jRPntS~#Gw;i@>b}$OnE40Cbm50DnEN|N^aHPoDQY^VA8g+#4^_Ob z7c?|U@yvEzQoKY;F2AozbJm;E;k~LXzQUCCZ&Br=dFJ8QUe*gwEfW9MR=wy*u2j_4 z=*7Dy%98nodTGlQS(cWe1ItfIU@S^k77R$`&*`cv{iLb-LaFNT5wo)Qys8=5V`|$! zSC0&CHme#As7JeN&13#gb=~$>S)J3X>w`7Y5Z|HKloraG(X~35nIXY%%XMRPlr;8v z^ty`|<cZy7>dE5~vp$rqo;rBWG*!kc>HN$*UGSTFrs++yA$dqOS8O-U;ZYs(^-5^u zxZae~A)5vd>()Ql%I5Aaz2*CI+1l2kpB?Z>+o~1%xjhLoF3SFH81J}|@Bj7}iS(UO zDiS$*C~ABp^7eie<Gv@jcM@+k>F@s+`U7e~v3-`=XN7$h2ULmu=Azsi0{>!05qotT z%j%IiA(KL8g-i>X7cw!Yof$GUWNyghkl7*A<Cq^ZL8qM|GDWAIBgZ6>St8R!=7~%c znJLFqk-2hA7MU%_bdmXTOc<Fl$CQydb4=Q4XN^o7nKv?VWah}!k-2kB9+^GI^pW{< zBml_(M+%%a2S^f}HVa4^kUSuXKr(@(0?7rE3?v&I=|J+qkq{&!94SF^!jTlG%?d|a zki2jt2FVPP8YDMJa**sG=|S>?BnZh6k|L+g5l51oHcK37a@ss`BnrtCk}4!uNV1S@ zA?ZT$g(M8g7?Lul%^8w3r_CBi+MG6T9En3R$B{ZDcO1z>vd57=B!5T(kqja!L~@8E z(P^`Yq|s^fh$PZ!Gl`@U$t6cJk!*6L6Uiq>LXnJeq!h_1M^c?Ot4La%Hm^uxoi?*b pYLVO`$wjh@q!-CA{tpryXA3>smfGW=<<0lzdi;5L-aKz^++RkMdw>7{ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Merida b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Merida deleted file mode 100644 index ea852da33a81478433a389e2b4da03b425d9f764..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1422 zcmd7ROGs2<7>Ds!GcpT|LWwRQ5r|-;j+e~Jv{46hCT~-km6y`7Ny|?yvGVePA_!%< z2qFoh=tiNnNHSYUkc&uyLMovMiileD6-ZLnbe?G+v<P|+=lo!1`}{p+KCfN=cqP`q zbFFvLrQxZ{$ezi{rLMe!gxVIdH;1Z3XQ?C=eNf5KX_8`pq}I+`A*svXo78tdW!?9O zCT%)IuOGf|HVn<`jiY@g{p2gXX+W8bhB2MleL`){zn~q}4Js?HTW4n#s+@4IcCJoT z&Y3RB4T(^>&ue7Mo3ASGj#FF{ON{$WjBLFzZSq?eNWt-Erm!kn7uAoL;>`Kl;~FsA zqCV>FvF)ZrCUj}USylRaNbi_#Q)OfQdgo-h+I4MEcHhoW<-Mn*;`Az2>1&dzj&!pp z*CTt&qfB*7iqxbB8}H&GUAywFsr{0q_x%_*z9*4-|I4eU?$(U1AAg_@^iS!7m#?UX z#(P@z^s2_P7t-XdQ_X3kawx~G4lg?=Epa~6@~u-^!}Cn*RFxe0w8k90>yTrQ!%f@8 z3f(^V*>rSe>dwBWCMY;)&Odnk{_C?M*7v-G`28a{C6sT_!r#BR+#YchdnDU>9a$dn z{6!3Y>j;8$hyn=%iGw2$BodBLkXSf^L89RZC!iG%M?gqKNJvObNKi;rNLWZ*NMJ~0 zNN7lGNN`AWNO%FQ_&5R#Xhp~oA`&A<kVupqVIpyI1d2q8go?z91dBwAgp0(B1RT(c z7zr7P83`JRnj>r^ZjQi_$T>nsV&@1RiJl{TBz|N70j&`rLqNuW3<4PiG7MxK$Uu;h zAVWdM!Z8?RG#tZ0#=|k7fYyjOh7`~m6UU&CQE?0l85c4zWMuf?3@yxBU5d51Sa*^w Q!4@CuPKdW9+v3B10g}OV)Bpeg diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Metlakatla b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Metlakatla deleted file mode 100644 index 1e94be3d552ea0d6e29824469866c2a51a187be9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1423 zcmb``Pe>F|0LSs!b#+}`Ybwn@2YD1|n#pMR?-Y_`Vv^#zshMSIV*mV$Xr(C_<{=zC zgdMU6VbsAKI@uwMqEjg5A&NjMh%P1_Iuw!9`;K`k^wJFPeTLoZ_ZO&cI-RNg^?21U z9G+5j_)hFo*UO;<xv=wF%R*g}zA{}X?0c!YHkKk>*ZjJ>D^i5C?lL`f$uhJo!VJsz zNw2YFdav)7K7G#gO+FD3UoA88{gm{-oz<hBj>t`qru5DC9|-;Ch`wdW6kEI7^=(aU zBD$(Vk0}a>?RhzRY)ZC>+fi=D`{G1`JIf4aeU!mZ2aU=^TU5SCHL6xVi0TQyadh#y zs3|xgYX+8$V>1(?wtn6?K0YW;lq^|wgLmY~J#*Hn#;dYE%CZ^?8)d_nQL8bzNH)%P zSWVvDvS~7Co%tLk&)#S^&dsNa^PLsO1<Nm*gE>aa@Um#ljyKwx=S6$WPov}TL(yT! zTAjIbvUBl=)fH#Su9<gM_xDkGas07$=}m{c+<V*VnGVX{+J5WGSgv%rLtLJ9-_S5# z*D4#{n)W(L(`<XVPxILJEz=e5+<xcQZM(lki{@Wf{GpP7R$8vk5p_z{DF|r!#p;Lr zV)dmS7uPC*e-{z1{^szMsl#`ot)6|)e!aq;K_dYv1gXSPm4Z$!d{7LJss<<rsRt<t zsR$_vsR=2{QB{SM<*4dH3PUPGN<(TxibJYH%0ucy3PdVIN<?ZzibSeJ%0%i!3Pmb) zRHY)dI;vukYLRl0dXa)1RmDijNX<ymNYzN$NZm-`NaaZBj;eN~ct=$|Qof_AA6Wph z0%Qru8jwXGt3Z~4tOHpHvJzw|j%qE)VjR_KkmWe4^&ksER)j1GSrf7-WL5ZQSsr)j tx^I}5*S*Sy_u8}u?*6BNtu4$kg6-w8y|j|O>6z(9T1iGmdPcet@f%E;ZIl22 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Mexico_City b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Mexico_City deleted file mode 100644 index e7fb6f2953d123efbc2550f450decd794b017d4f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1584 zcmd6m*-Mo{07pkNDie&#9$G*m5W&p7va(E5OmA-2B`dv}Ub9R`EwQp3Pz0e&AEHHs zDB38p9x}}yBv3FC!-&dAE)*g4&=g40_BH4G1A?H3e#6Z9;CnsCSy17Q5Pw{W`8(U( z#aDW#WY3o>Pp>=Ibw6R;)#n%E>igNMhbHg1hR;T2jO2XwjC^>LG3Gt&8M~jGF>yY? z^SZwIX?S_Ph^U(@Ba`z*RMrO>9TY2KBA&>#bC!#B%ck_Y_rJvY?~irtw2#`*`$%u> z`JpxqwClLjlWKF9)LW_tReZ}Sxi$TgN+_+CiECQaw!}=C<nLC=t0HCcOtVPw36Lo- z%f$A#Uu9}vvPc_Uq#fsi#g1FkI=x}O$T;~zXBG#ktjd0!9Y0Sw)4Fs{;764ka$M($ zQI#KXLFRjU)XwQfSuohCc0DhYyKmeUd+u$Kg>4<8=*&v#s;CvkC*pKTic{<@4AiB; zF`_KaTe}x#sqz)?borMkweRP!t{7jU_P@EV58RzmmBT~wVCRIYx_V7k*F03RwN2I( zyb`tU1F|l5KpaYP$iqv!Mg5uzUH`2~H2A0LhKXWv<kM<>^g)6+Hs-GzFBhrfw?FF> z&GD+K{h9Xi=FBq3$A0<xx5u(B`w3xL-5tWmvTj}!b1kd?j+dYPE=Y4Yg(KT361a)x z<~fD)FFdl$a0%iQ#3_hZ5Vvd^zaWl5JcGDq)A$B)&ZhAW;vU35?8ZTchY%MTK0=&i zcnNWn;ipaGD8o~Ts}Nry&O*F}xC`+Y;xNQxh|3V4Ax=ZQhPVy!+oo}x;kixYI>UE} z^9=7H?lb&{G{EQp(gLIhNE47QAZ<YUfHVT>#HMKl(hH;+NH>sn82vyRVsr#)iP00J zDMnY2witau8iRCZ)3gTZ4bmK>J4kzw{vZuPI)t<c=@HT-qf1Dej6NZaGCH+sT4nTV t(=^NI7Sb-GUr57{jv+0>|Fvgd6L*Y>JH!zc8Xg)J;s_55jSda-{SB~`;=}*| diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Miquelon b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Miquelon deleted file mode 100644 index b924b7100438cfacf25c56c494fd1abf3f262100..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1666 zcmd7S-Afcv0EY3=#6pS!2_iwPOtIY6-Obv{wqs>dy6s6<GgJFeldaUgG*eTGAc`m| zvZRoRJ|qe+Dk}mxP#6@^Au)qMq9h{dA|eP3r}NAo5OfpGF!Q^Zo4I(O6E2Hv_ga6v zBIaw1d8VD|^Y_HpSE;1NQ9bMM0WrIHK+oB6P9<mc=(%efRm$`eI(6O#l{$V?ro}B* zX(Pwwye|oAe*aFHKIj*&?x1wvohdTfGi2u3U&2$Huf2OmgfGvf7ZfUyl{!@~^j;N< zV!vsBLcj8V8q|x&uBasg_w~|uM^tw2Yq{)kwF;cRCzoGZtwcko%sE;mR)m`6%IaLP zDx*y1u1XcT-%sj1*GiQ)Sg+SinXA^^m3r;hi7Nkcoh*2hEP`zzxvno(gvvcqp8qV? zXUEIJ#^<6a;fD+t-xlGqVOf%ON|cO#*QJTKRO!<py>a}cD!cYTZyKpr<wv`8MZZ*) z)vbDSw^wZmUX)vpg~T>ji>#{ki0UcjvL-KH)O-!d+LRxn_GOZc#14zdooKn^(<8C7 zGg0q)HKgjAEM4FGKs6M9(7R7}sXbXw_1=b7wQu?jy+2f;_K!c2P5u_qG;&=w&nOqo z{m10Np8?U*9g(eXlSEs4zC83WTC`WXWXFY3(P7(mRP=;@a!1?ti&D$7?Pto0vF#yk zO|tEe@1rIc1jANNQP^^2`po0C!hbO^^Zzy@V~z|B85=S<WOT^zknte{L`H}V(b0?% z8Kk2bB{EE8oX9|tks?Dy#)=FU87(qgWW30Lkr5+9M#hW`+R=;}88$L*WZ=lik)b1F zM+T3K9vMC|ek1@S0we@S69W>2qlp3u!_mZn1cF3@go4C^1cO9_goDI`1cXF{gyd*q zLV|KMQ6XVDnz)d_kjRkGkl2vmkm!)`kob@QkqD6xkr<I69Zi%-n2sh+Bv3~aDH19Y zD-tXcEfOvgFA^{kF%mKoGZM6;i5dyp(Zr1e?r0)MLPugpf=8l9!bjpq4gkmh@eqj1 bHpfB0XWrgGdeG<gx--**9*^7O&W!sFD*CZb diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Moncton b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Moncton deleted file mode 100644 index 9df8d0f2ec9fc8f1974d83cdd8155c79340007ed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3154 zcmeIzZ%ma{0LSr*s3Q_36+<KytxyA0ki>s+EgYc`M+FoUJe9`4TaW^3-qe;(c+uR< zKlx`kt4XdkG|ZtSVgj1Zc?2cR#G?qBfr6TuT)Ca^)648d?|RX>JJ09Yv-|q@O`4PW zcDU_tr@Q&W<(xK`cmGx9v8sK)C@NbccO1MV$|pvt@_j??hXMoCp$*;a6&)^hc=2_6 z<;4bdWaba{@5?LI(TK0?RogyO)qOs;*W^4<$9zuNkH6Zkj<=TBPxMPyC+bgDo-DX3 zYlq&;sg<p&F0WpnwVzh!lFM}c;Jxa{$gTRk?Gtsu&#5oyJoQuO7J0F9mioD2xxBPH zS2R?l$;*W)LKj8LE16N^>WU!Q7#AR}rF+VzVJ^`eJ4j#e?XPYGd+1;KT~jx^H|m@B zYt*mJ)w-qrOVwIatZyBz7Pm{PWZRBn(Y|h%ytA@U+|4eK_vS4Wza?hL`_T#F_mT1P z!LUsAN3SsX&}*7{_+YB;xDl#c=R@?P<Goa8Sx@aQZdbO=ZQ5gPo$9irR(s~OiLUat z>?Uf3*Wgn5gzqNdZQCfl+m?za^%B|R!UpA2nJRl8$XC5~=V{+9v(;0Dvvlue<5i!` zak_76pz@0wp!-F2s;7rN(*8pRi2h!eb%4hs5zy|E1Fl>afoB@zGe?eyfqN_Epq-zK z!FhLd(1&ZpkmR#^Xx2{kY~+6Z+|-ZM^M0S|;1LT{aObyjxOc1?-mqDYxH(+CP?6>g zsT<)4EsA!AmG*FqToL3Pwf>f4bjBoC_#)+qh#lk_GvgaaWUz<p#qbS|vE3V8Q3Lk0 zL^W5t#&xW38DCTEns70<WnxK{b5eOq%S-EaIit5lwb-)@oRe24J6=xAa=tQutRrS* zymLxSf5()&TXk&cbQN3Y)Nwu$Dy}qLPi^&6)3z^{@%7;%!I>ss+uv6t&W)C0<9#uG zVvwAXcV5g4^pr`-2SrjxlT3-+E>fC2^z4CUYIaqlPVL;P=6q4DUvF@#xvPtHT1C1_ zpI@lw71@<c*d^asn<m~2Es$?zM2q=8S#m*akXX<fFEfHYMaHQxnc2NbWPa@{vzm{I zg_}aO<8-5XC%>nDx1?HSC%5UGb;atv$XdN9yHG9m+oy9A7pmOOGcrG_K;$=+%BB8U zVrj)jx$Hr_c)w_gTz)=GI9H^~56XPSiu4I`<>ouW!?Vj{eqFmg=Hui3_+R_xb{~zg z+1%~}du(0Z?sLk+%k4f^Y3pIV`&!Sw@d-(`DKnF7lVi-qS>}o)Ga}}A{Pj%w7xUvb zCw*Y+cgPGOQ-sVBGD((ZmXK+(H1mW^6f#rDR3USPOcpX*$aEp|g-jSSW5|?QnmI!z z&C<*oGHuAbS(=GMW)7J;WbTm3LuL<|K4ktZ%>*Jdh)f|ehsY!%vxrP1GLOhaA~T6h zB{G-DWFoVPOeZp*$b=#@YH6kvnNws^ky%Bi6`5CLVv(6erWTo7WO9+&MWz>-Uu1%j z8Ahhq(#$b3$;d1t(~Q<U^TI@P%uEAQjm$MN*~n}o(~ZnGGU3RKTbe0H<{X)HWY&>s zN9G-wcx2|0sYm7>nS5mSk?BX~A4vd`0VD;MCI?6okSri+K=Obj0?7oD3M3auGLUQ_ z=|J*<B*fBW1WAdd$qAAaBr8Z-kh~y?K{A7+2FVSQ93(qPdXW4e2|_Z2q{!0b2uTu> zB_vHqo{&T#nL<*9<O)d^k}V`%NWPGSS(=O?DYG;=Ly~4`vWBD$$s3Y5By&jWklZ23 zL$ZgY56K^rKueQBB!!kHhe#4FO%{<fB6&m-iDVK<C6Y@dnMgK~bRzjg5{hILNvWmD zDUwu6lT{?GmL{)AVv)=usYP;&Bp1mpl3pagNP>|JBPq5tIYyFfX|jx@+0x`0Ni>pa qB-Kc+kz^y;#{bj(kLmU{O&??09+D6d79KV#Bw_UEu+d?oy#EAS!oC#% diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Monterrey b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Monterrey deleted file mode 100644 index a8928c8dc94aaebfaf9cdeb93011d41b482a4cc6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1390 zcmc)J$xBsX7{~EP6EX{g!WIo67KmWi+04o`&5P;H)N7iRL+Q1vmakf3<?w<M2xYkl zA_*F3qR?6-nFSK$B9fqpN+^ONq87bIk~E#p_xu4ti|9EVzKgRwpP#qP?~9i|UWxs6 zmi^AVFg#fqQ9LEf>h7Aj+E$5g304X2Qb{cQppqg}B{}|~S~+`(q%3}KQr`WNRo@?& z)af9-dib7MGxS5R9qlt|$6o1m1InZ~j_Hh^qiTKrIh|SEsIp>u^oFbgl^yES?&S%} zJ<}~YL18NAd5vs*^Ht^Ea!cOC0^>OuC7Z5IoBX!9viZm}Q&1JD3mZmEQN|qY%^NVq z;UD#u=nhjN6S_3)lq!8aq_<ADtFp0vz3pka+J0qFcHB%?<-NzH;zWe1^fyaYXPViW z<CR_I;ift&S!&V(jc<OTu3h@p)P7FXyMK-w|Ko+a?&W1ue`7{BjNey#`X}|?i<eYm z(;cl2_o}9{7t-vjS1qZdvM<}C_AfdutucPn`mIaaLUT>qWR)EFw89*`ohgSNg_`#B z6}n?^%5-*T=&rseCLr*iJeGC#i-=`iJtIMuHF7;5IM3si%p&{E@{0E_e!gWN0H6W_ z4hR$s93UttIABn4Z~&no;eg`Q#=-%Hf`$Tzf`<Z#f`|f%f{6l(f{Fr*f{Ox-f{X&q zsf~>ToKqVe2RsTs4uBMd91tlOIY3fSQeaYWQh-vBQlL_>QouU3(Nf@2@KOL%5OYAL zVCDc#LCpc1f|~<41vv+F3U&&3r#5;Dd<uTb04O7%41qER${;ACpbUdD4vv9PM#3=^ z%2+rC<J2Av$8en5<KY+(Wkei9qKt_$D9Whle;Zbay|83^VbPvMSDY(0+7lP+N^-@9 F{076ZW}E;3 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Montevideo b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Montevideo deleted file mode 100644 index 2f357bcf50da794541a518510777bd5c470b9b77..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1510 zcmdVZSx8h-0Eh8Ar8!#W1`%00R_2sMCoLGlYRt@aY_fsM3VTv~tSAhsc?xNHh-iBd zyw!_saKMCt7N;zi!nkBfWl*%BL>4V5w4Kg(e2u8b?&Y4}W#(y^?;omZsLQkdcx}+% zCg^A0ktJ{P&mL=PYgL2(^B<Gsg_oOr7atUfOPxm|m)myBt6$n9*E-te^@pb-H(E}~ zjw^d2(eNI5^Z4e-t=i49b6=zH_R8h*&ej@VS7xT{o?h+iaTkc*SsA|G;S6#2aEq@m zqf7LisPn#?d_cbYwA4FNTrNir40y)UcF3`>>7MUDSBM{@DPHU3E@3^c_QY&BBxAak z*>NY+W!&?pr`=sG-uRj-5kI)olQ<()B!-*psY79rRNG)DKN%1yD=X}jg9~Na;<I*E zXGqM>Y4prF^IFbLK5l21*URjo0#8m>lE`s3+Vc}~<$Sr!Uhtw{<Q|=A7gmmnRcjVS zi%QQqtJ9jJ#hDes;?Mh|CGL8sq<>qqbhykZYg-j9@5yy4nrr=)t%*)xZ=t`c>4UR& z%N&1j`;_3if>?ib@O^N7`j9^)oM7l%uRpAma!rVt_}hC@?4;N@eUG2+aroeG?pUSn z1uV;)F-mnuEw@tld#ou+J#t*BoR&VHJ$6k~>eUO^Or_oqyFBCXm4T2I(9c4#L_hiY zf>S?v<}FXZE!J<Le+WqbPDMmWNJvabP)JlrSV&w*U`S+0Xh>{Ga7c7Wcu0ImfJlT$ zh)9e`kVuqBm`I#P9Vikh5~@+hiUe!a(IVj*b-YNxMjbH{GMbp#A3<~JsDZGJI&LIz zqmCR29f{qjgGZt_>hO{HkpUnhK!#w{V?YLhi~<=3G7e-Q$ViNOD9BihdN9anjCwf8 zc#r`hBSMCRj0qVOGAg4U7BViQ9vCt*WN66Pkij9NLxzWp4;dgbLS%@@7?D9DqcrMa TVp#u2|Lr&v3iM=G<R|<B28k=W diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Montreal b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Montreal deleted file mode 100644 index 6752c5b05285678b86aea170f0921fc5f5e57738..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3494 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 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Montserrat b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Montserrat deleted file mode 100644 index 697cf5bcf7f151ffc1c1fc4247e4e9c7e3ff01a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 148 zcmWHE%1kq2zzZ0GvP?kCG1=UB4deg+$3hqw{{KIIfPuxwH-y14ID{dD1VjD<0ZxOs JfTo#n0RWR(9N_=} diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Nassau b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Nassau deleted file mode 100644 index d807a61d4e9b725648fbbfb1bd6c93046d9785aa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2388 zcmdtie@xV60LSqIQR#qyk|ISis0ie@B8XR_!Y<Sk(!&5v9}T=A6i;gBQHHrNCjYob z1GUChT3K5oGfP)vV9wlHDYBaV7(TYeT8n%PD}uc1c|ZNxU;Wp5ZqN7i?Ee3}y|oQn z@*V#;Q_VkI&LMMo&*&^%+VSc2tCbff-2H>8^D8f=UY8dGhx&i52*}?SuM@xL)XMSu zcB(&OU2-C_Moo-Y>&YJ$sXs3j>l^20tKi8b9eN|A9Nj@3)_z5W?^Jq<42lSGLr$$! zVp_>%IX(BZh@3MZZ;Cr2oQ}iNsh<~7YOjp`>Qxof?~^y5YE!XqKBwajZc*|3>h&!x z52{-m+<Hb$hDs<;*S9T<R=1}|>BN+DaYy8+o*5n`X8z)ov#yMaq`{x$?1A$l`Pk?3 z&R33!Iev$}Yfq<0srpW*ZtYcf7o5@eEPp}WoAA0$%h;~cf*;FtXO&7HeobclSg7Xq zwad&QugL0YklDu<h@93HGPg5P<oSF$f7^tZ=PuXtSAQ!C(&p*~`F)~rdW<fb^|dM* zxvCdVex!=e4(dhU^e9*F&+`5cpH&a+zaSUCv{{ujzblut?G{TbUX;t~Hi^<4zbq?V zCd$T+YIoK~<sRzL<uOZC`SB*bd^A<9czK^(`DKal>}r&&-cJz~>pilvD?&Wv%8{#| z91&}h;-$ChobXPL$+ZP<iM8Ly>gwdPs`|_|T@yU2YL5)*b;BKMecK8BNMDoMP}i+D z_N-FE^Pb$)-Y7O_b;(D49#Iz)koE2yQ9oKMeQEK+_nAvJOdAsoZzs#GBVUNdu43JE z{+fEspQIn}9a7CzK`r;6P)`&ny{)-hZBIC@cT}{f9l^`eU(_Z1!vivq7!ZNJ!?I<( zRy@_SS3Z5oC3dy?<TEFeMeBxgx%+@agolNPO$m?q5B@@-5Bv^CDD+8xSVSmv>K#X< zeMj4G+)9tvQTDL8Ys{@Qx75pi!v6kv|HaZm=CC$oamebB<ss{{ngt>&M3#uG5m_X% zN@ST<vrc58$V!o=qFpNw7RxcK1(u7f7g;c}Vr0q4nvq2#t45ZMtlMf9j;tJ6I<j_T z@yP0t<s<7y3V>7qDFIRgqzFhAkTM{3Knh_sl|V{?)B-66QVpaWNIj5(AQeGMg46^l z3Q`rMELKw&q%c-f8Kg8wZII$1)j`UG)CVaLQX!;7NR5ypAyq=kgwzQsl+{!UDHT#H zq*zF`ka8jQLJEdd3@I5>Go)xp)sV7TP2G^fSxx1T(pgRIkm4cLL&}HL4=Es0L8OF8 z4Ur-uRYb~YHFZP^X*HEZN@+E<M2d-26DcQBPo$toMUj#sHARYwR23;JQdgv~R#RD| zv{qAFq_|d7U8KB7eUSnq6-G*o)EFr;Qe~vfNS%>FTTP{rQd>=}kz!j-wUKfo^+pPg kR2(TeQgi(O7Tsw=Utl7i>6w?EpPifO$;->m%g%NF1yhyakpKVy diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/New_York b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/New_York deleted file mode 100644 index 2f75480e069b60b6c58a9137c7eebd4796f74226..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3536 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 EZ-WKA#Q*>R diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Nipigon b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Nipigon deleted file mode 100644 index f6a856e693420d6d989c45acff2c48b60db69186..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2122 zcmdtie@xVM9LMo5L`4TAloTnELB$T?_+h7LRG6^q)DzOfluSPwcta@Oq1~Vib)lsH zxJJWT?OJKg+8mkLv>KCg=GMxT)%rF1)E0kK*vIG(7aP~-`T4iM`m3$)?elqjcmLc! z_j*Q~+csBu|9Gyn-*9;P?csgqPJ1Oz49F|*|EkVj4mW=KtdR>vf64_lrPJq($TiuA zl+QaTKC?$<=-ra}&1*XAR7|ct*{5f``HabaakI|Z+iI@sxnE!37BVx}mgwBD-`ub; zQ{U*%FnNW3byNC;nU$KMX8qxl**{LG{PVxb%_HYj!O_p<mRFCeIdRY2x@$lcHvMFZ zwhZapf~U>xOP|ws<i25wOSbCb>5s+lYtsI)*QMl_1$ypqzm$$fRav4<0>|d7^4?`q zF_5P!V=+_J^_Q9#3Y$Auey@VXbIts!VYT4uEK@!ETU|Z=yIDB(p<Z<6yt(VUgsvI7 zD0hFbQ{S`y3%U2DO}e)89a-GBL*3W#yew(isOrk&QeU@3)lVKap|TA+G`i1(vli>{ zu@19zqDU`$d9N)0s#Zm|x66w63RT0ph%^qSsRwGxW#tp&YE^!YM4Qg4=+vaF4!)&U z|2)I2DLA9ooW5k%P9N6IhepjqWBc^FzT@WM;SRmN<$&3cSfN$qUD?>*t~Qko$|JFe zYRT%B)=;@>ooJR=agK_8RwHd!O{%sd1+r!QOVvKO$aI{$q#upvo5zMmb!XGGk^RT@ z<3Vk@IuGcrxgVKr4Ly3>^bZoR9#rwM5$VqBR^7t~rRQ?9dNQ$Fp8C2*ZSRfA(<cg4 z@A|Opc)?StDXA$}q;dbJpJeh#t>-0^pPWibOD0dg?WMc-Om}B5k3_xtI(t^x^PoMA zQTvznycBmu|HTxN_UXE~s}`9AG7DrH$UKmVIPFaMA*O=N1(}S~&IXwdG9P3@$c&IF zA#*||h0F?>7BVknV#v&psUdSiCWp+<X{U$G51Ak`Lu87`9Fa*PvqYwe%oCX?GE-!# z$XuOvvdC<mcDl%XkqIL+My8C+8JRRPYh>EUypf3`Ge@S5%pI9LGJB_;J~DqK0Z0ar z6d*Z3l7M6ZNduAxBoRm^kW?VKaN1-b*>Ku)Ao+0GgdiC~Qi9|JNeYq`BrQl@ki;OF zK~jU{#%Ys-WXEaKgXG6)6NF?4NfDAGBuPk?kTfBALK1~!3P}}`D<oM+wwyLyNWPpl zVMxZDHf2c8kfb45L(+!i4M`l5IV5#R?vUgm*>l?TA^CIK1R@!9+7u!=M3RVP5lJJG gM<kK>Kgp!e)-z};S{j)bs0vh+Mk*@<m4OQ1-!F??7ytkO diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Nome b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Nome deleted file mode 100644 index 10998df3bbe67aa8a02602301d10ec2b2c33006b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2367 zcmciCeN2^A0LSqQ0v8C15)_f>@eShD0|-J<UI-&Z<Uy`CAyO!aVaZD{hA*I)j@&BE zHiy&bILB67wlm#KW6@35+OpgYw~}0xZq0PbTCWz#?R-zR{;2t1o@dYVIlH_6{=V*- z=BKh8|2kp%7hcY8{c=y-sz0Z97W+o${nR#EZ@YdUU8Saux7+^L-7d#Kl^yVWt}C!R z$DY={(i>D?=?ku0<P9mz_Bk_Wc%3h<_k~4W^M)P1Y=?jUh4;3v$9xfEzq%s5!@k>3 zjJfW3<D4C}Z`gI`&Ufs)HoWSZ-h9B0uHNE`Debjq<k!1qCfC`qb9=nA!iwy;z_s4E z)aa<VABxoMiwk7@=zMkeNvBLW5~A)ocv)Iq`C?ArX*t(3Tg+Sctu;UAx>&I6BP%iH zE0L7)rj;}`sglEAvXaNYR4G^5tkjYBRNC1WWcuJim2tF1F6@0yiC1iy*(60)N0!Vk z*(MfMMa!I|29cZfi(Kq{Smeb|xAHFCEAl6Qw(k2dT-<;DbE`llst1NoSP$+FRZI5o zw_L4PRN?lwWl_b)>Y;{xvUuTJYH9H%x%9^iq9lF5Dmi;fltyl}N{<eSWmjvhvIFm{ z<)3xS^38|TieojhqIQR}_ZG;?f+n@HD?wJpmnyf%A>DtZDo@Tu>G|dnu{yzTt^OcI zR8L*7YK9`jW8<f++U*nK@sS~GO@mLY9qhO2%D+?f{fFce>1WiFO*>>mq*9F~O|tRo z9@UgoDw{s(RL#y**?ice)?JE}Pw(vz&-hZT^<Aq(i;A#XJ&Q%#t_iC>cb0gz)n|3Y zOp4BmBUYz>rs~Q&BfG|bQ{Ayjc8{D_8?Nn<8wcN2o6dF0&AqRwp5q?byQWWV8OW0X zfztwlf^YVOggS5G<8T~naX9?`M%xkO_jl9<gqm-J`6bHSqy7HAHb<=AziVqiyt&U= zUha0RsM7DF`nBDTB7H9^b~~!Ig=P9uSf+3K1n}Yfb#edq(!%v0csVcYmwTdLpCu=+ ze~LZ*6{E=Vko6h$0+AJ>St1wK$kB@gR*5VVStqhkWTnVbk+mB2Vv*Gv^>UH*A`3=V zj4T;hGqPx8)yT4ubt4N$R*ozkSv#_LWcA4Mk@XvO0gSo=NC}V{AVol`fRq8L15ya2 z5=beKS|G(hs)3ZlsOy0g#HcHRlmw{>QWT^rNLi4&Aca9HgOmoT4N@GWI!Jkt`XB`| z>IxwxLTZE*38@lNCZtYCp^!=;r9x_j6bq>qQZA#e7g8{zt{74>qplfJG^A=s*^s&+ zg+nTbln$vKQaq%3NcoJqen<h0x`Idvjk<<N5s@k)Wkl+T6cVW<Qc9$jNHLLWBIQKt zi4@eRD~goVsB4N8)u^kAlohEfQdp$2NNJJUBE?0ji<B3sFH&Hmt}s$!qpmShWTUP! zQf8#iNTHERBc(=ajW>!N6c`+Gv&R`0dJCVwlie`!KZg6Ca^JXxlk|Mzo>rcnk(D9R M$}=-FGBZT@pJb_W#sB~S diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Noronha b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Noronha deleted file mode 100644 index f140726f2a6945357b325f0bb452dce7557bbff7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 716 zcmb8sJugF10Eh8=FG5N<s{x0mSR~X?O~n^LLehw^2@+FBwlXuEiGksa;tOaykw~yf zut?v$EYzThm!>7hdF}`Ba&Jz4!x`?)^N-K1EQg&RpMHB=XHU!a!O~)?Eq0Om3afOv zS7!3d;$}q4o6@t)wqNROdR*jcjWWM`Aqu%IS&WCo>rPp}HB5>3qZ#?pDpX~<Q&vt7 zMKy4utNTx?R;tL)&4lVWUzeS0=c-HhX*qnXx;N%!Pjf~EXFVOfTM(hhgAQG#MdUrD zM^dXITDX?cM_0wp%6c^6sH8E*bN}>u#@y~XjxpsIx89ihqSG`n8FvN-hwKSE@qZMt zA2n1#%J|wkNFk&WQp(rXLW=p?YDhVx9#Rmgh?GQXB1Ms^NLgQ77b)y(D<h?m+U!kn zq&iX_sgEpxtbi=xYu7*)@wKZU%OL9@3;EiWkfo5dFlqngPkXuEFN+06?QUb?z&FdM B9xVU> diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/North_Dakota/Beulah b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/North_Dakota/Beulah deleted file mode 100644 index 246345dde7cada7b0de81cc23fabc66b60d51e79..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2380 zcmd_qZ%oxy9LMo<5xsH)JDC^)LTO1LAfOnK6a_?(1mP7>2%|v6{_yh;B!+lOg7Khv zmWxp)L7~-}33GEeHqy-2R_4Oyv^Gjx|19dR++u;;&ig#=QLSfv?|%37yZ8C$?Ok8L zF-83C+~yx1uFE{UM=JBxb0|Z<Htbft?UB0gl^@l|oxyr^@l|KEI!ydI(I_W>C>K)~ z%H*|=GQ{*yy7a#lDMWXKbahONfTyp?8C$|tVD$n$vv^9)%9_;fq%q}wAyo&-6DsKN zp!E1&SJ!>rr-LuPCqho_(Q}UXiR<6)mGb31;)c%W<lN?3abtaroVPAdgy!ET=cmVt zn__R5VT*Frf*_9!4~S9Wzb(-bmxEN~=xn|4<WDMU@QRM^JELxHS}1RM_J~@v)-M-t z{zTlGdP&|^@UB=AdP>H`X%RF1m5%jn6|rL{b=(!NSUU2Cjz8z9gr4Vh;?WYdthG)j z?OUOe>)K?>w)tv#-bT5iWJ0CJ+%H$Ae4*}e$H}yaKSbL1!7_dFqR9C07kTHG!(!Ed zM`sQn5O?kUS>L^Xx5#SvRNvFKU)@_YptEasshnjm>fD?SD);x(GB2S;<ehs{=7&^? z{G*++U_47a@ajRm`h2A-Y-v^x9!qkHDl1fR*IehJRhg=!@v5^XGFo}po_D-cE>)U3 z<dl9JCCZ~d_m!U(V%_vH-}?T`qGGJuSK0P~cz9%|ud3#d*w9nyd!+DvRo&6-Jett2 z9;>TxYC_soZC<8RJHAQP#Y8)GX9`rk+vU_Bj#rz%`^I^^D_=Zu*6(|=X{mVX$R%Gx zX^3$4p7L!;{Z(vjIOy9J`kB~X)ZyDcJ+7M4`kkh+vua0JyR&0tP&H3%a(4FYQ_ox| za9Ua$)vlp<r?sj~?e3oA1h~v+Mxce)|M)X&=D+&*{k<;<;rGAO>k9Py4`?ylz6aZH z>GvNWaLwaggsm?0iozW8tT9iSd5XOv+x*Tpzd4uv2Jb&uo8MejVDJF4I%Ijs`j7=8 zD@2xPHETo`iL4S?CbCYn3+08Ca%QQ(S~(VrtQJ`=vR-7t$cn9I$;g_mX3@y1k!2(6 z=2$qga*m}VYv))zvU-l?BkSiV08#;t5+F4|ihxwXYRZ7r0VxDh38WNAEs$a$)j-OD z)PtiSNJThGg4D!nih@+dYRZDtg`+S?WsuS!wLyx5R0k;!QXiy1NQICRAvHpZgjC6D z%7oO3qfkhtI7)@oilbOawK&R!)C(yXQZb}tNX@LKXh_wprff*vtfp{C<v2=*)D9^g zQaz-6Nd1rkA{9hRh}6((iilLvYRbq_N2@6$M<tO`a?}zjCPy`qa&puYDJW7=q@+kq zk)k41wVJXbb+wwpB9*n8(jv7*ipx=5q`VyUMGDMOVWh+yHAafeQDv(sGg4=(DKt`P ut0^^7YoypnwUKfo^+pPg|F4RBOxRbNz{eLZPfSTniZ4t~PE1Zr^85t^>~W3& diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/North_Dakota/Center b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/North_Dakota/Center deleted file mode 100644 index 1fa0703778034551487b7b55d80d41ad220f2102..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2380 zcmd_qUrd#C9LMqBLG%EDJ((235lRa}0Rh8+q%0r?c?9*yA0Y~Z5X<=a2NX5>l?>*E z`D`x2{t!5FwK8OGhI1p#YOQoGY|hq3YRego^{l*bf#>P>{@r%vMOS^#p7VOnx&OQa z>ziK46#qJ}{)dO_)(`JKrN4TQ<l66_@~Xa0pWXlVZ|b{!k@nca8*;2JM*MxV#hSWa zDW)$~Shv2(6~W;g%l*(NL{FUM=?aRF9k;9*TVhpc-8_3{*|eIqV#@ZWk1Ox~EIZs9 zRpCd6tO)0@y5n-c9r@$uB5HK6J^N(8xbvev%R01I+_mp@Yff8(xVx#|np;&QqKluh z?#W3O_a;AN#VjaP^TH#n*pMU@`)8sZcQsu3#=`9Rr+-)RLlbsF|2cJE>wN3}*9O&s zb*{B=(^>IA))ni)l21iq^cgE@ku8#fKikO>TSfBtX?xK`Kr9}4Q>9$kAX9sHsI=n+ za!GrYN<Ww=Ga6e(=C&}ow5U=%yk<gXCFP1`nP=rAUZ2R0yY6IP3yPenZ=Kw)FN;Ti z`ovj2IIZ$dz2Q7|U|c=^j&xQukE$m+_RA+r53Bt8W?8VLLlqXRmW6+PCW=xwJ4F`` ziQ=eIr}+48Q8Jm~JpJxlYURaM(!ZxotvZn|OKYlCS@#^ddU>8&({e+u^(Cmlx{ER} z?NQ}f!?OI>cu^VugH!pH5LLkw&ia9?qI$f?sp<GqJTtP(sjWXEp6#u1p7Vd9>blzG zhSUM|d}Fn&kLpwnMR~Gea-(WYN|24`N>r2ABb$z<s7=>?kuP=^i<i#3&gRy|;^o0B zPIGybkO$5<TeAKTTbn;{wncw0wwHD}+k=y;HG4p|j-OXMV>;!|ks;M~bEDkVdr<AZ zR3i7Zx2RW!Q)GK>g?hDTwhZy;&x}w5ueb4;HS<6FxNd)#5U%@ipC{CH-?K%Sd5<*T zmg}B8=9$a8h*{|m2!DZo*6OE1KV<=tuYc$3-<-#ML*O>n=IW~rjXZ{|4p|<uK4gK& z3Xvrm^%{{yBCAA}iL4XNLV01OoL(xhR*uCYt3{TJtQT1@vSOoNGO}i)UNo|5WZB5N zITntroMY+8+Bp`Fte#`}$oe@7fK-5^1V{~#A|O>T>M|g8Knj6W0x1Pj3#1rGHIQ;3 z_24K7QW1`lAT=@Sq99c<>arkp;V2AJ8Kg8wZII$1)j`U`Q6Hp092G)J#8D%pNE}r% z>N0WE2`LmurI1n~wL*%8R0}B=QZJ-nNX3wnAvH7VqH$EssLRGtH=`~bN9B;xA+<w_ zhg1(KA5uT0fJg<A5+XG;>LMalH0m;P)X}I5$x%t9lpM80ipfz;q?{b}L<)*j6e%fE zQ>3U!RgJo=NL`J(ut;T%y0l1bk>YYx7b!1CeUSolR2V5SM~#spb5z-=%Z$|7s0)o$ v+Nev7)EX%^Qf;K%NWGDQ<NvGT5jyP4bl_9`OVcvb(o_5y8EF}5=@I_`+R%Lx diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/North_Dakota/New_Salem b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/North_Dakota/New_Salem deleted file mode 100644 index 123f2aeecfc88f2e543f99d6a859e02788170852..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2380 zcmd_qZ%kEn9LMqBMfA!I?3allAe5E_0s@KwNm)Pyc?IzbC`3^pVi`aGK%$1fl3+e? zp3RN0lEBE-nhA3=92;R)Yb)o%=Cn3STmLNTtlVOOoPO`~v`4L;^}Rdyb?$xsc?UMs zZ%h+^JFoeNhwCs8@6p<PbsfvHUK{l4?zU*F=j9*uC;LOKk%iaQNOgqxbG%Vb{7^0? zFO|s~A7_cFflTSV87)L-l=QSuiJ)h1$Z1<6b#V1OYkKjdp0RSm@}`Vx?}2nHL=Nka z<NeZSAJsQ~-D8DbeourA@3Ur|?h!Y?)h*@Wed3n=FUZ-=wc^(L8aZcuz6dXPNY2fS z7q`XVEh84>>3JbO85tC(BY#_DMO_Wi(IYdh`DcF8G5y!9*q(Fx_NMvrj^|J41?wES zaPz0)&h#ttuEKZ3qVTgaF2NFUQ(sx}zHK6Y^o*5oEg%*Ty>2C5P&%pWMJxGaiC)rD zXQdokrc>)$W!m<+dTIVfxvXSdr^h`km#2N9@9`$cjHo|E#`mEzbK<hd`sf#V@0WvO zMW4^g9y}uMJNUD8|0{dN%7$V6K<feZV9`;XQ`4Ywm$d4<+%+oi_jg5p(iS`a!eLPm zR%92P+${>nQtd}xeMzsnxLW!5H0#x;QdCi8g)Z)xt=6o_)+LSC)!OJ-9awi!1tvYZ zG<`soej6joV?MXbKNMp9)G2#I?^RJT+G$s|ejpwl+GSVO921XqRoajH-`Cac&FYDy zUj1ZUg{lc_)3y28s&;IXu8WIRb>|9oz1O4ak0<KQ-+iN=>L?ITpLgsnO^d}dC$88H zrC~xHJZo=F|5a>jc*EWv{+ZZO)Nb#X8q-Y~y{c*SyxtknrgjeX>*n!IYFF1Gz57z3 z+SAggpBqS2EmdWDZ|5u(<T0OV!7jZ1>(7ko|G~#`y2pfYoVU9@!H#pp5;NWRQ1@Fp z&gnkS9NtC5Dt|!ubIr5XJZ0u74u~A{JIDOyJnlCH{=wQDb5+5ieaPyN<ss`s7Kp46 zS)!|1BeF<jmB=!Yb)vgaURWt-mI|zuW3k9;k>w)mMHY;#*wri<S+lEIG_q=B*~q#% z7LKf(W9i7+ITnwso@4pQ`Z)@KRDh!dNDYu8AXRWRWkBkH6auLPQVOINNHLIVAmu>n z!BG&TA{-?_YT{~&f>g!Tlm)2^M`4i4Af-WSgA@m;4pJVZK1hL(3LzyzYJ?OCsgkQH z6H+IRLLrsnC>2sGj$$Fz;wTqVFQi~d#gLLAHFGsZ<EWaeDH})KTutFPDu<K~sU1>0 zq<TpCkoqA7L@J1s5UHW7DI!uuS5rogI=Y%da#Rv2B}XlhVscayDJMrgk%A%>MM{d) z6e%iFRaaA1q^_=}ut;THO=*$ZBE{vXE>d2O`XUA9s4!Aujv6CH=BTo(DKk=MS5s)D v(ype|NUf1#Bh^OAjno?{IR3vX?lWOuZUUd^Uz(hjoRa8IO-)WsPVxN((J^&k diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Nuuk b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Nuuk deleted file mode 100644 index 0160308bf63690a6dee51c3c8849f494a47186c2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1878 zcmdVaYfQ~?9LMpKG}g?%E(w*86i#(IN4ZrlsfLd0K`zN92??PUaTqhR*1opJ48yc$ zMmz`)a+&KGVzXv$W172}4Rc%j`@R3>kw>1`{M-4z&U$vX@B8DMxwydN_~QvO|KY<^ zYCe2#w`XIaqm#E{VrS2H4T*ZIT{=C|(7;<7`th80Z9cBu?jF$Ymv(5_nX?jpv`!-S z?w1~wDv=eNq-Rly^qRdudT0A2DkVeuIFlthJVyGq>nbrp=^FESpvFFr)_zT0wEvYh zI-vfmI%{5QT=fHu-*Q6}R-aK<{xMC=y)W*Pdhw(-$iT@vB`IQ`B)iKbxy3Jo!>V=g z<9RaVN2v}yn=Zp1=4eW7o~AYo)wHc6b@-le9Z?XaBex8ZQJF!So*yQoqhD%9dW&QR zUDvFrCzAF4g^UTjAY&S@$=K#YGOq53WZyim-l|F&fApYEC@z+Xm78_a^zAyiXrWFS zRHVM_ES(xUUZ*+x>9j8{%?ZhroO>O0#^+d>dFqqSY6_Ow2RcY@{X3cC|0sFYjWRc{ zN#?D8qw|NKmIb*tH9vB<EKIG_g0?4hQH1KESG%;Zr9>BBE7v8DeY*7UEG@daQkHE? z)#BPIvb-=-S8Pp^m6KAWq##sQCH9cj8Q)}02Zxj<glOr9XHwSwi<aHFEamU->)I2w zvaYc~D|TPh^>zDnLwSw*tNiM>EGwXOtH6K$*UGYPZ*({;tLcuT_3wA{(}1>?#XH;U zbHuqk=HoV}7ZC94<@<|kH9ySaVtKe)<Z_YgMJ^b*Vq0^`$TcGuja)Ty*~oPx7mi#x za_PvmBNvZcJ#zWT^&<r!6(A+pni`NIkSdTekUEe;kV=qJkXn#pkZO=}kb01UkcyC! zY)wr_QMRTkq%5Q^q%fp1q%@>9q&TEHq&%cPq(G!Xq(r1fq)1y+B~qrXsS_y_sT3&{ zsTC;}sTL_0sTV02sTe64sTnES)>Ms@ZENaA3P&nON=Ir(ibtwP%17!)764fRWC@Tp zKo$X61!Ng)%{m|pfvg0w6v$d2i-D{LvK+{IAPa)52(l!|njnjUtO~L$wq{+Bg|Rg& zgDefQHpt>2tAi{LvOdTH+5T566r5s~Da~Wv?lh;@6Q30CN{Dkiy@{@0UlW6W0s=0- ADF6Tf diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Ojinaga b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Ojinaga deleted file mode 100644 index fc4a03e36931bbca9b00e0344d3659e4af700be5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1484 zcmd7RT}V@59LMp;vJ^2rL_wfLP#}aZH}f^KOlz4gOV?Uvx=J0((v>o-e0d;Ay7DPR z0#gc-E+Q0>WdwF*cZGQo7Gy#8LKIjK38ts#d%6#TF8Uu1pTl<h{kbawbq?{ztI+?h z)bE<X@W<fLw}v<2I*;#u!IW<-Hp4fzczMq54+%$8bTG~76<f<b1=ExE8X1n4GBawk zk(Ka6WPOM=vKL;6obRjEw(v8NI~=37KkOHI-JjKtz7Dao@u|x1?324nhgCsMn=IUN zP3<nMmV4rxm2*?Rbk1KjiXu14qUk1M-|Pxmd}C0RJg=0l)-JU_oF_{w1L{EU26-^I zSe1pA$@0V$<vuhk-9O`%C;hSXyh}E`>)#6RM4WMCX+l)oo->Zl+!2+XQ^v9JE264q z)Tkb)7e3ddI^NYKPo#{flm39LS=FOzoyD^DOGx>XQl$ThR|TTtW#C?pI`#gmtnWQ+ zoSuvmXF}OV!_b^)^duO;?kRCLebG4AI4YXfzBZamdqwlof(m7g$k5Cy)v~Tfwv0bg z=jTK6!oV$caoQ_e+b^lMu^ic6RjWF#C(4LrJj?YH8S!r)(;P??!ZiDph&0W+H$}8* zJ{XRO<vYUo{d<YaEnMYpQNUZMzxC_>i%Lv=l!DZP6oXWQlw+yup*;%Xs0b;Eqb8&% zq$;E=q%KQc7*ZKWX-I7x#Ua&kl!w&EQ6N$wQX*0#QY2C(QYKQTr7jey)KZs<)QS{~ zREw00)Qc31RE(62)Ql93RBfrtM(VcIg(H<)>e7+gIf_TB=O`bkpJM^Y3OJU4tN~dB zvI=Aw$T}?bLXeeM>ZKrSvDAw}R)Z`DSr5m8kQH$(30V`zqL5W_EDKqerCu1aGE2QQ vWNnsuamebB<ss`s7Kp46St9<QYmCwJ%+#|?cBR=Iw$x;o-EOnnQe%DrGnt91 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Panama b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Panama deleted file mode 100644 index 9964b9a33452f4b636f43703b7cdec4891cbda5f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 182 zcmWHE%1kq2zzdjwvdlot(*Pv8za+k3WcvSqYXJiTkd$Cx`Tu|C1_llv-w+08Aa)H7 ZVF)3?%>O`;*{&u4qKPq^3uu8U7XX0%EG7T| diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Pangnirtung b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Pangnirtung deleted file mode 100644 index 3e4e0db6ae0a5a704f8cdd549071cc5b7124e2fd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2094 zcmeIyaZFWJ0LStBf|Qu7oKYx92^pa9-UEAuh6Mq=J?+U2AEsb>H0TYXIGHjqLt8q_ zfBd5cZZ(#}Kb);u8LrmGpfzi?)>WdlYH+H>A8oWlwB<72?R-zQ+S=OM`m_6X?&t3Q z^R~D5`zD&(AFgozb}cY(I9&V8;kjgJqVeE|&wMQ|7XBzNiW%>xP`LV1am(nU_SNe8 zEqPvcELYu7neuKdzM^spa^1xlQ))@zio0a?7m@qbl$&>9QY;-CbMs#t6*rw2a&O-I zgIe~~VYi^^6IHnDgm+8ioLau_Y46tT<Em&yn^%+?7A2WcuVivStoW|PTRGAzO2_YY z%LZFS@NBUg>RT(q&*g~nWKvh`{#mSw#`JBCUy4Z4N_~69h`3{ZmafeGTvbk|oYj{< z&}+_L(06_@sH)C<FW0_(P~CORlXt(cQ&o4pE^7`Q5cf1ZFKb(Oh`La>tgovT^>e3m zv~0VIjvv*rtQr+N+o{*h6sq+vJ}dA0v|7aXcgPLr3Pi)!xODr|#r;(w*|>LFY|L9I z6HV`n#N|1;DRNqD`u1AAIsd%c{O+vYk~*cDPmb%B$)jrPp<(^tNT=G?I-s`?Zcrlr zhTL(aL+mW;mk%Z5qBW~WwnamtZKhc!ix!IHM^&<Y-kfNEC138Eo)8`VYjo$wv+9xV zJpJgIan;q7((>4_dMu*!?ydp#c=kJbPeZTTlbVv<mHnc7a!mH*^oX93A=!JWS?n7; zET8zSO6>1T$|v8<7k%4e^1yLNqy?@@OHaG{A3yWv|NhCi=8vcUK>luy<NFg{Al=?G zeE+>sXMyj3qXO62H`%-iEcX4kUUioG{>v{p%Xkhf|Lgm*aM-DNAmP-w=4>>lu8v#6 zspps%wH)*8I05^Wzuo?PPW+2m_~v37$UKmVSj|k3sUUOVyO<0z8)Q1je2@ttGeV|> z%*kpdh0F?>7BVknV#v&psUdSiCWp)pnI1AfWP->Ht!9eI9Ia-O$Sjd*BJ)Hhip&(5 zDl%7OvdC<a=_2z*CXCD&nKCkGtC=(xvqq+k%o~|FGIM0=$lQ_1BeO@QkIWxQ0FnW# zNdb}rt4RWq1*=H|k_RLaNG6a}Ah|%2fn)<o2a*pYAxK87CM8HttR^W)R;(s1NM4Y{ zAeli@gX9KD4w4-tJxG3#1R)thQiSBlYLbLx$!gMs<jHChg=7jz6_P6?SxB~!bRqdd z5{6_9Ng0wet4SJ?HLFP*k~gbK9FjRCbx7`z<RRHZ(ue=&k6*#bG>wdyR+h$B1uKH# N(s+4!usj&f{1s}GV)+07 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Paramaribo b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Paramaribo deleted file mode 100644 index bc8a6edf1331b6912c26e81078b00c8e5d87ffdf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 262 zcmWHE%1kq2zzbM`vLGxpk+pBfJ}vJfmy&e0NbfV;QUCw{e?}%|7MB12&v-B}07)AL z5Zebto;$(7@&EtT3k-Zdz99?&K&)$EY-|7`8A3>~6llkPki{SxWI2ciIRNBjkRw2J RJy47+hj7^donvRr1pph+PYM74 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Phoenix b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Phoenix deleted file mode 100644 index ac6bb0c78291f1e341f42c34639458fb385bf8ed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 328 zcmWHE%1kq2zzev6vMfL>&;TUnEwh?1e>Z!>f;O263unD-INixJ;k@{Lne+Wm*Ia0n zlKJ(cRN(iE2nHrbAY=wYMyCJ&r@dof`2T<P0!Ehq|L0C%-~h9Ee0)O~d|iMz7>L6| z7(z&J%6}k;W8v8VqCrjq(I97mXpqxDG{|`%8stO}4RR)!209f)gPaSZK~4tIWICG* I=zeo90HHg7VgLXD diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Port-au-Prince b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Port-au-Prince deleted file mode 100644 index 287f1439266639f9564149d6e162feaba3fbed86..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1434 zcmd7ROGs2v0Eh8AWkP}r7lNf}Z_#uf+EkRmP-9XwdDBsHG&_|xjG7)F+1SGh3ZYF% zr7l8<T0{_5W)y^E1ht723tEJoHZFqdikqmI>3o-{pf>KhmpQ-7T$s&#|6nL`sKEH= zmH6}9N-fVRr}c5Ax%K;^^ljsd9iM%RXFi$f?<ag26XWKRv0-24ox5h%)yux6y_d{o zXO8-oSG-ay8iv$L?|rpuN3U9)I-s(1+f{aKMC2q@sGO;Ok^5o2S~J=u@+N~Kf3R9O zht~;L_h#X~m?k{oDpk<-RTP$NQftfJiY=v4b8B6(&+iJE#r|wxX-z<yeF<WBkxP~x znHJ?4DKc2`Tm-+(%1ZA|vFGWGRTaCTLf0p)>Z$Xp=In^IceF{>*7aNa26rhDxF`4b zG>QZHeez&9AnKB%vcAM6>OY2LI6FmzUlhqm;;e|=%9IV$uSH|uMyu)Nj5^$zVKom; zs+NkFB`=JqR<E+!TKZLc>JzJ@v`clw-pS4leWG(}Oh(h9B073ac6|wnV}s}9@i#@{ zM0Z%8e2^)+Yq!f&1BP(SpZDudSn&7#`|Vtw;_*jr!_cSSNQlRuJ$5XN#~<D{lK*_( z83-DtsgGj6{*(vxA8Z&7M{o{N#Pt>F$uf~R_yqz%BC*w>Ah969AkiS<An_mpArT=V zAu%CAAyFY=A#vI2z>vsnb!bRzNN`AWNO(wmNPtL$NQg*`NRUXBNSH{RNT5ihNT^7x zNU%t>NVrJ6wmM)WVkBfFW+Z4NY9wqVZX|FdawK#lb|iQtdL(=#ep@{NWCXT)2*?<0 z^&pT@Aj3e$feZv02{II9EXZJx(ICS?#$&4ogp9~m4+$BQtsWFIDr8v5xR8M%BSVIU c|K-?{^zOWRe|dpIXMxk57w~wT9;Z9$2O7SHqW}N^ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Port_of_Spain b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Port_of_Spain deleted file mode 100644 index 697cf5bcf7f151ffc1c1fc4247e4e9c7e3ff01a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 148 zcmWHE%1kq2zzZ0GvP?kCG1=UB4deg+$3hqw{{KIIfPuxwH-y14ID{dD1VjD<0ZxOs JfTo#n0RWR(9N_=} diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Porto_Acre b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Porto_Acre deleted file mode 100644 index a374cb43d98bfbd06c82ca306a74f96993fd5657..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 628 zcmb8sJxIeq7=YnRY(b*vB7%roy9@pmL_{)nP`pYead0ZQxd`GC9dvQ&B#Mh`J2^?~ zbX(CWb7`xBn?(@+N@_Xp4bFk)INpPUgzt&BwVR(8u}{j}Ce0o^FP#?3!+BBeZmY_> zly}X7TU&aNwbrPtk9C83W#4Ud=4A6KbRQeH^2yt9KQG3EujHZot&Zf+(6Vahva(%$ zc0=ba2#X`C(@M+Vvr9E`Uy_ptA8P747o-+m)%5X+Ob@)M?2a!t{e<$h*0vS1`fOWk zwI_tuRb?f#uH1-z&f@>Pw(g0U*+sK6!s}sb^I^^8l<A`y0g3`ef}#=Ch)`6b8X1ZX zMTnwAk)mi(#3*VMIf`CXBS=w<Y9uL|6jAfX1gaESiY`T%qD+ydXj8<gZ{8JSZrMGl LJ1fS1HRJpN5(O6b diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Porto_Velho b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Porto_Velho deleted file mode 100644 index 2e873a5aa868c5605443c48510646f1408d58c4a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 576 zcmb8sJxjwt0Eh8Qe4)g*#X$$_+p2Kb4k99_t||xt!4IGaPA<9?yLJ~r2S@F6V=E3B zgyJTM4yCDG1c!hMzLZuu@5u*<m~i}t5W@e7zqzwDBNDH)ecEA9?@=-TTpHMTE&Z(N z^4pTStmkEQ_DWTwl&THC1hw+E4BL~ceiF&Y@LV<gMfrZ*7kqT>%Fkd=ef3Z2=K7p! zR_<iWYXq%}ZrzRs)pwzwM{Z74`rt{Ao-GGsnNW`(?yHHO2c0v<xK6_D8go4)gfaKG zPNy-IK%`byeK9RF_GE?skA3!2hK<P1Si2S3i)==A$J*`4{#e@p>43CAdLT`ZE=U`s w57G$f6l+@{y<%-Mq#M$Xzehi$A<_|PiS$I8V$QysP}On&=<3bex(iwF7t{3qt^fc4 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Puerto_Rico b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Puerto_Rico deleted file mode 100644 index a662a57137b69e8ba445e899566222cdd422a764..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 246 zcmWHE%1kq2zyK^j5fBCe7+atL$T|JZ=)fiAF9nwp-d<p2W@7yR{}4L^!~g%s4=}L& z|9|xYBL|q|@$n5|a0~|G03Z$z0qSG~;}8<;`ws+F&!+AK(I9(4G{|l+O{V=^Ku4Ky F0RY1$N|^uv diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Punta_Arenas b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Punta_Arenas deleted file mode 100644 index a5a8af52c2f26baf6f85a1786f69593491ad5195..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1902 zcmdtiYiP}J9LMqhIcIie7dAu8ZSI%3{OpWvZ1Xc_b3bfsX(S4h7%>m5HWJGNmqij1 zNs{<&F56`JB~6%|^WZcqOKFH?A@|GQ@BJ^Hc;ta6&guVuo%U??eSZp;l&ng&{`f?g zzwq$cVjg~XuQacHB6r5o;-~%-<xiSUS{t=mwza8dYo@H7Y6UJ8mFmlbQv6raPs^*G z)q%Q%7G2kV)L;L-SU22G^f&iiFPqmr4}^S+bf~Oaeh+5IAJt!!-F#nLn;t3G7Qc4O znaZ;$S%)PisZLq*Ww;fiyiwPs_i=}c_z^EV-w3M6w)ZmX>}wI-*dk-90;0?D2HAB@ zt%%(f(s6kQMYmOTI(|f%=sx3!?h#k5dJfyBd%oGMdWA35y@HEX?`KnVLQR_L^PpJv zJ&>UKUCfgGOTVcB`x0ehg+~nB;Fg2Zzly>0+U1bmZDMGerH6jLA%?yEq=&bj6eB*~ z(j#v+s!=UxbkeC4YII$d9<yV+8hd!H9=Bqp5|z8<`0N~&yu3vEGFwE7oGm9rO&1em z>SbzpNTpd_W!k+6k^Uk{PdfKfOuiGNGxju#%(ERjYwZOwr7Eap{#`Y7%_W`fJFlkY z9n#a|_o|%nwKC^jsmhHzD04g9BJWL^oOykNm=!FNv+FH2r)H9z+vFAV{5$mgV;7V^ zyHzhJ->()XeUSOZn^Zy6Ls^*mOcY*xrHiKRQWdssyWB31E6n}t>v5ZJr|^IJ^?Gf) zai?XO_cbfbwi}ccVcWO070uga-l2di_SauR0V{US+yX1#JY&QJ^Q4%^XHL<4T&~|1 z{KX-g|JyFv-R~Q6(8y6Ehm9OJa^T33BZrP0J96;I(IbbC9KWLp0Eqwz0g1uU1c5~1 zXu?3^KqnA>5D6a>3J?nt3=$0z4iXO%5E7B22?>b_2?~h{2@8n}2@Hu02@Q!22@Z)4 z2@i=62@r|U(S(S^=xBmOqC~<(;zR;PB1J+)Vnu>QqD8_*;za^RB6c((BQYaEBT*w^ zBXJ{vBatJaBe5gFBhe$_Bk>~xfQ$e#1jra5gMf^JqZtNd9FT!PMgkcMWGs-uKt=-@ z4rDx#0YOFt84_en9L=C0qvB|W1sNA)V33hPh6WiMWN?ttL52qzA7p@#5kiIt86#wn Y9L*>p!-N&)<o}y-ip(&RmF0{43F9_LCjbBd diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Rainy_River b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Rainy_River deleted file mode 100644 index ea66099155ca930810062eebcfbc7fc99e97097f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2122 zcmds%T};(w9LJwSHjzZhq!0;wDG5CwU?`gOCX7KI@#S~`A@c=8EaR8LNz~})#-uLN zP0DmNj7GIqO^Ib#i|lo+mocQdTE(=MYi`t2d11*oJ)h^ctFGGm{`Wke|Nb}U=6pWk zbq)9Dn}6(T_l3jS-Qj(zx~sFVOOL(%r+j+3a>M73kLj7&m*mXG2{wMlfKEtyLlR7n zCfKLsnsXgG@tYGi@pQ9JI(5iSe&vu!I@)BfeWJ-sX^GhD8X{(Db)iizD>T<HPPI2= zrJ9ski)32-s7Z~RCaJ%t==AefByI37z486;CB5f6&FFehW<)2OnftnA*4p39>}~Jb zn+k@^&E?1Joa8r6=G=WYb8Jwv5;ohc;a;74vBb{ne_De>n<TsQ5zXl>mievKn%gl) z^6H}|e`mZbD6KNLuD&P*nM=&V{4ZqD_%u^E{byTvVazPP@|j)o$vJb|x3Afy$49m3 zodfpvgTs2qvtsXTJgs-NJt=oryr9eK8l`xCo0b%>l9E5(GNswuZRyZaQ<hj^%X;^i z@{v4y&vVb{^0O->w6{f9oXnMq+8SMXc#5oATBNI+FUgv;3=OY6E8)?AMhf~Q@>9C0 zO8?4MeQZqi*h#yt`v+4qe8kqaePr(K-)+~|y=3m|thF0LALz#R7TJ{Dt()s>q%Lv4 zZYeF2EhAgCJ~Kn=zbw~=@d0UgJ*e9*{3s6`E;A1f#O(IyJoC`;^R_XPXyo9B_ThqG z&5p(w?at&u(^S!Jo5n^oTG%bo;Q`&1vR`)f_h`%It+KnbL-%}LE_+*>_0hhdw63qz z$Bs;rxIkRss&U-^=@W~+TxCowcIrf6TrBqL^CsTEPxN=v@=(|;D|Tm%JC*LN47<Oy zF#&&t|Ah)Mw;jK<-vUtrq6I_^h#n9{Je?-|5UN0QfhgnYw1KDt(FdXsL?ehw44oiK zF|>lH#n20)7(+9NY7E^V$}zO_bm~F$gD42m5TYVPM~IRPEg@<$^n@tN&=jI7Lsw6y zEJRyRr!GWah{6z!Au2<3hA0iu8lpBsZ;0Xy%^|8YbcZO<(B9Lj&(I%|07eENDS+ev zk_1Q=AZdW)0g?zvCLpPR<igV>gOLqSmkvfgJY7N<8G)n(k`qW$AX$N=1(Fv?Vj!7; zqy~~3PnR4>c065r82RyZ31Vajk|IWqAW33m36ds8o*;>WWD1fhNUk8sf@I6nr3;cT zPnR%A#ynlhAUT61jgd7-+8B9*B#x0eNa`55gCviUJx`ZDNd7!s0wEdnbSZ@75Rybl m79nYb<Pnlc_&>>Hf~)63SJ7Z-K~8>7ZZMRWmy?&1oA5XN!8Dlw diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Rankin_Inlet b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Rankin_Inlet deleted file mode 100644 index 3a70587472c633aaa178c7f979b8b3884d604372..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1892 zcmdUveN5DK9LGOLPK}M6DT+vtkAxn_9fqC{q{T4?ilm$bLS~90n)31K5FhaC#`GV{ zKb%j~;lt2>s+nV=u0@umTdO%nb8QvVTGrf{U#%^tjPv{Y`M=qpzHfK0?e2E>&*$}u zF0NmhD^Fdc`*fgtCjYs2o&1|KZ|Q^A8gCA(uaMzYVVhhWmJ!oa?Z~WDNf|p$M-A?i z)Pzx*dOyXCzV%4cx*nQWzWP<u&;4RDPJXGc#)in4T_<(yqI)uK^%r)0UbjprIc_H= zpO?%@yKH8Em&r<8ZnJvY&7?bpc5>$d<L_Rk*{zKx&>qp8<|-51KT$(<G0ELHSf><K z%Igd7XkO+FnVS2(P8*aa;n9ED@a=w?{^&b9<LXVB`ST}s*4aLj|M^GujeR|4_EEKS z8ZMhRTRzmc%1)Vr+6Il}w3x!k0xkUef)r)1wME@Wq&TU}7PoJclHQP=d+d;zcVoVm zZf`R4JAztPQ*GWp__8jTm2Vbq{zuExGE8*Q4UP8sOhw*Bt@tBdD${?omEVd~^>^6C zZNEu%&tY5B@{PRPxz#SIJtOb6*4U+`Uz_*$H0iSJHnY60T5FSbn-xX*x}tZLsmsjJ zx*tkR{UD##f9f}@Z~v}q4i?J?*W-3=Y_hC7d&@RdB#G|3V%O*0l?@H2?Z)IT*;Ka2 zZtCwfv2dHldaj!-DZ6z`=Q-2#V3lrd-EX%2RHECPH=7+7{o1_b9kcWBOPb(Ic;Q(e z1D^St|M`ng4lf?RcG))|9{>1+ycmyP`plQas|<bePIfRT1(8Tp3d-HnvCuL4Kkhc} z#_dAx7jnb=Id{ysWyn1<ZW?mejN69XH{-@Vx;uy5I^^CVHxIdc$n8V!pWy(+1BMF_ z9~e$RykNND(fI*!#G~^B;tIqUh%*pxAnri?fj9*5h~W~%Cx%lHuNZDY{9-uf(Rs#j z4dNTaIf!=<_aOd39E5lXaS`Gp#7T&k5H~$KKN*gCbe=L?_2_(MI1BL>;x5Erh{F(% zAudCFhByuJ8sfG`=QqT0kIr+3>mHr&4Cf)<Gu(&x&u9Ro1B@0xdH`txqzjNXK>7e_ zgh$s2NGm+LUO<}R(RBmT4oE*34S{ro(Go~c7)^n6h0zvBUl@(?=sE*wjYroTNOL^8 s?m*fD=?|nqkPbmw1nCic9-EZt0yWhI%3nGqkQ)g4OGBYRC=g713}O-J3jhEB diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Recife b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Recife deleted file mode 100644 index d7abb168a7434579852b7533fe062fed9297ec2b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 716 zcmb8sy)T170LSsC^%5z;Vld!nBnFa8OG-3iBw>(rz+e*6iNRnIF_<Jq5|$gqAUC!q zi?@jgkx1X@BrJq#ik$o2A3!}%E}!9s=gIdMn~u+gykDO#ds|^o-PZnmBGE9KOMDNj z<V&wS%q)q!{sVdURFbLYd!0&7iS%ca%<N`FHoYTrv9NgCHu}A4Mih=_<wt$1Do%9E z;_0y{1+H{yuc$tstL4|mifTFEl&#CRs!jE25x!9EYjN38d!~YujXL<SC^{pry7T%} zL<%RmKd~+bvUxf1*q{c_jE*kUt5su+-&fY_HzqscdB)^(zDi?mF1?zu@tD^mL-vHd z*guNcj~c2VWt_GSQV6MplycfyNHM3ahLl6<AqA0&NJ*q7QWU9*ly%y=NMWa~jFd)d zvp2<&>PUH{KC%F^0<whDu7ND#w5uS?AnPCtIqgcwQpj4kYX7CIy?p*Z77Ik}ZbRX~ E4^%lMr2qf` diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Regina b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Regina deleted file mode 100644 index 20c9c84df491e4072ec4c5d2c931a7433d9fd394..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 980 zcmc)I%S%*Y9Eb7Wq@_$lyqJMVi$W|41r?0;Dt1v+oCsXRm>A5;gMUCATqHt^7hF5K z5s4sImBW-o-ctz1OIfDJyk9wlE5VNMb9AR0SH8o0K8Ime^L)c~(HBK>;#@M{a5=^1 z@}BkTp#6HRuUB^_((Lz*Rqls^2hPW`Lbp%db>g{K-MAZa5?2bW#P?n2({6_KIet0v zwK?4#sNZr1Yc}1X`|Xk8!U=ceX0J1vy<v?7Cn96}<JPy$caib7kWS|8S;_h=nQVBi zrfQpH`pJ@-xiKd{iigxs>6h7SJ!;nJl3)J^^zSb%GB@9?|GbIW^Zl)Qq0P3PSX3`Y zpWA<5KGsVQOYP-n`FiEfEqk^6ky^_rk@eeoYW-iXY^}O#duCF0hLh?-;M7k_>ZxBJ z{rIBibu5c`-rKG~s(IIv?!Slpr{XD@6_sJBEH$^*+^6PNho!{4a{|ZD@EQJm&m00E z5s(l_3?v8=1qp-1@il>vNWLZ%5(^22L_@+M@sNN>L?k2<6A9{Tq9S3DxJY1M6B!AO z#72T6(UI^-d}IK=W(3F(kTD>GKt_QK0~rT05M(6CP>``8gF!}v3<ntxG9X_wB4kL& OnDE>O6*LRG7d!-P)%6Mh diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Resolute b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Resolute deleted file mode 100644 index 0a73b753ba597f89cd57cc3875e7869dc133778c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1892 zcmdUvT};(=9EZP$TpAm-OcIeGEk*QjI0r+ICY5p+gG78eA_%^u7-AY<-wvWiKQ^XU z<%P>^I!uS&lvBrin~Tg+H>Yz9b#5Bdn$Eege!XnDU>twX-y5!+UiM*!=j@z6<L3K3 z(S>y%=gL#p;J$s)y^^o@Hk*HQW-fg+uHnvWb>%XwGHjEJ!}9u+R69H?RZ>Pz))7Pc zBsF1#rv8;;M&9k!w9fy`8$bQ3>BnxHjQv0Ao3U49RP%lvJ^xR6Yt;|-?Yu4-Q?k#F zO+GG}<C|?}f2YYxTyC?v+s*igg?2*6SH|D9OtV`XOrSlYIZc%&xO1$AYGabSeuz#i zs*rc)KGeL-sWK_|vQ8eHCgG6}Z1{e^OzFL3r(U=t@80^}PCL?P^3Qx}-`mk`-ruA4 zgZi^(ddn9&qwIhwsHxXTPKzmw%+bQXPfAht8e7!$jT9%9+2ZysQqmK$AMX9y%)Bv6 zOSd+fSto*8R$XOg?;5IersbQt8~@RHX&ELu|At2Ue5O3_l$PI1mx}ajw&J`<W&a7g zu<bXg>fUXuTYiy69h>dqnnSXrwc0K%J!d}J-l)s6+syLXDy>P{W>ysC>x!P0rZzJ} zYp;};y1_oJJM1^B?*Fcz>?)SkSL1d~Y=V4x<gTqRPZHhnvt66_hpekVXxArq%7(J- zc0+%UiG|xV)_v7%O4+8HI*ysfM=N!6>rS)fW{GZX+GsvI<=3Xg3(V)cU)BU)!VAy( zGibn*1K&UE-w$~1$>GK07ti_z#pB<7D=)?4r;qxQ_${wK`6N3Sl!8bkDh2c0%dyZg z`W$x~cjI;;_Y1jU{yBHdxMj#aGj1Ak*NoeS+&AOKJ-R!G+&bjmAvX`Xd&uoW?w{cR z!~=#45FZ#$K)hhM;nDd4am1tZ1mX(B7l<<uZy@eK{DC+G@rdCP#3zPR5U&_+LHuGk z=Fxe^a1G)c!#Rj|5ceSdK^%m52yqeOBg9FFmk>8SIzJhXdUT#LT=nRDWjG7*7UC|% zUx>pHk0CBYe1<p;@fzZ`N9Q-hagWY(hU*@k?+oW5-ZR{X_|Iqnqyvl=Kzaaa0;CI& zHbD9SX@p1D2}mnEx?Vt<;n8&i(hf*J7!84RgwYa6PZ&*sbcN9tNM9I@@#s1OX^ltM x8%T3Jy6!;Q1L+T>L68nXS_J74{697+(FJOf3zWZfVjwpV^p}Q0flwfr_!wfe>F)pl diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Rio_Branco b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Rio_Branco deleted file mode 100644 index a374cb43d98bfbd06c82ca306a74f96993fd5657..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 628 zcmb8sJxIeq7=YnRY(b*vB7%roy9@pmL_{)nP`pYead0ZQxd`GC9dvQ&B#Mh`J2^?~ zbX(CWb7`xBn?(@+N@_Xp4bFk)INpPUgzt&BwVR(8u}{j}Ce0o^FP#?3!+BBeZmY_> zly}X7TU&aNwbrPtk9C83W#4Ud=4A6KbRQeH^2yt9KQG3EujHZot&Zf+(6Vahva(%$ zc0=ba2#X`C(@M+Vvr9E`Uy_ptA8P747o-+m)%5X+Ob@)M?2a!t{e<$h*0vS1`fOWk zwI_tuRb?f#uH1-z&f@>Pw(g0U*+sK6!s}sb^I^^8l<A`y0g3`ef}#=Ch)`6b8X1ZX zMTnwAk)mi(#3*VMIf`CXBS=w<Y9uL|6jAfX1gaESiY`T%qD+ydXj8<gZ{8JSZrMGl LJ1fS1HRJpN5(O6b diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Rosario b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Rosario deleted file mode 100644 index da4c23a545b3603bcdd4555ba8feba117802e7b4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1076 zcmc)IKWLLd9Eb5YZK5$03@9if60xNuA{=RB#6RVg4plKr4Je%yL?{S~gB3)hi<1zL zAP6mu?W%YV)zU_L8f&ye38W%|LqKs;L}G|ld;Xqt7oE(@y`O_DFMOZu(D13G_s3tK z{JTod`YZC9xRF;6E)Mz+H@(!;Tk`(&(pfdL;gXq|n$)wc`+n)>YxU^Od-M20M9<A` z^vzISKN%bIpYAEE^5v>|wz;Y2j|ctvm4vG7Pn$~po_cY$;4fru>xEC(%woo>Mg7s# z;win<f6_Geg;is`X}*R|t7bClH$RN)*1CSvs?^lC#)!XM+o`{oQ|3qMi28YF&|eu% zDSN%wUp;w9hda*{w-u&zXS7i4N`KK^pU)S&x2{#))nmoDXZ^U|T};$#YWuCDv2^pf z-Zhud10!qnz}sBx!19DXSUM5QS!)Ar?SJ`%g1?_OY<KsNwdJbkxp&aoit)nMzN!W~ ztbJDxM7et%hcj8PU(OEIE2l?J(#!tCGV+o3+~{46EQG9tEQPG)l*N$MoU$CU9<m^^ zBC;g1CbB59DzYrHF0wGPvQw5u)^^I`$m+=QPFWu*z$q0VB_K5*ML4Ajqzt4Erxb!z z;*?U5T99IpYLIe}de9ZbMJkfuJxW4qLW)AFLdtSVT}WY0sSGL2DYYTRA=M$}A@v~z YI;BFSM5IQ{$*29FA|rdH&Ay(<FVq<9-T(jq diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Santa_Isabel b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Santa_Isabel deleted file mode 100644 index ada6bf78b2815d3d99c97d521ab9a6b35c8af8c3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2342 zcmdtiUrg0y9LMn=gpw%wq@u(hds2#laOA%z_Rpvz$O)7qi5Z#kXHW)-p%f81w$_^C ziw?_G^yKV<wIXJb{bS^oTWhSsR+x=3Q(zcHtQD2x^t^vvcGX?$clJE5-_G6d;`8?J zsIE+N{_)JU|8RIZ?BPA~wccM_x*7}Xx~H3_dMnH8-i=ny>9Fak&n6DH46gd6Zt(c~ zb>BpnIz#PmPhD)@EZ^sCl}lyGaycPGM!orJZ1EN~9-pMfr_<F$=t4Cy7@@9=PN^Sy zep8cY2i1@5=hgg?ZnNP0fC}$#Hw)kER*Smc)arP<y6#!giyQ0JlIp#BY3Vi<k>}UT z)~!{`6S8#V%3`^GUZjo+&XlO>3=@5Exx@@EGqE54E-QLw%nh$z5Z$m^-+1sNSy>XU zSJiy0;xd2IH|2k*ZjSg;$0v5G_}NL55Z0m+hCern6T8*wz8;fwu33^hj~dUZU9zV6 zag%a%qoh_H(P{N@lJ4E7Gm7U*W_*dxN*kB8q1ie+W{%1pi_+`<98>GhUe!4lK2;mu ziZr);@VdIS?GJO?i-*<iwcnXLTDxRpVV}9P{5i>8W6WK-d*tp#hm1F_P`op*=)90r z$s0PT^Dixt%`crY1z*>Quc^b_(_0{gJNKKSV;<SEq10?`P*NO|WBl8u#eX%{lw^J- zC70Lh?JIs(+dqlXrL*VMj+3+czTtP&&ejoqf8X<}to)3AptDi!@(r5@pXrd@$^GV` zs{K+Pe!^6EOQmA6)l|jjNYy~4sSb^m>Nhr-n$dtfe5^u0@<oi=)8N&QcF(HXk_27X zHliNOny>fPo>BD?lX_p_NwqI9&opHBOT+LLb0G4B9OxS`jWezCL}#~oa;Q?8n%m7& zr#DG+S-pAsg+vJo4hp^|IAo5!{yV=w;7Ebv1OhLM6A}otwK&)E9<;!{m3uEO@cA8I zvEM1;<l1wuJw<*7<2XTo-~N9wu7G_Q7&0<sXvo-*!6BnVhKG#L)eaCDAu>c{jL0C7 zQ6j@c#)%9R8L6usDl%4AJ6L42$Z(PIA_L~j88I?sWX#B*kx?VVM#hZ{92q$>bY$$v z;E~ZI!$-!C1i;ls00{vS10)DY6p%0=aX<orL;?u~5(^|4NHmaexY~Fi0dchvK|+GW z1PKZf6(lT3T#&#ZkwHR(#0Cit5*;KwNPLh0x!MRJAwpt=1PO@}5+)>0NT85NA)!KI zg#-(U77{KbUP!=PZN!j}x!RZ^K|`X3gbj%s5;!DsNa&E*A;CkUhlJ17#t#XgtBoKM zLRT9@B#1~9kuV~0L;{IK5(y;|OC*>`G?8#3@k9dZY9oq-)YZlm3974&DiT&Cu1H{! z$ReRdVv7V9i7paeB)&+1U2TMs5WCtKBSChxQAWay#2E=R5@{sVNUZUHAM7w&^K4u5 UBwxBG&6ASkOHK8pdQ!sv0^LWd&Hw-a diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Santarem b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Santarem deleted file mode 100644 index c28f36063bd264e932a1910861e884d2a1669b00..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 602 zcmb8sy-UMD0EY2v8>Pgr#l=DE$Et8x2N97|mkufj0l~>h5nOapT#ByUMbN=foo-CU zAzKj~1ks^1wToLo1wTrwocH7pD4Gy{fk49h#9Q559~Ui;jD70ZtMlk`Kj-(Xy!t;& zy7)GyuBwN!JbA6kQCd~{UV=(-Lx#-}RXvI1Q+Tdw-mH8-?g~EIw&Z89qrSRFb$xkC z)l2uX;nsr2MZ0cBz3RJA(ET^3YGChKXU^t>!EC694tCXW$D_`zZL7R7CYfk)rc%b- z`a&4<aF=k5DFq_Uy>J#5JuxP;_L>mhKc?C*8s;LCW9@8YIx-(g5Nk6aDPnC7BngrQ zNrU7;5+Rw8R7fr)S**>5q>Hurkc3D^ek3W8oJdk6E0Pw;izLRpeMgJPiR9lhyVExK HOxFDc#B>P9 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Santiago b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Santiago deleted file mode 100644 index 816a0428188d99f437004312ee73c3860ee0f54f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2529 zcmd_rZA{fw0LStF<?<8{2|^~Qg%n1iaDc0T0Uk+IQt+1eL{~C(AZmcbLn(!^l~`LO zqqU~Z>``6Q16DwjdDa7DQQf;@WRtZuwbh!8o-9po=lfs0>Q(RB`rrM}=kC6|+wXfy z%c?3et$#eB<`-U`m(0ue*xlx67fTlJ_ndbhZ2orOkhMdr@}_~Vraalb(DI&GTdUtn zbh+Qoc~!pStn~K8kLaFr``x`)J-Tl&!96s+S`Kah&ilpLcKzkF(`q<#l^$;FkXL=V z@><7b<sbS~TXkoZqrt5MWRY^N%FuxcDJm#`g$%YLRY>?r8S>4T3cVI1uRG;aVWYpw z@WU5HME{74Z1aliU+j~UwsecACx><P(oQkCqDRLhH;UNBFX$VhJJgg}yY!UtdNnn8 zy`Jh@t>P{$(D7Z_YTD->IelNensGc|-c<Xiy16|;CbT%k%$fk1m~%zkQgTk-8aFDE zvMrtT$0;%Er{DE$XAX(vOCRXl-|JU*jJ&Q>UOuR1_q6Fbt&gkJ=eO##jhmF%y+@`O z6sn93RWdVgM7ZQKIX8Tfm>1bAvx0|Jwlzs+e-bKkzE9EfkNzO;JRPZXpBfT*hsSjO z)?;Epn@`J?AFG91PUwQnH`QHBpVNzCo>7JA-LmlKTD2s)Q!W_`5KG4!WzoqRakp=+ zT-Ix;<z4e-@j!?uakuIf2aYLs!5Mu|^Rw#Sl;7k^Pn{|a|4OdOx**mZ|52~I@guRW z{WD#5>8QA`MrqHHO0~YeS(ooEQumjZ>kU;Y>H(M38;c^<rr1QiIeAQN{v}XXOpXv0 zqcdgY_(id$-zlqnUa|GSdAY5tTWoJ0ln?If6xE(1vSz1JwYg8r9c3M=F6j;Z(ENH; zAGB9D#IIHj=eOy`%h{^w!(#pL*YWC+*V6RP_p`*VC!%%pD{<n{>Qwny>lM*b5+z&w ze!nBY;dBHBOnjUH&LHy!hx|uA!G3@LyOw32fqs9VvO@j-L2X5FI?Orjbwo{^{Jy-n z)LLoYIbyDPUFMxwqQhaPW*&#5^k3}L{6+q%Ju?Q7og!OB_KIv4*)6hNWWUIUksTvj zM)r(s+ScqE**3CoWaGAG=g8KPy(62qHM>W)kM{ogLIZeA2Y?nJJwTd(bOC7t(g&mw zwx$zEE0A6w%|N<=v;*k}(h#I0NK25OAWcEKg0uzc3(^={(;1{Swx%~obCB*J?Lqp3 zGzjSs(jufsNRyB*A#FnXgfz<5bP8z|(krA{NVkx7A^k!chI9;R8PYSPX-L<Qwjq5( z8i#ZaX&ur#q<OZcdr13`{vi!SI*7Co=^@fYq>D%!kv<}gL^_GI($@46X{N2|Celu% zpGZTIjv_5ZdWtj^=_=Azq_0S0k<KEmMS5#%nu~PT*0dMtFVbM7!$^yf9wSXgx{S0L z=`+%3q|>&h)kv>xO|y}1Bke}|jWitTIMQ;Y=Sb6$t|M(n`i?Xn={(YUr1!R_`AGMX z_9OjA?f~Q-K<)zMK0xjS<X%AT23wPk|Kt4-mTPW~e3v;h^Jf?5q^76NOUrQ0E_VI> GE$lDZUi%6F diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Santo_Domingo b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Santo_Domingo deleted file mode 100644 index 4fe36fd4c11f998ba3f626c5e23d97bd82d12791..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 458 zcmWHE%1kq2zzYO{vTQ&s-2fzZ-FHg(#o>M7*Yd*-|CfKfz~Eecg0cPb1;$_X9?S(F z0+{czc(4Xs3Siye>A`NWC4hawo)eq`(*i7i?|ERQ`7nWznTeSN4q2I5|Nq}t!N33{ z6Bt<j|37|!k@Nrmof{Z<|NlR*gHaG9!XWPB8^RFm0wi2rfH*jWLD#^<*nq(i$O<9B z{r`a=vt5=0M1%YRqCtKE(;)wV0LV`u0Q47#0{IP01N{f0L4E|&K!1X0kYB+x(7zxW c<YzDq^f!nG`5i=q{12jO5e8hqfH2_#013~GqyPW_ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Sao_Paulo b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Sao_Paulo deleted file mode 100644 index 13ff083869a9ac8476775587de8476654a100017..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1444 zcmcK3%}bO)0LSr1D=96lLqvr-CL)&Fv}?MSnI)!{Ynh9wNeGo_9f~NbLugbI2!*`~ zb{RT^bcp9rq(Wd}sV7T}Ky=;o)Qgl+x~$gIeCH1+Iyeu*=kQ$S@csF!8|qxvUr&wx zyGY;V_a2>j(iu}6==_zZx~4N^xBsjd@jR9zpF?tV?FW0bt4fT`t(N}#elb4QE(1Qd z_))z~{#<fI%=8?Sv(a%XSe7b-eXm3)a>x#K1l8P^2sz(!NyQG_kZ~8@t9Z557Vbfn zaJfNli0W5~l`HMUiPIt}>${ya+$WL~Vr263NtI$v%al7UV&kV3_NJ3AmD=-Erq%U| zbk!y|?|CR>(?z)@)~j5Hgzb(vAu>EZnGt*;GDW=19IRJaGp}t==QWW%J}I}|OjX<a z9Xsb#wA#_zDsxM}shzFAWnTJ_+SMGCyVrab`DHI<{_I;(;4QZc0#mARRkJL7c2^XI z9@xcg=f&QUtM<O8+p46y&i2-xQ>E=i_Wt5q;=q;TvP@*FgGUQxxwT&T@>8VmqeoOE zM#+kSb)qtSN>+Bvi>ir1S$*9v4*P5En))8m=r~Sz*n)lGjx$_hS&lOq2wUtp@7`ET zOT0cSO}g}TTfYCOLO;}@45SXDE(ECrDFvy;sEa|WG3s)VdXR#Uijb0!nvkN9s*tjf zx{SIoq%xx}4XF(&j^?QjDG#X+DG;d;DG{mBsEb6ZH0m;uI*qzeq*9|U6{!^|7O55~ z7pWI17^xU38L1g58mZc-%SP%p>cWxAk<yXck>Zi+k@AuHkp&<tK$d{40a*mH3Zq^I zvJRtO2(l8RUJ9}nWHHEUkmVrjK^BCp2w4)cCS*~_s*q(N>oV$vAuBWLr6FrG>ct_e dLzaiE4_P2K>Q)wPgJI$SSYc$2-eRsh@()nK$prua diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Scoresbysund b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Scoresbysund deleted file mode 100644 index e20e9e1c4272adc40c07562bb3d6767cb056b550..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1916 zcmdVaT}ah;9LMp$Q<sRux6Fr9b4yLlqn_i_svYgYR9xp+*2y``Ip;&RIk#LB-D+o} zhzOByARAGVqmT%*F03xBw)TW0lOQB&#Uk0(9+0A>#gNnQ{olndcD0+qjvQZqJe&*R z`~LW9wl(Ki|9H(Zf8oum!@PNxLmzo!BfV`a=jA1T5ta0$KRWW3#spu{n1>fNcJh?Y zzt*n{zB-_B=PyY7;E*I7J|YXdRT6i8EYG#J%kx_rWRb@wN$wI!b`(fTe5x#th?UgP zVojaS)3hH`G<_mkmwYozGlu_A$FW~Dv-hTE?YXSkJI<@K@ua$HZ%9u2u;dnwNZy7| zBtM}~3UWH7V8$;?<9c=J?Rr`EXNNAoP%JNgU#;$eIxQSou0?xS>54<~y0SS*SM6CQ zt4l+*xG_%Fr2MQU#WPYG`kj^~{UBviKS_D;B`F^tm6s-u%G#k5;u-r~y*=GhG5DFT zYipDB-Mh8&<^8&$wMjR=(5gO9nQn@y&?-l|Ry}rVbyTTTU!SY5Os7fB*+;s0B3!og z&ym{U-{n>RL#gW>m)Ghhq<+`0`ud7<(oj35jfn@Psc=Y}!_Mf|1l6tgKGl|)cHK7G zrElE!>6^zlYwNe$<*j{%+BUFJ-fl_MclPGX_DZ+3H^<1ku7$Fr<cYjD$C8fhDDAj^ zS2|}u*3PS6OV`v5egE`;d@w$uI}d)TyN3Go!>(iM@A0cY5C{Z46Z~vQ=zshZ5(xa( zVp)N}<Q>aAKe!(h_V=?D#^D7;{Po-8^;wzD9P@Tr8BQmkm=~X!2g~;_F4+9D0j`*@ za>>XwBNvTaHFDXu=DLv!N3I;XbmZERi$|^=xqRgMkphqkkP?s@kRp&OkTQ@uY)v6Z zB}geqEl4p)HAp!~JxD=FMMz0VO-NBlRY+M#UACq$q%vDm8d4il98w)p9#S7tAW|Vx zB2pt#BvK_(CQ>I-C{n4dDHW;J))b3Wi<FDhixiAhjFgPjj1-Mjjg*bljTDYlZfi<M zYPU7TBh@42BlRN-fUE$r1jrg7i-4>GvJA*NAPa%41hN#!TG*P!Kvn};4rD!$1wmE> zSrTMTkVQdO1z8qkU66%ARt8xbWNmEC;vlPIYnBIDA7p`$6+)H>StDeTkX5q%-!D_R d+bmX*%WXER$l=Y+%Fl9UI~`t^(|&S=KLvok!I1y} diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Shiprock b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Shiprock deleted file mode 100644 index 5fbe26b1d93d1acb2561c390c1e097d07f1a262e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2444 zcmdtjeN5F=9LMnkqQH%ZQ;8v<nU)CgtR#>b6-0<P2(NH8!YHnHS1a(Ln-=0RD8?U+ zvtrCL36!+fOng|gv7xTv+REl|Yg!BKxhxw!Y?8peo%dPwPk;4STVM9OuOIjS&-=Po z`_|@&f812_4G-6C9^R)b{@GWcUmFNlJ<liU-dDa?dprTXw{@E6E54}vI`*j#+N1RF zyx$s!>*B?gOursm&?$b8b?d7UesOi|Njd(VTTGm*mXq%nh`_OY8GIv2h@FWtq%9yq zpPH0YHYBL9x|w=v#e|wxIIhF9MpXC<xjIswP>}}?Nyq3Ob<M?I9d-V=h(6JxW8Uo* zv2XTB`ErZ6w*6Uo-Bypd-d8WDuPPC7rT5Ai`6=Rtlm#+=Zn2sf>5vJb$tvNO`8x57 zNR>1kp=X`^LCrpNN#EFeTFvp#k~i%*sOGK=%6aQP6gTI7E^k@(wwNFHo=i^FA~|qD zr#Lo>l#!D<^^!~6I=EM-oo!U<-OuTaBb6$%*{ic&TBNeQtuklR47IRitz1+&rgD?- zlegu3q85jz%DluYBJbNMnLmDB6rB1=-u~%;Skmv%cMR+nOFMqlckbFQ3L8GsceU<P zcbE6;d+N8TqRba{anTx8{Ogb`NpBJ*XZOp}=vq;Fq+Kq%Tqw$3eO)jAxJEgf+VuVJ zELG(-K3&l@M?J8lOjr6t)rzEa?OOSja!thQs@zkm>gzP=p8ch855>q;fg!QFZ&W@w zvR~A+4$FrI+eK~tQMsmjy?EGpM%T5qsYlWe>qoslRUh4{JtbwzbJ?%G$?3{_+O2)z zvC4O#K(G7eXSKeoT0V9rMm+A%mrooV6%AF1vaw@WY{;FI8yk*_O>r0G=JGDFIWVsM zd54vM<TJe`zEf=(Jg&En`PI|iz51DRZq?M>qPHC@P|dX-y?tkr3Jv-5Z%WwTuYY~@ z-y00>?i3;ze5)rU%)Dz6Vc(<dr(EuI31^XcR+y*SJQXgpA|XQThwERgFKDhdEUF(_ zA+khdjmRRARU*qo)@d~hMOKO|)oRv?EEZWUvRq`nR<mGa#mJJ8HKScLFRYp~%LdlX zv2bMN$kLIuBa25?Z#BzD)^9ZhKq`Qg0I2~-5s)fylmV#&M<I|(aFhb61xGQEYH*YT zsRvRJq#{;R5~L<bQIM)2WkKqK6b7jbQW~T-9K}JZ!%-fjK2}p8q(W9xBBVwfMMA2C zlnJR5QYfTSNU4xoA;m(fg_H}a7g8{!VpdZ!q-GpNL#oD6Hl%JGg+nUGQ97h{Nb!*B zA>~8rXEg;xDrhw&L~3X?MMSE|QAVVWNFk9*BBexXi4+s5CQ?qMo>o&(q@q?+QlzF< zQ&gm?9A!o7%28OPvK*yFYRgevq`F9Xk@_M9Mk;JIB}Qs&HAP0MY&B&@>WmZ`sWeBa zky>*U8>u!&xsiHv6db9z)s!5mxz!XMsk+sa9jQA~c%<@3>5<wa#mE15^&RHNV6pj8 VNOLaC$jQh`b7p5}WM^bK{s0D?lEVN1 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Sitka b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Sitka deleted file mode 100644 index 31f7061371910ad42e4310b7a646ba1a98b6cba4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2329 zcmciCeN2^A0LSrr5x8)LdP+z{v=b^<UOhm(6=f(!hy=#<CPWs6-C-ptjNu!J>Bz0( zYMX;ubev<=mU^aJ=~`I2)|SZ#w_fI=bZeGV*Lqux<aWNNmw#&h)qI|v=X2ox{rmbG zTAs*r{p*P_|KafTnZrGGtNEPTnXJa<{M0tql;%txtq|eYGaOfcx^O=i=R|Z(6;syD z4@EZlRMc{BD7q|GdE}*#=Y_>8))@)K9yl(%-|NuSuMerXFHSr0@9k1I96RLP_{Kru z4D51l+8GizZ)kU>wX7Ej^(&mjO24?Jq{x|`UMP}M>q0YPlSFbvK`1#h!AbsMk)C;e zo=O>;t7o0?sM&|3^{xB9Q=+p(-qv$Ur3PloIcvTZa|^D@c}qVMX^CG+U&folH#wox zy)TON@h^48#Ws;Sd|YRpd0u4??$bF()~W^F&uaNnt;!85nb)4D@+-E<+v^fkfv;H> z=KZ3IJon1tlxd>)!hBgW@w2$&L$AE^>}R4>r|G-iIVSE7#ps25_lkR3FY2=GZ>vQ$ zAM3@<1FC$%LA|7WlUnlQIa!h2FDlNQl$G%tMdgtpx%6_QsCxN*z3kI2RlRw?zW=QT zRnxdb*X}7*%S(g$fzH{gE~QfY11{zNJyQn?&a1#T_sNyB!(!zJ8M1!zoM;$|lMjub z6ph=j$cKlA#H!{|`N&|ec(nSGZtC5y9?Krlj|X?C=6J1FR|M7S%e!^ZSE+)hJ9LXD zQ?(oj=rtGO)suVL<x`^>;_1#6a;=UNt$`xh)^|m$E1V(Mw~mVT#0l9^b69kQr|Zt* z5!E^Vo9;@|s%!YH-tg;gwQ=xWz3KA~wYmFMz2#^?b+78t&-527cf=HT<h9-?PxN(s zU9Pd$T&{4qZ>uXZ9DXI_j<Mf3`*p(Mo;Ftkzq*s`eb%ySzpJ*+oCnRRHK*L~syBa^ zRhdg!mARS6&Br`e|9=lF*8I-l37Nw^HEf=RC$4^iTYB>ckf9-Cvzo!79UT{j$799^ z3=kP1GDKvI$RLqXBEz(raUuh?nvo(yMaGH@78xxvTx7h+fRPa+Lq^7o3>q0VGHhhr z$iR`2BSW{Ev0KgHk<lZ=N5+o?0Eqw+0we}V5RfP!VL;-51OkbK)r10xh1CQDi3So5 zBpygWkcc25L1Kag1&In079=i6V35clp+RC}HNiomgM<f(4-z0GLP&^^7$HGIqJ)GA zi4zhiBvMurDkN4`6D%ZJRue8HUP!=@h#?_EVul0_i5e0%ByLFHkjPn0=#bc1P4JND zSxxwm_#pvAB8Y?#i6Ih1B#KBFkvJlOL?VfV5{aeN1QUs-)r1p?r_}@$i6|0MB&JAE zk*FeJMdFGC7KtnpS|qks6I>*^Ruf(%zE%@pB*I9Dkr*REMxu;_8UKoNWJJ`p-sl+5 nb$tJ>bC2(TZ}dNr{`2Cc-6d2!t2#d?FGpro=jP_*=1A`!V0=z$ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Barthelemy b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Barthelemy deleted file mode 100644 index 697cf5bcf7f151ffc1c1fc4247e4e9c7e3ff01a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 148 zcmWHE%1kq2zzZ0GvP?kCG1=UB4deg+$3hqw{{KIIfPuxwH-y14ID{dD1VjD<0ZxOs JfTo#n0RWR(9N_=} diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Johns b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Johns deleted file mode 100644 index 65a5b0c720dad151ffdcba3dbe91c8bd638845c6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3655 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 AC;$Ke diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Kitts b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Kitts deleted file mode 100644 index 697cf5bcf7f151ffc1c1fc4247e4e9c7e3ff01a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 148 zcmWHE%1kq2zzZ0GvP?kCG1=UB4deg+$3hqw{{KIIfPuxwH-y14ID{dD1VjD<0ZxOs JfTo#n0RWR(9N_=} diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Lucia b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Lucia deleted file mode 100644 index 697cf5bcf7f151ffc1c1fc4247e4e9c7e3ff01a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 148 zcmWHE%1kq2zzZ0GvP?kCG1=UB4deg+$3hqw{{KIIfPuxwH-y14ID{dD1VjD<0ZxOs JfTo#n0RWR(9N_=} diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Thomas b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Thomas deleted file mode 100644 index 697cf5bcf7f151ffc1c1fc4247e4e9c7e3ff01a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 148 zcmWHE%1kq2zzZ0GvP?kCG1=UB4deg+$3hqw{{KIIfPuxwH-y14ID{dD1VjD<0ZxOs JfTo#n0RWR(9N_=} diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Vincent b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/St_Vincent deleted file mode 100644 index 697cf5bcf7f151ffc1c1fc4247e4e9c7e3ff01a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 148 zcmWHE%1kq2zzZ0GvP?kCG1=UB4deg+$3hqw{{KIIfPuxwH-y14ID{dD1VjD<0ZxOs JfTo#n0RWR(9N_=} diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Swift_Current b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Swift_Current deleted file mode 100644 index 8e9ef255eeb11515b84126d9ee5c0c6b3c72f2a0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 560 zcmchTtxH2;6o=29*AK?PHz>Pnf?;Jz(0@Rq17TML+sa@`EoPIj_O2KNb<H5MDhM_$ zYj+<yFbD&gxXlHtyq@P`5tC)Vmvf%O+kQ{DTQ050pUmhFL()3j!SUBgaDG#_7q_!V zjY`T!%b)vEF_7k=XIh0lX>a#TXX#lUSMSY}+(~!w(sW;H($D71TY6sJU&m(9Y0B^+ zGNWokKI$VoKDZXYn6U{jG3D#}{idBe?Ta{fRr7r3&aBMEcPie7Eeo6ZQ1Tl(1)Uw8 ztx(qWCf?5u|54Lvs0yhIsSK$NsUB17Lli(XKvY0<K$JkVK-9!kJrG3@O%PQOT@Ymu RZ4h-3ePjX(lj?LW`3>UA>oEWT diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Tegucigalpa b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Tegucigalpa deleted file mode 100644 index 2adacb2e500e2f9621b2debc1756d308747b67f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 252 zcmWHE%1kq2zzf)cvdlotv&6^SMPb&R2Z}MX1C*-vJy5o(4RDF=dEj#G#04fsF#P|2 zoecxS|NlETFtYsrzj^@!hmUUvgR=_|2Zu0(kYL$=AOKkiavI1|5Dl^zM1w2`(I5wa RXpkeoG_elh0=mYG3jhxjJc9rL diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Thule b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Thule deleted file mode 100644 index 6f802f1c2acf9cc73481ae86c9e099fcfc28cf25..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1502 zcmc)J%}dll0Eh84Lqak<Bm}*HC#`gKS1n6zwY0_B%`sQ;-Kn%qtxPjtH|rp!Cxfs+ z#gpWz42+Nhi^{z8G9`u($b_t?geZ!@aGU4%2Lv6W8HUecuFuz3UVqwY`{SuGzv1R> z9KPEAEAD%jjt^F;o%5A?*NjW;p6-+hbB9IZXoa*-#*3t$ESY>WQaJo&+S&41q_{J5 z>hU)sEpEHs<Ge5SMuc?w)>kTh`IFwadQa_t`CMmwyrD8Dw9I<kq7Do^ldfT(%5EBy zIlax|V8JzcsJ2MtCY_OaxoINr+mLoA7Ap5#K<7uLsQk%lePks@9UbYGo)1pp4OGcv z4>yZ~N|zLaKSW_>tUP{cK@@EZm%idh!nYcfC21p~Bp9YkcTB0$7fZTqZAg`m&FG57 zfU4{r*HzQis=Bsc*NkQ>>AfRQT(1%*6Z_;Tzf06cHOM-5tf*V@NPk?o@V~ap`iP*Y zzZ)$ZmS;udtpt7c?UFjzwn?9#m{Co|U-X56an+pmUbi&$tBWxYbZbGQYF&FL+tT|) z+v23`*wP?6rUzx`PmkytZI|5(b`j_)lb5HWMNf5xymI@iSQqwBZz%Mn*JcZa=2h7G zP-yn4ZG*?_v*qNPSLCz#{vwi)IfOz|#DWBaM1zEb#DfHcM1+Kd#DoNeM1_Qf#DxTg zM23Wh#D)ZCX`(~IL*hdML?T2&L}EmOM508(MB+pOMIuE)wKTCJ!CIPVk#H?dyhy-E z#7M|U%t+8k)JWJ!+(_U^<Vfh2CUzuvOA|d3zNLvD82~Z@WC+L@kU=1$K!$;g0~rW1 z5@aaISdhV3n$aM`u{7gB24rbQgbWE86EY}dRLHQ9aUlakMurRx85=S<OEWrTc$Q{- v$N(+P2$3NoV?+jtj1n0pGEV&O1C2B*O*Lyx@TS<E_T&Vw!(n&WlOulvI~S8( diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Thunder_Bay b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Thunder_Bay deleted file mode 100644 index e504c9acf198fbd447221f120354774e46dbbcc0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2202 zcmdtiZ%oxy9LMn=h(;GkC@E4R1B+dR%O6A0s5D@=t6m|!n3Czyz&nKE8yZ0xnqj0p zV9f@#8mqKs|3+rET#ZRNYini7YW*7>+u}hBJ4O#$tb04}v!3;+XRUL0&g<@O_u=Oq zX=vVB=KbT$u)lCQPuR=%tUdPWo3~Sc^0<+6dB4dyHKo0Qm`Uh8uM;2CW}3uQlKNAo z*J+hJcSJ5tKdgM-A@P~VREpjwsb9aS(@sX^vJ*Xe<|~hy^k=r}jQvgK@~+$U70p32 zYkh&v4EfEKi&OPg{uGmy>sMDNPng+>DQfnwKACfVLS>)*S*{s5qjHXZCfB}jRL$-1 z%yo|(RJrv(n7nO6dS3Y{bN%us^$nRXoBV?9IzRTI_<i--KlYLo{Ip2VAMTaH(TFM< zY?i>Wg{ruFg_Io3Ql-(TDQo{jEeM9pjjO*?<@xi?!m?qt=#n&3G3OgyG5(8LJoUa_ za{8>f>DxhFIdnm8es7PyrSEgO_1P_YY1><}tY^2nt@bIYYTT@<i#w#Ix=Phd9x=h9 zO*%Mwz=YD4>CmxOvwR{?uXt|1to(AR3h!!>Rqy1g+6`f;>rYa5R2IwX2gcQ!><o$2 zf2<-?ld`t_RkilVnPy$iX}#{$MYBG3L^m8BHFu32&>MP=o4bcw^~S~lvuSXZR^hj0 zb8m~<Qq(W^M8m2vty7wU#j0tdL8AE?D*9=qG|!k+&2Qw$w(&1iOaBtndgh|Ow<Fu! zH#Dl->SIRwj_do&wP|k~(AzUVFgt3y^p4o~(oxZ`I>tt%Gpkc|4j+=P-y76JgZpIX zSCwj4cT^sJH%E1E49V`NJ(Z9+Eh%yOf8rC5zaH_tc>J~Jy`*^j#G77nJpR$igjDyY zyLZ;gaKx)x6Y*-eciLNLZ?*lKJqdrmk$*9jxIOI`_7)<OL1u$Y$H{y+c0$06kSQT^ zLMDaG3Yiu%FJxj)J2PZz$lQ?0A+tlKhs+O|ATmQ_ipU(1Ng}gErisiGnJ6+-r=2P? zS7frtY?0|A^F=0%%ov$6GG}Dc$gGiRBlC9Ji6b+2+NmRRM<$QV9+^Hee<T4&29OjW zIY5$tWC2M7k_RLaNG6;%6-X|SWFXl<(t+dyNeGe=Bqc~rkfb14LDGWc#c30RWX5Sz zgXG3(lY?XjNe_}ABtb}qkQ5;~LXw1J2}u)@C#Ovmk}0Q66_P8bO%{?ZBwa|pkc1%_ zLsEw13`rW2H6(3F-jKv0nRD9IA-Qwf<RRH}+Vmm$LlTH&5J@4DLnMhv7Lha}c|;P4 zWYTF<iR990lZj;0Y14`16G<qNQ6!~EPLZVI|1_&U+uU;7+QRUHKv|%qFkD(1C=HbO F{sL6nZ3h4V diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Tijuana b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Tijuana deleted file mode 100644 index ada6bf78b2815d3d99c97d521ab9a6b35c8af8c3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2342 zcmdtiUrg0y9LMn=gpw%wq@u(hds2#laOA%z_Rpvz$O)7qi5Z#kXHW)-p%f81w$_^C ziw?_G^yKV<wIXJb{bS^oTWhSsR+x=3Q(zcHtQD2x^t^vvcGX?$clJE5-_G6d;`8?J zsIE+N{_)JU|8RIZ?BPA~wccM_x*7}Xx~H3_dMnH8-i=ny>9Fak&n6DH46gd6Zt(c~ zb>BpnIz#PmPhD)@EZ^sCl}lyGaycPGM!orJZ1EN~9-pMfr_<F$=t4Cy7@@9=PN^Sy zep8cY2i1@5=hgg?ZnNP0fC}$#Hw)kER*Smc)arP<y6#!giyQ0JlIp#BY3Vi<k>}UT z)~!{`6S8#V%3`^GUZjo+&XlO>3=@5Exx@@EGqE54E-QLw%nh$z5Z$m^-+1sNSy>XU zSJiy0;xd2IH|2k*ZjSg;$0v5G_}NL55Z0m+hCern6T8*wz8;fwu33^hj~dUZU9zV6 zag%a%qoh_H(P{N@lJ4E7Gm7U*W_*dxN*kB8q1ie+W{%1pi_+`<98>GhUe!4lK2;mu ziZr);@VdIS?GJO?i-*<iwcnXLTDxRpVV}9P{5i>8W6WK-d*tp#hm1F_P`op*=)90r z$s0PT^Dixt%`crY1z*>Quc^b_(_0{gJNKKSV;<SEq10?`P*NO|WBl8u#eX%{lw^J- zC70Lh?JIs(+dqlXrL*VMj+3+czTtP&&ejoqf8X<}to)3AptDi!@(r5@pXrd@$^GV` zs{K+Pe!^6EOQmA6)l|jjNYy~4sSb^m>Nhr-n$dtfe5^u0@<oi=)8N&QcF(HXk_27X zHliNOny>fPo>BD?lX_p_NwqI9&opHBOT+LLb0G4B9OxS`jWezCL}#~oa;Q?8n%m7& zr#DG+S-pAsg+vJo4hp^|IAo5!{yV=w;7Ebv1OhLM6A}otwK&)E9<;!{m3uEO@cA8I zvEM1;<l1wuJw<*7<2XTo-~N9wu7G_Q7&0<sXvo-*!6BnVhKG#L)eaCDAu>c{jL0C7 zQ6j@c#)%9R8L6usDl%4AJ6L42$Z(PIA_L~j88I?sWX#B*kx?VVM#hZ{92q$>bY$$v z;E~ZI!$-!C1i;ls00{vS10)DY6p%0=aX<orL;?u~5(^|4NHmaexY~Fi0dchvK|+GW z1PKZf6(lT3T#&#ZkwHR(#0Cit5*;KwNPLh0x!MRJAwpt=1PO@}5+)>0NT85NA)!KI zg#-(U77{KbUP!=PZN!j}x!RZ^K|`X3gbj%s5;!DsNa&E*A;CkUhlJ17#t#XgtBoKM zLRT9@B#1~9kuV~0L;{IK5(y;|OC*>`G?8#3@k9dZY9oq-)YZlm3974&DiT&Cu1H{! z$ReRdVv7V9i7paeB)&+1U2TMs5WCtKBSChxQAWay#2E=R5@{sVNUZUHAM7w&^K4u5 UBwxBG&6ASkOHK8pdQ!sv0^LWd&Hw-a diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Toronto b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Toronto deleted file mode 100644 index 6752c5b05285678b86aea170f0921fc5f5e57738..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3494 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 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Tortola b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Tortola deleted file mode 100644 index 697cf5bcf7f151ffc1c1fc4247e4e9c7e3ff01a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 148 zcmWHE%1kq2zzZ0GvP?kCG1=UB4deg+$3hqw{{KIIfPuxwH-y14ID{dD1VjD<0ZxOs JfTo#n0RWR(9N_=} diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Vancouver b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Vancouver deleted file mode 100644 index bb60cbced30763c08b6cf73554c8d6651ff387d0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2892 zcmd_rZ%oxy9LMns{^5_3Cle(?JE@7FBA_UWW*Y8_iKtvj%<xYF!!%Uvs%2=4R`!oW z=ATy4H}XNQ5*@SIOonc`T2TpRqIM%oWgw|&iAwi&-oK|k>S61!b6&sk{JuY)g+&F) zu78{!_CH)st-XBr+hU)}gNNn4Ly_j|t<lmj<ofD{rNdOCw~szCHB|jD|EfNzTh)&# zjrx@98`TtfKsPn-Rj2*O<xHJXXMHvD)1HrwuXelqy!Ca{T)AF;DOzpLmFCK?8S~6< zd1-P!ZmhZBUZ5}bovT`6C+e1tF{(8rMz=OZs<sP$eQEy<)qbp5|6b9gE?0NSl{JUd z)pDP7Y(8SH71zo2#UGeIva00IDKD5Cqsydoc$K=@r$BCnmZ@8v&+FSQ1*+>*zW(dW z8Ondqtpgv%E7z_#9rRLf6}+LB?zU#Q>Ao~pddv+sJ*S3ANa7_Es@o(?eQUy9^%8z% zpXt?HExnuSRYYBd-0@kp>a%CBR&Q0PJGUC$cVmgVt7xt6mpflYW_Wb}3FFm(xN$ma zaJIQSEJ{ZQr<mxDv2xG30VbxQzYIKb(+t|*DfhmA#%S*decyA3&ET8}J!HjcH8kb2 zzJKQDYFOlP9UEV%V*TwB7rsTs`M#6*)@5o$?S2{ASZYR9Zj*$XC1!N#Q<AuCnn@~r zLnoIEHDlcC^w{j4CM7mUk4tVb<3mz)YD^E6dNEp0xP4JgJl3Vt&U~dN?TeDhhdxpd zl;4smZ@;D<EIun!%l4RQS+(-e@>fjyXp!mZtIYIkjoLlxW#w)>pfe&?s*IYQdS?4< z_3%42GVA0DleuZT%>Hzi$y&5t=Ilr?b0_7>Jg+j@F=^tN-(fsm10^TrgvmKSQ7;&D zRW0};M(6q))xzC={iyGNT2$7oAFJJ|@|GXfiz_#(C7C{1`r>x8Y*d{*Ubx;YkEoJ- zcdp5AFO$O9G*eh#AVnbqP0=SaWW|Mmd16PtUip2DTIF@?C#(IcI44f8E^k(A#`V%` zi;t?3$acLhYqwe#2orB=o$>nGWJ6Sy*-%?A8#~L))0Nfo%&7viskB0#JvhUZ=9S3i zUGXM3D7ag9`}{Zm0)bcGbh!e7cTG_DK%jh!E7bY!?YwGMrpGlW-QH|_AF+3i$NtJ) zt{~^}{EIpS?8%$#y@XT(DFspsq!^C28b~>idLRWsDuR>*sR>dPM_U!7EJ$6D!XTAF zN`uq}DGpK{q&!G{kOCnULP~_x2q}`ItrAiuM_VVPP)MbaQX#cMiiK1QDHl>Nq+m$J zkdh%aLyCq}4JjK^H%D7Iq;g2<klLYBJU*x%$CeMMA5uW1f=CIG8X`qRs)&>ksUuQI zM_Wmxlt?X+Vj|T<%8AqyDJW7=q@+kqk)k41MaqiQ6)7xISw~x1q_#+Lk?JDlMe2(b z7^yH)Vx-1Mk&!ARWk%}kXbX*0+R>I8sWnn;q}oWik$NKqM=Fk#9H}`{bfoG?*^#;< zg-0syXiJaO9w|OjeWd(I{gDMgRsdN7WDSr-Kvn@+24o!^?Lr_c;b@lvSqn$I7|3cM z%Ym#1vLMKcAWMR*39=~2svygPtc#;v7-VG}?b0A?<7gKLSsi3~ko7?p2w5RyiI6oy z771A;WSNk4LKX^HDM!0h$XYqt#X?rg(JmLVUdVzWD~2o?vS!GlA*+Tg8?tW5!XYc? zXqOIIJ4d^C$m%)T<wMpFSwLh3ktIad5Lrb0f3IS=9m`ZZnj<sEBqS#!j?7F-N=Qmb G4F4NPN4LZP diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Virgin b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Virgin deleted file mode 100644 index 697cf5bcf7f151ffc1c1fc4247e4e9c7e3ff01a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 148 zcmWHE%1kq2zzZ0GvP?kCG1=UB4deg+$3hqw{{KIIfPuxwH-y14ID{dD1VjD<0ZxOs JfTo#n0RWR(9N_=} diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Whitehorse b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Whitehorse deleted file mode 100644 index 9ee229c0eb82c6aea7359e0b38677264f3cad8ab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1614 zcmdthNk~;u0Eh9XIix5Y$T_v+lv8S%vo@I`np62SpJ@|PC`Hm>n-T>HGQvYrE;2hx zn`onm5m-V&LAa=V(IP`42qTcnf-J??`7X3-6}0L;&ix(l%EkY)H?$l{xBc<>m@gcj zCUdyQb(+`Uy{VC#6ERvp_Zt}+p6;Bwm@qOO^Q~?AP=@@T)~*&4hQ(6E0kNj#qzrJ> ziojC449d+G!HHQiB)Ue0`h>_Z_e>SGkfGPU3s&LNK|12$4;4AOsMih6DA}GYqq-ib z=sJHH)B0M(W`2@!W%tGUz!x$;X;8$k%<DwoPLVkKOecLjERrWj^#*5$N*V0asbdFK zTE`i^v9C~VI(kK>pNdtROHRv-8ZVU@UnjHDKd5Z)9GMgDDRSn*WbV?O$a}IZ^Jkul zf{_rtW#W$5+WS*)yM9@0Kk-KI=)SEAt0wi%=1Zz5P3z*K<Er?pQ<kLkh!W?xEcHJo zO2_(T*?gtgH87^jU$v@=b60ic-Evjccve?mOI5oI9C}Z?P&MKC+FrY$?8_0lF7u_T zd!HxkBfp6H$Klek;uH<HR^-0fanacQRyIxci~Y@y<blD)&+cyKx5~ra)7{JaU;kFS zTwTpJo6FVP>E>bXZ8r18-2JS#aJg<Mw*c<8Q0pGS+ZI(`VYfMo%&9SFuQ}EHZ9Y_+ z57ovBBafT){(Z6k#nN2nIe(#N09hQeI%Ijs`j7=8E3`CAMAnEb5?Lkx5X(f?i7XUZ zDY8^#t;k}L)mob6BI`vKjI0=0GO}i5(a5TiWh3iG7LKeOSvs<IOS5=n^_FJ&$oi22 zkP46zkQ$I8kSdTekUEe;kV=qJkXn#pkZLSVIY>Q7K}bbNNk~mdQAkxtSx8+-VMt|2 zX-I9BrZ}WJOH&?FpQR}fsSqg<sSzm>sS+s@sS_y_sT3&{snyaHi&SfA%0=q6GzB9S XBPAm>BSj-sBW2_NRkyE+KHK*fniI0_ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Winnipeg b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Winnipeg deleted file mode 100644 index ac40299f6b27043e8f2454ac594b0ec184c1a237..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2868 zcmeH|ZA_JA9EbnMHxNb5#0UvYD~2Khis1`osbi1`>Jd@M)G)*{9^X)W!GDX1ep0i1 z8Aa--<yxV0DQY8Ab8h7vq9kdAsN_`gN!>yvPWN?JTU&l{>tnyO`?;R;d^qQPIoIW# zp7&au{A+&Z35Ojthx=Y?E~TFP4W&m9rk7Rj&<_vZb&hNwsYla_-EY^n>FNG=oYS*9 zyESX)%9+VC-Lq59N^Reh?)UNg<(yQwbwS&tu3@8l-hABo6WQ*C`Yrn7t_@CoRiXa0 zZlTjqmZcZ-yiQ|LqFzcK=3Jf;u2&+1ou;Hw@^jCj?$wAexq7R&d(HfsYt=38^`=I- zQG3j7K7LGo+4!Y<JHK4-#Ljl_c2CiJ{snTcC0FiW&6L)2$@2S&5z<yUP<)?+ifj!O zPf44!TY6L4F9^{Nv$|-<^j7UOx>@~V>eavRDec_jum;E;4RCjAmxfK+weBkkJiJ7^ z9oQk=cfBJ$w!JNntXnKS3+KqAc^T4cT9O1MCrIz%k@8q%hy?c=r;q!$N=Um14Y?Jp zeHuG!X!SjP;_K@gw&#L|?>MP_3%bjbZ&hf&DZfhpdEd!X@ip>v%IES-&=(RhV1q=o zRcmCxLW!*3s{^iiWnk5N8dc-ypt7YJy?2rhE}Et>n}%v^Zh^!t>a9bPGG*wb7LAV> zA;aQ+&}aQZC85u6lF-y9!|&J0h~o`1^86tgRne-6hdz+!*4OLvrK@Fh{$YKgxKv+E z+o@x6R_WNm#X4^6L}%RX{gO0jzME9DO_BrC+~mD0B&9jled+xzI=*&-le)4{C+v%H z(z3HOeREG|;;2NOwB(L6IW%0oQ)(S=t4A~9E1irhVUihk#?AajWLn!kcY1lFWYuqV zvx|?(%T>$W895)zD`na4%+w<~tEAAGJ*Zq?&CPOh0@vuAq(o;<^IXl12zPQ%rf8m@ z$I1IFO6N6Qa$et@EN`6hx$_GK%9|Az-TaI|an>Jo7sTI`h4~-3i-M|UaaxJHxUE?W z63U%|`ct|rc#X5HYL6DS%ypKRZPFFzQk<1VOLSFblv6Zgs;=JJ&1vVcul61Oy7}|% zgRUJr{kN|NeaFK*^ZCkei1>U5c6&Pbe4lO?e|z86UVHrW`S?_?j2UarWOJsPlkPSD zZV`{iV<F;w2s8N1axU+F7h(uYV+n{UAhv)Q17Zz`IUx41GzNiK1Y#11O&~^rSOsDh zh+Qm=VIY>VG^T;r24WnDbs*+}*au=Dh=m{~g4hURB#4zDW`fws(ijS2DNAE2h^-*T zf>;Y;E{MG#27_1(Vlqo(Gl<b3R)d%gTDx(B;h3=;!*mSWF^mVX9>jbQ`#}r{u^_~R z5F1(=BSNeQF(bo{5JNI7$uK3umJDMutjRDZ!=4O-GAzn4Da57>qgooPLd*)WE5xu6 z%R)>Gu`R>65bH9`%djuQzzhpBOl)av3^B5$u`<NW3_C*%4Y4%D)DT-kj193i!`u*i zGYk%~IK$)+n=_1VX{^pLJHze_!!s-oF+Icf5aTnf4>3Q){*VGdDgY^grKtg<2$rS_ zj51i7Ixq?WsRX1HkXk^B0jUP09FTfI3IeGJq$HN6CXk|7nyN6$VrlBaC=8@BjM6}A z!zd1<I*jr_>H{edq(YDqL23jklBKB<q)e8kPLM)bno2=R1*sLISdeNl$_1$xqhOGV zF-iuh8KY>HrfQI~S(>^*3TJ652Pqw-c97yhss||_q<--K0{&gV029YyCX!L9L!#rN PW1>=HW20lEV*>sFRXeOf diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Yakutat b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Yakutat deleted file mode 100644 index da209f9f0a07625ec83d4ec84917216347f5687f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2305 zcmciCZA{fw0LSqQ0v8C165>IklMf(I*TYrdQk0<(ArcVRn-Ezjc88T<useK!xTPbv z3TK<c+2A<GR$I0+-AY$r=~`PRBiwozMd{Wom#+1+isW{_r+iiORrCMfIiLUTef|4- zo7x_CJO1@J%`Y6D0dx4y=rh;p-HY|)f}cAkTb7C0V{2sSRgZ8C7R#{b(?oc8s+_Z> zNJX?1>d5*O6;+n3o$?Rme6e1~Bz&P_4xf>+Ka8mxz8=+apHGSScZc<j$4A9Yue~D^ z_797jcMr*1wg$!AwmzBIxIrXUt(Ui!REXs4a+xx}MWx1M%Czv6DlIoLA??Q%dfxd( zDt&UHzU`z_WgLmpw;%jYi9m_GBY0ZP_sx?FHhn7=7G9ByR(&WklfIH!Ij@VX*%_T3 z`;y3>{!-^$>=3zQCv@J~7gYYxLG3!aSuN>(PRp0;RDoYfcc)t|t$bE4Ye-auS*^0j z{i`Z=-X}fjbA{)^Vp%fti@5WHSb5jfr=nD6>bu`QF7DYAt(PA-Ant9ysLOV~rB>8_ zq*u1?SLI9I&=uv|RmD%|WM%%Ks62a0R>f}<RYynUs!PqH`jz+e>QA~=&5lF*fj65} zZSyW&x35&ym-_XCfeh7<UZuT0hw}cJt9^y%mG7JT<=TvpSo?mCY@9tOnnvQ}!_%ik z^Ullik+Bi6u605_I@B*7tNC8H^dC~|^T+iD|1Q-Uul2@CzuI_dul8qEDgT)+-R8_y zZHIk&(}j5T#J*1X<V22mDzHXw)^VcUS1daQE{iQisq*Re3DKD}BfDykh^|nw4tT~@ zVET96ouXCu*p%M-+g`P8XjE_itV`|a9o9X^e5!X{P(L&1QDNb8!XmEuMnzu7*Wnls zIvk-;u)`4%3JvsyMcX^h-U;?jwEw2AuJJk=8_apgoH}#Ly^gYKdzoL&6UOy7-v1s` zwE3IEv&S61GeYKBe)7u4*wbHp0vQ)FFsm6E+M)5m*m%s~fYBktL&k>;5E&sdL}ZLs zGe~5VRx?awoX9|tks?Dy#)=FU87(qgWW30Lkr5+9M#hW`8W}Y*Y-HS4GjOXJIWlx) z?8xAe(Idl0#*YL5i2xD;BnC(jkSHKwu$nj^fv}oLAfZ5Ffdm7I1`-Y=9!Nlth#(<B zVuAz(i3$=HBrZr`tR^x@Xpq<-!9k*fga?Ta5+Ec(NQjUaAwfc-goMdz;)DdsY9fV% z%4%YT1Ph545-ucONWhSYAt6Izh6D|X8WJ|Ei5n6)tBD*EI;)8t5<Db&NcfQWApt}p zh=dS{AreF+ibxodI3j_xnn)s{w3=8V!L*uaBH={hi3AjhC=ya6rbtkcs3KuS;)(>; zY9fn-)@ovl1lMY!i-Z@6FA`uR!bpgb7~?-djtGyu=Ie~Qj_=hX_n4mkFI~PGW@~I& Zb%VErZs*l3b-7(Kucn~DRp64be*u!YOXvUq diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Yellowknife b/venv/lib/python3.8/site-packages/pytz/zoneinfo/America/Yellowknife deleted file mode 100644 index e6afa390e879f97cef351e382ae62daf183e8d77..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1966 zcmdtiZ%h<)9LMo5V5v9M-)0yJnrV7M+;N~JkeL;9Azc`rh(wqM-cBn>-OUW~*TOL# z@m)FAX0n_%AGDIxwVE5vHGEPwcW$je3s-4vmJO>-HkIr5{yptckJ|dWyO(2QJo&vp z@s{Maa{0&I>3+h8+v`63f9^<ezI@)FtLepmb)~oD%Z<{Ou8Cy_#%Cwn&0U+Kl2`Y* znNw9HcNZ-)`HO1p-01-`FFR=G{jpRFew=O#)6;bR*<bB~53lMyN6y=YsrlyK*G||) z8!~3`_AlhViXY69wI9gRyw6OqSS2`lNs9tIrD*J|7GI6a{Ub-U<YJc%4IR+%sYYAc zlhDYUD{NV!*Oc#?W0yy_nH7x_wj%h1d7%7TyK-u=sVul5mA~Ygs+-?P^|{~8gWsKz zRl@;&=*(eRJ@A`8d}zO{>HJb3={;m0Z5Y<a+V|O-(l@lWX0xsRbJRpb-4eZc+|<oz zle$y=X6>~#Qvde5`s7!wHrCyzPkpr7Hnb*n-QYs|^s0JoOl8~kg&~b^xNPIMW@%H! zIooul#56DXNt#DznoX0V(sFFvJTrD&T6@#x*^z!}Yd>u^5ABfWVi$BvU!UC?I;qbm zlD2)uLG6gv+m34~O$0+WalToTQ)k)a`_;Pr=j(RI;70Spg_-hVs>-}{Vq7|#3QX5P zT3)WWZFY8^mR)(5%<hIk**$qvQ<W!eYV3R6lYh|e8TnLSnMm2aLr3)0ubXXm&+EGH z<7(T})}i~~DzrIS**Q~k?)VS>@!Ui*nfKnwn&Q8wWip3Vax<AvhO><SNnR)tk=Vw# z#MZgbdiSZR;VbTbG0Xot-|>I(tTXO-+Q{=pp19XNbL6Qb&z(QQlSiIC$J0liKSu&c z21p7>4qlf8k_D0mk_VCqk_nOuk_(ayk_|^XNIo11AsKmHN=Qy#mlTo}M_Nc;NMcB4 zNNPxKNODMaNP0+qNP<X)NQy{~UY8`2B}bY_o*aoHnR29x<jRpOk}Z-hk}r}llCjsN zjO6TfNh4W%UD`<A9El^DBdH^~BgrG#Bk3dgBNKqkfY(g{G6!Ba3CJvX-83Ncz%dcX zOmIvEG8Y_^fy@TSbRhGAOb9X~$dn*+;&qdP%!=1d3o<WWH!;Y}AX9_P4aejlv%@hx z$oz0j5Hdp?Q-sWs*G&>KOI|lk$UJ%7L?JVUOcgR$$Yde2g-jRzPv$G&hHa(Ww368J RaCtaV5-TeUmxUvNzX6=<+*SYp diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Casey b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Casey deleted file mode 100644 index cbcbe4e339d934f57725542db534641292fd077c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 384 zcmWHE%1kq2zyPd35fBCeULXdsdH%_rY4Ezmrr_Ow>Vx0PIST&HXD38(SvN#2;TMSB zDdG^*E87q|&D9_-`6xqt#R8l9|Ns9pGBGkS12G6PflLE|f(8Z_28LN17&wsGx&{Ue z+6ER3+J=T8MT`(4gaiiy?fVaMBuFR7p&%OMSP%_zFo*^@8bpH}4x&Mh2hku8fM}2> eKs3lBAR6Qu5CC}yL{r66TsA;Y+UXh^asdDb$3#&8 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Davis b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Davis deleted file mode 100644 index 916f2c25926bf444b7c366110a29a3fafb17fbc0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 297 zcmWHE%1kq2zyK^j5fBCe4j=}xd7jU4VEE>KU*MnnY6h=cA_m^me>wQATxH<z{QW@v z|Ns9P85o(EnV6YDnm{0_0Hn_?0AvD)t!rSwplx6d#HJu=Mi34m!G53>|3Pj5(I9t# mXpmb#0OTGJ4RRBR2DuAFgWLw9>w#*?aUYir(8YGT=3D^3yE`2K diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/DumontDUrville b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/DumontDUrville deleted file mode 100644 index a71b39c0046b02c20e17d33d333e5af0b01eced2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 194 zcmWHE%1kq2zzbM_vP?kCab-_g!#$IPgy%L)4fX&3|7T=iWQ6JLS-`-eYhb{jZD_y{ lLV}q<WB!B81<@e0K{UvGkh%3hHZD83Y=Ab|=^7ev0RZueD4_rV diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Macquarie b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Macquarie deleted file mode 100644 index 9e7cc687d76b00d8f112245d5c5d2f20a2a61814..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2260 zcmds%TTGU99LK*e@Qxr9Er)<YY9)s_ym&xJ#Y2E#BQahGNRbdZSSENtGJX5athbAp zW^S@<i8Mwx4rJDBV-eZrTEl9q?4UX7qS48<HOnE=^LcFRrkn0spJ#hM|NWoa=lk(j zH#aQMKN9}e?P159r<(IR{#m=dI+&@h;F;QsQB4|uuR}Km0-88qrJHU2HrcyWsyJev zV1hzc^eMC@*TSaEmbY}4d9USIc;<wKe;#iU(N`?u%^MbZb=Yn{5vQmxzR{GxxTc<c zSJ5?>HLbH-)ANRONBcqDnRrq&DjPK8=Cg{)Dbmc)b&8!^Z?WHHDc)0P@x7aE)@ZWL z4i;F#aHJ(RCfQxb1~jKCU~}z)&0Bq3cQ^m2d*<!ey~QJ%AF@eFDSb-%?JXt$JZdSQ zb}Dt`oZWY3uhLHSSo+Zo%IFAM=B_;Xwl!PU#%fzo@w^r;UuKK4o3uC~(XwOKDtkh< z<XW0?E`4jcy<>L&;QO|8DAktrjB5FbD9d~9oK^&Wv6WkTw5sM~TU`*;19=0MpYggC zBp$Uw?}J(sep+jO?^e<GFRS?CL9IQ%TP4Se^iVKY>-MCow58nE*B08trAw@AWwQBw zaaKMj(ki0Itzz;gd*te6tGsf-sy-UB>Y;vn^z0>Vcw<BxJKs^w3w_$u-lf{6m-JZW z0o4`l)aIOe)hCy0OKhPUrng$7r_LIGEwiT4d~5z>v27imZ;zjzX-}NI&9)uBZco|| zw!P(RYuOsE)~Y|Wqj*d^bHCEAln=E#ZcuFzr_^@+HSHNYr1mdOPkqp;y>Hj)>46U0 z*B!9^N48twK&?HqW4(DoLc=`X(ErTi{LU^fb}3AHrQZ`F-8$d8|NAE0=hLc!GQac6 z_w&)?;QtrXnRM9ajS*%-m>FTFgqag&QkYp`riI;kabRNL%nUI#U~a(VFtY=u=h~Sc zW`eGr8DggB+L<F}l9*Wn(*))TOca<YFjZi#z+{2h0@HQv%omt2Fk@iKuAMmplXmUQ z8Z&LoyfG8U%p5ayVD6a7V`dLbADBOo03ZWE3S2um0Fr>o0+0qw9)Lt(G6AFllM5gj zm~3Fu0ptUd5FjI%l(=?sf=LRH6--(%dBG$GlNlg2nA`x#!DI(W4<<iAf-o7vqzIEE zAW5#BECFc(@&qIb$P|z&AXh-LFxkSS3zIKQ!Y~=bq|CLGGfdJjS;M3alQ&G_fXo4@ z19Ar>56B*nJ|KTU0)Y$yDFkweNup~fi<mTG@`y<!CX<*{VseQ|CMKJhbOQMV5(;D# zNGXt0AgQjMtO98T@(Lst$SjarOl~pB#bg)%57Qe-jMKAx<T$M)%a@Ur;Y%x7gfbUK F{s~?R05kvq diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Mawson b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Mawson deleted file mode 100644 index b32e7fd6c6a3faddaa98dec06b88dcca3574486f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 199 zcmWHE%1kq2zzdjxvLMX!NWrMV>z0y3{r~^}8JU=1nnDs7SQr@G0vI@S4Gb8x4a|Vp flp%x!gMsG#2N@1B5o7^~Cdv{n8=zHox~5zJ1<D+K diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/McMurdo b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/McMurdo deleted file mode 100644 index 6575fdce31183d8238b18f2f30ab5b9227c7071c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2437 zcmd_rdrXye9LMqJpwhVKWemws!@O`gTvUW2LIninl6fRN8GVz42MwVlp$lXgnPXVf zmaRD|$pO<6kpwLTF@#zdvNfreebbp|D>PSA%fg=bv;M3<`l~;Bp6&Pg?QG|tvwhyj z<t{CbH~#jy;jd43T5=!1(K^~X+CBT1ZZ2rAK4%_ScuqPB`ptL3`{iI_tJyiKRk}jz z&8{E&^w8BZ^YBN_`tDGk`QBNN9(nt+=jibdwR`K3r>AMJ9$R<V)4OS_9?#wBdB3Pa z`<%6&6WI;YA1I!IsB#&&Qe&R{>eW=AkU!LC?{4+IxLf=he^>vZV;WF<S_8Y9G^nsg zZ+xXr$ENJkan&U{KI~bYP>`h)Mv65!F;auiZ<3IynG({!T0$KW656~-Zu-t&CT*T2 zH}_nSuo6F+{Q96w$rzTY8{6fUSRV~9{Y0k){h+rx9Wvc(fzAjxD>Kea)0xA4GOO2H zBR+1H$UWf__0|@Nt{)@LhP4v2=Dfs~<w)G(4<tUnRA)!*kvR!VbgplMBm_rm!q2Tb z?{bhPeqOIhUtH4L4wUKb-GP$4Jx}jw{7F*Q$LXE5Cna@duFNm&kOj%HvM}XkNt-lI z(!;7H{n{^*G2)g*SL!tLbh2cfD$&J9!(>TkmS#5^lCvXHb8F5>UR8kJRXn0gB|`4b zP+gYlFRtmmx_t5l$@hL!^RExeJ>Ng41>d&IiW8=~yI+!f_tnYDmNvcbg%T-zew*H3 zo+V;d>H~R^vMMuQi(&%g!I_D=I`E<tk6kXsSN*i)(mXLw4QuIV6J<^3r@FT7nmn{) zzm~oDjjXHMuH_ZoQXy^f@QSbXk<@LnKIw>7PN|efC%&c|jC|Sf>(g4LiBkP#kv`TF zDvuvZ*C$#N^vPYTq-INq);^OaPno}|m&0q+KfT_g$NZ<SVKfa{b1?P|I7S=B8(oHv zVYKvcKRD<J<Zf7Z&g>kQk?UT@Vc*hRe9v$=4A;Nd-gWDl-<jQlY!KNYvPEQ%$R?3p zBHKjviEPx?+9|SCWUt6(k=-KOMfQtq7}+thWn|CDrjcDE+eY?{Y#iCSt+jPz@BB1u z-qzYZvVCO#NCS`#AT2<8fHVQ=0@4Pg4@e_ytxh1Vu(f)DG{e^F2GR~&s~<>1kd7cN zL3)BT1?dXX7NjpoW01}utwDN&G{@HJ4$>Z^KS+a+4k0Z<dW19y=@QZ=q)$krkWL}3 zLVATX%hu`^(k`T5NW+khAuU6ChBOW78qzkTZ%E^i&LOQsdWSU6*6JS8KBRw01Cb6Q zEkt^VG!f|{(nh3@NF$L>BCSMvi8K@GCelt@tDi_ik&YrQMS6-f73nI{R-~^;W0B4x ztwnl^G#BYE(q5#$wpN3Y4kIl_dW<v~=`zx0q|ZpBkxnD6MtY4j8|gOEZlvEx!)>jO zBP~aIjx-(VI?{He??~g3&g1`~^}hTCM90PFy3<@yIZ4jB&e*7&InFp|Y|L!mKLIzD B3|asH diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Palmer b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Palmer deleted file mode 100644 index 3dd85f84ff48fb8553b4a964659872ae1fb7d33d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1418 zcmd7ROGs2v0Eh8=$4LiGDqN)YveI6Yb##1;=Hui8P0P%YlrV^bNH<E0+60!1l87Eq z)IzWaM1<+F7P&AwR3ts1M8sSKK`~GS(gV}9Zs)t^s#UaUE|=fo4h%EQ_pja6xIf+c z<K;6?xOs)l&3XR#rCZi`xKmBU73+zCAu;*&u>3xhrKTQc>goQF_|a7(e|BUF=TwG_ zx>lil$<3D+ihdOzxm(8%?o<ikLY>$fREu6T$i?Rp)smh9xwK_kEjyDWlUgIh@@9`* zkuxP$R=tzS39m&;(9$WB_r<Eu6MFUN6|v^qBfa*)J+*G+y7ph~RO|1y>(sVmYQx1Q zy>ah8C61nuX+@<feNUqd<d299St&DPN<>y{pUjRNRzYi?3_kOTocDg6d-H?X^dwg2 zoqR6xZ;a`JrfyN#KB#5rsoH$tjxGvxsp9erx+LzjDowjBOTV<JvIXa5*_cO^e>x<$ z^f!x&!FpNQXQ{2dxpLd%C{b12rnh%=tLmarz2nGPRpTF*p@xI1Hs+PA%MOdWo{ze| z__%6y9LHnNUfu|=Jty*?FRz#X%Ca11KwDnN8GdQ|9OvyDdoE|ooM)cQzH9kXg|JdZ zhPeag{vCmB&wPxr_Ak;fzsMmESCa^miK|Hk$puLU$p%RW$p_tpIGBw1GNgp$gd~Mz z<!aJG@<I|rGDA{Bazm0svP05C@<S3tGDK2Da&$FGB3UA7B6%W-BAFtoBDo^TBH1G8 zBKaZ-BN-zpBRL~UBUvM9BYC@;#F5OA)REkg<dN)=^pX6L2_Q2-rhv==nFKNmS2GP{ z9<F90$V`x_Aag+`gUkk*4l*BPLdcAeDIs%0CWXujnU<@W7cwzyH3`j*%wzwzGmFkM J11tzc{{lwWnyUZ+ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Rothera b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Rothera deleted file mode 100644 index 8b2430a20eb481b488fccd5f1a966d06bfa214b9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 164 zcmWHE%1kq2zzdjwvLMXC%cRRt|NsAgMn;JG|NpOEU|`WTFksL%FlGoL!6cA=kZB-* N+e9uKpt*L&TmTbL6~q7l diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/South_Pole b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/South_Pole deleted file mode 100644 index 6575fdce31183d8238b18f2f30ab5b9227c7071c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2437 zcmd_rdrXye9LMqJpwhVKWemws!@O`gTvUW2LIninl6fRN8GVz42MwVlp$lXgnPXVf zmaRD|$pO<6kpwLTF@#zdvNfreebbp|D>PSA%fg=bv;M3<`l~;Bp6&Pg?QG|tvwhyj z<t{CbH~#jy;jd43T5=!1(K^~X+CBT1ZZ2rAK4%_ScuqPB`ptL3`{iI_tJyiKRk}jz z&8{E&^w8BZ^YBN_`tDGk`QBNN9(nt+=jibdwR`K3r>AMJ9$R<V)4OS_9?#wBdB3Pa z`<%6&6WI;YA1I!IsB#&&Qe&R{>eW=AkU!LC?{4+IxLf=he^>vZV;WF<S_8Y9G^nsg zZ+xXr$ENJkan&U{KI~bYP>`h)Mv65!F;auiZ<3IynG({!T0$KW656~-Zu-t&CT*T2 zH}_nSuo6F+{Q96w$rzTY8{6fUSRV~9{Y0k){h+rx9Wvc(fzAjxD>Kea)0xA4GOO2H zBR+1H$UWf__0|@Nt{)@LhP4v2=Dfs~<w)G(4<tUnRA)!*kvR!VbgplMBm_rm!q2Tb z?{bhPeqOIhUtH4L4wUKb-GP$4Jx}jw{7F*Q$LXE5Cna@duFNm&kOj%HvM}XkNt-lI z(!;7H{n{^*G2)g*SL!tLbh2cfD$&J9!(>TkmS#5^lCvXHb8F5>UR8kJRXn0gB|`4b zP+gYlFRtmmx_t5l$@hL!^RExeJ>Ng41>d&IiW8=~yI+!f_tnYDmNvcbg%T-zew*H3 zo+V;d>H~R^vMMuQi(&%g!I_D=I`E<tk6kXsSN*i)(mXLw4QuIV6J<^3r@FT7nmn{) zzm~oDjjXHMuH_ZoQXy^f@QSbXk<@LnKIw>7PN|efC%&c|jC|Sf>(g4LiBkP#kv`TF zDvuvZ*C$#N^vPYTq-INq);^OaPno}|m&0q+KfT_g$NZ<SVKfa{b1?P|I7S=B8(oHv zVYKvcKRD<J<Zf7Z&g>kQk?UT@Vc*hRe9v$=4A;Nd-gWDl-<jQlY!KNYvPEQ%$R?3p zBHKjviEPx?+9|SCWUt6(k=-KOMfQtq7}+thWn|CDrjcDE+eY?{Y#iCSt+jPz@BB1u z-qzYZvVCO#NCS`#AT2<8fHVQ=0@4Pg4@e_ytxh1Vu(f)DG{e^F2GR~&s~<>1kd7cN zL3)BT1?dXX7NjpoW01}utwDN&G{@HJ4$>Z^KS+a+4k0Z<dW19y=@QZ=q)$krkWL}3 zLVATX%hu`^(k`T5NW+khAuU6ChBOW78qzkTZ%E^i&LOQsdWSU6*6JS8KBRw01Cb6Q zEkt^VG!f|{(nh3@NF$L>BCSMvi8K@GCelt@tDi_ik&YrQMS6-f73nI{R-~^;W0B4x ztwnl^G#BYE(q5#$wpN3Y4kIl_dW<v~=`zx0q|ZpBkxnD6MtY4j8|gOEZlvEx!)>jO zBP~aIjx-(VI?{He??~g3&g1`~^}hTCM90PFy3<@yIZ4jB&e*7&InFp|Y|L!mKLIzD B3|asH diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Syowa b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Syowa deleted file mode 100644 index 254af7d12f38af0abd6302a4df574e45b50d1805..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 165 zcmWHE%1kq2zzdjwvLMXyd}9Pd{r~^}85v>fwG0?obPWs`v<-|ILP#(PXvlw%X&`{x NL@pbkxpun7TmV+`7QFxf diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Troll b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Troll deleted file mode 100644 index 5e565da2f6b138b70179cb7e72347163ab44b6ab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1162 zcmc)IPe_w-9LMoz{(&({z6Ro<KL!#MO?@_zE^6SP4a-^PGSkfd=+s&(t;AKfLl6-n z-$M`{f})U!7#*?>9ioUZkkLh=Lj(yL5fW5L2U)-OucN2v&@+B}J$nv2JfC;8b1)Wk zR$Y1K35Tn}9PZcDtqnVMp?t0HT`vt=7PYZ{MMC*+G+g>o!b=O%l>0)OGBdJk{;up! zKal3x=Ng$9mzIZjbWb87d&jS6>w)XKFW#qZJK`E`4(tBn7H#)$)AnUoJBmWm@ot?S z{JB*+pZw6SIiDQ5T`1j;zslj%cj>v2kt02Ga&+vA9^3g;j(5*$Z^@+e)uc7%o!0)1 zs{NmD>cGmd4$dU?#D}P!yx*nq*F$pZT8$>A+T`>=iJrMyB}1*%G8`+Gvw=-=uJM<g zFLY$2qDV)+eUj0FWgUI{N|H<O^}?emxtMvTmnL88So)S;PTtehL`qZHY&O@E^RJ&A zUNF~&&7ME++iQP%%Usvl?gq_q9mnIbC;As#@h|LUHJc&3A=@GQAsZq)TFsWoo>sFd zvMaJJvM;hRvNN(ZvNy6hvOBUpvOm%Q(t*{qfb?KBO(0z$Z6JLhjUb&MtsuQ1%^=+% z?I8Ui4Iv#NEg?NwO;bo$NLxr>NMlH6NNY%MNOMScNP9?sNP|d+NQ+31R?{TXrPZ{F w^ocZzbc(c!^olf#bZh+&?fR-s$+fQe4%U_h{gKM@s&cm?;Ex1cdspfE4Vhy68UO$Q diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Vostok b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Antarctica/Vostok deleted file mode 100644 index 728305305df3d82fca7829ff3e9581583758dbeb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 165 zcmWHE%1kq2zzdjwvLMXyGNQAg{{R2~jEpe#AqfmDx&{Ue+6HC}AtaatG~_?XG>|#C OP2{oxnro+P#svVn4Hz*1 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Arctic/Longyearbyen b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Arctic/Longyearbyen deleted file mode 100644 index 15a34c3cedb7c9ca519c195f5ec0ce9d8d1885a5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2228 zcmdtiUrd#C9LMp4h!iXLF@<9RLLs4r{0IL8nH_<d97{PFsRSw_7EzvzL26Vw=Nh?h zja80ZR*qRS?1J(Ft@X!73&~8@tXx~HtTZB#=+9XF-cM^?)J->C^m}%m*Ry9k7iT-4 zcWA|i+8p2CPPBW&hx3^G@O<e*?$(|*;A=m*xw_|2u)6omVjX+YZ+*`P^uZH(I{rwi zJ`Bg{#F}WGJ(z6g_Lu3qr;9YWGeh4uC26Qm`k^91=S$CPc=muUq@C1=|EPY{kd0<e z(CE+!n;cxIDY?H`Y|2@SoBWyiBafMX_;s5)aL_LQXs=!I_Tv_R_=pk?bSm+gXEm+W zl(gkxCD(^_<*K#1sw||G!eUKNFHmYiny$WNs?wqYmNt@SGrml<nf-Bg&CzJPw(BQL z-}jBpYWu`8w!d$gn+{u6&C8Zuc}h9qF69<=D{tA8%1_**f}AE5jJ0S^e4EWVy;^gB zZM1nu0=n+g3M=fWvZC&JcKwb8HorZ=Zm3PM1>5K9#*!!t)WmCH>KQ8zjHx8*Ju6N5 zT&06wX;I{xTGZF0n+9Ic;?9>;*87G9ceQHCf#>Yzh6dfzy3Ll}_NXnZUuWgB>n&7P zYPb5A*z)w5wtO_pDq>4i@$qGL`^XHfc<q9%?2pl^y^~bgbxwD*46CZGPt{fZTD|pK zTQmQV)>igfP10_yE9$h`i(a+$iDv7+e#+{`!nUEO+3q|Yvb*-LwEA~9>h7II*3eO| zd+L(x-W~bcxU^8=TEFhgo~BL3KkNQUJ~d{>TI0|cYMMA|O~>C+^WZ6a;FS(-?(4QK zyWg^{oqO!T=6%+(tHs7ejEjgI{|{Hxg#Z5X`C_KH|FAD1IbyueH&MQe|GfY4=CAi< z!H_RdT+S`THzM3Y_YnFQi}}r+@Zj`%WI3L0J;;KP6(LJP)`TnySrxJ@WL?O@kd+}z zL)L~Y4p|+tJY;>y0+AIWOGMU)EYj1hl3&g;k#!;qMOKO|)zhsNSuC<zWVy(Ckp&|w zMwX1M8Cf*4YGm2Sx{-w=D@T@&tliTs9$7uId}RGd0gwtHB|vI`6alFMQU;_BNFk6) zAf-TR;pvKjRKwGi1E~j65TqhVNsyW#MM0{9lm)2^QW&H%NNJGTAjLtd<LSzS)W_2m z2&oWKBBVx0k&r4OWkTwN6bh*nQYxfYNU@M=dAf2T_40HDLn?-p45=AXG^A=s*^s&+ zg+nTbln$vKQaq%3NcoWZdAb536+}vi)DS5mQbnYUNF9+vB9%l+iPRD)CQ?nLoJc)A xT|tqGdb*M#HARYwR23;JQdgv~`2VbIj0^9qY!aLv%+1Kp$Vv}pXJKY;%<s!{R2~2T diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Aden b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Aden deleted file mode 100644 index 2aea25f8c210369e0b805d0dd5f0e899190c2340..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 165 zcmWHE%1kq2zzdjwvLMWHRoZMz{r~^}85tQEw9kO_Xc;iD`1pn}Xd4(agpgno(2)Ni S(?Dk6Hj&E)Xs(^EF&6;xtQkK5 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Almaty b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Almaty deleted file mode 100644 index a4b00779005803d665d613e326bb77d86f45ebd8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 997 zcmd7QPe_w-9LMqBYNo7&A*9avXPLEZS##-HZq9F)NU$0)BE%q~5}_bMB&hIE-a3TX zB{~d@4$`Hem)PMec=S*pUe>^a9z2vFUPNvF-cJcbx^(Lq&tA`-jWPEAr2B^+M9g0g z&!4*;R<6BMzGvTOCfCA8gD*1GwOMaX#pgiH=E|Ge)#Z#Y@AKBp4`uwh5v~6;s15IL zY2)i&ZF=6NfrlYIHc+q4eU*AV{!3dzYkI=Jq$dx5)1Z4tf*U{O)bfv1>(jTX)`hQf zdTv%i(^)z5VN%*ACgkj^F*!FpBH??3(tdkfBTpXb`R-xuxN%)O8*XYe(yq~+n8y6q zBvz=?i(6so%57^rUnPl;KI#6lA<3~V>3O#(a=###UasqCu~>8+Jn;MBE-QH)Dld6a z`Ucl-W3IIDzg$ikdwut@tHPM{9dl&wdGC(P-r4_|zN={y3U}J`f<2>rjd3|g`X4IT zA6}#cQiE@y2vP+p<7n$3g^)@}DWn!s45@~cL+T*~k%~x3q$W}nsfv_E>N?uONM)q7 zqpgh;N2(*`k^0C2kQE?HK-PdP0$ByJ3}hY1LLBW%kfk`<wIGW@R)Z`DSr4)xWJSo5 XkToHT!cp7g|5=qMVON%Hi+XkeW0>4| diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Amman b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Amman deleted file mode 100644 index c9e8707912d45ec0f9eaf56d46877fe9289d4a11..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1853 zcmdVaYfQ~?9LMo<B$v~1_rNTd2+47(qvVoHs6>~u94#SVO05u%YAKfy9+?MaW-~M5 z0kIk4fqUiwJ@B9F=K6ITv#{APHskmHV>7dvht7XHuhZG-+4ubk<d+uv9DjU;{`j`i z$mcF68*f`3f~&QoyUE`vGEq9cerUNu%hYwPr$6k)TXo;9w7OgwEM4obTHOwYO84Ml zEBweU>9?n|)xZ9W4A`jtfx$--v8csADCeRKp83#<EIK1YMqIFlCN7s@Vf(D8uvHrM zWQKqEvvU&NT5OFty;wa>)2)%a($rhsY{hIUlGwZh8dsDmzT_4eH7!cwBlb%|q)SFS zw@6}5gCxG%r(>S1(Xltq%ea;T9e;eUBsJE{goZkqSXUvFc4o`u!dyu%|DaPcf;u&+ zP^WnUnvxu&sqWF57STh~+WKg^%PZ-vpLNEo?lQCKzGhr`Cz;znN!G!el3j66a*h}H zXT|T4K+XxB-Ft)N`gUmUm))Azvs&{Wtk*g3@-_eLLY;d(N$2gJs`HQa*MhY}biuCi zBJ(@y!rFeaC^b?F^S?^b&<?VA++!&YeJLe<FG<Pst5O>BNJ}ptma?Z8b;*Hkvh-4; zF57lU%NsZA^75^^qOL?&W|eEOFkM%9{aTSxER|h-TIHE8RUfmZ+8r&`cj9Dqn_Fs5 z^^)4wH?n5Ods*A;(sfmLWc~IwZRh;k6XLX=_8~mqKmYdL?zg}H{HtHSbvPo9a$M1| z&h`#R_&`VJpYME=kr{BLq|D+iz^|Onz&{-6SM%af`A?1&IauUqZO!2#$7^d27&&6( zkdb3X4jMUX<gk(BMh+Y~a^%pFV@D1iIeO&qk>f`KKq5dwKw_{pK_F2eVIXlJfgq6} zp&+p!!64Bf;UMuK0U;3~At5o@nxK%Vkg$-rkid}0kkF9Wkl>K$knoWBkN}Ygkr0s> zksxhNlt`GiCQc+!BvK?)BvvF?Bw8d~Bwi$7Bw{3FTN5)9w5^F62^)zU2^@(W2_1<Y z2_A_a2_K0c831GikRd?E02u^ZGYZHs*qU)b1_BugWGIlaKn4RD4P-bB4#oo+5M)G< zAwk9j85CPHD#)<dnsGq}1{oP-Xppf%1_v1({BMTGWhQ8(k1_IOj`AjW<70gBp3Jyd K^D!YN&h-tD8q{(C diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Anadyr b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Anadyr deleted file mode 100644 index 6ed8b7cb07634b9d669c6c36448fb8df0fdb32a3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1188 zcmd7QPe_w-9LMqB<F*<rC@RyrR{lwst=TqBEOpM*#5Rp!r$YEr7WC&3(IJqqs36Fo zphKBdP|1*p9V#dcJdEfd(IE(|;0H<2C3dKT6+Hdkj|B_5bZg^zUeBJ5!S;D)_8dAG zSATu@e%<Xfa=mKO9~^&lXLPzW6o{@a-*vmpJCG}zzY;C~bUEpt&F3m+N|S-9YFTrC zr3A;_vi9OvSvUMqDv!L8s=Y6yI`u?qS|??F_=eO5Mx}1aDG9l=I`rkb-Y|EqP=7L6 zsDC}IH|CG(@WVm9>F$7zT<y>e=c0P^i7Fi(TA^cu35g%~OJjSbH0}N_TY@Fh9D6U# zKjx&RVqUkrdoEkQz17>MveG*HOt;<3>-ML&bmIJk?if3xlLs#7&a*dVd(UCrwg0qq z*QRw(*FM?dY0$kj-O~FxC4H_s>3bQGogciCdaz8=Gx0+ICHvTjZQGWs#O1ck)3d1P zx!7CuqWFzJug%9iN=*#$$7ZLMTdBOZyh=TOrIvEG%z5Gd?`z9^W-O<cFWgV}XH+;A zH%F5>8qE>otCX^MWd31F^Gj^zL?-1+m=&28nb*-wjLeKojm(Wqj?9iskIauGfMkHA zfaHKAfn<TCf#iWC;%G8KQbBTYG|3>@An73aAPFHEAt@m_AxR-wA!#9bA&DWGIhxdv z+#F4ENOnkiNPb9yNQOv?NRCL7NR~*NNS;WdNTx`tNUn}1StMIWlP;1kk}#4nk}{5% R?f>JPeQhT7L?jmX{RF};8GZl& diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Aqtau b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Aqtau deleted file mode 100644 index e2d0f919541fc9d64f01d8c6128c7e73a94869cf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 983 zcmd7QK}ge40LSq+bvmYmCpTT%Ds$?ZuIa|CY3m{$COqN~f+)O$32CRH)FJTD2!ak# zp2UM>bchIrJXz48W9U106ZIXubm?GSWRCT|f0Y8ec<cXX`~3Ic7-Qd`GkSkAA^v&z zPww_uxvqcLIB(XLOWB6tMm*qK4F?W?E(O0ItTb*%!cE^Eu7o}n^u_nHx_NO@w>%%w zmmUx4@Pj^md8|`k$%XXQOr36xmh`pI58YO~rz7548ToZ2+xLsA<I%F}*xHqyUpHm+ z;}?1T&8m#ezm{EvSF(HNrHW5HQ8&gvm_+`W>FIxAdhbq~WOLr662m4{a!fijrP4bo z(^t%?o1cT`)^?Z5yiKb9^?Eh%G@x!T9H{KQLv^Qc!OWG*Wlu$ARfRph)qkBezT+3Z znzN_ZD@1qL{tY6X6;(nEO5qd2QKF7#k9|J9bA0Ww@BaB@ZrBmgc&~jV?IXq42;t#y z&Jn==?lKXO5PS(SkRYx$3K9m1g9Jh%A)%01NH8QC5)O%n1VkbtA(5C!P$a6W4U5D@ z0=wGCNN6NB5*&$+gh%2d1F#52fD8c{12PC?6v!}K?KqHuxZ05*LqW!Z3<enuG8|+) Z$bgU$Aw$AB+v2|&lRskzHV{kte*-*r+;so| diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Aqtobe b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Aqtobe deleted file mode 100644 index 06f0a13a662aacfa70c489d2fec5276362576089..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1011 zcmd7QK}eHv7{~Gdrn9wq=wfP1d#&_Umu7Pt)8<^4(ZS$B20|$8V4~nj5(NVxMwg<C z9Yj2cN{8?;p-vTe=os`Ix=D5M5<!RRB0ARp``TfLF5cYB_SxQdyo`N+`TH|dG4tO? z_}|&MmG>83H9wzzvsKPExKB$LoA#W>;I7kn_<N)2`>#^-zUy52xKN6`E9&K)d2Lyr z($;5Vdgakwb!G>&ZM<8rjzsiYx?ZnG%i13KsU6{O>ITB%{yCP;gQG&%;#Q&S^H=Hq z@JXVt_vFU*uJpXvl-}Zs+<aJ+zR7vHHL;<wxh3r%daUu$2~D(2YBDyg$#PCpk#R|V z>C}Ovj10aH>Fs?-(l1>Zdh3_Wlk+mXb|BdYKjco)=yIh}@%d|NYy9>I)Kwklf>j@? zFYrEKOk$P)C6zU`#^l5VjmZ~$^}HJUT74!bK6~}#n<wAl>d3vkiT1_qGhv@eZf1<n zd*n|M!~XsXL69iig)m4QB#@_#goHw3A;FMnNH`=O5)g@qghXN@L6N9PSR^hI7>Vp@ zLnE<~;GQ-*5*~?<3;-DcG6ZA{$RLnWAj3e$feZv02{IH<I~HUxo^~|IaFFpJ142fG c3<((%GALwJ$gptPHaT<S3Z?DhGChgVU!>35vj6}9 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ashgabat b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ashgabat deleted file mode 100644 index 73891af1ee95a4d5d602967fd5a965c8a7ec1327..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 619 zcmci8J4?e*7=Ym~rq$YZaM51krCy^Jp@=OCMLLK$ROk>8#Gz9`a1|YdE^g{Sa1gqQ zLl(D!{s4z>cW`lWaZnf063^ROaBy+)gp)U%gmBK|ZSU3=<=4^wy_z=VdEhd2wszfU zl?L4te<*pINkndPiTBrw<kO3vx_2|_y93{89_#SczK)#Nbo6vf$Bs5Mv$vw-JM%hG zc672B*Qsnvr=4e=i9M(rj#b>Z&&urMM|JM7QLP6-VA(yLD-`~5_4e7eNTJEDmP-;6 z@v2rtWW6Hs?!CKWnU&5rye)5flFcodSuiut55zJ<ygwY?>?;6(g1}FJpkPoy+BGN? z7zz#rh=N3cqF_<LC}<Qo3LXWJf=Gd+U{XLSsO=h93N8hh*3B9I4LMpg=Bo?&=od*G Be>VUC diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ashkhabad b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ashkhabad deleted file mode 100644 index 73891af1ee95a4d5d602967fd5a965c8a7ec1327..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 619 zcmci8J4?e*7=Ym~rq$YZaM51krCy^Jp@=OCMLLK$ROk>8#Gz9`a1|YdE^g{Sa1gqQ zLl(D!{s4z>cW`lWaZnf063^ROaBy+)gp)U%gmBK|ZSU3=<=4^wy_z=VdEhd2wszfU zl?L4te<*pINkndPiTBrw<kO3vx_2|_y93{89_#SczK)#Nbo6vf$Bs5Mv$vw-JM%hG zc672B*Qsnvr=4e=i9M(rj#b>Z&&urMM|JM7QLP6-VA(yLD-`~5_4e7eNTJEDmP-;6 z@v2rtWW6Hs?!CKWnU&5rye)5flFcodSuiut55zJ<ygwY?>?;6(g1}FJpkPoy+BGN? z7zz#rh=N3cqF_<LC}<Qo3LXWJf=Gd+U{XLSsO=h93N8hh*3B9I4LMpg=Bo?&=od*G Be>VUC diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Atyrau b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Atyrau deleted file mode 100644 index 8b5153e0545f550c6f9b0da9ce134a8a7a4ebe36..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 991 zcmd7QKWGzS9Eb5YH8CM6l0llZX*AW^*u=JH(u7pgKQ6%`!b=Ghq=k2g1;t4$3M~{Q zIJwnHIutDq;*f$)Ds<>5_BXf{HG_+bL+cW1N#EzHlEKBz9GB1K0!PU6tz5r3pHY8( z1%KVmTDd;?qI*TZUJvQ6=m#ef*hoa0du!2eyY=p!WTNN&y?X3zO?qE0NPKl(PCc5D z(@R$+aeGYqW>a#e9Fw!fPU%k{$hp{e83=umq%WkCKYr@-U-!-6{by$I<7b`P+Sch; zoBG1~h8}wSR1eoy^vK<scB%{d;@p~K?kq}n{DF*4&q*#`m3(GW@&_d;#BQ0wr+i~< zzickOi#9Ir44dNfoEd);HWLpcX7b6dnYz(5S8693%dJ++({aq(VGrN&w!<H2`@k3e zz@NkCQ_89Hm!ur!RjQ;_K&gsRoxFSO`|mqP*B<+AVM>LM?w7AsRNBefGiT4dJx6(z zQXXEFe~4gzdy5cA3?4!dB#NsIgTz4sA(4<!NGv265)BE5#6toi5s{EcOe8206$$HV z<065P$gVat5*rDQL`T9S@sR-_BS40Li~$)0G74lE$T(c>K#-BR+Myt0K?Z}21{n@A c9%Mksh>#&6W5Q+I;=dYHuxN)iF_a4)0w=fGaR2}S diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Baghdad b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Baghdad deleted file mode 100644 index f7162edf93c28193436cc379c0dfe4185e368a42..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 983 zcmchVKS-2u9EZQBUWiIXi=KZoQ#<wS)zj|ESAG4HE+@Rh(U5`-DoRB|4H1%G5Tro} zYA7fqFmezFTLeK62NiL!MWh;ji`3#22t{)Ko~yy3#ih^7d(V&K<v8BwN!}hCX_SBN z%-?TgmYmP4{g`oFlkbfB`M=Js7JOgvLtnbQ!tIwkMJt<L@xq2*^7fG_ogOx2<G0Mk zd%dQ7AZ{)t!luG4G?(jgO=Zz<Q<ZyQs)M0B)rXJe%C}_=?;T0aR=d_NJ6bpYP$F-J zq<;E?ULAj>&i&8QFj%aO{-8uXUz!?TXmk0bUc0a^v5X~&{rIWzeOIpUKGhrR542_J zqquXk()xN|+n()e`;(A(cl)(tU`9F<&!wyNlXgee^k!L5dd?n7uf%mCl}ZINGXGpz z!BbpWBH{P;tw{Kt*mI2|*&=Z-kazN&=u1kcy=$GQy_<Mk0)gZyUcCK(sj;cWuMh$J z0us`+A|Ns#LLgEgVjyxLf*_J0q9C#$!XVNh;vn)M0wEG1BGa@o8A2ga8Db%FA%Yo_ z8KNPwA;KBbA>tYG838~dfP}z^Ax#?uBnn0tkT@WLFd|`u0*M6@3?mvyIE;800YM^y Ygv5x65fq%TuKs&eIj)VYEfUQ+2Jt=1sQ>@~ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Bahrain b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Bahrain deleted file mode 100644 index 63188b269d077e29f48a42a03c2a52aefdb61320..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 199 zcmWHE%1kq2zzdjxvLMW}@Y7ramaa($>i_@$&&b5Yz+eyn(rDqpz{0?wWx&AU;~T=D kZD0b##tb1O7z{M;Kge*9X&?(gG*Omt*#NDw(>3M-02;d=O#lD@ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Baku b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Baku deleted file mode 100644 index a0de74b958e42ade6f93ec0c4bc06ae714d5c606..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1227 zcmdVZPe_w-7{KvoZL>KocCk5^{WDwYinTvBOKs(!q0O4Q6ry5>k_w3xb(8!-B^{)o z@DO?K5Eez9QelUVCIlTa34Ra}6xAsLE7tG()*y-w9ec*R@4I*7h3)w)bMVAaSpFEd zxx&G;nS*oBZQn%un-}HjiolKhs>=D0*YzafU9#P)d@Fh1Vk}fOcPa0mxu#c7UC`B& zXZ4!#V|wk#fL=G8)awt$^@dcPu4%5)8-r!K*8f#+DtoU3PG2_g$(`N&x-?h!Y$;d& z_+4(>;RR3l%tKG4<&H%AE=#QXsx*dAO5?ZF68Dd(_{)B2`f^<Dn2pKK#ctJnt5>y5 z2UY7>MD4n{QYD5e)b5K7vZv#-YCF0@+G`h7N83l~bWW>e%~MH!crIP`2huhFNV;E5 z$lkk?lA61(daj(8eN)%f{!>{=kDpV$gCnYMcu@6kKcX_JCUwA@Py<1~8Z8tGHv6(4 z4~O%YN6GRMhpY7GJH=1@rFN06GyJ~wA#sRwrfn{fctXmH&&4Y?bLIEXq<S*a5Q>;1 zW{xPg5t}vEsr4%J534obsK9zDE9Ne&nX+oix~-a(Q`SydJ!SnA0u%-m3KR|$5)>8` z8WbKBA`~VRDikghGFA;63LOd`3Ly$33MC3B22u>H7-(5FycmdCHOv^OQMfUXqp+jU zqwu2;q%fpVWZ+04$-t6AlYu9Ns8z$1fvQ!*m4Pe+TL!umz6^vZj2S3XI8#VdSW{?I WcvFbeQDfmhVD4@<e}L94QTKNn-Sr&+ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Bangkok b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Bangkok deleted file mode 100644 index c292ac5b5f489a88bf10a1263b14e7412479d9e7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 199 zcmWHE%1kq2zzdjxvLMXU03;S=r5~yP|NlQD6B7eNoDEO}M6xh2Bo#1l`1pn}I03P? lfjL762?hhr`yaNg^$3UtSpYJ%9>^wW36~AfDmz_sE&#dsBrE^` diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Barnaul b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Barnaul deleted file mode 100644 index 759592a255408caf354d0c4a2e406ee5a1638181..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1221 zcmd7QUr19?9Ki9joNmkr3CcffWtlCT=5f_rP3@E}(M^LGLS+!zAA_P1LVqYUw0emc zQ4kS?IC_e>(4U78I#ke$^blqbA|>@w4;3XrXsq+SHs~RO-a3c7&)wm2Vf%d(yAB-) zia##TuhS+Y_XR^Q&&=K*o+@4BKbl%xloo~V;ex{NulkGLkEe<!@<qw$?v!_=$69iG zr{%lRYAwAOv6h{#v`P>AtmT~xtQE10RTlYdtqe?A<=z+8s{ALG-}y=Ur{Boc?_R5l z6Bks)*kifo>0KGPmzI_3tFr3KdAWA*xUBB&k=4)Q{c_(yRkP=^4jwzA*VXsx^*grf z4ZaQ?3fAb*kFXAV+f{h7L~optYSYN9j!Z06b+?LD{ljV1aBfCzzCNzh{z<iE;EUcG zeWV(@$8=Nqkcu`w(A#ncRCC!i-Td*UZpk^NTb`fQt#3PZ>`u3ikDgR*m!dim`zkxW zeNcUwOvaHjZ*Dttf7^Mk>=(By@2}hGayo@*ALM^d>=oud+3#=*(UlbQv!B@$hdG&h zrYp%k&&1mjA|ONN3Y)8z*9eDM!jbrgshS^>VY0|{c?%Oprp#i}wr1MM#F449m^?Cl zqyVG>qy(e}qzI%6qzt4Eq!6SMq!gqUTT={D4N{J+sRt<tsR$_vsR=0xsmj)rh17)< zhE#@>hSY`>hg4^4%0ue2H3cFSA|)a<B1IxqB4r|VB84KABBdg=BE=%rBIP3W+M0rq jifv8FNX<ymNYzN$NZm-`*k_vfe=GOYnd%#=YCS&zctRPH diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Beirut b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Beirut deleted file mode 100644 index fb266ede2279b6aff913538d9d5aae3935e53aeb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2154 zcmdVae@xVM9LMpmB8n(#wPqnC280239vD9|k&-SnIenWal8Jm2PlALJg%mQJX}M*t z?403juGEXlF(ks8xms&YUBi!C^pC@RR;_M|K$F&*x%xc6{omGq^}XHaao>Ia`fm4n z23OZ^%ys_pdd)tKvEPK9_INi`ZH~3>lH*HvsuRUMI+C7Y-pgpy9rxcb9oM=gnz_eB zM?G?N(x>WbztYzR2hCt_Sgv2(Y=+wJmf@}wYNVx1kBh8Tv02aS@g*^4!sHJnF0DYt zUB9B^W9v-(#oJ}l&%<W&sY8-*K2=RQa6wOfKUPg^JgE~$y=KOxBRZ*ny-M!Za!>C; zGcz2cQx2V1vziLz-ecJ&b=7B*R#T<Y3y1Z6^FLM@iK#L>IcjF#EZ3P%y~*sGsIz+d zRQB;x;t6*t@9sBc&ej9Ux1mXLDmzVX;0-;u=ymgeXN%5DZZ!D`D|P;@pedZOMhXY= z&4V`=$h@<6nTIZ?$oxp2DmpV(7Q8%N6(9al9uEDk9@*{ah5pN`r22dPX!=>@FZoJ8 z7JF2crbcw>&>6EhX0Kk{_qKWbhdRBav(1!!^NIxauQN+e*2=Pm5+nPT$nsT6J+a9n zD+(5>VA)hzIXz94XZ<4Ozl~QFcP8kH@1p9-(P6#1_kw!r+e>=Q(Vt9Z&qsP~+c{Ge zKB!gI2WH)lZdqTv&s0~2Wy8z{6Dn$!jd8E4n&b+piPo#9Z_Sh1bIVlSK$1Muk)t+! zU8w8#-k};IiTc@^U)6Ja{?MD3-)0&^SM(O&4YSq%g>IVGZ<@UW(mZn7Y@71AY}4&# z`_Mbm($#8O`(Bb4+TT(;Iz#f}_7>H)zf{JK`44>@XVxP7A9gZ*W5zj7Qi?ONED&`3 z{uLZSC-^V6@Ta}Xd%yey*#xo+WE;pnkc}WaLAK&*_kwK3)$Rt_j;q}dvLR$g$d-^j zA)7*W#p|&xWM9a}kewl0bG3UzHs@-0hinhoAF@GYhsYL@JtCV#c8P2g*(b75WT(hh zk-Z|DMRtp97uheeVPwb1mR;?hkxjeWT_f8@_Kj>D**UUxWber4k=-NPNA{020O^3M zZ2{5)SK9=n3rHJ~J|K-iI)StT=>^gZq#H;(kbWQyK{|r81nG&ZZ3@yASKAh(FGypM z&LFKpdV@3v=?>B!q(4Z5kPaa&LVDzCn}l@9)wT)g6VfQ8Q%I|jULnmwx`nh0=@-&4 zq+>|Ske(q;L%QZ_+lKTFX&llyq;*K|kme!XL)wS*4{0FML8OI950NG!U348e?cUQz u?r9{_Nu-rXFOg;<-9*}n|F?d|+lYE{$!T_At~bx?o8!w4<oN#n75^7NMSg1l diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Bishkek b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Bishkek deleted file mode 100644 index f6e20dd3a85eadd3dcc28cf59f3acc5b95584f0e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 983 zcmc)IPe>F|0LSt7+AT#5rbFqpYEx-jZR)tSfAa4t7$dq6vc?b{B1&2E;HgvTp)iCF z(J?$M_~#H^3c5sp-a&8=UV;t-vd|$BFB#HB7F*wUOp5T*seR0TmVsTC`TjE3vm;Tl z@2mXR-I$io#tU=8cr&|U9}Pdq9jke5RF}W9s<&33)~tWcnJcDod^wv7y}PGsUyiD} z8CTUm=~pN2w<&8ZqE6nZRi_3ItJCd2RYPP$HHN;ZGnJoIIJlh(|M-?V`(aj{TT9sI z7w4_Wl4)O<du%l=6z%3mS*vBLVB5C`tk#i_b~HVjyVyDHT^hQUkJa7v;?ZP2zMb}x zp<yRkXz?x=6HeRvBVPN8>2xeKyPa=~PS=#-c0VsTsXLo)&%>>JZ{KIPxA@GOER{+! zaA5ZY5B_lu$=|0;{&fNYA^N`aaIRbxK_PC9OZ|8<H$~On``#Vt-;q^=>5PcjF?}WU z73Zr$N+~k`@bLA2EfD~Tz;6%&iGc+1)lrZzNE{>(5(x=~#6p50(U5RRJR~3z5ebRJ zM1mqweRWtQE)p1tjD$vFBf*jANO&YZG5}-*$Pkb*AcH_g;j4#%jKfzC1Q`i36l5&O jV35%u!$HP_3<wz!G9+I;CY;o5{_CJBI`q7{n&K5ZD?izN diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Brunei b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Brunei deleted file mode 100644 index 3dab0abf4ed950f46a23282c59f6f6fa3b6ba758..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 203 zcmWHE%1kq2zzdjxvLMX2wu{MSSGs#g{r~^}8JU<E7_#?(G-g&XurM$bG%#@a_=YfO o8<-m#07(mm5E6_An)n}NJctHa0W!B9$R@%XE*qd_cDfc^0Q8R~*8l(j diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Calcutta b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Calcutta deleted file mode 100644 index 0014046d29a38e9b8006f746fea794d7f71eb479..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 285 zcmWHE%1kq2zzf)bvMfL>)Bq&f=kD2c>UNLD8P-CHGgFOLTq+To!N|l6gbWNpH-HKl zyxl;meIpn+7#N~67<qhrLl}I4*fThULEFI0*nlB~u$}BcgIIxB>^~5w?UK*{(az6b z8-Qq#8$dM39UvOy7BCHT4~T}kiG`Vk8Rn><3m``Uod$Fi&}lqirwM?Z=7HfnE}%<w JO|6U#xBzzAN{avh diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Chita b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Chita deleted file mode 100644 index c4149c05ce2638c976aec0d18eb7567c7276bc80..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1221 zcmd7QO-R#W9Ki8sZN8uqze{N?bERw9)O3|>>9krVx=B%^C<%mKD2o_TR1g{TdKmFL z6hU+_dV`QIy&TM23Kb$$o~(mlhq{<V1QM~H@4p5kx^(OL!~gUDKYJK#zi)Ea!Tllg z*H!#`H)iEoZoQlBe{y@o%nNKw%`dw&Sz35;rgZjMPuZuz)PjlW$%Uh>Deq817Y#(U z{AQglPFHBfX;I%{moDl4qD$jbTG=$NRlyPUd!OpE;`<u#yp_P$VOjp+xv%=<Az$_Q zJy|h)U4oA<OU<2AQhT*m>dtq|%3}$s-y4;N-3K&uG^VSfow|CfU)Pk^Xk(~A8-L8z zu(wLW?`JgfJzv%iz0szLkJ5bivqT49Ny~-T(t2Y+*6n*F>(9N=4Q<yXw&#Iv^q-Kn zSXwvb?UeS)BicTFTsz!bv}0_Cc20#f{xG76(aq9z#jDBqOSApkn6EFB$++BeeqElt zoGZT|=Oy=pKc5Q=+-_rfd-#h}XN||0bib?6m@{fhviIzc%kE^)7<(qWZ%PtfNfWFO zn_xq|HNuw}m$OXrALeR*PKMbc^JOt(WX{N}9qqi4nIm&YW{=DtX#nW}X#wd0X#(j2 zX#?p4X$0v6X$9%U(Kds0gS6vl`#~B)Izn1PdP15)x<cAQ`a&8*Izw7RdPACXwA~@? zIoke^29XYt7Lgv2CXp_YHjzG&Mv+dDR*_zjW|3}@b{%cMNW+e{W29xIXQXMQYou)! UePf?(;eT(usM$u}QX47y2`NzqQUCw| diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Choibalsan b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Choibalsan deleted file mode 100644 index e48daa82435078a2a731225ee963b30a48f78ce1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 949 zcmc)IyH8V50LSsu2a&W*s74YMiac6cEqwr0DwLP4VURjiG#ZivX-rHR&cKF|I}j7K z!yP&qH62Po;@HvAL<TmPjKdu$gavM*&h>oz2N;~ZH#eV~c4%|HzrvH}&ql;wuay4w zf_^T)+CPqTcz>8zPIir}-%qV;d(*1xOTX;?+@}KX-Lj|bQrFjxWN)dV`kwB}{`=q5 zz{HLWMn9=gS6L2v->R^C+Y0~MvLlCYtQ!Zf?VDd$tZ2Pt57i!6u}a>KZzQe6YQjzy zFImHj^J*lYkfW1vm5N=Iw*r23+xJtBpKO{F^^ZoT_Q9O27{=7bx;eeNY|Ipw%-KTD zxSPwG+0>ws3x>>lfvlK2+p!;ZzN;>@EvbdyFRG6kS+(A5HXTm4>-@K~P2Wx-N{>0M zWhLA~C_}Uh@zNANA<9*UpLd6T=kxh|K}3^d`bq2Oj))E?Md2S#TmQi(C(f^N>d46> zr;ijsDj+408b}eO3Q`8CgA_t4A*GO7NHL^ZOI;4BhZICAA|;WUNKvFJQWmL;6h<l| zrIFf5ails@9;uHk09gUD1Y`}!B9K)e%RttFECg8z7fV6bf-I(`UJbGw{6FjQWb~G% HVrkDG_#M&T diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Chongqing b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Chongqing deleted file mode 100644 index 91f6f8bc2e234bafd484146986bdb289082c3588..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 561 zcmbu*zb^w}9LMo*sb7uZVlR)P+QDKF36WCLNNV90hMH8mol%_2lQ6N|X0Wt&|A0ig zYPz+k{ufWWnRwpMAJ9ZRm*-x?E%$l*C$;LT3_WT4b=2NzZC~|=C*8PAnz!SMZcTj$ zt?sL|$L>r!EJ$Z#%XIIr^!v`U`Pj?IXSr#5n@#x|uLk|}K=-#pGy8I==4y|zif-%k z``2;iyrCBIr}1LxMlH>RUUvCRWd{{6H&If#PQe>V40%K@diI|riW5nZK+9zLz?b5# zy+^+If0*`TPqbFdBNLIC$W&ym(@sWaJMDC2K9T^*fTTcjAW4ucNE)Zj!x|DHnUGXS cE+iR}4M~UOLlQb|MkJ;4e>qdO>B@TQ7g9&Lh5!Hn diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Chungking b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Chungking deleted file mode 100644 index 91f6f8bc2e234bafd484146986bdb289082c3588..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 561 zcmbu*zb^w}9LMo*sb7uZVlR)P+QDKF36WCLNNV90hMH8mol%_2lQ6N|X0Wt&|A0ig zYPz+k{ufWWnRwpMAJ9ZRm*-x?E%$l*C$;LT3_WT4b=2NzZC~|=C*8PAnz!SMZcTj$ zt?sL|$L>r!EJ$Z#%XIIr^!v`U`Pj?IXSr#5n@#x|uLk|}K=-#pGy8I==4y|zif-%k z``2;iyrCBIr}1LxMlH>RUUvCRWd{{6H&If#PQe>V40%K@diI|riW5nZK+9zLz?b5# zy+^+If0*`TPqbFdBNLIC$W&ym(@sWaJMDC2K9T^*fTTcjAW4ucNE)Zj!x|DHnUGXS cE+iR}4M~UOLlQb|MkJ;4e>qdO>B@TQ7g9&Lh5!Hn diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Colombo b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Colombo deleted file mode 100644 index 62c64d85dfbdc41ae8e78bc8304ceb35b16b4255..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 372 zcmWHE%1kq2zzaBmvK&Ax(Eudc=kAp`9VMf2W~%mrOQj7KhRYZ<j0zbPT<l+I)c^ng zpOJ}~g^87oiHU*1>kd#ogVz%V76u022#^sW35<LU4AB{kLLia>NQNXZ07XEuKE5Fg zzCf&PU}|gtB+Wn=$O<9Bfk6BJhi#jw0-`|<1<@eKf@qL~K{UwGAa{Wr4x&Mh2hku8 XfarRl8mfDO%LeQ%J6%&NV*@S#78_5_ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Dacca b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Dacca deleted file mode 100644 index b11c92841068c12a5d0102402127ff4537a66899..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 337 zcmWHE%1kq2zzaBlvTQ&s(*Pt+-EP}(hP6=Q%v7TlcUN4R;bnb9z}x1=g!=#g|1&Z% zGqJF;urM%$904k22)e)kWJhN(08Q|XVBiCaCoqUGFeDW)O8EGOFn9p5wt<<k0gyBW zlV(7cIYS5uZUS2SKeMfE4~Pc24Mc<72d05;1koUOg4_dgD~JZU7ev<s<*4OmE*qdv I>~zhz06V-;=l}o! diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Damascus b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Damascus deleted file mode 100644 index d9104a7ab8cb13b4c87eb25ff633b03ec12ddd81..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2294 zcmdVadrVe!9LMn=AVP>}q$@82QW4|w0FQtL2o@4y5B3Wl92b=zQ4$h#6e1Lm<J!E< ztS!4N(pChh)moZ!%dxgfo4V$&TCv4yM~h`QJ95!MDxLS~|F-_C@3Zr~&UXI(y!{n* z8@%El?`7v}kn>D`WBBdXH@7F7-Rln+Z&lxF_T+RLy(>n{zNl*BP|Vln;gAmd%5%kH zxbih)q-lvcnzhXsD}C3z8tu2QWn2)~CNu2uh;POCg_HKg_ygk4kN+^P4}LCg^fVhc z`-M5Vqt6xx(?me+pb^+vYX%iY*i)*1GlLUeu&3t5h>-BljL=0TX6Ww|c3ALE5q92V zOuG~=!rwn;Oh1!rM%0(vGmbQgnZ9R@J4R25IfD(x+<{eMUjMKWRk~0_?-?>;3bu+n zch9jGWH*b2^#|=m-jB@K*nDI0?3HF*aGVi$wbEMh)ARDKi}O_c+1WDTXo5=YuF^?e z1(s)TyG(9xQz;Ga>C`HryfRHM&AF)3QXiM;QJ<=e$S%Ds@KtNs$a#79P_%W=H-4FU zx<qB2*r~Joc38__IVp2?eW-G`T-Gb<bJe|ToAiCY%~sy>KDjcfSLH|EkoSjYSOxJp zvS6%46;9iv3(rkht9}WT4<5f=`Of?(i}sJJ)rU{ZhnfeK+<izs?C)2_b$et<+Uv?+ z+^b7xZC7i&yY!mT8dVm#QI~z!X_XKAbVYx)Rr#eyuRV}wtvfnXukVPps=AV-S{Gtf zx6P1`WdCf{R9umdE}p6$%lt}i2)?9h=N^}}LuXZ8&=<Py)H`b9565(U&p!3UCok%T zeMhXu?x*#Wje9NQnR2~pb)&VpCQCPYq}A*zlTSr>t(L@0*>ZW7)fzruwhpAKEx+EB zTTk4k+Rj<B{iQM0@xgVytz|%U?*Co~2K*;~LM#Yn9PuduQ-qiwBX02(`9*$y34ea! z{}=0-bdCifD?*lptO;2ZvMOX*$hwe)AuB_chO7-)9I`rOdC2-)odqH*baj@9tPxox zvPxu`=&q9&7Ros*<yb1RR%EfrYLVq4>*ZK5vSL?f$;g^rokb(7=2$keZe-!e$~l&f ztes==$m%(kkF1}g07wNmN`TaWqX<Y9kTM{3KnmgNR01glQVXOQNHvghAoV~Bf>Z=4 z2~rcJC`eV1vLJOq3WHR})hP{98>Bc$b&&EP^+5`RR0t^%QX`~DNR^N>A$39ug;WYD zm8(-Lq*$&_wUBZl^+F1UR17H@QZuAzNY#+CA$3Cvhg1$JovTwjq<F4Q^^o!*^+O7X zR1hg4QbVMONEMMXB6UOxiBu9PB~nYIn66GWk#f2^^+XDaR1_&GQd6X;NL7)tB6URy zi&PdVEmB*gxUNohk@C7a^+gJdR2V5SQe&jZNR{#bTjnq)&q-cFomjNglkQ1RPDw0E JP5JvR>@T$Ir`-Sm diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Dhaka b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Dhaka deleted file mode 100644 index b11c92841068c12a5d0102402127ff4537a66899..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 337 zcmWHE%1kq2zzaBlvTQ&s(*Pt+-EP}(hP6=Q%v7TlcUN4R;bnb9z}x1=g!=#g|1&Z% zGqJF;urM%$904k22)e)kWJhN(08Q|XVBiCaCoqUGFeDW)O8EGOFn9p5wt<<k0gyBW zlV(7cIYS5uZUS2SKeMfE4~Pc24Mc<72d05;1koUOg4_dgD~JZU7ev<s<*4OmE*qdv I>~zhz06V-;=l}o! diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Dili b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Dili deleted file mode 100644 index 30943bbd0a8251404c407cde82243294071baf22..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 227 zcmWHE%1kq2zzbM`vdlotGwGSck<&AcK5)M>D6l*{lcE0q|No3kj7&@n45fQOMiewK zurM&xO<>^g@eN_nHn0F<ONI~<tN@z$A7l-P23Z9%6=WTV23ZLL^*}iytmU!+T5hLn G$prxMLN2uc diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Dubai b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Dubai deleted file mode 100644 index fc0a589e2b22acd9a76e402f0e7ef3c7b0547148..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 165 zcmWHE%1kq2zzdjwvLMW{@YBo{_5c6>XJlkxFunoOW8uKS;^P~_plx8n5JG}UKtuk6 SOaqyL+e9uKpt*LsCR_liP#c>7 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Dushanbe b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Dushanbe deleted file mode 100644 index 82d85b8c1b387ffc54acf509ac75220465b64d4c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 591 zcmWHE%1kq2zzR5^qLM%w#1>d3+1#*o@p}VN_1Xnu5}O3XIW{VY|9m<@;^mVClD8!V zq|Rh6kls^vKxR$)0ogeb2jqG@56IV89Z<;8KA;#Qb3n<5_kgnXzXK}T?+>U-KRBSq zeer-g%U=ieFYg>QPW1=W|NsA=k(mhsSy+)E8#_A#gF^$zL2dyIEDQ`u1&lx^g(NWW zz(|+~BTxjS#>Y2=LEFF-h|Pi645XET5ePy^@G#Il|3RJx(IAh5%m8^FM1ukVM1ukW zOalV~M1ukYM1ukZM1ukaM1ukbM1ukcM1ukdM1ukeM1ukfM1ukgM1ukhM1ukiM1ukj sM1ukkM1uklM1ukmM1uknOalWGM1ukpMArk|PV+$JvH=FQovtYt0Q1Os`2YX_ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Famagusta b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Famagusta deleted file mode 100644 index 653b146a60e5e5641a07bfc82f9590dad1ed69f5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2028 zcmdtiZ%kEn9LMo<Lsnk=^Cka~UH)kJ54^yID=G$>5|YK$W8Ab<;+SwjLrfF`|J?@? zbB?*M#@1ZA<s{acL*4xIz{+XP>E`fk>4WB&$86P_ur_n98msd@+9Mx0pL*`@echd% zdmsJYpXkbUu>#|<>v{JMZ?2v0oA1eAew-d0K5)$O_wTop{;qLGe0Rwl*<ECf+H>0; z-5#){d8wVecF20M(lN(GCOBim7tC>)=dJN$y3Le?BUZ}24)diupI8%qs5f8!zRn7K z({868-Q}bmjM?d(wNA$NH|&WG<<6wl+4d_HSx#p02zzoc$(a%uw5KKwIMWi7%xU-i z*7TnT%&hBot?Y}}%o!*9tYG&EGpFmgmD~QQnYU%X6{=}A^Q(HDg2+BQT%yj*oXvJ& zT9Y%YpjBoK#br*QOXu{jk)nTEbndsM^6JfZwYaBROU};Kc^wOM{^zOsS}ao+v=_<3 zMTuHk6Oh-Z{HkT8L$WCGik4^IlJdb{WO2fIS=@J7-n?@}-s=5YDz2W>$lgv_a`dn+ zZEO^?bC)h#u}9x-sMX5Z4H~T|*LPBu=<;BeE`Jcx6?WWy@BVaIdHPRXb;B>Kzetv< zlXvC)_&ura>JzK_hOF7~yM8eLjI6D?sx=u0q_(72V=tW2x-`|g-#*j&p(b5-xlPyi zNA<(6R%yefO|oHki8l6B%EtN({ivf*HZ3cbrdWz>&QF&uWq(O?vLP*b<Fw_EpQLrv z18uc0O55O%y7hREZ0kF#+YemO9leKiXIr<%_r~=(-_yMkhCTU}_~b_(Jz*Fb*ExpS zA>S~=NS$a5|Nryho$Qb?^5LC|NYp4RtK=hU%m{_~mCtAR9ua+tqyDdZaoqU}jy!Vg zk)w|se<T4U10)3`2P6q33nUFB4<r#J6C@Q+Hy0!sBpW0hBp)OpBqJmxBqt;(Br7B> zBrhZ}Br_y6BsWhtIV3wIJtRLQK_o*YMI=WgNhC`oO(ahwQ6y6&RU}tWH(4ZGPd8m8 zUnF59V<crHXC!GPYb0$XZzORfb0l>ncO-cvdrvogB!5qL0+1O%rU01(WD<~BK&Ani z2V^3UnLwrjnG0kxklFBbrvsS}WI~V`L8b(m6J%15SwW@+nHOYYkeNZI2ALaVa*)|U zrpMErA7p}%8A7HAnImM9kXb^e37IEkqL7(FrV5!WWU`RiLZ-{poiAj<Jlz>XrVN=g oWYUmXL#7RxH++UB&hIW?P5~PjjD&Lwb3=LIU?e}}eVgh353H8ZHvj+t diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Gaza b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Gaza deleted file mode 100644 index a4ca1c6e028f91977916e3ab1f45d5be135eea02..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2422 zcmd_rZA?{l0LStF4dijwNNrA$heQS9NkD=i3A`Yf<Vmkip8qId7UC^UF+gs`*m}~r zTIHm0#n{+%(j0THQO3&5G)|~l^M(IjB*a79R4_22|M#%!g}$k`owIX3hqDVW7{4!$ zf~}Pa;*P^lzv1F|TVFiSap~Kc{2p;;qD_32-0V8{)1d48kw3&YUj~bw{Vxl%y;XeM zSTA~Cz3jSB(c!vS<uCe^Hp~8-(Z+!PNjY#ynu9|V?xD_YVz{Tl{mVPo#Yo3-r+d#L z*RKbzxvv-GiyJ%UId7)E?iyX+;v5SKaNSDkb>EuG6615doZ~;96%*qr?%PW;4WGK# zl+R>`={q(c{n`@DSwH_SXNMNbc@wAQ{C(9j@RQ%vg57my(77oYEDstXFMT9Kb34rk zOWs!tLyC>Cf;hQIq#KL<ht=Zmu9-^)dsO%-4<q8@kc?~(HXr)9LPfn|Gouf!R57LP zMr>__ip%-JjO+7OOUtumd`7oSu!qaU&{nxD%ugoSn&iU|l*wc-yOBIquTn;&`N-8$ zmD-bOrhS^B9z7OjE^k?=()W9rk2TCt8AUIu%#uE}BIAVH9^EFh?w>TW@BKk#_iuNu z9Ga_gP6U{_Ur(r2htuTaM`M~-mvxzWZ;dxUv8>xzv-65H3J<6!9bIy*{jjkvu|+y^ ztBmz?dew%ABDrC-+r4qtS-J62t2_V35n0gL<Sx9hPZqtmLKPq1WR&dPElb~AD`iQ( zEUT+lo0g}_%|(VP4_Y8A(&AO6cZ%8)I9qM$o3Ea_J*Kvvo>Wg?`CdKKc2!k<J}S30 zeWt2gFU#$fA1Y_#N%`!WQ}Vg;Lvly#2Xd#qUOs<cqudpJQ0*G2lr=MJRZUNh+%sIP zUN{yhYtN^vx_7fx{n1dhw<cUQyy2ldZ1?<gdV1XD^qQehZy#?Tyz}(%^tH~red~XI zCq#&$|KLSroXt~+z!2g4*M0hpzR$GY1X!Q>`<YL!&U1*YtaaQRBG;}j{VZ%Yex6M; z{iMHe{EPWb>7%}DRR=OdOFczoj>sgDSt8R!=7~%cnJF?=WUk0$k=a`6=_2#B)DuQ# zj7%AsGcsvp*2uJxc_R}?W{yl9nL9FhWcHSN`pEn(bpntKASvLNN)9Y_5|At)X+ZLT zBm&6<k_sdjNHUOYAn8Ezfg}XU2$B*cCrDC|tXS%_AbCL&gJcFt4U!uqIY@Sp^dR{` z5@e|}gro?`5t1Y%OGuiKJRylfGG(b#h2#oJ7LqL_T}Zx=gdrJ2QikLVNg9$hByC9E zki=Q)%ps{ma)%@j$sUqEB!5T(kqja!L~@8E5y>KwMkJ3&B9Tm5>Qo}RwA9H&vWcV< z$tRLfB%?@5k(?q)MY4*d70D}-SR}JZYLVPp>f|EXMbeAp7fCRZVI;*!j*%oISw_-~ z<QYjcl4&H>NUkk)vXN|C>U1OdMiP!>97#Enb0q2bKhL_K?tXMU{{f=%5@Hf#5@QpS Nqw<!<O+Tji{Rs}{1%m(p diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Harbin b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Harbin deleted file mode 100644 index 91f6f8bc2e234bafd484146986bdb289082c3588..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 561 zcmbu*zb^w}9LMo*sb7uZVlR)P+QDKF36WCLNNV90hMH8mol%_2lQ6N|X0Wt&|A0ig zYPz+k{ufWWnRwpMAJ9ZRm*-x?E%$l*C$;LT3_WT4b=2NzZC~|=C*8PAnz!SMZcTj$ zt?sL|$L>r!EJ$Z#%XIIr^!v`U`Pj?IXSr#5n@#x|uLk|}K=-#pGy8I==4y|zif-%k z``2;iyrCBIr}1LxMlH>RUUvCRWd{{6H&If#PQe>V40%K@diI|riW5nZK+9zLz?b5# zy+^+If0*`TPqbFdBNLIC$W&ym(@sWaJMDC2K9T^*fTTcjAW4ucNE)Zj!x|DHnUGXS cE+iR}4M~UOLlQb|MkJ;4e>qdO>B@TQ7g9&Lh5!Hn diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Hebron b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Hebron deleted file mode 100644 index 1a206a70c7da285a55cf3790e116e633fbd0a14a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2450 zcmd_rZA?{l0LStF4dijwOl_u!kf=aB2}lqmffoc5Jn7ZR^B)DwLZmds0J#-o>q+No zOQ(e^#>TQqbF4W>87ni>?g=$(y7})#LOjGx1p_1ce-Eo(=$qEd&e=Vm!`Z#OVEn$< zk-xbjPTX<$=_kB6_Ujk-GoAW!I?p9ekF|=g5)V1g{?zY0cjOQ8&6o3pYwyd#Y-<tU zHr9*oS1&owm$y4FRQikFgpIQIW~9;Qe_ZxmlxF|Hn0ugOix_k@xPN*3x)^FdR_)%k z!1?RGYwqj$dE&;l+0{3bUw00#ZLS^(oaVfh(Cxl8ks(HBc~y`8ct(tkCb@4fN;iD! zUQ<5f?WXTYpY&^uGpGOjyPOeRAZL%Al5_S{$$(FOQ*(FLnSo~~<UD!62zu!w8Jyi= zK2-d!njchTgyhG_1tQg0=s&0yes|4W)bCQECq0a?3j;E|ZJzn?iE<V3ip`8XxLie* zv>DO0VJar;3p1w2TP-fjl(A`DGR__<<AYn|k`O<cU~7_(JWwhVz3fKfM7>HHlIEjV zOH{He-Aws3O+9ur#9Z1uU#0H#G9Pc4qS6XqRO!V%YFXOHZhK^_%(#Et$h`LlmD#(s zdilUCm36|)$o_gvtvH+_pZMU4T3Om@=Dam}D0fMhkz44mavQH0tF~X3M!`Pyq@z== zwjVau#5YSvcBQd)X17`wRw&mEce&S3KO@&)Y;ot^I3n{qn%o8F_sGI`mZ_p+8;s)J zJ7vk6tEDW?lcjZ4YQxfGxv|htWr1^Lc}lFR@J>>j0%oX9J#*Akw@1|GQ{(FC%ipVK zTCb|g&xhrfrq5JW%O$zB;(b-!cw9ca>ZE+G?4aBh{hr)zub0o?*C=;H9#A`mDrC*n zT2<r9lDh_r)C)($W$n3CRkuG=)qfbQcGrZehBrKvhwYw!PEU`!oL*D(>Fwj~gLj@D zp1#(3w~zjZXF>$^=zo0?9%J(qA|Ock{&k&vqOVh}C)2F={C&?mSLQfGM#dU04v}rw zFMTg;Hh!N?GkK?faQurQPUxe)bH#(mAT9MMkzpd^L<WkC6d5WqR%EcqXp!L}<3$E+ zsYi?q*;0=g88k9#WZ1~Kk%1#4M~04!9T_|_dSv*>_>llu>Ifhqu+%X?f`CMUKPq9c z)Nw!pfkXlc1riG+7)Ugba3JwO0)j*Y2?-JtBq&H!kgy<eK>}l`BZGtni477QBsxfV zkoX`0LL!8O2#JxU4iXY2Buq%0kU$}kLPCYa3JI2_jusLwBwk3skcc56Lt=&m4T%~O zHY9FH;E>26p+jP4se^|^4+$R<KO}%i1d$LTF+_rBsiSDA!-&KY2_zCpB$P-jkzgXx zM8avQ<B0^+Qb!aCDH2m8s7O?iup)6q0*gcz2`v&^B)CX)k?<n%MFMQ8BaDO?i7^sn zB+5vbkvJoPMk0-b8i_R$Y$V!9xRH1x0k_l<M?!9?V~zwJi8>N?B<@Jyk;vo!KJ<S2 dn;<fl?}Uh)xTyH3_~`h=h@8bSlebBJe*$<|4kQ2o diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ho_Chi_Minh b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ho_Chi_Minh deleted file mode 100644 index e2934e371b6d5cf80244d8d55594f7094bc9cbb8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 351 zcmWHE%1kq2zzev5vTQ&s+R@|OFmbUq*ICnN4HqNN6<o5m`*780x4@HaPa59p&tTxP zJ<d@7|NnnRCT12UW*}r@U`PQQo&1e~g@GZdfPs^Np`d|*mw};f0)rq##K$*;Apk^Z z8<+#J1rS>@gplAYppE}QP6N>(=YeRD6G1e{nIIbER1ghvE{Fy>8AOAe4FVvigFrn{ Qj0(=@vH^O=PS>0Z0O4(7+W-In diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Hong_Kong b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Hong_Kong deleted file mode 100644 index 23d0375fba3377a3d513d849c0d29c82ad2add64..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1203 zcmd7QU1-f=0LSs?e_rh{a>4}{MD&!#u^Z16wn@Wr?82!@F;a5cyrs<5X_8uzPOZ35 zlB;KwMCrM5X)}@6?btZ;wsRV0UUrThHplb*N4apbJI}v!K2QJ4|L+^$p4eL{{&|AG z->$cEpK~&?C)FKW5$W!4kKBzOKKAHhCiS?fxAjT;HuJRhn(8^S%Ji<OG3jNMCS9yD zebZ-|zGw4H|8T)PHxuT?y|l?(nyUtG=GDvN<LcGfJMwjXLcKY9MZR4gRfCP4Iy<96 z<<@rS+}K7lH2;(yN-s6<O8fPDQ*J&C)a&7MBj#gQvm9x8Xg=vJ@^ixt^QA2!zg9m` zqx-@#zu>wm)Q!q-i<4?>_HJ49?^4D5I{AIDR{h8{>hb$K&BU!5{qt(IDP35k#hHc1 zN&2<tfX{e$<g_oAHU2uE46O93;F7Eio>;BQ0$sAK(5XV%%W`T@hnjZ#w48aqN`((L zYscgDIUaw&KAu01<C)|mL{o^5eW+FVgh-~GDMGZgIpy3%`0w|dV{x$|%5N)w4RNu_ zUfkn2@kwl1vWGp9O<nD-$hOG7$i~Rd$kxc-$mYoIu6BE5e^=W8(gD%}(gV^2(go56 z(g)HA(h1TE(hJfI(v7Qa2kFPvHiUG9w1o78G=+49w1xDAG=_ABw1)JCG>3GDw1@PE zH0WwOL|R08M4CjpM7K>Y^vSV}0-YkQBE2HbBHbeGBK^ABhLMh4ZOcf{NYhByNZa_o L^&PV1SE$f0t#TGS diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Hovd b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Hovd deleted file mode 100644 index 4cb800a9187901afa985f1ae67565d654021cabc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 891 zcmcK2yDvjw7=ZDwR3b{8MdDVi`=#nm1+Dvn4wBPKh!7EROLXYy@(m)0;TyW?aE68s zhBH`*MS{sjEJh5($R?@t_yZ&cZ}a6hG-;amdG*Pqg%<Jav|8WVt*7nWeZ_JeZ$|#> zgDQA*h{D?`Rdf-M#V3B{jJsvYflIm8)1-UVrb?%tW!dPHD(}9L6`pHVS(KDjj$>7A zzZTUWS6a>Uv8cU2((11Egy(cut52*5Z){m>*ba)u=$O_t-zb`=7gbAeRJQs@RGZf; z+nx2QBPUmOy<VE#r{_jb;>`5N;znTm(Cm$F8h!H{X1_jb3=GYfgKY!GP({Bv?3{6j z@{(paV@-xX_sxlyak-UBrEKYGfBd8i5qf7)`Yh{+NL!{5a}kj}7Sx5Osl$4m*7FJd z4=c6)Ns6`dyQ~&jFS25WH6yD=){U$jSv#_NWc^42Bm<HH$$=z6vLI=GwDKT{7&0NL z7;+)W7_uSh81f+r88RX%k(@|UBrB2@$%`aLG9#&x+(>dHJCYvBkDLH<2FNKO=YX8V VkJecrr-A=`9$7uskp#THtZ(&(y9)pS diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Irkutsk b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Irkutsk deleted file mode 100644 index 4dcbbb7ea21e193cd2e2578a17bc955caea227a4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1243 zcmdVZPe_wt9Ki8sxz)13A)40Io>E(Dt=24?I{(zNvE~lNh!`1ISqL3QL>NepOu9sL z$PUusN9HX$X@m$Ocqovdj0y?*d+8De5k%Q~zOM~Nbm`dp^1h#U&&CUTf8RHm>Nyou zf8AF9UX2*JF3FhF?c$=T@sT-Ksi!NmrhI6j%sHgWzCB8pe|(r(JO5*0-E1P`o=i!_ z-MCcV3QN^hzpU@85`CsfHXK#5G5%Sqo8C!{Z%%66GqP#bxOnVuwdc!Iz4^nFfVcNT z!24`WZ<!g@zOkEn>zymwf1_7#yWFF<pG)b$$++Ipd0v8N4@zD05!rdDPIgr`N`0_Y z>K7{{<PPf4tDn;Fy+k)ozLBQ+uR1)ssGBEV>XyORx^;L$w{=hJJp<2WZ~KUjoOmGn zY6o?DWLWk)PU~oOpF}?mNUY$P#2$Ccf%k0^zZaE`*-o9f=9Ogpg{wcC&DxgP3zl}r z^1OY8Gw(zG7k^%_bU2jinl?|Avt6m<Y2{Sv;&q#O)ai_J<<7Ykn_0>IhH>Q9m8&C> zR55e-0=v!8V2%*CRm!%sCI4Z>=AUH`-@nv~j2am?w`1hU*pbm&n(-qEAQ>PjAUPmO zAXy-3AbB8(AekVkAh{sPAlV@4Ao*CDgpiDolq^k7NK!~vNLol<NMcB4NNPxKNODMa zNP0+qNP?CoLnK8@lOvKOk|mNRk|&ZVk|~lZk}Hxdk}Z-hk}r}lk};C9rO6pd+R|i= cq>bc_B#vZ`q>lZjf&VD?!mxP(TKu8HUwI%CVE_OC diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Istanbul b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Istanbul deleted file mode 100644 index 508446bb6aee2841ab88e82607a6ad6e748e7db7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1947 zcmd_qZ%9>V0LSs?`nP+{bz_9Pc+<9~_m<WCx4Je{%S>!HcdDyFf5t&8ib5V%gGPe4 zDT7wf8GBJA#8%G0%Gwr#Q7fV`boS>^w&_xK##j)+d<I!_QucgLuUc=`>z&KFpX24? zi_7!<#nx`!TqvHq()1_XTs!s6b0DtYtbL=0+9zk2?YA!2M>jP($98{cbkxSpFUrr_ zojD=rc&Nqh3Wv?E-yYc~#`ZcVFBcd+d&-?&&&x*d@=^20YjLBmuiLz_&1>8|T4MHB zCK$J(>CR8HcH2MajW`3|4fbHdL38kKx&6z%ubtaB)*D0pwmJM&neo^CZ_WD+BgW{K z6!SrL#7=4YRHl|3mZ{_K3vZxVdhI^p8+%u#efc;(d9XsJchtpS>O3W<v@M8F`FpAn z*n36>hR!&dcWf2>VMI-DFOXULcc|><jcUgBI`!)MW$Lx)0yVQVtX`iJP&q-L%1s+r zq2!PZjlLqoe|Y7r{(t1`@9)XHvqN%D$5lCZU#ptec3Qr%^D~*h@e^6F;k+t*@1QDL zbVL=e`ar!oJ+9^#u2b_LHK<7DE*TkKs!GP!%7x$Ms<&>J%F@nCx#(P$Ec+-&mbVL8 zu{l*PZVRd<Rd;1&<72fnr%zT@I%-*RuT?$sSAX@Ncl<Spm;5!?di=|OKjweCyUQQF za?x6GVA!fX`MLE@Q<LA=-)gN~^RcyR`zC93<bppIt+whiYOVURBUb&xd~411c}B~` z#Dpg?;YD6a$w`SRssH^o$@|<ZDM^UTus%j2bBoZ=v-3TZgb2<M={$?6LPRP&)BgSW zv)_rXh>03~S5>X%Ehh5vi}YR0f7O>qUr(RhKSb;W4!HhJChEWG89)v?a@bw<fkzHK za`2JEj|6~3fP{d=;HrZ_qCmnx;y?m%)sY~fAh969AkiS<An_mpArT=VAu+k?ppdAL zu#mWrz>vt0(2&@W;P_pM4hhdy$Hzs0t~x?4LPTOjf<&T3!bIY9)qx_By6RAoSdn0n zXpwM{c#(jSh>?(yn3157sFARdxLtMNNaRT9NbE@PNc2efNc_kEAR~Yb0Wt>2ARwcF z3<EL_u6iJlk#N;Rfs6$*7|3WK!-0$kG9bu^AVY$T2{I_is360Fj0-X_$jG?rp+UyR zRSym_I>_)K<AV$kGD64@A!CFL5;982Fd^fF3=}d_u6n4DvBDO82LBg><tx>LRyMcD F_XJx;ZRG#} diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Jakarta b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Jakarta deleted file mode 100644 index 5baa3a8f2ed24f68c49bd7e3ccd4772a8e734414..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 355 zcmWHE%1kq2zzaBlvg|;t&;TS>R<u6YC3Y|2^#10KOJVN{uG<{rxb<I+;mg*29gIxO zEX=ITYzz!33P7bGl7)dGU4a2;LS_X69|J?(1O^cXhJpqL2?mCw0tOi$-w*~TAl5c8 zH!=W`#vsxXh%FexJ)IarNO0YMAh1vKOaRd!SAuAeOF=ZqwICYgVh{~-HHZee97NN` M^;|$N=$dl@08sQ^zW@LL diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Jayapura b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Jayapura deleted file mode 100644 index 3002c82022f7e9a4ff1ad545ea617106a13b24e0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 221 zcmWHE%1kq2zzdjxvMfL>v`g&Zj0+JvKYZD`D1(s+DBS!4q_J)SNV;_f0|%JR=i?i~ nplx6Y!o~&+;hrH3AtYGx9|%AefoPCrAev+gxq!CnT5<sZ?71+l diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Jerusalem b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Jerusalem deleted file mode 100644 index 1ebd0664aa29c0abd722661f761031ec0304631c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2388 zcmd_qZ%kEn9LMqRO}t*foJ^@^$e%I_#mnWdRFaCKU?8`+F@%6)1ZE)}lgJeEm)c)U zw-&XgqFcm9rNg4O=Au^9Xd}28i&V_hACLmvX$1;P?Yz(0SnE+wdeZmq+}GLVDWA8m za6?6+{Nn<xUwF6%>)}0ASznEwjORPnc1y=ZvwV@dUv>5msW0ETB3++HNcY~I;%{k^ zuXfeR$rpRo*X6CMr!rW23q7j$T!DNW_nA5sUM8n!UX;^AemT>YBz+&I$ywti`L3-? zooo778TB>teSV$%&|aZ_OevM08Z%Y@b<1R++LZGlC)Hr|VKq3oRa~|8hU;>xKXB|9 zEvPxsKkMf|wAoQb+MJ0K+Kqdvw6OL|#@r`r{o$QgwFvEXZ{&`nT2$8i{+mh~jhiEj zz4Hn^+AXrg8y!4iM1M2jzjdhFxb2fE-k6?YZGKCHf5EYGBlZP{f8oAWhP$-I8@DaS z@MIqM$7jB3BrLA-CdR*~CC$0wPY!9&l7DUXE(&m|McocPb*xm~-ZyUC;UCfOJW`}B ze&djycIaL0uAMvdCA9~QrJGaqW!@$&J$tV#&&<_V#BP#|@G*1c^gLNPTxPBsPL|B` zqk2~7^|HEszj^oD<C48Q(9CHFRcoHxr{`8*RNj(w^B&(Rb#G;so|kk?`LY-2_su?_ z@?)>n^MBv23PNMdf}VA1?P#!B*tT31^^BPJAJC+@t=lZAOPA7Dj+$EWJXu%Qr9Y77 zl(OPh{lTz7DNlP@uW$ya^>eHB_5B0tq09ODhT|RT;j^jwBX7Q?Do^;#jnC{>Rm~~p zqvcgffA$7*)0%pDtbD@U?A|EV8GYvCGjgTIJ+9YWh?gxh&gfgZX33KmKGL@y9+hof z2ld+5LR8(6r}d|5epB1`l<5xVHB%-(0h6zjZ&RI9ozq;?T=?I7M53J5|GGq8k^qtU z9*0XLEK;V6q%L*L{QEDHf6dPE$!hD#T46nTXuXIy91gzzdJ*yci^W~FF8_m1Cy?bK z>$9~Mh^!D<BC<wgk;p2MWg_cD7K*GCSt_ztTWhh%YLVq4>$SBOjI0=0GO}i5(a5Ti zWh3iG7LKeOSvs<IWbw%Ak>%T3>*pwdtyKY}1V{~#A|O>j%7D}XDFjjpq!dUkkYXU! zK+1vC11Shn5u_xxR!xwiAXP!ig46{m3{n}SG)Qfb;vm&Q%7fGgDG*X2q(rt>jgTVQ zT2(^IgwzQs6jCXqR7kCmVj<N+%7xSmDHun^kdkrK3@MteRW+n+9Cbqq$5A<?bR4xq ziicDWDIZclq<}~TkrE;`M2d)1(bg&>Qb${>kVqwwQX;iPipfz;q?{b}L<-7LQKY0C zHARZbQB|a@NL_8M!XlMLN{iGMDK1i7q`XLdkpd$XMoP?4W2DF&RYuCpQD<AL&>WSv ywMxxVYoyp5)keyV)Eg-{{y!@oWEFm4f|dH%oJ4n$J1H(9B{nDC<4$&ag8l@yuiuRT diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kabul b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kabul deleted file mode 100644 index d19b9bd51d701d8bfe7b3e95c9f6f3c736a9aeee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 208 zcmWHE%1kq2zzdjxvLMXY03<H_yzWr{|NnnRCME_3hX+6r1`7uU76t};4+ah&-w+0E s0}~K7Hed)L!Dyg~|1;ZWEdbFVD?sMf1KC7a!({`u&Q90F%GiJl0ClM*ng9R* diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kamchatka b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kamchatka deleted file mode 100644 index 3e80b4e09f792e37422ffafe42355aeb3e6940eb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1166 zcmd7QPe_w-9LMozI%`=_6z0Dy|D<cJ*`8TqsdJ_#wiy&VRf8}6gZ>;MIs_6H6$BL& zNYsit^lwDO4iyv&JdEfd;UNgD;0sC6C3dKT6|CR;S;B%Y-Fn9MdiFd!JnZw1?>MkO zWc~G+_xozEk@H3Ow_nLVxt*M>@cJT4s}ku-&#v*xnajbd&zB<AQ`vOQL`9@F(<sXx zE|Iz$Zdrc*o2(f5B=v{hO2f`q(inXvO`Q*9rT@A#*Itm8`6tBdPO10nHC;7*HRn4X z$@$)l=<4iY^*>JNnmb!HFxI23XM(!+Sc3-lE>=4cmeA2^Y3r_+b=!W(`nnQnw?9bx z&uQtXnbD5-FJ;5`ce*i?lFq3Y+I2Up-Oq1n`0PFHNuJWkzH{1p`lf6eIH-MlPD+1s zOb7aQ%jU9H9c=2C!7ou6Ds7RW*8$n`(Ie4E3nexY$_-!49~sT(^RCj8!pmJ&^qMob z=u7d9KhMq2+?F+#;g3zGEpz^K(&e$N)VQ@^_H*`%%Umh^hP$!hxaGHP^KLWm!eB0r z_&@At9zV~9$c{V)TOxZRn>w0Zk!_KEk&Tg^k*$%vk<F3ak?oQFkp_?skQR_0kS35W z98DWYA4nsPrW2$Uq!*+aq#L9iq#vXqq$8vyq$i{)q${K?N7EP5n4{?oX$|QOX%6WQ zX%FcSX%OiUX%XoWX%guYX%p!aY1GklinQuzdPSN=x<%SW`o&SR{r}c*d6!8#9I!*> FzW|Yw7d`+0 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Karachi b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Karachi deleted file mode 100644 index ba65c0e8d31cb1d59935878af29baac722f45936..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 379 zcmWHE%1kq2zzev6vTQ&s+gbN#$(gA}D=w7?&A7Yb!3rk-)dn`}T{qay*I3};xWK@Z z+kJuOle-39Z>kj-nHZT_S-_Bi!R`*o0^bM*76yjs3`Q;n2DbnP0S1PU1V#}sThhlj zghAWD)Yt$>nt@4Eh5+y25Fio45JG|*{{sQYogf<IRuBzxFNg-Y8RQU<yFoO_?I0TD beh>}v1BeFs155+`0-~wyA1<J$bWOPcU^!Gm diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kashgar b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kashgar deleted file mode 100644 index faa14d92d58fa883c4203022e091dc9154ac92dc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 165 zcmWHE%1kq2zzdjwvLMW{;oq*5`v3p`GcqzT1j&H(gd{Mq`1pn}Xd9R@gpgno(2)Ni S(?Dk6Hj&E)Xs(^E85aO>>Kf4i diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kathmandu b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kathmandu deleted file mode 100644 index a5d510753f02d5dedcf1ffac153558466dca9b99..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 212 zcmWHE%1kq2zzdjxvLGz5@KbGzoP@!O`v3p`GcqwTF!=ugY4nX?U}0bgxWmBZ;~T=D qZD49_03uCH8A3=f9BAf$kOd$UL6(4MqAlXG0b6LNYiea;$^`(OKO|oO diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Katmandu b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Katmandu deleted file mode 100644 index a5d510753f02d5dedcf1ffac153558466dca9b99..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 212 zcmWHE%1kq2zzdjxvLGz5@KbGzoP@!O`v3p`GcqwTF!=ugY4nX?U}0bgxWmBZ;~T=D qZD49_03uCH8A3=f9BAf$kOd$UL6(4MqAlXG0b6LNYiea;$^`(OKO|oO diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Khandyga b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Khandyga deleted file mode 100644 index 72bea64ba83546e72ff9d6a4f9a9e64cc2d93b47..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1271 zcmdVZPe_wt9Ki8sy6K!5&mq%V=E|*QQ`=U_mQK@YGB+b?rz8;iYekIcP!R5g{@6j{ zIRwG*P?U9%@K7C=xAag*P<gTrf;$v}iFApG^?ctY?9ioSzZc%`yJznP+w*yo$A(V_ z#b2lD&uWh@*Bc&u%zb_Sa8^`%kES-(jxN^NZ>`k)csW%2C7ar`u)Mf=t~2GFPN*%D z5mh(dqPC9JtNLqFxh`1Lw!u}kJ-(zG+UAwpH>*6(7ivf46Xmsjklybza%b+9tMSTt zSL6I+xohU0^gX*Rn;u=2&3DhqmK%d|_vM82pNz=B@v|y;DXR8F`qkbe9<{HoNwo&c zRqL<yD&%y_(5Dp@{#hpXPrp}f3!i2C#5WnqzL6a_-^tF*r0iVHr4F2$5M9@^MtAS1 zh@KcXdOX9TH#%Y*w8ceV!;sOpe8z~Cb{ny`F{6LUZN#7YjKo}*7`Rhq9J*L?I2nH} z()oPeQd&|tthS<~ti0$&@f$X)!(LH*R90B6LZqwtpHqg=*JJlBb|FTTShsdwTe0Ys z!abQOi{wtB?<|}%Q$nxssl-51`1~Q^3;1=zx&gjiSj^E${=;_bUzlghDcjDl^_1<W z5HPD5P$*D1P)JZ%P-swiP>4{NP^eJ2P{>f&Q0P$jPzX^NnbnjioG7HsYE~3l6kZf! z6lN4^6mAr96m}GP6n+$f6owRvW;I6&Nwb<Ig(ih3g(!t7g(`(Bg{)c4mO__-FNH7z wV+v&k&J@xNtj%iL6y9bvaSC$^bqaR|@)Y(I`b=7z_z(Fz+VxY>(HwUC1_{j!ssI20 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kolkata b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kolkata deleted file mode 100644 index 0014046d29a38e9b8006f746fea794d7f71eb479..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 285 zcmWHE%1kq2zzf)bvMfL>)Bq&f=kD2c>UNLD8P-CHGgFOLTq+To!N|l6gbWNpH-HKl zyxl;meIpn+7#N~67<qhrLl}I4*fThULEFI0*nlB~u$}BcgIIxB>^~5w?UK*{(az6b z8-Qq#8$dM39UvOy7BCHT4~T}kiG`Vk8Rn><3m``Uod$Fi&}lqirwM?Z=7HfnE}%<w JO|6U#xBzzAN{avh diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Krasnoyarsk b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Krasnoyarsk deleted file mode 100644 index 30c6f165052efa4fbc176cbcf19b626b1615d88b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1207 zcmd7QPe_wt9Ki8sIcqo*FQv6s%VkTa^=s8!O>JssI_(gPus;<25hEe#4|NC>vVw?M zRF~)yj_45alj;(lDx!lFMASi|BnvuZ5nUu=J>S;`5?#9WyuACod)}89w%<3k{a{zb z{B?PM?>1VwF1|52``i7&vA~?r;q=_nj4AO97MD!E?l1lHDm`!1YvzyaNc)Dnb;0dU z^<Qt(g%{$w=v0*kdi=V0XOWgAvl@(l)g|FEE%&|9rQSyxa(|J~_jj^v{B5G*<hew} z%ZF0=_^yQSWuz)|RjRL?mE{8`WW}*=k^P;ra@T-Hj_lS|bzQo8OM|ZQZ_;QasL`L5 z8uKM2_NGwR{wR}m!xI`GbxZ9{uhc#GDD`JP%ld0iC2`=nG@KsS#^xbu+V?~^lwX$S zrdzr(|G2aS&uh!XC2h^?(bi{2we9_8P2Sn6?IVYz<6@1bk{<$n*=*L8H)HB>=TAFk z&YJdR`i(!YJ#M!#+lu&iQ+tfP?(KJZjM>|33Ui;i9hcq7J!9-MxqVaE-jOn4iP|$} z&l+B4TvIFc4<og|Cd*in(efI`i;S4Xm>un?k#Qp<XEAnU^vL*;1dt4n6p$Q{B#<nS zG>|-yM3797R2*$CNHRz^jy4@6A0#0pBP1mxCnPB(D<mx>FC;M}GbA-6H%FTslAWVX z56KTn5Xlfp5y=rr63G%t6Uh@v6v-4x70DGz7RlDpri<k3XcI;<Mp8y{Mv_Ld#y;D? Pf1Y+ht!=%&x~AY41H=h* diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kuala_Lumpur b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kuala_Lumpur deleted file mode 100644 index 612b01e71cf873b7f8a80d25d7906d77aa91ca5c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 383 zcmWHE%1kq2zzaBmvK&CH&;TUbnp+p|O81*^fa^)Zsm)IlPEU;Ixa5)hL2Tkzj{5)q z|1&Z%v#_$Uva>TV#D@XZGbF|`urM$r6@ZLLS777;kqkgGvw}g0fuU{!g9HOZK?8$~ zk8cP=Fc51Sn1is90f;mPk(NMg!4N`%LxJx2UuPD&3Pgh(45C4f2GJmggJ_WBK{Ut% cAR6Qekb6NM0nzn9F`9XX%LeErJ6#Jd04>j8q5uE@ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kuching b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kuching deleted file mode 100644 index c86750cb7d512966b1a8b19cb44531a618b00930..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 483 zcmWHE%1kq2zzc+dvTQ&sv9^nC!mf1pj{Vi@4f{V!2ONxD({S+Wf`G$z4;T(_yL{oO zf^fsp8SDYa8QmF<S6W>-@%RkG$>{wTP96E*aN6c`!0Cw*43|7|Kh*#K|DTbW2?eq+ zGcz!x7l0g+S;4@<z))(y$i=`=(7+(Tz)&}VK?K6~@eN_nHZV6f0Fo9)U=ql(WC$U_ z8$jFtgS-NwLEZt;ATNPwptnFY$ZKF4=sge(@*<c9dJ{y0yb7j)-UZPhFN0~Iw?Q<> p>mVBBeGm-_0uT)f1~3f_3J?tn4v?Sgfov)V36~8pi0pJNxB$;9wBrB( diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kuwait b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Kuwait deleted file mode 100644 index 2aea25f8c210369e0b805d0dd5f0e899190c2340..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 165 zcmWHE%1kq2zzdjwvLMWHRoZMz{r~^}85tQEw9kO_Xc;iD`1pn}Xd4(agpgno(2)Ni S(?Dk6Hj&E)Xs(^EF&6;xtQkK5 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Macao b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Macao deleted file mode 100644 index cac65063d0dbf48e37c547fba3b67f34110d5a90..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1227 zcmd7RPe>F|0LSq+?!R0$N(#IcMKK|v1<`m2O@$@W40a(XO1(se)e!wZEJXxCBAxUQ zMIC~%s6$abB0QF4iDlZdnc5$B(b{~O+N$ODzC+zS)UA22pU1#n_V?Y$&W63~#k^18 z_uG(``;v1FyP7*gM^)$e)1hax54S(>nXBu%e7*Z+{VBWWMB08;eoOUky=nIysZy^? z!zxx(sbc9FJD%5T$7B8Wo74llU$)zCyGGT(wYVC*e@_jad8FR8w5s<tYt)BhC)LNI z95r0qVkZ`+RI;?qNv5~Rk!2U0kyxP|%^Yw($vpXau*ONXj>#__jpo?#7g9Of%&$A{ z%JK8X=C`tLYhqu%Il26fH5HmLzpsi~>80U<X<wZ+J-MM^X1Ls%9jJAFbnTHp+c!IN zx65Sa%1TExuaHL6=VTr9O3&`3<E>6eU&w3vH+rnV>Vz3MyUEJ-cbM5zPpn|#hMCjX zX5~I^G8bPevGNZ!I)*1pAH(aL=NSIKK0@q2%+GG07G5Emt{Mx3h+Y)Ad>V`Xyysq3 z9T64bh$viFEDDQDL`7wUFABpDk$>1UqaSufwsqC}A{!$+BU>YTBby_;BikeUBMl%O zxat;=9$a-3NEb*ONFPWeNGC`uNH0h;NH<73NIytJNJp-^C8Q@;-4xOl(iYMe(iqYi z(i+km(j3wq(jL+u(jd|y(jw9$(xj{I5@{3Z6KNFb6x~+2&?}E_7U&jf7wH#i80i>k h8R^+oH;r`ds@q2TMjA&tM_R}Kt@oh*AFQ>4zW`b`JQ@H1 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Macau b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Macau deleted file mode 100644 index cac65063d0dbf48e37c547fba3b67f34110d5a90..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1227 zcmd7RPe>F|0LSq+?!R0$N(#IcMKK|v1<`m2O@$@W40a(XO1(se)e!wZEJXxCBAxUQ zMIC~%s6$abB0QF4iDlZdnc5$B(b{~O+N$ODzC+zS)UA22pU1#n_V?Y$&W63~#k^18 z_uG(``;v1FyP7*gM^)$e)1hax54S(>nXBu%e7*Z+{VBWWMB08;eoOUky=nIysZy^? z!zxx(sbc9FJD%5T$7B8Wo74llU$)zCyGGT(wYVC*e@_jad8FR8w5s<tYt)BhC)LNI z95r0qVkZ`+RI;?qNv5~Rk!2U0kyxP|%^Yw($vpXau*ONXj>#__jpo?#7g9Of%&$A{ z%JK8X=C`tLYhqu%Il26fH5HmLzpsi~>80U<X<wZ+J-MM^X1Ls%9jJAFbnTHp+c!IN zx65Sa%1TExuaHL6=VTr9O3&`3<E>6eU&w3vH+rnV>Vz3MyUEJ-cbM5zPpn|#hMCjX zX5~I^G8bPevGNZ!I)*1pAH(aL=NSIKK0@q2%+GG07G5Emt{Mx3h+Y)Ad>V`Xyysq3 z9T64bh$viFEDDQDL`7wUFABpDk$>1UqaSufwsqC}A{!$+BU>YTBby_;BikeUBMl%O zxat;=9$a-3NEb*ONFPWeNGC`uNH0h;NH<73NIytJNJp-^C8Q@;-4xOl(iYMe(iqYi z(i+km(j3wq(jL+u(jd|y(jw9$(xj{I5@{3Z6KNFb6x~+2&?}E_7U&jf7wH#i80i>k h8R^+oH;r`ds@q2TMjA&tM_R}Kt@oh*AFQ>4zW`b`JQ@H1 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Magadan b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Magadan deleted file mode 100644 index b4fcac18e3540f029f01bbf2751045b3983d96fa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1222 zcmd7QPe_wt9Ki8sZMLNzB*;Ilm9}izQnzKx+FaH$v28SD5LrRcAE;e^L<gyZhw2b% zU82K~5-PM<(ZM9d!wx}*BtoQvbP%e81o04FieNq8*9IfHbnAI}_j&icFE4DrZ)V{9 zxsdwns`|YfH*#I`q#-=^;=#n?I^XVeZGE;-=eqE&?)&}j`lWm6hK0Gp`dM$<Jrj@( z`6ls<u9c0$cG+}gSsJsSrRn&4*_?PS-pEVY;(sj7?wo9`x+y-#l=dx;>usOLRm<QJ z)iQrWZ+~@J`zNz{$HNo4^-fB+U5n}VOYJ&vrcnn^CM9&yCp){^q@#b0?DEt|IQT`v zKfg(*+o?N0%*&o1OM36jltdQZ=;)(4-8KDG$F5K6eYxAZ`|Mr4|7u<i^bG3w>05HJ zc|iBXMGjR&b+5NydcPi%K6{7sy^YA>kF}C`=8@!VNT)`Ml1bzjkGe<IP_bCF*;lO` zj*7BlwX^I?`HerXT~3EXsgYCs#lvIDTu&5iE~RqMRdwmJv|}?nrDv3RrnIlBlc|jI z2Lt8|nKQ`Clx<~Y{$Z}>=M<SOGGAW9jFCAbv$izzMrMx89hp5cf20AV1Ed9{2c!w4 z3#1LC52O*K6QmWS7faI&(hZAtEKNU1Lr6zROGr;hQ%F}xTS#9>V@PL6Ye;WMbC#w% zq&-X1AJQPwA<`n!Bhn<&CDJC+C(<a=Dbgy^E7B~|Ez+)~=@)6((sYcpjP#5&jdYE) Wjr7eLGA;b?jaNoZ^s&}pu<{q*izCbc diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Makassar b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Makassar deleted file mode 100644 index 556ba866933d37f3cfcf8042045d64e209bae30f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 254 zcmWHE%1kq2zzbM_vaCQXy6{u%gk54+C!Fq(ZMYQnu7Ht=87P<k0i+v90@(!(3>*v$ zbrTqPz-$2@-w+00Al5dp0AfpqaL*7&h7c00{0{^mYe6)~Y7h;w9z;{%1TK(6bS=05 Dzv?@= diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Manila b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Manila deleted file mode 100644 index f4f4b04efa2b6a442d4072b3899f4dae69bdd771..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 328 zcmWHE%1kq2zzaBmvaCQX&;TS3&iT@CNX($%^rz<x7gnkkJj$_Tcyx8q2mVsG27$Dy z4@`_q%s|Y@^#8y72cUX}x(SRd3=9Pg3>+Xf0}q7l;~T;d-~z<KAq-wX975O`TtLIv zfLP!^5Qsdy1E#Cx?I(cvAZLMSkkddk$ax?d<U|k+aweDtIu+z9kaIya$jOY%Ow24m W%)|_Hb728UjyRWd0llDW!36+57-4z< diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Muscat b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Muscat deleted file mode 100644 index fc0a589e2b22acd9a76e402f0e7ef3c7b0547148..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 165 zcmWHE%1kq2zzdjwvLMW{@YBo{_5c6>XJlkxFunoOW8uKS;^P~_plx8n5JG}UKtuk6 SOaqyL+e9uKpt*LsCR_liP#c>7 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Nicosia b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Nicosia deleted file mode 100644 index f7f10ab7665e94ca44fd8cd98a362cd4b304eff1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2002 zcmdVaZAeuI9LMqNOjy@ye{0UQ>qF(rhpu|nY}s_Jnc9QbPV-i-GEb#fYtAi8r(5m5 z$Yg}XzY-#9P-GGju7RsTPxL@E2zOwMF+w`6v5iOxDx!vL=X;=6dll@>&gI_E<)ZKY z-(P6e#&DkJUr&tl3vZr?^XB{bW1l8}H+J}I+dH(^ihWjRkGpWq7~flHPS|zFdZp86 zO6yW9Zo{ZKvC1|k1t;6D=3h4AQ!kmXP3kogqK}#h54()l@9s1w|JZ1}aiziZo$Is` zPwudj4u!4c?s_|A+d^wfQ@K5LO{O)iBEwEC8fU%fkF}@!MywgJ!**IstdaKEYo`A; zY-Id&-^{%FgE4bp(De6yV`TN5GP67P897_`nt{4jBe$mC&I|6b@{84;m9@nxNNTZX z=e5i1(TL3P_2`_TbyE0Oo6bF7B5&WS)}p>zEj~L}-|3pK^A0BJyWv!w-&rW{mBnaD zolh1_|3gblMx`v~do54BE#)J>%cAH@vS{$SEWUeGmh_*HiW?U-xVu{_Pae^w&COzT z@6cr{cj^00^;-2-lZGnFb$LRiuJC8*iYEcBjxUqypC{@EkJDw<=|{TyrdQS+j+2^! z`?5CjP-=Sy#jL$4>$cz1_4CfihMF5%mvTVri~BYF^0(TMq}uT3er+6W(T&$Tbkk5s zKRmu#o33q^kG?F{=DsTVxG_aP=_-)T%Zj8WoFH3rlVxk^Q)!L!NLx<4wmtY&+9y2G zcI&EijQpaXo$8a%2hZxZ1DADs|5y4&N3TY9NA#tr7kfpI`A=USPs&1WF*6V~#^Xtx z;u-t=lV2)=Ax~*(6(1q~Dk{qT2))2<|Lr{7H~-F!BX^G6I&$yG%_Db@+&*&uNCQX* zNDD|0NE1jGNE@zBA4nreCrB$uFGw>;H%L23KS)DJM@UOZPe@ZpS4dk(U#?DLNM}fE zNN-4UNOwqkNPkF!NQX#^NRLR9NS8>PNT04wqe!Q&POC_-NV7<{NV`bCNW)0SNXtmi zNYhByNZUx?NaIN7u1@Pn@2*bsNcTwlNdL$NAUl9;0kQ|kCLp_jYy+|n$VMPL;p%J! zvKOw-W+1zPYzML*$c7+0f@}%0C&;ECyMk;BvM<QSAUlI>4YD_`&gLMygKQ77Kgb3l zJA`ZzvPZ}!A-jZZ6S7apMj<<eY!$LsuFhs5yXER^7qVZ-h9NtKY#Fj=$fn`{b=SPk a%w^><c>Z91c0qO^C*L2;4Y=QCdH(?jq|NOB diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Novokuznetsk b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Novokuznetsk deleted file mode 100644 index d983276119c95872882589a9fdd829eb1f86f606..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1165 zcmd7QPe_w-9LMqBa+Wy>FXd{jmdln->)Wcin%b5v^IuS`gZ-iCj~EC^f2bf($O<B2 zQC*^&BO)TcQC-5rsE7_y5K#w-k|gMmb?6ci>-T<4SkR?g&)8nio@b1)&pW;SV0Xm) z^_cnlYSPMi`7LiC_h4u&FgtW8Gsl}X6(vLE72n?sct5?)%pLWZc_TYAzTqC7f4fWl z*V}Z#g}5#}RjYwszb@K2ODo&+8jOF{#o;ln^1ak0p2r$;f059)_p)^SU84HLxkUA= zM^f|To`mmbr8aw2>aLuXWrN3M`OzMc{avzR*PuoY@79%#-MVUPQdj#oX*3el=+7FB z`4SR)Tc&G%RLa`n35}1srQwE08Xta?rZb;q-L+?uIPgM}r^j`D>aH~Jd#W3%E=#KU zrfw`gCN079+A?uTTZ?+N_4yHP`><Kt?`+eKk&}tei>X|HKA(3LO`CkUiwhppXB50C zyz%F`{g~UBEjj+!^d4i+`vzPk#_a7gWmB(HS6ueW<Y&0s(U~@3iP~q(KI{1c<KjsF z!+!SX=h+b1kuPCOWKRw@b+o%8+amjNurabTvNf_dvN^IlvOTgt(g4x{(gM;0(gf0l zqiqA}18Kz3c7n8m^nx^lbc3{m^n)~nbcD2o^n^5pbcM9#X!}AMbF`fyts%W3%^}?( z?IHak4I&*PEh0T4O(I<)Z6bXljXK&+kyagTuSl~<w@AB4zu0fL|KA!eZLmo<)zz2& E0^gSc761SM diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Novosibirsk b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Novosibirsk deleted file mode 100644 index e0ee5fcea981010008b7b9dc3af1cdd53363128c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1221 zcmd7QUr19?9Ki9joK9wh1f_GWEVX6Rx~`h5sh!d#I%g20s0>2;3q>O&Dgq6YULr>M z5D|oI^b~QRKMyhJP(6+wLhNBkNxk$^QND!LI^SzT4?*<SIoy5j4wnnt@0-|n{76vz zak+n;b{M%YAJ2PgAEu|Pm-tVmmR4p&MQOUc;_Iv7%J-8gPrgi4<@Tq%*<)(i-Mz|p zt6MF<5>YEIG^pwmKDDxMky;fisG7(pRU4RAb>5e1b=foJcYd_|GjFUl?_SILvzKN4 z#8YeS^ZQodLB<OF=oJl_v}_z3lj|;x%JqY1q;=@1Y&vjF2Tz~W8(IhT#$7x0Cf{xy z3O4D`_plCodu4d4N^hRE<d*C=9my}2Eq6S!_3?~s8=aL~Z%#^icuH;?`K-4`pUC!s z3EfdQE~D*_^p4^Y*;#W#cYe67yNb^1t``?|_uD=lyEmYFa_40HYE&m;U#vaXb9$&y zC^(81%x!1!Z@a|Bmr_^BU$@icbP5sA@;@gI3Ui+vc9aUypA-w{Kj%*z=49@f{v`K2 z(-TjKfE6-V*j&xLMmWq8j>JDq)%=hGlSQV>TbM91WfqgRHPc2Wj!d1!<dNwk1t1k5 zB_K5*MIcomWgvARg&>t6r69G~nqrV@kaBEIJxD=FMYg6S7BwM7Aypw|A$1{zA(bJe zA+;gJA=TNM@{sy$O@T;-NQp>|NRddDNSR2TNTEojNU2DzNU=z@NV!P8wx(dDVp~%( eQZrICQZ-UGQa4gK4w)wY-^$%Bruw$VX7^8#1sDDR diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Omsk b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Omsk deleted file mode 100644 index b29b7693118fb1ed214adb8a4e686172d0914b2f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1207 zcmd7QUr1A77=ZD!oHf*71f_FYmf5mp9apa9zuwd-%UL5vL>NR?A{0c3R1^~CT||UI zM9{?ODuS%M2%$IVDkKV|8xex+qKg#Dn=o77b8Il8o9;S?v){Mx91d*nlRVOMDrEij z$p5|DWMu6fej;PfM&|6*fy=2iMWfzA&*QSf@1JfIeV$4ArhMMwiJp{yyiZFWc5CU~ z!@BlbOxIni)w0t;UEf)v8{#XqyzZxN49;nV|ATJIf2RTWq6Fq=W%JCJMCJKgiOR{h zvgOrF2|gW_t@lTyYG_EdT^*F|y?tVz=$7iEH#KzbjP7XY)tv_qXie!M4Tq{Vycp4l zf4@Ygi*@&cEw$r6v~FsZ)Iab^!}ED*99)n+cixMfoR+-<U$rUvLYliKwWVTMqRnI4 znmZtE<+rtM_MXOaE^6$}72Wr-Q`;YPX?)^>bX<>Wvi+OgpH8P;Im?z#cW&0Xd_~rm z>>GcsJ#M#UwY=uvZB1Baef+G;V_C^#Rzc=7v*R*5nP)8XOlIFIh<7Bdpj~6GUFHh& zGRw7eB>!Qg=GUYdD>7PM!+4PqBV%?nqejM!j2sy|GJ0hENCHR(ND4>}ND@dENE%2U zNFqokNGgsd7bF=Z8%L84k`Iy)k`a;;k`s~?k`<B`k{6N~k{Oa3lAEJR4$02Zq=)2( zB#2~)q=@8*B#C5+q>1E-B#LB;q>AK<B#UJ0XwpUUbu<Yh86znpIU`9US!2Ix;6G10 MuimuYSQXCu1%lfY$^ZZW diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Oral b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Oral deleted file mode 100644 index ad1f9ca1ca321f6852d1d654d1fb0b14c556330f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1005 zcmd7QPe_w-9LMqB)F;Q3@Q`kES<9^DmO7^!v!>ZaI!qYxKp+L*LkaykNl}NugF}!y zM0JV|MbaT67SySt4jn~)hi+>84qZBQF*=CJ`o14Mbnw!x=izx?;~9+cyg&Zb<>{Q+ z^@!{|9aj0g??wE<>f6PZN_*-~tt0j+84bTqMmK&wiG5$M#aB|v&ZV2R#QUn<|MG_I zdOU3p+&yOx-accK*GBB2^J&{%PT0exR@;-=vPTlX-O-jGF6G4~^(!LBzHLhHt!L8v z<!dGVc}+5JmgV^3N9lW5lm6;c8MuC5vKQxM@WLyXn^|x}qxanK*{d$!HRB4oNmtnN zT`_S*ifaWovRRfBA7bw0O23qz=VkO=n~cpz<<z5f8Nak4r>lG2Y`tC&H8eIgHt6Z? z**TlToZdFO+&#~jY!B}xoi$CyOjJzR7+*rI+>PG<elk%B>9@sk)3*J*Jn5TEc1W+h zUIo2)wR(g&{C_B+f4)u)qzFGk6{HMOCr}F^m5@?MEu<Jy4Jn7zLkc1lk&;MFq$pAq zDT~xa3I}Rsq%=}HP>Ungk@84=WC6$ukR>2%Pz;MeR)H)7SqHKZWF>*R6l5)dx)@|N j$a0YNAPYiPge(bJ6S62|RXD3n{;y?4O1ikQzI@~luEgG{ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Phnom_Penh b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Phnom_Penh deleted file mode 100644 index c292ac5b5f489a88bf10a1263b14e7412479d9e7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 199 zcmWHE%1kq2zzdjxvLMXU03;S=r5~yP|NlQD6B7eNoDEO}M6xh2Bo#1l`1pn}I03P? lfjL762?hhr`yaNg^$3UtSpYJ%9>^wW36~AfDmz_sE&#dsBrE^` diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Pontianak b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Pontianak deleted file mode 100644 index 12ce24cbeae404efe6921081d21289be452ff88d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 353 zcmWHE%1kq2zzaBlvg|-C-~GRjVVBr_hSQZxI4*^~E4XfRjN{gSHHI%+_jM@VDrsP3 zVrF7tVr64sNNWI@2qak;7&0pufF{&UVBlk5C}?010+V743`qqH(muW+3;{r_ZD4L} z03<De*n%P4GsF={I5C8f;JE)l0CFIR200Q$gB%K?L5>B{AP0kJkfT8~$l)M|(!}vx KKp*Iua{&O~6I|B- diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Pyongyang b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Pyongyang deleted file mode 100644 index 7ad7e0b2cf8fa4fc844fe8cc9c58e4f3018cead1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 237 zcmWHE%1kq2zzbM`vMfN%(|!HpoJr5beq7Q|EC@ZvR1o#1w1AO`nUR@+q4WvJi1H4Q z!nz3z9AJ{g$2Ww*J2-^F3y4EVu;@P!fGh*iAPYe>$Wo9UAd5jXNtSZ~U7>5q1ppt4 BHM0N! diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Qatar b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Qatar deleted file mode 100644 index 63188b269d077e29f48a42a03c2a52aefdb61320..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 199 zcmWHE%1kq2zzdjxvLMW}@Y7ramaa($>i_@$&&b5Yz+eyn(rDqpz{0?wWx&AU;~T=D kZD0b##tb1O7z{M;Kge*9X&?(gG*Omt*#NDw(>3M-02;d=O#lD@ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Qostanay b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Qostanay deleted file mode 100644 index 73b9d963efc99f7af196755a6b2be015d9cb7a67..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1011 zcmd7QPe_w-9LMqB=AZV*Ll^VUG@q<|)cLPD$J9C3Wq45dA_E~N>|jFBNfZSIAw~ps zt5bB4ln&8hLY*q`&@t$H@Fv>DO9UROi`baI_hW}0x^!y~+iQEC@i6xO<nG*CjG4ba z!hg=jt-Qbdy5&*+-F7+C=sqr8Y2I_10=rJr>Cdg^Z$C;c2d>lld9@VzP}H_JE86~I zQLjFk(~gZPb?%SqwS2F3PDk{5szGl=%X%|%qFv#y>ehwD{q<YAkIxD{YukmM{Uho9 z^hKg?_oQ!USNfm5l!4+?8C)*P(87w`n%~mc(z*^$Jka>;ypFUlXd*VLiE>txk-Q`i zyLI#|En^=;I)30t>Xj=K@BNZ~7?jE9$CA1GU2YeRZdNK4pTDNI#&3_h`l{nnpz1^Q z1^Yf2G-iB<|0S6*wZ>${1dPcQd=0!B`&xY_D?WSm;+q#&`R4RY&P0de_Bmpo32tVL z&wJ$lA%^|^6@nm9xC>#BI7lE*8wm-8#6p50(U5RRJR~3z5ebRJM1mqwk+4WyBrp=$ z(}qT3Bf&jwbR;|y9~l5L0%Qot7?43Aqd<m%i~|`6G7@Aco^~wAU_9+;kl`TXK?a13 d2pJMGCS*{^sE}ddrfu@yjVqM0YfJYhLg(fL+z9{x diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Qyzylorda b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Qyzylorda deleted file mode 100644 index c2fe4c144c82b300ff126ed44098ee2bf8d752d3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1025 zcmd7QKWGzS9Eb5Y*G6N~!NvaZtUdqr+Q!xzn~>HdjZ1K-@S_BTl0t@B5S&Vjg%%1D zy6C1Z;t*6Eq(cgIQlW#R;BRmcinw$U!9iW5hV*?-hZMSWYeMdm+=YYW`4*>c&nC>i zkJ$gSNh|M<zv^18zJ6ZMpYZS3+B-MBj>x*#@#j~y^V`o_*Ou>{{BXDCzOCq~wFT{d zI;*E2+|-`s>+0PZ)ib35Jv-s*xlEg$kJt5r`$KzUU)2xC#Q*(Q`nGq<{fm#K|C8ni z-hY(%#-?0+u`Yv;p2<+<p<J4;$nea9T%N9KVs1&VWbf(7<g_NcXEc=<*HpcrX}2Wl zFMT??lasM`QN6n5N#><5**A{lR*%W}lWoc0`YzWhMoaGJ>Pn;02stgSEslMLk2F1x zh9k`%_q>ldjxpIXe@;4YT8$})i5OEXhuSzAdu%>akWg@y^Z&lX)rlKL6CWP2ucUpY zxS25_9;SGJBK8L~sDhN?F4RE^A(aAcDWn!s45@~cL+T*~k%~x3q$W}nsfv_E>LP`a z%1G%zTN^2kR1dV}k^0C2kQE?HK-PdP0$ByJ3}hY1LXedpOF`BWXcvR5CeSViSr4)x jWJSo5kToHTLRN(=3t1PkFkG>14&Tb689Tk)U^2Q3<g(wT diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Rangoon b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Rangoon deleted file mode 100644 index dd77395b05a89b875683f8aa82062748f2ed504c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 268 zcmWHE%1kq2zzbM`vLGzf03;TEDh@pT>5s(4S?M3@|NsBb$i&RV#J~`x50nFuEDQ|M z84Mf@40RJ2_#kW_-w=i%Al5c8Gd2K{mJA^zSPHb`f7rIpiy#_gIfw>107Qcv0kXFq U$R^7nTsB}w+3A{D85?i`02U)YF8}}l diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Riyadh b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Riyadh deleted file mode 100644 index 2aea25f8c210369e0b805d0dd5f0e899190c2340..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 165 zcmWHE%1kq2zzdjwvLMWHRoZMz{r~^}85tQEw9kO_Xc;iD`1pn}Xd4(agpgno(2)Ni S(?Dk6Hj&E)Xs(^EF&6;xtQkK5 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Saigon b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Saigon deleted file mode 100644 index e2934e371b6d5cf80244d8d55594f7094bc9cbb8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 351 zcmWHE%1kq2zzev5vTQ&s+R@|OFmbUq*ICnN4HqNN6<o5m`*780x4@HaPa59p&tTxP zJ<d@7|NnnRCT12UW*}r@U`PQQo&1e~g@GZdfPs^Np`d|*mw};f0)rq##K$*;Apk^Z z8<+#J1rS>@gplAYppE}QP6N>(=YeRD6G1e{nIIbER1ghvE{Fy>8AOAe4FVvigFrn{ Qj0(=@vH^O=PS>0Z0O4(7+W-In diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Sakhalin b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Sakhalin deleted file mode 100644 index 485459ce0397787a099064952c66989712ae707f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1202 zcmd7QO-R#W9KiA4+I-0hBFb4y)6|wNbz5bcFZr6RZ8TzZ=mmn_uw5RaLlo!(Wf4hq z=p<qt5(^?iB4q3!B-FtoBsz>Py&by5bCAd&*7N<FP*8_%{r>#-{qH&aVf%fO2m4Nj z<&U%U=V_NM&#Nz+=aaL+3A4t(Gf`ZUn(`K&e(9aR)n4*xG_f{2JGE}6GU3Yv)%yDt zs&r(PDjRaE4HxEAdFrF8IP_X=j6PMB&6BDsa8FhHhSjEJ*OcG$*!bth&E^l|Qgd#f z)V#WCwoIQlfk!E`_0C~adoyn8F14BZv-Ku;yxfG2#8mi<Uu|oxQ``4@^^Vdq-4L4B z4c|pK`iiCT%{$%n?W^p{OzY-sR$9j1N^3eJZG%r__wcB+pBR&li)r22b49w2jp**` zKI!S|*L(7!(pz~{_kKR5BkoQec@fcj-&g7AgMg0BbV&UA3Z0Cm&4DiyGLXyVT<#?c zmnZL+E5G2kFZl(3yF3LRkI3LN{^I@{VxR9$xe7&wAIkE@&&3m$JsG+!D;LgV@uUQT zO%e!&?H#grke7&yN&dq&?T^T@QOZ_%37e&Cm$G4}cFUAaQ?^anIA!aU%~Q5d5kOHu zkwDQv5kXNwkwMWx5kgVo)JmafVG!fgs-eiC=%EOrD56NBXrhRssG`WC=%NUtD5FSo zYPC_sIkoC2@)-0{1TrXOkjS8sK_r7p2ALF{3_>YN8KhFQGKh6*)l%d-wR$OnDT*nQ a88lNwQ&ckp*24cOyQsxtZ>tT3ihckL$`3{W diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Samarkand b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Samarkand deleted file mode 100644 index 030d47ce0785f3bdb75314e0d03fb20c3e0172d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 577 zcmcK0yGz4R6oB!Qw$ajdaM3o#M|?&sf{672rF0U93K;@|I5-sqS8)-#)JgvYhe9`T zh=ZGhtKe{U2NxFy9n?jz#QPON1Q!PrZhqlH!aZNOwOe11U$5S;UB}3K-<fl?eA(_) z`~Bl+pm6Qw(-&U;{k2tie2JVp-y6I=h}^5D4xR7o@M&E~PBwM)a9zE<RUO-&)$y9E z6Xl#v7CSoSKI?S$UVS?o_-`M<%)?XAh~wBwBvZ+Rx$T}Gw=Gh+;Xo@@Nr|ilk`@Vf ztQ=1<&+nbuMkvMkMYBp~E%A|vWrcs3)Ep#cT4ZAWz|_d($n;%J0i*&_0;z!%L8>5S pkUB^qq!LmJsf83nsv+f&dPu>prXo@j8|Li)S2I&Kc`I|J%qQNwd4B)^ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Seoul b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Seoul deleted file mode 100644 index 96199e73e73aafacd89e48cb2855a96d7a134e1d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 617 zcmcK0&npB`0KoA#c14?7Qk#qN;~<AkiGwRH?4p>H)21*|8mE0H7m3)~$w^8n2PbF# z11Bj5<7Z79v(sWd<uJMMzLSHKa`0ZS@0<57^FHSE!d$QTb+qc+I=vdVTqU>tRCqDe zrQF$~?N;}4SK)_!eU|oa+)Z_Rl=SZWlDaRvd8LVN^{{vxJ~p>l{!C1ko3cUBW6PlY zZdH<#vT}N9J-znH=fe~0<vb;;>${ffUzTkLIj4PT-sxB!bUMdJ9HS;4`<_Paj~Sf_ zk+0|1^BW>A#EK*IS7G01i1zwqZHGN4*)daOrc5!aS7z80<{zH@sRvJ|JfA{9VTh_J zC>#_L3JZmX!b2gVFj1%|Tof`28-*^a=A#fs)r=HM3MYk>!b+h<3SJ5^g_-^%bwazR G2NGX5oeD|- diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Shanghai b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Shanghai deleted file mode 100644 index 91f6f8bc2e234bafd484146986bdb289082c3588..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 561 zcmbu*zb^w}9LMo*sb7uZVlR)P+QDKF36WCLNNV90hMH8mol%_2lQ6N|X0Wt&|A0ig zYPz+k{ufWWnRwpMAJ9ZRm*-x?E%$l*C$;LT3_WT4b=2NzZC~|=C*8PAnz!SMZcTj$ zt?sL|$L>r!EJ$Z#%XIIr^!v`U`Pj?IXSr#5n@#x|uLk|}K=-#pGy8I==4y|zif-%k z``2;iyrCBIr}1LxMlH>RUUvCRWd{{6H&If#PQe>V40%K@diI|riW5nZK+9zLz?b5# zy+^+If0*`TPqbFdBNLIC$W&ym(@sWaJMDC2K9T^*fTTcjAW4ucNE)Zj!x|DHnUGXS cE+iR}4M~UOLlQb|MkJ;4e>qdO>B@TQ7g9&Lh5!Hn diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Singapore b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Singapore deleted file mode 100644 index 2364b2178b03853b1771cb3f34b964fdb82e2e91..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 383 zcmWHE%1kq2zzaBmvK&CH&;TUbnp+p|O81*^fa^)Zsm)IlPEU;Ixa5)hL2Tkzj{5)q z|1&Z%v#_$Uva>TVB*p^OgGd$zhNJ?J5$OtyJRp(*NM=?r2r)3!O<<5<U?^x{kn!;i zVF(6dZ3A-<HZlN_#vsxXh%FdGNN_079sldhf)|5mkb^-q$k8Ag<ZuuTay*Czc>qL% aJOOeq$Ri-S9w<gL&v4lQy=13r!36*{S756E diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Srednekolymsk b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Srednekolymsk deleted file mode 100644 index 261a9832b3ee4bda7c9935b566a7f7f0e6489e97..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1208 zcmd7QPe_wt9Ki8sZRS!B68NvV(v~e->fUK)Z7$PHbQ=xXC96|^pmzBY9i$E(szYRd z4$)ym1r=JX=wK4zVTZs&5+Tw-ItbZ8f_MloMX;XlYl9J8y7j!g`@DPJmlw9*H#KtR zbV&VmmH*!DHF90~w61;m<-^IPD*v8jb!|FV<39Vo=KKAg+Le3By2bh2ra52IGZU2h zY@>MZZj{aAPT6vCRT|QtrSa$o*&3S_U-*@53p|k~Pe!(vUlYG;TKiWg^p52T)jWDw zH7{J%JKtQ;fvL3K_2`&xxt-9hm!rDve47rQY|z&6xP;F6rM<gVI)*pMZf~V@T3@8| z=Qru{l<KaJ3$pjeirzOfE#bwtI`Vj4cfWq7qgST%{>)9?bLx&ha49Rj{iC|?#0@#v zG@|?aL=Kfi^nh<z2EHDVL1%{yz6;CHr)r5k_ey*&q!ZWkl8R-Q#`5{R!?|wlaFrAt z>r0Ei6yNys+U;^Fb*r9#cl?1e*ONJiTdB+oRZ;jX>^RI$;TdI~DeS9?cp{|&R?wUw zb6UJiIo4L{A4Y0^O`fqLqvbV>7a1`!W?M6AWZcNek+CDAN5+pNfMkHAfaHKAfn<TC zf#iWCf@FfEVrz0il3|gJtw{&T2T2IY2uTUa2}ugc3P}se3rP&g3`q^i&DJD`WM^yA zL-IosL^4EDL~=xuM6yKEMDj!uMKVQFMRG-wMY6Ru=_2{snuL*zk(7~~k))BVam+OE PpQl|GF|9{iEUWAnYp)@o diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Taipei b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Taipei deleted file mode 100644 index 24c43444b6751343d2915843d03e55753d4d7359..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 761 zcmcK1KPZH89LMqR`FoCmn=A^0GKfqDQI3Jm<e?~=l<jvYiS%0xSWNzmibWa8A_Gc^ z!QVR^$KlTZUknWD{NC(h@OyfmS3S@4ygyD`S7*8Wc#7@URC{M@`&etP*Sk)u-Wwax z`!x&Zpsr93{j27va#ez9ohp>~qC>H1bDSuWlg({)8fn$xc`;|*J#xO-p(2CBaxpP! zF58!Nv~NpYRXxacS-!d{2uRF3r{YPoI{q3ox6z>79b~EdjZFQpRBayLKICa?-8_d% zwdsFX=^riPejHU9;SufGSur^$GurEfl`F}W{HseO5V!v$N=u5!(73pHy0X6C_!}MZ zH968?Z(pq=&L1)*?CISxxkxS~8Ilc2hvY*NA{mjCNX{>9QY0&q7RiewMlvI*k=#gf zBs-EG$&XBc%z#XR%<-k21epby2AKz$2$>0)3YiO;jM~h`VLD_!WI|*{{KqLhcGr>$ F&nGsEUL61c diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Tashkent b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Tashkent deleted file mode 100644 index 32a9d7d0c9cbfa841cc4e922fd1b486a34b57370..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 591 zcmWHE%1kq2zzR5^qLM%w#1>d3+040h@p}VN_1Xnu5}O3XIW{VY|9m<@;^mVClD8!V zq|Rh6kls^vKxR$)0ogeb2jqG@56IV89Z<;8KA;#Qb3n<5_kgnXzXK}T?+>U-KRBSq zeer-g%U=ieFYg>Qp1cjH|Ns9#BQp~OvaljSHg<Lf28Zt;2e}0>urM$r6)*yw6q3Ne z10!J~j6e~P8Xw;f25kdVAT|eLGmusWMj!|w!NWlJ{0Dg&M1wpIG6Up!5Df|d5Df|h zFbxa{5Df|p5Df|t5Df|x5Df|#5Df|(5Df|-5Df|>5Df|_5Df|}5Df}25Df}65Df}A s5Df}E5Df}I5Df}M5Df}QFbxb$5Df}Y5M2*+JIw=?%LW+KcDklq0A1~R=>Px# diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Tbilisi b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Tbilisi deleted file mode 100644 index b608d79748884c4a8271e695fe4ed992a91fea65..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1035 zcmd6lJ!lj`7(i#^Mej!oi<sP9;!mPpE<ZXZcVX2_oCMS+!Xn3kK_P_+2o@=Vl@P&P zXBBJ=Rw@=^v4vQK6e9>)sFjuBWEvF(!Nw+utl!(@z{1AP9d_O@J1p$JSDm^xJEZ=4 zWwv+ALe_1!WO|Za_P%`B9kdnh*?k@FbbIoxX<zrkj&I6l*UCEgrf&1AORn?jZP#^w z-tE6L;||=cxr5iwyF-_K*F9NuJ(Zk0Jdklm@|*5x=DRDjW~U23)6>15Qgg-kAA`P^ zFHHY48w@;pXa?^-2#zh*&GGpgMqj<8Ph45D!=tld>Ed`;?yA|5p`LK$mv8;N(S9Rm zPi}PUQ>&Zy^jbn!9%s$y%4a=R-!NyEUu!edFsAV;9AE7GF>&_m+(HyZUQ1%f)@a@N z$JmujwaDPf_T%QUR5FoJsu;<?V3u{CRw<><1>PQ|e53X@=jM(lJ6mUb!<sXb7pkf{ zAydB|mb)x>i8m_c$)!~FAGF9<M78HD9z+jB5pP2iL={9=Oi>2W22lsm2T=&o2vG^q z2~i5s3Q-Hu3sDTw3{efy4N)Fbv_sTG^g|MWWB^G4k^>|ONEVPZAbCI%fn)+n1(Hil xNd}TlOi2fl4<sQ-Mv#;sIYE+wWCckprsM@l43ZgK5GVg>YUzr!H#S&G{{}x>-pT*~ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Tehran b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Tehran deleted file mode 100644 index 8cec5ad7de2f2c14dd4b0a6c375d7198ef7429b6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2582 zcmchYYfP499L66Mg&7_KDr+uXW>A2@`>OBl2?$bdK?RXRc}!GL6DS2rJfewdKnY<& ziidzg(ZV2aQb-f(1|iY#6i{Yv;wHmQ+)Ul*xi06|`jWw(_s5^>8hp8adm?8ojk6g4 z__fGP9n5D)!Sc2GT&uGlaBROEnCulWC_BJsQ0KUSC!^xE^P~{vV!Nqby`EC;!&0?- z>u&Y(>0SDjnirHuS+n%q6D_>5d+U)Kwkq!=oAg;wEque5X-nWOWwmtaQ6o~+XxHI# zOy5#5=1#P>U2jw3!Zta!evlYfHBgQ}m?tI_1nP;ITKTO`mHr72M8KR<{c4!E3iKbT zgM2Gg@YQ-L&xeUAb<<_Y(H0R}lCG!bJE&<}D&_RF@gi(VhYp{esAhyF=!l88)lAQQ zGIFS!i0a>>qm5ZAy30|<{E;nQKbs}rsC5yuj-1f5izll&x!rPZMw*zH;-=@vA5w3| zl<5T_78NV5$b}wpV$pLhda+Z!T6{lP#&tG{`1VG*q&Y$?t?ALr$~UXG_FCogoGOu! z9;Xvm-c(7k1@i5vVd9-hL*)uvu~_+1giaoONu@Ys$dr3dBDJGRzuW4s-aGB5S5?=l zw6Ya)b>UsHCaYMl-Qc0tC0>^67t9xSz3hA2_v-UlzYW7jU>)YCy<zwY!_hD%huaM> z3=v>B8-~BMd-~z;r%sDBBF)Fc$7=O4KS!I-C_LsB`R^-hc(k$}^9xG@u{Qj7EDpr# zKrD|m*9T&OAXW%si6GVpVv(e|N)XEgu}%;R1+h{PO9io35Q_z|S`f<xv0e}h2C-rg zO9ruK(p)r%RfAYIh;@TlIEa;lSUQNcgIGL>)q_|*i1mXo0E7h~OaNg62qQpP0m2Lr zc7QMhge4$M0bvUWV?bB~!W<CxfG`MzMWksG2%A6{1;Q#2W`VE^gkc~o17R8n+dvox z!a5M<fv^vRfgmg-O%p-b2*OAZR)R1Sgq<J^1z{-&Q$g4Y!dMX2f-o0^y&wz*VKE4k zNz-N!MuV^#gxMhM24Oe|%R!h9!gdhGgRmalFk>F?^q_0JH(Iu{ziGrX?7#0)$9!|& zQ0AMv?=sK0zK;2pi)(p*(9oOrR#ndawu3hIKg_?zJTr3{^Q_f_nP(>yGXH4qZr&e< z59htzubKTE-)Q!8huJg##CaR@JUbinyxY~xcl>#r_oo*EdGD;f#eV+LRQ3x>hBN<c zXDRbtTVj~+Ue(ULaA_OwJ#%7t?+qQu{=SKM?C<vsV*dH_^~{U<KlHz-=K=HLuKVnl zTutZw#aVCmzdTjRe(8}|<_C&8m><mD!MrSE2=hb9^~?{)hcW*uW;*Y$r?l`c7aQ3> z;^D~tH_uiwuW%aAyyD&s=9QgE%)f0<<bCu^H*Zz5kNv80H}=2VbDsIJoY~Ber#mvQ zUYX6jW?>fZ@1tFKpLp#g`zLL|?Ef&LoB651Y0PUK+?m(@b(neGjYGVDY_szIso@Iy zx;l>i`Z8DM4TS~FPiF-)Z(QHRyeX-X_s_8rywA)q*l!NXVE?Se%KY4mRm^{JiD%x@ zr;~ZhotwPRcdX!j;o?yCFV+{ce@V?`e)+&<=D+4=FmKItV&1mq3Eu6A+j;*s*Ps30 y!|MK*x8&n}2S57j|INF&-vqv){k*K>tUl(?=KI;tGsHI5+cL^C#4^Tevftk%?{cC5 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Tel_Aviv b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Tel_Aviv deleted file mode 100644 index 1ebd0664aa29c0abd722661f761031ec0304631c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2388 zcmd_qZ%kEn9LMqRO}t*foJ^@^$e%I_#mnWdRFaCKU?8`+F@%6)1ZE)}lgJeEm)c)U zw-&XgqFcm9rNg4O=Au^9Xd}28i&V_hACLmvX$1;P?Yz(0SnE+wdeZmq+}GLVDWA8m za6?6+{Nn<xUwF6%>)}0ASznEwjORPnc1y=ZvwV@dUv>5msW0ETB3++HNcY~I;%{k^ zuXfeR$rpRo*X6CMr!rW23q7j$T!DNW_nA5sUM8n!UX;^AemT>YBz+&I$ywti`L3-? zooo778TB>teSV$%&|aZ_OevM08Z%Y@b<1R++LZGlC)Hr|VKq3oRa~|8hU;>xKXB|9 zEvPxsKkMf|wAoQb+MJ0K+Kqdvw6OL|#@r`r{o$QgwFvEXZ{&`nT2$8i{+mh~jhiEj zz4Hn^+AXrg8y!4iM1M2jzjdhFxb2fE-k6?YZGKCHf5EYGBlZP{f8oAWhP$-I8@DaS z@MIqM$7jB3BrLA-CdR*~CC$0wPY!9&l7DUXE(&m|McocPb*xm~-ZyUC;UCfOJW`}B ze&djycIaL0uAMvdCA9~QrJGaqW!@$&J$tV#&&<_V#BP#|@G*1c^gLNPTxPBsPL|B` zqk2~7^|HEszj^oD<C48Q(9CHFRcoHxr{`8*RNj(w^B&(Rb#G;so|kk?`LY-2_su?_ z@?)>n^MBv23PNMdf}VA1?P#!B*tT31^^BPJAJC+@t=lZAOPA7Dj+$EWJXu%Qr9Y77 zl(OPh{lTz7DNlP@uW$ya^>eHB_5B0tq09ODhT|RT;j^jwBX7Q?Do^;#jnC{>Rm~~p zqvcgffA$7*)0%pDtbD@U?A|EV8GYvCGjgTIJ+9YWh?gxh&gfgZX33KmKGL@y9+hof z2ld+5LR8(6r}d|5epB1`l<5xVHB%-(0h6zjZ&RI9ozq;?T=?I7M53J5|GGq8k^qtU z9*0XLEK;V6q%L*L{QEDHf6dPE$!hD#T46nTXuXIy91gzzdJ*yci^W~FF8_m1Cy?bK z>$9~Mh^!D<BC<wgk;p2MWg_cD7K*GCSt_ztTWhh%YLVq4>$SBOjI0=0GO}i5(a5Ti zWh3iG7LKeOSvs<IWbw%Ak>%T3>*pwdtyKY}1V{~#A|O>j%7D}XDFjjpq!dUkkYXU! zK+1vC11Shn5u_xxR!xwiAXP!ig46{m3{n}SG)Qfb;vm&Q%7fGgDG*X2q(rt>jgTVQ zT2(^IgwzQs6jCXqR7kCmVj<N+%7xSmDHun^kdkrK3@MteRW+n+9Cbqq$5A<?bR4xq ziicDWDIZclq<}~TkrE;`M2d)1(bg&>Qb${>kVqwwQX;iPipfz;q?{b}L<-7LQKY0C zHARZbQB|a@NL_8M!XlMLN{iGMDK1i7q`XLdkpd$XMoP?4W2DF&RYuCpQD<AL&>WSv ywMxxVYoyp5)keyV)Eg-{{y!@oWEFm4f|dH%oJ4n$J1H(9B{nDC<4$&ag8l@yuiuRT diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Thimbu b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Thimbu deleted file mode 100644 index fe409c7a2a40294af6bae4523492be88d38a97bc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 203 zcmWHE%1kq2zzdjxvLMWN^_ggiVxsSg`v3p`GcqwTFof`cH2Ov`umIT!3|v0GAq?6E krp5+9(u^U51fzi_{s$QkG7n@0h$hk+E*qd_cDiO<0C>Y6?EnA( diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Thimphu b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Thimphu deleted file mode 100644 index fe409c7a2a40294af6bae4523492be88d38a97bc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 203 zcmWHE%1kq2zzdjxvLMWN^_ggiVxsSg`v3p`GcqwTFof`cH2Ov`umIT!3|v0GAq?6E krp5+9(u^U51fzi_{s$QkG7n@0h$hk+E*qd_cDiO<0C>Y6?EnA( diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Tokyo b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Tokyo deleted file mode 100644 index 26f4d34d67b46513491f26c2e661c6e653cc130d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 309 zcmWHE%1kq2zyK^j5fBCeP9O%cc^ZJkbvvel>u)1J-1zaU;O1HD54YJFKHOd_`{B;B zM<4F?{Qtnr$OM5549(0y^$a}=7=fDWCNOY7NFU!21}_&N4h{iHGlFmk36A&=1gVFX r6o6=uW56`fK_D9BC=d;D7>EWr4om|b2%<rb1kq$Wlndx;T}v(iZ^UHp diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Tomsk b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Tomsk deleted file mode 100644 index 670e2ad2ce22f08d496b42363caa2e424121b20c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1221 zcmd7QUr19?9Ki9ryt=VT_)=PHWiDGft<$Qx+O%W3Y)%Ve5SCGBi9yhapg#l}TD?T< zp&%j%anwu1f&M&%(4~45A3}@}DXAWOu_zx3iFLl$gb}^;*16n$?#{hj*nZ#C!4o|p z<FCv8d$(E3b;;1Dy>FikPnRzXoXRXO%NnJw;gZrHZ~Dt-CNe7~J;ut>LmBT#uUhq> zL;3Ess@2z`YR$zOResW^)^;vc70I0PN580b!D&_LeXZ7eUaElkSp??Ziwz&&$*OZ# zW!3l#QT^(X2tLk=n(R$cd*h1OICxfUI@2q}u@15M@SqBvKBBhN_o%J=8`U=79u*Gx zRrqJMig=}nOckr`^A%#p$gGM^nj&`3BVuDSs{YxWY`8oxcix_m^7xc&9QbPOia(c4 z-Q!ks<&cawJ+*ch4#*b&Evseru9YabU?s*bS*;&Bt>nXQt8MhWY`-42Qps=PK;paA zm&@fG1xpqVvoP-{a^`)>yWw&c{c)I1(=?2I_xYbwM-6?Q?svEhqbqF`FMclWIP}iK zGhJz}d8VyBWduc7pAmi5@fyRSm*GhL!&LPT$uU`Ey1a!6BU5HEX<I#QWa7xwSxg?8 zK2iWu0a5}|15yN11yTl52T}-92~rADi>)pOsRk*>R@Z|Rgj9r-gw%u-g;a%<h17)< zhE#@>hSY`>XRE72%Cpt=Aq658A|)a<+Ug>aDv>ggI*~$=N|92LT9IOrYLRl0dTn*V jNX53gWTa-KXryYSY@}|aaO~4f{J)jEW4ii=+B)|yku?`w diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ujung_Pandang b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ujung_Pandang deleted file mode 100644 index 556ba866933d37f3cfcf8042045d64e209bae30f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 254 zcmWHE%1kq2zzbM_vaCQXy6{u%gk54+C!Fq(ZMYQnu7Ht=87P<k0i+v90@(!(3>*v$ zbrTqPz-$2@-w+00Al5dp0AfpqaL*7&h7c00{0{^mYe6)~Y7h;w9z;{%1TK(6bS=05 Dzv?@= diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ulaanbaatar b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ulaanbaatar deleted file mode 100644 index 2e20cc3a438bb2076bfc1856045075dd041cad3d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 891 zcmcK2yDvjw9Eb6@N+K?CNhEG{Ek#vJ>)zI-HPL|-iOWD5i5R?t3E>^Ygq*>E7|vj0 z)0DwzFxXrMF*0<KlVFq7dHewqgI7*IgGA)}{GwBf3vJ@p=QV$uZhraOcW)zk+0R;W z@<x?BeHo><5mk2Ok>zJ@WjijE6*~p0a_vJ_ExoJi=|@>J{Ge)kFQwgiq3X(xWPSFb za-=5=$45dmyc`&f_Xncsdev~oS4H#5jN#g!5iMIm!@Uv|o>-O9Iy<G>A_3_Q_?6F9 zDcfxosw3ATdy?mRZ~RR2pPcG}{XH$XwX657NUcA%tPe!Tw88MG9`gCLu-&T<*+%on zi;nb(j5#^+xvo#XhU8`{m9kjV{`g}RBIaYLdC43bnk7>RsYK35Br2SqPV?(Fzb+B| z!=&bal44f=F4H3OA`>GsBU2-DBa<VuBhw@EBMFcUND3qek_5?ur1{az!y^%riAO3V z7ms8}HXiAad^{2&8IhDoP9!Ok6-kTaMG_;Kk<>_TBsr2DNsr`5P5?Or<P?x|Ku+RE U^DL0lz<)lEEWddqL04DSH~vDxIRF3v diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ulan_Bator b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ulan_Bator deleted file mode 100644 index 2e20cc3a438bb2076bfc1856045075dd041cad3d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 891 zcmcK2yDvjw9Eb6@N+K?CNhEG{Ek#vJ>)zI-HPL|-iOWD5i5R?t3E>^Ygq*>E7|vj0 z)0DwzFxXrMF*0<KlVFq7dHewqgI7*IgGA)}{GwBf3vJ@p=QV$uZhraOcW)zk+0R;W z@<x?BeHo><5mk2Ok>zJ@WjijE6*~p0a_vJ_ExoJi=|@>J{Ge)kFQwgiq3X(xWPSFb za-=5=$45dmyc`&f_Xncsdev~oS4H#5jN#g!5iMIm!@Uv|o>-O9Iy<G>A_3_Q_?6F9 zDcfxosw3ATdy?mRZ~RR2pPcG}{XH$XwX657NUcA%tPe!Tw88MG9`gCLu-&T<*+%on zi;nb(j5#^+xvo#XhU8`{m9kjV{`g}RBIaYLdC43bnk7>RsYK35Br2SqPV?(Fzb+B| z!=&bal44f=F4H3OA`>GsBU2-DBa<VuBhw@EBMFcUND3qek_5?ur1{az!y^%riAO3V z7ms8}HXiAad^{2&8IhDoP9!Ok6-kTaMG_;Kk<>_TBsr2DNsr`5P5?Or<P?x|Ku+RE U^DL0lz<)lEEWddqL04DSH~vDxIRF3v diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Urumqi b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Urumqi deleted file mode 100644 index faa14d92d58fa883c4203022e091dc9154ac92dc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 165 zcmWHE%1kq2zzdjwvLMW{;oq*5`v3p`GcqzT1j&H(gd{Mq`1pn}Xd9R@gpgno(2)Ni S(?Dk6Hj&E)Xs(^E85aO>>Kf4i diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ust-Nera b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Ust-Nera deleted file mode 100644 index 9e4a78f6a547de2a91e728ac4ab5ffa4884105b4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1252 zcmdVZPe_wt9Ki8sZOdsLBuZCnr7c^w)NPr}HrL8jY+H%#lGUj{P$T#e9i$+G{y=1Z z4$)ymf2gp)!h=Z+4?7eck_eFwR;TJ9K|I7RMX;XlYX^}o9eZA0KJT9QWw7`6U8e8o zk+AyfTKs3X-N?23-usXFXZK&KW&S-<<<1tWUB}*5|G1NI&)n`=K0R4jG2!d+j0a`q zaIJW6Es<4&c3FM8C^gwHQoHY+tVzBSU-Y@G4Lp`QPfpe?x-5RjnD!Tk^!m?3s=j}> zs-L=~H@rBd1EX2J@xgxGa3if7&&PGs$tE2<RHH)&QW8GlmrZSr(%f4vo4u9N68b7F zzrIVvQ>G&yrlj@fjNURnCei8FI`(i<x8<Mc_=QouHFr%X4&T(<&JD}<j(**K@T%;n z>(d?WBAw2d?(+3Y*SEdWZEu$DH&NO7sY;Shy^@*;>-3e9>^fddWRiJ3P%4#d3mkUq za4wv4l)2`7n0sUXb-B~!QtDzSuUO71hf-&*E3=au;Z;8>*ed5=+syvpUA2_E%G{lO zhMiP8qXNN*Ia^gA6f$SnoI$=?DckJI{KJ^duPZTXWZW!9j*J}{y`>pHk^qtck^+(g zk_3_kk_M6ok_eIsk_wUwk_?g!k`9uOrAY|Mh($`4CMP5*Br7B>BrhZ}Br_y6BsU~E zBs(NMBtIlUOOqjzqNT|ZNfOBtNfXHvNfgNxNfpTzNfyZ#Nf*f%Nf^l(N!ilmj3jMo hvPRNI@<tLzGDlKJa>oJF!he>0Ma=vO;tio-#cvx!EIt4L diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Vientiane b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Vientiane deleted file mode 100644 index c292ac5b5f489a88bf10a1263b14e7412479d9e7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 199 zcmWHE%1kq2zzdjxvLMXU03;S=r5~yP|NlQD6B7eNoDEO}M6xh2Bo#1l`1pn}I03P? lfjL762?hhr`yaNg^$3UtSpYJ%9>^wW36~AfDmz_sE&#dsBrE^` diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Vladivostok b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Vladivostok deleted file mode 100644 index 8ab253ce73555cbbf42ec67a8560acef080fc480..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1208 zcmd7QPe{{o7{~EvI%}xGI^?XSS!&CcZ9hxVoGWK@tT~9-C2KI~AL1=K*dO$PiU=e+ zbSRMsOzL3KAq~cEStkh(br~J3ymSen4jIJyzJE3t(WP6Tq3=1zK%ZA?aOiBC{B>2o zUyYdZ-2LcyEIm6lx3b9>&D7LhT=cj`mOQIZj@Evj$!yLqEpAz`GTvNRx6TB#Zn8n^ z$2aP>D`na+{8hJ~Sk@hhciPzfTATbYwAuSucUIj~pYxUYzRk(5<ym*jNZQ@<_O9%n zzbXFbmt@bwVQIZ{Quba;O5j3Rf~Nywr3ba`e7o-J3F-c09&N9y*A8n{JAR6GdTXTf z{YUNk@m&t&=CwPYm(cVF>B;6KeEp>yoVYKC&P+@1)vQLMH>B^>q#kY_l4#$k_E#h% z)|k=Qmvb5~k7)c&T#tNe(!^804lMLa^411TC9*4Hg+jqmUbgmdR+K!}tuOhZ^cR0V zcR8IRm#6sej@}mYeBznIB{Kd%s*B%?uQ<#r#rKGLPw{oB9!RFdAM6spWtp!aA102q zrT*ch=C3JmR?2Dl7|u&MG3Cs5&8aEprktE|cFO4~=cf>$FrZMNaG;Q&u%OVO@SqT( zFriSfYq&7TP}tZtbQpXXgcyt%lo*^Cq!_Fiv?#nN#3;-t)F|BS8gdkNb`3oWKL$Yx zLk2|#M+Qj-O9o8_PYO{6QwmiER|;7MTf2rXg|A&hn8KJsnZlVtn!=in83X@0?aGj` K9&WXQmA?Rv8vN}5 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Yakutsk b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Yakutsk deleted file mode 100644 index c815e99b1a8f2d4b9bd45d3a6f39c95db5bbf563..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1207 zcmd7QPe_wt9Ki8sId!PS?^0UJT<KaiwYf^RbXuB;Zc@}BN{XOA^p6-(ln@#8_b}pj zD1zwF{~)A`)xo@_P$5C($vOyjs17F4B_h`IeQhwJOShgE_IdW~W$?bgZ*trIy<zj$ zRs8$3)yiIOzWco6@$C^aC$Kp+x9q}1sptH3>G!8Q%RUXJ=8aEH%pYw@d503Zpg*SN z*Xwj)x<V^Xiuw+@bWzV&T^yg(%EmFR3XZ7X`$U%%-`9ZqtpvUe%hC_eeAOoo`l`q7 z$+F?A5`1(~YVPz(?d1bfceY2CA5BPTcTDQH@6+&+HeC_x(v_S1x~jZJ8^VR!@N>3C zyj2o;KdsRp1+seRjW&*dl%~61BsTa`n$NwKmTUd8X3v1EJ@Z^!+pkF5t_Ql#e_Yzz z(z-r>t8`Qz){d!T+L^aeJ6~<luF0^*A4WAXx<R@xc{Le-Vfr$ej4N-}%;nC{xe5w% zzU2P!=icLX8`FD>x0^a`>^^<N<uT@znv(2i_QYjRviBH!PxjoDB)XF(7>bx+eaIT+ z&x~tkCI4Zh_GvPV6&Wpy@ggHe#_VWEjf@)^IWl%+^vL*;1dt4n6p$Q{B#<nSG>|-y zM3797R2*$CNHRz^jy4@6A0#0pBP1mxCnPB(D<mx>FC;M}GbA-6H%FTslAWVX56KTn z5Xlfp5y=rr63G%t6Uh@v6v-4x70DGz7RlDpri<k3XcI;<Mp8y{Mv_LdX7$+y{`0hp Lnr!RMwb7zq`+Wh_ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Yangon b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Yangon deleted file mode 100644 index dd77395b05a89b875683f8aa82062748f2ed504c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 268 zcmWHE%1kq2zzbM`vLGzf03;TEDh@pT>5s(4S?M3@|NsBb$i&RV#J~`x50nFuEDQ|M z84Mf@40RJ2_#kW_-w=i%Al5c8Gd2K{mJA^zSPHb`f7rIpiy#_gIfw>107Qcv0kXFq U$R^7nTsB}w+3A{D85?i`02U)YF8}}l diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Yekaterinburg b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Yekaterinburg deleted file mode 100644 index 6958d7edddb85d298c5f2b890b21d9ca2056e9c5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1243 zcmdVZPe_wt9Ki8s>S~)FBr2_Ct;}9^S!-=$)|{*5%$o2}gCLX!nNV~ol7a#uMg>I? zb*c`Q;i*3p>Qs?|N2}kVOGpLfB?1rCC2Xwc``TbcmySIz?>_IIjTiR*zRT=CJQ!4e zT{XXVlSZx=-#p;9ZZ8@yJ{~P3mRJ|_OY0|mb*|@ux*y+0>OX(YFPpY}%coA}y-#zp z;@*%n+!~aXm-fl3Gdsn1v|U#BwaS{bR~lnAvesXaChx4QtNtLCvszo<f9mF$xopd+ z(QM0`_quiRwe~-n(ChDx>$dB6^oHCuz41g&2L^`prv4EL9zQLcJI+dIPrrm41|$;f zlt>{ZQE#7)zH65Dxwzi)%p+T;eL6N~>5eBAI)2WrJ8#VB#Gx;GTTaRLu9rG_@T2T# zdZ@dSlag{?)!mI_(mi`$dMYnS&#No4>(de0{ot6Sr_Sr%%X=l0b|i+2#iFC4s&f8t zE+{(|y2{>^fAHtE+v!v)`j$r=dZDV!bwat6%48kpQKz)3Exnd@9A>BV9mY}GSGDQh zjMC=x2SVnIm@~|6m2%9l%s-6S{IVirMn=tI+}w_lBV$KKZ)?VnB!Faqq=4jrB!Ogs zq=DptB!Xmuq=MvvB!gswq=V#RYZ5{-LQ=9dIUz|QSs`g5c_E1*nIWkmxgp6R*&*p6 z`5_6~nhcQ?ZB33yl1P?Fnn<2VqDZDlsz|O#vPiZ_x=6lA!brwQ%C;tFBxzfdHIg=x aH<CD#Ig&aKn+E=)+&wY#2Z*<YJ-+}Y93Hp; diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Yerevan b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Asia/Yerevan deleted file mode 100644 index 250bfe020ada912671d670e77403a269c74b658e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1151 zcmd7QPe_w-9LMqBlP+yac*$)p`)4-izaDfOtER3@m$`|==nx%#Q3m}vJcLk(V27+z zL`4NjQHSUdQXM=5X6(>WJw&Hg@CAvWC?e>P73=qYaxkJxxAySt_3&&wuzlXy1ILbb zslUFw%Xj;XT-QAaOzwI2s&;fu=w`m&zhL{S=aarA>#_g6$_ENjyJ7BpKKS&iterY1 zjkm^S-Ni9ke|EoYIGK`-2jj9S9hRm<gKTcEk>=nJ*;4aSLY{yQef8>=x2v4+%O$7v z`3I+M`nA)3Z{F#+_RQ&=c;svyzw6jXt~lL2mnE|AghU%pNvta)v7cFq2aoIco0x3- zp4QuE{j#IbsT233x@V?N_g?VnzR52-IrdHOoLDWp1`4|W@MqcGJgW!#U&x^6j!rdA zOX|~%3{~8ap@rMBckzr2Kg>yb?z+xgIwT`gr**DaELs&Sejk;dvSVe{@=<oL{PWUv zrBdN1{GF|~GS`EnR<%;`q^d2wm+n~R&Y#~&XR@lz?lx!CoDm+QEcccDhw;pBC^8^2 zB2QsRWK3jGS2HRyEHW-KFfuYSG%_|aI5IjiJTg8K01^Qb0ulof1QLa-2?L1(2?U7* z2?dD-2?mJ<2?vP>2?&V@2?>eG)dYn^<!Zu0;z9yLB11w$Vnc#MqC>(%;zI&NB1A$& pVnl*OqI5N3B5}H!K#@q1P?1=XV3BAsXSV(?!}TUi$h{pA?=Ncm39<kH diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Azores b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Azores deleted file mode 100644 index 56593dbfff9bc50bb32e64ff282d0502e75526c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3484 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 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Bermuda b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Bermuda deleted file mode 100644 index 527524ed295aba41b9a0448ffd7993c489a2cb99..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2396 zcmdti|4)@w0LSr*n8TY8DHI8qXoVPD;o?OE3^n8qggDB@_#$*N5J8C`K}e#Sl+rJ> z6<S6#7sL7?sbNN6#xN9r2=yTOg)!kcgtnHO+1A=jZs+~{0d4)(dd|-Cdba21&)ZX2 zvD0b$$EU;mz0cgB*UhVA_(b|gUvEz6?5i63xTP=Q<Y4&Bk2|{c@aXsIeCLS1FtkWr ztZS62CsvH)70F9&3&rJ{UGhpmin?0ZqOab(DaMj^>ajCJVtn}lIo|cDxb9mfueZD{ zCZ^nSvZ`Cn?3u5BUNcAeE$x-_0}l(ktzFu0H;DW7KDl7*J>@@8AOpUsR}XwvrvpF8 zR}Z#6s~0vVsYMlQbx=W=3eE`C4<*j3hgaOwA<II=BYu;5vCloR__x1g=#5DcHZmc@ zPoEY`z8sK`9{WTrt-GTm-gr|i%lk<$uRNw6bDh$UXC6>b1i!B%SC*;B*{@`j-L0Y~ zj>wh2M5!nH8)fupx`^p4l8)XLVpa1x8T+nX#FZClXYH>d-kq#hZ@nN~k>NVQ`Gr_B z&#MzdhgIUt4ZZg636(T7sFTOvQ7JuIuKTW5J=OMuO#RTK)>n7Q4J|cdW6oRh>C#-0 zwrZE$l;#qfem|<+F<X>-v`J_9$E%Fq5}kP~SZ(guFSD*VMRrrMeCAY;$l0DMMf)FO zOG<>?T6az4hWScQ-nYVYcUo?9b%<@#K01F%pUOWor3+?{s=}_bx@e+FZErcQi~CDd zNolKou5-PT+1>K_gT-P;%pv(gd8#P&uasr(2vK$`OO{9ait_UgSut-~RD2#ND`(D$ z-G`&~o{Lkesy;x!*mG7@=iSyXwH;SAu1mVMx>da#d{Xbt*{$}@j>!7NL!y47S2l!H ziiZAn+4yIcc%^fn+<(m>nwksbt9^l@xg=S>cI1wj<73WT-~Z(CdIytiHm`Ri(`T;r z?dSDgRz3^7-g5)Cz^rVKZDX#v#tmuans3j)Sen;76$eAok;NgaLzaiE4_P3xLS%`^ z8j(dJt3;NGtP@!%vQlKJ$XYGUVv*Han&l$vwKNMxR%~gOjI0@1G_q=B*(M}5){QJ2 zS-GWII<j_T@yP0t<s<7y3V>7qDFIRgqzFhAkTM{3Knj6W0x5;1sRdFDq#8&$ka{2m zK`Mfj1gQy96r?IhS&+IQg|Rf1K}ut3YJ(I9sSZ*eq&`T2kP0CsLTZE*38@lNCZtYC zp^!=;rLr`&LW+e{3n>>;FQi~d#gLLAHA9MqR1GN`Qa7Y<mZow@=`2m{km6aI>LKMr z>W35%sUT89q=rZlkt!l(MCynX($Z8CDW#>UB~naFQ%$6tNIj8)A{9kSiqsS-DpFOX ztVmsv!XlMLN^5Cqixk(=R2M0)rKvAcV5GuGiIEy3MMkQOlo_crQfQ>oNU1GNt&w6| ynrb8Ewlwud3XW79DLGPer07W1@&8wLyUF`%llkcEc!$#w8=V~&=ZJH}+W!Xk<^WLu diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Canary b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Canary deleted file mode 100644 index f3192156ff043a529461aa9004a8de9dda326f7d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1897 zcmdVaUrd#C9LMqJ2q<IDeNhn$5S0+9Bb)<5YM>GUvpA-5QdEdkL@gpEV~`qiI@cUy zpEjm*<+A0Nb4p%NT_Cmo&X%&aWKPYs<;woe(acdgM!)ydO`BKVwE3{Z>ltU`>ihmg z*KTdh_wIVeyT9<^X>}jo6MJH7hcA?l%$yP_@}?HtR#L`qnl|M-CC8js^39Jl{n~qa z;M=2m@Uu6Ra%R9%Pxe~cTW{NpPFeb{JvOtc#b(uRwAocr%P20lhk`|xnVMyDCQi4k zxH4tkny2g^GnF$mO%H!DL67wPrQoq&G`IV*a`%0$yd7s0YB;5E-6hL!>9c~8ew(-Q zpcSSav7-DoD;n*v`6=C+e|5brxYMeI17-Hul^PZI)T^X_p%(2g)#5i(wWKjarTZ4x z;}vl#Ye=ytGOw$=Y}6{^zEWkz_f~o1CtDixi7g#GYfoN#*PiM<VO8foR-~)bmYsY@ zPd7K)^3J_lvHE~kHf>V%qfLrdRqC1KWm*-?(W;S<YLY6f=Hg_nxs`2eKloGYh7zpy zXrk5i{cg{8+_d`cL3^%#$ky-vRT~z6XdCO!sUiKaZ7S(iWBmKtoF;Al`H;4ZwrK0w zc0GSJsuzy0Q`48*?Zwwi)Z9~TFKtQJw*7^+eMPagG$z~2;Tg80{BL_D(X-aPB()Cz zU~Q8|)b`Ei)_&uXUOnAoI|uu<>+q-A-Frl@wI5SQSBC=QVq)X|_n)z`KjeAt_ples znR)S^H^~AM|NCAQiF$KGVQ+PL)P1U>d>04={v~=3r#t2z&KEgh{sU*s!zm-@jGQ!b z*1qnvk@H4Q96593)RA*XP98aX<n)pAM-o6XKvF<*K$1YRK+^Dac_4`(nINekxgg0P z*&yj4`5*})86hblIUz|QSs`ipy1bCYd|hTpYDjKKa!7VadPsgqf=Gr)ib#$~l1P?F znn<2VqP{LuBvoIRE0QddEs`#hFOo2lF_JQpGm<otHIg=xH<Gxo%N$AF*X52Rk7SRe zkK~U`05Su}6d-eeOad|s$TT4HfJ_836UbEfy176m1DOqEI*|E5CIp!gWJ-`ZK_&&6 z6=YhFc|j%ynHgkieBIn2ljG}V2bmsZevk=5W(b)gWRCDYo}>gfR3U~c7%9jt%njv* LgOPBEw}gKHM@+Br diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Cape_Verde b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Cape_Verde deleted file mode 100644 index e2a49d248de086306d2dd16a2b2d497a008c8f07..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 270 zcmWHE%1kq2zyPd35fBCe7@KF(vsDYuOr4`}sia1LTl~92{r~^}8JU<_SpNTi`GtYu z|NqAi7=Y}L9~e0hYz7V=-w*~}10x_dWME(fnFu06NU#`a&wr5RAR6QV5Djt!$SjaU TKy*D&jBLkn*#I49XUGKr1p`uu diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Faeroe b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Faeroe deleted file mode 100644 index 4dab7ef0859c244b916d61b7489d7371881e0ca2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1815 zcmdVaT};h!9LMpFG}f>$R-qD-ila_ZNC~Ni%0ov*lJr0%6s?eE%#7B)w#E#TY0WH$ zi*S*Lc^s2wvt}NeP4jHcM#HS-_x`(d<;LdU{(Jp*F1q@>zs?oKMUifQJpIitygcRR z<$LhKjg47efgja-_zU%Mf2clRuIY%b^E&czgO0j&NPVwd6~AVe_#Zzhqia<HcJ7uj zC1o;pWxk9{aY|rpqKvmkOORi%Oc*pmf;|#6xM!+{ybjXP4sV@!XMj#>`L6cH_d2=$ znTG9spy6AusH5PVM&vw|$g&oh64xqImmZcV{}U1&St-%IH8S0|UZ;2F$&8;B8gn&4 zW<Jl-*rr^KYmL!a`{ro;F+ZJM6sU9d&XBoD9-2_#EAxWhYGOjKBzfG|<iMAb-2F!8 zyWf!c?e}Cs*J)YkIx8t{*EO}SR??bJ>7vq7SzNnEmt-E$r6q-$KCMKZDapFbCrvZ# zp_=i{p;=x@lJ#VmF7FAE6_>thc88~|Y#1szEuUmn%@@h7Z<p1%9g<i5LD$4zmi(MH zEeJR&g>fz|8hBCH`m3&ecSP6qmTB?5DqY{{)D35{wdC#=*|<MWOPkVV)4BlNye~?& zEQyt}A|EM_7%f{9f5^6>Zc-8Mr4^rFN#&4lTKVX<RCPbq?H8J4M|-R8JbF{BT_<!` zRioC_)u^qX`@jC{>-%wrJ(<VMX^7Yc{{Bu$b-HCH@}@h@FE$&m^DlPUXCAi6zhj@s zMv<Lbnyn&xMK+7<7TGScUu46`j*%@Rdqy^m>>AlNvTtPL$j*_iTbjKin@4t!Y#-S_ z(g4x{(gM;0(ge~4(gxB8(g@NC(u$?&1!>08bc3{m^n)~nbcD2o^n^5pbcM8q^o2Br zbcVEs^oBHNX}Uw&vo!r74I&*PEh0T4O(I<)Z6bXljUt^Qts=c5&03mnk#;RjzevMK z$4JXa&q&iq*GSt)-$>&~=Sb^F?@04V_elGerhnuHAa?+{1;{->ZUS-_klTRV2joT| zcLKQ;$h|;r268u$+hJ+$2XaF!%^g8*335-6n}XaG<hCI91^<T|<7uvrgR5gtoe~xm O<_M3lr$#vV^85v)jhDp$ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Faroe b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Faroe deleted file mode 100644 index 4dab7ef0859c244b916d61b7489d7371881e0ca2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1815 zcmdVaT};h!9LMpFG}f>$R-qD-ila_ZNC~Ni%0ov*lJr0%6s?eE%#7B)w#E#TY0WH$ zi*S*Lc^s2wvt}NeP4jHcM#HS-_x`(d<;LdU{(Jp*F1q@>zs?oKMUifQJpIitygcRR z<$LhKjg47efgja-_zU%Mf2clRuIY%b^E&czgO0j&NPVwd6~AVe_#Zzhqia<HcJ7uj zC1o;pWxk9{aY|rpqKvmkOORi%Oc*pmf;|#6xM!+{ybjXP4sV@!XMj#>`L6cH_d2=$ znTG9spy6AusH5PVM&vw|$g&oh64xqImmZcV{}U1&St-%IH8S0|UZ;2F$&8;B8gn&4 zW<Jl-*rr^KYmL!a`{ro;F+ZJM6sU9d&XBoD9-2_#EAxWhYGOjKBzfG|<iMAb-2F!8 zyWf!c?e}Cs*J)YkIx8t{*EO}SR??bJ>7vq7SzNnEmt-E$r6q-$KCMKZDapFbCrvZ# zp_=i{p;=x@lJ#VmF7FAE6_>thc88~|Y#1szEuUmn%@@h7Z<p1%9g<i5LD$4zmi(MH zEeJR&g>fz|8hBCH`m3&ecSP6qmTB?5DqY{{)D35{wdC#=*|<MWOPkVV)4BlNye~?& zEQyt}A|EM_7%f{9f5^6>Zc-8Mr4^rFN#&4lTKVX<RCPbq?H8J4M|-R8JbF{BT_<!` zRioC_)u^qX`@jC{>-%wrJ(<VMX^7Yc{{Bu$b-HCH@}@h@FE$&m^DlPUXCAi6zhj@s zMv<Lbnyn&xMK+7<7TGScUu46`j*%@Rdqy^m>>AlNvTtPL$j*_iTbjKin@4t!Y#-S_ z(g4x{(gM;0(ge~4(gxB8(g@NC(u$?&1!>08bc3{m^n)~nbcD2o^n^5pbcM8q^o2Br zbcVEs^oBHNX}Uw&vo!r74I&*PEh0T4O(I<)Z6bXljUt^Qts=c5&03mnk#;RjzevMK z$4JXa&q&iq*GSt)-$>&~=Sb^F?@04V_elGerhnuHAa?+{1;{->ZUS-_klTRV2joT| zcLKQ;$h|;r268u$+hJ+$2XaF!%^g8*335-6n}XaG<hCI91^<T|<7uvrgR5gtoe~xm O<_M3lr$#vV^85v)jhDp$ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Jan_Mayen b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Jan_Mayen deleted file mode 100644 index 15a34c3cedb7c9ca519c195f5ec0ce9d8d1885a5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2228 zcmdtiUrd#C9LMp4h!iXLF@<9RLLs4r{0IL8nH_<d97{PFsRSw_7EzvzL26Vw=Nh?h zja80ZR*qRS?1J(Ft@X!73&~8@tXx~HtTZB#=+9XF-cM^?)J->C^m}%m*Ry9k7iT-4 zcWA|i+8p2CPPBW&hx3^G@O<e*?$(|*;A=m*xw_|2u)6omVjX+YZ+*`P^uZH(I{rwi zJ`Bg{#F}WGJ(z6g_Lu3qr;9YWGeh4uC26Qm`k^91=S$CPc=muUq@C1=|EPY{kd0<e z(CE+!n;cxIDY?H`Y|2@SoBWyiBafMX_;s5)aL_LQXs=!I_Tv_R_=pk?bSm+gXEm+W zl(gkxCD(^_<*K#1sw||G!eUKNFHmYiny$WNs?wqYmNt@SGrml<nf-Bg&CzJPw(BQL z-}jBpYWu`8w!d$gn+{u6&C8Zuc}h9qF69<=D{tA8%1_**f}AE5jJ0S^e4EWVy;^gB zZM1nu0=n+g3M=fWvZC&JcKwb8HorZ=Zm3PM1>5K9#*!!t)WmCH>KQ8zjHx8*Ju6N5 zT&06wX;I{xTGZF0n+9Ic;?9>;*87G9ceQHCf#>Yzh6dfzy3Ll}_NXnZUuWgB>n&7P zYPb5A*z)w5wtO_pDq>4i@$qGL`^XHfc<q9%?2pl^y^~bgbxwD*46CZGPt{fZTD|pK zTQmQV)>igfP10_yE9$h`i(a+$iDv7+e#+{`!nUEO+3q|Yvb*-LwEA~9>h7II*3eO| zd+L(x-W~bcxU^8=TEFhgo~BL3KkNQUJ~d{>TI0|cYMMA|O~>C+^WZ6a;FS(-?(4QK zyWg^{oqO!T=6%+(tHs7ejEjgI{|{Hxg#Z5X`C_KH|FAD1IbyueH&MQe|GfY4=CAi< z!H_RdT+S`THzM3Y_YnFQi}}r+@Zj`%WI3L0J;;KP6(LJP)`TnySrxJ@WL?O@kd+}z zL)L~Y4p|+tJY;>y0+AIWOGMU)EYj1hl3&g;k#!;qMOKO|)zhsNSuC<zWVy(Ckp&|w zMwX1M8Cf*4YGm2Sx{-w=D@T@&tliTs9$7uId}RGd0gwtHB|vI`6alFMQU;_BNFk6) zAf-TR;pvKjRKwGi1E~j65TqhVNsyW#MM0{9lm)2^QW&H%NNJGTAjLtd<LSzS)W_2m z2&oWKBBVx0k&r4OWkTwN6bh*nQYxfYNU@M=dAf2T_40HDLn?-p45=AXG^A=s*^s&+ zg+nTbln$vKQaq%3NcoWZdAb536+}vi)DS5mQbnYUNF9+vB9%l+iPRD)CQ?nLoJc)A xT|tqGdb*M#HARYwR23;JQdgv~`2VbIj0^9qY!aLv%+1Kp$Vv}pXJKY;%<s!{R2~2T diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Madeira b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Madeira deleted file mode 100644 index 5213761f891303f95e1962570568ae62ed387950..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3475 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 XTqn_e+qG%m#%UW9-8aVJr;tAYB=HW> diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Reykjavik b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Reykjavik deleted file mode 100644 index 10e0fc8190a401f67b861ced3b8b16401432a565..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1162 zcmc)IO-K}R7{~FMc3s3G76L_sdZN@of-OT3ifGF^)E;6NqAo5`K~YdqbStrh=!Nu9 zr>&mEQ}hObVC*3X5;d*O)NM6;HCOFLvurJE`hUluOP9Jdf0)lObDQ5cvUS(aW!4`r z-><i8jXe8LMUQE$Zk}}^aiaF(flXDHx;%aj*I1Vu%W4}|6jwDg9rWJ|6<EzHi={c0 zceABvjkeq^k~UwVwp|VC{l0c-KfOph;y2{M9-lsp)k$JQS|8P1)6SAseZ1qWc9kcj zyJElg<lmBHVOW!s=Oi_IpQN4~mfnFp?Q7a1Pdk=NfBhkSc0E^~S8vuAXEO3~Te-g4 zo08YTxjGPv%bNw?b+9a{>6ryGlzUr;hNonBBBmp){qnZ^h`zgWN8UF^^~1?}89g7= zvE9ez<IzeP537EvTrHnVt94@4LisXhyJqHRNoIVVPW~8_ubqqaTiT;j@d}w?|2`h? zKb<Vc8HrB+XWQ#IW208~^qqIM*ZneUV<=*k1OnEQz*1|ydFGRCNB&|t$6Tz3EQqX# zEQzd%EQ+j(EbD64MHWU@b~Q^QYrC4ok=0$z^2qu~0Z0W%2}lh{5l9tC8Au&SAxI@i zDM&4@rWm9eS5ppB4^j|P5mFLT6H*jX6;c*b7g88f8B!Wj8&VunovSGisSha-sSqg< rsSzm>sS+s@sS_y_sT3&{sTC;}sn*q$i`0u0j8u&OzvLVfbs*;_NO)Hd diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/South_Georgia b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/South_Georgia deleted file mode 100644 index 446660861227aa8ceb7084f48c3b2654ea64f4dc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 164 zcmWHE%1kq2zzdjwvLMXS03_=F|Nqa(`2YXi0}KrR|37}fz~bW@!k}wl#1KM)NkBvX TXSV$Xnt{(mE*qe^c1BzPW>qAj diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/St_Helena b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/St_Helena deleted file mode 100644 index 28b32ab2e0b9053f39a91d9f28b6072e41423954..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 148 zcmWHE%1kq2zzZ0GvP?kCG3nVP561uh|5!kkv-tRiFt`J82nmM#2LhZ1aRE&;-~s@2 CSQl9U diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Stanley b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Atlantic/Stanley deleted file mode 100644 index 88077f110715ac1e349708821ac1e00f35bf6395..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1214 zcmd7QK}ge40LStFQn6NtgaW6jvr?RCzHK^Fr#(~Dmf@;hT!&^vXb@4iPP2lNAjrCR zsF0|jSC<Zn{K?tcN?Juw7BP|z1wq})px68UPoAP~?a%vv#@l7^`^Ms9hXd9hKmF#{ zVsqAwo7d&u1L4`BxSa|Wh`FY){b>D1kuDvUY3)*vzjw&Y`$d&~T_K;$%&DjMwVV%~ z5}uM@((`g!m3>Qj%WobM8=g;jE6(?c${YJt)sc|&PIRj3NU7X7TBSDmmgMFEm#SIy zPS*M>MeU~<Syy6-x)%$!@9PIqe{b5}l1qt(OIPehH6^y57`K})P6)C0pzS|-T?IOl zGB|uzHJ6XbmbOvV^0P;_dLpXzZH?Uaqd~PjD3<MS>T?~F*?jn6f3)-X?R?i&Uvzss zlaQxZN4wi^C3cK_iT0FTNc46;i}o%ZOY~LWjrJ|<NesB>a|5$S^E*G^$wjUW<#%N# zbAxC6`J~p`Rj^{&Q&ec4<rjbVy{Jg*Ov<vHccIp=a;}wHr)_JE){A-9T5c?J!~Njy zn6=NGMiDfp*_?nC`-d^jf7WB?N~V!fkztW>k%5tsk)a*U*vR0>=*aNM_(%Xq1g0H} z5FAYmNDxRANEk>QNFYcgNGM1wNH9n=NH|D5NI;GzA|xb76B7~?5)~2_5*HE}5*ZR2 z5*rd65*-pA5+4$vqlpj+(b2?+1c^k6go(t71d2q8go?z91dBwAgp0(B1ng)cMnZNp fF(W}cny8Vmk+_k-k;pM=w)`(bcZW^(T|xJ6rO<TZ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/ACT b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/ACT deleted file mode 100644 index 0aea4c3d43e504dafabc031d7ca9cbe8db46163c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2190 zcmdUvTTGXA9EU&ulo6zo<v1#N$OJ?9qhe5K9yq2L${z$uBTkAP1pcX5iC+(m+EUXl zWX23>jxH*U)-=Z=%8eBQtBVe#Il5_B8|$WGX7+pDy6mRAdfx5#ynC<Si{Ix7l-JcR z);}`&@2^Lkd7ozPXj}iWwe_TEAn=|B`fKdcxe^=f%(bERpoUu#ZBl)PO`bYaA%$@k z@=Lmfrrfa5FJmn%;;Mzc|GR~c_t|Z)$7sse-)U;|bxk|}ks`KS(e14rn!ch}cQhT+ zo$;qNqqJ5t{y3<}^gKmPdC8*ZR9kfaev9?xSZrsN#f>J|%$97M)faB@d)n--6Wy9! z)@*ZZ$mXtoP4nu0)ZKIUYJUEp=8s>~g2XN@7`~*$uwzQ>dPfV#g1Wc$GfVp7s4Z%G z%aXerET!~_`HvS_>gIA=+?ZxdmS@`1jZv01E8do+PS~;=vh=t}rC<KuGCIfX{+^5W zz{rR)&x~sMg&wVV;S)W0@|0HAoYAU-7i@KQi`G=NSyu8Jmc6FgazfTBcV30%{@S6u zA6`}dSBLaa|4ywvSF3fMn^bTjPwQJU^ziP5Dy%QI4HY@IvG6`CTA5%0e~cB+4!4qs z>sE5}C)+fB#Y(RZS=n%}mG_>tN6uf?qi+ssbL)rN@?w`BYid`;wqts{^nfb!f~rcd zR&_$LYNB&gJH5fS`YLVf&qcOvG|TEfPqXcP_t+EfM%k06Z?&ghnXsqrn(e6n*6O#1 zs-f&RHRg{gm@%Sf5(l(1rboNN-qx;(Q`$XtR88NQ_I%o)XFsUabKQsS`Hp7WdwhpA zAE>Z>jT>x|@0S12BOSizF0xLZ^|@R9a=XI*I@c8hv?@D`qbMNxd<y)FZQOJOBll%u zHsaas1hW;-ZZDY4V0MGq4rV|685_dv2-uQmw<pY|JiA?Cw&mIF3$roI&Va1}djmEH z><-u-us>jfzz%^edUksRHVNz!vrW%#pO}q$c00vv6|+~&W-+_PY!}!sX2X~r16v06 z3~bu7+cmIl&u-tq#yz{816v37j@dkB_n7Tt_K#@*rURH3V0wUQ0;UU?Hh6Y@z%;_M z>jb71m|kF-0dxas2hb0oAwWlfmSB1UGzHTYOj|I00UG1kbp~h+&>NsRKzD%l0Q~_P z1at^!5vE6&CSkgSX%nVTm_~Vaox-#V(<@A~Fx|qm3+NZnFrZ^V%YdE%O#`|Hv<>JR z&^VxTnAUlAy~8vQ(>+Z4F#W?c5Ys_S3o$*!G!f_`&_<w-KqG-p0<HAydI>ZW=qAuk ppr1fPF&)LU6w_1ue{O0xbzPL|r?g20ss7~DWPeh@Qk1eJ{7;jB{Fnd$ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Adelaide b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Adelaide deleted file mode 100644 index f5dedca59e2b220f7395c73f60ff26e610373e8b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2208 zcmd7UZ%kEn9LMo<|1iFn62urI4dPFx6n`#Y3=9!PQj!aVHv<CFRPch-4GphoO4%LX zVpFrGch0TS5!iZ?YoN}pF_&aiOw<0Ytx=Y-wVAcmYAgD^5B02`d(Q58ot+2g(fPc0 z{f&XveCt0C_dief8M%+`HJ78+7xd`aLK*j;k@2xD`r$~kel%FEAHUWk6MbHF1<TYu zD?_4c(>3bXr5f#ZYxJjS>WTYaJ;N@Ix&FT1@@lHw`uTS<YmZZ6PmM`j%T<{jIU(_- z=VeZ)Uv5hol7#wBN%-qUNi3?7#A|P8Qd);5jj7Ic_;l`IyUv@;)jRsCG<h^$Q+6EJ zI}e|h)P}I8^<L5R<;Nr=@Uz^N{=CeuyexM+TV+A!uq>GPL^3@Q$sFIP_e}N3y^)KW zb?K01_b=3(lOfIBRw3SljhffIUh}(3v|vfOE~-n>`;zBtVZNn>e@1K3yksf*YD$a$ zn3lz7$Mya%C#7WI2U&9FoRo$?kflckq-@h$vTX0DF0a@p<r|LcikvsKqCBh*MAga4 zj5b~Q+X-29?TA!<)-Ml^?UL0aol-T}BEG{lQr%Z3HQV!~HrS*Ot@CMJZK<v)%T>QO zRUb}`*R`{qx_0^(edPL8t^fLpHcXt?#&<{b(No__)6ivUj=U!=IxLTc24&smh^()F zK^|Y#BO8i3WaGjn*_7my*7%UNIRe^tqfs|cuGYZC5^W#N){eJRbj#~;+WC^DPxRi< zCxhQ;usv3uYM7R;%AaIw@uY0ayd+QGeoneQ?@0IW1G0VUkc7VIlN}dA(sMc>J5Ro% zyN-qRnS<TB`?)sV(^ao7hw~;nE$i7I&4+BgJmfH6bvR;qX0BB}zqPD<1(!8`%W^m@ z|Nn0ziZ_^Jzxi<=J8h1wiTw$<bB-&BY{k~>1=)<P*$uKCWIxD;kR9=IwuI~n*_5r> z6|yZ`voB<0wq|F@){wm+n?rVoY!BHVvO#2r$QF@3BAc`|yF|8WYxaq3)Yj}2*{ZGC zE3#Q+x5##p{URGic8qKp*)y_fWY@^Hk$oc@w>3LQwr*?oj%*&;J+ggd|40Ln4j?T+ zdVn+m=>pOQqz_0VY)vPSR@j<eAk9F!fwTkZ2htFvBS=e-o*+#@x`MO?=?l^rq%%ls zY)x;F<{;fc+Jp25X%NyOq(w-NkR~BrLfVA%327A4DWp}lrdLR_kZvLELi&X?4Cxrs zGNfln(~zzqZA1EoG!E$;(mJGfNb_t>_mK7>{X-gvbP#DF(nF+)NEeYdB7H;}iF6Wa zCDKcznYN~zNIQ{!A`L}4inJ8zDbiG=t4LcNZl~)eI{%I9?gRW~Fo~Us>r80fGl?~I gwL5D!Hip_}7cVaG@+`}j=grB>@n-oJL2g0J-<z}q^8f$< diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Brisbane b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Brisbane deleted file mode 100644 index 7ff9949ffa93e44835ab133998b89e440094f909..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 419 zcmWHE%1kq2zzSHPqJlsg#O7-N5_9|xHO$$g&u}_qGsEfQsSRhghc%pC?%r^2K{3Pm zcFhLn0?P&#UKs{e&$A4w?_V*fYp!QdKYxZnlXD`2=K6IE%#2K^kb$AU0%$J7tPPAn zOL`VCa6(8Q-w*~zR~HZw9KyiB$jA^vf>ZwkLDAd!93UFxWH1eMHi!l}9ZUnA528U{ z0MQ_CfM}3cKs3lZAeVu>1foIS0s)ZMz%<Z%AOP|rm<D<i1VCN|)0BCa3*>QKLjx`V Df+TPt diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Broken_Hill b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Broken_Hill deleted file mode 100644 index 698c76e30e91f568a29daca12993cfacbfdbf83e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2229 zcmd7Ue@xVM9LMqRaYww56hxho2Js_i6h96y28M_tDairhWd{Li{y;$T!om|xS$X4K zHb+)^b8MN8fvv4&1?t=yb4f<UH0{^gin1U4MbuWSE$Q?8R)1Ch`~B{|kK6Z;yWRGE zJ$Jsk=FPd*e;%&C?;bGnKBmiDdMhtz@7a7A^_`K?k*)gvP=kKZU#TA+?Ub=@k2(V- z>YAA<k<}?0`O8v`^0+kW<79Qmey8q1r$$e{t2e%sBr`t!R%Y&vkeE{=65DuHW`$2k zT=99C9o#Q-5(i|izfI;|dq(CJRLM;<dNe+{RpUog=R3SQzrRHnjA!dD-4&WJ9H)sp zkL#_6PfJp5NRzv+Xv*?qlG^-}+?KLW(#kJO+T@fhOdphmV;@PnJ1pt1y(M={bjqFK zi<)uikY)zo(5#a|&Gx^jo`ZFo)39E1+lw@BNvSTXNz}U%(lkHU()>T7v|vGk6nrtE zg}+bB;<KZA_vhnM)c1odIde{mL+{DbBYje`=~Y?w)UYluJ0PVSj_Zo7SG24&r1wPD z$ja0vUHR(?S@r!9DgR`@+&i*cRu8pFMSr7s4_8TLcZpQ($dT$mz23LZt2Ncdx~3#s zeV!z}KPgVv&Wg~r(?9D2lULRM<rS?RJFj(b59x!azLENY%hC{jM;did9t!r$x-DT@ z?|)hzUezfZ3R-33?e(%L-Yc8qg4*P0)~2aC-7>yfn=ck=%W$T)zMiOCUyjwb=PZ4s zYf85TzSclXj67O9E$!t$%J#x>c`W^sJbv>z>2SX(9l!O-j)_AO{H$AcUI<F(>1Nq= z@&(;}ETm5y?9e?=HtF7Wzd9We*U@QN`+CiTY&}2VFi&+TY`OosR(O5ZveFe?*7z*T z;jn!Fzl|IC1atJ57w_jxn`8St-H08ozOQiCY-a%3jIG%XvK?EqA7n$wj*u-Od*Vyj z6tXL1TefCj$i{5V&XBFyn!O>LLw1L357{5GL1c%>7Lh$7n?!brY}3~46WJ)TQ)H{Q zX0OO*ZOv|x?IQa{HjL~T*)p<cWYfs5k!>UUMmBD1c8+Y_*6bbGysg<ivVCO#NCS`# zAT2<8fHVQ=0@4Pg4@e`BP9UwYHN8NZVQad9v;*k}(h#I0NK25OAWcEKg0uzc3(^>* zGe~QY-XP7fHQhnlgY*Y!5Yi!}MM#g3CLvuy+Jy88X%x~aq*X|-kY?GMZXxYL`h_$M z=@`;7q-RLekgg$ZL;8j^4(S}yI;3|<^N{W#?XxxgLmG&55NRROL!^mF7m+q1eMB0G zbP{PL(o3Y7NH>vo+M0eM4MjSNv=r$n(p03YNL!J<B8_!KL^@s9(fLnhpFPTdhdn)1 t))Y79U&Spmv9*h9x7Yj{6W(ZUWEL*Y^Kdi6o8!sK$?{})7eRJj^q)im5PARr diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Canberra b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Canberra deleted file mode 100644 index 0aea4c3d43e504dafabc031d7ca9cbe8db46163c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2190 zcmdUvTTGXA9EU&ulo6zo<v1#N$OJ?9qhe5K9yq2L${z$uBTkAP1pcX5iC+(m+EUXl zWX23>jxH*U)-=Z=%8eBQtBVe#Il5_B8|$WGX7+pDy6mRAdfx5#ynC<Si{Ix7l-JcR z);}`&@2^Lkd7ozPXj}iWwe_TEAn=|B`fKdcxe^=f%(bERpoUu#ZBl)PO`bYaA%$@k z@=Lmfrrfa5FJmn%;;Mzc|GR~c_t|Z)$7sse-)U;|bxk|}ks`KS(e14rn!ch}cQhT+ zo$;qNqqJ5t{y3<}^gKmPdC8*ZR9kfaev9?xSZrsN#f>J|%$97M)faB@d)n--6Wy9! z)@*ZZ$mXtoP4nu0)ZKIUYJUEp=8s>~g2XN@7`~*$uwzQ>dPfV#g1Wc$GfVp7s4Z%G z%aXerET!~_`HvS_>gIA=+?ZxdmS@`1jZv01E8do+PS~;=vh=t}rC<KuGCIfX{+^5W zz{rR)&x~sMg&wVV;S)W0@|0HAoYAU-7i@KQi`G=NSyu8Jmc6FgazfTBcV30%{@S6u zA6`}dSBLaa|4ywvSF3fMn^bTjPwQJU^ziP5Dy%QI4HY@IvG6`CTA5%0e~cB+4!4qs z>sE5}C)+fB#Y(RZS=n%}mG_>tN6uf?qi+ssbL)rN@?w`BYid`;wqts{^nfb!f~rcd zR&_$LYNB&gJH5fS`YLVf&qcOvG|TEfPqXcP_t+EfM%k06Z?&ghnXsqrn(e6n*6O#1 zs-f&RHRg{gm@%Sf5(l(1rboNN-qx;(Q`$XtR88NQ_I%o)XFsUabKQsS`Hp7WdwhpA zAE>Z>jT>x|@0S12BOSizF0xLZ^|@R9a=XI*I@c8hv?@D`qbMNxd<y)FZQOJOBll%u zHsaas1hW;-ZZDY4V0MGq4rV|685_dv2-uQmw<pY|JiA?Cw&mIF3$roI&Va1}djmEH z><-u-us>jfzz%^edUksRHVNz!vrW%#pO}q$c00vv6|+~&W-+_PY!}!sX2X~r16v06 z3~bu7+cmIl&u-tq#yz{816v37j@dkB_n7Tt_K#@*rURH3V0wUQ0;UU?Hh6Y@z%;_M z>jb71m|kF-0dxas2hb0oAwWlfmSB1UGzHTYOj|I00UG1kbp~h+&>NsRKzD%l0Q~_P z1at^!5vE6&CSkgSX%nVTm_~Vaox-#V(<@A~Fx|qm3+NZnFrZ^V%YdE%O#`|Hv<>JR z&^VxTnAUlAy~8vQ(>+Z4F#W?c5Ys_S3o$*!G!f_`&_<w-KqG-p0<HAydI>ZW=qAuk ppr1fPF&)LU6w_1ue{O0xbzPL|r?g20ss7~DWPeh@Qk1eJ{7;jB{Fnd$ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Currie b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Currie deleted file mode 100644 index 3adb8e1bf7c6ec51f1c100538799271d7d7a6e6f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2358 zcmds%YfP4P7>9qa=m=8Da*7C~R-8f(9w8M^990tI1%VV%Ia($NB3ZuOQ|oOlSDBkk zOOVFsiv#JPH5Qp|tPxmSN7EeD*68Hgn&nXGxt{vim%g>GXS=Wep6|cQTT)XwNB_v! zzyBU}%zL6a=h&xB_EJxxUcQiS$8EE<yd7n&Wh<@U`<nXuD(u74g*MQUWrMBtI`5CQ zk@pVjdbdwE`igb4vCBp~7D<JN%;S&Hn5CTxs7<x86T&qvZ@P`Unqq;8H!Se8FbfK~ zY(Z~ax8N&h?beoQ8vn)Dn&2DJ#53<Ir1X+*Yi`q|v|iobbU=4Rp3vl?N=?4GUsF=D zH8o(ZLT8p+=(ouV^JH3B$5xv@6l3B342w7$Y>`#bcIT09%_#QSOdGUWD~{=|njdxd zti8G?XFyS7HYqx`Q_;V@shFRKEcTOT#SNUZdtcw9_>=86`|t)O9Q0daLz<Gd*I4q# z5}Q-_l;$p3Z1WaWYkoweEts-O3vS33UX54E#cwRNW7zKNdEXZG#@XWbAuVYcZ)s1S z(^B6rwydIE%S%796&Zf5OzXDvgjXyh@~~x&Tdl0XQ_A|iP1)bSsGQFaXjR`Xtv+3; zH681fdn8-;`%|@ccbxKS3v69krah3i(DIkXm^W#f70d{>!jKUw9R11GU%6yOmj|u* ze6N-CcG-hxE^5Q81KQa9j!K{I)TX9Zl~uo>%|-jPCA(f*Q_58yQ=p2_OjS;*vntOP ztNJzHs)y38=HvOc?QE1ibZV+SeBu_{{`@t2#D1_HwO?87wm{Vt|Dl~Z!>UicpoZ9f z?V8r3#-NjGymnl>ho4i^m!?NQsMDUew&=0$gZ6lv&-NbLVZME3_QcM07T_84AN{0f z!krQ5XqU%X#Ivmm`s=RA^=f%WIw#*Nc|7v|i(QR6G$iOd%)T%i!|V*RHO$^Ho5SqR zwX;3U{xBQF>=3g>%pNhD#OxBg+vLGM!PzKcr@&T$y<#>C?AEojUCe%6I~&IA*tN4| z%$_lu26hc>8`w9nabV}b)`7hPn+JC9+Sxv^f1m+C2V6TX0D9osX#%DTm^NVgfN2D# z6F@64y}&dB=myXZpdUa(fR4C!S_1S0(-fd9n6?0Y!88Ww45l?eZ!pclbO&e;rawS~ zFdcI3v<TB9ph=i6VcLZ06Q)r>r!cJodWC5g&@D{6fPP^bhUpllWkAndJ52++2DA<6 z8_+nQb3p5W-T}=6x`$~Wrhk|QVmgRvA*P3}ohD+sh-o9HkC;YcItjEA=q1ohpqoHD zfqnuF1v(0}6zD0?R7_W0J8i}E71LNuXECkC^cK@xOm{Ku#q<|wFwkM3#XygNCIek| z?X(%_Gtg+D(?F|%USpb#={Ba_`2W)HU`jqaIf<&r=O!m5Bqt=r=gvckbA$f`><L3Z diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Darwin b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Darwin deleted file mode 100644 index 74a30879bc6180d588a706451226cb4c95faf79d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 325 zcmWHE%1kq2zzSHPqMSe)#O7-N5_9}ccFfsh#&J4i7su)2IUQ%V$99}u?$>c{K^4dO zc7qOPMkWYkV5nLFRL?MZ1tU;%>kI~<F(A^%H-y2_*#$%dhcGZOGBSkVb^<HN1R&r7 zVi23}KM)j)O^N`~)k4e#AR6Q(Fb#AThz2<gOaq+<qCrjs(I97nXpmDuG|0J(EKJN0 l2y<`U1dwNeu7<c5;&v8@tAP#%J00w7E|3RwEv<|VxBwKFV|oAp diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Eucla b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Eucla deleted file mode 100644 index 3bf1171caddd7882d8a438f1d5eca0026549be08..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 470 zcmWHE%1kq2zzSHPq9Q;V#1?1(5_9~nh|JmJFy(Z}ktwH-my4X)o*{B}d87y@|3?wd zZG0k9j1eMI%S%NxRf9w{*YBU=TDWD38*9uIcjY1x_ji>dp3EU4p68-P>i_@$&&<e# z4w)DjDlP!6Vd#`$1ln26!@vb0eSAY0v<)mxOo5~YkYr$FWC$U_?Lh1Pmn`Gj0HQ&D z0MkH!fM}3kz%<Z5AR6Q+5DoGd$SokhfoY)sKs3mYU>fL85DoGxm<IY6M1%YcqCx%! m(ICHrX`uf>G$;(fG%y@MbUn~6O2dN71{^MSx)xR@rd$9)WNteE diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Hobart b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Hobart deleted file mode 100644 index 3adb8e1bf7c6ec51f1c100538799271d7d7a6e6f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2358 zcmds%YfP4P7>9qa=m=8Da*7C~R-8f(9w8M^990tI1%VV%Ia($NB3ZuOQ|oOlSDBkk zOOVFsiv#JPH5Qp|tPxmSN7EeD*68Hgn&nXGxt{vim%g>GXS=Wep6|cQTT)XwNB_v! zzyBU}%zL6a=h&xB_EJxxUcQiS$8EE<yd7n&Wh<@U`<nXuD(u74g*MQUWrMBtI`5CQ zk@pVjdbdwE`igb4vCBp~7D<JN%;S&Hn5CTxs7<x86T&qvZ@P`Unqq;8H!Se8FbfK~ zY(Z~ax8N&h?beoQ8vn)Dn&2DJ#53<Ir1X+*Yi`q|v|iobbU=4Rp3vl?N=?4GUsF=D zH8o(ZLT8p+=(ouV^JH3B$5xv@6l3B342w7$Y>`#bcIT09%_#QSOdGUWD~{=|njdxd zti8G?XFyS7HYqx`Q_;V@shFRKEcTOT#SNUZdtcw9_>=86`|t)O9Q0daLz<Gd*I4q# z5}Q-_l;$p3Z1WaWYkoweEts-O3vS33UX54E#cwRNW7zKNdEXZG#@XWbAuVYcZ)s1S z(^B6rwydIE%S%796&Zf5OzXDvgjXyh@~~x&Tdl0XQ_A|iP1)bSsGQFaXjR`Xtv+3; zH681fdn8-;`%|@ccbxKS3v69krah3i(DIkXm^W#f70d{>!jKUw9R11GU%6yOmj|u* ze6N-CcG-hxE^5Q81KQa9j!K{I)TX9Zl~uo>%|-jPCA(f*Q_58yQ=p2_OjS;*vntOP ztNJzHs)y38=HvOc?QE1ibZV+SeBu_{{`@t2#D1_HwO?87wm{Vt|Dl~Z!>UicpoZ9f z?V8r3#-NjGymnl>ho4i^m!?NQsMDUew&=0$gZ6lv&-NbLVZME3_QcM07T_84AN{0f z!krQ5XqU%X#Ivmm`s=RA^=f%WIw#*Nc|7v|i(QR6G$iOd%)T%i!|V*RHO$^Ho5SqR zwX;3U{xBQF>=3g>%pNhD#OxBg+vLGM!PzKcr@&T$y<#>C?AEojUCe%6I~&IA*tN4| z%$_lu26hc>8`w9nabV}b)`7hPn+JC9+Sxv^f1m+C2V6TX0D9osX#%DTm^NVgfN2D# z6F@64y}&dB=myXZpdUa(fR4C!S_1S0(-fd9n6?0Y!88Ww45l?eZ!pclbO&e;rawS~ zFdcI3v<TB9ph=i6VcLZ06Q)r>r!cJodWC5g&@D{6fPP^bhUpllWkAndJ52++2DA<6 z8_+nQb3p5W-T}=6x`$~Wrhk|QVmgRvA*P3}ohD+sh-o9HkC;YcItjEA=q1ohpqoHD zfqnuF1v(0}6zD0?R7_W0J8i}E71LNuXECkC^cK@xOm{Ku#q<|wFwkM3#XygNCIek| z?X(%_Gtg+D(?F|%USpb#={Ba_`2W)HU`jqaIf<&r=O!m5Bqt=r=gvckbA$f`><L3Z diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/LHI b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/LHI deleted file mode 100644 index 9e04a80ecea45473faabeb609eb06cfe62193d48..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1860 zcmdVaT}ah;9LMqh$-1zMYO%zJoU;d<)6V|?tT>jMJy=;jG(DAOR!g&UdfG30@Y}OA zHhYj3g(Y2V6@(E)Wl=8LO2&|gh$I?qQCSxuUG!T7{RXkq@BL@jgWU|~!T;+VypRLm z_b0qK+A!Yv$Dd91uY>GwQnP)0_*cWzgixVLc(Ff{m|iQ1J!>P$fvJ+*Q5H$*OP7%? zZX~rkPCnXtP^BF^Yd)@4D!sW!Mon+kqodEwm{IHX*y3Nz*jK;njLZ&`arZ}^8NbhD zp8sBd+P}tRwO?1+y?bSxe5Zn)tL3w*X5}6(5wEsHjc*J}PJU2Ls2C;_Q-`TZ-fNlk z?zIY~3^Acc_f>AkGnst-ikk9UugN>ztMjj2HU(c_)>DrkHH9mW>S<qHlIcaFXVkUH z%wU@;n$aY)2IcA5qpM~1+ar3;ivy<k*Ufrv&pI>j>LOjzQEp0)<?6B)&y+W%==rKl zK3^VE74u!GEKF8mcepG_d#4r-eIpBFkJX}A52WhJO;vrjOBUZarE0qFn<Zy{(zWeZ z%+kFl^fGBT%OiXA7ggKLiaGVVF0{nde=<w2Oe`=BAJnN;ff`x$N0Ey3<xBKlhFaa7 zCTlLntF<QsvhL7JwZ8eee5vjz6^)q<)&07$xX*0Ny{$K8{%kfUozq+5Pn#`&eyf}M zTZ}y1pts(Nnr%N+>g}E1$c|G=?K~WjU3)6j?#8*YI~I!t;s*Tv8W{H<y#_i?+ZcOB zPU{KBzCYO&h<BVLXPlvqbNoVJL`iAbnO0O8cCtJ#$F)z_e|k>%U!1A^X0eS4O^^6D zoGWs&zV>X9)AhCIi=42pJ!9mQk#j~)8aZp^w2|{hP8>ON<kXRKM^4_?o;`B<zV`f) z1bl4<ND4>}ND@dENE%2UNFqokNGeD!NHRz^NIJeYA0#1Pn-P){k`s~?k`<B`k{6N~ zk{Oa3k{gm7k{yyBk{^<wugwri5y=rr63G%t6Uh@v6v-4x70DGz7ReS#7s(e%*w<!^ zq>SW@B#mT^q>bc_B#vZ`q>ki{B#&f|q>to}OaL+i$Q1b6IY1@>nFVATka<8R0+|V9 zDv-HACIgubWIB-fKqds45oAhy?VKQ!g3JmsEy%ne6NAhQGBwEDAd}<!|C*h_dHw_y bjPu;dIj;TS*|%PHspkg0pqpJf0S3PZa7Xsj diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Lindeman b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Lindeman deleted file mode 100644 index 4ee1825abfe65887069dcbd10bcf786d50ba0702..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 475 zcmWHE%1kq2zzSHPqM|?=#O7-N5_9|xHO$$g&u}_qGsEfQsSRhghc%pC?%r^2K{3Pm zcFhLn0?P&#UKs{e&$A4w?_V*fYp!QdKYxZnlXD`2=K6IES}%(kv}c@Z(7Dv#pj)w~ zftisB6EZM#uL0V{Flz%N(Bhs244e?s$2Ww*(bWY+1cxv%FfuZPkl_6PKv48{(G?I4 z@&=d&dIdy-yaT3zUINh|Z-Ho#*FZGLdmtL*MUcxt-UQJguYv%`yI>mVWe@;)8%zVe k4gw(WgK1z8fB+~MKmZgJAQ}`LAest6!UYN(T|)yd00dHiMF0Q* diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Lord_Howe b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Lord_Howe deleted file mode 100644 index 9e04a80ecea45473faabeb609eb06cfe62193d48..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1860 zcmdVaT}ah;9LMqh$-1zMYO%zJoU;d<)6V|?tT>jMJy=;jG(DAOR!g&UdfG30@Y}OA zHhYj3g(Y2V6@(E)Wl=8LO2&|gh$I?qQCSxuUG!T7{RXkq@BL@jgWU|~!T;+VypRLm z_b0qK+A!Yv$Dd91uY>GwQnP)0_*cWzgixVLc(Ff{m|iQ1J!>P$fvJ+*Q5H$*OP7%? zZX~rkPCnXtP^BF^Yd)@4D!sW!Mon+kqodEwm{IHX*y3Nz*jK;njLZ&`arZ}^8NbhD zp8sBd+P}tRwO?1+y?bSxe5Zn)tL3w*X5}6(5wEsHjc*J}PJU2Ls2C;_Q-`TZ-fNlk z?zIY~3^Acc_f>AkGnst-ikk9UugN>ztMjj2HU(c_)>DrkHH9mW>S<qHlIcaFXVkUH z%wU@;n$aY)2IcA5qpM~1+ar3;ivy<k*Ufrv&pI>j>LOjzQEp0)<?6B)&y+W%==rKl zK3^VE74u!GEKF8mcepG_d#4r-eIpBFkJX}A52WhJO;vrjOBUZarE0qFn<Zy{(zWeZ z%+kFl^fGBT%OiXA7ggKLiaGVVF0{nde=<w2Oe`=BAJnN;ff`x$N0Ey3<xBKlhFaa7 zCTlLntF<QsvhL7JwZ8eee5vjz6^)q<)&07$xX*0Ny{$K8{%kfUozq+5Pn#`&eyf}M zTZ}y1pts(Nnr%N+>g}E1$c|G=?K~WjU3)6j?#8*YI~I!t;s*Tv8W{H<y#_i?+ZcOB zPU{KBzCYO&h<BVLXPlvqbNoVJL`iAbnO0O8cCtJ#$F)z_e|k>%U!1A^X0eS4O^^6D zoGWs&zV>X9)AhCIi=42pJ!9mQk#j~)8aZp^w2|{hP8>ON<kXRKM^4_?o;`B<zV`f) z1bl4<ND4>}ND@dENE%2UNFqokNGeD!NHRz^NIJeYA0#1Pn-P){k`s~?k`<B`k{6N~ zk{Oa3k{gm7k{yyBk{^<wugwri5y=rr63G%t6Uh@v6v-4x70DGz7ReS#7s(e%*w<!^ zq>SW@B#mT^q>bc_B#vZ`q>ki{B#&f|q>to}OaL+i$Q1b6IY1@>nFVATka<8R0+|V9 zDv-HACIgubWIB-fKqds45oAhy?VKQ!g3JmsEy%ne6NAhQGBwEDAd}<!|C*h_dHw_y bjPu;dIj;TS*|%PHspkg0pqpJf0S3PZa7Xsj diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Melbourne b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Melbourne deleted file mode 100644 index ee903f4b1fc292bc9cbec7b501a266030ef3510e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2190 zcmdUvTTGU99LK+}$_Prya>zl+Ln#;nuZlq_dEl60C@%<<N}Los2)rs-NxwYo?V>WR zO=e7y=IElrXial0qS{y?vbyL%nxh+|+FUmkGqeBasmpG<tIxCjKhK`4=i>kU1S;z5 z7U>_E^!L{noq3;P?r2~4p|$s>YB2DQ1_x^G{Fzc4>dLbV9YGC;l5Ao_rcIhWLt#bn z7WPYqg{NM(@Gs&lBI>e5y!*RFUhTJ=PsHk$ufEmf)@zz__5($2zNA~*IyE(`Pq(!k z(CrB)HLa{p)Bf16=!|?tUpZkhvuiA7;8~0F<yu@<wZ)Gn+Kf<+&Fqh~ggxzc$I%|m zDsQ#f&97+As#i6){zu(8XRq!m7}C56TQonZTl0s{D=FfzlDgm0g0Z0PZu``dKR;v( zTi&pgo<>XEnWeNN#pd5sVT+p5ZSnGDwq(O}OP`rwOa0@v^tvn~K3W+Uzq8D)F}t_- zW4mu;M9WT%YWcZdWgYxT_a8g16}6|da{oD7l@rqH>UPUcdChWGw_0x48s*Kcw7g$C zm4D@B6?}O>4-D+mnlp7;+qF@JNAtBVl&J@s7pSPA#MW2l+J>TgtawGD1=3=zWLBh= zMqRVg8$a2`tCy_o@&zj&?z4)%)ArEWi+cF=A#G}VUz?xn)|QqIRc<@1N6Pl8DnF>| zj2hJ>mZ&x+S9MbxZL6=!w*Fjf+eWjk{<C!3-apSCeS5k+cJd~B{H1Yw!hWzF4c}P9 z_HZ?p|E8vbF$FV6v@>Z?yJCB_JK|049zU+;u|sP4+O+4BMm_mnm7eN(!Jh7HwY^7n zSnIw@d!}i<P4rFp4?R-odv}p_?6l9_>gPKY@z=SwFrbw=*&M|I$>&qxUu@%sBN%-! z2D1^*ZYP+ncy@ciYzDI%%yuyQ;m_C*W=Fu5Ji9$%Hs#sv3bQTGZeN&<VRi;=4cHs7 zIbe6d_JI8X8w7R;Y|*pZBd|%&ZkL#CdUpH7Y}B*cDQ2sfy<#?t*)3+fz<x0s26hZ= z8Q3$hX<*mDwmrLj0~`13b`ESE*gIzPnB8NxkJ&%a089rkEx_~u(*#TxFm3Sc`haPK zXV(c#D=@vlGy~`c&<>y<Ktq6z04>4v1ZWDTE10%m`T{h@v+E4d8lX2obAavu?E(4& zGzjPr&>~EaFipaA3DYJ_pD>N`>^g;M6{c61W?{O8X&2BhpkYAAfR+J01DXbO4QLzC zH=uDq=P<4F?0Sc39;SPk_F?*mX&|P9m=<Dsh-o6wMWBs9AAv>!odjCx+4T}=CeTfw qoj^Z<hGII3X(^_s`2XD0Nb0)KpGIku3;k&+{*<)j!X+qmapa$<aQM0a diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/NSW b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/NSW deleted file mode 100644 index 0aea4c3d43e504dafabc031d7ca9cbe8db46163c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2190 zcmdUvTTGXA9EU&ulo6zo<v1#N$OJ?9qhe5K9yq2L${z$uBTkAP1pcX5iC+(m+EUXl zWX23>jxH*U)-=Z=%8eBQtBVe#Il5_B8|$WGX7+pDy6mRAdfx5#ynC<Si{Ix7l-JcR z);}`&@2^Lkd7ozPXj}iWwe_TEAn=|B`fKdcxe^=f%(bERpoUu#ZBl)PO`bYaA%$@k z@=Lmfrrfa5FJmn%;;Mzc|GR~c_t|Z)$7sse-)U;|bxk|}ks`KS(e14rn!ch}cQhT+ zo$;qNqqJ5t{y3<}^gKmPdC8*ZR9kfaev9?xSZrsN#f>J|%$97M)faB@d)n--6Wy9! z)@*ZZ$mXtoP4nu0)ZKIUYJUEp=8s>~g2XN@7`~*$uwzQ>dPfV#g1Wc$GfVp7s4Z%G z%aXerET!~_`HvS_>gIA=+?ZxdmS@`1jZv01E8do+PS~;=vh=t}rC<KuGCIfX{+^5W zz{rR)&x~sMg&wVV;S)W0@|0HAoYAU-7i@KQi`G=NSyu8Jmc6FgazfTBcV30%{@S6u zA6`}dSBLaa|4ywvSF3fMn^bTjPwQJU^ziP5Dy%QI4HY@IvG6`CTA5%0e~cB+4!4qs z>sE5}C)+fB#Y(RZS=n%}mG_>tN6uf?qi+ssbL)rN@?w`BYid`;wqts{^nfb!f~rcd zR&_$LYNB&gJH5fS`YLVf&qcOvG|TEfPqXcP_t+EfM%k06Z?&ghnXsqrn(e6n*6O#1 zs-f&RHRg{gm@%Sf5(l(1rboNN-qx;(Q`$XtR88NQ_I%o)XFsUabKQsS`Hp7WdwhpA zAE>Z>jT>x|@0S12BOSizF0xLZ^|@R9a=XI*I@c8hv?@D`qbMNxd<y)FZQOJOBll%u zHsaas1hW;-ZZDY4V0MGq4rV|685_dv2-uQmw<pY|JiA?Cw&mIF3$roI&Va1}djmEH z><-u-us>jfzz%^edUksRHVNz!vrW%#pO}q$c00vv6|+~&W-+_PY!}!sX2X~r16v06 z3~bu7+cmIl&u-tq#yz{816v37j@dkB_n7Tt_K#@*rURH3V0wUQ0;UU?Hh6Y@z%;_M z>jb71m|kF-0dxas2hb0oAwWlfmSB1UGzHTYOj|I00UG1kbp~h+&>NsRKzD%l0Q~_P z1at^!5vE6&CSkgSX%nVTm_~Vaox-#V(<@A~Fx|qm3+NZnFrZ^V%YdE%O#`|Hv<>JR z&^VxTnAUlAy~8vQ(>+Z4F#W?c5Ys_S3o$*!G!f_`&_<w-KqG-p0<HAydI>ZW=qAuk ppr1fPF&)LU6w_1ue{O0xbzPL|r?g20ss7~DWPeh@Qk1eJ{7;jB{Fnd$ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/North b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/North deleted file mode 100644 index 74a30879bc6180d588a706451226cb4c95faf79d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 325 zcmWHE%1kq2zzSHPqMSe)#O7-N5_9}ccFfsh#&J4i7su)2IUQ%V$99}u?$>c{K^4dO zc7qOPMkWYkV5nLFRL?MZ1tU;%>kI~<F(A^%H-y2_*#$%dhcGZOGBSkVb^<HN1R&r7 zVi23}KM)j)O^N`~)k4e#AR6Q(Fb#AThz2<gOaq+<qCrjs(I97nXpmDuG|0J(EKJN0 l2y<`U1dwNeu7<c5;&v8@tAP#%J00w7E|3RwEv<|VxBwKFV|oAp diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Perth b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Perth deleted file mode 100644 index f8ddbdf215d34b022af11c3d1930dd6ea4dca87e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 446 zcmWHE%1kq2zzSHPqQXEL#O7-N5_A0SEts>%Tj6xbd4<!*8yB3}UbNus^5g}a{J$4) zZj)Fb#hA1}YI*$vP1TqMn(I#~xEAhLaAQqZa96Hb;Qp?8fhTj^0?%`)3z!+1&>;gu z&K#f(40RJ2fz}l?FmOUhAKwrL$8Z-A5gfw6z{toDLV~0J13}3$u_quJ<ajU*^Z<wk zc>+uWJp!UZo&nJy4}n|)@)Vc`dJIH^JO`$M9t6=KPl9QnM?o~mvmhGeVGs@SG?)f@ U97KaW52h&%04`8a=vr_A0IP9yp8x;= diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Queensland b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Queensland deleted file mode 100644 index 7ff9949ffa93e44835ab133998b89e440094f909..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 419 zcmWHE%1kq2zzSHPqJlsg#O7-N5_9|xHO$$g&u}_qGsEfQsSRhghc%pC?%r^2K{3Pm zcFhLn0?P&#UKs{e&$A4w?_V*fYp!QdKYxZnlXD`2=K6IE%#2K^kb$AU0%$J7tPPAn zOL`VCa6(8Q-w*~zR~HZw9KyiB$jA^vf>ZwkLDAd!93UFxWH1eMHi!l}9ZUnA528U{ z0MQ_CfM}3cKs3lZAeVu>1foIS0s)ZMz%<Z%AOP|rm<D<i1VCN|)0BCa3*>QKLjx`V Df+TPt diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/South b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/South deleted file mode 100644 index f5dedca59e2b220f7395c73f60ff26e610373e8b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2208 zcmd7UZ%kEn9LMo<|1iFn62urI4dPFx6n`#Y3=9!PQj!aVHv<CFRPch-4GphoO4%LX zVpFrGch0TS5!iZ?YoN}pF_&aiOw<0Ytx=Y-wVAcmYAgD^5B02`d(Q58ot+2g(fPc0 z{f&XveCt0C_dief8M%+`HJ78+7xd`aLK*j;k@2xD`r$~kel%FEAHUWk6MbHF1<TYu zD?_4c(>3bXr5f#ZYxJjS>WTYaJ;N@Ix&FT1@@lHw`uTS<YmZZ6PmM`j%T<{jIU(_- z=VeZ)Uv5hol7#wBN%-qUNi3?7#A|P8Qd);5jj7Ic_;l`IyUv@;)jRsCG<h^$Q+6EJ zI}e|h)P}I8^<L5R<;Nr=@Uz^N{=CeuyexM+TV+A!uq>GPL^3@Q$sFIP_e}N3y^)KW zb?K01_b=3(lOfIBRw3SljhffIUh}(3v|vfOE~-n>`;zBtVZNn>e@1K3yksf*YD$a$ zn3lz7$Mya%C#7WI2U&9FoRo$?kflckq-@h$vTX0DF0a@p<r|LcikvsKqCBh*MAga4 zj5b~Q+X-29?TA!<)-Ml^?UL0aol-T}BEG{lQr%Z3HQV!~HrS*Ot@CMJZK<v)%T>QO zRUb}`*R`{qx_0^(edPL8t^fLpHcXt?#&<{b(No__)6ivUj=U!=IxLTc24&smh^()F zK^|Y#BO8i3WaGjn*_7my*7%UNIRe^tqfs|cuGYZC5^W#N){eJRbj#~;+WC^DPxRi< zCxhQ;usv3uYM7R;%AaIw@uY0ayd+QGeoneQ?@0IW1G0VUkc7VIlN}dA(sMc>J5Ro% zyN-qRnS<TB`?)sV(^ao7hw~;nE$i7I&4+BgJmfH6bvR;qX0BB}zqPD<1(!8`%W^m@ z|Nn0ziZ_^Jzxi<=J8h1wiTw$<bB-&BY{k~>1=)<P*$uKCWIxD;kR9=IwuI~n*_5r> z6|yZ`voB<0wq|F@){wm+n?rVoY!BHVvO#2r$QF@3BAc`|yF|8WYxaq3)Yj}2*{ZGC zE3#Q+x5##p{URGic8qKp*)y_fWY@^Hk$oc@w>3LQwr*?oj%*&;J+ggd|40Ln4j?T+ zdVn+m=>pOQqz_0VY)vPSR@j<eAk9F!fwTkZ2htFvBS=e-o*+#@x`MO?=?l^rq%%ls zY)x;F<{;fc+Jp25X%NyOq(w-NkR~BrLfVA%327A4DWp}lrdLR_kZvLELi&X?4Cxrs zGNfln(~zzqZA1EoG!E$;(mJGfNb_t>_mK7>{X-gvbP#DF(nF+)NEeYdB7H;}iF6Wa zCDKcznYN~zNIQ{!A`L}4inJ8zDbiG=t4LcNZl~)eI{%I9?gRW~Fo~Us>r80fGl?~I gwL5D!Hip_}7cVaG@+`}j=grB>@n-oJL2g0J-<z}q^8f$< diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Sydney b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Sydney deleted file mode 100644 index 0aea4c3d43e504dafabc031d7ca9cbe8db46163c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2190 zcmdUvTTGXA9EU&ulo6zo<v1#N$OJ?9qhe5K9yq2L${z$uBTkAP1pcX5iC+(m+EUXl zWX23>jxH*U)-=Z=%8eBQtBVe#Il5_B8|$WGX7+pDy6mRAdfx5#ynC<Si{Ix7l-JcR z);}`&@2^Lkd7ozPXj}iWwe_TEAn=|B`fKdcxe^=f%(bERpoUu#ZBl)PO`bYaA%$@k z@=Lmfrrfa5FJmn%;;Mzc|GR~c_t|Z)$7sse-)U;|bxk|}ks`KS(e14rn!ch}cQhT+ zo$;qNqqJ5t{y3<}^gKmPdC8*ZR9kfaev9?xSZrsN#f>J|%$97M)faB@d)n--6Wy9! z)@*ZZ$mXtoP4nu0)ZKIUYJUEp=8s>~g2XN@7`~*$uwzQ>dPfV#g1Wc$GfVp7s4Z%G z%aXerET!~_`HvS_>gIA=+?ZxdmS@`1jZv01E8do+PS~;=vh=t}rC<KuGCIfX{+^5W zz{rR)&x~sMg&wVV;S)W0@|0HAoYAU-7i@KQi`G=NSyu8Jmc6FgazfTBcV30%{@S6u zA6`}dSBLaa|4ywvSF3fMn^bTjPwQJU^ziP5Dy%QI4HY@IvG6`CTA5%0e~cB+4!4qs z>sE5}C)+fB#Y(RZS=n%}mG_>tN6uf?qi+ssbL)rN@?w`BYid`;wqts{^nfb!f~rcd zR&_$LYNB&gJH5fS`YLVf&qcOvG|TEfPqXcP_t+EfM%k06Z?&ghnXsqrn(e6n*6O#1 zs-f&RHRg{gm@%Sf5(l(1rboNN-qx;(Q`$XtR88NQ_I%o)XFsUabKQsS`Hp7WdwhpA zAE>Z>jT>x|@0S12BOSizF0xLZ^|@R9a=XI*I@c8hv?@D`qbMNxd<y)FZQOJOBll%u zHsaas1hW;-ZZDY4V0MGq4rV|685_dv2-uQmw<pY|JiA?Cw&mIF3$roI&Va1}djmEH z><-u-us>jfzz%^edUksRHVNz!vrW%#pO}q$c00vv6|+~&W-+_PY!}!sX2X~r16v06 z3~bu7+cmIl&u-tq#yz{816v37j@dkB_n7Tt_K#@*rURH3V0wUQ0;UU?Hh6Y@z%;_M z>jb71m|kF-0dxas2hb0oAwWlfmSB1UGzHTYOj|I00UG1kbp~h+&>NsRKzD%l0Q~_P z1at^!5vE6&CSkgSX%nVTm_~Vaox-#V(<@A~Fx|qm3+NZnFrZ^V%YdE%O#`|Hv<>JR z&^VxTnAUlAy~8vQ(>+Z4F#W?c5Ys_S3o$*!G!f_`&_<w-KqG-p0<HAydI>ZW=qAuk ppr1fPF&)LU6w_1ue{O0xbzPL|r?g20ss7~DWPeh@Qk1eJ{7;jB{Fnd$ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Tasmania b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Tasmania deleted file mode 100644 index 3adb8e1bf7c6ec51f1c100538799271d7d7a6e6f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2358 zcmds%YfP4P7>9qa=m=8Da*7C~R-8f(9w8M^990tI1%VV%Ia($NB3ZuOQ|oOlSDBkk zOOVFsiv#JPH5Qp|tPxmSN7EeD*68Hgn&nXGxt{vim%g>GXS=Wep6|cQTT)XwNB_v! zzyBU}%zL6a=h&xB_EJxxUcQiS$8EE<yd7n&Wh<@U`<nXuD(u74g*MQUWrMBtI`5CQ zk@pVjdbdwE`igb4vCBp~7D<JN%;S&Hn5CTxs7<x86T&qvZ@P`Unqq;8H!Se8FbfK~ zY(Z~ax8N&h?beoQ8vn)Dn&2DJ#53<Ir1X+*Yi`q|v|iobbU=4Rp3vl?N=?4GUsF=D zH8o(ZLT8p+=(ouV^JH3B$5xv@6l3B342w7$Y>`#bcIT09%_#QSOdGUWD~{=|njdxd zti8G?XFyS7HYqx`Q_;V@shFRKEcTOT#SNUZdtcw9_>=86`|t)O9Q0daLz<Gd*I4q# z5}Q-_l;$p3Z1WaWYkoweEts-O3vS33UX54E#cwRNW7zKNdEXZG#@XWbAuVYcZ)s1S z(^B6rwydIE%S%796&Zf5OzXDvgjXyh@~~x&Tdl0XQ_A|iP1)bSsGQFaXjR`Xtv+3; zH681fdn8-;`%|@ccbxKS3v69krah3i(DIkXm^W#f70d{>!jKUw9R11GU%6yOmj|u* ze6N-CcG-hxE^5Q81KQa9j!K{I)TX9Zl~uo>%|-jPCA(f*Q_58yQ=p2_OjS;*vntOP ztNJzHs)y38=HvOc?QE1ibZV+SeBu_{{`@t2#D1_HwO?87wm{Vt|Dl~Z!>UicpoZ9f z?V8r3#-NjGymnl>ho4i^m!?NQsMDUew&=0$gZ6lv&-NbLVZME3_QcM07T_84AN{0f z!krQ5XqU%X#Ivmm`s=RA^=f%WIw#*Nc|7v|i(QR6G$iOd%)T%i!|V*RHO$^Ho5SqR zwX;3U{xBQF>=3g>%pNhD#OxBg+vLGM!PzKcr@&T$y<#>C?AEojUCe%6I~&IA*tN4| z%$_lu26hc>8`w9nabV}b)`7hPn+JC9+Sxv^f1m+C2V6TX0D9osX#%DTm^NVgfN2D# z6F@64y}&dB=myXZpdUa(fR4C!S_1S0(-fd9n6?0Y!88Ww45l?eZ!pclbO&e;rawS~ zFdcI3v<TB9ph=i6VcLZ06Q)r>r!cJodWC5g&@D{6fPP^bhUpllWkAndJ52++2DA<6 z8_+nQb3p5W-T}=6x`$~Wrhk|QVmgRvA*P3}ohD+sh-o9HkC;YcItjEA=q1ohpqoHD zfqnuF1v(0}6zD0?R7_W0J8i}E71LNuXECkC^cK@xOm{Ku#q<|wFwkM3#XygNCIek| z?X(%_Gtg+D(?F|%USpb#={Ba_`2W)HU`jqaIf<&r=O!m5Bqt=r=gvckbA$f`><L3Z diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Victoria b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Victoria deleted file mode 100644 index ee903f4b1fc292bc9cbec7b501a266030ef3510e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2190 zcmdUvTTGU99LK+}$_Prya>zl+Ln#;nuZlq_dEl60C@%<<N}Los2)rs-NxwYo?V>WR zO=e7y=IElrXial0qS{y?vbyL%nxh+|+FUmkGqeBasmpG<tIxCjKhK`4=i>kU1S;z5 z7U>_E^!L{noq3;P?r2~4p|$s>YB2DQ1_x^G{Fzc4>dLbV9YGC;l5Ao_rcIhWLt#bn z7WPYqg{NM(@Gs&lBI>e5y!*RFUhTJ=PsHk$ufEmf)@zz__5($2zNA~*IyE(`Pq(!k z(CrB)HLa{p)Bf16=!|?tUpZkhvuiA7;8~0F<yu@<wZ)Gn+Kf<+&Fqh~ggxzc$I%|m zDsQ#f&97+As#i6){zu(8XRq!m7}C56TQonZTl0s{D=FfzlDgm0g0Z0PZu``dKR;v( zTi&pgo<>XEnWeNN#pd5sVT+p5ZSnGDwq(O}OP`rwOa0@v^tvn~K3W+Uzq8D)F}t_- zW4mu;M9WT%YWcZdWgYxT_a8g16}6|da{oD7l@rqH>UPUcdChWGw_0x48s*Kcw7g$C zm4D@B6?}O>4-D+mnlp7;+qF@JNAtBVl&J@s7pSPA#MW2l+J>TgtawGD1=3=zWLBh= zMqRVg8$a2`tCy_o@&zj&?z4)%)ArEWi+cF=A#G}VUz?xn)|QqIRc<@1N6Pl8DnF>| zj2hJ>mZ&x+S9MbxZL6=!w*Fjf+eWjk{<C!3-apSCeS5k+cJd~B{H1Yw!hWzF4c}P9 z_HZ?p|E8vbF$FV6v@>Z?yJCB_JK|049zU+;u|sP4+O+4BMm_mnm7eN(!Jh7HwY^7n zSnIw@d!}i<P4rFp4?R-odv}p_?6l9_>gPKY@z=SwFrbw=*&M|I$>&qxUu@%sBN%-! z2D1^*ZYP+ncy@ciYzDI%%yuyQ;m_C*W=Fu5Ji9$%Hs#sv3bQTGZeN&<VRi;=4cHs7 zIbe6d_JI8X8w7R;Y|*pZBd|%&ZkL#CdUpH7Y}B*cDQ2sfy<#?t*)3+fz<x0s26hZ= z8Q3$hX<*mDwmrLj0~`13b`ESE*gIzPnB8NxkJ&%a089rkEx_~u(*#TxFm3Sc`haPK zXV(c#D=@vlGy~`c&<>y<Ktq6z04>4v1ZWDTE10%m`T{h@v+E4d8lX2obAavu?E(4& zGzjPr&>~EaFipaA3DYJ_pD>N`>^g;M6{c61W?{O8X&2BhpkYAAfR+J01DXbO4QLzC zH=uDq=P<4F?0Sc39;SPk_F?*mX&|P9m=<Dsh-o6wMWBs9AAv>!odjCx+4T}=CeTfw qoj^Z<hGII3X(^_s`2XD0Nb0)KpGIku3;k&+{*<)j!X+qmapa$<aQM0a diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/West b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/West deleted file mode 100644 index f8ddbdf215d34b022af11c3d1930dd6ea4dca87e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 446 zcmWHE%1kq2zzSHPqQXEL#O7-N5_A0SEts>%Tj6xbd4<!*8yB3}UbNus^5g}a{J$4) zZj)Fb#hA1}YI*$vP1TqMn(I#~xEAhLaAQqZa96Hb;Qp?8fhTj^0?%`)3z!+1&>;gu z&K#f(40RJ2fz}l?FmOUhAKwrL$8Z-A5gfw6z{toDLV~0J13}3$u_quJ<ajU*^Z<wk zc>+uWJp!UZo&nJy4}n|)@)Vc`dJIH^JO`$M9t6=KPl9QnM?o~mvmhGeVGs@SG?)f@ U97KaW52h&%04`8a=vr_A0IP9yp8x;= diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Yancowinna b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Australia/Yancowinna deleted file mode 100644 index 698c76e30e91f568a29daca12993cfacbfdbf83e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2229 zcmd7Ue@xVM9LMqRaYww56hxho2Js_i6h96y28M_tDairhWd{Li{y;$T!om|xS$X4K zHb+)^b8MN8fvv4&1?t=yb4f<UH0{^gin1U4MbuWSE$Q?8R)1Ch`~B{|kK6Z;yWRGE zJ$Jsk=FPd*e;%&C?;bGnKBmiDdMhtz@7a7A^_`K?k*)gvP=kKZU#TA+?Ub=@k2(V- z>YAA<k<}?0`O8v`^0+kW<79Qmey8q1r$$e{t2e%sBr`t!R%Y&vkeE{=65DuHW`$2k zT=99C9o#Q-5(i|izfI;|dq(CJRLM;<dNe+{RpUog=R3SQzrRHnjA!dD-4&WJ9H)sp zkL#_6PfJp5NRzv+Xv*?qlG^-}+?KLW(#kJO+T@fhOdphmV;@PnJ1pt1y(M={bjqFK zi<)uikY)zo(5#a|&Gx^jo`ZFo)39E1+lw@BNvSTXNz}U%(lkHU()>T7v|vGk6nrtE zg}+bB;<KZA_vhnM)c1odIde{mL+{DbBYje`=~Y?w)UYluJ0PVSj_Zo7SG24&r1wPD z$ja0vUHR(?S@r!9DgR`@+&i*cRu8pFMSr7s4_8TLcZpQ($dT$mz23LZt2Ncdx~3#s zeV!z}KPgVv&Wg~r(?9D2lULRM<rS?RJFj(b59x!azLENY%hC{jM;did9t!r$x-DT@ z?|)hzUezfZ3R-33?e(%L-Yc8qg4*P0)~2aC-7>yfn=ck=%W$T)zMiOCUyjwb=PZ4s zYf85TzSclXj67O9E$!t$%J#x>c`W^sJbv>z>2SX(9l!O-j)_AO{H$AcUI<F(>1Nq= z@&(;}ETm5y?9e?=HtF7Wzd9We*U@QN`+CiTY&}2VFi&+TY`OosR(O5ZveFe?*7z*T z;jn!Fzl|IC1atJ57w_jxn`8St-H08ozOQiCY-a%3jIG%XvK?EqA7n$wj*u-Od*Vyj z6tXL1TefCj$i{5V&XBFyn!O>LLw1L357{5GL1c%>7Lh$7n?!brY}3~46WJ)TQ)H{Q zX0OO*ZOv|x?IQa{HjL~T*)p<cWYfs5k!>UUMmBD1c8+Y_*6bbGysg<ivVCO#NCS`# zAT2<8fHVQ=0@4Pg4@e`BP9UwYHN8NZVQad9v;*k}(h#I0NK25OAWcEKg0uzc3(^>* zGe~QY-XP7fHQhnlgY*Y!5Yi!}MM#g3CLvuy+Jy88X%x~aq*X|-kY?GMZXxYL`h_$M z=@`;7q-RLekgg$ZL;8j^4(S}yI;3|<^N{W#?XxxgLmG&55NRROL!^mF7m+q1eMB0G zbP{PL(o3Y7NH>vo+M0eM4MjSNv=r$n(p03YNL!J<B8_!KL^@s9(fLnhpFPTdhdn)1 t))Y79U&Spmv9*h9x7Yj{6W(ZUWEL*Y^Kdi6o8!sK$?{})7eRJj^q)im5PARr diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Brazil/Acre b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Brazil/Acre deleted file mode 100644 index a374cb43d98bfbd06c82ca306a74f96993fd5657..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 628 zcmb8sJxIeq7=YnRY(b*vB7%roy9@pmL_{)nP`pYead0ZQxd`GC9dvQ&B#Mh`J2^?~ zbX(CWb7`xBn?(@+N@_Xp4bFk)INpPUgzt&BwVR(8u}{j}Ce0o^FP#?3!+BBeZmY_> zly}X7TU&aNwbrPtk9C83W#4Ud=4A6KbRQeH^2yt9KQG3EujHZot&Zf+(6Vahva(%$ zc0=ba2#X`C(@M+Vvr9E`Uy_ptA8P747o-+m)%5X+Ob@)M?2a!t{e<$h*0vS1`fOWk zwI_tuRb?f#uH1-z&f@>Pw(g0U*+sK6!s}sb^I^^8l<A`y0g3`ef}#=Ch)`6b8X1ZX zMTnwAk)mi(#3*VMIf`CXBS=w<Y9uL|6jAfX1gaESiY`T%qD+ydXj8<gZ{8JSZrMGl LJ1fS1HRJpN5(O6b diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Brazil/DeNoronha b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Brazil/DeNoronha deleted file mode 100644 index f140726f2a6945357b325f0bb452dce7557bbff7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 716 zcmb8sJugF10Eh8=FG5N<s{x0mSR~X?O~n^LLehw^2@+FBwlXuEiGksa;tOaykw~yf zut?v$EYzThm!>7hdF}`Ba&Jz4!x`?)^N-K1EQg&RpMHB=XHU!a!O~)?Eq0Om3afOv zS7!3d;$}q4o6@t)wqNROdR*jcjWWM`Aqu%IS&WCo>rPp}HB5>3qZ#?pDpX~<Q&vt7 zMKy4utNTx?R;tL)&4lVWUzeS0=c-HhX*qnXx;N%!Pjf~EXFVOfTM(hhgAQG#MdUrD zM^dXITDX?cM_0wp%6c^6sH8E*bN}>u#@y~XjxpsIx89ihqSG`n8FvN-hwKSE@qZMt zA2n1#%J|wkNFk&WQp(rXLW=p?YDhVx9#Rmgh?GQXB1Ms^NLgQ77b)y(D<h?m+U!kn zq&iX_sgEpxtbi=xYu7*)@wKZU%OL9@3;EiWkfo5dFlqngPkXuEFN+06?QUb?z&FdM B9xVU> diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Brazil/East b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Brazil/East deleted file mode 100644 index 13ff083869a9ac8476775587de8476654a100017..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1444 zcmcK3%}bO)0LSr1D=96lLqvr-CL)&Fv}?MSnI)!{Ynh9wNeGo_9f~NbLugbI2!*`~ zb{RT^bcp9rq(Wd}sV7T}Ky=;o)Qgl+x~$gIeCH1+Iyeu*=kQ$S@csF!8|qxvUr&wx zyGY;V_a2>j(iu}6==_zZx~4N^xBsjd@jR9zpF?tV?FW0bt4fT`t(N}#elb4QE(1Qd z_))z~{#<fI%=8?Sv(a%XSe7b-eXm3)a>x#K1l8P^2sz(!NyQG_kZ~8@t9Z557Vbfn zaJfNli0W5~l`HMUiPIt}>${ya+$WL~Vr263NtI$v%al7UV&kV3_NJ3AmD=-Erq%U| zbk!y|?|CR>(?z)@)~j5Hgzb(vAu>EZnGt*;GDW=19IRJaGp}t==QWW%J}I}|OjX<a z9Xsb#wA#_zDsxM}shzFAWnTJ_+SMGCyVrab`DHI<{_I;(;4QZc0#mARRkJL7c2^XI z9@xcg=f&QUtM<O8+p46y&i2-xQ>E=i_Wt5q;=q;TvP@*FgGUQxxwT&T@>8VmqeoOE zM#+kSb)qtSN>+Bvi>ir1S$*9v4*P5En))8m=r~Sz*n)lGjx$_hS&lOq2wUtp@7`ET zOT0cSO}g}TTfYCOLO;}@45SXDE(ECrDFvy;sEa|WG3s)VdXR#Uijb0!nvkN9s*tjf zx{SIoq%xx}4XF(&j^?QjDG#X+DG;d;DG{mBsEb6ZH0m;uI*qzeq*9|U6{!^|7O55~ z7pWI17^xU38L1g58mZc-%SP%p>cWxAk<yXck>Zi+k@AuHkp&<tK$d{40a*mH3Zq^I zvJRtO2(l8RUJ9}nWHHEUkmVrjK^BCp2w4)cCS*~_s*q(N>oV$vAuBWLr6FrG>ct_e dLzaiE4_P2K>Q)wPgJI$SSYc$2-eRsh@()nK$prua diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Brazil/West b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Brazil/West deleted file mode 100644 index 63d58f80f556e1c3135d6dbcb2a2dfc6f61b4fc9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 604 zcmb8sJ4?e*0EXctUMTUlxHza)*A@=8gNVrSGO8d11b;w9aB|VD=-OQb9URr^jIDGy z;85H|(V?`pi(5biFQrwE=gkj@m=K;oAmMuxY;NbKo!BF3pLW@+|L8KmTpZeXE&i;j z(%YiEY8;B{Oj%aLgshFc=vrw@)H_qMaT1EB`nhZd3*!BFK!5b?h)=yMzXnsPwLU9b zm3z_lo4S3`t2*JZ{4NyK=*_7d+kaN$XG=PnsjG>DJvrI;s8ae`rgL{9Z;bKW*wZtn zQg$3;9&X)kd#|0u%4*=GMaEuPC-}!w`!T~>WO1ZjjVwpjBLyOD1*Alzt$`Flsvu>M zI!Ga;5>g7Og%pdl)sS+LwjNRtsmOn%BvKP8id03)B6X3%NM+31cg1#gy+2C(bGG+< G*8c@X3<b{s diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/CET b/venv/lib/python3.8/site-packages/pytz/zoneinfo/CET deleted file mode 100644 index 122e934210cabf0b29a2dd7d11eb8220ed1cad43..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2094 zcmdVaUrd#C9LMp8h?UIfiw1`T#3DlL$bU!;Qac`)36yd&QV9)2EuuIPgVI>VoGa!& zHI{QoS}|75PF-NFp|$>w7LwIi!*Xr8vVU`K=IqZ{{oYSqcGF!wXM0{}zpLls_jyOw zZEGp={_(l+@6%mQ{?8bg8Q3^5dHl@2sh9?b4(XXUr2V~nG&ZAM<EK{H(H8@ncrIig zKUHGK9?h{&qN(<2?J`|5)TE>*=GdjZVOd9+lACiiE0U(!H7o40;@^~#{i9N6f2lzH zQ3cMvskD=?=<?4FXwJJ&D*f;g%QzUb%zgW9Zl5e``y)25HELIEXtFD-BbHqrwyT0= zmXncdSI<nd+=P&F&y{HYH#u4`nW}5vzev}P{G#B{_gdJ0TzS18DZk^e3YuS5VZ)Ra zMMtc-V$@33JZ+_!gH~45Wo6SnwkW+{i%x8^#lLrI$&rv<|3$sZhZ|Kfx<ohZT&|@9 z8Cuqot>wLo?Z(Okg__fCMb0UOL(^87@S&=*zp|>+-`dLfw{7LbnB8>pd0Q2G$*RZS zQqAr@t3CLvZf<L{TlyZ;>f0XIn%2##yRKD{>MGqDsMXrw0<Aq?p!$?btN(nKZa+8Q z*1h(#)=wtdh6BmgF!Gb#(R0=s`zLH;<D_lc@q_MM`nokWjH@|ouWhb~spaBB+L9@4 z`EHN4PDizEtXp@Ti0JMY)~oe{cDrX+h1!Pe?B1<ex^HKxwXZI>XiLEEFPv)~;a}~6 zWY0SDQ`C9pYwJonudZY7S@-EFJ^1RdJv1?@?R($Rj@Y0c?jBOl?jFT?7sUS;ex8?P zUV`Uk%!_l^_OCZ5p>SQq3xy-@FfK0gFE0Kc?&0$Lx&a^~K!$*f0T~1`3S=0_IFNxL zBSD6Oj0G8t`#_J;Aj3h%gA5265i%rXOvs>+Q6a-Z#^vh<hKvju8ZtIyaLDM8;UVKg z28fIh86q-9WRS=xkzpd^L<Z{XMv4p-87neaWVFa|k?|q}Mn;Sb85uJ&Xk^sLu#s^i z1NU_!M~3d}#*Pdg89g$5Wc)|~kO&|lKw^Ld0f_<<1|$whAdpBPq40IFK!V}xqJe}1 zi3bu8BqB&ikeDDrL85|$1&Iq17$h=CXnb94kl^^b=pf-i;)4VTi4YPZBt}S(kSHNx zLgIu33W*dFDkN4&uzX##kZ>XKLIQ?F3<(($GbCt8)R3?taYF)!L=FiZ5<4V#zAk!5 u_<UXbkN_ePL_&zf5D6j@Mf~4|G0_!rVIi#y))eQJ<`o2M3JWm5IPp)==nT>T diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/CST6CDT b/venv/lib/python3.8/site-packages/pytz/zoneinfo/CST6CDT deleted file mode 100644 index ca67929fbeb05083c63e8319dd9ebf65b3d75e4d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2310 zcmdtiUrg0y9LMqJpvE6LNEU@iQd%<PfPkTBQWh|FC<OJ0AY`E!Vi{i(P}JygV_+BN zCTUm=rO4IFsj&=ek^Nok&kSkKW-+bhoEz~}UYO81J@3cMuDWY|&wjtxZ|DB=4y>$u zEKB|4CfI*?xV`q_JGSePPak;iPdV5Yqq|=`CtvLh>eDl>$m!}xbM0!a8olH<V`u&9 zuP;(furF1GUiTW+=~bTg5fip~M2*`RE#s>v>ItR4$_<N#b$G_N622>0N5;M_k%wPZ zQRaD>c)mkNe}B|?Pd4h96MM|0H}<I5{SD^EXB*Vy<}!0rU75PMBFDt}bJQ*K6U?nC z2`Ya2Jed+PrV_%YNW$;&dg_HyNgTMQZ~N#+nRe_4oz(rI+}<=v-La!vrZ4|Z%~=0| zxifoE-BonJ%#3?SCC}Pnl7j;}C2EaH8S2%uE*F^8{=M2axLVS>HtY1>e3{)+p))#W zN@i`7%Gwkma|+AV-AgY^cJcx>H|uMe7oMncrd~2R7lUg4=$B@}=jYWu=iV|4kBsTu z_n$NO?jF+jy(DH){Yia)>n?eq<Q1J)Q!n|mTXjMH5-IrOT~(O2!4wYeSAK7a@%L_1 zMZ=lq!Ixjq51m;o#oL?p;^P@oQdOx-_f3{13v>0-#w)TcF-ZrOpOL_rN0(*yN!c&c zRQa^;O!;R@RRoWll|4VH%ArnE)%vM=xPPlzRdYx^(p6<1E&f<nw>Qh`v>v^two+=m zZF+5CuB;tir)!gwr1qO4T^H_=y2C!b{^HN__&&dS;#A0NXi8O29=TxZ%e+c<e_}Rf zkEo~WUo)HH22?{yyJ-jx>!zF@X&O4Ex5T%}mi}Y9`RY2^+SQ@Aoh_2>Esgr=KA*I# zTA`omj1iCWsIYPN^<VmhLT?^a<3phnM?K2DBiuXs`u}<P0hPDRJ}c}~8ek%x>#xAS z7*og|gF;4y3=0_-GB9LhPCGPYY{=k{(ILY_H$FZXAZJI&F+^mH9D_tgi3}4NCo)i{ z9Vs$YryVQDV3E-x!$ro63>X<P$B>aRa|{|8HOH`#adQkD89B$$k+E|O-f2gV3?CUk z5&$FuNC=P^a0CH~0!J8-IB*04i3CR|oHiCnFq}3TNH~yqAOS%lf`kN#2@(_}DjZ=! z;=&OaBr+VKL1M!Z9H)&AM|hC<a0Cd65E3FJMo5s5C?R1&;)DbWi4+nlr;Qayu$(qp z9N}`>cyR;_i5L<xBxXp^kf<SHL*j-64v8ERI;V{t5<I7k9!L0`HhvrdL?Xx$LL`P9 zK}4d+5k@4ANFb3&BB4ZLi3HPWqltvmY2%3m)M+D%gcOM>M^KTda)cF$D@S0F$Z~`h zi7iKPoi@5ic%3%BNPwL-!bpgb7$ZSOqKt$Yi8KE10v%<$J=gZzS3D;@D?P(koSB)P InVu2#H&QWvHUIzs diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Atlantic b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Atlantic deleted file mode 100644 index 756099abe6cee44295a5566ad6cd0c352fb82e64..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3424 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 VBH;<`BBCOk@Px?7h{y;h=x;6=LMH$K diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Central b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Central deleted file mode 100644 index ac40299f6b27043e8f2454ac594b0ec184c1a237..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2868 zcmeH|ZA_JA9EbnMHxNb5#0UvYD~2Khis1`osbi1`>Jd@M)G)*{9^X)W!GDX1ep0i1 z8Aa--<yxV0DQY8Ab8h7vq9kdAsN_`gN!>yvPWN?JTU&l{>tnyO`?;R;d^qQPIoIW# zp7&au{A+&Z35Ojthx=Y?E~TFP4W&m9rk7Rj&<_vZb&hNwsYla_-EY^n>FNG=oYS*9 zyESX)%9+VC-Lq59N^Reh?)UNg<(yQwbwS&tu3@8l-hABo6WQ*C`Yrn7t_@CoRiXa0 zZlTjqmZcZ-yiQ|LqFzcK=3Jf;u2&+1ou;Hw@^jCj?$wAexq7R&d(HfsYt=38^`=I- zQG3j7K7LGo+4!Y<JHK4-#Ljl_c2CiJ{snTcC0FiW&6L)2$@2S&5z<yUP<)?+ifj!O zPf44!TY6L4F9^{Nv$|-<^j7UOx>@~V>eavRDec_jum;E;4RCjAmxfK+weBkkJiJ7^ z9oQk=cfBJ$w!JNntXnKS3+KqAc^T4cT9O1MCrIz%k@8q%hy?c=r;q!$N=Um14Y?Jp zeHuG!X!SjP;_K@gw&#L|?>MP_3%bjbZ&hf&DZfhpdEd!X@ip>v%IES-&=(RhV1q=o zRcmCxLW!*3s{^iiWnk5N8dc-ypt7YJy?2rhE}Et>n}%v^Zh^!t>a9bPGG*wb7LAV> zA;aQ+&}aQZC85u6lF-y9!|&J0h~o`1^86tgRne-6hdz+!*4OLvrK@Fh{$YKgxKv+E z+o@x6R_WNm#X4^6L}%RX{gO0jzME9DO_BrC+~mD0B&9jled+xzI=*&-le)4{C+v%H z(z3HOeREG|;;2NOwB(L6IW%0oQ)(S=t4A~9E1irhVUihk#?AajWLn!kcY1lFWYuqV zvx|?(%T>$W895)zD`na4%+w<~tEAAGJ*Zq?&CPOh0@vuAq(o;<^IXl12zPQ%rf8m@ z$I1IFO6N6Qa$et@EN`6hx$_GK%9|Az-TaI|an>Jo7sTI`h4~-3i-M|UaaxJHxUE?W z63U%|`ct|rc#X5HYL6DS%ypKRZPFFzQk<1VOLSFblv6Zgs;=JJ&1vVcul61Oy7}|% zgRUJr{kN|NeaFK*^ZCkei1>U5c6&Pbe4lO?e|z86UVHrW`S?_?j2UarWOJsPlkPSD zZV`{iV<F;w2s8N1axU+F7h(uYV+n{UAhv)Q17Zz`IUx41GzNiK1Y#11O&~^rSOsDh zh+Qm=VIY>VG^T;r24WnDbs*+}*au=Dh=m{~g4hURB#4zDW`fws(ijS2DNAE2h^-*T zf>;Y;E{MG#27_1(Vlqo(Gl<b3R)d%gTDx(B;h3=;!*mSWF^mVX9>jbQ`#}r{u^_~R z5F1(=BSNeQF(bo{5JNI7$uK3umJDMutjRDZ!=4O-GAzn4Da57>qgooPLd*)WE5xu6 z%R)>Gu`R>65bH9`%djuQzzhpBOl)av3^B5$u`<NW3_C*%4Y4%D)DT-kj193i!`u*i zGYk%~IK$)+n=_1VX{^pLJHze_!!s-oF+Icf5aTnf4>3Q){*VGdDgY^grKtg<2$rS_ zj51i7Ixq?WsRX1HkXk^B0jUP09FTfI3IeGJq$HN6CXk|7nyN6$VrlBaC=8@BjM6}A z!zd1<I*jr_>H{edq(YDqL23jklBKB<q)e8kPLM)bno2=R1*sLISdeNl$_1$xqhOGV zF-iuh8KY>HrfQI~S(>^*3TJ652Pqw-c97yhss||_q<--K0{&gV029YyCX!L9L!#rN PW1>=HW20lEV*>sFRXeOf diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Eastern b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Eastern deleted file mode 100644 index 6752c5b05285678b86aea170f0921fc5f5e57738..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3494 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 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Mountain b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Mountain deleted file mode 100644 index cd78a6f8be1dd55ac5afd25bbae39bd5706e42d1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2332 zcmdtiT};(=9LMn=gaRiXew7#s8fi%oAP<s2W>gR%o+LOR8etU34pxx5GcCklf+M=| zTN$&N1S(-`g{f;cHqabyJ?PwVxvWIX%4XT<VapBU^n3rW*t+Vbi@s<7^ZFmS{=7Xa zy{j|TKW>Ws3lG<2AKs_EIC}Cz_u&C~b1>BO?08vv{9DcLmwuEz?Nim>#!sX#`<QvF z{F3gE=`;JXKGyptK2o1{Mu>mzAI<*SSoL|uMSUjWYZX#EL#C8oGgI@&B{Y51ge9Dl zaDBwM)Ude5cAM)j^h(6pVHJ6#O`<;RRnc$vX#IMdx}kH6zHwu{y2)For>!VbF~tw+ z>A6Yj=A=7x?3_X~BiyBD1}B=Czs-}lZ^KQzKTKvF{mIOJ|FYcDd%`66X6ajB7%+1x z0(x%aXX>`>Z}ja;-c$2pj_Jf?QHc}hCCRl`C5;}H<jWp)=g=NWIo)hhySGZ(!7?+y zwL#KfU0^aA+I8l-=_adawO&wm)nq3=r0>f7(ku*3);V#1s+>y^I(Pi6$~*pxzWb{| zwP?Rf?it*r7H|7m?%lar<u{#_``UM!`<LyP2kJJNg88pVVZka>`1^=1N^Ma^r~7qr zWQ{65*r}IX$yX(B^vTjQ)yCb@ArF7B*et8|N@-Vud1O(El=*^9d3>sPD!wzGYtd4f zecV)jpQ5W~UsP2iQF_J1h+4UKOg}o>ud3Vq`mv!-Ra19Juj*c-9(SLT+KvwMMCt)~ zvcYTWBDYI@QHiO);**BNRMT*xO1z=b#`|ubH2(0bS<|&#KXocfJ?+cY&kT&Irph?o zyv?tk&HhWTZ91gZ#hlmcmvyQ26XW8`IbeLF=VU|dcC%q<ST<hundiED<@qnFOiOE< zY&x80T5IZM^Nx5E95m^3UC5*#lmGEwzXt-Z^(YkxywejD5(w-P73RE0INy4y+oRkC z_9?f|a{H8e>_n6ba=twOVpRcqEDKo|vM^+2j&^Ct+K|N|t3#HDtPfcrvO-6@L}ZP~ zA|352k!2$5<X9-OQe>&fT9L&ft3{UUXxED@7+EpLl94rYEE-ug$Fh-ib1WQLImgnG zwR0>USv|6RWc`k|07wOp5+F4|ihxuBDFadmq!36YI7)%kf}<EnH5_d@ka{@Uf*=*) zC<#&%q$o&Lkg_0kK?;LZ1}P0v8>Bc$b&&EP^>MTXLMp^jBBVwfMMA2?Q6{8L9ECzE zg_H`Z6;dpuT8_3{NWC0w!H|kM+L9qP<0u+ZHKc4v-H^f|l|xF0)D9^gQawjoKBRt* zwtz?l9c>Ab8gdj7sUk-ikveh|5~(CdDUn(t#YC!!loP3^qb(>>QAb-+q^6Fxs7O_j zvLbcmC@fN0j?yBv<tQ#vU5@f1^>wrbMk?%RON`Xm(H0r0GE!!w&Pbt=N+YGl|7WdT ZHsT9y%v0Q1X_;y1DejDnw2ZWL*WZc*ZxH|h diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Newfoundland b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Newfoundland deleted file mode 100644 index 65a5b0c720dad151ffdcba3dbe91c8bd638845c6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3655 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 AC;$Ke diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Pacific b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Pacific deleted file mode 100644 index bb60cbced30763c08b6cf73554c8d6651ff387d0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2892 zcmd_rZ%oxy9LMns{^5_3Cle(?JE@7FBA_UWW*Y8_iKtvj%<xYF!!%Uvs%2=4R`!oW z=ATy4H}XNQ5*@SIOonc`T2TpRqIM%oWgw|&iAwi&-oK|k>S61!b6&sk{JuY)g+&F) zu78{!_CH)st-XBr+hU)}gNNn4Ly_j|t<lmj<ofD{rNdOCw~szCHB|jD|EfNzTh)&# zjrx@98`TtfKsPn-Rj2*O<xHJXXMHvD)1HrwuXelqy!Ca{T)AF;DOzpLmFCK?8S~6< zd1-P!ZmhZBUZ5}bovT`6C+e1tF{(8rMz=OZs<sP$eQEy<)qbp5|6b9gE?0NSl{JUd z)pDP7Y(8SH71zo2#UGeIva00IDKD5Cqsydoc$K=@r$BCnmZ@8v&+FSQ1*+>*zW(dW z8Ondqtpgv%E7z_#9rRLf6}+LB?zU#Q>Ao~pddv+sJ*S3ANa7_Es@o(?eQUy9^%8z% zpXt?HExnuSRYYBd-0@kp>a%CBR&Q0PJGUC$cVmgVt7xt6mpflYW_Wb}3FFm(xN$ma zaJIQSEJ{ZQr<mxDv2xG30VbxQzYIKb(+t|*DfhmA#%S*decyA3&ET8}J!HjcH8kb2 zzJKQDYFOlP9UEV%V*TwB7rsTs`M#6*)@5o$?S2{ASZYR9Zj*$XC1!N#Q<AuCnn@~r zLnoIEHDlcC^w{j4CM7mUk4tVb<3mz)YD^E6dNEp0xP4JgJl3Vt&U~dN?TeDhhdxpd zl;4smZ@;D<EIun!%l4RQS+(-e@>fjyXp!mZtIYIkjoLlxW#w)>pfe&?s*IYQdS?4< z_3%42GVA0DleuZT%>Hzi$y&5t=Ilr?b0_7>Jg+j@F=^tN-(fsm10^TrgvmKSQ7;&D zRW0};M(6q))xzC={iyGNT2$7oAFJJ|@|GXfiz_#(C7C{1`r>x8Y*d{*Ubx;YkEoJ- zcdp5AFO$O9G*eh#AVnbqP0=SaWW|Mmd16PtUip2DTIF@?C#(IcI44f8E^k(A#`V%` zi;t?3$acLhYqwe#2orB=o$>nGWJ6Sy*-%?A8#~L))0Nfo%&7viskB0#JvhUZ=9S3i zUGXM3D7ag9`}{Zm0)bcGbh!e7cTG_DK%jh!E7bY!?YwGMrpGlW-QH|_AF+3i$NtJ) zt{~^}{EIpS?8%$#y@XT(DFspsq!^C28b~>idLRWsDuR>*sR>dPM_U!7EJ$6D!XTAF zN`uq}DGpK{q&!G{kOCnULP~_x2q}`ItrAiuM_VVPP)MbaQX#cMiiK1QDHl>Nq+m$J zkdh%aLyCq}4JjK^H%D7Iq;g2<klLYBJU*x%$CeMMA5uW1f=CIG8X`qRs)&>ksUuQI zM_Wmxlt?X+Vj|T<%8AqyDJW7=q@+kqk)k41MaqiQ6)7xISw~x1q_#+Lk?JDlMe2(b z7^yH)Vx-1Mk&!ARWk%}kXbX*0+R>I8sWnn;q}oWik$NKqM=Fk#9H}`{bfoG?*^#;< zg-0syXiJaO9w|OjeWd(I{gDMgRsdN7WDSr-Kvn@+24o!^?Lr_c;b@lvSqn$I7|3cM z%Ym#1vLMKcAWMR*39=~2svygPtc#;v7-VG}?b0A?<7gKLSsi3~ko7?p2w5RyiI6oy z771A;WSNk4LKX^HDM!0h$XYqt#X?rg(JmLVUdVzWD~2o?vS!GlA*+Tg8?tW5!XYc? zXqOIIJ4d^C$m%)T<wMpFSwLh3ktIad5Lrb0f3IS=9m`ZZnj<sEBqS#!j?7F-N=Qmb G4F4NPN4LZP diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Saskatchewan b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Saskatchewan deleted file mode 100644 index 20c9c84df491e4072ec4c5d2c931a7433d9fd394..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 980 zcmc)I%S%*Y9Eb7Wq@_$lyqJMVi$W|41r?0;Dt1v+oCsXRm>A5;gMUCATqHt^7hF5K z5s4sImBW-o-ctz1OIfDJyk9wlE5VNMb9AR0SH8o0K8Ime^L)c~(HBK>;#@M{a5=^1 z@}BkTp#6HRuUB^_((Lz*Rqls^2hPW`Lbp%db>g{K-MAZa5?2bW#P?n2({6_KIet0v zwK?4#sNZr1Yc}1X`|Xk8!U=ceX0J1vy<v?7Cn96}<JPy$caib7kWS|8S;_h=nQVBi zrfQpH`pJ@-xiKd{iigxs>6h7SJ!;nJl3)J^^zSb%GB@9?|GbIW^Zl)Qq0P3PSX3`Y zpWA<5KGsVQOYP-n`FiEfEqk^6ky^_rk@eeoYW-iXY^}O#duCF0hLh?-;M7k_>ZxBJ z{rIBibu5c`-rKG~s(IIv?!Slpr{XD@6_sJBEH$^*+^6PNho!{4a{|ZD@EQJm&m00E z5s(l_3?v8=1qp-1@il>vNWLZ%5(^22L_@+M@sNN>L?k2<6A9{Tq9S3DxJY1M6B!AO z#72T6(UI^-d}IK=W(3F(kTD>GKt_QK0~rT05M(6CP>``8gF!}v3<ntxG9X_wB4kL& OnDE>O6*LRG7d!-P)%6Mh diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Yukon b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Canada/Yukon deleted file mode 100644 index 9ee229c0eb82c6aea7359e0b38677264f3cad8ab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1614 zcmdthNk~;u0Eh9XIix5Y$T_v+lv8S%vo@I`np62SpJ@|PC`Hm>n-T>HGQvYrE;2hx zn`onm5m-V&LAa=V(IP`42qTcnf-J??`7X3-6}0L;&ix(l%EkY)H?$l{xBc<>m@gcj zCUdyQb(+`Uy{VC#6ERvp_Zt}+p6;Bwm@qOO^Q~?AP=@@T)~*&4hQ(6E0kNj#qzrJ> ziojC449d+G!HHQiB)Ue0`h>_Z_e>SGkfGPU3s&LNK|12$4;4AOsMih6DA}GYqq-ib z=sJHH)B0M(W`2@!W%tGUz!x$;X;8$k%<DwoPLVkKOecLjERrWj^#*5$N*V0asbdFK zTE`i^v9C~VI(kK>pNdtROHRv-8ZVU@UnjHDKd5Z)9GMgDDRSn*WbV?O$a}IZ^Jkul zf{_rtW#W$5+WS*)yM9@0Kk-KI=)SEAt0wi%=1Zz5P3z*K<Er?pQ<kLkh!W?xEcHJo zO2_(T*?gtgH87^jU$v@=b60ic-Evjccve?mOI5oI9C}Z?P&MKC+FrY$?8_0lF7u_T zd!HxkBfp6H$Klek;uH<HR^-0fanacQRyIxci~Y@y<blD)&+cyKx5~ra)7{JaU;kFS zTwTpJo6FVP>E>bXZ8r18-2JS#aJg<Mw*c<8Q0pGS+ZI(`VYfMo%&9SFuQ}EHZ9Y_+ z57ovBBafT){(Z6k#nN2nIe(#N09hQeI%Ijs`j7=8E3`CAMAnEb5?Lkx5X(f?i7XUZ zDY8^#t;k}L)mob6BI`vKjI0=0GO}i5(a5TiWh3iG7LKeOSvs<IOS5=n^_FJ&$oi22 zkP46zkQ$I8kSdTekUEe;kV=qJkXn#pkZLSVIY>Q7K}bbNNk~mdQAkxtSx8+-VMt|2 zX-I9BrZ}WJOH&?FpQR}fsSqg<sSzm>sS+s@sS_y_sT3&{snyaHi&SfA%0=q6GzB9S XBPAm>BSj-sBW2_NRkyE+KHK*fniI0_ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Chile/Continental b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Chile/Continental deleted file mode 100644 index 816a0428188d99f437004312ee73c3860ee0f54f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2529 zcmd_rZA{fw0LStF<?<8{2|^~Qg%n1iaDc0T0Uk+IQt+1eL{~C(AZmcbLn(!^l~`LO zqqU~Z>``6Q16DwjdDa7DQQf;@WRtZuwbh!8o-9po=lfs0>Q(RB`rrM}=kC6|+wXfy z%c?3et$#eB<`-U`m(0ue*xlx67fTlJ_ndbhZ2orOkhMdr@}_~Vraalb(DI&GTdUtn zbh+Qoc~!pStn~K8kLaFr``x`)J-Tl&!96s+S`Kah&ilpLcKzkF(`q<#l^$;FkXL=V z@><7b<sbS~TXkoZqrt5MWRY^N%FuxcDJm#`g$%YLRY>?r8S>4T3cVI1uRG;aVWYpw z@WU5HME{74Z1aliU+j~UwsecACx><P(oQkCqDRLhH;UNBFX$VhJJgg}yY!UtdNnn8 zy`Jh@t>P{$(D7Z_YTD->IelNensGc|-c<Xiy16|;CbT%k%$fk1m~%zkQgTk-8aFDE zvMrtT$0;%Er{DE$XAX(vOCRXl-|JU*jJ&Q>UOuR1_q6Fbt&gkJ=eO##jhmF%y+@`O z6sn93RWdVgM7ZQKIX8Tfm>1bAvx0|Jwlzs+e-bKkzE9EfkNzO;JRPZXpBfT*hsSjO z)?;Epn@`J?AFG91PUwQnH`QHBpVNzCo>7JA-LmlKTD2s)Q!W_`5KG4!WzoqRakp=+ zT-Ix;<z4e-@j!?uakuIf2aYLs!5Mu|^Rw#Sl;7k^Pn{|a|4OdOx**mZ|52~I@guRW z{WD#5>8QA`MrqHHO0~YeS(ooEQumjZ>kU;Y>H(M38;c^<rr1QiIeAQN{v}XXOpXv0 zqcdgY_(id$-zlqnUa|GSdAY5tTWoJ0ln?If6xE(1vSz1JwYg8r9c3M=F6j;Z(ENH; zAGB9D#IIHj=eOy`%h{^w!(#pL*YWC+*V6RP_p`*VC!%%pD{<n{>Qwny>lM*b5+z&w ze!nBY;dBHBOnjUH&LHy!hx|uA!G3@LyOw32fqs9VvO@j-L2X5FI?Orjbwo{^{Jy-n z)LLoYIbyDPUFMxwqQhaPW*&#5^k3}L{6+q%Ju?Q7og!OB_KIv4*)6hNWWUIUksTvj zM)r(s+ScqE**3CoWaGAG=g8KPy(62qHM>W)kM{ogLIZeA2Y?nJJwTd(bOC7t(g&mw zwx$zEE0A6w%|N<=v;*k}(h#I0NK25OAWcEKg0uzc3(^={(;1{Swx%~obCB*J?Lqp3 zGzjSs(jufsNRyB*A#FnXgfz<5bP8z|(krA{NVkx7A^k!chI9;R8PYSPX-L<Qwjq5( z8i#ZaX&ur#q<OZcdr13`{vi!SI*7Co=^@fYq>D%!kv<}gL^_GI($@46X{N2|Celu% zpGZTIjv_5ZdWtj^=_=Azq_0S0k<KEmMS5#%nu~PT*0dMtFVbM7!$^yf9wSXgx{S0L z=`+%3q|>&h)kv>xO|y}1Bke}|jWitTIMQ;Y=Sb6$t|M(n`i?Xn={(YUr1!R_`AGMX z_9OjA?f~Q-K<)zMK0xjS<X%AT23wPk|Kt4-mTPW~e3v;h^Jf?5q^76NOUrQ0E_VI> GE$lDZUi%6F diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Chile/EasterIsland b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Chile/EasterIsland deleted file mode 100644 index cae3744096402e8a452336544edf96ca9ae5ad8d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2233 zcmdtiT};(=9LMqh;W^+W2$|3mS{MbwkLQQ*_=_YVJxF=dBs5cpfF(pgrWD3jVzpF8 zYi_!%R{7BM3tcFi%-?#l2P@BoBU`MSbgMNPJy}}*`@R3wRqLXgF8ZJI`@jA>7w6*a zeBPmkmZn1IZ&$4Sgv0f$Jv^swwzrYvy8pLurM@(9LEIA`8>iz7@paXk2wf|YcNdtb zjBJSxEYdNKUt$xE>ew$QB<@m*zU)|7;>Ul~3470}#L+SB??0(7-#wzIG!Lt!r%svV znn5+S>99%3>Q<?@?=)8=56HAxo6NMyPMIFF+)NKIk+idOP5MxoT=i+AzIsQxTyrR( zuWkQTuG^NOGkPP{jJ60pv;3mEzV0i1L)y5?EOSieFUQoZ?|wEno_<MXoqxyN^wy}{ zJocK&e)&boIoxk%_dOxGFSMGxRjWm9-lFrXs-<9Mi!Piqri%0eU7RpamH3b7(wI|H z=1kFLAH}Kiud_|X{%_PRANWn>(<juNy%Q$TdQi>n4;#JsL%Fs2O;c6)hTK;3yqTBs zoK)uz>+0{@Wq$IYo<9+xY9_mN?a?-MNBADS;D{p&hbnaNy;xOO-)9!>Iw<v3r_G%` z+vTq8pY-C!4hbcErk9qURZ9<jYnEO4zFM~J6Vq^hzq+?gOyj<_vb?j$tk_yB_k~uN zl`YwFe~~t;YW=c0b*5R9H6d$$h%!x66IIjr483;poN6A8)GgtYs&&^Hy>4h&J<xMp zKe%I1t#90?+ct`{S3aX3Y8a4?%-7As6`j%<z14K3FOjY@>rD5BGI`|PpxN+wx;*-7 zp4s?zsoL~pvgvsxO+B_gS3ll&QT5g(>0Z}$eNhpS|M-fI`7d8FuDf%C<9PQd*FCVu z7w5XWw>yb{-4E<>>?b4QOIjEVIo0;eRwee7+EZ-*_dXx*KM4Jc&Dfv8ZP`*~zuSJh z-43!J^ftr;JL0li0``P#3fUF1Eo5KF#*m$P+N~jbLpF!(4%r^EKV*Z*4v{S)dqg&g z>=M}~vQK2A$WA@&R*}7W+RY-nMYfCV7uhhfV`R(7o{>!>yGFK+>>JrQvU5+nb!6|z z=8@ea+eh|~Gyv%U(gLIhNE47QAZ<YUfHVT>1kwtm7f3UZZg|>uApJlZf^-CF3DOg! zDM(k4wjg~$8iRBOX${gFPum=%JD#>ZNPmz9Ass?mg!Bk$64E84O-P@RMj@R-T7~oq zX_lw$7Sb+H+b^VHNXL+tAw5HyhI9>S8`3wVaY*No)_L0AA<gr&-9y@k^bctu(m|w! zNDq-FB3(q<i1ZO@B+^Nwl}Im<W_sFgBJD)_i8K`HDAH1-r$|$gt|Dzk`s!)Z@qcY> ee5LJgpv2yb13AI+-2B{<yn=$9V9}pX@xKE%a7T*( diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Cuba b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Cuba deleted file mode 100644 index b69ac4510784f23ee794cd6d11e62315a7318e5e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2416 zcmdtiUrbhY9LMp8zcJLJ6#qmLCJ7b)9_Vot3TG2VL*Pq1n({9)1c3-M69XaFN}{#V zMQJAEqB7=IVPpfV(OH5rNAnxxu+f--ana`1az;e*^n0Jx)<rk1uKJyw^ZM=Ff8O50 zs)}US-=5$<{<a&rhaEJZ_jY`7@WYYUq<e3PHCR-kgCqIY`LvCC{<B(pD0-(1wddJi z_0N;xwCncB+gIi5h*5jGEJ&w)P1elXOr4o5uzwv()7j2L)^7tR^hV1rYp&O&zRpS8 zb!0;QS_W+Y`hE@AJz)iweJ4SlMRu@tMs8ZX(F%z=E+Ny6cBrdGLVv8b=3TCm`QIF} z7ueZy^XXmoE!}TPSkp1<*8Cszwu&Bmp?gRdZ8&O&7d@|wS2fy8(#mydaEZMvVuLQ5 z%CK*rjn#+?#nv5Tp}M>)-HL1|kUQI=tf)edtf=$1?pl|xD|4?{(JNE*?u4_}s_>UJ zX32ydGuJ7x)5Chtc&pqydP?u>tC6^#!y4a_BMC?LYhrVvB-IzHyE0poA6cU*S@C+m zwOu^RFUsoVld}3okEBKnY3kI7J}~=%K6v(HO&fbv*K`fb+E4drdfO?<IObKWqDa?g zdSv~zS2QbniDZ3yLN*1=$fl1(ADSGK?DksOJT$F2FScs#=ee3!e_7@ApCy0ILV5U^ zOHvSVUA$X95%27%Z1uFu)+^U^TV$_p>%XYm=ib!9cY3sF{D2m}a8yhBO0~4SQ6KHF zv@GWhd90;GcEmTx<CPgwzMxokX04E&SJS03CO|5`jFPJ0@1^Q}f2p22CpCv7^@$6U zTD#AsPj(Gx-IfX6-PWm3dHQuvU8_DF{;uxLtI@r4XJlXMOR{hLxa?nAE&Kag<k?>~ zOG8JMG+s)O1I^je)Eg$vrSbCIk)Omb!2jPqf&PDaf&%}$$LH%Fbh*seb_M!;=WM?a zpYQZZ*Ze=f{Mnr2b!{~7x=iyHc+GlTE<Zo-KUkd4oT`@CUSxU5`j7=8D|9qVMAqnN z7KyCV(JT{LC$dmvrN~l|wK|%`BCB;Y%SG0UEEriavSf7D%!NgB%&LK9BkM*Mj;tJ6 zI<j_T@yO~O&GM1;JDLI@6+lXW)Bq_0QU#<8NF9(uAeBH$fz$#i22u^A97sJJO+k=~ zASFR+f)oX*3Q`uNE=XaJ${?jdYJ(I9sSZ*eM^hi9KuCp<5+OB0iiA`NDHBpBq)<qu zkWwMFLW+e{3n`bQsTWc(M^iDRWJt}Bq9Ij7%7)YpDI8Kcq;!s^c1ZCYP4$rSIhy(* z1w<-{ln|*QQbeSRNEwkjB85aMiImdO)DkJCqp2oRPDfKuq@YMek&+@cMT&}46)7uH zSER5=Ws%Y%wMB~SXsU~p*U{7$DX^odFj8Wq#z>KoDkEh^>WmZ`sWeh*q}E8W9Zj{7 zayy!OBL#Of6-P>r)Ep@~Qgx*4NZs-OTli2Ddyk2JTuw?tazavKQe2MPo!~Y%cj)ib CX!a@q diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/EET b/venv/lib/python3.8/site-packages/pytz/zoneinfo/EET deleted file mode 100644 index cbdb71ddd38be8f4a23e57bdb4b86e52195e9f89..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1908 zcmdVaYfO~|9LMp8DKlB=AB;-^ViJOMfWy^GkQyAA3Yc;-;u0xWjZl#on97{Yxn%6; z#%!*fIvI1#$QPt9@G`s27O^(R9F=R!Rd$(cGe?)P`Fx*x*Q;JRpR;p5XXnLv_5c2Y zRa={~oc}yC-Cua~>~`OLpZ(Ziz2+RAZ*zMCvW`53HzX?}7^8V*MfQ01Uy4lpMN#v< zQS^*26n*!yVs5>!C$68={Ev<(_TnXrJ3DOg@0_p&eX@i-`)y%syFFP`Z;MKUmY5%~ zr+j&q6qjs^AC0l(&_X5O%TdbrNm?=yrPNPm>FJR_<Qx1+X#-y=z4vovbX=6b;XP&6 zPFhy`h-DXyTF%C!mK%TE^0K-tZ@R~p#SUoM&CRy_?@q0_RA|q9U8($`Iu(qr(6a|u zYvtQ<TGf=O)xFE@x#Cb2HpE&{(vJ!hPFr#4XDUhj)=KXDU~6VvwKe0{Z0)Vnwr==c zD;>L{vi?3RKYL2++uH2;z609u;+xvo+Ng@9tqPWw=!NKVZSpPArYXNFBa5x_Muc9v zmts}te^>QHnAMyNx7v|k?d6`kRyQziuhdQ0=Dj~_%gPH@UpuCTgk#oNFs!CWK2USK z)O`CbwM@5b>$PreyBXB0XR6iu=}vp?P=VTpDr|d8f_5CtwVfOCt-UGQc4aQGj=-Px zdbneq8IkJz?K|t5Go`LCKep~WliGc5$le$q)t+M?YVYuI?du*?Pk)a>oCo!CoVbNf zsN<yiL)?S==aXLofr_9L2n3ywf1lw0I9vCh98MQGU*v?5Ge%AsIcMagk+Vil8#!;} z#68_JM@}6%cjV-evqw%JIe#PpBm*P`BnKo3Bnu=BBo8DJBoj|J6(koV86+Dd9V8zl zAtWOtB_t;#DI_Z-EhH}_F(fljH#H<TPd7OvJ0v|MKO{jULnK8cM<hukOC(JsPb5(! zQzTU+S5G%tBwJ56T_j&5VI*TDWh7@LX(VeTZ6t3baU^pjbtHFBH+dv`Pd9xee`ErX z89=50nFC}JkXb;c0htG6B9NItrUID@WHON1@N}mGnGa+_kQqUy1ep_LQjl3erUjW7 zWMYt+L8b<o8)R~j+3|Fz2bmvFcY=@^LZ%3rBV>}0Swf}>ACh?rbGIrji`DX#WvAz+ P`!lkAWto2OTTa-0+xVLQ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/EST b/venv/lib/python3.8/site-packages/pytz/zoneinfo/EST deleted file mode 100644 index 21ebc00b3fc096035b9810519d778d04a3562a44..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 114 lcmWHE%1kq2AP5+NDp>yi-?@Q-!8JI9A%rYlTtKa+TmXY14MYF{ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/EST5EDT b/venv/lib/python3.8/site-packages/pytz/zoneinfo/EST5EDT deleted file mode 100644 index 9bce5007d4dbb871974a69cb0f68151c1ee22556..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2310 zcmdtiZ%oxy9LMnsqUZ$@Dhd@Tp<*Ea4Mn8Fgb~^m(u*OPel_q8p*X4CpbTrFq+4@N zgZ}N7WoB)T%xqeXsX23NX3A>zXLxLjwTe1M51iz^o%iu!k9yWRcjvr*yU#ywe?#-? zBF{h0So;r`^Mbv6Cx-T<sn<UGMPA?RQM+C~C7(ZM)Y*(b)ma(UmoL?u(Vyn%zs{AK zD<`Mw@S#)_c{`##y<rp8eL+V*uFV(~mKeFB#@1>XSAJf_795k<=O?KNiMwUOzMaNv zHcOn|q~gDMLnj;wsA~>)>51<=YZ6~tt&_GinQJ@l(bqLsnd_Hk>*VSzbHnU-ePdRf zNlDL=N#lpj<mfn={D)UfxiBoLXMR;vkDiva{a>h?cI}s&gB~;OnH`c|_k+n;)2DAK zK5lNEzg^#!yvJl_uhW^~PgRz;PG=3irLupXrKk6ItDFJ9<c6A6-hr8t-?=~)>`0Nq zK)@8Oy(}}Ts?F_-zL(<6>1Jk8zs!nFFeOvI)g?o}o7tnE=+YBs%$)B+x~%Uvb;rj~ z>pQo7sqT7Zl`e04U(M~>D0kQFRP!2FN=1H9RaVTC%8|XMDtCph8rW*86Xxpb1FdHM zaE4y+>K1kH*X82d(4rQ8m@YNTe5$r5M(!)iSBoASlEtY>%3pU<{G%gkN%6a~<j0Ao zKJA3AKYr0H4e!+ry9dkzgIo2ou7l>m{#L!bvDd5!E!5)sK&|X<kyW`p>Y;#78WY-8 zQ&qk+4L7JjW|9O>m8s@&BhtJtO|2RFN?LkKP3!54`r%-zd8BVZx7CG>+ICPsTCC05 zwqCt1`IuQ>)1lXg&#Pcbj|2ygs`iw2Y43kibzEwYCqkRlljq80LuWuebtp|bmshKe zFM1@(6Xl5>W1s)hFA_QYo+l;}`RquP$Gzj-8-Mlx$_l@ya<RSl+gs~rB2iZ#|GyYh z#2yBPj0zbRGA?9b$jF>_Xvo-*!6BnVhKFu^d@w+c9U(A8WQ@olkx?SUM8=5>)M-bG z4Ap7JiVPMREiznWyvTr&5hFuJ#*7Ra88tF&WZcNWk&z=qN5+l}-f2gV3?CUk5&$Fu zNC=P^AVEN)fP?{w0}==%5=bbVHWo-QoHiOrIFNWC0YM^yganBR5)>pVNLY}#Ab~+5 zgM<c&4H6uujSdnXBtA%hkO(0mLSlpj35gOCCL~TsppZx*p>o<-A;EImXd&Tp+IS%W zLn4NR42c;MG$d+B*pRp(fkPsPgwAPWhXl`QqlbjgY2$|k5Q!iXLL`Pr5RoV%VMOAH z1QLlP5=tbNNHCo?nn*aEHl9d8oi?IKNRgN#K}Dj9gcXS^5?Ca%NNADRBEfaq=px~D y+V~;?cG?IdAx2`11R04k5@saM_`eIZ*LJ(u_B+QnBd;j0Ajel&m{*ur;Qbp6U$$!i diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Egypt b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Egypt deleted file mode 100644 index d3f819623fc9ef90d327380fad15341ec1a0e202..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1955 zcmdVaZ)nw39LMo<r_Onu>Ge-G^V-ra*L3BUZ7pvu|6G|i=@<8oQbzt(p;QznmXNO4 zL87pXustvmRJ5YhGPA6O3K`U#)lS9~6!a`2m)ShcP1()0&imNI2zt<iz8ChoY!CM2 zyg%vXkFG2ee|tm!`fZbw@1vCa(c1ixY0Wh1BUdh%wy(PM(WCE&U!S>If3v&OeEVgu zZhv*9(eJL&-#s6iV=uiIbd^6GcJ-D7=SH@K=Q=|D%lV8w|M3&z*Y+mcy{SiB_+X#3 zYYNqG8-KDr%a@6Z4U=T=oDHh4cB{NJC8jQyAG4PSlcN8+Y}w!0CNlk%_V>dB>dL7@ zcHpgb>W>3Ga`1)yLTo9tkySsdtfpmh$l|ydT7Oy&o3UMFFNoRUxg9E}ASrXYM~LXK zXKb`Rp+=q^u(^9bSEG)U%4=Th6Qg%NV#hpPq+&0>F2~l^iE&TH<@kzDG2!08UYj>w zP2AROCuXWep4?&cPBp4Yy$O5$A)zLBNEzQcTTI!%!``4)sr*eR<c;;4#niQRa@xXt zQSi`oSy-4-HzmH1)3aX`Me$3v=<H{zSTx$=wkkEFbB~<4t3i|;{=wd|;ca#6wsB_G z<GH%Dsn3)x>DITcIALZNYkhlFiz$zOs4I$&hZPswgUXyw!^-dX26uM75zg7y93)zw z4ex4R9n5{_!LX{~{^0J7Yt6j620j0&I<p{As~6rk*CfXd1dB@Z%_8$yP#w!M)t|)l zV*8_6@=8l^&&fzwQ-4s`tbf4NyqO77tM4$W-RpJg<bg0<urA1o{70W5S^xaG`hSIp z*Sgmyif2XKQ=FVHMqK?~votM|$rL}*{5_KX7w>t{-E#+*?n2(R*S&4zeIsuidFRMm zN8UT~=8<=gynW>TBMl%OcwGxf4_?;<(go56(g)HA(h1TE(hJfI(hbrM(ht%Q(vjD- zg!JTfO(9(&Z6SRjjiK+1FSN$F-hk$i?vVC4`a>Gz=n!cU>Cx+&<ml4t+C=(98bvxq zTIJ{!X%^`gX_up4q+yPZk(QC3y{>7FuDz~pq;I5gq;sToj^2^xk?xW9Ir>L7fMW-c zEkO1F*#wSV@Vae4_QC5m0@(><D>(K7*$iYiknKSB1KAK{N02Q+_5|4!WLLayTabP6 zx{X102H6^9Z;;JFb_dxWWPgwiLUst*B4m${O+t3b>$VBmC$HNmWT%j=LiP&TEU()w auiGwUzr1e4yl%(v|FmUMH)<ti(LVwBTA^S7 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Eire b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Eire deleted file mode 100644 index 1d994902db21814a626e42639d7a96b18ee73756..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3492 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 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT deleted file mode 100644 index c63474664a289aa3c3c0d8b2ce06d484679754c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 114 hcmWHE%1kq2AP5+NDp(+@+<ikBLdep^1=MQ51psD724w&M diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+0 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+0 deleted file mode 100644 index c63474664a289aa3c3c0d8b2ce06d484679754c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 114 hcmWHE%1kq2AP5+NDp(+@+<ikBLdep^1=MQ51psD724w&M diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+1 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+1 deleted file mode 100644 index 4dab6f9005bea50a065c685ec8260b0da2bff921..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 116 ncmWHE%1kq2AP5+NDp>yi|M-D{LD#^LA%rYlTsA<xc7|L4sK^bF diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+10 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+10 deleted file mode 100644 index c749290af2f6b5fe22770c34eb1e8fc87cd85aff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 117 ocmWHE%1kq2AP5+NDp>yiFHT@!&^0t*2q8-smkm&_ouL6209yeIqyPW_ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+11 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+11 deleted file mode 100644 index d969982309e5ca7d32979a7dad814ca307d2cd8d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 117 ocmWHE%1kq2AP5+NDp>yiPYqyT&^0t<2q8-smkm&_ouMHY08u0hYybcN diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+12 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+12 deleted file mode 100644 index cdeec90973be28ee4075eadd22b8b574db2d7a5f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 117 ocmWHE%1kq2AP5+NDp>yi4|iZ-&^0t-2q8-smkm&_ouLsI07pj)Gynhq diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+2 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+2 deleted file mode 100644 index fbd2a941fda996f4abc1f0e09cdf99c271f5a1e2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 116 ncmWHE%1kq2AP5+NDp>yifBb-fLD#^DA%rYlTsA<xc1BzPpCk=f diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+3 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+3 deleted file mode 100644 index ee246ef56f18de61105af0c14d201fd090f74905..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 116 ncmWHE%1kq2AP5+NDp>yizj}dzLD#^TA%rYlTsA<xcE(%)m4FQ( diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+4 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+4 deleted file mode 100644 index 5a25ff2a6afda2cb09b9e147ad20610bc1923444..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 116 ncmWHE%1kq2AP5+NDp>yiKYoCLLD#^9A%rYlTsA<xb|zc^i`)$8 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+5 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+5 deleted file mode 100644 index c0b745f1cc44d03a00f8bdf127c154392e3baf27..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 116 ncmWHE%1kq2AP5+NDp>yi-?@Q-LD#^PA%rYlTsA<xcBWhaf;bGY diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+6 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+6 deleted file mode 100644 index 06e777d57e0267a0635b6b284729fddcfe6221dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 116 ncmWHE%1kq2AP5+NDp>yiU%h~VLD#^HA%rYlTsA<xc4k}vc$5ry diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+7 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+7 deleted file mode 100644 index 4e0b53a082f11f9b9debf5e110b97b1b0473c9a6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 116 ncmWHE%1kq2AP5+NDp>yipF4qpLD#^XA%rYlTsA<xcII3FZtx61 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+8 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+8 deleted file mode 100644 index 714b0c562889a8a774d9aa27810d8400164d00e6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 116 ncmWHE%1kq2AP5+NDp>yi?{8pW&^54N2q8-smkm&_odp*FWlRhR diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+9 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT+9 deleted file mode 100644 index 78b9daa373d2aa2856eafcc92ebc6d899cafde5c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 116 ncmWHE%1kq2AP5+NDp>yiZ!BP7&^54R2q8-smkm&_oh26lTc``r diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-0 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-0 deleted file mode 100644 index c63474664a289aa3c3c0d8b2ce06d484679754c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 114 hcmWHE%1kq2AP5+NDp(+@+<ikBLdep^1=MQ51psD724w&M diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-1 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-1 deleted file mode 100644 index a838bebf5e7bac3e1257eeb0a61c1b83feb1324c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 117 ocmWHE%1kq2AP5+NDp(j8_yiajv<(ayLdep^Wdqb}r)$Us0B2POH2?qr diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-10 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-10 deleted file mode 100644 index 68ff77db0d95c7d054ef33c05e05ba71bcbbbdd8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 118 pcmWHE%1kq2AP5+NDp(j8dKNG+Xd4<Zgpj3+%Lb^|PS?<Y3joWn2!Q|q diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-11 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-11 deleted file mode 100644 index 66af5a42be440f1fb8fec3b915afb49b356f63a5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 118 pcmWHE%1kq2AP5+NDp(j8W^G_#&^9z=2q8-smkm&_ovxuF7Xa3A2*CgV diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-12 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-12 deleted file mode 100644 index 17ba5057727dd73bd5f6234cc5b239b71a861945..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 118 pcmWHE%1kq2AP5+NDp(j8Rvchp&^9z;2q8-smkm&_ovxt~7XaZi2>}2A diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-13 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-13 deleted file mode 100644 index 5f3706ce64cadf081a6c56abd7ba423575a4abb2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 118 pcmWHE%1kq2AP5+NDp(j8wq0Og&^9z?2q8-smkm&_ovxuV7Xa(^2|)k= diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-14 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-14 deleted file mode 100644 index 7e9f9c465ce6211c65d617f60472c9b55b5052c5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 118 pcmWHE%1kq2AP5+NDp(j8jyzys&^9z-2q8-smkm&_ovxt?7XbFR34s6r diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-2 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-2 deleted file mode 100644 index fcef6d9acb247deb539fcc4b30149802572ea642..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 117 ocmWHE%1kq2AP5+NDp(j8WE2<}v<-|HLdep^Wdqb}r)$Io0CCs`bpQYW diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-3 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-3 deleted file mode 100644 index 27973bc857b4e618218ca2790acacb81f7c7bb82..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 117 ocmWHE%1kq2AP5+NDp(j8v<w&+v<-|ILdep^Wdqb}r)$gw0DM~pwEzGB diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-4 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-4 deleted file mode 100644 index 1efd841261a977ae218d408f9cc308c3e312a5e8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 117 ocmWHE%1kq2AP5+NDp(j8EF2gZv<*xcLdep^Wdqb}r)$Cm0EXTM^#A|> diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-5 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-5 deleted file mode 100644 index 1f761844fc44f8228bb748235bfd30be6c389cd1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 117 ocmWHE%1kq2AP5+NDp(j8+yWRFv<*xdLdep^Wdqb}r)$au0Fhw_H2?qr diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-6 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-6 deleted file mode 100644 index 952681ed46cb60e59baf76a2c43b49d5f67255d1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 117 ocmWHE%1kq2AP5+NDp(j8LJ}Alv<=J{Ldep^Wdqb}r)$Oq0Gs3obpQYW diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-7 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-7 deleted file mode 100644 index cefc9126c691060225ff2eee1241b1e5e9825fcd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 117 ocmWHE%1kq2AP5+NDp(j8k_s3Yv<=J|Ldep^Wdqb}r)$my0H$XLwEzGB diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-8 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-8 deleted file mode 100644 index afb093da00685297cb11347c4840acf3a8e2e2bf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 117 ocmWHE%1kq2AP5+NDp(j83K|#~v<)m6Ldep^Wdqb}r)$9l0I=!@^#A|> diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-9 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT-9 deleted file mode 100644 index 9265fb7c2071ec0e66c657ad2ae42d5dd525fe97..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 117 ocmWHE%1kq2AP5+NDp(j8>LxHSXd75Egpj3+%Lb^|PS=tP0K07nH2?qr diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT0 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/GMT0 deleted file mode 100644 index c63474664a289aa3c3c0d8b2ce06d484679754c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 114 hcmWHE%1kq2AP5+NDp(+@+<ikBLdep^1=MQ51psD724w&M diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/Greenwich b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/Greenwich deleted file mode 100644 index c63474664a289aa3c3c0d8b2ce06d484679754c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 114 hcmWHE%1kq2AP5+NDp(+@+<ikBLdep^1=MQ51psD724w&M diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/UCT b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/UCT deleted file mode 100644 index 91558be0c2bf903b2364215ba26d5227d6126508..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 114 hcmWHE%1kq2AP5+NDp(+@LPMMxLdep^1=MQ51psH$25|rY diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/UTC b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/UTC deleted file mode 100644 index 91558be0c2bf903b2364215ba26d5227d6126508..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 114 hcmWHE%1kq2AP5+NDp(+@LPMMxLdep^1=MQ51psH$25|rY diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/Universal b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/Universal deleted file mode 100644 index 91558be0c2bf903b2364215ba26d5227d6126508..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 114 hcmWHE%1kq2AP5+NDp(+@LPMMxLdep^1=MQ51psH$25|rY diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/Zulu b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Etc/Zulu deleted file mode 100644 index 91558be0c2bf903b2364215ba26d5227d6126508..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 114 hcmWHE%1kq2AP5+NDp(+@LPMMxLdep^1=MQ51psH$25|rY diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Amsterdam b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Amsterdam deleted file mode 100644 index c3ff07b436aedf662eae60f50668f5abcdb172b6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2910 zcmeIzdrVe!9LMqJQAndBe#Hb*yhVf;#0OAPlavt61VVixQt*<9T4adCur#`;wffC{ zb1ZXe-VoFwqTy|T_ghoRYLuF;O;>g?ax<saT>ai>Yt8jftv~vwb2z`(+2LP!fBX|> z<;Q#ea<#Kxc)059!+XzH?Xkj%y|SYD^PH7ucRQ;p_BkI^MLDaNg*t0A*{m(O>8vY^ zH0!g@ITe|KW<z3wQyDeUR7D>!8z)^do7${5n_4C~n=dai)zKH7>SHs^mLKz-nyS%e zYtwR5`(|IWZCf|9z3?&T!=>Y#y39V#j=77>PM_oK^6znWw{LOw3@<f%emd>chtDzf zXRerrTN|9l-A!iixie<p`?Y3&W3D++y3`!3I$;i;&&@fMU0is$>~P_cL0N@Ir`))D ztY^{H<0H0bp1eFpPHhU)rgbUu@zMcu`t>OJq$pHA%^0rjDyC`hJDsKd!c>*wMD36l zts(w!?U+77?oIebJ4ODWp&id_SnE?7c5SbQU)rkoeYQqBA9`22G&D*?b&Yggxmvmz zmG1LjlO6>{(lck8+@I!`$f2q7Kun@UMMTSkPPjw|rfBr_0ov>9DDB-Gs(p^M(Y|#z zHKyV_?N@$IV;7##{>2UI%iE%Hxo0K5s7?}+>Se&V_hew#RgxHADv7ttWKfrK9du!; z4F0u5hcu?h!(V3W(8|f0R6j%?S)8oHRz&FV{76k+I9MJX8K^0FU1UVmWlc@FEh7Uz z(ovCL$*7iZWOVBTGP>!wJbr1tjH%fyX(#t-`Vu1<)ob;M*|R0nyrE;CdRxa8OxN)b z6{tULls*}jp;<A#HS2~?vpbEH>@Py}>Fd2@!p@&{Vsnt>tmz=Rbys9k*)^G5-Xv2d zH_Oxo-|I8OcFDBdlbY9kxlB*0(fqbMbVgUz8Q(6`nYW8{*714z>;=C*w{fBt9GxT2 zzm=r3E62+VGrMcy;(;<}>`*Dn50klZ-K046mb}=(BPIPiY01@#QW|_iOHUt`c`ax4 zrP@k)xv5^~FF&XYYF6nh^D4A#Ntw3twrU;lH}5uqciB6r?cMHukMm#M9#25I{WtW4 zRCoj2_qKPw2h@5T`(?j3<c~90JmDTsL=SJoohRSZ(*2%{@qSOTwXe??@3Uu|JyTNs z_OZXPm)BnQ;OEcF>-GPGaQtSkRv}{xkbt<_h#(<BVuAz(i3$=HBrZr`kjNmRL1Kdh z2Z;_69wa`lHb6*(kPx}r7$HGIqJ)GAi4zhiBvMGIkXRwXLZXF)3yBvJFjpHfBxJ5O zW=PPGs3BoP;)Vnci5wC-R~tJdcu4e+@FDR-0*FKq2_X_gB#1~9kuV~0L;}g*0g*&P ziNq2KCK62~oJc&8fFcn^LW;!H)dm%bDiT&Cu1H{!$ReRdVv7V9i7paeB)&+1kq9Fp zMq-Qv+0{lF2{RIBB+y8tkx(PCMuLq*8wocOZzSMI#F3CAF-L;#YNL*X-POh&2|N;c zB=kt^k>DfIN5YT99~l5-1dt&>#sC=vWE7BLaJA!r41}v431ldcu|Ng`84YAOknunU z1Q`)zNRTl>1_c=vWLRA7xF7@LYDWec8f0vc!9hj`86ISOkO4wQ2pJ+|jF3S>MhO`v zWSo$Ja<wCc3>7j~$Y3F(g$x%mUdVtUBZdqaGG@r2A)|&28!~Rlz`5FyLx#@PjvX?1 t$mk)%hm0RGfXE2q|3eu3?}jkQj%B|%)-onNA$DM_FD5<Chy4?Reh2>ZkT3uM diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Andorra b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Andorra deleted file mode 100644 index 5962550392fa78514061582e9371c32b9f1d929b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1742 zcmdVaU1*H~9LMqJm=i7OKjo!thM5`1UTtPJ%yG7`jqN;aUS?kA*f_?HS(~>*){@rx zUo2WIL`&kN3>PC2B3dpi&5|OoNs5KEc)pKIS8kMNJ?C>;=koXcn=7k)DaId<)A|oD zkKcOv9<ks0c%0K`M4k^x)bSHCu305|&jA_l56Fbo8)Ra>DKS|dndC~B*vL4UJZy}_ zIo%r9KSQUyiq-g@Q9AX`5S`ZfO<iZ+>Gam8n$Y+_6Kk(&QpE*LF6)()K&PZ;cgc+6 zBa#-?F6k-tl0FcWjIphn@ob&U`cbEu*WEI^uT---$~C(yQ|C10=-gwGI?orQIgPVq zey&s96=P*V>>KsC2PD^dU-M#~OWw!VvM}tXEbP7~i(a0V#i4VO|L}$uv@}cM`BS>2 zx>}YtAJn3f!&>a$sNR`=HS_ay+2}%D?uystUz4<SWUiDx8KEosr^w1HUvyPZxU4=I zA!VH(WKHn1l(%-v+VUP*xA(oSpL<m{ls(jn=r-Ay9a7)W%epB_b<^9US~(EVs(TH( z`I)I(&aP7b-5S|?C|j#Lyt1t_TDLc)Nlj6f1bm}qNAftS^?a9|5r)(yj?}tOFQk6> zSFL|^TN*z0>aL3&vb(!W_q5&8y`gs9*KkIIEkSh*3LE^d{tUyxPIv|z#&9u)8b;)J z$FSeu^9xL)#A6z6`}Laq%;B&<%)c1mPwUy2eyJ51A`fFk28oOk874ALWT41Mk)a}E zMFxwE78$OsHC|-E$cT|4BV$Gejf@%@HZpEx;K<04p(A5Q29Jy$8NRJGek1@}D*_}0 zBnBi1Bnl)9Bn~7HBoZVPBo-tXBpM_fBpxInTPq?YBwH&cBq$^*BrGH@Brqg0Bs3&8 zBse5GBs?TOBtTm$LL@|6D@G(pBuXSqBu*qyBvK?)BvvF?Bw8d~Bwi$7Bw{3FTPtQH zXe4SRY$R?Za3pdhbR>2pcqDoxd?bG403b&IIRv)WF+dK2t#uTT!+;zI<Uk-t0yz}O hvB3Z4V1!#oWO}mO<279csR?NbNv?wABuq>V{{?7%e9iy> diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Astrakhan b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Astrakhan deleted file mode 100644 index 73a4d013fcb82c2beb6f885f359b9ca20da054e7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1165 zcmd7QO-R#m9LMqBa&xwI=uo+Ivj>~Qht-;!teQ5Pb6683h6gK<9)uw1OYBe(7-XI* zD1wM0f<}j)4|U37gqKJ?b+h0Hoq8aCmk5$tzxQ9e1<|elpY8SM#~5RucX8zCSX}+_ zTE2AJYvp<6-9WDNwCo>R9l2In6PSzD*Ue_?zq=j>KB~&v`DCnN=3J$5>aq^rKdVDG zO1kO%5xws8uwH*GuQ%*Z>5YX}-JEXFn>zeD9Q2tM|AL8lA`<x;kk&V!N86@9N&Azx z(ovq3=#>|;dE$|5DczFT;Y+ghz?6xfxN17PZ<@s3QzjWYW4hw|OxKTtCe?USQt$fA zwuKSd{=CKPm`_XkPFA{~HA&B8Sax1lk{R<#??lk-%6*XRp`WHN{91BZZTdYAB;Wkf z<iET!12ttcFn7=Fem`mUJiK5EGq+{%;&D?fghq$It&;I-wd$%_ws^ZeOLwie*6Zf& z@3-6Qb}JQK!5`ZeQ}(%k$W^CQDx>V#;`{Ftmpxhh4CjTxqH2$I+E>!P5`2MjaTWhz zKl}5mY>4d0m#`(WC$g!d-4)pu*%#Ru*%{dy*&Ep$*&W#)*&k^D=>TZ~=>cg1>B7;r zf%Jhif^>qkg7ktkgLH$mgY<(mgmi?og!F_o<!HM?+H$mgA&nuOA*~_3A<ZG(A?+dk zAq^rOA}u04B26M)B5gX_K9NQpZKp`9NUun<NViD4NWVC4xBuT7_N8soJ<){k7jTRa A6aWAK diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Athens b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Athens deleted file mode 100644 index 9f3a0678d766881389e129c93def7fffd74f14f1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2262 zcmd_qUrd#C9LMqJ2qYerzDWE@Kr|xMj&S(vpCF>+ftd$GI2x%42BH{|5-~`OV=>np zbKe%LoS9aPIcCQ$DCdw`R!$4Zt+8h1V7W5OIhHzW#p?HdYHO{lZo27r_B^lWJmZ3k z^LhK%)z@WO|2R(bhKsY;Ts+SXnA?HCyugX}%i||bA3JyU$C~kv<w)t!rIj+==bIRL zJ#PHd7wWf<MZH=*cHCJy?aIdL>2cSqrw<3M8H0zcnLTR)5nYvmTRRsAWZSP2S-W#$ zR$1RfRM9ilw`H9wjZXeSW1_y&*pOk3z4orgT|B0@e|A`BfAGA<pB$8gqd`f0<&ezj zQb}sxEpr>1WZs4vxx?p|<UFt3>B^OqgjBg}Mx3OEc{KG#w$A@1MHh_5=)#Yt>fQZ6 zsjKI*F6#b5(>g!V^yZW5u6<K8D$h%1Q@>>84@h>|i;|OgP;xU{C3mtzmc)1Kk_($; z=`St1Y|tb3d|9D+y;Yh&uuSjWQ>X<867;^hWG(DmD)$$Ksi!txmZw}&uV+$<!p>@O z@|YA~{Z>|lye}(8&d387-;kBTKJg8`rzQKkWYy8v^ufkPDeZbzS3k5@%NjOo`Qirk z`-*i<>?&RBTA*uhy0s#@NGd*`r4QejFYDg9uIopgvf*%~RQ6wyjUCsds(VDLt43wh zuJ84cg5y$CIi$5o`(<-}Q0v0q)-8#uTfTcqw@x-`{h2o1cEPWY9$Bvqr+3I>&*f`l zZ@E0aHA%Pc$&nqa^Q5URR-VY1BhB8Q<;h4(TGFGnW#VgTjku|;=RTCStLOEpw|Zsg z$bh!*Kc%~Z2leT;9_`rIp^lI#AydLa!$OU>Otn9}2??L}Uw<qsCeQq6xrbWTLboH_ zvJ&Q6Gc7AZtVo_6(SLvc*WdU`{8pj4yxwwde#>KD=F1<)Va}hAmc!xy7d!gRoaTa; zmm_;ZHf3veg=`Di7qT&AXUNu&y&;>kHM`@#VtdH`Y|REa?2yA2kv$@tM0Sa66WJ%S zQDmpcR*}6To3%B&MYfCV7uhhfV`R(7o{>!>yGFK+>>JrQvU6nX$lj67BfGaX+eh|~ zGyv%U(gLIhNE47QAZ<YUfHVT>1kwtm7f3UZZrGZ3ApNj44M94Bv;^r1(iEgCNL!G; zAdNvfgR}<e4bmK>J4kzw{@9uZAsw<cEkb&PGzsYv(k7%&NTZNWA+17sg)|H47Sb-H zU$&-UNXKkV%aEQSO+&hdv<>MS(m14ZNb8W^A<aX&hqMprAJRaigSMuHNDq-FB3(q< zi1ZO@B+^Nwl}Im<W+L50+KKcNX(-ZBThmgcr?#f4NLP`zB7H>~i*y!gE&gA7>oi4P Ylu4UiC0S`XY3}qaS4oE3e#&<K4n&?MSpWb4 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Belfast b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Belfast deleted file mode 100644 index ac02a81440f47a67b9f01d3fbcdb085266d20894..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3648 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 Nbd8QojP~#<@K40&SY`kK diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Belgrade b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Belgrade deleted file mode 100644 index 27de456f16ab549627b284a39e2265cbdb4ad8e9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1920 zcmdVaYfQ~?9LMqhL0H4S7@-o9T#oJ~DdMPHDwhrt$t4vMLdq?-nOU<hYs@g$HH>%= z9>mObA-Sy?W{kPcS{sI0<M;k=Hk(JD*!)lDyjrdG<oo`(Gv?)lS${mO%ujgptT1oB zZ@bQX+-w&4y!OplxqZw_>khf(&W;GVyCFdC9W0aksqxz7<tgp@;DC0!vR%E;Ul5-Y zmEya1zjQBC@msxKdgK>M&*^idSF&6DV-uveGfDz{0;NxzE)wYB(!kFV+V@p}_N(u# z{jass0aahsdE}iAEPt#)n{H|Fvhx~}eNsa+A4ynYm4wGtOT@&T66w27qQZ(Ls;N|> zy~{QF=`0!iy+~s&xMawabd9aZ(zxmv9lCkA4%_3S@j3oFeA8eVk?5hWY;PGE@J16{ zO_JzwLzDcUNm9dW8QuJnjIOJZF)t6x*vjLQTzgSdwv|chiGw<>pg_i#ZPW=<w(7+E zxtca8U){+`I>{?lCp-J;<S!wb-YHSiA9m2GpZiM2*-tvH-czO@XfK&nA7n=9N69L$ zlbKodGHcCyojvTF%*m|PY`@(yH?C51TA$HeU)9{VyELz<Q0LW@==`T{U2t@o=3ieT z3%A5+K}DJ@%Jb93n<Hh(gjgxe@sg#X-DO$AH(B1^lA_>FTGaSLiranB;=5O+q~VdS zJY6BH>Z*11?#sHSa-Xg(IijW8O4ZS#S#$g4(ehuuEURO*xhkujSS@~i`t)$LwyfVj z`E7EF+j1rFPIH?-a5(tlaX8$6al=2%Gb6Tf6mrYRJtH@b+%<CB$bBO>j@&u_nOjHh z9l3er?vdL^?jLCY=>TZ~=>cg1=>lm3=>us5>BQEwg7ktkgLH$mgY<(mgmi?og!F_o zg>;3qh4h6qhID3YT0?rXHO(R2A?+dkAq^rOA}u04B26M)B5fjlB8?)QBCR65+L~sO zZf#AwNWVzKNXJOaNY6;qNY_Z)NZ&}~NaslFNbk0$d8B(=(>~HavH{2rAX|X!0kR3m zE+E^0>;tk9$W9<zf$Rmc8OUzfn(aXL1KAK{N02Q+_5|4!WLJ=FLG}gN7-VOVtwHt% z*&JkdY|Zu{`(tZ12-zWIi;z7+HVN4!WSj7R-zQJATLVKGE@w)3P-IYuGbJ<xgTp<4 E0<)*Xw*UYD diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Berlin b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Berlin deleted file mode 100644 index 7f6d958f8630cba512d8e58ca8edfbd516291522..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2298 zcmd_qe@xVM9LMqR@gs$id#k~jfKV49cEa&9G05x$W^kHv8L5N>f)-(%#-KDTnRAWV zyT))1$saLh&944HTSIO3YqXF=yX-92mMgNFb2F#aSbd(~wrcCI{^_4Sci->hd-vz< zUQhqZ^$j`JKTeGKhKuupxp<zo)!cgHoNIbR=PvIF2eq&Nu)h4Z>fX*>IvmrYBje?A z@>Qpf9`MR1FXhRp=h9>>kRW46daTn`$G4u|zf{iDCF-Z;E)5lqrG^^EHFR*J^;yQC zoOREX&trNd9C1R!7u#gIZ;{-T`-{fAe$a&JU#c_mq&lx0*BKYy(3{Wf)0ywRsEJ39 zNz$R9B=6ZPv$|ALHa{z=O#!)Ob)DQ=;TKm?iQMKckhG+9xjk-%q(^%-{c4`h{w7T` zLJ2zOgGqYF;B|HPU(~tX=QOkPW6j!hR6X^tYj$;5asq>rTRbFr%X=h0xlamm+N5Bj zL*^xR>%8-|Quu4D&OhdryS}K>qJbJM9-6OrZ(pbjdXw~?2A3}EER=goqt#oVD2vj@ zwZuCirO_X0nd>VlyY#IrjyxfYM~CIU3$I9d@HMFzc}IOayJX3s{kpWdS?=%Jrpq3D zUY9qm)yg}Y)L&7i4>*_T3U`LCxaQHS_)@7lJ53+DI$KsA`AJuWVrBKdsZu@oqdeSk zMQXZ7Wlc>;YPWo^k1Tjg>Z(VyK4rJ8Ee>kK<ipyStlIe9E?qYf(DlRZ`sjJTK6Y@G zHhtJ4kMAhf=7CDtur5WP*q$#f%Zen>;FOKovt(1r&+_C{OIowywe|AX(l+Iqww-!k z+AoFmsW%7Y>CqwGy!&0<6717w+WWO*XNN{OA|j*yd__BWzQMjnO`81Qzbq?mhxs>K zNvVz~%bFtm!T<g|$K$xsvi`XL^?ilUZ+S~9xpA3K<~SVY?cm8Ahr|Cb2KAdc8xGW7 zM}}o<#)S+F85uG(WNgUbkkKK-L&k>;5E&sdL|ZdPWRSLIl*llVaUuh?H6yh(Lq*1l z3>FzJGF)3TUVaG%jEoo=GBRdl(6(mO$gq)dBLhc9jtm_cJ2H4=^vLj$@go61B7lSd zi2)J>Bnq}B3`iW1Kp>GoLV?5r2?i1kBpgUQkboc&K|+GW1PKZf6<ZS)BrdilFi2#O z&>*ovf`dc{2@et<BtS@nkPsm;LV|=u2?-MtCtDLJBvQ5}R7k9lU?I^$!iB^O2^bPF zBxFd;kf0$^L&Ao{&DI1CiJYwo9TGbvcu4e+@FDR-0*FKq2_X_gB#1~9kuV~0L;{IK z($<6$i6s(DB$`M#k$55jMIwrX6p1MkR3xfMSdq9Qfkh%~YeI{}*46|Ui7paeB)&+1 hkq9Fp#{X4}V@;^%W|M5UFE=wk)8qDKdoU|E_IIABaYO(B diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Bratislava b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Bratislava deleted file mode 100644 index ce8f433ece44f0b96b18d3b5780730e7f9cad9f5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2301 zcmc)Me@xVM9LMqRfyj?3d!GhJ^0SDLI{6KuL1rf~k~5XdNG1G%sCAKC#-KDTnRAWV zJ7YSBq!nY;jQRs>4XyQav=B|b>@3%oE7O{DGpE&9eV*T_(ei&kU+x~?@3FD5@p=y5 zl68&w*8fhF`GgnedGq4lx!JsRPjW5q4xYNWC)BS!y$AHA_f+?G?9!p=W*t5|PY%EC z(vep@a%4xL9DO!Jz6`|6v6Yc>d~=eXs5&MmUK~gZh6U1s)g|&()_|OJPm`~scS^{y zUP9+u#o3UlQ+x?J)jL;iDEM9D(tp<Yso$zA{II$%y{`#p-qIV7@6%}?zo3Z+4@uJg zeo5Z5S5i7vQa3&$Y5suRv}~2!T<w$e(sH@QT`U<%nR4r-1j&r>Xy)ZYo&H0HW(DK* zwofDV_JOPF?mee7x=v|!#}}Hj;h^R=ys3G0A;}L6NI}`46fW8+Maex<oZl+NqwP|X z*rg?>SIEpiT6ESSkKFl9t(NxHYuVr|y=&_no!y<JcQ>Z%oQ|1tPep`!8WLr0##t@* zj7mks=USQmom5`<QL4f}l&X;-x%bSgGOzy)sUH47z1urw{{ENszNRKw(78nyKJc6_ z@~_sKJN)XauGITo^L4R1OBY|s)!MiUsXaMGAG|zWmb~+;E)B-WvVBge8~8;YYQH4) zT_du*J}4_To!6DK-<4H$!`hI#TUM9#Yh%;_U6ZW3=BHh{b~K>thT8Pu(>{IVwWaF+ ztXUr2R;EpTHS*ZnR9(NdNSYUxN}$mtkLRVxhVtL!38y73IdR%@@q1~Fy`rs0KasWz zA${`gK6z?nP&e-WNH_KO=+kYz+P=MA!yIAZ6UJW=W6u*Kug7Isled|_W-BSpF~PE8 z#ftv#y=6HjkN>3F>$5!NHN5$(O7mcj!@-w*91h>LcVvDnKiWPzb|3erIVn{;uA=|Q zd0TeHGuuM;g=`Gj8L~BGZ^-75-67jU_J?c`*&(t;WRJ)uZOtx`ZQ7cBA{#|^ifk3x ztF75Aza6_pwu|f+*)XzWWXs5&ZOx{UT_f8@_Kj>D**UUxWber4k=-NPNA{020O<hI z0;C5>6KqWvkTxKFKpKH`0%--(3#1uHH;{H9{XiOmbOdP$(i5a9wx%mcTWn2Vkj5aL zL0W_K25An`9i%--e~<<t9YR`!^ayDZ(j}x#wx&-=qijv5kX9kRLYjqi3uzb9FQj2e z$B>pGJwuv?bPZ{nt?3)mI9t;>q;*K|kme!XL)wS*4{0FML8OI950NG!T}0Z5^bu*K zt?4AvN~D)aGm&m0?L_*CG!*G5(o&?SNK=unB5g(biZs^NbQWo?t?4b&T%@~5dy)Pk z4MsYQwAc}D+8Z(cnmG0x8Ff9be`0KsY+`JZZ2sGb73=Q+|9fwO>m2`GlDyy=SsveI bb01@hJtL2HyS)Y3McKJ-Z(c6u6vX@mfqZ3V diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Brussels b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Brussels deleted file mode 100644 index 40d7124e5346af056c75e2f7012a51d94e8154b7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2933 zcmc)LdrXye9LMoPfFK%v(EtV1Q$(mCcSue0g6L52N=n|)MASq=G6v>#G1GMJYjdeX z<EV(26wN>}yyP91lBH-`&P|uvW%iUgt>*0aewcI9+WgPw;W@8!*pKlKygwNur{u&s z9=n>E@9=Qdn1}ZP^UTZ2KB@Ccn}_9>He9q;U#QeI<<<Jh9@Vmv6<St*H`+CBgSB=} zZT`B*me%^2X;yi{d~3tl(EN(91Z!h>skNz-o3+_%wzc_YeEyc}S=OiL2U}Z@_p-K~ z*l1O547Ikq2IcSgz|;C{(Nt?^ewyp^f}O6a!I7@&)RE3z(c;=2Tj;83@rSGC{#DnW z-_E+eIJekY``z!(y>(Zd`)bZO_m?el9avfI{IWFId9Y}O^U&ml&cm6-&LcgdTt~Z% zavtk;(0M%boa^|-rmnjFZJZ~s50F!v1GRo#vV8qfyqwM(tKSp^$hQM~>X~Id<?Mh^ zeYSjp`YsNV79}YvGZNJ=J6v04wANPXedM{gztunV7Y%6jg9f^v(!g8$we{8Q+UAT) zgAOm#;Jy1KWNW3gU0o*amZ-F!HD8>$1@ipp3GzZ(hJ<!ckryKpB`hRdUTWT2!ab8U z{C2!{_%Td7HUwy=qh9)Q)m@D!|4BP9zo?NVUuo2gy&9dpO=HGfkl2DMiA$=L_@N(5 zLfbWx7+WNX_vT8M;N{xo(s=3mPoZ|(mn^S-pQ+s|vNWl-o4&T7m-Z+P(VjV>+N-3i z^zQ4a$=SiuC+xbWB;S+1o+q?l=w<15^O~f(AC%PkI_ZCPy$q<_B55ZNX!_D6GH~l! z9h8?RgO|LoLq>e4LvttUuvc<5Bdwpl9ym~kM|9NTccL}ZzprGTZ>ewG?jR#~{i&lG zd}OrCPsUXJDr4u~lC0(RGA^q@#?Ss)-|VqlCX6|$+3i=!#H32i@vhcMZB-}TSfP{e z73h?@VtwmUhEClyN^_4*muU-=G_PWqygj+S<}XN)=|j3pK~A8&6Vpy+r2HlC`Z=U9 z%3lkuD^lcpM~hA$k>Z;dbmoo<d9S`!XRSJ<vn$u=oZ@nwyL7I)J>&U|yNA1ncN4EC zzB%7`H}!d1x5MEPWd1d|JRA;Rad<l%Ax^jEkG^;FdvK=l<ij&*=^2g@DH)Dr`x(Xu z^I|SHH}hpK`v>jMZW;ew4D;I@JY0Ls!~3B7<{G~1@->`xqt1a81gVIvDG5>&q$o&L zkh0jCx*&x?Dua{;sSQ#bq&i4>koq76LMmiyN`%x1DH2j8q)bSikU}AqLP~|y3Mm#+ zEu>sXy^w+-6|*%ZLu!T;4XGMZHl%Jy;gHH9r9*0m6c4E$Qa+@9NCA-w+L{s~HAISt zR1qm7Qb(kaNF|X{BDF+{$sYmLM9PWO6DcTCQKY0uO_8D^RYl5*)YaA$7O5;!TBNo} zagpjG<wfd?6d0*6QevdWNRg2$BV|VFj1=0|R2nHYQfs8xNVSo2BlSiKj#L~eIZ|_^ z=t$L(vLkgz3U6yFkCfil)E+55QhlWSNd1uoKvn=*0%Q%4ML<>oSq5YskcB{20$B=M zvlhr=*qYTqmIGN2WI>P>L6!tr6J$}4RY8^oSr=qskd;A}#@4J2vN*P8b&%yj)(2T2 zWQC9=Le>abBxIG4WkS{oStw+skflP_3Rx^$vs%b<A?t-K7_wr>k|Aq`EE=+E$g&~p zhAbSia>&vlYlkeJtyw)}`E1SlAq$ACAhLwW8X}8`tRglpqk9u~4^I!zre5Apd~?3> z_G$LC?g!Io2GUHUxy&^B3gcwPPab{m=KtVK<H?6-7|7oLH<FL7B%A4DwzP9hvf0sy S^ti}`$modlm}rcO^Z6GUA-G)t diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Bucharest b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Bucharest deleted file mode 100644 index 4303b903e5e007484c0d8e1eea43a35e9b53f38b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2184 zcmdtie@xVM9LMqR1y}6)u{RQd0iu$LcESOoXy7jbvN%OKja1}oA!41BsO(6TTRO*z z+&g2HrJF9ttQql#Wrjv78Ex*QAFj2={4QIy=B$mJYmU|D`R$L^Tz|CnSMS^1<HoOz z?OxB&iuDco)(w|nzQU91Fi+kmM$OBy-p><`&l$0g|Gdxs;NlB*-}&wKiNQCWlkdOg ze0cbIr~lP9=cA4d&Z)?1=XB#@=S<B!XW+p+=i{P@&e`lF=abZUC-Lpi>@n3&RZ{TQ zp*stP?BuNB=v_&%Xi8jvG-aeWntJJAbnF*<qIaL!5luVsj+K7ofR(ZDMQdE=vsPx? zCTo1S-kPv#nKiMp+{!ARY2D+`wkD;IweG#mXHE7NMkinO+1cM+x2Jr0*`7KuY~Ob@ zX8RBI+ta#w?VO!2RpoBpV+ZQDROQw7IQh+6hYCviWct#Vr7&Z^%*c<(jL~)}O6$_1 z;WaYrdW+6JSt|E`Q=`S*bz0IlTj%VWuXA5d*Le+DI)CRZSy1lP()u)cVA2m-Ryr!> z-cPk6>!MU#`Cb;rosxyIL3!xX8}e|^TT*$hUxT|lWzms?y11!HsycV*l1HA?rQx+& zJu|GK$_ibUvPhTvr|9x)0j)_cmzuA}=%ZJ&WyO2H>dFf~S#=;$YL8x))$Jov*A)}H z?t-k@_LDv~_n16hdrs>!_sZIm9&Jc?SJ!2zuKV#7Z5(aZ^@FYY#BfNTJiJoFXE(}* zjuLI^u9l}7Gxh0Rg|cx;u{1ZN$fmq;vbpRx*^+2UOK!5Z{PL|t?zpCrp#f>V^0hwG z+bvsTecHD7v~KI!uiIM>Y5VSW^>}ZJ`}-r_8-K&s{`v{N8}GgOmjC);S*a28QROw> zvZe++=F^)#-n#vt-d6@g)&lb^E34)uWPa7-`SZ!2@pwZ2VkEzt3!irqkg*_xaW$hs zhJ%a;84xleWJt)EkU=4%LWYHm3mF(PGGu7T*!T|^95Om&c*yvW0U{$rhUjX>hzt@L zB{EE8oE!t?7%9h4ImXH{SdP(h43}fP90TSUF~^WO#_Vbajf@%@HZpEx;K<04p(A5Q z29Jy$89p+8BmhVRkPsj-a5X_dqTp)6fW!d_1QH1(6i6(PU?9;z!hysC2?!DqBqT^o zkf0z@aW!E<;^JxogG2@i4H6q9I7oDm@F4L)0)#{e2@w(_BuGe<TuqpeIJufYA(28t zg~SR877{HaTu8i-fFTh>LWaZ)2^tbLBy33BTutDR$RVLaVuu6|i5?O@Bz{N$kq9Co zL}G{p5s4xaMkJ1|CXh%ZT}>#FSR%nhqKSkPi6;_J{9i}ZXUaM)pT_!w1v!N|f!qRr LFfZV~o9_DqL0CBH diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Budapest b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Budapest deleted file mode 100644 index b76c873d9256e1d73c2ea672140b813f15657bc7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2368 zcmdtie@xVM9LMqFS0*#}Cc{$!v51gD;P{moWOe~FI1{;yR00!GljtO3M`@Tc*Bo<i zi@^v;MIvi<s|{)mUHPLXi_kJMY!(w0Y|T;RtTn99^K1XL{^+0n==<G$AK&}l?w{Me zp6(SJ%93n<J0_VYyf~W7i~C!)noG+Rdr8Z{*|F9^pSE>$>+2t??x}0iy{{dYeWf+p z?wKX~U5(N^-d)l+k}IFTW!L_8r<{BxMNVytmM@yULtpOf^_*VXsbA%WZXHNJCSS*P z$(fmN$TyQ4WzheK4qo=k`St^2!}&j#T-f%eTy$L5OI6opBxFcO-9s|^(@~w~iW$2t z`8!W&)Jf0uX&-y+0q=S2<L#aq!>@W~p04xEI<{NG4jq>8gFcC9-6ON>RU$XPBy-9u z<@Qx;<c>VIL}g^jopEUr9UdchO_?DvK~9ainxb<rMr-WAbiMnNNqSG$uNv2JS?4vJ z)%d#4G@<H{CYHXVj-o+Hs_c^F%pOTu)+nhFZIYJcm9&XknIG1m^Utl8^xvy>!C|M| z_idqObQWu7&jP)F$0A+W60Q%FMd_ltba^m4NS&o&@=)}MW;rJ$JE&K4qP~}$E0<(( zz!6#8e?lG}-Y>bnw<WLdBX#Ynmn8@H=_3^tvb27?=0CPmmzA&8f_ux=otLAJ+L!3^ zxL93&El~?Yv!(FNt@`-Yxw7K@Uv%X_u&mk}B1K(4$`iHYQryrlCB*}>ddm;`<iZbR zO;MkgMmEdZOrMtB+^y>(RM(9*>H3LE-Eg8tpE~E(jR#h0`KO!Y>6bILqO(ArSs$sM z9jUS@KSL_Z?DDK*wp3;PCeMY~q&gu~tH;iZcj`6uo;ofyR|fU@cRS^U{vO@jd{npi z+VsVm4z1l)tNwoe0fBzzYR<p_bDH<&$&I_ep5OS?Kj^0a?zGuLE|`D4Eqsn&pv^W_ zY?J@#KF{U0IkO75xcP>kIndm=|Ha1sFvmvw?p9=LmS%6r=8)YX+e7w;Y!KNYvPEQ% z$R?3pBHKjviEI?vDY8{$ugGSR-6GpX_KR#7*)g(ZOS5NW)5xxoZ6o_eHjeBZ*}A3K zJHI5GM|O{FAK5?B087&Wqy<P1kR~8qK-z%x0cix%38WQBFOX&+-9Xxb^aE)K(h*D3 z5~L?cQ;@D8Z9)2iGzRGm(i)^UNOO?xAnif=gER=~kfmu6(j!aLB&177n~**sjY2ww zv<m4J(k!G~NV|}JAq_)1hO`XnnWbqO(ltxdHl%Mz<B-lFtwVZ;G!N+>(mterNCS}$ zA}vIEXla^=bkWkZ5$Pk+NTicUE0JCz%|yD1v=iwk(om$MNK28PB27iQYH8Yv^c86= z(pjXnNN<tmBHcyWi}V+1Fw$Y9#Ym5lCL>+8G;K!uY-t*ebQ)<j(rcvINVk!8<Nv+i Z!6xbR9K=1&l^mZMpBU$IBw|8x@Sl-7wT}P* diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Busingen b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Busingen deleted file mode 100644 index ad6cf59281a1046d9dcd045fda521585e3e33e06..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1909 zcmciCX-L$09LMqhq+=x|UkjT`&1!PZnmp6((5_jPcE=8#Ej!E(waeVJGVQV`Btqi5 zAVpMc%Z5ah^}y<Z9c&jJCJUQH7eUcw5kZ9=Nd4abC5WxZ{r}9ohV0?@{qfIST%2Tm z^*GJH@Zni)KK$;!(R^KTEwQfLFSD+;`>f`(xmK9_nfB^=M_mEe)b;AL_I_|g`~164 z`=0w<!%v=)h(iq$x#th*SE~}WZj<ycDVG7W7sx=LU)*UKGRTuE(GfB7L$}@%<Me9G zo8db6VYJ4!_R=92I_uEJx9ZvdREO2w(zq>GHGbtuO(;C9iTO7rsk~8=)0<>?&JIb5 z+$*U`m6F;~EhEC~bj00xGV()(jymO)(YNz7t-e6hn?~uFn(;bzcZ7~BcI)^pBV|IS zQ@w@Z@>BF<&G2?ert`99x$jBVi$^js;BT4Oa!G!E@R$73a8P{BXEb|ztxP)fr%o;{ zl_|BGb?WqOnp0Awxj&Yu-<PGox+du~PpnRBPtd%uOv$^^Lub4hEHjV4)>*B=GJ9XB z<TpN-In}SEpsq#c7PQK|^=&$T><L+r->ijEyQC<+L5sT_(}j_$3!m)NMIGh3_)?WF zx$D=Z2WDx>#WGp8HC;>VbLF>1QM$Y)Marh8NqMnLRwVY5l^O43Rj4Hu@nKr=^1f7t zv}@%*=cVe!O<i-eUe>lW>AGEKb$!EL-B7h(tG8EcCx>|h0>AfbSzXLgSyn`UN1$be zh}HGW-@a_W<;}?D%g_IEIP5R~w{JGc{E-h&rTOqX^rLwOy=>cvW!HmhkQ=r&cZ}RJ za?d>6G;-I-ZQGjrMs6IrbL7^Mdq-{_xqIaHk^4s)KsrELKzcx$K)OKMK>DyXjUb&M ztsuQ1%^=+%?I8Ui4Iv#NEg?N2O(9(&Z6STxn#PdMY)xxOZ%A`UcSw6ke@KH!he(S^ zk4Te9mq?pPpGc!fr?#e5q*q(hEYdB~F48a3Fw!y7GSV~BG}1NFHqtlJIMTVTX&vd^ z)-;cFkF<~Uk8A+41IQL2dw^^LvJ1#IAp3x91hNyzRv>#}Yc>Pf4P-lz{XjMZ*%4$* zkUc>*1=$s3TabN0HU`-lWNVPUu{E26?2fJ39%O%z4MKJZ*&<|*kWE5%$q~@Wyn)W| z{eB*%p!b#;CNocFr$WT){^f7xX~O>|>c5RL-@#_Hh9$CIp6ukfl(+;>c47j?CkKB5 Dj=i{v diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Chisinau b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Chisinau deleted file mode 100644 index 5ee23fe0e59f044598675db44d53c20590b88934..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2390 zcmeIye@xVM9LMqZ#jg{Q&Nbq<8YYmQ{1n9!J;lQm&_fW(1g|7SK?@bb1pUl8M)PN4 z&59LkO=VMti%|+1l_@KNtFcu>>$^4kJ^ik7w#?P%`6brc`lJ5nzh1YyCwzBv&iQ^6 zty*7^CVxA}A5Zt|@^ie>A1_tC9P)a{NA@#wfApTY-r_y``F?Nr;7)H(Uz>66jTemb zC-xd|9<4Wen>HG6)s-1<S1vQ&DRCJW9!xdf&5ScHCf;RSitso3dYZlOJ=x&t|0>t< zL0kBtfmgB}gNJ80d`k~`!xE1B?vA+Z3bzk?!hgB5H{#n+U*vGME2_WQ7v0lp#+-b{ zjBVL%PT04_oLFCOPO4sE-m^N#jLVy4PM(u!-s_Asr^E!C@ndh9@!5GsLO_N}xDl@s zuZFAphQ9Ysy)fvR);ZvHzIxg-{YZy5X-~5!dFx?sN_nj(wY1$x+q}b<o^?uQEN_yG z*n=`NZG+6bT_c&%jVkj>q0GKjsqR0QArA~MQFD$JsH|?Mn%kJJ=DirIToqwz{+?;F zz<pC?myeT$Q$AJh?CX*f(5)6t{!kWO`$QJ|y(WtX&dQQ6o|WA87Rl>Bt@01-l%*$| z)v`@q@$9Qr1uN^-^6HhUa8{Wr%A2iLgu7I+Gg=kjj8i3HnNsqxzk29Kl&tFdQawEM ztE_JIlhV%5q-@t!S#zXUylXDWBMq0;qx0HiZRvScK5?%+mer~%?8nu**xhQ~*H5d; z+vRF~UzOT$B}Y}A$XC@D*UHAGWVPv-TOO|*ubya3keY%d*<3M3wxl{_tNS~tb^IXP zl7rMXb4cn!zfpC*F4=zVef3nwQQ0wYO4UE#sT$f3s-4@PQ@ak-DBB$Ye*S-b1&#@_ z2ieC4kGw+0{rL*i-wX`+?_MI&cKv@?qJ9#8k%&6czfDcCg^0vVlJTRTBTqsd62=o- z<mhLn%Qk`UOWf$^=#$YuAuqp3vh{m`e!Ja;eCP+(TmO<@xKO`y`3u-=BX8@6qJMFM zzv&fs_5DmaManr+PSUDAOUh|d&XaPYlryEAD&<@$Crde7%IQ+hmvX|CGp3v}<(w%e zO*w1IX;aRda^jRTr<^+f7@Rxh<SA!wRi8fP{3!%b7@$x<;ebK{g#`)?6dou<P?(@l zLE(Zz289i)nhpvdRy83MMktg}IH8b2VTD2qg%=7j6lN&YP`IIx!(fL&4}%}8nji*4 zRy9QojwmECSfbEG;fX>Ng((VE6s{O#QP^V8Md6D<7=<ybnlc7wRyAo1))=%gc%u-< zV2(l^gF6a&6!s|eQTU?}NMX>brjWv+RZSv=MFx!&9vMV3m}F4N;F3WmgG~yZ3_dA@ zG8m;$O5xP1CY8b}g;ol$6k;jNGN`3+%OID+E`weMzYKyI3^OQZaBNkR%wXB7rkTMr qg=hxT6sjp)Q^=<Ov;B|Q4%XkAo(A*I{Pd)Zq!ed<Y6?wG5B?oV8;IQi diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Copenhagen b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Copenhagen deleted file mode 100644 index 776be6e4a6d5a054152135a1ad149576052f49a1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2137 zcmciCeN0t#9LMo<xm+<)_9caD@nj*PcI6rJ0W`Y;Q@NIMReV4+5ygn)rVL7@Oj&Ep zeRVA7&}rpZHKG1M{R4%m<!~WVcE_xoEm!t5b2DcTWA%F<$8go({?5*MogK!;AAH{a z<&_l~)_+cz`NGZFWp3U_ziJ*W@lC5+f?fSR-ldy*ug{kY@4L0{9j{#6n<f1_lH{{M zw0u56^iusU`68xGgR9ykc=a0@C_JwN-DhNsZ;p)3{8OV6f7a+RU#r`BLEX2yblkNM z_2Em0^^voCH0I<fi9OmbaR&}be3MGT*4JcwRX`qHxmF%4@=IcFzD)4sNK$OFJU(ii zB)hztd^<}gewU<^g3&tplQ4av<9GEO`BA4df2k=uKh@ODCpE3SP18#+OGcnWGV?km zYtdVh9d}T2GU_B}utBEAH0#tWYh>DAwL1NjS7v-wqPeYQn%6m9XEx5(SuL^pR7IlB z-Z@R4E^w*0JVxduUDtf?pcJ^yYhmJ5DZKH$%ypiYxqUq{@7lXEzx@L#>g`tF?j~7q z^lg2nx>}xXdR-STeNz`zt<&NstJGgqsEgeTbctt@F1eGYB~b-ZGVqWtyFF2sAOB5P z1jA+J;Yca%_(fJV+>)~9K3QEBlr`Ia(&uKKkhP_~TAr|9*5$Qp#mHm2K2CN05Bqe( zU_dK->UHB4zdrxo3avU<BQLy>r`4^+^5TXB-PD*ZH4AekP~n!B(&J@w{vWa>(vsTL zD6PHut<*)_(YpSRrT)fcefgtSd8MyYx9&fq+u9H6_WC2*u)9G+93c*8=slNf#Qnc4 z>%m_0ziGvecZ6D2gjf#@J@0-Q{$AwsTi*O)9)5nqVGf!X|Nk#xr1>E?r_tQJNB(V2 zW#h#TtQqxd7P1Umvkqh-$V!l<AZtMugRBNw4zeC(LCA`bCE1!aA&as#tKyGiS;)GO zg&`|LmS$_#hAa+Q9kM)ReaHfl6(UPS)`%<;StYVeWSz)Dk(DA#Mb>I-7K^MFSuV0( zWWmUaktHK*Miz~%8d)~7Ze-!e%8{ibYqvFvM^<lZmXE9-DF9Ldqy$I}kRl*eK+1sB z0VxDh38WNAEs$a$)vz_?K<Z&@3W8JwDG5>&q$o&Lkg_0kK?;LZ1}P0v8>Bc$b!<&} zkowq~0wEPbN`%x1DH2j8q)bSikU}AqLP~|y3Mm#+Eu>sXy=+avkcuHCLu!T;4XGMZ zHl%Jy;gHH9r9*0m6c4E$Qa+@9wx)nc1#L|Uks2aJM5>6C5ve0mNTiYuXNWT-)OF7_ zBJBQOLzy(OG?_F}G%bq|YxL0b?w8^3b}auD%;931w{TO@De3go<I7CRPD%6l($g?C GGyET=z$0G( diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Dublin b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Dublin deleted file mode 100644 index 1d994902db21814a626e42639d7a96b18ee73756..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3492 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 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Gibraltar b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Gibraltar deleted file mode 100644 index 117aadb8364cd7901388098503f4538c7b445aeb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3052 zcmeIzSx}W_9LMo<Ledz=9-ROa#K#N~Lj+uMBTGc0fLu<ByQZQhk&+R(WKCvG<2e5s ziX0#xlh851C0udI4L3v)A;nD7+#R#bQB$<%`!-!w7v6N$`_6kl&zza}?ws$>Gi-87 zl<RL-L;DR6SGj#Sw|K{X<hCs~xwYOp?_h+<FW6ze$jdj2a#|Sk{zknx<F5H~LY`hS zbB`%VT5rDUeMc7tkI_p*%Js7LVS3r+TV}bd+AOc})n8w{ri*r`>f*hJb;;5sy~1Rf zl^;atRi7L(tEVQIZ_-zr(*EIQP5dyuHbR+oQ5k0aqraLB&63TApO2W07hSsS=r4NH z@gaKi`f9yp)jhNI^ELY0+yK2TGe>WqQLlF-XX%{-3e2u<!*zL&ZF+Zdt=V1oh}q}Y zR`%r#mHkygQt?(#Ik3tlm1C0CK{+jl(nd*Dx}U1L6QvGMzNf3lg_<Mrr*utFYg5yw zUTRLBQng7%y7r!zIU2q|AHDslu4^(?*ImA%kDv87-|w%~CwAU8Ka^fFCrkYFsq6~# zWBT*v^pxrP%)s{MCy$u3QH{;H=wf|7AXHy?%wzn$4v7EtEz<nV3VFQRNQ)gGOTebh zDzK<Twai<jg64~AHS1laQ`1%J5#!Vo2_Ds^SFCz6tg8wR3{h<xH&-FvF%oj4v$Q)K zETJ`i(tcM%d8+i5gcV$r4%u}QK6k%#oW4mS#urQE$YUxhy;OCIE>oQcex|y#%vW8b zGF8|5IjUPgwsbo&R&~FVAw4$7sGi4@rB~r-i7x9Q&&+#Hdglhpvng%lxw+j{pMKsF zGd@7|4L&ciG4-mS_g;x>b5g}!J*VQmwyF5aJ?e!sOVo=c%T+?fR!LkiUnLbSmY34f zRR8(!$$%jr$-vYJGU(}4@g&5_%l=6+I4o2K-;9uC-+n6jyJj-<MmsfZ?Qb%?#z&1X zP1VTKD{9o7>uPj%r5ZE3Mva|)NnYu_PK_H`A>&&uR1>00B&E?Bnb=Zf;)NWURG%)B z_hiYdCp<D`*>FiMpQc{>Fj~?I2dUR5wUVjxx~ORbda3jjfAvOWkeVKQTfN!Tr7}AD zO2)O*DznK=$vm`EWnDccGgcO=nU!TSYvFd8U6L<vXBEht1#{#f_k-SE?!Ru{^!lgw z8+bqb-`@A{|9;p0!Cg(1y8*fyxm<zT-I#A&O`WsvpXY=`kE_ohk1G!Q+Cxk%k3G2D zZnu4$*WGT<1GMG7y@pizG(Z~TXgh<n2I&pb9Hcu)dyxJh4MIAEv<T@D(j=ryNShpO zpO8j5+D;*@LVATX3+WcpE~H;b!;p?4Ekk;SG!5w*(l(@TNaGxB=aAMRy+fLZbPs7C z(m$kuNC%M?B0WT!h;$KYBhp7l+eoC7j<%IZFOg;<-9*}n^b=_)(osj-QlzIyQ<1JB zZFRJLb+nB|I_qd#i}cpfHW%rxqirwJU!=iEhmjT|Jw}?0bQx(g(r2X6NT-ojBfUnN z%}<<eJKA<5{YDy&bR20p(sQKgNY|0JBYj62k8~bsJ<@xm`AGMX_B-1CBO8G10I~(h z9w3{5>;ke4$UYz&f$Rjb706y7n}O^GvK@|gKadS^v^#=q39={1rXah5Yzwk4$i^T$ zgKQ15H^}B7yMt^GvOmZMIocgUw#d=$5wc0hE+N~5>=Uw4$W9?!h3plwS;%f7+lA~G zvSE&P$B->^w0nkZ8nSE1wjuk5Y#g$4$kriyhio3Qd&u@7`-f~GvV+JLI@&!%HWArH zWE+uvL^cxHNn|ULy+k$>*-d0Sk^MwA6xmT^OC9Z=BAe=HcNN)IWM7euMRpe1T4ZnW g|IPjP&GoTc+#!-N4omD5-X%ODEHN?yJ9hH<16u-G00000 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Guernsey b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Guernsey deleted file mode 100644 index ac02a81440f47a67b9f01d3fbcdb085266d20894..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3648 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 Nbd8QojP~#<@K40&SY`kK diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Helsinki b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Helsinki deleted file mode 100644 index b4f8f9cbb57450549933f83ac90dd56a2ca75344..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1900 zcmdVaYiP}J9LMqh%+NyL(Hv|u%xpNev#Z<YHfM9$FguvbY}n>D!>~5Db3~GszG{&W zvX;c`!B9r-BI~5Igq9-LB!!R`zxUr0<&h`KIi3IOv`%~UeSbXjSCl4Nf4n-GzwqHz zX+C@p@tH^6`ZZzq{JBLfS6>u`Mz#5R_4NB3fmeKvkBz?G&(CU~2gkJUjeQz+>9T~M zZjgw>N2OnlO5~R9(!Z=i1}t1E1G7C6mFAW~&QysGkCDM$drM4EhQ@qO*4P)(I;6Fi z4!zY`hc$gwXWbheUi(<%cHYzY4VTnad`1%r9!X+FlO&}#OY*G!k`i%5QWL8rwcRTt z!)kS8+hQ5@y;4VC&X6%r@-?l#P}7@7>)2frbljnE9bX!y6LyZ0iJ3u~Q5+_dqF<>y zqg^tC?rK)lQ^|V&Ql<o6lPUf?GWGchnbvShvRkfb&fXfCe)_o1C@+_pH9ItS?jD_0 zR-$<$%G8scrL!H=b&hk0&iUff{LoCvf7nCkeU6p+=RfI!)?it9EJO;L-pL~GM=7lJ zOHpB~EZ+K7myEk0OAA`GIP##Bq&H}3mvg!-LUq~e1G>DuLRZ|W)|G7@U3GGSmfc<_ zt9Pesd3~O&SstltccsX>+%%~ub;$aJezL*+O*V#DQW+nrl^>o-RrfDib^oSRzkj5g z8tY}Vzgf2&ysldtj_9`PI`!`LYCvEI``t0<U%oBNQDP2?XGhB#>I&#$S>gSyZohxe z&hc22&ByJ|<Kf}=RzSe7r{^zD_lJ4qT^xJ}Ibr0CkyGYBa?Z#}BWG=EP8&II<iwFP zM@}6%cjV-evqw%JIe#PpBm*P`BnKo3Bnu=BTayQp2$Bhs3X%(w43Z6!4w4U&5Rws+ z5|R^=6p|H^maWMPNzB${hNOn%h9rk%hopz(ha`w(h@^<*h$M+*iKL0-i6m-kGDT9g zHMt_mBH1G8BKaZ-BN-zpBRL~UBUvM9BY7i<+nUUg)NM`fNb*SbNcu?r$OIrWfJ^~0 z2goEKvw%zkG7rc^ATxnXg{_$jWHON1K&Atk4`f1+89}B5nG<AEkXb>d1(_FQVvw0Z zrpDIH4Kg{lW_FP2LFNaUAY_J+DMIE5|KmvtHXAiOk+pK>B*mq~x#E+YISDTNTXOJE D35>6g diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Isle_of_Man b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Isle_of_Man deleted file mode 100644 index ac02a81440f47a67b9f01d3fbcdb085266d20894..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3648 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 Nbd8QojP~#<@K40&SY`kK diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Istanbul b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Istanbul deleted file mode 100644 index 508446bb6aee2841ab88e82607a6ad6e748e7db7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1947 zcmd_qZ%9>V0LSs?`nP+{bz_9Pc+<9~_m<WCx4Je{%S>!HcdDyFf5t&8ib5V%gGPe4 zDT7wf8GBJA#8%G0%Gwr#Q7fV`boS>^w&_xK##j)+d<I!_QucgLuUc=`>z&KFpX24? zi_7!<#nx`!TqvHq()1_XTs!s6b0DtYtbL=0+9zk2?YA!2M>jP($98{cbkxSpFUrr_ zojD=rc&Nqh3Wv?E-yYc~#`ZcVFBcd+d&-?&&&x*d@=^20YjLBmuiLz_&1>8|T4MHB zCK$J(>CR8HcH2MajW`3|4fbHdL38kKx&6z%ubtaB)*D0pwmJM&neo^CZ_WD+BgW{K z6!SrL#7=4YRHl|3mZ{_K3vZxVdhI^p8+%u#efc;(d9XsJchtpS>O3W<v@M8F`FpAn z*n36>hR!&dcWf2>VMI-DFOXULcc|><jcUgBI`!)MW$Lx)0yVQVtX`iJP&q-L%1s+r zq2!PZjlLqoe|Y7r{(t1`@9)XHvqN%D$5lCZU#ptec3Qr%^D~*h@e^6F;k+t*@1QDL zbVL=e`ar!oJ+9^#u2b_LHK<7DE*TkKs!GP!%7x$Ms<&>J%F@nCx#(P$Ec+-&mbVL8 zu{l*PZVRd<Rd;1&<72fnr%zT@I%-*RuT?$sSAX@Ncl<Spm;5!?di=|OKjweCyUQQF za?x6GVA!fX`MLE@Q<LA=-)gN~^RcyR`zC93<bppIt+whiYOVURBUb&xd~411c}B~` z#Dpg?;YD6a$w`SRssH^o$@|<ZDM^UTus%j2bBoZ=v-3TZgb2<M={$?6LPRP&)BgSW zv)_rXh>03~S5>X%Ehh5vi}YR0f7O>qUr(RhKSb;W4!HhJChEWG89)v?a@bw<fkzHK za`2JEj|6~3fP{d=;HrZ_qCmnx;y?m%)sY~fAh969AkiS<An_mpArT=VAu+k?ppdAL zu#mWrz>vt0(2&@W;P_pM4hhdy$Hzs0t~x?4LPTOjf<&T3!bIY9)qx_By6RAoSdn0n zXpwM{c#(jSh>?(yn3157sFARdxLtMNNaRT9NbE@PNc2efNc_kEAR~Yb0Wt>2ARwcF z3<EL_u6iJlk#N;Rfs6$*7|3WK!-0$kG9bu^AVY$T2{I_is360Fj0-X_$jG?rp+UyR zRSym_I>_)K<AV$kGD64@A!CFL5;982Fd^fF3=}d_u6n4DvBDO82LBg><tx>LRyMcD F_XJx;ZRG#} diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Jersey b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Jersey deleted file mode 100644 index ac02a81440f47a67b9f01d3fbcdb085266d20894..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3648 zcmeI!X;9R49LMq95EV52K?)`wKO;4aaG^A_$UF%J^4N6K45`FSG9)9&jG9gz$NAb& zWNQ9AQu4qH%A`Zn@C-G>3?r{R@I=dm5bXE<&on*gkv-^9>@2UH9d?*uhVT319XUQV z#`TY{M)n<^d|k3nUI)Emzs>2i(#+ZKujlUen0bpgn-AyCGxPIW8}r5ny&&_dSvYpC zUNmK!S)8=qeAKH}FX=c&FYR2S^Seaq{4>>NnQNa}R@PE4udLE5wx;Qo+rQHVOOx~} zlWkVN<<V>2*<;qGCzy2^Yfa(cC{q+aQh(x6=F^x=v%dKy^I5RZe0Je`v!T+Ziw|7X zpC25dzgWLdf4QdKeD!{j-Z&>rZ_3KkU%yzVH~X^nmLZGHH$6t_lAfFNR^NWJwLHM= z2<ap{@*a_$d)vvb7w(mB*SMr~j8E;Bqq1k>W3o3RMD4AOQQwWP*ZZD`FyF@?)@AKF zn6f@~Qg-OD+Ml#S@2~eW2cl-`12ymJ@@DC}{LEQ>@OY^CX=kaf*ivJDE<9}x6@=)+ zxx37fj0erp36u4)p<T=`UNOgGnwk@_EA`2+2z{!B*PN<tqATkr>C@%s^qGob`s{|? z`rNud%=r)2=nJooGgb4a>WeAy=2A|w{&irg{w=w;zTDwP^LwvweZ_UbRJZrn)ra?* zn);LakB#e0?I}NVb;@#6x3xIkFTF%Ji12Cu!TGvjKu_JsGhH{TY@-8Inhw}juLG-+ zbd$BMP18LdedDaFrrGLX-F(u|M$L{gK|?m0;A~}Xie6}1_%4~2;b$bIM~Q^`eJib6 z<x8t$tK{bD>C$@hED1ZZRJB=ApxSPlrrOOA)qcSQrPDH0hgTETEeT!~p3+s_8rfZS z95_fiHEpFjcez74U%pEs0-H-jS%`G0yePL9R!ijeeR4-`xkP<jBwZ(eE}m(55<U7y z6_Zh@?u;!~cMW|{b!$6Mb&ttX-Rp8xkFZ?nQIVqVsm+w0U-VV?9`wn5OOhqFxToCz zW^d^=r;R+28ZNzGzen{M;4gij3{(9&o|OK5>(l`M?GhJ$NX4B$q2m2Esrb@uYT&U& zYEZ#4m9Xn8Nt`)DC9PN>4^5n?2G4j+hK!glL(|5}u)EX5n-C`thbGDJ$OsvJ#Us9! z1C;NFV0q;7ZEEBvzsabwK=r5zQlkscs>gDERmr)fYD{vON|}0E9`E(3dSdi0d9wX% zH8!?DQX3b^xV9qWPUXo{br~{#Tedu1;gt#bqa>|ll6vOtSedwFn0of9_LBZ)H#KR< zeJUe0R6Q5nPEGD#qn;0Psm!h|C9~?N%4&8+vi59I+2?<h7gsM)Q%Z~FrP*K0)Pi~P za`s}$nVBOuxUcu&=l<)#C;hJD^9>sQ^N0N#{@0Id*RB=W<K=3m+zrsx*yU=Y-A#GN zW#9Sx{e(oXtIsg6D-QeF7cRHkZJ*Ak+-~o6oJ;#lueBZ>uoF3(j`nmS=My=h$QeaW zDRNGclZu>G<g_B^6*;lUnMF=5a&8^%$wkhtqdmRI`9)4Ja)yypjGSZSBqL`TInBs< zMou(xrjb*PoNMG{BWK&uo^IrPBPSd=<H#vT&N*_@k+Y7RcI3PxCmuQT$f-xpJ#z9L z?b%08zoR|>NCJ=yASpm{fFuFQ0+I$tn+GHjNG6a}Ah~d~$#AsUK+@r8^MNG9(Pjim ziKER4k`yE>NLrA*Ac;XTgQNz@4U!xrJ4kwv{2&QJGURAegyaZG5|Sk(O-P=QL?M|% zQibFSNfweVBwa|pkc1%_LsI5wbA}`h$r_S2ByULK_}3(JNa~Q>A<09s=V;T1<j>J2 z5Xm5tLL`Ss5|Jz-X+-jfBofIal1e0(NHURZBI!i(>1Y#*WE4p$l2at9NLG=wB6&p; zi)0o_Es|R#xkz@A^dk9nv<XHs>}XSr<QPdZl4T^#NS={IBbi20jpQ0hHj-^5-AKM2 zZNia^JKB^ZIY*L?WF1L6l6NHWNam5$Be_SCk7OT7KaziB0w6QM(M|zm4mjFLfXo79 z8X)rknFz>CK&ApR7m&$-%m!pSAoBs45Xg*hv{M3^6OMLLAhQCQ7RbCnCI&Jykg0*p z4P<g4vjdqP$oxPi2r@&EDT2%qM>|Q7S%ORxWS$@s1(_+xR6*tnGFgz>f=m}=z916@ znK8(eLFSC3oixa-akSG0nK#J9L1qpzb&$D(OdkAy_V8Eu*Rv<k&LNMTMUjbjMs<tw Nbd8QojP~#<@K40&SY`kK diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Kaliningrad b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Kaliningrad deleted file mode 100644 index cc99beabe4ffc5107c4719d1201d6583b9ead03a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1493 zcmds$TS${(9Ebn&l-kr$=sahdhn$wpL#wo`In5JTu8U6Kg-AtETF{Neiwuc~S_kPu z%MdYw6rux^30-s%WabJXTY(S}cv0U?L`Bs5d}<MNQMdg*_C6oq24n1byu0?dIpvRw zn}6D*$$h5MN3Yf1(mVCi=$jt#UmCpazkJv4@AqBwKZ<JikH4$8J-KH0PYk$iPtTRu zCcCn2fsO=Qp!3*FpvTwp?BsCM^PP8Q;&ZP~CM3S9v_}S;>|f#@B+kZ8CI#J<$>ZlI zQ|@0eQm>yi()zlL^ixNSWu2`?#=#xN@;%i?X2V(|t31zGQIKS0rzS~`HCl4ROI7a2 z9F_Ohu2xP(s{DtamE+c|Di{o^!VBYSm2XU~K02a`TKm<Sy^qD&F(kzm!&0*Sgp{V8 zkuv82Df`wgu9R-&dfhDRzV1`&$4X^Guuhc^ZBrGa1!`k=vD(xdt18>#)n=bVws<}% zcWaDPWlt-Q`-4=6kE)uifYiKyA+@15rFP<;)V=AE`jI|q7{8$!PahX=gX3_BB_uTL z=M@ni5xHpYii)1U7F+-Rim{3;b?LuEQZp=JBC$4!`u#q?$P&X7St8=9v?Pe+7fJHM zx$xxIXY{-2bDwW$^orZl%;6OeHy(Y{*j%Mw_2MWh=4&mMxznQO{RfS{>m3@{y%nO9 zNv#w_D~MVUy&#G~G=r!H(G8*;L_3Ij5dBPQ1x;!VAu2+2<X501L`#U8CbgarMIo9( zRE6jYQ5K>tL|ur!5QQNcLsW+73{e`QHA8KN-X^u;5X~W~Lv)8I578c?K16>=0+0+K zDKK(iB*Dmnkp?3VlR6PbCMI<%j9eheFtUN91IY)H5F{f=N|2lwNkOt=qy@=~kr*U1 elR7m<ZYFhdjO-ZcG4g{X$o}&Tqjjc*&gdTt^LtAG diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Kiev b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Kiev deleted file mode 100644 index 9337c9ea27c0a61b1082f4be37cfb0f9484cf5e2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2088 zcmeIye@xVM9LMqRSD@%LeCwj~0)!+L?SunF(IBz&U<RkBoJ1;d)`?m~ipHQcTshYo zxwn()T)J5?G^flqv_G)*W3H^hb${fVBUh`H%{lkos=0EkKF_bC{^+m%=)b<-eZP+{ zU&d~`@p?wrZfPm8{&C!G-f(ernTzKcyUp#S?|A%dpD*_LNMUmLYORdC<JH7lK}n39 z*qS-}c=Fz9Usrk4M<d?fCx1BYT1L`08mzi+_&_r2{4po{)P5)D$ji?3p6yQV&bX7; zy2iPGeYG>AZlRN3QQ$n__c=4OJ<hC&x13q8=Y3o7gLn6wFR#buUic#N;9w%=?|U~g zulG!>aL<8A(T?*Ph@aNtrpr>&J}9M?Lo$E$K`F~QDho<FWx-gtlxOv7`IQZ_=vId= zem^J=jW%jUf3sE&E!KzkF4ZM(WNTGRzAoLfNFJ$9(_lPHmd(7Xq2QQQr+ub1`QJ#* zjUQ!s%15$1aZw)q{%xrpI4O0*A82@AkE}TLrmk#jlSt1iy6Umlbam@StzX!x(YhL4 z<6WT*{yExkGoX!`)zbLYRDJx{0$F?R7hQMBBkPY%k*2}x@<jK~(%hSnSo0;>u<M#W zx#T^0s%co`xrb$A<$$)NpVdt{s+)c~q?^aub<4#refmmNpE<EkTR+(*&%RozZT<D~ z+~!=}y0=WWt*Vgr7O!kCo-R8=zsd7cEa@o9)DGu6>CCvPoyiN*b>p(WaHd~gObqGH z!yoIefus6TSD$w8>sEV0${nd`sVR5fKGW~|`}9n>eNLS8U!0beeZ>5KaZfe(JS*L@ z<_4@umX#rv@W#Gp{9ayV`^JAe{%q&)hC6>-7mixB<_d+PR=B>_3L1l<dVW}DUYZ9E z+jcMb>#*(UznH`y=4d$gX&jjbG7n@T$V`x_Aaijwli_2T4Kf{MKCWg$$c&IFA#*|| zh0F?>7BVknV#v&psUdSiCWp)pnI1AfS2ICmhR76=IU<upW{FG_nI|$)WTwbek+~w1 zMP`dk7n!fCnJ_YAS2JZ~&d8*ZStHX%=8a4onK?3bWbVl1k=Y~DN9K<t0Lg%>Ndb}r zSCa%J3rHG}JRpfcGJ&K5$pw-OBpXONkbEEsK{DcMQi9~f)g%SU3X&EiFGymL%pj>j za)TrX$qtepBtJ-kkPIOyLUQD4l7wUlNfVMMBvDAFkW?YLLXw4K3rQD}FC<||#*maD zIde5hL$c;-(uU*>NgR?nBy~vckmTY2*)v~)ZF@{B=atY#f4H=;tT0ei>JJwO+^6}T FKLL|r@~!{? diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Kirov b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Kirov deleted file mode 100644 index a3b5320a0bd139c07b8642c4efd7b98f57c6e8dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1153 zcmd7QJ7`l;9LMn!oAj2%!9^R}q&{jI`t+JKCDpV>(>AoGP$W21h2o<i2>y`{3PKCk zPAVvZiXw`^#pj@tRf4#PZ6~)X9B}f1oW;eW@qDj#au7G~&Ap#+Ng(9+Esh=;PpChR z8vBHcBWo|-ueznWr=FBTBdg<A%WJ|5Zf(tcw)UIvQTU@OuU$;Jb#rIR^|Kds<lbo= zy*{BE&K}n5PVLd_kLLA;eQCY1(5xFXb$U}<NXH^U(-c}V@jzVSU&GS;=JQy~%TLn! z_^q^+=B548bLp6VD4Qp4ihJmSY}r3+62~u_WX}!Lx%;F^MW;+xVz24?e!!&bPe}S* zpXpv2m95X3%(lghWbWjo=V^oV&ctN<H6__`M|Mm{%+CG~k~{dr^u=CFe@>f$z<tR# zzA*VOugqXo$qX*sHAC-b%&rILOkwV}44*${iiPOdWTjH^Rjv4S`UAhuYNy)qbNl=0 zcO0cUuGs%kwYbW!)WC?({;TP%TDg2*e&VxF_)KBAs9N2my;An-RLW;x_CSu}KWt}z zeue#z4f#GhB3mMRdfH8qU6E~(eUXikosq4Py^+n4-I48){gDQc4v-d*9*`zHZ5K!z zNFPWeNGC`uNH0h;NH<73NIytJNJmIZNKc-&DWoe;+ZNIn(iqYi(i+km(j3wq(jL+u w(jd|y(jw9$(j?NQr)?AI)6+JJbc(c!^olf#bc>UA^Z%{gV8)i++nx;m1PZbYN&o-= diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Lisbon b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Lisbon deleted file mode 100644 index 355817b52b1b05680bbb57e4dc8de358eff27a39..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3469 zcmeI!cT|;i9LMoXh!gdvCa5?bC38dyI5Ele24>=dtKvW$hzs%YIu4o!DVeFq^V8IF z<s;%aq_}XUxEBswkz$UU=EC(DnwSy&-j9D&r$4fD>c1Wi_jSD@|M_`;9leLe2HO7e zc&bnM=DDK2dGC{?UgqAMowT^)NPY3IN0OE-xvwwHnyP=9=+u{`Z8eQ(hrWDfo}SV+ zS6>l7N>BCmG*@;>G1ELA>S>Q>o9nVxo9U~4&GkkXeZwan=EhG)n49!E`ex^JJ)>(e zeOq9dzP<cWeS6UkeaFKzeb>=#X6E)a=I&+D`kpUln0ptQ=DvhDbN|pN^FU;0^I#hf z{ZLDP^Kh#L=8?#?`jOnLdX`&bJ?oLCAG<ctJiaB|JbrJ5>qJsV*NICh=E?a@&65W@ z_Rn^vxUvuJ(NB%@GEc1?;yN9k>^i-2xqik`V4j)P!F4t;)^+ydsrtEI2hDFfY%z0! z&S>8@*sq<hx>>tWDpkAiY`&IzXPS0tM=$O2rexzv$~fcd+*rdkrKj<|^F8C*z#!v# zcthidc0R_9Ku_al?Ly<0PXq0CnQGeY=Vi1zdB13R7w>C#k6qF3eSJ#1pSD+fuxO+9 za7Kz|PW()JG(1`RanO1rKf*8`+vgZhnoKc%@*QJ5trTMvxOX=S@<R>JuNvCQF7~mN zo9SsQpWGrzjIEzkA*O0lMMo7`$^Ja))h0j7%D#7{SEWnR+x?{U&fhJoT+cMBo-<^% z19PO$u1ryVZMvwjWSOWrONv^PJ`!4-Q`GJ|NYn{)2;bHr;x)hKqHgti;&sm|qMnCc z)_c-a*1u6#Hpuak4G)!&Z)6lmztlVO&3PAPqvYeV@z`C`KW3c_h{_d#&J58cc&BI@ zzCbjqu~ak<Oc2cr6Gcm(d9vl@0V3%6c-bn`F5dbsQnp?dErWNql5bCIE88rtF5iju zm2H!QM7vNAX^-&{@7BE~L+phj)FVr__q{6GKe#D6xbG7kvX6@Qudfgt)6+!Qi9NE@ z>{+7o+U2rKe7xv7YpU$lbA}9$8!RJQ#7Re3d)eK)v+Uv5K=yd*FC#05ipcX7Wv?go zMenVTWuKhVqOVawL}lC){Sxy<^t^1*KRQPYn4BjEw%H~IMV*i_wHAuO!Ra!#<Q6%k zhLl5Ye=dg>I_0pV6XfvA4mn~?9~pOev=})(SjMl45Tl0HlKQk}Vsy9G!Wru=#st(9 zV?&;aaTRQ0eB;V;ym?I|lzS=@P9GE#9^}f28&-)AvUkc!3-`;(=}YB@6H;a3>_llR z?)Hj%v6uYvP(Sy_@0a>_CI0UBmn>y{l`j78e-#xy9i)cER!+DTLtCjozpt*jmHqv5 zTSfksSM|BqAAd5elf%|CB!U;d)t~I@jh#=_<EEY$FV^pR@!s(d#;-^{{enGfAR~wj zp`{u_WDt>2M1~O=M`R$8kwk_P8B1g^k<mnk(^8EmGN8zaB14LdDKe<Ys3OCPj4Lv* z$jDl%p+&|P8C+y^k>N$g7a3q=gpnae#uyo7WR#I%M#kAv4Ky;+mTIVxu|@{lQjIn; z+?Hy*kpZ_<BaRHYr5bZ&&@I)dBg1Z~#vK`WOEvPy&|9jpM+P4mePsBN@kauHM8Hyo z0Eqz-1SASb7?3z1fj}aGgaU~L5)337NH~yqAOW#d5kW$N!~_Wn5)~vYNL-M>Adx{r zgTw|24iX(CJV<<y03i{wR3YNO6EWf;NIXP|hcF>=LIQ<E3JDbwD<oJ*w2*LFs(2v* zLn4NR42c;MG$d+B*pRp(fkPsPgbs-v5<Db&NcfQWS*idc5kx|W#1IK05=A78NF0$s zB9TNwiNq2KCK62~oJc$^RX~x5TB?vDF-3xkL=_1u5?3U!NMw=FBC$n+i$oU*FA`rQ zz(|BGRfv%oTdE)<QAWay#2E=R5@{sVNUV`yBhf~}jl>%XI1+J76>=ozmMZ8-)RC|w zaYq7=L>>t}5_=^0Nc55LBk@NL0OSZj4gusCuv7;Daugtk0dgE52Lf^=Acq2SEFcF1 zax@@^19Chd2Ly6NAcq8UOjxRe0y!!y)nS1g7s!Eu92v-=fgBsi!GZrD9sl9cQCi(6 Y{v0ZPotiXi*2uqcfM2Hof8Le;4LU9nuK)l5 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Ljubljana b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Ljubljana deleted file mode 100644 index 27de456f16ab549627b284a39e2265cbdb4ad8e9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1920 zcmdVaYfQ~?9LMqhL0H4S7@-o9T#oJ~DdMPHDwhrt$t4vMLdq?-nOU<hYs@g$HH>%= z9>mObA-Sy?W{kPcS{sI0<M;k=Hk(JD*!)lDyjrdG<oo`(Gv?)lS${mO%ujgptT1oB zZ@bQX+-w&4y!OplxqZw_>khf(&W;GVyCFdC9W0aksqxz7<tgp@;DC0!vR%E;Ul5-Y zmEya1zjQBC@msxKdgK>M&*^idSF&6DV-uveGfDz{0;NxzE)wYB(!kFV+V@p}_N(u# z{jass0aahsdE}iAEPt#)n{H|Fvhx~}eNsa+A4ynYm4wGtOT@&T66w27qQZ(Ls;N|> zy~{QF=`0!iy+~s&xMawabd9aZ(zxmv9lCkA4%_3S@j3oFeA8eVk?5hWY;PGE@J16{ zO_JzwLzDcUNm9dW8QuJnjIOJZF)t6x*vjLQTzgSdwv|chiGw<>pg_i#ZPW=<w(7+E zxtca8U){+`I>{?lCp-J;<S!wb-YHSiA9m2GpZiM2*-tvH-czO@XfK&nA7n=9N69L$ zlbKodGHcCyojvTF%*m|PY`@(yH?C51TA$HeU)9{VyELz<Q0LW@==`T{U2t@o=3ieT z3%A5+K}DJ@%Jb93n<Hh(gjgxe@sg#X-DO$AH(B1^lA_>FTGaSLiranB;=5O+q~VdS zJY6BH>Z*11?#sHSa-Xg(IijW8O4ZS#S#$g4(ehuuEURO*xhkujSS@~i`t)$LwyfVj z`E7EF+j1rFPIH?-a5(tlaX8$6al=2%Gb6Tf6mrYRJtH@b+%<CB$bBO>j@&u_nOjHh z9l3er?vdL^?jLCY=>TZ~=>cg1=>lm3=>us5>BQEwg7ktkgLH$mgY<(mgmi?og!F_o zg>;3qh4h6qhID3YT0?rXHO(R2A?+dkAq^rOA}u04B26M)B5fjlB8?)QBCR65+L~sO zZf#AwNWVzKNXJOaNY6;qNY_Z)NZ&}~NaslFNbk0$d8B(=(>~HavH{2rAX|X!0kR3m zE+E^0>;tk9$W9<zf$Rmc8OUzfn(aXL1KAK{N02Q+_5|4!WLJ=FLG}gN7-VOVtwHt% z*&JkdY|Zu{`(tZ12-zWIi;z7+HVN4!WSj7R-zQJATLVKGE@w)3P-IYuGbJ<xgTp<4 E0<)*Xw*UYD diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/London b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/London deleted file mode 100644 index ac02a81440f47a67b9f01d3fbcdb085266d20894..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3648 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 Nbd8QojP~#<@K40&SY`kK diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Luxembourg b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Luxembourg deleted file mode 100644 index c4ca733f5345df24e5286b70464a6c0498353372..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2946 zcmeIze{{`t9LMo{o5dFMHf*xtTWbx?es3Xbm~mwD^TzU9X2{}N+S!EVv?H?Pymg$U z(XN>dF{=61hA_;DrI=7o4o6BI-IAjp$I<8c)sNH3KlM-l^!=Xi_whaV$Nt)VzFecH zXU94Ib_AGLxHxv2i|3%CvMseG9g8QHG@kRWzFK)<P5CPKo4Zv@i&kpsg*vxq;(G7e z1(!W#QGwodbEivr;zIBG@hMsnp6IQN*yPyI)#=^X^bOf~Ey2C%%1p;wXUg20j|_Ee zIa=whs*H1N^$c-ud%2C{?Ikn3@3>=Ld^dNoyLxDpXZyg>){YqQ?2OCv>}vVFXV>jZ zp55P`^1OF?sa134JFB+-qP1t&No#NE63@QZw_ER*gjoCYS6T<AEw&D37FcyD(Vj!y z$5@AZ?zfI)p7tC$=jW;K8)F^2GDwbZ4AzFSRQd4L1UWHln|zcTBp(m%ttXfFmQ#bm zv_<)34OrS<S{9|L%t_K#SrHoOYNxF;`bnGkpS5k+*BaFNGY$4RuEE#$YP(BY_5PC{ zZGUjNhSctn(9KoSVRfl=ELQ0>Z=qN@x$?l+$?{;jOTv1k$wQGz5*`{M4>xZo5x%J! zaU(%HUk=wUjX~P=P*Z)R`bUi{|4O^9IHyrXA87QPT8+utqOs%7N?dNW#3$EC!tmE5 zvBMfkip!UzTZPg+WQBG=KS_H0lBYfQq{?HTW@@jB37TBfQy*W{M^j2dwRd)y_9^Ni zef#@rYF3E!3%{aiskfxR?@=8P_PGqW_Js`e*)Ibd>g9<`>ts;XCP_cGPcxPk%izsx zb;!(_GPL+59X9F}9iB5qM?9LNuJi%=Wbj}e8QDcg-i*=Aw*4jZlR$myMrRql;|Cqn z=r3bEtz=yFH!{BPx=dKnAQLAv%B1;M_34zIGI`uF&FZvDrX*KscC+m|wS(%^FIVcc zTe&*DzCfQj@6s6?#%Rvr+4Ah-WSv<tLS{|tr0zwDGJ9Ar$;}Ry=VCj`oV1_h`Bo0e zi*BoV-iwkSa8vV7)Jeg$vpRQMg}l&Eqw`iB(D_wsbU{J67A`B)dz|L<X>zac-Oi@X z?snei=kMolzT?xRd5iz*bU1wL_>G2I&L-wpDh|KDJ_m@i1@Aiof4|>(#eCAdV!mbG z{p0@IUr5hzIa1R`aC13E@i59fn8WGhGIt*SJe*F~KZwX}a}W|FCblLhNK}xpAaOwg zV{0OVga(NX5*#EtNO+L=AOS)mgoFr*k*x_55+x)|NSu&BA(28tg~SR877{HaTu8i- zfFTh>LWac5)&vcS8WJ`nZb;ye$RVLaVuu6|i5?O@Bz{N$kq9CoL}F-bf`~*B2_q6m zB#=lXkx(MBM1qM#6A35(AH)+0C=yX5q)1GWpdwL4!ivNd2`my>TN7F&wn%W1=px}o z;)?_ri7*mkB*sXPktic!M&gVF8i_O#YFiU)B-lu_k#HmNMgopR90@rRb0p|U)RC|w zaYq7=L>>vft%*Gnd|MNJB>YJHkpVzP02u;g43I%UMgbWHWE_xzKt=)?3S=yh!LT)> zfeeSO84qMYkP$(K1Q`=#P>@kUh6NcHWMGhyL52ny8)R^7&FCP*V{66-86aeYkRd|G z2pJ?~l#pRU#t9iHWTcRxLdFUiEM&Bh;j%U3g$x)nV#tsoV}=YGGHS@MA>)P&95Qmq z&>>@o3?4Fi$ne>k@k0jC){G!Bgvb~ogNTeGGK|PL;{OAAXD0vkK>C|0?H0?ZMrOoE PB}T<WX2ix|biDts=f9={ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Madrid b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Madrid deleted file mode 100644 index 16f6420ab7efc7ceac3b0e42fe37836185cfc463..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2614 zcmeIzZA?{l9Ki8|NFqM{KoRSrXhdl7jF6awhF~W6cvBLIt0HP4U5T9d1Wu;r82i<% z#>&KG*hs+&a|^8{kTQWRWsS;WxiZV_Hf8q2=>I*vY2}+<^`>)n?&q9yxBKF5zwghv zbZvf|^^aqSdBer=s=2s#l$noL-f8vhuTHY6)!{j?y`Zel=SO$l<wEO7+aXW=p*X9d zdY=2}u2I$-&up^ZbjOsvRkYjPI6t85RNGZgb5@Sk@=%JWWu2p^HL2KjdO~*D>E24u z+1@W)?a#0GbTrR#byjz|KRg)eI#+hw{n3sQu8&<+?(-{ta$T6d+1))Zy{G$1w#Ro^ zN00A~=iGyTXz1~~Q0yMk6x=iPb%$qIO_FQ)o<7fr@-&s=MD@=L*8t}j9ho^(M#cZC zfuY~)=#igmkavd$U4K`{Tx!tU&sXam&Cjai#7PN0TrXo^-Y?@SR6@3Fm+=KfGGW<D zxiiBlq0`dju82el3l5jNhmMhOpHvO+ovahT4%10pqxGKFL3(fF&l*v4MI-lqs!`=< zHM;nO#^fE**qm;OD{7SZ<R+QC@C8X2yH671HcDb&sZ4R~)hQR3OVV!}bn3}ex&N~) zomQKx$xT!Bft@on<)vVqo*$|+%9G^5bRSL4bI8oF%bJ$jC+R+IIxF-`nRV?OneF|) z%<eoR4_`VcbL#6Pqy0V2tgMi^hY#qy!a|u}u|pRu*`o^!R_UVq3e=e~OCJfEtBWHh z>EfF)niZHXS)T;xqrDSl>DxCnyUS0ORr^a$<5hXA^t$Bk?G#sTmn`4<ovuhZE-Q1| zH7}$}RwdVKzV9(zJyvz~w=e3Nz9L<FrbHjV=+q}(%hrMq*2}ux$y!*uNS<61qVAmu zvVOrdDasF$r((xRaoR8Pw7(@Aq62k<=PTJb{HAU^*CHj?x^>ghTG`y$q+6;^>DKyv zx~-%}ODjutpx1!Eo!(vpZu7atImmag-+yuT_y1mDhQ%5#UIWn@Y+1qMy@vheK7enn zAp89-?lUr-){?YEd~lhkRGw1JlVy4FJ6`6nfA7x+=f4=_esgR~JZ2#SjSMw1*vN1r z18!@E92s<E*pY!ph8`JwWcZN)AQ3=9fW!a^f~|=H5(Xp=wk8lrB#=-bu|R@>L<0#2 z5)ULGNJNm3AThBuLE#@HDz+vpNL-M>Adx{rgTw|24iX(CJV<<y03i`VLWIN!2@(<| zTN5TEPDr4TNFkv@Vub_?i53zrBwk3skcc56Lt=&m4T%~OHd_-nBydRNkkBEqLxP7y z4+$R<KO}%i1d$LTF+_rhL=g$2t%)NNNLv$0B$P-jkzgXxM8b*06A361Q6!{DOp%}> zQANUv#1#pwt%)oWT3ZuaB)CX)k?<n%MFNaO7zr^FV<gB(l#wtaaYh1dYa)$=+SbGx z2{saKB-}{6k$@u+M?#Lo90@uSbtLRa+>yW|kw-#rYhsTCABjE^ekA_L0zj4kvIvl6 zfGh-LDIkjhSq{j8K$ZluC~VELKo*9rSsKXVK$ZuxK#(PZED~gy;QtH7{0X;OD1K(w XM8>jpA~NHn5~5-vGGk*fI^ORO@U!br diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Malta b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Malta deleted file mode 100644 index bf2452da40314be196f61e6a7cdd48eaf5c426f3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2620 zcmd_rZA_JQ7{~F$lLDz-_yDE{wa^en9z^gV(Uj1c2TM7bsVFL<7SSykL8%<eTs7vd zmf{$g_z=sc)D(4v)-q`{kr2bwaygw@+3eoTkSW^#dpqq#uX@v)?laEkaFmzV_vf9x zEO)r;A5UlV4L>|P%@3cu`pjF!sOwfmYvZ}f`lI&d1Fr1%-nwONsdAsI%6{M8x_Wo^ zwz(s%?Vdi_4SC6S<E5!`Y-fZvZA+7H^t?9b&(q@t;nL!1u}_Rk)NiM>NNZ%9buwm? zee$wTPlc38d(u9;{q&J@H{31OjZbRrn>TB%j`A}5*2QM~_G^1BSN$H_Z{bGEzjC$} zF!5z8@Qp${Xz06kr#?wm=g@&xa74Hjd}f3d($-T$4|nz5ck)l|vh{ag*Zrro+nVFP z`^!F6S+Lg^R#>UsCv5cfNS`A;hwO3nin^@fJ$}%LfMXhQ^)u~#;Uj(EM3wgW@*VAa z@Q}E7)ktLJ7U@^2(tqU|8IV^X56)dA4|%*2H8x!a#-_+1ceFg*rME-}rD^oF5jyzd zAdP7a*CF+tb!hE%jotB!4%=`><JKP4_!S2=A!oNHW}TMd1+|itS|=lBlu2^rW=R=d zBq<#wGOF(e9d&krjJ{E*V-BUsBj3-`vDNc6wQh`#TQ@<+SGe`j+$f!}cC<{K6r^c6 zedV!1moz=CLnZ}%t&^jEl*w0qk|_aS$dslAdHlk5nOgIqcp5*~jP<25ZP!+PB0pcA zEPY+4KmE4O$Xl$LBlFbjnXFGmOw*aMF*>s?L1*=vB(uKjuFqT>EVK9jp>tY8Wo}iN zWYzvA^GdGD{0&W#J-<~Jtol_Kjz1uavKlp~f4MA9t<l`zeYzx4b;-}0bZJL{E^8>( zXU}@|xew-O-dD@z`8QKFzdBQ1SlVB$b;+`P`dBH*jgS`;`^k#*c6lkxC57?5w9q~; zMcvx8sQHK#UpcL>d|WNBHr46M^255SX0xs?-k~MyOEkdG|K2Mg(7gQoc{i`S-ucb> zmwW%yKd94x{WAAdY3|A89^e<~a&;3|$ldol-~9c(C&TMXOV8xZ%U}4J2h9iXzqsDp z=CKZ)$U&~y(Ofce&B#R~SB+dYa^1*<BUg@GI&$sE#UodbTt0IBNCA)vASFO*fD{3# z0#XJ?QwO9FNF^LiDUez?nqnZ;K+1tmJ@`ODcuYlrk{~rfih@)HDGO2;q%cTj98GDE z+91V2s)LjVsSi>hq(VrEkQyOHLaKz6iHABNg+eOjXiA0D3Mm#+Eu>sXy^w+-6+=pf z)C?&aQZ=M(NZpXaA(cZ)=V)q&6c4E$Qa+@9NCA-wA|*s>h!hd2B2q@Ajz}SqN+P9n zG_^#E>1e8nloP2ZQc$F#NJ){JB1J{2ij)<pD^ggbvPfx>+9JhuG}T4Q>uBnW6d0*6 zQevdWNRg2$BV|VFj1(HFG*W7$)=04(O|_A7JDPeU1xG55lpLu!Qgo#1NZFCPBZWsQ zkCYy%JyLw6`bha5P5qGtKvn=*0%Q%4ML<>oSq5YskcB{20$B=VEs(`PRs&fMN3$Nt wf;gHLL6!tr6J$}4RY8^oSr`2OElj8xoneX0Pi#g~Tyk7OY(`=N#wUgT1<GOd9smFU diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Mariehamn b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Mariehamn deleted file mode 100644 index b4f8f9cbb57450549933f83ac90dd56a2ca75344..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1900 zcmdVaYiP}J9LMqh%+NyL(Hv|u%xpNev#Z<YHfM9$FguvbY}n>D!>~5Db3~GszG{&W zvX;c`!B9r-BI~5Igq9-LB!!R`zxUr0<&h`KIi3IOv`%~UeSbXjSCl4Nf4n-GzwqHz zX+C@p@tH^6`ZZzq{JBLfS6>u`Mz#5R_4NB3fmeKvkBz?G&(CU~2gkJUjeQz+>9T~M zZjgw>N2OnlO5~R9(!Z=i1}t1E1G7C6mFAW~&QysGkCDM$drM4EhQ@qO*4P)(I;6Fi z4!zY`hc$gwXWbheUi(<%cHYzY4VTnad`1%r9!X+FlO&}#OY*G!k`i%5QWL8rwcRTt z!)kS8+hQ5@y;4VC&X6%r@-?l#P}7@7>)2frbljnE9bX!y6LyZ0iJ3u~Q5+_dqF<>y zqg^tC?rK)lQ^|V&Ql<o6lPUf?GWGchnbvShvRkfb&fXfCe)_o1C@+_pH9ItS?jD_0 zR-$<$%G8scrL!H=b&hk0&iUff{LoCvf7nCkeU6p+=RfI!)?it9EJO;L-pL~GM=7lJ zOHpB~EZ+K7myEk0OAA`GIP##Bq&H}3mvg!-LUq~e1G>DuLRZ|W)|G7@U3GGSmfc<_ zt9Pesd3~O&SstltccsX>+%%~ub;$aJezL*+O*V#DQW+nrl^>o-RrfDib^oSRzkj5g z8tY}Vzgf2&ysldtj_9`PI`!`LYCvEI``t0<U%oBNQDP2?XGhB#>I&#$S>gSyZohxe z&hc22&ByJ|<Kf}=RzSe7r{^zD_lJ4qT^xJ}Ibr0CkyGYBa?Z#}BWG=EP8&II<iwFP zM@}6%cjV-evqw%JIe#PpBm*P`BnKo3Bnu=BTayQp2$Bhs3X%(w43Z6!4w4U&5Rws+ z5|R^=6p|H^maWMPNzB${hNOn%h9rk%hopz(ha`w(h@^<*h$M+*iKL0-i6m-kGDT9g zHMt_mBH1G8BKaZ-BN-zpBRL~UBUvM9BY7i<+nUUg)NM`fNb*SbNcu?r$OIrWfJ^~0 z2goEKvw%zkG7rc^ATxnXg{_$jWHON1K&Atk4`f1+89}B5nG<AEkXb>d1(_FQVvw0Z zrpDIH4Kg{lW_FP2LFNaUAY_J+DMIE5|KmvtHXAiOk+pK>B*mq~x#E+YISDTNTXOJE D35>6g diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Minsk b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Minsk deleted file mode 100644 index 453306c07566a94c0c391024fb16ee36245a0a40..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1321 zcmdthPe_w-9LMqRbk<sGJ7n|8txPk`&9Y5x)wI=|qMJ}{b%+WNLn=DhpJU{Y5a|&8 z@03u47)c4ypF<{e=n%GS9Rg!@iU>T^bBU;k^?R=t9Xiyt&%^e9d_?^B`XzSm>+{JU zSMu{|M3?&&O23U6V}ZLPM(@;~{&ebH)baGX^UU<su;baeCP&&{&|6k}ExoAxRmf?} zY;k^B@UVQgG;L(Up~b25>52zeOxKOGrhE9fx#Z+wbLr8fS$SZ)xolU5SruDrRtM|M z<zB<AaoNq<kLCS!Z=Gu83!AEc^jUfC%qs6lMm1bWsa1oMYW0zE)tJ1j*6e;FzC)wp zZ@no^+fGQc`?R$9_DjpRgA%A1Qi0cTS@(6XT0hw=8#3K0IJ#A}PIy(@kY8=QRH{OK zWopx)M>a=3sc^DH+G}2_Nce+v6iukk>gUq=enz?qZ%fzoed&I4QKI9+5=-4uJ*SSz zKsKAT6co;}7Fml5=l-~C^L}0S`G0p67mFA(`fn@7W3h_3D#a#J-zfTdsY4t*u`JBL z2SOGj|JnS##r@k?RmFM|(xYFIh;BS8Vcl>f&Ij%Kp}z4n`uTQZvGCGM{DT7hOJ{f7 zo2sK|popNTpva);pa`KTp-ABeKnq0-MNO_+4n+?|5JeG15=9e56h#$97DX3D7)2RH z8bupL97P>P9z`ETAVncXB1I!bBt<1fCPgPhC_^bjDnlznY_3`@LvF5GFGDazF+(y% zGetB-HAOZ>H$^x@IYl}{J4HN0Jw<-5T0i3i<f=~r<0LRn1LH(cP6Zp#|KtDTWY~lH Ku(UP!?cV`C@iFcI diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Monaco b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Monaco deleted file mode 100644 index adbe45d1c1db7287345b1826a356732075a38c51..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2944 zcmeIzYfu$+7{~EFDvEe}&;%0{lMprJ4yj3Mh-3nyo|IHX6H$|BC3Da;baG71aUL7S zGBi*TZ-`cS3%uX(Mpk2{<<#h;T^##2=GbM-_PdkQi(dJvH|@@z&+fiBug>}Yykn;2 z#ajP5S~zdGIQBXh_aXD0j}=8NhLxrknbHdp_UgJ7_L_rFoA;LdX_uAvH02XEn6>j; znst$F&H6cMrXpd1*)TrTt_({s8^cS@rmSxE=4SKE=9}^Mmg_lY>xE2Hbz-2|c5<Vs z-WY1Omk+adyy0WsUozc%V0X1YEL?2YWHzyP4v8|mqORGyW7F(CZR+hk_x9R*f7)Vy z^!Wr+`^9lnSHIir+q22+FUzqHytC9CeAk#mMfv9N)NFGkE5jV^?_(e99c_;HU1?5a zRoN#lH7`FEIM$rH;{E3IwrS?f^`UZhbD%b?OO}t{ikEXsem0*J2FRxw1GGhLAFJio zAk(U1lD2-cqqJF=qB1j4{d2>$t+#`=OCKZ;#r>}BLx0qOc3){=<FgugYrl55x?Las ztXw-DS)oC7`y{xkS~{&Rlg`UjLgp@zF8PJ>$hb+;HO(ub{Zi!7h(rks4wr5%J4m=s zvWDM|*Y4kjX^-;(+Vfa5eXQnJji~rudzD<$$c3jhYG$2A=Wf%O?28gxSR-*swGuyK zr6hD(BZ;v^l6bdRdIyzg@5>XV&mXh2@4jSt;>#@USDB+pwSD!;MFX{eX|N8+3)O)O z`^Zy+eKa{YNCt&n*OcVDGT7&&riOkksW-35kj95(NJG6mb9KE8t==MOXAWrk@@0}y zwN{4}6iDW>*LC>lr8**ivW|Q_U%hFm`fOl^j*94^qwYj&R{Oz{b)l_3ce}fc+4YN# zJ?|&u%Kas~=7x+fz9l&&4Kg9;yiA<;gFfGXw@k`Dqq!lgWO7oq=K1c_DV<cOeD}6a zy<4c$>SyZ<m%TcD(^$<vK0{tyoTLSnBju&3A!;v5kQu}KNnu`~yd2Y6W~TfmulQRs zE2_QDGFPOi^&KrbcT{HIyr^?_RLZLjwK{jzVVzgKMqis<p~cIK)zh?5;|DvN_}o8z zoB1~P`>#&RYI?)@e_D-VtR|M#T0FiyS*`Bh2Y2!K-+$xW2k_nsvaEmZ)6%_GrgM!> z8OaBi^OVd}vh!qF9*_G4f5W}U<9&dB+;ffs|FROKBS=eJot_{~LArvp1?daY7^E{u zYmnX`%|W_@v<K-A(jcTmu1<@P9wALax`ea|=@Zf@q*F+%kX|9pLb`>t3+WfqFr;Iy zPRo#<Ax%TNhO`ao8`3zWb4cru-XYCHx`(t6=^xTSq=T+b3y~hWI!#2nh_n&uBhpBu zlSnI(ULwupmq9l<XeZK7q@hShk(MGoMVg9q6=^HdSER8>XI-7vBE3bLi*y%hFVbJ6 z!AOUZ79%}Inv8TAX*1Giq|r#Hkyg7py+)dibQ@_m(r={UNXL<uBRxl&j&vPqJJNTg z@kr;9*1I~rN1E^IbRTIy(tl(FkR3p_0NDd%6Odg%wgK4(WFwHBK(+$e3uH4~o!vmT z!`0ajWJ8c0LAC_h6J%46T|u@5*%xGEkexxc2H6{Ab6lO>LAJ-$*&k$skR3v{2-zcK zlaO6Pwh7rMWTTLsLbeLoD`c~f-9om@)!8p(!;l?AwhY-bWYdscL$(dsH)P|GokO+` z**j$OkljPJ&(+yKWCLBD9YnSe*+XO#kzGW#5!pxle<L4!BmJED>=nb1Mx@6@CPYR@ Lq{l>KRGi;m_j$vq diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Moscow b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Moscow deleted file mode 100644 index ddb3f4e99a1030f33b56fad986c8d9c16e59eb32..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1535 zcmd_pOGs2v0Eh8&eK(rb!qglm&2)U$sA*0)IyEzjsUbNPSW%Qng3+OZ6j}@+wy8i0 zTv(<w>Y|s6YLnFvfkYNAS_B#d(ZT{b1Q9Ad&UZz$TD9&D_x_Go1;Ov{Z)$BR5`SH5 z^c!xj-TLO770{2~!?v;O6<<2~a%X1yzByZObnc(+f7>=aAe@1L@*#I{^@&i>RWve~ zaC~IY6&@P4`5GPslaD0WhbPu1O}P_eCL0pxR)vy2#ZM$pdfe;AuS}$j_ABe{Zk2lN zys}+9t=6AwR%vZ}Rr<jywV`gS$|%oP8}pM@rq!adV&|1T(k|^^lVtYC#6V8_(?HIf zIhp(Xv&_3cCG&%?WWm)Za#QC$x%o`LbToI%!b78~=v0p?cJ-+(dpcA}YCx419Z;p; zkE*hic3Jk$tDN&qa@*r9wSBT&mJfNP>yb@XbY;rQULoBr(Q-$pRqgamOV6<%%A5I8 z`aJJdRpcF6o$*Xn&%97I;XzgN`j*=Dp-a`?y`<{KZ_4`1CzZc0^@tH379J565g8R7 z6CJf8Dth5#iCy-ITe<9u<=^=89B&aK!>RufJR^iCykNxW^I6W7Jw}`mWo|?Nw{jgK zVewqmU?dA+O%tiVzt43T>5K2n+)F>t@7C4(MLl<;zP&sez51>dd5#j{^ZE6yUz(S} z(^$BcUYI8#{QuC`Pkrrs7#c%5Ls~<6Gu6!@-68EE{h8_pkq%9Di%5^Ax=Ex<q)q-* z`a~K<IyKd;BE2HbBHbeGBK;x_BON0xBRwNcBV8kHBYh){Bb_6yo9f<?=8^7Ab^A#F z$Oe!dAX`B8fNTQU1+oofAIL_KogiC5_F}3xgY3psZwJ{AvLR$g$d-^jA)7*Wg=`Di s7qT&AXUNu&y&;=Jc4w-$hwRT(ZxGobvPEQ%$R_cB-=#%wxuDqc3lb5KyZ`_I diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Nicosia b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Nicosia deleted file mode 100644 index f7f10ab7665e94ca44fd8cd98a362cd4b304eff1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2002 zcmdVaZAeuI9LMqNOjy@ye{0UQ>qF(rhpu|nY}s_Jnc9QbPV-i-GEb#fYtAi8r(5m5 z$Yg}XzY-#9P-GGju7RsTPxL@E2zOwMF+w`6v5iOxDx!vL=X;=6dll@>&gI_E<)ZKY z-(P6e#&DkJUr&tl3vZr?^XB{bW1l8}H+J}I+dH(^ihWjRkGpWq7~flHPS|zFdZp86 zO6yW9Zo{ZKvC1|k1t;6D=3h4AQ!kmXP3kogqK}#h54()l@9s1w|JZ1}aiziZo$Is` zPwudj4u!4c?s_|A+d^wfQ@K5LO{O)iBEwEC8fU%fkF}@!MywgJ!**IstdaKEYo`A; zY-Id&-^{%FgE4bp(De6yV`TN5GP67P897_`nt{4jBe$mC&I|6b@{84;m9@nxNNTZX z=e5i1(TL3P_2`_TbyE0Oo6bF7B5&WS)}p>zEj~L}-|3pK^A0BJyWv!w-&rW{mBnaD zolh1_|3gblMx`v~do54BE#)J>%cAH@vS{$SEWUeGmh_*HiW?U-xVu{_Pae^w&COzT z@6cr{cj^00^;-2-lZGnFb$LRiuJC8*iYEcBjxUqypC{@EkJDw<=|{TyrdQS+j+2^! z`?5CjP-=Sy#jL$4>$cz1_4CfihMF5%mvTVri~BYF^0(TMq}uT3er+6W(T&$Tbkk5s zKRmu#o33q^kG?F{=DsTVxG_aP=_-)T%Zj8WoFH3rlVxk^Q)!L!NLx<4wmtY&+9y2G zcI&EijQpaXo$8a%2hZxZ1DADs|5y4&N3TY9NA#tr7kfpI`A=USPs&1WF*6V~#^Xtx z;u-t=lV2)=Ax~*(6(1q~Dk{qT2))2<|Lr{7H~-F!BX^G6I&$yG%_Db@+&*&uNCQX* zNDD|0NE1jGNE@zBA4nreCrB$uFGw>;H%L23KS)DJM@UOZPe@ZpS4dk(U#?DLNM}fE zNN-4UNOwqkNPkF!NQX#^NRLR9NS8>PNT04wqe!Q&POC_-NV7<{NV`bCNW)0SNXtmi zNYhByNZUx?NaIN7u1@Pn@2*bsNcTwlNdL$NAUl9;0kQ|kCLp_jYy+|n$VMPL;p%J! zvKOw-W+1zPYzML*$c7+0f@}%0C&;ECyMk;BvM<QSAUlI>4YD_`&gLMygKQ77Kgb3l zJA`ZzvPZ}!A-jZZ6S7apMj<<eY!$LsuFhs5yXER^7qVZ-h9NtKY#Fj=$fn`{b=SPk a%w^><c>Z91c0qO^C*L2;4Y=QCdH(?jq|NOB diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Oslo b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Oslo deleted file mode 100644 index 15a34c3cedb7c9ca519c195f5ec0ce9d8d1885a5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2228 zcmdtiUrd#C9LMp4h!iXLF@<9RLLs4r{0IL8nH_<d97{PFsRSw_7EzvzL26Vw=Nh?h zja80ZR*qRS?1J(Ft@X!73&~8@tXx~HtTZB#=+9XF-cM^?)J->C^m}%m*Ry9k7iT-4 zcWA|i+8p2CPPBW&hx3^G@O<e*?$(|*;A=m*xw_|2u)6omVjX+YZ+*`P^uZH(I{rwi zJ`Bg{#F}WGJ(z6g_Lu3qr;9YWGeh4uC26Qm`k^91=S$CPc=muUq@C1=|EPY{kd0<e z(CE+!n;cxIDY?H`Y|2@SoBWyiBafMX_;s5)aL_LQXs=!I_Tv_R_=pk?bSm+gXEm+W zl(gkxCD(^_<*K#1sw||G!eUKNFHmYiny$WNs?wqYmNt@SGrml<nf-Bg&CzJPw(BQL z-}jBpYWu`8w!d$gn+{u6&C8Zuc}h9qF69<=D{tA8%1_**f}AE5jJ0S^e4EWVy;^gB zZM1nu0=n+g3M=fWvZC&JcKwb8HorZ=Zm3PM1>5K9#*!!t)WmCH>KQ8zjHx8*Ju6N5 zT&06wX;I{xTGZF0n+9Ic;?9>;*87G9ceQHCf#>Yzh6dfzy3Ll}_NXnZUuWgB>n&7P zYPb5A*z)w5wtO_pDq>4i@$qGL`^XHfc<q9%?2pl^y^~bgbxwD*46CZGPt{fZTD|pK zTQmQV)>igfP10_yE9$h`i(a+$iDv7+e#+{`!nUEO+3q|Yvb*-LwEA~9>h7II*3eO| zd+L(x-W~bcxU^8=TEFhgo~BL3KkNQUJ~d{>TI0|cYMMA|O~>C+^WZ6a;FS(-?(4QK zyWg^{oqO!T=6%+(tHs7ejEjgI{|{Hxg#Z5X`C_KH|FAD1IbyueH&MQe|GfY4=CAi< z!H_RdT+S`THzM3Y_YnFQi}}r+@Zj`%WI3L0J;;KP6(LJP)`TnySrxJ@WL?O@kd+}z zL)L~Y4p|+tJY;>y0+AIWOGMU)EYj1hl3&g;k#!;qMOKO|)zhsNSuC<zWVy(Ckp&|w zMwX1M8Cf*4YGm2Sx{-w=D@T@&tliTs9$7uId}RGd0gwtHB|vI`6alFMQU;_BNFk6) zAf-TR;pvKjRKwGi1E~j65TqhVNsyW#MM0{9lm)2^QW&H%NNJGTAjLtd<LSzS)W_2m z2&oWKBBVx0k&r4OWkTwN6bh*nQYxfYNU@M=dAf2T_40HDLn?-p45=AXG^A=s*^s&+ zg+nTbln$vKQaq%3NcoWZdAb536+}vi)DS5mQbnYUNF9+vB9%l+iPRD)CQ?nLoJc)A xT|tqGdb*M#HARYwR23;JQdgv~`2VbIj0^9qY!aLv%+1Kp$Vv}pXJKY;%<s!{R2~2T diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Paris b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Paris deleted file mode 100644 index 7d366c6098c49ecd546e1cc1538919e1414a3aee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2962 zcmeIze{{`t9LMoHHk+Awk7lwlSu-^Iy@f1v&654XjfL4{hAe$8IU^c}Bjh-59Y<+o znE5rM8m7(fUvpwqN1~jR6a6~+bmZvAk-pDwe^jTxoc`#azW02;kMI4Sd(Qpm-sj6R zdP-4(>mNsJ`w1sUoqcj2KF_|aD9Fh!PcJp)7ox2-4J)j*haNX?F8R$`SJBf{6l^l< z=LMJzF>TGp*%_uXdA`{+F2bscOg5XN%FUMCZq`=cxn}E)Bx~FCe6#&Rj;TI5(Cj$1 z+0<-~Fgq)<tz9qsn75WpHE&y8t#?WmTeUgf*6ty(W>4%jYi~k^RoAA`s=K?-+V}l7 z>)nqEO#R0vOhe;dv%hYOIj}C@I{5lhbLb6Y4wn|2Ba`#Y(cCO^tiO+Symy>A(RY<O znOkk0ywtLyu{i3=>FYz~%+?TX+TfP6uO`X4?9Z>9Tk?Z>zofl<kTpPC)%S4)Y!5Z9 zD<^2+D;=fH!Zei`DH>E5rENVOv|Z*Pxi9e-4UYI$+qe5vLz<t_kedgz!_}R7|A!UY z@#qQ-ZP+hi)iu&-%{uA4OeK8IeCbkLA`gt6AYC&&645VB9*j<r$gn8s7SKVWeB2s! zD@nV58L2(ax7VJ>ef6Q*pESDiYwfl2lEy52Ph)2^Xk6hAjnBI%2_?0Xm|8DM!&gai zr?rxjP%0^R%A|MbO6`4ly!82XruN<MmPbCx)qYj^np)piA6+z1`<I95fT9Q;xUi2r zHrPkqg`qMi^17zE@5o@EQ<@&}nWW#iCPSJZmLW}z^2F7RGPGu!WSl;znah_+R`q(# zo;FQ#mMzd>qn7IM;)y!q;bQe<r0bI*SvoShhmO1*r@6s{CHF#Ged<<s8NKI69dq7a z##RJLUhQ`>uI#4duWXWn{PQw??l<~$|GhFH@3a<%ua=3aHCp7iTPJl=o%GdfI{8kC zPHCK_&s_HC)GcGQ_{4O1c5$jss~RECO%7LUQL;=Q)=x@`Lge}Q&N3tIXL%vWB{O4# zb*A}3N&|0e>A7Pv>&8W$y{k%IY^v8etB>g1nzj1UtV%6gUZ!3?&6?la%iFJoZwud+ z-Yxz8{96V5S1*^VS-kz%<m&Bm1&Ws+@A%LD{oWPia)ovA3jWKrBcJ*6IrkZv9#@Wi zj!GNB#p7~2r}M^s>~eW|{c$=s&Np%K^77n6O77an)KleWk)$A5akSHd<ON9#k{Kj5 zNN$kiAlX6EgX9NE5RxGzMM#d2BstnyLehlf2}u-^DI`@$u8?FQ*+SBV<O@j{k})J@ zNY0R?Ioer6(uU*>NgR?nBy~vckmMoRL(+%j4@n@BK_rDp4v{1}+F3->h~yDTB$7!a zl}Iif?PMa^MAFGGf_!q2P$Z*BN|Br*Nky`Xq!r04l2|0ONNSPXI@-xavWuh_$uE*% zB*RFGksKpQMzV~g8Obw}Xe84}s*zkH$#%4}jiejNH<EB9<4DSpoFhp`vW}!3$vcvG zB=bn>k=!H6ceJyQq~FobKQaNx3?Ng0%mFe9$Sfe!fXo9j5y(s+Q-RC{G8xEhAk*P! z&j&Igj`oZoQ-aJ1GAYQcAk%`(3o<dt%pg;P%ndR*$m}4~<7m$hGC_{^3?Wm5%n>q4 z$Sfh#gv=8%QOHaoQ-#bGGFixMA=8D-7cyav_KYD@hRhi<X~?W0(}v6&GI7YvAybFU z9Wr^y>><;K%pWp=j`j>9Q|M^VAu@@`EF#m0%p)?9$V}q@Q^|w|{+p@vw>Py{yxU&b T=*+~J<e0eV%=kErP4xdAFa5mr diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Podgorica b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Podgorica deleted file mode 100644 index 27de456f16ab549627b284a39e2265cbdb4ad8e9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1920 zcmdVaYfQ~?9LMqhL0H4S7@-o9T#oJ~DdMPHDwhrt$t4vMLdq?-nOU<hYs@g$HH>%= z9>mObA-Sy?W{kPcS{sI0<M;k=Hk(JD*!)lDyjrdG<oo`(Gv?)lS${mO%ujgptT1oB zZ@bQX+-w&4y!OplxqZw_>khf(&W;GVyCFdC9W0aksqxz7<tgp@;DC0!vR%E;Ul5-Y zmEya1zjQBC@msxKdgK>M&*^idSF&6DV-uveGfDz{0;NxzE)wYB(!kFV+V@p}_N(u# z{jass0aahsdE}iAEPt#)n{H|Fvhx~}eNsa+A4ynYm4wGtOT@&T66w27qQZ(Ls;N|> zy~{QF=`0!iy+~s&xMawabd9aZ(zxmv9lCkA4%_3S@j3oFeA8eVk?5hWY;PGE@J16{ zO_JzwLzDcUNm9dW8QuJnjIOJZF)t6x*vjLQTzgSdwv|chiGw<>pg_i#ZPW=<w(7+E zxtca8U){+`I>{?lCp-J;<S!wb-YHSiA9m2GpZiM2*-tvH-czO@XfK&nA7n=9N69L$ zlbKodGHcCyojvTF%*m|PY`@(yH?C51TA$HeU)9{VyELz<Q0LW@==`T{U2t@o=3ieT z3%A5+K}DJ@%Jb93n<Hh(gjgxe@sg#X-DO$AH(B1^lA_>FTGaSLiranB;=5O+q~VdS zJY6BH>Z*11?#sHSa-Xg(IijW8O4ZS#S#$g4(ehuuEURO*xhkujSS@~i`t)$LwyfVj z`E7EF+j1rFPIH?-a5(tlaX8$6al=2%Gb6Tf6mrYRJtH@b+%<CB$bBO>j@&u_nOjHh z9l3er?vdL^?jLCY=>TZ~=>cg1=>lm3=>us5>BQEwg7ktkgLH$mgY<(mgmi?og!F_o zg>;3qh4h6qhID3YT0?rXHO(R2A?+dkAq^rOA}u04B26M)B5fjlB8?)QBCR65+L~sO zZf#AwNWVzKNXJOaNY6;qNY_Z)NZ&}~NaslFNbk0$d8B(=(>~HavH{2rAX|X!0kR3m zE+E^0>;tk9$W9<zf$Rmc8OUzfn(aXL1KAK{N02Q+_5|4!WLJ=FLG}gN7-VOVtwHt% z*&JkdY|Zu{`(tZ12-zWIi;z7+HVN4!WSj7R-zQJATLVKGE@w)3P-IYuGbJ<xgTp<4 E0<)*Xw*UYD diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Prague b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Prague deleted file mode 100644 index ce8f433ece44f0b96b18d3b5780730e7f9cad9f5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2301 zcmc)Me@xVM9LMqRfyj?3d!GhJ^0SDLI{6KuL1rf~k~5XdNG1G%sCAKC#-KDTnRAWV zJ7YSBq!nY;jQRs>4XyQav=B|b>@3%oE7O{DGpE&9eV*T_(ei&kU+x~?@3FD5@p=y5 zl68&w*8fhF`GgnedGq4lx!JsRPjW5q4xYNWC)BS!y$AHA_f+?G?9!p=W*t5|PY%EC z(vep@a%4xL9DO!Jz6`|6v6Yc>d~=eXs5&MmUK~gZh6U1s)g|&()_|OJPm`~scS^{y zUP9+u#o3UlQ+x?J)jL;iDEM9D(tp<Yso$zA{II$%y{`#p-qIV7@6%}?zo3Z+4@uJg zeo5Z5S5i7vQa3&$Y5suRv}~2!T<w$e(sH@QT`U<%nR4r-1j&r>Xy)ZYo&H0HW(DK* zwofDV_JOPF?mee7x=v|!#}}Hj;h^R=ys3G0A;}L6NI}`46fW8+Maex<oZl+NqwP|X z*rg?>SIEpiT6ESSkKFl9t(NxHYuVr|y=&_no!y<JcQ>Z%oQ|1tPep`!8WLr0##t@* zj7mks=USQmom5`<QL4f}l&X;-x%bSgGOzy)sUH47z1urw{{ENszNRKw(78nyKJc6_ z@~_sKJN)XauGITo^L4R1OBY|s)!MiUsXaMGAG|zWmb~+;E)B-WvVBge8~8;YYQH4) zT_du*J}4_To!6DK-<4H$!`hI#TUM9#Yh%;_U6ZW3=BHh{b~K>thT8Pu(>{IVwWaF+ ztXUr2R;EpTHS*ZnR9(NdNSYUxN}$mtkLRVxhVtL!38y73IdR%@@q1~Fy`rs0KasWz zA${`gK6z?nP&e-WNH_KO=+kYz+P=MA!yIAZ6UJW=W6u*Kug7Isled|_W-BSpF~PE8 z#ftv#y=6HjkN>3F>$5!NHN5$(O7mcj!@-w*91h>LcVvDnKiWPzb|3erIVn{;uA=|Q zd0TeHGuuM;g=`Gj8L~BGZ^-75-67jU_J?c`*&(t;WRJ)uZOtx`ZQ7cBA{#|^ifk3x ztF75Aza6_pwu|f+*)XzWWXs5&ZOx{UT_f8@_Kj>D**UUxWber4k=-NPNA{020O<hI z0;C5>6KqWvkTxKFKpKH`0%--(3#1uHH;{H9{XiOmbOdP$(i5a9wx%mcTWn2Vkj5aL zL0W_K25An`9i%--e~<<t9YR`!^ayDZ(j}x#wx&-=qijv5kX9kRLYjqi3uzb9FQj2e z$B>pGJwuv?bPZ{nt?3)mI9t;>q;*K|kme!XL)wS*4{0FML8OI950NG!T}0Z5^bu*K zt?4AvN~D)aGm&m0?L_*CG!*G5(o&?SNK=unB5g(biZs^NbQWo?t?4b&T%@~5dy)Pk z4MsYQwAc}D+8Z(cnmG0x8Ff9be`0KsY+`JZZ2sGb73=Q+|9fwO>m2`GlDyy=SsveI bb01@hJtL2HyS)Y3McKJ-Z(c6u6vX@mfqZ3V diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Riga b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Riga deleted file mode 100644 index 8db477d01736445cafce8af7a7085d226d81f546..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2198 zcmeIydrXye9LMqBNhl)1uPr<fAS!avkUMGyi5-C%978w~sfZb%7Lm6cl)^J&W{t6L z#%iuiGDnvgwPv=4uFG7bL^}Vl*66a;ipH8dt(>zB>i2$>wbuHhtv~xcJJ0LkVQh@? zc?Z^SZ^|`)J2UMYKAd*@;W^c@w-?`gV(MsD&s5*R()PY{ol|d&|NQmPn+=;k-O^Y& zJYFv6U-Rn7F`s;PC|`n|DH7Btcf_Q<5}Y0TWwAG6tkV12%nxEGqJwc`zT#Vkp9#jF z?h7THcsi8$LT6}B_wG>AzJ}1;=5?WY8%sm;E0%_m3)4djGU7rh32`PhD$=Bd7dUAb zQ=Rnhz0ShX2xrmR%g(JQC!CDqW6t8<VJEZejFYuzz{zen>g3d&Gr9iLCa-8v@~fVe zg2W@TB)3(TOm@h!_+DLp#wWLr)oNjXy%r5F*E<fZ)D_PsXmL}ruI#!^?ko*gUqigC zN*UJ@-=vg=f1+i{-$>boA7u564`ubpklgj%%Thk@x>O9mul}BHS##ngy}PAFD!U)o zwf8)wRn3iBy|h^a6=k~4yGCm=7HZ9<Y^{wcmD<m5(t9ta%lcEl>W0xs+1NKr>Q4S7 zn>v1x`rZ-QTt6!J?Vr#sE8dm+>xQ)<>98~w4QNxuJGwPdb?cAM>9)yTx_zikANVSu z55BrVn?K$u4;?Jhmi}sacw3V0I8Y!v*A~jICa>(ynIn5jF3TgcjO@*d(Y>K>r8WAJ zwg%5i+l4Rm(YN~Lv5`UDclaaSKX63b+m35TPltN0vDb{S>%y<KS6IZA>-xy6*9}pB zy>5*DZ!cqJAG7~>+{27n@U|zyn1s0|%9usjMvRFTb2D!|vD5cu#h%3J?@m8^=Kc9o z)6W(DfT^;dit2zVDG3;Vb-D3beI@pVzj~E@X&>C<@fhQA&y}yQ-aVeczu3?3_SBp@ zzX{n9vL$3su69$%u8?gZ`$9H`><rl&vNvRNu6B3)l57vzAF@GLyF+A)$R3eRBD+Mk ziR=^ED6&&ztH@rF%_6%+wu|hS!-hHR*wt<s*)y_fWY@^Hk$oc@M|O^E9oajwc@Deh zuzh6zNCS`#xY`yVJwTd(bOC7t(g&mwNGFh1AiY4Efpi0D2htCuAxKADZA*}zxZ0*5 zT|wG{^aW`Q(ix;RNN<qlAl*UQgY*Y!5Yi!6+ajb#uC_@?myk9geL@<AbP8z|(krA{ zNVkx7A^k!chI9;R8PYRX+cczWNZXLUA&o;ihqMmq9nw6cdr13`{vi!SI*7Co>7lD_ zBGN@y+eW01NF$L>BCSMvi8K@c?<Ri*+suFHW~2@7;#>lo;m^w~$jr{l%kbx9yHEL% Fe*o7aBb5LE diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Rome b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Rome deleted file mode 100644 index ac4c16342b5bbfa4c58a26f57db33b95f5b3e533..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2641 zcmciDdrVe!9LMp8n;;^6(G=q%7MYlcAfRBPDFP!OEa6Gb8+b!4q9ZA3sc4xi$K1Cx zokJ5ZxiqC#m}_dS(nbTxFf1x3%S?;r&Sp*t(SGm47_<7@bM~Cq;W+>Ny+5AmiwlRl z{&V@8FZ{Unn;-8z*O*5|$_=Zcv95Xh$y$5I5m&+6uivtERz@^e7QAEcT79Ts_so&j z9(PzlO;NI4cWI)W+8?U*yVK>HH<RRa@ofFJq^~r%8|*V<67;+525F4EZk-*x)jr#@ zMt|tOMOqUN+pSF}n%g28thP_8?VC5Nt@dqO>{}O4+qYl-$a0<h(Ds`9mgT*Dy5%$e z1<Uu<QrmCHCc9hlCd<FaGCLq+lpWAA)eelCY6aG&+CjmoR?vIlcF$j%?cfdV_C2TC zEm<07g&aC>^~$?x_0E|f_a^?WeWF{mZ||Qq)aR6jUj0=2U3g#bJ5#A)U%sK?$Bs+H z!77Q|zEk>_t3<6_D+7v3<o=oS<N>!wqDN=QgRvuIV8kGKD5#$d@=Mo2*OD~m;y@kT z*jFDu>90eoZ)oh^-*xEbA2n`WtqxmyOylPt(u7$}GQ6Z(64Q=KQtlQ>j@%(5hA)>9 z?PZb@zFAYw&5_i$QXO?XT^{*qnvUL=uW3g|>6rE7bZkY0K3W*9<JP6h_)I@dpC2w0 z242#P^mfVg`&zT2&r8;o-z3}TbIGo+k;g9Vk%?6Y#9jB9=4>pNNe6f7<Hg1DMENT^ zdFlquEn1*?Ba77I&eA7CC+U>f!8+x7yiV(rDbv31rB7Xpk?9}*r861>WoBiF%&PuV zW|v)+{LS@Jkl!eCR{f!K#~zV+v+8ty)HYd=R;7gjhjn43>cY!gby0hXF0NUjPoMMX zGw;sOqOX?7v#+IT@xDBHZc&t4>yu^4<k3=67%I;v^p~X>t+Fh{C8fjqXsP{+EDye} z%TJ$>6<3<{#Siw$OZ7)}<+d+$Rn-n%y<)GHZ7fr7uddt2*W6y-Jk8x{$6t3m{kq-# z+vVy}ZO)S`Vt|*g%M~oH?w!w$FJ0f=IUZMfMjj6j|HI2%XkI-3e|iJVKl0-`V1B%Z z+&0&kn9FXoj;*zj)9h$YG;*qulZ~8i<b)%q969O8X-7^xa_W(jkDPv_07wOp5+F4| zihxuBDFadmq!5m#5=beKS~!|wAk}a*<v{9z6a<}$@IpzrOih5IAXP!ig46{m3{n}S zG)Qe6O>vOwIGXYx^>H)>LMnum2&oZLB&146nUFdmg+eNYlnSYpqbU|rEu>sXy^w+- z6+=pf)C?&aQZ=M(NZpXaA(cZ)htv)!o};NAQa+@9NCA-wA|*s>h!hd2B2q@Ajz}Sq zN+P91YKaun(Nq&Dr=zJSQc$F#NJ){JB1J{2ij)<pD^ggbvPfx>+9Jh8s*9A@(bN|y zu%oFkQevdWNRg2$BV|VFj1(HFG*W7$)=06DY9r-#H1$Rb?r18GlpLu!Qgo#1NZFCP zBZWsQkCYy%JyLw6`bhba`XdYAXjTAO0%Q%4ML<>oSq5YskcB{20$B=VEs(`PRs&fM zWId1taWpG}EQzC86J$}4RY8^oSr=qskd;A}#>>aM>-P0Cx3>>Zb9dVD*B#Gp{&)ZG zoEkGYW@^l^m^}y<SI^F8$Cs|}3{LL9MyG3a%v+#YqM-?FQfy9QTyk7|Y)(Qv4oeLD E2jBk!N&o-= diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Samara b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Samara deleted file mode 100644 index 97d5dd9e6ed7fc924c9bcb514f991cc8b52061b3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1215 zcmdVYPe_wt9Ki8sx_@jDUTVuf{WDvey4KvrtZ6gTVQnBWIz+((WzZjJh=&fr1T6?6 zLLw-Nkfc+H2RoUxL(s)`kZwcxL3D|T5p^hu^?cvir6B0o^X}pE?B(T!?f1=}x^O<K z{#agfhs_!=n{(5w>YaQ(=N;V=xL?}pFGqatH)-E@+k*dtDs8L8Bh4$<OD!*Er1ja9 zv^|`V?YG8c$F-BP^KwRZoleT`Y*5-$&9bM<D;=$#>R#`9HQ)#o0$=@weeZpfLG@Y% z-+t7gS8KX+v8=o1Uh3|<3pzYKtM^aL=*YP#ec;TzM8|JRPv0Ghowy|NwsA>BbCURx zmt@ODom@*u?|N1rT=vVMN?50!#&zFPlkUIa(}y2?*6FctdSH6992u(U!LwC4+Oe#M z23KX+@mOct7bWv)Nk$s)$w>K;9D8?Fj?Wh*yYi%vyM3ivtkr6^hQ|73cWhivm(%5T zHT?SeH=QoKU8(RF^Jl71M459kt=vitkJ>i<ezuwW^=Cp6oAo4jcs`rUtIkM|*)g-@ zO4-b(zBq2I{67rV{H_|qMFz|(7&0<wWZ0Hw;K<OC!6U;*0ze`_LO^0bf<U4`!a(9c z0zo1{LP26dg0VEwAmJeKSek&4h>(zwn2?~5sF1LbxD1NGkjRkGkl2vmkmxK;cu0Jf zCO{-YBt#@eBuFGmBupeuBv2$$Bvd3;Bv>R`BwQq3OA{~>v84$ai5UqRi5dwTi)Qx! OP28T8iNC))=J^Tns}05g diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/San_Marino b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/San_Marino deleted file mode 100644 index ac4c16342b5bbfa4c58a26f57db33b95f5b3e533..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2641 zcmciDdrVe!9LMp8n;;^6(G=q%7MYlcAfRBPDFP!OEa6Gb8+b!4q9ZA3sc4xi$K1Cx zokJ5ZxiqC#m}_dS(nbTxFf1x3%S?;r&Sp*t(SGm47_<7@bM~Cq;W+>Ny+5AmiwlRl z{&V@8FZ{Unn;-8z*O*5|$_=Zcv95Xh$y$5I5m&+6uivtERz@^e7QAEcT79Ts_so&j z9(PzlO;NI4cWI)W+8?U*yVK>HH<RRa@ofFJq^~r%8|*V<67;+525F4EZk-*x)jr#@ zMt|tOMOqUN+pSF}n%g28thP_8?VC5Nt@dqO>{}O4+qYl-$a0<h(Ds`9mgT*Dy5%$e z1<Uu<QrmCHCc9hlCd<FaGCLq+lpWAA)eelCY6aG&+CjmoR?vIlcF$j%?cfdV_C2TC zEm<07g&aC>^~$?x_0E|f_a^?WeWF{mZ||Qq)aR6jUj0=2U3g#bJ5#A)U%sK?$Bs+H z!77Q|zEk>_t3<6_D+7v3<o=oS<N>!wqDN=QgRvuIV8kGKD5#$d@=Mo2*OD~m;y@kT z*jFDu>90eoZ)oh^-*xEbA2n`WtqxmyOylPt(u7$}GQ6Z(64Q=KQtlQ>j@%(5hA)>9 z?PZb@zFAYw&5_i$QXO?XT^{*qnvUL=uW3g|>6rE7bZkY0K3W*9<JP6h_)I@dpC2w0 z242#P^mfVg`&zT2&r8;o-z3}TbIGo+k;g9Vk%?6Y#9jB9=4>pNNe6f7<Hg1DMENT^ zdFlquEn1*?Ba77I&eA7CC+U>f!8+x7yiV(rDbv31rB7Xpk?9}*r861>WoBiF%&PuV zW|v)+{LS@Jkl!eCR{f!K#~zV+v+8ty)HYd=R;7gjhjn43>cY!gby0hXF0NUjPoMMX zGw;sOqOX?7v#+IT@xDBHZc&t4>yu^4<k3=67%I;v^p~X>t+Fh{C8fjqXsP{+EDye} z%TJ$>6<3<{#Siw$OZ7)}<+d+$Rn-n%y<)GHZ7fr7uddt2*W6y-Jk8x{$6t3m{kq-# z+vVy}ZO)S`Vt|*g%M~oH?w!w$FJ0f=IUZMfMjj6j|HI2%XkI-3e|iJVKl0-`V1B%Z z+&0&kn9FXoj;*zj)9h$YG;*qulZ~8i<b)%q969O8X-7^xa_W(jkDPv_07wOp5+F4| zihxuBDFadmq!5m#5=beKS~!|wAk}a*<v{9z6a<}$@IpzrOih5IAXP!ig46{m3{n}S zG)Qe6O>vOwIGXYx^>H)>LMnum2&oZLB&146nUFdmg+eNYlnSYpqbU|rEu>sXy^w+- z6+=pf)C?&aQZ=M(NZpXaA(cZ)htv)!o};NAQa+@9NCA-wA|*s>h!hd2B2q@Ajz}Sq zN+P91YKaun(Nq&Dr=zJSQc$F#NJ){JB1J{2ij)<pD^ggbvPfx>+9Jh8s*9A@(bN|y zu%oFkQevdWNRg2$BV|VFj1(HFG*W7$)=06DY9r-#H1$Rb?r18GlpLu!Qgo#1NZFCP zBZWsQkCYy%JyLw6`bhba`XdYAXjTAO0%Q%4ML<>oSq5YskcB{20$B=VEs(`PRs&fM zWId1taWpG}EQzC86J$}4RY8^oSr=qskd;A}#>>aM>-P0Cx3>>Zb9dVD*B#Gp{&)ZG zoEkGYW@^l^m^}y<SI^F8$Cs|}3{LL9MyG3a%v+#YqM-?FQfy9QTyk7|Y)(Qv4oeLD E2jBk!N&o-= diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Sarajevo b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Sarajevo deleted file mode 100644 index 27de456f16ab549627b284a39e2265cbdb4ad8e9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1920 zcmdVaYfQ~?9LMqhL0H4S7@-o9T#oJ~DdMPHDwhrt$t4vMLdq?-nOU<hYs@g$HH>%= z9>mObA-Sy?W{kPcS{sI0<M;k=Hk(JD*!)lDyjrdG<oo`(Gv?)lS${mO%ujgptT1oB zZ@bQX+-w&4y!OplxqZw_>khf(&W;GVyCFdC9W0aksqxz7<tgp@;DC0!vR%E;Ul5-Y zmEya1zjQBC@msxKdgK>M&*^idSF&6DV-uveGfDz{0;NxzE)wYB(!kFV+V@p}_N(u# z{jass0aahsdE}iAEPt#)n{H|Fvhx~}eNsa+A4ynYm4wGtOT@&T66w27qQZ(Ls;N|> zy~{QF=`0!iy+~s&xMawabd9aZ(zxmv9lCkA4%_3S@j3oFeA8eVk?5hWY;PGE@J16{ zO_JzwLzDcUNm9dW8QuJnjIOJZF)t6x*vjLQTzgSdwv|chiGw<>pg_i#ZPW=<w(7+E zxtca8U){+`I>{?lCp-J;<S!wb-YHSiA9m2GpZiM2*-tvH-czO@XfK&nA7n=9N69L$ zlbKodGHcCyojvTF%*m|PY`@(yH?C51TA$HeU)9{VyELz<Q0LW@==`T{U2t@o=3ieT z3%A5+K}DJ@%Jb93n<Hh(gjgxe@sg#X-DO$AH(B1^lA_>FTGaSLiranB;=5O+q~VdS zJY6BH>Z*11?#sHSa-Xg(IijW8O4ZS#S#$g4(ehuuEURO*xhkujSS@~i`t)$LwyfVj z`E7EF+j1rFPIH?-a5(tlaX8$6al=2%Gb6Tf6mrYRJtH@b+%<CB$bBO>j@&u_nOjHh z9l3er?vdL^?jLCY=>TZ~=>cg1=>lm3=>us5>BQEwg7ktkgLH$mgY<(mgmi?og!F_o zg>;3qh4h6qhID3YT0?rXHO(R2A?+dkAq^rOA}u04B26M)B5fjlB8?)QBCR65+L~sO zZf#AwNWVzKNXJOaNY6;qNY_Z)NZ&}~NaslFNbk0$d8B(=(>~HavH{2rAX|X!0kR3m zE+E^0>;tk9$W9<zf$Rmc8OUzfn(aXL1KAK{N02Q+_5|4!WLJ=FLG}gN7-VOVtwHt% z*&JkdY|Zu{`(tZ12-zWIi;z7+HVN4!WSj7R-zQJATLVKGE@w)3P-IYuGbJ<xgTp<4 E0<)*Xw*UYD diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Saratov b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Saratov deleted file mode 100644 index 8fd5f6d4b881457d13fdcdd35abb6fc5429d7084..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1183 zcmd7QO-R#W9Ki8sxiy;|x|B0Fd$GB6T5E1HYuaqSV9k&i5mq3*2tm+~@K6vaWS%N0 zf`}rDMwea>b;@K!mq<Nzv)~V%dLe$7E=jHD`xj3gqFc{@&;Rr1*%)lUZ(-=fNW%QF zR@f6ZtIKYlSKT%3<Ijs#gR7%AN^631@#@OiZ1oS%)8J=Qs+mv4*Unrh)lOY?LJ!Y7 z;aj6l-Nob1x^w%T^(XtB4TsXs#(bkwpV_RNnrk!?3TQ*sf<}E&iGB}C<GZiJO|QR5 z?Ad#1F3w8JwQ1Qh@kF+c-jVpRE3)nIlqODJ*Vc~Pn%s9*Q{i!KOB~d;pGP!Zdq&b9 zy0v{_NVdOh&>iy`$=uIL$BR1YoQ%lMn?|xDe(9PB>8_qnk~{iKyCZL<C+BFd?~(M? zztX;MZ?wOnsQq&fboa+e-Sha8=4bB7z~xg~$cKjy<o3!~xm@;CEL*(1KKEMg=khM{ zx4YNx^%@g%|L>-_vCqAOo=RiVS+jEKzI5WTCySrq-TXko#Nw@Xr|eD|<FPLm5AG`b z!yxVNC^JlCpnL&CMFxuu*VPUf88R|xWZ1~Sk)b1lM~06CfJA_VfW&|Vfkc6Xfy99X z;%Xy7LP26df<dA|!a?Fe0zx7}LPBCff<mG~!b0M5wSgg#x!TZ>*pT3m=#cP`_>cgR z2$2wx7?B{6D3LIcIFUe+NL_8HNUW|lSR`5`TqIs3U?gHBWE``z|8HXsWNhS}Ey=)d D1dR{C diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Simferopol b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Simferopol deleted file mode 100644 index 432e8315bc9dfa74080467f9e08073d9fdcc833a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1453 zcmd_pOGs2v0Eh82I#c6hdKQ&V&ZKGfFf~)t(X_6Oqu7i!In#saF@YI@xTuI0K~mNt zG)^ULD$)`oktnD(7Cn$CGMz;`i-aH{BJMH@sq<aYO^ayVz1;a-k0>JFKf3#HOR@Ol zO4TPkTtWTtp53lL2HbsF5BuD)H}<ah$YfByy_2R!Z~EofrBXR|!#A;T#qIc_^!G-Z zb3B~(BlTJOmz21B+;1!%xg5`U++%tMFPh$Kr_CjuN6pNW&1P2Xc5~^TIx{;|Zst_2 zG?(SO&0LSmT;5e^u6p-1mNz^WUj1M+mfv?jT+n?lR`B9wys+b}vF2DuxTyJ%v374y zy!c4JD5)NjrA=4lI`4H^R(wL1O`VdyjBe%oa6nf4JgzFA_~rWXU8<^ozp5UpR2$CK zsEt=W%4o?^H60alQ=LQkn=@o>?xYI%r(~VuwW`ngDC@s{mJNx|Wy9zzx%tyA8N53n zLnBXB<AqMSWw2LmZEKU^&NFJ;&hx6N^`MHB?`w~SyfIrs;vBof?ns<FeLIt8?*tb& z=Sj|a$$z`&JB7&nuK)8Qb3)jK@MH;nl2;^>g-DS?a$;LB^XW5e?wRk-yxY8-@Hzdn zK7*g-H-s9aBBGx_ASxOoLE+c>0};Nc)rb0p%Vx74jeeQEIF0^8Jiqj{<I%7ai3kY^ zi3te`i3$k|iOW(4#vedrNN7lGmO3~jIwU+KJ|sXSLL@{aMkGiiN+e7qP9#tyQY2I) zRwP&?S|nT~UL;^k9WfFz5;GDs5;YPw7jYwjBatJaTk6=6;4O9ZNcc$n$N-QLAVWaL zfD8f|1u_g|9LPYBksw1s#)1sSQjZ21j-?(CG9Y9`$dHgRA%j9jg$xTB7cwwpWcc3< L&862_P~!RxK#57i diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Skopje b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Skopje deleted file mode 100644 index 27de456f16ab549627b284a39e2265cbdb4ad8e9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1920 zcmdVaYfQ~?9LMqhL0H4S7@-o9T#oJ~DdMPHDwhrt$t4vMLdq?-nOU<hYs@g$HH>%= z9>mObA-Sy?W{kPcS{sI0<M;k=Hk(JD*!)lDyjrdG<oo`(Gv?)lS${mO%ujgptT1oB zZ@bQX+-w&4y!OplxqZw_>khf(&W;GVyCFdC9W0aksqxz7<tgp@;DC0!vR%E;Ul5-Y zmEya1zjQBC@msxKdgK>M&*^idSF&6DV-uveGfDz{0;NxzE)wYB(!kFV+V@p}_N(u# z{jass0aahsdE}iAEPt#)n{H|Fvhx~}eNsa+A4ynYm4wGtOT@&T66w27qQZ(Ls;N|> zy~{QF=`0!iy+~s&xMawabd9aZ(zxmv9lCkA4%_3S@j3oFeA8eVk?5hWY;PGE@J16{ zO_JzwLzDcUNm9dW8QuJnjIOJZF)t6x*vjLQTzgSdwv|chiGw<>pg_i#ZPW=<w(7+E zxtca8U){+`I>{?lCp-J;<S!wb-YHSiA9m2GpZiM2*-tvH-czO@XfK&nA7n=9N69L$ zlbKodGHcCyojvTF%*m|PY`@(yH?C51TA$HeU)9{VyELz<Q0LW@==`T{U2t@o=3ieT z3%A5+K}DJ@%Jb93n<Hh(gjgxe@sg#X-DO$AH(B1^lA_>FTGaSLiranB;=5O+q~VdS zJY6BH>Z*11?#sHSa-Xg(IijW8O4ZS#S#$g4(ehuuEURO*xhkujSS@~i`t)$LwyfVj z`E7EF+j1rFPIH?-a5(tlaX8$6al=2%Gb6Tf6mrYRJtH@b+%<CB$bBO>j@&u_nOjHh z9l3er?vdL^?jLCY=>TZ~=>cg1=>lm3=>us5>BQEwg7ktkgLH$mgY<(mgmi?og!F_o zg>;3qh4h6qhID3YT0?rXHO(R2A?+dkAq^rOA}u04B26M)B5fjlB8?)QBCR65+L~sO zZf#AwNWVzKNXJOaNY6;qNY_Z)NZ&}~NaslFNbk0$d8B(=(>~HavH{2rAX|X!0kR3m zE+E^0>;tk9$W9<zf$Rmc8OUzfn(aXL1KAK{N02Q+_5|4!WLJ=FLG}gN7-VOVtwHt% z*&JkdY|Zu{`(tZ12-zWIi;z7+HVN4!WSj7R-zQJATLVKGE@w)3P-IYuGbJ<xgTp<4 E0<)*Xw*UYD diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Sofia b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Sofia deleted file mode 100644 index 0e4d879332d21c93c229fc25587205020eeb3127..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2077 zcmb`He@xV69Dv^wP`nuXpdl(C7?5ZuzwuWP837}~PC1BF;!H#=B0ZHsirmyW*O>c6 ztmev1%du*XXfykRT0eBnHaf1AYpq-?TDGRvX3n+7>V3Yz+Nl2X^YVV5_ulV~zwUW_ zn|3zmnSae}d&6eB?B+Z#XdlB@*U9H^CTQrjQW@zjkno`l`67^>8n^9N@0{9_(Ye)k zh3_t0JR0x09-cS%qg@FxBjJRbgTeV@r-KW=><uowa5$Lw{@W($>?xD{>I-I3&mog? zV2?>{Z8D3u)S7#$%1v6)N|Wx%G#N<?%)K#gvm~l8xa5}GpZVi;@6xZX`IlWB@!oeX z<oBF;$Gg05(4TeWMQ`@rUVl#0K5uTrz-V4ze>lH*ND4N-B!$T*Wkp_xtQhZ>Rf&DN z>dIDG{b#$b`Jhzp|F&L>`Wv-)XpKH_bgh=WlB5qdr|H@wtL35cC@pPDl!r5}YFX*H zlt+E06=~l~#f_h&GU8*Y3|*2(#$K0o18+&y@P}G`yhqlbJ*|(nwTZXqux@zldEMB$ zU29ghs;{a-YZKOMooA`m-Okba_;RWLdX7GRD^oU||6Mm<cFUGianf+^nmo~cQyTk1 z;%~exTf2VICrjRwZ4JZPlyXA07Y}H2^t-wvS#`(HFKf$qKzCm1)Tgfa^yxP?YwM@G z<(Xr}+SXqq&$guKuA_yrdqa@~niFJC?jqS+_J{0?Gt!<NukFA6ARV!{wIh5{I&XZV z&kgp={?L#fIPr;g4V=`2ooBTBc(=M{MA+quoLEsar>)6*=k2WMJH3pF|IYsAOj4?e zG$vL|G-p?gG0SpXaZ~pb=YMXhs(q%c%x6lSUBd_aFvjJwfA%pkE|>4WfBJ6wp3NMz zoAbiI?9`nPrNh95vH1`cAUZ&lfM@|x1EPoh9|lDrnm|;6=mJp&q76hHhgKhmLJ*B0 zDnWE&P>Mk-2DKRUVo;1hGX~WdbYoDCK|2QZ81!>!6@+LAQ4yjeL`jI25H%rsLKKB) z3Q-lJD@0j{wh(n8`Z}}<Lo{}1RfgycQ5vE(L~V%P5XB*yLsW<84pAPWJw$zo{*VMf zGT_jr0FncTHVKd{K+*uo10)fUOh8fr$ps`CkZeHG0m%m>A&`tXv?+n)#Gy?JBrA}# zK=J}f3?ws<)If3rNe(1Ckn}+E14$4hLy#0fa^%n^36dp9njm?CBnpx#NU9*Yf+P!) zEl9c``GO=2k}*iiAUShrlLpC}Lz^~8-XMvCWDb%#NbVrXgOk~djEIbw5jC-9&YHF+ z@13{Nv+wkp>Rw_C-Lv(x-HR1tyJzbsPW|Gi?rrz%dE&`8sbA&)6mVJs?MJr_<?=iN V>8Z}oD$L5s&i7R3<~XMU_umlP+nN9X diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Stockholm b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Stockholm deleted file mode 100644 index f3e0c7f0f25f0a7290e56281c91190e3611498a7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1909 zcmciCYfQ~?9LMqhQ3q?ZZ%F8dB$uPBax1r^8ai$r<dR&HTS7<?G0n`HeQk|d3}elV zcn}`sGS@LQo1K~4Y|P!vhPkcrd;c3A@Yrep|EryP_<eu8(-##aT7P|<<{KV9Ys|y% zZ8w@%O+?k~8sGi*?LDKUL((@5j(VdV+dtG0zgrse;hc7QdR#l-*{@wL?a<IOXC>@t zorLe%ClOUDk>#7DYhkf;n>kOqXL%(mHC=kRQY1PoMtZjCBr#66#(e6py`DvDZ(m34 zbETE`t^cB~L$9=7^?i-4yrFTc&S-r8F-^$5CyB-Nl9bjU{U_~|<nX<cl2|G!O%*aQ zv|0x~nj?e0m+0WLZW;0*M^kI_G_7H<4&5?Bht-7X@Pa5EQ8`FPW;oTIA1b4wUue3! zNiv+*H8bk5WWIYYqx~+(=*DX@=IKEhTX#gVZk|`q_9_{7^ni{pDv}9Rn|0#UZ91uN zzGe?7RBu+MP7WETQ(V1u%IA2^3C@t5yX|z^r(QDs)JL7+3y_)ngCw{9t<0+UAbHh| zGCR*FbJoAsxx-G&yxg0bAGurRr`2ge>yx@5Ty??AUAnNTSQlL@)5VXxy5#T-Exfuy zmTpbcqS|a(wlGqcZ%LLF6H}$QAVgLsM98Z2ud+JGl9IS!EqVV$N&`P@>Fvu>_U@jp zJy9#`8XL5H_eEV_w^uim9ny;J73yf=@bmxwKb9qL%~e@}V)<KESXW2uUvIw2@^~$G zI#0Hj|8h9&m-pW{+tU1zhfk?__&w-{`FMT%s<C|X%DKo5+nPJ(pSfk^o{^hI?i#sm zTXWyYjU#uC+&Xga$ju{nkK8_T|40K!2S^J@4@eV87f2gOAGW3uq!XkSq!*+aq#L9i zq#vXqq$8vyq$i{)q${K?q%T|37}A-oX$|QOX%6WQX%FcSX%OiUX%XoWX%guYX%p!a zX%y+y*0hTBYHONBx<%SW`b8Q>I!0PXdPbT?x<=YY`bHW@I=3~gBfZ<2=8^7^_L2UP z4M27P*#cw_kWD~#0oev*ACQeeb^_T7WG`&ZW+1zPYzML*$c7+0f@}%0C&;ECyMk;B zvM<QSAUlI>4YD`3W^<6;u{GO+><_X*$POV}gzOQrN!Ywgel7f+|NrOrFhwv-fnqfe sQyY7p%$skRr)+zk{!CQ!Mwxej8LoZ_ESJlZ6q_6y@A4$XV_Z_ePe)m?eE<Le diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Tallinn b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Tallinn deleted file mode 100644 index b5acca3cf51e7f7b3176965748688ff41720246f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2148 zcmeIye@xVM9LMp`foInx=Z7{ri8~=lK|SF3rPd(P6PR&lC@1-g=m(+}p#nKbjqi#% z*O<L4Hs&gS6r&$A<{xTn*7`B$C@;EySZmaBwX(71zFRqG8>`RrTlbgikGB5o^WFFR z`0kDk{^0eDZ`sverfxcO%_rQP{pRL<fn^@YHWww1y)SZnU|3G7rF%xYcSpxhpS}F~ z#o@-pl?MIA+kTmNJ)*ySsX`}vE?v$lcr$s&yl-m!o~cIv?{hz%H|<MiPep3(OuU@T z`QU^dIQ60(eDzs-{$RJAd!WtE>)2@DwXM!x5M6HPR~6cKhqCR3fo!#Cj#m}9E3JZS zi>$&Q{np}1kG15&4QuI{X)81`Wfcu2tm1(Wt&*NGE8KS6Ds8!>%DP5XdG))hV#8ro z8GJ!4E9=$EX8QGtoFS<iZI$Zt_sV^TR>{g&0#ehSFRKRb(W~p+5^2lPYZhLS+Q^Kq zbAKlF`QPdKt3T<r>7VGe6XW{+AKuUnWAEr_;v<P28Pw}eos<VUJ9XpWbF%)y=Ve33 zc4=DPA@OLvZ1k^_=Fnnkz8;oMS#^5TSGUXNYlV8tx!+{#q*re{k*QnG{GuP~|5djR zP3VVPC-ox-r{&R=@9D={64I7?RBx{ylXlNp*%1`k@$<0koavHX<9+h@w{dymt*z2= zaj$;zaJ6)fHtF3vb7jw=O1*b|mF{Zy>+aI|x~KMrekxPxeI;44&;DNb`mRfF@`CQW z`n5cLdQ|V9I4=i|ekupYUXy3~Mx_5pzqn?lrMuj-Z%I!}Pn+%e>$=tZ_jTKxo30F> z+n4d*TuS*X%zqlsSxN=+Tpp!-T4ki3fjpI|)RM5uN`1Sc#+9A=B=znJ@-07^`gvC{ z8jGvAxg)hrJmRX>+_9zxbFVS)=0l}iE`GOx<GiLGE?4|tjO7n=n$IN?$Y>nRaFFpJ z142fG3<((%GALwJ$gq%cAp_&DV`RwCkg++M!6BnVhKGy~86Yx3WQfQZkwGG(M23ls z6B#HnQe>zc#>!!^j%KvTaFOvM14c%S3>g_SGH7Jf$gq)da~L>>k#iV2hp}@QyrUUC zGJItGNC1!sAR$0vfCK@F0ulx!4oD!7NFbqbG_gQ};b@|Pgae5O5)dRJNJx;FAVEQ* zf`kQ$3lbP4GDv6~O>B_hIGX4n;X&eq1PF-`5+Wo<NRW^yAz?z|gaitS6cQ>VR!FcM zO|+13A@M>2hC~br84@!jXh_tMupx0n0*6En2^|tUBzTS{dPw*jP5h7mA`wJFh{O;H kA`(UXKaBqnMz0BJQ5gjd#mb8-i^C=5p;&3yd8_dL31K4)Bme*a diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Tirane b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Tirane deleted file mode 100644 index 0b86017d243f1b7bbb41d6b4feefcb2b7edfc7d8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2084 zcmdVaZ%kEn9LMoPdKbGQeZlZ%fLMs2U4hF#MM1M0pb46CRs4e-6A=^XK*Yd5v6fkD z%zYo+S+1PA98;&{8vSwTtfmepGS|kMI?L6{XpQbx&YZIRz0V^z*Mpw4b<WOxo!#Bt zN59WIv}#jbj`h&xG2ifTy=5NW$L=|rSKqhgZKwa{Lb-Irr<cAM(&&uBNc8V>Y_F#+ z;=SB-W6aQEC#Gk<J@%W;k=XDw`>_-E9BGNM<McZxzH-<e=X~irKKrDdF#n`8e%vRv zFEAMK-5a<u!3sMQuGQF2_J15nJat-<j&)1&hx=t>r%KB9H)K*nvpltCy*ynWlGLIS znd~o+w4`*I67z(ldxDyND^D|iO4F%><8|7(NA;PWztn$dNT-LdYUa+1n$>bjvulrQ zp!$mBH1|kuaj)bp-6Q$Q`=lVJO$tUjWM*PmXI@_?g?C$Z*6E<kzE-70T{T+VJ4@&6 znx}I=NYZEPQgz<WLV2##qruulc|Pr?mIOzn)N?`0Qoon7;h$x}sIO$fK%czu<43Zv z`>2%npV5llowDfIL0#O~C@*%tsY_P8t4kX;XyuFs4V9PaGT$Oy?w_j5Z)a;&La9`J z8?P&GWyq?}{?yfjURiS>PO5u;leHaxNKJS^?3zJYx8qlRY3}E;zPev)Q})V+;%=>r z{!}+6t8V<|J*^*U)=how`ttRVZa%zP8_qY$mUoJ^v8z&EsZUX7SH3hYDU#+opS&8F zC@m#-<h3|UTC)<gHS&YB#opGo%V(v1_=;{l(IwjkdUgBWuXRWFK7GCYkaq0u(5OfL z=^i!uKf5g}{(VkrtXQKhD``?x^n>r^6(K8F!c!UIS5Z;!N9bRi{J+h`=|>iTtN>Yp zt62ko&mvsSDv)Kknsp!xK~{n+1z8KS7-Tiba**{P3qn?eED2c?vM5)xDr8x%W?jg_ zkd+}zL)L~Y4p|+tJY;>y0+AIWOGMU)ED~9zt63(pPGq6TN|B`^Yeg1|tQJ`=vR-7t z$cm9ABWp$$jjY<$EE`$3t64a*a%Abq+L6U0t4EfPtRE==QURm{NDYu8AXPxhfYia& z6auM)t0@Ii3#1rGHIQ;3^*{=OR0JsrQWK;oNL7%sAa!vyg+VIgYD$CD1}P3w9i%)+ zeUJhn6+%jc)CegOQYEBJNS%;EA(e79r9x_j6bq>qQZA%kNWqYbAtgg<h7=8{8d5f- zZb;#f%DI}-A+>Wg#Y3uxln<#NQb44FND1-(T|=)a<n#cE^jG9&=4WR6D+1Y=mFv9^ D;y&Xi diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Tiraspol b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Tiraspol deleted file mode 100644 index 5ee23fe0e59f044598675db44d53c20590b88934..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2390 zcmeIye@xVM9LMqZ#jg{Q&Nbq<8YYmQ{1n9!J;lQm&_fW(1g|7SK?@bb1pUl8M)PN4 z&59LkO=VMti%|+1l_@KNtFcu>>$^4kJ^ik7w#?P%`6brc`lJ5nzh1YyCwzBv&iQ^6 zty*7^CVxA}A5Zt|@^ie>A1_tC9P)a{NA@#wfApTY-r_y``F?Nr;7)H(Uz>66jTemb zC-xd|9<4Wen>HG6)s-1<S1vQ&DRCJW9!xdf&5ScHCf;RSitso3dYZlOJ=x&t|0>t< zL0kBtfmgB}gNJ80d`k~`!xE1B?vA+Z3bzk?!hgB5H{#n+U*vGME2_WQ7v0lp#+-b{ zjBVL%PT04_oLFCOPO4sE-m^N#jLVy4PM(u!-s_Asr^E!C@ndh9@!5GsLO_N}xDl@s zuZFAphQ9Ysy)fvR);ZvHzIxg-{YZy5X-~5!dFx?sN_nj(wY1$x+q}b<o^?uQEN_yG z*n=`NZG+6bT_c&%jVkj>q0GKjsqR0QArA~MQFD$JsH|?Mn%kJJ=DirIToqwz{+?;F zz<pC?myeT$Q$AJh?CX*f(5)6t{!kWO`$QJ|y(WtX&dQQ6o|WA87Rl>Bt@01-l%*$| z)v`@q@$9Qr1uN^-^6HhUa8{Wr%A2iLgu7I+Gg=kjj8i3HnNsqxzk29Kl&tFdQawEM ztE_JIlhV%5q-@t!S#zXUylXDWBMq0;qx0HiZRvScK5?%+mer~%?8nu**xhQ~*H5d; z+vRF~UzOT$B}Y}A$XC@D*UHAGWVPv-TOO|*ubya3keY%d*<3M3wxl{_tNS~tb^IXP zl7rMXb4cn!zfpC*F4=zVef3nwQQ0wYO4UE#sT$f3s-4@PQ@ak-DBB$Ye*S-b1&#@_ z2ieC4kGw+0{rL*i-wX`+?_MI&cKv@?qJ9#8k%&6czfDcCg^0vVlJTRTBTqsd62=o- z<mhLn%Qk`UOWf$^=#$YuAuqp3vh{m`e!Ja;eCP+(TmO<@xKO`y`3u-=BX8@6qJMFM zzv&fs_5DmaManr+PSUDAOUh|d&XaPYlryEAD&<@$Crde7%IQ+hmvX|CGp3v}<(w%e zO*w1IX;aRda^jRTr<^+f7@Rxh<SA!wRi8fP{3!%b7@$x<;ebK{g#`)?6dou<P?(@l zLE(Zz289i)nhpvdRy83MMktg}IH8b2VTD2qg%=7j6lN&YP`IIx!(fL&4}%}8nji*4 zRy9QojwmECSfbEG;fX>Ng((VE6s{O#QP^V8Md6D<7=<ybnlc7wRyAo1))=%gc%u-< zV2(l^gF6a&6!s|eQTU?}NMX>brjWv+RZSv=MFx!&9vMV3m}F4N;F3WmgG~yZ3_dA@ zG8m;$O5xP1CY8b}g;ol$6k;jNGN`3+%OID+E`weMzYKyI3^OQZaBNkR%wXB7rkTMr qg=hxT6sjp)Q^=<Ov;B|Q4%XkAo(A*I{Pd)Zq!ed<Y6?wG5B?oV8;IQi diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Ulyanovsk b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Ulyanovsk deleted file mode 100644 index 7b61bdc522b5b7f4397fdb9246185f4d972f4b6c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1267 zcmdVZPe{{I0KoD0%gwE=LkDY1H?wT6O;^9>CbOokrVeX@#PDDR(jOrRdV~jqz(MAz zf+C10qG)vK@1agvj_4Apr*0PfAUaeK?-GGh>wSOIQ<pmSetW;qkH=%M-}|mGd}1^% z{upcY3X_r5ljpiSqO<s{<Q-fWzFuDMpErH(xr}eoc;f#e${QAvX8r8>a>Mi$EAZf) z6}&lSHC{MwZ9F?<HJ!{^n+~O{&H0GcoUXUFw0W&iz@u8cODgOP%kX!<-1^B^jEv6| zBkvYv^z~QS`t-eQE6vH+)t7SH<YT#g?6x$IU6wlzPpkOpYpT8LmP#Brqmsd*>WCjy z9Y2q#RKvJTedtl0OT%*Kix#zOAuZGQva;)WqwJmv$=x@E%#6C^p2>jP+xuB&kN#3U zp|`R(YpFixLz!!SrE=fisQ#Lg>Yu-__I;dE`yX9Y`PsX2;L<5o$OlJ;e$>f{N~L1d ztg2oP=kitSs&%<n>)YR44wu6rL~KOARuMIYe(oDI+(M)>yz1(GWyR1d)jd(u&^rT7 zVl8`EXJ>w(AX?3KJ(GGS^wbAx=+E-td1Vy-;kfm$tZ?MWvGW}qJ#zd=0=7B>Bn2b~ zBnc!7Bn>1FBoQPNBo!nVBpD<dBpoClBq1atTb&Y;6Oxpz&I(Bj$qPvg$qY#i$qh*k z$qq>m$qz{o$q-4=R_BN$X{)nD(nRt^5=AmaQblq_l0~vb(naz`5=JscQbuw{lD5@Z kBWc^}yphC_%#qZQ+>zvw>~TW3@SmpdN$WpHcP!!g4SK2@ng9R* diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Uzhgorod b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Uzhgorod deleted file mode 100644 index 66ae8d69e3f86cfdd8d90a9b1d094d807f75f27a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2050 zcmd_qZ%kEn9LMqBNh!P)eQD8!xcn(H|8#}RKShH?uNP);?J8FzmB2#$6H%ZsD2-Om zwMOn+vYIO!mZLv2MjO=wZ2g&Qw9)mp<(eZ`tCh|<cD8b^8mr&?IO;)<deEcJ**UMX z-;?{~zCZDeJK9RjKdx)+2@h9~efZ9O(!R#$bn3*}I{D%)zb0M_%gGnYBzff3@4ozT z+Rd2vM)JnYZ>s&NlQI8q*L|FMJ}sFw8Lqx*;$SlS_@Em&_Pm?(%2RG`|1LLgPpg~X zzTUlgbB%jT{SvpJa=v?OFw31A@VU1=SLn{WxN>m8R~K3qo;Vr1eKgS$Jo;{I(ZEPc z;l6{hqTR<e)cTGVH=UM}u2Cti8k4ehFG_jNVOd<#Ba5f|q#}DjE6!|@rN4LUvJb;@ z$7G{c4mE4l*fPCy{|a6HazLxw3UtN3rLwXnMZ>MxvTE*GjfAJACgpRjE%;Vyr+$*v zvp$j4iE+8>hu5WU_-(15_(-D%`en_rBYJm7hs64y*0uLMtLxggYQvItjn~)edjA^T z5L}=eE`_u)qedFPzFzOWIA1ot|BG%q<&({W>C!ZMLGJ7OS(*nD($aiNw(LEx_b>lI z9%!1-*1SWqwQ5+~Qs2{UIjY;vy`<ZxyL88RukJh(*9YI+r0t(|%0tgoX~$55JiI+m zAK70noog$ltIaRFigRUm<X3q#-AH#)hIYH(OHbM*?Ma@H-l^02*vODPo*2_Thd$N4 z!-w^W-lN)gpiiAEX4%_GnSJ@b@~XdXCv}c@`>y^kZewmZXa8CzP0Va#0{Kqr%y&h# zbFDE8LneLZefcDiZ!$P>vS!|#)JNkc9N}q*n`px-`_!3;J&15%jN|<M@Oxa26aN<l z{9&)1QzMy32}lh{5l9tC8Au&SA^akhAf+I+c-mr+YLIe}dXR#Uijb0!nvkN9s*tjf zx{$(<%8=5K+K}Rq>X7n~`j7&V3Xu|#8j&KADv>ggI*~$=N|91MZLLVLp0-+~T%=y4 zV5DNCWTa-KXryYSY@}|aaHMjibfk8qcu!kBQog6HA6Woo1&}2`)&N-qWEGHQK-K|S z2xKLYr9jpKSqx9R8pv{Z+Vwyd1X&SeNsu)`76n-qWLc1PK^6vC8DwdYwLumKSsi3~ zJni}*3xuo?vP8%lA&Z2p60%IlIw1>%tQ4|T$XX$bg{&5`T%LBlkOlL!D~2o?vS!Gl mA*+Tg8?tWr|6Mqr-M~d9j9@TYT3B8fDk=>|i$mU5neR{PPwhhh diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Vaduz b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Vaduz deleted file mode 100644 index ad6cf59281a1046d9dcd045fda521585e3e33e06..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1909 zcmciCX-L$09LMqhq+=x|UkjT`&1!PZnmp6((5_jPcE=8#Ej!E(waeVJGVQV`Btqi5 zAVpMc%Z5ah^}y<Z9c&jJCJUQH7eUcw5kZ9=Nd4abC5WxZ{r}9ohV0?@{qfIST%2Tm z^*GJH@Zni)KK$;!(R^KTEwQfLFSD+;`>f`(xmK9_nfB^=M_mEe)b;AL_I_|g`~164 z`=0w<!%v=)h(iq$x#th*SE~}WZj<ycDVG7W7sx=LU)*UKGRTuE(GfB7L$}@%<Me9G zo8db6VYJ4!_R=92I_uEJx9ZvdREO2w(zq>GHGbtuO(;C9iTO7rsk~8=)0<>?&JIb5 z+$*U`m6F;~EhEC~bj00xGV()(jymO)(YNz7t-e6hn?~uFn(;bzcZ7~BcI)^pBV|IS zQ@w@Z@>BF<&G2?ert`99x$jBVi$^js;BT4Oa!G!E@R$73a8P{BXEb|ztxP)fr%o;{ zl_|BGb?WqOnp0Awxj&Yu-<PGox+du~PpnRBPtd%uOv$^^Lub4hEHjV4)>*B=GJ9XB z<TpN-In}SEpsq#c7PQK|^=&$T><L+r->ijEyQC<+L5sT_(}j_$3!m)NMIGh3_)?WF zx$D=Z2WDx>#WGp8HC;>VbLF>1QM$Y)Marh8NqMnLRwVY5l^O43Rj4Hu@nKr=^1f7t zv}@%*=cVe!O<i-eUe>lW>AGEKb$!EL-B7h(tG8EcCx>|h0>AfbSzXLgSyn`UN1$be zh}HGW-@a_W<;}?D%g_IEIP5R~w{JGc{E-h&rTOqX^rLwOy=>cvW!HmhkQ=r&cZ}RJ za?d>6G;-I-ZQGjrMs6IrbL7^Mdq-{_xqIaHk^4s)KsrELKzcx$K)OKMK>DyXjUb&M ztsuQ1%^=+%?I8Ui4Iv#NEg?N2O(9(&Z6STxn#PdMY)xxOZ%A`UcSw6ke@KH!he(S^ zk4Te9mq?pPpGc!fr?#e5q*q(hEYdB~F48a3Fw!y7GSV~BG}1NFHqtlJIMTVTX&vd^ z)-;cFkF<~Uk8A+41IQL2dw^^LvJ1#IAp3x91hNyzRv>#}Yc>Pf4P-lz{XjMZ*%4$* zkUc>*1=$s3TabN0HU`-lWNVPUu{E26?2fJ39%O%z4MKJZ*&<|*kWE5%$q~@Wyn)W| z{eB*%p!b#;CNocFr$WT){^f7xX~O>|>c5RL-@#_Hh9$CIp6ukfl(+;>c47j?CkKB5 Dj=i{v diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Vatican b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Vatican deleted file mode 100644 index ac4c16342b5bbfa4c58a26f57db33b95f5b3e533..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2641 zcmciDdrVe!9LMp8n;;^6(G=q%7MYlcAfRBPDFP!OEa6Gb8+b!4q9ZA3sc4xi$K1Cx zokJ5ZxiqC#m}_dS(nbTxFf1x3%S?;r&Sp*t(SGm47_<7@bM~Cq;W+>Ny+5AmiwlRl z{&V@8FZ{Unn;-8z*O*5|$_=Zcv95Xh$y$5I5m&+6uivtERz@^e7QAEcT79Ts_so&j z9(PzlO;NI4cWI)W+8?U*yVK>HH<RRa@ofFJq^~r%8|*V<67;+525F4EZk-*x)jr#@ zMt|tOMOqUN+pSF}n%g28thP_8?VC5Nt@dqO>{}O4+qYl-$a0<h(Ds`9mgT*Dy5%$e z1<Uu<QrmCHCc9hlCd<FaGCLq+lpWAA)eelCY6aG&+CjmoR?vIlcF$j%?cfdV_C2TC zEm<07g&aC>^~$?x_0E|f_a^?WeWF{mZ||Qq)aR6jUj0=2U3g#bJ5#A)U%sK?$Bs+H z!77Q|zEk>_t3<6_D+7v3<o=oS<N>!wqDN=QgRvuIV8kGKD5#$d@=Mo2*OD~m;y@kT z*jFDu>90eoZ)oh^-*xEbA2n`WtqxmyOylPt(u7$}GQ6Z(64Q=KQtlQ>j@%(5hA)>9 z?PZb@zFAYw&5_i$QXO?XT^{*qnvUL=uW3g|>6rE7bZkY0K3W*9<JP6h_)I@dpC2w0 z242#P^mfVg`&zT2&r8;o-z3}TbIGo+k;g9Vk%?6Y#9jB9=4>pNNe6f7<Hg1DMENT^ zdFlquEn1*?Ba77I&eA7CC+U>f!8+x7yiV(rDbv31rB7Xpk?9}*r861>WoBiF%&PuV zW|v)+{LS@Jkl!eCR{f!K#~zV+v+8ty)HYd=R;7gjhjn43>cY!gby0hXF0NUjPoMMX zGw;sOqOX?7v#+IT@xDBHZc&t4>yu^4<k3=67%I;v^p~X>t+Fh{C8fjqXsP{+EDye} z%TJ$>6<3<{#Siw$OZ7)}<+d+$Rn-n%y<)GHZ7fr7uddt2*W6y-Jk8x{$6t3m{kq-# z+vVy}ZO)S`Vt|*g%M~oH?w!w$FJ0f=IUZMfMjj6j|HI2%XkI-3e|iJVKl0-`V1B%Z z+&0&kn9FXoj;*zj)9h$YG;*qulZ~8i<b)%q969O8X-7^xa_W(jkDPv_07wOp5+F4| zihxuBDFadmq!5m#5=beKS~!|wAk}a*<v{9z6a<}$@IpzrOih5IAXP!ig46{m3{n}S zG)Qe6O>vOwIGXYx^>H)>LMnum2&oZLB&146nUFdmg+eNYlnSYpqbU|rEu>sXy^w+- z6+=pf)C?&aQZ=M(NZpXaA(cZ)htv)!o};NAQa+@9NCA-wA|*s>h!hd2B2q@Ajz}Sq zN+P91YKaun(Nq&Dr=zJSQc$F#NJ){JB1J{2ij)<pD^ggbvPfx>+9Jh8s*9A@(bN|y zu%oFkQevdWNRg2$BV|VFj1(HFG*W7$)=06DY9r-#H1$Rb?r18GlpLu!Qgo#1NZFCP zBZWsQkCYy%JyLw6`bhba`XdYAXjTAO0%Q%4ML<>oSq5YskcB{20$B=VEs(`PRs&fM zWId1taWpG}EQzC86J$}4RY8^oSr=qskd;A}#>>aM>-P0Cx3>>Zb9dVD*B#Gp{&)ZG zoEkGYW@^l^m^}y<SI^F8$Cs|}3{LL9MyG3a%v+#YqM-?FQfy9QTyk7|Y)(Qv4oeLD E2jBk!N&o-= diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Vienna b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Vienna deleted file mode 100644 index 3582bb15cd7322088839b0134987ad10e717b6b5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2200 zcmdtie@xVM9LMo5ASul3Z3buj5bY$SPJTmTklJ}Lg;SBsNF*>2wFu=h2Bn=pm~+Y8 zTgP+`Nkhh}>FFO>YiO;kMhgjNmtncKoWH6$Hgnb*tIzZMuj`Ng>5o3&eZP<IZo5Bj zyVujVa(#W4b<Y`ZKH=u<HaGA0Z#9q3iH@4i(52BsBSG!zIi+uXsCu~VfOc<;lcNhO zbs(xq2d|gNxpy5p)a{n9_vOg&_GCHlkCpQQk6fsY*KbOk8p=N_-=_A-MOU1B7qwre zcvD6n${wzXasHyQQ+`lK#5r}`{z#`@IiU|<IHGZ9_iFs<Gm>yDD2ay-%d~ctq|Mu8 zdV^nPtg4kqN`2xi@W@P8o+Kxv$fFadN=l?#Q|{#GtgFeI8j97&J|C}-_x-M}o|`(m z<C3PeeWmG}PHRTpam}n6kt~0oWEb{J&hq_|o7g3JSuK(`7LYmd9XjXoYRUhzS?8W{ z%ah+%XhCna7WU88r*<yTd7TM5zuu_}+VbV;qDXbu#mmCv>*{fjNm1mNTI~E$if>($ zMG>FKqM-p<eC4Q=1mBa=!H?Cur(KpDds~+_Hp;U09a{G6o4UMVjg~*rpuW;#ea5jw zSGZDj#oY|8h$)haix28^cV@}T_kYvMP_(Q%GFhtnewF6~x23vcNNTD>vU<zU`og>q zq_%2M>yi%2n!=#gPdKG(6IIvVIH2ps{JMUiRbRa9)0f_<)P^sb<mFw3+Spqz8`dT1 z#+|v+R8}DVdWXD{IZZZs{*YHEThg2!qs^l~Nz0_W+A{o^wB8!g*G~4z>qGsz`QWFz zCD^5JwDxFVPe8-N!Xw7rdxeEZ-uGW$mi0iH`R7^*)5FGD)+Di_{^`Bc>$BXRavnau z5oQjW7vI0w$zSGd=&nvj_F`)`gX{*`4zeF)L&%PhEg^eCHihg8*%q=dWMjzAY|Yk? zy&;=Jc86>a*&nh&eknUdwutNz*(9<{TeD4MpU6g$og!OB_KIv4*)6hNWWUIUksTvj zM)r(s8re0nZCkT%WaG%rk*y<pM>db_9@##!f209O2apyZJwTd(bOC9Dt?2{O2wT$$ zq!mankY*s=K-z)y18E4-5u_zZPmrb{T|wG{^aW{*t?3NX8e7vFq&Y};koF+`K^lZ~ z2x$@0Bcw@4myk9geL@;#YdVFr%GUG>X%^Bgq+LkAkcJ^0Lt2LP3~3tDHKc7w-;l;3 zokLn@YkG$?59uD#KBRw01Cb6QEkt^VG!f|{(nh3@NF$L>BCWJFy+oR6Yr2WF6X_?? kP^6<sOOc-9|FNmjCbP3M39ieVotB%H;qqo?V0w1+--?$-F#rGn diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Vilnius b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Vilnius deleted file mode 100644 index 7abd63fa608e0186b9f154d9fcc32472c28f6759..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2162 zcmeIyZ%kEn9LMqB4bdCX^^1iU0z@JK3E}cjZIi_KHw6^sihoHfL@Xjjb5I&*rOq|x zz7<=!bop=eXT*G9_8?n-<{H%v?-SM<wOXxgthv+5IonwM-Up~vkKB6L@9gk8I~N!a z_`Jg#ceECnf1O$O4L7ID-aKbH_RFzV=?y0ju6XIx&ms48YuDDHflE6-*^nEJT&|VR zUJvT<sS3IDe2GLuW#1%bzZ#vL^ksR_KiUxdZRYz)V}WS$Xhr!Qkr$#V7f!gT1JAi> z$DVfQ^zL@k_qDil+t<1oo2%VB>lV40OLE-1@{-+osmUfQKF(yvmO9y2vz(mogU<XB zzmt3Mx^wrrF(>cLsI#Ci;^ZHA*D2UD=!9BcaSEG1HAS8Mrnu})Q?ll;DNQ>r3yZpB z;dqZMPU+Ko4=vNBFQ;mGYo;zcaF5(q9jg^BDN;G_vQ|}$OLgqWT9f&;)Li*NmdAV` z%ZG<##doKrcJK|Ui@c}xM|x%Dz)4-z(IE}J&*<uP&+3}?ZQ8h~UBh)Xx;D5{oATys z)3uPUPpp>ppU=__S94_J`CoO@NStgwks!_Iev<opevvJG!?JbDh&-@=OdnkOwmj4v z(U$b1vaM`TTm5h8_B7S)Kfb7K<DI%=s9PWYDy)yZwn^JR+9i)3F4K<wMtQ6)U3VTT zm0hcsNM~zMb{Ec(JyqA`@dP7#3lep&`>k{Zu4z~FqI6&RLZ3L>FHa7?qx+72sQU+x z>r>rlwC6~V`fiGu78C2AK4bcf*qbM=xLYQ#_*?&Z1!e{$;Xk>I30|=OTIRO1W|}dx z+l=3sfS7n=Qs){mCO2em|Lct}iT8Y6T<%Mo`gH2qmofEI6W{aq-{Z@us}GxX_O7*e zMOD~T*}J~6);>4#P-$P-hl%6!8RMHgldt~##ODj&z;b@Kr|Ep85?K(kB4kO(nvg{y zt3sBAtP5EfvNB|8{8_9GSsb!DPrE#1eaHfl6(UPS)`%<;StYVeWSz)Dk(DA#Mb?Te zmcwc}EZ5Vn7g;c}Vr0q4nvq2#t45ZMtQ%Q4vT_bf=dgATi|4R<Wci+U{YU|j3Lqsw zYJe00sRB|4qz*_SkV+t>@U*o+is5Oifs_NO2T~BEB1lP)njl3%s)CdSsS8pVq%ufp zJZ)`|;&|HXAmu^ogA@p<5K<zfMo5v6Dj{V;>Vy;usT5Kwq*h3=JZ-g*av}9X3Wih+ zDH&2Tq-aRhkg_3lLkfpf4k;Z{JEVA?wt7hUJZ=4u0wNVeN{G}DDI!uu{J)GhTE;jV a)dfX_G_SrmzcfEoP@Gp^81kM<;{E^_i2_Uj diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Volgograd b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Volgograd deleted file mode 100644 index 11739ac271da2b623bef49ea64908820b7ca05fd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1165 zcmd7QPe_w-9LMozxiy&`x|B0F`(ty>KeaX|tEMfd8`cDg(Lswwe}o|DOL!;<3^Gp@ z6hTB0MWai9i8^I5qD!QnylL=2hv+Zgi<hL<@BP>*g6P)s@a*;Qu#K_LyD)fUIA;Cv zsQ&e|+sOU$Tl3kur=^;K72&JpmHz2yZS_>T_M7XG|D#o|n@vPlO`a{+Ph7GC_s-bC z>mzo<xx@DAQ+w<+M|1Yty-9mrK4LefHt71+It>MU+ElZkVNY1X^L~lUd@eS>`Xnt+ z=A^YWC2f~q$i}gUvT5X|L=Rn*&HE-acKnLQJ8x+F?vt7bp4N`okam1Opvn3Zl6>2v zTNVao>+>evHk*>vos4uoYmlz-kZiwZNqX2TJH`Uq-TOf@2Y+Z!=#BJdY|VP^ORn*y z=DxnxzN(V;P2bg>@5Xi4gY%l7ye<6~j%gtuEDp_l(f#iq7e_0Vifc*L;_3D{=Ta}H zdy&7ry1j0%*Rmod{@v!N<+iM3n*TRD;9B<ky~{l3J^B8E)e?=HtKD1)K5DtlQTT`T z%nz@yAhIIg!IH?D$fAyBRb*LYU1VWoWn^h&ZDes|b!2&DeWU=S0;B|_2BZk23P)20 zQU_89QVCKDQVUWHQVmiLQV&uPQV~)TQWH{?qp1oh%hA+@6oyoWl!nxX6o*uYl!w%Z z6o^!al!(-b6p2)cl<8>dL<)5@l_I4gwIanL)gt90^&$o1sA=H;so0k?ZFjZBeLn&7 C+!|T{ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Warsaw b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Warsaw deleted file mode 100644 index e33cf67171da78aa9e6eb02e50f9b9603da4c3f4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2654 zcmeIzYfP499LMnskW^Coqaw;dEFzImK@b%oGeT#8sXQv;2@Oz-3=a{S#64xMnREXf z;t(k<WagCELR+G9cA70CJdk0dR<1mZOhdBPm|fr7wboi&z35%nv*-TYJmc;4{dsbh z7mPN4Id|J%_;U8zFYm#QeN^p>ZmI4Qlv~|;;rgz&dabEFq_4cA`fB+O-M#a$*^__F z)RnH!Jz4yvoVt`QpS%&I&99}(r`r;wrTmCFy?tBJnaxePXP4YAI+q@ytqTvzXTuxi zd`z%>-n&xTyiaJ`l@ht^Ib$y0XmqZ8z1O*Vy3*+wP-!}jyk)-MUu&-I+-`n2mt(H4 zd(PZwOg2B}%r%`AL(I*j38t$w$@wWb%=E3D<@mqU$J|ps){!+)PC(vZr=Q2q>7SWs z2E=zbff4P_!2Zonkk4@^sI$Qtba9U}`0O?(_`Quz$k8`V=z-lPY}d<X$d(NzeEn)O zv@p-yJAanBFT*1d$!T(bOrk`F4wDD^43c5KsXDAHL8HEn)ZwiIHTr{|`e5VF8dG~k zM^s$Uk>wxjs5M75Ht(RuEohU`s~ROfrAZQIR?3*L8c7^oB8lB)GA^V-$F(n(@xK;p z(y>&T@I|&J*DcbNrX+o6(<Gf(9jXr(MChdQ@$$%IUro&mkw+shX<BNxO!oaqr$l@u zQ?7j{Q+-az)aH}&*u~c+y?(!BoI0+VTerxx1AFxG6)R-=mW?`N&Ssrin6Fu53)Pb` zMP~&~)7de@b@r`T%?_L_+2{M|+^#6eIeb&+wff2Y-2t+ou|pP?b;_cOX31UDDvL|6 z>XM0X%M%MuX<m4h<fqhYL9au)G)#5r<sG`LdzCIfxmKTS_vlmm=4s)FE9L1IQ*=dL zmOQg8T#Gi1k(D!&WmQ3ttd1KZYtnv^X9J8Bj|$Y{>)%L;|1B+Pd0*CEYtwZNb@F_3 zldi9NS4-<_^o6yxTDG-Jy?nfVdieI}byrUxZ(sXz=TF}L;itFXfB!M2e}la{JbM@u zI@GI|G5%uu{`oyR)+>Nt%)mdMzyD`OrpL^&-_*1$9v+j%OPYP*c-dng?)#m;J^$ib z-?nG=;g;#h^+v9^tG(vPRY$Hna^;b0k6eA^`XdQIGJvE2$pMlCBnwCykUSuXKr(@( z0?7rE3?v&!I*@$0+Jqn(akVKya)KlU$%?B@3z8QkF-T^R)F8P*l7nOiNe_}ABtaZ9 zgrtZ=j*uiFSwhl;<cUL~kW3+|LUQG5lZ9jpNf(kYBw-vf#vx@Ka>gNP9J0nCZ5;B3 zBo4_Ok~$=JNb+25_K@@;`9l(jWDrRql0zhkNEVSaB6&m-iDVK<C6Y@dnXWdQNIG3@ zK9PhX8AVcx<P=FNl2s(FNM4b|BAG=}i{utbE|Og&y{<ODNP=B$hLIE_IYyF<WEn{_ zl4m5*NT!igBe_PBjbs~1x2w%Jl5kg>aU|tP&XJ@eSx3^2<Q+*ol6fTcNbZs3BiTpN zkK`Yj09QK$$P^%RfJ_213&=De^MFhQG84#DAaj9C1~MDSbRhGAOo*$U5oAhS?VKQ! tg3JmsEy%ne6NAhQ{y#N;J2ifGjz+{WOfi}9Bgc%4jmeCQ#ZmEozX3dW2`vBs diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Zagreb b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Zagreb deleted file mode 100644 index 27de456f16ab549627b284a39e2265cbdb4ad8e9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1920 zcmdVaYfQ~?9LMqhL0H4S7@-o9T#oJ~DdMPHDwhrt$t4vMLdq?-nOU<hYs@g$HH>%= z9>mObA-Sy?W{kPcS{sI0<M;k=Hk(JD*!)lDyjrdG<oo`(Gv?)lS${mO%ujgptT1oB zZ@bQX+-w&4y!OplxqZw_>khf(&W;GVyCFdC9W0aksqxz7<tgp@;DC0!vR%E;Ul5-Y zmEya1zjQBC@msxKdgK>M&*^idSF&6DV-uveGfDz{0;NxzE)wYB(!kFV+V@p}_N(u# z{jass0aahsdE}iAEPt#)n{H|Fvhx~}eNsa+A4ynYm4wGtOT@&T66w27qQZ(Ls;N|> zy~{QF=`0!iy+~s&xMawabd9aZ(zxmv9lCkA4%_3S@j3oFeA8eVk?5hWY;PGE@J16{ zO_JzwLzDcUNm9dW8QuJnjIOJZF)t6x*vjLQTzgSdwv|chiGw<>pg_i#ZPW=<w(7+E zxtca8U){+`I>{?lCp-J;<S!wb-YHSiA9m2GpZiM2*-tvH-czO@XfK&nA7n=9N69L$ zlbKodGHcCyojvTF%*m|PY`@(yH?C51TA$HeU)9{VyELz<Q0LW@==`T{U2t@o=3ieT z3%A5+K}DJ@%Jb93n<Hh(gjgxe@sg#X-DO$AH(B1^lA_>FTGaSLiranB;=5O+q~VdS zJY6BH>Z*11?#sHSa-Xg(IijW8O4ZS#S#$g4(ehuuEURO*xhkujSS@~i`t)$LwyfVj z`E7EF+j1rFPIH?-a5(tlaX8$6al=2%Gb6Tf6mrYRJtH@b+%<CB$bBO>j@&u_nOjHh z9l3er?vdL^?jLCY=>TZ~=>cg1=>lm3=>us5>BQEwg7ktkgLH$mgY<(mgmi?og!F_o zg>;3qh4h6qhID3YT0?rXHO(R2A?+dkAq^rOA}u04B26M)B5fjlB8?)QBCR65+L~sO zZf#AwNWVzKNXJOaNY6;qNY_Z)NZ&}~NaslFNbk0$d8B(=(>~HavH{2rAX|X!0kR3m zE+E^0>;tk9$W9<zf$Rmc8OUzfn(aXL1KAK{N02Q+_5|4!WLJ=FLG}gN7-VOVtwHt% z*&JkdY|Zu{`(tZ12-zWIi;z7+HVN4!WSj7R-zQJATLVKGE@w)3P-IYuGbJ<xgTp<4 E0<)*Xw*UYD diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Zaporozhye b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Zaporozhye deleted file mode 100644 index e42edfc8506b9b99362b36d90c8b8c4db67d50d8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2106 zcmeIye@xVM9LMp`2^5`$Z{6@9Ku9!D5spI?4H7#KW`Lb?5~;*lh+0I5#=taMIp-R4 z?<T9ca<gPq%$RLxf1vA^Yu4zxKeFb?wN;De%zd|VR*u!@`E|6m{_2nZ>-*jJ`}p!@ z?6w=PXJq4!)`0oPaff}w#j(d;JkNX9-iFeT`%ev|M?W2!h>uOw$Y*c)H1>K>VrReX zNX>gAK0EE}N?-DL*!TO4_tP$?#M8%vm3NLEj%S=X=476D(aC!CIcHAaE+>0$i<8r~ z!MSU5l{2??nUh<d@60Pmcjjk$ox7*saPpG!I`Xcib>x5lQ+UA_SE38geI8yk5{niL zyc1sBe==IQ|8Tfy_ZjuKysgDe7bVa+A|(~0vSj^BQkr#CmIk_I>13~zW%O&=r7g1j zMwhNQ8<cy-8?}6}St~|Y=)DJ4>B?6!wX!u=SM6Ue_f;inuq8uQ&!5mxa8jz0KGEvj zZ>0L_53(lV16dP0FZX|UTxy1gq;~8*tvl2wYfrqU545*SxbJyg_uvb<zHO`4FKg3C zZMAOjt<{Et1=?`kuZ^iy()iUZedt=gY&`voZo1%=&Bta+)5sNhxc6si?vF{d`GRcO zcUd1<`K~<LG^Q=tM`UZou(l?j(rsC)+kSjmw@-HJj`KbG*rkX*{^lla`*^23aj-($ z2kYg@?b+IKpj39QE0@kzpX@50BfCSt$x}0pbQPs)m-DT3r(D<W_&MphdQtbB9F(VH zqq_IVhq`b0s6Nv(puLBB)iW*Omc*pQgj;W($+!LO^iI2ZPQU%XIE~5q)&7&2oVZCe zCNsx)jale7DaNFTnZ+B=?5TTMr6*(Rw^PraY~FC^Z)@u!W|2P-@S9L5V(RK^Owbw( z)$_w@`_evecs%X}e;poA<X<e~4|_D6{wNt)2(l7nDacxo#UQJ3waejSSr4)xWJRua zNywUzMIoy~mW8YfSs1c1WNFCSki{XZLzaiE4_P3xLS%`qc8$m)kyRqgMAnHc6j>>< zRAjBlVv*G%%SG0UEEriavSe4gW@OQ>cGbwTk#!>rM^=t39a%fFcx3g+@{#o;1wbl* zlmMv#QUq691*8nFwhl-kkV+t>Kx%;$1E~g54x}DPL6C|dB|&O}6vfq61u2WGtqW2Z zq%ufpklG-{L8^n42dNKIAf!S_iI5s0MMA2Cl*!fB2`Lm(DWp_Lt&n0N)k4aJ)C(yX zQZb}tNX?L<Ayq@l=4$JP6wcLF4k;Z{JEV9>^^o!*^~3)Q$hSZdy*8VR17xzGuB5QE Q&|g$iP*?1CpO$$41Tp&eZ~y=R diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Zurich b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Europe/Zurich deleted file mode 100644 index ad6cf59281a1046d9dcd045fda521585e3e33e06..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1909 zcmciCX-L$09LMqhq+=x|UkjT`&1!PZnmp6((5_jPcE=8#Ej!E(waeVJGVQV`Btqi5 zAVpMc%Z5ah^}y<Z9c&jJCJUQH7eUcw5kZ9=Nd4abC5WxZ{r}9ohV0?@{qfIST%2Tm z^*GJH@Zni)KK$;!(R^KTEwQfLFSD+;`>f`(xmK9_nfB^=M_mEe)b;AL_I_|g`~164 z`=0w<!%v=)h(iq$x#th*SE~}WZj<ycDVG7W7sx=LU)*UKGRTuE(GfB7L$}@%<Me9G zo8db6VYJ4!_R=92I_uEJx9ZvdREO2w(zq>GHGbtuO(;C9iTO7rsk~8=)0<>?&JIb5 z+$*U`m6F;~EhEC~bj00xGV()(jymO)(YNz7t-e6hn?~uFn(;bzcZ7~BcI)^pBV|IS zQ@w@Z@>BF<&G2?ert`99x$jBVi$^js;BT4Oa!G!E@R$73a8P{BXEb|ztxP)fr%o;{ zl_|BGb?WqOnp0Awxj&Yu-<PGox+du~PpnRBPtd%uOv$^^Lub4hEHjV4)>*B=GJ9XB z<TpN-In}SEpsq#c7PQK|^=&$T><L+r->ijEyQC<+L5sT_(}j_$3!m)NMIGh3_)?WF zx$D=Z2WDx>#WGp8HC;>VbLF>1QM$Y)Marh8NqMnLRwVY5l^O43Rj4Hu@nKr=^1f7t zv}@%*=cVe!O<i-eUe>lW>AGEKb$!EL-B7h(tG8EcCx>|h0>AfbSzXLgSyn`UN1$be zh}HGW-@a_W<;}?D%g_IEIP5R~w{JGc{E-h&rTOqX^rLwOy=>cvW!HmhkQ=r&cZ}RJ za?d>6G;-I-ZQGjrMs6IrbL7^Mdq-{_xqIaHk^4s)KsrELKzcx$K)OKMK>DyXjUb&M ztsuQ1%^=+%?I8Ui4Iv#NEg?N2O(9(&Z6STxn#PdMY)xxOZ%A`UcSw6ke@KH!he(S^ zk4Te9mq?pPpGc!fr?#e5q*q(hEYdB~F48a3Fw!y7GSV~BG}1NFHqtlJIMTVTX&vd^ z)-;cFkF<~Uk8A+41IQL2dw^^LvJ1#IAp3x91hNyzRv>#}Yc>Pf4P-lz{XjMZ*%4$* zkUc>*1=$s3TabN0HU`-lWNVPUu{E26?2fJ39%O%z4MKJZ*&<|*kWE5%$q~@Wyn)W| z{eB*%p!b#;CNocFr$WT){^f7xX~O>|>c5RL-@#_Hh9$CIp6ukfl(+;>c47j?CkKB5 Dj=i{v diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Factory b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Factory deleted file mode 100644 index 60aa2a0d695ba577ff87624d479f1eb25c8f1caf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 116 jcmWHE%1kq2AP5+NDp(+@bPWs`Ldep^Wdqb}XTSvjS7imx diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/GB b/venv/lib/python3.8/site-packages/pytz/zoneinfo/GB deleted file mode 100644 index ac02a81440f47a67b9f01d3fbcdb085266d20894..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3648 zcmeI!X;9R49LMq95EV52K?)`wKO;4aaG^A_$UF%J^4N6K45`FSG9)9&jG9gz$NAb& zWNQ9AQu4qH%A`Zn@C-G>3?r{R@I=dm5bXE<&on*gkv-^9>@2UH9d?*uhVT319XUQV z#`TY{M)n<^d|k3nUI)Emzs>2i(#+ZKujlUen0bpgn-AyCGxPIW8}r5ny&&_dSvYpC zUNmK!S)8=qeAKH}FX=c&FYR2S^Seaq{4>>NnQNa}R@PE4udLE5wx;Qo+rQHVOOx~} zlWkVN<<V>2*<;qGCzy2^Yfa(cC{q+aQh(x6=F^x=v%dKy^I5RZe0Je`v!T+Ziw|7X zpC25dzgWLdf4QdKeD!{j-Z&>rZ_3KkU%yzVH~X^nmLZGHH$6t_lAfFNR^NWJwLHM= z2<ap{@*a_$d)vvb7w(mB*SMr~j8E;Bqq1k>W3o3RMD4AOQQwWP*ZZD`FyF@?)@AKF zn6f@~Qg-OD+Ml#S@2~eW2cl-`12ymJ@@DC}{LEQ>@OY^CX=kaf*ivJDE<9}x6@=)+ zxx37fj0erp36u4)p<T=`UNOgGnwk@_EA`2+2z{!B*PN<tqATkr>C@%s^qGob`s{|? z`rNud%=r)2=nJooGgb4a>WeAy=2A|w{&irg{w=w;zTDwP^LwvweZ_UbRJZrn)ra?* zn);LakB#e0?I}NVb;@#6x3xIkFTF%Ji12Cu!TGvjKu_JsGhH{TY@-8Inhw}juLG-+ zbd$BMP18LdedDaFrrGLX-F(u|M$L{gK|?m0;A~}Xie6}1_%4~2;b$bIM~Q^`eJib6 z<x8t$tK{bD>C$@hED1ZZRJB=ApxSPlrrOOA)qcSQrPDH0hgTETEeT!~p3+s_8rfZS z95_fiHEpFjcez74U%pEs0-H-jS%`G0yePL9R!ijeeR4-`xkP<jBwZ(eE}m(55<U7y z6_Zh@?u;!~cMW|{b!$6Mb&ttX-Rp8xkFZ?nQIVqVsm+w0U-VV?9`wn5OOhqFxToCz zW^d^=r;R+28ZNzGzen{M;4gij3{(9&o|OK5>(l`M?GhJ$NX4B$q2m2Esrb@uYT&U& zYEZ#4m9Xn8Nt`)DC9PN>4^5n?2G4j+hK!glL(|5}u)EX5n-C`thbGDJ$OsvJ#Us9! z1C;NFV0q;7ZEEBvzsabwK=r5zQlkscs>gDERmr)fYD{vON|}0E9`E(3dSdi0d9wX% zH8!?DQX3b^xV9qWPUXo{br~{#Tedu1;gt#bqa>|ll6vOtSedwFn0of9_LBZ)H#KR< zeJUe0R6Q5nPEGD#qn;0Psm!h|C9~?N%4&8+vi59I+2?<h7gsM)Q%Z~FrP*K0)Pi~P za`s}$nVBOuxUcu&=l<)#C;hJD^9>sQ^N0N#{@0Id*RB=W<K=3m+zrsx*yU=Y-A#GN zW#9Sx{e(oXtIsg6D-QeF7cRHkZJ*Ak+-~o6oJ;#lueBZ>uoF3(j`nmS=My=h$QeaW zDRNGclZu>G<g_B^6*;lUnMF=5a&8^%$wkhtqdmRI`9)4Ja)yypjGSZSBqL`TInBs< zMou(xrjb*PoNMG{BWK&uo^IrPBPSd=<H#vT&N*_@k+Y7RcI3PxCmuQT$f-xpJ#z9L z?b%08zoR|>NCJ=yASpm{fFuFQ0+I$tn+GHjNG6a}Ah~d~$#AsUK+@r8^MNG9(Pjim ziKER4k`yE>NLrA*Ac;XTgQNz@4U!xrJ4kwv{2&QJGURAegyaZG5|Sk(O-P=QL?M|% zQibFSNfweVBwa|pkc1%_LsI5wbA}`h$r_S2ByULK_}3(JNa~Q>A<09s=V;T1<j>J2 z5Xm5tLL`Ss5|Jz-X+-jfBofIal1e0(NHURZBI!i(>1Y#*WE4p$l2at9NLG=wB6&p; zi)0o_Es|R#xkz@A^dk9nv<XHs>}XSr<QPdZl4T^#NS={IBbi20jpQ0hHj-^5-AKM2 zZNia^JKB^ZIY*L?WF1L6l6NHWNam5$Be_SCk7OT7KaziB0w6QM(M|zm4mjFLfXo79 z8X)rknFz>CK&ApR7m&$-%m!pSAoBs45Xg*hv{M3^6OMLLAhQCQ7RbCnCI&Jykg0*p z4P<g4vjdqP$oxPi2r@&EDT2%qM>|Q7S%ORxWS$@s1(_+xR6*tnGFgz>f=m}=z916@ znK8(eLFSC3oixa-akSG0nK#J9L1qpzb&$D(OdkAy_V8Eu*Rv<k&LNMTMUjbjMs<tw Nbd8QojP~#<@K40&SY`kK diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/GB-Eire b/venv/lib/python3.8/site-packages/pytz/zoneinfo/GB-Eire deleted file mode 100644 index ac02a81440f47a67b9f01d3fbcdb085266d20894..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3648 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 Nbd8QojP~#<@K40&SY`kK diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/GMT b/venv/lib/python3.8/site-packages/pytz/zoneinfo/GMT deleted file mode 100644 index c63474664a289aa3c3c0d8b2ce06d484679754c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 114 hcmWHE%1kq2AP5+NDp(+@+<ikBLdep^1=MQ51psD724w&M diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/GMT+0 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/GMT+0 deleted file mode 100644 index c63474664a289aa3c3c0d8b2ce06d484679754c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 114 hcmWHE%1kq2AP5+NDp(+@+<ikBLdep^1=MQ51psD724w&M diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/GMT-0 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/GMT-0 deleted file mode 100644 index c63474664a289aa3c3c0d8b2ce06d484679754c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 114 hcmWHE%1kq2AP5+NDp(+@+<ikBLdep^1=MQ51psD724w&M diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/GMT0 b/venv/lib/python3.8/site-packages/pytz/zoneinfo/GMT0 deleted file mode 100644 index c63474664a289aa3c3c0d8b2ce06d484679754c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 114 hcmWHE%1kq2AP5+NDp(+@+<ikBLdep^1=MQ51psD724w&M diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Greenwich b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Greenwich deleted file mode 100644 index c63474664a289aa3c3c0d8b2ce06d484679754c0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 114 hcmWHE%1kq2AP5+NDp(+@+<ikBLdep^1=MQ51psD724w&M diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/HST b/venv/lib/python3.8/site-packages/pytz/zoneinfo/HST deleted file mode 100644 index cccd45eb8cb2f56b6a1b75e2d7b9530cb5abf2e1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 115 mcmWHE%1kq2AP5+NDp>yiFHT@!@CXiJ2q8-s7f`FA0T%#a4Gc{H diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Hongkong b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Hongkong deleted file mode 100644 index 23d0375fba3377a3d513d849c0d29c82ad2add64..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1203 zcmd7QU1-f=0LSs?e_rh{a>4}{MD&!#u^Z16wn@Wr?82!@F;a5cyrs<5X_8uzPOZ35 zlB;KwMCrM5X)}@6?btZ;wsRV0UUrThHplb*N4apbJI}v!K2QJ4|L+^$p4eL{{&|AG z->$cEpK~&?C)FKW5$W!4kKBzOKKAHhCiS?fxAjT;HuJRhn(8^S%Ji<OG3jNMCS9yD zebZ-|zGw4H|8T)PHxuT?y|l?(nyUtG=GDvN<LcGfJMwjXLcKY9MZR4gRfCP4Iy<96 z<<@rS+}K7lH2;(yN-s6<O8fPDQ*J&C)a&7MBj#gQvm9x8Xg=vJ@^ixt^QA2!zg9m` zqx-@#zu>wm)Q!q-i<4?>_HJ49?^4D5I{AIDR{h8{>hb$K&BU!5{qt(IDP35k#hHc1 zN&2<tfX{e$<g_oAHU2uE46O93;F7Eio>;BQ0$sAK(5XV%%W`T@hnjZ#w48aqN`((L zYscgDIUaw&KAu01<C)|mL{o^5eW+FVgh-~GDMGZgIpy3%`0w|dV{x$|%5N)w4RNu_ zUfkn2@kwl1vWGp9O<nD-$hOG7$i~Rd$kxc-$mYoIu6BE5e^=W8(gD%}(gV^2(go56 z(g)HA(h1TE(hJfI(v7Qa2kFPvHiUG9w1o78G=+49w1xDAG=_ABw1)JCG>3GDw1@PE zH0WwOL|R08M4CjpM7K>Y^vSV}0-YkQBE2HbBHbeGBK^ABhLMh4ZOcf{NYhByNZa_o L^&PV1SE$f0t#TGS diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Iceland b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Iceland deleted file mode 100644 index 10e0fc8190a401f67b861ced3b8b16401432a565..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1162 zcmc)IO-K}R7{~FMc3s3G76L_sdZN@of-OT3ifGF^)E;6NqAo5`K~YdqbStrh=!Nu9 zr>&mEQ}hObVC*3X5;d*O)NM6;HCOFLvurJE`hUluOP9Jdf0)lObDQ5cvUS(aW!4`r z-><i8jXe8LMUQE$Zk}}^aiaF(flXDHx;%aj*I1Vu%W4}|6jwDg9rWJ|6<EzHi={c0 zceABvjkeq^k~UwVwp|VC{l0c-KfOph;y2{M9-lsp)k$JQS|8P1)6SAseZ1qWc9kcj zyJElg<lmBHVOW!s=Oi_IpQN4~mfnFp?Q7a1Pdk=NfBhkSc0E^~S8vuAXEO3~Te-g4 zo08YTxjGPv%bNw?b+9a{>6ryGlzUr;hNonBBBmp){qnZ^h`zgWN8UF^^~1?}89g7= zvE9ez<IzeP537EvTrHnVt94@4LisXhyJqHRNoIVVPW~8_ubqqaTiT;j@d}w?|2`h? zKb<Vc8HrB+XWQ#IW208~^qqIM*ZneUV<=*k1OnEQz*1|ydFGRCNB&|t$6Tz3EQqX# zEQzd%EQ+j(EbD64MHWU@b~Q^QYrC4ok=0$z^2qu~0Z0W%2}lh{5l9tC8Au&SAxI@i zDM&4@rWm9eS5ppB4^j|P5mFLT6H*jX6;c*b7g88f8B!Wj8&VunovSGisSha-sSqg< rsSzm>sS+s@sS_y_sT3&{sTC;}sn*q$i`0u0j8u&OzvLVfbs*;_NO)Hd diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Antananarivo b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Antananarivo deleted file mode 100644 index 9dcfc19c56e62b12b730f4335b34479695f273f5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 265 zcmWHE%1kq2zzbM`vLGzd{r}>hjqh$nY&rhm!ojy|BhKVhU14NmWM*PuP-+1gp{&8c z!oZ+qz`(`8ptgpA55o5G4PnqWFfuk^aCHQ;OiUR<NU-)l5P+-((ID$VG{^}c8srQR OO@ULmfUeRt<^llo>q3(N diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Chagos b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Chagos deleted file mode 100644 index 93d6dda50f579093f25617c77081ae99c8631ea5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 199 zcmWHE%1kq2zzdjxvLMXUS@(U8!Lz#?>i_@$&&b5Yz~KA@q|q&afrWt~B!Pj$$2WvQ k+rSiv%@{&RFc@gwe~{rI(?Ax0Xre6PvH@CUr)$Oq0G>%BlK=n! diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Christmas b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Christmas deleted file mode 100644 index d18c3810d97bbd424dc3c8fa98de46bfa08c3fa8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 165 zcmWHE%1kq2zzdjwvLMXS03_=F|Nqa($iR>+1LQCy6)>>)_=YfO8<;bMkYEzfkpIPE TE1!VOz-=Oz4bWUWU2`q~S7aD5 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Cocos b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Cocos deleted file mode 100644 index f8116e7025cadc709bbd995905e88c92ed03642a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 174 zcmWHE%1kq2zzdjwvLMXW03_=F|Nqa($iNVF2gqTF&R}5i@eN_nHZU_bU<e_>ETA#} YYeLnQfK0(>CYKG^Y&%^uD`NvL0F6i*%m4rY diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Comoro b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Comoro deleted file mode 100644 index 9dcfc19c56e62b12b730f4335b34479695f273f5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 265 zcmWHE%1kq2zzbM`vLGzd{r}>hjqh$nY&rhm!ojy|BhKVhU14NmWM*PuP-+1gp{&8c z!oZ+qz`(`8ptgpA55o5G4PnqWFfuk^aCHQ;OiUR<NU-)l5P+-((ID$VG{^}c8srQR OO@ULmfUeRt<^llo>q3(N diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Kerguelen b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Kerguelen deleted file mode 100644 index cde4cf7ea7086a3fa3609566ff03e9425b096f36..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 165 zcmWHE%1kq2zzdjwvLMWHD>12|{{R2~jEpe#ZUGD|x&{Ue+6JZ!AtaatG~_?XG>|#C OP2{oxnro+P$^`(9>=%~+ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Mahe b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Mahe deleted file mode 100644 index 208f9386bdad172305a48f6ab7e70ac3e1ca0e1e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 165 zcmWHE%1kq2zzdjwvLMXSS<l{5|NsAgMn(n(<3Auh77h$7KE5Fg+6E>JAtaatG~_?X SG>{p%P2{oxnro+P!UX{Gdl_K> diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Maldives b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Maldives deleted file mode 100644 index 7c839cfa9bd62842cf23f01d5195b239bc5a437c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 199 zcmWHE%1kq2zzdjxvLMXU03_b(AD&VF|NnnRCME_3mlr@05Xr*8;1<BZ;o}>^;0wgs l2Br)lBp3`d?|;~~`4S)+WC6(3dLWyiC0sT@tL$`5xd3Z|CHMdU diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Mauritius b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Mauritius deleted file mode 100644 index 17f26169904928e4061e4ee58bdf7a6c62001524..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 241 zcmWHE%1kq2zzf)bvdlot(^=0tLxT0KgT(D315f5@4?NHHU#S28|34EW5Hc|^n7#m+ z;}*ck!oXnRz`)_-8^WM%U<$-03?U@g12pnK$S#m+Ap5{H&`uByvKLGP?FP}r+RtSJ KbcLO+2^Rpsttt-y diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Mayotte b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Mayotte deleted file mode 100644 index 9dcfc19c56e62b12b730f4335b34479695f273f5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 265 zcmWHE%1kq2zzbM`vLGzd{r}>hjqh$nY&rhm!ojy|BhKVhU14NmWM*PuP-+1gp{&8c z!oZ+qz`(`8ptgpA55o5G4PnqWFfuk^aCHQ;OiUR<NU-)l5P+-((ID$VG{^}c8srQR OO@ULmfUeRt<^llo>q3(N diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Reunion b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Indian/Reunion deleted file mode 100644 index dfe08313dffde345044d5053e3359f92163d3e38..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 165 zcmWHE%1kq2zzdjwvLMVc@r-3d{r~^}85tQEOu$+!92i)9d_x$t4NMq9NH7U#$bXP& RAVYAQ$YldG*G|`j3jo2r7;yjq diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Iran b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Iran deleted file mode 100644 index 8cec5ad7de2f2c14dd4b0a6c375d7198ef7429b6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2582 zcmchYYfP499L66Mg&7_KDr+uXW>A2@`>OBl2?$bdK?RXRc}!GL6DS2rJfewdKnY<& ziidzg(ZV2aQb-f(1|iY#6i{Yv;wHmQ+)Ul*xi06|`jWw(_s5^>8hp8adm?8ojk6g4 z__fGP9n5D)!Sc2GT&uGlaBROEnCulWC_BJsQ0KUSC!^xE^P~{vV!Nqby`EC;!&0?- z>u&Y(>0SDjnirHuS+n%q6D_>5d+U)Kwkq!=oAg;wEque5X-nWOWwmtaQ6o~+XxHI# zOy5#5=1#P>U2jw3!Zta!evlYfHBgQ}m?tI_1nP;ITKTO`mHr72M8KR<{c4!E3iKbT zgM2Gg@YQ-L&xeUAb<<_Y(H0R}lCG!bJE&<}D&_RF@gi(VhYp{esAhyF=!l88)lAQQ zGIFS!i0a>>qm5ZAy30|<{E;nQKbs}rsC5yuj-1f5izll&x!rPZMw*zH;-=@vA5w3| zl<5T_78NV5$b}wpV$pLhda+Z!T6{lP#&tG{`1VG*q&Y$?t?ALr$~UXG_FCogoGOu! z9;Xvm-c(7k1@i5vVd9-hL*)uvu~_+1giaoONu@Ys$dr3dBDJGRzuW4s-aGB5S5?=l zw6Ya)b>UsHCaYMl-Qc0tC0>^67t9xSz3hA2_v-UlzYW7jU>)YCy<zwY!_hD%huaM> z3=v>B8-~BMd-~z;r%sDBBF)Fc$7=O4KS!I-C_LsB`R^-hc(k$}^9xG@u{Qj7EDpr# zKrD|m*9T&OAXW%si6GVpVv(e|N)XEgu}%;R1+h{PO9io35Q_z|S`f<xv0e}h2C-rg zO9ruK(p)r%RfAYIh;@TlIEa;lSUQNcgIGL>)q_|*i1mXo0E7h~OaNg62qQpP0m2Lr zc7QMhge4$M0bvUWV?bB~!W<CxfG`MzMWksG2%A6{1;Q#2W`VE^gkc~o17R8n+dvox z!a5M<fv^vRfgmg-O%p-b2*OAZR)R1Sgq<J^1z{-&Q$g4Y!dMX2f-o0^y&wz*VKE4k zNz-N!MuV^#gxMhM24Oe|%R!h9!gdhGgRmalFk>F?^q_0JH(Iu{ziGrX?7#0)$9!|& zQ0AMv?=sK0zK;2pi)(p*(9oOrR#ndawu3hIKg_?zJTr3{^Q_f_nP(>yGXH4qZr&e< z59htzubKTE-)Q!8huJg##CaR@JUbinyxY~xcl>#r_oo*EdGD;f#eV+LRQ3x>hBN<c zXDRbtTVj~+Ue(ULaA_OwJ#%7t?+qQu{=SKM?C<vsV*dH_^~{U<KlHz-=K=HLuKVnl zTutZw#aVCmzdTjRe(8}|<_C&8m><mD!MrSE2=hb9^~?{)hcW*uW;*Y$r?l`c7aQ3> z;^D~tH_uiwuW%aAyyD&s=9QgE%)f0<<bCu^H*Zz5kNv80H}=2VbDsIJoY~Ber#mvQ zUYX6jW?>fZ@1tFKpLp#g`zLL|?Ef&LoB651Y0PUK+?m(@b(neGjYGVDY_szIso@Iy zx;l>i`Z8DM4TS~FPiF-)Z(QHRyeX-X_s_8rywA)q*l!NXVE?Se%KY4mRm^{JiD%x@ zr;~ZhotwPRcdX!j;o?yCFV+{ce@V?`e)+&<=D+4=FmKItV&1mq3Eu6A+j;*s*Ps30 y!|MK*x8&n}2S57j|INF&-vqv){k*K>tUl(?=KI;tGsHI5+cL^C#4^Tevftk%?{cC5 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Israel b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Israel deleted file mode 100644 index 1ebd0664aa29c0abd722661f761031ec0304631c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2388 zcmd_qZ%kEn9LMqRO}t*foJ^@^$e%I_#mnWdRFaCKU?8`+F@%6)1ZE)}lgJeEm)c)U zw-&XgqFcm9rNg4O=Au^9Xd}28i&V_hACLmvX$1;P?Yz(0SnE+wdeZmq+}GLVDWA8m za6?6+{Nn<xUwF6%>)}0ASznEwjORPnc1y=ZvwV@dUv>5msW0ETB3++HNcY~I;%{k^ zuXfeR$rpRo*X6CMr!rW23q7j$T!DNW_nA5sUM8n!UX;^AemT>YBz+&I$ywti`L3-? zooo778TB>teSV$%&|aZ_OevM08Z%Y@b<1R++LZGlC)Hr|VKq3oRa~|8hU;>xKXB|9 zEvPxsKkMf|wAoQb+MJ0K+Kqdvw6OL|#@r`r{o$QgwFvEXZ{&`nT2$8i{+mh~jhiEj zz4Hn^+AXrg8y!4iM1M2jzjdhFxb2fE-k6?YZGKCHf5EYGBlZP{f8oAWhP$-I8@DaS z@MIqM$7jB3BrLA-CdR*~CC$0wPY!9&l7DUXE(&m|McocPb*xm~-ZyUC;UCfOJW`}B ze&djycIaL0uAMvdCA9~QrJGaqW!@$&J$tV#&&<_V#BP#|@G*1c^gLNPTxPBsPL|B` zqk2~7^|HEszj^oD<C48Q(9CHFRcoHxr{`8*RNj(w^B&(Rb#G;so|kk?`LY-2_su?_ z@?)>n^MBv23PNMdf}VA1?P#!B*tT31^^BPJAJC+@t=lZAOPA7Dj+$EWJXu%Qr9Y77 zl(OPh{lTz7DNlP@uW$ya^>eHB_5B0tq09ODhT|RT;j^jwBX7Q?Do^;#jnC{>Rm~~p zqvcgffA$7*)0%pDtbD@U?A|EV8GYvCGjgTIJ+9YWh?gxh&gfgZX33KmKGL@y9+hof z2ld+5LR8(6r}d|5epB1`l<5xVHB%-(0h6zjZ&RI9ozq;?T=?I7M53J5|GGq8k^qtU z9*0XLEK;V6q%L*L{QEDHf6dPE$!hD#T46nTXuXIy91gzzdJ*yci^W~FF8_m1Cy?bK z>$9~Mh^!D<BC<wgk;p2MWg_cD7K*GCSt_ztTWhh%YLVq4>$SBOjI0=0GO}i5(a5Ti zWh3iG7LKeOSvs<IWbw%Ak>%T3>*pwdtyKY}1V{~#A|O>j%7D}XDFjjpq!dUkkYXU! zK+1vC11Shn5u_xxR!xwiAXP!ig46{m3{n}SG)Qfb;vm&Q%7fGgDG*X2q(rt>jgTVQ zT2(^IgwzQs6jCXqR7kCmVj<N+%7xSmDHun^kdkrK3@MteRW+n+9Cbqq$5A<?bR4xq ziicDWDIZclq<}~TkrE;`M2d)1(bg&>Qb${>kVqwwQX;iPipfz;q?{b}L<-7LQKY0C zHARZbQB|a@NL_8M!XlMLN{iGMDK1i7q`XLdkpd$XMoP?4W2DF&RYuCpQD<AL&>WSv ywMxxVYoyp5)keyV)Eg-{{y!@oWEFm4f|dH%oJ4n$J1H(9B{nDC<4$&ag8l@yuiuRT diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Jamaica b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Jamaica deleted file mode 100644 index 2a9b7fd52d37a1ffe9fc589daa04d88c6c71a6e0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 482 zcmbu*F;Buk9ES0uk_c^)3WDIMQyobh+%-Uyi7q;I5!0=!3o!vT4otAP8W#r=1_s#J z{0waO1x)S}c>W(|V`9AK?l*LL-sn2%HPo-CDu1(bgL`?##rfCvsGjD7w>UqY7}q?; zo_<LE^{XzdZquFRP#50^CV1)T-RB!qx@+lj(lmQl$GXxEP4(2*`=MuQhhbdLeVPNu zi!;vF51+LQN2$%5wRSmEIcq;w8UL~qsSCO1UAbqGivCbw<s?r>eWXN!6g5cEMyW!| okUFFgsYFVVTBI1MM#_<TWC3IaWC>&qWD#T){QokpOmyOY16WpdI{*Lx diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Japan b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Japan deleted file mode 100644 index 26f4d34d67b46513491f26c2e661c6e653cc130d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 309 zcmWHE%1kq2zyK^j5fBCeP9O%cc^ZJkbvvel>u)1J-1zaU;O1HD54YJFKHOd_`{B;B zM<4F?{Qtnr$OM5549(0y^$a}=7=fDWCNOY7NFU!21}_&N4h{iHGlFmk36A&=1gVFX r6o6=uW56`fK_D9BC=d;D7>EWr4om|b2%<rb1kq$Wlndx;T}v(iZ^UHp diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Kwajalein b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Kwajalein deleted file mode 100644 index 1a7975fad7f7e96f7101eb3c64c9b420eeebb621..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 316 zcmWHE%1kq2zzf)cvTQ&s(Eub4zBRpY@)cLYdAG(7|J$SkbjtV~>i_@$&&b5g$im9X zz%b_lP!+?h4Gb&{3_S}NI2ah}CNS{){~zwaAi%(|;sAq)k8cQrwxJ;q8!%`aSTg7u z8Ufix3?U>q1!&{{Ix`6c5Djt?hz2<eM1!3MVgQ{7atp|bAi5qXL<MJZ*#I4D2Xr(S E0Dm)39RL6T diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Libya b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Libya deleted file mode 100644 index 07b393bb7db14cef1e906ebe63cfbbe8cddc79d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 625 zcmb`@&nrYh0KoCtT?f{Wo{Q(l;<399B=szg#O_6Gtap+!4%F^xj&jiEPvGPrIXXyc z%Rvq<PFu=NqS>-3N{@?jVZM*EQs%vx@B49?`FM-@HCOyP9P_uv%;tl)i^Sd8iFF@8 zl9lyqtMa(2t3%_edRW%a*-O7=ds5o9@5=rd(5+AXe%tM`Y%d@C9p?`+R@(48_if#^ zQ?I(WUZkU@RnN+%?#*4PcsimJsj#0+j>*1>Q{T<L%Hi~=N{tls+}^I3_il>0e5n`? z1y|&!-*2qu3%3vrOPnO;gv@@MEK$d^Xq=h##8hU1#S<Aby+0iK(+mzyIXne`f)La| zP%wfT5DE$#0)~PU)BsVCC{PqE3K#{A0!P8408$VskQ7V`C<T=QOTnc8Q;;dp6l@0I N^k31VMt;zZegQ-UsTu$P diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/MET b/venv/lib/python3.8/site-packages/pytz/zoneinfo/MET deleted file mode 100644 index 4a826bb185531c34eb37959037c68fbf08c23f71..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2094 zcmdVaUrd#C9LMp8h?UIfiw1`T#3DlL$bU!;Qac`)$)S{!kxFPFY7xbW7?j2;=3FuN zsj-|x(u%QaMqOa7p|$>w7LwIi!*Xr8vVU`K=IqZ{{oYSqcGF!wXM0{}zpLls_jyOx zZEG&_{_(l+@6%mQ{?F*28Q9oAdHl@2sbLKa9?~;!Nc(&CXlzEC#!s!Xqb~+D@m$D0 zeyYTdJ(^>m#8U0knq|6Vuu(}*%&|**!m{=<B{$`2Ry0ksBP;B(;@^~#{i9N6f2lzH zQ3cMvskD=?=<?4FXwJJ&D*f;g%Q!e}nfvzJ++JDM_D5`9OU$m=&}dgyM=iTNY*z)# zEGHw^uAZ4@xd|cVo-5J(Z*sI?GF8{Sf03>o`9;CO@3pY+xbk{FQhxhk6*Rr9!ulyI zij7!t#i*66dD==d2du29)5@m1ZBcrk7M<8+i+}IXk|QCz{);-54>hP_bct@*xm-*8 zGqkKZTg!VE+l`e83N@wMikwplho-GE;X_qre`QstzqOU|Z`;a=F}vyH^R{aEC958P zOOf5ZR&(%K-Q3!0xAZ=y)weyaH7%P}dtHm7)m6GRP@}cM1zLN)Ky@jVR`>ZV-F|Mq zt$Xcft)EP^4F{5~e&i>+qx-Bi^i9~thDqDB;|JZj^mS{jA6HY>UfWzTtmcakX-lTG z<-0xFIvvxtu`b<pBC5MzSg)23+U%ZP6>1%-wR^W_>Asz%*0#FbV$A`&zi_U#hkvyP zl0EClPf^F2udOrbygHA)XI-bK^x&&Q_Rz$rw(osMJBA1JaMz%^cXun!yCD9*@bkPR z^AbESV_uxQwtu}jiG*vTUL+iKhjDSye{u2ua1WQ?*9`y}0Wt(+49FmmQ6R%W#(@k3 z83{5JWGu*F+y{D$1{n@A9%Mksh>#&6V?qXnj0zbRGA>^?Fl1!N(2%hqgF{A#3=bI} zGC*X6$Pke+B7;Omi3}4NCo)i9H&SG%$XJoVBBMoyi;Nc;Ffw9f$jF$HK_jC^hK-CH z8Mv<-IWlx#H+E$3$mo&bBjZN`fJ6WZ0TKfw2uKu=Fd%V20)a#V35BnV1riKj7Y!sF zNIZ~$AQ3@Ag2V&~3KA70EJ$3Cz#x%9LgVXVg9OLdMF$BF5+5W$NQ96OAu&RNghUAm z6A~vRP)MYZP$98Gg5~R?g@g-<7ZNZeVo1o4m?1$!qK1SGi5n6)ByvdTkk}!?^L5cf u!sqMahXfFbAQD0(hDZ>RDB}MvjESz03kzvwFjAaXnpY5v6c%89apIpo*$oZ= diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/MST b/venv/lib/python3.8/site-packages/pytz/zoneinfo/MST deleted file mode 100644 index c93a58eee8b32f672fd3a96ca3e6ada5b0a0e168..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 114 lcmWHE%1kq2AP5+NDp>yipF4qp!8bUBA%rYlTtKbnTmW*V4CVj; diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/MST7MDT b/venv/lib/python3.8/site-packages/pytz/zoneinfo/MST7MDT deleted file mode 100644 index 4506a6e150dfd73884811c8c0f5a0e21dc76a756..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2310 zcmdtiYfRO39LMn=s39jVzb+U8nrTT8AfP9K%*Y@@Ize~@G{PwG>}UmEI%y&P42to< z`CS>aOoDFKnt5Hbv7xTv+REl|Yg!AtUo0D4wpd(FzxU6FJ?dHOd-ngo{yWb<Z~w~R z>Rk1Yn_~ar;hwh--@5ya0(rSF%Je*wBE2vEXg=(Wk-<5CG!ND%s=r1a)1yDssIjxv zdi;X|HE}dwhu=(5YFDz3=$KHEkB{p~>ypgm`sp&IV$57tI4V)uLndmwSEBWC6TR=C z_6)ybF8`ueV$K~?vB%pa?!8_W|5lIIFSMyEI-k;4Zf;ap1sn9$D@s&C>79C7eww-_ z?M9tAyVy*R_UNR@RFm}ETuJ^a+N2Cll^G{~GBXcekZXHSnOUJ3`nqlV&Ftl2J!j2F z>U!^&`i7<NsJRL6>(q2nsT1cV&9h#m4V{qm3x0J||ErR5rrBh6KP_2@E6u#tfMh?n zz~ltlb?$~~W`4<Py`XZ$cvJ7vH|Kt87DlD(yyQPs-uE#&fApLxIQfgd<+DDu=zvFV z?c1Xk@Az46+r3p4HhnC&x9>Jf$`8mL4O>jnyl17jXq74ceL$CFwy2Ubdv$4Sohm)t zsh3_XRAn!{E_Z)YYkVyoa?iVqO?holD!OKwdl!{SWhl}tOUV@f@^6fPEMBU-Cr#D2 z8M<cX*Q#b9POq34P%B>>*7ptVRkiJd`u_e-Ro8Gtuj*c_9`K!(`i>6sVCErtC=fIa zu{)))q|7v43`rn0(*#b{NH8ki1osuln(ux!YrCrT!>8laBcXi#=>B2VRF$locMPg^ z-f_LY>4@5pa9(dL?@}8lMkSPY$b^PImraQ~&8GfivUwzAp6KqCC(qWHmew}ea<ss- z)-}r3T`49)MX1P0_Vr)-g~NM9O%8|O?uk(DJ=MKqF8%K-@+;pm`&8Sf!p}q^F1`H! zVoYIs3<?<)GAv|V$iR@1IqlGpu_1#)Mu!X!-T3%mfSes6Fhq_qB7;Omi3}4NCo)i{ z9Vs$YryVOYSY))wa5=_{447lY$dEb4j0~D%)X1<o#*GY|W8}!tk+CC#ciPb-!$-!C z1OSNu5&|R!NDz=HAYtH$0}=?1NFbqb+E^gLaN1}f;oyh|5)dRJNJx;FAVEQ*f`kQ$ z3lbP4GDv8U*dW1i+UOwR;fN0sAdUzjA>xP;5+sf&Az?z|gaitS6cQ?@jTI6sr;Qd8 zE~kwb5-^U4At6Izh6D|X8WJ`nZb;ye$RVL~+Snn%bK2-3;d9#fApzuwAQD237$QOB zh$0e3jyNKLL?VfV5{V@eOs9<|5>BU$ClXMnjVKaQB&JAEIiiY$l_Rc5U^ya-gq9<= zNN}Atx=47PHoi!Joi@Tqh>;j0K}MpCgc*r5{_g_qvE5#1`<>yNpOu@Ho#D&L$;!#f G_WTVQwMumW diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Mexico/BajaNorte b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Mexico/BajaNorte deleted file mode 100644 index ada6bf78b2815d3d99c97d521ab9a6b35c8af8c3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2342 zcmdtiUrg0y9LMn=gpw%wq@u(hds2#laOA%z_Rpvz$O)7qi5Z#kXHW)-p%f81w$_^C ziw?_G^yKV<wIXJb{bS^oTWhSsR+x=3Q(zcHtQD2x^t^vvcGX?$clJE5-_G6d;`8?J zsIE+N{_)JU|8RIZ?BPA~wccM_x*7}Xx~H3_dMnH8-i=ny>9Fak&n6DH46gd6Zt(c~ zb>BpnIz#PmPhD)@EZ^sCl}lyGaycPGM!orJZ1EN~9-pMfr_<F$=t4Cy7@@9=PN^Sy zep8cY2i1@5=hgg?ZnNP0fC}$#Hw)kER*Smc)arP<y6#!giyQ0JlIp#BY3Vi<k>}UT z)~!{`6S8#V%3`^GUZjo+&XlO>3=@5Exx@@EGqE54E-QLw%nh$z5Z$m^-+1sNSy>XU zSJiy0;xd2IH|2k*ZjSg;$0v5G_}NL55Z0m+hCern6T8*wz8;fwu33^hj~dUZU9zV6 zag%a%qoh_H(P{N@lJ4E7Gm7U*W_*dxN*kB8q1ie+W{%1pi_+`<98>GhUe!4lK2;mu ziZr);@VdIS?GJO?i-*<iwcnXLTDxRpVV}9P{5i>8W6WK-d*tp#hm1F_P`op*=)90r z$s0PT^Dixt%`crY1z*>Quc^b_(_0{gJNKKSV;<SEq10?`P*NO|WBl8u#eX%{lw^J- zC70Lh?JIs(+dqlXrL*VMj+3+czTtP&&ejoqf8X<}to)3AptDi!@(r5@pXrd@$^GV` zs{K+Pe!^6EOQmA6)l|jjNYy~4sSb^m>Nhr-n$dtfe5^u0@<oi=)8N&QcF(HXk_27X zHliNOny>fPo>BD?lX_p_NwqI9&opHBOT+LLb0G4B9OxS`jWezCL}#~oa;Q?8n%m7& zr#DG+S-pAsg+vJo4hp^|IAo5!{yV=w;7Ebv1OhLM6A}otwK&)E9<;!{m3uEO@cA8I zvEM1;<l1wuJw<*7<2XTo-~N9wu7G_Q7&0<sXvo-*!6BnVhKG#L)eaCDAu>c{jL0C7 zQ6j@c#)%9R8L6usDl%4AJ6L42$Z(PIA_L~j88I?sWX#B*kx?VVM#hZ{92q$>bY$$v z;E~ZI!$-!C1i;ls00{vS10)DY6p%0=aX<orL;?u~5(^|4NHmaexY~Fi0dchvK|+GW z1PKZf6(lT3T#&#ZkwHR(#0Cit5*;KwNPLh0x!MRJAwpt=1PO@}5+)>0NT85NA)!KI zg#-(U77{KbUP!=PZN!j}x!RZ^K|`X3gbj%s5;!DsNa&E*A;CkUhlJ17#t#XgtBoKM zLRT9@B#1~9kuV~0L;{IK5(y;|OC*>`G?8#3@k9dZY9oq-)YZlm3974&DiT&Cu1H{! z$ReRdVv7V9i7paeB)&+1U2TMs5WCtKBSChxQAWay#2E=R5@{sVNUZUHAM7w&^K4u5 UBwxBG&6ASkOHK8pdQ!sv0^LWd&Hw-a diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Mexico/BajaSur b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Mexico/BajaSur deleted file mode 100644 index e4a785743d75f939c3e4798ebe7c79d38e4cfd08..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1526 zcmd6mduUH#9EZPSF0IvGatV=GiPmn+W@hYSGxpoYew!J#-)4R@cC}d>w!LL3a(Smj z%}^pNZHZYf<uAE}keW#?$(EEgEko-#&+)(Vhw^!Q&vQEG-{*1XmUzSEkK1bh9dF+$ z7rO>3JBG^py1dz*TL~{c-Tq5G-J=HwpM0wF^t9X<6sgo<#my?bdYWFG>{UxPjOd63 zYt+*4UL84Mk&2r2O``h!)v}*&BzkzVS>E+RVmkfIiaTu*d;GIm+1ezlDxR6R=2jh_ z-f0qw8gydF39~veUnd3BnB>4XojlT_Qhev@l%8s}_QN>6t~*PmKAk77(~&Ceny;kS z%}^OfKFa!n2(zK|p=8EQH}2G{k~R0c$qqUq8|AIZnR;30^xZR?h7ar9`{&H&*QI*P zmAh)|%`}~N=&Z^=8LB-cS`{?9q%fsWZOaRhqJ@cSd+a3fPWG7M*<Yo2DBkQCeJv#~ z1I^BNw`AA#@uu{_D_zzyV9GDu)D=~aP36H;x+=F{?e^B|>gY$RCTX+YGqYXQhSW*z zkE5zCAXn;oD^&fL7}<M!z1sJDj_kisW*Ry~8V{tKrep8LXN+^k`uP5XV_9cnL@cY# zh_7X}pO=Z2bzF--?>_4H_f(f#T$yf3uy2NaU5RdS|AjP`J;Z^?0}%)!5kw@1woDMA z;BTprvr_X!E{I?d$snRZWP=C?kq#oBLt8$GfD8#CA~Ixz2+5EVA|^vlh@cQjA)-QL zg$N6g79y@gTV9C34sD4cB12?`2+fchA~r*Ah~Ny#A)+&6hX~J*9wI(Nen<cg?Fb+t zKw^Ld0f_<<1|$whAdpBPp)g{B1jC315)LCCNI(wlh#(;`VuA$4hzb%GBrZr`kjNmR zL1Kdh2Z;_69wa_UfDY{lAt5@nV}u0Bh!PSeBTh)5j7Z^s8>*jOZlqmokZVbBSa4{N MD=aiPA~@9V7s`x}c>n+a diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Mexico/General b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Mexico/General deleted file mode 100644 index e7fb6f2953d123efbc2550f450decd794b017d4f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1584 zcmd6m*-Mo{07pkNDie&#9$G*m5W&p7va(E5OmA-2B`dv}Ub9R`EwQp3Pz0e&AEHHs zDB38p9x}}yBv3FC!-&dAE)*g4&=g40_BH4G1A?H3e#6Z9;CnsCSy17Q5Pw{W`8(U( z#aDW#WY3o>Pp>=Ibw6R;)#n%E>igNMhbHg1hR;T2jO2XwjC^>LG3Gt&8M~jGF>yY? z^SZwIX?S_Ph^U(@Ba`z*RMrO>9TY2KBA&>#bC!#B%ck_Y_rJvY?~irtw2#`*`$%u> z`JpxqwClLjlWKF9)LW_tReZ}Sxi$TgN+_+CiECQaw!}=C<nLC=t0HCcOtVPw36Lo- z%f$A#Uu9}vvPc_Uq#fsi#g1FkI=x}O$T;~zXBG#ktjd0!9Y0Sw)4Fs{;764ka$M($ zQI#KXLFRjU)XwQfSuohCc0DhYyKmeUd+u$Kg>4<8=*&v#s;CvkC*pKTic{<@4AiB; zF`_KaTe}x#sqz)?borMkweRP!t{7jU_P@EV58RzmmBT~wVCRIYx_V7k*F03RwN2I( zyb`tU1F|l5KpaYP$iqv!Mg5uzUH`2~H2A0LhKXWv<kM<>^g)6+Hs-GzFBhrfw?FF> z&GD+K{h9Xi=FBq3$A0<xx5u(B`w3xL-5tWmvTj}!b1kd?j+dYPE=Y4Yg(KT361a)x z<~fD)FFdl$a0%iQ#3_hZ5Vvd^zaWl5JcGDq)A$B)&ZhAW;vU35?8ZTchY%MTK0=&i zcnNWn;ipaGD8o~Ts}Nry&O*F}xC`+Y;xNQxh|3V4Ax=ZQhPVy!+oo}x;kixYI>UE} z^9=7H?lb&{G{EQp(gLIhNE47QAZ<YUfHVT>#HMKl(hH;+NH>sn82vyRVsr#)iP00J zDMnY2witau8iRCZ)3gTZ4bmK>J4kzw{vZuPI)t<c=@HT-qf1Dej6NZaGCH+sT4nTV t(=^NI7Sb-GUr57{jv+0>|Fvgd6L*Y>JH!zc8Xg)J;s_55jSda-{SB~`;=}*| diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/NZ b/venv/lib/python3.8/site-packages/pytz/zoneinfo/NZ deleted file mode 100644 index 6575fdce31183d8238b18f2f30ab5b9227c7071c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2437 zcmd_rdrXye9LMqJpwhVKWemws!@O`gTvUW2LIninl6fRN8GVz42MwVlp$lXgnPXVf zmaRD|$pO<6kpwLTF@#zdvNfreebbp|D>PSA%fg=bv;M3<`l~;Bp6&Pg?QG|tvwhyj z<t{CbH~#jy;jd43T5=!1(K^~X+CBT1ZZ2rAK4%_ScuqPB`ptL3`{iI_tJyiKRk}jz z&8{E&^w8BZ^YBN_`tDGk`QBNN9(nt+=jibdwR`K3r>AMJ9$R<V)4OS_9?#wBdB3Pa z`<%6&6WI;YA1I!IsB#&&Qe&R{>eW=AkU!LC?{4+IxLf=he^>vZV;WF<S_8Y9G^nsg zZ+xXr$ENJkan&U{KI~bYP>`h)Mv65!F;auiZ<3IynG({!T0$KW656~-Zu-t&CT*T2 zH}_nSuo6F+{Q96w$rzTY8{6fUSRV~9{Y0k){h+rx9Wvc(fzAjxD>Kea)0xA4GOO2H zBR+1H$UWf__0|@Nt{)@LhP4v2=Dfs~<w)G(4<tUnRA)!*kvR!VbgplMBm_rm!q2Tb z?{bhPeqOIhUtH4L4wUKb-GP$4Jx}jw{7F*Q$LXE5Cna@duFNm&kOj%HvM}XkNt-lI z(!;7H{n{^*G2)g*SL!tLbh2cfD$&J9!(>TkmS#5^lCvXHb8F5>UR8kJRXn0gB|`4b zP+gYlFRtmmx_t5l$@hL!^RExeJ>Ng41>d&IiW8=~yI+!f_tnYDmNvcbg%T-zew*H3 zo+V;d>H~R^vMMuQi(&%g!I_D=I`E<tk6kXsSN*i)(mXLw4QuIV6J<^3r@FT7nmn{) zzm~oDjjXHMuH_ZoQXy^f@QSbXk<@LnKIw>7PN|efC%&c|jC|Sf>(g4LiBkP#kv`TF zDvuvZ*C$#N^vPYTq-INq);^OaPno}|m&0q+KfT_g$NZ<SVKfa{b1?P|I7S=B8(oHv zVYKvcKRD<J<Zf7Z&g>kQk?UT@Vc*hRe9v$=4A;Nd-gWDl-<jQlY!KNYvPEQ%$R?3p zBHKjviEPx?+9|SCWUt6(k=-KOMfQtq7}+thWn|CDrjcDE+eY?{Y#iCSt+jPz@BB1u z-qzYZvVCO#NCS`#AT2<8fHVQ=0@4Pg4@e_ytxh1Vu(f)DG{e^F2GR~&s~<>1kd7cN zL3)BT1?dXX7NjpoW01}utwDN&G{@HJ4$>Z^KS+a+4k0Z<dW19y=@QZ=q)$krkWL}3 zLVATX%hu`^(k`T5NW+khAuU6ChBOW78qzkTZ%E^i&LOQsdWSU6*6JS8KBRw01Cb6Q zEkt^VG!f|{(nh3@NF$L>BCSMvi8K@GCelt@tDi_ik&YrQMS6-f73nI{R-~^;W0B4x ztwnl^G#BYE(q5#$wpN3Y4kIl_dW<v~=`zx0q|ZpBkxnD6MtY4j8|gOEZlvEx!)>jO zBP~aIjx-(VI?{He??~g3&g1`~^}hTCM90PFy3<@yIZ4jB&e*7&InFp|Y|L!mKLIzD B3|asH diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/NZ-CHAT b/venv/lib/python3.8/site-packages/pytz/zoneinfo/NZ-CHAT deleted file mode 100644 index c00410988272dec2ae70ede88720b4a46146a4d1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2068 zcmdVaYfRO39LMqhA$8-f<`|Nprg`CTJBN#4L}-AZAYJgJMD$7X9MDKh61s?HQaR^p z+O$X1EN2c|q;1qzfo|1$P?@dSW!X2|@<Bs$wQd@x-}_$=d(xxUIot2`Kj+EW*?ymQ zb4y1w?ET|w{NLYhck-OE%^jz{*!N~)<{y@L<e(*8IH=_Q%a-!laZBwzV`;CyVCiim zHu2d$n^bwgCileb%IqCBWo5lh8H-v*S<o`hJ*Lc=b;^8it+E0+$~v?}SACPBX-~}8 z)g$MX9ZS~q=TB-z?WksMJF0666Kz(<hc-L?d%HG2pg9SPZEotfntOJ(%^Q73^G{5$ zoDU8uI511OFYi>|uJOv>y<P?D&Z)4oQK6;pD;(*tqMQL0moBrCq}?jb$g|QP58HyD z)2-~2T~_|-MO%2R)2<s%Q^npUyT1PiRc;E|4ZWvS)w*1Z+FsM*ibCC3xlh&8CaWg9 zM>UszQteoami*FZb!RG6e>!GM-_F*up?YiR_tdyQXv?>pRa1AW-4q?Oo0X$mYRzt~ zN>THi6SiXdc||6?Xp#6y-S*w%w({$vTJ>(bwG2O_+h6HZ>q~=n$5S!2J-Ns3+)yvI zciCM{L9MQf*qVY=-94|&)}~!hbkYh%e@(X7#RY0VJ!%~vPu04ik8J(mCEc_CRqK5E zE8W|@*EVb%)<zBLzExk^{Z)Iksr)VLn$e{Praotzy@)pd_NaARnR-57V-JpG>7h4j z?BT<u_Q-+N+Ojj#dbd|=Yy0oEH6D)##wA?wpS}}3Z{V`KjNXxIZ=B~HZw(}Q-mwO6 z;$LS&W3v|wg+nFoEGp&<yVLUm0k8RATzB_R<BNu>cOciEALQ!$y6cZj0GR<Y1!NA$ zB#>Dk(?I5dOaz$;G8JDp7i2QNZZ^nteBFGI3HiDiAyY!;giH#V6*4VkUdY6dnITg{ z=7vlTnH@4cUpGHwg2)V!DI#-3CW*`vnI<w%WTMDSk*OkcMJ9{P7MZTEn=dk9WX8yp zkvSuiMrMsn8<{sUab)Jm)RDO(lSgKcOyAedA4vd`0VD-T4v-`uSwPZ&<N-+pk_jXg zNG_0MAlX3Df#d^8h_A~Ck`g2*NK%ljAZbDJf+PmX43ZioH%M}j>>%ku@`EG@$&jy0 z5t1V$Nl2EEG$DCH5`|<6NfnYSBw0wdkaQvWLK22#3`v=<%Nde1Bx^|8kh~#@Lo$b? z4#^#oJYUy<|8e$`D*Ogk=7quwi%Z-Gm&MB5#`64<{K5jh%55yp54q<e_nh=6i{2Jl diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Navajo b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Navajo deleted file mode 100644 index 5fbe26b1d93d1acb2561c390c1e097d07f1a262e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2444 zcmdtjeN5F=9LMnkqQH%ZQ;8v<nU)CgtR#>b6-0<P2(NH8!YHnHS1a(Ln-=0RD8?U+ zvtrCL36!+fOng|gv7xTv+REl|Yg!BKxhxw!Y?8peo%dPwPk;4STVM9OuOIjS&-=Po z`_|@&f812_4G-6C9^R)b{@GWcUmFNlJ<liU-dDa?dprTXw{@E6E54}vI`*j#+N1RF zyx$s!>*B?gOursm&?$b8b?d7UesOi|Njd(VTTGm*mXq%nh`_OY8GIv2h@FWtq%9yq zpPH0YHYBL9x|w=v#e|wxIIhF9MpXC<xjIswP>}}?Nyq3Ob<M?I9d-V=h(6JxW8Uo* zv2XTB`ErZ6w*6Uo-Bypd-d8WDuPPC7rT5Ai`6=Rtlm#+=Zn2sf>5vJb$tvNO`8x57 zNR>1kp=X`^LCrpNN#EFeTFvp#k~i%*sOGK=%6aQP6gTI7E^k@(wwNFHo=i^FA~|qD zr#Lo>l#!D<^^!~6I=EM-oo!U<-OuTaBb6$%*{ic&TBNeQtuklR47IRitz1+&rgD?- zlegu3q85jz%DluYBJbNMnLmDB6rB1=-u~%;Skmv%cMR+nOFMqlckbFQ3L8GsceU<P zcbE6;d+N8TqRba{anTx8{Ogb`NpBJ*XZOp}=vq;Fq+Kq%Tqw$3eO)jAxJEgf+VuVJ zELG(-K3&l@M?J8lOjr6t)rzEa?OOSja!thQs@zkm>gzP=p8ch855>q;fg!QFZ&W@w zvR~A+4$FrI+eK~tQMsmjy?EGpM%T5qsYlWe>qoslRUh4{JtbwzbJ?%G$?3{_+O2)z zvC4O#K(G7eXSKeoT0V9rMm+A%mrooV6%AF1vaw@WY{;FI8yk*_O>r0G=JGDFIWVsM zd54vM<TJe`zEf=(Jg&En`PI|iz51DRZq?M>qPHC@P|dX-y?tkr3Jv-5Z%WwTuYY~@ z-y00>?i3;ze5)rU%)Dz6Vc(<dr(EuI31^XcR+y*SJQXgpA|XQThwERgFKDhdEUF(_ zA+khdjmRRARU*qo)@d~hMOKO|)oRv?EEZWUvRq`nR<mGa#mJJ8HKScLFRYp~%LdlX zv2bMN$kLIuBa25?Z#BzD)^9ZhKq`Qg0I2~-5s)fylmV#&M<I|(aFhb61xGQEYH*YT zsRvRJq#{;R5~L<bQIM)2WkKqK6b7jbQW~T-9K}JZ!%-fjK2}p8q(W9xBBVwfMMA2C zlnJR5QYfTSNU4xoA;m(fg_H}a7g8{!VpdZ!q-GpNL#oD6Hl%JGg+nUGQ97h{Nb!*B zA>~8rXEg;xDrhw&L~3X?MMSE|QAVVWNFk9*BBexXi4+s5CQ?qMo>o&(q@q?+QlzF< zQ&gm?9A!o7%28OPvK*yFYRgevq`F9Xk@_M9Mk;JIB}Qs&HAP0MY&B&@>WmZ`sWeBa zky>*U8>u!&xsiHv6db9z)s!5mxz!XMsk+sa9jQA~c%<@3>5<wa#mE15^&RHNV6pj8 VNOLaC$jQh`b7p5}WM^bK{s0D?lEVN1 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/PRC b/venv/lib/python3.8/site-packages/pytz/zoneinfo/PRC deleted file mode 100644 index 91f6f8bc2e234bafd484146986bdb289082c3588..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 561 zcmbu*zb^w}9LMo*sb7uZVlR)P+QDKF36WCLNNV90hMH8mol%_2lQ6N|X0Wt&|A0ig zYPz+k{ufWWnRwpMAJ9ZRm*-x?E%$l*C$;LT3_WT4b=2NzZC~|=C*8PAnz!SMZcTj$ zt?sL|$L>r!EJ$Z#%XIIr^!v`U`Pj?IXSr#5n@#x|uLk|}K=-#pGy8I==4y|zif-%k z``2;iyrCBIr}1LxMlH>RUUvCRWd{{6H&If#PQe>V40%K@diI|riW5nZK+9zLz?b5# zy+^+If0*`TPqbFdBNLIC$W&ym(@sWaJMDC2K9T^*fTTcjAW4ucNE)Zj!x|DHnUGXS cE+iR}4M~UOLlQb|MkJ;4e>qdO>B@TQ7g9&Lh5!Hn diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/PST8PDT b/venv/lib/python3.8/site-packages/pytz/zoneinfo/PST8PDT deleted file mode 100644 index 99d246baa35cb9c6f56d50adbec163452e2a47fa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2310 zcmdtieN5F=9LMnsio{c$9#A5%lbUo9u7H9l_MqY}m<Y!8CT1qa!ypY6LMS6!tg_}f z<WPIMeRZzonxSJhn?>YSt2KIn)+`%iZKbPNWo?nty`A^*&;IJa*17wg*KfbS?mwS* zU|mC9p64GY#(v@9^w@`Y6?(NqUOAO)<jG7q_`)CN<K3w;H1qeZL)Ej@#qlTfrSo-a z;!Lgn>%$TiKIzwy*D{sofLBL7ov5PQ67-~Px0uP*84|NP-b`5%C$Tv{nb<wcBu;%| z;*P$n<9|735=MI^@vA|VG|(+qzSXO)I`W2A&v&b<cN=|8d$YQ>VY|MrYK=-R4d|&0 z7pQ680-Z9W(p(>xqEn;uP3ndDa>KXNOxn;?Nq_H8GyV9u+<5S;(XDgzO^?50W(1S; z%*L<Pto)z#%`4tkvy(s98JQuK5grq7{4V7k`BXB0*rew4AD67*4wD_)E55#sW^Ttr zlCyWI$*q4*=QYnV^ZYG(e&rOCpApmrdFRc7*g{>H7NZK!rRs&3&Z$KoOz5JsAF0L1 zQsmZCudCa-F3RmM?ooF%eIrXckC>(9{j#j)SyMb$WO?xxv;4PV?azKj`G-&F(xlC* zv~Ry&F}6zG`BI;({Ib!M?d*|NZ>}`u>vu@SKA%~=xJvG7Ri-knNCImvn7~B31oOWz z!S5F7wbOr9Yu``PRpDW^?r>P&Gjc+$?;O?l_U~64YEJ9>LhWi}*@#p>)nhhg56J!X zJ4{W|A*uCOncA^Vsm~}f^@DZN5Swlqj+RK{_Yw2JzFNKcvoy7()vq7y4XdW0S8wea zRoe;@^!BFHsyTT~x0D}NEs;2BEgUedBR@)8$|2L%KPc_vo#x?CuRL<5&g|^ymPb#P zn2rt2^4Nh)6Xl8WL{GBUf9V&AbnWs?jznIzf6v`lxI6Lk_ln|xr=rq6ciX2Tz(k@h zUx9xyrieWZ3K<nLEM#2Bz>twS?a+|1A%jCkhYSzh_;_J}96Lf_h{za`K_a6>hKY<5 z8K~2a6d9`1juja!GFoJ~$as+fBO^wJjEor>G%{*r*vPn%fg>YFhK`IK8NAbu9vMC| zek1@$1dtFQF+hTVL;(o{5(gv@NF<O@IBhJDU^s0wkZ>UJKmvk91PKWe6C@}|RFJSB zaX|uuL<R{B5*s8qP8%I0JV<<y03i`VLWIN!2@(<|Buq%0kU$}kLPF)Vu|k67w9!Js z<+Sla0)|8k2^kVIBxp#~kgy?fLjs3H4hfyp#tsRd(?$;opVP(<2_O<dB!ox|ksu;b zM8b%~5eXy`NhFj=ERkS3Z8VW^I&D0WfI4kNk&q%WMS_Y%6$vX6S0u1VWRcJ!u|<OG zw9!Sv>$LGj0_?OAMna6l7zr{GWhBf<obi7b=y==hLfh}GvU$EdUrtt8ZmuuamlOXt D9#L8< diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Apia b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Apia deleted file mode 100644 index dab1f3f602b297cff53222906fe7c20230587395..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1097 zcmc)I&u`0d9LMobt*fML35UgY;e_bc?W;wX%(4SA$+`_)*|5EJ)^&btW3~D<LqdoH zMzZ5X960%MAPzDSkvMHmf{1q<+z>avKR(a?0TM3Se7=t+J$%3UzMiSBf$U22$4`U% zcdk2CC*9?8=@0WN6HK&BE%TF;5p5lNC#^p(Tx%<oX?ymUZju$Ud4uYfrumXu`dB*_ zf0T6ShNkVTY<+)Lx4pe9olkSxHGNgK-##NdZu+|OV!w2so6w%2jUu_c?rMujra7&> zwPmt<c|!ZjKS_2$hh)FZ)BewEB=_Qj4m_`vJ@;pHum4^4P2SP{m)^)=;ff9oPs_0Q za-j3I9&DPBk@|<4Uy_$Yl~X!u(lYw>lom80hhO&Ukw;Z>^uc;Pc5AgBzn+n?^NaMv z>2)%m`=;a8+Q6J(Nw6eT`VZfbF}{0U*7mq}W^H$~30gZMfv~lG?WWwAd$VStF;6s5 z(UMG=8qbT>xhuyr5ijOW+@$_u8~3<&aP2d9FKgKd*~#7BuobcwvRP5L8?qg;AF?5` zBeEs3C$cHBYf-l?vM;hRvNN(ZvNy6hvOBUpvOm%Q(gD%}(gV^2(go5+QP&632+|4C z3epSG4AKqK4$=?O5YiFS64DdW6w(#a7SdNy*BH_n(i+km(j3wq(jL+u(jd}dQMcv) hZZX{8s%)(BV$OJDb+SIXDq2??t4_wFp8F9G{{{?RF~k4> diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Auckland b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Auckland deleted file mode 100644 index 6575fdce31183d8238b18f2f30ab5b9227c7071c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2437 zcmd_rdrXye9LMqJpwhVKWemws!@O`gTvUW2LIninl6fRN8GVz42MwVlp$lXgnPXVf zmaRD|$pO<6kpwLTF@#zdvNfreebbp|D>PSA%fg=bv;M3<`l~;Bp6&Pg?QG|tvwhyj z<t{CbH~#jy;jd43T5=!1(K^~X+CBT1ZZ2rAK4%_ScuqPB`ptL3`{iI_tJyiKRk}jz z&8{E&^w8BZ^YBN_`tDGk`QBNN9(nt+=jibdwR`K3r>AMJ9$R<V)4OS_9?#wBdB3Pa z`<%6&6WI;YA1I!IsB#&&Qe&R{>eW=AkU!LC?{4+IxLf=he^>vZV;WF<S_8Y9G^nsg zZ+xXr$ENJkan&U{KI~bYP>`h)Mv65!F;auiZ<3IynG({!T0$KW656~-Zu-t&CT*T2 zH}_nSuo6F+{Q96w$rzTY8{6fUSRV~9{Y0k){h+rx9Wvc(fzAjxD>Kea)0xA4GOO2H zBR+1H$UWf__0|@Nt{)@LhP4v2=Dfs~<w)G(4<tUnRA)!*kvR!VbgplMBm_rm!q2Tb z?{bhPeqOIhUtH4L4wUKb-GP$4Jx}jw{7F*Q$LXE5Cna@duFNm&kOj%HvM}XkNt-lI z(!;7H{n{^*G2)g*SL!tLbh2cfD$&J9!(>TkmS#5^lCvXHb8F5>UR8kJRXn0gB|`4b zP+gYlFRtmmx_t5l$@hL!^RExeJ>Ng41>d&IiW8=~yI+!f_tnYDmNvcbg%T-zew*H3 zo+V;d>H~R^vMMuQi(&%g!I_D=I`E<tk6kXsSN*i)(mXLw4QuIV6J<^3r@FT7nmn{) zzm~oDjjXHMuH_ZoQXy^f@QSbXk<@LnKIw>7PN|efC%&c|jC|Sf>(g4LiBkP#kv`TF zDvuvZ*C$#N^vPYTq-INq);^OaPno}|m&0q+KfT_g$NZ<SVKfa{b1?P|I7S=B8(oHv zVYKvcKRD<J<Zf7Z&g>kQk?UT@Vc*hRe9v$=4A;Nd-gWDl-<jQlY!KNYvPEQ%$R?3p zBHKjviEPx?+9|SCWUt6(k=-KOMfQtq7}+thWn|CDrjcDE+eY?{Y#iCSt+jPz@BB1u z-qzYZvVCO#NCS`#AT2<8fHVQ=0@4Pg4@e_ytxh1Vu(f)DG{e^F2GR~&s~<>1kd7cN zL3)BT1?dXX7NjpoW01}utwDN&G{@HJ4$>Z^KS+a+4k0Z<dW19y=@QZ=q)$krkWL}3 zLVATX%hu`^(k`T5NW+khAuU6ChBOW78qzkTZ%E^i&LOQsdWSU6*6JS8KBRw01Cb6Q zEkt^VG!f|{(nh3@NF$L>BCSMvi8K@GCelt@tDi_ik&YrQMS6-f73nI{R-~^;W0B4x ztwnl^G#BYE(q5#$wpN3Y4kIl_dW<v~=`zx0q|ZpBkxnD6MtY4j8|gOEZlvEx!)>jO zBP~aIjx-(VI?{He??~g3&g1`~^}hTCM90PFy3<@yIZ4jB&e*7&InFp|Y|L!mKLIzD B3|asH diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Bougainville b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Bougainville deleted file mode 100644 index 2892d268094ea785b045e53cb441a551672aabd0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 268 zcmWHE%1kq2zzbM`vMfL>&;TUPIGZJ0($4u1GVgjr{r~^}8JQTFnHd-+-T=xm^eg}= ztee2V!N4$U0|SqbZwQ07p#g)ofhCYOWC$T_85__TkcFZ^v;T)}3(^45MQ@i(0MQ`J zK{Ut#Ap1a$0MYe8F-9h4CKjOW5SMg*0J#L{9!{`(c){)w1i2@`7tK*zHbAG@=^7ex F0RVS6KXU*8 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Chatham b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Chatham deleted file mode 100644 index c00410988272dec2ae70ede88720b4a46146a4d1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2068 zcmdVaYfRO39LMqhA$8-f<`|Nprg`CTJBN#4L}-AZAYJgJMD$7X9MDKh61s?HQaR^p z+O$X1EN2c|q;1qzfo|1$P?@dSW!X2|@<Bs$wQd@x-}_$=d(xxUIot2`Kj+EW*?ymQ zb4y1w?ET|w{NLYhck-OE%^jz{*!N~)<{y@L<e(*8IH=_Q%a-!laZBwzV`;CyVCiim zHu2d$n^bwgCileb%IqCBWo5lh8H-v*S<o`hJ*Lc=b;^8it+E0+$~v?}SACPBX-~}8 z)g$MX9ZS~q=TB-z?WksMJF0666Kz(<hc-L?d%HG2pg9SPZEotfntOJ(%^Q73^G{5$ zoDU8uI511OFYi>|uJOv>y<P?D&Z)4oQK6;pD;(*tqMQL0moBrCq}?jb$g|QP58HyD z)2-~2T~_|-MO%2R)2<s%Q^npUyT1PiRc;E|4ZWvS)w*1Z+FsM*ibCC3xlh&8CaWg9 zM>UszQteoami*FZb!RG6e>!GM-_F*up?YiR_tdyQXv?>pRa1AW-4q?Oo0X$mYRzt~ zN>THi6SiXdc||6?Xp#6y-S*w%w({$vTJ>(bwG2O_+h6HZ>q~=n$5S!2J-Ns3+)yvI zciCM{L9MQf*qVY=-94|&)}~!hbkYh%e@(X7#RY0VJ!%~vPu04ik8J(mCEc_CRqK5E zE8W|@*EVb%)<zBLzExk^{Z)Iksr)VLn$e{Praotzy@)pd_NaARnR-57V-JpG>7h4j z?BT<u_Q-+N+Ojj#dbd|=Yy0oEH6D)##wA?wpS}}3Z{V`KjNXxIZ=B~HZw(}Q-mwO6 z;$LS&W3v|wg+nFoEGp&<yVLUm0k8RATzB_R<BNu>cOciEALQ!$y6cZj0GR<Y1!NA$ zB#>Dk(?I5dOaz$;G8JDp7i2QNZZ^nteBFGI3HiDiAyY!;giH#V6*4VkUdY6dnITg{ z=7vlTnH@4cUpGHwg2)V!DI#-3CW*`vnI<w%WTMDSk*OkcMJ9{P7MZTEn=dk9WX8yp zkvSuiMrMsn8<{sUab)Jm)RDO(lSgKcOyAedA4vd`0VD-T4v-`uSwPZ&<N-+pk_jXg zNG_0MAlX3Df#d^8h_A~Ck`g2*NK%ljAZbDJf+PmX43ZioH%M}j>>%ku@`EG@$&jy0 z5t1V$Nl2EEG$DCH5`|<6NfnYSBw0wdkaQvWLK22#3`v=<%Nde1Bx^|8kh~#@Lo$b? z4#^#oJYUy<|8e$`D*Ogk=7quwi%Z-Gm&MB5#`64<{K5jh%55yp54q<e_nh=6i{2Jl diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Chuuk b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Chuuk deleted file mode 100644 index 07c84b7110ad9589810b916390aedc7ef498f423..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 269 zcmWHE%1kq2zzf)bvMfN%(*Pu92rhoG!1CvZldrfEE(!8|sQ>@}KO++mGXDQ>a|Wn@ zp=SX|b=?F84hY-FH-tgk(11bPz>*<^ux;!>BUpi$2Waqrk%#+DKy;m%+7=KEvK>T& qTmYg$t^m;>mw@c92eKKNn1PT9=A1qskOV$QaoGT!XQyjuzy$!|p-bif diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Easter b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Easter deleted file mode 100644 index cae3744096402e8a452336544edf96ca9ae5ad8d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2233 zcmdtiT};(=9LMqh;W^+W2$|3mS{MbwkLQQ*_=_YVJxF=dBs5cpfF(pgrWD3jVzpF8 zYi_!%R{7BM3tcFi%-?#l2P@BoBU`MSbgMNPJy}}*`@R3wRqLXgF8ZJI`@jA>7w6*a zeBPmkmZn1IZ&$4Sgv0f$Jv^swwzrYvy8pLurM@(9LEIA`8>iz7@paXk2wf|YcNdtb zjBJSxEYdNKUt$xE>ew$QB<@m*zU)|7;>Ul~3470}#L+SB??0(7-#wzIG!Lt!r%svV znn5+S>99%3>Q<?@?=)8=56HAxo6NMyPMIFF+)NKIk+idOP5MxoT=i+AzIsQxTyrR( zuWkQTuG^NOGkPP{jJ60pv;3mEzV0i1L)y5?EOSieFUQoZ?|wEno_<MXoqxyN^wy}{ zJocK&e)&boIoxk%_dOxGFSMGxRjWm9-lFrXs-<9Mi!Piqri%0eU7RpamH3b7(wI|H z=1kFLAH}Kiud_|X{%_PRANWn>(<juNy%Q$TdQi>n4;#JsL%Fs2O;c6)hTK;3yqTBs zoK)uz>+0{@Wq$IYo<9+xY9_mN?a?-MNBADS;D{p&hbnaNy;xOO-)9!>Iw<v3r_G%` z+vTq8pY-C!4hbcErk9qURZ9<jYnEO4zFM~J6Vq^hzq+?gOyj<_vb?j$tk_yB_k~uN zl`YwFe~~t;YW=c0b*5R9H6d$$h%!x66IIjr483;poN6A8)GgtYs&&^Hy>4h&J<xMp zKe%I1t#90?+ct`{S3aX3Y8a4?%-7As6`j%<z14K3FOjY@>rD5BGI`|PpxN+wx;*-7 zp4s?zsoL~pvgvsxO+B_gS3ll&QT5g(>0Z}$eNhpS|M-fI`7d8FuDf%C<9PQd*FCVu z7w5XWw>yb{-4E<>>?b4QOIjEVIo0;eRwee7+EZ-*_dXx*KM4Jc&Dfv8ZP`*~zuSJh z-43!J^ftr;JL0li0``P#3fUF1Eo5KF#*m$P+N~jbLpF!(4%r^EKV*Z*4v{S)dqg&g z>=M}~vQK2A$WA@&R*}7W+RY-nMYfCV7uhhfV`R(7o{>!>yGFK+>>JrQvU5+nb!6|z z=8@ea+eh|~Gyv%U(gLIhNE47QAZ<YUfHVT>1kwtm7f3UZZg|>uApJlZf^-CF3DOg! zDM(k4wjg~$8iRBOX${gFPum=%JD#>ZNPmz9Ass?mg!Bk$64E84O-P@RMj@R-T7~oq zX_lw$7Sb+H+b^VHNXL+tAw5HyhI9>S8`3wVaY*No)_L0AA<gr&-9y@k^bctu(m|w! zNDq-FB3(q<i1ZO@B+^Nwl}Im<W_sFgBJD)_i8K`HDAH1-r$|$gt|Dzk`s!)Z@qcY> ee5LJgpv2yb13AI+-2B{<yn=$9V9}pX@xKE%a7T*( diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Efate b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Efate deleted file mode 100644 index d8d4093bc804be0730b5f5f530db42d55991afbf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 538 zcmb`Dy-LGS7(j1qq*8qVwQ99${Rs|fM@2qx5!%8PGU;L$L3{#HEcys;{?wt9qe!Rf z5IT1VPU`F;&MLG+{7xsKli&?E=ObLWIVafO-^-i6HK<?MtWn*}Bj=y3M)L4NlAX4U zJ$*;xt=BMp{}N5qAH&J3FFSR16K0N{?exKe%<MF6wpf$d)oVNFRb@VXVspb4$#r+_ z!pDXzz8yzPr(3f8z8QIyf>h%;cAbHQ+yA)6)Y|;WZRqHHd1r=x&!uu;JU_47H^y=F z9IxOHUV3$m8+YK>qdG!7A+8W#h%>|+;tuhLG=Ow~w1D)0G=X%1wCPd%KpH_hL0Un2 SL7Kt;?v`59j_WJFpZWoSR&+lA diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Enderbury b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Enderbury deleted file mode 100644 index f0b8252362b0916405ad479b9f3ac148a2527814..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 234 zcmWHE%1kq2zzbM_vLGzb03?LMSPtm3T5hQS|NlQD6EpMw|M7De82<kccVJ-o|35W= zfrEiz+XV(5AKwrLT|*-vHe}E?G-e1P!5*N||Le>{Q-Ici?E}#uJ3%z5_Hx+(ZMV}k HH0A;Td>k*g diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Fakaofo b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Fakaofo deleted file mode 100644 index e40307f6aab2a169bb957979f5580affb379131e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 200 zcmWHE%1kq2zzdjxvLMXU03`hW&fHM{|NnnRCZ_-Y<0}{#{{K%6U|?Zj*mi+|!^by- pLD$fbLEF%nA%p~jf#&_MGY{<mnh&-BL=$BRmkrP=J6%I#E&xI<DYF0o diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Fiji b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Fiji deleted file mode 100644 index e71691ee932809771920778c699c27e32ce99207..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1077 zcmcK2&r1|>7{~E(3knOi=n#cMhi>ZH?ufV;V&~mWvBBK!*CS%GyOpwuYuk?nPu)6% z6rN%UtBVl*q|>s9k#sN&il}%9BB+DdQL62EfB%3Wq8Yxt4g<q5pLdYSp7y;zUcL5o zlb!8zyY5#zyLW5nn+@sO-yvO3-b-R<t0or0lB|7|RN;^wuDq1Ky^GpEvmpH&^E!}U z)`54Wl_2;c!LytWcD#_mxugy?f7YQ=MAJW?YbLWpkA1kO$K&7i#L|+S-1AybecU1v zT9@H#i#q&iRYu0=b)@!4M*FVnXyt~CwdZtf=7MCyNzLYGHMbVge4?ml-X`R1OIpu8 zZIkhB-8ykIEEC_FwNPA_!g5_FkFLt(!zP*PUDK)SzhrvfE1f>CQt}>X=}1j3>a1S! zZ_DLsQLi*rwR|hB<sTI-*X#9A!#~|2&%0B#|L8qlY1r&}cdOpkWGe7lqQ0G&7yQK% z_AzzV;B748v{jI0oVE_KkkeK|mO|D-7DHA;mUG&A$bwE=5n0k{Ya)v}ZB=Ahr>%=D zjI4|-jjW9<j;xL>kF1Xr;Is;m5}Z~8QiRj0K+14h9Y`Tgs{|<psRbzpsRk(rsRt>@ zX%!(QIjtt7D5q70l;yO#kiwi+8B&_lYD0=cszb^{>O%^2T7}O4USi`x>#?UT8Z-T# S)>JeaiA4^WhTk5KH~t1r+$|gc diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Funafuti b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Funafuti deleted file mode 100644 index ea728637ac1fa43f2d73469151c688468b34c3e3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 166 zcmWHE%1kq2zzdjwvLMXS03_=F|Nqa($iT3I1;}Aoae#rv$2WvQ+t7$1gang-hWxKH U<M{(J1GkA>Hb8UjbPbKT0Kp&`eE<Le diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Galapagos b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Galapagos deleted file mode 100644 index 31f0921ea04cd201675b613082fb4b0b0b91941c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 238 zcmWHE%1kq2zzbM`vMfN%vu%k_gPg>X0Bv!u2ik>S0_y+&|If(G#LWEv{~DnD|NlET zFtC6~Mj*L*0RxARZwP~~fhiE1F@%s{5zyTKAj^P;GJq@u(I88~G|*xYO_JqYHb5uX HnQ;LCaeg|i diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Gambier b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Gambier deleted file mode 100644 index e1fc3daa55eb2bc8c5d6a78bd77a01d193a821a7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 164 zcmWHE%1kq2zzdjwvLMVcCBTEF{{R2~jEw*PH`XvP0LcOd79Zab23-S7h7b}=0vhrk SWE#j`+$M6_0L`_t<N^T6-XRVE diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Guadalcanal b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Guadalcanal deleted file mode 100644 index 7e9d10a100f9cbe796d99945dd60e0430dced523..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 166 zcmWHE%1kq2zzdjwvLMVc#oxH6{{R2~jEoEnQ@?=p%-X=f;^P~_plxW#5JG}UKtuk6 TOaqyL+e9uKpt*LshK5`KtEU_P diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Guam b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Guam deleted file mode 100644 index 66490d25dff9bcc8f710b0141f1a02e64aeb32f3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 494 zcmWHE%1kq2zzalxvaCQX+5jX@n@@dkL9g?}8}oe(@6CRE_&u9};h(*F&woZahX1h< z9~h?VFfh867BH3bF)*uz7qAyhXJ9{b@dFRXL<XLkb{*dRQyTbE7Z+GL$0aZ_F*2h; zmjD0FOn}xf^ekXtVPL46z`()4Flz%N4_HLN$2Ww*Jvf9x+rW~+-6e#<IRnTEA?yWF zpowfiEczb^L>?YJ1ETB9bbUZH$V(s^<Sh^l@*0Q+c@IQ`ya=Mf-UKl~UIhV=cR>K? zWe@;)8$^S=4gw(WgJ@6?fN5YbfM`%qfN5ZGfM`&VfM`&#fM`h2Ff*~BK~`AUv~K|^ PBO!#iK;fioXut&kj?IX8 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Honolulu b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Honolulu deleted file mode 100644 index c7cd060159bd22fc5e6f10ac5a2089afb2c19c6a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 329 zcmWHE%1kq2zyNGO5fBCeb|40^MH+y_ZdPZH-HL?~r#o#=TvGm0a4FH#;%aZP2O|?B zGYcc@|Nl8m3=BXrf`R4#|Edf|4lv0BCI$ZgFHT@!@$n5|@CXKC7a$G?;(!pK!3+$H uP%?xBC;bP4k_QF*Ks3l{U>fK=5Dju7hz2<mOaq+?qN(g$E}&lw4Y&a7X=UL6 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Johnston b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Johnston deleted file mode 100644 index c7cd060159bd22fc5e6f10ac5a2089afb2c19c6a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 329 zcmWHE%1kq2zyNGO5fBCeb|40^MH+y_ZdPZH-HL?~r#o#=TvGm0a4FH#;%aZP2O|?B zGYcc@|Nl8m3=BXrf`R4#|Edf|4lv0BCI$ZgFHT@!@$n5|@CXKC7a$G?;(!pK!3+$H uP%?xBC;bP4k_QF*Ks3l{U>fK=5Dju7hz2<mOaq+?qN(g$E}&lw4Y&a7X=UL6 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Kiritimati b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Kiritimati deleted file mode 100644 index 7cae0cb7562e5c0f9fa46913b71a5c3628c01bbf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 238 zcmWHE%1kq2zzbM_vLGzf03t#^G3c{uFR1_j|34!WGxPudIY8n6|FeK<{{JsdVBlh4 zIP!pj&&M}}LD$g0!~jGxXd9X^gpgnp(D46t<{lsm!8U?ukgXt^bep+sfcD$z8k%qc E08<Arwg3PC diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Kosrae b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Kosrae deleted file mode 100644 index a584aae5eb8187f88600e97b6d6c764245a37e65..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 351 zcmWHE%1kq2zzaBmvTQ&s(f}l82u{7Q!1CvZgKteQoP5QVa7mEw!~Ztv0JH9Nhx-5j z|1&Z%GBYu<Ff#uC@9qOs&oFBP0}BH~-2?^>28Nym3_J`BD-JLSK*W7~Lm0FT4H>iz zEP=EE5F0Us5Oxq3&{%dL76ID#U*zGIEg-tiOvVI6gB%E=L5>8`AculzkYhnK*ufwM s(9t0GfgBE^>w!XyOw3Fy%uK9IOfc8aI0KR+)el@YKwsJE8X9r|0FqT_fB*mh diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Kwajalein b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Kwajalein deleted file mode 100644 index 1a7975fad7f7e96f7101eb3c64c9b420eeebb621..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 316 zcmWHE%1kq2zzf)cvTQ&s(Eub4zBRpY@)cLYdAG(7|J$SkbjtV~>i_@$&&b5g$im9X zz%b_lP!+?h4Gb&{3_S}NI2ah}CNS{){~zwaAi%(|;sAq)k8cQrwxJ;q8!%`aSTg7u z8Ufix3?U>q1!&{{Ix`6c5Djt?hz2<eM1!3MVgQ{7atp|bAi5qXL<MJZ*#I4D2Xr(S E0Dm)39RL6T diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Majuro b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Majuro deleted file mode 100644 index 9ef8374de4fa73cd2a3359d3c3886b11643a7146..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 310 zcmWHE%1kq2zzaBlvaCQX(f}l82u{7Q!1CvZgKteQoP5QVaNgFv;D4KRK>h#!{~4JW znVA?_SQr=<fRr-K+Q0y0*G*smn$WX=fro)%#Q_EZAKwrLZ9_u_Z39anZ2-hZ3?U@A z0%+0yIx~?55Djt-hz7X`M1x!fqCqYL(O}ns7(f?-TvQKalJ80`8=zb5bPbKT0DetZ Aa{vGU diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Marquesas b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Marquesas deleted file mode 100644 index 74d6792bf6fcb791bfc0af1f827737f612abef67..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 173 zcmWHE%1kq2zzdjwvLMVgCBVm{{{R2~jEw*P*IF<z{QqB-!NB6<8^WM#U}<c?5JG}k YKx6)c%mdks&rB{Gu-SH&R>lTg0Q#CDx&QzG diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Midway b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Midway deleted file mode 100644 index cb56709a77dedb471150f4907771bf38f1879ba4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 175 zcmWHE%1kq2zzdjwvdlot(EubSvi{~^1d42|U|{(FKmG@ZObuXQ@$n5|2o4Tm2qD3| V|3Hvudx8T*6Ec?zXt<#v7XWnZBuoGR diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Nauru b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Nauru deleted file mode 100644 index acec0429f147f40279107a48cb85c3b0e9f56c94..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 252 zcmWHE%1kq2zzbM`vMfL>wD`F;%b5u;Ph4_V{~)Ni;zj-c|Nj}87@3(F80OS~j99n> zq_A!R0~Z6siUSOMKE5Fg+J=V41`OH;mOz#fLkJ1h0Zso8vJymttOd~^t3ft_tOwEc SKrs@Xz-0q;h@GyX5f=dOmpQEf diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Niue b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Niue deleted file mode 100644 index 684b010e8b6bad56b084072403110b94e8cfe2dd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 241 zcmWHE%1kq2zzbM_vLGzd03_}>n<fa9oU*9@|NlQD6EpMw{|Q?d7=Yvg2A2Q-<2)F+ z{{K%6U=Z-}4PnqVG&C{*k;Y(>A%q0GfX4r?GY|0r(I7j4Rx^O?1=00DF;ea3vH`lo I&d`tx082zVDF6Tf diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Norfolk b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Norfolk deleted file mode 100644 index 53c1aad4e0a541ee3c2c4c6de33a79ca93a7d244..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 880 zcmc)IJ4{ny7>Dui$i=h^ut;%W6~e8j7=*--5Tk*FE?5bYD0evZ#>>5e&=V#$#mSgp z(20d0BqWkJ=mr=EM+l1xgs{A9=u*DtL^cMPJWameNr#iu|I<W!vOi|dy{`WIw#>?X zv2TyPh7&)Ox9x@254_gAeecn`6@5Ins2!<!?eu1~t8GNP8+)~<_JQ`6+|$0uE$uJp zkpU+m1IKs8`&}c+UpM5*_lP`Q4au{`zw-Rek-YHtWKe#JBu{kc;h_#U?dnL~4;?N2 zs$)gVIv)C<<9}Z3#G$XLogsa>)vc2o_jPJ5Ew4U_Ouy}tnb{Ue58sh=CX;clWM${% zUgVQ&%tFfkGPB^DY-2utF=1m?Hl6&l`}d#CHDi{(IoF%x2~*~}Zj7@!YR_13y4>*y z$6kp`ENWjgGgDJIhb+r8SU1ovjI4|-jjW9<j;xL>kF1XrKq??5kQzvlKwAYVgVaF^ zA(fC)NG+roQVl7G)I$m)6_JuiO{8d`t%{UI>LP`a%1CLXHc}j^j+76yTmHZL;oJ7F ZQD5P@)>wUc+>KVcmC^F}O{l64p90#q=NSM1 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Noumea b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Noumea deleted file mode 100644 index 931a1a306f70eb0c7578a65425086270c6ea2b88..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 304 zcmWHE%1kq2zzSHQq8vaP#O9gw^+*Zdvt0rFVY?3q9Gep$X#U>8Xo2?!V+ogn`v3p` zGcf`oGYbm?!yF!v-W3NJf$Uiu7=R`q*gn1?4BCc9Kx_z7#K;&zf)jwY{0BJ$q!Z*6 l5Djt;hz2<cM1!0KqCrjr(IDr6XbPOjWdn4rovxuF7XYYcI)eZJ diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Pago_Pago b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Pago_Pago deleted file mode 100644 index cb56709a77dedb471150f4907771bf38f1879ba4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 175 zcmWHE%1kq2zzdjwvdlot(EubSvi{~^1d42|U|{(FKmG@ZObuXQ@$n5|2o4Tm2qD3| V|3Hvudx8T*6Ec?zXt<#v7XWnZBuoGR diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Palau b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Palau deleted file mode 100644 index 146b35152aaeffb5940d30910ba37703f4096285..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 180 zcmWHE%1kq2zzdjwvLMXS03_=F|Nqa(`2WAo6d;G8ZUO^~k8cQrwt*!>2w{_$fm%SA p18B&9k%#AVKy;m%*&C2q^*}Zw6BFEM5s)CV1za{jYwUC_xd1P4BeDPh diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Pitcairn b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Pitcairn deleted file mode 100644 index ef91b061bb145b2658d49fd5065ed74b1a6cf6f7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 202 zcmWHE%1kq2zzdjxvLMXY03=LZoH*+L|Nqa(#Pt7v8xI4+|Nk8o3@rcu_ct(b`S^w~ n=o(lU8-PfL5E6_An)tuYT<;6e2Cx+%nn-K7Y=D;8S#SXWD_|-E diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Pohnpei b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Pohnpei deleted file mode 100644 index c298ddd4debb649220e5dfde60948591bc6a3501..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 303 zcmWHE%1kq2zzf)cvaCQX&;TT62u{7Q!1CvZgKteQoP5QVa7mEwL;e5%{~4JWnVA?F z|NnQo0#wB?YXbud14G>e1`Y;>o&^j%5D_2W5C&~SLk4XFOCW8)5JK2;pne86AQk}H z@n7WOP8|?kXQr?QM1vdyqCpM<(I7{GXpqA|G{|uv*VF^qj7-c-EX+(yFc(e<0m%^O OPA(gutL=0R4Y>eZAz3j1 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Ponape b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Ponape deleted file mode 100644 index c298ddd4debb649220e5dfde60948591bc6a3501..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 303 zcmWHE%1kq2zzf)cvaCQX&;TT62u{7Q!1CvZgKteQoP5QVa7mEwL;e5%{~4JWnVA?F z|NnQo0#wB?YXbud14G>e1`Y;>o&^j%5D_2W5C&~SLk4XFOCW8)5JK2;pne86AQk}H z@n7WOP8|?kXQr?QM1vdyqCpM<(I7{GXpqA|G{|uv*VF^qj7-c-EX+(yFc(e<0m%^O OPA(gutL=0R4Y>eZAz3j1 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Port_Moresby b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Port_Moresby deleted file mode 100644 index 920ad27e629e350c1baac8537bb639a59fd19039..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 186 zcmWHE%1kq2zzdjwvLMXS03_=F|Nqa($iUF~1IS_MS-`;J;~T=DZD_y{Lf9l`pcWA3 z1sd`{Y+Douh%S1&WCF;ndLWyT31|_-=*|xeEMN;bK^6q~LT%x)0orA!YiPg)0AN8Q AvH$=8 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Rarotonga b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Rarotonga deleted file mode 100644 index da6b0fadea95ebd9d06a6ac997806993a4d7330d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 577 zcmb`@u}Z^G6vpw}v>;@Vs-Ya()LyHhA`}uGv{-Zy5sGdZtdk;0Ep84{2eq3oAl~u1 zIdt^}Iu%`f1aYdHPvG%<cUKTh$o&N}gzujooSrPJU$0QU=Hv-(<j4<7i&L9VG~Mg# znaVu{?PDEqj|z=#T^QdPsvcPyU6`V`Ws8q(Q+khVc)M=O!wEavDVxf}ht)f5=K3$T znuIjp9qWbs7e%dS9euu0ZE2uuuS2?K=1kW6>GqhrYf3Sn?W-K~`JwWeFFTpZ-Mv)R zlXxY@sp@e<-qJs8l;85zYHK7@-ByUb5St-(Lu_}-euxH6=>XBfDLo*XIHe0j8;Cv- njUYNfw1Vgb(F~#+L_3In5DlHu5u&A2dcyx~>NlnDMiTqqIAwb= diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Saipan b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Saipan deleted file mode 100644 index 66490d25dff9bcc8f710b0141f1a02e64aeb32f3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 494 zcmWHE%1kq2zzalxvaCQX+5jX@n@@dkL9g?}8}oe(@6CRE_&u9};h(*F&woZahX1h< z9~h?VFfh867BH3bF)*uz7qAyhXJ9{b@dFRXL<XLkb{*dRQyTbE7Z+GL$0aZ_F*2h; zmjD0FOn}xf^ekXtVPL46z`()4Flz%N4_HLN$2Ww*Jvf9x+rW~+-6e#<IRnTEA?yWF zpowfiEczb^L>?YJ1ETB9bbUZH$V(s^<Sh^l@*0Q+c@IQ`ya=Mf-UKl~UIhV=cR>K? zWe@;)8$^S=4gw(WgJ@6?fN5YbfM`%qfN5ZGfM`&VfM`&#fM`h2Ff*~BK~`AUv~K|^ PBO!#iK;fioXut&kj?IX8 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Samoa b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Samoa deleted file mode 100644 index cb56709a77dedb471150f4907771bf38f1879ba4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 175 zcmWHE%1kq2zzdjwvdlot(EubSvi{~^1d42|U|{(FKmG@ZObuXQ@$n5|2o4Tm2qD3| V|3Hvudx8T*6Ec?zXt<#v7XWnZBuoGR diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Tahiti b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Tahiti deleted file mode 100644 index 442b8eb5a438985092d8657ebcabe8859037482a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 165 zcmWHE%1kq2zzdjwvLMVcB_MQ1{r~^}85#foFFwJ*03;I_SbTg#7<3H{7(z%e324ZF TkZB-$ahu3x12osp(0~g7aQq_R diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Tarawa b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Tarawa deleted file mode 100644 index 3db6c750333fa6dc1efc84b1abc24528fbc00b0b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 166 zcmWHE%1kq2zzdjwvLMXS03_=F|Nqa($iT431ju1nae#rv$2WvQ+t7$1gang-hWxKH U6FLJj1GkA>Hb8UjbPbKT0MM`*rvLx| diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Tongatapu b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Tongatapu deleted file mode 100644 index 5553c6009acd272cae012a08b618c2fd649dceae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 372 zcmWHE%1kq2zzW!)qTE0l#1?7*5+{qDCYb+rzhH5>_JS1)M}Sq)4hQSUuL5j>W;sO2 zUcV4grEsDC|NsAtOw25-Od!a_z_8W>sFPuB0RsyI!?p_yTnr3H9x(DDvweI+7_<$I zj0}LJF%X-8G%zwUgplAopsoMw%-DB;Xpl2OMu40OqCw6D(I6*-X`r(~G|1^78svNs c4e|n*26_WT*8|O>l2^EFfL^oHH8kb|03GB`#sB~S diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Truk b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Truk deleted file mode 100644 index 07c84b7110ad9589810b916390aedc7ef498f423..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 269 zcmWHE%1kq2zzf)bvMfN%(*Pu92rhoG!1CvZldrfEE(!8|sQ>@}KO++mGXDQ>a|Wn@ zp=SX|b=?F84hY-FH-tgk(11bPz>*<^ux;!>BUpi$2Waqrk%#+DKy;m%+7=KEvK>T& qTmYg$t^m;>mw@c92eKKNn1PT9=A1qskOV$QaoGT!XQyjuzy$!|p-bif diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Wake b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Wake deleted file mode 100644 index c9e310670f07e9e577791bfa19fefde61351fcdf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 166 zcmWHE%1kq2zzdjwvLMXS03_=F|Nqa($iOhi1ju1nae#rv$2WvQ+t7$1gang-hWxKH UlQ;u11GkA>Hb8UjbPbKT0M2k3p#T5? diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Wallis b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Wallis deleted file mode 100644 index b35344b312c6ca690c0f79a858c3995a05c71ff3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 166 zcmWHE%1kq2zzdjwvLMXS03_=F|Nqa($iT2B0?1)lae#rv$2WvQ+t7$1gang-hWxKH U<5&SQ1GkA>Hb8UjbPbKT0O8CT)c^nh diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Yap b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Pacific/Yap deleted file mode 100644 index 07c84b7110ad9589810b916390aedc7ef498f423..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 269 zcmWHE%1kq2zzf)bvMfN%(*Pu92rhoG!1CvZldrfEE(!8|sQ>@}KO++mGXDQ>a|Wn@ zp=SX|b=?F84hY-FH-tgk(11bPz>*<^ux;!>BUpi$2Waqrk%#+DKy;m%+7=KEvK>T& qTmYg$t^m;>mw@c92eKKNn1PT9=A1qskOV$QaoGT!XQyjuzy$!|p-bif diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Poland b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Poland deleted file mode 100644 index e33cf67171da78aa9e6eb02e50f9b9603da4c3f4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2654 zcmeIzYfP499LMnskW^Coqaw;dEFzImK@b%oGeT#8sXQv;2@Oz-3=a{S#64xMnREXf z;t(k<WagCELR+G9cA70CJdk0dR<1mZOhdBPm|fr7wboi&z35%nv*-TYJmc;4{dsbh z7mPN4Id|J%_;U8zFYm#QeN^p>ZmI4Qlv~|;;rgz&dabEFq_4cA`fB+O-M#a$*^__F z)RnH!Jz4yvoVt`QpS%&I&99}(r`r;wrTmCFy?tBJnaxePXP4YAI+q@ytqTvzXTuxi zd`z%>-n&xTyiaJ`l@ht^Ib$y0XmqZ8z1O*Vy3*+wP-!}jyk)-MUu&-I+-`n2mt(H4 zd(PZwOg2B}%r%`AL(I*j38t$w$@wWb%=E3D<@mqU$J|ps){!+)PC(vZr=Q2q>7SWs z2E=zbff4P_!2Zonkk4@^sI$Qtba9U}`0O?(_`Quz$k8`V=z-lPY}d<X$d(NzeEn)O zv@p-yJAanBFT*1d$!T(bOrk`F4wDD^43c5KsXDAHL8HEn)ZwiIHTr{|`e5VF8dG~k zM^s$Uk>wxjs5M75Ht(RuEohU`s~ROfrAZQIR?3*L8c7^oB8lB)GA^V-$F(n(@xK;p z(y>&T@I|&J*DcbNrX+o6(<Gf(9jXr(MChdQ@$$%IUro&mkw+shX<BNxO!oaqr$l@u zQ?7j{Q+-az)aH}&*u~c+y?(!BoI0+VTerxx1AFxG6)R-=mW?`N&Ssrin6Fu53)Pb` zMP~&~)7de@b@r`T%?_L_+2{M|+^#6eIeb&+wff2Y-2t+ou|pP?b;_cOX31UDDvL|6 z>XM0X%M%MuX<m4h<fqhYL9au)G)#5r<sG`LdzCIfxmKTS_vlmm=4s)FE9L1IQ*=dL zmOQg8T#Gi1k(D!&WmQ3ttd1KZYtnv^X9J8Bj|$Y{>)%L;|1B+Pd0*CEYtwZNb@F_3 zldi9NS4-<_^o6yxTDG-Jy?nfVdieI}byrUxZ(sXz=TF}L;itFXfB!M2e}la{JbM@u zI@GI|G5%uu{`oyR)+>Nt%)mdMzyD`OrpL^&-_*1$9v+j%OPYP*c-dng?)#m;J^$ib z-?nG=;g;#h^+v9^tG(vPRY$Hna^;b0k6eA^`XdQIGJvE2$pMlCBnwCykUSuXKr(@( z0?7rE3?v&!I*@$0+Jqn(akVKya)KlU$%?B@3z8QkF-T^R)F8P*l7nOiNe_}ABtaZ9 zgrtZ=j*uiFSwhl;<cUL~kW3+|LUQG5lZ9jpNf(kYBw-vf#vx@Ka>gNP9J0nCZ5;B3 zBo4_Ok~$=JNb+25_K@@;`9l(jWDrRql0zhkNEVSaB6&m-iDVK<C6Y@dnXWdQNIG3@ zK9PhX8AVcx<P=FNl2s(FNM4b|BAG=}i{utbE|Og&y{<ODNP=B$hLIE_IYyF<WEn{_ zl4m5*NT!igBe_PBjbs~1x2w%Jl5kg>aU|tP&XJ@eSx3^2<Q+*ol6fTcNbZs3BiTpN zkK`Yj09QK$$P^%RfJ_213&=De^MFhQG84#DAaj9C1~MDSbRhGAOo*$U5oAhS?VKQ! tg3JmsEy%ne6NAhQ{y#N;J2ifGjz+{WOfi}9Bgc%4jmeCQ#ZmEozX3dW2`vBs diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Portugal b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Portugal deleted file mode 100644 index 355817b52b1b05680bbb57e4dc8de358eff27a39..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3469 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 Y{v0ZPotiXi*2uqcfM2Hof8Le;4LU9nuK)l5 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/ROC b/venv/lib/python3.8/site-packages/pytz/zoneinfo/ROC deleted file mode 100644 index 24c43444b6751343d2915843d03e55753d4d7359..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 761 zcmcK1KPZH89LMqR`FoCmn=A^0GKfqDQI3Jm<e?~=l<jvYiS%0xSWNzmibWa8A_Gc^ z!QVR^$KlTZUknWD{NC(h@OyfmS3S@4ygyD`S7*8Wc#7@URC{M@`&etP*Sk)u-Wwax z`!x&Zpsr93{j27va#ez9ohp>~qC>H1bDSuWlg({)8fn$xc`;|*J#xO-p(2CBaxpP! zF58!Nv~NpYRXxacS-!d{2uRF3r{YPoI{q3ox6z>79b~EdjZFQpRBayLKICa?-8_d% zwdsFX=^riPejHU9;SufGSur^$GurEfl`F}W{HseO5V!v$N=u5!(73pHy0X6C_!}MZ zH968?Z(pq=&L1)*?CISxxkxS~8Ilc2hvY*NA{mjCNX{>9QY0&q7RiewMlvI*k=#gf zBs-EG$&XBc%z#XR%<-k21epby2AKz$2$>0)3YiO;jM~h`VLD_!WI|*{{KqLhcGr>$ F&nGsEUL61c diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/ROK b/venv/lib/python3.8/site-packages/pytz/zoneinfo/ROK deleted file mode 100644 index 96199e73e73aafacd89e48cb2855a96d7a134e1d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 617 zcmcK0&npB`0KoA#c14?7Qk#qN;~<AkiGwRH?4p>H)21*|8mE0H7m3)~$w^8n2PbF# z11Bj5<7Z79v(sWd<uJMMzLSHKa`0ZS@0<57^FHSE!d$QTb+qc+I=vdVTqU>tRCqDe zrQF$~?N;}4SK)_!eU|oa+)Z_Rl=SZWlDaRvd8LVN^{{vxJ~p>l{!C1ko3cUBW6PlY zZdH<#vT}N9J-znH=fe~0<vb;;>${ffUzTkLIj4PT-sxB!bUMdJ9HS;4`<_Paj~Sf_ zk+0|1^BW>A#EK*IS7G01i1zwqZHGN4*)daOrc5!aS7z80<{zH@sRvJ|JfA{9VTh_J zC>#_L3JZmX!b2gVFj1%|Tof`28-*^a=A#fs)r=HM3MYk>!b+h<3SJ5^g_-^%bwazR G2NGX5oeD|- diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Singapore b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Singapore deleted file mode 100644 index 2364b2178b03853b1771cb3f34b964fdb82e2e91..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 383 zcmWHE%1kq2zzaBmvK&CH&;TUbnp+p|O81*^fa^)Zsm)IlPEU;Ixa5)hL2Tkzj{5)q z|1&Z%v#_$Uva>TVB*p^OgGd$zhNJ?J5$OtyJRp(*NM=?r2r)3!O<<5<U?^x{kn!;i zVF(6dZ3A-<HZlN_#vsxXh%FdGNN_079sldhf)|5mkb^-q$k8Ag<ZuuTay*Czc>qL% aJOOeq$Ri-S9w<gL&v4lQy=13r!36*{S756E diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Turkey b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Turkey deleted file mode 100644 index 508446bb6aee2841ab88e82607a6ad6e748e7db7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1947 zcmd_qZ%9>V0LSs?`nP+{bz_9Pc+<9~_m<WCx4Je{%S>!HcdDyFf5t&8ib5V%gGPe4 zDT7wf8GBJA#8%G0%Gwr#Q7fV`boS>^w&_xK##j)+d<I!_QucgLuUc=`>z&KFpX24? zi_7!<#nx`!TqvHq()1_XTs!s6b0DtYtbL=0+9zk2?YA!2M>jP($98{cbkxSpFUrr_ zojD=rc&Nqh3Wv?E-yYc~#`ZcVFBcd+d&-?&&&x*d@=^20YjLBmuiLz_&1>8|T4MHB zCK$J(>CR8HcH2MajW`3|4fbHdL38kKx&6z%ubtaB)*D0pwmJM&neo^CZ_WD+BgW{K z6!SrL#7=4YRHl|3mZ{_K3vZxVdhI^p8+%u#efc;(d9XsJchtpS>O3W<v@M8F`FpAn z*n36>hR!&dcWf2>VMI-DFOXULcc|><jcUgBI`!)MW$Lx)0yVQVtX`iJP&q-L%1s+r zq2!PZjlLqoe|Y7r{(t1`@9)XHvqN%D$5lCZU#ptec3Qr%^D~*h@e^6F;k+t*@1QDL zbVL=e`ar!oJ+9^#u2b_LHK<7DE*TkKs!GP!%7x$Ms<&>J%F@nCx#(P$Ec+-&mbVL8 zu{l*PZVRd<Rd;1&<72fnr%zT@I%-*RuT?$sSAX@Ncl<Spm;5!?di=|OKjweCyUQQF za?x6GVA!fX`MLE@Q<LA=-)gN~^RcyR`zC93<bppIt+whiYOVURBUb&xd~411c}B~` z#Dpg?;YD6a$w`SRssH^o$@|<ZDM^UTus%j2bBoZ=v-3TZgb2<M={$?6LPRP&)BgSW zv)_rXh>03~S5>X%Ehh5vi}YR0f7O>qUr(RhKSb;W4!HhJChEWG89)v?a@bw<fkzHK za`2JEj|6~3fP{d=;HrZ_qCmnx;y?m%)sY~fAh969AkiS<An_mpArT=VAu+k?ppdAL zu#mWrz>vt0(2&@W;P_pM4hhdy$Hzs0t~x?4LPTOjf<&T3!bIY9)qx_By6RAoSdn0n zXpwM{c#(jSh>?(yn3157sFARdxLtMNNaRT9NbE@PNc2efNc_kEAR~Yb0Wt>2ARwcF z3<EL_u6iJlk#N;Rfs6$*7|3WK!-0$kG9bu^AVY$T2{I_is360Fj0-X_$jG?rp+UyR zRSym_I>_)K<AV$kGD64@A!CFL5;982Fd^fF3=}d_u6n4DvBDO82LBg><tx>LRyMcD F_XJx;ZRG#} diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/UCT b/venv/lib/python3.8/site-packages/pytz/zoneinfo/UCT deleted file mode 100644 index 91558be0c2bf903b2364215ba26d5227d6126508..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 114 hcmWHE%1kq2AP5+NDp(+@LPMMxLdep^1=MQ51psH$25|rY diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Alaska b/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Alaska deleted file mode 100644 index 9bbb2fd3b361ea8aa4c126d14df5fa370343a63f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2371 zcmciCZA{fw0LSqQ0v8C15>k=qB=Y>=0R^EbF9-r60dl(ukxF8BSP2AU_(W1Vaw{?0 z9L`3^IkwuQo#|G(7TvVgCgupY9>$_{YbHzAdYVOYJKvM57d7AI|G)G99PW7g`??!i zp3HIl>j^WzaCr8a!#!oE`Hb$#^NlC`+&11+EPo#_Q!^(vxcqOdkdA>;SHO!YGO#<@ zHLJZu2Q@AC1=l9&kfKDNGdol}UtZ@6i<;75!xOIXAI|FAz8UpJe0f<$`i6bCpB$BU zym`hIb#PeTx#y_st}Xp?cFSH@bbY&wsc3WET~H_Iq^@?&UC^rMg)MQ#2G;7>^ysMA zAB*+;i-{_3e4)PQlvBkY3(@x;zN|!7fxNGGR4wq#mkFD`6AN>%%fyvuL{iMxGCA$2 zNS>M2so{G?>f~2CZK_SAkG!ul&cCEG2M_D4<D1o@o)@%ywMJ!omCWhLQH#r-mrLrR zRc>;#%***zEp@Jt`Ej#F{-qRIF#U_T|Ko7^z{KaGP$%gJ-#sZF+83&q9Xcdjty8*a z*E_1X`mA2wd{C7vdP|p<Y*VE_U65s&1ETEwX;~4uRa6`wk}Iz?iptkM(5pV{R#n@N z=!f5KP}PmQb<Kf7Ra@xQtGnV=U0j8BdmPIBN4oapUR0iM%jKGQzgY88nyjC>AR2}u z<YSYkMdPlk^6`-&v9@_kt{dzV>#M%kO?^ky6Pf4q2Jddw9I5rjGOyZrWxw_&S19i% zow~)Du3CmYdefyy_0)k5`Se(tc&6(SxmibuR?kw|)_+yB=gpJPwvLI8m}%KreN1%v z=jg8dbE<3dH{Cr~tL~8rz2(||wRP}4z3q!mwY}$cz2k&O^{nmH&kf|OfWTP+LBThB zLqeUm@O3yoyykHD{T=HaL4JR4TR^D&M%Z7X>^+9BBi8Tl-x&~Z?+L4_+>W9;a~?IP z#+-8gC@*n4>bX>!OHrk{nJ0h`&tDh!e{U_^`~!#Q6?3?!_|3EI)b&qsM_*AnvOQ#f zR<l85hiJFRg+20^O#-__wu$T$*(kD8WUI(tt!A^xZmnj!$bOLxBRfX6jO-cNG_q@C z+sM9=jUzipwvOx_**vm)Wc$eet)>B1(*dLfNDq)EAYDM(fb;=r1kwql6-Y0TW+2@_ z+F>>QKpJ8-9YI=x^aN=N(iNmFNMDe~Ae}*4gY*Vz4$>W@JxG6$23bvqkQO05LYjnh z32773C!|qGr;t`5y+WFWbPH*h)$|K#nALO)X_?jZ3~3tDHKc7w-;l;3okLoO^bTnr z(mkYoR?|PEfmYK&q=i<~L!^mF7m+q1eMB0GbP{PL(o3Y7NH>voBK<@fYBe22T52^t zMVe|gT}9f8^c86=(pjXnNN<tmBHcyWi}V+1u+?-JX|dJx7-_QAbQx(g(r2X6NT-oj zBfZ8O%?=6-4!POu3=6%5@88kx{$JDmPrGm2!ijnTdC#a?oRyO$Gpe$)v$C^f_@5Pu BZASnA diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Aleutian b/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Aleutian deleted file mode 100644 index 43236498f681cc06f64ca2afa613880331fe6fbb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2356 zcmciCZ%ma{0LSsm-|Iy&Dj-Bm!Hl7RhrdBt9tc86<UwwrWC#iolmVg)3ox8hdC|nN zoE0&9(I3~SV{FZ&u`@U43+KAv*1#M!H|MM|UA1J6yq)jK){C0&@;rN<&)MC5`}=yU zn_f<L{p)zlFT9+7^Ky@W%Y4rF75FBW|JFKD=g8X=FQ_}G+8qC<Ug<hk;RGDYmVupF zPEgxM9b8xL3n|akp?MiTcUrV|zrDlfiI~-%;p<M=%}aXzk5j${Q@3Qe9`!B!dP+WU zV$z9tcT_&uciMSq&j<41ra>oi^IjQM+~Y*&*2zbbYMq#bZoSBp@5Baf)v>D*mc{<! z=*3quRNO?mUUDW%J^E#&Ui#rJwXCB^#`jLCgvunjy!m(WSoVCmqGVD$9yKEqSDqG$ zeveKH8x%>?KkJo0^@vqt7j*K)_f*Qz7dmyMORerXqQyXsN^AUFrngI#QPeLpD-u*z z;!c^J5v-nYdu2{syvVthEpz9B#FOV@<Wt{Y6>C(cetPtrc&0yEuYLc7kS()1Z~s}9 zUv^19TmOkFSpAJIEa+2(zuu5VDIbfXi{r95{E#Rf8IdJ3&EomNZ}s}`4ye+ulX}Bf zuc)#u1KK%SqRQ9o)*CyLRYhEt_Es)b-nm>|nRQcDUagdymWGQ>XLID{J2yo2N3rt7 z>2a}T|D1ejY(&)5Ps^=C?}*yc+q&-HNwqEIvfkb}pz6cNbVJc@)i85hHzro8#tZv& zlRH;64cF`DYm3#ZM|<UKz8tZmW4nA^#fp~7LfLwFPPAnw%AGCKqCMIpca>?e%fCW* z<Xl!AKe%;g%$VvNyRP@l9#?M+o!4(p?o(Yo!@B!az3QnstoI&!P6Y%81q6rO>j|Cb zzK@T~_1P7d%kOV+T)}>Sdu_lx`(0pviLm!bzOER*zqd7DiM=mcU+Q&js4#Dpc^$7S z-`w*Hyso@;=CaOQ%n9Jb`Rn5S?~#R>Kk#ynn3sFJ-<-8){usyZgVi<2=#b%A&G?W3 zq8%X@hR88v1O|zW5*a2kPGq3SNRgph%~+AaTFq#Y;UeQj28@gt88R|vWYEZ{kzpg_ zMh1?I92q(?c4Y9#=#k-D&G@Y*07wLo5Fjx?f`CK;2?G)bBoIg>kWe78K!Slp!)n5T z#KUR=f<y!f2@(?|C`eS0upn_k0)s>b2@Mh(BsfTPknkY!v6=uO5kf+Q#0Uuz5+x)| zNSu&BA(28tg~SR877{J12^SJCs|gqqF{=p~5;G)dNYs$9A#p<jheQqu9TGbvcu4fD zCVWWztR{d+1g$27NDPr6B2h%bh{O>IBoav^lt?U*U?R~(!imJwY66Nx)M`SC#MEkn zibNF&D-u^Eut;Q)&?2!#f{R2K2`>^~s|hd?VXFx-5@V|gG7@DZ%t)M(KqHYxLXCH0 z9UK@EdauXrnRg$bziVB+?f+@^KheH>3o}7a6Q=0Nr5UN|sUo>FEiE-IRfPQs4Q6_I diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Arizona b/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Arizona deleted file mode 100644 index ac6bb0c78291f1e341f42c34639458fb385bf8ed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 328 zcmWHE%1kq2zzev6vMfL>&;TUnEwh?1e>Z!>f;O263unD-INixJ;k@{Lne+Wm*Ia0n zlKJ(cRN(iE2nHrbAY=wYMyCJ&r@dof`2T<P0!Ehq|L0C%-~h9Ee0)O~d|iMz7>L6| z7(z&J%6}k;W8v8VqCrjq(I97mXpqxDG{|`%8stO}4RR)!209f)gPaSZK~4tIWICG* I=zeo90HHg7VgLXD diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Central b/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Central deleted file mode 100644 index a5b1617c7f70bfc77b7d504aaa3f23603082c3cb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3576 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 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/East-Indiana b/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/East-Indiana deleted file mode 100644 index 09511ccdcf97a5baa8e1b0eb75e040eee6b6e0c4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1666 zcmdVaT};kV0LStFL*AOuCUenZx^UBrvdmhxOs$2dygYfS)X7^*(Gj&G`CoXy!A)V7 zj1gwph`4Am!&tLPDN)B;GiE#Fg4v$G^F7?Tvbk}do&V?GbJNZ5`vh`JHYPfMoH6Db zE@z#&yhpm`(ReP#J$385Y}z-$J$<5IK3qA&eb}2J9~}s~PolrdCq?6QSLLwtH1(tI z&gph~rg!RRNjIEcr$zTg9C!NEQT;sF>h^bR(=P@Z+?N-Q$bt46ckp0^RE>G=tCE0x zT{q8tlQ~DeEtuxM|1w2?F#kQ+7OB1So^l$3+PD9eN{g?O>1hi@`f#((h%HnZU59jL z*nE|FwM;Mk6s;DWJSZ3UqzZp+sm!`QLuBXs<&ydku{0%KE~^|8%Ok^OAm@Py{1}!i zk}irB?<VS1QTNoUyPx&yV6)0S+okgc4ypV-t$Iy+nJQS{pbHzbl<;4ZMf*#|+Sq!z zuGlZuhgHiB8S!Gnr(9V)Gh7sRrpS`f!=mJJl-xAbElTT?b=l+3YI9Yj-qO;g%5#ER z9&S}zla#I~Z&2GJ?&$5=HEMfsP*%;Y7gYndW%bl*QQdw<)_ltqI~w=OoxLfdwys$2 zYKsze1(|a9F-MH>+0V$3-!H%Z{Pi3)V$|q=@bSEsWXJKmn^$}xo_DFq8EfCi+vg;n z&ScNK-{G6O*dK5fq?x<i+?D1o2{`HIJ>7iA@!2N?{$g&PIRztwO~~w!=^^t&CWy?? zYNm+H5t*db%o3R<GEZcp$V`!`B6CG1Yc;b)ri;uMnJ_YAWXi~#kx3)7My8F-8<{vV zb7bmh=gte0=a|_8(?{lyBw#feASqZ)4oDJKlLe9nk_VCqk_nOuk_(ayk`0m$k`I!Q z)ntUEWHmV<Nm)%+NLol<NMcB4NNPxKNODMaNP0+qNP<X)NQzdIBa)=mWQn9{HF+Y5 zBAFtoBDo^TBH1G8BKaZ-BN-zpTTRYL(pHl-lD5_4jU<j_j--y{jwFv{kN<J{q2?DM Y$^0V3_-Dr@#?6ZHCnUrr#LWu*39tolUH||9 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Eastern b/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Eastern deleted file mode 100644 index 2f75480e069b60b6c58a9137c7eebd4796f74226..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3536 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 EZ-WKA#Q*>R diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Hawaii b/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Hawaii deleted file mode 100644 index c7cd060159bd22fc5e6f10ac5a2089afb2c19c6a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 329 zcmWHE%1kq2zyNGO5fBCeb|40^MH+y_ZdPZH-HL?~r#o#=TvGm0a4FH#;%aZP2O|?B zGYcc@|Nl8m3=BXrf`R4#|Edf|4lv0BCI$ZgFHT@!@$n5|@CXKC7a$G?;(!pK!3+$H uP%?xBC;bP4k_QF*Ks3l{U>fK=5Dju7hz2<mOaq+?qN(g$E}&lw4Y&a7X=UL6 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Indiana-Starke b/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Indiana-Starke deleted file mode 100644 index fcd408d74df43310a9a85c475f83d545f6d75911..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2428 zcmd_rQB2ik7{~Dkfe-{G6GJjEt(buXHk3Bl+S0K@BA5qIA&k@z%Y0QJQKQ$bL0&XV zn~G})i(IZ5T2rwtG^N&R&d?-CCBP(SA+N>-DV@{%eY?zBUH7p6`TTcudiDF_T~hY^ zO!>=&*l&2aJ@(-}THBBMeTjPSC%>tNnz6cZ&jt1M>pp#U+K@V15^B!potKU&r_Fb% zN2ODmO;=Q%boIPtzV{v07f!4<7rS@qOZ(qc-K|ynhpp>WPko{8E%U0r>I{9^GfVwg z9H*}oq?`WCbops^thpK=D_3t$G}r9^eyx4j{M_FszjU;jfiK$R`te>h*xaMd-c#zv zwv&2jX|1|7Tq?J(ddx_tM}Ge@!T4Gd#Q%PTk=+pzP&;Twy*wy^Yr|Dg$rv4+dtKf2 z#DES-{ziqo5wAldKT@Fw-jy)(wi?s3Lx*=AG!Z8%^w?wD&A9#BC9<yE+`YA2##iN= zd&=@<!s0X&<w=u?kH?sMr^iV2)Y)p%=n;t-HA%(XjMn${-d2;_Z|VC#yQE?dUDR=n z$JLa|aq_^HMm06>hD=-asd+H<oII4Z*E}3`SmGbqV&Z-6dV1J0Gw0DtHFwSeHTTz} zk~w3w$vjslo`@Xd`FN9L4WyW--r1$+b<9`Uo2&HvBgrbKs8Hwb9IqCnXXvLZhSb8z zaoU^Lp}ZpjIzP2V<zI=FMX}$SMW2f-_8l=xn);-$d$%citxcY3-DrxJ?~|qVMdsP; zle(m~N<BBDNiQocRLdi3^oq<3wPIkUE{%^<rKhuWSxA5?JCLYX^<P#m?DWWsXZ&V$ zWrDoa+-uh4M~K>X%B)Qtlyz&~GwY+;r97wBl=}vBWm=P}>^`G6MAxVdt%r2g@Jh9@ zeuv)FnWZ*YSLjz-5><6^fqr%OST!oZ{saa&c)jya@ZWrY=fCZ~4gQBe`&a*(-~ZuP zB7Xm|g8@N){|5~++P#On&qzLH!k^#I%l68XbL_LwJ_Yv4^~zlP&IPzn@cxJO`Rx@4 z`WlcGB1=Tph%6FWC9+JXT_>_oWTnVbk+mX=b=uV;%SG0UEEriavSeh<$fA)|Bg;nC zjVv5lIkI$Q?a1PtcJ;{eop$|50gwtHB|vI`6alFMQU;_BNFk6)Af-TRfvy<5Pz}zO zgQFfuK{zUclmw{>QWT^rPFohFE>2q*j>;gVL282(2dNHH9*+7T1>&d>QX-BTAw}Y- z5>h6PIw6JPsFc%|3aJ%RETmdUxsZAx1>>j~QZkO3Aw}b;8d5fnx;bs(kjf#YLu%)= z#p9@+)0U5;eok9JjtU|rL~4i>5vd|lMx>5NA(2WVr9^7!w8ccK>9pnKsHf8wl%t|Z zNjYkY6qTc@NLe}RiWC;9EK*vewn%Z2>N;(Ck@`AqfsqP3ZHbW@BSq$@GE!!aIwOVV zs5DY)j#?wd=BT#QmK&+J(-s`5xYL##sX0<~r0Pi7k-8&=$NyL5!|X4CS@xGfV)kQ6 RGn0}Nvr|%%Qj(Ix{s3RXO|k$0 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Michigan b/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Michigan deleted file mode 100644 index e104faa46545ee873295cde34e1d46bccad8647c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2230 zcmdtie@xV60LSq!L|_Lbm=r2fLCOx{_|+-mRT!}A)DzRg6ipuuyq!=ysokIqYk{WA zS<_*z#xkvuu92E8S1~nbZmmpNML&j5ZL!v(9-}{6S6t8gS^xD{|Fxdm^So~N*ZuQ( zhZ-Xr%AJ3lWb+G`v)f$0XLrAsx9WgzpY!3<T3*ioRbCb`^|`lC4><=_tm4^cV&BhG ze+*UWKQByI$<<e6O6ggVvU`fWF5|FpIftZ6Zx^YmTc&;SvPwT4me-%^QWIZ$N@pC{ zpfYzh>q#B=s2d`FJ$YrJ$_lvkjdRn~P3}~ko#z%)CXDK-iK$}hFD^Oln^BQ-=|?&J z%teuV>|=TJ!DHf<sH1Ova<9m1_*Um{>{qvW&*>Qpo>MckUeyJKn^nR1`_k=dQ10PZ zWZ@5U)U1IWvS=_QihCo{b7HnA>0BsF_hyT-a9Edb`dw7`1N!!*Ukh)+EIqq?K+H)= z*Ok-0RFxw?>$$OaRn_@Rdfr#P%GdvsyyKlG)SY`ik$1hYURAdpm-D-}iM#9f$(p8h zqP8R|>uPI6-B_RY7q3<R!Cg9#K3@e+wCV+;`D)>dJLRI!szq>Xi(LFxo~U0PluLS& z#J#=}x%80{u`DN3h8ix2P;5*t_Z|_;zniF6<epb6&Rx|j$NN;{;X%D>c$Zq;byD9y z(5lun?bmC27b_8bQ?A?5BGwo8$Opnf(UjgUoBbuCd9+c63o=FcBcF^UkBP|ZxpL#k zr=q2&O1ECTsveBy=!g0TRa?WjmU~XBhrLQ~YTK_iXPwns>O0hy@hdV~*(0LEXJmVJ zyJ#OcBs+d<6p!|H%g2U%VryquKK^#D=v)(!+n#qsLgF<^iP!!|KJobR8IBW=AAQM5 zipNjA;Y^6fKRBI`X5S3^PF@rYIW@~dP966?bC;M~8)67f!ryP`UyLSh4#PplgA526 zk<|<d851%nWK>o&EM#2B!1ybS3>li$j13taGCHdn9x^^;fXE1uAtGZ$28oOk874AL zWT41Mk)a}EMFxwE78$P9j29U&GGb)N$e58qBcn!!jf@)^I5Ki%=*ZZS!CTGfk>Oj- z_>ll05kNwK!~h8b5(Oj-NF0zrAdx^qfy4p{1`-V<999z#Bp^sckdPoTL4txr1qllh z7bGx9WRTDxu|a}kHPJ!BV>R(X0%SE2LPCVZ2niArB_vEpoRB~vkwQX+#0m+P)kF&k zm(|1z37FMH3<(($GbCt8)R3?taYF)!L=FiZ5<4V#Nc52KSxx+q09s81kq}x<43Qur zQAEOs#1RQ35=kVKNGy?HBGE*`X*Kag0%|o8MM7#dF-3xkL=_1u5?3U!NM!MU8(NpC Xu-DYLC|Kbs_mma|%gQ`uo>JFeUM!I( diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Mountain b/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Mountain deleted file mode 100644 index 5fbe26b1d93d1acb2561c390c1e097d07f1a262e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2444 zcmdtjeN5F=9LMnkqQH%ZQ;8v<nU)CgtR#>b6-0<P2(NH8!YHnHS1a(Ln-=0RD8?U+ zvtrCL36!+fOng|gv7xTv+REl|Yg!BKxhxw!Y?8peo%dPwPk;4STVM9OuOIjS&-=Po z`_|@&f812_4G-6C9^R)b{@GWcUmFNlJ<liU-dDa?dprTXw{@E6E54}vI`*j#+N1RF zyx$s!>*B?gOursm&?$b8b?d7UesOi|Njd(VTTGm*mXq%nh`_OY8GIv2h@FWtq%9yq zpPH0YHYBL9x|w=v#e|wxIIhF9MpXC<xjIswP>}}?Nyq3Ob<M?I9d-V=h(6JxW8Uo* zv2XTB`ErZ6w*6Uo-Bypd-d8WDuPPC7rT5Ai`6=Rtlm#+=Zn2sf>5vJb$tvNO`8x57 zNR>1kp=X`^LCrpNN#EFeTFvp#k~i%*sOGK=%6aQP6gTI7E^k@(wwNFHo=i^FA~|qD zr#Lo>l#!D<^^!~6I=EM-oo!U<-OuTaBb6$%*{ic&TBNeQtuklR47IRitz1+&rgD?- zlegu3q85jz%DluYBJbNMnLmDB6rB1=-u~%;Skmv%cMR+nOFMqlckbFQ3L8GsceU<P zcbE6;d+N8TqRba{anTx8{Ogb`NpBJ*XZOp}=vq;Fq+Kq%Tqw$3eO)jAxJEgf+VuVJ zELG(-K3&l@M?J8lOjr6t)rzEa?OOSja!thQs@zkm>gzP=p8ch855>q;fg!QFZ&W@w zvR~A+4$FrI+eK~tQMsmjy?EGpM%T5qsYlWe>qoslRUh4{JtbwzbJ?%G$?3{_+O2)z zvC4O#K(G7eXSKeoT0V9rMm+A%mrooV6%AF1vaw@WY{;FI8yk*_O>r0G=JGDFIWVsM zd54vM<TJe`zEf=(Jg&En`PI|iz51DRZq?M>qPHC@P|dX-y?tkr3Jv-5Z%WwTuYY~@ z-y00>?i3;ze5)rU%)Dz6Vc(<dr(EuI31^XcR+y*SJQXgpA|XQThwERgFKDhdEUF(_ zA+khdjmRRARU*qo)@d~hMOKO|)oRv?EEZWUvRq`nR<mGa#mJJ8HKScLFRYp~%LdlX zv2bMN$kLIuBa25?Z#BzD)^9ZhKq`Qg0I2~-5s)fylmV#&M<I|(aFhb61xGQEYH*YT zsRvRJq#{;R5~L<bQIM)2WkKqK6b7jbQW~T-9K}JZ!%-fjK2}p8q(W9xBBVwfMMA2C zlnJR5QYfTSNU4xoA;m(fg_H}a7g8{!VpdZ!q-GpNL#oD6Hl%JGg+nUGQ97h{Nb!*B zA>~8rXEg;xDrhw&L~3X?MMSE|QAVVWNFk9*BBexXi4+s5CQ?qMo>o&(q@q?+QlzF< zQ&gm?9A!o7%28OPvK*yFYRgevq`F9Xk@_M9Mk;JIB}Qs&HAP0MY&B&@>WmZ`sWeBa zky>*U8>u!&xsiHv6db9z)s!5mxz!XMsk+sa9jQA~c%<@3>5<wa#mE15^&RHNV6pj8 VNOLaC$jQh`b7p5}WM^bK{s0D?lEVN1 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Pacific b/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Pacific deleted file mode 100644 index 9dad4f4c75b373635ccbe634798f8d9e587e36c1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2836 zcmd_rX;76_9LMpCq6mtfOq2-iq$YxZfTFmRxecHqDoA36O9F#ws1Rxy(nOgx#-Gfk zjgDqbP8phGV_AeYIW>)C&^T@pSt6t2f|j^+Z|8g7_Ntdn&ok%woVoAs_m?@lATPo5 zkEetEg~RiiJ=}Yg*-zDbDdz3{A!447GFxB2F5j&SGj;v0Ev=hBKppiK&pB4MQ%-ol zl9RQfPBpwMKkxWZ8fw<cFY8{G#;OAOwP2~7E}bmDrOuGwb7JI7<WOl!o}|uppRSrC zqE&P25Opq~t2$Q~qRuy6Ru^_(S1pI?)Wyo<>QePZxx8$@x>9jOTGt$qtA!uSwYl%e zAL*~kpJSer>w`<AZQwR_quVUG*{NLJY<pJUYR*%)kLBvWzDZHueaYJQew6ZTiPU~C zbW!bAcGm5e4HW<R5vIfRAn7<Z&;-O?kbw2$O`!T-0(X9?gD&rq&W+Wk%kjf1xVF-C z{j^$j+wqZBuT`o$)`{-Esz}{guw3`Zo~c4oGj-1q!&R@yVLG&LhTIhxs>9kPN?7Yq zbNA_95?<HS^geJy`s{8q_iQ~Wx@3^P_n9xGZ&tAGx9EiGpLj{%H|cXVAmm3K5mluk zye%d&s7ysR{9vNaEl`7McAMz>Qi-YBU}E>olfk7=n79q&BtHKYolw+Yh9np3p&1<| zF(OM3OK6ti0ZBS3yn{+Q8>UCxI;%z=x~)f@{8o+L6>9F^|ABg-;-(q%#(MQ&;VCn= ze20unuQB5nz9bU{8#8gj5}A0lUMI)AsFLgV>eS%HDs|6hJ*j1?n*8P-Gv(+aNn5?q zO#Nhvq|aGlrfrIq>7%pFj1nao;iF9E%vQ;~-P>d({v=svM(SC8uBcgGhwE%_y_&t< zs~>LItLBt9>PKoetDJ=g_1vmeYF=7{nZI_UEQqN!kLItCg~8iQZgRHdwv?Ovh*6S% zIL{OW^p=91DP~cVPafNps}~;$S4&Eg_2boERhSj2msT{YWy3n_<%I`TQAmp}PT#JI zeSxMVsa8rF&YP8?+hk?UVY8~OT%N3|HcuVPlhvh_=IMPYQkqj_)@+HAc7FD4@9*IH z-+6t$$^jma&-a%2`TKkoWu8v%-o<^@l(bCGv<dcP*z=G*(=zQp+T-zapUi(z0-t?y z{KIOIA|O>j%7D}XDFjjpr!56i3#1rGHIQ;3^*{=OR0JsrQWK;oNL7%sAay|sgH#47 z4N@DYEe=v0r!5asAEZD?g^&^<HA0GnR0$~)QYWNPNTrZcA+<t^g;WbEm($h@DHu{Q zq-5x7#)YEs*s1|#L+XYU4yhbcI;3_;@tn4LNco($en<h43L+&$YKRmOsUlKFq>e}- zkxC+^L~4l?6R9RrPNbelL7lduNJ){JB1J{2ij)<pD^ggbvPfx>+9Jh8s*9A@Y3qv= z*l8<_lo+WoQe>pcNSTp3BZWpPjg%UxHBxM(+DN&PdLspQ+KMA3M{14~9jQ7}cBJk| z;gQNCrAKOy6d$QRQhukcKe7N$y8_4(IPDrBi-4>GvJA*NAPa%41hN#!S|E#otOl|i zPP-n+f;jDpAWP!3Yl18avMR{3AnSrG46-uF(jaStEDo|d$nqfTgDjBKt`M?BPP<0P zB023UA<KlU6S7dqN+C;ytQE3Y$Z8?Wg{&8{U{1SY$dWnjnjwqkw5x_J8?tW5!XYb% jEFH3T`2StJAUlLfb`Yb}hQubs#zm*a$H&IU#s&Qiukn{d diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Samoa b/venv/lib/python3.8/site-packages/pytz/zoneinfo/US/Samoa deleted file mode 100644 index cb56709a77dedb471150f4907771bf38f1879ba4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 175 zcmWHE%1kq2zzdjwvdlot(EubSvi{~^1d42|U|{(FKmG@ZObuXQ@$n5|2o4Tm2qD3| V|3Hvudx8T*6Ec?zXt<#v7XWnZBuoGR diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/UTC b/venv/lib/python3.8/site-packages/pytz/zoneinfo/UTC deleted file mode 100644 index 91558be0c2bf903b2364215ba26d5227d6126508..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 114 hcmWHE%1kq2AP5+NDp(+@LPMMxLdep^1=MQ51psH$25|rY diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Universal b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Universal deleted file mode 100644 index 91558be0c2bf903b2364215ba26d5227d6126508..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 114 hcmWHE%1kq2AP5+NDp(+@LPMMxLdep^1=MQ51psH$25|rY diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/W-SU b/venv/lib/python3.8/site-packages/pytz/zoneinfo/W-SU deleted file mode 100644 index ddb3f4e99a1030f33b56fad986c8d9c16e59eb32..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1535 zcmd_pOGs2v0Eh8&eK(rb!qglm&2)U$sA*0)IyEzjsUbNPSW%Qng3+OZ6j}@+wy8i0 zTv(<w>Y|s6YLnFvfkYNAS_B#d(ZT{b1Q9Ad&UZz$TD9&D_x_Go1;Ov{Z)$BR5`SH5 z^c!xj-TLO770{2~!?v;O6<<2~a%X1yzByZObnc(+f7>=aAe@1L@*#I{^@&i>RWve~ zaC~IY6&@P4`5GPslaD0WhbPu1O}P_eCL0pxR)vy2#ZM$pdfe;AuS}$j_ABe{Zk2lN zys}+9t=6AwR%vZ}Rr<jywV`gS$|%oP8}pM@rq!adV&|1T(k|^^lVtYC#6V8_(?HIf zIhp(Xv&_3cCG&%?WWm)Za#QC$x%o`LbToI%!b78~=v0p?cJ-+(dpcA}YCx419Z;p; zkE*hic3Jk$tDN&qa@*r9wSBT&mJfNP>yb@XbY;rQULoBr(Q-$pRqgamOV6<%%A5I8 z`aJJdRpcF6o$*Xn&%97I;XzgN`j*=Dp-a`?y`<{KZ_4`1CzZc0^@tH379J565g8R7 z6CJf8Dth5#iCy-ITe<9u<=^=89B&aK!>RufJR^iCykNxW^I6W7Jw}`mWo|?Nw{jgK zVewqmU?dA+O%tiVzt43T>5K2n+)F>t@7C4(MLl<;zP&sez51>dd5#j{^ZE6yUz(S} z(^$BcUYI8#{QuC`Pkrrs7#c%5Ls~<6Gu6!@-68EE{h8_pkq%9Di%5^Ax=Ex<q)q-* z`a~K<IyKd;BE2HbBHbeGBK;x_BON0xBRwNcBV8kHBYh){Bb_6yo9f<?=8^7Ab^A#F z$Oe!dAX`B8fNTQU1+oofAIL_KogiC5_F}3xgY3psZwJ{AvLR$g$d-^jA)7*Wg=`Di s7qT&AXUNu&y&;=Jc4w-$hwRT(ZxGobvPEQ%$R_cB-=#%wxuDqc3lb5KyZ`_I diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/WET b/venv/lib/python3.8/site-packages/pytz/zoneinfo/WET deleted file mode 100644 index c27390b5b638399057d5f5c6d09ef8c81d5f01c1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1905 zcmdVaT}+h)9LMp)h-J*^4~n3?Wkf(7;qa;uM>9My3RK`Iq#`NEiy{RP1HxE~F;~p} z+?b6O%NAqJDSCl*f!5S?wv4qk)~uXcuJ`8J)cMlbdcKd|b=6h#VTaGNb8)Wz-(PT3 zYg4x8U(W;1H+*>doDc60Jv`o^h_{#6BZC21SH2<}Qxz4A)q;vOwlL?8qLcs7q6I%F zCiE-CT>Dh9SB`4&HwU%k%znk4IBD^RCoSQ<_bqW)mel`-J=)f3OSd%GW930hE(+M= z-h4}mPqioJ$69Jwu~Kj3D($BfrOz(XlV=~)Q&YF(9sf<sM!r+V;FrqmIw4=<5oOg~ zwCv6)%kfWJZq)(HOBl2K>>kUX8?Y5|BU*83n-%=st-_PV_Vo9)Dw?R5f4WdBhgNIV zyYYIaDOsxr3+&mFFcmk(*_xDJ6eymvlCUpSnta(xul{Uhp{J~D=Da<3<wJXZ@{pBZ z_)Hc1hHdTP545hm-PRAksmhwSRMoaa)yvxyEHBlDn6=vIP1nYoKGjB-Snan_df`Tz zZTk4SHqVCJmV=R2H}$7&9k^!oBQy45{j6=<^SidM`otRQE~qhS)OPqM)im$8niHhv zU*A#7T&G&k_iE>*pmu$<S#9S!Z1-Nj+9#^*rIsYUJd|f0l||Os6l1SsC0bYDw!IqZ zvF^-hb^rCF^+eoM&)1(@@70UyJ2qjj%}lF*^tAR&j_LK@aSiMnP>ARM`s3U@VIEI} zg*Y#F|MN{vpgQQO2?RYM_nzQ?I9q;`(?!k~Ibr0CkyA#_898a>tdY}3&Ko&#SLe); zQ%BAnIeFylk<&-cA4veo07(JK0Z9VM0!ahO14#tQ#MMa!$puLU$p%RW$p=XY$p}da z$q7jc$qGpe$qPvg$;{PB4av>bNe;;lNe{^nNf5~pNfF5rNfOBtNfXHvNfgNxNfpV} z)kzk~*40TD$rni&$rwo)$r(u+$r?!;$s0)=$s9=?$=%gS9?9O-Ngv4{nE+%4kSRds z0GR}27LaK`<^h=qWG0ZQK;{CO3}iN3o#{a41DOzHMvy5%<^-7(WLA)ALFNUS7-VLU zsX^ujnH*$xT%GAb=Ev2UAY_J+DMIE5nIvSEkZHpEWS+vEt@1Hi-in-zybNDvmbW6y H$6NS60s5Ht diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/Zulu b/venv/lib/python3.8/site-packages/pytz/zoneinfo/Zulu deleted file mode 100644 index 91558be0c2bf903b2364215ba26d5227d6126508..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 114 hcmWHE%1kq2AP5+NDp(+@LPMMxLdep^1=MQ51psH$25|rY diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/iso3166.tab b/venv/lib/python3.8/site-packages/pytz/zoneinfo/iso3166.tab deleted file mode 100644 index a4ff61a..0000000 --- a/venv/lib/python3.8/site-packages/pytz/zoneinfo/iso3166.tab +++ /dev/null @@ -1,274 +0,0 @@ -# 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 (2015-05-02): -# 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 N976 (2018-11-06). 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 Southern & Antarctic Lands -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/venv/lib/python3.8/site-packages/pytz/zoneinfo/leapseconds b/venv/lib/python3.8/site-packages/pytz/zoneinfo/leapseconds deleted file mode 100644 index cf0df04..0000000 --- a/venv/lib/python3.8/site-packages/pytz/zoneinfo/leapseconds +++ /dev/null @@ -1,82 +0,0 @@ -# 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 2021 Dec 28 00:00:00 - -# POSIX timestamps for the data in this file: -#updated 1467936000 (2016-07-08 00:00:00 UTC) -#expires 1640649600 (2021-12-28 00:00:00 UTC) - -# Updated through IERS Bulletin C61 -# File expires on: 28 December 2021 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/tzdata.zi b/venv/lib/python3.8/site-packages/pytz/zoneinfo/tzdata.zi deleted file mode 100644 index aaf67f0..0000000 --- a/venv/lib/python3.8/site-packages/pytz/zoneinfo/tzdata.zi +++ /dev/null @@ -1,4459 +0,0 @@ -# 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 -L Africa/Abidjan Africa/Bamako -L Africa/Abidjan Africa/Banjul -L Africa/Abidjan Africa/Conakry -L Africa/Abidjan Africa/Dakar -L Africa/Abidjan Africa/Freetown -L Africa/Abidjan Africa/Lome -L Africa/Abidjan Africa/Nouakchott -L Africa/Abidjan Africa/Ouagadougou -L Africa/Abidjan Atlantic/St_Helena -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 - -Z Africa/Cairo 2:5:9 - LMT 1900 O -2 K EE%sT -R GH 1919 o - N 24 0 0:20 +0020 -R GH 1920 1942 - Ja 1 2 0 GMT -R GH 1920 1939 - S 1 2 0:20 +0020 -R GH 1940 1941 - May 1 2 0:20 +0020 -R GH 1950 1955 - S 1 2 0:30 +0030 -R GH 1951 1956 - Ja 1 2 0 GMT -Z Africa/Accra -0:0:52 - LMT 1915 N 2 -0 GH %s 1942 F 8 -0:30 - +0030 1946 Ja 6 -0 GH %s -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 -L Africa/Nairobi Africa/Addis_Ababa -L Africa/Nairobi Africa/Asmara -L Africa/Nairobi Africa/Dar_es_Salaam -L Africa/Nairobi Africa/Djibouti -L Africa/Nairobi Africa/Kampala -L Africa/Nairobi Africa/Mogadishu -L Africa/Nairobi Indian/Antananarivo -L Africa/Nairobi Indian/Comoro -L Africa/Nairobi Indian/Mayotte -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 30 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 - F 2 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 - N 7 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 12 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 17 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 19 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 24 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 29 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 - Jul 5 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 - Jun 3 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 -L Africa/Maputo Africa/Blantyre -L Africa/Maputo Africa/Bujumbura -L Africa/Maputo Africa/Gaborone -L Africa/Maputo Africa/Harare -L Africa/Maputo Africa/Kigali -L Africa/Maputo Africa/Lubumbashi -L Africa/Maputo Africa/Lusaka -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 -L Africa/Lagos Africa/Bangui -L Africa/Lagos Africa/Brazzaville -L Africa/Lagos Africa/Douala -L Africa/Lagos Africa/Kinshasa -L Africa/Lagos Africa/Libreville -L Africa/Lagos Africa/Luanda -L Africa/Lagos Africa/Malabo -L Africa/Lagos Africa/Niamey -L Africa/Lagos Africa/Porto-Novo -Z Indian/Reunion 3:41:52 - LMT 1911 Jun -4 - +04 -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 -Z Indian/Mahe 3:41:48 - LMT 1907 -4 - +04 -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 -L Africa/Johannesburg Africa/Maseru -L Africa/Johannesburg Africa/Mbabane -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 -Z Indian/Kerguelen 0 - -00 1950 -5 - +05 -Z Antarctica/DumontDUrville 0 - -00 1947 -10 - +10 1952 Ja 14 -0 - -00 1956 N -10 - +10 -Z Antarctica/Syowa 0 - -00 1957 Ja 29 -3 - +03 -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/Vostok 0 - -00 1957 D 16 -6 - +06 -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/Brunei 7:39:40 - LMT 1926 Mar -7:30 - +0730 1933 -8 - +08 -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 30 0:36:42 -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 -L Asia/Nicosia Europe/Nicosia -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 23:47:12 -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 1978 1980 - Mar 20 24 1 - -R i 1978 o - O 20 24 0 - -R i 1979 o - S 18 24 0 - -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 2023 - Mar 21 24 1 - -R i 2021 2023 - S 21 24 0 - -R i 2024 o - Mar 20 24 1 - -R i 2024 o - S 20 24 0 - -R i 2025 2027 - Mar 21 24 1 - -R i 2025 2027 - S 21 24 0 - -R i 2028 2029 - Mar 20 24 1 - -R i 2028 2029 - S 20 24 0 - -R i 2030 2031 - Mar 21 24 1 - -R i 2030 2031 - S 21 24 0 - -R i 2032 2033 - Mar 20 24 1 - -R i 2032 2033 - S 20 24 0 - -R i 2034 2035 - Mar 21 24 1 - -R i 2034 2035 - S 21 24 0 - -R i 2036 2037 - Mar 20 24 1 - -R i 2036 2037 - S 20 24 0 - -R i 2038 2039 - Mar 21 24 1 - -R i 2038 2039 - S 21 24 0 - -R i 2040 2041 - Mar 20 24 1 - -R i 2040 2041 - S 20 24 0 - -R i 2042 2043 - Mar 21 24 1 - -R i 2042 2043 - S 21 24 0 - -R i 2044 2045 - Mar 20 24 1 - -R i 2044 2045 - S 20 24 0 - -R i 2046 2047 - Mar 21 24 1 - -R i 2046 2047 - S 21 24 0 - -R i 2048 2049 - Mar 20 24 1 - -R i 2048 2049 - S 20 24 0 - -R i 2050 2051 - Mar 21 24 1 - -R i 2050 2051 - S 21 24 0 - -R i 2052 2053 - Mar 20 24 1 - -R i 2052 2053 - S 20 24 0 - -R i 2054 2055 - Mar 21 24 1 - -R i 2054 2055 - S 21 24 0 - -R i 2056 2057 - Mar 20 24 1 - -R i 2056 2057 - S 20 24 0 - -R i 2058 2059 - Mar 21 24 1 - -R i 2058 2059 - S 21 24 0 - -R i 2060 2062 - Mar 20 24 1 - -R i 2060 2062 - S 20 24 0 - -R i 2063 o - Mar 21 24 1 - -R i 2063 o - S 21 24 0 - -R i 2064 2066 - Mar 20 24 1 - -R i 2064 2066 - S 20 24 0 - -R i 2067 o - Mar 21 24 1 - -R i 2067 o - S 21 24 0 - -R i 2068 2070 - Mar 20 24 1 - -R i 2068 2070 - S 20 24 0 - -R i 2071 o - Mar 21 24 1 - -R i 2071 o - S 21 24 0 - -R i 2072 2074 - Mar 20 24 1 - -R i 2072 2074 - S 20 24 0 - -R i 2075 o - Mar 21 24 1 - -R i 2075 o - S 21 24 0 - -R i 2076 2078 - Mar 20 24 1 - -R i 2076 2078 - S 20 24 0 - -R i 2079 o - Mar 21 24 1 - -R i 2079 o - S 21 24 0 - -R i 2080 2082 - Mar 20 24 1 - -R i 2080 2082 - S 20 24 0 - -R i 2083 o - Mar 21 24 1 - -R i 2083 o - S 21 24 0 - -R i 2084 2086 - Mar 20 24 1 - -R i 2084 2086 - S 20 24 0 - -R i 2087 o - Mar 21 24 1 - -R i 2087 o - S 21 24 0 - -R i 2088 ma - Mar 20 24 1 - -R i 2088 ma - S 20 24 0 - -Z Asia/Tehran 3:25:44 - LMT 1916 -3:25:44 - TMT 1946 -3:30 - +0330 1977 N -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 ma - Mar lastTh 24 1 S -R J 2014 ma - O lastF 0s 0 - -Z Asia/Amman 2:23:44 - LMT 1931 -2 J EE%sT -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 ma - Mar lastSu 0 1 S -R l 1993 1998 - S lastSu 0 0 - -R l 1999 ma - O lastSu 0 0 - -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/Kuala_Lumpur 6:46:46 - 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 1982 -8 - +08 -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>=24 1 1 S -R P 2016 2018 - O Sa>=24 1 0 - -R P 2019 o - Mar 29 0 1 S -R P 2019 o - O Sa>=24 0 0 - -R P 2020 ma - Mar Sa>=24 0 1 S -R P 2020 ma - O Sa>=24 1 0 - -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 -L Asia/Qatar Asia/Bahrain -Z Asia/Riyadh 3:6:52 - LMT 1947 Mar 14 -3 - +03 -L Asia/Riyadh Asia/Aden -L Asia/Riyadh Asia/Kuwait -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 1982 -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 ma - Mar lastF 0 1 S -R S 2009 ma - O lastF 0 0 - -Z Asia/Damascus 2:25:12 - LMT 1920 -2 S EE%sT -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 +05/+06 1991 S 9 2s -5 - +05 -Z Asia/Bangkok 6:42:4 - LMT 1880 -6:42:4 - BMT 1920 Ap -7 - +07 -L Asia/Bangkok Asia/Phnom_Penh -L Asia/Bangkok Asia/Vientiane -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 -L Asia/Dubai Asia/Muscat -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:40 - 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 -Z Indian/Christmas 7:2:52 - LMT 1895 F -7 - +07 -Z Indian/Cocos 6:27:40 - LMT 1900 -6:30 - +0630 -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 ma - Ja Su>=12 3 0 - -R FJ 2019 o - N Su>=8 2 1 - -R FJ 2020 o - D 20 2 1 - -R FJ 2021 ma - N Su>=8 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 -L Pacific/Guam Pacific/Saipan -Z Pacific/Tarawa 11:32:4 - LMT 1901 -12 - +12 -Z Pacific/Enderbury -11:24:20 - LMT 1901 --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/Majuro 11:24:48 - LMT 1901 -11 - +11 1914 O -9 - +09 1919 F -11 - +11 1937 -10 - +10 1941 Ap -9 - +09 1944 Ja 30 -11 - +11 1969 O -12 - +12 -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/Chuuk -13:52:52 - LMT 1844 D 31 -10:7:8 - LMT 1901 -10 - +10 1914 O -9 - +09 1919 F -10 - +10 1941 Ap -9 - +09 1945 Au -10 - +10 -Z Pacific/Pohnpei -13:27:8 - LMT 1844 D 31 -10:32:52 - LMT 1901 -11 - +11 1914 O -9 - +09 1919 F -11 - +11 1937 -10 - +10 1941 Ap -9 - +09 1945 Au -11 - +11 -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 -L Pacific/Auckland Antarctica/McMurdo -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 -10:39:4 - LMT 1901 --10:30 - -1030 1978 N 12 --10 CK -10/-0930 -Z Pacific/Niue -11:19:40 - LMT 1901 --11:20 - -1120 1951 --11:30 - -1130 1978 O --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 -L Pacific/Pago_Pago Pacific/Midway -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 ma - Ap Su>=1 4 0 - -R WS 2012 ma - 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:20 - LMT 1901 -12:20 - +1220 1941 -13 - +13 1999 -13 TO +13/+14 -Z Pacific/Funafuti 11:56:52 - LMT 1901 -12 - +12 -Z Pacific/Wake 11:6:28 - LMT 1901 -12 - +12 -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 -Z Pacific/Wallis 12:15:20 - LMT 1901 -12 - +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 1 0s -0 G %s 1968 O 27 -1 - BST 1971 O 31 2u -0 G %s 1996 -0 E GMT/BST -L Europe/London Europe/Jersey -L Europe/London Europe/Guernsey -L Europe/London Europe/Isle_of_Man -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 - 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 -R D 1916 o - May 14 23 1 S -R D 1916 o - S 30 23 0 - -R D 1940 o - May 15 0 1 S -R D 1945 o - Ap 2 2s 1 S -R D 1945 o - Au 15 2s 0 - -R D 1946 o - May 1 2s 1 S -R D 1946 o - S 1 2s 0 - -R D 1947 o - May 4 2s 1 S -R D 1947 o - Au 10 2s 0 - -R D 1948 o - May 9 2s 1 S -R D 1948 o - Au 8 2s 0 - -Z Europe/Copenhagen 0:50:20 - LMT 1890 -0:50:20 - CMT 1894 -1 D CE%sT 1942 N 2 2s -1 c CE%sT 1945 Ap 2 2 -1 D CE%sT 1980 -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 -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 -L Europe/Helsinki Europe/Mariehamn -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 -L Europe/Zurich Europe/Busingen -Z Europe/Gibraltar -0:21:24 - LMT 1880 Au 2 0s -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 w 1917 1919 - F 19 23 1 - -R w 1917 o - O 21 1 0 - -R w 1918 1919 - N 16 1 0 - -R w 1921 o - Mar 19 23 1 - -R w 1921 o - Jun 23 1 0 - -R w 1939 o - Ap 29 23 1 - -R w 1939 o - O 29 2 0 - -R w 1940 o - F 25 2 1 - -R w 1940 1941 - N Su>=2 1s 0 - -R w 1941 1942 - Mar Su>=2 1s 1 - -R w 1943 1946 - Mar Su>=1 1s 1 - -R w 1942 1948 - O Su>=22 1s 0 - -R w 1947 1967 - Ap Su>=1 1s 1 - -R w 1949 o - O 30 1s 0 - -R w 1950 1966 - O Su>=22 1s 0 - -R w 1967 o - O 29 1s 0 - -Z Atlantic/Reykjavik -1:28 - LMT 1908 --1 w -01/+00 1968 Ap 7 1s -0 - GMT -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 23:49:56 -1 I CE%sT 1943 S 10 -1 c CE%sT 1944 Jun 4 -1 I CE%sT 1980 -1 E CE%sT -L Europe/Rome Europe/Vatican -L Europe/Rome Europe/San_Marino -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 -L Europe/Zurich Europe/Vaduz -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 LX 1916 o - May 14 23 1 S -R LX 1916 o - O 1 1 0 - -R LX 1917 o - Ap 28 23 1 S -R LX 1917 o - S 17 1 0 - -R LX 1918 o - Ap M>=15 2s 1 S -R LX 1918 o - S M>=15 2s 0 - -R LX 1919 o - Mar 1 23 1 S -R LX 1919 o - O 5 3 0 - -R LX 1920 o - F 14 23 1 S -R LX 1920 o - O 24 2 0 - -R LX 1921 o - Mar 14 23 1 S -R LX 1921 o - O 26 2 0 - -R LX 1922 o - Mar 25 23 1 S -R LX 1922 o - O Su>=2 1 0 - -R LX 1923 o - Ap 21 23 1 S -R LX 1923 o - O Su>=2 2 0 - -R LX 1924 o - Mar 29 23 1 S -R LX 1924 1928 - O Su>=2 1 0 - -R LX 1925 o - Ap 5 23 1 S -R LX 1926 o - Ap 17 23 1 S -R LX 1927 o - Ap 9 23 1 S -R LX 1928 o - Ap 14 23 1 S -R LX 1929 o - Ap 20 23 1 S -Z Europe/Luxembourg 0:24:36 - LMT 1904 Jun -1 LX CE%sT 1918 N 25 -0 LX WE%sT 1929 O 6 2s -0 b WE%sT 1940 May 14 3 -1 c WE%sT 1944 S 18 3 -1 b CE%sT 1977 -1 E CE%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 0s -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 -Z Europe/Monaco 0:29:32 - LMT 1892 Jun -0:9:21 - PMT 1911 Mar 29 -0 F WE%sT 1945 S 16 3 -1 F CE%sT 1977 -1 E CE%sT -R N 1916 o - May 1 0 1 NST -R N 1916 o - O 1 0 0 AMT -R N 1917 o - Ap 16 2s 1 NST -R N 1917 o - S 17 2s 0 AMT -R N 1918 1921 - Ap M>=1 2s 1 NST -R N 1918 1921 - S lastM 2s 0 AMT -R N 1922 o - Mar lastSu 2s 1 NST -R N 1922 1936 - O Su>=2 2s 0 AMT -R N 1923 o - Jun F>=1 2s 1 NST -R N 1924 o - Mar lastSu 2s 1 NST -R N 1925 o - Jun F>=1 2s 1 NST -R N 1926 1931 - May 15 2s 1 NST -R N 1932 o - May 22 2s 1 NST -R N 1933 1936 - May 15 2s 1 NST -R N 1937 o - May 22 2s 1 NST -R N 1937 o - Jul 1 0 1 S -R N 1937 1939 - O Su>=2 2s 0 - -R N 1938 1939 - May 15 2s 1 S -R N 1945 o - Ap 2 2s 1 S -R N 1945 o - S 16 2s 0 - -Z Europe/Amsterdam 0:19:32 - LMT 1835 -0:19:32 N %s 1937 Jul -0:20 N +0020/+0120 1940 May 16 -1 c CE%sT 1945 Ap 2 2 -1 N CE%sT 1977 -1 E CE%sT -R NO 1916 o - May 22 1 1 S -R NO 1916 o - S 30 0 0 - -R NO 1945 o - Ap 2 2s 1 S -R NO 1945 o - O 1 2s 0 - -R NO 1959 1964 - Mar Su>=15 2s 1 S -R NO 1959 1965 - S Su>=15 2s 0 - -R NO 1965 o - Ap 25 2s 1 S -Z Europe/Oslo 0:43 - LMT 1895 -1 NO CE%sT 1940 Au 10 23 -1 c CE%sT 1945 Ap 2 2 -1 NO CE%sT 1980 -1 E CE%sT -L Europe/Oslo Arctic/Longyearbyen -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 1949 - Ap Su>=1 2s 1 S -R p 1947 1949 - O Su>=1 2s 0 - -R p 1951 1965 - Ap Su>=1 2s 1 S -R p 1951 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 -2 e EE%sT 1994 May -3 e MSK/MSD 1996 Mar 31 0s -3 1 MSD 1996 O 27 3s -3 R MSK/MSD 1997 -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 +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 2018 O 28 2s -4 - +04 2020 D 27 2s -3 - +03 -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 +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 -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 -L Europe/Belgrade Europe/Ljubljana -L Europe/Belgrade Europe/Podgorica -L Europe/Belgrade Europe/Sarajevo -L Europe/Belgrade Europe/Skopje -L Europe/Belgrade Europe/Zagreb -L Europe/Prague Europe/Bratislava -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 1900 D 31 23:45:16 -0 s WE%sT 1940 Mar 16 23 -1 s CE%sT 1979 -1 E CE%sT -Z Africa/Ceuta -0:21:16 - LMT 1900 D 31 23:38:44 -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 -Z Europe/Stockholm 1:12:12 - LMT 1879 -1:0:14 - SET 1900 -1 - CET 1916 May 14 23 -1 1 CEST 1916 O 1 1 -1 - CET 1980 -1 E CE%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 -L Europe/Istanbul Asia/Istanbul -Z Europe/Kiev 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 e EE%sT 1995 -2 E EE%sT -Z Europe/Uzhgorod 1:29:12 - LMT 1890 O -1 - CET 1940 -1 c CE%sT 1944 O -1 1 CEST 1944 O 26 -1 - CET 1945 Jun 29 -3 R MSK/MSD 1990 -3 - MSK 1990 Jul 1 2 -1 - CET 1991 Mar 31 3 -2 - EET 1992 -2 e EE%sT 1995 -2 E EE%sT -Z Europe/Zaporozhye 2:20:40 - LMT 1880 -2:20 - +0220 1924 May 2 -2 - EET 1930 Jun 21 -3 - MSK 1941 Au 25 -1 c CE%sT 1943 O 25 -3 R MSK/MSD 1991 Mar 31 2 -2 e EE%sT 1995 -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 12:3:58 --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 12:9:24 --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 12:14:48 --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 12:14:21 --7 u M%sT 2003 O 26 2 --6 u C%sT -Z America/North_Dakota/Beulah -6:47:7 - LMT 1883 N 18 12:12:53 --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 12:0:4 --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 12:7:2 --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 11:31:42 --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 12:15:11 --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 12:15:22 --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 12:14:37 --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 12:9:53 --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 12:12:57 --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 12:10:53 --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 12:13:30 --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 12:13:35 --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 12:19:44 --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 12:16:58 --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 12:20:36 --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 -Z America/Blanc-Sablon -3:48:28 - LMT 1884 --4 C A%sT 1970 --4 - AST -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 -Z America/Thunder_Bay -5:57 - LMT 1895 --6 - CST 1910 --5 - EST 1942 --5 C E%sT 1970 --5 t E%sT 1973 --5 - EST 1974 --5 C E%sT -Z America/Nipigon -5:53:4 - LMT 1895 --5 C E%sT 1940 S 29 --5 1 EDT 1942 F 9 2s --5 C E%sT -Z America/Rainy_River -6:18:16 - LMT 1895 --6 C C%sT 1940 S 29 --6 1 CDT 1942 F 9 2s --6 C C%sT -Z America/Atikokan -6:6:28 - LMT 1895 --6 C C%sT 1940 S 29 --6 1 CDT 1942 F 9 2s --6 C C%sT 1945 S 30 2 --5 - EST -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 -Z America/Creston -7:46:4 - LMT 1884 --7 - MST 1916 O --8 - PST 1918 Jun 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 1965 o - Ap lastSu 0 2 DD -R Y 1965 o - O lastSu 2 0 S -R Y 1980 1986 - Ap lastSu 2 1 D -R Y 1980 2006 - O lastSu 2 0 S -R Y 1987 2006 - Ap Su>=1 2 1 D -Z America/Pangnirtung 0 - -00 1921 --4 Y A%sT 1995 Ap Su>=1 2 --5 C E%sT 1999 O 31 2 --6 C C%sT 2000 O 29 2 --5 C E%sT -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/Yellowknife 0 - -00 1935 --7 Y M%sT 1980 --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 1967 May 28 --8 Y P%sT 1980 --8 C P%sT 2020 N --7 - MST -Z America/Dawson -9:17:40 - LMT 1900 Au 20 --9 Y Y%sT 1973 O 28 --8 Y P%sT 1980 --8 C P%sT 2020 N --7 - MST -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 ma - Ap Su>=1 2 1 D -R m 2002 ma - O lastSu 2 0 S -Z America/Cancun -5:47:4 - LMT 1922 Ja 1 0:12:56 --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 0:1:32 --6 - CST 1981 D 23 --5 - EST 1982 D 2 --6 m C%sT -Z America/Matamoros -6:40 - LMT 1921 D 31 23:20 --6 - CST 1988 --6 u C%sT 1989 --6 m C%sT 2010 --6 u C%sT -Z America/Monterrey -6:41:16 - LMT 1921 D 31 23:18:44 --6 - CST 1988 --6 u C%sT 1989 --6 m C%sT -Z America/Mexico_City -6:36:36 - LMT 1922 Ja 1 0:23:24 --7 - MST 1927 Jun 10 23 --6 - CST 1930 N 15 --7 - MST 1931 May 1 23 --6 - CST 1931 O --7 - MST 1932 Ap --6 m C%sT 2001 S 30 2 --6 - CST 2002 F 20 --6 m C%sT -Z America/Ojinaga -6:57:40 - LMT 1922 Ja 1 0:2:20 --7 - MST 1927 Jun 10 23 --6 - CST 1930 N 15 --7 - MST 1931 May 1 23 --6 - CST 1931 O --7 - MST 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 -Z America/Chihuahua -7:4:20 - LMT 1921 D 31 23:55:40 --7 - MST 1927 Jun 10 23 --6 - CST 1930 N 15 --7 - MST 1931 May 1 23 --6 - CST 1931 O --7 - MST 1932 Ap --6 - CST 1996 --6 m C%sT 1998 --6 - CST 1998 Ap Su>=1 3 --7 m M%sT -Z America/Hermosillo -7:23:52 - LMT 1921 D 31 23:36:8 --7 - MST 1927 Jun 10 23 --6 - CST 1930 N 15 --7 - MST 1931 May 1 23 --6 - CST 1931 O --7 - MST 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 1921 D 31 23:54:20 --7 - MST 1927 Jun 10 23 --6 - CST 1930 N 15 --7 - MST 1931 May 1 23 --6 - CST 1931 O --7 - MST 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 1921 D 31 23:59 --7 - MST 1927 Jun 10 23 --6 - CST 1930 N 15 --7 - MST 1931 May 1 23 --6 - CST 1931 O --7 - MST 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 0:11:56 --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 BS 1942 o - May 1 24 1 W -R BS 1944 o - D 31 24 0 S -R BS 1945 o - F 1 0 1 W -R BS 1945 o - Au 14 23u 1 P -R BS 1945 o - O 17 24 0 S -R BS 1964 1975 - O lastSu 2 0 S -R BS 1964 1975 - Ap lastSu 2 1 D -Z America/Nassau -5:9:30 - LMT 1912 Mar 2 --5 BS E%sT 1976 --5 u E%sT -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 1924 --3:58:29 - BMT 1932 --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 -L America/Panama America/Cayman -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 -L America/Curacao America/Aruba -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 ma - S Su>=2 4u 1 - -Z America/Santiago -4:42:46 - LMT 1890 --4:42:46 - SMT 1910 Ja 10 --5 - -05 1916 Jul --4:42:46 - SMT 1918 S 10 --4 - -04 1919 Jul --4:42:46 - SMT 1927 S --5 x -05/-04 1932 S --4 - -04 1942 Jun --5 - -05 1942 Au --4 - -04 1946 Jul 15 --4 1 -03 1946 S --4 - -04 1947 Ap --5 - -05 1947 May 21 23 --4 x -04/-03 -Z America/Punta_Arenas -4:43:40 - LMT 1890 --4:42:46 - SMT 1910 Ja 10 --5 - -05 1916 Jul --4:42:46 - SMT 1918 S 10 --4 - -04 1919 Jul --4:42:46 - SMT 1927 S --5 x -05/-04 1932 S --4 - -04 1942 Jun --5 - -05 1942 Au --4 - -04 1947 Ap --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 - Ap 4 0 0 - -Z America/Bogota -4:56:16 - LMT 1884 Mar 13 --4:56:16 - BMT 1914 N 23 --5 CO -05/-04 -Z America/Curacao -4:35:47 - LMT 1912 F 12 --4:30 - -0430 1965 --4 - AST -L America/Curacao America/Lower_Princes -L America/Curacao America/Kralendijk -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:40 - LMT 1915 Mar --3:45 - -0345 1975 Jul 31 --3 - -03 1991 --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 -Z America/Port_of_Spain -4:6:4 - LMT 1912 Mar 2 --4 - AST -L America/Port_of_Spain America/Anguilla -L America/Port_of_Spain America/Antigua -L America/Port_of_Spain America/Dominica -L America/Port_of_Spain America/Grenada -L America/Port_of_Spain America/Guadeloupe -L America/Port_of_Spain America/Marigot -L America/Port_of_Spain America/Montserrat -L America/Port_of_Spain America/St_Barthelemy -L America/Port_of_Spain America/St_Kitts -L America/Port_of_Spain America/St_Lucia -L America/Port_of_Spain America/St_Thomas -L America/Port_of_Spain America/St_Vincent -L America/Port_of_Spain America/Tortola -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/GMT 0 - GMT -Z Etc/UTC 0 - UTC -L Etc/GMT GMT -L Etc/UTC Etc/Universal -L Etc/UTC Etc/Zulu -L Etc/GMT Etc/Greenwich -L Etc/GMT Etc/GMT-0 -L Etc/GMT Etc/GMT+0 -L Etc/GMT Etc/GMT0 -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 Africa/Nairobi Africa/Asmera -L Africa/Abidjan Africa/Timbuktu -L America/Argentina/Catamarca America/Argentina/ComodRivadavia -L America/Adak America/Atka -L America/Argentina/Buenos_Aires America/Buenos_Aires -L America/Argentina/Catamarca America/Catamarca -L America/Atikokan America/Coral_Harbour -L America/Argentina/Cordoba America/Cordoba -L America/Tijuana America/Ensenada -L America/Indiana/Indianapolis America/Fort_Wayne -L America/Nuuk America/Godthab -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/Toronto America/Montreal -L America/Rio_Branco America/Porto_Acre -L America/Argentina/Cordoba America/Rosario -L America/Tijuana America/Santa_Isabel -L America/Denver America/Shiprock -L America/Port_of_Spain America/Virgin -L Pacific/Auckland Antarctica/South_Pole -L Asia/Ashgabat Asia/Ashkhabad -L Asia/Kolkata Asia/Calcutta -L Asia/Shanghai Asia/Chongqing -L Asia/Shanghai Asia/Chungking -L Asia/Dhaka Asia/Dacca -L Asia/Shanghai Asia/Harbin -L Asia/Urumqi Asia/Kashgar -L Asia/Kathmandu Asia/Katmandu -L Asia/Macau Asia/Macao -L Asia/Yangon Asia/Rangoon -L Asia/Ho_Chi_Minh Asia/Saigon -L Asia/Jerusalem Asia/Tel_Aviv -L Asia/Thimphu Asia/Thimbu -L Asia/Makassar Asia/Ujung_Pandang -L Asia/Ulaanbaatar Asia/Ulan_Bator -L Atlantic/Faroe Atlantic/Faeroe -L Europe/Oslo Atlantic/Jan_Mayen -L Australia/Sydney Australia/ACT -L Australia/Sydney Australia/Canberra -L Australia/Hobart Australia/Currie -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/UTC Etc/UCT -L Europe/London Europe/Belfast -L Europe/Chisinau Europe/Tiraspol -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 Atlantic/Reykjavik 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 Pacific/Honolulu Pacific/Johnston -L Pacific/Pohnpei Pacific/Ponape -L Pacific/Pago_Pago Pacific/Samoa -L Pacific/Chuuk Pacific/Truk -L Pacific/Chuuk Pacific/Yap -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 diff --git a/venv/lib/python3.8/site-packages/pytz/zoneinfo/zone.tab b/venv/lib/python3.8/site-packages/pytz/zoneinfo/zone.tab deleted file mode 100644 index 1f0128f..0000000 --- a/venv/lib/python3.8/site-packages/pytz/zoneinfo/zone.tab +++ /dev/null @@ -1,451 +0,0 @@ -# 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 (2018-06-27): -# 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. -# -# 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 +4901-08816 America/Nipigon Eastern - ON, QC (no DST 1967-73) -CA +4823-08915 America/Thunder_Bay Eastern - ON (Thunder Bay) -CA +6344-06828 America/Iqaluit Eastern - NU (most east areas) -CA +6608-06544 America/Pangnirtung Eastern - NU (Pangnirtung) -CA +484531-0913718 America/Atikokan EST - ON (Atikokan); NU (Coral H) -CA +4953-09709 America/Winnipeg Central - ON (west); Manitoba -CA +4843-09434 America/Rainy_River Central - ON (Rainy R, Ft Frances) -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); SK (W) -CA +690650-1050310 America/Cambridge_Bay Mountain - NU (west) -CA +6227-11421 America/Yellowknife Mountain - NT (central) -CA +682059-1334300 America/Inuvik Mountain - NT (west) -CA +4906-11631 America/Creston MST - BC (Creston) -CA +5946-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 Chile (most areas) -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 Cyprus (most areas) -CY +3507+03357 Asia/Famagusta Northern Cyprus -CZ +5005+01426 Europe/Prague -DE +5230+01322 Europe/Berlin Germany (most areas) -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 Greenland (most areas) -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 -0308-17105 Pacific/Enderbury 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 Kazakhstan (most areas) -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 Marshall Islands (most areas) -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 Mongolia (most areas) -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 Time -MX +2105-08646 America/Cancun Eastern Standard Time - Quintana Roo -MX +2058-08937 America/Merida Central Time - Campeche, Yucatan -MX +2540-10019 America/Monterrey Central Time - Durango; Coahuila, Nuevo Leon, Tamaulipas (most areas) -MX +2550-09730 America/Matamoros Central Time US - Coahuila, Nuevo Leon, Tamaulipas (US border) -MX +2313-10625 America/Mazatlan Mountain Time - Baja California Sur, Nayarit, Sinaloa -MX +2838-10605 America/Chihuahua Mountain Time - Chihuahua (most areas) -MX +2934-10425 America/Ojinaga Mountain Time US - Chihuahua (US border) -MX +2904-11058 America/Hermosillo Mountain Standard Time - Sonora -MX +3232-11701 America/Tijuana Pacific Time US - Baja California -MX +2048-10515 America/Bahia_Banderas Central Time - Bahia de Banderas -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 New Zealand (most areas) -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 Papua New Guinea (most areas) -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); North 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 -2110-17510 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/Kiev Ukraine (most areas) -UA +4837+02218 Europe/Uzhgorod Transcarpathia -UA +4750+03510 Europe/Zaporozhye Zaporozhye and east Lugansk -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 - Arizona (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 Aleutian Islands -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/venv/lib/python3.8/site-packages/pytz/zoneinfo/zone1970.tab b/venv/lib/python3.8/site-packages/pytz/zoneinfo/zone1970.tab deleted file mode 100644 index 396e4d3..0000000 --- a/venv/lib/python3.8/site-packages/pytz/zoneinfo/zone1970.tab +++ /dev/null @@ -1,383 +0,0 @@ -# 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 a country has multiple 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 +2518+05518 Asia/Dubai -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 -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 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 Samoa, 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 +5050+00420 Europe/Brussels -BG +4241+02319 Europe/Sofia -BM +3217-06446 Atlantic/Bermuda -BN +0456+11455 Asia/Brunei -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 -BS +2505-07721 America/Nassau -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 +5125-05707 America/Blanc-Sablon AST - QC (Lower North Shore) -CA +4339-07923 America/Toronto Eastern - ON, QC (most areas) -CA +4901-08816 America/Nipigon Eastern - ON, QC (no DST 1967-73) -CA +4823-08915 America/Thunder_Bay Eastern - ON (Thunder Bay) -CA +6344-06828 America/Iqaluit Eastern - NU (most east areas) -CA +6608-06544 America/Pangnirtung Eastern - NU (Pangnirtung) -CA +484531-0913718 America/Atikokan EST - ON (Atikokan); NU (Coral H) -CA +4953-09709 America/Winnipeg Central - ON (west); Manitoba -CA +4843-09434 America/Rainy_River Central - ON (Rainy R, Ft Frances) -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); SK (W) -CA +690650-1050310 America/Cambridge_Bay Mountain - NU (west) -CA +6227-11421 America/Yellowknife Mountain - NT (central) -CA +682059-1334300 America/Inuvik Mountain - NT (west) -CA +4906-11631 America/Creston MST - BC (Creston) -CA +5946-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 -CH,DE,LI +4723+00832 Europe/Zurich Swiss time -CI,BF,GM,GN,ML,MR,SH,SL,SN,TG +0519-00402 Africa/Abidjan -CK -2114-15946 Pacific/Rarotonga -CL -3327-07040 America/Santiago Chile (most areas) -CL -5309-07055 America/Punta_Arenas Region of Magallanes -CL -2709-10926 Pacific/Easter Easter Island -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,AW,BQ,SX +1211-06900 America/Curacao -CX -1025+10543 Indian/Christmas -CY +3510+03322 Asia/Nicosia Cyprus (most areas) -CY +3507+03357 Asia/Famagusta Northern Cyprus -CZ,SK +5005+01426 Europe/Prague -DE +5230+01322 Europe/Berlin Germany (most areas) -DK +5540+01235 Europe/Copenhagen -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 +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 -GB,GG,IM,JE +513030-0000731 Europe/London -GE +4143+04449 Asia/Tbilisi -GF +0456-05220 America/Cayenne -GH +0533-00013 Africa/Accra -GI +3608-00521 Europe/Gibraltar -GL +6411-05144 America/Nuuk Greenland (most areas) -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 -IS +6409-02151 Atlantic/Reykjavik -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 +0125+17300 Pacific/Tarawa Gilbert Islands -KI -0308-17105 Pacific/Enderbury Phoenix Islands -KI +0152-15720 Pacific/Kiritimati Line Islands -KP +3901+12545 Asia/Pyongyang -KR +3733+12658 Asia/Seoul -KZ +4315+07657 Asia/Almaty Kazakhstan (most areas) -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 -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 -MH +0709+17112 Pacific/Majuro Marshall Islands (most areas) -MH +0905+16720 Pacific/Kwajalein Kwajalein -MM +1647+09610 Asia/Yangon -MN +4755+10653 Asia/Ulaanbaatar Mongolia (most areas) -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 +0410+07330 Indian/Maldives -MX +1924-09909 America/Mexico_City Central Time -MX +2105-08646 America/Cancun Eastern Standard Time - Quintana Roo -MX +2058-08937 America/Merida Central Time - Campeche, Yucatán -MX +2540-10019 America/Monterrey Central Time - Durango; Coahuila, Nuevo León, Tamaulipas (most areas) -MX +2550-09730 America/Matamoros Central Time US - Coahuila, Nuevo León, Tamaulipas (US border) -MX +2313-10625 America/Mazatlan Mountain Time - Baja California Sur, Nayarit, Sinaloa -MX +2838-10605 America/Chihuahua Mountain Time - Chihuahua (most areas) -MX +2934-10425 America/Ojinaga Mountain Time US - Chihuahua (US border) -MX +2904-11058 America/Hermosillo Mountain Standard Time - Sonora -MX +3232-11701 America/Tijuana Pacific Time US - Baja California -MX +2048-10515 America/Bahia_Banderas Central Time - Bahía de Banderas -MY +0310+10142 Asia/Kuala_Lumpur Malaysia (peninsula) -MY +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 -NL +5222+00454 Europe/Amsterdam -NO,SJ +5955+01045 Europe/Oslo -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,KY +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 Papua New Guinea (most areas) -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,BH +2517+05132 Asia/Qatar -RE,TF -2052+05528 Indian/Reunion Réunion, Crozet, Scattered Islands -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); North Kuril Is -RU +5301+15839 Asia/Kamchatka MSK+09 - Kamchatka -RU +6445+17729 Asia/Anadyr MSK+09 - Bering Sea -SA,KW,YE +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 -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 -TF -492110+0701303 Indian/Kerguelen Kerguelen, St Paul Island, Amsterdam Island -TH,KH,LA,VN +1345+10031 Asia/Bangkok Indochina (most areas) -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 -2110-17510 Pacific/Tongatapu -TR +4101+02858 Europe/Istanbul -TT,AG,AI,BL,DM,GD,GP,KN,LC,MF,MS,VC,VG,VI +1039-06131 America/Port_of_Spain -TV -0831+17913 Pacific/Funafuti -TW +2503+12130 Asia/Taipei -UA +5026+03031 Europe/Kiev Ukraine (most areas) -UA +4837+02218 Europe/Uzhgorod Transcarpathia -UA +4750+03510 Europe/Zaporozhye Zaporozhye and east Lugansk -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 - Arizona (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 Aleutian Islands -US,UM +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 Vietnam (south) -VU -1740+16825 Pacific/Efate -WF -1318-17610 Pacific/Wallis -WS -1350-17144 Pacific/Apia -ZA,LS,SZ -2615+02800 Africa/Johannesburg diff --git a/venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/INSTALLER b/venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/LICENSE b/venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/LICENSE deleted file mode 100644 index 67db858..0000000 --- a/venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/LICENSE +++ /dev/null @@ -1,175 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. diff --git a/venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/METADATA b/venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/METADATA deleted file mode 100644 index 6aaa2dd..0000000 --- a/venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/METADATA +++ /dev/null @@ -1,103 +0,0 @@ -Metadata-Version: 2.1 -Name: requests -Version: 2.25.1 -Summary: Python HTTP for Humans. -Home-page: https://requests.readthedocs.io -Author: Kenneth Reitz -Author-email: me@kennethreitz.org -License: Apache 2.0 -Project-URL: Documentation, https://requests.readthedocs.io -Project-URL: Source, https://github.com/psf/requests -Platform: UNKNOWN -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: Natural Language :: English -Classifier: License :: OSI Approved :: Apache Software 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.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.*, !=3.4.* -Description-Content-Type: text/markdown -Requires-Dist: chardet (<5,>=3.0.2) -Requires-Dist: idna (<3,>=2.5) -Requires-Dist: urllib3 (<1.27,>=1.21.1) -Requires-Dist: certifi (>=2017.4.17) -Provides-Extra: security -Requires-Dist: pyOpenSSL (>=0.14) ; extra == 'security' -Requires-Dist: cryptography (>=1.3.4) ; extra == 'security' -Provides-Extra: socks -Requires-Dist: PySocks (!=1.5.7,>=1.5.6) ; extra == 'socks' -Requires-Dist: win-inet-pton ; (sys_platform == "win32" and python_version == "2.7") and extra == 'socks' - -# Requests - -**Requests** is a simple, yet elegant HTTP library. - -```python ->>> import requests ->>> r = requests.get('https://api.github.com/user', auth=('user', 'pass')) ->>> r.status_code -200 ->>> r.headers['content-type'] -'application/json; charset=utf8' ->>> r.encoding -'utf-8' ->>> r.text -'{"type":"User"...' ->>> r.json() -{'disk_usage': 368627, 'private_gists': 484, ...} -``` - -Requests allows you to send HTTP/1.1 requests extremely easily. There’s no need to manually add query strings to your URLs, or to form-encode your `PUT` & `POST` data — but nowadays, just use the `json` method! - -Requests is one of the most downloaded Python package today, pulling in around `14M downloads / week`— according to GitHub, Requests is currently [depended upon](https://github.com/psf/requests/network/dependents?package_id=UGFja2FnZS01NzA4OTExNg%3D%3D) by `500,000+` repositories. You may certainly put your trust in this code. - -[![Downloads](https://pepy.tech/badge/requests/month)](https://pepy.tech/project/requests/month) -[![Supported Versions](https://img.shields.io/pypi/pyversions/requests.svg)](https://pypi.org/project/requests) -[![Contributors](https://img.shields.io/github/contributors/psf/requests.svg)](https://github.com/psf/requests/graphs/contributors) - -## Installing Requests and Supported Versions - -Requests is available on PyPI: - -```console -$ python -m pip install requests -``` - -Requests officially supports Python 2.7 & 3.5+. - -## Supported Features & Best–Practices - -Requests is ready for the demands of building robust and reliable HTTP–speaking applications, for the needs of today. - -- Keep-Alive & Connection Pooling -- International Domains and URLs -- Sessions with Cookie Persistence -- Browser-style TLS/SSL Verification -- Basic & Digest Authentication -- Familiar `dict`–like Cookies -- Automatic Content Decompression and Decoding -- Multi-part File Uploads -- SOCKS Proxy Support -- Connection Timeouts -- Streaming Downloads -- Automatic honoring of `.netrc` -- Chunked HTTP Requests - -## API Reference and User Guide available on [Read the Docs](https://requests.readthedocs.io) - -[![Read the Docs](https://raw.githubusercontent.com/psf/requests/master/ext/ss.png)](https://requests.readthedocs.io) - ---- - -[![Kenneth Reitz](https://raw.githubusercontent.com/psf/requests/master/ext/kr.png)](https://kennethreitz.org) [![Python Software Foundation](https://raw.githubusercontent.com/psf/requests/master/ext/psf.png)](https://www.python.org/psf) - - diff --git a/venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/RECORD b/venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/RECORD deleted file mode 100644 index 008165f..0000000 --- a/venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/RECORD +++ /dev/null @@ -1,42 +0,0 @@ -requests-2.25.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -requests-2.25.1.dist-info/LICENSE,sha256=CeipvOyAZxBGUsFoaFqwkx54aPnIKEtm9a5u2uXxEws,10142 -requests-2.25.1.dist-info/METADATA,sha256=RuNh38uN0IMsRT3OwaTNB_WyGx6RMwwQoMwujXfkUVM,4168 -requests-2.25.1.dist-info/RECORD,, -requests-2.25.1.dist-info/WHEEL,sha256=Z-nyYpwrcSqxfdux5Mbn_DQ525iP7J2DG3JgGvOYyTQ,110 -requests-2.25.1.dist-info/top_level.txt,sha256=fMSVmHfb5rbGOo6xv-O_tUX6j-WyixssE-SnwcDRxNQ,9 -requests/__init__.py,sha256=rsmg7xmbbCE_zmDcG6EDk_pyvdEfadztdBaWIkInlH8,4141 -requests/__pycache__/__init__.cpython-38.pyc,, -requests/__pycache__/__version__.cpython-38.pyc,, -requests/__pycache__/_internal_utils.cpython-38.pyc,, -requests/__pycache__/adapters.cpython-38.pyc,, -requests/__pycache__/api.cpython-38.pyc,, -requests/__pycache__/auth.cpython-38.pyc,, -requests/__pycache__/certs.cpython-38.pyc,, -requests/__pycache__/compat.cpython-38.pyc,, -requests/__pycache__/cookies.cpython-38.pyc,, -requests/__pycache__/exceptions.cpython-38.pyc,, -requests/__pycache__/help.cpython-38.pyc,, -requests/__pycache__/hooks.cpython-38.pyc,, -requests/__pycache__/models.cpython-38.pyc,, -requests/__pycache__/packages.cpython-38.pyc,, -requests/__pycache__/sessions.cpython-38.pyc,, -requests/__pycache__/status_codes.cpython-38.pyc,, -requests/__pycache__/structures.cpython-38.pyc,, -requests/__pycache__/utils.cpython-38.pyc,, -requests/__version__.py,sha256=k4J8c1yFRFzwGWwlN7miaDOclFtbcIs1GlnmT17YbXQ,441 -requests/_internal_utils.py,sha256=Zx3PnEUccyfsB-ie11nZVAW8qClJy0gx1qNME7rgT18,1096 -requests/adapters.py,sha256=WelSM1BCQXdbjEuDsBxqKDADeY8BHmxlrwbNnLN2rr4,21344 -requests/api.py,sha256=PlHM-HT3PQ5lyufoeGmV-nJxRi7UnUyGVh7OV7B9XV4,6496 -requests/auth.py,sha256=OMoJIVKyRLy9THr91y8rxysZuclwPB-K1Xg1zBomUhQ,10207 -requests/certs.py,sha256=dOB5rV2DZ13dEhq9BUa_4hd5kAqg59e_zUZB00faYz8,453 -requests/compat.py,sha256=iBRvu-X540CH4PJsuxr0vcGTnl_TZhq_75SwmeckQ7w,1782 -requests/cookies.py,sha256=Y-bKX6TvW3FnYlE6Au0SXtVVWcaNdFvuAwQxw-G0iTI,18430 -requests/exceptions.py,sha256=xXoj1rdhnxTS_DYphKZ9OvFZJQZ333A64REc9ZDZIgU,3161 -requests/help.py,sha256=lLcBtKAar8T6T78e9Tc4Zfd_EEJFhntxgib1JHNctEI,3515 -requests/hooks.py,sha256=QReGyy0bRcr5rkwCuObNakbYsc7EkiKeBwG4qHekr2Q,757 -requests/models.py,sha256=Uhb4Ra_ubNGBf-6ktHShgO5mUSCGZKa5D_wLGVCMtYk,34308 -requests/packages.py,sha256=Q2rF0L5mc3wQAvc6q_lAVtPTDOaOeFgD-7kWSQLkjEQ,542 -requests/sessions.py,sha256=BsnR-zYILgoFzJ6yq4T8ht_i0PwwPGVAxWxWaV5dcHg,30137 -requests/status_codes.py,sha256=gT79Pbs_cQjBgp-fvrUgg1dn2DQO32bDj4TInjnMPSc,4188 -requests/structures.py,sha256=msAtr9mq1JxHd-JRyiILfdFlpbJwvvFuP3rfUQT_QxE,3005 -requests/utils.py,sha256=_K9AgkN6efPe-a-zgZurXzds5PBC0CzDkyjAE2oCQFQ,30529 diff --git a/venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/WHEEL b/venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/WHEEL deleted file mode 100644 index 01b8fc7..0000000 --- a/venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/WHEEL +++ /dev/null @@ -1,6 +0,0 @@ -Wheel-Version: 1.0 -Generator: bdist_wheel (0.36.2) -Root-Is-Purelib: true -Tag: py2-none-any -Tag: py3-none-any - diff --git a/venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/top_level.txt b/venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/top_level.txt deleted file mode 100644 index f229360..0000000 --- a/venv/lib/python3.8/site-packages/requests-2.25.1.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -requests diff --git a/venv/lib/python3.8/site-packages/requests/__init__.py b/venv/lib/python3.8/site-packages/requests/__init__.py deleted file mode 100644 index f8f9429..0000000 --- a/venv/lib/python3.8/site-packages/requests/__init__.py +++ /dev/null @@ -1,137 +0,0 @@ -# -*- coding: utf-8 -*- - -# __ -# /__) _ _ _ _ _/ _ -# / ( (- (/ (/ (- _) / _) -# / - -""" -Requests HTTP Library -~~~~~~~~~~~~~~~~~~~~~ - -Requests is an HTTP library, written in Python, for human beings. -Basic GET usage: - - >>> import requests - >>> r = requests.get('https://www.python.org') - >>> r.status_code - 200 - >>> b'Python is a programming language' in r.content - True - -... or POST: - - >>> payload = dict(key1='value1', key2='value2') - >>> r = requests.post('https://httpbin.org/post', data=payload) - >>> print(r.text) - { - ... - "form": { - "key1": "value1", - "key2": "value2" - }, - ... - } - -The other HTTP methods are supported - see `requests.api`. Full documentation -is at <https://requests.readthedocs.io>. - -:copyright: (c) 2017 by Kenneth Reitz. -:license: Apache 2.0, see LICENSE for more details. -""" - -import urllib3 -import chardet -import warnings -from .exceptions import RequestsDependencyWarning - - -def check_compatibility(urllib3_version, chardet_version): - urllib3_version = urllib3_version.split('.') - assert urllib3_version != ['dev'] # Verify urllib3 isn't installed from git. - - # Sometimes, urllib3 only reports its version as 16.1. - if len(urllib3_version) == 2: - urllib3_version.append('0') - - # Check urllib3 for compatibility. - major, minor, patch = urllib3_version # noqa: F811 - major, minor, patch = int(major), int(minor), int(patch) - # urllib3 >= 1.21.1, <= 1.26 - assert major == 1 - assert minor >= 21 - assert minor <= 26 - - # Check chardet for compatibility. - major, minor, patch = chardet_version.split('.')[:3] - major, minor, patch = int(major), int(minor), int(patch) - # chardet >= 3.0.2, < 5.0.0 - assert (3, 0, 2) <= (major, minor, patch) < (5, 0, 0) - - -def _check_cryptography(cryptography_version): - # cryptography < 1.3.4 - try: - cryptography_version = list(map(int, cryptography_version.split('.'))) - except ValueError: - return - - if cryptography_version < [1, 3, 4]: - warning = 'Old version of cryptography ({}) may cause slowdown.'.format(cryptography_version) - warnings.warn(warning, RequestsDependencyWarning) - -# Check imported dependencies for compatibility. -try: - check_compatibility(urllib3.__version__, chardet.__version__) -except (AssertionError, ValueError): - warnings.warn("urllib3 ({}) or chardet ({}) doesn't match a supported " - "version!".format(urllib3.__version__, chardet.__version__), - RequestsDependencyWarning) - -# Attempt to enable urllib3's fallback for SNI support -# if the standard library doesn't support SNI or the -# 'ssl' library isn't available. -try: - try: - import ssl - except ImportError: - ssl = None - - if not getattr(ssl, "HAS_SNI", False): - from urllib3.contrib import pyopenssl - pyopenssl.inject_into_urllib3() - - # Check cryptography version - from cryptography import __version__ as cryptography_version - _check_cryptography(cryptography_version) -except ImportError: - pass - -# urllib3's DependencyWarnings should be silenced. -from urllib3.exceptions import DependencyWarning -warnings.simplefilter('ignore', DependencyWarning) - -from .__version__ import __title__, __description__, __url__, __version__ -from .__version__ import __build__, __author__, __author_email__, __license__ -from .__version__ import __copyright__, __cake__ - -from . import utils -from . import packages -from .models import Request, Response, PreparedRequest -from .api import request, get, head, post, patch, put, delete, options -from .sessions import session, Session -from .status_codes import codes -from .exceptions import ( - RequestException, Timeout, URLRequired, - TooManyRedirects, HTTPError, ConnectionError, - FileModeWarning, ConnectTimeout, ReadTimeout -) - -# Set default logging handler to avoid "No handler found" warnings. -import logging -from logging import NullHandler - -logging.getLogger(__name__).addHandler(NullHandler()) - -# FileModeWarnings go off per the default. -warnings.simplefilter('default', FileModeWarning, append=True) diff --git a/venv/lib/python3.8/site-packages/requests/__version__.py b/venv/lib/python3.8/site-packages/requests/__version__.py deleted file mode 100644 index 1267488..0000000 --- a/venv/lib/python3.8/site-packages/requests/__version__.py +++ /dev/null @@ -1,14 +0,0 @@ -# .-. .-. .-. . . .-. .-. .-. .-. -# |( |- |.| | | |- `-. | `-. -# ' ' `-' `-`.`-' `-' `-' ' `-' - -__title__ = 'requests' -__description__ = 'Python HTTP for Humans.' -__url__ = 'https://requests.readthedocs.io' -__version__ = '2.25.1' -__build__ = 0x022501 -__author__ = 'Kenneth Reitz' -__author_email__ = 'me@kennethreitz.org' -__license__ = 'Apache 2.0' -__copyright__ = 'Copyright 2020 Kenneth Reitz' -__cake__ = u'\u2728 \U0001f370 \u2728' diff --git a/venv/lib/python3.8/site-packages/requests/_internal_utils.py b/venv/lib/python3.8/site-packages/requests/_internal_utils.py deleted file mode 100644 index 759d9a5..0000000 --- a/venv/lib/python3.8/site-packages/requests/_internal_utils.py +++ /dev/null @@ -1,42 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -requests._internal_utils -~~~~~~~~~~~~~~ - -Provides utility functions that are consumed internally by Requests -which depend on extremely few external helpers (such as compat) -""" - -from .compat import is_py2, builtin_str, str - - -def to_native_string(string, encoding='ascii'): - """Given a string object, regardless of type, returns a representation of - that string in the native string type, encoding and decoding where - necessary. This assumes ASCII unless told otherwise. - """ - if isinstance(string, builtin_str): - out = string - else: - if is_py2: - out = string.encode(encoding) - else: - out = string.decode(encoding) - - return out - - -def unicode_is_ascii(u_string): - """Determine if unicode string only contains ASCII characters. - - :param str u_string: unicode string to check. Must be unicode - and not Python 2 `str`. - :rtype: bool - """ - assert isinstance(u_string, str) - try: - u_string.encode('ascii') - return True - except UnicodeEncodeError: - return False diff --git a/venv/lib/python3.8/site-packages/requests/adapters.py b/venv/lib/python3.8/site-packages/requests/adapters.py deleted file mode 100644 index fa4d9b3..0000000 --- a/venv/lib/python3.8/site-packages/requests/adapters.py +++ /dev/null @@ -1,533 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -requests.adapters -~~~~~~~~~~~~~~~~~ - -This module contains the transport adapters that Requests uses to define -and maintain connections. -""" - -import os.path -import socket - -from urllib3.poolmanager import PoolManager, proxy_from_url -from urllib3.response import HTTPResponse -from urllib3.util import parse_url -from urllib3.util import Timeout as TimeoutSauce -from urllib3.util.retry import Retry -from urllib3.exceptions import ClosedPoolError -from urllib3.exceptions import ConnectTimeoutError -from urllib3.exceptions import HTTPError as _HTTPError -from urllib3.exceptions import MaxRetryError -from urllib3.exceptions import NewConnectionError -from urllib3.exceptions import ProxyError as _ProxyError -from urllib3.exceptions import ProtocolError -from urllib3.exceptions import ReadTimeoutError -from urllib3.exceptions import SSLError as _SSLError -from urllib3.exceptions import ResponseError -from urllib3.exceptions import LocationValueError - -from .models import Response -from .compat import urlparse, basestring -from .utils import (DEFAULT_CA_BUNDLE_PATH, extract_zipped_paths, - get_encoding_from_headers, prepend_scheme_if_needed, - get_auth_from_url, urldefragauth, select_proxy) -from .structures import CaseInsensitiveDict -from .cookies import extract_cookies_to_jar -from .exceptions import (ConnectionError, ConnectTimeout, ReadTimeout, SSLError, - ProxyError, RetryError, InvalidSchema, InvalidProxyURL, - InvalidURL) -from .auth import _basic_auth_str - -try: - from urllib3.contrib.socks import SOCKSProxyManager -except ImportError: - def SOCKSProxyManager(*args, **kwargs): - raise InvalidSchema("Missing dependencies for SOCKS support.") - -DEFAULT_POOLBLOCK = False -DEFAULT_POOLSIZE = 10 -DEFAULT_RETRIES = 0 -DEFAULT_POOL_TIMEOUT = None - - -class BaseAdapter(object): - """The Base Transport Adapter""" - - def __init__(self): - super(BaseAdapter, self).__init__() - - def send(self, request, stream=False, timeout=None, verify=True, - cert=None, proxies=None): - """Sends PreparedRequest object. Returns Response object. - - :param request: The :class:`PreparedRequest <PreparedRequest>` being sent. - :param stream: (optional) Whether to stream the request content. - :param timeout: (optional) How long to wait for the server to send - data before giving up, as a float, or a :ref:`(connect timeout, - read timeout) <timeouts>` tuple. - :type timeout: float or tuple - :param verify: (optional) Either a boolean, in which case it controls whether we verify - the server's TLS certificate, or a string, in which case it must be a path - to a CA bundle to use - :param cert: (optional) Any user-provided SSL certificate to be trusted. - :param proxies: (optional) The proxies dictionary to apply to the request. - """ - raise NotImplementedError - - def close(self): - """Cleans up adapter specific items.""" - raise NotImplementedError - - -class HTTPAdapter(BaseAdapter): - """The built-in HTTP Adapter for urllib3. - - Provides a general-case interface for Requests sessions to contact HTTP and - HTTPS urls by implementing the Transport Adapter interface. This class will - usually be created by the :class:`Session <Session>` class under the - covers. - - :param pool_connections: The number of urllib3 connection pools to cache. - :param pool_maxsize: The maximum number of connections to save in the pool. - :param max_retries: The maximum number of retries each connection - should attempt. Note, this applies only to failed DNS lookups, socket - connections and connection timeouts, never to requests where data has - made it to the server. By default, Requests does not retry failed - connections. If you need granular control over the conditions under - which we retry a request, import urllib3's ``Retry`` class and pass - that instead. - :param pool_block: Whether the connection pool should block for connections. - - Usage:: - - >>> import requests - >>> s = requests.Session() - >>> a = requests.adapters.HTTPAdapter(max_retries=3) - >>> s.mount('http://', a) - """ - __attrs__ = ['max_retries', 'config', '_pool_connections', '_pool_maxsize', - '_pool_block'] - - def __init__(self, pool_connections=DEFAULT_POOLSIZE, - pool_maxsize=DEFAULT_POOLSIZE, max_retries=DEFAULT_RETRIES, - pool_block=DEFAULT_POOLBLOCK): - if max_retries == DEFAULT_RETRIES: - self.max_retries = Retry(0, read=False) - else: - self.max_retries = Retry.from_int(max_retries) - self.config = {} - self.proxy_manager = {} - - super(HTTPAdapter, self).__init__() - - self._pool_connections = pool_connections - self._pool_maxsize = pool_maxsize - self._pool_block = pool_block - - self.init_poolmanager(pool_connections, pool_maxsize, block=pool_block) - - def __getstate__(self): - return {attr: getattr(self, attr, None) for attr in self.__attrs__} - - def __setstate__(self, state): - # Can't handle by adding 'proxy_manager' to self.__attrs__ because - # self.poolmanager uses a lambda function, which isn't pickleable. - self.proxy_manager = {} - self.config = {} - - for attr, value in state.items(): - setattr(self, attr, value) - - self.init_poolmanager(self._pool_connections, self._pool_maxsize, - block=self._pool_block) - - def init_poolmanager(self, connections, maxsize, block=DEFAULT_POOLBLOCK, **pool_kwargs): - """Initializes a urllib3 PoolManager. - - This method should not be called from user code, and is only - exposed for use when subclassing the - :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. - - :param connections: The number of urllib3 connection pools to cache. - :param maxsize: The maximum number of connections to save in the pool. - :param block: Block when no free connections are available. - :param pool_kwargs: Extra keyword arguments used to initialize the Pool Manager. - """ - # save these values for pickling - self._pool_connections = connections - self._pool_maxsize = maxsize - self._pool_block = block - - self.poolmanager = PoolManager(num_pools=connections, maxsize=maxsize, - block=block, strict=True, **pool_kwargs) - - def proxy_manager_for(self, proxy, **proxy_kwargs): - """Return urllib3 ProxyManager for the given proxy. - - This method should not be called from user code, and is only - exposed for use when subclassing the - :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. - - :param proxy: The proxy to return a urllib3 ProxyManager for. - :param proxy_kwargs: Extra keyword arguments used to configure the Proxy Manager. - :returns: ProxyManager - :rtype: urllib3.ProxyManager - """ - if proxy in self.proxy_manager: - manager = self.proxy_manager[proxy] - elif proxy.lower().startswith('socks'): - username, password = get_auth_from_url(proxy) - manager = self.proxy_manager[proxy] = SOCKSProxyManager( - proxy, - username=username, - password=password, - num_pools=self._pool_connections, - maxsize=self._pool_maxsize, - block=self._pool_block, - **proxy_kwargs - ) - else: - proxy_headers = self.proxy_headers(proxy) - manager = self.proxy_manager[proxy] = proxy_from_url( - proxy, - proxy_headers=proxy_headers, - num_pools=self._pool_connections, - maxsize=self._pool_maxsize, - block=self._pool_block, - **proxy_kwargs) - - return manager - - def cert_verify(self, conn, url, verify, cert): - """Verify a SSL certificate. This method should not be called from user - code, and is only exposed for use when subclassing the - :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. - - :param conn: The urllib3 connection object associated with the cert. - :param url: The requested URL. - :param verify: Either a boolean, in which case it controls whether we verify - the server's TLS certificate, or a string, in which case it must be a path - to a CA bundle to use - :param cert: The SSL certificate to verify. - """ - if url.lower().startswith('https') and verify: - - cert_loc = None - - # Allow self-specified cert location. - if verify is not True: - cert_loc = verify - - if not cert_loc: - cert_loc = extract_zipped_paths(DEFAULT_CA_BUNDLE_PATH) - - if not cert_loc or not os.path.exists(cert_loc): - raise IOError("Could not find a suitable TLS CA certificate bundle, " - "invalid path: {}".format(cert_loc)) - - conn.cert_reqs = 'CERT_REQUIRED' - - if not os.path.isdir(cert_loc): - conn.ca_certs = cert_loc - else: - conn.ca_cert_dir = cert_loc - else: - conn.cert_reqs = 'CERT_NONE' - conn.ca_certs = None - conn.ca_cert_dir = None - - if cert: - if not isinstance(cert, basestring): - conn.cert_file = cert[0] - conn.key_file = cert[1] - else: - conn.cert_file = cert - conn.key_file = None - if conn.cert_file and not os.path.exists(conn.cert_file): - raise IOError("Could not find the TLS certificate file, " - "invalid path: {}".format(conn.cert_file)) - if conn.key_file and not os.path.exists(conn.key_file): - raise IOError("Could not find the TLS key file, " - "invalid path: {}".format(conn.key_file)) - - def build_response(self, req, resp): - """Builds a :class:`Response <requests.Response>` object from a urllib3 - response. This should not be called from user code, and is only exposed - for use when subclassing the - :class:`HTTPAdapter <requests.adapters.HTTPAdapter>` - - :param req: The :class:`PreparedRequest <PreparedRequest>` used to generate the response. - :param resp: The urllib3 response object. - :rtype: requests.Response - """ - response = Response() - - # Fallback to None if there's no status_code, for whatever reason. - response.status_code = getattr(resp, 'status', None) - - # Make headers case-insensitive. - response.headers = CaseInsensitiveDict(getattr(resp, 'headers', {})) - - # Set encoding. - response.encoding = get_encoding_from_headers(response.headers) - response.raw = resp - response.reason = response.raw.reason - - if isinstance(req.url, bytes): - response.url = req.url.decode('utf-8') - else: - response.url = req.url - - # Add new cookies from the server. - extract_cookies_to_jar(response.cookies, req, resp) - - # Give the Response some context. - response.request = req - response.connection = self - - return response - - def get_connection(self, url, proxies=None): - """Returns a urllib3 connection for the given URL. This should not be - called from user code, and is only exposed for use when subclassing the - :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. - - :param url: The URL to connect to. - :param proxies: (optional) A Requests-style dictionary of proxies used on this request. - :rtype: urllib3.ConnectionPool - """ - proxy = select_proxy(url, proxies) - - if proxy: - proxy = prepend_scheme_if_needed(proxy, 'http') - proxy_url = parse_url(proxy) - if not proxy_url.host: - raise InvalidProxyURL("Please check proxy URL. It is malformed" - " and could be missing the host.") - proxy_manager = self.proxy_manager_for(proxy) - conn = proxy_manager.connection_from_url(url) - else: - # Only scheme should be lower case - parsed = urlparse(url) - url = parsed.geturl() - conn = self.poolmanager.connection_from_url(url) - - return conn - - def close(self): - """Disposes of any internal state. - - Currently, this closes the PoolManager and any active ProxyManager, - which closes any pooled connections. - """ - self.poolmanager.clear() - for proxy in self.proxy_manager.values(): - proxy.clear() - - def request_url(self, request, proxies): - """Obtain the url to use when making the final request. - - If the message is being sent through a HTTP proxy, the full URL has to - be used. Otherwise, we should only use the path portion of the URL. - - This should not be called from user code, and is only exposed for use - when subclassing the - :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. - - :param request: The :class:`PreparedRequest <PreparedRequest>` being sent. - :param proxies: A dictionary of schemes or schemes and hosts to proxy URLs. - :rtype: str - """ - proxy = select_proxy(request.url, proxies) - scheme = urlparse(request.url).scheme - - is_proxied_http_request = (proxy and scheme != 'https') - using_socks_proxy = False - if proxy: - proxy_scheme = urlparse(proxy).scheme.lower() - using_socks_proxy = proxy_scheme.startswith('socks') - - url = request.path_url - if is_proxied_http_request and not using_socks_proxy: - url = urldefragauth(request.url) - - return url - - def add_headers(self, request, **kwargs): - """Add any headers needed by the connection. As of v2.0 this does - nothing by default, but is left for overriding by users that subclass - the :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. - - This should not be called from user code, and is only exposed for use - when subclassing the - :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. - - :param request: The :class:`PreparedRequest <PreparedRequest>` to add headers to. - :param kwargs: The keyword arguments from the call to send(). - """ - pass - - def proxy_headers(self, proxy): - """Returns a dictionary of the headers to add to any request sent - through a proxy. This works with urllib3 magic to ensure that they are - correctly sent to the proxy, rather than in a tunnelled request if - CONNECT is being used. - - This should not be called from user code, and is only exposed for use - when subclassing the - :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`. - - :param proxy: The url of the proxy being used for this request. - :rtype: dict - """ - headers = {} - username, password = get_auth_from_url(proxy) - - if username: - headers['Proxy-Authorization'] = _basic_auth_str(username, - password) - - return headers - - def send(self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None): - """Sends PreparedRequest object. Returns Response object. - - :param request: The :class:`PreparedRequest <PreparedRequest>` being sent. - :param stream: (optional) Whether to stream the request content. - :param timeout: (optional) How long to wait for the server to send - data before giving up, as a float, or a :ref:`(connect timeout, - read timeout) <timeouts>` tuple. - :type timeout: float or tuple or urllib3 Timeout object - :param verify: (optional) Either a boolean, in which case it controls whether - we verify the server's TLS certificate, or a string, in which case it - must be a path to a CA bundle to use - :param cert: (optional) Any user-provided SSL certificate to be trusted. - :param proxies: (optional) The proxies dictionary to apply to the request. - :rtype: requests.Response - """ - - try: - conn = self.get_connection(request.url, proxies) - except LocationValueError as e: - raise InvalidURL(e, request=request) - - self.cert_verify(conn, request.url, verify, cert) - url = self.request_url(request, proxies) - self.add_headers(request, stream=stream, timeout=timeout, verify=verify, cert=cert, proxies=proxies) - - chunked = not (request.body is None or 'Content-Length' in request.headers) - - if isinstance(timeout, tuple): - try: - connect, read = timeout - timeout = TimeoutSauce(connect=connect, read=read) - except ValueError as e: - # this may raise a string formatting error. - err = ("Invalid timeout {}. Pass a (connect, read) " - "timeout tuple, or a single float to set " - "both timeouts to the same value".format(timeout)) - raise ValueError(err) - elif isinstance(timeout, TimeoutSauce): - pass - else: - timeout = TimeoutSauce(connect=timeout, read=timeout) - - try: - if not chunked: - resp = conn.urlopen( - method=request.method, - url=url, - body=request.body, - headers=request.headers, - redirect=False, - assert_same_host=False, - preload_content=False, - decode_content=False, - retries=self.max_retries, - timeout=timeout - ) - - # Send the request. - else: - if hasattr(conn, 'proxy_pool'): - conn = conn.proxy_pool - - low_conn = conn._get_conn(timeout=DEFAULT_POOL_TIMEOUT) - - try: - low_conn.putrequest(request.method, - url, - skip_accept_encoding=True) - - for header, value in request.headers.items(): - low_conn.putheader(header, value) - - low_conn.endheaders() - - for i in request.body: - low_conn.send(hex(len(i))[2:].encode('utf-8')) - low_conn.send(b'\r\n') - low_conn.send(i) - low_conn.send(b'\r\n') - low_conn.send(b'0\r\n\r\n') - - # Receive the response from the server - try: - # For Python 2.7, use buffering of HTTP responses - r = low_conn.getresponse(buffering=True) - except TypeError: - # For compatibility with Python 3.3+ - r = low_conn.getresponse() - - resp = HTTPResponse.from_httplib( - r, - pool=conn, - connection=low_conn, - preload_content=False, - decode_content=False - ) - except: - # If we hit any problems here, clean up the connection. - # Then, reraise so that we can handle the actual exception. - low_conn.close() - raise - - except (ProtocolError, socket.error) as err: - raise ConnectionError(err, request=request) - - except MaxRetryError as e: - if isinstance(e.reason, ConnectTimeoutError): - # TODO: Remove this in 3.0.0: see #2811 - if not isinstance(e.reason, NewConnectionError): - raise ConnectTimeout(e, request=request) - - if isinstance(e.reason, ResponseError): - raise RetryError(e, request=request) - - if isinstance(e.reason, _ProxyError): - raise ProxyError(e, request=request) - - if isinstance(e.reason, _SSLError): - # This branch is for urllib3 v1.22 and later. - raise SSLError(e, request=request) - - raise ConnectionError(e, request=request) - - except ClosedPoolError as e: - raise ConnectionError(e, request=request) - - except _ProxyError as e: - raise ProxyError(e) - - except (_SSLError, _HTTPError) as e: - if isinstance(e, _SSLError): - # This branch is for urllib3 versions earlier than v1.22 - raise SSLError(e, request=request) - elif isinstance(e, ReadTimeoutError): - raise ReadTimeout(e, request=request) - else: - raise - - return self.build_response(request, resp) diff --git a/venv/lib/python3.8/site-packages/requests/api.py b/venv/lib/python3.8/site-packages/requests/api.py deleted file mode 100644 index e978e20..0000000 --- a/venv/lib/python3.8/site-packages/requests/api.py +++ /dev/null @@ -1,161 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -requests.api -~~~~~~~~~~~~ - -This module implements the Requests API. - -:copyright: (c) 2012 by Kenneth Reitz. -:license: Apache2, see LICENSE for more details. -""" - -from . import sessions - - -def request(method, url, **kwargs): - """Constructs and sends a :class:`Request <Request>`. - - :param method: method for the new :class:`Request` object: ``GET``, ``OPTIONS``, ``HEAD``, ``POST``, ``PUT``, ``PATCH``, or ``DELETE``. - :param url: URL for the new :class:`Request` object. - :param params: (optional) Dictionary, list of tuples or bytes to send - in the query string for the :class:`Request`. - :param data: (optional) Dictionary, list of tuples, bytes, or file-like - object to send in the body of the :class:`Request`. - :param json: (optional) A JSON serializable Python object to send in the body of the :class:`Request`. - :param headers: (optional) Dictionary of HTTP Headers to send with the :class:`Request`. - :param cookies: (optional) Dict or CookieJar object to send with the :class:`Request`. - :param files: (optional) Dictionary of ``'name': file-like-objects`` (or ``{'name': file-tuple}``) for multipart encoding upload. - ``file-tuple`` can be a 2-tuple ``('filename', fileobj)``, 3-tuple ``('filename', fileobj, 'content_type')`` - or a 4-tuple ``('filename', fileobj, 'content_type', custom_headers)``, where ``'content-type'`` is a string - defining the content type of the given file and ``custom_headers`` a dict-like object containing additional headers - to add for the file. - :param auth: (optional) Auth tuple to enable Basic/Digest/Custom HTTP Auth. - :param timeout: (optional) How many seconds to wait for the server to send data - before giving up, as a float, or a :ref:`(connect timeout, read - timeout) <timeouts>` tuple. - :type timeout: float or tuple - :param allow_redirects: (optional) Boolean. Enable/disable GET/OPTIONS/POST/PUT/PATCH/DELETE/HEAD redirection. Defaults to ``True``. - :type allow_redirects: bool - :param proxies: (optional) Dictionary mapping protocol to the URL of the proxy. - :param verify: (optional) Either a boolean, in which case it controls whether we verify - the server's TLS certificate, or a string, in which case it must be a path - to a CA bundle to use. Defaults to ``True``. - :param stream: (optional) if ``False``, the response content will be immediately downloaded. - :param cert: (optional) if String, path to ssl client cert file (.pem). If Tuple, ('cert', 'key') pair. - :return: :class:`Response <Response>` object - :rtype: requests.Response - - Usage:: - - >>> import requests - >>> req = requests.request('GET', 'https://httpbin.org/get') - >>> req - <Response [200]> - """ - - # By using the 'with' statement we are sure the session is closed, thus we - # avoid leaving sockets open which can trigger a ResourceWarning in some - # cases, and look like a memory leak in others. - with sessions.Session() as session: - return session.request(method=method, url=url, **kwargs) - - -def get(url, params=None, **kwargs): - r"""Sends a GET request. - - :param url: URL for the new :class:`Request` object. - :param params: (optional) Dictionary, list of tuples or bytes to send - in the query string for the :class:`Request`. - :param \*\*kwargs: Optional arguments that ``request`` takes. - :return: :class:`Response <Response>` object - :rtype: requests.Response - """ - - kwargs.setdefault('allow_redirects', True) - return request('get', url, params=params, **kwargs) - - -def options(url, **kwargs): - r"""Sends an OPTIONS request. - - :param url: URL for the new :class:`Request` object. - :param \*\*kwargs: Optional arguments that ``request`` takes. - :return: :class:`Response <Response>` object - :rtype: requests.Response - """ - - kwargs.setdefault('allow_redirects', True) - return request('options', url, **kwargs) - - -def head(url, **kwargs): - r"""Sends a HEAD request. - - :param url: URL for the new :class:`Request` object. - :param \*\*kwargs: Optional arguments that ``request`` takes. If - `allow_redirects` is not provided, it will be set to `False` (as - opposed to the default :meth:`request` behavior). - :return: :class:`Response <Response>` object - :rtype: requests.Response - """ - - kwargs.setdefault('allow_redirects', False) - return request('head', url, **kwargs) - - -def post(url, data=None, json=None, **kwargs): - r"""Sends a POST request. - - :param url: URL for the new :class:`Request` object. - :param data: (optional) Dictionary, list of tuples, bytes, or file-like - object to send in the body of the :class:`Request`. - :param json: (optional) json data to send in the body of the :class:`Request`. - :param \*\*kwargs: Optional arguments that ``request`` takes. - :return: :class:`Response <Response>` object - :rtype: requests.Response - """ - - return request('post', url, data=data, json=json, **kwargs) - - -def put(url, data=None, **kwargs): - r"""Sends a PUT request. - - :param url: URL for the new :class:`Request` object. - :param data: (optional) Dictionary, list of tuples, bytes, or file-like - object to send in the body of the :class:`Request`. - :param json: (optional) json data to send in the body of the :class:`Request`. - :param \*\*kwargs: Optional arguments that ``request`` takes. - :return: :class:`Response <Response>` object - :rtype: requests.Response - """ - - return request('put', url, data=data, **kwargs) - - -def patch(url, data=None, **kwargs): - r"""Sends a PATCH request. - - :param url: URL for the new :class:`Request` object. - :param data: (optional) Dictionary, list of tuples, bytes, or file-like - object to send in the body of the :class:`Request`. - :param json: (optional) json data to send in the body of the :class:`Request`. - :param \*\*kwargs: Optional arguments that ``request`` takes. - :return: :class:`Response <Response>` object - :rtype: requests.Response - """ - - return request('patch', url, data=data, **kwargs) - - -def delete(url, **kwargs): - r"""Sends a DELETE request. - - :param url: URL for the new :class:`Request` object. - :param \*\*kwargs: Optional arguments that ``request`` takes. - :return: :class:`Response <Response>` object - :rtype: requests.Response - """ - - return request('delete', url, **kwargs) diff --git a/venv/lib/python3.8/site-packages/requests/auth.py b/venv/lib/python3.8/site-packages/requests/auth.py deleted file mode 100644 index eeface3..0000000 --- a/venv/lib/python3.8/site-packages/requests/auth.py +++ /dev/null @@ -1,305 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -requests.auth -~~~~~~~~~~~~~ - -This module contains the authentication handlers for Requests. -""" - -import os -import re -import time -import hashlib -import threading -import warnings - -from base64 import b64encode - -from .compat import urlparse, str, basestring -from .cookies import extract_cookies_to_jar -from ._internal_utils import to_native_string -from .utils import parse_dict_header - -CONTENT_TYPE_FORM_URLENCODED = 'application/x-www-form-urlencoded' -CONTENT_TYPE_MULTI_PART = 'multipart/form-data' - - -def _basic_auth_str(username, password): - """Returns a Basic Auth string.""" - - # "I want us to put a big-ol' comment on top of it that - # says that this behaviour is dumb but we need to preserve - # it because people are relying on it." - # - Lukasa - # - # These are here solely to maintain backwards compatibility - # for things like ints. This will be removed in 3.0.0. - if not isinstance(username, basestring): - warnings.warn( - "Non-string usernames will no longer be supported in Requests " - "3.0.0. Please convert the object you've passed in ({!r}) to " - "a string or bytes object in the near future to avoid " - "problems.".format(username), - category=DeprecationWarning, - ) - username = str(username) - - if not isinstance(password, basestring): - warnings.warn( - "Non-string passwords will no longer be supported in Requests " - "3.0.0. Please convert the object you've passed in ({!r}) to " - "a string or bytes object in the near future to avoid " - "problems.".format(type(password)), - category=DeprecationWarning, - ) - password = str(password) - # -- End Removal -- - - if isinstance(username, str): - username = username.encode('latin1') - - if isinstance(password, str): - password = password.encode('latin1') - - authstr = 'Basic ' + to_native_string( - b64encode(b':'.join((username, password))).strip() - ) - - return authstr - - -class AuthBase(object): - """Base class that all auth implementations derive from""" - - def __call__(self, r): - raise NotImplementedError('Auth hooks must be callable.') - - -class HTTPBasicAuth(AuthBase): - """Attaches HTTP Basic Authentication to the given Request object.""" - - def __init__(self, username, password): - self.username = username - self.password = password - - def __eq__(self, other): - return all([ - self.username == getattr(other, 'username', None), - self.password == getattr(other, 'password', None) - ]) - - def __ne__(self, other): - return not self == other - - def __call__(self, r): - r.headers['Authorization'] = _basic_auth_str(self.username, self.password) - return r - - -class HTTPProxyAuth(HTTPBasicAuth): - """Attaches HTTP Proxy Authentication to a given Request object.""" - - def __call__(self, r): - r.headers['Proxy-Authorization'] = _basic_auth_str(self.username, self.password) - return r - - -class HTTPDigestAuth(AuthBase): - """Attaches HTTP Digest Authentication to the given Request object.""" - - def __init__(self, username, password): - self.username = username - self.password = password - # Keep state in per-thread local storage - self._thread_local = threading.local() - - def init_per_thread_state(self): - # Ensure state is initialized just once per-thread - if not hasattr(self._thread_local, 'init'): - self._thread_local.init = True - self._thread_local.last_nonce = '' - self._thread_local.nonce_count = 0 - self._thread_local.chal = {} - self._thread_local.pos = None - self._thread_local.num_401_calls = None - - def build_digest_header(self, method, url): - """ - :rtype: str - """ - - realm = self._thread_local.chal['realm'] - nonce = self._thread_local.chal['nonce'] - qop = self._thread_local.chal.get('qop') - algorithm = self._thread_local.chal.get('algorithm') - opaque = self._thread_local.chal.get('opaque') - hash_utf8 = None - - if algorithm is None: - _algorithm = 'MD5' - else: - _algorithm = algorithm.upper() - # lambdas assume digest modules are imported at the top level - if _algorithm == 'MD5' or _algorithm == 'MD5-SESS': - def md5_utf8(x): - if isinstance(x, str): - x = x.encode('utf-8') - return hashlib.md5(x).hexdigest() - hash_utf8 = md5_utf8 - elif _algorithm == 'SHA': - def sha_utf8(x): - if isinstance(x, str): - x = x.encode('utf-8') - return hashlib.sha1(x).hexdigest() - hash_utf8 = sha_utf8 - elif _algorithm == 'SHA-256': - def sha256_utf8(x): - if isinstance(x, str): - x = x.encode('utf-8') - return hashlib.sha256(x).hexdigest() - hash_utf8 = sha256_utf8 - elif _algorithm == 'SHA-512': - def sha512_utf8(x): - if isinstance(x, str): - x = x.encode('utf-8') - return hashlib.sha512(x).hexdigest() - hash_utf8 = sha512_utf8 - - KD = lambda s, d: hash_utf8("%s:%s" % (s, d)) - - if hash_utf8 is None: - return None - - # XXX not implemented yet - entdig = None - p_parsed = urlparse(url) - #: path is request-uri defined in RFC 2616 which should not be empty - path = p_parsed.path or "/" - if p_parsed.query: - path += '?' + p_parsed.query - - A1 = '%s:%s:%s' % (self.username, realm, self.password) - A2 = '%s:%s' % (method, path) - - HA1 = hash_utf8(A1) - HA2 = hash_utf8(A2) - - if nonce == self._thread_local.last_nonce: - self._thread_local.nonce_count += 1 - else: - self._thread_local.nonce_count = 1 - ncvalue = '%08x' % self._thread_local.nonce_count - s = str(self._thread_local.nonce_count).encode('utf-8') - s += nonce.encode('utf-8') - s += time.ctime().encode('utf-8') - s += os.urandom(8) - - cnonce = (hashlib.sha1(s).hexdigest()[:16]) - if _algorithm == 'MD5-SESS': - HA1 = hash_utf8('%s:%s:%s' % (HA1, nonce, cnonce)) - - if not qop: - respdig = KD(HA1, "%s:%s" % (nonce, HA2)) - elif qop == 'auth' or 'auth' in qop.split(','): - noncebit = "%s:%s:%s:%s:%s" % ( - nonce, ncvalue, cnonce, 'auth', HA2 - ) - respdig = KD(HA1, noncebit) - else: - # XXX handle auth-int. - return None - - self._thread_local.last_nonce = nonce - - # XXX should the partial digests be encoded too? - base = 'username="%s", realm="%s", nonce="%s", uri="%s", ' \ - 'response="%s"' % (self.username, realm, nonce, path, respdig) - if opaque: - base += ', opaque="%s"' % opaque - if algorithm: - base += ', algorithm="%s"' % algorithm - if entdig: - base += ', digest="%s"' % entdig - if qop: - base += ', qop="auth", nc=%s, cnonce="%s"' % (ncvalue, cnonce) - - return 'Digest %s' % (base) - - def handle_redirect(self, r, **kwargs): - """Reset num_401_calls counter on redirects.""" - if r.is_redirect: - self._thread_local.num_401_calls = 1 - - def handle_401(self, r, **kwargs): - """ - Takes the given response and tries digest-auth, if needed. - - :rtype: requests.Response - """ - - # If response is not 4xx, do not auth - # See https://github.com/psf/requests/issues/3772 - if not 400 <= r.status_code < 500: - self._thread_local.num_401_calls = 1 - return r - - if self._thread_local.pos is not None: - # Rewind the file position indicator of the body to where - # it was to resend the request. - r.request.body.seek(self._thread_local.pos) - s_auth = r.headers.get('www-authenticate', '') - - if 'digest' in s_auth.lower() and self._thread_local.num_401_calls < 2: - - self._thread_local.num_401_calls += 1 - pat = re.compile(r'digest ', flags=re.IGNORECASE) - self._thread_local.chal = parse_dict_header(pat.sub('', s_auth, count=1)) - - # Consume content and release the original connection - # to allow our new request to reuse the same one. - r.content - r.close() - prep = r.request.copy() - extract_cookies_to_jar(prep._cookies, r.request, r.raw) - prep.prepare_cookies(prep._cookies) - - prep.headers['Authorization'] = self.build_digest_header( - prep.method, prep.url) - _r = r.connection.send(prep, **kwargs) - _r.history.append(r) - _r.request = prep - - return _r - - self._thread_local.num_401_calls = 1 - return r - - def __call__(self, r): - # Initialize per-thread state, if needed - self.init_per_thread_state() - # If we have a saved nonce, skip the 401 - if self._thread_local.last_nonce: - r.headers['Authorization'] = self.build_digest_header(r.method, r.url) - try: - self._thread_local.pos = r.body.tell() - except AttributeError: - # In the case of HTTPDigestAuth being reused and the body of - # the previous request was a file-like object, pos has the - # file position of the previous body. Ensure it's set to - # None. - self._thread_local.pos = None - r.register_hook('response', self.handle_401) - r.register_hook('response', self.handle_redirect) - self._thread_local.num_401_calls = 1 - - return r - - def __eq__(self, other): - return all([ - self.username == getattr(other, 'username', None), - self.password == getattr(other, 'password', None) - ]) - - def __ne__(self, other): - return not self == other diff --git a/venv/lib/python3.8/site-packages/requests/certs.py b/venv/lib/python3.8/site-packages/requests/certs.py deleted file mode 100644 index d1a378d..0000000 --- a/venv/lib/python3.8/site-packages/requests/certs.py +++ /dev/null @@ -1,18 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- - -""" -requests.certs -~~~~~~~~~~~~~~ - -This module returns the preferred default CA certificate bundle. There is -only one — the one from the certifi package. - -If you are packaging Requests, e.g., for a Linux distribution or a managed -environment, you can change the definition of where() to return a separately -packaged CA bundle. -""" -from certifi import where - -if __name__ == '__main__': - print(where()) diff --git a/venv/lib/python3.8/site-packages/requests/compat.py b/venv/lib/python3.8/site-packages/requests/compat.py deleted file mode 100644 index 5de0769..0000000 --- a/venv/lib/python3.8/site-packages/requests/compat.py +++ /dev/null @@ -1,72 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -requests.compat -~~~~~~~~~~~~~~~ - -This module handles import compatibility issues between Python 2 and -Python 3. -""" - -import chardet - -import sys - -# ------- -# Pythons -# ------- - -# Syntax sugar. -_ver = sys.version_info - -#: Python 2.x? -is_py2 = (_ver[0] == 2) - -#: Python 3.x? -is_py3 = (_ver[0] == 3) - -try: - import simplejson as json -except ImportError: - import json - -# --------- -# Specifics -# --------- - -if is_py2: - from urllib import ( - quote, unquote, quote_plus, unquote_plus, urlencode, getproxies, - proxy_bypass, proxy_bypass_environment, getproxies_environment) - from urlparse import urlparse, urlunparse, urljoin, urlsplit, urldefrag - from urllib2 import parse_http_list - import cookielib - from Cookie import Morsel - from StringIO import StringIO - # Keep OrderedDict for backwards compatibility. - from collections import Callable, Mapping, MutableMapping, OrderedDict - - - builtin_str = str - bytes = str - str = unicode - basestring = basestring - numeric_types = (int, long, float) - integer_types = (int, long) - -elif is_py3: - from urllib.parse import urlparse, urlunparse, urljoin, urlsplit, urlencode, quote, unquote, quote_plus, unquote_plus, urldefrag - from urllib.request import parse_http_list, getproxies, proxy_bypass, proxy_bypass_environment, getproxies_environment - from http import cookiejar as cookielib - from http.cookies import Morsel - from io import StringIO - # Keep OrderedDict for backwards compatibility. - from collections import OrderedDict - from collections.abc import Callable, Mapping, MutableMapping - - builtin_str = str - str = str - bytes = bytes - basestring = (str, bytes) - numeric_types = (int, float) - integer_types = (int,) diff --git a/venv/lib/python3.8/site-packages/requests/cookies.py b/venv/lib/python3.8/site-packages/requests/cookies.py deleted file mode 100644 index 56fccd9..0000000 --- a/venv/lib/python3.8/site-packages/requests/cookies.py +++ /dev/null @@ -1,549 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -requests.cookies -~~~~~~~~~~~~~~~~ - -Compatibility code to be able to use `cookielib.CookieJar` with requests. - -requests.utils imports from here, so be careful with imports. -""" - -import copy -import time -import calendar - -from ._internal_utils import to_native_string -from .compat import cookielib, urlparse, urlunparse, Morsel, MutableMapping - -try: - import threading -except ImportError: - import dummy_threading as threading - - -class MockRequest(object): - """Wraps a `requests.Request` to mimic a `urllib2.Request`. - - The code in `cookielib.CookieJar` expects this interface in order to correctly - manage cookie policies, i.e., determine whether a cookie can be set, given the - domains of the request and the cookie. - - The original request object is read-only. The client is responsible for collecting - the new headers via `get_new_headers()` and interpreting them appropriately. You - probably want `get_cookie_header`, defined below. - """ - - def __init__(self, request): - self._r = request - self._new_headers = {} - self.type = urlparse(self._r.url).scheme - - def get_type(self): - return self.type - - def get_host(self): - return urlparse(self._r.url).netloc - - def get_origin_req_host(self): - return self.get_host() - - def get_full_url(self): - # Only return the response's URL if the user hadn't set the Host - # header - if not self._r.headers.get('Host'): - return self._r.url - # If they did set it, retrieve it and reconstruct the expected domain - host = to_native_string(self._r.headers['Host'], encoding='utf-8') - parsed = urlparse(self._r.url) - # Reconstruct the URL as we expect it - return urlunparse([ - parsed.scheme, host, parsed.path, parsed.params, parsed.query, - parsed.fragment - ]) - - def is_unverifiable(self): - return True - - def has_header(self, name): - return name in self._r.headers or name in self._new_headers - - def get_header(self, name, default=None): - return self._r.headers.get(name, self._new_headers.get(name, default)) - - def add_header(self, key, val): - """cookielib has no legitimate use for this method; add it back if you find one.""" - raise NotImplementedError("Cookie headers should be added with add_unredirected_header()") - - def add_unredirected_header(self, name, value): - self._new_headers[name] = value - - def get_new_headers(self): - return self._new_headers - - @property - def unverifiable(self): - return self.is_unverifiable() - - @property - def origin_req_host(self): - return self.get_origin_req_host() - - @property - def host(self): - return self.get_host() - - -class MockResponse(object): - """Wraps a `httplib.HTTPMessage` to mimic a `urllib.addinfourl`. - - ...what? Basically, expose the parsed HTTP headers from the server response - the way `cookielib` expects to see them. - """ - - def __init__(self, headers): - """Make a MockResponse for `cookielib` to read. - - :param headers: a httplib.HTTPMessage or analogous carrying the headers - """ - self._headers = headers - - def info(self): - return self._headers - - def getheaders(self, name): - self._headers.getheaders(name) - - -def extract_cookies_to_jar(jar, request, response): - """Extract the cookies from the response into a CookieJar. - - :param jar: cookielib.CookieJar (not necessarily a RequestsCookieJar) - :param request: our own requests.Request object - :param response: urllib3.HTTPResponse object - """ - if not (hasattr(response, '_original_response') and - response._original_response): - return - # the _original_response field is the wrapped httplib.HTTPResponse object, - req = MockRequest(request) - # pull out the HTTPMessage with the headers and put it in the mock: - res = MockResponse(response._original_response.msg) - jar.extract_cookies(res, req) - - -def get_cookie_header(jar, request): - """ - Produce an appropriate Cookie header string to be sent with `request`, or None. - - :rtype: str - """ - r = MockRequest(request) - jar.add_cookie_header(r) - return r.get_new_headers().get('Cookie') - - -def remove_cookie_by_name(cookiejar, name, domain=None, path=None): - """Unsets a cookie by name, by default over all domains and paths. - - Wraps CookieJar.clear(), is O(n). - """ - clearables = [] - for cookie in cookiejar: - if cookie.name != name: - continue - if domain is not None and domain != cookie.domain: - continue - if path is not None and path != cookie.path: - continue - clearables.append((cookie.domain, cookie.path, cookie.name)) - - for domain, path, name in clearables: - cookiejar.clear(domain, path, name) - - -class CookieConflictError(RuntimeError): - """There are two cookies that meet the criteria specified in the cookie jar. - Use .get and .set and include domain and path args in order to be more specific. - """ - - -class RequestsCookieJar(cookielib.CookieJar, MutableMapping): - """Compatibility class; is a cookielib.CookieJar, but exposes a dict - interface. - - This is the CookieJar we create by default for requests and sessions that - don't specify one, since some clients may expect response.cookies and - session.cookies to support dict operations. - - Requests does not use the dict interface internally; it's just for - compatibility with external client code. All requests code should work - out of the box with externally provided instances of ``CookieJar``, e.g. - ``LWPCookieJar`` and ``FileCookieJar``. - - Unlike a regular CookieJar, this class is pickleable. - - .. warning:: dictionary operations that are normally O(1) may be O(n). - """ - - def get(self, name, default=None, domain=None, path=None): - """Dict-like get() that also supports optional domain and path args in - order to resolve naming collisions from using one cookie jar over - multiple domains. - - .. warning:: operation is O(n), not O(1). - """ - try: - return self._find_no_duplicates(name, domain, path) - except KeyError: - return default - - def set(self, name, value, **kwargs): - """Dict-like set() that also supports optional domain and path args in - order to resolve naming collisions from using one cookie jar over - multiple domains. - """ - # support client code that unsets cookies by assignment of a None value: - if value is None: - remove_cookie_by_name(self, name, domain=kwargs.get('domain'), path=kwargs.get('path')) - return - - if isinstance(value, Morsel): - c = morsel_to_cookie(value) - else: - c = create_cookie(name, value, **kwargs) - self.set_cookie(c) - return c - - def iterkeys(self): - """Dict-like iterkeys() that returns an iterator of names of cookies - from the jar. - - .. seealso:: itervalues() and iteritems(). - """ - for cookie in iter(self): - yield cookie.name - - def keys(self): - """Dict-like keys() that returns a list of names of cookies from the - jar. - - .. seealso:: values() and items(). - """ - return list(self.iterkeys()) - - def itervalues(self): - """Dict-like itervalues() that returns an iterator of values of cookies - from the jar. - - .. seealso:: iterkeys() and iteritems(). - """ - for cookie in iter(self): - yield cookie.value - - def values(self): - """Dict-like values() that returns a list of values of cookies from the - jar. - - .. seealso:: keys() and items(). - """ - return list(self.itervalues()) - - def iteritems(self): - """Dict-like iteritems() that returns an iterator of name-value tuples - from the jar. - - .. seealso:: iterkeys() and itervalues(). - """ - for cookie in iter(self): - yield cookie.name, cookie.value - - def items(self): - """Dict-like items() that returns a list of name-value tuples from the - jar. Allows client-code to call ``dict(RequestsCookieJar)`` and get a - vanilla python dict of key value pairs. - - .. seealso:: keys() and values(). - """ - return list(self.iteritems()) - - def list_domains(self): - """Utility method to list all the domains in the jar.""" - domains = [] - for cookie in iter(self): - if cookie.domain not in domains: - domains.append(cookie.domain) - return domains - - def list_paths(self): - """Utility method to list all the paths in the jar.""" - paths = [] - for cookie in iter(self): - if cookie.path not in paths: - paths.append(cookie.path) - return paths - - def multiple_domains(self): - """Returns True if there are multiple domains in the jar. - Returns False otherwise. - - :rtype: bool - """ - domains = [] - for cookie in iter(self): - if cookie.domain is not None and cookie.domain in domains: - return True - domains.append(cookie.domain) - return False # there is only one domain in jar - - def get_dict(self, domain=None, path=None): - """Takes as an argument an optional domain and path and returns a plain - old Python dict of name-value pairs of cookies that meet the - requirements. - - :rtype: dict - """ - dictionary = {} - for cookie in iter(self): - if ( - (domain is None or cookie.domain == domain) and - (path is None or cookie.path == path) - ): - dictionary[cookie.name] = cookie.value - return dictionary - - def __contains__(self, name): - try: - return super(RequestsCookieJar, self).__contains__(name) - except CookieConflictError: - return True - - def __getitem__(self, name): - """Dict-like __getitem__() for compatibility with client code. Throws - exception if there are more than one cookie with name. In that case, - use the more explicit get() method instead. - - .. warning:: operation is O(n), not O(1). - """ - return self._find_no_duplicates(name) - - def __setitem__(self, name, value): - """Dict-like __setitem__ for compatibility with client code. Throws - exception if there is already a cookie of that name in the jar. In that - case, use the more explicit set() method instead. - """ - self.set(name, value) - - def __delitem__(self, name): - """Deletes a cookie given a name. Wraps ``cookielib.CookieJar``'s - ``remove_cookie_by_name()``. - """ - remove_cookie_by_name(self, name) - - def set_cookie(self, cookie, *args, **kwargs): - if hasattr(cookie.value, 'startswith') and cookie.value.startswith('"') and cookie.value.endswith('"'): - cookie.value = cookie.value.replace('\\"', '') - return super(RequestsCookieJar, self).set_cookie(cookie, *args, **kwargs) - - def update(self, other): - """Updates this jar with cookies from another CookieJar or dict-like""" - if isinstance(other, cookielib.CookieJar): - for cookie in other: - self.set_cookie(copy.copy(cookie)) - else: - super(RequestsCookieJar, self).update(other) - - def _find(self, name, domain=None, path=None): - """Requests uses this method internally to get cookie values. - - If there are conflicting cookies, _find arbitrarily chooses one. - See _find_no_duplicates if you want an exception thrown if there are - conflicting cookies. - - :param name: a string containing name of cookie - :param domain: (optional) string containing domain of cookie - :param path: (optional) string containing path of cookie - :return: cookie.value - """ - for cookie in iter(self): - if cookie.name == name: - if domain is None or cookie.domain == domain: - if path is None or cookie.path == path: - return cookie.value - - raise KeyError('name=%r, domain=%r, path=%r' % (name, domain, path)) - - def _find_no_duplicates(self, name, domain=None, path=None): - """Both ``__get_item__`` and ``get`` call this function: it's never - used elsewhere in Requests. - - :param name: a string containing name of cookie - :param domain: (optional) string containing domain of cookie - :param path: (optional) string containing path of cookie - :raises KeyError: if cookie is not found - :raises CookieConflictError: if there are multiple cookies - that match name and optionally domain and path - :return: cookie.value - """ - toReturn = None - for cookie in iter(self): - if cookie.name == name: - if domain is None or cookie.domain == domain: - if path is None or cookie.path == path: - if toReturn is not None: # if there are multiple cookies that meet passed in criteria - raise CookieConflictError('There are multiple cookies with name, %r' % (name)) - toReturn = cookie.value # we will eventually return this as long as no cookie conflict - - if toReturn: - return toReturn - raise KeyError('name=%r, domain=%r, path=%r' % (name, domain, path)) - - def __getstate__(self): - """Unlike a normal CookieJar, this class is pickleable.""" - state = self.__dict__.copy() - # remove the unpickleable RLock object - state.pop('_cookies_lock') - return state - - def __setstate__(self, state): - """Unlike a normal CookieJar, this class is pickleable.""" - self.__dict__.update(state) - if '_cookies_lock' not in self.__dict__: - self._cookies_lock = threading.RLock() - - def copy(self): - """Return a copy of this RequestsCookieJar.""" - new_cj = RequestsCookieJar() - new_cj.set_policy(self.get_policy()) - new_cj.update(self) - return new_cj - - def get_policy(self): - """Return the CookiePolicy instance used.""" - return self._policy - - -def _copy_cookie_jar(jar): - if jar is None: - return None - - if hasattr(jar, 'copy'): - # We're dealing with an instance of RequestsCookieJar - return jar.copy() - # We're dealing with a generic CookieJar instance - new_jar = copy.copy(jar) - new_jar.clear() - for cookie in jar: - new_jar.set_cookie(copy.copy(cookie)) - return new_jar - - -def create_cookie(name, value, **kwargs): - """Make a cookie from underspecified parameters. - - By default, the pair of `name` and `value` will be set for the domain '' - and sent on every request (this is sometimes called a "supercookie"). - """ - result = { - 'version': 0, - 'name': name, - 'value': value, - 'port': None, - 'domain': '', - 'path': '/', - 'secure': False, - 'expires': None, - 'discard': True, - 'comment': None, - 'comment_url': None, - 'rest': {'HttpOnly': None}, - 'rfc2109': False, - } - - badargs = set(kwargs) - set(result) - if badargs: - err = 'create_cookie() got unexpected keyword arguments: %s' - raise TypeError(err % list(badargs)) - - result.update(kwargs) - result['port_specified'] = bool(result['port']) - result['domain_specified'] = bool(result['domain']) - result['domain_initial_dot'] = result['domain'].startswith('.') - result['path_specified'] = bool(result['path']) - - return cookielib.Cookie(**result) - - -def morsel_to_cookie(morsel): - """Convert a Morsel object into a Cookie containing the one k/v pair.""" - - expires = None - if morsel['max-age']: - try: - expires = int(time.time() + int(morsel['max-age'])) - except ValueError: - raise TypeError('max-age: %s must be integer' % morsel['max-age']) - elif morsel['expires']: - time_template = '%a, %d-%b-%Y %H:%M:%S GMT' - expires = calendar.timegm( - time.strptime(morsel['expires'], time_template) - ) - return create_cookie( - comment=morsel['comment'], - comment_url=bool(morsel['comment']), - discard=False, - domain=morsel['domain'], - expires=expires, - name=morsel.key, - path=morsel['path'], - port=None, - rest={'HttpOnly': morsel['httponly']}, - rfc2109=False, - secure=bool(morsel['secure']), - value=morsel.value, - version=morsel['version'] or 0, - ) - - -def cookiejar_from_dict(cookie_dict, cookiejar=None, overwrite=True): - """Returns a CookieJar from a key/value dictionary. - - :param cookie_dict: Dict of key/values to insert into CookieJar. - :param cookiejar: (optional) A cookiejar to add the cookies to. - :param overwrite: (optional) If False, will not replace cookies - already in the jar with new ones. - :rtype: CookieJar - """ - if cookiejar is None: - cookiejar = RequestsCookieJar() - - if cookie_dict is not None: - names_from_jar = [cookie.name for cookie in cookiejar] - for name in cookie_dict: - if overwrite or (name not in names_from_jar): - cookiejar.set_cookie(create_cookie(name, cookie_dict[name])) - - return cookiejar - - -def merge_cookies(cookiejar, cookies): - """Add cookies to cookiejar and returns a merged CookieJar. - - :param cookiejar: CookieJar object to add the cookies to. - :param cookies: Dictionary or CookieJar object to be added. - :rtype: CookieJar - """ - if not isinstance(cookiejar, cookielib.CookieJar): - raise ValueError('You can only merge into CookieJar') - - if isinstance(cookies, dict): - cookiejar = cookiejar_from_dict( - cookies, cookiejar=cookiejar, overwrite=False) - elif isinstance(cookies, cookielib.CookieJar): - try: - cookiejar.update(cookies) - except AttributeError: - for cookie_in_jar in cookies: - cookiejar.set_cookie(cookie_in_jar) - - return cookiejar diff --git a/venv/lib/python3.8/site-packages/requests/exceptions.py b/venv/lib/python3.8/site-packages/requests/exceptions.py deleted file mode 100644 index 0e9c820..0000000 --- a/venv/lib/python3.8/site-packages/requests/exceptions.py +++ /dev/null @@ -1,123 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -requests.exceptions -~~~~~~~~~~~~~~~~~~~ - -This module contains the set of Requests' exceptions. -""" -from urllib3.exceptions import HTTPError as BaseHTTPError - - -class RequestException(IOError): - """There was an ambiguous exception that occurred while handling your - request. - """ - - def __init__(self, *args, **kwargs): - """Initialize RequestException with `request` and `response` objects.""" - response = kwargs.pop('response', None) - self.response = response - self.request = kwargs.pop('request', None) - if (response is not None and not self.request and - hasattr(response, 'request')): - self.request = self.response.request - super(RequestException, self).__init__(*args, **kwargs) - - -class HTTPError(RequestException): - """An HTTP error occurred.""" - - -class ConnectionError(RequestException): - """A Connection error occurred.""" - - -class ProxyError(ConnectionError): - """A proxy error occurred.""" - - -class SSLError(ConnectionError): - """An SSL error occurred.""" - - -class Timeout(RequestException): - """The request timed out. - - Catching this error will catch both - :exc:`~requests.exceptions.ConnectTimeout` and - :exc:`~requests.exceptions.ReadTimeout` errors. - """ - - -class ConnectTimeout(ConnectionError, Timeout): - """The request timed out while trying to connect to the remote server. - - Requests that produced this error are safe to retry. - """ - - -class ReadTimeout(Timeout): - """The server did not send any data in the allotted amount of time.""" - - -class URLRequired(RequestException): - """A valid URL is required to make a request.""" - - -class TooManyRedirects(RequestException): - """Too many redirects.""" - - -class MissingSchema(RequestException, ValueError): - """The URL schema (e.g. http or https) is missing.""" - - -class InvalidSchema(RequestException, ValueError): - """See defaults.py for valid schemas.""" - - -class InvalidURL(RequestException, ValueError): - """The URL provided was somehow invalid.""" - - -class InvalidHeader(RequestException, ValueError): - """The header value provided was somehow invalid.""" - - -class InvalidProxyURL(InvalidURL): - """The proxy URL provided is invalid.""" - - -class ChunkedEncodingError(RequestException): - """The server declared chunked encoding but sent an invalid chunk.""" - - -class ContentDecodingError(RequestException, BaseHTTPError): - """Failed to decode response content.""" - - -class StreamConsumedError(RequestException, TypeError): - """The content for this response was already consumed.""" - - -class RetryError(RequestException): - """Custom retries logic failed""" - - -class UnrewindableBodyError(RequestException): - """Requests encountered an error when trying to rewind a body.""" - -# Warnings - - -class RequestsWarning(Warning): - """Base warning for Requests.""" - - -class FileModeWarning(RequestsWarning, DeprecationWarning): - """A file was opened in text mode, but Requests determined its binary length.""" - - -class RequestsDependencyWarning(RequestsWarning): - """An imported dependency doesn't match the expected version range.""" diff --git a/venv/lib/python3.8/site-packages/requests/help.py b/venv/lib/python3.8/site-packages/requests/help.py deleted file mode 100644 index e53d35e..0000000 --- a/venv/lib/python3.8/site-packages/requests/help.py +++ /dev/null @@ -1,119 +0,0 @@ -"""Module containing bug report helper(s).""" -from __future__ import print_function - -import json -import platform -import sys -import ssl - -import idna -import urllib3 -import chardet - -from . import __version__ as requests_version - -try: - from urllib3.contrib import pyopenssl -except ImportError: - pyopenssl = None - OpenSSL = None - cryptography = None -else: - import OpenSSL - import cryptography - - -def _implementation(): - """Return a dict with the Python implementation and version. - - Provide both the name and the version of the Python implementation - currently running. For example, on CPython 2.7.5 it will return - {'name': 'CPython', 'version': '2.7.5'}. - - This function works best on CPython and PyPy: in particular, it probably - doesn't work for Jython or IronPython. Future investigation should be done - to work out the correct shape of the code for those platforms. - """ - implementation = platform.python_implementation() - - if implementation == 'CPython': - implementation_version = platform.python_version() - elif implementation == 'PyPy': - implementation_version = '%s.%s.%s' % (sys.pypy_version_info.major, - sys.pypy_version_info.minor, - sys.pypy_version_info.micro) - if sys.pypy_version_info.releaselevel != 'final': - implementation_version = ''.join([ - implementation_version, sys.pypy_version_info.releaselevel - ]) - elif implementation == 'Jython': - implementation_version = platform.python_version() # Complete Guess - elif implementation == 'IronPython': - implementation_version = platform.python_version() # Complete Guess - else: - implementation_version = 'Unknown' - - return {'name': implementation, 'version': implementation_version} - - -def info(): - """Generate information for a bug report.""" - try: - platform_info = { - 'system': platform.system(), - 'release': platform.release(), - } - except IOError: - platform_info = { - 'system': 'Unknown', - 'release': 'Unknown', - } - - implementation_info = _implementation() - urllib3_info = {'version': urllib3.__version__} - chardet_info = {'version': chardet.__version__} - - pyopenssl_info = { - 'version': None, - 'openssl_version': '', - } - if OpenSSL: - pyopenssl_info = { - 'version': OpenSSL.__version__, - 'openssl_version': '%x' % OpenSSL.SSL.OPENSSL_VERSION_NUMBER, - } - cryptography_info = { - 'version': getattr(cryptography, '__version__', ''), - } - idna_info = { - 'version': getattr(idna, '__version__', ''), - } - - system_ssl = ssl.OPENSSL_VERSION_NUMBER - system_ssl_info = { - 'version': '%x' % system_ssl if system_ssl is not None else '' - } - - return { - 'platform': platform_info, - 'implementation': implementation_info, - 'system_ssl': system_ssl_info, - 'using_pyopenssl': pyopenssl is not None, - 'pyOpenSSL': pyopenssl_info, - 'urllib3': urllib3_info, - 'chardet': chardet_info, - 'cryptography': cryptography_info, - 'idna': idna_info, - 'requests': { - 'version': requests_version, - }, - } - - -def main(): - """Pretty-print the bug information as JSON.""" - print(json.dumps(info(), sort_keys=True, indent=2)) - - -if __name__ == '__main__': - main() diff --git a/venv/lib/python3.8/site-packages/requests/hooks.py b/venv/lib/python3.8/site-packages/requests/hooks.py deleted file mode 100644 index 7a51f21..0000000 --- a/venv/lib/python3.8/site-packages/requests/hooks.py +++ /dev/null @@ -1,34 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -requests.hooks -~~~~~~~~~~~~~~ - -This module provides the capabilities for the Requests hooks system. - -Available hooks: - -``response``: - The response generated from a Request. -""" -HOOKS = ['response'] - - -def default_hooks(): - return {event: [] for event in HOOKS} - -# TODO: response is the only one - - -def dispatch_hook(key, hooks, hook_data, **kwargs): - """Dispatches a hook dictionary on a given piece of data.""" - hooks = hooks or {} - hooks = hooks.get(key) - if hooks: - if hasattr(hooks, '__call__'): - hooks = [hooks] - for hook in hooks: - _hook_data = hook(hook_data, **kwargs) - if _hook_data is not None: - hook_data = _hook_data - return hook_data diff --git a/venv/lib/python3.8/site-packages/requests/models.py b/venv/lib/python3.8/site-packages/requests/models.py deleted file mode 100644 index ec2edc2..0000000 --- a/venv/lib/python3.8/site-packages/requests/models.py +++ /dev/null @@ -1,956 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -requests.models -~~~~~~~~~~~~~~~ - -This module contains the primary objects that power Requests. -""" - -import datetime -import sys - -# Import encoding now, to avoid implicit import later. -# Implicit import within threads may cause LookupError when standard library is in a ZIP, -# such as in Embedded Python. See https://github.com/psf/requests/issues/3578. -import encodings.idna - -from urllib3.fields import RequestField -from urllib3.filepost import encode_multipart_formdata -from urllib3.util import parse_url -from urllib3.exceptions import ( - DecodeError, ReadTimeoutError, ProtocolError, LocationParseError) - -from io import UnsupportedOperation -from .hooks import default_hooks -from .structures import CaseInsensitiveDict - -from .auth import HTTPBasicAuth -from .cookies import cookiejar_from_dict, get_cookie_header, _copy_cookie_jar -from .exceptions import ( - HTTPError, MissingSchema, InvalidURL, ChunkedEncodingError, - ContentDecodingError, ConnectionError, StreamConsumedError) -from ._internal_utils import to_native_string, unicode_is_ascii -from .utils import ( - guess_filename, get_auth_from_url, requote_uri, - stream_decode_response_unicode, to_key_val_list, parse_header_links, - iter_slices, guess_json_utf, super_len, check_header_validity) -from .compat import ( - Callable, Mapping, - cookielib, urlunparse, urlsplit, urlencode, str, bytes, - is_py2, chardet, builtin_str, basestring) -from .compat import json as complexjson -from .status_codes import codes - -#: The set of HTTP status codes that indicate an automatically -#: processable redirect. -REDIRECT_STATI = ( - codes.moved, # 301 - codes.found, # 302 - codes.other, # 303 - codes.temporary_redirect, # 307 - codes.permanent_redirect, # 308 -) - -DEFAULT_REDIRECT_LIMIT = 30 -CONTENT_CHUNK_SIZE = 10 * 1024 -ITER_CHUNK_SIZE = 512 - - -class RequestEncodingMixin(object): - @property - def path_url(self): - """Build the path URL to use.""" - - url = [] - - p = urlsplit(self.url) - - path = p.path - if not path: - path = '/' - - url.append(path) - - query = p.query - if query: - url.append('?') - url.append(query) - - return ''.join(url) - - @staticmethod - def _encode_params(data): - """Encode parameters in a piece of data. - - Will successfully encode parameters when passed as a dict or a list of - 2-tuples. Order is retained if data is a list of 2-tuples but arbitrary - if parameters are supplied as a dict. - """ - - if isinstance(data, (str, bytes)): - return data - elif hasattr(data, 'read'): - return data - elif hasattr(data, '__iter__'): - result = [] - for k, vs in to_key_val_list(data): - if isinstance(vs, basestring) or not hasattr(vs, '__iter__'): - vs = [vs] - for v in vs: - if v is not None: - result.append( - (k.encode('utf-8') if isinstance(k, str) else k, - v.encode('utf-8') if isinstance(v, str) else v)) - return urlencode(result, doseq=True) - else: - return data - - @staticmethod - def _encode_files(files, data): - """Build the body for a multipart/form-data request. - - Will successfully encode files when passed as a dict or a list of - tuples. Order is retained if data is a list of tuples but arbitrary - if parameters are supplied as a dict. - The tuples may be 2-tuples (filename, fileobj), 3-tuples (filename, fileobj, contentype) - or 4-tuples (filename, fileobj, contentype, custom_headers). - """ - if (not files): - raise ValueError("Files must be provided.") - elif isinstance(data, basestring): - raise ValueError("Data must not be a string.") - - new_fields = [] - fields = to_key_val_list(data or {}) - files = to_key_val_list(files or {}) - - for field, val in fields: - if isinstance(val, basestring) or not hasattr(val, '__iter__'): - val = [val] - for v in val: - if v is not None: - # Don't call str() on bytestrings: in Py3 it all goes wrong. - if not isinstance(v, bytes): - v = str(v) - - new_fields.append( - (field.decode('utf-8') if isinstance(field, bytes) else field, - v.encode('utf-8') if isinstance(v, str) else v)) - - for (k, v) in files: - # support for explicit filename - ft = None - fh = None - if isinstance(v, (tuple, list)): - if len(v) == 2: - fn, fp = v - elif len(v) == 3: - fn, fp, ft = v - else: - fn, fp, ft, fh = v - else: - fn = guess_filename(v) or k - fp = v - - if isinstance(fp, (str, bytes, bytearray)): - fdata = fp - elif hasattr(fp, 'read'): - fdata = fp.read() - elif fp is None: - continue - else: - fdata = fp - - rf = RequestField(name=k, data=fdata, filename=fn, headers=fh) - rf.make_multipart(content_type=ft) - new_fields.append(rf) - - body, content_type = encode_multipart_formdata(new_fields) - - return body, content_type - - -class RequestHooksMixin(object): - def register_hook(self, event, hook): - """Properly register a hook.""" - - if event not in self.hooks: - raise ValueError('Unsupported event specified, with event name "%s"' % (event)) - - if isinstance(hook, Callable): - self.hooks[event].append(hook) - elif hasattr(hook, '__iter__'): - self.hooks[event].extend(h for h in hook if isinstance(h, Callable)) - - def deregister_hook(self, event, hook): - """Deregister a previously registered hook. - Returns True if the hook existed, False if not. - """ - - try: - self.hooks[event].remove(hook) - return True - except ValueError: - return False - - -class Request(RequestHooksMixin): - """A user-created :class:`Request <Request>` object. - - Used to prepare a :class:`PreparedRequest <PreparedRequest>`, which is sent to the server. - - :param method: HTTP method to use. - :param url: URL to send. - :param headers: dictionary of headers to send. - :param files: dictionary of {filename: fileobject} files to multipart upload. - :param data: the body to attach to the request. If a dictionary or - list of tuples ``[(key, value)]`` is provided, form-encoding will - take place. - :param json: json for the body to attach to the request (if files or data is not specified). - :param params: URL parameters to append to the URL. If a dictionary or - list of tuples ``[(key, value)]`` is provided, form-encoding will - take place. - :param auth: Auth handler or (user, pass) tuple. - :param cookies: dictionary or CookieJar of cookies to attach to this request. - :param hooks: dictionary of callback hooks, for internal usage. - - Usage:: - - >>> import requests - >>> req = requests.Request('GET', 'https://httpbin.org/get') - >>> req.prepare() - <PreparedRequest [GET]> - """ - - def __init__(self, - method=None, url=None, headers=None, files=None, data=None, - params=None, auth=None, cookies=None, hooks=None, json=None): - - # Default empty dicts for dict params. - data = [] if data is None else data - files = [] if files is None else files - headers = {} if headers is None else headers - params = {} if params is None else params - hooks = {} if hooks is None else hooks - - self.hooks = default_hooks() - for (k, v) in list(hooks.items()): - self.register_hook(event=k, hook=v) - - self.method = method - self.url = url - self.headers = headers - self.files = files - self.data = data - self.json = json - self.params = params - self.auth = auth - self.cookies = cookies - - def __repr__(self): - return '<Request [%s]>' % (self.method) - - def prepare(self): - """Constructs a :class:`PreparedRequest <PreparedRequest>` for transmission and returns it.""" - p = PreparedRequest() - p.prepare( - method=self.method, - url=self.url, - headers=self.headers, - files=self.files, - data=self.data, - json=self.json, - params=self.params, - auth=self.auth, - cookies=self.cookies, - hooks=self.hooks, - ) - return p - - -class PreparedRequest(RequestEncodingMixin, RequestHooksMixin): - """The fully mutable :class:`PreparedRequest <PreparedRequest>` object, - containing the exact bytes that will be sent to the server. - - Instances are generated from a :class:`Request <Request>` object, and - should not be instantiated manually; doing so may produce undesirable - effects. - - Usage:: - - >>> import requests - >>> req = requests.Request('GET', 'https://httpbin.org/get') - >>> r = req.prepare() - >>> r - <PreparedRequest [GET]> - - >>> s = requests.Session() - >>> s.send(r) - <Response [200]> - """ - - def __init__(self): - #: HTTP verb to send to the server. - self.method = None - #: HTTP URL to send the request to. - self.url = None - #: dictionary of HTTP headers. - self.headers = None - # The `CookieJar` used to create the Cookie header will be stored here - # after prepare_cookies is called - self._cookies = None - #: request body to send to the server. - self.body = None - #: dictionary of callback hooks, for internal usage. - self.hooks = default_hooks() - #: integer denoting starting position of a readable file-like body. - self._body_position = None - - def prepare(self, - method=None, url=None, headers=None, files=None, data=None, - params=None, auth=None, cookies=None, hooks=None, json=None): - """Prepares the entire request with the given parameters.""" - - self.prepare_method(method) - self.prepare_url(url, params) - self.prepare_headers(headers) - self.prepare_cookies(cookies) - self.prepare_body(data, files, json) - self.prepare_auth(auth, url) - - # Note that prepare_auth must be last to enable authentication schemes - # such as OAuth to work on a fully prepared request. - - # This MUST go after prepare_auth. Authenticators could add a hook - self.prepare_hooks(hooks) - - def __repr__(self): - return '<PreparedRequest [%s]>' % (self.method) - - def copy(self): - p = PreparedRequest() - p.method = self.method - p.url = self.url - p.headers = self.headers.copy() if self.headers is not None else None - p._cookies = _copy_cookie_jar(self._cookies) - p.body = self.body - p.hooks = self.hooks - p._body_position = self._body_position - return p - - def prepare_method(self, method): - """Prepares the given HTTP method.""" - self.method = method - if self.method is not None: - self.method = to_native_string(self.method.upper()) - - @staticmethod - def _get_idna_encoded_host(host): - import idna - - try: - host = idna.encode(host, uts46=True).decode('utf-8') - except idna.IDNAError: - raise UnicodeError - return host - - def prepare_url(self, url, params): - """Prepares the given HTTP URL.""" - #: Accept objects that have string representations. - #: We're unable to blindly call unicode/str functions - #: as this will include the bytestring indicator (b'') - #: on python 3.x. - #: https://github.com/psf/requests/pull/2238 - if isinstance(url, bytes): - url = url.decode('utf8') - else: - url = unicode(url) if is_py2 else str(url) - - # Remove leading whitespaces from url - url = url.lstrip() - - # Don't do any URL preparation for non-HTTP schemes like `mailto`, - # `data` etc to work around exceptions from `url_parse`, which - # handles RFC 3986 only. - if ':' in url and not url.lower().startswith('http'): - self.url = url - return - - # Support for unicode domain names and paths. - try: - scheme, auth, host, port, path, query, fragment = parse_url(url) - except LocationParseError as e: - raise InvalidURL(*e.args) - - if not scheme: - error = ("Invalid URL {0!r}: No schema supplied. Perhaps you meant http://{0}?") - error = error.format(to_native_string(url, 'utf8')) - - raise MissingSchema(error) - - if not host: - raise InvalidURL("Invalid URL %r: No host supplied" % url) - - # In general, we want to try IDNA encoding the hostname if the string contains - # non-ASCII characters. This allows users to automatically get the correct IDNA - # behaviour. For strings containing only ASCII characters, we need to also verify - # it doesn't start with a wildcard (*), before allowing the unencoded hostname. - if not unicode_is_ascii(host): - try: - host = self._get_idna_encoded_host(host) - except UnicodeError: - raise InvalidURL('URL has an invalid label.') - elif host.startswith(u'*'): - raise InvalidURL('URL has an invalid label.') - - # Carefully reconstruct the network location - netloc = auth or '' - if netloc: - netloc += '@' - netloc += host - if port: - netloc += ':' + str(port) - - # Bare domains aren't valid URLs. - if not path: - path = '/' - - if is_py2: - if isinstance(scheme, str): - scheme = scheme.encode('utf-8') - if isinstance(netloc, str): - netloc = netloc.encode('utf-8') - if isinstance(path, str): - path = path.encode('utf-8') - if isinstance(query, str): - query = query.encode('utf-8') - if isinstance(fragment, str): - fragment = fragment.encode('utf-8') - - if isinstance(params, (str, bytes)): - params = to_native_string(params) - - enc_params = self._encode_params(params) - if enc_params: - if query: - query = '%s&%s' % (query, enc_params) - else: - query = enc_params - - url = requote_uri(urlunparse([scheme, netloc, path, None, query, fragment])) - self.url = url - - def prepare_headers(self, headers): - """Prepares the given HTTP headers.""" - - self.headers = CaseInsensitiveDict() - if headers: - for header in headers.items(): - # Raise exception on invalid header value. - check_header_validity(header) - name, value = header - self.headers[to_native_string(name)] = value - - def prepare_body(self, data, files, json=None): - """Prepares the given HTTP body data.""" - - # Check if file, fo, generator, iterator. - # If not, run through normal process. - - # Nottin' on you. - body = None - content_type = None - - if not data and json is not None: - # urllib3 requires a bytes-like body. Python 2's json.dumps - # provides this natively, but Python 3 gives a Unicode string. - content_type = 'application/json' - body = complexjson.dumps(json) - if not isinstance(body, bytes): - body = body.encode('utf-8') - - is_stream = all([ - hasattr(data, '__iter__'), - not isinstance(data, (basestring, list, tuple, Mapping)) - ]) - - if is_stream: - try: - length = super_len(data) - except (TypeError, AttributeError, UnsupportedOperation): - length = None - - body = data - - if getattr(body, 'tell', None) is not None: - # Record the current file position before reading. - # This will allow us to rewind a file in the event - # of a redirect. - try: - self._body_position = body.tell() - except (IOError, OSError): - # This differentiates from None, allowing us to catch - # a failed `tell()` later when trying to rewind the body - self._body_position = object() - - if files: - raise NotImplementedError('Streamed bodies and files are mutually exclusive.') - - if length: - self.headers['Content-Length'] = builtin_str(length) - else: - self.headers['Transfer-Encoding'] = 'chunked' - else: - # Multi-part file uploads. - if files: - (body, content_type) = self._encode_files(files, data) - else: - if data: - body = self._encode_params(data) - if isinstance(data, basestring) or hasattr(data, 'read'): - content_type = None - else: - content_type = 'application/x-www-form-urlencoded' - - self.prepare_content_length(body) - - # Add content-type if it wasn't explicitly provided. - if content_type and ('content-type' not in self.headers): - self.headers['Content-Type'] = content_type - - self.body = body - - def prepare_content_length(self, body): - """Prepare Content-Length header based on request method and body""" - if body is not None: - length = super_len(body) - if length: - # If length exists, set it. Otherwise, we fallback - # to Transfer-Encoding: chunked. - self.headers['Content-Length'] = builtin_str(length) - elif self.method not in ('GET', 'HEAD') and self.headers.get('Content-Length') is None: - # Set Content-Length to 0 for methods that can have a body - # but don't provide one. (i.e. not GET or HEAD) - self.headers['Content-Length'] = '0' - - def prepare_auth(self, auth, url=''): - """Prepares the given HTTP auth data.""" - - # If no Auth is explicitly provided, extract it from the URL first. - if auth is None: - url_auth = get_auth_from_url(self.url) - auth = url_auth if any(url_auth) else None - - if auth: - if isinstance(auth, tuple) and len(auth) == 2: - # special-case basic HTTP auth - auth = HTTPBasicAuth(*auth) - - # Allow auth to make its changes. - r = auth(self) - - # Update self to reflect the auth changes. - self.__dict__.update(r.__dict__) - - # Recompute Content-Length - self.prepare_content_length(self.body) - - def prepare_cookies(self, cookies): - """Prepares the given HTTP cookie data. - - This function eventually generates a ``Cookie`` header from the - given cookies using cookielib. Due to cookielib's design, the header - will not be regenerated if it already exists, meaning this function - can only be called once for the life of the - :class:`PreparedRequest <PreparedRequest>` object. Any subsequent calls - to ``prepare_cookies`` will have no actual effect, unless the "Cookie" - header is removed beforehand. - """ - if isinstance(cookies, cookielib.CookieJar): - self._cookies = cookies - else: - self._cookies = cookiejar_from_dict(cookies) - - cookie_header = get_cookie_header(self._cookies, self) - if cookie_header is not None: - self.headers['Cookie'] = cookie_header - - def prepare_hooks(self, hooks): - """Prepares the given hooks.""" - # hooks can be passed as None to the prepare method and to this - # method. To prevent iterating over None, simply use an empty list - # if hooks is False-y - hooks = hooks or [] - for event in hooks: - self.register_hook(event, hooks[event]) - - -class Response(object): - """The :class:`Response <Response>` object, which contains a - server's response to an HTTP request. - """ - - __attrs__ = [ - '_content', 'status_code', 'headers', 'url', 'history', - 'encoding', 'reason', 'cookies', 'elapsed', 'request' - ] - - def __init__(self): - self._content = False - self._content_consumed = False - self._next = None - - #: Integer Code of responded HTTP Status, e.g. 404 or 200. - self.status_code = None - - #: Case-insensitive Dictionary of Response Headers. - #: For example, ``headers['content-encoding']`` will return the - #: value of a ``'Content-Encoding'`` response header. - self.headers = CaseInsensitiveDict() - - #: File-like object representation of response (for advanced usage). - #: Use of ``raw`` requires that ``stream=True`` be set on the request. - #: This requirement does not apply for use internally to Requests. - self.raw = None - - #: Final URL location of Response. - self.url = None - - #: Encoding to decode with when accessing r.text. - self.encoding = None - - #: A list of :class:`Response <Response>` objects from - #: the history of the Request. Any redirect responses will end - #: up here. The list is sorted from the oldest to the most recent request. - self.history = [] - - #: Textual reason of responded HTTP Status, e.g. "Not Found" or "OK". - self.reason = None - - #: A CookieJar of Cookies the server sent back. - self.cookies = cookiejar_from_dict({}) - - #: The amount of time elapsed between sending the request - #: and the arrival of the response (as a timedelta). - #: This property specifically measures the time taken between sending - #: the first byte of the request and finishing parsing the headers. It - #: is therefore unaffected by consuming the response content or the - #: value of the ``stream`` keyword argument. - self.elapsed = datetime.timedelta(0) - - #: The :class:`PreparedRequest <PreparedRequest>` object to which this - #: is a response. - self.request = None - - def __enter__(self): - return self - - def __exit__(self, *args): - self.close() - - def __getstate__(self): - # Consume everything; accessing the content attribute makes - # sure the content has been fully read. - if not self._content_consumed: - self.content - - return {attr: getattr(self, attr, None) for attr in self.__attrs__} - - def __setstate__(self, state): - for name, value in state.items(): - setattr(self, name, value) - - # pickled objects do not have .raw - setattr(self, '_content_consumed', True) - setattr(self, 'raw', None) - - def __repr__(self): - return '<Response [%s]>' % (self.status_code) - - def __bool__(self): - """Returns True if :attr:`status_code` is less than 400. - - This attribute checks if the status code of the response is between - 400 and 600 to see if there was a client error or a server error. If - the status code, is between 200 and 400, this will return True. This - is **not** a check to see if the response code is ``200 OK``. - """ - return self.ok - - def __nonzero__(self): - """Returns True if :attr:`status_code` is less than 400. - - This attribute checks if the status code of the response is between - 400 and 600 to see if there was a client error or a server error. If - the status code, is between 200 and 400, this will return True. This - is **not** a check to see if the response code is ``200 OK``. - """ - return self.ok - - def __iter__(self): - """Allows you to use a response as an iterator.""" - return self.iter_content(128) - - @property - def ok(self): - """Returns True if :attr:`status_code` is less than 400, False if not. - - This attribute checks if the status code of the response is between - 400 and 600 to see if there was a client error or a server error. If - the status code is between 200 and 400, this will return True. This - is **not** a check to see if the response code is ``200 OK``. - """ - try: - self.raise_for_status() - except HTTPError: - return False - return True - - @property - def is_redirect(self): - """True if this Response is a well-formed HTTP redirect that could have - been processed automatically (by :meth:`Session.resolve_redirects`). - """ - return ('location' in self.headers and self.status_code in REDIRECT_STATI) - - @property - def is_permanent_redirect(self): - """True if this Response one of the permanent versions of redirect.""" - return ('location' in self.headers and self.status_code in (codes.moved_permanently, codes.permanent_redirect)) - - @property - def next(self): - """Returns a PreparedRequest for the next request in a redirect chain, if there is one.""" - return self._next - - @property - def apparent_encoding(self): - """The apparent encoding, provided by the chardet library.""" - return chardet.detect(self.content)['encoding'] - - def iter_content(self, chunk_size=1, decode_unicode=False): - """Iterates over the response data. When stream=True is set on the - request, this avoids reading the content at once into memory for - large responses. The chunk size is the number of bytes it should - read into memory. This is not necessarily the length of each item - returned as decoding can take place. - - chunk_size must be of type int or None. A value of None will - function differently depending on the value of `stream`. - stream=True will read data as it arrives in whatever size the - chunks are received. If stream=False, data is returned as - a single chunk. - - If decode_unicode is True, content will be decoded using the best - available encoding based on the response. - """ - - def generate(): - # Special case for urllib3. - if hasattr(self.raw, 'stream'): - try: - for chunk in self.raw.stream(chunk_size, decode_content=True): - yield chunk - except ProtocolError as e: - raise ChunkedEncodingError(e) - except DecodeError as e: - raise ContentDecodingError(e) - except ReadTimeoutError as e: - raise ConnectionError(e) - else: - # Standard file-like object. - while True: - chunk = self.raw.read(chunk_size) - if not chunk: - break - yield chunk - - self._content_consumed = True - - if self._content_consumed and isinstance(self._content, bool): - raise StreamConsumedError() - elif chunk_size is not None and not isinstance(chunk_size, int): - raise TypeError("chunk_size must be an int, it is instead a %s." % type(chunk_size)) - # simulate reading small chunks of the content - reused_chunks = iter_slices(self._content, chunk_size) - - stream_chunks = generate() - - chunks = reused_chunks if self._content_consumed else stream_chunks - - if decode_unicode: - chunks = stream_decode_response_unicode(chunks, self) - - return chunks - - def iter_lines(self, chunk_size=ITER_CHUNK_SIZE, decode_unicode=False, delimiter=None): - """Iterates over the response data, one line at a time. When - stream=True is set on the request, this avoids reading the - content at once into memory for large responses. - - .. note:: This method is not reentrant safe. - """ - - pending = None - - for chunk in self.iter_content(chunk_size=chunk_size, decode_unicode=decode_unicode): - - if pending is not None: - chunk = pending + chunk - - if delimiter: - lines = chunk.split(delimiter) - else: - lines = chunk.splitlines() - - if lines and lines[-1] and chunk and lines[-1][-1] == chunk[-1]: - pending = lines.pop() - else: - pending = None - - for line in lines: - yield line - - if pending is not None: - yield pending - - @property - def content(self): - """Content of the response, in bytes.""" - - if self._content is False: - # Read the contents. - if self._content_consumed: - raise RuntimeError( - 'The content for this response was already consumed') - - if self.status_code == 0 or self.raw is None: - self._content = None - else: - self._content = b''.join(self.iter_content(CONTENT_CHUNK_SIZE)) or b'' - - self._content_consumed = True - # don't need to release the connection; that's been handled by urllib3 - # since we exhausted the data. - return self._content - - @property - def text(self): - """Content of the response, in unicode. - - If Response.encoding is None, encoding will be guessed using - ``chardet``. - - The encoding of the response content is determined based solely on HTTP - headers, following RFC 2616 to the letter. If you can take advantage of - non-HTTP knowledge to make a better guess at the encoding, you should - set ``r.encoding`` appropriately before accessing this property. - """ - - # Try charset from content-type - content = None - encoding = self.encoding - - if not self.content: - return str('') - - # Fallback to auto-detected encoding. - if self.encoding is None: - encoding = self.apparent_encoding - - # Decode unicode from given encoding. - try: - content = str(self.content, encoding, errors='replace') - except (LookupError, TypeError): - # A LookupError is raised if the encoding was not found which could - # indicate a misspelling or similar mistake. - # - # A TypeError can be raised if encoding is None - # - # So we try blindly encoding. - content = str(self.content, errors='replace') - - return content - - def json(self, **kwargs): - r"""Returns the json-encoded content of a response, if any. - - :param \*\*kwargs: Optional arguments that ``json.loads`` takes. - :raises ValueError: If the response body does not contain valid json. - """ - - if not self.encoding and self.content and len(self.content) > 3: - # No encoding set. JSON RFC 4627 section 3 states we should expect - # UTF-8, -16 or -32. Detect which one to use; If the detection or - # decoding fails, fall back to `self.text` (using chardet to make - # a best guess). - encoding = guess_json_utf(self.content) - if encoding is not None: - try: - return complexjson.loads( - self.content.decode(encoding), **kwargs - ) - except UnicodeDecodeError: - # Wrong UTF codec detected; usually because it's not UTF-8 - # but some other 8-bit codec. This is an RFC violation, - # and the server didn't bother to tell us what codec *was* - # used. - pass - return complexjson.loads(self.text, **kwargs) - - @property - def links(self): - """Returns the parsed header links of the response, if any.""" - - header = self.headers.get('link') - - # l = MultiDict() - l = {} - - if header: - links = parse_header_links(header) - - for link in links: - key = link.get('rel') or link.get('url') - l[key] = link - - return l - - def raise_for_status(self): - """Raises :class:`HTTPError`, if one occurred.""" - - http_error_msg = '' - if isinstance(self.reason, bytes): - # We attempt to decode utf-8 first because some servers - # choose to localize their reason strings. If the string - # isn't utf-8, we fall back to iso-8859-1 for all other - # encodings. (See PR #3538) - try: - reason = self.reason.decode('utf-8') - except UnicodeDecodeError: - reason = self.reason.decode('iso-8859-1') - else: - reason = self.reason - - if 400 <= self.status_code < 500: - http_error_msg = u'%s Client Error: %s for url: %s' % (self.status_code, reason, self.url) - - elif 500 <= self.status_code < 600: - http_error_msg = u'%s Server Error: %s for url: %s' % (self.status_code, reason, self.url) - - if http_error_msg: - raise HTTPError(http_error_msg, response=self) - - def close(self): - """Releases the connection back to the pool. Once this method has been - called the underlying ``raw`` object must not be accessed again. - - *Note: Should not normally need to be called explicitly.* - """ - if not self._content_consumed: - self.raw.close() - - release_conn = getattr(self.raw, 'release_conn', None) - if release_conn is not None: - release_conn() diff --git a/venv/lib/python3.8/site-packages/requests/packages.py b/venv/lib/python3.8/site-packages/requests/packages.py deleted file mode 100644 index 7232fe0..0000000 --- a/venv/lib/python3.8/site-packages/requests/packages.py +++ /dev/null @@ -1,14 +0,0 @@ -import sys - -# This code exists for backwards compatibility reasons. -# I don't like it either. Just look the other way. :) - -for package in ('urllib3', 'idna', 'chardet'): - locals()[package] = __import__(package) - # This traversal is apparently necessary such that the identities are - # preserved (requests.packages.urllib3.* is urllib3.*) - for mod in list(sys.modules): - if mod == package or mod.startswith(package + '.'): - sys.modules['requests.packages.' + mod] = sys.modules[mod] - -# Kinda cool, though, right? diff --git a/venv/lib/python3.8/site-packages/requests/sessions.py b/venv/lib/python3.8/site-packages/requests/sessions.py deleted file mode 100644 index 45ab8a5..0000000 --- a/venv/lib/python3.8/site-packages/requests/sessions.py +++ /dev/null @@ -1,781 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -requests.sessions -~~~~~~~~~~~~~~~~~ - -This module provides a Session object to manage and persist settings across -requests (cookies, auth, proxies). -""" -import os -import sys -import time -from datetime import timedelta -from collections import OrderedDict - -from .auth import _basic_auth_str -from .compat import cookielib, is_py3, urljoin, urlparse, Mapping -from .cookies import ( - cookiejar_from_dict, extract_cookies_to_jar, RequestsCookieJar, merge_cookies) -from .models import Request, PreparedRequest, DEFAULT_REDIRECT_LIMIT -from .hooks import default_hooks, dispatch_hook -from ._internal_utils import to_native_string -from .utils import to_key_val_list, default_headers, DEFAULT_PORTS -from .exceptions import ( - TooManyRedirects, InvalidSchema, ChunkedEncodingError, ContentDecodingError) - -from .structures import CaseInsensitiveDict -from .adapters import HTTPAdapter - -from .utils import ( - requote_uri, get_environ_proxies, get_netrc_auth, should_bypass_proxies, - get_auth_from_url, rewind_body -) - -from .status_codes import codes - -# formerly defined here, reexposed here for backward compatibility -from .models import REDIRECT_STATI - -# Preferred clock, based on which one is more accurate on a given system. -if sys.platform == 'win32': - try: # Python 3.4+ - preferred_clock = time.perf_counter - except AttributeError: # Earlier than Python 3. - preferred_clock = time.clock -else: - preferred_clock = time.time - - -def merge_setting(request_setting, session_setting, dict_class=OrderedDict): - """Determines appropriate setting for a given request, taking into account - the explicit setting on that request, and the setting in the session. If a - setting is a dictionary, they will be merged together using `dict_class` - """ - - if session_setting is None: - return request_setting - - if request_setting is None: - return session_setting - - # Bypass if not a dictionary (e.g. verify) - if not ( - isinstance(session_setting, Mapping) and - isinstance(request_setting, Mapping) - ): - return request_setting - - merged_setting = dict_class(to_key_val_list(session_setting)) - merged_setting.update(to_key_val_list(request_setting)) - - # Remove keys that are set to None. Extract keys first to avoid altering - # the dictionary during iteration. - none_keys = [k for (k, v) in merged_setting.items() if v is None] - for key in none_keys: - del merged_setting[key] - - return merged_setting - - -def merge_hooks(request_hooks, session_hooks, dict_class=OrderedDict): - """Properly merges both requests and session hooks. - - This is necessary because when request_hooks == {'response': []}, the - merge breaks Session hooks entirely. - """ - if session_hooks is None or session_hooks.get('response') == []: - return request_hooks - - if request_hooks is None or request_hooks.get('response') == []: - return session_hooks - - return merge_setting(request_hooks, session_hooks, dict_class) - - -class SessionRedirectMixin(object): - - def get_redirect_target(self, resp): - """Receives a Response. Returns a redirect URI or ``None``""" - # Due to the nature of how requests processes redirects this method will - # be called at least once upon the original response and at least twice - # on each subsequent redirect response (if any). - # If a custom mixin is used to handle this logic, it may be advantageous - # to cache the redirect location onto the response object as a private - # attribute. - if resp.is_redirect: - location = resp.headers['location'] - # Currently the underlying http module on py3 decode headers - # in latin1, but empirical evidence suggests that latin1 is very - # rarely used with non-ASCII characters in HTTP headers. - # It is more likely to get UTF8 header rather than latin1. - # This causes incorrect handling of UTF8 encoded location headers. - # To solve this, we re-encode the location in latin1. - if is_py3: - location = location.encode('latin1') - return to_native_string(location, 'utf8') - return None - - def should_strip_auth(self, old_url, new_url): - """Decide whether Authorization header should be removed when redirecting""" - old_parsed = urlparse(old_url) - new_parsed = urlparse(new_url) - if old_parsed.hostname != new_parsed.hostname: - return True - # Special case: allow http -> https redirect when using the standard - # ports. This isn't specified by RFC 7235, but is kept to avoid - # breaking backwards compatibility with older versions of requests - # that allowed any redirects on the same host. - if (old_parsed.scheme == 'http' and old_parsed.port in (80, None) - and new_parsed.scheme == 'https' and new_parsed.port in (443, None)): - return False - - # Handle default port usage corresponding to scheme. - changed_port = old_parsed.port != new_parsed.port - changed_scheme = old_parsed.scheme != new_parsed.scheme - default_port = (DEFAULT_PORTS.get(old_parsed.scheme, None), None) - if (not changed_scheme and old_parsed.port in default_port - and new_parsed.port in default_port): - return False - - # Standard case: root URI must match - return changed_port or changed_scheme - - def resolve_redirects(self, resp, req, stream=False, timeout=None, - verify=True, cert=None, proxies=None, yield_requests=False, **adapter_kwargs): - """Receives a Response. Returns a generator of Responses or Requests.""" - - hist = [] # keep track of history - - url = self.get_redirect_target(resp) - previous_fragment = urlparse(req.url).fragment - while url: - prepared_request = req.copy() - - # Update history and keep track of redirects. - # resp.history must ignore the original request in this loop - hist.append(resp) - resp.history = hist[1:] - - try: - resp.content # Consume socket so it can be released - except (ChunkedEncodingError, ContentDecodingError, RuntimeError): - resp.raw.read(decode_content=False) - - if len(resp.history) >= self.max_redirects: - raise TooManyRedirects('Exceeded {} redirects.'.format(self.max_redirects), response=resp) - - # Release the connection back into the pool. - resp.close() - - # Handle redirection without scheme (see: RFC 1808 Section 4) - if url.startswith('//'): - parsed_rurl = urlparse(resp.url) - url = ':'.join([to_native_string(parsed_rurl.scheme), url]) - - # Normalize url case and attach previous fragment if needed (RFC 7231 7.1.2) - parsed = urlparse(url) - if parsed.fragment == '' and previous_fragment: - parsed = parsed._replace(fragment=previous_fragment) - elif parsed.fragment: - previous_fragment = parsed.fragment - url = parsed.geturl() - - # Facilitate relative 'location' headers, as allowed by RFC 7231. - # (e.g. '/path/to/resource' instead of 'http://domain.tld/path/to/resource') - # Compliant with RFC3986, we percent encode the url. - if not parsed.netloc: - url = urljoin(resp.url, requote_uri(url)) - else: - url = requote_uri(url) - - prepared_request.url = to_native_string(url) - - self.rebuild_method(prepared_request, resp) - - # https://github.com/psf/requests/issues/1084 - if resp.status_code not in (codes.temporary_redirect, codes.permanent_redirect): - # https://github.com/psf/requests/issues/3490 - purged_headers = ('Content-Length', 'Content-Type', 'Transfer-Encoding') - for header in purged_headers: - prepared_request.headers.pop(header, None) - prepared_request.body = None - - headers = prepared_request.headers - headers.pop('Cookie', None) - - # Extract any cookies sent on the response to the cookiejar - # in the new request. Because we've mutated our copied prepared - # request, use the old one that we haven't yet touched. - extract_cookies_to_jar(prepared_request._cookies, req, resp.raw) - merge_cookies(prepared_request._cookies, self.cookies) - prepared_request.prepare_cookies(prepared_request._cookies) - - # Rebuild auth and proxy information. - proxies = self.rebuild_proxies(prepared_request, proxies) - self.rebuild_auth(prepared_request, resp) - - # A failed tell() sets `_body_position` to `object()`. This non-None - # value ensures `rewindable` will be True, allowing us to raise an - # UnrewindableBodyError, instead of hanging the connection. - rewindable = ( - prepared_request._body_position is not None and - ('Content-Length' in headers or 'Transfer-Encoding' in headers) - ) - - # Attempt to rewind consumed file-like object. - if rewindable: - rewind_body(prepared_request) - - # Override the original request. - req = prepared_request - - if yield_requests: - yield req - else: - - resp = self.send( - req, - stream=stream, - timeout=timeout, - verify=verify, - cert=cert, - proxies=proxies, - allow_redirects=False, - **adapter_kwargs - ) - - extract_cookies_to_jar(self.cookies, prepared_request, resp.raw) - - # extract redirect url, if any, for the next loop - url = self.get_redirect_target(resp) - yield resp - - def rebuild_auth(self, prepared_request, response): - """When being redirected we may want to strip authentication from the - request to avoid leaking credentials. This method intelligently removes - and reapplies authentication where possible to avoid credential loss. - """ - headers = prepared_request.headers - url = prepared_request.url - - if 'Authorization' in headers and self.should_strip_auth(response.request.url, url): - # If we get redirected to a new host, we should strip out any - # authentication headers. - del headers['Authorization'] - - # .netrc might have more auth for us on our new host. - new_auth = get_netrc_auth(url) if self.trust_env else None - if new_auth is not None: - prepared_request.prepare_auth(new_auth) - - - def rebuild_proxies(self, prepared_request, proxies): - """This method re-evaluates the proxy configuration by considering the - environment variables. If we are redirected to a URL covered by - NO_PROXY, we strip the proxy configuration. Otherwise, we set missing - proxy keys for this URL (in case they were stripped by a previous - redirect). - - This method also replaces the Proxy-Authorization header where - necessary. - - :rtype: dict - """ - proxies = proxies if proxies is not None else {} - headers = prepared_request.headers - url = prepared_request.url - scheme = urlparse(url).scheme - new_proxies = proxies.copy() - no_proxy = proxies.get('no_proxy') - - bypass_proxy = should_bypass_proxies(url, no_proxy=no_proxy) - if self.trust_env and not bypass_proxy: - environ_proxies = get_environ_proxies(url, no_proxy=no_proxy) - - proxy = environ_proxies.get(scheme, environ_proxies.get('all')) - - if proxy: - new_proxies.setdefault(scheme, proxy) - - if 'Proxy-Authorization' in headers: - del headers['Proxy-Authorization'] - - try: - username, password = get_auth_from_url(new_proxies[scheme]) - except KeyError: - username, password = None, None - - if username and password: - headers['Proxy-Authorization'] = _basic_auth_str(username, password) - - return new_proxies - - def rebuild_method(self, prepared_request, response): - """When being redirected we may want to change the method of the request - based on certain specs or browser behavior. - """ - method = prepared_request.method - - # https://tools.ietf.org/html/rfc7231#section-6.4.4 - if response.status_code == codes.see_other and method != 'HEAD': - method = 'GET' - - # Do what the browsers do, despite standards... - # First, turn 302s into GETs. - if response.status_code == codes.found and method != 'HEAD': - method = 'GET' - - # Second, if a POST is responded to with a 301, turn it into a GET. - # This bizarre behaviour is explained in Issue 1704. - if response.status_code == codes.moved and method == 'POST': - method = 'GET' - - prepared_request.method = method - - -class Session(SessionRedirectMixin): - """A Requests session. - - Provides cookie persistence, connection-pooling, and configuration. - - Basic Usage:: - - >>> import requests - >>> s = requests.Session() - >>> s.get('https://httpbin.org/get') - <Response [200]> - - Or as a context manager:: - - >>> with requests.Session() as s: - ... s.get('https://httpbin.org/get') - <Response [200]> - """ - - __attrs__ = [ - 'headers', 'cookies', 'auth', 'proxies', 'hooks', 'params', 'verify', - 'cert', 'adapters', 'stream', 'trust_env', - 'max_redirects', - ] - - def __init__(self): - - #: A case-insensitive dictionary of headers to be sent on each - #: :class:`Request <Request>` sent from this - #: :class:`Session <Session>`. - self.headers = default_headers() - - #: Default Authentication tuple or object to attach to - #: :class:`Request <Request>`. - self.auth = None - - #: Dictionary mapping protocol or protocol and host to the URL of the proxy - #: (e.g. {'http': 'foo.bar:3128', 'http://host.name': 'foo.bar:4012'}) to - #: be used on each :class:`Request <Request>`. - self.proxies = {} - - #: Event-handling hooks. - self.hooks = default_hooks() - - #: Dictionary of querystring data to attach to each - #: :class:`Request <Request>`. The dictionary values may be lists for - #: representing multivalued query parameters. - self.params = {} - - #: Stream response content default. - self.stream = False - - #: SSL Verification default. - #: Defaults to `True`, requiring requests to verify the TLS certificate at the - #: remote end. - #: If verify is set to `False`, requests will accept any TLS certificate - #: presented by the server, and will ignore hostname mismatches and/or - #: expired certificates, which will make your application vulnerable to - #: man-in-the-middle (MitM) attacks. - #: Only set this to `False` for testing. - self.verify = True - - #: SSL client certificate default, if String, path to ssl client - #: cert file (.pem). If Tuple, ('cert', 'key') pair. - self.cert = None - - #: Maximum number of redirects allowed. If the request exceeds this - #: limit, a :class:`TooManyRedirects` exception is raised. - #: This defaults to requests.models.DEFAULT_REDIRECT_LIMIT, which is - #: 30. - self.max_redirects = DEFAULT_REDIRECT_LIMIT - - #: Trust environment settings for proxy configuration, default - #: authentication and similar. - self.trust_env = True - - #: A CookieJar containing all currently outstanding cookies set on this - #: session. By default it is a - #: :class:`RequestsCookieJar <requests.cookies.RequestsCookieJar>`, but - #: may be any other ``cookielib.CookieJar`` compatible object. - self.cookies = cookiejar_from_dict({}) - - # Default connection adapters. - self.adapters = OrderedDict() - self.mount('https://', HTTPAdapter()) - self.mount('http://', HTTPAdapter()) - - def __enter__(self): - return self - - def __exit__(self, *args): - self.close() - - def prepare_request(self, request): - """Constructs a :class:`PreparedRequest <PreparedRequest>` for - transmission and returns it. The :class:`PreparedRequest` has settings - merged from the :class:`Request <Request>` instance and those of the - :class:`Session`. - - :param request: :class:`Request` instance to prepare with this - session's settings. - :rtype: requests.PreparedRequest - """ - cookies = request.cookies or {} - - # Bootstrap CookieJar. - if not isinstance(cookies, cookielib.CookieJar): - cookies = cookiejar_from_dict(cookies) - - # Merge with session cookies - merged_cookies = merge_cookies( - merge_cookies(RequestsCookieJar(), self.cookies), cookies) - - # Set environment's basic authentication if not explicitly set. - auth = request.auth - if self.trust_env and not auth and not self.auth: - auth = get_netrc_auth(request.url) - - p = PreparedRequest() - p.prepare( - method=request.method.upper(), - url=request.url, - files=request.files, - data=request.data, - json=request.json, - headers=merge_setting(request.headers, self.headers, dict_class=CaseInsensitiveDict), - params=merge_setting(request.params, self.params), - auth=merge_setting(auth, self.auth), - cookies=merged_cookies, - hooks=merge_hooks(request.hooks, self.hooks), - ) - return p - - def request(self, method, url, - params=None, data=None, headers=None, cookies=None, files=None, - auth=None, timeout=None, allow_redirects=True, proxies=None, - hooks=None, stream=None, verify=None, cert=None, json=None): - """Constructs a :class:`Request <Request>`, prepares it and sends it. - Returns :class:`Response <Response>` object. - - :param method: method for the new :class:`Request` object. - :param url: URL for the new :class:`Request` object. - :param params: (optional) Dictionary or bytes to be sent in the query - string for the :class:`Request`. - :param data: (optional) Dictionary, list of tuples, bytes, or file-like - object to send in the body of the :class:`Request`. - :param json: (optional) json to send in the body of the - :class:`Request`. - :param headers: (optional) Dictionary of HTTP Headers to send with the - :class:`Request`. - :param cookies: (optional) Dict or CookieJar object to send with the - :class:`Request`. - :param files: (optional) Dictionary of ``'filename': file-like-objects`` - for multipart encoding upload. - :param auth: (optional) Auth tuple or callable to enable - Basic/Digest/Custom HTTP Auth. - :param timeout: (optional) How long to wait for the server to send - data before giving up, as a float, or a :ref:`(connect timeout, - read timeout) <timeouts>` tuple. - :type timeout: float or tuple - :param allow_redirects: (optional) Set to True by default. - :type allow_redirects: bool - :param proxies: (optional) Dictionary mapping protocol or protocol and - hostname to the URL of the proxy. - :param stream: (optional) whether to immediately download the response - content. Defaults to ``False``. - :param verify: (optional) Either a boolean, in which case it controls whether we verify - the server's TLS certificate, or a string, in which case it must be a path - to a CA bundle to use. Defaults to ``True``. When set to - ``False``, requests will accept any TLS certificate presented by - the server, and will ignore hostname mismatches and/or expired - certificates, which will make your application vulnerable to - man-in-the-middle (MitM) attacks. Setting verify to ``False`` - may be useful during local development or testing. - :param cert: (optional) if String, path to ssl client cert file (.pem). - If Tuple, ('cert', 'key') pair. - :rtype: requests.Response - """ - # Create the Request. - req = Request( - method=method.upper(), - url=url, - headers=headers, - files=files, - data=data or {}, - json=json, - params=params or {}, - auth=auth, - cookies=cookies, - hooks=hooks, - ) - prep = self.prepare_request(req) - - proxies = proxies or {} - - settings = self.merge_environment_settings( - prep.url, proxies, stream, verify, cert - ) - - # Send the request. - send_kwargs = { - 'timeout': timeout, - 'allow_redirects': allow_redirects, - } - send_kwargs.update(settings) - resp = self.send(prep, **send_kwargs) - - return resp - - def get(self, url, **kwargs): - r"""Sends a GET request. Returns :class:`Response` object. - - :param url: URL for the new :class:`Request` object. - :param \*\*kwargs: Optional arguments that ``request`` takes. - :rtype: requests.Response - """ - - kwargs.setdefault('allow_redirects', True) - return self.request('GET', url, **kwargs) - - def options(self, url, **kwargs): - r"""Sends a OPTIONS request. Returns :class:`Response` object. - - :param url: URL for the new :class:`Request` object. - :param \*\*kwargs: Optional arguments that ``request`` takes. - :rtype: requests.Response - """ - - kwargs.setdefault('allow_redirects', True) - return self.request('OPTIONS', url, **kwargs) - - def head(self, url, **kwargs): - r"""Sends a HEAD request. Returns :class:`Response` object. - - :param url: URL for the new :class:`Request` object. - :param \*\*kwargs: Optional arguments that ``request`` takes. - :rtype: requests.Response - """ - - kwargs.setdefault('allow_redirects', False) - return self.request('HEAD', url, **kwargs) - - def post(self, url, data=None, json=None, **kwargs): - r"""Sends a POST request. Returns :class:`Response` object. - - :param url: URL for the new :class:`Request` object. - :param data: (optional) Dictionary, list of tuples, bytes, or file-like - object to send in the body of the :class:`Request`. - :param json: (optional) json to send in the body of the :class:`Request`. - :param \*\*kwargs: Optional arguments that ``request`` takes. - :rtype: requests.Response - """ - - return self.request('POST', url, data=data, json=json, **kwargs) - - def put(self, url, data=None, **kwargs): - r"""Sends a PUT request. Returns :class:`Response` object. - - :param url: URL for the new :class:`Request` object. - :param data: (optional) Dictionary, list of tuples, bytes, or file-like - object to send in the body of the :class:`Request`. - :param \*\*kwargs: Optional arguments that ``request`` takes. - :rtype: requests.Response - """ - - return self.request('PUT', url, data=data, **kwargs) - - def patch(self, url, data=None, **kwargs): - r"""Sends a PATCH request. Returns :class:`Response` object. - - :param url: URL for the new :class:`Request` object. - :param data: (optional) Dictionary, list of tuples, bytes, or file-like - object to send in the body of the :class:`Request`. - :param \*\*kwargs: Optional arguments that ``request`` takes. - :rtype: requests.Response - """ - - return self.request('PATCH', url, data=data, **kwargs) - - def delete(self, url, **kwargs): - r"""Sends a DELETE request. Returns :class:`Response` object. - - :param url: URL for the new :class:`Request` object. - :param \*\*kwargs: Optional arguments that ``request`` takes. - :rtype: requests.Response - """ - - return self.request('DELETE', url, **kwargs) - - def send(self, request, **kwargs): - """Send a given PreparedRequest. - - :rtype: requests.Response - """ - # Set defaults that the hooks can utilize to ensure they always have - # the correct parameters to reproduce the previous request. - kwargs.setdefault('stream', self.stream) - kwargs.setdefault('verify', self.verify) - kwargs.setdefault('cert', self.cert) - kwargs.setdefault('proxies', self.proxies) - - # It's possible that users might accidentally send a Request object. - # Guard against that specific failure case. - if isinstance(request, Request): - raise ValueError('You can only send PreparedRequests.') - - # Set up variables needed for resolve_redirects and dispatching of hooks - allow_redirects = kwargs.pop('allow_redirects', True) - stream = kwargs.get('stream') - hooks = request.hooks - - # Get the appropriate adapter to use - adapter = self.get_adapter(url=request.url) - - # Start time (approximately) of the request - start = preferred_clock() - - # Send the request - r = adapter.send(request, **kwargs) - - # Total elapsed time of the request (approximately) - elapsed = preferred_clock() - start - r.elapsed = timedelta(seconds=elapsed) - - # Response manipulation hooks - r = dispatch_hook('response', hooks, r, **kwargs) - - # Persist cookies - if r.history: - - # If the hooks create history then we want those cookies too - for resp in r.history: - extract_cookies_to_jar(self.cookies, resp.request, resp.raw) - - extract_cookies_to_jar(self.cookies, request, r.raw) - - # Resolve redirects if allowed. - if allow_redirects: - # Redirect resolving generator. - gen = self.resolve_redirects(r, request, **kwargs) - history = [resp for resp in gen] - else: - history = [] - - # Shuffle things around if there's history. - if history: - # Insert the first (original) request at the start - history.insert(0, r) - # Get the last request made - r = history.pop() - r.history = history - - # If redirects aren't being followed, store the response on the Request for Response.next(). - if not allow_redirects: - try: - r._next = next(self.resolve_redirects(r, request, yield_requests=True, **kwargs)) - except StopIteration: - pass - - if not stream: - r.content - - return r - - def merge_environment_settings(self, url, proxies, stream, verify, cert): - """ - Check the environment and merge it with some settings. - - :rtype: dict - """ - # Gather clues from the surrounding environment. - if self.trust_env: - # Set environment's proxies. - no_proxy = proxies.get('no_proxy') if proxies is not None else None - env_proxies = get_environ_proxies(url, no_proxy=no_proxy) - for (k, v) in env_proxies.items(): - proxies.setdefault(k, v) - - # Look for requests environment configuration and be compatible - # with cURL. - if verify is True or verify is None: - verify = (os.environ.get('REQUESTS_CA_BUNDLE') or - os.environ.get('CURL_CA_BUNDLE')) - - # Merge all the kwargs. - proxies = merge_setting(proxies, self.proxies) - stream = merge_setting(stream, self.stream) - verify = merge_setting(verify, self.verify) - cert = merge_setting(cert, self.cert) - - return {'verify': verify, 'proxies': proxies, 'stream': stream, - 'cert': cert} - - def get_adapter(self, url): - """ - Returns the appropriate connection adapter for the given URL. - - :rtype: requests.adapters.BaseAdapter - """ - for (prefix, adapter) in self.adapters.items(): - - if url.lower().startswith(prefix.lower()): - return adapter - - # Nothing matches :-/ - raise InvalidSchema("No connection adapters were found for {!r}".format(url)) - - def close(self): - """Closes all adapters and as such the session""" - for v in self.adapters.values(): - v.close() - - def mount(self, prefix, adapter): - """Registers a connection adapter to a prefix. - - Adapters are sorted in descending order by prefix length. - """ - self.adapters[prefix] = adapter - keys_to_move = [k for k in self.adapters if len(k) < len(prefix)] - - for key in keys_to_move: - self.adapters[key] = self.adapters.pop(key) - - def __getstate__(self): - state = {attr: getattr(self, attr, None) for attr in self.__attrs__} - return state - - def __setstate__(self, state): - for attr, value in state.items(): - setattr(self, attr, value) - - -def session(): - """ - Returns a :class:`Session` for context-management. - - .. deprecated:: 1.0.0 - - This method has been deprecated since version 1.0.0 and is only kept for - backwards compatibility. New code should use :class:`~requests.sessions.Session` - to create a session. This may be removed at a future date. - - :rtype: Session - """ - return Session() diff --git a/venv/lib/python3.8/site-packages/requests/status_codes.py b/venv/lib/python3.8/site-packages/requests/status_codes.py deleted file mode 100644 index d80a7cd..0000000 --- a/venv/lib/python3.8/site-packages/requests/status_codes.py +++ /dev/null @@ -1,123 +0,0 @@ -# -*- coding: utf-8 -*- - -r""" -The ``codes`` object defines a mapping from common names for HTTP statuses -to their numerical codes, accessible either as attributes or as dictionary -items. - -Example:: - - >>> import requests - >>> requests.codes['temporary_redirect'] - 307 - >>> requests.codes.teapot - 418 - >>> requests.codes['\o/'] - 200 - -Some codes have multiple names, and both upper- and lower-case versions of -the names are allowed. For example, ``codes.ok``, ``codes.OK``, and -``codes.okay`` all correspond to the HTTP status code 200. -""" - -from .structures import LookupDict - -_codes = { - - # Informational. - 100: ('continue',), - 101: ('switching_protocols',), - 102: ('processing',), - 103: ('checkpoint',), - 122: ('uri_too_long', 'request_uri_too_long'), - 200: ('ok', 'okay', 'all_ok', 'all_okay', 'all_good', '\\o/', '✓'), - 201: ('created',), - 202: ('accepted',), - 203: ('non_authoritative_info', 'non_authoritative_information'), - 204: ('no_content',), - 205: ('reset_content', 'reset'), - 206: ('partial_content', 'partial'), - 207: ('multi_status', 'multiple_status', 'multi_stati', 'multiple_stati'), - 208: ('already_reported',), - 226: ('im_used',), - - # Redirection. - 300: ('multiple_choices',), - 301: ('moved_permanently', 'moved', '\\o-'), - 302: ('found',), - 303: ('see_other', 'other'), - 304: ('not_modified',), - 305: ('use_proxy',), - 306: ('switch_proxy',), - 307: ('temporary_redirect', 'temporary_moved', 'temporary'), - 308: ('permanent_redirect', - 'resume_incomplete', 'resume',), # These 2 to be removed in 3.0 - - # Client Error. - 400: ('bad_request', 'bad'), - 401: ('unauthorized',), - 402: ('payment_required', 'payment'), - 403: ('forbidden',), - 404: ('not_found', '-o-'), - 405: ('method_not_allowed', 'not_allowed'), - 406: ('not_acceptable',), - 407: ('proxy_authentication_required', 'proxy_auth', 'proxy_authentication'), - 408: ('request_timeout', 'timeout'), - 409: ('conflict',), - 410: ('gone',), - 411: ('length_required',), - 412: ('precondition_failed', 'precondition'), - 413: ('request_entity_too_large',), - 414: ('request_uri_too_large',), - 415: ('unsupported_media_type', 'unsupported_media', 'media_type'), - 416: ('requested_range_not_satisfiable', 'requested_range', 'range_not_satisfiable'), - 417: ('expectation_failed',), - 418: ('im_a_teapot', 'teapot', 'i_am_a_teapot'), - 421: ('misdirected_request',), - 422: ('unprocessable_entity', 'unprocessable'), - 423: ('locked',), - 424: ('failed_dependency', 'dependency'), - 425: ('unordered_collection', 'unordered'), - 426: ('upgrade_required', 'upgrade'), - 428: ('precondition_required', 'precondition'), - 429: ('too_many_requests', 'too_many'), - 431: ('header_fields_too_large', 'fields_too_large'), - 444: ('no_response', 'none'), - 449: ('retry_with', 'retry'), - 450: ('blocked_by_windows_parental_controls', 'parental_controls'), - 451: ('unavailable_for_legal_reasons', 'legal_reasons'), - 499: ('client_closed_request',), - - # Server Error. - 500: ('internal_server_error', 'server_error', '/o\\', '✗'), - 501: ('not_implemented',), - 502: ('bad_gateway',), - 503: ('service_unavailable', 'unavailable'), - 504: ('gateway_timeout',), - 505: ('http_version_not_supported', 'http_version'), - 506: ('variant_also_negotiates',), - 507: ('insufficient_storage',), - 509: ('bandwidth_limit_exceeded', 'bandwidth'), - 510: ('not_extended',), - 511: ('network_authentication_required', 'network_auth', 'network_authentication'), -} - -codes = LookupDict(name='status_codes') - -def _init(): - for code, titles in _codes.items(): - for title in titles: - setattr(codes, title, code) - if not title.startswith(('\\', '/')): - setattr(codes, title.upper(), code) - - def doc(code): - names = ', '.join('``%s``' % n for n in _codes[code]) - return '* %d: %s' % (code, names) - - global __doc__ - __doc__ = (__doc__ + '\n' + - '\n'.join(doc(code) for code in sorted(_codes)) - if __doc__ is not None else None) - -_init() diff --git a/venv/lib/python3.8/site-packages/requests/structures.py b/venv/lib/python3.8/site-packages/requests/structures.py deleted file mode 100644 index 8ee0ba7..0000000 --- a/venv/lib/python3.8/site-packages/requests/structures.py +++ /dev/null @@ -1,105 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -requests.structures -~~~~~~~~~~~~~~~~~~~ - -Data structures that power Requests. -""" - -from collections import OrderedDict - -from .compat import Mapping, MutableMapping - - -class CaseInsensitiveDict(MutableMapping): - """A case-insensitive ``dict``-like object. - - Implements all methods and operations of - ``MutableMapping`` as well as dict's ``copy``. Also - provides ``lower_items``. - - All keys are expected to be strings. The structure remembers the - case of the last key to be set, and ``iter(instance)``, - ``keys()``, ``items()``, ``iterkeys()``, and ``iteritems()`` - will contain case-sensitive keys. However, querying and contains - testing is case insensitive:: - - cid = CaseInsensitiveDict() - cid['Accept'] = 'application/json' - cid['aCCEPT'] == 'application/json' # True - list(cid) == ['Accept'] # True - - For example, ``headers['content-encoding']`` will return the - value of a ``'Content-Encoding'`` response header, regardless - of how the header name was originally stored. - - If the constructor, ``.update``, or equality comparison - operations are given keys that have equal ``.lower()``s, the - behavior is undefined. - """ - - def __init__(self, data=None, **kwargs): - self._store = OrderedDict() - if data is None: - data = {} - self.update(data, **kwargs) - - def __setitem__(self, key, value): - # Use the lowercased key for lookups, but store the actual - # key alongside the value. - self._store[key.lower()] = (key, value) - - def __getitem__(self, key): - return self._store[key.lower()][1] - - def __delitem__(self, key): - del self._store[key.lower()] - - def __iter__(self): - return (casedkey for casedkey, mappedvalue in self._store.values()) - - def __len__(self): - return len(self._store) - - def lower_items(self): - """Like iteritems(), but with all lowercase keys.""" - return ( - (lowerkey, keyval[1]) - for (lowerkey, keyval) - in self._store.items() - ) - - def __eq__(self, other): - if isinstance(other, Mapping): - other = CaseInsensitiveDict(other) - else: - return NotImplemented - # Compare insensitively - return dict(self.lower_items()) == dict(other.lower_items()) - - # Copy is required - def copy(self): - return CaseInsensitiveDict(self._store.values()) - - def __repr__(self): - return str(dict(self.items())) - - -class LookupDict(dict): - """Dictionary lookup object.""" - - def __init__(self, name=None): - self.name = name - super(LookupDict, self).__init__() - - def __repr__(self): - return '<lookup \'%s\'>' % (self.name) - - def __getitem__(self, key): - # We allow fall-through here, so values default to None - - return self.__dict__.get(key, None) - - def get(self, key, default=None): - return self.__dict__.get(key, default) diff --git a/venv/lib/python3.8/site-packages/requests/utils.py b/venv/lib/python3.8/site-packages/requests/utils.py deleted file mode 100644 index db67938..0000000 --- a/venv/lib/python3.8/site-packages/requests/utils.py +++ /dev/null @@ -1,992 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -requests.utils -~~~~~~~~~~~~~~ - -This module provides utility functions that are used within Requests -that are also useful for external consumption. -""" - -import codecs -import contextlib -import io -import os -import re -import socket -import struct -import sys -import tempfile -import warnings -import zipfile -from collections import OrderedDict - -from .__version__ import __version__ -from . import certs -# to_native_string is unused here, but imported here for backwards compatibility -from ._internal_utils import to_native_string -from .compat import parse_http_list as _parse_list_header -from .compat import ( - quote, urlparse, bytes, str, unquote, getproxies, - proxy_bypass, urlunparse, basestring, integer_types, is_py3, - proxy_bypass_environment, getproxies_environment, Mapping) -from .cookies import cookiejar_from_dict -from .structures import CaseInsensitiveDict -from .exceptions import ( - InvalidURL, InvalidHeader, FileModeWarning, UnrewindableBodyError) - -NETRC_FILES = ('.netrc', '_netrc') - -DEFAULT_CA_BUNDLE_PATH = certs.where() - -DEFAULT_PORTS = {'http': 80, 'https': 443} - - -if sys.platform == 'win32': - # provide a proxy_bypass version on Windows without DNS lookups - - def proxy_bypass_registry(host): - try: - if is_py3: - import winreg - else: - import _winreg as winreg - except ImportError: - return False - - try: - internetSettings = winreg.OpenKey(winreg.HKEY_CURRENT_USER, - r'Software\Microsoft\Windows\CurrentVersion\Internet Settings') - # ProxyEnable could be REG_SZ or REG_DWORD, normalizing it - proxyEnable = int(winreg.QueryValueEx(internetSettings, - 'ProxyEnable')[0]) - # ProxyOverride is almost always a string - proxyOverride = winreg.QueryValueEx(internetSettings, - 'ProxyOverride')[0] - except OSError: - return False - if not proxyEnable or not proxyOverride: - return False - - # make a check value list from the registry entry: replace the - # '<local>' string by the localhost entry and the corresponding - # canonical entry. - proxyOverride = proxyOverride.split(';') - # now check if we match one of the registry values. - for test in proxyOverride: - if test == '<local>': - if '.' not in host: - return True - test = test.replace(".", r"\.") # mask dots - test = test.replace("*", r".*") # change glob sequence - test = test.replace("?", r".") # change glob char - if re.match(test, host, re.I): - return True - return False - - def proxy_bypass(host): # noqa - """Return True, if the host should be bypassed. - - Checks proxy settings gathered from the environment, if specified, - or the registry. - """ - if getproxies_environment(): - return proxy_bypass_environment(host) - else: - return proxy_bypass_registry(host) - - -def dict_to_sequence(d): - """Returns an internal sequence dictionary update.""" - - if hasattr(d, 'items'): - d = d.items() - - return d - - -def super_len(o): - total_length = None - current_position = 0 - - if hasattr(o, '__len__'): - total_length = len(o) - - elif hasattr(o, 'len'): - total_length = o.len - - elif hasattr(o, 'fileno'): - try: - fileno = o.fileno() - except io.UnsupportedOperation: - pass - else: - total_length = os.fstat(fileno).st_size - - # Having used fstat to determine the file length, we need to - # confirm that this file was opened up in binary mode. - if 'b' not in o.mode: - warnings.warn(( - "Requests has determined the content-length for this " - "request using the binary size of the file: however, the " - "file has been opened in text mode (i.e. without the 'b' " - "flag in the mode). This may lead to an incorrect " - "content-length. In Requests 3.0, support will be removed " - "for files in text mode."), - FileModeWarning - ) - - if hasattr(o, 'tell'): - try: - current_position = o.tell() - except (OSError, IOError): - # This can happen in some weird situations, such as when the file - # is actually a special file descriptor like stdin. In this - # instance, we don't know what the length is, so set it to zero and - # let requests chunk it instead. - if total_length is not None: - current_position = total_length - else: - if hasattr(o, 'seek') and total_length is None: - # StringIO and BytesIO have seek but no useable fileno - try: - # seek to end of file - o.seek(0, 2) - total_length = o.tell() - - # seek back to current position to support - # partially read file-like objects - o.seek(current_position or 0) - except (OSError, IOError): - total_length = 0 - - if total_length is None: - total_length = 0 - - return max(0, total_length - current_position) - - -def get_netrc_auth(url, raise_errors=False): - """Returns the Requests tuple auth for a given url from netrc.""" - - netrc_file = os.environ.get('NETRC') - if netrc_file is not None: - netrc_locations = (netrc_file,) - else: - netrc_locations = ('~/{}'.format(f) for f in NETRC_FILES) - - try: - from netrc import netrc, NetrcParseError - - netrc_path = None - - for f in netrc_locations: - try: - loc = os.path.expanduser(f) - except KeyError: - # os.path.expanduser can fail when $HOME is undefined and - # getpwuid fails. See https://bugs.python.org/issue20164 & - # https://github.com/psf/requests/issues/1846 - return - - if os.path.exists(loc): - netrc_path = loc - break - - # Abort early if there isn't one. - if netrc_path is None: - return - - ri = urlparse(url) - - # Strip port numbers from netloc. This weird `if...encode`` dance is - # used for Python 3.2, which doesn't support unicode literals. - splitstr = b':' - if isinstance(url, str): - splitstr = splitstr.decode('ascii') - host = ri.netloc.split(splitstr)[0] - - try: - _netrc = netrc(netrc_path).authenticators(host) - if _netrc: - # Return with login / password - login_i = (0 if _netrc[0] else 1) - return (_netrc[login_i], _netrc[2]) - except (NetrcParseError, IOError): - # If there was a parsing error or a permissions issue reading the file, - # we'll just skip netrc auth unless explicitly asked to raise errors. - if raise_errors: - raise - - # App Engine hackiness. - except (ImportError, AttributeError): - pass - - -def guess_filename(obj): - """Tries to guess the filename of the given object.""" - name = getattr(obj, 'name', None) - if (name and isinstance(name, basestring) and name[0] != '<' and - name[-1] != '>'): - return os.path.basename(name) - - -def extract_zipped_paths(path): - """Replace nonexistent paths that look like they refer to a member of a zip - archive with the location of an extracted copy of the target, or else - just return the provided path unchanged. - """ - if os.path.exists(path): - # this is already a valid path, no need to do anything further - return path - - # find the first valid part of the provided path and treat that as a zip archive - # assume the rest of the path is the name of a member in the archive - archive, member = os.path.split(path) - while archive and not os.path.exists(archive): - archive, prefix = os.path.split(archive) - member = '/'.join([prefix, member]) - - if not zipfile.is_zipfile(archive): - return path - - zip_file = zipfile.ZipFile(archive) - if member not in zip_file.namelist(): - return path - - # we have a valid zip archive and a valid member of that archive - tmp = tempfile.gettempdir() - extracted_path = os.path.join(tmp, *member.split('/')) - if not os.path.exists(extracted_path): - extracted_path = zip_file.extract(member, path=tmp) - - return extracted_path - - -def from_key_val_list(value): - """Take an object and test to see if it can be represented as a - dictionary. Unless it can not be represented as such, return an - OrderedDict, e.g., - - :: - - >>> from_key_val_list([('key', 'val')]) - OrderedDict([('key', 'val')]) - >>> from_key_val_list('string') - Traceback (most recent call last): - ... - ValueError: cannot encode objects that are not 2-tuples - >>> from_key_val_list({'key': 'val'}) - OrderedDict([('key', 'val')]) - - :rtype: OrderedDict - """ - if value is None: - return None - - if isinstance(value, (str, bytes, bool, int)): - raise ValueError('cannot encode objects that are not 2-tuples') - - return OrderedDict(value) - - -def to_key_val_list(value): - """Take an object and test to see if it can be represented as a - dictionary. If it can be, return a list of tuples, e.g., - - :: - - >>> to_key_val_list([('key', 'val')]) - [('key', 'val')] - >>> to_key_val_list({'key': 'val'}) - [('key', 'val')] - >>> to_key_val_list('string') - Traceback (most recent call last): - ... - ValueError: cannot encode objects that are not 2-tuples - - :rtype: list - """ - if value is None: - return None - - if isinstance(value, (str, bytes, bool, int)): - raise ValueError('cannot encode objects that are not 2-tuples') - - if isinstance(value, Mapping): - value = value.items() - - return list(value) - - -# From mitsuhiko/werkzeug (used with permission). -def parse_list_header(value): - """Parse lists as described by RFC 2068 Section 2. - - In particular, parse comma-separated lists where the elements of - the list may include quoted-strings. A quoted-string could - contain a comma. A non-quoted string could have quotes in the - middle. Quotes are removed automatically after parsing. - - It basically works like :func:`parse_set_header` just that items - may appear multiple times and case sensitivity is preserved. - - The return value is a standard :class:`list`: - - >>> parse_list_header('token, "quoted value"') - ['token', 'quoted value'] - - To create a header from the :class:`list` again, use the - :func:`dump_header` function. - - :param value: a string with a list header. - :return: :class:`list` - :rtype: list - """ - result = [] - for item in _parse_list_header(value): - if item[:1] == item[-1:] == '"': - item = unquote_header_value(item[1:-1]) - result.append(item) - return result - - -# From mitsuhiko/werkzeug (used with permission). -def parse_dict_header(value): - """Parse lists of key, value pairs as described by RFC 2068 Section 2 and - convert them into a python dict: - - >>> d = parse_dict_header('foo="is a fish", bar="as well"') - >>> type(d) is dict - True - >>> sorted(d.items()) - [('bar', 'as well'), ('foo', 'is a fish')] - - If there is no value for a key it will be `None`: - - >>> parse_dict_header('key_without_value') - {'key_without_value': None} - - To create a header from the :class:`dict` again, use the - :func:`dump_header` function. - - :param value: a string with a dict header. - :return: :class:`dict` - :rtype: dict - """ - result = {} - for item in _parse_list_header(value): - if '=' not in item: - result[item] = None - continue - name, value = item.split('=', 1) - if value[:1] == value[-1:] == '"': - value = unquote_header_value(value[1:-1]) - result[name] = value - return result - - -# From mitsuhiko/werkzeug (used with permission). -def unquote_header_value(value, is_filename=False): - r"""Unquotes a header value. (Reversal of :func:`quote_header_value`). - This does not use the real unquoting but what browsers are actually - using for quoting. - - :param value: the header value to unquote. - :rtype: str - """ - if value and value[0] == value[-1] == '"': - # this is not the real unquoting, but fixing this so that the - # RFC is met will result in bugs with internet explorer and - # probably some other browsers as well. IE for example is - # uploading files with "C:\foo\bar.txt" as filename - value = value[1:-1] - - # if this is a filename and the starting characters look like - # a UNC path, then just return the value without quotes. Using the - # replace sequence below on a UNC path has the effect of turning - # the leading double slash into a single slash and then - # _fix_ie_filename() doesn't work correctly. See #458. - if not is_filename or value[:2] != '\\\\': - return value.replace('\\\\', '\\').replace('\\"', '"') - return value - - -def dict_from_cookiejar(cj): - """Returns a key/value dictionary from a CookieJar. - - :param cj: CookieJar object to extract cookies from. - :rtype: dict - """ - - cookie_dict = {} - - for cookie in cj: - cookie_dict[cookie.name] = cookie.value - - return cookie_dict - - -def add_dict_to_cookiejar(cj, cookie_dict): - """Returns a CookieJar from a key/value dictionary. - - :param cj: CookieJar to insert cookies into. - :param cookie_dict: Dict of key/values to insert into CookieJar. - :rtype: CookieJar - """ - - return cookiejar_from_dict(cookie_dict, cj) - - -def get_encodings_from_content(content): - """Returns encodings from given content string. - - :param content: bytestring to extract encodings from. - """ - warnings.warn(( - 'In requests 3.0, get_encodings_from_content will be removed. For ' - 'more information, please see the discussion on issue #2266. (This' - ' warning should only appear once.)'), - DeprecationWarning) - - charset_re = re.compile(r'<meta.*?charset=["\']*(.+?)["\'>]', flags=re.I) - pragma_re = re.compile(r'<meta.*?content=["\']*;?charset=(.+?)["\'>]', flags=re.I) - xml_re = re.compile(r'^<\?xml.*?encoding=["\']*(.+?)["\'>]') - - return (charset_re.findall(content) + - pragma_re.findall(content) + - xml_re.findall(content)) - - -def _parse_content_type_header(header): - """Returns content type and parameters from given header - - :param header: string - :return: tuple containing content type and dictionary of - parameters - """ - - tokens = header.split(';') - content_type, params = tokens[0].strip(), tokens[1:] - params_dict = {} - items_to_strip = "\"' " - - for param in params: - param = param.strip() - if param: - key, value = param, True - index_of_equals = param.find("=") - if index_of_equals != -1: - key = param[:index_of_equals].strip(items_to_strip) - value = param[index_of_equals + 1:].strip(items_to_strip) - params_dict[key.lower()] = value - return content_type, params_dict - - -def get_encoding_from_headers(headers): - """Returns encodings from given HTTP Header Dict. - - :param headers: dictionary to extract encoding from. - :rtype: str - """ - - content_type = headers.get('content-type') - - if not content_type: - return None - - content_type, params = _parse_content_type_header(content_type) - - if 'charset' in params: - return params['charset'].strip("'\"") - - if 'text' in content_type: - return 'ISO-8859-1' - - if 'application/json' in content_type: - # Assume UTF-8 based on RFC 4627: https://www.ietf.org/rfc/rfc4627.txt since the charset was unset - return 'utf-8' - - -def stream_decode_response_unicode(iterator, r): - """Stream decodes a iterator.""" - - if r.encoding is None: - for item in iterator: - yield item - return - - decoder = codecs.getincrementaldecoder(r.encoding)(errors='replace') - for chunk in iterator: - rv = decoder.decode(chunk) - if rv: - yield rv - rv = decoder.decode(b'', final=True) - if rv: - yield rv - - -def iter_slices(string, slice_length): - """Iterate over slices of a string.""" - pos = 0 - if slice_length is None or slice_length <= 0: - slice_length = len(string) - while pos < len(string): - yield string[pos:pos + slice_length] - pos += slice_length - - -def get_unicode_from_response(r): - """Returns the requested content back in unicode. - - :param r: Response object to get unicode content from. - - Tried: - - 1. charset from content-type - 2. fall back and replace all unicode characters - - :rtype: str - """ - warnings.warn(( - 'In requests 3.0, get_unicode_from_response will be removed. For ' - 'more information, please see the discussion on issue #2266. (This' - ' warning should only appear once.)'), - DeprecationWarning) - - tried_encodings = [] - - # Try charset from content-type - encoding = get_encoding_from_headers(r.headers) - - if encoding: - try: - return str(r.content, encoding) - except UnicodeError: - tried_encodings.append(encoding) - - # Fall back: - try: - return str(r.content, encoding, errors='replace') - except TypeError: - return r.content - - -# The unreserved URI characters (RFC 3986) -UNRESERVED_SET = frozenset( - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + "0123456789-._~") - - -def unquote_unreserved(uri): - """Un-escape any percent-escape sequences in a URI that are unreserved - characters. This leaves all reserved, illegal and non-ASCII bytes encoded. - - :rtype: str - """ - parts = uri.split('%') - for i in range(1, len(parts)): - h = parts[i][0:2] - if len(h) == 2 and h.isalnum(): - try: - c = chr(int(h, 16)) - except ValueError: - raise InvalidURL("Invalid percent-escape sequence: '%s'" % h) - - if c in UNRESERVED_SET: - parts[i] = c + parts[i][2:] - else: - parts[i] = '%' + parts[i] - else: - parts[i] = '%' + parts[i] - return ''.join(parts) - - -def requote_uri(uri): - """Re-quote the given URI. - - This function passes the given URI through an unquote/quote cycle to - ensure that it is fully and consistently quoted. - - :rtype: str - """ - safe_with_percent = "!#$%&'()*+,/:;=?@[]~" - safe_without_percent = "!#$&'()*+,/:;=?@[]~" - try: - # Unquote only the unreserved characters - # Then quote only illegal characters (do not quote reserved, - # unreserved, or '%') - return quote(unquote_unreserved(uri), safe=safe_with_percent) - except InvalidURL: - # We couldn't unquote the given URI, so let's try quoting it, but - # there may be unquoted '%'s in the URI. We need to make sure they're - # properly quoted so they do not cause issues elsewhere. - return quote(uri, safe=safe_without_percent) - - -def address_in_network(ip, net): - """This function allows you to check if an IP belongs to a network subnet - - Example: returns True if ip = 192.168.1.1 and net = 192.168.1.0/24 - returns False if ip = 192.168.1.1 and net = 192.168.100.0/24 - - :rtype: bool - """ - ipaddr = struct.unpack('=L', socket.inet_aton(ip))[0] - netaddr, bits = net.split('/') - netmask = struct.unpack('=L', socket.inet_aton(dotted_netmask(int(bits))))[0] - network = struct.unpack('=L', socket.inet_aton(netaddr))[0] & netmask - return (ipaddr & netmask) == (network & netmask) - - -def dotted_netmask(mask): - """Converts mask from /xx format to xxx.xxx.xxx.xxx - - Example: if mask is 24 function returns 255.255.255.0 - - :rtype: str - """ - bits = 0xffffffff ^ (1 << 32 - mask) - 1 - return socket.inet_ntoa(struct.pack('>I', bits)) - - -def is_ipv4_address(string_ip): - """ - :rtype: bool - """ - try: - socket.inet_aton(string_ip) - except socket.error: - return False - return True - - -def is_valid_cidr(string_network): - """ - Very simple check of the cidr format in no_proxy variable. - - :rtype: bool - """ - if string_network.count('/') == 1: - try: - mask = int(string_network.split('/')[1]) - except ValueError: - return False - - if mask < 1 or mask > 32: - return False - - try: - socket.inet_aton(string_network.split('/')[0]) - except socket.error: - return False - else: - return False - return True - - -@contextlib.contextmanager -def set_environ(env_name, value): - """Set the environment variable 'env_name' to 'value' - - Save previous value, yield, and then restore the previous value stored in - the environment variable 'env_name'. - - If 'value' is None, do nothing""" - value_changed = value is not None - if value_changed: - old_value = os.environ.get(env_name) - os.environ[env_name] = value - try: - yield - finally: - if value_changed: - if old_value is None: - del os.environ[env_name] - else: - os.environ[env_name] = old_value - - -def should_bypass_proxies(url, no_proxy): - """ - Returns whether we should bypass proxies or not. - - :rtype: bool - """ - # Prioritize lowercase environment variables over uppercase - # to keep a consistent behaviour with other http projects (curl, wget). - get_proxy = lambda k: os.environ.get(k) or os.environ.get(k.upper()) - - # First check whether no_proxy is defined. If it is, check that the URL - # we're getting isn't in the no_proxy list. - no_proxy_arg = no_proxy - if no_proxy is None: - no_proxy = get_proxy('no_proxy') - parsed = urlparse(url) - - if parsed.hostname is None: - # URLs don't always have hostnames, e.g. file:/// urls. - return True - - if no_proxy: - # We need to check whether we match here. We need to see if we match - # the end of the hostname, both with and without the port. - no_proxy = ( - host for host in no_proxy.replace(' ', '').split(',') if host - ) - - if is_ipv4_address(parsed.hostname): - for proxy_ip in no_proxy: - if is_valid_cidr(proxy_ip): - if address_in_network(parsed.hostname, proxy_ip): - return True - elif parsed.hostname == proxy_ip: - # If no_proxy ip was defined in plain IP notation instead of cidr notation & - # matches the IP of the index - return True - else: - host_with_port = parsed.hostname - if parsed.port: - host_with_port += ':{}'.format(parsed.port) - - for host in no_proxy: - if parsed.hostname.endswith(host) or host_with_port.endswith(host): - # The URL does match something in no_proxy, so we don't want - # to apply the proxies on this URL. - return True - - with set_environ('no_proxy', no_proxy_arg): - # parsed.hostname can be `None` in cases such as a file URI. - try: - bypass = proxy_bypass(parsed.hostname) - except (TypeError, socket.gaierror): - bypass = False - - if bypass: - return True - - return False - - -def get_environ_proxies(url, no_proxy=None): - """ - Return a dict of environment proxies. - - :rtype: dict - """ - if should_bypass_proxies(url, no_proxy=no_proxy): - return {} - else: - return getproxies() - - -def select_proxy(url, proxies): - """Select a proxy for the url, if applicable. - - :param url: The url being for the request - :param proxies: A dictionary of schemes or schemes and hosts to proxy URLs - """ - proxies = proxies or {} - urlparts = urlparse(url) - if urlparts.hostname is None: - return proxies.get(urlparts.scheme, proxies.get('all')) - - proxy_keys = [ - urlparts.scheme + '://' + urlparts.hostname, - urlparts.scheme, - 'all://' + urlparts.hostname, - 'all', - ] - proxy = None - for proxy_key in proxy_keys: - if proxy_key in proxies: - proxy = proxies[proxy_key] - break - - return proxy - - -def default_user_agent(name="python-requests"): - """ - Return a string representing the default user agent. - - :rtype: str - """ - return '%s/%s' % (name, __version__) - - -def default_headers(): - """ - :rtype: requests.structures.CaseInsensitiveDict - """ - return CaseInsensitiveDict({ - 'User-Agent': default_user_agent(), - 'Accept-Encoding': ', '.join(('gzip', 'deflate')), - 'Accept': '*/*', - 'Connection': 'keep-alive', - }) - - -def parse_header_links(value): - """Return a list of parsed link headers proxies. - - i.e. Link: <http:/.../front.jpeg>; rel=front; type="image/jpeg",<http://.../back.jpeg>; rel=back;type="image/jpeg" - - :rtype: list - """ - - links = [] - - replace_chars = ' \'"' - - value = value.strip(replace_chars) - if not value: - return links - - for val in re.split(', *<', value): - try: - url, params = val.split(';', 1) - except ValueError: - url, params = val, '' - - link = {'url': url.strip('<> \'"')} - - for param in params.split(';'): - try: - key, value = param.split('=') - except ValueError: - break - - link[key.strip(replace_chars)] = value.strip(replace_chars) - - links.append(link) - - return links - - -# Null bytes; no need to recreate these on each call to guess_json_utf -_null = '\x00'.encode('ascii') # encoding to ASCII for Python 3 -_null2 = _null * 2 -_null3 = _null * 3 - - -def guess_json_utf(data): - """ - :rtype: str - """ - # JSON always starts with two ASCII characters, so detection is as - # easy as counting the nulls and from their location and count - # determine the encoding. Also detect a BOM, if present. - sample = data[:4] - if sample in (codecs.BOM_UTF32_LE, codecs.BOM_UTF32_BE): - return 'utf-32' # BOM included - if sample[:3] == codecs.BOM_UTF8: - return 'utf-8-sig' # BOM included, MS style (discouraged) - if sample[:2] in (codecs.BOM_UTF16_LE, codecs.BOM_UTF16_BE): - return 'utf-16' # BOM included - nullcount = sample.count(_null) - if nullcount == 0: - return 'utf-8' - if nullcount == 2: - if sample[::2] == _null2: # 1st and 3rd are null - return 'utf-16-be' - if sample[1::2] == _null2: # 2nd and 4th are null - return 'utf-16-le' - # Did not detect 2 valid UTF-16 ascii-range characters - if nullcount == 3: - if sample[:3] == _null3: - return 'utf-32-be' - if sample[1:] == _null3: - return 'utf-32-le' - # Did not detect a valid UTF-32 ascii-range character - return None - - -def prepend_scheme_if_needed(url, new_scheme): - """Given a URL that may or may not have a scheme, prepend the given scheme. - Does not replace a present scheme with the one provided as an argument. - - :rtype: str - """ - scheme, netloc, path, params, query, fragment = urlparse(url, new_scheme) - - # urlparse is a finicky beast, and sometimes decides that there isn't a - # netloc present. Assume that it's being over-cautious, and switch netloc - # and path if urlparse decided there was no netloc. - if not netloc: - netloc, path = path, netloc - - return urlunparse((scheme, netloc, path, params, query, fragment)) - - -def get_auth_from_url(url): - """Given a url with authentication components, extract them into a tuple of - username,password. - - :rtype: (str,str) - """ - parsed = urlparse(url) - - try: - auth = (unquote(parsed.username), unquote(parsed.password)) - except (AttributeError, TypeError): - auth = ('', '') - - return auth - - -# Moved outside of function to avoid recompile every call -_CLEAN_HEADER_REGEX_BYTE = re.compile(b'^\\S[^\\r\\n]*$|^$') -_CLEAN_HEADER_REGEX_STR = re.compile(r'^\S[^\r\n]*$|^$') - - -def check_header_validity(header): - """Verifies that header value is a string which doesn't contain - leading whitespace or return characters. This prevents unintended - header injection. - - :param header: tuple, in the format (name, value). - """ - name, value = header - - if isinstance(value, bytes): - pat = _CLEAN_HEADER_REGEX_BYTE - else: - pat = _CLEAN_HEADER_REGEX_STR - try: - if not pat.match(value): - raise InvalidHeader("Invalid return character or leading space in header: %s" % name) - except TypeError: - raise InvalidHeader("Value for header {%s: %s} must be of type str or " - "bytes, not %s" % (name, value, type(value))) - - -def urldefragauth(url): - """ - Given a url remove the fragment and the authentication part. - - :rtype: str - """ - scheme, netloc, path, params, query, fragment = urlparse(url) - - # see func:`prepend_scheme_if_needed` - if not netloc: - netloc, path = path, netloc - - netloc = netloc.rsplit('@', 1)[-1] - - return urlunparse((scheme, netloc, path, params, query, '')) - - -def rewind_body(prepared_request): - """Move file pointer back to its recorded starting position - so it can be read again on redirect. - """ - body_seek = getattr(prepared_request.body, 'seek', None) - if body_seek is not None and isinstance(prepared_request._body_position, integer_types): - try: - body_seek(prepared_request._body_position) - except (IOError, OSError): - raise UnrewindableBodyError("An error occurred when rewinding request " - "body for redirect.") - else: - raise UnrewindableBodyError("Unable to rewind request body for redirect.") diff --git a/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/AUTHORS.txt b/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/AUTHORS.txt deleted file mode 100644 index 04c42fc..0000000 --- a/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/AUTHORS.txt +++ /dev/null @@ -1,566 +0,0 @@ -@Switch01 -A_Rog -Aakanksha Agrawal -Abhinav Sagar -ABHYUDAY PRATAP SINGH -abs51295 -AceGentile -Adam Chainz -Adam Tse -Adam Wentz -admin -Adrien Morison -ahayrapetyan -Ahilya -AinsworthK -Akash Srivastava -Alan Yee -Albert Tugushev -Albert-Guan -albertg -Aleks Bunin -Alethea Flowers -Alex Gaynor -Alex Grönholm -Alex Loosley -Alex Morega -Alex Stachowiak -Alexander Shtyrov -Alexandre Conrad -Alexey Popravka -Alli -Ami Fischman -Ananya Maiti -Anatoly Techtonik -Anders Kaseorg -Andre Aguiar -Andreas Lutro -Andrei Geacar -Andrew Gaul -Andrey Bulgakov -Andrés Delfino -Andy Freeland -Andy Kluger -Ani Hayrapetyan -Aniruddha Basak -Anish Tambe -Anrs Hu -Anthony Sottile -Antoine Musso -Anton Ovchinnikov -Anton Patrushev -Antonio Alvarado Hernandez -Antony Lee -Antti Kaihola -Anubhav Patel -Anudit Nagar -Anuj Godase -AQNOUCH Mohammed -AraHaan -Arindam Choudhury -Armin Ronacher -Artem -Ashley Manton -Ashwin Ramaswami -atse -Atsushi Odagiri -Avner Cohen -Baptiste Mispelon -Barney Gale -barneygale -Bartek Ogryczak -Bastian Venthur -Ben Darnell -Ben Hoyt -Ben Rosser -Bence Nagy -Benjamin Peterson -Benjamin VanEvery -Benoit Pierre -Berker Peksag -Bernardo B. Marques -Bernhard M. Wiedemann -Bertil Hatt -Bhavam Vidyarthi -Bogdan Opanchuk -BorisZZZ -Brad Erickson -Bradley Ayers -Brandon L. Reiss -Brandt Bucher -Brett Randall -Brian Cristante -Brian Rosner -BrownTruck -Bruno Oliveira -Bruno Renié -Bstrdsmkr -Buck Golemon -burrows -Bussonnier Matthias -c22 -Caleb Martinez -Calvin Smith -Carl Meyer -Carlos Liam -Carol Willing -Carter Thayer -Cass -Chandrasekhar Atina -Chih-Hsuan Yen -Chris Brinker -Chris Hunt -Chris Jerdonek -Chris McDonough -Chris Wolfe -Christian Clauss -Christian Heimes -Christian Oudard -Christoph Reiter -Christopher Hunt -Christopher Snyder -cjc7373 -Clark Boylan -Clay McClure -Cody -Cody Soyland -Colin Watson -Connor Osborn -Cooper Lees -Cooper Ry Lees -Cory Benfield -Cory Wright -Craig Kerstiens -Cristian Sorinel -Curtis Doty -cytolentino -Damian Quiroga -Dan Black -Dan Savilonis -Dan Sully -daniel -Daniel Collins -Daniel Hahler -Daniel Holth -Daniel Jost -Daniel Shaulov -Daniele Esposti -Daniele Procida -Danny Hermes -Danny McClanahan -Dav Clark -Dave Abrahams -Dave Jones -David Aguilar -David Black -David Bordeynik -David Caro -David Evans -David Linke -David Pursehouse -David Tucker -David Wales -Davidovich -Deepak Sharma -derwolfe -Desetude -Devesh Kumar Singh -Diego Caraballo -DiegoCaraballo -Dmitry Gladkov -Domen Kožar -Donald Stufft -Dongweiming -Douglas Thor -DrFeathers -Dustin Ingram -Dwayne Bailey -Ed Morley -Eitan Adler -ekristina -elainechan -Eli Schwartz -Ellen Marie Dash -Emil Burzo -Emil Styrke -Endoh Takanao -enoch -Erdinc Mutlu -Eric Gillingham -Eric Hanchrow -Eric Hopper -Erik M. Bray -Erik Rose -Ernest W Durbin III -Ernest W. Durbin III -Erwin Janssen -Eugene Vereshchagin -everdimension -Felix Yan -fiber-space -Filip Kokosiński -Florian Briand -Florian Rathgeber -Francesco -Francesco Montesano -Frost Ming -Gabriel Curio -Gabriel de Perthuis -Garry Polley -gdanielson -Geoffrey Lehée -Geoffrey Sneddon -George Song -Georgi Valkov -ghost -Giftlin Rajaiah -gizmoguy1 -gkdoc -Gopinath M -GOTO Hayato -gpiks -Guilherme Espada -gutsytechster -Guy Rozendorn -gzpan123 -Hanjun Kim -Hari Charan -Harsh Vardhan -Herbert Pfennig -Hsiaoming Yang -Hugo -Hugo Lopes Tavares -Hugo van Kemenade -hugovk -Hynek Schlawack -Ian Bicking -Ian Cordasco -Ian Lee -Ian Stapleton Cordasco -Ian Wienand -Igor Kuzmitshov -Igor Sobreira -Ilan Schnell -Ilya Baryshev -INADA Naoki -Ionel Cristian Mărieș -Ionel Maries Cristian -Ivan Pozdeev -Jacob Kim -jakirkham -Jakub Stasiak -Jakub Vysoky -Jakub Wilk -James Cleveland -James Firth -James Polley -Jan Pokorný -Jannis Leidel -jarondl -Jason R. Coombs -Jay Graves -Jean-Christophe Fillion-Robin -Jeff Barber -Jeff Dairiki -Jelmer Vernooij -jenix21 -Jeremy Stanley -Jeremy Zafran -Jiashuo Li -Jim Garrison -Jivan Amara -John Paton -John T. Wodder II -John-Scott Atlakson -johnthagen -Jon Banafato -Jon Dufresne -Jon Parise -Jonas Nockert -Jonathan Herbert -Joost Molenaar -Jorge Niedbalski -Joseph Long -Josh Bronson -Josh Hansen -Josh Schneier -Juanjo Bazán -Julian Berman -Julian Gethmann -Julien Demoor -jwg4 -Jyrki Pulliainen -Kai Chen -Kamal Bin Mustafa -kaustav haldar -keanemind -Keith Maxwell -Kelsey Hightower -Kenneth Belitzky -Kenneth Reitz -Kevin Burke -Kevin Carter -Kevin Frommelt -Kevin R Patterson -Kexuan Sun -Kit Randel -KOLANICH -kpinc -Krishna Oza -Kumar McMillan -Kyle Persohn -lakshmanaram -Laszlo Kiss-Kollar -Laurent Bristiel -Laurie Opperman -Leon Sasson -Lev Givon -Lincoln de Sousa -Lipis -Loren Carvalho -Lucas Cimon -Ludovic Gasc -Luke Macken -Luo Jiebin -luojiebin -luz.paz -László Kiss Kollár -Marc Abramowitz -Marc Tamlyn -Marcus Smith -Mariatta -Mark Kohler -Mark Williams -Markus Hametner -Masaki -Masklinn -Matej Stuchlik -Mathew Jennings -Mathieu Bridon -Matt Good -Matt Maker -Matt Robenolt -matthew -Matthew Einhorn -Matthew Gilliard -Matthew Iversen -Matthew Trumbell -Matthew Willson -Matthias Bussonnier -mattip -Maxim Kurnikov -Maxime Rouyrre -mayeut -mbaluna -mdebi -memoselyk -Michael -Michael Aquilina -Michael E. Karpeles -Michael Klich -Michael Williamson -michaelpacer -Mickaël Schoentgen -Miguel Araujo Perez -Mihir Singh -Mike -Mike Hendricks -Min RK -MinRK -Miro Hrončok -Monica Baluna -montefra -Monty Taylor -Nate Coraor -Nathaniel J. Smith -Nehal J Wani -Neil Botelho -Nguyễn Gia Phong -Nick Coghlan -Nick Stenning -Nick Timkovich -Nicolas Bock -Nikhil Benesch -Nikolay Korolev -Nitesh Sharma -Noah Gorny -Nowell Strite -NtaleGrey -nvdv -Ofekmeister -ofrinevo -Oliver Jeeves -Oliver Tonnhofer -Olivier Girardot -Olivier Grisel -Ollie Rutherfurd -OMOTO Kenji -Omry Yadan -onlinejudge95 -Oren Held -Oscar Benjamin -Oz N Tiram -Pachwenko -Patrick Dubroy -Patrick Jenkins -Patrick Lawson -patricktokeeffe -Patrik Kopkan -Paul Kehrer -Paul Moore -Paul Nasrat -Paul Oswald -Paul van der Linden -Paulus Schoutsen -Pavithra Eswaramoorthy -Pawel Jasinski -Pekka Klärck -Peter Lisák -Peter Waller -petr-tik -Phaneendra Chiruvella -Phil Freo -Phil Pennock -Phil Whelan -Philip Jägenstedt -Philip Molloy -Philippe Ombredanne -Pi Delport -Pierre-Yves Rofes -pip -Prabakaran Kumaresshan -Prabhjyotsing Surjit Singh Sodhi -Prabhu Marappan -Pradyun Gedam -Prashant Sharma -Pratik Mallya -Preet Thakkar -Preston Holmes -Przemek Wrzos -Pulkit Goyal -Qiangning Hong -Quentin Pradet -R. David Murray -Rafael Caricio -Ralf Schmitt -Razzi Abuissa -rdb -Reece Dunham -Remi Rampin -Rene Dudfield -Riccardo Magliocchetti -Richard Jones -Ricky Ng-Adam -RobberPhex -Robert Collins -Robert McGibbon -Robert T. McGibbon -robin elisha robinson -Roey Berman -Rohan Jain -Roman Bogorodskiy -Romuald Brunet -Ronny Pfannschmidt -Rory McCann -Ross Brattain -Roy Wellington Ⅳ -Ryan Wooden -ryneeverett -Sachi King -Salvatore Rinchiera -Savio Jomton -schlamar -Scott Kitterman -Sean -seanj -Sebastian Jordan -Sebastian Schaetz -Segev Finer -SeongSoo Cho -Sergey Vasilyev -Seth Woodworth -Shlomi Fish -Shovan Maity -Simeon Visser -Simon Cross -Simon Pichugin -sinoroc -sinscary -Sorin Sbarnea -Stavros Korokithakis -Stefan Scherfke -Stefano Rivera -Stephan Erb -stepshal -Steve (Gadget) Barnes -Steve Barnes -Steve Dower -Steve Kowalik -Steven Myint -stonebig -Stéphane Bidoul -Stéphane Bidoul (ACSONE) -Stéphane Klein -Sumana Harihareswara -Sviatoslav Sydorenko -Swat009 -Takayuki SHIMIZUKAWA -tbeswick -Thijs Triemstra -Thomas Fenzl -Thomas Grainger -Thomas Guettler -Thomas Johansson -Thomas Kluyver -Thomas Smith -Tim D. Smith -Tim Gates -Tim Harder -Tim Heap -tim smith -tinruufu -Tom Forbes -Tom Freudenheim -Tom V -Tomas Hrnciar -Tomas Orsava -Tomer Chachamu -Tony Beswick -Tony Zhaocheng Tan -TonyBeswick -toonarmycaptain -Toshio Kuratomi -Travis Swicegood -Tzu-ping Chung -Valentin Haenel -Victor Stinner -victorvpaulo -Viktor Szépe -Ville Skyttä -Vinay Sajip -Vincent Philippon -Vinicyus Macedo -Vitaly Babiy -Vladimir Rutsky -W. Trevor King -Wil Tan -Wilfred Hughes -William ML Leslie -William T Olson -Wilson Mo -wim glenn -Wolfgang Maier -Xavier Fernandez -xoviat -xtreak -YAMAMOTO Takashi -Yen Chi Hsuan -Yeray Diaz Diaz -Yoval P -Yu Jian -Yuan Jing Vincent Yan -Zearin -Zhiping Deng -Zvezdan Petkovic -Łukasz Langa -Семён Марьясин diff --git a/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/INSTALLER b/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/LICENSE.txt b/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/LICENSE.txt deleted file mode 100644 index 737fec5..0000000 --- a/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/LICENSE.txt +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2008-2019 The pip developers (see AUTHORS.txt file) - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/METADATA b/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/METADATA deleted file mode 100644 index 4adf953..0000000 --- a/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/METADATA +++ /dev/null @@ -1,82 +0,0 @@ -Metadata-Version: 2.1 -Name: setuptools -Version: 44.0.0 -Summary: Easily download, build, install, upgrade, and uninstall Python packages -Home-page: https://github.com/pypa/setuptools -Author: Python Packaging Authority -Author-email: distutils-sig@python.org -License: UNKNOWN -Project-URL: Documentation, https://setuptools.readthedocs.io/ -Keywords: CPAN PyPI distutils eggs package management -Platform: UNKNOWN -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: MIT License -Classifier: Operating System :: OS Independent -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: Topic :: Software Development :: Libraries :: Python Modules -Classifier: Topic :: System :: Archiving :: Packaging -Classifier: Topic :: System :: Systems Administration -Classifier: Topic :: Utilities -Requires-Python: !=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7 -Description-Content-Type: text/x-rst; charset=UTF-8 - -.. image:: https://img.shields.io/pypi/v/setuptools.svg - :target: https://pypi.org/project/setuptools - -.. image:: https://img.shields.io/readthedocs/setuptools/latest.svg - :target: https://setuptools.readthedocs.io - -.. image:: https://img.shields.io/travis/pypa/setuptools/master.svg?label=Linux%20CI&logo=travis&logoColor=white - :target: https://travis-ci.org/pypa/setuptools - -.. image:: https://img.shields.io/appveyor/ci/pypa/setuptools/master.svg?label=Windows%20CI&logo=appveyor&logoColor=white - :target: https://ci.appveyor.com/project/pypa/setuptools/branch/master - -.. image:: https://img.shields.io/codecov/c/github/pypa/setuptools/master.svg?logo=codecov&logoColor=white - :target: https://codecov.io/gh/pypa/setuptools - -.. image:: https://tidelift.com/badges/github/pypa/setuptools?style=flat - :target: https://tidelift.com/subscription/pkg/pypi-setuptools?utm_source=pypi-setuptools&utm_medium=readme - -.. image:: https://img.shields.io/pypi/pyversions/setuptools.svg - -See the `Installation Instructions -<https://packaging.python.org/installing/>`_ in the Python Packaging -User's Guide for instructions on installing, upgrading, and uninstalling -Setuptools. - -Questions and comments should be directed to the `distutils-sig -mailing list <http://mail.python.org/pipermail/distutils-sig/>`_. -Bug reports and especially tested patches may be -submitted directly to the `bug tracker -<https://github.com/pypa/setuptools/issues>`_. - -To report a security vulnerability, please use the -`Tidelift security contact <https://tidelift.com/security>`_. -Tidelift will coordinate the fix and disclosure. - - -For Enterprise -============== - -Available as part of the Tidelift Subscription. - -Setuptools and the maintainers of thousands of other packages are working with Tidelift to deliver one enterprise subscription that covers all of the open source you use. - -`Learn more <https://tidelift.com/subscription/pkg/pypi-setuptools?utm_source=pypi-setuptools&utm_medium=referral&utm_campaign=github>`_. - -Code of Conduct -=============== - -Everyone interacting in the setuptools project's codebases, issue trackers, -chat rooms, and mailing lists is expected to follow the -`PyPA Code of Conduct <https://www.pypa.io/en/latest/code-of-conduct/>`_. - - diff --git a/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/RECORD b/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/RECORD deleted file mode 100644 index a6481a6..0000000 --- a/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/RECORD +++ /dev/null @@ -1,163 +0,0 @@ -../../../bin/easy_install,sha256=puwYb_NPnvgDcyg3O3bcAxp2mlT87hLdEghB1kCJCJ8,265 -../../../bin/easy_install-3.8,sha256=puwYb_NPnvgDcyg3O3bcAxp2mlT87hLdEghB1kCJCJ8,265 -__pycache__/easy_install.cpython-38.pyc,, -easy_install.py,sha256=MDC9vt5AxDsXX5qcKlBz2TnW6Tpuv_AobnfhCJ9X3PM,126 -setuptools-44.0.0.dist-info/AUTHORS.txt,sha256=RnTFYKrTgbpfWnZMizLRq0u31iGDJMbs-iqvafo1CcA,7734 -setuptools-44.0.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -setuptools-44.0.0.dist-info/LICENSE.txt,sha256=W6Ifuwlk-TatfRU2LR7W1JMcyMj5_y1NkRkOEJvnRDE,1090 -setuptools-44.0.0.dist-info/METADATA,sha256=L93fcafgVw4xoJUNG0lehyy0prVj-jU_JFxRh0ZUtos,3523 -setuptools-44.0.0.dist-info/RECORD,, -setuptools-44.0.0.dist-info/WHEEL,sha256=kGT74LWyRUZrL4VgLh6_g12IeVl_9u9ZVhadrgXZUEY,110 -setuptools-44.0.0.dist-info/dependency_links.txt,sha256=HlkCFkoK5TbZ5EMLbLKYhLcY_E31kBWD8TqW2EgmatQ,239 -setuptools-44.0.0.dist-info/entry_points.txt,sha256=ZmIqlp-SBdsBS2cuetmU2NdSOs4DG0kxctUR9UJ8Xk0,3150 -setuptools-44.0.0.dist-info/top_level.txt,sha256=2HUXVVwA4Pff1xgTFr3GsTXXKaPaO6vlG6oNJ_4u4Tg,38 -setuptools-44.0.0.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1 -setuptools/__init__.py,sha256=WBpCcn2lvdckotabeae1TTYonPOcgCIF3raD2zRWzBc,7283 -setuptools/__pycache__/__init__.cpython-38.pyc,, -setuptools/__pycache__/_deprecation_warning.cpython-38.pyc,, -setuptools/__pycache__/_imp.cpython-38.pyc,, -setuptools/__pycache__/archive_util.cpython-38.pyc,, -setuptools/__pycache__/build_meta.cpython-38.pyc,, -setuptools/__pycache__/config.cpython-38.pyc,, -setuptools/__pycache__/dep_util.cpython-38.pyc,, -setuptools/__pycache__/depends.cpython-38.pyc,, -setuptools/__pycache__/dist.cpython-38.pyc,, -setuptools/__pycache__/errors.cpython-38.pyc,, -setuptools/__pycache__/extension.cpython-38.pyc,, -setuptools/__pycache__/glob.cpython-38.pyc,, -setuptools/__pycache__/installer.cpython-38.pyc,, -setuptools/__pycache__/launch.cpython-38.pyc,, -setuptools/__pycache__/lib2to3_ex.cpython-38.pyc,, -setuptools/__pycache__/monkey.cpython-38.pyc,, -setuptools/__pycache__/msvc.cpython-38.pyc,, -setuptools/__pycache__/namespaces.cpython-38.pyc,, -setuptools/__pycache__/package_index.cpython-38.pyc,, -setuptools/__pycache__/py27compat.cpython-38.pyc,, -setuptools/__pycache__/py31compat.cpython-38.pyc,, -setuptools/__pycache__/py33compat.cpython-38.pyc,, -setuptools/__pycache__/py34compat.cpython-38.pyc,, -setuptools/__pycache__/sandbox.cpython-38.pyc,, -setuptools/__pycache__/site-patch.cpython-38.pyc,, -setuptools/__pycache__/ssl_support.cpython-38.pyc,, -setuptools/__pycache__/unicode_utils.cpython-38.pyc,, -setuptools/__pycache__/version.cpython-38.pyc,, -setuptools/__pycache__/wheel.cpython-38.pyc,, -setuptools/__pycache__/windows_support.cpython-38.pyc,, -setuptools/_deprecation_warning.py,sha256=jU9-dtfv6cKmtQJOXN8nP1mm7gONw5kKEtiPtbwnZyI,218 -setuptools/_imp.py,sha256=jloslOkxrTKbobgemfP94YII0nhqiJzE1bRmCTZ1a5I,2223 -setuptools/_vendor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -setuptools/_vendor/__pycache__/__init__.cpython-38.pyc,, -setuptools/_vendor/__pycache__/ordered_set.cpython-38.pyc,, -setuptools/_vendor/__pycache__/pyparsing.cpython-38.pyc,, -setuptools/_vendor/__pycache__/six.cpython-38.pyc,, -setuptools/_vendor/ordered_set.py,sha256=dbaCcs27dyN9gnMWGF5nA_BrVn6Q-NrjKYJpV9_fgBs,15130 -setuptools/_vendor/packaging/__about__.py,sha256=CpuMSyh1V7adw8QMjWKkY3LtdqRUkRX4MgJ6nF4stM0,744 -setuptools/_vendor/packaging/__init__.py,sha256=6enbp5XgRfjBjsI9-bn00HjHf5TH21PDMOKkJW8xw-w,562 -setuptools/_vendor/packaging/__pycache__/__about__.cpython-38.pyc,, -setuptools/_vendor/packaging/__pycache__/__init__.cpython-38.pyc,, -setuptools/_vendor/packaging/__pycache__/_compat.cpython-38.pyc,, -setuptools/_vendor/packaging/__pycache__/_structures.cpython-38.pyc,, -setuptools/_vendor/packaging/__pycache__/markers.cpython-38.pyc,, -setuptools/_vendor/packaging/__pycache__/requirements.cpython-38.pyc,, -setuptools/_vendor/packaging/__pycache__/specifiers.cpython-38.pyc,, -setuptools/_vendor/packaging/__pycache__/tags.cpython-38.pyc,, -setuptools/_vendor/packaging/__pycache__/utils.cpython-38.pyc,, -setuptools/_vendor/packaging/__pycache__/version.cpython-38.pyc,, -setuptools/_vendor/packaging/_compat.py,sha256=Ugdm-qcneSchW25JrtMIKgUxfEEBcCAz6WrEeXeqz9o,865 -setuptools/_vendor/packaging/_structures.py,sha256=pVd90XcXRGwpZRB_qdFuVEibhCHpX_bL5zYr9-N0mc8,1416 -setuptools/_vendor/packaging/markers.py,sha256=-meFl9Fr9V8rF5Rduzgett5EHK9wBYRUqssAV2pj0lw,8268 -setuptools/_vendor/packaging/requirements.py,sha256=3dwIJekt8RRGCUbgxX8reeAbgmZYjb0wcCRtmH63kxI,4742 -setuptools/_vendor/packaging/specifiers.py,sha256=0ZzQpcUnvrQ6LjR-mQRLzMr8G6hdRv-mY0VSf_amFtI,27778 -setuptools/_vendor/packaging/tags.py,sha256=EPLXhO6GTD7_oiWEO1U0l0PkfR8R_xivpMDHXnsTlts,12933 -setuptools/_vendor/packaging/utils.py,sha256=VaTC0Ei7zO2xl9ARiWmz2YFLFt89PuuhLbAlXMyAGms,1520 -setuptools/_vendor/packaging/version.py,sha256=Npdwnb8OHedj_2L86yiUqscujb7w_i5gmSK1PhOAFzg,11978 -setuptools/_vendor/pyparsing.py,sha256=tmrp-lu-qO1i75ZzIN5A12nKRRD1Cm4Vpk-5LR9rims,232055 -setuptools/_vendor/six.py,sha256=A6hdJZVjI3t_geebZ9BzUvwRrIXo0lfwzQlM2LcKyas,30098 -setuptools/archive_util.py,sha256=kw8Ib_lKjCcnPKNbS7h8HztRVK0d5RacU3r_KRdVnmM,6592 -setuptools/build_meta.py,sha256=-9Nmj9YdbW4zX3TssPJZhsENrTa4fw3k86Jm1cdKMik,9597 -setuptools/cli-32.exe,sha256=dfEuovMNnA2HLa3jRfMPVi5tk4R7alCbpTvuxtCyw0Y,65536 -setuptools/cli-64.exe,sha256=KLABu5pyrnokJCv6skjXZ6GsXeyYHGcqOUT3oHI3Xpo,74752 -setuptools/cli.exe,sha256=dfEuovMNnA2HLa3jRfMPVi5tk4R7alCbpTvuxtCyw0Y,65536 -setuptools/command/__init__.py,sha256=QCAuA9whnq8Bnoc0bBaS6Lw_KAUO0DiHYZQXEMNn5hg,568 -setuptools/command/__pycache__/__init__.cpython-38.pyc,, -setuptools/command/__pycache__/alias.cpython-38.pyc,, -setuptools/command/__pycache__/bdist_egg.cpython-38.pyc,, -setuptools/command/__pycache__/bdist_rpm.cpython-38.pyc,, -setuptools/command/__pycache__/bdist_wininst.cpython-38.pyc,, -setuptools/command/__pycache__/build_clib.cpython-38.pyc,, -setuptools/command/__pycache__/build_ext.cpython-38.pyc,, -setuptools/command/__pycache__/build_py.cpython-38.pyc,, -setuptools/command/__pycache__/develop.cpython-38.pyc,, -setuptools/command/__pycache__/dist_info.cpython-38.pyc,, -setuptools/command/__pycache__/easy_install.cpython-38.pyc,, -setuptools/command/__pycache__/egg_info.cpython-38.pyc,, -setuptools/command/__pycache__/install.cpython-38.pyc,, -setuptools/command/__pycache__/install_egg_info.cpython-38.pyc,, -setuptools/command/__pycache__/install_lib.cpython-38.pyc,, -setuptools/command/__pycache__/install_scripts.cpython-38.pyc,, -setuptools/command/__pycache__/py36compat.cpython-38.pyc,, -setuptools/command/__pycache__/register.cpython-38.pyc,, -setuptools/command/__pycache__/rotate.cpython-38.pyc,, -setuptools/command/__pycache__/saveopts.cpython-38.pyc,, -setuptools/command/__pycache__/sdist.cpython-38.pyc,, -setuptools/command/__pycache__/setopt.cpython-38.pyc,, -setuptools/command/__pycache__/test.cpython-38.pyc,, -setuptools/command/__pycache__/upload.cpython-38.pyc,, -setuptools/command/__pycache__/upload_docs.cpython-38.pyc,, -setuptools/command/alias.py,sha256=KjpE0sz_SDIHv3fpZcIQK-sCkJz-SrC6Gmug6b9Nkc8,2426 -setuptools/command/bdist_egg.py,sha256=nnfV8Ah8IRC_Ifv5Loa9FdxL66MVbyDXwy-foP810zM,18185 -setuptools/command/bdist_rpm.py,sha256=B7l0TnzCGb-0nLlm6rS00jWLkojASwVmdhW2w5Qz_Ak,1508 -setuptools/command/bdist_wininst.py,sha256=_6dz3lpB1tY200LxKPLM7qgwTCceOMgaWFF-jW2-pm0,637 -setuptools/command/build_clib.py,sha256=bQ9aBr-5ZSO-9fGsGsDLz0mnnFteHUZnftVLkhvHDq0,4484 -setuptools/command/build_ext.py,sha256=Ib42YUGksBswm2mL5xmQPF6NeTA6HcqrvAtEgFCv32A,13019 -setuptools/command/build_py.py,sha256=yWyYaaS9F3o9JbIczn064A5g1C5_UiKRDxGaTqYbtLE,9596 -setuptools/command/develop.py,sha256=MQlnGS6uP19erK2JCNOyQYoYyquk3PADrqrrinqqLtA,8184 -setuptools/command/dist_info.py,sha256=5t6kOfrdgALT-P3ogss6PF9k-Leyesueycuk3dUyZnI,960 -setuptools/command/easy_install.py,sha256=0lY8Agxe-7IgMtxgxFuOY1NrDlBzOUlpCKsvayXlTYY,89903 -setuptools/command/egg_info.py,sha256=0e_TXrMfpa8nGTO7GmJcmpPCMWzliZi6zt9aMchlumc,25578 -setuptools/command/install.py,sha256=8doMxeQEDoK4Eco0mO2WlXXzzp9QnsGJQ7Z7yWkZPG8,4705 -setuptools/command/install_egg_info.py,sha256=4zq_Ad3jE-EffParuyDEnvxU6efB-Xhrzdr8aB6Ln_8,3195 -setuptools/command/install_lib.py,sha256=9zdc-H5h6RPxjySRhOwi30E_WfcVva7gpfhZ5ata60w,5023 -setuptools/command/install_scripts.py,sha256=UD0rEZ6861mTYhIdzcsqKnUl8PozocXWl9VBQ1VTWnc,2439 -setuptools/command/launcher manifest.xml,sha256=xlLbjWrB01tKC0-hlVkOKkiSPbzMml2eOPtJ_ucCnbE,628 -setuptools/command/py36compat.py,sha256=SzjZcOxF7zdFUT47Zv2n7AM3H8koDys_0OpS-n9gIfc,4986 -setuptools/command/register.py,sha256=kk3DxXCb5lXTvqnhfwx2g6q7iwbUmgTyXUCaBooBOUk,468 -setuptools/command/rotate.py,sha256=co5C1EkI7P0GGT6Tqz-T2SIj2LBJTZXYELpmao6d4KQ,2164 -setuptools/command/saveopts.py,sha256=za7QCBcQimKKriWcoCcbhxPjUz30gSB74zuTL47xpP4,658 -setuptools/command/sdist.py,sha256=IL1LepD2h8qGKOFJ3rrQVbjNH_Q6ViD40l0QADr4MEU,8088 -setuptools/command/setopt.py,sha256=NTWDyx-gjDF-txf4dO577s7LOzHVoKR0Mq33rFxaRr8,5085 -setuptools/command/test.py,sha256=u2kXngIIdSYqtvwFlHiN6Iye1IB4TU6uadB2uiV1szw,9602 -setuptools/command/upload.py,sha256=XT3YFVfYPAmA5qhGg0euluU98ftxRUW-PzKcODMLxUs,462 -setuptools/command/upload_docs.py,sha256=oXiGplM_cUKLwE4CWWw98RzCufAu8tBhMC97GegFcms,7311 -setuptools/config.py,sha256=6SB2OY3qcooOJmG_rsK_s0pKBsorBlDpfMJUyzjQIGk,20575 -setuptools/dep_util.py,sha256=fgixvC1R7sH3r13ktyf7N0FALoqEXL1cBarmNpSEoWg,935 -setuptools/depends.py,sha256=qt2RWllArRvhnm8lxsyRpcthEZYp4GHQgREl1q0LkFw,5517 -setuptools/dist.py,sha256=xtXaNsOsE32MwwQqErzgXJF7jsTQz9GYFRrwnPFQ0J0,49865 -setuptools/errors.py,sha256=MVOcv381HNSajDgEUWzOQ4J6B5BHCBMSjHfaWcEwA1o,524 -setuptools/extension.py,sha256=uc6nHI-MxwmNCNPbUiBnybSyqhpJqjbhvOQ-emdvt_E,1729 -setuptools/extern/__init__.py,sha256=4q9gtShB1XFP6CisltsyPqtcfTO6ZM9Lu1QBl3l-qmo,2514 -setuptools/extern/__pycache__/__init__.cpython-38.pyc,, -setuptools/glob.py,sha256=o75cHrOxYsvn854thSxE0x9k8JrKDuhP_rRXlVB00Q4,5084 -setuptools/gui-32.exe,sha256=XBr0bHMA6Hpz2s9s9Bzjl-PwXfa9nH4ie0rFn4V2kWA,65536 -setuptools/gui-64.exe,sha256=aYKMhX1IJLn4ULHgWX0sE0yREUt6B3TEHf_jOw6yNyE,75264 -setuptools/gui.exe,sha256=XBr0bHMA6Hpz2s9s9Bzjl-PwXfa9nH4ie0rFn4V2kWA,65536 -setuptools/installer.py,sha256=TCFRonRo01I79zo-ucf3Ymhj8TenPlmhMijN916aaJs,5337 -setuptools/launch.py,sha256=sd7ejwhBocCDx_wG9rIs0OaZ8HtmmFU8ZC6IR_S0Lvg,787 -setuptools/lib2to3_ex.py,sha256=t5e12hbR2pi9V4ezWDTB4JM-AISUnGOkmcnYHek3xjg,2013 -setuptools/monkey.py,sha256=FGc9fffh7gAxMLFmJs2DW_OYWpBjkdbNS2n14UAK4NA,5264 -setuptools/msvc.py,sha256=8baJ6aYgCA4TRdWQQi185qB9dnU8FaP4wgpbmd7VODs,46751 -setuptools/namespaces.py,sha256=F0Nrbv8KCT2OrO7rwa03om4N4GZKAlnce-rr-cgDQa8,3199 -setuptools/package_index.py,sha256=6pb-B1POtHyLycAbkDETk4fO-Qv8_sY-rjTXhUOoh6k,40605 -setuptools/py27compat.py,sha256=tvmer0Tn-wk_JummCkoM22UIjpjL-AQ8uUiOaqTs8sI,1496 -setuptools/py31compat.py,sha256=h2rtZghOfwoGYd8sQ0-auaKiF3TcL3qX0bX3VessqcE,838 -setuptools/py33compat.py,sha256=SMF9Z8wnGicTOkU1uRNwZ_kz5Z_bj29PUBbqdqeeNsc,1330 -setuptools/py34compat.py,sha256=KYOd6ybRxjBW8NJmYD8t_UyyVmysppFXqHpFLdslGXU,245 -setuptools/sandbox.py,sha256=9UbwfEL5QY436oMI1LtFWohhoZ-UzwHvGyZjUH_qhkw,14276 -setuptools/script (dev).tmpl,sha256=RUzQzCQUaXtwdLtYHWYbIQmOaES5Brqq1FvUA_tu-5I,218 -setuptools/script.tmpl,sha256=WGTt5piezO27c-Dbx6l5Q4T3Ff20A5z7872hv3aAhYY,138 -setuptools/site-patch.py,sha256=OumkIHMuoSenRSW1382kKWI1VAwxNE86E5W8iDd34FY,2302 -setuptools/ssl_support.py,sha256=nLjPUBBw7RTTx6O4RJZ5eAMGgjJG8beiDbkFXDZpLuM,8493 -setuptools/unicode_utils.py,sha256=NOiZ_5hD72A6w-4wVj8awHFM3n51Kmw1Ic_vx15XFqw,996 -setuptools/version.py,sha256=og_cuZQb0QI6ukKZFfZWPlr1HgJBPPn2vO2m_bI9ZTE,144 -setuptools/wheel.py,sha256=zct-SEj5_LoHg6XELt2cVRdulsUENenCdS1ekM7TlZA,8455 -setuptools/windows_support.py,sha256=5GrfqSP2-dLGJoZTq2g6dCKkyQxxa2n5IQiXlJCoYEE,714 diff --git a/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/WHEEL b/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/WHEEL deleted file mode 100644 index ef99c6c..0000000 --- a/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/WHEEL +++ /dev/null @@ -1,6 +0,0 @@ -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/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/dependency_links.txt b/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/dependency_links.txt deleted file mode 100644 index e87d021..0000000 --- a/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/dependency_links.txt +++ /dev/null @@ -1,2 +0,0 @@ -https://files.pythonhosted.org/packages/source/c/certifi/certifi-2016.9.26.tar.gz#md5=baa81e951a29958563689d868ef1064d -https://files.pythonhosted.org/packages/source/w/wincertstore/wincertstore-0.2.zip#md5=ae728f2f007185648d0c7a8679b361e2 diff --git a/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/entry_points.txt b/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/entry_points.txt deleted file mode 100644 index 0fed3f1..0000000 --- a/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/entry_points.txt +++ /dev/null @@ -1,68 +0,0 @@ -[console_scripts] -easy_install = setuptools.command.easy_install:main - -[distutils.commands] -alias = setuptools.command.alias:alias -bdist_egg = setuptools.command.bdist_egg:bdist_egg -bdist_rpm = setuptools.command.bdist_rpm:bdist_rpm -bdist_wininst = setuptools.command.bdist_wininst:bdist_wininst -build_clib = setuptools.command.build_clib:build_clib -build_ext = setuptools.command.build_ext:build_ext -build_py = setuptools.command.build_py:build_py -develop = setuptools.command.develop:develop -dist_info = setuptools.command.dist_info:dist_info -easy_install = setuptools.command.easy_install:easy_install -egg_info = setuptools.command.egg_info:egg_info -install = setuptools.command.install:install -install_egg_info = setuptools.command.install_egg_info:install_egg_info -install_lib = setuptools.command.install_lib:install_lib -install_scripts = setuptools.command.install_scripts:install_scripts -rotate = setuptools.command.rotate:rotate -saveopts = setuptools.command.saveopts:saveopts -sdist = setuptools.command.sdist:sdist -setopt = setuptools.command.setopt:setopt -test = setuptools.command.test:test -upload_docs = setuptools.command.upload_docs:upload_docs - -[distutils.setup_keywords] -convert_2to3_doctests = setuptools.dist:assert_string_list -dependency_links = setuptools.dist:assert_string_list -eager_resources = setuptools.dist:assert_string_list -entry_points = setuptools.dist:check_entry_points -exclude_package_data = setuptools.dist:check_package_data -extras_require = setuptools.dist:check_extras -include_package_data = setuptools.dist:assert_bool -install_requires = setuptools.dist:check_requirements -namespace_packages = setuptools.dist:check_nsp -package_data = setuptools.dist:check_package_data -packages = setuptools.dist:check_packages -python_requires = setuptools.dist:check_specifier -setup_requires = setuptools.dist:check_requirements -test_loader = setuptools.dist:check_importable -test_runner = setuptools.dist:check_importable -test_suite = setuptools.dist:check_test_suite -tests_require = setuptools.dist:check_requirements -use_2to3 = setuptools.dist:assert_bool -use_2to3_exclude_fixers = setuptools.dist:assert_string_list -use_2to3_fixers = setuptools.dist:assert_string_list -zip_safe = setuptools.dist:assert_bool - -[egg_info.writers] -PKG-INFO = setuptools.command.egg_info:write_pkg_info -dependency_links.txt = setuptools.command.egg_info:overwrite_arg -depends.txt = setuptools.command.egg_info:warn_depends_obsolete -eager_resources.txt = setuptools.command.egg_info:overwrite_arg -entry_points.txt = setuptools.command.egg_info:write_entries -namespace_packages.txt = setuptools.command.egg_info:overwrite_arg -requires.txt = setuptools.command.egg_info:write_requirements -top_level.txt = setuptools.command.egg_info:write_toplevel_names - -[setuptools.finalize_distribution_options] -2to3_doctests = setuptools.dist:Distribution._finalize_2to3_doctests -features = setuptools.dist:Distribution._finalize_feature_opts -keywords = setuptools.dist:Distribution._finalize_setup_keywords -parent_finalize = setuptools.dist:_Distribution.finalize_options - -[setuptools.installation] -eggsecutable = setuptools.command.easy_install:bootstrap - diff --git a/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/top_level.txt b/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/top_level.txt deleted file mode 100644 index 4577c6a..0000000 --- a/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/top_level.txt +++ /dev/null @@ -1,3 +0,0 @@ -easy_install -pkg_resources -setuptools diff --git a/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/zip-safe b/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/zip-safe deleted file mode 100644 index 8b13789..0000000 --- a/venv/lib/python3.8/site-packages/setuptools-44.0.0.dist-info/zip-safe +++ /dev/null @@ -1 +0,0 @@ - diff --git a/venv/lib/python3.8/site-packages/setuptools/__init__.py b/venv/lib/python3.8/site-packages/setuptools/__init__.py deleted file mode 100644 index a71b2bb..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/__init__.py +++ /dev/null @@ -1,228 +0,0 @@ -"""Extensions to the 'distutils' for large or complex distributions""" - -import os -import sys -import functools -import distutils.core -import distutils.filelist -import re -from distutils.errors import DistutilsOptionError -from distutils.util import convert_path -from fnmatch import fnmatchcase - -from ._deprecation_warning import SetuptoolsDeprecationWarning - -from setuptools.extern.six import PY3, string_types -from setuptools.extern.six.moves import filter, map - -import setuptools.version -from setuptools.extension import Extension -from setuptools.dist import Distribution, Feature -from setuptools.depends import Require -from . import monkey - -__metaclass__ = type - - -__all__ = [ - 'setup', 'Distribution', 'Feature', 'Command', 'Extension', 'Require', - 'SetuptoolsDeprecationWarning', - 'find_packages' -] - -if PY3: - __all__.append('find_namespace_packages') - -__version__ = setuptools.version.__version__ - -bootstrap_install_from = None - -# If we run 2to3 on .py files, should we also convert docstrings? -# Default: yes; assume that we can detect doctests reliably -run_2to3_on_doctests = True -# Standard package names for fixer packages -lib2to3_fixer_packages = ['lib2to3.fixes'] - - -class PackageFinder: - """ - Generate a list of all Python packages found within a directory - """ - - @classmethod - def find(cls, where='.', exclude=(), include=('*',)): - """Return a list all Python packages found within directory 'where' - - 'where' is the root directory which will be searched for packages. It - should be supplied as a "cross-platform" (i.e. URL-style) path; it will - be converted to the appropriate local path syntax. - - 'exclude' is a sequence of package names to exclude; '*' can be used - as a wildcard in the names, such that 'foo.*' will exclude all - subpackages of 'foo' (but not 'foo' itself). - - 'include' is a sequence of package names to include. If it's - specified, only the named packages will be included. If it's not - specified, all found packages will be included. 'include' can contain - shell style wildcard patterns just like 'exclude'. - """ - - return list(cls._find_packages_iter( - convert_path(where), - cls._build_filter('ez_setup', '*__pycache__', *exclude), - cls._build_filter(*include))) - - @classmethod - def _find_packages_iter(cls, where, exclude, include): - """ - All the packages found in 'where' that pass the 'include' filter, but - not the 'exclude' filter. - """ - for root, dirs, files in os.walk(where, followlinks=True): - # Copy dirs to iterate over it, then empty dirs. - all_dirs = dirs[:] - dirs[:] = [] - - for dir in all_dirs: - full_path = os.path.join(root, dir) - rel_path = os.path.relpath(full_path, where) - package = rel_path.replace(os.path.sep, '.') - - # Skip directory trees that are not valid packages - if ('.' in dir or not cls._looks_like_package(full_path)): - continue - - # Should this package be included? - if include(package) and not exclude(package): - yield package - - # Keep searching subdirectories, as there may be more packages - # down there, even if the parent was excluded. - dirs.append(dir) - - @staticmethod - def _looks_like_package(path): - """Does a directory look like a package?""" - return os.path.isfile(os.path.join(path, '__init__.py')) - - @staticmethod - def _build_filter(*patterns): - """ - Given a list of patterns, return a callable that will be true only if - the input matches at least one of the patterns. - """ - return lambda name: any(fnmatchcase(name, pat=pat) for pat in patterns) - - -class PEP420PackageFinder(PackageFinder): - @staticmethod - def _looks_like_package(path): - return True - - -find_packages = PackageFinder.find - -if PY3: - find_namespace_packages = PEP420PackageFinder.find - - -def _install_setup_requires(attrs): - # Note: do not use `setuptools.Distribution` directly, as - # our PEP 517 backend patch `distutils.core.Distribution`. - dist = distutils.core.Distribution(dict( - (k, v) for k, v in attrs.items() - if k in ('dependency_links', 'setup_requires') - )) - # Honor setup.cfg's options. - dist.parse_config_files(ignore_option_errors=True) - if dist.setup_requires: - dist.fetch_build_eggs(dist.setup_requires) - - -def setup(**attrs): - # Make sure we have any requirements needed to interpret 'attrs'. - _install_setup_requires(attrs) - return distutils.core.setup(**attrs) - -setup.__doc__ = distutils.core.setup.__doc__ - - -_Command = monkey.get_unpatched(distutils.core.Command) - - -class Command(_Command): - __doc__ = _Command.__doc__ - - command_consumes_arguments = False - - def __init__(self, dist, **kw): - """ - Construct the command for dist, updating - vars(self) with any keyword parameters. - """ - _Command.__init__(self, dist) - vars(self).update(kw) - - def _ensure_stringlike(self, option, what, default=None): - val = getattr(self, option) - if val is None: - setattr(self, option, default) - return default - elif not isinstance(val, string_types): - raise DistutilsOptionError("'%s' must be a %s (got `%s`)" - % (option, what, val)) - return val - - def ensure_string_list(self, option): - r"""Ensure that 'option' is a list of strings. If 'option' is - currently a string, we split it either on /,\s*/ or /\s+/, so - "foo bar baz", "foo,bar,baz", and "foo, bar baz" all become - ["foo", "bar", "baz"]. - """ - val = getattr(self, option) - if val is None: - return - elif isinstance(val, string_types): - setattr(self, option, re.split(r',\s*|\s+', val)) - else: - if isinstance(val, list): - ok = all(isinstance(v, string_types) for v in val) - else: - ok = False - if not ok: - raise DistutilsOptionError( - "'%s' must be a list of strings (got %r)" - % (option, val)) - - def reinitialize_command(self, command, reinit_subcommands=0, **kw): - cmd = _Command.reinitialize_command(self, command, reinit_subcommands) - vars(cmd).update(kw) - return cmd - - -def _find_all_simple(path): - """ - Find all files under 'path' - """ - results = ( - os.path.join(base, file) - for base, dirs, files in os.walk(path, followlinks=True) - for file in files - ) - return filter(os.path.isfile, results) - - -def findall(dir=os.curdir): - """ - Find all files under 'dir' and return the list of full filenames. - Unless dir is '.', return full filenames with dir prepended. - """ - files = _find_all_simple(dir) - if dir == os.curdir: - make_rel = functools.partial(os.path.relpath, start=dir) - files = map(make_rel, files) - return list(files) - - -# Apply monkey patches -monkey.patch_all() diff --git a/venv/lib/python3.8/site-packages/setuptools/_deprecation_warning.py b/venv/lib/python3.8/site-packages/setuptools/_deprecation_warning.py deleted file mode 100644 index 086b64d..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/_deprecation_warning.py +++ /dev/null @@ -1,7 +0,0 @@ -class SetuptoolsDeprecationWarning(Warning): - """ - Base class for warning deprecations in ``setuptools`` - - This class is not derived from ``DeprecationWarning``, and as such is - visible by default. - """ diff --git a/venv/lib/python3.8/site-packages/setuptools/_imp.py b/venv/lib/python3.8/site-packages/setuptools/_imp.py deleted file mode 100644 index a3cce9b..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/_imp.py +++ /dev/null @@ -1,73 +0,0 @@ -""" -Re-implementation of find_module and get_frozen_object -from the deprecated imp module. -""" - -import os -import importlib.util -import importlib.machinery - -from .py34compat import module_from_spec - - -PY_SOURCE = 1 -PY_COMPILED = 2 -C_EXTENSION = 3 -C_BUILTIN = 6 -PY_FROZEN = 7 - - -def find_module(module, paths=None): - """Just like 'imp.find_module()', but with package support""" - spec = importlib.util.find_spec(module, paths) - if spec is None: - raise ImportError("Can't find %s" % module) - if not spec.has_location and hasattr(spec, 'submodule_search_locations'): - spec = importlib.util.spec_from_loader('__init__.py', spec.loader) - - kind = -1 - file = None - static = isinstance(spec.loader, type) - if spec.origin == 'frozen' or static and issubclass( - spec.loader, importlib.machinery.FrozenImporter): - kind = PY_FROZEN - path = None # imp compabilty - suffix = mode = '' # imp compability - elif spec.origin == 'built-in' or static and issubclass( - spec.loader, importlib.machinery.BuiltinImporter): - kind = C_BUILTIN - path = None # imp compabilty - suffix = mode = '' # imp compability - elif spec.has_location: - path = spec.origin - suffix = os.path.splitext(path)[1] - mode = 'r' if suffix in importlib.machinery.SOURCE_SUFFIXES else 'rb' - - if suffix in importlib.machinery.SOURCE_SUFFIXES: - kind = PY_SOURCE - elif suffix in importlib.machinery.BYTECODE_SUFFIXES: - kind = PY_COMPILED - elif suffix in importlib.machinery.EXTENSION_SUFFIXES: - kind = C_EXTENSION - - if kind in {PY_SOURCE, PY_COMPILED}: - file = open(path, mode) - else: - path = None - suffix = mode = '' - - return file, path, (suffix, mode, kind) - - -def get_frozen_object(module, paths=None): - spec = importlib.util.find_spec(module, paths) - if not spec: - raise ImportError("Can't find %s" % module) - return spec.loader.get_code(module) - - -def get_module(module, paths, info): - spec = importlib.util.find_spec(module, paths) - if not spec: - raise ImportError("Can't find %s" % module) - return module_from_spec(spec) diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/__init__.py b/venv/lib/python3.8/site-packages/setuptools/_vendor/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/ordered_set.py b/venv/lib/python3.8/site-packages/setuptools/_vendor/ordered_set.py deleted file mode 100644 index 1487600..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/_vendor/ordered_set.py +++ /dev/null @@ -1,488 +0,0 @@ -""" -An OrderedSet is a custom MutableSet that remembers its order, so that every -entry has an index that can be looked up. - -Based on a recipe originally posted to ActiveState Recipes by Raymond Hettiger, -and released under the MIT license. -""" -import itertools as it -from collections import deque - -try: - # Python 3 - from collections.abc import MutableSet, Sequence -except ImportError: - # Python 2.7 - from collections import MutableSet, Sequence - -SLICE_ALL = slice(None) -__version__ = "3.1" - - -def is_iterable(obj): - """ - Are we being asked to look up a list of things, instead of a single thing? - We check for the `__iter__` attribute so that this can cover types that - don't have to be known by this module, such as NumPy arrays. - - Strings, however, should be considered as atomic values to look up, not - iterables. The same goes for tuples, since they are immutable and therefore - valid entries. - - We don't need to check for the Python 2 `unicode` type, because it doesn't - have an `__iter__` attribute anyway. - """ - return ( - hasattr(obj, "__iter__") - and not isinstance(obj, str) - and not isinstance(obj, tuple) - ) - - -class OrderedSet(MutableSet, Sequence): - """ - An OrderedSet is a custom MutableSet that remembers its order, so that - every entry has an index that can be looked up. - - Example: - >>> OrderedSet([1, 1, 2, 3, 2]) - OrderedSet([1, 2, 3]) - """ - - def __init__(self, iterable=None): - self.items = [] - self.map = {} - if iterable is not None: - self |= iterable - - def __len__(self): - """ - Returns the number of unique elements in the ordered set - - Example: - >>> len(OrderedSet([])) - 0 - >>> len(OrderedSet([1, 2])) - 2 - """ - return len(self.items) - - def __getitem__(self, index): - """ - Get the item at a given index. - - If `index` is a slice, you will get back that slice of items, as a - new OrderedSet. - - If `index` is a list or a similar iterable, you'll get a list of - items corresponding to those indices. This is similar to NumPy's - "fancy indexing". The result is not an OrderedSet because you may ask - for duplicate indices, and the number of elements returned should be - the number of elements asked for. - - Example: - >>> oset = OrderedSet([1, 2, 3]) - >>> oset[1] - 2 - """ - if isinstance(index, slice) and index == SLICE_ALL: - return self.copy() - elif is_iterable(index): - return [self.items[i] for i in index] - elif hasattr(index, "__index__") or isinstance(index, slice): - result = self.items[index] - if isinstance(result, list): - return self.__class__(result) - else: - return result - else: - raise TypeError("Don't know how to index an OrderedSet by %r" % index) - - def copy(self): - """ - Return a shallow copy of this object. - - Example: - >>> this = OrderedSet([1, 2, 3]) - >>> other = this.copy() - >>> this == other - True - >>> this is other - False - """ - return self.__class__(self) - - def __getstate__(self): - if len(self) == 0: - # The state can't be an empty list. - # We need to return a truthy value, or else __setstate__ won't be run. - # - # This could have been done more gracefully by always putting the state - # in a tuple, but this way is backwards- and forwards- compatible with - # previous versions of OrderedSet. - return (None,) - else: - return list(self) - - def __setstate__(self, state): - if state == (None,): - self.__init__([]) - else: - self.__init__(state) - - def __contains__(self, key): - """ - Test if the item is in this ordered set - - Example: - >>> 1 in OrderedSet([1, 3, 2]) - True - >>> 5 in OrderedSet([1, 3, 2]) - False - """ - return key in self.map - - def add(self, key): - """ - Add `key` as an item to this OrderedSet, then return its index. - - If `key` is already in the OrderedSet, return the index it already - had. - - Example: - >>> oset = OrderedSet() - >>> oset.append(3) - 0 - >>> print(oset) - OrderedSet([3]) - """ - if key not in self.map: - self.map[key] = len(self.items) - self.items.append(key) - return self.map[key] - - append = add - - def update(self, sequence): - """ - Update the set with the given iterable sequence, then return the index - of the last element inserted. - - Example: - >>> oset = OrderedSet([1, 2, 3]) - >>> oset.update([3, 1, 5, 1, 4]) - 4 - >>> print(oset) - OrderedSet([1, 2, 3, 5, 4]) - """ - item_index = None - try: - for item in sequence: - item_index = self.add(item) - except TypeError: - raise ValueError( - "Argument needs to be an iterable, got %s" % type(sequence) - ) - return item_index - - def index(self, key): - """ - Get the index of a given entry, raising an IndexError if it's not - present. - - `key` can be an iterable of entries that is not a string, in which case - this returns a list of indices. - - Example: - >>> oset = OrderedSet([1, 2, 3]) - >>> oset.index(2) - 1 - """ - if is_iterable(key): - return [self.index(subkey) for subkey in key] - return self.map[key] - - # Provide some compatibility with pd.Index - get_loc = index - get_indexer = index - - def pop(self): - """ - Remove and return the last element from the set. - - Raises KeyError if the set is empty. - - Example: - >>> oset = OrderedSet([1, 2, 3]) - >>> oset.pop() - 3 - """ - if not self.items: - raise KeyError("Set is empty") - - elem = self.items[-1] - del self.items[-1] - del self.map[elem] - return elem - - def discard(self, key): - """ - Remove an element. Do not raise an exception if absent. - - The MutableSet mixin uses this to implement the .remove() method, which - *does* raise an error when asked to remove a non-existent item. - - Example: - >>> oset = OrderedSet([1, 2, 3]) - >>> oset.discard(2) - >>> print(oset) - OrderedSet([1, 3]) - >>> oset.discard(2) - >>> print(oset) - OrderedSet([1, 3]) - """ - if key in self: - i = self.map[key] - del self.items[i] - del self.map[key] - for k, v in self.map.items(): - if v >= i: - self.map[k] = v - 1 - - def clear(self): - """ - Remove all items from this OrderedSet. - """ - del self.items[:] - self.map.clear() - - def __iter__(self): - """ - Example: - >>> list(iter(OrderedSet([1, 2, 3]))) - [1, 2, 3] - """ - return iter(self.items) - - def __reversed__(self): - """ - Example: - >>> list(reversed(OrderedSet([1, 2, 3]))) - [3, 2, 1] - """ - return reversed(self.items) - - def __repr__(self): - if not self: - return "%s()" % (self.__class__.__name__,) - return "%s(%r)" % (self.__class__.__name__, list(self)) - - def __eq__(self, other): - """ - Returns true if the containers have the same items. If `other` is a - Sequence, then order is checked, otherwise it is ignored. - - Example: - >>> oset = OrderedSet([1, 3, 2]) - >>> oset == [1, 3, 2] - True - >>> oset == [1, 2, 3] - False - >>> oset == [2, 3] - False - >>> oset == OrderedSet([3, 2, 1]) - False - """ - # In Python 2 deque is not a Sequence, so treat it as one for - # consistent behavior with Python 3. - if isinstance(other, (Sequence, deque)): - # Check that this OrderedSet contains the same elements, in the - # same order, as the other object. - return list(self) == list(other) - try: - other_as_set = set(other) - except TypeError: - # If `other` can't be converted into a set, it's not equal. - return False - else: - return set(self) == other_as_set - - def union(self, *sets): - """ - Combines all unique items. - Each items order is defined by its first appearance. - - Example: - >>> oset = OrderedSet.union(OrderedSet([3, 1, 4, 1, 5]), [1, 3], [2, 0]) - >>> print(oset) - OrderedSet([3, 1, 4, 5, 2, 0]) - >>> oset.union([8, 9]) - OrderedSet([3, 1, 4, 5, 2, 0, 8, 9]) - >>> oset | {10} - OrderedSet([3, 1, 4, 5, 2, 0, 10]) - """ - cls = self.__class__ if isinstance(self, OrderedSet) else OrderedSet - containers = map(list, it.chain([self], sets)) - items = it.chain.from_iterable(containers) - return cls(items) - - def __and__(self, other): - # the parent implementation of this is backwards - return self.intersection(other) - - def intersection(self, *sets): - """ - Returns elements in common between all sets. Order is defined only - by the first set. - - Example: - >>> oset = OrderedSet.intersection(OrderedSet([0, 1, 2, 3]), [1, 2, 3]) - >>> print(oset) - OrderedSet([1, 2, 3]) - >>> oset.intersection([2, 4, 5], [1, 2, 3, 4]) - OrderedSet([2]) - >>> oset.intersection() - OrderedSet([1, 2, 3]) - """ - cls = self.__class__ if isinstance(self, OrderedSet) else OrderedSet - if sets: - common = set.intersection(*map(set, sets)) - items = (item for item in self if item in common) - else: - items = self - return cls(items) - - def difference(self, *sets): - """ - Returns all elements that are in this set but not the others. - - Example: - >>> OrderedSet([1, 2, 3]).difference(OrderedSet([2])) - OrderedSet([1, 3]) - >>> OrderedSet([1, 2, 3]).difference(OrderedSet([2]), OrderedSet([3])) - OrderedSet([1]) - >>> OrderedSet([1, 2, 3]) - OrderedSet([2]) - OrderedSet([1, 3]) - >>> OrderedSet([1, 2, 3]).difference() - OrderedSet([1, 2, 3]) - """ - cls = self.__class__ - if sets: - other = set.union(*map(set, sets)) - items = (item for item in self if item not in other) - else: - items = self - return cls(items) - - def issubset(self, other): - """ - Report whether another set contains this set. - - Example: - >>> OrderedSet([1, 2, 3]).issubset({1, 2}) - False - >>> OrderedSet([1, 2, 3]).issubset({1, 2, 3, 4}) - True - >>> OrderedSet([1, 2, 3]).issubset({1, 4, 3, 5}) - False - """ - if len(self) > len(other): # Fast check for obvious cases - return False - return all(item in other for item in self) - - def issuperset(self, other): - """ - Report whether this set contains another set. - - Example: - >>> OrderedSet([1, 2]).issuperset([1, 2, 3]) - False - >>> OrderedSet([1, 2, 3, 4]).issuperset({1, 2, 3}) - True - >>> OrderedSet([1, 4, 3, 5]).issuperset({1, 2, 3}) - False - """ - if len(self) < len(other): # Fast check for obvious cases - return False - return all(item in self for item in other) - - def symmetric_difference(self, other): - """ - Return the symmetric difference of two OrderedSets as a new set. - That is, the new set will contain all elements that are in exactly - one of the sets. - - Their order will be preserved, with elements from `self` preceding - elements from `other`. - - Example: - >>> this = OrderedSet([1, 4, 3, 5, 7]) - >>> other = OrderedSet([9, 7, 1, 3, 2]) - >>> this.symmetric_difference(other) - OrderedSet([4, 5, 9, 2]) - """ - cls = self.__class__ if isinstance(self, OrderedSet) else OrderedSet - diff1 = cls(self).difference(other) - diff2 = cls(other).difference(self) - return diff1.union(diff2) - - def _update_items(self, items): - """ - Replace the 'items' list of this OrderedSet with a new one, updating - self.map accordingly. - """ - self.items = items - self.map = {item: idx for (idx, item) in enumerate(items)} - - def difference_update(self, *sets): - """ - Update this OrderedSet to remove items from one or more other sets. - - Example: - >>> this = OrderedSet([1, 2, 3]) - >>> this.difference_update(OrderedSet([2, 4])) - >>> print(this) - OrderedSet([1, 3]) - - >>> this = OrderedSet([1, 2, 3, 4, 5]) - >>> this.difference_update(OrderedSet([2, 4]), OrderedSet([1, 4, 6])) - >>> print(this) - OrderedSet([3, 5]) - """ - items_to_remove = set() - for other in sets: - items_to_remove |= set(other) - self._update_items([item for item in self.items if item not in items_to_remove]) - - def intersection_update(self, other): - """ - Update this OrderedSet to keep only items in another set, preserving - their order in this set. - - Example: - >>> this = OrderedSet([1, 4, 3, 5, 7]) - >>> other = OrderedSet([9, 7, 1, 3, 2]) - >>> this.intersection_update(other) - >>> print(this) - OrderedSet([1, 3, 7]) - """ - other = set(other) - self._update_items([item for item in self.items if item in other]) - - def symmetric_difference_update(self, other): - """ - Update this OrderedSet to remove items from another set, then - add items from the other set that were not present in this set. - - Example: - >>> this = OrderedSet([1, 4, 3, 5, 7]) - >>> other = OrderedSet([9, 7, 1, 3, 2]) - >>> this.symmetric_difference_update(other) - >>> print(this) - OrderedSet([4, 5, 9, 2]) - """ - items_to_add = [item for item in other if item not in self] - items_to_remove = set(other) - self._update_items( - [item for item in self.items if item not in items_to_remove] + items_to_add - ) diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__about__.py b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__about__.py deleted file mode 100644 index dc95138..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__about__.py +++ /dev/null @@ -1,27 +0,0 @@ -# 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 __future__ import absolute_import, division, print_function - -__all__ = [ - "__title__", - "__summary__", - "__uri__", - "__version__", - "__author__", - "__email__", - "__license__", - "__copyright__", -] - -__title__ = "packaging" -__summary__ = "Core utilities for Python packages" -__uri__ = "https://github.com/pypa/packaging" - -__version__ = "19.2" - -__author__ = "Donald Stufft and individual contributors" -__email__ = "donald@stufft.io" - -__license__ = "BSD or Apache License, Version 2.0" -__copyright__ = "Copyright 2014-2019 %s" % __author__ diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__init__.py b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__init__.py deleted file mode 100644 index a0cf67d..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -# 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 __future__ import absolute_import, division, print_function - -from .__about__ import ( - __author__, - __copyright__, - __email__, - __license__, - __summary__, - __title__, - __uri__, - __version__, -) - -__all__ = [ - "__title__", - "__summary__", - "__uri__", - "__version__", - "__author__", - "__email__", - "__license__", - "__copyright__", -] diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/_compat.py b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/_compat.py deleted file mode 100644 index 25da473..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/_compat.py +++ /dev/null @@ -1,31 +0,0 @@ -# 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 __future__ import absolute_import, division, print_function - -import sys - - -PY2 = sys.version_info[0] == 2 -PY3 = sys.version_info[0] == 3 - -# flake8: noqa - -if PY3: - string_types = (str,) -else: - string_types = (basestring,) - - -def with_metaclass(meta, *bases): - """ - Create a base class with a metaclass. - """ - # This requires a bit of explanation: the basic idea is to make a dummy - # metaclass for one level of class instantiation that replaces itself with - # the actual metaclass. - class metaclass(meta): - def __new__(cls, name, this_bases, d): - return meta(name, bases, d) - - return type.__new__(metaclass, "temporary_class", (), {}) diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/_structures.py b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/_structures.py deleted file mode 100644 index 68dcca6..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/_structures.py +++ /dev/null @@ -1,68 +0,0 @@ -# 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 __future__ import absolute_import, division, print_function - - -class Infinity(object): - def __repr__(self): - return "Infinity" - - def __hash__(self): - return hash(repr(self)) - - def __lt__(self, other): - return False - - def __le__(self, other): - return False - - def __eq__(self, other): - return isinstance(other, self.__class__) - - def __ne__(self, other): - return not isinstance(other, self.__class__) - - def __gt__(self, other): - return True - - def __ge__(self, other): - return True - - def __neg__(self): - return NegativeInfinity - - -Infinity = Infinity() - - -class NegativeInfinity(object): - def __repr__(self): - return "-Infinity" - - def __hash__(self): - return hash(repr(self)) - - def __lt__(self, other): - return True - - def __le__(self, other): - return True - - def __eq__(self, other): - return isinstance(other, self.__class__) - - def __ne__(self, other): - return not isinstance(other, self.__class__) - - def __gt__(self, other): - return False - - def __ge__(self, other): - return False - - def __neg__(self): - return Infinity - - -NegativeInfinity = NegativeInfinity() diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/markers.py b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/markers.py deleted file mode 100644 index 4bdfdb2..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/markers.py +++ /dev/null @@ -1,296 +0,0 @@ -# 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 __future__ import absolute_import, division, print_function - -import operator -import os -import platform -import sys - -from setuptools.extern.pyparsing import ParseException, ParseResults, stringStart, stringEnd -from setuptools.extern.pyparsing import ZeroOrMore, Group, Forward, QuotedString -from setuptools.extern.pyparsing import Literal as L # noqa - -from ._compat import string_types -from .specifiers import Specifier, InvalidSpecifier - - -__all__ = [ - "InvalidMarker", - "UndefinedComparison", - "UndefinedEnvironmentName", - "Marker", - "default_environment", -] - - -class InvalidMarker(ValueError): - """ - An invalid marker was found, users should refer to PEP 508. - """ - - -class UndefinedComparison(ValueError): - """ - An invalid operation was attempted on a value that doesn't support it. - """ - - -class UndefinedEnvironmentName(ValueError): - """ - A name was attempted to be used that does not exist inside of the - environment. - """ - - -class Node(object): - def __init__(self, value): - self.value = value - - def __str__(self): - return str(self.value) - - def __repr__(self): - return "<{0}({1!r})>".format(self.__class__.__name__, str(self)) - - def serialize(self): - raise NotImplementedError - - -class Variable(Node): - def serialize(self): - return str(self) - - -class Value(Node): - def serialize(self): - return '"{0}"'.format(self) - - -class Op(Node): - def serialize(self): - return str(self) - - -VARIABLE = ( - L("implementation_version") - | L("platform_python_implementation") - | L("implementation_name") - | L("python_full_version") - | L("platform_release") - | L("platform_version") - | L("platform_machine") - | L("platform_system") - | L("python_version") - | L("sys_platform") - | L("os_name") - | L("os.name") - | L("sys.platform") # PEP-345 - | L("platform.version") # PEP-345 - | L("platform.machine") # PEP-345 - | L("platform.python_implementation") # PEP-345 - | L("python_implementation") # PEP-345 - | L("extra") # undocumented setuptools legacy -) -ALIASES = { - "os.name": "os_name", - "sys.platform": "sys_platform", - "platform.version": "platform_version", - "platform.machine": "platform_machine", - "platform.python_implementation": "platform_python_implementation", - "python_implementation": "platform_python_implementation", -} -VARIABLE.setParseAction(lambda s, l, t: Variable(ALIASES.get(t[0], t[0]))) - -VERSION_CMP = ( - L("===") | L("==") | L(">=") | L("<=") | L("!=") | L("~=") | L(">") | L("<") -) - -MARKER_OP = VERSION_CMP | L("not in") | L("in") -MARKER_OP.setParseAction(lambda s, l, t: Op(t[0])) - -MARKER_VALUE = QuotedString("'") | QuotedString('"') -MARKER_VALUE.setParseAction(lambda s, l, t: Value(t[0])) - -BOOLOP = L("and") | L("or") - -MARKER_VAR = VARIABLE | MARKER_VALUE - -MARKER_ITEM = Group(MARKER_VAR + MARKER_OP + MARKER_VAR) -MARKER_ITEM.setParseAction(lambda s, l, t: tuple(t[0])) - -LPAREN = L("(").suppress() -RPAREN = L(")").suppress() - -MARKER_EXPR = Forward() -MARKER_ATOM = MARKER_ITEM | Group(LPAREN + MARKER_EXPR + RPAREN) -MARKER_EXPR << MARKER_ATOM + ZeroOrMore(BOOLOP + MARKER_EXPR) - -MARKER = stringStart + MARKER_EXPR + stringEnd - - -def _coerce_parse_result(results): - if isinstance(results, ParseResults): - return [_coerce_parse_result(i) for i in results] - else: - return results - - -def _format_marker(marker, first=True): - assert isinstance(marker, (list, tuple, string_types)) - - # Sometimes we have a structure like [[...]] which is a single item list - # where the single item is itself it's own list. In that case we want skip - # the rest of this function so that we don't get extraneous () on the - # outside. - if ( - isinstance(marker, list) - and len(marker) == 1 - and isinstance(marker[0], (list, tuple)) - ): - return _format_marker(marker[0]) - - if isinstance(marker, list): - inner = (_format_marker(m, first=False) for m in marker) - if first: - return " ".join(inner) - else: - return "(" + " ".join(inner) + ")" - elif isinstance(marker, tuple): - return " ".join([m.serialize() for m in marker]) - else: - return marker - - -_operators = { - "in": lambda lhs, rhs: lhs in rhs, - "not in": lambda lhs, rhs: lhs not in rhs, - "<": operator.lt, - "<=": operator.le, - "==": operator.eq, - "!=": operator.ne, - ">=": operator.ge, - ">": operator.gt, -} - - -def _eval_op(lhs, op, rhs): - try: - spec = Specifier("".join([op.serialize(), rhs])) - except InvalidSpecifier: - pass - else: - return spec.contains(lhs) - - oper = _operators.get(op.serialize()) - if oper is None: - raise UndefinedComparison( - "Undefined {0!r} on {1!r} and {2!r}.".format(op, lhs, rhs) - ) - - return oper(lhs, rhs) - - -_undefined = object() - - -def _get_env(environment, name): - value = environment.get(name, _undefined) - - if value is _undefined: - raise UndefinedEnvironmentName( - "{0!r} does not exist in evaluation environment.".format(name) - ) - - return value - - -def _evaluate_markers(markers, environment): - groups = [[]] - - for marker in markers: - assert isinstance(marker, (list, tuple, string_types)) - - if isinstance(marker, list): - groups[-1].append(_evaluate_markers(marker, environment)) - elif isinstance(marker, tuple): - lhs, op, rhs = marker - - if isinstance(lhs, Variable): - lhs_value = _get_env(environment, lhs.value) - rhs_value = rhs.value - else: - lhs_value = lhs.value - rhs_value = _get_env(environment, rhs.value) - - groups[-1].append(_eval_op(lhs_value, op, rhs_value)) - else: - assert marker in ["and", "or"] - if marker == "or": - groups.append([]) - - return any(all(item) for item in groups) - - -def format_full_version(info): - version = "{0.major}.{0.minor}.{0.micro}".format(info) - kind = info.releaselevel - if kind != "final": - version += kind[0] + str(info.serial) - return version - - -def default_environment(): - if hasattr(sys, "implementation"): - iver = format_full_version(sys.implementation.version) - implementation_name = sys.implementation.name - else: - iver = "0" - implementation_name = "" - - return { - "implementation_name": implementation_name, - "implementation_version": iver, - "os_name": os.name, - "platform_machine": platform.machine(), - "platform_release": platform.release(), - "platform_system": platform.system(), - "platform_version": platform.version(), - "python_full_version": platform.python_version(), - "platform_python_implementation": platform.python_implementation(), - "python_version": ".".join(platform.python_version_tuple()[:2]), - "sys_platform": sys.platform, - } - - -class Marker(object): - def __init__(self, marker): - try: - self._markers = _coerce_parse_result(MARKER.parseString(marker)) - except ParseException as e: - err_str = "Invalid marker: {0!r}, parse error at {1!r}".format( - marker, marker[e.loc : e.loc + 8] - ) - raise InvalidMarker(err_str) - - def __str__(self): - return _format_marker(self._markers) - - def __repr__(self): - return "<Marker({0!r})>".format(str(self)) - - def evaluate(self, environment=None): - """Evaluate a marker. - - Return the boolean from evaluating the given marker against the - environment. environment is an optional argument to override all or - part of the determined environment. - - The environment is determined from the current Python process. - """ - current_environment = default_environment() - if environment is not None: - current_environment.update(environment) - - return _evaluate_markers(self._markers, current_environment) diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/requirements.py b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/requirements.py deleted file mode 100644 index 8a0c2cb..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/requirements.py +++ /dev/null @@ -1,138 +0,0 @@ -# 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 __future__ import absolute_import, division, print_function - -import string -import re - -from setuptools.extern.pyparsing import stringStart, stringEnd, originalTextFor, ParseException -from setuptools.extern.pyparsing import ZeroOrMore, Word, Optional, Regex, Combine -from setuptools.extern.pyparsing import Literal as L # noqa -from setuptools.extern.six.moves.urllib import parse as urlparse - -from .markers import MARKER_EXPR, Marker -from .specifiers import LegacySpecifier, Specifier, SpecifierSet - - -class InvalidRequirement(ValueError): - """ - An invalid requirement was found, users should refer to PEP 508. - """ - - -ALPHANUM = Word(string.ascii_letters + string.digits) - -LBRACKET = L("[").suppress() -RBRACKET = L("]").suppress() -LPAREN = L("(").suppress() -RPAREN = L(")").suppress() -COMMA = L(",").suppress() -SEMICOLON = L(";").suppress() -AT = L("@").suppress() - -PUNCTUATION = Word("-_.") -IDENTIFIER_END = ALPHANUM | (ZeroOrMore(PUNCTUATION) + ALPHANUM) -IDENTIFIER = Combine(ALPHANUM + ZeroOrMore(IDENTIFIER_END)) - -NAME = IDENTIFIER("name") -EXTRA = IDENTIFIER - -URI = Regex(r"[^ ]+")("url") -URL = AT + URI - -EXTRAS_LIST = EXTRA + ZeroOrMore(COMMA + EXTRA) -EXTRAS = (LBRACKET + Optional(EXTRAS_LIST) + RBRACKET)("extras") - -VERSION_PEP440 = Regex(Specifier._regex_str, re.VERBOSE | re.IGNORECASE) -VERSION_LEGACY = Regex(LegacySpecifier._regex_str, re.VERBOSE | re.IGNORECASE) - -VERSION_ONE = VERSION_PEP440 ^ VERSION_LEGACY -VERSION_MANY = Combine( - VERSION_ONE + ZeroOrMore(COMMA + VERSION_ONE), joinString=",", adjacent=False -)("_raw_spec") -_VERSION_SPEC = Optional(((LPAREN + VERSION_MANY + RPAREN) | VERSION_MANY)) -_VERSION_SPEC.setParseAction(lambda s, l, t: t._raw_spec or "") - -VERSION_SPEC = originalTextFor(_VERSION_SPEC)("specifier") -VERSION_SPEC.setParseAction(lambda s, l, t: t[1]) - -MARKER_EXPR = originalTextFor(MARKER_EXPR())("marker") -MARKER_EXPR.setParseAction( - lambda s, l, t: Marker(s[t._original_start : t._original_end]) -) -MARKER_SEPARATOR = SEMICOLON -MARKER = MARKER_SEPARATOR + MARKER_EXPR - -VERSION_AND_MARKER = VERSION_SPEC + Optional(MARKER) -URL_AND_MARKER = URL + Optional(MARKER) - -NAMED_REQUIREMENT = NAME + Optional(EXTRAS) + (URL_AND_MARKER | VERSION_AND_MARKER) - -REQUIREMENT = stringStart + NAMED_REQUIREMENT + stringEnd -# setuptools.extern.pyparsing isn't thread safe during initialization, so we do it eagerly, see -# issue #104 -REQUIREMENT.parseString("x[]") - - -class Requirement(object): - """Parse a requirement. - - Parse a given requirement string into its parts, such as name, specifier, - URL, and extras. Raises InvalidRequirement on a badly-formed requirement - string. - """ - - # TODO: Can we test whether something is contained within a requirement? - # If so how do we do that? Do we need to test against the _name_ of - # the thing as well as the version? What about the markers? - # TODO: Can we normalize the name and extra name? - - def __init__(self, requirement_string): - try: - req = REQUIREMENT.parseString(requirement_string) - except ParseException as e: - raise InvalidRequirement( - 'Parse error at "{0!r}": {1}'.format( - requirement_string[e.loc : e.loc + 8], e.msg - ) - ) - - self.name = req.name - if req.url: - parsed_url = urlparse.urlparse(req.url) - if parsed_url.scheme == "file": - if urlparse.urlunparse(parsed_url) != req.url: - raise InvalidRequirement("Invalid URL given") - elif not (parsed_url.scheme and parsed_url.netloc) or ( - not parsed_url.scheme and not parsed_url.netloc - ): - raise InvalidRequirement("Invalid URL: {0}".format(req.url)) - self.url = req.url - else: - self.url = None - self.extras = set(req.extras.asList() if req.extras else []) - self.specifier = SpecifierSet(req.specifier) - self.marker = req.marker if req.marker else None - - def __str__(self): - parts = [self.name] - - if self.extras: - parts.append("[{0}]".format(",".join(sorted(self.extras)))) - - if self.specifier: - parts.append(str(self.specifier)) - - if self.url: - parts.append("@ {0}".format(self.url)) - if self.marker: - parts.append(" ") - - if self.marker: - parts.append("; {0}".format(self.marker)) - - return "".join(parts) - - def __repr__(self): - return "<Requirement({0!r})>".format(str(self)) diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/specifiers.py b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/specifiers.py deleted file mode 100644 index 743576a..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/specifiers.py +++ /dev/null @@ -1,749 +0,0 @@ -# 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 __future__ import absolute_import, division, print_function - -import abc -import functools -import itertools -import re - -from ._compat import string_types, with_metaclass -from .version import Version, LegacyVersion, parse - - -class InvalidSpecifier(ValueError): - """ - An invalid specifier was found, users should refer to PEP 440. - """ - - -class BaseSpecifier(with_metaclass(abc.ABCMeta, object)): - @abc.abstractmethod - def __str__(self): - """ - Returns the str representation of this Specifier like object. This - should be representative of the Specifier itself. - """ - - @abc.abstractmethod - def __hash__(self): - """ - Returns a hash value for this Specifier like object. - """ - - @abc.abstractmethod - def __eq__(self, other): - """ - Returns a boolean representing whether or not the two Specifier like - objects are equal. - """ - - @abc.abstractmethod - def __ne__(self, other): - """ - Returns a boolean representing whether or not the two Specifier like - objects are not equal. - """ - - @abc.abstractproperty - def prereleases(self): - """ - Returns whether or not pre-releases as a whole are allowed by this - specifier. - """ - - @prereleases.setter - def prereleases(self, value): - """ - Sets whether or not pre-releases as a whole are allowed by this - specifier. - """ - - @abc.abstractmethod - def contains(self, item, prereleases=None): - """ - Determines if the given item is contained within this specifier. - """ - - @abc.abstractmethod - def filter(self, iterable, prereleases=None): - """ - Takes an iterable of items and filters them so that only items which - are contained within this specifier are allowed in it. - """ - - -class _IndividualSpecifier(BaseSpecifier): - - _operators = {} - - def __init__(self, spec="", prereleases=None): - match = self._regex.search(spec) - if not match: - raise InvalidSpecifier("Invalid specifier: '{0}'".format(spec)) - - self._spec = (match.group("operator").strip(), match.group("version").strip()) - - # Store whether or not this Specifier should accept prereleases - self._prereleases = prereleases - - def __repr__(self): - pre = ( - ", prereleases={0!r}".format(self.prereleases) - if self._prereleases is not None - else "" - ) - - return "<{0}({1!r}{2})>".format(self.__class__.__name__, str(self), pre) - - def __str__(self): - return "{0}{1}".format(*self._spec) - - def __hash__(self): - return hash(self._spec) - - def __eq__(self, other): - if isinstance(other, string_types): - try: - other = self.__class__(other) - except InvalidSpecifier: - return NotImplemented - elif not isinstance(other, self.__class__): - return NotImplemented - - return self._spec == other._spec - - def __ne__(self, other): - if isinstance(other, string_types): - try: - other = self.__class__(other) - except InvalidSpecifier: - return NotImplemented - elif not isinstance(other, self.__class__): - return NotImplemented - - return self._spec != other._spec - - def _get_operator(self, op): - return getattr(self, "_compare_{0}".format(self._operators[op])) - - def _coerce_version(self, version): - if not isinstance(version, (LegacyVersion, Version)): - version = parse(version) - return version - - @property - def operator(self): - return self._spec[0] - - @property - def version(self): - return self._spec[1] - - @property - def prereleases(self): - return self._prereleases - - @prereleases.setter - def prereleases(self, value): - self._prereleases = value - - def __contains__(self, item): - return self.contains(item) - - def contains(self, item, prereleases=None): - # Determine if prereleases are to be allowed or not. - if prereleases is None: - prereleases = self.prereleases - - # Normalize item to a Version or LegacyVersion, this allows us to have - # a shortcut for ``"2.0" in Specifier(">=2") - item = self._coerce_version(item) - - # Determine if we should be supporting prereleases in this specifier - # or not, if we do not support prereleases than we can short circuit - # logic if this version is a prereleases. - if item.is_prerelease and not prereleases: - return False - - # Actually do the comparison to determine if this item is contained - # within this Specifier or not. - return self._get_operator(self.operator)(item, self.version) - - def filter(self, iterable, prereleases=None): - yielded = False - found_prereleases = [] - - kw = {"prereleases": prereleases if prereleases is not None else True} - - # Attempt to iterate over all the values in the iterable and if any of - # them match, yield them. - for version in iterable: - parsed_version = self._coerce_version(version) - - if self.contains(parsed_version, **kw): - # If our version is a prerelease, and we were not set to allow - # prereleases, then we'll store it for later incase nothing - # else matches this specifier. - if parsed_version.is_prerelease and not ( - prereleases or self.prereleases - ): - found_prereleases.append(version) - # Either this is not a prerelease, or we should have been - # accepting prereleases from the beginning. - else: - yielded = True - yield version - - # Now that we've iterated over everything, determine if we've yielded - # any values, and if we have not and we have any prereleases stored up - # then we will go ahead and yield the prereleases. - if not yielded and found_prereleases: - for version in found_prereleases: - yield version - - -class LegacySpecifier(_IndividualSpecifier): - - _regex_str = r""" - (?P<operator>(==|!=|<=|>=|<|>)) - \s* - (?P<version> - [^,;\s)]* # Since this is a "legacy" specifier, and the version - # string can be just about anything, we match everything - # except for whitespace, a semi-colon for marker support, - # a closing paren since versions can be enclosed in - # them, and a comma since it's a version separator. - ) - """ - - _regex = re.compile(r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE) - - _operators = { - "==": "equal", - "!=": "not_equal", - "<=": "less_than_equal", - ">=": "greater_than_equal", - "<": "less_than", - ">": "greater_than", - } - - def _coerce_version(self, version): - if not isinstance(version, LegacyVersion): - version = LegacyVersion(str(version)) - return version - - def _compare_equal(self, prospective, spec): - return prospective == self._coerce_version(spec) - - def _compare_not_equal(self, prospective, spec): - return prospective != self._coerce_version(spec) - - def _compare_less_than_equal(self, prospective, spec): - return prospective <= self._coerce_version(spec) - - def _compare_greater_than_equal(self, prospective, spec): - return prospective >= self._coerce_version(spec) - - def _compare_less_than(self, prospective, spec): - return prospective < self._coerce_version(spec) - - def _compare_greater_than(self, prospective, spec): - return prospective > self._coerce_version(spec) - - -def _require_version_compare(fn): - @functools.wraps(fn) - def wrapped(self, prospective, spec): - if not isinstance(prospective, Version): - return False - return fn(self, prospective, spec) - - return wrapped - - -class Specifier(_IndividualSpecifier): - - _regex_str = r""" - (?P<operator>(~=|==|!=|<=|>=|<|>|===)) - (?P<version> - (?: - # The identity operators allow for an escape hatch that will - # do an exact string match of the version you wish to install. - # This will not be parsed by PEP 440 and we cannot determine - # any semantic meaning from it. This operator is discouraged - # but included entirely as an escape hatch. - (?<====) # Only match for the identity operator - \s* - [^\s]* # We just match everything, except for whitespace - # since we are only testing for strict identity. - ) - | - (?: - # The (non)equality operators allow for wild card and local - # versions to be specified so we have to define these two - # operators separately to enable that. - (?<===|!=) # Only match for equals and not equals - - \s* - v? - (?:[0-9]+!)? # epoch - [0-9]+(?:\.[0-9]+)* # release - (?: # pre release - [-_\.]? - (a|b|c|rc|alpha|beta|pre|preview) - [-_\.]? - [0-9]* - )? - (?: # post release - (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*) - )? - - # You cannot use a wild card and a dev or local version - # together so group them with a | and make them optional. - (?: - (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release - (?:\+[a-z0-9]+(?:[-_\.][a-z0-9]+)*)? # local - | - \.\* # Wild card syntax of .* - )? - ) - | - (?: - # The compatible operator requires at least two digits in the - # release segment. - (?<=~=) # Only match for the compatible operator - - \s* - v? - (?:[0-9]+!)? # epoch - [0-9]+(?:\.[0-9]+)+ # release (We have a + instead of a *) - (?: # pre release - [-_\.]? - (a|b|c|rc|alpha|beta|pre|preview) - [-_\.]? - [0-9]* - )? - (?: # post release - (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*) - )? - (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release - ) - | - (?: - # All other operators only allow a sub set of what the - # (non)equality operators do. Specifically they do not allow - # local versions to be specified nor do they allow the prefix - # matching wild cards. - (?<!==|!=|~=) # We have special cases for these - # operators so we want to make sure they - # don't match here. - - \s* - v? - (?:[0-9]+!)? # epoch - [0-9]+(?:\.[0-9]+)* # release - (?: # pre release - [-_\.]? - (a|b|c|rc|alpha|beta|pre|preview) - [-_\.]? - [0-9]* - )? - (?: # post release - (?:-[0-9]+)|(?:[-_\.]?(post|rev|r)[-_\.]?[0-9]*) - )? - (?:[-_\.]?dev[-_\.]?[0-9]*)? # dev release - ) - ) - """ - - _regex = re.compile(r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE) - - _operators = { - "~=": "compatible", - "==": "equal", - "!=": "not_equal", - "<=": "less_than_equal", - ">=": "greater_than_equal", - "<": "less_than", - ">": "greater_than", - "===": "arbitrary", - } - - @_require_version_compare - def _compare_compatible(self, prospective, spec): - # Compatible releases have an equivalent combination of >= and ==. That - # is that ~=2.2 is equivalent to >=2.2,==2.*. This allows us to - # implement this in terms of the other specifiers instead of - # implementing it ourselves. The only thing we need to do is construct - # the other specifiers. - - # We want everything but the last item in the version, but we want to - # ignore post and dev releases and we want to treat the pre-release as - # it's own separate segment. - prefix = ".".join( - list( - itertools.takewhile( - lambda x: (not x.startswith("post") and not x.startswith("dev")), - _version_split(spec), - ) - )[:-1] - ) - - # Add the prefix notation to the end of our string - prefix += ".*" - - return self._get_operator(">=")(prospective, spec) and self._get_operator("==")( - prospective, prefix - ) - - @_require_version_compare - def _compare_equal(self, prospective, spec): - # We need special logic to handle prefix matching - if spec.endswith(".*"): - # In the case of prefix matching we want to ignore local segment. - prospective = Version(prospective.public) - # Split the spec out by dots, and pretend that there is an implicit - # dot in between a release segment and a pre-release segment. - spec = _version_split(spec[:-2]) # Remove the trailing .* - - # Split the prospective version out by dots, and pretend that there - # is an implicit dot in between a release segment and a pre-release - # segment. - prospective = _version_split(str(prospective)) - - # Shorten the prospective version to be the same length as the spec - # so that we can determine if the specifier is a prefix of the - # prospective version or not. - prospective = prospective[: len(spec)] - - # Pad out our two sides with zeros so that they both equal the same - # length. - spec, prospective = _pad_version(spec, prospective) - else: - # Convert our spec string into a Version - spec = Version(spec) - - # If the specifier does not have a local segment, then we want to - # act as if the prospective version also does not have a local - # segment. - if not spec.local: - prospective = Version(prospective.public) - - return prospective == spec - - @_require_version_compare - def _compare_not_equal(self, prospective, spec): - return not self._compare_equal(prospective, spec) - - @_require_version_compare - def _compare_less_than_equal(self, prospective, spec): - return prospective <= Version(spec) - - @_require_version_compare - def _compare_greater_than_equal(self, prospective, spec): - return prospective >= Version(spec) - - @_require_version_compare - def _compare_less_than(self, prospective, spec): - # Convert our spec to a Version instance, since we'll want to work with - # it as a version. - spec = Version(spec) - - # Check to see if the prospective version is less than the spec - # version. If it's not we can short circuit and just return False now - # instead of doing extra unneeded work. - if not prospective < spec: - return False - - # This special case is here so that, unless the specifier itself - # includes is a pre-release version, that we do not accept pre-release - # versions for the version mentioned in the specifier (e.g. <3.1 should - # not match 3.1.dev0, but should match 3.0.dev0). - if not spec.is_prerelease and prospective.is_prerelease: - if Version(prospective.base_version) == Version(spec.base_version): - return False - - # If we've gotten to here, it means that prospective version is both - # less than the spec version *and* it's not a pre-release of the same - # version in the spec. - return True - - @_require_version_compare - def _compare_greater_than(self, prospective, spec): - # Convert our spec to a Version instance, since we'll want to work with - # it as a version. - spec = Version(spec) - - # Check to see if the prospective version is greater than the spec - # version. If it's not we can short circuit and just return False now - # instead of doing extra unneeded work. - if not prospective > spec: - return False - - # This special case is here so that, unless the specifier itself - # includes is a post-release version, that we do not accept - # post-release versions for the version mentioned in the specifier - # (e.g. >3.1 should not match 3.0.post0, but should match 3.2.post0). - if not spec.is_postrelease and prospective.is_postrelease: - if Version(prospective.base_version) == Version(spec.base_version): - return False - - # Ensure that we do not allow a local version of the version mentioned - # in the specifier, which is technically greater than, to match. - if prospective.local is not None: - if Version(prospective.base_version) == Version(spec.base_version): - return False - - # If we've gotten to here, it means that prospective version is both - # greater than the spec version *and* it's not a pre-release of the - # same version in the spec. - return True - - def _compare_arbitrary(self, prospective, spec): - return str(prospective).lower() == str(spec).lower() - - @property - def prereleases(self): - # If there is an explicit prereleases set for this, then we'll just - # blindly use that. - if self._prereleases is not None: - return self._prereleases - - # Look at all of our specifiers and determine if they are inclusive - # operators, and if they are if they are including an explicit - # prerelease. - operator, version = self._spec - if operator in ["==", ">=", "<=", "~=", "==="]: - # The == specifier can include a trailing .*, if it does we - # want to remove before parsing. - if operator == "==" and version.endswith(".*"): - version = version[:-2] - - # Parse the version, and if it is a pre-release than this - # specifier allows pre-releases. - if parse(version).is_prerelease: - return True - - return False - - @prereleases.setter - def prereleases(self, value): - self._prereleases = value - - -_prefix_regex = re.compile(r"^([0-9]+)((?:a|b|c|rc)[0-9]+)$") - - -def _version_split(version): - result = [] - for item in version.split("."): - match = _prefix_regex.search(item) - if match: - result.extend(match.groups()) - else: - result.append(item) - return result - - -def _pad_version(left, right): - left_split, right_split = [], [] - - # Get the release segment of our versions - left_split.append(list(itertools.takewhile(lambda x: x.isdigit(), left))) - right_split.append(list(itertools.takewhile(lambda x: x.isdigit(), right))) - - # Get the rest of our versions - left_split.append(left[len(left_split[0]) :]) - right_split.append(right[len(right_split[0]) :]) - - # Insert our padding - left_split.insert(1, ["0"] * max(0, len(right_split[0]) - len(left_split[0]))) - right_split.insert(1, ["0"] * max(0, len(left_split[0]) - len(right_split[0]))) - - return (list(itertools.chain(*left_split)), list(itertools.chain(*right_split))) - - -class SpecifierSet(BaseSpecifier): - def __init__(self, specifiers="", prereleases=None): - # Split on , to break each indidivual specifier into it's own item, and - # strip each item to remove leading/trailing whitespace. - specifiers = [s.strip() for s in specifiers.split(",") if s.strip()] - - # Parsed each individual specifier, attempting first to make it a - # Specifier and falling back to a LegacySpecifier. - parsed = set() - for specifier in specifiers: - try: - parsed.add(Specifier(specifier)) - except InvalidSpecifier: - parsed.add(LegacySpecifier(specifier)) - - # Turn our parsed specifiers into a frozen set and save them for later. - self._specs = frozenset(parsed) - - # Store our prereleases value so we can use it later to determine if - # we accept prereleases or not. - self._prereleases = prereleases - - def __repr__(self): - pre = ( - ", prereleases={0!r}".format(self.prereleases) - if self._prereleases is not None - else "" - ) - - return "<SpecifierSet({0!r}{1})>".format(str(self), pre) - - def __str__(self): - return ",".join(sorted(str(s) for s in self._specs)) - - def __hash__(self): - return hash(self._specs) - - def __and__(self, other): - if isinstance(other, string_types): - other = SpecifierSet(other) - elif not isinstance(other, SpecifierSet): - return NotImplemented - - specifier = SpecifierSet() - specifier._specs = frozenset(self._specs | other._specs) - - if self._prereleases is None and other._prereleases is not None: - specifier._prereleases = other._prereleases - elif self._prereleases is not None and other._prereleases is None: - specifier._prereleases = self._prereleases - elif self._prereleases == other._prereleases: - specifier._prereleases = self._prereleases - else: - raise ValueError( - "Cannot combine SpecifierSets with True and False prerelease " - "overrides." - ) - - return specifier - - def __eq__(self, other): - if isinstance(other, string_types): - other = SpecifierSet(other) - elif isinstance(other, _IndividualSpecifier): - other = SpecifierSet(str(other)) - elif not isinstance(other, SpecifierSet): - return NotImplemented - - return self._specs == other._specs - - def __ne__(self, other): - if isinstance(other, string_types): - other = SpecifierSet(other) - elif isinstance(other, _IndividualSpecifier): - other = SpecifierSet(str(other)) - elif not isinstance(other, SpecifierSet): - return NotImplemented - - return self._specs != other._specs - - def __len__(self): - return len(self._specs) - - def __iter__(self): - return iter(self._specs) - - @property - def prereleases(self): - # If we have been given an explicit prerelease modifier, then we'll - # pass that through here. - if self._prereleases is not None: - return self._prereleases - - # If we don't have any specifiers, and we don't have a forced value, - # then we'll just return None since we don't know if this should have - # pre-releases or not. - if not self._specs: - return None - - # Otherwise we'll see if any of the given specifiers accept - # prereleases, if any of them do we'll return True, otherwise False. - return any(s.prereleases for s in self._specs) - - @prereleases.setter - def prereleases(self, value): - self._prereleases = value - - def __contains__(self, item): - return self.contains(item) - - def contains(self, item, prereleases=None): - # Ensure that our item is a Version or LegacyVersion instance. - if not isinstance(item, (LegacyVersion, Version)): - item = parse(item) - - # Determine if we're forcing a prerelease or not, if we're not forcing - # one for this particular filter call, then we'll use whatever the - # SpecifierSet thinks for whether or not we should support prereleases. - if prereleases is None: - prereleases = self.prereleases - - # We can determine if we're going to allow pre-releases by looking to - # see if any of the underlying items supports them. If none of them do - # and this item is a pre-release then we do not allow it and we can - # short circuit that here. - # Note: This means that 1.0.dev1 would not be contained in something - # like >=1.0.devabc however it would be in >=1.0.debabc,>0.0.dev0 - if not prereleases and item.is_prerelease: - return False - - # We simply dispatch to the underlying specs here to make sure that the - # given version is contained within all of them. - # Note: This use of all() here means that an empty set of specifiers - # will always return True, this is an explicit design decision. - return all(s.contains(item, prereleases=prereleases) for s in self._specs) - - def filter(self, iterable, prereleases=None): - # Determine if we're forcing a prerelease or not, if we're not forcing - # one for this particular filter call, then we'll use whatever the - # SpecifierSet thinks for whether or not we should support prereleases. - if prereleases is None: - prereleases = self.prereleases - - # If we have any specifiers, then we want to wrap our iterable in the - # filter method for each one, this will act as a logical AND amongst - # each specifier. - if self._specs: - for spec in self._specs: - iterable = spec.filter(iterable, prereleases=bool(prereleases)) - return iterable - # If we do not have any specifiers, then we need to have a rough filter - # which will filter out any pre-releases, unless there are no final - # releases, and which will filter out LegacyVersion in general. - else: - filtered = [] - found_prereleases = [] - - for item in iterable: - # Ensure that we some kind of Version class for this item. - if not isinstance(item, (LegacyVersion, Version)): - parsed_version = parse(item) - else: - parsed_version = item - - # Filter out any item which is parsed as a LegacyVersion - if isinstance(parsed_version, LegacyVersion): - continue - - # Store any item which is a pre-release for later unless we've - # already found a final version or we are accepting prereleases - if parsed_version.is_prerelease and not prereleases: - if not filtered: - found_prereleases.append(item) - else: - filtered.append(item) - - # If we've found no items except for pre-releases, then we'll go - # ahead and use the pre-releases - if not filtered and found_prereleases and prereleases is None: - return found_prereleases - - return filtered diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/tags.py b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/tags.py deleted file mode 100644 index ec9942f..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/tags.py +++ /dev/null @@ -1,404 +0,0 @@ -# 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 __future__ import absolute_import - -import distutils.util - -try: - from importlib.machinery import EXTENSION_SUFFIXES -except ImportError: # pragma: no cover - import imp - - EXTENSION_SUFFIXES = [x[0] for x in imp.get_suffixes()] - del imp -import platform -import re -import sys -import sysconfig -import warnings - - -INTERPRETER_SHORT_NAMES = { - "python": "py", # Generic. - "cpython": "cp", - "pypy": "pp", - "ironpython": "ip", - "jython": "jy", -} - - -_32_BIT_INTERPRETER = sys.maxsize <= 2 ** 32 - - -class Tag(object): - - __slots__ = ["_interpreter", "_abi", "_platform"] - - def __init__(self, interpreter, abi, platform): - self._interpreter = interpreter.lower() - self._abi = abi.lower() - self._platform = platform.lower() - - @property - def interpreter(self): - return self._interpreter - - @property - def abi(self): - return self._abi - - @property - def platform(self): - return self._platform - - def __eq__(self, other): - return ( - (self.platform == other.platform) - and (self.abi == other.abi) - and (self.interpreter == other.interpreter) - ) - - def __hash__(self): - return hash((self._interpreter, self._abi, self._platform)) - - def __str__(self): - return "{}-{}-{}".format(self._interpreter, self._abi, self._platform) - - def __repr__(self): - return "<{self} @ {self_id}>".format(self=self, self_id=id(self)) - - -def parse_tag(tag): - tags = set() - interpreters, abis, platforms = tag.split("-") - for interpreter in interpreters.split("."): - for abi in abis.split("."): - for platform_ in platforms.split("."): - tags.add(Tag(interpreter, abi, platform_)) - return frozenset(tags) - - -def _normalize_string(string): - return string.replace(".", "_").replace("-", "_") - - -def _cpython_interpreter(py_version): - # TODO: Is using py_version_nodot for interpreter version critical? - return "cp{major}{minor}".format(major=py_version[0], minor=py_version[1]) - - -def _cpython_abis(py_version): - abis = [] - version = "{}{}".format(*py_version[:2]) - debug = pymalloc = ucs4 = "" - with_debug = sysconfig.get_config_var("Py_DEBUG") - has_refcount = hasattr(sys, "gettotalrefcount") - # Windows doesn't set Py_DEBUG, so checking for support of debug-compiled - # extension modules is the best option. - # https://github.com/pypa/pip/issues/3383#issuecomment-173267692 - has_ext = "_d.pyd" in EXTENSION_SUFFIXES - if with_debug or (with_debug is None and (has_refcount or has_ext)): - debug = "d" - if py_version < (3, 8): - with_pymalloc = sysconfig.get_config_var("WITH_PYMALLOC") - if with_pymalloc or with_pymalloc is None: - pymalloc = "m" - if py_version < (3, 3): - unicode_size = sysconfig.get_config_var("Py_UNICODE_SIZE") - if unicode_size == 4 or ( - unicode_size is None and sys.maxunicode == 0x10FFFF - ): - ucs4 = "u" - elif debug: - # Debug builds can also load "normal" extension modules. - # We can also assume no UCS-4 or pymalloc requirement. - abis.append("cp{version}".format(version=version)) - abis.insert( - 0, - "cp{version}{debug}{pymalloc}{ucs4}".format( - version=version, debug=debug, pymalloc=pymalloc, ucs4=ucs4 - ), - ) - return abis - - -def _cpython_tags(py_version, interpreter, abis, platforms): - for abi in abis: - for platform_ in platforms: - yield Tag(interpreter, abi, platform_) - for tag in (Tag(interpreter, "abi3", platform_) for platform_ in platforms): - yield tag - for tag in (Tag(interpreter, "none", platform_) for platform_ in platforms): - yield tag - # PEP 384 was first implemented in Python 3.2. - for minor_version in range(py_version[1] - 1, 1, -1): - for platform_ in platforms: - interpreter = "cp{major}{minor}".format( - major=py_version[0], minor=minor_version - ) - yield Tag(interpreter, "abi3", platform_) - - -def _pypy_interpreter(): - return "pp{py_major}{pypy_major}{pypy_minor}".format( - py_major=sys.version_info[0], - pypy_major=sys.pypy_version_info.major, - pypy_minor=sys.pypy_version_info.minor, - ) - - -def _generic_abi(): - abi = sysconfig.get_config_var("SOABI") - if abi: - return _normalize_string(abi) - else: - return "none" - - -def _pypy_tags(py_version, interpreter, abi, platforms): - for tag in (Tag(interpreter, abi, platform) for platform in platforms): - yield tag - for tag in (Tag(interpreter, "none", platform) for platform in platforms): - yield tag - - -def _generic_tags(interpreter, py_version, abi, platforms): - for tag in (Tag(interpreter, abi, platform) for platform in platforms): - yield tag - if abi != "none": - tags = (Tag(interpreter, "none", platform_) for platform_ in platforms) - for tag in tags: - yield tag - - -def _py_interpreter_range(py_version): - """ - Yield Python versions in descending order. - - After the latest version, the major-only version will be yielded, and then - all following versions up to 'end'. - """ - yield "py{major}{minor}".format(major=py_version[0], minor=py_version[1]) - yield "py{major}".format(major=py_version[0]) - for minor in range(py_version[1] - 1, -1, -1): - yield "py{major}{minor}".format(major=py_version[0], minor=minor) - - -def _independent_tags(interpreter, py_version, platforms): - """ - Return the sequence of tags that are consistent across implementations. - - The tags consist of: - - py*-none-<platform> - - <interpreter>-none-any - - py*-none-any - """ - for version in _py_interpreter_range(py_version): - for platform_ in platforms: - yield Tag(version, "none", platform_) - yield Tag(interpreter, "none", "any") - for version in _py_interpreter_range(py_version): - yield Tag(version, "none", "any") - - -def _mac_arch(arch, is_32bit=_32_BIT_INTERPRETER): - if not is_32bit: - return arch - - if arch.startswith("ppc"): - return "ppc" - - return "i386" - - -def _mac_binary_formats(version, cpu_arch): - formats = [cpu_arch] - if cpu_arch == "x86_64": - if version < (10, 4): - return [] - formats.extend(["intel", "fat64", "fat32"]) - - elif cpu_arch == "i386": - if version < (10, 4): - return [] - formats.extend(["intel", "fat32", "fat"]) - - elif cpu_arch == "ppc64": - # TODO: Need to care about 32-bit PPC for ppc64 through 10.2? - if version > (10, 5) or version < (10, 4): - return [] - formats.append("fat64") - - elif cpu_arch == "ppc": - if version > (10, 6): - return [] - formats.extend(["fat32", "fat"]) - - formats.append("universal") - return formats - - -def _mac_platforms(version=None, arch=None): - version_str, _, cpu_arch = platform.mac_ver() - if version is None: - version = tuple(map(int, version_str.split(".")[:2])) - if arch is None: - arch = _mac_arch(cpu_arch) - platforms = [] - for minor_version in range(version[1], -1, -1): - compat_version = version[0], minor_version - binary_formats = _mac_binary_formats(compat_version, arch) - for binary_format in binary_formats: - platforms.append( - "macosx_{major}_{minor}_{binary_format}".format( - major=compat_version[0], - minor=compat_version[1], - binary_format=binary_format, - ) - ) - return platforms - - -# From PEP 513. -def _is_manylinux_compatible(name, glibc_version): - # Check for presence of _manylinux module. - try: - import _manylinux - - return bool(getattr(_manylinux, name + "_compatible")) - except (ImportError, AttributeError): - # Fall through to heuristic check below. - pass - - return _have_compatible_glibc(*glibc_version) - - -def _glibc_version_string(): - # Returns glibc version string, or None if not using glibc. - import ctypes - - # ctypes.CDLL(None) internally calls dlopen(NULL), and as the dlopen - # manpage says, "If filename is NULL, then the returned handle is for the - # main program". This way we can let the linker do the work to figure out - # which libc our process is actually using. - process_namespace = ctypes.CDLL(None) - try: - gnu_get_libc_version = process_namespace.gnu_get_libc_version - except AttributeError: - # Symbol doesn't exist -> therefore, we are not linked to - # glibc. - return None - - # Call gnu_get_libc_version, which returns a string like "2.5" - gnu_get_libc_version.restype = ctypes.c_char_p - version_str = gnu_get_libc_version() - # py2 / py3 compatibility: - if not isinstance(version_str, str): - version_str = version_str.decode("ascii") - - return version_str - - -# Separated out from have_compatible_glibc for easier unit testing. -def _check_glibc_version(version_str, required_major, minimum_minor): - # Parse string and check against requested version. - # - # We use a regexp instead of str.split because we want to discard any - # random junk that might come after the minor version -- this might happen - # in patched/forked versions of glibc (e.g. Linaro's version of glibc - # uses version strings like "2.20-2014.11"). See gh-3588. - m = re.match(r"(?P<major>[0-9]+)\.(?P<minor>[0-9]+)", version_str) - if not m: - warnings.warn( - "Expected glibc version with 2 components major.minor," - " got: %s" % version_str, - RuntimeWarning, - ) - return False - return ( - int(m.group("major")) == required_major - and int(m.group("minor")) >= minimum_minor - ) - - -def _have_compatible_glibc(required_major, minimum_minor): - version_str = _glibc_version_string() - if version_str is None: - return False - return _check_glibc_version(version_str, required_major, minimum_minor) - - -def _linux_platforms(is_32bit=_32_BIT_INTERPRETER): - linux = _normalize_string(distutils.util.get_platform()) - if linux == "linux_x86_64" and is_32bit: - linux = "linux_i686" - manylinux_support = ( - ("manylinux2014", (2, 17)), # CentOS 7 w/ glibc 2.17 (PEP 599) - ("manylinux2010", (2, 12)), # CentOS 6 w/ glibc 2.12 (PEP 571) - ("manylinux1", (2, 5)), # CentOS 5 w/ glibc 2.5 (PEP 513) - ) - manylinux_support_iter = iter(manylinux_support) - for name, glibc_version in manylinux_support_iter: - if _is_manylinux_compatible(name, glibc_version): - platforms = [linux.replace("linux", name)] - break - else: - platforms = [] - # Support for a later manylinux implies support for an earlier version. - platforms += [linux.replace("linux", name) for name, _ in manylinux_support_iter] - platforms.append(linux) - return platforms - - -def _generic_platforms(): - platform = _normalize_string(distutils.util.get_platform()) - return [platform] - - -def _interpreter_name(): - name = platform.python_implementation().lower() - return INTERPRETER_SHORT_NAMES.get(name) or name - - -def _generic_interpreter(name, py_version): - version = sysconfig.get_config_var("py_version_nodot") - if not version: - version = "".join(map(str, py_version[:2])) - return "{name}{version}".format(name=name, version=version) - - -def sys_tags(): - """ - Returns the sequence of tag triples for the running interpreter. - - The order of the sequence corresponds to priority order for the - interpreter, from most to least important. - """ - py_version = sys.version_info[:2] - interpreter_name = _interpreter_name() - if platform.system() == "Darwin": - platforms = _mac_platforms() - elif platform.system() == "Linux": - platforms = _linux_platforms() - else: - platforms = _generic_platforms() - - if interpreter_name == "cp": - interpreter = _cpython_interpreter(py_version) - abis = _cpython_abis(py_version) - for tag in _cpython_tags(py_version, interpreter, abis, platforms): - yield tag - elif interpreter_name == "pp": - interpreter = _pypy_interpreter() - abi = _generic_abi() - for tag in _pypy_tags(py_version, interpreter, abi, platforms): - yield tag - else: - interpreter = _generic_interpreter(interpreter_name, py_version) - abi = _generic_abi() - for tag in _generic_tags(interpreter, py_version, abi, platforms): - yield tag - for tag in _independent_tags(interpreter, py_version, platforms): - yield tag diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/utils.py b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/utils.py deleted file mode 100644 index 8841878..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/utils.py +++ /dev/null @@ -1,57 +0,0 @@ -# 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 __future__ import absolute_import, division, print_function - -import re - -from .version import InvalidVersion, Version - - -_canonicalize_regex = re.compile(r"[-_.]+") - - -def canonicalize_name(name): - # This is taken from PEP 503. - return _canonicalize_regex.sub("-", name).lower() - - -def canonicalize_version(version): - """ - This is very similar to Version.__str__, but has one subtle differences - with the way it handles the release segment. - """ - - try: - version = Version(version) - except InvalidVersion: - # Legacy versions cannot be normalized - return version - - parts = [] - - # Epoch - if version.epoch != 0: - parts.append("{0}!".format(version.epoch)) - - # Release segment - # NB: This strips trailing '.0's to normalize - parts.append(re.sub(r"(\.0)+$", "", ".".join(str(x) for x in version.release))) - - # Pre-release - if version.pre is not None: - parts.append("".join(str(x) for x in version.pre)) - - # Post-release - if version.post is not None: - parts.append(".post{0}".format(version.post)) - - # Development release - if version.dev is not None: - parts.append(".dev{0}".format(version.dev)) - - # Local version segment - if version.local is not None: - parts.append("+{0}".format(version.local)) - - return "".join(parts) diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/version.py b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/version.py deleted file mode 100644 index 95157a1..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/version.py +++ /dev/null @@ -1,420 +0,0 @@ -# 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 __future__ import absolute_import, division, print_function - -import collections -import itertools -import re - -from ._structures import Infinity - - -__all__ = ["parse", "Version", "LegacyVersion", "InvalidVersion", "VERSION_PATTERN"] - - -_Version = collections.namedtuple( - "_Version", ["epoch", "release", "dev", "pre", "post", "local"] -) - - -def parse(version): - """ - Parse the given version string and return either a :class:`Version` object - or a :class:`LegacyVersion` object depending on if the given version is - a valid PEP 440 version or a legacy version. - """ - try: - return Version(version) - except InvalidVersion: - return LegacyVersion(version) - - -class InvalidVersion(ValueError): - """ - An invalid version was found, users should refer to PEP 440. - """ - - -class _BaseVersion(object): - def __hash__(self): - return hash(self._key) - - def __lt__(self, other): - return self._compare(other, lambda s, o: s < o) - - def __le__(self, other): - return self._compare(other, lambda s, o: s <= o) - - def __eq__(self, other): - return self._compare(other, lambda s, o: s == o) - - def __ge__(self, other): - return self._compare(other, lambda s, o: s >= o) - - def __gt__(self, other): - return self._compare(other, lambda s, o: s > o) - - def __ne__(self, other): - return self._compare(other, lambda s, o: s != o) - - def _compare(self, other, method): - if not isinstance(other, _BaseVersion): - return NotImplemented - - return method(self._key, other._key) - - -class LegacyVersion(_BaseVersion): - def __init__(self, version): - self._version = str(version) - self._key = _legacy_cmpkey(self._version) - - def __str__(self): - return self._version - - def __repr__(self): - return "<LegacyVersion({0})>".format(repr(str(self))) - - @property - def public(self): - return self._version - - @property - def base_version(self): - return self._version - - @property - def epoch(self): - return -1 - - @property - def release(self): - return None - - @property - def pre(self): - return None - - @property - def post(self): - return None - - @property - def dev(self): - return None - - @property - def local(self): - return None - - @property - def is_prerelease(self): - return False - - @property - def is_postrelease(self): - return False - - @property - def is_devrelease(self): - return False - - -_legacy_version_component_re = re.compile(r"(\d+ | [a-z]+ | \.| -)", re.VERBOSE) - -_legacy_version_replacement_map = { - "pre": "c", - "preview": "c", - "-": "final-", - "rc": "c", - "dev": "@", -} - - -def _parse_version_parts(s): - for part in _legacy_version_component_re.split(s): - part = _legacy_version_replacement_map.get(part, part) - - if not part or part == ".": - continue - - if part[:1] in "0123456789": - # pad for numeric comparison - yield part.zfill(8) - else: - yield "*" + part - - # ensure that alpha/beta/candidate are before final - yield "*final" - - -def _legacy_cmpkey(version): - # We hardcode an epoch of -1 here. A PEP 440 version can only have a epoch - # greater than or equal to 0. This will effectively put the LegacyVersion, - # which uses the defacto standard originally implemented by setuptools, - # as before all PEP 440 versions. - epoch = -1 - - # This scheme is taken from pkg_resources.parse_version setuptools prior to - # it's adoption of the packaging library. - parts = [] - for part in _parse_version_parts(version.lower()): - if part.startswith("*"): - # remove "-" before a prerelease tag - if part < "*final": - while parts and parts[-1] == "*final-": - parts.pop() - - # remove trailing zeros from each series of numeric parts - while parts and parts[-1] == "00000000": - parts.pop() - - parts.append(part) - parts = tuple(parts) - - return epoch, parts - - -# Deliberately not anchored to the start and end of the string, to make it -# easier for 3rd party code to reuse -VERSION_PATTERN = r""" - v? - (?: - (?:(?P<epoch>[0-9]+)!)? # epoch - (?P<release>[0-9]+(?:\.[0-9]+)*) # release segment - (?P<pre> # pre-release - [-_\.]? - (?P<pre_l>(a|b|c|rc|alpha|beta|pre|preview)) - [-_\.]? - (?P<pre_n>[0-9]+)? - )? - (?P<post> # post release - (?:-(?P<post_n1>[0-9]+)) - | - (?: - [-_\.]? - (?P<post_l>post|rev|r) - [-_\.]? - (?P<post_n2>[0-9]+)? - ) - )? - (?P<dev> # dev release - [-_\.]? - (?P<dev_l>dev) - [-_\.]? - (?P<dev_n>[0-9]+)? - )? - ) - (?:\+(?P<local>[a-z0-9]+(?:[-_\.][a-z0-9]+)*))? # local version -""" - - -class Version(_BaseVersion): - - _regex = re.compile(r"^\s*" + VERSION_PATTERN + r"\s*$", re.VERBOSE | re.IGNORECASE) - - def __init__(self, version): - # Validate the version and parse it into pieces - match = self._regex.search(version) - if not match: - raise InvalidVersion("Invalid version: '{0}'".format(version)) - - # Store the parsed out pieces of the version - self._version = _Version( - epoch=int(match.group("epoch")) if match.group("epoch") else 0, - release=tuple(int(i) for i in match.group("release").split(".")), - pre=_parse_letter_version(match.group("pre_l"), match.group("pre_n")), - post=_parse_letter_version( - match.group("post_l"), match.group("post_n1") or match.group("post_n2") - ), - dev=_parse_letter_version(match.group("dev_l"), match.group("dev_n")), - local=_parse_local_version(match.group("local")), - ) - - # Generate a key which will be used for sorting - self._key = _cmpkey( - self._version.epoch, - self._version.release, - self._version.pre, - self._version.post, - self._version.dev, - self._version.local, - ) - - def __repr__(self): - return "<Version({0})>".format(repr(str(self))) - - def __str__(self): - parts = [] - - # Epoch - if self.epoch != 0: - parts.append("{0}!".format(self.epoch)) - - # Release segment - parts.append(".".join(str(x) for x in self.release)) - - # Pre-release - if self.pre is not None: - parts.append("".join(str(x) for x in self.pre)) - - # Post-release - if self.post is not None: - parts.append(".post{0}".format(self.post)) - - # Development release - if self.dev is not None: - parts.append(".dev{0}".format(self.dev)) - - # Local version segment - if self.local is not None: - parts.append("+{0}".format(self.local)) - - return "".join(parts) - - @property - def epoch(self): - return self._version.epoch - - @property - def release(self): - return self._version.release - - @property - def pre(self): - return self._version.pre - - @property - def post(self): - return self._version.post[1] if self._version.post else None - - @property - def dev(self): - return self._version.dev[1] if self._version.dev else None - - @property - def local(self): - if self._version.local: - return ".".join(str(x) for x in self._version.local) - else: - return None - - @property - def public(self): - return str(self).split("+", 1)[0] - - @property - def base_version(self): - parts = [] - - # Epoch - if self.epoch != 0: - parts.append("{0}!".format(self.epoch)) - - # Release segment - parts.append(".".join(str(x) for x in self.release)) - - return "".join(parts) - - @property - def is_prerelease(self): - return self.dev is not None or self.pre is not None - - @property - def is_postrelease(self): - return self.post is not None - - @property - def is_devrelease(self): - return self.dev is not None - - -def _parse_letter_version(letter, number): - if letter: - # We consider there to be an implicit 0 in a pre-release if there is - # not a numeral associated with it. - if number is None: - number = 0 - - # We normalize any letters to their lower case form - letter = letter.lower() - - # We consider some words to be alternate spellings of other words and - # in those cases we want to normalize the spellings to our preferred - # spelling. - if letter == "alpha": - letter = "a" - elif letter == "beta": - letter = "b" - elif letter in ["c", "pre", "preview"]: - letter = "rc" - elif letter in ["rev", "r"]: - letter = "post" - - return letter, int(number) - if not letter and number: - # We assume if we are given a number, but we are not given a letter - # then this is using the implicit post release syntax (e.g. 1.0-1) - letter = "post" - - return letter, int(number) - - -_local_version_separators = re.compile(r"[\._-]") - - -def _parse_local_version(local): - """ - Takes a string like abc.1.twelve and turns it into ("abc", 1, "twelve"). - """ - if local is not None: - return tuple( - part.lower() if not part.isdigit() else int(part) - for part in _local_version_separators.split(local) - ) - - -def _cmpkey(epoch, release, pre, post, dev, local): - # When we compare a release version, we want to compare it with all of the - # trailing zeros removed. So we'll use a reverse the list, drop all the now - # leading zeros until we come to something non zero, then take the rest - # re-reverse it back into the correct order and make it a tuple and use - # that for our sorting key. - release = tuple( - reversed(list(itertools.dropwhile(lambda x: x == 0, reversed(release)))) - ) - - # We need to "trick" the sorting algorithm to put 1.0.dev0 before 1.0a0. - # We'll do this by abusing the pre segment, but we _only_ want to do this - # if there is not a pre or a post segment. If we have one of those then - # the normal sorting rules will handle this case correctly. - if pre is None and post is None and dev is not None: - pre = -Infinity - # Versions without a pre-release (except as noted above) should sort after - # those with one. - elif pre is None: - pre = Infinity - - # Versions without a post segment should sort before those with one. - if post is None: - post = -Infinity - - # Versions without a development segment should sort after those with one. - if dev is None: - dev = Infinity - - if local is None: - # Versions without a local segment should sort before those with one. - local = -Infinity - else: - # Versions with a local segment need that segment parsed to implement - # the sorting rules in PEP440. - # - Alpha numeric segments sort before numeric segments - # - Alpha numeric segments sort lexicographically - # - Numeric segments sort numerically - # - Shorter versions sort before longer versions when the prefixes - # match exactly - local = tuple((i, "") if isinstance(i, int) else (-Infinity, i) for i in local) - - return epoch, release, pre, post, dev, local diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/pyparsing.py b/venv/lib/python3.8/site-packages/setuptools/_vendor/pyparsing.py deleted file mode 100644 index cf75e1e..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/_vendor/pyparsing.py +++ /dev/null @@ -1,5742 +0,0 @@ -# module pyparsing.py -# -# Copyright (c) 2003-2018 Paul T. McGuire -# -# 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. -# - -__doc__ = \ -""" -pyparsing module - Classes and methods to define and execute parsing grammars -============================================================================= - -The pyparsing module is an alternative approach to creating and executing simple grammars, -vs. the traditional lex/yacc approach, or the use of regular expressions. With pyparsing, you -don't need to learn a new syntax for defining grammars or matching expressions - the parsing module -provides a library of classes that you use to construct the grammar directly in Python. - -Here is a program to parse "Hello, World!" (or any greeting of the form -C{"<salutation>, <addressee>!"}), built up using L{Word}, L{Literal}, and L{And} elements -(L{'+'<ParserElement.__add__>} operator gives L{And} expressions, strings are auto-converted to -L{Literal} expressions):: - - from pyparsing import Word, alphas - - # define grammar of a greeting - greet = Word(alphas) + "," + Word(alphas) + "!" - - hello = "Hello, World!" - print (hello, "->", greet.parseString(hello)) - -The program outputs the following:: - - Hello, World! -> ['Hello', ',', 'World', '!'] - -The Python representation of the grammar is quite readable, owing to the self-explanatory -class names, and the use of '+', '|' and '^' operators. - -The L{ParseResults} object returned from L{ParserElement.parseString<ParserElement.parseString>} can be accessed as a nested list, a dictionary, or an -object with named attributes. - -The pyparsing module handles some of the problems that are typically vexing when writing text parsers: - - extra or missing whitespace (the above program will also handle "Hello,World!", "Hello , World !", etc.) - - quoted strings - - embedded comments - - -Getting Started - ------------------ -Visit the classes L{ParserElement} and L{ParseResults} to see the base classes that most other pyparsing -classes inherit from. Use the docstrings for examples of how to: - - construct literal match expressions from L{Literal} and L{CaselessLiteral} classes - - construct character word-group expressions using the L{Word} class - - see how to create repetitive expressions using L{ZeroOrMore} and L{OneOrMore} classes - - use L{'+'<And>}, L{'|'<MatchFirst>}, L{'^'<Or>}, and L{'&'<Each>} operators to combine simple expressions into more complex ones - - associate names with your parsed results using L{ParserElement.setResultsName} - - find some helpful expression short-cuts like L{delimitedList} and L{oneOf} - - find more useful common expressions in the L{pyparsing_common} namespace class -""" - -__version__ = "2.2.1" -__versionTime__ = "18 Sep 2018 00:49 UTC" -__author__ = "Paul McGuire <ptmcg@users.sourceforge.net>" - -import string -from weakref import ref as wkref -import copy -import sys -import warnings -import re -import sre_constants -import collections -import pprint -import traceback -import types -from datetime import datetime - -try: - from _thread import RLock -except ImportError: - from threading import RLock - -try: - # Python 3 - from collections.abc import Iterable - from collections.abc import MutableMapping -except ImportError: - # Python 2.7 - from collections import Iterable - from collections import MutableMapping - -try: - from collections import OrderedDict as _OrderedDict -except ImportError: - try: - from ordereddict import OrderedDict as _OrderedDict - except ImportError: - _OrderedDict = None - -#~ sys.stderr.write( "testing pyparsing module, version %s, %s\n" % (__version__,__versionTime__ ) ) - -__all__ = [ -'And', 'CaselessKeyword', 'CaselessLiteral', 'CharsNotIn', 'Combine', 'Dict', 'Each', 'Empty', -'FollowedBy', 'Forward', 'GoToColumn', 'Group', 'Keyword', 'LineEnd', 'LineStart', 'Literal', -'MatchFirst', 'NoMatch', 'NotAny', 'OneOrMore', 'OnlyOnce', 'Optional', 'Or', -'ParseBaseException', 'ParseElementEnhance', 'ParseException', 'ParseExpression', 'ParseFatalException', -'ParseResults', 'ParseSyntaxException', 'ParserElement', 'QuotedString', 'RecursiveGrammarException', -'Regex', 'SkipTo', 'StringEnd', 'StringStart', 'Suppress', 'Token', 'TokenConverter', -'White', 'Word', 'WordEnd', 'WordStart', 'ZeroOrMore', -'alphanums', 'alphas', 'alphas8bit', 'anyCloseTag', 'anyOpenTag', 'cStyleComment', 'col', -'commaSeparatedList', 'commonHTMLEntity', 'countedArray', 'cppStyleComment', 'dblQuotedString', -'dblSlashComment', 'delimitedList', 'dictOf', 'downcaseTokens', 'empty', 'hexnums', -'htmlComment', 'javaStyleComment', 'line', 'lineEnd', 'lineStart', 'lineno', -'makeHTMLTags', 'makeXMLTags', 'matchOnlyAtCol', 'matchPreviousExpr', 'matchPreviousLiteral', -'nestedExpr', 'nullDebugAction', 'nums', 'oneOf', 'opAssoc', 'operatorPrecedence', 'printables', -'punc8bit', 'pythonStyleComment', 'quotedString', 'removeQuotes', 'replaceHTMLEntity', -'replaceWith', 'restOfLine', 'sglQuotedString', 'srange', 'stringEnd', -'stringStart', 'traceParseAction', 'unicodeString', 'upcaseTokens', 'withAttribute', -'indentedBlock', 'originalTextFor', 'ungroup', 'infixNotation','locatedExpr', 'withClass', -'CloseMatch', 'tokenMap', 'pyparsing_common', -] - -system_version = tuple(sys.version_info)[:3] -PY_3 = system_version[0] == 3 -if PY_3: - _MAX_INT = sys.maxsize - basestring = str - unichr = chr - _ustr = str - - # build list of single arg builtins, that can be used as parse actions - singleArgBuiltins = [sum, len, sorted, reversed, list, tuple, set, any, all, min, max] - -else: - _MAX_INT = sys.maxint - range = xrange - - def _ustr(obj): - """Drop-in replacement for str(obj) that tries to be Unicode friendly. It first tries - str(obj). If that fails with a UnicodeEncodeError, then it tries unicode(obj). It - then < returns the unicode object | encodes it with the default encoding | ... >. - """ - if isinstance(obj,unicode): - return obj - - try: - # If this works, then _ustr(obj) has the same behaviour as str(obj), so - # it won't break any existing code. - return str(obj) - - except UnicodeEncodeError: - # Else encode it - ret = unicode(obj).encode(sys.getdefaultencoding(), 'xmlcharrefreplace') - xmlcharref = Regex(r'&#\d+;') - xmlcharref.setParseAction(lambda t: '\\u' + hex(int(t[0][2:-1]))[2:]) - return xmlcharref.transformString(ret) - - # build list of single arg builtins, tolerant of Python version, that can be used as parse actions - singleArgBuiltins = [] - import __builtin__ - for fname in "sum len sorted reversed list tuple set any all min max".split(): - try: - singleArgBuiltins.append(getattr(__builtin__,fname)) - except AttributeError: - continue - -_generatorType = type((y for y in range(1))) - -def _xml_escape(data): - """Escape &, <, >, ", ', etc. in a string of data.""" - - # ampersand must be replaced first - from_symbols = '&><"\'' - to_symbols = ('&'+s+';' for s in "amp gt lt quot apos".split()) - for from_,to_ in zip(from_symbols, to_symbols): - data = data.replace(from_, to_) - return data - -class _Constants(object): - pass - -alphas = string.ascii_uppercase + string.ascii_lowercase -nums = "0123456789" -hexnums = nums + "ABCDEFabcdef" -alphanums = alphas + nums -_bslash = chr(92) -printables = "".join(c for c in string.printable if c not in string.whitespace) - -class ParseBaseException(Exception): - """base exception class for all parsing runtime exceptions""" - # Performance tuning: we construct a *lot* of these, so keep this - # constructor as small and fast as possible - def __init__( self, pstr, loc=0, msg=None, elem=None ): - self.loc = loc - if msg is None: - self.msg = pstr - self.pstr = "" - else: - self.msg = msg - self.pstr = pstr - self.parserElement = elem - self.args = (pstr, loc, msg) - - @classmethod - def _from_exception(cls, pe): - """ - internal factory method to simplify creating one type of ParseException - from another - avoids having __init__ signature conflicts among subclasses - """ - return cls(pe.pstr, pe.loc, pe.msg, pe.parserElement) - - def __getattr__( self, aname ): - """supported attributes by name are: - - lineno - returns the line number of the exception text - - col - returns the column number of the exception text - - line - returns the line containing the exception text - """ - if( aname == "lineno" ): - return lineno( self.loc, self.pstr ) - elif( aname in ("col", "column") ): - return col( self.loc, self.pstr ) - elif( aname == "line" ): - return line( self.loc, self.pstr ) - else: - raise AttributeError(aname) - - def __str__( self ): - return "%s (at char %d), (line:%d, col:%d)" % \ - ( self.msg, self.loc, self.lineno, self.column ) - def __repr__( self ): - return _ustr(self) - def markInputline( self, markerString = ">!<" ): - """Extracts the exception line from the input string, and marks - the location of the exception with a special symbol. - """ - line_str = self.line - line_column = self.column - 1 - if markerString: - line_str = "".join((line_str[:line_column], - markerString, line_str[line_column:])) - return line_str.strip() - def __dir__(self): - return "lineno col line".split() + dir(type(self)) - -class ParseException(ParseBaseException): - """ - Exception thrown when parse expressions don't match class; - supported attributes by name are: - - lineno - returns the line number of the exception text - - col - returns the column number of the exception text - - line - returns the line containing the exception text - - Example:: - try: - Word(nums).setName("integer").parseString("ABC") - except ParseException as pe: - print(pe) - print("column: {}".format(pe.col)) - - prints:: - Expected integer (at char 0), (line:1, col:1) - column: 1 - """ - pass - -class ParseFatalException(ParseBaseException): - """user-throwable exception thrown when inconsistent parse content - is found; stops all parsing immediately""" - pass - -class ParseSyntaxException(ParseFatalException): - """just like L{ParseFatalException}, but thrown internally when an - L{ErrorStop<And._ErrorStop>} ('-' operator) indicates that parsing is to stop - immediately because an unbacktrackable syntax error has been found""" - pass - -#~ class ReparseException(ParseBaseException): - #~ """Experimental class - parse actions can raise this exception to cause - #~ pyparsing to reparse the input string: - #~ - with a modified input string, and/or - #~ - with a modified start location - #~ Set the values of the ReparseException in the constructor, and raise the - #~ exception in a parse action to cause pyparsing to use the new string/location. - #~ Setting the values as None causes no change to be made. - #~ """ - #~ def __init_( self, newstring, restartLoc ): - #~ self.newParseText = newstring - #~ self.reparseLoc = restartLoc - -class RecursiveGrammarException(Exception): - """exception thrown by L{ParserElement.validate} if the grammar could be improperly recursive""" - def __init__( self, parseElementList ): - self.parseElementTrace = parseElementList - - def __str__( self ): - return "RecursiveGrammarException: %s" % self.parseElementTrace - -class _ParseResultsWithOffset(object): - def __init__(self,p1,p2): - self.tup = (p1,p2) - def __getitem__(self,i): - return self.tup[i] - def __repr__(self): - return repr(self.tup[0]) - def setOffset(self,i): - self.tup = (self.tup[0],i) - -class ParseResults(object): - """ - Structured parse results, to provide multiple means of access to the parsed data: - - as a list (C{len(results)}) - - by list index (C{results[0], results[1]}, etc.) - - by attribute (C{results.<resultsName>} - see L{ParserElement.setResultsName}) - - Example:: - integer = Word(nums) - date_str = (integer.setResultsName("year") + '/' - + integer.setResultsName("month") + '/' - + integer.setResultsName("day")) - # equivalent form: - # date_str = integer("year") + '/' + integer("month") + '/' + integer("day") - - # parseString returns a ParseResults object - result = date_str.parseString("1999/12/31") - - def test(s, fn=repr): - print("%s -> %s" % (s, fn(eval(s)))) - test("list(result)") - test("result[0]") - test("result['month']") - test("result.day") - test("'month' in result") - test("'minutes' in result") - test("result.dump()", str) - prints:: - list(result) -> ['1999', '/', '12', '/', '31'] - result[0] -> '1999' - result['month'] -> '12' - result.day -> '31' - 'month' in result -> True - 'minutes' in result -> False - result.dump() -> ['1999', '/', '12', '/', '31'] - - day: 31 - - month: 12 - - year: 1999 - """ - def __new__(cls, toklist=None, name=None, asList=True, modal=True ): - if isinstance(toklist, cls): - return toklist - retobj = object.__new__(cls) - retobj.__doinit = True - return retobj - - # Performance tuning: we construct a *lot* of these, so keep this - # constructor as small and fast as possible - def __init__( self, toklist=None, name=None, asList=True, modal=True, isinstance=isinstance ): - if self.__doinit: - self.__doinit = False - self.__name = None - self.__parent = None - self.__accumNames = {} - self.__asList = asList - self.__modal = modal - if toklist is None: - toklist = [] - if isinstance(toklist, list): - self.__toklist = toklist[:] - elif isinstance(toklist, _generatorType): - self.__toklist = list(toklist) - else: - self.__toklist = [toklist] - self.__tokdict = dict() - - if name is not None and name: - if not modal: - self.__accumNames[name] = 0 - if isinstance(name,int): - name = _ustr(name) # will always return a str, but use _ustr for consistency - self.__name = name - if not (isinstance(toklist, (type(None), basestring, list)) and toklist in (None,'',[])): - if isinstance(toklist,basestring): - toklist = [ toklist ] - if asList: - if isinstance(toklist,ParseResults): - self[name] = _ParseResultsWithOffset(toklist.copy(),0) - else: - self[name] = _ParseResultsWithOffset(ParseResults(toklist[0]),0) - self[name].__name = name - else: - try: - self[name] = toklist[0] - except (KeyError,TypeError,IndexError): - self[name] = toklist - - def __getitem__( self, i ): - if isinstance( i, (int,slice) ): - return self.__toklist[i] - else: - if i not in self.__accumNames: - return self.__tokdict[i][-1][0] - else: - return ParseResults([ v[0] for v in self.__tokdict[i] ]) - - def __setitem__( self, k, v, isinstance=isinstance ): - if isinstance(v,_ParseResultsWithOffset): - self.__tokdict[k] = self.__tokdict.get(k,list()) + [v] - sub = v[0] - elif isinstance(k,(int,slice)): - self.__toklist[k] = v - sub = v - else: - self.__tokdict[k] = self.__tokdict.get(k,list()) + [_ParseResultsWithOffset(v,0)] - sub = v - if isinstance(sub,ParseResults): - sub.__parent = wkref(self) - - def __delitem__( self, i ): - if isinstance(i,(int,slice)): - mylen = len( self.__toklist ) - del self.__toklist[i] - - # convert int to slice - if isinstance(i, int): - if i < 0: - i += mylen - i = slice(i, i+1) - # get removed indices - removed = list(range(*i.indices(mylen))) - removed.reverse() - # fixup indices in token dictionary - for name,occurrences in self.__tokdict.items(): - for j in removed: - for k, (value, position) in enumerate(occurrences): - occurrences[k] = _ParseResultsWithOffset(value, position - (position > j)) - else: - del self.__tokdict[i] - - def __contains__( self, k ): - return k in self.__tokdict - - def __len__( self ): return len( self.__toklist ) - def __bool__(self): return ( not not self.__toklist ) - __nonzero__ = __bool__ - def __iter__( self ): return iter( self.__toklist ) - def __reversed__( self ): return iter( self.__toklist[::-1] ) - def _iterkeys( self ): - if hasattr(self.__tokdict, "iterkeys"): - return self.__tokdict.iterkeys() - else: - return iter(self.__tokdict) - - def _itervalues( self ): - return (self[k] for k in self._iterkeys()) - - def _iteritems( self ): - return ((k, self[k]) for k in self._iterkeys()) - - if PY_3: - keys = _iterkeys - """Returns an iterator of all named result keys (Python 3.x only).""" - - values = _itervalues - """Returns an iterator of all named result values (Python 3.x only).""" - - items = _iteritems - """Returns an iterator of all named result key-value tuples (Python 3.x only).""" - - else: - iterkeys = _iterkeys - """Returns an iterator of all named result keys (Python 2.x only).""" - - itervalues = _itervalues - """Returns an iterator of all named result values (Python 2.x only).""" - - iteritems = _iteritems - """Returns an iterator of all named result key-value tuples (Python 2.x only).""" - - def keys( self ): - """Returns all named result keys (as a list in Python 2.x, as an iterator in Python 3.x).""" - return list(self.iterkeys()) - - def values( self ): - """Returns all named result values (as a list in Python 2.x, as an iterator in Python 3.x).""" - return list(self.itervalues()) - - def items( self ): - """Returns all named result key-values (as a list of tuples in Python 2.x, as an iterator in Python 3.x).""" - return list(self.iteritems()) - - def haskeys( self ): - """Since keys() returns an iterator, this method is helpful in bypassing - code that looks for the existence of any defined results names.""" - return bool(self.__tokdict) - - def pop( self, *args, **kwargs): - """ - Removes and returns item at specified index (default=C{last}). - Supports both C{list} and C{dict} semantics for C{pop()}. If passed no - argument or an integer argument, it will use C{list} semantics - and pop tokens from the list of parsed tokens. If passed a - non-integer argument (most likely a string), it will use C{dict} - semantics and pop the corresponding value from any defined - results names. A second default return value argument is - supported, just as in C{dict.pop()}. - - Example:: - def remove_first(tokens): - tokens.pop(0) - print(OneOrMore(Word(nums)).parseString("0 123 321")) # -> ['0', '123', '321'] - print(OneOrMore(Word(nums)).addParseAction(remove_first).parseString("0 123 321")) # -> ['123', '321'] - - label = Word(alphas) - patt = label("LABEL") + OneOrMore(Word(nums)) - print(patt.parseString("AAB 123 321").dump()) - - # Use pop() in a parse action to remove named result (note that corresponding value is not - # removed from list form of results) - def remove_LABEL(tokens): - tokens.pop("LABEL") - return tokens - patt.addParseAction(remove_LABEL) - print(patt.parseString("AAB 123 321").dump()) - prints:: - ['AAB', '123', '321'] - - LABEL: AAB - - ['AAB', '123', '321'] - """ - if not args: - args = [-1] - for k,v in kwargs.items(): - if k == 'default': - args = (args[0], v) - else: - raise TypeError("pop() got an unexpected keyword argument '%s'" % k) - if (isinstance(args[0], int) or - len(args) == 1 or - args[0] in self): - index = args[0] - ret = self[index] - del self[index] - return ret - else: - defaultvalue = args[1] - return defaultvalue - - def get(self, key, defaultValue=None): - """ - Returns named result matching the given key, or if there is no - such name, then returns the given C{defaultValue} or C{None} if no - C{defaultValue} is specified. - - Similar to C{dict.get()}. - - Example:: - integer = Word(nums) - date_str = integer("year") + '/' + integer("month") + '/' + integer("day") - - result = date_str.parseString("1999/12/31") - print(result.get("year")) # -> '1999' - print(result.get("hour", "not specified")) # -> 'not specified' - print(result.get("hour")) # -> None - """ - if key in self: - return self[key] - else: - return defaultValue - - def insert( self, index, insStr ): - """ - Inserts new element at location index in the list of parsed tokens. - - Similar to C{list.insert()}. - - Example:: - print(OneOrMore(Word(nums)).parseString("0 123 321")) # -> ['0', '123', '321'] - - # use a parse action to insert the parse location in the front of the parsed results - def insert_locn(locn, tokens): - tokens.insert(0, locn) - print(OneOrMore(Word(nums)).addParseAction(insert_locn).parseString("0 123 321")) # -> [0, '0', '123', '321'] - """ - self.__toklist.insert(index, insStr) - # fixup indices in token dictionary - for name,occurrences in self.__tokdict.items(): - for k, (value, position) in enumerate(occurrences): - occurrences[k] = _ParseResultsWithOffset(value, position + (position > index)) - - def append( self, item ): - """ - Add single element to end of ParseResults list of elements. - - Example:: - print(OneOrMore(Word(nums)).parseString("0 123 321")) # -> ['0', '123', '321'] - - # use a parse action to compute the sum of the parsed integers, and add it to the end - def append_sum(tokens): - tokens.append(sum(map(int, tokens))) - print(OneOrMore(Word(nums)).addParseAction(append_sum).parseString("0 123 321")) # -> ['0', '123', '321', 444] - """ - self.__toklist.append(item) - - def extend( self, itemseq ): - """ - Add sequence of elements to end of ParseResults list of elements. - - Example:: - patt = OneOrMore(Word(alphas)) - - # use a parse action to append the reverse of the matched strings, to make a palindrome - def make_palindrome(tokens): - tokens.extend(reversed([t[::-1] for t in tokens])) - return ''.join(tokens) - print(patt.addParseAction(make_palindrome).parseString("lskdj sdlkjf lksd")) # -> 'lskdjsdlkjflksddsklfjkldsjdksl' - """ - if isinstance(itemseq, ParseResults): - self += itemseq - else: - self.__toklist.extend(itemseq) - - def clear( self ): - """ - Clear all elements and results names. - """ - del self.__toklist[:] - self.__tokdict.clear() - - def __getattr__( self, name ): - try: - return self[name] - except KeyError: - return "" - - if name in self.__tokdict: - if name not in self.__accumNames: - return self.__tokdict[name][-1][0] - else: - return ParseResults([ v[0] for v in self.__tokdict[name] ]) - else: - return "" - - def __add__( self, other ): - ret = self.copy() - ret += other - return ret - - def __iadd__( self, other ): - if other.__tokdict: - offset = len(self.__toklist) - addoffset = lambda a: offset if a<0 else a+offset - otheritems = other.__tokdict.items() - otherdictitems = [(k, _ParseResultsWithOffset(v[0],addoffset(v[1])) ) - for (k,vlist) in otheritems for v in vlist] - for k,v in otherdictitems: - self[k] = v - if isinstance(v[0],ParseResults): - v[0].__parent = wkref(self) - - self.__toklist += other.__toklist - self.__accumNames.update( other.__accumNames ) - return self - - def __radd__(self, other): - if isinstance(other,int) and other == 0: - # useful for merging many ParseResults using sum() builtin - return self.copy() - else: - # this may raise a TypeError - so be it - return other + self - - def __repr__( self ): - return "(%s, %s)" % ( repr( self.__toklist ), repr( self.__tokdict ) ) - - def __str__( self ): - return '[' + ', '.join(_ustr(i) if isinstance(i, ParseResults) else repr(i) for i in self.__toklist) + ']' - - def _asStringList( self, sep='' ): - out = [] - for item in self.__toklist: - if out and sep: - out.append(sep) - if isinstance( item, ParseResults ): - out += item._asStringList() - else: - out.append( _ustr(item) ) - return out - - def asList( self ): - """ - Returns the parse results as a nested list of matching tokens, all converted to strings. - - Example:: - patt = OneOrMore(Word(alphas)) - result = patt.parseString("sldkj lsdkj sldkj") - # even though the result prints in string-like form, it is actually a pyparsing ParseResults - print(type(result), result) # -> <class 'pyparsing.ParseResults'> ['sldkj', 'lsdkj', 'sldkj'] - - # Use asList() to create an actual list - result_list = result.asList() - print(type(result_list), result_list) # -> <class 'list'> ['sldkj', 'lsdkj', 'sldkj'] - """ - return [res.asList() if isinstance(res,ParseResults) else res for res in self.__toklist] - - def asDict( self ): - """ - Returns the named parse results as a nested dictionary. - - Example:: - integer = Word(nums) - date_str = integer("year") + '/' + integer("month") + '/' + integer("day") - - result = date_str.parseString('12/31/1999') - print(type(result), repr(result)) # -> <class 'pyparsing.ParseResults'> (['12', '/', '31', '/', '1999'], {'day': [('1999', 4)], 'year': [('12', 0)], 'month': [('31', 2)]}) - - result_dict = result.asDict() - print(type(result_dict), repr(result_dict)) # -> <class 'dict'> {'day': '1999', 'year': '12', 'month': '31'} - - # even though a ParseResults supports dict-like access, sometime you just need to have a dict - import json - print(json.dumps(result)) # -> Exception: TypeError: ... is not JSON serializable - print(json.dumps(result.asDict())) # -> {"month": "31", "day": "1999", "year": "12"} - """ - if PY_3: - item_fn = self.items - else: - item_fn = self.iteritems - - def toItem(obj): - if isinstance(obj, ParseResults): - if obj.haskeys(): - return obj.asDict() - else: - return [toItem(v) for v in obj] - else: - return obj - - return dict((k,toItem(v)) for k,v in item_fn()) - - def copy( self ): - """ - Returns a new copy of a C{ParseResults} object. - """ - ret = ParseResults( self.__toklist ) - ret.__tokdict = self.__tokdict.copy() - ret.__parent = self.__parent - ret.__accumNames.update( self.__accumNames ) - ret.__name = self.__name - return ret - - def asXML( self, doctag=None, namedItemsOnly=False, indent="", formatted=True ): - """ - (Deprecated) Returns the parse results as XML. Tags are created for tokens and lists that have defined results names. - """ - nl = "\n" - out = [] - namedItems = dict((v[1],k) for (k,vlist) in self.__tokdict.items() - for v in vlist) - nextLevelIndent = indent + " " - - # collapse out indents if formatting is not desired - if not formatted: - indent = "" - nextLevelIndent = "" - nl = "" - - selfTag = None - if doctag is not None: - selfTag = doctag - else: - if self.__name: - selfTag = self.__name - - if not selfTag: - if namedItemsOnly: - return "" - else: - selfTag = "ITEM" - - out += [ nl, indent, "<", selfTag, ">" ] - - for i,res in enumerate(self.__toklist): - if isinstance(res,ParseResults): - if i in namedItems: - out += [ res.asXML(namedItems[i], - namedItemsOnly and doctag is None, - nextLevelIndent, - formatted)] - else: - out += [ res.asXML(None, - namedItemsOnly and doctag is None, - nextLevelIndent, - formatted)] - else: - # individual token, see if there is a name for it - resTag = None - if i in namedItems: - resTag = namedItems[i] - if not resTag: - if namedItemsOnly: - continue - else: - resTag = "ITEM" - xmlBodyText = _xml_escape(_ustr(res)) - out += [ nl, nextLevelIndent, "<", resTag, ">", - xmlBodyText, - "</", resTag, ">" ] - - out += [ nl, indent, "</", selfTag, ">" ] - return "".join(out) - - def __lookup(self,sub): - for k,vlist in self.__tokdict.items(): - for v,loc in vlist: - if sub is v: - return k - return None - - def getName(self): - r""" - Returns the results name for this token expression. Useful when several - different expressions might match at a particular location. - - Example:: - integer = Word(nums) - ssn_expr = Regex(r"\d\d\d-\d\d-\d\d\d\d") - house_number_expr = Suppress('#') + Word(nums, alphanums) - user_data = (Group(house_number_expr)("house_number") - | Group(ssn_expr)("ssn") - | Group(integer)("age")) - user_info = OneOrMore(user_data) - - result = user_info.parseString("22 111-22-3333 #221B") - for item in result: - print(item.getName(), ':', item[0]) - prints:: - age : 22 - ssn : 111-22-3333 - house_number : 221B - """ - if self.__name: - return self.__name - elif self.__parent: - par = self.__parent() - if par: - return par.__lookup(self) - else: - return None - elif (len(self) == 1 and - len(self.__tokdict) == 1 and - next(iter(self.__tokdict.values()))[0][1] in (0,-1)): - return next(iter(self.__tokdict.keys())) - else: - return None - - def dump(self, indent='', depth=0, full=True): - """ - Diagnostic method for listing out the contents of a C{ParseResults}. - Accepts an optional C{indent} argument so that this string can be embedded - in a nested display of other data. - - Example:: - integer = Word(nums) - date_str = integer("year") + '/' + integer("month") + '/' + integer("day") - - result = date_str.parseString('12/31/1999') - print(result.dump()) - prints:: - ['12', '/', '31', '/', '1999'] - - day: 1999 - - month: 31 - - year: 12 - """ - out = [] - NL = '\n' - out.append( indent+_ustr(self.asList()) ) - if full: - if self.haskeys(): - items = sorted((str(k), v) for k,v in self.items()) - for k,v in items: - if out: - out.append(NL) - out.append( "%s%s- %s: " % (indent,(' '*depth), k) ) - if isinstance(v,ParseResults): - if v: - out.append( v.dump(indent,depth+1) ) - else: - out.append(_ustr(v)) - else: - out.append(repr(v)) - elif any(isinstance(vv,ParseResults) for vv in self): - v = self - for i,vv in enumerate(v): - if isinstance(vv,ParseResults): - out.append("\n%s%s[%d]:\n%s%s%s" % (indent,(' '*(depth)),i,indent,(' '*(depth+1)),vv.dump(indent,depth+1) )) - else: - out.append("\n%s%s[%d]:\n%s%s%s" % (indent,(' '*(depth)),i,indent,(' '*(depth+1)),_ustr(vv))) - - return "".join(out) - - def pprint(self, *args, **kwargs): - """ - Pretty-printer for parsed results as a list, using the C{pprint} module. - Accepts additional positional or keyword args as defined for the - C{pprint.pprint} method. (U{http://docs.python.org/3/library/pprint.html#pprint.pprint}) - - Example:: - ident = Word(alphas, alphanums) - num = Word(nums) - func = Forward() - term = ident | num | Group('(' + func + ')') - func <<= ident + Group(Optional(delimitedList(term))) - result = func.parseString("fna a,b,(fnb c,d,200),100") - result.pprint(width=40) - prints:: - ['fna', - ['a', - 'b', - ['(', 'fnb', ['c', 'd', '200'], ')'], - '100']] - """ - pprint.pprint(self.asList(), *args, **kwargs) - - # add support for pickle protocol - def __getstate__(self): - return ( self.__toklist, - ( self.__tokdict.copy(), - self.__parent is not None and self.__parent() or None, - self.__accumNames, - self.__name ) ) - - def __setstate__(self,state): - self.__toklist = state[0] - (self.__tokdict, - par, - inAccumNames, - self.__name) = state[1] - self.__accumNames = {} - self.__accumNames.update(inAccumNames) - if par is not None: - self.__parent = wkref(par) - else: - self.__parent = None - - def __getnewargs__(self): - return self.__toklist, self.__name, self.__asList, self.__modal - - def __dir__(self): - return (dir(type(self)) + list(self.keys())) - -MutableMapping.register(ParseResults) - -def col (loc,strg): - """Returns current column within a string, counting newlines as line separators. - The first column is number 1. - - Note: the default parsing behavior is to expand tabs in the input string - before starting the parsing process. See L{I{ParserElement.parseString}<ParserElement.parseString>} for more information - on parsing strings containing C{<TAB>}s, and suggested methods to maintain a - consistent view of the parsed string, the parse location, and line and column - positions within the parsed string. - """ - s = strg - return 1 if 0<loc<len(s) and s[loc-1] == '\n' else loc - s.rfind("\n", 0, loc) - -def lineno(loc,strg): - """Returns current line number within a string, counting newlines as line separators. - The first line is number 1. - - Note: the default parsing behavior is to expand tabs in the input string - before starting the parsing process. See L{I{ParserElement.parseString}<ParserElement.parseString>} for more information - on parsing strings containing C{<TAB>}s, and suggested methods to maintain a - consistent view of the parsed string, the parse location, and line and column - positions within the parsed string. - """ - return strg.count("\n",0,loc) + 1 - -def line( loc, strg ): - """Returns the line of text containing loc within a string, counting newlines as line separators. - """ - lastCR = strg.rfind("\n", 0, loc) - nextCR = strg.find("\n", loc) - if nextCR >= 0: - return strg[lastCR+1:nextCR] - else: - return strg[lastCR+1:] - -def _defaultStartDebugAction( instring, loc, expr ): - print (("Match " + _ustr(expr) + " at loc " + _ustr(loc) + "(%d,%d)" % ( lineno(loc,instring), col(loc,instring) ))) - -def _defaultSuccessDebugAction( instring, startloc, endloc, expr, toks ): - print ("Matched " + _ustr(expr) + " -> " + str(toks.asList())) - -def _defaultExceptionDebugAction( instring, loc, expr, exc ): - print ("Exception raised:" + _ustr(exc)) - -def nullDebugAction(*args): - """'Do-nothing' debug action, to suppress debugging output during parsing.""" - pass - -# Only works on Python 3.x - nonlocal is toxic to Python 2 installs -#~ 'decorator to trim function calls to match the arity of the target' -#~ def _trim_arity(func, maxargs=3): - #~ if func in singleArgBuiltins: - #~ return lambda s,l,t: func(t) - #~ limit = 0 - #~ foundArity = False - #~ def wrapper(*args): - #~ nonlocal limit,foundArity - #~ while 1: - #~ try: - #~ ret = func(*args[limit:]) - #~ foundArity = True - #~ return ret - #~ except TypeError: - #~ if limit == maxargs or foundArity: - #~ raise - #~ limit += 1 - #~ continue - #~ return wrapper - -# this version is Python 2.x-3.x cross-compatible -'decorator to trim function calls to match the arity of the target' -def _trim_arity(func, maxargs=2): - if func in singleArgBuiltins: - return lambda s,l,t: func(t) - limit = [0] - foundArity = [False] - - # traceback return data structure changed in Py3.5 - normalize back to plain tuples - if system_version[:2] >= (3,5): - def extract_stack(limit=0): - # special handling for Python 3.5.0 - extra deep call stack by 1 - offset = -3 if system_version == (3,5,0) else -2 - frame_summary = traceback.extract_stack(limit=-offset+limit-1)[offset] - return [frame_summary[:2]] - def extract_tb(tb, limit=0): - frames = traceback.extract_tb(tb, limit=limit) - frame_summary = frames[-1] - return [frame_summary[:2]] - else: - extract_stack = traceback.extract_stack - extract_tb = traceback.extract_tb - - # synthesize what would be returned by traceback.extract_stack at the call to - # user's parse action 'func', so that we don't incur call penalty at parse time - - LINE_DIFF = 6 - # IF ANY CODE CHANGES, EVEN JUST COMMENTS OR BLANK LINES, BETWEEN THE NEXT LINE AND - # THE CALL TO FUNC INSIDE WRAPPER, LINE_DIFF MUST BE MODIFIED!!!! - this_line = extract_stack(limit=2)[-1] - pa_call_line_synth = (this_line[0], this_line[1]+LINE_DIFF) - - def wrapper(*args): - while 1: - try: - ret = func(*args[limit[0]:]) - foundArity[0] = True - return ret - except TypeError: - # re-raise TypeErrors if they did not come from our arity testing - if foundArity[0]: - raise - else: - try: - tb = sys.exc_info()[-1] - if not extract_tb(tb, limit=2)[-1][:2] == pa_call_line_synth: - raise - finally: - del tb - - if limit[0] <= maxargs: - limit[0] += 1 - continue - raise - - # copy func name to wrapper for sensible debug output - func_name = "<parse action>" - try: - func_name = getattr(func, '__name__', - getattr(func, '__class__').__name__) - except Exception: - func_name = str(func) - wrapper.__name__ = func_name - - return wrapper - -class ParserElement(object): - """Abstract base level parser element class.""" - DEFAULT_WHITE_CHARS = " \n\t\r" - verbose_stacktrace = False - - @staticmethod - def setDefaultWhitespaceChars( chars ): - r""" - Overrides the default whitespace chars - - Example:: - # default whitespace chars are space, <TAB> and newline - OneOrMore(Word(alphas)).parseString("abc def\nghi jkl") # -> ['abc', 'def', 'ghi', 'jkl'] - - # change to just treat newline as significant - ParserElement.setDefaultWhitespaceChars(" \t") - OneOrMore(Word(alphas)).parseString("abc def\nghi jkl") # -> ['abc', 'def'] - """ - ParserElement.DEFAULT_WHITE_CHARS = chars - - @staticmethod - def inlineLiteralsUsing(cls): - """ - Set class to be used for inclusion of string literals into a parser. - - Example:: - # default literal class used is Literal - integer = Word(nums) - date_str = integer("year") + '/' + integer("month") + '/' + integer("day") - - date_str.parseString("1999/12/31") # -> ['1999', '/', '12', '/', '31'] - - - # change to Suppress - ParserElement.inlineLiteralsUsing(Suppress) - date_str = integer("year") + '/' + integer("month") + '/' + integer("day") - - date_str.parseString("1999/12/31") # -> ['1999', '12', '31'] - """ - ParserElement._literalStringClass = cls - - def __init__( self, savelist=False ): - self.parseAction = list() - self.failAction = None - #~ self.name = "<unknown>" # don't define self.name, let subclasses try/except upcall - self.strRepr = None - self.resultsName = None - self.saveAsList = savelist - self.skipWhitespace = True - self.whiteChars = ParserElement.DEFAULT_WHITE_CHARS - self.copyDefaultWhiteChars = True - self.mayReturnEmpty = False # used when checking for left-recursion - self.keepTabs = False - self.ignoreExprs = list() - self.debug = False - self.streamlined = False - self.mayIndexError = True # used to optimize exception handling for subclasses that don't advance parse index - self.errmsg = "" - self.modalResults = True # used to mark results names as modal (report only last) or cumulative (list all) - self.debugActions = ( None, None, None ) #custom debug actions - self.re = None - self.callPreparse = True # used to avoid redundant calls to preParse - self.callDuringTry = False - - def copy( self ): - """ - Make a copy of this C{ParserElement}. Useful for defining different parse actions - for the same parsing pattern, using copies of the original parse element. - - Example:: - integer = Word(nums).setParseAction(lambda toks: int(toks[0])) - integerK = integer.copy().addParseAction(lambda toks: toks[0]*1024) + Suppress("K") - integerM = integer.copy().addParseAction(lambda toks: toks[0]*1024*1024) + Suppress("M") - - print(OneOrMore(integerK | integerM | integer).parseString("5K 100 640K 256M")) - prints:: - [5120, 100, 655360, 268435456] - Equivalent form of C{expr.copy()} is just C{expr()}:: - integerM = integer().addParseAction(lambda toks: toks[0]*1024*1024) + Suppress("M") - """ - cpy = copy.copy( self ) - cpy.parseAction = self.parseAction[:] - cpy.ignoreExprs = self.ignoreExprs[:] - if self.copyDefaultWhiteChars: - cpy.whiteChars = ParserElement.DEFAULT_WHITE_CHARS - return cpy - - def setName( self, name ): - """ - Define name for this expression, makes debugging and exception messages clearer. - - Example:: - Word(nums).parseString("ABC") # -> Exception: Expected W:(0123...) (at char 0), (line:1, col:1) - Word(nums).setName("integer").parseString("ABC") # -> Exception: Expected integer (at char 0), (line:1, col:1) - """ - self.name = name - self.errmsg = "Expected " + self.name - if hasattr(self,"exception"): - self.exception.msg = self.errmsg - return self - - def setResultsName( self, name, listAllMatches=False ): - """ - Define name for referencing matching tokens as a nested attribute - of the returned parse results. - NOTE: this returns a *copy* of the original C{ParserElement} object; - this is so that the client can define a basic element, such as an - integer, and reference it in multiple places with different names. - - You can also set results names using the abbreviated syntax, - C{expr("name")} in place of C{expr.setResultsName("name")} - - see L{I{__call__}<__call__>}. - - Example:: - date_str = (integer.setResultsName("year") + '/' - + integer.setResultsName("month") + '/' - + integer.setResultsName("day")) - - # equivalent form: - date_str = integer("year") + '/' + integer("month") + '/' + integer("day") - """ - newself = self.copy() - if name.endswith("*"): - name = name[:-1] - listAllMatches=True - newself.resultsName = name - newself.modalResults = not listAllMatches - return newself - - def setBreak(self,breakFlag = True): - """Method to invoke the Python pdb debugger when this element is - about to be parsed. Set C{breakFlag} to True to enable, False to - disable. - """ - if breakFlag: - _parseMethod = self._parse - def breaker(instring, loc, doActions=True, callPreParse=True): - import pdb - pdb.set_trace() - return _parseMethod( instring, loc, doActions, callPreParse ) - breaker._originalParseMethod = _parseMethod - self._parse = breaker - else: - if hasattr(self._parse,"_originalParseMethod"): - self._parse = self._parse._originalParseMethod - return self - - def setParseAction( self, *fns, **kwargs ): - """ - Define one or more actions to perform when successfully matching parse element definition. - Parse action fn is a callable method with 0-3 arguments, called as C{fn(s,loc,toks)}, - C{fn(loc,toks)}, C{fn(toks)}, or just C{fn()}, where: - - s = the original string being parsed (see note below) - - loc = the location of the matching substring - - toks = a list of the matched tokens, packaged as a C{L{ParseResults}} object - If the functions in fns modify the tokens, they can return them as the return - value from fn, and the modified list of tokens will replace the original. - Otherwise, fn does not need to return any value. - - Optional keyword arguments: - - callDuringTry = (default=C{False}) indicate if parse action should be run during lookaheads and alternate testing - - Note: the default parsing behavior is to expand tabs in the input string - before starting the parsing process. See L{I{parseString}<parseString>} for more information - on parsing strings containing C{<TAB>}s, and suggested methods to maintain a - consistent view of the parsed string, the parse location, and line and column - positions within the parsed string. - - Example:: - integer = Word(nums) - date_str = integer + '/' + integer + '/' + integer - - date_str.parseString("1999/12/31") # -> ['1999', '/', '12', '/', '31'] - - # use parse action to convert to ints at parse time - integer = Word(nums).setParseAction(lambda toks: int(toks[0])) - date_str = integer + '/' + integer + '/' + integer - - # note that integer fields are now ints, not strings - date_str.parseString("1999/12/31") # -> [1999, '/', 12, '/', 31] - """ - self.parseAction = list(map(_trim_arity, list(fns))) - self.callDuringTry = kwargs.get("callDuringTry", False) - return self - - def addParseAction( self, *fns, **kwargs ): - """ - Add one or more parse actions to expression's list of parse actions. See L{I{setParseAction}<setParseAction>}. - - See examples in L{I{copy}<copy>}. - """ - self.parseAction += list(map(_trim_arity, list(fns))) - self.callDuringTry = self.callDuringTry or kwargs.get("callDuringTry", False) - return self - - def addCondition(self, *fns, **kwargs): - """Add a boolean predicate function to expression's list of parse actions. See - L{I{setParseAction}<setParseAction>} for function call signatures. Unlike C{setParseAction}, - functions passed to C{addCondition} need to return boolean success/fail of the condition. - - Optional keyword arguments: - - message = define a custom message to be used in the raised exception - - fatal = if True, will raise ParseFatalException to stop parsing immediately; otherwise will raise ParseException - - Example:: - integer = Word(nums).setParseAction(lambda toks: int(toks[0])) - year_int = integer.copy() - year_int.addCondition(lambda toks: toks[0] >= 2000, message="Only support years 2000 and later") - date_str = year_int + '/' + integer + '/' + integer - - result = date_str.parseString("1999/12/31") # -> Exception: Only support years 2000 and later (at char 0), (line:1, col:1) - """ - msg = kwargs.get("message", "failed user-defined condition") - exc_type = ParseFatalException if kwargs.get("fatal", False) else ParseException - for fn in fns: - def pa(s,l,t): - if not bool(_trim_arity(fn)(s,l,t)): - raise exc_type(s,l,msg) - self.parseAction.append(pa) - self.callDuringTry = self.callDuringTry or kwargs.get("callDuringTry", False) - return self - - def setFailAction( self, fn ): - """Define action to perform if parsing fails at this expression. - Fail acton fn is a callable function that takes the arguments - C{fn(s,loc,expr,err)} where: - - s = string being parsed - - loc = location where expression match was attempted and failed - - expr = the parse expression that failed - - err = the exception thrown - The function returns no value. It may throw C{L{ParseFatalException}} - if it is desired to stop parsing immediately.""" - self.failAction = fn - return self - - def _skipIgnorables( self, instring, loc ): - exprsFound = True - while exprsFound: - exprsFound = False - for e in self.ignoreExprs: - try: - while 1: - loc,dummy = e._parse( instring, loc ) - exprsFound = True - except ParseException: - pass - return loc - - def preParse( self, instring, loc ): - if self.ignoreExprs: - loc = self._skipIgnorables( instring, loc ) - - if self.skipWhitespace: - wt = self.whiteChars - instrlen = len(instring) - while loc < instrlen and instring[loc] in wt: - loc += 1 - - return loc - - def parseImpl( self, instring, loc, doActions=True ): - return loc, [] - - def postParse( self, instring, loc, tokenlist ): - return tokenlist - - #~ @profile - def _parseNoCache( self, instring, loc, doActions=True, callPreParse=True ): - debugging = ( self.debug ) #and doActions ) - - if debugging or self.failAction: - #~ print ("Match",self,"at loc",loc,"(%d,%d)" % ( lineno(loc,instring), col(loc,instring) )) - if (self.debugActions[0] ): - self.debugActions[0]( instring, loc, self ) - if callPreParse and self.callPreparse: - preloc = self.preParse( instring, loc ) - else: - preloc = loc - tokensStart = preloc - try: - try: - loc,tokens = self.parseImpl( instring, preloc, doActions ) - except IndexError: - raise ParseException( instring, len(instring), self.errmsg, self ) - except ParseBaseException as err: - #~ print ("Exception raised:", err) - if self.debugActions[2]: - self.debugActions[2]( instring, tokensStart, self, err ) - if self.failAction: - self.failAction( instring, tokensStart, self, err ) - raise - else: - if callPreParse and self.callPreparse: - preloc = self.preParse( instring, loc ) - else: - preloc = loc - tokensStart = preloc - if self.mayIndexError or preloc >= len(instring): - try: - loc,tokens = self.parseImpl( instring, preloc, doActions ) - except IndexError: - raise ParseException( instring, len(instring), self.errmsg, self ) - else: - loc,tokens = self.parseImpl( instring, preloc, doActions ) - - tokens = self.postParse( instring, loc, tokens ) - - retTokens = ParseResults( tokens, self.resultsName, asList=self.saveAsList, modal=self.modalResults ) - if self.parseAction and (doActions or self.callDuringTry): - if debugging: - try: - for fn in self.parseAction: - tokens = fn( instring, tokensStart, retTokens ) - if tokens is not None: - retTokens = ParseResults( tokens, - self.resultsName, - asList=self.saveAsList and isinstance(tokens,(ParseResults,list)), - modal=self.modalResults ) - except ParseBaseException as err: - #~ print "Exception raised in user parse action:", err - if (self.debugActions[2] ): - self.debugActions[2]( instring, tokensStart, self, err ) - raise - else: - for fn in self.parseAction: - tokens = fn( instring, tokensStart, retTokens ) - if tokens is not None: - retTokens = ParseResults( tokens, - self.resultsName, - asList=self.saveAsList and isinstance(tokens,(ParseResults,list)), - modal=self.modalResults ) - if debugging: - #~ print ("Matched",self,"->",retTokens.asList()) - if (self.debugActions[1] ): - self.debugActions[1]( instring, tokensStart, loc, self, retTokens ) - - return loc, retTokens - - def tryParse( self, instring, loc ): - try: - return self._parse( instring, loc, doActions=False )[0] - except ParseFatalException: - raise ParseException( instring, loc, self.errmsg, self) - - def canParseNext(self, instring, loc): - try: - self.tryParse(instring, loc) - except (ParseException, IndexError): - return False - else: - return True - - class _UnboundedCache(object): - def __init__(self): - cache = {} - self.not_in_cache = not_in_cache = object() - - def get(self, key): - return cache.get(key, not_in_cache) - - def set(self, key, value): - cache[key] = value - - def clear(self): - cache.clear() - - def cache_len(self): - return len(cache) - - self.get = types.MethodType(get, self) - self.set = types.MethodType(set, self) - self.clear = types.MethodType(clear, self) - self.__len__ = types.MethodType(cache_len, self) - - if _OrderedDict is not None: - class _FifoCache(object): - def __init__(self, size): - self.not_in_cache = not_in_cache = object() - - cache = _OrderedDict() - - def get(self, key): - return cache.get(key, not_in_cache) - - def set(self, key, value): - cache[key] = value - while len(cache) > size: - try: - cache.popitem(False) - except KeyError: - pass - - def clear(self): - cache.clear() - - def cache_len(self): - return len(cache) - - self.get = types.MethodType(get, self) - self.set = types.MethodType(set, self) - self.clear = types.MethodType(clear, self) - self.__len__ = types.MethodType(cache_len, self) - - else: - class _FifoCache(object): - def __init__(self, size): - self.not_in_cache = not_in_cache = object() - - cache = {} - key_fifo = collections.deque([], size) - - def get(self, key): - return cache.get(key, not_in_cache) - - def set(self, key, value): - cache[key] = value - while len(key_fifo) > size: - cache.pop(key_fifo.popleft(), None) - key_fifo.append(key) - - def clear(self): - cache.clear() - key_fifo.clear() - - def cache_len(self): - return len(cache) - - self.get = types.MethodType(get, self) - self.set = types.MethodType(set, self) - self.clear = types.MethodType(clear, self) - self.__len__ = types.MethodType(cache_len, self) - - # argument cache for optimizing repeated calls when backtracking through recursive expressions - packrat_cache = {} # this is set later by enabledPackrat(); this is here so that resetCache() doesn't fail - packrat_cache_lock = RLock() - packrat_cache_stats = [0, 0] - - # this method gets repeatedly called during backtracking with the same arguments - - # we can cache these arguments and save ourselves the trouble of re-parsing the contained expression - def _parseCache( self, instring, loc, doActions=True, callPreParse=True ): - HIT, MISS = 0, 1 - lookup = (self, instring, loc, callPreParse, doActions) - with ParserElement.packrat_cache_lock: - cache = ParserElement.packrat_cache - value = cache.get(lookup) - if value is cache.not_in_cache: - ParserElement.packrat_cache_stats[MISS] += 1 - try: - value = self._parseNoCache(instring, loc, doActions, callPreParse) - except ParseBaseException as pe: - # cache a copy of the exception, without the traceback - cache.set(lookup, pe.__class__(*pe.args)) - raise - else: - cache.set(lookup, (value[0], value[1].copy())) - return value - else: - ParserElement.packrat_cache_stats[HIT] += 1 - if isinstance(value, Exception): - raise value - return (value[0], value[1].copy()) - - _parse = _parseNoCache - - @staticmethod - def resetCache(): - ParserElement.packrat_cache.clear() - ParserElement.packrat_cache_stats[:] = [0] * len(ParserElement.packrat_cache_stats) - - _packratEnabled = False - @staticmethod - def enablePackrat(cache_size_limit=128): - """Enables "packrat" parsing, which adds memoizing to the parsing logic. - Repeated parse attempts at the same string location (which happens - often in many complex grammars) can immediately return a cached value, - instead of re-executing parsing/validating code. Memoizing is done of - both valid results and parsing exceptions. - - Parameters: - - cache_size_limit - (default=C{128}) - if an integer value is provided - will limit the size of the packrat cache; if None is passed, then - the cache size will be unbounded; if 0 is passed, the cache will - be effectively disabled. - - This speedup may break existing programs that use parse actions that - have side-effects. For this reason, packrat parsing is disabled when - you first import pyparsing. To activate the packrat feature, your - program must call the class method C{ParserElement.enablePackrat()}. If - your program uses C{psyco} to "compile as you go", you must call - C{enablePackrat} before calling C{psyco.full()}. If you do not do this, - Python will crash. For best results, call C{enablePackrat()} immediately - after importing pyparsing. - - Example:: - import pyparsing - pyparsing.ParserElement.enablePackrat() - """ - if not ParserElement._packratEnabled: - ParserElement._packratEnabled = True - if cache_size_limit is None: - ParserElement.packrat_cache = ParserElement._UnboundedCache() - else: - ParserElement.packrat_cache = ParserElement._FifoCache(cache_size_limit) - ParserElement._parse = ParserElement._parseCache - - def parseString( self, instring, parseAll=False ): - """ - Execute the parse expression with the given string. - This is the main interface to the client code, once the complete - expression has been built. - - If you want the grammar to require that the entire input string be - successfully parsed, then set C{parseAll} to True (equivalent to ending - the grammar with C{L{StringEnd()}}). - - Note: C{parseString} implicitly calls C{expandtabs()} on the input string, - in order to report proper column numbers in parse actions. - If the input string contains tabs and - the grammar uses parse actions that use the C{loc} argument to index into the - string being parsed, you can ensure you have a consistent view of the input - string by: - - calling C{parseWithTabs} on your grammar before calling C{parseString} - (see L{I{parseWithTabs}<parseWithTabs>}) - - define your parse action using the full C{(s,loc,toks)} signature, and - reference the input string using the parse action's C{s} argument - - explictly expand the tabs in your input string before calling - C{parseString} - - Example:: - Word('a').parseString('aaaaabaaa') # -> ['aaaaa'] - Word('a').parseString('aaaaabaaa', parseAll=True) # -> Exception: Expected end of text - """ - ParserElement.resetCache() - if not self.streamlined: - self.streamline() - #~ self.saveAsList = True - for e in self.ignoreExprs: - e.streamline() - if not self.keepTabs: - instring = instring.expandtabs() - try: - loc, tokens = self._parse( instring, 0 ) - if parseAll: - loc = self.preParse( instring, loc ) - se = Empty() + StringEnd() - se._parse( instring, loc ) - except ParseBaseException as exc: - if ParserElement.verbose_stacktrace: - raise - else: - # catch and re-raise exception from here, clears out pyparsing internal stack trace - raise exc - else: - return tokens - - def scanString( self, instring, maxMatches=_MAX_INT, overlap=False ): - """ - Scan the input string for expression matches. Each match will return the - matching tokens, start location, and end location. May be called with optional - C{maxMatches} argument, to clip scanning after 'n' matches are found. If - C{overlap} is specified, then overlapping matches will be reported. - - Note that the start and end locations are reported relative to the string - being parsed. See L{I{parseString}<parseString>} for more information on parsing - strings with embedded tabs. - - Example:: - source = "sldjf123lsdjjkf345sldkjf879lkjsfd987" - print(source) - for tokens,start,end in Word(alphas).scanString(source): - print(' '*start + '^'*(end-start)) - print(' '*start + tokens[0]) - - prints:: - - sldjf123lsdjjkf345sldkjf879lkjsfd987 - ^^^^^ - sldjf - ^^^^^^^ - lsdjjkf - ^^^^^^ - sldkjf - ^^^^^^ - lkjsfd - """ - if not self.streamlined: - self.streamline() - for e in self.ignoreExprs: - e.streamline() - - if not self.keepTabs: - instring = _ustr(instring).expandtabs() - instrlen = len(instring) - loc = 0 - preparseFn = self.preParse - parseFn = self._parse - ParserElement.resetCache() - matches = 0 - try: - while loc <= instrlen and matches < maxMatches: - try: - preloc = preparseFn( instring, loc ) - nextLoc,tokens = parseFn( instring, preloc, callPreParse=False ) - except ParseException: - loc = preloc+1 - else: - if nextLoc > loc: - matches += 1 - yield tokens, preloc, nextLoc - if overlap: - nextloc = preparseFn( instring, loc ) - if nextloc > loc: - loc = nextLoc - else: - loc += 1 - else: - loc = nextLoc - else: - loc = preloc+1 - except ParseBaseException as exc: - if ParserElement.verbose_stacktrace: - raise - else: - # catch and re-raise exception from here, clears out pyparsing internal stack trace - raise exc - - def transformString( self, instring ): - """ - Extension to C{L{scanString}}, to modify matching text with modified tokens that may - be returned from a parse action. To use C{transformString}, define a grammar and - attach a parse action to it that modifies the returned token list. - Invoking C{transformString()} on a target string will then scan for matches, - and replace the matched text patterns according to the logic in the parse - action. C{transformString()} returns the resulting transformed string. - - Example:: - wd = Word(alphas) - wd.setParseAction(lambda toks: toks[0].title()) - - print(wd.transformString("now is the winter of our discontent made glorious summer by this sun of york.")) - Prints:: - Now Is The Winter Of Our Discontent Made Glorious Summer By This Sun Of York. - """ - out = [] - lastE = 0 - # force preservation of <TAB>s, to minimize unwanted transformation of string, and to - # keep string locs straight between transformString and scanString - self.keepTabs = True - try: - for t,s,e in self.scanString( instring ): - out.append( instring[lastE:s] ) - if t: - if isinstance(t,ParseResults): - out += t.asList() - elif isinstance(t,list): - out += t - else: - out.append(t) - lastE = e - out.append(instring[lastE:]) - out = [o for o in out if o] - return "".join(map(_ustr,_flatten(out))) - except ParseBaseException as exc: - if ParserElement.verbose_stacktrace: - raise - else: - # catch and re-raise exception from here, clears out pyparsing internal stack trace - raise exc - - def searchString( self, instring, maxMatches=_MAX_INT ): - """ - Another extension to C{L{scanString}}, simplifying the access to the tokens found - to match the given parse expression. May be called with optional - C{maxMatches} argument, to clip searching after 'n' matches are found. - - Example:: - # a capitalized word starts with an uppercase letter, followed by zero or more lowercase letters - cap_word = Word(alphas.upper(), alphas.lower()) - - print(cap_word.searchString("More than Iron, more than Lead, more than Gold I need Electricity")) - - # the sum() builtin can be used to merge results into a single ParseResults object - print(sum(cap_word.searchString("More than Iron, more than Lead, more than Gold I need Electricity"))) - prints:: - [['More'], ['Iron'], ['Lead'], ['Gold'], ['I'], ['Electricity']] - ['More', 'Iron', 'Lead', 'Gold', 'I', 'Electricity'] - """ - try: - return ParseResults([ t for t,s,e in self.scanString( instring, maxMatches ) ]) - except ParseBaseException as exc: - if ParserElement.verbose_stacktrace: - raise - else: - # catch and re-raise exception from here, clears out pyparsing internal stack trace - raise exc - - def split(self, instring, maxsplit=_MAX_INT, includeSeparators=False): - """ - Generator method to split a string using the given expression as a separator. - May be called with optional C{maxsplit} argument, to limit the number of splits; - and the optional C{includeSeparators} argument (default=C{False}), if the separating - matching text should be included in the split results. - - Example:: - punc = oneOf(list(".,;:/-!?")) - print(list(punc.split("This, this?, this sentence, is badly punctuated!"))) - prints:: - ['This', ' this', '', ' this sentence', ' is badly punctuated', ''] - """ - splits = 0 - last = 0 - for t,s,e in self.scanString(instring, maxMatches=maxsplit): - yield instring[last:s] - if includeSeparators: - yield t[0] - last = e - yield instring[last:] - - def __add__(self, other ): - """ - Implementation of + operator - returns C{L{And}}. Adding strings to a ParserElement - converts them to L{Literal}s by default. - - Example:: - greet = Word(alphas) + "," + Word(alphas) + "!" - hello = "Hello, World!" - print (hello, "->", greet.parseString(hello)) - Prints:: - Hello, World! -> ['Hello', ',', 'World', '!'] - """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return And( [ self, other ] ) - - def __radd__(self, other ): - """ - Implementation of + operator when left operand is not a C{L{ParserElement}} - """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return other + self - - def __sub__(self, other): - """ - Implementation of - operator, returns C{L{And}} with error stop - """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return self + And._ErrorStop() + other - - def __rsub__(self, other ): - """ - Implementation of - operator when left operand is not a C{L{ParserElement}} - """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return other - self - - def __mul__(self,other): - """ - Implementation of * operator, allows use of C{expr * 3} in place of - C{expr + expr + expr}. Expressions may also me multiplied by a 2-integer - tuple, similar to C{{min,max}} multipliers in regular expressions. Tuples - may also include C{None} as in: - - C{expr*(n,None)} or C{expr*(n,)} is equivalent - to C{expr*n + L{ZeroOrMore}(expr)} - (read as "at least n instances of C{expr}") - - C{expr*(None,n)} is equivalent to C{expr*(0,n)} - (read as "0 to n instances of C{expr}") - - C{expr*(None,None)} is equivalent to C{L{ZeroOrMore}(expr)} - - C{expr*(1,None)} is equivalent to C{L{OneOrMore}(expr)} - - Note that C{expr*(None,n)} does not raise an exception if - more than n exprs exist in the input stream; that is, - C{expr*(None,n)} does not enforce a maximum number of expr - occurrences. If this behavior is desired, then write - C{expr*(None,n) + ~expr} - """ - if isinstance(other,int): - minElements, optElements = other,0 - elif isinstance(other,tuple): - other = (other + (None, None))[:2] - if other[0] is None: - other = (0, other[1]) - if isinstance(other[0],int) and other[1] is None: - if other[0] == 0: - return ZeroOrMore(self) - if other[0] == 1: - return OneOrMore(self) - else: - return self*other[0] + ZeroOrMore(self) - elif isinstance(other[0],int) and isinstance(other[1],int): - minElements, optElements = other - optElements -= minElements - else: - raise TypeError("cannot multiply 'ParserElement' and ('%s','%s') objects", type(other[0]),type(other[1])) - else: - raise TypeError("cannot multiply 'ParserElement' and '%s' objects", type(other)) - - if minElements < 0: - raise ValueError("cannot multiply ParserElement by negative value") - if optElements < 0: - raise ValueError("second tuple value must be greater or equal to first tuple value") - if minElements == optElements == 0: - raise ValueError("cannot multiply ParserElement by 0 or (0,0)") - - if (optElements): - def makeOptionalList(n): - if n>1: - return Optional(self + makeOptionalList(n-1)) - else: - return Optional(self) - if minElements: - if minElements == 1: - ret = self + makeOptionalList(optElements) - else: - ret = And([self]*minElements) + makeOptionalList(optElements) - else: - ret = makeOptionalList(optElements) - else: - if minElements == 1: - ret = self - else: - ret = And([self]*minElements) - return ret - - def __rmul__(self, other): - return self.__mul__(other) - - def __or__(self, other ): - """ - Implementation of | operator - returns C{L{MatchFirst}} - """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return MatchFirst( [ self, other ] ) - - def __ror__(self, other ): - """ - Implementation of | operator when left operand is not a C{L{ParserElement}} - """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return other | self - - def __xor__(self, other ): - """ - Implementation of ^ operator - returns C{L{Or}} - """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return Or( [ self, other ] ) - - def __rxor__(self, other ): - """ - Implementation of ^ operator when left operand is not a C{L{ParserElement}} - """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return other ^ self - - def __and__(self, other ): - """ - Implementation of & operator - returns C{L{Each}} - """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return Each( [ self, other ] ) - - def __rand__(self, other ): - """ - Implementation of & operator when left operand is not a C{L{ParserElement}} - """ - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - if not isinstance( other, ParserElement ): - warnings.warn("Cannot combine element of type %s with ParserElement" % type(other), - SyntaxWarning, stacklevel=2) - return None - return other & self - - def __invert__( self ): - """ - Implementation of ~ operator - returns C{L{NotAny}} - """ - return NotAny( self ) - - def __call__(self, name=None): - """ - Shortcut for C{L{setResultsName}}, with C{listAllMatches=False}. - - If C{name} is given with a trailing C{'*'} character, then C{listAllMatches} will be - passed as C{True}. - - If C{name} is omitted, same as calling C{L{copy}}. - - Example:: - # these are equivalent - userdata = Word(alphas).setResultsName("name") + Word(nums+"-").setResultsName("socsecno") - userdata = Word(alphas)("name") + Word(nums+"-")("socsecno") - """ - if name is not None: - return self.setResultsName(name) - else: - return self.copy() - - def suppress( self ): - """ - Suppresses the output of this C{ParserElement}; useful to keep punctuation from - cluttering up returned output. - """ - return Suppress( self ) - - def leaveWhitespace( self ): - """ - Disables the skipping of whitespace before matching the characters in the - C{ParserElement}'s defined pattern. This is normally only used internally by - the pyparsing module, but may be needed in some whitespace-sensitive grammars. - """ - self.skipWhitespace = False - return self - - def setWhitespaceChars( self, chars ): - """ - Overrides the default whitespace chars - """ - self.skipWhitespace = True - self.whiteChars = chars - self.copyDefaultWhiteChars = False - return self - - def parseWithTabs( self ): - """ - Overrides default behavior to expand C{<TAB>}s to spaces before parsing the input string. - Must be called before C{parseString} when the input grammar contains elements that - match C{<TAB>} characters. - """ - self.keepTabs = True - return self - - def ignore( self, other ): - """ - Define expression to be ignored (e.g., comments) while doing pattern - matching; may be called repeatedly, to define multiple comment or other - ignorable patterns. - - Example:: - patt = OneOrMore(Word(alphas)) - patt.parseString('ablaj /* comment */ lskjd') # -> ['ablaj'] - - patt.ignore(cStyleComment) - patt.parseString('ablaj /* comment */ lskjd') # -> ['ablaj', 'lskjd'] - """ - if isinstance(other, basestring): - other = Suppress(other) - - if isinstance( other, Suppress ): - if other not in self.ignoreExprs: - self.ignoreExprs.append(other) - else: - self.ignoreExprs.append( Suppress( other.copy() ) ) - return self - - def setDebugActions( self, startAction, successAction, exceptionAction ): - """ - Enable display of debugging messages while doing pattern matching. - """ - self.debugActions = (startAction or _defaultStartDebugAction, - successAction or _defaultSuccessDebugAction, - exceptionAction or _defaultExceptionDebugAction) - self.debug = True - return self - - def setDebug( self, flag=True ): - """ - Enable display of debugging messages while doing pattern matching. - Set C{flag} to True to enable, False to disable. - - Example:: - wd = Word(alphas).setName("alphaword") - integer = Word(nums).setName("numword") - term = wd | integer - - # turn on debugging for wd - wd.setDebug() - - OneOrMore(term).parseString("abc 123 xyz 890") - - prints:: - Match alphaword at loc 0(1,1) - Matched alphaword -> ['abc'] - Match alphaword at loc 3(1,4) - Exception raised:Expected alphaword (at char 4), (line:1, col:5) - Match alphaword at loc 7(1,8) - Matched alphaword -> ['xyz'] - Match alphaword at loc 11(1,12) - Exception raised:Expected alphaword (at char 12), (line:1, col:13) - Match alphaword at loc 15(1,16) - Exception raised:Expected alphaword (at char 15), (line:1, col:16) - - The output shown is that produced by the default debug actions - custom debug actions can be - specified using L{setDebugActions}. Prior to attempting - to match the C{wd} expression, the debugging message C{"Match <exprname> at loc <n>(<line>,<col>)"} - is shown. Then if the parse succeeds, a C{"Matched"} message is shown, or an C{"Exception raised"} - message is shown. Also note the use of L{setName} to assign a human-readable name to the expression, - which makes debugging and exception messages easier to understand - for instance, the default - name created for the C{Word} expression without calling C{setName} is C{"W:(ABCD...)"}. - """ - if flag: - self.setDebugActions( _defaultStartDebugAction, _defaultSuccessDebugAction, _defaultExceptionDebugAction ) - else: - self.debug = False - return self - - def __str__( self ): - return self.name - - def __repr__( self ): - return _ustr(self) - - def streamline( self ): - self.streamlined = True - self.strRepr = None - return self - - def checkRecursion( self, parseElementList ): - pass - - def validate( self, validateTrace=[] ): - """ - Check defined expressions for valid structure, check for infinite recursive definitions. - """ - self.checkRecursion( [] ) - - def parseFile( self, file_or_filename, parseAll=False ): - """ - Execute the parse expression on the given file or filename. - If a filename is specified (instead of a file object), - the entire file is opened, read, and closed before parsing. - """ - try: - file_contents = file_or_filename.read() - except AttributeError: - with open(file_or_filename, "r") as f: - file_contents = f.read() - try: - return self.parseString(file_contents, parseAll) - except ParseBaseException as exc: - if ParserElement.verbose_stacktrace: - raise - else: - # catch and re-raise exception from here, clears out pyparsing internal stack trace - raise exc - - def __eq__(self,other): - if isinstance(other, ParserElement): - return self is other or vars(self) == vars(other) - elif isinstance(other, basestring): - return self.matches(other) - else: - return super(ParserElement,self)==other - - def __ne__(self,other): - return not (self == other) - - def __hash__(self): - return hash(id(self)) - - def __req__(self,other): - return self == other - - def __rne__(self,other): - return not (self == other) - - def matches(self, testString, parseAll=True): - """ - Method for quick testing of a parser against a test string. Good for simple - inline microtests of sub expressions while building up larger parser. - - Parameters: - - testString - to test against this expression for a match - - parseAll - (default=C{True}) - flag to pass to C{L{parseString}} when running tests - - Example:: - expr = Word(nums) - assert expr.matches("100") - """ - try: - self.parseString(_ustr(testString), parseAll=parseAll) - return True - except ParseBaseException: - return False - - def runTests(self, tests, parseAll=True, comment='#', fullDump=True, printResults=True, failureTests=False): - """ - Execute the parse expression on a series of test strings, showing each - test, the parsed results or where the parse failed. Quick and easy way to - run a parse expression against a list of sample strings. - - Parameters: - - tests - a list of separate test strings, or a multiline string of test strings - - parseAll - (default=C{True}) - flag to pass to C{L{parseString}} when running tests - - comment - (default=C{'#'}) - expression for indicating embedded comments in the test - string; pass None to disable comment filtering - - fullDump - (default=C{True}) - dump results as list followed by results names in nested outline; - if False, only dump nested list - - printResults - (default=C{True}) prints test output to stdout - - failureTests - (default=C{False}) indicates if these tests are expected to fail parsing - - Returns: a (success, results) tuple, where success indicates that all tests succeeded - (or failed if C{failureTests} is True), and the results contain a list of lines of each - test's output - - Example:: - number_expr = pyparsing_common.number.copy() - - result = number_expr.runTests(''' - # unsigned integer - 100 - # negative integer - -100 - # float with scientific notation - 6.02e23 - # integer with scientific notation - 1e-12 - ''') - print("Success" if result[0] else "Failed!") - - result = number_expr.runTests(''' - # stray character - 100Z - # missing leading digit before '.' - -.100 - # too many '.' - 3.14.159 - ''', failureTests=True) - print("Success" if result[0] else "Failed!") - prints:: - # unsigned integer - 100 - [100] - - # negative integer - -100 - [-100] - - # float with scientific notation - 6.02e23 - [6.02e+23] - - # integer with scientific notation - 1e-12 - [1e-12] - - Success - - # stray character - 100Z - ^ - FAIL: Expected end of text (at char 3), (line:1, col:4) - - # missing leading digit before '.' - -.100 - ^ - FAIL: Expected {real number with scientific notation | real number | signed integer} (at char 0), (line:1, col:1) - - # too many '.' - 3.14.159 - ^ - FAIL: Expected end of text (at char 4), (line:1, col:5) - - Success - - Each test string must be on a single line. If you want to test a string that spans multiple - lines, create a test like this:: - - expr.runTest(r"this is a test\\n of strings that spans \\n 3 lines") - - (Note that this is a raw string literal, you must include the leading 'r'.) - """ - if isinstance(tests, basestring): - tests = list(map(str.strip, tests.rstrip().splitlines())) - if isinstance(comment, basestring): - comment = Literal(comment) - allResults = [] - comments = [] - success = True - for t in tests: - if comment is not None and comment.matches(t, False) or comments and not t: - comments.append(t) - continue - if not t: - continue - out = ['\n'.join(comments), t] - comments = [] - try: - t = t.replace(r'\n','\n') - result = self.parseString(t, parseAll=parseAll) - out.append(result.dump(full=fullDump)) - success = success and not failureTests - except ParseBaseException as pe: - fatal = "(FATAL)" if isinstance(pe, ParseFatalException) else "" - if '\n' in t: - out.append(line(pe.loc, t)) - out.append(' '*(col(pe.loc,t)-1) + '^' + fatal) - else: - out.append(' '*pe.loc + '^' + fatal) - out.append("FAIL: " + str(pe)) - success = success and failureTests - result = pe - except Exception as exc: - out.append("FAIL-EXCEPTION: " + str(exc)) - success = success and failureTests - result = exc - - if printResults: - if fullDump: - out.append('') - print('\n'.join(out)) - - allResults.append((t, result)) - - return success, allResults - - -class Token(ParserElement): - """ - Abstract C{ParserElement} subclass, for defining atomic matching patterns. - """ - def __init__( self ): - super(Token,self).__init__( savelist=False ) - - -class Empty(Token): - """ - An empty token, will always match. - """ - def __init__( self ): - super(Empty,self).__init__() - self.name = "Empty" - self.mayReturnEmpty = True - self.mayIndexError = False - - -class NoMatch(Token): - """ - A token that will never match. - """ - def __init__( self ): - super(NoMatch,self).__init__() - self.name = "NoMatch" - self.mayReturnEmpty = True - self.mayIndexError = False - self.errmsg = "Unmatchable token" - - def parseImpl( self, instring, loc, doActions=True ): - raise ParseException(instring, loc, self.errmsg, self) - - -class Literal(Token): - """ - Token to exactly match a specified string. - - Example:: - Literal('blah').parseString('blah') # -> ['blah'] - Literal('blah').parseString('blahfooblah') # -> ['blah'] - Literal('blah').parseString('bla') # -> Exception: Expected "blah" - - For case-insensitive matching, use L{CaselessLiteral}. - - For keyword matching (force word break before and after the matched string), - use L{Keyword} or L{CaselessKeyword}. - """ - def __init__( self, matchString ): - super(Literal,self).__init__() - self.match = matchString - self.matchLen = len(matchString) - try: - self.firstMatchChar = matchString[0] - except IndexError: - warnings.warn("null string passed to Literal; use Empty() instead", - SyntaxWarning, stacklevel=2) - self.__class__ = Empty - self.name = '"%s"' % _ustr(self.match) - self.errmsg = "Expected " + self.name - self.mayReturnEmpty = False - self.mayIndexError = False - - # Performance tuning: this routine gets called a *lot* - # if this is a single character match string and the first character matches, - # short-circuit as quickly as possible, and avoid calling startswith - #~ @profile - def parseImpl( self, instring, loc, doActions=True ): - if (instring[loc] == self.firstMatchChar and - (self.matchLen==1 or instring.startswith(self.match,loc)) ): - return loc+self.matchLen, self.match - raise ParseException(instring, loc, self.errmsg, self) -_L = Literal -ParserElement._literalStringClass = Literal - -class Keyword(Token): - """ - Token to exactly match a specified string as a keyword, that is, it must be - immediately followed by a non-keyword character. Compare with C{L{Literal}}: - - C{Literal("if")} will match the leading C{'if'} in C{'ifAndOnlyIf'}. - - C{Keyword("if")} will not; it will only match the leading C{'if'} in C{'if x=1'}, or C{'if(y==2)'} - Accepts two optional constructor arguments in addition to the keyword string: - - C{identChars} is a string of characters that would be valid identifier characters, - defaulting to all alphanumerics + "_" and "$" - - C{caseless} allows case-insensitive matching, default is C{False}. - - Example:: - Keyword("start").parseString("start") # -> ['start'] - Keyword("start").parseString("starting") # -> Exception - - For case-insensitive matching, use L{CaselessKeyword}. - """ - DEFAULT_KEYWORD_CHARS = alphanums+"_$" - - def __init__( self, matchString, identChars=None, caseless=False ): - super(Keyword,self).__init__() - if identChars is None: - identChars = Keyword.DEFAULT_KEYWORD_CHARS - self.match = matchString - self.matchLen = len(matchString) - try: - self.firstMatchChar = matchString[0] - except IndexError: - warnings.warn("null string passed to Keyword; use Empty() instead", - SyntaxWarning, stacklevel=2) - self.name = '"%s"' % self.match - self.errmsg = "Expected " + self.name - self.mayReturnEmpty = False - self.mayIndexError = False - self.caseless = caseless - if caseless: - self.caselessmatch = matchString.upper() - identChars = identChars.upper() - self.identChars = set(identChars) - - def parseImpl( self, instring, loc, doActions=True ): - if self.caseless: - if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and - (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) and - (loc == 0 or instring[loc-1].upper() not in self.identChars) ): - return loc+self.matchLen, self.match - else: - if (instring[loc] == self.firstMatchChar and - (self.matchLen==1 or instring.startswith(self.match,loc)) and - (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen] not in self.identChars) and - (loc == 0 or instring[loc-1] not in self.identChars) ): - return loc+self.matchLen, self.match - raise ParseException(instring, loc, self.errmsg, self) - - def copy(self): - c = super(Keyword,self).copy() - c.identChars = Keyword.DEFAULT_KEYWORD_CHARS - return c - - @staticmethod - def setDefaultKeywordChars( chars ): - """Overrides the default Keyword chars - """ - Keyword.DEFAULT_KEYWORD_CHARS = chars - -class CaselessLiteral(Literal): - """ - Token to match a specified string, ignoring case of letters. - Note: the matched results will always be in the case of the given - match string, NOT the case of the input text. - - Example:: - OneOrMore(CaselessLiteral("CMD")).parseString("cmd CMD Cmd10") # -> ['CMD', 'CMD', 'CMD'] - - (Contrast with example for L{CaselessKeyword}.) - """ - def __init__( self, matchString ): - super(CaselessLiteral,self).__init__( matchString.upper() ) - # Preserve the defining literal. - self.returnString = matchString - self.name = "'%s'" % self.returnString - self.errmsg = "Expected " + self.name - - def parseImpl( self, instring, loc, doActions=True ): - if instring[ loc:loc+self.matchLen ].upper() == self.match: - return loc+self.matchLen, self.returnString - raise ParseException(instring, loc, self.errmsg, self) - -class CaselessKeyword(Keyword): - """ - Caseless version of L{Keyword}. - - Example:: - OneOrMore(CaselessKeyword("CMD")).parseString("cmd CMD Cmd10") # -> ['CMD', 'CMD'] - - (Contrast with example for L{CaselessLiteral}.) - """ - def __init__( self, matchString, identChars=None ): - super(CaselessKeyword,self).__init__( matchString, identChars, caseless=True ) - - def parseImpl( self, instring, loc, doActions=True ): - if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and - (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) ): - return loc+self.matchLen, self.match - raise ParseException(instring, loc, self.errmsg, self) - -class CloseMatch(Token): - """ - A variation on L{Literal} which matches "close" matches, that is, - strings with at most 'n' mismatching characters. C{CloseMatch} takes parameters: - - C{match_string} - string to be matched - - C{maxMismatches} - (C{default=1}) maximum number of mismatches allowed to count as a match - - The results from a successful parse will contain the matched text from the input string and the following named results: - - C{mismatches} - a list of the positions within the match_string where mismatches were found - - C{original} - the original match_string used to compare against the input string - - If C{mismatches} is an empty list, then the match was an exact match. - - Example:: - patt = CloseMatch("ATCATCGAATGGA") - patt.parseString("ATCATCGAAXGGA") # -> (['ATCATCGAAXGGA'], {'mismatches': [[9]], 'original': ['ATCATCGAATGGA']}) - patt.parseString("ATCAXCGAAXGGA") # -> Exception: Expected 'ATCATCGAATGGA' (with up to 1 mismatches) (at char 0), (line:1, col:1) - - # exact match - patt.parseString("ATCATCGAATGGA") # -> (['ATCATCGAATGGA'], {'mismatches': [[]], 'original': ['ATCATCGAATGGA']}) - - # close match allowing up to 2 mismatches - patt = CloseMatch("ATCATCGAATGGA", maxMismatches=2) - patt.parseString("ATCAXCGAAXGGA") # -> (['ATCAXCGAAXGGA'], {'mismatches': [[4, 9]], 'original': ['ATCATCGAATGGA']}) - """ - def __init__(self, match_string, maxMismatches=1): - super(CloseMatch,self).__init__() - self.name = match_string - self.match_string = match_string - self.maxMismatches = maxMismatches - self.errmsg = "Expected %r (with up to %d mismatches)" % (self.match_string, self.maxMismatches) - self.mayIndexError = False - self.mayReturnEmpty = False - - def parseImpl( self, instring, loc, doActions=True ): - start = loc - instrlen = len(instring) - maxloc = start + len(self.match_string) - - if maxloc <= instrlen: - match_string = self.match_string - match_stringloc = 0 - mismatches = [] - maxMismatches = self.maxMismatches - - for match_stringloc,s_m in enumerate(zip(instring[loc:maxloc], self.match_string)): - src,mat = s_m - if src != mat: - mismatches.append(match_stringloc) - if len(mismatches) > maxMismatches: - break - else: - loc = match_stringloc + 1 - results = ParseResults([instring[start:loc]]) - results['original'] = self.match_string - results['mismatches'] = mismatches - return loc, results - - raise ParseException(instring, loc, self.errmsg, self) - - -class Word(Token): - """ - Token for matching words composed of allowed character sets. - Defined with string containing all allowed initial characters, - an optional string containing allowed body characters (if omitted, - defaults to the initial character set), and an optional minimum, - maximum, and/or exact length. The default value for C{min} is 1 (a - minimum value < 1 is not valid); the default values for C{max} and C{exact} - are 0, meaning no maximum or exact length restriction. An optional - C{excludeChars} parameter can list characters that might be found in - the input C{bodyChars} string; useful to define a word of all printables - except for one or two characters, for instance. - - L{srange} is useful for defining custom character set strings for defining - C{Word} expressions, using range notation from regular expression character sets. - - A common mistake is to use C{Word} to match a specific literal string, as in - C{Word("Address")}. Remember that C{Word} uses the string argument to define - I{sets} of matchable characters. This expression would match "Add", "AAA", - "dAred", or any other word made up of the characters 'A', 'd', 'r', 'e', and 's'. - To match an exact literal string, use L{Literal} or L{Keyword}. - - pyparsing includes helper strings for building Words: - - L{alphas} - - L{nums} - - L{alphanums} - - L{hexnums} - - L{alphas8bit} (alphabetic characters in ASCII range 128-255 - accented, tilded, umlauted, etc.) - - L{punc8bit} (non-alphabetic characters in ASCII range 128-255 - currency, symbols, superscripts, diacriticals, etc.) - - L{printables} (any non-whitespace character) - - Example:: - # a word composed of digits - integer = Word(nums) # equivalent to Word("0123456789") or Word(srange("0-9")) - - # a word with a leading capital, and zero or more lowercase - capital_word = Word(alphas.upper(), alphas.lower()) - - # hostnames are alphanumeric, with leading alpha, and '-' - hostname = Word(alphas, alphanums+'-') - - # roman numeral (not a strict parser, accepts invalid mix of characters) - roman = Word("IVXLCDM") - - # any string of non-whitespace characters, except for ',' - csv_value = Word(printables, excludeChars=",") - """ - def __init__( self, initChars, bodyChars=None, min=1, max=0, exact=0, asKeyword=False, excludeChars=None ): - super(Word,self).__init__() - if excludeChars: - initChars = ''.join(c for c in initChars if c not in excludeChars) - if bodyChars: - bodyChars = ''.join(c for c in bodyChars if c not in excludeChars) - self.initCharsOrig = initChars - self.initChars = set(initChars) - if bodyChars : - self.bodyCharsOrig = bodyChars - self.bodyChars = set(bodyChars) - else: - self.bodyCharsOrig = initChars - self.bodyChars = set(initChars) - - self.maxSpecified = max > 0 - - if min < 1: - raise ValueError("cannot specify a minimum length < 1; use Optional(Word()) if zero-length word is permitted") - - self.minLen = min - - if max > 0: - self.maxLen = max - else: - self.maxLen = _MAX_INT - - if exact > 0: - self.maxLen = exact - self.minLen = exact - - self.name = _ustr(self) - self.errmsg = "Expected " + self.name - self.mayIndexError = False - self.asKeyword = asKeyword - - if ' ' not in self.initCharsOrig+self.bodyCharsOrig and (min==1 and max==0 and exact==0): - if self.bodyCharsOrig == self.initCharsOrig: - self.reString = "[%s]+" % _escapeRegexRangeChars(self.initCharsOrig) - elif len(self.initCharsOrig) == 1: - self.reString = "%s[%s]*" % \ - (re.escape(self.initCharsOrig), - _escapeRegexRangeChars(self.bodyCharsOrig),) - else: - self.reString = "[%s][%s]*" % \ - (_escapeRegexRangeChars(self.initCharsOrig), - _escapeRegexRangeChars(self.bodyCharsOrig),) - if self.asKeyword: - self.reString = r"\b"+self.reString+r"\b" - try: - self.re = re.compile( self.reString ) - except Exception: - self.re = None - - def parseImpl( self, instring, loc, doActions=True ): - if self.re: - result = self.re.match(instring,loc) - if not result: - raise ParseException(instring, loc, self.errmsg, self) - - loc = result.end() - return loc, result.group() - - if not(instring[ loc ] in self.initChars): - raise ParseException(instring, loc, self.errmsg, self) - - start = loc - loc += 1 - instrlen = len(instring) - bodychars = self.bodyChars - maxloc = start + self.maxLen - maxloc = min( maxloc, instrlen ) - while loc < maxloc and instring[loc] in bodychars: - loc += 1 - - throwException = False - if loc - start < self.minLen: - throwException = True - if self.maxSpecified and loc < instrlen and instring[loc] in bodychars: - throwException = True - if self.asKeyword: - if (start>0 and instring[start-1] in bodychars) or (loc<instrlen and instring[loc] in bodychars): - throwException = True - - if throwException: - raise ParseException(instring, loc, self.errmsg, self) - - return loc, instring[start:loc] - - def __str__( self ): - try: - return super(Word,self).__str__() - except Exception: - pass - - - if self.strRepr is None: - - def charsAsStr(s): - if len(s)>4: - return s[:4]+"..." - else: - return s - - if ( self.initCharsOrig != self.bodyCharsOrig ): - self.strRepr = "W:(%s,%s)" % ( charsAsStr(self.initCharsOrig), charsAsStr(self.bodyCharsOrig) ) - else: - self.strRepr = "W:(%s)" % charsAsStr(self.initCharsOrig) - - return self.strRepr - - -class Regex(Token): - r""" - Token for matching strings that match a given regular expression. - Defined with string specifying the regular expression in a form recognized by the inbuilt Python re module. - If the given regex contains named groups (defined using C{(?P<name>...)}), these will be preserved as - named parse results. - - Example:: - realnum = Regex(r"[+-]?\d+\.\d*") - date = Regex(r'(?P<year>\d{4})-(?P<month>\d\d?)-(?P<day>\d\d?)') - # ref: http://stackoverflow.com/questions/267399/how-do-you-match-only-valid-roman-numerals-with-a-regular-expression - roman = Regex(r"M{0,4}(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})") - """ - compiledREtype = type(re.compile("[A-Z]")) - def __init__( self, pattern, flags=0): - """The parameters C{pattern} and C{flags} are passed to the C{re.compile()} function as-is. See the Python C{re} module for an explanation of the acceptable patterns and flags.""" - super(Regex,self).__init__() - - if isinstance(pattern, basestring): - if not pattern: - warnings.warn("null string passed to Regex; use Empty() instead", - SyntaxWarning, stacklevel=2) - - self.pattern = pattern - self.flags = flags - - try: - self.re = re.compile(self.pattern, self.flags) - self.reString = self.pattern - except sre_constants.error: - warnings.warn("invalid pattern (%s) passed to Regex" % pattern, - SyntaxWarning, stacklevel=2) - raise - - elif isinstance(pattern, Regex.compiledREtype): - self.re = pattern - self.pattern = \ - self.reString = str(pattern) - self.flags = flags - - else: - raise ValueError("Regex may only be constructed with a string or a compiled RE object") - - self.name = _ustr(self) - self.errmsg = "Expected " + self.name - self.mayIndexError = False - self.mayReturnEmpty = True - - def parseImpl( self, instring, loc, doActions=True ): - result = self.re.match(instring,loc) - if not result: - raise ParseException(instring, loc, self.errmsg, self) - - loc = result.end() - d = result.groupdict() - ret = ParseResults(result.group()) - if d: - for k in d: - ret[k] = d[k] - return loc,ret - - def __str__( self ): - try: - return super(Regex,self).__str__() - except Exception: - pass - - if self.strRepr is None: - self.strRepr = "Re:(%s)" % repr(self.pattern) - - return self.strRepr - - -class QuotedString(Token): - r""" - Token for matching strings that are delimited by quoting characters. - - Defined with the following parameters: - - quoteChar - string of one or more characters defining the quote delimiting string - - escChar - character to escape quotes, typically backslash (default=C{None}) - - escQuote - special quote sequence to escape an embedded quote string (such as SQL's "" to escape an embedded ") (default=C{None}) - - multiline - boolean indicating whether quotes can span multiple lines (default=C{False}) - - unquoteResults - boolean indicating whether the matched text should be unquoted (default=C{True}) - - endQuoteChar - string of one or more characters defining the end of the quote delimited string (default=C{None} => same as quoteChar) - - convertWhitespaceEscapes - convert escaped whitespace (C{'\t'}, C{'\n'}, etc.) to actual whitespace (default=C{True}) - - Example:: - qs = QuotedString('"') - print(qs.searchString('lsjdf "This is the quote" sldjf')) - complex_qs = QuotedString('{{', endQuoteChar='}}') - print(complex_qs.searchString('lsjdf {{This is the "quote"}} sldjf')) - sql_qs = QuotedString('"', escQuote='""') - print(sql_qs.searchString('lsjdf "This is the quote with ""embedded"" quotes" sldjf')) - prints:: - [['This is the quote']] - [['This is the "quote"']] - [['This is the quote with "embedded" quotes']] - """ - def __init__( self, quoteChar, escChar=None, escQuote=None, multiline=False, unquoteResults=True, endQuoteChar=None, convertWhitespaceEscapes=True): - super(QuotedString,self).__init__() - - # remove white space from quote chars - wont work anyway - quoteChar = quoteChar.strip() - if not quoteChar: - warnings.warn("quoteChar cannot be the empty string",SyntaxWarning,stacklevel=2) - raise SyntaxError() - - if endQuoteChar is None: - endQuoteChar = quoteChar - else: - endQuoteChar = endQuoteChar.strip() - if not endQuoteChar: - warnings.warn("endQuoteChar cannot be the empty string",SyntaxWarning,stacklevel=2) - raise SyntaxError() - - self.quoteChar = quoteChar - self.quoteCharLen = len(quoteChar) - self.firstQuoteChar = quoteChar[0] - self.endQuoteChar = endQuoteChar - self.endQuoteCharLen = len(endQuoteChar) - self.escChar = escChar - self.escQuote = escQuote - self.unquoteResults = unquoteResults - self.convertWhitespaceEscapes = convertWhitespaceEscapes - - if multiline: - self.flags = re.MULTILINE | re.DOTALL - self.pattern = r'%s(?:[^%s%s]' % \ - ( re.escape(self.quoteChar), - _escapeRegexRangeChars(self.endQuoteChar[0]), - (escChar is not None and _escapeRegexRangeChars(escChar) or '') ) - else: - self.flags = 0 - self.pattern = r'%s(?:[^%s\n\r%s]' % \ - ( re.escape(self.quoteChar), - _escapeRegexRangeChars(self.endQuoteChar[0]), - (escChar is not None and _escapeRegexRangeChars(escChar) or '') ) - if len(self.endQuoteChar) > 1: - self.pattern += ( - '|(?:' + ')|(?:'.join("%s[^%s]" % (re.escape(self.endQuoteChar[:i]), - _escapeRegexRangeChars(self.endQuoteChar[i])) - for i in range(len(self.endQuoteChar)-1,0,-1)) + ')' - ) - if escQuote: - self.pattern += (r'|(?:%s)' % re.escape(escQuote)) - if escChar: - self.pattern += (r'|(?:%s.)' % re.escape(escChar)) - self.escCharReplacePattern = re.escape(self.escChar)+"(.)" - self.pattern += (r')*%s' % re.escape(self.endQuoteChar)) - - try: - self.re = re.compile(self.pattern, self.flags) - self.reString = self.pattern - except sre_constants.error: - warnings.warn("invalid pattern (%s) passed to Regex" % self.pattern, - SyntaxWarning, stacklevel=2) - raise - - self.name = _ustr(self) - self.errmsg = "Expected " + self.name - self.mayIndexError = False - self.mayReturnEmpty = True - - def parseImpl( self, instring, loc, doActions=True ): - result = instring[loc] == self.firstQuoteChar and self.re.match(instring,loc) or None - if not result: - raise ParseException(instring, loc, self.errmsg, self) - - loc = result.end() - ret = result.group() - - if self.unquoteResults: - - # strip off quotes - ret = ret[self.quoteCharLen:-self.endQuoteCharLen] - - if isinstance(ret,basestring): - # replace escaped whitespace - if '\\' in ret and self.convertWhitespaceEscapes: - ws_map = { - r'\t' : '\t', - r'\n' : '\n', - r'\f' : '\f', - r'\r' : '\r', - } - for wslit,wschar in ws_map.items(): - ret = ret.replace(wslit, wschar) - - # replace escaped characters - if self.escChar: - ret = re.sub(self.escCharReplacePattern, r"\g<1>", ret) - - # replace escaped quotes - if self.escQuote: - ret = ret.replace(self.escQuote, self.endQuoteChar) - - return loc, ret - - def __str__( self ): - try: - return super(QuotedString,self).__str__() - except Exception: - pass - - if self.strRepr is None: - self.strRepr = "quoted string, starting with %s ending with %s" % (self.quoteChar, self.endQuoteChar) - - return self.strRepr - - -class CharsNotIn(Token): - """ - Token for matching words composed of characters I{not} in a given set (will - include whitespace in matched characters if not listed in the provided exclusion set - see example). - Defined with string containing all disallowed characters, and an optional - minimum, maximum, and/or exact length. The default value for C{min} is 1 (a - minimum value < 1 is not valid); the default values for C{max} and C{exact} - are 0, meaning no maximum or exact length restriction. - - Example:: - # define a comma-separated-value as anything that is not a ',' - csv_value = CharsNotIn(',') - print(delimitedList(csv_value).parseString("dkls,lsdkjf,s12 34,@!#,213")) - prints:: - ['dkls', 'lsdkjf', 's12 34', '@!#', '213'] - """ - def __init__( self, notChars, min=1, max=0, exact=0 ): - super(CharsNotIn,self).__init__() - self.skipWhitespace = False - self.notChars = notChars - - if min < 1: - raise ValueError("cannot specify a minimum length < 1; use Optional(CharsNotIn()) if zero-length char group is permitted") - - self.minLen = min - - if max > 0: - self.maxLen = max - else: - self.maxLen = _MAX_INT - - if exact > 0: - self.maxLen = exact - self.minLen = exact - - self.name = _ustr(self) - self.errmsg = "Expected " + self.name - self.mayReturnEmpty = ( self.minLen == 0 ) - self.mayIndexError = False - - def parseImpl( self, instring, loc, doActions=True ): - if instring[loc] in self.notChars: - raise ParseException(instring, loc, self.errmsg, self) - - start = loc - loc += 1 - notchars = self.notChars - maxlen = min( start+self.maxLen, len(instring) ) - while loc < maxlen and \ - (instring[loc] not in notchars): - loc += 1 - - if loc - start < self.minLen: - raise ParseException(instring, loc, self.errmsg, self) - - return loc, instring[start:loc] - - def __str__( self ): - try: - return super(CharsNotIn, self).__str__() - except Exception: - pass - - if self.strRepr is None: - if len(self.notChars) > 4: - self.strRepr = "!W:(%s...)" % self.notChars[:4] - else: - self.strRepr = "!W:(%s)" % self.notChars - - return self.strRepr - -class White(Token): - """ - Special matching class for matching whitespace. Normally, whitespace is ignored - by pyparsing grammars. This class is included when some whitespace structures - are significant. Define with a string containing the whitespace characters to be - matched; default is C{" \\t\\r\\n"}. Also takes optional C{min}, C{max}, and C{exact} arguments, - as defined for the C{L{Word}} class. - """ - whiteStrs = { - " " : "<SPC>", - "\t": "<TAB>", - "\n": "<LF>", - "\r": "<CR>", - "\f": "<FF>", - } - def __init__(self, ws=" \t\r\n", min=1, max=0, exact=0): - super(White,self).__init__() - self.matchWhite = ws - self.setWhitespaceChars( "".join(c for c in self.whiteChars if c not in self.matchWhite) ) - #~ self.leaveWhitespace() - self.name = ("".join(White.whiteStrs[c] for c in self.matchWhite)) - self.mayReturnEmpty = True - self.errmsg = "Expected " + self.name - - self.minLen = min - - if max > 0: - self.maxLen = max - else: - self.maxLen = _MAX_INT - - if exact > 0: - self.maxLen = exact - self.minLen = exact - - def parseImpl( self, instring, loc, doActions=True ): - if not(instring[ loc ] in self.matchWhite): - raise ParseException(instring, loc, self.errmsg, self) - start = loc - loc += 1 - maxloc = start + self.maxLen - maxloc = min( maxloc, len(instring) ) - while loc < maxloc and instring[loc] in self.matchWhite: - loc += 1 - - if loc - start < self.minLen: - raise ParseException(instring, loc, self.errmsg, self) - - return loc, instring[start:loc] - - -class _PositionToken(Token): - def __init__( self ): - super(_PositionToken,self).__init__() - self.name=self.__class__.__name__ - self.mayReturnEmpty = True - self.mayIndexError = False - -class GoToColumn(_PositionToken): - """ - Token to advance to a specific column of input text; useful for tabular report scraping. - """ - def __init__( self, colno ): - super(GoToColumn,self).__init__() - self.col = colno - - def preParse( self, instring, loc ): - if col(loc,instring) != self.col: - instrlen = len(instring) - if self.ignoreExprs: - loc = self._skipIgnorables( instring, loc ) - while loc < instrlen and instring[loc].isspace() and col( loc, instring ) != self.col : - loc += 1 - return loc - - def parseImpl( self, instring, loc, doActions=True ): - thiscol = col( loc, instring ) - if thiscol > self.col: - raise ParseException( instring, loc, "Text not in expected column", self ) - newloc = loc + self.col - thiscol - ret = instring[ loc: newloc ] - return newloc, ret - - -class LineStart(_PositionToken): - """ - Matches if current position is at the beginning of a line within the parse string - - Example:: - - test = '''\ - AAA this line - AAA and this line - AAA but not this one - B AAA and definitely not this one - ''' - - for t in (LineStart() + 'AAA' + restOfLine).searchString(test): - print(t) - - Prints:: - ['AAA', ' this line'] - ['AAA', ' and this line'] - - """ - def __init__( self ): - super(LineStart,self).__init__() - self.errmsg = "Expected start of line" - - def parseImpl( self, instring, loc, doActions=True ): - if col(loc, instring) == 1: - return loc, [] - raise ParseException(instring, loc, self.errmsg, self) - -class LineEnd(_PositionToken): - """ - Matches if current position is at the end of a line within the parse string - """ - def __init__( self ): - super(LineEnd,self).__init__() - self.setWhitespaceChars( ParserElement.DEFAULT_WHITE_CHARS.replace("\n","") ) - self.errmsg = "Expected end of line" - - def parseImpl( self, instring, loc, doActions=True ): - if loc<len(instring): - if instring[loc] == "\n": - return loc+1, "\n" - else: - raise ParseException(instring, loc, self.errmsg, self) - elif loc == len(instring): - return loc+1, [] - else: - raise ParseException(instring, loc, self.errmsg, self) - -class StringStart(_PositionToken): - """ - Matches if current position is at the beginning of the parse string - """ - def __init__( self ): - super(StringStart,self).__init__() - self.errmsg = "Expected start of text" - - def parseImpl( self, instring, loc, doActions=True ): - if loc != 0: - # see if entire string up to here is just whitespace and ignoreables - if loc != self.preParse( instring, 0 ): - raise ParseException(instring, loc, self.errmsg, self) - return loc, [] - -class StringEnd(_PositionToken): - """ - Matches if current position is at the end of the parse string - """ - def __init__( self ): - super(StringEnd,self).__init__() - self.errmsg = "Expected end of text" - - def parseImpl( self, instring, loc, doActions=True ): - if loc < len(instring): - raise ParseException(instring, loc, self.errmsg, self) - elif loc == len(instring): - return loc+1, [] - elif loc > len(instring): - return loc, [] - else: - raise ParseException(instring, loc, self.errmsg, self) - -class WordStart(_PositionToken): - """ - Matches if the current position is at the beginning of a Word, and - is not preceded by any character in a given set of C{wordChars} - (default=C{printables}). To emulate the C{\b} behavior of regular expressions, - use C{WordStart(alphanums)}. C{WordStart} will also match at the beginning of - the string being parsed, or at the beginning of a line. - """ - def __init__(self, wordChars = printables): - super(WordStart,self).__init__() - self.wordChars = set(wordChars) - self.errmsg = "Not at the start of a word" - - def parseImpl(self, instring, loc, doActions=True ): - if loc != 0: - if (instring[loc-1] in self.wordChars or - instring[loc] not in self.wordChars): - raise ParseException(instring, loc, self.errmsg, self) - return loc, [] - -class WordEnd(_PositionToken): - """ - Matches if the current position is at the end of a Word, and - is not followed by any character in a given set of C{wordChars} - (default=C{printables}). To emulate the C{\b} behavior of regular expressions, - use C{WordEnd(alphanums)}. C{WordEnd} will also match at the end of - the string being parsed, or at the end of a line. - """ - def __init__(self, wordChars = printables): - super(WordEnd,self).__init__() - self.wordChars = set(wordChars) - self.skipWhitespace = False - self.errmsg = "Not at the end of a word" - - def parseImpl(self, instring, loc, doActions=True ): - instrlen = len(instring) - if instrlen>0 and loc<instrlen: - if (instring[loc] in self.wordChars or - instring[loc-1] not in self.wordChars): - raise ParseException(instring, loc, self.errmsg, self) - return loc, [] - - -class ParseExpression(ParserElement): - """ - Abstract subclass of ParserElement, for combining and post-processing parsed tokens. - """ - def __init__( self, exprs, savelist = False ): - super(ParseExpression,self).__init__(savelist) - if isinstance( exprs, _generatorType ): - exprs = list(exprs) - - if isinstance( exprs, basestring ): - self.exprs = [ ParserElement._literalStringClass( exprs ) ] - elif isinstance( exprs, Iterable ): - exprs = list(exprs) - # if sequence of strings provided, wrap with Literal - if all(isinstance(expr, basestring) for expr in exprs): - exprs = map(ParserElement._literalStringClass, exprs) - self.exprs = list(exprs) - else: - try: - self.exprs = list( exprs ) - except TypeError: - self.exprs = [ exprs ] - self.callPreparse = False - - def __getitem__( self, i ): - return self.exprs[i] - - def append( self, other ): - self.exprs.append( other ) - self.strRepr = None - return self - - def leaveWhitespace( self ): - """Extends C{leaveWhitespace} defined in base class, and also invokes C{leaveWhitespace} on - all contained expressions.""" - self.skipWhitespace = False - self.exprs = [ e.copy() for e in self.exprs ] - for e in self.exprs: - e.leaveWhitespace() - return self - - def ignore( self, other ): - if isinstance( other, Suppress ): - if other not in self.ignoreExprs: - super( ParseExpression, self).ignore( other ) - for e in self.exprs: - e.ignore( self.ignoreExprs[-1] ) - else: - super( ParseExpression, self).ignore( other ) - for e in self.exprs: - e.ignore( self.ignoreExprs[-1] ) - return self - - def __str__( self ): - try: - return super(ParseExpression,self).__str__() - except Exception: - pass - - if self.strRepr is None: - self.strRepr = "%s:(%s)" % ( self.__class__.__name__, _ustr(self.exprs) ) - return self.strRepr - - def streamline( self ): - super(ParseExpression,self).streamline() - - for e in self.exprs: - e.streamline() - - # collapse nested And's of the form And( And( And( a,b), c), d) to And( a,b,c,d ) - # but only if there are no parse actions or resultsNames on the nested And's - # (likewise for Or's and MatchFirst's) - if ( len(self.exprs) == 2 ): - other = self.exprs[0] - if ( isinstance( other, self.__class__ ) and - not(other.parseAction) and - other.resultsName is None and - not other.debug ): - self.exprs = other.exprs[:] + [ self.exprs[1] ] - self.strRepr = None - self.mayReturnEmpty |= other.mayReturnEmpty - self.mayIndexError |= other.mayIndexError - - other = self.exprs[-1] - if ( isinstance( other, self.__class__ ) and - not(other.parseAction) and - other.resultsName is None and - not other.debug ): - self.exprs = self.exprs[:-1] + other.exprs[:] - self.strRepr = None - self.mayReturnEmpty |= other.mayReturnEmpty - self.mayIndexError |= other.mayIndexError - - self.errmsg = "Expected " + _ustr(self) - - return self - - def setResultsName( self, name, listAllMatches=False ): - ret = super(ParseExpression,self).setResultsName(name,listAllMatches) - return ret - - def validate( self, validateTrace=[] ): - tmp = validateTrace[:]+[self] - for e in self.exprs: - e.validate(tmp) - self.checkRecursion( [] ) - - def copy(self): - ret = super(ParseExpression,self).copy() - ret.exprs = [e.copy() for e in self.exprs] - return ret - -class And(ParseExpression): - """ - Requires all given C{ParseExpression}s to be found in the given order. - Expressions may be separated by whitespace. - May be constructed using the C{'+'} operator. - May also be constructed using the C{'-'} operator, which will suppress backtracking. - - Example:: - integer = Word(nums) - name_expr = OneOrMore(Word(alphas)) - - expr = And([integer("id"),name_expr("name"),integer("age")]) - # more easily written as: - expr = integer("id") + name_expr("name") + integer("age") - """ - - class _ErrorStop(Empty): - def __init__(self, *args, **kwargs): - super(And._ErrorStop,self).__init__(*args, **kwargs) - self.name = '-' - self.leaveWhitespace() - - def __init__( self, exprs, savelist = True ): - super(And,self).__init__(exprs, savelist) - self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs) - self.setWhitespaceChars( self.exprs[0].whiteChars ) - self.skipWhitespace = self.exprs[0].skipWhitespace - self.callPreparse = True - - def parseImpl( self, instring, loc, doActions=True ): - # pass False as last arg to _parse for first element, since we already - # pre-parsed the string as part of our And pre-parsing - loc, resultlist = self.exprs[0]._parse( instring, loc, doActions, callPreParse=False ) - errorStop = False - for e in self.exprs[1:]: - if isinstance(e, And._ErrorStop): - errorStop = True - continue - if errorStop: - try: - loc, exprtokens = e._parse( instring, loc, doActions ) - except ParseSyntaxException: - raise - except ParseBaseException as pe: - pe.__traceback__ = None - raise ParseSyntaxException._from_exception(pe) - except IndexError: - raise ParseSyntaxException(instring, len(instring), self.errmsg, self) - else: - loc, exprtokens = e._parse( instring, loc, doActions ) - if exprtokens or exprtokens.haskeys(): - resultlist += exprtokens - return loc, resultlist - - def __iadd__(self, other ): - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - return self.append( other ) #And( [ self, other ] ) - - def checkRecursion( self, parseElementList ): - subRecCheckList = parseElementList[:] + [ self ] - for e in self.exprs: - e.checkRecursion( subRecCheckList ) - if not e.mayReturnEmpty: - break - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "{" + " ".join(_ustr(e) for e in self.exprs) + "}" - - return self.strRepr - - -class Or(ParseExpression): - """ - Requires that at least one C{ParseExpression} is found. - If two expressions match, the expression that matches the longest string will be used. - May be constructed using the C{'^'} operator. - - Example:: - # construct Or using '^' operator - - number = Word(nums) ^ Combine(Word(nums) + '.' + Word(nums)) - print(number.searchString("123 3.1416 789")) - prints:: - [['123'], ['3.1416'], ['789']] - """ - def __init__( self, exprs, savelist = False ): - super(Or,self).__init__(exprs, savelist) - if self.exprs: - self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs) - else: - self.mayReturnEmpty = True - - def parseImpl( self, instring, loc, doActions=True ): - maxExcLoc = -1 - maxException = None - matches = [] - for e in self.exprs: - try: - loc2 = e.tryParse( instring, loc ) - except ParseException as err: - err.__traceback__ = None - if err.loc > maxExcLoc: - maxException = err - maxExcLoc = err.loc - except IndexError: - if len(instring) > maxExcLoc: - maxException = ParseException(instring,len(instring),e.errmsg,self) - maxExcLoc = len(instring) - else: - # save match among all matches, to retry longest to shortest - matches.append((loc2, e)) - - if matches: - matches.sort(key=lambda x: -x[0]) - for _,e in matches: - try: - return e._parse( instring, loc, doActions ) - except ParseException as err: - err.__traceback__ = None - if err.loc > maxExcLoc: - maxException = err - maxExcLoc = err.loc - - if maxException is not None: - maxException.msg = self.errmsg - raise maxException - else: - raise ParseException(instring, loc, "no defined alternatives to match", self) - - - def __ixor__(self, other ): - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - return self.append( other ) #Or( [ self, other ] ) - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "{" + " ^ ".join(_ustr(e) for e in self.exprs) + "}" - - return self.strRepr - - def checkRecursion( self, parseElementList ): - subRecCheckList = parseElementList[:] + [ self ] - for e in self.exprs: - e.checkRecursion( subRecCheckList ) - - -class MatchFirst(ParseExpression): - """ - Requires that at least one C{ParseExpression} is found. - If two expressions match, the first one listed is the one that will match. - May be constructed using the C{'|'} operator. - - Example:: - # construct MatchFirst using '|' operator - - # watch the order of expressions to match - number = Word(nums) | Combine(Word(nums) + '.' + Word(nums)) - print(number.searchString("123 3.1416 789")) # Fail! -> [['123'], ['3'], ['1416'], ['789']] - - # put more selective expression first - number = Combine(Word(nums) + '.' + Word(nums)) | Word(nums) - print(number.searchString("123 3.1416 789")) # Better -> [['123'], ['3.1416'], ['789']] - """ - def __init__( self, exprs, savelist = False ): - super(MatchFirst,self).__init__(exprs, savelist) - if self.exprs: - self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs) - else: - self.mayReturnEmpty = True - - def parseImpl( self, instring, loc, doActions=True ): - maxExcLoc = -1 - maxException = None - for e in self.exprs: - try: - ret = e._parse( instring, loc, doActions ) - return ret - except ParseException as err: - if err.loc > maxExcLoc: - maxException = err - maxExcLoc = err.loc - except IndexError: - if len(instring) > maxExcLoc: - maxException = ParseException(instring,len(instring),e.errmsg,self) - maxExcLoc = len(instring) - - # only got here if no expression matched, raise exception for match that made it the furthest - else: - if maxException is not None: - maxException.msg = self.errmsg - raise maxException - else: - raise ParseException(instring, loc, "no defined alternatives to match", self) - - def __ior__(self, other ): - if isinstance( other, basestring ): - other = ParserElement._literalStringClass( other ) - return self.append( other ) #MatchFirst( [ self, other ] ) - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "{" + " | ".join(_ustr(e) for e in self.exprs) + "}" - - return self.strRepr - - def checkRecursion( self, parseElementList ): - subRecCheckList = parseElementList[:] + [ self ] - for e in self.exprs: - e.checkRecursion( subRecCheckList ) - - -class Each(ParseExpression): - """ - Requires all given C{ParseExpression}s to be found, but in any order. - Expressions may be separated by whitespace. - May be constructed using the C{'&'} operator. - - Example:: - color = oneOf("RED ORANGE YELLOW GREEN BLUE PURPLE BLACK WHITE BROWN") - shape_type = oneOf("SQUARE CIRCLE TRIANGLE STAR HEXAGON OCTAGON") - integer = Word(nums) - shape_attr = "shape:" + shape_type("shape") - posn_attr = "posn:" + Group(integer("x") + ',' + integer("y"))("posn") - color_attr = "color:" + color("color") - size_attr = "size:" + integer("size") - - # use Each (using operator '&') to accept attributes in any order - # (shape and posn are required, color and size are optional) - shape_spec = shape_attr & posn_attr & Optional(color_attr) & Optional(size_attr) - - shape_spec.runTests(''' - shape: SQUARE color: BLACK posn: 100, 120 - shape: CIRCLE size: 50 color: BLUE posn: 50,80 - color:GREEN size:20 shape:TRIANGLE posn:20,40 - ''' - ) - prints:: - shape: SQUARE color: BLACK posn: 100, 120 - ['shape:', 'SQUARE', 'color:', 'BLACK', 'posn:', ['100', ',', '120']] - - color: BLACK - - posn: ['100', ',', '120'] - - x: 100 - - y: 120 - - shape: SQUARE - - - shape: CIRCLE size: 50 color: BLUE posn: 50,80 - ['shape:', 'CIRCLE', 'size:', '50', 'color:', 'BLUE', 'posn:', ['50', ',', '80']] - - color: BLUE - - posn: ['50', ',', '80'] - - x: 50 - - y: 80 - - shape: CIRCLE - - size: 50 - - - color: GREEN size: 20 shape: TRIANGLE posn: 20,40 - ['color:', 'GREEN', 'size:', '20', 'shape:', 'TRIANGLE', 'posn:', ['20', ',', '40']] - - color: GREEN - - posn: ['20', ',', '40'] - - x: 20 - - y: 40 - - shape: TRIANGLE - - size: 20 - """ - def __init__( self, exprs, savelist = True ): - super(Each,self).__init__(exprs, savelist) - self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs) - self.skipWhitespace = True - self.initExprGroups = True - - def parseImpl( self, instring, loc, doActions=True ): - if self.initExprGroups: - self.opt1map = dict((id(e.expr),e) for e in self.exprs if isinstance(e,Optional)) - opt1 = [ e.expr for e in self.exprs if isinstance(e,Optional) ] - opt2 = [ e for e in self.exprs if e.mayReturnEmpty and not isinstance(e,Optional)] - self.optionals = opt1 + opt2 - self.multioptionals = [ e.expr for e in self.exprs if isinstance(e,ZeroOrMore) ] - self.multirequired = [ e.expr for e in self.exprs if isinstance(e,OneOrMore) ] - self.required = [ e for e in self.exprs if not isinstance(e,(Optional,ZeroOrMore,OneOrMore)) ] - self.required += self.multirequired - self.initExprGroups = False - tmpLoc = loc - tmpReqd = self.required[:] - tmpOpt = self.optionals[:] - matchOrder = [] - - keepMatching = True - while keepMatching: - tmpExprs = tmpReqd + tmpOpt + self.multioptionals + self.multirequired - failed = [] - for e in tmpExprs: - try: - tmpLoc = e.tryParse( instring, tmpLoc ) - except ParseException: - failed.append(e) - else: - matchOrder.append(self.opt1map.get(id(e),e)) - if e in tmpReqd: - tmpReqd.remove(e) - elif e in tmpOpt: - tmpOpt.remove(e) - if len(failed) == len(tmpExprs): - keepMatching = False - - if tmpReqd: - missing = ", ".join(_ustr(e) for e in tmpReqd) - raise ParseException(instring,loc,"Missing one or more required elements (%s)" % missing ) - - # add any unmatched Optionals, in case they have default values defined - matchOrder += [e for e in self.exprs if isinstance(e,Optional) and e.expr in tmpOpt] - - resultlist = [] - for e in matchOrder: - loc,results = e._parse(instring,loc,doActions) - resultlist.append(results) - - finalResults = sum(resultlist, ParseResults([])) - return loc, finalResults - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "{" + " & ".join(_ustr(e) for e in self.exprs) + "}" - - return self.strRepr - - def checkRecursion( self, parseElementList ): - subRecCheckList = parseElementList[:] + [ self ] - for e in self.exprs: - e.checkRecursion( subRecCheckList ) - - -class ParseElementEnhance(ParserElement): - """ - Abstract subclass of C{ParserElement}, for combining and post-processing parsed tokens. - """ - def __init__( self, expr, savelist=False ): - super(ParseElementEnhance,self).__init__(savelist) - if isinstance( expr, basestring ): - if issubclass(ParserElement._literalStringClass, Token): - expr = ParserElement._literalStringClass(expr) - else: - expr = ParserElement._literalStringClass(Literal(expr)) - self.expr = expr - self.strRepr = None - if expr is not None: - self.mayIndexError = expr.mayIndexError - self.mayReturnEmpty = expr.mayReturnEmpty - self.setWhitespaceChars( expr.whiteChars ) - self.skipWhitespace = expr.skipWhitespace - self.saveAsList = expr.saveAsList - self.callPreparse = expr.callPreparse - self.ignoreExprs.extend(expr.ignoreExprs) - - def parseImpl( self, instring, loc, doActions=True ): - if self.expr is not None: - return self.expr._parse( instring, loc, doActions, callPreParse=False ) - else: - raise ParseException("",loc,self.errmsg,self) - - def leaveWhitespace( self ): - self.skipWhitespace = False - self.expr = self.expr.copy() - if self.expr is not None: - self.expr.leaveWhitespace() - return self - - def ignore( self, other ): - if isinstance( other, Suppress ): - if other not in self.ignoreExprs: - super( ParseElementEnhance, self).ignore( other ) - if self.expr is not None: - self.expr.ignore( self.ignoreExprs[-1] ) - else: - super( ParseElementEnhance, self).ignore( other ) - if self.expr is not None: - self.expr.ignore( self.ignoreExprs[-1] ) - return self - - def streamline( self ): - super(ParseElementEnhance,self).streamline() - if self.expr is not None: - self.expr.streamline() - return self - - def checkRecursion( self, parseElementList ): - if self in parseElementList: - raise RecursiveGrammarException( parseElementList+[self] ) - subRecCheckList = parseElementList[:] + [ self ] - if self.expr is not None: - self.expr.checkRecursion( subRecCheckList ) - - def validate( self, validateTrace=[] ): - tmp = validateTrace[:]+[self] - if self.expr is not None: - self.expr.validate(tmp) - self.checkRecursion( [] ) - - def __str__( self ): - try: - return super(ParseElementEnhance,self).__str__() - except Exception: - pass - - if self.strRepr is None and self.expr is not None: - self.strRepr = "%s:(%s)" % ( self.__class__.__name__, _ustr(self.expr) ) - return self.strRepr - - -class FollowedBy(ParseElementEnhance): - """ - Lookahead matching of the given parse expression. C{FollowedBy} - does I{not} advance the parsing position within the input string, it only - verifies that the specified parse expression matches at the current - position. C{FollowedBy} always returns a null token list. - - Example:: - # use FollowedBy to match a label only if it is followed by a ':' - data_word = Word(alphas) - label = data_word + FollowedBy(':') - attr_expr = Group(label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join)) - - OneOrMore(attr_expr).parseString("shape: SQUARE color: BLACK posn: upper left").pprint() - prints:: - [['shape', 'SQUARE'], ['color', 'BLACK'], ['posn', 'upper left']] - """ - def __init__( self, expr ): - super(FollowedBy,self).__init__(expr) - self.mayReturnEmpty = True - - def parseImpl( self, instring, loc, doActions=True ): - self.expr.tryParse( instring, loc ) - return loc, [] - - -class NotAny(ParseElementEnhance): - """ - Lookahead to disallow matching with the given parse expression. C{NotAny} - does I{not} advance the parsing position within the input string, it only - verifies that the specified parse expression does I{not} match at the current - position. Also, C{NotAny} does I{not} skip over leading whitespace. C{NotAny} - always returns a null token list. May be constructed using the '~' operator. - - Example:: - - """ - def __init__( self, expr ): - super(NotAny,self).__init__(expr) - #~ self.leaveWhitespace() - self.skipWhitespace = False # do NOT use self.leaveWhitespace(), don't want to propagate to exprs - self.mayReturnEmpty = True - self.errmsg = "Found unwanted token, "+_ustr(self.expr) - - def parseImpl( self, instring, loc, doActions=True ): - if self.expr.canParseNext(instring, loc): - raise ParseException(instring, loc, self.errmsg, self) - return loc, [] - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "~{" + _ustr(self.expr) + "}" - - return self.strRepr - -class _MultipleMatch(ParseElementEnhance): - def __init__( self, expr, stopOn=None): - super(_MultipleMatch, self).__init__(expr) - self.saveAsList = True - ender = stopOn - if isinstance(ender, basestring): - ender = ParserElement._literalStringClass(ender) - self.not_ender = ~ender if ender is not None else None - - def parseImpl( self, instring, loc, doActions=True ): - self_expr_parse = self.expr._parse - self_skip_ignorables = self._skipIgnorables - check_ender = self.not_ender is not None - if check_ender: - try_not_ender = self.not_ender.tryParse - - # must be at least one (but first see if we are the stopOn sentinel; - # if so, fail) - if check_ender: - try_not_ender(instring, loc) - loc, tokens = self_expr_parse( instring, loc, doActions, callPreParse=False ) - try: - hasIgnoreExprs = (not not self.ignoreExprs) - while 1: - if check_ender: - try_not_ender(instring, loc) - if hasIgnoreExprs: - preloc = self_skip_ignorables( instring, loc ) - else: - preloc = loc - loc, tmptokens = self_expr_parse( instring, preloc, doActions ) - if tmptokens or tmptokens.haskeys(): - tokens += tmptokens - except (ParseException,IndexError): - pass - - return loc, tokens - -class OneOrMore(_MultipleMatch): - """ - Repetition of one or more of the given expression. - - Parameters: - - expr - expression that must match one or more times - - stopOn - (default=C{None}) - expression for a terminating sentinel - (only required if the sentinel would ordinarily match the repetition - expression) - - Example:: - data_word = Word(alphas) - label = data_word + FollowedBy(':') - attr_expr = Group(label + Suppress(':') + OneOrMore(data_word).setParseAction(' '.join)) - - text = "shape: SQUARE posn: upper left color: BLACK" - OneOrMore(attr_expr).parseString(text).pprint() # Fail! read 'color' as data instead of next label -> [['shape', 'SQUARE color']] - - # use stopOn attribute for OneOrMore to avoid reading label string as part of the data - attr_expr = Group(label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join)) - OneOrMore(attr_expr).parseString(text).pprint() # Better -> [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'BLACK']] - - # could also be written as - (attr_expr * (1,)).parseString(text).pprint() - """ - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "{" + _ustr(self.expr) + "}..." - - return self.strRepr - -class ZeroOrMore(_MultipleMatch): - """ - Optional repetition of zero or more of the given expression. - - Parameters: - - expr - expression that must match zero or more times - - stopOn - (default=C{None}) - expression for a terminating sentinel - (only required if the sentinel would ordinarily match the repetition - expression) - - Example: similar to L{OneOrMore} - """ - def __init__( self, expr, stopOn=None): - super(ZeroOrMore,self).__init__(expr, stopOn=stopOn) - self.mayReturnEmpty = True - - def parseImpl( self, instring, loc, doActions=True ): - try: - return super(ZeroOrMore, self).parseImpl(instring, loc, doActions) - except (ParseException,IndexError): - return loc, [] - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "[" + _ustr(self.expr) + "]..." - - return self.strRepr - -class _NullToken(object): - def __bool__(self): - return False - __nonzero__ = __bool__ - def __str__(self): - return "" - -_optionalNotMatched = _NullToken() -class Optional(ParseElementEnhance): - """ - Optional matching of the given expression. - - Parameters: - - expr - expression that must match zero or more times - - default (optional) - value to be returned if the optional expression is not found. - - Example:: - # US postal code can be a 5-digit zip, plus optional 4-digit qualifier - zip = Combine(Word(nums, exact=5) + Optional('-' + Word(nums, exact=4))) - zip.runTests(''' - # traditional ZIP code - 12345 - - # ZIP+4 form - 12101-0001 - - # invalid ZIP - 98765- - ''') - prints:: - # traditional ZIP code - 12345 - ['12345'] - - # ZIP+4 form - 12101-0001 - ['12101-0001'] - - # invalid ZIP - 98765- - ^ - FAIL: Expected end of text (at char 5), (line:1, col:6) - """ - def __init__( self, expr, default=_optionalNotMatched ): - super(Optional,self).__init__( expr, savelist=False ) - self.saveAsList = self.expr.saveAsList - self.defaultValue = default - self.mayReturnEmpty = True - - def parseImpl( self, instring, loc, doActions=True ): - try: - loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False ) - except (ParseException,IndexError): - if self.defaultValue is not _optionalNotMatched: - if self.expr.resultsName: - tokens = ParseResults([ self.defaultValue ]) - tokens[self.expr.resultsName] = self.defaultValue - else: - tokens = [ self.defaultValue ] - else: - tokens = [] - return loc, tokens - - def __str__( self ): - if hasattr(self,"name"): - return self.name - - if self.strRepr is None: - self.strRepr = "[" + _ustr(self.expr) + "]" - - return self.strRepr - -class SkipTo(ParseElementEnhance): - """ - Token for skipping over all undefined text until the matched expression is found. - - Parameters: - - expr - target expression marking the end of the data to be skipped - - include - (default=C{False}) if True, the target expression is also parsed - (the skipped text and target expression are returned as a 2-element list). - - ignore - (default=C{None}) used to define grammars (typically quoted strings and - comments) that might contain false matches to the target expression - - failOn - (default=C{None}) define expressions that are not allowed to be - included in the skipped test; if found before the target expression is found, - the SkipTo is not a match - - Example:: - report = ''' - Outstanding Issues Report - 1 Jan 2000 - - # | Severity | Description | Days Open - -----+----------+-------------------------------------------+----------- - 101 | Critical | Intermittent system crash | 6 - 94 | Cosmetic | Spelling error on Login ('log|n') | 14 - 79 | Minor | System slow when running too many reports | 47 - ''' - integer = Word(nums) - SEP = Suppress('|') - # use SkipTo to simply match everything up until the next SEP - # - ignore quoted strings, so that a '|' character inside a quoted string does not match - # - parse action will call token.strip() for each matched token, i.e., the description body - string_data = SkipTo(SEP, ignore=quotedString) - string_data.setParseAction(tokenMap(str.strip)) - ticket_expr = (integer("issue_num") + SEP - + string_data("sev") + SEP - + string_data("desc") + SEP - + integer("days_open")) - - for tkt in ticket_expr.searchString(report): - print tkt.dump() - prints:: - ['101', 'Critical', 'Intermittent system crash', '6'] - - days_open: 6 - - desc: Intermittent system crash - - issue_num: 101 - - sev: Critical - ['94', 'Cosmetic', "Spelling error on Login ('log|n')", '14'] - - days_open: 14 - - desc: Spelling error on Login ('log|n') - - issue_num: 94 - - sev: Cosmetic - ['79', 'Minor', 'System slow when running too many reports', '47'] - - days_open: 47 - - desc: System slow when running too many reports - - issue_num: 79 - - sev: Minor - """ - def __init__( self, other, include=False, ignore=None, failOn=None ): - super( SkipTo, self ).__init__( other ) - self.ignoreExpr = ignore - self.mayReturnEmpty = True - self.mayIndexError = False - self.includeMatch = include - self.asList = False - if isinstance(failOn, basestring): - self.failOn = ParserElement._literalStringClass(failOn) - else: - self.failOn = failOn - self.errmsg = "No match found for "+_ustr(self.expr) - - def parseImpl( self, instring, loc, doActions=True ): - startloc = loc - instrlen = len(instring) - expr = self.expr - expr_parse = self.expr._parse - self_failOn_canParseNext = self.failOn.canParseNext if self.failOn is not None else None - self_ignoreExpr_tryParse = self.ignoreExpr.tryParse if self.ignoreExpr is not None else None - - tmploc = loc - while tmploc <= instrlen: - if self_failOn_canParseNext is not None: - # break if failOn expression matches - if self_failOn_canParseNext(instring, tmploc): - break - - if self_ignoreExpr_tryParse is not None: - # advance past ignore expressions - while 1: - try: - tmploc = self_ignoreExpr_tryParse(instring, tmploc) - except ParseBaseException: - break - - try: - expr_parse(instring, tmploc, doActions=False, callPreParse=False) - except (ParseException, IndexError): - # no match, advance loc in string - tmploc += 1 - else: - # matched skipto expr, done - break - - else: - # ran off the end of the input string without matching skipto expr, fail - raise ParseException(instring, loc, self.errmsg, self) - - # build up return values - loc = tmploc - skiptext = instring[startloc:loc] - skipresult = ParseResults(skiptext) - - if self.includeMatch: - loc, mat = expr_parse(instring,loc,doActions,callPreParse=False) - skipresult += mat - - return loc, skipresult - -class Forward(ParseElementEnhance): - """ - Forward declaration of an expression to be defined later - - used for recursive grammars, such as algebraic infix notation. - When the expression is known, it is assigned to the C{Forward} variable using the '<<' operator. - - Note: take care when assigning to C{Forward} not to overlook precedence of operators. - Specifically, '|' has a lower precedence than '<<', so that:: - fwdExpr << a | b | c - will actually be evaluated as:: - (fwdExpr << a) | b | c - thereby leaving b and c out as parseable alternatives. It is recommended that you - explicitly group the values inserted into the C{Forward}:: - fwdExpr << (a | b | c) - Converting to use the '<<=' operator instead will avoid this problem. - - See L{ParseResults.pprint} for an example of a recursive parser created using - C{Forward}. - """ - def __init__( self, other=None ): - super(Forward,self).__init__( other, savelist=False ) - - def __lshift__( self, other ): - if isinstance( other, basestring ): - other = ParserElement._literalStringClass(other) - self.expr = other - self.strRepr = None - self.mayIndexError = self.expr.mayIndexError - self.mayReturnEmpty = self.expr.mayReturnEmpty - self.setWhitespaceChars( self.expr.whiteChars ) - self.skipWhitespace = self.expr.skipWhitespace - self.saveAsList = self.expr.saveAsList - self.ignoreExprs.extend(self.expr.ignoreExprs) - return self - - def __ilshift__(self, other): - return self << other - - def leaveWhitespace( self ): - self.skipWhitespace = False - return self - - def streamline( self ): - if not self.streamlined: - self.streamlined = True - if self.expr is not None: - self.expr.streamline() - return self - - def validate( self, validateTrace=[] ): - if self not in validateTrace: - tmp = validateTrace[:]+[self] - if self.expr is not None: - self.expr.validate(tmp) - self.checkRecursion([]) - - def __str__( self ): - if hasattr(self,"name"): - return self.name - return self.__class__.__name__ + ": ..." - - # stubbed out for now - creates awful memory and perf issues - self._revertClass = self.__class__ - self.__class__ = _ForwardNoRecurse - try: - if self.expr is not None: - retString = _ustr(self.expr) - else: - retString = "None" - finally: - self.__class__ = self._revertClass - return self.__class__.__name__ + ": " + retString - - def copy(self): - if self.expr is not None: - return super(Forward,self).copy() - else: - ret = Forward() - ret <<= self - return ret - -class _ForwardNoRecurse(Forward): - def __str__( self ): - return "..." - -class TokenConverter(ParseElementEnhance): - """ - Abstract subclass of C{ParseExpression}, for converting parsed results. - """ - def __init__( self, expr, savelist=False ): - super(TokenConverter,self).__init__( expr )#, savelist ) - self.saveAsList = False - -class Combine(TokenConverter): - """ - Converter to concatenate all matching tokens to a single string. - By default, the matching patterns must also be contiguous in the input string; - this can be disabled by specifying C{'adjacent=False'} in the constructor. - - Example:: - real = Word(nums) + '.' + Word(nums) - print(real.parseString('3.1416')) # -> ['3', '.', '1416'] - # will also erroneously match the following - print(real.parseString('3. 1416')) # -> ['3', '.', '1416'] - - real = Combine(Word(nums) + '.' + Word(nums)) - print(real.parseString('3.1416')) # -> ['3.1416'] - # no match when there are internal spaces - print(real.parseString('3. 1416')) # -> Exception: Expected W:(0123...) - """ - def __init__( self, expr, joinString="", adjacent=True ): - super(Combine,self).__init__( expr ) - # suppress whitespace-stripping in contained parse expressions, but re-enable it on the Combine itself - if adjacent: - self.leaveWhitespace() - self.adjacent = adjacent - self.skipWhitespace = True - self.joinString = joinString - self.callPreparse = True - - def ignore( self, other ): - if self.adjacent: - ParserElement.ignore(self, other) - else: - super( Combine, self).ignore( other ) - return self - - def postParse( self, instring, loc, tokenlist ): - retToks = tokenlist.copy() - del retToks[:] - retToks += ParseResults([ "".join(tokenlist._asStringList(self.joinString)) ], modal=self.modalResults) - - if self.resultsName and retToks.haskeys(): - return [ retToks ] - else: - return retToks - -class Group(TokenConverter): - """ - Converter to return the matched tokens as a list - useful for returning tokens of C{L{ZeroOrMore}} and C{L{OneOrMore}} expressions. - - Example:: - ident = Word(alphas) - num = Word(nums) - term = ident | num - func = ident + Optional(delimitedList(term)) - print(func.parseString("fn a,b,100")) # -> ['fn', 'a', 'b', '100'] - - func = ident + Group(Optional(delimitedList(term))) - print(func.parseString("fn a,b,100")) # -> ['fn', ['a', 'b', '100']] - """ - def __init__( self, expr ): - super(Group,self).__init__( expr ) - self.saveAsList = True - - def postParse( self, instring, loc, tokenlist ): - return [ tokenlist ] - -class Dict(TokenConverter): - """ - Converter to return a repetitive expression as a list, but also as a dictionary. - Each element can also be referenced using the first token in the expression as its key. - Useful for tabular report scraping when the first column can be used as a item key. - - Example:: - data_word = Word(alphas) - label = data_word + FollowedBy(':') - attr_expr = Group(label + Suppress(':') + OneOrMore(data_word).setParseAction(' '.join)) - - text = "shape: SQUARE posn: upper left color: light blue texture: burlap" - attr_expr = (label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join)) - - # print attributes as plain groups - print(OneOrMore(attr_expr).parseString(text).dump()) - - # instead of OneOrMore(expr), parse using Dict(OneOrMore(Group(expr))) - Dict will auto-assign names - result = Dict(OneOrMore(Group(attr_expr))).parseString(text) - print(result.dump()) - - # access named fields as dict entries, or output as dict - print(result['shape']) - print(result.asDict()) - prints:: - ['shape', 'SQUARE', 'posn', 'upper left', 'color', 'light blue', 'texture', 'burlap'] - - [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'light blue'], ['texture', 'burlap']] - - color: light blue - - posn: upper left - - shape: SQUARE - - texture: burlap - SQUARE - {'color': 'light blue', 'posn': 'upper left', 'texture': 'burlap', 'shape': 'SQUARE'} - See more examples at L{ParseResults} of accessing fields by results name. - """ - def __init__( self, expr ): - super(Dict,self).__init__( expr ) - self.saveAsList = True - - def postParse( self, instring, loc, tokenlist ): - for i,tok in enumerate(tokenlist): - if len(tok) == 0: - continue - ikey = tok[0] - if isinstance(ikey,int): - ikey = _ustr(tok[0]).strip() - if len(tok)==1: - tokenlist[ikey] = _ParseResultsWithOffset("",i) - elif len(tok)==2 and not isinstance(tok[1],ParseResults): - tokenlist[ikey] = _ParseResultsWithOffset(tok[1],i) - else: - dictvalue = tok.copy() #ParseResults(i) - del dictvalue[0] - if len(dictvalue)!= 1 or (isinstance(dictvalue,ParseResults) and dictvalue.haskeys()): - tokenlist[ikey] = _ParseResultsWithOffset(dictvalue,i) - else: - tokenlist[ikey] = _ParseResultsWithOffset(dictvalue[0],i) - - if self.resultsName: - return [ tokenlist ] - else: - return tokenlist - - -class Suppress(TokenConverter): - """ - Converter for ignoring the results of a parsed expression. - - Example:: - source = "a, b, c,d" - wd = Word(alphas) - wd_list1 = wd + ZeroOrMore(',' + wd) - print(wd_list1.parseString(source)) - - # often, delimiters that are useful during parsing are just in the - # way afterward - use Suppress to keep them out of the parsed output - wd_list2 = wd + ZeroOrMore(Suppress(',') + wd) - print(wd_list2.parseString(source)) - prints:: - ['a', ',', 'b', ',', 'c', ',', 'd'] - ['a', 'b', 'c', 'd'] - (See also L{delimitedList}.) - """ - def postParse( self, instring, loc, tokenlist ): - return [] - - def suppress( self ): - return self - - -class OnlyOnce(object): - """ - Wrapper for parse actions, to ensure they are only called once. - """ - def __init__(self, methodCall): - self.callable = _trim_arity(methodCall) - self.called = False - def __call__(self,s,l,t): - if not self.called: - results = self.callable(s,l,t) - self.called = True - return results - raise ParseException(s,l,"") - def reset(self): - self.called = False - -def traceParseAction(f): - """ - Decorator for debugging parse actions. - - When the parse action is called, this decorator will print C{">> entering I{method-name}(line:I{current_source_line}, I{parse_location}, I{matched_tokens})".} - When the parse action completes, the decorator will print C{"<<"} followed by the returned value, or any exception that the parse action raised. - - Example:: - wd = Word(alphas) - - @traceParseAction - def remove_duplicate_chars(tokens): - return ''.join(sorted(set(''.join(tokens)))) - - wds = OneOrMore(wd).setParseAction(remove_duplicate_chars) - print(wds.parseString("slkdjs sld sldd sdlf sdljf")) - prints:: - >>entering remove_duplicate_chars(line: 'slkdjs sld sldd sdlf sdljf', 0, (['slkdjs', 'sld', 'sldd', 'sdlf', 'sdljf'], {})) - <<leaving remove_duplicate_chars (ret: 'dfjkls') - ['dfjkls'] - """ - f = _trim_arity(f) - def z(*paArgs): - thisFunc = f.__name__ - s,l,t = paArgs[-3:] - if len(paArgs)>3: - thisFunc = paArgs[0].__class__.__name__ + '.' + thisFunc - sys.stderr.write( ">>entering %s(line: '%s', %d, %r)\n" % (thisFunc,line(l,s),l,t) ) - try: - ret = f(*paArgs) - except Exception as exc: - sys.stderr.write( "<<leaving %s (exception: %s)\n" % (thisFunc,exc) ) - raise - sys.stderr.write( "<<leaving %s (ret: %r)\n" % (thisFunc,ret) ) - return ret - try: - z.__name__ = f.__name__ - except AttributeError: - pass - return z - -# -# global helpers -# -def delimitedList( expr, delim=",", combine=False ): - """ - Helper to define a delimited list of expressions - the delimiter defaults to ','. - By default, the list elements and delimiters can have intervening whitespace, and - comments, but this can be overridden by passing C{combine=True} in the constructor. - If C{combine} is set to C{True}, the matching tokens are returned as a single token - string, with the delimiters included; otherwise, the matching tokens are returned - as a list of tokens, with the delimiters suppressed. - - Example:: - delimitedList(Word(alphas)).parseString("aa,bb,cc") # -> ['aa', 'bb', 'cc'] - delimitedList(Word(hexnums), delim=':', combine=True).parseString("AA:BB:CC:DD:EE") # -> ['AA:BB:CC:DD:EE'] - """ - dlName = _ustr(expr)+" ["+_ustr(delim)+" "+_ustr(expr)+"]..." - if combine: - return Combine( expr + ZeroOrMore( delim + expr ) ).setName(dlName) - else: - return ( expr + ZeroOrMore( Suppress( delim ) + expr ) ).setName(dlName) - -def countedArray( expr, intExpr=None ): - """ - Helper to define a counted list of expressions. - This helper defines a pattern of the form:: - integer expr expr expr... - where the leading integer tells how many expr expressions follow. - The matched tokens returns the array of expr tokens as a list - the leading count token is suppressed. - - If C{intExpr} is specified, it should be a pyparsing expression that produces an integer value. - - Example:: - countedArray(Word(alphas)).parseString('2 ab cd ef') # -> ['ab', 'cd'] - - # in this parser, the leading integer value is given in binary, - # '10' indicating that 2 values are in the array - binaryConstant = Word('01').setParseAction(lambda t: int(t[0], 2)) - countedArray(Word(alphas), intExpr=binaryConstant).parseString('10 ab cd ef') # -> ['ab', 'cd'] - """ - arrayExpr = Forward() - def countFieldParseAction(s,l,t): - n = t[0] - arrayExpr << (n and Group(And([expr]*n)) or Group(empty)) - return [] - if intExpr is None: - intExpr = Word(nums).setParseAction(lambda t:int(t[0])) - else: - intExpr = intExpr.copy() - intExpr.setName("arrayLen") - intExpr.addParseAction(countFieldParseAction, callDuringTry=True) - return ( intExpr + arrayExpr ).setName('(len) ' + _ustr(expr) + '...') - -def _flatten(L): - ret = [] - for i in L: - if isinstance(i,list): - ret.extend(_flatten(i)) - else: - ret.append(i) - return ret - -def matchPreviousLiteral(expr): - """ - Helper to define an expression that is indirectly defined from - the tokens matched in a previous expression, that is, it looks - for a 'repeat' of a previous expression. For example:: - first = Word(nums) - second = matchPreviousLiteral(first) - matchExpr = first + ":" + second - will match C{"1:1"}, but not C{"1:2"}. Because this matches a - previous literal, will also match the leading C{"1:1"} in C{"1:10"}. - If this is not desired, use C{matchPreviousExpr}. - Do I{not} use with packrat parsing enabled. - """ - rep = Forward() - def copyTokenToRepeater(s,l,t): - if t: - if len(t) == 1: - rep << t[0] - else: - # flatten t tokens - tflat = _flatten(t.asList()) - rep << And(Literal(tt) for tt in tflat) - else: - rep << Empty() - expr.addParseAction(copyTokenToRepeater, callDuringTry=True) - rep.setName('(prev) ' + _ustr(expr)) - return rep - -def matchPreviousExpr(expr): - """ - Helper to define an expression that is indirectly defined from - the tokens matched in a previous expression, that is, it looks - for a 'repeat' of a previous expression. For example:: - first = Word(nums) - second = matchPreviousExpr(first) - matchExpr = first + ":" + second - will match C{"1:1"}, but not C{"1:2"}. Because this matches by - expressions, will I{not} match the leading C{"1:1"} in C{"1:10"}; - the expressions are evaluated first, and then compared, so - C{"1"} is compared with C{"10"}. - Do I{not} use with packrat parsing enabled. - """ - rep = Forward() - e2 = expr.copy() - rep <<= e2 - def copyTokenToRepeater(s,l,t): - matchTokens = _flatten(t.asList()) - def mustMatchTheseTokens(s,l,t): - theseTokens = _flatten(t.asList()) - if theseTokens != matchTokens: - raise ParseException("",0,"") - rep.setParseAction( mustMatchTheseTokens, callDuringTry=True ) - expr.addParseAction(copyTokenToRepeater, callDuringTry=True) - rep.setName('(prev) ' + _ustr(expr)) - return rep - -def _escapeRegexRangeChars(s): - #~ escape these chars: ^-] - for c in r"\^-]": - s = s.replace(c,_bslash+c) - s = s.replace("\n",r"\n") - s = s.replace("\t",r"\t") - return _ustr(s) - -def oneOf( strs, caseless=False, useRegex=True ): - """ - Helper to quickly define a set of alternative Literals, and makes sure to do - longest-first testing when there is a conflict, regardless of the input order, - but returns a C{L{MatchFirst}} for best performance. - - Parameters: - - strs - a string of space-delimited literals, or a collection of string literals - - caseless - (default=C{False}) - treat all literals as caseless - - useRegex - (default=C{True}) - as an optimization, will generate a Regex - object; otherwise, will generate a C{MatchFirst} object (if C{caseless=True}, or - if creating a C{Regex} raises an exception) - - Example:: - comp_oper = oneOf("< = > <= >= !=") - var = Word(alphas) - number = Word(nums) - term = var | number - comparison_expr = term + comp_oper + term - print(comparison_expr.searchString("B = 12 AA=23 B<=AA AA>12")) - prints:: - [['B', '=', '12'], ['AA', '=', '23'], ['B', '<=', 'AA'], ['AA', '>', '12']] - """ - if caseless: - isequal = ( lambda a,b: a.upper() == b.upper() ) - masks = ( lambda a,b: b.upper().startswith(a.upper()) ) - parseElementClass = CaselessLiteral - else: - isequal = ( lambda a,b: a == b ) - masks = ( lambda a,b: b.startswith(a) ) - parseElementClass = Literal - - symbols = [] - if isinstance(strs,basestring): - symbols = strs.split() - elif isinstance(strs, Iterable): - symbols = list(strs) - else: - warnings.warn("Invalid argument to oneOf, expected string or iterable", - SyntaxWarning, stacklevel=2) - if not symbols: - return NoMatch() - - i = 0 - while i < len(symbols)-1: - cur = symbols[i] - for j,other in enumerate(symbols[i+1:]): - if ( isequal(other, cur) ): - del symbols[i+j+1] - break - elif ( masks(cur, other) ): - del symbols[i+j+1] - symbols.insert(i,other) - cur = other - break - else: - i += 1 - - if not caseless and useRegex: - #~ print (strs,"->", "|".join( [ _escapeRegexChars(sym) for sym in symbols] )) - try: - if len(symbols)==len("".join(symbols)): - return Regex( "[%s]" % "".join(_escapeRegexRangeChars(sym) for sym in symbols) ).setName(' | '.join(symbols)) - else: - return Regex( "|".join(re.escape(sym) for sym in symbols) ).setName(' | '.join(symbols)) - except Exception: - warnings.warn("Exception creating Regex for oneOf, building MatchFirst", - SyntaxWarning, stacklevel=2) - - - # last resort, just use MatchFirst - return MatchFirst(parseElementClass(sym) for sym in symbols).setName(' | '.join(symbols)) - -def dictOf( key, value ): - """ - Helper to easily and clearly define a dictionary by specifying the respective patterns - for the key and value. Takes care of defining the C{L{Dict}}, C{L{ZeroOrMore}}, and C{L{Group}} tokens - in the proper order. The key pattern can include delimiting markers or punctuation, - as long as they are suppressed, thereby leaving the significant key text. The value - pattern can include named results, so that the C{Dict} results can include named token - fields. - - Example:: - text = "shape: SQUARE posn: upper left color: light blue texture: burlap" - attr_expr = (label + Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join)) - print(OneOrMore(attr_expr).parseString(text).dump()) - - attr_label = label - attr_value = Suppress(':') + OneOrMore(data_word, stopOn=label).setParseAction(' '.join) - - # similar to Dict, but simpler call format - result = dictOf(attr_label, attr_value).parseString(text) - print(result.dump()) - print(result['shape']) - print(result.shape) # object attribute access works too - print(result.asDict()) - prints:: - [['shape', 'SQUARE'], ['posn', 'upper left'], ['color', 'light blue'], ['texture', 'burlap']] - - color: light blue - - posn: upper left - - shape: SQUARE - - texture: burlap - SQUARE - SQUARE - {'color': 'light blue', 'shape': 'SQUARE', 'posn': 'upper left', 'texture': 'burlap'} - """ - return Dict( ZeroOrMore( Group ( key + value ) ) ) - -def originalTextFor(expr, asString=True): - """ - Helper to return the original, untokenized text for a given expression. Useful to - restore the parsed fields of an HTML start tag into the raw tag text itself, or to - revert separate tokens with intervening whitespace back to the original matching - input text. By default, returns astring containing the original parsed text. - - If the optional C{asString} argument is passed as C{False}, then the return value is a - C{L{ParseResults}} containing any results names that were originally matched, and a - single token containing the original matched text from the input string. So if - the expression passed to C{L{originalTextFor}} contains expressions with defined - results names, you must set C{asString} to C{False} if you want to preserve those - results name values. - - Example:: - src = "this is test <b> bold <i>text</i> </b> normal text " - for tag in ("b","i"): - opener,closer = makeHTMLTags(tag) - patt = originalTextFor(opener + SkipTo(closer) + closer) - print(patt.searchString(src)[0]) - prints:: - ['<b> bold <i>text</i> </b>'] - ['<i>text</i>'] - """ - locMarker = Empty().setParseAction(lambda s,loc,t: loc) - endlocMarker = locMarker.copy() - endlocMarker.callPreparse = False - matchExpr = locMarker("_original_start") + expr + endlocMarker("_original_end") - if asString: - extractText = lambda s,l,t: s[t._original_start:t._original_end] - else: - def extractText(s,l,t): - t[:] = [s[t.pop('_original_start'):t.pop('_original_end')]] - matchExpr.setParseAction(extractText) - matchExpr.ignoreExprs = expr.ignoreExprs - return matchExpr - -def ungroup(expr): - """ - Helper to undo pyparsing's default grouping of And expressions, even - if all but one are non-empty. - """ - return TokenConverter(expr).setParseAction(lambda t:t[0]) - -def locatedExpr(expr): - """ - Helper to decorate a returned token with its starting and ending locations in the input string. - This helper adds the following results names: - - locn_start = location where matched expression begins - - locn_end = location where matched expression ends - - value = the actual parsed results - - Be careful if the input text contains C{<TAB>} characters, you may want to call - C{L{ParserElement.parseWithTabs}} - - Example:: - wd = Word(alphas) - for match in locatedExpr(wd).searchString("ljsdf123lksdjjf123lkkjj1222"): - print(match) - prints:: - [[0, 'ljsdf', 5]] - [[8, 'lksdjjf', 15]] - [[18, 'lkkjj', 23]] - """ - locator = Empty().setParseAction(lambda s,l,t: l) - return Group(locator("locn_start") + expr("value") + locator.copy().leaveWhitespace()("locn_end")) - - -# convenience constants for positional expressions -empty = Empty().setName("empty") -lineStart = LineStart().setName("lineStart") -lineEnd = LineEnd().setName("lineEnd") -stringStart = StringStart().setName("stringStart") -stringEnd = StringEnd().setName("stringEnd") - -_escapedPunc = Word( _bslash, r"\[]-*.$+^?()~ ", exact=2 ).setParseAction(lambda s,l,t:t[0][1]) -_escapedHexChar = Regex(r"\\0?[xX][0-9a-fA-F]+").setParseAction(lambda s,l,t:unichr(int(t[0].lstrip(r'\0x'),16))) -_escapedOctChar = Regex(r"\\0[0-7]+").setParseAction(lambda s,l,t:unichr(int(t[0][1:],8))) -_singleChar = _escapedPunc | _escapedHexChar | _escapedOctChar | CharsNotIn(r'\]', exact=1) -_charRange = Group(_singleChar + Suppress("-") + _singleChar) -_reBracketExpr = Literal("[") + Optional("^").setResultsName("negate") + Group( OneOrMore( _charRange | _singleChar ) ).setResultsName("body") + "]" - -def srange(s): - r""" - Helper to easily define string ranges for use in Word construction. Borrows - syntax from regexp '[]' string range definitions:: - srange("[0-9]") -> "0123456789" - srange("[a-z]") -> "abcdefghijklmnopqrstuvwxyz" - srange("[a-z$_]") -> "abcdefghijklmnopqrstuvwxyz$_" - The input string must be enclosed in []'s, and the returned string is the expanded - character set joined into a single string. - The values enclosed in the []'s may be: - - a single character - - an escaped character with a leading backslash (such as C{\-} or C{\]}) - - an escaped hex character with a leading C{'\x'} (C{\x21}, which is a C{'!'} character) - (C{\0x##} is also supported for backwards compatibility) - - an escaped octal character with a leading C{'\0'} (C{\041}, which is a C{'!'} character) - - a range of any of the above, separated by a dash (C{'a-z'}, etc.) - - any combination of the above (C{'aeiouy'}, C{'a-zA-Z0-9_$'}, etc.) - """ - _expanded = lambda p: p if not isinstance(p,ParseResults) else ''.join(unichr(c) for c in range(ord(p[0]),ord(p[1])+1)) - try: - return "".join(_expanded(part) for part in _reBracketExpr.parseString(s).body) - except Exception: - return "" - -def matchOnlyAtCol(n): - """ - Helper method for defining parse actions that require matching at a specific - column in the input text. - """ - def verifyCol(strg,locn,toks): - if col(locn,strg) != n: - raise ParseException(strg,locn,"matched token not at column %d" % n) - return verifyCol - -def replaceWith(replStr): - """ - Helper method for common parse actions that simply return a literal value. Especially - useful when used with C{L{transformString<ParserElement.transformString>}()}. - - Example:: - num = Word(nums).setParseAction(lambda toks: int(toks[0])) - na = oneOf("N/A NA").setParseAction(replaceWith(math.nan)) - term = na | num - - OneOrMore(term).parseString("324 234 N/A 234") # -> [324, 234, nan, 234] - """ - return lambda s,l,t: [replStr] - -def removeQuotes(s,l,t): - """ - Helper parse action for removing quotation marks from parsed quoted strings. - - Example:: - # by default, quotation marks are included in parsed results - quotedString.parseString("'Now is the Winter of our Discontent'") # -> ["'Now is the Winter of our Discontent'"] - - # use removeQuotes to strip quotation marks from parsed results - quotedString.setParseAction(removeQuotes) - quotedString.parseString("'Now is the Winter of our Discontent'") # -> ["Now is the Winter of our Discontent"] - """ - return t[0][1:-1] - -def tokenMap(func, *args): - """ - Helper to define a parse action by mapping a function to all elements of a ParseResults list.If any additional - args are passed, they are forwarded to the given function as additional arguments after - the token, as in C{hex_integer = Word(hexnums).setParseAction(tokenMap(int, 16))}, which will convert the - parsed data to an integer using base 16. - - Example (compare the last to example in L{ParserElement.transformString}:: - hex_ints = OneOrMore(Word(hexnums)).setParseAction(tokenMap(int, 16)) - hex_ints.runTests(''' - 00 11 22 aa FF 0a 0d 1a - ''') - - upperword = Word(alphas).setParseAction(tokenMap(str.upper)) - OneOrMore(upperword).runTests(''' - my kingdom for a horse - ''') - - wd = Word(alphas).setParseAction(tokenMap(str.title)) - OneOrMore(wd).setParseAction(' '.join).runTests(''' - now is the winter of our discontent made glorious summer by this sun of york - ''') - prints:: - 00 11 22 aa FF 0a 0d 1a - [0, 17, 34, 170, 255, 10, 13, 26] - - my kingdom for a horse - ['MY', 'KINGDOM', 'FOR', 'A', 'HORSE'] - - now is the winter of our discontent made glorious summer by this sun of york - ['Now Is The Winter Of Our Discontent Made Glorious Summer By This Sun Of York'] - """ - def pa(s,l,t): - return [func(tokn, *args) for tokn in t] - - try: - func_name = getattr(func, '__name__', - getattr(func, '__class__').__name__) - except Exception: - func_name = str(func) - pa.__name__ = func_name - - return pa - -upcaseTokens = tokenMap(lambda t: _ustr(t).upper()) -"""(Deprecated) Helper parse action to convert tokens to upper case. Deprecated in favor of L{pyparsing_common.upcaseTokens}""" - -downcaseTokens = tokenMap(lambda t: _ustr(t).lower()) -"""(Deprecated) Helper parse action to convert tokens to lower case. Deprecated in favor of L{pyparsing_common.downcaseTokens}""" - -def _makeTags(tagStr, xml): - """Internal helper to construct opening and closing tag expressions, given a tag name""" - if isinstance(tagStr,basestring): - resname = tagStr - tagStr = Keyword(tagStr, caseless=not xml) - else: - resname = tagStr.name - - tagAttrName = Word(alphas,alphanums+"_-:") - if (xml): - tagAttrValue = dblQuotedString.copy().setParseAction( removeQuotes ) - openTag = Suppress("<") + tagStr("tag") + \ - Dict(ZeroOrMore(Group( tagAttrName + Suppress("=") + tagAttrValue ))) + \ - Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">") - else: - printablesLessRAbrack = "".join(c for c in printables if c not in ">") - tagAttrValue = quotedString.copy().setParseAction( removeQuotes ) | Word(printablesLessRAbrack) - openTag = Suppress("<") + tagStr("tag") + \ - Dict(ZeroOrMore(Group( tagAttrName.setParseAction(downcaseTokens) + \ - Optional( Suppress("=") + tagAttrValue ) ))) + \ - Optional("/",default=[False]).setResultsName("empty").setParseAction(lambda s,l,t:t[0]=='/') + Suppress(">") - closeTag = Combine(_L("</") + tagStr + ">") - - openTag = openTag.setResultsName("start"+"".join(resname.replace(":"," ").title().split())).setName("<%s>" % resname) - closeTag = closeTag.setResultsName("end"+"".join(resname.replace(":"," ").title().split())).setName("</%s>" % resname) - openTag.tag = resname - closeTag.tag = resname - return openTag, closeTag - -def makeHTMLTags(tagStr): - """ - Helper to construct opening and closing tag expressions for HTML, given a tag name. Matches - tags in either upper or lower case, attributes with namespaces and with quoted or unquoted values. - - Example:: - text = '<td>More info at the <a href="http://pyparsing.wikispaces.com">pyparsing</a> wiki page</td>' - # makeHTMLTags returns pyparsing expressions for the opening and closing tags as a 2-tuple - a,a_end = makeHTMLTags("A") - link_expr = a + SkipTo(a_end)("link_text") + a_end - - for link in link_expr.searchString(text): - # attributes in the <A> tag (like "href" shown here) are also accessible as named results - print(link.link_text, '->', link.href) - prints:: - pyparsing -> http://pyparsing.wikispaces.com - """ - return _makeTags( tagStr, False ) - -def makeXMLTags(tagStr): - """ - Helper to construct opening and closing tag expressions for XML, given a tag name. Matches - tags only in the given upper/lower case. - - Example: similar to L{makeHTMLTags} - """ - return _makeTags( tagStr, True ) - -def withAttribute(*args,**attrDict): - """ - Helper to create a validating parse action to be used with start tags created - with C{L{makeXMLTags}} or C{L{makeHTMLTags}}. Use C{withAttribute} to qualify a starting tag - with a required attribute value, to avoid false matches on common tags such as - C{<TD>} or C{<DIV>}. - - Call C{withAttribute} with a series of attribute names and values. Specify the list - of filter attributes names and values as: - - keyword arguments, as in C{(align="right")}, or - - as an explicit dict with C{**} operator, when an attribute name is also a Python - reserved word, as in C{**{"class":"Customer", "align":"right"}} - - a list of name-value tuples, as in ( ("ns1:class", "Customer"), ("ns2:align","right") ) - For attribute names with a namespace prefix, you must use the second form. Attribute - names are matched insensitive to upper/lower case. - - If just testing for C{class} (with or without a namespace), use C{L{withClass}}. - - To verify that the attribute exists, but without specifying a value, pass - C{withAttribute.ANY_VALUE} as the value. - - Example:: - html = ''' - <div> - Some text - <div type="grid">1 4 0 1 0</div> - <div type="graph">1,3 2,3 1,1</div> - <div>this has no type</div> - </div> - - ''' - div,div_end = makeHTMLTags("div") - - # only match div tag having a type attribute with value "grid" - div_grid = div().setParseAction(withAttribute(type="grid")) - grid_expr = div_grid + SkipTo(div | div_end)("body") - for grid_header in grid_expr.searchString(html): - print(grid_header.body) - - # construct a match with any div tag having a type attribute, regardless of the value - div_any_type = div().setParseAction(withAttribute(type=withAttribute.ANY_VALUE)) - div_expr = div_any_type + SkipTo(div | div_end)("body") - for div_header in div_expr.searchString(html): - print(div_header.body) - prints:: - 1 4 0 1 0 - - 1 4 0 1 0 - 1,3 2,3 1,1 - """ - if args: - attrs = args[:] - else: - attrs = attrDict.items() - attrs = [(k,v) for k,v in attrs] - def pa(s,l,tokens): - for attrName,attrValue in attrs: - if attrName not in tokens: - raise ParseException(s,l,"no matching attribute " + attrName) - if attrValue != withAttribute.ANY_VALUE and tokens[attrName] != attrValue: - raise ParseException(s,l,"attribute '%s' has value '%s', must be '%s'" % - (attrName, tokens[attrName], attrValue)) - return pa -withAttribute.ANY_VALUE = object() - -def withClass(classname, namespace=''): - """ - Simplified version of C{L{withAttribute}} when matching on a div class - made - difficult because C{class} is a reserved word in Python. - - Example:: - html = ''' - <div> - Some text - <div class="grid">1 4 0 1 0</div> - <div class="graph">1,3 2,3 1,1</div> - <div>this &lt;div&gt; has no class</div> - </div> - - ''' - div,div_end = makeHTMLTags("div") - div_grid = div().setParseAction(withClass("grid")) - - grid_expr = div_grid + SkipTo(div | div_end)("body") - for grid_header in grid_expr.searchString(html): - print(grid_header.body) - - div_any_type = div().setParseAction(withClass(withAttribute.ANY_VALUE)) - div_expr = div_any_type + SkipTo(div | div_end)("body") - for div_header in div_expr.searchString(html): - print(div_header.body) - prints:: - 1 4 0 1 0 - - 1 4 0 1 0 - 1,3 2,3 1,1 - """ - classattr = "%s:class" % namespace if namespace else "class" - return withAttribute(**{classattr : classname}) - -opAssoc = _Constants() -opAssoc.LEFT = object() -opAssoc.RIGHT = object() - -def infixNotation( baseExpr, opList, lpar=Suppress('('), rpar=Suppress(')') ): - """ - Helper method for constructing grammars of expressions made up of - operators working in a precedence hierarchy. Operators may be unary or - binary, left- or right-associative. Parse actions can also be attached - to operator expressions. The generated parser will also recognize the use - of parentheses to override operator precedences (see example below). - - Note: if you define a deep operator list, you may see performance issues - when using infixNotation. See L{ParserElement.enablePackrat} for a - mechanism to potentially improve your parser performance. - - Parameters: - - baseExpr - expression representing the most basic element for the nested - - opList - list of tuples, one for each operator precedence level in the - expression grammar; each tuple is of the form - (opExpr, numTerms, rightLeftAssoc, parseAction), where: - - opExpr is the pyparsing expression for the operator; - may also be a string, which will be converted to a Literal; - if numTerms is 3, opExpr is a tuple of two expressions, for the - two operators separating the 3 terms - - numTerms is the number of terms for this operator (must - be 1, 2, or 3) - - rightLeftAssoc is the indicator whether the operator is - right or left associative, using the pyparsing-defined - constants C{opAssoc.RIGHT} and C{opAssoc.LEFT}. - - parseAction is the parse action to be associated with - expressions matching this operator expression (the - parse action tuple member may be omitted); if the parse action - is passed a tuple or list of functions, this is equivalent to - calling C{setParseAction(*fn)} (L{ParserElement.setParseAction}) - - lpar - expression for matching left-parentheses (default=C{Suppress('(')}) - - rpar - expression for matching right-parentheses (default=C{Suppress(')')}) - - Example:: - # simple example of four-function arithmetic with ints and variable names - integer = pyparsing_common.signed_integer - varname = pyparsing_common.identifier - - arith_expr = infixNotation(integer | varname, - [ - ('-', 1, opAssoc.RIGHT), - (oneOf('* /'), 2, opAssoc.LEFT), - (oneOf('+ -'), 2, opAssoc.LEFT), - ]) - - arith_expr.runTests(''' - 5+3*6 - (5+3)*6 - -2--11 - ''', fullDump=False) - prints:: - 5+3*6 - [[5, '+', [3, '*', 6]]] - - (5+3)*6 - [[[5, '+', 3], '*', 6]] - - -2--11 - [[['-', 2], '-', ['-', 11]]] - """ - ret = Forward() - lastExpr = baseExpr | ( lpar + ret + rpar ) - for i,operDef in enumerate(opList): - opExpr,arity,rightLeftAssoc,pa = (operDef + (None,))[:4] - termName = "%s term" % opExpr if arity < 3 else "%s%s term" % opExpr - if arity == 3: - if opExpr is None or len(opExpr) != 2: - raise ValueError("if numterms=3, opExpr must be a tuple or list of two expressions") - opExpr1, opExpr2 = opExpr - thisExpr = Forward().setName(termName) - if rightLeftAssoc == opAssoc.LEFT: - if arity == 1: - matchExpr = FollowedBy(lastExpr + opExpr) + Group( lastExpr + OneOrMore( opExpr ) ) - elif arity == 2: - if opExpr is not None: - matchExpr = FollowedBy(lastExpr + opExpr + lastExpr) + Group( lastExpr + OneOrMore( opExpr + lastExpr ) ) - else: - matchExpr = FollowedBy(lastExpr+lastExpr) + Group( lastExpr + OneOrMore(lastExpr) ) - elif arity == 3: - matchExpr = FollowedBy(lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr) + \ - Group( lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr ) - else: - raise ValueError("operator must be unary (1), binary (2), or ternary (3)") - elif rightLeftAssoc == opAssoc.RIGHT: - if arity == 1: - # try to avoid LR with this extra test - if not isinstance(opExpr, Optional): - opExpr = Optional(opExpr) - matchExpr = FollowedBy(opExpr.expr + thisExpr) + Group( opExpr + thisExpr ) - elif arity == 2: - if opExpr is not None: - matchExpr = FollowedBy(lastExpr + opExpr + thisExpr) + Group( lastExpr + OneOrMore( opExpr + thisExpr ) ) - else: - matchExpr = FollowedBy(lastExpr + thisExpr) + Group( lastExpr + OneOrMore( thisExpr ) ) - elif arity == 3: - matchExpr = FollowedBy(lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr) + \ - Group( lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr ) - else: - raise ValueError("operator must be unary (1), binary (2), or ternary (3)") - else: - raise ValueError("operator must indicate right or left associativity") - if pa: - if isinstance(pa, (tuple, list)): - matchExpr.setParseAction(*pa) - else: - matchExpr.setParseAction(pa) - thisExpr <<= ( matchExpr.setName(termName) | lastExpr ) - lastExpr = thisExpr - ret <<= lastExpr - return ret - -operatorPrecedence = infixNotation -"""(Deprecated) Former name of C{L{infixNotation}}, will be dropped in a future release.""" - -dblQuotedString = Combine(Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*')+'"').setName("string enclosed in double quotes") -sglQuotedString = Combine(Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*")+"'").setName("string enclosed in single quotes") -quotedString = Combine(Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*')+'"'| - Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*")+"'").setName("quotedString using single or double quotes") -unicodeString = Combine(_L('u') + quotedString.copy()).setName("unicode string literal") - -def nestedExpr(opener="(", closer=")", content=None, ignoreExpr=quotedString.copy()): - """ - Helper method for defining nested lists enclosed in opening and closing - delimiters ("(" and ")" are the default). - - Parameters: - - opener - opening character for a nested list (default=C{"("}); can also be a pyparsing expression - - closer - closing character for a nested list (default=C{")"}); can also be a pyparsing expression - - content - expression for items within the nested lists (default=C{None}) - - ignoreExpr - expression for ignoring opening and closing delimiters (default=C{quotedString}) - - If an expression is not provided for the content argument, the nested - expression will capture all whitespace-delimited content between delimiters - as a list of separate values. - - Use the C{ignoreExpr} argument to define expressions that may contain - opening or closing characters that should not be treated as opening - or closing characters for nesting, such as quotedString or a comment - expression. Specify multiple expressions using an C{L{Or}} or C{L{MatchFirst}}. - The default is L{quotedString}, but if no expressions are to be ignored, - then pass C{None} for this argument. - - Example:: - data_type = oneOf("void int short long char float double") - decl_data_type = Combine(data_type + Optional(Word('*'))) - ident = Word(alphas+'_', alphanums+'_') - number = pyparsing_common.number - arg = Group(decl_data_type + ident) - LPAR,RPAR = map(Suppress, "()") - - code_body = nestedExpr('{', '}', ignoreExpr=(quotedString | cStyleComment)) - - c_function = (decl_data_type("type") - + ident("name") - + LPAR + Optional(delimitedList(arg), [])("args") + RPAR - + code_body("body")) - c_function.ignore(cStyleComment) - - source_code = ''' - int is_odd(int x) { - return (x%2); - } - - int dec_to_hex(char hchar) { - if (hchar >= '0' && hchar <= '9') { - return (ord(hchar)-ord('0')); - } else { - return (10+ord(hchar)-ord('A')); - } - } - ''' - for func in c_function.searchString(source_code): - print("%(name)s (%(type)s) args: %(args)s" % func) - - prints:: - is_odd (int) args: [['int', 'x']] - dec_to_hex (int) args: [['char', 'hchar']] - """ - if opener == closer: - raise ValueError("opening and closing strings cannot be the same") - if content is None: - if isinstance(opener,basestring) and isinstance(closer,basestring): - if len(opener) == 1 and len(closer)==1: - if ignoreExpr is not None: - content = (Combine(OneOrMore(~ignoreExpr + - CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS,exact=1)) - ).setParseAction(lambda t:t[0].strip())) - else: - content = (empty.copy()+CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS - ).setParseAction(lambda t:t[0].strip())) - else: - if ignoreExpr is not None: - content = (Combine(OneOrMore(~ignoreExpr + - ~Literal(opener) + ~Literal(closer) + - CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1)) - ).setParseAction(lambda t:t[0].strip())) - else: - content = (Combine(OneOrMore(~Literal(opener) + ~Literal(closer) + - CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1)) - ).setParseAction(lambda t:t[0].strip())) - else: - raise ValueError("opening and closing arguments must be strings if no content expression is given") - ret = Forward() - if ignoreExpr is not None: - ret <<= Group( Suppress(opener) + ZeroOrMore( ignoreExpr | ret | content ) + Suppress(closer) ) - else: - ret <<= Group( Suppress(opener) + ZeroOrMore( ret | content ) + Suppress(closer) ) - ret.setName('nested %s%s expression' % (opener,closer)) - return ret - -def indentedBlock(blockStatementExpr, indentStack, indent=True): - """ - Helper method for defining space-delimited indentation blocks, such as - those used to define block statements in Python source code. - - Parameters: - - blockStatementExpr - expression defining syntax of statement that - is repeated within the indented block - - indentStack - list created by caller to manage indentation stack - (multiple statementWithIndentedBlock expressions within a single grammar - should share a common indentStack) - - indent - boolean indicating whether block must be indented beyond the - the current level; set to False for block of left-most statements - (default=C{True}) - - A valid block must contain at least one C{blockStatement}. - - Example:: - data = ''' - def A(z): - A1 - B = 100 - G = A2 - A2 - A3 - B - def BB(a,b,c): - BB1 - def BBA(): - bba1 - bba2 - bba3 - C - D - def spam(x,y): - def eggs(z): - pass - ''' - - - indentStack = [1] - stmt = Forward() - - identifier = Word(alphas, alphanums) - funcDecl = ("def" + identifier + Group( "(" + Optional( delimitedList(identifier) ) + ")" ) + ":") - func_body = indentedBlock(stmt, indentStack) - funcDef = Group( funcDecl + func_body ) - - rvalue = Forward() - funcCall = Group(identifier + "(" + Optional(delimitedList(rvalue)) + ")") - rvalue << (funcCall | identifier | Word(nums)) - assignment = Group(identifier + "=" + rvalue) - stmt << ( funcDef | assignment | identifier ) - - module_body = OneOrMore(stmt) - - parseTree = module_body.parseString(data) - parseTree.pprint() - prints:: - [['def', - 'A', - ['(', 'z', ')'], - ':', - [['A1'], [['B', '=', '100']], [['G', '=', 'A2']], ['A2'], ['A3']]], - 'B', - ['def', - 'BB', - ['(', 'a', 'b', 'c', ')'], - ':', - [['BB1'], [['def', 'BBA', ['(', ')'], ':', [['bba1'], ['bba2'], ['bba3']]]]]], - 'C', - 'D', - ['def', - 'spam', - ['(', 'x', 'y', ')'], - ':', - [[['def', 'eggs', ['(', 'z', ')'], ':', [['pass']]]]]]] - """ - def checkPeerIndent(s,l,t): - if l >= len(s): return - curCol = col(l,s) - if curCol != indentStack[-1]: - if curCol > indentStack[-1]: - raise ParseFatalException(s,l,"illegal nesting") - raise ParseException(s,l,"not a peer entry") - - def checkSubIndent(s,l,t): - curCol = col(l,s) - if curCol > indentStack[-1]: - indentStack.append( curCol ) - else: - raise ParseException(s,l,"not a subentry") - - def checkUnindent(s,l,t): - if l >= len(s): return - curCol = col(l,s) - if not(indentStack and curCol < indentStack[-1] and curCol <= indentStack[-2]): - raise ParseException(s,l,"not an unindent") - indentStack.pop() - - NL = OneOrMore(LineEnd().setWhitespaceChars("\t ").suppress()) - INDENT = (Empty() + Empty().setParseAction(checkSubIndent)).setName('INDENT') - PEER = Empty().setParseAction(checkPeerIndent).setName('') - UNDENT = Empty().setParseAction(checkUnindent).setName('UNINDENT') - if indent: - smExpr = Group( Optional(NL) + - #~ FollowedBy(blockStatementExpr) + - INDENT + (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) + UNDENT) - else: - smExpr = Group( Optional(NL) + - (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) ) - blockStatementExpr.ignore(_bslash + LineEnd()) - return smExpr.setName('indented block') - -alphas8bit = srange(r"[\0xc0-\0xd6\0xd8-\0xf6\0xf8-\0xff]") -punc8bit = srange(r"[\0xa1-\0xbf\0xd7\0xf7]") - -anyOpenTag,anyCloseTag = makeHTMLTags(Word(alphas,alphanums+"_:").setName('any tag')) -_htmlEntityMap = dict(zip("gt lt amp nbsp quot apos".split(),'><& "\'')) -commonHTMLEntity = Regex('&(?P<entity>' + '|'.join(_htmlEntityMap.keys()) +");").setName("common HTML entity") -def replaceHTMLEntity(t): - """Helper parser action to replace common HTML entities with their special characters""" - return _htmlEntityMap.get(t.entity) - -# it's easy to get these comment structures wrong - they're very common, so may as well make them available -cStyleComment = Combine(Regex(r"/\*(?:[^*]|\*(?!/))*") + '*/').setName("C style comment") -"Comment of the form C{/* ... */}" - -htmlComment = Regex(r"<!--[\s\S]*?-->").setName("HTML comment") -"Comment of the form C{<!-- ... -->}" - -restOfLine = Regex(r".*").leaveWhitespace().setName("rest of line") -dblSlashComment = Regex(r"//(?:\\\n|[^\n])*").setName("// comment") -"Comment of the form C{// ... (to end of line)}" - -cppStyleComment = Combine(Regex(r"/\*(?:[^*]|\*(?!/))*") + '*/'| dblSlashComment).setName("C++ style comment") -"Comment of either form C{L{cStyleComment}} or C{L{dblSlashComment}}" - -javaStyleComment = cppStyleComment -"Same as C{L{cppStyleComment}}" - -pythonStyleComment = Regex(r"#.*").setName("Python style comment") -"Comment of the form C{# ... (to end of line)}" - -_commasepitem = Combine(OneOrMore(Word(printables, excludeChars=',') + - Optional( Word(" \t") + - ~Literal(",") + ~LineEnd() ) ) ).streamline().setName("commaItem") -commaSeparatedList = delimitedList( Optional( quotedString.copy() | _commasepitem, default="") ).setName("commaSeparatedList") -"""(Deprecated) Predefined expression of 1 or more printable words or quoted strings, separated by commas. - This expression is deprecated in favor of L{pyparsing_common.comma_separated_list}.""" - -# some other useful expressions - using lower-case class name since we are really using this as a namespace -class pyparsing_common: - """ - Here are some common low-level expressions that may be useful in jump-starting parser development: - - numeric forms (L{integers<integer>}, L{reals<real>}, L{scientific notation<sci_real>}) - - common L{programming identifiers<identifier>} - - network addresses (L{MAC<mac_address>}, L{IPv4<ipv4_address>}, L{IPv6<ipv6_address>}) - - ISO8601 L{dates<iso8601_date>} and L{datetime<iso8601_datetime>} - - L{UUID<uuid>} - - L{comma-separated list<comma_separated_list>} - Parse actions: - - C{L{convertToInteger}} - - C{L{convertToFloat}} - - C{L{convertToDate}} - - C{L{convertToDatetime}} - - C{L{stripHTMLTags}} - - C{L{upcaseTokens}} - - C{L{downcaseTokens}} - - Example:: - pyparsing_common.number.runTests(''' - # any int or real number, returned as the appropriate type - 100 - -100 - +100 - 3.14159 - 6.02e23 - 1e-12 - ''') - - pyparsing_common.fnumber.runTests(''' - # any int or real number, returned as float - 100 - -100 - +100 - 3.14159 - 6.02e23 - 1e-12 - ''') - - pyparsing_common.hex_integer.runTests(''' - # hex numbers - 100 - FF - ''') - - pyparsing_common.fraction.runTests(''' - # fractions - 1/2 - -3/4 - ''') - - pyparsing_common.mixed_integer.runTests(''' - # mixed fractions - 1 - 1/2 - -3/4 - 1-3/4 - ''') - - import uuid - pyparsing_common.uuid.setParseAction(tokenMap(uuid.UUID)) - pyparsing_common.uuid.runTests(''' - # uuid - 12345678-1234-5678-1234-567812345678 - ''') - prints:: - # any int or real number, returned as the appropriate type - 100 - [100] - - -100 - [-100] - - +100 - [100] - - 3.14159 - [3.14159] - - 6.02e23 - [6.02e+23] - - 1e-12 - [1e-12] - - # any int or real number, returned as float - 100 - [100.0] - - -100 - [-100.0] - - +100 - [100.0] - - 3.14159 - [3.14159] - - 6.02e23 - [6.02e+23] - - 1e-12 - [1e-12] - - # hex numbers - 100 - [256] - - FF - [255] - - # fractions - 1/2 - [0.5] - - -3/4 - [-0.75] - - # mixed fractions - 1 - [1] - - 1/2 - [0.5] - - -3/4 - [-0.75] - - 1-3/4 - [1.75] - - # uuid - 12345678-1234-5678-1234-567812345678 - [UUID('12345678-1234-5678-1234-567812345678')] - """ - - convertToInteger = tokenMap(int) - """ - Parse action for converting parsed integers to Python int - """ - - convertToFloat = tokenMap(float) - """ - Parse action for converting parsed numbers to Python float - """ - - integer = Word(nums).setName("integer").setParseAction(convertToInteger) - """expression that parses an unsigned integer, returns an int""" - - hex_integer = Word(hexnums).setName("hex integer").setParseAction(tokenMap(int,16)) - """expression that parses a hexadecimal integer, returns an int""" - - signed_integer = Regex(r'[+-]?\d+').setName("signed integer").setParseAction(convertToInteger) - """expression that parses an integer with optional leading sign, returns an int""" - - fraction = (signed_integer().setParseAction(convertToFloat) + '/' + signed_integer().setParseAction(convertToFloat)).setName("fraction") - """fractional expression of an integer divided by an integer, returns a float""" - fraction.addParseAction(lambda t: t[0]/t[-1]) - - mixed_integer = (fraction | signed_integer + Optional(Optional('-').suppress() + fraction)).setName("fraction or mixed integer-fraction") - """mixed integer of the form 'integer - fraction', with optional leading integer, returns float""" - mixed_integer.addParseAction(sum) - - real = Regex(r'[+-]?\d+\.\d*').setName("real number").setParseAction(convertToFloat) - """expression that parses a floating point number and returns a float""" - - sci_real = Regex(r'[+-]?\d+([eE][+-]?\d+|\.\d*([eE][+-]?\d+)?)').setName("real number with scientific notation").setParseAction(convertToFloat) - """expression that parses a floating point number with optional scientific notation and returns a float""" - - # streamlining this expression makes the docs nicer-looking - number = (sci_real | real | signed_integer).streamline() - """any numeric expression, returns the corresponding Python type""" - - fnumber = Regex(r'[+-]?\d+\.?\d*([eE][+-]?\d+)?').setName("fnumber").setParseAction(convertToFloat) - """any int or real number, returned as float""" - - identifier = Word(alphas+'_', alphanums+'_').setName("identifier") - """typical code identifier (leading alpha or '_', followed by 0 or more alphas, nums, or '_')""" - - ipv4_address = Regex(r'(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})(\.(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})){3}').setName("IPv4 address") - "IPv4 address (C{0.0.0.0 - 255.255.255.255})" - - _ipv6_part = Regex(r'[0-9a-fA-F]{1,4}').setName("hex_integer") - _full_ipv6_address = (_ipv6_part + (':' + _ipv6_part)*7).setName("full IPv6 address") - _short_ipv6_address = (Optional(_ipv6_part + (':' + _ipv6_part)*(0,6)) + "::" + Optional(_ipv6_part + (':' + _ipv6_part)*(0,6))).setName("short IPv6 address") - _short_ipv6_address.addCondition(lambda t: sum(1 for tt in t if pyparsing_common._ipv6_part.matches(tt)) < 8) - _mixed_ipv6_address = ("::ffff:" + ipv4_address).setName("mixed IPv6 address") - ipv6_address = Combine((_full_ipv6_address | _mixed_ipv6_address | _short_ipv6_address).setName("IPv6 address")).setName("IPv6 address") - "IPv6 address (long, short, or mixed form)" - - mac_address = Regex(r'[0-9a-fA-F]{2}([:.-])[0-9a-fA-F]{2}(?:\1[0-9a-fA-F]{2}){4}').setName("MAC address") - "MAC address xx:xx:xx:xx:xx (may also have '-' or '.' delimiters)" - - @staticmethod - def convertToDate(fmt="%Y-%m-%d"): - """ - Helper to create a parse action for converting parsed date string to Python datetime.date - - Params - - - fmt - format to be passed to datetime.strptime (default=C{"%Y-%m-%d"}) - - Example:: - date_expr = pyparsing_common.iso8601_date.copy() - date_expr.setParseAction(pyparsing_common.convertToDate()) - print(date_expr.parseString("1999-12-31")) - prints:: - [datetime.date(1999, 12, 31)] - """ - def cvt_fn(s,l,t): - try: - return datetime.strptime(t[0], fmt).date() - except ValueError as ve: - raise ParseException(s, l, str(ve)) - return cvt_fn - - @staticmethod - def convertToDatetime(fmt="%Y-%m-%dT%H:%M:%S.%f"): - """ - Helper to create a parse action for converting parsed datetime string to Python datetime.datetime - - Params - - - fmt - format to be passed to datetime.strptime (default=C{"%Y-%m-%dT%H:%M:%S.%f"}) - - Example:: - dt_expr = pyparsing_common.iso8601_datetime.copy() - dt_expr.setParseAction(pyparsing_common.convertToDatetime()) - print(dt_expr.parseString("1999-12-31T23:59:59.999")) - prints:: - [datetime.datetime(1999, 12, 31, 23, 59, 59, 999000)] - """ - def cvt_fn(s,l,t): - try: - return datetime.strptime(t[0], fmt) - except ValueError as ve: - raise ParseException(s, l, str(ve)) - return cvt_fn - - iso8601_date = Regex(r'(?P<year>\d{4})(?:-(?P<month>\d\d)(?:-(?P<day>\d\d))?)?').setName("ISO8601 date") - "ISO8601 date (C{yyyy-mm-dd})" - - iso8601_datetime = Regex(r'(?P<year>\d{4})-(?P<month>\d\d)-(?P<day>\d\d)[T ](?P<hour>\d\d):(?P<minute>\d\d)(:(?P<second>\d\d(\.\d*)?)?)?(?P<tz>Z|[+-]\d\d:?\d\d)?').setName("ISO8601 datetime") - "ISO8601 datetime (C{yyyy-mm-ddThh:mm:ss.s(Z|+-00:00)}) - trailing seconds, milliseconds, and timezone optional; accepts separating C{'T'} or C{' '}" - - uuid = Regex(r'[0-9a-fA-F]{8}(-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}').setName("UUID") - "UUID (C{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx})" - - _html_stripper = anyOpenTag.suppress() | anyCloseTag.suppress() - @staticmethod - def stripHTMLTags(s, l, tokens): - """ - Parse action to remove HTML tags from web page HTML source - - Example:: - # strip HTML links from normal text - text = '<td>More info at the <a href="http://pyparsing.wikispaces.com">pyparsing</a> wiki page</td>' - td,td_end = makeHTMLTags("TD") - table_text = td + SkipTo(td_end).setParseAction(pyparsing_common.stripHTMLTags)("body") + td_end - - print(table_text.parseString(text).body) # -> 'More info at the pyparsing wiki page' - """ - return pyparsing_common._html_stripper.transformString(tokens[0]) - - _commasepitem = Combine(OneOrMore(~Literal(",") + ~LineEnd() + Word(printables, excludeChars=',') - + Optional( White(" \t") ) ) ).streamline().setName("commaItem") - comma_separated_list = delimitedList( Optional( quotedString.copy() | _commasepitem, default="") ).setName("comma separated list") - """Predefined expression of 1 or more printable words or quoted strings, separated by commas.""" - - upcaseTokens = staticmethod(tokenMap(lambda t: _ustr(t).upper())) - """Parse action to convert tokens to upper case.""" - - downcaseTokens = staticmethod(tokenMap(lambda t: _ustr(t).lower())) - """Parse action to convert tokens to lower case.""" - - -if __name__ == "__main__": - - selectToken = CaselessLiteral("select") - fromToken = CaselessLiteral("from") - - ident = Word(alphas, alphanums + "_$") - - columnName = delimitedList(ident, ".", combine=True).setParseAction(upcaseTokens) - columnNameList = Group(delimitedList(columnName)).setName("columns") - columnSpec = ('*' | columnNameList) - - tableName = delimitedList(ident, ".", combine=True).setParseAction(upcaseTokens) - tableNameList = Group(delimitedList(tableName)).setName("tables") - - simpleSQL = selectToken("command") + columnSpec("columns") + fromToken + tableNameList("tables") - - # demo runTests method, including embedded comments in test string - simpleSQL.runTests(""" - # '*' as column list and dotted table name - select * from SYS.XYZZY - - # caseless match on "SELECT", and casts back to "select" - SELECT * from XYZZY, ABC - - # list of column names, and mixed case SELECT keyword - Select AA,BB,CC from Sys.dual - - # multiple tables - Select A, B, C from Sys.dual, Table2 - - # invalid SELECT keyword - should fail - Xelect A, B, C from Sys.dual - - # incomplete command - should fail - Select - - # invalid column name - should fail - Select ^^^ frox Sys.dual - - """) - - pyparsing_common.number.runTests(""" - 100 - -100 - +100 - 3.14159 - 6.02e23 - 1e-12 - """) - - # any int or real number, returned as float - pyparsing_common.fnumber.runTests(""" - 100 - -100 - +100 - 3.14159 - 6.02e23 - 1e-12 - """) - - pyparsing_common.hex_integer.runTests(""" - 100 - FF - """) - - import uuid - pyparsing_common.uuid.setParseAction(tokenMap(uuid.UUID)) - pyparsing_common.uuid.runTests(""" - 12345678-1234-5678-1234-567812345678 - """) diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/six.py b/venv/lib/python3.8/site-packages/setuptools/_vendor/six.py deleted file mode 100644 index 190c023..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/_vendor/six.py +++ /dev/null @@ -1,868 +0,0 @@ -"""Utilities for writing code that runs on Python 2 and 3""" - -# Copyright (c) 2010-2015 Benjamin Peterson -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -from __future__ import absolute_import - -import functools -import itertools -import operator -import sys -import types - -__author__ = "Benjamin Peterson <benjamin@python.org>" -__version__ = "1.10.0" - - -# Useful for very coarse version differentiation. -PY2 = sys.version_info[0] == 2 -PY3 = sys.version_info[0] == 3 -PY34 = sys.version_info[0:2] >= (3, 4) - -if PY3: - string_types = str, - integer_types = int, - class_types = type, - text_type = str - binary_type = bytes - - MAXSIZE = sys.maxsize -else: - string_types = basestring, - integer_types = (int, long) - class_types = (type, types.ClassType) - text_type = unicode - binary_type = str - - if sys.platform.startswith("java"): - # Jython always uses 32 bits. - MAXSIZE = int((1 << 31) - 1) - else: - # It's possible to have sizeof(long) != sizeof(Py_ssize_t). - class X(object): - - def __len__(self): - return 1 << 31 - try: - len(X()) - except OverflowError: - # 32-bit - MAXSIZE = int((1 << 31) - 1) - else: - # 64-bit - MAXSIZE = int((1 << 63) - 1) - del X - - -def _add_doc(func, doc): - """Add documentation to a function.""" - func.__doc__ = doc - - -def _import_module(name): - """Import module, returning the module after the last dot.""" - __import__(name) - return sys.modules[name] - - -class _LazyDescr(object): - - def __init__(self, name): - self.name = name - - def __get__(self, obj, tp): - result = self._resolve() - setattr(obj, self.name, result) # Invokes __set__. - try: - # This is a bit ugly, but it avoids running this again by - # removing this descriptor. - delattr(obj.__class__, self.name) - except AttributeError: - pass - return result - - -class MovedModule(_LazyDescr): - - def __init__(self, name, old, new=None): - super(MovedModule, self).__init__(name) - if PY3: - if new is None: - new = name - self.mod = new - else: - self.mod = old - - def _resolve(self): - return _import_module(self.mod) - - def __getattr__(self, attr): - _module = self._resolve() - value = getattr(_module, attr) - setattr(self, attr, value) - return value - - -class _LazyModule(types.ModuleType): - - def __init__(self, name): - super(_LazyModule, self).__init__(name) - self.__doc__ = self.__class__.__doc__ - - def __dir__(self): - attrs = ["__doc__", "__name__"] - attrs += [attr.name for attr in self._moved_attributes] - return attrs - - # Subclasses should override this - _moved_attributes = [] - - -class MovedAttribute(_LazyDescr): - - def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None): - super(MovedAttribute, self).__init__(name) - if PY3: - if new_mod is None: - new_mod = name - self.mod = new_mod - if new_attr is None: - if old_attr is None: - new_attr = name - else: - new_attr = old_attr - self.attr = new_attr - else: - self.mod = old_mod - if old_attr is None: - old_attr = name - self.attr = old_attr - - def _resolve(self): - module = _import_module(self.mod) - return getattr(module, self.attr) - - -class _SixMetaPathImporter(object): - - """ - A meta path importer to import six.moves and its submodules. - - This class implements a PEP302 finder and loader. It should be compatible - with Python 2.5 and all existing versions of Python3 - """ - - def __init__(self, six_module_name): - self.name = six_module_name - self.known_modules = {} - - def _add_module(self, mod, *fullnames): - for fullname in fullnames: - self.known_modules[self.name + "." + fullname] = mod - - def _get_module(self, fullname): - return self.known_modules[self.name + "." + fullname] - - def find_module(self, fullname, path=None): - if fullname in self.known_modules: - return self - return None - - def __get_module(self, fullname): - try: - return self.known_modules[fullname] - except KeyError: - raise ImportError("This loader does not know module " + fullname) - - def load_module(self, fullname): - try: - # in case of a reload - return sys.modules[fullname] - except KeyError: - pass - mod = self.__get_module(fullname) - if isinstance(mod, MovedModule): - mod = mod._resolve() - else: - mod.__loader__ = self - sys.modules[fullname] = mod - return mod - - def is_package(self, fullname): - """ - Return true, if the named module is a package. - - We need this method to get correct spec objects with - Python 3.4 (see PEP451) - """ - return hasattr(self.__get_module(fullname), "__path__") - - def get_code(self, fullname): - """Return None - - Required, if is_package is implemented""" - self.__get_module(fullname) # eventually raises ImportError - return None - get_source = get_code # same as get_code - -_importer = _SixMetaPathImporter(__name__) - - -class _MovedItems(_LazyModule): - - """Lazy loading of moved objects""" - __path__ = [] # mark as package - - -_moved_attributes = [ - MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"), - MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"), - MovedAttribute("filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"), - MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"), - MovedAttribute("intern", "__builtin__", "sys"), - MovedAttribute("map", "itertools", "builtins", "imap", "map"), - MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"), - MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"), - MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"), - MovedAttribute("reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload"), - MovedAttribute("reduce", "__builtin__", "functools"), - MovedAttribute("shlex_quote", "pipes", "shlex", "quote"), - MovedAttribute("StringIO", "StringIO", "io"), - MovedAttribute("UserDict", "UserDict", "collections"), - MovedAttribute("UserList", "UserList", "collections"), - MovedAttribute("UserString", "UserString", "collections"), - MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"), - MovedAttribute("zip", "itertools", "builtins", "izip", "zip"), - MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"), - MovedModule("builtins", "__builtin__"), - MovedModule("configparser", "ConfigParser"), - MovedModule("copyreg", "copy_reg"), - MovedModule("dbm_gnu", "gdbm", "dbm.gnu"), - MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread"), - MovedModule("http_cookiejar", "cookielib", "http.cookiejar"), - MovedModule("http_cookies", "Cookie", "http.cookies"), - MovedModule("html_entities", "htmlentitydefs", "html.entities"), - MovedModule("html_parser", "HTMLParser", "html.parser"), - MovedModule("http_client", "httplib", "http.client"), - MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"), - MovedModule("email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart"), - MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"), - MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"), - MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"), - MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"), - MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"), - MovedModule("cPickle", "cPickle", "pickle"), - MovedModule("queue", "Queue"), - MovedModule("reprlib", "repr"), - MovedModule("socketserver", "SocketServer"), - MovedModule("_thread", "thread", "_thread"), - MovedModule("tkinter", "Tkinter"), - MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"), - MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"), - MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"), - MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"), - MovedModule("tkinter_tix", "Tix", "tkinter.tix"), - MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"), - MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"), - MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"), - MovedModule("tkinter_colorchooser", "tkColorChooser", - "tkinter.colorchooser"), - MovedModule("tkinter_commondialog", "tkCommonDialog", - "tkinter.commondialog"), - MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"), - MovedModule("tkinter_font", "tkFont", "tkinter.font"), - MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"), - MovedModule("tkinter_tksimpledialog", "tkSimpleDialog", - "tkinter.simpledialog"), - MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"), - MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"), - MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"), - MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"), - MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"), - MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"), -] -# Add windows specific modules. -if sys.platform == "win32": - _moved_attributes += [ - MovedModule("winreg", "_winreg"), - ] - -for attr in _moved_attributes: - setattr(_MovedItems, attr.name, attr) - if isinstance(attr, MovedModule): - _importer._add_module(attr, "moves." + attr.name) -del attr - -_MovedItems._moved_attributes = _moved_attributes - -moves = _MovedItems(__name__ + ".moves") -_importer._add_module(moves, "moves") - - -class Module_six_moves_urllib_parse(_LazyModule): - - """Lazy loading of moved objects in six.moves.urllib_parse""" - - -_urllib_parse_moved_attributes = [ - MovedAttribute("ParseResult", "urlparse", "urllib.parse"), - MovedAttribute("SplitResult", "urlparse", "urllib.parse"), - MovedAttribute("parse_qs", "urlparse", "urllib.parse"), - MovedAttribute("parse_qsl", "urlparse", "urllib.parse"), - MovedAttribute("urldefrag", "urlparse", "urllib.parse"), - MovedAttribute("urljoin", "urlparse", "urllib.parse"), - MovedAttribute("urlparse", "urlparse", "urllib.parse"), - MovedAttribute("urlsplit", "urlparse", "urllib.parse"), - MovedAttribute("urlunparse", "urlparse", "urllib.parse"), - MovedAttribute("urlunsplit", "urlparse", "urllib.parse"), - MovedAttribute("quote", "urllib", "urllib.parse"), - MovedAttribute("quote_plus", "urllib", "urllib.parse"), - MovedAttribute("unquote", "urllib", "urllib.parse"), - MovedAttribute("unquote_plus", "urllib", "urllib.parse"), - MovedAttribute("urlencode", "urllib", "urllib.parse"), - MovedAttribute("splitquery", "urllib", "urllib.parse"), - MovedAttribute("splittag", "urllib", "urllib.parse"), - MovedAttribute("splituser", "urllib", "urllib.parse"), - MovedAttribute("uses_fragment", "urlparse", "urllib.parse"), - MovedAttribute("uses_netloc", "urlparse", "urllib.parse"), - MovedAttribute("uses_params", "urlparse", "urllib.parse"), - MovedAttribute("uses_query", "urlparse", "urllib.parse"), - MovedAttribute("uses_relative", "urlparse", "urllib.parse"), -] -for attr in _urllib_parse_moved_attributes: - setattr(Module_six_moves_urllib_parse, attr.name, attr) -del attr - -Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes - -_importer._add_module(Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"), - "moves.urllib_parse", "moves.urllib.parse") - - -class Module_six_moves_urllib_error(_LazyModule): - - """Lazy loading of moved objects in six.moves.urllib_error""" - - -_urllib_error_moved_attributes = [ - MovedAttribute("URLError", "urllib2", "urllib.error"), - MovedAttribute("HTTPError", "urllib2", "urllib.error"), - MovedAttribute("ContentTooShortError", "urllib", "urllib.error"), -] -for attr in _urllib_error_moved_attributes: - setattr(Module_six_moves_urllib_error, attr.name, attr) -del attr - -Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes - -_importer._add_module(Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"), - "moves.urllib_error", "moves.urllib.error") - - -class Module_six_moves_urllib_request(_LazyModule): - - """Lazy loading of moved objects in six.moves.urllib_request""" - - -_urllib_request_moved_attributes = [ - MovedAttribute("urlopen", "urllib2", "urllib.request"), - MovedAttribute("install_opener", "urllib2", "urllib.request"), - MovedAttribute("build_opener", "urllib2", "urllib.request"), - MovedAttribute("pathname2url", "urllib", "urllib.request"), - MovedAttribute("url2pathname", "urllib", "urllib.request"), - MovedAttribute("getproxies", "urllib", "urllib.request"), - MovedAttribute("Request", "urllib2", "urllib.request"), - MovedAttribute("OpenerDirector", "urllib2", "urllib.request"), - MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"), - MovedAttribute("ProxyHandler", "urllib2", "urllib.request"), - MovedAttribute("BaseHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"), - MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"), - MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"), - MovedAttribute("FileHandler", "urllib2", "urllib.request"), - MovedAttribute("FTPHandler", "urllib2", "urllib.request"), - MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"), - MovedAttribute("UnknownHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"), - MovedAttribute("urlretrieve", "urllib", "urllib.request"), - MovedAttribute("urlcleanup", "urllib", "urllib.request"), - MovedAttribute("URLopener", "urllib", "urllib.request"), - MovedAttribute("FancyURLopener", "urllib", "urllib.request"), - MovedAttribute("proxy_bypass", "urllib", "urllib.request"), -] -for attr in _urllib_request_moved_attributes: - setattr(Module_six_moves_urllib_request, attr.name, attr) -del attr - -Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes - -_importer._add_module(Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"), - "moves.urllib_request", "moves.urllib.request") - - -class Module_six_moves_urllib_response(_LazyModule): - - """Lazy loading of moved objects in six.moves.urllib_response""" - - -_urllib_response_moved_attributes = [ - MovedAttribute("addbase", "urllib", "urllib.response"), - MovedAttribute("addclosehook", "urllib", "urllib.response"), - MovedAttribute("addinfo", "urllib", "urllib.response"), - MovedAttribute("addinfourl", "urllib", "urllib.response"), -] -for attr in _urllib_response_moved_attributes: - setattr(Module_six_moves_urllib_response, attr.name, attr) -del attr - -Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes - -_importer._add_module(Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"), - "moves.urllib_response", "moves.urllib.response") - - -class Module_six_moves_urllib_robotparser(_LazyModule): - - """Lazy loading of moved objects in six.moves.urllib_robotparser""" - - -_urllib_robotparser_moved_attributes = [ - MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"), -] -for attr in _urllib_robotparser_moved_attributes: - setattr(Module_six_moves_urllib_robotparser, attr.name, attr) -del attr - -Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes - -_importer._add_module(Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"), - "moves.urllib_robotparser", "moves.urllib.robotparser") - - -class Module_six_moves_urllib(types.ModuleType): - - """Create a six.moves.urllib namespace that resembles the Python 3 namespace""" - __path__ = [] # mark as package - parse = _importer._get_module("moves.urllib_parse") - error = _importer._get_module("moves.urllib_error") - request = _importer._get_module("moves.urllib_request") - response = _importer._get_module("moves.urllib_response") - robotparser = _importer._get_module("moves.urllib_robotparser") - - def __dir__(self): - return ['parse', 'error', 'request', 'response', 'robotparser'] - -_importer._add_module(Module_six_moves_urllib(__name__ + ".moves.urllib"), - "moves.urllib") - - -def add_move(move): - """Add an item to six.moves.""" - setattr(_MovedItems, move.name, move) - - -def remove_move(name): - """Remove item from six.moves.""" - try: - delattr(_MovedItems, name) - except AttributeError: - try: - del moves.__dict__[name] - except KeyError: - raise AttributeError("no such move, %r" % (name,)) - - -if PY3: - _meth_func = "__func__" - _meth_self = "__self__" - - _func_closure = "__closure__" - _func_code = "__code__" - _func_defaults = "__defaults__" - _func_globals = "__globals__" -else: - _meth_func = "im_func" - _meth_self = "im_self" - - _func_closure = "func_closure" - _func_code = "func_code" - _func_defaults = "func_defaults" - _func_globals = "func_globals" - - -try: - advance_iterator = next -except NameError: - def advance_iterator(it): - return it.next() -next = advance_iterator - - -try: - callable = callable -except NameError: - def callable(obj): - return any("__call__" in klass.__dict__ for klass in type(obj).__mro__) - - -if PY3: - def get_unbound_function(unbound): - return unbound - - create_bound_method = types.MethodType - - def create_unbound_method(func, cls): - return func - - Iterator = object -else: - def get_unbound_function(unbound): - return unbound.im_func - - def create_bound_method(func, obj): - return types.MethodType(func, obj, obj.__class__) - - def create_unbound_method(func, cls): - return types.MethodType(func, None, cls) - - class Iterator(object): - - def next(self): - return type(self).__next__(self) - - callable = callable -_add_doc(get_unbound_function, - """Get the function out of a possibly unbound function""") - - -get_method_function = operator.attrgetter(_meth_func) -get_method_self = operator.attrgetter(_meth_self) -get_function_closure = operator.attrgetter(_func_closure) -get_function_code = operator.attrgetter(_func_code) -get_function_defaults = operator.attrgetter(_func_defaults) -get_function_globals = operator.attrgetter(_func_globals) - - -if PY3: - def iterkeys(d, **kw): - return iter(d.keys(**kw)) - - def itervalues(d, **kw): - return iter(d.values(**kw)) - - def iteritems(d, **kw): - return iter(d.items(**kw)) - - def iterlists(d, **kw): - return iter(d.lists(**kw)) - - viewkeys = operator.methodcaller("keys") - - viewvalues = operator.methodcaller("values") - - viewitems = operator.methodcaller("items") -else: - def iterkeys(d, **kw): - return d.iterkeys(**kw) - - def itervalues(d, **kw): - return d.itervalues(**kw) - - def iteritems(d, **kw): - return d.iteritems(**kw) - - def iterlists(d, **kw): - return d.iterlists(**kw) - - viewkeys = operator.methodcaller("viewkeys") - - viewvalues = operator.methodcaller("viewvalues") - - viewitems = operator.methodcaller("viewitems") - -_add_doc(iterkeys, "Return an iterator over the keys of a dictionary.") -_add_doc(itervalues, "Return an iterator over the values of a dictionary.") -_add_doc(iteritems, - "Return an iterator over the (key, value) pairs of a dictionary.") -_add_doc(iterlists, - "Return an iterator over the (key, [values]) pairs of a dictionary.") - - -if PY3: - def b(s): - return s.encode("latin-1") - - def u(s): - return s - unichr = chr - import struct - int2byte = struct.Struct(">B").pack - del struct - byte2int = operator.itemgetter(0) - indexbytes = operator.getitem - iterbytes = iter - import io - StringIO = io.StringIO - BytesIO = io.BytesIO - _assertCountEqual = "assertCountEqual" - if sys.version_info[1] <= 1: - _assertRaisesRegex = "assertRaisesRegexp" - _assertRegex = "assertRegexpMatches" - else: - _assertRaisesRegex = "assertRaisesRegex" - _assertRegex = "assertRegex" -else: - def b(s): - return s - # Workaround for standalone backslash - - def u(s): - return unicode(s.replace(r'\\', r'\\\\'), "unicode_escape") - unichr = unichr - int2byte = chr - - def byte2int(bs): - return ord(bs[0]) - - def indexbytes(buf, i): - return ord(buf[i]) - iterbytes = functools.partial(itertools.imap, ord) - import StringIO - StringIO = BytesIO = StringIO.StringIO - _assertCountEqual = "assertItemsEqual" - _assertRaisesRegex = "assertRaisesRegexp" - _assertRegex = "assertRegexpMatches" -_add_doc(b, """Byte literal""") -_add_doc(u, """Text literal""") - - -def assertCountEqual(self, *args, **kwargs): - return getattr(self, _assertCountEqual)(*args, **kwargs) - - -def assertRaisesRegex(self, *args, **kwargs): - return getattr(self, _assertRaisesRegex)(*args, **kwargs) - - -def assertRegex(self, *args, **kwargs): - return getattr(self, _assertRegex)(*args, **kwargs) - - -if PY3: - exec_ = getattr(moves.builtins, "exec") - - def reraise(tp, value, tb=None): - if value is None: - value = tp() - if value.__traceback__ is not tb: - raise value.with_traceback(tb) - raise value - -else: - def exec_(_code_, _globs_=None, _locs_=None): - """Execute code in a namespace.""" - if _globs_ is None: - frame = sys._getframe(1) - _globs_ = frame.f_globals - if _locs_ is None: - _locs_ = frame.f_locals - del frame - elif _locs_ is None: - _locs_ = _globs_ - exec("""exec _code_ in _globs_, _locs_""") - - exec_("""def reraise(tp, value, tb=None): - raise tp, value, tb -""") - - -if sys.version_info[:2] == (3, 2): - exec_("""def raise_from(value, from_value): - if from_value is None: - raise value - raise value from from_value -""") -elif sys.version_info[:2] > (3, 2): - exec_("""def raise_from(value, from_value): - raise value from from_value -""") -else: - def raise_from(value, from_value): - raise value - - -print_ = getattr(moves.builtins, "print", None) -if print_ is None: - def print_(*args, **kwargs): - """The new-style print function for Python 2.4 and 2.5.""" - fp = kwargs.pop("file", sys.stdout) - if fp is None: - return - - def write(data): - if not isinstance(data, basestring): - data = str(data) - # If the file has an encoding, encode unicode with it. - if (isinstance(fp, file) and - isinstance(data, unicode) and - fp.encoding is not None): - errors = getattr(fp, "errors", None) - if errors is None: - errors = "strict" - data = data.encode(fp.encoding, errors) - fp.write(data) - want_unicode = False - sep = kwargs.pop("sep", None) - if sep is not None: - if isinstance(sep, unicode): - want_unicode = True - elif not isinstance(sep, str): - raise TypeError("sep must be None or a string") - end = kwargs.pop("end", None) - if end is not None: - if isinstance(end, unicode): - want_unicode = True - elif not isinstance(end, str): - raise TypeError("end must be None or a string") - if kwargs: - raise TypeError("invalid keyword arguments to print()") - if not want_unicode: - for arg in args: - if isinstance(arg, unicode): - want_unicode = True - break - if want_unicode: - newline = unicode("\n") - space = unicode(" ") - else: - newline = "\n" - space = " " - if sep is None: - sep = space - if end is None: - end = newline - for i, arg in enumerate(args): - if i: - write(sep) - write(arg) - write(end) -if sys.version_info[:2] < (3, 3): - _print = print_ - - def print_(*args, **kwargs): - fp = kwargs.get("file", sys.stdout) - flush = kwargs.pop("flush", False) - _print(*args, **kwargs) - if flush and fp is not None: - fp.flush() - -_add_doc(reraise, """Reraise an exception.""") - -if sys.version_info[0:2] < (3, 4): - def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS, - updated=functools.WRAPPER_UPDATES): - def wrapper(f): - f = functools.wraps(wrapped, assigned, updated)(f) - f.__wrapped__ = wrapped - return f - return wrapper -else: - wraps = functools.wraps - - -def with_metaclass(meta, *bases): - """Create a base class with a metaclass.""" - # This requires a bit of explanation: the basic idea is to make a dummy - # metaclass for one level of class instantiation that replaces itself with - # the actual metaclass. - class metaclass(meta): - - def __new__(cls, name, this_bases, d): - return meta(name, bases, d) - return type.__new__(metaclass, 'temporary_class', (), {}) - - -def add_metaclass(metaclass): - """Class decorator for creating a class with a metaclass.""" - def wrapper(cls): - orig_vars = cls.__dict__.copy() - slots = orig_vars.get('__slots__') - if slots is not None: - if isinstance(slots, str): - slots = [slots] - for slots_var in slots: - orig_vars.pop(slots_var) - orig_vars.pop('__dict__', None) - orig_vars.pop('__weakref__', None) - return metaclass(cls.__name__, cls.__bases__, orig_vars) - return wrapper - - -def python_2_unicode_compatible(klass): - """ - A decorator that defines __unicode__ and __str__ methods under Python 2. - Under Python 3 it does nothing. - - To support Python 2 and 3 with a single code base, define a __str__ method - returning text and apply this decorator to the class. - """ - if PY2: - if '__str__' not in klass.__dict__: - raise ValueError("@python_2_unicode_compatible cannot be applied " - "to %s because it doesn't define __str__()." % - klass.__name__) - klass.__unicode__ = klass.__str__ - klass.__str__ = lambda self: self.__unicode__().encode('utf-8') - return klass - - -# Complete the moves implementation. -# This code is at the end of this module to speed up module loading. -# Turn this module into a package. -__path__ = [] # required for PEP 302 and PEP 451 -__package__ = __name__ # see PEP 366 @ReservedAssignment -if globals().get("__spec__") is not None: - __spec__.submodule_search_locations = [] # PEP 451 @UndefinedVariable -# Remove other six meta path importers, since they cause problems. This can -# happen if six is removed from sys.modules and then reloaded. (Setuptools does -# this for some reason.) -if sys.meta_path: - for i, importer in enumerate(sys.meta_path): - # Here's some real nastiness: Another "instance" of the six module might - # be floating around. Therefore, we can't use isinstance() to check for - # the six meta path importer, since the other six instance will have - # inserted an importer with different class. - if (type(importer).__name__ == "_SixMetaPathImporter" and - importer.name == __name__): - del sys.meta_path[i] - break - del i, importer -# Finally, add the importer to the meta path import hook. -sys.meta_path.append(_importer) diff --git a/venv/lib/python3.8/site-packages/setuptools/archive_util.py b/venv/lib/python3.8/site-packages/setuptools/archive_util.py deleted file mode 100644 index 8143604..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/archive_util.py +++ /dev/null @@ -1,173 +0,0 @@ -"""Utilities for extracting common archive formats""" - -import zipfile -import tarfile -import os -import shutil -import posixpath -import contextlib -from distutils.errors import DistutilsError - -from pkg_resources import ensure_directory - -__all__ = [ - "unpack_archive", "unpack_zipfile", "unpack_tarfile", "default_filter", - "UnrecognizedFormat", "extraction_drivers", "unpack_directory", -] - - -class UnrecognizedFormat(DistutilsError): - """Couldn't recognize the archive type""" - - -def default_filter(src, dst): - """The default progress/filter callback; returns True for all files""" - return dst - - -def unpack_archive(filename, extract_dir, progress_filter=default_filter, - drivers=None): - """Unpack `filename` to `extract_dir`, or raise ``UnrecognizedFormat`` - - `progress_filter` is a function taking two arguments: a source path - internal to the archive ('/'-separated), and a filesystem path where it - will be extracted. The callback must return the desired extract path - (which may be the same as the one passed in), or else ``None`` to skip - that file or directory. The callback can thus be used to report on the - progress of the extraction, as well as to filter the items extracted or - alter their extraction paths. - - `drivers`, if supplied, must be a non-empty sequence of functions with the - same signature as this function (minus the `drivers` argument), that raise - ``UnrecognizedFormat`` if they do not support extracting the designated - archive type. The `drivers` are tried in sequence until one is found that - does not raise an error, or until all are exhausted (in which case - ``UnrecognizedFormat`` is raised). If you do not supply a sequence of - drivers, the module's ``extraction_drivers`` constant will be used, which - means that ``unpack_zipfile`` and ``unpack_tarfile`` will be tried, in that - order. - """ - for driver in drivers or extraction_drivers: - try: - driver(filename, extract_dir, progress_filter) - except UnrecognizedFormat: - continue - else: - return - else: - raise UnrecognizedFormat( - "Not a recognized archive type: %s" % filename - ) - - -def unpack_directory(filename, extract_dir, progress_filter=default_filter): - """"Unpack" a directory, using the same interface as for archives - - Raises ``UnrecognizedFormat`` if `filename` is not a directory - """ - if not os.path.isdir(filename): - raise UnrecognizedFormat("%s is not a directory" % filename) - - paths = { - filename: ('', extract_dir), - } - for base, dirs, files in os.walk(filename): - src, dst = paths[base] - for d in dirs: - paths[os.path.join(base, d)] = src + d + '/', os.path.join(dst, d) - for f in files: - target = os.path.join(dst, f) - target = progress_filter(src + f, target) - if not target: - # skip non-files - continue - ensure_directory(target) - f = os.path.join(base, f) - shutil.copyfile(f, target) - shutil.copystat(f, target) - - -def unpack_zipfile(filename, extract_dir, progress_filter=default_filter): - """Unpack zip `filename` to `extract_dir` - - Raises ``UnrecognizedFormat`` if `filename` is not a zipfile (as determined - by ``zipfile.is_zipfile()``). See ``unpack_archive()`` for an explanation - of the `progress_filter` argument. - """ - - if not zipfile.is_zipfile(filename): - raise UnrecognizedFormat("%s is not a zip file" % (filename,)) - - with zipfile.ZipFile(filename) as z: - for info in z.infolist(): - name = info.filename - - # don't extract absolute paths or ones with .. in them - if name.startswith('/') or '..' in name.split('/'): - continue - - target = os.path.join(extract_dir, *name.split('/')) - target = progress_filter(name, target) - if not target: - continue - if name.endswith('/'): - # directory - ensure_directory(target) - else: - # file - ensure_directory(target) - data = z.read(info.filename) - with open(target, 'wb') as f: - f.write(data) - unix_attributes = info.external_attr >> 16 - if unix_attributes: - os.chmod(target, unix_attributes) - - -def unpack_tarfile(filename, extract_dir, progress_filter=default_filter): - """Unpack tar/tar.gz/tar.bz2 `filename` to `extract_dir` - - Raises ``UnrecognizedFormat`` if `filename` is not a tarfile (as determined - by ``tarfile.open()``). See ``unpack_archive()`` for an explanation - of the `progress_filter` argument. - """ - try: - tarobj = tarfile.open(filename) - except tarfile.TarError: - raise UnrecognizedFormat( - "%s is not a compressed or uncompressed tar file" % (filename,) - ) - with contextlib.closing(tarobj): - # don't do any chowning! - tarobj.chown = lambda *args: None - for member in tarobj: - name = member.name - # don't extract absolute paths or ones with .. in them - if not name.startswith('/') and '..' not in name.split('/'): - prelim_dst = os.path.join(extract_dir, *name.split('/')) - - # resolve any links and to extract the link targets as normal - # files - while member is not None and (member.islnk() or member.issym()): - linkpath = member.linkname - if member.issym(): - base = posixpath.dirname(member.name) - linkpath = posixpath.join(base, linkpath) - linkpath = posixpath.normpath(linkpath) - member = tarobj._getmember(linkpath) - - if member is not None and (member.isfile() or member.isdir()): - final_dst = progress_filter(name, prelim_dst) - if final_dst: - if final_dst.endswith(os.sep): - final_dst = final_dst[:-1] - try: - # XXX Ugh - tarobj._extract_member(member, final_dst) - except tarfile.ExtractError: - # chown/chmod/mkfifo/mknode/makedev failed - pass - return True - - -extraction_drivers = unpack_directory, unpack_zipfile, unpack_tarfile diff --git a/venv/lib/python3.8/site-packages/setuptools/build_meta.py b/venv/lib/python3.8/site-packages/setuptools/build_meta.py deleted file mode 100644 index 10c4b52..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/build_meta.py +++ /dev/null @@ -1,257 +0,0 @@ -"""A PEP 517 interface to setuptools - -Previously, when a user or a command line tool (let's call it a "frontend") -needed to make a request of setuptools to take a certain action, for -example, generating a list of installation requirements, the frontend would -would call "setup.py egg_info" or "setup.py bdist_wheel" on the command line. - -PEP 517 defines a different method of interfacing with setuptools. Rather -than calling "setup.py" directly, the frontend should: - - 1. Set the current directory to the directory with a setup.py file - 2. Import this module into a safe python interpreter (one in which - setuptools can potentially set global variables or crash hard). - 3. Call one of the functions defined in PEP 517. - -What each function does is defined in PEP 517. However, here is a "casual" -definition of the functions (this definition should not be relied on for -bug reports or API stability): - - - `build_wheel`: build a wheel in the folder and return the basename - - `get_requires_for_build_wheel`: get the `setup_requires` to build - - `prepare_metadata_for_build_wheel`: get the `install_requires` - - `build_sdist`: build an sdist in the folder and return the basename - - `get_requires_for_build_sdist`: get the `setup_requires` to build - -Again, this is not a formal definition! Just a "taste" of the module. -""" - -import io -import os -import sys -import tokenize -import shutil -import contextlib - -import setuptools -import distutils -from setuptools.py31compat import TemporaryDirectory - -from pkg_resources import parse_requirements -from pkg_resources.py31compat import makedirs - -__all__ = ['get_requires_for_build_sdist', - 'get_requires_for_build_wheel', - 'prepare_metadata_for_build_wheel', - 'build_wheel', - 'build_sdist', - '__legacy__', - 'SetupRequirementsError'] - -class SetupRequirementsError(BaseException): - def __init__(self, specifiers): - self.specifiers = specifiers - - -class Distribution(setuptools.dist.Distribution): - def fetch_build_eggs(self, specifiers): - specifier_list = list(map(str, parse_requirements(specifiers))) - - raise SetupRequirementsError(specifier_list) - - @classmethod - @contextlib.contextmanager - def patch(cls): - """ - Replace - distutils.dist.Distribution with this class - for the duration of this context. - """ - orig = distutils.core.Distribution - distutils.core.Distribution = cls - try: - yield - finally: - distutils.core.Distribution = orig - - -def _to_str(s): - """ - Convert a filename to a string (on Python 2, explicitly - a byte string, not Unicode) as distutils checks for the - exact type str. - """ - if sys.version_info[0] == 2 and not isinstance(s, str): - # Assume it's Unicode, as that's what the PEP says - # should be provided. - return s.encode(sys.getfilesystemencoding()) - return s - - -def _get_immediate_subdirectories(a_dir): - return [name for name in os.listdir(a_dir) - if os.path.isdir(os.path.join(a_dir, name))] - - -def _file_with_extension(directory, extension): - matching = ( - f for f in os.listdir(directory) - if f.endswith(extension) - ) - file, = matching - return file - - -def _open_setup_script(setup_script): - if not os.path.exists(setup_script): - # Supply a default setup.py - return io.StringIO(u"from setuptools import setup; setup()") - - return getattr(tokenize, 'open', open)(setup_script) - - -class _BuildMetaBackend(object): - - def _fix_config(self, config_settings): - config_settings = config_settings or {} - config_settings.setdefault('--global-option', []) - return config_settings - - def _get_build_requires(self, config_settings, requirements): - config_settings = self._fix_config(config_settings) - - sys.argv = sys.argv[:1] + ['egg_info'] + \ - config_settings["--global-option"] - try: - with Distribution.patch(): - self.run_setup() - except SetupRequirementsError as e: - requirements += e.specifiers - - return requirements - - def run_setup(self, setup_script='setup.py'): - # Note that we can reuse our build directory between calls - # Correctness comes first, then optimization later - __file__ = setup_script - __name__ = '__main__' - - with _open_setup_script(__file__) as f: - code = f.read().replace(r'\r\n', r'\n') - - exec(compile(code, __file__, 'exec'), locals()) - - def get_requires_for_build_wheel(self, config_settings=None): - config_settings = self._fix_config(config_settings) - return self._get_build_requires(config_settings, requirements=['wheel']) - - def get_requires_for_build_sdist(self, config_settings=None): - config_settings = self._fix_config(config_settings) - return self._get_build_requires(config_settings, requirements=[]) - - def prepare_metadata_for_build_wheel(self, metadata_directory, - config_settings=None): - sys.argv = sys.argv[:1] + ['dist_info', '--egg-base', - _to_str(metadata_directory)] - self.run_setup() - - dist_info_directory = metadata_directory - while True: - dist_infos = [f for f in os.listdir(dist_info_directory) - if f.endswith('.dist-info')] - - if (len(dist_infos) == 0 and - len(_get_immediate_subdirectories(dist_info_directory)) == 1): - - dist_info_directory = os.path.join( - dist_info_directory, os.listdir(dist_info_directory)[0]) - continue - - assert len(dist_infos) == 1 - break - - # PEP 517 requires that the .dist-info directory be placed in the - # metadata_directory. To comply, we MUST copy the directory to the root - if dist_info_directory != metadata_directory: - shutil.move( - os.path.join(dist_info_directory, dist_infos[0]), - metadata_directory) - shutil.rmtree(dist_info_directory, ignore_errors=True) - - return dist_infos[0] - - def _build_with_temp_dir(self, setup_command, result_extension, - result_directory, config_settings): - config_settings = self._fix_config(config_settings) - result_directory = os.path.abspath(result_directory) - - # Build in a temporary directory, then copy to the target. - makedirs(result_directory, exist_ok=True) - with TemporaryDirectory(dir=result_directory) as tmp_dist_dir: - sys.argv = (sys.argv[:1] + setup_command + - ['--dist-dir', tmp_dist_dir] + - config_settings["--global-option"]) - self.run_setup() - - result_basename = _file_with_extension(tmp_dist_dir, result_extension) - result_path = os.path.join(result_directory, result_basename) - if os.path.exists(result_path): - # os.rename will fail overwriting on non-Unix. - os.remove(result_path) - os.rename(os.path.join(tmp_dist_dir, result_basename), result_path) - - return result_basename - - - def build_wheel(self, wheel_directory, config_settings=None, - metadata_directory=None): - return self._build_with_temp_dir(['bdist_wheel'], '.whl', - wheel_directory, config_settings) - - def build_sdist(self, sdist_directory, config_settings=None): - return self._build_with_temp_dir(['sdist', '--formats', 'gztar'], - '.tar.gz', sdist_directory, - config_settings) - - -class _BuildMetaLegacyBackend(_BuildMetaBackend): - """Compatibility backend for setuptools - - This is a version of setuptools.build_meta that endeavors to maintain backwards - compatibility with pre-PEP 517 modes of invocation. It exists as a temporary - bridge between the old packaging mechanism and the new packaging mechanism, - and will eventually be removed. - """ - def run_setup(self, setup_script='setup.py'): - # In order to maintain compatibility with scripts assuming that - # the setup.py script is in a directory on the PYTHONPATH, inject - # '' into sys.path. (pypa/setuptools#1642) - sys_path = list(sys.path) # Save the original path - - script_dir = os.path.dirname(os.path.abspath(setup_script)) - if script_dir not in sys.path: - sys.path.insert(0, script_dir) - - try: - super(_BuildMetaLegacyBackend, - self).run_setup(setup_script=setup_script) - finally: - # While PEP 517 frontends should be calling each hook in a fresh - # subprocess according to the standard (and thus it should not be - # strictly necessary to restore the old sys.path), we'll restore - # the original path so that the path manipulation does not persist - # within the hook after run_setup is called. - sys.path[:] = sys_path - -# The primary backend -_BACKEND = _BuildMetaBackend() - -get_requires_for_build_wheel = _BACKEND.get_requires_for_build_wheel -get_requires_for_build_sdist = _BACKEND.get_requires_for_build_sdist -prepare_metadata_for_build_wheel = _BACKEND.prepare_metadata_for_build_wheel -build_wheel = _BACKEND.build_wheel -build_sdist = _BACKEND.build_sdist - - -# The legacy backend -__legacy__ = _BuildMetaLegacyBackend() diff --git a/venv/lib/python3.8/site-packages/setuptools/cli-32.exe b/venv/lib/python3.8/site-packages/setuptools/cli-32.exe deleted file mode 100644 index b1487b7819e7286577a043c7726fbe0ca1543083..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 65536 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 diff --git a/venv/lib/python3.8/site-packages/setuptools/cli-64.exe b/venv/lib/python3.8/site-packages/setuptools/cli-64.exe deleted file mode 100644 index 675e6bf3743f3d3011c238657e7128ee9960ef7f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 74752 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 diff --git a/venv/lib/python3.8/site-packages/setuptools/cli.exe b/venv/lib/python3.8/site-packages/setuptools/cli.exe deleted file mode 100644 index b1487b7819e7286577a043c7726fbe0ca1543083..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 65536 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 diff --git a/venv/lib/python3.8/site-packages/setuptools/command/__init__.py b/venv/lib/python3.8/site-packages/setuptools/command/__init__.py deleted file mode 100644 index 743f558..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/command/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -__all__ = [ - 'alias', 'bdist_egg', 'bdist_rpm', 'build_ext', 'build_py', 'develop', - 'easy_install', 'egg_info', 'install', 'install_lib', 'rotate', 'saveopts', - 'sdist', 'setopt', 'test', 'install_egg_info', 'install_scripts', - 'bdist_wininst', 'upload_docs', 'build_clib', 'dist_info', -] - -from distutils.command.bdist import bdist -import sys - -from setuptools.command import install_scripts - -if 'egg' not in bdist.format_commands: - bdist.format_command['egg'] = ('bdist_egg', "Python .egg file") - bdist.format_commands.append('egg') - -del bdist, sys diff --git a/venv/lib/python3.8/site-packages/setuptools/command/alias.py b/venv/lib/python3.8/site-packages/setuptools/command/alias.py deleted file mode 100644 index 4532b1c..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/command/alias.py +++ /dev/null @@ -1,80 +0,0 @@ -from distutils.errors import DistutilsOptionError - -from setuptools.extern.six.moves import map - -from setuptools.command.setopt import edit_config, option_base, config_file - - -def shquote(arg): - """Quote an argument for later parsing by shlex.split()""" - for c in '"', "'", "\\", "#": - if c in arg: - return repr(arg) - if arg.split() != [arg]: - return repr(arg) - return arg - - -class alias(option_base): - """Define a shortcut that invokes one or more commands""" - - description = "define a shortcut to invoke one or more commands" - command_consumes_arguments = True - - user_options = [ - ('remove', 'r', 'remove (unset) the alias'), - ] + option_base.user_options - - boolean_options = option_base.boolean_options + ['remove'] - - def initialize_options(self): - option_base.initialize_options(self) - self.args = None - self.remove = None - - def finalize_options(self): - option_base.finalize_options(self) - if self.remove and len(self.args) != 1: - raise DistutilsOptionError( - "Must specify exactly one argument (the alias name) when " - "using --remove" - ) - - def run(self): - aliases = self.distribution.get_option_dict('aliases') - - if not self.args: - print("Command Aliases") - print("---------------") - for alias in aliases: - print("setup.py alias", format_alias(alias, aliases)) - return - - elif len(self.args) == 1: - alias, = self.args - if self.remove: - command = None - elif alias in aliases: - print("setup.py alias", format_alias(alias, aliases)) - return - else: - print("No alias definition found for %r" % alias) - return - else: - alias = self.args[0] - command = ' '.join(map(shquote, self.args[1:])) - - edit_config(self.filename, {'aliases': {alias: command}}, self.dry_run) - - -def format_alias(name, aliases): - source, command = aliases[name] - if source == config_file('global'): - source = '--global-config ' - elif source == config_file('user'): - source = '--user-config ' - elif source == config_file('local'): - source = '' - else: - source = '--filename=%r' % source - return source + name + ' ' + command diff --git a/venv/lib/python3.8/site-packages/setuptools/command/bdist_egg.py b/venv/lib/python3.8/site-packages/setuptools/command/bdist_egg.py deleted file mode 100644 index 98470f1..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/command/bdist_egg.py +++ /dev/null @@ -1,502 +0,0 @@ -"""setuptools.command.bdist_egg - -Build .egg distributions""" - -from distutils.errors import DistutilsSetupError -from distutils.dir_util import remove_tree, mkpath -from distutils import log -from types import CodeType -import sys -import os -import re -import textwrap -import marshal - -from setuptools.extern import six - -from pkg_resources import get_build_platform, Distribution, ensure_directory -from pkg_resources import EntryPoint -from setuptools.extension import Library -from setuptools import Command - -try: - # Python 2.7 or >=3.2 - from sysconfig import get_path, get_python_version - - def _get_purelib(): - return get_path("purelib") -except ImportError: - from distutils.sysconfig import get_python_lib, get_python_version - - def _get_purelib(): - return get_python_lib(False) - - -def strip_module(filename): - if '.' in filename: - filename = os.path.splitext(filename)[0] - if filename.endswith('module'): - filename = filename[:-6] - return filename - - -def sorted_walk(dir): - """Do os.walk in a reproducible way, - independent of indeterministic filesystem readdir order - """ - for base, dirs, files in os.walk(dir): - dirs.sort() - files.sort() - yield base, dirs, files - - -def write_stub(resource, pyfile): - _stub_template = textwrap.dedent(""" - def __bootstrap__(): - global __bootstrap__, __loader__, __file__ - import sys, pkg_resources, imp - __file__ = pkg_resources.resource_filename(__name__, %r) - __loader__ = None; del __bootstrap__, __loader__ - imp.load_dynamic(__name__,__file__) - __bootstrap__() - """).lstrip() - with open(pyfile, 'w') as f: - f.write(_stub_template % resource) - - -class bdist_egg(Command): - description = "create an \"egg\" distribution" - - user_options = [ - ('bdist-dir=', 'b', - "temporary directory for creating the distribution"), - ('plat-name=', 'p', "platform name to embed in generated filenames " - "(default: %s)" % get_build_platform()), - ('exclude-source-files', None, - "remove all .py files from the generated egg"), - ('keep-temp', 'k', - "keep the pseudo-installation tree around after " + - "creating the distribution archive"), - ('dist-dir=', 'd', - "directory to put final built distributions in"), - ('skip-build', None, - "skip rebuilding everything (for testing/debugging)"), - ] - - boolean_options = [ - 'keep-temp', 'skip-build', 'exclude-source-files' - ] - - def initialize_options(self): - self.bdist_dir = None - self.plat_name = None - self.keep_temp = 0 - self.dist_dir = None - self.skip_build = 0 - self.egg_output = None - self.exclude_source_files = None - - def finalize_options(self): - ei_cmd = self.ei_cmd = self.get_finalized_command("egg_info") - self.egg_info = ei_cmd.egg_info - - if self.bdist_dir is None: - bdist_base = self.get_finalized_command('bdist').bdist_base - self.bdist_dir = os.path.join(bdist_base, 'egg') - - if self.plat_name is None: - self.plat_name = get_build_platform() - - self.set_undefined_options('bdist', ('dist_dir', 'dist_dir')) - - if self.egg_output is None: - - # Compute filename of the output egg - basename = Distribution( - None, None, ei_cmd.egg_name, ei_cmd.egg_version, - get_python_version(), - self.distribution.has_ext_modules() and self.plat_name - ).egg_name() - - self.egg_output = os.path.join(self.dist_dir, basename + '.egg') - - def do_install_data(self): - # Hack for packages that install data to install's --install-lib - self.get_finalized_command('install').install_lib = self.bdist_dir - - site_packages = os.path.normcase(os.path.realpath(_get_purelib())) - old, self.distribution.data_files = self.distribution.data_files, [] - - for item in old: - if isinstance(item, tuple) and len(item) == 2: - if os.path.isabs(item[0]): - realpath = os.path.realpath(item[0]) - normalized = os.path.normcase(realpath) - if normalized == site_packages or normalized.startswith( - site_packages + os.sep - ): - item = realpath[len(site_packages) + 1:], item[1] - # XXX else: raise ??? - self.distribution.data_files.append(item) - - try: - log.info("installing package data to %s", self.bdist_dir) - self.call_command('install_data', force=0, root=None) - finally: - self.distribution.data_files = old - - def get_outputs(self): - return [self.egg_output] - - def call_command(self, cmdname, **kw): - """Invoke reinitialized command `cmdname` with keyword args""" - for dirname in INSTALL_DIRECTORY_ATTRS: - kw.setdefault(dirname, self.bdist_dir) - kw.setdefault('skip_build', self.skip_build) - kw.setdefault('dry_run', self.dry_run) - cmd = self.reinitialize_command(cmdname, **kw) - self.run_command(cmdname) - return cmd - - def run(self): - # Generate metadata first - self.run_command("egg_info") - # We run install_lib before install_data, because some data hacks - # pull their data path from the install_lib command. - log.info("installing library code to %s", self.bdist_dir) - instcmd = self.get_finalized_command('install') - old_root = instcmd.root - instcmd.root = None - if self.distribution.has_c_libraries() and not self.skip_build: - self.run_command('build_clib') - cmd = self.call_command('install_lib', warn_dir=0) - instcmd.root = old_root - - all_outputs, ext_outputs = self.get_ext_outputs() - self.stubs = [] - to_compile = [] - for (p, ext_name) in enumerate(ext_outputs): - filename, ext = os.path.splitext(ext_name) - pyfile = os.path.join(self.bdist_dir, strip_module(filename) + - '.py') - self.stubs.append(pyfile) - log.info("creating stub loader for %s", ext_name) - if not self.dry_run: - write_stub(os.path.basename(ext_name), pyfile) - to_compile.append(pyfile) - ext_outputs[p] = ext_name.replace(os.sep, '/') - - if to_compile: - cmd.byte_compile(to_compile) - if self.distribution.data_files: - self.do_install_data() - - # Make the EGG-INFO directory - archive_root = self.bdist_dir - egg_info = os.path.join(archive_root, 'EGG-INFO') - self.mkpath(egg_info) - if self.distribution.scripts: - script_dir = os.path.join(egg_info, 'scripts') - log.info("installing scripts to %s", script_dir) - self.call_command('install_scripts', install_dir=script_dir, - no_ep=1) - - self.copy_metadata_to(egg_info) - native_libs = os.path.join(egg_info, "native_libs.txt") - if all_outputs: - log.info("writing %s", native_libs) - if not self.dry_run: - ensure_directory(native_libs) - libs_file = open(native_libs, 'wt') - libs_file.write('\n'.join(all_outputs)) - libs_file.write('\n') - libs_file.close() - elif os.path.isfile(native_libs): - log.info("removing %s", native_libs) - if not self.dry_run: - os.unlink(native_libs) - - write_safety_flag( - os.path.join(archive_root, 'EGG-INFO'), self.zip_safe() - ) - - if os.path.exists(os.path.join(self.egg_info, 'depends.txt')): - log.warn( - "WARNING: 'depends.txt' will not be used by setuptools 0.6!\n" - "Use the install_requires/extras_require setup() args instead." - ) - - if self.exclude_source_files: - self.zap_pyfiles() - - # Make the archive - make_zipfile(self.egg_output, archive_root, verbose=self.verbose, - dry_run=self.dry_run, mode=self.gen_header()) - if not self.keep_temp: - remove_tree(self.bdist_dir, dry_run=self.dry_run) - - # Add to 'Distribution.dist_files' so that the "upload" command works - getattr(self.distribution, 'dist_files', []).append( - ('bdist_egg', get_python_version(), self.egg_output)) - - def zap_pyfiles(self): - log.info("Removing .py files from temporary directory") - for base, dirs, files in walk_egg(self.bdist_dir): - for name in files: - path = os.path.join(base, name) - - if name.endswith('.py'): - log.debug("Deleting %s", path) - os.unlink(path) - - if base.endswith('__pycache__'): - path_old = path - - pattern = r'(?P<name>.+)\.(?P<magic>[^.]+)\.pyc' - m = re.match(pattern, name) - path_new = os.path.join( - base, os.pardir, m.group('name') + '.pyc') - log.info( - "Renaming file from [%s] to [%s]" - % (path_old, path_new)) - try: - os.remove(path_new) - except OSError: - pass - os.rename(path_old, path_new) - - def zip_safe(self): - safe = getattr(self.distribution, 'zip_safe', None) - if safe is not None: - return safe - log.warn("zip_safe flag not set; analyzing archive contents...") - return analyze_egg(self.bdist_dir, self.stubs) - - def gen_header(self): - epm = EntryPoint.parse_map(self.distribution.entry_points or '') - ep = epm.get('setuptools.installation', {}).get('eggsecutable') - if ep is None: - return 'w' # not an eggsecutable, do it the usual way. - - if not ep.attrs or ep.extras: - raise DistutilsSetupError( - "eggsecutable entry point (%r) cannot have 'extras' " - "or refer to a module" % (ep,) - ) - - pyver = '{}.{}'.format(*sys.version_info) - pkg = ep.module_name - full = '.'.join(ep.attrs) - base = ep.attrs[0] - basename = os.path.basename(self.egg_output) - - header = ( - "#!/bin/sh\n" - 'if [ `basename $0` = "%(basename)s" ]\n' - 'then exec python%(pyver)s -c "' - "import sys, os; sys.path.insert(0, os.path.abspath('$0')); " - "from %(pkg)s import %(base)s; sys.exit(%(full)s())" - '" "$@"\n' - 'else\n' - ' echo $0 is not the correct name for this egg file.\n' - ' echo Please rename it back to %(basename)s and try again.\n' - ' exec false\n' - 'fi\n' - ) % locals() - - if not self.dry_run: - mkpath(os.path.dirname(self.egg_output), dry_run=self.dry_run) - f = open(self.egg_output, 'w') - f.write(header) - f.close() - return 'a' - - def copy_metadata_to(self, target_dir): - "Copy metadata (egg info) to the target_dir" - # normalize the path (so that a forward-slash in egg_info will - # match using startswith below) - norm_egg_info = os.path.normpath(self.egg_info) - prefix = os.path.join(norm_egg_info, '') - for path in self.ei_cmd.filelist.files: - if path.startswith(prefix): - target = os.path.join(target_dir, path[len(prefix):]) - ensure_directory(target) - self.copy_file(path, target) - - def get_ext_outputs(self): - """Get a list of relative paths to C extensions in the output distro""" - - all_outputs = [] - ext_outputs = [] - - paths = {self.bdist_dir: ''} - for base, dirs, files in sorted_walk(self.bdist_dir): - for filename in files: - if os.path.splitext(filename)[1].lower() in NATIVE_EXTENSIONS: - all_outputs.append(paths[base] + filename) - for filename in dirs: - paths[os.path.join(base, filename)] = (paths[base] + - filename + '/') - - if self.distribution.has_ext_modules(): - build_cmd = self.get_finalized_command('build_ext') - for ext in build_cmd.extensions: - if isinstance(ext, Library): - continue - fullname = build_cmd.get_ext_fullname(ext.name) - filename = build_cmd.get_ext_filename(fullname) - if not os.path.basename(filename).startswith('dl-'): - if os.path.exists(os.path.join(self.bdist_dir, filename)): - ext_outputs.append(filename) - - return all_outputs, ext_outputs - - -NATIVE_EXTENSIONS = dict.fromkeys('.dll .so .dylib .pyd'.split()) - - -def walk_egg(egg_dir): - """Walk an unpacked egg's contents, skipping the metadata directory""" - walker = sorted_walk(egg_dir) - base, dirs, files = next(walker) - if 'EGG-INFO' in dirs: - dirs.remove('EGG-INFO') - yield base, dirs, files - for bdf in walker: - yield bdf - - -def analyze_egg(egg_dir, stubs): - # check for existing flag in EGG-INFO - for flag, fn in safety_flags.items(): - if os.path.exists(os.path.join(egg_dir, 'EGG-INFO', fn)): - return flag - if not can_scan(): - return False - safe = True - for base, dirs, files in walk_egg(egg_dir): - for name in files: - if name.endswith('.py') or name.endswith('.pyw'): - continue - elif name.endswith('.pyc') or name.endswith('.pyo'): - # always scan, even if we already know we're not safe - safe = scan_module(egg_dir, base, name, stubs) and safe - return safe - - -def write_safety_flag(egg_dir, safe): - # Write or remove zip safety flag file(s) - for flag, fn in safety_flags.items(): - fn = os.path.join(egg_dir, fn) - if os.path.exists(fn): - if safe is None or bool(safe) != flag: - os.unlink(fn) - elif safe is not None and bool(safe) == flag: - f = open(fn, 'wt') - f.write('\n') - f.close() - - -safety_flags = { - True: 'zip-safe', - False: 'not-zip-safe', -} - - -def scan_module(egg_dir, base, name, stubs): - """Check whether module possibly uses unsafe-for-zipfile stuff""" - - filename = os.path.join(base, name) - if filename[:-1] in stubs: - return True # Extension module - pkg = base[len(egg_dir) + 1:].replace(os.sep, '.') - module = pkg + (pkg and '.' or '') + os.path.splitext(name)[0] - if six.PY2: - skip = 8 # skip magic & date - elif sys.version_info < (3, 7): - skip = 12 # skip magic & date & file size - else: - skip = 16 # skip magic & reserved? & date & file size - f = open(filename, 'rb') - f.read(skip) - code = marshal.load(f) - f.close() - safe = True - symbols = dict.fromkeys(iter_symbols(code)) - for bad in ['__file__', '__path__']: - if bad in symbols: - log.warn("%s: module references %s", module, bad) - safe = False - if 'inspect' in symbols: - for bad in [ - 'getsource', 'getabsfile', 'getsourcefile', 'getfile' - 'getsourcelines', 'findsource', 'getcomments', 'getframeinfo', - 'getinnerframes', 'getouterframes', 'stack', 'trace' - ]: - if bad in symbols: - log.warn("%s: module MAY be using inspect.%s", module, bad) - safe = False - return safe - - -def iter_symbols(code): - """Yield names and strings used by `code` and its nested code objects""" - for name in code.co_names: - yield name - for const in code.co_consts: - if isinstance(const, six.string_types): - yield const - elif isinstance(const, CodeType): - for name in iter_symbols(const): - yield name - - -def can_scan(): - if not sys.platform.startswith('java') and sys.platform != 'cli': - # CPython, PyPy, etc. - return True - log.warn("Unable to analyze compiled code on this platform.") - log.warn("Please ask the author to include a 'zip_safe'" - " setting (either True or False) in the package's setup.py") - - -# Attribute names of options for commands that might need to be convinced to -# install to the egg build directory - -INSTALL_DIRECTORY_ATTRS = [ - 'install_lib', 'install_dir', 'install_data', 'install_base' -] - - -def make_zipfile(zip_filename, base_dir, verbose=0, dry_run=0, compress=True, - mode='w'): - """Create a zip file from all the files under 'base_dir'. The output - zip file will be named 'base_dir' + ".zip". Uses either the "zipfile" - Python module (if available) or the InfoZIP "zip" utility (if installed - and found on the default search path). If neither tool is available, - raises DistutilsExecError. Returns the name of the output zip file. - """ - import zipfile - - mkpath(os.path.dirname(zip_filename), dry_run=dry_run) - log.info("creating '%s' and adding '%s' to it", zip_filename, base_dir) - - def visit(z, dirname, names): - for name in names: - path = os.path.normpath(os.path.join(dirname, name)) - if os.path.isfile(path): - p = path[len(base_dir) + 1:] - if not dry_run: - z.write(path, p) - log.debug("adding '%s'", p) - - compression = zipfile.ZIP_DEFLATED if compress else zipfile.ZIP_STORED - if not dry_run: - z = zipfile.ZipFile(zip_filename, mode, compression=compression) - for dirname, dirs, files in sorted_walk(base_dir): - visit(z, dirname, files) - z.close() - else: - for dirname, dirs, files in sorted_walk(base_dir): - visit(None, dirname, files) - return zip_filename diff --git a/venv/lib/python3.8/site-packages/setuptools/command/bdist_rpm.py b/venv/lib/python3.8/site-packages/setuptools/command/bdist_rpm.py deleted file mode 100644 index 7073092..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/command/bdist_rpm.py +++ /dev/null @@ -1,43 +0,0 @@ -import distutils.command.bdist_rpm as orig - - -class bdist_rpm(orig.bdist_rpm): - """ - Override the default bdist_rpm behavior to do the following: - - 1. Run egg_info to ensure the name and version are properly calculated. - 2. Always run 'install' using --single-version-externally-managed to - disable eggs in RPM distributions. - 3. Replace dash with underscore in the version numbers for better RPM - compatibility. - """ - - def run(self): - # ensure distro name is up-to-date - self.run_command('egg_info') - - orig.bdist_rpm.run(self) - - def _make_spec_file(self): - version = self.distribution.get_version() - rpmversion = version.replace('-', '_') - spec = orig.bdist_rpm._make_spec_file(self) - line23 = '%define version ' + version - line24 = '%define version ' + rpmversion - spec = [ - line.replace( - "Source0: %{name}-%{version}.tar", - "Source0: %{name}-%{unmangled_version}.tar" - ).replace( - "setup.py install ", - "setup.py install --single-version-externally-managed " - ).replace( - "%setup", - "%setup -n %{name}-%{unmangled_version}" - ).replace(line23, line24) - for line in spec - ] - insert_loc = spec.index(line24) + 1 - unmangled_version = "%define unmangled_version " + version - spec.insert(insert_loc, unmangled_version) - return spec diff --git a/venv/lib/python3.8/site-packages/setuptools/command/bdist_wininst.py b/venv/lib/python3.8/site-packages/setuptools/command/bdist_wininst.py deleted file mode 100644 index 073de97..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/command/bdist_wininst.py +++ /dev/null @@ -1,21 +0,0 @@ -import distutils.command.bdist_wininst as orig - - -class bdist_wininst(orig.bdist_wininst): - def reinitialize_command(self, command, reinit_subcommands=0): - """ - Supplement reinitialize_command to work around - http://bugs.python.org/issue20819 - """ - cmd = self.distribution.reinitialize_command( - command, reinit_subcommands) - if command in ('install', 'install_lib'): - cmd.install_lib = None - return cmd - - def run(self): - self._is_running = True - try: - orig.bdist_wininst.run(self) - finally: - self._is_running = False diff --git a/venv/lib/python3.8/site-packages/setuptools/command/build_clib.py b/venv/lib/python3.8/site-packages/setuptools/command/build_clib.py deleted file mode 100644 index 09caff6..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/command/build_clib.py +++ /dev/null @@ -1,98 +0,0 @@ -import distutils.command.build_clib as orig -from distutils.errors import DistutilsSetupError -from distutils import log -from setuptools.dep_util import newer_pairwise_group - - -class build_clib(orig.build_clib): - """ - Override the default build_clib behaviour to do the following: - - 1. Implement a rudimentary timestamp-based dependency system - so 'compile()' doesn't run every time. - 2. Add more keys to the 'build_info' dictionary: - * obj_deps - specify dependencies for each object compiled. - this should be a dictionary mapping a key - with the source filename to a list of - dependencies. Use an empty string for global - dependencies. - * cflags - specify a list of additional flags to pass to - the compiler. - """ - - def build_libraries(self, libraries): - for (lib_name, build_info) in libraries: - sources = build_info.get('sources') - if sources is None or not isinstance(sources, (list, tuple)): - raise DistutilsSetupError( - "in 'libraries' option (library '%s'), " - "'sources' must be present and must be " - "a list of source filenames" % lib_name) - sources = list(sources) - - log.info("building '%s' library", lib_name) - - # Make sure everything is the correct type. - # obj_deps should be a dictionary of keys as sources - # and a list/tuple of files that are its dependencies. - obj_deps = build_info.get('obj_deps', dict()) - if not isinstance(obj_deps, dict): - raise DistutilsSetupError( - "in 'libraries' option (library '%s'), " - "'obj_deps' must be a dictionary of " - "type 'source: list'" % lib_name) - dependencies = [] - - # Get the global dependencies that are specified by the '' key. - # These will go into every source's dependency list. - global_deps = obj_deps.get('', list()) - if not isinstance(global_deps, (list, tuple)): - raise DistutilsSetupError( - "in 'libraries' option (library '%s'), " - "'obj_deps' must be a dictionary of " - "type 'source: list'" % lib_name) - - # Build the list to be used by newer_pairwise_group - # each source will be auto-added to its dependencies. - for source in sources: - src_deps = [source] - src_deps.extend(global_deps) - extra_deps = obj_deps.get(source, list()) - if not isinstance(extra_deps, (list, tuple)): - raise DistutilsSetupError( - "in 'libraries' option (library '%s'), " - "'obj_deps' must be a dictionary of " - "type 'source: list'" % lib_name) - src_deps.extend(extra_deps) - dependencies.append(src_deps) - - expected_objects = self.compiler.object_filenames( - sources, - output_dir=self.build_temp - ) - - if newer_pairwise_group(dependencies, expected_objects) != ([], []): - # First, compile the source code to object files in the library - # directory. (This should probably change to putting object - # files in a temporary build directory.) - macros = build_info.get('macros') - include_dirs = build_info.get('include_dirs') - cflags = build_info.get('cflags') - objects = self.compiler.compile( - sources, - output_dir=self.build_temp, - macros=macros, - include_dirs=include_dirs, - extra_postargs=cflags, - debug=self.debug - ) - - # Now "link" the object files together into a static library. - # (On Unix at least, this isn't really linking -- it just - # builds an archive. Whatever.) - self.compiler.create_static_lib( - expected_objects, - lib_name, - output_dir=self.build_clib, - debug=self.debug - ) diff --git a/venv/lib/python3.8/site-packages/setuptools/command/build_ext.py b/venv/lib/python3.8/site-packages/setuptools/command/build_ext.py deleted file mode 100644 index daa8e4f..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/command/build_ext.py +++ /dev/null @@ -1,327 +0,0 @@ -import os -import sys -import itertools -from distutils.command.build_ext import build_ext as _du_build_ext -from distutils.file_util import copy_file -from distutils.ccompiler import new_compiler -from distutils.sysconfig import customize_compiler, get_config_var -from distutils.errors import DistutilsError -from distutils import log - -from setuptools.extension import Library -from setuptools.extern import six - -if six.PY2: - import imp - - EXTENSION_SUFFIXES = [s for s, _, tp in imp.get_suffixes() if tp == imp.C_EXTENSION] -else: - from importlib.machinery import EXTENSION_SUFFIXES - -try: - # Attempt to use Cython for building extensions, if available - from Cython.Distutils.build_ext import build_ext as _build_ext - # Additionally, assert that the compiler module will load - # also. Ref #1229. - __import__('Cython.Compiler.Main') -except ImportError: - _build_ext = _du_build_ext - -# make sure _config_vars is initialized -get_config_var("LDSHARED") -from distutils.sysconfig import _config_vars as _CONFIG_VARS - - -def _customize_compiler_for_shlib(compiler): - if sys.platform == "darwin": - # building .dylib requires additional compiler flags on OSX; here we - # temporarily substitute the pyconfig.h variables so that distutils' - # 'customize_compiler' uses them before we build the shared libraries. - tmp = _CONFIG_VARS.copy() - try: - # XXX Help! I don't have any idea whether these are right... - _CONFIG_VARS['LDSHARED'] = ( - "gcc -Wl,-x -dynamiclib -undefined dynamic_lookup") - _CONFIG_VARS['CCSHARED'] = " -dynamiclib" - _CONFIG_VARS['SO'] = ".dylib" - customize_compiler(compiler) - finally: - _CONFIG_VARS.clear() - _CONFIG_VARS.update(tmp) - else: - customize_compiler(compiler) - - -have_rtld = False -use_stubs = False -libtype = 'shared' - -if sys.platform == "darwin": - use_stubs = True -elif os.name != 'nt': - try: - import dl - use_stubs = have_rtld = hasattr(dl, 'RTLD_NOW') - except ImportError: - pass - -if_dl = lambda s: s if have_rtld else '' - - -def get_abi3_suffix(): - """Return the file extension for an abi3-compliant Extension()""" - for suffix in EXTENSION_SUFFIXES: - if '.abi3' in suffix: # Unix - return suffix - elif suffix == '.pyd': # Windows - return suffix - - -class build_ext(_build_ext): - def run(self): - """Build extensions in build directory, then copy if --inplace""" - old_inplace, self.inplace = self.inplace, 0 - _build_ext.run(self) - self.inplace = old_inplace - if old_inplace: - self.copy_extensions_to_source() - - def copy_extensions_to_source(self): - build_py = self.get_finalized_command('build_py') - for ext in self.extensions: - fullname = self.get_ext_fullname(ext.name) - filename = self.get_ext_filename(fullname) - modpath = fullname.split('.') - package = '.'.join(modpath[:-1]) - package_dir = build_py.get_package_dir(package) - dest_filename = os.path.join(package_dir, - os.path.basename(filename)) - src_filename = os.path.join(self.build_lib, filename) - - # Always copy, even if source is older than destination, to ensure - # that the right extensions for the current Python/platform are - # used. - copy_file( - src_filename, dest_filename, verbose=self.verbose, - dry_run=self.dry_run - ) - if ext._needs_stub: - self.write_stub(package_dir or os.curdir, ext, True) - - def get_ext_filename(self, fullname): - filename = _build_ext.get_ext_filename(self, fullname) - if fullname in self.ext_map: - ext = self.ext_map[fullname] - use_abi3 = ( - six.PY3 - and getattr(ext, 'py_limited_api') - and get_abi3_suffix() - ) - if use_abi3: - so_ext = get_config_var('EXT_SUFFIX') - filename = filename[:-len(so_ext)] - filename = filename + get_abi3_suffix() - if isinstance(ext, Library): - fn, ext = os.path.splitext(filename) - return self.shlib_compiler.library_filename(fn, libtype) - elif use_stubs and ext._links_to_dynamic: - d, fn = os.path.split(filename) - return os.path.join(d, 'dl-' + fn) - return filename - - def initialize_options(self): - _build_ext.initialize_options(self) - self.shlib_compiler = None - self.shlibs = [] - self.ext_map = {} - - def finalize_options(self): - _build_ext.finalize_options(self) - self.extensions = self.extensions or [] - self.check_extensions_list(self.extensions) - self.shlibs = [ext for ext in self.extensions - if isinstance(ext, Library)] - if self.shlibs: - self.setup_shlib_compiler() - for ext in self.extensions: - ext._full_name = self.get_ext_fullname(ext.name) - for ext in self.extensions: - fullname = ext._full_name - self.ext_map[fullname] = ext - - # distutils 3.1 will also ask for module names - # XXX what to do with conflicts? - self.ext_map[fullname.split('.')[-1]] = ext - - ltd = self.shlibs and self.links_to_dynamic(ext) or False - ns = ltd and use_stubs and not isinstance(ext, Library) - ext._links_to_dynamic = ltd - ext._needs_stub = ns - filename = ext._file_name = self.get_ext_filename(fullname) - libdir = os.path.dirname(os.path.join(self.build_lib, filename)) - if ltd and libdir not in ext.library_dirs: - ext.library_dirs.append(libdir) - if ltd and use_stubs and os.curdir not in ext.runtime_library_dirs: - ext.runtime_library_dirs.append(os.curdir) - - def setup_shlib_compiler(self): - compiler = self.shlib_compiler = new_compiler( - compiler=self.compiler, dry_run=self.dry_run, force=self.force - ) - _customize_compiler_for_shlib(compiler) - - if self.include_dirs is not None: - compiler.set_include_dirs(self.include_dirs) - if self.define is not None: - # 'define' option is a list of (name,value) tuples - for (name, value) in self.define: - compiler.define_macro(name, value) - if self.undef is not None: - for macro in self.undef: - compiler.undefine_macro(macro) - if self.libraries is not None: - compiler.set_libraries(self.libraries) - if self.library_dirs is not None: - compiler.set_library_dirs(self.library_dirs) - if self.rpath is not None: - compiler.set_runtime_library_dirs(self.rpath) - if self.link_objects is not None: - compiler.set_link_objects(self.link_objects) - - # hack so distutils' build_extension() builds a library instead - compiler.link_shared_object = link_shared_object.__get__(compiler) - - def get_export_symbols(self, ext): - if isinstance(ext, Library): - return ext.export_symbols - return _build_ext.get_export_symbols(self, ext) - - def build_extension(self, ext): - ext._convert_pyx_sources_to_lang() - _compiler = self.compiler - try: - if isinstance(ext, Library): - self.compiler = self.shlib_compiler - _build_ext.build_extension(self, ext) - if ext._needs_stub: - cmd = self.get_finalized_command('build_py').build_lib - self.write_stub(cmd, ext) - finally: - self.compiler = _compiler - - def links_to_dynamic(self, ext): - """Return true if 'ext' links to a dynamic lib in the same package""" - # XXX this should check to ensure the lib is actually being built - # XXX as dynamic, and not just using a locally-found version or a - # XXX static-compiled version - libnames = dict.fromkeys([lib._full_name for lib in self.shlibs]) - pkg = '.'.join(ext._full_name.split('.')[:-1] + ['']) - return any(pkg + libname in libnames for libname in ext.libraries) - - def get_outputs(self): - return _build_ext.get_outputs(self) + self.__get_stubs_outputs() - - def __get_stubs_outputs(self): - # assemble the base name for each extension that needs a stub - ns_ext_bases = ( - os.path.join(self.build_lib, *ext._full_name.split('.')) - for ext in self.extensions - if ext._needs_stub - ) - # pair each base with the extension - pairs = itertools.product(ns_ext_bases, self.__get_output_extensions()) - return list(base + fnext for base, fnext in pairs) - - def __get_output_extensions(self): - yield '.py' - yield '.pyc' - if self.get_finalized_command('build_py').optimize: - yield '.pyo' - - def write_stub(self, output_dir, ext, compile=False): - log.info("writing stub loader for %s to %s", ext._full_name, - output_dir) - stub_file = (os.path.join(output_dir, *ext._full_name.split('.')) + - '.py') - if compile and os.path.exists(stub_file): - raise DistutilsError(stub_file + " already exists! Please delete.") - if not self.dry_run: - f = open(stub_file, 'w') - f.write( - '\n'.join([ - "def __bootstrap__():", - " global __bootstrap__, __file__, __loader__", - " import sys, os, pkg_resources, imp" + if_dl(", dl"), - " __file__ = pkg_resources.resource_filename" - "(__name__,%r)" - % os.path.basename(ext._file_name), - " del __bootstrap__", - " if '__loader__' in globals():", - " del __loader__", - if_dl(" old_flags = sys.getdlopenflags()"), - " old_dir = os.getcwd()", - " try:", - " os.chdir(os.path.dirname(__file__))", - if_dl(" sys.setdlopenflags(dl.RTLD_NOW)"), - " imp.load_dynamic(__name__,__file__)", - " finally:", - if_dl(" sys.setdlopenflags(old_flags)"), - " os.chdir(old_dir)", - "__bootstrap__()", - "" # terminal \n - ]) - ) - f.close() - if compile: - from distutils.util import byte_compile - - byte_compile([stub_file], optimize=0, - force=True, dry_run=self.dry_run) - optimize = self.get_finalized_command('install_lib').optimize - if optimize > 0: - byte_compile([stub_file], optimize=optimize, - force=True, dry_run=self.dry_run) - if os.path.exists(stub_file) and not self.dry_run: - os.unlink(stub_file) - - -if use_stubs or os.name == 'nt': - # Build shared libraries - # - def link_shared_object( - self, objects, output_libname, output_dir=None, libraries=None, - library_dirs=None, runtime_library_dirs=None, export_symbols=None, - debug=0, extra_preargs=None, extra_postargs=None, build_temp=None, - target_lang=None): - self.link( - self.SHARED_LIBRARY, objects, output_libname, - output_dir, libraries, library_dirs, runtime_library_dirs, - export_symbols, debug, extra_preargs, extra_postargs, - build_temp, target_lang - ) -else: - # Build static libraries everywhere else - libtype = 'static' - - def link_shared_object( - self, objects, output_libname, output_dir=None, libraries=None, - library_dirs=None, runtime_library_dirs=None, export_symbols=None, - debug=0, extra_preargs=None, extra_postargs=None, build_temp=None, - target_lang=None): - # XXX we need to either disallow these attrs on Library instances, - # or warn/abort here if set, or something... - # libraries=None, library_dirs=None, runtime_library_dirs=None, - # export_symbols=None, extra_preargs=None, extra_postargs=None, - # build_temp=None - - assert output_dir is None # distutils build_ext doesn't pass this - output_dir, filename = os.path.split(output_libname) - basename, ext = os.path.splitext(filename) - if self.library_filename("x").startswith('lib'): - # strip 'lib' prefix; this is kludgy if some platform uses - # a different prefix - basename = basename[3:] - - self.create_static_lib( - objects, basename, output_dir, debug, target_lang - ) diff --git a/venv/lib/python3.8/site-packages/setuptools/command/build_py.py b/venv/lib/python3.8/site-packages/setuptools/command/build_py.py deleted file mode 100644 index b0314fd..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/command/build_py.py +++ /dev/null @@ -1,270 +0,0 @@ -from glob import glob -from distutils.util import convert_path -import distutils.command.build_py as orig -import os -import fnmatch -import textwrap -import io -import distutils.errors -import itertools - -from setuptools.extern import six -from setuptools.extern.six.moves import map, filter, filterfalse - -try: - from setuptools.lib2to3_ex import Mixin2to3 -except ImportError: - - class Mixin2to3: - def run_2to3(self, files, doctests=True): - "do nothing" - - -class build_py(orig.build_py, Mixin2to3): - """Enhanced 'build_py' command that includes data files with packages - - The data files are specified via a 'package_data' argument to 'setup()'. - See 'setuptools.dist.Distribution' for more details. - - Also, this version of the 'build_py' command allows you to specify both - 'py_modules' and 'packages' in the same setup operation. - """ - - def finalize_options(self): - orig.build_py.finalize_options(self) - self.package_data = self.distribution.package_data - self.exclude_package_data = (self.distribution.exclude_package_data or - {}) - if 'data_files' in self.__dict__: - del self.__dict__['data_files'] - self.__updated_files = [] - self.__doctests_2to3 = [] - - def run(self): - """Build modules, packages, and copy data files to build directory""" - if not self.py_modules and not self.packages: - return - - if self.py_modules: - self.build_modules() - - if self.packages: - self.build_packages() - self.build_package_data() - - self.run_2to3(self.__updated_files, False) - self.run_2to3(self.__updated_files, True) - self.run_2to3(self.__doctests_2to3, True) - - # Only compile actual .py files, using our base class' idea of what our - # output files are. - self.byte_compile(orig.build_py.get_outputs(self, include_bytecode=0)) - - def __getattr__(self, attr): - "lazily compute data files" - if attr == 'data_files': - self.data_files = self._get_data_files() - return self.data_files - return orig.build_py.__getattr__(self, attr) - - def build_module(self, module, module_file, package): - if six.PY2 and isinstance(package, six.string_types): - # avoid errors on Python 2 when unicode is passed (#190) - package = package.split('.') - outfile, copied = orig.build_py.build_module(self, module, module_file, - package) - if copied: - self.__updated_files.append(outfile) - return outfile, copied - - def _get_data_files(self): - """Generate list of '(package,src_dir,build_dir,filenames)' tuples""" - self.analyze_manifest() - return list(map(self._get_pkg_data_files, self.packages or ())) - - def _get_pkg_data_files(self, package): - # Locate package source directory - src_dir = self.get_package_dir(package) - - # Compute package build directory - build_dir = os.path.join(*([self.build_lib] + package.split('.'))) - - # Strip directory from globbed filenames - filenames = [ - os.path.relpath(file, src_dir) - for file in self.find_data_files(package, src_dir) - ] - return package, src_dir, build_dir, filenames - - def find_data_files(self, package, src_dir): - """Return filenames for package's data files in 'src_dir'""" - patterns = self._get_platform_patterns( - self.package_data, - package, - src_dir, - ) - globs_expanded = map(glob, patterns) - # flatten the expanded globs into an iterable of matches - globs_matches = itertools.chain.from_iterable(globs_expanded) - glob_files = filter(os.path.isfile, globs_matches) - files = itertools.chain( - self.manifest_files.get(package, []), - glob_files, - ) - return self.exclude_data_files(package, src_dir, files) - - def build_package_data(self): - """Copy data files into build directory""" - for package, src_dir, build_dir, filenames in self.data_files: - for filename in filenames: - target = os.path.join(build_dir, filename) - self.mkpath(os.path.dirname(target)) - srcfile = os.path.join(src_dir, filename) - outf, copied = self.copy_file(srcfile, target) - srcfile = os.path.abspath(srcfile) - if (copied and - srcfile in self.distribution.convert_2to3_doctests): - self.__doctests_2to3.append(outf) - - def analyze_manifest(self): - self.manifest_files = mf = {} - if not self.distribution.include_package_data: - return - src_dirs = {} - for package in self.packages or (): - # Locate package source directory - src_dirs[assert_relative(self.get_package_dir(package))] = package - - self.run_command('egg_info') - ei_cmd = self.get_finalized_command('egg_info') - for path in ei_cmd.filelist.files: - d, f = os.path.split(assert_relative(path)) - prev = None - oldf = f - while d and d != prev and d not in src_dirs: - prev = d - d, df = os.path.split(d) - f = os.path.join(df, f) - if d in src_dirs: - if path.endswith('.py') and f == oldf: - continue # it's a module, not data - mf.setdefault(src_dirs[d], []).append(path) - - def get_data_files(self): - pass # Lazily compute data files in _get_data_files() function. - - def check_package(self, package, package_dir): - """Check namespace packages' __init__ for declare_namespace""" - try: - return self.packages_checked[package] - except KeyError: - pass - - init_py = orig.build_py.check_package(self, package, package_dir) - self.packages_checked[package] = init_py - - if not init_py or not self.distribution.namespace_packages: - return init_py - - for pkg in self.distribution.namespace_packages: - if pkg == package or pkg.startswith(package + '.'): - break - else: - return init_py - - with io.open(init_py, 'rb') as f: - contents = f.read() - if b'declare_namespace' not in contents: - raise distutils.errors.DistutilsError( - "Namespace package problem: %s is a namespace package, but " - "its\n__init__.py does not call declare_namespace()! Please " - 'fix it.\n(See the setuptools manual under ' - '"Namespace Packages" for details.)\n"' % (package,) - ) - return init_py - - def initialize_options(self): - self.packages_checked = {} - orig.build_py.initialize_options(self) - - def get_package_dir(self, package): - res = orig.build_py.get_package_dir(self, package) - if self.distribution.src_root is not None: - return os.path.join(self.distribution.src_root, res) - return res - - def exclude_data_files(self, package, src_dir, files): - """Filter filenames for package's data files in 'src_dir'""" - files = list(files) - patterns = self._get_platform_patterns( - self.exclude_package_data, - package, - src_dir, - ) - match_groups = ( - fnmatch.filter(files, pattern) - for pattern in patterns - ) - # flatten the groups of matches into an iterable of matches - matches = itertools.chain.from_iterable(match_groups) - bad = set(matches) - keepers = ( - fn - for fn in files - if fn not in bad - ) - # ditch dupes - return list(_unique_everseen(keepers)) - - @staticmethod - def _get_platform_patterns(spec, package, src_dir): - """ - yield platform-specific path patterns (suitable for glob - or fn_match) from a glob-based spec (such as - self.package_data or self.exclude_package_data) - matching package in src_dir. - """ - raw_patterns = itertools.chain( - spec.get('', []), - spec.get(package, []), - ) - return ( - # Each pattern has to be converted to a platform-specific path - os.path.join(src_dir, convert_path(pattern)) - for pattern in raw_patterns - ) - - -# from Python docs -def _unique_everseen(iterable, key=None): - "List unique elements, preserving order. Remember all elements ever seen." - # unique_everseen('AAAABBBCCDAABBB') --> A B C D - # unique_everseen('ABBCcAD', str.lower) --> A B C D - seen = set() - seen_add = seen.add - if key is None: - for element in filterfalse(seen.__contains__, iterable): - seen_add(element) - yield element - else: - for element in iterable: - k = key(element) - if k not in seen: - seen_add(k) - yield element - - -def assert_relative(path): - if not os.path.isabs(path): - return path - from distutils.errors import DistutilsSetupError - - msg = textwrap.dedent(""" - Error: setup script specifies an absolute path: - - %s - - setup() arguments must *always* be /-separated paths relative to the - setup.py directory, *never* absolute paths. - """).lstrip() % path - raise DistutilsSetupError(msg) diff --git a/venv/lib/python3.8/site-packages/setuptools/command/develop.py b/venv/lib/python3.8/site-packages/setuptools/command/develop.py deleted file mode 100644 index 009e4f9..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/command/develop.py +++ /dev/null @@ -1,221 +0,0 @@ -from distutils.util import convert_path -from distutils import log -from distutils.errors import DistutilsError, DistutilsOptionError -import os -import glob -import io - -from setuptools.extern import six - -import pkg_resources -from setuptools.command.easy_install import easy_install -from setuptools import namespaces -import setuptools - -__metaclass__ = type - - -class develop(namespaces.DevelopInstaller, easy_install): - """Set up package for development""" - - description = "install package in 'development mode'" - - user_options = easy_install.user_options + [ - ("uninstall", "u", "Uninstall this source package"), - ("egg-path=", None, "Set the path to be used in the .egg-link file"), - ] - - boolean_options = easy_install.boolean_options + ['uninstall'] - - command_consumes_arguments = False # override base - - def run(self): - if self.uninstall: - self.multi_version = True - self.uninstall_link() - self.uninstall_namespaces() - else: - self.install_for_development() - self.warn_deprecated_options() - - def initialize_options(self): - self.uninstall = None - self.egg_path = None - easy_install.initialize_options(self) - self.setup_path = None - self.always_copy_from = '.' # always copy eggs installed in curdir - - def finalize_options(self): - ei = self.get_finalized_command("egg_info") - if ei.broken_egg_info: - template = "Please rename %r to %r before using 'develop'" - args = ei.egg_info, ei.broken_egg_info - raise DistutilsError(template % args) - self.args = [ei.egg_name] - - easy_install.finalize_options(self) - self.expand_basedirs() - self.expand_dirs() - # pick up setup-dir .egg files only: no .egg-info - self.package_index.scan(glob.glob('*.egg')) - - egg_link_fn = ei.egg_name + '.egg-link' - self.egg_link = os.path.join(self.install_dir, egg_link_fn) - self.egg_base = ei.egg_base - if self.egg_path is None: - self.egg_path = os.path.abspath(ei.egg_base) - - target = pkg_resources.normalize_path(self.egg_base) - egg_path = pkg_resources.normalize_path( - os.path.join(self.install_dir, self.egg_path)) - if egg_path != target: - raise DistutilsOptionError( - "--egg-path must be a relative path from the install" - " directory to " + target - ) - - # Make a distribution for the package's source - self.dist = pkg_resources.Distribution( - target, - pkg_resources.PathMetadata(target, os.path.abspath(ei.egg_info)), - project_name=ei.egg_name - ) - - self.setup_path = self._resolve_setup_path( - self.egg_base, - self.install_dir, - self.egg_path, - ) - - @staticmethod - def _resolve_setup_path(egg_base, install_dir, egg_path): - """ - Generate a path from egg_base back to '.' where the - setup script resides and ensure that path points to the - setup path from $install_dir/$egg_path. - """ - path_to_setup = egg_base.replace(os.sep, '/').rstrip('/') - if path_to_setup != os.curdir: - path_to_setup = '../' * (path_to_setup.count('/') + 1) - resolved = pkg_resources.normalize_path( - os.path.join(install_dir, egg_path, path_to_setup) - ) - if resolved != pkg_resources.normalize_path(os.curdir): - raise DistutilsOptionError( - "Can't get a consistent path to setup script from" - " installation directory", resolved, - pkg_resources.normalize_path(os.curdir)) - return path_to_setup - - def install_for_development(self): - if six.PY3 and getattr(self.distribution, 'use_2to3', False): - # If we run 2to3 we can not do this inplace: - - # Ensure metadata is up-to-date - self.reinitialize_command('build_py', inplace=0) - self.run_command('build_py') - bpy_cmd = self.get_finalized_command("build_py") - build_path = pkg_resources.normalize_path(bpy_cmd.build_lib) - - # Build extensions - self.reinitialize_command('egg_info', egg_base=build_path) - self.run_command('egg_info') - - self.reinitialize_command('build_ext', inplace=0) - self.run_command('build_ext') - - # Fixup egg-link and easy-install.pth - ei_cmd = self.get_finalized_command("egg_info") - self.egg_path = build_path - self.dist.location = build_path - # XXX - self.dist._provider = pkg_resources.PathMetadata( - build_path, ei_cmd.egg_info) - else: - # Without 2to3 inplace works fine: - self.run_command('egg_info') - - # Build extensions in-place - self.reinitialize_command('build_ext', inplace=1) - self.run_command('build_ext') - - self.install_site_py() # ensure that target dir is site-safe - if setuptools.bootstrap_install_from: - self.easy_install(setuptools.bootstrap_install_from) - setuptools.bootstrap_install_from = None - - self.install_namespaces() - - # create an .egg-link in the installation dir, pointing to our egg - log.info("Creating %s (link to %s)", self.egg_link, self.egg_base) - if not self.dry_run: - with open(self.egg_link, "w") as f: - f.write(self.egg_path + "\n" + self.setup_path) - # postprocess the installed distro, fixing up .pth, installing scripts, - # and handling requirements - self.process_distribution(None, self.dist, not self.no_deps) - - def uninstall_link(self): - if os.path.exists(self.egg_link): - log.info("Removing %s (link to %s)", self.egg_link, self.egg_base) - egg_link_file = open(self.egg_link) - contents = [line.rstrip() for line in egg_link_file] - egg_link_file.close() - if contents not in ([self.egg_path], - [self.egg_path, self.setup_path]): - log.warn("Link points to %s: uninstall aborted", contents) - return - if not self.dry_run: - os.unlink(self.egg_link) - if not self.dry_run: - self.update_pth(self.dist) # remove any .pth link to us - if self.distribution.scripts: - # XXX should also check for entry point scripts! - log.warn("Note: you must uninstall or replace scripts manually!") - - def install_egg_scripts(self, dist): - if dist is not self.dist: - # Installing a dependency, so fall back to normal behavior - return easy_install.install_egg_scripts(self, dist) - - # create wrapper scripts in the script dir, pointing to dist.scripts - - # new-style... - self.install_wrapper_scripts(dist) - - # ...and old-style - for script_name in self.distribution.scripts or []: - script_path = os.path.abspath(convert_path(script_name)) - script_name = os.path.basename(script_path) - with io.open(script_path) as strm: - script_text = strm.read() - self.install_script(dist, script_name, script_text, script_path) - - def install_wrapper_scripts(self, dist): - dist = VersionlessRequirement(dist) - return easy_install.install_wrapper_scripts(self, dist) - - -class VersionlessRequirement: - """ - Adapt a pkg_resources.Distribution to simply return the project - name as the 'requirement' so that scripts will work across - multiple versions. - - >>> from pkg_resources import Distribution - >>> dist = Distribution(project_name='foo', version='1.0') - >>> str(dist.as_requirement()) - 'foo==1.0' - >>> adapted_dist = VersionlessRequirement(dist) - >>> str(adapted_dist.as_requirement()) - 'foo' - """ - - def __init__(self, dist): - self.__dist = dist - - def __getattr__(self, name): - return getattr(self.__dist, name) - - def as_requirement(self): - return self.project_name diff --git a/venv/lib/python3.8/site-packages/setuptools/command/dist_info.py b/venv/lib/python3.8/site-packages/setuptools/command/dist_info.py deleted file mode 100644 index c45258f..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/command/dist_info.py +++ /dev/null @@ -1,36 +0,0 @@ -""" -Create a dist_info directory -As defined in the wheel specification -""" - -import os - -from distutils.core import Command -from distutils import log - - -class dist_info(Command): - - description = 'create a .dist-info directory' - - user_options = [ - ('egg-base=', 'e', "directory containing .egg-info directories" - " (default: top of the source tree)"), - ] - - def initialize_options(self): - self.egg_base = None - - def finalize_options(self): - pass - - def run(self): - egg_info = self.get_finalized_command('egg_info') - egg_info.egg_base = self.egg_base - egg_info.finalize_options() - egg_info.run() - dist_info_dir = egg_info.egg_info[:-len('.egg-info')] + '.dist-info' - log.info("creating '{}'".format(os.path.abspath(dist_info_dir))) - - bdist_wheel = self.get_finalized_command('bdist_wheel') - bdist_wheel.egg2dist(egg_info.egg_info, dist_info_dir) diff --git a/venv/lib/python3.8/site-packages/setuptools/command/easy_install.py b/venv/lib/python3.8/site-packages/setuptools/command/easy_install.py deleted file mode 100644 index 1f6839c..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/command/easy_install.py +++ /dev/null @@ -1,2402 +0,0 @@ -#!/usr/bin/env python -""" -Easy Install ------------- - -A tool for doing automatic download/extract/build of distutils-based Python -packages. For detailed documentation, see the accompanying EasyInstall.txt -file, or visit the `EasyInstall home page`__. - -__ https://setuptools.readthedocs.io/en/latest/easy_install.html - -""" - -from glob import glob -from distutils.util import get_platform -from distutils.util import convert_path, subst_vars -from distutils.errors import ( - DistutilsArgError, DistutilsOptionError, - DistutilsError, DistutilsPlatformError, -) -from distutils.command.install import INSTALL_SCHEMES, SCHEME_KEYS -from distutils import log, dir_util -from distutils.command.build_scripts import first_line_re -from distutils.spawn import find_executable -import sys -import os -import zipimport -import shutil -import tempfile -import zipfile -import re -import stat -import random -import textwrap -import warnings -import site -import struct -import contextlib -import subprocess -import shlex -import io - - -from sysconfig import get_config_vars, get_path - -from setuptools import SetuptoolsDeprecationWarning - -from setuptools.extern import six -from setuptools.extern.six.moves import configparser, map - -from setuptools import Command -from setuptools.sandbox import run_setup -from setuptools.py27compat import rmtree_safe -from setuptools.command import setopt -from setuptools.archive_util import unpack_archive -from setuptools.package_index import ( - PackageIndex, parse_requirement_arg, URL_SCHEME, -) -from setuptools.command import bdist_egg, egg_info -from setuptools.wheel import Wheel -from pkg_resources import ( - yield_lines, normalize_path, resource_string, ensure_directory, - get_distribution, find_distributions, Environment, Requirement, - Distribution, PathMetadata, EggMetadata, WorkingSet, DistributionNotFound, - VersionConflict, DEVELOP_DIST, -) -import pkg_resources.py31compat - -__metaclass__ = type - -# Turn on PEP440Warnings -warnings.filterwarnings("default", category=pkg_resources.PEP440Warning) - -__all__ = [ - 'samefile', 'easy_install', 'PthDistributions', 'extract_wininst_cfg', - 'main', 'get_exe_prefixes', -] - - -def is_64bit(): - return struct.calcsize("P") == 8 - - -def samefile(p1, p2): - """ - Determine if two paths reference the same file. - - Augments os.path.samefile to work on Windows and - suppresses errors if the path doesn't exist. - """ - both_exist = os.path.exists(p1) and os.path.exists(p2) - use_samefile = hasattr(os.path, 'samefile') and both_exist - if use_samefile: - return os.path.samefile(p1, p2) - norm_p1 = os.path.normpath(os.path.normcase(p1)) - norm_p2 = os.path.normpath(os.path.normcase(p2)) - return norm_p1 == norm_p2 - - -if six.PY2: - - def _to_bytes(s): - return s - - def isascii(s): - try: - six.text_type(s, 'ascii') - return True - except UnicodeError: - return False -else: - - def _to_bytes(s): - return s.encode('utf8') - - def isascii(s): - try: - s.encode('ascii') - return True - except UnicodeError: - return False - - -_one_liner = lambda text: textwrap.dedent(text).strip().replace('\n', '; ') - - -class easy_install(Command): - """Manage a download/build/install process""" - description = "Find/get/install Python packages" - command_consumes_arguments = True - - user_options = [ - ('prefix=', None, "installation prefix"), - ("zip-ok", "z", "install package as a zipfile"), - ("multi-version", "m", "make apps have to require() a version"), - ("upgrade", "U", "force upgrade (searches PyPI for latest versions)"), - ("install-dir=", "d", "install package to DIR"), - ("script-dir=", "s", "install scripts to DIR"), - ("exclude-scripts", "x", "Don't install scripts"), - ("always-copy", "a", "Copy all needed packages to install dir"), - ("index-url=", "i", "base URL of Python Package Index"), - ("find-links=", "f", "additional URL(s) to search for packages"), - ("build-directory=", "b", - "download/extract/build in DIR; keep the results"), - ('optimize=', 'O', - "also compile with optimization: -O1 for \"python -O\", " - "-O2 for \"python -OO\", and -O0 to disable [default: -O0]"), - ('record=', None, - "filename in which to record list of installed files"), - ('always-unzip', 'Z', "don't install as a zipfile, no matter what"), - ('site-dirs=', 'S', "list of directories where .pth files work"), - ('editable', 'e', "Install specified packages in editable form"), - ('no-deps', 'N', "don't install dependencies"), - ('allow-hosts=', 'H', "pattern(s) that hostnames must match"), - ('local-snapshots-ok', 'l', - "allow building eggs from local checkouts"), - ('version', None, "print version information and exit"), - ('install-layout=', None, "installation layout to choose (known values: deb)"), - ('force-installation-into-system-dir', '0', "force installation into /usr"), - ('no-find-links', None, - "Don't load find-links defined in packages being installed") - ] - boolean_options = [ - 'zip-ok', 'multi-version', 'exclude-scripts', 'upgrade', 'always-copy', - 'editable', - 'no-deps', 'local-snapshots-ok', 'version', 'force-installation-into-system-dir' - ] - - if site.ENABLE_USER_SITE: - help_msg = "install in user site-package '%s'" % site.USER_SITE - user_options.append(('user', None, help_msg)) - boolean_options.append('user') - - negative_opt = {'always-unzip': 'zip-ok'} - create_index = PackageIndex - - def initialize_options(self): - # the --user option seems to be an opt-in one, - # so the default should be False. - self.user = 0 - self.zip_ok = self.local_snapshots_ok = None - self.install_dir = self.script_dir = self.exclude_scripts = None - self.index_url = None - self.find_links = None - self.build_directory = None - self.args = None - self.optimize = self.record = None - self.upgrade = self.always_copy = self.multi_version = None - self.editable = self.no_deps = self.allow_hosts = None - self.root = self.prefix = self.no_report = None - self.version = None - self.install_purelib = None # for pure module distributions - self.install_platlib = None # non-pure (dists w/ extensions) - self.install_headers = None # for C/C++ headers - self.install_lib = None # set to either purelib or platlib - self.install_scripts = None - self.install_data = None - self.install_base = None - self.install_platbase = None - if site.ENABLE_USER_SITE: - self.install_userbase = site.USER_BASE - self.install_usersite = site.USER_SITE - else: - self.install_userbase = None - self.install_usersite = None - self.no_find_links = None - - # Options not specifiable via command line - self.package_index = None - self.pth_file = self.always_copy_from = None - self.site_dirs = None - self.installed_projects = {} - self.sitepy_installed = False - # enable custom installation, known values: deb - self.install_layout = None - self.force_installation_into_system_dir = None - self.multiarch = None - - # Always read easy_install options, even if we are subclassed, or have - # an independent instance created. This ensures that defaults will - # always come from the standard configuration file(s)' "easy_install" - # section, even if this is a "develop" or "install" command, or some - # other embedding. - self._dry_run = None - self.verbose = self.distribution.verbose - self.distribution._set_command_options( - self, self.distribution.get_option_dict('easy_install') - ) - - def delete_blockers(self, blockers): - extant_blockers = ( - filename for filename in blockers - if os.path.exists(filename) or os.path.islink(filename) - ) - list(map(self._delete_path, extant_blockers)) - - def _delete_path(self, path): - log.info("Deleting %s", path) - if self.dry_run: - return - - is_tree = os.path.isdir(path) and not os.path.islink(path) - remover = rmtree if is_tree else os.unlink - remover(path) - - @staticmethod - def _render_version(): - """ - Render the Setuptools version and installation details, then exit. - """ - ver = '{}.{}'.format(*sys.version_info) - dist = get_distribution('setuptools') - tmpl = 'setuptools {dist.version} from {dist.location} (Python {ver})' - print(tmpl.format(**locals())) - raise SystemExit() - - def finalize_options(self): - self.version and self._render_version() - - py_version = sys.version.split()[0] - prefix, exec_prefix = get_config_vars('prefix', 'exec_prefix') - - self.config_vars = { - 'dist_name': self.distribution.get_name(), - 'dist_version': self.distribution.get_version(), - 'dist_fullname': self.distribution.get_fullname(), - 'py_version': py_version, - 'py_version_short': py_version[0:3], - 'py_version_nodot': py_version[0] + py_version[2], - 'sys_prefix': prefix, - 'prefix': prefix, - 'sys_exec_prefix': exec_prefix, - 'exec_prefix': exec_prefix, - # Only python 3.2+ has abiflags - 'abiflags': getattr(sys, 'abiflags', ''), - } - - if site.ENABLE_USER_SITE: - self.config_vars['userbase'] = self.install_userbase - self.config_vars['usersite'] = self.install_usersite - - self._fix_install_dir_for_user_site() - - self.expand_basedirs() - self.expand_dirs() - - if self.install_layout: - if not self.install_layout.lower() in ['deb']: - raise DistutilsOptionError("unknown value for --install-layout") - self.install_layout = self.install_layout.lower() - - import sysconfig - if sys.version_info[:2] >= (3, 3): - self.multiarch = sysconfig.get_config_var('MULTIARCH') - - self._expand( - 'install_dir', 'script_dir', 'build_directory', - 'site_dirs', - ) - # If a non-default installation directory was specified, default the - # script directory to match it. - if self.script_dir is None: - self.script_dir = self.install_dir - - if self.no_find_links is None: - self.no_find_links = False - - # Let install_dir get set by install_lib command, which in turn - # gets its info from the install command, and takes into account - # --prefix and --home and all that other crud. - self.set_undefined_options( - 'install_lib', ('install_dir', 'install_dir') - ) - # Likewise, set default script_dir from 'install_scripts.install_dir' - self.set_undefined_options( - 'install_scripts', ('install_dir', 'script_dir') - ) - - if self.user and self.install_purelib: - self.install_dir = self.install_purelib - self.script_dir = self.install_scripts - - if self.prefix == '/usr' and not self.force_installation_into_system_dir: - raise DistutilsOptionError("""installation into /usr - -Trying to install into the system managed parts of the file system. Please -consider to install to another location, or use the option ---force-installation-into-system-dir to overwrite this warning. -""") - - # default --record from the install command - self.set_undefined_options('install', ('record', 'record')) - # Should this be moved to the if statement below? It's not used - # elsewhere - normpath = map(normalize_path, sys.path) - self.all_site_dirs = get_site_dirs() - if self.site_dirs is not None: - site_dirs = [ - os.path.expanduser(s.strip()) for s in - self.site_dirs.split(',') - ] - for d in site_dirs: - if not os.path.isdir(d): - log.warn("%s (in --site-dirs) does not exist", d) - elif normalize_path(d) not in normpath: - raise DistutilsOptionError( - d + " (in --site-dirs) is not on sys.path" - ) - else: - self.all_site_dirs.append(normalize_path(d)) - if not self.editable: - self.check_site_dir() - self.index_url = self.index_url or "https://pypi.org/simple/" - self.shadow_path = self.all_site_dirs[:] - for path_item in self.install_dir, normalize_path(self.script_dir): - if path_item not in self.shadow_path: - self.shadow_path.insert(0, path_item) - - if self.allow_hosts is not None: - hosts = [s.strip() for s in self.allow_hosts.split(',')] - else: - hosts = ['*'] - if self.package_index is None: - self.package_index = self.create_index( - self.index_url, search_path=self.shadow_path, hosts=hosts, - ) - self.local_index = Environment(self.shadow_path + sys.path) - - if self.find_links is not None: - if isinstance(self.find_links, six.string_types): - self.find_links = self.find_links.split() - else: - self.find_links = [] - if self.local_snapshots_ok: - self.package_index.scan_egg_links(self.shadow_path + sys.path) - if not self.no_find_links: - self.package_index.add_find_links(self.find_links) - self.set_undefined_options('install_lib', ('optimize', 'optimize')) - if not isinstance(self.optimize, int): - try: - self.optimize = int(self.optimize) - if not (0 <= self.optimize <= 2): - raise ValueError - except ValueError: - raise DistutilsOptionError("--optimize must be 0, 1, or 2") - - if self.editable and not self.build_directory: - raise DistutilsArgError( - "Must specify a build directory (-b) when using --editable" - ) - if not self.args: - raise DistutilsArgError( - "No urls, filenames, or requirements specified (see --help)") - - self.outputs = [] - - def _fix_install_dir_for_user_site(self): - """ - Fix the install_dir if "--user" was used. - """ - if not self.user or not site.ENABLE_USER_SITE: - return - - self.create_home_path() - if self.install_userbase is None: - msg = "User base directory is not specified" - raise DistutilsPlatformError(msg) - self.install_base = self.install_platbase = self.install_userbase - scheme_name = os.name.replace('posix', 'unix') + '_user' - self.select_scheme(scheme_name) - - def _expand_attrs(self, attrs): - for attr in attrs: - val = getattr(self, attr) - if val is not None: - if os.name == 'posix' or os.name == 'nt': - val = os.path.expanduser(val) - val = subst_vars(val, self.config_vars) - setattr(self, attr, val) - - def expand_basedirs(self): - """Calls `os.path.expanduser` on install_base, install_platbase and - root.""" - self._expand_attrs(['install_base', 'install_platbase', 'root']) - - def expand_dirs(self): - """Calls `os.path.expanduser` on install dirs.""" - dirs = [ - 'install_purelib', - 'install_platlib', - 'install_lib', - 'install_headers', - 'install_scripts', - 'install_data', - ] - self._expand_attrs(dirs) - - def run(self, show_deprecation=True): - if show_deprecation: - self.announce( - "WARNING: The easy_install command is deprecated " - "and will be removed in a future version." - , log.WARN, - ) - if self.verbose != self.distribution.verbose: - log.set_verbosity(self.verbose) - try: - for spec in self.args: - self.easy_install(spec, not self.no_deps) - if self.record: - outputs = list(sorted(self.outputs)) - if self.root: # strip any package prefix - root_len = len(self.root) - for counter in range(len(outputs)): - outputs[counter] = outputs[counter][root_len:] - from distutils import file_util - - self.execute( - file_util.write_file, (self.record, outputs), - "writing list of installed files to '%s'" % - self.record - ) - self.warn_deprecated_options() - finally: - log.set_verbosity(self.distribution.verbose) - - def pseudo_tempname(self): - """Return a pseudo-tempname base in the install directory. - This code is intentionally naive; if a malicious party can write to - the target directory you're already in deep doodoo. - """ - try: - pid = os.getpid() - except Exception: - pid = random.randint(0, sys.maxsize) - return os.path.join(self.install_dir, "test-easy-install-%s" % pid) - - def warn_deprecated_options(self): - pass - - def check_site_dir(self): - """Verify that self.install_dir is .pth-capable dir, if needed""" - - instdir = normalize_path(self.install_dir) - pth_file = os.path.join(instdir, 'easy-install.pth') - - # Is it a configured, PYTHONPATH, implicit, or explicit site dir? - is_site_dir = instdir in self.all_site_dirs - - if not is_site_dir and not self.multi_version: - # No? Then directly test whether it does .pth file processing - is_site_dir = self.check_pth_processing() - else: - # make sure we can write to target dir - testfile = self.pseudo_tempname() + '.write-test' - test_exists = os.path.exists(testfile) - try: - if test_exists: - os.unlink(testfile) - open(testfile, 'w').close() - os.unlink(testfile) - except (OSError, IOError): - self.cant_write_to_target() - - if not is_site_dir and not self.multi_version: - # Can't install non-multi to non-site dir - raise DistutilsError(self.no_default_version_msg()) - - if is_site_dir: - if self.pth_file is None: - self.pth_file = PthDistributions(pth_file, self.all_site_dirs) - else: - self.pth_file = None - - if instdir not in map(normalize_path, _pythonpath()): - # only PYTHONPATH dirs need a site.py, so pretend it's there - self.sitepy_installed = True - elif self.multi_version and not os.path.exists(pth_file): - self.sitepy_installed = True # don't need site.py in this case - self.pth_file = None # and don't create a .pth file - self.install_dir = instdir - - __cant_write_msg = textwrap.dedent(""" - can't create or remove files in install directory - - The following error occurred while trying to add or remove files in the - installation directory: - - %s - - The installation directory you specified (via --install-dir, --prefix, or - the distutils default setting) was: - - %s - """).lstrip() - - __not_exists_id = textwrap.dedent(""" - This directory does not currently exist. Please create it and try again, or - choose a different installation directory (using the -d or --install-dir - option). - """).lstrip() - - __access_msg = textwrap.dedent(""" - Perhaps your account does not have write access to this directory? If the - installation directory is a system-owned directory, you may need to sign in - as the administrator or "root" account. If you do not have administrative - access to this machine, you may wish to choose a different installation - directory, preferably one that is listed in your PYTHONPATH environment - variable. - - For information on other options, you may wish to consult the - documentation at: - - https://setuptools.readthedocs.io/en/latest/easy_install.html - - Please make the appropriate changes for your system and try again. - """).lstrip() - - def cant_write_to_target(self): - msg = self.__cant_write_msg % (sys.exc_info()[1], self.install_dir,) - - if not os.path.exists(self.install_dir): - msg += '\n' + self.__not_exists_id - else: - msg += '\n' + self.__access_msg - raise DistutilsError(msg) - - def check_pth_processing(self): - """Empirically verify whether .pth files are supported in inst. dir""" - instdir = self.install_dir - log.info("Checking .pth file support in %s", instdir) - pth_file = self.pseudo_tempname() + ".pth" - ok_file = pth_file + '.ok' - ok_exists = os.path.exists(ok_file) - tmpl = _one_liner(""" - import os - f = open({ok_file!r}, 'w') - f.write('OK') - f.close() - """) + '\n' - try: - if ok_exists: - os.unlink(ok_file) - dirname = os.path.dirname(ok_file) - pkg_resources.py31compat.makedirs(dirname, exist_ok=True) - f = open(pth_file, 'w') - except (OSError, IOError): - self.cant_write_to_target() - else: - try: - f.write(tmpl.format(**locals())) - f.close() - f = None - executable = sys.executable - if os.name == 'nt': - dirname, basename = os.path.split(executable) - alt = os.path.join(dirname, 'pythonw.exe') - use_alt = ( - basename.lower() == 'python.exe' and - os.path.exists(alt) - ) - if use_alt: - # use pythonw.exe to avoid opening a console window - executable = alt - - from distutils.spawn import spawn - - spawn([executable, '-E', '-c', 'pass'], 0) - - if os.path.exists(ok_file): - log.info( - "TEST PASSED: %s appears to support .pth files", - instdir - ) - return True - finally: - if f: - f.close() - if os.path.exists(ok_file): - os.unlink(ok_file) - if os.path.exists(pth_file): - os.unlink(pth_file) - if not self.multi_version: - log.warn("TEST FAILED: %s does NOT support .pth files", instdir) - return False - - def install_egg_scripts(self, dist): - """Write all the scripts for `dist`, unless scripts are excluded""" - if not self.exclude_scripts and dist.metadata_isdir('scripts'): - for script_name in dist.metadata_listdir('scripts'): - if dist.metadata_isdir('scripts/' + script_name): - # The "script" is a directory, likely a Python 3 - # __pycache__ directory, so skip it. - continue - self.install_script( - dist, script_name, - dist.get_metadata('scripts/' + script_name) - ) - self.install_wrapper_scripts(dist) - - def add_output(self, path): - if os.path.isdir(path): - for base, dirs, files in os.walk(path): - for filename in files: - self.outputs.append(os.path.join(base, filename)) - else: - self.outputs.append(path) - - def not_editable(self, spec): - if self.editable: - raise DistutilsArgError( - "Invalid argument %r: you can't use filenames or URLs " - "with --editable (except via the --find-links option)." - % (spec,) - ) - - def check_editable(self, spec): - if not self.editable: - return - - if os.path.exists(os.path.join(self.build_directory, spec.key)): - raise DistutilsArgError( - "%r already exists in %s; can't do a checkout there" % - (spec.key, self.build_directory) - ) - - @contextlib.contextmanager - def _tmpdir(self): - tmpdir = tempfile.mkdtemp(prefix=u"easy_install-") - try: - # cast to str as workaround for #709 and #710 and #712 - yield str(tmpdir) - finally: - os.path.exists(tmpdir) and rmtree(rmtree_safe(tmpdir)) - - def easy_install(self, spec, deps=False): - if not self.editable: - self.install_site_py() - - with self._tmpdir() as tmpdir: - if not isinstance(spec, Requirement): - if URL_SCHEME(spec): - # It's a url, download it to tmpdir and process - self.not_editable(spec) - dl = self.package_index.download(spec, tmpdir) - return self.install_item(None, dl, tmpdir, deps, True) - - elif os.path.exists(spec): - # Existing file or directory, just process it directly - self.not_editable(spec) - return self.install_item(None, spec, tmpdir, deps, True) - else: - spec = parse_requirement_arg(spec) - - self.check_editable(spec) - dist = self.package_index.fetch_distribution( - spec, tmpdir, self.upgrade, self.editable, - not self.always_copy, self.local_index - ) - if dist is None: - msg = "Could not find suitable distribution for %r" % spec - if self.always_copy: - msg += " (--always-copy skips system and development eggs)" - raise DistutilsError(msg) - elif dist.precedence == DEVELOP_DIST: - # .egg-info dists don't need installing, just process deps - self.process_distribution(spec, dist, deps, "Using") - return dist - else: - return self.install_item(spec, dist.location, tmpdir, deps) - - def install_item(self, spec, download, tmpdir, deps, install_needed=False): - - # Installation is also needed if file in tmpdir or is not an egg - install_needed = install_needed or self.always_copy - install_needed = install_needed or os.path.dirname(download) == tmpdir - install_needed = install_needed or not download.endswith('.egg') - install_needed = install_needed or ( - self.always_copy_from is not None and - os.path.dirname(normalize_path(download)) == - normalize_path(self.always_copy_from) - ) - - if spec and not install_needed: - # at this point, we know it's a local .egg, we just don't know if - # it's already installed. - for dist in self.local_index[spec.project_name]: - if dist.location == download: - break - else: - install_needed = True # it's not in the local index - - log.info("Processing %s", os.path.basename(download)) - - if install_needed: - dists = self.install_eggs(spec, download, tmpdir) - for dist in dists: - self.process_distribution(spec, dist, deps) - else: - dists = [self.egg_distribution(download)] - self.process_distribution(spec, dists[0], deps, "Using") - - if spec is not None: - for dist in dists: - if dist in spec: - return dist - - def select_scheme(self, name): - """Sets the install directories by applying the install schemes.""" - # it's the caller's problem if they supply a bad name! - scheme = INSTALL_SCHEMES[name] - for key in SCHEME_KEYS: - attrname = 'install_' + key - if getattr(self, attrname) is None: - setattr(self, attrname, scheme[key]) - - def process_distribution(self, requirement, dist, deps=True, *info): - self.update_pth(dist) - self.package_index.add(dist) - if dist in self.local_index[dist.key]: - self.local_index.remove(dist) - self.local_index.add(dist) - self.install_egg_scripts(dist) - self.installed_projects[dist.key] = dist - log.info(self.installation_report(requirement, dist, *info)) - if (dist.has_metadata('dependency_links.txt') and - not self.no_find_links): - self.package_index.add_find_links( - dist.get_metadata_lines('dependency_links.txt') - ) - if not deps and not self.always_copy: - return - elif requirement is not None and dist.key != requirement.key: - log.warn("Skipping dependencies for %s", dist) - return # XXX this is not the distribution we were looking for - elif requirement is None or dist not in requirement: - # if we wound up with a different version, resolve what we've got - distreq = dist.as_requirement() - requirement = Requirement(str(distreq)) - log.info("Processing dependencies for %s", requirement) - try: - distros = WorkingSet([]).resolve( - [requirement], self.local_index, self.easy_install - ) - except DistributionNotFound as e: - raise DistutilsError(str(e)) - except VersionConflict as e: - raise DistutilsError(e.report()) - if self.always_copy or self.always_copy_from: - # Force all the relevant distros to be copied or activated - for dist in distros: - if dist.key not in self.installed_projects: - self.easy_install(dist.as_requirement()) - log.info("Finished processing dependencies for %s", requirement) - - def should_unzip(self, dist): - if self.zip_ok is not None: - return not self.zip_ok - if dist.has_metadata('not-zip-safe'): - return True - if not dist.has_metadata('zip-safe'): - return True - return False - - def maybe_move(self, spec, dist_filename, setup_base): - dst = os.path.join(self.build_directory, spec.key) - if os.path.exists(dst): - msg = ( - "%r already exists in %s; build directory %s will not be kept" - ) - log.warn(msg, spec.key, self.build_directory, setup_base) - return setup_base - if os.path.isdir(dist_filename): - setup_base = dist_filename - else: - if os.path.dirname(dist_filename) == setup_base: - os.unlink(dist_filename) # get it out of the tmp dir - contents = os.listdir(setup_base) - if len(contents) == 1: - dist_filename = os.path.join(setup_base, contents[0]) - if os.path.isdir(dist_filename): - # if the only thing there is a directory, move it instead - setup_base = dist_filename - ensure_directory(dst) - shutil.move(setup_base, dst) - return dst - - def install_wrapper_scripts(self, dist): - if self.exclude_scripts: - return - for args in ScriptWriter.best().get_args(dist): - self.write_script(*args) - - def install_script(self, dist, script_name, script_text, dev_path=None): - """Generate a legacy script wrapper and install it""" - spec = str(dist.as_requirement()) - is_script = is_python_script(script_text, script_name) - - if is_script: - body = self._load_template(dev_path) % locals() - script_text = ScriptWriter.get_header(script_text) + body - self.write_script(script_name, _to_bytes(script_text), 'b') - - @staticmethod - def _load_template(dev_path): - """ - There are a couple of template scripts in the package. This - function loads one of them and prepares it for use. - """ - # See https://github.com/pypa/setuptools/issues/134 for info - # on script file naming and downstream issues with SVR4 - name = 'script.tmpl' - if dev_path: - name = name.replace('.tmpl', ' (dev).tmpl') - - raw_bytes = resource_string('setuptools', name) - return raw_bytes.decode('utf-8') - - def write_script(self, script_name, contents, mode="t", blockers=()): - """Write an executable file to the scripts directory""" - self.delete_blockers( # clean up old .py/.pyw w/o a script - [os.path.join(self.script_dir, x) for x in blockers] - ) - log.info("Installing %s script to %s", script_name, self.script_dir) - target = os.path.join(self.script_dir, script_name) - self.add_output(target) - - if self.dry_run: - return - - mask = current_umask() - ensure_directory(target) - if os.path.exists(target): - os.unlink(target) - with open(target, "w" + mode) as f: - f.write(contents) - chmod(target, 0o777 - mask) - - def install_eggs(self, spec, dist_filename, tmpdir): - # .egg dirs or files are already built, so just return them - if dist_filename.lower().endswith('.egg'): - return [self.install_egg(dist_filename, tmpdir)] - elif dist_filename.lower().endswith('.exe'): - return [self.install_exe(dist_filename, tmpdir)] - elif dist_filename.lower().endswith('.whl'): - return [self.install_wheel(dist_filename, tmpdir)] - - # Anything else, try to extract and build - setup_base = tmpdir - if os.path.isfile(dist_filename) and not dist_filename.endswith('.py'): - unpack_archive(dist_filename, tmpdir, self.unpack_progress) - elif os.path.isdir(dist_filename): - setup_base = os.path.abspath(dist_filename) - - if (setup_base.startswith(tmpdir) # something we downloaded - and self.build_directory and spec is not None): - setup_base = self.maybe_move(spec, dist_filename, setup_base) - - # Find the setup.py file - setup_script = os.path.join(setup_base, 'setup.py') - - if not os.path.exists(setup_script): - setups = glob(os.path.join(setup_base, '*', 'setup.py')) - if not setups: - raise DistutilsError( - "Couldn't find a setup script in %s" % - os.path.abspath(dist_filename) - ) - if len(setups) > 1: - raise DistutilsError( - "Multiple setup scripts in %s" % - os.path.abspath(dist_filename) - ) - setup_script = setups[0] - - # Now run it, and return the result - if self.editable: - log.info(self.report_editable(spec, setup_script)) - return [] - else: - return self.build_and_install(setup_script, setup_base) - - def egg_distribution(self, egg_path): - if os.path.isdir(egg_path): - metadata = PathMetadata(egg_path, os.path.join(egg_path, - 'EGG-INFO')) - else: - metadata = EggMetadata(zipimport.zipimporter(egg_path)) - return Distribution.from_filename(egg_path, metadata=metadata) - - def install_egg(self, egg_path, tmpdir): - destination = os.path.join( - self.install_dir, - os.path.basename(egg_path), - ) - destination = os.path.abspath(destination) - if not self.dry_run: - ensure_directory(destination) - - dist = self.egg_distribution(egg_path) - if not samefile(egg_path, destination): - if os.path.isdir(destination) and not os.path.islink(destination): - dir_util.remove_tree(destination, dry_run=self.dry_run) - elif os.path.exists(destination): - self.execute( - os.unlink, - (destination,), - "Removing " + destination, - ) - try: - new_dist_is_zipped = False - if os.path.isdir(egg_path): - if egg_path.startswith(tmpdir): - f, m = shutil.move, "Moving" - else: - f, m = shutil.copytree, "Copying" - elif self.should_unzip(dist): - self.mkpath(destination) - f, m = self.unpack_and_compile, "Extracting" - else: - new_dist_is_zipped = True - if egg_path.startswith(tmpdir): - f, m = shutil.move, "Moving" - else: - f, m = shutil.copy2, "Copying" - self.execute( - f, - (egg_path, destination), - (m + " %s to %s") % ( - os.path.basename(egg_path), - os.path.dirname(destination) - ), - ) - update_dist_caches( - destination, - fix_zipimporter_caches=new_dist_is_zipped, - ) - except Exception: - update_dist_caches(destination, fix_zipimporter_caches=False) - raise - - self.add_output(destination) - return self.egg_distribution(destination) - - def install_exe(self, dist_filename, tmpdir): - # See if it's valid, get data - cfg = extract_wininst_cfg(dist_filename) - if cfg is None: - raise DistutilsError( - "%s is not a valid distutils Windows .exe" % dist_filename - ) - # Create a dummy distribution object until we build the real distro - dist = Distribution( - None, - project_name=cfg.get('metadata', 'name'), - version=cfg.get('metadata', 'version'), platform=get_platform(), - ) - - # Convert the .exe to an unpacked egg - egg_path = os.path.join(tmpdir, dist.egg_name() + '.egg') - dist.location = egg_path - egg_tmp = egg_path + '.tmp' - _egg_info = os.path.join(egg_tmp, 'EGG-INFO') - pkg_inf = os.path.join(_egg_info, 'PKG-INFO') - ensure_directory(pkg_inf) # make sure EGG-INFO dir exists - dist._provider = PathMetadata(egg_tmp, _egg_info) # XXX - self.exe_to_egg(dist_filename, egg_tmp) - - # Write EGG-INFO/PKG-INFO - if not os.path.exists(pkg_inf): - f = open(pkg_inf, 'w') - f.write('Metadata-Version: 1.0\n') - for k, v in cfg.items('metadata'): - if k != 'target_version': - f.write('%s: %s\n' % (k.replace('_', '-').title(), v)) - f.close() - script_dir = os.path.join(_egg_info, 'scripts') - # delete entry-point scripts to avoid duping - self.delete_blockers([ - os.path.join(script_dir, args[0]) - for args in ScriptWriter.get_args(dist) - ]) - # Build .egg file from tmpdir - bdist_egg.make_zipfile( - egg_path, egg_tmp, verbose=self.verbose, dry_run=self.dry_run, - ) - # install the .egg - return self.install_egg(egg_path, tmpdir) - - def exe_to_egg(self, dist_filename, egg_tmp): - """Extract a bdist_wininst to the directories an egg would use""" - # Check for .pth file and set up prefix translations - prefixes = get_exe_prefixes(dist_filename) - to_compile = [] - native_libs = [] - top_level = {} - - def process(src, dst): - s = src.lower() - for old, new in prefixes: - if s.startswith(old): - src = new + src[len(old):] - parts = src.split('/') - dst = os.path.join(egg_tmp, *parts) - dl = dst.lower() - if dl.endswith('.pyd') or dl.endswith('.dll'): - parts[-1] = bdist_egg.strip_module(parts[-1]) - top_level[os.path.splitext(parts[0])[0]] = 1 - native_libs.append(src) - elif dl.endswith('.py') and old != 'SCRIPTS/': - top_level[os.path.splitext(parts[0])[0]] = 1 - to_compile.append(dst) - return dst - if not src.endswith('.pth'): - log.warn("WARNING: can't process %s", src) - return None - - # extract, tracking .pyd/.dll->native_libs and .py -> to_compile - unpack_archive(dist_filename, egg_tmp, process) - stubs = [] - for res in native_libs: - if res.lower().endswith('.pyd'): # create stubs for .pyd's - parts = res.split('/') - resource = parts[-1] - parts[-1] = bdist_egg.strip_module(parts[-1]) + '.py' - pyfile = os.path.join(egg_tmp, *parts) - to_compile.append(pyfile) - stubs.append(pyfile) - bdist_egg.write_stub(resource, pyfile) - self.byte_compile(to_compile) # compile .py's - bdist_egg.write_safety_flag( - os.path.join(egg_tmp, 'EGG-INFO'), - bdist_egg.analyze_egg(egg_tmp, stubs)) # write zip-safety flag - - for name in 'top_level', 'native_libs': - if locals()[name]: - txt = os.path.join(egg_tmp, 'EGG-INFO', name + '.txt') - if not os.path.exists(txt): - f = open(txt, 'w') - f.write('\n'.join(locals()[name]) + '\n') - f.close() - - def install_wheel(self, wheel_path, tmpdir): - wheel = Wheel(wheel_path) - assert wheel.is_compatible() - destination = os.path.join(self.install_dir, wheel.egg_name()) - destination = os.path.abspath(destination) - if not self.dry_run: - ensure_directory(destination) - if os.path.isdir(destination) and not os.path.islink(destination): - dir_util.remove_tree(destination, dry_run=self.dry_run) - elif os.path.exists(destination): - self.execute( - os.unlink, - (destination,), - "Removing " + destination, - ) - try: - self.execute( - wheel.install_as_egg, - (destination,), - ("Installing %s to %s") % ( - os.path.basename(wheel_path), - os.path.dirname(destination) - ), - ) - finally: - update_dist_caches(destination, fix_zipimporter_caches=False) - self.add_output(destination) - return self.egg_distribution(destination) - - __mv_warning = textwrap.dedent(""" - Because this distribution was installed --multi-version, before you can - import modules from this package in an application, you will need to - 'import pkg_resources' and then use a 'require()' call similar to one of - these examples, in order to select the desired version: - - pkg_resources.require("%(name)s") # latest installed version - pkg_resources.require("%(name)s==%(version)s") # this exact version - pkg_resources.require("%(name)s>=%(version)s") # this version or higher - """).lstrip() - - __id_warning = textwrap.dedent(""" - Note also that the installation directory must be on sys.path at runtime for - this to work. (e.g. by being the application's script directory, by being on - PYTHONPATH, or by being added to sys.path by your code.) - """) - - def installation_report(self, req, dist, what="Installed"): - """Helpful installation message for display to package users""" - msg = "\n%(what)s %(eggloc)s%(extras)s" - if self.multi_version and not self.no_report: - msg += '\n' + self.__mv_warning - if self.install_dir not in map(normalize_path, sys.path): - msg += '\n' + self.__id_warning - - eggloc = dist.location - name = dist.project_name - version = dist.version - extras = '' # TODO: self.report_extras(req, dist) - return msg % locals() - - __editable_msg = textwrap.dedent(""" - Extracted editable version of %(spec)s to %(dirname)s - - If it uses setuptools in its setup script, you can activate it in - "development" mode by going to that directory and running:: - - %(python)s setup.py develop - - See the setuptools documentation for the "develop" command for more info. - """).lstrip() - - def report_editable(self, spec, setup_script): - dirname = os.path.dirname(setup_script) - python = sys.executable - return '\n' + self.__editable_msg % locals() - - def run_setup(self, setup_script, setup_base, args): - sys.modules.setdefault('distutils.command.bdist_egg', bdist_egg) - sys.modules.setdefault('distutils.command.egg_info', egg_info) - - args = list(args) - if self.verbose > 2: - v = 'v' * (self.verbose - 1) - args.insert(0, '-' + v) - elif self.verbose < 2: - args.insert(0, '-q') - if self.dry_run: - args.insert(0, '-n') - log.info( - "Running %s %s", setup_script[len(setup_base) + 1:], ' '.join(args) - ) - try: - run_setup(setup_script, args) - except SystemExit as v: - raise DistutilsError("Setup script exited with %s" % (v.args[0],)) - - def build_and_install(self, setup_script, setup_base): - args = ['bdist_egg', '--dist-dir'] - - dist_dir = tempfile.mkdtemp( - prefix='egg-dist-tmp-', dir=os.path.dirname(setup_script) - ) - try: - self._set_fetcher_options(os.path.dirname(setup_script)) - args.append(dist_dir) - - self.run_setup(setup_script, setup_base, args) - all_eggs = Environment([dist_dir]) - eggs = [] - for key in all_eggs: - for dist in all_eggs[key]: - eggs.append(self.install_egg(dist.location, setup_base)) - if not eggs and not self.dry_run: - log.warn("No eggs found in %s (setup script problem?)", - dist_dir) - return eggs - finally: - rmtree(dist_dir) - log.set_verbosity(self.verbose) # restore our log verbosity - - def _set_fetcher_options(self, base): - """ - When easy_install is about to run bdist_egg on a source dist, that - source dist might have 'setup_requires' directives, requiring - additional fetching. Ensure the fetcher options given to easy_install - are available to that command as well. - """ - # find the fetch options from easy_install and write them out - # to the setup.cfg file. - ei_opts = self.distribution.get_option_dict('easy_install').copy() - fetch_directives = ( - 'find_links', 'site_dirs', 'index_url', 'optimize', 'allow_hosts', - ) - fetch_options = {} - for key, val in ei_opts.items(): - if key not in fetch_directives: - continue - fetch_options[key.replace('_', '-')] = val[1] - # create a settings dictionary suitable for `edit_config` - settings = dict(easy_install=fetch_options) - cfg_filename = os.path.join(base, 'setup.cfg') - setopt.edit_config(cfg_filename, settings) - - def update_pth(self, dist): - if self.pth_file is None: - return - - for d in self.pth_file[dist.key]: # drop old entries - if self.multi_version or d.location != dist.location: - log.info("Removing %s from easy-install.pth file", d) - self.pth_file.remove(d) - if d.location in self.shadow_path: - self.shadow_path.remove(d.location) - - if not self.multi_version: - if dist.location in self.pth_file.paths: - log.info( - "%s is already the active version in easy-install.pth", - dist, - ) - else: - log.info("Adding %s to easy-install.pth file", dist) - self.pth_file.add(dist) # add new entry - if dist.location not in self.shadow_path: - self.shadow_path.append(dist.location) - - if not self.dry_run: - - self.pth_file.save() - - if dist.key == 'setuptools': - # Ensure that setuptools itself never becomes unavailable! - # XXX should this check for latest version? - filename = os.path.join(self.install_dir, 'setuptools.pth') - if os.path.islink(filename): - os.unlink(filename) - f = open(filename, 'wt') - f.write(self.pth_file.make_relative(dist.location) + '\n') - f.close() - - def unpack_progress(self, src, dst): - # Progress filter for unpacking - log.debug("Unpacking %s to %s", src, dst) - return dst # only unpack-and-compile skips files for dry run - - def unpack_and_compile(self, egg_path, destination): - to_compile = [] - to_chmod = [] - - def pf(src, dst): - if dst.endswith('.py') and not src.startswith('EGG-INFO/'): - to_compile.append(dst) - elif dst.endswith('.dll') or dst.endswith('.so'): - to_chmod.append(dst) - self.unpack_progress(src, dst) - return not self.dry_run and dst or None - - unpack_archive(egg_path, destination, pf) - self.byte_compile(to_compile) - if not self.dry_run: - for f in to_chmod: - mode = ((os.stat(f)[stat.ST_MODE]) | 0o555) & 0o7755 - chmod(f, mode) - - def byte_compile(self, to_compile): - if sys.dont_write_bytecode: - return - - from distutils.util import byte_compile - - try: - # try to make the byte compile messages quieter - log.set_verbosity(self.verbose - 1) - - byte_compile(to_compile, optimize=0, force=1, dry_run=self.dry_run) - if self.optimize: - byte_compile( - to_compile, optimize=self.optimize, force=1, - dry_run=self.dry_run, - ) - finally: - log.set_verbosity(self.verbose) # restore original verbosity - - __no_default_msg = textwrap.dedent(""" - bad install directory or PYTHONPATH - - You are attempting to install a package to a directory that is not - on PYTHONPATH and which Python does not read ".pth" files from. The - installation directory you specified (via --install-dir, --prefix, or - the distutils default setting) was: - - %s - - and your PYTHONPATH environment variable currently contains: - - %r - - Here are some of your options for correcting the problem: - - * You can choose a different installation directory, i.e., one that is - on PYTHONPATH or supports .pth files - - * You can add the installation directory to the PYTHONPATH environment - variable. (It must then also be on PYTHONPATH whenever you run - Python and want to use the package(s) you are installing.) - - * You can set up the installation directory to support ".pth" files by - using one of the approaches described here: - - https://setuptools.readthedocs.io/en/latest/easy_install.html#custom-installation-locations - - - Please make the appropriate changes for your system and try again.""").lstrip() - - def no_default_version_msg(self): - template = self.__no_default_msg - return template % (self.install_dir, os.environ.get('PYTHONPATH', '')) - - def install_site_py(self): - """Make sure there's a site.py in the target dir, if needed""" - - if self.sitepy_installed: - return # already did it, or don't need to - - sitepy = os.path.join(self.install_dir, "site.py") - source = resource_string("setuptools", "site-patch.py") - source = source.decode('utf-8') - current = "" - - if os.path.exists(sitepy): - log.debug("Checking existing site.py in %s", self.install_dir) - with io.open(sitepy) as strm: - current = strm.read() - - if not current.startswith('def __boot():'): - raise DistutilsError( - "%s is not a setuptools-generated site.py; please" - " remove it." % sitepy - ) - - if current != source: - log.info("Creating %s", sitepy) - if not self.dry_run: - ensure_directory(sitepy) - with io.open(sitepy, 'w', encoding='utf-8') as strm: - strm.write(source) - self.byte_compile([sitepy]) - - self.sitepy_installed = True - - def create_home_path(self): - """Create directories under ~.""" - if not self.user: - return - home = convert_path(os.path.expanduser("~")) - for name, path in six.iteritems(self.config_vars): - if path.startswith(home) and not os.path.isdir(path): - self.debug_print("os.makedirs('%s', 0o700)" % path) - os.makedirs(path, 0o700) - - if sys.version[:3] in ('2.3', '2.4', '2.5') or 'real_prefix' in sys.__dict__: - sitedir_name = 'site-packages' - else: - sitedir_name = 'dist-packages' - - INSTALL_SCHEMES = dict( - posix=dict( - install_dir='$base/lib/python$py_version_short/site-packages', - script_dir='$base/bin', - ), - unix_local = dict( - install_dir = '$base/local/lib/python$py_version_short/%s' % sitedir_name, - script_dir = '$base/local/bin', - ), - posix_local = dict( - install_dir = '$base/local/lib/python$py_version_short/%s' % sitedir_name, - script_dir = '$base/local/bin', - ), - deb_system = dict( - install_dir = '$base/lib/python3/%s' % sitedir_name, - script_dir = '$base/bin', - ), - ) - - DEFAULT_SCHEME = dict( - install_dir='$base/Lib/site-packages', - script_dir='$base/Scripts', - ) - - def _expand(self, *attrs): - config_vars = self.get_finalized_command('install').config_vars - - if self.prefix or self.install_layout: - if self.install_layout and self.install_layout in ['deb']: - scheme_name = "deb_system" - self.prefix = '/usr' - elif self.prefix or 'real_prefix' in sys.__dict__: - scheme_name = os.name - else: - scheme_name = "posix_local" - # Set default install_dir/scripts from --prefix - config_vars = config_vars.copy() - config_vars['base'] = self.prefix - scheme = self.INSTALL_SCHEMES.get(scheme_name,self.DEFAULT_SCHEME) - for attr, val in scheme.items(): - if getattr(self, attr, None) is None: - setattr(self, attr, val) - - from distutils.util import subst_vars - - for attr in attrs: - val = getattr(self, attr) - if val is not None: - val = subst_vars(val, config_vars) - if os.name == 'posix': - val = os.path.expanduser(val) - setattr(self, attr, val) - - -def _pythonpath(): - items = os.environ.get('PYTHONPATH', '').split(os.pathsep) - return filter(None, items) - - -def get_site_dirs(): - """ - Return a list of 'site' dirs - """ - - sitedirs = [] - - # start with PYTHONPATH - sitedirs.extend(_pythonpath()) - - prefixes = [sys.prefix] - if sys.exec_prefix != sys.prefix: - prefixes.append(sys.exec_prefix) - for prefix in prefixes: - if prefix: - if sys.platform in ('os2emx', 'riscos'): - sitedirs.append(os.path.join(prefix, "Lib", "site-packages")) - elif os.sep == '/': - sitedirs.extend([ - os.path.join( - prefix, - "local/lib", - "python" + sys.version[:3], - "dist-packages", - ), - os.path.join( - prefix, - "lib", - "python{}.{}".format(*sys.version_info), - "dist-packages", - ), - os.path.join(prefix, "lib", "site-python"), - ]) - else: - sitedirs.extend([ - prefix, - os.path.join(prefix, "lib", "site-packages"), - ]) - if sys.platform == 'darwin': - # for framework builds *only* we add the standard Apple - # locations. Currently only per-user, but /Library and - # /Network/Library could be added too - if 'Python.framework' in prefix: - home = os.environ.get('HOME') - if home: - home_sp = os.path.join( - home, - 'Library', - 'Python', - '{}.{}'.format(*sys.version_info), - 'site-packages', - ) - sitedirs.append(home_sp) - lib_paths = get_path('purelib'), get_path('platlib') - for site_lib in lib_paths: - if site_lib not in sitedirs: - sitedirs.append(site_lib) - - if site.ENABLE_USER_SITE: - sitedirs.append(site.USER_SITE) - - try: - sitedirs.extend(site.getsitepackages()) - except AttributeError: - pass - - sitedirs = list(map(normalize_path, sitedirs)) - - return sitedirs - - -def expand_paths(inputs): - """Yield sys.path directories that might contain "old-style" packages""" - - seen = {} - - for dirname in inputs: - dirname = normalize_path(dirname) - if dirname in seen: - continue - - seen[dirname] = 1 - if not os.path.isdir(dirname): - continue - - files = os.listdir(dirname) - yield dirname, files - - for name in files: - if not name.endswith('.pth'): - # We only care about the .pth files - continue - if name in ('easy-install.pth', 'setuptools.pth'): - # Ignore .pth files that we control - continue - - # Read the .pth file - f = open(os.path.join(dirname, name)) - lines = list(yield_lines(f)) - f.close() - - # Yield existing non-dupe, non-import directory lines from it - for line in lines: - if not line.startswith("import"): - line = normalize_path(line.rstrip()) - if line not in seen: - seen[line] = 1 - if not os.path.isdir(line): - continue - yield line, os.listdir(line) - - -def extract_wininst_cfg(dist_filename): - """Extract configuration data from a bdist_wininst .exe - - Returns a configparser.RawConfigParser, or None - """ - f = open(dist_filename, 'rb') - try: - endrec = zipfile._EndRecData(f) - if endrec is None: - return None - - prepended = (endrec[9] - endrec[5]) - endrec[6] - if prepended < 12: # no wininst data here - return None - f.seek(prepended - 12) - - tag, cfglen, bmlen = struct.unpack("<iii", f.read(12)) - if tag not in (0x1234567A, 0x1234567B): - return None # not a valid tag - - f.seek(prepended - (12 + cfglen)) - init = {'version': '', 'target_version': ''} - cfg = configparser.RawConfigParser(init) - try: - part = f.read(cfglen) - # Read up to the first null byte. - config = part.split(b'\0', 1)[0] - # Now the config is in bytes, but for RawConfigParser, it should - # be text, so decode it. - config = config.decode(sys.getfilesystemencoding()) - cfg.readfp(six.StringIO(config)) - except configparser.Error: - return None - if not cfg.has_section('metadata') or not cfg.has_section('Setup'): - return None - return cfg - - finally: - f.close() - - -def get_exe_prefixes(exe_filename): - """Get exe->egg path translations for a given .exe file""" - - prefixes = [ - ('PURELIB/', ''), - ('PLATLIB/pywin32_system32', ''), - ('PLATLIB/', ''), - ('SCRIPTS/', 'EGG-INFO/scripts/'), - ('DATA/lib/site-packages', ''), - ] - z = zipfile.ZipFile(exe_filename) - try: - for info in z.infolist(): - name = info.filename - parts = name.split('/') - if len(parts) == 3 and parts[2] == 'PKG-INFO': - if parts[1].endswith('.egg-info'): - prefixes.insert(0, ('/'.join(parts[:2]), 'EGG-INFO/')) - break - if len(parts) != 2 or not name.endswith('.pth'): - continue - if name.endswith('-nspkg.pth'): - continue - if parts[0].upper() in ('PURELIB', 'PLATLIB'): - contents = z.read(name) - if six.PY3: - contents = contents.decode() - for pth in yield_lines(contents): - pth = pth.strip().replace('\\', '/') - if not pth.startswith('import'): - prefixes.append((('%s/%s/' % (parts[0], pth)), '')) - finally: - z.close() - prefixes = [(x.lower(), y) for x, y in prefixes] - prefixes.sort() - prefixes.reverse() - return prefixes - - -class PthDistributions(Environment): - """A .pth file with Distribution paths in it""" - - dirty = False - - def __init__(self, filename, sitedirs=()): - self.filename = filename - self.sitedirs = list(map(normalize_path, sitedirs)) - self.basedir = normalize_path(os.path.dirname(self.filename)) - self._load() - Environment.__init__(self, [], None, None) - for path in yield_lines(self.paths): - list(map(self.add, find_distributions(path, True))) - - def _load(self): - self.paths = [] - saw_import = False - seen = dict.fromkeys(self.sitedirs) - if os.path.isfile(self.filename): - f = open(self.filename, 'rt') - for line in f: - if line.startswith('import'): - saw_import = True - continue - path = line.rstrip() - self.paths.append(path) - if not path.strip() or path.strip().startswith('#'): - continue - # skip non-existent paths, in case somebody deleted a package - # manually, and duplicate paths as well - path = self.paths[-1] = normalize_path( - os.path.join(self.basedir, path) - ) - if not os.path.exists(path) or path in seen: - self.paths.pop() # skip it - self.dirty = True # we cleaned up, so we're dirty now :) - continue - seen[path] = 1 - f.close() - - if self.paths and not saw_import: - self.dirty = True # ensure anything we touch has import wrappers - while self.paths and not self.paths[-1].strip(): - self.paths.pop() - - def save(self): - """Write changed .pth file back to disk""" - if not self.dirty: - return - - rel_paths = list(map(self.make_relative, self.paths)) - if rel_paths: - log.debug("Saving %s", self.filename) - lines = self._wrap_lines(rel_paths) - data = '\n'.join(lines) + '\n' - - if os.path.islink(self.filename): - os.unlink(self.filename) - with open(self.filename, 'wt') as f: - f.write(data) - - elif os.path.exists(self.filename): - log.debug("Deleting empty %s", self.filename) - os.unlink(self.filename) - - self.dirty = False - - @staticmethod - def _wrap_lines(lines): - return lines - - def add(self, dist): - """Add `dist` to the distribution map""" - new_path = ( - dist.location not in self.paths and ( - dist.location not in self.sitedirs or - # account for '.' being in PYTHONPATH - dist.location == os.getcwd() - ) - ) - if new_path: - self.paths.append(dist.location) - self.dirty = True - Environment.add(self, dist) - - def remove(self, dist): - """Remove `dist` from the distribution map""" - while dist.location in self.paths: - self.paths.remove(dist.location) - self.dirty = True - Environment.remove(self, dist) - - def make_relative(self, path): - npath, last = os.path.split(normalize_path(path)) - baselen = len(self.basedir) - parts = [last] - sep = os.altsep == '/' and '/' or os.sep - while len(npath) >= baselen: - if npath == self.basedir: - parts.append(os.curdir) - parts.reverse() - return sep.join(parts) - npath, last = os.path.split(npath) - parts.append(last) - else: - return path - - -class RewritePthDistributions(PthDistributions): - @classmethod - def _wrap_lines(cls, lines): - yield cls.prelude - for line in lines: - yield line - yield cls.postlude - - prelude = _one_liner(""" - import sys - sys.__plen = len(sys.path) - """) - postlude = _one_liner(""" - import sys - new = sys.path[sys.__plen:] - del sys.path[sys.__plen:] - p = getattr(sys, '__egginsert', 0) - sys.path[p:p] = new - sys.__egginsert = p + len(new) - """) - - -if os.environ.get('SETUPTOOLS_SYS_PATH_TECHNIQUE', 'raw') == 'rewrite': - PthDistributions = RewritePthDistributions - - -def _first_line_re(): - """ - Return a regular expression based on first_line_re suitable for matching - strings. - """ - if isinstance(first_line_re.pattern, str): - return first_line_re - - # first_line_re in Python >=3.1.4 and >=3.2.1 is a bytes pattern. - return re.compile(first_line_re.pattern.decode()) - - -def auto_chmod(func, arg, exc): - if func in [os.unlink, os.remove] and os.name == 'nt': - chmod(arg, stat.S_IWRITE) - return func(arg) - et, ev, _ = sys.exc_info() - six.reraise(et, (ev[0], ev[1] + (" %s %s" % (func, arg)))) - - -def update_dist_caches(dist_path, fix_zipimporter_caches): - """ - Fix any globally cached `dist_path` related data - - `dist_path` should be a path of a newly installed egg distribution (zipped - or unzipped). - - sys.path_importer_cache contains finder objects that have been cached when - importing data from the original distribution. Any such finders need to be - cleared since the replacement distribution might be packaged differently, - e.g. a zipped egg distribution might get replaced with an unzipped egg - folder or vice versa. Having the old finders cached may then cause Python - to attempt loading modules from the replacement distribution using an - incorrect loader. - - zipimport.zipimporter objects are Python loaders charged with importing - data packaged inside zip archives. If stale loaders referencing the - original distribution, are left behind, they can fail to load modules from - the replacement distribution. E.g. if an old zipimport.zipimporter instance - is used to load data from a new zipped egg archive, it may cause the - operation to attempt to locate the requested data in the wrong location - - one indicated by the original distribution's zip archive directory - information. Such an operation may then fail outright, e.g. report having - read a 'bad local file header', or even worse, it may fail silently & - return invalid data. - - zipimport._zip_directory_cache contains cached zip archive directory - information for all existing zipimport.zipimporter instances and all such - instances connected to the same archive share the same cached directory - information. - - If asked, and the underlying Python implementation allows it, we can fix - all existing zipimport.zipimporter instances instead of having to track - them down and remove them one by one, by updating their shared cached zip - archive directory information. This, of course, assumes that the - replacement distribution is packaged as a zipped egg. - - If not asked to fix existing zipimport.zipimporter instances, we still do - our best to clear any remaining zipimport.zipimporter related cached data - that might somehow later get used when attempting to load data from the new - distribution and thus cause such load operations to fail. Note that when - tracking down such remaining stale data, we can not catch every conceivable - usage from here, and we clear only those that we know of and have found to - cause problems if left alive. Any remaining caches should be updated by - whomever is in charge of maintaining them, i.e. they should be ready to - handle us replacing their zip archives with new distributions at runtime. - - """ - # There are several other known sources of stale zipimport.zipimporter - # instances that we do not clear here, but might if ever given a reason to - # do so: - # * Global setuptools pkg_resources.working_set (a.k.a. 'master working - # set') may contain distributions which may in turn contain their - # zipimport.zipimporter loaders. - # * Several zipimport.zipimporter loaders held by local variables further - # up the function call stack when running the setuptools installation. - # * Already loaded modules may have their __loader__ attribute set to the - # exact loader instance used when importing them. Python 3.4 docs state - # that this information is intended mostly for introspection and so is - # not expected to cause us problems. - normalized_path = normalize_path(dist_path) - _uncache(normalized_path, sys.path_importer_cache) - if fix_zipimporter_caches: - _replace_zip_directory_cache_data(normalized_path) - else: - # Here, even though we do not want to fix existing and now stale - # zipimporter cache information, we still want to remove it. Related to - # Python's zip archive directory information cache, we clear each of - # its stale entries in two phases: - # 1. Clear the entry so attempting to access zip archive information - # via any existing stale zipimport.zipimporter instances fails. - # 2. Remove the entry from the cache so any newly constructed - # zipimport.zipimporter instances do not end up using old stale - # zip archive directory information. - # This whole stale data removal step does not seem strictly necessary, - # but has been left in because it was done before we started replacing - # the zip archive directory information cache content if possible, and - # there are no relevant unit tests that we can depend on to tell us if - # this is really needed. - _remove_and_clear_zip_directory_cache_data(normalized_path) - - -def _collect_zipimporter_cache_entries(normalized_path, cache): - """ - Return zipimporter cache entry keys related to a given normalized path. - - Alternative path spellings (e.g. those using different character case or - those using alternative path separators) related to the same path are - included. Any sub-path entries are included as well, i.e. those - corresponding to zip archives embedded in other zip archives. - - """ - result = [] - prefix_len = len(normalized_path) - for p in cache: - np = normalize_path(p) - if (np.startswith(normalized_path) and - np[prefix_len:prefix_len + 1] in (os.sep, '')): - result.append(p) - return result - - -def _update_zipimporter_cache(normalized_path, cache, updater=None): - """ - Update zipimporter cache data for a given normalized path. - - Any sub-path entries are processed as well, i.e. those corresponding to zip - archives embedded in other zip archives. - - Given updater is a callable taking a cache entry key and the original entry - (after already removing the entry from the cache), and expected to update - the entry and possibly return a new one to be inserted in its place. - Returning None indicates that the entry should not be replaced with a new - one. If no updater is given, the cache entries are simply removed without - any additional processing, the same as if the updater simply returned None. - - """ - for p in _collect_zipimporter_cache_entries(normalized_path, cache): - # N.B. pypy's custom zipimport._zip_directory_cache implementation does - # not support the complete dict interface: - # * Does not support item assignment, thus not allowing this function - # to be used only for removing existing cache entries. - # * Does not support the dict.pop() method, forcing us to use the - # get/del patterns instead. For more detailed information see the - # following links: - # https://github.com/pypa/setuptools/issues/202#issuecomment-202913420 - # http://bit.ly/2h9itJX - old_entry = cache[p] - del cache[p] - new_entry = updater and updater(p, old_entry) - if new_entry is not None: - cache[p] = new_entry - - -def _uncache(normalized_path, cache): - _update_zipimporter_cache(normalized_path, cache) - - -def _remove_and_clear_zip_directory_cache_data(normalized_path): - def clear_and_remove_cached_zip_archive_directory_data(path, old_entry): - old_entry.clear() - - _update_zipimporter_cache( - normalized_path, zipimport._zip_directory_cache, - updater=clear_and_remove_cached_zip_archive_directory_data) - - -# PyPy Python implementation does not allow directly writing to the -# zipimport._zip_directory_cache and so prevents us from attempting to correct -# its content. The best we can do there is clear the problematic cache content -# and have PyPy repopulate it as needed. The downside is that if there are any -# stale zipimport.zipimporter instances laying around, attempting to use them -# will fail due to not having its zip archive directory information available -# instead of being automatically corrected to use the new correct zip archive -# directory information. -if '__pypy__' in sys.builtin_module_names: - _replace_zip_directory_cache_data = \ - _remove_and_clear_zip_directory_cache_data -else: - - def _replace_zip_directory_cache_data(normalized_path): - def replace_cached_zip_archive_directory_data(path, old_entry): - # N.B. In theory, we could load the zip directory information just - # once for all updated path spellings, and then copy it locally and - # update its contained path strings to contain the correct - # spelling, but that seems like a way too invasive move (this cache - # structure is not officially documented anywhere and could in - # theory change with new Python releases) for no significant - # benefit. - old_entry.clear() - zipimport.zipimporter(path) - old_entry.update(zipimport._zip_directory_cache[path]) - return old_entry - - _update_zipimporter_cache( - normalized_path, zipimport._zip_directory_cache, - updater=replace_cached_zip_archive_directory_data) - - -def is_python(text, filename='<string>'): - "Is this string a valid Python script?" - try: - compile(text, filename, 'exec') - except (SyntaxError, TypeError): - return False - else: - return True - - -def is_sh(executable): - """Determine if the specified executable is a .sh (contains a #! line)""" - try: - with io.open(executable, encoding='latin-1') as fp: - magic = fp.read(2) - except (OSError, IOError): - return executable - return magic == '#!' - - -def nt_quote_arg(arg): - """Quote a command line argument according to Windows parsing rules""" - return subprocess.list2cmdline([arg]) - - -def is_python_script(script_text, filename): - """Is this text, as a whole, a Python script? (as opposed to shell/bat/etc. - """ - if filename.endswith('.py') or filename.endswith('.pyw'): - return True # extension says it's Python - if is_python(script_text, filename): - return True # it's syntactically valid Python - if script_text.startswith('#!'): - # It begins with a '#!' line, so check if 'python' is in it somewhere - return 'python' in script_text.splitlines()[0].lower() - - return False # Not any Python I can recognize - - -try: - from os import chmod as _chmod -except ImportError: - # Jython compatibility - def _chmod(*args): - pass - - -def chmod(path, mode): - log.debug("changing mode of %s to %o", path, mode) - try: - _chmod(path, mode) - except os.error as e: - log.debug("chmod failed: %s", e) - - -class CommandSpec(list): - """ - A command spec for a #! header, specified as a list of arguments akin to - those passed to Popen. - """ - - options = [] - split_args = dict() - - @classmethod - def best(cls): - """ - Choose the best CommandSpec class based on environmental conditions. - """ - return cls - - @classmethod - def _sys_executable(cls): - _default = os.path.normpath(sys.executable) - return os.environ.get('__PYVENV_LAUNCHER__', _default) - - @classmethod - def from_param(cls, param): - """ - Construct a CommandSpec from a parameter to build_scripts, which may - be None. - """ - if isinstance(param, cls): - return param - if isinstance(param, list): - return cls(param) - if param is None: - return cls.from_environment() - # otherwise, assume it's a string. - return cls.from_string(param) - - @classmethod - def from_environment(cls): - return cls([cls._sys_executable()]) - - @classmethod - def from_string(cls, string): - """ - Construct a command spec from a simple string representing a command - line parseable by shlex.split. - """ - items = shlex.split(string, **cls.split_args) - return cls(items) - - def install_options(self, script_text): - self.options = shlex.split(self._extract_options(script_text)) - cmdline = subprocess.list2cmdline(self) - if not isascii(cmdline): - self.options[:0] = ['-x'] - - @staticmethod - def _extract_options(orig_script): - """ - Extract any options from the first line of the script. - """ - first = (orig_script + '\n').splitlines()[0] - match = _first_line_re().match(first) - options = match.group(1) or '' if match else '' - return options.strip() - - def as_header(self): - return self._render(self + list(self.options)) - - @staticmethod - def _strip_quotes(item): - _QUOTES = '"\'' - for q in _QUOTES: - if item.startswith(q) and item.endswith(q): - return item[1:-1] - return item - - @staticmethod - def _render(items): - cmdline = subprocess.list2cmdline( - CommandSpec._strip_quotes(item.strip()) for item in items) - return '#!' + cmdline + '\n' - - -# For pbr compat; will be removed in a future version. -sys_executable = CommandSpec._sys_executable() - - -class WindowsCommandSpec(CommandSpec): - split_args = dict(posix=False) - - -class ScriptWriter: - """ - Encapsulates behavior around writing entry point scripts for console and - gui apps. - """ - - template = textwrap.dedent(r""" - # EASY-INSTALL-ENTRY-SCRIPT: %(spec)r,%(group)r,%(name)r - __requires__ = %(spec)r - import re - import sys - from pkg_resources import load_entry_point - - if __name__ == '__main__': - sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) - sys.exit( - load_entry_point(%(spec)r, %(group)r, %(name)r)() - ) - """).lstrip() - - command_spec_class = CommandSpec - - @classmethod - def get_script_args(cls, dist, executable=None, wininst=False): - # for backward compatibility - warnings.warn("Use get_args", EasyInstallDeprecationWarning) - writer = (WindowsScriptWriter if wininst else ScriptWriter).best() - header = cls.get_script_header("", executable, wininst) - return writer.get_args(dist, header) - - @classmethod - def get_script_header(cls, script_text, executable=None, wininst=False): - # for backward compatibility - warnings.warn("Use get_header", EasyInstallDeprecationWarning, stacklevel=2) - if wininst: - executable = "python.exe" - return cls.get_header(script_text, executable) - - @classmethod - def get_args(cls, dist, header=None): - """ - Yield write_script() argument tuples for a distribution's - console_scripts and gui_scripts entry points. - """ - if header is None: - header = cls.get_header() - spec = str(dist.as_requirement()) - for type_ in 'console', 'gui': - group = type_ + '_scripts' - for name, ep in dist.get_entry_map(group).items(): - cls._ensure_safe_name(name) - script_text = cls.template % locals() - args = cls._get_script_args(type_, name, header, script_text) - for res in args: - yield res - - @staticmethod - def _ensure_safe_name(name): - """ - Prevent paths in *_scripts entry point names. - """ - has_path_sep = re.search(r'[\\/]', name) - if has_path_sep: - raise ValueError("Path separators not allowed in script names") - - @classmethod - def get_writer(cls, force_windows): - # for backward compatibility - warnings.warn("Use best", EasyInstallDeprecationWarning) - return WindowsScriptWriter.best() if force_windows else cls.best() - - @classmethod - def best(cls): - """ - Select the best ScriptWriter for this environment. - """ - if sys.platform == 'win32' or (os.name == 'java' and os._name == 'nt'): - return WindowsScriptWriter.best() - else: - return cls - - @classmethod - def _get_script_args(cls, type_, name, header, script_text): - # Simply write the stub with no extension. - yield (name, header + script_text) - - @classmethod - def get_header(cls, script_text="", executable=None): - """Create a #! line, getting options (if any) from script_text""" - cmd = cls.command_spec_class.best().from_param(executable) - cmd.install_options(script_text) - return cmd.as_header() - - -class WindowsScriptWriter(ScriptWriter): - command_spec_class = WindowsCommandSpec - - @classmethod - def get_writer(cls): - # for backward compatibility - warnings.warn("Use best", EasyInstallDeprecationWarning) - return cls.best() - - @classmethod - def best(cls): - """ - Select the best ScriptWriter suitable for Windows - """ - writer_lookup = dict( - executable=WindowsExecutableLauncherWriter, - natural=cls, - ) - # for compatibility, use the executable launcher by default - launcher = os.environ.get('SETUPTOOLS_LAUNCHER', 'executable') - return writer_lookup[launcher] - - @classmethod - def _get_script_args(cls, type_, name, header, script_text): - "For Windows, add a .py extension" - ext = dict(console='.pya', gui='.pyw')[type_] - if ext not in os.environ['PATHEXT'].lower().split(';'): - msg = ( - "{ext} not listed in PATHEXT; scripts will not be " - "recognized as executables." - ).format(**locals()) - warnings.warn(msg, UserWarning) - old = ['.pya', '.py', '-script.py', '.pyc', '.pyo', '.pyw', '.exe'] - old.remove(ext) - header = cls._adjust_header(type_, header) - blockers = [name + x for x in old] - yield name + ext, header + script_text, 't', blockers - - @classmethod - def _adjust_header(cls, type_, orig_header): - """ - Make sure 'pythonw' is used for gui and and 'python' is used for - console (regardless of what sys.executable is). - """ - pattern = 'pythonw.exe' - repl = 'python.exe' - if type_ == 'gui': - pattern, repl = repl, pattern - pattern_ob = re.compile(re.escape(pattern), re.IGNORECASE) - new_header = pattern_ob.sub(string=orig_header, repl=repl) - return new_header if cls._use_header(new_header) else orig_header - - @staticmethod - def _use_header(new_header): - """ - Should _adjust_header use the replaced header? - - On non-windows systems, always use. On - Windows systems, only use the replaced header if it resolves - to an executable on the system. - """ - clean_header = new_header[2:-1].strip('"') - return sys.platform != 'win32' or find_executable(clean_header) - - -class WindowsExecutableLauncherWriter(WindowsScriptWriter): - @classmethod - def _get_script_args(cls, type_, name, header, script_text): - """ - For Windows, add a .py extension and an .exe launcher - """ - if type_ == 'gui': - launcher_type = 'gui' - ext = '-script.pyw' - old = ['.pyw'] - else: - launcher_type = 'cli' - ext = '-script.py' - old = ['.py', '.pyc', '.pyo'] - hdr = cls._adjust_header(type_, header) - blockers = [name + x for x in old] - yield (name + ext, hdr + script_text, 't', blockers) - yield ( - name + '.exe', get_win_launcher(launcher_type), - 'b' # write in binary mode - ) - if not is_64bit(): - # install a manifest for the launcher to prevent Windows - # from detecting it as an installer (which it will for - # launchers like easy_install.exe). Consider only - # adding a manifest for launchers detected as installers. - # See Distribute #143 for details. - m_name = name + '.exe.manifest' - yield (m_name, load_launcher_manifest(name), 't') - - -# for backward-compatibility -get_script_args = ScriptWriter.get_script_args -get_script_header = ScriptWriter.get_script_header - - -def get_win_launcher(type): - """ - Load the Windows launcher (executable) suitable for launching a script. - - `type` should be either 'cli' or 'gui' - - Returns the executable as a byte string. - """ - launcher_fn = '%s.exe' % type - if is_64bit(): - launcher_fn = launcher_fn.replace(".", "-64.") - else: - launcher_fn = launcher_fn.replace(".", "-32.") - return resource_string('setuptools', launcher_fn) - - -def load_launcher_manifest(name): - manifest = pkg_resources.resource_string(__name__, 'launcher manifest.xml') - if six.PY2: - return manifest % vars() - else: - return manifest.decode('utf-8') % vars() - - -def rmtree(path, ignore_errors=False, onerror=auto_chmod): - return shutil.rmtree(path, ignore_errors, onerror) - - -def current_umask(): - tmp = os.umask(0o022) - os.umask(tmp) - return tmp - - -def bootstrap(): - # This function is called when setuptools*.egg is run using /bin/sh - import setuptools - - argv0 = os.path.dirname(setuptools.__path__[0]) - sys.argv[0] = argv0 - sys.argv.append(argv0) - main() - - -def main(argv=None, **kw): - from setuptools import setup - from setuptools.dist import Distribution - - class DistributionWithoutHelpCommands(Distribution): - common_usage = "" - - def _show_help(self, *args, **kw): - with _patch_usage(): - Distribution._show_help(self, *args, **kw) - - if argv is None: - argv = sys.argv[1:] - - with _patch_usage(): - setup( - script_args=['-q', 'easy_install', '-v'] + argv, - script_name=sys.argv[0] or 'easy_install', - distclass=DistributionWithoutHelpCommands, - **kw - ) - - -@contextlib.contextmanager -def _patch_usage(): - import distutils.core - USAGE = textwrap.dedent(""" - usage: %(script)s [options] requirement_or_url ... - or: %(script)s --help - """).lstrip() - - def gen_usage(script_name): - return USAGE % dict( - script=os.path.basename(script_name), - ) - - saved = distutils.core.gen_usage - distutils.core.gen_usage = gen_usage - try: - yield - finally: - distutils.core.gen_usage = saved - -class EasyInstallDeprecationWarning(SetuptoolsDeprecationWarning): - """Class for warning about deprecations in EasyInstall in SetupTools. Not ignored by default, unlike DeprecationWarning.""" - diff --git a/venv/lib/python3.8/site-packages/setuptools/command/egg_info.py b/venv/lib/python3.8/site-packages/setuptools/command/egg_info.py deleted file mode 100644 index b767ef3..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/command/egg_info.py +++ /dev/null @@ -1,717 +0,0 @@ -"""setuptools.command.egg_info - -Create a distribution's .egg-info directory and contents""" - -from distutils.filelist import FileList as _FileList -from distutils.errors import DistutilsInternalError -from distutils.util import convert_path -from distutils import log -import distutils.errors -import distutils.filelist -import os -import re -import sys -import io -import warnings -import time -import collections - -from setuptools.extern import six -from setuptools.extern.six.moves import map - -from setuptools import Command -from setuptools.command.sdist import sdist -from setuptools.command.sdist import walk_revctrl -from setuptools.command.setopt import edit_config -from setuptools.command import bdist_egg -from pkg_resources import ( - parse_requirements, safe_name, parse_version, - safe_version, yield_lines, EntryPoint, iter_entry_points, to_filename) -import setuptools.unicode_utils as unicode_utils -from setuptools.glob import glob - -from setuptools.extern import packaging -from setuptools import SetuptoolsDeprecationWarning - -def translate_pattern(glob): - """ - Translate a file path glob like '*.txt' in to a regular expression. - This differs from fnmatch.translate which allows wildcards to match - directory separators. It also knows about '**/' which matches any number of - directories. - """ - pat = '' - - # This will split on '/' within [character classes]. This is deliberate. - chunks = glob.split(os.path.sep) - - sep = re.escape(os.sep) - valid_char = '[^%s]' % (sep,) - - for c, chunk in enumerate(chunks): - last_chunk = c == len(chunks) - 1 - - # Chunks that are a literal ** are globstars. They match anything. - if chunk == '**': - if last_chunk: - # Match anything if this is the last component - pat += '.*' - else: - # Match '(name/)*' - pat += '(?:%s+%s)*' % (valid_char, sep) - continue # Break here as the whole path component has been handled - - # Find any special characters in the remainder - i = 0 - chunk_len = len(chunk) - while i < chunk_len: - char = chunk[i] - if char == '*': - # Match any number of name characters - pat += valid_char + '*' - elif char == '?': - # Match a name character - pat += valid_char - elif char == '[': - # Character class - inner_i = i + 1 - # Skip initial !/] chars - if inner_i < chunk_len and chunk[inner_i] == '!': - inner_i = inner_i + 1 - if inner_i < chunk_len and chunk[inner_i] == ']': - inner_i = inner_i + 1 - - # Loop till the closing ] is found - while inner_i < chunk_len and chunk[inner_i] != ']': - inner_i = inner_i + 1 - - if inner_i >= chunk_len: - # Got to the end of the string without finding a closing ] - # Do not treat this as a matching group, but as a literal [ - pat += re.escape(char) - else: - # Grab the insides of the [brackets] - inner = chunk[i + 1:inner_i] - char_class = '' - - # Class negation - if inner[0] == '!': - char_class = '^' - inner = inner[1:] - - char_class += re.escape(inner) - pat += '[%s]' % (char_class,) - - # Skip to the end ] - i = inner_i - else: - pat += re.escape(char) - i += 1 - - # Join each chunk with the dir separator - if not last_chunk: - pat += sep - - pat += r'\Z' - return re.compile(pat, flags=re.MULTILINE|re.DOTALL) - - -class InfoCommon: - tag_build = None - tag_date = None - - @property - def name(self): - return safe_name(self.distribution.get_name()) - - def tagged_version(self): - version = self.distribution.get_version() - # egg_info may be called more than once for a distribution, - # in which case the version string already contains all tags. - if self.vtags and version.endswith(self.vtags): - return safe_version(version) - return safe_version(version + self.vtags) - - def tags(self): - version = '' - if self.tag_build: - version += self.tag_build - if self.tag_date: - version += time.strftime("-%Y%m%d") - return version - vtags = property(tags) - - -class egg_info(InfoCommon, Command): - description = "create a distribution's .egg-info directory" - - user_options = [ - ('egg-base=', 'e', "directory containing .egg-info directories" - " (default: top of the source tree)"), - ('tag-date', 'd', "Add date stamp (e.g. 20050528) to version number"), - ('tag-build=', 'b', "Specify explicit tag to add to version number"), - ('no-date', 'D', "Don't include date stamp [default]"), - ] - - boolean_options = ['tag-date'] - negative_opt = { - 'no-date': 'tag-date', - } - - def initialize_options(self): - self.egg_base = None - self.egg_name = None - self.egg_info = None - self.egg_version = None - self.broken_egg_info = False - - #################################### - # allow the 'tag_svn_revision' to be detected and - # set, supporting sdists built on older Setuptools. - @property - def tag_svn_revision(self): - pass - - @tag_svn_revision.setter - def tag_svn_revision(self, value): - pass - #################################### - - def save_version_info(self, filename): - """ - Materialize the value of date into the - build tag. Install build keys in a deterministic order - to avoid arbitrary reordering on subsequent builds. - """ - egg_info = collections.OrderedDict() - # follow the order these keys would have been added - # when PYTHONHASHSEED=0 - egg_info['tag_build'] = self.tags() - egg_info['tag_date'] = 0 - edit_config(filename, dict(egg_info=egg_info)) - - def finalize_options(self): - # Note: we need to capture the current value returned - # by `self.tagged_version()`, so we can later update - # `self.distribution.metadata.version` without - # repercussions. - self.egg_name = self.name - self.egg_version = self.tagged_version() - parsed_version = parse_version(self.egg_version) - - try: - is_version = isinstance(parsed_version, packaging.version.Version) - spec = ( - "%s==%s" if is_version else "%s===%s" - ) - list( - parse_requirements(spec % (self.egg_name, self.egg_version)) - ) - except ValueError: - raise distutils.errors.DistutilsOptionError( - "Invalid distribution name or version syntax: %s-%s" % - (self.egg_name, self.egg_version) - ) - - if self.egg_base is None: - dirs = self.distribution.package_dir - self.egg_base = (dirs or {}).get('', os.curdir) - - self.ensure_dirname('egg_base') - self.egg_info = to_filename(self.egg_name) + '.egg-info' - if self.egg_base != os.curdir: - self.egg_info = os.path.join(self.egg_base, self.egg_info) - if '-' in self.egg_name: - self.check_broken_egg_info() - - # Set package version for the benefit of dumber commands - # (e.g. sdist, bdist_wininst, etc.) - # - self.distribution.metadata.version = self.egg_version - - # If we bootstrapped around the lack of a PKG-INFO, as might be the - # case in a fresh checkout, make sure that any special tags get added - # to the version info - # - pd = self.distribution._patched_dist - if pd is not None and pd.key == self.egg_name.lower(): - pd._version = self.egg_version - pd._parsed_version = parse_version(self.egg_version) - self.distribution._patched_dist = None - - def write_or_delete_file(self, what, filename, data, force=False): - """Write `data` to `filename` or delete if empty - - If `data` is non-empty, this routine is the same as ``write_file()``. - If `data` is empty but not ``None``, this is the same as calling - ``delete_file(filename)`. If `data` is ``None``, then this is a no-op - unless `filename` exists, in which case a warning is issued about the - orphaned file (if `force` is false), or deleted (if `force` is true). - """ - if data: - self.write_file(what, filename, data) - elif os.path.exists(filename): - if data is None and not force: - log.warn( - "%s not set in setup(), but %s exists", what, filename - ) - return - else: - self.delete_file(filename) - - def write_file(self, what, filename, data): - """Write `data` to `filename` (if not a dry run) after announcing it - - `what` is used in a log message to identify what is being written - to the file. - """ - log.info("writing %s to %s", what, filename) - if six.PY3: - data = data.encode("utf-8") - if not self.dry_run: - f = open(filename, 'wb') - f.write(data) - f.close() - - def delete_file(self, filename): - """Delete `filename` (if not a dry run) after announcing it""" - log.info("deleting %s", filename) - if not self.dry_run: - os.unlink(filename) - - def run(self): - self.mkpath(self.egg_info) - os.utime(self.egg_info, None) - installer = self.distribution.fetch_build_egg - for ep in iter_entry_points('egg_info.writers'): - ep.require(installer=installer) - writer = ep.resolve() - writer(self, ep.name, os.path.join(self.egg_info, ep.name)) - - # Get rid of native_libs.txt if it was put there by older bdist_egg - nl = os.path.join(self.egg_info, "native_libs.txt") - if os.path.exists(nl): - self.delete_file(nl) - - self.find_sources() - - def find_sources(self): - """Generate SOURCES.txt manifest file""" - manifest_filename = os.path.join(self.egg_info, "SOURCES.txt") - mm = manifest_maker(self.distribution) - mm.manifest = manifest_filename - mm.run() - self.filelist = mm.filelist - - def check_broken_egg_info(self): - bei = self.egg_name + '.egg-info' - if self.egg_base != os.curdir: - bei = os.path.join(self.egg_base, bei) - if os.path.exists(bei): - log.warn( - "-" * 78 + '\n' - "Note: Your current .egg-info directory has a '-' in its name;" - '\nthis will not work correctly with "setup.py develop".\n\n' - 'Please rename %s to %s to correct this problem.\n' + '-' * 78, - bei, self.egg_info - ) - self.broken_egg_info = self.egg_info - self.egg_info = bei # make it work for now - - -class FileList(_FileList): - # Implementations of the various MANIFEST.in commands - - def process_template_line(self, line): - # Parse the line: split it up, make sure the right number of words - # is there, and return the relevant words. 'action' is always - # defined: it's the first word of the line. Which of the other - # three are defined depends on the action; it'll be either - # patterns, (dir and patterns), or (dir_pattern). - (action, patterns, dir, dir_pattern) = self._parse_template_line(line) - - # OK, now we know that the action is valid and we have the - # right number of words on the line for that action -- so we - # can proceed with minimal error-checking. - if action == 'include': - self.debug_print("include " + ' '.join(patterns)) - for pattern in patterns: - if not self.include(pattern): - log.warn("warning: no files found matching '%s'", pattern) - - elif action == 'exclude': - self.debug_print("exclude " + ' '.join(patterns)) - for pattern in patterns: - if not self.exclude(pattern): - log.warn(("warning: no previously-included files " - "found matching '%s'"), pattern) - - elif action == 'global-include': - self.debug_print("global-include " + ' '.join(patterns)) - for pattern in patterns: - if not self.global_include(pattern): - log.warn(("warning: no files found matching '%s' " - "anywhere in distribution"), pattern) - - elif action == 'global-exclude': - self.debug_print("global-exclude " + ' '.join(patterns)) - for pattern in patterns: - if not self.global_exclude(pattern): - log.warn(("warning: no previously-included files matching " - "'%s' found anywhere in distribution"), - pattern) - - elif action == 'recursive-include': - self.debug_print("recursive-include %s %s" % - (dir, ' '.join(patterns))) - for pattern in patterns: - if not self.recursive_include(dir, pattern): - log.warn(("warning: no files found matching '%s' " - "under directory '%s'"), - pattern, dir) - - elif action == 'recursive-exclude': - self.debug_print("recursive-exclude %s %s" % - (dir, ' '.join(patterns))) - for pattern in patterns: - if not self.recursive_exclude(dir, pattern): - log.warn(("warning: no previously-included files matching " - "'%s' found under directory '%s'"), - pattern, dir) - - elif action == 'graft': - self.debug_print("graft " + dir_pattern) - if not self.graft(dir_pattern): - log.warn("warning: no directories found matching '%s'", - dir_pattern) - - elif action == 'prune': - self.debug_print("prune " + dir_pattern) - if not self.prune(dir_pattern): - log.warn(("no previously-included directories found " - "matching '%s'"), dir_pattern) - - else: - raise DistutilsInternalError( - "this cannot happen: invalid action '%s'" % action) - - def _remove_files(self, predicate): - """ - Remove all files from the file list that match the predicate. - Return True if any matching files were removed - """ - found = False - for i in range(len(self.files) - 1, -1, -1): - if predicate(self.files[i]): - self.debug_print(" removing " + self.files[i]) - del self.files[i] - found = True - return found - - def include(self, pattern): - """Include files that match 'pattern'.""" - found = [f for f in glob(pattern) if not os.path.isdir(f)] - self.extend(found) - return bool(found) - - def exclude(self, pattern): - """Exclude files that match 'pattern'.""" - match = translate_pattern(pattern) - return self._remove_files(match.match) - - def recursive_include(self, dir, pattern): - """ - Include all files anywhere in 'dir/' that match the pattern. - """ - full_pattern = os.path.join(dir, '**', pattern) - found = [f for f in glob(full_pattern, recursive=True) - if not os.path.isdir(f)] - self.extend(found) - return bool(found) - - def recursive_exclude(self, dir, pattern): - """ - Exclude any file anywhere in 'dir/' that match the pattern. - """ - match = translate_pattern(os.path.join(dir, '**', pattern)) - return self._remove_files(match.match) - - def graft(self, dir): - """Include all files from 'dir/'.""" - found = [ - item - for match_dir in glob(dir) - for item in distutils.filelist.findall(match_dir) - ] - self.extend(found) - return bool(found) - - def prune(self, dir): - """Filter out files from 'dir/'.""" - match = translate_pattern(os.path.join(dir, '**')) - return self._remove_files(match.match) - - def global_include(self, pattern): - """ - Include all files anywhere in the current directory that match the - pattern. This is very inefficient on large file trees. - """ - if self.allfiles is None: - self.findall() - match = translate_pattern(os.path.join('**', pattern)) - found = [f for f in self.allfiles if match.match(f)] - self.extend(found) - return bool(found) - - def global_exclude(self, pattern): - """ - Exclude all files anywhere that match the pattern. - """ - match = translate_pattern(os.path.join('**', pattern)) - return self._remove_files(match.match) - - def append(self, item): - if item.endswith('\r'): # Fix older sdists built on Windows - item = item[:-1] - path = convert_path(item) - - if self._safe_path(path): - self.files.append(path) - - def extend(self, paths): - self.files.extend(filter(self._safe_path, paths)) - - def _repair(self): - """ - Replace self.files with only safe paths - - Because some owners of FileList manipulate the underlying - ``files`` attribute directly, this method must be called to - repair those paths. - """ - self.files = list(filter(self._safe_path, self.files)) - - def _safe_path(self, path): - enc_warn = "'%s' not %s encodable -- skipping" - - # To avoid accidental trans-codings errors, first to unicode - u_path = unicode_utils.filesys_decode(path) - if u_path is None: - log.warn("'%s' in unexpected encoding -- skipping" % path) - return False - - # Must ensure utf-8 encodability - utf8_path = unicode_utils.try_encode(u_path, "utf-8") - if utf8_path is None: - log.warn(enc_warn, path, 'utf-8') - return False - - try: - # accept is either way checks out - if os.path.exists(u_path) or os.path.exists(utf8_path): - return True - # this will catch any encode errors decoding u_path - except UnicodeEncodeError: - log.warn(enc_warn, path, sys.getfilesystemencoding()) - - -class manifest_maker(sdist): - template = "MANIFEST.in" - - def initialize_options(self): - self.use_defaults = 1 - self.prune = 1 - self.manifest_only = 1 - self.force_manifest = 1 - - def finalize_options(self): - pass - - def run(self): - self.filelist = FileList() - if not os.path.exists(self.manifest): - self.write_manifest() # it must exist so it'll get in the list - self.add_defaults() - if os.path.exists(self.template): - self.read_template() - self.prune_file_list() - self.filelist.sort() - self.filelist.remove_duplicates() - self.write_manifest() - - def _manifest_normalize(self, path): - path = unicode_utils.filesys_decode(path) - return path.replace(os.sep, '/') - - def write_manifest(self): - """ - Write the file list in 'self.filelist' to the manifest file - named by 'self.manifest'. - """ - self.filelist._repair() - - # Now _repairs should encodability, but not unicode - files = [self._manifest_normalize(f) for f in self.filelist.files] - msg = "writing manifest file '%s'" % self.manifest - self.execute(write_file, (self.manifest, files), msg) - - def warn(self, msg): - if not self._should_suppress_warning(msg): - sdist.warn(self, msg) - - @staticmethod - def _should_suppress_warning(msg): - """ - suppress missing-file warnings from sdist - """ - return re.match(r"standard file .*not found", msg) - - def add_defaults(self): - sdist.add_defaults(self) - self.check_license() - self.filelist.append(self.template) - self.filelist.append(self.manifest) - rcfiles = list(walk_revctrl()) - if rcfiles: - self.filelist.extend(rcfiles) - elif os.path.exists(self.manifest): - self.read_manifest() - - if os.path.exists("setup.py"): - # setup.py should be included by default, even if it's not - # the script called to create the sdist - self.filelist.append("setup.py") - - ei_cmd = self.get_finalized_command('egg_info') - self.filelist.graft(ei_cmd.egg_info) - - def prune_file_list(self): - build = self.get_finalized_command('build') - base_dir = self.distribution.get_fullname() - self.filelist.prune(build.build_base) - self.filelist.prune(base_dir) - sep = re.escape(os.sep) - self.filelist.exclude_pattern(r'(^|' + sep + r')(RCS|CVS|\.svn)' + sep, - is_regex=1) - - -def write_file(filename, contents): - """Create a file with the specified name and write 'contents' (a - sequence of strings without line terminators) to it. - """ - contents = "\n".join(contents) - - # assuming the contents has been vetted for utf-8 encoding - contents = contents.encode("utf-8") - - with open(filename, "wb") as f: # always write POSIX-style manifest - f.write(contents) - - -def write_pkg_info(cmd, basename, filename): - log.info("writing %s", filename) - if not cmd.dry_run: - metadata = cmd.distribution.metadata - metadata.version, oldver = cmd.egg_version, metadata.version - metadata.name, oldname = cmd.egg_name, metadata.name - - try: - # write unescaped data to PKG-INFO, so older pkg_resources - # can still parse it - metadata.write_pkg_info(cmd.egg_info) - finally: - metadata.name, metadata.version = oldname, oldver - - safe = getattr(cmd.distribution, 'zip_safe', None) - - bdist_egg.write_safety_flag(cmd.egg_info, safe) - - -def warn_depends_obsolete(cmd, basename, filename): - if os.path.exists(filename): - log.warn( - "WARNING: 'depends.txt' is not used by setuptools 0.6!\n" - "Use the install_requires/extras_require setup() args instead." - ) - - -def _write_requirements(stream, reqs): - lines = yield_lines(reqs or ()) - append_cr = lambda line: line + '\n' - lines = map(append_cr, sorted(lines)) - stream.writelines(lines) - - -def write_requirements(cmd, basename, filename): - dist = cmd.distribution - data = six.StringIO() - _write_requirements(data, dist.install_requires) - extras_require = dist.extras_require or {} - for extra in sorted(extras_require): - data.write('\n[{extra}]\n'.format(**vars())) - _write_requirements(data, extras_require[extra]) - cmd.write_or_delete_file("requirements", filename, data.getvalue()) - - -def write_setup_requirements(cmd, basename, filename): - data = io.StringIO() - _write_requirements(data, cmd.distribution.setup_requires) - cmd.write_or_delete_file("setup-requirements", filename, data.getvalue()) - - -def write_toplevel_names(cmd, basename, filename): - pkgs = dict.fromkeys( - [ - k.split('.', 1)[0] - for k in cmd.distribution.iter_distribution_names() - ] - ) - cmd.write_file("top-level names", filename, '\n'.join(sorted(pkgs)) + '\n') - - -def overwrite_arg(cmd, basename, filename): - write_arg(cmd, basename, filename, True) - - -def write_arg(cmd, basename, filename, force=False): - argname = os.path.splitext(basename)[0] - value = getattr(cmd.distribution, argname, None) - if value is not None: - value = '\n'.join(value) + '\n' - cmd.write_or_delete_file(argname, filename, value, force) - - -def write_entries(cmd, basename, filename): - ep = cmd.distribution.entry_points - - if isinstance(ep, six.string_types) or ep is None: - data = ep - elif ep is not None: - data = [] - for section, contents in sorted(ep.items()): - if not isinstance(contents, six.string_types): - contents = EntryPoint.parse_group(section, contents) - contents = '\n'.join(sorted(map(str, contents.values()))) - data.append('[%s]\n%s\n\n' % (section, contents)) - data = ''.join(data) - - cmd.write_or_delete_file('entry points', filename, data, True) - - -def get_pkg_info_revision(): - """ - Get a -r### off of PKG-INFO Version in case this is an sdist of - a subversion revision. - """ - warnings.warn("get_pkg_info_revision is deprecated.", EggInfoDeprecationWarning) - if os.path.exists('PKG-INFO'): - with io.open('PKG-INFO') as f: - for line in f: - match = re.match(r"Version:.*-r(\d+)\s*$", line) - if match: - return int(match.group(1)) - return 0 - - -class EggInfoDeprecationWarning(SetuptoolsDeprecationWarning): - """Class for warning about deprecations in eggInfo in setupTools. Not ignored by default, unlike DeprecationWarning.""" diff --git a/venv/lib/python3.8/site-packages/setuptools/command/install.py b/venv/lib/python3.8/site-packages/setuptools/command/install.py deleted file mode 100644 index 72b9a3e..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/command/install.py +++ /dev/null @@ -1,125 +0,0 @@ -from distutils.errors import DistutilsArgError -import inspect -import glob -import warnings -import platform -import distutils.command.install as orig - -import setuptools - -# Prior to numpy 1.9, NumPy relies on the '_install' name, so provide it for -# now. See https://github.com/pypa/setuptools/issues/199/ -_install = orig.install - - -class install(orig.install): - """Use easy_install to install the package, w/dependencies""" - - user_options = orig.install.user_options + [ - ('old-and-unmanageable', None, "Try not to use this!"), - ('single-version-externally-managed', None, - "used by system package builders to create 'flat' eggs"), - ] - boolean_options = orig.install.boolean_options + [ - 'old-and-unmanageable', 'single-version-externally-managed', - ] - new_commands = [ - ('install_egg_info', lambda self: True), - ('install_scripts', lambda self: True), - ] - _nc = dict(new_commands) - - def initialize_options(self): - orig.install.initialize_options(self) - self.old_and_unmanageable = None - self.single_version_externally_managed = None - - def finalize_options(self): - orig.install.finalize_options(self) - if self.root: - self.single_version_externally_managed = True - elif self.single_version_externally_managed: - if not self.root and not self.record: - raise DistutilsArgError( - "You must specify --record or --root when building system" - " packages" - ) - - def handle_extra_path(self): - if self.root or self.single_version_externally_managed: - # explicit backward-compatibility mode, allow extra_path to work - return orig.install.handle_extra_path(self) - - # Ignore extra_path when installing an egg (or being run by another - # command without --root or --single-version-externally-managed - self.path_file = None - self.extra_dirs = '' - - def run(self): - # Explicit request for old-style install? Just do it - if self.old_and_unmanageable or self.single_version_externally_managed: - return orig.install.run(self) - - if not self._called_from_setup(inspect.currentframe()): - # Run in backward-compatibility mode to support bdist_* commands. - orig.install.run(self) - else: - self.do_egg_install() - - @staticmethod - def _called_from_setup(run_frame): - """ - Attempt to detect whether run() was called from setup() or by another - command. If called by setup(), the parent caller will be the - 'run_command' method in 'distutils.dist', and *its* caller will be - the 'run_commands' method. If called any other way, the - immediate caller *might* be 'run_command', but it won't have been - called by 'run_commands'. Return True in that case or if a call stack - is unavailable. Return False otherwise. - """ - if run_frame is None: - msg = "Call stack not available. bdist_* commands may fail." - warnings.warn(msg) - if platform.python_implementation() == 'IronPython': - msg = "For best results, pass -X:Frames to enable call stack." - warnings.warn(msg) - return True - res = inspect.getouterframes(run_frame)[2] - caller, = res[:1] - info = inspect.getframeinfo(caller) - caller_module = caller.f_globals.get('__name__', '') - return ( - caller_module == 'distutils.dist' - and info.function == 'run_commands' - ) - - def do_egg_install(self): - - easy_install = self.distribution.get_command_class('easy_install') - - cmd = easy_install( - self.distribution, args="x", root=self.root, record=self.record, - ) - cmd.ensure_finalized() # finalize before bdist_egg munges install cmd - cmd.always_copy_from = '.' # make sure local-dir eggs get installed - - # pick up setup-dir .egg files only: no .egg-info - cmd.package_index.scan(glob.glob('*.egg')) - - self.run_command('bdist_egg') - args = [self.distribution.get_command_obj('bdist_egg').egg_output] - - if setuptools.bootstrap_install_from: - # Bootstrap self-installation of setuptools - args.insert(0, setuptools.bootstrap_install_from) - - cmd.args = args - cmd.run(show_deprecation=False) - setuptools.bootstrap_install_from = None - - -# XXX Python 3.1 doesn't see _nc if this is inside the class -install.sub_commands = ( - [cmd for cmd in orig.install.sub_commands if cmd[0] not in install._nc] + - install.new_commands -) diff --git a/venv/lib/python3.8/site-packages/setuptools/command/install_egg_info.py b/venv/lib/python3.8/site-packages/setuptools/command/install_egg_info.py deleted file mode 100644 index 5f405bc..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/command/install_egg_info.py +++ /dev/null @@ -1,82 +0,0 @@ -from distutils import log, dir_util -import os, sys - -from setuptools import Command -from setuptools import namespaces -from setuptools.archive_util import unpack_archive -import pkg_resources - - -class install_egg_info(namespaces.Installer, Command): - """Install an .egg-info directory for the package""" - - description = "Install an .egg-info directory for the package" - - user_options = [ - ('install-dir=', 'd', "directory to install to"), - ] - - def initialize_options(self): - self.install_dir = None - self.install_layout = None - self.prefix_option = None - - def finalize_options(self): - self.set_undefined_options('install_lib', - ('install_dir', 'install_dir')) - self.set_undefined_options('install',('install_layout','install_layout')) - if sys.hexversion > 0x2060000: - self.set_undefined_options('install',('prefix_option','prefix_option')) - ei_cmd = self.get_finalized_command("egg_info") - basename = pkg_resources.Distribution( - None, None, ei_cmd.egg_name, ei_cmd.egg_version - ).egg_name() + '.egg-info' - - if self.install_layout: - if not self.install_layout.lower() in ['deb']: - raise DistutilsOptionError("unknown value for --install-layout") - self.install_layout = self.install_layout.lower() - basename = basename.replace('-py%s' % pkg_resources.PY_MAJOR, '') - elif self.prefix_option or 'real_prefix' in sys.__dict__: - # don't modify for virtualenv - pass - else: - basename = basename.replace('-py%s' % pkg_resources.PY_MAJOR, '') - - self.source = ei_cmd.egg_info - self.target = os.path.join(self.install_dir, basename) - self.outputs = [] - - def run(self): - self.run_command('egg_info') - if os.path.isdir(self.target) and not os.path.islink(self.target): - dir_util.remove_tree(self.target, dry_run=self.dry_run) - elif os.path.exists(self.target): - self.execute(os.unlink, (self.target,), "Removing " + self.target) - if not self.dry_run: - pkg_resources.ensure_directory(self.target) - self.execute( - self.copytree, (), "Copying %s to %s" % (self.source, self.target) - ) - self.install_namespaces() - - def get_outputs(self): - return self.outputs - - def copytree(self): - # Copy the .egg-info tree to site-packages - def skimmer(src, dst): - # filter out source-control directories; note that 'src' is always - # a '/'-separated path, regardless of platform. 'dst' is a - # platform-specific path. - for skip in '.svn/', 'CVS/': - if src.startswith(skip) or '/' + skip in src: - return None - if self.install_layout and self.install_layout in ['deb'] and src.startswith('SOURCES.txt'): - log.info("Skipping SOURCES.txt") - return None - self.outputs.append(dst) - log.debug("Copying %s to %s", src, dst) - return dst - - unpack_archive(self.source, self.target, skimmer) diff --git a/venv/lib/python3.8/site-packages/setuptools/command/install_lib.py b/venv/lib/python3.8/site-packages/setuptools/command/install_lib.py deleted file mode 100644 index bf81519..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/command/install_lib.py +++ /dev/null @@ -1,147 +0,0 @@ -import os -import sys -from itertools import product, starmap -import distutils.command.install_lib as orig - - -class install_lib(orig.install_lib): - """Don't add compiled flags to filenames of non-Python files""" - - def initialize_options(self): - orig.install_lib.initialize_options(self) - self.multiarch = None - self.install_layout = None - - def finalize_options(self): - orig.install_lib.finalize_options(self) - self.set_undefined_options('install',('install_layout','install_layout')) - if self.install_layout == 'deb' and sys.version_info[:2] >= (3, 3): - import sysconfig - self.multiarch = sysconfig.get_config_var('MULTIARCH') - - def run(self): - self.build() - outfiles = self.install() - if outfiles is not None: - # always compile, in case we have any extension stubs to deal with - self.byte_compile(outfiles) - - def get_exclusions(self): - """ - Return a collections.Sized collections.Container of paths to be - excluded for single_version_externally_managed installations. - """ - all_packages = ( - pkg - for ns_pkg in self._get_SVEM_NSPs() - for pkg in self._all_packages(ns_pkg) - ) - - excl_specs = product(all_packages, self._gen_exclusion_paths()) - return set(starmap(self._exclude_pkg_path, excl_specs)) - - def _exclude_pkg_path(self, pkg, exclusion_path): - """ - Given a package name and exclusion path within that package, - compute the full exclusion path. - """ - parts = pkg.split('.') + [exclusion_path] - return os.path.join(self.install_dir, *parts) - - @staticmethod - def _all_packages(pkg_name): - """ - >>> list(install_lib._all_packages('foo.bar.baz')) - ['foo.bar.baz', 'foo.bar', 'foo'] - """ - while pkg_name: - yield pkg_name - pkg_name, sep, child = pkg_name.rpartition('.') - - def _get_SVEM_NSPs(self): - """ - Get namespace packages (list) but only for - single_version_externally_managed installations and empty otherwise. - """ - # TODO: is it necessary to short-circuit here? i.e. what's the cost - # if get_finalized_command is called even when namespace_packages is - # False? - if not self.distribution.namespace_packages: - return [] - - install_cmd = self.get_finalized_command('install') - svem = install_cmd.single_version_externally_managed - - return self.distribution.namespace_packages if svem else [] - - @staticmethod - def _gen_exclusion_paths(): - """ - Generate file paths to be excluded for namespace packages (bytecode - cache files). - """ - # always exclude the package module itself - yield '__init__.py' - - yield '__init__.pyc' - yield '__init__.pyo' - - if not hasattr(sys, 'implementation'): - return - - base = os.path.join('__pycache__', '__init__.' + sys.implementation.cache_tag) - yield base + '.pyc' - yield base + '.pyo' - yield base + '.opt-1.pyc' - yield base + '.opt-2.pyc' - - def copy_tree( - self, infile, outfile, - preserve_mode=1, preserve_times=1, preserve_symlinks=0, level=1 - ): - assert preserve_mode and preserve_times and not preserve_symlinks - exclude = self.get_exclusions() - - if not exclude: - import distutils.dir_util - distutils.dir_util._multiarch = self.multiarch - return orig.install_lib.copy_tree(self, infile, outfile) - - # Exclude namespace package __init__.py* files from the output - - from setuptools.archive_util import unpack_directory - from distutils import log - - outfiles = [] - - if self.multiarch: - import sysconfig - ext_suffix = sysconfig.get_config_var ('EXT_SUFFIX') - if ext_suffix.endswith(self.multiarch + ext_suffix[-3:]): - new_suffix = None - else: - new_suffix = "%s-%s%s" % (ext_suffix[:-3], self.multiarch, ext_suffix[-3:]) - - def pf(src, dst): - if dst in exclude: - log.warn("Skipping installation of %s (namespace package)", - dst) - return False - - if self.multiarch and new_suffix and dst.endswith(ext_suffix) and not dst.endswith(new_suffix): - dst = dst.replace(ext_suffix, new_suffix) - log.info("renaming extension to %s", os.path.basename(dst)) - - log.info("copying %s -> %s", src, os.path.dirname(dst)) - outfiles.append(dst) - return dst - - unpack_directory(infile, outfile, pf) - return outfiles - - def get_outputs(self): - outputs = orig.install_lib.get_outputs(self) - exclude = self.get_exclusions() - if exclude: - return [f for f in outputs if f not in exclude] - return outputs diff --git a/venv/lib/python3.8/site-packages/setuptools/command/install_scripts.py b/venv/lib/python3.8/site-packages/setuptools/command/install_scripts.py deleted file mode 100644 index 1623427..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/command/install_scripts.py +++ /dev/null @@ -1,65 +0,0 @@ -from distutils import log -import distutils.command.install_scripts as orig -import os -import sys - -from pkg_resources import Distribution, PathMetadata, ensure_directory - - -class install_scripts(orig.install_scripts): - """Do normal script install, plus any egg_info wrapper scripts""" - - def initialize_options(self): - orig.install_scripts.initialize_options(self) - self.no_ep = False - - def run(self): - import setuptools.command.easy_install as ei - - self.run_command("egg_info") - if self.distribution.scripts: - orig.install_scripts.run(self) # run first to set up self.outfiles - else: - self.outfiles = [] - if self.no_ep: - # don't install entry point scripts into .egg file! - return - - ei_cmd = self.get_finalized_command("egg_info") - dist = Distribution( - ei_cmd.egg_base, PathMetadata(ei_cmd.egg_base, ei_cmd.egg_info), - ei_cmd.egg_name, ei_cmd.egg_version, - ) - bs_cmd = self.get_finalized_command('build_scripts') - exec_param = getattr(bs_cmd, 'executable', None) - bw_cmd = self.get_finalized_command("bdist_wininst") - is_wininst = getattr(bw_cmd, '_is_running', False) - writer = ei.ScriptWriter - if is_wininst: - exec_param = "python.exe" - writer = ei.WindowsScriptWriter - if exec_param == sys.executable: - # In case the path to the Python executable contains a space, wrap - # it so it's not split up. - exec_param = [exec_param] - # resolve the writer to the environment - writer = writer.best() - cmd = writer.command_spec_class.best().from_param(exec_param) - for args in writer.get_args(dist, cmd.as_header()): - self.write_script(*args) - - def write_script(self, script_name, contents, mode="t", *ignored): - """Write an executable file to the scripts directory""" - from setuptools.command.easy_install import chmod, current_umask - - log.info("Installing %s script to %s", script_name, self.install_dir) - target = os.path.join(self.install_dir, script_name) - self.outfiles.append(target) - - mask = current_umask() - if not self.dry_run: - ensure_directory(target) - f = open(target, "w" + mode) - f.write(contents) - f.close() - chmod(target, 0o777 - mask) diff --git a/venv/lib/python3.8/site-packages/setuptools/command/launcher manifest.xml b/venv/lib/python3.8/site-packages/setuptools/command/launcher manifest.xml deleted file mode 100644 index 5972a96..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/command/launcher manifest.xml +++ /dev/null @@ -1,15 +0,0 @@ -<?xml version="1.0" encoding="UTF-8" standalone="yes"?> -<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> - <assemblyIdentity version="1.0.0.0" - processorArchitecture="X86" - name="%(name)s" - type="win32"/> - <!-- Identify the application security requirements. --> - <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3"> - <security> - <requestedPrivileges> - <requestedExecutionLevel level="asInvoker" uiAccess="false"/> - </requestedPrivileges> - </security> - </trustInfo> -</assembly> diff --git a/venv/lib/python3.8/site-packages/setuptools/command/py36compat.py b/venv/lib/python3.8/site-packages/setuptools/command/py36compat.py deleted file mode 100644 index 61063e7..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/command/py36compat.py +++ /dev/null @@ -1,136 +0,0 @@ -import os -from glob import glob -from distutils.util import convert_path -from distutils.command import sdist - -from setuptools.extern.six.moves import filter - - -class sdist_add_defaults: - """ - Mix-in providing forward-compatibility for functionality as found in - distutils on Python 3.7. - - Do not edit the code in this class except to update functionality - as implemented in distutils. Instead, override in the subclass. - """ - - def add_defaults(self): - """Add all the default files to self.filelist: - - README or README.txt - - setup.py - - test/test*.py - - all pure Python modules mentioned in setup script - - all files pointed by package_data (build_py) - - all files defined in data_files. - - all files defined as scripts. - - all C sources listed as part of extensions or C libraries - in the setup script (doesn't catch C headers!) - Warns if (README or README.txt) or setup.py are missing; everything - else is optional. - """ - self._add_defaults_standards() - self._add_defaults_optional() - self._add_defaults_python() - self._add_defaults_data_files() - self._add_defaults_ext() - self._add_defaults_c_libs() - self._add_defaults_scripts() - - @staticmethod - def _cs_path_exists(fspath): - """ - Case-sensitive path existence check - - >>> sdist_add_defaults._cs_path_exists(__file__) - True - >>> sdist_add_defaults._cs_path_exists(__file__.upper()) - False - """ - if not os.path.exists(fspath): - return False - # make absolute so we always have a directory - abspath = os.path.abspath(fspath) - directory, filename = os.path.split(abspath) - return filename in os.listdir(directory) - - def _add_defaults_standards(self): - standards = [self.READMES, self.distribution.script_name] - for fn in standards: - if isinstance(fn, tuple): - alts = fn - got_it = False - for fn in alts: - if self._cs_path_exists(fn): - got_it = True - self.filelist.append(fn) - break - - if not got_it: - self.warn("standard file not found: should have one of " + - ', '.join(alts)) - else: - if self._cs_path_exists(fn): - self.filelist.append(fn) - else: - self.warn("standard file '%s' not found" % fn) - - def _add_defaults_optional(self): - optional = ['test/test*.py', 'setup.cfg'] - for pattern in optional: - files = filter(os.path.isfile, glob(pattern)) - self.filelist.extend(files) - - def _add_defaults_python(self): - # build_py is used to get: - # - python modules - # - files defined in package_data - build_py = self.get_finalized_command('build_py') - - # getting python files - if self.distribution.has_pure_modules(): - self.filelist.extend(build_py.get_source_files()) - - # getting package_data files - # (computed in build_py.data_files by build_py.finalize_options) - for pkg, src_dir, build_dir, filenames in build_py.data_files: - for filename in filenames: - self.filelist.append(os.path.join(src_dir, filename)) - - def _add_defaults_data_files(self): - # getting distribution.data_files - if self.distribution.has_data_files(): - for item in self.distribution.data_files: - if isinstance(item, str): - # plain file - item = convert_path(item) - if os.path.isfile(item): - self.filelist.append(item) - else: - # a (dirname, filenames) tuple - dirname, filenames = item - for f in filenames: - f = convert_path(f) - if os.path.isfile(f): - self.filelist.append(f) - - def _add_defaults_ext(self): - if self.distribution.has_ext_modules(): - build_ext = self.get_finalized_command('build_ext') - self.filelist.extend(build_ext.get_source_files()) - - def _add_defaults_c_libs(self): - if self.distribution.has_c_libraries(): - build_clib = self.get_finalized_command('build_clib') - self.filelist.extend(build_clib.get_source_files()) - - def _add_defaults_scripts(self): - if self.distribution.has_scripts(): - build_scripts = self.get_finalized_command('build_scripts') - self.filelist.extend(build_scripts.get_source_files()) - - -if hasattr(sdist.sdist, '_add_defaults_standards'): - # disable the functionality already available upstream - class sdist_add_defaults: - pass diff --git a/venv/lib/python3.8/site-packages/setuptools/command/register.py b/venv/lib/python3.8/site-packages/setuptools/command/register.py deleted file mode 100644 index b8266b9..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/command/register.py +++ /dev/null @@ -1,18 +0,0 @@ -from distutils import log -import distutils.command.register as orig - -from setuptools.errors import RemovedCommandError - - -class register(orig.register): - """Formerly used to register packages on PyPI.""" - - def run(self): - msg = ( - "The register command has been removed, use twine to upload " - + "instead (https://pypi.org/p/twine)" - ) - - self.announce("ERROR: " + msg, log.ERROR) - - raise RemovedCommandError(msg) diff --git a/venv/lib/python3.8/site-packages/setuptools/command/rotate.py b/venv/lib/python3.8/site-packages/setuptools/command/rotate.py deleted file mode 100644 index b89353f..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/command/rotate.py +++ /dev/null @@ -1,66 +0,0 @@ -from distutils.util import convert_path -from distutils import log -from distutils.errors import DistutilsOptionError -import os -import shutil - -from setuptools.extern import six - -from setuptools import Command - - -class rotate(Command): - """Delete older distributions""" - - description = "delete older distributions, keeping N newest files" - user_options = [ - ('match=', 'm', "patterns to match (required)"), - ('dist-dir=', 'd', "directory where the distributions are"), - ('keep=', 'k', "number of matching distributions to keep"), - ] - - boolean_options = [] - - def initialize_options(self): - self.match = None - self.dist_dir = None - self.keep = None - - def finalize_options(self): - if self.match is None: - raise DistutilsOptionError( - "Must specify one or more (comma-separated) match patterns " - "(e.g. '.zip' or '.egg')" - ) - if self.keep is None: - raise DistutilsOptionError("Must specify number of files to keep") - try: - self.keep = int(self.keep) - except ValueError: - raise DistutilsOptionError("--keep must be an integer") - if isinstance(self.match, six.string_types): - self.match = [ - convert_path(p.strip()) for p in self.match.split(',') - ] - self.set_undefined_options('bdist', ('dist_dir', 'dist_dir')) - - def run(self): - self.run_command("egg_info") - from glob import glob - - for pattern in self.match: - pattern = self.distribution.get_name() + '*' + pattern - files = glob(os.path.join(self.dist_dir, pattern)) - files = [(os.path.getmtime(f), f) for f in files] - files.sort() - files.reverse() - - log.info("%d file(s) matching %s", len(files), pattern) - files = files[self.keep:] - for (t, f) in files: - log.info("Deleting %s", f) - if not self.dry_run: - if os.path.isdir(f): - shutil.rmtree(f) - else: - os.unlink(f) diff --git a/venv/lib/python3.8/site-packages/setuptools/command/saveopts.py b/venv/lib/python3.8/site-packages/setuptools/command/saveopts.py deleted file mode 100644 index 611cec5..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/command/saveopts.py +++ /dev/null @@ -1,22 +0,0 @@ -from setuptools.command.setopt import edit_config, option_base - - -class saveopts(option_base): - """Save command-line options to a file""" - - description = "save supplied options to setup.cfg or other config file" - - def run(self): - dist = self.distribution - settings = {} - - for cmd in dist.command_options: - - if cmd == 'saveopts': - continue # don't save our own options! - - for opt, (src, val) in dist.get_option_dict(cmd).items(): - if src == "command line": - settings.setdefault(cmd, {})[opt] = val - - edit_config(self.filename, settings, self.dry_run) diff --git a/venv/lib/python3.8/site-packages/setuptools/command/sdist.py b/venv/lib/python3.8/site-packages/setuptools/command/sdist.py deleted file mode 100644 index a851453..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/command/sdist.py +++ /dev/null @@ -1,252 +0,0 @@ -from distutils import log -import distutils.command.sdist as orig -import os -import sys -import io -import contextlib - -from setuptools.extern import six, ordered_set - -from .py36compat import sdist_add_defaults - -import pkg_resources - -_default_revctrl = list - - -def walk_revctrl(dirname=''): - """Find all files under revision control""" - for ep in pkg_resources.iter_entry_points('setuptools.file_finders'): - for item in ep.load()(dirname): - yield item - - -class sdist(sdist_add_defaults, orig.sdist): - """Smart sdist that finds anything supported by revision control""" - - user_options = [ - ('formats=', None, - "formats for source distribution (comma-separated list)"), - ('keep-temp', 'k', - "keep the distribution tree around after creating " + - "archive file(s)"), - ('dist-dir=', 'd', - "directory to put the source distribution archive(s) in " - "[default: dist]"), - ] - - negative_opt = {} - - README_EXTENSIONS = ['', '.rst', '.txt', '.md'] - READMES = tuple('README{0}'.format(ext) for ext in README_EXTENSIONS) - - def run(self): - self.run_command('egg_info') - ei_cmd = self.get_finalized_command('egg_info') - self.filelist = ei_cmd.filelist - self.filelist.append(os.path.join(ei_cmd.egg_info, 'SOURCES.txt')) - self.check_readme() - - # Run sub commands - for cmd_name in self.get_sub_commands(): - self.run_command(cmd_name) - - self.make_distribution() - - dist_files = getattr(self.distribution, 'dist_files', []) - for file in self.archive_files: - data = ('sdist', '', file) - if data not in dist_files: - dist_files.append(data) - - def initialize_options(self): - orig.sdist.initialize_options(self) - - self._default_to_gztar() - - def _default_to_gztar(self): - # only needed on Python prior to 3.6. - if sys.version_info >= (3, 6, 0, 'beta', 1): - return - self.formats = ['gztar'] - - def make_distribution(self): - """ - Workaround for #516 - """ - with self._remove_os_link(): - orig.sdist.make_distribution(self) - - @staticmethod - @contextlib.contextmanager - def _remove_os_link(): - """ - In a context, remove and restore os.link if it exists - """ - - class NoValue: - pass - - orig_val = getattr(os, 'link', NoValue) - try: - del os.link - except Exception: - pass - try: - yield - finally: - if orig_val is not NoValue: - setattr(os, 'link', orig_val) - - def __read_template_hack(self): - # This grody hack closes the template file (MANIFEST.in) if an - # exception occurs during read_template. - # Doing so prevents an error when easy_install attempts to delete the - # file. - try: - orig.sdist.read_template(self) - except Exception: - _, _, tb = sys.exc_info() - tb.tb_next.tb_frame.f_locals['template'].close() - raise - - # Beginning with Python 2.7.2, 3.1.4, and 3.2.1, this leaky file handle - # has been fixed, so only override the method if we're using an earlier - # Python. - has_leaky_handle = ( - sys.version_info < (2, 7, 2) - or (3, 0) <= sys.version_info < (3, 1, 4) - or (3, 2) <= sys.version_info < (3, 2, 1) - ) - if has_leaky_handle: - read_template = __read_template_hack - - def _add_defaults_optional(self): - if six.PY2: - sdist_add_defaults._add_defaults_optional(self) - else: - super()._add_defaults_optional() - if os.path.isfile('pyproject.toml'): - self.filelist.append('pyproject.toml') - - def _add_defaults_python(self): - """getting python files""" - if self.distribution.has_pure_modules(): - build_py = self.get_finalized_command('build_py') - self.filelist.extend(build_py.get_source_files()) - self._add_data_files(self._safe_data_files(build_py)) - - def _safe_data_files(self, build_py): - """ - Extracting data_files from build_py is known to cause - infinite recursion errors when `include_package_data` - is enabled, so suppress it in that case. - """ - if self.distribution.include_package_data: - return () - return build_py.data_files - - def _add_data_files(self, data_files): - """ - Add data files as found in build_py.data_files. - """ - self.filelist.extend( - os.path.join(src_dir, name) - for _, src_dir, _, filenames in data_files - for name in filenames - ) - - def _add_defaults_data_files(self): - try: - if six.PY2: - sdist_add_defaults._add_defaults_data_files(self) - else: - super()._add_defaults_data_files() - except TypeError: - log.warn("data_files contains unexpected objects") - - def check_readme(self): - for f in self.READMES: - if os.path.exists(f): - return - else: - self.warn( - "standard file not found: should have one of " + - ', '.join(self.READMES) - ) - - def make_release_tree(self, base_dir, files): - orig.sdist.make_release_tree(self, base_dir, files) - - # Save any egg_info command line options used to create this sdist - dest = os.path.join(base_dir, 'setup.cfg') - if hasattr(os, 'link') and os.path.exists(dest): - # unlink and re-copy, since it might be hard-linked, and - # we don't want to change the source version - os.unlink(dest) - self.copy_file('setup.cfg', dest) - - self.get_finalized_command('egg_info').save_version_info(dest) - - def _manifest_is_not_generated(self): - # check for special comment used in 2.7.1 and higher - if not os.path.isfile(self.manifest): - return False - - with io.open(self.manifest, 'rb') as fp: - first_line = fp.readline() - return (first_line != - '# file GENERATED by distutils, do NOT edit\n'.encode()) - - def read_manifest(self): - """Read the manifest file (named by 'self.manifest') and use it to - fill in 'self.filelist', the list of files to include in the source - distribution. - """ - log.info("reading manifest file '%s'", self.manifest) - manifest = open(self.manifest, 'rb') - for line in manifest: - # The manifest must contain UTF-8. See #303. - if six.PY3: - try: - line = line.decode('UTF-8') - except UnicodeDecodeError: - log.warn("%r not UTF-8 decodable -- skipping" % line) - continue - # ignore comments and blank lines - line = line.strip() - if line.startswith('#') or not line: - continue - self.filelist.append(line) - manifest.close() - - def check_license(self): - """Checks if license_file' or 'license_files' is configured and adds any - valid paths to 'self.filelist'. - """ - - files = ordered_set.OrderedSet() - - opts = self.distribution.get_option_dict('metadata') - - # ignore the source of the value - _, license_file = opts.get('license_file', (None, None)) - - if license_file is None: - log.debug("'license_file' option was not specified") - else: - files.add(license_file) - - try: - files.update(self.distribution.metadata.license_files) - except TypeError: - log.warn("warning: 'license_files' option is malformed") - - for f in files: - if not os.path.exists(f): - log.warn( - "warning: Failed to find the configured license file '%s'", - f) - files.remove(f) - - self.filelist.extend(files) diff --git a/venv/lib/python3.8/site-packages/setuptools/command/setopt.py b/venv/lib/python3.8/site-packages/setuptools/command/setopt.py deleted file mode 100644 index 7e57cc0..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/command/setopt.py +++ /dev/null @@ -1,149 +0,0 @@ -from distutils.util import convert_path -from distutils import log -from distutils.errors import DistutilsOptionError -import distutils -import os - -from setuptools.extern.six.moves import configparser - -from setuptools import Command - -__all__ = ['config_file', 'edit_config', 'option_base', 'setopt'] - - -def config_file(kind="local"): - """Get the filename of the distutils, local, global, or per-user config - - `kind` must be one of "local", "global", or "user" - """ - if kind == 'local': - return 'setup.cfg' - if kind == 'global': - return os.path.join( - os.path.dirname(distutils.__file__), 'distutils.cfg' - ) - if kind == 'user': - dot = os.name == 'posix' and '.' or '' - return os.path.expanduser(convert_path("~/%spydistutils.cfg" % dot)) - raise ValueError( - "config_file() type must be 'local', 'global', or 'user'", kind - ) - - -def edit_config(filename, settings, dry_run=False): - """Edit a configuration file to include `settings` - - `settings` is a dictionary of dictionaries or ``None`` values, keyed by - command/section name. A ``None`` value means to delete the entire section, - while a dictionary lists settings to be changed or deleted in that section. - A setting of ``None`` means to delete that setting. - """ - log.debug("Reading configuration from %s", filename) - opts = configparser.RawConfigParser() - opts.read([filename]) - for section, options in settings.items(): - if options is None: - log.info("Deleting section [%s] from %s", section, filename) - opts.remove_section(section) - else: - if not opts.has_section(section): - log.debug("Adding new section [%s] to %s", section, filename) - opts.add_section(section) - for option, value in options.items(): - if value is None: - log.debug( - "Deleting %s.%s from %s", - section, option, filename - ) - opts.remove_option(section, option) - if not opts.options(section): - log.info("Deleting empty [%s] section from %s", - section, filename) - opts.remove_section(section) - else: - log.debug( - "Setting %s.%s to %r in %s", - section, option, value, filename - ) - opts.set(section, option, value) - - log.info("Writing %s", filename) - if not dry_run: - with open(filename, 'w') as f: - opts.write(f) - - -class option_base(Command): - """Abstract base class for commands that mess with config files""" - - user_options = [ - ('global-config', 'g', - "save options to the site-wide distutils.cfg file"), - ('user-config', 'u', - "save options to the current user's pydistutils.cfg file"), - ('filename=', 'f', - "configuration file to use (default=setup.cfg)"), - ] - - boolean_options = [ - 'global-config', 'user-config', - ] - - def initialize_options(self): - self.global_config = None - self.user_config = None - self.filename = None - - def finalize_options(self): - filenames = [] - if self.global_config: - filenames.append(config_file('global')) - if self.user_config: - filenames.append(config_file('user')) - if self.filename is not None: - filenames.append(self.filename) - if not filenames: - filenames.append(config_file('local')) - if len(filenames) > 1: - raise DistutilsOptionError( - "Must specify only one configuration file option", - filenames - ) - self.filename, = filenames - - -class setopt(option_base): - """Save command-line options to a file""" - - description = "set an option in setup.cfg or another config file" - - user_options = [ - ('command=', 'c', 'command to set an option for'), - ('option=', 'o', 'option to set'), - ('set-value=', 's', 'value of the option'), - ('remove', 'r', 'remove (unset) the value'), - ] + option_base.user_options - - boolean_options = option_base.boolean_options + ['remove'] - - def initialize_options(self): - option_base.initialize_options(self) - self.command = None - self.option = None - self.set_value = None - self.remove = None - - def finalize_options(self): - option_base.finalize_options(self) - if self.command is None or self.option is None: - raise DistutilsOptionError("Must specify --command *and* --option") - if self.set_value is None and not self.remove: - raise DistutilsOptionError("Must specify --set-value or --remove") - - def run(self): - edit_config( - self.filename, { - self.command: {self.option.replace('-', '_'): self.set_value} - }, - self.dry_run - ) diff --git a/venv/lib/python3.8/site-packages/setuptools/command/test.py b/venv/lib/python3.8/site-packages/setuptools/command/test.py deleted file mode 100644 index c148b38..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/command/test.py +++ /dev/null @@ -1,279 +0,0 @@ -import os -import operator -import sys -import contextlib -import itertools -import unittest -from distutils.errors import DistutilsError, DistutilsOptionError -from distutils import log -from unittest import TestLoader - -from setuptools.extern import six -from setuptools.extern.six.moves import map, filter - -from pkg_resources import (resource_listdir, resource_exists, normalize_path, - working_set, _namespace_packages, evaluate_marker, - add_activation_listener, require, EntryPoint) -from setuptools import Command -from .build_py import _unique_everseen - -__metaclass__ = type - - -class ScanningLoader(TestLoader): - - def __init__(self): - TestLoader.__init__(self) - self._visited = set() - - def loadTestsFromModule(self, module, pattern=None): - """Return a suite of all tests cases contained in the given module - - If the module is a package, load tests from all the modules in it. - If the module has an ``additional_tests`` function, call it and add - the return value to the tests. - """ - if module in self._visited: - return None - self._visited.add(module) - - tests = [] - tests.append(TestLoader.loadTestsFromModule(self, module)) - - if hasattr(module, "additional_tests"): - tests.append(module.additional_tests()) - - if hasattr(module, '__path__'): - for file in resource_listdir(module.__name__, ''): - if file.endswith('.py') and file != '__init__.py': - submodule = module.__name__ + '.' + file[:-3] - else: - if resource_exists(module.__name__, file + '/__init__.py'): - submodule = module.__name__ + '.' + file - else: - continue - tests.append(self.loadTestsFromName(submodule)) - - if len(tests) != 1: - return self.suiteClass(tests) - else: - return tests[0] # don't create a nested suite for only one return - - -# adapted from jaraco.classes.properties:NonDataProperty -class NonDataProperty: - def __init__(self, fget): - self.fget = fget - - def __get__(self, obj, objtype=None): - if obj is None: - return self - return self.fget(obj) - - -class test(Command): - """Command to run unit tests after in-place build""" - - description = "run unit tests after in-place build (deprecated)" - - user_options = [ - ('test-module=', 'm', "Run 'test_suite' in specified module"), - ('test-suite=', 's', - "Run single test, case or suite (e.g. 'module.test_suite')"), - ('test-runner=', 'r', "Test runner to use"), - ] - - def initialize_options(self): - self.test_suite = None - self.test_module = None - self.test_loader = None - self.test_runner = None - - def finalize_options(self): - - if self.test_suite and self.test_module: - msg = "You may specify a module or a suite, but not both" - raise DistutilsOptionError(msg) - - if self.test_suite is None: - if self.test_module is None: - self.test_suite = self.distribution.test_suite - else: - self.test_suite = self.test_module + ".test_suite" - - if self.test_loader is None: - self.test_loader = getattr(self.distribution, 'test_loader', None) - if self.test_loader is None: - self.test_loader = "setuptools.command.test:ScanningLoader" - if self.test_runner is None: - self.test_runner = getattr(self.distribution, 'test_runner', None) - - @NonDataProperty - def test_args(self): - return list(self._test_args()) - - def _test_args(self): - if not self.test_suite and sys.version_info >= (2, 7): - yield 'discover' - if self.verbose: - yield '--verbose' - if self.test_suite: - yield self.test_suite - - def with_project_on_sys_path(self, func): - """ - Backward compatibility for project_on_sys_path context. - """ - with self.project_on_sys_path(): - func() - - @contextlib.contextmanager - def project_on_sys_path(self, include_dists=[]): - with_2to3 = six.PY3 and getattr(self.distribution, 'use_2to3', False) - - if with_2to3: - # If we run 2to3 we can not do this inplace: - - # Ensure metadata is up-to-date - self.reinitialize_command('build_py', inplace=0) - self.run_command('build_py') - bpy_cmd = self.get_finalized_command("build_py") - build_path = normalize_path(bpy_cmd.build_lib) - - # Build extensions - self.reinitialize_command('egg_info', egg_base=build_path) - self.run_command('egg_info') - - self.reinitialize_command('build_ext', inplace=0) - self.run_command('build_ext') - else: - # Without 2to3 inplace works fine: - self.run_command('egg_info') - - # Build extensions in-place - self.reinitialize_command('build_ext', inplace=1) - self.run_command('build_ext') - - ei_cmd = self.get_finalized_command("egg_info") - - old_path = sys.path[:] - old_modules = sys.modules.copy() - - try: - project_path = normalize_path(ei_cmd.egg_base) - sys.path.insert(0, project_path) - working_set.__init__() - add_activation_listener(lambda dist: dist.activate()) - require('%s==%s' % (ei_cmd.egg_name, ei_cmd.egg_version)) - with self.paths_on_pythonpath([project_path]): - yield - finally: - sys.path[:] = old_path - sys.modules.clear() - sys.modules.update(old_modules) - working_set.__init__() - - @staticmethod - @contextlib.contextmanager - def paths_on_pythonpath(paths): - """ - Add the indicated paths to the head of the PYTHONPATH environment - variable so that subprocesses will also see the packages at - these paths. - - Do this in a context that restores the value on exit. - """ - nothing = object() - orig_pythonpath = os.environ.get('PYTHONPATH', nothing) - current_pythonpath = os.environ.get('PYTHONPATH', '') - try: - prefix = os.pathsep.join(_unique_everseen(paths)) - to_join = filter(None, [prefix, current_pythonpath]) - new_path = os.pathsep.join(to_join) - if new_path: - os.environ['PYTHONPATH'] = new_path - yield - finally: - if orig_pythonpath is nothing: - os.environ.pop('PYTHONPATH', None) - else: - os.environ['PYTHONPATH'] = orig_pythonpath - - @staticmethod - def install_dists(dist): - """ - Install the requirements indicated by self.distribution and - return an iterable of the dists that were built. - """ - ir_d = dist.fetch_build_eggs(dist.install_requires) - tr_d = dist.fetch_build_eggs(dist.tests_require or []) - er_d = dist.fetch_build_eggs( - v for k, v in dist.extras_require.items() - if k.startswith(':') and evaluate_marker(k[1:]) - ) - return itertools.chain(ir_d, tr_d, er_d) - - def run(self): - self.announce( - "WARNING: Testing via this command is deprecated and will be " - "removed in a future version. Users looking for a generic test " - "entry point independent of test runner are encouraged to use " - "tox.", - log.WARN, - ) - - installed_dists = self.install_dists(self.distribution) - - cmd = ' '.join(self._argv) - if self.dry_run: - self.announce('skipping "%s" (dry run)' % cmd) - return - - self.announce('running "%s"' % cmd) - - paths = map(operator.attrgetter('location'), installed_dists) - with self.paths_on_pythonpath(paths): - with self.project_on_sys_path(): - self.run_tests() - - def run_tests(self): - # Purge modules under test from sys.modules. The test loader will - # re-import them from the build location. Required when 2to3 is used - # with namespace packages. - if six.PY3 and getattr(self.distribution, 'use_2to3', False): - module = self.test_suite.split('.')[0] - if module in _namespace_packages: - del_modules = [] - if module in sys.modules: - del_modules.append(module) - module += '.' - for name in sys.modules: - if name.startswith(module): - del_modules.append(name) - list(map(sys.modules.__delitem__, del_modules)) - - test = unittest.main( - None, None, self._argv, - testLoader=self._resolve_as_ep(self.test_loader), - testRunner=self._resolve_as_ep(self.test_runner), - exit=False, - ) - if not test.result.wasSuccessful(): - msg = 'Test failed: %s' % test.result - self.announce(msg, log.ERROR) - raise DistutilsError(msg) - - @property - def _argv(self): - return ['unittest'] + self.test_args - - @staticmethod - def _resolve_as_ep(val): - """ - Load the indicated attribute value, called, as a as if it were - specified as an entry point. - """ - if val is None: - return - parsed = EntryPoint.parse("x=" + val) - return parsed.resolve()() diff --git a/venv/lib/python3.8/site-packages/setuptools/command/upload.py b/venv/lib/python3.8/site-packages/setuptools/command/upload.py deleted file mode 100644 index ec7f81e..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/command/upload.py +++ /dev/null @@ -1,17 +0,0 @@ -from distutils import log -from distutils.command import upload as orig - -from setuptools.errors import RemovedCommandError - - -class upload(orig.upload): - """Formerly used to upload packages to PyPI.""" - - def run(self): - msg = ( - "The upload command has been removed, use twine to upload " - + "instead (https://pypi.org/p/twine)" - ) - - self.announce("ERROR: " + msg, log.ERROR) - raise RemovedCommandError(msg) diff --git a/venv/lib/python3.8/site-packages/setuptools/command/upload_docs.py b/venv/lib/python3.8/site-packages/setuptools/command/upload_docs.py deleted file mode 100644 index 07aa564..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/command/upload_docs.py +++ /dev/null @@ -1,206 +0,0 @@ -# -*- coding: utf-8 -*- -"""upload_docs - -Implements a Distutils 'upload_docs' subcommand (upload documentation to -PyPI's pythonhosted.org). -""" - -from base64 import standard_b64encode -from distutils import log -from distutils.errors import DistutilsOptionError -import os -import socket -import zipfile -import tempfile -import shutil -import itertools -import functools - -from setuptools.extern import six -from setuptools.extern.six.moves import http_client, urllib - -from pkg_resources import iter_entry_points -from .upload import upload - - -def _encode(s): - errors = 'surrogateescape' if six.PY3 else 'strict' - return s.encode('utf-8', errors) - - -class upload_docs(upload): - # override the default repository as upload_docs isn't - # supported by Warehouse (and won't be). - DEFAULT_REPOSITORY = 'https://pypi.python.org/pypi/' - - description = 'Upload documentation to PyPI' - - user_options = [ - ('repository=', 'r', - "url of repository [default: %s]" % upload.DEFAULT_REPOSITORY), - ('show-response', None, - 'display full response text from server'), - ('upload-dir=', None, 'directory to upload'), - ] - boolean_options = upload.boolean_options - - def has_sphinx(self): - if self.upload_dir is None: - for ep in iter_entry_points('distutils.commands', 'build_sphinx'): - return True - - sub_commands = [('build_sphinx', has_sphinx)] - - def initialize_options(self): - upload.initialize_options(self) - self.upload_dir = None - self.target_dir = None - - def finalize_options(self): - upload.finalize_options(self) - if self.upload_dir is None: - if self.has_sphinx(): - build_sphinx = self.get_finalized_command('build_sphinx') - self.target_dir = build_sphinx.builder_target_dir - else: - build = self.get_finalized_command('build') - self.target_dir = os.path.join(build.build_base, 'docs') - else: - self.ensure_dirname('upload_dir') - self.target_dir = self.upload_dir - if 'pypi.python.org' in self.repository: - log.warn("Upload_docs command is deprecated. Use RTD instead.") - self.announce('Using upload directory %s' % self.target_dir) - - def create_zipfile(self, filename): - zip_file = zipfile.ZipFile(filename, "w") - try: - self.mkpath(self.target_dir) # just in case - for root, dirs, files in os.walk(self.target_dir): - if root == self.target_dir and not files: - tmpl = "no files found in upload directory '%s'" - raise DistutilsOptionError(tmpl % self.target_dir) - for name in files: - full = os.path.join(root, name) - relative = root[len(self.target_dir):].lstrip(os.path.sep) - dest = os.path.join(relative, name) - zip_file.write(full, dest) - finally: - zip_file.close() - - def run(self): - # Run sub commands - for cmd_name in self.get_sub_commands(): - self.run_command(cmd_name) - - tmp_dir = tempfile.mkdtemp() - name = self.distribution.metadata.get_name() - zip_file = os.path.join(tmp_dir, "%s.zip" % name) - try: - self.create_zipfile(zip_file) - self.upload_file(zip_file) - finally: - shutil.rmtree(tmp_dir) - - @staticmethod - def _build_part(item, sep_boundary): - key, values = item - title = '\nContent-Disposition: form-data; name="%s"' % key - # handle multiple entries for the same name - if not isinstance(values, list): - values = [values] - for value in values: - if isinstance(value, tuple): - title += '; filename="%s"' % value[0] - value = value[1] - else: - value = _encode(value) - yield sep_boundary - yield _encode(title) - yield b"\n\n" - yield value - if value and value[-1:] == b'\r': - yield b'\n' # write an extra newline (lurve Macs) - - @classmethod - def _build_multipart(cls, data): - """ - Build up the MIME payload for the POST data - """ - boundary = b'--------------GHSKFJDLGDS7543FJKLFHRE75642756743254' - sep_boundary = b'\n--' + boundary - end_boundary = sep_boundary + b'--' - end_items = end_boundary, b"\n", - builder = functools.partial( - cls._build_part, - sep_boundary=sep_boundary, - ) - part_groups = map(builder, data.items()) - parts = itertools.chain.from_iterable(part_groups) - body_items = itertools.chain(parts, end_items) - content_type = 'multipart/form-data; boundary=%s' % boundary.decode('ascii') - return b''.join(body_items), content_type - - def upload_file(self, filename): - with open(filename, 'rb') as f: - content = f.read() - meta = self.distribution.metadata - data = { - ':action': 'doc_upload', - 'name': meta.get_name(), - 'content': (os.path.basename(filename), content), - } - # set up the authentication - credentials = _encode(self.username + ':' + self.password) - credentials = standard_b64encode(credentials) - if six.PY3: - credentials = credentials.decode('ascii') - auth = "Basic " + credentials - - body, ct = self._build_multipart(data) - - msg = "Submitting documentation to %s" % (self.repository) - self.announce(msg, log.INFO) - - # build the Request - # We can't use urllib2 since we need to send the Basic - # auth right with the first request - schema, netloc, url, params, query, fragments = \ - urllib.parse.urlparse(self.repository) - assert not params and not query and not fragments - if schema == 'http': - conn = http_client.HTTPConnection(netloc) - elif schema == 'https': - conn = http_client.HTTPSConnection(netloc) - else: - raise AssertionError("unsupported schema " + schema) - - data = '' - try: - conn.connect() - conn.putrequest("POST", url) - content_type = ct - conn.putheader('Content-type', content_type) - conn.putheader('Content-length', str(len(body))) - conn.putheader('Authorization', auth) - conn.endheaders() - conn.send(body) - except socket.error as e: - self.announce(str(e), log.ERROR) - return - - r = conn.getresponse() - if r.status == 200: - msg = 'Server response (%s): %s' % (r.status, r.reason) - self.announce(msg, log.INFO) - elif r.status == 301: - location = r.getheader('Location') - if location is None: - location = 'https://pythonhosted.org/%s/' % meta.get_name() - msg = 'Upload successful. Visit %s' % location - self.announce(msg, log.INFO) - else: - msg = 'Upload failed (%s): %s' % (r.status, r.reason) - self.announce(msg, log.ERROR) - if self.show_response: - print('-' * 75, r.read(), '-' * 75) diff --git a/venv/lib/python3.8/site-packages/setuptools/config.py b/venv/lib/python3.8/site-packages/setuptools/config.py deleted file mode 100644 index 9b9a0c4..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/config.py +++ /dev/null @@ -1,659 +0,0 @@ -from __future__ import absolute_import, unicode_literals -import io -import os -import sys - -import warnings -import functools -from collections import defaultdict -from functools import partial -from functools import wraps -from importlib import import_module - -from distutils.errors import DistutilsOptionError, DistutilsFileError -from setuptools.extern.packaging.version import LegacyVersion, parse -from setuptools.extern.packaging.specifiers import SpecifierSet -from setuptools.extern.six import string_types, PY3 - - -__metaclass__ = type - - -def read_configuration( - filepath, find_others=False, ignore_option_errors=False): - """Read given configuration file and returns options from it as a dict. - - :param str|unicode filepath: Path to configuration file - to get options from. - - :param bool find_others: Whether to search for other configuration files - which could be on in various places. - - :param bool ignore_option_errors: Whether to silently ignore - options, values of which could not be resolved (e.g. due to exceptions - in directives such as file:, attr:, etc.). - If False exceptions are propagated as expected. - - :rtype: dict - """ - from setuptools.dist import Distribution, _Distribution - - filepath = os.path.abspath(filepath) - - if not os.path.isfile(filepath): - raise DistutilsFileError( - 'Configuration file %s does not exist.' % filepath) - - current_directory = os.getcwd() - os.chdir(os.path.dirname(filepath)) - - try: - dist = Distribution() - - filenames = dist.find_config_files() if find_others else [] - if filepath not in filenames: - filenames.append(filepath) - - _Distribution.parse_config_files(dist, filenames=filenames) - - handlers = parse_configuration( - dist, dist.command_options, - ignore_option_errors=ignore_option_errors) - - finally: - os.chdir(current_directory) - - return configuration_to_dict(handlers) - - -def _get_option(target_obj, key): - """ - Given a target object and option key, get that option from - the target object, either through a get_{key} method or - from an attribute directly. - """ - getter_name = 'get_{key}'.format(**locals()) - by_attribute = functools.partial(getattr, target_obj, key) - getter = getattr(target_obj, getter_name, by_attribute) - return getter() - - -def configuration_to_dict(handlers): - """Returns configuration data gathered by given handlers as a dict. - - :param list[ConfigHandler] handlers: Handlers list, - usually from parse_configuration() - - :rtype: dict - """ - config_dict = defaultdict(dict) - - for handler in handlers: - for option in handler.set_options: - value = _get_option(handler.target_obj, option) - config_dict[handler.section_prefix][option] = value - - return config_dict - - -def parse_configuration( - distribution, command_options, ignore_option_errors=False): - """Performs additional parsing of configuration options - for a distribution. - - Returns a list of used option handlers. - - :param Distribution distribution: - :param dict command_options: - :param bool ignore_option_errors: Whether to silently ignore - options, values of which could not be resolved (e.g. due to exceptions - in directives such as file:, attr:, etc.). - If False exceptions are propagated as expected. - :rtype: list - """ - options = ConfigOptionsHandler( - distribution, command_options, ignore_option_errors) - options.parse() - - meta = ConfigMetadataHandler( - distribution.metadata, command_options, ignore_option_errors, - distribution.package_dir) - meta.parse() - - return meta, options - - -class ConfigHandler: - """Handles metadata supplied in configuration files.""" - - section_prefix = None - """Prefix for config sections handled by this handler. - Must be provided by class heirs. - - """ - - aliases = {} - """Options aliases. - For compatibility with various packages. E.g.: d2to1 and pbr. - Note: `-` in keys is replaced with `_` by config parser. - - """ - - def __init__(self, target_obj, options, ignore_option_errors=False): - sections = {} - - section_prefix = self.section_prefix - for section_name, section_options in options.items(): - if not section_name.startswith(section_prefix): - continue - - section_name = section_name.replace(section_prefix, '').strip('.') - sections[section_name] = section_options - - self.ignore_option_errors = ignore_option_errors - self.target_obj = target_obj - self.sections = sections - self.set_options = [] - - @property - def parsers(self): - """Metadata item name to parser function mapping.""" - raise NotImplementedError( - '%s must provide .parsers property' % self.__class__.__name__) - - def __setitem__(self, option_name, value): - unknown = tuple() - target_obj = self.target_obj - - # Translate alias into real name. - option_name = self.aliases.get(option_name, option_name) - - current_value = getattr(target_obj, option_name, unknown) - - if current_value is unknown: - raise KeyError(option_name) - - if current_value: - # Already inhabited. Skipping. - return - - skip_option = False - parser = self.parsers.get(option_name) - if parser: - try: - value = parser(value) - - except Exception: - skip_option = True - if not self.ignore_option_errors: - raise - - if skip_option: - return - - setter = getattr(target_obj, 'set_%s' % option_name, None) - if setter is None: - setattr(target_obj, option_name, value) - else: - setter(value) - - self.set_options.append(option_name) - - @classmethod - def _parse_list(cls, value, separator=','): - """Represents value as a list. - - Value is split either by separator (defaults to comma) or by lines. - - :param value: - :param separator: List items separator character. - :rtype: list - """ - if isinstance(value, list): # _get_parser_compound case - return value - - if '\n' in value: - value = value.splitlines() - else: - value = value.split(separator) - - return [chunk.strip() for chunk in value if chunk.strip()] - - @classmethod - def _parse_dict(cls, value): - """Represents value as a dict. - - :param value: - :rtype: dict - """ - separator = '=' - result = {} - for line in cls._parse_list(value): - key, sep, val = line.partition(separator) - if sep != separator: - raise DistutilsOptionError( - 'Unable to parse option value to dict: %s' % value) - result[key.strip()] = val.strip() - - return result - - @classmethod - def _parse_bool(cls, value): - """Represents value as boolean. - - :param value: - :rtype: bool - """ - value = value.lower() - return value in ('1', 'true', 'yes') - - @classmethod - def _exclude_files_parser(cls, key): - """Returns a parser function to make sure field inputs - are not files. - - Parses a value after getting the key so error messages are - more informative. - - :param key: - :rtype: callable - """ - def parser(value): - exclude_directive = 'file:' - if value.startswith(exclude_directive): - raise ValueError( - 'Only strings are accepted for the {0} field, ' - 'files are not accepted'.format(key)) - return value - return parser - - @classmethod - def _parse_file(cls, value): - """Represents value as a string, allowing including text - from nearest files using `file:` directive. - - Directive is sandboxed and won't reach anything outside - directory with setup.py. - - Examples: - file: README.rst, CHANGELOG.md, src/file.txt - - :param str value: - :rtype: str - """ - include_directive = 'file:' - - if not isinstance(value, string_types): - return value - - if not value.startswith(include_directive): - return value - - spec = value[len(include_directive):] - filepaths = (os.path.abspath(path.strip()) for path in spec.split(',')) - return '\n'.join( - cls._read_file(path) - for path in filepaths - if (cls._assert_local(path) or True) - and os.path.isfile(path) - ) - - @staticmethod - def _assert_local(filepath): - if not filepath.startswith(os.getcwd()): - raise DistutilsOptionError( - '`file:` directive can not access %s' % filepath) - - @staticmethod - def _read_file(filepath): - with io.open(filepath, encoding='utf-8') as f: - return f.read() - - @classmethod - def _parse_attr(cls, value, package_dir=None): - """Represents value as a module attribute. - - Examples: - attr: package.attr - attr: package.module.attr - - :param str value: - :rtype: str - """ - attr_directive = 'attr:' - if not value.startswith(attr_directive): - return value - - attrs_path = value.replace(attr_directive, '').strip().split('.') - attr_name = attrs_path.pop() - - module_name = '.'.join(attrs_path) - module_name = module_name or '__init__' - - parent_path = os.getcwd() - if package_dir: - if attrs_path[0] in package_dir: - # A custom path was specified for the module we want to import - custom_path = package_dir[attrs_path[0]] - parts = custom_path.rsplit('/', 1) - if len(parts) > 1: - parent_path = os.path.join(os.getcwd(), parts[0]) - module_name = parts[1] - else: - module_name = custom_path - elif '' in package_dir: - # A custom parent directory was specified for all root modules - parent_path = os.path.join(os.getcwd(), package_dir['']) - sys.path.insert(0, parent_path) - try: - module = import_module(module_name) - value = getattr(module, attr_name) - - finally: - sys.path = sys.path[1:] - - return value - - @classmethod - def _get_parser_compound(cls, *parse_methods): - """Returns parser function to represents value as a list. - - Parses a value applying given methods one after another. - - :param parse_methods: - :rtype: callable - """ - def parse(value): - parsed = value - - for method in parse_methods: - parsed = method(parsed) - - return parsed - - return parse - - @classmethod - def _parse_section_to_dict(cls, section_options, values_parser=None): - """Parses section options into a dictionary. - - Optionally applies a given parser to values. - - :param dict section_options: - :param callable values_parser: - :rtype: dict - """ - value = {} - values_parser = values_parser or (lambda val: val) - for key, (_, val) in section_options.items(): - value[key] = values_parser(val) - return value - - def parse_section(self, section_options): - """Parses configuration file section. - - :param dict section_options: - """ - for (name, (_, value)) in section_options.items(): - try: - self[name] = value - - except KeyError: - pass # Keep silent for a new option may appear anytime. - - def parse(self): - """Parses configuration file items from one - or more related sections. - - """ - for section_name, section_options in self.sections.items(): - - method_postfix = '' - if section_name: # [section.option] variant - method_postfix = '_%s' % section_name - - section_parser_method = getattr( - self, - # Dots in section names are translated into dunderscores. - ('parse_section%s' % method_postfix).replace('.', '__'), - None) - - if section_parser_method is None: - raise DistutilsOptionError( - 'Unsupported distribution option section: [%s.%s]' % ( - self.section_prefix, section_name)) - - section_parser_method(section_options) - - def _deprecated_config_handler(self, func, msg, warning_class): - """ this function will wrap around parameters that are deprecated - - :param msg: deprecation message - :param warning_class: class of warning exception to be raised - :param func: function to be wrapped around - """ - @wraps(func) - def config_handler(*args, **kwargs): - warnings.warn(msg, warning_class) - return func(*args, **kwargs) - - return config_handler - - -class ConfigMetadataHandler(ConfigHandler): - - section_prefix = 'metadata' - - aliases = { - 'home_page': 'url', - 'summary': 'description', - 'classifier': 'classifiers', - 'platform': 'platforms', - } - - strict_mode = False - """We need to keep it loose, to be partially compatible with - `pbr` and `d2to1` packages which also uses `metadata` section. - - """ - - def __init__(self, target_obj, options, ignore_option_errors=False, - package_dir=None): - super(ConfigMetadataHandler, self).__init__(target_obj, options, - ignore_option_errors) - self.package_dir = package_dir - - @property - def parsers(self): - """Metadata item name to parser function mapping.""" - parse_list = self._parse_list - parse_file = self._parse_file - parse_dict = self._parse_dict - exclude_files_parser = self._exclude_files_parser - - return { - 'platforms': parse_list, - 'keywords': parse_list, - 'provides': parse_list, - 'requires': self._deprecated_config_handler( - parse_list, - "The requires parameter is deprecated, please use " - "install_requires for runtime dependencies.", - DeprecationWarning), - 'obsoletes': parse_list, - 'classifiers': self._get_parser_compound(parse_file, parse_list), - 'license': exclude_files_parser('license'), - 'license_files': parse_list, - 'description': parse_file, - 'long_description': parse_file, - 'version': self._parse_version, - 'project_urls': parse_dict, - } - - def _parse_version(self, value): - """Parses `version` option value. - - :param value: - :rtype: str - - """ - version = self._parse_file(value) - - if version != value: - version = version.strip() - # Be strict about versions loaded from file because it's easy to - # accidentally include newlines and other unintended content - if isinstance(parse(version), LegacyVersion): - tmpl = ( - 'Version loaded from {value} does not ' - 'comply with PEP 440: {version}' - ) - raise DistutilsOptionError(tmpl.format(**locals())) - - return version - - version = self._parse_attr(value, self.package_dir) - - if callable(version): - version = version() - - if not isinstance(version, string_types): - if hasattr(version, '__iter__'): - version = '.'.join(map(str, version)) - else: - version = '%s' % version - - return version - - -class ConfigOptionsHandler(ConfigHandler): - - section_prefix = 'options' - - @property - def parsers(self): - """Metadata item name to parser function mapping.""" - parse_list = self._parse_list - parse_list_semicolon = partial(self._parse_list, separator=';') - parse_bool = self._parse_bool - parse_dict = self._parse_dict - - return { - 'zip_safe': parse_bool, - 'use_2to3': parse_bool, - 'include_package_data': parse_bool, - 'package_dir': parse_dict, - 'use_2to3_fixers': parse_list, - 'use_2to3_exclude_fixers': parse_list, - 'convert_2to3_doctests': parse_list, - 'scripts': parse_list, - 'eager_resources': parse_list, - 'dependency_links': parse_list, - 'namespace_packages': parse_list, - 'install_requires': parse_list_semicolon, - 'setup_requires': parse_list_semicolon, - 'tests_require': parse_list_semicolon, - 'packages': self._parse_packages, - 'entry_points': self._parse_file, - 'py_modules': parse_list, - 'python_requires': SpecifierSet, - } - - def _parse_packages(self, value): - """Parses `packages` option value. - - :param value: - :rtype: list - """ - find_directives = ['find:', 'find_namespace:'] - trimmed_value = value.strip() - - if trimmed_value not in find_directives: - return self._parse_list(value) - - findns = trimmed_value == find_directives[1] - if findns and not PY3: - raise DistutilsOptionError( - 'find_namespace: directive is unsupported on Python < 3.3') - - # Read function arguments from a dedicated section. - find_kwargs = self.parse_section_packages__find( - self.sections.get('packages.find', {})) - - if findns: - from setuptools import find_namespace_packages as find_packages - else: - from setuptools import find_packages - - return find_packages(**find_kwargs) - - def parse_section_packages__find(self, section_options): - """Parses `packages.find` configuration file section. - - To be used in conjunction with _parse_packages(). - - :param dict section_options: - """ - section_data = self._parse_section_to_dict( - section_options, self._parse_list) - - valid_keys = ['where', 'include', 'exclude'] - - find_kwargs = dict( - [(k, v) for k, v in section_data.items() if k in valid_keys and v]) - - where = find_kwargs.get('where') - if where is not None: - find_kwargs['where'] = where[0] # cast list to single val - - return find_kwargs - - def parse_section_entry_points(self, section_options): - """Parses `entry_points` configuration file section. - - :param dict section_options: - """ - parsed = self._parse_section_to_dict(section_options, self._parse_list) - self['entry_points'] = parsed - - def _parse_package_data(self, section_options): - parsed = self._parse_section_to_dict(section_options, self._parse_list) - - root = parsed.get('*') - if root: - parsed[''] = root - del parsed['*'] - - return parsed - - def parse_section_package_data(self, section_options): - """Parses `package_data` configuration file section. - - :param dict section_options: - """ - self['package_data'] = self._parse_package_data(section_options) - - def parse_section_exclude_package_data(self, section_options): - """Parses `exclude_package_data` configuration file section. - - :param dict section_options: - """ - self['exclude_package_data'] = self._parse_package_data( - section_options) - - def parse_section_extras_require(self, section_options): - """Parses `extras_require` configuration file section. - - :param dict section_options: - """ - parse_list = partial(self._parse_list, separator=';') - self['extras_require'] = self._parse_section_to_dict( - section_options, parse_list) - - def parse_section_data_files(self, section_options): - """Parses `data_files` configuration file section. - - :param dict section_options: - """ - parsed = self._parse_section_to_dict(section_options, self._parse_list) - self['data_files'] = [(k, v) for k, v in parsed.items()] diff --git a/venv/lib/python3.8/site-packages/setuptools/dep_util.py b/venv/lib/python3.8/site-packages/setuptools/dep_util.py deleted file mode 100644 index 2931c13..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/dep_util.py +++ /dev/null @@ -1,23 +0,0 @@ -from distutils.dep_util import newer_group - -# yes, this is was almost entirely copy-pasted from -# 'newer_pairwise()', this is just another convenience -# function. -def newer_pairwise_group(sources_groups, targets): - """Walk both arguments in parallel, testing if each source group is newer - than its corresponding target. Returns a pair of lists (sources_groups, - targets) where sources is newer than target, according to the semantics - of 'newer_group()'. - """ - if len(sources_groups) != len(targets): - raise ValueError("'sources_group' and 'targets' must be the same length") - - # build a pair of lists (sources_groups, targets) where source is newer - n_sources = [] - n_targets = [] - for i in range(len(sources_groups)): - if newer_group(sources_groups[i], targets[i]): - n_sources.append(sources_groups[i]) - n_targets.append(targets[i]) - - return n_sources, n_targets diff --git a/venv/lib/python3.8/site-packages/setuptools/depends.py b/venv/lib/python3.8/site-packages/setuptools/depends.py deleted file mode 100644 index a37675c..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/depends.py +++ /dev/null @@ -1,176 +0,0 @@ -import sys -import marshal -import contextlib -from distutils.version import StrictVersion - -from .py33compat import Bytecode - -from .py27compat import find_module, PY_COMPILED, PY_FROZEN, PY_SOURCE -from . import py27compat - - -__all__ = [ - 'Require', 'find_module', 'get_module_constant', 'extract_constant' -] - - -class Require: - """A prerequisite to building or installing a distribution""" - - def __init__( - self, name, requested_version, module, homepage='', - attribute=None, format=None): - - if format is None and requested_version is not None: - format = StrictVersion - - if format is not None: - requested_version = format(requested_version) - if attribute is None: - attribute = '__version__' - - self.__dict__.update(locals()) - del self.self - - def full_name(self): - """Return full package/distribution name, w/version""" - if self.requested_version is not None: - return '%s-%s' % (self.name, self.requested_version) - return self.name - - def version_ok(self, version): - """Is 'version' sufficiently up-to-date?""" - return self.attribute is None or self.format is None or \ - str(version) != "unknown" and version >= self.requested_version - - def get_version(self, paths=None, default="unknown"): - """Get version number of installed module, 'None', or 'default' - - Search 'paths' for module. If not found, return 'None'. If found, - return the extracted version attribute, or 'default' if no version - attribute was specified, or the value cannot be determined without - importing the module. The version is formatted according to the - requirement's version format (if any), unless it is 'None' or the - supplied 'default'. - """ - - if self.attribute is None: - try: - f, p, i = find_module(self.module, paths) - if f: - f.close() - return default - except ImportError: - return None - - v = get_module_constant(self.module, self.attribute, default, paths) - - if v is not None and v is not default and self.format is not None: - return self.format(v) - - return v - - def is_present(self, paths=None): - """Return true if dependency is present on 'paths'""" - return self.get_version(paths) is not None - - def is_current(self, paths=None): - """Return true if dependency is present and up-to-date on 'paths'""" - version = self.get_version(paths) - if version is None: - return False - return self.version_ok(version) - - -def maybe_close(f): - @contextlib.contextmanager - def empty(): - yield - return - if not f: - return empty() - - return contextlib.closing(f) - - -def get_module_constant(module, symbol, default=-1, paths=None): - """Find 'module' by searching 'paths', and extract 'symbol' - - Return 'None' if 'module' does not exist on 'paths', or it does not define - 'symbol'. If the module defines 'symbol' as a constant, return the - constant. Otherwise, return 'default'.""" - - try: - f, path, (suffix, mode, kind) = info = find_module(module, paths) - except ImportError: - # Module doesn't exist - return None - - with maybe_close(f): - if kind == PY_COMPILED: - f.read(8) # skip magic & date - code = marshal.load(f) - elif kind == PY_FROZEN: - code = py27compat.get_frozen_object(module, paths) - elif kind == PY_SOURCE: - code = compile(f.read(), path, 'exec') - else: - # Not something we can parse; we'll have to import it. :( - imported = py27compat.get_module(module, paths, info) - return getattr(imported, symbol, None) - - return extract_constant(code, symbol, default) - - -def extract_constant(code, symbol, default=-1): - """Extract the constant value of 'symbol' from 'code' - - If the name 'symbol' is bound to a constant value by the Python code - object 'code', return that value. If 'symbol' is bound to an expression, - return 'default'. Otherwise, return 'None'. - - Return value is based on the first assignment to 'symbol'. 'symbol' must - be a global, or at least a non-"fast" local in the code block. That is, - only 'STORE_NAME' and 'STORE_GLOBAL' opcodes are checked, and 'symbol' - must be present in 'code.co_names'. - """ - if symbol not in code.co_names: - # name's not there, can't possibly be an assignment - return None - - name_idx = list(code.co_names).index(symbol) - - STORE_NAME = 90 - STORE_GLOBAL = 97 - LOAD_CONST = 100 - - const = default - - for byte_code in Bytecode(code): - op = byte_code.opcode - arg = byte_code.arg - - if op == LOAD_CONST: - const = code.co_consts[arg] - elif arg == name_idx and (op == STORE_NAME or op == STORE_GLOBAL): - return const - else: - const = default - - -def _update_globals(): - """ - Patch the globals to remove the objects not available on some platforms. - - XXX it'd be better to test assertions about bytecode instead. - """ - - if not sys.platform.startswith('java') and sys.platform != 'cli': - return - incompatible = 'extract_constant', 'get_module_constant' - for name in incompatible: - del globals()[name] - __all__.remove(name) - - -_update_globals() diff --git a/venv/lib/python3.8/site-packages/setuptools/dist.py b/venv/lib/python3.8/site-packages/setuptools/dist.py deleted file mode 100644 index f22429e..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/dist.py +++ /dev/null @@ -1,1274 +0,0 @@ -# -*- coding: utf-8 -*- -__all__ = ['Distribution'] - -import io -import sys -import re -import os -import warnings -import numbers -import distutils.log -import distutils.core -import distutils.cmd -import distutils.dist -from distutils.util import strtobool -from distutils.debug import DEBUG -from distutils.fancy_getopt import translate_longopt -import itertools - -from collections import defaultdict -from email import message_from_file - -from distutils.errors import ( - DistutilsOptionError, DistutilsPlatformError, DistutilsSetupError, -) -from distutils.util import rfc822_escape -from distutils.version import StrictVersion - -from setuptools.extern import six -from setuptools.extern import packaging -from setuptools.extern import ordered_set -from setuptools.extern.six.moves import map, filter, filterfalse - -from . import SetuptoolsDeprecationWarning - -from setuptools.depends import Require -from setuptools import windows_support -from setuptools.monkey import get_unpatched -from setuptools.config import parse_configuration -import pkg_resources - -__import__('setuptools.extern.packaging.specifiers') -__import__('setuptools.extern.packaging.version') - - -def _get_unpatched(cls): - warnings.warn("Do not call this function", DistDeprecationWarning) - return get_unpatched(cls) - - -def get_metadata_version(self): - mv = getattr(self, 'metadata_version', None) - - if mv is None: - if self.long_description_content_type or self.provides_extras: - mv = StrictVersion('2.1') - elif (self.maintainer is not None or - self.maintainer_email is not None or - getattr(self, 'python_requires', None) is not None or - self.project_urls): - mv = StrictVersion('1.2') - elif (self.provides or self.requires or self.obsoletes or - self.classifiers or self.download_url): - mv = StrictVersion('1.1') - else: - mv = StrictVersion('1.0') - - self.metadata_version = mv - - return mv - - -def read_pkg_file(self, file): - """Reads the metadata values from a file object.""" - msg = message_from_file(file) - - def _read_field(name): - value = msg[name] - if value == 'UNKNOWN': - return None - return value - - def _read_list(name): - values = msg.get_all(name, None) - if values == []: - return None - return values - - self.metadata_version = StrictVersion(msg['metadata-version']) - self.name = _read_field('name') - self.version = _read_field('version') - self.description = _read_field('summary') - # we are filling author only. - self.author = _read_field('author') - self.maintainer = None - self.author_email = _read_field('author-email') - self.maintainer_email = None - self.url = _read_field('home-page') - self.license = _read_field('license') - - if 'download-url' in msg: - self.download_url = _read_field('download-url') - else: - self.download_url = None - - self.long_description = _read_field('description') - self.description = _read_field('summary') - - if 'keywords' in msg: - self.keywords = _read_field('keywords').split(',') - - self.platforms = _read_list('platform') - self.classifiers = _read_list('classifier') - - # PEP 314 - these fields only exist in 1.1 - if self.metadata_version == StrictVersion('1.1'): - self.requires = _read_list('requires') - self.provides = _read_list('provides') - self.obsoletes = _read_list('obsoletes') - else: - self.requires = None - self.provides = None - self.obsoletes = None - - -# Based on Python 3.5 version -def write_pkg_file(self, file): - """Write the PKG-INFO format data to a file object. - """ - version = self.get_metadata_version() - - if six.PY2: - def write_field(key, value): - file.write("%s: %s\n" % (key, self._encode_field(value))) - else: - def write_field(key, value): - file.write("%s: %s\n" % (key, value)) - - write_field('Metadata-Version', str(version)) - write_field('Name', self.get_name()) - write_field('Version', self.get_version()) - write_field('Summary', self.get_description()) - write_field('Home-page', self.get_url()) - - if version < StrictVersion('1.2'): - write_field('Author', self.get_contact()) - write_field('Author-email', self.get_contact_email()) - else: - optional_fields = ( - ('Author', 'author'), - ('Author-email', 'author_email'), - ('Maintainer', 'maintainer'), - ('Maintainer-email', 'maintainer_email'), - ) - - for field, attr in optional_fields: - attr_val = getattr(self, attr) - - if attr_val is not None: - write_field(field, attr_val) - - write_field('License', self.get_license()) - if self.download_url: - write_field('Download-URL', self.download_url) - for project_url in self.project_urls.items(): - write_field('Project-URL', '%s, %s' % project_url) - - long_desc = rfc822_escape(self.get_long_description()) - write_field('Description', long_desc) - - keywords = ','.join(self.get_keywords()) - if keywords: - write_field('Keywords', keywords) - - if version >= StrictVersion('1.2'): - for platform in self.get_platforms(): - write_field('Platform', platform) - else: - self._write_list(file, 'Platform', self.get_platforms()) - - self._write_list(file, 'Classifier', self.get_classifiers()) - - # PEP 314 - self._write_list(file, 'Requires', self.get_requires()) - self._write_list(file, 'Provides', self.get_provides()) - self._write_list(file, 'Obsoletes', self.get_obsoletes()) - - # Setuptools specific for PEP 345 - if hasattr(self, 'python_requires'): - write_field('Requires-Python', self.python_requires) - - # PEP 566 - if self.long_description_content_type: - write_field( - 'Description-Content-Type', - self.long_description_content_type - ) - if self.provides_extras: - for extra in sorted(self.provides_extras): - write_field('Provides-Extra', extra) - - -sequence = tuple, list - - -def check_importable(dist, attr, value): - try: - ep = pkg_resources.EntryPoint.parse('x=' + value) - assert not ep.extras - except (TypeError, ValueError, AttributeError, AssertionError): - raise DistutilsSetupError( - "%r must be importable 'module:attrs' string (got %r)" - % (attr, value) - ) - - -def assert_string_list(dist, attr, value): - """Verify that value is a string list""" - try: - # verify that value is a list or tuple to exclude unordered - # or single-use iterables - assert isinstance(value, (list, tuple)) - # verify that elements of value are strings - assert ''.join(value) != value - except (TypeError, ValueError, AttributeError, AssertionError): - raise DistutilsSetupError( - "%r must be a list of strings (got %r)" % (attr, value) - ) - - -def check_nsp(dist, attr, value): - """Verify that namespace packages are valid""" - ns_packages = value - assert_string_list(dist, attr, ns_packages) - for nsp in ns_packages: - if not dist.has_contents_for(nsp): - raise DistutilsSetupError( - "Distribution contains no modules or packages for " + - "namespace package %r" % nsp - ) - parent, sep, child = nsp.rpartition('.') - if parent and parent not in ns_packages: - distutils.log.warn( - "WARNING: %r is declared as a package namespace, but %r" - " is not: please correct this in setup.py", nsp, parent - ) - - -def check_extras(dist, attr, value): - """Verify that extras_require mapping is valid""" - try: - list(itertools.starmap(_check_extra, value.items())) - except (TypeError, ValueError, AttributeError): - raise DistutilsSetupError( - "'extras_require' must be a dictionary whose values are " - "strings or lists of strings containing valid project/version " - "requirement specifiers." - ) - - -def _check_extra(extra, reqs): - name, sep, marker = extra.partition(':') - if marker and pkg_resources.invalid_marker(marker): - raise DistutilsSetupError("Invalid environment marker: " + marker) - list(pkg_resources.parse_requirements(reqs)) - - -def assert_bool(dist, attr, value): - """Verify that value is True, False, 0, or 1""" - if bool(value) != value: - tmpl = "{attr!r} must be a boolean value (got {value!r})" - raise DistutilsSetupError(tmpl.format(attr=attr, value=value)) - - -def check_requirements(dist, attr, value): - """Verify that install_requires is a valid requirements list""" - try: - list(pkg_resources.parse_requirements(value)) - if isinstance(value, (dict, set)): - raise TypeError("Unordered types are not allowed") - except (TypeError, ValueError) as error: - tmpl = ( - "{attr!r} must be a string or list of strings " - "containing valid project/version requirement specifiers; {error}" - ) - raise DistutilsSetupError(tmpl.format(attr=attr, error=error)) - - -def check_specifier(dist, attr, value): - """Verify that value is a valid version specifier""" - try: - packaging.specifiers.SpecifierSet(value) - except packaging.specifiers.InvalidSpecifier as error: - tmpl = ( - "{attr!r} must be a string " - "containing valid version specifiers; {error}" - ) - raise DistutilsSetupError(tmpl.format(attr=attr, error=error)) - - -def check_entry_points(dist, attr, value): - """Verify that entry_points map is parseable""" - try: - pkg_resources.EntryPoint.parse_map(value) - except ValueError as e: - raise DistutilsSetupError(e) - - -def check_test_suite(dist, attr, value): - if not isinstance(value, six.string_types): - raise DistutilsSetupError("test_suite must be a string") - - -def check_package_data(dist, attr, value): - """Verify that value is a dictionary of package names to glob lists""" - if not isinstance(value, dict): - raise DistutilsSetupError( - "{!r} must be a dictionary mapping package names to lists of " - "string wildcard patterns".format(attr)) - for k, v in value.items(): - if not isinstance(k, six.string_types): - raise DistutilsSetupError( - "keys of {!r} dict must be strings (got {!r})" - .format(attr, k) - ) - assert_string_list(dist, 'values of {!r} dict'.format(attr), v) - - -def check_packages(dist, attr, value): - for pkgname in value: - if not re.match(r'\w+(\.\w+)*', pkgname): - distutils.log.warn( - "WARNING: %r not a valid package name; please use only " - ".-separated package names in setup.py", pkgname - ) - - -_Distribution = get_unpatched(distutils.core.Distribution) - - -class Distribution(_Distribution): - """Distribution with support for features, tests, and package data - - This is an enhanced version of 'distutils.dist.Distribution' that - effectively adds the following new optional keyword arguments to 'setup()': - - 'install_requires' -- a string or sequence of strings specifying project - versions that the distribution requires when installed, in the format - used by 'pkg_resources.require()'. They will be installed - automatically when the package is installed. If you wish to use - packages that are not available in PyPI, or want to give your users an - alternate download location, you can add a 'find_links' option to the - '[easy_install]' section of your project's 'setup.cfg' file, and then - setuptools will scan the listed web pages for links that satisfy the - requirements. - - 'extras_require' -- a dictionary mapping names of optional "extras" to the - additional requirement(s) that using those extras incurs. For example, - this:: - - extras_require = dict(reST = ["docutils>=0.3", "reSTedit"]) - - indicates that the distribution can optionally provide an extra - capability called "reST", but it can only be used if docutils and - reSTedit are installed. If the user installs your package using - EasyInstall and requests one of your extras, the corresponding - additional requirements will be installed if needed. - - 'features' **deprecated** -- a dictionary mapping option names to - 'setuptools.Feature' - objects. Features are a portion of the distribution that can be - included or excluded based on user options, inter-feature dependencies, - and availability on the current system. Excluded features are omitted - from all setup commands, including source and binary distributions, so - you can create multiple distributions from the same source tree. - Feature names should be valid Python identifiers, except that they may - contain the '-' (minus) sign. Features can be included or excluded - via the command line options '--with-X' and '--without-X', where 'X' is - the name of the feature. Whether a feature is included by default, and - whether you are allowed to control this from the command line, is - determined by the Feature object. See the 'Feature' class for more - information. - - 'test_suite' -- the name of a test suite to run for the 'test' command. - If the user runs 'python setup.py test', the package will be installed, - and the named test suite will be run. The format is the same as - would be used on a 'unittest.py' command line. That is, it is the - dotted name of an object to import and call to generate a test suite. - - 'package_data' -- a dictionary mapping package names to lists of filenames - or globs to use to find data files contained in the named packages. - If the dictionary has filenames or globs listed under '""' (the empty - string), those names will be searched for in every package, in addition - to any names for the specific package. Data files found using these - names/globs will be installed along with the package, in the same - location as the package. Note that globs are allowed to reference - the contents of non-package subdirectories, as long as you use '/' as - a path separator. (Globs are automatically converted to - platform-specific paths at runtime.) - - In addition to these new keywords, this class also has several new methods - for manipulating the distribution's contents. For example, the 'include()' - and 'exclude()' methods can be thought of as in-place add and subtract - commands that add or remove packages, modules, extensions, and so on from - the distribution. They are used by the feature subsystem to configure the - distribution for the included and excluded features. - """ - - _DISTUTILS_UNSUPPORTED_METADATA = { - 'long_description_content_type': None, - 'project_urls': dict, - 'provides_extras': ordered_set.OrderedSet, - 'license_files': ordered_set.OrderedSet, - } - - _patched_dist = None - - def patch_missing_pkg_info(self, attrs): - # Fake up a replacement for the data that would normally come from - # PKG-INFO, but which might not yet be built if this is a fresh - # checkout. - # - if not attrs or 'name' not in attrs or 'version' not in attrs: - return - key = pkg_resources.safe_name(str(attrs['name'])).lower() - dist = pkg_resources.working_set.by_key.get(key) - if dist is not None and not dist.has_metadata('PKG-INFO'): - dist._version = pkg_resources.safe_version(str(attrs['version'])) - self._patched_dist = dist - - def __init__(self, attrs=None): - have_package_data = hasattr(self, "package_data") - if not have_package_data: - self.package_data = {} - attrs = attrs or {} - if 'features' in attrs or 'require_features' in attrs: - Feature.warn_deprecated() - self.require_features = [] - self.features = {} - self.dist_files = [] - # Filter-out setuptools' specific options. - self.src_root = attrs.pop("src_root", None) - self.patch_missing_pkg_info(attrs) - self.dependency_links = attrs.pop('dependency_links', []) - self.setup_requires = attrs.pop('setup_requires', []) - for ep in pkg_resources.iter_entry_points('distutils.setup_keywords'): - vars(self).setdefault(ep.name, None) - _Distribution.__init__(self, { - k: v for k, v in attrs.items() - if k not in self._DISTUTILS_UNSUPPORTED_METADATA - }) - - # Fill-in missing metadata fields not supported by distutils. - # Note some fields may have been set by other tools (e.g. pbr) - # above; they are taken preferrentially to setup() arguments - for option, default in self._DISTUTILS_UNSUPPORTED_METADATA.items(): - for source in self.metadata.__dict__, attrs: - if option in source: - value = source[option] - break - else: - value = default() if default else None - setattr(self.metadata, option, value) - - if isinstance(self.metadata.version, numbers.Number): - # Some people apparently take "version number" too literally :) - self.metadata.version = str(self.metadata.version) - - if self.metadata.version is not None: - try: - ver = packaging.version.Version(self.metadata.version) - normalized_version = str(ver) - if self.metadata.version != normalized_version: - warnings.warn( - "Normalizing '%s' to '%s'" % ( - self.metadata.version, - normalized_version, - ) - ) - self.metadata.version = normalized_version - except (packaging.version.InvalidVersion, TypeError): - warnings.warn( - "The version specified (%r) is an invalid version, this " - "may not work as expected with newer versions of " - "setuptools, pip, and PyPI. Please see PEP 440 for more " - "details." % self.metadata.version - ) - self._finalize_requires() - - def _finalize_requires(self): - """ - Set `metadata.python_requires` and fix environment markers - in `install_requires` and `extras_require`. - """ - if getattr(self, 'python_requires', None): - self.metadata.python_requires = self.python_requires - - if getattr(self, 'extras_require', None): - for extra in self.extras_require.keys(): - # Since this gets called multiple times at points where the - # keys have become 'converted' extras, ensure that we are only - # truly adding extras we haven't seen before here. - extra = extra.split(':')[0] - if extra: - self.metadata.provides_extras.add(extra) - - self._convert_extras_requirements() - self._move_install_requirements_markers() - - def _convert_extras_requirements(self): - """ - Convert requirements in `extras_require` of the form - `"extra": ["barbazquux; {marker}"]` to - `"extra:{marker}": ["barbazquux"]`. - """ - spec_ext_reqs = getattr(self, 'extras_require', None) or {} - self._tmp_extras_require = defaultdict(list) - for section, v in spec_ext_reqs.items(): - # Do not strip empty sections. - self._tmp_extras_require[section] - for r in pkg_resources.parse_requirements(v): - suffix = self._suffix_for(r) - self._tmp_extras_require[section + suffix].append(r) - - @staticmethod - def _suffix_for(req): - """ - For a requirement, return the 'extras_require' suffix for - that requirement. - """ - return ':' + str(req.marker) if req.marker else '' - - def _move_install_requirements_markers(self): - """ - Move requirements in `install_requires` that are using environment - markers `extras_require`. - """ - - # divide the install_requires into two sets, simple ones still - # handled by install_requires and more complex ones handled - # by extras_require. - - def is_simple_req(req): - return not req.marker - - spec_inst_reqs = getattr(self, 'install_requires', None) or () - inst_reqs = list(pkg_resources.parse_requirements(spec_inst_reqs)) - simple_reqs = filter(is_simple_req, inst_reqs) - complex_reqs = filterfalse(is_simple_req, inst_reqs) - self.install_requires = list(map(str, simple_reqs)) - - for r in complex_reqs: - self._tmp_extras_require[':' + str(r.marker)].append(r) - self.extras_require = dict( - (k, [str(r) for r in map(self._clean_req, v)]) - for k, v in self._tmp_extras_require.items() - ) - - def _clean_req(self, req): - """ - Given a Requirement, remove environment markers and return it. - """ - req.marker = None - return req - - def _parse_config_files(self, filenames=None): - """ - Adapted from distutils.dist.Distribution.parse_config_files, - this method provides the same functionality in subtly-improved - ways. - """ - from setuptools.extern.six.moves.configparser import ConfigParser - - # Ignore install directory options if we have a venv - if six.PY3 and sys.prefix != sys.base_prefix: - ignore_options = [ - 'install-base', 'install-platbase', 'install-lib', - 'install-platlib', 'install-purelib', 'install-headers', - 'install-scripts', 'install-data', 'prefix', 'exec-prefix', - 'home', 'user', 'root'] - else: - ignore_options = [] - - ignore_options = frozenset(ignore_options) - - if filenames is None: - filenames = self.find_config_files() - - if DEBUG: - self.announce("Distribution.parse_config_files():") - - parser = ConfigParser() - for filename in filenames: - with io.open(filename, encoding='utf-8') as reader: - if DEBUG: - self.announce(" reading {filename}".format(**locals())) - (parser.read_file if six.PY3 else parser.readfp)(reader) - for section in parser.sections(): - options = parser.options(section) - opt_dict = self.get_option_dict(section) - - for opt in options: - if opt != '__name__' and opt not in ignore_options: - val = self._try_str(parser.get(section, opt)) - opt = opt.replace('-', '_') - opt_dict[opt] = (filename, val) - - # Make the ConfigParser forget everything (so we retain - # the original filenames that options come from) - parser.__init__() - - # If there was a "global" section in the config file, use it - # to set Distribution options. - - if 'global' in self.command_options: - for (opt, (src, val)) in self.command_options['global'].items(): - alias = self.negative_opt.get(opt) - try: - if alias: - setattr(self, alias, not strtobool(val)) - elif opt in ('verbose', 'dry_run'): # ugh! - setattr(self, opt, strtobool(val)) - else: - setattr(self, opt, val) - except ValueError as msg: - raise DistutilsOptionError(msg) - - @staticmethod - def _try_str(val): - """ - On Python 2, much of distutils relies on string values being of - type 'str' (bytes) and not unicode text. If the value can be safely - encoded to bytes using the default encoding, prefer that. - - Why the default encoding? Because that value can be implicitly - decoded back to text if needed. - - Ref #1653 - """ - if six.PY3: - return val - try: - return val.encode() - except UnicodeEncodeError: - pass - return val - - def _set_command_options(self, command_obj, option_dict=None): - """ - Set the options for 'command_obj' from 'option_dict'. Basically - this means copying elements of a dictionary ('option_dict') to - attributes of an instance ('command'). - - 'command_obj' must be a Command instance. If 'option_dict' is not - supplied, uses the standard option dictionary for this command - (from 'self.command_options'). - - (Adopted from distutils.dist.Distribution._set_command_options) - """ - command_name = command_obj.get_command_name() - if option_dict is None: - option_dict = self.get_option_dict(command_name) - - if DEBUG: - self.announce(" setting options for '%s' command:" % command_name) - for (option, (source, value)) in option_dict.items(): - if DEBUG: - self.announce(" %s = %s (from %s)" % (option, value, - source)) - try: - bool_opts = [translate_longopt(o) - for o in command_obj.boolean_options] - except AttributeError: - bool_opts = [] - try: - neg_opt = command_obj.negative_opt - except AttributeError: - neg_opt = {} - - try: - is_string = isinstance(value, six.string_types) - if option in neg_opt and is_string: - setattr(command_obj, neg_opt[option], not strtobool(value)) - elif option in bool_opts and is_string: - setattr(command_obj, option, strtobool(value)) - elif hasattr(command_obj, option): - setattr(command_obj, option, value) - else: - raise DistutilsOptionError( - "error in %s: command '%s' has no such option '%s'" - % (source, command_name, option)) - except ValueError as msg: - raise DistutilsOptionError(msg) - - def parse_config_files(self, filenames=None, ignore_option_errors=False): - """Parses configuration files from various levels - and loads configuration. - - """ - self._parse_config_files(filenames=filenames) - - parse_configuration(self, self.command_options, - ignore_option_errors=ignore_option_errors) - self._finalize_requires() - - def parse_command_line(self): - """Process features after parsing command line options""" - result = _Distribution.parse_command_line(self) - if self.features: - self._finalize_features() - return result - - def _feature_attrname(self, name): - """Convert feature name to corresponding option attribute name""" - return 'with_' + name.replace('-', '_') - - def fetch_build_eggs(self, requires): - """Resolve pre-setup requirements""" - resolved_dists = pkg_resources.working_set.resolve( - pkg_resources.parse_requirements(requires), - installer=self.fetch_build_egg, - replace_conflicting=True, - ) - for dist in resolved_dists: - pkg_resources.working_set.add(dist, replace=True) - return resolved_dists - - def finalize_options(self): - """ - Allow plugins to apply arbitrary operations to the - distribution. Each hook may optionally define a 'order' - to influence the order of execution. Smaller numbers - go first and the default is 0. - """ - hook_key = 'setuptools.finalize_distribution_options' - - def by_order(hook): - return getattr(hook, 'order', 0) - eps = pkg_resources.iter_entry_points(hook_key) - for ep in sorted(eps, key=by_order): - ep.load()(self) - - def _finalize_setup_keywords(self): - for ep in pkg_resources.iter_entry_points('distutils.setup_keywords'): - value = getattr(self, ep.name, None) - if value is not None: - ep.require(installer=self.fetch_build_egg) - ep.load()(self, ep.name, value) - - def _finalize_2to3_doctests(self): - if getattr(self, 'convert_2to3_doctests', None): - # XXX may convert to set here when we can rely on set being builtin - self.convert_2to3_doctests = [ - os.path.abspath(p) - for p in self.convert_2to3_doctests - ] - else: - self.convert_2to3_doctests = [] - - def get_egg_cache_dir(self): - egg_cache_dir = os.path.join(os.curdir, '.eggs') - if not os.path.exists(egg_cache_dir): - os.mkdir(egg_cache_dir) - windows_support.hide_file(egg_cache_dir) - readme_txt_filename = os.path.join(egg_cache_dir, 'README.txt') - with open(readme_txt_filename, 'w') as f: - f.write('This directory contains eggs that were downloaded ' - 'by setuptools to build, test, and run plug-ins.\n\n') - f.write('This directory caches those eggs to prevent ' - 'repeated downloads.\n\n') - f.write('However, it is safe to delete this directory.\n\n') - - return egg_cache_dir - - def fetch_build_egg(self, req): - """Fetch an egg needed for building""" - from setuptools.installer import fetch_build_egg - return fetch_build_egg(self, req) - - def _finalize_feature_opts(self): - """Add --with-X/--without-X options based on optional features""" - - if not self.features: - return - - go = [] - no = self.negative_opt.copy() - - for name, feature in self.features.items(): - self._set_feature(name, None) - feature.validate(self) - - if feature.optional: - descr = feature.description - incdef = ' (default)' - excdef = '' - if not feature.include_by_default(): - excdef, incdef = incdef, excdef - - new = ( - ('with-' + name, None, 'include ' + descr + incdef), - ('without-' + name, None, 'exclude ' + descr + excdef), - ) - go.extend(new) - no['without-' + name] = 'with-' + name - - self.global_options = self.feature_options = go + self.global_options - self.negative_opt = self.feature_negopt = no - - def _finalize_features(self): - """Add/remove features and resolve dependencies between them""" - - # First, flag all the enabled items (and thus their dependencies) - for name, feature in self.features.items(): - enabled = self.feature_is_included(name) - if enabled or (enabled is None and feature.include_by_default()): - feature.include_in(self) - self._set_feature(name, 1) - - # Then disable the rest, so that off-by-default features don't - # get flagged as errors when they're required by an enabled feature - for name, feature in self.features.items(): - if not self.feature_is_included(name): - feature.exclude_from(self) - self._set_feature(name, 0) - - def get_command_class(self, command): - """Pluggable version of get_command_class()""" - if command in self.cmdclass: - return self.cmdclass[command] - - eps = pkg_resources.iter_entry_points('distutils.commands', command) - for ep in eps: - ep.require(installer=self.fetch_build_egg) - self.cmdclass[command] = cmdclass = ep.load() - return cmdclass - else: - return _Distribution.get_command_class(self, command) - - def print_commands(self): - for ep in pkg_resources.iter_entry_points('distutils.commands'): - if ep.name not in self.cmdclass: - # don't require extras as the commands won't be invoked - cmdclass = ep.resolve() - self.cmdclass[ep.name] = cmdclass - return _Distribution.print_commands(self) - - def get_command_list(self): - for ep in pkg_resources.iter_entry_points('distutils.commands'): - if ep.name not in self.cmdclass: - # don't require extras as the commands won't be invoked - cmdclass = ep.resolve() - self.cmdclass[ep.name] = cmdclass - return _Distribution.get_command_list(self) - - def _set_feature(self, name, status): - """Set feature's inclusion status""" - setattr(self, self._feature_attrname(name), status) - - def feature_is_included(self, name): - """Return 1 if feature is included, 0 if excluded, 'None' if unknown""" - return getattr(self, self._feature_attrname(name)) - - def include_feature(self, name): - """Request inclusion of feature named 'name'""" - - if self.feature_is_included(name) == 0: - descr = self.features[name].description - raise DistutilsOptionError( - descr + " is required, but was excluded or is not available" - ) - self.features[name].include_in(self) - self._set_feature(name, 1) - - def include(self, **attrs): - """Add items to distribution that are named in keyword arguments - - For example, 'dist.include(py_modules=["x"])' would add 'x' to - the distribution's 'py_modules' attribute, if it was not already - there. - - Currently, this method only supports inclusion for attributes that are - lists or tuples. If you need to add support for adding to other - attributes in this or a subclass, you can add an '_include_X' method, - where 'X' is the name of the attribute. The method will be called with - the value passed to 'include()'. So, 'dist.include(foo={"bar":"baz"})' - will try to call 'dist._include_foo({"bar":"baz"})', which can then - handle whatever special inclusion logic is needed. - """ - for k, v in attrs.items(): - include = getattr(self, '_include_' + k, None) - if include: - include(v) - else: - self._include_misc(k, v) - - def exclude_package(self, package): - """Remove packages, modules, and extensions in named package""" - - pfx = package + '.' - if self.packages: - self.packages = [ - p for p in self.packages - if p != package and not p.startswith(pfx) - ] - - if self.py_modules: - self.py_modules = [ - p for p in self.py_modules - if p != package and not p.startswith(pfx) - ] - - if self.ext_modules: - self.ext_modules = [ - p for p in self.ext_modules - if p.name != package and not p.name.startswith(pfx) - ] - - def has_contents_for(self, package): - """Return true if 'exclude_package(package)' would do something""" - - pfx = package + '.' - - for p in self.iter_distribution_names(): - if p == package or p.startswith(pfx): - return True - - def _exclude_misc(self, name, value): - """Handle 'exclude()' for list/tuple attrs without a special handler""" - if not isinstance(value, sequence): - raise DistutilsSetupError( - "%s: setting must be a list or tuple (%r)" % (name, value) - ) - try: - old = getattr(self, name) - except AttributeError: - raise DistutilsSetupError( - "%s: No such distribution setting" % name - ) - if old is not None and not isinstance(old, sequence): - raise DistutilsSetupError( - name + ": this setting cannot be changed via include/exclude" - ) - elif old: - setattr(self, name, [item for item in old if item not in value]) - - def _include_misc(self, name, value): - """Handle 'include()' for list/tuple attrs without a special handler""" - - if not isinstance(value, sequence): - raise DistutilsSetupError( - "%s: setting must be a list (%r)" % (name, value) - ) - try: - old = getattr(self, name) - except AttributeError: - raise DistutilsSetupError( - "%s: No such distribution setting" % name - ) - if old is None: - setattr(self, name, value) - elif not isinstance(old, sequence): - raise DistutilsSetupError( - name + ": this setting cannot be changed via include/exclude" - ) - else: - new = [item for item in value if item not in old] - setattr(self, name, old + new) - - def exclude(self, **attrs): - """Remove items from distribution that are named in keyword arguments - - For example, 'dist.exclude(py_modules=["x"])' would remove 'x' from - the distribution's 'py_modules' attribute. Excluding packages uses - the 'exclude_package()' method, so all of the package's contained - packages, modules, and extensions are also excluded. - - Currently, this method only supports exclusion from attributes that are - lists or tuples. If you need to add support for excluding from other - attributes in this or a subclass, you can add an '_exclude_X' method, - where 'X' is the name of the attribute. The method will be called with - the value passed to 'exclude()'. So, 'dist.exclude(foo={"bar":"baz"})' - will try to call 'dist._exclude_foo({"bar":"baz"})', which can then - handle whatever special exclusion logic is needed. - """ - for k, v in attrs.items(): - exclude = getattr(self, '_exclude_' + k, None) - if exclude: - exclude(v) - else: - self._exclude_misc(k, v) - - def _exclude_packages(self, packages): - if not isinstance(packages, sequence): - raise DistutilsSetupError( - "packages: setting must be a list or tuple (%r)" % (packages,) - ) - list(map(self.exclude_package, packages)) - - def _parse_command_opts(self, parser, args): - # Remove --with-X/--without-X options when processing command args - self.global_options = self.__class__.global_options - self.negative_opt = self.__class__.negative_opt - - # First, expand any aliases - command = args[0] - aliases = self.get_option_dict('aliases') - while command in aliases: - src, alias = aliases[command] - del aliases[command] # ensure each alias can expand only once! - import shlex - args[:1] = shlex.split(alias, True) - command = args[0] - - nargs = _Distribution._parse_command_opts(self, parser, args) - - # Handle commands that want to consume all remaining arguments - cmd_class = self.get_command_class(command) - if getattr(cmd_class, 'command_consumes_arguments', None): - self.get_option_dict(command)['args'] = ("command line", nargs) - if nargs is not None: - return [] - - return nargs - - def get_cmdline_options(self): - """Return a '{cmd: {opt:val}}' map of all command-line options - - Option names are all long, but do not include the leading '--', and - contain dashes rather than underscores. If the option doesn't take - an argument (e.g. '--quiet'), the 'val' is 'None'. - - Note that options provided by config files are intentionally excluded. - """ - - d = {} - - for cmd, opts in self.command_options.items(): - - for opt, (src, val) in opts.items(): - - if src != "command line": - continue - - opt = opt.replace('_', '-') - - if val == 0: - cmdobj = self.get_command_obj(cmd) - neg_opt = self.negative_opt.copy() - neg_opt.update(getattr(cmdobj, 'negative_opt', {})) - for neg, pos in neg_opt.items(): - if pos == opt: - opt = neg - val = None - break - else: - raise AssertionError("Shouldn't be able to get here") - - elif val == 1: - val = None - - d.setdefault(cmd, {})[opt] = val - - return d - - def iter_distribution_names(self): - """Yield all packages, modules, and extension names in distribution""" - - for pkg in self.packages or (): - yield pkg - - for module in self.py_modules or (): - yield module - - for ext in self.ext_modules or (): - if isinstance(ext, tuple): - name, buildinfo = ext - else: - name = ext.name - if name.endswith('module'): - name = name[:-6] - yield name - - def handle_display_options(self, option_order): - """If there were any non-global "display-only" options - (--help-commands or the metadata display options) on the command - line, display the requested info and return true; else return - false. - """ - import sys - - if six.PY2 or self.help_commands: - return _Distribution.handle_display_options(self, option_order) - - # Stdout may be StringIO (e.g. in tests) - if not isinstance(sys.stdout, io.TextIOWrapper): - return _Distribution.handle_display_options(self, option_order) - - # Don't wrap stdout if utf-8 is already the encoding. Provides - # workaround for #334. - if sys.stdout.encoding.lower() in ('utf-8', 'utf8'): - return _Distribution.handle_display_options(self, option_order) - - # Print metadata in UTF-8 no matter the platform - encoding = sys.stdout.encoding - errors = sys.stdout.errors - newline = sys.platform != 'win32' and '\n' or None - line_buffering = sys.stdout.line_buffering - - sys.stdout = io.TextIOWrapper( - sys.stdout.detach(), 'utf-8', errors, newline, line_buffering) - try: - return _Distribution.handle_display_options(self, option_order) - finally: - sys.stdout = io.TextIOWrapper( - sys.stdout.detach(), encoding, errors, newline, line_buffering) - - -class Feature: - """ - **deprecated** -- The `Feature` facility was never completely implemented - or supported, `has reported issues - <https://github.com/pypa/setuptools/issues/58>`_ and will be removed in - a future version. - - A subset of the distribution that can be excluded if unneeded/wanted - - Features are created using these keyword arguments: - - 'description' -- a short, human readable description of the feature, to - be used in error messages, and option help messages. - - 'standard' -- if true, the feature is included by default if it is - available on the current system. Otherwise, the feature is only - included if requested via a command line '--with-X' option, or if - another included feature requires it. The default setting is 'False'. - - 'available' -- if true, the feature is available for installation on the - current system. The default setting is 'True'. - - 'optional' -- if true, the feature's inclusion can be controlled from the - command line, using the '--with-X' or '--without-X' options. If - false, the feature's inclusion status is determined automatically, - based on 'availabile', 'standard', and whether any other feature - requires it. The default setting is 'True'. - - 'require_features' -- a string or sequence of strings naming features - that should also be included if this feature is included. Defaults to - empty list. May also contain 'Require' objects that should be - added/removed from the distribution. - - 'remove' -- a string or list of strings naming packages to be removed - from the distribution if this feature is *not* included. If the - feature *is* included, this argument is ignored. This argument exists - to support removing features that "crosscut" a distribution, such as - defining a 'tests' feature that removes all the 'tests' subpackages - provided by other features. The default for this argument is an empty - list. (Note: the named package(s) or modules must exist in the base - distribution when the 'setup()' function is initially called.) - - other keywords -- any other keyword arguments are saved, and passed to - the distribution's 'include()' and 'exclude()' methods when the - feature is included or excluded, respectively. So, for example, you - could pass 'packages=["a","b"]' to cause packages 'a' and 'b' to be - added or removed from the distribution as appropriate. - - A feature must include at least one 'requires', 'remove', or other - keyword argument. Otherwise, it can't affect the distribution in any way. - Note also that you can subclass 'Feature' to create your own specialized - feature types that modify the distribution in other ways when included or - excluded. See the docstrings for the various methods here for more detail. - Aside from the methods, the only feature attributes that distributions look - at are 'description' and 'optional'. - """ - - @staticmethod - def warn_deprecated(): - msg = ( - "Features are deprecated and will be removed in a future " - "version. See https://github.com/pypa/setuptools/issues/65." - ) - warnings.warn(msg, DistDeprecationWarning, stacklevel=3) - - def __init__( - self, description, standard=False, available=True, - optional=True, require_features=(), remove=(), **extras): - self.warn_deprecated() - - self.description = description - self.standard = standard - self.available = available - self.optional = optional - if isinstance(require_features, (str, Require)): - require_features = require_features, - - self.require_features = [ - r for r in require_features if isinstance(r, str) - ] - er = [r for r in require_features if not isinstance(r, str)] - if er: - extras['require_features'] = er - - if isinstance(remove, str): - remove = remove, - self.remove = remove - self.extras = extras - - if not remove and not require_features and not extras: - raise DistutilsSetupError( - "Feature %s: must define 'require_features', 'remove', or " - "at least one of 'packages', 'py_modules', etc." - ) - - def include_by_default(self): - """Should this feature be included by default?""" - return self.available and self.standard - - def include_in(self, dist): - """Ensure feature and its requirements are included in distribution - - You may override this in a subclass to perform additional operations on - the distribution. Note that this method may be called more than once - per feature, and so should be idempotent. - - """ - - if not self.available: - raise DistutilsPlatformError( - self.description + " is required, " - "but is not available on this platform" - ) - - dist.include(**self.extras) - - for f in self.require_features: - dist.include_feature(f) - - def exclude_from(self, dist): - """Ensure feature is excluded from distribution - - You may override this in a subclass to perform additional operations on - the distribution. This method will be called at most once per - feature, and only after all included features have been asked to - include themselves. - """ - - dist.exclude(**self.extras) - - if self.remove: - for item in self.remove: - dist.exclude_package(item) - - def validate(self, dist): - """Verify that feature makes sense in context of distribution - - This method is called by the distribution just before it parses its - command line. It checks to ensure that the 'remove' attribute, if any, - contains only valid package/module names that are present in the base - distribution when 'setup()' is called. You may override it in a - subclass to perform any other required validation of the feature - against a target distribution. - """ - - for item in self.remove: - if not dist.has_contents_for(item): - raise DistutilsSetupError( - "%s wants to be able to remove %s, but the distribution" - " doesn't contain any packages or modules under %s" - % (self.description, item, item) - ) - - -class DistDeprecationWarning(SetuptoolsDeprecationWarning): - """Class for warning about deprecations in dist in - setuptools. Not ignored by default, unlike DeprecationWarning.""" diff --git a/venv/lib/python3.8/site-packages/setuptools/errors.py b/venv/lib/python3.8/site-packages/setuptools/errors.py deleted file mode 100644 index 2701747..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/errors.py +++ /dev/null @@ -1,16 +0,0 @@ -"""setuptools.errors - -Provides exceptions used by setuptools modules. -""" - -from distutils.errors import DistutilsError - - -class RemovedCommandError(DistutilsError, RuntimeError): - """Error used for commands that have been removed in setuptools. - - Since ``setuptools`` is built on ``distutils``, simply removing a command - from ``setuptools`` will make the behavior fall back to ``distutils``; this - error is raised if a command exists in ``distutils`` but has been actively - removed in ``setuptools``. - """ diff --git a/venv/lib/python3.8/site-packages/setuptools/extension.py b/venv/lib/python3.8/site-packages/setuptools/extension.py deleted file mode 100644 index 2946889..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/extension.py +++ /dev/null @@ -1,57 +0,0 @@ -import re -import functools -import distutils.core -import distutils.errors -import distutils.extension - -from setuptools.extern.six.moves import map - -from .monkey import get_unpatched - - -def _have_cython(): - """ - Return True if Cython can be imported. - """ - cython_impl = 'Cython.Distutils.build_ext' - try: - # from (cython_impl) import build_ext - __import__(cython_impl, fromlist=['build_ext']).build_ext - return True - except Exception: - pass - return False - - -# for compatibility -have_pyrex = _have_cython - -_Extension = get_unpatched(distutils.core.Extension) - - -class Extension(_Extension): - """Extension that uses '.c' files in place of '.pyx' files""" - - def __init__(self, name, sources, *args, **kw): - # The *args is needed for compatibility as calls may use positional - # arguments. py_limited_api may be set only via keyword. - self.py_limited_api = kw.pop("py_limited_api", False) - _Extension.__init__(self, name, sources, *args, **kw) - - def _convert_pyx_sources_to_lang(self): - """ - Replace sources with .pyx extensions to sources with the target - language extension. This mechanism allows language authors to supply - pre-converted sources but to prefer the .pyx sources. - """ - if _have_cython(): - # the build has Cython, so allow it to compile the .pyx files - return - lang = self.language or '' - target_ext = '.cpp' if lang.lower() == 'c++' else '.c' - sub = functools.partial(re.sub, '.pyx$', target_ext) - self.sources = list(map(sub, self.sources)) - - -class Library(Extension): - """Just like a regular Extension, but built as a library instead""" diff --git a/venv/lib/python3.8/site-packages/setuptools/extern/__init__.py b/venv/lib/python3.8/site-packages/setuptools/extern/__init__.py deleted file mode 100644 index e8c616f..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/extern/__init__.py +++ /dev/null @@ -1,73 +0,0 @@ -import sys - - -class VendorImporter: - """ - A PEP 302 meta path importer for finding optionally-vendored - or otherwise naturally-installed packages from root_name. - """ - - def __init__(self, root_name, vendored_names=(), vendor_pkg=None): - self.root_name = root_name - self.vendored_names = set(vendored_names) - self.vendor_pkg = vendor_pkg or root_name.replace('extern', '_vendor') - - @property - def search_path(self): - """ - Search first the vendor package then as a natural package. - """ - yield self.vendor_pkg + '.' - yield '' - - def find_module(self, fullname, path=None): - """ - Return self when fullname starts with root_name and the - target module is one vendored through this importer. - """ - root, base, target = fullname.partition(self.root_name + '.') - if root: - return - if not any(map(target.startswith, self.vendored_names)): - return - return self - - def load_module(self, fullname): - """ - Iterate over the search path to locate and load fullname. - """ - root, base, target = fullname.partition(self.root_name + '.') - for prefix in self.search_path: - try: - extant = prefix + target - __import__(extant) - mod = sys.modules[extant] - sys.modules[fullname] = mod - # mysterious hack: - # Remove the reference to the extant package/module - # on later Python versions to cause relative imports - # in the vendor package to resolve the same modules - # as those going through this importer. - if sys.version_info >= (3, ): - del sys.modules[extant] - return mod - except ImportError: - pass - else: - raise ImportError( - "The '{target}' package is required; " - "normally this is bundled with this package so if you get " - "this warning, consult the packager of your " - "distribution.".format(**locals()) - ) - - def install(self): - """ - Install this importer into sys.meta_path if not already present. - """ - if self not in sys.meta_path: - sys.meta_path.append(self) - - -names = 'six', 'packaging', 'pyparsing', 'ordered_set', -VendorImporter(__name__, names, 'setuptools._vendor').install() diff --git a/venv/lib/python3.8/site-packages/setuptools/glob.py b/venv/lib/python3.8/site-packages/setuptools/glob.py deleted file mode 100644 index 9d7cbc5..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/glob.py +++ /dev/null @@ -1,174 +0,0 @@ -""" -Filename globbing utility. Mostly a copy of `glob` from Python 3.5. - -Changes include: - * `yield from` and PEP3102 `*` removed. - * Hidden files are not ignored. -""" - -import os -import re -import fnmatch - -__all__ = ["glob", "iglob", "escape"] - - -def glob(pathname, recursive=False): - """Return a list of paths matching a pathname pattern. - - The pattern may contain simple shell-style wildcards a la - fnmatch. However, unlike fnmatch, filenames starting with a - dot are special cases that are not matched by '*' and '?' - patterns. - - If recursive is true, the pattern '**' will match any files and - zero or more directories and subdirectories. - """ - return list(iglob(pathname, recursive=recursive)) - - -def iglob(pathname, recursive=False): - """Return an iterator which yields the paths matching a pathname pattern. - - The pattern may contain simple shell-style wildcards a la - fnmatch. However, unlike fnmatch, filenames starting with a - dot are special cases that are not matched by '*' and '?' - patterns. - - If recursive is true, the pattern '**' will match any files and - zero or more directories and subdirectories. - """ - it = _iglob(pathname, recursive) - if recursive and _isrecursive(pathname): - s = next(it) # skip empty string - assert not s - return it - - -def _iglob(pathname, recursive): - dirname, basename = os.path.split(pathname) - if not has_magic(pathname): - if basename: - if os.path.lexists(pathname): - yield pathname - else: - # Patterns ending with a slash should match only directories - if os.path.isdir(dirname): - yield pathname - return - if not dirname: - if recursive and _isrecursive(basename): - for x in glob2(dirname, basename): - yield x - else: - for x in glob1(dirname, basename): - yield x - return - # `os.path.split()` returns the argument itself as a dirname if it is a - # drive or UNC path. Prevent an infinite recursion if a drive or UNC path - # contains magic characters (i.e. r'\\?\C:'). - if dirname != pathname and has_magic(dirname): - dirs = _iglob(dirname, recursive) - else: - dirs = [dirname] - if has_magic(basename): - if recursive and _isrecursive(basename): - glob_in_dir = glob2 - else: - glob_in_dir = glob1 - else: - glob_in_dir = glob0 - for dirname in dirs: - for name in glob_in_dir(dirname, basename): - yield os.path.join(dirname, name) - - -# These 2 helper functions non-recursively glob inside a literal directory. -# They return a list of basenames. `glob1` accepts a pattern while `glob0` -# takes a literal basename (so it only has to check for its existence). - - -def glob1(dirname, pattern): - if not dirname: - if isinstance(pattern, bytes): - dirname = os.curdir.encode('ASCII') - else: - dirname = os.curdir - try: - names = os.listdir(dirname) - except OSError: - return [] - return fnmatch.filter(names, pattern) - - -def glob0(dirname, basename): - if not basename: - # `os.path.split()` returns an empty basename for paths ending with a - # directory separator. 'q*x/' should match only directories. - if os.path.isdir(dirname): - return [basename] - else: - if os.path.lexists(os.path.join(dirname, basename)): - return [basename] - return [] - - -# This helper function recursively yields relative pathnames inside a literal -# directory. - - -def glob2(dirname, pattern): - assert _isrecursive(pattern) - yield pattern[:0] - for x in _rlistdir(dirname): - yield x - - -# Recursively yields relative pathnames inside a literal directory. -def _rlistdir(dirname): - if not dirname: - if isinstance(dirname, bytes): - dirname = os.curdir.encode('ASCII') - else: - dirname = os.curdir - try: - names = os.listdir(dirname) - except os.error: - return - for x in names: - yield x - path = os.path.join(dirname, x) if dirname else x - for y in _rlistdir(path): - yield os.path.join(x, y) - - -magic_check = re.compile('([*?[])') -magic_check_bytes = re.compile(b'([*?[])') - - -def has_magic(s): - if isinstance(s, bytes): - match = magic_check_bytes.search(s) - else: - match = magic_check.search(s) - return match is not None - - -def _isrecursive(pattern): - if isinstance(pattern, bytes): - return pattern == b'**' - else: - return pattern == '**' - - -def escape(pathname): - """Escape all special characters. - """ - # Escaping is done by wrapping any of "*?[" between square brackets. - # Metacharacters do not work in the drive part and shouldn't be escaped. - drive, pathname = os.path.splitdrive(pathname) - if isinstance(pathname, bytes): - pathname = magic_check_bytes.sub(br'[\1]', pathname) - else: - pathname = magic_check.sub(r'[\1]', pathname) - return drive + pathname diff --git a/venv/lib/python3.8/site-packages/setuptools/gui-32.exe b/venv/lib/python3.8/site-packages/setuptools/gui-32.exe deleted file mode 100644 index f8d3509653ba8f80ca7f3aa7f95616142ba83a94..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 65536 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 diff --git a/venv/lib/python3.8/site-packages/setuptools/gui-64.exe b/venv/lib/python3.8/site-packages/setuptools/gui-64.exe deleted file mode 100644 index 330c51a5dde15a0bb610a48cd0ca11770c914dae..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 75264 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 diff --git a/venv/lib/python3.8/site-packages/setuptools/gui.exe b/venv/lib/python3.8/site-packages/setuptools/gui.exe deleted file mode 100644 index f8d3509653ba8f80ca7f3aa7f95616142ba83a94..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 65536 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 diff --git a/venv/lib/python3.8/site-packages/setuptools/installer.py b/venv/lib/python3.8/site-packages/setuptools/installer.py deleted file mode 100644 index 9f8be2e..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/installer.py +++ /dev/null @@ -1,150 +0,0 @@ -import glob -import os -import subprocess -import sys -from distutils import log -from distutils.errors import DistutilsError - -import pkg_resources -from setuptools.command.easy_install import easy_install -from setuptools.extern import six -from setuptools.wheel import Wheel - -from .py31compat import TemporaryDirectory - - -def _fixup_find_links(find_links): - """Ensure find-links option end-up being a list of strings.""" - if isinstance(find_links, six.string_types): - return find_links.split() - assert isinstance(find_links, (tuple, list)) - return find_links - - -def _legacy_fetch_build_egg(dist, req): - """Fetch an egg needed for building. - - Legacy path using EasyInstall. - """ - tmp_dist = dist.__class__({'script_args': ['easy_install']}) - opts = tmp_dist.get_option_dict('easy_install') - opts.clear() - opts.update( - (k, v) - for k, v in dist.get_option_dict('easy_install').items() - if k in ( - # don't use any other settings - 'find_links', 'site_dirs', 'index_url', - 'optimize', 'site_dirs', 'allow_hosts', - )) - if dist.dependency_links: - links = dist.dependency_links[:] - if 'find_links' in opts: - links = _fixup_find_links(opts['find_links'][1]) + links - opts['find_links'] = ('setup', links) - install_dir = dist.get_egg_cache_dir() - cmd = easy_install( - tmp_dist, args=["x"], install_dir=install_dir, - exclude_scripts=True, - always_copy=False, build_directory=None, editable=False, - upgrade=False, multi_version=True, no_report=True, user=False - ) - cmd.ensure_finalized() - return cmd.easy_install(req) - - -def fetch_build_egg(dist, req): - """Fetch an egg needed for building. - - Use pip/wheel to fetch/build a wheel.""" - # Check pip is available. - try: - pkg_resources.get_distribution('pip') - except pkg_resources.DistributionNotFound: - dist.announce( - 'WARNING: The pip package is not available, falling back ' - 'to EasyInstall for handling setup_requires/test_requires; ' - 'this is deprecated and will be removed in a future version.' - , log.WARN - ) - return _legacy_fetch_build_egg(dist, req) - # Warn if wheel is not. - try: - pkg_resources.get_distribution('wheel') - except pkg_resources.DistributionNotFound: - dist.announce('WARNING: The wheel package is not available.', log.WARN) - # Ignore environment markers; if supplied, it is required. - req = strip_marker(req) - # Take easy_install options into account, but do not override relevant - # pip environment variables (like PIP_INDEX_URL or PIP_QUIET); they'll - # take precedence. - opts = dist.get_option_dict('easy_install') - if 'allow_hosts' in opts: - raise DistutilsError('the `allow-hosts` option is not supported ' - 'when using pip to install requirements.') - if 'PIP_QUIET' in os.environ or 'PIP_VERBOSE' in os.environ: - quiet = False - else: - quiet = True - if 'PIP_INDEX_URL' in os.environ: - index_url = None - elif 'index_url' in opts: - index_url = opts['index_url'][1] - else: - index_url = None - if 'find_links' in opts: - find_links = _fixup_find_links(opts['find_links'][1])[:] - else: - find_links = [] - if dist.dependency_links: - find_links.extend(dist.dependency_links) - eggs_dir = os.path.realpath(dist.get_egg_cache_dir()) - environment = pkg_resources.Environment() - for egg_dist in pkg_resources.find_distributions(eggs_dir): - if egg_dist in req and environment.can_add(egg_dist): - return egg_dist - with TemporaryDirectory() as tmpdir: - cmd = [ - sys.executable, '-m', 'pip', - '--disable-pip-version-check', - 'wheel', '--no-deps', - '-w', tmpdir, - ] - if quiet: - cmd.append('--quiet') - if index_url is not None: - cmd.extend(('--index-url', index_url)) - if find_links is not None: - for link in find_links: - cmd.extend(('--find-links', link)) - # If requirement is a PEP 508 direct URL, directly pass - # the URL to pip, as `req @ url` does not work on the - # command line. - if req.url: - cmd.append(req.url) - else: - cmd.append(str(req)) - try: - subprocess.check_call(cmd) - except subprocess.CalledProcessError as e: - raise DistutilsError(str(e)) - wheel = Wheel(glob.glob(os.path.join(tmpdir, '*.whl'))[0]) - dist_location = os.path.join(eggs_dir, wheel.egg_name()) - wheel.install_as_egg(dist_location) - dist_metadata = pkg_resources.PathMetadata( - dist_location, os.path.join(dist_location, 'EGG-INFO')) - dist = pkg_resources.Distribution.from_filename( - dist_location, metadata=dist_metadata) - return dist - - -def strip_marker(req): - """ - Return a new requirement without the environment marker to avoid - calling pip with something like `babel; extra == "i18n"`, which - would always be ignored. - """ - # create a copy to avoid mutating the input - req = pkg_resources.Requirement.parse(str(req)) - req.marker = None - return req diff --git a/venv/lib/python3.8/site-packages/setuptools/launch.py b/venv/lib/python3.8/site-packages/setuptools/launch.py deleted file mode 100644 index 308283e..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/launch.py +++ /dev/null @@ -1,35 +0,0 @@ -""" -Launch the Python script on the command line after -setuptools is bootstrapped via import. -""" - -# Note that setuptools gets imported implicitly by the -# invocation of this script using python -m setuptools.launch - -import tokenize -import sys - - -def run(): - """ - Run the script in sys.argv[1] as if it had - been invoked naturally. - """ - __builtins__ - script_name = sys.argv[1] - namespace = dict( - __file__=script_name, - __name__='__main__', - __doc__=None, - ) - sys.argv[:] = sys.argv[1:] - - open_ = getattr(tokenize, 'open', open) - script = open_(script_name).read() - norm_script = script.replace('\\r\\n', '\\n') - code = compile(norm_script, script_name, 'exec') - exec(code, namespace) - - -if __name__ == '__main__': - run() diff --git a/venv/lib/python3.8/site-packages/setuptools/lib2to3_ex.py b/venv/lib/python3.8/site-packages/setuptools/lib2to3_ex.py deleted file mode 100644 index 4b1a73f..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/lib2to3_ex.py +++ /dev/null @@ -1,62 +0,0 @@ -""" -Customized Mixin2to3 support: - - - adds support for converting doctests - - -This module raises an ImportError on Python 2. -""" - -from distutils.util import Mixin2to3 as _Mixin2to3 -from distutils import log -from lib2to3.refactor import RefactoringTool, get_fixers_from_package - -import setuptools - - -class DistutilsRefactoringTool(RefactoringTool): - def log_error(self, msg, *args, **kw): - log.error(msg, *args) - - def log_message(self, msg, *args): - log.info(msg, *args) - - def log_debug(self, msg, *args): - log.debug(msg, *args) - - -class Mixin2to3(_Mixin2to3): - def run_2to3(self, files, doctests=False): - # See of the distribution option has been set, otherwise check the - # setuptools default. - if self.distribution.use_2to3 is not True: - return - if not files: - return - log.info("Fixing " + " ".join(files)) - self.__build_fixer_names() - self.__exclude_fixers() - if doctests: - if setuptools.run_2to3_on_doctests: - r = DistutilsRefactoringTool(self.fixer_names) - r.refactor(files, write=True, doctests_only=True) - else: - _Mixin2to3.run_2to3(self, files) - - def __build_fixer_names(self): - if self.fixer_names: - return - self.fixer_names = [] - for p in setuptools.lib2to3_fixer_packages: - self.fixer_names.extend(get_fixers_from_package(p)) - if self.distribution.use_2to3_fixers is not None: - for p in self.distribution.use_2to3_fixers: - self.fixer_names.extend(get_fixers_from_package(p)) - - def __exclude_fixers(self): - excluded_fixers = getattr(self, 'exclude_fixers', []) - if self.distribution.use_2to3_exclude_fixers is not None: - excluded_fixers.extend(self.distribution.use_2to3_exclude_fixers) - for fixer_name in excluded_fixers: - if fixer_name in self.fixer_names: - self.fixer_names.remove(fixer_name) diff --git a/venv/lib/python3.8/site-packages/setuptools/monkey.py b/venv/lib/python3.8/site-packages/setuptools/monkey.py deleted file mode 100644 index 3c77f8c..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/monkey.py +++ /dev/null @@ -1,179 +0,0 @@ -""" -Monkey patching of distutils. -""" - -import sys -import distutils.filelist -import platform -import types -import functools -from importlib import import_module -import inspect - -from setuptools.extern import six - -import setuptools - -__all__ = [] -""" -Everything is private. Contact the project team -if you think you need this functionality. -""" - - -def _get_mro(cls): - """ - Returns the bases classes for cls sorted by the MRO. - - Works around an issue on Jython where inspect.getmro will not return all - base classes if multiple classes share the same name. Instead, this - function will return a tuple containing the class itself, and the contents - of cls.__bases__. See https://github.com/pypa/setuptools/issues/1024. - """ - if platform.python_implementation() == "Jython": - return (cls,) + cls.__bases__ - return inspect.getmro(cls) - - -def get_unpatched(item): - lookup = ( - get_unpatched_class if isinstance(item, six.class_types) else - get_unpatched_function if isinstance(item, types.FunctionType) else - lambda item: None - ) - return lookup(item) - - -def get_unpatched_class(cls): - """Protect against re-patching the distutils if reloaded - - Also ensures that no other distutils extension monkeypatched the distutils - first. - """ - external_bases = ( - cls - for cls in _get_mro(cls) - if not cls.__module__.startswith('setuptools') - ) - base = next(external_bases) - if not base.__module__.startswith('distutils'): - msg = "distutils has already been patched by %r" % cls - raise AssertionError(msg) - return base - - -def patch_all(): - # we can't patch distutils.cmd, alas - distutils.core.Command = setuptools.Command - - has_issue_12885 = sys.version_info <= (3, 5, 3) - - if has_issue_12885: - # fix findall bug in distutils (http://bugs.python.org/issue12885) - distutils.filelist.findall = setuptools.findall - - needs_warehouse = ( - sys.version_info < (2, 7, 13) - or - (3, 4) < sys.version_info < (3, 4, 6) - or - (3, 5) < sys.version_info <= (3, 5, 3) - ) - - if needs_warehouse: - warehouse = 'https://upload.pypi.org/legacy/' - distutils.config.PyPIRCCommand.DEFAULT_REPOSITORY = warehouse - - _patch_distribution_metadata() - - # Install Distribution throughout the distutils - for module in distutils.dist, distutils.core, distutils.cmd: - module.Distribution = setuptools.dist.Distribution - - # Install the patched Extension - distutils.core.Extension = setuptools.extension.Extension - distutils.extension.Extension = setuptools.extension.Extension - if 'distutils.command.build_ext' in sys.modules: - sys.modules['distutils.command.build_ext'].Extension = ( - setuptools.extension.Extension - ) - - patch_for_msvc_specialized_compiler() - - -def _patch_distribution_metadata(): - """Patch write_pkg_file and read_pkg_file for higher metadata standards""" - for attr in ('write_pkg_file', 'read_pkg_file', 'get_metadata_version'): - new_val = getattr(setuptools.dist, attr) - setattr(distutils.dist.DistributionMetadata, attr, new_val) - - -def patch_func(replacement, target_mod, func_name): - """ - Patch func_name in target_mod with replacement - - Important - original must be resolved by name to avoid - patching an already patched function. - """ - original = getattr(target_mod, func_name) - - # set the 'unpatched' attribute on the replacement to - # point to the original. - vars(replacement).setdefault('unpatched', original) - - # replace the function in the original module - setattr(target_mod, func_name, replacement) - - -def get_unpatched_function(candidate): - return getattr(candidate, 'unpatched') - - -def patch_for_msvc_specialized_compiler(): - """ - Patch functions in distutils to use standalone Microsoft Visual C++ - compilers. - """ - # import late to avoid circular imports on Python < 3.5 - msvc = import_module('setuptools.msvc') - - if platform.system() != 'Windows': - # Compilers only availables on Microsoft Windows - return - - def patch_params(mod_name, func_name): - """ - Prepare the parameters for patch_func to patch indicated function. - """ - repl_prefix = 'msvc9_' if 'msvc9' in mod_name else 'msvc14_' - repl_name = repl_prefix + func_name.lstrip('_') - repl = getattr(msvc, repl_name) - mod = import_module(mod_name) - if not hasattr(mod, func_name): - raise ImportError(func_name) - return repl, mod, func_name - - # Python 2.7 to 3.4 - msvc9 = functools.partial(patch_params, 'distutils.msvc9compiler') - - # Python 3.5+ - msvc14 = functools.partial(patch_params, 'distutils._msvccompiler') - - try: - # Patch distutils.msvc9compiler - patch_func(*msvc9('find_vcvarsall')) - patch_func(*msvc9('query_vcvarsall')) - except ImportError: - pass - - try: - # Patch distutils._msvccompiler._get_vc_env - patch_func(*msvc14('_get_vc_env')) - except ImportError: - pass - - try: - # Patch distutils._msvccompiler.gen_lib_options for Numpy - patch_func(*msvc14('gen_lib_options')) - except ImportError: - pass diff --git a/venv/lib/python3.8/site-packages/setuptools/msvc.py b/venv/lib/python3.8/site-packages/setuptools/msvc.py deleted file mode 100644 index 2ffe1c8..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/msvc.py +++ /dev/null @@ -1,1679 +0,0 @@ -""" -Improved support for Microsoft Visual C++ compilers. - -Known supported compilers: --------------------------- -Microsoft Visual C++ 9.0: - Microsoft Visual C++ Compiler for Python 2.7 (x86, amd64) - Microsoft Windows SDK 6.1 (x86, x64, ia64) - Microsoft Windows SDK 7.0 (x86, x64, ia64) - -Microsoft Visual C++ 10.0: - Microsoft Windows SDK 7.1 (x86, x64, ia64) - -Microsoft Visual C++ 14.X: - Microsoft Visual C++ Build Tools 2015 (x86, x64, arm) - Microsoft Visual Studio Build Tools 2017 (x86, x64, arm, arm64) - Microsoft Visual Studio Build Tools 2019 (x86, x64, arm, arm64) - -This may also support compilers shipped with compatible Visual Studio versions. -""" - -import json -from io import open -from os import listdir, pathsep -from os.path import join, isfile, isdir, dirname -import sys -import platform -import itertools -import distutils.errors -from setuptools.extern.packaging.version import LegacyVersion - -from setuptools.extern.six.moves import filterfalse - -from .monkey import get_unpatched - -if platform.system() == 'Windows': - from setuptools.extern.six.moves import winreg - from os import environ -else: - # Mock winreg and environ so the module can be imported on this platform. - - class winreg: - HKEY_USERS = None - HKEY_CURRENT_USER = None - HKEY_LOCAL_MACHINE = None - HKEY_CLASSES_ROOT = None - - environ = dict() - -_msvc9_suppress_errors = ( - # msvc9compiler isn't available on some platforms - ImportError, - - # msvc9compiler raises DistutilsPlatformError in some - # environments. See #1118. - distutils.errors.DistutilsPlatformError, -) - -try: - from distutils.msvc9compiler import Reg -except _msvc9_suppress_errors: - pass - - -def msvc9_find_vcvarsall(version): - """ - Patched "distutils.msvc9compiler.find_vcvarsall" to use the standalone - compiler build for Python - (VCForPython / Microsoft Visual C++ Compiler for Python 2.7). - - Fall back to original behavior when the standalone compiler is not - available. - - Redirect the path of "vcvarsall.bat". - - Parameters - ---------- - version: float - Required Microsoft Visual C++ version. - - Return - ------ - str - vcvarsall.bat path - """ - vc_base = r'Software\%sMicrosoft\DevDiv\VCForPython\%0.1f' - key = vc_base % ('', version) - try: - # Per-user installs register the compiler path here - productdir = Reg.get_value(key, "installdir") - except KeyError: - try: - # All-user installs on a 64-bit system register here - key = vc_base % ('Wow6432Node\\', version) - productdir = Reg.get_value(key, "installdir") - except KeyError: - productdir = None - - if productdir: - vcvarsall = join(productdir, "vcvarsall.bat") - if isfile(vcvarsall): - return vcvarsall - - return get_unpatched(msvc9_find_vcvarsall)(version) - - -def msvc9_query_vcvarsall(ver, arch='x86', *args, **kwargs): - """ - Patched "distutils.msvc9compiler.query_vcvarsall" for support extra - Microsoft Visual C++ 9.0 and 10.0 compilers. - - Set environment without use of "vcvarsall.bat". - - Parameters - ---------- - ver: float - Required Microsoft Visual C++ version. - arch: str - Target architecture. - - Return - ------ - dict - environment - """ - # Try to get environment from vcvarsall.bat (Classical way) - try: - orig = get_unpatched(msvc9_query_vcvarsall) - return orig(ver, arch, *args, **kwargs) - except distutils.errors.DistutilsPlatformError: - # Pass error if Vcvarsall.bat is missing - pass - except ValueError: - # Pass error if environment not set after executing vcvarsall.bat - pass - - # If error, try to set environment directly - try: - return EnvironmentInfo(arch, ver).return_env() - except distutils.errors.DistutilsPlatformError as exc: - _augment_exception(exc, ver, arch) - raise - - -def msvc14_get_vc_env(plat_spec): - """ - Patched "distutils._msvccompiler._get_vc_env" for support extra - Microsoft Visual C++ 14.X compilers. - - Set environment without use of "vcvarsall.bat". - - Parameters - ---------- - plat_spec: str - Target architecture. - - Return - ------ - dict - environment - """ - # Try to get environment from vcvarsall.bat (Classical way) - try: - return get_unpatched(msvc14_get_vc_env)(plat_spec) - except distutils.errors.DistutilsPlatformError: - # Pass error Vcvarsall.bat is missing - pass - - # If error, try to set environment directly - try: - return EnvironmentInfo(plat_spec, vc_min_ver=14.0).return_env() - except distutils.errors.DistutilsPlatformError as exc: - _augment_exception(exc, 14.0) - raise - - -def msvc14_gen_lib_options(*args, **kwargs): - """ - Patched "distutils._msvccompiler.gen_lib_options" for fix - compatibility between "numpy.distutils" and "distutils._msvccompiler" - (for Numpy < 1.11.2) - """ - if "numpy.distutils" in sys.modules: - import numpy as np - if LegacyVersion(np.__version__) < LegacyVersion('1.11.2'): - return np.distutils.ccompiler.gen_lib_options(*args, **kwargs) - return get_unpatched(msvc14_gen_lib_options)(*args, **kwargs) - - -def _augment_exception(exc, version, arch=''): - """ - Add details to the exception message to help guide the user - as to what action will resolve it. - """ - # Error if MSVC++ directory not found or environment not set - message = exc.args[0] - - if "vcvarsall" in message.lower() or "visual c" in message.lower(): - # Special error message if MSVC++ not installed - tmpl = 'Microsoft Visual C++ {version:0.1f} is required.' - message = tmpl.format(**locals()) - msdownload = 'www.microsoft.com/download/details.aspx?id=%d' - if version == 9.0: - if arch.lower().find('ia64') > -1: - # For VC++ 9.0, if IA64 support is needed, redirect user - # to Windows SDK 7.0. - # Note: No download link available from Microsoft. - message += ' Get it with "Microsoft Windows SDK 7.0"' - else: - # For VC++ 9.0 redirect user to Vc++ for Python 2.7 : - # This redirection link is maintained by Microsoft. - # Contact vspython@microsoft.com if it needs updating. - message += ' Get it from http://aka.ms/vcpython27' - elif version == 10.0: - # For VC++ 10.0 Redirect user to Windows SDK 7.1 - message += ' Get it with "Microsoft Windows SDK 7.1": ' - message += msdownload % 8279 - elif version >= 14.0: - # For VC++ 14.X Redirect user to latest Visual C++ Build Tools - message += (' Get it with "Build Tools for Visual Studio": ' - r'https://visualstudio.microsoft.com/downloads/') - - exc.args = (message, ) - - -class PlatformInfo: - """ - Current and Target Architectures information. - - Parameters - ---------- - arch: str - Target architecture. - """ - current_cpu = environ.get('processor_architecture', '').lower() - - def __init__(self, arch): - self.arch = arch.lower().replace('x64', 'amd64') - - @property - def target_cpu(self): - """ - Return Target CPU architecture. - - Return - ------ - str - Target CPU - """ - return self.arch[self.arch.find('_') + 1:] - - def target_is_x86(self): - """ - Return True if target CPU is x86 32 bits.. - - Return - ------ - bool - CPU is x86 32 bits - """ - return self.target_cpu == 'x86' - - def current_is_x86(self): - """ - Return True if current CPU is x86 32 bits.. - - Return - ------ - bool - CPU is x86 32 bits - """ - return self.current_cpu == 'x86' - - def current_dir(self, hidex86=False, x64=False): - """ - Current platform specific subfolder. - - Parameters - ---------- - hidex86: bool - return '' and not '\x86' if architecture is x86. - x64: bool - return '\x64' and not '\amd64' if architecture is amd64. - - Return - ------ - str - subfolder: '\target', or '' (see hidex86 parameter) - """ - return ( - '' if (self.current_cpu == 'x86' and hidex86) else - r'\x64' if (self.current_cpu == 'amd64' and x64) else - r'\%s' % self.current_cpu - ) - - def target_dir(self, hidex86=False, x64=False): - r""" - Target platform specific subfolder. - - Parameters - ---------- - hidex86: bool - return '' and not '\x86' if architecture is x86. - x64: bool - return '\x64' and not '\amd64' if architecture is amd64. - - Return - ------ - str - subfolder: '\current', or '' (see hidex86 parameter) - """ - return ( - '' if (self.target_cpu == 'x86' and hidex86) else - r'\x64' if (self.target_cpu == 'amd64' and x64) else - r'\%s' % self.target_cpu - ) - - def cross_dir(self, forcex86=False): - r""" - Cross platform specific subfolder. - - Parameters - ---------- - forcex86: bool - Use 'x86' as current architecture even if current architecture is - not x86. - - Return - ------ - str - subfolder: '' if target architecture is current architecture, - '\current_target' if not. - """ - current = 'x86' if forcex86 else self.current_cpu - return ( - '' if self.target_cpu == current else - self.target_dir().replace('\\', '\\%s_' % current) - ) - - -class RegistryInfo: - """ - Microsoft Visual Studio related registry information. - - Parameters - ---------- - platform_info: PlatformInfo - "PlatformInfo" instance. - """ - HKEYS = (winreg.HKEY_USERS, - winreg.HKEY_CURRENT_USER, - winreg.HKEY_LOCAL_MACHINE, - winreg.HKEY_CLASSES_ROOT) - - def __init__(self, platform_info): - self.pi = platform_info - - @property - def visualstudio(self): - """ - Microsoft Visual Studio root registry key. - - Return - ------ - str - Registry key - """ - return 'VisualStudio' - - @property - def sxs(self): - """ - Microsoft Visual Studio SxS registry key. - - Return - ------ - str - Registry key - """ - return join(self.visualstudio, 'SxS') - - @property - def vc(self): - """ - Microsoft Visual C++ VC7 registry key. - - Return - ------ - str - Registry key - """ - return join(self.sxs, 'VC7') - - @property - def vs(self): - """ - Microsoft Visual Studio VS7 registry key. - - Return - ------ - str - Registry key - """ - return join(self.sxs, 'VS7') - - @property - def vc_for_python(self): - """ - Microsoft Visual C++ for Python registry key. - - Return - ------ - str - Registry key - """ - return r'DevDiv\VCForPython' - - @property - def microsoft_sdk(self): - """ - Microsoft SDK registry key. - - Return - ------ - str - Registry key - """ - return 'Microsoft SDKs' - - @property - def windows_sdk(self): - """ - Microsoft Windows/Platform SDK registry key. - - Return - ------ - str - Registry key - """ - return join(self.microsoft_sdk, 'Windows') - - @property - def netfx_sdk(self): - """ - Microsoft .NET Framework SDK registry key. - - Return - ------ - str - Registry key - """ - return join(self.microsoft_sdk, 'NETFXSDK') - - @property - def windows_kits_roots(self): - """ - Microsoft Windows Kits Roots registry key. - - Return - ------ - str - Registry key - """ - return r'Windows Kits\Installed Roots' - - def microsoft(self, key, x86=False): - """ - Return key in Microsoft software registry. - - Parameters - ---------- - key: str - Registry key path where look. - x86: str - Force x86 software registry. - - Return - ------ - str - Registry key - """ - node64 = '' if self.pi.current_is_x86() or x86 else 'Wow6432Node' - return join('Software', node64, 'Microsoft', key) - - def lookup(self, key, name): - """ - Look for values in registry in Microsoft software registry. - - Parameters - ---------- - key: str - Registry key path where look. - name: str - Value name to find. - - Return - ------ - str - value - """ - key_read = winreg.KEY_READ - openkey = winreg.OpenKey - ms = self.microsoft - for hkey in self.HKEYS: - try: - bkey = openkey(hkey, ms(key), 0, key_read) - except (OSError, IOError): - if not self.pi.current_is_x86(): - try: - bkey = openkey(hkey, ms(key, True), 0, key_read) - except (OSError, IOError): - continue - else: - continue - try: - return winreg.QueryValueEx(bkey, name)[0] - except (OSError, IOError): - pass - - -class SystemInfo: - """ - Microsoft Windows and Visual Studio related system information. - - Parameters - ---------- - registry_info: RegistryInfo - "RegistryInfo" instance. - vc_ver: float - Required Microsoft Visual C++ version. - """ - - # Variables and properties in this class use originals CamelCase variables - # names from Microsoft source files for more easy comparison. - WinDir = environ.get('WinDir', '') - ProgramFiles = environ.get('ProgramFiles', '') - ProgramFilesx86 = environ.get('ProgramFiles(x86)', ProgramFiles) - - def __init__(self, registry_info, vc_ver=None): - self.ri = registry_info - self.pi = self.ri.pi - - self.known_vs_paths = self.find_programdata_vs_vers() - - # Except for VS15+, VC version is aligned with VS version - self.vs_ver = self.vc_ver = ( - vc_ver or self._find_latest_available_vs_ver()) - - def _find_latest_available_vs_ver(self): - """ - Find the latest VC version - - Return - ------ - float - version - """ - reg_vc_vers = self.find_reg_vs_vers() - - if not (reg_vc_vers or self.known_vs_paths): - raise distutils.errors.DistutilsPlatformError( - 'No Microsoft Visual C++ version found') - - vc_vers = set(reg_vc_vers) - vc_vers.update(self.known_vs_paths) - return sorted(vc_vers)[-1] - - def find_reg_vs_vers(self): - """ - Find Microsoft Visual Studio versions available in registry. - - Return - ------ - list of float - Versions - """ - ms = self.ri.microsoft - vckeys = (self.ri.vc, self.ri.vc_for_python, self.ri.vs) - vs_vers = [] - for hkey in self.ri.HKEYS: - for key in vckeys: - try: - bkey = winreg.OpenKey(hkey, ms(key), 0, winreg.KEY_READ) - except (OSError, IOError): - continue - subkeys, values, _ = winreg.QueryInfoKey(bkey) - for i in range(values): - try: - ver = float(winreg.EnumValue(bkey, i)[0]) - if ver not in vs_vers: - vs_vers.append(ver) - except ValueError: - pass - for i in range(subkeys): - try: - ver = float(winreg.EnumKey(bkey, i)) - if ver not in vs_vers: - vs_vers.append(ver) - except ValueError: - pass - return sorted(vs_vers) - - def find_programdata_vs_vers(self): - r""" - Find Visual studio 2017+ versions from information in - "C:\ProgramData\Microsoft\VisualStudio\Packages\_Instances". - - Return - ------ - dict - float version as key, path as value. - """ - vs_versions = {} - instances_dir = \ - r'C:\ProgramData\Microsoft\VisualStudio\Packages\_Instances' - - try: - hashed_names = listdir(instances_dir) - - except (OSError, IOError): - # Directory not exists with all Visual Studio versions - return vs_versions - - for name in hashed_names: - try: - # Get VS installation path from "state.json" file - state_path = join(instances_dir, name, 'state.json') - with open(state_path, 'rt', encoding='utf-8') as state_file: - state = json.load(state_file) - vs_path = state['installationPath'] - - # Raises OSError if this VS installation does not contain VC - listdir(join(vs_path, r'VC\Tools\MSVC')) - - # Store version and path - vs_versions[self._as_float_version( - state['installationVersion'])] = vs_path - - except (OSError, IOError, KeyError): - # Skip if "state.json" file is missing or bad format - continue - - return vs_versions - - @staticmethod - def _as_float_version(version): - """ - Return a string version as a simplified float version (major.minor) - - Parameters - ---------- - version: str - Version. - - Return - ------ - float - version - """ - return float('.'.join(version.split('.')[:2])) - - @property - def VSInstallDir(self): - """ - Microsoft Visual Studio directory. - - Return - ------ - str - path - """ - # Default path - default = join(self.ProgramFilesx86, - 'Microsoft Visual Studio %0.1f' % self.vs_ver) - - # Try to get path from registry, if fail use default path - return self.ri.lookup(self.ri.vs, '%0.1f' % self.vs_ver) or default - - @property - def VCInstallDir(self): - """ - Microsoft Visual C++ directory. - - Return - ------ - str - path - """ - path = self._guess_vc() or self._guess_vc_legacy() - - if not isdir(path): - msg = 'Microsoft Visual C++ directory not found' - raise distutils.errors.DistutilsPlatformError(msg) - - return path - - def _guess_vc(self): - """ - Locate Visual C++ for VS2017+. - - Return - ------ - str - path - """ - if self.vs_ver <= 14.0: - return '' - - try: - # First search in known VS paths - vs_dir = self.known_vs_paths[self.vs_ver] - except KeyError: - # Else, search with path from registry - vs_dir = self.VSInstallDir - - guess_vc = join(vs_dir, r'VC\Tools\MSVC') - - # Subdir with VC exact version as name - try: - # Update the VC version with real one instead of VS version - vc_ver = listdir(guess_vc)[-1] - self.vc_ver = self._as_float_version(vc_ver) - return join(guess_vc, vc_ver) - except (OSError, IOError, IndexError): - return '' - - def _guess_vc_legacy(self): - """ - Locate Visual C++ for versions prior to 2017. - - Return - ------ - str - path - """ - default = join(self.ProgramFilesx86, - r'Microsoft Visual Studio %0.1f\VC' % self.vs_ver) - - # Try to get "VC++ for Python" path from registry as default path - reg_path = join(self.ri.vc_for_python, '%0.1f' % self.vs_ver) - python_vc = self.ri.lookup(reg_path, 'installdir') - default_vc = join(python_vc, 'VC') if python_vc else default - - # Try to get path from registry, if fail use default path - return self.ri.lookup(self.ri.vc, '%0.1f' % self.vs_ver) or default_vc - - @property - def WindowsSdkVersion(self): - """ - Microsoft Windows SDK versions for specified MSVC++ version. - - Return - ------ - tuple of str - versions - """ - if self.vs_ver <= 9.0: - return '7.0', '6.1', '6.0a' - elif self.vs_ver == 10.0: - return '7.1', '7.0a' - elif self.vs_ver == 11.0: - return '8.0', '8.0a' - elif self.vs_ver == 12.0: - return '8.1', '8.1a' - elif self.vs_ver >= 14.0: - return '10.0', '8.1' - - @property - def WindowsSdkLastVersion(self): - """ - Microsoft Windows SDK last version. - - Return - ------ - str - version - """ - return self._use_last_dir_name(join(self.WindowsSdkDir, 'lib')) - - @property - def WindowsSdkDir(self): - """ - Microsoft Windows SDK directory. - - Return - ------ - str - path - """ - sdkdir = '' - for ver in self.WindowsSdkVersion: - # Try to get it from registry - loc = join(self.ri.windows_sdk, 'v%s' % ver) - sdkdir = self.ri.lookup(loc, 'installationfolder') - if sdkdir: - break - if not sdkdir or not isdir(sdkdir): - # Try to get "VC++ for Python" version from registry - path = join(self.ri.vc_for_python, '%0.1f' % self.vc_ver) - install_base = self.ri.lookup(path, 'installdir') - if install_base: - sdkdir = join(install_base, 'WinSDK') - if not sdkdir or not isdir(sdkdir): - # If fail, use default new path - for ver in self.WindowsSdkVersion: - intver = ver[:ver.rfind('.')] - path = r'Microsoft SDKs\Windows Kits\%s' % intver - d = join(self.ProgramFiles, path) - if isdir(d): - sdkdir = d - if not sdkdir or not isdir(sdkdir): - # If fail, use default old path - for ver in self.WindowsSdkVersion: - path = r'Microsoft SDKs\Windows\v%s' % ver - d = join(self.ProgramFiles, path) - if isdir(d): - sdkdir = d - if not sdkdir: - # If fail, use Platform SDK - sdkdir = join(self.VCInstallDir, 'PlatformSDK') - return sdkdir - - @property - def WindowsSDKExecutablePath(self): - """ - Microsoft Windows SDK executable directory. - - Return - ------ - str - path - """ - # Find WinSDK NetFx Tools registry dir name - if self.vs_ver <= 11.0: - netfxver = 35 - arch = '' - else: - netfxver = 40 - hidex86 = True if self.vs_ver <= 12.0 else False - arch = self.pi.current_dir(x64=True, hidex86=hidex86) - fx = 'WinSDK-NetFx%dTools%s' % (netfxver, arch.replace('\\', '-')) - - # list all possibles registry paths - regpaths = [] - if self.vs_ver >= 14.0: - for ver in self.NetFxSdkVersion: - regpaths += [join(self.ri.netfx_sdk, ver, fx)] - - for ver in self.WindowsSdkVersion: - regpaths += [join(self.ri.windows_sdk, 'v%sA' % ver, fx)] - - # Return installation folder from the more recent path - for path in regpaths: - execpath = self.ri.lookup(path, 'installationfolder') - if execpath: - return execpath - - @property - def FSharpInstallDir(self): - """ - Microsoft Visual F# directory. - - Return - ------ - str - path - """ - path = join(self.ri.visualstudio, r'%0.1f\Setup\F#' % self.vs_ver) - return self.ri.lookup(path, 'productdir') or '' - - @property - def UniversalCRTSdkDir(self): - """ - Microsoft Universal CRT SDK directory. - - Return - ------ - str - path - """ - # Set Kit Roots versions for specified MSVC++ version - vers = ('10', '81') if self.vs_ver >= 14.0 else () - - # Find path of the more recent Kit - for ver in vers: - sdkdir = self.ri.lookup(self.ri.windows_kits_roots, - 'kitsroot%s' % ver) - if sdkdir: - return sdkdir or '' - - @property - def UniversalCRTSdkLastVersion(self): - """ - Microsoft Universal C Runtime SDK last version. - - Return - ------ - str - version - """ - return self._use_last_dir_name(join(self.UniversalCRTSdkDir, 'lib')) - - @property - def NetFxSdkVersion(self): - """ - Microsoft .NET Framework SDK versions. - - Return - ------ - tuple of str - versions - """ - # Set FxSdk versions for specified VS version - return (('4.7.2', '4.7.1', '4.7', - '4.6.2', '4.6.1', '4.6', - '4.5.2', '4.5.1', '4.5') - if self.vs_ver >= 14.0 else ()) - - @property - def NetFxSdkDir(self): - """ - Microsoft .NET Framework SDK directory. - - Return - ------ - str - path - """ - sdkdir = '' - for ver in self.NetFxSdkVersion: - loc = join(self.ri.netfx_sdk, ver) - sdkdir = self.ri.lookup(loc, 'kitsinstallationfolder') - if sdkdir: - break - return sdkdir - - @property - def FrameworkDir32(self): - """ - Microsoft .NET Framework 32bit directory. - - Return - ------ - str - path - """ - # Default path - guess_fw = join(self.WinDir, r'Microsoft.NET\Framework') - - # Try to get path from registry, if fail use default path - return self.ri.lookup(self.ri.vc, 'frameworkdir32') or guess_fw - - @property - def FrameworkDir64(self): - """ - Microsoft .NET Framework 64bit directory. - - Return - ------ - str - path - """ - # Default path - guess_fw = join(self.WinDir, r'Microsoft.NET\Framework64') - - # Try to get path from registry, if fail use default path - return self.ri.lookup(self.ri.vc, 'frameworkdir64') or guess_fw - - @property - def FrameworkVersion32(self): - """ - Microsoft .NET Framework 32bit versions. - - Return - ------ - tuple of str - versions - """ - return self._find_dot_net_versions(32) - - @property - def FrameworkVersion64(self): - """ - Microsoft .NET Framework 64bit versions. - - Return - ------ - tuple of str - versions - """ - return self._find_dot_net_versions(64) - - def _find_dot_net_versions(self, bits): - """ - Find Microsoft .NET Framework versions. - - Parameters - ---------- - bits: int - Platform number of bits: 32 or 64. - - Return - ------ - tuple of str - versions - """ - # Find actual .NET version in registry - reg_ver = self.ri.lookup(self.ri.vc, 'frameworkver%d' % bits) - dot_net_dir = getattr(self, 'FrameworkDir%d' % bits) - ver = reg_ver or self._use_last_dir_name(dot_net_dir, 'v') or '' - - # Set .NET versions for specified MSVC++ version - if self.vs_ver >= 12.0: - return ver, 'v4.0' - elif self.vs_ver >= 10.0: - return 'v4.0.30319' if ver.lower()[:2] != 'v4' else ver, 'v3.5' - elif self.vs_ver == 9.0: - return 'v3.5', 'v2.0.50727' - elif self.vs_ver == 8.0: - return 'v3.0', 'v2.0.50727' - - @staticmethod - def _use_last_dir_name(path, prefix=''): - """ - Return name of the last dir in path or '' if no dir found. - - Parameters - ---------- - path: str - Use dirs in this path - prefix: str - Use only dirs starting by this prefix - - Return - ------ - str - name - """ - matching_dirs = ( - dir_name - for dir_name in reversed(listdir(path)) - if isdir(join(path, dir_name)) and - dir_name.startswith(prefix) - ) - return next(matching_dirs, None) or '' - - -class EnvironmentInfo: - """ - Return environment variables for specified Microsoft Visual C++ version - and platform : Lib, Include, Path and libpath. - - This function is compatible with Microsoft Visual C++ 9.0 to 14.X. - - Script created by analysing Microsoft environment configuration files like - "vcvars[...].bat", "SetEnv.Cmd", "vcbuildtools.bat", ... - - Parameters - ---------- - arch: str - Target architecture. - vc_ver: float - Required Microsoft Visual C++ version. If not set, autodetect the last - version. - vc_min_ver: float - Minimum Microsoft Visual C++ version. - """ - - # Variables and properties in this class use originals CamelCase variables - # names from Microsoft source files for more easy comparison. - - def __init__(self, arch, vc_ver=None, vc_min_ver=0): - self.pi = PlatformInfo(arch) - self.ri = RegistryInfo(self.pi) - self.si = SystemInfo(self.ri, vc_ver) - - if self.vc_ver < vc_min_ver: - err = 'No suitable Microsoft Visual C++ version found' - raise distutils.errors.DistutilsPlatformError(err) - - @property - def vs_ver(self): - """ - Microsoft Visual Studio. - - Return - ------ - float - version - """ - return self.si.vs_ver - - @property - def vc_ver(self): - """ - Microsoft Visual C++ version. - - Return - ------ - float - version - """ - return self.si.vc_ver - - @property - def VSTools(self): - """ - Microsoft Visual Studio Tools. - - Return - ------ - list of str - paths - """ - paths = [r'Common7\IDE', r'Common7\Tools'] - - if self.vs_ver >= 14.0: - arch_subdir = self.pi.current_dir(hidex86=True, x64=True) - paths += [r'Common7\IDE\CommonExtensions\Microsoft\TestWindow'] - paths += [r'Team Tools\Performance Tools'] - paths += [r'Team Tools\Performance Tools%s' % arch_subdir] - - return [join(self.si.VSInstallDir, path) for path in paths] - - @property - def VCIncludes(self): - """ - Microsoft Visual C++ & Microsoft Foundation Class Includes. - - Return - ------ - list of str - paths - """ - return [join(self.si.VCInstallDir, 'Include'), - join(self.si.VCInstallDir, r'ATLMFC\Include')] - - @property - def VCLibraries(self): - """ - Microsoft Visual C++ & Microsoft Foundation Class Libraries. - - Return - ------ - list of str - paths - """ - if self.vs_ver >= 15.0: - arch_subdir = self.pi.target_dir(x64=True) - else: - arch_subdir = self.pi.target_dir(hidex86=True) - paths = ['Lib%s' % arch_subdir, r'ATLMFC\Lib%s' % arch_subdir] - - if self.vs_ver >= 14.0: - paths += [r'Lib\store%s' % arch_subdir] - - return [join(self.si.VCInstallDir, path) for path in paths] - - @property - def VCStoreRefs(self): - """ - Microsoft Visual C++ store references Libraries. - - Return - ------ - list of str - paths - """ - if self.vs_ver < 14.0: - return [] - return [join(self.si.VCInstallDir, r'Lib\store\references')] - - @property - def VCTools(self): - """ - Microsoft Visual C++ Tools. - - Return - ------ - list of str - paths - """ - si = self.si - tools = [join(si.VCInstallDir, 'VCPackages')] - - forcex86 = True if self.vs_ver <= 10.0 else False - arch_subdir = self.pi.cross_dir(forcex86) - if arch_subdir: - tools += [join(si.VCInstallDir, 'Bin%s' % arch_subdir)] - - if self.vs_ver == 14.0: - path = 'Bin%s' % self.pi.current_dir(hidex86=True) - tools += [join(si.VCInstallDir, path)] - - elif self.vs_ver >= 15.0: - host_dir = (r'bin\HostX86%s' if self.pi.current_is_x86() else - r'bin\HostX64%s') - tools += [join( - si.VCInstallDir, host_dir % self.pi.target_dir(x64=True))] - - if self.pi.current_cpu != self.pi.target_cpu: - tools += [join( - si.VCInstallDir, host_dir % self.pi.current_dir(x64=True))] - - else: - tools += [join(si.VCInstallDir, 'Bin')] - - return tools - - @property - def OSLibraries(self): - """ - Microsoft Windows SDK Libraries. - - Return - ------ - list of str - paths - """ - if self.vs_ver <= 10.0: - arch_subdir = self.pi.target_dir(hidex86=True, x64=True) - return [join(self.si.WindowsSdkDir, 'Lib%s' % arch_subdir)] - - else: - arch_subdir = self.pi.target_dir(x64=True) - lib = join(self.si.WindowsSdkDir, 'lib') - libver = self._sdk_subdir - return [join(lib, '%sum%s' % (libver , arch_subdir))] - - @property - def OSIncludes(self): - """ - Microsoft Windows SDK Include. - - Return - ------ - list of str - paths - """ - include = join(self.si.WindowsSdkDir, 'include') - - if self.vs_ver <= 10.0: - return [include, join(include, 'gl')] - - else: - if self.vs_ver >= 14.0: - sdkver = self._sdk_subdir - else: - sdkver = '' - return [join(include, '%sshared' % sdkver), - join(include, '%sum' % sdkver), - join(include, '%swinrt' % sdkver)] - - @property - def OSLibpath(self): - """ - Microsoft Windows SDK Libraries Paths. - - Return - ------ - list of str - paths - """ - ref = join(self.si.WindowsSdkDir, 'References') - libpath = [] - - if self.vs_ver <= 9.0: - libpath += self.OSLibraries - - if self.vs_ver >= 11.0: - libpath += [join(ref, r'CommonConfiguration\Neutral')] - - if self.vs_ver >= 14.0: - libpath += [ - ref, - join(self.si.WindowsSdkDir, 'UnionMetadata'), - join(ref, 'Windows.Foundation.UniversalApiContract', '1.0.0.0'), - join(ref, 'Windows.Foundation.FoundationContract', '1.0.0.0'), - join(ref,'Windows.Networking.Connectivity.WwanContract', - '1.0.0.0'), - join(self.si.WindowsSdkDir, 'ExtensionSDKs', 'Microsoft.VCLibs', - '%0.1f' % self.vs_ver, 'References', 'CommonConfiguration', - 'neutral'), - ] - return libpath - - @property - def SdkTools(self): - """ - Microsoft Windows SDK Tools. - - Return - ------ - list of str - paths - """ - return list(self._sdk_tools()) - - def _sdk_tools(self): - """ - Microsoft Windows SDK Tools paths generator. - - Return - ------ - generator of str - paths - """ - if self.vs_ver < 15.0: - bin_dir = 'Bin' if self.vs_ver <= 11.0 else r'Bin\x86' - yield join(self.si.WindowsSdkDir, bin_dir) - - if not self.pi.current_is_x86(): - arch_subdir = self.pi.current_dir(x64=True) - path = 'Bin%s' % arch_subdir - yield join(self.si.WindowsSdkDir, path) - - if self.vs_ver in (10.0, 11.0): - if self.pi.target_is_x86(): - arch_subdir = '' - else: - arch_subdir = self.pi.current_dir(hidex86=True, x64=True) - path = r'Bin\NETFX 4.0 Tools%s' % arch_subdir - yield join(self.si.WindowsSdkDir, path) - - elif self.vs_ver >= 15.0: - path = join(self.si.WindowsSdkDir, 'Bin') - arch_subdir = self.pi.current_dir(x64=True) - sdkver = self.si.WindowsSdkLastVersion - yield join(path, '%s%s' % (sdkver, arch_subdir)) - - if self.si.WindowsSDKExecutablePath: - yield self.si.WindowsSDKExecutablePath - - @property - def _sdk_subdir(self): - """ - Microsoft Windows SDK version subdir. - - Return - ------ - str - subdir - """ - ucrtver = self.si.WindowsSdkLastVersion - return ('%s\\' % ucrtver) if ucrtver else '' - - @property - def SdkSetup(self): - """ - Microsoft Windows SDK Setup. - - Return - ------ - list of str - paths - """ - if self.vs_ver > 9.0: - return [] - - return [join(self.si.WindowsSdkDir, 'Setup')] - - @property - def FxTools(self): - """ - Microsoft .NET Framework Tools. - - Return - ------ - list of str - paths - """ - pi = self.pi - si = self.si - - if self.vs_ver <= 10.0: - include32 = True - include64 = not pi.target_is_x86() and not pi.current_is_x86() - else: - include32 = pi.target_is_x86() or pi.current_is_x86() - include64 = pi.current_cpu == 'amd64' or pi.target_cpu == 'amd64' - - tools = [] - if include32: - tools += [join(si.FrameworkDir32, ver) - for ver in si.FrameworkVersion32] - if include64: - tools += [join(si.FrameworkDir64, ver) - for ver in si.FrameworkVersion64] - return tools - - @property - def NetFxSDKLibraries(self): - """ - Microsoft .Net Framework SDK Libraries. - - Return - ------ - list of str - paths - """ - if self.vs_ver < 14.0 or not self.si.NetFxSdkDir: - return [] - - arch_subdir = self.pi.target_dir(x64=True) - return [join(self.si.NetFxSdkDir, r'lib\um%s' % arch_subdir)] - - @property - def NetFxSDKIncludes(self): - """ - Microsoft .Net Framework SDK Includes. - - Return - ------ - list of str - paths - """ - if self.vs_ver < 14.0 or not self.si.NetFxSdkDir: - return [] - - return [join(self.si.NetFxSdkDir, r'include\um')] - - @property - def VsTDb(self): - """ - Microsoft Visual Studio Team System Database. - - Return - ------ - list of str - paths - """ - return [join(self.si.VSInstallDir, r'VSTSDB\Deploy')] - - @property - def MSBuild(self): - """ - Microsoft Build Engine. - - Return - ------ - list of str - paths - """ - if self.vs_ver < 12.0: - return [] - elif self.vs_ver < 15.0: - base_path = self.si.ProgramFilesx86 - arch_subdir = self.pi.current_dir(hidex86=True) - else: - base_path = self.si.VSInstallDir - arch_subdir = '' - - path = r'MSBuild\%0.1f\bin%s' % (self.vs_ver, arch_subdir) - build = [join(base_path, path)] - - if self.vs_ver >= 15.0: - # Add Roslyn C# & Visual Basic Compiler - build += [join(base_path, path, 'Roslyn')] - - return build - - @property - def HTMLHelpWorkshop(self): - """ - Microsoft HTML Help Workshop. - - Return - ------ - list of str - paths - """ - if self.vs_ver < 11.0: - return [] - - return [join(self.si.ProgramFilesx86, 'HTML Help Workshop')] - - @property - def UCRTLibraries(self): - """ - Microsoft Universal C Runtime SDK Libraries. - - Return - ------ - list of str - paths - """ - if self.vs_ver < 14.0: - return [] - - arch_subdir = self.pi.target_dir(x64=True) - lib = join(self.si.UniversalCRTSdkDir, 'lib') - ucrtver = self._ucrt_subdir - return [join(lib, '%sucrt%s' % (ucrtver, arch_subdir))] - - @property - def UCRTIncludes(self): - """ - Microsoft Universal C Runtime SDK Include. - - Return - ------ - list of str - paths - """ - if self.vs_ver < 14.0: - return [] - - include = join(self.si.UniversalCRTSdkDir, 'include') - return [join(include, '%sucrt' % self._ucrt_subdir)] - - @property - def _ucrt_subdir(self): - """ - Microsoft Universal C Runtime SDK version subdir. - - Return - ------ - str - subdir - """ - ucrtver = self.si.UniversalCRTSdkLastVersion - return ('%s\\' % ucrtver) if ucrtver else '' - - @property - def FSharp(self): - """ - Microsoft Visual F#. - - Return - ------ - list of str - paths - """ - if 11.0 > self.vs_ver > 12.0: - return [] - - return [self.si.FSharpInstallDir] - - @property - def VCRuntimeRedist(self): - """ - Microsoft Visual C++ runtime redistributable dll. - - Return - ------ - str - path - """ - vcruntime = 'vcruntime%d0.dll' % self.vc_ver - arch_subdir = self.pi.target_dir(x64=True).strip('\\') - - # Installation prefixes candidates - prefixes = [] - tools_path = self.si.VCInstallDir - redist_path = dirname(tools_path.replace(r'\Tools', r'\Redist')) - if isdir(redist_path): - # Redist version may not be exactly the same as tools - redist_path = join(redist_path, listdir(redist_path)[-1]) - prefixes += [redist_path, join(redist_path, 'onecore')] - - prefixes += [join(tools_path, 'redist')] # VS14 legacy path - - # CRT directory - crt_dirs = ('Microsoft.VC%d.CRT' % (self.vc_ver * 10), - # Sometime store in directory with VS version instead of VC - 'Microsoft.VC%d.CRT' % (int(self.vs_ver) * 10)) - - # vcruntime path - for prefix, crt_dir in itertools.product(prefixes, crt_dirs): - path = join(prefix, arch_subdir, crt_dir, vcruntime) - if isfile(path): - return path - - def return_env(self, exists=True): - """ - Return environment dict. - - Parameters - ---------- - exists: bool - It True, only return existing paths. - - Return - ------ - dict - environment - """ - env = dict( - include=self._build_paths('include', - [self.VCIncludes, - self.OSIncludes, - self.UCRTIncludes, - self.NetFxSDKIncludes], - exists), - lib=self._build_paths('lib', - [self.VCLibraries, - self.OSLibraries, - self.FxTools, - self.UCRTLibraries, - self.NetFxSDKLibraries], - exists), - libpath=self._build_paths('libpath', - [self.VCLibraries, - self.FxTools, - self.VCStoreRefs, - self.OSLibpath], - exists), - path=self._build_paths('path', - [self.VCTools, - self.VSTools, - self.VsTDb, - self.SdkTools, - self.SdkSetup, - self.FxTools, - self.MSBuild, - self.HTMLHelpWorkshop, - self.FSharp], - exists), - ) - if self.vs_ver >= 14 and isfile(self.VCRuntimeRedist): - env['py_vcruntime_redist'] = self.VCRuntimeRedist - return env - - def _build_paths(self, name, spec_path_lists, exists): - """ - Given an environment variable name and specified paths, - return a pathsep-separated string of paths containing - unique, extant, directories from those paths and from - the environment variable. Raise an error if no paths - are resolved. - - Parameters - ---------- - name: str - Environment variable name - spec_path_lists: list of str - Paths - exists: bool - It True, only return existing paths. - - Return - ------ - str - Pathsep-separated paths - """ - # flatten spec_path_lists - spec_paths = itertools.chain.from_iterable(spec_path_lists) - env_paths = environ.get(name, '').split(pathsep) - paths = itertools.chain(spec_paths, env_paths) - extant_paths = list(filter(isdir, paths)) if exists else paths - if not extant_paths: - msg = "%s environment variable is empty" % name.upper() - raise distutils.errors.DistutilsPlatformError(msg) - unique_paths = self._unique_everseen(extant_paths) - return pathsep.join(unique_paths) - - # from Python docs - @staticmethod - def _unique_everseen(iterable, key=None): - """ - List unique elements, preserving order. - Remember all elements ever seen. - - _unique_everseen('AAAABBBCCDAABBB') --> A B C D - - _unique_everseen('ABBCcAD', str.lower) --> A B C D - """ - seen = set() - seen_add = seen.add - if key is None: - for element in filterfalse(seen.__contains__, iterable): - seen_add(element) - yield element - else: - for element in iterable: - k = key(element) - if k not in seen: - seen_add(k) - yield element diff --git a/venv/lib/python3.8/site-packages/setuptools/namespaces.py b/venv/lib/python3.8/site-packages/setuptools/namespaces.py deleted file mode 100644 index dc16106..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/namespaces.py +++ /dev/null @@ -1,107 +0,0 @@ -import os -from distutils import log -import itertools - -from setuptools.extern.six.moves import map - - -flatten = itertools.chain.from_iterable - - -class Installer: - - nspkg_ext = '-nspkg.pth' - - def install_namespaces(self): - nsp = self._get_all_ns_packages() - if not nsp: - return - filename, ext = os.path.splitext(self._get_target()) - filename += self.nspkg_ext - self.outputs.append(filename) - log.info("Installing %s", filename) - lines = map(self._gen_nspkg_line, nsp) - - if self.dry_run: - # always generate the lines, even in dry run - list(lines) - return - - with open(filename, 'wt') as f: - f.writelines(lines) - - def uninstall_namespaces(self): - filename, ext = os.path.splitext(self._get_target()) - filename += self.nspkg_ext - if not os.path.exists(filename): - return - log.info("Removing %s", filename) - os.remove(filename) - - def _get_target(self): - return self.target - - _nspkg_tmpl = ( - "import sys, types, os", - "has_mfs = sys.version_info > (3, 5)", - "p = os.path.join(%(root)s, *%(pth)r)", - "importlib = has_mfs and __import__('importlib.util')", - "has_mfs and __import__('importlib.machinery')", - "m = has_mfs and " - "sys.modules.setdefault(%(pkg)r, " - "importlib.util.module_from_spec(" - "importlib.machinery.PathFinder.find_spec(%(pkg)r, " - "[os.path.dirname(p)])))", - "m = m or " - "sys.modules.setdefault(%(pkg)r, types.ModuleType(%(pkg)r))", - "mp = (m or []) and m.__dict__.setdefault('__path__',[])", - "(p not in mp) and mp.append(p)", - ) - "lines for the namespace installer" - - _nspkg_tmpl_multi = ( - 'm and setattr(sys.modules[%(parent)r], %(child)r, m)', - ) - "additional line(s) when a parent package is indicated" - - def _get_root(self): - return "sys._getframe(1).f_locals['sitedir']" - - def _gen_nspkg_line(self, pkg): - # ensure pkg is not a unicode string under Python 2.7 - pkg = str(pkg) - pth = tuple(pkg.split('.')) - root = self._get_root() - tmpl_lines = self._nspkg_tmpl - parent, sep, child = pkg.rpartition('.') - if parent: - tmpl_lines += self._nspkg_tmpl_multi - return ';'.join(tmpl_lines) % locals() + '\n' - - def _get_all_ns_packages(self): - """Return sorted list of all package namespaces""" - pkgs = self.distribution.namespace_packages or [] - return sorted(flatten(map(self._pkg_names, pkgs))) - - @staticmethod - def _pkg_names(pkg): - """ - Given a namespace package, yield the components of that - package. - - >>> names = Installer._pkg_names('a.b.c') - >>> set(names) == set(['a', 'a.b', 'a.b.c']) - True - """ - parts = pkg.split('.') - while parts: - yield '.'.join(parts) - parts.pop() - - -class DevelopInstaller(Installer): - def _get_root(self): - return repr(str(self.egg_path)) - - def _get_target(self): - return self.egg_link diff --git a/venv/lib/python3.8/site-packages/setuptools/package_index.py b/venv/lib/python3.8/site-packages/setuptools/package_index.py deleted file mode 100644 index f419d47..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/package_index.py +++ /dev/null @@ -1,1136 +0,0 @@ -"""PyPI and direct package downloading""" -import sys -import os -import re -import shutil -import socket -import base64 -import hashlib -import itertools -import warnings -from functools import wraps - -from setuptools.extern import six -from setuptools.extern.six.moves import urllib, http_client, configparser, map - -import setuptools -from pkg_resources import ( - CHECKOUT_DIST, Distribution, BINARY_DIST, normalize_path, SOURCE_DIST, - Environment, find_distributions, safe_name, safe_version, - to_filename, Requirement, DEVELOP_DIST, EGG_DIST, -) -from setuptools import ssl_support -from distutils import log -from distutils.errors import DistutilsError -from fnmatch import translate -from setuptools.py27compat import get_all_headers -from setuptools.py33compat import unescape -from setuptools.wheel import Wheel - -__metaclass__ = type - -EGG_FRAGMENT = re.compile(r'^egg=([-A-Za-z0-9_.+!]+)$') -HREF = re.compile(r"""href\s*=\s*['"]?([^'"> ]+)""", re.I) -PYPI_MD5 = re.compile( - r'<a href="([^"#]+)">([^<]+)</a>\n\s+\(<a (?:title="MD5 hash"\n\s+)' - r'href="[^?]+\?:action=show_md5&amp;digest=([0-9a-f]{32})">md5</a>\)' -) -URL_SCHEME = re.compile('([-+.a-z0-9]{2,}):', re.I).match -EXTENSIONS = ".tar.gz .tar.bz2 .tar .zip .tgz".split() - -__all__ = [ - 'PackageIndex', 'distros_for_url', 'parse_bdist_wininst', - 'interpret_distro_name', -] - -_SOCKET_TIMEOUT = 15 - -_tmpl = "setuptools/{setuptools.__version__} Python-urllib/{py_major}" -user_agent = _tmpl.format(py_major='{}.{}'.format(*sys.version_info), setuptools=setuptools) - - -def parse_requirement_arg(spec): - try: - return Requirement.parse(spec) - except ValueError: - raise DistutilsError( - "Not a URL, existing file, or requirement spec: %r" % (spec,) - ) - - -def parse_bdist_wininst(name): - """Return (base,pyversion) or (None,None) for possible .exe name""" - - lower = name.lower() - base, py_ver, plat = None, None, None - - if lower.endswith('.exe'): - if lower.endswith('.win32.exe'): - base = name[:-10] - plat = 'win32' - elif lower.startswith('.win32-py', -16): - py_ver = name[-7:-4] - base = name[:-16] - plat = 'win32' - elif lower.endswith('.win-amd64.exe'): - base = name[:-14] - plat = 'win-amd64' - elif lower.startswith('.win-amd64-py', -20): - py_ver = name[-7:-4] - base = name[:-20] - plat = 'win-amd64' - return base, py_ver, plat - - -def egg_info_for_url(url): - parts = urllib.parse.urlparse(url) - scheme, server, path, parameters, query, fragment = parts - base = urllib.parse.unquote(path.split('/')[-1]) - if server == 'sourceforge.net' and base == 'download': # XXX Yuck - base = urllib.parse.unquote(path.split('/')[-2]) - if '#' in base: - base, fragment = base.split('#', 1) - return base, fragment - - -def distros_for_url(url, metadata=None): - """Yield egg or source distribution objects that might be found at a URL""" - base, fragment = egg_info_for_url(url) - for dist in distros_for_location(url, base, metadata): - yield dist - if fragment: - match = EGG_FRAGMENT.match(fragment) - if match: - for dist in interpret_distro_name( - url, match.group(1), metadata, precedence=CHECKOUT_DIST - ): - yield dist - - -def distros_for_location(location, basename, metadata=None): - """Yield egg or source distribution objects based on basename""" - if basename.endswith('.egg.zip'): - basename = basename[:-4] # strip the .zip - if basename.endswith('.egg') and '-' in basename: - # only one, unambiguous interpretation - return [Distribution.from_location(location, basename, metadata)] - if basename.endswith('.whl') and '-' in basename: - wheel = Wheel(basename) - if not wheel.is_compatible(): - return [] - return [Distribution( - location=location, - project_name=wheel.project_name, - version=wheel.version, - # Increase priority over eggs. - precedence=EGG_DIST + 1, - )] - if basename.endswith('.exe'): - win_base, py_ver, platform = parse_bdist_wininst(basename) - if win_base is not None: - return interpret_distro_name( - location, win_base, metadata, py_ver, BINARY_DIST, platform - ) - # Try source distro extensions (.zip, .tgz, etc.) - # - for ext in EXTENSIONS: - if basename.endswith(ext): - basename = basename[:-len(ext)] - return interpret_distro_name(location, basename, metadata) - return [] # no extension matched - - -def distros_for_filename(filename, metadata=None): - """Yield possible egg or source distribution objects based on a filename""" - return distros_for_location( - normalize_path(filename), os.path.basename(filename), metadata - ) - - -def interpret_distro_name( - location, basename, metadata, py_version=None, precedence=SOURCE_DIST, - platform=None -): - """Generate alternative interpretations of a source distro name - - Note: if `location` is a filesystem filename, you should call - ``pkg_resources.normalize_path()`` on it before passing it to this - routine! - """ - # Generate alternative interpretations of a source distro name - # Because some packages are ambiguous as to name/versions split - # e.g. "adns-python-1.1.0", "egenix-mx-commercial", etc. - # So, we generate each possible interepretation (e.g. "adns, python-1.1.0" - # "adns-python, 1.1.0", and "adns-python-1.1.0, no version"). In practice, - # the spurious interpretations should be ignored, because in the event - # there's also an "adns" package, the spurious "python-1.1.0" version will - # compare lower than any numeric version number, and is therefore unlikely - # to match a request for it. It's still a potential problem, though, and - # in the long run PyPI and the distutils should go for "safe" names and - # versions in distribution archive names (sdist and bdist). - - parts = basename.split('-') - if not py_version and any(re.match(r'py\d\.\d$', p) for p in parts[2:]): - # it is a bdist_dumb, not an sdist -- bail out - return - - for p in range(1, len(parts) + 1): - yield Distribution( - location, metadata, '-'.join(parts[:p]), '-'.join(parts[p:]), - py_version=py_version, precedence=precedence, - platform=platform - ) - - -# From Python 2.7 docs -def unique_everseen(iterable, key=None): - "List unique elements, preserving order. Remember all elements ever seen." - # unique_everseen('AAAABBBCCDAABBB') --> A B C D - # unique_everseen('ABBCcAD', str.lower) --> A B C D - seen = set() - seen_add = seen.add - if key is None: - for element in six.moves.filterfalse(seen.__contains__, iterable): - seen_add(element) - yield element - else: - for element in iterable: - k = key(element) - if k not in seen: - seen_add(k) - yield element - - -def unique_values(func): - """ - Wrap a function returning an iterable such that the resulting iterable - only ever yields unique items. - """ - - @wraps(func) - def wrapper(*args, **kwargs): - return unique_everseen(func(*args, **kwargs)) - - return wrapper - - -REL = re.compile(r"""<([^>]*\srel\s*=\s*['"]?([^'">]+)[^>]*)>""", re.I) -# this line is here to fix emacs' cruddy broken syntax highlighting - - -@unique_values -def find_external_links(url, page): - """Find rel="homepage" and rel="download" links in `page`, yielding URLs""" - - for match in REL.finditer(page): - tag, rel = match.groups() - rels = set(map(str.strip, rel.lower().split(','))) - if 'homepage' in rels or 'download' in rels: - for match in HREF.finditer(tag): - yield urllib.parse.urljoin(url, htmldecode(match.group(1))) - - for tag in ("<th>Home Page", "<th>Download URL"): - pos = page.find(tag) - if pos != -1: - match = HREF.search(page, pos) - if match: - yield urllib.parse.urljoin(url, htmldecode(match.group(1))) - - -class ContentChecker: - """ - A null content checker that defines the interface for checking content - """ - - def feed(self, block): - """ - Feed a block of data to the hash. - """ - return - - def is_valid(self): - """ - Check the hash. Return False if validation fails. - """ - return True - - def report(self, reporter, template): - """ - Call reporter with information about the checker (hash name) - substituted into the template. - """ - return - - -class HashChecker(ContentChecker): - pattern = re.compile( - r'(?P<hash_name>sha1|sha224|sha384|sha256|sha512|md5)=' - r'(?P<expected>[a-f0-9]+)' - ) - - def __init__(self, hash_name, expected): - self.hash_name = hash_name - self.hash = hashlib.new(hash_name) - self.expected = expected - - @classmethod - def from_url(cls, url): - "Construct a (possibly null) ContentChecker from a URL" - fragment = urllib.parse.urlparse(url)[-1] - if not fragment: - return ContentChecker() - match = cls.pattern.search(fragment) - if not match: - return ContentChecker() - return cls(**match.groupdict()) - - def feed(self, block): - self.hash.update(block) - - def is_valid(self): - return self.hash.hexdigest() == self.expected - - def report(self, reporter, template): - msg = template % self.hash_name - return reporter(msg) - - -class PackageIndex(Environment): - """A distribution index that scans web pages for download URLs""" - - def __init__( - self, index_url="https://pypi.org/simple/", hosts=('*',), - ca_bundle=None, verify_ssl=True, *args, **kw - ): - Environment.__init__(self, *args, **kw) - self.index_url = index_url + "/" [:not index_url.endswith('/')] - self.scanned_urls = {} - self.fetched_urls = {} - self.package_pages = {} - self.allows = re.compile('|'.join(map(translate, hosts))).match - self.to_scan = [] - use_ssl = ( - verify_ssl - and ssl_support.is_available - and (ca_bundle or ssl_support.find_ca_bundle()) - ) - if use_ssl: - self.opener = ssl_support.opener_for(ca_bundle) - else: - self.opener = urllib.request.urlopen - - def process_url(self, url, retrieve=False): - """Evaluate a URL as a possible download, and maybe retrieve it""" - if url in self.scanned_urls and not retrieve: - return - self.scanned_urls[url] = True - if not URL_SCHEME(url): - self.process_filename(url) - return - else: - dists = list(distros_for_url(url)) - if dists: - if not self.url_ok(url): - return - self.debug("Found link: %s", url) - - if dists or not retrieve or url in self.fetched_urls: - list(map(self.add, dists)) - return # don't need the actual page - - if not self.url_ok(url): - self.fetched_urls[url] = True - return - - self.info("Reading %s", url) - self.fetched_urls[url] = True # prevent multiple fetch attempts - tmpl = "Download error on %s: %%s -- Some packages may not be found!" - f = self.open_url(url, tmpl % url) - if f is None: - return - self.fetched_urls[f.url] = True - if 'html' not in f.headers.get('content-type', '').lower(): - f.close() # not html, we can't process it - return - - base = f.url # handle redirects - page = f.read() - if not isinstance(page, str): - # In Python 3 and got bytes but want str. - if isinstance(f, urllib.error.HTTPError): - # Errors have no charset, assume latin1: - charset = 'latin-1' - else: - charset = f.headers.get_param('charset') or 'latin-1' - page = page.decode(charset, "ignore") - f.close() - for match in HREF.finditer(page): - link = urllib.parse.urljoin(base, htmldecode(match.group(1))) - self.process_url(link) - if url.startswith(self.index_url) and getattr(f, 'code', None) != 404: - page = self.process_index(url, page) - - def process_filename(self, fn, nested=False): - # process filenames or directories - if not os.path.exists(fn): - self.warn("Not found: %s", fn) - return - - if os.path.isdir(fn) and not nested: - path = os.path.realpath(fn) - for item in os.listdir(path): - self.process_filename(os.path.join(path, item), True) - - dists = distros_for_filename(fn) - if dists: - self.debug("Found: %s", fn) - list(map(self.add, dists)) - - def url_ok(self, url, fatal=False): - s = URL_SCHEME(url) - is_file = s and s.group(1).lower() == 'file' - if is_file or self.allows(urllib.parse.urlparse(url)[1]): - return True - msg = ( - "\nNote: Bypassing %s (disallowed host; see " - "http://bit.ly/2hrImnY for details).\n") - if fatal: - raise DistutilsError(msg % url) - else: - self.warn(msg, url) - - def scan_egg_links(self, search_path): - dirs = filter(os.path.isdir, search_path) - egg_links = ( - (path, entry) - for path in dirs - for entry in os.listdir(path) - if entry.endswith('.egg-link') - ) - list(itertools.starmap(self.scan_egg_link, egg_links)) - - def scan_egg_link(self, path, entry): - with open(os.path.join(path, entry)) as raw_lines: - # filter non-empty lines - lines = list(filter(None, map(str.strip, raw_lines))) - - if len(lines) != 2: - # format is not recognized; punt - return - - egg_path, setup_path = lines - - for dist in find_distributions(os.path.join(path, egg_path)): - dist.location = os.path.join(path, *lines) - dist.precedence = SOURCE_DIST - self.add(dist) - - def process_index(self, url, page): - """Process the contents of a PyPI page""" - - def scan(link): - # Process a URL to see if it's for a package page - if link.startswith(self.index_url): - parts = list(map( - urllib.parse.unquote, link[len(self.index_url):].split('/') - )) - if len(parts) == 2 and '#' not in parts[1]: - # it's a package page, sanitize and index it - pkg = safe_name(parts[0]) - ver = safe_version(parts[1]) - self.package_pages.setdefault(pkg.lower(), {})[link] = True - return to_filename(pkg), to_filename(ver) - return None, None - - # process an index page into the package-page index - for match in HREF.finditer(page): - try: - scan(urllib.parse.urljoin(url, htmldecode(match.group(1)))) - except ValueError: - pass - - pkg, ver = scan(url) # ensure this page is in the page index - if pkg: - # process individual package page - for new_url in find_external_links(url, page): - # Process the found URL - base, frag = egg_info_for_url(new_url) - if base.endswith('.py') and not frag: - if ver: - new_url += '#egg=%s-%s' % (pkg, ver) - else: - self.need_version_info(url) - self.scan_url(new_url) - - return PYPI_MD5.sub( - lambda m: '<a href="%s#md5=%s">%s</a>' % m.group(1, 3, 2), page - ) - else: - return "" # no sense double-scanning non-package pages - - def need_version_info(self, url): - self.scan_all( - "Page at %s links to .py file(s) without version info; an index " - "scan is required.", url - ) - - def scan_all(self, msg=None, *args): - if self.index_url not in self.fetched_urls: - if msg: - self.warn(msg, *args) - self.info( - "Scanning index of all packages (this may take a while)" - ) - self.scan_url(self.index_url) - - def find_packages(self, requirement): - self.scan_url(self.index_url + requirement.unsafe_name + '/') - - if not self.package_pages.get(requirement.key): - # Fall back to safe version of the name - self.scan_url(self.index_url + requirement.project_name + '/') - - if not self.package_pages.get(requirement.key): - # We couldn't find the target package, so search the index page too - self.not_found_in_index(requirement) - - for url in list(self.package_pages.get(requirement.key, ())): - # scan each page that might be related to the desired package - self.scan_url(url) - - def obtain(self, requirement, installer=None): - self.prescan() - self.find_packages(requirement) - for dist in self[requirement.key]: - if dist in requirement: - return dist - self.debug("%s does not match %s", requirement, dist) - return super(PackageIndex, self).obtain(requirement, installer) - - def check_hash(self, checker, filename, tfp): - """ - checker is a ContentChecker - """ - checker.report( - self.debug, - "Validating %%s checksum for %s" % filename) - if not checker.is_valid(): - tfp.close() - os.unlink(filename) - raise DistutilsError( - "%s validation failed for %s; " - "possible download problem?" - % (checker.hash.name, os.path.basename(filename)) - ) - - def add_find_links(self, urls): - """Add `urls` to the list that will be prescanned for searches""" - for url in urls: - if ( - self.to_scan is None # if we have already "gone online" - or not URL_SCHEME(url) # or it's a local file/directory - or url.startswith('file:') - or list(distros_for_url(url)) # or a direct package link - ): - # then go ahead and process it now - self.scan_url(url) - else: - # otherwise, defer retrieval till later - self.to_scan.append(url) - - def prescan(self): - """Scan urls scheduled for prescanning (e.g. --find-links)""" - if self.to_scan: - list(map(self.scan_url, self.to_scan)) - self.to_scan = None # from now on, go ahead and process immediately - - def not_found_in_index(self, requirement): - if self[requirement.key]: # we've seen at least one distro - meth, msg = self.info, "Couldn't retrieve index page for %r" - else: # no distros seen for this name, might be misspelled - meth, msg = ( - self.warn, - "Couldn't find index page for %r (maybe misspelled?)") - meth(msg, requirement.unsafe_name) - self.scan_all() - - def download(self, spec, tmpdir): - """Locate and/or download `spec` to `tmpdir`, returning a local path - - `spec` may be a ``Requirement`` object, or a string containing a URL, - an existing local filename, or a project/version requirement spec - (i.e. the string form of a ``Requirement`` object). If it is the URL - of a .py file with an unambiguous ``#egg=name-version`` tag (i.e., one - that escapes ``-`` as ``_`` throughout), a trivial ``setup.py`` is - automatically created alongside the downloaded file. - - If `spec` is a ``Requirement`` object or a string containing a - project/version requirement spec, this method returns the location of - a matching distribution (possibly after downloading it to `tmpdir`). - If `spec` is a locally existing file or directory name, it is simply - returned unchanged. If `spec` is a URL, it is downloaded to a subpath - of `tmpdir`, and the local filename is returned. Various errors may be - raised if a problem occurs during downloading. - """ - if not isinstance(spec, Requirement): - scheme = URL_SCHEME(spec) - if scheme: - # It's a url, download it to tmpdir - found = self._download_url(scheme.group(1), spec, tmpdir) - base, fragment = egg_info_for_url(spec) - if base.endswith('.py'): - found = self.gen_setup(found, fragment, tmpdir) - return found - elif os.path.exists(spec): - # Existing file or directory, just return it - return spec - else: - spec = parse_requirement_arg(spec) - return getattr(self.fetch_distribution(spec, tmpdir), 'location', None) - - def fetch_distribution( - self, requirement, tmpdir, force_scan=False, source=False, - develop_ok=False, local_index=None): - """Obtain a distribution suitable for fulfilling `requirement` - - `requirement` must be a ``pkg_resources.Requirement`` instance. - If necessary, or if the `force_scan` flag is set, the requirement is - searched for in the (online) package index as well as the locally - installed packages. If a distribution matching `requirement` is found, - the returned distribution's ``location`` is the value you would have - gotten from calling the ``download()`` method with the matching - distribution's URL or filename. If no matching distribution is found, - ``None`` is returned. - - If the `source` flag is set, only source distributions and source - checkout links will be considered. Unless the `develop_ok` flag is - set, development and system eggs (i.e., those using the ``.egg-info`` - format) will be ignored. - """ - # process a Requirement - self.info("Searching for %s", requirement) - skipped = {} - dist = None - - def find(req, env=None): - if env is None: - env = self - # Find a matching distribution; may be called more than once - - for dist in env[req.key]: - - if dist.precedence == DEVELOP_DIST and not develop_ok: - if dist not in skipped: - self.warn( - "Skipping development or system egg: %s", dist, - ) - skipped[dist] = 1 - continue - - test = ( - dist in req - and (dist.precedence <= SOURCE_DIST or not source) - ) - if test: - loc = self.download(dist.location, tmpdir) - dist.download_location = loc - if os.path.exists(dist.download_location): - return dist - - if force_scan: - self.prescan() - self.find_packages(requirement) - dist = find(requirement) - - if not dist and local_index is not None: - dist = find(requirement, local_index) - - if dist is None: - if self.to_scan is not None: - self.prescan() - dist = find(requirement) - - if dist is None and not force_scan: - self.find_packages(requirement) - dist = find(requirement) - - if dist is None: - self.warn( - "No local packages or working download links found for %s%s", - (source and "a source distribution of " or ""), - requirement, - ) - else: - self.info("Best match: %s", dist) - return dist.clone(location=dist.download_location) - - def fetch(self, requirement, tmpdir, force_scan=False, source=False): - """Obtain a file suitable for fulfilling `requirement` - - DEPRECATED; use the ``fetch_distribution()`` method now instead. For - backward compatibility, this routine is identical but returns the - ``location`` of the downloaded distribution instead of a distribution - object. - """ - dist = self.fetch_distribution(requirement, tmpdir, force_scan, source) - if dist is not None: - return dist.location - return None - - def gen_setup(self, filename, fragment, tmpdir): - match = EGG_FRAGMENT.match(fragment) - dists = match and [ - d for d in - interpret_distro_name(filename, match.group(1), None) if d.version - ] or [] - - if len(dists) == 1: # unambiguous ``#egg`` fragment - basename = os.path.basename(filename) - - # Make sure the file has been downloaded to the temp dir. - if os.path.dirname(filename) != tmpdir: - dst = os.path.join(tmpdir, basename) - from setuptools.command.easy_install import samefile - if not samefile(filename, dst): - shutil.copy2(filename, dst) - filename = dst - - with open(os.path.join(tmpdir, 'setup.py'), 'w') as file: - file.write( - "from setuptools import setup\n" - "setup(name=%r, version=%r, py_modules=[%r])\n" - % ( - dists[0].project_name, dists[0].version, - os.path.splitext(basename)[0] - ) - ) - return filename - - elif match: - raise DistutilsError( - "Can't unambiguously interpret project/version identifier %r; " - "any dashes in the name or version should be escaped using " - "underscores. %r" % (fragment, dists) - ) - else: - raise DistutilsError( - "Can't process plain .py files without an '#egg=name-version'" - " suffix to enable automatic setup script generation." - ) - - dl_blocksize = 8192 - - def _download_to(self, url, filename): - self.info("Downloading %s", url) - # Download the file - fp = None - try: - checker = HashChecker.from_url(url) - fp = self.open_url(url) - if isinstance(fp, urllib.error.HTTPError): - raise DistutilsError( - "Can't download %s: %s %s" % (url, fp.code, fp.msg) - ) - headers = fp.info() - blocknum = 0 - bs = self.dl_blocksize - size = -1 - if "content-length" in headers: - # Some servers return multiple Content-Length headers :( - sizes = get_all_headers(headers, 'Content-Length') - size = max(map(int, sizes)) - self.reporthook(url, filename, blocknum, bs, size) - with open(filename, 'wb') as tfp: - while True: - block = fp.read(bs) - if block: - checker.feed(block) - tfp.write(block) - blocknum += 1 - self.reporthook(url, filename, blocknum, bs, size) - else: - break - self.check_hash(checker, filename, tfp) - return headers - finally: - if fp: - fp.close() - - def reporthook(self, url, filename, blocknum, blksize, size): - pass # no-op - - def open_url(self, url, warning=None): - if url.startswith('file:'): - return local_open(url) - try: - return open_with_auth(url, self.opener) - except (ValueError, http_client.InvalidURL) as v: - msg = ' '.join([str(arg) for arg in v.args]) - if warning: - self.warn(warning, msg) - else: - raise DistutilsError('%s %s' % (url, msg)) - except urllib.error.HTTPError as v: - return v - except urllib.error.URLError as v: - if warning: - self.warn(warning, v.reason) - else: - raise DistutilsError("Download error for %s: %s" - % (url, v.reason)) - except http_client.BadStatusLine as v: - if warning: - self.warn(warning, v.line) - else: - raise DistutilsError( - '%s returned a bad status line. The server might be ' - 'down, %s' % - (url, v.line) - ) - except (http_client.HTTPException, socket.error) as v: - if warning: - self.warn(warning, v) - else: - raise DistutilsError("Download error for %s: %s" - % (url, v)) - - def _download_url(self, scheme, url, tmpdir): - # Determine download filename - # - name, fragment = egg_info_for_url(url) - if name: - while '..' in name: - name = name.replace('..', '.').replace('\\', '_') - else: - name = "__downloaded__" # default if URL has no path contents - - if name.endswith('.egg.zip'): - name = name[:-4] # strip the extra .zip before download - - filename = os.path.join(tmpdir, name) - - # Download the file - # - if scheme == 'svn' or scheme.startswith('svn+'): - return self._download_svn(url, filename) - elif scheme == 'git' or scheme.startswith('git+'): - return self._download_git(url, filename) - elif scheme.startswith('hg+'): - return self._download_hg(url, filename) - elif scheme == 'file': - return urllib.request.url2pathname(urllib.parse.urlparse(url)[2]) - else: - self.url_ok(url, True) # raises error if not allowed - return self._attempt_download(url, filename) - - def scan_url(self, url): - self.process_url(url, True) - - def _attempt_download(self, url, filename): - headers = self._download_to(url, filename) - if 'html' in headers.get('content-type', '').lower(): - return self._download_html(url, headers, filename) - else: - return filename - - def _download_html(self, url, headers, filename): - file = open(filename) - for line in file: - if line.strip(): - # Check for a subversion index page - if re.search(r'<title>([^- ]+ - )?Revision \d+:', line): - # it's a subversion index page: - file.close() - os.unlink(filename) - return self._download_svn(url, filename) - break # not an index page - file.close() - os.unlink(filename) - raise DistutilsError("Unexpected HTML page found at " + url) - - def _download_svn(self, url, filename): - warnings.warn("SVN download support is deprecated", UserWarning) - url = url.split('#', 1)[0] # remove any fragment for svn's sake - creds = '' - if url.lower().startswith('svn:') and '@' in url: - scheme, netloc, path, p, q, f = urllib.parse.urlparse(url) - if not netloc and path.startswith('//') and '/' in path[2:]: - netloc, path = path[2:].split('/', 1) - auth, host = _splituser(netloc) - if auth: - if ':' in auth: - user, pw = auth.split(':', 1) - creds = " --username=%s --password=%s" % (user, pw) - else: - creds = " --username=" + auth - netloc = host - parts = scheme, netloc, url, p, q, f - url = urllib.parse.urlunparse(parts) - self.info("Doing subversion checkout from %s to %s", url, filename) - os.system("svn checkout%s -q %s %s" % (creds, url, filename)) - return filename - - @staticmethod - def _vcs_split_rev_from_url(url, pop_prefix=False): - scheme, netloc, path, query, frag = urllib.parse.urlsplit(url) - - scheme = scheme.split('+', 1)[-1] - - # Some fragment identification fails - path = path.split('#', 1)[0] - - rev = None - if '@' in path: - path, rev = path.rsplit('@', 1) - - # Also, discard fragment - url = urllib.parse.urlunsplit((scheme, netloc, path, query, '')) - - return url, rev - - def _download_git(self, url, filename): - filename = filename.split('#', 1)[0] - url, rev = self._vcs_split_rev_from_url(url, pop_prefix=True) - - self.info("Doing git clone from %s to %s", url, filename) - os.system("git clone --quiet %s %s" % (url, filename)) - - if rev is not None: - self.info("Checking out %s", rev) - os.system("git -C %s checkout --quiet %s" % ( - filename, - rev, - )) - - return filename - - def _download_hg(self, url, filename): - filename = filename.split('#', 1)[0] - url, rev = self._vcs_split_rev_from_url(url, pop_prefix=True) - - self.info("Doing hg clone from %s to %s", url, filename) - os.system("hg clone --quiet %s %s" % (url, filename)) - - if rev is not None: - self.info("Updating to %s", rev) - os.system("hg --cwd %s up -C -r %s -q" % ( - filename, - rev, - )) - - return filename - - def debug(self, msg, *args): - log.debug(msg, *args) - - def info(self, msg, *args): - log.info(msg, *args) - - def warn(self, msg, *args): - log.warn(msg, *args) - - -# This pattern matches a character entity reference (a decimal numeric -# references, a hexadecimal numeric reference, or a named reference). -entity_sub = re.compile(r'&(#(\d+|x[\da-fA-F]+)|[\w.:-]+);?').sub - - -def decode_entity(match): - what = match.group(0) - return unescape(what) - - -def htmldecode(text): - """ - Decode HTML entities in the given text. - - >>> htmldecode( - ... 'https://../package_name-0.1.2.tar.gz' - ... '?tokena=A&amp;tokenb=B">package_name-0.1.2.tar.gz') - 'https://../package_name-0.1.2.tar.gz?tokena=A&tokenb=B">package_name-0.1.2.tar.gz' - """ - return entity_sub(decode_entity, text) - - -def socket_timeout(timeout=15): - def _socket_timeout(func): - def _socket_timeout(*args, **kwargs): - old_timeout = socket.getdefaulttimeout() - socket.setdefaulttimeout(timeout) - try: - return func(*args, **kwargs) - finally: - socket.setdefaulttimeout(old_timeout) - - return _socket_timeout - - return _socket_timeout - - -def _encode_auth(auth): - """ - A function compatible with Python 2.3-3.3 that will encode - auth from a URL suitable for an HTTP header. - >>> str(_encode_auth('username%3Apassword')) - 'dXNlcm5hbWU6cGFzc3dvcmQ=' - - Long auth strings should not cause a newline to be inserted. - >>> long_auth = 'username:' + 'password'*10 - >>> chr(10) in str(_encode_auth(long_auth)) - False - """ - auth_s = urllib.parse.unquote(auth) - # convert to bytes - auth_bytes = auth_s.encode() - encoded_bytes = base64.b64encode(auth_bytes) - # convert back to a string - encoded = encoded_bytes.decode() - # strip the trailing carriage return - return encoded.replace('\n', '') - - -class Credential: - """ - A username/password pair. Use like a namedtuple. - """ - - def __init__(self, username, password): - self.username = username - self.password = password - - def __iter__(self): - yield self.username - yield self.password - - def __str__(self): - return '%(username)s:%(password)s' % vars(self) - - -class PyPIConfig(configparser.RawConfigParser): - def __init__(self): - """ - Load from ~/.pypirc - """ - defaults = dict.fromkeys(['username', 'password', 'repository'], '') - configparser.RawConfigParser.__init__(self, defaults) - - rc = os.path.join(os.path.expanduser('~'), '.pypirc') - if os.path.exists(rc): - self.read(rc) - - @property - def creds_by_repository(self): - sections_with_repositories = [ - section for section in self.sections() - if self.get(section, 'repository').strip() - ] - - return dict(map(self._get_repo_cred, sections_with_repositories)) - - def _get_repo_cred(self, section): - repo = self.get(section, 'repository').strip() - return repo, Credential( - self.get(section, 'username').strip(), - self.get(section, 'password').strip(), - ) - - def find_credential(self, url): - """ - If the URL indicated appears to be a repository defined in this - config, return the credential for that repository. - """ - for repository, cred in self.creds_by_repository.items(): - if url.startswith(repository): - return cred - - -def open_with_auth(url, opener=urllib.request.urlopen): - """Open a urllib2 request, handling HTTP authentication""" - - parsed = urllib.parse.urlparse(url) - scheme, netloc, path, params, query, frag = parsed - - # Double scheme does not raise on Mac OS X as revealed by a - # failing test. We would expect "nonnumeric port". Refs #20. - if netloc.endswith(':'): - raise http_client.InvalidURL("nonnumeric port: ''") - - if scheme in ('http', 'https'): - auth, address = _splituser(netloc) - else: - auth = None - - if not auth: - cred = PyPIConfig().find_credential(url) - if cred: - auth = str(cred) - info = cred.username, url - log.info('Authenticating as %s for %s (from .pypirc)', *info) - - if auth: - auth = "Basic " + _encode_auth(auth) - parts = scheme, address, path, params, query, frag - new_url = urllib.parse.urlunparse(parts) - request = urllib.request.Request(new_url) - request.add_header("Authorization", auth) - else: - request = urllib.request.Request(url) - - request.add_header('User-Agent', user_agent) - fp = opener(request) - - if auth: - # Put authentication info back into request URL if same host, - # so that links found on the page will work - s2, h2, path2, param2, query2, frag2 = urllib.parse.urlparse(fp.url) - if s2 == scheme and h2 == address: - parts = s2, netloc, path2, param2, query2, frag2 - fp.url = urllib.parse.urlunparse(parts) - - return fp - - -# copy of urllib.parse._splituser from Python 3.8 -def _splituser(host): - """splituser('user[:passwd]@host[:port]') --> 'user[:passwd]', 'host[:port]'.""" - user, delim, host = host.rpartition('@') - return (user if delim else None), host - - -# adding a timeout to avoid freezing package_index -open_with_auth = socket_timeout(_SOCKET_TIMEOUT)(open_with_auth) - - -def fix_sf_url(url): - return url # backward compatibility - - -def local_open(url): - """Read a local path, with special support for directories""" - scheme, server, path, param, query, frag = urllib.parse.urlparse(url) - filename = urllib.request.url2pathname(path) - if os.path.isfile(filename): - return urllib.request.urlopen(url) - elif path.endswith('/') and os.path.isdir(filename): - files = [] - for f in os.listdir(filename): - filepath = os.path.join(filename, f) - if f == 'index.html': - with open(filepath, 'r') as fp: - body = fp.read() - break - elif os.path.isdir(filepath): - f += '/' - files.append('<a href="{name}">{name}</a>'.format(name=f)) - else: - tmpl = ( - "<html><head><title>{url}</title>" - "</head><body>{files}</body></html>") - body = tmpl.format(url=url, files='\n'.join(files)) - status, message = 200, "OK" - else: - status, message, body = 404, "Path not found", "Not found" - - headers = {'content-type': 'text/html'} - body_stream = six.StringIO(body) - return urllib.error.HTTPError(url, status, message, headers, body_stream) diff --git a/venv/lib/python3.8/site-packages/setuptools/py27compat.py b/venv/lib/python3.8/site-packages/setuptools/py27compat.py deleted file mode 100644 index 1d57360..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/py27compat.py +++ /dev/null @@ -1,60 +0,0 @@ -""" -Compatibility Support for Python 2.7 and earlier -""" - -import sys -import platform - -from setuptools.extern import six - - -def get_all_headers(message, key): - """ - Given an HTTPMessage, return all headers matching a given key. - """ - return message.get_all(key) - - -if six.PY2: - def get_all_headers(message, key): - return message.getheaders(key) - - -linux_py2_ascii = ( - platform.system() == 'Linux' and - six.PY2 -) - -rmtree_safe = str if linux_py2_ascii else lambda x: x -"""Workaround for http://bugs.python.org/issue24672""" - - -try: - from ._imp import find_module, PY_COMPILED, PY_FROZEN, PY_SOURCE - from ._imp import get_frozen_object, get_module -except ImportError: - import imp - from imp import PY_COMPILED, PY_FROZEN, PY_SOURCE # noqa - - def find_module(module, paths=None): - """Just like 'imp.find_module()', but with package support""" - parts = module.split('.') - while parts: - part = parts.pop(0) - f, path, (suffix, mode, kind) = info = imp.find_module(part, paths) - - if kind == imp.PKG_DIRECTORY: - parts = parts or ['__init__'] - paths = [path] - - elif parts: - raise ImportError("Can't find %r in %s" % (parts, module)) - - return info - - def get_frozen_object(module, paths): - return imp.get_frozen_object(module) - - def get_module(module, paths, info): - imp.load_module(module, *info) - return sys.modules[module] diff --git a/venv/lib/python3.8/site-packages/setuptools/py31compat.py b/venv/lib/python3.8/site-packages/setuptools/py31compat.py deleted file mode 100644 index e1da7ee..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/py31compat.py +++ /dev/null @@ -1,32 +0,0 @@ -__all__ = [] - -__metaclass__ = type - - -try: - # Python >=3.2 - from tempfile import TemporaryDirectory -except ImportError: - import shutil - import tempfile - - class TemporaryDirectory: - """ - Very simple temporary directory context manager. - Will try to delete afterward, but will also ignore OS and similar - errors on deletion. - """ - - def __init__(self, **kwargs): - self.name = None # Handle mkdtemp raising an exception - self.name = tempfile.mkdtemp(**kwargs) - - def __enter__(self): - return self.name - - def __exit__(self, exctype, excvalue, exctrace): - try: - shutil.rmtree(self.name, True) - except OSError: # removal errors are not the only possible - pass - self.name = None diff --git a/venv/lib/python3.8/site-packages/setuptools/py33compat.py b/venv/lib/python3.8/site-packages/setuptools/py33compat.py deleted file mode 100644 index cb69443..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/py33compat.py +++ /dev/null @@ -1,59 +0,0 @@ -import dis -import array -import collections - -try: - import html -except ImportError: - html = None - -from setuptools.extern import six -from setuptools.extern.six.moves import html_parser - -__metaclass__ = type - -OpArg = collections.namedtuple('OpArg', 'opcode arg') - - -class Bytecode_compat: - def __init__(self, code): - self.code = code - - def __iter__(self): - """Yield '(op,arg)' pair for each operation in code object 'code'""" - - bytes = array.array('b', self.code.co_code) - eof = len(self.code.co_code) - - ptr = 0 - extended_arg = 0 - - while ptr < eof: - - op = bytes[ptr] - - if op >= dis.HAVE_ARGUMENT: - - arg = bytes[ptr + 1] + bytes[ptr + 2] * 256 + extended_arg - ptr += 3 - - if op == dis.EXTENDED_ARG: - long_type = six.integer_types[-1] - extended_arg = arg * long_type(65536) - continue - - else: - arg = None - ptr += 1 - - yield OpArg(op, arg) - - -Bytecode = getattr(dis, 'Bytecode', Bytecode_compat) - - -unescape = getattr(html, 'unescape', None) -if unescape is None: - # HTMLParser.unescape is deprecated since Python 3.4, and will be removed - # from 3.9. - unescape = html_parser.HTMLParser().unescape diff --git a/venv/lib/python3.8/site-packages/setuptools/py34compat.py b/venv/lib/python3.8/site-packages/setuptools/py34compat.py deleted file mode 100644 index 3ad9172..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/py34compat.py +++ /dev/null @@ -1,13 +0,0 @@ -import importlib - -try: - import importlib.util -except ImportError: - pass - - -try: - module_from_spec = importlib.util.module_from_spec -except AttributeError: - def module_from_spec(spec): - return spec.loader.load_module(spec.name) diff --git a/venv/lib/python3.8/site-packages/setuptools/sandbox.py b/venv/lib/python3.8/site-packages/setuptools/sandbox.py deleted file mode 100644 index 685f3f7..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/sandbox.py +++ /dev/null @@ -1,491 +0,0 @@ -import os -import sys -import tempfile -import operator -import functools -import itertools -import re -import contextlib -import pickle -import textwrap - -from setuptools.extern import six -from setuptools.extern.six.moves import builtins, map - -import pkg_resources.py31compat - -if sys.platform.startswith('java'): - import org.python.modules.posix.PosixModule as _os -else: - _os = sys.modules[os.name] -try: - _file = file -except NameError: - _file = None -_open = open -from distutils.errors import DistutilsError -from pkg_resources import working_set - - -__all__ = [ - "AbstractSandbox", "DirectorySandbox", "SandboxViolation", "run_setup", -] - - -def _execfile(filename, globals, locals=None): - """ - Python 3 implementation of execfile. - """ - mode = 'rb' - with open(filename, mode) as stream: - script = stream.read() - if locals is None: - locals = globals - code = compile(script, filename, 'exec') - exec(code, globals, locals) - - -@contextlib.contextmanager -def save_argv(repl=None): - saved = sys.argv[:] - if repl is not None: - sys.argv[:] = repl - try: - yield saved - finally: - sys.argv[:] = saved - - -@contextlib.contextmanager -def save_path(): - saved = sys.path[:] - try: - yield saved - finally: - sys.path[:] = saved - - -@contextlib.contextmanager -def override_temp(replacement): - """ - Monkey-patch tempfile.tempdir with replacement, ensuring it exists - """ - pkg_resources.py31compat.makedirs(replacement, exist_ok=True) - - saved = tempfile.tempdir - - tempfile.tempdir = replacement - - try: - yield - finally: - tempfile.tempdir = saved - - -@contextlib.contextmanager -def pushd(target): - saved = os.getcwd() - os.chdir(target) - try: - yield saved - finally: - os.chdir(saved) - - -class UnpickleableException(Exception): - """ - An exception representing another Exception that could not be pickled. - """ - - @staticmethod - def dump(type, exc): - """ - Always return a dumped (pickled) type and exc. If exc can't be pickled, - wrap it in UnpickleableException first. - """ - try: - return pickle.dumps(type), pickle.dumps(exc) - except Exception: - # get UnpickleableException inside the sandbox - from setuptools.sandbox import UnpickleableException as cls - return cls.dump(cls, cls(repr(exc))) - - -class ExceptionSaver: - """ - A Context Manager that will save an exception, serialized, and restore it - later. - """ - - def __enter__(self): - return self - - def __exit__(self, type, exc, tb): - if not exc: - return - - # dump the exception - self._saved = UnpickleableException.dump(type, exc) - self._tb = tb - - # suppress the exception - return True - - def resume(self): - "restore and re-raise any exception" - - if '_saved' not in vars(self): - return - - type, exc = map(pickle.loads, self._saved) - six.reraise(type, exc, self._tb) - - -@contextlib.contextmanager -def save_modules(): - """ - Context in which imported modules are saved. - - Translates exceptions internal to the context into the equivalent exception - outside the context. - """ - saved = sys.modules.copy() - with ExceptionSaver() as saved_exc: - yield saved - - sys.modules.update(saved) - # remove any modules imported since - del_modules = ( - mod_name for mod_name in sys.modules - if mod_name not in saved - # exclude any encodings modules. See #285 - and not mod_name.startswith('encodings.') - ) - _clear_modules(del_modules) - - saved_exc.resume() - - -def _clear_modules(module_names): - for mod_name in list(module_names): - del sys.modules[mod_name] - - -@contextlib.contextmanager -def save_pkg_resources_state(): - saved = pkg_resources.__getstate__() - try: - yield saved - finally: - pkg_resources.__setstate__(saved) - - -@contextlib.contextmanager -def setup_context(setup_dir): - temp_dir = os.path.join(setup_dir, 'temp') - with save_pkg_resources_state(): - with save_modules(): - hide_setuptools() - with save_path(): - with save_argv(): - with override_temp(temp_dir): - with pushd(setup_dir): - # ensure setuptools commands are available - __import__('setuptools') - yield - - -def _needs_hiding(mod_name): - """ - >>> _needs_hiding('setuptools') - True - >>> _needs_hiding('pkg_resources') - True - >>> _needs_hiding('setuptools_plugin') - False - >>> _needs_hiding('setuptools.__init__') - True - >>> _needs_hiding('distutils') - True - >>> _needs_hiding('os') - False - >>> _needs_hiding('Cython') - True - """ - pattern = re.compile(r'(setuptools|pkg_resources|distutils|Cython)(\.|$)') - return bool(pattern.match(mod_name)) - - -def hide_setuptools(): - """ - Remove references to setuptools' modules from sys.modules to allow the - invocation to import the most appropriate setuptools. This technique is - necessary to avoid issues such as #315 where setuptools upgrading itself - would fail to find a function declared in the metadata. - """ - modules = filter(_needs_hiding, sys.modules) - _clear_modules(modules) - - -def run_setup(setup_script, args): - """Run a distutils setup script, sandboxed in its directory""" - setup_dir = os.path.abspath(os.path.dirname(setup_script)) - with setup_context(setup_dir): - try: - sys.argv[:] = [setup_script] + list(args) - sys.path.insert(0, setup_dir) - # reset to include setup dir, w/clean callback list - working_set.__init__() - working_set.callbacks.append(lambda dist: dist.activate()) - - # __file__ should be a byte string on Python 2 (#712) - dunder_file = ( - setup_script - if isinstance(setup_script, str) else - setup_script.encode(sys.getfilesystemencoding()) - ) - - with DirectorySandbox(setup_dir): - ns = dict(__file__=dunder_file, __name__='__main__') - _execfile(setup_script, ns) - except SystemExit as v: - if v.args and v.args[0]: - raise - # Normal exit, just return - - -class AbstractSandbox: - """Wrap 'os' module and 'open()' builtin for virtualizing setup scripts""" - - _active = False - - def __init__(self): - self._attrs = [ - name for name in dir(_os) - if not name.startswith('_') and hasattr(self, name) - ] - - def _copy(self, source): - for name in self._attrs: - setattr(os, name, getattr(source, name)) - - def __enter__(self): - self._copy(self) - if _file: - builtins.file = self._file - builtins.open = self._open - self._active = True - - def __exit__(self, exc_type, exc_value, traceback): - self._active = False - if _file: - builtins.file = _file - builtins.open = _open - self._copy(_os) - - def run(self, func): - """Run 'func' under os sandboxing""" - with self: - return func() - - def _mk_dual_path_wrapper(name): - original = getattr(_os, name) - - def wrap(self, src, dst, *args, **kw): - if self._active: - src, dst = self._remap_pair(name, src, dst, *args, **kw) - return original(src, dst, *args, **kw) - - return wrap - - for name in ["rename", "link", "symlink"]: - if hasattr(_os, name): - locals()[name] = _mk_dual_path_wrapper(name) - - def _mk_single_path_wrapper(name, original=None): - original = original or getattr(_os, name) - - def wrap(self, path, *args, **kw): - if self._active: - path = self._remap_input(name, path, *args, **kw) - return original(path, *args, **kw) - - return wrap - - if _file: - _file = _mk_single_path_wrapper('file', _file) - _open = _mk_single_path_wrapper('open', _open) - for name in [ - "stat", "listdir", "chdir", "open", "chmod", "chown", "mkdir", - "remove", "unlink", "rmdir", "utime", "lchown", "chroot", "lstat", - "startfile", "mkfifo", "mknod", "pathconf", "access" - ]: - if hasattr(_os, name): - locals()[name] = _mk_single_path_wrapper(name) - - def _mk_single_with_return(name): - original = getattr(_os, name) - - def wrap(self, path, *args, **kw): - if self._active: - path = self._remap_input(name, path, *args, **kw) - return self._remap_output(name, original(path, *args, **kw)) - return original(path, *args, **kw) - - return wrap - - for name in ['readlink', 'tempnam']: - if hasattr(_os, name): - locals()[name] = _mk_single_with_return(name) - - def _mk_query(name): - original = getattr(_os, name) - - def wrap(self, *args, **kw): - retval = original(*args, **kw) - if self._active: - return self._remap_output(name, retval) - return retval - - return wrap - - for name in ['getcwd', 'tmpnam']: - if hasattr(_os, name): - locals()[name] = _mk_query(name) - - def _validate_path(self, path): - """Called to remap or validate any path, whether input or output""" - return path - - def _remap_input(self, operation, path, *args, **kw): - """Called for path inputs""" - return self._validate_path(path) - - def _remap_output(self, operation, path): - """Called for path outputs""" - return self._validate_path(path) - - def _remap_pair(self, operation, src, dst, *args, **kw): - """Called for path pairs like rename, link, and symlink operations""" - return ( - self._remap_input(operation + '-from', src, *args, **kw), - self._remap_input(operation + '-to', dst, *args, **kw) - ) - - -if hasattr(os, 'devnull'): - _EXCEPTIONS = [os.devnull,] -else: - _EXCEPTIONS = [] - - -class DirectorySandbox(AbstractSandbox): - """Restrict operations to a single subdirectory - pseudo-chroot""" - - write_ops = dict.fromkeys([ - "open", "chmod", "chown", "mkdir", "remove", "unlink", "rmdir", - "utime", "lchown", "chroot", "mkfifo", "mknod", "tempnam", - ]) - - _exception_patterns = [ - # Allow lib2to3 to attempt to save a pickled grammar object (#121) - r'.*lib2to3.*\.pickle$', - ] - "exempt writing to paths that match the pattern" - - def __init__(self, sandbox, exceptions=_EXCEPTIONS): - self._sandbox = os.path.normcase(os.path.realpath(sandbox)) - self._prefix = os.path.join(self._sandbox, '') - self._exceptions = [ - os.path.normcase(os.path.realpath(path)) - for path in exceptions - ] - AbstractSandbox.__init__(self) - - def _violation(self, operation, *args, **kw): - from setuptools.sandbox import SandboxViolation - raise SandboxViolation(operation, args, kw) - - if _file: - - def _file(self, path, mode='r', *args, **kw): - if mode not in ('r', 'rt', 'rb', 'rU', 'U') and not self._ok(path): - self._violation("file", path, mode, *args, **kw) - return _file(path, mode, *args, **kw) - - def _open(self, path, mode='r', *args, **kw): - if mode not in ('r', 'rt', 'rb', 'rU', 'U') and not self._ok(path): - self._violation("open", path, mode, *args, **kw) - return _open(path, mode, *args, **kw) - - def tmpnam(self): - self._violation("tmpnam") - - def _ok(self, path): - active = self._active - try: - self._active = False - realpath = os.path.normcase(os.path.realpath(path)) - return ( - self._exempted(realpath) - or realpath == self._sandbox - or realpath.startswith(self._prefix) - ) - finally: - self._active = active - - def _exempted(self, filepath): - start_matches = ( - filepath.startswith(exception) - for exception in self._exceptions - ) - pattern_matches = ( - re.match(pattern, filepath) - for pattern in self._exception_patterns - ) - candidates = itertools.chain(start_matches, pattern_matches) - return any(candidates) - - def _remap_input(self, operation, path, *args, **kw): - """Called for path inputs""" - if operation in self.write_ops and not self._ok(path): - self._violation(operation, os.path.realpath(path), *args, **kw) - return path - - def _remap_pair(self, operation, src, dst, *args, **kw): - """Called for path pairs like rename, link, and symlink operations""" - if not self._ok(src) or not self._ok(dst): - self._violation(operation, src, dst, *args, **kw) - return (src, dst) - - def open(self, file, flags, mode=0o777, *args, **kw): - """Called for low-level os.open()""" - if flags & WRITE_FLAGS and not self._ok(file): - self._violation("os.open", file, flags, mode, *args, **kw) - return _os.open(file, flags, mode, *args, **kw) - - -WRITE_FLAGS = functools.reduce( - operator.or_, [getattr(_os, a, 0) for a in - "O_WRONLY O_RDWR O_APPEND O_CREAT O_TRUNC O_TEMPORARY".split()] -) - - -class SandboxViolation(DistutilsError): - """A setup script attempted to modify the filesystem outside the sandbox""" - - tmpl = textwrap.dedent(""" - SandboxViolation: {cmd}{args!r} {kwargs} - - The package setup script has attempted to modify files on your system - that are not within the EasyInstall build area, and has been aborted. - - This package cannot be safely installed by EasyInstall, and may not - support alternate installation locations even if you run its setup - script by hand. Please inform the package's author and the EasyInstall - maintainers to find out if a fix or workaround is available. - """).lstrip() - - def __str__(self): - cmd, args, kwargs = self.args - return self.tmpl.format(**locals()) diff --git a/venv/lib/python3.8/site-packages/setuptools/script (dev).tmpl b/venv/lib/python3.8/site-packages/setuptools/script (dev).tmpl deleted file mode 100644 index 39a24b0..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/script (dev).tmpl +++ /dev/null @@ -1,6 +0,0 @@ -# EASY-INSTALL-DEV-SCRIPT: %(spec)r,%(script_name)r -__requires__ = %(spec)r -__import__('pkg_resources').require(%(spec)r) -__file__ = %(dev_path)r -with open(__file__) as f: - exec(compile(f.read(), __file__, 'exec')) diff --git a/venv/lib/python3.8/site-packages/setuptools/script.tmpl b/venv/lib/python3.8/site-packages/setuptools/script.tmpl deleted file mode 100644 index ff5efbc..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/script.tmpl +++ /dev/null @@ -1,3 +0,0 @@ -# EASY-INSTALL-SCRIPT: %(spec)r,%(script_name)r -__requires__ = %(spec)r -__import__('pkg_resources').run_script(%(spec)r, %(script_name)r) diff --git a/venv/lib/python3.8/site-packages/setuptools/site-patch.py b/venv/lib/python3.8/site-packages/setuptools/site-patch.py deleted file mode 100644 index 40b00de..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/site-patch.py +++ /dev/null @@ -1,74 +0,0 @@ -def __boot(): - import sys - import os - PYTHONPATH = os.environ.get('PYTHONPATH') - if PYTHONPATH is None or (sys.platform == 'win32' and not PYTHONPATH): - PYTHONPATH = [] - else: - PYTHONPATH = PYTHONPATH.split(os.pathsep) - - pic = getattr(sys, 'path_importer_cache', {}) - stdpath = sys.path[len(PYTHONPATH):] - mydir = os.path.dirname(__file__) - - for item in stdpath: - if item == mydir or not item: - continue # skip if current dir. on Windows, or my own directory - importer = pic.get(item) - if importer is not None: - loader = importer.find_module('site') - if loader is not None: - # This should actually reload the current module - loader.load_module('site') - break - else: - try: - import imp # Avoid import loop in Python 3 - stream, path, descr = imp.find_module('site', [item]) - except ImportError: - continue - if stream is None: - continue - try: - # This should actually reload the current module - imp.load_module('site', stream, path, descr) - finally: - stream.close() - break - else: - raise ImportError("Couldn't find the real 'site' module") - - known_paths = dict([(makepath(item)[1], 1) for item in sys.path]) # 2.2 comp - - oldpos = getattr(sys, '__egginsert', 0) # save old insertion position - sys.__egginsert = 0 # and reset the current one - - for item in PYTHONPATH: - addsitedir(item) - - sys.__egginsert += oldpos # restore effective old position - - d, nd = makepath(stdpath[0]) - insert_at = None - new_path = [] - - for item in sys.path: - p, np = makepath(item) - - if np == nd and insert_at is None: - # We've hit the first 'system' path entry, so added entries go here - insert_at = len(new_path) - - if np in known_paths or insert_at is None: - new_path.append(item) - else: - # new path after the insert point, back-insert it - new_path.insert(insert_at, item) - insert_at += 1 - - sys.path[:] = new_path - - -if __name__ == 'site': - __boot() - del __boot diff --git a/venv/lib/python3.8/site-packages/setuptools/ssl_support.py b/venv/lib/python3.8/site-packages/setuptools/ssl_support.py deleted file mode 100644 index 226db69..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/ssl_support.py +++ /dev/null @@ -1,260 +0,0 @@ -import os -import socket -import atexit -import re -import functools - -from setuptools.extern.six.moves import urllib, http_client, map, filter - -from pkg_resources import ResolutionError, ExtractionError - -try: - import ssl -except ImportError: - ssl = None - -__all__ = [ - 'VerifyingHTTPSHandler', 'find_ca_bundle', 'is_available', 'cert_paths', - 'opener_for' -] - -cert_paths = """ -/etc/pki/tls/certs/ca-bundle.crt -/etc/ssl/certs/ca-certificates.crt -/usr/share/ssl/certs/ca-bundle.crt -/usr/local/share/certs/ca-root.crt -/etc/ssl/cert.pem -/System/Library/OpenSSL/certs/cert.pem -/usr/local/share/certs/ca-root-nss.crt -/etc/ssl/ca-bundle.pem -""".strip().split() - -try: - HTTPSHandler = urllib.request.HTTPSHandler - HTTPSConnection = http_client.HTTPSConnection -except AttributeError: - HTTPSHandler = HTTPSConnection = object - -is_available = ssl is not None and object not in (HTTPSHandler, HTTPSConnection) - - -try: - from ssl import CertificateError, match_hostname -except ImportError: - try: - from backports.ssl_match_hostname import CertificateError - from backports.ssl_match_hostname import match_hostname - except ImportError: - CertificateError = None - match_hostname = None - -if not CertificateError: - - class CertificateError(ValueError): - pass - - -if not match_hostname: - - def _dnsname_match(dn, hostname, max_wildcards=1): - """Matching according to RFC 6125, section 6.4.3 - - https://tools.ietf.org/html/rfc6125#section-6.4.3 - """ - pats = [] - if not dn: - return False - - # Ported from python3-syntax: - # leftmost, *remainder = dn.split(r'.') - parts = dn.split(r'.') - leftmost = parts[0] - remainder = parts[1:] - - wildcards = leftmost.count('*') - if wildcards > max_wildcards: - # Issue #17980: avoid denials of service by refusing more - # than one wildcard per fragment. A survey of established - # policy among SSL implementations showed it to be a - # reasonable choice. - raise CertificateError( - "too many wildcards in certificate DNS name: " + repr(dn)) - - # speed up common case w/o wildcards - if not wildcards: - return dn.lower() == hostname.lower() - - # RFC 6125, section 6.4.3, subitem 1. - # The client SHOULD NOT attempt to match a presented identifier in which - # the wildcard character comprises a label other than the left-most label. - if leftmost == '*': - # When '*' is a fragment by itself, it matches a non-empty dotless - # fragment. - pats.append('[^.]+') - elif leftmost.startswith('xn--') or hostname.startswith('xn--'): - # RFC 6125, section 6.4.3, subitem 3. - # The client SHOULD NOT attempt to match a presented identifier - # where the wildcard character is embedded within an A-label or - # U-label of an internationalized domain name. - pats.append(re.escape(leftmost)) - else: - # Otherwise, '*' matches any dotless string, e.g. www* - pats.append(re.escape(leftmost).replace(r'\*', '[^.]*')) - - # add the remaining fragments, ignore any wildcards - for frag in remainder: - pats.append(re.escape(frag)) - - pat = re.compile(r'\A' + r'\.'.join(pats) + r'\Z', re.IGNORECASE) - return pat.match(hostname) - - def match_hostname(cert, hostname): - """Verify that *cert* (in decoded format as returned by - SSLSocket.getpeercert()) matches the *hostname*. RFC 2818 and RFC 6125 - rules are followed, but IP addresses are not accepted for *hostname*. - - CertificateError is raised on failure. On success, the function - returns nothing. - """ - if not cert: - raise ValueError("empty or no certificate") - dnsnames = [] - san = cert.get('subjectAltName', ()) - for key, value in san: - if key == 'DNS': - if _dnsname_match(value, hostname): - return - dnsnames.append(value) - if not dnsnames: - # The subject is only checked when there is no dNSName entry - # in subjectAltName - for sub in cert.get('subject', ()): - for key, value in sub: - # XXX according to RFC 2818, the most specific Common Name - # must be used. - if key == 'commonName': - if _dnsname_match(value, hostname): - return - dnsnames.append(value) - if len(dnsnames) > 1: - raise CertificateError("hostname %r " - "doesn't match either of %s" - % (hostname, ', '.join(map(repr, dnsnames)))) - elif len(dnsnames) == 1: - raise CertificateError("hostname %r " - "doesn't match %r" - % (hostname, dnsnames[0])) - else: - raise CertificateError("no appropriate commonName or " - "subjectAltName fields were found") - - -class VerifyingHTTPSHandler(HTTPSHandler): - """Simple verifying handler: no auth, subclasses, timeouts, etc.""" - - def __init__(self, ca_bundle): - self.ca_bundle = ca_bundle - HTTPSHandler.__init__(self) - - def https_open(self, req): - return self.do_open( - lambda host, **kw: VerifyingHTTPSConn(host, self.ca_bundle, **kw), req - ) - - -class VerifyingHTTPSConn(HTTPSConnection): - """Simple verifying connection: no auth, subclasses, timeouts, etc.""" - - def __init__(self, host, ca_bundle, **kw): - HTTPSConnection.__init__(self, host, **kw) - self.ca_bundle = ca_bundle - - def connect(self): - sock = socket.create_connection( - (self.host, self.port), getattr(self, 'source_address', None) - ) - - # Handle the socket if a (proxy) tunnel is present - if hasattr(self, '_tunnel') and getattr(self, '_tunnel_host', None): - self.sock = sock - self._tunnel() - # http://bugs.python.org/issue7776: Python>=3.4.1 and >=2.7.7 - # change self.host to mean the proxy server host when tunneling is - # being used. Adapt, since we are interested in the destination - # host for the match_hostname() comparison. - actual_host = self._tunnel_host - else: - actual_host = self.host - - if hasattr(ssl, 'create_default_context'): - ctx = ssl.create_default_context(cafile=self.ca_bundle) - self.sock = ctx.wrap_socket(sock, server_hostname=actual_host) - else: - # This is for python < 2.7.9 and < 3.4? - self.sock = ssl.wrap_socket( - sock, cert_reqs=ssl.CERT_REQUIRED, ca_certs=self.ca_bundle - ) - try: - match_hostname(self.sock.getpeercert(), actual_host) - except CertificateError: - self.sock.shutdown(socket.SHUT_RDWR) - self.sock.close() - raise - - -def opener_for(ca_bundle=None): - """Get a urlopen() replacement that uses ca_bundle for verification""" - return urllib.request.build_opener( - VerifyingHTTPSHandler(ca_bundle or find_ca_bundle()) - ).open - - -# from jaraco.functools -def once(func): - @functools.wraps(func) - def wrapper(*args, **kwargs): - if not hasattr(func, 'always_returns'): - func.always_returns = func(*args, **kwargs) - return func.always_returns - return wrapper - - -@once -def get_win_certfile(): - try: - import wincertstore - except ImportError: - return None - - class CertFile(wincertstore.CertFile): - def __init__(self): - super(CertFile, self).__init__() - atexit.register(self.close) - - def close(self): - try: - super(CertFile, self).close() - except OSError: - pass - - _wincerts = CertFile() - _wincerts.addstore('CA') - _wincerts.addstore('ROOT') - return _wincerts.name - - -def find_ca_bundle(): - """Return an existing CA bundle path, or None""" - extant_cert_paths = filter(os.path.isfile, cert_paths) - return ( - get_win_certfile() - or next(extant_cert_paths, None) - or _certifi_where() - ) - - -def _certifi_where(): - try: - return __import__('certifi').where() - except (ImportError, ResolutionError, ExtractionError): - pass diff --git a/venv/lib/python3.8/site-packages/setuptools/unicode_utils.py b/venv/lib/python3.8/site-packages/setuptools/unicode_utils.py deleted file mode 100644 index 7c63efd..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/unicode_utils.py +++ /dev/null @@ -1,44 +0,0 @@ -import unicodedata -import sys - -from setuptools.extern import six - - -# HFS Plus uses decomposed UTF-8 -def decompose(path): - if isinstance(path, six.text_type): - return unicodedata.normalize('NFD', path) - try: - path = path.decode('utf-8') - path = unicodedata.normalize('NFD', path) - path = path.encode('utf-8') - except UnicodeError: - pass # Not UTF-8 - return path - - -def filesys_decode(path): - """ - Ensure that the given path is decoded, - NONE when no expected encoding works - """ - - if isinstance(path, six.text_type): - return path - - fs_enc = sys.getfilesystemencoding() or 'utf-8' - candidates = fs_enc, 'utf-8' - - for enc in candidates: - try: - return path.decode(enc) - except UnicodeDecodeError: - continue - - -def try_encode(string, enc): - "turn unicode encoding into a functional routine" - try: - return string.encode(enc) - except UnicodeEncodeError: - return None diff --git a/venv/lib/python3.8/site-packages/setuptools/version.py b/venv/lib/python3.8/site-packages/setuptools/version.py deleted file mode 100644 index 95e1869..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/version.py +++ /dev/null @@ -1,6 +0,0 @@ -import pkg_resources - -try: - __version__ = pkg_resources.get_distribution('setuptools').version -except Exception: - __version__ = 'unknown' diff --git a/venv/lib/python3.8/site-packages/setuptools/wheel.py b/venv/lib/python3.8/site-packages/setuptools/wheel.py deleted file mode 100644 index 025aaa8..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/wheel.py +++ /dev/null @@ -1,220 +0,0 @@ -"""Wheels support.""" - -from distutils.util import get_platform -from distutils import log -import email -import itertools -import os -import posixpath -import re -import zipfile - -import pkg_resources -import setuptools -from pkg_resources import parse_version -from setuptools.extern.packaging.tags import sys_tags -from setuptools.extern.packaging.utils import canonicalize_name -from setuptools.extern.six import PY3 -from setuptools.command.egg_info import write_requirements - - -__metaclass__ = type - - -WHEEL_NAME = re.compile( - r"""^(?P<project_name>.+?)-(?P<version>\d.*?) - ((-(?P<build>\d.*?))?-(?P<py_version>.+?)-(?P<abi>.+?)-(?P<platform>.+?) - )\.whl$""", - re.VERBOSE).match - -NAMESPACE_PACKAGE_INIT = '''\ -try: - __import__('pkg_resources').declare_namespace(__name__) -except ImportError: - __path__ = __import__('pkgutil').extend_path(__path__, __name__) -''' - - -def unpack(src_dir, dst_dir): - '''Move everything under `src_dir` to `dst_dir`, and delete the former.''' - for dirpath, dirnames, filenames in os.walk(src_dir): - subdir = os.path.relpath(dirpath, src_dir) - for f in filenames: - src = os.path.join(dirpath, f) - dst = os.path.join(dst_dir, subdir, f) - os.renames(src, dst) - for n, d in reversed(list(enumerate(dirnames))): - src = os.path.join(dirpath, d) - dst = os.path.join(dst_dir, subdir, d) - if not os.path.exists(dst): - # Directory does not exist in destination, - # rename it and prune it from os.walk list. - os.renames(src, dst) - del dirnames[n] - # Cleanup. - for dirpath, dirnames, filenames in os.walk(src_dir, topdown=True): - assert not filenames - os.rmdir(dirpath) - - -class Wheel: - - def __init__(self, filename): - match = WHEEL_NAME(os.path.basename(filename)) - if match is None: - raise ValueError('invalid wheel name: %r' % filename) - self.filename = filename - for k, v in match.groupdict().items(): - setattr(self, k, v) - - def tags(self): - '''List tags (py_version, abi, platform) supported by this wheel.''' - return itertools.product( - self.py_version.split('.'), - self.abi.split('.'), - self.platform.split('.'), - ) - - def is_compatible(self): - '''Is the wheel is compatible with the current platform?''' - supported_tags = set((t.interpreter, t.abi, t.platform) for t in sys_tags()) - return next((True for t in self.tags() if t in supported_tags), False) - - def egg_name(self): - return pkg_resources.Distribution( - project_name=self.project_name, version=self.version, - platform=(None if self.platform == 'any' else get_platform()), - ).egg_name() + '.egg' - - def get_dist_info(self, zf): - # find the correct name of the .dist-info dir in the wheel file - for member in zf.namelist(): - dirname = posixpath.dirname(member) - if (dirname.endswith('.dist-info') and - canonicalize_name(dirname).startswith( - canonicalize_name(self.project_name))): - return dirname - raise ValueError("unsupported wheel format. .dist-info not found") - - def install_as_egg(self, destination_eggdir): - '''Install wheel as an egg directory.''' - with zipfile.ZipFile(self.filename) as zf: - self._install_as_egg(destination_eggdir, zf) - - def _install_as_egg(self, destination_eggdir, zf): - dist_basename = '%s-%s' % (self.project_name, self.version) - dist_info = self.get_dist_info(zf) - dist_data = '%s.data' % dist_basename - egg_info = os.path.join(destination_eggdir, 'EGG-INFO') - - self._convert_metadata(zf, destination_eggdir, dist_info, egg_info) - self._move_data_entries(destination_eggdir, dist_data) - self._fix_namespace_packages(egg_info, destination_eggdir) - - @staticmethod - def _convert_metadata(zf, destination_eggdir, dist_info, egg_info): - def get_metadata(name): - with zf.open(posixpath.join(dist_info, name)) as fp: - value = fp.read().decode('utf-8') if PY3 else fp.read() - return email.parser.Parser().parsestr(value) - - wheel_metadata = get_metadata('WHEEL') - # Check wheel format version is supported. - wheel_version = parse_version(wheel_metadata.get('Wheel-Version')) - wheel_v1 = ( - parse_version('1.0') <= wheel_version < parse_version('2.0dev0') - ) - if not wheel_v1: - raise ValueError( - 'unsupported wheel format version: %s' % wheel_version) - # Extract to target directory. - os.mkdir(destination_eggdir) - zf.extractall(destination_eggdir) - # Convert metadata. - dist_info = os.path.join(destination_eggdir, dist_info) - dist = pkg_resources.Distribution.from_location( - destination_eggdir, dist_info, - metadata=pkg_resources.PathMetadata(destination_eggdir, dist_info), - ) - - # Note: Evaluate and strip markers now, - # as it's difficult to convert back from the syntax: - # foobar; "linux" in sys_platform and extra == 'test' - def raw_req(req): - req.marker = None - return str(req) - install_requires = list(sorted(map(raw_req, dist.requires()))) - extras_require = { - extra: sorted( - req - for req in map(raw_req, dist.requires((extra,))) - if req not in install_requires - ) - for extra in dist.extras - } - os.rename(dist_info, egg_info) - os.rename( - os.path.join(egg_info, 'METADATA'), - os.path.join(egg_info, 'PKG-INFO'), - ) - setup_dist = setuptools.Distribution( - attrs=dict( - install_requires=install_requires, - extras_require=extras_require, - ), - ) - # Temporarily disable info traces. - log_threshold = log._global_log.threshold - log.set_threshold(log.WARN) - try: - write_requirements( - setup_dist.get_command_obj('egg_info'), - None, - os.path.join(egg_info, 'requires.txt'), - ) - finally: - log.set_threshold(log_threshold) - - @staticmethod - def _move_data_entries(destination_eggdir, dist_data): - """Move data entries to their correct location.""" - dist_data = os.path.join(destination_eggdir, dist_data) - dist_data_scripts = os.path.join(dist_data, 'scripts') - if os.path.exists(dist_data_scripts): - egg_info_scripts = os.path.join( - destination_eggdir, 'EGG-INFO', 'scripts') - os.mkdir(egg_info_scripts) - for entry in os.listdir(dist_data_scripts): - # Remove bytecode, as it's not properly handled - # during easy_install scripts install phase. - if entry.endswith('.pyc'): - os.unlink(os.path.join(dist_data_scripts, entry)) - else: - os.rename( - os.path.join(dist_data_scripts, entry), - os.path.join(egg_info_scripts, entry), - ) - os.rmdir(dist_data_scripts) - for subdir in filter(os.path.exists, ( - os.path.join(dist_data, d) - for d in ('data', 'headers', 'purelib', 'platlib') - )): - unpack(subdir, destination_eggdir) - if os.path.exists(dist_data): - os.rmdir(dist_data) - - @staticmethod - def _fix_namespace_packages(egg_info, destination_eggdir): - namespace_packages = os.path.join( - egg_info, 'namespace_packages.txt') - if os.path.exists(namespace_packages): - with open(namespace_packages) as fp: - namespace_packages = fp.read().split() - for mod in namespace_packages: - mod_dir = os.path.join(destination_eggdir, *mod.split('.')) - mod_init = os.path.join(mod_dir, '__init__.py') - if not os.path.exists(mod_dir): - os.mkdir(mod_dir) - if not os.path.exists(mod_init): - with open(mod_init, 'w') as fp: - fp.write(NAMESPACE_PACKAGE_INIT) diff --git a/venv/lib/python3.8/site-packages/setuptools/windows_support.py b/venv/lib/python3.8/site-packages/setuptools/windows_support.py deleted file mode 100644 index cb977cf..0000000 --- a/venv/lib/python3.8/site-packages/setuptools/windows_support.py +++ /dev/null @@ -1,29 +0,0 @@ -import platform -import ctypes - - -def windows_only(func): - if platform.system() != 'Windows': - return lambda *args, **kwargs: None - return func - - -@windows_only -def hide_file(path): - """ - Set the hidden attribute on a file or directory. - - From http://stackoverflow.com/questions/19622133/ - - `path` must be text. - """ - __import__('ctypes.wintypes') - SetFileAttributes = ctypes.windll.kernel32.SetFileAttributesW - SetFileAttributes.argtypes = ctypes.wintypes.LPWSTR, ctypes.wintypes.DWORD - SetFileAttributes.restype = ctypes.wintypes.BOOL - - FILE_ATTRIBUTE_HIDDEN = 0x02 - - ret = SetFileAttributes(path, FILE_ATTRIBUTE_HIDDEN) - if not ret: - raise ctypes.WinError() diff --git a/venv/lib/python3.8/site-packages/six-1.16.0.dist-info/INSTALLER b/venv/lib/python3.8/site-packages/six-1.16.0.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.8/site-packages/six-1.16.0.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.8/site-packages/six-1.16.0.dist-info/LICENSE b/venv/lib/python3.8/site-packages/six-1.16.0.dist-info/LICENSE deleted file mode 100644 index de66331..0000000 --- a/venv/lib/python3.8/site-packages/six-1.16.0.dist-info/LICENSE +++ /dev/null @@ -1,18 +0,0 @@ -Copyright (c) 2010-2020 Benjamin Peterson - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/venv/lib/python3.8/site-packages/six-1.16.0.dist-info/METADATA b/venv/lib/python3.8/site-packages/six-1.16.0.dist-info/METADATA deleted file mode 100644 index 6d7525c..0000000 --- a/venv/lib/python3.8/site-packages/six-1.16.0.dist-info/METADATA +++ /dev/null @@ -1,49 +0,0 @@ -Metadata-Version: 2.1 -Name: six -Version: 1.16.0 -Summary: Python 2 and 3 compatibility utilities -Home-page: https://github.com/benjaminp/six -Author: Benjamin Peterson -Author-email: benjamin@python.org -License: MIT -Platform: UNKNOWN -Classifier: Development Status :: 5 - Production/Stable -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 3 -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: MIT License -Classifier: Topic :: Software Development :: Libraries -Classifier: Topic :: Utilities -Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.* - -.. image:: https://img.shields.io/pypi/v/six.svg - :target: https://pypi.org/project/six/ - :alt: six on PyPI - -.. image:: https://travis-ci.org/benjaminp/six.svg?branch=master - :target: https://travis-ci.org/benjaminp/six - :alt: six on TravisCI - -.. image:: https://readthedocs.org/projects/six/badge/?version=latest - :target: https://six.readthedocs.io/ - :alt: six's documentation on Read the Docs - -.. image:: https://img.shields.io/badge/license-MIT-green.svg - :target: https://github.com/benjaminp/six/blob/master/LICENSE - :alt: MIT License badge - -Six is a Python 2 and 3 compatibility library. It provides utility functions -for smoothing over the differences between the Python versions with the goal of -writing Python code that is compatible on both Python versions. See the -documentation for more information on what is provided. - -Six supports Python 2.7 and 3.3+. It is contained in only one Python -file, so it can be easily copied into your project. (The copyright and license -notice must be retained.) - -Online documentation is at https://six.readthedocs.io/. - -Bugs can be reported to https://github.com/benjaminp/six. The code can also -be found there. - - diff --git a/venv/lib/python3.8/site-packages/six-1.16.0.dist-info/RECORD b/venv/lib/python3.8/site-packages/six-1.16.0.dist-info/RECORD deleted file mode 100644 index 4de46ba..0000000 --- a/venv/lib/python3.8/site-packages/six-1.16.0.dist-info/RECORD +++ /dev/null @@ -1,8 +0,0 @@ -__pycache__/six.cpython-38.pyc,, -six-1.16.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -six-1.16.0.dist-info/LICENSE,sha256=i7hQxWWqOJ_cFvOkaWWtI9gq3_YPI5P8J2K2MYXo5sk,1066 -six-1.16.0.dist-info/METADATA,sha256=VQcGIFCAEmfZcl77E5riPCN4v2TIsc_qtacnjxKHJoI,1795 -six-1.16.0.dist-info/RECORD,, -six-1.16.0.dist-info/WHEEL,sha256=Z-nyYpwrcSqxfdux5Mbn_DQ525iP7J2DG3JgGvOYyTQ,110 -six-1.16.0.dist-info/top_level.txt,sha256=_iVH_iYEtEXnD8nYGQYpYFUvkUW9sEO1GYbkeKSAais,4 -six.py,sha256=TOOfQi7nFGfMrIvtdr6wX4wyHH8M7aknmuLfo2cBBrM,34549 diff --git a/venv/lib/python3.8/site-packages/six-1.16.0.dist-info/WHEEL b/venv/lib/python3.8/site-packages/six-1.16.0.dist-info/WHEEL deleted file mode 100644 index 01b8fc7..0000000 --- a/venv/lib/python3.8/site-packages/six-1.16.0.dist-info/WHEEL +++ /dev/null @@ -1,6 +0,0 @@ -Wheel-Version: 1.0 -Generator: bdist_wheel (0.36.2) -Root-Is-Purelib: true -Tag: py2-none-any -Tag: py3-none-any - diff --git a/venv/lib/python3.8/site-packages/six-1.16.0.dist-info/top_level.txt b/venv/lib/python3.8/site-packages/six-1.16.0.dist-info/top_level.txt deleted file mode 100644 index ffe2fce..0000000 --- a/venv/lib/python3.8/site-packages/six-1.16.0.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -six diff --git a/venv/lib/python3.8/site-packages/six.py b/venv/lib/python3.8/site-packages/six.py deleted file mode 100644 index 4e15675..0000000 --- a/venv/lib/python3.8/site-packages/six.py +++ /dev/null @@ -1,998 +0,0 @@ -# Copyright (c) 2010-2020 Benjamin Peterson -# -# 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. - -"""Utilities for writing code that runs on Python 2 and 3""" - -from __future__ import absolute_import - -import functools -import itertools -import operator -import sys -import types - -__author__ = "Benjamin Peterson <benjamin@python.org>" -__version__ = "1.16.0" - - -# Useful for very coarse version differentiation. -PY2 = sys.version_info[0] == 2 -PY3 = sys.version_info[0] == 3 -PY34 = sys.version_info[0:2] >= (3, 4) - -if PY3: - string_types = str, - integer_types = int, - class_types = type, - text_type = str - binary_type = bytes - - MAXSIZE = sys.maxsize -else: - string_types = basestring, - integer_types = (int, long) - class_types = (type, types.ClassType) - text_type = unicode - binary_type = str - - if sys.platform.startswith("java"): - # Jython always uses 32 bits. - MAXSIZE = int((1 << 31) - 1) - else: - # It's possible to have sizeof(long) != sizeof(Py_ssize_t). - class X(object): - - def __len__(self): - return 1 << 31 - try: - len(X()) - except OverflowError: - # 32-bit - MAXSIZE = int((1 << 31) - 1) - else: - # 64-bit - MAXSIZE = int((1 << 63) - 1) - del X - -if PY34: - from importlib.util import spec_from_loader -else: - spec_from_loader = None - - -def _add_doc(func, doc): - """Add documentation to a function.""" - func.__doc__ = doc - - -def _import_module(name): - """Import module, returning the module after the last dot.""" - __import__(name) - return sys.modules[name] - - -class _LazyDescr(object): - - def __init__(self, name): - self.name = name - - def __get__(self, obj, tp): - result = self._resolve() - setattr(obj, self.name, result) # Invokes __set__. - try: - # This is a bit ugly, but it avoids running this again by - # removing this descriptor. - delattr(obj.__class__, self.name) - except AttributeError: - pass - return result - - -class MovedModule(_LazyDescr): - - def __init__(self, name, old, new=None): - super(MovedModule, self).__init__(name) - if PY3: - if new is None: - new = name - self.mod = new - else: - self.mod = old - - def _resolve(self): - return _import_module(self.mod) - - def __getattr__(self, attr): - _module = self._resolve() - value = getattr(_module, attr) - setattr(self, attr, value) - return value - - -class _LazyModule(types.ModuleType): - - def __init__(self, name): - super(_LazyModule, self).__init__(name) - self.__doc__ = self.__class__.__doc__ - - def __dir__(self): - attrs = ["__doc__", "__name__"] - attrs += [attr.name for attr in self._moved_attributes] - return attrs - - # Subclasses should override this - _moved_attributes = [] - - -class MovedAttribute(_LazyDescr): - - def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None): - super(MovedAttribute, self).__init__(name) - if PY3: - if new_mod is None: - new_mod = name - self.mod = new_mod - if new_attr is None: - if old_attr is None: - new_attr = name - else: - new_attr = old_attr - self.attr = new_attr - else: - self.mod = old_mod - if old_attr is None: - old_attr = name - self.attr = old_attr - - def _resolve(self): - module = _import_module(self.mod) - return getattr(module, self.attr) - - -class _SixMetaPathImporter(object): - - """ - A meta path importer to import six.moves and its submodules. - - This class implements a PEP302 finder and loader. It should be compatible - with Python 2.5 and all existing versions of Python3 - """ - - def __init__(self, six_module_name): - self.name = six_module_name - self.known_modules = {} - - def _add_module(self, mod, *fullnames): - for fullname in fullnames: - self.known_modules[self.name + "." + fullname] = mod - - def _get_module(self, fullname): - return self.known_modules[self.name + "." + fullname] - - def find_module(self, fullname, path=None): - if fullname in self.known_modules: - return self - return None - - def find_spec(self, fullname, path, target=None): - if fullname in self.known_modules: - return spec_from_loader(fullname, self) - return None - - def __get_module(self, fullname): - try: - return self.known_modules[fullname] - except KeyError: - raise ImportError("This loader does not know module " + fullname) - - def load_module(self, fullname): - try: - # in case of a reload - return sys.modules[fullname] - except KeyError: - pass - mod = self.__get_module(fullname) - if isinstance(mod, MovedModule): - mod = mod._resolve() - else: - mod.__loader__ = self - sys.modules[fullname] = mod - return mod - - def is_package(self, fullname): - """ - Return true, if the named module is a package. - - We need this method to get correct spec objects with - Python 3.4 (see PEP451) - """ - return hasattr(self.__get_module(fullname), "__path__") - - def get_code(self, fullname): - """Return None - - Required, if is_package is implemented""" - self.__get_module(fullname) # eventually raises ImportError - return None - get_source = get_code # same as get_code - - def create_module(self, spec): - return self.load_module(spec.name) - - def exec_module(self, module): - pass - -_importer = _SixMetaPathImporter(__name__) - - -class _MovedItems(_LazyModule): - - """Lazy loading of moved objects""" - __path__ = [] # mark as package - - -_moved_attributes = [ - MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"), - MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"), - MovedAttribute("filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"), - MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"), - MovedAttribute("intern", "__builtin__", "sys"), - MovedAttribute("map", "itertools", "builtins", "imap", "map"), - MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"), - MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"), - MovedAttribute("getoutput", "commands", "subprocess"), - MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"), - MovedAttribute("reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload"), - MovedAttribute("reduce", "__builtin__", "functools"), - MovedAttribute("shlex_quote", "pipes", "shlex", "quote"), - MovedAttribute("StringIO", "StringIO", "io"), - MovedAttribute("UserDict", "UserDict", "collections"), - MovedAttribute("UserList", "UserList", "collections"), - MovedAttribute("UserString", "UserString", "collections"), - MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"), - MovedAttribute("zip", "itertools", "builtins", "izip", "zip"), - MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"), - MovedModule("builtins", "__builtin__"), - MovedModule("configparser", "ConfigParser"), - MovedModule("collections_abc", "collections", "collections.abc" if sys.version_info >= (3, 3) else "collections"), - MovedModule("copyreg", "copy_reg"), - MovedModule("dbm_gnu", "gdbm", "dbm.gnu"), - MovedModule("dbm_ndbm", "dbm", "dbm.ndbm"), - MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread" if sys.version_info < (3, 9) else "_thread"), - MovedModule("http_cookiejar", "cookielib", "http.cookiejar"), - MovedModule("http_cookies", "Cookie", "http.cookies"), - MovedModule("html_entities", "htmlentitydefs", "html.entities"), - MovedModule("html_parser", "HTMLParser", "html.parser"), - MovedModule("http_client", "httplib", "http.client"), - MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"), - MovedModule("email_mime_image", "email.MIMEImage", "email.mime.image"), - MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"), - MovedModule("email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart"), - MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"), - MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"), - MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"), - MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"), - MovedModule("cPickle", "cPickle", "pickle"), - MovedModule("queue", "Queue"), - MovedModule("reprlib", "repr"), - MovedModule("socketserver", "SocketServer"), - MovedModule("_thread", "thread", "_thread"), - MovedModule("tkinter", "Tkinter"), - MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"), - MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"), - MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"), - MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"), - MovedModule("tkinter_tix", "Tix", "tkinter.tix"), - MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"), - MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"), - MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"), - MovedModule("tkinter_colorchooser", "tkColorChooser", - "tkinter.colorchooser"), - MovedModule("tkinter_commondialog", "tkCommonDialog", - "tkinter.commondialog"), - MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"), - MovedModule("tkinter_font", "tkFont", "tkinter.font"), - MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"), - MovedModule("tkinter_tksimpledialog", "tkSimpleDialog", - "tkinter.simpledialog"), - MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"), - MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"), - MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"), - MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"), - MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"), - MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"), -] -# Add windows specific modules. -if sys.platform == "win32": - _moved_attributes += [ - MovedModule("winreg", "_winreg"), - ] - -for attr in _moved_attributes: - setattr(_MovedItems, attr.name, attr) - if isinstance(attr, MovedModule): - _importer._add_module(attr, "moves." + attr.name) -del attr - -_MovedItems._moved_attributes = _moved_attributes - -moves = _MovedItems(__name__ + ".moves") -_importer._add_module(moves, "moves") - - -class Module_six_moves_urllib_parse(_LazyModule): - - """Lazy loading of moved objects in six.moves.urllib_parse""" - - -_urllib_parse_moved_attributes = [ - MovedAttribute("ParseResult", "urlparse", "urllib.parse"), - MovedAttribute("SplitResult", "urlparse", "urllib.parse"), - MovedAttribute("parse_qs", "urlparse", "urllib.parse"), - MovedAttribute("parse_qsl", "urlparse", "urllib.parse"), - MovedAttribute("urldefrag", "urlparse", "urllib.parse"), - MovedAttribute("urljoin", "urlparse", "urllib.parse"), - MovedAttribute("urlparse", "urlparse", "urllib.parse"), - MovedAttribute("urlsplit", "urlparse", "urllib.parse"), - MovedAttribute("urlunparse", "urlparse", "urllib.parse"), - MovedAttribute("urlunsplit", "urlparse", "urllib.parse"), - MovedAttribute("quote", "urllib", "urllib.parse"), - MovedAttribute("quote_plus", "urllib", "urllib.parse"), - MovedAttribute("unquote", "urllib", "urllib.parse"), - MovedAttribute("unquote_plus", "urllib", "urllib.parse"), - MovedAttribute("unquote_to_bytes", "urllib", "urllib.parse", "unquote", "unquote_to_bytes"), - MovedAttribute("urlencode", "urllib", "urllib.parse"), - MovedAttribute("splitquery", "urllib", "urllib.parse"), - MovedAttribute("splittag", "urllib", "urllib.parse"), - MovedAttribute("splituser", "urllib", "urllib.parse"), - MovedAttribute("splitvalue", "urllib", "urllib.parse"), - MovedAttribute("uses_fragment", "urlparse", "urllib.parse"), - MovedAttribute("uses_netloc", "urlparse", "urllib.parse"), - MovedAttribute("uses_params", "urlparse", "urllib.parse"), - MovedAttribute("uses_query", "urlparse", "urllib.parse"), - MovedAttribute("uses_relative", "urlparse", "urllib.parse"), -] -for attr in _urllib_parse_moved_attributes: - setattr(Module_six_moves_urllib_parse, attr.name, attr) -del attr - -Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes - -_importer._add_module(Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"), - "moves.urllib_parse", "moves.urllib.parse") - - -class Module_six_moves_urllib_error(_LazyModule): - - """Lazy loading of moved objects in six.moves.urllib_error""" - - -_urllib_error_moved_attributes = [ - MovedAttribute("URLError", "urllib2", "urllib.error"), - MovedAttribute("HTTPError", "urllib2", "urllib.error"), - MovedAttribute("ContentTooShortError", "urllib", "urllib.error"), -] -for attr in _urllib_error_moved_attributes: - setattr(Module_six_moves_urllib_error, attr.name, attr) -del attr - -Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes - -_importer._add_module(Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"), - "moves.urllib_error", "moves.urllib.error") - - -class Module_six_moves_urllib_request(_LazyModule): - - """Lazy loading of moved objects in six.moves.urllib_request""" - - -_urllib_request_moved_attributes = [ - MovedAttribute("urlopen", "urllib2", "urllib.request"), - MovedAttribute("install_opener", "urllib2", "urllib.request"), - MovedAttribute("build_opener", "urllib2", "urllib.request"), - MovedAttribute("pathname2url", "urllib", "urllib.request"), - MovedAttribute("url2pathname", "urllib", "urllib.request"), - MovedAttribute("getproxies", "urllib", "urllib.request"), - MovedAttribute("Request", "urllib2", "urllib.request"), - MovedAttribute("OpenerDirector", "urllib2", "urllib.request"), - MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"), - MovedAttribute("ProxyHandler", "urllib2", "urllib.request"), - MovedAttribute("BaseHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"), - MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"), - MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"), - MovedAttribute("FileHandler", "urllib2", "urllib.request"), - MovedAttribute("FTPHandler", "urllib2", "urllib.request"), - MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"), - MovedAttribute("UnknownHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"), - MovedAttribute("urlretrieve", "urllib", "urllib.request"), - MovedAttribute("urlcleanup", "urllib", "urllib.request"), - MovedAttribute("URLopener", "urllib", "urllib.request"), - MovedAttribute("FancyURLopener", "urllib", "urllib.request"), - MovedAttribute("proxy_bypass", "urllib", "urllib.request"), - MovedAttribute("parse_http_list", "urllib2", "urllib.request"), - MovedAttribute("parse_keqv_list", "urllib2", "urllib.request"), -] -for attr in _urllib_request_moved_attributes: - setattr(Module_six_moves_urllib_request, attr.name, attr) -del attr - -Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes - -_importer._add_module(Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"), - "moves.urllib_request", "moves.urllib.request") - - -class Module_six_moves_urllib_response(_LazyModule): - - """Lazy loading of moved objects in six.moves.urllib_response""" - - -_urllib_response_moved_attributes = [ - MovedAttribute("addbase", "urllib", "urllib.response"), - MovedAttribute("addclosehook", "urllib", "urllib.response"), - MovedAttribute("addinfo", "urllib", "urllib.response"), - MovedAttribute("addinfourl", "urllib", "urllib.response"), -] -for attr in _urllib_response_moved_attributes: - setattr(Module_six_moves_urllib_response, attr.name, attr) -del attr - -Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes - -_importer._add_module(Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"), - "moves.urllib_response", "moves.urllib.response") - - -class Module_six_moves_urllib_robotparser(_LazyModule): - - """Lazy loading of moved objects in six.moves.urllib_robotparser""" - - -_urllib_robotparser_moved_attributes = [ - MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"), -] -for attr in _urllib_robotparser_moved_attributes: - setattr(Module_six_moves_urllib_robotparser, attr.name, attr) -del attr - -Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes - -_importer._add_module(Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"), - "moves.urllib_robotparser", "moves.urllib.robotparser") - - -class Module_six_moves_urllib(types.ModuleType): - - """Create a six.moves.urllib namespace that resembles the Python 3 namespace""" - __path__ = [] # mark as package - parse = _importer._get_module("moves.urllib_parse") - error = _importer._get_module("moves.urllib_error") - request = _importer._get_module("moves.urllib_request") - response = _importer._get_module("moves.urllib_response") - robotparser = _importer._get_module("moves.urllib_robotparser") - - def __dir__(self): - return ['parse', 'error', 'request', 'response', 'robotparser'] - -_importer._add_module(Module_six_moves_urllib(__name__ + ".moves.urllib"), - "moves.urllib") - - -def add_move(move): - """Add an item to six.moves.""" - setattr(_MovedItems, move.name, move) - - -def remove_move(name): - """Remove item from six.moves.""" - try: - delattr(_MovedItems, name) - except AttributeError: - try: - del moves.__dict__[name] - except KeyError: - raise AttributeError("no such move, %r" % (name,)) - - -if PY3: - _meth_func = "__func__" - _meth_self = "__self__" - - _func_closure = "__closure__" - _func_code = "__code__" - _func_defaults = "__defaults__" - _func_globals = "__globals__" -else: - _meth_func = "im_func" - _meth_self = "im_self" - - _func_closure = "func_closure" - _func_code = "func_code" - _func_defaults = "func_defaults" - _func_globals = "func_globals" - - -try: - advance_iterator = next -except NameError: - def advance_iterator(it): - return it.next() -next = advance_iterator - - -try: - callable = callable -except NameError: - def callable(obj): - return any("__call__" in klass.__dict__ for klass in type(obj).__mro__) - - -if PY3: - def get_unbound_function(unbound): - return unbound - - create_bound_method = types.MethodType - - def create_unbound_method(func, cls): - return func - - Iterator = object -else: - def get_unbound_function(unbound): - return unbound.im_func - - def create_bound_method(func, obj): - return types.MethodType(func, obj, obj.__class__) - - def create_unbound_method(func, cls): - return types.MethodType(func, None, cls) - - class Iterator(object): - - def next(self): - return type(self).__next__(self) - - callable = callable -_add_doc(get_unbound_function, - """Get the function out of a possibly unbound function""") - - -get_method_function = operator.attrgetter(_meth_func) -get_method_self = operator.attrgetter(_meth_self) -get_function_closure = operator.attrgetter(_func_closure) -get_function_code = operator.attrgetter(_func_code) -get_function_defaults = operator.attrgetter(_func_defaults) -get_function_globals = operator.attrgetter(_func_globals) - - -if PY3: - def iterkeys(d, **kw): - return iter(d.keys(**kw)) - - def itervalues(d, **kw): - return iter(d.values(**kw)) - - def iteritems(d, **kw): - return iter(d.items(**kw)) - - def iterlists(d, **kw): - return iter(d.lists(**kw)) - - viewkeys = operator.methodcaller("keys") - - viewvalues = operator.methodcaller("values") - - viewitems = operator.methodcaller("items") -else: - def iterkeys(d, **kw): - return d.iterkeys(**kw) - - def itervalues(d, **kw): - return d.itervalues(**kw) - - def iteritems(d, **kw): - return d.iteritems(**kw) - - def iterlists(d, **kw): - return d.iterlists(**kw) - - viewkeys = operator.methodcaller("viewkeys") - - viewvalues = operator.methodcaller("viewvalues") - - viewitems = operator.methodcaller("viewitems") - -_add_doc(iterkeys, "Return an iterator over the keys of a dictionary.") -_add_doc(itervalues, "Return an iterator over the values of a dictionary.") -_add_doc(iteritems, - "Return an iterator over the (key, value) pairs of a dictionary.") -_add_doc(iterlists, - "Return an iterator over the (key, [values]) pairs of a dictionary.") - - -if PY3: - def b(s): - return s.encode("latin-1") - - def u(s): - return s - unichr = chr - import struct - int2byte = struct.Struct(">B").pack - del struct - byte2int = operator.itemgetter(0) - indexbytes = operator.getitem - iterbytes = iter - import io - StringIO = io.StringIO - BytesIO = io.BytesIO - del io - _assertCountEqual = "assertCountEqual" - if sys.version_info[1] <= 1: - _assertRaisesRegex = "assertRaisesRegexp" - _assertRegex = "assertRegexpMatches" - _assertNotRegex = "assertNotRegexpMatches" - else: - _assertRaisesRegex = "assertRaisesRegex" - _assertRegex = "assertRegex" - _assertNotRegex = "assertNotRegex" -else: - def b(s): - return s - # Workaround for standalone backslash - - def u(s): - return unicode(s.replace(r'\\', r'\\\\'), "unicode_escape") - unichr = unichr - int2byte = chr - - def byte2int(bs): - return ord(bs[0]) - - def indexbytes(buf, i): - return ord(buf[i]) - iterbytes = functools.partial(itertools.imap, ord) - import StringIO - StringIO = BytesIO = StringIO.StringIO - _assertCountEqual = "assertItemsEqual" - _assertRaisesRegex = "assertRaisesRegexp" - _assertRegex = "assertRegexpMatches" - _assertNotRegex = "assertNotRegexpMatches" -_add_doc(b, """Byte literal""") -_add_doc(u, """Text literal""") - - -def assertCountEqual(self, *args, **kwargs): - return getattr(self, _assertCountEqual)(*args, **kwargs) - - -def assertRaisesRegex(self, *args, **kwargs): - return getattr(self, _assertRaisesRegex)(*args, **kwargs) - - -def assertRegex(self, *args, **kwargs): - return getattr(self, _assertRegex)(*args, **kwargs) - - -def assertNotRegex(self, *args, **kwargs): - return getattr(self, _assertNotRegex)(*args, **kwargs) - - -if PY3: - exec_ = getattr(moves.builtins, "exec") - - def reraise(tp, value, tb=None): - try: - if value is None: - value = tp() - if value.__traceback__ is not tb: - raise value.with_traceback(tb) - raise value - finally: - value = None - tb = None - -else: - def exec_(_code_, _globs_=None, _locs_=None): - """Execute code in a namespace.""" - if _globs_ is None: - frame = sys._getframe(1) - _globs_ = frame.f_globals - if _locs_ is None: - _locs_ = frame.f_locals - del frame - elif _locs_ is None: - _locs_ = _globs_ - exec("""exec _code_ in _globs_, _locs_""") - - exec_("""def reraise(tp, value, tb=None): - try: - raise tp, value, tb - finally: - tb = None -""") - - -if sys.version_info[:2] > (3,): - exec_("""def raise_from(value, from_value): - try: - raise value from from_value - finally: - value = None -""") -else: - def raise_from(value, from_value): - raise value - - -print_ = getattr(moves.builtins, "print", None) -if print_ is None: - def print_(*args, **kwargs): - """The new-style print function for Python 2.4 and 2.5.""" - fp = kwargs.pop("file", sys.stdout) - if fp is None: - return - - def write(data): - if not isinstance(data, basestring): - data = str(data) - # If the file has an encoding, encode unicode with it. - if (isinstance(fp, file) and - isinstance(data, unicode) and - fp.encoding is not None): - errors = getattr(fp, "errors", None) - if errors is None: - errors = "strict" - data = data.encode(fp.encoding, errors) - fp.write(data) - want_unicode = False - sep = kwargs.pop("sep", None) - if sep is not None: - if isinstance(sep, unicode): - want_unicode = True - elif not isinstance(sep, str): - raise TypeError("sep must be None or a string") - end = kwargs.pop("end", None) - if end is not None: - if isinstance(end, unicode): - want_unicode = True - elif not isinstance(end, str): - raise TypeError("end must be None or a string") - if kwargs: - raise TypeError("invalid keyword arguments to print()") - if not want_unicode: - for arg in args: - if isinstance(arg, unicode): - want_unicode = True - break - if want_unicode: - newline = unicode("\n") - space = unicode(" ") - else: - newline = "\n" - space = " " - if sep is None: - sep = space - if end is None: - end = newline - for i, arg in enumerate(args): - if i: - write(sep) - write(arg) - write(end) -if sys.version_info[:2] < (3, 3): - _print = print_ - - def print_(*args, **kwargs): - fp = kwargs.get("file", sys.stdout) - flush = kwargs.pop("flush", False) - _print(*args, **kwargs) - if flush and fp is not None: - fp.flush() - -_add_doc(reraise, """Reraise an exception.""") - -if sys.version_info[0:2] < (3, 4): - # This does exactly the same what the :func:`py3:functools.update_wrapper` - # function does on Python versions after 3.2. It sets the ``__wrapped__`` - # attribute on ``wrapper`` object and it doesn't raise an error if any of - # the attributes mentioned in ``assigned`` and ``updated`` are missing on - # ``wrapped`` object. - def _update_wrapper(wrapper, wrapped, - assigned=functools.WRAPPER_ASSIGNMENTS, - updated=functools.WRAPPER_UPDATES): - for attr in assigned: - try: - value = getattr(wrapped, attr) - except AttributeError: - continue - else: - setattr(wrapper, attr, value) - for attr in updated: - getattr(wrapper, attr).update(getattr(wrapped, attr, {})) - wrapper.__wrapped__ = wrapped - return wrapper - _update_wrapper.__doc__ = functools.update_wrapper.__doc__ - - def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS, - updated=functools.WRAPPER_UPDATES): - return functools.partial(_update_wrapper, wrapped=wrapped, - assigned=assigned, updated=updated) - wraps.__doc__ = functools.wraps.__doc__ - -else: - wraps = functools.wraps - - -def with_metaclass(meta, *bases): - """Create a base class with a metaclass.""" - # This requires a bit of explanation: the basic idea is to make a dummy - # metaclass for one level of class instantiation that replaces itself with - # the actual metaclass. - class metaclass(type): - - def __new__(cls, name, this_bases, d): - if sys.version_info[:2] >= (3, 7): - # This version introduced PEP 560 that requires a bit - # of extra care (we mimic what is done by __build_class__). - resolved_bases = types.resolve_bases(bases) - if resolved_bases is not bases: - d['__orig_bases__'] = bases - else: - resolved_bases = bases - return meta(name, resolved_bases, d) - - @classmethod - def __prepare__(cls, name, this_bases): - return meta.__prepare__(name, bases) - return type.__new__(metaclass, 'temporary_class', (), {}) - - -def add_metaclass(metaclass): - """Class decorator for creating a class with a metaclass.""" - def wrapper(cls): - orig_vars = cls.__dict__.copy() - slots = orig_vars.get('__slots__') - if slots is not None: - if isinstance(slots, str): - slots = [slots] - for slots_var in slots: - orig_vars.pop(slots_var) - orig_vars.pop('__dict__', None) - orig_vars.pop('__weakref__', None) - if hasattr(cls, '__qualname__'): - orig_vars['__qualname__'] = cls.__qualname__ - return metaclass(cls.__name__, cls.__bases__, orig_vars) - return wrapper - - -def ensure_binary(s, encoding='utf-8', errors='strict'): - """Coerce **s** to six.binary_type. - - For Python 2: - - `unicode` -> encoded to `str` - - `str` -> `str` - - For Python 3: - - `str` -> encoded to `bytes` - - `bytes` -> `bytes` - """ - if isinstance(s, binary_type): - return s - if isinstance(s, text_type): - return s.encode(encoding, errors) - raise TypeError("not expecting type '%s'" % type(s)) - - -def ensure_str(s, encoding='utf-8', errors='strict'): - """Coerce *s* to `str`. - - For Python 2: - - `unicode` -> encoded to `str` - - `str` -> `str` - - For Python 3: - - `str` -> `str` - - `bytes` -> decoded to `str` - """ - # Optimization: Fast return for the common case. - if type(s) is str: - return s - if PY2 and isinstance(s, text_type): - return s.encode(encoding, errors) - elif PY3 and isinstance(s, binary_type): - return s.decode(encoding, errors) - elif not isinstance(s, (text_type, binary_type)): - raise TypeError("not expecting type '%s'" % type(s)) - return s - - -def ensure_text(s, encoding='utf-8', errors='strict'): - """Coerce *s* to six.text_type. - - For Python 2: - - `unicode` -> `unicode` - - `str` -> `unicode` - - For Python 3: - - `str` -> `str` - - `bytes` -> decoded to `str` - """ - if isinstance(s, binary_type): - return s.decode(encoding, errors) - elif isinstance(s, text_type): - return s - else: - raise TypeError("not expecting type '%s'" % type(s)) - - -def python_2_unicode_compatible(klass): - """ - A class decorator that defines __unicode__ and __str__ methods under Python 2. - Under Python 3 it does nothing. - - To support Python 2 and 3 with a single code base, define a __str__ method - returning text and apply this decorator to the class. - """ - if PY2: - if '__str__' not in klass.__dict__: - raise ValueError("@python_2_unicode_compatible cannot be applied " - "to %s because it doesn't define __str__()." % - klass.__name__) - klass.__unicode__ = klass.__str__ - klass.__str__ = lambda self: self.__unicode__().encode('utf-8') - return klass - - -# Complete the moves implementation. -# This code is at the end of this module to speed up module loading. -# Turn this module into a package. -__path__ = [] # required for PEP 302 and PEP 451 -__package__ = __name__ # see PEP 366 @ReservedAssignment -if globals().get("__spec__") is not None: - __spec__.submodule_search_locations = [] # PEP 451 @UndefinedVariable -# Remove other six meta path importers, since they cause problems. This can -# happen if six is removed from sys.modules and then reloaded. (Setuptools does -# this for some reason.) -if sys.meta_path: - for i, importer in enumerate(sys.meta_path): - # Here's some real nastiness: Another "instance" of the six module might - # be floating around. Therefore, we can't use isinstance() to check for - # the six meta path importer, since the other six instance will have - # inserted an importer with different class. - if (type(importer).__name__ == "_SixMetaPathImporter" and - importer.name == __name__): - del sys.meta_path[i] - break - del i, importer -# Finally, add the importer to the meta path import hook. -sys.meta_path.append(_importer) diff --git a/venv/lib/python3.8/site-packages/telegram/__init__.py b/venv/lib/python3.8/site-packages/telegram/__init__.py deleted file mode 100644 index c71d3fd..0000000 --- a/venv/lib/python3.8/site-packages/telegram/__init__.py +++ /dev/null @@ -1,294 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""A library that provides a Python interface to the Telegram Bot API""" - -from .base import TelegramObject -from .botcommand import BotCommand -from .user import User -from .files.chatphoto import ChatPhoto -from .chat import Chat -from .chatlocation import ChatLocation -from .chatinvitelink import ChatInviteLink -from .chatmember import ChatMember -from .chatmemberupdated import ChatMemberUpdated -from .chatpermissions import ChatPermissions -from .files.photosize import PhotoSize -from .files.audio import Audio -from .files.voice import Voice -from .files.document import Document -from .files.animation import Animation -from .files.sticker import Sticker, StickerSet, MaskPosition -from .files.video import Video -from .files.contact import Contact -from .files.location import Location -from .files.venue import Venue -from .files.videonote import VideoNote -from .chataction import ChatAction -from .dice import Dice -from .userprofilephotos import UserProfilePhotos -from .keyboardbuttonpolltype import KeyboardButtonPollType -from .keyboardbutton import KeyboardButton -from .replymarkup import ReplyMarkup -from .replykeyboardmarkup import ReplyKeyboardMarkup -from .replykeyboardremove import ReplyKeyboardRemove -from .forcereply import ForceReply -from .error import TelegramError -from .files.inputfile import InputFile -from .files.file import File -from .parsemode import ParseMode -from .messageentity import MessageEntity -from .messageid import MessageId -from .games.game import Game -from .poll import Poll, PollOption, PollAnswer -from .voicechat import ( - VoiceChatStarted, - VoiceChatEnded, - VoiceChatParticipantsInvited, - VoiceChatScheduled, -) -from .loginurl import LoginUrl -from .proximityalerttriggered import ProximityAlertTriggered -from .games.callbackgame import CallbackGame -from .payment.shippingaddress import ShippingAddress -from .payment.orderinfo import OrderInfo -from .payment.successfulpayment import SuccessfulPayment -from .payment.invoice import Invoice -from .passport.credentials import EncryptedCredentials -from .passport.passportfile import PassportFile -from .passport.data import IdDocumentData, PersonalDetails, ResidentialAddress -from .passport.encryptedpassportelement import EncryptedPassportElement -from .passport.passportdata import PassportData -from .inline.inlinekeyboardbutton import InlineKeyboardButton -from .inline.inlinekeyboardmarkup import InlineKeyboardMarkup -from .messageautodeletetimerchanged import MessageAutoDeleteTimerChanged -from .message import Message -from .callbackquery import CallbackQuery -from .choseninlineresult import ChosenInlineResult -from .inline.inputmessagecontent import InputMessageContent -from .inline.inlinequery import InlineQuery -from .inline.inlinequeryresult import InlineQueryResult -from .inline.inlinequeryresultarticle import InlineQueryResultArticle -from .inline.inlinequeryresultaudio import InlineQueryResultAudio -from .inline.inlinequeryresultcachedaudio import InlineQueryResultCachedAudio -from .inline.inlinequeryresultcacheddocument import InlineQueryResultCachedDocument -from .inline.inlinequeryresultcachedgif import InlineQueryResultCachedGif -from .inline.inlinequeryresultcachedmpeg4gif import InlineQueryResultCachedMpeg4Gif -from .inline.inlinequeryresultcachedphoto import InlineQueryResultCachedPhoto -from .inline.inlinequeryresultcachedsticker import InlineQueryResultCachedSticker -from .inline.inlinequeryresultcachedvideo import InlineQueryResultCachedVideo -from .inline.inlinequeryresultcachedvoice import InlineQueryResultCachedVoice -from .inline.inlinequeryresultcontact import InlineQueryResultContact -from .inline.inlinequeryresultdocument import InlineQueryResultDocument -from .inline.inlinequeryresultgif import InlineQueryResultGif -from .inline.inlinequeryresultlocation import InlineQueryResultLocation -from .inline.inlinequeryresultmpeg4gif import InlineQueryResultMpeg4Gif -from .inline.inlinequeryresultphoto import InlineQueryResultPhoto -from .inline.inlinequeryresultvenue import InlineQueryResultVenue -from .inline.inlinequeryresultvideo import InlineQueryResultVideo -from .inline.inlinequeryresultvoice import InlineQueryResultVoice -from .inline.inlinequeryresultgame import InlineQueryResultGame -from .inline.inputtextmessagecontent import InputTextMessageContent -from .inline.inputlocationmessagecontent import InputLocationMessageContent -from .inline.inputvenuemessagecontent import InputVenueMessageContent -from .payment.labeledprice import LabeledPrice -from .inline.inputinvoicemessagecontent import InputInvoiceMessageContent -from .inline.inputcontactmessagecontent import InputContactMessageContent -from .payment.shippingoption import ShippingOption -from .payment.precheckoutquery import PreCheckoutQuery -from .payment.shippingquery import ShippingQuery -from .webhookinfo import WebhookInfo -from .games.gamehighscore import GameHighScore -from .update import Update -from .files.inputmedia import ( - InputMedia, - InputMediaVideo, - InputMediaPhoto, - InputMediaAnimation, - InputMediaAudio, - InputMediaDocument, -) -from .constants import ( - MAX_MESSAGE_LENGTH, - MAX_CAPTION_LENGTH, - SUPPORTED_WEBHOOK_PORTS, - MAX_FILESIZE_DOWNLOAD, - MAX_FILESIZE_UPLOAD, - MAX_MESSAGES_PER_SECOND_PER_CHAT, - MAX_MESSAGES_PER_SECOND, - MAX_MESSAGES_PER_MINUTE_PER_GROUP, -) -from .passport.passportelementerrors import ( - PassportElementError, - PassportElementErrorDataField, - PassportElementErrorFile, - PassportElementErrorFiles, - PassportElementErrorFrontSide, - PassportElementErrorReverseSide, - PassportElementErrorSelfie, - PassportElementErrorTranslationFile, - PassportElementErrorTranslationFiles, - PassportElementErrorUnspecified, -) -from .passport.credentials import ( - Credentials, - DataCredentials, - SecureData, - SecureValue, - FileCredentials, - TelegramDecryptionError, -) -from .bot import Bot -from .version import __version__, bot_api_version # noqa: F401 - -__author__ = 'devs@python-telegram-bot.org' - -__all__ = ( # Keep this alphabetically ordered - 'Animation', - 'Audio', - 'Bot', - 'BotCommand', - 'CallbackGame', - 'CallbackQuery', - 'Chat', - 'ChatAction', - 'ChatInviteLink', - 'ChatLocation', - 'ChatMember', - 'ChatMemberUpdated', - 'ChatPermissions', - 'ChatPhoto', - 'ChosenInlineResult', - 'Contact', - 'Credentials', - 'DataCredentials', - 'Dice', - 'Document', - 'EncryptedCredentials', - 'EncryptedPassportElement', - 'File', - 'FileCredentials', - 'ForceReply', - 'Game', - 'GameHighScore', - 'IdDocumentData', - 'InlineKeyboardButton', - 'InlineKeyboardMarkup', - 'InlineQuery', - 'InlineQueryResult', - 'InlineQueryResultArticle', - 'InlineQueryResultAudio', - 'InlineQueryResultCachedAudio', - 'InlineQueryResultCachedDocument', - 'InlineQueryResultCachedGif', - 'InlineQueryResultCachedMpeg4Gif', - 'InlineQueryResultCachedPhoto', - 'InlineQueryResultCachedSticker', - 'InlineQueryResultCachedVideo', - 'InlineQueryResultCachedVoice', - 'InlineQueryResultContact', - 'InlineQueryResultDocument', - 'InlineQueryResultGame', - 'InlineQueryResultGif', - 'InlineQueryResultLocation', - 'InlineQueryResultMpeg4Gif', - 'InlineQueryResultPhoto', - 'InlineQueryResultVenue', - 'InlineQueryResultVideo', - 'InlineQueryResultVoice', - 'InputContactMessageContent', - 'InputFile', - 'InputInvoiceMessageContent', - 'InputLocationMessageContent', - 'InputMedia', - 'InputMediaAnimation', - 'InputMediaAudio', - 'InputMediaDocument', - 'InputMediaPhoto', - 'InputMediaVideo', - 'InputMessageContent', - 'InputTextMessageContent', - 'InputVenueMessageContent', - 'Invoice', - 'KeyboardButton', - 'KeyboardButtonPollType', - 'LabeledPrice', - 'Location', - 'LoginUrl', - 'MAX_CAPTION_LENGTH', - 'MAX_FILESIZE_DOWNLOAD', - 'MAX_FILESIZE_UPLOAD', - 'MAX_MESSAGES_PER_MINUTE_PER_GROUP', - 'MAX_MESSAGES_PER_SECOND', - 'MAX_MESSAGES_PER_SECOND_PER_CHAT', - 'MAX_MESSAGE_LENGTH', - 'MaskPosition', - 'Message', - 'MessageAutoDeleteTimerChanged', - 'MessageEntity', - 'MessageId', - 'OrderInfo', - 'ParseMode', - 'PassportData', - 'PassportElementError', - 'PassportElementErrorDataField', - 'PassportElementErrorFile', - 'PassportElementErrorFiles', - 'PassportElementErrorFrontSide', - 'PassportElementErrorReverseSide', - 'PassportElementErrorSelfie', - 'PassportElementErrorTranslationFile', - 'PassportElementErrorTranslationFiles', - 'PassportElementErrorUnspecified', - 'PassportFile', - 'PersonalDetails', - 'PhotoSize', - 'Poll', - 'PollAnswer', - 'PollOption', - 'PreCheckoutQuery', - 'ProximityAlertTriggered', - 'ReplyKeyboardMarkup', - 'ReplyKeyboardRemove', - 'ReplyMarkup', - 'ResidentialAddress', - 'SUPPORTED_WEBHOOK_PORTS', - 'SecureData', - 'SecureValue', - 'ShippingAddress', - 'ShippingOption', - 'ShippingQuery', - 'Sticker', - 'StickerSet', - 'SuccessfulPayment', - 'TelegramDecryptionError', - 'TelegramError', - 'TelegramObject', - 'Update', - 'User', - 'UserProfilePhotos', - 'Venue', - 'Video', - 'VideoNote', - 'Voice', - 'VoiceChatStarted', - 'VoiceChatEnded', - 'VoiceChatScheduled', - 'VoiceChatParticipantsInvited', - 'WebhookInfo', -) diff --git a/venv/lib/python3.8/site-packages/telegram/__main__.py b/venv/lib/python3.8/site-packages/telegram/__main__.py deleted file mode 100644 index 0e8db82..0000000 --- a/venv/lib/python3.8/site-packages/telegram/__main__.py +++ /dev/null @@ -1,54 +0,0 @@ -# !/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -# pylint: disable=C0114 -import subprocess -import sys -from typing import Optional - -import certifi - -from . import __version__ as telegram_ver -from .constants import BOT_API_VERSION - - -def _git_revision() -> Optional[str]: - try: - output = subprocess.check_output( # skipcq: BAN-B607 - ["git", "describe", "--long", "--tags"], stderr=subprocess.STDOUT - ) - except (subprocess.SubprocessError, OSError): - return None - return output.decode().strip() - - -def print_ver_info() -> None: # skipcq: PY-D0003 - git_revision = _git_revision() - print(f'python-telegram-bot {telegram_ver}' + (f' ({git_revision})' if git_revision else '')) - print(f'Bot API {BOT_API_VERSION}') - print(f'certifi {certifi.__version__}') # type: ignore[attr-defined] - sys_version = sys.version.replace('\n', ' ') - print(f'Python {sys_version}') - - -def main() -> None: # skipcq: PY-D0003 - print_ver_info() - - -if __name__ == '__main__': - main() diff --git a/venv/lib/python3.8/site-packages/telegram/base.py b/venv/lib/python3.8/site-packages/telegram/base.py deleted file mode 100644 index 0f906e9..0000000 --- a/venv/lib/python3.8/site-packages/telegram/base.py +++ /dev/null @@ -1,152 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""Base class for Telegram Objects.""" -try: - import ujson as json -except ImportError: - import json # type: ignore[no-redef] - -import warnings -from typing import TYPE_CHECKING, List, Optional, Tuple, Type, TypeVar - -from telegram.utils.types import JSONDict -from telegram.utils.deprecate import set_new_attribute_deprecated - -if TYPE_CHECKING: - from telegram import Bot - -TO = TypeVar('TO', bound='TelegramObject', covariant=True) - - -class TelegramObject: - """Base class for most Telegram objects.""" - - _id_attrs: Tuple[object, ...] = () - - # Adding slots reduces memory usage & allows for faster attribute access. - # Only instance variables should be added to __slots__. - # We add __dict__ here for backward compatibility & also to avoid repetition for subclasses. - __slots__ = ('__dict__',) - - def __str__(self) -> str: - return str(self.to_dict()) - - def __getitem__(self, item: str) -> object: - return getattr(self, item, None) - - def __setattr__(self, key: str, value: object) -> None: - set_new_attribute_deprecated(self, key, value) - - @staticmethod - def _parse_data(data: Optional[JSONDict]) -> Optional[JSONDict]: - return None if data is None else data.copy() - - @classmethod - def de_json(cls: Type[TO], data: Optional[JSONDict], bot: 'Bot') -> Optional[TO]: - """Converts JSON data to a Telegram object. - - Args: - data (Dict[:obj:`str`, ...]): The JSON data. - bot (:class:`telegram.Bot`): The bot associated with this object. - - Returns: - The Telegram object. - - """ - data = cls._parse_data(data) - - if data is None: - return None - - if cls == TelegramObject: - return cls() - return cls(bot=bot, **data) # type: ignore[call-arg] - - @classmethod - def de_list(cls: Type[TO], data: Optional[List[JSONDict]], bot: 'Bot') -> List[Optional[TO]]: - """Converts JSON data to a list of Telegram objects. - - Args: - data (Dict[:obj:`str`, ...]): The JSON data. - bot (:class:`telegram.Bot`): The bot associated with these objects. - - Returns: - A list of Telegram objects. - - """ - if not data: - return [] - - return [cls.de_json(d, bot) for d in data] - - def to_json(self) -> str: - """Gives a JSON representation of object. - - Returns: - :obj:`str` - """ - return json.dumps(self.to_dict()) - - def to_dict(self) -> JSONDict: - """Gives representation of object as :obj:`dict`. - - Returns: - :obj:`dict` - """ - data = {} - - # We want to get all attributes for the class, using self.__slots__ only includes the - # attributes used by that class itself, and not its superclass(es). Hence we get its MRO - # and then get their attributes. The `[:-2]` slice excludes the `object` class & the - # TelegramObject class itself. - attrs = {attr for cls in self.__class__.__mro__[:-2] for attr in cls.__slots__} - for key in attrs: - if key == 'bot' or key.startswith('_'): - continue - - value = getattr(self, key, None) - if value is not None: - if hasattr(value, 'to_dict'): - data[key] = value.to_dict() - else: - data[key] = value - - if data.get('from_user'): - data['from'] = data.pop('from_user', None) - return data - - def __eq__(self, other: object) -> bool: - if isinstance(other, self.__class__): - if self._id_attrs == (): - warnings.warn( - f"Objects of type {self.__class__.__name__} can not be meaningfully tested for" - " equivalence." - ) - if other._id_attrs == (): - warnings.warn( - f"Objects of type {other.__class__.__name__} can not be meaningfully tested" - " for equivalence." - ) - return self._id_attrs == other._id_attrs - return super().__eq__(other) # pylint: disable=no-member - - def __hash__(self) -> int: - if self._id_attrs: - return hash((self.__class__, self._id_attrs)) # pylint: disable=no-member - return super().__hash__() diff --git a/venv/lib/python3.8/site-packages/telegram/bot.py b/venv/lib/python3.8/site-packages/telegram/bot.py deleted file mode 100644 index db81a1d..0000000 --- a/venv/lib/python3.8/site-packages/telegram/bot.py +++ /dev/null @@ -1,5318 +0,0 @@ -#!/usr/bin/env python -# pylint: disable=E0611,E0213,E1102,E1101,R0913,R0904 -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram Bot.""" - -import functools -import logging -import warnings -from datetime import datetime - -from typing import ( - TYPE_CHECKING, - Callable, - List, - Optional, - Tuple, - TypeVar, - Union, - no_type_check, - Dict, - cast, - Sequence, -) - -try: - import ujson as json -except ImportError: - import json # type: ignore[no-redef] # noqa: F723 - -try: - from cryptography.hazmat.backends import default_backend - from cryptography.hazmat.primitives import serialization - - CRYPTO_INSTALLED = True -except ImportError: - default_backend = None # type: ignore[assignment] - serialization = None # type: ignore[assignment] - CRYPTO_INSTALLED = False - -from telegram import ( - Animation, - Audio, - BotCommand, - Chat, - ChatMember, - ChatPermissions, - ChatPhoto, - Contact, - Document, - File, - GameHighScore, - Location, - MaskPosition, - Message, - MessageId, - PassportElementError, - PhotoSize, - Poll, - ReplyMarkup, - ShippingOption, - Sticker, - StickerSet, - TelegramObject, - Update, - User, - UserProfilePhotos, - Venue, - Video, - VideoNote, - Voice, - WebhookInfo, - InlineKeyboardMarkup, - ChatInviteLink, -) -from telegram.constants import MAX_INLINE_QUERY_RESULTS -from telegram.error import InvalidToken, TelegramError -from telegram.utils.deprecate import TelegramDeprecationWarning -from telegram.utils.helpers import ( - DEFAULT_NONE, - DefaultValue, - to_timestamp, - is_local_file, - parse_file_input, - DEFAULT_20, -) -from telegram.utils.request import Request -from telegram.utils.types import FileInput, JSONDict, ODVInput, DVInput - -if TYPE_CHECKING: - from telegram.ext import Defaults - from telegram import ( - InputMediaAudio, - InputMediaDocument, - InputMediaPhoto, - InputMediaVideo, - InputMedia, - InlineQueryResult, - LabeledPrice, - MessageEntity, - ) - -RT = TypeVar('RT') - - -def log( # skipcq: PY-D0003 - func: Callable[..., RT], *args: object, **kwargs: object # pylint: disable=W0613 -) -> Callable[..., RT]: - logger = logging.getLogger(func.__module__) - - @functools.wraps(func) - def decorator(*args: object, **kwargs: object) -> RT: # pylint: disable=W0613 - logger.debug('Entering: %s', func.__name__) - result = func(*args, **kwargs) - logger.debug(result) - logger.debug('Exiting: %s', func.__name__) - return result - - return decorator - - -class Bot(TelegramObject): - """This object represents a Telegram Bot. - - .. versionadded:: 13.2 - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`bot` is equal. - - Note: - Most bot methods have the argument ``api_kwargs`` which allows to pass arbitrary keywords - to the Telegram API. This can be used to access new features of the API before they were - incorporated into PTB. However, this is not guaranteed to work, i.e. it will fail for - passing files. - - Args: - token (:obj:`str`): Bot's unique authentication. - base_url (:obj:`str`, optional): Telegram Bot API service URL. - base_file_url (:obj:`str`, optional): Telegram Bot API file URL. - request (:obj:`telegram.utils.request.Request`, optional): Pre initialized - :obj:`telegram.utils.request.Request`. - private_key (:obj:`bytes`, optional): Private key for decryption of telegram passport data. - private_key_password (:obj:`bytes`, optional): Password for above private key. - defaults (:class:`telegram.ext.Defaults`, optional): An object containing default values to - be used if not set explicitly in the bot methods. - - .. deprecated:: 13.6 - Passing :class:`telegram.ext.Defaults` to :class:`telegram.Bot` is deprecated. If - you want to use :class:`telegram.ext.Defaults`, please use - :class:`telegram.ext.ExtBot` instead. - - """ - - __slots__ = ( - 'token', - 'base_url', - 'base_file_url', - 'private_key', - 'defaults', - '_bot', - '_commands', - '_request', - 'logger', - ) - - def __init__( - self, - token: str, - base_url: str = None, - base_file_url: str = None, - request: 'Request' = None, - private_key: bytes = None, - private_key_password: bytes = None, - defaults: 'Defaults' = None, - ): - self.token = self._validate_token(token) - - # Gather default - self.defaults = defaults - - if self.defaults: - warnings.warn( - 'Passing Defaults to telegram.Bot is deprecated. Use telegram.ext.ExtBot instead.', - TelegramDeprecationWarning, - stacklevel=3, - ) - - if base_url is None: - base_url = 'https://api.telegram.org/bot' - - if base_file_url is None: - base_file_url = 'https://api.telegram.org/file/bot' - - self.base_url = str(base_url) + str(self.token) - self.base_file_url = str(base_file_url) + str(self.token) - self._bot: Optional[User] = None - self._commands: Optional[List[BotCommand]] = None - self._request = request or Request() - self.private_key = None - self.logger = logging.getLogger(__name__) - - if private_key: - if not CRYPTO_INSTALLED: - raise RuntimeError( - 'To use Telegram Passports, PTB must be installed via `pip install ' - 'python-telegram-bot[passport]`.' - ) - self.private_key = serialization.load_pem_private_key( - private_key, password=private_key_password, backend=default_backend() - ) - - # The ext_bot argument is a little hack to get warnings handled correctly. - # It's not very clean, but the warnings will be dropped at some point anyway. - def __setattr__(self, key: str, value: object, ext_bot: bool = False) -> None: - if issubclass(self.__class__, Bot) and self.__class__ is not Bot and not ext_bot: - object.__setattr__(self, key, value) - return - super().__setattr__(key, value) - - def _insert_defaults( - self, data: Dict[str, object], timeout: ODVInput[float] - ) -> Optional[float]: - """ - Inserts the defaults values for optional kwargs for which tg.ext.Defaults provides - convenience functionality, i.e. the kwargs with a tg.utils.helpers.DefaultValue default - - data is edited in-place. As timeout is not passed via the kwargs, it needs to be passed - separately and gets returned. - - This can only work, if all kwargs that may have defaults are passed in data! - """ - effective_timeout = DefaultValue.get_value(timeout) - - # If we have no Defaults, we just need to replace DefaultValue instances - # with the actual value - if not self.defaults: - data.update((key, DefaultValue.get_value(value)) for key, value in data.items()) - return effective_timeout - - # if we have Defaults, we replace all DefaultValue instances with the relevant - # Defaults value. If there is none, we fall back to the default value of the bot method - for key, val in data.items(): - if isinstance(val, DefaultValue): - data[key] = self.defaults.api_defaults.get(key, val.value) - - if isinstance(timeout, DefaultValue): - # If we get here, we use Defaults.timeout, unless that's not set, which is the - # case if isinstance(self.defaults.timeout, DefaultValue) - return ( - self.defaults.timeout - if not isinstance(self.defaults.timeout, DefaultValue) - else effective_timeout - ) - return effective_timeout - - def _post( - self, - endpoint: str, - data: JSONDict = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> Union[bool, JSONDict, None]: - if data is None: - data = {} - - if api_kwargs: - if data: - data.update(api_kwargs) - else: - data = api_kwargs - - # Insert is in-place, so no return value for data - if endpoint != 'getUpdates': - effective_timeout = self._insert_defaults(data, timeout) - else: - effective_timeout = cast(float, timeout) - # Drop any None values because Telegram doesn't handle them well - data = {key: value for key, value in data.items() if value is not None} - - return self.request.post( - f'{self.base_url}/{endpoint}', data=data, timeout=effective_timeout - ) - - def _message( - self, - endpoint: str, - data: JSONDict, - reply_to_message_id: int = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: ReplyMarkup = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> Union[bool, Message]: - if reply_to_message_id is not None: - data['reply_to_message_id'] = reply_to_message_id - - # We don't check if (DEFAULT_)None here, so that _put is able to insert the defaults - # correctly, if necessary - data['disable_notification'] = disable_notification - data['allow_sending_without_reply'] = allow_sending_without_reply - - if reply_markup is not None: - if isinstance(reply_markup, ReplyMarkup): - # We need to_json() instead of to_dict() here, because reply_markups may be - # attached to media messages, which aren't json dumped by utils.request - data['reply_markup'] = reply_markup.to_json() - else: - data['reply_markup'] = reply_markup - - if data.get('media') and (data['media'].parse_mode == DEFAULT_NONE): - if self.defaults: - data['media'].parse_mode = DefaultValue.get_value(self.defaults.parse_mode) - else: - data['media'].parse_mode = None - - result = self._post(endpoint, data, timeout=timeout, api_kwargs=api_kwargs) - - if result is True: - return result - - return Message.de_json(result, self) # type: ignore[return-value, arg-type] - - @property - def request(self) -> Request: # skip-cq: PY-D0003 - return self._request - - @staticmethod - def _validate_token(token: str) -> str: - """A very basic validation on token.""" - if any(x.isspace() for x in token): - raise InvalidToken() - - left, sep, _right = token.partition(':') - if (not sep) or (not left.isdigit()) or (len(left) < 3): - raise InvalidToken() - - return token - - @property - def bot(self) -> User: - """:class:`telegram.User`: User instance for the bot as returned by :meth:`get_me`.""" - if self._bot is None: - self._bot = self.get_me() - return self._bot - - @property - def id(self) -> int: # pylint: disable=C0103 - """:obj:`int`: Unique identifier for this bot.""" - return self.bot.id - - @property - def first_name(self) -> str: - """:obj:`str`: Bot's first name.""" - return self.bot.first_name - - @property - def last_name(self) -> str: - """:obj:`str`: Optional. Bot's last name.""" - return self.bot.last_name # type: ignore - - @property - def username(self) -> str: - """:obj:`str`: Bot's username.""" - return self.bot.username # type: ignore - - @property - def link(self) -> str: - """:obj:`str`: Convenience property. Returns the t.me link of the bot.""" - return f"https://t.me/{self.username}" - - @property - def can_join_groups(self) -> bool: - """:obj:`bool`: Bot's :attr:`telegram.User.can_join_groups` attribute.""" - return self.bot.can_join_groups # type: ignore - - @property - def can_read_all_group_messages(self) -> bool: - """:obj:`bool`: Bot's :attr:`telegram.User.can_read_all_group_messages` attribute.""" - return self.bot.can_read_all_group_messages # type: ignore - - @property - def supports_inline_queries(self) -> bool: - """:obj:`bool`: Bot's :attr:`telegram.User.supports_inline_queries` attribute.""" - return self.bot.supports_inline_queries # type: ignore - - @property - def commands(self) -> List[BotCommand]: - """List[:class:`BotCommand`]: Bot's commands.""" - if self._commands is None: - self._commands = self.get_my_commands() - return self._commands - - @property - def name(self) -> str: - """:obj:`str`: Bot's @username.""" - return f'@{self.username}' - - @log - def get_me(self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None) -> User: - """A simple method for testing your bot's auth token. Requires no parameters. - - Args: - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :class:`telegram.User`: A :class:`telegram.User` instance representing that bot if the - credentials are valid, :obj:`None` otherwise. - - Raises: - :class:`telegram.error.TelegramError` - - """ - result = self._post('getMe', timeout=timeout, api_kwargs=api_kwargs) - - self._bot = User.de_json(result, self) # type: ignore[return-value, arg-type] - - return self._bot # type: ignore[return-value] - - @log - def send_message( - self, - chat_id: Union[int, str], - text: str, - parse_mode: ODVInput[str] = DEFAULT_NONE, - disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: ReplyMarkup = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - ) -> Message: - """Use this method to send text messages. - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target channel (in the format ``@channelusername``). - text (:obj:`str`): Text of the message to be sent. Max 4096 characters after entities - parsing. Also found as :attr:`telegram.constants.MAX_MESSAGE_LENGTH`. - parse_mode (:obj:`str`): Send Markdown or HTML, if you want Telegram apps to show bold, - italic, fixed-width text or inline URLs in your bot's message. See the constants in - :class:`telegram.ParseMode` for the available modes. - entities (List[:class:`telegram.MessageEntity`], optional): List of special entities - that appear in message text, which can be specified instead of :attr:`parse_mode`. - disable_web_page_preview (:obj:`bool`, optional): Disables link previews for links in - this message. - disable_notification (:obj:`bool`, optional): Sends the message silently. Users will - receive a notification with no sound. - reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the - original message. - allow_sending_without_reply (:obj:`bool`, optional): Pass :obj:`True`, if the message - should be sent even if the specified replied-to message is not found. - reply_markup (:class:`telegram.ReplyMarkup`, optional): Additional interface options. - A JSON-serialized object for an inline keyboard, custom reply keyboard, - instructions to remove reply keyboard or to force a reply from the user. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :class:`telegram.Message`: On success, the sent message is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - 'chat_id': chat_id, - 'text': text, - 'parse_mode': parse_mode, - 'disable_web_page_preview': disable_web_page_preview, - } - - if entities: - data['entities'] = [me.to_dict() for me in entities] - - return self._message( # type: ignore[return-value] - 'sendMessage', - data, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - allow_sending_without_reply=allow_sending_without_reply, - timeout=timeout, - api_kwargs=api_kwargs, - ) - - @log - def delete_message( - self, - chat_id: Union[str, int], - message_id: int, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> bool: - """ - Use this method to delete a message, including service messages, with the following - limitations: - - - A message can only be deleted if it was sent less than 48 hours ago. - - A dice message in a private chat can only be deleted if it was sent more than 24 - hours ago. - - Bots can delete outgoing messages in private chats, groups, and supergroups. - - Bots can delete incoming messages in private chats. - - Bots granted :attr:`telegram.ChatMember.can_post_messages` permissions can delete - outgoing messages in channels. - - If the bot is an administrator of a group, it can delete any message there. - - If the bot has :attr:`telegram.ChatMember.can_delete_messages` permission in a - supergroup or a channel, it can delete any message there. - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target channel (in the format ``@channelusername``). - message_id (:obj:`int`): Identifier of the message to delete. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {'chat_id': chat_id, 'message_id': message_id} - - result = self._post('deleteMessage', data, timeout=timeout, api_kwargs=api_kwargs) - - return result # type: ignore[return-value] - - @log - def forward_message( - self, - chat_id: Union[int, str], - from_chat_id: Union[str, int], - message_id: int, - disable_notification: DVInput[bool] = DEFAULT_NONE, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> Message: - """Use this method to forward messages of any kind. Service messages can't be forwarded. - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target channel (in the format ``@channelusername``). - from_chat_id (:obj:`int` | :obj:`str`): Unique identifier for the chat where the - original message was sent (or channel username in the format ``@channelusername``). - message_id (:obj:`int`): Message identifier in the chat specified in from_chat_id. - disable_notification (:obj:`bool`, optional): Sends the message silently. Users will - receive a notification with no sound. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :class:`telegram.Message`: On success, the sent Message is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {} - - if chat_id: - data['chat_id'] = chat_id - if from_chat_id: - data['from_chat_id'] = from_chat_id - if message_id: - data['message_id'] = message_id - - return self._message( # type: ignore[return-value] - 'forwardMessage', - data, - disable_notification=disable_notification, - timeout=timeout, - api_kwargs=api_kwargs, - ) - - @log - def send_photo( - self, - chat_id: Union[int, str], - photo: Union[FileInput, 'PhotoSize'], - caption: str = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: ReplyMarkup = None, - timeout: DVInput[float] = DEFAULT_20, - parse_mode: ODVInput[str] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - filename: str = None, - ) -> Message: - """Use this method to send photos. - - Note: - The photo argument can be either a file_id, an URL or a file from disk - ``open(filename, 'rb')`` - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target channel (in the format ``@channelusername``). - photo (:obj:`str` | `filelike object` | :obj:`bytes` | :class:`pathlib.Path` | \ - :class:`telegram.PhotoSize`): Photo to send. - Pass a file_id as String to send a photo that exists on the Telegram servers - (recommended), pass an HTTP URL as a String for Telegram to get a photo from the - Internet, or upload a new photo using multipart/form-data. Lastly you can pass - an existing :class:`telegram.PhotoSize` object to send. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - filename (:obj:`str`, optional): Custom file name for the photo, when uploading a - new file. Convenience parameter, useful e.g. when sending files generated by the - :obj:`tempfile` module. - - .. versionadded:: 13.1 - caption (:obj:`str`, optional): Photo caption (may also be used when resending photos - by file_id), 0-1024 characters after entities parsing. - parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to - show bold, italic, fixed-width text or inline URLs in the media caption. See the - constants in :class:`telegram.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special - entities that appear in message text, which can be specified instead of - :attr:`parse_mode`. - disable_notification (:obj:`bool`, optional): Sends the message silently. Users will - receive a notification with no sound. - reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the - original message. - allow_sending_without_reply (:obj:`bool`, optional): Pass :obj:`True`, if the message - should be sent even if the specified replied-to message is not found. - reply_markup (:class:`telegram.ReplyMarkup`, optional): Additional interface options. A - JSON-serialized object for an inline keyboard, custom reply keyboard, instructions - to remove reply keyboard or to force a reply from the user. - timeout (:obj:`int` | :obj:`float`, optional): Send file timeout (default: 20 seconds). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :class:`telegram.Message`: On success, the sent Message is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - 'chat_id': chat_id, - 'photo': parse_file_input(photo, PhotoSize, filename=filename), - 'parse_mode': parse_mode, - } - - if caption: - data['caption'] = caption - - if caption_entities: - data['caption_entities'] = [me.to_dict() for me in caption_entities] - - return self._message( # type: ignore[return-value] - 'sendPhoto', - data, - timeout=timeout, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - allow_sending_without_reply=allow_sending_without_reply, - api_kwargs=api_kwargs, - ) - - @log - def send_audio( - self, - chat_id: Union[int, str], - audio: Union[FileInput, 'Audio'], - duration: int = None, - performer: str = None, - title: str = None, - caption: str = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: ReplyMarkup = None, - timeout: DVInput[float] = DEFAULT_20, - parse_mode: ODVInput[str] = DEFAULT_NONE, - thumb: FileInput = None, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - filename: str = None, - ) -> Message: - """ - Use this method to send audio files, if you want Telegram clients to display them in the - music player. Your audio must be in the .mp3 or .m4a format. - - Bots can currently send audio files of up to 50 MB in size, this limit may be changed in - the future. - - For sending voice messages, use the :meth:`send_voice` method instead. - - Note: - The audio argument can be either a file_id, an URL or a file from disk - ``open(filename, 'rb')`` - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target channel (in the format ``@channelusername``). - audio (:obj:`str` | `filelike object` | :obj:`bytes` | :class:`pathlib.Path` | \ - :class:`telegram.Audio`): Audio file to send. - Pass a file_id as String to send an audio file that exists on the Telegram servers - (recommended), pass an HTTP URL as a String for Telegram to get an audio file from - the Internet, or upload a new one using multipart/form-data. Lastly you can pass - an existing :class:`telegram.Audio` object to send. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - filename (:obj:`str`, optional): Custom file name for the audio, when uploading a - new file. Convenience parameter, useful e.g. when sending files generated by the - :obj:`tempfile` module. - - .. versionadded:: 13.1 - caption (:obj:`str`, optional): Audio caption, 0-1024 characters after entities - parsing. - parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to - show bold, italic, fixed-width text or inline URLs in the media caption. See the - constants in :class:`telegram.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special - entities that appear in message text, which can be specified instead of - :attr:`parse_mode`. - duration (:obj:`int`, optional): Duration of sent audio in seconds. - performer (:obj:`str`, optional): Performer. - title (:obj:`str`, optional): Track name. - disable_notification (:obj:`bool`, optional): Sends the message silently. Users will - receive a notification with no sound. - reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the - original message. - allow_sending_without_reply (:obj:`bool`, optional): Pass :obj:`True`, if the message - should be sent even if the specified replied-to message is not found. - reply_markup (:class:`telegram.ReplyMarkup`, optional): Additional interface options. A - JSON-serialized object for an inline keyboard, custom reply keyboard, instructions - to remove reply keyboard or to force a reply from the user. - thumb (`filelike object` | :obj:`bytes` | :class:`pathlib.Path`, optional): Thumbnail - of the file sent; can be ignored if - thumbnail generation for the file is supported server-side. The thumbnail should be - in JPEG format and less than 200 kB in size. A thumbnail's width and height should - not exceed 320. Ignored if the file is not uploaded using multipart/form-data. - Thumbnails can't be reused and can be only uploaded as a new file. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - timeout (:obj:`int` | :obj:`float`, optional): Send file timeout (default: 20 seconds). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :class:`telegram.Message`: On success, the sent Message is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - 'chat_id': chat_id, - 'audio': parse_file_input(audio, Audio, filename=filename), - 'parse_mode': parse_mode, - } - - if duration: - data['duration'] = duration - if performer: - data['performer'] = performer - if title: - data['title'] = title - if caption: - data['caption'] = caption - - if caption_entities: - data['caption_entities'] = [me.to_dict() for me in caption_entities] - if thumb: - data['thumb'] = parse_file_input(thumb, attach=True) - - return self._message( # type: ignore[return-value] - 'sendAudio', - data, - timeout=timeout, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - allow_sending_without_reply=allow_sending_without_reply, - api_kwargs=api_kwargs, - ) - - @log - def send_document( - self, - chat_id: Union[int, str], - document: Union[FileInput, 'Document'], - filename: str = None, - caption: str = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: ReplyMarkup = None, - timeout: DVInput[float] = DEFAULT_20, - parse_mode: ODVInput[str] = DEFAULT_NONE, - thumb: FileInput = None, - api_kwargs: JSONDict = None, - disable_content_type_detection: bool = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - ) -> Message: - """ - Use this method to send general files. - - Bots can currently send files of any type of up to 50 MB in size, this limit may be - changed in the future. - - Note: - The document argument can be either a file_id, an URL or a file from disk - ``open(filename, 'rb')`` - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target channel (in the format ``@channelusername``). - document (:obj:`str` | `filelike object` | :obj:`bytes` | :class:`pathlib.Path` | \ - :class:`telegram.Document`): File to send. - Pass a file_id as String to send a file that exists on the Telegram servers - (recommended), pass an HTTP URL as a String for Telegram to get a file from the - Internet, or upload a new one using multipart/form-data. Lastly you can pass - an existing :class:`telegram.Document` object to send. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - filename (:obj:`str`, optional): Custom file name for the document, when uploading a - new file. Convenience parameter, useful e.g. when sending files generated by the - :obj:`tempfile` module. - caption (:obj:`str`, optional): Document caption (may also be used when resending - documents by file_id), 0-1024 characters after entities parsing. - disable_content_type_detection (:obj:`bool`, optional): Disables automatic server-side - content type detection for files uploaded using multipart/form-data. - parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to - show bold, italic, fixed-width text or inline URLs in the media caption. See the - constants in :class:`telegram.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special - entities that appear in message text, which can be specified instead of - :attr:`parse_mode`. - disable_notification (:obj:`bool`, optional): Sends the message silently. Users will - receive a notification with no sound. - reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the - original message. - allow_sending_without_reply (:obj:`bool`, optional): Pass :obj:`True`, if the message - should be sent even if the specified replied-to message is not found. - reply_markup (:class:`telegram.ReplyMarkup`, optional): Additional interface options. A - JSON-serialized object for an inline keyboard, custom reply keyboard, instructions - to remove reply keyboard or to force a reply from the user. - thumb (`filelike object` | :obj:`bytes` | :class:`pathlib.Path`, optional): Thumbnail - of the file sent; can be ignored if - thumbnail generation for the file is supported server-side. The thumbnail should be - in JPEG format and less than 200 kB in size. A thumbnail's width and height should - not exceed 320. Ignored if the file is not uploaded using multipart/form-data. - Thumbnails can't be reused and can be only uploaded as a new file. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - timeout (:obj:`int` | :obj:`float`, optional): Send file timeout (default: 20 seconds). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :class:`telegram.Message`: On success, the sent Message is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - 'chat_id': chat_id, - 'document': parse_file_input(document, Document, filename=filename), - 'parse_mode': parse_mode, - } - - if caption: - data['caption'] = caption - - if caption_entities: - data['caption_entities'] = [me.to_dict() for me in caption_entities] - if disable_content_type_detection is not None: - data['disable_content_type_detection'] = disable_content_type_detection - if thumb: - data['thumb'] = parse_file_input(thumb, attach=True) - - return self._message( # type: ignore[return-value] - 'sendDocument', - data, - timeout=timeout, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - allow_sending_without_reply=allow_sending_without_reply, - api_kwargs=api_kwargs, - ) - - @log - def send_sticker( - self, - chat_id: Union[int, str], - sticker: Union[FileInput, 'Sticker'], - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: ReplyMarkup = None, - timeout: DVInput[float] = DEFAULT_20, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - ) -> Message: - """ - Use this method to send static .WEBP or animated .TGS stickers. - - Note: - The sticker argument can be either a file_id, an URL or a file from disk - ``open(filename, 'rb')`` - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target channel (in the format ``@channelusername``). - sticker (:obj:`str` | `filelike object` | :obj:`bytes` | :class:`pathlib.Path` | \ - :class:`telegram.Sticker`): Sticker to send. - Pass a file_id as String to send a file that exists on the Telegram servers - (recommended), pass an HTTP URL as a String for Telegram to get a .webp file from - the Internet, or upload a new one using multipart/form-data. Lastly you can pass - an existing :class:`telegram.Sticker` object to send. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - disable_notification (:obj:`bool`, optional): Sends the message silently. Users will - receive a notification with no sound. - reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the - original message. - allow_sending_without_reply (:obj:`bool`, optional): Pass :obj:`True`, if the message - should be sent even if the specified replied-to message is not found. - reply_markup (:class:`telegram.ReplyMarkup`, optional): Additional interface options. A - JSON-serialized object for an inline keyboard, custom reply keyboard, instructions - to remove reply keyboard or to force a reply from the user. - timeout (:obj:`int` | :obj:`float`, optional): Send file timeout (default: 20 seconds). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :class:`telegram.Message`: On success, the sent Message is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {'chat_id': chat_id, 'sticker': parse_file_input(sticker, Sticker)} - - return self._message( # type: ignore[return-value] - 'sendSticker', - data, - timeout=timeout, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - allow_sending_without_reply=allow_sending_without_reply, - api_kwargs=api_kwargs, - ) - - @log - def send_video( - self, - chat_id: Union[int, str], - video: Union[FileInput, 'Video'], - duration: int = None, - caption: str = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: ReplyMarkup = None, - timeout: DVInput[float] = DEFAULT_20, - width: int = None, - height: int = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - supports_streaming: bool = None, - thumb: FileInput = None, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - filename: str = None, - ) -> Message: - """ - Use this method to send video files, Telegram clients support mp4 videos - (other formats may be sent as Document). - - Bots can currently send video files of up to 50 MB in size, this limit may be changed in - the future. - - Note: - * The video argument can be either a file_id, an URL or a file from disk - ``open(filename, 'rb')`` - * ``thumb`` will be ignored for small video files, for which Telegram can easily - generate thumb nails. However, this behaviour is undocumented and might be changed - by Telegram. - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target channel (in the format ``@channelusername``). - video (:obj:`str` | `filelike object` | :obj:`bytes` | :class:`pathlib.Path` | \ - :class:`telegram.Video`): Video file to send. - Pass a file_id as String to send an video file that exists on the Telegram servers - (recommended), pass an HTTP URL as a String for Telegram to get an video file from - the Internet, or upload a new one using multipart/form-data. Lastly you can pass - an existing :class:`telegram.Video` object to send. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - filename (:obj:`str`, optional): Custom file name for the video, when uploading a - new file. Convenience parameter, useful e.g. when sending files generated by the - :obj:`tempfile` module. - - .. versionadded:: 13.1 - duration (:obj:`int`, optional): Duration of sent video in seconds. - width (:obj:`int`, optional): Video width. - height (:obj:`int`, optional): Video height. - caption (:obj:`str`, optional): Video caption (may also be used when resending videos - by file_id), 0-1024 characters after entities parsing. - parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to - show bold, italic, fixed-width text or inline URLs in the media caption. See the - constants in :class:`telegram.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special - entities that appear in message text, which can be specified instead of - :attr:`parse_mode`. - supports_streaming (:obj:`bool`, optional): Pass :obj:`True`, if the uploaded video is - suitable for streaming. - disable_notification (:obj:`bool`, optional): Sends the message silently. Users will - receive a notification with no sound. - reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the - original message. - allow_sending_without_reply (:obj:`bool`, optional): Pass :obj:`True`, if the message - should be sent even if the specified replied-to message is not found. - reply_markup (:class:`telegram.ReplyMarkup`, optional): Additional interface options. A - JSON-serialized object for an inline keyboard, custom reply keyboard, instructions - to remove reply keyboard or to force a reply from the user. - thumb (`filelike object` | :obj:`bytes` | :class:`pathlib.Path`, optional): Thumbnail - of the file sent; can be ignored if - thumbnail generation for the file is supported server-side. The thumbnail should be - in JPEG format and less than 200 kB in size. A thumbnail's width and height should - not exceed 320. Ignored if the file is not uploaded using multipart/form-data. - Thumbnails can't be reused and can be only uploaded as a new file. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - timeout (:obj:`int` | :obj:`float`, optional): Send file timeout (default: 20 seconds). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :class:`telegram.Message`: On success, the sent Message is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - 'chat_id': chat_id, - 'video': parse_file_input(video, Video, filename=filename), - 'parse_mode': parse_mode, - } - - if duration: - data['duration'] = duration - if caption: - data['caption'] = caption - if caption_entities: - data['caption_entities'] = [me.to_dict() for me in caption_entities] - if supports_streaming: - data['supports_streaming'] = supports_streaming - if width: - data['width'] = width - if height: - data['height'] = height - if thumb: - data['thumb'] = parse_file_input(thumb, attach=True) - - return self._message( # type: ignore[return-value] - 'sendVideo', - data, - timeout=timeout, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - allow_sending_without_reply=allow_sending_without_reply, - api_kwargs=api_kwargs, - ) - - @log - def send_video_note( - self, - chat_id: Union[int, str], - video_note: Union[FileInput, 'VideoNote'], - duration: int = None, - length: int = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: ReplyMarkup = None, - timeout: DVInput[float] = DEFAULT_20, - thumb: FileInput = None, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - filename: str = None, - ) -> Message: - """ - As of v.4.0, Telegram clients support rounded square mp4 videos of up to 1 minute long. - Use this method to send video messages. - - Note: - * The video_note argument can be either a file_id or a file from disk - ``open(filename, 'rb')`` - * ``thumb`` will be ignored for small video files, for which Telegram can easily - generate thumb nails. However, this behaviour is undocumented and might be changed - by Telegram. - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target channel (in the format ``@channelusername``). - video_note (:obj:`str` | `filelike object` | :obj:`bytes` | :class:`pathlib.Path` | \ - :class:`telegram.VideoNote`): Video note - to send. Pass a file_id as String to send a video note that exists on the Telegram - servers (recommended) or upload a new video using multipart/form-data. Or you can - pass an existing :class:`telegram.VideoNote` object to send. Sending video notes by - a URL is currently unsupported. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - filename (:obj:`str`, optional): Custom file name for the video note, when uploading a - new file. Convenience parameter, useful e.g. when sending files generated by the - :obj:`tempfile` module. - - .. versionadded:: 13.1 - duration (:obj:`int`, optional): Duration of sent video in seconds. - length (:obj:`int`, optional): Video width and height, i.e. diameter of the video - message. - disable_notification (:obj:`bool`, optional): Sends the message silently. Users will - receive a notification with no sound. - reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the - original message. - allow_sending_without_reply (:obj:`bool`, optional): Pass :obj:`True`, if the message - should be sent even if the specified replied-to message is not found. - reply_markup (:class:`telegram.ReplyMarkup`, optional): Additional interface options. A - JSON-serialized object for an inline keyboard, custom reply keyboard, - instructions to remove reply keyboard or to force a reply from the user. - thumb (`filelike object` | :obj:`bytes` | :class:`pathlib.Path`, optional): Thumbnail - of the file sent; can be ignored if - thumbnail generation for the file is supported server-side. The thumbnail should be - in JPEG format and less than 200 kB in size. A thumbnail's width and height should - not exceed 320. Ignored if the file is not uploaded using multipart/form-data. - Thumbnails can't be reused and can be only uploaded as a new file. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - timeout (:obj:`int` | :obj:`float`, optional): Send file timeout (default: 20 seconds). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :class:`telegram.Message`: On success, the sent Message is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - 'chat_id': chat_id, - 'video_note': parse_file_input(video_note, VideoNote, filename=filename), - } - - if duration is not None: - data['duration'] = duration - if length is not None: - data['length'] = length - if thumb: - data['thumb'] = parse_file_input(thumb, attach=True) - - return self._message( # type: ignore[return-value] - 'sendVideoNote', - data, - timeout=timeout, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - allow_sending_without_reply=allow_sending_without_reply, - api_kwargs=api_kwargs, - ) - - @log - def send_animation( - self, - chat_id: Union[int, str], - animation: Union[FileInput, 'Animation'], - duration: int = None, - width: int = None, - height: int = None, - thumb: FileInput = None, - caption: str = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: ReplyMarkup = None, - timeout: DVInput[float] = DEFAULT_20, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - filename: str = None, - ) -> Message: - """ - Use this method to send animation files (GIF or H.264/MPEG-4 AVC video without sound). - Bots can currently send animation files of up to 50 MB in size, this limit may be changed - in the future. - - Note: - ``thumb`` will be ignored for small files, for which Telegram can easily - generate thumb nails. However, this behaviour is undocumented and might be changed - by Telegram. - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target channel (in the format ``@channelusername``). - animation (:obj:`str` | `filelike object` | :obj:`bytes` | :class:`pathlib.Path` | \ - :class:`telegram.Animation`): Animation to - send. Pass a file_id as String to send an animation that exists on the Telegram - servers (recommended), pass an HTTP URL as a String for Telegram to get an - animation from the Internet, or upload a new animation using multipart/form-data. - Lastly you can pass an existing :class:`telegram.Animation` object to send. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - filename (:obj:`str`, optional): Custom file name for the animation, when uploading a - new file. Convenience parameter, useful e.g. when sending files generated by the - :obj:`tempfile` module. - - .. versionadded:: 13.1 - duration (:obj:`int`, optional): Duration of sent animation in seconds. - width (:obj:`int`, optional): Animation width. - height (:obj:`int`, optional): Animation height. - thumb (`filelike object` | :obj:`bytes` | :class:`pathlib.Path`, optional): Thumbnail - of the file sent; can be ignored if - thumbnail generation for the file is supported server-side. The thumbnail should be - in JPEG format and less than 200 kB in size. A thumbnail's width and height should - not exceed 320. Ignored if the file is not uploaded using multipart/form-data. - Thumbnails can't be reused and can be only uploaded as a new file. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - caption (:obj:`str`, optional): Animation caption (may also be used when resending - animations by file_id), 0-1024 characters after entities parsing. - parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to - show bold, italic, fixed-width text or inline URLs in the media caption. See the - constants in :class:`telegram.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special - entities that appear in message text, which can be specified instead of - :attr:`parse_mode`. - disable_notification (:obj:`bool`, optional): Sends the message silently. Users will - receive a notification with no sound. - reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the - original message. - allow_sending_without_reply (:obj:`bool`, optional): Pass :obj:`True`, if the message - should be sent even if the specified replied-to message is not found. - reply_markup (:class:`telegram.ReplyMarkup`, optional): Additional interface options. A - JSON-serialized object for an inline keyboard, custom reply keyboard, instructions - to remove reply keyboard or to force a reply from the user. - timeout (:obj:`int` | :obj:`float`, optional): Send file timeout (default: 20 seconds). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :class:`telegram.Message`: On success, the sent Message is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - 'chat_id': chat_id, - 'animation': parse_file_input(animation, Animation, filename=filename), - 'parse_mode': parse_mode, - } - - if duration: - data['duration'] = duration - if width: - data['width'] = width - if height: - data['height'] = height - if thumb: - data['thumb'] = parse_file_input(thumb, attach=True) - if caption: - data['caption'] = caption - if caption_entities: - data['caption_entities'] = [me.to_dict() for me in caption_entities] - - return self._message( # type: ignore[return-value] - 'sendAnimation', - data, - timeout=timeout, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - allow_sending_without_reply=allow_sending_without_reply, - api_kwargs=api_kwargs, - ) - - @log - def send_voice( - self, - chat_id: Union[int, str], - voice: Union[FileInput, 'Voice'], - duration: int = None, - caption: str = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: ReplyMarkup = None, - timeout: DVInput[float] = DEFAULT_20, - parse_mode: ODVInput[str] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - filename: str = None, - ) -> Message: - """ - Use this method to send audio files, if you want Telegram clients to display the file - as a playable voice message. For this to work, your audio must be in an .ogg file - encoded with OPUS (other formats may be sent as Audio or Document). Bots can currently - send voice messages of up to 50 MB in size, this limit may be changed in the future. - - Note: - The voice argument can be either a file_id, an URL or a file from disk - ``open(filename, 'rb')`` - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target channel (in the format ``@channelusername``). - voice (:obj:`str` | `filelike object` | :obj:`bytes` | :class:`pathlib.Path` | \ - :class:`telegram.Voice`): Voice file to send. - Pass a file_id as String to send an voice file that exists on the Telegram servers - (recommended), pass an HTTP URL as a String for Telegram to get an voice file from - the Internet, or upload a new one using multipart/form-data. Lastly you can pass - an existing :class:`telegram.Voice` object to send. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - filename (:obj:`str`, optional): Custom file name for the voice, when uploading a - new file. Convenience parameter, useful e.g. when sending files generated by the - :obj:`tempfile` module. - - .. versionadded:: 13.1 - caption (:obj:`str`, optional): Voice message caption, 0-1024 characters after entities - parsing. - parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to - show bold, italic, fixed-width text or inline URLs in the media caption. See the - constants in :class:`telegram.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special - entities that appear in message text, which can be specified instead of - :attr:`parse_mode`. - duration (:obj:`int`, optional): Duration of the voice message in seconds. - disable_notification (:obj:`bool`, optional): Sends the message silently. Users will - receive a notification with no sound. - reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the - original message. - allow_sending_without_reply (:obj:`bool`, optional): Pass :obj:`True`, if the message - should be sent even if the specified replied-to message is not found. - reply_markup (:class:`telegram.ReplyMarkup`, optional): Additional interface options. A - JSON-serialized object for an inline keyboard, custom reply keyboard, - instructions to remove reply keyboard or to force a reply from the user. - timeout (:obj:`int` | :obj:`float`, optional): Send file timeout (default: 20 seconds). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :class:`telegram.Message`: On success, the sent Message is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - 'chat_id': chat_id, - 'voice': parse_file_input(voice, Voice, filename=filename), - 'parse_mode': parse_mode, - } - - if duration: - data['duration'] = duration - if caption: - data['caption'] = caption - - if caption_entities: - data['caption_entities'] = [me.to_dict() for me in caption_entities] - - return self._message( # type: ignore[return-value] - 'sendVoice', - data, - timeout=timeout, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - allow_sending_without_reply=allow_sending_without_reply, - api_kwargs=api_kwargs, - ) - - @log - def send_media_group( - self, - chat_id: Union[int, str], - media: List[ - Union['InputMediaAudio', 'InputMediaDocument', 'InputMediaPhoto', 'InputMediaVideo'] - ], - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - timeout: DVInput[float] = DEFAULT_20, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - ) -> List[Message]: - """Use this method to send a group of photos or videos as an album. - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target channel (in the format ``@channelusername``). - media (List[:class:`telegram.InputMediaAudio`, :class:`telegram.InputMediaDocument`, \ - :class:`telegram.InputMediaPhoto`, :class:`telegram.InputMediaVideo`]): An array - describing messages to be sent, must include 2–10 items. - disable_notification (:obj:`bool`, optional): Sends the message silently. Users will - receive a notification with no sound. - reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the - original message. - allow_sending_without_reply (:obj:`bool`, optional): Pass :obj:`True`, if the message - should be sent even if the specified replied-to message is not found. - timeout (:obj:`int` | :obj:`float`, optional): Send file timeout (default: 20 seconds). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - List[:class:`telegram.Message`]: An array of the sent Messages. - - Raises: - :class:`telegram.error.TelegramError` - """ - data: JSONDict = { - 'chat_id': chat_id, - 'media': media, - 'disable_notification': disable_notification, - 'allow_sending_without_reply': allow_sending_without_reply, - } - - for med in data['media']: - if med.parse_mode == DEFAULT_NONE: - if self.defaults: - med.parse_mode = DefaultValue.get_value(self.defaults.parse_mode) - else: - med.parse_mode = None - - if reply_to_message_id: - data['reply_to_message_id'] = reply_to_message_id - - result = self._post('sendMediaGroup', data, timeout=timeout, api_kwargs=api_kwargs) - - return Message.de_list(result, self) # type: ignore - - @log - def send_location( - self, - chat_id: Union[int, str], - latitude: float = None, - longitude: float = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: ReplyMarkup = None, - timeout: ODVInput[float] = DEFAULT_NONE, - location: Location = None, - live_period: int = None, - api_kwargs: JSONDict = None, - horizontal_accuracy: float = None, - heading: int = None, - proximity_alert_radius: int = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - ) -> Message: - """Use this method to send point on the map. - - Note: - You can either supply a :obj:`latitude` and :obj:`longitude` or a :obj:`location`. - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target channel (in the format ``@channelusername``). - latitude (:obj:`float`, optional): Latitude of location. - longitude (:obj:`float`, optional): Longitude of location. - location (:class:`telegram.Location`, optional): The location to send. - horizontal_accuracy (:obj:`int`, optional): The radius of uncertainty for the location, - measured in meters; 0-1500. - live_period (:obj:`int`, optional): Period in seconds for which the location will be - updated, should be between 60 and 86400. - heading (:obj:`int`, optional): For live locations, a direction in which the user is - moving, in degrees. Must be between 1 and 360 if specified. - proximity_alert_radius (:obj:`int`, optional): For live locations, a maximum distance - for proximity alerts about approaching another chat member, in meters. Must be - between 1 and 100000 if specified. - disable_notification (:obj:`bool`, optional): Sends the message silently. Users will - receive a notification with no sound. - reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the - original message. - allow_sending_without_reply (:obj:`bool`, optional): Pass :obj:`True`, if the message - should be sent even if the specified replied-to message is not found. - reply_markup (:class:`telegram.ReplyMarkup`, optional): Additional interface options. A - JSON-serialized object for an inline keyboard, custom reply keyboard, - instructions to remove reply keyboard or to force a reply from the user. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :class:`telegram.Message`: On success, the sent Message is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - if not ((latitude is not None and longitude is not None) or location): - raise ValueError( - "Either location or latitude and longitude must be passed as argument." - ) - - if not (latitude is not None or longitude is not None) ^ bool(location): - raise ValueError( - "Either location or latitude and longitude must be passed as argument. Not both." - ) - - if isinstance(location, Location): - latitude = location.latitude - longitude = location.longitude - - data: JSONDict = {'chat_id': chat_id, 'latitude': latitude, 'longitude': longitude} - - if live_period: - data['live_period'] = live_period - if horizontal_accuracy: - data['horizontal_accuracy'] = horizontal_accuracy - if heading: - data['heading'] = heading - if proximity_alert_radius: - data['proximity_alert_radius'] = proximity_alert_radius - - return self._message( # type: ignore[return-value] - 'sendLocation', - data, - timeout=timeout, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - allow_sending_without_reply=allow_sending_without_reply, - api_kwargs=api_kwargs, - ) - - @log - def edit_message_live_location( - self, - chat_id: Union[str, int] = None, - message_id: int = None, - inline_message_id: int = None, - latitude: float = None, - longitude: float = None, - location: Location = None, - reply_markup: InlineKeyboardMarkup = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - horizontal_accuracy: float = None, - heading: int = None, - proximity_alert_radius: int = None, - ) -> Union[Message, bool]: - """Use this method to edit live location messages sent by the bot or via the bot - (for inline bots). A location can be edited until its :attr:`telegram.Location.live_period` - expires or editing is explicitly disabled by a call to :meth:`stop_message_live_location`. - - Note: - You can either supply a :obj:`latitude` and :obj:`longitude` or a :obj:`location`. - - Args: - chat_id (:obj:`int` | :obj:`str`, optional): Required if inline_message_id is not - specified. Unique identifier for the target chat or username of the target channel - (in the format ``@channelusername``). - message_id (:obj:`int`, optional): Required if inline_message_id is not specified. - Identifier of the message to edit. - inline_message_id (:obj:`str`, optional): Required if chat_id and message_id are not - specified. Identifier of the inline message. - latitude (:obj:`float`, optional): Latitude of location. - longitude (:obj:`float`, optional): Longitude of location. - location (:class:`telegram.Location`, optional): The location to send. - horizontal_accuracy (:obj:`float`, optional): The radius of uncertainty for the - location, measured in meters; 0-1500. - heading (:obj:`int`, optional): Direction in which the user is moving, in degrees. Must - be between 1 and 360 if specified. - proximity_alert_radius (:obj:`int`, optional): Maximum distance for proximity alerts - about approaching another chat member, in meters. Must be between 1 and 100000 if - specified. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): A JSON-serialized - object for a new inline keyboard. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :class:`telegram.Message`: On success, if edited message is not an inline message, the - edited message is returned, otherwise :obj:`True` is returned. - """ - if not (all([latitude, longitude]) or location): - raise ValueError( - "Either location or latitude and longitude must be passed as argument." - ) - if not (latitude is not None or longitude is not None) ^ bool(location): - raise ValueError( - "Either location or latitude and longitude must be passed as argument. Not both." - ) - - if isinstance(location, Location): - latitude = location.latitude - longitude = location.longitude - - data: JSONDict = {'latitude': latitude, 'longitude': longitude} - - if chat_id: - data['chat_id'] = chat_id - if message_id: - data['message_id'] = message_id - if inline_message_id: - data['inline_message_id'] = inline_message_id - if horizontal_accuracy: - data['horizontal_accuracy'] = horizontal_accuracy - if heading: - data['heading'] = heading - if proximity_alert_radius: - data['proximity_alert_radius'] = proximity_alert_radius - - return self._message( - 'editMessageLiveLocation', - data, - timeout=timeout, - reply_markup=reply_markup, - api_kwargs=api_kwargs, - ) - - @log - def stop_message_live_location( - self, - chat_id: Union[str, int] = None, - message_id: int = None, - inline_message_id: int = None, - reply_markup: InlineKeyboardMarkup = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> Union[Message, bool]: - """Use this method to stop updating a live location message sent by the bot or via the bot - (for inline bots) before live_period expires. - - Args: - chat_id (:obj:`int` | :obj:`str`): Required if inline_message_id is not specified. - Unique identifier for the target chat or username of the target channel - (in the format ``@channelusername``). - message_id (:obj:`int`, optional): Required if inline_message_id is not specified. - Identifier of the sent message with live location to stop. - inline_message_id (:obj:`str`, optional): Required if chat_id and message_id are not - specified. Identifier of the inline message. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): A JSON-serialized - object for a new inline keyboard. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :class:`telegram.Message`: On success, if edited message is sent by the bot, the - sent Message is returned, otherwise :obj:`True` is returned. - """ - data: JSONDict = {} - - if chat_id: - data['chat_id'] = chat_id - if message_id: - data['message_id'] = message_id - if inline_message_id: - data['inline_message_id'] = inline_message_id - - return self._message( - 'stopMessageLiveLocation', - data, - timeout=timeout, - reply_markup=reply_markup, - api_kwargs=api_kwargs, - ) - - @log - def send_venue( - self, - chat_id: Union[int, str], - latitude: float = None, - longitude: float = None, - title: str = None, - address: str = None, - foursquare_id: str = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: ReplyMarkup = None, - timeout: ODVInput[float] = DEFAULT_NONE, - venue: Venue = None, - foursquare_type: str = None, - api_kwargs: JSONDict = None, - google_place_id: str = None, - google_place_type: str = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - ) -> Message: - """Use this method to send information about a venue. - - Note: - * You can either supply :obj:`venue`, or :obj:`latitude`, :obj:`longitude`, - :obj:`title` and :obj:`address` and optionally :obj:`foursquare_id` and - :obj:`foursquare_type` or optionally :obj:`google_place_id` and - :obj:`google_place_type`. - * Foursquare details and Google Pace details are mutually exclusive. However, this - behaviour is undocumented and might be changed by Telegram. - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target channel (in the format ``@channelusername``). - latitude (:obj:`float`, optional): Latitude of venue. - longitude (:obj:`float`, optional): Longitude of venue. - title (:obj:`str`, optional): Name of the venue. - address (:obj:`str`, optional): Address of the venue. - foursquare_id (:obj:`str`, optional): Foursquare identifier of the venue. - foursquare_type (:obj:`str`, optional): Foursquare type of the venue, if known. - (For example, "arts_entertainment/default", "arts_entertainment/aquarium" or - "food/icecream".) - google_place_id (:obj:`str`, optional): Google Places identifier of the venue. - google_place_type (:obj:`str`, optional): Google Places type of the venue. (See - `supported types \ - <https://developers.google.com/places/web-service/supported_types>`_.) - venue (:class:`telegram.Venue`, optional): The venue to send. - disable_notification (:obj:`bool`, optional): Sends the message silently. Users will - receive a notification with no sound. - reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the - original message. - allow_sending_without_reply (:obj:`bool`, optional): Pass :obj:`True`, if the message - should be sent even if the specified replied-to message is not found. - reply_markup (:class:`telegram.ReplyMarkup`, optional): Additional interface options. A - JSON-serialized object for an inline keyboard, custom reply keyboard, instructions - to remove reply keyboard or to force a reply from the user. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :class:`telegram.Message`: On success, the sent Message is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - if not (venue or all([latitude, longitude, address, title])): - raise ValueError( - "Either venue or latitude, longitude, address and title must be" - "passed as arguments." - ) - - if isinstance(venue, Venue): - latitude = venue.location.latitude - longitude = venue.location.longitude - address = venue.address - title = venue.title - foursquare_id = venue.foursquare_id - foursquare_type = venue.foursquare_type - google_place_id = venue.google_place_id - google_place_type = venue.google_place_type - - data: JSONDict = { - 'chat_id': chat_id, - 'latitude': latitude, - 'longitude': longitude, - 'address': address, - 'title': title, - } - - if foursquare_id: - data['foursquare_id'] = foursquare_id - if foursquare_type: - data['foursquare_type'] = foursquare_type - if google_place_id: - data['google_place_id'] = google_place_id - if google_place_type: - data['google_place_type'] = google_place_type - - return self._message( # type: ignore[return-value] - 'sendVenue', - data, - timeout=timeout, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - allow_sending_without_reply=allow_sending_without_reply, - api_kwargs=api_kwargs, - ) - - @log - def send_contact( - self, - chat_id: Union[int, str], - phone_number: str = None, - first_name: str = None, - last_name: str = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: ReplyMarkup = None, - timeout: ODVInput[float] = DEFAULT_NONE, - contact: Contact = None, - vcard: str = None, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - ) -> Message: - """Use this method to send phone contacts. - - Note: - You can either supply :obj:`contact` or :obj:`phone_number` and :obj:`first_name` - with optionally :obj:`last_name` and optionally :obj:`vcard`. - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target channel (in the format ``@channelusername``). - phone_number (:obj:`str`, optional): Contact's phone number. - first_name (:obj:`str`, optional): Contact's first name. - last_name (:obj:`str`, optional): Contact's last name. - vcard (:obj:`str`, optional): Additional data about the contact in the form of a vCard, - 0-2048 bytes. - contact (:class:`telegram.Contact`, optional): The contact to send. - disable_notification (:obj:`bool`, optional): Sends the message silently. Users will - receive a notification with no sound. - reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the - original message. - allow_sending_without_reply (:obj:`bool`, optional): Pass :obj:`True`, if the message - should be sent even if the specified replied-to message is not found. - reply_markup (:class:`telegram.ReplyMarkup`, optional): Additional interface options. A - JSON-serialized object for an inline keyboard, custom reply keyboard, instructions - to remove reply keyboard or to force a reply from the user. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :class:`telegram.Message`: On success, the sent Message is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - if (not contact) and (not all([phone_number, first_name])): - raise ValueError( - "Either contact or phone_number and first_name must be passed as arguments." - ) - - if isinstance(contact, Contact): - phone_number = contact.phone_number - first_name = contact.first_name - last_name = contact.last_name - vcard = contact.vcard - - data: JSONDict = { - 'chat_id': chat_id, - 'phone_number': phone_number, - 'first_name': first_name, - } - - if last_name: - data['last_name'] = last_name - if vcard: - data['vcard'] = vcard - - return self._message( # type: ignore[return-value] - 'sendContact', - data, - timeout=timeout, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - allow_sending_without_reply=allow_sending_without_reply, - api_kwargs=api_kwargs, - ) - - @log - def send_game( - self, - chat_id: Union[int, str], - game_short_name: str, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: InlineKeyboardMarkup = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - ) -> Message: - """Use this method to send a game. - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat. - game_short_name (:obj:`str`): Short name of the game, serves as the unique identifier - for the game. Set up your games via `@BotFather <https://t.me/BotFather>`_. - disable_notification (:obj:`bool`, optional): Sends the message silently. Users will - receive a notification with no sound. - reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the - original message. - allow_sending_without_reply (:obj:`bool`, optional): Pass :obj:`True`, if the message - should be sent even if the specified replied-to message is not found. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): A JSON-serialized - object for a new inline keyboard. If empty, one ‘Play game_title’ button will be - shown. If not empty, the first button must launch the game. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :class:`telegram.Message`: On success, the sent Message is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {'chat_id': chat_id, 'game_short_name': game_short_name} - - return self._message( # type: ignore[return-value] - 'sendGame', - data, - timeout=timeout, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - allow_sending_without_reply=allow_sending_without_reply, - api_kwargs=api_kwargs, - ) - - @log - def send_chat_action( - self, - chat_id: Union[str, int], - action: str, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> bool: - """ - Use this method when you need to tell the user that something is happening on the bot's - side. The status is set for 5 seconds or less (when a message arrives from your bot, - Telegram clients clear its typing status). Telegram only recommends using this method when - a response from the bot will take a noticeable amount of time to arrive. - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target channel (in the format ``@channelusername``). - action(:class:`telegram.ChatAction` | :obj:`str`): Type of action to broadcast. Choose - one, depending on what the user is about to receive. For convenience look at the - constants in :class:`telegram.ChatAction` - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {'chat_id': chat_id, 'action': action} - - result = self._post('sendChatAction', data, timeout=timeout, api_kwargs=api_kwargs) - - return result # type: ignore[return-value] - - def _effective_inline_results( # pylint: disable=R0201 - self, - results: Union[ - Sequence['InlineQueryResult'], Callable[[int], Optional[Sequence['InlineQueryResult']]] - ], - next_offset: str = None, - current_offset: str = None, - ) -> Tuple[Sequence['InlineQueryResult'], Optional[str]]: - """ - Builds the effective results from the results input. - We make this a stand-alone method so tg.ext.ExtBot can wrap it. - - Returns: - Tuple of 1. the effective results and 2. correct the next_offset - - """ - if current_offset is not None and next_offset is not None: - raise ValueError('`current_offset` and `next_offset` are mutually exclusive!') - - if current_offset is not None: - # Convert the string input to integer - if current_offset == '': - current_offset_int = 0 - else: - current_offset_int = int(current_offset) - - # for now set to empty string, stating that there are no more results - # might change later - next_offset = '' - - if callable(results): - callable_output = results(current_offset_int) - if not callable_output: - effective_results: Sequence['InlineQueryResult'] = [] - else: - effective_results = callable_output - # the callback *might* return more results on the next call, so we increment - # the page count - next_offset = str(current_offset_int + 1) - else: - if len(results) > (current_offset_int + 1) * MAX_INLINE_QUERY_RESULTS: - # we expect more results for the next page - next_offset_int = current_offset_int + 1 - next_offset = str(next_offset_int) - effective_results = results[ - current_offset_int - * MAX_INLINE_QUERY_RESULTS : next_offset_int - * MAX_INLINE_QUERY_RESULTS - ] - else: - effective_results = results[current_offset_int * MAX_INLINE_QUERY_RESULTS :] - else: - effective_results = results # type: ignore[assignment] - - return effective_results, next_offset - - @log - def answer_inline_query( - self, - inline_query_id: str, - results: Union[ - Sequence['InlineQueryResult'], Callable[[int], Optional[Sequence['InlineQueryResult']]] - ], - cache_time: int = 300, - is_personal: bool = None, - next_offset: str = None, - switch_pm_text: str = None, - switch_pm_parameter: str = None, - timeout: ODVInput[float] = DEFAULT_NONE, - current_offset: str = None, - api_kwargs: JSONDict = None, - ) -> bool: - """ - Use this method to send answers to an inline query. No more than 50 results per query are - allowed. - - Warning: - In most use cases :attr:`current_offset` should not be passed manually. Instead of - calling this method directly, use the shortcut :meth:`telegram.InlineQuery.answer` with - ``auto_pagination=True``, which will take care of passing the correct value. - - Args: - inline_query_id (:obj:`str`): Unique identifier for the answered query. - results (List[:class:`telegram.InlineQueryResult`] | Callable): A list of results for - the inline query. In case :attr:`current_offset` is passed, ``results`` may also be - a callable that accepts the current page index starting from 0. It must return - either a list of :class:`telegram.InlineQueryResult` instances or :obj:`None` if - there are no more results. - cache_time (:obj:`int`, optional): The maximum amount of time in seconds that the - result of the inline query may be cached on the server. Defaults to ``300``. - is_personal (:obj:`bool`, optional): Pass :obj:`True`, if results may be cached on - the server side only for the user that sent the query. By default, - results may be returned to any user who sends the same query. - next_offset (:obj:`str`, optional): Pass the offset that a client should send in the - next query with the same text to receive more results. Pass an empty string if - there are no more results or if you don't support pagination. Offset length can't - exceed 64 bytes. - switch_pm_text (:obj:`str`, optional): If passed, clients will display a button with - specified text that switches the user to a private chat with the bot and sends the - bot a start message with the parameter ``switch_pm_parameter``. - switch_pm_parameter (:obj:`str`, optional): Deep-linking parameter for the /start - message sent to the bot when user presses the switch button. 1-64 characters, - only A-Z, a-z, 0-9, _ and - are allowed. - current_offset (:obj:`str`, optional): The :attr:`telegram.InlineQuery.offset` of - the inline query to answer. If passed, PTB will automatically take care of - the pagination for you, i.e. pass the correct ``next_offset`` and truncate the - results list/get the results from the callable you passed. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Example: - An inline bot that sends YouTube videos can ask the user to connect the bot to their - YouTube account to adapt search results accordingly. To do this, it displays a - 'Connect your YouTube account' button above the results, or even before showing any. - The user presses the button, switches to a private chat with the bot and, in doing so, - passes a start parameter that instructs the bot to return an oauth link. Once done, the - bot can offer a switch_inline button so that the user can easily return to the chat - where they wanted to use the bot's inline capabilities. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - - @no_type_check - def _set_defaults(res): - # pylint: disable=W0212 - if hasattr(res, 'parse_mode') and res.parse_mode == DEFAULT_NONE: - if self.defaults: - res.parse_mode = self.defaults.parse_mode - else: - res.parse_mode = None - if hasattr(res, 'input_message_content') and res.input_message_content: - if ( - hasattr(res.input_message_content, 'parse_mode') - and res.input_message_content.parse_mode == DEFAULT_NONE - ): - if self.defaults: - res.input_message_content.parse_mode = DefaultValue.get_value( - self.defaults.parse_mode - ) - else: - res.input_message_content.parse_mode = None - if ( - hasattr(res.input_message_content, 'disable_web_page_preview') - and res.input_message_content.disable_web_page_preview == DEFAULT_NONE - ): - if self.defaults: - res.input_message_content.disable_web_page_preview = ( - DefaultValue.get_value(self.defaults.disable_web_page_preview) - ) - else: - res.input_message_content.disable_web_page_preview = None - - effective_results, next_offset = self._effective_inline_results( - results=results, next_offset=next_offset, current_offset=current_offset - ) - - # Apply defaults - for result in effective_results: - _set_defaults(result) - - results_dicts = [res.to_dict() for res in effective_results] - - data: JSONDict = {'inline_query_id': inline_query_id, 'results': results_dicts} - - if cache_time or cache_time == 0: - data['cache_time'] = cache_time - if is_personal: - data['is_personal'] = is_personal - if next_offset is not None: - data['next_offset'] = next_offset - if switch_pm_text: - data['switch_pm_text'] = switch_pm_text - if switch_pm_parameter: - data['switch_pm_parameter'] = switch_pm_parameter - - return self._post( # type: ignore[return-value] - 'answerInlineQuery', - data, - timeout=timeout, - api_kwargs=api_kwargs, - ) - - @log - def get_user_profile_photos( - self, - user_id: Union[str, int], - offset: int = None, - limit: int = 100, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> Optional[UserProfilePhotos]: - """Use this method to get a list of profile pictures for a user. - - Args: - user_id (:obj:`int`): Unique identifier of the target user. - offset (:obj:`int`, optional): Sequential number of the first photo to be returned. - By default, all photos are returned. - limit (:obj:`int`, optional): Limits the number of photos to be retrieved. Values - between 1-100 are accepted. Defaults to ``100``. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :class:`telegram.UserProfilePhotos` - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {'user_id': user_id} - - if offset is not None: - data['offset'] = offset - if limit: - data['limit'] = limit - - result = self._post('getUserProfilePhotos', data, timeout=timeout, api_kwargs=api_kwargs) - - return UserProfilePhotos.de_json(result, self) # type: ignore[return-value, arg-type] - - @log - def get_file( - self, - file_id: Union[ - str, Animation, Audio, ChatPhoto, Document, PhotoSize, Sticker, Video, VideoNote, Voice - ], - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> File: - """ - Use this method to get basic info about a file and prepare it for downloading. For the - moment, bots can download files of up to 20MB in size. The file can then be downloaded - with :meth:`telegram.File.download`. It is guaranteed that the link will be - valid for at least 1 hour. When the link expires, a new one can be requested by - calling get_file again. - - Note: - This function may not preserve the original file name and MIME type. - You should save the file's MIME type and name (if available) when the File object - is received. - - Args: - file_id (:obj:`str` | :class:`telegram.Animation` | :class:`telegram.Audio` | \ - :class:`telegram.ChatPhoto` | :class:`telegram.Document` | \ - :class:`telegram.PhotoSize` | :class:`telegram.Sticker` | \ - :class:`telegram.Video` | :class:`telegram.VideoNote` | \ - :class:`telegram.Voice`): - Either the file identifier or an object that has a file_id attribute - to get file information about. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :class:`telegram.File` - - Raises: - :class:`telegram.error.TelegramError` - - """ - try: - file_id = file_id.file_id # type: ignore[union-attr] - except AttributeError: - pass - - data: JSONDict = {'file_id': file_id} - - result = self._post('getFile', data, timeout=timeout, api_kwargs=api_kwargs) - - if result.get('file_path') and not is_local_file( # type: ignore[union-attr] - result['file_path'] # type: ignore[index] - ): - result['file_path'] = '{}/{}'.format( # type: ignore[index] - self.base_file_url, result['file_path'] # type: ignore[index] - ) - - return File.de_json(result, self) # type: ignore[return-value, arg-type] - - @log - def kick_chat_member( - self, - chat_id: Union[str, int], - user_id: Union[str, int], - timeout: ODVInput[float] = DEFAULT_NONE, - until_date: Union[int, datetime] = None, - api_kwargs: JSONDict = None, - revoke_messages: bool = None, - ) -> bool: - """ - Use this method to kick a user from a group, supergroup or a channel. In the case of - supergroups and channels, the user will not be able to return to the group on their own - using invite links, etc., unless unbanned first. The bot must be an administrator in the - chat for this to work and must have the appropriate admin rights. - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target group or username - of the target supergroup or channel (in the format ``@channelusername``). - user_id (:obj:`int`): Unique identifier of the target user. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - until_date (:obj:`int` | :obj:`datetime.datetime`, optional): Date when the user will - be unbanned, unix time. If user is banned for more than 366 days or less than 30 - seconds from the current time they are considered to be banned forever. Applied - for supergroups and channels only. - For timezone naive :obj:`datetime.datetime` objects, the default timezone of the - bot will be used. - revoke_messages (:obj:`bool`, optional): Pass :obj:`True` to delete all messages from - the chat for the user that is being removed. If :obj:`False`, the user will be able - to see messages in the group that were sent before the user was removed. - Always :obj:`True` for supergroups and channels. - - .. versionadded:: 13.4 - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {'chat_id': chat_id, 'user_id': user_id} - - if until_date is not None: - if isinstance(until_date, datetime): - until_date = to_timestamp( - until_date, tzinfo=self.defaults.tzinfo if self.defaults else None - ) - data['until_date'] = until_date - - if revoke_messages is not None: - data['revoke_messages'] = revoke_messages - - result = self._post('kickChatMember', data, timeout=timeout, api_kwargs=api_kwargs) - - return result # type: ignore[return-value] - - @log - def unban_chat_member( - self, - chat_id: Union[str, int], - user_id: Union[str, int], - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - only_if_banned: bool = None, - ) -> bool: - """Use this method to unban a previously kicked user in a supergroup or channel. - - The user will *not* return to the group or channel automatically, but will be able to join - via link, etc. The bot must be an administrator for this to work. By default, this method - guarantees that after the call the user is not a member of the chat, but will be able to - join it. So if the user is a member of the chat they will also be *removed* from the chat. - If you don't want this, use the parameter :attr:`only_if_banned`. - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target supergroup or channel (in the format ``@channelusername``). - user_id (:obj:`int`): Unique identifier of the target user. - only_if_banned (:obj:`bool`, optional): Do nothing if the user is not banned. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :obj:`bool` On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {'chat_id': chat_id, 'user_id': user_id} - - if only_if_banned is not None: - data['only_if_banned'] = only_if_banned - - result = self._post('unbanChatMember', data, timeout=timeout, api_kwargs=api_kwargs) - - return result # type: ignore[return-value] - - @log - def answer_callback_query( - self, - callback_query_id: str, - text: str = None, - show_alert: bool = False, - url: str = None, - cache_time: int = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> bool: - """ - Use this method to send answers to callback queries sent from inline keyboards. The answer - will be displayed to the user as a notification at the top of the chat screen or as an - alert. - Alternatively, the user can be redirected to the specified Game URL. For this option to - work, you must first create a game for your bot via `@BotFather <https://t.me/BotFather>`_ - and accept the terms. Otherwise, you may use links like t.me/your_bot?start=XXXX that open - your bot with a parameter. - - Args: - callback_query_id (:obj:`str`): Unique identifier for the query to be answered. - text (:obj:`str`, optional): Text of the notification. If not specified, nothing will - be shown to the user, 0-200 characters. - show_alert (:obj:`bool`, optional): If :obj:`True`, an alert will be shown by the - client instead of a notification at the top of the chat screen. Defaults to - :obj:`False`. - url (:obj:`str`, optional): URL that will be opened by the user's client. If you have - created a Game and accepted the conditions via - `@BotFather <https://t.me/BotFather>`_, specify the URL that - opens your game - note that this will only work if the query comes from a callback - game button. Otherwise, you may use links like t.me/your_bot?start=XXXX that open - your bot with a parameter. - cache_time (:obj:`int`, optional): The maximum amount of time in seconds that the - result of the callback query may be cached client-side. Defaults to 0. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :obj:`bool` On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {'callback_query_id': callback_query_id} - - if text: - data['text'] = text - if show_alert: - data['show_alert'] = show_alert - if url: - data['url'] = url - if cache_time is not None: - data['cache_time'] = cache_time - - result = self._post('answerCallbackQuery', data, timeout=timeout, api_kwargs=api_kwargs) - - return result # type: ignore[return-value] - - @log - def edit_message_text( - self, - text: str, - chat_id: Union[str, int] = None, - message_id: int = None, - inline_message_id: int = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, - reply_markup: InlineKeyboardMarkup = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - ) -> Union[Message, bool]: - """ - Use this method to edit text and game messages. - - Args: - chat_id (:obj:`int` | :obj:`str`, optional): Required if inline_message_id is not - specified. Unique identifier for the target chat or username of the target channel - (in the format ``@channelusername``) - message_id (:obj:`int`, optional): Required if inline_message_id is not specified. - Identifier of the message to edit. - inline_message_id (:obj:`str`, optional): Required if chat_id and message_id are not - specified. Identifier of the inline message. - text (:obj:`str`): New text of the message, 1-4096 characters after entities parsing. - parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to - show bold, italic, fixed-width text or inline URLs in your bot's message. See the - constants in :class:`telegram.ParseMode` for the available modes. - entities (List[:class:`telegram.MessageEntity`], optional): List of special entities - that appear in message text, which can be specified instead of :attr:`parse_mode`. - disable_web_page_preview (:obj:`bool`, optional): Disables link previews for links in - this message. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): A JSON-serialized - object for an inline keyboard. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :class:`telegram.Message`: On success, if edited message is not an inline message, the - edited message is returned, otherwise :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - 'text': text, - 'parse_mode': parse_mode, - 'disable_web_page_preview': disable_web_page_preview, - } - - if chat_id: - data['chat_id'] = chat_id - if message_id: - data['message_id'] = message_id - if inline_message_id: - data['inline_message_id'] = inline_message_id - if entities: - data['entities'] = [me.to_dict() for me in entities] - - return self._message( - 'editMessageText', - data, - timeout=timeout, - reply_markup=reply_markup, - api_kwargs=api_kwargs, - ) - - @log - def edit_message_caption( - self, - chat_id: Union[str, int] = None, - message_id: int = None, - inline_message_id: int = None, - caption: str = None, - reply_markup: InlineKeyboardMarkup = None, - timeout: ODVInput[float] = DEFAULT_NONE, - parse_mode: ODVInput[str] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - ) -> Union[Message, bool]: - """ - Use this method to edit captions of messages. - - Args: - chat_id (:obj:`int` | :obj:`str`, optional): Required if inline_message_id is not - specified. Unique identifier for the target chat or username of the target channel - (in the format ``@channelusername``) - message_id (:obj:`int`, optional): Required if inline_message_id is not specified. - Identifier of the message to edit. - inline_message_id (:obj:`str`, optional): Required if chat_id and message_id are not - specified. Identifier of the inline message. - caption (:obj:`str`, optional): New caption of the message, 0-1024 characters after - entities parsing. - parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to - show bold, italic, fixed-width text or inline URLs in the media caption. See the - constants in :class:`telegram.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special - entities that appear in message text, which can be specified instead of - :attr:`parse_mode`. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): A JSON-serialized - object for an inline keyboard. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :class:`telegram.Message`: On success, if edited message is not an inline message, the - edited message is returned, otherwise :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - if inline_message_id is None and (chat_id is None or message_id is None): - raise ValueError( - 'edit_message_caption: Both chat_id and message_id are required when ' - 'inline_message_id is not specified' - ) - - data: JSONDict = {'parse_mode': parse_mode} - - if caption: - data['caption'] = caption - if caption_entities: - data['caption_entities'] = [me.to_dict() for me in caption_entities] - if chat_id: - data['chat_id'] = chat_id - if message_id: - data['message_id'] = message_id - if inline_message_id: - data['inline_message_id'] = inline_message_id - - return self._message( - 'editMessageCaption', - data, - timeout=timeout, - reply_markup=reply_markup, - api_kwargs=api_kwargs, - ) - - @log - def edit_message_media( - self, - chat_id: Union[str, int] = None, - message_id: int = None, - inline_message_id: int = None, - media: 'InputMedia' = None, - reply_markup: InlineKeyboardMarkup = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> Union[Message, bool]: - """ - Use this method to edit animation, audio, document, photo, or video messages. If a message - is part of a message album, then it can be edited only to an audio for audio albums, only - to a document for document albums and to a photo or a video otherwise. When an inline - message is edited, a new file can't be uploaded. Use a previously uploaded file via its - ``file_id`` or specify a URL. - - Args: - chat_id (:obj:`int` | :obj:`str`, optional): Required if inline_message_id is not - specified. Unique identifier for the target chat or username of the target channel - (in the format ``@channelusername``). - message_id (:obj:`int`, optional): Required if inline_message_id is not specified. - Identifier of the message to edit. - inline_message_id (:obj:`str`, optional): Required if chat_id and message_id are not - specified. Identifier of the inline message. - media (:class:`telegram.InputMedia`): An object for a new media content - of the message. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): A JSON-serialized - object for an inline keyboard. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :class:`telegram.Message`: On success, if edited message is sent by the bot, the - edited Message is returned, otherwise :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - """ - if inline_message_id is None and (chat_id is None or message_id is None): - raise ValueError( - 'edit_message_media: Both chat_id and message_id are required when ' - 'inline_message_id is not specified' - ) - - data: JSONDict = {'media': media} - - if chat_id: - data['chat_id'] = chat_id - if message_id: - data['message_id'] = message_id - if inline_message_id: - data['inline_message_id'] = inline_message_id - - return self._message( - 'editMessageMedia', - data, - timeout=timeout, - reply_markup=reply_markup, - api_kwargs=api_kwargs, - ) - - @log - def edit_message_reply_markup( - self, - chat_id: Union[str, int] = None, - message_id: int = None, - inline_message_id: int = None, - reply_markup: Optional['InlineKeyboardMarkup'] = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> Union[Message, bool]: - """ - Use this method to edit only the reply markup of messages sent by the bot or via the bot - (for inline bots). - - Args: - chat_id (:obj:`int` | :obj:`str`, optional): Required if inline_message_id is not - specified. Unique identifier for the target chat or username of the target channel - (in the format ``@channelusername``). - message_id (:obj:`int`, optional): Required if inline_message_id is not specified. - Identifier of the message to edit. - inline_message_id (:obj:`str`, optional): Required if chat_id and message_id are not - specified. Identifier of the inline message. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): A JSON-serialized - object for an inline keyboard. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :class:`telegram.Message`: On success, if edited message is not an inline message, the - edited message is returned, otherwise :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - if inline_message_id is None and (chat_id is None or message_id is None): - raise ValueError( - 'edit_message_reply_markup: Both chat_id and message_id are required when ' - 'inline_message_id is not specified' - ) - - data: JSONDict = {} - - if chat_id: - data['chat_id'] = chat_id - if message_id: - data['message_id'] = message_id - if inline_message_id: - data['inline_message_id'] = inline_message_id - - return self._message( - 'editMessageReplyMarkup', - data, - timeout=timeout, - reply_markup=reply_markup, - api_kwargs=api_kwargs, - ) - - @log - def get_updates( - self, - offset: int = None, - limit: int = 100, - timeout: float = 0, - read_latency: float = 2.0, - allowed_updates: List[str] = None, - api_kwargs: JSONDict = None, - ) -> List[Update]: - """Use this method to receive incoming updates using long polling. - - Args: - offset (:obj:`int`, optional): Identifier of the first update to be returned. Must be - greater by one than the highest among the identifiers of previously received - updates. By default, updates starting with the earliest unconfirmed update are - returned. An update is considered confirmed as soon as getUpdates is called with an - offset higher than its :attr:`telegram.Update.update_id`. The negative offset can - be specified to retrieve updates starting from -offset update from the end of the - updates queue. All previous updates will forgotten. - limit (:obj:`int`, optional): Limits the number of updates to be retrieved. Values - between 1-100 are accepted. Defaults to ``100``. - timeout (:obj:`int`, optional): Timeout in seconds for long polling. Defaults to ``0``, - i.e. usual short polling. Should be positive, short polling should be used for - testing purposes only. - read_latency (:obj:`float` | :obj:`int`, optional): Grace time in seconds for receiving - the reply from server. Will be added to the ``timeout`` value and used as the read - timeout from server. Defaults to ``2``. - allowed_updates (List[:obj:`str`]), optional): A JSON-serialized list the types of - updates you want your bot to receive. For example, specify ["message", - "edited_channel_post", "callback_query"] to only receive updates of these types. - See :class:`telegram.Update` for a complete list of available update types. - Specify an empty list to receive all updates except - :attr:`telegram.Update.chat_member` (default). If not specified, the previous - setting will be used. Please note that this parameter doesn't affect updates - created before the call to the get_updates, so unwanted updates may be received for - a short period of time. - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Note: - 1. This method will not work if an outgoing webhook is set up. - 2. In order to avoid getting duplicate updates, recalculate offset after each - server response. - 3. To take full advantage of this library take a look at :class:`telegram.ext.Updater` - - Returns: - List[:class:`telegram.Update`] - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {'timeout': timeout} - - if offset: - data['offset'] = offset - if limit: - data['limit'] = limit - if allowed_updates is not None: - data['allowed_updates'] = allowed_updates - - # Ideally we'd use an aggressive read timeout for the polling. However, - # * Short polling should return within 2 seconds. - # * Long polling poses a different problem: the connection might have been dropped while - # waiting for the server to return and there's no way of knowing the connection had been - # dropped in real time. - result = cast( - List[JSONDict], - self._post( - 'getUpdates', - data, - timeout=float(read_latency) + float(timeout), - api_kwargs=api_kwargs, - ), - ) - - if result: - self.logger.debug('Getting updates: %s', [u['update_id'] for u in result]) - else: - self.logger.debug('No new updates found.') - - return Update.de_list(result, self) # type: ignore[return-value] - - @log - def set_webhook( - self, - url: str = None, - certificate: FileInput = None, - timeout: ODVInput[float] = DEFAULT_NONE, - max_connections: int = 40, - allowed_updates: List[str] = None, - api_kwargs: JSONDict = None, - ip_address: str = None, - drop_pending_updates: bool = None, - ) -> bool: - """ - Use this method to specify a url and receive incoming updates via an outgoing webhook. - Whenever there is an update for the bot, Telegram will send an HTTPS POST request to the - specified url, containing a JSON-serialized Update. In case of an unsuccessful request, - Telegram will give up after a reasonable amount of attempts. - - If you'd like to make sure that the Webhook request comes from Telegram, Telegram - recommends using a secret path in the URL, e.g. https://www.example.com/<token>. Since - nobody else knows your bot's token, you can be pretty sure it's us. - - Note: - The certificate argument should be a file from disk ``open(filename, 'rb')``. - - Args: - url (:obj:`str`): HTTPS url to send updates to. Use an empty string to remove webhook - integration. - certificate (:obj:`filelike`): Upload your public key certificate so that the root - certificate in use can be checked. See our self-signed guide for details. - (https://goo.gl/rw7w6Y) - ip_address (:obj:`str`, optional): The fixed IP address which will be used to send - webhook requests instead of the IP address resolved through DNS. - max_connections (:obj:`int`, optional): Maximum allowed number of simultaneous HTTPS - connections to the webhook for update delivery, 1-100. Defaults to ``40``. Use - lower values to limit the load on your bot's server, and higher values to increase - your bot's throughput. - allowed_updates (List[:obj:`str`], optional): A JSON-serialized list the types of - updates you want your bot to receive. For example, specify ["message", - "edited_channel_post", "callback_query"] to only receive updates of these types. - See :class:`telegram.Update` for a complete list of available update types. - Specify an empty list to receive all updates except - :attr:`telegram.Update.chat_member` (default). If not specified, the previous - setting will be used. Please note that this parameter doesn't affect updates - created before the call to the set_webhook, so unwanted updates may be received for - a short period of time. - drop_pending_updates (:obj:`bool`, optional): Pass :obj:`True` to drop all pending - updates. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Note: - 1. You will not be able to receive updates using :meth:`get_updates` for long as an - outgoing webhook is set up. - 2. To use a self-signed certificate, you need to upload your public key certificate - using certificate parameter. Please upload as InputFile, sending a String will not - work. - 3. Ports currently supported for Webhooks: ``443``, ``80``, ``88``, ``8443``. - - If you're having any trouble setting up webhooks, please check out this `guide to - Webhooks`_. - - Returns: - :obj:`bool` On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - .. _`guide to Webhooks`: https://core.telegram.org/bots/webhooks - - """ - data: JSONDict = {} - - if url is not None: - data['url'] = url - if certificate: - data['certificate'] = parse_file_input(certificate) - if max_connections is not None: - data['max_connections'] = max_connections - if allowed_updates is not None: - data['allowed_updates'] = allowed_updates - if ip_address: - data['ip_address'] = ip_address - if drop_pending_updates: - data['drop_pending_updates'] = drop_pending_updates - - result = self._post('setWebhook', data, timeout=timeout, api_kwargs=api_kwargs) - - return result # type: ignore[return-value] - - @log - def delete_webhook( - self, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - drop_pending_updates: bool = None, - ) -> bool: - """ - Use this method to remove webhook integration if you decide to switch back to - :meth:`get_updates()`. - - Args: - drop_pending_updates (:obj:`bool`, optional): Pass :obj:`True` to drop all pending - updates. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data = {} - - if drop_pending_updates: - data['drop_pending_updates'] = drop_pending_updates - - result = self._post('deleteWebhook', data, timeout=timeout, api_kwargs=api_kwargs) - - return result # type: ignore[return-value] - - @log - def leave_chat( - self, - chat_id: Union[str, int], - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> bool: - """Use this method for your bot to leave a group, supergroup or channel. - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target supergroup or channel (in the format ``@channelusername``). - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {'chat_id': chat_id} - - result = self._post('leaveChat', data, timeout=timeout, api_kwargs=api_kwargs) - - return result # type: ignore[return-value] - - @log - def get_chat( - self, - chat_id: Union[str, int], - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> Chat: - """ - Use this method to get up to date information about the chat (current name of the user for - one-on-one conversations, current username of a user, group or channel, etc.). - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target supergroup or channel (in the format ``@channelusername``). - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :class:`telegram.Chat` - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {'chat_id': chat_id} - - result = self._post('getChat', data, timeout=timeout, api_kwargs=api_kwargs) - - return Chat.de_json(result, self) # type: ignore[return-value, arg-type] - - @log - def get_chat_administrators( - self, - chat_id: Union[str, int], - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> List[ChatMember]: - """ - Use this method to get a list of administrators in a chat. - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target supergroup or channel (in the format ``@channelusername``). - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - List[:class:`telegram.ChatMember`]: On success, returns a list of ``ChatMember`` - objects that contains information about all chat administrators except - other bots. If the chat is a group or a supergroup and no administrators were - appointed, only the creator will be returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {'chat_id': chat_id} - - result = self._post('getChatAdministrators', data, timeout=timeout, api_kwargs=api_kwargs) - - return ChatMember.de_list(result, self) # type: ignore - - @log - def get_chat_members_count( - self, - chat_id: Union[str, int], - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> int: - """Use this method to get the number of members in a chat. - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target supergroup or channel (in the format ``@channelusername``). - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :obj:`int`: Number of members in the chat. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {'chat_id': chat_id} - - result = self._post('getChatMembersCount', data, timeout=timeout, api_kwargs=api_kwargs) - - return result # type: ignore[return-value] - - @log - def get_chat_member( - self, - chat_id: Union[str, int], - user_id: Union[str, int], - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> ChatMember: - """Use this method to get information about a member of a chat. - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target supergroup or channel (in the format ``@channelusername``). - user_id (:obj:`int`): Unique identifier of the target user. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :class:`telegram.ChatMember` - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {'chat_id': chat_id, 'user_id': user_id} - - result = self._post('getChatMember', data, timeout=timeout, api_kwargs=api_kwargs) - - return ChatMember.de_json(result, self) # type: ignore[return-value, arg-type] - - @log - def set_chat_sticker_set( - self, - chat_id: Union[str, int], - sticker_set_name: str, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> bool: - """Use this method to set a new group sticker set for a supergroup. - The bot must be an administrator in the chat for this to work and must have the appropriate - admin rights. Use the field :attr:`telegram.Chat.can_set_sticker_set` optionally returned - in :meth:`get_chat` requests to check if the bot can use this method. - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target supergroup (in the format @supergroupusername). - sticker_set_name (:obj:`str`): Name of the sticker set to be set as the group - sticker set. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - """ - data: JSONDict = {'chat_id': chat_id, 'sticker_set_name': sticker_set_name} - - result = self._post('setChatStickerSet', data, timeout=timeout, api_kwargs=api_kwargs) - - return result # type: ignore[return-value] - - @log - def delete_chat_sticker_set( - self, - chat_id: Union[str, int], - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> bool: - """Use this method to delete a group sticker set from a supergroup. The bot must be an - administrator in the chat for this to work and must have the appropriate admin rights. - Use the field :attr:`telegram.Chat.can_set_sticker_set` optionally returned in - :meth:`get_chat` requests to check if the bot can use this method. - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target supergroup (in the format @supergroupusername). - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - """ - data: JSONDict = {'chat_id': chat_id} - - result = self._post('deleteChatStickerSet', data, timeout=timeout, api_kwargs=api_kwargs) - - return result # type: ignore[return-value] - - def get_webhook_info( - self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None - ) -> WebhookInfo: - """Use this method to get current webhook status. Requires no parameters. - - If the bot is using :meth:`get_updates`, will return an object with the - :attr:`telegram.WebhookInfo.url` field empty. - - Args: - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :class:`telegram.WebhookInfo` - - """ - result = self._post('getWebhookInfo', None, timeout=timeout, api_kwargs=api_kwargs) - - return WebhookInfo.de_json(result, self) # type: ignore[return-value, arg-type] - - @log - def set_game_score( - self, - user_id: Union[int, str], - score: int, - chat_id: Union[str, int] = None, - message_id: int = None, - inline_message_id: int = None, - force: bool = None, - disable_edit_message: bool = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> Union[Message, bool]: - """ - Use this method to set the score of the specified user in a game. - - Args: - user_id (:obj:`int`): User identifier. - score (:obj:`int`): New score, must be non-negative. - force (:obj:`bool`, optional): Pass :obj:`True`, if the high score is allowed to - decrease. This can be useful when fixing mistakes or banning cheaters. - disable_edit_message (:obj:`bool`, optional): Pass :obj:`True`, if the game message - should not be automatically edited to include the current scoreboard. - chat_id (:obj:`int` | :obj:`str`, optional): Required if inline_message_id is not - specified. Unique identifier for the target chat. - message_id (:obj:`int`, optional): Required if inline_message_id is not specified. - Identifier of the sent message. - inline_message_id (:obj:`str`, optional): Required if chat_id and message_id are not - specified. Identifier of the inline message. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :class:`telegram.Message`: The edited message, or if the message wasn't sent by the bot - , :obj:`True`. - - Raises: - :class:`telegram.error.TelegramError`: If the new score is not greater than the user's - current score in the chat and force is :obj:`False`. - - """ - data: JSONDict = {'user_id': user_id, 'score': score} - - if chat_id: - data['chat_id'] = chat_id - if message_id: - data['message_id'] = message_id - if inline_message_id: - data['inline_message_id'] = inline_message_id - if force is not None: - data['force'] = force - if disable_edit_message is not None: - data['disable_edit_message'] = disable_edit_message - - return self._message( - 'setGameScore', - data, - timeout=timeout, - api_kwargs=api_kwargs, - ) - - @log - def get_game_high_scores( - self, - user_id: Union[int, str], - chat_id: Union[str, int] = None, - message_id: int = None, - inline_message_id: int = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> List[GameHighScore]: - """ - Use this method to get data for high score tables. Will return the score of the specified - user and several of their neighbors in a game. - - Note: - This method will currently return scores for the target user, plus two of their - closest neighbors on each side. Will also return the top three users if the user and - his neighbors are not among them. Please note that this behavior is subject to change. - - Args: - user_id (:obj:`int`): Target user id. - chat_id (:obj:`int` | :obj:`str`, optional): Required if inline_message_id is not - specified. Unique identifier for the target chat. - message_id (:obj:`int`, optional): Required if inline_message_id is not specified. - Identifier of the sent message. - inline_message_id (:obj:`str`, optional): Required if chat_id and message_id are not - specified. Identifier of the inline message. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - List[:class:`telegram.GameHighScore`] - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {'user_id': user_id} - - if chat_id: - data['chat_id'] = chat_id - if message_id: - data['message_id'] = message_id - if inline_message_id: - data['inline_message_id'] = inline_message_id - - result = self._post('getGameHighScores', data, timeout=timeout, api_kwargs=api_kwargs) - - return GameHighScore.de_list(result, self) # type: ignore - - @log - def send_invoice( - self, - chat_id: Union[int, str], - title: str, - description: str, - payload: str, - provider_token: str, - currency: str, - prices: List['LabeledPrice'], - start_parameter: str = None, - photo_url: str = None, - photo_size: int = None, - photo_width: int = None, - photo_height: int = None, - need_name: bool = None, - need_phone_number: bool = None, - need_email: bool = None, - need_shipping_address: bool = None, - is_flexible: bool = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: InlineKeyboardMarkup = None, - provider_data: Union[str, object] = None, - send_phone_number_to_provider: bool = None, - send_email_to_provider: bool = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - max_tip_amount: int = None, - suggested_tip_amounts: List[int] = None, - ) -> Message: - """Use this method to send invoices. - - Warning: - As of API 5.2 :attr:`start_parameter` is an optional argument and therefore the order - of the arguments had to be changed. Use keyword arguments to make sure that the - arguments are passed correctly. - - .. versionchanged:: 13.5 - As of Bot API 5.2, the parameter :attr:`start_parameter` is optional. - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target channel (in the format ``@channelusername``). - title (:obj:`str`): Product name, 1-32 characters. - description (:obj:`str`): Product description, 1-255 characters. - payload (:obj:`str`): Bot-defined invoice payload, 1-128 bytes. This will not be - displayed to the user, use for your internal processes. - provider_token (:obj:`str`): Payments provider token, obtained via - `@BotFather <https://t.me/BotFather>`_. - currency (:obj:`str`): Three-letter ISO 4217 currency code. - prices (List[:class:`telegram.LabeledPrice`)]: Price breakdown, a JSON-serialized list - of components (e.g. product price, tax, discount, delivery cost, delivery tax, - bonus, etc.). - max_tip_amount (:obj:`int`, optional): The maximum accepted amount for tips in the - smallest units of the currency (integer, not float/double). For example, for a - maximum tip of US$ 1.45 pass ``max_tip_amount = 145``. See the exp parameter in - `currencies.json <https://core.telegram.org/bots/payments/currencies.json>`_, it - shows the number of digits past the decimal point for each currency (2 for the - majority of currencies). Defaults to ``0``. - - .. versionadded:: 13.5 - suggested_tip_amounts (List[:obj:`int`], optional): A JSON-serialized array of - suggested amounts of tips in the smallest units of the currency (integer, not - float/double). At most 4 suggested tip amounts can be specified. The suggested tip - amounts must be positive, passed in a strictly increased order and must not exceed - ``max_tip_amount``. - - .. versionadded:: 13.5 - start_parameter (:obj:`str`, optional): Unique deep-linking parameter. If left empty, - *forwarded copies* of the sent message will have a *Pay* button, allowing - multiple users to pay directly from the forwarded message, using the same invoice. - If non-empty, forwarded copies of the sent message will have a *URL* button with a - deep link to the bot (instead of a *Pay* button), with the value used as the - start parameter. - - .. versionchanged:: 13.5 - As of Bot API 5.2, this parameter is optional. - provider_data (:obj:`str` | :obj:`object`, optional): JSON-serialized data about the - invoice, which will be shared with the payment provider. A detailed description of - required fields should be provided by the payment provider. When an object is - passed, it will be encoded as JSON. - photo_url (:obj:`str`, optional): URL of the product photo for the invoice. Can be a - photo of the goods or a marketing image for a service. People like it better when - they see what they are paying for. - photo_size (:obj:`str`, optional): Photo size. - photo_width (:obj:`int`, optional): Photo width. - photo_height (:obj:`int`, optional): Photo height. - need_name (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's full - name to complete the order. - need_phone_number (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's - phone number to complete the order. - need_email (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's email - to complete the order. - need_shipping_address (:obj:`bool`, optional): Pass :obj:`True`, if you require the - user's shipping address to complete the order. - send_phone_number_to_provider (:obj:`bool`, optional): Pass :obj:`True`, if user's - phone number should be sent to provider. - send_email_to_provider (:obj:`bool`, optional): Pass :obj:`True`, if user's email - address should be sent to provider. - is_flexible (:obj:`bool`, optional): Pass :obj:`True`, if the final price depends on - the shipping method. - disable_notification (:obj:`bool`, optional): Sends the message silently. Users will - receive a notification with no sound. - reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the - original message. - allow_sending_without_reply (:obj:`bool`, optional): Pass :obj:`True`, if the message - should be sent even if the specified replied-to message is not found. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): A JSON-serialized - object for an inline keyboard. If empty, one 'Pay total price' button will be - shown. If not empty, the first button must be a Pay button. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :class:`telegram.Message`: On success, the sent Message is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - 'chat_id': chat_id, - 'title': title, - 'description': description, - 'payload': payload, - 'provider_token': provider_token, - 'currency': currency, - 'prices': [p.to_dict() for p in prices], - } - if max_tip_amount is not None: - data['max_tip_amount'] = max_tip_amount - if suggested_tip_amounts is not None: - data['suggested_tip_amounts'] = suggested_tip_amounts - if start_parameter is not None: - data['start_parameter'] = start_parameter - if provider_data is not None: - if isinstance(provider_data, str): - data['provider_data'] = provider_data - else: - data['provider_data'] = json.dumps(provider_data) - if photo_url is not None: - data['photo_url'] = photo_url - if photo_size is not None: - data['photo_size'] = photo_size - if photo_width is not None: - data['photo_width'] = photo_width - if photo_height is not None: - data['photo_height'] = photo_height - if need_name is not None: - data['need_name'] = need_name - if need_phone_number is not None: - data['need_phone_number'] = need_phone_number - if need_email is not None: - data['need_email'] = need_email - if need_shipping_address is not None: - data['need_shipping_address'] = need_shipping_address - if is_flexible is not None: - data['is_flexible'] = is_flexible - if send_phone_number_to_provider is not None: - data['send_phone_number_to_provider'] = send_phone_number_to_provider - if send_email_to_provider is not None: - data['send_email_to_provider'] = send_email_to_provider - - return self._message( # type: ignore[return-value] - 'sendInvoice', - data, - timeout=timeout, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - allow_sending_without_reply=allow_sending_without_reply, - api_kwargs=api_kwargs, - ) - - @log - def answer_shipping_query( # pylint: disable=C0103 - self, - shipping_query_id: str, - ok: bool, - shipping_options: List[ShippingOption] = None, - error_message: str = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> bool: - """ - If you sent an invoice requesting a shipping address and the parameter ``is_flexible`` was - specified, the Bot API will send an :class:`telegram.Update` with a - :attr:`Update.shipping_query` field to the bot. Use this method to reply to shipping - queries. - - Args: - shipping_query_id (:obj:`str`): Unique identifier for the query to be answered. - ok (:obj:`bool`): Specify :obj:`True` if delivery to the specified address is possible - and :obj:`False` if there are any problems (for example, if delivery to the - specified address is not possible). - shipping_options (List[:class:`telegram.ShippingOption`]), optional]: Required if ok is - :obj:`True`. A JSON-serialized array of available shipping options. - error_message (:obj:`str`, optional): Required if ok is :obj:`False`. Error message in - human readable form that explains why it is impossible to complete the order (e.g. - "Sorry, delivery to your desired address is unavailable"). Telegram will display - this message to the user. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - ok = bool(ok) - - if ok and (shipping_options is None or error_message is not None): - raise TelegramError( - 'answerShippingQuery: If ok is True, shipping_options ' - 'should not be empty and there should not be error_message' - ) - - if not ok and (shipping_options is not None or error_message is None): - raise TelegramError( - 'answerShippingQuery: If ok is False, error_message ' - 'should not be empty and there should not be shipping_options' - ) - - data: JSONDict = {'shipping_query_id': shipping_query_id, 'ok': ok} - - if ok: - if not shipping_options: - # not using an assert statement directly here since they are removed in - # the optimized bytecode - raise AssertionError - data['shipping_options'] = [option.to_dict() for option in shipping_options] - if error_message is not None: - data['error_message'] = error_message - - result = self._post('answerShippingQuery', data, timeout=timeout, api_kwargs=api_kwargs) - - return result # type: ignore[return-value] - - @log - def answer_pre_checkout_query( # pylint: disable=C0103 - self, - pre_checkout_query_id: str, - ok: bool, - error_message: str = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> bool: - """ - Once the user has confirmed their payment and shipping details, the Bot API sends the final - confirmation in the form of an :class:`telegram.Update` with the field - :attr:`Update.pre_checkout_query`. Use this method to respond to such pre-checkout queries. - - Note: - The Bot API must receive an answer within 10 seconds after the pre-checkout - query was sent. - - Args: - pre_checkout_query_id (:obj:`str`): Unique identifier for the query to be answered. - ok (:obj:`bool`): Specify :obj:`True` if everything is alright - (goods are available, etc.) and the bot is ready to proceed with the order. Use - :obj:`False` if there are any problems. - error_message (:obj:`str`, optional): Required if ok is :obj:`False`. Error message - in human readable form that explains the reason for failure to proceed with - the checkout (e.g. "Sorry, somebody just bought the last of our amazing black - T-shirts while you were busy filling out your payment details. Please choose a - different color or garment!"). Telegram will display this message to the user. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - ok = bool(ok) - - if not (ok ^ (error_message is not None)): # pylint: disable=C0325 - raise TelegramError( - 'answerPreCheckoutQuery: If ok is True, there should ' - 'not be error_message; if ok is False, error_message ' - 'should not be empty' - ) - - data: JSONDict = {'pre_checkout_query_id': pre_checkout_query_id, 'ok': ok} - - if error_message is not None: - data['error_message'] = error_message - - result = self._post('answerPreCheckoutQuery', data, timeout=timeout, api_kwargs=api_kwargs) - - return result # type: ignore[return-value] - - @log - def restrict_chat_member( - self, - chat_id: Union[str, int], - user_id: Union[str, int], - permissions: ChatPermissions, - until_date: Union[int, datetime] = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> bool: - """ - Use this method to restrict a user in a supergroup. The bot must be an administrator in - the supergroup for this to work and must have the appropriate admin rights. Pass - :obj:`True` for all boolean parameters to lift restrictions from a user. - - Note: - Since Bot API 4.4, :meth:`restrict_chat_member` takes the new user permissions in a - single argument of type :class:`telegram.ChatPermissions`. The old way of passing - parameters will not keep working forever. - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target supergroup (in the format @supergroupusername). - user_id (:obj:`int`): Unique identifier of the target user. - until_date (:obj:`int` | :obj:`datetime.datetime`, optional): Date when restrictions - will be lifted for the user, unix time. If user is restricted for more than 366 - days or less than 30 seconds from the current time, they are considered to be - restricted forever. - For timezone naive :obj:`datetime.datetime` objects, the default timezone of the - bot will be used. - permissions (:class:`telegram.ChatPermissions`): A JSON-serialized object for new user - permissions. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - """ - data: JSONDict = { - 'chat_id': chat_id, - 'user_id': user_id, - 'permissions': permissions.to_dict(), - } - - if until_date is not None: - if isinstance(until_date, datetime): - until_date = to_timestamp( - until_date, tzinfo=self.defaults.tzinfo if self.defaults else None - ) - data['until_date'] = until_date - - result = self._post('restrictChatMember', data, timeout=timeout, api_kwargs=api_kwargs) - - return result # type: ignore[return-value] - - @log - def promote_chat_member( - self, - chat_id: Union[str, int], - user_id: Union[str, int], - can_change_info: bool = None, - can_post_messages: bool = None, - can_edit_messages: bool = None, - can_delete_messages: bool = None, - can_invite_users: bool = None, - can_restrict_members: bool = None, - can_pin_messages: bool = None, - can_promote_members: bool = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - is_anonymous: bool = None, - can_manage_chat: bool = None, - can_manage_voice_chats: bool = None, - ) -> bool: - """ - Use this method to promote or demote a user in a supergroup or a channel. The bot must be - an administrator in the chat for this to work and must have the appropriate admin rights. - Pass :obj:`False` for all boolean parameters to demote a user. - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target channel (in the format ``@channelusername``). - user_id (:obj:`int`): Unique identifier of the target user. - is_anonymous (:obj:`bool`, optional): Pass :obj:`True`, if the administrator's presence - in the chat is hidden. - can_manage_chat (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can - access the chat event log, chat statistics, message statistics in channels, see - channel members, see anonymous administrators in supergroups and ignore slow mode. - Implied by any other administrator privilege. - - .. versionadded:: 13.4 - - can_manage_voice_chats (:obj:`bool`, optional): Pass :obj:`True`, if the administrator - can manage voice chats. - - .. versionadded:: 13.4 - - can_change_info (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can - change chat title, photo and other settings. - can_post_messages (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can - create channel posts, channels only. - can_edit_messages (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can - edit messages of other users and can pin messages, channels only. - can_delete_messages (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can - delete messages of other users. - can_invite_users (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can - invite new users to the chat. - can_restrict_members (:obj:`bool`, optional): Pass :obj:`True`, if the administrator - can restrict, ban or unban chat members. - can_pin_messages (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can - pin messages, supergroups only. - can_promote_members (:obj:`bool`, optional): Pass :obj:`True`, if the administrator can - add new administrators with a subset of his own privileges or demote administrators - that he has promoted, directly or indirectly (promoted by administrators that were - appointed by him). - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {'chat_id': chat_id, 'user_id': user_id} - - if is_anonymous is not None: - data['is_anonymous'] = is_anonymous - if can_change_info is not None: - data['can_change_info'] = can_change_info - if can_post_messages is not None: - data['can_post_messages'] = can_post_messages - if can_edit_messages is not None: - data['can_edit_messages'] = can_edit_messages - if can_delete_messages is not None: - data['can_delete_messages'] = can_delete_messages - if can_invite_users is not None: - data['can_invite_users'] = can_invite_users - if can_restrict_members is not None: - data['can_restrict_members'] = can_restrict_members - if can_pin_messages is not None: - data['can_pin_messages'] = can_pin_messages - if can_promote_members is not None: - data['can_promote_members'] = can_promote_members - if can_manage_chat is not None: - data['can_manage_chat'] = can_manage_chat - if can_manage_voice_chats is not None: - data['can_manage_voice_chats'] = can_manage_voice_chats - - result = self._post('promoteChatMember', data, timeout=timeout, api_kwargs=api_kwargs) - - return result # type: ignore[return-value] - - @log - def set_chat_permissions( - self, - chat_id: Union[str, int], - permissions: ChatPermissions, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> bool: - """ - Use this method to set default chat permissions for all members. The bot must be an - administrator in the group or a supergroup for this to work and must have the - :attr:`telegram.ChatMember.can_restrict_members` admin rights. - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username of - the target supergroup (in the format `@supergroupusername`). - permissions (:class:`telegram.ChatPermissions`): New default chat permissions. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {'chat_id': chat_id, 'permissions': permissions.to_dict()} - - result = self._post('setChatPermissions', data, timeout=timeout, api_kwargs=api_kwargs) - - return result # type: ignore[return-value] - - @log - def set_chat_administrator_custom_title( - self, - chat_id: Union[int, str], - user_id: Union[int, str], - custom_title: str, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> bool: - """ - Use this method to set a custom title for administrators promoted by the bot in a - supergroup. The bot must be an administrator for this to work. - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username of - the target supergroup (in the format `@supergroupusername`). - user_id (:obj:`int`): Unique identifier of the target administrator. - custom_title (:obj:`str`): New custom title for the administrator; 0-16 characters, - emoji are not allowed. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {'chat_id': chat_id, 'user_id': user_id, 'custom_title': custom_title} - - result = self._post( - 'setChatAdministratorCustomTitle', data, timeout=timeout, api_kwargs=api_kwargs - ) - - return result # type: ignore[return-value] - - @log - def export_chat_invite_link( - self, - chat_id: Union[str, int], - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> str: - """ - Use this method to generate a new primary invite link for a chat; any previously generated - link is revoked. The bot must be an administrator in the chat for this to work and must - have the appropriate admin rights. - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target channel (in the format ``@channelusername``). - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Note: - Each administrator in a chat generates their own invite links. Bots can't use invite - links generated by other administrators. If you want your bot to work with invite - links, it will need to generate its own link using :meth:`export_chat_invite_link` or - by calling the :meth:`get_chat` method. If your bot needs to generate a new primary - invite link replacing its previous one, use :attr:`export_chat_invite_link` again. - - Returns: - :obj:`str`: New invite link on success. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {'chat_id': chat_id} - - result = self._post('exportChatInviteLink', data, timeout=timeout, api_kwargs=api_kwargs) - - return result # type: ignore[return-value] - - @log - def create_chat_invite_link( - self, - chat_id: Union[str, int], - expire_date: Union[int, datetime] = None, - member_limit: int = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> ChatInviteLink: - """ - Use this method to create an additional invite link for a chat. The bot must be an - administrator in the chat for this to work and must have the appropriate admin rights. - The link can be revoked using the method :meth:`revoke_chat_invite_link`. - - .. versionadded:: 13.4 - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target channel (in the format ``@channelusername``). - expire_date (:obj:`int` | :obj:`datetime.datetime`, optional): Date when the link will - expire. Integer input will be interpreted as Unix timestamp. - For timezone naive :obj:`datetime.datetime` objects, the default timezone of the - bot will be used. - member_limit (:obj:`int`, optional): Maximum number of users that can be members of - the chat simultaneously after joining the chat via this invite link; 1-99999. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :class:`telegram.ChatInviteLink` - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - 'chat_id': chat_id, - } - - if expire_date is not None: - if isinstance(expire_date, datetime): - expire_date = to_timestamp( - expire_date, tzinfo=self.defaults.tzinfo if self.defaults else None - ) - data['expire_date'] = expire_date - - if member_limit is not None: - data['member_limit'] = member_limit - - result = self._post('createChatInviteLink', data, timeout=timeout, api_kwargs=api_kwargs) - - return ChatInviteLink.de_json(result, self) # type: ignore[return-value, arg-type] - - @log - def edit_chat_invite_link( - self, - chat_id: Union[str, int], - invite_link: str, - expire_date: Union[int, datetime] = None, - member_limit: int = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> ChatInviteLink: - """ - Use this method to edit a non-primary invite link created by the bot. The bot must be an - administrator in the chat for this to work and must have the appropriate admin rights. - - .. versionadded:: 13.4 - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target channel (in the format ``@channelusername``). - invite_link (:obj:`str`): The invite link to edit. - expire_date (:obj:`int` | :obj:`datetime.datetime`, optional): Date when the link will - expire. - For timezone naive :obj:`datetime.datetime` objects, the default timezone of the - bot will be used. - member_limit (:obj:`int`, optional): Maximum number of users that can be members of - the chat simultaneously after joining the chat via this invite link; 1-99999. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :class:`telegram.ChatInviteLink` - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {'chat_id': chat_id, 'invite_link': invite_link} - - if expire_date is not None: - if isinstance(expire_date, datetime): - expire_date = to_timestamp( - expire_date, tzinfo=self.defaults.tzinfo if self.defaults else None - ) - data['expire_date'] = expire_date - - if member_limit is not None: - data['member_limit'] = member_limit - - result = self._post('editChatInviteLink', data, timeout=timeout, api_kwargs=api_kwargs) - - return ChatInviteLink.de_json(result, self) # type: ignore[return-value, arg-type] - - @log - def revoke_chat_invite_link( - self, - chat_id: Union[str, int], - invite_link: str, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> ChatInviteLink: - """ - Use this method to revoke an invite link created by the bot. If the primary link is - revoked, a new link is automatically generated. The bot must be an administrator in the - chat for this to work and must have the appropriate admin rights. - - .. versionadded:: 13.4 - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target channel (in the format ``@channelusername``). - invite_link (:obj:`str`): The invite link to edit. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :class:`telegram.ChatInviteLink` - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {'chat_id': chat_id, 'invite_link': invite_link} - - result = self._post('revokeChatInviteLink', data, timeout=timeout, api_kwargs=api_kwargs) - - return ChatInviteLink.de_json(result, self) # type: ignore[return-value, arg-type] - - @log - def set_chat_photo( - self, - chat_id: Union[str, int], - photo: FileInput, - timeout: DVInput[float] = DEFAULT_20, - api_kwargs: JSONDict = None, - ) -> bool: - """Use this method to set a new profile photo for the chat. - - Photos can't be changed for private chats. The bot must be an administrator in the chat - for this to work and must have the appropriate admin rights. - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target channel (in the format ``@channelusername``). - photo (`filelike object` | :obj:`bytes` | :class:`pathlib.Path`): New chat photo. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {'chat_id': chat_id, 'photo': parse_file_input(photo)} - - result = self._post('setChatPhoto', data, timeout=timeout, api_kwargs=api_kwargs) - - return result # type: ignore[return-value] - - @log - def delete_chat_photo( - self, - chat_id: Union[str, int], - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> bool: - """ - Use this method to delete a chat photo. Photos can't be changed for private chats. The bot - must be an administrator in the chat for this to work and must have the appropriate admin - rights. - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target channel (in the format ``@channelusername``). - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {'chat_id': chat_id} - - result = self._post('deleteChatPhoto', data, timeout=timeout, api_kwargs=api_kwargs) - - return result # type: ignore[return-value] - - @log - def set_chat_title( - self, - chat_id: Union[str, int], - title: str, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> bool: - """ - Use this method to change the title of a chat. Titles can't be changed for private chats. - The bot must be an administrator in the chat for this to work and must have the appropriate - admin rights. - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target channel (in the format ``@channelusername``). - title (:obj:`str`): New chat title, 1-255 characters. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {'chat_id': chat_id, 'title': title} - - result = self._post('setChatTitle', data, timeout=timeout, api_kwargs=api_kwargs) - - return result # type: ignore[return-value] - - @log - def set_chat_description( - self, - chat_id: Union[str, int], - description: str, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> bool: - """ - Use this method to change the description of a group, a supergroup or a channel. The bot - must be an administrator in the chat for this to work and must have the appropriate admin - rights. - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target channel (in the format ``@channelusername``). - description (:obj:`str`): New chat description, 0-255 characters. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {'chat_id': chat_id, 'description': description} - - result = self._post('setChatDescription', data, timeout=timeout, api_kwargs=api_kwargs) - - return result # type: ignore[return-value] - - @log - def pin_chat_message( - self, - chat_id: Union[str, int], - message_id: int, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> bool: - """ - Use this method to add a message to the list of pinned messages in a chat. If the - chat is not a private chat, the bot must be an administrator in the chat for this to work - and must have the :attr:`telegram.ChatMember.can_pin_messages` admin right in a supergroup - or :attr:`telegram.ChatMember.can_edit_messages` admin right in a channel. - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target channel (in the format ``@channelusername``). - message_id (:obj:`int`): Identifier of a message to pin. - disable_notification (:obj:`bool`, optional): Pass :obj:`True`, if it is not necessary - to send a notification to all chat members about the new pinned message. - Notifications are always disabled in channels and private chats. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - 'chat_id': chat_id, - 'message_id': message_id, - 'disable_notification': disable_notification, - } - - return self._post( # type: ignore[return-value] - 'pinChatMessage', data, timeout=timeout, api_kwargs=api_kwargs - ) - - @log - def unpin_chat_message( - self, - chat_id: Union[str, int], - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - message_id: int = None, - ) -> bool: - """ - Use this method to remove a message from the list of pinned messages in a chat. If the - chat is not a private chat, the bot must be an administrator in the chat for this to work - and must have the :attr:`telegram.ChatMember.can_pin_messages` admin right in a - supergroup or :attr:`telegram.ChatMember.can_edit_messages` admin right in a channel. - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target channel (in the format ``@channelusername``). - message_id (:obj:`int`, optional): Identifier of a message to unpin. If not specified, - the most recent pinned message (by sending date) will be unpinned. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {'chat_id': chat_id} - - if message_id is not None: - data['message_id'] = message_id - - return self._post( # type: ignore[return-value] - 'unpinChatMessage', data, timeout=timeout, api_kwargs=api_kwargs - ) - - @log - def unpin_all_chat_messages( - self, - chat_id: Union[str, int], - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> bool: - """ - Use this method to clear the list of pinned messages in a chat. If the - chat is not a private chat, the bot must be an administrator in the chat for this - to work and must have the :attr:`telegram.ChatMember.can_pin_messages` admin right in a - supergroup or :attr:`telegram.ChatMember.can_edit_messages` admin right in a channel. - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target channel (in the format ``@channelusername``). - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {'chat_id': chat_id} - - return self._post( # type: ignore[return-value] - 'unpinAllChatMessages', data, timeout=timeout, api_kwargs=api_kwargs - ) - - @log - def get_sticker_set( - self, - name: str, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> StickerSet: - """Use this method to get a sticker set. - - Args: - name (:obj:`str`): Name of the sticker set. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during - creation of the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :class:`telegram.StickerSet` - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {'name': name} - - result = self._post('getStickerSet', data, timeout=timeout, api_kwargs=api_kwargs) - - return StickerSet.de_json(result, self) # type: ignore[return-value, arg-type] - - @log - def upload_sticker_file( - self, - user_id: Union[str, int], - png_sticker: FileInput, - timeout: DVInput[float] = DEFAULT_20, - api_kwargs: JSONDict = None, - ) -> File: - """ - Use this method to upload a .png file with a sticker for later use in - :meth:`create_new_sticker_set` and :meth:`add_sticker_to_set` methods (can be used multiple - times). - - Note: - The png_sticker argument can be either a file_id, an URL or a file from disk - ``open(filename, 'rb')`` - - Args: - user_id (:obj:`int`): User identifier of sticker file owner. - png_sticker (:obj:`str` | `filelike object` | :obj:`bytes` | :class:`pathlib.Path`): - Png image with the sticker, - must be up to 512 kilobytes in size, dimensions must not exceed 512px, - and either width or height must be exactly 512px. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during - creation of the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :class:`telegram.File`: On success, the uploaded File is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {'user_id': user_id, 'png_sticker': parse_file_input(png_sticker)} - - result = self._post('uploadStickerFile', data, timeout=timeout, api_kwargs=api_kwargs) - - return File.de_json(result, self) # type: ignore[return-value, arg-type] - - @log - def create_new_sticker_set( - self, - user_id: Union[str, int], - name: str, - title: str, - emojis: str, - png_sticker: FileInput = None, - contains_masks: bool = None, - mask_position: MaskPosition = None, - timeout: DVInput[float] = DEFAULT_20, - tgs_sticker: FileInput = None, - api_kwargs: JSONDict = None, - ) -> bool: - """ - Use this method to create new sticker set owned by a user. - The bot will be able to edit the created sticker set. - You must use exactly one of the fields ``png_sticker`` or ``tgs_sticker``. - - Warning: - As of API 4.7 ``png_sticker`` is an optional argument and therefore the order of the - arguments had to be changed. Use keyword arguments to make sure that the arguments are - passed correctly. - - Note: - The png_sticker and tgs_sticker argument can be either a file_id, an URL or a file from - disk ``open(filename, 'rb')`` - - Args: - user_id (:obj:`int`): User identifier of created sticker set owner. - name (:obj:`str`): Short name of sticker set, to be used in t.me/addstickers/ URLs - (e.g., animals). Can contain only english letters, digits and underscores. - Must begin with a letter, can't contain consecutive underscores and - must end in "_by_<bot username>". <bot_username> is case insensitive. - 1-64 characters. - title (:obj:`str`): Sticker set title, 1-64 characters. - png_sticker (:obj:`str` | `filelike object` | :obj:`bytes` | :class:`pathlib.Path`, \ - optional): Png image with the sticker, - must be up to 512 kilobytes in size, dimensions must not exceed 512px, - and either width or height must be exactly 512px. Pass a file_id as a String to - send a file that already exists on the Telegram servers, pass an HTTP URL as a - String for Telegram to get a file from the Internet, or upload a new one - using multipart/form-data. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - tgs_sticker (:obj:`str` | `filelike object` | :obj:`bytes` | :class:`pathlib.Path`, \ - optional): TGS animation with the sticker, - uploaded using multipart/form-data. See - https://core.telegram.org/animated_stickers#technical-requirements for technical - requirements. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - emojis (:obj:`str`): One or more emoji corresponding to the sticker. - contains_masks (:obj:`bool`, optional): Pass :obj:`True`, if a set of mask stickers - should be created. - mask_position (:class:`telegram.MaskPosition`, optional): Position where the mask - should be placed on faces. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during - creation of the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {'user_id': user_id, 'name': name, 'title': title, 'emojis': emojis} - - if png_sticker is not None: - data['png_sticker'] = parse_file_input(png_sticker) - if tgs_sticker is not None: - data['tgs_sticker'] = parse_file_input(tgs_sticker) - if contains_masks is not None: - data['contains_masks'] = contains_masks - if mask_position is not None: - # We need to_json() instead of to_dict() here, because we're sending a media - # message here, which isn't json dumped by utils.request - data['mask_position'] = mask_position.to_json() - - result = self._post('createNewStickerSet', data, timeout=timeout, api_kwargs=api_kwargs) - - return result # type: ignore[return-value] - - @log - def add_sticker_to_set( - self, - user_id: Union[str, int], - name: str, - emojis: str, - png_sticker: FileInput = None, - mask_position: MaskPosition = None, - timeout: DVInput[float] = DEFAULT_20, - tgs_sticker: FileInput = None, - api_kwargs: JSONDict = None, - ) -> bool: - """ - Use this method to add a new sticker to a set created by the bot. - You must use exactly one of the fields ``png_sticker`` or ``tgs_sticker``. Animated - stickers can be added to animated sticker sets and only to them. Animated sticker sets can - have up to 50 stickers. Static sticker sets can have up to 120 stickers. - - Warning: - As of API 4.7 ``png_sticker`` is an optional argument and therefore the order of the - arguments had to be changed. Use keyword arguments to make sure that the arguments are - passed correctly. - - Note: - The png_sticker and tgs_sticker argument can be either a file_id, an URL or a file from - disk ``open(filename, 'rb')`` - - Args: - user_id (:obj:`int`): User identifier of created sticker set owner. - - name (:obj:`str`): Sticker set name. - png_sticker (:obj:`str` | `filelike object` | :obj:`bytes` | :class:`pathlib.Path`, \ - optional): PNG image with the sticker, - must be up to 512 kilobytes in size, dimensions must not exceed 512px, - and either width or height must be exactly 512px. Pass a file_id as a String to - send a file that already exists on the Telegram servers, pass an HTTP URL as a - String for Telegram to get a file from the Internet, or upload a new one - using multipart/form-data. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - tgs_sticker (:obj:`str` | `filelike object` | :obj:`bytes` | :class:`pathlib.Path`, \ - optional): TGS animation with the sticker, - uploaded using multipart/form-data. See - https://core.telegram.org/animated_stickers#technical-requirements for technical - requirements. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - emojis (:obj:`str`): One or more emoji corresponding to the sticker. - mask_position (:class:`telegram.MaskPosition`, optional): Position where the mask - should be placed on faces. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during - creation of the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {'user_id': user_id, 'name': name, 'emojis': emojis} - - if png_sticker is not None: - data['png_sticker'] = parse_file_input(png_sticker) - if tgs_sticker is not None: - data['tgs_sticker'] = parse_file_input(tgs_sticker) - if mask_position is not None: - # We need to_json() instead of to_dict() here, because we're sending a media - # message here, which isn't json dumped by utils.request - data['mask_position'] = mask_position.to_json() - - result = self._post('addStickerToSet', data, timeout=timeout, api_kwargs=api_kwargs) - - return result # type: ignore[return-value] - - @log - def set_sticker_position_in_set( - self, - sticker: str, - position: int, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> bool: - """Use this method to move a sticker in a set created by the bot to a specific position. - - Args: - sticker (:obj:`str`): File identifier of the sticker. - position (:obj:`int`): New sticker position in the set, zero-based. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during - creation of the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {'sticker': sticker, 'position': position} - - result = self._post( - 'setStickerPositionInSet', data, timeout=timeout, api_kwargs=api_kwargs - ) - - return result # type: ignore[return-value] - - @log - def delete_sticker_from_set( - self, - sticker: str, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> bool: - """Use this method to delete a sticker from a set created by the bot. - - Args: - sticker (:obj:`str`): File identifier of the sticker. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during - creation of the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {'sticker': sticker} - - result = self._post('deleteStickerFromSet', data, timeout=timeout, api_kwargs=api_kwargs) - - return result # type: ignore[return-value] - - @log - def set_sticker_set_thumb( - self, - name: str, - user_id: Union[str, int], - thumb: FileInput = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> bool: - """Use this method to set the thumbnail of a sticker set. Animated thumbnails can be set - for animated sticker sets only. - - Note: - The thumb can be either a file_id, an URL or a file from disk ``open(filename, 'rb')`` - - Args: - name (:obj:`str`): Sticker set name - user_id (:obj:`int`): User identifier of created sticker set owner. - thumb (:obj:`str` | `filelike object` | :obj:`bytes` | :class:`pathlib.Path`, \ - optional): A PNG image with the thumbnail, must - be up to 128 kilobytes in size and have width and height exactly 100px, or a TGS - animation with the thumbnail up to 32 kilobytes in size; see - https://core.telegram.org/animated_stickers#technical-requirements for animated - sticker technical requirements. Pass a file_id as a String to send a file that - already exists on the Telegram servers, pass an HTTP URL as a String for Telegram - to get a file from the Internet, or upload a new one using multipart/form-data. - Animated sticker set thumbnail can't be uploaded via HTTP URL. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during - creation of the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {'name': name, 'user_id': user_id} - - if thumb is not None: - data['thumb'] = parse_file_input(thumb) - - result = self._post('setStickerSetThumb', data, timeout=timeout, api_kwargs=api_kwargs) - - return result # type: ignore[return-value] - - @log - def set_passport_data_errors( - self, - user_id: Union[str, int], - errors: List[PassportElementError], - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> bool: - """ - Informs a user that some of the Telegram Passport elements they provided contains errors. - The user will not be able to re-submit their Passport to you until the errors are fixed - (the contents of the field for which you returned the error must change). - - Use this if the data submitted by the user doesn't satisfy the standards your service - requires for any reason. For example, if a birthday date seems invalid, a submitted - document is blurry, a scan shows evidence of tampering, etc. Supply some details in the - error message to make sure the user knows how to correct the issues. - - Args: - user_id (:obj:`int`): User identifier - errors (List[:class:`PassportElementError`]): A JSON-serialized array describing the - errors. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during - creation of the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {'user_id': user_id, 'errors': [error.to_dict() for error in errors]} - - result = self._post('setPassportDataErrors', data, timeout=timeout, api_kwargs=api_kwargs) - - return result # type: ignore[return-value] - - @log - def send_poll( - self, - chat_id: Union[int, str], - question: str, - options: List[str], - is_anonymous: bool = True, - type: str = Poll.REGULAR, # pylint: disable=W0622 - allows_multiple_answers: bool = False, - correct_option_id: int = None, - is_closed: bool = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: ReplyMarkup = None, - timeout: ODVInput[float] = DEFAULT_NONE, - explanation: str = None, - explanation_parse_mode: ODVInput[str] = DEFAULT_NONE, - open_period: int = None, - close_date: Union[int, datetime] = None, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - explanation_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - ) -> Message: - """ - Use this method to send a native poll. - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target channel (in the format ``@channelusername``). - question (:obj:`str`): Poll question, 1-300 characters. - options (List[:obj:`str`]): List of answer options, 2-10 strings 1-100 characters each. - is_anonymous (:obj:`bool`, optional): :obj:`True`, if the poll needs to be anonymous, - defaults to :obj:`True`. - type (:obj:`str`, optional): Poll type, :attr:`telegram.Poll.QUIZ` or - :attr:`telegram.Poll.REGULAR`, defaults to :attr:`telegram.Poll.REGULAR`. - allows_multiple_answers (:obj:`bool`, optional): :obj:`True`, if the poll allows - multiple answers, ignored for polls in quiz mode, defaults to :obj:`False`. - correct_option_id (:obj:`int`, optional): 0-based identifier of the correct answer - option, required for polls in quiz mode. - explanation (:obj:`str`, optional): Text that is shown when a user chooses an incorrect - answer or taps on the lamp icon in a quiz-style poll, 0-200 characters with at most - 2 line feeds after entities parsing. - explanation_parse_mode (:obj:`str`, optional): Mode for parsing entities in the - explanation. See the constants in :class:`telegram.ParseMode` for the available - modes. - explanation_entities (List[:class:`telegram.MessageEntity`], optional): List of special - entities that appear in message text, which can be specified instead of - :attr:`parse_mode`. - open_period (:obj:`int`, optional): Amount of time in seconds the poll will be active - after creation, 5-600. Can't be used together with :attr:`close_date`. - close_date (:obj:`int` | :obj:`datetime.datetime`, optional): Point in time (Unix - timestamp) when the poll will be automatically closed. Must be at least 5 and no - more than 600 seconds in the future. Can't be used together with - :attr:`open_period`. - For timezone naive :obj:`datetime.datetime` objects, the default timezone of the - bot will be used. - is_closed (:obj:`bool`, optional): Pass :obj:`True`, if the poll needs to be - immediately closed. This can be useful for poll preview. - disable_notification (:obj:`bool`, optional): Sends the message silently. Users will - receive a notification with no sound. - reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the - original message. - allow_sending_without_reply (:obj:`bool`, optional): Pass :obj:`True`, if the message - should be sent even if the specified replied-to message is not found. - reply_markup (:class:`telegram.ReplyMarkup`, optional): Additional interface options. A - JSON-serialized object for an inline keyboard, custom reply keyboard, instructions - to remove reply keyboard or to force a reply from the user. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :class:`telegram.Message`: On success, the sent Message is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - 'chat_id': chat_id, - 'question': question, - 'options': options, - 'explanation_parse_mode': explanation_parse_mode, - } - - if not is_anonymous: - data['is_anonymous'] = is_anonymous - if type: - data['type'] = type - if allows_multiple_answers: - data['allows_multiple_answers'] = allows_multiple_answers - if correct_option_id is not None: - data['correct_option_id'] = correct_option_id - if is_closed: - data['is_closed'] = is_closed - if explanation: - data['explanation'] = explanation - if explanation_entities: - data['explanation_entities'] = [me.to_dict() for me in explanation_entities] - if open_period: - data['open_period'] = open_period - if close_date: - if isinstance(close_date, datetime): - close_date = to_timestamp( - close_date, tzinfo=self.defaults.tzinfo if self.defaults else None - ) - data['close_date'] = close_date - - return self._message( # type: ignore[return-value] - 'sendPoll', - data, - timeout=timeout, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - allow_sending_without_reply=allow_sending_without_reply, - api_kwargs=api_kwargs, - ) - - @log - def stop_poll( - self, - chat_id: Union[int, str], - message_id: int, - reply_markup: InlineKeyboardMarkup = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> Poll: - """ - Use this method to stop a poll which was sent by the bot. - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target channel (in the format ``@channelusername``). - message_id (:obj:`int`): Identifier of the original message with the poll. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): A JSON-serialized - object for a new message inline keyboard. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :class:`telegram.Poll`: On success, the stopped Poll with the final results is - returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = {'chat_id': chat_id, 'message_id': message_id} - - if reply_markup: - if isinstance(reply_markup, ReplyMarkup): - # We need to_json() instead of to_dict() here, because reply_markups may be - # attached to media messages, which aren't json dumped by utils.request - data['reply_markup'] = reply_markup.to_json() - else: - data['reply_markup'] = reply_markup - - result = self._post('stopPoll', data, timeout=timeout, api_kwargs=api_kwargs) - - return Poll.de_json(result, self) # type: ignore[return-value, arg-type] - - @log - def send_dice( - self, - chat_id: Union[int, str], - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: ReplyMarkup = None, - timeout: ODVInput[float] = DEFAULT_NONE, - emoji: str = None, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - ) -> Message: - """ - Use this method to send an animated emoji that will display a random value. - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target channel (in the format ``@channelusername``). - emoji (:obj:`str`, optional): Emoji on which the dice throw animation is based. - Currently, must be one of “🎲”, “🎯”, “🏀”, “⚽”, "🎳", or “🎰”. Dice can have - values 1-6 for “🎲”, “🎯” and "🎳", values 1-5 for “🏀” and “⚽”, and values 1-64 - for “🎰”. Defaults to “🎲”. - - .. versionchanged:: 13.4 - Added the "🎳" emoji. - disable_notification (:obj:`bool`, optional): Sends the message silently. Users will - receive a notification with no sound. - reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the - original message. - allow_sending_without_reply (:obj:`bool`, optional): Pass :obj:`True`, if the message - should be sent even if the specified replied-to message is not found. - reply_markup (:class:`telegram.ReplyMarkup`, optional): Additional interface options. A - JSON-serialized object for an inline keyboard, custom reply keyboard, instructions - to remove reply keyboard or to force a reply from the user. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :class:`telegram.Message`: On success, the sent Message is returned. - - Raises: - :class:`telegram.error.TelegramError` - - """ - data: JSONDict = { - 'chat_id': chat_id, - } - - if emoji: - data['emoji'] = emoji - - return self._message( # type: ignore[return-value] - 'sendDice', - data, - timeout=timeout, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - allow_sending_without_reply=allow_sending_without_reply, - api_kwargs=api_kwargs, - ) - - @log - def get_my_commands( - self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None - ) -> List[BotCommand]: - """ - Use this method to get the current list of the bot's commands. - - Args: - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - List[:class:`telegram.BotCommand]`: On success, the commands set for the bot - - Raises: - :class:`telegram.error.TelegramError` - - """ - result = self._post('getMyCommands', timeout=timeout, api_kwargs=api_kwargs) - - self._commands = BotCommand.de_list(result, self) # type: ignore[assignment,arg-type] - - return self._commands # type: ignore[return-value] - - @log - def set_my_commands( - self, - commands: List[Union[BotCommand, Tuple[str, str]]], - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> bool: - """ - Use this method to change the list of the bot's commands. - - Args: - commands (List[:class:`BotCommand` | (:obj:`str`, :obj:`str`)]): A JSON-serialized list - of bot commands to be set as the list of the bot's commands. At most 100 commands - can be specified. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :obj:`True`: On success - - Raises: - :class:`telegram.error.TelegramError` - - """ - cmds = [c if isinstance(c, BotCommand) else BotCommand(c[0], c[1]) for c in commands] - - data: JSONDict = {'commands': [c.to_dict() for c in cmds]} - - result = self._post('setMyCommands', data, timeout=timeout, api_kwargs=api_kwargs) - - # Set commands. No need to check for outcome. - # If request failed, we won't come this far - self._commands = cmds - - return result # type: ignore[return-value] - - @log - def log_out(self, timeout: ODVInput[float] = DEFAULT_NONE) -> bool: - """ - Use this method to log out from the cloud Bot API server before launching the bot locally. - You *must* log out the bot before running it locally, otherwise there is no guarantee that - the bot will receive updates. After a successful call, you can immediately log in on a - local server, but will not be able to log in back to the cloud Bot API server for 10 - minutes. - - Args: - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - - Returns: - :obj:`True`: On success - - Raises: - :class:`telegram.error.TelegramError` - - """ - return self._post('logOut', timeout=timeout) # type: ignore[return-value] - - @log - def close(self, timeout: ODVInput[float] = DEFAULT_NONE) -> bool: - """ - Use this method to close the bot instance before moving it from one local server to - another. You need to delete the webhook before calling this method to ensure that the bot - isn't launched again after server restart. The method will return error 429 in the first - 10 minutes after the bot is launched. - - Args: - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - - Returns: - :obj:`True`: On success - - Raises: - :class:`telegram.error.TelegramError` - - """ - return self._post('close', timeout=timeout) # type: ignore[return-value] - - @log - def copy_message( - self, - chat_id: Union[int, str], - from_chat_id: Union[str, int], - message_id: int, - caption: str = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[Tuple['MessageEntity', ...], List['MessageEntity']] = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE, - reply_markup: ReplyMarkup = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> MessageId: - """ - Use this method to copy messages of any kind. Service messages and invoice messages can't - be copied. The method is analogous to the method :meth:`forward_message`, but the copied - message doesn't have a link to the original message. - - Args: - chat_id (:obj:`int` | :obj:`str`): Unique identifier for the target chat or username - of the target channel (in the format ``@channelusername``). - from_chat_id (:obj:`int` | :obj:`str`): Unique identifier for the chat where the - original message was sent (or channel username in the format ``@channelusername``). - message_id (:obj:`int`): Message identifier in the chat specified in from_chat_id. - caption (:obj:`str`, optional): New caption for media, 0-1024 characters after - entities parsing. If not specified, the original caption is kept. - parse_mode (:obj:`str`, optional): Mode for parsing entities in the new caption. See - the constants in :class:`telegram.ParseMode` for the available modes. - caption_entities (:class:`telegram.utils.types.SLT[MessageEntity]`): List of special - entities that appear in the new caption, which can be specified instead of - parse_mode - disable_notification (:obj:`bool`, optional): Sends the message silently. Users will - receive a notification with no sound. - reply_to_message_id (:obj:`int`, optional): If the message is a reply, ID of the - original message. - allow_sending_without_reply (:obj:`bool`, optional): Pass :obj:`True`, if the message - should be sent even if the specified replied-to message is not found. - reply_markup (:class:`telegram.ReplyMarkup`, optional): Additional interface options. - A JSON-serialized object for an inline keyboard, custom reply keyboard, - instructions to remove reply keyboard or to force a reply from the user. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - api_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to be passed to the - Telegram API. - - Returns: - :class:`telegram.MessageId`: On success - - Raises: - :class:`telegram.error.TelegramError` - """ - data: JSONDict = { - 'chat_id': chat_id, - 'from_chat_id': from_chat_id, - 'message_id': message_id, - 'parse_mode': parse_mode, - 'disable_notification': disable_notification, - 'allow_sending_without_reply': allow_sending_without_reply, - } - if caption: - data['caption'] = caption - if caption_entities: - data['caption_entities'] = caption_entities - if reply_to_message_id: - data['reply_to_message_id'] = reply_to_message_id - if reply_markup: - if isinstance(reply_markup, ReplyMarkup): - # We need to_json() instead of to_dict() here, because reply_markups may be - # attached to media messages, which aren't json dumped by utils.request - data['reply_markup'] = reply_markup.to_json() - else: - data['reply_markup'] = reply_markup - - result = self._post('copyMessage', data, timeout=timeout, api_kwargs=api_kwargs) - return MessageId.de_json(result, self) # type: ignore[return-value, arg-type] - - def to_dict(self) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data: JSONDict = {'id': self.id, 'username': self.username, 'first_name': self.first_name} - - if self.last_name: - data['last_name'] = self.last_name - - return data - - def __eq__(self, other: object) -> bool: - return self.bot == other - - def __hash__(self) -> int: - return hash(self.bot) - - # camelCase aliases - getMe = get_me - """Alias for :meth:`get_me`""" - sendMessage = send_message - """Alias for :meth:`send_message`""" - deleteMessage = delete_message - """Alias for :meth:`delete_message`""" - forwardMessage = forward_message - """Alias for :meth:`forward_message`""" - sendPhoto = send_photo - """Alias for :meth:`send_photo`""" - sendAudio = send_audio - """Alias for :meth:`send_audio`""" - sendDocument = send_document - """Alias for :meth:`send_document`""" - sendSticker = send_sticker - """Alias for :meth:`send_sticker`""" - sendVideo = send_video - """Alias for :meth:`send_video`""" - sendAnimation = send_animation - """Alias for :meth:`send_animation`""" - sendVoice = send_voice - """Alias for :meth:`send_voice`""" - sendVideoNote = send_video_note - """Alias for :meth:`send_video_note`""" - sendMediaGroup = send_media_group - """Alias for :meth:`send_media_group`""" - sendLocation = send_location - """Alias for :meth:`send_location`""" - editMessageLiveLocation = edit_message_live_location - """Alias for :meth:`edit_message_live_location`""" - stopMessageLiveLocation = stop_message_live_location - """Alias for :meth:`stop_message_live_location`""" - sendVenue = send_venue - """Alias for :meth:`send_venue`""" - sendContact = send_contact - """Alias for :meth:`send_contact`""" - sendGame = send_game - """Alias for :meth:`send_game`""" - sendChatAction = send_chat_action - """Alias for :meth:`send_chat_action`""" - answerInlineQuery = answer_inline_query - """Alias for :meth:`answer_inline_query`""" - getUserProfilePhotos = get_user_profile_photos - """Alias for :meth:`get_user_profile_photos`""" - getFile = get_file - """Alias for :meth:`get_file`""" - kickChatMember = kick_chat_member - """Alias for :meth:`kick_chat_member`""" - unbanChatMember = unban_chat_member - """Alias for :meth:`unban_chat_member`""" - answerCallbackQuery = answer_callback_query - """Alias for :meth:`answer_callback_query`""" - editMessageText = edit_message_text - """Alias for :meth:`edit_message_text`""" - editMessageCaption = edit_message_caption - """Alias for :meth:`edit_message_caption`""" - editMessageMedia = edit_message_media - """Alias for :meth:`edit_message_media`""" - editMessageReplyMarkup = edit_message_reply_markup - """Alias for :meth:`edit_message_reply_markup`""" - getUpdates = get_updates - """Alias for :meth:`get_updates`""" - setWebhook = set_webhook - """Alias for :meth:`set_webhook`""" - deleteWebhook = delete_webhook - """Alias for :meth:`delete_webhook`""" - leaveChat = leave_chat - """Alias for :meth:`leave_chat`""" - getChat = get_chat - """Alias for :meth:`get_chat`""" - getChatAdministrators = get_chat_administrators - """Alias for :meth:`get_chat_administrators`""" - getChatMember = get_chat_member - """Alias for :meth:`get_chat_member`""" - setChatStickerSet = set_chat_sticker_set - """Alias for :meth:`set_chat_sticker_set`""" - deleteChatStickerSet = delete_chat_sticker_set - """Alias for :meth:`delete_chat_sticker_set`""" - getChatMembersCount = get_chat_members_count - """Alias for :meth:`get_chat_members_count`""" - getWebhookInfo = get_webhook_info - """Alias for :meth:`get_webhook_info`""" - setGameScore = set_game_score - """Alias for :meth:`set_game_score`""" - getGameHighScores = get_game_high_scores - """Alias for :meth:`get_game_high_scores`""" - sendInvoice = send_invoice - """Alias for :meth:`send_invoice`""" - answerShippingQuery = answer_shipping_query - """Alias for :meth:`answer_shipping_query`""" - answerPreCheckoutQuery = answer_pre_checkout_query - """Alias for :meth:`answer_pre_checkout_query`""" - restrictChatMember = restrict_chat_member - """Alias for :meth:`restrict_chat_member`""" - promoteChatMember = promote_chat_member - """Alias for :meth:`promote_chat_member`""" - setChatPermissions = set_chat_permissions - """Alias for :meth:`set_chat_permissions`""" - setChatAdministratorCustomTitle = set_chat_administrator_custom_title - """Alias for :meth:`set_chat_administrator_custom_title`""" - exportChatInviteLink = export_chat_invite_link - """Alias for :meth:`export_chat_invite_link`""" - createChatInviteLink = create_chat_invite_link - """Alias for :attr:`create_chat_invite_link`""" - editChatInviteLink = edit_chat_invite_link - """Alias for :attr:`edit_chat_invite_link`""" - revokeChatInviteLink = revoke_chat_invite_link - """Alias for :attr:`revoke_chat_invite_link`""" - setChatPhoto = set_chat_photo - """Alias for :meth:`set_chat_photo`""" - deleteChatPhoto = delete_chat_photo - """Alias for :meth:`delete_chat_photo`""" - setChatTitle = set_chat_title - """Alias for :meth:`set_chat_title`""" - setChatDescription = set_chat_description - """Alias for :meth:`set_chat_description`""" - pinChatMessage = pin_chat_message - """Alias for :meth:`pin_chat_message`""" - unpinChatMessage = unpin_chat_message - """Alias for :meth:`unpin_chat_message`""" - unpinAllChatMessages = unpin_all_chat_messages - """Alias for :meth:`unpin_all_chat_messages`""" - getStickerSet = get_sticker_set - """Alias for :meth:`get_sticker_set`""" - uploadStickerFile = upload_sticker_file - """Alias for :meth:`upload_sticker_file`""" - createNewStickerSet = create_new_sticker_set - """Alias for :meth:`create_new_sticker_set`""" - addStickerToSet = add_sticker_to_set - """Alias for :meth:`add_sticker_to_set`""" - setStickerPositionInSet = set_sticker_position_in_set - """Alias for :meth:`set_sticker_position_in_set`""" - deleteStickerFromSet = delete_sticker_from_set - """Alias for :meth:`delete_sticker_from_set`""" - setStickerSetThumb = set_sticker_set_thumb - """Alias for :meth:`set_sticker_set_thumb`""" - setPassportDataErrors = set_passport_data_errors - """Alias for :meth:`set_passport_data_errors`""" - sendPoll = send_poll - """Alias for :meth:`send_poll`""" - stopPoll = stop_poll - """Alias for :meth:`stop_poll`""" - sendDice = send_dice - """Alias for :meth:`send_dice`""" - getMyCommands = get_my_commands - """Alias for :meth:`get_my_commands`""" - setMyCommands = set_my_commands - """Alias for :meth:`set_my_commands`""" - logOut = log_out - """Alias for :meth:`log_out`""" - copyMessage = copy_message - """Alias for :meth:`copy_message`""" diff --git a/venv/lib/python3.8/site-packages/telegram/botcommand.py b/venv/lib/python3.8/site-packages/telegram/botcommand.py deleted file mode 100644 index 8b36e3e..0000000 --- a/venv/lib/python3.8/site-packages/telegram/botcommand.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env python -# pylint: disable=R0903 -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram Bot Command.""" -from typing import Any - -from telegram import TelegramObject - - -class BotCommand(TelegramObject): - """ - This object represents a bot command. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`command` and :attr:`description` are equal. - - Args: - command (:obj:`str`): Text of the command, 1-32 characters. Can contain only lowercase - English letters, digits and underscores. - description (:obj:`str`): Description of the command, 3-256 characters. - - Attributes: - command (:obj:`str`): Text of the command. - description (:obj:`str`): Description of the command. - - """ - - __slots__ = ('description', '_id_attrs', 'command') - - def __init__(self, command: str, description: str, **_kwargs: Any): - self.command = command - self.description = description - - self._id_attrs = (self.command, self.description) diff --git a/venv/lib/python3.8/site-packages/telegram/callbackquery.py b/venv/lib/python3.8/site-packages/telegram/callbackquery.py deleted file mode 100644 index 47b05b9..0000000 --- a/venv/lib/python3.8/site-packages/telegram/callbackquery.py +++ /dev/null @@ -1,658 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -# pylint: disable=W0622 -"""This module contains an object that represents a Telegram CallbackQuery""" -from typing import TYPE_CHECKING, Any, List, Optional, Union, Tuple, ClassVar - -from telegram import Message, TelegramObject, User, Location, ReplyMarkup, constants -from telegram.utils.helpers import DEFAULT_NONE -from telegram.utils.types import JSONDict, ODVInput, DVInput - -if TYPE_CHECKING: - from telegram import ( - Bot, - GameHighScore, - InlineKeyboardMarkup, - MessageId, - InputMedia, - MessageEntity, - ) - - -class CallbackQuery(TelegramObject): - """ - This object represents an incoming callback query from a callback button in an inline keyboard. - - If the button that originated the query was attached to a message sent by the bot, the field - :attr:`message` will be present. If the button was attached to a message sent via the bot (in - inline mode), the field :attr:`inline_message_id` will be present. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`id` is equal. - - Note: - * In Python ``from`` is a reserved word, use ``from_user`` instead. - * Exactly one of the fields :attr:`data` or :attr:`game_short_name` will be present. - * After the user presses an inline button, Telegram clients will display a progress bar - until you call :attr:`answer`. It is, therefore, necessary to react - by calling :attr:`telegram.Bot.answer_callback_query` even if no notification to the user - is needed (e.g., without specifying any of the optional parameters). - * If you're using :attr:`Bot.arbitrary_callback_data`, :attr:`data` may be an instance - of :class:`telegram.ext.InvalidCallbackData`. This will be the case, if the data - associated with the button triggering the :class:`telegram.CallbackQuery` was already - deleted or if :attr:`data` was manipulated by a malicious client. - - .. versionadded:: 13.6 - - - Args: - id (:obj:`str`): Unique identifier for this query. - from_user (:class:`telegram.User`): Sender. - chat_instance (:obj:`str`): Global identifier, uniquely corresponding to the chat to which - the message with the callback button was sent. Useful for high scores in games. - message (:class:`telegram.Message`, optional): Message with the callback button that - originated the query. Note that message content and message date will not be available - if the message is too old. - data (:obj:`str`, optional): Data associated with the callback button. Be aware that a bad - client can send arbitrary data in this field. - inline_message_id (:obj:`str`, optional): Identifier of the message sent via the bot in - inline mode, that originated the query. - game_short_name (:obj:`str`, optional): Short name of a Game to be returned, serves as - the unique identifier for the game - bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods. - - Attributes: - id (:obj:`str`): Unique identifier for this query. - from_user (:class:`telegram.User`): Sender. - chat_instance (:obj:`str`): Global identifier, uniquely corresponding to the chat to which - the message with the callback button was sent. - message (:class:`telegram.Message`): Optional. Message with the callback button that - originated the query. - data (:obj:`str` | :obj:`object`): Optional. Data associated with the callback button. - inline_message_id (:obj:`str`): Optional. Identifier of the message sent via the bot in - inline mode, that originated the query. - game_short_name (:obj:`str`): Optional. Short name of a Game to be returned. - bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods. - - """ - - __slots__ = ( - 'bot', - 'game_short_name', - 'message', - 'chat_instance', - 'id', - 'from_user', - 'inline_message_id', - 'data', - '_id_attrs', - ) - - def __init__( - self, - id: str, # pylint: disable=W0622 - from_user: User, - chat_instance: str, - message: Message = None, - data: str = None, - inline_message_id: str = None, - game_short_name: str = None, - bot: 'Bot' = None, - **_kwargs: Any, - ): - # Required - self.id = id # pylint: disable=C0103 - self.from_user = from_user - self.chat_instance = chat_instance - # Optionals - self.message = message - self.data = data - self.inline_message_id = inline_message_id - self.game_short_name = game_short_name - - self.bot = bot - - self._id_attrs = (self.id,) - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['CallbackQuery']: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data['from_user'] = User.de_json(data.get('from'), bot) - data['message'] = Message.de_json(data.get('message'), bot) - - return cls(bot=bot, **data) - - def answer( - self, - text: str = None, - show_alert: bool = False, - url: str = None, - cache_time: int = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> bool: - """Shortcut for:: - - bot.answer_callback_query(update.callback_query.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.answer_callback_query`. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return self.bot.answer_callback_query( - callback_query_id=self.id, - text=text, - show_alert=show_alert, - url=url, - cache_time=cache_time, - timeout=timeout, - api_kwargs=api_kwargs, - ) - - def edit_message_text( - self, - text: str, - parse_mode: ODVInput[str] = DEFAULT_NONE, - disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, - reply_markup: 'InlineKeyboardMarkup' = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - ) -> Union[Message, bool]: - """Shortcut for either:: - - update.callback_query.message.edit_text(text, *args, **kwargs) - - or:: - - bot.edit_message_text(text, inline_message_id=update.callback_query.inline_message_id, - *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.edit_message_text` and :meth:`telegram.Message.edit_text`. - - Returns: - :class:`telegram.Message`: On success, if edited message is sent by the bot, the - edited Message is returned, otherwise :obj:`True` is returned. - - """ - if self.inline_message_id: - return self.bot.edit_message_text( - inline_message_id=self.inline_message_id, - text=text, - parse_mode=parse_mode, - disable_web_page_preview=disable_web_page_preview, - reply_markup=reply_markup, - timeout=timeout, - api_kwargs=api_kwargs, - entities=entities, - chat_id=None, - message_id=None, - ) - return self.message.edit_text( - text=text, - parse_mode=parse_mode, - disable_web_page_preview=disable_web_page_preview, - reply_markup=reply_markup, - timeout=timeout, - api_kwargs=api_kwargs, - entities=entities, - ) - - def edit_message_caption( - self, - caption: str = None, - reply_markup: 'InlineKeyboardMarkup' = None, - timeout: ODVInput[float] = DEFAULT_NONE, - parse_mode: ODVInput[str] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - ) -> Union[Message, bool]: - """Shortcut for either:: - - update.callback_query.message.edit_caption(caption, *args, **kwargs) - - or:: - - bot.edit_message_caption(caption=caption - inline_message_id=update.callback_query.inline_message_id, - *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.edit_message_caption` and :meth:`telegram.Message.edit_caption`. - - Returns: - :class:`telegram.Message`: On success, if edited message is sent by the bot, the - edited Message is returned, otherwise :obj:`True` is returned. - - """ - if self.inline_message_id: - return self.bot.edit_message_caption( - caption=caption, - inline_message_id=self.inline_message_id, - reply_markup=reply_markup, - timeout=timeout, - parse_mode=parse_mode, - api_kwargs=api_kwargs, - caption_entities=caption_entities, - chat_id=None, - message_id=None, - ) - return self.message.edit_caption( - caption=caption, - reply_markup=reply_markup, - timeout=timeout, - parse_mode=parse_mode, - api_kwargs=api_kwargs, - caption_entities=caption_entities, - ) - - def edit_message_reply_markup( - self, - reply_markup: Optional['InlineKeyboardMarkup'] = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> Union[Message, bool]: - """Shortcut for either:: - - update.callback_query.message.edit_reply_markup( - reply_markup=reply_markup, - *args, - **kwargs - ) - - or:: - - bot.edit_message_reply_markup - inline_message_id=update.callback_query.inline_message_id, - reply_markup=reply_markup, - *args, - **kwargs - ) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.edit_message_reply_markup` and - :meth:`telegram.Message.edit_reply_markup`. - - Returns: - :class:`telegram.Message`: On success, if edited message is sent by the bot, the - edited Message is returned, otherwise :obj:`True` is returned. - - """ - if self.inline_message_id: - return self.bot.edit_message_reply_markup( - reply_markup=reply_markup, - inline_message_id=self.inline_message_id, - timeout=timeout, - api_kwargs=api_kwargs, - chat_id=None, - message_id=None, - ) - return self.message.edit_reply_markup( - reply_markup=reply_markup, - timeout=timeout, - api_kwargs=api_kwargs, - ) - - def edit_message_media( - self, - media: 'InputMedia' = None, - reply_markup: 'InlineKeyboardMarkup' = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> Union[Message, bool]: - """Shortcut for either:: - - update.callback_query.message.edit_media(*args, **kwargs) - - or:: - - bot.edit_message_media(inline_message_id=update.callback_query.inline_message_id, - *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.edit_message_media` and :meth:`telegram.Message.edit_media`. - - Returns: - :class:`telegram.Message`: On success, if edited message is sent by the bot, the - edited Message is returned, otherwise :obj:`True` is returned. - - """ - if self.inline_message_id: - return self.bot.edit_message_media( - inline_message_id=self.inline_message_id, - media=media, - reply_markup=reply_markup, - timeout=timeout, - api_kwargs=api_kwargs, - chat_id=None, - message_id=None, - ) - return self.message.edit_media( - media=media, - reply_markup=reply_markup, - timeout=timeout, - api_kwargs=api_kwargs, - ) - - def edit_message_live_location( - self, - latitude: float = None, - longitude: float = None, - location: Location = None, - reply_markup: 'InlineKeyboardMarkup' = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - horizontal_accuracy: float = None, - heading: int = None, - proximity_alert_radius: int = None, - ) -> Union[Message, bool]: - """Shortcut for either:: - - update.callback_query.message.edit_live_location(*args, **kwargs) - - or:: - - bot.edit_message_live_location( - inline_message_id=update.callback_query.inline_message_id, - *args, **kwargs - ) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.edit_message_live_location` and - :meth:`telegram.Message.edit_live_location`. - - Returns: - :class:`telegram.Message`: On success, if edited message is sent by the bot, the - edited Message is returned, otherwise :obj:`True` is returned. - - """ - if self.inline_message_id: - return self.bot.edit_message_live_location( - inline_message_id=self.inline_message_id, - latitude=latitude, - longitude=longitude, - location=location, - reply_markup=reply_markup, - timeout=timeout, - api_kwargs=api_kwargs, - horizontal_accuracy=horizontal_accuracy, - heading=heading, - proximity_alert_radius=proximity_alert_radius, - chat_id=None, - message_id=None, - ) - return self.message.edit_live_location( - latitude=latitude, - longitude=longitude, - location=location, - reply_markup=reply_markup, - timeout=timeout, - api_kwargs=api_kwargs, - horizontal_accuracy=horizontal_accuracy, - heading=heading, - proximity_alert_radius=proximity_alert_radius, - ) - - def stop_message_live_location( - self, - reply_markup: 'InlineKeyboardMarkup' = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> Union[Message, bool]: - """Shortcut for either:: - - update.callback_query.message.stop_live_location(*args, **kwargs) - - or:: - - bot.stop_message_live_location( - inline_message_id=update.callback_query.inline_message_id, - *args, **kwargs - ) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.stop_message_live_location` and - :meth:`telegram.Message.stop_live_location`. - - Returns: - :class:`telegram.Message`: On success, if edited message is sent by the bot, the - edited Message is returned, otherwise :obj:`True` is returned. - - """ - if self.inline_message_id: - return self.bot.stop_message_live_location( - inline_message_id=self.inline_message_id, - reply_markup=reply_markup, - timeout=timeout, - api_kwargs=api_kwargs, - chat_id=None, - message_id=None, - ) - return self.message.stop_live_location( - reply_markup=reply_markup, - timeout=timeout, - api_kwargs=api_kwargs, - ) - - def set_game_score( - self, - user_id: Union[int, str], - score: int, - force: bool = None, - disable_edit_message: bool = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> Union[Message, bool]: - """Shortcut for either:: - - update.callback_query.message.set_game_score(*args, **kwargs) - - or:: - - bot.set_game_score(inline_message_id=update.callback_query.inline_message_id, - *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.set_game_score` and :meth:`telegram.Message.set_game_score`. - - Returns: - :class:`telegram.Message`: On success, if edited message is sent by the bot, the - edited Message is returned, otherwise :obj:`True` is returned. - - """ - if self.inline_message_id: - return self.bot.set_game_score( - inline_message_id=self.inline_message_id, - user_id=user_id, - score=score, - force=force, - disable_edit_message=disable_edit_message, - timeout=timeout, - api_kwargs=api_kwargs, - chat_id=None, - message_id=None, - ) - return self.message.set_game_score( - user_id=user_id, - score=score, - force=force, - disable_edit_message=disable_edit_message, - timeout=timeout, - api_kwargs=api_kwargs, - ) - - def get_game_high_scores( - self, - user_id: Union[int, str], - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> List['GameHighScore']: - """Shortcut for either:: - - update.callback_query.message.get_game_high_score(*args, **kwargs) - - or:: - - bot.get_game_high_scores(inline_message_id=update.callback_query.inline_message_id, - *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.get_game_high_scores` and :meth:`telegram.Message.get_game_high_score`. - - Returns: - List[:class:`telegram.GameHighScore`] - - """ - if self.inline_message_id: - return self.bot.get_game_high_scores( - inline_message_id=self.inline_message_id, - user_id=user_id, - timeout=timeout, - api_kwargs=api_kwargs, - chat_id=None, - message_id=None, - ) - return self.message.get_game_high_scores( - user_id=user_id, - timeout=timeout, - api_kwargs=api_kwargs, - ) - - def delete_message( - self, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> bool: - """Shortcut for:: - - update.callback_query.message.delete(*args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Message.delete`. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return self.message.delete( - timeout=timeout, - api_kwargs=api_kwargs, - ) - - def pin_message( - self, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> bool: - """Shortcut for:: - - update.callback_query.message.pin(*args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Message.pin`. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return self.message.pin( - disable_notification=disable_notification, - timeout=timeout, - api_kwargs=api_kwargs, - ) - - def unpin_message( - self, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> bool: - """Shortcut for:: - - update.callback_query.message.unpin(*args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Message.unpin`. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return self.message.unpin( - timeout=timeout, - api_kwargs=api_kwargs, - ) - - def copy_message( - self, - chat_id: Union[int, str], - caption: str = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[Tuple['MessageEntity', ...], List['MessageEntity']] = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE, - reply_markup: ReplyMarkup = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> 'MessageId': - """Shortcut for:: - - update.callback_query.message.copy( - chat_id, - from_chat_id=update.message.chat_id, - message_id=update.message.message_id, - *args, - **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Message.copy`. - - Returns: - :class:`telegram.MessageId`: On success, returns the MessageId of the sent message. - - """ - return self.message.copy( - chat_id=chat_id, - caption=caption, - parse_mode=parse_mode, - caption_entities=caption_entities, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - allow_sending_without_reply=allow_sending_without_reply, - reply_markup=reply_markup, - timeout=timeout, - api_kwargs=api_kwargs, - ) - - MAX_ANSWER_TEXT_LENGTH: ClassVar[int] = constants.MAX_ANSWER_CALLBACK_QUERY_TEXT_LENGTH - """ - :const:`telegram.constants.MAX_ANSWER_CALLBACK_QUERY_TEXT_LENGTH` - - .. versionadded:: 13.2 - """ diff --git a/venv/lib/python3.8/site-packages/telegram/chat.py b/venv/lib/python3.8/site-packages/telegram/chat.py deleted file mode 100644 index 95ed61d..0000000 --- a/venv/lib/python3.8/site-packages/telegram/chat.py +++ /dev/null @@ -1,1559 +0,0 @@ -#!/usr/bin/env python -# pylint: disable=W0622 -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram Chat.""" -from datetime import datetime -from typing import TYPE_CHECKING, List, Optional, ClassVar, Union, Tuple, Any - -from telegram import ChatPhoto, TelegramObject, constants -from telegram.utils.types import JSONDict, FileInput, ODVInput, DVInput - -from .chatpermissions import ChatPermissions -from .chatlocation import ChatLocation -from .utils.helpers import DEFAULT_NONE, DEFAULT_20 - -if TYPE_CHECKING: - from telegram import ( - Bot, - ChatMember, - ChatInviteLink, - Message, - MessageId, - ReplyMarkup, - Contact, - InlineKeyboardMarkup, - Location, - Venue, - MessageEntity, - InputMediaAudio, - InputMediaDocument, - InputMediaPhoto, - InputMediaVideo, - PhotoSize, - Audio, - Document, - Animation, - LabeledPrice, - Sticker, - Video, - VideoNote, - Voice, - ) - - -class Chat(TelegramObject): - """This object represents a chat. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`id` is equal. - - Args: - id (:obj:`int`): Unique identifier for this chat. This number may be greater than 32 bits - and some programming languages may have difficulty/silent defects in interpreting it. - But it is smaller than 52 bits, so a signed 64 bit integer or double-precision float - type are safe for storing this identifier. - type (:obj:`str`): Type of chat, can be either 'private', 'group', 'supergroup' or - 'channel'. - title (:obj:`str`, optional): Title, for supergroups, channels and group chats. - username(:obj:`str`, optional): Username, for private chats, supergroups and channels if - available. - first_name(:obj:`str`, optional): First name of the other party in a private chat. - last_name(:obj:`str`, optional): Last name of the other party in a private chat. - photo (:class:`telegram.ChatPhoto`, optional): Chat photo. - Returned only in :meth:`telegram.Bot.get_chat`. - bio (:obj:`str`, optional): Bio of the other party in a private chat. Returned only in - :meth:`telegram.Bot.get_chat`. - description (:obj:`str`, optional): Description, for groups, supergroups and channel chats. - Returned only in :meth:`telegram.Bot.get_chat`. - invite_link (:obj:`str`, optional): Primary invite link, for groups, supergroups and - channel. Returned only in :meth:`telegram.Bot.get_chat`. - pinned_message (:class:`telegram.Message`, optional): The most recent pinned message - (by sending date). Returned only in :meth:`telegram.Bot.get_chat`. - permissions (:class:`telegram.ChatPermissions`): Optional. Default chat member permissions, - for groups and supergroups. Returned only in :meth:`telegram.Bot.get_chat`. - slow_mode_delay (:obj:`int`, optional): For supergroups, the minimum allowed delay between - consecutive messages sent by each unprivileged user. - Returned only in :meth:`telegram.Bot.get_chat`. - message_auto_delete_time (:obj:`int`, optional): The time after which all messages sent to - the chat will be automatically deleted; in seconds. Returned only in - :meth:`telegram.Bot.get_chat`. - - .. versionadded:: 13.4 - bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods. - sticker_set_name (:obj:`str`, optional): For supergroups, name of group sticker set. - Returned only in :meth:`telegram.Bot.get_chat`. - can_set_sticker_set (:obj:`bool`, optional): :obj:`True`, if the bot can change group the - sticker set. Returned only in :meth:`telegram.Bot.get_chat`. - linked_chat_id (:obj:`int`, optional): Unique identifier for the linked chat, i.e. the - discussion group identifier for a channel and vice versa; for supergroups and channel - chats. Returned only in :meth:`telegram.Bot.get_chat`. - location (:class:`telegram.ChatLocation`, optional): For supergroups, the location to which - the supergroup is connected. Returned only in :meth:`telegram.Bot.get_chat`. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - id (:obj:`int`): Unique identifier for this chat. - type (:obj:`str`): Type of chat. - title (:obj:`str`): Optional. Title, for supergroups, channels and group chats. - username (:obj:`str`): Optional. Username. - first_name (:obj:`str`): Optional. First name of the other party in a private chat. - last_name (:obj:`str`): Optional. Last name of the other party in a private chat. - photo (:class:`telegram.ChatPhoto`): Optional. Chat photo. - bio (:obj:`str`): Optional. Bio of the other party in a private chat. Returned only in - :meth:`telegram.Bot.get_chat`. - description (:obj:`str`): Optional. Description, for groups, supergroups and channel chats. - invite_link (:obj:`str`): Optional. Primary invite link, for groups, supergroups and - channel. Returned only in :meth:`telegram.Bot.get_chat`. - pinned_message (:class:`telegram.Message`): Optional. The most recent pinned message - (by sending date). Returned only in :meth:`telegram.Bot.get_chat`. - permissions (:class:`telegram.ChatPermissions`): Optional. Default chat member permissions, - for groups and supergroups. Returned only in :meth:`telegram.Bot.get_chat`. - slow_mode_delay (:obj:`int`): Optional. For supergroups, the minimum allowed delay between - consecutive messages sent by each unprivileged user. Returned only in - :meth:`telegram.Bot.get_chat`. - message_auto_delete_time (:obj:`int`): Optional. The time after which all messages sent to - the chat will be automatically deleted; in seconds. Returned only in - :meth:`telegram.Bot.get_chat`. - - .. versionadded:: 13.4 - sticker_set_name (:obj:`str`): Optional. For supergroups, name of Group sticker set. - can_set_sticker_set (:obj:`bool`): Optional. :obj:`True`, if the bot can change group the - sticker set. - linked_chat_id (:obj:`int`): Optional. Unique identifier for the linked chat, i.e. the - discussion group identifier for a channel and vice versa; for supergroups and channel - chats. Returned only in :meth:`telegram.Bot.get_chat`. - location (:class:`telegram.ChatLocation`): Optional. For supergroups, the location to which - the supergroup is connected. Returned only in :meth:`telegram.Bot.get_chat`. - - """ - - __slots__ = ( - 'bio', - 'id', - 'type', - 'last_name', - 'bot', - 'sticker_set_name', - 'slow_mode_delay', - 'location', - 'first_name', - 'permissions', - 'invite_link', - 'pinned_message', - 'description', - 'can_set_sticker_set', - 'username', - 'title', - 'photo', - 'linked_chat_id', - 'all_members_are_administrators', - 'message_auto_delete_time', - '_id_attrs', - ) - - SENDER: ClassVar[str] = constants.CHAT_SENDER - """:const:`telegram.constants.CHAT_SENDER` - - .. versionadded:: 13.5 - """ - PRIVATE: ClassVar[str] = constants.CHAT_PRIVATE - """:const:`telegram.constants.CHAT_PRIVATE`""" - GROUP: ClassVar[str] = constants.CHAT_GROUP - """:const:`telegram.constants.CHAT_GROUP`""" - SUPERGROUP: ClassVar[str] = constants.CHAT_SUPERGROUP - """:const:`telegram.constants.CHAT_SUPERGROUP`""" - CHANNEL: ClassVar[str] = constants.CHAT_CHANNEL - """:const:`telegram.constants.CHAT_CHANNEL`""" - - def __init__( - self, - id: int, - type: str, - title: str = None, - username: str = None, - first_name: str = None, - last_name: str = None, - bot: 'Bot' = None, - photo: ChatPhoto = None, - description: str = None, - invite_link: str = None, - pinned_message: 'Message' = None, - permissions: ChatPermissions = None, - sticker_set_name: str = None, - can_set_sticker_set: bool = None, - slow_mode_delay: int = None, - bio: str = None, - linked_chat_id: int = None, - location: ChatLocation = None, - message_auto_delete_time: int = None, - **_kwargs: Any, - ): - # Required - self.id = int(id) # pylint: disable=C0103 - self.type = type - # Optionals - self.title = title - self.username = username - self.first_name = first_name - self.last_name = last_name - # TODO: Remove (also from tests), when Telegram drops this completely - self.all_members_are_administrators = _kwargs.get('all_members_are_administrators') - self.photo = photo - self.bio = bio - self.description = description - self.invite_link = invite_link - self.pinned_message = pinned_message - self.permissions = permissions - self.slow_mode_delay = slow_mode_delay - self.message_auto_delete_time = ( - int(message_auto_delete_time) if message_auto_delete_time is not None else None - ) - self.sticker_set_name = sticker_set_name - self.can_set_sticker_set = can_set_sticker_set - self.linked_chat_id = linked_chat_id - self.location = location - - self.bot = bot - self._id_attrs = (self.id,) - - @property - def full_name(self) -> Optional[str]: - """ - :obj:`str`: Convenience property. If :attr:`first_name` is not :obj:`None` gives, - :attr:`first_name` followed by (if available) :attr:`last_name`. - - Note: - :attr:`full_name` will always be :obj:`None`, if the chat is a (super)group or - channel. - - .. versionadded:: 13.2 - """ - if not self.first_name: - return None - if self.last_name: - return f'{self.first_name} {self.last_name}' - return self.first_name - - @property - def link(self) -> Optional[str]: - """:obj:`str`: Convenience property. If the chat has a :attr:`username`, returns a t.me - link of the chat. - """ - if self.username: - return f"https://t.me/{self.username}" - return None - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Chat']: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data['photo'] = ChatPhoto.de_json(data.get('photo'), bot) - from telegram import Message # pylint: disable=C0415 - - data['pinned_message'] = Message.de_json(data.get('pinned_message'), bot) - data['permissions'] = ChatPermissions.de_json(data.get('permissions'), bot) - data['location'] = ChatLocation.de_json(data.get('location'), bot) - - return cls(bot=bot, **data) - - def leave(self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None) -> bool: - """Shortcut for:: - - bot.leave_chat(update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.leave_chat`. - - Returns: - :obj:`bool` If the action was sent successfully. - - """ - return self.bot.leave_chat( - chat_id=self.id, - timeout=timeout, - api_kwargs=api_kwargs, - ) - - def get_administrators( - self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None - ) -> List['ChatMember']: - """Shortcut for:: - - bot.get_chat_administrators(update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.get_chat_administrators`. - - Returns: - List[:class:`telegram.ChatMember`]: A list of administrators in a chat. An Array of - :class:`telegram.ChatMember` objects that contains information about all - chat administrators except other bots. If the chat is a group or a supergroup - and no administrators were appointed, only the creator will be returned. - - """ - return self.bot.get_chat_administrators( - chat_id=self.id, - timeout=timeout, - api_kwargs=api_kwargs, - ) - - def get_members_count( - self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None - ) -> int: - """Shortcut for:: - - bot.get_chat_members_count(update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.get_chat_members_count`. - - Returns: - :obj:`int` - - """ - return self.bot.get_chat_members_count( - chat_id=self.id, - timeout=timeout, - api_kwargs=api_kwargs, - ) - - def get_member( - self, - user_id: Union[str, int], - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> 'ChatMember': - """Shortcut for:: - - bot.get_chat_member(update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.get_chat_member`. - - Returns: - :class:`telegram.ChatMember` - - """ - return self.bot.get_chat_member( - chat_id=self.id, - user_id=user_id, - timeout=timeout, - api_kwargs=api_kwargs, - ) - - def kick_member( - self, - user_id: Union[str, int], - timeout: ODVInput[float] = DEFAULT_NONE, - until_date: Union[int, datetime] = None, - api_kwargs: JSONDict = None, - revoke_messages: bool = None, - ) -> bool: - """Shortcut for:: - - bot.kick_chat_member(update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.kick_chat_member`. - - Returns: - :obj:`bool`: If the action was sent successfully. - - Note: - This method will only work if the `All Members Are Admins` setting is off in the - target group. Otherwise members may only be removed by the group's creator or by the - member that added them. - - """ - return self.bot.kick_chat_member( - chat_id=self.id, - user_id=user_id, - timeout=timeout, - until_date=until_date, - api_kwargs=api_kwargs, - revoke_messages=revoke_messages, - ) - - def unban_member( - self, - user_id: Union[str, int], - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - only_if_banned: bool = None, - ) -> bool: - """Shortcut for:: - - bot.unban_chat_member(update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.unban_chat_member`. - - Returns: - :obj:`bool`: If the action was sent successfully. - - """ - return self.bot.unban_chat_member( - chat_id=self.id, - user_id=user_id, - timeout=timeout, - api_kwargs=api_kwargs, - only_if_banned=only_if_banned, - ) - - def promote_member( - self, - user_id: Union[str, int], - can_change_info: bool = None, - can_post_messages: bool = None, - can_edit_messages: bool = None, - can_delete_messages: bool = None, - can_invite_users: bool = None, - can_restrict_members: bool = None, - can_pin_messages: bool = None, - can_promote_members: bool = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - is_anonymous: bool = None, - can_manage_chat: bool = None, - can_manage_voice_chats: bool = None, - ) -> bool: - """Shortcut for:: - - bot.promote_chat_member(update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.promote_chat_member`. - - .. versionadded:: 13.2 - - Returns: - :obj:`bool`: If the action was sent successfully. - - """ - return self.bot.promote_chat_member( - chat_id=self.id, - user_id=user_id, - can_change_info=can_change_info, - can_post_messages=can_post_messages, - can_edit_messages=can_edit_messages, - can_delete_messages=can_delete_messages, - can_invite_users=can_invite_users, - can_restrict_members=can_restrict_members, - can_pin_messages=can_pin_messages, - can_promote_members=can_promote_members, - timeout=timeout, - api_kwargs=api_kwargs, - is_anonymous=is_anonymous, - can_manage_chat=can_manage_chat, - can_manage_voice_chats=can_manage_voice_chats, - ) - - def restrict_member( - self, - user_id: Union[str, int], - permissions: ChatPermissions, - until_date: Union[int, datetime] = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> bool: - """Shortcut for:: - - bot.restrict_chat_member(update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.restrict_chat_member`. - - .. versionadded:: 13.2 - - Returns: - :obj:`bool`: If the action was sent successfully. - - """ - return self.bot.restrict_chat_member( - chat_id=self.id, - user_id=user_id, - permissions=permissions, - until_date=until_date, - timeout=timeout, - api_kwargs=api_kwargs, - ) - - def set_permissions( - self, - permissions: ChatPermissions, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> bool: - """Shortcut for:: - - bot.set_chat_permissions(update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.set_chat_permissions`. - - Returns: - :obj:`bool`: If the action was sent successfully. - - """ - return self.bot.set_chat_permissions( - chat_id=self.id, - permissions=permissions, - timeout=timeout, - api_kwargs=api_kwargs, - ) - - def set_administrator_custom_title( - self, - user_id: Union[int, str], - custom_title: str, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> bool: - """Shortcut for:: - - bot.set_chat_administrator_custom_title(update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.set_chat_administrator_custom_title`. - - Returns: - :obj:`bool`: If the action was sent successfully. - - """ - return self.bot.set_chat_administrator_custom_title( - chat_id=self.id, - user_id=user_id, - custom_title=custom_title, - timeout=timeout, - api_kwargs=api_kwargs, - ) - - def pin_message( - self, - message_id: int, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> bool: - """Shortcut for:: - - bot.pin_chat_message(chat_id=update.effective_chat.id, - *args, - **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.pin_chat_message`. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return self.bot.pin_chat_message( - chat_id=self.id, - message_id=message_id, - disable_notification=disable_notification, - timeout=timeout, - api_kwargs=api_kwargs, - ) - - def unpin_message( - self, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - message_id: int = None, - ) -> bool: - """Shortcut for:: - - bot.unpin_chat_message(chat_id=update.effective_chat.id, - *args, - **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.unpin_chat_message`. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return self.bot.unpin_chat_message( - chat_id=self.id, - timeout=timeout, - api_kwargs=api_kwargs, - message_id=message_id, - ) - - def unpin_all_messages( - self, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> bool: - """Shortcut for:: - - bot.unpin_all_chat_messages(chat_id=update.effective_chat.id, - *args, - **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.unpin_all_chat_messages`. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return self.bot.unpin_all_chat_messages( - chat_id=self.id, - timeout=timeout, - api_kwargs=api_kwargs, - ) - - def send_message( - self, - text: str, - parse_mode: ODVInput[str] = DEFAULT_NONE, - disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: 'ReplyMarkup' = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - ) -> 'Message': - """Shortcut for:: - - bot.send_message(update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_message`. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return self.bot.send_message( - chat_id=self.id, - text=text, - parse_mode=parse_mode, - disable_web_page_preview=disable_web_page_preview, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - entities=entities, - ) - - def send_media_group( - self, - media: List[ - Union['InputMediaAudio', 'InputMediaDocument', 'InputMediaPhoto', 'InputMediaVideo'] - ], - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - timeout: DVInput[float] = DEFAULT_20, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - ) -> List['Message']: - """Shortcut for:: - - bot.send_media_group(update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_media_group`. - - Returns: - List[:class:`telegram.Message`:] On success, instance representing the message posted. - - """ - return self.bot.send_media_group( - chat_id=self.id, - media=media, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - timeout=timeout, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - ) - - def send_chat_action( - self, - action: str, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> bool: - """Shortcut for:: - - bot.send_chat_action(update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_chat_action`. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return self.bot.send_chat_action( - chat_id=self.id, - action=action, - timeout=timeout, - api_kwargs=api_kwargs, - ) - - send_action = send_chat_action - """Alias for :attr:`send_chat_action`""" - - def send_photo( - self, - photo: Union[FileInput, 'PhotoSize'], - caption: str = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: 'ReplyMarkup' = None, - timeout: DVInput[float] = DEFAULT_20, - parse_mode: ODVInput[str] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - filename: str = None, - ) -> 'Message': - """Shortcut for:: - - bot.send_photo(update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_photo`. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return self.bot.send_photo( - chat_id=self.id, - photo=photo, - caption=caption, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - parse_mode=parse_mode, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - filename=filename, - ) - - def send_contact( - self, - phone_number: str = None, - first_name: str = None, - last_name: str = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: 'ReplyMarkup' = None, - timeout: ODVInput[float] = DEFAULT_NONE, - contact: 'Contact' = None, - vcard: str = None, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - ) -> 'Message': - """Shortcut for:: - - bot.send_contact(update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_contact`. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return self.bot.send_contact( - chat_id=self.id, - phone_number=phone_number, - first_name=first_name, - last_name=last_name, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - contact=contact, - vcard=vcard, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - ) - - def send_audio( - self, - audio: Union[FileInput, 'Audio'], - duration: int = None, - performer: str = None, - title: str = None, - caption: str = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: 'ReplyMarkup' = None, - timeout: DVInput[float] = DEFAULT_20, - parse_mode: ODVInput[str] = DEFAULT_NONE, - thumb: FileInput = None, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - filename: str = None, - ) -> 'Message': - """Shortcut for:: - - bot.send_audio(update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_audio`. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return self.bot.send_audio( - chat_id=self.id, - audio=audio, - duration=duration, - performer=performer, - title=title, - caption=caption, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - parse_mode=parse_mode, - thumb=thumb, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - filename=filename, - ) - - def send_document( - self, - document: Union[FileInput, 'Document'], - filename: str = None, - caption: str = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: 'ReplyMarkup' = None, - timeout: DVInput[float] = DEFAULT_20, - parse_mode: ODVInput[str] = DEFAULT_NONE, - thumb: FileInput = None, - api_kwargs: JSONDict = None, - disable_content_type_detection: bool = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - ) -> 'Message': - """Shortcut for:: - - bot.send_document(update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_document`. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return self.bot.send_document( - chat_id=self.id, - document=document, - filename=filename, - caption=caption, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - parse_mode=parse_mode, - thumb=thumb, - api_kwargs=api_kwargs, - disable_content_type_detection=disable_content_type_detection, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - ) - - def send_dice( - self, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: 'ReplyMarkup' = None, - timeout: ODVInput[float] = DEFAULT_NONE, - emoji: str = None, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - ) -> 'Message': - """Shortcut for:: - - bot.send_dice(update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_dice`. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return self.bot.send_dice( - chat_id=self.id, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - emoji=emoji, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - ) - - def send_game( - self, - game_short_name: str, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: 'InlineKeyboardMarkup' = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - ) -> 'Message': - """Shortcut for:: - - bot.send_game(update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_game`. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return self.bot.send_game( - chat_id=self.id, - game_short_name=game_short_name, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - ) - - def send_invoice( - self, - title: str, - description: str, - payload: str, - provider_token: str, - currency: str, - prices: List['LabeledPrice'], - start_parameter: str = None, - photo_url: str = None, - photo_size: int = None, - photo_width: int = None, - photo_height: int = None, - need_name: bool = None, - need_phone_number: bool = None, - need_email: bool = None, - need_shipping_address: bool = None, - is_flexible: bool = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: 'InlineKeyboardMarkup' = None, - provider_data: Union[str, object] = None, - send_phone_number_to_provider: bool = None, - send_email_to_provider: bool = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - max_tip_amount: int = None, - suggested_tip_amounts: List[int] = None, - ) -> 'Message': - """Shortcut for:: - - bot.send_invoice(update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_invoice`. - - Warning: - As of API 5.2 :attr:`start_parameter` is an optional argument and therefore the order - of the arguments had to be changed. Use keyword arguments to make sure that the - arguments are passed correctly. - - .. versionchanged:: 13.5 - As of Bot API 5.2, the parameter :attr:`start_parameter` is optional. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return self.bot.send_invoice( - chat_id=self.id, - title=title, - description=description, - payload=payload, - provider_token=provider_token, - currency=currency, - prices=prices, - start_parameter=start_parameter, - photo_url=photo_url, - photo_size=photo_size, - photo_width=photo_width, - photo_height=photo_height, - need_name=need_name, - need_phone_number=need_phone_number, - need_email=need_email, - need_shipping_address=need_shipping_address, - is_flexible=is_flexible, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - provider_data=provider_data, - send_phone_number_to_provider=send_phone_number_to_provider, - send_email_to_provider=send_email_to_provider, - timeout=timeout, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - max_tip_amount=max_tip_amount, - suggested_tip_amounts=suggested_tip_amounts, - ) - - def send_location( - self, - latitude: float = None, - longitude: float = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: 'ReplyMarkup' = None, - timeout: ODVInput[float] = DEFAULT_NONE, - location: 'Location' = None, - live_period: int = None, - api_kwargs: JSONDict = None, - horizontal_accuracy: float = None, - heading: int = None, - proximity_alert_radius: int = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - ) -> 'Message': - """Shortcut for:: - - bot.send_location(update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_location`. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return self.bot.send_location( - chat_id=self.id, - latitude=latitude, - longitude=longitude, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - location=location, - live_period=live_period, - api_kwargs=api_kwargs, - horizontal_accuracy=horizontal_accuracy, - heading=heading, - proximity_alert_radius=proximity_alert_radius, - allow_sending_without_reply=allow_sending_without_reply, - ) - - def send_animation( - self, - animation: Union[FileInput, 'Animation'], - duration: int = None, - width: int = None, - height: int = None, - thumb: FileInput = None, - caption: str = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: 'ReplyMarkup' = None, - timeout: DVInput[float] = DEFAULT_20, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - filename: str = None, - ) -> 'Message': - """Shortcut for:: - - bot.send_animation(update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_animation`. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return self.bot.send_animation( - chat_id=self.id, - animation=animation, - duration=duration, - width=width, - height=height, - thumb=thumb, - caption=caption, - parse_mode=parse_mode, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - filename=filename, - ) - - def send_sticker( - self, - sticker: Union[FileInput, 'Sticker'], - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: 'ReplyMarkup' = None, - timeout: DVInput[float] = DEFAULT_20, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - ) -> 'Message': - """Shortcut for:: - - bot.send_sticker(update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_sticker`. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return self.bot.send_sticker( - chat_id=self.id, - sticker=sticker, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - ) - - def send_venue( - self, - latitude: float = None, - longitude: float = None, - title: str = None, - address: str = None, - foursquare_id: str = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: 'ReplyMarkup' = None, - timeout: ODVInput[float] = DEFAULT_NONE, - venue: 'Venue' = None, - foursquare_type: str = None, - api_kwargs: JSONDict = None, - google_place_id: str = None, - google_place_type: str = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - ) -> 'Message': - """Shortcut for:: - - bot.send_venue(update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_venue`. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return self.bot.send_venue( - chat_id=self.id, - latitude=latitude, - longitude=longitude, - title=title, - address=address, - foursquare_id=foursquare_id, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - venue=venue, - foursquare_type=foursquare_type, - api_kwargs=api_kwargs, - google_place_id=google_place_id, - google_place_type=google_place_type, - allow_sending_without_reply=allow_sending_without_reply, - ) - - def send_video( - self, - video: Union[FileInput, 'Video'], - duration: int = None, - caption: str = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: 'ReplyMarkup' = None, - timeout: DVInput[float] = DEFAULT_20, - width: int = None, - height: int = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - supports_streaming: bool = None, - thumb: FileInput = None, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - filename: str = None, - ) -> 'Message': - """Shortcut for:: - - bot.send_video(update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_video`. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return self.bot.send_video( - chat_id=self.id, - video=video, - duration=duration, - caption=caption, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - width=width, - height=height, - parse_mode=parse_mode, - supports_streaming=supports_streaming, - thumb=thumb, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - filename=filename, - ) - - def send_video_note( - self, - video_note: Union[FileInput, 'VideoNote'], - duration: int = None, - length: int = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: 'ReplyMarkup' = None, - timeout: DVInput[float] = DEFAULT_20, - thumb: FileInput = None, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - filename: str = None, - ) -> 'Message': - """Shortcut for:: - - bot.send_video_note(update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_video_note`. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return self.bot.send_video_note( - chat_id=self.id, - video_note=video_note, - duration=duration, - length=length, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - thumb=thumb, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - filename=filename, - ) - - def send_voice( - self, - voice: Union[FileInput, 'Voice'], - duration: int = None, - caption: str = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: 'ReplyMarkup' = None, - timeout: DVInput[float] = DEFAULT_20, - parse_mode: ODVInput[str] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - filename: str = None, - ) -> 'Message': - """Shortcut for:: - - bot.send_voice(update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_voice`. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return self.bot.send_voice( - chat_id=self.id, - voice=voice, - duration=duration, - caption=caption, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - parse_mode=parse_mode, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - filename=filename, - ) - - def send_poll( - self, - question: str, - options: List[str], - is_anonymous: bool = True, - # We use constant.POLL_REGULAR instead of Poll.REGULAR here to avoid circular imports - type: str = constants.POLL_REGULAR, # pylint: disable=W0622 - allows_multiple_answers: bool = False, - correct_option_id: int = None, - is_closed: bool = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: 'ReplyMarkup' = None, - timeout: ODVInput[float] = DEFAULT_NONE, - explanation: str = None, - explanation_parse_mode: ODVInput[str] = DEFAULT_NONE, - open_period: int = None, - close_date: Union[int, datetime] = None, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - explanation_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - ) -> 'Message': - """Shortcut for:: - - bot.send_poll(update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_poll`. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return self.bot.send_poll( - chat_id=self.id, - question=question, - options=options, - is_anonymous=is_anonymous, - type=type, # pylint=pylint, - allows_multiple_answers=allows_multiple_answers, - correct_option_id=correct_option_id, - is_closed=is_closed, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - explanation=explanation, - explanation_parse_mode=explanation_parse_mode, - open_period=open_period, - close_date=close_date, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - explanation_entities=explanation_entities, - ) - - def send_copy( - self, - from_chat_id: Union[str, int], - message_id: int, - caption: str = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[Tuple['MessageEntity', ...], List['MessageEntity']] = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE, - reply_markup: 'ReplyMarkup' = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> 'MessageId': - """Shortcut for:: - - bot.copy_message(chat_id=update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.copy_message`. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return self.bot.copy_message( - chat_id=self.id, - from_chat_id=from_chat_id, - message_id=message_id, - caption=caption, - parse_mode=parse_mode, - caption_entities=caption_entities, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - allow_sending_without_reply=allow_sending_without_reply, - reply_markup=reply_markup, - timeout=timeout, - api_kwargs=api_kwargs, - ) - - def copy_message( - self, - chat_id: Union[int, str], - message_id: int, - caption: str = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[Tuple['MessageEntity', ...], List['MessageEntity']] = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE, - reply_markup: 'ReplyMarkup' = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> 'MessageId': - """Shortcut for:: - - bot.copy_message(from_chat_id=update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.copy_message`. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return self.bot.copy_message( - from_chat_id=self.id, - chat_id=chat_id, - message_id=message_id, - caption=caption, - parse_mode=parse_mode, - caption_entities=caption_entities, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - allow_sending_without_reply=allow_sending_without_reply, - reply_markup=reply_markup, - timeout=timeout, - api_kwargs=api_kwargs, - ) - - def export_invite_link( - self, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> str: - """Shortcut for:: - - bot.export_chat_invite_link(chat_id=update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.export_chat_invite_link`. - - .. versionadded:: 13.4 - - Returns: - :obj:`str`: New invite link on success. - - """ - return self.bot.export_chat_invite_link( - chat_id=self.id, timeout=timeout, api_kwargs=api_kwargs - ) - - def create_invite_link( - self, - expire_date: Union[int, datetime] = None, - member_limit: int = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> 'ChatInviteLink': - """Shortcut for:: - - bot.create_chat_invite_link(chat_id=update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.create_chat_invite_link`. - - .. versionadded:: 13.4 - - Returns: - :class:`telegram.ChatInviteLink` - - """ - return self.bot.create_chat_invite_link( - chat_id=self.id, - expire_date=expire_date, - member_limit=member_limit, - timeout=timeout, - api_kwargs=api_kwargs, - ) - - def edit_invite_link( - self, - invite_link: str, - expire_date: Union[int, datetime] = None, - member_limit: int = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> 'ChatInviteLink': - """Shortcut for:: - - bot.edit_chat_invite_link(chat_id=update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.edit_chat_invite_link`. - - .. versionadded:: 13.4 - - Returns: - :class:`telegram.ChatInviteLink` - - """ - return self.bot.edit_chat_invite_link( - chat_id=self.id, - invite_link=invite_link, - expire_date=expire_date, - member_limit=member_limit, - timeout=timeout, - api_kwargs=api_kwargs, - ) - - def revoke_invite_link( - self, - invite_link: str, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> 'ChatInviteLink': - """Shortcut for:: - - bot.revoke_chat_invite_link(chat_id=update.effective_chat.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.revoke_chat_invite_link`. - - .. versionadded:: 13.4 - - Returns: - :class:`telegram.ChatInviteLink` - - """ - return self.bot.revoke_chat_invite_link( - chat_id=self.id, invite_link=invite_link, timeout=timeout, api_kwargs=api_kwargs - ) diff --git a/venv/lib/python3.8/site-packages/telegram/chataction.py b/venv/lib/python3.8/site-packages/telegram/chataction.py deleted file mode 100644 index c737b81..0000000 --- a/venv/lib/python3.8/site-packages/telegram/chataction.py +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env python -# pylint: disable=R0903 -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram ChatAction.""" -from typing import ClassVar -from telegram import constants -from telegram.utils.deprecate import set_new_attribute_deprecated - - -class ChatAction: - """Helper class to provide constants for different chat actions.""" - - __slots__ = ('__dict__',) # Adding __dict__ here since it doesn't subclass TGObject - FIND_LOCATION: ClassVar[str] = constants.CHATACTION_FIND_LOCATION - """:const:`telegram.constants.CHATACTION_FIND_LOCATION`""" - RECORD_AUDIO: ClassVar[str] = constants.CHATACTION_RECORD_AUDIO - """:const:`telegram.constants.CHATACTION_RECORD_AUDIO` - - .. deprecated:: 13.5 - Deprecated by Telegram. Use :attr:`RECORD_VOICE` instead. - """ - RECORD_VOICE: ClassVar[str] = constants.CHATACTION_RECORD_VOICE - """:const:`telegram.constants.CHATACTION_RECORD_VOICE` - - .. versionadded:: 13.5 - """ - RECORD_VIDEO: ClassVar[str] = constants.CHATACTION_RECORD_VIDEO - """:const:`telegram.constants.CHATACTION_RECORD_VIDEO`""" - RECORD_VIDEO_NOTE: ClassVar[str] = constants.CHATACTION_RECORD_VIDEO_NOTE - """:const:`telegram.constants.CHATACTION_RECORD_VIDEO_NOTE`""" - TYPING: ClassVar[str] = constants.CHATACTION_TYPING - """:const:`telegram.constants.CHATACTION_TYPING`""" - UPLOAD_AUDIO: ClassVar[str] = constants.CHATACTION_UPLOAD_AUDIO - """:const:`telegram.constants.CHATACTION_UPLOAD_AUDIO` - - .. deprecated:: 13.5 - Deprecated by Telegram. Use :attr:`UPLOAD_VOICE` instead. - """ - UPLOAD_VOICE: ClassVar[str] = constants.CHATACTION_UPLOAD_VOICE - """:const:`telegram.constants.CHATACTION_UPLOAD_VOICE` - - .. versionadded:: 13.5 - """ - UPLOAD_DOCUMENT: ClassVar[str] = constants.CHATACTION_UPLOAD_DOCUMENT - """:const:`telegram.constants.CHATACTION_UPLOAD_DOCUMENT`""" - UPLOAD_PHOTO: ClassVar[str] = constants.CHATACTION_UPLOAD_PHOTO - """:const:`telegram.constants.CHATACTION_UPLOAD_PHOTO`""" - UPLOAD_VIDEO: ClassVar[str] = constants.CHATACTION_UPLOAD_VIDEO - """:const:`telegram.constants.CHATACTION_UPLOAD_VIDEO`""" - UPLOAD_VIDEO_NOTE: ClassVar[str] = constants.CHATACTION_UPLOAD_VIDEO_NOTE - """:const:`telegram.constants.CHATACTION_UPLOAD_VIDEO_NOTE`""" - - def __setattr__(self, key: str, value: object) -> None: - set_new_attribute_deprecated(self, key, value) diff --git a/venv/lib/python3.8/site-packages/telegram/chatinvitelink.py b/venv/lib/python3.8/site-packages/telegram/chatinvitelink.py deleted file mode 100644 index 0755853..0000000 --- a/venv/lib/python3.8/site-packages/telegram/chatinvitelink.py +++ /dev/null @@ -1,114 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents an invite link for a chat.""" -import datetime -from typing import TYPE_CHECKING, Any, Optional - -from telegram import TelegramObject, User -from telegram.utils.helpers import from_timestamp, to_timestamp -from telegram.utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - - -class ChatInviteLink(TelegramObject): - """This object represents an invite link for a chat. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`invite_link`, :attr:`creator`, :attr:`is_primary` and - :attr:`is_revoked` are equal. - - .. versionadded:: 13.4 - - Args: - invite_link (:obj:`str`): The invite link. - creator (:class:`telegram.User`): Creator of the link. - is_primary (:obj:`bool`): :obj:`True`, if the link is primary. - is_revoked (:obj:`bool`): :obj:`True`, if the link is revoked. - expire_date (:class:`datetime.datetime`, optional): Date when the link will expire or - has been expired. - member_limit (:obj:`int`, optional): Maximum number of users that can be members of the - chat simultaneously after joining the chat via this invite link; 1-99999. - - Attributes: - invite_link (:obj:`str`): The invite link. If the link was created by another chat - administrator, then the second part of the link will be replaced with ``'…'``. - creator (:class:`telegram.User`): Creator of the link. - is_primary (:obj:`bool`): :obj:`True`, if the link is primary. - is_revoked (:obj:`bool`): :obj:`True`, if the link is revoked. - expire_date (:class:`datetime.datetime`): Optional. Date when the link will expire or - has been expired. - member_limit (:obj:`int`): Optional. Maximum number of users that can be members - of the chat simultaneously after joining the chat via this invite link; 1-99999. - - """ - - __slots__ = ( - 'invite_link', - 'creator', - 'is_primary', - 'is_revoked', - 'expire_date', - 'member_limit', - '_id_attrs', - ) - - def __init__( - self, - invite_link: str, - creator: User, - is_primary: bool, - is_revoked: bool, - expire_date: datetime.datetime = None, - member_limit: int = None, - **_kwargs: Any, - ): - # Required - self.invite_link = invite_link - self.creator = creator - self.is_primary = is_primary - self.is_revoked = is_revoked - - # Optionals - self.expire_date = expire_date - self.member_limit = int(member_limit) if member_limit is not None else None - - self._id_attrs = (self.invite_link, self.creator, self.is_primary, self.is_revoked) - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['ChatInviteLink']: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data['creator'] = User.de_json(data.get('creator'), bot) - data['expire_date'] = from_timestamp(data.get('expire_date', None)) - - return cls(**data) - - def to_dict(self) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict() - - data['expire_date'] = to_timestamp(self.expire_date) - - return data diff --git a/venv/lib/python3.8/site-packages/telegram/chatlocation.py b/venv/lib/python3.8/site-packages/telegram/chatlocation.py deleted file mode 100644 index dcdbb6f..0000000 --- a/venv/lib/python3.8/site-packages/telegram/chatlocation.py +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a location to which a chat is connected.""" - -from typing import TYPE_CHECKING, Any, Optional - -from telegram import TelegramObject -from telegram.utils.types import JSONDict - -from .files.location import Location - -if TYPE_CHECKING: - from telegram import Bot - - -class ChatLocation(TelegramObject): - """This object represents a location to which a chat is connected. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`location` is equal. - - Args: - location (:class:`telegram.Location`): The location to which the supergroup is connected. - Can't be a live location. - address (:obj:`str`): Location address; 1-64 characters, as defined by the chat owner - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - location (:class:`telegram.Location`): The location to which the supergroup is connected. - address (:obj:`str`): Location address, as defined by the chat owner - - """ - - __slots__ = ('location', '_id_attrs', 'address') - - def __init__( - self, - location: Location, - address: str, - **_kwargs: Any, - ): - self.location = location - self.address = address - - self._id_attrs = (self.location,) - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['ChatLocation']: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data['location'] = Location.de_json(data.get('location'), bot) - - return cls(bot=bot, **data) diff --git a/venv/lib/python3.8/site-packages/telegram/chatmember.py b/venv/lib/python3.8/site-packages/telegram/chatmember.py deleted file mode 100644 index 3246c4b..0000000 --- a/venv/lib/python3.8/site-packages/telegram/chatmember.py +++ /dev/null @@ -1,253 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram ChatMember.""" -import datetime -from typing import TYPE_CHECKING, Any, Optional, ClassVar - -from telegram import TelegramObject, User, constants -from telegram.utils.helpers import from_timestamp, to_timestamp -from telegram.utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - - -class ChatMember(TelegramObject): - """This object contains information about one member of a chat. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`user` and :attr:`status` are equal. - - Args: - user (:class:`telegram.User`): Information about the user. - status (:obj:`str`): The member's status in the chat. Can be 'creator', 'administrator', - 'member', 'restricted', 'left' or 'kicked'. - custom_title (:obj:`str`, optional): Owner and administrators only. - Custom title for this user. - is_anonymous (:obj:`bool`, optional): Owner and administrators only. :obj:`True`, if the - user's presence in the chat is hidden. - until_date (:class:`datetime.datetime`, optional): Restricted and kicked only. Date when - restrictions will be lifted for this user. - can_be_edited (:obj:`bool`, optional): Administrators only. :obj:`True`, if the bot is - allowed to edit administrator privileges of that user. - can_manage_chat (:obj:`bool`, optional): Administrators only. :obj:`True`, if the - administrator can access the chat event log, chat statistics, message statistics in - channels, see channel members, see anonymous administrators in supergroups and ignore - slow mode. Implied by any other administrator privilege. - - .. versionadded:: 13.4 - - can_manage_voice_chats (:obj:`bool`, optional): Administrators only. :obj:`True`, if the - administrator can manage voice chats. - - .. versionadded:: 13.4 - - can_change_info (:obj:`bool`, optional): Administrators and restricted only. :obj:`True`, - if the user can change the chat title, photo and other settings. - can_post_messages (:obj:`bool`, optional): Administrators only. :obj:`True`, if the - administrator can post in the channel, channels only. - can_edit_messages (:obj:`bool`, optional): Administrators only. :obj:`True`, if the - administrator can edit messages of other users and can pin messages; channels only. - can_delete_messages (:obj:`bool`, optional): Administrators only. :obj:`True`, if the - administrator can delete messages of other users. - can_invite_users (:obj:`bool`, optional): Administrators and restricted only. :obj:`True`, - if the user can invite new users to the chat. - can_restrict_members (:obj:`bool`, optional): Administrators only. :obj:`True`, if the - administrator can restrict, ban or unban chat members. - can_pin_messages (:obj:`bool`, optional): Administrators and restricted only. :obj:`True`, - if the user can pin messages, groups and supergroups only. - can_promote_members (:obj:`bool`, optional): Administrators only. :obj:`True`, if the - administrator can add new administrators with a subset of his own privileges or demote - administrators that he has promoted, directly or indirectly (promoted by administrators - that were appointed by the user). - is_member (:obj:`bool`, optional): Restricted only. :obj:`True`, if the user is a member of - the chat at the moment of the request. - can_send_messages (:obj:`bool`, optional): Restricted only. :obj:`True`, if the user can - send text messages, contacts, locations and venues. - can_send_media_messages (:obj:`bool`, optional): Restricted only. :obj:`True`, if the user - can send audios, documents, photos, videos, video notes and voice notes. - can_send_polls (:obj:`bool`, optional): Restricted only. :obj:`True`, if the user is - allowed to send polls. - can_send_other_messages (:obj:`bool`, optional): Restricted only. :obj:`True`, if the user - can send animations, games, stickers and use inline bots. - can_add_web_page_previews (:obj:`bool`, optional): Restricted only. :obj:`True`, if user - may add web page previews to his messages. - - Attributes: - user (:class:`telegram.User`): Information about the user. - status (:obj:`str`): The member's status in the chat. - custom_title (:obj:`str`): Optional. Custom title for owner and administrators. - is_anonymous (:obj:`bool`): Optional. :obj:`True`, if the user's presence in the chat is - hidden. - until_date (:class:`datetime.datetime`): Optional. Date when restrictions will be lifted - for this user. - can_be_edited (:obj:`bool`): Optional. If the bot is allowed to edit administrator - privileges of that user. - can_manage_chat (:obj:`bool`): Optional. If the administrator can access the chat event - log, chat statistics, message statistics in channels, see channel members, see - anonymous administrators in supergroups and ignore slow mode. - - .. versionadded:: 13.4 - - can_manage_voice_chats (:obj:`bool`): Optional. if the administrator can manage - voice chats. - - .. versionadded:: 13.4 - - can_change_info (:obj:`bool`): Optional. If the user can change the chat title, photo and - other settings. - can_post_messages (:obj:`bool`): Optional. If the administrator can post in the channel. - can_edit_messages (:obj:`bool`): Optional. If the administrator can edit messages of other - users. - can_delete_messages (:obj:`bool`): Optional. If the administrator can delete messages of - other users. - can_invite_users (:obj:`bool`): Optional. If the user can invite new users to the chat. - can_restrict_members (:obj:`bool`): Optional. If the administrator can restrict, ban or - unban chat members. - can_pin_messages (:obj:`bool`): Optional. If the user can pin messages. - can_promote_members (:obj:`bool`): Optional. If the administrator can add new - administrators. - is_member (:obj:`bool`): Optional. Restricted only. :obj:`True`, if the user is a member of - the chat at the moment of the request. - can_send_messages (:obj:`bool`): Optional. If the user can send text messages, contacts, - locations and venues. - can_send_media_messages (:obj:`bool`): Optional. If the user can send media messages, - implies can_send_messages. - can_send_polls (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to - send polls. - can_send_other_messages (:obj:`bool`): Optional. If the user can send animations, games, - stickers and use inline bots, implies can_send_media_messages. - can_add_web_page_previews (:obj:`bool`): Optional. If user may add web page previews to his - messages, implies can_send_media_messages - - """ - - __slots__ = ( - 'is_member', - 'can_restrict_members', - 'can_delete_messages', - 'custom_title', - 'can_be_edited', - 'can_post_messages', - 'can_send_messages', - 'can_edit_messages', - 'can_send_media_messages', - 'is_anonymous', - 'can_add_web_page_previews', - 'can_send_other_messages', - 'can_invite_users', - 'can_send_polls', - 'user', - 'can_promote_members', - 'status', - 'can_change_info', - 'can_pin_messages', - 'can_manage_chat', - 'can_manage_voice_chats', - 'until_date', - '_id_attrs', - ) - - ADMINISTRATOR: ClassVar[str] = constants.CHATMEMBER_ADMINISTRATOR - """:const:`telegram.constants.CHATMEMBER_ADMINISTRATOR`""" - CREATOR: ClassVar[str] = constants.CHATMEMBER_CREATOR - """:const:`telegram.constants.CHATMEMBER_CREATOR`""" - KICKED: ClassVar[str] = constants.CHATMEMBER_KICKED - """:const:`telegram.constants.CHATMEMBER_KICKED`""" - LEFT: ClassVar[str] = constants.CHATMEMBER_LEFT - """:const:`telegram.constants.CHATMEMBER_LEFT`""" - MEMBER: ClassVar[str] = constants.CHATMEMBER_MEMBER - """:const:`telegram.constants.CHATMEMBER_MEMBER`""" - RESTRICTED: ClassVar[str] = constants.CHATMEMBER_RESTRICTED - """:const:`telegram.constants.CHATMEMBER_RESTRICTED`""" - - def __init__( - self, - user: User, - status: str, - until_date: datetime.datetime = None, - can_be_edited: bool = None, - can_change_info: bool = None, - can_post_messages: bool = None, - can_edit_messages: bool = None, - can_delete_messages: bool = None, - can_invite_users: bool = None, - can_restrict_members: bool = None, - can_pin_messages: bool = None, - can_promote_members: bool = None, - can_send_messages: bool = None, - can_send_media_messages: bool = None, - can_send_polls: bool = None, - can_send_other_messages: bool = None, - can_add_web_page_previews: bool = None, - is_member: bool = None, - custom_title: str = None, - is_anonymous: bool = None, - can_manage_chat: bool = None, - can_manage_voice_chats: bool = None, - **_kwargs: Any, - ): - # Required - self.user = user - self.status = status - - # Optionals - self.custom_title = custom_title - self.is_anonymous = is_anonymous - self.until_date = until_date - self.can_be_edited = can_be_edited - self.can_change_info = can_change_info - self.can_post_messages = can_post_messages - self.can_edit_messages = can_edit_messages - self.can_delete_messages = can_delete_messages - self.can_invite_users = can_invite_users - self.can_restrict_members = can_restrict_members - self.can_pin_messages = can_pin_messages - self.can_promote_members = can_promote_members - self.can_send_messages = can_send_messages - self.can_send_media_messages = can_send_media_messages - self.can_send_polls = can_send_polls - self.can_send_other_messages = can_send_other_messages - self.can_add_web_page_previews = can_add_web_page_previews - self.is_member = is_member - self.can_manage_chat = can_manage_chat - self.can_manage_voice_chats = can_manage_voice_chats - - self._id_attrs = (self.user, self.status) - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['ChatMember']: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data['user'] = User.de_json(data.get('user'), bot) - data['until_date'] = from_timestamp(data.get('until_date', None)) - - return cls(**data) - - def to_dict(self) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict() - - data['until_date'] = to_timestamp(self.until_date) - - return data diff --git a/venv/lib/python3.8/site-packages/telegram/chatmemberupdated.py b/venv/lib/python3.8/site-packages/telegram/chatmemberupdated.py deleted file mode 100644 index 4d49a6c..0000000 --- a/venv/lib/python3.8/site-packages/telegram/chatmemberupdated.py +++ /dev/null @@ -1,173 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram ChatMemberUpdated.""" -import datetime -from typing import TYPE_CHECKING, Any, Optional, Dict, Tuple, Union - -from telegram import TelegramObject, User, Chat, ChatMember, ChatInviteLink -from telegram.utils.helpers import from_timestamp, to_timestamp -from telegram.utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - - -class ChatMemberUpdated(TelegramObject): - """This object represents changes in the status of a chat member. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`chat`, :attr:`from_user`, :attr:`date`, - :attr:`old_chat_member` and :attr:`new_chat_member` are equal. - - .. versionadded:: 13.4 - - Note: - In Python ``from`` is a reserved word, use ``from_user`` instead. - - Args: - chat (:class:`telegram.Chat`): Chat the user belongs to. - from_user (:class:`telegram.User`): Performer of the action, which resulted in the change. - date (:class:`datetime.datetime`): Date the change was done in Unix time. Converted to - :class:`datetime.datetime`. - old_chat_member (:class:`telegram.ChatMember`): Previous information about the chat member. - new_chat_member (:class:`telegram.ChatMember`): New information about the chat member. - invite_link (:class:`telegram.ChatInviteLink`, optional): Chat invite link, which was used - by the user to join the chat. For joining by invite link events only. - - Attributes: - chat (:class:`telegram.Chat`): Chat the user belongs to. - from_user (:class:`telegram.User`): Performer of the action, which resulted in the change. - date (:class:`datetime.datetime`): Date the change was done in Unix time. Converted to - :class:`datetime.datetime`. - old_chat_member (:class:`telegram.ChatMember`): Previous information about the chat member. - new_chat_member (:class:`telegram.ChatMember`): New information about the chat member. - invite_link (:class:`telegram.ChatInviteLink`): Optional. Chat invite link, which was used - by the user to join the chat. - - """ - - __slots__ = ( - 'chat', - 'from_user', - 'date', - 'old_chat_member', - 'new_chat_member', - 'invite_link', - '_id_attrs', - ) - - def __init__( - self, - chat: Chat, - from_user: User, - date: datetime.datetime, - old_chat_member: ChatMember, - new_chat_member: ChatMember, - invite_link: ChatInviteLink = None, - **_kwargs: Any, - ): - # Required - self.chat = chat - self.from_user = from_user - self.date = date - self.old_chat_member = old_chat_member - self.new_chat_member = new_chat_member - - # Optionals - self.invite_link = invite_link - - self._id_attrs = ( - self.chat, - self.from_user, - self.date, - self.old_chat_member, - self.new_chat_member, - ) - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['ChatMemberUpdated']: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data['chat'] = Chat.de_json(data.get('chat'), bot) - data['from_user'] = User.de_json(data.get('from'), bot) - data['date'] = from_timestamp(data.get('date')) - data['old_chat_member'] = ChatMember.de_json(data.get('old_chat_member'), bot) - data['new_chat_member'] = ChatMember.de_json(data.get('new_chat_member'), bot) - data['invite_link'] = ChatInviteLink.de_json(data.get('invite_link'), bot) - - return cls(**data) - - def to_dict(self) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict() - - # Required - data['date'] = to_timestamp(self.date) - - return data - - def difference( - self, - ) -> Dict[ - str, - Tuple[ - Union[str, bool, datetime.datetime, User], Union[str, bool, datetime.datetime, User] - ], - ]: - """Computes the difference between :attr:`old_chat_member` and :attr:`new_chat_member`. - - Example: - .. code:: python - - >>> chat_member_updated.difference() - {'custom_title': ('old title', 'new title')} - - Note: - To determine, if the :attr:`telegram.ChatMember.user` attribute has changed, *every* - attribute of the user will be checked. - - .. versionadded:: 13.5 - - Returns: - Dict[:obj:`str`, Tuple[:obj:`obj`, :obj:`obj`]]: A dictionary mapping attribute names - to tuples of the form ``(old_value, new_value)`` - """ - # we first get the names of the attributes that have changed - # user.to_dict() is unhashable, so that needs some special casing further down - old_dict = self.old_chat_member.to_dict() - old_user_dict = old_dict.pop('user') - new_dict = self.new_chat_member.to_dict() - new_user_dict = new_dict.pop('user') - - # Generator for speed: we only need to iterate over it once - # we can't directly use the values from old_dict ^ new_dict b/c that set is unordered - attributes = (entry[0] for entry in set(old_dict.items()) ^ set(new_dict.items())) - - result = { - attribute: (self.old_chat_member[attribute], self.new_chat_member[attribute]) - for attribute in attributes - } - if old_user_dict != new_user_dict: - result['user'] = (self.old_chat_member.user, self.new_chat_member.user) - - return result # type: ignore[return-value] diff --git a/venv/lib/python3.8/site-packages/telegram/chatpermissions.py b/venv/lib/python3.8/site-packages/telegram/chatpermissions.py deleted file mode 100644 index 0b5a7b9..0000000 --- a/venv/lib/python3.8/site-packages/telegram/chatpermissions.py +++ /dev/null @@ -1,124 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram ChatPermission.""" - -from typing import Any - -from telegram import TelegramObject - - -class ChatPermissions(TelegramObject): - """Describes actions that a non-administrator user is allowed to take in a chat. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`can_send_messages`, :attr:`can_send_media_messages`, - :attr:`can_send_polls`, :attr:`can_send_other_messages`, :attr:`can_add_web_page_previews`, - :attr:`can_change_info`, :attr:`can_invite_users` and :attr:`can_pin_messages` are equal. - - Note: - Though not stated explicitly in the official docs, Telegram changes not only the - permissions that are set, but also sets all the others to :obj:`False`. However, since not - documented, this behaviour may change unbeknown to PTB. - - Args: - can_send_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed to send text - messages, contacts, locations and venues. - can_send_media_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed to - send audios, documents, photos, videos, video notes and voice notes, implies - :attr:`can_send_messages`. - can_send_polls (:obj:`bool`, optional): :obj:`True`, if the user is allowed to send polls, - implies :attr:`can_send_messages`. - can_send_other_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed to - send animations, games, stickers and use inline bots, implies - :attr:`can_send_media_messages`. - can_add_web_page_previews (:obj:`bool`, optional): :obj:`True`, if the user is allowed to - add web page previews to their messages, implies :attr:`can_send_media_messages`. - can_change_info (:obj:`bool`, optional): :obj:`True`, if the user is allowed to change the - chat title, photo and other settings. Ignored in public supergroups. - can_invite_users (:obj:`bool`, optional): :obj:`True`, if the user is allowed to invite new - users to the chat. - can_pin_messages (:obj:`bool`, optional): :obj:`True`, if the user is allowed to pin - messages. Ignored in public supergroups. - - Attributes: - can_send_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to send text - messages, contacts, locations and venues. - can_send_media_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to - send audios, documents, photos, videos, video notes and voice notes, implies - :attr:`can_send_messages`. - can_send_polls (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to send polls, - implies :attr:`can_send_messages`. - can_send_other_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to - send animations, games, stickers and use inline bots, implies - :attr:`can_send_media_messages`. - can_add_web_page_previews (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to - add web page previews to their messages, implies :attr:`can_send_media_messages`. - can_change_info (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to change the - chat title, photo and other settings. Ignored in public supergroups. - can_invite_users (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to invite - new users to the chat. - can_pin_messages (:obj:`bool`): Optional. :obj:`True`, if the user is allowed to pin - messages. Ignored in public supergroups. - - """ - - __slots__ = ( - 'can_send_other_messages', - 'can_invite_users', - 'can_send_polls', - '_id_attrs', - 'can_send_messages', - 'can_send_media_messages', - 'can_change_info', - 'can_pin_messages', - 'can_add_web_page_previews', - ) - - def __init__( - self, - can_send_messages: bool = None, - can_send_media_messages: bool = None, - can_send_polls: bool = None, - can_send_other_messages: bool = None, - can_add_web_page_previews: bool = None, - can_change_info: bool = None, - can_invite_users: bool = None, - can_pin_messages: bool = None, - **_kwargs: Any, - ): - # Required - self.can_send_messages = can_send_messages - self.can_send_media_messages = can_send_media_messages - self.can_send_polls = can_send_polls - self.can_send_other_messages = can_send_other_messages - self.can_add_web_page_previews = can_add_web_page_previews - self.can_change_info = can_change_info - self.can_invite_users = can_invite_users - self.can_pin_messages = can_pin_messages - - self._id_attrs = ( - self.can_send_messages, - self.can_send_media_messages, - self.can_send_polls, - self.can_send_other_messages, - self.can_add_web_page_previews, - self.can_change_info, - self.can_invite_users, - self.can_pin_messages, - ) diff --git a/venv/lib/python3.8/site-packages/telegram/choseninlineresult.py b/venv/lib/python3.8/site-packages/telegram/choseninlineresult.py deleted file mode 100644 index 384d57e..0000000 --- a/venv/lib/python3.8/site-packages/telegram/choseninlineresult.py +++ /dev/null @@ -1,98 +0,0 @@ -#!/usr/bin/env python -# pylint: disable=R0902,R0913 -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram ChosenInlineResult.""" - -from typing import TYPE_CHECKING, Any, Optional - -from telegram import Location, TelegramObject, User -from telegram.utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - - -class ChosenInlineResult(TelegramObject): - """ - Represents a result of an inline query that was chosen by the user and sent to their chat - partner. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`result_id` is equal. - - Note: - * In Python ``from`` is a reserved word, use ``from_user`` instead. - * It is necessary to enable inline feedback via `@Botfather <https://t.me/BotFather>`_ in - order to receive these objects in updates. - - Args: - result_id (:obj:`str`): The unique identifier for the result that was chosen. - from_user (:class:`telegram.User`): The user that chose the result. - location (:class:`telegram.Location`, optional): Sender location, only for bots that - require user location. - inline_message_id (:obj:`str`, optional): Identifier of the sent inline message. Available - only if there is an inline keyboard attached to the message. Will be also received in - callback queries and can be used to edit the message. - query (:obj:`str`): The query that was used to obtain the result. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - result_id (:obj:`str`): The unique identifier for the result that was chosen. - from_user (:class:`telegram.User`): The user that chose the result. - location (:class:`telegram.Location`): Optional. Sender location. - inline_message_id (:obj:`str`): Optional. Identifier of the sent inline message. - query (:obj:`str`): The query that was used to obtain the result. - - """ - - __slots__ = ('location', 'result_id', 'from_user', 'inline_message_id', '_id_attrs', 'query') - - def __init__( - self, - result_id: str, - from_user: User, - query: str, - location: Location = None, - inline_message_id: str = None, - **_kwargs: Any, - ): - # Required - self.result_id = result_id - self.from_user = from_user - self.query = query - # Optionals - self.location = location - self.inline_message_id = inline_message_id - - self._id_attrs = (self.result_id,) - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['ChosenInlineResult']: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - # Required - data['from_user'] = User.de_json(data.pop('from'), bot) - # Optionals - data['location'] = Location.de_json(data.get('location'), bot) - - return cls(**data) diff --git a/venv/lib/python3.8/site-packages/telegram/constants.py b/venv/lib/python3.8/site-packages/telegram/constants.py deleted file mode 100644 index 02cb2d2..0000000 --- a/venv/lib/python3.8/site-packages/telegram/constants.py +++ /dev/null @@ -1,345 +0,0 @@ -# python-telegram-bot - a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# by the python-telegram-bot contributors <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""Constants in the Telegram network. - -The following constants were extracted from the -`Telegram Bots FAQ <https://core.telegram.org/bots/faq>`_ and -`Telegram Bots API <https://core.telegram.org/bots/api>`_. - -Attributes: - BOT_API_VERSION (:obj:`str`): `5.2`. Telegram Bot API version supported by this - version of `python-telegram-bot`. Also available as ``telegram.bot_api_version``. - - .. versionadded:: 13.4 - MAX_MESSAGE_LENGTH (:obj:`int`): 4096 - MAX_CAPTION_LENGTH (:obj:`int`): 1024 - SUPPORTED_WEBHOOK_PORTS (List[:obj:`int`]): [443, 80, 88, 8443] - MAX_FILESIZE_DOWNLOAD (:obj:`int`): In bytes (20MB) - MAX_FILESIZE_UPLOAD (:obj:`int`): In bytes (50MB) - MAX_PHOTOSIZE_UPLOAD (:obj:`int`): In bytes (10MB) - MAX_MESSAGES_PER_SECOND_PER_CHAT (:obj:`int`): `1`. Telegram may allow short bursts that go - over this limit, but eventually you'll begin receiving 429 errors. - MAX_MESSAGES_PER_SECOND (:obj:`int`): 30 - MAX_MESSAGES_PER_MINUTE_PER_GROUP (:obj:`int`): 20 - MAX_INLINE_QUERY_RESULTS (:obj:`int`): 50 - MAX_ANSWER_CALLBACK_QUERY_TEXT_LENGTH (:obj:`int`): 200 - - .. versionadded:: 13.2 - -The following constant have been found by experimentation: - -Attributes: - MAX_MESSAGE_ENTITIES (:obj:`int`): 100 (Beyond this cap telegram will simply ignore further - formatting styles) - ANONYMOUS_ADMIN_ID (:obj:`int`): ``1087968824`` (User id in groups for anonymous admin) - SERVICE_CHAT_ID (:obj:`int`): ``777000`` (Telegram service chat, that also acts as sender of - channel posts forwarded to discussion groups) - -The following constants are related to specific classes and are also available -as attributes of those classes: - -:class:`telegram.Chat`: - -Attributes: - CHAT_PRIVATE (:obj:`str`): ``'private'`` - CHAT_GROUP (:obj:`str`): ``'group'`` - CHAT_SUPERGROUP (:obj:`str`): ``'supergroup'`` - CHAT_CHANNEL (:obj:`str`): ``'channel'`` - CHAT_SENDER (:obj:`str`): ``'sender'``. Only relevant for - :attr:`telegram.InlineQuery.chat_type`. - - .. versionadded:: 13.5 - -:class:`telegram.ChatAction`: - -Attributes: - CHATACTION_FIND_LOCATION (:obj:`str`): ``'find_location'`` - CHATACTION_RECORD_AUDIO (:obj:`str`): ``'record_audio'`` - - .. deprecated:: 13.5 - Deprecated by Telegram. Use :const:`CHATACTION_RECORD_VOICE` instead. - CHATACTION_RECORD_VOICE (:obj:`str`): ``'record_voice'`` - - .. versionadded:: 13.5 - CHATACTION_RECORD_VIDEO (:obj:`str`): ``'record_video'`` - CHATACTION_RECORD_VIDEO_NOTE (:obj:`str`): ``'record_video_note'`` - CHATACTION_TYPING (:obj:`str`): ``'typing'`` - CHATACTION_UPLOAD_AUDIO (:obj:`str`): ``'upload_audio'`` - - .. deprecated:: 13.5 - Deprecated by Telegram. Use :const:`CHATACTION_UPLOAD_VOICE` instead. - CHATACTION_UPLOAD_VOICE (:obj:`str`): ``'upload_voice'`` - - .. versionadded:: 13.5 - CHATACTION_UPLOAD_DOCUMENT (:obj:`str`): ``'upload_document'`` - CHATACTION_UPLOAD_PHOTO (:obj:`str`): ``'upload_photo'`` - CHATACTION_UPLOAD_VIDEO (:obj:`str`): ``'upload_video'`` - CHATACTION_UPLOAD_VIDEO_NOTE (:obj:`str`): ``'upload_video_note'`` - -:class:`telegram.ChatMember`: - -Attributes: - CHATMEMBER_ADMINISTRATOR (:obj:`str`): ``'administrator'`` - CHATMEMBER_CREATOR (:obj:`str`): ``'creator'`` - CHATMEMBER_KICKED (:obj:`str`): ``'kicked'`` - CHATMEMBER_LEFT (:obj:`str`): ``'left'`` - CHATMEMBER_MEMBER (:obj:`str`): ``'member'`` - CHATMEMBER_RESTRICTED (:obj:`str`): ``'restricted'`` - -:class:`telegram.Dice`: - -Attributes: - DICE_DICE (:obj:`str`): ``'🎲'`` - DICE_DARTS (:obj:`str`): ``'🎯'`` - DICE_BASKETBALL (:obj:`str`): ``'🏀'`` - DICE_FOOTBALL (:obj:`str`): ``'⚽'`` - DICE_SLOT_MACHINE (:obj:`str`): ``'🎰'`` - DICE_BOWLING (:obj:`str`): ``'🎳'`` - - .. versionadded:: 13.4 - DICE_ALL_EMOJI (List[:obj:`str`]): List of all supported base emoji. - - .. versionchanged:: 13.4 - Added :attr:`DICE_BOWLING` - -:class:`telegram.MessageEntity`: - -Attributes: - MESSAGEENTITY_MENTION (:obj:`str`): ``'mention'`` - MESSAGEENTITY_HASHTAG (:obj:`str`): ``'hashtag'`` - MESSAGEENTITY_CASHTAG (:obj:`str`): ``'cashtag'`` - MESSAGEENTITY_PHONE_NUMBER (:obj:`str`): ``'phone_number'`` - MESSAGEENTITY_BOT_COMMAND (:obj:`str`): ``'bot_command'`` - MESSAGEENTITY_URL (:obj:`str`): ``'url'`` - MESSAGEENTITY_EMAIL (:obj:`str`): ``'email'`` - MESSAGEENTITY_BOLD (:obj:`str`): ``'bold'`` - MESSAGEENTITY_ITALIC (:obj:`str`): ``'italic'`` - MESSAGEENTITY_CODE (:obj:`str`): ``'code'`` - MESSAGEENTITY_PRE (:obj:`str`): ``'pre'`` - MESSAGEENTITY_TEXT_LINK (:obj:`str`): ``'text_link'`` - MESSAGEENTITY_TEXT_MENTION (:obj:`str`): ``'text_mention'`` - MESSAGEENTITY_UNDERLINE (:obj:`str`): ``'underline'`` - MESSAGEENTITY_STRIKETHROUGH (:obj:`str`): ``'strikethrough'`` - MESSAGEENTITY_ALL_TYPES (List[:obj:`str`]): List of all the types of message entity. - -:class:`telegram.ParseMode`: - -Attributes: - PARSEMODE_MARKDOWN (:obj:`str`): ``'Markdown'`` - PARSEMODE_MARKDOWN_V2 (:obj:`str`): ``'MarkdownV2'`` - PARSEMODE_HTML (:obj:`str`): ``'HTML'`` - -:class:`telegram.Poll`: - -Attributes: - POLL_REGULAR (:obj:`str`): ``'regular'`` - POLL_QUIZ (:obj:`str`): ``'quiz'`` - MAX_POLL_QUESTION_LENGTH (:obj:`int`): 300 - MAX_POLL_OPTION_LENGTH (:obj:`int`): 100 - -:class:`telegram.MaskPosition`: - -Attributes: - STICKER_FOREHEAD (:obj:`str`): ``'forehead'`` - STICKER_EYES (:obj:`str`): ``'eyes'`` - STICKER_MOUTH (:obj:`str`): ``'mouth'`` - STICKER_CHIN (:obj:`str`): ``'chin'`` - -:class:`telegram.Update`: - -Attributes: - UPDATE_MESSAGE (:obj:`str`): ``'message'`` - - .. versionadded:: 13.5 - UPDATE_EDITED_MESSAGE (:obj:`str`): ``'edited_message'`` - - .. versionadded:: 13.5 - UPDATE_CHANNEL_POST (:obj:`str`): ``'channel_post'`` - - .. versionadded:: 13.5 - UPDATE_EDITED_CHANNEL_POST (:obj:`str`): ``'edited_channel_post'`` - - .. versionadded:: 13.5 - UPDATE_INLINE_QUERY (:obj:`str`): ``'inline_query'`` - - .. versionadded:: 13.5 - UPDATE_CHOSEN_INLINE_RESULT (:obj:`str`): ``'chosen_inline_result'`` - - .. versionadded:: 13.5 - UPDATE_CALLBACK_QUERY (:obj:`str`): ``'callback_query'`` - - .. versionadded:: 13.5 - UPDATE_SHIPPING_QUERY (:obj:`str`): ``'shipping_query'`` - - .. versionadded:: 13.5 - UPDATE_PRE_CHECKOUT_QUERY (:obj:`str`): ``'pre_checkout_query'`` - - .. versionadded:: 13.5 - UPDATE_POLL (:obj:`str`): ``'poll'`` - - .. versionadded:: 13.5 - UPDATE_POLL_ANSWER (:obj:`str`): ``'poll_answer'`` - - .. versionadded:: 13.5 - UPDATE_MY_CHAT_MEMBER (:obj:`str`): ``'my_chat_member'`` - - .. versionadded:: 13.5 - UPDATE_CHAT_MEMBER (:obj:`str`): ``'chat_member'`` - - .. versionadded:: 13.5 - UPDATE_ALL_TYPES (List[:obj:`str`]): List of all update types. - - .. versionadded:: 13.5 - -""" -from typing import List - -BOT_API_VERSION: str = '5.2' -MAX_MESSAGE_LENGTH: int = 4096 -MAX_CAPTION_LENGTH: int = 1024 -ANONYMOUS_ADMIN_ID: int = 1087968824 -SERVICE_CHAT_ID: int = 777000 - -# constants above this line are tested - -SUPPORTED_WEBHOOK_PORTS: List[int] = [443, 80, 88, 8443] -MAX_FILESIZE_DOWNLOAD: int = int(20e6) # (20MB) -MAX_FILESIZE_UPLOAD: int = int(50e6) # (50MB) -MAX_PHOTOSIZE_UPLOAD: int = int(10e6) # (10MB) -MAX_MESSAGES_PER_SECOND_PER_CHAT: int = 1 -MAX_MESSAGES_PER_SECOND: int = 30 -MAX_MESSAGES_PER_MINUTE_PER_GROUP: int = 20 -MAX_MESSAGE_ENTITIES: int = 100 -MAX_INLINE_QUERY_RESULTS: int = 50 -MAX_ANSWER_CALLBACK_QUERY_TEXT_LENGTH: int = 200 - -CHAT_SENDER: str = 'sender' -CHAT_PRIVATE: str = 'private' -CHAT_GROUP: str = 'group' -CHAT_SUPERGROUP: str = 'supergroup' -CHAT_CHANNEL: str = 'channel' - -CHATACTION_FIND_LOCATION: str = 'find_location' -CHATACTION_RECORD_AUDIO: str = 'record_audio' -CHATACTION_RECORD_VOICE: str = 'record_voice' -CHATACTION_RECORD_VIDEO: str = 'record_video' -CHATACTION_RECORD_VIDEO_NOTE: str = 'record_video_note' -CHATACTION_TYPING: str = 'typing' -CHATACTION_UPLOAD_AUDIO: str = 'upload_audio' -CHATACTION_UPLOAD_VOICE: str = 'upload_voice' -CHATACTION_UPLOAD_DOCUMENT: str = 'upload_document' -CHATACTION_UPLOAD_PHOTO: str = 'upload_photo' -CHATACTION_UPLOAD_VIDEO: str = 'upload_video' -CHATACTION_UPLOAD_VIDEO_NOTE: str = 'upload_video_note' - -CHATMEMBER_ADMINISTRATOR: str = 'administrator' -CHATMEMBER_CREATOR: str = 'creator' -CHATMEMBER_KICKED: str = 'kicked' -CHATMEMBER_LEFT: str = 'left' -CHATMEMBER_MEMBER: str = 'member' -CHATMEMBER_RESTRICTED: str = 'restricted' - -DICE_DICE: str = '🎲' -DICE_DARTS: str = '🎯' -DICE_BASKETBALL: str = '🏀' -DICE_FOOTBALL: str = '⚽' -DICE_SLOT_MACHINE: str = '🎰' -DICE_BOWLING: str = '🎳' -DICE_ALL_EMOJI: List[str] = [ - DICE_DICE, - DICE_DARTS, - DICE_BASKETBALL, - DICE_FOOTBALL, - DICE_SLOT_MACHINE, - DICE_BOWLING, -] - -MESSAGEENTITY_MENTION: str = 'mention' -MESSAGEENTITY_HASHTAG: str = 'hashtag' -MESSAGEENTITY_CASHTAG: str = 'cashtag' -MESSAGEENTITY_PHONE_NUMBER: str = 'phone_number' -MESSAGEENTITY_BOT_COMMAND: str = 'bot_command' -MESSAGEENTITY_URL: str = 'url' -MESSAGEENTITY_EMAIL: str = 'email' -MESSAGEENTITY_BOLD: str = 'bold' -MESSAGEENTITY_ITALIC: str = 'italic' -MESSAGEENTITY_CODE: str = 'code' -MESSAGEENTITY_PRE: str = 'pre' -MESSAGEENTITY_TEXT_LINK: str = 'text_link' -MESSAGEENTITY_TEXT_MENTION: str = 'text_mention' -MESSAGEENTITY_UNDERLINE: str = 'underline' -MESSAGEENTITY_STRIKETHROUGH: str = 'strikethrough' -MESSAGEENTITY_ALL_TYPES: List[str] = [ - MESSAGEENTITY_MENTION, - MESSAGEENTITY_HASHTAG, - MESSAGEENTITY_CASHTAG, - MESSAGEENTITY_PHONE_NUMBER, - MESSAGEENTITY_BOT_COMMAND, - MESSAGEENTITY_URL, - MESSAGEENTITY_EMAIL, - MESSAGEENTITY_BOLD, - MESSAGEENTITY_ITALIC, - MESSAGEENTITY_CODE, - MESSAGEENTITY_PRE, - MESSAGEENTITY_TEXT_LINK, - MESSAGEENTITY_TEXT_MENTION, - MESSAGEENTITY_UNDERLINE, - MESSAGEENTITY_STRIKETHROUGH, -] - -PARSEMODE_MARKDOWN: str = 'Markdown' -PARSEMODE_MARKDOWN_V2: str = 'MarkdownV2' -PARSEMODE_HTML: str = 'HTML' - -POLL_REGULAR: str = 'regular' -POLL_QUIZ: str = 'quiz' -MAX_POLL_QUESTION_LENGTH: int = 300 -MAX_POLL_OPTION_LENGTH: int = 100 - -STICKER_FOREHEAD: str = 'forehead' -STICKER_EYES: str = 'eyes' -STICKER_MOUTH: str = 'mouth' -STICKER_CHIN: str = 'chin' - -UPDATE_MESSAGE = 'message' -UPDATE_EDITED_MESSAGE = 'edited_message' -UPDATE_CHANNEL_POST = 'channel_post' -UPDATE_EDITED_CHANNEL_POST = 'edited_channel_post' -UPDATE_INLINE_QUERY = 'inline_query' -UPDATE_CHOSEN_INLINE_RESULT = 'chosen_inline_result' -UPDATE_CALLBACK_QUERY = 'callback_query' -UPDATE_SHIPPING_QUERY = 'shipping_query' -UPDATE_PRE_CHECKOUT_QUERY = 'pre_checkout_query' -UPDATE_POLL = 'poll' -UPDATE_POLL_ANSWER = 'poll_answer' -UPDATE_MY_CHAT_MEMBER = 'my_chat_member' -UPDATE_CHAT_MEMBER = 'chat_member' -UPDATE_ALL_TYPES = [ - UPDATE_MESSAGE, - UPDATE_EDITED_MESSAGE, - UPDATE_CHANNEL_POST, - UPDATE_EDITED_CHANNEL_POST, - UPDATE_INLINE_QUERY, - UPDATE_CHOSEN_INLINE_RESULT, - UPDATE_CALLBACK_QUERY, - UPDATE_SHIPPING_QUERY, - UPDATE_PRE_CHECKOUT_QUERY, - UPDATE_POLL, - UPDATE_POLL_ANSWER, - UPDATE_MY_CHAT_MEMBER, - UPDATE_CHAT_MEMBER, -] diff --git a/venv/lib/python3.8/site-packages/telegram/dice.py b/venv/lib/python3.8/site-packages/telegram/dice.py deleted file mode 100644 index 3406cee..0000000 --- a/venv/lib/python3.8/site-packages/telegram/dice.py +++ /dev/null @@ -1,92 +0,0 @@ -#!/usr/bin/env python -# pylint: disable=R0903 -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram Dice.""" -from typing import Any, List, ClassVar - -from telegram import TelegramObject, constants - - -class Dice(TelegramObject): - """ - This object represents an animated emoji with a random value for currently supported base - emoji. (The singular form of "dice" is "die". However, PTB mimics the Telegram API, which uses - the term "dice".) - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`value` and :attr:`emoji` are equal. - - Note: - If :attr:`emoji` is "🎯", a value of 6 currently represents a bullseye, while a value of 1 - indicates that the dartboard was missed. However, this behaviour is undocumented and might - be changed by Telegram. - - If :attr:`emoji` is "🏀", a value of 4 or 5 currently score a basket, while a value of 1 to - 3 indicates that the basket was missed. However, this behaviour is undocumented and might - be changed by Telegram. - - If :attr:`emoji` is "⚽", a value of 4 to 5 currently scores a goal, while a value of 1 to - 3 indicates that the goal was missed. However, this behaviour is undocumented and might - be changed by Telegram. - - If :attr:`emoji` is "🎳", a value of 6 knocks all the pins, while a value of 1 means all - the pins were missed. However, this behaviour is undocumented and might be changed by - Telegram. - - If :attr:`emoji` is "🎰", each value corresponds to a unique combination of symbols, which - can be found at our `wiki <https://git.io/JkeC6>`_. However, this behaviour is undocumented - and might be changed by Telegram. - - Args: - value (:obj:`int`): Value of the dice. 1-6 for dice, darts and bowling balls, 1-5 for - basketball and football/soccer ball, 1-64 for slot machine. - emoji (:obj:`str`): Emoji on which the dice throw animation is based. - - Attributes: - value (:obj:`int`): Value of the dice. - emoji (:obj:`str`): Emoji on which the dice throw animation is based. - - """ - - __slots__ = ('emoji', 'value', '_id_attrs') - - def __init__(self, value: int, emoji: str, **_kwargs: Any): - self.value = value - self.emoji = emoji - - self._id_attrs = (self.value, self.emoji) - - DICE: ClassVar[str] = constants.DICE_DICE # skipcq: PTC-W0052 - """:const:`telegram.constants.DICE_DICE`""" - DARTS: ClassVar[str] = constants.DICE_DARTS - """:const:`telegram.constants.DICE_DARTS`""" - BASKETBALL: ClassVar[str] = constants.DICE_BASKETBALL - """:const:`telegram.constants.DICE_BASKETBALL`""" - FOOTBALL: ClassVar[str] = constants.DICE_FOOTBALL - """:const:`telegram.constants.DICE_FOOTBALL`""" - SLOT_MACHINE: ClassVar[str] = constants.DICE_SLOT_MACHINE - """:const:`telegram.constants.DICE_SLOT_MACHINE`""" - BOWLING: ClassVar[str] = constants.DICE_BOWLING - """ - :const:`telegram.constants.DICE_BOWLING` - - .. versionadded:: 13.4 - """ - ALL_EMOJI: ClassVar[List[str]] = constants.DICE_ALL_EMOJI - """:const:`telegram.constants.DICE_ALL_EMOJI`""" diff --git a/venv/lib/python3.8/site-packages/telegram/error.py b/venv/lib/python3.8/site-packages/telegram/error.py deleted file mode 100644 index 5e597cd..0000000 --- a/venv/lib/python3.8/site-packages/telegram/error.py +++ /dev/null @@ -1,151 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -# pylint: disable=C0115 -"""This module contains an object that represents Telegram errors.""" -from typing import Tuple - - -def _lstrip_str(in_s: str, lstr: str) -> str: - """ - Args: - in_s (:obj:`str`): in string - lstr (:obj:`str`): substr to strip from left side - - Returns: - :obj:`str`: The stripped string. - - """ - if in_s.startswith(lstr): - res = in_s[len(lstr) :] - else: - res = in_s - return res - - -class TelegramError(Exception): - """Base class for Telegram errors.""" - - # Apparently the base class Exception already has __dict__ in it, so its not included here - __slots__ = ('message',) - - def __init__(self, message: str): - super().__init__() - - msg = _lstrip_str(message, 'Error: ') - msg = _lstrip_str(msg, '[Error]: ') - msg = _lstrip_str(msg, 'Bad Request: ') - if msg != message: - # api_error - capitalize the msg... - msg = msg.capitalize() - self.message = msg - - def __str__(self) -> str: - return '%s' % self.message - - def __reduce__(self) -> Tuple[type, Tuple[str]]: - return self.__class__, (self.message,) - - -class Unauthorized(TelegramError): - """Raised when the bot has not enough rights to perform the requested action.""" - - __slots__ = () - - -class InvalidToken(TelegramError): - """Raised when the token is invalid.""" - - __slots__ = () - - def __init__(self) -> None: - super().__init__('Invalid token') - - def __reduce__(self) -> Tuple[type, Tuple]: # type: ignore[override] - return self.__class__, () - - -class NetworkError(TelegramError): - """Base class for exceptions due to networking errors.""" - - __slots__ = () - - -class BadRequest(NetworkError): - """Raised when Telegram could not process the request correctly.""" - - __slots__ = () - - -class TimedOut(NetworkError): - """Raised when a request took too long to finish.""" - - __slots__ = () - - def __init__(self) -> None: - super().__init__('Timed out') - - def __reduce__(self) -> Tuple[type, Tuple]: # type: ignore[override] - return self.__class__, () - - -class ChatMigrated(TelegramError): - """ - Raised when the requested group chat migrated to supergroup and has a new chat id. - - Args: - new_chat_id (:obj:`int`): The new chat id of the group. - - """ - - __slots__ = ('new_chat_id',) - - def __init__(self, new_chat_id: int): - super().__init__(f'Group migrated to supergroup. New chat id: {new_chat_id}') - self.new_chat_id = new_chat_id - - def __reduce__(self) -> Tuple[type, Tuple[int]]: # type: ignore[override] - return self.__class__, (self.new_chat_id,) - - -class RetryAfter(TelegramError): - """ - Raised when flood limits where exceeded. - - Args: - retry_after (:obj:`int`): Time in seconds, after which the bot can retry the request. - - """ - - __slots__ = ('retry_after',) - - def __init__(self, retry_after: int): - super().__init__(f'Flood control exceeded. Retry in {float(retry_after)} seconds') - self.retry_after = float(retry_after) - - def __reduce__(self) -> Tuple[type, Tuple[float]]: # type: ignore[override] - return self.__class__, (self.retry_after,) - - -class Conflict(TelegramError): - """Raised when a long poll or webhook conflicts with another one.""" - - __slots__ = () - - def __reduce__(self) -> Tuple[type, Tuple[str]]: - return self.__class__, (self.message,) diff --git a/venv/lib/python3.8/site-packages/telegram/ext/__init__.py b/venv/lib/python3.8/site-packages/telegram/ext/__init__.py deleted file mode 100644 index b4b4cc5..0000000 --- a/venv/lib/python3.8/site-packages/telegram/ext/__init__.py +++ /dev/null @@ -1,104 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -# pylint: disable=C0413 -"""Extensions over the Telegram Bot API to facilitate bot making""" - -from .extbot import ExtBot -from .basepersistence import BasePersistence -from .picklepersistence import PicklePersistence -from .dictpersistence import DictPersistence -from .handler import Handler -from .callbackcontext import CallbackContext -from .contexttypes import ContextTypes -from .dispatcher import Dispatcher, DispatcherHandlerStop, run_async - -# https://bugs.python.org/issue41451, fixed on 3.7+, doesn't actually remove slots -# try-except is just here in case the __init__ is called twice (like in the tests) -# this block is also the reason for the pylint-ignore at the top of the file -try: - del Dispatcher.__slots__ # type: ignore[has-type] -except AttributeError as exc: - if str(exc) == '__slots__': - pass - else: - raise exc - -from .jobqueue import JobQueue, Job -from .updater import Updater -from .callbackqueryhandler import CallbackQueryHandler -from .choseninlineresulthandler import ChosenInlineResultHandler -from .inlinequeryhandler import InlineQueryHandler -from .filters import BaseFilter, MessageFilter, UpdateFilter, Filters -from .messagehandler import MessageHandler -from .commandhandler import CommandHandler, PrefixHandler -from .regexhandler import RegexHandler -from .stringcommandhandler import StringCommandHandler -from .stringregexhandler import StringRegexHandler -from .typehandler import TypeHandler -from .conversationhandler import ConversationHandler -from .precheckoutqueryhandler import PreCheckoutQueryHandler -from .shippingqueryhandler import ShippingQueryHandler -from .messagequeue import MessageQueue -from .messagequeue import DelayQueue -from .pollanswerhandler import PollAnswerHandler -from .pollhandler import PollHandler -from .chatmemberhandler import ChatMemberHandler -from .defaults import Defaults -from .callbackdatacache import CallbackDataCache, InvalidCallbackData - -__all__ = ( - 'BaseFilter', - 'BasePersistence', - 'CallbackContext', - 'CallbackDataCache', - 'CallbackQueryHandler', - 'ChatMemberHandler', - 'ChosenInlineResultHandler', - 'CommandHandler', - 'ContextTypes', - 'ConversationHandler', - 'Defaults', - 'DelayQueue', - 'DictPersistence', - 'Dispatcher', - 'DispatcherHandlerStop', - 'ExtBot', - 'Filters', - 'Handler', - 'InlineQueryHandler', - 'InvalidCallbackData', - 'Job', - 'JobQueue', - 'MessageFilter', - 'MessageHandler', - 'MessageQueue', - 'PicklePersistence', - 'PollAnswerHandler', - 'PollHandler', - 'PreCheckoutQueryHandler', - 'PrefixHandler', - 'RegexHandler', - 'ShippingQueryHandler', - 'StringCommandHandler', - 'StringRegexHandler', - 'TypeHandler', - 'UpdateFilter', - 'Updater', - 'run_async', -) diff --git a/venv/lib/python3.8/site-packages/telegram/ext/basepersistence.py b/venv/lib/python3.8/site-packages/telegram/ext/basepersistence.py deleted file mode 100644 index 8833733..0000000 --- a/venv/lib/python3.8/site-packages/telegram/ext/basepersistence.py +++ /dev/null @@ -1,538 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the BasePersistence class.""" -import warnings -from sys import version_info as py_ver -from abc import ABC, abstractmethod -from copy import copy -from typing import Dict, Optional, Tuple, cast, ClassVar, Generic, DefaultDict - -from telegram.utils.deprecate import set_new_attribute_deprecated - -from telegram import Bot -import telegram.ext.extbot - -from telegram.ext.utils.types import UD, CD, BD, ConversationDict, CDCData - - -class BasePersistence(Generic[UD, CD, BD], ABC): - """Interface class for adding persistence to your bot. - Subclass this object for different implementations of a persistent bot. - - All relevant methods must be overwritten. This includes: - - * :meth:`get_bot_data` - * :meth:`update_bot_data` - * :meth:`refresh_bot_data` - * :meth:`get_chat_data` - * :meth:`update_chat_data` - * :meth:`refresh_chat_data` - * :meth:`get_user_data` - * :meth:`update_user_data` - * :meth:`refresh_user_data` - * :meth:`get_callback_data` - * :meth:`update_callback_data` - * :meth:`get_conversations` - * :meth:`update_conversation` - * :meth:`flush` - - If you don't actually need one of those methods, a simple ``pass`` is enough. For example, if - ``store_bot_data=False``, you don't need :meth:`get_bot_data`, :meth:`update_bot_data` or - :meth:`refresh_bot_data`. - - Warning: - Persistence will try to replace :class:`telegram.Bot` instances by :attr:`REPLACED_BOT` and - insert the bot set with :meth:`set_bot` upon loading of the data. This is to ensure that - changes to the bot apply to the saved objects, too. If you change the bots token, this may - lead to e.g. ``Chat not found`` errors. For the limitations on replacing bots see - :meth:`replace_bot` and :meth:`insert_bot`. - - Note: - :meth:`replace_bot` and :meth:`insert_bot` are used *independently* of the implementation - of the :meth:`update/get_*` methods, i.e. you don't need to worry about it while - implementing a custom persistence subclass. - - Args: - store_user_data (:obj:`bool`, optional): Whether user_data should be saved by this - persistence class. Default is :obj:`True`. - store_chat_data (:obj:`bool`, optional): Whether chat_data should be saved by this - persistence class. Default is :obj:`True` . - store_bot_data (:obj:`bool`, optional): Whether bot_data should be saved by this - persistence class. Default is :obj:`True`. - store_callback_data (:obj:`bool`, optional): Whether callback_data should be saved by this - persistence class. Default is :obj:`False`. - - .. versionadded:: 13.6 - - Attributes: - store_user_data (:obj:`bool`): Optional, Whether user_data should be saved by this - persistence class. - store_chat_data (:obj:`bool`): Optional. Whether chat_data should be saved by this - persistence class. - store_bot_data (:obj:`bool`): Optional. Whether bot_data should be saved by this - persistence class. - store_callback_data (:obj:`bool`): Optional. Whether callback_data should be saved by this - persistence class. - - .. versionadded:: 13.6 - """ - - # Apparently Py 3.7 and below have '__dict__' in ABC - if py_ver < (3, 7): - __slots__ = ( - 'store_user_data', - 'store_chat_data', - 'store_bot_data', - 'store_callback_data', - 'bot', - ) - else: - __slots__ = ( - 'store_user_data', # type: ignore[assignment] - 'store_chat_data', - 'store_bot_data', - 'store_callback_data', - 'bot', - '__dict__', - ) - - def __new__( - cls, *args: object, **kwargs: object # pylint: disable=W0613 - ) -> 'BasePersistence': - """This overrides the get_* and update_* methods to use insert/replace_bot. - That has the side effect that we always pass deepcopied data to those methods, so in - Pickle/DictPersistence we don't have to worry about copying the data again. - - Note: This doesn't hold for second tuple-entry of callback_data. That's a Dict[str, str], - so no bots to replace anyway. - """ - instance = super().__new__(cls) - get_user_data = instance.get_user_data - get_chat_data = instance.get_chat_data - get_bot_data = instance.get_bot_data - get_callback_data = instance.get_callback_data - update_user_data = instance.update_user_data - update_chat_data = instance.update_chat_data - update_bot_data = instance.update_bot_data - update_callback_data = instance.update_callback_data - - def get_user_data_insert_bot() -> DefaultDict[int, UD]: - return instance.insert_bot(get_user_data()) - - def get_chat_data_insert_bot() -> DefaultDict[int, CD]: - return instance.insert_bot(get_chat_data()) - - def get_bot_data_insert_bot() -> BD: - return instance.insert_bot(get_bot_data()) - - def get_callback_data_insert_bot() -> Optional[CDCData]: - cdc_data = get_callback_data() - if cdc_data is None: - return None - return instance.insert_bot(cdc_data[0]), cdc_data[1] - - def update_user_data_replace_bot(user_id: int, data: UD) -> None: - return update_user_data(user_id, instance.replace_bot(data)) - - def update_chat_data_replace_bot(chat_id: int, data: CD) -> None: - return update_chat_data(chat_id, instance.replace_bot(data)) - - def update_bot_data_replace_bot(data: BD) -> None: - return update_bot_data(instance.replace_bot(data)) - - def update_callback_data_replace_bot(data: CDCData) -> None: - obj_data, queue = data - return update_callback_data((instance.replace_bot(obj_data), queue)) - - # We want to ignore TGDeprecation warnings so we use obj.__setattr__. Adds to __dict__ - object.__setattr__(instance, 'get_user_data', get_user_data_insert_bot) - object.__setattr__(instance, 'get_chat_data', get_chat_data_insert_bot) - object.__setattr__(instance, 'get_bot_data', get_bot_data_insert_bot) - object.__setattr__(instance, 'get_callback_data', get_callback_data_insert_bot) - object.__setattr__(instance, 'update_user_data', update_user_data_replace_bot) - object.__setattr__(instance, 'update_chat_data', update_chat_data_replace_bot) - object.__setattr__(instance, 'update_bot_data', update_bot_data_replace_bot) - object.__setattr__(instance, 'update_callback_data', update_callback_data_replace_bot) - return instance - - def __init__( - self, - store_user_data: bool = True, - store_chat_data: bool = True, - store_bot_data: bool = True, - store_callback_data: bool = False, - ): - self.store_user_data = store_user_data - self.store_chat_data = store_chat_data - self.store_bot_data = store_bot_data - self.store_callback_data = store_callback_data - self.bot: Bot = None # type: ignore[assignment] - - def __setattr__(self, key: str, value: object) -> None: - # Allow user defined subclasses to have custom attributes. - if issubclass(self.__class__, BasePersistence) and self.__class__.__name__ not in { - 'DictPersistence', - 'PicklePersistence', - }: - object.__setattr__(self, key, value) - return - set_new_attribute_deprecated(self, key, value) - - def set_bot(self, bot: Bot) -> None: - """Set the Bot to be used by this persistence instance. - - Args: - bot (:class:`telegram.Bot`): The bot. - """ - if self.store_callback_data and not isinstance(bot, telegram.ext.extbot.ExtBot): - raise TypeError('store_callback_data can only be used with telegram.ext.ExtBot.') - - self.bot = bot - - @classmethod - def replace_bot(cls, obj: object) -> object: - """ - Replaces all instances of :class:`telegram.Bot` that occur within the passed object with - :attr:`REPLACED_BOT`. Currently, this handles objects of type ``list``, ``tuple``, ``set``, - ``frozenset``, ``dict``, ``defaultdict`` and objects that have a ``__dict__`` or - ``__slots__`` attribute, excluding classes and objects that can't be copied with - ``copy.copy``. - - Args: - obj (:obj:`object`): The object - - Returns: - :obj:`obj`: Copy of the object with Bot instances replaced. - """ - return cls._replace_bot(obj, {}) - - @classmethod - def _replace_bot(cls, obj: object, memo: Dict[int, object]) -> object: # pylint: disable=R0911 - obj_id = id(obj) - if obj_id in memo: - return memo[obj_id] - - if isinstance(obj, Bot): - memo[obj_id] = cls.REPLACED_BOT - return cls.REPLACED_BOT - if isinstance(obj, (list, set)): - # We copy the iterable here for thread safety, i.e. make sure the object we iterate - # over doesn't change its length during the iteration - temp_iterable = obj.copy() - new_iterable = obj.__class__(cls._replace_bot(item, memo) for item in temp_iterable) - memo[obj_id] = new_iterable - return new_iterable - if isinstance(obj, (tuple, frozenset)): - # tuples and frozensets are immutable so we don't need to worry about thread safety - new_immutable = obj.__class__(cls._replace_bot(item, memo) for item in obj) - memo[obj_id] = new_immutable - return new_immutable - if isinstance(obj, type): - # classes usually do have a __dict__, but it's not writable - warnings.warn( - 'BasePersistence.replace_bot does not handle classes. See ' - 'the docs of BasePersistence.replace_bot for more information.', - RuntimeWarning, - ) - return obj - - try: - new_obj = copy(obj) - memo[obj_id] = new_obj - except Exception: - warnings.warn( - 'BasePersistence.replace_bot does not handle objects that can not be copied. See ' - 'the docs of BasePersistence.replace_bot for more information.', - RuntimeWarning, - ) - memo[obj_id] = obj - return obj - - if isinstance(obj, dict): - # We handle dicts via copy(obj) so we don't have to make a - # difference between dict and defaultdict - new_obj = cast(dict, new_obj) - # We can't iterate over obj.items() due to thread safety, i.e. the dicts length may - # change during the iteration - temp_dict = new_obj.copy() - new_obj.clear() - for k, val in temp_dict.items(): - new_obj[cls._replace_bot(k, memo)] = cls._replace_bot(val, memo) - memo[obj_id] = new_obj - return new_obj - if hasattr(obj, '__dict__'): - for attr_name, attr in new_obj.__dict__.items(): - setattr(new_obj, attr_name, cls._replace_bot(attr, memo)) - memo[obj_id] = new_obj - return new_obj - if hasattr(obj, '__slots__'): - for attr_name in new_obj.__slots__: - setattr( - new_obj, - attr_name, - cls._replace_bot(cls._replace_bot(getattr(new_obj, attr_name), memo), memo), - ) - memo[obj_id] = new_obj - return new_obj - - return obj - - def insert_bot(self, obj: object) -> object: - """ - Replaces all instances of :attr:`REPLACED_BOT` that occur within the passed object with - :attr:`bot`. Currently, this handles objects of type ``list``, ``tuple``, ``set``, - ``frozenset``, ``dict``, ``defaultdict`` and objects that have a ``__dict__`` or - ``__slots__`` attribute, excluding classes and objects that can't be copied with - ``copy.copy``. - - Args: - obj (:obj:`object`): The object - - Returns: - :obj:`obj`: Copy of the object with Bot instances inserted. - """ - return self._insert_bot(obj, {}) - - def _insert_bot(self, obj: object, memo: Dict[int, object]) -> object: # pylint: disable=R0911 - obj_id = id(obj) - if obj_id in memo: - return memo[obj_id] - - if isinstance(obj, Bot): - memo[obj_id] = self.bot - return self.bot - if isinstance(obj, str) and obj == self.REPLACED_BOT: - memo[obj_id] = self.bot - return self.bot - if isinstance(obj, (list, set)): - # We copy the iterable here for thread safety, i.e. make sure the object we iterate - # over doesn't change its length during the iteration - temp_iterable = obj.copy() - new_iterable = obj.__class__(self._insert_bot(item, memo) for item in temp_iterable) - memo[obj_id] = new_iterable - return new_iterable - if isinstance(obj, (tuple, frozenset)): - # tuples and frozensets are immutable so we don't need to worry about thread safety - new_immutable = obj.__class__(self._insert_bot(item, memo) for item in obj) - memo[obj_id] = new_immutable - return new_immutable - if isinstance(obj, type): - # classes usually do have a __dict__, but it's not writable - warnings.warn( - 'BasePersistence.insert_bot does not handle classes. See ' - 'the docs of BasePersistence.insert_bot for more information.', - RuntimeWarning, - ) - return obj - - try: - new_obj = copy(obj) - except Exception: - warnings.warn( - 'BasePersistence.insert_bot does not handle objects that can not be copied. See ' - 'the docs of BasePersistence.insert_bot for more information.', - RuntimeWarning, - ) - memo[obj_id] = obj - return obj - - if isinstance(obj, dict): - # We handle dicts via copy(obj) so we don't have to make a - # difference between dict and defaultdict - new_obj = cast(dict, new_obj) - # We can't iterate over obj.items() due to thread safety, i.e. the dicts length may - # change during the iteration - temp_dict = new_obj.copy() - new_obj.clear() - for k, val in temp_dict.items(): - new_obj[self._insert_bot(k, memo)] = self._insert_bot(val, memo) - memo[obj_id] = new_obj - return new_obj - if hasattr(obj, '__dict__'): - for attr_name, attr in new_obj.__dict__.items(): - setattr(new_obj, attr_name, self._insert_bot(attr, memo)) - memo[obj_id] = new_obj - return new_obj - if hasattr(obj, '__slots__'): - for attr_name in obj.__slots__: - setattr( - new_obj, - attr_name, - self._insert_bot(self._insert_bot(getattr(new_obj, attr_name), memo), memo), - ) - memo[obj_id] = new_obj - return new_obj - - return obj - - @abstractmethod - def get_user_data(self) -> DefaultDict[int, UD]: - """Will be called by :class:`telegram.ext.Dispatcher` upon creation with a - persistence object. It should return the ``user_data`` if stored, or an empty - :obj:`defaultdict(telegram.ext.utils.types.UD)` with integer keys. - - Returns: - DefaultDict[:obj:`int`, :class:`telegram.ext.utils.types.UD`]: The restored user data. - """ - - @abstractmethod - def get_chat_data(self) -> DefaultDict[int, CD]: - """Will be called by :class:`telegram.ext.Dispatcher` upon creation with a - persistence object. It should return the ``chat_data`` if stored, or an empty - :obj:`defaultdict(telegram.ext.utils.types.CD)` with integer keys. - - Returns: - DefaultDict[:obj:`int`, :class:`telegram.ext.utils.types.CD`]: The restored chat data. - """ - - @abstractmethod - def get_bot_data(self) -> BD: - """Will be called by :class:`telegram.ext.Dispatcher` upon creation with a - persistence object. It should return the ``bot_data`` if stored, or an empty - :class:`telegram.ext.utils.types.BD`. - - Returns: - :class:`telegram.ext.utils.types.BD`: The restored bot data. - """ - - def get_callback_data(self) -> Optional[CDCData]: - """Will be called by :class:`telegram.ext.Dispatcher` upon creation with a - persistence object. If callback data was stored, it should be returned. - - .. versionadded:: 13.6 - - Returns: - Optional[:class:`telegram.ext.utils.types.CDCData`]: The restored meta data or - :obj:`None`, if no data was stored. - """ - raise NotImplementedError - - @abstractmethod - def get_conversations(self, name: str) -> ConversationDict: - """Will be called by :class:`telegram.ext.Dispatcher` when a - :class:`telegram.ext.ConversationHandler` is added if - :attr:`telegram.ext.ConversationHandler.persistent` is :obj:`True`. - It should return the conversations for the handler with `name` or an empty :obj:`dict` - - Args: - name (:obj:`str`): The handlers name. - - Returns: - :obj:`dict`: The restored conversations for the handler. - """ - - @abstractmethod - def update_conversation( - self, name: str, key: Tuple[int, ...], new_state: Optional[object] - ) -> None: - """Will be called when a :attr:`telegram.ext.ConversationHandler.update_state` - is called. This allows the storage of the new state in the persistence. - - Args: - name (:obj:`str`): The handler's name. - key (:obj:`tuple`): The key the state is changed for. - new_state (:obj:`tuple` | :obj:`any`): The new state for the given key. - """ - - @abstractmethod - def update_user_data(self, user_id: int, data: UD) -> None: - """Will be called by the :class:`telegram.ext.Dispatcher` after a handler has - handled an update. - - Args: - user_id (:obj:`int`): The user the data might have been changed for. - data (:class:`telegram.ext.utils.types.UD`): The - :attr:`telegram.ext.dispatcher.user_data` ``[user_id]``. - """ - - @abstractmethod - def update_chat_data(self, chat_id: int, data: CD) -> None: - """Will be called by the :class:`telegram.ext.Dispatcher` after a handler has - handled an update. - - Args: - chat_id (:obj:`int`): The chat the data might have been changed for. - data (:class:`telegram.ext.utils.types.CD`): The - :attr:`telegram.ext.dispatcher.chat_data` ``[chat_id]``. - """ - - @abstractmethod - def update_bot_data(self, data: BD) -> None: - """Will be called by the :class:`telegram.ext.Dispatcher` after a handler has - handled an update. - - Args: - data (:class:`telegram.ext.utils.types.BD`): The - :attr:`telegram.ext.dispatcher.bot_data`. - """ - - def refresh_user_data(self, user_id: int, user_data: UD) -> None: - """Will be called by the :class:`telegram.ext.Dispatcher` before passing the - :attr:`user_data` to a callback. Can be used to update data stored in :attr:`user_data` - from an external source. - - .. versionadded:: 13.6 - - Args: - user_id (:obj:`int`): The user ID this :attr:`user_data` is associated with. - user_data (:class:`telegram.ext.utils.types.UD`): The ``user_data`` of a single user. - """ - - def refresh_chat_data(self, chat_id: int, chat_data: CD) -> None: - """Will be called by the :class:`telegram.ext.Dispatcher` before passing the - :attr:`chat_data` to a callback. Can be used to update data stored in :attr:`chat_data` - from an external source. - - .. versionadded:: 13.6 - - Args: - chat_id (:obj:`int`): The chat ID this :attr:`chat_data` is associated with. - chat_data (:class:`telegram.ext.utils.types.CD`): The ``chat_data`` of a single chat. - """ - - def refresh_bot_data(self, bot_data: BD) -> None: - """Will be called by the :class:`telegram.ext.Dispatcher` before passing the - :attr:`bot_data` to a callback. Can be used to update data stored in :attr:`bot_data` - from an external source. - - .. versionadded:: 13.6 - - Args: - bot_data (:class:`telegram.ext.utils.types.BD`): The ``bot_data``. - """ - - def update_callback_data(self, data: CDCData) -> None: - """Will be called by the :class:`telegram.ext.Dispatcher` after a handler has - handled an update. - - .. versionadded:: 13.6 - - Args: - data (:class:`telegram.ext.utils.types.CDCData`:): The relevant data to restore - :attr:`telegram.ext.dispatcher.bot.callback_data_cache`. - """ - raise NotImplementedError - - def flush(self) -> None: - """Will be called by :class:`telegram.ext.Updater` upon receiving a stop signal. Gives the - persistence a chance to finish up saving or close a database connection gracefully. - """ - - REPLACED_BOT: ClassVar[str] = 'bot_instance_replaced_by_ptb_persistence' - """:obj:`str`: Placeholder for :class:`telegram.Bot` instances replaced in saved data.""" diff --git a/venv/lib/python3.8/site-packages/telegram/ext/callbackcontext.py b/venv/lib/python3.8/site-packages/telegram/ext/callbackcontext.py deleted file mode 100644 index 5c5e9be..0000000 --- a/venv/lib/python3.8/site-packages/telegram/ext/callbackcontext.py +++ /dev/null @@ -1,361 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -# pylint: disable=R0201 -"""This module contains the CallbackContext class.""" -from queue import Queue -from typing import ( - TYPE_CHECKING, - Dict, - List, - Match, - NoReturn, - Optional, - Tuple, - Union, - Generic, - Type, - TypeVar, -) - -from telegram import Update, CallbackQuery -from telegram.ext import ExtBot -from telegram.ext.utils.types import UD, CD, BD - -if TYPE_CHECKING: - from telegram import Bot - from telegram.ext import Dispatcher, Job, JobQueue - -CC = TypeVar('CC', bound='CallbackContext') - - -class CallbackContext(Generic[UD, CD, BD]): - """ - This is a context object passed to the callback called by :class:`telegram.ext.Handler` - or by the :class:`telegram.ext.Dispatcher` in an error handler added by - :attr:`telegram.ext.Dispatcher.add_error_handler` or to the callback of a - :class:`telegram.ext.Job`. - - Note: - :class:`telegram.ext.Dispatcher` will create a single context for an entire update. This - means that if you got 2 handlers in different groups and they both get called, they will - get passed the same `CallbackContext` object (of course with proper attributes like - `.matches` differing). This allows you to add custom attributes in a lower handler group - callback, and then subsequently access those attributes in a higher handler group callback. - Note that the attributes on `CallbackContext` might change in the future, so make sure to - use a fairly unique name for the attributes. - - Warning: - Do not combine custom attributes and ``@run_async``/ - :meth:`telegram.ext.Disptacher.run_async`. Due to how ``run_async`` works, it will - almost certainly execute the callbacks for an update out of order, and the attributes - that you think you added will not be present. - - Args: - dispatcher (:class:`telegram.ext.Dispatcher`): The dispatcher associated with this context. - - Attributes: - matches (List[:obj:`re match object`]): Optional. If the associated update originated from - a regex-supported handler or had a :class:`Filters.regex`, this will contain a list of - match objects for every pattern where ``re.search(pattern, string)`` returned a match. - Note that filters short circuit, so combined regex filters will not always - be evaluated. - args (List[:obj:`str`]): Optional. Arguments passed to a command if the associated update - is handled by :class:`telegram.ext.CommandHandler`, :class:`telegram.ext.PrefixHandler` - or :class:`telegram.ext.StringCommandHandler`. It contains a list of the words in the - text after the command, using any whitespace string as a delimiter. - error (:obj:`Exception`): Optional. The error that was raised. Only present when passed - to a error handler registered with :attr:`telegram.ext.Dispatcher.add_error_handler`. - async_args (List[:obj:`object`]): Optional. Positional arguments of the function that - raised the error. Only present when the raising function was run asynchronously using - :meth:`telegram.ext.Dispatcher.run_async`. - async_kwargs (Dict[:obj:`str`, :obj:`object`]): Optional. Keyword arguments of the function - that raised the error. Only present when the raising function was run asynchronously - using :meth:`telegram.ext.Dispatcher.run_async`. - job (:class:`telegram.ext.Job`): Optional. The job which originated this callback. - Only present when passed to the callback of :class:`telegram.ext.Job`. - - """ - - __slots__ = ( - '_dispatcher', - '_chat_id_and_data', - '_user_id_and_data', - 'args', - 'matches', - 'error', - 'job', - 'async_args', - 'async_kwargs', - '__dict__', - ) - - def __init__(self, dispatcher: 'Dispatcher'): - """ - Args: - dispatcher (:class:`telegram.ext.Dispatcher`): - """ - if not dispatcher.use_context: - raise ValueError( - 'CallbackContext should not be used with a non context aware ' 'dispatcher!' - ) - self._dispatcher = dispatcher - self._chat_id_and_data: Optional[Tuple[int, CD]] = None - self._user_id_and_data: Optional[Tuple[int, UD]] = None - self.args: Optional[List[str]] = None - self.matches: Optional[List[Match]] = None - self.error: Optional[Exception] = None - self.job: Optional['Job'] = None - self.async_args: Optional[Union[List, Tuple]] = None - self.async_kwargs: Optional[Dict[str, object]] = None - - @property - def dispatcher(self) -> 'Dispatcher': - """:class:`telegram.ext.Dispatcher`: The dispatcher associated with this context.""" - return self._dispatcher - - @property - def bot_data(self) -> BD: - """:obj:`dict`: Optional. A dict that can be used to keep any data in. For each - update it will be the same ``dict``. - """ - return self.dispatcher.bot_data - - @bot_data.setter - def bot_data(self, value: object) -> NoReturn: - raise AttributeError( - "You can not assign a new value to bot_data, see https://git.io/Jt6ic" - ) - - @property - def chat_data(self) -> Optional[CD]: - """:obj:`dict`: Optional. A dict that can be used to keep any data in. For each - update from the same chat id it will be the same ``dict``. - - Warning: - When a group chat migrates to a supergroup, its chat id will change and the - ``chat_data`` needs to be transferred. For details see our `wiki page - <https://github.com/python-telegram-bot/python-telegram-bot/wiki/ - Storing-bot,-user-and-chat-related-data#chat-migration>`_. - """ - if self._chat_id_and_data: - return self._chat_id_and_data[1] - return None - - @chat_data.setter - def chat_data(self, value: object) -> NoReturn: - raise AttributeError( - "You can not assign a new value to chat_data, see https://git.io/Jt6ic" - ) - - @property - def user_data(self) -> Optional[UD]: - """:obj:`dict`: Optional. A dict that can be used to keep any data in. For each - update from the same user it will be the same ``dict``. - """ - if self._user_id_and_data: - return self._user_id_and_data[1] - return None - - @user_data.setter - def user_data(self, value: object) -> NoReturn: - raise AttributeError( - "You can not assign a new value to user_data, see https://git.io/Jt6ic" - ) - - def refresh_data(self) -> None: - """If :attr:`dispatcher` uses persistence, calls - :meth:`telegram.ext.BasePersistence.refresh_bot_data` on :attr:`bot_data`, - :meth:`telegram.ext.BasePersistence.refresh_chat_data` on :attr:`chat_data` and - :meth:`telegram.ext.BasePersistence.refresh_user_data` on :attr:`user_data`, if - appropriate. - - .. versionadded:: 13.6 - """ - if self.dispatcher.persistence: - if self.dispatcher.persistence.store_bot_data: - self.dispatcher.persistence.refresh_bot_data(self.bot_data) - if self.dispatcher.persistence.store_chat_data and self._chat_id_and_data is not None: - self.dispatcher.persistence.refresh_chat_data(*self._chat_id_and_data) - if self.dispatcher.persistence.store_user_data and self._user_id_and_data is not None: - self.dispatcher.persistence.refresh_user_data(*self._user_id_and_data) - - def drop_callback_data(self, callback_query: CallbackQuery) -> None: - """ - Deletes the cached data for the specified callback query. - - .. versionadded:: 13.6 - - Note: - Will *not* raise exceptions in case the data is not found in the cache. - *Will* raise :class:`KeyError` in case the callback query can not be found in the - cache. - - Args: - callback_query (:class:`telegram.CallbackQuery`): The callback query. - - Raises: - KeyError | RuntimeError: :class:`KeyError`, if the callback query can not be found in - the cache and :class:`RuntimeError`, if the bot doesn't allow for arbitrary - callback data. - """ - if isinstance(self.bot, ExtBot): - if not self.bot.arbitrary_callback_data: - raise RuntimeError( - 'This telegram.ext.ExtBot instance does not use arbitrary callback data.' - ) - self.bot.callback_data_cache.drop_data(callback_query) - else: - raise RuntimeError('telegram.Bot does not allow for arbitrary callback data.') - - @classmethod - def from_error( - cls: Type[CC], - update: object, - error: Exception, - dispatcher: 'Dispatcher', - async_args: Union[List, Tuple] = None, - async_kwargs: Dict[str, object] = None, - ) -> CC: - """ - Constructs an instance of :class:`telegram.ext.CallbackContext` to be passed to the error - handlers. - - .. seealso:: :meth:`telegram.ext.Dispatcher.add_error_handler` - - Args: - update (:obj:`object` | :class:`telegram.Update`): The update associated with the - error. May be :obj:`None`, e.g. for errors in job callbacks. - error (:obj:`Exception`): The error. - dispatcher (:class:`telegram.ext.Dispatcher`): The dispatcher associated with this - context. - async_args (List[:obj:`object`]): Optional. Positional arguments of the function that - raised the error. Pass only when the raising function was run asynchronously using - :meth:`telegram.ext.Dispatcher.run_async`. - async_kwargs (Dict[:obj:`str`, :obj:`object`]): Optional. Keyword arguments of the - function that raised the error. Pass only when the raising function was run - asynchronously using :meth:`telegram.ext.Dispatcher.run_async`. - - Returns: - :class:`telegram.ext.CallbackContext` - """ - self = cls.from_update(update, dispatcher) - self.error = error - self.async_args = async_args - self.async_kwargs = async_kwargs - return self - - @classmethod - def from_update(cls: Type[CC], update: object, dispatcher: 'Dispatcher') -> CC: - """ - Constructs an instance of :class:`telegram.ext.CallbackContext` to be passed to the - handlers. - - .. seealso:: :meth:`telegram.ext.Dispatcher.add_handler` - - Args: - update (:obj:`object` | :class:`telegram.Update`): The update. - dispatcher (:class:`telegram.ext.Dispatcher`): The dispatcher associated with this - context. - - Returns: - :class:`telegram.ext.CallbackContext` - """ - self = cls(dispatcher) - - if update is not None and isinstance(update, Update): - chat = update.effective_chat - user = update.effective_user - - if chat: - self._chat_id_and_data = ( - chat.id, - dispatcher.chat_data[chat.id], # pylint: disable=W0212 - ) - if user: - self._user_id_and_data = ( - user.id, - dispatcher.user_data[user.id], # pylint: disable=W0212 - ) - return self - - @classmethod - def from_job(cls: Type[CC], job: 'Job', dispatcher: 'Dispatcher') -> CC: - """ - Constructs an instance of :class:`telegram.ext.CallbackContext` to be passed to a - job callback. - - .. seealso:: :meth:`telegram.ext.JobQueue` - - Args: - job (:class:`telegram.ext.Job`): The job. - dispatcher (:class:`telegram.ext.Dispatcher`): The dispatcher associated with this - context. - - Returns: - :class:`telegram.ext.CallbackContext` - """ - self = cls(dispatcher) - self.job = job - return self - - def update(self, data: Dict[str, object]) -> None: - """Updates ``self.__slots__`` with the passed data. - - Args: - data (Dict[:obj:`str`, :obj:`object`]): The data. - """ - for key, value in data.items(): - setattr(self, key, value) - - @property - def bot(self) -> 'Bot': - """:class:`telegram.Bot`: The bot associated with this context.""" - return self._dispatcher.bot - - @property - def job_queue(self) -> Optional['JobQueue']: - """ - :class:`telegram.ext.JobQueue`: The ``JobQueue`` used by the - :class:`telegram.ext.Dispatcher` and (usually) the :class:`telegram.ext.Updater` - associated with this context. - - """ - return self._dispatcher.job_queue - - @property - def update_queue(self) -> Queue: - """ - :class:`queue.Queue`: The ``Queue`` instance used by the - :class:`telegram.ext.Dispatcher` and (usually) the :class:`telegram.ext.Updater` - associated with this context. - - """ - return self._dispatcher.update_queue - - @property - def match(self) -> Optional[Match[str]]: - """ - `Regex match type`: The first match from :attr:`matches`. - Useful if you are only filtering using a single regex filter. - Returns `None` if :attr:`matches` is empty. - """ - try: - return self.matches[0] # type: ignore[index] # pylint: disable=unsubscriptable-object - except (IndexError, TypeError): - return None diff --git a/venv/lib/python3.8/site-packages/telegram/ext/callbackdatacache.py b/venv/lib/python3.8/site-packages/telegram/ext/callbackdatacache.py deleted file mode 100644 index ac60e47..0000000 --- a/venv/lib/python3.8/site-packages/telegram/ext/callbackdatacache.py +++ /dev/null @@ -1,427 +0,0 @@ -#!/usr/bin/env python - -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. - -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the CallbackDataCache class.""" -import logging -import time -from datetime import datetime -from threading import Lock -from typing import Dict, Tuple, Union, Optional, MutableMapping, TYPE_CHECKING, cast -from uuid import uuid4 - -from cachetools import LRUCache # pylint: disable=E0401 - -from telegram import ( - InlineKeyboardMarkup, - InlineKeyboardButton, - TelegramError, - CallbackQuery, - Message, - User, -) -from telegram.utils.helpers import to_float_timestamp -from telegram.ext.utils.types import CDCData - -if TYPE_CHECKING: - from telegram.ext import ExtBot - - -class InvalidCallbackData(TelegramError): - """ - Raised when the received callback data has been tempered with or deleted from cache. - - .. versionadded:: 13.6 - - Args: - callback_data (:obj:`int`, optional): The button data of which the callback data could not - be found. - - Attributes: - callback_data (:obj:`int`): Optional. The button data of which the callback data could not - be found. - """ - - __slots__ = ('callback_data',) - - def __init__(self, callback_data: str = None) -> None: - super().__init__( - 'The object belonging to this callback_data was deleted or the callback_data was ' - 'manipulated.' - ) - self.callback_data = callback_data - - def __reduce__(self) -> Tuple[type, Tuple[Optional[str]]]: # type: ignore[override] - return self.__class__, (self.callback_data,) - - -class _KeyboardData: - __slots__ = ('keyboard_uuid', 'button_data', 'access_time') - - def __init__( - self, keyboard_uuid: str, access_time: float = None, button_data: Dict[str, object] = None - ): - self.keyboard_uuid = keyboard_uuid - self.button_data = button_data or {} - self.access_time = access_time or time.time() - - def update_access_time(self) -> None: - """Updates the access time with the current time.""" - self.access_time = time.time() - - def to_tuple(self) -> Tuple[str, float, Dict[str, object]]: - """Gives a tuple representation consisting of the keyboard uuid, the access time and the - button data. - """ - return self.keyboard_uuid, self.access_time, self.button_data - - -class CallbackDataCache: - """A custom cache for storing the callback data of a :class:`telegram.ext.ExtBot`. Internally, - it keeps two mappings with fixed maximum size: - - * One for mapping the data received in callback queries to the cached objects - * One for mapping the IDs of received callback queries to the cached objects - - The second mapping allows to manually drop data that has been cached for keyboards of messages - sent via inline mode. - If necessary, will drop the least recently used items. - - .. versionadded:: 13.6 - - Args: - bot (:class:`telegram.ext.ExtBot`): The bot this cache is for. - maxsize (:obj:`int`, optional): Maximum number of items in each of the internal mappings. - Defaults to 1024. - persistent_data (:obj:`telegram.ext.utils.types.CDCData`, optional): Data to initialize - the cache with, as returned by :meth:`telegram.ext.BasePersistence.get_callback_data`. - - Attributes: - bot (:class:`telegram.ext.ExtBot`): The bot this cache is for. - maxsize (:obj:`int`): maximum size of the cache. - - """ - - __slots__ = ('bot', 'maxsize', '_keyboard_data', '_callback_queries', '__lock', 'logger') - - def __init__( - self, - bot: 'ExtBot', - maxsize: int = 1024, - persistent_data: CDCData = None, - ): - self.logger = logging.getLogger(__name__) - - self.bot = bot - self.maxsize = maxsize - self._keyboard_data: MutableMapping[str, _KeyboardData] = LRUCache(maxsize=maxsize) - self._callback_queries: MutableMapping[str, str] = LRUCache(maxsize=maxsize) - self.__lock = Lock() - - if persistent_data: - keyboard_data, callback_queries = persistent_data - for key, value in callback_queries.items(): - self._callback_queries[key] = value - for uuid, access_time, data in keyboard_data: - self._keyboard_data[uuid] = _KeyboardData( - keyboard_uuid=uuid, access_time=access_time, button_data=data - ) - - @property - def persistence_data(self) -> CDCData: - """:obj:`telegram.ext.utils.types.CDCData`: The data that needs to be persisted to allow - caching callback data across bot reboots. - """ - # While building a list/dict from the LRUCaches has linear runtime (in the number of - # entries), the runtime is bounded by maxsize and it has the big upside of not throwing a - # highly customized data structure at users trying to implement a custom persistence class - with self.__lock: - return [data.to_tuple() for data in self._keyboard_data.values()], dict( - self._callback_queries.items() - ) - - def process_keyboard(self, reply_markup: InlineKeyboardMarkup) -> InlineKeyboardMarkup: - """Registers the reply markup to the cache. If any of the buttons have - :attr:`callback_data`, stores that data and builds a new keyboard with the correspondingly - replaced buttons. Otherwise does nothing and returns the original reply markup. - - Args: - reply_markup (:class:`telegram.InlineKeyboardMarkup`): The keyboard. - - Returns: - :class:`telegram.InlineKeyboardMarkup`: The keyboard to be passed to Telegram. - - """ - with self.__lock: - return self.__process_keyboard(reply_markup) - - def __process_keyboard(self, reply_markup: InlineKeyboardMarkup) -> InlineKeyboardMarkup: - keyboard_uuid = uuid4().hex - keyboard_data = _KeyboardData(keyboard_uuid) - - # Built a new nested list of buttons by replacing the callback data if needed - buttons = [ - [ - # We create a new button instead of replacing callback_data in case the - # same object is used elsewhere - InlineKeyboardButton( - btn.text, - callback_data=self.__put_button(btn.callback_data, keyboard_data), - ) - if btn.callback_data - else btn - for btn in column - ] - for column in reply_markup.inline_keyboard - ] - - if not keyboard_data.button_data: - # If we arrive here, no data had to be replaced and we can return the input - return reply_markup - - self._keyboard_data[keyboard_uuid] = keyboard_data - return InlineKeyboardMarkup(buttons) - - @staticmethod - def __put_button(callback_data: object, keyboard_data: _KeyboardData) -> str: - """Stores the data for a single button in :attr:`keyboard_data`. - Returns the string that should be passed instead of the callback_data, which is - ``keyboard_uuid + button_uuids``. - """ - uuid = uuid4().hex - keyboard_data.button_data[uuid] = callback_data - return f'{keyboard_data.keyboard_uuid}{uuid}' - - def __get_keyboard_uuid_and_button_data( - self, callback_data: str - ) -> Union[Tuple[str, object], Tuple[None, InvalidCallbackData]]: - keyboard, button = self.extract_uuids(callback_data) - try: - # we get the values before calling update() in case KeyErrors are raised - # we don't want to update in that case - keyboard_data = self._keyboard_data[keyboard] - button_data = keyboard_data.button_data[button] - # Update the timestamp for the LRU - keyboard_data.update_access_time() - return keyboard, button_data - except KeyError: - return None, InvalidCallbackData(callback_data) - - @staticmethod - def extract_uuids(callback_data: str) -> Tuple[str, str]: - """Extracts the keyboard uuid and the button uuid from the given ``callback_data``. - - Args: - callback_data (:obj:`str`): The ``callback_data`` as present in the button. - - Returns: - (:obj:`str`, :obj:`str`): Tuple of keyboard and button uuid - - """ - # Extract the uuids as put in __put_button - return callback_data[:32], callback_data[32:] - - def process_message(self, message: Message) -> None: - """Replaces the data in the inline keyboard attached to the message with the cached - objects, if necessary. If the data could not be found, - :class:`telegram.ext.InvalidCallbackData` will be inserted. - - Note: - Checks :attr:`telegram.Message.via_bot` and :attr:`telegram.Message.from_user` to check - if the reply markup (if any) was actually sent by this caches bot. If it was not, the - message will be returned unchanged. - - Note that this will fail for channel posts, as :attr:`telegram.Message.from_user` is - :obj:`None` for those! In the corresponding reply markups the callback data will be - replaced by :class:`telegram.ext.InvalidCallbackData`. - - Warning: - * Does *not* consider :attr:`telegram.Message.reply_to_message` and - :attr:`telegram.Message.pinned_message`. Pass them to these method separately. - * *In place*, i.e. the passed :class:`telegram.Message` will be changed! - - Args: - message (:class:`telegram.Message`): The message. - - """ - with self.__lock: - self.__process_message(message) - - def __process_message(self, message: Message) -> Optional[str]: - """As documented in process_message, but returns the uuid of the attached keyboard, if any, - which is relevant for process_callback_query. - - **IN PLACE** - """ - if not message.reply_markup: - return None - - if message.via_bot: - sender: Optional[User] = message.via_bot - elif message.from_user: - sender = message.from_user - else: - sender = None - - if sender is not None and sender != self.bot.bot: - return None - - keyboard_uuid = None - - for row in message.reply_markup.inline_keyboard: - for button in row: - if button.callback_data: - button_data = cast(str, button.callback_data) - keyboard_id, callback_data = self.__get_keyboard_uuid_and_button_data( - button_data - ) - # update_callback_data makes sure that the _id_attrs are updated - button.update_callback_data(callback_data) - - # This is lazy loaded. The firsts time we find a button - # we load the associated keyboard - afterwards, there is - if not keyboard_uuid and not isinstance(callback_data, InvalidCallbackData): - keyboard_uuid = keyboard_id - - return keyboard_uuid - - def process_callback_query(self, callback_query: CallbackQuery) -> None: - """Replaces the data in the callback query and the attached messages keyboard with the - cached objects, if necessary. If the data could not be found, - :class:`telegram.ext.InvalidCallbackData` will be inserted. - If :attr:`callback_query.data` or :attr:`callback_query.message` is present, this also - saves the callback queries ID in order to be able to resolve it to the stored data. - - Note: - Also considers inserts data into the buttons of - :attr:`telegram.Message.reply_to_message` and :attr:`telegram.Message.pinned_message` - if necessary. - - Warning: - *In place*, i.e. the passed :class:`telegram.CallbackQuery` will be changed! - - Args: - callback_query (:class:`telegram.CallbackQuery`): The callback query. - - """ - with self.__lock: - mapped = False - - if callback_query.data: - data = callback_query.data - - # Get the cached callback data for the CallbackQuery - keyboard_uuid, button_data = self.__get_keyboard_uuid_and_button_data(data) - callback_query.data = button_data # type: ignore[assignment] - - # Map the callback queries ID to the keyboards UUID for later use - if not mapped and not isinstance(button_data, InvalidCallbackData): - self._callback_queries[callback_query.id] = keyboard_uuid # type: ignore - mapped = True - - # Get the cached callback data for the inline keyboard attached to the - # CallbackQuery. - if callback_query.message: - self.__process_message(callback_query.message) - for message in ( - callback_query.message.pinned_message, - callback_query.message.reply_to_message, - ): - if message: - self.__process_message(message) - - def drop_data(self, callback_query: CallbackQuery) -> None: - """Deletes the data for the specified callback query. - - Note: - Will *not* raise exceptions in case the callback data is not found in the cache. - *Will* raise :class:`KeyError` in case the callback query can not be found in the - cache. - - Args: - callback_query (:class:`telegram.CallbackQuery`): The callback query. - - Raises: - KeyError: If the callback query can not be found in the cache - """ - with self.__lock: - try: - keyboard_uuid = self._callback_queries.pop(callback_query.id) - self.__drop_keyboard(keyboard_uuid) - except KeyError as exc: - raise KeyError('CallbackQuery was not found in cache.') from exc - - def __drop_keyboard(self, keyboard_uuid: str) -> None: - try: - self._keyboard_data.pop(keyboard_uuid) - except KeyError: - return - - def clear_callback_data(self, time_cutoff: Union[float, datetime] = None) -> None: - """Clears the stored callback data. - - Args: - time_cutoff (:obj:`float` | :obj:`datetime.datetime`, optional): Pass a UNIX timestamp - or a :obj:`datetime.datetime` to clear only entries which are older. - For timezone naive :obj:`datetime.datetime` objects, the default timezone of the - bot will be used. - - """ - with self.__lock: - self.__clear(self._keyboard_data, time_cutoff=time_cutoff) - - def clear_callback_queries(self) -> None: - """Clears the stored callback query IDs.""" - with self.__lock: - self.__clear(self._callback_queries) - - def __clear(self, mapping: MutableMapping, time_cutoff: Union[float, datetime] = None) -> None: - if not time_cutoff: - mapping.clear() - return - - if isinstance(time_cutoff, datetime): - effective_cutoff = to_float_timestamp( - time_cutoff, tzinfo=self.bot.defaults.tzinfo if self.bot.defaults else None - ) - else: - effective_cutoff = time_cutoff - - # We need a list instead of a generator here, as the list doesn't change it's size - # during the iteration - to_drop = [key for key, data in mapping.items() if data.access_time < effective_cutoff] - for key in to_drop: - mapping.pop(key) diff --git a/venv/lib/python3.8/site-packages/telegram/ext/callbackqueryhandler.py b/venv/lib/python3.8/site-packages/telegram/ext/callbackqueryhandler.py deleted file mode 100644 index beea75f..0000000 --- a/venv/lib/python3.8/site-packages/telegram/ext/callbackqueryhandler.py +++ /dev/null @@ -1,236 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the CallbackQueryHandler class.""" - -import re -from typing import ( - TYPE_CHECKING, - Callable, - Dict, - Match, - Optional, - Pattern, - TypeVar, - Union, - cast, -) - -from telegram import Update -from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE - -from .handler import Handler -from .utils.types import CCT - -if TYPE_CHECKING: - from telegram.ext import Dispatcher - -RT = TypeVar('RT') - - -class CallbackQueryHandler(Handler[Update, CCT]): - """Handler class to handle Telegram callback queries. Optionally based on a regex. - - Read the documentation of the ``re`` module for more information. - - Note: - * :attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you - can use to keep any data in will be sent to the :attr:`callback` function. Related to - either the user or the chat that the update was sent in. For each update from the same - user or in the same chat, it will be the same ``dict``. - - Note that this is DEPRECATED, and you should use context based callbacks. See - https://git.io/fxJuV for more info. - * If your bot allows arbitrary objects as ``callback_data``, it may happen that the - original ``callback_data`` for the incoming :class:`telegram.CallbackQuery`` can not be - found. This is the case when either a malicious client tempered with the - ``callback_data`` or the data was simply dropped from cache or not persisted. In these - cases, an instance of :class:`telegram.ext.InvalidCallbackData` will be set as - ``callback_data``. - - .. versionadded:: 13.6 - - Warning: - When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - Args: - callback (:obj:`callable`): The callback function for this handler. Will be called when - :attr:`check_update` has determined that an update should be processed by this handler. - Callback signature for context based API: - - ``def callback(update: Update, context: CallbackContext)`` - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``update_queue`` will be passed to the callback function. It will be the ``Queue`` - instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher` - that contains new updates which can be used to insert updates. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``job_queue`` will be passed to the callback function. It will be a - :class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater` - which can be used to schedule new jobs. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - pattern (:obj:`str` | `Pattern` | :obj:`callable` | :obj:`type`, optional): - Pattern to test :attr:`telegram.CallbackQuery.data` against. If a string or a regex - pattern is passed, :meth:`re.match` is used on :attr:`telegram.CallbackQuery.data` to - determine if an update should be handled by this handler. If your bot allows arbitrary - objects as ``callback_data``, non-strings will be accepted. To filter arbitrary - objects you may pass - - * a callable, accepting exactly one argument, namely the - :attr:`telegram.CallbackQuery.data`. It must return :obj:`True` or - :obj:`False`/:obj:`None` to indicate, whether the update should be handled. - * a :obj:`type`. If :attr:`telegram.CallbackQuery.data` is an instance of that type - (or a subclass), the update will be handled. - - If :attr:`telegram.CallbackQuery.data` is :obj:`None`, the - :class:`telegram.CallbackQuery` update will not be handled. - - .. versionchanged:: 13.6 - Added support for arbitrary callback data. - pass_groups (:obj:`bool`, optional): If the callback should be passed the result of - ``re.match(pattern, data).groups()`` as a keyword argument called ``groups``. - Default is :obj:`False` - DEPRECATED: Please switch to context based callbacks. - pass_groupdict (:obj:`bool`, optional): If the callback should be passed the result of - ``re.match(pattern, data).groupdict()`` as a keyword argument called ``groupdict``. - Default is :obj:`False` - DEPRECATED: Please switch to context based callbacks. - pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``user_data`` will be passed to the callback function. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``chat_data`` will be passed to the callback function. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - run_async (:obj:`bool`): Determines whether the callback will run asynchronously. - Defaults to :obj:`False`. - - Attributes: - callback (:obj:`callable`): The callback function for this handler. - pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be - passed to the callback function. - pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to - the callback function. - pattern (`Pattern` | :obj:`callable` | :obj:`type`): Optional. Regex pattern, callback or - type to test :attr:`telegram.CallbackQuery.data` against. - - .. versionchanged:: 13.6 - Added support for arbitrary callback data. - pass_groups (:obj:`bool`): Determines whether ``groups`` will be passed to the - callback function. - pass_groupdict (:obj:`bool`): Determines whether ``groupdict``. will be passed to - the callback function. - pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to - the callback function. - pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to - the callback function. - run_async (:obj:`bool`): Determines whether the callback will run asynchronously. - - """ - - __slots__ = ('pattern', 'pass_groups', 'pass_groupdict') - - def __init__( - self, - callback: Callable[[Update, CCT], RT], - pass_update_queue: bool = False, - pass_job_queue: bool = False, - pattern: Union[str, Pattern, type, Callable[[object], Optional[bool]]] = None, - pass_groups: bool = False, - pass_groupdict: bool = False, - pass_user_data: bool = False, - pass_chat_data: bool = False, - run_async: Union[bool, DefaultValue] = DEFAULT_FALSE, - ): - super().__init__( - callback, - pass_update_queue=pass_update_queue, - pass_job_queue=pass_job_queue, - pass_user_data=pass_user_data, - pass_chat_data=pass_chat_data, - run_async=run_async, - ) - - if isinstance(pattern, str): - pattern = re.compile(pattern) - - self.pattern = pattern - self.pass_groups = pass_groups - self.pass_groupdict = pass_groupdict - - def check_update(self, update: object) -> Optional[Union[bool, object]]: - """Determines whether an update should be passed to this handlers :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - if isinstance(update, Update) and update.callback_query: - callback_data = update.callback_query.data - if self.pattern: - if callback_data is None: - return False - if isinstance(self.pattern, type): - return isinstance(callback_data, self.pattern) - if callable(self.pattern): - return self.pattern(callback_data) - match = re.match(self.pattern, callback_data) - if match: - return match - else: - return True - return None - - def collect_optional_args( - self, - dispatcher: 'Dispatcher', - update: Update = None, - check_result: Union[bool, Match] = None, - ) -> Dict[str, object]: - """Pass the results of ``re.match(pattern, data).{groups(), groupdict()}`` to the - callback as a keyword arguments called ``groups`` and ``groupdict``, respectively, if - needed. - """ - optional_args = super().collect_optional_args(dispatcher, update, check_result) - if self.pattern and not callable(self.pattern): - check_result = cast(Match, check_result) - if self.pass_groups: - optional_args['groups'] = check_result.groups() - if self.pass_groupdict: - optional_args['groupdict'] = check_result.groupdict() - return optional_args - - def collect_additional_context( - self, - context: CCT, - update: Update, - dispatcher: 'Dispatcher', - check_result: Union[bool, Match], - ) -> None: - """Add the result of ``re.match(pattern, update.callback_query.data)`` to - :attr:`CallbackContext.matches` as list with one element. - """ - if self.pattern: - check_result = cast(Match, check_result) - context.matches = [check_result] diff --git a/venv/lib/python3.8/site-packages/telegram/ext/chatmemberhandler.py b/venv/lib/python3.8/site-packages/telegram/ext/chatmemberhandler.py deleted file mode 100644 index 9499cfd..0000000 --- a/venv/lib/python3.8/site-packages/telegram/ext/chatmemberhandler.py +++ /dev/null @@ -1,145 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2019-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the ChatMemberHandler classes.""" -from typing import ClassVar, TypeVar, Union, Callable - -from telegram import Update -from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE -from .handler import Handler -from .utils.types import CCT - -RT = TypeVar('RT') - - -class ChatMemberHandler(Handler[Update, CCT]): - """Handler class to handle Telegram updates that contain a chat member update. - - .. versionadded:: 13.4 - - Note: - :attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you - can use to keep any data in will be sent to the :attr:`callback` function. Related to - either the user or the chat that the update was sent in. For each update from the same user - or in the same chat, it will be the same ``dict``. - - Note that this is DEPRECATED, and you should use context based callbacks. See - https://git.io/fxJuV for more info. - - Warning: - When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - Args: - callback (:obj:`callable`): The callback function for this handler. Will be called when - :attr:`check_update` has determined that an update should be processed by this handler. - Callback signature for context based API: - - ``def callback(update: Update, context: CallbackContext)`` - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - chat_member_types (:obj:`int`, optional): Pass one of :attr:`MY_CHAT_MEMBER`, - :attr:`CHAT_MEMBER` or :attr:`ANY_CHAT_MEMBER` to specify if this handler should handle - only updates with :attr:`telegram.Update.my_chat_member`, - :attr:`telegram.Update.chat_member` or both. Defaults to :attr:`MY_CHAT_MEMBER`. - pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``update_queue`` will be passed to the callback function. It will be the ``Queue`` - instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher` - that contains new updates which can be used to insert updates. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``job_queue`` will be passed to the callback function. It will be a - :class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater` - which can be used to schedule new jobs. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``user_data`` will be passed to the callback function. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``chat_data`` will be passed to the callback function. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - run_async (:obj:`bool`): Determines whether the callback will run asynchronously. - Defaults to :obj:`False`. - - Attributes: - callback (:obj:`callable`): The callback function for this handler. - chat_member_types (:obj:`int`, optional): Specifies if this handler should handle - only updates with :attr:`telegram.Update.my_chat_member`, - :attr:`telegram.Update.chat_member` or both. - pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be - passed to the callback function. - pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to - the callback function. - pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to - the callback function. - pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to - the callback function. - run_async (:obj:`bool`): Determines whether the callback will run asynchronously. - - """ - - __slots__ = ('chat_member_types',) - MY_CHAT_MEMBER: ClassVar[int] = -1 - """:obj:`int`: Used as a constant to handle only :attr:`telegram.Update.my_chat_member`.""" - CHAT_MEMBER: ClassVar[int] = 0 - """:obj:`int`: Used as a constant to handle only :attr:`telegram.Update.chat_member`.""" - ANY_CHAT_MEMBER: ClassVar[int] = 1 - """:obj:`int`: Used as a constant to handle bot :attr:`telegram.Update.my_chat_member` - and :attr:`telegram.Update.chat_member`.""" - - def __init__( - self, - callback: Callable[[Update, CCT], RT], - chat_member_types: int = MY_CHAT_MEMBER, - pass_update_queue: bool = False, - pass_job_queue: bool = False, - pass_user_data: bool = False, - pass_chat_data: bool = False, - run_async: Union[bool, DefaultValue] = DEFAULT_FALSE, - ): - super().__init__( - callback, - pass_update_queue=pass_update_queue, - pass_job_queue=pass_job_queue, - pass_user_data=pass_user_data, - pass_chat_data=pass_chat_data, - run_async=run_async, - ) - - self.chat_member_types = chat_member_types - - def check_update(self, update: object) -> bool: - """Determines whether an update should be passed to this handlers :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - if isinstance(update, Update): - if not (update.my_chat_member or update.chat_member): - return False - if self.chat_member_types == self.ANY_CHAT_MEMBER: - return True - if self.chat_member_types == self.CHAT_MEMBER: - return bool(update.chat_member) - return bool(update.my_chat_member) - return False diff --git a/venv/lib/python3.8/site-packages/telegram/ext/choseninlineresulthandler.py b/venv/lib/python3.8/site-packages/telegram/ext/choseninlineresulthandler.py deleted file mode 100644 index ec35289..0000000 --- a/venv/lib/python3.8/site-packages/telegram/ext/choseninlineresulthandler.py +++ /dev/null @@ -1,160 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the ChosenInlineResultHandler class.""" -import re -from typing import Optional, TypeVar, Union, Callable, TYPE_CHECKING, Pattern, Match, cast - -from telegram import Update - -from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE -from .handler import Handler -from .utils.types import CCT - -RT = TypeVar('RT') - -if TYPE_CHECKING: - from telegram.ext import CallbackContext, Dispatcher - - -class ChosenInlineResultHandler(Handler[Update, CCT]): - """Handler class to handle Telegram updates that contain a chosen inline result. - - Note: - :attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you - can use to keep any data in will be sent to the :attr:`callback` function. Related to - either the user or the chat that the update was sent in. For each update from the same user - or in the same chat, it will be the same ``dict``. - - Note that this is DEPRECATED, and you should use context based callbacks. See - https://git.io/fxJuV for more info. - - Warning: - When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - Args: - callback (:obj:`callable`): The callback function for this handler. Will be called when - :attr:`check_update` has determined that an update should be processed by this handler. - Callback signature for context based API: - - ``def callback(update: Update, context: CallbackContext)`` - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``update_queue`` will be passed to the callback function. It will be the ``Queue`` - instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher` - that contains new updates which can be used to insert updates. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``job_queue`` will be passed to the callback function. It will be a - :class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater` - which can be used to schedule new jobs. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``user_data`` will be passed to the callback function. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``chat_data`` will be passed to the callback function. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - run_async (:obj:`bool`): Determines whether the callback will run asynchronously. - Defaults to :obj:`False`. - pattern (:obj:`str` | `Pattern`, optional): Regex pattern. If not :obj:`None`, ``re.match`` - is used on :attr:`telegram.ChosenInlineResult.result_id` to determine if an update - should be handled by this handler. This is accessible in the callback as - :attr:`telegram.ext.CallbackContext.matches`. - - .. versionadded:: 13.6 - - Attributes: - callback (:obj:`callable`): The callback function for this handler. - pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be - passed to the callback function. - pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to - the callback function. - pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to - the callback function. - pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to - the callback function. - run_async (:obj:`bool`): Determines whether the callback will run asynchronously. - pattern (`Pattern`): Optional. Regex pattern to test - :attr:`telegram.ChosenInlineResult.result_id` against. - - .. versionadded:: 13.6 - - """ - - __slots__ = ('pattern',) - - def __init__( - self, - callback: Callable[[Update, 'CallbackContext'], RT], - pass_update_queue: bool = False, - pass_job_queue: bool = False, - pass_user_data: bool = False, - pass_chat_data: bool = False, - run_async: Union[bool, DefaultValue] = DEFAULT_FALSE, - pattern: Union[str, Pattern] = None, - ): - super().__init__( - callback, - pass_update_queue=pass_update_queue, - pass_job_queue=pass_job_queue, - pass_user_data=pass_user_data, - pass_chat_data=pass_chat_data, - run_async=run_async, - ) - - if isinstance(pattern, str): - pattern = re.compile(pattern) - - self.pattern = pattern - - def check_update(self, update: object) -> Optional[Union[bool, object]]: - """Determines whether an update should be passed to this handlers :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - if isinstance(update, Update) and update.chosen_inline_result: - if self.pattern: - match = re.match(self.pattern, update.chosen_inline_result.result_id) - if match: - return match - else: - return True - return None - - def collect_additional_context( - self, - context: 'CallbackContext', - update: Update, - dispatcher: 'Dispatcher', - check_result: Union[bool, Match], - ) -> None: - """This function adds the matched regex pattern result to - :attr:`telegram.ext.CallbackContext.matches`. - """ - if self.pattern: - check_result = cast(Match, check_result) - context.matches = [check_result] diff --git a/venv/lib/python3.8/site-packages/telegram/ext/commandhandler.py b/venv/lib/python3.8/site-packages/telegram/ext/commandhandler.py deleted file mode 100644 index 1f0a321..0000000 --- a/venv/lib/python3.8/site-packages/telegram/ext/commandhandler.py +++ /dev/null @@ -1,456 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the CommandHandler and PrefixHandler classes.""" -import re -import warnings -from typing import TYPE_CHECKING, Callable, Dict, List, Optional, Tuple, TypeVar, Union - -from telegram import MessageEntity, Update -from telegram.ext import BaseFilter, Filters -from telegram.utils.deprecate import TelegramDeprecationWarning -from telegram.utils.types import SLT -from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE - -from .utils.types import CCT -from .handler import Handler - -if TYPE_CHECKING: - from telegram.ext import Dispatcher - -RT = TypeVar('RT') - - -class CommandHandler(Handler[Update, CCT]): - """Handler class to handle Telegram commands. - - Commands are Telegram messages that start with ``/``, optionally followed by an ``@`` and the - bot's name and/or some additional text. The handler will add a ``list`` to the - :class:`CallbackContext` named :attr:`CallbackContext.args`. It will contain a list of strings, - which is the text following the command split on single or consecutive whitespace characters. - - By default the handler listens to messages as well as edited messages. To change this behavior - use ``~Filters.update.edited_message`` in the filter argument. - - Note: - * :class:`CommandHandler` does *not* handle (edited) channel posts. - * :attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a :obj:`dict` you - can use to keep any data in will be sent to the :attr:`callback` function. Related to - either the user or the chat that the update was sent in. For each update from the same - user or in the same chat, it will be the same :obj:`dict`. - - Note that this is DEPRECATED, and you should use context based callbacks. See - https://git.io/fxJuV for more info. - - Warning: - When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - Args: - command (:class:`telegram.utils.types.SLT[str]`): - The command or list of commands this handler should listen for. - Limitations are the same as described here https://core.telegram.org/bots#commands - callback (:obj:`callable`): The callback function for this handler. Will be called when - :attr:`check_update` has determined that an update should be processed by this handler. - Callback signature for context based API: - - ``def callback(update: Update, context: CallbackContext)`` - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - filters (:class:`telegram.ext.BaseFilter`, optional): A filter inheriting from - :class:`telegram.ext.filters.BaseFilter`. Standard filters can be found in - :class:`telegram.ext.filters.Filters`. Filters can be combined using bitwise - operators (& for and, | for or, ~ for not). - allow_edited (:obj:`bool`, optional): Determines whether the handler should also accept - edited messages. Default is :obj:`False`. - DEPRECATED: Edited is allowed by default. To change this behavior use - ``~Filters.update.edited_message``. - pass_args (:obj:`bool`, optional): Determines whether the handler should be passed the - arguments passed to the command as a keyword argument called ``args``. It will contain - a list of strings, which is the text following the command split on single or - consecutive whitespace characters. Default is :obj:`False` - DEPRECATED: Please switch to context based callbacks. - pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``update_queue`` will be passed to the callback function. It will be the ``Queue`` - instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher` - that contains new updates which can be used to insert updates. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``job_queue`` will be passed to the callback function. It will be a - :class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater` - which can be used to schedule new jobs. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``user_data`` will be passed to the callback function. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``chat_data`` will be passed to the callback function. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - run_async (:obj:`bool`): Determines whether the callback will run asynchronously. - Defaults to :obj:`False`. - - Raises: - ValueError: when command is too long or has illegal chars. - - Attributes: - command (:class:`telegram.utils.types.SLT[str]`): - The command or list of commands this handler should listen for. - Limitations are the same as described here https://core.telegram.org/bots#commands - callback (:obj:`callable`): The callback function for this handler. - filters (:class:`telegram.ext.BaseFilter`): Optional. Only allow updates with these - Filters. - allow_edited (:obj:`bool`): Determines whether the handler should also accept - edited messages. - pass_args (:obj:`bool`): Determines whether the handler should be passed - ``args``. - pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be - passed to the callback function. - pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to - the callback function. - pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to - the callback function. - pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to - the callback function. - run_async (:obj:`bool`): Determines whether the callback will run asynchronously. - """ - - __slots__ = ('command', 'filters', 'pass_args') - - def __init__( - self, - command: SLT[str], - callback: Callable[[Update, CCT], RT], - filters: BaseFilter = None, - allow_edited: bool = None, - pass_args: bool = False, - pass_update_queue: bool = False, - pass_job_queue: bool = False, - pass_user_data: bool = False, - pass_chat_data: bool = False, - run_async: Union[bool, DefaultValue] = DEFAULT_FALSE, - ): - super().__init__( - callback, - pass_update_queue=pass_update_queue, - pass_job_queue=pass_job_queue, - pass_user_data=pass_user_data, - pass_chat_data=pass_chat_data, - run_async=run_async, - ) - - if isinstance(command, str): - self.command = [command.lower()] - else: - self.command = [x.lower() for x in command] - for comm in self.command: - if not re.match(r'^[\da-z_]{1,32}$', comm): - raise ValueError('Command is not a valid bot command') - - if filters: - self.filters = Filters.update.messages & filters - else: - self.filters = Filters.update.messages - - if allow_edited is not None: - warnings.warn( - 'allow_edited is deprecated. See https://git.io/fxJuV for more info', - TelegramDeprecationWarning, - stacklevel=2, - ) - if not allow_edited: - self.filters &= ~Filters.update.edited_message - self.pass_args = pass_args - - def check_update( - self, update: object - ) -> Optional[Union[bool, Tuple[List[str], Optional[Union[bool, Dict]]]]]: - """Determines whether an update should be passed to this handlers :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`list`: The list of args for the handler. - - """ - if isinstance(update, Update) and update.effective_message: - message = update.effective_message - - if ( - message.entities - and message.entities[0].type == MessageEntity.BOT_COMMAND - and message.entities[0].offset == 0 - and message.text - and message.bot - ): - command = message.text[1 : message.entities[0].length] - args = message.text.split()[1:] - command_parts = command.split('@') - command_parts.append(message.bot.username) - - if not ( - command_parts[0].lower() in self.command - and command_parts[1].lower() == message.bot.username.lower() - ): - return None - - filter_result = self.filters(update) - if filter_result: - return args, filter_result - return False - return None - - def collect_optional_args( - self, - dispatcher: 'Dispatcher', - update: Update = None, - check_result: Optional[Union[bool, Tuple[List[str], Optional[bool]]]] = None, - ) -> Dict[str, object]: - """Provide text after the command to the callback the ``args`` argument as list, split on - single whitespaces. - """ - optional_args = super().collect_optional_args(dispatcher, update) - if self.pass_args and isinstance(check_result, tuple): - optional_args['args'] = check_result[0] - return optional_args - - def collect_additional_context( - self, - context: CCT, - update: Update, - dispatcher: 'Dispatcher', - check_result: Optional[Union[bool, Tuple[List[str], Optional[bool]]]], - ) -> None: - """Add text after the command to :attr:`CallbackContext.args` as list, split on single - whitespaces and add output of data filters to :attr:`CallbackContext` as well. - """ - if isinstance(check_result, tuple): - context.args = check_result[0] - if isinstance(check_result[1], dict): - context.update(check_result[1]) - - -class PrefixHandler(CommandHandler): - """Handler class to handle custom prefix commands. - - This is a intermediate handler between :class:`MessageHandler` and :class:`CommandHandler`. - It supports configurable commands with the same options as CommandHandler. It will respond to - every combination of :attr:`prefix` and :attr:`command`. It will add a ``list`` to the - :class:`CallbackContext` named :attr:`CallbackContext.args`. It will contain a list of strings, - which is the text following the command split on single or consecutive whitespace characters. - - Examples: - - Single prefix and command: - - .. code:: python - - PrefixHandler('!', 'test', callback) # will respond to '!test'. - - Multiple prefixes, single command: - - .. code:: python - - PrefixHandler(['!', '#'], 'test', callback) # will respond to '!test' and '#test'. - - Multiple prefixes and commands: - - .. code:: python - - PrefixHandler(['!', '#'], ['test', 'help'], callback) # will respond to '!test', \ - '#test', '!help' and '#help'. - - - By default the handler listens to messages as well as edited messages. To change this behavior - use ``~Filters.update.edited_message``. - - Note: - * :class:`PrefixHandler` does *not* handle (edited) channel posts. - * :attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a :obj:`dict` you - can use to keep any data in will be sent to the :attr:`callback` function. Related to - either the user or the chat that the update was sent in. For each update from the same - user or in the same chat, it will be the same :obj:`dict`. - - Note that this is DEPRECATED, and you should use context based callbacks. See - https://git.io/fxJuV for more info. - - Warning: - When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - Args: - prefix (:class:`telegram.utils.types.SLT[str]`): - The prefix(es) that will precede :attr:`command`. - command (:class:`telegram.utils.types.SLT[str]`): - The command or list of commands this handler should listen for. - callback (:obj:`callable`): The callback function for this handler. Will be called when - :attr:`check_update` has determined that an update should be processed by this handler. - Callback signature for context based API: - - ``def callback(update: Update, context: CallbackContext)`` - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - filters (:class:`telegram.ext.BaseFilter`, optional): A filter inheriting from - :class:`telegram.ext.filters.BaseFilter`. Standard filters can be found in - :class:`telegram.ext.filters.Filters`. Filters can be combined using bitwise - operators (& for and, | for or, ~ for not). - pass_args (:obj:`bool`, optional): Determines whether the handler should be passed the - arguments passed to the command as a keyword argument called ``args``. It will contain - a list of strings, which is the text following the command split on single or - consecutive whitespace characters. Default is :obj:`False` - DEPRECATED: Please switch to context based callbacks. - pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``update_queue`` will be passed to the callback function. It will be the ``Queue`` - instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher` - that contains new updates which can be used to insert updates. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``job_queue`` will be passed to the callback function. It will be a - :class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater` - which can be used to schedule new jobs. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``user_data`` will be passed to the callback function. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``chat_data`` will be passed to the callback function. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - run_async (:obj:`bool`): Determines whether the callback will run asynchronously. - Defaults to :obj:`False`. - - Attributes: - callback (:obj:`callable`): The callback function for this handler. - filters (:class:`telegram.ext.BaseFilter`): Optional. Only allow updates with these - Filters. - pass_args (:obj:`bool`): Determines whether the handler should be passed - ``args``. - pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be - passed to the callback function. - pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to - the callback function. - pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to - the callback function. - pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to - the callback function. - run_async (:obj:`bool`): Determines whether the callback will run asynchronously. - - """ - - # 'prefix' is a class property, & 'command' is included in the superclass, so they're left out. - __slots__ = ('_prefix', '_command', '_commands') - - def __init__( - self, - prefix: SLT[str], - command: SLT[str], - callback: Callable[[Update, CCT], RT], - filters: BaseFilter = None, - pass_args: bool = False, - pass_update_queue: bool = False, - pass_job_queue: bool = False, - pass_user_data: bool = False, - pass_chat_data: bool = False, - run_async: Union[bool, DefaultValue] = DEFAULT_FALSE, - ): - - self._prefix: List[str] = [] - self._command: List[str] = [] - self._commands: List[str] = [] - - super().__init__( - 'nocommand', - callback, - filters=filters, - allow_edited=None, - pass_args=pass_args, - pass_update_queue=pass_update_queue, - pass_job_queue=pass_job_queue, - pass_user_data=pass_user_data, - pass_chat_data=pass_chat_data, - run_async=run_async, - ) - - self.prefix = prefix # type: ignore[assignment] - self.command = command # type: ignore[assignment] - self._build_commands() - - @property - def prefix(self) -> List[str]: - """ - The prefixes that will precede :attr:`command`. - - Returns: - List[:obj:`str`] - """ - return self._prefix - - @prefix.setter - def prefix(self, prefix: Union[str, List[str]]) -> None: - if isinstance(prefix, str): - self._prefix = [prefix.lower()] - else: - self._prefix = prefix - self._build_commands() - - @property # type: ignore[override] - def command(self) -> List[str]: # type: ignore[override] - """ - The list of commands this handler should listen for. - - Returns: - List[:obj:`str`] - """ - return self._command - - @command.setter - def command(self, command: Union[str, List[str]]) -> None: - if isinstance(command, str): - self._command = [command.lower()] - else: - self._command = command - self._build_commands() - - def _build_commands(self) -> None: - self._commands = [x.lower() + y.lower() for x in self.prefix for y in self.command] - - def check_update( - self, update: object - ) -> Optional[Union[bool, Tuple[List[str], Optional[Union[bool, Dict]]]]]: - """Determines whether an update should be passed to this handlers :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`list`: The list of args for the handler. - - """ - if isinstance(update, Update) and update.effective_message: - message = update.effective_message - - if message.text: - text_list = message.text.split() - if text_list[0].lower() not in self._commands: - return None - filter_result = self.filters(update) - if filter_result: - return text_list[1:], filter_result - return False - return None diff --git a/venv/lib/python3.8/site-packages/telegram/ext/contexttypes.py b/venv/lib/python3.8/site-packages/telegram/ext/contexttypes.py deleted file mode 100644 index 2156e7f..0000000 --- a/venv/lib/python3.8/site-packages/telegram/ext/contexttypes.py +++ /dev/null @@ -1,194 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2020 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -# pylint: disable=R0201 -"""This module contains the auxiliary class ContextTypes.""" -from typing import Type, Generic, overload, Dict # pylint: disable=W0611 - -from telegram.ext.callbackcontext import CallbackContext -from telegram.ext.utils.types import CCT, UD, CD, BD - - -class ContextTypes(Generic[CCT, UD, CD, BD]): - """ - Convenience class to gather customizable types of the :class:`telegram.ext.CallbackContext` - interface. - - .. versionadded:: 13.6 - - Args: - context (:obj:`type`, optional): Determines the type of the ``context`` argument of all - (error-)handler callbacks and job callbacks. Must be a subclass of - :class:`telegram.ext.CallbackContext`. Defaults to - :class:`telegram.ext.CallbackContext`. - bot_data (:obj:`type`, optional): Determines the type of ``context.bot_data`` of all - (error-)handler callbacks and job callbacks. Defaults to :obj:`dict`. Must support - instantiating without arguments. - chat_data (:obj:`type`, optional): Determines the type of ``context.chat_data`` of all - (error-)handler callbacks and job callbacks. Defaults to :obj:`dict`. Must support - instantiating without arguments. - user_data (:obj:`type`, optional): Determines the type of ``context.user_data`` of all - (error-)handler callbacks and job callbacks. Defaults to :obj:`dict`. Must support - instantiating without arguments. - - """ - - __slots__ = ('_context', '_bot_data', '_chat_data', '_user_data') - - @overload - def __init__( - self: 'ContextTypes[CallbackContext, Dict, Dict, Dict]', - ): - ... - - @overload - def __init__(self: 'ContextTypes[CCT, Dict, Dict, Dict]', context: Type[CCT]): - ... - - @overload - def __init__(self: 'ContextTypes[CallbackContext, UD, Dict, Dict]', bot_data: Type[UD]): - ... - - @overload - def __init__(self: 'ContextTypes[CallbackContext, Dict, CD, Dict]', chat_data: Type[CD]): - ... - - @overload - def __init__(self: 'ContextTypes[CallbackContext, Dict, Dict, BD]', user_data: Type[BD]): - ... - - @overload - def __init__( - self: 'ContextTypes[CCT, UD, Dict, Dict]', context: Type[CCT], bot_data: Type[UD] - ): - ... - - @overload - def __init__( - self: 'ContextTypes[CCT, Dict, CD, Dict]', context: Type[CCT], chat_data: Type[CD] - ): - ... - - @overload - def __init__( - self: 'ContextTypes[CCT, Dict, Dict, BD]', context: Type[CCT], user_data: Type[BD] - ): - ... - - @overload - def __init__( - self: 'ContextTypes[CallbackContext, UD, CD, Dict]', - bot_data: Type[UD], - chat_data: Type[CD], - ): - ... - - @overload - def __init__( - self: 'ContextTypes[CallbackContext, UD, Dict, BD]', - bot_data: Type[UD], - user_data: Type[BD], - ): - ... - - @overload - def __init__( - self: 'ContextTypes[CallbackContext, Dict, CD, BD]', - chat_data: Type[CD], - user_data: Type[BD], - ): - ... - - @overload - def __init__( - self: 'ContextTypes[CCT, UD, CD, Dict]', - context: Type[CCT], - bot_data: Type[UD], - chat_data: Type[CD], - ): - ... - - @overload - def __init__( - self: 'ContextTypes[CCT, UD, Dict, BD]', - context: Type[CCT], - bot_data: Type[UD], - user_data: Type[BD], - ): - ... - - @overload - def __init__( - self: 'ContextTypes[CCT, Dict, CD, BD]', - context: Type[CCT], - chat_data: Type[CD], - user_data: Type[BD], - ): - ... - - @overload - def __init__( - self: 'ContextTypes[CallbackContext, UD, CD, BD]', - bot_data: Type[UD], - chat_data: Type[CD], - user_data: Type[BD], - ): - ... - - @overload - def __init__( - self: 'ContextTypes[CCT, UD, CD, BD]', - context: Type[CCT], - bot_data: Type[UD], - chat_data: Type[CD], - user_data: Type[BD], - ): - ... - - def __init__( # type: ignore[no-untyped-def] - self, - context=CallbackContext, - bot_data=dict, - chat_data=dict, - user_data=dict, - ): - if not issubclass(context, CallbackContext): - raise ValueError('context must be a subclass of CallbackContext.') - - # We make all those only accessible via properties because we don't currently support - # changing this at runtime, so overriding the attributes doesn't make sense - self._context = context - self._bot_data = bot_data - self._chat_data = chat_data - self._user_data = user_data - - @property - def context(self) -> Type[CCT]: - return self._context - - @property - def bot_data(self) -> Type[BD]: - return self._bot_data - - @property - def chat_data(self) -> Type[CD]: - return self._chat_data - - @property - def user_data(self) -> Type[UD]: - return self._user_data diff --git a/venv/lib/python3.8/site-packages/telegram/ext/conversationhandler.py b/venv/lib/python3.8/site-packages/telegram/ext/conversationhandler.py deleted file mode 100644 index df94f9b..0000000 --- a/venv/lib/python3.8/site-packages/telegram/ext/conversationhandler.py +++ /dev/null @@ -1,725 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -# pylint: disable=R0201 -"""This module contains the ConversationHandler.""" - -import logging -import warnings -import functools -import datetime -from threading import Lock -from typing import TYPE_CHECKING, Dict, List, NoReturn, Optional, Union, Tuple, cast, ClassVar - -from telegram import Update -from telegram.ext import ( - BasePersistence, - CallbackContext, - CallbackQueryHandler, - ChosenInlineResultHandler, - DispatcherHandlerStop, - Handler, - InlineQueryHandler, -) -from telegram.ext.utils.promise import Promise -from telegram.ext.utils.types import ConversationDict -from telegram.ext.utils.types import CCT - -if TYPE_CHECKING: - from telegram.ext import Dispatcher, Job -CheckUpdateType = Optional[Tuple[Tuple[int, ...], Handler, object]] - - -class _ConversationTimeoutContext: - # '__dict__' is not included since this a private class - __slots__ = ('conversation_key', 'update', 'dispatcher', 'callback_context') - - def __init__( - self, - conversation_key: Tuple[int, ...], - update: Update, - dispatcher: 'Dispatcher', - callback_context: Optional[CallbackContext], - ): - self.conversation_key = conversation_key - self.update = update - self.dispatcher = dispatcher - self.callback_context = callback_context - - -class ConversationHandler(Handler[Update, CCT]): - """ - A handler to hold a conversation with a single or multiple users through Telegram updates by - managing four collections of other handlers. - - Note: - ``ConversationHandler`` will only accept updates that are (subclass-)instances of - :class:`telegram.Update`. This is, because depending on the :attr:`per_user` and - :attr:`per_chat` ``ConversationHandler`` relies on - :attr:`telegram.Update.effective_user` and/or :attr:`telegram.Update.effective_chat` in - order to determine which conversation an update should belong to. For ``per_message=True``, - ``ConversationHandler`` uses ``update.callback_query.message.message_id`` when - ``per_chat=True`` and ``update.callback_query.inline_message_id`` when ``per_chat=False``. - For a more detailed explanation, please see our `FAQ`_. - - Finally, ``ConversationHandler``, does *not* handle (edited) channel posts. - - .. _`FAQ`: https://git.io/JtcyU - - The first collection, a ``list`` named :attr:`entry_points`, is used to initiate the - conversation, for example with a :class:`telegram.ext.CommandHandler` or - :class:`telegram.ext.MessageHandler`. - - The second collection, a ``dict`` named :attr:`states`, contains the different conversation - steps and one or more associated handlers that should be used if the user sends a message when - the conversation with them is currently in that state. Here you can also define a state for - :attr:`TIMEOUT` to define the behavior when :attr:`conversation_timeout` is exceeded, and a - state for :attr:`WAITING` to define behavior when a new update is received while the previous - ``@run_async`` decorated handler is not finished. - - The third collection, a ``list`` named :attr:`fallbacks`, is used if the user is currently in a - conversation but the state has either no associated handler or the handler that is associated - to the state is inappropriate for the update, for example if the update contains a command, but - a regular text message is expected. You could use this for a ``/cancel`` command or to let the - user know their message was not recognized. - - To change the state of conversation, the callback function of a handler must return the new - state after responding to the user. If it does not return anything (returning :obj:`None` by - default), the state will not change. If an entry point callback function returns :obj:`None`, - the conversation ends immediately after the execution of this callback function. - To end the conversation, the callback function must return :attr:`END` or ``-1``. To - handle the conversation timeout, use handler :attr:`TIMEOUT` or ``-2``. - Finally, :class:`telegram.ext.DispatcherHandlerStop` can be used in conversations as described - in the corresponding documentation. - - Note: - In each of the described collections of handlers, a handler may in turn be a - :class:`ConversationHandler`. In that case, the nested :class:`ConversationHandler` should - have the attribute :attr:`map_to_parent` which allows to return to the parent conversation - at specified states within the nested conversation. - - Note that the keys in :attr:`map_to_parent` must not appear as keys in :attr:`states` - attribute or else the latter will be ignored. You may map :attr:`END` to one of the parents - states to continue the parent conversation after this has ended or even map a state to - :attr:`END` to end the *parent* conversation from within the nested one. For an example on - nested :class:`ConversationHandler` s, see our `examples`_. - - .. _`examples`: https://github.com/python-telegram-bot/python-telegram-bot/blob/master/examples - - Args: - entry_points (List[:class:`telegram.ext.Handler`]): A list of ``Handler`` objects that can - trigger the start of the conversation. The first handler which :attr:`check_update` - method returns :obj:`True` will be used. If all return :obj:`False`, the update is not - handled. - states (Dict[:obj:`object`, List[:class:`telegram.ext.Handler`]]): A :obj:`dict` that - defines the different states of conversation a user can be in and one or more - associated ``Handler`` objects that should be used in that state. The first handler - which :attr:`check_update` method returns :obj:`True` will be used. - fallbacks (List[:class:`telegram.ext.Handler`]): A list of handlers that might be used if - the user is in a conversation, but every handler for their current state returned - :obj:`False` on :attr:`check_update`. The first handler which :attr:`check_update` - method returns :obj:`True` will be used. If all return :obj:`False`, the update is not - handled. - allow_reentry (:obj:`bool`, optional): If set to :obj:`True`, a user that is currently in a - conversation can restart the conversation by triggering one of the entry points. - per_chat (:obj:`bool`, optional): If the conversationkey should contain the Chat's ID. - Default is :obj:`True`. - per_user (:obj:`bool`, optional): If the conversationkey should contain the User's ID. - Default is :obj:`True`. - per_message (:obj:`bool`, optional): If the conversationkey should contain the Message's - ID. Default is :obj:`False`. - conversation_timeout (:obj:`float` | :obj:`datetime.timedelta`, optional): When this - handler is inactive more than this timeout (in seconds), it will be automatically - ended. If this value is 0 or :obj:`None` (default), there will be no timeout. The last - received update and the corresponding ``context`` will be handled by ALL the handler's - who's :attr:`check_update` method returns :obj:`True` that are in the state - :attr:`ConversationHandler.TIMEOUT`. - - Note: - Using `conversation_timeout` with nested conversations is currently not - supported. You can still try to use it, but it will likely behave differently - from what you expect. - - - name (:obj:`str`, optional): The name for this conversationhandler. Required for - persistence. - persistent (:obj:`bool`, optional): If the conversations dict for this handler should be - saved. Name is required and persistence has to be set in :class:`telegram.ext.Updater` - map_to_parent (Dict[:obj:`object`, :obj:`object`], optional): A :obj:`dict` that can be - used to instruct a nested conversationhandler to transition into a mapped state on - its parent conversationhandler in place of a specified nested state. - run_async (:obj:`bool`, optional): Pass :obj:`True` to *override* the - :attr:`Handler.run_async` setting of all handlers (in :attr:`entry_points`, - :attr:`states` and :attr:`fallbacks`). - - Note: - If set to :obj:`True`, you should not pass a handler instance, that needs to be - run synchronously in another context. - - .. versionadded:: 13.2 - - Raises: - ValueError - - Attributes: - persistent (:obj:`bool`): Optional. If the conversations dict for this handler should be - saved. Name is required and persistence has to be set in :class:`telegram.ext.Updater` - run_async (:obj:`bool`): If :obj:`True`, will override the - :attr:`Handler.run_async` setting of all internal handlers on initialization. - - .. versionadded:: 13.2 - - """ - - __slots__ = ( - '_entry_points', - '_states', - '_fallbacks', - '_allow_reentry', - '_per_user', - '_per_chat', - '_per_message', - '_conversation_timeout', - '_name', - 'persistent', - '_persistence', - '_map_to_parent', - 'timeout_jobs', - '_timeout_jobs_lock', - '_conversations', - '_conversations_lock', - 'logger', - ) - - END: ClassVar[int] = -1 - """:obj:`int`: Used as a constant to return when a conversation is ended.""" - TIMEOUT: ClassVar[int] = -2 - """:obj:`int`: Used as a constant to handle state when a conversation is timed out.""" - WAITING: ClassVar[int] = -3 - """:obj:`int`: Used as a constant to handle state when a conversation is still waiting on the - previous ``@run_sync`` decorated running handler to finish.""" - # pylint: disable=W0231 - def __init__( - self, - entry_points: List[Handler[Update, CCT]], - states: Dict[object, List[Handler[Update, CCT]]], - fallbacks: List[Handler[Update, CCT]], - allow_reentry: bool = False, - per_chat: bool = True, - per_user: bool = True, - per_message: bool = False, - conversation_timeout: Union[float, datetime.timedelta] = None, - name: str = None, - persistent: bool = False, - map_to_parent: Dict[object, object] = None, - run_async: bool = False, - ): - self.run_async = run_async - - self._entry_points = entry_points - self._states = states - self._fallbacks = fallbacks - - self._allow_reentry = allow_reentry - self._per_user = per_user - self._per_chat = per_chat - self._per_message = per_message - self._conversation_timeout = conversation_timeout - self._name = name - if persistent and not self.name: - raise ValueError("Conversations can't be persistent when handler is unnamed.") - self.persistent: bool = persistent - self._persistence: Optional[BasePersistence] = None - """:obj:`telegram.ext.BasePersistence`: The persistence used to store conversations. - Set by dispatcher""" - self._map_to_parent = map_to_parent - - self.timeout_jobs: Dict[Tuple[int, ...], 'Job'] = {} - self._timeout_jobs_lock = Lock() - self._conversations: ConversationDict = {} - self._conversations_lock = Lock() - - self.logger = logging.getLogger(__name__) - - if not any((self.per_user, self.per_chat, self.per_message)): - raise ValueError("'per_user', 'per_chat' and 'per_message' can't all be 'False'") - - if self.per_message and not self.per_chat: - warnings.warn( - "If 'per_message=True' is used, 'per_chat=True' should also be used, " - "since message IDs are not globally unique." - ) - - all_handlers: List[Handler] = [] - all_handlers.extend(entry_points) - all_handlers.extend(fallbacks) - - for state_handlers in states.values(): - all_handlers.extend(state_handlers) - - if self.per_message: - for handler in all_handlers: - if not isinstance(handler, CallbackQueryHandler): - warnings.warn( - "If 'per_message=True', all entry points and state handlers" - " must be 'CallbackQueryHandler', since no other handlers " - "have a message context." - ) - break - else: - for handler in all_handlers: - if isinstance(handler, CallbackQueryHandler): - warnings.warn( - "If 'per_message=False', 'CallbackQueryHandler' will not be " - "tracked for every message." - ) - break - - if self.per_chat: - for handler in all_handlers: - if isinstance(handler, (InlineQueryHandler, ChosenInlineResultHandler)): - warnings.warn( - "If 'per_chat=True', 'InlineQueryHandler' can not be used, " - "since inline queries have no chat context." - ) - break - - if self.conversation_timeout: - for handler in all_handlers: - if isinstance(handler, self.__class__): - warnings.warn( - "Using `conversation_timeout` with nested conversations is currently not " - "supported. You can still try to use it, but it will likely behave " - "differently from what you expect." - ) - break - - if self.run_async: - for handler in all_handlers: - handler.run_async = True - - @property - def entry_points(self) -> List[Handler]: - """List[:class:`telegram.ext.Handler`]: A list of ``Handler`` objects that can trigger the - start of the conversation. - """ - return self._entry_points - - @entry_points.setter - def entry_points(self, value: object) -> NoReturn: - raise ValueError('You can not assign a new value to entry_points after initialization.') - - @property - def states(self) -> Dict[object, List[Handler]]: - """Dict[:obj:`object`, List[:class:`telegram.ext.Handler`]]: A :obj:`dict` that - defines the different states of conversation a user can be in and one or more - associated ``Handler`` objects that should be used in that state. - """ - return self._states - - @states.setter - def states(self, value: object) -> NoReturn: - raise ValueError('You can not assign a new value to states after initialization.') - - @property - def fallbacks(self) -> List[Handler]: - """List[:class:`telegram.ext.Handler`]: A list of handlers that might be used if - the user is in a conversation, but every handler for their current state returned - :obj:`False` on :attr:`check_update`. - """ - return self._fallbacks - - @fallbacks.setter - def fallbacks(self, value: object) -> NoReturn: - raise ValueError('You can not assign a new value to fallbacks after initialization.') - - @property - def allow_reentry(self) -> bool: - return self._allow_reentry - - @allow_reentry.setter - def allow_reentry(self, value: object) -> NoReturn: - """:obj:`bool`: Determines if a user can restart a conversation with an entry point.""" - raise ValueError('You can not assign a new value to allow_reentry after initialization.') - - @property - def per_user(self) -> bool: - """:obj:`bool`: If the conversation key should contain the User's ID.""" - return self._per_user - - @per_user.setter - def per_user(self, value: object) -> NoReturn: - raise ValueError('You can not assign a new value to per_user after initialization.') - - @property - def per_chat(self) -> bool: - """:obj:`bool`: If the conversation key should contain the Chat's ID.""" - return self._per_chat - - @per_chat.setter - def per_chat(self, value: object) -> NoReturn: - raise ValueError('You can not assign a new value to per_chat after initialization.') - - @property - def per_message(self) -> bool: - """:obj:`bool`: If the conversation key should contain the message's ID.""" - return self._per_message - - @per_message.setter - def per_message(self, value: object) -> NoReturn: - raise ValueError('You can not assign a new value to per_message after initialization.') - - @property - def conversation_timeout( - self, - ) -> Optional[Union[float, datetime.timedelta]]: - """:obj:`float` | :obj:`datetime.timedelta`: Optional. When this - handler is inactive more than this timeout (in seconds), it will be automatically - ended. - """ - return self._conversation_timeout - - @conversation_timeout.setter - def conversation_timeout(self, value: object) -> NoReturn: - raise ValueError( - 'You can not assign a new value to conversation_timeout after initialization.' - ) - - @property - def name(self) -> Optional[str]: - """:obj:`str`: Optional. The name for this :class:`ConversationHandler`.""" - return self._name - - @name.setter - def name(self, value: object) -> NoReturn: - raise ValueError('You can not assign a new value to name after initialization.') - - @property - def map_to_parent(self) -> Optional[Dict[object, object]]: - """Dict[:obj:`object`, :obj:`object`]: Optional. A :obj:`dict` that can be - used to instruct a nested :class:`ConversationHandler` to transition into a mapped state on - its parent :class:`ConversationHandler` in place of a specified nested state. - """ - return self._map_to_parent - - @map_to_parent.setter - def map_to_parent(self, value: object) -> NoReturn: - raise ValueError('You can not assign a new value to map_to_parent after initialization.') - - @property - def persistence(self) -> Optional[BasePersistence]: - """The persistence class as provided by the :class:`Dispatcher`.""" - return self._persistence - - @persistence.setter - def persistence(self, persistence: BasePersistence) -> None: - self._persistence = persistence - # Set persistence for nested conversations - for handlers in self.states.values(): - for handler in handlers: - if isinstance(handler, ConversationHandler): - handler.persistence = self.persistence - - @property - def conversations(self) -> ConversationDict: # skipcq: PY-D0003 - return self._conversations - - @conversations.setter - def conversations(self, value: ConversationDict) -> None: - self._conversations = value - # Set conversations for nested conversations - for handlers in self.states.values(): - for handler in handlers: - if isinstance(handler, ConversationHandler) and self.persistence and handler.name: - handler.conversations = self.persistence.get_conversations(handler.name) - - def _get_key(self, update: Update) -> Tuple[int, ...]: - chat = update.effective_chat - user = update.effective_user - - key = [] - - if self.per_chat: - key.append(chat.id) # type: ignore[union-attr] - - if self.per_user and user is not None: - key.append(user.id) - - if self.per_message: - key.append( - update.callback_query.inline_message_id # type: ignore[union-attr] - or update.callback_query.message.message_id # type: ignore[union-attr] - ) - - return tuple(key) - - def _resolve_promise(self, state: Tuple) -> object: - old_state, new_state = state - try: - res = new_state.result(0) - res = res if res is not None else old_state - except Exception as exc: - self.logger.exception("Promise function raised exception") - self.logger.exception("%s", exc) - res = old_state - finally: - if res is None and old_state is None: - res = self.END - return res - - def _schedule_job( - self, - new_state: object, - dispatcher: 'Dispatcher', - update: Update, - context: Optional[CallbackContext], - conversation_key: Tuple[int, ...], - ) -> None: - if new_state != self.END: - try: - # both job_queue & conversation_timeout are checked before calling _schedule_job - j_queue = dispatcher.job_queue - self.timeout_jobs[conversation_key] = j_queue.run_once( # type: ignore[union-attr] - self._trigger_timeout, - self.conversation_timeout, # type: ignore[arg-type] - context=_ConversationTimeoutContext( - conversation_key, update, dispatcher, context - ), - ) - except Exception as exc: - self.logger.exception( - "Failed to schedule timeout job due to the following exception:" - ) - self.logger.exception("%s", exc) - - def check_update(self, update: object) -> CheckUpdateType: # pylint: disable=R0911 - """ - Determines whether an update should be handled by this conversationhandler, and if so in - which state the conversation currently is. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - if not isinstance(update, Update): - return None - # Ignore messages in channels - if update.channel_post or update.edited_channel_post: - return None - if self.per_chat and not update.effective_chat: - return None - if self.per_message and not update.callback_query: - return None - if update.callback_query and self.per_chat and not update.callback_query.message: - return None - - key = self._get_key(update) - with self._conversations_lock: - state = self.conversations.get(key) - - # Resolve promises - if isinstance(state, tuple) and len(state) == 2 and isinstance(state[1], Promise): - self.logger.debug('waiting for promise...') - - # check if promise is finished or not - if state[1].done.wait(0): - res = self._resolve_promise(state) - self._update_state(res, key) - with self._conversations_lock: - state = self.conversations.get(key) - - # if not then handle WAITING state instead - else: - hdlrs = self.states.get(self.WAITING, []) - for hdlr in hdlrs: - check = hdlr.check_update(update) - if check is not None and check is not False: - return key, hdlr, check - return None - - self.logger.debug('selecting conversation %s with state %s', str(key), str(state)) - - handler = None - - # Search entry points for a match - if state is None or self.allow_reentry: - for entry_point in self.entry_points: - check = entry_point.check_update(update) - if check is not None and check is not False: - handler = entry_point - break - - else: - if state is None: - return None - - # Get the handler list for current state, if we didn't find one yet and we're still here - if state is not None and not handler: - handlers = self.states.get(state) - - for candidate in handlers or []: - check = candidate.check_update(update) - if check is not None and check is not False: - handler = candidate - break - - # Find a fallback handler if all other handlers fail - else: - for fallback in self.fallbacks: - check = fallback.check_update(update) - if check is not None and check is not False: - handler = fallback - break - - else: - return None - - return key, handler, check # type: ignore[return-value] - - def handle_update( # type: ignore[override] - self, - update: Update, - dispatcher: 'Dispatcher', - check_result: CheckUpdateType, - context: CallbackContext = None, - ) -> Optional[object]: - """Send the update to the callback for the current state and Handler - - Args: - check_result: The result from check_update. For this handler it's a tuple of key, - handler, and the handler's check result. - update (:class:`telegram.Update`): Incoming telegram update. - dispatcher (:class:`telegram.ext.Dispatcher`): Dispatcher that originated the Update. - context (:class:`telegram.ext.CallbackContext`, optional): The context as provided by - the dispatcher. - - """ - update = cast(Update, update) # for mypy - conversation_key, handler, check_result = check_result # type: ignore[assignment,misc] - raise_dp_handler_stop = False - - with self._timeout_jobs_lock: - # Remove the old timeout job (if present) - timeout_job = self.timeout_jobs.pop(conversation_key, None) - - if timeout_job is not None: - timeout_job.schedule_removal() - try: - new_state = handler.handle_update(update, dispatcher, check_result, context) - except DispatcherHandlerStop as exception: - new_state = exception.state - raise_dp_handler_stop = True - with self._timeout_jobs_lock: - if self.conversation_timeout: - if dispatcher.job_queue is not None: - # Add the new timeout job - if isinstance(new_state, Promise): - new_state.add_done_callback( - functools.partial( - self._schedule_job, - dispatcher=dispatcher, - update=update, - context=context, - conversation_key=conversation_key, - ) - ) - elif new_state != self.END: - self._schedule_job( - new_state, dispatcher, update, context, conversation_key - ) - else: - self.logger.warning( - "Ignoring `conversation_timeout` because the Dispatcher has no JobQueue." - ) - - if isinstance(self.map_to_parent, dict) and new_state in self.map_to_parent: - self._update_state(self.END, conversation_key) - if raise_dp_handler_stop: - raise DispatcherHandlerStop(self.map_to_parent.get(new_state)) - return self.map_to_parent.get(new_state) - - self._update_state(new_state, conversation_key) - if raise_dp_handler_stop: - # Don't pass the new state here. If we're in a nested conversation, the parent is - # expecting None as return value. - raise DispatcherHandlerStop() - return None - - def _update_state(self, new_state: object, key: Tuple[int, ...]) -> None: - if new_state == self.END: - with self._conversations_lock: - if key in self.conversations: - # If there is no key in conversations, nothing is done. - del self.conversations[key] - if self.persistent and self.persistence and self.name: - self.persistence.update_conversation(self.name, key, None) - - elif isinstance(new_state, Promise): - with self._conversations_lock: - self.conversations[key] = (self.conversations.get(key), new_state) - if self.persistent and self.persistence and self.name: - self.persistence.update_conversation( - self.name, key, (self.conversations.get(key), new_state) - ) - - elif new_state is not None: - if new_state not in self.states: - warnings.warn( - f"Handler returned state {new_state} which is unknown to the " - f"ConversationHandler{' ' + self.name if self.name is not None else ''}." - ) - with self._conversations_lock: - self.conversations[key] = new_state - if self.persistent and self.persistence and self.name: - self.persistence.update_conversation(self.name, key, new_state) - - def _trigger_timeout(self, context: CallbackContext, job: 'Job' = None) -> None: - self.logger.debug('conversation timeout was triggered!') - - # Backward compatibility with bots that do not use CallbackContext - if isinstance(context, CallbackContext): - job = context.job - ctxt = cast(_ConversationTimeoutContext, job.context) # type: ignore[union-attr] - else: - ctxt = cast(_ConversationTimeoutContext, job.context) - - callback_context = ctxt.callback_context - - with self._timeout_jobs_lock: - found_job = self.timeout_jobs[ctxt.conversation_key] - if found_job is not job: - # The timeout has been cancelled in handle_update - return - del self.timeout_jobs[ctxt.conversation_key] - - handlers = self.states.get(self.TIMEOUT, []) - for handler in handlers: - check = handler.check_update(ctxt.update) - if check is not None and check is not False: - try: - handler.handle_update(ctxt.update, ctxt.dispatcher, check, callback_context) - except DispatcherHandlerStop: - self.logger.warning( - 'DispatcherHandlerStop in TIMEOUT state of ' - 'ConversationHandler has no effect. Ignoring.' - ) - - self._update_state(self.END, ctxt.conversation_key) diff --git a/venv/lib/python3.8/site-packages/telegram/ext/defaults.py b/venv/lib/python3.8/site-packages/telegram/ext/defaults.py deleted file mode 100644 index 8546f71..0000000 --- a/venv/lib/python3.8/site-packages/telegram/ext/defaults.py +++ /dev/null @@ -1,267 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2020-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -# pylint: disable=R0201 -"""This module contains the class Defaults, which allows to pass default values to Updater.""" -from typing import NoReturn, Optional, Dict, Any - -import pytz - -from telegram.utils.deprecate import set_new_attribute_deprecated -from telegram.utils.helpers import DEFAULT_NONE -from telegram.utils.types import ODVInput - - -class Defaults: - """Convenience Class to gather all parameters with a (user defined) default value - - Parameters: - parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show - bold, italic, fixed-width text or URLs in your bot's message. - disable_notification (:obj:`bool`, optional): Sends the message silently. Users will - receive a notification with no sound. - disable_web_page_preview (:obj:`bool`, optional): Disables link previews for links in this - message. - allow_sending_without_reply (:obj:`bool`, optional): Pass :obj:`True`, if the message - should be sent even if the specified replied-to message is not found. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as the - read timeout from the server (instead of the one specified during creation of the - connection pool). - - Note: - Will *not* be used for :meth:`telegram.Bot.get_updates`! - quote (:obj:`bool`, optional): If set to :obj:`True`, the reply is sent as an actual reply - to the message. If ``reply_to_message_id`` is passed in ``kwargs``, this parameter will - be ignored. Default: :obj:`True` in group chats and :obj:`False` in private chats. - tzinfo (:obj:`tzinfo`, optional): A timezone to be used for all date(time) inputs - appearing throughout PTB, i.e. if a timezone naive date(time) object is passed - somewhere, it will be assumed to be in ``tzinfo``. Must be a timezone provided by the - ``pytz`` module. Defaults to UTC. - run_async (:obj:`bool`, optional): Default setting for the ``run_async`` parameter of - handlers and error handlers registered through :meth:`Dispatcher.add_handler` and - :meth:`Dispatcher.add_error_handler`. Defaults to :obj:`False`. - """ - - __slots__ = ( - '_timeout', - '_tzinfo', - '_disable_web_page_preview', - '_run_async', - '_quote', - '_disable_notification', - '_allow_sending_without_reply', - '_parse_mode', - '_api_defaults', - '__dict__', - ) - - def __init__( - self, - parse_mode: str = None, - disable_notification: bool = None, - disable_web_page_preview: bool = None, - # Timeout needs special treatment, since the bot methods have two different - # default values for timeout (None and 20s) - timeout: ODVInput[float] = DEFAULT_NONE, - quote: bool = None, - tzinfo: pytz.BaseTzInfo = pytz.utc, - run_async: bool = False, - allow_sending_without_reply: bool = None, - ): - self._parse_mode = parse_mode - self._disable_notification = disable_notification - self._disable_web_page_preview = disable_web_page_preview - self._allow_sending_without_reply = allow_sending_without_reply - self._timeout = timeout - self._quote = quote - self._tzinfo = tzinfo - self._run_async = run_async - - # Gather all defaults that actually have a default value - self._api_defaults = {} - for kwarg in ( - 'parse_mode', - 'explanation_parse_mode', - 'disable_notification', - 'disable_web_page_preview', - 'allow_sending_without_reply', - ): - value = getattr(self, kwarg) - if value not in [None, DEFAULT_NONE]: - self._api_defaults[kwarg] = value - # Special casing, as None is a valid default value - if self._timeout != DEFAULT_NONE: - self._api_defaults['timeout'] = self._timeout - - def __setattr__(self, key: str, value: object) -> None: - set_new_attribute_deprecated(self, key, value) - - @property - def api_defaults(self) -> Dict[str, Any]: # skip-cq: PY-D0003 - return self._api_defaults - - @property - def parse_mode(self) -> Optional[str]: - """:obj:`str`: Optional. Send Markdown or HTML, if you want Telegram apps to show - bold, italic, fixed-width text or URLs in your bot's message. - """ - return self._parse_mode - - @parse_mode.setter - def parse_mode(self, value: object) -> NoReturn: - raise AttributeError( - "You can not assign a new value to defaults after because it would " - "not have any effect." - ) - - @property - def explanation_parse_mode(self) -> Optional[str]: - """:obj:`str`: Optional. Alias for :attr:`parse_mode`, used for - the corresponding parameter of :meth:`telegram.Bot.send_poll`. - """ - return self._parse_mode - - @explanation_parse_mode.setter - def explanation_parse_mode(self, value: object) -> NoReturn: - raise AttributeError( - "You can not assign a new value to defaults after because it would " - "not have any effect." - ) - - @property - def disable_notification(self) -> Optional[bool]: - """:obj:`bool`: Optional. Sends the message silently. Users will - receive a notification with no sound. - """ - return self._disable_notification - - @disable_notification.setter - def disable_notification(self, value: object) -> NoReturn: - raise AttributeError( - "You can not assign a new value to defaults after because it would " - "not have any effect." - ) - - @property - def disable_web_page_preview(self) -> Optional[bool]: - """:obj:`bool`: Optional. Disables link previews for links in this - message. - """ - return self._disable_web_page_preview - - @disable_web_page_preview.setter - def disable_web_page_preview(self, value: object) -> NoReturn: - raise AttributeError( - "You can not assign a new value to defaults after because it would " - "not have any effect." - ) - - @property - def allow_sending_without_reply(self) -> Optional[bool]: - """:obj:`bool`: Optional. Pass :obj:`True`, if the message - should be sent even if the specified replied-to message is not found. - """ - return self._allow_sending_without_reply - - @allow_sending_without_reply.setter - def allow_sending_without_reply(self, value: object) -> NoReturn: - raise AttributeError( - "You can not assign a new value to defaults after because it would " - "not have any effect." - ) - - @property - def timeout(self) -> ODVInput[float]: - """:obj:`int` | :obj:`float`: Optional. If this value is specified, use it as the - read timeout from the server (instead of the one specified during creation of the - connection pool). - """ - return self._timeout - - @timeout.setter - def timeout(self, value: object) -> NoReturn: - raise AttributeError( - "You can not assign a new value to defaults after because it would " - "not have any effect." - ) - - @property - def quote(self) -> Optional[bool]: - """:obj:`bool`: Optional. If set to :obj:`True`, the reply is sent as an actual reply - to the message. If ``reply_to_message_id`` is passed in ``kwargs``, this parameter will - be ignored. Default: :obj:`True` in group chats and :obj:`False` in private chats. - """ - return self._quote - - @quote.setter - def quote(self, value: object) -> NoReturn: - raise AttributeError( - "You can not assign a new value to defaults after because it would " - "not have any effect." - ) - - @property - def tzinfo(self) -> pytz.BaseTzInfo: - """:obj:`tzinfo`: A timezone to be used for all date(time) objects appearing - throughout PTB. - """ - return self._tzinfo - - @tzinfo.setter - def tzinfo(self, value: object) -> NoReturn: - raise AttributeError( - "You can not assign a new value to defaults after because it would " - "not have any effect." - ) - - @property - def run_async(self) -> bool: - """:obj:`bool`: Optional. Default setting for the ``run_async`` parameter of - handlers and error handlers registered through :meth:`Dispatcher.add_handler` and - :meth:`Dispatcher.add_error_handler`. - """ - return self._run_async - - @run_async.setter - def run_async(self, value: object) -> NoReturn: - raise AttributeError( - "You can not assign a new value to defaults after because it would " - "not have any effect." - ) - - def __hash__(self) -> int: - return hash( - ( - self._parse_mode, - self._disable_notification, - self._disable_web_page_preview, - self._allow_sending_without_reply, - self._timeout, - self._quote, - self._tzinfo, - self._run_async, - ) - ) - - def __eq__(self, other: object) -> bool: - if isinstance(other, Defaults): - return all(getattr(self, attr) == getattr(other, attr) for attr in self.__slots__) - return False - - def __ne__(self, other: object) -> bool: - return not self == other diff --git a/venv/lib/python3.8/site-packages/telegram/ext/dictpersistence.py b/venv/lib/python3.8/site-packages/telegram/ext/dictpersistence.py deleted file mode 100644 index 044fc65..0000000 --- a/venv/lib/python3.8/site-packages/telegram/ext/dictpersistence.py +++ /dev/null @@ -1,404 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the DictPersistence class.""" - -from typing import DefaultDict, Dict, Optional, Tuple, cast -from collections import defaultdict - -from telegram.utils.helpers import ( - decode_conversations_from_json, - decode_user_chat_data_from_json, - encode_conversations_to_json, -) -from telegram.ext import BasePersistence -from telegram.ext.utils.types import ConversationDict, CDCData - -try: - import ujson as json -except ImportError: - import json # type: ignore[no-redef] - - -class DictPersistence(BasePersistence): - """Using Python's :obj:`dict` and ``json`` for making your bot persistent. - - Note: - This class does *not* implement a :meth:`flush` method, meaning that data managed by - ``DictPersistence`` is in-memory only and will be lost when the bot shuts down. This is, - because ``DictPersistence`` is mainly intended as starting point for custom persistence - classes that need to JSON-serialize the stored data before writing them to file/database. - - Warning: - :class:`DictPersistence` will try to replace :class:`telegram.Bot` instances by - :attr:`REPLACED_BOT` and insert the bot set with - :meth:`telegram.ext.BasePersistence.set_bot` upon loading of the data. This is to ensure - that changes to the bot apply to the saved objects, too. If you change the bots token, this - may lead to e.g. ``Chat not found`` errors. For the limitations on replacing bots see - :meth:`telegram.ext.BasePersistence.replace_bot` and - :meth:`telegram.ext.BasePersistence.insert_bot`. - - Args: - store_user_data (:obj:`bool`, optional): Whether user_data should be saved by this - persistence class. Default is :obj:`True`. - store_chat_data (:obj:`bool`, optional): Whether chat_data should be saved by this - persistence class. Default is :obj:`True`. - store_bot_data (:obj:`bool`, optional): Whether bot_data should be saved by this - persistence class. Default is :obj:`True`. - store_callback_data (:obj:`bool`, optional): Whether callback_data should be saved by this - persistence class. Default is :obj:`False`. - - .. versionadded:: 13.6 - user_data_json (:obj:`str`, optional): JSON string that will be used to reconstruct - user_data on creating this persistence. Default is ``""``. - chat_data_json (:obj:`str`, optional): JSON string that will be used to reconstruct - chat_data on creating this persistence. Default is ``""``. - bot_data_json (:obj:`str`, optional): JSON string that will be used to reconstruct - bot_data on creating this persistence. Default is ``""``. - callback_data_json (:obj:`str`, optional): Json string that will be used to reconstruct - callback_data on creating this persistence. Default is ``""``. - - .. versionadded:: 13.6 - conversations_json (:obj:`str`, optional): JSON string that will be used to reconstruct - conversation on creating this persistence. Default is ``""``. - - Attributes: - store_user_data (:obj:`bool`): Whether user_data should be saved by this - persistence class. - store_chat_data (:obj:`bool`): Whether chat_data should be saved by this - persistence class. - store_bot_data (:obj:`bool`): Whether bot_data should be saved by this - persistence class. - store_callback_data (:obj:`bool`): Whether callback_data be saved by this - persistence class. - - .. versionadded:: 13.6 - """ - - __slots__ = ( - '_user_data', - '_chat_data', - '_bot_data', - '_callback_data', - '_conversations', - '_user_data_json', - '_chat_data_json', - '_bot_data_json', - '_callback_data_json', - '_conversations_json', - ) - - def __init__( - self, - store_user_data: bool = True, - store_chat_data: bool = True, - store_bot_data: bool = True, - user_data_json: str = '', - chat_data_json: str = '', - bot_data_json: str = '', - conversations_json: str = '', - store_callback_data: bool = False, - callback_data_json: str = '', - ): - super().__init__( - store_user_data=store_user_data, - store_chat_data=store_chat_data, - store_bot_data=store_bot_data, - store_callback_data=store_callback_data, - ) - self._user_data = None - self._chat_data = None - self._bot_data = None - self._callback_data = None - self._conversations = None - self._user_data_json = None - self._chat_data_json = None - self._bot_data_json = None - self._callback_data_json = None - self._conversations_json = None - if user_data_json: - try: - self._user_data = decode_user_chat_data_from_json(user_data_json) - self._user_data_json = user_data_json - except (ValueError, AttributeError) as exc: - raise TypeError("Unable to deserialize user_data_json. Not valid JSON") from exc - if chat_data_json: - try: - self._chat_data = decode_user_chat_data_from_json(chat_data_json) - self._chat_data_json = chat_data_json - except (ValueError, AttributeError) as exc: - raise TypeError("Unable to deserialize chat_data_json. Not valid JSON") from exc - if bot_data_json: - try: - self._bot_data = json.loads(bot_data_json) - self._bot_data_json = bot_data_json - except (ValueError, AttributeError) as exc: - raise TypeError("Unable to deserialize bot_data_json. Not valid JSON") from exc - if not isinstance(self._bot_data, dict): - raise TypeError("bot_data_json must be serialized dict") - if callback_data_json: - try: - data = json.loads(callback_data_json) - except (ValueError, AttributeError) as exc: - raise TypeError( - "Unable to deserialize callback_data_json. Not valid JSON" - ) from exc - # We are a bit more thorough with the checking of the format here, because it's - # more complicated than for the other things - try: - if data is None: - self._callback_data = None - else: - self._callback_data = cast( - CDCData, - ([(one, float(two), three) for one, two, three in data[0]], data[1]), - ) - self._callback_data_json = callback_data_json - except (ValueError, IndexError) as exc: - raise TypeError("callback_data_json is not in the required format") from exc - if self._callback_data is not None and ( - not all( - isinstance(entry[2], dict) and isinstance(entry[0], str) - for entry in self._callback_data[0] - ) - or not isinstance(self._callback_data[1], dict) - ): - raise TypeError("callback_data_json is not in the required format") - - if conversations_json: - try: - self._conversations = decode_conversations_from_json(conversations_json) - self._conversations_json = conversations_json - except (ValueError, AttributeError) as exc: - raise TypeError( - "Unable to deserialize conversations_json. Not valid JSON" - ) from exc - - @property - def user_data(self) -> Optional[DefaultDict[int, Dict]]: - """:obj:`dict`: The user_data as a dict.""" - return self._user_data - - @property - def user_data_json(self) -> str: - """:obj:`str`: The user_data serialized as a JSON-string.""" - if self._user_data_json: - return self._user_data_json - return json.dumps(self.user_data) - - @property - def chat_data(self) -> Optional[DefaultDict[int, Dict]]: - """:obj:`dict`: The chat_data as a dict.""" - return self._chat_data - - @property - def chat_data_json(self) -> str: - """:obj:`str`: The chat_data serialized as a JSON-string.""" - if self._chat_data_json: - return self._chat_data_json - return json.dumps(self.chat_data) - - @property - def bot_data(self) -> Optional[Dict]: - """:obj:`dict`: The bot_data as a dict.""" - return self._bot_data - - @property - def bot_data_json(self) -> str: - """:obj:`str`: The bot_data serialized as a JSON-string.""" - if self._bot_data_json: - return self._bot_data_json - return json.dumps(self.bot_data) - - @property - def callback_data(self) -> Optional[CDCData]: - """:class:`telegram.ext.utils.types.CDCData`: The meta data on the stored callback data. - - .. versionadded:: 13.6 - """ - return self._callback_data - - @property - def callback_data_json(self) -> str: - """:obj:`str`: The meta data on the stored callback data as a JSON-string. - - .. versionadded:: 13.6 - """ - if self._callback_data_json: - return self._callback_data_json - return json.dumps(self.callback_data) - - @property - def conversations(self) -> Optional[Dict[str, ConversationDict]]: - """:obj:`dict`: The conversations as a dict.""" - return self._conversations - - @property - def conversations_json(self) -> str: - """:obj:`str`: The conversations serialized as a JSON-string.""" - if self._conversations_json: - return self._conversations_json - return encode_conversations_to_json(self.conversations) # type: ignore[arg-type] - - def get_user_data(self) -> DefaultDict[int, Dict[object, object]]: - """Returns the user_data created from the ``user_data_json`` or an empty - :obj:`defaultdict`. - - Returns: - :obj:`defaultdict`: The restored user data. - """ - if self.user_data is None: - self._user_data = defaultdict(dict) - return self.user_data # type: ignore[return-value] - - def get_chat_data(self) -> DefaultDict[int, Dict[object, object]]: - """Returns the chat_data created from the ``chat_data_json`` or an empty - :obj:`defaultdict`. - - Returns: - :obj:`defaultdict`: The restored chat data. - """ - if self.chat_data is None: - self._chat_data = defaultdict(dict) - return self.chat_data # type: ignore[return-value] - - def get_bot_data(self) -> Dict[object, object]: - """Returns the bot_data created from the ``bot_data_json`` or an empty :obj:`dict`. - - Returns: - :obj:`dict`: The restored bot data. - """ - if self.bot_data is None: - self._bot_data = {} - return self.bot_data # type: ignore[return-value] - - def get_callback_data(self) -> Optional[CDCData]: - """Returns the callback_data created from the ``callback_data_json`` or :obj:`None`. - - .. versionadded:: 13.6 - - Returns: - Optional[:class:`telegram.ext.utils.types.CDCData`]: The restored meta data or - :obj:`None`, if no data was stored. - """ - if self.callback_data is None: - self._callback_data = None - return None - return self.callback_data[0], self.callback_data[1].copy() - - def get_conversations(self, name: str) -> ConversationDict: - """Returns the conversations created from the ``conversations_json`` or an empty - :obj:`dict`. - - Returns: - :obj:`dict`: The restored conversations data. - """ - if self.conversations is None: - self._conversations = {} - return self.conversations.get(name, {}).copy() # type: ignore[union-attr] - - def update_conversation( - self, name: str, key: Tuple[int, ...], new_state: Optional[object] - ) -> None: - """Will update the conversations for the given handler. - - Args: - name (:obj:`str`): The handler's name. - key (:obj:`tuple`): The key the state is changed for. - new_state (:obj:`tuple` | :obj:`any`): The new state for the given key. - """ - if not self._conversations: - self._conversations = {} - if self._conversations.setdefault(name, {}).get(key) == new_state: - return - self._conversations[name][key] = new_state - self._conversations_json = None - - def update_user_data(self, user_id: int, data: Dict) -> None: - """Will update the user_data (if changed). - - Args: - user_id (:obj:`int`): The user the data might have been changed for. - data (:obj:`dict`): The :attr:`telegram.ext.dispatcher.user_data` ``[user_id]``. - """ - if self._user_data is None: - self._user_data = defaultdict(dict) - if self._user_data.get(user_id) == data: - return - self._user_data[user_id] = data - self._user_data_json = None - - def update_chat_data(self, chat_id: int, data: Dict) -> None: - """Will update the chat_data (if changed). - - Args: - chat_id (:obj:`int`): The chat the data might have been changed for. - data (:obj:`dict`): The :attr:`telegram.ext.dispatcher.chat_data` ``[chat_id]``. - """ - if self._chat_data is None: - self._chat_data = defaultdict(dict) - if self._chat_data.get(chat_id) == data: - return - self._chat_data[chat_id] = data - self._chat_data_json = None - - def update_bot_data(self, data: Dict) -> None: - """Will update the bot_data (if changed). - - Args: - data (:obj:`dict`): The :attr:`telegram.ext.dispatcher.bot_data`. - """ - if self._bot_data == data: - return - self._bot_data = data - self._bot_data_json = None - - def update_callback_data(self, data: CDCData) -> None: - """Will update the callback_data (if changed). - - .. versionadded:: 13.6 - - Args: - data (:class:`telegram.ext.utils.types.CDCData`:): The relevant data to restore - :attr:`telegram.ext.dispatcher.bot.callback_data_cache`. - """ - if self._callback_data == data: - return - self._callback_data = (data[0], data[1].copy()) - self._callback_data_json = None - - def refresh_user_data(self, user_id: int, user_data: Dict) -> None: - """Does nothing. - - .. versionadded:: 13.6 - .. seealso:: :meth:`telegram.ext.BasePersistence.refresh_user_data` - """ - - def refresh_chat_data(self, chat_id: int, chat_data: Dict) -> None: - """Does nothing. - - .. versionadded:: 13.6 - .. seealso:: :meth:`telegram.ext.BasePersistence.refresh_chat_data` - """ - - def refresh_bot_data(self, bot_data: Dict) -> None: - """Does nothing. - - .. versionadded:: 13.6 - .. seealso:: :meth:`telegram.ext.BasePersistence.refresh_bot_data` - """ diff --git a/venv/lib/python3.8/site-packages/telegram/ext/dispatcher.py b/venv/lib/python3.8/site-packages/telegram/ext/dispatcher.py deleted file mode 100644 index 3322acf..0000000 --- a/venv/lib/python3.8/site-packages/telegram/ext/dispatcher.py +++ /dev/null @@ -1,820 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the Dispatcher class.""" - -import logging -import warnings -import weakref -from collections import defaultdict -from functools import wraps -from queue import Empty, Queue -from threading import BoundedSemaphore, Event, Lock, Thread, current_thread -from time import sleep -from typing import ( - TYPE_CHECKING, - Callable, - DefaultDict, - Dict, - List, - Optional, - Set, - Union, - Generic, - TypeVar, - overload, - cast, -) -from uuid import uuid4 - -from telegram import TelegramError, Update -from telegram.ext import BasePersistence, ContextTypes -from telegram.ext.callbackcontext import CallbackContext -from telegram.ext.handler import Handler -import telegram.ext.extbot -from telegram.ext.callbackdatacache import CallbackDataCache -from telegram.utils.deprecate import TelegramDeprecationWarning, set_new_attribute_deprecated -from telegram.ext.utils.promise import Promise -from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE -from telegram.ext.utils.types import CCT, UD, CD, BD - -if TYPE_CHECKING: - from telegram import Bot - from telegram.ext import JobQueue - -DEFAULT_GROUP: int = 0 - -UT = TypeVar('UT') - - -def run_async( - func: Callable[[Update, CallbackContext], object] -) -> Callable[[Update, CallbackContext], object]: - """ - Function decorator that will run the function in a new thread. - - Will run :attr:`telegram.ext.Dispatcher.run_async`. - - Using this decorator is only possible when only a single Dispatcher exist in the system. - - Note: - DEPRECATED. Use :attr:`telegram.ext.Dispatcher.run_async` directly instead or the - :attr:`Handler.run_async` parameter. - - Warning: - If you're using ``@run_async`` you cannot rely on adding custom attributes to - :class:`telegram.ext.CallbackContext`. See its docs for more info. - """ - - @wraps(func) - def async_func(*args: object, **kwargs: object) -> object: - warnings.warn( - 'The @run_async decorator is deprecated. Use the `run_async` parameter of ' - 'your Handler or `Dispatcher.run_async` instead.', - TelegramDeprecationWarning, - stacklevel=2, - ) - return Dispatcher.get_instance()._run_async( # pylint: disable=W0212 - func, *args, update=None, error_handling=False, **kwargs - ) - - return async_func - - -class DispatcherHandlerStop(Exception): - """ - Raise this in handler to prevent execution of any other handler (even in different group). - - In order to use this exception in a :class:`telegram.ext.ConversationHandler`, pass the - optional ``state`` parameter instead of returning the next state: - - .. code-block:: python - - def callback(update, context): - ... - raise DispatcherHandlerStop(next_state) - - Attributes: - state (:obj:`object`): Optional. The next state of the conversation. - - Args: - state (:obj:`object`, optional): The next state of the conversation. - """ - - __slots__ = ('state',) - - def __init__(self, state: object = None) -> None: - super().__init__() - self.state = state - - -class Dispatcher(Generic[CCT, UD, CD, BD]): - """This class dispatches all kinds of updates to its registered handlers. - - Args: - bot (:class:`telegram.Bot`): The bot object that should be passed to the handlers. - update_queue (:obj:`Queue`): The synchronized queue that will contain the updates. - job_queue (:class:`telegram.ext.JobQueue`, optional): The :class:`telegram.ext.JobQueue` - instance to pass onto handler callbacks. - workers (:obj:`int`, optional): Number of maximum concurrent worker threads for the - ``@run_async`` decorator and :meth:`run_async`. Defaults to 4. - persistence (:class:`telegram.ext.BasePersistence`, optional): The persistence class to - store data that should be persistent over restarts. - use_context (:obj:`bool`, optional): If set to :obj:`True` uses the context based callback - API (ignored if `dispatcher` argument is used). Defaults to :obj:`True`. - **New users**: set this to :obj:`True`. - context_types (:class:`telegram.ext.ContextTypes`, optional): Pass an instance - of :class:`telegram.ext.ContextTypes` to customize the types used in the - ``context`` interface. If not passed, the defaults documented in - :class:`telegram.ext.ContextTypes` will be used. - - .. versionadded:: 13.6 - - Attributes: - bot (:class:`telegram.Bot`): The bot object that should be passed to the handlers. - update_queue (:obj:`Queue`): The synchronized queue that will contain the updates. - job_queue (:class:`telegram.ext.JobQueue`): Optional. The :class:`telegram.ext.JobQueue` - instance to pass onto handler callbacks. - workers (:obj:`int`, optional): Number of maximum concurrent worker threads for the - ``@run_async`` decorator and :meth:`run_async`. - user_data (:obj:`defaultdict`): A dictionary handlers can use to store data for the user. - chat_data (:obj:`defaultdict`): A dictionary handlers can use to store data for the chat. - bot_data (:obj:`dict`): A dictionary handlers can use to store data for the bot. - persistence (:class:`telegram.ext.BasePersistence`): Optional. The persistence class to - store data that should be persistent over restarts. - context_types (:class:`telegram.ext.ContextTypes`): Container for the types used - in the ``context`` interface. - - .. versionadded:: 13.6 - - """ - - # Allowing '__weakref__' creation here since we need it for the singleton - __slots__ = ( - 'workers', - 'persistence', - 'use_context', - 'update_queue', - 'job_queue', - 'user_data', - 'chat_data', - 'bot_data', - '_update_persistence_lock', - 'handlers', - 'groups', - 'error_handlers', - 'running', - '__stop_event', - '__exception_event', - '__async_queue', - '__async_threads', - 'bot', - '__dict__', - '__weakref__', - 'context_types', - ) - - __singleton_lock = Lock() - __singleton_semaphore = BoundedSemaphore() - __singleton = None - logger = logging.getLogger(__name__) - - @overload - def __init__( - self: 'Dispatcher[CallbackContext[Dict, Dict, Dict], Dict, Dict, Dict]', - bot: 'Bot', - update_queue: Queue, - workers: int = 4, - exception_event: Event = None, - job_queue: 'JobQueue' = None, - persistence: BasePersistence = None, - use_context: bool = True, - ): - ... - - @overload - def __init__( - self: 'Dispatcher[CCT, UD, CD, BD]', - bot: 'Bot', - update_queue: Queue, - workers: int = 4, - exception_event: Event = None, - job_queue: 'JobQueue' = None, - persistence: BasePersistence = None, - use_context: bool = True, - context_types: ContextTypes[CCT, UD, CD, BD] = None, - ): - ... - - def __init__( - self, - bot: 'Bot', - update_queue: Queue, - workers: int = 4, - exception_event: Event = None, - job_queue: 'JobQueue' = None, - persistence: BasePersistence = None, - use_context: bool = True, - context_types: ContextTypes[CCT, UD, CD, BD] = None, - ): - self.bot = bot - self.update_queue = update_queue - self.job_queue = job_queue - self.workers = workers - self.use_context = use_context - self.context_types = cast(ContextTypes[CCT, UD, CD, BD], context_types or ContextTypes()) - - if not use_context: - warnings.warn( - 'Old Handler API is deprecated - see https://git.io/fxJuV for details', - TelegramDeprecationWarning, - stacklevel=3, - ) - - if self.workers < 1: - warnings.warn( - 'Asynchronous callbacks can not be processed without at least one worker thread.' - ) - - self.user_data: DefaultDict[int, UD] = defaultdict(self.context_types.user_data) - self.chat_data: DefaultDict[int, CD] = defaultdict(self.context_types.chat_data) - self.bot_data = self.context_types.bot_data() - self.persistence: Optional[BasePersistence] = None - self._update_persistence_lock = Lock() - if persistence: - if not isinstance(persistence, BasePersistence): - raise TypeError("persistence must be based on telegram.ext.BasePersistence") - self.persistence = persistence - self.persistence.set_bot(self.bot) - if self.persistence.store_user_data: - self.user_data = self.persistence.get_user_data() - if not isinstance(self.user_data, defaultdict): - raise ValueError("user_data must be of type defaultdict") - if self.persistence.store_chat_data: - self.chat_data = self.persistence.get_chat_data() - if not isinstance(self.chat_data, defaultdict): - raise ValueError("chat_data must be of type defaultdict") - if self.persistence.store_bot_data: - self.bot_data = self.persistence.get_bot_data() - if not isinstance(self.bot_data, self.context_types.bot_data): - raise ValueError( - f"bot_data must be of type {self.context_types.bot_data.__name__}" - ) - if self.persistence.store_callback_data: - self.bot = cast(telegram.ext.extbot.ExtBot, self.bot) - persistent_data = self.persistence.get_callback_data() - if persistent_data is not None: - if not isinstance(persistent_data, tuple) and len(persistent_data) != 2: - raise ValueError('callback_data must be a 2-tuple') - self.bot.callback_data_cache = CallbackDataCache( - self.bot, - self.bot.callback_data_cache.maxsize, - persistent_data=persistent_data, - ) - else: - self.persistence = None - - self.handlers: Dict[int, List[Handler]] = {} - """Dict[:obj:`int`, List[:class:`telegram.ext.Handler`]]: Holds the handlers per group.""" - self.groups: List[int] = [] - """List[:obj:`int`]: A list with all groups.""" - self.error_handlers: Dict[Callable, Union[bool, DefaultValue]] = {} - """Dict[:obj:`callable`, :obj:`bool`]: A dict, where the keys are error handlers and the - values indicate whether they are to be run asynchronously.""" - - self.running = False - """:obj:`bool`: Indicates if this dispatcher is running.""" - self.__stop_event = Event() - self.__exception_event = exception_event or Event() - self.__async_queue: Queue = Queue() - self.__async_threads: Set[Thread] = set() - - # For backward compatibility, we allow a "singleton" mode for the dispatcher. When there's - # only one instance of Dispatcher, it will be possible to use the `run_async` decorator. - with self.__singleton_lock: - if self.__singleton_semaphore.acquire(blocking=False): # pylint: disable=R1732 - self._set_singleton(self) - else: - self._set_singleton(None) - - def __setattr__(self, key: str, value: object) -> None: - # Mangled names don't automatically apply in __setattr__ (see - # https://docs.python.org/3/tutorial/classes.html#private-variables), so we have to make - # it mangled so they don't raise TelegramDeprecationWarning unnecessarily - if key.startswith('__'): - key = f"_{self.__class__.__name__}{key}" - if issubclass(self.__class__, Dispatcher) and self.__class__ is not Dispatcher: - object.__setattr__(self, key, value) - return - set_new_attribute_deprecated(self, key, value) - - @property - def exception_event(self) -> Event: # skipcq: PY-D0003 - return self.__exception_event - - def _init_async_threads(self, base_name: str, workers: int) -> None: - base_name = f'{base_name}_' if base_name else '' - - for i in range(workers): - thread = Thread(target=self._pooled, name=f'Bot:{self.bot.id}:worker:{base_name}{i}') - self.__async_threads.add(thread) - thread.start() - - @classmethod - def _set_singleton(cls, val: Optional['Dispatcher']) -> None: - cls.logger.debug('Setting singleton dispatcher as %s', val) - cls.__singleton = weakref.ref(val) if val else None - - @classmethod - def get_instance(cls) -> 'Dispatcher': - """Get the singleton instance of this class. - - Returns: - :class:`telegram.ext.Dispatcher` - - Raises: - RuntimeError - - """ - if cls.__singleton is not None: - return cls.__singleton() # type: ignore[return-value] # pylint: disable=not-callable - raise RuntimeError(f'{cls.__name__} not initialized or multiple instances exist') - - def _pooled(self) -> None: - thr_name = current_thread().getName() - while 1: - promise = self.__async_queue.get() - - # If unpacking fails, the thread pool is being closed from Updater._join_async_threads - if not isinstance(promise, Promise): - self.logger.debug( - "Closing run_async thread %s/%d", thr_name, len(self.__async_threads) - ) - break - - promise.run() - - if not promise.exception: - self.update_persistence(update=promise.update) - continue - - if isinstance(promise.exception, DispatcherHandlerStop): - self.logger.warning( - 'DispatcherHandlerStop is not supported with async functions; func: %s', - promise.pooled_function.__name__, - ) - continue - - # Avoid infinite recursion of error handlers. - if promise.pooled_function in self.error_handlers: - self.logger.error('An uncaught error was raised while handling the error.') - continue - - # Don't perform error handling for a `Promise` with deactivated error handling. This - # should happen only via the deprecated `@run_async` decorator or `Promises` created - # within error handlers - if not promise.error_handling: - self.logger.error('A promise with deactivated error handling raised an error.') - continue - - # If we arrive here, an exception happened in the promise and was neither - # DispatcherHandlerStop nor raised by an error handler. So we can and must handle it - try: - self.dispatch_error(promise.update, promise.exception, promise=promise) - except Exception: - self.logger.exception('An uncaught error was raised while handling the error.') - - def run_async( - self, func: Callable[..., object], *args: object, update: object = None, **kwargs: object - ) -> Promise: - """ - Queue a function (with given args/kwargs) to be run asynchronously. Exceptions raised - by the function will be handled by the error handlers registered with - :meth:`add_error_handler`. - - Warning: - * If you're using ``@run_async``/:meth:`run_async` you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - * Calling a function through :meth:`run_async` from within an error handler can lead to - an infinite error handling loop. - - Args: - func (:obj:`callable`): The function to run in the thread. - *args (:obj:`tuple`, optional): Arguments to ``func``. - update (:class:`telegram.Update` | :obj:`object`, optional): The update associated with - the functions call. If passed, it will be available in the error handlers, in case - an exception is raised by :attr:`func`. - **kwargs (:obj:`dict`, optional): Keyword arguments to ``func``. - - Returns: - Promise - - """ - return self._run_async(func, *args, update=update, error_handling=True, **kwargs) - - def _run_async( - self, - func: Callable[..., object], - *args: object, - update: object = None, - error_handling: bool = True, - **kwargs: object, - ) -> Promise: - # TODO: Remove error_handling parameter once we drop the @run_async decorator - promise = Promise(func, args, kwargs, update=update, error_handling=error_handling) - self.__async_queue.put(promise) - return promise - - def start(self, ready: Event = None) -> None: - """Thread target of thread 'dispatcher'. - - Runs in background and processes the update queue. - - Args: - ready (:obj:`threading.Event`, optional): If specified, the event will be set once the - dispatcher is ready. - - """ - if self.running: - self.logger.warning('already running') - if ready is not None: - ready.set() - return - - if self.__exception_event.is_set(): - msg = 'reusing dispatcher after exception event is forbidden' - self.logger.error(msg) - raise TelegramError(msg) - - self._init_async_threads(str(uuid4()), self.workers) - self.running = True - self.logger.debug('Dispatcher started') - - if ready is not None: - ready.set() - - while 1: - try: - # Pop update from update queue. - update = self.update_queue.get(True, 1) - except Empty: - if self.__stop_event.is_set(): - self.logger.debug('orderly stopping') - break - if self.__exception_event.is_set(): - self.logger.critical('stopping due to exception in another thread') - break - continue - - self.logger.debug('Processing Update: %s', update) - self.process_update(update) - self.update_queue.task_done() - - self.running = False - self.logger.debug('Dispatcher thread stopped') - - def stop(self) -> None: - """Stops the thread.""" - if self.running: - self.__stop_event.set() - while self.running: - sleep(0.1) - self.__stop_event.clear() - - # async threads must be join()ed only after the dispatcher thread was joined, - # otherwise we can still have new async threads dispatched - threads = list(self.__async_threads) - total = len(threads) - - # Stop all threads in the thread pool by put()ting one non-tuple per thread - for i in range(total): - self.__async_queue.put(None) - - for i, thr in enumerate(threads): - self.logger.debug('Waiting for async thread %s/%s to end', i + 1, total) - thr.join() - self.__async_threads.remove(thr) - self.logger.debug('async thread %s/%s has ended', i + 1, total) - - @property - def has_running_threads(self) -> bool: # skipcq: PY-D0003 - return self.running or bool(self.__async_threads) - - def process_update(self, update: object) -> None: - """Processes a single update and updates the persistence. - - Note: - If the update is handled by least one synchronously running handlers (i.e. - ``run_async=False``), :meth:`update_persistence` is called *once* after all handlers - synchronous handlers are done. Each asynchronously running handler will trigger - :meth:`update_persistence` on its own. - - Args: - update (:class:`telegram.Update` | :obj:`object` | \ - :class:`telegram.error.TelegramError`): - The update to process. - - """ - # An error happened while polling - if isinstance(update, TelegramError): - try: - self.dispatch_error(None, update) - except Exception: - self.logger.exception('An uncaught error was raised while handling the error.') - return - - context = None - handled = False - sync_modes = [] - - for group in self.groups: - try: - for handler in self.handlers[group]: - check = handler.check_update(update) - if check is not None and check is not False: - if not context and self.use_context: - context = self.context_types.context.from_update(update, self) - context.refresh_data() - handled = True - sync_modes.append(handler.run_async) - handler.handle_update(update, self, check, context) - break - - # Stop processing with any other handler. - except DispatcherHandlerStop: - self.logger.debug('Stopping further handlers due to DispatcherHandlerStop') - self.update_persistence(update=update) - break - - # Dispatch any error. - except Exception as exc: - try: - self.dispatch_error(update, exc) - except DispatcherHandlerStop: - self.logger.debug('Error handler stopped further handlers') - break - # Errors should not stop the thread. - except Exception: - self.logger.exception('An uncaught error was raised while handling the error.') - - # Update persistence, if handled - handled_only_async = all(sync_modes) - if handled: - # Respect default settings - if all(mode is DEFAULT_FALSE for mode in sync_modes) and self.bot.defaults: - handled_only_async = self.bot.defaults.run_async - # If update was only handled by async handlers, we don't need to update here - if not handled_only_async: - self.update_persistence(update=update) - - def add_handler(self, handler: Handler[UT, CCT], group: int = DEFAULT_GROUP) -> None: - """Register a handler. - - TL;DR: Order and priority counts. 0 or 1 handlers per group will be used. End handling of - update with :class:`telegram.ext.DispatcherHandlerStop`. - - A handler must be an instance of a subclass of :class:`telegram.ext.Handler`. All handlers - are organized in groups with a numeric value. The default group is 0. All groups will be - evaluated for handling an update, but only 0 or 1 handler per group will be used. If - :class:`telegram.ext.DispatcherHandlerStop` is raised from one of the handlers, no further - handlers (regardless of the group) will be called. - - The priority/order of handlers is determined as follows: - - * Priority of the group (lower group number == higher priority) - * The first handler in a group which should handle an update (see - :attr:`telegram.ext.Handler.check_update`) will be used. Other handlers from the - group will not be used. The order in which handlers were added to the group defines the - priority. - - Args: - handler (:class:`telegram.ext.Handler`): A Handler instance. - group (:obj:`int`, optional): The group identifier. Default is 0. - - """ - # Unfortunately due to circular imports this has to be here - from .conversationhandler import ConversationHandler # pylint: disable=C0415 - - if not isinstance(handler, Handler): - raise TypeError(f'handler is not an instance of {Handler.__name__}') - if not isinstance(group, int): - raise TypeError('group is not int') - # For some reason MyPy infers the type of handler is <nothing> here, - # so for now we just ignore all the errors - if ( - isinstance(handler, ConversationHandler) - and handler.persistent # type: ignore[attr-defined] - and handler.name # type: ignore[attr-defined] - ): - if not self.persistence: - raise ValueError( - f"ConversationHandler {handler.name} " # type: ignore[attr-defined] - f"can not be persistent if dispatcher has no persistence" - ) - handler.persistence = self.persistence # type: ignore[attr-defined] - handler.conversations = ( # type: ignore[attr-defined] - self.persistence.get_conversations(handler.name) # type: ignore[attr-defined] - ) - - if group not in self.handlers: - self.handlers[group] = [] - self.groups.append(group) - self.groups = sorted(self.groups) - - self.handlers[group].append(handler) - - def remove_handler(self, handler: Handler, group: int = DEFAULT_GROUP) -> None: - """Remove a handler from the specified group. - - Args: - handler (:class:`telegram.ext.Handler`): A Handler instance. - group (:obj:`object`, optional): The group identifier. Default is 0. - - """ - if handler in self.handlers[group]: - self.handlers[group].remove(handler) - if not self.handlers[group]: - del self.handlers[group] - self.groups.remove(group) - - def update_persistence(self, update: object = None) -> None: - """Update :attr:`user_data`, :attr:`chat_data` and :attr:`bot_data` in :attr:`persistence`. - - Args: - update (:class:`telegram.Update`, optional): The update to process. If passed, only the - corresponding ``user_data`` and ``chat_data`` will be updated. - """ - with self._update_persistence_lock: - self.__update_persistence(update) - - def __update_persistence(self, update: object = None) -> None: - if self.persistence: - # We use list() here in order to decouple chat_ids from self.chat_data, as dict view - # objects will change, when the dict does and we want to loop over chat_ids - chat_ids = list(self.chat_data.keys()) - user_ids = list(self.user_data.keys()) - - if isinstance(update, Update): - if update.effective_chat: - chat_ids = [update.effective_chat.id] - else: - chat_ids = [] - if update.effective_user: - user_ids = [update.effective_user.id] - else: - user_ids = [] - - if self.persistence.store_callback_data: - self.bot = cast(telegram.ext.extbot.ExtBot, self.bot) - try: - self.persistence.update_callback_data( - self.bot.callback_data_cache.persistence_data - ) - except Exception as exc: - try: - self.dispatch_error(update, exc) - except Exception: - message = ( - 'Saving callback data raised an error and an ' - 'uncaught error was raised while handling ' - 'the error with an error_handler' - ) - self.logger.exception(message) - if self.persistence.store_bot_data: - try: - self.persistence.update_bot_data(self.bot_data) - except Exception as exc: - try: - self.dispatch_error(update, exc) - except Exception: - message = ( - 'Saving bot data raised an error and an ' - 'uncaught error was raised while handling ' - 'the error with an error_handler' - ) - self.logger.exception(message) - if self.persistence.store_chat_data: - for chat_id in chat_ids: - try: - self.persistence.update_chat_data(chat_id, self.chat_data[chat_id]) - except Exception as exc: - try: - self.dispatch_error(update, exc) - except Exception: - message = ( - 'Saving chat data raised an error and an ' - 'uncaught error was raised while handling ' - 'the error with an error_handler' - ) - self.logger.exception(message) - if self.persistence.store_user_data: - for user_id in user_ids: - try: - self.persistence.update_user_data(user_id, self.user_data[user_id]) - except Exception as exc: - try: - self.dispatch_error(update, exc) - except Exception: - message = ( - 'Saving user data raised an error and an ' - 'uncaught error was raised while handling ' - 'the error with an error_handler' - ) - self.logger.exception(message) - - def add_error_handler( - self, - callback: Callable[[object, CCT], None], - run_async: Union[bool, DefaultValue] = DEFAULT_FALSE, # pylint: disable=W0621 - ) -> None: - """Registers an error handler in the Dispatcher. This handler will receive every error - which happens in your bot. - - Note: - Attempts to add the same callback multiple times will be ignored. - - Warning: - The errors handled within these handlers won't show up in the logger, so you - need to make sure that you reraise the error. - - Args: - callback (:obj:`callable`): The callback function for this error handler. Will be - called when an error is raised. Callback signature for context based API: - - ``def callback(update: object, context: CallbackContext)`` - - The error that happened will be present in context.error. - run_async (:obj:`bool`, optional): Whether this handlers callback should be run - asynchronously using :meth:`run_async`. Defaults to :obj:`False`. - - Note: - See https://git.io/fxJuV for more info about switching to context based API. - """ - if callback in self.error_handlers: - self.logger.debug('The callback is already registered as an error handler. Ignoring.') - return - - if run_async is DEFAULT_FALSE and self.bot.defaults and self.bot.defaults.run_async: - run_async = True - - self.error_handlers[callback] = run_async - - def remove_error_handler(self, callback: Callable[[object, CCT], None]) -> None: - """Removes an error handler. - - Args: - callback (:obj:`callable`): The error handler to remove. - - """ - self.error_handlers.pop(callback, None) - - def dispatch_error( - self, update: Optional[object], error: Exception, promise: Promise = None - ) -> None: - """Dispatches an error. - - Args: - update (:obj:`object` | :class:`telegram.Update`): The update that caused the error. - error (:obj:`Exception`): The error that was raised. - promise (:class:`telegram.utils.Promise`, optional): The promise whose pooled function - raised the error. - - """ - async_args = None if not promise else promise.args - async_kwargs = None if not promise else promise.kwargs - - if self.error_handlers: - for callback, run_async in self.error_handlers.items(): # pylint: disable=W0621 - if self.use_context: - context = self.context_types.context.from_error( - update, error, self, async_args=async_args, async_kwargs=async_kwargs - ) - if run_async: - self.run_async(callback, update, context, update=update) - else: - callback(update, context) - else: - if run_async: - self.run_async(callback, self.bot, update, error, update=update) - else: - callback(self.bot, update, error) - - else: - self.logger.exception( - 'No error handlers are registered, logging exception.', exc_info=error - ) diff --git a/venv/lib/python3.8/site-packages/telegram/ext/extbot.py b/venv/lib/python3.8/site-packages/telegram/ext/extbot.py deleted file mode 100644 index a718bce..0000000 --- a/venv/lib/python3.8/site-packages/telegram/ext/extbot.py +++ /dev/null @@ -1,326 +0,0 @@ -#!/usr/bin/env python -# pylint: disable=E0611,E0213,E1102,C0103,E1101,R0913,R0904 -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram Bot with convenience extensions.""" -from copy import copy -from typing import Union, cast, List, Callable, Optional, Tuple, TypeVar, TYPE_CHECKING, Sequence - -import telegram.bot -from telegram import ( - ReplyMarkup, - Message, - InlineKeyboardMarkup, - Poll, - MessageId, - Update, - Chat, - CallbackQuery, -) - -from telegram.ext.callbackdatacache import CallbackDataCache -from telegram.utils.types import JSONDict, ODVInput, DVInput -from ..utils.helpers import DEFAULT_NONE - -if TYPE_CHECKING: - from telegram import InlineQueryResult, MessageEntity - from telegram.utils.request import Request - from .defaults import Defaults - -HandledTypes = TypeVar('HandledTypes', bound=Union[Message, CallbackQuery, Chat]) - - -class ExtBot(telegram.bot.Bot): - """This object represents a Telegram Bot with convenience extensions. - - Warning: - Not to be confused with :class:`telegram.Bot`. - - For the documentation of the arguments, methods and attributes, please see - :class:`telegram.Bot`. - - .. versionadded:: 13.6 - - Args: - defaults (:class:`telegram.ext.Defaults`, optional): An object containing default values to - be used if not set explicitly in the bot methods. - arbitrary_callback_data (:obj:`bool` | :obj:`int`, optional): Whether to - allow arbitrary objects as callback data for :class:`telegram.InlineKeyboardButton`. - Pass an integer to specify the maximum number of objects cached in memory. For more - details, please see our `wiki <https://git.io/JGBDI>`_. Defaults to :obj:`False`. - - Attributes: - arbitrary_callback_data (:obj:`bool` | :obj:`int`): Whether this bot instance - allows to use arbitrary objects as callback data for - :class:`telegram.InlineKeyboardButton`. - callback_data_cache (:class:`telegram.ext.CallbackDataCache`): The cache for objects passed - as callback data for :class:`telegram.InlineKeyboardButton`. - - """ - - __slots__ = ('arbitrary_callback_data', 'callback_data_cache') - - # The ext_bot argument is a little hack to get warnings handled correctly. - # It's not very clean, but the warnings will be dropped at some point anyway. - def __setattr__(self, key: str, value: object, ext_bot: bool = True) -> None: - if issubclass(self.__class__, ExtBot) and self.__class__ is not ExtBot: - object.__setattr__(self, key, value) - return - super().__setattr__(key, value, ext_bot=ext_bot) # type: ignore[call-arg] - - def __init__( - self, - token: str, - base_url: str = None, - base_file_url: str = None, - request: 'Request' = None, - private_key: bytes = None, - private_key_password: bytes = None, - defaults: 'Defaults' = None, - arbitrary_callback_data: Union[bool, int] = False, - ): - super().__init__( - token=token, - base_url=base_url, - base_file_url=base_file_url, - request=request, - private_key=private_key, - private_key_password=private_key_password, - defaults=defaults, - ) - - # set up callback_data - if not isinstance(arbitrary_callback_data, bool): - maxsize = cast(int, arbitrary_callback_data) - self.arbitrary_callback_data = True - else: - maxsize = 1024 - self.arbitrary_callback_data = arbitrary_callback_data - self.callback_data_cache: CallbackDataCache = CallbackDataCache(bot=self, maxsize=maxsize) - - def _replace_keyboard(self, reply_markup: Optional[ReplyMarkup]) -> Optional[ReplyMarkup]: - # If the reply_markup is an inline keyboard and we allow arbitrary callback data, let the - # CallbackDataCache build a new keyboard with the data replaced. Otherwise return the input - if isinstance(reply_markup, InlineKeyboardMarkup) and self.arbitrary_callback_data: - return self.callback_data_cache.process_keyboard(reply_markup) - - return reply_markup - - def insert_callback_data(self, update: Update) -> None: - """If this bot allows for arbitrary callback data, this inserts the cached data into all - corresponding buttons within this update. - - Note: - Checks :attr:`telegram.Message.via_bot` and :attr:`telegram.Message.from_user` to check - if the reply markup (if any) was actually sent by this caches bot. If it was not, the - message will be returned unchanged. - - Note that this will fail for channel posts, as :attr:`telegram.Message.from_user` is - :obj:`None` for those! In the corresponding reply markups the callback data will be - replaced by :class:`telegram.ext.InvalidCallbackData`. - - Warning: - *In place*, i.e. the passed :class:`telegram.Message` will be changed! - - Args: - update (:class`telegram.Update`): The update. - - """ - # The only incoming updates that can directly contain a message sent by the bot itself are: - # * CallbackQueries - # * Messages where the pinned_message is sent by the bot - # * Messages where the reply_to_message is sent by the bot - # * Messages where via_bot is the bot - # Finally there is effective_chat.pinned message, but that's only returned in get_chat - if update.callback_query: - self._insert_callback_data(update.callback_query) - # elif instead of if, as effective_message includes callback_query.message - # and that has already been processed - elif update.effective_message: - self._insert_callback_data(update.effective_message) - - def _insert_callback_data(self, obj: HandledTypes) -> HandledTypes: - if not self.arbitrary_callback_data: - return obj - - if isinstance(obj, CallbackQuery): - self.callback_data_cache.process_callback_query(obj) - return obj # type: ignore[return-value] - - if isinstance(obj, Message): - if obj.reply_to_message: - # reply_to_message can't contain further reply_to_messages, so no need to check - self.callback_data_cache.process_message(obj.reply_to_message) - if obj.reply_to_message.pinned_message: - # pinned messages can't contain reply_to_message, no need to check - self.callback_data_cache.process_message(obj.reply_to_message.pinned_message) - if obj.pinned_message: - # pinned messages can't contain reply_to_message, no need to check - self.callback_data_cache.process_message(obj.pinned_message) - - # Finally, handle the message itself - self.callback_data_cache.process_message(message=obj) - return obj # type: ignore[return-value] - - if isinstance(obj, Chat) and obj.pinned_message: - self.callback_data_cache.process_message(obj.pinned_message) - - return obj - - def _message( - self, - endpoint: str, - data: JSONDict, - reply_to_message_id: int = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_markup: ReplyMarkup = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> Union[bool, Message]: - # We override this method to call self._replace_keyboard and self._insert_callback_data. - # This covers most methods that have a reply_markup - result = super()._message( - endpoint=endpoint, - data=data, - reply_to_message_id=reply_to_message_id, - disable_notification=disable_notification, - reply_markup=self._replace_keyboard(reply_markup), - allow_sending_without_reply=allow_sending_without_reply, - timeout=timeout, - api_kwargs=api_kwargs, - ) - if isinstance(result, Message): - self._insert_callback_data(result) - return result - - def get_updates( - self, - offset: int = None, - limit: int = 100, - timeout: float = 0, - read_latency: float = 2.0, - allowed_updates: List[str] = None, - api_kwargs: JSONDict = None, - ) -> List[Update]: - updates = super().get_updates( - offset=offset, - limit=limit, - timeout=timeout, - read_latency=read_latency, - allowed_updates=allowed_updates, - api_kwargs=api_kwargs, - ) - - for update in updates: - self.insert_callback_data(update) - - return updates - - def _effective_inline_results( # pylint: disable=R0201 - self, - results: Union[ - Sequence['InlineQueryResult'], Callable[[int], Optional[Sequence['InlineQueryResult']]] - ], - next_offset: str = None, - current_offset: str = None, - ) -> Tuple[Sequence['InlineQueryResult'], Optional[str]]: - """ - This method is called by Bot.answer_inline_query to build the actual results list. - Overriding this to call self._replace_keyboard suffices - """ - effective_results, next_offset = super()._effective_inline_results( - results=results, next_offset=next_offset, current_offset=current_offset - ) - - # Process arbitrary callback - if not self.arbitrary_callback_data: - return effective_results, next_offset - results = [] - for result in effective_results: - # All currently existingInlineQueryResults have a reply_markup, but future ones - # might not have. Better be save than sorry - if not hasattr(result, 'reply_markup'): - results.append(result) - else: - # We build a new result in case the user wants to use the same object in - # different places - new_result = copy(result) - markup = self._replace_keyboard(result.reply_markup) # type: ignore[attr-defined] - new_result.reply_markup = markup - results.append(new_result) - - return results, next_offset - - def stop_poll( - self, - chat_id: Union[int, str], - message_id: int, - reply_markup: InlineKeyboardMarkup = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> Poll: - # We override this method to call self._replace_keyboard - return super().stop_poll( - chat_id=chat_id, - message_id=message_id, - reply_markup=self._replace_keyboard(reply_markup), - timeout=timeout, - api_kwargs=api_kwargs, - ) - - def copy_message( - self, - chat_id: Union[int, str], - from_chat_id: Union[str, int], - message_id: int, - caption: str = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[Tuple['MessageEntity', ...], List['MessageEntity']] = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE, - reply_markup: ReplyMarkup = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> MessageId: - # We override this method to call self._replace_keyboard - return super().copy_message( - chat_id=chat_id, - from_chat_id=from_chat_id, - message_id=message_id, - caption=caption, - parse_mode=parse_mode, - caption_entities=caption_entities, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - allow_sending_without_reply=allow_sending_without_reply, - reply_markup=self._replace_keyboard(reply_markup), - timeout=timeout, - api_kwargs=api_kwargs, - ) - - def get_chat( - self, - chat_id: Union[str, int], - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> Chat: - # We override this method to call self._insert_callback_data - result = super().get_chat(chat_id=chat_id, timeout=timeout, api_kwargs=api_kwargs) - return self._insert_callback_data(result) diff --git a/venv/lib/python3.8/site-packages/telegram/ext/filters.py b/venv/lib/python3.8/site-packages/telegram/ext/filters.py deleted file mode 100644 index 72a4b30..0000000 --- a/venv/lib/python3.8/site-packages/telegram/ext/filters.py +++ /dev/null @@ -1,2313 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -# pylint: disable=C0112, C0103, W0221 -"""This module contains the Filters for use with the MessageHandler class.""" - -import re -import warnings - -from abc import ABC, abstractmethod -from sys import version_info as py_ver -from threading import Lock -from typing import ( - Dict, - FrozenSet, - List, - Match, - Optional, - Pattern, - Set, - Tuple, - Union, - cast, - NoReturn, -) - -from telegram import Chat, Message, MessageEntity, Update, User - -__all__ = [ - 'Filters', - 'BaseFilter', - 'MessageFilter', - 'UpdateFilter', - 'InvertedFilter', - 'MergedFilter', - 'XORFilter', -] - -from telegram.utils.deprecate import TelegramDeprecationWarning, set_new_attribute_deprecated -from telegram.utils.types import SLT - -DataDict = Dict[str, list] - - -class BaseFilter(ABC): - """Base class for all Filters. - - Filters subclassing from this class can combined using bitwise operators: - - And: - - >>> (Filters.text & Filters.entity(MENTION)) - - Or: - - >>> (Filters.audio | Filters.video) - - Exclusive Or: - - >>> (Filters.regex('To Be') ^ Filters.regex('Not 2B')) - - Not: - - >>> ~ Filters.command - - Also works with more than two filters: - - >>> (Filters.text & (Filters.entity(URL) | Filters.entity(TEXT_LINK))) - >>> Filters.text & (~ Filters.forwarded) - - Note: - Filters use the same short circuiting logic as python's `and`, `or` and `not`. - This means that for example: - - >>> Filters.regex(r'(a?x)') | Filters.regex(r'(b?x)') - - With ``message.text == x``, will only ever return the matches for the first filter, - since the second one is never evaluated. - - - If you want to create your own filters create a class inheriting from either - :class:`MessageFilter` or :class:`UpdateFilter` and implement a :meth:`filter` method that - returns a boolean: :obj:`True` if the message should be - handled, :obj:`False` otherwise. - Note that the filters work only as class instances, not - actual class objects (so remember to - initialize your filter classes). - - By default the filters name (what will get printed when converted to a string for display) - will be the class name. If you want to overwrite this assign a better name to the :attr:`name` - class variable. - - Attributes: - name (:obj:`str`): Name for this filter. Defaults to the type of filter. - data_filter (:obj:`bool`): Whether this filter is a data filter. A data filter should - return a dict with lists. The dict will be merged with - :class:`telegram.ext.CallbackContext`'s internal dict in most cases - (depends on the handler). - """ - - if py_ver < (3, 7): - __slots__ = ('_name', '_data_filter') - else: - __slots__ = ('_name', '_data_filter', '__dict__') # type: ignore[assignment] - - def __new__(cls, *args: object, **kwargs: object) -> 'BaseFilter': # pylint: disable=W0613 - instance = super().__new__(cls) - instance._name = None - instance._data_filter = False - - return instance - - @abstractmethod - def __call__(self, update: Update) -> Optional[Union[bool, DataDict]]: - ... - - def __and__(self, other: 'BaseFilter') -> 'BaseFilter': - return MergedFilter(self, and_filter=other) - - def __or__(self, other: 'BaseFilter') -> 'BaseFilter': - return MergedFilter(self, or_filter=other) - - def __xor__(self, other: 'BaseFilter') -> 'BaseFilter': - return XORFilter(self, other) - - def __invert__(self) -> 'BaseFilter': - return InvertedFilter(self) - - def __setattr__(self, key: str, value: object) -> None: - # Allow setting custom attributes w/o warning for user defined custom filters. - # To differentiate between a custom and a PTB filter, we use this hacky but - # simple way of checking the module name where the class is defined from. - if ( - issubclass(self.__class__, (UpdateFilter, MessageFilter)) - and self.__class__.__module__ != __name__ - ): # __name__ is telegram.ext.filters - object.__setattr__(self, key, value) - return - set_new_attribute_deprecated(self, key, value) - - @property - def data_filter(self) -> bool: - return self._data_filter - - @data_filter.setter - def data_filter(self, value: bool) -> None: - self._data_filter = value - - @property - def name(self) -> Optional[str]: - return self._name - - @name.setter - def name(self, name: Optional[str]) -> None: - self._name = name # pylint: disable=E0237 - - def __repr__(self) -> str: - # We do this here instead of in a __init__ so filter don't have to call __init__ or super() - if self.name is None: - self.name = self.__class__.__name__ - return self.name - - -class MessageFilter(BaseFilter): - """Base class for all Message Filters. In contrast to :class:`UpdateFilter`, the object passed - to :meth:`filter` is ``update.effective_message``. - - Please see :class:`telegram.ext.filters.BaseFilter` for details on how to create custom - filters. - - Attributes: - name (:obj:`str`): Name for this filter. Defaults to the type of filter. - data_filter (:obj:`bool`): Whether this filter is a data filter. A data filter should - return a dict with lists. The dict will be merged with - :class:`telegram.ext.CallbackContext`'s internal dict in most cases - (depends on the handler). - - """ - - __slots__ = () - - def __call__(self, update: Update) -> Optional[Union[bool, DataDict]]: - return self.filter(update.effective_message) - - @abstractmethod - def filter(self, message: Message) -> Optional[Union[bool, DataDict]]: - """This method must be overwritten. - - Args: - message (:class:`telegram.Message`): The message that is tested. - - Returns: - :obj:`dict` or :obj:`bool` - - """ - - -class UpdateFilter(BaseFilter): - """Base class for all Update Filters. In contrast to :class:`MessageFilter`, the object - passed to :meth:`filter` is ``update``, which allows to create filters like - :attr:`Filters.update.edited_message`. - - Please see :class:`telegram.ext.filters.BaseFilter` for details on how to create custom - filters. - - Attributes: - name (:obj:`str`): Name for this filter. Defaults to the type of filter. - data_filter (:obj:`bool`): Whether this filter is a data filter. A data filter should - return a dict with lists. The dict will be merged with - :class:`telegram.ext.CallbackContext`'s internal dict in most cases - (depends on the handler). - - """ - - __slots__ = () - - def __call__(self, update: Update) -> Optional[Union[bool, DataDict]]: - return self.filter(update) - - @abstractmethod - def filter(self, update: Update) -> Optional[Union[bool, DataDict]]: - """This method must be overwritten. - - Args: - update (:class:`telegram.Update`): The update that is tested. - - Returns: - :obj:`dict` or :obj:`bool`. - - """ - - -class InvertedFilter(UpdateFilter): - """Represents a filter that has been inverted. - - Args: - f: The filter to invert. - - """ - - __slots__ = ('f',) - - def __init__(self, f: BaseFilter): - self.f = f - - def filter(self, update: Update) -> bool: - return not bool(self.f(update)) - - @property - def name(self) -> str: - return f"<inverted {self.f}>" - - @name.setter - def name(self, name: str) -> NoReturn: - raise RuntimeError('Cannot set name for InvertedFilter') - - -class MergedFilter(UpdateFilter): - """Represents a filter consisting of two other filters. - - Args: - base_filter: Filter 1 of the merged filter. - and_filter: Optional filter to "and" with base_filter. Mutually exclusive with or_filter. - or_filter: Optional filter to "or" with base_filter. Mutually exclusive with and_filter. - - """ - - __slots__ = ('base_filter', 'and_filter', 'or_filter') - - def __init__( - self, base_filter: BaseFilter, and_filter: BaseFilter = None, or_filter: BaseFilter = None - ): - self.base_filter = base_filter - if self.base_filter.data_filter: - self.data_filter = True - self.and_filter = and_filter - if ( - self.and_filter - and not isinstance(self.and_filter, bool) - and self.and_filter.data_filter - ): - self.data_filter = True - self.or_filter = or_filter - if self.or_filter and not isinstance(self.and_filter, bool) and self.or_filter.data_filter: - self.data_filter = True - - @staticmethod - def _merge(base_output: Union[bool, Dict], comp_output: Union[bool, Dict]) -> DataDict: - base = base_output if isinstance(base_output, dict) else {} - comp = comp_output if isinstance(comp_output, dict) else {} - for k in comp.keys(): - # Make sure comp values are lists - comp_value = comp[k] if isinstance(comp[k], list) else [] - try: - # If base is a list then merge - if isinstance(base[k], list): - base[k] += comp_value - else: - base[k] = [base[k]] + comp_value - except KeyError: - base[k] = comp_value - return base - - def filter(self, update: Update) -> Union[bool, DataDict]: # pylint: disable=R0911 - base_output = self.base_filter(update) - # We need to check if the filters are data filters and if so return the merged data. - # If it's not a data filter or an or_filter but no matches return bool - if self.and_filter: - # And filter needs to short circuit if base is falsey - if base_output: - comp_output = self.and_filter(update) - if comp_output: - if self.data_filter: - merged = self._merge(base_output, comp_output) - if merged: - return merged - return True - elif self.or_filter: - # Or filter needs to short circuit if base is truthey - if base_output: - if self.data_filter: - return base_output - return True - - comp_output = self.or_filter(update) - if comp_output: - if self.data_filter: - return comp_output - return True - return False - - @property - def name(self) -> str: - return ( - f"<{self.base_filter} {'and' if self.and_filter else 'or'} " - f"{self.and_filter or self.or_filter}>" - ) - - @name.setter - def name(self, name: str) -> NoReturn: - raise RuntimeError('Cannot set name for MergedFilter') - - -class XORFilter(UpdateFilter): - """Convenience filter acting as wrapper for :class:`MergedFilter` representing the an XOR gate - for two filters. - - Args: - base_filter: Filter 1 of the merged filter. - xor_filter: Filter 2 of the merged filter. - - """ - - __slots__ = ('base_filter', 'xor_filter', 'merged_filter') - - def __init__(self, base_filter: BaseFilter, xor_filter: BaseFilter): - self.base_filter = base_filter - self.xor_filter = xor_filter - self.merged_filter = (base_filter & ~xor_filter) | (~base_filter & xor_filter) - - def filter(self, update: Update) -> Optional[Union[bool, DataDict]]: - return self.merged_filter(update) - - @property - def name(self) -> str: - return f'<{self.base_filter} xor {self.xor_filter}>' - - @name.setter - def name(self, name: str) -> NoReturn: - raise RuntimeError('Cannot set name for XORFilter') - - -class _DiceEmoji(MessageFilter): - __slots__ = ('emoji',) - - def __init__(self, emoji: str = None, name: str = None): - self.name = f'Filters.dice.{name}' if name else 'Filters.dice' - self.emoji = emoji - - class _DiceValues(MessageFilter): - __slots__ = ('values', 'emoji') - - def __init__( - self, - values: SLT[int], - name: str, - emoji: str = None, - ): - self.values = [values] if isinstance(values, int) else values - self.emoji = emoji - self.name = f'{name}({values})' - - def filter(self, message: Message) -> bool: - if message.dice and message.dice.value in self.values: - if self.emoji: - return message.dice.emoji == self.emoji - return True - return False - - def __call__( # type: ignore[override] - self, update: Union[Update, List[int], Tuple[int]] - ) -> Union[bool, '_DiceValues']: - if isinstance(update, Update): - return self.filter(update.effective_message) - return self._DiceValues(update, self.name, emoji=self.emoji) - - def filter(self, message: Message) -> bool: - if bool(message.dice): - if self.emoji: - return message.dice.emoji == self.emoji - return True - return False - - -class Filters: - """Predefined filters for use as the ``filter`` argument of - :class:`telegram.ext.MessageHandler`. - - Examples: - Use ``MessageHandler(Filters.video, callback_method)`` to filter all video - messages. Use ``MessageHandler(Filters.contact, callback_method)`` for all contacts. etc. - - """ - - __slots__ = ('__dict__',) - - def __setattr__(self, key: str, value: object) -> None: - set_new_attribute_deprecated(self, key, value) - - class _All(MessageFilter): - __slots__ = () - name = 'Filters.all' - - def filter(self, message: Message) -> bool: - return True - - all = _All() - """All Messages.""" - - class _Text(MessageFilter): - __slots__ = () - name = 'Filters.text' - - class _TextStrings(MessageFilter): - __slots__ = ('strings',) - - def __init__(self, strings: Union[List[str], Tuple[str]]): - self.strings = strings - self.name = f'Filters.text({strings})' - - def filter(self, message: Message) -> bool: - if message.text: - return message.text in self.strings - return False - - def __call__( # type: ignore[override] - self, update: Union[Update, List[str], Tuple[str]] - ) -> Union[bool, '_TextStrings']: - if isinstance(update, Update): - return self.filter(update.effective_message) - return self._TextStrings(update) - - def filter(self, message: Message) -> bool: - return bool(message.text) - - text = _Text() - """Text Messages. If a list of strings is passed, it filters messages to only allow those - whose text is appearing in the given list. - - Examples: - To allow any text message, simply use - ``MessageHandler(Filters.text, callback_method)``. - - A simple use case for passing a list is to allow only messages that were sent by a - custom :class:`telegram.ReplyKeyboardMarkup`:: - - buttons = ['Start', 'Settings', 'Back'] - markup = ReplyKeyboardMarkup.from_column(buttons) - ... - MessageHandler(Filters.text(buttons), callback_method) - - Note: - * Dice messages don't have text. If you want to filter either text or dice messages, use - ``Filters.text | Filters.dice``. - * Messages containing a command are accepted by this filter. Use - ``Filters.text & (~Filters.command)``, if you want to filter only text messages without - commands. - - Args: - update (List[:obj:`str`] | Tuple[:obj:`str`], optional): Which messages to allow. Only - exact matches are allowed. If not specified, will allow any text message. - """ - - class _Caption(MessageFilter): - __slots__ = () - name = 'Filters.caption' - - class _CaptionStrings(MessageFilter): - __slots__ = ('strings',) - - def __init__(self, strings: Union[List[str], Tuple[str]]): - self.strings = strings - self.name = f'Filters.caption({strings})' - - def filter(self, message: Message) -> bool: - if message.caption: - return message.caption in self.strings - return False - - def __call__( # type: ignore[override] - self, update: Union[Update, List[str], Tuple[str]] - ) -> Union[bool, '_CaptionStrings']: - if isinstance(update, Update): - return self.filter(update.effective_message) - return self._CaptionStrings(update) - - def filter(self, message: Message) -> bool: - return bool(message.caption) - - caption = _Caption() - """Messages with a caption. If a list of strings is passed, it filters messages to only - allow those whose caption is appearing in the given list. - - Examples: - ``MessageHandler(Filters.caption, callback_method)`` - - Args: - update (List[:obj:`str`] | Tuple[:obj:`str`], optional): Which captions to allow. Only - exact matches are allowed. If not specified, will allow any message with a caption. - """ - - class _Command(MessageFilter): - __slots__ = () - name = 'Filters.command' - - class _CommandOnlyStart(MessageFilter): - __slots__ = ('only_start',) - - def __init__(self, only_start: bool): - self.only_start = only_start - self.name = f'Filters.command({only_start})' - - def filter(self, message: Message) -> bool: - return bool( - message.entities - and any(e.type == MessageEntity.BOT_COMMAND for e in message.entities) - ) - - def __call__( # type: ignore[override] - self, update: Union[bool, Update] - ) -> Union[bool, '_CommandOnlyStart']: - if isinstance(update, Update): - return self.filter(update.effective_message) - return self._CommandOnlyStart(update) - - def filter(self, message: Message) -> bool: - return bool( - message.entities - and message.entities[0].type == MessageEntity.BOT_COMMAND - and message.entities[0].offset == 0 - ) - - command = _Command() - """ - Messages with a :attr:`telegram.MessageEntity.BOT_COMMAND`. By default only allows - messages `starting` with a bot command. Pass :obj:`False` to also allow messages that contain a - bot command `anywhere` in the text. - - Examples:: - - MessageHandler(Filters.command, command_at_start_callback) - MessageHandler(Filters.command(False), command_anywhere_callback) - - Note: - ``Filters.text`` also accepts messages containing a command. - - Args: - update (:obj:`bool`, optional): Whether to only allow messages that `start` with a bot - command. Defaults to :obj:`True`. - """ - - class regex(MessageFilter): - """ - Filters updates by searching for an occurrence of ``pattern`` in the message text. - The ``re.search()`` function is used to determine whether an update should be filtered. - - Refer to the documentation of the ``re`` module for more information. - - To get the groups and groupdict matched, see :attr:`telegram.ext.CallbackContext.matches`. - - Examples: - Use ``MessageHandler(Filters.regex(r'help'), callback)`` to capture all messages that - contain the word 'help'. You can also use - ``MessageHandler(Filters.regex(re.compile(r'help', re.IGNORECASE)), callback)`` if - you want your pattern to be case insensitive. This approach is recommended - if you need to specify flags on your pattern. - - Note: - Filters use the same short circuiting logic as python's `and`, `or` and `not`. - This means that for example: - - >>> Filters.regex(r'(a?x)') | Filters.regex(r'(b?x)') - - With a message.text of `x`, will only ever return the matches for the first filter, - since the second one is never evaluated. - - Args: - pattern (:obj:`str` | :obj:`Pattern`): The regex pattern. - """ - - __slots__ = ('pattern',) - data_filter = True - - def __init__(self, pattern: Union[str, Pattern]): - if isinstance(pattern, str): - pattern = re.compile(pattern) - pattern = cast(Pattern, pattern) - self.pattern: Pattern = pattern - self.name = f'Filters.regex({self.pattern})' - - def filter(self, message: Message) -> Optional[Dict[str, List[Match]]]: - """""" # remove method from docs - if message.text: - match = self.pattern.search(message.text) - if match: - return {'matches': [match]} - return {} - - class caption_regex(MessageFilter): - """ - Filters updates by searching for an occurrence of ``pattern`` in the message caption. - - This filter works similarly to :class:`Filters.regex`, with the only exception being that - it applies to the message caption instead of the text. - - Examples: - Use ``MessageHandler(Filters.photo & Filters.caption_regex(r'help'), callback)`` - to capture all photos with caption containing the word 'help'. - - Note: - This filter will not work on simple text messages, but only on media with caption. - - Args: - pattern (:obj:`str` | :obj:`Pattern`): The regex pattern. - """ - - __slots__ = ('pattern',) - data_filter = True - - def __init__(self, pattern: Union[str, Pattern]): - if isinstance(pattern, str): - pattern = re.compile(pattern) - pattern = cast(Pattern, pattern) - self.pattern: Pattern = pattern - self.name = f'Filters.caption_regex({self.pattern})' - - def filter(self, message: Message) -> Optional[Dict[str, List[Match]]]: - """""" # remove method from docs - if message.caption: - match = self.pattern.search(message.caption) - if match: - return {'matches': [match]} - return {} - - class _Reply(MessageFilter): - __slots__ = () - name = 'Filters.reply' - - def filter(self, message: Message) -> bool: - return bool(message.reply_to_message) - - reply = _Reply() - """Messages that are a reply to another message.""" - - class _Audio(MessageFilter): - __slots__ = () - name = 'Filters.audio' - - def filter(self, message: Message) -> bool: - return bool(message.audio) - - audio = _Audio() - """Messages that contain :class:`telegram.Audio`.""" - - class _Document(MessageFilter): - __slots__ = () - name = 'Filters.document' - - class category(MessageFilter): - """Filters documents by their category in the mime-type attribute. - - Note: - This Filter only filters by the mime_type of the document, - it doesn't check the validity of the document. - The user can manipulate the mime-type of a message and - send media with wrong types that don't fit to this handler. - - Example: - Filters.document.category('audio/') returns :obj:`True` for all types - of audio sent as file, for example 'audio/mpeg' or 'audio/x-wav'. - """ - - __slots__ = ('_category',) - - def __init__(self, category: Optional[str]): - """Initialize the category you want to filter - - Args: - category (str, optional): category of the media you want to filter - """ - self._category = category - self.name = f"Filters.document.category('{self._category}')" - - def filter(self, message: Message) -> bool: - """""" # remove method from docs - if message.document: - return message.document.mime_type.startswith(self._category) - return False - - application = category('application/') - audio = category('audio/') - image = category('image/') - video = category('video/') - text = category('text/') - - class mime_type(MessageFilter): - """This Filter filters documents by their mime-type attribute - - Note: - This Filter only filters by the mime_type of the document, - it doesn't check the validity of document. - The user can manipulate the mime-type of a message and - send media with wrong types that don't fit to this handler. - - Example: - ``Filters.document.mime_type('audio/mpeg')`` filters all audio in mp3 format. - """ - - __slots__ = ('mimetype',) - - def __init__(self, mimetype: Optional[str]): - self.mimetype = mimetype - self.name = f"Filters.document.mime_type('{self.mimetype}')" - - def filter(self, message: Message) -> bool: - """""" # remove method from docs - if message.document: - return message.document.mime_type == self.mimetype - return False - - apk = mime_type('application/vnd.android.package-archive') - doc = mime_type('application/msword') - docx = mime_type('application/vnd.openxmlformats-officedocument.wordprocessingml.document') - exe = mime_type('application/x-ms-dos-executable') - gif = mime_type('video/mp4') - jpg = mime_type('image/jpeg') - mp3 = mime_type('audio/mpeg') - pdf = mime_type('application/pdf') - py = mime_type('text/x-python') - svg = mime_type('image/svg+xml') - txt = mime_type('text/plain') - targz = mime_type('application/x-compressed-tar') - wav = mime_type('audio/x-wav') - xml = mime_type('application/xml') - zip = mime_type('application/zip') - - class file_extension(MessageFilter): - """This filter filters documents by their file ending/extension. - - Note: - * This Filter only filters by the file ending/extension of the document, - it doesn't check the validity of document. - * The user can manipulate the file extension of a document and - send media with wrong types that don't fit to this handler. - * Case insensitive by default, - you may change this with the flag ``case_sensitive=True``. - * Extension should be passed without leading dot - unless it's a part of the extension. - * Pass :obj:`None` to filter files with no extension, - i.e. without a dot in the filename. - - Example: - * ``Filters.document.file_extension("jpg")`` - filters files with extension ``".jpg"``. - * ``Filters.document.file_extension(".jpg")`` - filters files with extension ``"..jpg"``. - * ``Filters.document.file_extension("Dockerfile", case_sensitive=True)`` - filters files with extension ``".Dockerfile"`` minding the case. - * ``Filters.document.file_extension(None)`` - filters files without a dot in the filename. - """ - - __slots__ = ('_file_extension', 'is_case_sensitive') - - def __init__(self, file_extension: Optional[str], case_sensitive: bool = False): - """Initialize the extension you want to filter. - - Args: - file_extension (:obj:`str` | :obj:`None`): - media file extension you want to filter. - case_sensitive (:obj:bool, optional): - pass :obj:`True` to make the filter case sensitive. - Default: :obj:`False`. - """ - self.is_case_sensitive = case_sensitive - if file_extension is None: - self._file_extension = None - self.name = "Filters.document.file_extension(None)" - elif self.is_case_sensitive: - self._file_extension = f".{file_extension}" - self.name = ( - f"Filters.document.file_extension({file_extension!r}," - " case_sensitive=True)" - ) - else: - self._file_extension = f".{file_extension}".lower() - self.name = f"Filters.document.file_extension({file_extension.lower()!r})" - - def filter(self, message: Message) -> bool: - """""" # remove method from docs - if message.document is None: - return False - if self._file_extension is None: - return "." not in message.document.file_name - if self.is_case_sensitive: - filename = message.document.file_name - else: - filename = message.document.file_name.lower() - return filename.endswith(self._file_extension) - - def filter(self, message: Message) -> bool: - return bool(message.document) - - document = _Document() - """ - Subset for messages containing a document/file. - - Examples: - Use these filters like: ``Filters.document.mp3``, - ``Filters.document.mime_type("text/plain")`` etc. Or use just - ``Filters.document`` for all document messages. - - Attributes: - category: Filters documents by their category in the mime-type attribute - - Note: - This Filter only filters by the mime_type of the document, - it doesn't check the validity of the document. - The user can manipulate the mime-type of a message and - send media with wrong types that don't fit to this handler. - - Example: - ``Filters.document.category('audio/')`` filters all types - of audio sent as file, for example 'audio/mpeg' or 'audio/x-wav'. - application: Same as ``Filters.document.category("application")``. - audio: Same as ``Filters.document.category("audio")``. - image: Same as ``Filters.document.category("image")``. - video: Same as ``Filters.document.category("video")``. - text: Same as ``Filters.document.category("text")``. - mime_type: Filters documents by their mime-type attribute - - Note: - This Filter only filters by the mime_type of the document, - it doesn't check the validity of document. - - The user can manipulate the mime-type of a message and - send media with wrong types that don't fit to this handler. - - Example: - ``Filters.document.mime_type('audio/mpeg')`` filters all audio in mp3 format. - apk: Same as ``Filters.document.mime_type("application/vnd.android.package-archive")``. - doc: Same as ``Filters.document.mime_type("application/msword")``. - docx: Same as ``Filters.document.mime_type("application/vnd.openxmlformats-\ -officedocument.wordprocessingml.document")``. - exe: Same as ``Filters.document.mime_type("application/x-ms-dos-executable")``. - gif: Same as ``Filters.document.mime_type("video/mp4")``. - jpg: Same as ``Filters.document.mime_type("image/jpeg")``. - mp3: Same as ``Filters.document.mime_type("audio/mpeg")``. - pdf: Same as ``Filters.document.mime_type("application/pdf")``. - py: Same as ``Filters.document.mime_type("text/x-python")``. - svg: Same as ``Filters.document.mime_type("image/svg+xml")``. - txt: Same as ``Filters.document.mime_type("text/plain")``. - targz: Same as ``Filters.document.mime_type("application/x-compressed-tar")``. - wav: Same as ``Filters.document.mime_type("audio/x-wav")``. - xml: Same as ``Filters.document.mime_type("application/xml")``. - zip: Same as ``Filters.document.mime_type("application/zip")``. - file_extension: This filter filters documents by their file ending/extension. - - Note: - * This Filter only filters by the file ending/extension of the document, - it doesn't check the validity of document. - * The user can manipulate the file extension of a document and - send media with wrong types that don't fit to this handler. - * Case insensitive by default, - you may change this with the flag ``case_sensitive=True``. - * Extension should be passed without leading dot - unless it's a part of the extension. - * Pass :obj:`None` to filter files with no extension, - i.e. without a dot in the filename. - - Example: - * ``Filters.document.file_extension("jpg")`` - filters files with extension ``".jpg"``. - * ``Filters.document.file_extension(".jpg")`` - filters files with extension ``"..jpg"``. - * ``Filters.document.file_extension("Dockerfile", case_sensitive=True)`` - filters files with extension ``".Dockerfile"`` minding the case. - * ``Filters.document.file_extension(None)`` - filters files without a dot in the filename. - """ - - class _Animation(MessageFilter): - __slots__ = () - name = 'Filters.animation' - - def filter(self, message: Message) -> bool: - return bool(message.animation) - - animation = _Animation() - """Messages that contain :class:`telegram.Animation`.""" - - class _Photo(MessageFilter): - __slots__ = () - name = 'Filters.photo' - - def filter(self, message: Message) -> bool: - return bool(message.photo) - - photo = _Photo() - """Messages that contain :class:`telegram.PhotoSize`.""" - - class _Sticker(MessageFilter): - __slots__ = () - name = 'Filters.sticker' - - def filter(self, message: Message) -> bool: - return bool(message.sticker) - - sticker = _Sticker() - """Messages that contain :class:`telegram.Sticker`.""" - - class _Video(MessageFilter): - __slots__ = () - name = 'Filters.video' - - def filter(self, message: Message) -> bool: - return bool(message.video) - - video = _Video() - """Messages that contain :class:`telegram.Video`.""" - - class _Voice(MessageFilter): - __slots__ = () - name = 'Filters.voice' - - def filter(self, message: Message) -> bool: - return bool(message.voice) - - voice = _Voice() - """Messages that contain :class:`telegram.Voice`.""" - - class _VideoNote(MessageFilter): - __slots__ = () - name = 'Filters.video_note' - - def filter(self, message: Message) -> bool: - return bool(message.video_note) - - video_note = _VideoNote() - """Messages that contain :class:`telegram.VideoNote`.""" - - class _Contact(MessageFilter): - __slots__ = () - name = 'Filters.contact' - - def filter(self, message: Message) -> bool: - return bool(message.contact) - - contact = _Contact() - """Messages that contain :class:`telegram.Contact`.""" - - class _Location(MessageFilter): - __slots__ = () - name = 'Filters.location' - - def filter(self, message: Message) -> bool: - return bool(message.location) - - location = _Location() - """Messages that contain :class:`telegram.Location`.""" - - class _Venue(MessageFilter): - __slots__ = () - name = 'Filters.venue' - - def filter(self, message: Message) -> bool: - return bool(message.venue) - - venue = _Venue() - """Messages that contain :class:`telegram.Venue`.""" - - class _StatusUpdate(UpdateFilter): - """Subset for messages containing a status update. - - Examples: - Use these filters like: ``Filters.status_update.new_chat_members`` etc. Or use just - ``Filters.status_update`` for all status update messages. - - """ - - __slots__ = () - - class _NewChatMembers(MessageFilter): - __slots__ = () - name = 'Filters.status_update.new_chat_members' - - def filter(self, message: Message) -> bool: - return bool(message.new_chat_members) - - new_chat_members = _NewChatMembers() - """Messages that contain :attr:`telegram.Message.new_chat_members`.""" - - class _LeftChatMember(MessageFilter): - __slots__ = () - name = 'Filters.status_update.left_chat_member' - - def filter(self, message: Message) -> bool: - return bool(message.left_chat_member) - - left_chat_member = _LeftChatMember() - """Messages that contain :attr:`telegram.Message.left_chat_member`.""" - - class _NewChatTitle(MessageFilter): - __slots__ = () - name = 'Filters.status_update.new_chat_title' - - def filter(self, message: Message) -> bool: - return bool(message.new_chat_title) - - new_chat_title = _NewChatTitle() - """Messages that contain :attr:`telegram.Message.new_chat_title`.""" - - class _NewChatPhoto(MessageFilter): - __slots__ = () - name = 'Filters.status_update.new_chat_photo' - - def filter(self, message: Message) -> bool: - return bool(message.new_chat_photo) - - new_chat_photo = _NewChatPhoto() - """Messages that contain :attr:`telegram.Message.new_chat_photo`.""" - - class _DeleteChatPhoto(MessageFilter): - __slots__ = () - name = 'Filters.status_update.delete_chat_photo' - - def filter(self, message: Message) -> bool: - return bool(message.delete_chat_photo) - - delete_chat_photo = _DeleteChatPhoto() - """Messages that contain :attr:`telegram.Message.delete_chat_photo`.""" - - class _ChatCreated(MessageFilter): - __slots__ = () - name = 'Filters.status_update.chat_created' - - def filter(self, message: Message) -> bool: - return bool( - message.group_chat_created - or message.supergroup_chat_created - or message.channel_chat_created - ) - - chat_created = _ChatCreated() - """Messages that contain :attr:`telegram.Message.group_chat_created`, - :attr: `telegram.Message.supergroup_chat_created` or - :attr: `telegram.Message.channel_chat_created`.""" - - class _MessageAutoDeleteTimerChanged(MessageFilter): - __slots__ = () - name = 'MessageAutoDeleteTimerChanged' - - def filter(self, message: Message) -> bool: - return bool(message.message_auto_delete_timer_changed) - - message_auto_delete_timer_changed = _MessageAutoDeleteTimerChanged() - """Messages that contain :attr:`message_auto_delete_timer_changed`""" - - class _Migrate(MessageFilter): - __slots__ = () - name = 'Filters.status_update.migrate' - - def filter(self, message: Message) -> bool: - return bool(message.migrate_from_chat_id or message.migrate_to_chat_id) - - migrate = _Migrate() - """Messages that contain :attr:`telegram.Message.migrate_from_chat_id` or - :attr:`telegram.Message.migrate_to_chat_id`.""" - - class _PinnedMessage(MessageFilter): - __slots__ = () - name = 'Filters.status_update.pinned_message' - - def filter(self, message: Message) -> bool: - return bool(message.pinned_message) - - pinned_message = _PinnedMessage() - """Messages that contain :attr:`telegram.Message.pinned_message`.""" - - class _ConnectedWebsite(MessageFilter): - __slots__ = () - name = 'Filters.status_update.connected_website' - - def filter(self, message: Message) -> bool: - return bool(message.connected_website) - - connected_website = _ConnectedWebsite() - """Messages that contain :attr:`telegram.Message.connected_website`.""" - - class _ProximityAlertTriggered(MessageFilter): - __slots__ = () - name = 'Filters.status_update.proximity_alert_triggered' - - def filter(self, message: Message) -> bool: - return bool(message.proximity_alert_triggered) - - proximity_alert_triggered = _ProximityAlertTriggered() - """Messages that contain :attr:`telegram.Message.proximity_alert_triggered`.""" - - class _VoiceChatScheduled(MessageFilter): - __slots__ = () - name = 'Filters.status_update.voice_chat_scheduled' - - def filter(self, message: Message) -> bool: - return bool(message.voice_chat_scheduled) - - voice_chat_scheduled = _VoiceChatScheduled() - """Messages that contain :attr:`telegram.Message.voice_chat_scheduled`.""" - - class _VoiceChatStarted(MessageFilter): - __slots__ = () - name = 'Filters.status_update.voice_chat_started' - - def filter(self, message: Message) -> bool: - return bool(message.voice_chat_started) - - voice_chat_started = _VoiceChatStarted() - """Messages that contain :attr:`telegram.Message.voice_chat_started`.""" - - class _VoiceChatEnded(MessageFilter): - __slots__ = () - name = 'Filters.status_update.voice_chat_ended' - - def filter(self, message: Message) -> bool: - return bool(message.voice_chat_ended) - - voice_chat_ended = _VoiceChatEnded() - """Messages that contain :attr:`telegram.Message.voice_chat_ended`.""" - - class _VoiceChatParticipantsInvited(MessageFilter): - __slots__ = () - name = 'Filters.status_update.voice_chat_participants_invited' - - def filter(self, message: Message) -> bool: - return bool(message.voice_chat_participants_invited) - - voice_chat_participants_invited = _VoiceChatParticipantsInvited() - """Messages that contain :attr:`telegram.Message.voice_chat_participants_invited`.""" - - name = 'Filters.status_update' - - def filter(self, message: Update) -> bool: - return bool( - self.new_chat_members(message) - or self.left_chat_member(message) - or self.new_chat_title(message) - or self.new_chat_photo(message) - or self.delete_chat_photo(message) - or self.chat_created(message) - or self.message_auto_delete_timer_changed(message) - or self.migrate(message) - or self.pinned_message(message) - or self.connected_website(message) - or self.proximity_alert_triggered(message) - or self.voice_chat_scheduled(message) - or self.voice_chat_started(message) - or self.voice_chat_ended(message) - or self.voice_chat_participants_invited(message) - ) - - status_update = _StatusUpdate() - """Subset for messages containing a status update. - - Examples: - Use these filters like: ``Filters.status_update.new_chat_members`` etc. Or use just - ``Filters.status_update`` for all status update messages. - - Attributes: - chat_created: Messages that contain - :attr:`telegram.Message.group_chat_created`, - :attr:`telegram.Message.supergroup_chat_created` or - :attr:`telegram.Message.channel_chat_created`. - connected_website: Messages that contain - :attr:`telegram.Message.connected_website`. - delete_chat_photo: Messages that contain - :attr:`telegram.Message.delete_chat_photo`. - left_chat_member: Messages that contain - :attr:`telegram.Message.left_chat_member`. - migrate: Messages that contain - :attr:`telegram.Message.migrate_to_chat_id` or - :attr:`telegram.Message.migrate_from_chat_id`. - new_chat_members: Messages that contain - :attr:`telegram.Message.new_chat_members`. - new_chat_photo: Messages that contain - :attr:`telegram.Message.new_chat_photo`. - new_chat_title: Messages that contain - :attr:`telegram.Message.new_chat_title`. - message_auto_delete_timer_changed: Messages that contain - :attr:`message_auto_delete_timer_changed`. - - .. versionadded:: 13.4 - pinned_message: Messages that contain - :attr:`telegram.Message.pinned_message`. - proximity_alert_triggered: Messages that contain - :attr:`telegram.Message.proximity_alert_triggered`. - voice_chat_scheduled: Messages that contain - :attr:`telegram.Message.voice_chat_scheduled`. - - .. versionadded:: 13.5 - voice_chat_started: Messages that contain - :attr:`telegram.Message.voice_chat_started`. - - .. versionadded:: 13.4 - voice_chat_ended: Messages that contain - :attr:`telegram.Message.voice_chat_ended`. - - .. versionadded:: 13.4 - voice_chat_participants_invited: Messages that contain - :attr:`telegram.Message.voice_chat_participants_invited`. - - .. versionadded:: 13.4 - - """ - - class _Forwarded(MessageFilter): - __slots__ = () - name = 'Filters.forwarded' - - def filter(self, message: Message) -> bool: - return bool(message.forward_date) - - forwarded = _Forwarded() - """Messages that are forwarded.""" - - class _Game(MessageFilter): - __slots__ = () - name = 'Filters.game' - - def filter(self, message: Message) -> bool: - return bool(message.game) - - game = _Game() - """Messages that contain :class:`telegram.Game`.""" - - class entity(MessageFilter): - """ - Filters messages to only allow those which have a :class:`telegram.MessageEntity` - where their `type` matches `entity_type`. - - Examples: - Example ``MessageHandler(Filters.entity("hashtag"), callback_method)`` - - Args: - entity_type: Entity type to check for. All types can be found as constants - in :class:`telegram.MessageEntity`. - - """ - - __slots__ = ('entity_type',) - - def __init__(self, entity_type: str): - self.entity_type = entity_type - self.name = f'Filters.entity({self.entity_type})' - - def filter(self, message: Message) -> bool: - """""" # remove method from docs - return any(entity.type == self.entity_type for entity in message.entities) - - class caption_entity(MessageFilter): - """ - Filters media messages to only allow those which have a :class:`telegram.MessageEntity` - where their `type` matches `entity_type`. - - Examples: - Example ``MessageHandler(Filters.caption_entity("hashtag"), callback_method)`` - - Args: - entity_type: Caption Entity type to check for. All types can be found as constants - in :class:`telegram.MessageEntity`. - - """ - - __slots__ = ('entity_type',) - - def __init__(self, entity_type: str): - self.entity_type = entity_type - self.name = f'Filters.caption_entity({self.entity_type})' - - def filter(self, message: Message) -> bool: - """""" # remove method from docs - return any(entity.type == self.entity_type for entity in message.caption_entities) - - class _Private(MessageFilter): - __slots__ = () - name = 'Filters.private' - - def filter(self, message: Message) -> bool: - warnings.warn( - 'Filters.private is deprecated. Use Filters.chat_type.private instead.', - TelegramDeprecationWarning, - stacklevel=2, - ) - return message.chat.type == Chat.PRIVATE - - private = _Private() - """ - Messages sent in a private chat. - - Note: - DEPRECATED. Use - :attr:`telegram.ext.Filters.chat_type.private` instead. - """ - - class _Group(MessageFilter): - __slots__ = () - name = 'Filters.group' - - def filter(self, message: Message) -> bool: - warnings.warn( - 'Filters.group is deprecated. Use Filters.chat_type.groups instead.', - TelegramDeprecationWarning, - stacklevel=2, - ) - return message.chat.type in [Chat.GROUP, Chat.SUPERGROUP] - - group = _Group() - """ - Messages sent in a group or a supergroup chat. - - Note: - DEPRECATED. Use - :attr:`telegram.ext.Filters.chat_type.groups` instead. - """ - - class _ChatType(MessageFilter): - __slots__ = () - name = 'Filters.chat_type' - - class _Channel(MessageFilter): - __slots__ = () - name = 'Filters.chat_type.channel' - - def filter(self, message: Message) -> bool: - return message.chat.type == Chat.CHANNEL - - channel = _Channel() - - class _Group(MessageFilter): - __slots__ = () - name = 'Filters.chat_type.group' - - def filter(self, message: Message) -> bool: - return message.chat.type == Chat.GROUP - - group = _Group() - - class _SuperGroup(MessageFilter): - __slots__ = () - name = 'Filters.chat_type.supergroup' - - def filter(self, message: Message) -> bool: - return message.chat.type == Chat.SUPERGROUP - - supergroup = _SuperGroup() - - class _Groups(MessageFilter): - __slots__ = () - name = 'Filters.chat_type.groups' - - def filter(self, message: Message) -> bool: - return message.chat.type in [Chat.GROUP, Chat.SUPERGROUP] - - groups = _Groups() - - class _Private(MessageFilter): - __slots__ = () - name = 'Filters.chat_type.private' - - def filter(self, message: Message) -> bool: - return message.chat.type == Chat.PRIVATE - - private = _Private() - - def filter(self, message: Message) -> bool: - return bool(message.chat.type) - - chat_type = _ChatType() - """Subset for filtering the type of chat. - - Examples: - Use these filters like: ``Filters.chat_type.channel`` or - ``Filters.chat_type.supergroup`` etc. Or use just ``Filters.chat_type`` for all - chat types. - - Attributes: - channel: Updates from channel - group: Updates from group - supergroup: Updates from supergroup - groups: Updates from group *or* supergroup - private: Updates sent in private chat - """ - - class _ChatUserBaseFilter(MessageFilter, ABC): - __slots__ = ( - 'chat_id_name', - 'username_name', - 'allow_empty', - '__lock', - '_chat_ids', - '_usernames', - ) - - def __init__( - self, - chat_id: SLT[int] = None, - username: SLT[str] = None, - allow_empty: bool = False, - ): - self.chat_id_name = 'chat_id' - self.username_name = 'username' - self.allow_empty = allow_empty - self.__lock = Lock() - - self._chat_ids: Set[int] = set() - self._usernames: Set[str] = set() - - self._set_chat_ids(chat_id) - self._set_usernames(username) - - @abstractmethod - def get_chat_or_user(self, message: Message) -> Union[Chat, User, None]: - ... - - @staticmethod - def _parse_chat_id(chat_id: SLT[int]) -> Set[int]: - if chat_id is None: - return set() - if isinstance(chat_id, int): - return {chat_id} - return set(chat_id) - - @staticmethod - def _parse_username(username: SLT[str]) -> Set[str]: - if username is None: - return set() - if isinstance(username, str): - return {username[1:] if username.startswith('@') else username} - return {chat[1:] if chat.startswith('@') else chat for chat in username} - - def _set_chat_ids(self, chat_id: SLT[int]) -> None: - with self.__lock: - if chat_id and self._usernames: - raise RuntimeError( - f"Can't set {self.chat_id_name} in conjunction with (already set) " - f"{self.username_name}s." - ) - self._chat_ids = self._parse_chat_id(chat_id) - - def _set_usernames(self, username: SLT[str]) -> None: - with self.__lock: - if username and self._chat_ids: - raise RuntimeError( - f"Can't set {self.username_name} in conjunction with (already set) " - f"{self.chat_id_name}s." - ) - self._usernames = self._parse_username(username) - - @property - def chat_ids(self) -> FrozenSet[int]: - with self.__lock: - return frozenset(self._chat_ids) - - @chat_ids.setter - def chat_ids(self, chat_id: SLT[int]) -> None: - self._set_chat_ids(chat_id) - - @property - def usernames(self) -> FrozenSet[str]: - with self.__lock: - return frozenset(self._usernames) - - @usernames.setter - def usernames(self, username: SLT[str]) -> None: - self._set_usernames(username) - - def add_usernames(self, username: SLT[str]) -> None: - with self.__lock: - if self._chat_ids: - raise RuntimeError( - f"Can't set {self.username_name} in conjunction with (already set) " - f"{self.chat_id_name}s." - ) - - parsed_username = self._parse_username(username) - self._usernames |= parsed_username - - def add_chat_ids(self, chat_id: SLT[int]) -> None: - with self.__lock: - if self._usernames: - raise RuntimeError( - f"Can't set {self.chat_id_name} in conjunction with (already set) " - f"{self.username_name}s." - ) - - parsed_chat_id = self._parse_chat_id(chat_id) - - self._chat_ids |= parsed_chat_id - - def remove_usernames(self, username: SLT[str]) -> None: - with self.__lock: - if self._chat_ids: - raise RuntimeError( - f"Can't set {self.username_name} in conjunction with (already set) " - f"{self.chat_id_name}s." - ) - - parsed_username = self._parse_username(username) - self._usernames -= parsed_username - - def remove_chat_ids(self, chat_id: SLT[int]) -> None: - with self.__lock: - if self._usernames: - raise RuntimeError( - f"Can't set {self.chat_id_name} in conjunction with (already set) " - f"{self.username_name}s." - ) - parsed_chat_id = self._parse_chat_id(chat_id) - self._chat_ids -= parsed_chat_id - - def filter(self, message: Message) -> bool: - """""" # remove method from docs - chat_or_user = self.get_chat_or_user(message) - if chat_or_user: - if self.chat_ids: - return chat_or_user.id in self.chat_ids - if self.usernames: - return bool(chat_or_user.username and chat_or_user.username in self.usernames) - return self.allow_empty - return False - - @property - def name(self) -> str: - return ( - f'Filters.{self.__class__.__name__}(' - f'{", ".join(str(s) for s in (self.usernames or self.chat_ids))})' - ) - - @name.setter - def name(self, name: str) -> NoReturn: - raise RuntimeError(f'Cannot set name for Filters.{self.__class__.__name__}') - - class user(_ChatUserBaseFilter): - # pylint: disable=W0235 - """Filters messages to allow only those which are from specified user ID(s) or - username(s). - - Examples: - ``MessageHandler(Filters.user(1234), callback_method)`` - - Warning: - :attr:`user_ids` will give a *copy* of the saved user ids as :class:`frozenset`. This - is to ensure thread safety. To add/remove a user, you should use :meth:`add_usernames`, - :meth:`add_user_ids`, :meth:`remove_usernames` and :meth:`remove_user_ids`. Only update - the entire set by ``filter.user_ids/usernames = new_set``, if you are entirely sure - that it is not causing race conditions, as this will complete replace the current set - of allowed users. - - Args: - user_id(:class:`telegram.utils.types.SLT[int]`, optional): - Which user ID(s) to allow through. - username(:class:`telegram.utils.types.SLT[str]`, optional): - Which username(s) to allow through. Leading ``'@'`` s in usernames will be - discarded. - allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no user - is specified in :attr:`user_ids` and :attr:`usernames`. Defaults to :obj:`False` - - Raises: - RuntimeError: If user_id and username are both present. - - Attributes: - user_ids(set(:obj:`int`), optional): Which user ID(s) to allow through. - usernames(set(:obj:`str`), optional): Which username(s) (without leading ``'@'``) to - allow through. - allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no user - is specified in :attr:`user_ids` and :attr:`usernames`. - - """ - - __slots__ = () - - def __init__( - self, - user_id: SLT[int] = None, - username: SLT[str] = None, - allow_empty: bool = False, - ): - super().__init__(chat_id=user_id, username=username, allow_empty=allow_empty) - self.chat_id_name = 'user_id' - - def get_chat_or_user(self, message: Message) -> Optional[User]: - return message.from_user - - @property - def user_ids(self) -> FrozenSet[int]: - return self.chat_ids - - @user_ids.setter - def user_ids(self, user_id: SLT[int]) -> None: - self.chat_ids = user_id # type: ignore[assignment] - - def add_usernames(self, username: SLT[str]) -> None: - """ - Add one or more users to the allowed usernames. - - Args: - username(:class:`telegram.utils.types.SLT[str]`, optional): - Which username(s) to allow through. - Leading ``'@'`` s in usernames will be discarded. - """ - return super().add_usernames(username) - - def add_user_ids(self, user_id: SLT[int]) -> None: - """ - Add one or more users to the allowed user ids. - - Args: - user_id(:class:`telegram.utils.types.SLT[int]`, optional): - Which user ID(s) to allow through. - """ - return super().add_chat_ids(user_id) - - def remove_usernames(self, username: SLT[str]) -> None: - """ - Remove one or more users from allowed usernames. - - Args: - username(:class:`telegram.utils.types.SLT[str]`, optional): - Which username(s) to disallow through. - Leading ``'@'`` s in usernames will be discarded. - """ - return super().remove_usernames(username) - - def remove_user_ids(self, user_id: SLT[int]) -> None: - """ - Remove one or more users from allowed user ids. - - Args: - user_id(:class:`telegram.utils.types.SLT[int]`, optional): - Which user ID(s) to disallow through. - """ - return super().remove_chat_ids(user_id) - - class via_bot(_ChatUserBaseFilter): - # pylint: disable=W0235 - """Filters messages to allow only those which are from specified via_bot ID(s) or - username(s). - - Examples: - ``MessageHandler(Filters.via_bot(1234), callback_method)`` - - Warning: - :attr:`bot_ids` will give a *copy* of the saved bot ids as :class:`frozenset`. This - is to ensure thread safety. To add/remove a bot, you should use :meth:`add_usernames`, - :meth:`add_bot_ids`, :meth:`remove_usernames` and :meth:`remove_bot_ids`. Only update - the entire set by ``filter.bot_ids/usernames = new_set``, if you are entirely sure - that it is not causing race conditions, as this will complete replace the current set - of allowed bots. - - Args: - bot_id(:class:`telegram.utils.types.SLT[int]`, optional): - Which bot ID(s) to allow through. - username(:class:`telegram.utils.types.SLT[str]`, optional): - Which username(s) to allow through. Leading ``'@'`` s in usernames will be - discarded. - allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no user - is specified in :attr:`bot_ids` and :attr:`usernames`. Defaults to :obj:`False` - - Raises: - RuntimeError: If bot_id and username are both present. - - Attributes: - bot_ids(set(:obj:`int`), optional): Which bot ID(s) to allow through. - usernames(set(:obj:`str`), optional): Which username(s) (without leading ``'@'``) to - allow through. - allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no bot - is specified in :attr:`bot_ids` and :attr:`usernames`. - - """ - - __slots__ = () - - def __init__( - self, - bot_id: SLT[int] = None, - username: SLT[str] = None, - allow_empty: bool = False, - ): - super().__init__(chat_id=bot_id, username=username, allow_empty=allow_empty) - self.chat_id_name = 'bot_id' - - def get_chat_or_user(self, message: Message) -> Optional[User]: - return message.via_bot - - @property - def bot_ids(self) -> FrozenSet[int]: - return self.chat_ids - - @bot_ids.setter - def bot_ids(self, bot_id: SLT[int]) -> None: - self.chat_ids = bot_id # type: ignore[assignment] - - def add_usernames(self, username: SLT[str]) -> None: - """ - Add one or more users to the allowed usernames. - - Args: - username(:class:`telegram.utils.types.SLT[str]`, optional): - Which username(s) to allow through. - Leading ``'@'`` s in usernames will be discarded. - """ - return super().add_usernames(username) - - def add_bot_ids(self, bot_id: SLT[int]) -> None: - """ - - Add one or more users to the allowed user ids. - - Args: - bot_id(:class:`telegram.utils.types.SLT[int]`, optional): - Which bot ID(s) to allow through. - """ - return super().add_chat_ids(bot_id) - - def remove_usernames(self, username: SLT[str]) -> None: - """ - Remove one or more users from allowed usernames. - - Args: - username(:class:`telegram.utils.types.SLT[str]`, optional): - Which username(s) to disallow through. - Leading ``'@'`` s in usernames will be discarded. - """ - return super().remove_usernames(username) - - def remove_bot_ids(self, bot_id: SLT[int]) -> None: - """ - Remove one or more users from allowed user ids. - - Args: - bot_id(:class:`telegram.utils.types.SLT[int]`, optional): - Which bot ID(s) to disallow through. - """ - return super().remove_chat_ids(bot_id) - - class chat(_ChatUserBaseFilter): - # pylint: disable=W0235 - """Filters messages to allow only those which are from a specified chat ID or username. - - Examples: - ``MessageHandler(Filters.chat(-1234), callback_method)`` - - Warning: - :attr:`chat_ids` will give a *copy* of the saved chat ids as :class:`frozenset`. This - is to ensure thread safety. To add/remove a chat, you should use :meth:`add_usernames`, - :meth:`add_chat_ids`, :meth:`remove_usernames` and :meth:`remove_chat_ids`. Only update - the entire set by ``filter.chat_ids/usernames = new_set``, if you are entirely sure - that it is not causing race conditions, as this will complete replace the current set - of allowed chats. - - Args: - chat_id(:class:`telegram.utils.types.SLT[int]`, optional): - Which chat ID(s) to allow through. - username(:class:`telegram.utils.types.SLT[str]`, optional): - Which username(s) to allow through. - Leading ``'@'`` s in usernames will be discarded. - allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no chat - is specified in :attr:`chat_ids` and :attr:`usernames`. Defaults to :obj:`False` - - Raises: - RuntimeError: If chat_id and username are both present. - - Attributes: - chat_ids(set(:obj:`int`), optional): Which chat ID(s) to allow through. - usernames(set(:obj:`str`), optional): Which username(s) (without leading ``'@'``) to - allow through. - allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no chat - is specified in :attr:`chat_ids` and :attr:`usernames`. - - """ - - __slots__ = () - - def get_chat_or_user(self, message: Message) -> Optional[Chat]: - return message.chat - - def add_usernames(self, username: SLT[str]) -> None: - """ - Add one or more chats to the allowed usernames. - - Args: - username(:class:`telegram.utils.types.SLT[str]`, optional): - Which username(s) to allow through. - Leading ``'@'`` s in usernames will be discarded. - """ - return super().add_usernames(username) - - def add_chat_ids(self, chat_id: SLT[int]) -> None: - """ - Add one or more chats to the allowed chat ids. - - Args: - chat_id(:class:`telegram.utils.types.SLT[int]`, optional): - Which chat ID(s) to allow through. - """ - return super().add_chat_ids(chat_id) - - def remove_usernames(self, username: SLT[str]) -> None: - """ - Remove one or more chats from allowed usernames. - - Args: - username(:class:`telegram.utils.types.SLT[str]`, optional): - Which username(s) to disallow through. - Leading ``'@'`` s in usernames will be discarded. - """ - return super().remove_usernames(username) - - def remove_chat_ids(self, chat_id: SLT[int]) -> None: - """ - Remove one or more chats from allowed chat ids. - - Args: - chat_id(:class:`telegram.utils.types.SLT[int]`, optional): - Which chat ID(s) to disallow through. - """ - return super().remove_chat_ids(chat_id) - - class forwarded_from(_ChatUserBaseFilter): - # pylint: disable=W0235 - """Filters messages to allow only those which are forwarded from the specified chat ID(s) - or username(s) based on :attr:`telegram.Message.forward_from` and - :attr:`telegram.Message.forward_from_chat`. - - .. versionadded:: 13.5 - - Examples: - ``MessageHandler(Filters.forwarded_from(chat_id=1234), callback_method)`` - - Note: - When a user has disallowed adding a link to their account while forwarding their - messages, this filter will *not* work since both - :attr:`telegram.Message.forwarded_from` and - :attr:`telegram.Message.forwarded_from_chat` are :obj:`None`. However, this behaviour - is undocumented and might be changed by Telegram. - - Warning: - :attr:`chat_ids` will give a *copy* of the saved chat ids as :class:`frozenset`. This - is to ensure thread safety. To add/remove a chat, you should use :meth:`add_usernames`, - :meth:`add_chat_ids`, :meth:`remove_usernames` and :meth:`remove_chat_ids`. Only update - the entire set by ``filter.chat_ids/usernames = new_set``, if you are entirely sure - that it is not causing race conditions, as this will complete replace the current set - of allowed chats. - - Args: - chat_id(:class:`telegram.utils.types.SLT[int]`, optional): - Which chat/user ID(s) to allow through. - username(:class:`telegram.utils.types.SLT[str]`, optional): - Which username(s) to allow through. Leading ``'@'`` s in usernames will be - discarded. - allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no chat - is specified in :attr:`chat_ids` and :attr:`usernames`. Defaults to :obj:`False`. - - Raises: - RuntimeError: If both chat_id and username are present. - - Attributes: - chat_ids(set(:obj:`int`), optional): Which chat/user ID(s) to allow through. - usernames(set(:obj:`str`), optional): Which username(s) (without leading ``'@'``) to - allow through. - allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no chat - is specified in :attr:`chat_ids` and :attr:`usernames`. - """ - - __slots__ = () - - def get_chat_or_user(self, message: Message) -> Union[User, Chat, None]: - return message.forward_from or message.forward_from_chat - - def add_usernames(self, username: SLT[str]) -> None: - """ - Add one or more chats to the allowed usernames. - - Args: - username(:class:`telegram.utils.types.SLT[str]`, optional): - Which username(s) to allow through. - Leading ``'@'`` s in usernames will be discarded. - """ - return super().add_usernames(username) - - def add_chat_ids(self, chat_id: SLT[int]) -> None: - """ - Add one or more chats to the allowed chat ids. - - Args: - chat_id(:class:`telegram.utils.types.SLT[int]`, optional): - Which chat/user ID(s) to allow through. - """ - return super().add_chat_ids(chat_id) - - def remove_usernames(self, username: SLT[str]) -> None: - """ - Remove one or more chats from allowed usernames. - - Args: - username(:class:`telegram.utils.types.SLT[str]`, optional): - Which username(s) to disallow through. - Leading ``'@'`` s in usernames will be discarded. - """ - return super().remove_usernames(username) - - def remove_chat_ids(self, chat_id: SLT[int]) -> None: - """ - Remove one or more chats from allowed chat ids. - - Args: - chat_id(:class:`telegram.utils.types.SLT[int]`, optional): - Which chat/user ID(s) to disallow through. - """ - return super().remove_chat_ids(chat_id) - - class sender_chat(_ChatUserBaseFilter): - # pylint: disable=W0235 - """Filters messages to allow only those which are from a specified sender chats chat ID or - username. - - Examples: - * To filter for messages forwarded to a discussion group from a channel with ID - ``-1234``, use ``MessageHandler(Filters.sender_chat(-1234), callback_method)``. - * To filter for messages of anonymous admins in a super group with username - ``@anonymous``, use - ``MessageHandler(Filters.sender_chat(username='anonymous'), callback_method)``. - * To filter for messages forwarded to a discussion group from *any* channel, use - ``MessageHandler(Filters.sender_chat.channel, callback_method)``. - * To filter for messages of anonymous admins in *any* super group, use - ``MessageHandler(Filters.sender_chat.super_group, callback_method)``. - - Note: - Remember, ``sender_chat`` is also set for messages in a channel as the channel itself, - so when your bot is an admin in a channel and the linked discussion group, you would - receive the message twice (once from inside the channel, once inside the discussion - group). - - Warning: - :attr:`chat_ids` will return a *copy* of the saved chat ids as :class:`frozenset`. This - is to ensure thread safety. To add/remove a chat, you should use :meth:`add_usernames`, - :meth:`add_chat_ids`, :meth:`remove_usernames` and :meth:`remove_chat_ids`. Only update - the entire set by ``filter.chat_ids/usernames = new_set``, if you are entirely sure - that it is not causing race conditions, as this will complete replace the current set - of allowed chats. - - Args: - chat_id(:class:`telegram.utils.types.SLT[int]`, optional): - Which sender chat chat ID(s) to allow through. - username(:class:`telegram.utils.types.SLT[str]`, optional): - Which sender chat username(s) to allow through. - Leading ``'@'`` s in usernames will be discarded. - allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no sender - chat is specified in :attr:`chat_ids` and :attr:`usernames`. Defaults to - :obj:`False` - - Raises: - RuntimeError: If both chat_id and username are present. - - Attributes: - chat_ids(set(:obj:`int`), optional): Which sender chat chat ID(s) to allow through. - usernames(set(:obj:`str`), optional): Which sender chat username(s) (without leading - ``'@'``) to allow through. - allow_empty(:obj:`bool`, optional): Whether updates should be processed, if no sender - chat is specified in :attr:`chat_ids` and :attr:`usernames`. - super_group: Messages whose sender chat is a super group. - - Examples: - ``Filters.sender_chat.supergroup`` - channel: Messages whose sender chat is a channel. - - Examples: - ``Filters.sender_chat.channel`` - - """ - - __slots__ = () - - def get_chat_or_user(self, message: Message) -> Optional[Chat]: - return message.sender_chat - - def add_usernames(self, username: SLT[str]) -> None: - """ - Add one or more sender chats to the allowed usernames. - - Args: - username(:class:`telegram.utils.types.SLT[str]`, optional): - Which sender chat username(s) to allow through. - Leading ``'@'`` s in usernames will be discarded. - """ - return super().add_usernames(username) - - def add_chat_ids(self, chat_id: SLT[int]) -> None: - """ - Add one or more sender chats to the allowed chat ids. - - Args: - chat_id(:class:`telegram.utils.types.SLT[int]`, optional): - Which sender chat ID(s) to allow through. - """ - return super().add_chat_ids(chat_id) - - def remove_usernames(self, username: SLT[str]) -> None: - """ - Remove one or more sender chats from allowed usernames. - - Args: - username(:class:`telegram.utils.types.SLT[str]`, optional): - Which sender chat username(s) to disallow through. - Leading ``'@'`` s in usernames will be discarded. - """ - return super().remove_usernames(username) - - def remove_chat_ids(self, chat_id: SLT[int]) -> None: - """ - Remove one or more sender chats from allowed chat ids. - - Args: - chat_id(:class:`telegram.utils.types.SLT[int]`, optional): - Which sender chat ID(s) to disallow through. - """ - return super().remove_chat_ids(chat_id) - - class _SuperGroup(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - if message.sender_chat: - return message.sender_chat.type == Chat.SUPERGROUP - return False - - class _Channel(MessageFilter): - __slots__ = () - - def filter(self, message: Message) -> bool: - if message.sender_chat: - return message.sender_chat.type == Chat.CHANNEL - return False - - super_group = _SuperGroup() - channel = _Channel() - - class _Invoice(MessageFilter): - __slots__ = () - name = 'Filters.invoice' - - def filter(self, message: Message) -> bool: - return bool(message.invoice) - - invoice = _Invoice() - """Messages that contain :class:`telegram.Invoice`.""" - - class _SuccessfulPayment(MessageFilter): - __slots__ = () - name = 'Filters.successful_payment' - - def filter(self, message: Message) -> bool: - return bool(message.successful_payment) - - successful_payment = _SuccessfulPayment() - """Messages that confirm a :class:`telegram.SuccessfulPayment`.""" - - class _PassportData(MessageFilter): - __slots__ = () - name = 'Filters.passport_data' - - def filter(self, message: Message) -> bool: - return bool(message.passport_data) - - passport_data = _PassportData() - """Messages that contain a :class:`telegram.PassportData`""" - - class _Poll(MessageFilter): - __slots__ = () - name = 'Filters.poll' - - def filter(self, message: Message) -> bool: - return bool(message.poll) - - poll = _Poll() - """Messages that contain a :class:`telegram.Poll`.""" - - class _Dice(_DiceEmoji): - __slots__ = () - dice = _DiceEmoji('🎲', 'dice') - darts = _DiceEmoji('🎯', 'darts') - basketball = _DiceEmoji('🏀', 'basketball') - football = _DiceEmoji('⚽') - slot_machine = _DiceEmoji('🎰') - bowling = _DiceEmoji('🎳', 'bowling') - - dice = _Dice() - """Dice Messages. If an integer or a list of integers is passed, it filters messages to only - allow those whose dice value is appearing in the given list. - - Examples: - To allow any dice message, simply use - ``MessageHandler(Filters.dice, callback_method)``. - - To allow only dice messages with the emoji 🎲, but any value, use - ``MessageHandler(Filters.dice.dice, callback_method)``. - - To allow only dice messages with the emoji 🎯 and with value 6, use - ``MessageHandler(Filters.dice.darts(6), callback_method)``. - - To allow only dice messages with the emoji ⚽ and with value 5 `or` 6, use - ``MessageHandler(Filters.dice.football([5, 6]), callback_method)``. - - Note: - Dice messages don't have text. If you want to filter either text or dice messages, use - ``Filters.text | Filters.dice``. - - Args: - update (:class:`telegram.utils.types.SLT[int]`, optional): - Which values to allow. If not specified, will allow any dice message. - - Attributes: - dice: Dice messages with the emoji 🎲. Passing a list of integers is supported just as for - :attr:`Filters.dice`. - darts: Dice messages with the emoji 🎯. Passing a list of integers is supported just as for - :attr:`Filters.dice`. - basketball: Dice messages with the emoji 🏀. Passing a list of integers is supported just - as for :attr:`Filters.dice`. - football: Dice messages with the emoji ⚽. Passing a list of integers is supported just - as for :attr:`Filters.dice`. - slot_machine: Dice messages with the emoji 🎰. Passing a list of integers is supported just - as for :attr:`Filters.dice`. - bowling: Dice messages with the emoji 🎳. Passing a list of integers is supported just - as for :attr:`Filters.dice`. - - .. versionadded:: 13.4 - - """ - - class language(MessageFilter): - """Filters messages to only allow those which are from users with a certain language code. - - Note: - According to official Telegram API documentation, not every single user has the - `language_code` attribute. Do not count on this filter working on all users. - - Examples: - ``MessageHandler(Filters.language("en"), callback_method)`` - - Args: - lang (:class:`telegram.utils.types.SLT[str]`): - Which language code(s) to allow through. - This will be matched using ``.startswith`` meaning that - 'en' will match both 'en_US' and 'en_GB'. - - """ - - __slots__ = ('lang',) - - def __init__(self, lang: SLT[str]): - if isinstance(lang, str): - lang = cast(str, lang) - self.lang = [lang] - else: - lang = cast(List[str], lang) - self.lang = lang - self.name = f'Filters.language({self.lang})' - - def filter(self, message: Message) -> bool: - """""" # remove method from docs - return bool( - message.from_user.language_code - and any(message.from_user.language_code.startswith(x) for x in self.lang) - ) - - class _Attachment(MessageFilter): - __slots__ = () - - name = 'Filters.attachment' - - def filter(self, message: Message) -> bool: - return bool(message.effective_attachment) - - attachment = _Attachment() - """Messages that contain :meth:`telegram.Message.effective_attachment`. - - - .. versionadded:: 13.6""" - - class _UpdateType(UpdateFilter): - __slots__ = () - name = 'Filters.update' - - class _Message(UpdateFilter): - __slots__ = () - name = 'Filters.update.message' - - def filter(self, update: Update) -> bool: - return update.message is not None - - message = _Message() - - class _EditedMessage(UpdateFilter): - __slots__ = () - name = 'Filters.update.edited_message' - - def filter(self, update: Update) -> bool: - return update.edited_message is not None - - edited_message = _EditedMessage() - - class _Messages(UpdateFilter): - __slots__ = () - name = 'Filters.update.messages' - - def filter(self, update: Update) -> bool: - return update.message is not None or update.edited_message is not None - - messages = _Messages() - - class _ChannelPost(UpdateFilter): - __slots__ = () - name = 'Filters.update.channel_post' - - def filter(self, update: Update) -> bool: - return update.channel_post is not None - - channel_post = _ChannelPost() - - class _EditedChannelPost(UpdateFilter): - __slots__ = () - name = 'Filters.update.edited_channel_post' - - def filter(self, update: Update) -> bool: - return update.edited_channel_post is not None - - edited_channel_post = _EditedChannelPost() - - class _ChannelPosts(UpdateFilter): - __slots__ = () - name = 'Filters.update.channel_posts' - - def filter(self, update: Update) -> bool: - return update.channel_post is not None or update.edited_channel_post is not None - - channel_posts = _ChannelPosts() - - def filter(self, update: Update) -> bool: - return bool(self.messages(update) or self.channel_posts(update)) - - update = _UpdateType() - """Subset for filtering the type of update. - - Examples: - Use these filters like: ``Filters.update.message`` or - ``Filters.update.channel_posts`` etc. Or use just ``Filters.update`` for all - types. - - Attributes: - message: Updates with :attr:`telegram.Update.message` - edited_message: Updates with :attr:`telegram.Update.edited_message` - messages: Updates with either :attr:`telegram.Update.message` or - :attr:`telegram.Update.edited_message` - channel_post: Updates with :attr:`telegram.Update.channel_post` - edited_channel_post: Updates with - :attr:`telegram.Update.edited_channel_post` - channel_posts: Updates with either :attr:`telegram.Update.channel_post` or - :attr:`telegram.Update.edited_channel_post` - """ diff --git a/venv/lib/python3.8/site-packages/telegram/ext/handler.py b/venv/lib/python3.8/site-packages/telegram/ext/handler.py deleted file mode 100644 index befaf41..0000000 --- a/venv/lib/python3.8/site-packages/telegram/ext/handler.py +++ /dev/null @@ -1,260 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the base class for handlers as used by the Dispatcher.""" -from abc import ABC, abstractmethod -from typing import TYPE_CHECKING, Any, Callable, Dict, Optional, TypeVar, Union, Generic -from sys import version_info as py_ver - -from telegram.utils.deprecate import set_new_attribute_deprecated - -from telegram import Update -from telegram.ext.utils.promise import Promise -from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE -from telegram.ext.utils.types import CCT - -if TYPE_CHECKING: - from telegram.ext import Dispatcher - -RT = TypeVar('RT') -UT = TypeVar('UT') - - -class Handler(Generic[UT, CCT], ABC): - """The base class for all update handlers. Create custom handlers by inheriting from it. - - Note: - :attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you - can use to keep any data in will be sent to the :attr:`callback` function. Related to - either the user or the chat that the update was sent in. For each update from the same user - or in the same chat, it will be the same ``dict``. - - Note that this is DEPRECATED, and you should use context based callbacks. See - https://git.io/fxJuV for more info. - - Warning: - When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - Args: - callback (:obj:`callable`): The callback function for this handler. Will be called when - :attr:`check_update` has determined that an update should be processed by this handler. - Callback signature for context based API: - - ``def callback(update: Update, context: CallbackContext)`` - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``update_queue`` will be passed to the callback function. It will be the ``Queue`` - instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher` - that contains new updates which can be used to insert updates. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``job_queue`` will be passed to the callback function. It will be a - :class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater` - which can be used to schedule new jobs. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``user_data`` will be passed to the callback function. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``chat_data`` will be passed to the callback function. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - run_async (:obj:`bool`): Determines whether the callback will run asynchronously. - Defaults to :obj:`False`. - - Attributes: - callback (:obj:`callable`): The callback function for this handler. - pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be - passed to the callback function. - pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to - the callback function. - pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to - the callback function. - pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to - the callback function. - run_async (:obj:`bool`): Determines whether the callback will run asynchronously. - - """ - - # Apparently Py 3.7 and below have '__dict__' in ABC - if py_ver < (3, 7): - __slots__ = ( - 'callback', - 'pass_update_queue', - 'pass_job_queue', - 'pass_user_data', - 'pass_chat_data', - 'run_async', - ) - else: - __slots__ = ( - 'callback', # type: ignore[assignment] - 'pass_update_queue', - 'pass_job_queue', - 'pass_user_data', - 'pass_chat_data', - 'run_async', - '__dict__', - ) - - def __init__( - self, - callback: Callable[[UT, CCT], RT], - pass_update_queue: bool = False, - pass_job_queue: bool = False, - pass_user_data: bool = False, - pass_chat_data: bool = False, - run_async: Union[bool, DefaultValue] = DEFAULT_FALSE, - ): - self.callback = callback - self.pass_update_queue = pass_update_queue - self.pass_job_queue = pass_job_queue - self.pass_user_data = pass_user_data - self.pass_chat_data = pass_chat_data - self.run_async = run_async - - def __setattr__(self, key: str, value: object) -> None: - # See comment on BaseFilter to know why this was done. - if key.startswith('__'): - key = f"_{self.__class__.__name__}{key}" - if issubclass(self.__class__, Handler) and not self.__class__.__module__.startswith( - 'telegram.ext.' - ): - object.__setattr__(self, key, value) - return - set_new_attribute_deprecated(self, key, value) - - @abstractmethod - def check_update(self, update: object) -> Optional[Union[bool, object]]: - """ - This method is called to determine if an update should be handled by - this handler instance. It should always be overridden. - - Note: - Custom updates types can be handled by the dispatcher. Therefore, an implementation of - this method should always check the type of :attr:`update`. - - Args: - update (:obj:`str` | :class:`telegram.Update`): The update to be tested. - - Returns: - Either :obj:`None` or :obj:`False` if the update should not be handled. Otherwise an - object that will be passed to :meth:`handle_update` and - :meth:`collect_additional_context` when the update gets handled. - - """ - - def handle_update( - self, - update: UT, - dispatcher: 'Dispatcher', - check_result: object, - context: CCT = None, - ) -> Union[RT, Promise]: - """ - This method is called if it was determined that an update should indeed - be handled by this instance. Calls :attr:`callback` along with its respectful - arguments. To work with the :class:`telegram.ext.ConversationHandler`, this method - returns the value returned from :attr:`callback`. - Note that it can be overridden if needed by the subclassing handler. - - Args: - update (:obj:`str` | :class:`telegram.Update`): The update to be handled. - dispatcher (:class:`telegram.ext.Dispatcher`): The calling dispatcher. - check_result (:obj:`obj`): The result from :attr:`check_update`. - context (:class:`telegram.ext.CallbackContext`, optional): The context as provided by - the dispatcher. - - """ - run_async = self.run_async - if ( - self.run_async is DEFAULT_FALSE - and dispatcher.bot.defaults - and dispatcher.bot.defaults.run_async - ): - run_async = True - - if context: - self.collect_additional_context(context, update, dispatcher, check_result) - if run_async: - return dispatcher.run_async(self.callback, update, context, update=update) - return self.callback(update, context) - - optional_args = self.collect_optional_args(dispatcher, update, check_result) - if run_async: - return dispatcher.run_async( - self.callback, dispatcher.bot, update, update=update, **optional_args - ) - return self.callback(dispatcher.bot, update, **optional_args) # type: ignore - - def collect_additional_context( - self, - context: CCT, - update: UT, - dispatcher: 'Dispatcher', - check_result: Any, - ) -> None: - """Prepares additional arguments for the context. Override if needed. - - Args: - context (:class:`telegram.ext.CallbackContext`): The context object. - update (:class:`telegram.Update`): The update to gather chat/user id from. - dispatcher (:class:`telegram.ext.Dispatcher`): The calling dispatcher. - check_result: The result (return value) from :attr:`check_update`. - - """ - - def collect_optional_args( - self, - dispatcher: 'Dispatcher', - update: UT = None, - check_result: Any = None, # pylint: disable=W0613 - ) -> Dict[str, object]: - """ - Prepares the optional arguments. If the handler has additional optional args, - it should subclass this method, but remember to call this super method. - - DEPRECATED: This method is being replaced by new context based callbacks. Please see - https://git.io/fxJuV for more info. - - Args: - dispatcher (:class:`telegram.ext.Dispatcher`): The dispatcher. - update (:class:`telegram.Update`): The update to gather chat/user id from. - check_result: The result from check_update - - """ - optional_args: Dict[str, object] = {} - - if self.pass_update_queue: - optional_args['update_queue'] = dispatcher.update_queue - if self.pass_job_queue: - optional_args['job_queue'] = dispatcher.job_queue - if self.pass_user_data and isinstance(update, Update): - user = update.effective_user - optional_args['user_data'] = dispatcher.user_data[ - user.id if user else None # type: ignore[index] - ] - if self.pass_chat_data and isinstance(update, Update): - chat = update.effective_chat - optional_args['chat_data'] = dispatcher.chat_data[ - chat.id if chat else None # type: ignore[index] - ] - - return optional_args diff --git a/venv/lib/python3.8/site-packages/telegram/ext/inlinequeryhandler.py b/venv/lib/python3.8/site-packages/telegram/ext/inlinequeryhandler.py deleted file mode 100644 index 11103e7..0000000 --- a/venv/lib/python3.8/site-packages/telegram/ext/inlinequeryhandler.py +++ /dev/null @@ -1,221 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the InlineQueryHandler class.""" -import re -from typing import ( - TYPE_CHECKING, - Callable, - Dict, - Match, - Optional, - Pattern, - TypeVar, - Union, - cast, - List, -) - -from telegram import Update -from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE - -from .handler import Handler -from .utils.types import CCT - -if TYPE_CHECKING: - from telegram.ext import Dispatcher - -RT = TypeVar('RT') - - -class InlineQueryHandler(Handler[Update, CCT]): - """ - Handler class to handle Telegram inline queries. Optionally based on a regex. Read the - documentation of the ``re`` module for more information. - - Note: - :attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you - can use to keep any data in will be sent to the :attr:`callback` function. Related to - either the user or the chat that the update was sent in. For each update from the same user - or in the same chat, it will be the same ``dict``. - - Note that this is DEPRECATED, and you should use context based callbacks. See - https://git.io/fxJuV for more info. - - Warning: - * When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - * :attr:`telegram.InlineQuery.chat_type` will not be set for inline queries from secret - chats and may not be set for inline queries coming from third-party clients. These - updates won't be handled, if :attr:`chat_types` is passed. - - Args: - callback (:obj:`callable`): The callback function for this handler. Will be called when - :attr:`check_update` has determined that an update should be processed by this handler. - Callback signature for context based API: - - ``def callback(update: Update, context: CallbackContext)`` - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``update_queue`` will be passed to the callback function. It will be the ``Queue`` - instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher` - that contains new updates which can be used to insert updates. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``job_queue`` will be passed to the callback function. It will be a - :class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater` - which can be used to schedule new jobs. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - pattern (:obj:`str` | :obj:`Pattern`, optional): Regex pattern. If not :obj:`None`, - ``re.match`` is used on :attr:`telegram.InlineQuery.query` to determine if an update - should be handled by this handler. - chat_types (List[:obj:`str`], optional): List of allowed chat types. If passed, will only - handle inline queries with the appropriate :attr:`telegram.InlineQuery.chat_type`. - - .. versionadded:: 13.5 - pass_groups (:obj:`bool`, optional): If the callback should be passed the result of - ``re.match(pattern, data).groups()`` as a keyword argument called ``groups``. - Default is :obj:`False` - DEPRECATED: Please switch to context based callbacks. - pass_groupdict (:obj:`bool`, optional): If the callback should be passed the result of - ``re.match(pattern, data).groupdict()`` as a keyword argument called ``groupdict``. - Default is :obj:`False` - DEPRECATED: Please switch to context based callbacks. - pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``user_data`` will be passed to the callback function. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``chat_data`` will be passed to the callback function. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - run_async (:obj:`bool`): Determines whether the callback will run asynchronously. - Defaults to :obj:`False`. - - Attributes: - callback (:obj:`callable`): The callback function for this handler. - pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be - passed to the callback function. - pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to - the callback function. - pattern (:obj:`str` | :obj:`Pattern`): Optional. Regex pattern to test - :attr:`telegram.InlineQuery.query` against. - chat_types (List[:obj:`str`], optional): List of allowed chat types. - - .. versionadded:: 13.5 - pass_groups (:obj:`bool`): Determines whether ``groups`` will be passed to the - callback function. - pass_groupdict (:obj:`bool`): Determines whether ``groupdict``. will be passed to - the callback function. - pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to - the callback function. - pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to - the callback function. - run_async (:obj:`bool`): Determines whether the callback will run asynchronously. - - """ - - __slots__ = ('pattern', 'chat_types', 'pass_groups', 'pass_groupdict') - - def __init__( - self, - callback: Callable[[Update, CCT], RT], - pass_update_queue: bool = False, - pass_job_queue: bool = False, - pattern: Union[str, Pattern] = None, - pass_groups: bool = False, - pass_groupdict: bool = False, - pass_user_data: bool = False, - pass_chat_data: bool = False, - run_async: Union[bool, DefaultValue] = DEFAULT_FALSE, - chat_types: List[str] = None, - ): - super().__init__( - callback, - pass_update_queue=pass_update_queue, - pass_job_queue=pass_job_queue, - pass_user_data=pass_user_data, - pass_chat_data=pass_chat_data, - run_async=run_async, - ) - - if isinstance(pattern, str): - pattern = re.compile(pattern) - - self.pattern = pattern - self.chat_types = chat_types - self.pass_groups = pass_groups - self.pass_groupdict = pass_groupdict - - def check_update(self, update: object) -> Optional[Union[bool, Match]]: - """ - Determines whether an update should be passed to this handlers :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - if isinstance(update, Update) and update.inline_query: - if (self.chat_types is not None) and ( - update.inline_query.chat_type not in self.chat_types - ): - return False - if self.pattern: - if update.inline_query.query: - match = re.match(self.pattern, update.inline_query.query) - if match: - return match - else: - return True - return None - - def collect_optional_args( - self, - dispatcher: 'Dispatcher', - update: Update = None, - check_result: Optional[Union[bool, Match]] = None, - ) -> Dict[str, object]: - """Pass the results of ``re.match(pattern, query).{groups(), groupdict()}`` to the - callback as a keyword arguments called ``groups`` and ``groupdict``, respectively, if - needed. - """ - optional_args = super().collect_optional_args(dispatcher, update, check_result) - if self.pattern: - check_result = cast(Match, check_result) - if self.pass_groups: - optional_args['groups'] = check_result.groups() - if self.pass_groupdict: - optional_args['groupdict'] = check_result.groupdict() - return optional_args - - def collect_additional_context( - self, - context: CCT, - update: Update, - dispatcher: 'Dispatcher', - check_result: Optional[Union[bool, Match]], - ) -> None: - """Add the result of ``re.match(pattern, update.inline_query.query)`` to - :attr:`CallbackContext.matches` as list with one element. - """ - if self.pattern: - check_result = cast(Match, check_result) - context.matches = [check_result] diff --git a/venv/lib/python3.8/site-packages/telegram/ext/jobqueue.py b/venv/lib/python3.8/site-packages/telegram/ext/jobqueue.py deleted file mode 100644 index a6e8e1a..0000000 --- a/venv/lib/python3.8/site-packages/telegram/ext/jobqueue.py +++ /dev/null @@ -1,656 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the classes JobQueue and Job.""" - -import datetime -import logging -from typing import TYPE_CHECKING, Callable, List, Optional, Tuple, Union, cast, overload - -import pytz -from apscheduler.events import EVENT_JOB_ERROR, EVENT_JOB_EXECUTED, JobEvent -from apscheduler.schedulers.background import BackgroundScheduler -from apscheduler.triggers.combining import OrTrigger -from apscheduler.triggers.cron import CronTrigger -from apscheduler.job import Job as APSJob - -from telegram.ext.callbackcontext import CallbackContext -from telegram.utils.types import JSONDict -from telegram.utils.deprecate import set_new_attribute_deprecated - -if TYPE_CHECKING: - from telegram import Bot - from telegram.ext import Dispatcher - import apscheduler.job # noqa: F401 - - -class JobQueue: - """This class allows you to periodically perform tasks with the bot. It is a convenience - wrapper for the APScheduler library. - - Attributes: - scheduler (:class:`apscheduler.schedulers.background.BackgroundScheduler`): The APScheduler - bot (:class:`telegram.Bot`): The bot instance that should be passed to the jobs. - DEPRECATED: Use :attr:`set_dispatcher` instead. - - """ - - __slots__ = ('_dispatcher', 'logger', 'scheduler', '__dict__') - - def __init__(self) -> None: - self._dispatcher: 'Dispatcher' = None # type: ignore[assignment] - self.logger = logging.getLogger(self.__class__.__name__) - self.scheduler = BackgroundScheduler(timezone=pytz.utc) - self.scheduler.add_listener( - self._update_persistence, mask=EVENT_JOB_EXECUTED | EVENT_JOB_ERROR - ) - - # Dispatch errors and don't log them in the APS logger - def aps_log_filter(record): # type: ignore - return 'raised an exception' not in record.msg - - logging.getLogger('apscheduler.executors.default').addFilter(aps_log_filter) - self.scheduler.add_listener(self._dispatch_error, EVENT_JOB_ERROR) - - def __setattr__(self, key: str, value: object) -> None: - set_new_attribute_deprecated(self, key, value) - - def _build_args(self, job: 'Job') -> List[Union[CallbackContext, 'Bot', 'Job']]: - if self._dispatcher.use_context: - return [self._dispatcher.context_types.context.from_job(job, self._dispatcher)] - return [self._dispatcher.bot, job] - - def _tz_now(self) -> datetime.datetime: - return datetime.datetime.now(self.scheduler.timezone) - - def _update_persistence(self, _: JobEvent) -> None: - self._dispatcher.update_persistence() - - def _dispatch_error(self, event: JobEvent) -> None: - try: - self._dispatcher.dispatch_error(None, event.exception) - # Errors should not stop the thread. - except Exception: - self.logger.exception( - 'An error was raised while processing the job and an ' - 'uncaught error was raised while handling the error ' - 'with an error_handler.' - ) - - @overload - def _parse_time_input(self, time: None, shift_day: bool = False) -> None: - ... - - @overload - def _parse_time_input( - self, - time: Union[float, int, datetime.timedelta, datetime.datetime, datetime.time], - shift_day: bool = False, - ) -> datetime.datetime: - ... - - def _parse_time_input( - self, - time: Union[float, int, datetime.timedelta, datetime.datetime, datetime.time, None], - shift_day: bool = False, - ) -> Optional[datetime.datetime]: - if time is None: - return None - if isinstance(time, (int, float)): - return self._tz_now() + datetime.timedelta(seconds=time) - if isinstance(time, datetime.timedelta): - return self._tz_now() + time - if isinstance(time, datetime.time): - date_time = datetime.datetime.combine( - datetime.datetime.now(tz=time.tzinfo or self.scheduler.timezone).date(), time - ) - if date_time.tzinfo is None: - date_time = self.scheduler.timezone.localize(date_time) - if shift_day and date_time <= datetime.datetime.now(pytz.utc): - date_time += datetime.timedelta(days=1) - return date_time - # isinstance(time, datetime.datetime): - return time - - def set_dispatcher(self, dispatcher: 'Dispatcher') -> None: - """Set the dispatcher to be used by this JobQueue. Use this instead of passing a - :class:`telegram.Bot` to the JobQueue, which is deprecated. - - Args: - dispatcher (:class:`telegram.ext.Dispatcher`): The dispatcher. - - """ - self._dispatcher = dispatcher - if dispatcher.bot.defaults: - self.scheduler.configure(timezone=dispatcher.bot.defaults.tzinfo or pytz.utc) - - def run_once( - self, - callback: Callable[['CallbackContext'], None], - when: Union[float, datetime.timedelta, datetime.datetime, datetime.time], - context: object = None, - name: str = None, - job_kwargs: JSONDict = None, - ) -> 'Job': - """Creates a new ``Job`` that runs once and adds it to the queue. - - Args: - callback (:obj:`callable`): The callback function that should be executed by the new - job. Callback signature for context based API: - - ``def callback(CallbackContext)`` - - ``context.job`` is the :class:`telegram.ext.Job` instance. It can be used to access - its ``job.context`` or change it to a repeating job. - when (:obj:`int` | :obj:`float` | :obj:`datetime.timedelta` | \ - :obj:`datetime.datetime` | :obj:`datetime.time`): - Time in or at which the job should run. This parameter will be interpreted - depending on its type. - - * :obj:`int` or :obj:`float` will be interpreted as "seconds from now" in which the - job should run. - * :obj:`datetime.timedelta` will be interpreted as "time from now" in which the - job should run. - * :obj:`datetime.datetime` will be interpreted as a specific date and time at - which the job should run. If the timezone (``datetime.tzinfo``) is :obj:`None`, - the default timezone of the bot will be used. - * :obj:`datetime.time` will be interpreted as a specific time of day at which the - job should run. This could be either today or, if the time has already passed, - tomorrow. If the timezone (``time.tzinfo``) is :obj:`None`, the - default timezone of the bot will be used. - - context (:obj:`object`, optional): Additional data needed for the callback function. - Can be accessed through ``job.context`` in the callback. Defaults to :obj:`None`. - name (:obj:`str`, optional): The name of the new job. Defaults to - ``callback.__name__``. - job_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to pass to the - ``scheduler.add_job()``. - - Returns: - :class:`telegram.ext.Job`: The new ``Job`` instance that has been added to the job - queue. - - """ - if not job_kwargs: - job_kwargs = {} - - name = name or callback.__name__ - job = Job(callback, context, name, self) - date_time = self._parse_time_input(when, shift_day=True) - - j = self.scheduler.add_job( - callback, - name=name, - trigger='date', - run_date=date_time, - args=self._build_args(job), - timezone=date_time.tzinfo or self.scheduler.timezone, - **job_kwargs, - ) - - job.job = j - return job - - def run_repeating( - self, - callback: Callable[['CallbackContext'], None], - interval: Union[float, datetime.timedelta], - first: Union[float, datetime.timedelta, datetime.datetime, datetime.time] = None, - last: Union[float, datetime.timedelta, datetime.datetime, datetime.time] = None, - context: object = None, - name: str = None, - job_kwargs: JSONDict = None, - ) -> 'Job': - """Creates a new ``Job`` that runs at specified intervals and adds it to the queue. - - Note: - For a note about DST, please see the documentation of `APScheduler`_. - - .. _`APScheduler`: https://apscheduler.readthedocs.io/en/stable/modules/triggers/cron.html - #daylight-saving-time-behavior - - Args: - callback (:obj:`callable`): The callback function that should be executed by the new - job. Callback signature for context based API: - - ``def callback(CallbackContext)`` - - ``context.job`` is the :class:`telegram.ext.Job` instance. It can be used to access - its ``job.context`` or change it to a repeating job. - interval (:obj:`int` | :obj:`float` | :obj:`datetime.timedelta`): The interval in which - the job will run. If it is an :obj:`int` or a :obj:`float`, it will be interpreted - as seconds. - first (:obj:`int` | :obj:`float` | :obj:`datetime.timedelta` | \ - :obj:`datetime.datetime` | :obj:`datetime.time`, optional): - Time in or at which the job should run. This parameter will be interpreted - depending on its type. - - * :obj:`int` or :obj:`float` will be interpreted as "seconds from now" in which the - job should run. - * :obj:`datetime.timedelta` will be interpreted as "time from now" in which the - job should run. - * :obj:`datetime.datetime` will be interpreted as a specific date and time at - which the job should run. If the timezone (``datetime.tzinfo``) is :obj:`None`, - the default timezone of the bot will be used. - * :obj:`datetime.time` will be interpreted as a specific time of day at which the - job should run. This could be either today or, if the time has already passed, - tomorrow. If the timezone (``time.tzinfo``) is :obj:`None`, the - default timezone of the bot will be used. - - Defaults to ``interval`` - last (:obj:`int` | :obj:`float` | :obj:`datetime.timedelta` | \ - :obj:`datetime.datetime` | :obj:`datetime.time`, optional): - Latest possible time for the job to run. This parameter will be interpreted - depending on its type. See ``first`` for details. - - If ``last`` is :obj:`datetime.datetime` or :obj:`datetime.time` type - and ``last.tzinfo`` is :obj:`None`, the default timezone of the bot will be - assumed. - - Defaults to :obj:`None`. - context (:obj:`object`, optional): Additional data needed for the callback function. - Can be accessed through ``job.context`` in the callback. Defaults to :obj:`None`. - name (:obj:`str`, optional): The name of the new job. Defaults to - ``callback.__name__``. - job_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to pass to the - ``scheduler.add_job()``. - - Returns: - :class:`telegram.ext.Job`: The new ``Job`` instance that has been added to the job - queue. - - """ - if not job_kwargs: - job_kwargs = {} - - name = name or callback.__name__ - job = Job(callback, context, name, self) - - dt_first = self._parse_time_input(first) - dt_last = self._parse_time_input(last) - - if dt_last and dt_first and dt_last < dt_first: - raise ValueError("'last' must not be before 'first'!") - - if isinstance(interval, datetime.timedelta): - interval = interval.total_seconds() - - j = self.scheduler.add_job( - callback, - trigger='interval', - args=self._build_args(job), - start_date=dt_first, - end_date=dt_last, - seconds=interval, - name=name, - **job_kwargs, - ) - - job.job = j - return job - - def run_monthly( - self, - callback: Callable[['CallbackContext'], None], - when: datetime.time, - day: int, - context: object = None, - name: str = None, - day_is_strict: bool = True, - job_kwargs: JSONDict = None, - ) -> 'Job': - """Creates a new ``Job`` that runs on a monthly basis and adds it to the queue. - - Args: - callback (:obj:`callable`): The callback function that should be executed by the new - job. Callback signature for context based API: - - ``def callback(CallbackContext)`` - - ``context.job`` is the :class:`telegram.ext.Job` instance. It can be used to access - its ``job.context`` or change it to a repeating job. - when (:obj:`datetime.time`): Time of day at which the job should run. If the timezone - (``when.tzinfo``) is :obj:`None`, the default timezone of the bot will be used. - day (:obj:`int`): Defines the day of the month whereby the job would run. It should - be within the range of 1 and 31, inclusive. - context (:obj:`object`, optional): Additional data needed for the callback function. - Can be accessed through ``job.context`` in the callback. Defaults to :obj:`None`. - name (:obj:`str`, optional): The name of the new job. Defaults to - ``callback.__name__``. - day_is_strict (:obj:`bool`, optional): If :obj:`False` and day > month.days, will pick - the last day in the month. Defaults to :obj:`True`. - job_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to pass to the - ``scheduler.add_job()``. - - Returns: - :class:`telegram.ext.Job`: The new ``Job`` instance that has been added to the job - queue. - - """ - if not job_kwargs: - job_kwargs = {} - - name = name or callback.__name__ - job = Job(callback, context, name, self) - - if day_is_strict: - j = self.scheduler.add_job( - callback, - trigger='cron', - args=self._build_args(job), - name=name, - day=day, - hour=when.hour, - minute=when.minute, - second=when.second, - timezone=when.tzinfo or self.scheduler.timezone, - **job_kwargs, - ) - else: - trigger = OrTrigger( - [ - CronTrigger( - day=day, - hour=when.hour, - minute=when.minute, - second=when.second, - timezone=when.tzinfo, - **job_kwargs, - ), - CronTrigger( - day='last', - hour=when.hour, - minute=when.minute, - second=when.second, - timezone=when.tzinfo or self.scheduler.timezone, - **job_kwargs, - ), - ] - ) - j = self.scheduler.add_job( - callback, trigger=trigger, args=self._build_args(job), name=name, **job_kwargs - ) - - job.job = j - return job - - def run_daily( - self, - callback: Callable[['CallbackContext'], None], - time: datetime.time, - days: Tuple[int, ...] = tuple(range(7)), - context: object = None, - name: str = None, - job_kwargs: JSONDict = None, - ) -> 'Job': - """Creates a new ``Job`` that runs on a daily basis and adds it to the queue. - - Note: - For a note about DST, please see the documentation of `APScheduler`_. - - .. _`APScheduler`: https://apscheduler.readthedocs.io/en/stable/modules/triggers/cron.html - #daylight-saving-time-behavior - - Args: - callback (:obj:`callable`): The callback function that should be executed by the new - job. Callback signature for context based API: - - ``def callback(CallbackContext)`` - - ``context.job`` is the :class:`telegram.ext.Job` instance. It can be used to access - its ``job.context`` or change it to a repeating job. - time (:obj:`datetime.time`): Time of day at which the job should run. If the timezone - (``time.tzinfo``) is :obj:`None`, the default timezone of the bot will be used. - days (Tuple[:obj:`int`], optional): Defines on which days of the week the job should - run (where ``0-6`` correspond to monday - sunday). Defaults to ``EVERY_DAY`` - context (:obj:`object`, optional): Additional data needed for the callback function. - Can be accessed through ``job.context`` in the callback. Defaults to :obj:`None`. - name (:obj:`str`, optional): The name of the new job. Defaults to - ``callback.__name__``. - job_kwargs (:obj:`dict`, optional): Arbitrary keyword arguments to pass to the - ``scheduler.add_job()``. - - Returns: - :class:`telegram.ext.Job`: The new ``Job`` instance that has been added to the job - queue. - - """ - if not job_kwargs: - job_kwargs = {} - - name = name or callback.__name__ - job = Job(callback, context, name, self) - - j = self.scheduler.add_job( - callback, - name=name, - args=self._build_args(job), - trigger='cron', - day_of_week=','.join([str(d) for d in days]), - hour=time.hour, - minute=time.minute, - second=time.second, - timezone=time.tzinfo or self.scheduler.timezone, - **job_kwargs, - ) - - job.job = j - return job - - def run_custom( - self, - callback: Callable[['CallbackContext'], None], - job_kwargs: JSONDict, - context: object = None, - name: str = None, - ) -> 'Job': - """Creates a new customly defined ``Job``. - - Args: - callback (:obj:`callable`): The callback function that should be executed by the new - job. Callback signature for context based API: - - ``def callback(CallbackContext)`` - - ``context.job`` is the :class:`telegram.ext.Job` instance. It can be used to access - its ``job.context`` or change it to a repeating job. - job_kwargs (:obj:`dict`): Arbitrary keyword arguments. Used as arguments for - ``scheduler.add_job``. - context (:obj:`object`, optional): Additional data needed for the callback function. - Can be accessed through ``job.context`` in the callback. Defaults to ``None``. - name (:obj:`str`, optional): The name of the new job. Defaults to - ``callback.__name__``. - - Returns: - :class:`telegram.ext.Job`: The new ``Job`` instance that has been added to the job - queue. - - """ - name = name or callback.__name__ - job = Job(callback, context, name, self) - - j = self.scheduler.add_job(callback, args=self._build_args(job), name=name, **job_kwargs) - - job.job = j - return job - - def start(self) -> None: - """Starts the job_queue thread.""" - if not self.scheduler.running: - self.scheduler.start() - - def stop(self) -> None: - """Stops the thread.""" - if self.scheduler.running: - self.scheduler.shutdown() - - def jobs(self) -> Tuple['Job', ...]: - """Returns a tuple of all *scheduled* jobs that are currently in the ``JobQueue``.""" - return tuple( - Job._from_aps_job(job, self) # pylint: disable=W0212 - for job in self.scheduler.get_jobs() - ) - - def get_jobs_by_name(self, name: str) -> Tuple['Job', ...]: - """Returns a tuple of all *pending/scheduled* jobs with the given name that are currently - in the ``JobQueue``. - """ - return tuple(job for job in self.jobs() if job.name == name) - - -class Job: - """This class is a convenience wrapper for the jobs held in a :class:`telegram.ext.JobQueue`. - With the current backend APScheduler, :attr:`job` holds a :class:`apscheduler.job.Job` - instance. - - Note: - * All attributes and instance methods of :attr:`job` are also directly available as - attributes/methods of the corresponding :class:`telegram.ext.Job` object. - * Two instances of :class:`telegram.ext.Job` are considered equal, if their corresponding - ``job`` attributes have the same ``id``. - * If :attr:`job` isn't passed on initialization, it must be set manually afterwards for - this :class:`telegram.ext.Job` to be useful. - - Args: - callback (:obj:`callable`): The callback function that should be executed by the new job. - Callback signature for context based API: - - ``def callback(CallbackContext)`` - - a ``context.job`` is the :class:`telegram.ext.Job` instance. It can be used to access - its ``job.context`` or change it to a repeating job. - context (:obj:`object`, optional): Additional data needed for the callback function. Can be - accessed through ``job.context`` in the callback. Defaults to :obj:`None`. - name (:obj:`str`, optional): The name of the new job. Defaults to ``callback.__name__``. - job_queue (:class:`telegram.ext.JobQueue`, optional): The ``JobQueue`` this job belongs to. - Only optional for backward compatibility with ``JobQueue.put()``. - job (:class:`apscheduler.job.Job`, optional): The APS Job this job is a wrapper for. - - Attributes: - callback (:obj:`callable`): The callback function that should be executed by the new job. - context (:obj:`object`): Optional. Additional data needed for the callback function. - name (:obj:`str`): Optional. The name of the new job. - job_queue (:class:`telegram.ext.JobQueue`): Optional. The ``JobQueue`` this job belongs to. - job (:class:`apscheduler.job.Job`): Optional. The APS Job this job is a wrapper for. - """ - - __slots__ = ( - 'callback', - 'context', - 'name', - 'job_queue', - '_removed', - '_enabled', - 'job', - '__dict__', - ) - - def __init__( - self, - callback: Callable[['CallbackContext'], None], - context: object = None, - name: str = None, - job_queue: JobQueue = None, - job: APSJob = None, - ): - - self.callback = callback - self.context = context - self.name = name or callback.__name__ - self.job_queue = job_queue - - self._removed = False - self._enabled = False - - self.job = cast(APSJob, job) # skipcq: PTC-W0052 - - def __setattr__(self, key: str, value: object) -> None: - set_new_attribute_deprecated(self, key, value) - - def run(self, dispatcher: 'Dispatcher') -> None: - """Executes the callback function independently of the jobs schedule.""" - try: - if dispatcher.use_context: - self.callback(dispatcher.context_types.context.from_job(self, dispatcher)) - else: - self.callback(dispatcher.bot, self) # type: ignore[arg-type,call-arg] - except Exception as exc: - try: - dispatcher.dispatch_error(None, exc) - # Errors should not stop the thread. - except Exception: - dispatcher.logger.exception( - 'An error was raised while processing the job and an ' - 'uncaught error was raised while handling the error ' - 'with an error_handler.' - ) - - def schedule_removal(self) -> None: - """ - Schedules this job for removal from the ``JobQueue``. It will be removed without executing - its callback function again. - """ - self.job.remove() - self._removed = True - - @property - def removed(self) -> bool: - """:obj:`bool`: Whether this job is due to be removed.""" - return self._removed - - @property - def enabled(self) -> bool: - """:obj:`bool`: Whether this job is enabled.""" - return self._enabled - - @enabled.setter - def enabled(self, status: bool) -> None: - if status: - self.job.resume() - else: - self.job.pause() - self._enabled = status - - @property - def next_t(self) -> Optional[datetime.datetime]: - """ - :obj:`datetime.datetime`: Datetime for the next job execution. - Datetime is localized according to :attr:`tzinfo`. - If job is removed or already ran it equals to :obj:`None`. - """ - return self.job.next_run_time - - @classmethod - def _from_aps_job(cls, job: APSJob, job_queue: JobQueue) -> 'Job': - # context based callbacks - if len(job.args) == 1: - context = job.args[0].job.context - else: - context = job.args[1].context - return cls(job.func, context=context, name=job.name, job_queue=job_queue, job=job) - - def __getattr__(self, item: str) -> object: - return getattr(self.job, item) - - def __lt__(self, other: object) -> bool: - return False - - def __eq__(self, other: object) -> bool: - if isinstance(other, self.__class__): - return self.id == other.id - return False diff --git a/venv/lib/python3.8/site-packages/telegram/ext/messagehandler.py b/venv/lib/python3.8/site-packages/telegram/ext/messagehandler.py deleted file mode 100644 index c3f0c01..0000000 --- a/venv/lib/python3.8/site-packages/telegram/ext/messagehandler.py +++ /dev/null @@ -1,208 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -# TODO: Remove allow_edited -"""This module contains the MessageHandler class.""" -import warnings -from typing import TYPE_CHECKING, Callable, Dict, Optional, TypeVar, Union - -from telegram import Update -from telegram.ext import BaseFilter, Filters -from telegram.utils.deprecate import TelegramDeprecationWarning -from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE - -from .handler import Handler -from .utils.types import CCT - -if TYPE_CHECKING: - from telegram.ext import Dispatcher - -RT = TypeVar('RT') - - -class MessageHandler(Handler[Update, CCT]): - """Handler class to handle telegram messages. They might contain text, media or status updates. - - Note: - :attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you - can use to keep any data in will be sent to the :attr:`callback` function. Related to - either the user or the chat that the update was sent in. For each update from the same user - or in the same chat, it will be the same ``dict``. - - Note that this is DEPRECATED, and you should use context based callbacks. See - https://git.io/fxJuV for more info. - - Warning: - When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - Args: - filters (:class:`telegram.ext.BaseFilter`, optional): A filter inheriting from - :class:`telegram.ext.filters.BaseFilter`. Standard filters can be found in - :class:`telegram.ext.filters.Filters`. Filters can be combined using bitwise - operators (& for and, | for or, ~ for not). Default is - :attr:`telegram.ext.filters.Filters.update`. This defaults to all message_type updates - being: ``message``, ``edited_message``, ``channel_post`` and ``edited_channel_post``. - If you don't want or need any of those pass ``~Filters.update.*`` in the filter - argument. - callback (:obj:`callable`): The callback function for this handler. Will be called when - :attr:`check_update` has determined that an update should be processed by this handler. - Callback signature for context based API: - - ``def callback(update: Update, context: CallbackContext)`` - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``update_queue`` will be passed to the callback function. It will be the ``Queue`` - instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher` - that contains new updates which can be used to insert updates. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``job_queue`` will be passed to the callback function. It will be a - :class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater` - which can be used to schedule new jobs. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``user_data`` will be passed to the callback function. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``chat_data`` will be passed to the callback function. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - message_updates (:obj:`bool`, optional): Should "normal" message updates be handled? - Default is :obj:`None`. - DEPRECATED: Please switch to filters for update filtering. - channel_post_updates (:obj:`bool`, optional): Should channel posts updates be handled? - Default is :obj:`None`. - DEPRECATED: Please switch to filters for update filtering. - edited_updates (:obj:`bool`, optional): Should "edited" message updates be handled? Default - is :obj:`None`. - DEPRECATED: Please switch to filters for update filtering. - run_async (:obj:`bool`): Determines whether the callback will run asynchronously. - Defaults to :obj:`False`. - - Raises: - ValueError - - Attributes: - filters (:obj:`Filter`): Only allow updates with these Filters. See - :mod:`telegram.ext.filters` for a full list of all available filters. - callback (:obj:`callable`): The callback function for this handler. - pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be - passed to the callback function. - pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to - the callback function. - pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to - the callback function. - pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to - the callback function. - message_updates (:obj:`bool`): Should "normal" message updates be handled? - Default is :obj:`None`. - channel_post_updates (:obj:`bool`): Should channel posts updates be handled? - Default is :obj:`None`. - edited_updates (:obj:`bool`): Should "edited" message updates be handled? - Default is :obj:`None`. - run_async (:obj:`bool`): Determines whether the callback will run asynchronously. - - """ - - __slots__ = ('filters',) - - def __init__( - self, - filters: BaseFilter, - callback: Callable[[Update, CCT], RT], - pass_update_queue: bool = False, - pass_job_queue: bool = False, - pass_user_data: bool = False, - pass_chat_data: bool = False, - message_updates: bool = None, - channel_post_updates: bool = None, - edited_updates: bool = None, - run_async: Union[bool, DefaultValue] = DEFAULT_FALSE, - ): - - super().__init__( - callback, - pass_update_queue=pass_update_queue, - pass_job_queue=pass_job_queue, - pass_user_data=pass_user_data, - pass_chat_data=pass_chat_data, - run_async=run_async, - ) - if message_updates is False and channel_post_updates is False and edited_updates is False: - raise ValueError( - 'message_updates, channel_post_updates and edited_updates are all False' - ) - if filters is not None: - self.filters = Filters.update & filters - else: - self.filters = Filters.update - if message_updates is not None: - warnings.warn( - 'message_updates is deprecated. See https://git.io/fxJuV for more info', - TelegramDeprecationWarning, - stacklevel=2, - ) - if message_updates is False: - self.filters &= ~Filters.update.message - - if channel_post_updates is not None: - warnings.warn( - 'channel_post_updates is deprecated. See https://git.io/fxJuV ' 'for more info', - TelegramDeprecationWarning, - stacklevel=2, - ) - if channel_post_updates is False: - self.filters &= ~Filters.update.channel_post - - if edited_updates is not None: - warnings.warn( - 'edited_updates is deprecated. See https://git.io/fxJuV for more info', - TelegramDeprecationWarning, - stacklevel=2, - ) - if edited_updates is False: - self.filters &= ~( - Filters.update.edited_message | Filters.update.edited_channel_post - ) - - def check_update(self, update: object) -> Optional[Union[bool, Dict[str, list]]]: - """Determines whether an update should be passed to this handlers :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - if isinstance(update, Update) and update.effective_message: - return self.filters(update) - return None - - def collect_additional_context( - self, - context: CCT, - update: Update, - dispatcher: 'Dispatcher', - check_result: Optional[Union[bool, Dict[str, object]]], - ) -> None: - """Adds possible output of data filters to the :class:`CallbackContext`.""" - if isinstance(check_result, dict): - context.update(check_result) diff --git a/venv/lib/python3.8/site-packages/telegram/ext/messagequeue.py b/venv/lib/python3.8/site-packages/telegram/ext/messagequeue.py deleted file mode 100644 index ece0bc3..0000000 --- a/venv/lib/python3.8/site-packages/telegram/ext/messagequeue.py +++ /dev/null @@ -1,334 +0,0 @@ -#!/usr/bin/env python -# -# Module author: -# Tymofii A. Khodniev (thodnev) <thodnev@mail.ru> -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/] -"""A throughput-limiting message processor for Telegram bots.""" -import functools -import queue as q -import threading -import time -import warnings -from typing import TYPE_CHECKING, Callable, List, NoReturn - -from telegram.ext.utils.promise import Promise -from telegram.utils.deprecate import TelegramDeprecationWarning - -if TYPE_CHECKING: - from telegram import Bot - -# We need to count < 1s intervals, so the most accurate timer is needed -curtime = time.perf_counter - - -class DelayQueueError(RuntimeError): - """Indicates processing errors.""" - - __slots__ = () - - -class DelayQueue(threading.Thread): - """ - Processes callbacks from queue with specified throughput limits. Creates a separate thread to - process callbacks with delays. - - .. deprecated:: 13.3 - :class:`telegram.ext.DelayQueue` in its current form is deprecated and will be reinvented - in a future release. See `this thread <https://git.io/JtDbF>`_ for a list of known bugs. - - Args: - queue (:obj:`Queue`, optional): Used to pass callbacks to thread. Creates ``Queue`` - implicitly if not provided. - burst_limit (:obj:`int`, optional): Number of maximum callbacks to process per time-window - defined by :attr:`time_limit_ms`. Defaults to 30. - time_limit_ms (:obj:`int`, optional): Defines width of time-window used when each - processing limit is calculated. Defaults to 1000. - exc_route (:obj:`callable`, optional): A callable, accepting 1 positional argument; used to - route exceptions from processor thread to main thread; is called on `Exception` - subclass exceptions. If not provided, exceptions are routed through dummy handler, - which re-raises them. - autostart (:obj:`bool`, optional): If :obj:`True`, processor is started immediately after - object's creation; if :obj:`False`, should be started manually by `start` method. - Defaults to :obj:`True`. - name (:obj:`str`, optional): Thread's name. Defaults to ``'DelayQueue-N'``, where N is - sequential number of object created. - - Attributes: - burst_limit (:obj:`int`): Number of maximum callbacks to process per time-window. - time_limit (:obj:`int`): Defines width of time-window used when each processing limit is - calculated. - exc_route (:obj:`callable`): A callable, accepting 1 positional argument; used to route - exceptions from processor thread to main thread; - name (:obj:`str`): Thread's name. - - """ - - _instcnt = 0 # instance counter - - def __init__( - self, - queue: q.Queue = None, - burst_limit: int = 30, - time_limit_ms: int = 1000, - exc_route: Callable[[Exception], None] = None, - autostart: bool = True, - name: str = None, - ): - warnings.warn( - 'DelayQueue in its current form is deprecated and will be reinvented in a future ' - 'release. See https://git.io/JtDbF for a list of known bugs.', - category=TelegramDeprecationWarning, - ) - - self._queue = queue if queue is not None else q.Queue() - self.burst_limit = burst_limit - self.time_limit = time_limit_ms / 1000 - self.exc_route = exc_route if exc_route is not None else self._default_exception_handler - self.__exit_req = False # flag to gently exit thread - self.__class__._instcnt += 1 - if name is None: - name = f'{self.__class__.__name__}-{self.__class__._instcnt}' - super().__init__(name=name) - self.daemon = False - if autostart: # immediately start processing - super().start() - - def run(self) -> None: - """ - Do not use the method except for unthreaded testing purposes, the method normally is - automatically called by autostart argument. - - """ - times: List[float] = [] # used to store each callable processing time - while True: - item = self._queue.get() - if self.__exit_req: - return # shutdown thread - # delay routine - now = time.perf_counter() - t_delta = now - self.time_limit # calculate early to improve perf. - if times and t_delta > times[-1]: - # if last call was before the limit time-window - # used to impr. perf. in long-interval calls case - times = [now] - else: - # collect last in current limit time-window - times = [t for t in times if t >= t_delta] - times.append(now) - if len(times) >= self.burst_limit: # if throughput limit was hit - time.sleep(times[1] - t_delta) - # finally process one - try: - func, args, kwargs = item - func(*args, **kwargs) - except Exception as exc: # re-route any exceptions - self.exc_route(exc) # to prevent thread exit - - def stop(self, timeout: float = None) -> None: - """Used to gently stop processor and shutdown its thread. - - Args: - timeout (:obj:`float`): Indicates maximum time to wait for processor to stop and its - thread to exit. If timeout exceeds and processor has not stopped, method silently - returns. :attr:`is_alive` could be used afterwards to check the actual status. - ``timeout`` set to :obj:`None`, blocks until processor is shut down. - Defaults to :obj:`None`. - - """ - self.__exit_req = True # gently request - self._queue.put(None) # put something to unfreeze if frozen - super().join(timeout=timeout) - - @staticmethod - def _default_exception_handler(exc: Exception) -> NoReturn: - """ - Dummy exception handler which re-raises exception in thread. Could be possibly overwritten - by subclasses. - - """ - raise exc - - def __call__(self, func: Callable, *args: object, **kwargs: object) -> None: - """Used to process callbacks in throughput-limiting thread through queue. - - Args: - func (:obj:`callable`): The actual function (or any callable) that is processed through - queue. - *args (:obj:`list`): Variable-length `func` arguments. - **kwargs (:obj:`dict`): Arbitrary keyword-arguments to `func`. - - """ - if not self.is_alive() or self.__exit_req: - raise DelayQueueError('Could not process callback in stopped thread') - self._queue.put((func, args, kwargs)) - - -# The most straightforward way to implement this is to use 2 sequential delay -# queues, like on classic delay chain schematics in electronics. -# So, message path is: -# msg --> group delay if group msg, else no delay --> normal msg delay --> out -# This way OS threading scheduler cares of timings accuracy. -# (see time.time, time.clock, time.perf_counter, time.sleep @ docs.python.org) -class MessageQueue: - """ - Implements callback processing with proper delays to avoid hitting Telegram's message limits. - Contains two ``DelayQueue``, for group and for all messages, interconnected in delay chain. - Callables are processed through *group* ``DelayQueue``, then through *all* ``DelayQueue`` for - group-type messages. For non-group messages, only the *all* ``DelayQueue`` is used. - - .. deprecated:: 13.3 - :class:`telegram.ext.MessageQueue` in its current form is deprecated and will be reinvented - in a future release. See `this thread <https://git.io/JtDbF>`_ for a list of known bugs. - - Args: - all_burst_limit (:obj:`int`, optional): Number of maximum *all-type* callbacks to process - per time-window defined by :attr:`all_time_limit_ms`. Defaults to 30. - all_time_limit_ms (:obj:`int`, optional): Defines width of *all-type* time-window used when - each processing limit is calculated. Defaults to 1000 ms. - group_burst_limit (:obj:`int`, optional): Number of maximum *group-type* callbacks to - process per time-window defined by :attr:`group_time_limit_ms`. Defaults to 20. - group_time_limit_ms (:obj:`int`, optional): Defines width of *group-type* time-window used - when each processing limit is calculated. Defaults to 60000 ms. - exc_route (:obj:`callable`, optional): A callable, accepting one positional argument; used - to route exceptions from processor threads to main thread; is called on ``Exception`` - subclass exceptions. If not provided, exceptions are routed through dummy handler, - which re-raises them. - autostart (:obj:`bool`, optional): If :obj:`True`, processors are started immediately after - object's creation; if :obj:`False`, should be started manually by :attr:`start` method. - Defaults to :obj:`True`. - - """ - - def __init__( - self, - all_burst_limit: int = 30, - all_time_limit_ms: int = 1000, - group_burst_limit: int = 20, - group_time_limit_ms: int = 60000, - exc_route: Callable[[Exception], None] = None, - autostart: bool = True, - ): - warnings.warn( - 'MessageQueue in its current form is deprecated and will be reinvented in a future ' - 'release. See https://git.io/JtDbF for a list of known bugs.', - category=TelegramDeprecationWarning, - ) - - # create according delay queues, use composition - self._all_delayq = DelayQueue( - burst_limit=all_burst_limit, - time_limit_ms=all_time_limit_ms, - exc_route=exc_route, - autostart=autostart, - ) - self._group_delayq = DelayQueue( - burst_limit=group_burst_limit, - time_limit_ms=group_time_limit_ms, - exc_route=exc_route, - autostart=autostart, - ) - - def start(self) -> None: - """Method is used to manually start the ``MessageQueue`` processing.""" - self._all_delayq.start() - self._group_delayq.start() - - def stop(self, timeout: float = None) -> None: - """Stops the ``MessageQueue``.""" - self._group_delayq.stop(timeout=timeout) - self._all_delayq.stop(timeout=timeout) - - stop.__doc__ = DelayQueue.stop.__doc__ or '' # reuse docstring if any - - def __call__(self, promise: Callable, is_group_msg: bool = False) -> Callable: - """ - Processes callables in throughput-limiting queues to avoid hitting limits (specified with - :attr:`burst_limit` and :attr:`time_limit`. - - Args: - promise (:obj:`callable`): Mainly the ``telegram.utils.promise.Promise`` (see Notes for - other callables), that is processed in delay queues. - is_group_msg (:obj:`bool`, optional): Defines whether ``promise`` would be processed in - group*+*all* ``DelayQueue``s (if set to :obj:`True`), or only through *all* - ``DelayQueue`` (if set to :obj:`False`), resulting in needed delays to avoid - hitting specified limits. Defaults to :obj:`False`. - - Note: - Method is designed to accept ``telegram.utils.promise.Promise`` as ``promise`` - argument, but other callables could be used too. For example, lambdas or simple - functions could be used to wrap original func to be called with needed args. In that - case, be sure that either wrapper func does not raise outside exceptions or the proper - :attr:`exc_route` handler is provided. - - Returns: - :obj:`callable`: Used as ``promise`` argument. - - """ - if not is_group_msg: # ignore middle group delay - self._all_delayq(promise) - else: # use middle group delay - self._group_delayq(self._all_delayq, promise) - return promise - - -def queuedmessage(method: Callable) -> Callable: - """A decorator to be used with :attr:`telegram.Bot` send* methods. - - Note: - As it probably wouldn't be a good idea to make this decorator a property, it has been coded - as decorator function, so it implies that first positional argument to wrapped MUST be - self. - - The next object attributes are used by decorator: - - Attributes: - self._is_messages_queued_default (:obj:`bool`): Value to provide class-defaults to - ``queued`` kwarg if not provided during wrapped method call. - self._msg_queue (:class:`telegram.ext.messagequeue.MessageQueue`): The actual - ``MessageQueue`` used to delay outbound messages according to specified time-limits. - - Wrapped method starts accepting the next kwargs: - - Args: - queued (:obj:`bool`, optional): If set to :obj:`True`, the ``MessageQueue`` is used to - process output messages. Defaults to `self._is_queued_out`. - isgroup (:obj:`bool`, optional): If set to :obj:`True`, the message is meant to be - group-type(as there's no obvious way to determine its type in other way at the moment). - Group-type messages could have additional processing delay according to limits set - in `self._out_queue`. Defaults to :obj:`False`. - - Returns: - ``telegram.utils.promise.Promise``: In case call is queued or original method's return - value if it's not. - - """ - - @functools.wraps(method) - def wrapped(self: 'Bot', *args: object, **kwargs: object) -> object: - # pylint: disable=W0212 - queued = kwargs.pop( - 'queued', self._is_messages_queued_default # type: ignore[attr-defined] - ) - isgroup = kwargs.pop('isgroup', False) - if queued: - prom = Promise(method, (self,) + args, kwargs) - return self._msg_queue(prom, isgroup) # type: ignore[attr-defined] - return method(self, *args, **kwargs) - - return wrapped diff --git a/venv/lib/python3.8/site-packages/telegram/ext/picklepersistence.py b/venv/lib/python3.8/site-packages/telegram/ext/picklepersistence.py deleted file mode 100644 index 3870d41..0000000 --- a/venv/lib/python3.8/site-packages/telegram/ext/picklepersistence.py +++ /dev/null @@ -1,463 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the PicklePersistence class.""" -import pickle -from collections import defaultdict -from typing import ( - Any, - Dict, - Optional, - Tuple, - overload, - cast, - DefaultDict, -) - -from telegram.ext import BasePersistence -from .utils.types import UD, CD, BD, ConversationDict, CDCData -from .contexttypes import ContextTypes - - -class PicklePersistence(BasePersistence[UD, CD, BD]): - """Using python's builtin pickle for making your bot persistent. - - Warning: - :class:`PicklePersistence` will try to replace :class:`telegram.Bot` instances by - :attr:`REPLACED_BOT` and insert the bot set with - :meth:`telegram.ext.BasePersistence.set_bot` upon loading of the data. This is to ensure - that changes to the bot apply to the saved objects, too. If you change the bots token, this - may lead to e.g. ``Chat not found`` errors. For the limitations on replacing bots see - :meth:`telegram.ext.BasePersistence.replace_bot` and - :meth:`telegram.ext.BasePersistence.insert_bot`. - - Args: - filename (:obj:`str`): The filename for storing the pickle files. When :attr:`single_file` - is :obj:`False` this will be used as a prefix. - store_user_data (:obj:`bool`, optional): Whether user_data should be saved by this - persistence class. Default is :obj:`True`. - store_chat_data (:obj:`bool`, optional): Whether chat_data should be saved by this - persistence class. Default is :obj:`True`. - store_bot_data (:obj:`bool`, optional): Whether bot_data should be saved by this - persistence class. Default is :obj:`True`. - store_callback_data (:obj:`bool`, optional): Whether callback_data should be saved by this - persistence class. Default is :obj:`False`. - - .. versionadded:: 13.6 - single_file (:obj:`bool`, optional): When :obj:`False` will store 5 separate files of - `filename_user_data`, `filename_chat_data`, `filename_bot_data`, `filename_chat_data`, - `filename_callback_data` and `filename_conversations`. Default is :obj:`True`. - on_flush (:obj:`bool`, optional): When :obj:`True` will only save to file when - :meth:`flush` is called and keep data in memory until that happens. When - :obj:`False` will store data on any transaction *and* on call to :meth:`flush`. - Default is :obj:`False`. - context_types (:class:`telegram.ext.ContextTypes`, optional): Pass an instance - of :class:`telegram.ext.ContextTypes` to customize the types used in the - ``context`` interface. If not passed, the defaults documented in - :class:`telegram.ext.ContextTypes` will be used. - - .. versionadded:: 13.6 - - Attributes: - filename (:obj:`str`): The filename for storing the pickle files. When :attr:`single_file` - is :obj:`False` this will be used as a prefix. - store_user_data (:obj:`bool`): Optional. Whether user_data should be saved by this - persistence class. - store_chat_data (:obj:`bool`): Optional. Whether chat_data should be saved by this - persistence class. - store_bot_data (:obj:`bool`): Optional. Whether bot_data should be saved by this - persistence class. - store_callback_data (:obj:`bool`): Optional. Whether callback_data be saved by this - persistence class. - - .. versionadded:: 13.6 - single_file (:obj:`bool`): Optional. When :obj:`False` will store 5 separate files of - `filename_user_data`, `filename_chat_data`, `filename_bot_data`, `filename_chat_data`, - `filename_callback_data` and `filename_conversations`. Default is :obj:`True`. - on_flush (:obj:`bool`, optional): When :obj:`True` will only save to file when - :meth:`flush` is called and keep data in memory until that happens. When - :obj:`False` will store data on any transaction *and* on call to :meth:`flush`. - Default is :obj:`False`. - context_types (:class:`telegram.ext.ContextTypes`): Container for the types used - in the ``context`` interface. - - .. versionadded:: 13.6 - """ - - __slots__ = ( - 'filename', - 'single_file', - 'on_flush', - 'user_data', - 'chat_data', - 'bot_data', - 'callback_data', - 'conversations', - 'context_types', - ) - - @overload - def __init__( - self: 'PicklePersistence[Dict, Dict, Dict]', - filename: str, - store_user_data: bool = True, - store_chat_data: bool = True, - store_bot_data: bool = True, - single_file: bool = True, - on_flush: bool = False, - store_callback_data: bool = False, - ): - ... - - @overload - def __init__( - self: 'PicklePersistence[UD, CD, BD]', - filename: str, - store_user_data: bool = True, - store_chat_data: bool = True, - store_bot_data: bool = True, - single_file: bool = True, - on_flush: bool = False, - store_callback_data: bool = False, - context_types: ContextTypes[Any, UD, CD, BD] = None, - ): - ... - - def __init__( - self, - filename: str, - store_user_data: bool = True, - store_chat_data: bool = True, - store_bot_data: bool = True, - single_file: bool = True, - on_flush: bool = False, - store_callback_data: bool = False, - context_types: ContextTypes[Any, UD, CD, BD] = None, - ): - super().__init__( - store_user_data=store_user_data, - store_chat_data=store_chat_data, - store_bot_data=store_bot_data, - store_callback_data=store_callback_data, - ) - self.filename = filename - self.single_file = single_file - self.on_flush = on_flush - self.user_data: Optional[DefaultDict[int, UD]] = None - self.chat_data: Optional[DefaultDict[int, CD]] = None - self.bot_data: Optional[BD] = None - self.callback_data: Optional[CDCData] = None - self.conversations: Optional[Dict[str, Dict[Tuple, object]]] = None - self.context_types = cast(ContextTypes[Any, UD, CD, BD], context_types or ContextTypes()) - - def _load_singlefile(self) -> None: - try: - filename = self.filename - with open(self.filename, "rb") as file: - data = pickle.load(file) - self.user_data = defaultdict(self.context_types.user_data, data['user_data']) - self.chat_data = defaultdict(self.context_types.chat_data, data['chat_data']) - # For backwards compatibility with files not containing bot data - self.bot_data = data.get('bot_data', self.context_types.bot_data()) - self.callback_data = data.get('callback_data', {}) - self.conversations = data['conversations'] - except OSError: - self.conversations = {} - self.user_data = defaultdict(self.context_types.user_data) - self.chat_data = defaultdict(self.context_types.chat_data) - self.bot_data = self.context_types.bot_data() - self.callback_data = None - except pickle.UnpicklingError as exc: - raise TypeError(f"File {filename} does not contain valid pickle data") from exc - except Exception as exc: - raise TypeError(f"Something went wrong unpickling {filename}") from exc - - @staticmethod - def _load_file(filename: str) -> Any: - try: - with open(filename, "rb") as file: - return pickle.load(file) - except OSError: - return None - except pickle.UnpicklingError as exc: - raise TypeError(f"File {filename} does not contain valid pickle data") from exc - except Exception as exc: - raise TypeError(f"Something went wrong unpickling {filename}") from exc - - def _dump_singlefile(self) -> None: - with open(self.filename, "wb") as file: - data = { - 'conversations': self.conversations, - 'user_data': self.user_data, - 'chat_data': self.chat_data, - 'bot_data': self.bot_data, - 'callback_data': self.callback_data, - } - pickle.dump(data, file) - - @staticmethod - def _dump_file(filename: str, data: object) -> None: - with open(filename, "wb") as file: - pickle.dump(data, file) - - def get_user_data(self) -> DefaultDict[int, UD]: - """Returns the user_data from the pickle file if it exists or an empty :obj:`defaultdict`. - - Returns: - DefaultDict[:obj:`int`, :class:`telegram.ext.utils.types.UD`]: The restored user data. - """ - if self.user_data: - pass - elif not self.single_file: - filename = f"{self.filename}_user_data" - data = self._load_file(filename) - if not data: - data = defaultdict(self.context_types.user_data) - else: - data = defaultdict(self.context_types.user_data, data) - self.user_data = data - else: - self._load_singlefile() - return self.user_data # type: ignore[return-value] - - def get_chat_data(self) -> DefaultDict[int, CD]: - """Returns the chat_data from the pickle file if it exists or an empty :obj:`defaultdict`. - - Returns: - DefaultDict[:obj:`int`, :class:`telegram.ext.utils.types.CD`]: The restored chat data. - """ - if self.chat_data: - pass - elif not self.single_file: - filename = f"{self.filename}_chat_data" - data = self._load_file(filename) - if not data: - data = defaultdict(self.context_types.chat_data) - else: - data = defaultdict(self.context_types.chat_data, data) - self.chat_data = data - else: - self._load_singlefile() - return self.chat_data # type: ignore[return-value] - - def get_bot_data(self) -> BD: - """Returns the bot_data from the pickle file if it exists or an empty object of type - :class:`telegram.ext.utils.types.BD`. - - Returns: - :class:`telegram.ext.utils.types.BD`: The restored bot data. - """ - if self.bot_data: - pass - elif not self.single_file: - filename = f"{self.filename}_bot_data" - data = self._load_file(filename) - if not data: - data = self.context_types.bot_data() - self.bot_data = data - else: - self._load_singlefile() - return self.bot_data # type: ignore[return-value] - - def get_callback_data(self) -> Optional[CDCData]: - """Returns the callback data from the pickle file if it exists or :obj:`None`. - - .. versionadded:: 13.6 - - Returns: - Optional[:class:`telegram.ext.utils.types.CDCData`]: The restored meta data or - :obj:`None`, if no data was stored. - """ - if self.callback_data: - pass - elif not self.single_file: - filename = f"{self.filename}_callback_data" - data = self._load_file(filename) - if not data: - data = None - self.callback_data = data - else: - self._load_singlefile() - if self.callback_data is None: - return None - return self.callback_data[0], self.callback_data[1].copy() - - def get_conversations(self, name: str) -> ConversationDict: - """Returns the conversations from the pickle file if it exists or an empty dict. - - Args: - name (:obj:`str`): The handlers name. - - Returns: - :obj:`dict`: The restored conversations for the handler. - """ - if self.conversations: - pass - elif not self.single_file: - filename = f"{self.filename}_conversations" - data = self._load_file(filename) - if not data: - data = {name: {}} - self.conversations = data - else: - self._load_singlefile() - return self.conversations.get(name, {}).copy() # type: ignore[union-attr] - - def update_conversation( - self, name: str, key: Tuple[int, ...], new_state: Optional[object] - ) -> None: - """Will update the conversations for the given handler and depending on :attr:`on_flush` - save the pickle file. - - Args: - name (:obj:`str`): The handler's name. - key (:obj:`tuple`): The key the state is changed for. - new_state (:obj:`tuple` | :obj:`any`): The new state for the given key. - """ - if not self.conversations: - self.conversations = {} - if self.conversations.setdefault(name, {}).get(key) == new_state: - return - self.conversations[name][key] = new_state - if not self.on_flush: - if not self.single_file: - filename = f"{self.filename}_conversations" - self._dump_file(filename, self.conversations) - else: - self._dump_singlefile() - - def update_user_data(self, user_id: int, data: UD) -> None: - """Will update the user_data and depending on :attr:`on_flush` save the pickle file. - - Args: - user_id (:obj:`int`): The user the data might have been changed for. - data (:class:`telegram.ext.utils.types.UD`): The - :attr:`telegram.ext.dispatcher.user_data` ``[user_id]``. - """ - if self.user_data is None: - self.user_data = defaultdict(self.context_types.user_data) - if self.user_data.get(user_id) == data: - return - self.user_data[user_id] = data - if not self.on_flush: - if not self.single_file: - filename = f"{self.filename}_user_data" - self._dump_file(filename, self.user_data) - else: - self._dump_singlefile() - - def update_chat_data(self, chat_id: int, data: CD) -> None: - """Will update the chat_data and depending on :attr:`on_flush` save the pickle file. - - Args: - chat_id (:obj:`int`): The chat the data might have been changed for. - data (:class:`telegram.ext.utils.types.CD`): The - :attr:`telegram.ext.dispatcher.chat_data` ``[chat_id]``. - """ - if self.chat_data is None: - self.chat_data = defaultdict(self.context_types.chat_data) - if self.chat_data.get(chat_id) == data: - return - self.chat_data[chat_id] = data - if not self.on_flush: - if not self.single_file: - filename = f"{self.filename}_chat_data" - self._dump_file(filename, self.chat_data) - else: - self._dump_singlefile() - - def update_bot_data(self, data: BD) -> None: - """Will update the bot_data and depending on :attr:`on_flush` save the pickle file. - - Args: - data (:class:`telegram.ext.utils.types.BD`): The - :attr:`telegram.ext.dispatcher.bot_data`. - """ - if self.bot_data == data: - return - self.bot_data = data - if not self.on_flush: - if not self.single_file: - filename = f"{self.filename}_bot_data" - self._dump_file(filename, self.bot_data) - else: - self._dump_singlefile() - - def update_callback_data(self, data: CDCData) -> None: - """Will update the callback_data (if changed) and depending on :attr:`on_flush` save the - pickle file. - - .. versionadded:: 13.6 - - Args: - data (:class:`telegram.ext.utils.types.CDCData`:): The relevant data to restore - :attr:`telegram.ext.dispatcher.bot.callback_data`. - """ - if self.callback_data == data: - return - self.callback_data = (data[0], data[1].copy()) - if not self.on_flush: - if not self.single_file: - filename = f"{self.filename}_callback_data" - self._dump_file(filename, self.callback_data) - else: - self._dump_singlefile() - - def refresh_user_data(self, user_id: int, user_data: UD) -> None: - """Does nothing. - - .. versionadded:: 13.6 - .. seealso:: :meth:`telegram.ext.BasePersistence.refresh_user_data` - """ - - def refresh_chat_data(self, chat_id: int, chat_data: CD) -> None: - """Does nothing. - - .. versionadded:: 13.6 - .. seealso:: :meth:`telegram.ext.BasePersistence.refresh_chat_data` - """ - - def refresh_bot_data(self, bot_data: BD) -> None: - """Does nothing. - - .. versionadded:: 13.6 - .. seealso:: :meth:`telegram.ext.BasePersistence.refresh_bot_data` - """ - - def flush(self) -> None: - """Will save all data in memory to pickle file(s).""" - if self.single_file: - if ( - self.user_data - or self.chat_data - or self.bot_data - or self.callback_data - or self.conversations - ): - self._dump_singlefile() - else: - if self.user_data: - self._dump_file(f"{self.filename}_user_data", self.user_data) - if self.chat_data: - self._dump_file(f"{self.filename}_chat_data", self.chat_data) - if self.bot_data: - self._dump_file(f"{self.filename}_bot_data", self.bot_data) - if self.callback_data: - self._dump_file(f"{self.filename}_callback_data", self.callback_data) - if self.conversations: - self._dump_file(f"{self.filename}_conversations", self.conversations) diff --git a/venv/lib/python3.8/site-packages/telegram/ext/pollanswerhandler.py b/venv/lib/python3.8/site-packages/telegram/ext/pollanswerhandler.py deleted file mode 100644 index 199bcb3..0000000 --- a/venv/lib/python3.8/site-packages/telegram/ext/pollanswerhandler.py +++ /dev/null @@ -1,98 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2019-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the PollAnswerHandler class.""" - - -from telegram import Update - -from .handler import Handler -from .utils.types import CCT - - -class PollAnswerHandler(Handler[Update, CCT]): - """Handler class to handle Telegram updates that contain a poll answer. - - Note: - :attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you - can use to keep any data in will be sent to the :attr:`callback` function. Related to - either the user or the chat that the update was sent in. For each update from the same user - or in the same chat, it will be the same ``dict``. - - Note that this is DEPRECATED, and you should use context based callbacks. See - https://git.io/fxJuV for more info. - - Warning: - When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - Args: - callback (:obj:`callable`): The callback function for this handler. Will be called when - :attr:`check_update` has determined that an update should be processed by this handler. - Callback signature for context based API: - - ``def callback(update: Update, context: CallbackContext)`` - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``update_queue`` will be passed to the callback function. It will be the ``Queue`` - instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher` - that contains new updates which can be used to insert updates. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``job_queue`` will be passed to the callback function. It will be a - :class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater` - which can be used to schedule new jobs. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``user_data`` will be passed to the callback function. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``chat_data`` will be passed to the callback function. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - run_async (:obj:`bool`): Determines whether the callback will run asynchronously. - Defaults to :obj:`False`. - - Attributes: - callback (:obj:`callable`): The callback function for this handler. - pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be - passed to the callback function. - pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to - the callback function. - pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to - the callback function. - pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to - the callback function. - run_async (:obj:`bool`): Determines whether the callback will run asynchronously. - - """ - - __slots__ = () - - def check_update(self, update: object) -> bool: - """Determines whether an update should be passed to this handlers :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - return isinstance(update, Update) and bool(update.poll_answer) diff --git a/venv/lib/python3.8/site-packages/telegram/ext/pollhandler.py b/venv/lib/python3.8/site-packages/telegram/ext/pollhandler.py deleted file mode 100644 index 7b67e76..0000000 --- a/venv/lib/python3.8/site-packages/telegram/ext/pollhandler.py +++ /dev/null @@ -1,98 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2019-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the PollHandler classes.""" - - -from telegram import Update - -from .handler import Handler -from .utils.types import CCT - - -class PollHandler(Handler[Update, CCT]): - """Handler class to handle Telegram updates that contain a poll. - - Note: - :attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you - can use to keep any data in will be sent to the :attr:`callback` function. Related to - either the user or the chat that the update was sent in. For each update from the same user - or in the same chat, it will be the same ``dict``. - - Note that this is DEPRECATED, and you should use context based callbacks. See - https://git.io/fxJuV for more info. - - Warning: - When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - Args: - callback (:obj:`callable`): The callback function for this handler. Will be called when - :attr:`check_update` has determined that an update should be processed by this handler. - Callback signature for context based API: - - ``def callback(update: Update, context: CallbackContext)`` - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``update_queue`` will be passed to the callback function. It will be the ``Queue`` - instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher` - that contains new updates which can be used to insert updates. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``job_queue`` will be passed to the callback function. It will be a - :class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater` - which can be used to schedule new jobs. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``user_data`` will be passed to the callback function. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``chat_data`` will be passed to the callback function. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - run_async (:obj:`bool`): Determines whether the callback will run asynchronously. - Defaults to :obj:`False`. - - Attributes: - callback (:obj:`callable`): The callback function for this handler. - pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be - passed to the callback function. - pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to - the callback function. - pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to - the callback function. - pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to - the callback function. - run_async (:obj:`bool`): Determines whether the callback will run asynchronously. - - """ - - __slots__ = () - - def check_update(self, update: object) -> bool: - """Determines whether an update should be passed to this handlers :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - return isinstance(update, Update) and bool(update.poll) diff --git a/venv/lib/python3.8/site-packages/telegram/ext/precheckoutqueryhandler.py b/venv/lib/python3.8/site-packages/telegram/ext/precheckoutqueryhandler.py deleted file mode 100644 index 3a2eee3..0000000 --- a/venv/lib/python3.8/site-packages/telegram/ext/precheckoutqueryhandler.py +++ /dev/null @@ -1,98 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the PreCheckoutQueryHandler class.""" - - -from telegram import Update - -from .handler import Handler -from .utils.types import CCT - - -class PreCheckoutQueryHandler(Handler[Update, CCT]): - """Handler class to handle Telegram PreCheckout callback queries. - - Note: - :attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you - can use to keep any data in will be sent to the :attr:`callback` function. Related to - either the user or the chat that the update was sent in. For each update from the same user - or in the same chat, it will be the same ``dict``. - - Note that this is DEPRECATED, and you should use context based callbacks. See - https://git.io/fxJuV for more info. - - Warning: - When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - Args: - callback (:obj:`callable`): The callback function for this handler. Will be called when - :attr:`check_update` has determined that an update should be processed by this handler. - Callback signature for context based API: - - ``def callback(update: Update, context: CallbackContext)`` - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``update_queue`` will be passed to the callback function. It will be the ``Queue`` - DEPRECATED: Please switch to context based callbacks. - instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher` - that contains new updates which can be used to insert updates. Default is :obj:`False`. - pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``job_queue`` will be passed to the callback function. It will be a - :class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater` - which can be used to schedule new jobs. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``user_data`` will be passed to the callback function. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``chat_data`` will be passed to the callback function. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - run_async (:obj:`bool`): Determines whether the callback will run asynchronously. - Defaults to :obj:`False`. - - Attributes: - callback (:obj:`callable`): The callback function for this handler. - pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be - passed to the callback function. - pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to - the callback function. - pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to - the callback function. - pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to - the callback function. - run_async (:obj:`bool`): Determines whether the callback will run asynchronously. - - """ - - __slots__ = () - - def check_update(self, update: object) -> bool: - """Determines whether an update should be passed to this handlers :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - return isinstance(update, Update) and bool(update.pre_checkout_query) diff --git a/venv/lib/python3.8/site-packages/telegram/ext/regexhandler.py b/venv/lib/python3.8/site-packages/telegram/ext/regexhandler.py deleted file mode 100644 index 399e4df..0000000 --- a/venv/lib/python3.8/site-packages/telegram/ext/regexhandler.py +++ /dev/null @@ -1,166 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -# TODO: Remove allow_edited -"""This module contains the RegexHandler class.""" - -import warnings -from typing import TYPE_CHECKING, Callable, Dict, Optional, Pattern, TypeVar, Union, Any - -from telegram import Update -from telegram.ext import Filters, MessageHandler -from telegram.utils.deprecate import TelegramDeprecationWarning -from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE -from telegram.ext.utils.types import CCT - -if TYPE_CHECKING: - from telegram.ext import Dispatcher - -RT = TypeVar('RT') - - -class RegexHandler(MessageHandler): - """Handler class to handle Telegram updates based on a regex. - - It uses a regular expression to check text messages. Read the documentation of the ``re`` - module for more information. The ``re.match`` function is used to determine if an update should - be handled by this handler. - - Note: - This handler is being deprecated. For the same use case use: - ``MessageHandler(Filters.regex(r'pattern'), callback)`` - - Warning: - When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - - Args: - pattern (:obj:`str` | :obj:`Pattern`): The regex pattern. - callback (:obj:`callable`): The callback function for this handler. Will be called when - :attr:`check_update` has determined that an update should be processed by this handler. - Callback signature for context based API: - - ``def callback(update: Update, context: CallbackContext)`` - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - pass_groups (:obj:`bool`, optional): If the callback should be passed the result of - ``re.match(pattern, data).groups()`` as a keyword argument called ``groups``. - Default is :obj:`False` - pass_groupdict (:obj:`bool`, optional): If the callback should be passed the result of - ``re.match(pattern, data).groupdict()`` as a keyword argument called ``groupdict``. - Default is :obj:`False` - pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``update_queue`` will be passed to the callback function. It will be the ``Queue`` - instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher` - that contains new updates which can be used to insert updates. Default is :obj:`False`. - pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``job_queue`` will be passed to the callback function. It will be a - :class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater` - which can be used to schedule new jobs. Default is :obj:`False`. - pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``user_data`` will be passed to the callback function. Default is :obj:`False`. - pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``chat_data`` will be passed to the callback function. Default is :obj:`False`. - message_updates (:obj:`bool`, optional): Should "normal" message updates be handled? - Default is :obj:`True`. - channel_post_updates (:obj:`bool`, optional): Should channel posts updates be handled? - Default is :obj:`True`. - edited_updates (:obj:`bool`, optional): Should "edited" message updates be handled? Default - is :obj:`False`. - run_async (:obj:`bool`): Determines whether the callback will run asynchronously. - Defaults to :obj:`False`. - - Raises: - ValueError - - Attributes: - pattern (:obj:`str` | :obj:`Pattern`): The regex pattern. - callback (:obj:`callable`): The callback function for this handler. - pass_groups (:obj:`bool`): Determines whether ``groups`` will be passed to the - callback function. - pass_groupdict (:obj:`bool`): Determines whether ``groupdict``. will be passed to - the callback function. - pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be - passed to the callback function. - pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to - the callback function. - pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to - the callback function. - pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to - the callback function. - run_async (:obj:`bool`): Determines whether the callback will run asynchronously. - - """ - - __slots__ = ('pass_groups', 'pass_groupdict') - - def __init__( - self, - pattern: Union[str, Pattern], - callback: Callable[[Update, CCT], RT], - pass_groups: bool = False, - pass_groupdict: bool = False, - pass_update_queue: bool = False, - pass_job_queue: bool = False, - pass_user_data: bool = False, - pass_chat_data: bool = False, - allow_edited: bool = False, # pylint: disable=W0613 - message_updates: bool = True, - channel_post_updates: bool = False, - edited_updates: bool = False, - run_async: Union[bool, DefaultValue] = DEFAULT_FALSE, - ): - warnings.warn( - 'RegexHandler is deprecated. See https://git.io/fxJuV for more info', - TelegramDeprecationWarning, - stacklevel=2, - ) - super().__init__( - Filters.regex(pattern), - callback, - pass_update_queue=pass_update_queue, - pass_job_queue=pass_job_queue, - pass_user_data=pass_user_data, - pass_chat_data=pass_chat_data, - message_updates=message_updates, - channel_post_updates=channel_post_updates, - edited_updates=edited_updates, - run_async=run_async, - ) - self.pass_groups = pass_groups - self.pass_groupdict = pass_groupdict - - def collect_optional_args( - self, - dispatcher: 'Dispatcher', - update: Update = None, - check_result: Optional[Union[bool, Dict[str, Any]]] = None, - ) -> Dict[str, object]: - """Pass the results of ``re.match(pattern, text).{groups(), groupdict()}`` to the - callback as a keyword arguments called ``groups`` and ``groupdict``, respectively, if - needed. - """ - optional_args = super().collect_optional_args(dispatcher, update, check_result) - if isinstance(check_result, dict): - if self.pass_groups: - optional_args['groups'] = check_result['matches'][0].groups() - if self.pass_groupdict: - optional_args['groupdict'] = check_result['matches'][0].groupdict() - return optional_args diff --git a/venv/lib/python3.8/site-packages/telegram/ext/shippingqueryhandler.py b/venv/lib/python3.8/site-packages/telegram/ext/shippingqueryhandler.py deleted file mode 100644 index e4229ce..0000000 --- a/venv/lib/python3.8/site-packages/telegram/ext/shippingqueryhandler.py +++ /dev/null @@ -1,97 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the ShippingQueryHandler class.""" - - -from telegram import Update -from .handler import Handler -from .utils.types import CCT - - -class ShippingQueryHandler(Handler[Update, CCT]): - """Handler class to handle Telegram shipping callback queries. - - Note: - :attr:`pass_user_data` and :attr:`pass_chat_data` determine whether a ``dict`` you - can use to keep any data in will be sent to the :attr:`callback` function. Related to - either the user or the chat that the update was sent in. For each update from the same user - or in the same chat, it will be the same ``dict``. - - Note that this is DEPRECATED, and you should use context based callbacks. See - https://git.io/fxJuV for more info. - - Warning: - When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - Args: - callback (:obj:`callable`): The callback function for this handler. Will be called when - :attr:`check_update` has determined that an update should be processed by this handler. - Callback signature for context based API: - - ``def callback(update: Update, context: CallbackContext)`` - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``update_queue`` will be passed to the callback function. It will be the ``Queue`` - instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher` - that contains new updates which can be used to insert updates. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``job_queue`` will be passed to the callback function. It will be a - :class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater` - which can be used to schedule new jobs. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - pass_user_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``user_data`` will be passed to the callback function. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - pass_chat_data (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``chat_data`` will be passed to the callback function. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - run_async (:obj:`bool`): Determines whether the callback will run asynchronously. - Defaults to :obj:`False`. - - Attributes: - callback (:obj:`callable`): The callback function for this handler. - pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be - passed to the callback function. - pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to - the callback function. - pass_user_data (:obj:`bool`): Determines whether ``user_data`` will be passed to - the callback function. - pass_chat_data (:obj:`bool`): Determines whether ``chat_data`` will be passed to - the callback function. - run_async (:obj:`bool`): Determines whether the callback will run asynchronously. - - """ - - __slots__ = () - - def check_update(self, update: object) -> bool: - """Determines whether an update should be passed to this handlers :attr:`callback`. - - Args: - update (:class:`telegram.Update` | :obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - return isinstance(update, Update) and bool(update.shipping_query) diff --git a/venv/lib/python3.8/site-packages/telegram/ext/stringcommandhandler.py b/venv/lib/python3.8/site-packages/telegram/ext/stringcommandhandler.py deleted file mode 100644 index 1d84892..0000000 --- a/venv/lib/python3.8/site-packages/telegram/ext/stringcommandhandler.py +++ /dev/null @@ -1,149 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the StringCommandHandler class.""" - -from typing import TYPE_CHECKING, Callable, Dict, List, Optional, TypeVar, Union - -from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE - -from .handler import Handler -from .utils.types import CCT - -if TYPE_CHECKING: - from telegram.ext import Dispatcher - -RT = TypeVar('RT') - - -class StringCommandHandler(Handler[str, CCT]): - """Handler class to handle string commands. Commands are string updates that start with ``/``. - The handler will add a ``list`` to the - :class:`CallbackContext` named :attr:`CallbackContext.args`. It will contain a list of strings, - which is the text following the command split on single whitespace characters. - - Note: - This handler is not used to handle Telegram :attr:`telegram.Update`, but strings manually - put in the queue. For example to send messages with the bot using command line or API. - - Warning: - When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - Args: - command (:obj:`str`): The command this handler should listen for. - callback (:obj:`callable`): The callback function for this handler. Will be called when - :attr:`check_update` has determined that an update should be processed by this handler. - Callback signature for context based API: - - ``def callback(update: Update, context: CallbackContext)`` - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - pass_args (:obj:`bool`, optional): Determines whether the handler should be passed the - arguments passed to the command as a keyword argument called ``args``. It will contain - a list of strings, which is the text following the command split on single or - consecutive whitespace characters. Default is :obj:`False` - DEPRECATED: Please switch to context based callbacks. - pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``update_queue`` will be passed to the callback function. It will be the ``Queue`` - instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher` - that contains new updates which can be used to insert updates. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``job_queue`` will be passed to the callback function. It will be a - class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater` - which can be used to schedule new jobs. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - run_async (:obj:`bool`): Determines whether the callback will run asynchronously. - Defaults to :obj:`False`. - - Attributes: - command (:obj:`str`): The command this handler should listen for. - callback (:obj:`callable`): The callback function for this handler. - pass_args (:obj:`bool`): Determines whether the handler should be passed - ``args``. - pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be - passed to the callback function. - pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to - the callback function. - run_async (:obj:`bool`): Determines whether the callback will run asynchronously. - - """ - - __slots__ = ('command', 'pass_args') - - def __init__( - self, - command: str, - callback: Callable[[str, CCT], RT], - pass_args: bool = False, - pass_update_queue: bool = False, - pass_job_queue: bool = False, - run_async: Union[bool, DefaultValue] = DEFAULT_FALSE, - ): - super().__init__( - callback, - pass_update_queue=pass_update_queue, - pass_job_queue=pass_job_queue, - run_async=run_async, - ) - self.command = command - self.pass_args = pass_args - - def check_update(self, update: object) -> Optional[List[str]]: - """Determines whether an update should be passed to this handlers :attr:`callback`. - - Args: - update (:obj:`object`): The incoming update. - - Returns: - :obj:`bool` - - """ - if isinstance(update, str) and update.startswith('/'): - args = update[1:].split(' ') - if args[0] == self.command: - return args[1:] - return None - - def collect_optional_args( - self, - dispatcher: 'Dispatcher', - update: str = None, - check_result: Optional[List[str]] = None, - ) -> Dict[str, object]: - """Provide text after the command to the callback the ``args`` argument as list, split on - single whitespaces. - """ - optional_args = super().collect_optional_args(dispatcher, update, check_result) - if self.pass_args: - optional_args['args'] = check_result - return optional_args - - def collect_additional_context( - self, - context: CCT, - update: str, - dispatcher: 'Dispatcher', - check_result: Optional[List[str]], - ) -> None: - """Add text after the command to :attr:`CallbackContext.args` as list, split on single - whitespaces. - """ - context.args = check_result diff --git a/venv/lib/python3.8/site-packages/telegram/ext/stringregexhandler.py b/venv/lib/python3.8/site-packages/telegram/ext/stringregexhandler.py deleted file mode 100644 index 282c48a..0000000 --- a/venv/lib/python3.8/site-packages/telegram/ext/stringregexhandler.py +++ /dev/null @@ -1,166 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the StringRegexHandler class.""" - -import re -from typing import TYPE_CHECKING, Callable, Dict, Match, Optional, Pattern, TypeVar, Union - -from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE - -from .handler import Handler -from .utils.types import CCT - -if TYPE_CHECKING: - from telegram.ext import Dispatcher - -RT = TypeVar('RT') - - -class StringRegexHandler(Handler[str, CCT]): - """Handler class to handle string updates based on a regex which checks the update content. - - Read the documentation of the ``re`` module for more information. The ``re.match`` function is - used to determine if an update should be handled by this handler. - - Note: - This handler is not used to handle Telegram :attr:`telegram.Update`, but strings manually - put in the queue. For example to send messages with the bot using command line or API. - - Warning: - When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - Args: - pattern (:obj:`str` | :obj:`Pattern`): The regex pattern. - callback (:obj:`callable`): The callback function for this handler. Will be called when - :attr:`check_update` has determined that an update should be processed by this handler. - Callback signature for context based API: - - ``def callback(update: Update, context: CallbackContext)`` - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - pass_groups (:obj:`bool`, optional): If the callback should be passed the result of - ``re.match(pattern, data).groups()`` as a keyword argument called ``groups``. - Default is :obj:`False` - DEPRECATED: Please switch to context based callbacks. - pass_groupdict (:obj:`bool`, optional): If the callback should be passed the result of - ``re.match(pattern, data).groupdict()`` as a keyword argument called ``groupdict``. - Default is :obj:`False` - DEPRECATED: Please switch to context based callbacks. - pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``update_queue`` will be passed to the callback function. It will be the ``Queue`` - instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher` - that contains new updates which can be used to insert updates. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``job_queue`` will be passed to the callback function. It will be a - :class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater` - which can be used to schedule new jobs. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - run_async (:obj:`bool`): Determines whether the callback will run asynchronously. - Defaults to :obj:`False`. - - Attributes: - pattern (:obj:`str` | :obj:`Pattern`): The regex pattern. - callback (:obj:`callable`): The callback function for this handler. - pass_groups (:obj:`bool`): Determines whether ``groups`` will be passed to the - callback function. - pass_groupdict (:obj:`bool`): Determines whether ``groupdict``. will be passed to - the callback function. - pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be - passed to the callback function. - pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to - the callback function. - run_async (:obj:`bool`): Determines whether the callback will run asynchronously. - - """ - - __slots__ = ('pass_groups', 'pass_groupdict', 'pattern') - - def __init__( - self, - pattern: Union[str, Pattern], - callback: Callable[[str, CCT], RT], - pass_groups: bool = False, - pass_groupdict: bool = False, - pass_update_queue: bool = False, - pass_job_queue: bool = False, - run_async: Union[bool, DefaultValue] = DEFAULT_FALSE, - ): - super().__init__( - callback, - pass_update_queue=pass_update_queue, - pass_job_queue=pass_job_queue, - run_async=run_async, - ) - - if isinstance(pattern, str): - pattern = re.compile(pattern) - - self.pattern = pattern - self.pass_groups = pass_groups - self.pass_groupdict = pass_groupdict - - def check_update(self, update: object) -> Optional[Match]: - """Determines whether an update should be passed to this handlers :attr:`callback`. - - Args: - update (:obj:`object`): The incoming update. - - Returns: - :obj:`bool` - - """ - if isinstance(update, str): - match = re.match(self.pattern, update) - if match: - return match - return None - - def collect_optional_args( - self, - dispatcher: 'Dispatcher', - update: str = None, - check_result: Optional[Match] = None, - ) -> Dict[str, object]: - """Pass the results of ``re.match(pattern, update).{groups(), groupdict()}`` to the - callback as a keyword arguments called ``groups`` and ``groupdict``, respectively, if - needed. - """ - optional_args = super().collect_optional_args(dispatcher, update, check_result) - if self.pattern: - if self.pass_groups and check_result: - optional_args['groups'] = check_result.groups() - if self.pass_groupdict and check_result: - optional_args['groupdict'] = check_result.groupdict() - return optional_args - - def collect_additional_context( - self, - context: CCT, - update: str, - dispatcher: 'Dispatcher', - check_result: Optional[Match], - ) -> None: - """Add the result of ``re.match(pattern, update)`` to :attr:`CallbackContext.matches` as - list with one element. - """ - if self.pattern and check_result: - context.matches = [check_result] diff --git a/venv/lib/python3.8/site-packages/telegram/ext/typehandler.py b/venv/lib/python3.8/site-packages/telegram/ext/typehandler.py deleted file mode 100644 index 531d10c..0000000 --- a/venv/lib/python3.8/site-packages/telegram/ext/typehandler.py +++ /dev/null @@ -1,108 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the TypeHandler class.""" - -from typing import Callable, Type, TypeVar, Union -from telegram.utils.helpers import DefaultValue, DEFAULT_FALSE - -from .handler import Handler -from .utils.types import CCT - -RT = TypeVar('RT') -UT = TypeVar('UT') - - -class TypeHandler(Handler[UT, CCT]): - """Handler class to handle updates of custom types. - - Warning: - When setting ``run_async`` to :obj:`True`, you cannot rely on adding custom - attributes to :class:`telegram.ext.CallbackContext`. See its docs for more info. - - Args: - type (:obj:`type`): The ``type`` of updates this handler should process, as - determined by ``isinstance`` - callback (:obj:`callable`): The callback function for this handler. Will be called when - :attr:`check_update` has determined that an update should be processed by this handler. - Callback signature for context based API: - - ``def callback(update: Update, context: CallbackContext)`` - - The return value of the callback is usually ignored except for the special case of - :class:`telegram.ext.ConversationHandler`. - strict (:obj:`bool`, optional): Use ``type`` instead of ``isinstance``. - Default is :obj:`False` - pass_update_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``update_queue`` will be passed to the callback function. It will be the ``Queue`` - instance used by the :class:`telegram.ext.Updater` and :class:`telegram.ext.Dispatcher` - that contains new updates which can be used to insert updates. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - pass_job_queue (:obj:`bool`, optional): If set to :obj:`True`, a keyword argument called - ``job_queue`` will be passed to the callback function. It will be a - :class:`telegram.ext.JobQueue` instance created by the :class:`telegram.ext.Updater` - which can be used to schedule new jobs. Default is :obj:`False`. - DEPRECATED: Please switch to context based callbacks. - run_async (:obj:`bool`): Determines whether the callback will run asynchronously. - Defaults to :obj:`False`. - - Attributes: - type (:obj:`type`): The ``type`` of updates this handler should process. - callback (:obj:`callable`): The callback function for this handler. - strict (:obj:`bool`): Use ``type`` instead of ``isinstance``. Default is :obj:`False`. - pass_update_queue (:obj:`bool`): Determines whether ``update_queue`` will be - passed to the callback function. - pass_job_queue (:obj:`bool`): Determines whether ``job_queue`` will be passed to - the callback function. - run_async (:obj:`bool`): Determines whether the callback will run asynchronously. - - """ - - __slots__ = ('type', 'strict') - - def __init__( - self, - type: Type[UT], # pylint: disable=W0622 - callback: Callable[[UT, CCT], RT], - strict: bool = False, - pass_update_queue: bool = False, - pass_job_queue: bool = False, - run_async: Union[bool, DefaultValue] = DEFAULT_FALSE, - ): - super().__init__( - callback, - pass_update_queue=pass_update_queue, - pass_job_queue=pass_job_queue, - run_async=run_async, - ) - self.type = type # pylint: disable=E0237 - self.strict = strict # pylint: disable=E0237 - - def check_update(self, update: object) -> bool: - """Determines whether an update should be passed to this handlers :attr:`callback`. - - Args: - update (:obj:`object`): Incoming update. - - Returns: - :obj:`bool` - - """ - if not self.strict: - return isinstance(update, self.type) - return type(update) is self.type # pylint: disable=C0123 diff --git a/venv/lib/python3.8/site-packages/telegram/ext/updater.py b/venv/lib/python3.8/site-packages/telegram/ext/updater.py deleted file mode 100644 index 37a2e7e..0000000 --- a/venv/lib/python3.8/site-packages/telegram/ext/updater.py +++ /dev/null @@ -1,890 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the class Updater, which tries to make creating Telegram bots intuitive.""" - -import logging -import ssl -import warnings -from queue import Queue -from signal import SIGABRT, SIGINT, SIGTERM, signal -from threading import Event, Lock, Thread, current_thread -from time import sleep -from typing import ( - TYPE_CHECKING, - Any, - Callable, - Dict, - List, - Optional, - Tuple, - Union, - no_type_check, - Generic, - overload, -) - -from telegram import Bot, TelegramError -from telegram.error import InvalidToken, RetryAfter, TimedOut, Unauthorized -from telegram.ext import Dispatcher, JobQueue, ContextTypes, ExtBot -from telegram.utils.deprecate import TelegramDeprecationWarning, set_new_attribute_deprecated -from telegram.utils.helpers import get_signal_name, DEFAULT_FALSE, DefaultValue -from telegram.utils.request import Request -from telegram.ext.utils.types import CCT, UD, CD, BD -from telegram.ext.utils.webhookhandler import WebhookAppClass, WebhookServer - -if TYPE_CHECKING: - from telegram.ext import BasePersistence, Defaults, CallbackContext - - -class Updater(Generic[CCT, UD, CD, BD]): - """ - This class, which employs the :class:`telegram.ext.Dispatcher`, provides a frontend to - :class:`telegram.Bot` to the programmer, so they can focus on coding the bot. Its purpose is to - receive the updates from Telegram and to deliver them to said dispatcher. It also runs in a - separate thread, so the user can interact with the bot, for example on the command line. The - dispatcher supports handlers for different kinds of data: Updates from Telegram, basic text - commands and even arbitrary types. The updater can be started as a polling service or, for - production, use a webhook to receive updates. This is achieved using the WebhookServer and - WebhookHandler classes. - - Note: - * You must supply either a :attr:`bot` or a :attr:`token` argument. - * If you supply a :attr:`bot`, you will need to pass :attr:`arbitrary_callback_data`, - and :attr:`defaults` to the bot instead of the :class:`telegram.ext.Updater`. In this - case, you'll have to use the class :class:`telegram.ext.ExtBot`. - - .. versionchanged:: 13.6 - - Args: - token (:obj:`str`, optional): The bot's token given by the @BotFather. - base_url (:obj:`str`, optional): Base_url for the bot. - base_file_url (:obj:`str`, optional): Base_file_url for the bot. - workers (:obj:`int`, optional): Amount of threads in the thread pool for functions - decorated with ``@run_async`` (ignored if `dispatcher` argument is used). - bot (:class:`telegram.Bot`, optional): A pre-initialized bot instance (ignored if - `dispatcher` argument is used). If a pre-initialized bot is used, it is the user's - responsibility to create it using a `Request` instance with a large enough connection - pool. - dispatcher (:class:`telegram.ext.Dispatcher`, optional): A pre-initialized dispatcher - instance. If a pre-initialized dispatcher is used, it is the user's responsibility to - create it with proper arguments. - private_key (:obj:`bytes`, optional): Private key for decryption of telegram passport data. - private_key_password (:obj:`bytes`, optional): Password for above private key. - user_sig_handler (:obj:`function`, optional): Takes ``signum, frame`` as positional - arguments. This will be called when a signal is received, defaults are (SIGINT, - SIGTERM, SIGABRT) settable with :attr:`idle`. - request_kwargs (:obj:`dict`, optional): Keyword args to control the creation of a - `telegram.utils.request.Request` object (ignored if `bot` or `dispatcher` argument is - used). The request_kwargs are very useful for the advanced users who would like to - control the default timeouts and/or control the proxy used for http communication. - use_context (:obj:`bool`, optional): If set to :obj:`True` uses the context based callback - API (ignored if `dispatcher` argument is used). Defaults to :obj:`True`. - **New users**: set this to :obj:`True`. - persistence (:class:`telegram.ext.BasePersistence`, optional): The persistence class to - store data that should be persistent over restarts (ignored if `dispatcher` argument is - used). - defaults (:class:`telegram.ext.Defaults`, optional): An object containing default values to - be used if not set explicitly in the bot methods. - arbitrary_callback_data (:obj:`bool` | :obj:`int` | :obj:`None`, optional): Whether to - allow arbitrary objects as callback data for :class:`telegram.InlineKeyboardButton`. - Pass an integer to specify the maximum number of cached objects. For more details, - please see our wiki. Defaults to :obj:`False`. - - .. versionadded:: 13.6 - context_types (:class:`telegram.ext.ContextTypes`, optional): Pass an instance - of :class:`telegram.ext.ContextTypes` to customize the types used in the - ``context`` interface. If not passed, the defaults documented in - :class:`telegram.ext.ContextTypes` will be used. - - .. versionadded:: 13.6 - - Raises: - ValueError: If both :attr:`token` and :attr:`bot` are passed or none of them. - - - Attributes: - bot (:class:`telegram.Bot`): The bot used with this Updater. - user_sig_handler (:obj:`function`): Optional. Function to be called when a signal is - received. - update_queue (:obj:`Queue`): Queue for the updates. - job_queue (:class:`telegram.ext.JobQueue`): Jobqueue for the updater. - dispatcher (:class:`telegram.ext.Dispatcher`): Dispatcher that handles the updates and - dispatches them to the handlers. - running (:obj:`bool`): Indicates if the updater is running. - persistence (:class:`telegram.ext.BasePersistence`): Optional. The persistence class to - store data that should be persistent over restarts. - use_context (:obj:`bool`): Optional. :obj:`True` if using context based callbacks. - - """ - - __slots__ = ( - 'persistence', - 'dispatcher', - 'user_sig_handler', - 'bot', - 'logger', - 'update_queue', - 'job_queue', - '__exception_event', - 'last_update_id', - 'running', - '_request', - 'is_idle', - 'httpd', - '__lock', - '__threads', - '__dict__', - ) - - @overload - def __init__( - self: 'Updater[CallbackContext, dict, dict, dict]', - token: str = None, - base_url: str = None, - workers: int = 4, - bot: Bot = None, - private_key: bytes = None, - private_key_password: bytes = None, - user_sig_handler: Callable = None, - request_kwargs: Dict[str, Any] = None, - persistence: 'BasePersistence' = None, # pylint: disable=E0601 - defaults: 'Defaults' = None, - use_context: bool = True, - base_file_url: str = None, - arbitrary_callback_data: Union[DefaultValue, bool, int, None] = DEFAULT_FALSE, - ): - ... - - @overload - def __init__( - self: 'Updater[CCT, UD, CD, BD]', - token: str = None, - base_url: str = None, - workers: int = 4, - bot: Bot = None, - private_key: bytes = None, - private_key_password: bytes = None, - user_sig_handler: Callable = None, - request_kwargs: Dict[str, Any] = None, - persistence: 'BasePersistence' = None, - defaults: 'Defaults' = None, - use_context: bool = True, - base_file_url: str = None, - arbitrary_callback_data: Union[DefaultValue, bool, int, None] = DEFAULT_FALSE, - context_types: ContextTypes[CCT, UD, CD, BD] = None, - ): - ... - - @overload - def __init__( - self: 'Updater[CCT, UD, CD, BD]', - user_sig_handler: Callable = None, - dispatcher: Dispatcher[CCT, UD, CD, BD] = None, - ): - ... - - def __init__( # type: ignore[no-untyped-def,misc] - self, - token: str = None, - base_url: str = None, - workers: int = 4, - bot: Bot = None, - private_key: bytes = None, - private_key_password: bytes = None, - user_sig_handler: Callable = None, - request_kwargs: Dict[str, Any] = None, - persistence: 'BasePersistence' = None, - defaults: 'Defaults' = None, - use_context: bool = True, - dispatcher=None, - base_file_url: str = None, - arbitrary_callback_data: Union[DefaultValue, bool, int, None] = DEFAULT_FALSE, - context_types: ContextTypes[CCT, UD, CD, BD] = None, - ): - - if defaults and bot: - warnings.warn( - 'Passing defaults to an Updater has no effect when a Bot is passed ' - 'as well. Pass them to the Bot instead.', - TelegramDeprecationWarning, - stacklevel=2, - ) - if arbitrary_callback_data is not DEFAULT_FALSE and bot: - warnings.warn( - 'Passing arbitrary_callback_data to an Updater has no ' - 'effect when a Bot is passed as well. Pass them to the Bot instead.', - stacklevel=2, - ) - - if dispatcher is None: - if (token is None) and (bot is None): - raise ValueError('`token` or `bot` must be passed') - if (token is not None) and (bot is not None): - raise ValueError('`token` and `bot` are mutually exclusive') - if (private_key is not None) and (bot is not None): - raise ValueError('`bot` and `private_key` are mutually exclusive') - else: - if bot is not None: - raise ValueError('`dispatcher` and `bot` are mutually exclusive') - if persistence is not None: - raise ValueError('`dispatcher` and `persistence` are mutually exclusive') - if use_context != dispatcher.use_context: - raise ValueError('`dispatcher` and `use_context` are mutually exclusive') - if context_types is not None: - raise ValueError('`dispatcher` and `context_types` are mutually exclusive') - if workers is not None: - raise ValueError('`dispatcher` and `workers` are mutually exclusive') - - self.logger = logging.getLogger(__name__) - self._request = None - - if dispatcher is None: - con_pool_size = workers + 4 - - if bot is not None: - self.bot = bot - if bot.request.con_pool_size < con_pool_size: - self.logger.warning( - 'Connection pool of Request object is smaller than optimal value (%s)', - con_pool_size, - ) - else: - # we need a connection pool the size of: - # * for each of the workers - # * 1 for Dispatcher - # * 1 for polling Updater (even if webhook is used, we can spare a connection) - # * 1 for JobQueue - # * 1 for main thread - if request_kwargs is None: - request_kwargs = {} - if 'con_pool_size' not in request_kwargs: - request_kwargs['con_pool_size'] = con_pool_size - self._request = Request(**request_kwargs) - self.bot = ExtBot( - token, # type: ignore[arg-type] - base_url, - base_file_url=base_file_url, - request=self._request, - private_key=private_key, - private_key_password=private_key_password, - defaults=defaults, - arbitrary_callback_data=( - False # type: ignore[arg-type] - if arbitrary_callback_data is DEFAULT_FALSE - else arbitrary_callback_data - ), - ) - self.update_queue: Queue = Queue() - self.job_queue = JobQueue() - self.__exception_event = Event() - self.persistence = persistence - self.dispatcher = Dispatcher( - self.bot, - self.update_queue, - job_queue=self.job_queue, - workers=workers, - exception_event=self.__exception_event, - persistence=persistence, - use_context=use_context, - context_types=context_types, - ) - self.job_queue.set_dispatcher(self.dispatcher) - else: - con_pool_size = dispatcher.workers + 4 - - self.bot = dispatcher.bot - if self.bot.request.con_pool_size < con_pool_size: - self.logger.warning( - 'Connection pool of Request object is smaller than optimal value (%s)', - con_pool_size, - ) - self.update_queue = dispatcher.update_queue - self.__exception_event = dispatcher.exception_event - self.persistence = dispatcher.persistence - self.job_queue = dispatcher.job_queue - self.dispatcher = dispatcher - - self.user_sig_handler = user_sig_handler - self.last_update_id = 0 - self.running = False - self.is_idle = False - self.httpd = None - self.__lock = Lock() - self.__threads: List[Thread] = [] - - def __setattr__(self, key: str, value: object) -> None: - if key.startswith('__'): - key = f"_{self.__class__.__name__}{key}" - if issubclass(self.__class__, Updater) and self.__class__ is not Updater: - object.__setattr__(self, key, value) - return - set_new_attribute_deprecated(self, key, value) - - def _init_thread(self, target: Callable, name: str, *args: object, **kwargs: object) -> None: - thr = Thread( - target=self._thread_wrapper, - name=f"Bot:{self.bot.id}:{name}", - args=(target,) + args, - kwargs=kwargs, - ) - thr.start() - self.__threads.append(thr) - - def _thread_wrapper(self, target: Callable, *args: object, **kwargs: object) -> None: - thr_name = current_thread().name - self.logger.debug('%s - started', thr_name) - try: - target(*args, **kwargs) - except Exception: - self.__exception_event.set() - self.logger.exception('unhandled exception in %s', thr_name) - raise - self.logger.debug('%s - ended', thr_name) - - def start_polling( - self, - poll_interval: float = 0.0, - timeout: float = 10, - clean: bool = None, - bootstrap_retries: int = -1, - read_latency: float = 2.0, - allowed_updates: List[str] = None, - drop_pending_updates: bool = None, - ) -> Optional[Queue]: - """Starts polling updates from Telegram. - - Args: - poll_interval (:obj:`float`, optional): Time to wait between polling updates from - Telegram in seconds. Default is ``0.0``. - timeout (:obj:`float`, optional): Passed to :meth:`telegram.Bot.get_updates`. - drop_pending_updates (:obj:`bool`, optional): Whether to clean any pending updates on - Telegram servers before actually starting to poll. Default is :obj:`False`. - - .. versionadded :: 13.4 - clean (:obj:`bool`, optional): Alias for ``drop_pending_updates``. - - .. deprecated:: 13.4 - Use ``drop_pending_updates`` instead. - bootstrap_retries (:obj:`int`, optional): Whether the bootstrapping phase of the - :class:`telegram.ext.Updater` will retry on failures on the Telegram server. - - * < 0 - retry indefinitely (default) - * 0 - no retries - * > 0 - retry up to X times - - allowed_updates (List[:obj:`str`], optional): Passed to - :meth:`telegram.Bot.get_updates`. - read_latency (:obj:`float` | :obj:`int`, optional): Grace time in seconds for receiving - the reply from server. Will be added to the ``timeout`` value and used as the read - timeout from server (Default: ``2``). - - Returns: - :obj:`Queue`: The update queue that can be filled from the main thread. - - """ - if (clean is not None) and (drop_pending_updates is not None): - raise TypeError('`clean` and `drop_pending_updates` are mutually exclusive.') - - if clean is not None: - warnings.warn( - 'The argument `clean` of `start_polling` is deprecated. Please use ' - '`drop_pending_updates` instead.', - category=TelegramDeprecationWarning, - stacklevel=2, - ) - - drop_pending_updates = drop_pending_updates if drop_pending_updates is not None else clean - - with self.__lock: - if not self.running: - self.running = True - - # Create & start threads - self.job_queue.start() - dispatcher_ready = Event() - polling_ready = Event() - self._init_thread(self.dispatcher.start, "dispatcher", ready=dispatcher_ready) - self._init_thread( - self._start_polling, - "updater", - poll_interval, - timeout, - read_latency, - bootstrap_retries, - drop_pending_updates, - allowed_updates, - ready=polling_ready, - ) - - self.logger.debug('Waiting for Dispatcher and polling to start') - dispatcher_ready.wait() - polling_ready.wait() - - # Return the update queue so the main thread can insert updates - return self.update_queue - return None - - def start_webhook( - self, - listen: str = '127.0.0.1', - port: int = 80, - url_path: str = '', - cert: str = None, - key: str = None, - clean: bool = None, - bootstrap_retries: int = 0, - webhook_url: str = None, - allowed_updates: List[str] = None, - force_event_loop: bool = None, - drop_pending_updates: bool = None, - ip_address: str = None, - max_connections: int = 40, - ) -> Optional[Queue]: - """ - Starts a small http server to listen for updates via webhook. If :attr:`cert` - and :attr:`key` are not provided, the webhook will be started directly on - http://listen:port/url_path, so SSL can be handled by another - application. Else, the webhook will be started on - https://listen:port/url_path. Also calls :meth:`telegram.Bot.set_webhook` as required. - - .. versionchanged:: 13.4 - :meth:`start_webhook` now *always* calls :meth:`telegram.Bot.set_webhook`, so pass - ``webhook_url`` instead of calling ``updater.bot.set_webhook(webhook_url)`` manually. - - Args: - listen (:obj:`str`, optional): IP-Address to listen on. Default ``127.0.0.1``. - port (:obj:`int`, optional): Port the bot should be listening on. Default ``80``. - url_path (:obj:`str`, optional): Path inside url. - cert (:obj:`str`, optional): Path to the SSL certificate file. - key (:obj:`str`, optional): Path to the SSL key file. - drop_pending_updates (:obj:`bool`, optional): Whether to clean any pending updates on - Telegram servers before actually starting to poll. Default is :obj:`False`. - - .. versionadded :: 13.4 - clean (:obj:`bool`, optional): Alias for ``drop_pending_updates``. - - .. deprecated:: 13.4 - Use ``drop_pending_updates`` instead. - bootstrap_retries (:obj:`int`, optional): Whether the bootstrapping phase of the - :class:`telegram.ext.Updater` will retry on failures on the Telegram server. - - * < 0 - retry indefinitely (default) - * 0 - no retries - * > 0 - retry up to X times - - webhook_url (:obj:`str`, optional): Explicitly specify the webhook url. Useful behind - NAT, reverse proxy, etc. Default is derived from ``listen``, ``port`` & - ``url_path``. - ip_address (:obj:`str`, optional): Passed to :meth:`telegram.Bot.set_webhook`. - - .. versionadded :: 13.4 - allowed_updates (List[:obj:`str`], optional): Passed to - :meth:`telegram.Bot.set_webhook`. - force_event_loop (:obj:`bool`, optional): Legacy parameter formerly used for a - workaround on Windows + Python 3.8+. No longer has any effect. - - .. deprecated:: 13.6 - Since version 13.6, ``tornade>=6.1`` is required, which resolves the former - issue. - - max_connections (:obj:`int`, optional): Passed to - :meth:`telegram.Bot.set_webhook`. - - .. versionadded:: 13.6 - - Returns: - :obj:`Queue`: The update queue that can be filled from the main thread. - - """ - if (clean is not None) and (drop_pending_updates is not None): - raise TypeError('`clean` and `drop_pending_updates` are mutually exclusive.') - - if clean is not None: - warnings.warn( - 'The argument `clean` of `start_webhook` is deprecated. Please use ' - '`drop_pending_updates` instead.', - category=TelegramDeprecationWarning, - stacklevel=2, - ) - - if force_event_loop is not None: - warnings.warn( - 'The argument `force_event_loop` of `start_webhook` is deprecated and no longer ' - 'has any effect.', - category=TelegramDeprecationWarning, - stacklevel=2, - ) - - drop_pending_updates = drop_pending_updates if drop_pending_updates is not None else clean - - with self.__lock: - if not self.running: - self.running = True - - # Create & start threads - webhook_ready = Event() - dispatcher_ready = Event() - self.job_queue.start() - self._init_thread(self.dispatcher.start, "dispatcher", dispatcher_ready) - self._init_thread( - self._start_webhook, - "updater", - listen, - port, - url_path, - cert, - key, - bootstrap_retries, - drop_pending_updates, - webhook_url, - allowed_updates, - ready=webhook_ready, - ip_address=ip_address, - max_connections=max_connections, - ) - - self.logger.debug('Waiting for Dispatcher and Webhook to start') - webhook_ready.wait() - dispatcher_ready.wait() - - # Return the update queue so the main thread can insert updates - return self.update_queue - return None - - @no_type_check - def _start_polling( - self, - poll_interval, - timeout, - read_latency, - bootstrap_retries, - drop_pending_updates, - allowed_updates, - ready=None, - ): # pragma: no cover - # Thread target of thread 'updater'. Runs in background, pulls - # updates from Telegram and inserts them in the update queue of the - # Dispatcher. - - self.logger.debug('Updater thread started (polling)') - - self._bootstrap( - bootstrap_retries, - drop_pending_updates=drop_pending_updates, - webhook_url='', - allowed_updates=None, - ) - - self.logger.debug('Bootstrap done') - - def polling_action_cb(): - updates = self.bot.get_updates( - self.last_update_id, - timeout=timeout, - read_latency=read_latency, - allowed_updates=allowed_updates, - ) - - if updates: - if not self.running: - self.logger.debug('Updates ignored and will be pulled again on restart') - else: - for update in updates: - self.update_queue.put(update) - self.last_update_id = updates[-1].update_id + 1 - - return True - - def polling_onerr_cb(exc): - # Put the error into the update queue and let the Dispatcher - # broadcast it - self.update_queue.put(exc) - - if ready is not None: - ready.set() - - self._network_loop_retry( - polling_action_cb, polling_onerr_cb, 'getting Updates', poll_interval - ) - - @no_type_check - def _network_loop_retry(self, action_cb, onerr_cb, description, interval): - """Perform a loop calling `action_cb`, retrying after network errors. - - Stop condition for loop: `self.running` evaluates :obj:`False` or return value of - `action_cb` evaluates :obj:`False`. - - Args: - action_cb (:obj:`callable`): Network oriented callback function to call. - onerr_cb (:obj:`callable`): Callback to call when TelegramError is caught. Receives the - exception object as a parameter. - description (:obj:`str`): Description text to use for logs and exception raised. - interval (:obj:`float` | :obj:`int`): Interval to sleep between each call to - `action_cb`. - - """ - self.logger.debug('Start network loop retry %s', description) - cur_interval = interval - while self.running: - try: - if not action_cb(): - break - except RetryAfter as exc: - self.logger.info('%s', exc) - cur_interval = 0.5 + exc.retry_after - except TimedOut as toe: - self.logger.debug('Timed out %s: %s', description, toe) - # If failure is due to timeout, we should retry asap. - cur_interval = 0 - except InvalidToken as pex: - self.logger.error('Invalid token; aborting') - raise pex - except TelegramError as telegram_exc: - self.logger.error('Error while %s: %s', description, telegram_exc) - onerr_cb(telegram_exc) - cur_interval = self._increase_poll_interval(cur_interval) - else: - cur_interval = interval - - if cur_interval: - sleep(cur_interval) - - @staticmethod - def _increase_poll_interval(current_interval: float) -> float: - # increase waiting times on subsequent errors up to 30secs - if current_interval == 0: - current_interval = 1 - elif current_interval < 30: - current_interval *= 1.5 - else: - current_interval = min(30.0, current_interval) - return current_interval - - @no_type_check - def _start_webhook( - self, - listen, - port, - url_path, - cert, - key, - bootstrap_retries, - drop_pending_updates, - webhook_url, - allowed_updates, - ready=None, - ip_address=None, - max_connections: int = 40, - ): - self.logger.debug('Updater thread started (webhook)') - - # Note that we only use the SSL certificate for the WebhookServer, if the key is also - # present. This is because the WebhookServer may not actually be in charge of performing - # the SSL handshake, e.g. in case a reverse proxy is used - use_ssl = cert is not None and key is not None - - if not url_path.startswith('/'): - url_path = f'/{url_path}' - - # Create Tornado app instance - app = WebhookAppClass(url_path, self.bot, self.update_queue) - - # Form SSL Context - # An SSLError is raised if the private key does not match with the certificate - if use_ssl: - try: - ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) - ssl_ctx.load_cert_chain(cert, key) - except ssl.SSLError as exc: - raise TelegramError('Invalid SSL Certificate') from exc - else: - ssl_ctx = None - - # Create and start server - self.httpd = WebhookServer(listen, port, app, ssl_ctx) - - if not webhook_url: - webhook_url = self._gen_webhook_url(listen, port, url_path) - - # We pass along the cert to the webhook if present. - cert_file = open(cert, 'rb') if cert is not None else None - self._bootstrap( - max_retries=bootstrap_retries, - drop_pending_updates=drop_pending_updates, - webhook_url=webhook_url, - allowed_updates=allowed_updates, - cert=cert_file, - ip_address=ip_address, - max_connections=max_connections, - ) - if cert_file is not None: - cert_file.close() - - self.httpd.serve_forever(ready=ready) - - @staticmethod - def _gen_webhook_url(listen: str, port: int, url_path: str) -> str: - return f'https://{listen}:{port}{url_path}' - - @no_type_check - def _bootstrap( - self, - max_retries, - drop_pending_updates, - webhook_url, - allowed_updates, - cert=None, - bootstrap_interval=5, - ip_address=None, - max_connections: int = 40, - ): - retries = [0] - - def bootstrap_del_webhook(): - self.logger.debug('Deleting webhook') - if drop_pending_updates: - self.logger.debug('Dropping pending updates from Telegram server') - self.bot.delete_webhook(drop_pending_updates=drop_pending_updates) - return False - - def bootstrap_set_webhook(): - self.logger.debug('Setting webhook') - if drop_pending_updates: - self.logger.debug('Dropping pending updates from Telegram server') - self.bot.set_webhook( - url=webhook_url, - certificate=cert, - allowed_updates=allowed_updates, - ip_address=ip_address, - drop_pending_updates=drop_pending_updates, - max_connections=max_connections, - ) - return False - - def bootstrap_onerr_cb(exc): - if not isinstance(exc, Unauthorized) and (max_retries < 0 or retries[0] < max_retries): - retries[0] += 1 - self.logger.warning( - 'Failed bootstrap phase; try=%s max_retries=%s', retries[0], max_retries - ) - else: - self.logger.error('Failed bootstrap phase after %s retries (%s)', retries[0], exc) - raise exc - - # Dropping pending updates from TG can be efficiently done with the drop_pending_updates - # parameter of delete/start_webhook, even in the case of polling. Also we want to make - # sure that no webhook is configured in case of polling, so we just always call - # delete_webhook for polling - if drop_pending_updates or not webhook_url: - self._network_loop_retry( - bootstrap_del_webhook, - bootstrap_onerr_cb, - 'bootstrap del webhook', - bootstrap_interval, - ) - retries[0] = 0 - - # Restore/set webhook settings, if needed. Again, we don't know ahead if a webhook is set, - # so we set it anyhow. - if webhook_url: - self._network_loop_retry( - bootstrap_set_webhook, - bootstrap_onerr_cb, - 'bootstrap set webhook', - bootstrap_interval, - ) - - def stop(self) -> None: - """Stops the polling/webhook thread, the dispatcher and the job queue.""" - self.job_queue.stop() - with self.__lock: - if self.running or self.dispatcher.has_running_threads: - self.logger.debug('Stopping Updater and Dispatcher...') - - self.running = False - - self._stop_httpd() - self._stop_dispatcher() - self._join_threads() - - # Stop the Request instance only if it was created by the Updater - if self._request: - self._request.stop() - - @no_type_check - def _stop_httpd(self) -> None: - if self.httpd: - self.logger.debug( - 'Waiting for current webhook connection to be ' - 'closed... Send a Telegram message to the bot to exit ' - 'immediately.' - ) - self.httpd.shutdown() - self.httpd = None - - @no_type_check - def _stop_dispatcher(self) -> None: - self.logger.debug('Requesting Dispatcher to stop...') - self.dispatcher.stop() - - @no_type_check - def _join_threads(self) -> None: - for thr in self.__threads: - self.logger.debug('Waiting for %s thread to end', thr.name) - thr.join() - self.logger.debug('%s thread has ended', thr.name) - self.__threads = [] - - @no_type_check - def _signal_handler(self, signum, frame) -> None: - self.is_idle = False - if self.running: - self.logger.info( - 'Received signal %s (%s), stopping...', signum, get_signal_name(signum) - ) - if self.persistence: - # Update user_data, chat_data and bot_data before flushing - self.dispatcher.update_persistence() - self.persistence.flush() - self.stop() - if self.user_sig_handler: - self.user_sig_handler(signum, frame) - else: - self.logger.warning('Exiting immediately!') - # pylint: disable=C0415,W0212 - import os - - os._exit(1) - - def idle(self, stop_signals: Union[List, Tuple] = (SIGINT, SIGTERM, SIGABRT)) -> None: - """Blocks until one of the signals are received and stops the updater. - - Args: - stop_signals (:obj:`list` | :obj:`tuple`): List containing signals from the signal - module that should be subscribed to. :meth:`Updater.stop()` will be called on - receiving one of those signals. Defaults to (``SIGINT``, ``SIGTERM``, ``SIGABRT``). - - """ - for sig in stop_signals: - signal(sig, self._signal_handler) - - self.is_idle = True - - while self.is_idle: - sleep(1) diff --git a/venv/lib/python3.8/site-packages/telegram/ext/utils/__init__.py b/venv/lib/python3.8/site-packages/telegram/ext/utils/__init__.py deleted file mode 100644 index 85c96bc..0000000 --- a/venv/lib/python3.8/site-packages/telegram/ext/utils/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. diff --git a/venv/lib/python3.8/site-packages/telegram/ext/utils/promise.py b/venv/lib/python3.8/site-packages/telegram/ext/utils/promise.py deleted file mode 100644 index 6b54824..0000000 --- a/venv/lib/python3.8/site-packages/telegram/ext/utils/promise.py +++ /dev/null @@ -1,158 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the Promise class.""" - -import logging -from threading import Event -from typing import Callable, List, Optional, Tuple, TypeVar, Union - -from telegram.utils.deprecate import set_new_attribute_deprecated -from telegram.utils.types import JSONDict - -RT = TypeVar('RT') - - -logger = logging.getLogger(__name__) - - -class Promise: - """A simple Promise implementation for use with the run_async decorator, DelayQueue etc. - - Args: - pooled_function (:obj:`callable`): The callable that will be called concurrently. - args (:obj:`list` | :obj:`tuple`): Positional arguments for :attr:`pooled_function`. - kwargs (:obj:`dict`): Keyword arguments for :attr:`pooled_function`. - update (:class:`telegram.Update` | :obj:`object`, optional): The update this promise is - associated with. - error_handling (:obj:`bool`, optional): Whether exceptions raised by :attr:`func` - may be handled by error handlers. Defaults to :obj:`True`. - - Attributes: - pooled_function (:obj:`callable`): The callable that will be called concurrently. - args (:obj:`list` | :obj:`tuple`): Positional arguments for :attr:`pooled_function`. - kwargs (:obj:`dict`): Keyword arguments for :attr:`pooled_function`. - done (:obj:`threading.Event`): Is set when the result is available. - update (:class:`telegram.Update` | :obj:`object`): Optional. The update this promise is - associated with. - error_handling (:obj:`bool`): Optional. Whether exceptions raised by :attr:`func` - may be handled by error handlers. Defaults to :obj:`True`. - - """ - - __slots__ = ( - 'pooled_function', - 'args', - 'kwargs', - 'update', - 'error_handling', - 'done', - '_done_callback', - '_result', - '_exception', - '__dict__', - ) - - # TODO: Remove error_handling parameter once we drop the @run_async decorator - def __init__( - self, - pooled_function: Callable[..., RT], - args: Union[List, Tuple], - kwargs: JSONDict, - update: object = None, - error_handling: bool = True, - ): - self.pooled_function = pooled_function - self.args = args - self.kwargs = kwargs - self.update = update - self.error_handling = error_handling - self.done = Event() - self._done_callback: Optional[Callable] = None - self._result: Optional[RT] = None - self._exception: Optional[Exception] = None - - def __setattr__(self, key: str, value: object) -> None: - set_new_attribute_deprecated(self, key, value) - - def run(self) -> None: - """Calls the :attr:`pooled_function` callable.""" - try: - self._result = self.pooled_function(*self.args, **self.kwargs) - - except Exception as exc: - self._exception = exc - - finally: - self.done.set() - if self._exception is None and self._done_callback: - try: - self._done_callback(self.result()) - except Exception as exc: - logger.warning( - "`done_callback` of a Promise raised the following exception." - " The exception won't be handled by error handlers." - ) - logger.warning("Full traceback:", exc_info=exc) - - def __call__(self) -> None: - self.run() - - def result(self, timeout: float = None) -> Optional[RT]: - """Return the result of the ``Promise``. - - Args: - timeout (:obj:`float`, optional): Maximum time in seconds to wait for the result to be - calculated. ``None`` means indefinite. Default is ``None``. - - Returns: - Returns the return value of :attr:`pooled_function` or ``None`` if the ``timeout`` - expires. - - Raises: - object exception raised by :attr:`pooled_function`. - """ - self.done.wait(timeout=timeout) - if self._exception is not None: - raise self._exception # pylint: disable=raising-bad-type - return self._result - - def add_done_callback(self, callback: Callable) -> None: - """ - Callback to be run when :class:`telegram.ext.utils.promise.Promise` becomes done. - - Note: - Callback won't be called if :attr:`pooled_function` - raises an exception. - - Args: - callback (:obj:`callable`): The callable that will be called when promise is done. - callback will be called by passing ``Promise.result()`` as only positional argument. - - """ - if self.done.wait(0): - callback(self.result()) - else: - self._done_callback = callback - - @property - def exception(self) -> Optional[Exception]: - """The exception raised by :attr:`pooled_function` or ``None`` if no exception has been - raised (yet). - """ - return self._exception diff --git a/venv/lib/python3.8/site-packages/telegram/ext/utils/types.py b/venv/lib/python3.8/site-packages/telegram/ext/utils/types.py deleted file mode 100644 index b7152f6..0000000 --- a/venv/lib/python3.8/site-packages/telegram/ext/utils/types.py +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains custom typing aliases. - -.. versionadded:: 13.6 -""" -from typing import TypeVar, TYPE_CHECKING, Tuple, List, Dict, Any, Optional - -if TYPE_CHECKING: - from telegram.ext import CallbackContext # noqa: F401 - - -ConversationDict = Dict[Tuple[int, ...], Optional[object]] -"""Dicts as maintained by the :class:`telegram.ext.ConversationHandler`. - - .. versionadded:: 13.6 -""" - -CDCData = Tuple[List[Tuple[str, float, Dict[str, Any]]], Dict[str, str]] -"""Tuple[List[Tuple[:obj:`str`, :obj:`float`, Dict[:obj:`str`, :obj:`any`]]], \ - Dict[:obj:`str`, :obj:`str`]]: Data returned by - :attr:`telegram.ext.CallbackDataCache.persistence_data`. - - .. versionadded:: 13.6 -""" - -CCT = TypeVar('CCT', bound='CallbackContext') -"""An instance of :class:`telegram.ext.CallbackContext` or a custom subclass. - -.. versionadded:: 13.6 -""" -UD = TypeVar('UD') -"""Type of the user data for a single user. - -.. versionadded:: 13.6 -""" -CD = TypeVar('CD') -"""Type of the chat data for a single user. - -.. versionadded:: 13.6 -""" -BD = TypeVar('BD') -"""Type of the bot data. - -.. versionadded:: 13.6 -""" diff --git a/venv/lib/python3.8/site-packages/telegram/ext/utils/webhookhandler.py b/venv/lib/python3.8/site-packages/telegram/ext/utils/webhookhandler.py deleted file mode 100644 index ddf5e69..0000000 --- a/venv/lib/python3.8/site-packages/telegram/ext/utils/webhookhandler.py +++ /dev/null @@ -1,177 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -# pylint: disable=C0114 - -import logging -from queue import Queue -from ssl import SSLContext -from threading import Event, Lock -from typing import TYPE_CHECKING, Any, Optional - -import tornado.web -from tornado import httputil -from tornado.httpserver import HTTPServer -from tornado.ioloop import IOLoop - -from telegram import Update -from telegram.ext import ExtBot -from telegram.utils.deprecate import set_new_attribute_deprecated -from telegram.utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - -try: - import ujson as json -except ImportError: - import json # type: ignore[no-redef] - - -class WebhookServer: - __slots__ = ( - 'http_server', - 'listen', - 'port', - 'loop', - 'logger', - 'is_running', - 'server_lock', - 'shutdown_lock', - '__dict__', - ) - - def __init__( - self, listen: str, port: int, webhook_app: 'WebhookAppClass', ssl_ctx: SSLContext - ): - self.http_server = HTTPServer(webhook_app, ssl_options=ssl_ctx) - self.listen = listen - self.port = port - self.loop: Optional[IOLoop] = None - self.logger = logging.getLogger(__name__) - self.is_running = False - self.server_lock = Lock() - self.shutdown_lock = Lock() - - def __setattr__(self, key: str, value: object) -> None: - set_new_attribute_deprecated(self, key, value) - - def serve_forever(self, ready: Event = None) -> None: - with self.server_lock: - IOLoop().make_current() - self.is_running = True - self.logger.debug('Webhook Server started.') - self.loop = IOLoop.current() - self.http_server.listen(self.port, address=self.listen) - - if ready is not None: - ready.set() - - self.loop.start() - self.logger.debug('Webhook Server stopped.') - self.is_running = False - - def shutdown(self) -> None: - with self.shutdown_lock: - if not self.is_running: - self.logger.warning('Webhook Server already stopped.') - return - self.loop.add_callback(self.loop.stop) # type: ignore - - def handle_error(self, request: object, client_address: str) -> None: # pylint: disable=W0613 - """Handle an error gracefully.""" - self.logger.debug( - 'Exception happened during processing of request from %s', - client_address, - exc_info=True, - ) - - -class WebhookAppClass(tornado.web.Application): - def __init__(self, webhook_path: str, bot: 'Bot', update_queue: Queue): - self.shared_objects = {"bot": bot, "update_queue": update_queue} - handlers = [(rf"{webhook_path}/?", WebhookHandler, self.shared_objects)] # noqa - tornado.web.Application.__init__(self, handlers) # type: ignore - - def log_request(self, handler: tornado.web.RequestHandler) -> None: # skipcq: PTC-W0049 - pass - - -# WebhookHandler, process webhook calls -# pylint: disable=W0223 -class WebhookHandler(tornado.web.RequestHandler): - SUPPORTED_METHODS = ["POST"] # type: ignore - - def __init__( - self, - application: tornado.web.Application, - request: httputil.HTTPServerRequest, - **kwargs: JSONDict, - ): - super().__init__(application, request, **kwargs) - self.logger = logging.getLogger(__name__) - - def initialize(self, bot: 'Bot', update_queue: Queue) -> None: - # pylint: disable=W0201 - self.bot = bot - self.update_queue = update_queue - - def set_default_headers(self) -> None: - self.set_header("Content-Type", 'application/json; charset="utf-8"') - - def post(self) -> None: - self.logger.debug('Webhook triggered') - self._validate_post() - json_string = self.request.body.decode() - data = json.loads(json_string) - self.set_status(200) - self.logger.debug('Webhook received data: %s', json_string) - update = Update.de_json(data, self.bot) - if update: - self.logger.debug('Received Update with ID %d on Webhook', update.update_id) - # handle arbitrary callback data, if necessary - if isinstance(self.bot, ExtBot): - self.bot.insert_callback_data(update) - self.update_queue.put(update) - - def _validate_post(self) -> None: - ct_header = self.request.headers.get("Content-Type", None) - if ct_header != 'application/json': - raise tornado.web.HTTPError(403) - - def write_error(self, status_code: int, **kwargs: Any) -> None: - """Log an arbitrary message. - - This is used by all other logging functions. - - It overrides ``BaseHTTPRequestHandler.log_message``, which logs to ``sys.stderr``. - - The first argument, FORMAT, is a format string for the message to be logged. If the format - string contains any % escapes requiring parameters, they should be specified as subsequent - arguments (it's just like printf!). - - The client ip is prefixed to every message. - - """ - super().write_error(status_code, **kwargs) - self.logger.debug( - "%s - - %s", - self.request.remote_ip, - "Exception in WebhookHandler", - exc_info=kwargs['exc_info'], - ) diff --git a/venv/lib/python3.8/site-packages/telegram/files/__init__.py b/venv/lib/python3.8/site-packages/telegram/files/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.8/site-packages/telegram/files/animation.py b/venv/lib/python3.8/site-packages/telegram/files/animation.py deleted file mode 100644 index 199cf33..0000000 --- a/venv/lib/python3.8/site-packages/telegram/files/animation.py +++ /dev/null @@ -1,137 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram Animation.""" -from typing import TYPE_CHECKING, Any, Optional - -from telegram import PhotoSize, TelegramObject -from telegram.utils.helpers import DEFAULT_NONE -from telegram.utils.types import JSONDict, ODVInput - -if TYPE_CHECKING: - from telegram import Bot, File - - -class Animation(TelegramObject): - """This object represents an animation file (GIF or H.264/MPEG-4 AVC video without sound). - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`file_unique_id` is equal. - - Args: - file_id (:obj:`str`): Identifier for this file, which can be used to download - or reuse the file. - file_unique_id (:obj:`str`): Unique identifier for this file, which - is supposed to be the same over time and for different bots. - Can't be used to download or reuse the file. - width (:obj:`int`): Video width as defined by sender. - height (:obj:`int`): Video height as defined by sender. - duration (:obj:`int`): Duration of the video in seconds as defined by sender. - thumb (:class:`telegram.PhotoSize`, optional): Animation thumbnail as defined by sender. - file_name (:obj:`str`, optional): Original animation filename as defined by sender. - mime_type (:obj:`str`, optional): MIME type of the file as defined by sender. - file_size (:obj:`int`, optional): File size. - bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - file_id (:obj:`str`): File identifier. - file_unique_id (:obj:`str`): Unique identifier for this file, which - is supposed to be the same over time and for different bots. - Can't be used to download or reuse the file. - width (:obj:`int`): Video width as defined by sender. - height (:obj:`int`): Video height as defined by sender. - duration (:obj:`int`): Duration of the video in seconds as defined by sender. - thumb (:class:`telegram.PhotoSize`): Optional. Animation thumbnail as defined by sender. - file_name (:obj:`str`): Optional. Original animation filename as defined by sender. - mime_type (:obj:`str`): Optional. MIME type of the file as defined by sender. - file_size (:obj:`int`): Optional. File size. - bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods. - - """ - - __slots__ = ( - 'bot', - 'width', - 'file_id', - 'file_size', - 'file_name', - 'thumb', - 'duration', - 'mime_type', - 'height', - 'file_unique_id', - '_id_attrs', - ) - - def __init__( - self, - file_id: str, - file_unique_id: str, - width: int, - height: int, - duration: int, - thumb: PhotoSize = None, - file_name: str = None, - mime_type: str = None, - file_size: int = None, - bot: 'Bot' = None, - **_kwargs: Any, - ): - # Required - self.file_id = str(file_id) - self.file_unique_id = str(file_unique_id) - self.width = int(width) - self.height = int(height) - self.duration = duration - # Optionals - self.thumb = thumb - self.file_name = file_name - self.mime_type = mime_type - self.file_size = file_size - self.bot = bot - - self._id_attrs = (self.file_unique_id,) - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Animation']: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data['thumb'] = PhotoSize.de_json(data.get('thumb'), bot) - - return cls(bot=bot, **data) - - def get_file( - self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None - ) -> 'File': - """Convenience wrapper over :attr:`telegram.Bot.get_file` - - For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. - - Returns: - :class:`telegram.File` - - Raises: - :class:`telegram.error.TelegramError` - - """ - return self.bot.get_file(file_id=self.file_id, timeout=timeout, api_kwargs=api_kwargs) diff --git a/venv/lib/python3.8/site-packages/telegram/files/audio.py b/venv/lib/python3.8/site-packages/telegram/files/audio.py deleted file mode 100644 index d95711a..0000000 --- a/venv/lib/python3.8/site-packages/telegram/files/audio.py +++ /dev/null @@ -1,141 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram Audio.""" - -from typing import TYPE_CHECKING, Any, Optional - -from telegram import PhotoSize, TelegramObject -from telegram.utils.helpers import DEFAULT_NONE -from telegram.utils.types import JSONDict, ODVInput - -if TYPE_CHECKING: - from telegram import Bot, File - - -class Audio(TelegramObject): - """This object represents an audio file to be treated as music by the Telegram clients. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`file_unique_id` is equal. - - Args: - file_id (:obj:`str`): Identifier for this file, which can be used to download - or reuse the file. - file_unique_id (:obj:`str`): Unique identifier for this file, which is supposed to be - the same over time and for different bots. Can't be used to download or reuse the file. - duration (:obj:`int`): Duration of the audio in seconds as defined by sender. - performer (:obj:`str`, optional): Performer of the audio as defined by sender or by audio - tags. - title (:obj:`str`, optional): Title of the audio as defined by sender or by audio tags. - file_name (:obj:`str`, optional): Original filename as defined by sender. - mime_type (:obj:`str`, optional): MIME type of the file as defined by sender. - file_size (:obj:`int`, optional): File size. - thumb (:class:`telegram.PhotoSize`, optional): Thumbnail of the album cover to - which the music file belongs. - bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - file_id (:obj:`str`): Identifier for this file. - file_unique_id (:obj:`str`): Unique identifier for this file, which - is supposed to be the same over time and for different bots. - Can't be used to download or reuse the file. - duration (:obj:`int`): Duration of the audio in seconds. - performer (:obj:`str`): Optional. Performer of the audio as defined by sender or by audio - tags. - title (:obj:`str`): Optional. Title of the audio as defined by sender or by audio tags. - file_name (:obj:`str`): Optional. Original filename as defined by sender. - mime_type (:obj:`str`): Optional. MIME type of the file as defined by sender. - file_size (:obj:`int`): Optional. File size. - thumb (:class:`telegram.PhotoSize`): Optional. Thumbnail of the album cover to - which the music file belongs. - bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods. - - """ - - __slots__ = ( - 'file_id', - 'bot', - 'file_size', - 'file_name', - 'thumb', - 'title', - 'duration', - 'performer', - 'mime_type', - 'file_unique_id', - '_id_attrs', - ) - - def __init__( - self, - file_id: str, - file_unique_id: str, - duration: int, - performer: str = None, - title: str = None, - mime_type: str = None, - file_size: int = None, - thumb: PhotoSize = None, - bot: 'Bot' = None, - file_name: str = None, - **_kwargs: Any, - ): - # Required - self.file_id = str(file_id) - self.file_unique_id = str(file_unique_id) - self.duration = int(duration) - # Optionals - self.performer = performer - self.title = title - self.file_name = file_name - self.mime_type = mime_type - self.file_size = file_size - self.thumb = thumb - self.bot = bot - - self._id_attrs = (self.file_unique_id,) - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Audio']: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data['thumb'] = PhotoSize.de_json(data.get('thumb'), bot) - - return cls(bot=bot, **data) - - def get_file( - self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None - ) -> 'File': - """Convenience wrapper over :attr:`telegram.Bot.get_file` - - For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. - - Returns: - :class:`telegram.File` - - Raises: - :class:`telegram.error.TelegramError` - - """ - return self.bot.get_file(file_id=self.file_id, timeout=timeout, api_kwargs=api_kwargs) diff --git a/venv/lib/python3.8/site-packages/telegram/files/chatphoto.py b/venv/lib/python3.8/site-packages/telegram/files/chatphoto.py deleted file mode 100644 index 5302c7e..0000000 --- a/venv/lib/python3.8/site-packages/telegram/files/chatphoto.py +++ /dev/null @@ -1,132 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram ChatPhoto.""" -from typing import TYPE_CHECKING, Any - -from telegram import TelegramObject -from telegram.utils.helpers import DEFAULT_NONE -from telegram.utils.types import JSONDict, ODVInput - -if TYPE_CHECKING: - from telegram import Bot, File - - -class ChatPhoto(TelegramObject): - """This object represents a chat photo. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`small_file_unique_id` and :attr:`big_file_unique_id` are - equal. - - Args: - small_file_id (:obj:`str`): Unique file identifier of small (160x160) chat photo. This - file_id can be used only for photo download and only for as long - as the photo is not changed. - small_file_unique_id (:obj:`str`): Unique file identifier of small (160x160) chat photo, - which is supposed to be the same over time and for different bots. - Can't be used to download or reuse the file. - big_file_id (:obj:`str`): Unique file identifier of big (640x640) chat photo. This file_id - can be used only for photo download and only for as long as the photo is not changed. - big_file_unique_id (:obj:`str`): Unique file identifier of big (640x640) chat photo, - which is supposed to be the same over time and for different bots. - Can't be used to download or reuse the file. - bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - small_file_id (:obj:`str`): File identifier of small (160x160) chat photo. - This file_id can be used only for photo download and only for as long - as the photo is not changed. - small_file_unique_id (:obj:`str`): Unique file identifier of small (160x160) chat photo, - which is supposed to be the same over time and for different bots. - Can't be used to download or reuse the file. - big_file_id (:obj:`str`): File identifier of big (640x640) chat photo. - This file_id can be used only for photo download and only for as long as - the photo is not changed. - big_file_unique_id (:obj:`str`): Unique file identifier of big (640x640) chat photo, - which is supposed to be the same over time and for different bots. - Can't be used to download or reuse the file. - - """ - - __slots__ = ( - 'big_file_unique_id', - 'bot', - 'small_file_id', - 'small_file_unique_id', - 'big_file_id', - '_id_attrs', - ) - - def __init__( - self, - small_file_id: str, - small_file_unique_id: str, - big_file_id: str, - big_file_unique_id: str, - bot: 'Bot' = None, - **_kwargs: Any, - ): - self.small_file_id = small_file_id - self.small_file_unique_id = small_file_unique_id - self.big_file_id = big_file_id - self.big_file_unique_id = big_file_unique_id - - self.bot = bot - - self._id_attrs = ( - self.small_file_unique_id, - self.big_file_unique_id, - ) - - def get_small_file( - self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None - ) -> 'File': - """Convenience wrapper over :attr:`telegram.Bot.get_file` for getting the - small (160x160) chat photo - - For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. - - Returns: - :class:`telegram.File` - - Raises: - :class:`telegram.error.TelegramError` - - """ - return self.bot.get_file( - file_id=self.small_file_id, timeout=timeout, api_kwargs=api_kwargs - ) - - def get_big_file( - self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None - ) -> 'File': - """Convenience wrapper over :attr:`telegram.Bot.get_file` for getting the - big (640x640) chat photo - - For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. - - Returns: - :class:`telegram.File` - - Raises: - :class:`telegram.error.TelegramError` - - """ - return self.bot.get_file(file_id=self.big_file_id, timeout=timeout, api_kwargs=api_kwargs) diff --git a/venv/lib/python3.8/site-packages/telegram/files/contact.py b/venv/lib/python3.8/site-packages/telegram/files/contact.py deleted file mode 100644 index 257fdf4..0000000 --- a/venv/lib/python3.8/site-packages/telegram/files/contact.py +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram Contact.""" - -from typing import Any - -from telegram import TelegramObject - - -class Contact(TelegramObject): - """This object represents a phone contact. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`phone_number` is equal. - - Args: - phone_number (:obj:`str`): Contact's phone number. - first_name (:obj:`str`): Contact's first name. - last_name (:obj:`str`, optional): Contact's last name. - user_id (:obj:`int`, optional): Contact's user identifier in Telegram. - vcard (:obj:`str`, optional): Additional data about the contact in the form of a vCard. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - phone_number (:obj:`str`): Contact's phone number. - first_name (:obj:`str`): Contact's first name. - last_name (:obj:`str`): Optional. Contact's last name. - user_id (:obj:`int`): Optional. Contact's user identifier in Telegram. - vcard (:obj:`str`): Optional. Additional data about the contact in the form of a vCard. - - """ - - __slots__ = ('vcard', 'user_id', 'first_name', 'last_name', 'phone_number', '_id_attrs') - - def __init__( - self, - phone_number: str, - first_name: str, - last_name: str = None, - user_id: int = None, - vcard: str = None, - **_kwargs: Any, - ): - # Required - self.phone_number = str(phone_number) - self.first_name = first_name - # Optionals - self.last_name = last_name - self.user_id = user_id - self.vcard = vcard - - self._id_attrs = (self.phone_number,) diff --git a/venv/lib/python3.8/site-packages/telegram/files/document.py b/venv/lib/python3.8/site-packages/telegram/files/document.py deleted file mode 100644 index dad9f9b..0000000 --- a/venv/lib/python3.8/site-packages/telegram/files/document.py +++ /dev/null @@ -1,125 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram Document.""" - -from typing import TYPE_CHECKING, Any, Optional - -from telegram import PhotoSize, TelegramObject -from telegram.utils.helpers import DEFAULT_NONE -from telegram.utils.types import JSONDict, ODVInput - -if TYPE_CHECKING: - from telegram import Bot, File - - -class Document(TelegramObject): - """This object represents a general file - (as opposed to photos, voice messages and audio files). - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`file_unique_id` is equal. - - Args: - file_id (:obj:`str`): Identifier for this file, which can be used to download - or reuse the file. - file_unique_id (:obj:`str`): Unique identifier for this file, which is supposed to be - the same over time and for different bots. Can't be used to download or reuse the file. - thumb (:class:`telegram.PhotoSize`, optional): Document thumbnail as defined by sender. - file_name (:obj:`str`, optional): Original filename as defined by sender. - mime_type (:obj:`str`, optional): MIME type of the file as defined by sender. - file_size (:obj:`int`, optional): File size. - bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - file_id (:obj:`str`): File identifier. - file_unique_id (:obj:`str`): Unique identifier for this file, which - is supposed to be the same over time and for different bots. - Can't be used to download or reuse the file. - thumb (:class:`telegram.PhotoSize`): Optional. Document thumbnail. - file_name (:obj:`str`): Original filename. - mime_type (:obj:`str`): Optional. MIME type of the file. - file_size (:obj:`int`): Optional. File size. - bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods. - - """ - - __slots__ = ( - 'bot', - 'file_id', - 'file_size', - 'file_name', - 'thumb', - 'mime_type', - 'file_unique_id', - '_id_attrs', - ) - - _id_keys = ('file_id',) - - def __init__( - self, - file_id: str, - file_unique_id: str, - thumb: PhotoSize = None, - file_name: str = None, - mime_type: str = None, - file_size: int = None, - bot: 'Bot' = None, - **_kwargs: Any, - ): - # Required - self.file_id = str(file_id) - self.file_unique_id = str(file_unique_id) - # Optionals - self.thumb = thumb - self.file_name = file_name - self.mime_type = mime_type - self.file_size = file_size - self.bot = bot - - self._id_attrs = (self.file_unique_id,) - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Document']: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data['thumb'] = PhotoSize.de_json(data.get('thumb'), bot) - - return cls(bot=bot, **data) - - def get_file( - self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None - ) -> 'File': - """Convenience wrapper over :attr:`telegram.Bot.get_file` - - For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. - - Returns: - :class:`telegram.File` - - Raises: - :class:`telegram.error.TelegramError` - - """ - return self.bot.get_file(file_id=self.file_id, timeout=timeout, api_kwargs=api_kwargs) diff --git a/venv/lib/python3.8/site-packages/telegram/files/file.py b/venv/lib/python3.8/site-packages/telegram/files/file.py deleted file mode 100644 index c3391bd..0000000 --- a/venv/lib/python3.8/site-packages/telegram/files/file.py +++ /dev/null @@ -1,213 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram File.""" -import os -import shutil -import urllib.parse as urllib_parse -from base64 import b64decode -from os.path import basename -from typing import IO, TYPE_CHECKING, Any, Optional, Union - -from telegram import TelegramObject -from telegram.passport.credentials import decrypt -from telegram.utils.helpers import is_local_file - -if TYPE_CHECKING: - from telegram import Bot, FileCredentials - - -class File(TelegramObject): - """ - This object represents a file ready to be downloaded. The file can be downloaded with - :attr:`download`. It is guaranteed that the link will be valid for at least 1 hour. When the - link expires, a new one can be requested by calling :meth:`telegram.Bot.get_file`. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`file_unique_id` is equal. - - Note: - * Maximum file size to download is 20 MB. - * If you obtain an instance of this class from :attr:`telegram.PassportFile.get_file`, - then it will automatically be decrypted as it downloads when you call :attr:`download()`. - - Args: - file_id (:obj:`str`): Identifier for this file, which can be used to download - or reuse the file. - file_unique_id (:obj:`str`): Unique identifier for this file, which - is supposed to be the same over time and for different bots. - Can't be used to download or reuse the file. - file_size (:obj:`int`, optional): Optional. File size, if known. - file_path (:obj:`str`, optional): File path. Use :attr:`download` to get the file. - bot (:obj:`telegram.Bot`, optional): Bot to use with shortcut method. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - file_id (:obj:`str`): Identifier for this file. - file_unique_id (:obj:`str`): Unique identifier for this file, which - is supposed to be the same over time and for different bots. - Can't be used to download or reuse the file. - file_size (:obj:`str`): Optional. File size. - file_path (:obj:`str`): Optional. File path. Use :attr:`download` to get the file. - - """ - - __slots__ = ( - 'bot', - 'file_id', - 'file_size', - 'file_unique_id', - 'file_path', - '_credentials', - '_id_attrs', - ) - - def __init__( - self, - file_id: str, - file_unique_id: str, - bot: 'Bot' = None, - file_size: int = None, - file_path: str = None, - **_kwargs: Any, - ): - # Required - self.file_id = str(file_id) - self.file_unique_id = str(file_unique_id) - # Optionals - self.file_size = file_size - self.file_path = file_path - self.bot = bot - self._credentials: Optional['FileCredentials'] = None - - self._id_attrs = (self.file_unique_id,) - - def download( - self, custom_path: str = None, out: IO = None, timeout: int = None - ) -> Union[str, IO]: - """ - Download this file. By default, the file is saved in the current working directory with its - original filename as reported by Telegram. If the file has no filename, it the file ID will - be used as filename. If a :attr:`custom_path` is supplied, it will be saved to that path - instead. If :attr:`out` is defined, the file contents will be saved to that object using - the ``out.write`` method. - - Note: - * :attr:`custom_path` and :attr:`out` are mutually exclusive. - * If neither :attr:`custom_path` nor :attr:`out` is provided and :attr:`file_path` is - the path of a local file (which is the case when a Bot API Server is running in - local mode), this method will just return the path. - - Args: - custom_path (:obj:`str`, optional): Custom path. - out (:obj:`io.BufferedWriter`, optional): A file-like object. Must be opened for - writing in binary mode, if applicable. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - - Returns: - :obj:`str` | :obj:`io.BufferedWriter`: The same object as :attr:`out` if specified. - Otherwise, returns the filename downloaded to or the file path of the local file. - - Raises: - ValueError: If both :attr:`custom_path` and :attr:`out` are passed. - - """ - if custom_path is not None and out is not None: - raise ValueError('custom_path and out are mutually exclusive') - - local_file = is_local_file(self.file_path) - - if local_file: - url = self.file_path - else: - # Convert any UTF-8 char into a url encoded ASCII string. - url = self._get_encoded_url() - - if out: - if local_file: - with open(url, 'rb') as file: - buf = file.read() - else: - buf = self.bot.request.retrieve(url) - if self._credentials: - buf = decrypt( - b64decode(self._credentials.secret), b64decode(self._credentials.hash), buf - ) - out.write(buf) - return out - - if custom_path and local_file: - shutil.copyfile(self.file_path, custom_path) - return custom_path - - if custom_path: - filename = custom_path - elif local_file: - return self.file_path - elif self.file_path: - filename = basename(self.file_path) - else: - filename = os.path.join(os.getcwd(), self.file_id) - - buf = self.bot.request.retrieve(url, timeout=timeout) - if self._credentials: - buf = decrypt( - b64decode(self._credentials.secret), b64decode(self._credentials.hash), buf - ) - with open(filename, 'wb') as fobj: - fobj.write(buf) - return filename - - def _get_encoded_url(self) -> str: - """Convert any UTF-8 char in :obj:`File.file_path` into a url encoded ASCII string.""" - sres = urllib_parse.urlsplit(self.file_path) - return urllib_parse.urlunsplit( - urllib_parse.SplitResult( - sres.scheme, sres.netloc, urllib_parse.quote(sres.path), sres.query, sres.fragment - ) - ) - - def download_as_bytearray(self, buf: bytearray = None) -> bytes: - """Download this file and return it as a bytearray. - - Args: - buf (:obj:`bytearray`, optional): Extend the given bytearray with the downloaded data. - - Returns: - :obj:`bytearray`: The same object as :attr:`buf` if it was specified. Otherwise a newly - allocated :obj:`bytearray`. - - """ - if buf is None: - buf = bytearray() - if is_local_file(self.file_path): - with open(self.file_path, "rb") as file: - buf.extend(file.read()) - else: - buf.extend(self.bot.request.retrieve(self._get_encoded_url())) - return buf - - def set_credentials(self, credentials: 'FileCredentials') -> None: - """Sets the passport credentials for the file. - - Args: - credentials (:class:`telegram.FileCredentials`): The credentials. - """ - self._credentials = credentials diff --git a/venv/lib/python3.8/site-packages/telegram/files/inputfile.py b/venv/lib/python3.8/site-packages/telegram/files/inputfile.py deleted file mode 100644 index 583f4a6..0000000 --- a/venv/lib/python3.8/site-packages/telegram/files/inputfile.py +++ /dev/null @@ -1,119 +0,0 @@ -#!/usr/bin/env python -# pylint: disable=W0622,E0611 -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram InputFile.""" - -import imghdr -import logging -import mimetypes -import os -from typing import IO, Optional, Tuple, Union -from uuid import uuid4 - -from telegram.utils.deprecate import set_new_attribute_deprecated - -DEFAULT_MIME_TYPE = 'application/octet-stream' -logger = logging.getLogger(__name__) - - -class InputFile: - """This object represents a Telegram InputFile. - - Args: - obj (:obj:`File handler` | :obj:`bytes`): An open file descriptor or the files content as - bytes. - filename (:obj:`str`, optional): Filename for this InputFile. - attach (:obj:`bool`, optional): Whether this should be send as one file or is part of a - collection of files. - - Raises: - TelegramError - - Attributes: - input_file_content (:obj:`bytes`): The binary content of the file to send. - filename (:obj:`str`): Optional. Filename for the file to be sent. - attach (:obj:`str`): Optional. Attach id for sending multiple files. - - """ - - __slots__ = ('filename', 'attach', 'input_file_content', 'mimetype', '__dict__') - - def __init__(self, obj: Union[IO, bytes], filename: str = None, attach: bool = None): - self.filename = None - if isinstance(obj, bytes): - self.input_file_content = obj - else: - self.input_file_content = obj.read() - self.attach = 'attached' + uuid4().hex if attach else None - - if filename: - self.filename = filename - elif hasattr(obj, 'name') and not isinstance(obj.name, int): # type: ignore[union-attr] - self.filename = os.path.basename(obj.name) # type: ignore[union-attr] - - image_mime_type = self.is_image(self.input_file_content) - if image_mime_type: - self.mimetype = image_mime_type - elif self.filename: - self.mimetype = mimetypes.guess_type(self.filename)[0] or DEFAULT_MIME_TYPE - else: - self.mimetype = DEFAULT_MIME_TYPE - - if not self.filename: - self.filename = self.mimetype.replace('/', '.') - - def __setattr__(self, key: str, value: object) -> None: - set_new_attribute_deprecated(self, key, value) - - @property - def field_tuple(self) -> Tuple[str, bytes, str]: # skipcq: PY-D0003 - return self.filename, self.input_file_content, self.mimetype - - @staticmethod - def is_image(stream: bytes) -> Optional[str]: - """Check if the content file is an image by analyzing its headers. - - Args: - stream (:obj:`bytes`): A byte stream representing the content of a file. - - Returns: - :obj:`str` | :obj:`None`: The mime-type of an image, if the input is an image, or - :obj:`None` else. - - """ - try: - image = imghdr.what(None, stream) - if image: - return f'image/{image}' - return None - except Exception: - logger.debug( - "Could not parse file content. Assuming that file is not an image.", exc_info=True - ) - return None - - @staticmethod - def is_file(obj: object) -> bool: # skipcq: PY-D0003 - return hasattr(obj, 'read') - - def to_dict(self) -> Optional[str]: - """See :meth:`telegram.TelegramObject.to_dict`.""" - if self.attach: - return 'attach://' + self.attach - return None diff --git a/venv/lib/python3.8/site-packages/telegram/files/inputmedia.py b/venv/lib/python3.8/site-packages/telegram/files/inputmedia.py deleted file mode 100644 index f59cf4d..0000000 --- a/venv/lib/python3.8/site-packages/telegram/files/inputmedia.py +++ /dev/null @@ -1,525 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""Base class for Telegram InputMedia Objects.""" - -from typing import Union, List, Tuple - -from telegram import ( - Animation, - Audio, - Document, - InputFile, - PhotoSize, - TelegramObject, - Video, - MessageEntity, -) -from telegram.utils.helpers import DEFAULT_NONE, parse_file_input -from telegram.utils.types import FileInput, JSONDict, ODVInput - - -class InputMedia(TelegramObject): - """Base class for Telegram InputMedia Objects. - - See :class:`telegram.InputMediaAnimation`, :class:`telegram.InputMediaAudio`, - :class:`telegram.InputMediaDocument`, :class:`telegram.InputMediaPhoto` and - :class:`telegram.InputMediaVideo` for detailed use. - - """ - - __slots__ = () - caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...], None] = None - - def to_dict(self) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict() - - if self.caption_entities: - data['caption_entities'] = [ - ce.to_dict() for ce in self.caption_entities # pylint: disable=E1133 - ] - - return data - - -class InputMediaAnimation(InputMedia): - """Represents an animation file (GIF or H.264/MPEG-4 AVC video without sound) to be sent. - - Note: - When using a :class:`telegram.Animation` for the :attr:`media` attribute. It will take the - width, height and duration from that video, unless otherwise specified with the optional - arguments. - - Args: - media (:obj:`str` | `filelike object` | :obj:`bytes` | :class:`pathlib.Path` | \ - :class:`telegram.Animation`): File to send. Pass a - file_id to send a file that exists on the Telegram servers (recommended), pass an HTTP - URL for Telegram to get a file from the Internet. Lastly you can pass an existing - :class:`telegram.Animation` object to send. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - filename (:obj:`str`, optional): Custom file name for the animation, when uploading a - new file. Convenience parameter, useful e.g. when sending files generated by the - :obj:`tempfile` module. - - .. versionadded:: 13.1 - thumb (`filelike object` | :obj:`bytes` | :class:`pathlib.Path`, optional): Thumbnail of - the file sent; can be ignored if - thumbnail generation for the file is supported server-side. The thumbnail should be - in JPEG format and less than 200 kB in size. A thumbnail's width and height should - not exceed 320. Ignored if the file is not uploaded using multipart/form-data. - Thumbnails can't be reused and can be only uploaded as a new file. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - caption (:obj:`str`, optional): Caption of the animation to be sent, 0-1024 characters - after entities parsing. - parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show - bold, italic, fixed-width text or inline URLs in the media caption. See the constants - in :class:`telegram.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special - entities that appear in the caption, which can be specified instead of parse_mode. - width (:obj:`int`, optional): Animation width. - height (:obj:`int`, optional): Animation height. - duration (:obj:`int`, optional): Animation duration. - - Attributes: - type (:obj:`str`): ``animation``. - media (:obj:`str` | :class:`telegram.InputFile`): Animation to send. - caption (:obj:`str`): Optional. Caption of the document to be sent. - parse_mode (:obj:`str`): Optional. The parse mode to use for text formatting. - caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special - entities that appear in the caption. - thumb (:class:`telegram.InputFile`): Optional. Thumbnail of the file to send. - width (:obj:`int`): Optional. Animation width. - height (:obj:`int`): Optional. Animation height. - duration (:obj:`int`): Optional. Animation duration. - - """ - - __slots__ = ( - 'caption_entities', - 'width', - 'media', - 'thumb', - 'caption', - 'duration', - 'parse_mode', - 'height', - 'type', - ) - - def __init__( - self, - media: Union[FileInput, Animation], - thumb: FileInput = None, - caption: str = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - width: int = None, - height: int = None, - duration: int = None, - caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None, - filename: str = None, - ): - self.type = 'animation' - - if isinstance(media, Animation): - self.media: Union[str, InputFile] = media.file_id - self.width = media.width - self.height = media.height - self.duration = media.duration - else: - self.media = parse_file_input(media, attach=True, filename=filename) - - if thumb: - self.thumb = parse_file_input(thumb, attach=True) - - if caption: - self.caption = caption - self.parse_mode = parse_mode - self.caption_entities = caption_entities - if width: - self.width = width - if height: - self.height = height - if duration: - self.duration = duration - - -class InputMediaPhoto(InputMedia): - """Represents a photo to be sent. - - Args: - media (:obj:`str` | `filelike object` | :obj:`bytes` | :class:`pathlib.Path` | \ - :class:`telegram.PhotoSize`): File to send. Pass a - file_id to send a file that exists on the Telegram servers (recommended), pass an HTTP - URL for Telegram to get a file from the Internet. Lastly you can pass an existing - :class:`telegram.PhotoSize` object to send. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - filename (:obj:`str`, optional): Custom file name for the photo, when uploading a - new file. Convenience parameter, useful e.g. when sending files generated by the - :obj:`tempfile` module. - - .. versionadded:: 13.1 - caption (:obj:`str`, optional ): Caption of the photo to be sent, 0-1024 characters after - entities parsing. - parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show - bold, italic, fixed-width text or inline URLs in the media caption. See the constants - in :class:`telegram.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special - entities that appear in the caption, which can be specified instead of parse_mode. - - Attributes: - type (:obj:`str`): ``photo``. - media (:obj:`str` | :class:`telegram.InputFile`): Photo to send. - caption (:obj:`str`): Optional. Caption of the document to be sent. - parse_mode (:obj:`str`): Optional. The parse mode to use for text formatting. - caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special - entities that appear in the caption. - - """ - - __slots__ = ('caption_entities', 'media', 'caption', 'parse_mode', 'type') - - def __init__( - self, - media: Union[FileInput, PhotoSize], - caption: str = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None, - filename: str = None, - ): - self.type = 'photo' - self.media = parse_file_input(media, PhotoSize, attach=True, filename=filename) - - if caption: - self.caption = caption - self.parse_mode = parse_mode - self.caption_entities = caption_entities - - -class InputMediaVideo(InputMedia): - """Represents a video to be sent. - - Note: - * When using a :class:`telegram.Video` for the :attr:`media` attribute. It will take the - width, height and duration from that video, unless otherwise specified with the optional - arguments. - * ``thumb`` will be ignored for small video files, for which Telegram can easily - generate thumb nails. However, this behaviour is undocumented and might be changed - by Telegram. - - Args: - media (:obj:`str` | `filelike object` | :obj:`bytes` | :class:`pathlib.Path` | \ - :class:`telegram.Video`): File to send. Pass a - file_id to send a file that exists on the Telegram servers (recommended), pass an HTTP - URL for Telegram to get a file from the Internet. Lastly you can pass an existing - :class:`telegram.Video` object to send. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - filename (:obj:`str`, optional): Custom file name for the video, when uploading a - new file. Convenience parameter, useful e.g. when sending files generated by the - :obj:`tempfile` module. - - .. versionadded:: 13.1 - caption (:obj:`str`, optional): Caption of the video to be sent, 0-1024 characters after - entities parsing. - parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show - bold, italic, fixed-width text or inline URLs in the media caption. See the constants - in :class:`telegram.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special - entities that appear in the caption, which can be specified instead of parse_mode. - width (:obj:`int`, optional): Video width. - height (:obj:`int`, optional): Video height. - duration (:obj:`int`, optional): Video duration. - supports_streaming (:obj:`bool`, optional): Pass :obj:`True`, if the uploaded video is - suitable for streaming. - thumb (`filelike object` | :obj:`bytes` | :class:`pathlib.Path`, optional): Thumbnail of - the file sent; can be ignored if - thumbnail generation for the file is supported server-side. The thumbnail should be - in JPEG format and less than 200 kB in size. A thumbnail's width and height should - not exceed 320. Ignored if the file is not uploaded using multipart/form-data. - Thumbnails can't be reused and can be only uploaded as a new file. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - - Attributes: - type (:obj:`str`): ``video``. - media (:obj:`str` | :class:`telegram.InputFile`): Video file to send. - caption (:obj:`str`): Optional. Caption of the document to be sent. - parse_mode (:obj:`str`): Optional. The parse mode to use for text formatting. - caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special - entities that appear in the caption. - width (:obj:`int`): Optional. Video width. - height (:obj:`int`): Optional. Video height. - duration (:obj:`int`): Optional. Video duration. - supports_streaming (:obj:`bool`): Optional. Pass :obj:`True`, if the uploaded video is - suitable for streaming. - thumb (:class:`telegram.InputFile`): Optional. Thumbnail of the file to send. - - """ - - __slots__ = ( - 'caption_entities', - 'width', - 'media', - 'thumb', - 'supports_streaming', - 'caption', - 'duration', - 'parse_mode', - 'height', - 'type', - ) - - def __init__( - self, - media: Union[FileInput, Video], - caption: str = None, - width: int = None, - height: int = None, - duration: int = None, - supports_streaming: bool = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - thumb: FileInput = None, - caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None, - filename: str = None, - ): - self.type = 'video' - - if isinstance(media, Video): - self.media: Union[str, InputFile] = media.file_id - self.width = media.width - self.height = media.height - self.duration = media.duration - else: - self.media = parse_file_input(media, attach=True, filename=filename) - - if thumb: - self.thumb = parse_file_input(thumb, attach=True) - - if caption: - self.caption = caption - self.parse_mode = parse_mode - self.caption_entities = caption_entities - if width: - self.width = width - if height: - self.height = height - if duration: - self.duration = duration - if supports_streaming: - self.supports_streaming = supports_streaming - - -class InputMediaAudio(InputMedia): - """Represents an audio file to be treated as music to be sent. - - Note: - When using a :class:`telegram.Audio` for the :attr:`media` attribute. It will take the - duration, performer and title from that video, unless otherwise specified with the - optional arguments. - - Args: - media (:obj:`str` | `filelike object` | :obj:`bytes` | :class:`pathlib.Path` | \ - :class:`telegram.Audio`): - File to send. Pass a - file_id to send a file that exists on the Telegram servers (recommended), pass an HTTP - URL for Telegram to get a file from the Internet. Lastly you can pass an existing - :class:`telegram.Audio` object to send. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - filename (:obj:`str`, optional): Custom file name for the audio, when uploading a - new file. Convenience parameter, useful e.g. when sending files generated by the - :obj:`tempfile` module. - - .. versionadded:: 13.1 - caption (:obj:`str`, optional): Caption of the audio to be sent, 0-1024 characters after - entities parsing. - parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show - bold, italic, fixed-width text or inline URLs in the media caption. See the constants - in :class:`telegram.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special - entities that appear in the caption, which can be specified instead of parse_mode. - duration (:obj:`int`): Duration of the audio in seconds as defined by sender. - performer (:obj:`str`, optional): Performer of the audio as defined by sender or by audio - tags. - title (:obj:`str`, optional): Title of the audio as defined by sender or by audio tags. - thumb (`filelike object` | :obj:`bytes` | :class:`pathlib.Path`, optional): Thumbnail of - the file sent; can be ignored if - thumbnail generation for the file is supported server-side. The thumbnail should be - in JPEG format and less than 200 kB in size. A thumbnail's width and height should - not exceed 320. Ignored if the file is not uploaded using multipart/form-data. - Thumbnails can't be reused and can be only uploaded as a new file. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - - Attributes: - type (:obj:`str`): ``audio``. - media (:obj:`str` | :class:`telegram.InputFile`): Audio file to send. - caption (:obj:`str`): Optional. Caption of the document to be sent. - parse_mode (:obj:`str`): Optional. The parse mode to use for text formatting. - caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special - entities that appear in the caption. - duration (:obj:`int`): Duration of the audio in seconds. - performer (:obj:`str`): Optional. Performer of the audio as defined by sender or by audio - tags. - title (:obj:`str`): Optional. Title of the audio as defined by sender or by audio tags. - thumb (:class:`telegram.InputFile`): Optional. Thumbnail of the file to send. - - """ - - __slots__ = ( - 'caption_entities', - 'media', - 'thumb', - 'caption', - 'title', - 'duration', - 'type', - 'parse_mode', - 'performer', - ) - - def __init__( - self, - media: Union[FileInput, Audio], - thumb: FileInput = None, - caption: str = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - duration: int = None, - performer: str = None, - title: str = None, - caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None, - filename: str = None, - ): - self.type = 'audio' - - if isinstance(media, Audio): - self.media: Union[str, InputFile] = media.file_id - self.duration = media.duration - self.performer = media.performer - self.title = media.title - else: - self.media = parse_file_input(media, attach=True, filename=filename) - - if thumb: - self.thumb = parse_file_input(thumb, attach=True) - - if caption: - self.caption = caption - self.parse_mode = parse_mode - self.caption_entities = caption_entities - if duration: - self.duration = duration - if performer: - self.performer = performer - if title: - self.title = title - - -class InputMediaDocument(InputMedia): - """Represents a general file to be sent. - - Args: - media (:obj:`str` | `filelike object` | :obj:`bytes` | :class:`pathlib.Path` | \ - :class:`telegram.Document`): File to send. Pass a - file_id to send a file that exists on the Telegram servers (recommended), pass an HTTP - URL for Telegram to get a file from the Internet. Lastly you can pass an existing - :class:`telegram.Document` object to send. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - filename (:obj:`str`, optional): Custom file name for the document, when uploading a - new file. Convenience parameter, useful e.g. when sending files generated by the - :obj:`tempfile` module. - - .. versionadded:: 13.1 - caption (:obj:`str`, optional): Caption of the document to be sent, 0-1024 characters after - entities parsing. - parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show - bold, italic, fixed-width text or inline URLs in the media caption. See the constants - in :class:`telegram.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special - entities that appear in the caption, which can be specified instead of parse_mode. - thumb (`filelike object` | :obj:`bytes` | :class:`pathlib.Path`, optional): Thumbnail of - the file sent; can be ignored if - thumbnail generation for the file is supported server-side. The thumbnail should be - in JPEG format and less than 200 kB in size. A thumbnail's width and height should - not exceed 320. Ignored if the file is not uploaded using multipart/form-data. - Thumbnails can't be reused and can be only uploaded as a new file. - - .. versionchanged:: 13.2 - Accept :obj:`bytes` as input. - disable_content_type_detection (:obj:`bool`, optional): Disables automatic server-side - content type detection for files uploaded using multipart/form-data. Always true, if - the document is sent as part of an album. - - Attributes: - type (:obj:`str`): ``document``. - media (:obj:`str` | :class:`telegram.InputFile`): File to send. - caption (:obj:`str`): Optional. Caption of the document to be sent. - parse_mode (:obj:`str`): Optional. The parse mode to use for text formatting. - caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special - entities that appear in the caption. - thumb (:class:`telegram.InputFile`): Optional. Thumbnail of the file to send. - disable_content_type_detection (:obj:`bool`): Optional. Disables automatic server-side - content type detection for files uploaded using multipart/form-data. Always true, if - the document is sent as part of an album. - - """ - - __slots__ = ( - 'caption_entities', - 'media', - 'thumb', - 'caption', - 'parse_mode', - 'type', - 'disable_content_type_detection', - ) - - def __init__( - self, - media: Union[FileInput, Document], - thumb: FileInput = None, - caption: str = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - disable_content_type_detection: bool = None, - caption_entities: Union[List[MessageEntity], Tuple[MessageEntity, ...]] = None, - filename: str = None, - ): - self.type = 'document' - self.media = parse_file_input(media, Document, attach=True, filename=filename) - - if thumb: - self.thumb = parse_file_input(thumb, attach=True) - - if caption: - self.caption = caption - self.parse_mode = parse_mode - self.caption_entities = caption_entities - self.disable_content_type_detection = disable_content_type_detection diff --git a/venv/lib/python3.8/site-packages/telegram/files/location.py b/venv/lib/python3.8/site-packages/telegram/files/location.py deleted file mode 100644 index 8f5c1c6..0000000 --- a/venv/lib/python3.8/site-packages/telegram/files/location.py +++ /dev/null @@ -1,91 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram Location.""" - -from typing import Any - -from telegram import TelegramObject - - -class Location(TelegramObject): - """This object represents a point on the map. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`longitute` and :attr:`latitude` are equal. - - Args: - longitude (:obj:`float`): Longitude as defined by sender. - latitude (:obj:`float`): Latitude as defined by sender. - horizontal_accuracy (:obj:`float`, optional): The radius of uncertainty for the location, - measured in meters; 0-1500. - live_period (:obj:`int`, optional): Time relative to the message sending date, during which - the location can be updated, in seconds. For active live locations only. - heading (:obj:`int`, optional): The direction in which user is moving, in degrees; 1-360. - For active live locations only. - proximity_alert_radius (:obj:`int`, optional): Maximum distance for proximity alerts about - approaching another chat member, in meters. For sent live locations only. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - longitude (:obj:`float`): Longitude as defined by sender. - latitude (:obj:`float`): Latitude as defined by sender. - horizontal_accuracy (:obj:`float`): Optional. The radius of uncertainty for the location, - measured in meters. - live_period (:obj:`int`): Optional. Time relative to the message sending date, during which - the location can be updated, in seconds. For active live locations only. - heading (:obj:`int`): Optional. The direction in which user is moving, in degrees. - For active live locations only. - proximity_alert_radius (:obj:`int`): Optional. Maximum distance for proximity alerts about - approaching another chat member, in meters. For sent live locations only. - - """ - - __slots__ = ( - 'longitude', - 'horizontal_accuracy', - 'proximity_alert_radius', - 'live_period', - 'latitude', - 'heading', - '_id_attrs', - ) - - def __init__( - self, - longitude: float, - latitude: float, - horizontal_accuracy: float = None, - live_period: int = None, - heading: int = None, - proximity_alert_radius: int = None, - **_kwargs: Any, - ): - # Required - self.longitude = float(longitude) - self.latitude = float(latitude) - - # Optionals - self.horizontal_accuracy = float(horizontal_accuracy) if horizontal_accuracy else None - self.live_period = int(live_period) if live_period else None - self.heading = int(heading) if heading else None - self.proximity_alert_radius = ( - int(proximity_alert_radius) if proximity_alert_radius else None - ) - - self._id_attrs = (self.longitude, self.latitude) diff --git a/venv/lib/python3.8/site-packages/telegram/files/photosize.py b/venv/lib/python3.8/site-packages/telegram/files/photosize.py deleted file mode 100644 index 831a7c0..0000000 --- a/venv/lib/python3.8/site-packages/telegram/files/photosize.py +++ /dev/null @@ -1,98 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram PhotoSize.""" - -from typing import TYPE_CHECKING, Any - -from telegram import TelegramObject -from telegram.utils.helpers import DEFAULT_NONE -from telegram.utils.types import JSONDict, ODVInput - -if TYPE_CHECKING: - from telegram import Bot, File - - -class PhotoSize(TelegramObject): - """This object represents one size of a photo or a file/sticker thumbnail. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`file_unique_id` is equal. - - Args: - file_id (:obj:`str`): Identifier for this file, which can be used to download - or reuse the file. - file_unique_id (:obj:`str`): Unique identifier for this file, which - is supposed to be the same over time and for different bots. - Can't be used to download or reuse the file. - width (:obj:`int`): Photo width. - height (:obj:`int`): Photo height. - file_size (:obj:`int`, optional): File size. - bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - file_id (:obj:`str`): Identifier for this file. - file_unique_id (:obj:`str`): Unique identifier for this file, which - is supposed to be the same over time and for different bots. - Can't be used to download or reuse the file. - width (:obj:`int`): Photo width. - height (:obj:`int`): Photo height. - file_size (:obj:`int`): Optional. File size. - bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods. - - """ - - __slots__ = ('bot', 'width', 'file_id', 'file_size', 'height', 'file_unique_id', '_id_attrs') - - def __init__( - self, - file_id: str, - file_unique_id: str, - width: int, - height: int, - file_size: int = None, - bot: 'Bot' = None, - **_kwargs: Any, - ): - # Required - self.file_id = str(file_id) - self.file_unique_id = str(file_unique_id) - self.width = int(width) - self.height = int(height) - # Optionals - self.file_size = file_size - self.bot = bot - - self._id_attrs = (self.file_unique_id,) - - def get_file( - self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None - ) -> 'File': - """Convenience wrapper over :attr:`telegram.Bot.get_file` - - For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. - - Returns: - :class:`telegram.File` - - Raises: - :class:`telegram.error.TelegramError` - - """ - return self.bot.get_file(file_id=self.file_id, timeout=timeout, api_kwargs=api_kwargs) diff --git a/venv/lib/python3.8/site-packages/telegram/files/sticker.py b/venv/lib/python3.8/site-packages/telegram/files/sticker.py deleted file mode 100644 index 681c708..0000000 --- a/venv/lib/python3.8/site-packages/telegram/files/sticker.py +++ /dev/null @@ -1,288 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains objects that represents stickers.""" - -from typing import TYPE_CHECKING, Any, List, Optional, ClassVar - -from telegram import PhotoSize, TelegramObject, constants -from telegram.utils.helpers import DEFAULT_NONE -from telegram.utils.types import JSONDict, ODVInput - -if TYPE_CHECKING: - from telegram import Bot, File - - -class Sticker(TelegramObject): - """This object represents a sticker. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`file_unique_id` is equal. - - Args: - file_id (:obj:`str`): Identifier for this file, which can be used to download - or reuse the file. - file_unique_id (:obj:`str`): Unique identifier for this file, which - is supposed to be the same over time and for different bots. - Can't be used to download or reuse the file. - width (:obj:`int`): Sticker width. - height (:obj:`int`): Sticker height. - is_animated (:obj:`bool`): :obj:`True`, if the sticker is animated. - thumb (:class:`telegram.PhotoSize`, optional): Sticker thumbnail in the .WEBP or .JPG - format. - emoji (:obj:`str`, optional): Emoji associated with the sticker - set_name (:obj:`str`, optional): Name of the sticker set to which the sticker - belongs. - mask_position (:class:`telegram.MaskPosition`, optional): For mask stickers, the - position where the mask should be placed. - file_size (:obj:`int`, optional): File size. - bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods. - **kwargs (obj:`dict`): Arbitrary keyword arguments. - - Attributes: - file_id (:obj:`str`): Identifier for this file. - file_unique_id (:obj:`str`): Unique identifier for this file, which - is supposed to be the same over time and for different bots. - Can't be used to download or reuse the file. - width (:obj:`int`): Sticker width. - height (:obj:`int`): Sticker height. - is_animated (:obj:`bool`): :obj:`True`, if the sticker is animated. - thumb (:class:`telegram.PhotoSize`): Optional. Sticker thumbnail in the .webp or .jpg - format. - emoji (:obj:`str`): Optional. Emoji associated with the sticker. - set_name (:obj:`str`): Optional. Name of the sticker set to which the sticker belongs. - mask_position (:class:`telegram.MaskPosition`): Optional. For mask stickers, the position - where the mask should be placed. - file_size (:obj:`int`): Optional. File size. - bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods. - - """ - - __slots__ = ( - 'bot', - 'width', - 'file_id', - 'is_animated', - 'file_size', - 'thumb', - 'set_name', - 'mask_position', - 'height', - 'file_unique_id', - 'emoji', - '_id_attrs', - ) - - def __init__( - self, - file_id: str, - file_unique_id: str, - width: int, - height: int, - is_animated: bool, - thumb: PhotoSize = None, - emoji: str = None, - file_size: int = None, - set_name: str = None, - mask_position: 'MaskPosition' = None, - bot: 'Bot' = None, - **_kwargs: Any, - ): - # Required - self.file_id = str(file_id) - self.file_unique_id = str(file_unique_id) - self.width = int(width) - self.height = int(height) - self.is_animated = is_animated - # Optionals - self.thumb = thumb - self.emoji = emoji - self.file_size = file_size - self.set_name = set_name - self.mask_position = mask_position - self.bot = bot - - self._id_attrs = (self.file_unique_id,) - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Sticker']: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data['thumb'] = PhotoSize.de_json(data.get('thumb'), bot) - data['mask_position'] = MaskPosition.de_json(data.get('mask_position'), bot) - - return cls(bot=bot, **data) - - def get_file( - self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None - ) -> 'File': - """Convenience wrapper over :attr:`telegram.Bot.get_file` - - For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. - - Returns: - :class:`telegram.File` - - Raises: - :class:`telegram.error.TelegramError` - - """ - return self.bot.get_file(file_id=self.file_id, timeout=timeout, api_kwargs=api_kwargs) - - -class StickerSet(TelegramObject): - """This object represents a sticker set. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`name` is equal. - - Attributes: - name (:obj:`str`): Sticker set name. - title (:obj:`str`): Sticker set title. - is_animated (:obj:`bool`): :obj:`True`, if the sticker set contains animated stickers. - contains_masks (:obj:`bool`): :obj:`True`, if the sticker set contains masks. - stickers (List[:class:`telegram.Sticker`]): List of all set stickers. - thumb (:class:`telegram.PhotoSize`): Optional. Sticker set thumbnail in the .WEBP or .TGS - format. - - Args: - name (:obj:`str`): Sticker set name. - title (:obj:`str`): Sticker set title. - is_animated (:obj:`bool`): :obj:`True`, if the sticker set contains animated stickers. - contains_masks (:obj:`bool`): :obj:`True`, if the sticker set contains masks. - stickers (List[:class:`telegram.Sticker`]): List of all set stickers. - thumb (:class:`telegram.PhotoSize`, optional): Sticker set thumbnail in the .WEBP or .TGS - format. - - """ - - __slots__ = ( - 'is_animated', - 'contains_masks', - 'thumb', - 'title', - 'stickers', - 'name', - '_id_attrs', - ) - - def __init__( - self, - name: str, - title: str, - is_animated: bool, - contains_masks: bool, - stickers: List[Sticker], - thumb: PhotoSize = None, - **_kwargs: Any, - ): - self.name = name - self.title = title - self.is_animated = is_animated - self.contains_masks = contains_masks - self.stickers = stickers - # Optionals - self.thumb = thumb - - self._id_attrs = (self.name,) - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['StickerSet']: - """See :meth:`telegram.TelegramObject.de_json`.""" - if not data: - return None - - data['thumb'] = PhotoSize.de_json(data.get('thumb'), bot) - data['stickers'] = Sticker.de_list(data.get('stickers'), bot) - - return cls(bot=bot, **data) - - def to_dict(self) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict() - - data['stickers'] = [s.to_dict() for s in data.get('stickers')] - - return data - - -class MaskPosition(TelegramObject): - """This object describes the position on faces where a mask should be placed by default. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`point`, :attr:`x_shift`, :attr:`y_shift` and, :attr:`scale` - are equal. - - Attributes: - point (:obj:`str`): The part of the face relative to which the mask should be placed. - One of ``'forehead'``, ``'eyes'``, ``'mouth'``, or ``'chin'``. - x_shift (:obj:`float`): Shift by X-axis measured in widths of the mask scaled to the face - size, from left to right. - y_shift (:obj:`float`): Shift by Y-axis measured in heights of the mask scaled to the face - size, from top to bottom. - scale (:obj:`float`): Mask scaling coefficient. For example, 2.0 means double size. - - Note: - :attr:`type` should be one of the following: `forehead`, `eyes`, `mouth` or `chin`. You can - use the class constants for those. - - Args: - point (:obj:`str`): The part of the face relative to which the mask should be placed. - One of ``'forehead'``, ``'eyes'``, ``'mouth'``, or ``'chin'``. - x_shift (:obj:`float`): Shift by X-axis measured in widths of the mask scaled to the face - size, from left to right. For example, choosing -1.0 will place mask just to the left - of the default mask position. - y_shift (:obj:`float`): Shift by Y-axis measured in heights of the mask scaled to the face - size, from top to bottom. For example, 1.0 will place the mask just below the default - mask position. - scale (:obj:`float`): Mask scaling coefficient. For example, 2.0 means double size. - - """ - - __slots__ = ('point', 'scale', 'x_shift', 'y_shift', '_id_attrs') - - FOREHEAD: ClassVar[str] = constants.STICKER_FOREHEAD - """:const:`telegram.constants.STICKER_FOREHEAD`""" - EYES: ClassVar[str] = constants.STICKER_EYES - """:const:`telegram.constants.STICKER_EYES`""" - MOUTH: ClassVar[str] = constants.STICKER_MOUTH - """:const:`telegram.constants.STICKER_MOUTH`""" - CHIN: ClassVar[str] = constants.STICKER_CHIN - """:const:`telegram.constants.STICKER_CHIN`""" - - def __init__(self, point: str, x_shift: float, y_shift: float, scale: float, **_kwargs: Any): - self.point = point - self.x_shift = x_shift - self.y_shift = y_shift - self.scale = scale - - self._id_attrs = (self.point, self.x_shift, self.y_shift, self.scale) - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['MaskPosition']: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if data is None: - return None - - return cls(**data) diff --git a/venv/lib/python3.8/site-packages/telegram/files/venue.py b/venv/lib/python3.8/site-packages/telegram/files/venue.py deleted file mode 100644 index 3ba2c53..0000000 --- a/venv/lib/python3.8/site-packages/telegram/files/venue.py +++ /dev/null @@ -1,107 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram Venue.""" - -from typing import TYPE_CHECKING, Any, Optional - -from telegram import Location, TelegramObject -from telegram.utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - - -class Venue(TelegramObject): - """This object represents a venue. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`location` and :attr:`title` are equal. - - Note: - Foursquare details and Google Pace details are mutually exclusive. However, this - behaviour is undocumented and might be changed by Telegram. - - Args: - location (:class:`telegram.Location`): Venue location. - title (:obj:`str`): Name of the venue. - address (:obj:`str`): Address of the venue. - foursquare_id (:obj:`str`, optional): Foursquare identifier of the venue. - foursquare_type (:obj:`str`, optional): Foursquare type of the venue. (For example, - "arts_entertainment/default", "arts_entertainment/aquarium" or "food/icecream".) - google_place_id (:obj:`str`, optional): Google Places identifier of the venue. - google_place_type (:obj:`str`, optional): Google Places type of the venue. (See - `supported types <https://developers.google.com/places/web-service/supported_types>`_.) - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - location (:class:`telegram.Location`): Venue location. - title (:obj:`str`): Name of the venue. - address (:obj:`str`): Address of the venue. - foursquare_id (:obj:`str`): Optional. Foursquare identifier of the venue. - foursquare_type (:obj:`str`): Optional. Foursquare type of the venue. - google_place_id (:obj:`str`): Optional. Google Places identifier of the venue. - google_place_type (:obj:`str`): Optional. Google Places type of the venue. - - """ - - __slots__ = ( - 'google_place_type', - 'location', - 'title', - 'address', - 'foursquare_type', - 'foursquare_id', - 'google_place_id', - '_id_attrs', - ) - - def __init__( - self, - location: Location, - title: str, - address: str, - foursquare_id: str = None, - foursquare_type: str = None, - google_place_id: str = None, - google_place_type: str = None, - **_kwargs: Any, - ): - # Required - self.location = location - self.title = title - self.address = address - # Optionals - self.foursquare_id = foursquare_id - self.foursquare_type = foursquare_type - self.google_place_id = google_place_id - self.google_place_type = google_place_type - - self._id_attrs = (self.location, self.title) - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Venue']: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data['location'] = Location.de_json(data.get('location'), bot) - - return cls(**data) diff --git a/venv/lib/python3.8/site-packages/telegram/files/video.py b/venv/lib/python3.8/site-packages/telegram/files/video.py deleted file mode 100644 index 76bb07c..0000000 --- a/venv/lib/python3.8/site-packages/telegram/files/video.py +++ /dev/null @@ -1,138 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram Video.""" - -from typing import TYPE_CHECKING, Any, Optional - -from telegram import PhotoSize, TelegramObject -from telegram.utils.helpers import DEFAULT_NONE -from telegram.utils.types import JSONDict, ODVInput - -if TYPE_CHECKING: - from telegram import Bot, File - - -class Video(TelegramObject): - """This object represents a video file. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`file_unique_id` is equal. - - Args: - file_id (:obj:`str`): Identifier for this file, which can be used to download - or reuse the file. - file_unique_id (:obj:`str`): Unique identifier for this file, which - is supposed to be the same over time and for different bots. - Can't be used to download or reuse the file. - width (:obj:`int`): Video width as defined by sender. - height (:obj:`int`): Video height as defined by sender. - duration (:obj:`int`): Duration of the video in seconds as defined by sender. - thumb (:class:`telegram.PhotoSize`, optional): Video thumbnail. - file_name (:obj:`str`, optional): Original filename as defined by sender. - mime_type (:obj:`str`, optional): Mime type of a file as defined by sender. - file_size (:obj:`int`, optional): File size. - bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - file_id (:obj:`str`): Identifier for this file. - file_unique_id (:obj:`str`): Unique identifier for this file, which - is supposed to be the same over time and for different bots. - Can't be used to download or reuse the file. - width (:obj:`int`): Video width as defined by sender. - height (:obj:`int`): Video height as defined by sender. - duration (:obj:`int`): Duration of the video in seconds as defined by sender. - thumb (:class:`telegram.PhotoSize`): Optional. Video thumbnail. - file_name (:obj:`str`): Optional. Original filename as defined by sender. - mime_type (:obj:`str`): Optional. Mime type of a file as defined by sender. - file_size (:obj:`int`): Optional. File size. - bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods. - - """ - - __slots__ = ( - 'bot', - 'width', - 'file_id', - 'file_size', - 'file_name', - 'thumb', - 'duration', - 'mime_type', - 'height', - 'file_unique_id', - '_id_attrs', - ) - - def __init__( - self, - file_id: str, - file_unique_id: str, - width: int, - height: int, - duration: int, - thumb: PhotoSize = None, - mime_type: str = None, - file_size: int = None, - bot: 'Bot' = None, - file_name: str = None, - **_kwargs: Any, - ): - # Required - self.file_id = str(file_id) - self.file_unique_id = str(file_unique_id) - self.width = int(width) - self.height = int(height) - self.duration = int(duration) - # Optionals - self.thumb = thumb - self.file_name = file_name - self.mime_type = mime_type - self.file_size = file_size - self.bot = bot - - self._id_attrs = (self.file_unique_id,) - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Video']: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data['thumb'] = PhotoSize.de_json(data.get('thumb'), bot) - - return cls(bot=bot, **data) - - def get_file( - self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None - ) -> 'File': - """Convenience wrapper over :attr:`telegram.Bot.get_file` - - For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. - - Returns: - :class:`telegram.File` - - Raises: - :class:`telegram.error.TelegramError` - - """ - return self.bot.get_file(file_id=self.file_id, timeout=timeout, api_kwargs=api_kwargs) diff --git a/venv/lib/python3.8/site-packages/telegram/files/videonote.py b/venv/lib/python3.8/site-packages/telegram/files/videonote.py deleted file mode 100644 index 8c70406..0000000 --- a/venv/lib/python3.8/site-packages/telegram/files/videonote.py +++ /dev/null @@ -1,124 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram VideoNote.""" - -from typing import TYPE_CHECKING, Optional, Any - -from telegram import PhotoSize, TelegramObject -from telegram.utils.helpers import DEFAULT_NONE -from telegram.utils.types import JSONDict, ODVInput - -if TYPE_CHECKING: - from telegram import Bot, File - - -class VideoNote(TelegramObject): - """This object represents a video message (available in Telegram apps as of v.4.0). - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`file_unique_id` is equal. - - Args: - file_id (:obj:`str`): Identifier for this file, which can be used to download - or reuse the file. - file_unique_id (:obj:`str`): Unique identifier for this file, which - is supposed to be the same over time and for different bots. - Can't be used to download or reuse the file. - length (:obj:`int`): Video width and height (diameter of the video message) as defined - by sender. - duration (:obj:`int`): Duration of the video in seconds as defined by sender. - thumb (:class:`telegram.PhotoSize`, optional): Video thumbnail. - file_size (:obj:`int`, optional): File size. - bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - file_id (:obj:`str`): Identifier for this file. - file_unique_id (:obj:`str`): Unique identifier for this file, which - is supposed to be the same over time and for different bots. - Can't be used to download or reuse the file. - length (:obj:`int`): Video width and height as defined by sender. - duration (:obj:`int`): Duration of the video in seconds as defined by sender. - thumb (:class:`telegram.PhotoSize`): Optional. Video thumbnail. - file_size (:obj:`int`): Optional. File size. - bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods. - - """ - - __slots__ = ( - 'bot', - 'length', - 'file_id', - 'file_size', - 'thumb', - 'duration', - 'file_unique_id', - '_id_attrs', - ) - - def __init__( - self, - file_id: str, - file_unique_id: str, - length: int, - duration: int, - thumb: PhotoSize = None, - file_size: int = None, - bot: 'Bot' = None, - **_kwargs: Any, - ): - # Required - self.file_id = str(file_id) - self.file_unique_id = str(file_unique_id) - self.length = int(length) - self.duration = int(duration) - # Optionals - self.thumb = thumb - self.file_size = file_size - self.bot = bot - - self._id_attrs = (self.file_unique_id,) - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['VideoNote']: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data['thumb'] = PhotoSize.de_json(data.get('thumb'), bot) - - return cls(bot=bot, **data) - - def get_file( - self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None - ) -> 'File': - """Convenience wrapper over :attr:`telegram.Bot.get_file` - - For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. - - Returns: - :class:`telegram.File` - - Raises: - :class:`telegram.error.TelegramError` - - """ - return self.bot.get_file(file_id=self.file_id, timeout=timeout, api_kwargs=api_kwargs) diff --git a/venv/lib/python3.8/site-packages/telegram/files/voice.py b/venv/lib/python3.8/site-packages/telegram/files/voice.py deleted file mode 100644 index f65c5c5..0000000 --- a/venv/lib/python3.8/site-packages/telegram/files/voice.py +++ /dev/null @@ -1,106 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram Voice.""" - -from typing import TYPE_CHECKING, Any - -from telegram import TelegramObject -from telegram.utils.helpers import DEFAULT_NONE -from telegram.utils.types import JSONDict, ODVInput - -if TYPE_CHECKING: - from telegram import Bot, File - - -class Voice(TelegramObject): - """This object represents a voice note. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`file_unique_id` is equal. - - Args: - file_id (:obj:`str`): Identifier for this file, which can be used to download - or reuse the file. - file_unique_id (:obj:`str`): Unique identifier for this file, which - is supposed to be the same over time and for different bots. - Can't be used to download or reuse the file. - duration (:obj:`int`, optional): Duration of the audio in seconds as defined by sender. - mime_type (:obj:`str`, optional): MIME type of the file as defined by sender. - file_size (:obj:`int`, optional): File size. - bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - file_id (:obj:`str`): Identifier for this file. - file_unique_id (:obj:`str`): Unique identifier for this file, which - is supposed to be the same over time and for different bots. - Can't be used to download or reuse the file. - duration (:obj:`int`): Duration of the audio in seconds as defined by sender. - mime_type (:obj:`str`): Optional. MIME type of the file as defined by sender. - file_size (:obj:`int`): Optional. File size. - bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods. - - """ - - __slots__ = ( - 'bot', - 'file_id', - 'file_size', - 'duration', - 'mime_type', - 'file_unique_id', - '_id_attrs', - ) - - def __init__( - self, - file_id: str, - file_unique_id: str, - duration: int, - mime_type: str = None, - file_size: int = None, - bot: 'Bot' = None, - **_kwargs: Any, - ): - # Required - self.file_id = str(file_id) - self.file_unique_id = str(file_unique_id) - self.duration = int(duration) - # Optionals - self.mime_type = mime_type - self.file_size = file_size - self.bot = bot - - self._id_attrs = (self.file_unique_id,) - - def get_file( - self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None - ) -> 'File': - """Convenience wrapper over :attr:`telegram.Bot.get_file` - - For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. - - Returns: - :class:`telegram.File` - - Raises: - :class:`telegram.error.TelegramError` - - """ - return self.bot.get_file(file_id=self.file_id, timeout=timeout, api_kwargs=api_kwargs) diff --git a/venv/lib/python3.8/site-packages/telegram/forcereply.py b/venv/lib/python3.8/site-packages/telegram/forcereply.py deleted file mode 100644 index aaf7c73..0000000 --- a/venv/lib/python3.8/site-packages/telegram/forcereply.py +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram ForceReply.""" - -from typing import Any - -from telegram import ReplyMarkup - - -class ForceReply(ReplyMarkup): - """ - Upon receiving a message with this object, Telegram clients will display a reply interface to - the user (act as if the user has selected the bot's message and tapped 'Reply'). This can be - extremely useful if you want to create user-friendly step-by-step interfaces without having - to sacrifice privacy mode. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`selective` is equal. - - Args: - selective (:obj:`bool`, optional): Use this parameter if you want to force reply from - specific users only. Targets: - - 1) Users that are @mentioned in the text of the Message object. - 2) If the bot's message is a reply (has reply_to_message_id), sender of the - original message. - - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - force_reply (:obj:`True`): Shows reply interface to the user, as if they manually selected - the bots message and tapped 'Reply'. - selective (:obj:`bool`): Optional. Force reply from specific users only. - - """ - - __slots__ = ('selective', 'force_reply', '_id_attrs') - - def __init__(self, force_reply: bool = True, selective: bool = False, **_kwargs: Any): - # Required - self.force_reply = bool(force_reply) - # Optionals - self.selective = bool(selective) - - self._id_attrs = (self.selective,) diff --git a/venv/lib/python3.8/site-packages/telegram/games/__init__.py b/venv/lib/python3.8/site-packages/telegram/games/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.8/site-packages/telegram/games/callbackgame.py b/venv/lib/python3.8/site-packages/telegram/games/callbackgame.py deleted file mode 100644 index 8a116da..0000000 --- a/venv/lib/python3.8/site-packages/telegram/games/callbackgame.py +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram CallbackGame.""" - -from telegram import TelegramObject - - -class CallbackGame(TelegramObject): - """A placeholder, currently holds no information. Use BotFather to set up your game.""" - - __slots__ = () diff --git a/venv/lib/python3.8/site-packages/telegram/games/game.py b/venv/lib/python3.8/site-packages/telegram/games/game.py deleted file mode 100644 index d56bebe..0000000 --- a/venv/lib/python3.8/site-packages/telegram/games/game.py +++ /dev/null @@ -1,186 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram Game.""" - -import sys -from typing import TYPE_CHECKING, Any, Dict, List, Optional - -from telegram import Animation, MessageEntity, PhotoSize, TelegramObject -from telegram.utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - - -class Game(TelegramObject): - """ - This object represents a game. Use `BotFather <https://t.me/BotFather>`_ to create and edit - games, their short names will act as unique identifiers. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`title`, :attr:`description` and :attr:`photo` are equal. - - Args: - title (:obj:`str`): Title of the game. - description (:obj:`str`): Description of the game. - photo (List[:class:`telegram.PhotoSize`]): Photo that will be displayed in the game message - in chats. - text (:obj:`str`, optional): Brief description of the game or high scores included in the - game message. Can be automatically edited to include current high scores for the game - when the bot calls :meth:`telegram.Bot.set_game_score`, or manually edited - using :meth:`telegram.Bot.edit_message_text`. - 0-4096 characters. Also found as ``telegram.constants.MAX_MESSAGE_LENGTH``. - text_entities (List[:class:`telegram.MessageEntity`], optional): Special entities that - appear in text, such as usernames, URLs, bot commands, etc. - animation (:class:`telegram.Animation`, optional): Animation that will be displayed in the - game message in chats. Upload via `BotFather <https://t.me/BotFather>`_. - - Attributes: - title (:obj:`str`): Title of the game. - description (:obj:`str`): Description of the game. - photo (List[:class:`telegram.PhotoSize`]): Photo that will be displayed in the game message - in chats. - text (:obj:`str`): Optional. Brief description of the game or high scores included in the - game message. Can be automatically edited to include current high scores for the game - when the bot calls :meth:`telegram.Bot.set_game_score`, or manually edited - using :meth:`telegram.Bot.edit_message_text`. - text_entities (List[:class:`telegram.MessageEntity`]): Optional. Special entities that - appear in text, such as usernames, URLs, bot commands, etc. - animation (:class:`telegram.Animation`): Optional. Animation that will be displayed in the - game message in chats. Upload via `BotFather <https://t.me/BotFather>`_. - - """ - - __slots__ = ( - 'title', - 'photo', - 'description', - 'text_entities', - 'text', - 'animation', - '_id_attrs', - ) - - def __init__( - self, - title: str, - description: str, - photo: List[PhotoSize], - text: str = None, - text_entities: List[MessageEntity] = None, - animation: Animation = None, - **_kwargs: Any, - ): - # Required - self.title = title - self.description = description - self.photo = photo - # Optionals - self.text = text - self.text_entities = text_entities or [] - self.animation = animation - - self._id_attrs = (self.title, self.description, self.photo) - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Game']: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data['photo'] = PhotoSize.de_list(data.get('photo'), bot) - data['text_entities'] = MessageEntity.de_list(data.get('text_entities'), bot) - data['animation'] = Animation.de_json(data.get('animation'), bot) - - return cls(**data) - - def to_dict(self) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict() - - data['photo'] = [p.to_dict() for p in self.photo] - if self.text_entities: - data['text_entities'] = [x.to_dict() for x in self.text_entities] - - return data - - def parse_text_entity(self, entity: MessageEntity) -> str: - """Returns the text from a given :class:`telegram.MessageEntity`. - - Note: - This method is present because Telegram calculates the offset and length in - UTF-16 codepoint pairs, which some versions of Python don't handle automatically. - (That is, you can't just slice ``Message.text`` with the offset and length.) - - Args: - entity (:class:`telegram.MessageEntity`): The entity to extract the text from. It must - be an entity that belongs to this message. - - Returns: - :obj:`str`: The text of the given entity. - - Raises: - RuntimeError: If this game has no text. - - """ - if not self.text: - raise RuntimeError("This Game has no 'text'.") - - # Is it a narrow build, if so we don't need to convert - if sys.maxunicode == 0xFFFF: - return self.text[entity.offset : entity.offset + entity.length] - entity_text = self.text.encode('utf-16-le') - entity_text = entity_text[entity.offset * 2 : (entity.offset + entity.length) * 2] - - return entity_text.decode('utf-16-le') - - def parse_text_entities(self, types: List[str] = None) -> Dict[MessageEntity, str]: - """ - Returns a :obj:`dict` that maps :class:`telegram.MessageEntity` to :obj:`str`. - It contains entities from this message filtered by their ``type`` attribute as the key, and - the text that each entity belongs to as the value of the :obj:`dict`. - - Note: - This method should always be used instead of the :attr:`text_entities` attribute, since - it calculates the correct substring from the message text based on UTF-16 codepoints. - See :attr:`parse_text_entity` for more info. - - Args: - types (List[:obj:`str`], optional): List of ``MessageEntity`` types as strings. If the - ``type`` attribute of an entity is contained in this list, it will be returned. - Defaults to :attr:`telegram.MessageEntity.ALL_TYPES`. - - Returns: - Dict[:class:`telegram.MessageEntity`, :obj:`str`]: A dictionary of entities mapped to - the text that belongs to them, calculated based on UTF-16 codepoints. - - """ - if types is None: - types = MessageEntity.ALL_TYPES - - return { - entity: self.parse_text_entity(entity) - for entity in (self.text_entities or []) - if entity.type in types - } - - def __hash__(self) -> int: - return hash((self.title, self.description, tuple(p for p in self.photo))) diff --git a/venv/lib/python3.8/site-packages/telegram/games/gamehighscore.py b/venv/lib/python3.8/site-packages/telegram/games/gamehighscore.py deleted file mode 100644 index bfa7cbf..0000000 --- a/venv/lib/python3.8/site-packages/telegram/games/gamehighscore.py +++ /dev/null @@ -1,67 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram GameHighScore.""" - -from typing import TYPE_CHECKING, Optional - -from telegram import TelegramObject, User -from telegram.utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - - -class GameHighScore(TelegramObject): - """This object represents one row of the high scores table for a game. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`position`, :attr:`user` and :attr:`score` are equal. - - Args: - position (:obj:`int`): Position in high score table for the game. - user (:class:`telegram.User`): User. - score (:obj:`int`): Score. - - Attributes: - position (:obj:`int`): Position in high score table for the game. - user (:class:`telegram.User`): User. - score (:obj:`int`): Score. - - """ - - __slots__ = ('position', 'user', 'score', '_id_attrs') - - def __init__(self, position: int, user: User, score: int): - self.position = position - self.user = user - self.score = score - - self._id_attrs = (self.position, self.user, self.score) - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['GameHighScore']: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data['user'] = User.de_json(data.get('user'), bot) - - return cls(**data) diff --git a/venv/lib/python3.8/site-packages/telegram/inline/__init__.py b/venv/lib/python3.8/site-packages/telegram/inline/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinekeyboardbutton.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinekeyboardbutton.py deleted file mode 100644 index b9d0c32..0000000 --- a/venv/lib/python3.8/site-packages/telegram/inline/inlinekeyboardbutton.py +++ /dev/null @@ -1,162 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram InlineKeyboardButton.""" - -from typing import TYPE_CHECKING, Any - -from telegram import TelegramObject - -if TYPE_CHECKING: - from telegram import CallbackGame, LoginUrl - - -class InlineKeyboardButton(TelegramObject): - """This object represents one button of an inline keyboard. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`text`, :attr:`url`, :attr:`login_url`, :attr:`callback_data`, - :attr:`switch_inline_query`, :attr:`switch_inline_query_current_chat`, :attr:`callback_game` - and :attr:`pay` are equal. - - Note: - * You must use exactly one of the optional fields. Mind that :attr:`callback_game` is not - working as expected. Putting a game short name in it might, but is not guaranteed to - work. - * If your bot allows for arbitrary callback data, in keyboards returned in a response - from telegram, :attr:`callback_data` maybe be an instance of - :class:`telegram.ext.InvalidCallbackData`. This will be the case, if the data - associated with the button was already deleted. - - .. versionadded:: 13.6 - - Warning: - If your bot allows your arbitrary callback data, buttons whose callback data is a - non-hashable object will be come unhashable. Trying to evaluate ``hash(button)`` will - result in a :class:`TypeError`. - - .. versionchanged:: 13.6 - - Args: - text (:obj:`str`): Label text on the button. - url (:obj:`str`, optional): HTTP or tg:// url to be opened when button is pressed. - login_url (:class:`telegram.LoginUrl`, optional): An HTTP URL used to automatically - authorize the user. Can be used as a replacement for the Telegram Login Widget. - callback_data (:obj:`str` | :obj:`Any`, optional): Data to be sent in a callback query to - the bot when button is pressed, UTF-8 1-64 bytes. If the bot instance allows arbitrary - callback data, anything can be passed. - switch_inline_query (:obj:`str`, optional): If set, pressing the button will prompt the - user to select one of their chats, open that chat and insert the bot's username and the - specified inline query in the input field. Can be empty, in which case just the bot's - username will be inserted. This offers an easy way for users to start using your bot - in inline mode when they are currently in a private chat with it. Especially useful - when combined with switch_pm* actions - in this case the user will be automatically - returned to the chat they switched from, skipping the chat selection screen. - switch_inline_query_current_chat (:obj:`str`, optional): If set, pressing the button will - insert the bot's username and the specified inline query in the current chat's input - field. Can be empty, in which case only the bot's username will be inserted. This - offers a quick way for the user to open your bot in inline mode in the same chat - good - for selecting something from multiple options. - callback_game (:class:`telegram.CallbackGame`, optional): Description of the game that will - be launched when the user presses the button. This type of button must always be - the ``first`` button in the first row. - pay (:obj:`bool`, optional): Specify :obj:`True`, to send a Pay button. This type of button - must always be the ``first`` button in the first row. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - text (:obj:`str`): Label text on the button. - url (:obj:`str`): Optional. HTTP or tg:// url to be opened when button is pressed. - login_url (:class:`telegram.LoginUrl`): Optional. An HTTP URL used to automatically - authorize the user. Can be used as a replacement for the Telegram Login Widget. - callback_data (:obj:`str` | :obj:`object`): Optional. Data to be sent in a callback query - to the bot when button is pressed, UTF-8 1-64 bytes. - switch_inline_query (:obj:`str`): Optional. Will prompt the user to select one of their - chats, open that chat and insert the bot's username and the specified inline query in - the input field. Can be empty, in which case just the bot’s username will be inserted. - switch_inline_query_current_chat (:obj:`str`): Optional. Will insert the bot's username and - the specified inline query in the current chat's input field. Can be empty, in which - case just the bot’s username will be inserted. - callback_game (:class:`telegram.CallbackGame`): Optional. Description of the game that will - be launched when the user presses the button. - pay (:obj:`bool`): Optional. Specify :obj:`True`, to send a Pay button. - - """ - - __slots__ = ( - 'callback_game', - 'url', - 'switch_inline_query_current_chat', - 'callback_data', - 'pay', - 'switch_inline_query', - 'text', - '_id_attrs', - 'login_url', - ) - - def __init__( - self, - text: str, - url: str = None, - callback_data: object = None, - switch_inline_query: str = None, - switch_inline_query_current_chat: str = None, - callback_game: 'CallbackGame' = None, - pay: bool = None, - login_url: 'LoginUrl' = None, - **_kwargs: Any, - ): - # Required - self.text = text - - # Optionals - self.url = url - self.login_url = login_url - self.callback_data = callback_data - self.switch_inline_query = switch_inline_query - self.switch_inline_query_current_chat = switch_inline_query_current_chat - self.callback_game = callback_game - self.pay = pay - self._id_attrs = () - self._set_id_attrs() - - def _set_id_attrs(self) -> None: - self._id_attrs = ( - self.text, - self.url, - self.login_url, - self.callback_data, - self.switch_inline_query, - self.switch_inline_query_current_chat, - self.callback_game, - self.pay, - ) - - def update_callback_data(self, callback_data: object) -> None: - """ - Sets :attr:`callback_data` to the passed object. Intended to be used by - :class:`telegram.ext.CallbackDataCache`. - - .. versionadded:: 13.6 - - Args: - callback_data (:obj:`obj`): The new callback data. - """ - self.callback_data = callback_data - self._set_id_attrs() diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinekeyboardmarkup.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinekeyboardmarkup.py deleted file mode 100644 index a917d96..0000000 --- a/venv/lib/python3.8/site-packages/telegram/inline/inlinekeyboardmarkup.py +++ /dev/null @@ -1,138 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram InlineKeyboardMarkup.""" - -from typing import TYPE_CHECKING, Any, List, Optional - -from telegram import InlineKeyboardButton, ReplyMarkup -from telegram.utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - - -class InlineKeyboardMarkup(ReplyMarkup): - """ - This object represents an inline keyboard that appears right next to the message it belongs to. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their the size of :attr:`inline_keyboard` and all the buttons are equal. - - Args: - inline_keyboard (List[List[:class:`telegram.InlineKeyboardButton`]]): List of button rows, - each represented by a list of InlineKeyboardButton objects. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - inline_keyboard (List[List[:class:`telegram.InlineKeyboardButton`]]): List of button rows, - each represented by a list of InlineKeyboardButton objects. - - """ - - __slots__ = ('inline_keyboard', '_id_attrs') - - def __init__(self, inline_keyboard: List[List[InlineKeyboardButton]], **_kwargs: Any): - # Required - self.inline_keyboard = inline_keyboard - - self._id_attrs = (self.inline_keyboard,) - - def to_dict(self) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict() - - data['inline_keyboard'] = [] - for inline_keyboard in self.inline_keyboard: - data['inline_keyboard'].append([x.to_dict() for x in inline_keyboard]) - - return data - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['InlineKeyboardMarkup']: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - keyboard = [] - for row in data['inline_keyboard']: - tmp = [] - for col in row: - btn = InlineKeyboardButton.de_json(col, bot) - if btn: - tmp.append(btn) - keyboard.append(tmp) - - return cls(keyboard) - - @classmethod - def from_button(cls, button: InlineKeyboardButton, **kwargs: object) -> 'InlineKeyboardMarkup': - """Shortcut for:: - - InlineKeyboardMarkup([[button]], **kwargs) - - Return an InlineKeyboardMarkup from a single InlineKeyboardButton - - Args: - button (:class:`telegram.InlineKeyboardButton`): The button to use in the markup - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - """ - return cls([[button]], **kwargs) - - @classmethod - def from_row( - cls, button_row: List[InlineKeyboardButton], **kwargs: object - ) -> 'InlineKeyboardMarkup': - """Shortcut for:: - - InlineKeyboardMarkup([button_row], **kwargs) - - Return an InlineKeyboardMarkup from a single row of InlineKeyboardButtons - - Args: - button_row (List[:class:`telegram.InlineKeyboardButton`]): The button to use in the - markup - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - """ - return cls([button_row], **kwargs) - - @classmethod - def from_column( - cls, button_column: List[InlineKeyboardButton], **kwargs: object - ) -> 'InlineKeyboardMarkup': - """Shortcut for:: - - InlineKeyboardMarkup([[button] for button in button_column], **kwargs) - - Return an InlineKeyboardMarkup from a single column of InlineKeyboardButtons - - Args: - button_column (List[:class:`telegram.InlineKeyboardButton`]): The button to use in the - markup - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - """ - button_grid = [[button] for button in button_column] - return cls(button_grid, **kwargs) - - def __hash__(self) -> int: - return hash(tuple(tuple(button for button in row) for row in self.inline_keyboard)) diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequery.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequery.py deleted file mode 100644 index 412188d..0000000 --- a/venv/lib/python3.8/site-packages/telegram/inline/inlinequery.py +++ /dev/null @@ -1,168 +0,0 @@ -#!/usr/bin/env python -# pylint: disable=R0902,R0913 -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram InlineQuery.""" - -from typing import TYPE_CHECKING, Any, Optional, Union, Callable, ClassVar, Sequence - -from telegram import Location, TelegramObject, User, constants -from telegram.utils.helpers import DEFAULT_NONE -from telegram.utils.types import JSONDict, ODVInput - -if TYPE_CHECKING: - from telegram import Bot, InlineQueryResult - - -class InlineQuery(TelegramObject): - """ - This object represents an incoming inline query. When the user sends an empty query, your bot - could return some default or trending results. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`id` is equal. - - Note: - In Python ``from`` is a reserved word, use ``from_user`` instead. - - Args: - id (:obj:`str`): Unique identifier for this query. - from_user (:class:`telegram.User`): Sender. - query (:obj:`str`): Text of the query (up to 256 characters). - offset (:obj:`str`): Offset of the results to be returned, can be controlled by the bot. - chat_type (:obj:`str`, optional): Type of the chat, from which the inline query was sent. - Can be either :attr:`telegram.Chat.SENDER` for a private chat with the inline query - sender, :attr:`telegram.Chat.PRIVATE`, :attr:`telegram.Chat.GROUP`, - :attr:`telegram.Chat.SUPERGROUP` or :attr:`telegram.Chat.CHANNEL`. The chat type should - be always known for requests sent from official clients and most third-party clients, - unless the request was sent from a secret chat. - - .. versionadded:: 13.5 - location (:class:`telegram.Location`, optional): Sender location, only for bots that - request user location. - bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - id (:obj:`str`): Unique identifier for this query. - from_user (:class:`telegram.User`): Sender. - query (:obj:`str`): Text of the query (up to 256 characters). - offset (:obj:`str`): Offset of the results to be returned, can be controlled by the bot. - location (:class:`telegram.Location`): Optional. Sender location, only for bots that - request user location. - chat_type (:obj:`str`, optional): Type of the chat, from which the inline query was sent. - - .. versionadded:: 13.5 - - """ - - __slots__ = ('bot', 'location', 'chat_type', 'id', 'offset', 'from_user', 'query', '_id_attrs') - - def __init__( - self, - id: str, # pylint: disable=W0622 - from_user: User, - query: str, - offset: str, - location: Location = None, - bot: 'Bot' = None, - chat_type: str = None, - **_kwargs: Any, - ): - # Required - self.id = id # pylint: disable=C0103 - self.from_user = from_user - self.query = query - self.offset = offset - - # Optional - self.location = location - self.chat_type = chat_type - - self.bot = bot - self._id_attrs = (self.id,) - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['InlineQuery']: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data['from_user'] = User.de_json(data.get('from'), bot) - data['location'] = Location.de_json(data.get('location'), bot) - - return cls(bot=bot, **data) - - def answer( - self, - results: Union[ - Sequence['InlineQueryResult'], Callable[[int], Optional[Sequence['InlineQueryResult']]] - ], - cache_time: int = 300, - is_personal: bool = None, - next_offset: str = None, - switch_pm_text: str = None, - switch_pm_parameter: str = None, - timeout: ODVInput[float] = DEFAULT_NONE, - current_offset: str = None, - api_kwargs: JSONDict = None, - auto_pagination: bool = False, - ) -> bool: - """Shortcut for:: - - bot.answer_inline_query(update.inline_query.id, - *args, - current_offset=self.offset if auto_pagination else None, - **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.answer_inline_query`. - - Args: - auto_pagination (:obj:`bool`, optional): If set to :obj:`True`, :attr:`offset` will be - passed as :attr:`current_offset` to :meth:`telegram.Bot.answer_inline_query`. - Defaults to :obj:`False`. - - Raises: - TypeError: If both :attr:`current_offset` and :attr:`auto_pagination` are supplied. - """ - if current_offset and auto_pagination: - # We raise TypeError instead of ValueError for backwards compatibility with versions - # which didn't check this here but let Python do the checking - raise TypeError('current_offset and auto_pagination are mutually exclusive!') - return self.bot.answer_inline_query( - inline_query_id=self.id, - current_offset=self.offset if auto_pagination else current_offset, - results=results, - cache_time=cache_time, - is_personal=is_personal, - next_offset=next_offset, - switch_pm_text=switch_pm_text, - switch_pm_parameter=switch_pm_parameter, - timeout=timeout, - api_kwargs=api_kwargs, - ) - - MAX_RESULTS: ClassVar[int] = constants.MAX_INLINE_QUERY_RESULTS - """ - :const:`telegram.constants.MAX_INLINE_QUERY_RESULTS` - - .. versionadded:: 13.2 - """ diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresult.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresult.py deleted file mode 100644 index 756e2fb..0000000 --- a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresult.py +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -# pylint: disable=W0622 -"""This module contains the classes that represent Telegram InlineQueryResult.""" - -from typing import Any - -from telegram import TelegramObject -from telegram.utils.types import JSONDict - - -class InlineQueryResult(TelegramObject): - """Baseclass for the InlineQueryResult* classes. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`id` is equal. - - Note: - All URLs passed in inline query results will be available to end users and therefore must - be assumed to be *public*. - - Args: - type (:obj:`str`): Type of the result. - id (:obj:`str`): Unique identifier for this result, 1-64 Bytes. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - type (:obj:`str`): Type of the result. - id (:obj:`str`): Unique identifier for this result, 1-64 Bytes. - - """ - - __slots__ = ('type', 'id', '_id_attrs') - - def __init__(self, type: str, id: str, **_kwargs: Any): - # Required - self.type = str(type) - self.id = str(id) # pylint: disable=C0103 - - self._id_attrs = (self.id,) - - def to_dict(self) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict() - - # pylint: disable=E1101 - if ( - hasattr(self, 'caption_entities') - and self.caption_entities # type: ignore[attr-defined] - ): - data['caption_entities'] = [ - ce.to_dict() for ce in self.caption_entities # type: ignore[attr-defined] - ] - - return data diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultarticle.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultarticle.py deleted file mode 100644 index 3827ae3..0000000 --- a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultarticle.py +++ /dev/null @@ -1,105 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the classes that represent Telegram InlineQueryResultArticle.""" - -from typing import TYPE_CHECKING, Any - -from telegram import InlineQueryResult - -if TYPE_CHECKING: - from telegram import InputMessageContent, ReplyMarkup - - -class InlineQueryResultArticle(InlineQueryResult): - """This object represents a Telegram InlineQueryResultArticle. - - Args: - id (:obj:`str`): Unique identifier for this result, 1-64 Bytes. - title (:obj:`str`): Title of the result. - input_message_content (:class:`telegram.InputMessageContent`): Content of the message to - be sent. - reply_markup (:class:`telegram.ReplyMarkup`, optional): Inline keyboard attached to - the message - url (:obj:`str`, optional): URL of the result. - hide_url (:obj:`bool`, optional): Pass :obj:`True`, if you don't want the URL to be shown - in the message. - description (:obj:`str`, optional): Short description of the result. - thumb_url (:obj:`str`, optional): Url of the thumbnail for the result. - thumb_width (:obj:`int`, optional): Thumbnail width. - thumb_height (:obj:`int`, optional): Thumbnail height. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - type (:obj:`str`): 'article'. - id (:obj:`str`): Unique identifier for this result, 1-64 Bytes. - title (:obj:`str`): Title of the result. - input_message_content (:class:`telegram.InputMessageContent`): Content of the message to - be sent. - reply_markup (:class:`telegram.ReplyMarkup`): Optional. Inline keyboard attached to - the message. - url (:obj:`str`): Optional. URL of the result. - hide_url (:obj:`bool`): Optional. Pass :obj:`True`, if you don't want the URL to be shown - in the message. - description (:obj:`str`): Optional. Short description of the result. - thumb_url (:obj:`str`): Optional. Url of the thumbnail for the result. - thumb_width (:obj:`int`): Optional. Thumbnail width. - thumb_height (:obj:`int`): Optional. Thumbnail height. - - """ - - __slots__ = ( - 'reply_markup', - 'thumb_width', - 'thumb_height', - 'hide_url', - 'url', - 'title', - 'description', - 'input_message_content', - 'thumb_url', - ) - - def __init__( - self, - id: str, # pylint: disable=W0622 - title: str, - input_message_content: 'InputMessageContent', - reply_markup: 'ReplyMarkup' = None, - url: str = None, - hide_url: bool = None, - description: str = None, - thumb_url: str = None, - thumb_width: int = None, - thumb_height: int = None, - **_kwargs: Any, - ): - - # Required - super().__init__('article', id) - self.title = title - self.input_message_content = input_message_content - - # Optional - self.reply_markup = reply_markup - self.url = url - self.hide_url = hide_url - self.description = description - self.thumb_url = thumb_url - self.thumb_width = thumb_width - self.thumb_height = thumb_height diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultaudio.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultaudio.py deleted file mode 100644 index 93eaa16..0000000 --- a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultaudio.py +++ /dev/null @@ -1,116 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the classes that represent Telegram InlineQueryResultAudio.""" - -from typing import TYPE_CHECKING, Any, Union, Tuple, List - -from telegram import InlineQueryResult, MessageEntity -from telegram.utils.helpers import DEFAULT_NONE -from telegram.utils.types import ODVInput - -if TYPE_CHECKING: - from telegram import InputMessageContent, ReplyMarkup - - -class InlineQueryResultAudio(InlineQueryResult): - """ - Represents a link to an mp3 audio file. By default, this audio file will be sent by the user. - Alternatively, you can use :attr:`input_message_content` to send a message with the specified - content instead of the audio. - - Args: - id (:obj:`str`): Unique identifier for this result, 1-64 bytes. - audio_url (:obj:`str`): A valid URL for the audio file. - title (:obj:`str`): Title. - performer (:obj:`str`, optional): Performer. - audio_duration (:obj:`str`, optional): Audio duration in seconds. - caption (:obj:`str`, optional): Caption, 0-1024 characters after entities parsing. - parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show - bold, italic, fixed-width text or inline URLs in the media caption. See the constants - in :class:`telegram.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special - entities that appear in the caption, which can be specified instead of - :attr:`parse_mode`. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the - message to be sent instead of the audio. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - type (:obj:`str`): 'audio'. - id (:obj:`str`): Unique identifier for this result, 1-64 bytes. - audio_url (:obj:`str`): A valid URL for the audio file. - title (:obj:`str`): Title. - performer (:obj:`str`): Optional. Performer. - audio_duration (:obj:`str`): Optional. Audio duration in seconds. - caption (:obj:`str`): Optional. Caption, 0-1024 characters after entities parsing. - parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show - bold, italic, fixed-width text or inline URLs in the media caption. See the constants - in :class:`telegram.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special - entities that appear in the caption, which can be specified instead of - :attr:`parse_mode`. - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the - message to be sent instead of the audio. - - """ - - __slots__ = ( - 'reply_markup', - 'caption_entities', - 'caption', - 'title', - 'parse_mode', - 'audio_url', - 'performer', - 'input_message_content', - 'audio_duration', - ) - - def __init__( - self, - id: str, # pylint: disable=W0622 - audio_url: str, - title: str, - performer: str = None, - audio_duration: int = None, - caption: str = None, - reply_markup: 'ReplyMarkup' = None, - input_message_content: 'InputMessageContent' = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, - **_kwargs: Any, - ): - - # Required - super().__init__('audio', id) - self.audio_url = audio_url - self.title = title - - # Optionals - self.performer = performer - self.audio_duration = audio_duration - self.caption = caption - self.parse_mode = parse_mode - self.caption_entities = caption_entities - self.reply_markup = reply_markup - self.input_message_content = input_message_content diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedaudio.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedaudio.py deleted file mode 100644 index 41222bb..0000000 --- a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedaudio.py +++ /dev/null @@ -1,100 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the classes that represent Telegram InlineQueryResultCachedAudio.""" - -from typing import TYPE_CHECKING, Any, Union, Tuple, List - -from telegram import InlineQueryResult, MessageEntity -from telegram.utils.helpers import DEFAULT_NONE -from telegram.utils.types import ODVInput - -if TYPE_CHECKING: - from telegram import InputMessageContent, ReplyMarkup - - -class InlineQueryResultCachedAudio(InlineQueryResult): - """ - Represents a link to an mp3 audio file stored on the Telegram servers. By default, this audio - file will be sent by the user. Alternatively, you can use :attr:`input_message_content` to - send a message with the specified content instead of the audio. - - Args: - id (:obj:`str`): Unique identifier for this result, 1-64 bytes. - audio_file_id (:obj:`str`): A valid file identifier for the audio file. - caption (:obj:`str`, optional): Caption, 0-1024 characters after entities parsing. - parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show - bold, italic, fixed-width text or inline URLs in the media caption. See the constants - in :class:`telegram.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special - entities that appear in the caption, which can be specified instead of - :attr:`parse_mode`. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the - message to be sent instead of the audio. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - type (:obj:`str`): 'audio'. - id (:obj:`str`): Unique identifier for this result, 1-64 bytes. - audio_file_id (:obj:`str`): A valid file identifier for the audio file. - caption (:obj:`str`): Optional. Caption, 0-1024 characters after entities parsing. - parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show - bold, italic, fixed-width text or inline URLs in the media caption. See the constants - in :class:`telegram.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special - entities that appear in the caption, which can be specified instead of - :attr:`parse_mode`. - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the - message to be sent instead of the audio. - - """ - - __slots__ = ( - 'reply_markup', - 'caption_entities', - 'caption', - 'parse_mode', - 'audio_file_id', - 'input_message_content', - ) - - def __init__( - self, - id: str, # pylint: disable=W0622 - audio_file_id: str, - caption: str = None, - reply_markup: 'ReplyMarkup' = None, - input_message_content: 'InputMessageContent' = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, - **_kwargs: Any, - ): - # Required - super().__init__('audio', id) - self.audio_file_id = audio_file_id - - # Optionals - self.caption = caption - self.parse_mode = parse_mode - self.caption_entities = caption_entities - self.reply_markup = reply_markup - self.input_message_content = input_message_content diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcacheddocument.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcacheddocument.py deleted file mode 100644 index 784ccaf..0000000 --- a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcacheddocument.py +++ /dev/null @@ -1,113 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -# pylint: disable=W0622 -"""This module contains the classes that represent Telegram InlineQueryResultCachedDocument.""" - -from typing import TYPE_CHECKING, Any, Union, Tuple, List - -from telegram import InlineQueryResult, MessageEntity -from telegram.utils.helpers import DEFAULT_NONE -from telegram.utils.types import ODVInput - -if TYPE_CHECKING: - from telegram import InputMessageContent, ReplyMarkup - - -class InlineQueryResultCachedDocument(InlineQueryResult): - """ - Represents a link to a file stored on the Telegram servers. By default, this file will be sent - by the user with an optional caption. Alternatively, you can use :attr:`input_message_content` - to send a message with the specified content instead of the file. - - Args: - id (:obj:`str`): Unique identifier for this result, 1-64 bytes. - title (:obj:`str`): Title for the result. - document_file_id (:obj:`str`): A valid file identifier for the file. - description (:obj:`str`, optional): Short description of the result. - caption (:obj:`str`, optional): Caption of the document to be sent, 0-1024 characters - after entities parsing. - parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show - bold, italic, fixed-width text or inline URLs in the media caption.. See the constants - in :class:`telegram.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special - entities that appear in the caption, which can be specified instead of - :attr:`parse_mode`. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the - message to be sent instead of the file. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - type (:obj:`str`): 'document'. - id (:obj:`str`): Unique identifier for this result, 1-64 bytes. - title (:obj:`str`): Title for the result. - document_file_id (:obj:`str`): A valid file identifier for the file. - description (:obj:`str`): Optional. Short description of the result. - caption (:obj:`str`): Optional. Caption of the document to be sent, 0-1024 characters - after entities parsing. - parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show - bold, italic, fixed-width text or inline URLs in the media caption.. See the constants - in :class:`telegram.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special - entities that appear in the caption, which can be specified instead of - :attr:`parse_mode`. - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the - message to be sent instead of the file. - - """ - - __slots__ = ( - 'reply_markup', - 'caption_entities', - 'document_file_id', - 'caption', - 'title', - 'description', - 'parse_mode', - 'input_message_content', - ) - - def __init__( - self, - id: str, # pylint: disable=W0622 - title: str, - document_file_id: str, - description: str = None, - caption: str = None, - reply_markup: 'ReplyMarkup' = None, - input_message_content: 'InputMessageContent' = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, - **_kwargs: Any, - ): - # Required - super().__init__('document', id) - self.title = title - self.document_file_id = document_file_id - - # Optionals - self.description = description - self.caption = caption - self.parse_mode = parse_mode - self.caption_entities = caption_entities - self.reply_markup = reply_markup - self.input_message_content = input_message_content diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedgif.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedgif.py deleted file mode 100644 index ca2fc42..0000000 --- a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedgif.py +++ /dev/null @@ -1,108 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the classes that represent Telegram InlineQueryResultCachedGif.""" - -from typing import TYPE_CHECKING, Any, Union, Tuple, List - -from telegram import InlineQueryResult, MessageEntity -from telegram.utils.helpers import DEFAULT_NONE -from telegram.utils.types import ODVInput - -if TYPE_CHECKING: - from telegram import InputMessageContent, ReplyMarkup - - -class InlineQueryResultCachedGif(InlineQueryResult): - """ - Represents a link to an animated GIF file stored on the Telegram servers. By default, this - animated GIF file will be sent by the user with an optional caption. Alternatively, you can - use :attr:`input_message_content` to send a message with specified content instead of - the animation. - - Args: - id (:obj:`str`): Unique identifier for this result, 1-64 bytes. - gif_file_id (:obj:`str`): A valid file identifier for the GIF file. - title (:obj:`str`, optional): Title for the result.caption (:obj:`str`, optional): - caption (:obj:`str`, optional): Caption of the GIF file to be sent, 0-1024 characters - after entities parsing. - parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show - bold, italic, fixed-width text or inline URLs in the media caption. See the constants - in :class:`telegram.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special - entities that appear in the caption, which can be specified instead of - :attr:`parse_mode`. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the - message to be sent instead of the gif. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - type (:obj:`str`): 'gif'. - id (:obj:`str`): Unique identifier for this result, 1-64 bytes. - gif_file_id (:obj:`str`): A valid file identifier for the GIF file. - title (:obj:`str`): Optional. Title for the result. - caption (:obj:`str`): Optional. Caption of the GIF file to be sent, 0-1024 characters - after entities parsing. - parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show - bold, italic, fixed-width text or inline URLs in the media caption. See the constants - in :class:`telegram.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special - entities that appear in the caption, which can be specified instead of - :attr:`parse_mode`. - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the - message to be sent instead of the gif. - - """ - - __slots__ = ( - 'reply_markup', - 'caption_entities', - 'caption', - 'title', - 'input_message_content', - 'parse_mode', - 'gif_file_id', - ) - - def __init__( - self, - id: str, # pylint: disable=W0622 - gif_file_id: str, - title: str = None, - caption: str = None, - reply_markup: 'ReplyMarkup' = None, - input_message_content: 'InputMessageContent' = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, - **_kwargs: Any, - ): - # Required - super().__init__('gif', id) - self.gif_file_id = gif_file_id - - # Optionals - self.title = title - self.caption = caption - self.parse_mode = parse_mode - self.caption_entities = caption_entities - self.reply_markup = reply_markup - self.input_message_content = input_message_content diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedmpeg4gif.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedmpeg4gif.py deleted file mode 100644 index 4f0f85c..0000000 --- a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedmpeg4gif.py +++ /dev/null @@ -1,108 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the classes that represent Telegram InlineQueryResultMpeg4Gif.""" - -from typing import TYPE_CHECKING, Any, Union, Tuple, List - -from telegram import InlineQueryResult, MessageEntity -from telegram.utils.helpers import DEFAULT_NONE -from telegram.utils.types import ODVInput - -if TYPE_CHECKING: - from telegram import InputMessageContent, ReplyMarkup - - -class InlineQueryResultCachedMpeg4Gif(InlineQueryResult): - """ - Represents a link to a video animation (H.264/MPEG-4 AVC video without sound) stored on the - Telegram servers. By default, this animated MPEG-4 file will be sent by the user with an - optional caption. Alternatively, you can use :attr:`input_message_content` to send a message - with the specified content instead of the animation. - - Args: - id (:obj:`str`): Unique identifier for this result, 1-64 bytes. - mpeg4_file_id (:obj:`str`): A valid file identifier for the MP4 file. - title (:obj:`str`, optional): Title for the result. - caption (:obj:`str`, optional): Caption of the MPEG-4 file to be sent, 0-1024 characters - after entities parsing. - parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show - bold, italic, fixed-width text or inline URLs in the media caption. See the constants - in :class:`telegram.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special - entities that appear in the caption, which can be specified instead of - :attr:`parse_mode`. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the - message to be sent instead of the MPEG-4 file. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - type (:obj:`str`): 'mpeg4_gif'. - id (:obj:`str`): Unique identifier for this result, 1-64 bytes. - mpeg4_file_id (:obj:`str`): A valid file identifier for the MP4 file. - title (:obj:`str`): Optional. Title for the result. - caption (:obj:`str`): Optional. Caption of the MPEG-4 file to be sent, 0-1024 characters - after entities parsing. - parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show - bold, italic, fixed-width text or inline URLs in the media caption. See the constants - in :class:`telegram.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special - entities that appear in the caption, which can be specified instead of - :attr:`parse_mode`. - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the - message to be sent instead of the MPEG-4 file. - - """ - - __slots__ = ( - 'reply_markup', - 'caption_entities', - 'mpeg4_file_id', - 'caption', - 'title', - 'parse_mode', - 'input_message_content', - ) - - def __init__( - self, - id: str, # pylint: disable=W0622 - mpeg4_file_id: str, - title: str = None, - caption: str = None, - reply_markup: 'ReplyMarkup' = None, - input_message_content: 'InputMessageContent' = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, - **_kwargs: Any, - ): - # Required - super().__init__('mpeg4_gif', id) - self.mpeg4_file_id = mpeg4_file_id - - # Optionals - self.title = title - self.caption = caption - self.parse_mode = parse_mode - self.caption_entities = caption_entities - self.reply_markup = reply_markup - self.input_message_content = input_message_content diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedphoto.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedphoto.py deleted file mode 100644 index 4a929dd..0000000 --- a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedphoto.py +++ /dev/null @@ -1,114 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -# pylint: disable=W0622 -"""This module contains the classes that represent Telegram InlineQueryResultPhoto""" - -from typing import TYPE_CHECKING, Any, Union, Tuple, List - -from telegram import InlineQueryResult, MessageEntity -from telegram.utils.helpers import DEFAULT_NONE -from telegram.utils.types import ODVInput - -if TYPE_CHECKING: - from telegram import InputMessageContent, ReplyMarkup - - -class InlineQueryResultCachedPhoto(InlineQueryResult): - """ - Represents a link to a photo stored on the Telegram servers. By default, this photo will be - sent by the user with an optional caption. Alternatively, you can use - :attr:`input_message_content` to send a message with the specified content instead - of the photo. - - Args: - id (:obj:`str`): Unique identifier for this result, 1-64 bytes. - photo_file_id (:obj:`str`): A valid file identifier of the photo. - title (:obj:`str`, optional): Title for the result. - description (:obj:`str`, optional): Short description of the result. - caption (:obj:`str`, optional): Caption of the photo to be sent, 0-1024 characters after - entities parsing. - parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show - bold, italic, fixed-width text or inline URLs in the media caption. See the constants - in :class:`telegram.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special - entities that appear in the caption, which can be specified instead of - :attr:`parse_mode`. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the - message to be sent instead of the photo. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - type (:obj:`str`): 'photo'. - id (:obj:`str`): Unique identifier for this result, 1-64 bytes. - photo_file_id (:obj:`str`): A valid file identifier of the photo. - title (:obj:`str`): Optional. Title for the result. - description (:obj:`str`): Optional. Short description of the result. - caption (:obj:`str`): Optional. Caption of the photo to be sent, 0-1024 characters after - entities parsing. - parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show - bold, italic, fixed-width text or inline URLs in the media caption. See the constants - in :class:`telegram.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special - entities that appear in the caption, which can be specified instead of - :attr:`parse_mode`. - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the - message to be sent instead of the photo. - - """ - - __slots__ = ( - 'reply_markup', - 'caption_entities', - 'caption', - 'title', - 'description', - 'parse_mode', - 'photo_file_id', - 'input_message_content', - ) - - def __init__( - self, - id: str, # pylint: disable=W0622 - photo_file_id: str, - title: str = None, - description: str = None, - caption: str = None, - reply_markup: 'ReplyMarkup' = None, - input_message_content: 'InputMessageContent' = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, - **_kwargs: Any, - ): - # Required - super().__init__('photo', id) - self.photo_file_id = photo_file_id - - # Optionals - self.title = title - self.description = description - self.caption = caption - self.parse_mode = parse_mode - self.caption_entities = caption_entities - self.reply_markup = reply_markup - self.input_message_content = input_message_content diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedsticker.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedsticker.py deleted file mode 100644 index f369bdd..0000000 --- a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedsticker.py +++ /dev/null @@ -1,71 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the classes that represent Telegram InlineQueryResultCachedSticker.""" - -from typing import TYPE_CHECKING, Any - -from telegram import InlineQueryResult - -if TYPE_CHECKING: - from telegram import InputMessageContent, ReplyMarkup - - -class InlineQueryResultCachedSticker(InlineQueryResult): - """ - Represents a link to a sticker stored on the Telegram servers. By default, this sticker will - be sent by the user. Alternatively, you can use :attr:`input_message_content` to send a - message with the specified content instead of the sticker. - - Args: - id (:obj:`str`): Unique identifier for this result, 1-64 bytes. - sticker_file_id (:obj:`str`): A valid file identifier of the sticker. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the - message to be sent instead of the sticker. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - type (:obj:`str`): 'sticker`. - id (:obj:`str`): Unique identifier for this result, 1-64 bytes. - sticker_file_id (:obj:`str`): A valid file identifier of the sticker. - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the - message to be sent instead of the sticker. - - """ - - __slots__ = ('reply_markup', 'input_message_content', 'sticker_file_id') - - def __init__( - self, - id: str, # pylint: disable=W0622 - sticker_file_id: str, - reply_markup: 'ReplyMarkup' = None, - input_message_content: 'InputMessageContent' = None, - **_kwargs: Any, - ): - # Required - super().__init__('sticker', id) - self.sticker_file_id = sticker_file_id - - # Optionals - self.reply_markup = reply_markup - self.input_message_content = input_message_content diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedvideo.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedvideo.py deleted file mode 100644 index ee91515..0000000 --- a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedvideo.py +++ /dev/null @@ -1,113 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the classes that represent Telegram InlineQueryResultCachedVideo.""" - -from typing import TYPE_CHECKING, Any, Union, Tuple, List - -from telegram import InlineQueryResult, MessageEntity -from telegram.utils.helpers import DEFAULT_NONE -from telegram.utils.types import ODVInput - -if TYPE_CHECKING: - from telegram import InputMessageContent, ReplyMarkup - - -class InlineQueryResultCachedVideo(InlineQueryResult): - """ - Represents a link to a video file stored on the Telegram servers. By default, this video file - will be sent by the user with an optional caption. Alternatively, you can use - :attr:`input_message_content` to send a message with the specified content instead - of the video. - - Args: - id (:obj:`str`): Unique identifier for this result, 1-64 bytes. - video_file_id (:obj:`str`): A valid file identifier for the video file. - title (:obj:`str`): Title for the result. - description (:obj:`str`, optional): Short description of the result. - caption (:obj:`str`, optional): Caption of the video to be sent, 0-1024 characters after - entities parsing. - parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show - bold, italic, fixed-width text or inline URLs in the media caption. See the constants - in :class:`telegram.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special - entities that appear in the caption, which can be specified instead of - :attr:`parse_mode`. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the - message to be sent instead of the video. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - type (:obj:`str`): 'video'. - id (:obj:`str`): Unique identifier for this result, 1-64 bytes. - video_file_id (:obj:`str`): A valid file identifier for the video file. - title (:obj:`str`): Title for the result. - description (:obj:`str`): Optional. Short description of the result. - caption (:obj:`str`): Optional. Caption of the video to be sent, 0-1024 characters after - entities parsing. - parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show - bold, italic, fixed-width text or inline URLs in the media caption. See the constants - in :class:`telegram.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special - entities that appear in the caption, which can be specified instead of - :attr:`parse_mode`. - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the - message to be sent instead of the video. - - """ - - __slots__ = ( - 'reply_markup', - 'caption_entities', - 'caption', - 'title', - 'description', - 'parse_mode', - 'input_message_content', - 'video_file_id', - ) - - def __init__( - self, - id: str, # pylint: disable=W0622 - video_file_id: str, - title: str, - description: str = None, - caption: str = None, - reply_markup: 'ReplyMarkup' = None, - input_message_content: 'InputMessageContent' = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, - **_kwargs: Any, - ): - # Required - super().__init__('video', id) - self.video_file_id = video_file_id - self.title = title - - # Optionals - self.description = description - self.caption = caption - self.parse_mode = parse_mode - self.caption_entities = caption_entities - self.reply_markup = reply_markup - self.input_message_content = input_message_content diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedvoice.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedvoice.py deleted file mode 100644 index ff2ef22..0000000 --- a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcachedvoice.py +++ /dev/null @@ -1,105 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the classes that represent Telegram InlineQueryResultCachedVoice.""" - -from typing import TYPE_CHECKING, Any, Union, Tuple, List - -from telegram import InlineQueryResult, MessageEntity -from telegram.utils.helpers import DEFAULT_NONE -from telegram.utils.types import ODVInput - -if TYPE_CHECKING: - from telegram import InputMessageContent, ReplyMarkup - - -class InlineQueryResultCachedVoice(InlineQueryResult): - """ - Represents a link to a voice message stored on the Telegram servers. By default, this voice - message will be sent by the user. Alternatively, you can use :attr:`input_message_content` to - send a message with the specified content instead of the voice message. - - Args: - id (:obj:`str`): Unique identifier for this result, 1-64 bytes. - voice_file_id (:obj:`str`): A valid file identifier for the voice message. - title (:obj:`str`): Voice message title. - caption (:obj:`str`, optional): Caption, 0-1024 characters after entities parsing. - parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show - bold, italic, fixed-width text or inline URLs in the media caption. See the constants - in :class:`telegram.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special - entities that appear in the caption, which can be specified instead of - :attr:`parse_mode`. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the - message to be sent instead of the voice message. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - type (:obj:`str`): 'voice'. - id (:obj:`str`): Unique identifier for this result, 1-64 bytes. - voice_file_id (:obj:`str`): A valid file identifier for the voice message. - title (:obj:`str`): Voice message title. - caption (:obj:`str`): Optional. Caption, 0-1024 characters after entities parsing. - parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show - bold, italic, fixed-width text or inline URLs in the media caption. See the constants - in :class:`telegram.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special - entities that appear in the caption, which can be specified instead of - :attr:`parse_mode`. - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the - message to be sent instead of the voice message. - - """ - - __slots__ = ( - 'reply_markup', - 'caption_entities', - 'caption', - 'title', - 'parse_mode', - 'voice_file_id', - 'input_message_content', - ) - - def __init__( - self, - id: str, # pylint: disable=W0622 - voice_file_id: str, - title: str, - caption: str = None, - reply_markup: 'ReplyMarkup' = None, - input_message_content: 'InputMessageContent' = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, - **_kwargs: Any, - ): - # Required - super().__init__('voice', id) - self.voice_file_id = voice_file_id - self.title = title - - # Optionals - self.caption = caption - self.parse_mode = parse_mode - self.caption_entities = caption_entities - self.reply_markup = reply_markup - self.input_message_content = input_message_content diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcontact.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcontact.py deleted file mode 100644 index 42dd75d..0000000 --- a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultcontact.py +++ /dev/null @@ -1,107 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the classes that represent Telegram InlineQueryResultContact.""" - -from typing import TYPE_CHECKING, Any - -from telegram import InlineQueryResult - -if TYPE_CHECKING: - from telegram import InputMessageContent, ReplyMarkup - - -class InlineQueryResultContact(InlineQueryResult): - """ - Represents a contact with a phone number. By default, this contact will be sent by the user. - Alternatively, you can use :attr:`input_message_content` to send a message with the specified - content instead of the contact. - - Args: - id (:obj:`str`): Unique identifier for this result, 1-64 bytes. - phone_number (:obj:`str`): Contact's phone number. - first_name (:obj:`str`): Contact's first name. - last_name (:obj:`str`, optional): Contact's last name. - vcard (:obj:`str`, optional): Additional data about the contact in the form of a vCard, - 0-2048 bytes. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the - message to be sent instead of the contact. - thumb_url (:obj:`str`, optional): Url of the thumbnail for the result. - thumb_width (:obj:`int`, optional): Thumbnail width. - thumb_height (:obj:`int`, optional): Thumbnail height. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - type (:obj:`str`): 'contact'. - id (:obj:`str`): Unique identifier for this result, 1-64 bytes. - phone_number (:obj:`str`): Contact's phone number. - first_name (:obj:`str`): Contact's first name. - last_name (:obj:`str`): Optional. Contact's last name. - vcard (:obj:`str`): Optional. Additional data about the contact in the form of a vCard, - 0-2048 bytes. - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the - message to be sent instead of the contact. - thumb_url (:obj:`str`): Optional. Url of the thumbnail for the result. - thumb_width (:obj:`int`): Optional. Thumbnail width. - thumb_height (:obj:`int`): Optional. Thumbnail height. - - """ - - __slots__ = ( - 'reply_markup', - 'thumb_width', - 'thumb_height', - 'vcard', - 'first_name', - 'last_name', - 'phone_number', - 'input_message_content', - 'thumb_url', - ) - - def __init__( - self, - id: str, # pylint: disable=W0622 - phone_number: str, - first_name: str, - last_name: str = None, - reply_markup: 'ReplyMarkup' = None, - input_message_content: 'InputMessageContent' = None, - thumb_url: str = None, - thumb_width: int = None, - thumb_height: int = None, - vcard: str = None, - **_kwargs: Any, - ): - # Required - super().__init__('contact', id) - self.phone_number = phone_number - self.first_name = first_name - - # Optionals - self.last_name = last_name - self.vcard = vcard - self.reply_markup = reply_markup - self.input_message_content = input_message_content - self.thumb_url = thumb_url - self.thumb_width = thumb_width - self.thumb_height = thumb_height diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultdocument.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultdocument.py deleted file mode 100644 index 4e3c0b0..0000000 --- a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultdocument.py +++ /dev/null @@ -1,135 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the classes that represent Telegram InlineQueryResultDocument""" - -from typing import TYPE_CHECKING, Any, Union, Tuple, List - -from telegram import InlineQueryResult, MessageEntity -from telegram.utils.helpers import DEFAULT_NONE -from telegram.utils.types import ODVInput - -if TYPE_CHECKING: - from telegram import InputMessageContent, ReplyMarkup - - -class InlineQueryResultDocument(InlineQueryResult): - """ - Represents a link to a file. By default, this file will be sent by the user with an optional - caption. Alternatively, you can use :attr:`input_message_content` to send a message with the - specified content instead of the file. Currently, only .PDF and .ZIP files can be sent - using this method. - - Args: - id (:obj:`str`): Unique identifier for this result, 1-64 bytes. - title (:obj:`str`): Title for the result. - caption (:obj:`str`, optional): Caption of the document to be sent, 0-1024 characters - after entities parsing. - parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show - bold, italic, fixed-width text or inline URLs in the media caption. See the constants - in :class:`telegram.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special - entities that appear in the caption, which can be specified instead of - :attr:`parse_mode`. - document_url (:obj:`str`): A valid URL for the file. - mime_type (:obj:`str`): Mime type of the content of the file, either "application/pdf" - or "application/zip". - description (:obj:`str`, optional): Short description of the result. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the - message to be sent instead of the file. - thumb_url (:obj:`str`, optional): URL of the thumbnail (jpeg only) for the file. - thumb_width (:obj:`int`, optional): Thumbnail width. - thumb_height (:obj:`int`, optional): Thumbnail height. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - type (:obj:`str`): 'document'. - id (:obj:`str`): Unique identifier for this result, 1-64 bytes. - title (:obj:`str`): Title for the result. - caption (:obj:`str`): Optional. Caption of the document to be sent, 0-1024 characters - after entities parsing. - parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show - bold, italic, fixed-width text or inline URLs in the media caption. See the constants - in :class:`telegram.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special - entities that appear in the caption, which can be specified instead of - :attr:`parse_mode`. - document_url (:obj:`str`): A valid URL for the file. - mime_type (:obj:`str`): Mime type of the content of the file, either "application/pdf" - or "application/zip". - description (:obj:`str`): Optional. Short description of the result. - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the - message to be sent instead of the file. - thumb_url (:obj:`str`): Optional. URL of the thumbnail (jpeg only) for the file. - thumb_width (:obj:`int`): Optional. Thumbnail width. - thumb_height (:obj:`int`): Optional. Thumbnail height. - - """ - - __slots__ = ( - 'reply_markup', - 'caption_entities', - 'document_url', - 'thumb_width', - 'thumb_height', - 'caption', - 'title', - 'description', - 'parse_mode', - 'mime_type', - 'thumb_url', - 'input_message_content', - ) - - def __init__( - self, - id: str, # pylint: disable=W0622 - document_url: str, - title: str, - mime_type: str, - caption: str = None, - description: str = None, - reply_markup: 'ReplyMarkup' = None, - input_message_content: 'InputMessageContent' = None, - thumb_url: str = None, - thumb_width: int = None, - thumb_height: int = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, - **_kwargs: Any, - ): - # Required - super().__init__('document', id) - self.document_url = document_url - self.title = title - self.mime_type = mime_type - - # Optionals - self.caption = caption - self.parse_mode = parse_mode - self.caption_entities = caption_entities - self.description = description - self.reply_markup = reply_markup - self.input_message_content = input_message_content - self.thumb_url = thumb_url - self.thumb_width = thumb_width - self.thumb_height = thumb_height diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultgame.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultgame.py deleted file mode 100644 index f8535b4..0000000 --- a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultgame.py +++ /dev/null @@ -1,62 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the classes that represent Telegram InlineQueryResultGame.""" - -from typing import TYPE_CHECKING, Any - -from telegram import InlineQueryResult - -if TYPE_CHECKING: - from telegram import ReplyMarkup - - -class InlineQueryResultGame(InlineQueryResult): - """Represents a :class:`telegram.Game`. - - Args: - id (:obj:`str`): Unique identifier for this result, 1-64 bytes. - game_short_name (:obj:`str`): Short name of the game. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - type (:obj:`str`): 'game'. - id (:obj:`str`): Unique identifier for this result, 1-64 bytes. - game_short_name (:obj:`str`): Short name of the game. - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. - - """ - - __slots__ = ('reply_markup', 'game_short_name') - - def __init__( - self, - id: str, # pylint: disable=W0622 - game_short_name: str, - reply_markup: 'ReplyMarkup' = None, - **_kwargs: Any, - ): - # Required - super().__init__('game', id) - self.id = id # pylint: disable=W0622 - self.game_short_name = game_short_name - - self.reply_markup = reply_markup diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultgif.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultgif.py deleted file mode 100644 index 619af45..0000000 --- a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultgif.py +++ /dev/null @@ -1,137 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -# pylint: disable=W0622 -"""This module contains the classes that represent Telegram InlineQueryResultGif.""" - -from typing import TYPE_CHECKING, Any, Union, Tuple, List - -from telegram import InlineQueryResult, MessageEntity -from telegram.utils.helpers import DEFAULT_NONE -from telegram.utils.types import ODVInput - -if TYPE_CHECKING: - from telegram import InputMessageContent, ReplyMarkup - - -class InlineQueryResultGif(InlineQueryResult): - """ - Represents a link to an animated GIF file. By default, this animated GIF file will be sent by - the user with optional caption. Alternatively, you can use :attr:`input_message_content` to - send a message with the specified content instead of the animation. - - Args: - id (:obj:`str`): Unique identifier for this result, 1-64 bytes. - gif_url (:obj:`str`): A valid URL for the GIF file. File size must not exceed 1MB. - gif_width (:obj:`int`, optional): Width of the GIF. - gif_height (:obj:`int`, optional): Height of the GIF. - gif_duration (:obj:`int`, optional): Duration of the GIF - thumb_url (:obj:`str`): URL of the static (JPEG or GIF) or animated (MPEG4) thumbnail for - the result. - thumb_mime_type (:obj:`str`, optional): MIME type of the thumbnail, must be one of - ``'image/jpeg'``, ``'image/gif'``, or ``'video/mp4'``. Defaults to ``'image/jpeg'``. - title (:obj:`str`, optional): Title for the result. - caption (:obj:`str`, optional): Caption of the GIF file to be sent, 0-1024 characters - after entities parsing. - parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show - bold, italic, fixed-width text or inline URLs in the media caption. See the constants - in :class:`telegram.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special - entities that appear in the caption, which can be specified instead of - :attr:`parse_mode`. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the - message to be sent instead of the GIF animation. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - type (:obj:`str`): 'gif'. - id (:obj:`str`): Unique identifier for this result, 1-64 bytes. - gif_url (:obj:`str`): A valid URL for the GIF file. File size must not exceed 1MB. - gif_width (:obj:`int`): Optional. Width of the GIF. - gif_height (:obj:`int`): Optional. Height of the GIF. - gif_duration (:obj:`int`): Optional. Duration of the GIF. - thumb_url (:obj:`str`): URL of the static (JPEG or GIF) or animated (MPEG4) thumbnail for - the result. - thumb_mime_type (:obj:`str`): Optional. MIME type of the thumbnail. - title (:obj:`str`): Optional. Title for the result. - caption (:obj:`str`): Optional. Caption of the GIF file to be sent, 0-1024 characters - after entities parsing. - parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show - bold, italic, fixed-width text or inline URLs in the media caption. See the constants - in :class:`telegram.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special - entities that appear in the caption, which can be specified instead of - :attr:`parse_mode`. - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the - message to be sent instead of the GIF animation. - - """ - - __slots__ = ( - 'reply_markup', - 'gif_height', - 'thumb_mime_type', - 'caption_entities', - 'gif_width', - 'title', - 'caption', - 'parse_mode', - 'gif_duration', - 'input_message_content', - 'gif_url', - 'thumb_url', - ) - - def __init__( - self, - id: str, # pylint: disable=W0622 - gif_url: str, - thumb_url: str, - gif_width: int = None, - gif_height: int = None, - title: str = None, - caption: str = None, - reply_markup: 'ReplyMarkup' = None, - input_message_content: 'InputMessageContent' = None, - gif_duration: int = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - thumb_mime_type: str = None, - caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, - **_kwargs: Any, - ): - - # Required - super().__init__('gif', id) - self.gif_url = gif_url - self.thumb_url = thumb_url - - # Optionals - self.gif_width = gif_width - self.gif_height = gif_height - self.gif_duration = gif_duration - self.title = title - self.caption = caption - self.parse_mode = parse_mode - self.caption_entities = caption_entities - self.reply_markup = reply_markup - self.input_message_content = input_message_content - self.thumb_mime_type = thumb_mime_type diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultlocation.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultlocation.py deleted file mode 100644 index 2591b63..0000000 --- a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultlocation.py +++ /dev/null @@ -1,131 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the classes that represent Telegram InlineQueryResultLocation.""" - -from typing import TYPE_CHECKING, Any - -from telegram import InlineQueryResult - -if TYPE_CHECKING: - from telegram import InputMessageContent, ReplyMarkup - - -class InlineQueryResultLocation(InlineQueryResult): - """ - Represents a location on a map. By default, the location will be sent by the user. - Alternatively, you can use :attr:`input_message_content` to send a message with the specified - content instead of the location. - - Args: - id (:obj:`str`): Unique identifier for this result, 1-64 bytes. - latitude (:obj:`float`): Location latitude in degrees. - longitude (:obj:`float`): Location longitude in degrees. - title (:obj:`str`): Location title. - horizontal_accuracy (:obj:`float`, optional): The radius of uncertainty for the location, - measured in meters; 0-1500. - live_period (:obj:`int`, optional): Period in seconds for which the location can be - updated, should be between 60 and 86400. - heading (:obj:`int`, optional): For live locations, a direction in which the user is - moving, in degrees. Must be between 1 and 360 if specified. - proximity_alert_radius (:obj:`int`, optional): For live locations, a maximum distance for - proximity alerts about approaching another chat member, in meters. Must be between 1 - and 100000 if specified. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the - message to be sent instead of the location. - thumb_url (:obj:`str`, optional): Url of the thumbnail for the result. - thumb_width (:obj:`int`, optional): Thumbnail width. - thumb_height (:obj:`int`, optional): Thumbnail height. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - type (:obj:`str`): 'location'. - id (:obj:`str`): Unique identifier for this result, 1-64 bytes. - latitude (:obj:`float`): Location latitude in degrees. - longitude (:obj:`float`): Location longitude in degrees. - title (:obj:`str`): Location title. - horizontal_accuracy (:obj:`float`): Optional. The radius of uncertainty for the location, - measured in meters. - live_period (:obj:`int`): Optional. Period in seconds for which the location can be - updated, should be between 60 and 86400. - heading (:obj:`int`): Optional. For live locations, a direction in which the user is - moving, in degrees. - proximity_alert_radius (:obj:`int`): Optional. For live locations, a maximum distance for - proximity alerts about approaching another chat member, in meters. - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the - message to be sent instead of the location. - thumb_url (:obj:`str`): Optional. Url of the thumbnail for the result. - thumb_width (:obj:`int`): Optional. Thumbnail width. - thumb_height (:obj:`int`): Optional. Thumbnail height. - - """ - - __slots__ = ( - 'longitude', - 'reply_markup', - 'thumb_width', - 'thumb_height', - 'heading', - 'title', - 'live_period', - 'proximity_alert_radius', - 'input_message_content', - 'latitude', - 'horizontal_accuracy', - 'thumb_url', - ) - - def __init__( - self, - id: str, # pylint: disable=W0622 - latitude: float, - longitude: float, - title: str, - live_period: int = None, - reply_markup: 'ReplyMarkup' = None, - input_message_content: 'InputMessageContent' = None, - thumb_url: str = None, - thumb_width: int = None, - thumb_height: int = None, - horizontal_accuracy: float = None, - heading: int = None, - proximity_alert_radius: int = None, - **_kwargs: Any, - ): - # Required - super().__init__('location', id) - self.latitude = float(latitude) - self.longitude = float(longitude) - self.title = title - - # Optionals - self.live_period = live_period - self.reply_markup = reply_markup - self.input_message_content = input_message_content - self.thumb_url = thumb_url - self.thumb_width = thumb_width - self.thumb_height = thumb_height - self.horizontal_accuracy = float(horizontal_accuracy) if horizontal_accuracy else None - self.heading = int(heading) if heading else None - self.proximity_alert_radius = ( - int(proximity_alert_radius) if proximity_alert_radius else None - ) diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultmpeg4gif.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultmpeg4gif.py deleted file mode 100644 index 3eb1c21..0000000 --- a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultmpeg4gif.py +++ /dev/null @@ -1,136 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the classes that represent Telegram InlineQueryResultMpeg4Gif.""" - -from typing import TYPE_CHECKING, Any, Union, Tuple, List - -from telegram import InlineQueryResult, MessageEntity -from telegram.utils.helpers import DEFAULT_NONE -from telegram.utils.types import ODVInput - -if TYPE_CHECKING: - from telegram import InputMessageContent, ReplyMarkup - - -class InlineQueryResultMpeg4Gif(InlineQueryResult): - """ - Represents a link to a video animation (H.264/MPEG-4 AVC video without sound). By default, this - animated MPEG-4 file will be sent by the user with optional caption. Alternatively, you can - use :attr:`input_message_content` to send a message with the specified content instead of the - animation. - - Args: - id (:obj:`str`): Unique identifier for this result, 1-64 bytes. - mpeg4_url (:obj:`str`): A valid URL for the MP4 file. File size must not exceed 1MB. - mpeg4_width (:obj:`int`, optional): Video width. - mpeg4_height (:obj:`int`, optional): Video height. - mpeg4_duration (:obj:`int`, optional): Video duration. - thumb_url (:obj:`str`): URL of the static thumbnail (jpeg or gif) for the result. - thumb_mime_type (:obj:`str`): Optional. MIME type of the thumbnail, must be one of - ``'image/jpeg'``, ``'image/gif'``, or ``'video/mp4'``. Defaults to ``'image/jpeg'``. - title (:obj:`str`, optional): Title for the result. - caption (:obj:`str`, optional): Caption of the MPEG-4 file to be sent, 0-1024 characters - after entities parsing. - parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show - bold, italic, fixed-width text or inline URLs in the media caption. See the constants - in :class:`telegram.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special - entities that appear in the caption, which can be specified instead of - :attr:`parse_mode`. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the - message to be sent instead of the video animation. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - type (:obj:`str`): 'mpeg4_gif'. - id (:obj:`str`): Unique identifier for this result, 1-64 bytes. - mpeg4_url (:obj:`str`): A valid URL for the MP4 file. File size must not exceed 1MB. - mpeg4_width (:obj:`int`): Optional. Video width. - mpeg4_height (:obj:`int`): Optional. Video height. - mpeg4_duration (:obj:`int`): Optional. Video duration. - thumb_url (:obj:`str`): URL of the static (JPEG or GIF) or animated (MPEG4) thumbnail for - the result. - thumb_mime_type (:obj:`str`): Optional. MIME type of the thumbnail. - title (:obj:`str`): Optional. Title for the result. - caption (:obj:`str`): Optional. Caption of the MPEG-4 file to be sent, 0-1024 characters - after entities parsing. - parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show - bold, italic, fixed-width text or inline URLs in the media caption. See the constants - in :class:`telegram.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special - entities that appear in the caption, which can be specified instead of - :attr:`parse_mode`. - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the - message to be sent instead of the video animation. - - """ - - __slots__ = ( - 'reply_markup', - 'thumb_mime_type', - 'caption_entities', - 'mpeg4_duration', - 'mpeg4_width', - 'title', - 'caption', - 'parse_mode', - 'input_message_content', - 'mpeg4_url', - 'mpeg4_height', - 'thumb_url', - ) - - def __init__( - self, - id: str, # pylint: disable=W0622 - mpeg4_url: str, - thumb_url: str, - mpeg4_width: int = None, - mpeg4_height: int = None, - title: str = None, - caption: str = None, - reply_markup: 'ReplyMarkup' = None, - input_message_content: 'InputMessageContent' = None, - mpeg4_duration: int = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - thumb_mime_type: str = None, - caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, - **_kwargs: Any, - ): - - # Required - super().__init__('mpeg4_gif', id) - self.mpeg4_url = mpeg4_url - self.thumb_url = thumb_url - - # Optional - self.mpeg4_width = mpeg4_width - self.mpeg4_height = mpeg4_height - self.mpeg4_duration = mpeg4_duration - self.title = title - self.caption = caption - self.parse_mode = parse_mode - self.caption_entities = caption_entities - self.reply_markup = reply_markup - self.input_message_content = input_message_content - self.thumb_mime_type = thumb_mime_type diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultphoto.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultphoto.py deleted file mode 100644 index 98f7185..0000000 --- a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultphoto.py +++ /dev/null @@ -1,129 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the classes that represent Telegram InlineQueryResultPhoto.""" - -from typing import TYPE_CHECKING, Any, Union, Tuple, List - -from telegram import InlineQueryResult, MessageEntity -from telegram.utils.helpers import DEFAULT_NONE -from telegram.utils.types import ODVInput - -if TYPE_CHECKING: - from telegram import InputMessageContent, ReplyMarkup - - -class InlineQueryResultPhoto(InlineQueryResult): - """ - Represents a link to a photo. By default, this photo will be sent by the user with optional - caption. Alternatively, you can use :attr:`input_message_content` to send a message with the - specified content instead of the photo. - - Args: - id (:obj:`str`): Unique identifier for this result, 1-64 bytes. - photo_url (:obj:`str`): A valid URL of the photo. Photo must be in jpeg format. Photo size - must not exceed 5MB. - thumb_url (:obj:`str`): URL of the thumbnail for the photo. - photo_width (:obj:`int`, optional): Width of the photo. - photo_height (:obj:`int`, optional): Height of the photo. - title (:obj:`str`, optional): Title for the result. - description (:obj:`str`, optional): Short description of the result. - caption (:obj:`str`, optional): Caption of the photo to be sent, 0-1024 characters after - entities parsing. - parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show - bold, italic, fixed-width text or inline URLs in the media caption. See the constants - in :class:`telegram.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special - entities that appear in the caption, which can be specified instead of - :attr:`parse_mode`. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the - message to be sent instead of the photo. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - type (:obj:`str`): 'photo'. - id (:obj:`str`): Unique identifier for this result, 1-64 bytes. - photo_url (:obj:`str`): A valid URL of the photo. Photo must be in jpeg format. Photo size - must not exceed 5MB. - thumb_url (:obj:`str`): URL of the thumbnail for the photo. - photo_width (:obj:`int`): Optional. Width of the photo. - photo_height (:obj:`int`): Optional. Height of the photo. - title (:obj:`str`): Optional. Title for the result. - description (:obj:`str`): Optional. Short description of the result. - caption (:obj:`str`): Optional. Caption of the photo to be sent, 0-1024 characters after - entities parsing. - parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show - bold, italic, fixed-width text or inline URLs in the media caption. See the constants - in :class:`telegram.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special - entities that appear in the caption, which can be specified instead of - :attr:`parse_mode`. - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the - message to be sent instead of the photo. - - """ - - __slots__ = ( - 'photo_url', - 'reply_markup', - 'caption_entities', - 'photo_width', - 'caption', - 'title', - 'description', - 'parse_mode', - 'input_message_content', - 'photo_height', - 'thumb_url', - ) - - def __init__( - self, - id: str, # pylint: disable=W0622 - photo_url: str, - thumb_url: str, - photo_width: int = None, - photo_height: int = None, - title: str = None, - description: str = None, - caption: str = None, - reply_markup: 'ReplyMarkup' = None, - input_message_content: 'InputMessageContent' = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, - **_kwargs: Any, - ): - # Required - super().__init__('photo', id) - self.photo_url = photo_url - self.thumb_url = thumb_url - - # Optionals - self.photo_width = int(photo_width) if photo_width is not None else None - self.photo_height = int(photo_height) if photo_height is not None else None - self.title = title - self.description = description - self.caption = caption - self.parse_mode = parse_mode - self.caption_entities = caption_entities - self.reply_markup = reply_markup - self.input_message_content = input_message_content diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultvenue.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultvenue.py deleted file mode 100644 index 9930f7a..0000000 --- a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultvenue.py +++ /dev/null @@ -1,133 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the classes that represent Telegram InlineQueryResultVenue.""" - -from typing import TYPE_CHECKING, Any - -from telegram import InlineQueryResult - -if TYPE_CHECKING: - from telegram import InputMessageContent, ReplyMarkup - - -class InlineQueryResultVenue(InlineQueryResult): - """ - Represents a venue. By default, the venue will be sent by the user. Alternatively, you can - use :attr:`input_message_content` to send a message with the specified content instead of the - venue. - - Note: - Foursquare details and Google Pace details are mutually exclusive. However, this - behaviour is undocumented and might be changed by Telegram. - - Args: - id (:obj:`str`): Unique identifier for this result, 1-64 Bytes. - latitude (:obj:`float`): Latitude of the venue location in degrees. - longitude (:obj:`float`): Longitude of the venue location in degrees. - title (:obj:`str`): Title of the venue. - address (:obj:`str`): Address of the venue. - foursquare_id (:obj:`str`, optional): Foursquare identifier of the venue if known. - foursquare_type (:obj:`str`, optional): Foursquare type of the venue, if known. - (For example, "arts_entertainment/default", "arts_entertainment/aquarium" or - "food/icecream".) - google_place_id (:obj:`str`, optional): Google Places identifier of the venue. - google_place_type (:obj:`str`, optional): Google Places type of the venue. (See - `supported types <https://developers.google.com/places/web-service/supported_types>`_.) - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the - message to be sent instead of the location. - thumb_url (:obj:`str`, optional): Url of the thumbnail for the result. - thumb_width (:obj:`int`, optional): Thumbnail width. - thumb_height (:obj:`int`, optional): Thumbnail height. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - type (:obj:`str`): 'venue'. - id (:obj:`str`): Unique identifier for this result, 1-64 Bytes. - latitude (:obj:`float`): Latitude of the venue location in degrees. - longitude (:obj:`float`): Longitude of the venue location in degrees. - title (:obj:`str`): Title of the venue. - address (:obj:`str`): Address of the venue. - foursquare_id (:obj:`str`): Optional. Foursquare identifier of the venue if known. - foursquare_type (:obj:`str`): Optional. Foursquare type of the venue, if known. - google_place_id (:obj:`str`): Optional. Google Places identifier of the venue. - google_place_type (:obj:`str`): Optional. Google Places type of the venue. - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the - message to be sent instead of the venue. - thumb_url (:obj:`str`): Optional. Url of the thumbnail for the result. - thumb_width (:obj:`int`): Optional. Thumbnail width. - thumb_height (:obj:`int`): Optional. Thumbnail height. - - """ - - __slots__ = ( - 'longitude', - 'reply_markup', - 'google_place_type', - 'thumb_width', - 'thumb_height', - 'title', - 'address', - 'foursquare_id', - 'foursquare_type', - 'google_place_id', - 'input_message_content', - 'latitude', - 'thumb_url', - ) - - def __init__( - self, - id: str, # pylint: disable=W0622 - latitude: float, - longitude: float, - title: str, - address: str, - foursquare_id: str = None, - foursquare_type: str = None, - reply_markup: 'ReplyMarkup' = None, - input_message_content: 'InputMessageContent' = None, - thumb_url: str = None, - thumb_width: int = None, - thumb_height: int = None, - google_place_id: str = None, - google_place_type: str = None, - **_kwargs: Any, - ): - - # Required - super().__init__('venue', id) - self.latitude = latitude - self.longitude = longitude - self.title = title - self.address = address - - # Optional - self.foursquare_id = foursquare_id - self.foursquare_type = foursquare_type - self.google_place_id = google_place_id - self.google_place_type = google_place_type - self.reply_markup = reply_markup - self.input_message_content = input_message_content - self.thumb_url = thumb_url - self.thumb_width = thumb_width - self.thumb_height = thumb_height diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultvideo.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultvideo.py deleted file mode 100644 index b84a3f2..0000000 --- a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultvideo.py +++ /dev/null @@ -1,146 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the classes that represent Telegram InlineQueryResultVideo.""" - -from typing import TYPE_CHECKING, Any, Union, Tuple, List - -from telegram import InlineQueryResult, MessageEntity -from telegram.utils.helpers import DEFAULT_NONE -from telegram.utils.types import ODVInput - -if TYPE_CHECKING: - from telegram import InputMessageContent, ReplyMarkup - - -class InlineQueryResultVideo(InlineQueryResult): - """ - Represents a link to a page containing an embedded video player or a video file. By default, - this video file will be sent by the user with an optional caption. Alternatively, you can use - :attr:`input_message_content` to send a message with the specified content instead of - the video. - - Note: - If an InlineQueryResultVideo message contains an embedded video (e.g., YouTube), you must - replace its content using :attr:`input_message_content`. - - Args: - id (:obj:`str`): Unique identifier for this result, 1-64 bytes. - video_url (:obj:`str`): A valid URL for the embedded video player or video file. - mime_type (:obj:`str`): Mime type of the content of video url, "text/html" or "video/mp4". - thumb_url (:obj:`str`): URL of the thumbnail (jpeg only) for the video. - title (:obj:`str`): Title for the result. - caption (:obj:`str`, optional): Caption, 0-1024 characters after entities parsing. - parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show - bold, italic, fixed-width text or inline URLs in the media caption. See the constants - in :class:`telegram.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special - entities that appear in the caption, which can be specified instead of - :attr:`parse_mode`. - video_width (:obj:`int`, optional): Video width. - video_height (:obj:`int`, optional): Video height. - video_duration (:obj:`int`, optional): Video duration in seconds. - description (:obj:`str`, optional): Short description of the result. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the - message to be sent instead of the video. This field is required if - InlineQueryResultVideo is used to send an HTML-page as a result - (e.g., a YouTube video). - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - type (:obj:`str`): 'video'. - id (:obj:`str`): Unique identifier for this result, 1-64 bytes. - video_url (:obj:`str`): A valid URL for the embedded video player or video file. - mime_type (:obj:`str`): Mime type of the content of video url, "text/html" or "video/mp4". - thumb_url (:obj:`str`): URL of the thumbnail (jpeg only) for the video. - title (:obj:`str`): Title for the result. - caption (:obj:`str`): Optional. Caption of the video to be sent, 0-1024 characters after - entities parsing. - parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show - bold, italic, fixed-width text or inline URLs in the media caption. See the constants - in :class:`telegram.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special - entities that appear in the caption, which can be specified instead of - :attr:`parse_mode`. - video_width (:obj:`int`): Optional. Video width. - video_height (:obj:`int`): Optional. Video height. - video_duration (:obj:`int`): Optional. Video duration in seconds. - description (:obj:`str`): Optional. Short description of the result. - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the - message to be sent instead of the video. This field is required if - InlineQueryResultVideo is used to send an HTML-page as a result - (e.g., a YouTube video). - - """ - - __slots__ = ( - 'video_url', - 'reply_markup', - 'caption_entities', - 'caption', - 'title', - 'description', - 'video_duration', - 'parse_mode', - 'mime_type', - 'input_message_content', - 'video_height', - 'video_width', - 'thumb_url', - ) - - def __init__( - self, - id: str, # pylint: disable=W0622 - video_url: str, - mime_type: str, - thumb_url: str, - title: str, - caption: str = None, - video_width: int = None, - video_height: int = None, - video_duration: int = None, - description: str = None, - reply_markup: 'ReplyMarkup' = None, - input_message_content: 'InputMessageContent' = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, - **_kwargs: Any, - ): - - # Required - super().__init__('video', id) - self.video_url = video_url - self.mime_type = mime_type - self.thumb_url = thumb_url - self.title = title - - # Optional - self.caption = caption - self.parse_mode = parse_mode - self.caption_entities = caption_entities - self.video_width = video_width - self.video_height = video_height - self.video_duration = video_duration - self.description = description - self.reply_markup = reply_markup - self.input_message_content = input_message_content diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultvoice.py b/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultvoice.py deleted file mode 100644 index 531f04b..0000000 --- a/venv/lib/python3.8/site-packages/telegram/inline/inlinequeryresultvoice.py +++ /dev/null @@ -1,112 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the classes that represent Telegram InlineQueryResultVoice.""" - -from typing import TYPE_CHECKING, Any, Union, Tuple, List - -from telegram import InlineQueryResult, MessageEntity -from telegram.utils.helpers import DEFAULT_NONE -from telegram.utils.types import ODVInput - -if TYPE_CHECKING: - from telegram import InputMessageContent, ReplyMarkup - - -class InlineQueryResultVoice(InlineQueryResult): - """ - Represents a link to a voice recording in an .ogg container encoded with OPUS. By default, - this voice recording will be sent by the user. Alternatively, you can use - :attr:`input_message_content` to send a message with the specified content instead of the - the voice message. - - Args: - id (:obj:`str`): Unique identifier for this result, 1-64 bytes. - voice_url (:obj:`str`): A valid URL for the voice recording. - title (:obj:`str`): Recording title. - caption (:obj:`str`, optional): Caption, 0-1024 characters after entities parsing. - parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show - bold, italic, fixed-width text or inline URLs in the media caption. See the constants - in :class:`telegram.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`], optional): List of special - entities that appear in the caption, which can be specified instead of - :attr:`parse_mode`. - voice_duration (:obj:`int`, optional): Recording duration in seconds. - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`, optional): Content of the - message to be sent instead of the voice recording. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - type (:obj:`str`): 'voice'. - id (:obj:`str`): Unique identifier for this result, 1-64 bytes. - voice_url (:obj:`str`): A valid URL for the voice recording. - title (:obj:`str`): Recording title. - caption (:obj:`str`): Optional. Caption, 0-1024 characters after entities parsing. - parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show - bold, italic, fixed-width text or inline URLs in the media caption. See the constants - in :class:`telegram.ParseMode` for the available modes. - caption_entities (List[:class:`telegram.MessageEntity`]): Optional. List of special - entities that appear in the caption, which can be specified instead of - :attr:`parse_mode`. - voice_duration (:obj:`int`): Optional. Recording duration in seconds. - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. - input_message_content (:class:`telegram.InputMessageContent`): Optional. Content of the - message to be sent instead of the voice recording. - - """ - - __slots__ = ( - 'reply_markup', - 'caption_entities', - 'voice_duration', - 'caption', - 'title', - 'voice_url', - 'parse_mode', - 'input_message_content', - ) - - def __init__( - self, - id: str, # pylint: disable=W0622 - voice_url: str, - title: str, - voice_duration: int = None, - caption: str = None, - reply_markup: 'ReplyMarkup' = None, - input_message_content: 'InputMessageContent' = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, - **_kwargs: Any, - ): - - # Required - super().__init__('voice', id) - self.voice_url = voice_url - self.title = title - - # Optional - self.voice_duration = voice_duration - self.caption = caption - self.parse_mode = parse_mode - self.caption_entities = caption_entities - self.reply_markup = reply_markup - self.input_message_content = input_message_content diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inputcontactmessagecontent.py b/venv/lib/python3.8/site-packages/telegram/inline/inputcontactmessagecontent.py deleted file mode 100644 index 22e9460..0000000 --- a/venv/lib/python3.8/site-packages/telegram/inline/inputcontactmessagecontent.py +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the classes that represent Telegram InputContactMessageContent.""" - -from typing import Any - -from telegram import InputMessageContent - - -class InputContactMessageContent(InputMessageContent): - """Represents the content of a contact message to be sent as the result of an inline query. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`phone_number` is equal. - - Args: - phone_number (:obj:`str`): Contact's phone number. - first_name (:obj:`str`): Contact's first name. - last_name (:obj:`str`, optional): Contact's last name. - vcard (:obj:`str`, optional): Additional data about the contact in the form of a vCard, - 0-2048 bytes. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - phone_number (:obj:`str`): Contact's phone number. - first_name (:obj:`str`): Contact's first name. - last_name (:obj:`str`): Optional. Contact's last name. - vcard (:obj:`str`): Optional. Additional data about the contact in the form of a vCard, - 0-2048 bytes. - - """ - - __slots__ = ('vcard', 'first_name', 'last_name', 'phone_number', '_id_attrs') - - def __init__( - self, - phone_number: str, - first_name: str, - last_name: str = None, - vcard: str = None, - **_kwargs: Any, - ): - # Required - self.phone_number = phone_number - self.first_name = first_name - # Optionals - self.last_name = last_name - self.vcard = vcard - - self._id_attrs = (self.phone_number,) diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inputinvoicemessagecontent.py b/venv/lib/python3.8/site-packages/telegram/inline/inputinvoicemessagecontent.py deleted file mode 100644 index 2cbbcb8..0000000 --- a/venv/lib/python3.8/site-packages/telegram/inline/inputinvoicemessagecontent.py +++ /dev/null @@ -1,242 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains a class that represents a Telegram InputInvoiceMessageContent.""" - -from typing import Any, List, Optional, TYPE_CHECKING - -from telegram import InputMessageContent, LabeledPrice -from telegram.utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - - -class InputInvoiceMessageContent(InputMessageContent): - """ - Represents the content of a invoice message to be sent as the result of an inline query. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`title`, :attr:`description`, :attr:`payload`, - :attr:`provider_token`, :attr:`currency` and :attr:`prices` are equal. - - .. versionadded:: 13.5 - - Args: - title (:obj:`str`): Product name, 1-32 characters - description (:obj:`str`): Product description, 1-255 characters - payload (:obj:`str`):Bot-defined invoice payload, 1-128 bytes. This will not be displayed - to the user, use for your internal processes. - provider_token (:obj:`str`): Payment provider token, obtained via - `@Botfather <https://t.me/Botfather>`_. - currency (:obj:`str`): Three-letter ISO 4217 currency code, see more on - `currencies <https://core.telegram.org/bots/payments#supported-currencies>`_ - prices (List[:class:`telegram.LabeledPrice`]): Price breakdown, a JSON-serialized list of - components (e.g. product price, tax, discount, delivery cost, delivery tax, bonus, - etc.) - max_tip_amount (:obj:`int`, optional): The maximum accepted amount for tips in the smallest - units of the currency (integer, not float/double). For example, for a maximum tip of - US$ 1.45 pass ``max_tip_amount = 145``. See the ``exp`` parameter in - `currencies.json <https://core.telegram.org/bots/payments/currencies.json>`_, it - shows the number of digits past the decimal point for each currency (2 for the majority - of currencies). Defaults to ``0``. - suggested_tip_amounts (List[:obj:`int`], optional): A JSON-serialized array of suggested - amounts of tip in the smallest units of the currency (integer, not float/double). At - most 4 suggested tip amounts can be specified. The suggested tip amounts must be - positive, passed in a strictly increased order and must not exceed - :attr:`max_tip_amount`. - provider_data (:obj:`str`, optional): A JSON-serialized object for data about the invoice, - which will be shared with the payment provider. A detailed description of the required - fields should be provided by the payment provider. - photo_url (:obj:`str`, optional): URL of the product photo for the invoice. Can be a photo - of the goods or a marketing image for a service. People like it better when they see - what they are paying for. - photo_size (:obj:`int`, optional): Photo size. - photo_width (:obj:`int`, optional): Photo width. - photo_height (:obj:`int`, optional): Photo height. - need_name (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's full name to - complete the order. - need_phone_number (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's - phone number to complete the order - need_email (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's email - address to complete the order. - need_shipping_address (:obj:`bool`, optional): Pass :obj:`True`, if you require the user's - shipping address to complete the order - send_phone_number_to_provider (:obj:`bool`, optional): Pass :obj:`True`, if user's phone - number should be sent to provider. - send_email_to_provider (:obj:`bool`, optional): Pass :obj:`True`, if user's email address - should be sent to provider. - is_flexible (:obj:`bool`, optional): Pass :obj:`True`, if the final price depends on the - shipping method. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - title (:obj:`str`): Product name, 1-32 characters - description (:obj:`str`): Product description, 1-255 characters - payload (:obj:`str`):Bot-defined invoice payload, 1-128 bytes. This will not be displayed - to the user, use for your internal processes. - provider_token (:obj:`str`): Payment provider token, obtained via - `@Botfather <https://t.me/Botfather>`_. - currency (:obj:`str`): Three-letter ISO 4217 currency code, see more on - `currencies <https://core.telegram.org/bots/payments#supported-currencies>`_ - prices (List[:class:`telegram.LabeledPrice`]): Price breakdown, a JSON-serialized list of - components. - max_tip_amount (:obj:`int`): Optional. The maximum accepted amount for tips in the smallest - units of the currency (integer, not float/double). - suggested_tip_amounts (List[:obj:`int`]): Optional. A JSON-serialized array of suggested - amounts of tip in the smallest units of the currency (integer, not float/double). - provider_data (:obj:`str`): Optional. A JSON-serialized object for data about the invoice, - which will be shared with the payment provider. - photo_url (:obj:`str`): Optional. URL of the product photo for the invoice. - photo_size (:obj:`int`): Optional. Photo size. - photo_width (:obj:`int`): Optional. Photo width. - photo_height (:obj:`int`): Optional. Photo height. - need_name (:obj:`bool`): Optional. Pass :obj:`True`, if you require the user's full name to - complete the order. - need_phone_number (:obj:`bool`): Optional. Pass :obj:`True`, if you require the user's - phone number to complete the order - need_email (:obj:`bool`): Optional. Pass :obj:`True`, if you require the user's email - address to complete the order. - need_shipping_address (:obj:`bool`): Optional. Pass :obj:`True`, if you require the user's - shipping address to complete the order - send_phone_number_to_provider (:obj:`bool`): Optional. Pass :obj:`True`, if user's phone - number should be sent to provider. - send_email_to_provider (:obj:`bool`): Optional. Pass :obj:`True`, if user's email address - should be sent to provider. - is_flexible (:obj:`bool`): Optional. Pass :obj:`True`, if the final price depends on the - shipping method. - - """ - - __slots__ = ( - 'title', - 'description', - 'payload', - 'provider_token', - 'currency', - 'prices', - 'max_tip_amount', - 'suggested_tip_amounts', - 'provider_data', - 'photo_url', - 'photo_size', - 'photo_width', - 'photo_height', - 'need_name', - 'need_phone_number', - 'need_email', - 'need_shipping_address', - 'send_phone_number_to_provider', - 'send_email_to_provider', - 'is_flexible', - '_id_attrs', - ) - - def __init__( - self, - title: str, - description: str, - payload: str, - provider_token: str, - currency: str, - prices: List[LabeledPrice], - max_tip_amount: int = None, - suggested_tip_amounts: List[int] = None, - provider_data: str = None, - photo_url: str = None, - photo_size: int = None, - photo_width: int = None, - photo_height: int = None, - need_name: bool = None, - need_phone_number: bool = None, - need_email: bool = None, - need_shipping_address: bool = None, - send_phone_number_to_provider: bool = None, - send_email_to_provider: bool = None, - is_flexible: bool = None, - **_kwargs: Any, - ): - # Required - self.title = title - self.description = description - self.payload = payload - self.provider_token = provider_token - self.currency = currency - self.prices = prices - # Optionals - self.max_tip_amount = int(max_tip_amount) if max_tip_amount else None - self.suggested_tip_amounts = ( - [int(sta) for sta in suggested_tip_amounts] if suggested_tip_amounts else None - ) - self.provider_data = provider_data - self.photo_url = photo_url - self.photo_size = int(photo_size) if photo_size else None - self.photo_width = int(photo_width) if photo_width else None - self.photo_height = int(photo_height) if photo_height else None - self.need_name = need_name - self.need_phone_number = need_phone_number - self.need_email = need_email - self.need_shipping_address = need_shipping_address - self.send_phone_number_to_provider = send_phone_number_to_provider - self.send_email_to_provider = send_email_to_provider - self.is_flexible = is_flexible - - self._id_attrs = ( - self.title, - self.description, - self.payload, - self.provider_token, - self.currency, - self.prices, - ) - - def __hash__(self) -> int: - # we override this as self.prices is a list and not hashable - prices = tuple(self.prices) - return hash( - ( - self.title, - self.description, - self.payload, - self.provider_token, - self.currency, - prices, - ) - ) - - def to_dict(self) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict() - - data['prices'] = [price.to_dict() for price in self.prices] - - return data - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: 'Bot' - ) -> Optional['InputInvoiceMessageContent']: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data['prices'] = LabeledPrice.de_list(data.get('prices'), bot) - - return cls(**data, bot=bot) diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inputlocationmessagecontent.py b/venv/lib/python3.8/site-packages/telegram/inline/inputlocationmessagecontent.py deleted file mode 100644 index fe86628..0000000 --- a/venv/lib/python3.8/site-packages/telegram/inline/inputlocationmessagecontent.py +++ /dev/null @@ -1,88 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the classes that represent Telegram InputLocationMessageContent.""" - -from typing import Any - -from telegram import InputMessageContent - - -class InputLocationMessageContent(InputMessageContent): - # fmt: off - """ - Represents the content of a location message to be sent as the result of an inline query. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`latitude` and :attr:`longitude` are equal. - - Args: - latitude (:obj:`float`): Latitude of the location in degrees. - longitude (:obj:`float`): Longitude of the location in degrees. - horizontal_accuracy (:obj:`float`, optional): The radius of uncertainty for the location, - measured in meters; 0-1500. - live_period (:obj:`int`, optional): Period in seconds for which the location can be - updated, should be between 60 and 86400. - heading (:obj:`int`, optional): For live locations, a direction in which the user is - moving, in degrees. Must be between 1 and 360 if specified. - proximity_alert_radius (:obj:`int`, optional): For live locations, a maximum distance for - proximity alerts about approaching another chat member, in meters. Must be between 1 - and 100000 if specified. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - latitude (:obj:`float`): Latitude of the location in degrees. - longitude (:obj:`float`): Longitude of the location in degrees. - horizontal_accuracy (:obj:`float`): Optional. The radius of uncertainty for the location, - measured in meters. - live_period (:obj:`int`): Optional. Period in seconds for which the location can be - updated. - heading (:obj:`int`): Optional. For live locations, a direction in which the user is - moving, in degrees. - proximity_alert_radius (:obj:`int`): Optional. For live locations, a maximum distance for - proximity alerts about approaching another chat member, in meters. - - """ - - __slots__ = ('longitude', 'horizontal_accuracy', 'proximity_alert_radius', 'live_period', - 'latitude', 'heading', '_id_attrs') - # fmt: on - - def __init__( - self, - latitude: float, - longitude: float, - live_period: int = None, - horizontal_accuracy: float = None, - heading: int = None, - proximity_alert_radius: int = None, - **_kwargs: Any, - ): - # Required - self.latitude = latitude - self.longitude = longitude - - # Optionals - self.live_period = int(live_period) if live_period else None - self.horizontal_accuracy = float(horizontal_accuracy) if horizontal_accuracy else None - self.heading = int(heading) if heading else None - self.proximity_alert_radius = ( - int(proximity_alert_radius) if proximity_alert_radius else None - ) - - self._id_attrs = (self.latitude, self.longitude) diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inputmessagecontent.py b/venv/lib/python3.8/site-packages/telegram/inline/inputmessagecontent.py deleted file mode 100644 index 44fd681..0000000 --- a/venv/lib/python3.8/site-packages/telegram/inline/inputmessagecontent.py +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the classes that represent Telegram InputMessageContent.""" - -from telegram import TelegramObject - - -class InputMessageContent(TelegramObject): - """Base class for Telegram InputMessageContent Objects. - - See: :class:`telegram.InputContactMessageContent`, - :class:`telegram.InputInvoiceMessageContent`, - :class:`telegram.InputLocationMessageContent`, :class:`telegram.InputTextMessageContent` and - :class:`telegram.InputVenueMessageContent` for more details. - - """ - - __slots__ = () diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inputtextmessagecontent.py b/venv/lib/python3.8/site-packages/telegram/inline/inputtextmessagecontent.py deleted file mode 100644 index 3d60f45..0000000 --- a/venv/lib/python3.8/site-packages/telegram/inline/inputtextmessagecontent.py +++ /dev/null @@ -1,88 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the classes that represent Telegram InputTextMessageContent.""" - -from typing import Any, Union, Tuple, List - -from telegram import InputMessageContent, MessageEntity -from telegram.utils.helpers import DEFAULT_NONE -from telegram.utils.types import JSONDict, ODVInput - - -class InputTextMessageContent(InputMessageContent): - """ - Represents the content of a text message to be sent as the result of an inline query. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`message_text` is equal. - - Args: - message_text (:obj:`str`): Text of the message to be sent, 1-4096 characters after entities - parsing. Also found as :attr:`telegram.constants.MAX_MESSAGE_LENGTH`. - parse_mode (:obj:`str`, optional): Send Markdown or HTML, if you want Telegram apps to show - bold, italic, fixed-width text or inline URLs in your bot's message. See the constants - in :class:`telegram.ParseMode` for the available modes. - entities (List[:class:`telegram.MessageEntity`], optional): List of special - entities that appear in the caption, which can be specified instead of - :attr:`parse_mode`. - disable_web_page_preview (:obj:`bool`, optional): Disables link previews for links in the - sent message. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - message_text (:obj:`str`): Text of the message to be sent, 1-4096 characters after entities - parsing. - parse_mode (:obj:`str`): Optional. Send Markdown or HTML, if you want Telegram apps to show - bold, italic, fixed-width text or inline URLs in your bot's message. See the constants - in :class:`telegram.ParseMode` for the available modes. - entities (List[:class:`telegram.MessageEntity`]): Optional. List of special - entities that appear in the caption, which can be specified instead of - :attr:`parse_mode`. - disable_web_page_preview (:obj:`bool`): Optional. Disables link previews for links in the - sent message. - - """ - - __slots__ = ('disable_web_page_preview', 'parse_mode', 'entities', 'message_text', '_id_attrs') - - def __init__( - self, - message_text: str, - parse_mode: ODVInput[str] = DEFAULT_NONE, - disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, - entities: Union[Tuple[MessageEntity, ...], List[MessageEntity]] = None, - **_kwargs: Any, - ): - # Required - self.message_text = message_text - # Optionals - self.parse_mode = parse_mode - self.entities = entities - self.disable_web_page_preview = disable_web_page_preview - - self._id_attrs = (self.message_text,) - - def to_dict(self) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict() - - if self.entities: - data['entities'] = [ce.to_dict() for ce in self.entities] - - return data diff --git a/venv/lib/python3.8/site-packages/telegram/inline/inputvenuemessagecontent.py b/venv/lib/python3.8/site-packages/telegram/inline/inputvenuemessagecontent.py deleted file mode 100644 index 55652d2..0000000 --- a/venv/lib/python3.8/site-packages/telegram/inline/inputvenuemessagecontent.py +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the classes that represent Telegram InputVenueMessageContent.""" - -from typing import Any - -from telegram import InputMessageContent - - -class InputVenueMessageContent(InputMessageContent): - """Represents the content of a venue message to be sent as the result of an inline query. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`latitude`, :attr:`longitude` and :attr:`title` - are equal. - - Note: - Foursquare details and Google Pace details are mutually exclusive. However, this - behaviour is undocumented and might be changed by Telegram. - - Args: - latitude (:obj:`float`): Latitude of the location in degrees. - longitude (:obj:`float`): Longitude of the location in degrees. - title (:obj:`str`): Name of the venue. - address (:obj:`str`): Address of the venue. - foursquare_id (:obj:`str`, optional): Foursquare identifier of the venue, if known. - foursquare_type (:obj:`str`, optional): Foursquare type of the venue, if known. - (For example, "arts_entertainment/default", "arts_entertainment/aquarium" or - "food/icecream".) - google_place_id (:obj:`str`, optional): Google Places identifier of the venue. - google_place_type (:obj:`str`, optional): Google Places type of the venue. (See - `supported types <https://developers.google.com/places/web-service/supported_types>`_.) - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - latitude (:obj:`float`): Latitude of the location in degrees. - longitude (:obj:`float`): Longitude of the location in degrees. - title (:obj:`str`): Name of the venue. - address (:obj:`str`): Address of the venue. - foursquare_id (:obj:`str`): Optional. Foursquare identifier of the venue, if known. - foursquare_type (:obj:`str`): Optional. Foursquare type of the venue, if known. - google_place_id (:obj:`str`): Optional. Google Places identifier of the venue. - google_place_type (:obj:`str`): Optional. Google Places type of the venue. - - """ - - __slots__ = ( - 'longitude', - 'google_place_type', - 'title', - 'address', - 'foursquare_id', - 'foursquare_type', - 'google_place_id', - 'latitude', - '_id_attrs', - ) - - def __init__( - self, - latitude: float, - longitude: float, - title: str, - address: str, - foursquare_id: str = None, - foursquare_type: str = None, - google_place_id: str = None, - google_place_type: str = None, - **_kwargs: Any, - ): - # Required - self.latitude = latitude - self.longitude = longitude - self.title = title - self.address = address - # Optionals - self.foursquare_id = foursquare_id - self.foursquare_type = foursquare_type - self.google_place_id = google_place_id - self.google_place_type = google_place_type - - self._id_attrs = ( - self.latitude, - self.longitude, - self.title, - ) diff --git a/venv/lib/python3.8/site-packages/telegram/keyboardbutton.py b/venv/lib/python3.8/site-packages/telegram/keyboardbutton.py deleted file mode 100644 index 590801b..0000000 --- a/venv/lib/python3.8/site-packages/telegram/keyboardbutton.py +++ /dev/null @@ -1,83 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram KeyboardButton.""" - -from typing import Any - -from telegram import TelegramObject, KeyboardButtonPollType - - -class KeyboardButton(TelegramObject): - """ - This object represents one button of the reply keyboard. For simple text buttons String can be - used instead of this object to specify text of the button. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`text`, :attr:`request_contact`, :attr:`request_location` and - :attr:`request_poll` are equal. - - Note: - * Optional fields are mutually exclusive. - * :attr:`request_contact` and :attr:`request_location` options will only work in Telegram - versions released after 9 April, 2016. Older clients will ignore them. - * :attr:`request_poll` option will only work in Telegram versions released after 23 - January, 2020. Older clients will receive unsupported message. - - Args: - text (:obj:`str`): Text of the button. If none of the optional fields are used, it will be - sent to the bot as a message when the button is pressed. - request_contact (:obj:`bool`, optional): If :obj:`True`, the user's phone number will be - sent as a contact when the button is pressed. Available in private chats only. - request_location (:obj:`bool`, optional): If :obj:`True`, the user's current location will - be sent when the button is pressed. Available in private chats only. - request_poll (:class:`KeyboardButtonPollType`, optional): If specified, the user will be - asked to create a poll and send it to the bot when the button is pressed. Available in - private chats only. - - Attributes: - text (:obj:`str`): Text of the button. - request_contact (:obj:`bool`): Optional. The user's phone number will be sent. - request_location (:obj:`bool`): Optional. The user's current location will be sent. - request_poll (:class:`KeyboardButtonPollType`): Optional. If the user should create a poll. - - """ - - __slots__ = ('request_location', 'request_contact', 'request_poll', 'text', '_id_attrs') - - def __init__( - self, - text: str, - request_contact: bool = None, - request_location: bool = None, - request_poll: KeyboardButtonPollType = None, - **_kwargs: Any, - ): - # Required - self.text = text - # Optionals - self.request_contact = request_contact - self.request_location = request_location - self.request_poll = request_poll - - self._id_attrs = ( - self.text, - self.request_contact, - self.request_location, - self.request_poll, - ) diff --git a/venv/lib/python3.8/site-packages/telegram/keyboardbuttonpolltype.py b/venv/lib/python3.8/site-packages/telegram/keyboardbuttonpolltype.py deleted file mode 100644 index 89be62a..0000000 --- a/venv/lib/python3.8/site-packages/telegram/keyboardbuttonpolltype.py +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env python -# pylint: disable=R0903 -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2020-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a type of a Telegram Poll.""" -from typing import Any - -from telegram import TelegramObject - - -class KeyboardButtonPollType(TelegramObject): - """This object represents type of a poll, which is allowed to be created - and sent when the corresponding button is pressed. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`type` is equal. - - Attributes: - type (:obj:`str`): Optional. If :attr:`telegram.Poll.QUIZ` is passed, the user will be - allowed to create only polls in the quiz mode. If :attr:`telegram.Poll.REGULAR` is - passed, only regular polls will be allowed. Otherwise, the user will be allowed to - create a poll of any type. - """ - - __slots__ = ('type', '_id_attrs') - - def __init__(self, type: str = None, **_kwargs: Any): # pylint: disable=W0622 - self.type = type - - self._id_attrs = (self.type,) diff --git a/venv/lib/python3.8/site-packages/telegram/loginurl.py b/venv/lib/python3.8/site-packages/telegram/loginurl.py deleted file mode 100644 index 8179273..0000000 --- a/venv/lib/python3.8/site-packages/telegram/loginurl.py +++ /dev/null @@ -1,89 +0,0 @@ -#!/usr/bin/env python -# pylint: disable=R0903 -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram LoginUrl.""" -from typing import Any - -from telegram import TelegramObject - - -class LoginUrl(TelegramObject): - """This object represents a parameter of the inline keyboard button used to automatically - authorize a user. Serves as a great replacement for the Telegram Login Widget when the user is - coming from Telegram. All the user needs to do is tap/click a button and confirm that they want - to log in. Telegram apps support these buttons as of version 5.7. - - Sample bot: `@discussbot <https://t.me/dicussbot>`_ - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`url` is equal. - - Note: - You must always check the hash of the received data to verify the authentication - and the integrity of the data as described in - `Checking authorization <https://core.telegram.org/widgets/login#checking-authorization>`_ - - Args: - url (:obj:`str`): An HTTP URL to be opened with user authorization data added to the query - string when the button is pressed. If the user refuses to provide authorization data, - the original URL without information about the user will be opened. The data added is - the same as described in - `Receiving authorization data - <https://core.telegram.org/widgets/login#receiving-authorization-data>`_ - forward_text (:obj:`str`, optional): New text of the button in forwarded messages. - bot_username (:obj:`str`, optional): Username of a bot, which will be used for user - authorization. See - `Setting up a bot <https://core.telegram.org/widgets/login#setting-up-a-bot>`_ - for more details. If not specified, the current - bot's username will be assumed. The url's domain must be the same as the domain linked - with the bot. See - `Linking your domain to the bot - <https://core.telegram.org/widgets/login#linking-your-domain-to-the-bot>`_ - for more details. - request_write_access (:obj:`bool`, optional): Pass :obj:`True` to request the permission - for your bot to send messages to the user. - - Attributes: - url (:obj:`str`): An HTTP URL to be opened with user authorization data. - forward_text (:obj:`str`): Optional. New text of the button in forwarded messages. - bot_username (:obj:`str`): Optional. Username of a bot, which will be used for user - authorization. - request_write_access (:obj:`bool`): Optional. Pass :obj:`True` to request the permission - for your bot to send messages to the user. - - """ - - __slots__ = ('bot_username', 'request_write_access', 'url', 'forward_text', '_id_attrs') - - def __init__( - self, - url: str, - forward_text: bool = None, - bot_username: str = None, - request_write_access: bool = None, - **_kwargs: Any, - ): - # Required - self.url = url - # Optional - self.forward_text = forward_text - self.bot_username = bot_username - self.request_write_access = request_write_access - - self._id_attrs = (self.url,) diff --git a/venv/lib/python3.8/site-packages/telegram/message.py b/venv/lib/python3.8/site-packages/telegram/message.py deleted file mode 100644 index 63e18bf..0000000 --- a/venv/lib/python3.8/site-packages/telegram/message.py +++ /dev/null @@ -1,2888 +0,0 @@ -#!/usr/bin/env python -# pylint: disable=R0902,R0913 -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram Message.""" -import datetime -import sys -from html import escape -from typing import TYPE_CHECKING, Any, Dict, List, Optional, Union, ClassVar, Tuple - -from telegram import ( - Animation, - Audio, - Chat, - Contact, - Dice, - Document, - Game, - InlineKeyboardMarkup, - Invoice, - Location, - MessageEntity, - ParseMode, - PassportData, - PhotoSize, - Poll, - Sticker, - SuccessfulPayment, - TelegramObject, - User, - Venue, - Video, - VideoNote, - Voice, - VoiceChatStarted, - VoiceChatEnded, - VoiceChatParticipantsInvited, - ProximityAlertTriggered, - ReplyMarkup, - MessageAutoDeleteTimerChanged, - VoiceChatScheduled, -) -from telegram.utils.helpers import ( - escape_markdown, - from_timestamp, - to_timestamp, - DEFAULT_NONE, - DEFAULT_20, -) -from telegram.utils.types import JSONDict, FileInput, ODVInput, DVInput - -if TYPE_CHECKING: - from telegram import ( - Bot, - GameHighScore, - InputMedia, - MessageId, - InputMediaAudio, - InputMediaDocument, - InputMediaPhoto, - InputMediaVideo, - LabeledPrice, - ) - - -class Message(TelegramObject): - # fmt: off - """This object represents a message. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`message_id` and :attr:`chat` are equal. - - Note: - In Python ``from`` is a reserved word, use ``from_user`` instead. - - Args: - message_id (:obj:`int`): Unique message identifier inside this chat. - from_user (:class:`telegram.User`, optional): Sender, empty for messages sent - to channels. - sender_chat (:class:`telegram.Chat`, optional): Sender of the message, sent on behalf of a - chat. The channel itself for channel messages. The supergroup itself for messages from - anonymous group administrators. The linked channel for messages automatically forwarded - to the discussion group. - date (:class:`datetime.datetime`): Date the message was sent in Unix time. Converted to - :class:`datetime.datetime`. - chat (:class:`telegram.Chat`): Conversation the message belongs to. - forward_from (:class:`telegram.User`, optional): For forwarded messages, sender of - the original message. - forward_from_chat (:class:`telegram.Chat`, optional): For messages forwarded from channels - or from anonymous administrators, information about the original sender chat. - forward_from_message_id (:obj:`int`, optional): For forwarded channel posts, identifier of - the original message in the channel. - forward_sender_name (:obj:`str`, optional): Sender's name for messages forwarded from users - who disallow adding a link to their account in forwarded messages. - forward_date (:class:`datetime.datetime`, optional): For forwarded messages, date the - original message was sent in Unix time. Converted to :class:`datetime.datetime`. - reply_to_message (:class:`telegram.Message`, optional): For replies, the original message. - edit_date (:class:`datetime.datetime`, optional): Date the message was last edited in Unix - time. Converted to :class:`datetime.datetime`. - media_group_id (:obj:`str`, optional): The unique identifier of a media message group this - message belongs to. - text (str, optional): For text messages, the actual UTF-8 text of the message, 0-4096 - characters. Also found as :attr:`telegram.constants.MAX_MESSAGE_LENGTH`. - entities (List[:class:`telegram.MessageEntity`], optional): For text messages, special - entities like usernames, URLs, bot commands, etc. that appear in the text. See - :attr:`parse_entity` and :attr:`parse_entities` methods for how to use properly. - caption_entities (List[:class:`telegram.MessageEntity`]): Optional. For Messages with a - Caption. Special entities like usernames, URLs, bot commands, etc. that appear in the - caption. See :attr:`Message.parse_caption_entity` and :attr:`parse_caption_entities` - methods for how to use properly. - audio (:class:`telegram.Audio`, optional): Message is an audio file, information - about the file. - document (:class:`telegram.Document`, optional): Message is a general file, information - about the file. - animation (:class:`telegram.Animation`, optional): Message is an animation, information - about the animation. For backward compatibility, when this field is set, the document - field will also be set. - game (:class:`telegram.Game`, optional): Message is a game, information about the game. - photo (List[:class:`telegram.PhotoSize`], optional): Message is a photo, available - sizes of the photo. - sticker (:class:`telegram.Sticker`, optional): Message is a sticker, information - about the sticker. - video (:class:`telegram.Video`, optional): Message is a video, information about the video. - voice (:class:`telegram.Voice`, optional): Message is a voice message, information about - the file. - video_note (:class:`telegram.VideoNote`, optional): Message is a video note, information - about the video message. - new_chat_members (List[:class:`telegram.User`], optional): New members that were added to - the group or supergroup and information about them (the bot itself may be one of these - members). - caption (:obj:`str`, optional): Caption for the animation, audio, document, photo, video - or voice, 0-1024 characters. - contact (:class:`telegram.Contact`, optional): Message is a shared contact, information - about the contact. - location (:class:`telegram.Location`, optional): Message is a shared location, information - about the location. - venue (:class:`telegram.Venue`, optional): Message is a venue, information about the venue. - For backward compatibility, when this field is set, the location field will also be - set. - left_chat_member (:class:`telegram.User`, optional): A member was removed from the group, - information about them (this member may be the bot itself). - new_chat_title (:obj:`str`, optional): A chat title was changed to this value. - new_chat_photo (List[:class:`telegram.PhotoSize`], optional): A chat photo was changed to - this value. - delete_chat_photo (:obj:`bool`, optional): Service message: The chat photo was deleted. - group_chat_created (:obj:`bool`, optional): Service message: The group has been created. - supergroup_chat_created (:obj:`bool`, optional): Service message: The supergroup has been - created. This field can't be received in a message coming through updates, because bot - can't be a member of a supergroup when it is created. It can only be found in - :attr:`reply_to_message` if someone replies to a very first message in a directly - created supergroup. - channel_chat_created (:obj:`bool`, optional): Service message: The channel has been - created. This field can't be received in a message coming through updates, because bot - can't be a member of a channel when it is created. It can only be found in - :attr:`reply_to_message` if someone replies to a very first message in a channel. - message_auto_delete_timer_changed (:class:`telegram.MessageAutoDeleteTimerChanged`, \ - optional): Service message: auto-delete timer settings changed in the chat. - - .. versionadded:: 13.4 - migrate_to_chat_id (:obj:`int`, optional): The group has been migrated to a supergroup with - the specified identifier. This number may be greater than 32 bits and some programming - languages may have difficulty/silent defects in interpreting it. But it is smaller than - 52 bits, so a signed 64 bit integer or double-precision float type are safe for storing - this identifier. - migrate_from_chat_id (:obj:`int`, optional): The supergroup has been migrated from a group - with the specified identifier. This number may be greater than 32 bits and some - programming languages may have difficulty/silent defects in interpreting it. But it is - smaller than 52 bits, so a signed 64 bit integer or double-precision float type are - safe for storing this identifier. - pinned_message (:class:`telegram.Message`, optional): Specified message was pinned. Note - that the Message object in this field will not contain further :attr:`reply_to_message` - fields even if it is itself a reply. - invoice (:class:`telegram.Invoice`, optional): Message is an invoice for a payment, - information about the invoice. - successful_payment (:class:`telegram.SuccessfulPayment`, optional): Message is a service - message about a successful payment, information about the payment. - connected_website (:obj:`str`, optional): The domain name of the website on which the user - has logged in. - forward_signature (:obj:`str`, optional): For messages forwarded from channels, signature - of the post author if present. - author_signature (:obj:`str`, optional): Signature of the post author for messages in - channels, or the custom title of an anonymous group administrator. - passport_data (:class:`telegram.PassportData`, optional): Telegram Passport data. - poll (:class:`telegram.Poll`, optional): Message is a native poll, - information about the poll. - dice (:class:`telegram.Dice`, optional): Message is a dice with random value from 1 to 6. - via_bot (:class:`telegram.User`, optional): Message was sent through an inline bot. - proximity_alert_triggered (:class:`telegram.ProximityAlertTriggered`, optional): Service - message. A user in the chat triggered another user's proximity alert while sharing - Live Location. - voice_chat_scheduled (:class:`telegram.VoiceChatScheduled`, optional): Service message: - voice chat scheduled. - - .. versionadded:: 13.5 - voice_chat_started (:class:`telegram.VoiceChatStarted`, optional): Service message: voice - chat started. - - .. versionadded:: 13.4 - voice_chat_ended (:class:`telegram.VoiceChatEnded`, optional): Service message: voice chat - ended. - - .. versionadded:: 13.4 - voice_chat_participants_invited (:class:`telegram.VoiceChatParticipantsInvited` optional): - Service message: new participants invited to a voice chat. - - .. versionadded:: 13.4 - reply_markup (:class:`telegram.InlineKeyboardMarkup`, optional): Inline keyboard attached - to the message. ``login_url`` buttons are represented as ordinary url buttons. - bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods. - - Attributes: - message_id (:obj:`int`): Unique message identifier inside this chat. - from_user (:class:`telegram.User`): Optional. Sender. - sender_chat (:class:`telegram.Chat`): Optional. Sender of the message, sent on behalf of a - chat. The channel itself for channel messages. The supergroup itself for messages from - anonymous group administrators. The linked channel for messages automatically forwarded - to the discussion group. - date (:class:`datetime.datetime`): Date the message was sent. - chat (:class:`telegram.Chat`): Conversation the message belongs to. - forward_from (:class:`telegram.User`): Optional. Sender of the original message. - forward_from_chat (:class:`telegram.Chat`): Optional. For messages forwarded from channels - or from anonymous administrators, information about the original sender chat. - forward_from_message_id (:obj:`int`): Optional. Identifier of the original message in the - channel. - forward_date (:class:`datetime.datetime`): Optional. Date the original message was sent. - reply_to_message (:class:`telegram.Message`): Optional. For replies, the original message. - Note that the Message object in this field will not contain further - ``reply_to_message`` fields even if it itself is a reply. - edit_date (:class:`datetime.datetime`): Optional. Date the message was last edited. - media_group_id (:obj:`str`): Optional. The unique identifier of a media message group this - message belongs to. - text (:obj:`str`): Optional. The actual UTF-8 text of the message. - entities (List[:class:`telegram.MessageEntity`]): Optional. Special entities like - usernames, URLs, bot commands, etc. that appear in the text. See - :attr:`Message.parse_entity` and :attr:`parse_entities` methods for how to use - properly. - caption_entities (List[:class:`telegram.MessageEntity`]): Optional. Special entities like - usernames, URLs, bot commands, etc. that appear in the caption. See - :attr:`Message.parse_caption_entity` and :attr:`parse_caption_entities` methods for how - to use properly. - audio (:class:`telegram.Audio`): Optional. Information about the file. - document (:class:`telegram.Document`): Optional. Information about the file. - animation (:class:`telegram.Animation`) Optional. Information about the file. - For backward compatibility, when this field is set, the document field will also be - set. - game (:class:`telegram.Game`): Optional. Information about the game. - photo (List[:class:`telegram.PhotoSize`]): Optional. Available sizes of the photo. - sticker (:class:`telegram.Sticker`): Optional. Information about the sticker. - video (:class:`telegram.Video`): Optional. Information about the video. - voice (:class:`telegram.Voice`): Optional. Information about the file. - video_note (:class:`telegram.VideoNote`): Optional. Information about the video message. - new_chat_members (List[:class:`telegram.User`]): Optional. Information about new members to - the chat. (the bot itself may be one of these members). - caption (:obj:`str`): Optional. Caption for the document, photo or video, 0-1024 - characters. - contact (:class:`telegram.Contact`): Optional. Information about the contact. - location (:class:`telegram.Location`): Optional. Information about the location. - venue (:class:`telegram.Venue`): Optional. Information about the venue. - left_chat_member (:class:`telegram.User`): Optional. Information about the user that left - the group. (this member may be the bot itself). - new_chat_title (:obj:`str`): Optional. A chat title was changed to this value. - new_chat_photo (List[:class:`telegram.PhotoSize`]): Optional. A chat photo was changed to - this value. - delete_chat_photo (:obj:`bool`): Optional. The chat photo was deleted. - group_chat_created (:obj:`bool`): Optional. The group has been created. - supergroup_chat_created (:obj:`bool`): Optional. The supergroup has been created. - channel_chat_created (:obj:`bool`): Optional. The channel has been created. - message_auto_delete_timer_changed (:class:`telegram.MessageAutoDeleteTimerChanged`): - Optional. Service message: auto-delete timer settings changed in the chat. - - .. versionadded:: 13.4 - migrate_to_chat_id (:obj:`int`): Optional. The group has been migrated to a supergroup with - the specified identifier. - migrate_from_chat_id (:obj:`int`): Optional. The supergroup has been migrated from a group - with the specified identifier. - pinned_message (:class:`telegram.message`): Optional. Specified message was pinned. - invoice (:class:`telegram.Invoice`): Optional. Information about the invoice. - successful_payment (:class:`telegram.SuccessfulPayment`): Optional. Information about the - payment. - connected_website (:obj:`str`): Optional. The domain name of the website on which the user - has logged in. - forward_signature (:obj:`str`): Optional. Signature of the post author for messages - forwarded from channels. - forward_sender_name (:obj:`str`): Optional. Sender's name for messages forwarded from users - who disallow adding a link to their account in forwarded messages. - author_signature (:obj:`str`): Optional. Signature of the post author for messages in - channels, or the custom title of an anonymous group administrator. - passport_data (:class:`telegram.PassportData`): Optional. Telegram Passport data. - poll (:class:`telegram.Poll`): Optional. Message is a native poll, - information about the poll. - dice (:class:`telegram.Dice`): Optional. Message is a dice. - via_bot (:class:`telegram.User`): Optional. Bot through which the message was sent. - proximity_alert_triggered (:class:`telegram.ProximityAlertTriggered`): Optional. Service - message. A user in the chat triggered another user's proximity alert while sharing - Live Location. - voice_chat_scheduled (:class:`telegram.VoiceChatScheduled`): Optional. Service message: - voice chat scheduled. - - .. versionadded:: 13.5 - voice_chat_started (:class:`telegram.VoiceChatStarted`): Optional. Service message: voice - chat started. - - .. versionadded:: 13.4 - voice_chat_ended (:class:`telegram.VoiceChatEnded`): Optional. Service message: voice chat - ended. - - .. versionadded:: 13.4 - voice_chat_participants_invited (:class:`telegram.VoiceChatParticipantsInvited`): Optional. - Service message: new participants invited to a voice chat. - - .. versionadded:: 13.4 - reply_markup (:class:`telegram.InlineKeyboardMarkup`): Optional. Inline keyboard attached - to the message. - bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods. - - """ - - # fmt: on - __slots__ = ( - 'reply_markup', - 'audio', - 'contact', - 'migrate_to_chat_id', - 'forward_signature', - 'chat', - 'successful_payment', - 'game', - 'text', - 'forward_sender_name', - 'document', - 'new_chat_title', - 'forward_date', - 'group_chat_created', - 'media_group_id', - 'caption', - 'video', - 'bot', - 'entities', - 'via_bot', - 'new_chat_members', - 'connected_website', - 'animation', - 'migrate_from_chat_id', - 'forward_from', - 'sticker', - 'location', - 'venue', - 'edit_date', - 'reply_to_message', - 'passport_data', - 'pinned_message', - 'forward_from_chat', - 'new_chat_photo', - 'message_id', - 'delete_chat_photo', - 'from_user', - 'author_signature', - 'proximity_alert_triggered', - 'sender_chat', - 'dice', - 'forward_from_message_id', - 'caption_entities', - 'voice', - 'date', - 'supergroup_chat_created', - 'poll', - 'left_chat_member', - 'photo', - 'channel_chat_created', - 'invoice', - 'video_note', - '_effective_attachment', - 'message_auto_delete_timer_changed', - 'voice_chat_ended', - 'voice_chat_participants_invited', - 'voice_chat_started', - 'voice_chat_scheduled', - '_id_attrs', - ) - - ATTACHMENT_TYPES: ClassVar[List[str]] = [ - 'audio', - 'game', - 'animation', - 'document', - 'photo', - 'sticker', - 'video', - 'voice', - 'video_note', - 'contact', - 'location', - 'venue', - 'invoice', - 'successful_payment', - ] - MESSAGE_TYPES: ClassVar[List[str]] = [ - 'text', - 'new_chat_members', - 'left_chat_member', - 'new_chat_title', - 'new_chat_photo', - 'delete_chat_photo', - 'group_chat_created', - 'supergroup_chat_created', - 'channel_chat_created', - 'message_auto_delete_timer_changed', - 'migrate_to_chat_id', - 'migrate_from_chat_id', - 'pinned_message', - 'poll', - 'dice', - 'passport_data', - 'proximity_alert_triggered', - 'voice_chat_scheduled', - 'voice_chat_started', - 'voice_chat_ended', - 'voice_chat_participants_invited', - ] + ATTACHMENT_TYPES - - def __init__( - self, - message_id: int, - date: datetime.datetime, - chat: Chat, - from_user: User = None, - forward_from: User = None, - forward_from_chat: Chat = None, - forward_from_message_id: int = None, - forward_date: datetime.datetime = None, - reply_to_message: 'Message' = None, - edit_date: datetime.datetime = None, - text: str = None, - entities: List['MessageEntity'] = None, - caption_entities: List['MessageEntity'] = None, - audio: Audio = None, - document: Document = None, - game: Game = None, - photo: List[PhotoSize] = None, - sticker: Sticker = None, - video: Video = None, - voice: Voice = None, - video_note: VideoNote = None, - new_chat_members: List[User] = None, - caption: str = None, - contact: Contact = None, - location: Location = None, - venue: Venue = None, - left_chat_member: User = None, - new_chat_title: str = None, - new_chat_photo: List[PhotoSize] = None, - delete_chat_photo: bool = False, - group_chat_created: bool = False, - supergroup_chat_created: bool = False, - channel_chat_created: bool = False, - migrate_to_chat_id: int = None, - migrate_from_chat_id: int = None, - pinned_message: 'Message' = None, - invoice: Invoice = None, - successful_payment: SuccessfulPayment = None, - forward_signature: str = None, - author_signature: str = None, - media_group_id: str = None, - connected_website: str = None, - animation: Animation = None, - passport_data: PassportData = None, - poll: Poll = None, - forward_sender_name: str = None, - reply_markup: InlineKeyboardMarkup = None, - bot: 'Bot' = None, - dice: Dice = None, - via_bot: User = None, - proximity_alert_triggered: ProximityAlertTriggered = None, - sender_chat: Chat = None, - voice_chat_started: VoiceChatStarted = None, - voice_chat_ended: VoiceChatEnded = None, - voice_chat_participants_invited: VoiceChatParticipantsInvited = None, - message_auto_delete_timer_changed: MessageAutoDeleteTimerChanged = None, - voice_chat_scheduled: VoiceChatScheduled = None, - **_kwargs: Any, - ): - # Required - self.message_id = int(message_id) - # Optionals - self.from_user = from_user - self.sender_chat = sender_chat - self.date = date - self.chat = chat - self.forward_from = forward_from - self.forward_from_chat = forward_from_chat - self.forward_date = forward_date - self.reply_to_message = reply_to_message - self.edit_date = edit_date - self.text = text - self.entities = entities or [] - self.caption_entities = caption_entities or [] - self.audio = audio - self.game = game - self.document = document - self.photo = photo or [] - self.sticker = sticker - self.video = video - self.voice = voice - self.video_note = video_note - self.caption = caption - self.contact = contact - self.location = location - self.venue = venue - self.new_chat_members = new_chat_members or [] - self.left_chat_member = left_chat_member - self.new_chat_title = new_chat_title - self.new_chat_photo = new_chat_photo or [] - self.delete_chat_photo = bool(delete_chat_photo) - self.group_chat_created = bool(group_chat_created) - self.supergroup_chat_created = bool(supergroup_chat_created) - self.migrate_to_chat_id = migrate_to_chat_id - self.migrate_from_chat_id = migrate_from_chat_id - self.channel_chat_created = bool(channel_chat_created) - self.message_auto_delete_timer_changed = message_auto_delete_timer_changed - self.pinned_message = pinned_message - self.forward_from_message_id = forward_from_message_id - self.invoice = invoice - self.successful_payment = successful_payment - self.connected_website = connected_website - self.forward_signature = forward_signature - self.forward_sender_name = forward_sender_name - self.author_signature = author_signature - self.media_group_id = media_group_id - self.animation = animation - self.passport_data = passport_data - self.poll = poll - self.dice = dice - self.via_bot = via_bot - self.proximity_alert_triggered = proximity_alert_triggered - self.voice_chat_scheduled = voice_chat_scheduled - self.voice_chat_started = voice_chat_started - self.voice_chat_ended = voice_chat_ended - self.voice_chat_participants_invited = voice_chat_participants_invited - self.reply_markup = reply_markup - self.bot = bot - - self._effective_attachment = DEFAULT_NONE - - self._id_attrs = (self.message_id, self.chat) - - @property - def chat_id(self) -> int: - """:obj:`int`: Shortcut for :attr:`telegram.Chat.id` for :attr:`chat`.""" - return self.chat.id - - @property - def link(self) -> Optional[str]: - """:obj:`str`: Convenience property. If the chat of the message is not - a private chat or normal group, returns a t.me link of the message. - """ - if self.chat.type not in [Chat.PRIVATE, Chat.GROUP]: - if self.chat.username: - to_link = self.chat.username - else: - # Get rid of leading -100 for supergroups - to_link = f"c/{str(self.chat.id)[4:]}" - return f"https://t.me/{to_link}/{self.message_id}" - return None - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Message']: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data['from_user'] = User.de_json(data.get('from'), bot) - data['sender_chat'] = Chat.de_json(data.get('sender_chat'), bot) - data['date'] = from_timestamp(data['date']) - data['chat'] = Chat.de_json(data.get('chat'), bot) - data['entities'] = MessageEntity.de_list(data.get('entities'), bot) - data['caption_entities'] = MessageEntity.de_list(data.get('caption_entities'), bot) - data['forward_from'] = User.de_json(data.get('forward_from'), bot) - data['forward_from_chat'] = Chat.de_json(data.get('forward_from_chat'), bot) - data['forward_date'] = from_timestamp(data.get('forward_date')) - data['reply_to_message'] = Message.de_json(data.get('reply_to_message'), bot) - data['edit_date'] = from_timestamp(data.get('edit_date')) - data['audio'] = Audio.de_json(data.get('audio'), bot) - data['document'] = Document.de_json(data.get('document'), bot) - data['animation'] = Animation.de_json(data.get('animation'), bot) - data['game'] = Game.de_json(data.get('game'), bot) - data['photo'] = PhotoSize.de_list(data.get('photo'), bot) - data['sticker'] = Sticker.de_json(data.get('sticker'), bot) - data['video'] = Video.de_json(data.get('video'), bot) - data['voice'] = Voice.de_json(data.get('voice'), bot) - data['video_note'] = VideoNote.de_json(data.get('video_note'), bot) - data['contact'] = Contact.de_json(data.get('contact'), bot) - data['location'] = Location.de_json(data.get('location'), bot) - data['venue'] = Venue.de_json(data.get('venue'), bot) - data['new_chat_members'] = User.de_list(data.get('new_chat_members'), bot) - data['left_chat_member'] = User.de_json(data.get('left_chat_member'), bot) - data['new_chat_photo'] = PhotoSize.de_list(data.get('new_chat_photo'), bot) - data['message_auto_delete_timer_changed'] = MessageAutoDeleteTimerChanged.de_json( - data.get('message_auto_delete_timer_changed'), bot - ) - data['pinned_message'] = Message.de_json(data.get('pinned_message'), bot) - data['invoice'] = Invoice.de_json(data.get('invoice'), bot) - data['successful_payment'] = SuccessfulPayment.de_json(data.get('successful_payment'), bot) - data['passport_data'] = PassportData.de_json(data.get('passport_data'), bot) - data['poll'] = Poll.de_json(data.get('poll'), bot) - data['dice'] = Dice.de_json(data.get('dice'), bot) - data['via_bot'] = User.de_json(data.get('via_bot'), bot) - data['proximity_alert_triggered'] = ProximityAlertTriggered.de_json( - data.get('proximity_alert_triggered'), bot - ) - data['reply_markup'] = InlineKeyboardMarkup.de_json(data.get('reply_markup'), bot) - data['voice_chat_scheduled'] = VoiceChatScheduled.de_json( - data.get('voice_chat_scheduled'), bot - ) - data['voice_chat_started'] = VoiceChatStarted.de_json(data.get('voice_chat_started'), bot) - data['voice_chat_ended'] = VoiceChatEnded.de_json(data.get('voice_chat_ended'), bot) - data['voice_chat_participants_invited'] = VoiceChatParticipantsInvited.de_json( - data.get('voice_chat_participants_invited'), bot - ) - return cls(bot=bot, **data) - - @property - def effective_attachment( - self, - ) -> Union[ - Contact, - Document, - Animation, - Game, - Invoice, - Location, - List[PhotoSize], - Sticker, - SuccessfulPayment, - Venue, - Video, - VideoNote, - Voice, - None, - ]: - """ - :class:`telegram.Audio` - or :class:`telegram.Contact` - or :class:`telegram.Document` - or :class:`telegram.Animation` - or :class:`telegram.Game` - or :class:`telegram.Invoice` - or :class:`telegram.Location` - or List[:class:`telegram.PhotoSize`] - or :class:`telegram.Sticker` - or :class:`telegram.SuccessfulPayment` - or :class:`telegram.Venue` - or :class:`telegram.Video` - or :class:`telegram.VideoNote` - or :class:`telegram.Voice`: The attachment that this message was sent with. May be - :obj:`None` if no attachment was sent. - - """ - if self._effective_attachment is not DEFAULT_NONE: - return self._effective_attachment # type: ignore - - for i in Message.ATTACHMENT_TYPES: - if getattr(self, i, None): - self._effective_attachment = getattr(self, i) - break - else: - self._effective_attachment = None - - return self._effective_attachment # type: ignore - - def __getitem__(self, item: str) -> Any: # pylint: disable=R1710 - return self.chat.id if item == 'chat_id' else super().__getitem__(item) - - def to_dict(self) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict() - - # Required - data['date'] = to_timestamp(self.date) - # Optionals - if self.forward_date: - data['forward_date'] = to_timestamp(self.forward_date) - if self.edit_date: - data['edit_date'] = to_timestamp(self.edit_date) - if self.photo: - data['photo'] = [p.to_dict() for p in self.photo] - if self.entities: - data['entities'] = [e.to_dict() for e in self.entities] - if self.caption_entities: - data['caption_entities'] = [e.to_dict() for e in self.caption_entities] - if self.new_chat_photo: - data['new_chat_photo'] = [p.to_dict() for p in self.new_chat_photo] - if self.new_chat_members: - data['new_chat_members'] = [u.to_dict() for u in self.new_chat_members] - - return data - - def _quote(self, quote: Optional[bool], reply_to_message_id: Optional[int]) -> Optional[int]: - """Modify kwargs for replying with or without quoting.""" - if reply_to_message_id is not None: - return reply_to_message_id - - if quote is not None: - if quote: - return self.message_id - - else: - if self.bot.defaults: - default_quote = self.bot.defaults.quote - else: - default_quote = None - if (default_quote is None and self.chat.type != Chat.PRIVATE) or default_quote: - return self.message_id - - return None - - def reply_text( - self, - text: str, - parse_mode: ODVInput[str] = DEFAULT_NONE, - disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: ReplyMarkup = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - quote: bool = None, - ) -> 'Message': - """Shortcut for:: - - bot.send_message(update.effective_message.chat_id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_message`. - - Args: - quote (:obj:`bool`, optional): If set to :obj:`True`, the message is sent as an actual - reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this - parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` in - private chats. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - reply_to_message_id = self._quote(quote, reply_to_message_id) - return self.bot.send_message( - chat_id=self.chat_id, - text=text, - parse_mode=parse_mode, - disable_web_page_preview=disable_web_page_preview, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - entities=entities, - ) - - def reply_markdown( - self, - text: str, - disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: ReplyMarkup = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - quote: bool = None, - ) -> 'Message': - """Shortcut for:: - - bot.send_message( - update.effective_message.chat_id, - parse_mode=ParseMode.MARKDOWN, - *args, - **kwargs, - ) - - Sends a message with Markdown version 1 formatting. - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_message`. - - Note: - :attr:`telegram.ParseMode.MARKDOWN` is a legacy mode, retained by Telegram for - backward compatibility. You should use :meth:`reply_markdown_v2` instead. - - Args: - quote (:obj:`bool`, optional): If set to :obj:`True`, the message is sent as an actual - reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this - parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` in - private chats. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - """ - reply_to_message_id = self._quote(quote, reply_to_message_id) - return self.bot.send_message( - chat_id=self.chat_id, - text=text, - parse_mode=ParseMode.MARKDOWN, - disable_web_page_preview=disable_web_page_preview, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - entities=entities, - ) - - def reply_markdown_v2( - self, - text: str, - disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: ReplyMarkup = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - quote: bool = None, - ) -> 'Message': - """Shortcut for:: - - bot.send_message( - update.effective_message.chat_id, - parse_mode=ParseMode.MARKDOWN_V2, - *args, - **kwargs, - ) - - Sends a message with markdown version 2 formatting. - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_message`. - - Args: - quote (:obj:`bool`, optional): If set to :obj:`True`, the message is sent as an actual - reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this - parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` in - private chats. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - """ - reply_to_message_id = self._quote(quote, reply_to_message_id) - return self.bot.send_message( - chat_id=self.chat_id, - text=text, - parse_mode=ParseMode.MARKDOWN_V2, - disable_web_page_preview=disable_web_page_preview, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - entities=entities, - ) - - def reply_html( - self, - text: str, - disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: ReplyMarkup = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - quote: bool = None, - ) -> 'Message': - """Shortcut for:: - - bot.send_message( - update.effective_message.chat_id, - parse_mode=ParseMode.HTML, - *args, - **kwargs, - ) - - Sends a message with HTML formatting. - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_message`. - - Args: - quote (:obj:`bool`, optional): If set to :obj:`True`, the message is sent as an actual - reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this - parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` in - private chats. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - """ - reply_to_message_id = self._quote(quote, reply_to_message_id) - return self.bot.send_message( - chat_id=self.chat_id, - text=text, - parse_mode=ParseMode.HTML, - disable_web_page_preview=disable_web_page_preview, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - entities=entities, - ) - - def reply_media_group( - self, - media: List[ - Union['InputMediaAudio', 'InputMediaDocument', 'InputMediaPhoto', 'InputMediaVideo'] - ], - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - timeout: DVInput[float] = DEFAULT_20, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - quote: bool = None, - ) -> List['Message']: - """Shortcut for:: - - bot.send_media_group(update.effective_message.chat_id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_media_group`. - - Args: - quote (:obj:`bool`, optional): If set to :obj:`True`, the media group is sent as an - actual reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, - this parameter will be ignored. Default: :obj:`True` in group chats and - :obj:`False` in private chats. - - Returns: - List[:class:`telegram.Message`]: An array of the sent Messages. - - Raises: - :class:`telegram.error.TelegramError` - """ - reply_to_message_id = self._quote(quote, reply_to_message_id) - return self.bot.send_media_group( - chat_id=self.chat_id, - media=media, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - timeout=timeout, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - ) - - def reply_photo( - self, - photo: Union[FileInput, 'PhotoSize'], - caption: str = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: ReplyMarkup = None, - timeout: DVInput[float] = DEFAULT_20, - parse_mode: ODVInput[str] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - filename: str = None, - quote: bool = None, - ) -> 'Message': - """Shortcut for:: - - bot.send_photo(update.effective_message.chat_id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_photo`. - - Args: - quote (:obj:`bool`, optional): If set to :obj:`True`, the photo is sent as an actual - reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, - this parameter will be ignored. Default: :obj:`True` in group chats and - :obj:`False` in private chats. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - reply_to_message_id = self._quote(quote, reply_to_message_id) - return self.bot.send_photo( - chat_id=self.chat_id, - photo=photo, - caption=caption, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - parse_mode=parse_mode, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - filename=filename, - ) - - def reply_audio( - self, - audio: Union[FileInput, 'Audio'], - duration: int = None, - performer: str = None, - title: str = None, - caption: str = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: ReplyMarkup = None, - timeout: DVInput[float] = DEFAULT_20, - parse_mode: ODVInput[str] = DEFAULT_NONE, - thumb: FileInput = None, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - filename: str = None, - quote: bool = None, - ) -> 'Message': - """Shortcut for:: - - bot.send_audio(update.effective_message.chat_id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_audio`. - - Args: - quote (:obj:`bool`, optional): If set to :obj:`True`, the audio is sent as an actual - reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, - this parameter will be ignored. Default: :obj:`True` in group chats and - :obj:`False` in private chats. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - reply_to_message_id = self._quote(quote, reply_to_message_id) - return self.bot.send_audio( - chat_id=self.chat_id, - audio=audio, - duration=duration, - performer=performer, - title=title, - caption=caption, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - parse_mode=parse_mode, - thumb=thumb, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - filename=filename, - ) - - def reply_document( - self, - document: Union[FileInput, 'Document'], - filename: str = None, - caption: str = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: ReplyMarkup = None, - timeout: DVInput[float] = DEFAULT_20, - parse_mode: ODVInput[str] = DEFAULT_NONE, - thumb: FileInput = None, - api_kwargs: JSONDict = None, - disable_content_type_detection: bool = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - quote: bool = None, - ) -> 'Message': - """Shortcut for:: - - bot.send_document(update.effective_message.chat_id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_document`. - - Args: - quote (:obj:`bool`, optional): If set to :obj:`True`, the document is sent as an actual - reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this - parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` in - private chats. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - reply_to_message_id = self._quote(quote, reply_to_message_id) - return self.bot.send_document( - chat_id=self.chat_id, - document=document, - filename=filename, - caption=caption, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - parse_mode=parse_mode, - thumb=thumb, - api_kwargs=api_kwargs, - disable_content_type_detection=disable_content_type_detection, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - ) - - def reply_animation( - self, - animation: Union[FileInput, 'Animation'], - duration: int = None, - width: int = None, - height: int = None, - thumb: FileInput = None, - caption: str = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: ReplyMarkup = None, - timeout: DVInput[float] = DEFAULT_20, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - filename: str = None, - quote: bool = None, - ) -> 'Message': - """Shortcut for:: - - bot.send_animation(update.effective_message.chat_id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_animation`. - - Args: - quote (:obj:`bool`, optional): If set to :obj:`True`, the animation is sent as an - actual reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, - this parameter will be ignored. Default: :obj:`True` in group chats and - :obj:`False` in private chats. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - reply_to_message_id = self._quote(quote, reply_to_message_id) - return self.bot.send_animation( - chat_id=self.chat_id, - animation=animation, - duration=duration, - width=width, - height=height, - thumb=thumb, - caption=caption, - parse_mode=parse_mode, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - filename=filename, - ) - - def reply_sticker( - self, - sticker: Union[FileInput, 'Sticker'], - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: ReplyMarkup = None, - timeout: DVInput[float] = DEFAULT_20, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - quote: bool = None, - ) -> 'Message': - """Shortcut for:: - - bot.send_sticker(update.effective_message.chat_id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_sticker`. - - Args: - quote (:obj:`bool`, optional): If set to :obj:`True`, the sticker is sent as an actual - reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this - parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` in - private chats. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - reply_to_message_id = self._quote(quote, reply_to_message_id) - return self.bot.send_sticker( - chat_id=self.chat_id, - sticker=sticker, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - ) - - def reply_video( - self, - video: Union[FileInput, 'Video'], - duration: int = None, - caption: str = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: ReplyMarkup = None, - timeout: DVInput[float] = DEFAULT_20, - width: int = None, - height: int = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - supports_streaming: bool = None, - thumb: FileInput = None, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - filename: str = None, - quote: bool = None, - ) -> 'Message': - """Shortcut for:: - - bot.send_video(update.effective_message.chat_id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_video`. - - Args: - quote (:obj:`bool`, optional): If set to :obj:`True`, the video is sent as an actual - reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this - parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` in - private chats. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - reply_to_message_id = self._quote(quote, reply_to_message_id) - return self.bot.send_video( - chat_id=self.chat_id, - video=video, - duration=duration, - caption=caption, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - width=width, - height=height, - parse_mode=parse_mode, - supports_streaming=supports_streaming, - thumb=thumb, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - filename=filename, - ) - - def reply_video_note( - self, - video_note: Union[FileInput, 'VideoNote'], - duration: int = None, - length: int = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: ReplyMarkup = None, - timeout: DVInput[float] = DEFAULT_20, - thumb: FileInput = None, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - filename: str = None, - quote: bool = None, - ) -> 'Message': - """Shortcut for:: - - bot.send_video_note(update.effective_message.chat_id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_video_note`. - - Args: - quote (:obj:`bool`, optional): If set to :obj:`True`, the video note is sent as an - actual reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, - this parameter will be ignored. Default: :obj:`True` in group chats and - :obj:`False` in private chats. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - reply_to_message_id = self._quote(quote, reply_to_message_id) - return self.bot.send_video_note( - chat_id=self.chat_id, - video_note=video_note, - duration=duration, - length=length, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - thumb=thumb, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - filename=filename, - ) - - def reply_voice( - self, - voice: Union[FileInput, 'Voice'], - duration: int = None, - caption: str = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: ReplyMarkup = None, - timeout: DVInput[float] = DEFAULT_20, - parse_mode: ODVInput[str] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - filename: str = None, - quote: bool = None, - ) -> 'Message': - """Shortcut for:: - - bot.send_voice(update.effective_message.chat_id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_voice`. - - Args: - quote (:obj:`bool`, optional): If set to :obj:`True`, the voice note is sent as an - actual reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, - this parameter will be ignored. Default: :obj:`True` in group chats and - :obj:`False` in private chats. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - reply_to_message_id = self._quote(quote, reply_to_message_id) - return self.bot.send_voice( - chat_id=self.chat_id, - voice=voice, - duration=duration, - caption=caption, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - parse_mode=parse_mode, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - filename=filename, - ) - - def reply_location( - self, - latitude: float = None, - longitude: float = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: ReplyMarkup = None, - timeout: ODVInput[float] = DEFAULT_NONE, - location: Location = None, - live_period: int = None, - api_kwargs: JSONDict = None, - horizontal_accuracy: float = None, - heading: int = None, - proximity_alert_radius: int = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - quote: bool = None, - ) -> 'Message': - """Shortcut for:: - - bot.send_location(update.effective_message.chat_id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_location`. - - Args: - quote (:obj:`bool`, optional): If set to :obj:`True`, the location is sent as an actual - reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this - parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` in - private chats. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - reply_to_message_id = self._quote(quote, reply_to_message_id) - return self.bot.send_location( - chat_id=self.chat_id, - latitude=latitude, - longitude=longitude, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - location=location, - live_period=live_period, - api_kwargs=api_kwargs, - horizontal_accuracy=horizontal_accuracy, - heading=heading, - proximity_alert_radius=proximity_alert_radius, - allow_sending_without_reply=allow_sending_without_reply, - ) - - def reply_venue( - self, - latitude: float = None, - longitude: float = None, - title: str = None, - address: str = None, - foursquare_id: str = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: ReplyMarkup = None, - timeout: ODVInput[float] = DEFAULT_NONE, - venue: Venue = None, - foursquare_type: str = None, - api_kwargs: JSONDict = None, - google_place_id: str = None, - google_place_type: str = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - quote: bool = None, - ) -> 'Message': - """Shortcut for:: - - bot.send_venue(update.effective_message.chat_id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_venue`. - - Args: - quote (:obj:`bool`, optional): If set to :obj:`True`, the venue is sent as an actual - reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this - parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` in - private chats. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - reply_to_message_id = self._quote(quote, reply_to_message_id) - return self.bot.send_venue( - chat_id=self.chat_id, - latitude=latitude, - longitude=longitude, - title=title, - address=address, - foursquare_id=foursquare_id, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - venue=venue, - foursquare_type=foursquare_type, - api_kwargs=api_kwargs, - google_place_id=google_place_id, - google_place_type=google_place_type, - allow_sending_without_reply=allow_sending_without_reply, - ) - - def reply_contact( - self, - phone_number: str = None, - first_name: str = None, - last_name: str = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: ReplyMarkup = None, - timeout: ODVInput[float] = DEFAULT_NONE, - contact: Contact = None, - vcard: str = None, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - quote: bool = None, - ) -> 'Message': - """Shortcut for:: - - bot.send_contact(update.effective_message.chat_id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_contact`. - - Args: - quote (:obj:`bool`, optional): If set to :obj:`True`, the contact is sent as an actual - reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this - parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` in - private chats. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - reply_to_message_id = self._quote(quote, reply_to_message_id) - return self.bot.send_contact( - chat_id=self.chat_id, - phone_number=phone_number, - first_name=first_name, - last_name=last_name, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - contact=contact, - vcard=vcard, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - ) - - def reply_poll( - self, - question: str, - options: List[str], - is_anonymous: bool = True, - type: str = Poll.REGULAR, # pylint: disable=W0622 - allows_multiple_answers: bool = False, - correct_option_id: int = None, - is_closed: bool = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: ReplyMarkup = None, - timeout: ODVInput[float] = DEFAULT_NONE, - explanation: str = None, - explanation_parse_mode: ODVInput[str] = DEFAULT_NONE, - open_period: int = None, - close_date: Union[int, datetime.datetime] = None, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - explanation_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - quote: bool = None, - ) -> 'Message': - """Shortcut for:: - - bot.send_poll(update.effective_message.chat_id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_poll`. - - Args: - quote (:obj:`bool`, optional): If set to :obj:`True`, the poll is sent as an actual - reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, - this parameter will be ignored. Default: :obj:`True` in group chats and - :obj:`False` in private chats. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - reply_to_message_id = self._quote(quote, reply_to_message_id) - return self.bot.send_poll( - chat_id=self.chat_id, - question=question, - options=options, - is_anonymous=is_anonymous, - type=type, - allows_multiple_answers=allows_multiple_answers, - correct_option_id=correct_option_id, - is_closed=is_closed, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - explanation=explanation, - explanation_parse_mode=explanation_parse_mode, - open_period=open_period, - close_date=close_date, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - explanation_entities=explanation_entities, - ) - - def reply_dice( - self, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: ReplyMarkup = None, - timeout: ODVInput[float] = DEFAULT_NONE, - emoji: str = None, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - quote: bool = None, - ) -> 'Message': - """Shortcut for:: - - bot.send_dice(update.effective_message.chat_id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_dice`. - - Args: - quote (:obj:`bool`, optional): If set to :obj:`True`, the dice is sent as an actual - reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this - parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` - in private chats. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - reply_to_message_id = self._quote(quote, reply_to_message_id) - return self.bot.send_dice( - chat_id=self.chat_id, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - emoji=emoji, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - ) - - def reply_chat_action( - self, - action: str, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> bool: - """Shortcut for:: - - bot.send_chat_action(update.effective_message.chat_id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_chat_action`. - - .. versionadded:: 13.2 - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return self.bot.send_chat_action( - chat_id=self.chat_id, - action=action, - timeout=timeout, - api_kwargs=api_kwargs, - ) - - def reply_game( - self, - game_short_name: str, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: 'InlineKeyboardMarkup' = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - quote: bool = None, - ) -> 'Message': - """Shortcut for:: - - bot.send_game(update.effective_message.chat_id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_game`. - - Args: - quote (:obj:`bool`, optional): If set to :obj:`True`, the game is sent as an actual - reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this - parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` - in private chats. - - .. versionadded:: 13.2 - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - reply_to_message_id = self._quote(quote, reply_to_message_id) - return self.bot.send_game( - chat_id=self.chat_id, - game_short_name=game_short_name, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - ) - - def reply_invoice( - self, - title: str, - description: str, - payload: str, - provider_token: str, - currency: str, - prices: List['LabeledPrice'], - start_parameter: str = None, - photo_url: str = None, - photo_size: int = None, - photo_width: int = None, - photo_height: int = None, - need_name: bool = None, - need_phone_number: bool = None, - need_email: bool = None, - need_shipping_address: bool = None, - is_flexible: bool = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: 'InlineKeyboardMarkup' = None, - provider_data: Union[str, object] = None, - send_phone_number_to_provider: bool = None, - send_email_to_provider: bool = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - quote: bool = None, - max_tip_amount: int = None, - suggested_tip_amounts: List[int] = None, - ) -> 'Message': - """Shortcut for:: - - bot.send_invoice(update.effective_message.chat_id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_invoice`. - - Warning: - As of API 5.2 :attr:`start_parameter` is an optional argument and therefore the order - of the arguments had to be changed. Use keyword arguments to make sure that the - arguments are passed correctly. - - .. versionadded:: 13.2 - - .. versionchanged:: 13.5 - As of Bot API 5.2, the parameter :attr:`start_parameter` is optional. - - Args: - quote (:obj:`bool`, optional): If set to :obj:`True`, the invoice is sent as an actual - reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, this - parameter will be ignored. Default: :obj:`True` in group chats and :obj:`False` - in private chats. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - reply_to_message_id = self._quote(quote, reply_to_message_id) - return self.bot.send_invoice( - chat_id=self.chat_id, - title=title, - description=description, - payload=payload, - provider_token=provider_token, - currency=currency, - prices=prices, - start_parameter=start_parameter, - photo_url=photo_url, - photo_size=photo_size, - photo_width=photo_width, - photo_height=photo_height, - need_name=need_name, - need_phone_number=need_phone_number, - need_email=need_email, - need_shipping_address=need_shipping_address, - is_flexible=is_flexible, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - provider_data=provider_data, - send_phone_number_to_provider=send_phone_number_to_provider, - send_email_to_provider=send_email_to_provider, - timeout=timeout, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - max_tip_amount=max_tip_amount, - suggested_tip_amounts=suggested_tip_amounts, - ) - - def forward( - self, - chat_id: Union[int, str], - disable_notification: DVInput[bool] = DEFAULT_NONE, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> 'Message': - """Shortcut for:: - - bot.forward_message(chat_id=chat_id, - from_chat_id=update.effective_message.chat_id, - message_id=update.effective_message.message_id, - *args, - **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.forward_message`. - - Returns: - :class:`telegram.Message`: On success, instance representing the message forwarded. - - """ - return self.bot.forward_message( - chat_id=chat_id, - from_chat_id=self.chat_id, - message_id=self.message_id, - disable_notification=disable_notification, - timeout=timeout, - api_kwargs=api_kwargs, - ) - - def copy( - self, - chat_id: Union[int, str], - caption: str = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[Tuple['MessageEntity', ...], List['MessageEntity']] = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE, - reply_markup: ReplyMarkup = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> 'MessageId': - """Shortcut for:: - - bot.copy_message(chat_id=chat_id, - from_chat_id=update.effective_message.chat_id, - message_id=update.effective_message.message_id, - *args, - **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.copy_message`. - - Returns: - :class:`telegram.MessageId`: On success, returns the MessageId of the sent message. - - """ - return self.bot.copy_message( - chat_id=chat_id, - from_chat_id=self.chat_id, - message_id=self.message_id, - caption=caption, - parse_mode=parse_mode, - caption_entities=caption_entities, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - allow_sending_without_reply=allow_sending_without_reply, - reply_markup=reply_markup, - timeout=timeout, - api_kwargs=api_kwargs, - ) - - def reply_copy( - self, - from_chat_id: Union[str, int], - message_id: int, - caption: str = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[Tuple['MessageEntity', ...], List['MessageEntity']] = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE, - reply_markup: ReplyMarkup = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - quote: bool = None, - ) -> 'MessageId': - """Shortcut for:: - - bot.copy_message(chat_id=message.chat.id, - from_chat_id=from_chat_id, - message_id=message_id, - *args, - **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.copy_message`. - - Args: - quote (:obj:`bool`, optional): If set to :obj:`True`, the copy is sent as an actual - reply to this message. If ``reply_to_message_id`` is passed in ``kwargs``, - this parameter will be ignored. Default: :obj:`True` in group chats and - :obj:`False` in private chats. - - .. versionadded:: 13.1 - - Returns: - :class:`telegram.MessageId`: On success, returns the MessageId of the sent message. - - """ - reply_to_message_id = self._quote(quote, reply_to_message_id) - return self.bot.copy_message( - chat_id=self.chat_id, - from_chat_id=from_chat_id, - message_id=message_id, - caption=caption, - parse_mode=parse_mode, - caption_entities=caption_entities, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - allow_sending_without_reply=allow_sending_without_reply, - reply_markup=reply_markup, - timeout=timeout, - api_kwargs=api_kwargs, - ) - - def edit_text( - self, - text: str, - parse_mode: ODVInput[str] = DEFAULT_NONE, - disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, - reply_markup: InlineKeyboardMarkup = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - ) -> Union['Message', bool]: - """Shortcut for:: - - bot.edit_message_text(chat_id=message.chat_id, - message_id=message.message_id, - *args, - **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.edit_message_text`. - - Note: - You can only edit messages that the bot sent itself (i.e. of the ``bot.send_*`` family - of methods) or channel posts, if the bot is an admin in that channel. However, this - behaviour is undocumented and might be changed by Telegram. - - Returns: - :class:`telegram.Message`: On success, if edited message is sent by the bot, the - edited Message is returned, otherwise ``True`` is returned. - - """ - return self.bot.edit_message_text( - chat_id=self.chat_id, - message_id=self.message_id, - text=text, - parse_mode=parse_mode, - disable_web_page_preview=disable_web_page_preview, - reply_markup=reply_markup, - timeout=timeout, - api_kwargs=api_kwargs, - entities=entities, - inline_message_id=None, - ) - - def edit_caption( - self, - caption: str = None, - reply_markup: InlineKeyboardMarkup = None, - timeout: ODVInput[float] = DEFAULT_NONE, - parse_mode: ODVInput[str] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - ) -> Union['Message', bool]: - """Shortcut for:: - - bot.edit_message_caption(chat_id=message.chat_id, - message_id=message.message_id, - *args, - **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.edit_message_caption`. - - Note: - You can only edit messages that the bot sent itself (i.e. of the ``bot.send_*`` family - of methods) or channel posts, if the bot is an admin in that channel. However, this - behaviour is undocumented and might be changed by Telegram. - - Returns: - :class:`telegram.Message`: On success, if edited message is sent by the bot, the - edited Message is returned, otherwise ``True`` is returned. - - """ - return self.bot.edit_message_caption( - chat_id=self.chat_id, - message_id=self.message_id, - caption=caption, - reply_markup=reply_markup, - timeout=timeout, - parse_mode=parse_mode, - api_kwargs=api_kwargs, - caption_entities=caption_entities, - inline_message_id=None, - ) - - def edit_media( - self, - media: 'InputMedia' = None, - reply_markup: InlineKeyboardMarkup = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> Union['Message', bool]: - """Shortcut for:: - - bot.edit_message_media(chat_id=message.chat_id, - message_id=message.message_id, - *args, - **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.edit_message_media`. - - Note: - You can only edit messages that the bot sent itself(i.e. of the ``bot.send_*`` family - of methods) or channel posts, if the bot is an admin in that channel. However, this - behaviour is undocumented and might be changed by Telegram. - - Returns: - :class:`telegram.Message`: On success, if edited message is sent by the bot, the - edited Message is returned, otherwise ``True`` is returned. - - """ - return self.bot.edit_message_media( - chat_id=self.chat_id, - message_id=self.message_id, - media=media, - reply_markup=reply_markup, - timeout=timeout, - api_kwargs=api_kwargs, - inline_message_id=None, - ) - - def edit_reply_markup( - self, - reply_markup: Optional['InlineKeyboardMarkup'] = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> Union['Message', bool]: - """Shortcut for:: - - bot.edit_message_reply_markup(chat_id=message.chat_id, - message_id=message.message_id, - *args, - **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.edit_message_reply_markup`. - - Note: - You can only edit messages that the bot sent itself (i.e. of the ``bot.send_*`` family - of methods) or channel posts, if the bot is an admin in that channel. However, this - behaviour is undocumented and might be changed by Telegram. - - Returns: - :class:`telegram.Message`: On success, if edited message is sent by the bot, the - edited Message is returned, otherwise ``True`` is returned. - """ - return self.bot.edit_message_reply_markup( - chat_id=self.chat_id, - message_id=self.message_id, - reply_markup=reply_markup, - timeout=timeout, - api_kwargs=api_kwargs, - inline_message_id=None, - ) - - def edit_live_location( - self, - latitude: float = None, - longitude: float = None, - location: Location = None, - reply_markup: InlineKeyboardMarkup = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - horizontal_accuracy: float = None, - heading: int = None, - proximity_alert_radius: int = None, - ) -> Union['Message', bool]: - """Shortcut for:: - - bot.edit_message_live_location(chat_id=message.chat_id, - message_id=message.message_id, - *args, - **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.edit_message_live_location`. - - Note: - You can only edit messages that the bot sent itself (i.e. of the ``bot.send_*`` family - of methods) or channel posts, if the bot is an admin in that channel. However, this - behaviour is undocumented and might be changed by Telegram. - - Returns: - :class:`telegram.Message`: On success, if edited message is sent by the bot, the - edited Message is returned, otherwise :obj:`True` is returned. - """ - return self.bot.edit_message_live_location( - chat_id=self.chat_id, - message_id=self.message_id, - latitude=latitude, - longitude=longitude, - location=location, - reply_markup=reply_markup, - timeout=timeout, - api_kwargs=api_kwargs, - horizontal_accuracy=horizontal_accuracy, - heading=heading, - proximity_alert_radius=proximity_alert_radius, - inline_message_id=None, - ) - - def stop_live_location( - self, - reply_markup: InlineKeyboardMarkup = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> Union['Message', bool]: - """Shortcut for:: - - bot.stop_message_live_location(chat_id=message.chat_id, - message_id=message.message_id, - *args, - **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.stop_message_live_location`. - - Note: - You can only edit messages that the bot sent itself (i.e. of the ``bot.send_*`` family - of methods) or channel posts, if the bot is an admin in that channel. However, this - behaviour is undocumented and might be changed by Telegram. - - Returns: - :class:`telegram.Message`: On success, if edited message is sent by the bot, the - edited Message is returned, otherwise :obj:`True` is returned. - """ - return self.bot.stop_message_live_location( - chat_id=self.chat_id, - message_id=self.message_id, - reply_markup=reply_markup, - timeout=timeout, - api_kwargs=api_kwargs, - inline_message_id=None, - ) - - def set_game_score( - self, - user_id: Union[int, str], - score: int, - force: bool = None, - disable_edit_message: bool = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> Union['Message', bool]: - """Shortcut for:: - - bot.set_game_score(chat_id=message.chat_id, - message_id=message.message_id, - *args, - **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.set_game_score`. - - Note: - You can only edit messages that the bot sent itself (i.e. of the ``bot.send_*`` family - of methods) or channel posts, if the bot is an admin in that channel. However, this - behaviour is undocumented and might be changed by Telegram. - - Returns: - :class:`telegram.Message`: On success, if edited message is sent by the bot, the - edited Message is returned, otherwise :obj:`True` is returned. - """ - return self.bot.set_game_score( - chat_id=self.chat_id, - message_id=self.message_id, - user_id=user_id, - score=score, - force=force, - disable_edit_message=disable_edit_message, - timeout=timeout, - api_kwargs=api_kwargs, - inline_message_id=None, - ) - - def get_game_high_scores( - self, - user_id: Union[int, str], - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> List['GameHighScore']: - """Shortcut for:: - - bot.get_game_high_scores(chat_id=message.chat_id, - message_id=message.message_id, - *args, - **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.get_game_high_scores`. - - Note: - You can only edit messages that the bot sent itself (i.e. of the ``bot.send_*`` family - of methods) or channel posts, if the bot is an admin in that channel. However, this - behaviour is undocumented and might be changed by Telegram. - - Returns: - List[:class:`telegram.GameHighScore`] - """ - return self.bot.get_game_high_scores( - chat_id=self.chat_id, - message_id=self.message_id, - user_id=user_id, - timeout=timeout, - api_kwargs=api_kwargs, - inline_message_id=None, - ) - - def delete( - self, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> bool: - """Shortcut for:: - - bot.delete_message(chat_id=message.chat_id, - message_id=message.message_id, - *args, - **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.delete_message`. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return self.bot.delete_message( - chat_id=self.chat_id, - message_id=self.message_id, - timeout=timeout, - api_kwargs=api_kwargs, - ) - - def stop_poll( - self, - reply_markup: InlineKeyboardMarkup = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> Poll: - """Shortcut for:: - - bot.stop_poll(chat_id=message.chat_id, - message_id=message.message_id, - *args, - **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.stop_poll`. - - Returns: - :class:`telegram.Poll`: On success, the stopped Poll with the final results is - returned. - - """ - return self.bot.stop_poll( - chat_id=self.chat_id, - message_id=self.message_id, - reply_markup=reply_markup, - timeout=timeout, - api_kwargs=api_kwargs, - ) - - def pin( - self, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> bool: - """Shortcut for:: - - bot.pin_chat_message(chat_id=message.chat_id, - message_id=message.message_id, - *args, - **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.pin_chat_message`. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return self.bot.pin_chat_message( - chat_id=self.chat_id, - message_id=self.message_id, - disable_notification=disable_notification, - timeout=timeout, - api_kwargs=api_kwargs, - ) - - def unpin( - self, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> bool: - """Shortcut for:: - - bot.unpin_chat_message(chat_id=message.chat_id, - message_id=message.message_id, - *args, - **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.unpin_chat_message`. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return self.bot.unpin_chat_message( - chat_id=self.chat_id, - message_id=self.message_id, - timeout=timeout, - api_kwargs=api_kwargs, - ) - - def parse_entity(self, entity: MessageEntity) -> str: - """Returns the text from a given :class:`telegram.MessageEntity`. - - Note: - This method is present because Telegram calculates the offset and length in - UTF-16 codepoint pairs, which some versions of Python don't handle automatically. - (That is, you can't just slice ``Message.text`` with the offset and length.) - - Args: - entity (:class:`telegram.MessageEntity`): The entity to extract the text from. It must - be an entity that belongs to this message. - - Returns: - :obj:`str`: The text of the given entity. - - Raises: - RuntimeError: If the message has no text. - - """ - if not self.text: - raise RuntimeError("This Message has no 'text'.") - - # Is it a narrow build, if so we don't need to convert - if sys.maxunicode == 0xFFFF: - return self.text[entity.offset : entity.offset + entity.length] - - entity_text = self.text.encode('utf-16-le') - entity_text = entity_text[entity.offset * 2 : (entity.offset + entity.length) * 2] - return entity_text.decode('utf-16-le') - - def parse_caption_entity(self, entity: MessageEntity) -> str: - """Returns the text from a given :class:`telegram.MessageEntity`. - - Note: - This method is present because Telegram calculates the offset and length in - UTF-16 codepoint pairs, which some versions of Python don't handle automatically. - (That is, you can't just slice ``Message.caption`` with the offset and length.) - - Args: - entity (:class:`telegram.MessageEntity`): The entity to extract the text from. It must - be an entity that belongs to this message. - - Returns: - :obj:`str`: The text of the given entity. - - Raises: - RuntimeError: If the message has no caption. - - """ - if not self.caption: - raise RuntimeError("This Message has no 'caption'.") - - # Is it a narrow build, if so we don't need to convert - if sys.maxunicode == 0xFFFF: - return self.caption[entity.offset : entity.offset + entity.length] - - entity_text = self.caption.encode('utf-16-le') - entity_text = entity_text[entity.offset * 2 : (entity.offset + entity.length) * 2] - return entity_text.decode('utf-16-le') - - def parse_entities(self, types: List[str] = None) -> Dict[MessageEntity, str]: - """ - Returns a :obj:`dict` that maps :class:`telegram.MessageEntity` to :obj:`str`. - It contains entities from this message filtered by their - :attr:`telegram.MessageEntity.type` attribute as the key, and the text that each entity - belongs to as the value of the :obj:`dict`. - - Note: - This method should always be used instead of the :attr:`entities` attribute, since it - calculates the correct substring from the message text based on UTF-16 codepoints. - See :attr:`parse_entity` for more info. - - Args: - types (List[:obj:`str`], optional): List of :class:`telegram.MessageEntity` types as - strings. If the ``type`` attribute of an entity is contained in this list, it will - be returned. Defaults to a list of all types. All types can be found as constants - in :class:`telegram.MessageEntity`. - - Returns: - Dict[:class:`telegram.MessageEntity`, :obj:`str`]: A dictionary of entities mapped to - the text that belongs to them, calculated based on UTF-16 codepoints. - - """ - if types is None: - types = MessageEntity.ALL_TYPES - - return { - entity: self.parse_entity(entity) - for entity in (self.entities or []) - if entity.type in types - } - - def parse_caption_entities(self, types: List[str] = None) -> Dict[MessageEntity, str]: - """ - Returns a :obj:`dict` that maps :class:`telegram.MessageEntity` to :obj:`str`. - It contains entities from this message's caption filtered by their - :attr:`telegram.MessageEntity.type` attribute as the key, and the text that each entity - belongs to as the value of the :obj:`dict`. - - Note: - This method should always be used instead of the :attr:`caption_entities` attribute, - since it calculates the correct substring from the message text based on UTF-16 - codepoints. See :attr:`parse_entity` for more info. - - Args: - types (List[:obj:`str`], optional): List of :class:`telegram.MessageEntity` types as - strings. If the ``type`` attribute of an entity is contained in this list, it will - be returned. Defaults to a list of all types. All types can be found as constants - in :class:`telegram.MessageEntity`. - - Returns: - Dict[:class:`telegram.MessageEntity`, :obj:`str`]: A dictionary of entities mapped to - the text that belongs to them, calculated based on UTF-16 codepoints. - - """ - if types is None: - types = MessageEntity.ALL_TYPES - - return { - entity: self.parse_caption_entity(entity) - for entity in (self.caption_entities or []) - if entity.type in types - } - - @staticmethod - def _parse_html( - message_text: Optional[str], - entities: Dict[MessageEntity, str], - urled: bool = False, - offset: int = 0, - ) -> Optional[str]: - if message_text is None: - return None - - if sys.maxunicode != 0xFFFF: - message_text = message_text.encode('utf-16-le') # type: ignore - - html_text = '' - last_offset = 0 - - sorted_entities = sorted(entities.items(), key=(lambda item: item[0].offset)) - parsed_entities = [] - - for (entity, text) in sorted_entities: - if entity not in parsed_entities: - nested_entities = { - e: t - for (e, t) in sorted_entities - if e.offset >= entity.offset - and e.offset + e.length <= entity.offset + entity.length - and e != entity - } - parsed_entities.extend(list(nested_entities.keys())) - - orig_text = text - text = escape(text) - - if nested_entities: - text = Message._parse_html( - orig_text, nested_entities, urled=urled, offset=entity.offset - ) - - if entity.type == MessageEntity.TEXT_LINK: - insert = f'<a href="{entity.url}">{text}</a>' - elif entity.type == MessageEntity.TEXT_MENTION and entity.user: - insert = f'<a href="tg://user?id={entity.user.id}">{text}</a>' - elif entity.type == MessageEntity.URL and urled: - insert = f'<a href="{text}">{text}</a>' - elif entity.type == MessageEntity.BOLD: - insert = '<b>' + text + '</b>' - elif entity.type == MessageEntity.ITALIC: - insert = '<i>' + text + '</i>' - elif entity.type == MessageEntity.CODE: - insert = '<code>' + text + '</code>' - elif entity.type == MessageEntity.PRE: - if entity.language: - insert = f'<pre><code class="{entity.language}">{text}</code></pre>' - else: - insert = '<pre>' + text + '</pre>' - elif entity.type == MessageEntity.UNDERLINE: - insert = '<u>' + text + '</u>' - elif entity.type == MessageEntity.STRIKETHROUGH: - insert = '<s>' + text + '</s>' - else: - insert = text - - if offset == 0: - if sys.maxunicode == 0xFFFF: - html_text += ( - escape(message_text[last_offset : entity.offset - offset]) + insert - ) - else: - html_text += ( - escape( - message_text[ # type: ignore - last_offset * 2 : (entity.offset - offset) * 2 - ].decode('utf-16-le') - ) - + insert - ) - else: - if sys.maxunicode == 0xFFFF: - html_text += message_text[last_offset : entity.offset - offset] + insert - else: - html_text += ( - message_text[ # type: ignore - last_offset * 2 : (entity.offset - offset) * 2 - ].decode('utf-16-le') - + insert - ) - - last_offset = entity.offset - offset + entity.length - - if offset == 0: - if sys.maxunicode == 0xFFFF: - html_text += escape(message_text[last_offset:]) - else: - html_text += escape( - message_text[last_offset * 2 :].decode('utf-16-le') # type: ignore - ) - else: - if sys.maxunicode == 0xFFFF: - html_text += message_text[last_offset:] - else: - html_text += message_text[last_offset * 2 :].decode('utf-16-le') # type: ignore - - return html_text - - @property - def text_html(self) -> str: - """Creates an HTML-formatted string from the markup entities found in the message. - - Use this if you want to retrieve the message text with the entities formatted as HTML in - the same way the original message was formatted. - - Returns: - :obj:`str`: Message text with entities formatted as HTML. - - """ - return self._parse_html(self.text, self.parse_entities(), urled=False) - - @property - def text_html_urled(self) -> str: - """Creates an HTML-formatted string from the markup entities found in the message. - - Use this if you want to retrieve the message text with the entities formatted as HTML. - This also formats :attr:`telegram.MessageEntity.URL` as a hyperlink. - - Returns: - :obj:`str`: Message text with entities formatted as HTML. - - """ - return self._parse_html(self.text, self.parse_entities(), urled=True) - - @property - def caption_html(self) -> str: - """Creates an HTML-formatted string from the markup entities found in the message's - caption. - - Use this if you want to retrieve the message caption with the caption entities formatted as - HTML in the same way the original message was formatted. - - Returns: - :obj:`str`: Message caption with caption entities formatted as HTML. - - """ - return self._parse_html(self.caption, self.parse_caption_entities(), urled=False) - - @property - def caption_html_urled(self) -> str: - """Creates an HTML-formatted string from the markup entities found in the message's - caption. - - Use this if you want to retrieve the message caption with the caption entities formatted as - HTML. This also formats :attr:`telegram.MessageEntity.URL` as a hyperlink. - - Returns: - :obj:`str`: Message caption with caption entities formatted as HTML. - - """ - return self._parse_html(self.caption, self.parse_caption_entities(), urled=True) - - @staticmethod - def _parse_markdown( - message_text: Optional[str], - entities: Dict[MessageEntity, str], - urled: bool = False, - version: int = 1, - offset: int = 0, - ) -> Optional[str]: - version = int(version) - - if message_text is None: - return None - - if sys.maxunicode != 0xFFFF: - message_text = message_text.encode('utf-16-le') # type: ignore - - markdown_text = '' - last_offset = 0 - - sorted_entities = sorted(entities.items(), key=(lambda item: item[0].offset)) - parsed_entities = [] - - for (entity, text) in sorted_entities: - if entity not in parsed_entities: - nested_entities = { - e: t - for (e, t) in sorted_entities - if e.offset >= entity.offset - and e.offset + e.length <= entity.offset + entity.length - and e != entity - } - parsed_entities.extend(list(nested_entities.keys())) - - orig_text = text - text = escape_markdown(text, version=version) - - if nested_entities: - if version < 2: - raise ValueError( - 'Nested entities are not supported for Markdown ' 'version 1' - ) - - text = Message._parse_markdown( - orig_text, - nested_entities, - urled=urled, - offset=entity.offset, - version=version, - ) - - if entity.type == MessageEntity.TEXT_LINK: - if version == 1: - url = entity.url - else: - # Links need special escaping. Also can't have entities nested within - url = escape_markdown( - entity.url, version=version, entity_type=MessageEntity.TEXT_LINK - ) - insert = f'[{text}]({url})' - elif entity.type == MessageEntity.TEXT_MENTION and entity.user: - insert = f'[{text}](tg://user?id={entity.user.id})' - elif entity.type == MessageEntity.URL and urled: - if version == 1: - link = orig_text - else: - link = text - insert = f'[{link}]({orig_text})' - elif entity.type == MessageEntity.BOLD: - insert = '*' + text + '*' - elif entity.type == MessageEntity.ITALIC: - insert = '_' + text + '_' - elif entity.type == MessageEntity.CODE: - # Monospace needs special escaping. Also can't have entities nested within - insert = ( - '`' - + escape_markdown( - orig_text, version=version, entity_type=MessageEntity.CODE - ) - + '`' - ) - elif entity.type == MessageEntity.PRE: - # Monospace needs special escaping. Also can't have entities nested within - code = escape_markdown( - orig_text, version=version, entity_type=MessageEntity.PRE - ) - if entity.language: - prefix = '```' + entity.language + '\n' - else: - if code.startswith('\\'): - prefix = '```' - else: - prefix = '```\n' - insert = prefix + code + '```' - elif entity.type == MessageEntity.UNDERLINE: - if version == 1: - raise ValueError( - 'Underline entities are not supported for Markdown ' 'version 1' - ) - insert = '__' + text + '__' - elif entity.type == MessageEntity.STRIKETHROUGH: - if version == 1: - raise ValueError( - 'Strikethrough entities are not supported for Markdown ' 'version 1' - ) - insert = '~' + text + '~' - else: - insert = text - - if offset == 0: - if sys.maxunicode == 0xFFFF: - markdown_text += ( - escape_markdown( - message_text[last_offset : entity.offset - offset], version=version - ) - + insert - ) - else: - markdown_text += ( - escape_markdown( - message_text[ # type: ignore - last_offset * 2 : (entity.offset - offset) * 2 - ].decode('utf-16-le'), - version=version, - ) - + insert - ) - else: - if sys.maxunicode == 0xFFFF: - markdown_text += ( - message_text[last_offset : entity.offset - offset] + insert - ) - else: - markdown_text += ( - message_text[ # type: ignore - last_offset * 2 : (entity.offset - offset) * 2 - ].decode('utf-16-le') - + insert - ) - - last_offset = entity.offset - offset + entity.length - - if offset == 0: - if sys.maxunicode == 0xFFFF: - markdown_text += escape_markdown(message_text[last_offset:], version=version) - else: - markdown_text += escape_markdown( - message_text[last_offset * 2 :].decode('utf-16-le'), # type: ignore - version=version, - ) - else: - if sys.maxunicode == 0xFFFF: - markdown_text += message_text[last_offset:] - else: - markdown_text += message_text[last_offset * 2 :].decode( # type: ignore - 'utf-16-le' - ) - - return markdown_text - - @property - def text_markdown(self) -> str: - """Creates an Markdown-formatted string from the markup entities found in the message - using :class:`telegram.ParseMode.MARKDOWN`. - - Use this if you want to retrieve the message text with the entities formatted as Markdown - in the same way the original message was formatted. - - Note: - :attr:`telegram.ParseMode.MARKDOWN` is is a legacy mode, retained by Telegram for - backward compatibility. You should use :meth:`text_markdown_v2` instead. - - Returns: - :obj:`str`: Message text with entities formatted as Markdown. - - """ - return self._parse_markdown(self.text, self.parse_entities(), urled=False) - - @property - def text_markdown_v2(self) -> str: - """Creates an Markdown-formatted string from the markup entities found in the message - using :class:`telegram.ParseMode.MARKDOWN_V2`. - - Use this if you want to retrieve the message text with the entities formatted as Markdown - in the same way the original message was formatted. - - Returns: - :obj:`str`: Message text with entities formatted as Markdown. - - """ - return self._parse_markdown(self.text, self.parse_entities(), urled=False, version=2) - - @property - def text_markdown_urled(self) -> str: - """Creates an Markdown-formatted string from the markup entities found in the message - using :class:`telegram.ParseMode.MARKDOWN`. - - Use this if you want to retrieve the message text with the entities formatted as Markdown. - This also formats :attr:`telegram.MessageEntity.URL` as a hyperlink. - - Note: - :attr:`telegram.ParseMode.MARKDOWN` is is a legacy mode, retained by Telegram for - backward compatibility. You should use :meth:`text_markdown_v2_urled` instead. - - Returns: - :obj:`str`: Message text with entities formatted as Markdown. - - """ - return self._parse_markdown(self.text, self.parse_entities(), urled=True) - - @property - def text_markdown_v2_urled(self) -> str: - """Creates an Markdown-formatted string from the markup entities found in the message - using :class:`telegram.ParseMode.MARKDOWN_V2`. - - Use this if you want to retrieve the message text with the entities formatted as Markdown. - This also formats :attr:`telegram.MessageEntity.URL` as a hyperlink. - - Returns: - :obj:`str`: Message text with entities formatted as Markdown. - - """ - return self._parse_markdown(self.text, self.parse_entities(), urled=True, version=2) - - @property - def caption_markdown(self) -> str: - """Creates an Markdown-formatted string from the markup entities found in the message's - caption using :class:`telegram.ParseMode.MARKDOWN`. - - Use this if you want to retrieve the message caption with the caption entities formatted as - Markdown in the same way the original message was formatted. - - Note: - :attr:`telegram.ParseMode.MARKDOWN` is is a legacy mode, retained by Telegram for - backward compatibility. You should use :meth:`caption_markdown_v2` instead. - - Returns: - :obj:`str`: Message caption with caption entities formatted as Markdown. - - """ - return self._parse_markdown(self.caption, self.parse_caption_entities(), urled=False) - - @property - def caption_markdown_v2(self) -> str: - """Creates an Markdown-formatted string from the markup entities found in the message's - caption using :class:`telegram.ParseMode.MARKDOWN_V2`. - - Use this if you want to retrieve the message caption with the caption entities formatted as - Markdown in the same way the original message was formatted. - - Returns: - :obj:`str`: Message caption with caption entities formatted as Markdown. - - """ - return self._parse_markdown( - self.caption, self.parse_caption_entities(), urled=False, version=2 - ) - - @property - def caption_markdown_urled(self) -> str: - """Creates an Markdown-formatted string from the markup entities found in the message's - caption using :class:`telegram.ParseMode.MARKDOWN`. - - Use this if you want to retrieve the message caption with the caption entities formatted as - Markdown. This also formats :attr:`telegram.MessageEntity.URL` as a hyperlink. - - Note: - :attr:`telegram.ParseMode.MARKDOWN` is is a legacy mode, retained by Telegram for - backward compatibility. You should use :meth:`caption_markdown_v2_urled` instead. - - Returns: - :obj:`str`: Message caption with caption entities formatted as Markdown. - - """ - return self._parse_markdown(self.caption, self.parse_caption_entities(), urled=True) - - @property - def caption_markdown_v2_urled(self) -> str: - """Creates an Markdown-formatted string from the markup entities found in the message's - caption using :class:`telegram.ParseMode.MARKDOWN_V2`. - - Use this if you want to retrieve the message caption with the caption entities formatted as - Markdown. This also formats :attr:`telegram.MessageEntity.URL` as a hyperlink. - - Returns: - :obj:`str`: Message caption with caption entities formatted as Markdown. - - """ - return self._parse_markdown( - self.caption, self.parse_caption_entities(), urled=True, version=2 - ) diff --git a/venv/lib/python3.8/site-packages/telegram/messageautodeletetimerchanged.py b/venv/lib/python3.8/site-packages/telegram/messageautodeletetimerchanged.py deleted file mode 100644 index 3fb1ce9..0000000 --- a/venv/lib/python3.8/site-packages/telegram/messageautodeletetimerchanged.py +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a change in the Telegram message auto -deletion. -""" - -from typing import Any - -from telegram import TelegramObject - - -class MessageAutoDeleteTimerChanged(TelegramObject): - """This object represents a service message about a change in auto-delete timer settings. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`message_auto_delete_time` is equal. - - .. versionadded:: 13.4 - - Args: - message_auto_delete_time (:obj:`int`): New auto-delete time for messages in the - chat. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - message_auto_delete_time (:obj:`int`): New auto-delete time for messages in the - chat. - - """ - - __slots__ = ('message_auto_delete_time', '_id_attrs') - - def __init__( - self, - message_auto_delete_time: int, - **_kwargs: Any, - ): - self.message_auto_delete_time = int(message_auto_delete_time) - - self._id_attrs = (self.message_auto_delete_time,) diff --git a/venv/lib/python3.8/site-packages/telegram/messageentity.py b/venv/lib/python3.8/site-packages/telegram/messageentity.py deleted file mode 100644 index 0a0350e..0000000 --- a/venv/lib/python3.8/site-packages/telegram/messageentity.py +++ /dev/null @@ -1,129 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram MessageEntity.""" - -from typing import TYPE_CHECKING, Any, List, Optional, ClassVar - -from telegram import TelegramObject, User, constants -from telegram.utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - - -class MessageEntity(TelegramObject): - """ - This object represents one special entity in a text message. For example, hashtags, - usernames, URLs, etc. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`type`, :attr:`offset` and :attr:`length` are equal. - - Args: - type (:obj:`str`): Type of the entity. Can be mention (@username), hashtag, bot_command, - url, email, phone_number, bold (bold text), italic (italic text), strikethrough, - code (monowidth string), pre (monowidth block), text_link (for clickable text URLs), - text_mention (for users without usernames). - offset (:obj:`int`): Offset in UTF-16 code units to the start of the entity. - length (:obj:`int`): Length of the entity in UTF-16 code units. - url (:obj:`str`, optional): For :attr:`TEXT_LINK` only, url that will be opened after - user taps on the text. - user (:class:`telegram.User`, optional): For :attr:`TEXT_MENTION` only, the mentioned - user. - language (:obj:`str`, optional): For :attr:`PRE` only, the programming language of - the entity text. - - Attributes: - type (:obj:`str`): Type of the entity. - offset (:obj:`int`): Offset in UTF-16 code units to the start of the entity. - length (:obj:`int`): Length of the entity in UTF-16 code units. - url (:obj:`str`): Optional. Url that will be opened after user taps on the text. - user (:class:`telegram.User`): Optional. The mentioned user. - language (:obj:`str`): Optional. Programming language of the entity text. - - """ - - __slots__ = ('length', 'url', 'user', 'type', 'language', 'offset', '_id_attrs') - - def __init__( - self, - type: str, # pylint: disable=W0622 - offset: int, - length: int, - url: str = None, - user: User = None, - language: str = None, - **_kwargs: Any, - ): - # Required - self.type = type - self.offset = offset - self.length = length - # Optionals - self.url = url - self.user = user - self.language = language - - self._id_attrs = (self.type, self.offset, self.length) - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['MessageEntity']: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data['user'] = User.de_json(data.get('user'), bot) - - return cls(**data) - - MENTION: ClassVar[str] = constants.MESSAGEENTITY_MENTION - """:const:`telegram.constants.MESSAGEENTITY_MENTION`""" - HASHTAG: ClassVar[str] = constants.MESSAGEENTITY_HASHTAG - """:const:`telegram.constants.MESSAGEENTITY_HASHTAG`""" - CASHTAG: ClassVar[str] = constants.MESSAGEENTITY_CASHTAG - """:const:`telegram.constants.MESSAGEENTITY_CASHTAG`""" - PHONE_NUMBER: ClassVar[str] = constants.MESSAGEENTITY_PHONE_NUMBER - """:const:`telegram.constants.MESSAGEENTITY_PHONE_NUMBER`""" - BOT_COMMAND: ClassVar[str] = constants.MESSAGEENTITY_BOT_COMMAND - """:const:`telegram.constants.MESSAGEENTITY_BOT_COMMAND`""" - URL: ClassVar[str] = constants.MESSAGEENTITY_URL - """:const:`telegram.constants.MESSAGEENTITY_URL`""" - EMAIL: ClassVar[str] = constants.MESSAGEENTITY_EMAIL - """:const:`telegram.constants.MESSAGEENTITY_EMAIL`""" - BOLD: ClassVar[str] = constants.MESSAGEENTITY_BOLD - """:const:`telegram.constants.MESSAGEENTITY_BOLD`""" - ITALIC: ClassVar[str] = constants.MESSAGEENTITY_ITALIC - """:const:`telegram.constants.MESSAGEENTITY_ITALIC`""" - CODE: ClassVar[str] = constants.MESSAGEENTITY_CODE - """:const:`telegram.constants.MESSAGEENTITY_CODE`""" - PRE: ClassVar[str] = constants.MESSAGEENTITY_PRE - """:const:`telegram.constants.MESSAGEENTITY_PRE`""" - TEXT_LINK: ClassVar[str] = constants.MESSAGEENTITY_TEXT_LINK - """:const:`telegram.constants.MESSAGEENTITY_TEXT_LINK`""" - TEXT_MENTION: ClassVar[str] = constants.MESSAGEENTITY_TEXT_MENTION - """:const:`telegram.constants.MESSAGEENTITY_TEXT_MENTION`""" - UNDERLINE: ClassVar[str] = constants.MESSAGEENTITY_UNDERLINE - """:const:`telegram.constants.MESSAGEENTITY_UNDERLINE`""" - STRIKETHROUGH: ClassVar[str] = constants.MESSAGEENTITY_STRIKETHROUGH - """:const:`telegram.constants.MESSAGEENTITY_STRIKETHROUGH`""" - ALL_TYPES: ClassVar[List[str]] = constants.MESSAGEENTITY_ALL_TYPES - """:const:`telegram.constants.MESSAGEENTITY_ALL_TYPES`\n - List of all the types""" diff --git a/venv/lib/python3.8/site-packages/telegram/messageid.py b/venv/lib/python3.8/site-packages/telegram/messageid.py deleted file mode 100644 index 56eca3a..0000000 --- a/venv/lib/python3.8/site-packages/telegram/messageid.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2020-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents an instance of a Telegram MessageId.""" -from typing import Any - -from telegram import TelegramObject - - -class MessageId(TelegramObject): - """This object represents a unique message identifier. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`message_id` is equal. - - Attributes: - message_id (:obj:`int`): Unique message identifier - """ - - __slots__ = ('message_id', '_id_attrs') - - def __init__(self, message_id: int, **_kwargs: Any): - self.message_id = int(message_id) - - self._id_attrs = (self.message_id,) diff --git a/venv/lib/python3.8/site-packages/telegram/parsemode.py b/venv/lib/python3.8/site-packages/telegram/parsemode.py deleted file mode 100644 index 86bc07b..0000000 --- a/venv/lib/python3.8/site-packages/telegram/parsemode.py +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env python -# pylint: disable=R0903 -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram Message Parse Modes.""" -from typing import ClassVar - -from telegram import constants -from telegram.utils.deprecate import set_new_attribute_deprecated - - -class ParseMode: - """This object represents a Telegram Message Parse Modes.""" - - __slots__ = ('__dict__',) - - MARKDOWN: ClassVar[str] = constants.PARSEMODE_MARKDOWN - """:const:`telegram.constants.PARSEMODE_MARKDOWN`\n - - Note: - :attr:`MARKDOWN` is a legacy mode, retained by Telegram for backward compatibility. - You should use :attr:`MARKDOWN_V2` instead. - """ - MARKDOWN_V2: ClassVar[str] = constants.PARSEMODE_MARKDOWN_V2 - """:const:`telegram.constants.PARSEMODE_MARKDOWN_V2`""" - HTML: ClassVar[str] = constants.PARSEMODE_HTML - """:const:`telegram.constants.PARSEMODE_HTML`""" - - def __setattr__(self, key: str, value: object) -> None: - set_new_attribute_deprecated(self, key, value) diff --git a/venv/lib/python3.8/site-packages/telegram/passport/__init__.py b/venv/lib/python3.8/site-packages/telegram/passport/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.8/site-packages/telegram/passport/credentials.py b/venv/lib/python3.8/site-packages/telegram/passport/credentials.py deleted file mode 100644 index 156c79d..0000000 --- a/venv/lib/python3.8/site-packages/telegram/passport/credentials.py +++ /dev/null @@ -1,497 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -# pylint: disable=C0114, W0622 -try: - import ujson as json -except ImportError: - import json # type: ignore[no-redef] - -from base64 import b64decode -from typing import TYPE_CHECKING, Any, List, Optional, Tuple, Union, no_type_check - -try: - from cryptography.hazmat.backends import default_backend - from cryptography.hazmat.primitives.asymmetric.padding import MGF1, OAEP - from cryptography.hazmat.primitives.ciphers import Cipher - from cryptography.hazmat.primitives.ciphers.algorithms import AES - from cryptography.hazmat.primitives.ciphers.modes import CBC - from cryptography.hazmat.primitives.hashes import SHA1, SHA256, SHA512, Hash - - CRYPTO_INSTALLED = True -except ImportError: - default_backend = None - MGF1, OAEP, Cipher, AES, CBC = (None, None, None, None, None) # type: ignore[misc] - SHA1, SHA256, SHA512, Hash = (None, None, None, None) # type: ignore[misc] - - CRYPTO_INSTALLED = False - -from telegram import TelegramError, TelegramObject -from telegram.utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - - -class TelegramDecryptionError(TelegramError): - """Something went wrong with decryption.""" - - __slots__ = ('_msg',) - - def __init__(self, message: Union[str, Exception]): - super().__init__(f"TelegramDecryptionError: {message}") - self._msg = str(message) - - def __reduce__(self) -> Tuple[type, Tuple[str]]: - return self.__class__, (self._msg,) - - -@no_type_check -def decrypt(secret, hash, data): - """ - Decrypt per telegram docs at https://core.telegram.org/passport. - - Args: - secret (:obj:`str` or :obj:`bytes`): The encryption secret, either as bytes or as a - base64 encoded string. - hash (:obj:`str` or :obj:`bytes`): The hash, either as bytes or as a - base64 encoded string. - data (:obj:`str` or :obj:`bytes`): The data to decrypt, either as bytes or as a - base64 encoded string. - file (:obj:`bool`): Force data to be treated as raw data, instead of trying to - b64decode it. - - Raises: - :class:`TelegramDecryptionError`: Given hash does not match hash of decrypted data. - - Returns: - :obj:`bytes`: The decrypted data as bytes. - - """ - if not CRYPTO_INSTALLED: - raise RuntimeError( - 'To use Telegram Passports, PTB must be installed via `pip install ' - 'python-telegram-bot[passport]`.' - ) - # Make a SHA512 hash of secret + update - digest = Hash(SHA512(), backend=default_backend()) - digest.update(secret + hash) - secret_hash_hash = digest.finalize() - # First 32 chars is our key, next 16 is the initialisation vector - key, init_vector = secret_hash_hash[:32], secret_hash_hash[32 : 32 + 16] - # Init a AES-CBC cipher and decrypt the data - cipher = Cipher(AES(key), CBC(init_vector), backend=default_backend()) - decryptor = cipher.decryptor() - data = decryptor.update(data) + decryptor.finalize() - # Calculate SHA256 hash of the decrypted data - digest = Hash(SHA256(), backend=default_backend()) - digest.update(data) - data_hash = digest.finalize() - # If the newly calculated hash did not match the one telegram gave us - if data_hash != hash: - # Raise a error that is caught inside telegram.PassportData and transformed into a warning - raise TelegramDecryptionError(f"Hashes are not equal! {data_hash} != {hash}") - # Return data without padding - return data[data[0] :] - - -@no_type_check -def decrypt_json(secret, hash, data): - """Decrypts data using secret and hash and then decodes utf-8 string and loads json""" - return json.loads(decrypt(secret, hash, data).decode('utf-8')) - - -class EncryptedCredentials(TelegramObject): - """Contains data required for decrypting and authenticating EncryptedPassportElement. See the - Telegram Passport Documentation for a complete description of the data decryption and - authentication processes. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`data`, :attr:`hash` and :attr:`secret` are equal. - - Note: - This object is decrypted only when originating from - :obj:`telegram.PassportData.decrypted_credentials`. - - Args: - data (:class:`telegram.Credentials` or :obj:`str`): Decrypted data with unique user's - nonce, data hashes and secrets used for EncryptedPassportElement decryption and - authentication or base64 encrypted data. - hash (:obj:`str`): Base64-encoded data hash for data authentication. - secret (:obj:`str`): Decrypted or encrypted secret used for decryption. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - data (:class:`telegram.Credentials` or :obj:`str`): Decrypted data with unique user's - nonce, data hashes and secrets used for EncryptedPassportElement decryption and - authentication or base64 encrypted data. - hash (:obj:`str`): Base64-encoded data hash for data authentication. - secret (:obj:`str`): Decrypted or encrypted secret used for decryption. - - """ - - __slots__ = ( - 'hash', - 'secret', - 'bot', - 'data', - '_id_attrs', - '_decrypted_secret', - '_decrypted_data', - ) - - def __init__(self, data: str, hash: str, secret: str, bot: 'Bot' = None, **_kwargs: Any): - # Required - self.data = data - self.hash = hash - self.secret = secret - - self._id_attrs = (self.data, self.hash, self.secret) - - self.bot = bot - self._decrypted_secret = None - self._decrypted_data: Optional['Credentials'] = None - - @property - def decrypted_secret(self) -> str: - """ - :obj:`str`: Lazily decrypt and return secret. - - Raises: - telegram.TelegramDecryptionError: Decryption failed. Usually due to bad - private/public key but can also suggest malformed/tampered data. - """ - if self._decrypted_secret is None: - if not CRYPTO_INSTALLED: - raise RuntimeError( - 'To use Telegram Passports, PTB must be installed via `pip install ' - 'python-telegram-bot[passport]`.' - ) - # Try decrypting according to step 1 at - # https://core.telegram.org/passport#decrypting-data - # We make sure to base64 decode the secret first. - # Telegram says to use OAEP padding so we do that. The Mask Generation Function - # is the default for OAEP, the algorithm is the default for PHP which is what - # Telegram's backend servers run. - try: - self._decrypted_secret = self.bot.private_key.decrypt( - b64decode(self.secret), - OAEP(mgf=MGF1(algorithm=SHA1()), algorithm=SHA1(), label=None), # skipcq - ) - except ValueError as exception: - # If decryption fails raise exception - raise TelegramDecryptionError(exception) from exception - return self._decrypted_secret - - @property - def decrypted_data(self) -> 'Credentials': - """ - :class:`telegram.Credentials`: Lazily decrypt and return credentials data. This object - also contains the user specified nonce as - `decrypted_data.nonce`. - - Raises: - telegram.TelegramDecryptionError: Decryption failed. Usually due to bad - private/public key but can also suggest malformed/tampered data. - """ - if self._decrypted_data is None: - self._decrypted_data = Credentials.de_json( - decrypt_json(self.decrypted_secret, b64decode(self.hash), b64decode(self.data)), - self.bot, - ) - return self._decrypted_data - - -class Credentials(TelegramObject): - """ - Attributes: - secure_data (:class:`telegram.SecureData`): Credentials for encrypted data - nonce (:obj:`str`): Bot-specified nonce - """ - - __slots__ = ('bot', 'nonce', 'secure_data') - - def __init__(self, secure_data: 'SecureData', nonce: str, bot: 'Bot' = None, **_kwargs: Any): - # Required - self.secure_data = secure_data - self.nonce = nonce - - self.bot = bot - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Credentials']: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data['secure_data'] = SecureData.de_json(data.get('secure_data'), bot=bot) - - return cls(bot=bot, **data) - - -class SecureData(TelegramObject): - """ - This object represents the credentials that were used to decrypt the encrypted data. - All fields are optional and depend on fields that were requested. - - Attributes: - personal_details (:class:`telegram.SecureValue`, optional): Credentials for encrypted - personal details. - passport (:class:`telegram.SecureValue`, optional): Credentials for encrypted passport. - internal_passport (:class:`telegram.SecureValue`, optional): Credentials for encrypted - internal passport. - driver_license (:class:`telegram.SecureValue`, optional): Credentials for encrypted - driver license. - identity_card (:class:`telegram.SecureValue`, optional): Credentials for encrypted ID card - address (:class:`telegram.SecureValue`, optional): Credentials for encrypted - residential address. - utility_bill (:class:`telegram.SecureValue`, optional): Credentials for encrypted - utility bill. - bank_statement (:class:`telegram.SecureValue`, optional): Credentials for encrypted - bank statement. - rental_agreement (:class:`telegram.SecureValue`, optional): Credentials for encrypted - rental agreement. - passport_registration (:class:`telegram.SecureValue`, optional): Credentials for encrypted - registration from internal passport. - temporary_registration (:class:`telegram.SecureValue`, optional): Credentials for encrypted - temporary registration. - """ - - __slots__ = ( - 'bot', - 'utility_bill', - 'personal_details', - 'temporary_registration', - 'address', - 'driver_license', - 'rental_agreement', - 'internal_passport', - 'identity_card', - 'bank_statement', - 'passport', - 'passport_registration', - ) - - def __init__( - self, - personal_details: 'SecureValue' = None, - passport: 'SecureValue' = None, - internal_passport: 'SecureValue' = None, - driver_license: 'SecureValue' = None, - identity_card: 'SecureValue' = None, - address: 'SecureValue' = None, - utility_bill: 'SecureValue' = None, - bank_statement: 'SecureValue' = None, - rental_agreement: 'SecureValue' = None, - passport_registration: 'SecureValue' = None, - temporary_registration: 'SecureValue' = None, - bot: 'Bot' = None, - **_kwargs: Any, - ): - # Optionals - self.temporary_registration = temporary_registration - self.passport_registration = passport_registration - self.rental_agreement = rental_agreement - self.bank_statement = bank_statement - self.utility_bill = utility_bill - self.address = address - self.identity_card = identity_card - self.driver_license = driver_license - self.internal_passport = internal_passport - self.passport = passport - self.personal_details = personal_details - - self.bot = bot - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['SecureData']: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data['temporary_registration'] = SecureValue.de_json( - data.get('temporary_registration'), bot=bot - ) - data['passport_registration'] = SecureValue.de_json( - data.get('passport_registration'), bot=bot - ) - data['rental_agreement'] = SecureValue.de_json(data.get('rental_agreement'), bot=bot) - data['bank_statement'] = SecureValue.de_json(data.get('bank_statement'), bot=bot) - data['utility_bill'] = SecureValue.de_json(data.get('utility_bill'), bot=bot) - data['address'] = SecureValue.de_json(data.get('address'), bot=bot) - data['identity_card'] = SecureValue.de_json(data.get('identity_card'), bot=bot) - data['driver_license'] = SecureValue.de_json(data.get('driver_license'), bot=bot) - data['internal_passport'] = SecureValue.de_json(data.get('internal_passport'), bot=bot) - data['passport'] = SecureValue.de_json(data.get('passport'), bot=bot) - data['personal_details'] = SecureValue.de_json(data.get('personal_details'), bot=bot) - - return cls(bot=bot, **data) - - -class SecureValue(TelegramObject): - """ - This object represents the credentials that were used to decrypt the encrypted value. - All fields are optional and depend on the type of field. - - Attributes: - data (:class:`telegram.DataCredentials`, optional): Credentials for encrypted Telegram - Passport data. Available for "personal_details", "passport", "driver_license", - "identity_card", "identity_passport" and "address" types. - front_side (:class:`telegram.FileCredentials`, optional): Credentials for encrypted - document's front side. Available for "passport", "driver_license", "identity_card" - and "internal_passport". - reverse_side (:class:`telegram.FileCredentials`, optional): Credentials for encrypted - document's reverse side. Available for "driver_license" and "identity_card". - selfie (:class:`telegram.FileCredentials`, optional): Credentials for encrypted selfie - of the user with a document. Can be available for "passport", "driver_license", - "identity_card" and "internal_passport". - translation (List[:class:`telegram.FileCredentials`], optional): Credentials for an - encrypted translation of the document. Available for "passport", "driver_license", - "identity_card", "internal_passport", "utility_bill", "bank_statement", - "rental_agreement", "passport_registration" and "temporary_registration". - files (List[:class:`telegram.FileCredentials`], optional): Credentials for encrypted - files. Available for "utility_bill", "bank_statement", "rental_agreement", - "passport_registration" and "temporary_registration" types. - - """ - - __slots__ = ('data', 'front_side', 'reverse_side', 'selfie', 'files', 'translation', 'bot') - - def __init__( - self, - data: 'DataCredentials' = None, - front_side: 'FileCredentials' = None, - reverse_side: 'FileCredentials' = None, - selfie: 'FileCredentials' = None, - files: List['FileCredentials'] = None, - translation: List['FileCredentials'] = None, - bot: 'Bot' = None, - **_kwargs: Any, - ): - self.data = data - self.front_side = front_side - self.reverse_side = reverse_side - self.selfie = selfie - self.files = files - self.translation = translation - - self.bot = bot - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['SecureValue']: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data['data'] = DataCredentials.de_json(data.get('data'), bot=bot) - data['front_side'] = FileCredentials.de_json(data.get('front_side'), bot=bot) - data['reverse_side'] = FileCredentials.de_json(data.get('reverse_side'), bot=bot) - data['selfie'] = FileCredentials.de_json(data.get('selfie'), bot=bot) - data['files'] = FileCredentials.de_list(data.get('files'), bot=bot) - data['translation'] = FileCredentials.de_list(data.get('translation'), bot=bot) - - return cls(bot=bot, **data) - - def to_dict(self) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict() - - data['files'] = [p.to_dict() for p in self.files] - data['translation'] = [p.to_dict() for p in self.translation] - - return data - - -class _CredentialsBase(TelegramObject): - """Base class for DataCredentials and FileCredentials.""" - - __slots__ = ('hash', 'secret', 'file_hash', 'data_hash', 'bot') - - def __init__(self, hash: str, secret: str, bot: 'Bot' = None, **_kwargs: Any): - self.hash = hash - self.secret = secret - - # Aliases just be be sure - self.file_hash = self.hash - self.data_hash = self.hash - - self.bot = bot - - -class DataCredentials(_CredentialsBase): - """ - These credentials can be used to decrypt encrypted data from the data field in - EncryptedPassportData. - - Args: - data_hash (:obj:`str`): Checksum of encrypted data - secret (:obj:`str`): Secret of encrypted data - - Attributes: - hash (:obj:`str`): Checksum of encrypted data - secret (:obj:`str`): Secret of encrypted data - """ - - __slots__ = () - - def __init__(self, data_hash: str, secret: str, **_kwargs: Any): - super().__init__(data_hash, secret, **_kwargs) - - def to_dict(self) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict() - - del data['file_hash'] - del data['hash'] - - return data - - -class FileCredentials(_CredentialsBase): - """ - These credentials can be used to decrypt encrypted files from the front_side, - reverse_side, selfie and files fields in EncryptedPassportData. - - Args: - file_hash (:obj:`str`): Checksum of encrypted file - secret (:obj:`str`): Secret of encrypted file - - Attributes: - hash (:obj:`str`): Checksum of encrypted file - secret (:obj:`str`): Secret of encrypted file - """ - - __slots__ = () - - def __init__(self, file_hash: str, secret: str, **_kwargs: Any): - super().__init__(file_hash, secret, **_kwargs) - - def to_dict(self) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict() - - del data['data_hash'] - del data['hash'] - - return data diff --git a/venv/lib/python3.8/site-packages/telegram/passport/data.py b/venv/lib/python3.8/site-packages/telegram/passport/data.py deleted file mode 100644 index b17f5d8..0000000 --- a/venv/lib/python3.8/site-packages/telegram/passport/data.py +++ /dev/null @@ -1,153 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -# pylint: disable=C0114 -from typing import TYPE_CHECKING, Any - -from telegram import TelegramObject - -if TYPE_CHECKING: - from telegram import Bot - - -class PersonalDetails(TelegramObject): - """ - This object represents personal details. - - Attributes: - first_name (:obj:`str`): First Name. - middle_name (:obj:`str`): Optional. First Name. - last_name (:obj:`str`): Last Name. - birth_date (:obj:`str`): Date of birth in DD.MM.YYYY format. - gender (:obj:`str`): Gender, male or female. - country_code (:obj:`str`): Citizenship (ISO 3166-1 alpha-2 country code). - residence_country_code (:obj:`str`): Country of residence (ISO 3166-1 alpha-2 country - code). - first_name_native (:obj:`str`): First Name in the language of the user's country of - residence. - middle_name_native (:obj:`str`): Optional. Middle Name in the language of the user's - country of residence. - last_name_native (:obj:`str`): Last Name in the language of the user's country of - residence. - """ - - __slots__ = ( - 'middle_name', - 'first_name_native', - 'last_name_native', - 'residence_country_code', - 'first_name', - 'last_name', - 'country_code', - 'gender', - 'bot', - 'middle_name_native', - 'birth_date', - ) - - def __init__( - self, - first_name: str, - last_name: str, - birth_date: str, - gender: str, - country_code: str, - residence_country_code: str, - first_name_native: str = None, - last_name_native: str = None, - middle_name: str = None, - middle_name_native: str = None, - bot: 'Bot' = None, - **_kwargs: Any, - ): - # Required - self.first_name = first_name - self.last_name = last_name - self.middle_name = middle_name - self.birth_date = birth_date - self.gender = gender - self.country_code = country_code - self.residence_country_code = residence_country_code - self.first_name_native = first_name_native - self.last_name_native = last_name_native - self.middle_name_native = middle_name_native - - self.bot = bot - - -class ResidentialAddress(TelegramObject): - """ - This object represents a residential address. - - Attributes: - street_line1 (:obj:`str`): First line for the address. - street_line2 (:obj:`str`): Optional. Second line for the address. - city (:obj:`str`): City. - state (:obj:`str`): Optional. State. - country_code (:obj:`str`): ISO 3166-1 alpha-2 country code. - post_code (:obj:`str`): Address post code. - """ - - __slots__ = ( - 'post_code', - 'city', - 'country_code', - 'street_line2', - 'street_line1', - 'bot', - 'state', - ) - - def __init__( - self, - street_line1: str, - street_line2: str, - city: str, - state: str, - country_code: str, - post_code: str, - bot: 'Bot' = None, - **_kwargs: Any, - ): - # Required - self.street_line1 = street_line1 - self.street_line2 = street_line2 - self.city = city - self.state = state - self.country_code = country_code - self.post_code = post_code - - self.bot = bot - - -class IdDocumentData(TelegramObject): - """ - This object represents the data of an identity document. - - Attributes: - document_no (:obj:`str`): Document number. - expiry_date (:obj:`str`): Optional. Date of expiry, in DD.MM.YYYY format. - """ - - __slots__ = ('document_no', 'bot', 'expiry_date') - - def __init__(self, document_no: str, expiry_date: str, bot: 'Bot' = None, **_kwargs: Any): - self.document_no = document_no - self.expiry_date = expiry_date - - self.bot = bot diff --git a/venv/lib/python3.8/site-packages/telegram/passport/encryptedpassportelement.py b/venv/lib/python3.8/site-packages/telegram/passport/encryptedpassportelement.py deleted file mode 100644 index 74e3aaf..0000000 --- a/venv/lib/python3.8/site-packages/telegram/passport/encryptedpassportelement.py +++ /dev/null @@ -1,266 +0,0 @@ -#!/usr/bin/env python -# flake8: noqa: E501 -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram EncryptedPassportElement.""" -from base64 import b64decode -from typing import TYPE_CHECKING, Any, List, Optional - -from telegram import ( - IdDocumentData, - PassportFile, - PersonalDetails, - ResidentialAddress, - TelegramObject, -) -from telegram.passport.credentials import decrypt_json -from telegram.utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot, Credentials - - -class EncryptedPassportElement(TelegramObject): - """ - Contains information about documents or other Telegram Passport elements shared with the bot - by the user. The data has been automatically decrypted by python-telegram-bot. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`type`, :attr:`data`, :attr:`phone_number`, :attr:`email`, - :attr:`files`, :attr:`front_side`, :attr:`reverse_side` and :attr:`selfie` are equal. - - Note: - This object is decrypted only when originating from - :obj:`telegram.PassportData.decrypted_data`. - - Args: - type (:obj:`str`): Element type. One of "personal_details", "passport", "driver_license", - "identity_card", "internal_passport", "address", "utility_bill", "bank_statement", - "rental_agreement", "passport_registration", "temporary_registration", "phone_number", - "email". - data (:class:`telegram.PersonalDetails` | :class:`telegram.IdDocument` | \ - :class:`telegram.ResidentialAddress` | :obj:`str`, optional): - Decrypted or encrypted data, available for "personal_details", "passport", - "driver_license", "identity_card", "identity_passport" and "address" types. - phone_number (:obj:`str`, optional): User's verified phone number, available only for - "phone_number" type. - email (:obj:`str`, optional): User's verified email address, available only for "email" - type. - files (List[:class:`telegram.PassportFile`], optional): Array of encrypted/decrypted files - with documents provided by the user, available for "utility_bill", "bank_statement", - "rental_agreement", "passport_registration" and "temporary_registration" types. - front_side (:class:`telegram.PassportFile`, optional): Encrypted/decrypted file with the - front side of the document, provided by the user. Available for "passport", - "driver_license", "identity_card" and "internal_passport". - reverse_side (:class:`telegram.PassportFile`, optional): Encrypted/decrypted file with the - reverse side of the document, provided by the user. Available for "driver_license" and - "identity_card". - selfie (:class:`telegram.PassportFile`, optional): Encrypted/decrypted file with the - selfie of the user holding a document, provided by the user; available for "passport", - "driver_license", "identity_card" and "internal_passport". - translation (List[:class:`telegram.PassportFile`], optional): Array of encrypted/decrypted - files with translated versions of documents provided by the user. Available if - requested for "passport", "driver_license", "identity_card", "internal_passport", - "utility_bill", "bank_statement", "rental_agreement", "passport_registration" and - "temporary_registration" types. - hash (:obj:`str`): Base64-encoded element hash for using in - :class:`telegram.PassportElementErrorUnspecified`. - bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - type (:obj:`str`): Element type. One of "personal_details", "passport", "driver_license", - "identity_card", "internal_passport", "address", "utility_bill", "bank_statement", - "rental_agreement", "passport_registration", "temporary_registration", "phone_number", - "email". - data (:class:`telegram.PersonalDetails` | :class:`telegram.IdDocument` | \ - :class:`telegram.ResidentialAddress` | :obj:`str`): - Optional. Decrypted or encrypted data, available for "personal_details", "passport", - "driver_license", "identity_card", "identity_passport" and "address" types. - phone_number (:obj:`str`): Optional. User's verified phone number, available only for - "phone_number" type. - email (:obj:`str`): Optional. User's verified email address, available only for "email" - type. - files (List[:class:`telegram.PassportFile`]): Optional. Array of encrypted/decrypted files - with documents provided by the user, available for "utility_bill", "bank_statement", - "rental_agreement", "passport_registration" and "temporary_registration" types. - front_side (:class:`telegram.PassportFile`): Optional. Encrypted/decrypted file with the - front side of the document, provided by the user. Available for "passport", - "driver_license", "identity_card" and "internal_passport". - reverse_side (:class:`telegram.PassportFile`): Optional. Encrypted/decrypted file with the - reverse side of the document, provided by the user. Available for "driver_license" and - "identity_card". - selfie (:class:`telegram.PassportFile`): Optional. Encrypted/decrypted file with the - selfie of the user holding a document, provided by the user; available for "passport", - "driver_license", "identity_card" and "internal_passport". - translation (List[:class:`telegram.PassportFile`]): Optional. Array of encrypted/decrypted - files with translated versions of documents provided by the user. Available if - requested for "passport", "driver_license", "identity_card", "internal_passport", - "utility_bill", "bank_statement", "rental_agreement", "passport_registration" and - "temporary_registration" types. - hash (:obj:`str`): Base64-encoded element hash for using in - :class:`telegram.PassportElementErrorUnspecified`. - bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods. - - """ - - __slots__ = ( - 'selfie', - 'files', - 'type', - 'translation', - 'email', - 'hash', - 'phone_number', - 'bot', - 'reverse_side', - 'front_side', - 'data', - '_id_attrs', - ) - - def __init__( - self, - type: str, # pylint: disable=W0622 - data: PersonalDetails = None, - phone_number: str = None, - email: str = None, - files: List[PassportFile] = None, - front_side: PassportFile = None, - reverse_side: PassportFile = None, - selfie: PassportFile = None, - translation: List[PassportFile] = None, - hash: str = None, # pylint: disable=W0622 - bot: 'Bot' = None, - credentials: 'Credentials' = None, # pylint: disable=W0613 - **_kwargs: Any, - ): - # Required - self.type = type - # Optionals - self.data = data - self.phone_number = phone_number - self.email = email - self.files = files - self.front_side = front_side - self.reverse_side = reverse_side - self.selfie = selfie - self.translation = translation - self.hash = hash - - self._id_attrs = ( - self.type, - self.data, - self.phone_number, - self.email, - self.files, - self.front_side, - self.reverse_side, - self.selfie, - ) - - self.bot = bot - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['EncryptedPassportElement']: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data['files'] = PassportFile.de_list(data.get('files'), bot) or None - data['front_side'] = PassportFile.de_json(data.get('front_side'), bot) - data['reverse_side'] = PassportFile.de_json(data.get('reverse_side'), bot) - data['selfie'] = PassportFile.de_json(data.get('selfie'), bot) - data['translation'] = PassportFile.de_list(data.get('translation'), bot) or None - - return cls(bot=bot, **data) - - @classmethod - def de_json_decrypted( - cls, data: Optional[JSONDict], bot: 'Bot', credentials: 'Credentials' - ) -> Optional['EncryptedPassportElement']: - """Variant of :meth:`telegram.TelegramObject.de_json` that also takes into account - passport credentials. - - Args: - data (Dict[:obj:`str`, ...]): The JSON data. - bot (:class:`telegram.Bot`): The bot associated with this object. - credentials (:class:`telegram.FileCredentials`): The credentials - - Returns: - :class:`telegram.EncryptedPassportElement`: - - """ - if not data: - return None - - if data['type'] not in ('phone_number', 'email'): - secure_data = getattr(credentials.secure_data, data['type']) - - if secure_data.data is not None: - # If not already decrypted - if not isinstance(data['data'], dict): - data['data'] = decrypt_json( - b64decode(secure_data.data.secret), - b64decode(secure_data.data.hash), - b64decode(data['data']), - ) - if data['type'] == 'personal_details': - data['data'] = PersonalDetails.de_json(data['data'], bot=bot) - elif data['type'] in ( - 'passport', - 'internal_passport', - 'driver_license', - 'identity_card', - ): - data['data'] = IdDocumentData.de_json(data['data'], bot=bot) - elif data['type'] == 'address': - data['data'] = ResidentialAddress.de_json(data['data'], bot=bot) - - data['files'] = ( - PassportFile.de_list_decrypted(data.get('files'), bot, secure_data.files) or None - ) - data['front_side'] = PassportFile.de_json_decrypted( - data.get('front_side'), bot, secure_data.front_side - ) - data['reverse_side'] = PassportFile.de_json_decrypted( - data.get('reverse_side'), bot, secure_data.reverse_side - ) - data['selfie'] = PassportFile.de_json_decrypted( - data.get('selfie'), bot, secure_data.selfie - ) - data['translation'] = ( - PassportFile.de_list_decrypted( - data.get('translation'), bot, secure_data.translation - ) - or None - ) - - return cls(bot=bot, **data) - - def to_dict(self) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict() - - if self.files: - data['files'] = [p.to_dict() for p in self.files] - if self.translation: - data['translation'] = [p.to_dict() for p in self.translation] - - return data diff --git a/venv/lib/python3.8/site-packages/telegram/passport/passportdata.py b/venv/lib/python3.8/site-packages/telegram/passport/passportdata.py deleted file mode 100644 index a8d1ede..0000000 --- a/venv/lib/python3.8/site-packages/telegram/passport/passportdata.py +++ /dev/null @@ -1,121 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""Contains information about Telegram Passport data shared with the bot by the user.""" - -from typing import TYPE_CHECKING, Any, List, Optional - -from telegram import EncryptedCredentials, EncryptedPassportElement, TelegramObject -from telegram.utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot, Credentials - - -class PassportData(TelegramObject): - """Contains information about Telegram Passport data shared with the bot by the user. - - Note: - To be able to decrypt this object, you must pass your ``private_key`` to either - :class:`telegram.Updater` or :class:`telegram.Bot`. Decrypted data is then found in - :attr:`decrypted_data` and the payload can be found in :attr:`decrypted_credentials`'s - attribute :attr:`telegram.Credentials.payload`. - - Args: - data (List[:class:`telegram.EncryptedPassportElement`]): Array with encrypted information - about documents and other Telegram Passport elements that was shared with the bot. - credentials (:class:`telegram.EncryptedCredentials`)): Encrypted credentials. - bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - data (List[:class:`telegram.EncryptedPassportElement`]): Array with encrypted information - about documents and other Telegram Passport elements that was shared with the bot. - credentials (:class:`telegram.EncryptedCredentials`): Encrypted credentials. - bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods. - - """ - - __slots__ = ('bot', 'credentials', 'data', '_decrypted_data', '_id_attrs') - - def __init__( - self, - data: List[EncryptedPassportElement], - credentials: EncryptedCredentials, - bot: 'Bot' = None, - **_kwargs: Any, - ): - self.data = data - self.credentials = credentials - - self.bot = bot - self._decrypted_data: Optional[List[EncryptedPassportElement]] = None - self._id_attrs = tuple([x.type for x in data] + [credentials.hash]) - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['PassportData']: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data['data'] = EncryptedPassportElement.de_list(data.get('data'), bot) - data['credentials'] = EncryptedCredentials.de_json(data.get('credentials'), bot) - - return cls(bot=bot, **data) - - def to_dict(self) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict() - - data['data'] = [e.to_dict() for e in self.data] - - return data - - @property - def decrypted_data(self) -> List[EncryptedPassportElement]: - """ - List[:class:`telegram.EncryptedPassportElement`]: Lazily decrypt and return information - about documents and other Telegram Passport elements which were shared with the bot. - - Raises: - telegram.TelegramDecryptionError: Decryption failed. Usually due to bad - private/public key but can also suggest malformed/tampered data. - """ - if self._decrypted_data is None: - self._decrypted_data = [ - EncryptedPassportElement.de_json_decrypted( - element.to_dict(), self.bot, self.decrypted_credentials - ) - for element in self.data - ] - return self._decrypted_data - - @property - def decrypted_credentials(self) -> 'Credentials': - """ - :class:`telegram.Credentials`: Lazily decrypt and return credentials that were used - to decrypt the data. This object also contains the user specified payload as - `decrypted_data.payload`. - - Raises: - telegram.TelegramDecryptionError: Decryption failed. Usually due to bad - private/public key but can also suggest malformed/tampered data. - """ - return self.credentials.decrypted_data diff --git a/venv/lib/python3.8/site-packages/telegram/passport/passportelementerrors.py b/venv/lib/python3.8/site-packages/telegram/passport/passportelementerrors.py deleted file mode 100644 index 4d61f96..0000000 --- a/venv/lib/python3.8/site-packages/telegram/passport/passportelementerrors.py +++ /dev/null @@ -1,382 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -# pylint: disable=W0622 -"""This module contains the classes that represent Telegram PassportElementError.""" - -from typing import Any - -from telegram import TelegramObject - - -class PassportElementError(TelegramObject): - """Baseclass for the PassportElementError* classes. - - This object represents an error in the Telegram Passport element which was submitted that - should be resolved by the user. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`source` and :attr:`type` are equal. - - Args: - source (:obj:`str`): Error source. - type (:obj:`str`): The section of the user's Telegram Passport which has the error. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - source (:obj:`str`): Error source. - type (:obj:`str`): The section of the user's Telegram Passport which has the error. - message (:obj:`str`): Error message. - - """ - - # All subclasses of this class won't have _id_attrs in slots since it's added here. - __slots__ = ('message', 'source', 'type', '_id_attrs') - - def __init__(self, source: str, type: str, message: str, **_kwargs: Any): - # Required - self.source = str(source) - self.type = str(type) - self.message = str(message) - - self._id_attrs = (self.source, self.type) - - -class PassportElementErrorDataField(PassportElementError): - """ - Represents an issue in one of the data fields that was provided by the user. The error is - considered resolved when the field's value changes. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`source`, :attr:`type`, :attr:`field_name`, :attr:`data_hash` - and :attr:`message` are equal. - - Args: - type (:obj:`str`): The section of the user's Telegram Passport which has the error, one of - ``"personal_details"``, ``"passport"``, ``"driver_license"``, ``"identity_card"``, - ``"internal_passport"``, ``"address"``. - field_name (:obj:`str`): Name of the data field which has the error. - data_hash (:obj:`str`): Base64-encoded data hash. - message (:obj:`str`): Error message. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - type (:obj:`str`): The section of the user's Telegram Passport which has the error, one of - ``"personal_details"``, ``"passport"``, ``"driver_license"``, ``"identity_card"``, - ``"internal_passport"``, ``"address"``. - field_name (:obj:`str`): Name of the data field which has the error. - data_hash (:obj:`str`): Base64-encoded data hash. - message (:obj:`str`): Error message. - - """ - - __slots__ = ('data_hash', 'field_name') - - def __init__(self, type: str, field_name: str, data_hash: str, message: str, **_kwargs: Any): - # Required - super().__init__('data', type, message) - self.field_name = field_name - self.data_hash = data_hash - - self._id_attrs = (self.source, self.type, self.field_name, self.data_hash, self.message) - - -class PassportElementErrorFile(PassportElementError): - """ - Represents an issue with a document scan. The error is considered resolved when the file with - the document scan changes. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`source`, :attr:`type`, :attr:`file_hash`, and - :attr:`message` are equal. - - Args: - type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of - ``"utility_bill"``, ``"bank_statement"``, ``"rental_agreement"``, - ``"passport_registration"``, ``"temporary_registration"``. - file_hash (:obj:`str`): Base64-encoded file hash. - message (:obj:`str`): Error message. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of - ``"utility_bill"``, ``"bank_statement"``, ``"rental_agreement"``, - ``"passport_registration"``, ``"temporary_registration"``. - file_hash (:obj:`str`): Base64-encoded file hash. - message (:obj:`str`): Error message. - - """ - - __slots__ = ('file_hash',) - - def __init__(self, type: str, file_hash: str, message: str, **_kwargs: Any): - # Required - super().__init__('file', type, message) - self.file_hash = file_hash - - self._id_attrs = (self.source, self.type, self.file_hash, self.message) - - -class PassportElementErrorFiles(PassportElementError): - """ - Represents an issue with a list of scans. The error is considered resolved when the list of - files with the document scans changes. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`source`, :attr:`type`, :attr:`file_hashes`, and - :attr:`message` are equal. - - Args: - type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of - ``"utility_bill"``, ``"bank_statement"``, ``"rental_agreement"``, - ``"passport_registration"``, ``"temporary_registration"``. - file_hashes (List[:obj:`str`]): List of base64-encoded file hashes. - message (:obj:`str`): Error message. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of - ``"utility_bill"``, ``"bank_statement"``, ``"rental_agreement"``, - ``"passport_registration"``, ``"temporary_registration"``. - file_hashes (List[:obj:`str`]): List of base64-encoded file hashes. - message (:obj:`str`): Error message. - - """ - - __slots__ = ('file_hashes',) - - def __init__(self, type: str, file_hashes: str, message: str, **_kwargs: Any): - # Required - super().__init__('files', type, message) - self.file_hashes = file_hashes - - self._id_attrs = (self.source, self.type, self.message) + tuple(file_hashes) - - -class PassportElementErrorFrontSide(PassportElementError): - """ - Represents an issue with the front side of a document. The error is considered resolved when - the file with the front side of the document changes. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`source`, :attr:`type`, :attr:`file_hash`, and - :attr:`message` are equal. - - Args: - type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of - ``"passport"``, ``"driver_license"``, ``"identity_card"``, ``"internal_passport"``. - file_hash (:obj:`str`): Base64-encoded hash of the file with the front side of the - document. - message (:obj:`str`): Error message. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of - ``"passport"``, ``"driver_license"``, ``"identity_card"``, ``"internal_passport"``. - file_hash (:obj:`str`): Base64-encoded hash of the file with the front side of the - document. - message (:obj:`str`): Error message. - - """ - - __slots__ = ('file_hash',) - - def __init__(self, type: str, file_hash: str, message: str, **_kwargs: Any): - # Required - super().__init__('front_side', type, message) - self.file_hash = file_hash - - self._id_attrs = (self.source, self.type, self.file_hash, self.message) - - -class PassportElementErrorReverseSide(PassportElementError): - """ - Represents an issue with the reverse side of a document. The error is considered resolved when - the file with the reverse side of the document changes. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`source`, :attr:`type`, :attr:`file_hash`, and - :attr:`message` are equal. - - Args: - type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of - ``"driver_license"``, ``"identity_card"``. - file_hash (:obj:`str`): Base64-encoded hash of the file with the reverse side of the - document. - message (:obj:`str`): Error message. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of - ``"driver_license"``, ``"identity_card"``. - file_hash (:obj:`str`): Base64-encoded hash of the file with the reverse side of the - document. - message (:obj:`str`): Error message. - - """ - - __slots__ = ('file_hash',) - - def __init__(self, type: str, file_hash: str, message: str, **_kwargs: Any): - # Required - super().__init__('reverse_side', type, message) - self.file_hash = file_hash - - self._id_attrs = (self.source, self.type, self.file_hash, self.message) - - -class PassportElementErrorSelfie(PassportElementError): - """ - Represents an issue with the selfie with a document. The error is considered resolved when - the file with the selfie changes. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`source`, :attr:`type`, :attr:`file_hash`, and - :attr:`message` are equal. - - Args: - type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of - ``"passport"``, ``"driver_license"``, ``"identity_card"``, ``"internal_passport"``. - file_hash (:obj:`str`): Base64-encoded hash of the file with the selfie. - message (:obj:`str`): Error message. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - type (:obj:`str`): The section of the user's Telegram Passport which has the issue, one of - ``"passport"``, ``"driver_license"``, ``"identity_card"``, ``"internal_passport"``. - file_hash (:obj:`str`): Base64-encoded hash of the file with the selfie. - message (:obj:`str`): Error message. - - """ - - __slots__ = ('file_hash',) - - def __init__(self, type: str, file_hash: str, message: str, **_kwargs: Any): - # Required - super().__init__('selfie', type, message) - self.file_hash = file_hash - - self._id_attrs = (self.source, self.type, self.file_hash, self.message) - - -class PassportElementErrorTranslationFile(PassportElementError): - """ - Represents an issue with one of the files that constitute the translation of a document. - The error is considered resolved when the file changes. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`source`, :attr:`type`, :attr:`file_hash`, and - :attr:`message` are equal. - - Args: - type (:obj:`str`): Type of element of the user's Telegram Passport which has the issue, - one of ``"passport"``, ``"driver_license"``, ``"identity_card"``, - ``"internal_passport"``, ``"utility_bill"``, ``"bank_statement"``, - ``"rental_agreement"``, ``"passport_registration"``, ``"temporary_registration"``. - file_hash (:obj:`str`): Base64-encoded hash of the file. - message (:obj:`str`): Error message. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - type (:obj:`str`): Type of element of the user's Telegram Passport which has the issue, - one of ``"passport"``, ``"driver_license"``, ``"identity_card"``, - ``"internal_passport"``, ``"utility_bill"``, ``"bank_statement"``, - ``"rental_agreement"``, ``"passport_registration"``, ``"temporary_registration"``. - file_hash (:obj:`str`): Base64-encoded hash of the file. - message (:obj:`str`): Error message. - - """ - - __slots__ = ('file_hash',) - - def __init__(self, type: str, file_hash: str, message: str, **_kwargs: Any): - # Required - super().__init__('translation_file', type, message) - self.file_hash = file_hash - - self._id_attrs = (self.source, self.type, self.file_hash, self.message) - - -class PassportElementErrorTranslationFiles(PassportElementError): - """ - Represents an issue with the translated version of a document. The error is considered - resolved when a file with the document translation changes. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`source`, :attr:`type`, :attr:`file_hashes`, and - :attr:`message` are equal. - - Args: - type (:obj:`str`): Type of element of the user's Telegram Passport which has the issue, - one of ``"passport"``, ``"driver_license"``, ``"identity_card"``, - ``"internal_passport"``, ``"utility_bill"``, ``"bank_statement"``, - ``"rental_agreement"``, ``"passport_registration"``, ``"temporary_registration"``. - file_hashes (List[:obj:`str`]): List of base64-encoded file hashes. - message (:obj:`str`): Error message. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - type (:obj:`str`): Type of element of the user's Telegram Passport which has the issue, - one of ``"passport"``, ``"driver_license"``, ``"identity_card"``, - ``"internal_passport"``, ``"utility_bill"``, ``"bank_statement"``, - ``"rental_agreement"``, ``"passport_registration"``, ``"temporary_registration"``. - file_hashes (List[:obj:`str`]): List of base64-encoded file hashes. - message (:obj:`str`): Error message. - - """ - - __slots__ = ('file_hashes',) - - def __init__(self, type: str, file_hashes: str, message: str, **_kwargs: Any): - # Required - super().__init__('translation_files', type, message) - self.file_hashes = file_hashes - - self._id_attrs = (self.source, self.type, self.message) + tuple(file_hashes) - - -class PassportElementErrorUnspecified(PassportElementError): - """ - Represents an issue in an unspecified place. The error is considered resolved when new - data is added. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`source`, :attr:`type`, :attr:`element_hash`, - and :attr:`message` are equal. - - Args: - type (:obj:`str`): Type of element of the user's Telegram Passport which has the issue. - element_hash (:obj:`str`): Base64-encoded element hash. - message (:obj:`str`): Error message. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - type (:obj:`str`): Type of element of the user's Telegram Passport which has the issue. - element_hash (:obj:`str`): Base64-encoded element hash. - message (:obj:`str`): Error message. - - """ - - __slots__ = ('element_hash',) - - def __init__(self, type: str, element_hash: str, message: str, **_kwargs: Any): - # Required - super().__init__('unspecified', type, message) - self.element_hash = element_hash - - self._id_attrs = (self.source, self.type, self.element_hash, self.message) diff --git a/venv/lib/python3.8/site-packages/telegram/passport/passportfile.py b/venv/lib/python3.8/site-packages/telegram/passport/passportfile.py deleted file mode 100644 index b5f2122..0000000 --- a/venv/lib/python3.8/site-packages/telegram/passport/passportfile.py +++ /dev/null @@ -1,160 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Encrypted PassportFile.""" - -from typing import TYPE_CHECKING, Any, List, Optional - -from telegram import TelegramObject -from telegram.utils.helpers import DEFAULT_NONE -from telegram.utils.types import JSONDict, ODVInput - -if TYPE_CHECKING: - from telegram import Bot, File, FileCredentials - - -class PassportFile(TelegramObject): - """ - This object represents a file uploaded to Telegram Passport. Currently all Telegram Passport - files are in JPEG format when decrypted and don't exceed 10MB. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`file_unique_id` is equal. - - Args: - file_id (:obj:`str`): Identifier for this file, which can be used to download - or reuse the file. - file_unique_id (:obj:`str`): Unique identifier for this file, which - is supposed to be the same over time and for different bots. - Can't be used to download or reuse the file. - file_size (:obj:`int`): File size. - file_date (:obj:`int`): Unix time when the file was uploaded. - bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - file_id (:obj:`str`): Identifier for this file. - file_unique_id (:obj:`str`): Unique identifier for this file, which - is supposed to be the same over time and for different bots. - Can't be used to download or reuse the file. - file_size (:obj:`int`): File size. - file_date (:obj:`int`): Unix time when the file was uploaded. - bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods. - - """ - - __slots__ = ( - 'file_date', - 'bot', - 'file_id', - 'file_size', - '_credentials', - 'file_unique_id', - '_id_attrs', - ) - - def __init__( - self, - file_id: str, - file_unique_id: str, - file_date: int, - file_size: int = None, - bot: 'Bot' = None, - credentials: 'FileCredentials' = None, - **_kwargs: Any, - ): - # Required - self.file_id = file_id - self.file_unique_id = file_unique_id - self.file_size = file_size - self.file_date = file_date - # Optionals - self.bot = bot - self._credentials = credentials - - self._id_attrs = (self.file_unique_id,) - - @classmethod - def de_json_decrypted( - cls, data: Optional[JSONDict], bot: 'Bot', credentials: 'FileCredentials' - ) -> Optional['PassportFile']: - """Variant of :meth:`telegram.TelegramObject.de_json` that also takes into account - passport credentials. - - Args: - data (Dict[:obj:`str`, ...]): The JSON data. - bot (:class:`telegram.Bot`): The bot associated with this object. - credentials (:class:`telegram.FileCredentials`): The credentials - - Returns: - :class:`telegram.PassportFile`: - - """ - data = cls._parse_data(data) - - if not data: - return None - - data['credentials'] = credentials - - return cls(bot=bot, **data) - - @classmethod - def de_list_decrypted( - cls, data: Optional[List[JSONDict]], bot: 'Bot', credentials: List['FileCredentials'] - ) -> List[Optional['PassportFile']]: - """Variant of :meth:`telegram.TelegramObject.de_list` that also takes into account - passport credentials. - - Args: - data (Dict[:obj:`str`, ...]): The JSON data. - bot (:class:`telegram.Bot`): The bot associated with these objects. - credentials (:class:`telegram.FileCredentials`): The credentials - - Returns: - List[:class:`telegram.PassportFile`]: - - """ - if not data: - return [] - - return [ - cls.de_json_decrypted(passport_file, bot, credentials[i]) - for i, passport_file in enumerate(data) - ] - - def get_file( - self, timeout: ODVInput[float] = DEFAULT_NONE, api_kwargs: JSONDict = None - ) -> 'File': - """ - Wrapper over :attr:`telegram.Bot.get_file`. Will automatically assign the correct - credentials to the returned :class:`telegram.File` if originating from - :obj:`telegram.PassportData.decrypted_data`. - - For the documentation of the arguments, please see :meth:`telegram.Bot.get_file`. - - Returns: - :class:`telegram.File` - - Raises: - :class:`telegram.error.TelegramError` - - """ - file = self.bot.get_file(file_id=self.file_id, timeout=timeout, api_kwargs=api_kwargs) - file.set_credentials(self._credentials) - return file diff --git a/venv/lib/python3.8/site-packages/telegram/payment/__init__.py b/venv/lib/python3.8/site-packages/telegram/payment/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.8/site-packages/telegram/payment/invoice.py b/venv/lib/python3.8/site-packages/telegram/payment/invoice.py deleted file mode 100644 index dea2740..0000000 --- a/venv/lib/python3.8/site-packages/telegram/payment/invoice.py +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram Invoice.""" - -from typing import Any - -from telegram import TelegramObject - - -class Invoice(TelegramObject): - """This object contains basic information about an invoice. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`title`, :attr:`description`, :attr:`start_parameter`, - :attr:`currency` and :attr:`total_amount` are equal. - - Args: - title (:obj:`str`): Product name. - description (:obj:`str`): Product description. - start_parameter (:obj:`str`): Unique bot deep-linking parameter that can be used to - generate this invoice. - currency (:obj:`str`): Three-letter ISO 4217 currency code. - total_amount (:obj:`int`): Total price in the smallest units of the currency (integer, not - float/double). For example, for a price of US$ 1.45 pass ``amount = 145``. See the - :obj:`exp` parameter in - `currencies.json <https://core.telegram.org/bots/payments/currencies.json>`_, - it shows the number of digits past the decimal point for each currency - (2 for the majority of currencies). - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - title (:obj:`str`): Product name. - description (:obj:`str`): Product description. - start_parameter (:obj:`str`): Unique bot deep-linking parameter. - currency (:obj:`str`): Three-letter ISO 4217 currency code. - total_amount (:obj:`int`): Total price in the smallest units of the currency. - - """ - - __slots__ = ( - 'currency', - 'start_parameter', - 'title', - 'description', - 'total_amount', - '_id_attrs', - ) - - def __init__( - self, - title: str, - description: str, - start_parameter: str, - currency: str, - total_amount: int, - **_kwargs: Any, - ): - self.title = title - self.description = description - self.start_parameter = start_parameter - self.currency = currency - self.total_amount = total_amount - - self._id_attrs = ( - self.title, - self.description, - self.start_parameter, - self.currency, - self.total_amount, - ) diff --git a/venv/lib/python3.8/site-packages/telegram/payment/labeledprice.py b/venv/lib/python3.8/site-packages/telegram/payment/labeledprice.py deleted file mode 100644 index 221c62d..0000000 --- a/venv/lib/python3.8/site-packages/telegram/payment/labeledprice.py +++ /dev/null @@ -1,54 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram LabeledPrice.""" - -from typing import Any - -from telegram import TelegramObject - - -class LabeledPrice(TelegramObject): - """This object represents a portion of the price for goods or services. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`label` and :attr:`amount` are equal. - - Args: - label (:obj:`str`): Portion label. - amount (:obj:`int`): Price of the product in the smallest units of the currency (integer, - not float/double). For example, for a price of US$ 1.45 pass ``amount = 145``. - See the :obj:`exp` parameter in - `currencies.json <https://core.telegram.org/bots/payments/currencies.json>`_, - it shows the number of digits past the decimal point for each currency - (2 for the majority of currencies). - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - label (:obj:`str`): Portion label. - amount (:obj:`int`): Price of the product in the smallest units of the currency. - - """ - - __slots__ = ('label', '_id_attrs', 'amount') - - def __init__(self, label: str, amount: int, **_kwargs: Any): - self.label = label - self.amount = amount - - self._id_attrs = (self.label, self.amount) diff --git a/venv/lib/python3.8/site-packages/telegram/payment/orderinfo.py b/venv/lib/python3.8/site-packages/telegram/payment/orderinfo.py deleted file mode 100644 index 7ebe358..0000000 --- a/venv/lib/python3.8/site-packages/telegram/payment/orderinfo.py +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram OrderInfo.""" - -from typing import TYPE_CHECKING, Any, Optional - -from telegram import ShippingAddress, TelegramObject -from telegram.utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - - -class OrderInfo(TelegramObject): - """This object represents information about an order. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`name`, :attr:`phone_number`, :attr:`email` and - :attr:`shipping_address` are equal. - - Args: - name (:obj:`str`, optional): User name. - phone_number (:obj:`str`, optional): User's phone number. - email (:obj:`str`, optional): User email. - shipping_address (:class:`telegram.ShippingAddress`, optional): User shipping address. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - name (:obj:`str`): Optional. User name. - phone_number (:obj:`str`): Optional. User's phone number. - email (:obj:`str`): Optional. User email. - shipping_address (:class:`telegram.ShippingAddress`): Optional. User shipping address. - - """ - - __slots__ = ('email', 'shipping_address', 'phone_number', 'name', '_id_attrs') - - def __init__( - self, - name: str = None, - phone_number: str = None, - email: str = None, - shipping_address: str = None, - **_kwargs: Any, - ): - self.name = name - self.phone_number = phone_number - self.email = email - self.shipping_address = shipping_address - - self._id_attrs = (self.name, self.phone_number, self.email, self.shipping_address) - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['OrderInfo']: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return cls() - - data['shipping_address'] = ShippingAddress.de_json(data.get('shipping_address'), bot) - - return cls(**data) diff --git a/venv/lib/python3.8/site-packages/telegram/payment/precheckoutquery.py b/venv/lib/python3.8/site-packages/telegram/payment/precheckoutquery.py deleted file mode 100644 index a8f2eb2..0000000 --- a/venv/lib/python3.8/site-packages/telegram/payment/precheckoutquery.py +++ /dev/null @@ -1,140 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram PreCheckoutQuery.""" - -from typing import TYPE_CHECKING, Any, Optional - -from telegram import OrderInfo, TelegramObject, User -from telegram.utils.helpers import DEFAULT_NONE -from telegram.utils.types import JSONDict, ODVInput - -if TYPE_CHECKING: - from telegram import Bot - - -class PreCheckoutQuery(TelegramObject): - """This object contains information about an incoming pre-checkout query. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`id` is equal. - - Note: - In Python ``from`` is a reserved word, use ``from_user`` instead. - - Args: - id (:obj:`str`): Unique query identifier. - from_user (:class:`telegram.User`): User who sent the query. - currency (:obj:`str`): Three-letter ISO 4217 currency code. - total_amount (:obj:`int`): Total price in the smallest units of the currency (integer, not - float/double). For example, for a price of US$ 1.45 pass ``amount = 145``. - See the :obj:`exp` parameter in - `currencies.json <https://core.telegram.org/bots/payments/currencies.json>`_, - it shows the number of digits past the decimal point for each currency - (2 for the majority of currencies). - invoice_payload (:obj:`str`): Bot specified invoice payload. - shipping_option_id (:obj:`str`, optional): Identifier of the shipping option chosen by the - user. - order_info (:class:`telegram.OrderInfo`, optional): Order info provided by the user. - bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - id (:obj:`str`): Unique query identifier. - from_user (:class:`telegram.User`): User who sent the query. - currency (:obj:`str`): Three-letter ISO 4217 currency code. - total_amount (:obj:`int`): Total price in the smallest units of the currency. - invoice_payload (:obj:`str`): Bot specified invoice payload. - shipping_option_id (:obj:`str`): Optional. Identifier of the shipping option chosen by the - user. - order_info (:class:`telegram.OrderInfo`): Optional. Order info provided by the user. - bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods. - - """ - - __slots__ = ( - 'bot', - 'invoice_payload', - 'shipping_option_id', - 'currency', - 'order_info', - 'total_amount', - 'id', - 'from_user', - '_id_attrs', - ) - - def __init__( - self, - id: str, # pylint: disable=W0622 - from_user: User, - currency: str, - total_amount: int, - invoice_payload: str, - shipping_option_id: str = None, - order_info: OrderInfo = None, - bot: 'Bot' = None, - **_kwargs: Any, - ): - self.id = id # pylint: disable=C0103 - self.from_user = from_user - self.currency = currency - self.total_amount = total_amount - self.invoice_payload = invoice_payload - self.shipping_option_id = shipping_option_id - self.order_info = order_info - - self.bot = bot - - self._id_attrs = (self.id,) - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['PreCheckoutQuery']: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data['from_user'] = User.de_json(data.pop('from'), bot) - data['order_info'] = OrderInfo.de_json(data.get('order_info'), bot) - - return cls(bot=bot, **data) - - def answer( # pylint: disable=C0103 - self, - ok: bool, - error_message: str = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> bool: - """Shortcut for:: - - bot.answer_pre_checkout_query(update.pre_checkout_query.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.answer_pre_checkout_query`. - - """ - return self.bot.answer_pre_checkout_query( - pre_checkout_query_id=self.id, - ok=ok, - error_message=error_message, - timeout=timeout, - api_kwargs=api_kwargs, - ) diff --git a/venv/lib/python3.8/site-packages/telegram/payment/shippingaddress.py b/venv/lib/python3.8/site-packages/telegram/payment/shippingaddress.py deleted file mode 100644 index 2ea5a45..0000000 --- a/venv/lib/python3.8/site-packages/telegram/payment/shippingaddress.py +++ /dev/null @@ -1,86 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram ShippingAddress.""" - -from typing import Any - -from telegram import TelegramObject - - -class ShippingAddress(TelegramObject): - """This object represents a Telegram ShippingAddress. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`country_code`, :attr:`state`, :attr:`city`, - :attr:`street_line1`, :attr:`street_line2` and :attr:`post_cod` are equal. - - Args: - country_code (:obj:`str`): ISO 3166-1 alpha-2 country code. - state (:obj:`str`): State, if applicable. - city (:obj:`str`): City. - street_line1 (:obj:`str`): First line for the address. - street_line2 (:obj:`str`): Second line for the address. - post_code (:obj:`str`): Address post code. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - country_code (:obj:`str`): ISO 3166-1 alpha-2 country code. - state (:obj:`str`): State, if applicable. - city (:obj:`str`): City. - street_line1 (:obj:`str`): First line for the address. - street_line2 (:obj:`str`): Second line for the address. - post_code (:obj:`str`): Address post code. - - """ - - __slots__ = ( - 'post_code', - 'city', - '_id_attrs', - 'country_code', - 'street_line2', - 'street_line1', - 'state', - ) - - def __init__( - self, - country_code: str, - state: str, - city: str, - street_line1: str, - street_line2: str, - post_code: str, - **_kwargs: Any, - ): - self.country_code = country_code - self.state = state - self.city = city - self.street_line1 = street_line1 - self.street_line2 = street_line2 - self.post_code = post_code - - self._id_attrs = ( - self.country_code, - self.state, - self.city, - self.street_line1, - self.street_line2, - self.post_code, - ) diff --git a/venv/lib/python3.8/site-packages/telegram/payment/shippingoption.py b/venv/lib/python3.8/site-packages/telegram/payment/shippingoption.py deleted file mode 100644 index 6ddbb0b..0000000 --- a/venv/lib/python3.8/site-packages/telegram/payment/shippingoption.py +++ /dev/null @@ -1,70 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram ShippingOption.""" - -from typing import TYPE_CHECKING, Any, List - -from telegram import TelegramObject -from telegram.utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import LabeledPrice # noqa - - -class ShippingOption(TelegramObject): - """This object represents one shipping option. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`id` is equal. - - Args: - id (:obj:`str`): Shipping option identifier. - title (:obj:`str`): Option title. - prices (List[:class:`telegram.LabeledPrice`]): List of price portions. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - id (:obj:`str`): Shipping option identifier. - title (:obj:`str`): Option title. - prices (List[:class:`telegram.LabeledPrice`]): List of price portions. - - """ - - __slots__ = ('prices', 'title', 'id', '_id_attrs') - - def __init__( - self, - id: str, # pylint: disable=W0622 - title: str, - prices: List['LabeledPrice'], - **_kwargs: Any, - ): - self.id = id # pylint: disable=C0103 - self.title = title - self.prices = prices - - self._id_attrs = (self.id,) - - def to_dict(self) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict() - - data['prices'] = [p.to_dict() for p in self.prices] - - return data diff --git a/venv/lib/python3.8/site-packages/telegram/payment/shippingquery.py b/venv/lib/python3.8/site-packages/telegram/payment/shippingquery.py deleted file mode 100644 index bcde858..0000000 --- a/venv/lib/python3.8/site-packages/telegram/payment/shippingquery.py +++ /dev/null @@ -1,113 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram ShippingQuery.""" - -from typing import TYPE_CHECKING, Any, Optional, List - -from telegram import ShippingAddress, TelegramObject, User, ShippingOption -from telegram.utils.helpers import DEFAULT_NONE -from telegram.utils.types import JSONDict, ODVInput - -if TYPE_CHECKING: - from telegram import Bot - - -class ShippingQuery(TelegramObject): - """This object contains information about an incoming shipping query. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`id` is equal. - - Note: - In Python ``from`` is a reserved word, use ``from_user`` instead. - - Args: - id (:obj:`str`): Unique query identifier. - from_user (:class:`telegram.User`): User who sent the query. - invoice_payload (:obj:`str`): Bot specified invoice payload. - shipping_address (:class:`telegram.ShippingAddress`): User specified shipping address. - bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - id (:obj:`str`): Unique query identifier. - from_user (:class:`telegram.User`): User who sent the query. - invoice_payload (:obj:`str`): Bot specified invoice payload. - shipping_address (:class:`telegram.ShippingAddress`): User specified shipping address. - bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods. - - """ - - __slots__ = ('bot', 'invoice_payload', 'shipping_address', 'id', 'from_user', '_id_attrs') - - def __init__( - self, - id: str, # pylint: disable=W0622 - from_user: User, - invoice_payload: str, - shipping_address: ShippingAddress, - bot: 'Bot' = None, - **_kwargs: Any, - ): - self.id = id # pylint: disable=C0103 - self.from_user = from_user - self.invoice_payload = invoice_payload - self.shipping_address = shipping_address - - self.bot = bot - - self._id_attrs = (self.id,) - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['ShippingQuery']: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data['from_user'] = User.de_json(data.pop('from'), bot) - data['shipping_address'] = ShippingAddress.de_json(data.get('shipping_address'), bot) - - return cls(bot=bot, **data) - - def answer( # pylint: disable=C0103 - self, - ok: bool, - shipping_options: List[ShippingOption] = None, - error_message: str = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> bool: - """Shortcut for:: - - bot.answer_shipping_query(update.shipping_query.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.answer_shipping_query`. - - """ - return self.bot.answer_shipping_query( - shipping_query_id=self.id, - ok=ok, - shipping_options=shipping_options, - error_message=error_message, - timeout=timeout, - api_kwargs=api_kwargs, - ) diff --git a/venv/lib/python3.8/site-packages/telegram/payment/successfulpayment.py b/venv/lib/python3.8/site-packages/telegram/payment/successfulpayment.py deleted file mode 100644 index 6997ca7..0000000 --- a/venv/lib/python3.8/site-packages/telegram/payment/successfulpayment.py +++ /dev/null @@ -1,107 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram SuccessfulPayment.""" - -from typing import TYPE_CHECKING, Any, Optional - -from telegram import OrderInfo, TelegramObject -from telegram.utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - - -class SuccessfulPayment(TelegramObject): - """This object contains basic information about a successful payment. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`telegram_payment_charge_id` and - :attr:`provider_payment_charge_id` are equal. - - Args: - currency (:obj:`str`): Three-letter ISO 4217 currency code. - total_amount (:obj:`int`): Total price in the smallest units of the currency (integer, not - float/double). For example, for a price of US$ 1.45 pass ``amount = 145``. - See the :obj:`exp` parameter in - `currencies.json <https://core.telegram.org/bots/payments/currencies.json>`_, - it shows the number of digits past the decimal point for each currency - (2 for the majority of currencies). - invoice_payload (:obj:`str`): Bot specified invoice payload. - shipping_option_id (:obj:`str`, optional): Identifier of the shipping option chosen by the - user. - order_info (:class:`telegram.OrderInfo`, optional): Order info provided by the user. - telegram_payment_charge_id (:obj:`str`): Telegram payment identifier. - provider_payment_charge_id (:obj:`str`): Provider payment identifier. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - currency (:obj:`str`): Three-letter ISO 4217 currency code. - total_amount (:obj:`int`): Total price in the smallest units of the currency. - invoice_payload (:obj:`str`): Bot specified invoice payload. - shipping_option_id (:obj:`str`): Optional. Identifier of the shipping option chosen by the - user. - order_info (:class:`telegram.OrderInfo`): Optional. Order info provided by the user. - telegram_payment_charge_id (:obj:`str`): Telegram payment identifier. - provider_payment_charge_id (:obj:`str`): Provider payment identifier. - - """ - - __slots__ = ( - 'invoice_payload', - 'shipping_option_id', - 'currency', - 'order_info', - 'telegram_payment_charge_id', - 'provider_payment_charge_id', - 'total_amount', - '_id_attrs', - ) - - def __init__( - self, - currency: str, - total_amount: int, - invoice_payload: str, - telegram_payment_charge_id: str, - provider_payment_charge_id: str, - shipping_option_id: str = None, - order_info: OrderInfo = None, - **_kwargs: Any, - ): - self.currency = currency - self.total_amount = total_amount - self.invoice_payload = invoice_payload - self.shipping_option_id = shipping_option_id - self.order_info = order_info - self.telegram_payment_charge_id = telegram_payment_charge_id - self.provider_payment_charge_id = provider_payment_charge_id - - self._id_attrs = (self.telegram_payment_charge_id, self.provider_payment_charge_id) - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['SuccessfulPayment']: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data['order_info'] = OrderInfo.de_json(data.get('order_info'), bot) - - return cls(**data) diff --git a/venv/lib/python3.8/site-packages/telegram/poll.py b/venv/lib/python3.8/site-packages/telegram/poll.py deleted file mode 100644 index 9c28ce5..0000000 --- a/venv/lib/python3.8/site-packages/telegram/poll.py +++ /dev/null @@ -1,295 +0,0 @@ -#!/usr/bin/env python -# pylint: disable=R0903 -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram Poll.""" - -import datetime -import sys -from typing import TYPE_CHECKING, Any, Dict, List, Optional, ClassVar - -from telegram import MessageEntity, TelegramObject, User, constants -from telegram.utils.helpers import from_timestamp, to_timestamp -from telegram.utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - - -class PollOption(TelegramObject): - """ - This object contains information about one answer option in a poll. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`text` and :attr:`voter_count` are equal. - - Args: - text (:obj:`str`): Option text, 1-100 characters. - voter_count (:obj:`int`): Number of users that voted for this option. - - Attributes: - text (:obj:`str`): Option text, 1-100 characters. - voter_count (:obj:`int`): Number of users that voted for this option. - - """ - - __slots__ = ('voter_count', 'text', '_id_attrs') - - def __init__(self, text: str, voter_count: int, **_kwargs: Any): - self.text = text - self.voter_count = voter_count - - self._id_attrs = (self.text, self.voter_count) - - MAX_LENGTH: ClassVar[int] = constants.MAX_POLL_OPTION_LENGTH - """:const:`telegram.constants.MAX_POLL_OPTION_LENGTH`""" - - -class PollAnswer(TelegramObject): - """ - This object represents an answer of a user in a non-anonymous poll. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`poll_id`, :attr:`user` and :attr:`options_ids` are equal. - - Attributes: - poll_id (:obj:`str`): Unique poll identifier. - user (:class:`telegram.User`): The user, who changed the answer to the poll. - option_ids (List[:obj:`int`]): Identifiers of answer options, chosen by the user. - - Args: - poll_id (:obj:`str`): Unique poll identifier. - user (:class:`telegram.User`): The user, who changed the answer to the poll. - option_ids (List[:obj:`int`]): 0-based identifiers of answer options, chosen by the user. - May be empty if the user retracted their vote. - - """ - - __slots__ = ('option_ids', 'user', 'poll_id', '_id_attrs') - - def __init__(self, poll_id: str, user: User, option_ids: List[int], **_kwargs: Any): - self.poll_id = poll_id - self.user = user - self.option_ids = option_ids - - self._id_attrs = (self.poll_id, self.user, tuple(self.option_ids)) - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['PollAnswer']: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data['user'] = User.de_json(data.get('user'), bot) - - return cls(**data) - - -class Poll(TelegramObject): - """ - This object contains information about a poll. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`id` is equal. - - Attributes: - id (:obj:`str`): Unique poll identifier. - question (:obj:`str`): Poll question, 1-300 characters. - options (List[:class:`PollOption`]): List of poll options. - total_voter_count (:obj:`int`): Total number of users that voted in the poll. - is_closed (:obj:`bool`): :obj:`True`, if the poll is closed. - is_anonymous (:obj:`bool`): :obj:`True`, if the poll is anonymous. - type (:obj:`str`): Poll type, currently can be :attr:`REGULAR` or :attr:`QUIZ`. - allows_multiple_answers (:obj:`bool`): :obj:`True`, if the poll allows multiple answers. - correct_option_id (:obj:`int`): Optional. Identifier of the correct answer option. - explanation (:obj:`str`): Optional. Text that is shown when a user chooses an incorrect - answer or taps on the lamp icon in a quiz-style poll. - explanation_entities (List[:class:`telegram.MessageEntity`]): Optional. Special entities - like usernames, URLs, bot commands, etc. that appear in the :attr:`explanation`. - open_period (:obj:`int`): Optional. Amount of time in seconds the poll will be active - after creation. - close_date (:obj:`datetime.datetime`): Optional. Point in time when the poll will be - automatically closed. - - Args: - id (:obj:`str`): Unique poll identifier. - question (:obj:`str`): Poll question, 1-300 characters. - options (List[:class:`PollOption`]): List of poll options. - is_closed (:obj:`bool`): :obj:`True`, if the poll is closed. - is_anonymous (:obj:`bool`): :obj:`True`, if the poll is anonymous. - type (:obj:`str`): Poll type, currently can be :attr:`REGULAR` or :attr:`QUIZ`. - allows_multiple_answers (:obj:`bool`): :obj:`True`, if the poll allows multiple answers. - correct_option_id (:obj:`int`, optional): 0-based identifier of the correct answer option. - Available only for polls in the quiz mode, which are closed, or was sent (not - forwarded) by the bot or to the private chat with the bot. - explanation (:obj:`str`, optional): Text that is shown when a user chooses an incorrect - answer or taps on the lamp icon in a quiz-style poll, 0-200 characters. - explanation_entities (List[:class:`telegram.MessageEntity`], optional): Special entities - like usernames, URLs, bot commands, etc. that appear in the :attr:`explanation`. - open_period (:obj:`int`, optional): Amount of time in seconds the poll will be active - after creation. - close_date (:obj:`datetime.datetime`, optional): Point in time (Unix timestamp) when the - poll will be automatically closed. Converted to :obj:`datetime.datetime`. - - """ - - __slots__ = ( - 'total_voter_count', - 'allows_multiple_answers', - 'open_period', - 'options', - 'type', - 'explanation_entities', - 'is_anonymous', - 'close_date', - 'is_closed', - 'id', - 'explanation', - 'question', - 'correct_option_id', - '_id_attrs', - ) - - def __init__( - self, - id: str, # pylint: disable=W0622 - question: str, - options: List[PollOption], - total_voter_count: int, - is_closed: bool, - is_anonymous: bool, - type: str, # pylint: disable=W0622 - allows_multiple_answers: bool, - correct_option_id: int = None, - explanation: str = None, - explanation_entities: List[MessageEntity] = None, - open_period: int = None, - close_date: datetime.datetime = None, - **_kwargs: Any, - ): - self.id = id # pylint: disable=C0103 - self.question = question - self.options = options - self.total_voter_count = total_voter_count - self.is_closed = is_closed - self.is_anonymous = is_anonymous - self.type = type - self.allows_multiple_answers = allows_multiple_answers - self.correct_option_id = correct_option_id - self.explanation = explanation - self.explanation_entities = explanation_entities - self.open_period = open_period - self.close_date = close_date - - self._id_attrs = (self.id,) - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Poll']: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data['options'] = [PollOption.de_json(option, bot) for option in data['options']] - data['explanation_entities'] = MessageEntity.de_list(data.get('explanation_entities'), bot) - data['close_date'] = from_timestamp(data.get('close_date')) - - return cls(**data) - - def to_dict(self) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict() - - data['options'] = [x.to_dict() for x in self.options] - if self.explanation_entities: - data['explanation_entities'] = [e.to_dict() for e in self.explanation_entities] - data['close_date'] = to_timestamp(data.get('close_date')) - - return data - - def parse_explanation_entity(self, entity: MessageEntity) -> str: - """Returns the text from a given :class:`telegram.MessageEntity`. - - Note: - This method is present because Telegram calculates the offset and length in - UTF-16 codepoint pairs, which some versions of Python don't handle automatically. - (That is, you can't just slice ``Message.text`` with the offset and length.) - - Args: - entity (:class:`telegram.MessageEntity`): The entity to extract the text from. It must - be an entity that belongs to this message. - - Returns: - :obj:`str`: The text of the given entity. - - Raises: - RuntimeError: If the poll has no explanation. - - """ - if not self.explanation: - raise RuntimeError("This Poll has no 'explanation'.") - - # Is it a narrow build, if so we don't need to convert - if sys.maxunicode == 0xFFFF: - return self.explanation[entity.offset : entity.offset + entity.length] - entity_text = self.explanation.encode('utf-16-le') - entity_text = entity_text[entity.offset * 2 : (entity.offset + entity.length) * 2] - - return entity_text.decode('utf-16-le') - - def parse_explanation_entities(self, types: List[str] = None) -> Dict[MessageEntity, str]: - """ - Returns a :obj:`dict` that maps :class:`telegram.MessageEntity` to :obj:`str`. - It contains entities from this polls explanation filtered by their ``type`` attribute as - the key, and the text that each entity belongs to as the value of the :obj:`dict`. - - Note: - This method should always be used instead of the :attr:`explanation_entities` - attribute, since it calculates the correct substring from the message text based on - UTF-16 codepoints. See :attr:`parse_explanation_entity` for more info. - - Args: - types (List[:obj:`str`], optional): List of ``MessageEntity`` types as strings. If the - ``type`` attribute of an entity is contained in this list, it will be returned. - Defaults to :attr:`telegram.MessageEntity.ALL_TYPES`. - - Returns: - Dict[:class:`telegram.MessageEntity`, :obj:`str`]: A dictionary of entities mapped to - the text that belongs to them, calculated based on UTF-16 codepoints. - - """ - if types is None: - types = MessageEntity.ALL_TYPES - - return { - entity: self.parse_explanation_entity(entity) - for entity in (self.explanation_entities or []) - if entity.type in types - } - - REGULAR: ClassVar[str] = constants.POLL_REGULAR - """:const:`telegram.constants.POLL_REGULAR`""" - QUIZ: ClassVar[str] = constants.POLL_QUIZ - """:const:`telegram.constants.POLL_QUIZ`""" - MAX_QUESTION_LENGTH: ClassVar[int] = constants.MAX_POLL_QUESTION_LENGTH - """:const:`telegram.constants.MAX_POLL_QUESTION_LENGTH`""" - MAX_OPTION_LENGTH: ClassVar[int] = constants.MAX_POLL_OPTION_LENGTH - """:const:`telegram.constants.MAX_POLL_OPTION_LENGTH`""" diff --git a/venv/lib/python3.8/site-packages/telegram/proximityalerttriggered.py b/venv/lib/python3.8/site-packages/telegram/proximityalerttriggered.py deleted file mode 100644 index 507fb77..0000000 --- a/venv/lib/python3.8/site-packages/telegram/proximityalerttriggered.py +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram Proximity Alert.""" -from typing import Any, Optional, TYPE_CHECKING - -from telegram import TelegramObject, User -from telegram.utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - - -class ProximityAlertTriggered(TelegramObject): - """ - This object represents the content of a service message, sent whenever a user in the chat - triggers a proximity alert set by another user. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`traveler`, :attr:`watcher` and :attr:`distance` are equal. - - Args: - traveler (:class:`telegram.User`): User that triggered the alert - watcher (:class:`telegram.User`): User that set the alert - distance (:obj:`int`): The distance between the users - - Attributes: - traveler (:class:`telegram.User`): User that triggered the alert - watcher (:class:`telegram.User`): User that set the alert - distance (:obj:`int`): The distance between the users - - """ - - __slots__ = ('traveler', 'distance', 'watcher', '_id_attrs') - - def __init__(self, traveler: User, watcher: User, distance: int, **_kwargs: Any): - self.traveler = traveler - self.watcher = watcher - self.distance = distance - - self._id_attrs = (self.traveler, self.watcher, self.distance) - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['ProximityAlertTriggered']: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data['traveler'] = User.de_json(data.get('traveler'), bot) - data['watcher'] = User.de_json(data.get('watcher'), bot) - - return cls(bot=bot, **data) diff --git a/venv/lib/python3.8/site-packages/telegram/py.typed b/venv/lib/python3.8/site-packages/telegram/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.8/site-packages/telegram/replykeyboardmarkup.py b/venv/lib/python3.8/site-packages/telegram/replykeyboardmarkup.py deleted file mode 100644 index 490ce33..0000000 --- a/venv/lib/python3.8/site-packages/telegram/replykeyboardmarkup.py +++ /dev/null @@ -1,251 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram ReplyKeyboardMarkup.""" - -from typing import Any, List, Union, Sequence - -from telegram import KeyboardButton, ReplyMarkup -from telegram.utils.types import JSONDict - - -class ReplyKeyboardMarkup(ReplyMarkup): - """This object represents a custom keyboard with reply options. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their the size of :attr:`keyboard` and all the buttons are equal. - - Example: - A user requests to change the bot's language, bot replies to the request with a keyboard - to select the new language. Other users in the group don't see the keyboard. - - Args: - keyboard (List[List[:obj:`str` | :class:`telegram.KeyboardButton`]]): Array of button rows, - each represented by an Array of :class:`telegram.KeyboardButton` objects. - resize_keyboard (:obj:`bool`, optional): Requests clients to resize the keyboard vertically - for optimal fit (e.g., make the keyboard smaller if there are just two rows of - buttons). Defaults to :obj:`False`, in which case the custom keyboard is always of the - same height as the app's standard keyboard. - one_time_keyboard (:obj:`bool`, optional): Requests clients to hide the keyboard as soon as - it's been used. The keyboard will still be available, but clients will automatically - display the usual letter-keyboard in the chat - the user can press a special button in - the input field to see the custom keyboard again. Defaults to :obj:`False`. - selective (:obj:`bool`, optional): Use this parameter if you want to show the keyboard to - specific users only. Targets: - - 1) Users that are @mentioned in the text of the Message object. - 2) If the bot's message is a reply (has ``reply_to_message_id``), sender of the - original message. - - Defaults to :obj:`False`. - - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - keyboard (List[List[:class:`telegram.KeyboardButton` | :obj:`str`]]): Array of button rows. - resize_keyboard (:obj:`bool`): Optional. Requests clients to resize the keyboard. - one_time_keyboard (:obj:`bool`): Optional. Requests clients to hide the keyboard as soon as - it's been used. - selective (:obj:`bool`): Optional. Show the keyboard to specific users only. - - """ - - __slots__ = ('selective', 'keyboard', 'resize_keyboard', 'one_time_keyboard', '_id_attrs') - - def __init__( - self, - keyboard: Sequence[Sequence[Union[str, KeyboardButton]]], - resize_keyboard: bool = False, - one_time_keyboard: bool = False, - selective: bool = False, - **_kwargs: Any, - ): - # Required - self.keyboard = [] - for row in keyboard: - button_row = [] - for button in row: - if isinstance(button, KeyboardButton): - button_row.append(button) # telegram.KeyboardButton - else: - button_row.append(KeyboardButton(button)) # str - self.keyboard.append(button_row) - - # Optionals - self.resize_keyboard = bool(resize_keyboard) - self.one_time_keyboard = bool(one_time_keyboard) - self.selective = bool(selective) - - self._id_attrs = (self.keyboard,) - - def to_dict(self) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict() - - data['keyboard'] = [] - for row in self.keyboard: - data['keyboard'].append([button.to_dict() for button in row]) - return data - - @classmethod - def from_button( - cls, - button: Union[KeyboardButton, str], - resize_keyboard: bool = False, - one_time_keyboard: bool = False, - selective: bool = False, - **kwargs: object, - ) -> 'ReplyKeyboardMarkup': - """Shortcut for:: - - ReplyKeyboardMarkup([[button]], **kwargs) - - Return a ReplyKeyboardMarkup from a single KeyboardButton. - - Args: - button (:class:`telegram.KeyboardButton` | :obj:`str`): The button to use in - the markup. - resize_keyboard (:obj:`bool`, optional): Requests clients to resize the keyboard - vertically for optimal fit (e.g., make the keyboard smaller if there are just two - rows of buttons). Defaults to :obj:`False`, in which case the custom keyboard is - always of the same height as the app's standard keyboard. - one_time_keyboard (:obj:`bool`, optional): Requests clients to hide the keyboard as - soon as it's been used. The keyboard will still be available, but clients will - automatically display the usual letter-keyboard in the chat - the user can press - a special button in the input field to see the custom keyboard again. - Defaults to :obj:`False`. - selective (:obj:`bool`, optional): Use this parameter if you want to show the keyboard - to specific users only. Targets: - - 1) Users that are @mentioned in the text of the Message object. - 2) If the bot's message is a reply (has reply_to_message_id), sender of the - original message. - - Defaults to :obj:`False`. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - """ - return cls( - [[button]], - resize_keyboard=resize_keyboard, - one_time_keyboard=one_time_keyboard, - selective=selective, - **kwargs, - ) - - @classmethod - def from_row( - cls, - button_row: List[Union[str, KeyboardButton]], - resize_keyboard: bool = False, - one_time_keyboard: bool = False, - selective: bool = False, - **kwargs: object, - ) -> 'ReplyKeyboardMarkup': - """Shortcut for:: - - ReplyKeyboardMarkup([button_row], **kwargs) - - Return a ReplyKeyboardMarkup from a single row of KeyboardButtons. - - Args: - button_row (List[:class:`telegram.KeyboardButton` | :obj:`str`]): The button to use in - the markup. - resize_keyboard (:obj:`bool`, optional): Requests clients to resize the keyboard - vertically for optimal fit (e.g., make the keyboard smaller if there are just two - rows of buttons). Defaults to :obj:`False`, in which case the custom keyboard is - always of the same height as the app's standard keyboard. - one_time_keyboard (:obj:`bool`, optional): Requests clients to hide the keyboard as - soon as it's been used. The keyboard will still be available, but clients will - automatically display the usual letter-keyboard in the chat - the user can press - a special button in the input field to see the custom keyboard again. - Defaults to :obj:`False`. - selective (:obj:`bool`, optional): Use this parameter if you want to show the keyboard - to specific users only. Targets: - - 1) Users that are @mentioned in the text of the Message object. - 2) If the bot's message is a reply (has reply_to_message_id), sender of the - original message. - - Defaults to :obj:`False`. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - """ - return cls( - [button_row], - resize_keyboard=resize_keyboard, - one_time_keyboard=one_time_keyboard, - selective=selective, - **kwargs, - ) - - @classmethod - def from_column( - cls, - button_column: List[Union[str, KeyboardButton]], - resize_keyboard: bool = False, - one_time_keyboard: bool = False, - selective: bool = False, - **kwargs: object, - ) -> 'ReplyKeyboardMarkup': - """Shortcut for:: - - ReplyKeyboardMarkup([[button] for button in button_column], **kwargs) - - Return a ReplyKeyboardMarkup from a single column of KeyboardButtons. - - Args: - button_column (List[:class:`telegram.KeyboardButton` | :obj:`str`]): The button to use - in the markup. - resize_keyboard (:obj:`bool`, optional): Requests clients to resize the keyboard - vertically for optimal fit (e.g., make the keyboard smaller if there are just two - rows of buttons). Defaults to :obj:`False`, in which case the custom keyboard is - always of the same height as the app's standard keyboard. - one_time_keyboard (:obj:`bool`, optional): Requests clients to hide the keyboard as - soon as it's been used. The keyboard will still be available, but clients will - automatically display the usual letter-keyboard in the chat - the user can press - a special button in the input field to see the custom keyboard again. - Defaults to :obj:`False`. - selective (:obj:`bool`, optional): Use this parameter if you want to show the keyboard - to specific users only. Targets: - - 1) Users that are @mentioned in the text of the Message object. - 2) If the bot's message is a reply (has reply_to_message_id), sender of the - original message. - - Defaults to :obj:`False`. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - """ - button_grid = [[button] for button in button_column] - return cls( - button_grid, - resize_keyboard=resize_keyboard, - one_time_keyboard=one_time_keyboard, - selective=selective, - **kwargs, - ) - - def __hash__(self) -> int: - return hash( - ( - tuple(tuple(button for button in row) for row in self.keyboard), - self.resize_keyboard, - self.one_time_keyboard, - self.selective, - ) - ) diff --git a/venv/lib/python3.8/site-packages/telegram/replykeyboardremove.py b/venv/lib/python3.8/site-packages/telegram/replykeyboardremove.py deleted file mode 100644 index 5f3c255..0000000 --- a/venv/lib/python3.8/site-packages/telegram/replykeyboardremove.py +++ /dev/null @@ -1,64 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram ReplyKeyboardRemove.""" -from typing import Any - -from telegram import ReplyMarkup - - -class ReplyKeyboardRemove(ReplyMarkup): - """ - Upon receiving a message with this object, Telegram clients will remove the current custom - keyboard and display the default letter-keyboard. By default, custom keyboards are displayed - until a new keyboard is sent by a bot. An exception is made for one-time keyboards that are - hidden immediately after the user presses a button (see :class:`telegram.ReplyKeyboardMarkup`). - - Example: - A user votes in a poll, bot returns confirmation message in reply to the vote and removes - the keyboard for that user, while still showing the keyboard with poll options to users who - haven't voted yet. - - Note: - User will not be able to summon this keyboard; if you want to hide the keyboard from - sight but keep it accessible, use :attr:`telegram.ReplyKeyboardMarkup.one_time_keyboard`. - - Args: - selective (:obj:`bool`, optional): Use this parameter if you want to remove the keyboard - for specific users only. Targets: - - 1) Users that are @mentioned in the text of the :class:`telegram.Message` object. - 2) If the bot's message is a reply (has `reply_to_message_id`), sender of the original - message. - - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - remove_keyboard (:obj:`True`): Requests clients to remove the custom keyboard. - selective (:obj:`bool`): Optional. Use this parameter if you want to remove the keyboard - for specific users only. - - """ - - __slots__ = ('selective', 'remove_keyboard') - - def __init__(self, selective: bool = False, **_kwargs: Any): - # Required - self.remove_keyboard = True - # Optionals - self.selective = bool(selective) diff --git a/venv/lib/python3.8/site-packages/telegram/replymarkup.py b/venv/lib/python3.8/site-packages/telegram/replymarkup.py deleted file mode 100644 index 4f2c01d..0000000 --- a/venv/lib/python3.8/site-packages/telegram/replymarkup.py +++ /dev/null @@ -1,33 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""Base class for Telegram ReplyMarkup Objects.""" - -from telegram import TelegramObject - - -class ReplyMarkup(TelegramObject): - """Base class for Telegram ReplyMarkup Objects. - - See :class:`telegram.InlineKeyboardMarkup`, :class:`telegram.ReplyKeyboardMarkup`, - :class:`telegram.ReplyKeyboardRemove` and :class:`telegram.ForceReply` for - detailed use. - - """ - - __slots__ = () diff --git a/venv/lib/python3.8/site-packages/telegram/update.py b/venv/lib/python3.8/site-packages/telegram/update.py deleted file mode 100644 index b610b35..0000000 --- a/venv/lib/python3.8/site-packages/telegram/update.py +++ /dev/null @@ -1,388 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram Update.""" - -from typing import TYPE_CHECKING, Any, Optional - -from telegram import ( - CallbackQuery, - ChosenInlineResult, - InlineQuery, - Message, - Poll, - PreCheckoutQuery, - ShippingQuery, - TelegramObject, - ChatMemberUpdated, - constants, -) -from telegram.poll import PollAnswer -from telegram.utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot, Chat, User # noqa - - -class Update(TelegramObject): - """This object represents an incoming update. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`update_id` is equal. - - Note: - At most one of the optional parameters can be present in any given update. - - Args: - update_id (:obj:`int`): The update's unique identifier. Update identifiers start from a - certain positive number and increase sequentially. This ID becomes especially handy if - you're using Webhooks, since it allows you to ignore repeated updates or to restore the - correct update sequence, should they get out of order. If there are no new updates for - at least a week, then identifier of the next update will be chosen randomly instead of - sequentially. - message (:class:`telegram.Message`, optional): New incoming message of any kind - text, - photo, sticker, etc. - edited_message (:class:`telegram.Message`, optional): New version of a message that is - known to the bot and was edited. - channel_post (:class:`telegram.Message`, optional): New incoming channel post of any kind - - text, photo, sticker, etc. - edited_channel_post (:class:`telegram.Message`, optional): New version of a channel post - that is known to the bot and was edited. - inline_query (:class:`telegram.InlineQuery`, optional): New incoming inline query. - chosen_inline_result (:class:`telegram.ChosenInlineResult`, optional): The result of an - inline query that was chosen by a user and sent to their chat partner. - callback_query (:class:`telegram.CallbackQuery`, optional): New incoming callback query. - shipping_query (:class:`telegram.ShippingQuery`, optional): New incoming shipping query. - Only for invoices with flexible price. - pre_checkout_query (:class:`telegram.PreCheckoutQuery`, optional): New incoming - pre-checkout query. Contains full information about checkout. - poll (:class:`telegram.Poll`, optional): New poll state. Bots receive only updates about - stopped polls and polls, which are sent by the bot. - poll_answer (:class:`telegram.PollAnswer`, optional): A user changed their answer - in a non-anonymous poll. Bots receive new votes only in polls that were sent - by the bot itself. - my_chat_member (:class:`telegram.ChatMemberUpdated`, optional): The bot's chat member - status was updated in a chat. For private chats, this update is received only when the - bot is blocked or unblocked by the user. - - .. versionadded:: 13.4 - chat_member (:class:`telegram.ChatMemberUpdated`, optional): A chat member's status was - updated in a chat. The bot must be an administrator in the chat and must explicitly - specify ``'chat_member'`` in the list of ``'allowed_updates'`` to receive these - updates (see :meth:`telegram.Bot.get_updates`, :meth:`telegram.Bot.set_webhook`, - :meth:`telegram.ext.Updater.start_polling` and - :meth:`telegram.ext.Updater.start_webhook`). - - .. versionadded:: 13.4 - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - update_id (:obj:`int`): The update's unique identifier. - message (:class:`telegram.Message`): Optional. New incoming message. - edited_message (:class:`telegram.Message`): Optional. New version of a message. - channel_post (:class:`telegram.Message`): Optional. New incoming channel post. - edited_channel_post (:class:`telegram.Message`): Optional. New version of a channel post. - inline_query (:class:`telegram.InlineQuery`): Optional. New incoming inline query. - chosen_inline_result (:class:`telegram.ChosenInlineResult`): Optional. The result of an - inline query that was chosen by a user. - callback_query (:class:`telegram.CallbackQuery`): Optional. New incoming callback query. - shipping_query (:class:`telegram.ShippingQuery`): Optional. New incoming shipping query. - pre_checkout_query (:class:`telegram.PreCheckoutQuery`): Optional. New incoming - pre-checkout query. - poll (:class:`telegram.Poll`): Optional. New poll state. Bots receive only updates - about stopped polls and polls, which are sent by the bot. - poll_answer (:class:`telegram.PollAnswer`): Optional. A user changed their answer - in a non-anonymous poll. Bots receive new votes only in polls that were sent - by the bot itself. - my_chat_member (:class:`telegram.ChatMemberUpdated`): Optional. The bot's chat member - status was updated in a chat. For private chats, this update is received only when the - bot is blocked or unblocked by the user. - - .. versionadded:: 13.4 - chat_member (:class:`telegram.ChatMemberUpdated`): Optional. A chat member's status was - updated in a chat. The bot must be an administrator in the chat and must explicitly - specify ``'chat_member'`` in the list of ``'allowed_updates'`` to receive these - updates (see :meth:`telegram.Bot.get_updates`, :meth:`telegram.Bot.set_webhook`, - :meth:`telegram.ext.Updater.start_polling` and - :meth:`telegram.ext.Updater.start_webhook`). - - .. versionadded:: 13.4 - - """ - - __slots__ = ( - 'callback_query', - 'chosen_inline_result', - 'pre_checkout_query', - 'inline_query', - 'update_id', - 'message', - 'shipping_query', - 'poll', - 'poll_answer', - 'channel_post', - 'edited_channel_post', - 'edited_message', - '_effective_user', - '_effective_chat', - '_effective_message', - 'my_chat_member', - 'chat_member', - '_id_attrs', - ) - - MESSAGE = constants.UPDATE_MESSAGE - """:const:`telegram.constants.UPDATE_MESSAGE` - - .. versionadded:: 13.5""" - EDITED_MESSAGE = constants.UPDATE_EDITED_MESSAGE - """:const:`telegram.constants.UPDATE_EDITED_MESSAGE` - - .. versionadded:: 13.5""" - CHANNEL_POST = constants.UPDATE_CHANNEL_POST - """:const:`telegram.constants.UPDATE_CHANNEL_POST` - - .. versionadded:: 13.5""" - EDITED_CHANNEL_POST = constants.UPDATE_EDITED_CHANNEL_POST - """:const:`telegram.constants.UPDATE_EDITED_CHANNEL_POST` - - .. versionadded:: 13.5""" - INLINE_QUERY = constants.UPDATE_INLINE_QUERY - """:const:`telegram.constants.UPDATE_INLINE_QUERY` - - .. versionadded:: 13.5""" - CHOSEN_INLINE_RESULT = constants.UPDATE_CHOSEN_INLINE_RESULT - """:const:`telegram.constants.UPDATE_CHOSEN_INLINE_RESULT` - - .. versionadded:: 13.5""" - CALLBACK_QUERY = constants.UPDATE_CALLBACK_QUERY - """:const:`telegram.constants.UPDATE_CALLBACK_QUERY` - - .. versionadded:: 13.5""" - SHIPPING_QUERY = constants.UPDATE_SHIPPING_QUERY - """:const:`telegram.constants.UPDATE_SHIPPING_QUERY` - - .. versionadded:: 13.5""" - PRE_CHECKOUT_QUERY = constants.UPDATE_PRE_CHECKOUT_QUERY - """:const:`telegram.constants.UPDATE_PRE_CHECKOUT_QUERY` - - .. versionadded:: 13.5""" - POLL = constants.UPDATE_POLL - """:const:`telegram.constants.UPDATE_POLL` - - .. versionadded:: 13.5""" - POLL_ANSWER = constants.UPDATE_POLL_ANSWER - """:const:`telegram.constants.UPDATE_POLL_ANSWER` - - .. versionadded:: 13.5""" - MY_CHAT_MEMBER = constants.UPDATE_MY_CHAT_MEMBER - """:const:`telegram.constants.UPDATE_MY_CHAT_MEMBER` - - .. versionadded:: 13.5""" - CHAT_MEMBER = constants.UPDATE_CHAT_MEMBER - """:const:`telegram.constants.UPDATE_CHAT_MEMBER` - - .. versionadded:: 13.5""" - ALL_TYPES = constants.UPDATE_ALL_TYPES - """:const:`telegram.constants.UPDATE_ALL_TYPES` - - .. versionadded:: 13.5""" - - def __init__( - self, - update_id: int, - message: Message = None, - edited_message: Message = None, - channel_post: Message = None, - edited_channel_post: Message = None, - inline_query: InlineQuery = None, - chosen_inline_result: ChosenInlineResult = None, - callback_query: CallbackQuery = None, - shipping_query: ShippingQuery = None, - pre_checkout_query: PreCheckoutQuery = None, - poll: Poll = None, - poll_answer: PollAnswer = None, - my_chat_member: ChatMemberUpdated = None, - chat_member: ChatMemberUpdated = None, - **_kwargs: Any, - ): - # Required - self.update_id = int(update_id) - # Optionals - self.message = message - self.edited_message = edited_message - self.inline_query = inline_query - self.chosen_inline_result = chosen_inline_result - self.callback_query = callback_query - self.shipping_query = shipping_query - self.pre_checkout_query = pre_checkout_query - self.channel_post = channel_post - self.edited_channel_post = edited_channel_post - self.poll = poll - self.poll_answer = poll_answer - self.my_chat_member = my_chat_member - self.chat_member = chat_member - - self._effective_user: Optional['User'] = None - self._effective_chat: Optional['Chat'] = None - self._effective_message: Optional[Message] = None - - self._id_attrs = (self.update_id,) - - @property - def effective_user(self) -> Optional['User']: - """ - :class:`telegram.User`: The user that sent this update, no matter what kind of update this - is. Will be :obj:`None` for :attr:`channel_post` and :attr:`poll`. - - """ - if self._effective_user: - return self._effective_user - - user = None - - if self.message: - user = self.message.from_user - - elif self.edited_message: - user = self.edited_message.from_user - - elif self.inline_query: - user = self.inline_query.from_user - - elif self.chosen_inline_result: - user = self.chosen_inline_result.from_user - - elif self.callback_query: - user = self.callback_query.from_user - - elif self.shipping_query: - user = self.shipping_query.from_user - - elif self.pre_checkout_query: - user = self.pre_checkout_query.from_user - - elif self.poll_answer: - user = self.poll_answer.user - - elif self.my_chat_member: - user = self.my_chat_member.from_user - - elif self.chat_member: - user = self.chat_member.from_user - - self._effective_user = user - return user - - @property - def effective_chat(self) -> Optional['Chat']: - """ - :class:`telegram.Chat`: The chat that this update was sent in, no matter what kind of - update this is. Will be :obj:`None` for :attr:`inline_query`, - :attr:`chosen_inline_result`, :attr:`callback_query` from inline messages, - :attr:`shipping_query`, :attr:`pre_checkout_query`, :attr:`poll` and - :attr:`poll_answer`. - - """ - if self._effective_chat: - return self._effective_chat - - chat = None - - if self.message: - chat = self.message.chat - - elif self.edited_message: - chat = self.edited_message.chat - - elif self.callback_query and self.callback_query.message: - chat = self.callback_query.message.chat - - elif self.channel_post: - chat = self.channel_post.chat - - elif self.edited_channel_post: - chat = self.edited_channel_post.chat - - elif self.my_chat_member: - chat = self.my_chat_member.chat - - elif self.chat_member: - chat = self.chat_member.chat - - self._effective_chat = chat - return chat - - @property - def effective_message(self) -> Optional[Message]: - """ - :class:`telegram.Message`: The message included in this update, no matter what kind of - update this is. Will be :obj:`None` for :attr:`inline_query`, - :attr:`chosen_inline_result`, :attr:`callback_query` from inline messages, - :attr:`shipping_query`, :attr:`pre_checkout_query`, :attr:`poll` and - :attr:`poll_answer`. - - """ - if self._effective_message: - return self._effective_message - - message = None - - if self.message: - message = self.message - - elif self.edited_message: - message = self.edited_message - - elif self.callback_query: - message = self.callback_query.message - - elif self.channel_post: - message = self.channel_post - - elif self.edited_channel_post: - message = self.edited_channel_post - - self._effective_message = message - return message - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['Update']: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data['message'] = Message.de_json(data.get('message'), bot) - data['edited_message'] = Message.de_json(data.get('edited_message'), bot) - data['inline_query'] = InlineQuery.de_json(data.get('inline_query'), bot) - data['chosen_inline_result'] = ChosenInlineResult.de_json( - data.get('chosen_inline_result'), bot - ) - data['callback_query'] = CallbackQuery.de_json(data.get('callback_query'), bot) - data['shipping_query'] = ShippingQuery.de_json(data.get('shipping_query'), bot) - data['pre_checkout_query'] = PreCheckoutQuery.de_json(data.get('pre_checkout_query'), bot) - data['channel_post'] = Message.de_json(data.get('channel_post'), bot) - data['edited_channel_post'] = Message.de_json(data.get('edited_channel_post'), bot) - data['poll'] = Poll.de_json(data.get('poll'), bot) - data['poll_answer'] = PollAnswer.de_json(data.get('poll_answer'), bot) - data['my_chat_member'] = ChatMemberUpdated.de_json(data.get('my_chat_member'), bot) - data['chat_member'] = ChatMemberUpdated.de_json(data.get('chat_member'), bot) - - return cls(**data) diff --git a/venv/lib/python3.8/site-packages/telegram/user.py b/venv/lib/python3.8/site-packages/telegram/user.py deleted file mode 100644 index ecb4a3c..0000000 --- a/venv/lib/python3.8/site-packages/telegram/user.py +++ /dev/null @@ -1,1142 +0,0 @@ -#!/usr/bin/env python -# pylint: disable=W0622 -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram User.""" -from datetime import datetime -from typing import TYPE_CHECKING, Any, List, Optional, Union, Tuple - -from telegram import TelegramObject, constants -from telegram.utils.helpers import ( - mention_html as util_mention_html, - DEFAULT_NONE, - DEFAULT_20, -) -from telegram.utils.helpers import mention_markdown as util_mention_markdown -from telegram.utils.types import JSONDict, FileInput, ODVInput, DVInput - -if TYPE_CHECKING: - from telegram import ( - Bot, - Message, - UserProfilePhotos, - MessageId, - InputMediaAudio, - InputMediaDocument, - InputMediaPhoto, - InputMediaVideo, - MessageEntity, - ReplyMarkup, - PhotoSize, - Audio, - Contact, - Document, - InlineKeyboardMarkup, - LabeledPrice, - Location, - Animation, - Sticker, - Video, - Venue, - VideoNote, - Voice, - ) - - -class User(TelegramObject): - """This object represents a Telegram user or bot. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`id` is equal. - - Args: - id (:obj:`int`): Unique identifier for this user or bot. - is_bot (:obj:`bool`): :obj:`True`, if this user is a bot. - first_name (:obj:`str`): User's or bots first name. - last_name (:obj:`str`, optional): User's or bots last name. - username (:obj:`str`, optional): User's or bots username. - language_code (:obj:`str`, optional): IETF language tag of the user's language. - can_join_groups (:obj:`str`, optional): :obj:`True`, if the bot can be invited to groups. - Returned only in :attr:`telegram.Bot.get_me` requests. - can_read_all_group_messages (:obj:`str`, optional): :obj:`True`, if privacy mode is - disabled for the bot. Returned only in :attr:`telegram.Bot.get_me` requests. - supports_inline_queries (:obj:`str`, optional): :obj:`True`, if the bot supports inline - queries. Returned only in :attr:`telegram.Bot.get_me` requests. - bot (:class:`telegram.Bot`, optional): The Bot to use for instance methods. - - Attributes: - id (:obj:`int`): Unique identifier for this user or bot. - is_bot (:obj:`bool`): :obj:`True`, if this user is a bot. - first_name (:obj:`str`): User's or bot's first name. - last_name (:obj:`str`): Optional. User's or bot's last name. - username (:obj:`str`): Optional. User's or bot's username. - language_code (:obj:`str`): Optional. IETF language tag of the user's language. - can_join_groups (:obj:`str`): Optional. :obj:`True`, if the bot can be invited to groups. - Returned only in :attr:`telegram.Bot.get_me` requests. - can_read_all_group_messages (:obj:`str`): Optional. :obj:`True`, if privacy mode is - disabled for the bot. Returned only in :attr:`telegram.Bot.get_me` requests. - supports_inline_queries (:obj:`str`): Optional. :obj:`True`, if the bot supports inline - queries. Returned only in :attr:`telegram.Bot.get_me` requests. - bot (:class:`telegram.Bot`): Optional. The Bot to use for instance methods. - - """ - - __slots__ = ( - 'is_bot', - 'can_read_all_group_messages', - 'username', - 'first_name', - 'last_name', - 'can_join_groups', - 'supports_inline_queries', - 'id', - 'bot', - 'language_code', - '_id_attrs', - ) - - def __init__( - self, - id: int, - first_name: str, - is_bot: bool, - last_name: str = None, - username: str = None, - language_code: str = None, - can_join_groups: bool = None, - can_read_all_group_messages: bool = None, - supports_inline_queries: bool = None, - bot: 'Bot' = None, - **_kwargs: Any, - ): - # Required - self.id = int(id) # pylint: disable=C0103 - self.first_name = first_name - self.is_bot = is_bot - # Optionals - self.last_name = last_name - self.username = username - self.language_code = language_code - self.can_join_groups = can_join_groups - self.can_read_all_group_messages = can_read_all_group_messages - self.supports_inline_queries = supports_inline_queries - self.bot = bot - - self._id_attrs = (self.id,) - - @property - def name(self) -> str: - """:obj:`str`: Convenience property. If available, returns the user's :attr:`username` - prefixed with "@". If :attr:`username` is not available, returns :attr:`full_name`. - """ - if self.username: - return f'@{self.username}' - return self.full_name - - @property - def full_name(self) -> str: - """:obj:`str`: Convenience property. The user's :attr:`first_name`, followed by (if - available) :attr:`last_name`. - """ - if self.last_name: - return f'{self.first_name} {self.last_name}' - return self.first_name - - @property - def link(self) -> Optional[str]: - """:obj:`str`: Convenience property. If :attr:`username` is available, returns a t.me link - of the user. - """ - if self.username: - return f"https://t.me/{self.username}" - return None - - def get_profile_photos( - self, - offset: int = None, - limit: int = 100, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> Optional['UserProfilePhotos']: - """ - Shortcut for:: - - bot.get_user_profile_photos(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.get_user_profile_photos`. - - """ - return self.bot.get_user_profile_photos( - user_id=self.id, - offset=offset, - limit=limit, - timeout=timeout, - api_kwargs=api_kwargs, - ) - - def mention_markdown(self, name: str = None) -> str: - """ - Note: - :attr:`telegram.ParseMode.MARKDOWN` is is a legacy mode, retained by Telegram for - backward compatibility. You should use :meth:`mention_markdown_v2` instead. - - Args: - name (:obj:`str`): The name used as a link for the user. Defaults to :attr:`full_name`. - - Returns: - :obj:`str`: The inline mention for the user as markdown (version 1). - - """ - if name: - return util_mention_markdown(self.id, name) - return util_mention_markdown(self.id, self.full_name) - - def mention_markdown_v2(self, name: str = None) -> str: - """ - Args: - name (:obj:`str`): The name used as a link for the user. Defaults to :attr:`full_name`. - - Returns: - :obj:`str`: The inline mention for the user as markdown (version 2). - - """ - if name: - return util_mention_markdown(self.id, name, version=2) - return util_mention_markdown(self.id, self.full_name, version=2) - - def mention_html(self, name: str = None) -> str: - """ - Args: - name (:obj:`str`): The name used as a link for the user. Defaults to :attr:`full_name`. - - Returns: - :obj:`str`: The inline mention for the user as HTML. - - """ - if name: - return util_mention_html(self.id, name) - return util_mention_html(self.id, self.full_name) - - def pin_message( - self, - message_id: int, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> bool: - """Shortcut for:: - - bot.pin_chat_message(chat_id=update.effective_user.id, - *args, - **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.pin_chat_message`. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return self.bot.pin_chat_message( - chat_id=self.id, - message_id=message_id, - disable_notification=disable_notification, - timeout=timeout, - api_kwargs=api_kwargs, - ) - - def unpin_message( - self, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - message_id: int = None, - ) -> bool: - """Shortcut for:: - - bot.unpin_chat_message(chat_id=update.effective_user.id, - *args, - **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.unpin_chat_message`. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return self.bot.unpin_chat_message( - chat_id=self.id, - timeout=timeout, - api_kwargs=api_kwargs, - message_id=message_id, - ) - - def unpin_all_messages( - self, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> bool: - """Shortcut for:: - - bot.unpin_all_chat_messages(chat_id=update.effective_user.id, - *args, - **kwargs) - - For the documentation of the arguments, please see - :meth:`telegram.Bot.unpin_all_chat_messages`. - - Returns: - :obj:`bool`: On success, :obj:`True` is returned. - - """ - return self.bot.unpin_all_chat_messages( - chat_id=self.id, - timeout=timeout, - api_kwargs=api_kwargs, - ) - - def send_message( - self, - text: str, - parse_mode: ODVInput[str] = DEFAULT_NONE, - disable_web_page_preview: ODVInput[bool] = DEFAULT_NONE, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: 'ReplyMarkup' = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - ) -> 'Message': - """Shortcut for:: - - bot.send_message(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_message`. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return self.bot.send_message( - chat_id=self.id, - text=text, - parse_mode=parse_mode, - disable_web_page_preview=disable_web_page_preview, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - entities=entities, - ) - - def send_photo( - self, - photo: Union[FileInput, 'PhotoSize'], - caption: str = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: 'ReplyMarkup' = None, - timeout: DVInput[float] = DEFAULT_20, - parse_mode: ODVInput[str] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - filename: str = None, - ) -> 'Message': - """Shortcut for:: - - bot.send_message(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_photo`. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return self.bot.send_photo( - chat_id=self.id, - photo=photo, - caption=caption, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - parse_mode=parse_mode, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - filename=filename, - ) - - def send_media_group( - self, - media: List[ - Union['InputMediaAudio', 'InputMediaDocument', 'InputMediaPhoto', 'InputMediaVideo'] - ], - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - timeout: DVInput[float] = DEFAULT_20, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - ) -> List['Message']: - """Shortcut for:: - - bot.send_message(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_media_group`. - - Returns: - List[:class:`telegram.Message`:] On success, instance representing the message posted. - - """ - return self.bot.send_media_group( - chat_id=self.id, - media=media, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - timeout=timeout, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - ) - - def send_audio( - self, - audio: Union[FileInput, 'Audio'], - duration: int = None, - performer: str = None, - title: str = None, - caption: str = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: 'ReplyMarkup' = None, - timeout: DVInput[float] = DEFAULT_20, - parse_mode: ODVInput[str] = DEFAULT_NONE, - thumb: FileInput = None, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - filename: str = None, - ) -> 'Message': - """Shortcut for:: - - bot.send_message(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_audio`. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return self.bot.send_audio( - chat_id=self.id, - audio=audio, - duration=duration, - performer=performer, - title=title, - caption=caption, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - parse_mode=parse_mode, - thumb=thumb, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - filename=filename, - ) - - def send_chat_action( - self, - action: str, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> bool: - """Shortcut for:: - - bot.send_message(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_chat_action`. - - Returns: - :obj:`True`: On success. - - """ - return self.bot.send_chat_action( - chat_id=self.id, - action=action, - timeout=timeout, - api_kwargs=api_kwargs, - ) - - send_action = send_chat_action - """Alias for :attr:`send_chat_action`""" - - def send_contact( - self, - phone_number: str = None, - first_name: str = None, - last_name: str = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: 'ReplyMarkup' = None, - timeout: ODVInput[float] = DEFAULT_NONE, - contact: 'Contact' = None, - vcard: str = None, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - ) -> 'Message': - """Shortcut for:: - - bot.send_message(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_contact`. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return self.bot.send_contact( - chat_id=self.id, - phone_number=phone_number, - first_name=first_name, - last_name=last_name, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - contact=contact, - vcard=vcard, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - ) - - def send_dice( - self, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: 'ReplyMarkup' = None, - timeout: ODVInput[float] = DEFAULT_NONE, - emoji: str = None, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - ) -> 'Message': - """Shortcut for:: - - bot.send_message(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_dice`. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return self.bot.send_dice( - chat_id=self.id, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - emoji=emoji, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - ) - - def send_document( - self, - document: Union[FileInput, 'Document'], - filename: str = None, - caption: str = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: 'ReplyMarkup' = None, - timeout: DVInput[float] = DEFAULT_20, - parse_mode: ODVInput[str] = DEFAULT_NONE, - thumb: FileInput = None, - api_kwargs: JSONDict = None, - disable_content_type_detection: bool = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - ) -> 'Message': - """Shortcut for:: - - bot.send_message(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_document`. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return self.bot.send_document( - chat_id=self.id, - document=document, - filename=filename, - caption=caption, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - parse_mode=parse_mode, - thumb=thumb, - api_kwargs=api_kwargs, - disable_content_type_detection=disable_content_type_detection, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - ) - - def send_game( - self, - game_short_name: str, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: 'InlineKeyboardMarkup' = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - ) -> 'Message': - """Shortcut for:: - - bot.send_message(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_game`. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return self.bot.send_game( - chat_id=self.id, - game_short_name=game_short_name, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - ) - - def send_invoice( - self, - title: str, - description: str, - payload: str, - provider_token: str, - currency: str, - prices: List['LabeledPrice'], - start_parameter: str = None, - photo_url: str = None, - photo_size: int = None, - photo_width: int = None, - photo_height: int = None, - need_name: bool = None, - need_phone_number: bool = None, - need_email: bool = None, - need_shipping_address: bool = None, - is_flexible: bool = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: 'InlineKeyboardMarkup' = None, - provider_data: Union[str, object] = None, - send_phone_number_to_provider: bool = None, - send_email_to_provider: bool = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - max_tip_amount: int = None, - suggested_tip_amounts: List[int] = None, - ) -> 'Message': - """Shortcut for:: - - bot.send_message(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_invoice`. - - Warning: - As of API 5.2 :attr:`start_parameter` is an optional argument and therefore the order - of the arguments had to be changed. Use keyword arguments to make sure that the - arguments are passed correctly. - - .. versionchanged:: 13.5 - As of Bot API 5.2, the parameter :attr:`start_parameter` is optional. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return self.bot.send_invoice( - chat_id=self.id, - title=title, - description=description, - payload=payload, - provider_token=provider_token, - currency=currency, - prices=prices, - start_parameter=start_parameter, - photo_url=photo_url, - photo_size=photo_size, - photo_width=photo_width, - photo_height=photo_height, - need_name=need_name, - need_phone_number=need_phone_number, - need_email=need_email, - need_shipping_address=need_shipping_address, - is_flexible=is_flexible, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - provider_data=provider_data, - send_phone_number_to_provider=send_phone_number_to_provider, - send_email_to_provider=send_email_to_provider, - timeout=timeout, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - max_tip_amount=max_tip_amount, - suggested_tip_amounts=suggested_tip_amounts, - ) - - def send_location( - self, - latitude: float = None, - longitude: float = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: 'ReplyMarkup' = None, - timeout: ODVInput[float] = DEFAULT_NONE, - location: 'Location' = None, - live_period: int = None, - api_kwargs: JSONDict = None, - horizontal_accuracy: float = None, - heading: int = None, - proximity_alert_radius: int = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - ) -> 'Message': - """Shortcut for:: - - bot.send_message(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_location`. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return self.bot.send_location( - chat_id=self.id, - latitude=latitude, - longitude=longitude, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - location=location, - live_period=live_period, - api_kwargs=api_kwargs, - horizontal_accuracy=horizontal_accuracy, - heading=heading, - proximity_alert_radius=proximity_alert_radius, - allow_sending_without_reply=allow_sending_without_reply, - ) - - def send_animation( - self, - animation: Union[FileInput, 'Animation'], - duration: int = None, - width: int = None, - height: int = None, - thumb: FileInput = None, - caption: str = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: 'ReplyMarkup' = None, - timeout: DVInput[float] = DEFAULT_20, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - filename: str = None, - ) -> 'Message': - """Shortcut for:: - - bot.send_message(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_animation`. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return self.bot.send_animation( - chat_id=self.id, - animation=animation, - duration=duration, - width=width, - height=height, - thumb=thumb, - caption=caption, - parse_mode=parse_mode, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - filename=filename, - ) - - def send_sticker( - self, - sticker: Union[FileInput, 'Sticker'], - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: 'ReplyMarkup' = None, - timeout: DVInput[float] = DEFAULT_20, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - ) -> 'Message': - """Shortcut for:: - - bot.send_message(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_sticker`. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return self.bot.send_sticker( - chat_id=self.id, - sticker=sticker, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - ) - - def send_video( - self, - video: Union[FileInput, 'Video'], - duration: int = None, - caption: str = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: 'ReplyMarkup' = None, - timeout: DVInput[float] = DEFAULT_20, - width: int = None, - height: int = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - supports_streaming: bool = None, - thumb: FileInput = None, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - filename: str = None, - ) -> 'Message': - """Shortcut for:: - - bot.send_message(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_video`. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return self.bot.send_video( - chat_id=self.id, - video=video, - duration=duration, - caption=caption, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - width=width, - height=height, - parse_mode=parse_mode, - supports_streaming=supports_streaming, - thumb=thumb, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - filename=filename, - ) - - def send_venue( - self, - latitude: float = None, - longitude: float = None, - title: str = None, - address: str = None, - foursquare_id: str = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: 'ReplyMarkup' = None, - timeout: ODVInput[float] = DEFAULT_NONE, - venue: 'Venue' = None, - foursquare_type: str = None, - api_kwargs: JSONDict = None, - google_place_id: str = None, - google_place_type: str = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - ) -> 'Message': - """Shortcut for:: - - bot.send_message(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_venue`. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return self.bot.send_venue( - chat_id=self.id, - latitude=latitude, - longitude=longitude, - title=title, - address=address, - foursquare_id=foursquare_id, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - venue=venue, - foursquare_type=foursquare_type, - api_kwargs=api_kwargs, - google_place_id=google_place_id, - google_place_type=google_place_type, - allow_sending_without_reply=allow_sending_without_reply, - ) - - def send_video_note( - self, - video_note: Union[FileInput, 'VideoNote'], - duration: int = None, - length: int = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: 'ReplyMarkup' = None, - timeout: DVInput[float] = DEFAULT_20, - thumb: FileInput = None, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - filename: str = None, - ) -> 'Message': - """Shortcut for:: - - bot.send_message(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_video_note`. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return self.bot.send_video_note( - chat_id=self.id, - video_note=video_note, - duration=duration, - length=length, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - thumb=thumb, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - filename=filename, - ) - - def send_voice( - self, - voice: Union[FileInput, 'Voice'], - duration: int = None, - caption: str = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: 'ReplyMarkup' = None, - timeout: DVInput[float] = DEFAULT_20, - parse_mode: ODVInput[str] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - caption_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - filename: str = None, - ) -> 'Message': - """Shortcut for:: - - bot.send_message(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_voice`. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return self.bot.send_voice( - chat_id=self.id, - voice=voice, - duration=duration, - caption=caption, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - parse_mode=parse_mode, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - caption_entities=caption_entities, - filename=filename, - ) - - def send_poll( - self, - question: str, - options: List[str], - is_anonymous: bool = True, - # We use constant.POLL_REGULAR instead of Poll.REGULAR here to avoid circular imports - type: str = constants.POLL_REGULAR, # pylint: disable=W0622 - allows_multiple_answers: bool = False, - correct_option_id: int = None, - is_closed: bool = None, - disable_notification: ODVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - reply_markup: 'ReplyMarkup' = None, - timeout: ODVInput[float] = DEFAULT_NONE, - explanation: str = None, - explanation_parse_mode: ODVInput[str] = DEFAULT_NONE, - open_period: int = None, - close_date: Union[int, datetime] = None, - api_kwargs: JSONDict = None, - allow_sending_without_reply: ODVInput[bool] = DEFAULT_NONE, - explanation_entities: Union[List['MessageEntity'], Tuple['MessageEntity', ...]] = None, - ) -> 'Message': - """Shortcut for:: - - bot.send_message(update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.send_poll`. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return self.bot.send_poll( - chat_id=self.id, - question=question, - options=options, - is_anonymous=is_anonymous, - type=type, # pylint=pylint, - allows_multiple_answers=allows_multiple_answers, - correct_option_id=correct_option_id, - is_closed=is_closed, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - reply_markup=reply_markup, - timeout=timeout, - explanation=explanation, - explanation_parse_mode=explanation_parse_mode, - open_period=open_period, - close_date=close_date, - api_kwargs=api_kwargs, - allow_sending_without_reply=allow_sending_without_reply, - explanation_entities=explanation_entities, - ) - - def send_copy( - self, - from_chat_id: Union[str, int], - message_id: int, - caption: str = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[Tuple['MessageEntity', ...], List['MessageEntity']] = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE, - reply_markup: 'ReplyMarkup' = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> 'MessageId': - """Shortcut for:: - - bot.copy_message(chat_id=update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.copy_message`. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return self.bot.copy_message( - chat_id=self.id, - from_chat_id=from_chat_id, - message_id=message_id, - caption=caption, - parse_mode=parse_mode, - caption_entities=caption_entities, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - allow_sending_without_reply=allow_sending_without_reply, - reply_markup=reply_markup, - timeout=timeout, - api_kwargs=api_kwargs, - ) - - def copy_message( - self, - chat_id: Union[int, str], - message_id: int, - caption: str = None, - parse_mode: ODVInput[str] = DEFAULT_NONE, - caption_entities: Union[Tuple['MessageEntity', ...], List['MessageEntity']] = None, - disable_notification: DVInput[bool] = DEFAULT_NONE, - reply_to_message_id: int = None, - allow_sending_without_reply: DVInput[bool] = DEFAULT_NONE, - reply_markup: 'ReplyMarkup' = None, - timeout: ODVInput[float] = DEFAULT_NONE, - api_kwargs: JSONDict = None, - ) -> 'MessageId': - """Shortcut for:: - - bot.copy_message(from_chat_id=update.effective_user.id, *args, **kwargs) - - For the documentation of the arguments, please see :meth:`telegram.Bot.copy_message`. - - Returns: - :class:`telegram.Message`: On success, instance representing the message posted. - - """ - return self.bot.copy_message( - from_chat_id=self.id, - chat_id=chat_id, - message_id=message_id, - caption=caption, - parse_mode=parse_mode, - caption_entities=caption_entities, - disable_notification=disable_notification, - reply_to_message_id=reply_to_message_id, - allow_sending_without_reply=allow_sending_without_reply, - reply_markup=reply_markup, - timeout=timeout, - api_kwargs=api_kwargs, - ) diff --git a/venv/lib/python3.8/site-packages/telegram/userprofilephotos.py b/venv/lib/python3.8/site-packages/telegram/userprofilephotos.py deleted file mode 100644 index bd277bf..0000000 --- a/venv/lib/python3.8/site-packages/telegram/userprofilephotos.py +++ /dev/null @@ -1,79 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram UserProfilePhotos.""" - -from typing import TYPE_CHECKING, Any, List, Optional - -from telegram import PhotoSize, TelegramObject -from telegram.utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - - -class UserProfilePhotos(TelegramObject): - """This object represent a user's profile pictures. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`total_count` and :attr:`photos` are equal. - - Args: - total_count (:obj:`int`): Total number of profile pictures the target user has. - photos (List[List[:class:`telegram.PhotoSize`]]): Requested profile pictures (in up to 4 - sizes each). - - Attributes: - total_count (:obj:`int`): Total number of profile pictures. - photos (List[List[:class:`telegram.PhotoSize`]]): Requested profile pictures. - - """ - - __slots__ = ('photos', 'total_count', '_id_attrs') - - def __init__(self, total_count: int, photos: List[List[PhotoSize]], **_kwargs: Any): - # Required - self.total_count = int(total_count) - self.photos = photos - - self._id_attrs = (self.total_count, self.photos) - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['UserProfilePhotos']: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data['photos'] = [PhotoSize.de_list(photo, bot) for photo in data['photos']] - - return cls(**data) - - def to_dict(self) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict() - - data['photos'] = [] - for photo in self.photos: - data['photos'].append([x.to_dict() for x in photo]) - - return data - - def __hash__(self) -> int: - return hash(tuple(tuple(p for p in photo) for photo in self.photos)) diff --git a/venv/lib/python3.8/site-packages/telegram/utils/__init__.py b/venv/lib/python3.8/site-packages/telegram/utils/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.8/site-packages/telegram/utils/deprecate.py b/venv/lib/python3.8/site-packages/telegram/utils/deprecate.py deleted file mode 100644 index fbf6042..0000000 --- a/venv/lib/python3.8/site-packages/telegram/utils/deprecate.py +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module facilitates the deprecation of functions.""" - -import warnings - - -# We use our own DeprecationWarning since they are muted by default and "UserWarning" makes it -# seem like it's the user that issued the warning -# We name it something else so that you don't get confused when you attempt to suppress it -class TelegramDeprecationWarning(Warning): - """Custom warning class for deprecations in this library.""" - - __slots__ = () - - -# Function to warn users that setting custom attributes is deprecated (Use only in __setattr__!) -# Checks if a custom attribute is added by checking length of dictionary before & after -# assigning attribute. This is the fastest way to do it (I hope!). -def set_new_attribute_deprecated(self: object, key: str, value: object) -> None: - """Warns the user if they set custom attributes on PTB objects.""" - org = len(self.__dict__) - object.__setattr__(self, key, value) - new = len(self.__dict__) - if new > org: - warnings.warn( - "Setting custom attributes on objects of the PTB library is deprecated.", - TelegramDeprecationWarning, - ) diff --git a/venv/lib/python3.8/site-packages/telegram/utils/helpers.py b/venv/lib/python3.8/site-packages/telegram/utils/helpers.py deleted file mode 100644 index 6705cc9..0000000 --- a/venv/lib/python3.8/site-packages/telegram/utils/helpers.py +++ /dev/null @@ -1,596 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains helper functions.""" - -import datetime as dtm # dtm = "DateTime Module" -import re -import signal -import time - -from collections import defaultdict -from html import escape -from pathlib import Path - -from typing import ( - TYPE_CHECKING, - Any, - DefaultDict, - Dict, - Optional, - Tuple, - Union, - Type, - cast, - IO, - TypeVar, - Generic, - overload, -) - -from telegram.utils.types import JSONDict, FileInput - -if TYPE_CHECKING: - from telegram import Message, Update, TelegramObject, InputFile - -# in PTB-Raw we don't have pytz, so we make a little workaround here -DTM_UTC = dtm.timezone.utc -try: - import pytz - - UTC = pytz.utc -except ImportError: - UTC = DTM_UTC # type: ignore[assignment] - -try: - import ujson as json -except ImportError: - import json # type: ignore[no-redef] - - -# From https://stackoverflow.com/questions/2549939/get-signal-names-from-numbers-in-python -_signames = { - v: k - for k, v in reversed(sorted(vars(signal).items())) - if k.startswith('SIG') and not k.startswith('SIG_') -} - - -def get_signal_name(signum: int) -> str: - """Returns the signal name of the given signal number.""" - return _signames[signum] - - -def is_local_file(obj: Optional[Union[str, Path]]) -> bool: - """ - Checks if a given string is a file on local system. - - Args: - obj (:obj:`str`): The string to check. - """ - if obj is None: - return False - - path = Path(obj) - try: - return path.is_file() - except Exception: - return False - - -def parse_file_input( - file_input: Union[FileInput, 'TelegramObject'], - tg_type: Type['TelegramObject'] = None, - attach: bool = None, - filename: str = None, -) -> Union[str, 'InputFile', Any]: - """ - Parses input for sending files: - - * For string input, if the input is an absolute path of a local file, - adds the ``file://`` prefix. If the input is a relative path of a local file, computes the - absolute path and adds the ``file://`` prefix. Returns the input unchanged, otherwise. - * :class:`pathlib.Path` objects are treated the same way as strings. - * For IO and bytes input, returns an :class:`telegram.InputFile`. - * If :attr:`tg_type` is specified and the input is of that type, returns the ``file_id`` - attribute. - - Args: - file_input (:obj:`str` | :obj:`bytes` | `filelike object` | Telegram media object): The - input to parse. - tg_type (:obj:`type`, optional): The Telegram media type the input can be. E.g. - :class:`telegram.Animation`. - attach (:obj:`bool`, optional): Whether this file should be send as one file or is part of - a collection of files. Only relevant in case an :class:`telegram.InputFile` is - returned. - filename (:obj:`str`, optional): The filename. Only relevant in case an - :class:`telegram.InputFile` is returned. - - Returns: - :obj:`str` | :class:`telegram.InputFile` | :obj:`object`: The parsed input or the untouched - :attr:`file_input`, in case it's no valid file input. - """ - # Importing on file-level yields cyclic Import Errors - from telegram import InputFile # pylint: disable=C0415 - - if isinstance(file_input, str) and file_input.startswith('file://'): - return file_input - if isinstance(file_input, (str, Path)): - if is_local_file(file_input): - out = Path(file_input).absolute().as_uri() - else: - out = file_input # type: ignore[assignment] - return out - if isinstance(file_input, bytes): - return InputFile(file_input, attach=attach, filename=filename) - if InputFile.is_file(file_input): - file_input = cast(IO, file_input) - return InputFile(file_input, attach=attach, filename=filename) - if tg_type and isinstance(file_input, tg_type): - return file_input.file_id # type: ignore[attr-defined] - return file_input - - -def escape_markdown(text: str, version: int = 1, entity_type: str = None) -> str: - """ - Helper function to escape telegram markup symbols. - - Args: - text (:obj:`str`): The text. - version (:obj:`int` | :obj:`str`): Use to specify the version of telegrams Markdown. - Either ``1`` or ``2``. Defaults to ``1``. - entity_type (:obj:`str`, optional): For the entity types ``PRE``, ``CODE`` and the link - part of ``TEXT_LINKS``, only certain characters need to be escaped in ``MarkdownV2``. - See the official API documentation for details. Only valid in combination with - ``version=2``, will be ignored else. - """ - if int(version) == 1: - escape_chars = r'_*`[' - elif int(version) == 2: - if entity_type in ['pre', 'code']: - escape_chars = r'\`' - elif entity_type == 'text_link': - escape_chars = r'\)' - else: - escape_chars = r'_*[]()~`>#+-=|{}.!' - else: - raise ValueError('Markdown version must be either 1 or 2!') - - return re.sub(f'([{re.escape(escape_chars)}])', r'\\\1', text) - - -# -------- date/time related helpers -------- -def _datetime_to_float_timestamp(dt_obj: dtm.datetime) -> float: - """ - Converts a datetime object to a float timestamp (with sub-second precision). - If the datetime object is timezone-naive, it is assumed to be in UTC. - """ - if dt_obj.tzinfo is None: - dt_obj = dt_obj.replace(tzinfo=dtm.timezone.utc) - return dt_obj.timestamp() - - -def _localize(datetime: dtm.datetime, tzinfo: dtm.tzinfo) -> dtm.datetime: - """Localize the datetime, where UTC is handled depending on whether pytz is available or not""" - if tzinfo is DTM_UTC: - return datetime.replace(tzinfo=DTM_UTC) - return tzinfo.localize(datetime) # type: ignore[attr-defined] - - -def to_float_timestamp( - time_object: Union[int, float, dtm.timedelta, dtm.datetime, dtm.time], - reference_timestamp: float = None, - tzinfo: dtm.tzinfo = None, -) -> float: - """ - Converts a given time object to a float POSIX timestamp. - Used to convert different time specifications to a common format. The time object - can be relative (i.e. indicate a time increment, or a time of day) or absolute. - object objects from the :class:`datetime` module that are timezone-naive will be assumed - to be in UTC, if ``bot`` is not passed or ``bot.defaults`` is :obj:`None`. - - Args: - time_object (:obj:`int` | :obj:`float` | :obj:`datetime.timedelta` | \ - :obj:`datetime.datetime` | :obj:`datetime.time`): - Time value to convert. The semantics of this parameter will depend on its type: - - * :obj:`int` or :obj:`float` will be interpreted as "seconds from ``reference_t``" - * :obj:`datetime.timedelta` will be interpreted as - "time increment from ``reference_t``" - * :obj:`datetime.datetime` will be interpreted as an absolute date/time value - * :obj:`datetime.time` will be interpreted as a specific time of day - - reference_timestamp (:obj:`float`, optional): POSIX timestamp that indicates the absolute - time from which relative calculations are to be performed (e.g. when ``t`` is given as - an :obj:`int`, indicating "seconds from ``reference_t``"). Defaults to now (the time at - which this function is called). - - If ``t`` is given as an absolute representation of date & time (i.e. a - :obj:`datetime.datetime` object), ``reference_timestamp`` is not relevant and so its - value should be :obj:`None`. If this is not the case, a ``ValueError`` will be raised. - tzinfo (:obj:`pytz.BaseTzInfo`, optional): If ``t`` is a naive object from the - :class:`datetime` module, it will be interpreted as this timezone. Defaults to - ``pytz.utc``. - - Note: - Only to be used by ``telegram.ext``. - - - Returns: - :obj:`float` | :obj:`None`: - The return value depends on the type of argument ``t``. - If ``t`` is given as a time increment (i.e. as a :obj:`int`, :obj:`float` or - :obj:`datetime.timedelta`), then the return value will be ``reference_t`` + ``t``. - - Else if it is given as an absolute date/time value (i.e. a :obj:`datetime.datetime` - object), the equivalent value as a POSIX timestamp will be returned. - - Finally, if it is a time of the day without date (i.e. a :obj:`datetime.time` - object), the return value is the nearest future occurrence of that time of day. - - Raises: - TypeError: If ``t``'s type is not one of those described above. - ValueError: If ``t`` is a :obj:`datetime.datetime` and :obj:`reference_timestamp` is not - :obj:`None`. - """ - if reference_timestamp is None: - reference_timestamp = time.time() - elif isinstance(time_object, dtm.datetime): - raise ValueError('t is an (absolute) datetime while reference_timestamp is not None') - - if isinstance(time_object, dtm.timedelta): - return reference_timestamp + time_object.total_seconds() - if isinstance(time_object, (int, float)): - return reference_timestamp + time_object - - if tzinfo is None: - tzinfo = UTC - - if isinstance(time_object, dtm.time): - reference_dt = dtm.datetime.fromtimestamp( - reference_timestamp, tz=time_object.tzinfo or tzinfo - ) - reference_date = reference_dt.date() - reference_time = reference_dt.timetz() - - aware_datetime = dtm.datetime.combine(reference_date, time_object) - if aware_datetime.tzinfo is None: - aware_datetime = _localize(aware_datetime, tzinfo) - - # if the time of day has passed today, use tomorrow - if reference_time > aware_datetime.timetz(): - aware_datetime += dtm.timedelta(days=1) - return _datetime_to_float_timestamp(aware_datetime) - if isinstance(time_object, dtm.datetime): - if time_object.tzinfo is None: - time_object = _localize(time_object, tzinfo) - return _datetime_to_float_timestamp(time_object) - - raise TypeError(f'Unable to convert {type(time_object).__name__} object to timestamp') - - -def to_timestamp( - dt_obj: Union[int, float, dtm.timedelta, dtm.datetime, dtm.time, None], - reference_timestamp: float = None, - tzinfo: dtm.tzinfo = None, -) -> Optional[int]: - """ - Wrapper over :func:`to_float_timestamp` which returns an integer (the float value truncated - down to the nearest integer). - - See the documentation for :func:`to_float_timestamp` for more details. - """ - return ( - int(to_float_timestamp(dt_obj, reference_timestamp, tzinfo)) - if dt_obj is not None - else None - ) - - -def from_timestamp(unixtime: Optional[int], tzinfo: dtm.tzinfo = UTC) -> Optional[dtm.datetime]: - """ - Converts an (integer) unix timestamp to a timezone aware datetime object. - :obj:`None` s are left alone (i.e. ``from_timestamp(None)`` is :obj:`None`). - - Args: - unixtime (:obj:`int`): Integer POSIX timestamp. - tzinfo (:obj:`datetime.tzinfo`, optional): The timezone to which the timestamp is to be - converted to. Defaults to UTC. - - Returns: - Timezone aware equivalent :obj:`datetime.datetime` value if ``unixtime`` is not - :obj:`None`; else :obj:`None`. - """ - if unixtime is None: - return None - - if tzinfo is not None: - return dtm.datetime.fromtimestamp(unixtime, tz=tzinfo) - return dtm.datetime.utcfromtimestamp(unixtime) - - -# -------- end -------- - - -def mention_html(user_id: Union[int, str], name: str) -> str: - """ - Args: - user_id (:obj:`int`): The user's id which you want to mention. - name (:obj:`str`): The name the mention is showing. - - Returns: - :obj:`str`: The inline mention for the user as HTML. - """ - return f'<a href="tg://user?id={user_id}">{escape(name)}</a>' - - -def mention_markdown(user_id: Union[int, str], name: str, version: int = 1) -> str: - """ - Args: - user_id (:obj:`int`): The user's id which you want to mention. - name (:obj:`str`): The name the mention is showing. - version (:obj:`int` | :obj:`str`): Use to specify the version of Telegram's Markdown. - Either ``1`` or ``2``. Defaults to ``1``. - - Returns: - :obj:`str`: The inline mention for the user as Markdown. - """ - return f'[{escape_markdown(name, version=version)}](tg://user?id={user_id})' - - -def effective_message_type(entity: Union['Message', 'Update']) -> Optional[str]: - """ - Extracts the type of message as a string identifier from a :class:`telegram.Message` or a - :class:`telegram.Update`. - - Args: - entity (:class:`telegram.Update` | :class:`telegram.Message`): The ``update`` or - ``message`` to extract from. - - Returns: - :obj:`str`: One of ``Message.MESSAGE_TYPES`` - - """ - # Importing on file-level yields cyclic Import Errors - from telegram import Message, Update # pylint: disable=C0415 - - if isinstance(entity, Message): - message = entity - elif isinstance(entity, Update): - message = entity.effective_message # type: ignore[assignment] - else: - raise TypeError(f"entity is not Message or Update (got: {type(entity)})") - - for i in Message.MESSAGE_TYPES: - if getattr(message, i, None): - return i - - return None - - -def create_deep_linked_url(bot_username: str, payload: str = None, group: bool = False) -> str: - """ - Creates a deep-linked URL for this ``bot_username`` with the specified ``payload``. - See https://core.telegram.org/bots#deep-linking to learn more. - - The ``payload`` may consist of the following characters: ``A-Z, a-z, 0-9, _, -`` - - Note: - Works well in conjunction with - ``CommandHandler("start", callback, filters = Filters.regex('payload'))`` - - Examples: - ``create_deep_linked_url(bot.get_me().username, "some-params")`` - - Args: - bot_username (:obj:`str`): The username to link to - payload (:obj:`str`, optional): Parameters to encode in the created URL - group (:obj:`bool`, optional): If :obj:`True` the user is prompted to select a group to - add the bot to. If :obj:`False`, opens a one-on-one conversation with the bot. - Defaults to :obj:`False`. - - Returns: - :obj:`str`: An URL to start the bot with specific parameters - """ - if bot_username is None or len(bot_username) <= 3: - raise ValueError("You must provide a valid bot_username.") - - base_url = f'https://t.me/{bot_username}' - if not payload: - return base_url - - if len(payload) > 64: - raise ValueError("The deep-linking payload must not exceed 64 characters.") - - if not re.match(r'^[A-Za-z0-9_-]+$', payload): - raise ValueError( - "Only the following characters are allowed for deep-linked " - "URLs: A-Z, a-z, 0-9, _ and -" - ) - - if group: - key = 'startgroup' - else: - key = 'start' - - return f'{base_url}?{key}={payload}' - - -def encode_conversations_to_json(conversations: Dict[str, Dict[Tuple, object]]) -> str: - """Helper method to encode a conversations dict (that uses tuples as keys) to a - JSON-serializable way. Use :meth:`decode_conversations_from_json` to decode. - - Args: - conversations (:obj:`dict`): The conversations dict to transform to JSON. - - Returns: - :obj:`str`: The JSON-serialized conversations dict - """ - tmp: Dict[str, JSONDict] = {} - for handler, states in conversations.items(): - tmp[handler] = {} - for key, state in states.items(): - tmp[handler][json.dumps(key)] = state - return json.dumps(tmp) - - -def decode_conversations_from_json(json_string: str) -> Dict[str, Dict[Tuple, object]]: - """Helper method to decode a conversations dict (that uses tuples as keys) from a - JSON-string created with :meth:`encode_conversations_to_json`. - - Args: - json_string (:obj:`str`): The conversations dict as JSON string. - - Returns: - :obj:`dict`: The conversations dict after decoding - """ - tmp = json.loads(json_string) - conversations: Dict[str, Dict[Tuple, object]] = {} - for handler, states in tmp.items(): - conversations[handler] = {} - for key, state in states.items(): - conversations[handler][tuple(json.loads(key))] = state - return conversations - - -def decode_user_chat_data_from_json(data: str) -> DefaultDict[int, Dict[object, object]]: - """Helper method to decode chat or user data (that uses ints as keys) from a - JSON-string. - - Args: - data (:obj:`str`): The user/chat_data dict as JSON string. - - Returns: - :obj:`dict`: The user/chat_data defaultdict after decoding - """ - tmp: DefaultDict[int, Dict[object, object]] = defaultdict(dict) - decoded_data = json.loads(data) - for user, user_data in decoded_data.items(): - user = int(user) - tmp[user] = {} - for key, value in user_data.items(): - try: - key = int(key) - except ValueError: - pass - tmp[user][key] = value - return tmp - - -DVType = TypeVar('DVType', bound=object) -OT = TypeVar('OT', bound=object) - - -class DefaultValue(Generic[DVType]): - """Wrapper for immutable default arguments that allows to check, if the default value was set - explicitly. Usage:: - - DefaultOne = DefaultValue(1) - def f(arg=DefaultOne): - if arg is DefaultOne: - print('`arg` is the default') - arg = arg.value - else: - print('`arg` was set explicitly') - print(f'`arg` = {str(arg)}') - - This yields:: - - >>> f() - `arg` is the default - `arg` = 1 - >>> f(1) - `arg` was set explicitly - `arg` = 1 - >>> f(2) - `arg` was set explicitly - `arg` = 2 - - Also allows to evaluate truthiness:: - - default = DefaultValue(value) - if default: - ... - - is equivalent to:: - - default = DefaultValue(value) - if value: - ... - - ``repr(DefaultValue(value))`` returns ``repr(value)`` and ``str(DefaultValue(value))`` returns - ``f'DefaultValue({value})'``. - - Args: - value (:obj:`obj`): The value of the default argument - - Attributes: - value (:obj:`obj`): The value of the default argument - - """ - - __slots__ = ('value', '__dict__') - - def __init__(self, value: DVType = None): - self.value = value - - def __bool__(self) -> bool: - return bool(self.value) - - @overload - @staticmethod - def get_value(obj: 'DefaultValue[OT]') -> OT: - ... - - @overload - @staticmethod - def get_value(obj: OT) -> OT: - ... - - @staticmethod - def get_value(obj: Union[OT, 'DefaultValue[OT]']) -> OT: - """ - Shortcut for:: - - return obj.value if isinstance(obj, DefaultValue) else obj - - Args: - obj (:obj:`object`): The object to process - - Returns: - Same type as input, or the value of the input: The value - """ - return obj.value if isinstance(obj, DefaultValue) else obj # type: ignore[return-value] - - # This is mostly here for readability during debugging - def __str__(self) -> str: - return f'DefaultValue({self.value})' - - # This is here to have the default instances nicely rendered in the docs - def __repr__(self) -> str: - return repr(self.value) - - -DEFAULT_NONE: DefaultValue = DefaultValue(None) -""":class:`DefaultValue`: Default :obj:`None`""" - -DEFAULT_FALSE: DefaultValue = DefaultValue(False) -""":class:`DefaultValue`: Default :obj:`False`""" - -DEFAULT_20: DefaultValue = DefaultValue(20) -""":class:`DefaultValue`: Default :obj:`20`""" diff --git a/venv/lib/python3.8/site-packages/telegram/utils/promise.py b/venv/lib/python3.8/site-packages/telegram/utils/promise.py deleted file mode 100644 index c25d56d..0000000 --- a/venv/lib/python3.8/site-packages/telegram/utils/promise.py +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the :class:`telegram.ext.utils.promise.Promise` class for backwards -compatibility. -""" -import warnings - -import telegram.ext.utils.promise as promise -from telegram.utils.deprecate import TelegramDeprecationWarning - -warnings.warn( - 'telegram.utils.promise is deprecated. Please use telegram.ext.utils.promise instead.', - TelegramDeprecationWarning, -) - -Promise = promise.Promise -""" -:class:`telegram.ext.utils.promise.Promise` - -.. deprecated:: v13.2 - Use :class:`telegram.ext.utils.promise.Promise` instead. -""" diff --git a/venv/lib/python3.8/site-packages/telegram/utils/request.py b/venv/lib/python3.8/site-packages/telegram/utils/request.py deleted file mode 100644 index f2c35bf..0000000 --- a/venv/lib/python3.8/site-packages/telegram/utils/request.py +++ /dev/null @@ -1,395 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains methods to make POST and GET requests.""" -import logging -import os -import socket -import sys -import warnings - -try: - import ujson as json -except ImportError: - import json # type: ignore[no-redef] - -from typing import Any, Union - -import certifi - -try: - import telegram.vendor.ptb_urllib3.urllib3 as urllib3 - import telegram.vendor.ptb_urllib3.urllib3.contrib.appengine as appengine - from telegram.vendor.ptb_urllib3.urllib3.connection import HTTPConnection - from telegram.vendor.ptb_urllib3.urllib3.fields import RequestField - from telegram.vendor.ptb_urllib3.urllib3.util.timeout import Timeout -except ImportError: # pragma: no cover - try: - import urllib3 # type: ignore[no-redef] - import urllib3.contrib.appengine as appengine # type: ignore[no-redef] - from urllib3.connection import HTTPConnection # type: ignore[no-redef] - from urllib3.fields import RequestField # type: ignore[no-redef] - from urllib3.util.timeout import Timeout # type: ignore[no-redef] - - warnings.warn( - 'python-telegram-bot is using upstream urllib3. This is allowed but not ' - 'supported by python-telegram-bot maintainers.' - ) - except ImportError: - warnings.warn( - "python-telegram-bot wasn't properly installed. Please refer to README.rst on " - "how to properly install." - ) - raise - -# pylint: disable=C0412 -from telegram import InputFile, InputMedia, TelegramError -from telegram.error import ( - BadRequest, - ChatMigrated, - Conflict, - InvalidToken, - NetworkError, - RetryAfter, - TimedOut, - Unauthorized, -) -from telegram.utils.types import JSONDict -from telegram.utils.deprecate import set_new_attribute_deprecated - - -def _render_part(self: RequestField, name: str, value: str) -> str: # pylint: disable=W0613 - r""" - Monkey patch urllib3.urllib3.fields.RequestField to make it *not* support RFC2231 compliant - Content-Disposition headers since telegram servers don't understand it. Instead just escape - \\ and " and replace any \n and \r with a space. - """ - value = value.replace('\\', '\\\\').replace('"', '\\"') - value = value.replace('\r', ' ').replace('\n', ' ') - return f'{name}="{value}"' - - -RequestField._render_part = _render_part # type: ignore # pylint: disable=W0212 - -logging.getLogger('telegram.vendor.ptb_urllib3.urllib3').setLevel(logging.WARNING) - -USER_AGENT = 'Python Telegram Bot (https://github.com/python-telegram-bot/python-telegram-bot)' - - -class Request: - """ - Helper class for python-telegram-bot which provides methods to perform POST & GET towards - Telegram servers. - - Args: - con_pool_size (:obj:`int`): Number of connections to keep in the connection pool. - proxy_url (:obj:`str`): The URL to the proxy server. For example: `http://127.0.0.1:3128`. - urllib3_proxy_kwargs (:obj:`dict`): Arbitrary arguments passed as-is to - :obj:`urllib3.ProxyManager`. This value will be ignored if :attr:`proxy_url` is not - set. - connect_timeout (:obj:`int` | :obj:`float`): The maximum amount of time (in seconds) to - wait for a connection attempt to a server to succeed. :obj:`None` will set an - infinite timeout for connection attempts. Defaults to ``5.0``. - read_timeout (:obj:`int` | :obj:`float`): The maximum amount of time (in seconds) to wait - between consecutive read operations for a response from the server. :obj:`None` will - set an infinite timeout. This value is usually overridden by the various - :class:`telegram.Bot` methods. Defaults to ``5.0``. - - """ - - __slots__ = ('_connect_timeout', '_con_pool_size', '_con_pool', '__dict__') - - def __init__( - self, - con_pool_size: int = 1, - proxy_url: str = None, - urllib3_proxy_kwargs: JSONDict = None, - connect_timeout: float = 5.0, - read_timeout: float = 5.0, - ): - if urllib3_proxy_kwargs is None: - urllib3_proxy_kwargs = {} - - self._connect_timeout = connect_timeout - - sockopts = HTTPConnection.default_socket_options + [ - (socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) - ] - - # TODO: Support other platforms like mac and windows. - if 'linux' in sys.platform: - sockopts.append( - (socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 120) # pylint: disable=no-member - ) - sockopts.append( - (socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 30) # pylint: disable=no-member - ) - sockopts.append( - (socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 8) # pylint: disable=no-member - ) - - self._con_pool_size = con_pool_size - - kwargs = dict( - maxsize=con_pool_size, - cert_reqs='CERT_REQUIRED', - ca_certs=certifi.where(), - socket_options=sockopts, - timeout=urllib3.Timeout(connect=self._connect_timeout, read=read_timeout, total=None), - ) - - # Set a proxy according to the following order: - # * proxy defined in proxy_url (+ urllib3_proxy_kwargs) - # * proxy set in `HTTPS_PROXY` env. var. - # * proxy set in `https_proxy` env. var. - # * None (if no proxy is configured) - - if not proxy_url: - proxy_url = os.environ.get('HTTPS_PROXY') or os.environ.get('https_proxy') - - self._con_pool: Union[ - urllib3.PoolManager, - appengine.AppEngineManager, - 'SOCKSProxyManager', # noqa: F821 - urllib3.ProxyManager, - ] = None # type: ignore - if not proxy_url: - if appengine.is_appengine_sandbox(): - # Use URLFetch service if running in App Engine - self._con_pool = appengine.AppEngineManager() - else: - self._con_pool = urllib3.PoolManager(**kwargs) - else: - kwargs.update(urllib3_proxy_kwargs) - if proxy_url.startswith('socks'): - try: - # pylint: disable=C0415 - from telegram.vendor.ptb_urllib3.urllib3.contrib.socks import SOCKSProxyManager - except ImportError as exc: - raise RuntimeError('PySocks is missing') from exc - self._con_pool = SOCKSProxyManager(proxy_url, **kwargs) - else: - mgr = urllib3.proxy_from_url(proxy_url, **kwargs) - if mgr.proxy.auth: - # TODO: what about other auth types? - auth_hdrs = urllib3.make_headers(proxy_basic_auth=mgr.proxy.auth) - mgr.proxy_headers.update(auth_hdrs) - - self._con_pool = mgr - - def __setattr__(self, key: str, value: object) -> None: - set_new_attribute_deprecated(self, key, value) - - @property - def con_pool_size(self) -> int: - """The size of the connection pool used.""" - return self._con_pool_size - - def stop(self) -> None: - """Performs cleanup on shutdown.""" - self._con_pool.clear() # type: ignore - - @staticmethod - def _parse(json_data: bytes) -> Union[JSONDict, bool]: - """Try and parse the JSON returned from Telegram. - - Returns: - dict: A JSON parsed as Python dict with results - on error this dict will be empty. - - """ - decoded_s = json_data.decode('utf-8', 'replace') - try: - data = json.loads(decoded_s) - except ValueError as exc: - raise TelegramError('Invalid server response') from exc - - if not data.get('ok'): # pragma: no cover - description = data.get('description') - parameters = data.get('parameters') - if parameters: - migrate_to_chat_id = parameters.get('migrate_to_chat_id') - if migrate_to_chat_id: - raise ChatMigrated(migrate_to_chat_id) - retry_after = parameters.get('retry_after') - if retry_after: - raise RetryAfter(retry_after) - if description: - return description - - return data['result'] - - def _request_wrapper(self, *args: object, **kwargs: Any) -> bytes: - """Wraps urllib3 request for handling known exceptions. - - Args: - args: unnamed arguments, passed to urllib3 request. - kwargs: keyword arguments, passed to urllib3 request. - - Returns: - bytes: A non-parsed JSON text. - - Raises: - TelegramError - - """ - # Make sure to hint Telegram servers that we reuse connections by sending - # "Connection: keep-alive" in the HTTP headers. - if 'headers' not in kwargs: - kwargs['headers'] = {} - kwargs['headers']['connection'] = 'keep-alive' - # Also set our user agent - kwargs['headers']['user-agent'] = USER_AGENT - - try: - resp = self._con_pool.request(*args, **kwargs) - except urllib3.exceptions.TimeoutError as error: - raise TimedOut() from error - except urllib3.exceptions.HTTPError as error: - # HTTPError must come last as its the base urllib3 exception class - # TODO: do something smart here; for now just raise NetworkError - raise NetworkError(f'urllib3 HTTPError {error}') from error - - if 200 <= resp.status <= 299: - # 200-299 range are HTTP success statuses - return resp.data - - try: - message = str(self._parse(resp.data)) - except ValueError: - message = 'Unknown HTTPError' - - if resp.status in (401, 403): - raise Unauthorized(message) - if resp.status == 400: - raise BadRequest(message) - if resp.status == 404: - raise InvalidToken() - if resp.status == 409: - raise Conflict(message) - if resp.status == 413: - raise NetworkError( - 'File too large. Check telegram api limits ' - 'https://core.telegram.org/bots/api#senddocument' - ) - if resp.status == 502: - raise NetworkError('Bad Gateway') - raise NetworkError(f'{message} ({resp.status})') - - def post(self, url: str, data: JSONDict, timeout: float = None) -> Union[JSONDict, bool]: - """Request an URL. - - Args: - url (:obj:`str`): The web location we want to retrieve. - data (Dict[:obj:`str`, :obj:`str` | :obj:`int`], optional): A dict of key/value pairs. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - - Returns: - A JSON object. - - """ - urlopen_kwargs = {} - - if timeout is not None: - urlopen_kwargs['timeout'] = Timeout(read=timeout, connect=self._connect_timeout) - - if data is None: - data = {} - - # Are we uploading files? - files = False - - # pylint: disable=R1702 - for key, val in data.copy().items(): - if isinstance(val, InputFile): - # Convert the InputFile to urllib3 field format - data[key] = val.field_tuple - files = True - elif isinstance(val, (float, int)): - # Urllib3 doesn't like floats it seems - data[key] = str(val) - elif key == 'media': - # One media or multiple - if isinstance(val, InputMedia): - # Attach and set val to attached name - data[key] = val.to_json() - if isinstance(val.media, InputFile): # type: ignore - data[val.media.attach] = val.media.field_tuple # type: ignore - else: - # Attach and set val to attached name for all - media = [] - for med in val: - media_dict = med.to_dict() - media.append(media_dict) - if isinstance(med.media, InputFile): - data[med.media.attach] = med.media.field_tuple - # if the file has a thumb, we also need to attach it to the data - if "thumb" in media_dict: - data[med.thumb.attach] = med.thumb.field_tuple - data[key] = json.dumps(media) - files = True - elif isinstance(val, list): - # In case we're sending files, we need to json-dump lists manually - # As we can't know if that's the case, we just json-dump here - data[key] = json.dumps(val) - - # Use multipart upload if we're uploading files, otherwise use JSON - if files: - result = self._request_wrapper('POST', url, fields=data, **urlopen_kwargs) - else: - result = self._request_wrapper( - 'POST', - url, - body=json.dumps(data).encode('utf-8'), - headers={'Content-Type': 'application/json'}, - **urlopen_kwargs, - ) - - return self._parse(result) - - def retrieve(self, url: str, timeout: float = None) -> bytes: - """Retrieve the contents of a file by its URL. - - Args: - url (:obj:`str`): The web location we want to retrieve. - timeout (:obj:`int` | :obj:`float`): If this value is specified, use it as the read - timeout from the server (instead of the one specified during creation of the - connection pool). - - """ - urlopen_kwargs = {} - if timeout is not None: - urlopen_kwargs['timeout'] = Timeout(read=timeout, connect=self._connect_timeout) - - return self._request_wrapper('GET', url, **urlopen_kwargs) - - def download(self, url: str, filename: str, timeout: float = None) -> None: - """Download a file by its URL. - - Args: - url (:obj:`str`): The web location we want to retrieve. - timeout (:obj:`int` | :obj:`float`, optional): If this value is specified, use it as - the read timeout from the server (instead of the one specified during creation of - the connection pool). - filename (:obj:`str`): The filename within the path to download the file. - - """ - buf = self.retrieve(url, timeout=timeout) - with open(filename, 'wb') as fobj: - fobj.write(buf) diff --git a/venv/lib/python3.8/site-packages/telegram/utils/types.py b/venv/lib/python3.8/site-packages/telegram/utils/types.py deleted file mode 100644 index 2f9ff8f..0000000 --- a/venv/lib/python3.8/site-packages/telegram/utils/types.py +++ /dev/null @@ -1,57 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains custom typing aliases.""" -from pathlib import Path -from typing import ( - IO, - TYPE_CHECKING, - Any, - Dict, - List, - Optional, - Tuple, - TypeVar, - Union, -) - -if TYPE_CHECKING: - from telegram import InputFile # noqa: F401 - from telegram.utils.helpers import DefaultValue # noqa: F401 - -FileLike = Union[IO, 'InputFile'] -"""Either an open file handler or a :class:`telegram.InputFile`.""" - -FileInput = Union[str, bytes, FileLike, Path] -"""Valid input for passing files to Telegram. Either a file id as string, a file like object, -a local file path as string, :class:`pathlib.Path` or the file contents as :obj:`bytes`.""" - -JSONDict = Dict[str, Any] -"""Dictionary containing response from Telegram or data to send to the API.""" - -DVType = TypeVar('DVType') -ODVInput = Optional[Union['DefaultValue[DVType]', DVType]] -"""Generic type for bot method parameters which can have defaults. ``ODVInput[type]`` is the same -as ``Optional[Union[DefaultValue, type]]``.""" -DVInput = Union['DefaultValue[DVType]', DVType] -"""Generic type for bot method parameters which can have defaults. ``DVInput[type]`` is the same -as ``Union[DefaultValue, type]``.""" - -RT = TypeVar("RT") -SLT = Union[RT, List[RT], Tuple[RT, ...]] -"""Single instance or list/tuple of instances.""" diff --git a/venv/lib/python3.8/site-packages/telegram/utils/webhookhandler.py b/venv/lib/python3.8/site-packages/telegram/utils/webhookhandler.py deleted file mode 100644 index 727eecb..0000000 --- a/venv/lib/python3.8/site-packages/telegram/utils/webhookhandler.py +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains the :class:`telegram.ext.utils.webhookhandler.WebhookHandler` class for -backwards compatibility. -""" -import warnings - -import telegram.ext.utils.webhookhandler as webhook_handler -from telegram.utils.deprecate import TelegramDeprecationWarning - -warnings.warn( - 'telegram.utils.webhookhandler is deprecated. Please use telegram.ext.utils.webhookhandler ' - 'instead.', - TelegramDeprecationWarning, -) - -WebhookHandler = webhook_handler.WebhookHandler -WebhookServer = webhook_handler.WebhookServer -WebhookAppClass = webhook_handler.WebhookAppClass diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/__init__.py b/venv/lib/python3.8/site-packages/telegram/vendor/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/__init__.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/__init__.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/__init__.py deleted file mode 100644 index 0cd5e34..0000000 --- a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/__init__.py +++ /dev/null @@ -1,96 +0,0 @@ -""" -urllib3 - Thread-safe connection pooling and re-using. -""" -from __future__ import absolute_import -import warnings - -from .connectionpool import ( - HTTPConnectionPool, - HTTPSConnectionPool, - connection_from_url -) - -from . import exceptions -from .filepost import encode_multipart_formdata -from .poolmanager import PoolManager, ProxyManager, proxy_from_url -from .response import HTTPResponse -from .util.request import make_headers -from .util.url import get_host -from .util.timeout import Timeout -from .util.retry import Retry - - -# Set default logging handler to avoid "No handler found" warnings. -import logging -try: # Python 2.7+ - from logging import NullHandler -except ImportError: - class NullHandler(logging.Handler): - def emit(self, record): - pass - -__author__ = 'Andrey Petrov (andrey.petrov@shazow.net)' -__license__ = 'MIT' -__version__ = 'dev' - -__all__ = ( - 'HTTPConnectionPool', - 'HTTPSConnectionPool', - 'PoolManager', - 'ProxyManager', - 'HTTPResponse', - 'Retry', - 'Timeout', - 'add_stderr_logger', - 'connection_from_url', - 'disable_warnings', - 'encode_multipart_formdata', - 'get_host', - 'make_headers', - 'proxy_from_url', -) - -logging.getLogger(__name__).addHandler(NullHandler()) - - -def add_stderr_logger(level=logging.DEBUG): - """ - Helper for quickly adding a StreamHandler to the logger. Useful for - debugging. - - Returns the handler after adding it. - """ - # This method needs to be in this __init__.py to get the __name__ correct - # even if urllib3 is vendored within another package. - logger = logging.getLogger(__name__) - handler = logging.StreamHandler() - handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s %(message)s')) - logger.addHandler(handler) - logger.setLevel(level) - logger.debug('Added a stderr logging handler to logger: %s', __name__) - return handler - - -# ... Clean up. -del NullHandler - - -# All warning filters *must* be appended unless you're really certain that they -# shouldn't be: otherwise, it's very hard for users to use most Python -# mechanisms to silence them. -# SecurityWarning's always go off by default. -warnings.simplefilter('always', exceptions.SecurityWarning, append=True) -# SubjectAltNameWarning's should go off once per host -warnings.simplefilter('default', exceptions.SubjectAltNameWarning, append=True) -# InsecurePlatformWarning's don't vary between requests, so we keep it default. -warnings.simplefilter('default', exceptions.InsecurePlatformWarning, - append=True) -# SNIMissingWarnings should go off only once. -warnings.simplefilter('default', exceptions.SNIMissingWarning, append=True) - - -def disable_warnings(category=exceptions.HTTPWarning): - """ - Helper for quickly disabling all urllib3 warnings. - """ - warnings.simplefilter('ignore', category) diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/_collections.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/_collections.py deleted file mode 100644 index 4fcd2ab..0000000 --- a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/_collections.py +++ /dev/null @@ -1,327 +0,0 @@ -from __future__ import absolute_import -try: - from collections.abc import Mapping, MutableMapping -except ImportError: - from collections import Mapping, MutableMapping -try: - from threading import RLock -except ImportError: # Platform-specific: No threads available - class RLock: - def __enter__(self): - pass - - def __exit__(self, exc_type, exc_value, traceback): - pass - - -try: # Python 2.7+ - from collections import OrderedDict -except ImportError: - from .packages.ordered_dict import OrderedDict -from .packages.six import iterkeys, itervalues, PY3 - - -__all__ = ['RecentlyUsedContainer', 'HTTPHeaderDict'] - - -_Null = object() - - -class RecentlyUsedContainer(MutableMapping): - """ - Provides a thread-safe dict-like container which maintains up to - ``maxsize`` keys while throwing away the least-recently-used keys beyond - ``maxsize``. - - :param maxsize: - Maximum number of recent elements to retain. - - :param dispose_func: - Every time an item is evicted from the container, - ``dispose_func(value)`` is called. Callback which will get called - """ - - ContainerCls = OrderedDict - - def __init__(self, maxsize=10, dispose_func=None): - self._maxsize = maxsize - self.dispose_func = dispose_func - - self._container = self.ContainerCls() - self.lock = RLock() - - def __getitem__(self, key): - # Re-insert the item, moving it to the end of the eviction line. - with self.lock: - item = self._container.pop(key) - self._container[key] = item - return item - - def __setitem__(self, key, value): - evicted_value = _Null - with self.lock: - # Possibly evict the existing value of 'key' - evicted_value = self._container.get(key, _Null) - self._container[key] = value - - # If we didn't evict an existing value, we might have to evict the - # least recently used item from the beginning of the container. - if len(self._container) > self._maxsize: - _key, evicted_value = self._container.popitem(last=False) - - if self.dispose_func and evicted_value is not _Null: - self.dispose_func(evicted_value) - - def __delitem__(self, key): - with self.lock: - value = self._container.pop(key) - - if self.dispose_func: - self.dispose_func(value) - - def __len__(self): - with self.lock: - return len(self._container) - - def __iter__(self): - raise NotImplementedError('Iteration over this class is unlikely to be threadsafe.') - - def clear(self): - with self.lock: - # Copy pointers to all values, then wipe the mapping - values = list(itervalues(self._container)) - self._container.clear() - - if self.dispose_func: - for value in values: - self.dispose_func(value) - - def keys(self): - with self.lock: - return list(iterkeys(self._container)) - - -class HTTPHeaderDict(MutableMapping): - """ - :param headers: - An iterable of field-value pairs. Must not contain multiple field names - when compared case-insensitively. - - :param kwargs: - Additional field-value pairs to pass in to ``dict.update``. - - A ``dict`` like container for storing HTTP Headers. - - Field names are stored and compared case-insensitively in compliance with - RFC 7230. Iteration provides the first case-sensitive key seen for each - case-insensitive pair. - - Using ``__setitem__`` syntax overwrites fields that compare equal - case-insensitively in order to maintain ``dict``'s api. For fields that - compare equal, instead create a new ``HTTPHeaderDict`` and use ``.add`` - in a loop. - - If multiple fields that are equal case-insensitively are passed to the - constructor or ``.update``, the behavior is undefined and some will be - lost. - - >>> headers = HTTPHeaderDict() - >>> headers.add('Set-Cookie', 'foo=bar') - >>> headers.add('set-cookie', 'baz=quxx') - >>> headers['content-length'] = '7' - >>> headers['SET-cookie'] - 'foo=bar, baz=quxx' - >>> headers['Content-Length'] - '7' - """ - - def __init__(self, headers=None, **kwargs): - super(HTTPHeaderDict, self).__init__() - self._container = OrderedDict() - if headers is not None: - if isinstance(headers, HTTPHeaderDict): - self._copy_from(headers) - else: - self.extend(headers) - if kwargs: - self.extend(kwargs) - - def __setitem__(self, key, val): - self._container[key.lower()] = (key, val) - return self._container[key.lower()] - - def __getitem__(self, key): - val = self._container[key.lower()] - return ', '.join(val[1:]) - - def __delitem__(self, key): - del self._container[key.lower()] - - def __contains__(self, key): - return key.lower() in self._container - - def __eq__(self, other): - if not isinstance(other, Mapping) and not hasattr(other, 'keys'): - return False - if not isinstance(other, type(self)): - other = type(self)(other) - return (dict((k.lower(), v) for k, v in self.itermerged()) == - dict((k.lower(), v) for k, v in other.itermerged())) - - def __ne__(self, other): - return not self.__eq__(other) - - if not PY3: # Python 2 - iterkeys = MutableMapping.iterkeys - itervalues = MutableMapping.itervalues - - __marker = object() - - def __len__(self): - return len(self._container) - - def __iter__(self): - # Only provide the originally cased names - for vals in self._container.values(): - yield vals[0] - - def pop(self, key, default=__marker): - '''D.pop(k[,d]) -> v, remove specified key and return the corresponding value. - If key is not found, d is returned if given, otherwise KeyError is raised. - ''' - # Using the MutableMapping function directly fails due to the private marker. - # Using ordinary dict.pop would expose the internal structures. - # So let's reinvent the wheel. - try: - value = self[key] - except KeyError: - if default is self.__marker: - raise - return default - else: - del self[key] - return value - - def discard(self, key): - try: - del self[key] - except KeyError: - pass - - def add(self, key, val): - """Adds a (name, value) pair, doesn't overwrite the value if it already - exists. - - >>> headers = HTTPHeaderDict(foo='bar') - >>> headers.add('Foo', 'baz') - >>> headers['foo'] - 'bar, baz' - """ - key_lower = key.lower() - new_vals = key, val - # Keep the common case aka no item present as fast as possible - vals = self._container.setdefault(key_lower, new_vals) - if new_vals is not vals: - # new_vals was not inserted, as there was a previous one - if isinstance(vals, list): - # If already several items got inserted, we have a list - vals.append(val) - else: - # vals should be a tuple then, i.e. only one item so far - # Need to convert the tuple to list for further extension - self._container[key_lower] = [vals[0], vals[1], val] - - def extend(self, *args, **kwargs): - """Generic import function for any type of header-like object. - Adapted version of MutableMapping.update in order to insert items - with self.add instead of self.__setitem__ - """ - if len(args) > 1: - raise TypeError("extend() takes at most 1 positional " - "arguments ({0} given)".format(len(args))) - other = args[0] if len(args) >= 1 else () - - if isinstance(other, HTTPHeaderDict): - for key, val in other.iteritems(): - self.add(key, val) - elif isinstance(other, Mapping): - for key in other: - self.add(key, other[key]) - elif hasattr(other, "keys"): - for key in other.keys(): - self.add(key, other[key]) - else: - for key, value in other: - self.add(key, value) - - for key, value in kwargs.items(): - self.add(key, value) - - def getlist(self, key): - """Returns a list of all the values for the named field. Returns an - empty list if the key doesn't exist.""" - try: - vals = self._container[key.lower()] - except KeyError: - return [] - else: - if isinstance(vals, tuple): - return [vals[1]] - else: - return vals[1:] - - # Backwards compatibility for httplib - getheaders = getlist - getallmatchingheaders = getlist - iget = getlist - - def __repr__(self): - return "%s(%s)" % (type(self).__name__, dict(self.itermerged())) - - def _copy_from(self, other): - for key in other: - val = other.getlist(key) - if isinstance(val, list): - # Don't need to convert tuples - val = list(val) - self._container[key.lower()] = [key] + val - - def copy(self): - clone = type(self)() - clone._copy_from(self) - return clone - - def iteritems(self): - """Iterate over all header lines, including duplicate ones.""" - for key in self: - vals = self._container[key.lower()] - for val in vals[1:]: - yield vals[0], val - - def itermerged(self): - """Iterate over all headers, merging duplicate ones together.""" - for key in self: - val = self._container[key.lower()] - yield val[0], ', '.join(val[1:]) - - def items(self): - return list(self.iteritems()) - - @classmethod - def from_httplib(cls, message): # Python 2 - """Read headers from a Python 2 httplib message object.""" - # python2.7 does not expose a proper API for exporting multiheaders - # efficiently. This function re-reads raw lines from the message - # object and extracts the multiheaders properly. - headers = [] - - for line in message.headers: - if line.startswith((' ', '\t')): - key, value = headers[-1] - headers[-1] = (key, value + '\r\n' + line.rstrip()) - continue - - key, value = line.split(':', 1) - headers.append((key, value.strip())) - - return cls(headers) diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/connection.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/connection.py deleted file mode 100644 index 9f06c39..0000000 --- a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/connection.py +++ /dev/null @@ -1,369 +0,0 @@ -from __future__ import absolute_import -import datetime -import logging -import os -import sys -import socket -from socket import error as SocketError, timeout as SocketTimeout -import warnings -from .packages import six -from .packages.six.moves.http_client import HTTPConnection as _HTTPConnection -from .packages.six.moves.http_client import HTTPException # noqa: F401 - -try: # Compiled with SSL? - import ssl - BaseSSLError = ssl.SSLError -except (ImportError, AttributeError): # Platform-specific: No SSL. - ssl = None - - class BaseSSLError(BaseException): - pass - - -try: # Python 3: - # Not a no-op, we're adding this to the namespace so it can be imported. - ConnectionError = ConnectionError -except NameError: # Python 2: - class ConnectionError(Exception): - pass - - -from .exceptions import ( - NewConnectionError, - ConnectTimeoutError, - SubjectAltNameWarning, - SystemTimeWarning, -) -from .packages.ssl_match_hostname import match_hostname, CertificateError - -from .util.ssl_ import ( - resolve_cert_reqs, - resolve_ssl_version, - assert_fingerprint, - create_urllib3_context, - ssl_wrap_socket -) - - -from .util import connection - -from ._collections import HTTPHeaderDict - -log = logging.getLogger(__name__) - -port_by_scheme = { - 'http': 80, - 'https': 443, -} - -# When updating RECENT_DATE, move it to -# within two years of the current date, and no -# earlier than 6 months ago. -RECENT_DATE = datetime.date(2016, 1, 1) - - -class DummyConnection(object): - """Used to detect a failed ConnectionCls import.""" - pass - - -class HTTPConnection(_HTTPConnection, object): - """ - Based on httplib.HTTPConnection but provides an extra constructor - backwards-compatibility layer between older and newer Pythons. - - Additional keyword parameters are used to configure attributes of the connection. - Accepted parameters include: - - - ``strict``: See the documentation on :class:`urllib3.connectionpool.HTTPConnectionPool` - - ``source_address``: Set the source address for the current connection. - - .. note:: This is ignored for Python 2.6. It is only applied for 2.7 and 3.x - - - ``socket_options``: Set specific options on the underlying socket. If not specified, then - defaults are loaded from ``HTTPConnection.default_socket_options`` which includes disabling - Nagle's algorithm (sets TCP_NODELAY to 1) unless the connection is behind a proxy. - - For example, if you wish to enable TCP Keep Alive in addition to the defaults, - you might pass:: - - HTTPConnection.default_socket_options + [ - (socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1), - ] - - Or you may want to disable the defaults by passing an empty list (e.g., ``[]``). - """ - - default_port = port_by_scheme['http'] - - #: Disable Nagle's algorithm by default. - #: ``[(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)]`` - default_socket_options = [(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)] - - #: Whether this connection verifies the host's certificate. - is_verified = False - - def __init__(self, *args, **kw): - if six.PY3: # Python 3 - kw.pop('strict', None) - - # Pre-set source_address in case we have an older Python like 2.6. - self.source_address = kw.get('source_address') - - if sys.version_info < (2, 7): # Python 2.6 - # _HTTPConnection on Python 2.6 will balk at this keyword arg, but - # not newer versions. We can still use it when creating a - # connection though, so we pop it *after* we have saved it as - # self.source_address. - kw.pop('source_address', None) - - #: The socket options provided by the user. If no options are - #: provided, we use the default options. - self.socket_options = kw.pop('socket_options', self.default_socket_options) - - # Superclass also sets self.source_address in Python 2.7+. - _HTTPConnection.__init__(self, *args, **kw) - - def _new_conn(self): - """ Establish a socket connection and set nodelay settings on it. - - :return: New socket connection. - """ - extra_kw = {} - if self.source_address: - extra_kw['source_address'] = self.source_address - - if self.socket_options: - extra_kw['socket_options'] = self.socket_options - - try: - conn = connection.create_connection( - (self.host, self.port), self.timeout, **extra_kw) - - except SocketTimeout as e: - raise ConnectTimeoutError( - self, "Connection to %s timed out. (connect timeout=%s)" % - (self.host, self.timeout)) - - except SocketError as e: - raise NewConnectionError( - self, "Failed to establish a new connection: %s" % e) - - return conn - - def _prepare_conn(self, conn): - self.sock = conn - # the _tunnel_host attribute was added in python 2.6.3 (via - # http://hg.python.org/cpython/rev/0f57b30a152f) so pythons 2.6(0-2) do - # not have them. - if getattr(self, '_tunnel_host', None): - # TODO: Fix tunnel so it doesn't depend on self.sock state. - self._tunnel() - # Mark this connection as not reusable - self.auto_open = 0 - - def connect(self): - conn = self._new_conn() - self._prepare_conn(conn) - - def request_chunked(self, method, url, body=None, headers=None): - """ - Alternative to the common request method, which sends the - body with chunked encoding and not as one block - """ - headers = HTTPHeaderDict(headers if headers is not None else {}) - skip_accept_encoding = 'accept-encoding' in headers - skip_host = 'host' in headers - self.putrequest( - method, - url, - skip_accept_encoding=skip_accept_encoding, - skip_host=skip_host - ) - for header, value in headers.items(): - self.putheader(header, value) - if 'transfer-encoding' not in headers: - self.putheader('Transfer-Encoding', 'chunked') - self.endheaders() - - if body is not None: - stringish_types = six.string_types + (six.binary_type,) - if isinstance(body, stringish_types): - body = (body,) - for chunk in body: - if not chunk: - continue - if not isinstance(chunk, six.binary_type): - chunk = chunk.encode('utf8') - len_str = hex(len(chunk))[2:] - self.send(len_str.encode('utf-8')) - self.send(b'\r\n') - self.send(chunk) - self.send(b'\r\n') - - # After the if clause, to always have a closed body - self.send(b'0\r\n\r\n') - - -class HTTPSConnection(HTTPConnection): - default_port = port_by_scheme['https'] - - ssl_version = None - - def __init__(self, host, port=None, key_file=None, cert_file=None, - strict=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, - ssl_context=None, **kw): - - HTTPConnection.__init__(self, host, port, strict=strict, - timeout=timeout, **kw) - - self.key_file = key_file - self.cert_file = cert_file - self.ssl_context = ssl_context - - # Required property for Google AppEngine 1.9.0 which otherwise causes - # HTTPS requests to go out as HTTP. (See Issue #356) - self._protocol = 'https' - - def connect(self): - conn = self._new_conn() - self._prepare_conn(conn) - - if self.ssl_context is None: - self.ssl_context = create_urllib3_context( - ssl_version=resolve_ssl_version(None), - cert_reqs=resolve_cert_reqs(None), - ) - - self.sock = ssl_wrap_socket( - sock=conn, - keyfile=self.key_file, - certfile=self.cert_file, - ssl_context=self.ssl_context, - ) - - -class VerifiedHTTPSConnection(HTTPSConnection): - """ - Based on httplib.HTTPSConnection but wraps the socket with - SSL certification. - """ - cert_reqs = None - ca_certs = None - ca_cert_dir = None - ssl_version = None - assert_fingerprint = None - - def set_cert(self, key_file=None, cert_file=None, - cert_reqs=None, ca_certs=None, - assert_hostname=None, assert_fingerprint=None, - ca_cert_dir=None): - """ - This method should only be called once, before the connection is used. - """ - # If cert_reqs is not provided, we can try to guess. If the user gave - # us a cert database, we assume they want to use it: otherwise, if - # they gave us an SSL Context object we should use whatever is set for - # it. - if cert_reqs is None: - if ca_certs or ca_cert_dir: - cert_reqs = 'CERT_REQUIRED' - elif self.ssl_context is not None: - cert_reqs = self.ssl_context.verify_mode - - self.key_file = key_file - self.cert_file = cert_file - self.cert_reqs = cert_reqs - self.assert_hostname = assert_hostname - self.assert_fingerprint = assert_fingerprint - self.ca_certs = ca_certs and os.path.expanduser(ca_certs) - self.ca_cert_dir = ca_cert_dir and os.path.expanduser(ca_cert_dir) - - def connect(self): - # Add certificate verification - conn = self._new_conn() - - hostname = self.host - if getattr(self, '_tunnel_host', None): - # _tunnel_host was added in Python 2.6.3 - # (See: http://hg.python.org/cpython/rev/0f57b30a152f) - - self.sock = conn - # Calls self._set_hostport(), so self.host is - # self._tunnel_host below. - self._tunnel() - # Mark this connection as not reusable - self.auto_open = 0 - - # Override the host with the one we're requesting data from. - hostname = self._tunnel_host - - is_time_off = datetime.date.today() < RECENT_DATE - if is_time_off: - warnings.warn(( - 'System time is way off (before {0}). This will probably ' - 'lead to SSL verification errors').format(RECENT_DATE), - SystemTimeWarning - ) - - # Wrap socket using verification with the root certs in - # trusted_root_certs - if self.ssl_context is None: - self.ssl_context = create_urllib3_context( - ssl_version=resolve_ssl_version(self.ssl_version), - cert_reqs=resolve_cert_reqs(self.cert_reqs), - ) - - context = self.ssl_context - context.verify_mode = resolve_cert_reqs(self.cert_reqs) - self.sock = ssl_wrap_socket( - sock=conn, - keyfile=self.key_file, - certfile=self.cert_file, - ca_certs=self.ca_certs, - ca_cert_dir=self.ca_cert_dir, - server_hostname=hostname, - ssl_context=context) - - if self.assert_fingerprint: - assert_fingerprint(self.sock.getpeercert(binary_form=True), - self.assert_fingerprint) - elif context.verify_mode != ssl.CERT_NONE \ - and self.assert_hostname is not False: - cert = self.sock.getpeercert() - if not cert.get('subjectAltName', ()): - warnings.warn(( - 'Certificate for {0} has no `subjectAltName`, falling back to check for a ' - '`commonName` for now. This feature is being removed by major browsers and ' - 'deprecated by RFC 2818. (See https://github.com/shazow/urllib3/issues/497 ' - 'for details.)'.format(hostname)), - SubjectAltNameWarning - ) - _match_hostname(cert, self.assert_hostname or hostname) - - self.is_verified = ( - context.verify_mode == ssl.CERT_REQUIRED or - self.assert_fingerprint is not None - ) - - -def _match_hostname(cert, asserted_hostname): - try: - match_hostname(cert, asserted_hostname) - except CertificateError as e: - log.error( - 'Certificate did not match expected hostname: %s. ' - 'Certificate: %s', asserted_hostname, cert - ) - # Add cert to exception and reraise so client code can inspect - # the cert when catching the exception, if they want to - e._peer_cert = cert - raise - - -if ssl: - # Make a copy for testing. - UnverifiedHTTPSConnection = HTTPSConnection - HTTPSConnection = VerifiedHTTPSConnection -else: - HTTPSConnection = DummyConnection diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/connectionpool.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/connectionpool.py deleted file mode 100644 index a958f99..0000000 --- a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/connectionpool.py +++ /dev/null @@ -1,912 +0,0 @@ -from __future__ import absolute_import -import errno -import logging -import sys -import warnings - -from socket import error as SocketError, timeout as SocketTimeout -import socket - - -from .exceptions import ( - ClosedPoolError, - ProtocolError, - EmptyPoolError, - HeaderParsingError, - HostChangedError, - LocationValueError, - MaxRetryError, - ProxyError, - ReadTimeoutError, - SSLError, - TimeoutError, - InsecureRequestWarning, - NewConnectionError, - ConnectTimeoutError, -) -from .packages.ssl_match_hostname import CertificateError -from .packages import six -from .packages.six.moves import queue -from .connection import ( - port_by_scheme, - DummyConnection, - HTTPConnection, HTTPSConnection, VerifiedHTTPSConnection, - HTTPException, BaseSSLError, -) -from .request import RequestMethods -from .response import HTTPResponse - -from .util.connection import is_connection_dropped -from .util.request import set_file_position -from .util.response import assert_header_parsing -from .util.retry import Retry -from .util.timeout import Timeout -from .util.url import get_host, Url - - -if six.PY2: - # Queue is imported for side effects on MS Windows - import Queue as _unused_module_Queue # noqa: F401 - -xrange = six.moves.xrange - -log = logging.getLogger(__name__) - -_Default = object() - - -# Pool objects -class ConnectionPool(object): - """ - Base class for all connection pools, such as - :class:`.HTTPConnectionPool` and :class:`.HTTPSConnectionPool`. - """ - - scheme = None - QueueCls = queue.LifoQueue - - def __init__(self, host, port=None): - if not host: - raise LocationValueError("No host specified.") - - self.host = _ipv6_host(host).lower() - self.port = port - - def __str__(self): - return '%s(host=%r, port=%r)' % (type(self).__name__, - self.host, self.port) - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_val, exc_tb): - self.close() - # Return False to re-raise any potential exceptions - return False - - def close(self): - """ - Close all pooled connections and disable the pool. - """ - pass - - -# This is taken from http://hg.python.org/cpython/file/7aaba721ebc0/Lib/socket.py#l252 -_blocking_errnos = set([errno.EAGAIN, errno.EWOULDBLOCK]) - - -class HTTPConnectionPool(ConnectionPool, RequestMethods): - """ - Thread-safe connection pool for one host. - - :param host: - Host used for this HTTP Connection (e.g. "localhost"), passed into - :class:`httplib.HTTPConnection`. - - :param port: - Port used for this HTTP Connection (None is equivalent to 80), passed - into :class:`httplib.HTTPConnection`. - - :param strict: - Causes BadStatusLine to be raised if the status line can't be parsed - as a valid HTTP/1.0 or 1.1 status line, passed into - :class:`httplib.HTTPConnection`. - - .. note:: - Only works in Python 2. This parameter is ignored in Python 3. - - :param timeout: - Socket timeout in seconds for each individual connection. This can - be a float or integer, which sets the timeout for the HTTP request, - or an instance of :class:`urllib3.util.Timeout` which gives you more - fine-grained control over request timeouts. After the constructor has - been parsed, this is always a `urllib3.util.Timeout` object. - - :param maxsize: - Number of connections to save that can be reused. More than 1 is useful - in multithreaded situations. If ``block`` is set to False, more - connections will be created but they will not be saved once they've - been used. - - :param block: - If set to True, no more than ``maxsize`` connections will be used at - a time. When no free connections are available, the call will block - until a connection has been released. This is a useful side effect for - particular multithreaded situations where one does not want to use more - than maxsize connections per host to prevent flooding. - - :param headers: - Headers to include with all requests, unless other headers are given - explicitly. - - :param retries: - Retry configuration to use by default with requests in this pool. - - :param _proxy: - Parsed proxy URL, should not be used directly, instead, see - :class:`urllib3.connectionpool.ProxyManager`" - - :param _proxy_headers: - A dictionary with proxy headers, should not be used directly, - instead, see :class:`urllib3.connectionpool.ProxyManager`" - - :param \\**conn_kw: - Additional parameters are used to create fresh :class:`urllib3.connection.HTTPConnection`, - :class:`urllib3.connection.HTTPSConnection` instances. - """ - - scheme = 'http' - ConnectionCls = HTTPConnection - ResponseCls = HTTPResponse - - def __init__(self, host, port=None, strict=False, - timeout=Timeout.DEFAULT_TIMEOUT, maxsize=1, block=False, - headers=None, retries=None, - _proxy=None, _proxy_headers=None, - **conn_kw): - ConnectionPool.__init__(self, host, port) - RequestMethods.__init__(self, headers) - - self.strict = strict - - if not isinstance(timeout, Timeout): - timeout = Timeout.from_float(timeout) - - if retries is None: - retries = Retry.DEFAULT - - self.timeout = timeout - self.retries = retries - - self.pool = self.QueueCls(maxsize) - self.block = block - - self.proxy = _proxy - self.proxy_headers = _proxy_headers or {} - - # Fill the queue up so that doing get() on it will block properly - for _ in xrange(maxsize): - self.pool.put(None) - - # These are mostly for testing and debugging purposes. - self.num_connections = 0 - self.num_requests = 0 - self.conn_kw = conn_kw - - if self.proxy: - # Enable Nagle's algorithm for proxies, to avoid packet fragmentation. - # We cannot know if the user has added default socket options, so we cannot replace the - # list. - self.conn_kw.setdefault('socket_options', []) - - def _new_conn(self): - """ - Return a fresh :class:`HTTPConnection`. - """ - self.num_connections += 1 - log.debug("Starting new HTTP connection (%d): %s", - self.num_connections, self.host) - - conn = self.ConnectionCls(host=self.host, port=self.port, - timeout=self.timeout.connect_timeout, - strict=self.strict, **self.conn_kw) - return conn - - def _get_conn(self, timeout=None): - """ - Get a connection. Will return a pooled connection if one is available. - - If no connections are available and :prop:`.block` is ``False``, then a - fresh connection is returned. - - :param timeout: - Seconds to wait before giving up and raising - :class:`urllib3.exceptions.EmptyPoolError` if the pool is empty and - :prop:`.block` is ``True``. - """ - conn = None - try: - conn = self.pool.get(block=self.block, timeout=timeout) - - except AttributeError: # self.pool is None - raise ClosedPoolError(self, "Pool is closed.") - - except queue.Empty: - if self.block: - raise EmptyPoolError(self, - "Pool reached maximum size and no more " - "connections are allowed.") - pass # Oh well, we'll create a new connection then - - # If this is a persistent connection, check if it got disconnected - if conn and is_connection_dropped(conn): - log.debug("Resetting dropped connection: %s", self.host) - conn.close() - if getattr(conn, 'auto_open', 1) == 0: - # This is a proxied connection that has been mutated by - # httplib._tunnel() and cannot be reused (since it would - # attempt to bypass the proxy) - conn = None - - return conn or self._new_conn() - - def _put_conn(self, conn): - """ - Put a connection back into the pool. - - :param conn: - Connection object for the current host and port as returned by - :meth:`._new_conn` or :meth:`._get_conn`. - - If the pool is already full, the connection is closed and discarded - because we exceeded maxsize. If connections are discarded frequently, - then maxsize should be increased. - - If the pool is closed, then the connection will be closed and discarded. - """ - try: - self.pool.put(conn, block=False) - return # Everything is dandy, done. - except AttributeError: - # self.pool is None. - pass - except queue.Full: - # This should never happen if self.block == True - log.warning( - "Connection pool is full, discarding connection: %s", - self.host) - - # Connection never got put back into the pool, close it. - if conn: - conn.close() - - def _validate_conn(self, conn): - """ - Called right before a request is made, after the socket is created. - """ - # Force connect early to allow us to set read timeout in time - if not getattr(conn, 'sock', None): # AppEngine might not have `.sock` - conn.connect() - - def _prepare_proxy(self, conn): - # Nothing to do for HTTP connections. - pass - - def _get_timeout(self, timeout): - """ Helper that always returns a :class:`urllib3.util.Timeout` """ - if timeout is _Default: - return self.timeout.clone() - - if isinstance(timeout, Timeout): - return timeout.clone() - else: - # User passed us an int/float. This is for backwards compatibility, - # can be removed later - return Timeout.from_float(timeout) - - def _raise_timeout(self, err, url, timeout_value, exc_cls): - """Is the error actually a timeout? Will raise a ReadTimeout or pass""" - - # exc_cls is either ReadTimeoutError or ConnectTimeoutError - # Only ReadTimeoutError requires the url (preserving old behaviour) - args = [self] - if exc_cls is ReadTimeoutError: - args.append(url) - desc = 'Read' - else: - desc = 'Connect' - - if isinstance(err, SocketTimeout): - args.append("%s timed out. (%s timeout=%s)" % (desc, desc.lower(), timeout_value)) - raise exc_cls(*args) - - # See the above comment about EAGAIN in Python 3. In Python 2 we have - # to specifically catch it and throw the timeout error - elif hasattr(err, 'errno') and err.errno in _blocking_errnos: - args.append("%s timed out. (%s timeout=%s)" % (desc, desc.lower(), timeout_value)) - raise exc_cls(*args) - - # Catch possible read timeouts thrown as SSL errors. If not the - # case, rethrow the original. We need to do this because of: - # http://bugs.python.org/issue10272 - elif 'timed out' in str(err) or 'did not complete (read)' in str(err): # Python 2.6 - args.append("%s timed out. (%s timeout=%s)" % (desc, desc.lower(), timeout_value)) - raise exc_cls(*args) - - def _make_request(self, conn, method, url, timeout=_Default, chunked=False, - **httplib_request_kw): - """ - Perform a request on a given urllib connection object taken from our - pool. - - :param conn: - a connection from one of our connection pools - - :param timeout: - Socket timeout in seconds for the request. This can be a - float or integer, which will set the same timeout value for - the socket connect and the socket read, or an instance of - :class:`urllib3.util.Timeout`, which gives you more fine-grained - control over your timeouts. - """ - self.num_requests += 1 - - timeout_obj = self._get_timeout(timeout) - timeout_obj.start_connect() - conn.timeout = timeout_obj.connect_timeout - - # Trigger any extra validation we need to do. - try: - self._validate_conn(conn) - except (SocketTimeout, BaseSSLError) as e: - # Py2 raises this as a BaseSSLError, Py3 raises it as socket timeout. - self._raise_timeout(err=e, url=url, timeout_value=conn.timeout, - exc_cls=ConnectTimeoutError) - raise - - # Reset the timeout for the recv() on the socket - read_timeout = timeout_obj.read_timeout - - # App Engine doesn't have a sock attr - if getattr(conn, 'sock', None): - # In Python 3 socket.py will catch EAGAIN and return None when you - # try and read into the file pointer created by http.client, which - # instead raises a BadStatusLine exception. Instead of catching - # the exception and assuming all BadStatusLine exceptions are read - # timeouts, check for a zero timeout before making the request. - if read_timeout == 0: - raise ReadTimeoutError( - self, url, "Read timed out. (read timeout=%s)" % read_timeout) - if read_timeout is Timeout.DEFAULT_TIMEOUT: - conn.sock.settimeout(socket.getdefaulttimeout()) - else: # None or a value - conn.sock.settimeout(read_timeout) - - # conn.request() calls httplib.*.request, not the method in - # urllib3.request. It also calls makefile (recv) on the socket. - if chunked: - conn.request_chunked(method, url, **httplib_request_kw) - else: - conn.request(method, url, **httplib_request_kw) - - # Receive the response from the server - try: - try: # Python 2.7, use buffering of HTTP responses - httplib_response = conn.getresponse(buffering=True) - except TypeError: # Python 2.6 and older, Python 3 - try: - httplib_response = conn.getresponse() - except Exception as e: - # Remove the TypeError from the exception chain in Python 3; - # otherwise it looks like a programming error was the cause. - six.raise_from(e, None) - except (SocketTimeout, BaseSSLError, SocketError) as e: - self._raise_timeout(err=e, url=url, timeout_value=read_timeout, - exc_cls=ReadTimeoutError) - raise - - # AppEngine doesn't have a version attr. - http_version = getattr(conn, '_http_vsn_str', 'HTTP/?') - log.debug("%s://%s:%s \"%s %s %s\" %s %s", self.scheme, self.host, self.port, - method, url, http_version, httplib_response.status, - httplib_response.length) - - try: - assert_header_parsing(httplib_response.msg) - except HeaderParsingError as hpe: # Platform-specific: Python 3 - log.warning( - 'Failed to parse headers (url=%s): %s', - self._absolute_url(url), hpe, exc_info=True) - - return httplib_response - - def _absolute_url(self, path): - return Url(scheme=self.scheme, host=self.host, port=self.port, path=path).url - - def close(self): - """ - Close all pooled connections and disable the pool. - """ - # Disable access to the pool - old_pool, self.pool = self.pool, None - - try: - while True: - conn = old_pool.get(block=False) - if conn: - conn.close() - - except queue.Empty: - pass # Done. - - def is_same_host(self, url): - """ - Check if the given ``url`` is a member of the same host as this - connection pool. - """ - if url.startswith('/'): - return True - - # TODO: Add optional support for socket.gethostbyname checking. - scheme, host, port = get_host(url) - - host = _ipv6_host(host).lower() - - # Use explicit default port for comparison when none is given - if self.port and not port: - port = port_by_scheme.get(scheme) - elif not self.port and port == port_by_scheme.get(scheme): - port = None - - return (scheme, host, port) == (self.scheme, self.host, self.port) - - def urlopen(self, method, url, body=None, headers=None, retries=None, - redirect=True, assert_same_host=True, timeout=_Default, - pool_timeout=None, release_conn=None, chunked=False, - body_pos=None, **response_kw): - """ - Get a connection from the pool and perform an HTTP request. This is the - lowest level call for making a request, so you'll need to specify all - the raw details. - - .. note:: - - More commonly, it's appropriate to use a convenience method provided - by :class:`.RequestMethods`, such as :meth:`request`. - - .. note:: - - `release_conn` will only behave as expected if - `preload_content=False` because we want to make - `preload_content=False` the default behaviour someday soon without - breaking backwards compatibility. - - :param method: - HTTP request method (such as GET, POST, PUT, etc.) - - :param body: - Data to send in the request body (useful for creating - POST requests, see HTTPConnectionPool.post_url for - more convenience). - - :param headers: - Dictionary of custom headers to send, such as User-Agent, - If-None-Match, etc. If None, pool headers are used. If provided, - these headers completely replace any pool-specific headers. - - :param retries: - Configure the number of retries to allow before raising a - :class:`~urllib3.exceptions.MaxRetryError` exception. - - Pass ``None`` to retry until you receive a response. Pass a - :class:`~urllib3.util.retry.Retry` object for fine-grained control - over different types of retries. - Pass an integer number to retry connection errors that many times, - but no other types of errors. Pass zero to never retry. - - If ``False``, then retries are disabled and any exception is raised - immediately. Also, instead of raising a MaxRetryError on redirects, - the redirect response will be returned. - - :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int. - - :param redirect: - If True, automatically handle redirects (status codes 301, 302, - 303, 307, 308). Each redirect counts as a retry. Disabling retries - will disable redirect, too. - - :param assert_same_host: - If ``True``, will make sure that the host of the pool requests is - consistent else will raise HostChangedError. When False, you can - use the pool on an HTTP proxy and request foreign hosts. - - :param timeout: - If specified, overrides the default timeout for this one - request. It may be a float (in seconds) or an instance of - :class:`urllib3.util.Timeout`. - - :param pool_timeout: - If set and the pool is set to block=True, then this method will - block for ``pool_timeout`` seconds and raise EmptyPoolError if no - connection is available within the time period. - - :param release_conn: - If False, then the urlopen call will not release the connection - back into the pool once a response is received (but will release if - you read the entire contents of the response such as when - `preload_content=True`). This is useful if you're not preloading - the response's content immediately. You will need to call - ``r.release_conn()`` on the response ``r`` to return the connection - back into the pool. If None, it takes the value of - ``response_kw.get('preload_content', True)``. - - :param chunked: - If True, urllib3 will send the body using chunked transfer - encoding. Otherwise, urllib3 will send the body using the standard - content-length form. Defaults to False. - - :param int body_pos: - Position to seek to in file-like body in the event of a retry or - redirect. Typically this won't need to be set because urllib3 will - auto-populate the value when needed. - - :param \\**response_kw: - Additional parameters are passed to - :meth:`urllib3.response.HTTPResponse.from_httplib` - """ - if headers is None: - headers = self.headers - - if not isinstance(retries, Retry): - retries = Retry.from_int(retries, redirect=redirect, default=self.retries) - - if release_conn is None: - release_conn = response_kw.get('preload_content', True) - - # Check host - if assert_same_host and not self.is_same_host(url): - raise HostChangedError(self, url, retries) - - conn = None - - # Track whether `conn` needs to be released before - # returning/raising/recursing. Update this variable if necessary, and - # leave `release_conn` constant throughout the function. That way, if - # the function recurses, the original value of `release_conn` will be - # passed down into the recursive call, and its value will be respected. - # - # See issue #651 [1] for details. - # - # [1] <https://github.com/shazow/urllib3/issues/651> - release_this_conn = release_conn - - # Merge the proxy headers. Only do this in HTTP. We have to copy the - # headers dict so we can safely change it without those changes being - # reflected in anyone else's copy. - if self.scheme == 'http': - headers = headers.copy() - headers.update(self.proxy_headers) - - # Must keep the exception bound to a separate variable or else Python 3 - # complains about UnboundLocalError. - err = None - - # Keep track of whether we cleanly exited the except block. This - # ensures we do proper cleanup in finally. - clean_exit = False - - # Rewind body position, if needed. Record current position - # for future rewinds in the event of a redirect/retry. - body_pos = set_file_position(body, body_pos) - - try: - # Request a connection from the queue. - timeout_obj = self._get_timeout(timeout) - conn = self._get_conn(timeout=pool_timeout) - - conn.timeout = timeout_obj.connect_timeout - - is_new_proxy_conn = self.proxy is not None and not getattr(conn, 'sock', None) - if is_new_proxy_conn: - self._prepare_proxy(conn) - - # Make the request on the httplib connection object. - httplib_response = self._make_request(conn, method, url, - timeout=timeout_obj, - body=body, headers=headers, - chunked=chunked) - - # If we're going to release the connection in ``finally:``, then - # the response doesn't need to know about the connection. Otherwise - # it will also try to release it and we'll have a double-release - # mess. - response_conn = conn if not release_conn else None - - # Pass method to Response for length checking - response_kw['request_method'] = method - - # Import httplib's response into our own wrapper object - response = self.ResponseCls.from_httplib(httplib_response, - pool=self, - connection=response_conn, - retries=retries, - **response_kw) - - # Everything went great! - clean_exit = True - - except queue.Empty: - # Timed out by queue. - raise EmptyPoolError(self, "No pool connections are available.") - - except (BaseSSLError, CertificateError) as e: - # Close the connection. If a connection is reused on which there - # was a Certificate error, the next request will certainly raise - # another Certificate error. - clean_exit = False - raise SSLError(e) - - except SSLError: - # Treat SSLError separately from BaseSSLError to preserve - # traceback. - clean_exit = False - raise - - except (TimeoutError, HTTPException, SocketError, ProtocolError) as e: - # Discard the connection for these exceptions. It will be - # be replaced during the next _get_conn() call. - clean_exit = False - - if isinstance(e, (SocketError, NewConnectionError)) and self.proxy: - e = ProxyError('Cannot connect to proxy.', e) - elif isinstance(e, (SocketError, HTTPException)): - e = ProtocolError('Connection aborted.', e) - - retries = retries.increment(method, url, error=e, _pool=self, - _stacktrace=sys.exc_info()[2]) - retries.sleep() - - # Keep track of the error for the retry warning. - err = e - - finally: - if not clean_exit: - # We hit some kind of exception, handled or otherwise. We need - # to throw the connection away unless explicitly told not to. - # Close the connection, set the variable to None, and make sure - # we put the None back in the pool to avoid leaking it. - conn = conn and conn.close() - release_this_conn = True - - if release_this_conn: - # Put the connection back to be reused. If the connection is - # expired then it will be None, which will get replaced with a - # fresh connection during _get_conn. - self._put_conn(conn) - - if not conn: - # Try again - log.warning("Retrying (%r) after connection " - "broken by '%r': %s", retries, err, url) - return self.urlopen(method, url, body, headers, retries, - redirect, assert_same_host, - timeout=timeout, pool_timeout=pool_timeout, - release_conn=release_conn, body_pos=body_pos, - **response_kw) - - # Handle redirect? - redirect_location = redirect and response.get_redirect_location() - if redirect_location: - if response.status == 303: - method = 'GET' - - try: - retries = retries.increment(method, url, response=response, _pool=self) - except MaxRetryError: - if retries.raise_on_redirect: - # Release the connection for this response, since we're not - # returning it to be released manually. - response.release_conn() - raise - return response - - retries.sleep_for_retry(response) - log.debug("Redirecting %s -> %s", url, redirect_location) - return self.urlopen( - method, redirect_location, body, headers, - retries=retries, redirect=redirect, - assert_same_host=assert_same_host, - timeout=timeout, pool_timeout=pool_timeout, - release_conn=release_conn, body_pos=body_pos, - **response_kw) - - # Check if we should retry the HTTP response. - has_retry_after = bool(response.getheader('Retry-After')) - if retries.is_retry(method, response.status, has_retry_after): - try: - retries = retries.increment(method, url, response=response, _pool=self) - except MaxRetryError: - if retries.raise_on_status: - # Release the connection for this response, since we're not - # returning it to be released manually. - response.release_conn() - raise - return response - retries.sleep(response) - log.debug("Retry: %s", url) - return self.urlopen( - method, url, body, headers, - retries=retries, redirect=redirect, - assert_same_host=assert_same_host, - timeout=timeout, pool_timeout=pool_timeout, - release_conn=release_conn, - body_pos=body_pos, **response_kw) - - return response - - -class HTTPSConnectionPool(HTTPConnectionPool): - """ - Same as :class:`.HTTPConnectionPool`, but HTTPS. - - When Python is compiled with the :mod:`ssl` module, then - :class:`.VerifiedHTTPSConnection` is used, which *can* verify certificates, - instead of :class:`.HTTPSConnection`. - - :class:`.VerifiedHTTPSConnection` uses one of ``assert_fingerprint``, - ``assert_hostname`` and ``host`` in this order to verify connections. - If ``assert_hostname`` is False, no verification is done. - - The ``key_file``, ``cert_file``, ``cert_reqs``, ``ca_certs``, - ``ca_cert_dir``, and ``ssl_version`` are only used if :mod:`ssl` is - available and are fed into :meth:`urllib3.util.ssl_wrap_socket` to upgrade - the connection socket into an SSL socket. - """ - - scheme = 'https' - ConnectionCls = HTTPSConnection - - def __init__(self, host, port=None, - strict=False, timeout=Timeout.DEFAULT_TIMEOUT, maxsize=1, - block=False, headers=None, retries=None, - _proxy=None, _proxy_headers=None, - key_file=None, cert_file=None, cert_reqs=None, - ca_certs=None, ssl_version=None, - assert_hostname=None, assert_fingerprint=None, - ca_cert_dir=None, **conn_kw): - - HTTPConnectionPool.__init__(self, host, port, strict, timeout, maxsize, - block, headers, retries, _proxy, _proxy_headers, - **conn_kw) - - if ca_certs and cert_reqs is None: - cert_reqs = 'CERT_REQUIRED' - - self.key_file = key_file - self.cert_file = cert_file - self.cert_reqs = cert_reqs - self.ca_certs = ca_certs - self.ca_cert_dir = ca_cert_dir - self.ssl_version = ssl_version - self.assert_hostname = assert_hostname - self.assert_fingerprint = assert_fingerprint - - def _prepare_conn(self, conn): - """ - Prepare the ``connection`` for :meth:`urllib3.util.ssl_wrap_socket` - and establish the tunnel if proxy is used. - """ - - if isinstance(conn, VerifiedHTTPSConnection): - conn.set_cert(key_file=self.key_file, - cert_file=self.cert_file, - cert_reqs=self.cert_reqs, - ca_certs=self.ca_certs, - ca_cert_dir=self.ca_cert_dir, - assert_hostname=self.assert_hostname, - assert_fingerprint=self.assert_fingerprint) - conn.ssl_version = self.ssl_version - return conn - - def _prepare_proxy(self, conn): - """ - Establish tunnel connection early, because otherwise httplib - would improperly set Host: header to proxy's IP:port. - """ - # Python 2.7+ - try: - set_tunnel = conn.set_tunnel - except AttributeError: # Platform-specific: Python 2.6 - set_tunnel = conn._set_tunnel - - if sys.version_info <= (2, 6, 4) and not self.proxy_headers: # Python 2.6.4 and older - set_tunnel(self.host, self.port) - else: - set_tunnel(self.host, self.port, self.proxy_headers) - - conn.connect() - - def _new_conn(self): - """ - Return a fresh :class:`httplib.HTTPSConnection`. - """ - self.num_connections += 1 - log.debug("Starting new HTTPS connection (%d): %s", - self.num_connections, self.host) - - if not self.ConnectionCls or self.ConnectionCls is DummyConnection: - raise SSLError("Can't connect to HTTPS URL because the SSL " - "module is not available.") - - actual_host = self.host - actual_port = self.port - if self.proxy is not None: - actual_host = self.proxy.host - actual_port = self.proxy.port - - conn = self.ConnectionCls(host=actual_host, port=actual_port, - timeout=self.timeout.connect_timeout, - strict=self.strict, **self.conn_kw) - - return self._prepare_conn(conn) - - def _validate_conn(self, conn): - """ - Called right before a request is made, after the socket is created. - """ - super(HTTPSConnectionPool, self)._validate_conn(conn) - - if not conn.is_verified: - warnings.warn(( - 'Unverified HTTPS request is being made. ' - 'Adding certificate verification is strongly advised. See: ' - 'https://urllib3.readthedocs.io/en/latest/advanced-usage.html' - '#ssl-warnings'), - InsecureRequestWarning) - - -def connection_from_url(url, **kw): - """ - Given a url, return an :class:`.ConnectionPool` instance of its host. - - This is a shortcut for not having to parse out the scheme, host, and port - of the url before creating an :class:`.ConnectionPool` instance. - - :param url: - Absolute URL string that must include the scheme. Port is optional. - - :param \\**kw: - Passes additional parameters to the constructor of the appropriate - :class:`.ConnectionPool`. Useful for specifying things like - timeout, maxsize, headers, etc. - - Example:: - - >>> conn = connection_from_url('http://google.com/') - >>> r = conn.request('GET', '/') - """ - scheme, host, port = get_host(url) - port = port or port_by_scheme.get(scheme, 80) - if scheme == 'https': - return HTTPSConnectionPool(host, port=port, **kw) - else: - return HTTPConnectionPool(host, port=port, **kw) - - -def _ipv6_host(host): - """ - Process IPv6 address literals - """ - - # httplib doesn't like it when we include brackets in IPv6 addresses - # Specifically, if we include brackets but also pass the port then - # httplib crazily doubles up the square brackets on the Host header. - # Instead, we need to make sure we never pass ``None`` as the port. - # However, for backward compatibility reasons we can't actually - # *assert* that. See http://bugs.python.org/issue28539 - # - # Also if an IPv6 address literal has a zone identifier, the - # percent sign might be URIencoded, convert it back into ASCII - if host.startswith('[') and host.endswith(']'): - host = host.replace('%25', '%').strip('[]') - return host diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/contrib/__init__.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/contrib/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/contrib/appengine.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/contrib/appengine.py deleted file mode 100644 index 814b022..0000000 --- a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/contrib/appengine.py +++ /dev/null @@ -1,296 +0,0 @@ -""" -This module provides a pool manager that uses Google App Engine's -`URLFetch Service <https://cloud.google.com/appengine/docs/python/urlfetch>`_. - -Example usage:: - - from urllib3 import PoolManager - from urllib3.contrib.appengine import AppEngineManager, is_appengine_sandbox - - if is_appengine_sandbox(): - # AppEngineManager uses AppEngine's URLFetch API behind the scenes - http = AppEngineManager() - else: - # PoolManager uses a socket-level API behind the scenes - http = PoolManager() - - r = http.request('GET', 'https://google.com/') - -There are `limitations <https://cloud.google.com/appengine/docs/python/\ -urlfetch/#Python_Quotas_and_limits>`_ to the URLFetch service and it may not be -the best choice for your application. There are three options for using -urllib3 on Google App Engine: - -1. You can use :class:`AppEngineManager` with URLFetch. URLFetch is - cost-effective in many circumstances as long as your usage is within the - limitations. -2. You can use a normal :class:`~urllib3.PoolManager` by enabling sockets. - Sockets also have `limitations and restrictions - <https://cloud.google.com/appengine/docs/python/sockets/\ - #limitations-and-restrictions>`_ and have a lower free quota than URLFetch. - To use sockets, be sure to specify the following in your ``app.yaml``:: - - env_variables: - GAE_USE_SOCKETS_HTTPLIB : 'true' - -3. If you are using `App Engine Flexible -<https://cloud.google.com/appengine/docs/flexible/>`_, you can use the standard -:class:`PoolManager` without any configuration or special environment variables. -""" - -from __future__ import absolute_import -import logging -import os -import warnings -from ..packages.six.moves.urllib.parse import urljoin - -from ..exceptions import ( - HTTPError, - HTTPWarning, - MaxRetryError, - ProtocolError, - TimeoutError, - SSLError -) - -from ..packages.six import BytesIO -from ..request import RequestMethods -from ..response import HTTPResponse -from ..util.timeout import Timeout -from ..util.retry import Retry - -try: - from google.appengine.api import urlfetch -except ImportError: - urlfetch = None - - -log = logging.getLogger(__name__) - - -class AppEnginePlatformWarning(HTTPWarning): - pass - - -class AppEnginePlatformError(HTTPError): - pass - - -class AppEngineManager(RequestMethods): - """ - Connection manager for Google App Engine sandbox applications. - - This manager uses the URLFetch service directly instead of using the - emulated httplib, and is subject to URLFetch limitations as described in - the App Engine documentation `here - <https://cloud.google.com/appengine/docs/python/urlfetch>`_. - - Notably it will raise an :class:`AppEnginePlatformError` if: - * URLFetch is not available. - * If you attempt to use this on App Engine Flexible, as full socket - support is available. - * If a request size is more than 10 megabytes. - * If a response size is more than 32 megabtyes. - * If you use an unsupported request method such as OPTIONS. - - Beyond those cases, it will raise normal urllib3 errors. - """ - - def __init__(self, headers=None, retries=None, validate_certificate=True, - urlfetch_retries=True): - if not urlfetch: - raise AppEnginePlatformError( - "URLFetch is not available in this environment.") - - if is_prod_appengine_mvms(): - raise AppEnginePlatformError( - "Use normal urllib3.PoolManager instead of AppEngineManager" - "on Managed VMs, as using URLFetch is not necessary in " - "this environment.") - - warnings.warn( - "urllib3 is using URLFetch on Google App Engine sandbox instead " - "of sockets. To use sockets directly instead of URLFetch see " - "https://urllib3.readthedocs.io/en/latest/reference/urllib3.contrib.html.", - AppEnginePlatformWarning) - - RequestMethods.__init__(self, headers) - self.validate_certificate = validate_certificate - self.urlfetch_retries = urlfetch_retries - - self.retries = retries or Retry.DEFAULT - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_val, exc_tb): - # Return False to re-raise any potential exceptions - return False - - def urlopen(self, method, url, body=None, headers=None, - retries=None, redirect=True, timeout=Timeout.DEFAULT_TIMEOUT, - **response_kw): - - retries = self._get_retries(retries, redirect) - - try: - follow_redirects = ( - redirect and - retries.redirect != 0 and - retries.total) - response = urlfetch.fetch( - url, - payload=body, - method=method, - headers=headers or {}, - allow_truncated=False, - follow_redirects=self.urlfetch_retries and follow_redirects, - deadline=self._get_absolute_timeout(timeout), - validate_certificate=self.validate_certificate, - ) - except urlfetch.DeadlineExceededError as e: - raise TimeoutError(self, e) - - except urlfetch.InvalidURLError as e: - if 'too large' in str(e): - raise AppEnginePlatformError( - "URLFetch request too large, URLFetch only " - "supports requests up to 10mb in size.", e) - raise ProtocolError(e) - - except urlfetch.DownloadError as e: - if 'Too many redirects' in str(e): - raise MaxRetryError(self, url, reason=e) - raise ProtocolError(e) - - except urlfetch.ResponseTooLargeError as e: - raise AppEnginePlatformError( - "URLFetch response too large, URLFetch only supports" - "responses up to 32mb in size.", e) - - except urlfetch.SSLCertificateError as e: - raise SSLError(e) - - except urlfetch.InvalidMethodError as e: - raise AppEnginePlatformError( - "URLFetch does not support method: %s" % method, e) - - http_response = self._urlfetch_response_to_http_response( - response, retries=retries, **response_kw) - - # Handle redirect? - redirect_location = redirect and http_response.get_redirect_location() - if redirect_location: - # Check for redirect response - if (self.urlfetch_retries and retries.raise_on_redirect): - raise MaxRetryError(self, url, "too many redirects") - else: - if http_response.status == 303: - method = 'GET' - - try: - retries = retries.increment(method, url, response=http_response, _pool=self) - except MaxRetryError: - if retries.raise_on_redirect: - raise MaxRetryError(self, url, "too many redirects") - return http_response - - retries.sleep_for_retry(http_response) - log.debug("Redirecting %s -> %s", url, redirect_location) - redirect_url = urljoin(url, redirect_location) - return self.urlopen( - method, redirect_url, body, headers, - retries=retries, redirect=redirect, - timeout=timeout, **response_kw) - - # Check if we should retry the HTTP response. - has_retry_after = bool(http_response.getheader('Retry-After')) - if retries.is_retry(method, http_response.status, has_retry_after): - retries = retries.increment( - method, url, response=http_response, _pool=self) - log.debug("Retry: %s", url) - retries.sleep(http_response) - return self.urlopen( - method, url, - body=body, headers=headers, - retries=retries, redirect=redirect, - timeout=timeout, **response_kw) - - return http_response - - def _urlfetch_response_to_http_response(self, urlfetch_resp, **response_kw): - - if is_prod_appengine(): - # Production GAE handles deflate encoding automatically, but does - # not remove the encoding header. - content_encoding = urlfetch_resp.headers.get('content-encoding') - - if content_encoding == 'deflate': - del urlfetch_resp.headers['content-encoding'] - - transfer_encoding = urlfetch_resp.headers.get('transfer-encoding') - # We have a full response's content, - # so let's make sure we don't report ourselves as chunked data. - if transfer_encoding == 'chunked': - encodings = transfer_encoding.split(",") - encodings.remove('chunked') - urlfetch_resp.headers['transfer-encoding'] = ','.join(encodings) - - return HTTPResponse( - # In order for decoding to work, we must present the content as - # a file-like object. - body=BytesIO(urlfetch_resp.content), - headers=urlfetch_resp.headers, - status=urlfetch_resp.status_code, - **response_kw - ) - - def _get_absolute_timeout(self, timeout): - if timeout is Timeout.DEFAULT_TIMEOUT: - return None # Defer to URLFetch's default. - if isinstance(timeout, Timeout): - if timeout._read is not None or timeout._connect is not None: - warnings.warn( - "URLFetch does not support granular timeout settings, " - "reverting to total or default URLFetch timeout.", - AppEnginePlatformWarning) - return timeout.total - return timeout - - def _get_retries(self, retries, redirect): - if not isinstance(retries, Retry): - retries = Retry.from_int( - retries, redirect=redirect, default=self.retries) - - if retries.connect or retries.read or retries.redirect: - warnings.warn( - "URLFetch only supports total retries and does not " - "recognize connect, read, or redirect retry parameters.", - AppEnginePlatformWarning) - - return retries - - -def is_appengine(): - return (is_local_appengine() or - is_prod_appengine() or - is_prod_appengine_mvms()) - - -def is_appengine_sandbox(): - return is_appengine() and not is_prod_appengine_mvms() - - -def is_local_appengine(): - return ('APPENGINE_RUNTIME' in os.environ and - 'Development/' in os.environ['SERVER_SOFTWARE']) - - -def is_prod_appengine(): - return ('APPENGINE_RUNTIME' in os.environ and - 'Google App Engine/' in os.environ['SERVER_SOFTWARE'] and - not is_prod_appengine_mvms()) - - -def is_prod_appengine_mvms(): - return os.environ.get('GAE_VM', False) == 'true' diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/contrib/ntlmpool.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/contrib/ntlmpool.py deleted file mode 100644 index 642e99e..0000000 --- a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/contrib/ntlmpool.py +++ /dev/null @@ -1,112 +0,0 @@ -""" -NTLM authenticating pool, contributed by erikcederstran - -Issue #10, see: http://code.google.com/p/urllib3/issues/detail?id=10 -""" -from __future__ import absolute_import - -from logging import getLogger -from ntlm import ntlm - -from .. import HTTPSConnectionPool -from ..packages.six.moves.http_client import HTTPSConnection - - -log = getLogger(__name__) - - -class NTLMConnectionPool(HTTPSConnectionPool): - """ - Implements an NTLM authentication version of an urllib3 connection pool - """ - - scheme = 'https' - - def __init__(self, user, pw, authurl, *args, **kwargs): - """ - authurl is a random URL on the server that is protected by NTLM. - user is the Windows user, probably in the DOMAIN\\username format. - pw is the password for the user. - """ - super(NTLMConnectionPool, self).__init__(*args, **kwargs) - self.authurl = authurl - self.rawuser = user - user_parts = user.split('\\', 1) - self.domain = user_parts[0].upper() - self.user = user_parts[1] - self.pw = pw - - def _new_conn(self): - # Performs the NTLM handshake that secures the connection. The socket - # must be kept open while requests are performed. - self.num_connections += 1 - log.debug('Starting NTLM HTTPS connection no. %d: https://%s%s', - self.num_connections, self.host, self.authurl) - - headers = {} - headers['Connection'] = 'Keep-Alive' - req_header = 'Authorization' - resp_header = 'www-authenticate' - - conn = HTTPSConnection(host=self.host, port=self.port) - - # Send negotiation message - headers[req_header] = ( - 'NTLM %s' % ntlm.create_NTLM_NEGOTIATE_MESSAGE(self.rawuser)) - log.debug('Request headers: %s', headers) - conn.request('GET', self.authurl, None, headers) - res = conn.getresponse() - reshdr = dict(res.getheaders()) - log.debug('Response status: %s %s', res.status, res.reason) - log.debug('Response headers: %s', reshdr) - log.debug('Response data: %s [...]', res.read(100)) - - # Remove the reference to the socket, so that it can not be closed by - # the response object (we want to keep the socket open) - res.fp = None - - # Server should respond with a challenge message - auth_header_values = reshdr[resp_header].split(', ') - auth_header_value = None - for s in auth_header_values: - if s[:5] == 'NTLM ': - auth_header_value = s[5:] - if auth_header_value is None: - raise Exception('Unexpected %s response header: %s' % - (resp_header, reshdr[resp_header])) - - # Send authentication message - ServerChallenge, NegotiateFlags = \ - ntlm.parse_NTLM_CHALLENGE_MESSAGE(auth_header_value) - auth_msg = ntlm.create_NTLM_AUTHENTICATE_MESSAGE(ServerChallenge, - self.user, - self.domain, - self.pw, - NegotiateFlags) - headers[req_header] = 'NTLM %s' % auth_msg - log.debug('Request headers: %s', headers) - conn.request('GET', self.authurl, None, headers) - res = conn.getresponse() - log.debug('Response status: %s %s', res.status, res.reason) - log.debug('Response headers: %s', dict(res.getheaders())) - log.debug('Response data: %s [...]', res.read()[:100]) - if res.status != 200: - if res.status == 401: - raise Exception('Server rejected request: wrong ' - 'username or password') - raise Exception('Wrong server response: %s %s' % - (res.status, res.reason)) - - res.fp = None - log.debug('Connection established') - return conn - - def urlopen(self, method, url, body=None, headers=None, retries=3, - redirect=True, assert_same_host=True): - if headers is None: - headers = {} - headers['Connection'] = 'Keep-Alive' - return super(NTLMConnectionPool, self).urlopen(method, url, body, - headers, retries, - redirect, - assert_same_host) diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/contrib/pyopenssl.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/contrib/pyopenssl.py deleted file mode 100644 index eb4d476..0000000 --- a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/contrib/pyopenssl.py +++ /dev/null @@ -1,450 +0,0 @@ -""" -SSL with SNI_-support for Python 2. Follow these instructions if you would -like to verify SSL certificates in Python 2. Note, the default libraries do -*not* do certificate checking; you need to do additional work to validate -certificates yourself. - -This needs the following packages installed: - -* pyOpenSSL (tested with 16.0.0) -* cryptography (minimum 1.3.4, from pyopenssl) -* idna (minimum 2.0, from cryptography) - -However, pyopenssl depends on cryptography, which depends on idna, so while we -use all three directly here we end up having relatively few packages required. - -You can install them with the following command: - - pip install pyopenssl cryptography idna - -To activate certificate checking, call -:func:`~urllib3.contrib.pyopenssl.inject_into_urllib3` from your Python code -before you begin making HTTP requests. This can be done in a ``sitecustomize`` -module, or at any other time before your application begins using ``urllib3``, -like this:: - - try: - import urllib3.contrib.pyopenssl - urllib3.contrib.pyopenssl.inject_into_urllib3() - except ImportError: - pass - -Now you can use :mod:`urllib3` as you normally would, and it will support SNI -when the required modules are installed. - -Activating this module also has the positive side effect of disabling SSL/TLS -compression in Python 2 (see `CRIME attack`_). - -If you want to configure the default list of supported cipher suites, you can -set the ``urllib3.contrib.pyopenssl.DEFAULT_SSL_CIPHER_LIST`` variable. - -.. _sni: https://en.wikipedia.org/wiki/Server_Name_Indication -.. _crime attack: https://en.wikipedia.org/wiki/CRIME_(security_exploit) -""" -from __future__ import absolute_import - -import OpenSSL.SSL -from cryptography import x509 -from cryptography.hazmat.backends.openssl import backend as openssl_backend -from cryptography.hazmat.backends.openssl.x509 import _Certificate - -from socket import timeout, error as SocketError -from io import BytesIO - -try: # Platform-specific: Python 2 - from socket import _fileobject -except ImportError: # Platform-specific: Python 3 - _fileobject = None - from ..packages.backports.makefile import backport_makefile - -import logging -import ssl -import six -import sys - -from .. import util - -__all__ = ['inject_into_urllib3', 'extract_from_urllib3'] - -# SNI always works. -HAS_SNI = True - -# Map from urllib3 to PyOpenSSL compatible parameter-values. -_openssl_versions = { - ssl.PROTOCOL_SSLv23: OpenSSL.SSL.SSLv23_METHOD, - ssl.PROTOCOL_TLSv1: OpenSSL.SSL.TLSv1_METHOD, -} - -if hasattr(ssl, 'PROTOCOL_TLSv1_1') and hasattr(OpenSSL.SSL, 'TLSv1_1_METHOD'): - _openssl_versions[ssl.PROTOCOL_TLSv1_1] = OpenSSL.SSL.TLSv1_1_METHOD - -if hasattr(ssl, 'PROTOCOL_TLSv1_2') and hasattr(OpenSSL.SSL, 'TLSv1_2_METHOD'): - _openssl_versions[ssl.PROTOCOL_TLSv1_2] = OpenSSL.SSL.TLSv1_2_METHOD - -try: - _openssl_versions.update({ssl.PROTOCOL_SSLv3: OpenSSL.SSL.SSLv3_METHOD}) -except AttributeError: - pass - -_stdlib_to_openssl_verify = { - ssl.CERT_NONE: OpenSSL.SSL.VERIFY_NONE, - ssl.CERT_OPTIONAL: OpenSSL.SSL.VERIFY_PEER, - ssl.CERT_REQUIRED: - OpenSSL.SSL.VERIFY_PEER + OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT, -} -_openssl_to_stdlib_verify = dict( - (v, k) for k, v in _stdlib_to_openssl_verify.items() -) - -# OpenSSL will only write 16K at a time -SSL_WRITE_BLOCKSIZE = 16384 - -orig_util_HAS_SNI = util.HAS_SNI -orig_util_SSLContext = util.ssl_.SSLContext - - -log = logging.getLogger(__name__) - - -def inject_into_urllib3(): - 'Monkey-patch urllib3 with PyOpenSSL-backed SSL-support.' - - _validate_dependencies_met() - - util.ssl_.SSLContext = PyOpenSSLContext - util.HAS_SNI = HAS_SNI - util.ssl_.HAS_SNI = HAS_SNI - util.IS_PYOPENSSL = True - util.ssl_.IS_PYOPENSSL = True - - -def extract_from_urllib3(): - 'Undo monkey-patching by :func:`inject_into_urllib3`.' - - util.ssl_.SSLContext = orig_util_SSLContext - util.HAS_SNI = orig_util_HAS_SNI - util.ssl_.HAS_SNI = orig_util_HAS_SNI - util.IS_PYOPENSSL = False - util.ssl_.IS_PYOPENSSL = False - - -def _validate_dependencies_met(): - """ - Verifies that PyOpenSSL's package-level dependencies have been met. - Throws `ImportError` if they are not met. - """ - # Method added in `cryptography==1.1`; not available in older versions - from cryptography.x509.extensions import Extensions - if getattr(Extensions, "get_extension_for_class", None) is None: - raise ImportError("'cryptography' module missing required functionality. " - "Try upgrading to v1.3.4 or newer.") - - # pyOpenSSL 0.14 and above use cryptography for OpenSSL bindings. The _x509 - # attribute is only present on those versions. - from OpenSSL.crypto import X509 - x509 = X509() - if getattr(x509, "_x509", None) is None: - raise ImportError("'pyOpenSSL' module missing required functionality. " - "Try upgrading to v0.14 or newer.") - - -def _dnsname_to_stdlib(name): - """ - Converts a dNSName SubjectAlternativeName field to the form used by the - standard library on the given Python version. - - Cryptography produces a dNSName as a unicode string that was idna-decoded - from ASCII bytes. We need to idna-encode that string to get it back, and - then on Python 3 we also need to convert to unicode via UTF-8 (the stdlib - uses PyUnicode_FromStringAndSize on it, which decodes via UTF-8). - """ - def idna_encode(name): - """ - Borrowed wholesale from the Python Cryptography Project. It turns out - that we can't just safely call `idna.encode`: it can explode for - wildcard names. This avoids that problem. - """ - import idna - - for prefix in [u'*.', u'.']: - if name.startswith(prefix): - name = name[len(prefix):] - return prefix.encode('ascii') + idna.encode(name) - return idna.encode(name) - - name = idna_encode(name) - if sys.version_info >= (3, 0): - name = name.decode('utf-8') - return name - - -def get_subj_alt_name(peer_cert): - """ - Given an PyOpenSSL certificate, provides all the subject alternative names. - """ - # Pass the cert to cryptography, which has much better APIs for this. - # This is technically using private APIs, but should work across all - # relevant versions until PyOpenSSL gets something proper for this. - cert = _Certificate(openssl_backend, peer_cert._x509) - - # We want to find the SAN extension. Ask Cryptography to locate it (it's - # faster than looping in Python) - try: - ext = cert.extensions.get_extension_for_class( - x509.SubjectAlternativeName - ).value - except x509.ExtensionNotFound: - # No such extension, return the empty list. - return [] - except (x509.DuplicateExtension, x509.UnsupportedExtension, - x509.UnsupportedGeneralNameType, UnicodeError) as e: - # A problem has been found with the quality of the certificate. Assume - # no SAN field is present. - log.warning( - "A problem was encountered with the certificate that prevented " - "urllib3 from finding the SubjectAlternativeName field. This can " - "affect certificate validation. The error was %s", - e, - ) - return [] - - # We want to return dNSName and iPAddress fields. We need to cast the IPs - # back to strings because the match_hostname function wants them as - # strings. - # Sadly the DNS names need to be idna encoded and then, on Python 3, UTF-8 - # decoded. This is pretty frustrating, but that's what the standard library - # does with certificates, and so we need to attempt to do the same. - names = [ - ('DNS', _dnsname_to_stdlib(name)) - for name in ext.get_values_for_type(x509.DNSName) - ] - names.extend( - ('IP Address', str(name)) - for name in ext.get_values_for_type(x509.IPAddress) - ) - - return names - - -class WrappedSocket(object): - '''API-compatibility wrapper for Python OpenSSL's Connection-class. - - Note: _makefile_refs, _drop() and _reuse() are needed for the garbage - collector of pypy. - ''' - - def __init__(self, connection, socket, suppress_ragged_eofs=True): - self.connection = connection - self.socket = socket - self.suppress_ragged_eofs = suppress_ragged_eofs - self._makefile_refs = 0 - self._closed = False - - def fileno(self): - return self.socket.fileno() - - # Copy-pasted from Python 3.5 source code - def _decref_socketios(self): - if self._makefile_refs > 0: - self._makefile_refs -= 1 - if self._closed: - self.close() - - def recv(self, *args, **kwargs): - try: - data = self.connection.recv(*args, **kwargs) - except OpenSSL.SSL.SysCallError as e: - if self.suppress_ragged_eofs and e.args == (-1, 'Unexpected EOF'): - return b'' - else: - raise SocketError(str(e)) - except OpenSSL.SSL.ZeroReturnError as e: - if self.connection.get_shutdown() == OpenSSL.SSL.RECEIVED_SHUTDOWN: - return b'' - else: - raise - except OpenSSL.SSL.WantReadError: - rd = util.wait_for_read(self.socket, self.socket.gettimeout()) - if not rd: - raise timeout('The read operation timed out') - else: - return self.recv(*args, **kwargs) - else: - return data - - def recv_into(self, *args, **kwargs): - try: - return self.connection.recv_into(*args, **kwargs) - except OpenSSL.SSL.SysCallError as e: - if self.suppress_ragged_eofs and e.args == (-1, 'Unexpected EOF'): - return 0 - else: - raise SocketError(str(e)) - except OpenSSL.SSL.ZeroReturnError as e: - if self.connection.get_shutdown() == OpenSSL.SSL.RECEIVED_SHUTDOWN: - return 0 - else: - raise - except OpenSSL.SSL.WantReadError: - rd = util.wait_for_read(self.socket, self.socket.gettimeout()) - if not rd: - raise timeout('The read operation timed out') - else: - return self.recv_into(*args, **kwargs) - - def settimeout(self, timeout): - return self.socket.settimeout(timeout) - - def _send_until_done(self, data): - while True: - try: - return self.connection.send(data) - except OpenSSL.SSL.WantWriteError: - wr = util.wait_for_write(self.socket, self.socket.gettimeout()) - if not wr: - raise timeout() - continue - - def sendall(self, data): - total_sent = 0 - while total_sent < len(data): - sent = self._send_until_done(data[total_sent:total_sent + SSL_WRITE_BLOCKSIZE]) - total_sent += sent - - def shutdown(self): - # FIXME rethrow compatible exceptions should we ever use this - self.connection.shutdown() - - def close(self): - if self._makefile_refs < 1: - try: - self._closed = True - return self.connection.close() - except OpenSSL.SSL.Error: - return - else: - self._makefile_refs -= 1 - - def getpeercert(self, binary_form=False): - x509 = self.connection.get_peer_certificate() - - if not x509: - return x509 - - if binary_form: - return OpenSSL.crypto.dump_certificate( - OpenSSL.crypto.FILETYPE_ASN1, - x509) - - return { - 'subject': ( - (('commonName', x509.get_subject().CN),), - ), - 'subjectAltName': get_subj_alt_name(x509) - } - - def _reuse(self): - self._makefile_refs += 1 - - def _drop(self): - if self._makefile_refs < 1: - self.close() - else: - self._makefile_refs -= 1 - - -if _fileobject: # Platform-specific: Python 2 - def makefile(self, mode, bufsize=-1): - self._makefile_refs += 1 - return _fileobject(self, mode, bufsize, close=True) -else: # Platform-specific: Python 3 - makefile = backport_makefile - -WrappedSocket.makefile = makefile - - -class PyOpenSSLContext(object): - """ - I am a wrapper class for the PyOpenSSL ``Context`` object. I am responsible - for translating the interface of the standard library ``SSLContext`` object - to calls into PyOpenSSL. - """ - def __init__(self, protocol): - self.protocol = _openssl_versions[protocol] - self._ctx = OpenSSL.SSL.Context(self.protocol) - self._options = 0 - self.check_hostname = False - - @property - def options(self): - return self._options - - @options.setter - def options(self, value): - self._options = value - self._ctx.set_options(value) - - @property - def verify_mode(self): - return _openssl_to_stdlib_verify[self._ctx.get_verify_mode()] - - @verify_mode.setter - def verify_mode(self, value): - self._ctx.set_verify( - _stdlib_to_openssl_verify[value], - _verify_callback - ) - - def set_default_verify_paths(self): - self._ctx.set_default_verify_paths() - - def set_ciphers(self, ciphers): - if isinstance(ciphers, six.text_type): - ciphers = ciphers.encode('utf-8') - self._ctx.set_cipher_list(ciphers) - - def load_verify_locations(self, cafile=None, capath=None, cadata=None): - if cafile is not None: - cafile = cafile.encode('utf-8') - if capath is not None: - capath = capath.encode('utf-8') - self._ctx.load_verify_locations(cafile, capath) - if cadata is not None: - self._ctx.load_verify_locations(BytesIO(cadata)) - - def load_cert_chain(self, certfile, keyfile=None, password=None): - self._ctx.use_certificate_file(certfile) - if password is not None: - self._ctx.set_passwd_cb(lambda max_length, prompt_twice, userdata: password) - self._ctx.use_privatekey_file(keyfile or certfile) - - def wrap_socket(self, sock, server_side=False, - do_handshake_on_connect=True, suppress_ragged_eofs=True, - server_hostname=None): - cnx = OpenSSL.SSL.Connection(self._ctx, sock) - - if isinstance(server_hostname, six.text_type): # Platform-specific: Python 3 - server_hostname = server_hostname.encode('utf-8') - - if server_hostname is not None: - cnx.set_tlsext_host_name(server_hostname) - - cnx.set_connect_state() - - while True: - try: - cnx.do_handshake() - except OpenSSL.SSL.WantReadError: - rd = util.wait_for_read(sock, sock.gettimeout()) - if not rd: - raise timeout('select timed out') - continue - except OpenSSL.SSL.Error as e: - raise ssl.SSLError('bad handshake: %r' % e) - break - - return WrappedSocket(cnx, sock) - - -def _verify_callback(cnx, x509, err_no, err_depth, return_code): - return err_no == 0 diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/contrib/socks.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/contrib/socks.py deleted file mode 100644 index 811e312..0000000 --- a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/contrib/socks.py +++ /dev/null @@ -1,192 +0,0 @@ -# -*- coding: utf-8 -*- -""" -This module contains provisional support for SOCKS proxies from within -urllib3. This module supports SOCKS4 (specifically the SOCKS4A variant) and -SOCKS5. To enable its functionality, either install PySocks or install this -module with the ``socks`` extra. - -The SOCKS implementation supports the full range of urllib3 features. It also -supports the following SOCKS features: - -- SOCKS4 -- SOCKS4a -- SOCKS5 -- Usernames and passwords for the SOCKS proxy - -Known Limitations: - -- Currently PySocks does not support contacting remote websites via literal - IPv6 addresses. Any such connection attempt will fail. You must use a domain - name. -- Currently PySocks does not support IPv6 connections to the SOCKS proxy. Any - such connection attempt will fail. -""" -from __future__ import absolute_import - -try: - import socks -except ImportError: - import warnings - from ..exceptions import DependencyWarning - - warnings.warn(( - 'SOCKS support in urllib3 requires the installation of optional ' - 'dependencies: specifically, PySocks. For more information, see ' - 'https://urllib3.readthedocs.io/en/latest/contrib.html#socks-proxies' - ), - DependencyWarning - ) - raise - -from socket import error as SocketError, timeout as SocketTimeout - -from ..connection import ( - HTTPConnection, HTTPSConnection -) -from ..connectionpool import ( - HTTPConnectionPool, HTTPSConnectionPool -) -from ..exceptions import ConnectTimeoutError, NewConnectionError -from ..poolmanager import PoolManager -from ..util.url import parse_url - -try: - import ssl -except ImportError: - ssl = None - - -class SOCKSConnection(HTTPConnection): - """ - A plain-text HTTP connection that connects via a SOCKS proxy. - """ - def __init__(self, *args, **kwargs): - self._socks_options = kwargs.pop('_socks_options') - super(SOCKSConnection, self).__init__(*args, **kwargs) - - def _new_conn(self): - """ - Establish a new connection via the SOCKS proxy. - """ - extra_kw = {} - if self.source_address: - extra_kw['source_address'] = self.source_address - - if self.socket_options: - extra_kw['socket_options'] = self.socket_options - - try: - conn = socks.create_connection( - (self.host, self.port), - proxy_type=self._socks_options['socks_version'], - proxy_addr=self._socks_options['proxy_host'], - proxy_port=self._socks_options['proxy_port'], - proxy_username=self._socks_options['username'], - proxy_password=self._socks_options['password'], - proxy_rdns=self._socks_options['rdns'], - timeout=self.timeout, - **extra_kw - ) - - except SocketTimeout as e: - raise ConnectTimeoutError( - self, "Connection to %s timed out. (connect timeout=%s)" % - (self.host, self.timeout)) - - except socks.ProxyError as e: - # This is fragile as hell, but it seems to be the only way to raise - # useful errors here. - if e.socket_err: - error = e.socket_err - if isinstance(error, SocketTimeout): - raise ConnectTimeoutError( - self, - "Connection to %s timed out. (connect timeout=%s)" % - (self.host, self.timeout) - ) - else: - raise NewConnectionError( - self, - "Failed to establish a new connection: %s" % error - ) - else: - raise NewConnectionError( - self, - "Failed to establish a new connection: %s" % e - ) - - except SocketError as e: # Defensive: PySocks should catch all these. - raise NewConnectionError( - self, "Failed to establish a new connection: %s" % e) - - return conn - - -# We don't need to duplicate the Verified/Unverified distinction from -# urllib3/connection.py here because the HTTPSConnection will already have been -# correctly set to either the Verified or Unverified form by that module. This -# means the SOCKSHTTPSConnection will automatically be the correct type. -class SOCKSHTTPSConnection(SOCKSConnection, HTTPSConnection): - pass - - -class SOCKSHTTPConnectionPool(HTTPConnectionPool): - ConnectionCls = SOCKSConnection - - -class SOCKSHTTPSConnectionPool(HTTPSConnectionPool): - ConnectionCls = SOCKSHTTPSConnection - - -class SOCKSProxyManager(PoolManager): - """ - A version of the urllib3 ProxyManager that routes connections via the - defined SOCKS proxy. - """ - pool_classes_by_scheme = { - 'http': SOCKSHTTPConnectionPool, - 'https': SOCKSHTTPSConnectionPool, - } - - def __init__(self, proxy_url, username=None, password=None, - num_pools=10, headers=None, **connection_pool_kw): - parsed = parse_url(proxy_url) - - if username is None and password is None and parsed.auth is not None: - split = parsed.auth.split(':') - if len(split) == 2: - username, password = split - if parsed.scheme == 'socks5': - socks_version = socks.PROXY_TYPE_SOCKS5 - rdns = False - elif parsed.scheme == 'socks5h': - socks_version = socks.PROXY_TYPE_SOCKS5 - rdns = True - elif parsed.scheme == 'socks4': - socks_version = socks.PROXY_TYPE_SOCKS4 - rdns = False - elif parsed.scheme == 'socks4a': - socks_version = socks.PROXY_TYPE_SOCKS4 - rdns = True - else: - raise ValueError( - "Unable to determine SOCKS version from %s" % proxy_url - ) - - self.proxy_url = proxy_url - - socks_options = { - 'socks_version': socks_version, - 'proxy_host': parsed.host, - 'proxy_port': parsed.port, - 'username': username, - 'password': password, - 'rdns': rdns - } - connection_pool_kw['_socks_options'] = socks_options - - super(SOCKSProxyManager, self).__init__( - num_pools, headers, **connection_pool_kw - ) - - self.pool_classes_by_scheme = SOCKSProxyManager.pool_classes_by_scheme diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/exceptions.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/exceptions.py deleted file mode 100644 index 6c4be58..0000000 --- a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/exceptions.py +++ /dev/null @@ -1,246 +0,0 @@ -from __future__ import absolute_import -from .packages.six.moves.http_client import ( - IncompleteRead as httplib_IncompleteRead -) -# Base Exceptions - - -class HTTPError(Exception): - "Base exception used by this module." - pass - - -class HTTPWarning(Warning): - "Base warning used by this module." - pass - - -class PoolError(HTTPError): - "Base exception for errors caused within a pool." - def __init__(self, pool, message): - self.pool = pool - HTTPError.__init__(self, "%s: %s" % (pool, message)) - - def __reduce__(self): - # For pickling purposes. - return self.__class__, (None, None) - - -class RequestError(PoolError): - "Base exception for PoolErrors that have associated URLs." - def __init__(self, pool, url, message): - self.url = url - PoolError.__init__(self, pool, message) - - def __reduce__(self): - # For pickling purposes. - return self.__class__, (None, self.url, None) - - -class SSLError(HTTPError): - "Raised when SSL certificate fails in an HTTPS connection." - pass - - -class ProxyError(HTTPError): - "Raised when the connection to a proxy fails." - pass - - -class DecodeError(HTTPError): - "Raised when automatic decoding based on Content-Type fails." - pass - - -class ProtocolError(HTTPError): - "Raised when something unexpected happens mid-request/response." - pass - - -#: Renamed to ProtocolError but aliased for backwards compatibility. -ConnectionError = ProtocolError - - -# Leaf Exceptions - -class MaxRetryError(RequestError): - """Raised when the maximum number of retries is exceeded. - - :param pool: The connection pool - :type pool: :class:`~urllib3.connectionpool.HTTPConnectionPool` - :param string url: The requested Url - :param exceptions.Exception reason: The underlying error - - """ - - def __init__(self, pool, url, reason=None): - self.reason = reason - - message = "Max retries exceeded with url: %s (Caused by %r)" % ( - url, reason) - - RequestError.__init__(self, pool, url, message) - - -class HostChangedError(RequestError): - "Raised when an existing pool gets a request for a foreign host." - - def __init__(self, pool, url, retries=3): - message = "Tried to open a foreign host with url: %s" % url - RequestError.__init__(self, pool, url, message) - self.retries = retries - - -class TimeoutStateError(HTTPError): - """ Raised when passing an invalid state to a timeout """ - pass - - -class TimeoutError(HTTPError): - """ Raised when a socket timeout error occurs. - - Catching this error will catch both :exc:`ReadTimeoutErrors - <ReadTimeoutError>` and :exc:`ConnectTimeoutErrors <ConnectTimeoutError>`. - """ - pass - - -class ReadTimeoutError(TimeoutError, RequestError): - "Raised when a socket timeout occurs while receiving data from a server" - pass - - -# This timeout error does not have a URL attached and needs to inherit from the -# base HTTPError -class ConnectTimeoutError(TimeoutError): - "Raised when a socket timeout occurs while connecting to a server" - pass - - -class NewConnectionError(ConnectTimeoutError, PoolError): - "Raised when we fail to establish a new connection. Usually ECONNREFUSED." - pass - - -class EmptyPoolError(PoolError): - "Raised when a pool runs out of connections and no more are allowed." - pass - - -class ClosedPoolError(PoolError): - "Raised when a request enters a pool after the pool has been closed." - pass - - -class LocationValueError(ValueError, HTTPError): - "Raised when there is something wrong with a given URL input." - pass - - -class LocationParseError(LocationValueError): - "Raised when get_host or similar fails to parse the URL input." - - def __init__(self, location): - message = "Failed to parse: %s" % location - HTTPError.__init__(self, message) - - self.location = location - - -class ResponseError(HTTPError): - "Used as a container for an error reason supplied in a MaxRetryError." - GENERIC_ERROR = 'too many error responses' - SPECIFIC_ERROR = 'too many {status_code} error responses' - - -class SecurityWarning(HTTPWarning): - "Warned when perfoming security reducing actions" - pass - - -class SubjectAltNameWarning(SecurityWarning): - "Warned when connecting to a host with a certificate missing a SAN." - pass - - -class InsecureRequestWarning(SecurityWarning): - "Warned when making an unverified HTTPS request." - pass - - -class SystemTimeWarning(SecurityWarning): - "Warned when system time is suspected to be wrong" - pass - - -class InsecurePlatformWarning(SecurityWarning): - "Warned when certain SSL configuration is not available on a platform." - pass - - -class SNIMissingWarning(HTTPWarning): - "Warned when making a HTTPS request without SNI available." - pass - - -class DependencyWarning(HTTPWarning): - """ - Warned when an attempt is made to import a module with missing optional - dependencies. - """ - pass - - -class ResponseNotChunked(ProtocolError, ValueError): - "Response needs to be chunked in order to read it as chunks." - pass - - -class BodyNotHttplibCompatible(HTTPError): - """ - Body should be httplib.HTTPResponse like (have an fp attribute which - returns raw chunks) for read_chunked(). - """ - pass - - -class IncompleteRead(HTTPError, httplib_IncompleteRead): - """ - Response length doesn't match expected Content-Length - - Subclass of http_client.IncompleteRead to allow int value - for `partial` to avoid creating large objects on streamed - reads. - """ - def __init__(self, partial, expected): - super(IncompleteRead, self).__init__(partial, expected) - - def __repr__(self): - return ('IncompleteRead(%i bytes read, ' - '%i more expected)' % (self.partial, self.expected)) - - -class InvalidHeader(HTTPError): - "The header provided was somehow invalid." - pass - - -class ProxySchemeUnknown(AssertionError, ValueError): - "ProxyManager does not support the supplied scheme" - # TODO(t-8ch): Stop inheriting from AssertionError in v2.0. - - def __init__(self, scheme): - message = "Not supported proxy scheme %s" % scheme - super(ProxySchemeUnknown, self).__init__(message) - - -class HeaderParsingError(HTTPError): - "Raised by assert_header_parsing, but we convert it to a log.warning statement." - def __init__(self, defects, unparsed_data): - message = '%s, unparsed data: %r' % (defects or 'Unknown', unparsed_data) - super(HeaderParsingError, self).__init__(message) - - -class UnrewindableBodyError(HTTPError): - "urllib3 encountered an error when trying to rewind a body" - pass diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/fields.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/fields.py deleted file mode 100644 index 19b0ae0..0000000 --- a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/fields.py +++ /dev/null @@ -1,178 +0,0 @@ -from __future__ import absolute_import -import email.utils -import mimetypes - -from .packages import six - - -def guess_content_type(filename, default='application/octet-stream'): - """ - Guess the "Content-Type" of a file. - - :param filename: - The filename to guess the "Content-Type" of using :mod:`mimetypes`. - :param default: - If no "Content-Type" can be guessed, default to `default`. - """ - if filename: - return mimetypes.guess_type(filename)[0] or default - return default - - -def format_header_param(name, value): - """ - Helper function to format and quote a single header parameter. - - Particularly useful for header parameters which might contain - non-ASCII values, like file names. This follows RFC 2231, as - suggested by RFC 2388 Section 4.4. - - :param name: - The name of the parameter, a string expected to be ASCII only. - :param value: - The value of the parameter, provided as a unicode string. - """ - if not any(ch in value for ch in '"\\\r\n'): - result = '%s="%s"' % (name, value) - try: - result.encode('ascii') - except (UnicodeEncodeError, UnicodeDecodeError): - pass - else: - return result - if not six.PY3 and isinstance(value, six.text_type): # Python 2: - value = value.encode('utf-8') - value = email.utils.encode_rfc2231(value, 'utf-8') - value = '%s*=%s' % (name, value) - return value - - -class RequestField(object): - """ - A data container for request body parameters. - - :param name: - The name of this request field. - :param data: - The data/value body. - :param filename: - An optional filename of the request field. - :param headers: - An optional dict-like object of headers to initially use for the field. - """ - def __init__(self, name, data, filename=None, headers=None): - self._name = name - self._filename = filename - self.data = data - self.headers = {} - if headers: - self.headers = dict(headers) - - @classmethod - def from_tuples(cls, fieldname, value): - """ - A :class:`~urllib3.fields.RequestField` factory from old-style tuple parameters. - - Supports constructing :class:`~urllib3.fields.RequestField` from - parameter of key/value strings AND key/filetuple. A filetuple is a - (filename, data, MIME type) tuple where the MIME type is optional. - For example:: - - 'foo': 'bar', - 'fakefile': ('foofile.txt', 'contents of foofile'), - 'realfile': ('barfile.txt', open('realfile').read()), - 'typedfile': ('bazfile.bin', open('bazfile').read(), 'image/jpeg'), - 'nonamefile': 'contents of nonamefile field', - - Field names and filenames must be unicode. - """ - if isinstance(value, tuple): - if len(value) == 3: - filename, data, content_type = value - else: - filename, data = value - content_type = guess_content_type(filename) - else: - filename = None - content_type = None - data = value - - request_param = cls(fieldname, data, filename=filename) - request_param.make_multipart(content_type=content_type) - - return request_param - - def _render_part(self, name, value): - """ - Overridable helper function to format a single header parameter. - - :param name: - The name of the parameter, a string expected to be ASCII only. - :param value: - The value of the parameter, provided as a unicode string. - """ - return format_header_param(name, value) - - def _render_parts(self, header_parts): - """ - Helper function to format and quote a single header. - - Useful for single headers that are composed of multiple items. E.g., - 'Content-Disposition' fields. - - :param header_parts: - A sequence of (k, v) typles or a :class:`dict` of (k, v) to format - as `k1="v1"; k2="v2"; ...`. - """ - parts = [] - iterable = header_parts - if isinstance(header_parts, dict): - iterable = header_parts.items() - - for name, value in iterable: - if value is not None: - parts.append(self._render_part(name, value)) - - return '; '.join(parts) - - def render_headers(self): - """ - Renders the headers for this request field. - """ - lines = [] - - sort_keys = ['Content-Disposition', 'Content-Type', 'Content-Location'] - for sort_key in sort_keys: - if self.headers.get(sort_key, False): - lines.append('%s: %s' % (sort_key, self.headers[sort_key])) - - for header_name, header_value in self.headers.items(): - if header_name not in sort_keys: - if header_value: - lines.append('%s: %s' % (header_name, header_value)) - - lines.append('\r\n') - return '\r\n'.join(lines) - - def make_multipart(self, content_disposition=None, content_type=None, - content_location=None): - """ - Makes this request field into a multipart request field. - - This method overrides "Content-Disposition", "Content-Type" and - "Content-Location" headers to the request parameter. - - :param content_type: - The 'Content-Type' of the request body. - :param content_location: - The 'Content-Location' of the request body. - - """ - self.headers['Content-Disposition'] = content_disposition or 'form-data' - self.headers['Content-Disposition'] += '; '.join([ - '', self._render_parts( - (('name', self._name), ('filename', self._filename)) - ) - ]) - self.headers['Content-Type'] = content_type - self.headers['Content-Location'] = content_location diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/filepost.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/filepost.py deleted file mode 100644 index cd11cee..0000000 --- a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/filepost.py +++ /dev/null @@ -1,94 +0,0 @@ -from __future__ import absolute_import -import codecs - -from uuid import uuid4 -from io import BytesIO - -from .packages import six -from .packages.six import b -from .fields import RequestField - -writer = codecs.lookup('utf-8')[3] - - -def choose_boundary(): - """ - Our embarrassingly-simple replacement for mimetools.choose_boundary. - """ - return uuid4().hex - - -def iter_field_objects(fields): - """ - Iterate over fields. - - Supports list of (k, v) tuples and dicts, and lists of - :class:`~urllib3.fields.RequestField`. - - """ - if isinstance(fields, dict): - i = six.iteritems(fields) - else: - i = iter(fields) - - for field in i: - if isinstance(field, RequestField): - yield field - else: - yield RequestField.from_tuples(*field) - - -def iter_fields(fields): - """ - .. deprecated:: 1.6 - - Iterate over fields. - - The addition of :class:`~urllib3.fields.RequestField` makes this function - obsolete. Instead, use :func:`iter_field_objects`, which returns - :class:`~urllib3.fields.RequestField` objects. - - Supports list of (k, v) tuples and dicts. - """ - if isinstance(fields, dict): - return ((k, v) for k, v in six.iteritems(fields)) - - return ((k, v) for k, v in fields) - - -def encode_multipart_formdata(fields, boundary=None): - """ - Encode a dictionary of ``fields`` using the multipart/form-data MIME format. - - :param fields: - Dictionary of fields or list of (key, :class:`~urllib3.fields.RequestField`). - - :param boundary: - If not specified, then a random boundary will be generated using - :func:`mimetools.choose_boundary`. - """ - body = BytesIO() - if boundary is None: - boundary = choose_boundary() - - for field in iter_field_objects(fields): - body.write(b('--%s\r\n' % (boundary))) - - writer(body).write(field.render_headers()) - data = field.data - - if isinstance(data, int): - data = str(data) # Backwards compatibility - - if isinstance(data, six.text_type): - writer(body).write(data) - else: - body.write(data) - - body.write(b'\r\n') - - body.write(b('--%s--\r\n' % (boundary))) - - content_type = str('multipart/form-data; boundary=%s' % boundary) - - return body.getvalue(), content_type diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/__init__.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/__init__.py deleted file mode 100644 index 170e974..0000000 --- a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from __future__ import absolute_import - -from . import ssl_match_hostname - -__all__ = ('ssl_match_hostname', ) diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/backports/__init__.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/backports/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/backports/makefile.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/backports/makefile.py deleted file mode 100644 index 75b80dc..0000000 --- a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/backports/makefile.py +++ /dev/null @@ -1,53 +0,0 @@ -# -*- coding: utf-8 -*- -""" -backports.makefile -~~~~~~~~~~~~~~~~~~ - -Backports the Python 3 ``socket.makefile`` method for use with anything that -wants to create a "fake" socket object. -""" -import io - -from socket import SocketIO - - -def backport_makefile(self, mode="r", buffering=None, encoding=None, - errors=None, newline=None): - """ - Backport of ``socket.makefile`` from Python 3.5. - """ - if not set(mode) <= set(["r", "w", "b"]): - raise ValueError( - "invalid mode %r (only r, w, b allowed)" % (mode,) - ) - writing = "w" in mode - reading = "r" in mode or not writing - assert reading or writing - binary = "b" in mode - rawmode = "" - if reading: - rawmode += "r" - if writing: - rawmode += "w" - raw = SocketIO(self, rawmode) - self._makefile_refs += 1 - if buffering is None: - buffering = -1 - if buffering < 0: - buffering = io.DEFAULT_BUFFER_SIZE - if buffering == 0: - if not binary: - raise ValueError("unbuffered streams must be binary") - return raw - if reading and writing: - buffer = io.BufferedRWPair(raw, raw, buffering) - elif reading: - buffer = io.BufferedReader(raw, buffering) - else: - assert writing - buffer = io.BufferedWriter(raw, buffering) - if binary: - return buffer - text = io.TextIOWrapper(buffer, encoding, errors, newline) - text.mode = mode - return text diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/ordered_dict.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/ordered_dict.py deleted file mode 100644 index 4479363..0000000 --- a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/ordered_dict.py +++ /dev/null @@ -1,259 +0,0 @@ -# Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy. -# Passes Python2.7's test suite and incorporates all the latest updates. -# Copyright 2009 Raymond Hettinger, released under the MIT License. -# http://code.activestate.com/recipes/576693/ -try: - from thread import get_ident as _get_ident -except ImportError: - from dummy_thread import get_ident as _get_ident - -try: - from _abcoll import KeysView, ValuesView, ItemsView -except ImportError: - pass - - -class OrderedDict(dict): - 'Dictionary that remembers insertion order' - # An inherited dict maps keys to values. - # The inherited dict provides __getitem__, __len__, __contains__, and get. - # The remaining methods are order-aware. - # Big-O running times for all methods are the same as for regular dictionaries. - - # 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). - # Each link is stored as a list of length three: [PREV, NEXT, KEY]. - - def __init__(self, *args, **kwds): - '''Initialize an ordered dictionary. Signature is the same as for - regular dictionaries, but keyword arguments are not recommended - because their insertion order is arbitrary. - - ''' - if len(args) > 1: - raise TypeError('expected at most 1 arguments, got %d' % len(args)) - try: - self.__root - except AttributeError: - self.__root = root = [] # sentinel node - root[:] = [root, root, None] - self.__map = {} - self.__update(*args, **kwds) - - def __setitem__(self, key, value, dict_setitem=dict.__setitem__): - 'od.__setitem__(i, y) <==> od[i]=y' - # Setting a new item creates a new link which goes at the end of the linked - # list, and the inherited dictionary is updated with the new key/value pair. - if key not in self: - root = self.__root - last = root[0] - last[1] = root[0] = self.__map[key] = [last, root, key] - dict_setitem(self, key, value) - - def __delitem__(self, key, dict_delitem=dict.__delitem__): - 'od.__delitem__(y) <==> del od[y]' - # Deleting an existing item uses self.__map to find the link which is - # then removed by updating the links in the predecessor and successor nodes. - dict_delitem(self, key) - link_prev, link_next, key = self.__map.pop(key) - link_prev[1] = link_next - link_next[0] = link_prev - - def __iter__(self): - 'od.__iter__() <==> iter(od)' - root = self.__root - curr = root[1] - while curr is not root: - yield curr[2] - curr = curr[1] - - def __reversed__(self): - 'od.__reversed__() <==> reversed(od)' - root = self.__root - curr = root[0] - while curr is not root: - yield curr[2] - curr = curr[0] - - def clear(self): - 'od.clear() -> None. Remove all items from od.' - try: - for node in self.__map.itervalues(): - del node[:] - root = self.__root - root[:] = [root, root, None] - self.__map.clear() - except AttributeError: - pass - dict.clear(self) - - def popitem(self, last=True): - '''od.popitem() -> (k, v), return and remove a (key, value) pair. - Pairs are returned in LIFO order if last is true or FIFO order if false. - - ''' - if not self: - raise KeyError('dictionary is empty') - root = self.__root - if last: - link = root[0] - link_prev = link[0] - link_prev[1] = root - root[0] = link_prev - else: - link = root[1] - link_next = link[1] - root[1] = link_next - link_next[0] = root - key = link[2] - del self.__map[key] - value = dict.pop(self, key) - return key, value - - # -- the following methods do not depend on the internal structure -- - - def keys(self): - 'od.keys() -> list of keys in od' - return list(self) - - def values(self): - 'od.values() -> list of values in od' - return [self[key] for key in self] - - def items(self): - 'od.items() -> list of (key, value) pairs in od' - return [(key, self[key]) for key in self] - - def iterkeys(self): - 'od.iterkeys() -> an iterator over the keys in od' - return iter(self) - - def itervalues(self): - 'od.itervalues -> an iterator over the values in od' - for k in self: - yield self[k] - - def iteritems(self): - 'od.iteritems -> an iterator over the (key, value) items in od' - for k in self: - yield (k, self[k]) - - def update(*args, **kwds): - '''od.update(E, **F) -> None. Update od from dict/iterable E and F. - - If E is a dict instance, does: for k in E: od[k] = E[k] - If E has a .keys() method, does: for k in E.keys(): od[k] = E[k] - Or if E is an iterable of items, does: for k, v in E: od[k] = v - In either case, this is followed by: for k, v in F.items(): od[k] = v - - ''' - if len(args) > 2: - raise TypeError('update() takes at most 2 positional ' - 'arguments (%d given)' % (len(args),)) - elif not args: - raise TypeError('update() takes at least 1 argument (0 given)') - self = args[0] - # Make progressively weaker assumptions about "other" - other = () - if len(args) == 2: - other = args[1] - if isinstance(other, dict): - for key in other: - self[key] = other[key] - elif hasattr(other, 'keys'): - for key in other.keys(): - self[key] = other[key] - else: - for key, value in other: - self[key] = value - for key, value in kwds.items(): - self[key] = value - - __update = update # let subclasses override update without breaking __init__ - - __marker = object() - - def pop(self, key, default=__marker): - '''od.pop(k[,d]) -> v, remove specified key and return the corresponding value. - If key is not found, d is returned if given, otherwise KeyError is raised. - - ''' - if key in self: - result = self[key] - del self[key] - return result - if default is self.__marker: - raise KeyError(key) - return default - - def setdefault(self, key, default=None): - 'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od' - if key in self: - return self[key] - self[key] = default - return default - - def __repr__(self, _repr_running={}): - 'od.__repr__() <==> repr(od)' - call_key = id(self), _get_ident() - if call_key in _repr_running: - return '...' - _repr_running[call_key] = 1 - try: - if not self: - return '%s()' % (self.__class__.__name__,) - return '%s(%r)' % (self.__class__.__name__, self.items()) - finally: - del _repr_running[call_key] - - def __reduce__(self): - 'Return state information for pickling' - items = [[k, self[k]] for k in self] - inst_dict = vars(self).copy() - for k in vars(OrderedDict()): - inst_dict.pop(k, None) - if inst_dict: - return (self.__class__, (items,), inst_dict) - return self.__class__, (items,) - - def copy(self): - 'od.copy() -> a shallow copy of od' - return self.__class__(self) - - @classmethod - def fromkeys(cls, iterable, value=None): - '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S - and values equal to v (which defaults to None). - - ''' - d = cls() - for key in iterable: - d[key] = value - return d - - def __eq__(self, other): - '''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive - while comparison to a regular mapping is order-insensitive. - - ''' - if isinstance(other, OrderedDict): - return len(self)==len(other) and self.items() == other.items() - return dict.__eq__(self, other) - - def __ne__(self, other): - return not self == other - - # -- the following methods are only used in Python 2.7 -- - - def viewkeys(self): - "od.viewkeys() -> a set-like object providing a view on od's keys" - return KeysView(self) - - def viewvalues(self): - "od.viewvalues() -> an object providing a view on od's values" - return ValuesView(self) - - def viewitems(self): - "od.viewitems() -> a set-like object providing a view on od's items" - return ItemsView(self) diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/six.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/six.py deleted file mode 100644 index 190c023..0000000 --- a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/six.py +++ /dev/null @@ -1,868 +0,0 @@ -"""Utilities for writing code that runs on Python 2 and 3""" - -# Copyright (c) 2010-2015 Benjamin Peterson -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -from __future__ import absolute_import - -import functools -import itertools -import operator -import sys -import types - -__author__ = "Benjamin Peterson <benjamin@python.org>" -__version__ = "1.10.0" - - -# Useful for very coarse version differentiation. -PY2 = sys.version_info[0] == 2 -PY3 = sys.version_info[0] == 3 -PY34 = sys.version_info[0:2] >= (3, 4) - -if PY3: - string_types = str, - integer_types = int, - class_types = type, - text_type = str - binary_type = bytes - - MAXSIZE = sys.maxsize -else: - string_types = basestring, - integer_types = (int, long) - class_types = (type, types.ClassType) - text_type = unicode - binary_type = str - - if sys.platform.startswith("java"): - # Jython always uses 32 bits. - MAXSIZE = int((1 << 31) - 1) - else: - # It's possible to have sizeof(long) != sizeof(Py_ssize_t). - class X(object): - - def __len__(self): - return 1 << 31 - try: - len(X()) - except OverflowError: - # 32-bit - MAXSIZE = int((1 << 31) - 1) - else: - # 64-bit - MAXSIZE = int((1 << 63) - 1) - del X - - -def _add_doc(func, doc): - """Add documentation to a function.""" - func.__doc__ = doc - - -def _import_module(name): - """Import module, returning the module after the last dot.""" - __import__(name) - return sys.modules[name] - - -class _LazyDescr(object): - - def __init__(self, name): - self.name = name - - def __get__(self, obj, tp): - result = self._resolve() - setattr(obj, self.name, result) # Invokes __set__. - try: - # This is a bit ugly, but it avoids running this again by - # removing this descriptor. - delattr(obj.__class__, self.name) - except AttributeError: - pass - return result - - -class MovedModule(_LazyDescr): - - def __init__(self, name, old, new=None): - super(MovedModule, self).__init__(name) - if PY3: - if new is None: - new = name - self.mod = new - else: - self.mod = old - - def _resolve(self): - return _import_module(self.mod) - - def __getattr__(self, attr): - _module = self._resolve() - value = getattr(_module, attr) - setattr(self, attr, value) - return value - - -class _LazyModule(types.ModuleType): - - def __init__(self, name): - super(_LazyModule, self).__init__(name) - self.__doc__ = self.__class__.__doc__ - - def __dir__(self): - attrs = ["__doc__", "__name__"] - attrs += [attr.name for attr in self._moved_attributes] - return attrs - - # Subclasses should override this - _moved_attributes = [] - - -class MovedAttribute(_LazyDescr): - - def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None): - super(MovedAttribute, self).__init__(name) - if PY3: - if new_mod is None: - new_mod = name - self.mod = new_mod - if new_attr is None: - if old_attr is None: - new_attr = name - else: - new_attr = old_attr - self.attr = new_attr - else: - self.mod = old_mod - if old_attr is None: - old_attr = name - self.attr = old_attr - - def _resolve(self): - module = _import_module(self.mod) - return getattr(module, self.attr) - - -class _SixMetaPathImporter(object): - - """ - A meta path importer to import six.moves and its submodules. - - This class implements a PEP302 finder and loader. It should be compatible - with Python 2.5 and all existing versions of Python3 - """ - - def __init__(self, six_module_name): - self.name = six_module_name - self.known_modules = {} - - def _add_module(self, mod, *fullnames): - for fullname in fullnames: - self.known_modules[self.name + "." + fullname] = mod - - def _get_module(self, fullname): - return self.known_modules[self.name + "." + fullname] - - def find_module(self, fullname, path=None): - if fullname in self.known_modules: - return self - return None - - def __get_module(self, fullname): - try: - return self.known_modules[fullname] - except KeyError: - raise ImportError("This loader does not know module " + fullname) - - def load_module(self, fullname): - try: - # in case of a reload - return sys.modules[fullname] - except KeyError: - pass - mod = self.__get_module(fullname) - if isinstance(mod, MovedModule): - mod = mod._resolve() - else: - mod.__loader__ = self - sys.modules[fullname] = mod - return mod - - def is_package(self, fullname): - """ - Return true, if the named module is a package. - - We need this method to get correct spec objects with - Python 3.4 (see PEP451) - """ - return hasattr(self.__get_module(fullname), "__path__") - - def get_code(self, fullname): - """Return None - - Required, if is_package is implemented""" - self.__get_module(fullname) # eventually raises ImportError - return None - get_source = get_code # same as get_code - -_importer = _SixMetaPathImporter(__name__) - - -class _MovedItems(_LazyModule): - - """Lazy loading of moved objects""" - __path__ = [] # mark as package - - -_moved_attributes = [ - MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"), - MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"), - MovedAttribute("filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"), - MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"), - MovedAttribute("intern", "__builtin__", "sys"), - MovedAttribute("map", "itertools", "builtins", "imap", "map"), - MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"), - MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"), - MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"), - MovedAttribute("reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload"), - MovedAttribute("reduce", "__builtin__", "functools"), - MovedAttribute("shlex_quote", "pipes", "shlex", "quote"), - MovedAttribute("StringIO", "StringIO", "io"), - MovedAttribute("UserDict", "UserDict", "collections"), - MovedAttribute("UserList", "UserList", "collections"), - MovedAttribute("UserString", "UserString", "collections"), - MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"), - MovedAttribute("zip", "itertools", "builtins", "izip", "zip"), - MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"), - MovedModule("builtins", "__builtin__"), - MovedModule("configparser", "ConfigParser"), - MovedModule("copyreg", "copy_reg"), - MovedModule("dbm_gnu", "gdbm", "dbm.gnu"), - MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread"), - MovedModule("http_cookiejar", "cookielib", "http.cookiejar"), - MovedModule("http_cookies", "Cookie", "http.cookies"), - MovedModule("html_entities", "htmlentitydefs", "html.entities"), - MovedModule("html_parser", "HTMLParser", "html.parser"), - MovedModule("http_client", "httplib", "http.client"), - MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"), - MovedModule("email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart"), - MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"), - MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"), - MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"), - MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"), - MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"), - MovedModule("cPickle", "cPickle", "pickle"), - MovedModule("queue", "Queue"), - MovedModule("reprlib", "repr"), - MovedModule("socketserver", "SocketServer"), - MovedModule("_thread", "thread", "_thread"), - MovedModule("tkinter", "Tkinter"), - MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"), - MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"), - MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"), - MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"), - MovedModule("tkinter_tix", "Tix", "tkinter.tix"), - MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"), - MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"), - MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"), - MovedModule("tkinter_colorchooser", "tkColorChooser", - "tkinter.colorchooser"), - MovedModule("tkinter_commondialog", "tkCommonDialog", - "tkinter.commondialog"), - MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"), - MovedModule("tkinter_font", "tkFont", "tkinter.font"), - MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"), - MovedModule("tkinter_tksimpledialog", "tkSimpleDialog", - "tkinter.simpledialog"), - MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"), - MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"), - MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"), - MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"), - MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"), - MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"), -] -# Add windows specific modules. -if sys.platform == "win32": - _moved_attributes += [ - MovedModule("winreg", "_winreg"), - ] - -for attr in _moved_attributes: - setattr(_MovedItems, attr.name, attr) - if isinstance(attr, MovedModule): - _importer._add_module(attr, "moves." + attr.name) -del attr - -_MovedItems._moved_attributes = _moved_attributes - -moves = _MovedItems(__name__ + ".moves") -_importer._add_module(moves, "moves") - - -class Module_six_moves_urllib_parse(_LazyModule): - - """Lazy loading of moved objects in six.moves.urllib_parse""" - - -_urllib_parse_moved_attributes = [ - MovedAttribute("ParseResult", "urlparse", "urllib.parse"), - MovedAttribute("SplitResult", "urlparse", "urllib.parse"), - MovedAttribute("parse_qs", "urlparse", "urllib.parse"), - MovedAttribute("parse_qsl", "urlparse", "urllib.parse"), - MovedAttribute("urldefrag", "urlparse", "urllib.parse"), - MovedAttribute("urljoin", "urlparse", "urllib.parse"), - MovedAttribute("urlparse", "urlparse", "urllib.parse"), - MovedAttribute("urlsplit", "urlparse", "urllib.parse"), - MovedAttribute("urlunparse", "urlparse", "urllib.parse"), - MovedAttribute("urlunsplit", "urlparse", "urllib.parse"), - MovedAttribute("quote", "urllib", "urllib.parse"), - MovedAttribute("quote_plus", "urllib", "urllib.parse"), - MovedAttribute("unquote", "urllib", "urllib.parse"), - MovedAttribute("unquote_plus", "urllib", "urllib.parse"), - MovedAttribute("urlencode", "urllib", "urllib.parse"), - MovedAttribute("splitquery", "urllib", "urllib.parse"), - MovedAttribute("splittag", "urllib", "urllib.parse"), - MovedAttribute("splituser", "urllib", "urllib.parse"), - MovedAttribute("uses_fragment", "urlparse", "urllib.parse"), - MovedAttribute("uses_netloc", "urlparse", "urllib.parse"), - MovedAttribute("uses_params", "urlparse", "urllib.parse"), - MovedAttribute("uses_query", "urlparse", "urllib.parse"), - MovedAttribute("uses_relative", "urlparse", "urllib.parse"), -] -for attr in _urllib_parse_moved_attributes: - setattr(Module_six_moves_urllib_parse, attr.name, attr) -del attr - -Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes - -_importer._add_module(Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"), - "moves.urllib_parse", "moves.urllib.parse") - - -class Module_six_moves_urllib_error(_LazyModule): - - """Lazy loading of moved objects in six.moves.urllib_error""" - - -_urllib_error_moved_attributes = [ - MovedAttribute("URLError", "urllib2", "urllib.error"), - MovedAttribute("HTTPError", "urllib2", "urllib.error"), - MovedAttribute("ContentTooShortError", "urllib", "urllib.error"), -] -for attr in _urllib_error_moved_attributes: - setattr(Module_six_moves_urllib_error, attr.name, attr) -del attr - -Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes - -_importer._add_module(Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"), - "moves.urllib_error", "moves.urllib.error") - - -class Module_six_moves_urllib_request(_LazyModule): - - """Lazy loading of moved objects in six.moves.urllib_request""" - - -_urllib_request_moved_attributes = [ - MovedAttribute("urlopen", "urllib2", "urllib.request"), - MovedAttribute("install_opener", "urllib2", "urllib.request"), - MovedAttribute("build_opener", "urllib2", "urllib.request"), - MovedAttribute("pathname2url", "urllib", "urllib.request"), - MovedAttribute("url2pathname", "urllib", "urllib.request"), - MovedAttribute("getproxies", "urllib", "urllib.request"), - MovedAttribute("Request", "urllib2", "urllib.request"), - MovedAttribute("OpenerDirector", "urllib2", "urllib.request"), - MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"), - MovedAttribute("ProxyHandler", "urllib2", "urllib.request"), - MovedAttribute("BaseHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"), - MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"), - MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"), - MovedAttribute("FileHandler", "urllib2", "urllib.request"), - MovedAttribute("FTPHandler", "urllib2", "urllib.request"), - MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"), - MovedAttribute("UnknownHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"), - MovedAttribute("urlretrieve", "urllib", "urllib.request"), - MovedAttribute("urlcleanup", "urllib", "urllib.request"), - MovedAttribute("URLopener", "urllib", "urllib.request"), - MovedAttribute("FancyURLopener", "urllib", "urllib.request"), - MovedAttribute("proxy_bypass", "urllib", "urllib.request"), -] -for attr in _urllib_request_moved_attributes: - setattr(Module_six_moves_urllib_request, attr.name, attr) -del attr - -Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes - -_importer._add_module(Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"), - "moves.urllib_request", "moves.urllib.request") - - -class Module_six_moves_urllib_response(_LazyModule): - - """Lazy loading of moved objects in six.moves.urllib_response""" - - -_urllib_response_moved_attributes = [ - MovedAttribute("addbase", "urllib", "urllib.response"), - MovedAttribute("addclosehook", "urllib", "urllib.response"), - MovedAttribute("addinfo", "urllib", "urllib.response"), - MovedAttribute("addinfourl", "urllib", "urllib.response"), -] -for attr in _urllib_response_moved_attributes: - setattr(Module_six_moves_urllib_response, attr.name, attr) -del attr - -Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes - -_importer._add_module(Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"), - "moves.urllib_response", "moves.urllib.response") - - -class Module_six_moves_urllib_robotparser(_LazyModule): - - """Lazy loading of moved objects in six.moves.urllib_robotparser""" - - -_urllib_robotparser_moved_attributes = [ - MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"), -] -for attr in _urllib_robotparser_moved_attributes: - setattr(Module_six_moves_urllib_robotparser, attr.name, attr) -del attr - -Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes - -_importer._add_module(Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"), - "moves.urllib_robotparser", "moves.urllib.robotparser") - - -class Module_six_moves_urllib(types.ModuleType): - - """Create a six.moves.urllib namespace that resembles the Python 3 namespace""" - __path__ = [] # mark as package - parse = _importer._get_module("moves.urllib_parse") - error = _importer._get_module("moves.urllib_error") - request = _importer._get_module("moves.urllib_request") - response = _importer._get_module("moves.urllib_response") - robotparser = _importer._get_module("moves.urllib_robotparser") - - def __dir__(self): - return ['parse', 'error', 'request', 'response', 'robotparser'] - -_importer._add_module(Module_six_moves_urllib(__name__ + ".moves.urllib"), - "moves.urllib") - - -def add_move(move): - """Add an item to six.moves.""" - setattr(_MovedItems, move.name, move) - - -def remove_move(name): - """Remove item from six.moves.""" - try: - delattr(_MovedItems, name) - except AttributeError: - try: - del moves.__dict__[name] - except KeyError: - raise AttributeError("no such move, %r" % (name,)) - - -if PY3: - _meth_func = "__func__" - _meth_self = "__self__" - - _func_closure = "__closure__" - _func_code = "__code__" - _func_defaults = "__defaults__" - _func_globals = "__globals__" -else: - _meth_func = "im_func" - _meth_self = "im_self" - - _func_closure = "func_closure" - _func_code = "func_code" - _func_defaults = "func_defaults" - _func_globals = "func_globals" - - -try: - advance_iterator = next -except NameError: - def advance_iterator(it): - return it.next() -next = advance_iterator - - -try: - callable = callable -except NameError: - def callable(obj): - return any("__call__" in klass.__dict__ for klass in type(obj).__mro__) - - -if PY3: - def get_unbound_function(unbound): - return unbound - - create_bound_method = types.MethodType - - def create_unbound_method(func, cls): - return func - - Iterator = object -else: - def get_unbound_function(unbound): - return unbound.im_func - - def create_bound_method(func, obj): - return types.MethodType(func, obj, obj.__class__) - - def create_unbound_method(func, cls): - return types.MethodType(func, None, cls) - - class Iterator(object): - - def next(self): - return type(self).__next__(self) - - callable = callable -_add_doc(get_unbound_function, - """Get the function out of a possibly unbound function""") - - -get_method_function = operator.attrgetter(_meth_func) -get_method_self = operator.attrgetter(_meth_self) -get_function_closure = operator.attrgetter(_func_closure) -get_function_code = operator.attrgetter(_func_code) -get_function_defaults = operator.attrgetter(_func_defaults) -get_function_globals = operator.attrgetter(_func_globals) - - -if PY3: - def iterkeys(d, **kw): - return iter(d.keys(**kw)) - - def itervalues(d, **kw): - return iter(d.values(**kw)) - - def iteritems(d, **kw): - return iter(d.items(**kw)) - - def iterlists(d, **kw): - return iter(d.lists(**kw)) - - viewkeys = operator.methodcaller("keys") - - viewvalues = operator.methodcaller("values") - - viewitems = operator.methodcaller("items") -else: - def iterkeys(d, **kw): - return d.iterkeys(**kw) - - def itervalues(d, **kw): - return d.itervalues(**kw) - - def iteritems(d, **kw): - return d.iteritems(**kw) - - def iterlists(d, **kw): - return d.iterlists(**kw) - - viewkeys = operator.methodcaller("viewkeys") - - viewvalues = operator.methodcaller("viewvalues") - - viewitems = operator.methodcaller("viewitems") - -_add_doc(iterkeys, "Return an iterator over the keys of a dictionary.") -_add_doc(itervalues, "Return an iterator over the values of a dictionary.") -_add_doc(iteritems, - "Return an iterator over the (key, value) pairs of a dictionary.") -_add_doc(iterlists, - "Return an iterator over the (key, [values]) pairs of a dictionary.") - - -if PY3: - def b(s): - return s.encode("latin-1") - - def u(s): - return s - unichr = chr - import struct - int2byte = struct.Struct(">B").pack - del struct - byte2int = operator.itemgetter(0) - indexbytes = operator.getitem - iterbytes = iter - import io - StringIO = io.StringIO - BytesIO = io.BytesIO - _assertCountEqual = "assertCountEqual" - if sys.version_info[1] <= 1: - _assertRaisesRegex = "assertRaisesRegexp" - _assertRegex = "assertRegexpMatches" - else: - _assertRaisesRegex = "assertRaisesRegex" - _assertRegex = "assertRegex" -else: - def b(s): - return s - # Workaround for standalone backslash - - def u(s): - return unicode(s.replace(r'\\', r'\\\\'), "unicode_escape") - unichr = unichr - int2byte = chr - - def byte2int(bs): - return ord(bs[0]) - - def indexbytes(buf, i): - return ord(buf[i]) - iterbytes = functools.partial(itertools.imap, ord) - import StringIO - StringIO = BytesIO = StringIO.StringIO - _assertCountEqual = "assertItemsEqual" - _assertRaisesRegex = "assertRaisesRegexp" - _assertRegex = "assertRegexpMatches" -_add_doc(b, """Byte literal""") -_add_doc(u, """Text literal""") - - -def assertCountEqual(self, *args, **kwargs): - return getattr(self, _assertCountEqual)(*args, **kwargs) - - -def assertRaisesRegex(self, *args, **kwargs): - return getattr(self, _assertRaisesRegex)(*args, **kwargs) - - -def assertRegex(self, *args, **kwargs): - return getattr(self, _assertRegex)(*args, **kwargs) - - -if PY3: - exec_ = getattr(moves.builtins, "exec") - - def reraise(tp, value, tb=None): - if value is None: - value = tp() - if value.__traceback__ is not tb: - raise value.with_traceback(tb) - raise value - -else: - def exec_(_code_, _globs_=None, _locs_=None): - """Execute code in a namespace.""" - if _globs_ is None: - frame = sys._getframe(1) - _globs_ = frame.f_globals - if _locs_ is None: - _locs_ = frame.f_locals - del frame - elif _locs_ is None: - _locs_ = _globs_ - exec("""exec _code_ in _globs_, _locs_""") - - exec_("""def reraise(tp, value, tb=None): - raise tp, value, tb -""") - - -if sys.version_info[:2] == (3, 2): - exec_("""def raise_from(value, from_value): - if from_value is None: - raise value - raise value from from_value -""") -elif sys.version_info[:2] > (3, 2): - exec_("""def raise_from(value, from_value): - raise value from from_value -""") -else: - def raise_from(value, from_value): - raise value - - -print_ = getattr(moves.builtins, "print", None) -if print_ is None: - def print_(*args, **kwargs): - """The new-style print function for Python 2.4 and 2.5.""" - fp = kwargs.pop("file", sys.stdout) - if fp is None: - return - - def write(data): - if not isinstance(data, basestring): - data = str(data) - # If the file has an encoding, encode unicode with it. - if (isinstance(fp, file) and - isinstance(data, unicode) and - fp.encoding is not None): - errors = getattr(fp, "errors", None) - if errors is None: - errors = "strict" - data = data.encode(fp.encoding, errors) - fp.write(data) - want_unicode = False - sep = kwargs.pop("sep", None) - if sep is not None: - if isinstance(sep, unicode): - want_unicode = True - elif not isinstance(sep, str): - raise TypeError("sep must be None or a string") - end = kwargs.pop("end", None) - if end is not None: - if isinstance(end, unicode): - want_unicode = True - elif not isinstance(end, str): - raise TypeError("end must be None or a string") - if kwargs: - raise TypeError("invalid keyword arguments to print()") - if not want_unicode: - for arg in args: - if isinstance(arg, unicode): - want_unicode = True - break - if want_unicode: - newline = unicode("\n") - space = unicode(" ") - else: - newline = "\n" - space = " " - if sep is None: - sep = space - if end is None: - end = newline - for i, arg in enumerate(args): - if i: - write(sep) - write(arg) - write(end) -if sys.version_info[:2] < (3, 3): - _print = print_ - - def print_(*args, **kwargs): - fp = kwargs.get("file", sys.stdout) - flush = kwargs.pop("flush", False) - _print(*args, **kwargs) - if flush and fp is not None: - fp.flush() - -_add_doc(reraise, """Reraise an exception.""") - -if sys.version_info[0:2] < (3, 4): - def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS, - updated=functools.WRAPPER_UPDATES): - def wrapper(f): - f = functools.wraps(wrapped, assigned, updated)(f) - f.__wrapped__ = wrapped - return f - return wrapper -else: - wraps = functools.wraps - - -def with_metaclass(meta, *bases): - """Create a base class with a metaclass.""" - # This requires a bit of explanation: the basic idea is to make a dummy - # metaclass for one level of class instantiation that replaces itself with - # the actual metaclass. - class metaclass(meta): - - def __new__(cls, name, this_bases, d): - return meta(name, bases, d) - return type.__new__(metaclass, 'temporary_class', (), {}) - - -def add_metaclass(metaclass): - """Class decorator for creating a class with a metaclass.""" - def wrapper(cls): - orig_vars = cls.__dict__.copy() - slots = orig_vars.get('__slots__') - if slots is not None: - if isinstance(slots, str): - slots = [slots] - for slots_var in slots: - orig_vars.pop(slots_var) - orig_vars.pop('__dict__', None) - orig_vars.pop('__weakref__', None) - return metaclass(cls.__name__, cls.__bases__, orig_vars) - return wrapper - - -def python_2_unicode_compatible(klass): - """ - A decorator that defines __unicode__ and __str__ methods under Python 2. - Under Python 3 it does nothing. - - To support Python 2 and 3 with a single code base, define a __str__ method - returning text and apply this decorator to the class. - """ - if PY2: - if '__str__' not in klass.__dict__: - raise ValueError("@python_2_unicode_compatible cannot be applied " - "to %s because it doesn't define __str__()." % - klass.__name__) - klass.__unicode__ = klass.__str__ - klass.__str__ = lambda self: self.__unicode__().encode('utf-8') - return klass - - -# Complete the moves implementation. -# This code is at the end of this module to speed up module loading. -# Turn this module into a package. -__path__ = [] # required for PEP 302 and PEP 451 -__package__ = __name__ # see PEP 366 @ReservedAssignment -if globals().get("__spec__") is not None: - __spec__.submodule_search_locations = [] # PEP 451 @UndefinedVariable -# Remove other six meta path importers, since they cause problems. This can -# happen if six is removed from sys.modules and then reloaded. (Setuptools does -# this for some reason.) -if sys.meta_path: - for i, importer in enumerate(sys.meta_path): - # Here's some real nastiness: Another "instance" of the six module might - # be floating around. Therefore, we can't use isinstance() to check for - # the six meta path importer, since the other six instance will have - # inserted an importer with different class. - if (type(importer).__name__ == "_SixMetaPathImporter" and - importer.name == __name__): - del sys.meta_path[i] - break - del i, importer -# Finally, add the importer to the meta path import hook. -sys.meta_path.append(_importer) diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/ssl_match_hostname/__init__.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/ssl_match_hostname/__init__.py deleted file mode 100644 index d6594eb..0000000 --- a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/ssl_match_hostname/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -import sys - -try: - # Our match_hostname function is the same as 3.5's, so we only want to - # import the match_hostname function if it's at least that good. - if sys.version_info < (3, 5): - raise ImportError("Fallback to vendored code") - - from ssl import CertificateError, match_hostname -except ImportError: - try: - # Backport of the function from a pypi module - from backports.ssl_match_hostname import CertificateError, match_hostname - except ImportError: - # Our vendored copy - from ._implementation import CertificateError, match_hostname - -# Not needed, but documenting what we provide. -__all__ = ('CertificateError', 'match_hostname') diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/ssl_match_hostname/_implementation.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/ssl_match_hostname/_implementation.py deleted file mode 100644 index 1fd42f3..0000000 --- a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/packages/ssl_match_hostname/_implementation.py +++ /dev/null @@ -1,157 +0,0 @@ -"""The match_hostname() function from Python 3.3.3, essential when using SSL.""" - -# Note: This file is under the PSF license as the code comes from the python -# stdlib. http://docs.python.org/3/license.html - -import re -import sys - -# ipaddress has been backported to 2.6+ in pypi. If it is installed on the -# system, use it to handle IPAddress ServerAltnames (this was added in -# python-3.5) otherwise only do DNS matching. This allows -# backports.ssl_match_hostname to continue to be used all the way back to -# python-2.4. -try: - import ipaddress -except ImportError: - ipaddress = None - -__version__ = '3.5.0.1' - - -class CertificateError(ValueError): - pass - - -def _dnsname_match(dn, hostname, max_wildcards=1): - """Matching according to RFC 6125, section 6.4.3 - - http://tools.ietf.org/html/rfc6125#section-6.4.3 - """ - pats = [] - if not dn: - return False - - # Ported from python3-syntax: - # leftmost, *remainder = dn.split(r'.') - parts = dn.split(r'.') - leftmost = parts[0] - remainder = parts[1:] - - wildcards = leftmost.count('*') - if wildcards > max_wildcards: - # Issue #17980: avoid denials of service by refusing more - # than one wildcard per fragment. A survey of established - # policy among SSL implementations showed it to be a - # reasonable choice. - raise CertificateError( - "too many wildcards in certificate DNS name: " + repr(dn)) - - # speed up common case w/o wildcards - if not wildcards: - return dn.lower() == hostname.lower() - - # RFC 6125, section 6.4.3, subitem 1. - # The client SHOULD NOT attempt to match a presented identifier in which - # the wildcard character comprises a label other than the left-most label. - if leftmost == '*': - # When '*' is a fragment by itself, it matches a non-empty dotless - # fragment. - pats.append('[^.]+') - elif leftmost.startswith('xn--') or hostname.startswith('xn--'): - # RFC 6125, section 6.4.3, subitem 3. - # The client SHOULD NOT attempt to match a presented identifier - # where the wildcard character is embedded within an A-label or - # U-label of an internationalized domain name. - pats.append(re.escape(leftmost)) - else: - # Otherwise, '*' matches any dotless string, e.g. www* - pats.append(re.escape(leftmost).replace(r'\*', '[^.]*')) - - # add the remaining fragments, ignore any wildcards - for frag in remainder: - pats.append(re.escape(frag)) - - pat = re.compile(r'\A' + r'\.'.join(pats) + r'\Z', re.IGNORECASE) - return pat.match(hostname) - - -def _to_unicode(obj): - if isinstance(obj, str) and sys.version_info < (3,): - obj = unicode(obj, encoding='ascii', errors='strict') - return obj - -def _ipaddress_match(ipname, host_ip): - """Exact matching of IP addresses. - - RFC 6125 explicitly doesn't define an algorithm for this - (section 1.7.2 - "Out of Scope"). - """ - # OpenSSL may add a trailing newline to a subjectAltName's IP address - # Divergence from upstream: ipaddress can't handle byte str - ip = ipaddress.ip_address(_to_unicode(ipname).rstrip()) - return ip == host_ip - - -def match_hostname(cert, hostname): - """Verify that *cert* (in decoded format as returned by - SSLSocket.getpeercert()) matches the *hostname*. RFC 2818 and RFC 6125 - rules are followed, but IP addresses are not accepted for *hostname*. - - CertificateError is raised on failure. On success, the function - returns nothing. - """ - if not cert: - raise ValueError("empty or no certificate, match_hostname needs a " - "SSL socket or SSL context with either " - "CERT_OPTIONAL or CERT_REQUIRED") - try: - # Divergence from upstream: ipaddress can't handle byte str - host_ip = ipaddress.ip_address(_to_unicode(hostname)) - except ValueError: - # Not an IP address (common case) - host_ip = None - except UnicodeError: - # Divergence from upstream: Have to deal with ipaddress not taking - # byte strings. addresses should be all ascii, so we consider it not - # an ipaddress in this case - host_ip = None - except AttributeError: - # Divergence from upstream: Make ipaddress library optional - if ipaddress is None: - host_ip = None - else: - raise - dnsnames = [] - san = cert.get('subjectAltName', ()) - for key, value in san: - if key == 'DNS': - if host_ip is None and _dnsname_match(value, hostname): - return - dnsnames.append(value) - elif key == 'IP Address': - if host_ip is not None and _ipaddress_match(value, host_ip): - return - dnsnames.append(value) - if not dnsnames: - # The subject is only checked when there is no dNSName entry - # in subjectAltName - for sub in cert.get('subject', ()): - for key, value in sub: - # XXX according to RFC 2818, the most specific Common Name - # must be used. - if key == 'commonName': - if _dnsname_match(value, hostname): - return - dnsnames.append(value) - if len(dnsnames) > 1: - raise CertificateError("hostname %r " - "doesn't match either of %s" - % (hostname, ', '.join(map(repr, dnsnames)))) - elif len(dnsnames) == 1: - raise CertificateError("hostname %r " - "doesn't match %r" - % (hostname, dnsnames[0])) - else: - raise CertificateError("no appropriate commonName or " - "subjectAltName fields were found") diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/poolmanager.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/poolmanager.py deleted file mode 100644 index cc5a00e..0000000 --- a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/poolmanager.py +++ /dev/null @@ -1,363 +0,0 @@ -from __future__ import absolute_import -import collections -import functools -import logging - -from ._collections import RecentlyUsedContainer -from .connectionpool import HTTPConnectionPool, HTTPSConnectionPool -from .connectionpool import port_by_scheme -from .exceptions import LocationValueError, MaxRetryError, ProxySchemeUnknown -from .packages.six.moves.urllib.parse import urljoin -from .request import RequestMethods -from .util.url import parse_url -from .util.retry import Retry - - -__all__ = ['PoolManager', 'ProxyManager', 'proxy_from_url'] - - -log = logging.getLogger(__name__) - -SSL_KEYWORDS = ('key_file', 'cert_file', 'cert_reqs', 'ca_certs', - 'ssl_version', 'ca_cert_dir', 'ssl_context') - -# The base fields to use when determining what pool to get a connection from; -# these do not rely on the ``connection_pool_kw`` and can be determined by the -# URL and potentially the ``urllib3.connection.port_by_scheme`` dictionary. -# -# All custom key schemes should include the fields in this key at a minimum. -BasePoolKey = collections.namedtuple('BasePoolKey', ('scheme', 'host', 'port')) - -# The fields to use when determining what pool to get a HTTP and HTTPS -# connection from. All additional fields must be present in the PoolManager's -# ``connection_pool_kw`` instance variable. -HTTPPoolKey = collections.namedtuple( - 'HTTPPoolKey', BasePoolKey._fields + ('timeout', 'retries', 'strict', - 'block', 'source_address') -) -HTTPSPoolKey = collections.namedtuple( - 'HTTPSPoolKey', HTTPPoolKey._fields + SSL_KEYWORDS -) - - -def _default_key_normalizer(key_class, request_context): - """ - Create a pool key of type ``key_class`` for a request. - - According to RFC 3986, both the scheme and host are case-insensitive. - Therefore, this function normalizes both before constructing the pool - key for an HTTPS request. If you wish to change this behaviour, provide - alternate callables to ``key_fn_by_scheme``. - - :param key_class: - The class to use when constructing the key. This should be a namedtuple - with the ``scheme`` and ``host`` keys at a minimum. - - :param request_context: - A dictionary-like object that contain the context for a request. - It should contain a key for each field in the :class:`HTTPPoolKey` - """ - context = {} - for key in key_class._fields: - context[key] = request_context.get(key) - context['scheme'] = context['scheme'].lower() - context['host'] = context['host'].lower() - return key_class(**context) - - -# A dictionary that maps a scheme to a callable that creates a pool key. -# This can be used to alter the way pool keys are constructed, if desired. -# Each PoolManager makes a copy of this dictionary so they can be configured -# globally here, or individually on the instance. -key_fn_by_scheme = { - 'http': functools.partial(_default_key_normalizer, HTTPPoolKey), - 'https': functools.partial(_default_key_normalizer, HTTPSPoolKey), -} - -pool_classes_by_scheme = { - 'http': HTTPConnectionPool, - 'https': HTTPSConnectionPool, -} - - -class PoolManager(RequestMethods): - """ - Allows for arbitrary requests while transparently keeping track of - necessary connection pools for you. - - :param num_pools: - Number of connection pools to cache before discarding the least - recently used pool. - - :param headers: - Headers to include with all requests, unless other headers are given - explicitly. - - :param \\**connection_pool_kw: - Additional parameters are used to create fresh - :class:`urllib3.connectionpool.ConnectionPool` instances. - - Example:: - - >>> manager = PoolManager(num_pools=2) - >>> r = manager.request('GET', 'http://google.com/') - >>> r = manager.request('GET', 'http://google.com/mail') - >>> r = manager.request('GET', 'http://yahoo.com/') - >>> len(manager.pools) - 2 - - """ - - proxy = None - - def __init__(self, num_pools=10, headers=None, **connection_pool_kw): - RequestMethods.__init__(self, headers) - self.connection_pool_kw = connection_pool_kw - self.pools = RecentlyUsedContainer(num_pools, - dispose_func=lambda p: p.close()) - - # Locally set the pool classes and keys so other PoolManagers can - # override them. - self.pool_classes_by_scheme = pool_classes_by_scheme - self.key_fn_by_scheme = key_fn_by_scheme.copy() - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_val, exc_tb): - self.clear() - # Return False to re-raise any potential exceptions - return False - - def _new_pool(self, scheme, host, port): - """ - Create a new :class:`ConnectionPool` based on host, port and scheme. - - This method is used to actually create the connection pools handed out - by :meth:`connection_from_url` and companion methods. It is intended - to be overridden for customization. - """ - pool_cls = self.pool_classes_by_scheme[scheme] - kwargs = self.connection_pool_kw - if scheme == 'http': - kwargs = self.connection_pool_kw.copy() - for kw in SSL_KEYWORDS: - kwargs.pop(kw, None) - - return pool_cls(host, port, **kwargs) - - def clear(self): - """ - Empty our store of pools and direct them all to close. - - This will not affect in-flight connections, but they will not be - re-used after completion. - """ - self.pools.clear() - - def connection_from_host(self, host, port=None, scheme='http'): - """ - Get a :class:`ConnectionPool` based on the host, port, and scheme. - - If ``port`` isn't given, it will be derived from the ``scheme`` using - ``urllib3.connectionpool.port_by_scheme``. - """ - - if not host: - raise LocationValueError("No host specified.") - - request_context = self.connection_pool_kw.copy() - request_context['scheme'] = scheme or 'http' - if not port: - port = port_by_scheme.get(request_context['scheme'].lower(), 80) - request_context['port'] = port - request_context['host'] = host - - return self.connection_from_context(request_context) - - def connection_from_context(self, request_context): - """ - Get a :class:`ConnectionPool` based on the request context. - - ``request_context`` must at least contain the ``scheme`` key and its - value must be a key in ``key_fn_by_scheme`` instance variable. - """ - scheme = request_context['scheme'].lower() - pool_key_constructor = self.key_fn_by_scheme[scheme] - pool_key = pool_key_constructor(request_context) - - return self.connection_from_pool_key(pool_key) - - def connection_from_pool_key(self, pool_key): - """ - Get a :class:`ConnectionPool` based on the provided pool key. - - ``pool_key`` should be a namedtuple that only contains immutable - objects. At a minimum it must have the ``scheme``, ``host``, and - ``port`` fields. - """ - with self.pools.lock: - # If the scheme, host, or port doesn't match existing open - # connections, open a new ConnectionPool. - pool = self.pools.get(pool_key) - if pool: - return pool - - # Make a fresh ConnectionPool of the desired type - pool = self._new_pool(pool_key.scheme, pool_key.host, pool_key.port) - self.pools[pool_key] = pool - - return pool - - def connection_from_url(self, url): - """ - Similar to :func:`urllib3.connectionpool.connection_from_url` but - doesn't pass any additional parameters to the - :class:`urllib3.connectionpool.ConnectionPool` constructor. - - Additional parameters are taken from the :class:`.PoolManager` - constructor. - """ - u = parse_url(url) - return self.connection_from_host(u.host, port=u.port, scheme=u.scheme) - - def urlopen(self, method, url, redirect=True, **kw): - """ - Same as :meth:`urllib3.connectionpool.HTTPConnectionPool.urlopen` - with custom cross-host redirect logic and only sends the request-uri - portion of the ``url``. - - The given ``url`` parameter must be absolute, such that an appropriate - :class:`urllib3.connectionpool.ConnectionPool` can be chosen for it. - """ - u = parse_url(url) - conn = self.connection_from_host(u.host, port=u.port, scheme=u.scheme) - - kw['assert_same_host'] = False - kw['redirect'] = False - if 'headers' not in kw: - kw['headers'] = self.headers - - if self.proxy is not None and u.scheme == "http": - response = conn.urlopen(method, url, **kw) - else: - response = conn.urlopen(method, u.request_uri, **kw) - - redirect_location = redirect and response.get_redirect_location() - if not redirect_location: - return response - - # Support relative URLs for redirecting. - redirect_location = urljoin(url, redirect_location) - - # RFC 7231, Section 6.4.4 - if response.status == 303: - method = 'GET' - - retries = kw.get('retries') - if not isinstance(retries, Retry): - retries = Retry.from_int(retries, redirect=redirect) - - try: - retries = retries.increment(method, url, response=response, _pool=conn) - except MaxRetryError: - if retries.raise_on_redirect: - raise - return response - - kw['retries'] = retries - kw['redirect'] = redirect - - log.info("Redirecting %s -> %s", url, redirect_location) - return self.urlopen(method, redirect_location, **kw) - - -class ProxyManager(PoolManager): - """ - Behaves just like :class:`PoolManager`, but sends all requests through - the defined proxy, using the CONNECT method for HTTPS URLs. - - :param proxy_url: - The URL of the proxy to be used. - - :param proxy_headers: - A dictionary contaning headers that will be sent to the proxy. In case - of HTTP they are being sent with each request, while in the - HTTPS/CONNECT case they are sent only once. Could be used for proxy - authentication. - - Example: - >>> proxy = urllib3.ProxyManager('http://localhost:3128/') - >>> r1 = proxy.request('GET', 'http://google.com/') - >>> r2 = proxy.request('GET', 'http://httpbin.org/') - >>> len(proxy.pools) - 1 - >>> r3 = proxy.request('GET', 'https://httpbin.org/') - >>> r4 = proxy.request('GET', 'https://twitter.com/') - >>> len(proxy.pools) - 3 - - """ - - def __init__(self, proxy_url, num_pools=10, headers=None, - proxy_headers=None, **connection_pool_kw): - - if isinstance(proxy_url, HTTPConnectionPool): - proxy_url = '%s://%s:%i' % (proxy_url.scheme, proxy_url.host, - proxy_url.port) - proxy = parse_url(proxy_url) - if not proxy.port: - port = port_by_scheme.get(proxy.scheme, 80) - proxy = proxy._replace(port=port) - - if proxy.scheme not in ("http", "https"): - raise ProxySchemeUnknown(proxy.scheme) - - self.proxy = proxy - self.proxy_headers = proxy_headers or {} - - connection_pool_kw['_proxy'] = self.proxy - connection_pool_kw['_proxy_headers'] = self.proxy_headers - - super(ProxyManager, self).__init__( - num_pools, headers, **connection_pool_kw) - - def connection_from_host(self, host, port=None, scheme='http'): - if scheme == "https": - return super(ProxyManager, self).connection_from_host( - host, port, scheme) - - return super(ProxyManager, self).connection_from_host( - self.proxy.host, self.proxy.port, self.proxy.scheme) - - def _set_proxy_headers(self, url, headers=None): - """ - Sets headers needed by proxies: specifically, the Accept and Host - headers. Only sets headers not provided by the user. - """ - headers_ = {'Accept': '*/*'} - - netloc = parse_url(url).netloc - if netloc: - headers_['Host'] = netloc - - if headers: - headers_.update(headers) - return headers_ - - def urlopen(self, method, url, redirect=True, **kw): - "Same as HTTP(S)ConnectionPool.urlopen, ``url`` must be absolute." - u = parse_url(url) - - if u.scheme == "http": - # For proxied HTTPS requests, httplib sets the necessary headers - # on the CONNECT to the proxy. For HTTP, we'll definitely - # need to set 'Host' at the very least. - headers = kw.get('headers', self.headers) - kw['headers'] = self._set_proxy_headers(url, headers) - - return super(ProxyManager, self).urlopen(method, url, redirect=redirect, **kw) - - -def proxy_from_url(url, **kw): - return ProxyManager(proxy_url=url, **kw) diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/request.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/request.py deleted file mode 100644 index c0fddff..0000000 --- a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/request.py +++ /dev/null @@ -1,148 +0,0 @@ -from __future__ import absolute_import - -from .filepost import encode_multipart_formdata -from .packages.six.moves.urllib.parse import urlencode - - -__all__ = ['RequestMethods'] - - -class RequestMethods(object): - """ - Convenience mixin for classes who implement a :meth:`urlopen` method, such - as :class:`~urllib3.connectionpool.HTTPConnectionPool` and - :class:`~urllib3.poolmanager.PoolManager`. - - Provides behavior for making common types of HTTP request methods and - decides which type of request field encoding to use. - - Specifically, - - :meth:`.request_encode_url` is for sending requests whose fields are - encoded in the URL (such as GET, HEAD, DELETE). - - :meth:`.request_encode_body` is for sending requests whose fields are - encoded in the *body* of the request using multipart or www-form-urlencoded - (such as for POST, PUT, PATCH). - - :meth:`.request` is for making any kind of request, it will look up the - appropriate encoding format and use one of the above two methods to make - the request. - - Initializer parameters: - - :param headers: - Headers to include with all requests, unless other headers are given - explicitly. - """ - - _encode_url_methods = set(['DELETE', 'GET', 'HEAD', 'OPTIONS']) - - def __init__(self, headers=None): - self.headers = headers or {} - - def urlopen(self, method, url, body=None, headers=None, - encode_multipart=True, multipart_boundary=None, - **kw): # Abstract - raise NotImplemented("Classes extending RequestMethods must implement " - "their own ``urlopen`` method.") - - def request(self, method, url, fields=None, headers=None, **urlopen_kw): - """ - Make a request using :meth:`urlopen` with the appropriate encoding of - ``fields`` based on the ``method`` used. - - This is a convenience method that requires the least amount of manual - effort. It can be used in most situations, while still having the - option to drop down to more specific methods when necessary, such as - :meth:`request_encode_url`, :meth:`request_encode_body`, - or even the lowest level :meth:`urlopen`. - """ - method = method.upper() - - if method in self._encode_url_methods: - return self.request_encode_url(method, url, fields=fields, - headers=headers, - **urlopen_kw) - else: - return self.request_encode_body(method, url, fields=fields, - headers=headers, - **urlopen_kw) - - def request_encode_url(self, method, url, fields=None, headers=None, - **urlopen_kw): - """ - Make a request using :meth:`urlopen` with the ``fields`` encoded in - the url. This is useful for request methods like GET, HEAD, DELETE, etc. - """ - if headers is None: - headers = self.headers - - extra_kw = {'headers': headers} - extra_kw.update(urlopen_kw) - - if fields: - url += '?' + urlencode(fields) - - return self.urlopen(method, url, **extra_kw) - - def request_encode_body(self, method, url, fields=None, headers=None, - encode_multipart=True, multipart_boundary=None, - **urlopen_kw): - """ - Make a request using :meth:`urlopen` with the ``fields`` encoded in - the body. This is useful for request methods like POST, PUT, PATCH, etc. - - When ``encode_multipart=True`` (default), then - :meth:`urllib3.filepost.encode_multipart_formdata` is used to encode - the payload with the appropriate content type. Otherwise - :meth:`urllib.urlencode` is used with the - 'application/x-www-form-urlencoded' content type. - - Multipart encoding must be used when posting files, and it's reasonably - safe to use it in other times too. However, it may break request - signing, such as with OAuth. - - Supports an optional ``fields`` parameter of key/value strings AND - key/filetuple. A filetuple is a (filename, data, MIME type) tuple where - the MIME type is optional. For example:: - - fields = { - 'foo': 'bar', - 'fakefile': ('foofile.txt', 'contents of foofile'), - 'realfile': ('barfile.txt', open('realfile').read()), - 'typedfile': ('bazfile.bin', open('bazfile').read(), - 'image/jpeg'), - 'nonamefile': 'contents of nonamefile field', - } - - When uploading a file, providing a filename (the first parameter of the - tuple) is optional but recommended to best mimick behavior of browsers. - - Note that if ``headers`` are supplied, the 'Content-Type' header will - be overwritten because it depends on the dynamic random boundary string - which is used to compose the body of the request. The random boundary - string can be explicitly set with the ``multipart_boundary`` parameter. - """ - if headers is None: - headers = self.headers - - extra_kw = {'headers': {}} - - if fields: - if 'body' in urlopen_kw: - raise TypeError( - "request got values for both 'fields' and 'body', can only specify one.") - - if encode_multipart: - body, content_type = encode_multipart_formdata(fields, boundary=multipart_boundary) - else: - body, content_type = urlencode(fields), 'application/x-www-form-urlencoded' - - extra_kw['body'] = body - extra_kw['headers'] = {'Content-Type': content_type} - - extra_kw['headers'].update(headers) - extra_kw.update(urlopen_kw) - - return self.urlopen(method, url, **extra_kw) diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/response.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/response.py deleted file mode 100644 index 6f1b63c..0000000 --- a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/response.py +++ /dev/null @@ -1,618 +0,0 @@ -from __future__ import absolute_import -from contextlib import contextmanager -import zlib -import io -import logging -from socket import timeout as SocketTimeout -from socket import error as SocketError - -from ._collections import HTTPHeaderDict -from .exceptions import ( - BodyNotHttplibCompatible, ProtocolError, DecodeError, ReadTimeoutError, - ResponseNotChunked, IncompleteRead, InvalidHeader -) -from .packages.six import string_types as basestring, binary_type, PY3 -from .packages.six.moves import http_client as httplib -from .connection import HTTPException, BaseSSLError -from .util.response import is_fp_closed, is_response_to_head - -log = logging.getLogger(__name__) - - -class DeflateDecoder(object): - - def __init__(self): - self._first_try = True - self._data = binary_type() - self._obj = zlib.decompressobj() - - def __getattr__(self, name): - return getattr(self._obj, name) - - def decompress(self, data): - if not data: - return data - - if not self._first_try: - return self._obj.decompress(data) - - self._data += data - try: - return self._obj.decompress(data) - except zlib.error: - self._first_try = False - self._obj = zlib.decompressobj(-zlib.MAX_WBITS) - try: - return self.decompress(self._data) - finally: - self._data = None - - -class GzipDecoder(object): - - def __init__(self): - self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS) - - def __getattr__(self, name): - return getattr(self._obj, name) - - def decompress(self, data): - if not data: - return data - return self._obj.decompress(data) - - -def _get_decoder(mode): - if mode == 'gzip': - return GzipDecoder() - - return DeflateDecoder() - - -class HTTPResponse(io.IOBase): - """ - HTTP Response container. - - Backwards-compatible to httplib's HTTPResponse but the response ``body`` is - loaded and decoded on-demand when the ``data`` property is accessed. This - class is also compatible with the Python standard library's :mod:`io` - module, and can hence be treated as a readable object in the context of that - framework. - - Extra parameters for behaviour not present in httplib.HTTPResponse: - - :param preload_content: - If True, the response's body will be preloaded during construction. - - :param decode_content: - If True, attempts to decode specific content-encoding's based on headers - (like 'gzip' and 'deflate') will be skipped and raw data will be used - instead. - - :param original_response: - When this HTTPResponse wrapper is generated from an httplib.HTTPResponse - object, it's convenient to include the original for debug purposes. It's - otherwise unused. - - :param retries: - The retries contains the last :class:`~urllib3.util.retry.Retry` that - was used during the request. - - :param enforce_content_length: - Enforce content length checking. Body returned by server must match - value of Content-Length header, if present. Otherwise, raise error. - """ - - CONTENT_DECODERS = ['gzip', 'deflate'] - REDIRECT_STATUSES = [301, 302, 303, 307, 308] - - def __init__(self, body='', headers=None, status=0, version=0, reason=None, - strict=0, preload_content=True, decode_content=True, - original_response=None, pool=None, connection=None, - retries=None, enforce_content_length=False, request_method=None): - - if isinstance(headers, HTTPHeaderDict): - self.headers = headers - else: - self.headers = HTTPHeaderDict(headers) - self.status = status - self.version = version - self.reason = reason - self.strict = strict - self.decode_content = decode_content - self.retries = retries - self.enforce_content_length = enforce_content_length - - self._decoder = None - self._body = None - self._fp = None - self._original_response = original_response - self._fp_bytes_read = 0 - - if body and isinstance(body, (basestring, binary_type)): - self._body = body - - self._pool = pool - self._connection = connection - - if hasattr(body, 'read'): - self._fp = body - - # Are we using the chunked-style of transfer encoding? - self.chunked = False - self.chunk_left = None - tr_enc = self.headers.get('transfer-encoding', '').lower() - # Don't incur the penalty of creating a list and then discarding it - encodings = (enc.strip() for enc in tr_enc.split(",")) - if "chunked" in encodings: - self.chunked = True - - # Determine length of response - self.length_remaining = self._init_length(request_method) - - # If requested, preload the body. - if preload_content and not self._body: - self._body = self.read(decode_content=decode_content) - - def get_redirect_location(self): - """ - Should we redirect and where to? - - :returns: Truthy redirect location string if we got a redirect status - code and valid location. ``None`` if redirect status and no - location. ``False`` if not a redirect status code. - """ - if self.status in self.REDIRECT_STATUSES: - return self.headers.get('location') - - return False - - def release_conn(self): - if not self._pool or not self._connection: - return - - self._pool._put_conn(self._connection) - self._connection = None - - @property - def data(self): - # For backwords-compat with earlier urllib3 0.4 and earlier. - if self._body: - return self._body - - if self._fp: - return self.read(cache_content=True) - - @property - def connection(self): - return self._connection - - def tell(self): - """ - Obtain the number of bytes pulled over the wire so far. May differ from - the amount of content returned by :meth:``HTTPResponse.read`` if bytes - are encoded on the wire (e.g, compressed). - """ - return self._fp_bytes_read - - def _init_length(self, request_method): - """ - Set initial length value for Response content if available. - """ - length = self.headers.get('content-length') - - if length is not None and self.chunked: - # This Response will fail with an IncompleteRead if it can't be - # received as chunked. This method falls back to attempt reading - # the response before raising an exception. - log.warning("Received response with both Content-Length and " - "Transfer-Encoding set. This is expressly forbidden " - "by RFC 7230 sec 3.3.2. Ignoring Content-Length and " - "attempting to process response as Transfer-Encoding: " - "chunked.") - return None - - elif length is not None: - try: - # RFC 7230 section 3.3.2 specifies multiple content lengths can - # be sent in a single Content-Length header - # (e.g. Content-Length: 42, 42). This line ensures the values - # are all valid ints and that as long as the `set` length is 1, - # all values are the same. Otherwise, the header is invalid. - lengths = set([int(val) for val in length.split(',')]) - if len(lengths) > 1: - raise InvalidHeader("Content-Length contained multiple " - "unmatching values (%s)" % length) - length = lengths.pop() - except ValueError: - length = None - else: - if length < 0: - length = None - - # Convert status to int for comparison - # In some cases, httplib returns a status of "_UNKNOWN" - try: - status = int(self.status) - except ValueError: - status = 0 - - # Check for responses that shouldn't include a body - if status in (204, 304) or 100 <= status < 200 or request_method == 'HEAD': - length = 0 - - return length - - def _init_decoder(self): - """ - Set-up the _decoder attribute if necessary. - """ - # Note: content-encoding value should be case-insensitive, per RFC 7230 - # Section 3.2 - content_encoding = self.headers.get('content-encoding', '').lower() - if self._decoder is None and content_encoding in self.CONTENT_DECODERS: - self._decoder = _get_decoder(content_encoding) - - def _decode(self, data, decode_content, flush_decoder): - """ - Decode the data passed in and potentially flush the decoder. - """ - try: - if decode_content and self._decoder: - data = self._decoder.decompress(data) - except (IOError, zlib.error) as e: - content_encoding = self.headers.get('content-encoding', '').lower() - raise DecodeError( - "Received response with content-encoding: %s, but " - "failed to decode it." % content_encoding, e) - - if flush_decoder and decode_content: - data += self._flush_decoder() - - return data - - def _flush_decoder(self): - """ - Flushes the decoder. Should only be called if the decoder is actually - being used. - """ - if self._decoder: - buf = self._decoder.decompress(b'') - return buf + self._decoder.flush() - - return b'' - - @contextmanager - def _error_catcher(self): - """ - Catch low-level python exceptions, instead re-raising urllib3 - variants, so that low-level exceptions are not leaked in the - high-level api. - - On exit, release the connection back to the pool. - """ - clean_exit = False - - try: - try: - yield - - except SocketTimeout: - # FIXME: Ideally we'd like to include the url in the ReadTimeoutError but - # there is yet no clean way to get at it from this context. - raise ReadTimeoutError(self._pool, None, 'Read timed out.') - - except BaseSSLError as e: - # FIXME: Is there a better way to differentiate between SSLErrors? - if 'read operation timed out' not in str(e): # Defensive: - # This shouldn't happen but just in case we're missing an edge - # case, let's avoid swallowing SSL errors. - raise - - raise ReadTimeoutError(self._pool, None, 'Read timed out.') - - except (HTTPException, SocketError) as e: - # This includes IncompleteRead. - raise ProtocolError('Connection broken: %r' % e, e) - - # If no exception is thrown, we should avoid cleaning up - # unnecessarily. - clean_exit = True - finally: - # If we didn't terminate cleanly, we need to throw away our - # connection. - if not clean_exit: - # The response may not be closed but we're not going to use it - # anymore so close it now to ensure that the connection is - # released back to the pool. - if self._original_response: - self._original_response.close() - - # Closing the response may not actually be sufficient to close - # everything, so if we have a hold of the connection close that - # too. - if self._connection: - self._connection.close() - - # If we hold the original response but it's closed now, we should - # return the connection back to the pool. - if self._original_response and self._original_response.isclosed(): - self.release_conn() - - def read(self, amt=None, decode_content=None, cache_content=False): - """ - Similar to :meth:`httplib.HTTPResponse.read`, but with two additional - parameters: ``decode_content`` and ``cache_content``. - - :param amt: - How much of the content to read. If specified, caching is skipped - because it doesn't make sense to cache partial content as the full - response. - - :param decode_content: - If True, will attempt to decode the body based on the - 'content-encoding' header. - - :param cache_content: - If True, will save the returned data such that the same result is - returned despite of the state of the underlying file object. This - is useful if you want the ``.data`` property to continue working - after having ``.read()`` the file object. (Overridden if ``amt`` is - set.) - """ - self._init_decoder() - if decode_content is None: - decode_content = self.decode_content - - if self._fp is None: - return - - flush_decoder = False - data = None - - with self._error_catcher(): - if amt is None: - # cStringIO doesn't like amt=None - data = self._fp.read() - flush_decoder = True - else: - cache_content = False - data = self._fp.read(amt) - if amt != 0 and not data: # Platform-specific: Buggy versions of Python. - # Close the connection when no data is returned - # - # This is redundant to what httplib/http.client _should_ - # already do. However, versions of python released before - # December 15, 2012 (http://bugs.python.org/issue16298) do - # not properly close the connection in all cases. There is - # no harm in redundantly calling close. - self._fp.close() - flush_decoder = True - if self.enforce_content_length and self.length_remaining not in (0, None): - # This is an edge case that httplib failed to cover due - # to concerns of backward compatibility. We're - # addressing it here to make sure IncompleteRead is - # raised during streaming, so all calls with incorrect - # Content-Length are caught. - raise IncompleteRead(self._fp_bytes_read, self.length_remaining) - - if data: - self._fp_bytes_read += len(data) - if self.length_remaining is not None: - self.length_remaining -= len(data) - - data = self._decode(data, decode_content, flush_decoder) - - if cache_content: - self._body = data - - return data - - def stream(self, amt=2**16, decode_content=None): - """ - A generator wrapper for the read() method. A call will block until - ``amt`` bytes have been read from the connection or until the - connection is closed. - - :param amt: - How much of the content to read. The generator will return up to - much data per iteration, but may return less. This is particularly - likely when using compressed data. However, the empty string will - never be returned. - - :param decode_content: - If True, will attempt to decode the body based on the - 'content-encoding' header. - """ - if self.chunked and self.supports_chunked_reads(): - for line in self.read_chunked(amt, decode_content=decode_content): - yield line - else: - while not is_fp_closed(self._fp): - data = self.read(amt=amt, decode_content=decode_content) - - if data: - yield data - - @classmethod - def from_httplib(ResponseCls, r, **response_kw): - """ - Given an :class:`httplib.HTTPResponse` instance ``r``, return a - corresponding :class:`urllib3.response.HTTPResponse` object. - - Remaining parameters are passed to the HTTPResponse constructor, along - with ``original_response=r``. - """ - headers = r.msg - - if not isinstance(headers, HTTPHeaderDict): - if PY3: # Python 3 - headers = HTTPHeaderDict(headers.items()) - else: # Python 2 - headers = HTTPHeaderDict.from_httplib(headers) - - # HTTPResponse objects in Python 3 don't have a .strict attribute - strict = getattr(r, 'strict', 0) - resp = ResponseCls(body=r, - headers=headers, - status=r.status, - version=r.version, - reason=r.reason, - strict=strict, - original_response=r, - **response_kw) - return resp - - # Backwards-compatibility methods for httplib.HTTPResponse - def getheaders(self): - return self.headers - - def getheader(self, name, default=None): - return self.headers.get(name, default) - - # Overrides from io.IOBase - def close(self): - if not self.closed: - self._fp.close() - - if self._connection: - self._connection.close() - - @property - def closed(self): - if self._fp is None: - return True - elif hasattr(self._fp, 'isclosed'): - return self._fp.isclosed() - elif hasattr(self._fp, 'closed'): - return self._fp.closed - else: - return True - - def fileno(self): - if self._fp is None: - raise IOError("HTTPResponse has no file to get a fileno from") - elif hasattr(self._fp, "fileno"): - return self._fp.fileno() - else: - raise IOError("The file-like object this HTTPResponse is wrapped " - "around has no file descriptor") - - def flush(self): - if self._fp is not None and hasattr(self._fp, 'flush'): - return self._fp.flush() - - def readable(self): - # This method is required for `io` module compatibility. - return True - - def readinto(self, b): - # This method is required for `io` module compatibility. - temp = self.read(len(b)) - if len(temp) == 0: - return 0 - else: - b[:len(temp)] = temp - return len(temp) - - def supports_chunked_reads(self): - """ - Checks if the underlying file-like object looks like a - httplib.HTTPResponse object. We do this by testing for the fp - attribute. If it is present we assume it returns raw chunks as - processed by read_chunked(). - """ - return hasattr(self._fp, 'fp') - - def _update_chunk_length(self): - # First, we'll figure out length of a chunk and then - # we'll try to read it from socket. - if self.chunk_left is not None: - return - line = self._fp.fp.readline() - line = line.split(b';', 1)[0] - try: - self.chunk_left = int(line, 16) - except ValueError: - # Invalid chunked protocol response, abort. - self.close() - raise httplib.IncompleteRead(line) - - def _handle_chunk(self, amt): - returned_chunk = None - if amt is None: - chunk = self._fp._safe_read(self.chunk_left) - returned_chunk = chunk - self._fp._safe_read(2) # Toss the CRLF at the end of the chunk. - self.chunk_left = None - elif amt < self.chunk_left: - value = self._fp._safe_read(amt) - self.chunk_left = self.chunk_left - amt - returned_chunk = value - elif amt == self.chunk_left: - value = self._fp._safe_read(amt) - self._fp._safe_read(2) # Toss the CRLF at the end of the chunk. - self.chunk_left = None - returned_chunk = value - else: # amt > self.chunk_left - returned_chunk = self._fp._safe_read(self.chunk_left) - self._fp._safe_read(2) # Toss the CRLF at the end of the chunk. - self.chunk_left = None - return returned_chunk - - def read_chunked(self, amt=None, decode_content=None): - """ - Similar to :meth:`HTTPResponse.read`, but with an additional - parameter: ``decode_content``. - - :param decode_content: - If True, will attempt to decode the body based on the - 'content-encoding' header. - """ - self._init_decoder() - # FIXME: Rewrite this method and make it a class with a better structured logic. - if not self.chunked: - raise ResponseNotChunked( - "Response is not chunked. " - "Header 'transfer-encoding: chunked' is missing.") - if not self.supports_chunked_reads(): - raise BodyNotHttplibCompatible( - "Body should be httplib.HTTPResponse like. " - "It should have have an fp attribute which returns raw chunks.") - - # Don't bother reading the body of a HEAD request. - if self._original_response and is_response_to_head(self._original_response): - self._original_response.close() - return - - with self._error_catcher(): - while True: - self._update_chunk_length() - if self.chunk_left == 0: - break - chunk = self._handle_chunk(amt) - decoded = self._decode(chunk, decode_content=decode_content, - flush_decoder=False) - if decoded: - yield decoded - - if decode_content: - # On CPython and PyPy, we should never need to flush the - # decoder. However, on Jython we *might* need to, so - # lets defensively do it anyway. - decoded = self._flush_decoder() - if decoded: # Platform-specific: Jython. - yield decoded - - # Chunk content ends with \r\n: discard it. - while True: - line = self._fp.fp.readline() - if not line: - # Some sites may not end with '\r\n'. - break - if line == b'\r\n': - break - - # We read everything; close the "file". - if self._original_response: - self._original_response.close() diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/__init__.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/__init__.py deleted file mode 100644 index 5ced5a4..0000000 --- a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/__init__.py +++ /dev/null @@ -1,52 +0,0 @@ -from __future__ import absolute_import -# For backwards compatibility, provide imports that used to be here. -from .connection import is_connection_dropped -from .request import make_headers -from .response import is_fp_closed -from .ssl_ import ( - SSLContext, - HAS_SNI, - IS_PYOPENSSL, - assert_fingerprint, - resolve_cert_reqs, - resolve_ssl_version, - ssl_wrap_socket, -) -from .timeout import ( - current_time, - Timeout, -) - -from .retry import Retry -from .url import ( - get_host, - parse_url, - split_first, - Url, -) -from .wait import ( - wait_for_read, - wait_for_write -) - -__all__ = ( - 'HAS_SNI', - 'IS_PYOPENSSL', - 'SSLContext', - 'Retry', - 'Timeout', - 'Url', - 'assert_fingerprint', - 'current_time', - 'is_connection_dropped', - 'is_fp_closed', - 'get_host', - 'parse_url', - 'make_headers', - 'resolve_cert_reqs', - 'resolve_ssl_version', - 'split_first', - 'ssl_wrap_socket', - 'wait_for_read', - 'wait_for_write' -) diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/connection.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/connection.py deleted file mode 100644 index bf699cf..0000000 --- a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/connection.py +++ /dev/null @@ -1,130 +0,0 @@ -from __future__ import absolute_import -import socket -from .wait import wait_for_read -from .selectors import HAS_SELECT, SelectorError - - -def is_connection_dropped(conn): # Platform-specific - """ - Returns True if the connection is dropped and should be closed. - - :param conn: - :class:`httplib.HTTPConnection` object. - - Note: For platforms like AppEngine, this will always return ``False`` to - let the platform handle connection recycling transparently for us. - """ - sock = getattr(conn, 'sock', False) - if sock is False: # Platform-specific: AppEngine - return False - if sock is None: # Connection already closed (such as by httplib). - return True - - if not HAS_SELECT: - return False - - try: - return bool(wait_for_read(sock, timeout=0.0)) - except SelectorError: - return True - - -# This function is copied from socket.py in the Python 2.7 standard -# library test suite. Added to its signature is only `socket_options`. -# One additional modification is that we avoid binding to IPv6 servers -# discovered in DNS if the system doesn't have IPv6 functionality. -def create_connection(address, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, - source_address=None, socket_options=None): - """Connect to *address* and return the socket object. - - Convenience function. Connect to *address* (a 2-tuple ``(host, - port)``) and return the socket object. Passing the optional - *timeout* parameter will set the timeout on the socket instance - before attempting to connect. If no *timeout* is supplied, the - global default timeout setting returned by :func:`getdefaulttimeout` - is used. If *source_address* is set it must be a tuple of (host, port) - for the socket to bind as a source address before making the connection. - An host of '' or port 0 tells the OS to use the default. - """ - - host, port = address - if host.startswith('['): - host = host.strip('[]') - err = None - - # Using the value from allowed_gai_family() in the context of getaddrinfo lets - # us select whether to work with IPv4 DNS records, IPv6 records, or both. - # The original create_connection function always returns all records. - family = allowed_gai_family() - - for res in socket.getaddrinfo(host, port, family, socket.SOCK_STREAM): - af, socktype, proto, canonname, sa = res - sock = None - try: - sock = socket.socket(af, socktype, proto) - - # If provided, set socket level options before connecting. - _set_socket_options(sock, socket_options) - - if timeout is not socket._GLOBAL_DEFAULT_TIMEOUT: - sock.settimeout(timeout) - if source_address: - sock.bind(source_address) - sock.connect(sa) - return sock - - except socket.error as e: - err = e - if sock is not None: - sock.close() - sock = None - - if err is not None: - raise err - - raise socket.error("getaddrinfo returns an empty list") - - -def _set_socket_options(sock, options): - if options is None: - return - - for opt in options: - sock.setsockopt(*opt) - - -def allowed_gai_family(): - """This function is designed to work in the context of - getaddrinfo, where family=socket.AF_UNSPEC is the default and - will perform a DNS search for both IPv6 and IPv4 records.""" - - family = socket.AF_INET - if HAS_IPV6: - family = socket.AF_UNSPEC - return family - - -def _has_ipv6(host): - """ Returns True if the system can bind an IPv6 address. """ - sock = None - has_ipv6 = False - - if socket.has_ipv6: - # has_ipv6 returns true if cPython was compiled with IPv6 support. - # It does not tell us if the system has IPv6 support enabled. To - # determine that we must bind to an IPv6 address. - # https://github.com/shazow/urllib3/pull/611 - # https://bugs.python.org/issue658327 - try: - sock = socket.socket(socket.AF_INET6) - sock.bind((host, 0)) - has_ipv6 = True - except Exception: - pass - - if sock: - sock.close() - return has_ipv6 - - -HAS_IPV6 = _has_ipv6('::1') diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/request.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/request.py deleted file mode 100644 index 974fc40..0000000 --- a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/request.py +++ /dev/null @@ -1,118 +0,0 @@ -from __future__ import absolute_import -from base64 import b64encode - -from ..packages.six import b, integer_types -from ..exceptions import UnrewindableBodyError - -ACCEPT_ENCODING = 'gzip,deflate' -_FAILEDTELL = object() - - -def make_headers(keep_alive=None, accept_encoding=None, user_agent=None, - basic_auth=None, proxy_basic_auth=None, disable_cache=None): - """ - Shortcuts for generating request headers. - - :param keep_alive: - If ``True``, adds 'connection: keep-alive' header. - - :param accept_encoding: - Can be a boolean, list, or string. - ``True`` translates to 'gzip,deflate'. - List will get joined by comma. - String will be used as provided. - - :param user_agent: - String representing the user-agent you want, such as - "python-urllib3/0.6" - - :param basic_auth: - Colon-separated username:password string for 'authorization: basic ...' - auth header. - - :param proxy_basic_auth: - Colon-separated username:password string for 'proxy-authorization: basic ...' - auth header. - - :param disable_cache: - If ``True``, adds 'cache-control: no-cache' header. - - Example:: - - >>> make_headers(keep_alive=True, user_agent="Batman/1.0") - {'connection': 'keep-alive', 'user-agent': 'Batman/1.0'} - >>> make_headers(accept_encoding=True) - {'accept-encoding': 'gzip,deflate'} - """ - headers = {} - if accept_encoding: - if isinstance(accept_encoding, str): - pass - elif isinstance(accept_encoding, list): - accept_encoding = ','.join(accept_encoding) - else: - accept_encoding = ACCEPT_ENCODING - headers['accept-encoding'] = accept_encoding - - if user_agent: - headers['user-agent'] = user_agent - - if keep_alive: - headers['connection'] = 'keep-alive' - - if basic_auth: - headers['authorization'] = 'Basic ' + \ - b64encode(b(basic_auth)).decode('utf-8') - - if proxy_basic_auth: - headers['proxy-authorization'] = 'Basic ' + \ - b64encode(b(proxy_basic_auth)).decode('utf-8') - - if disable_cache: - headers['cache-control'] = 'no-cache' - - return headers - - -def set_file_position(body, pos): - """ - If a position is provided, move file to that point. - Otherwise, we'll attempt to record a position for future use. - """ - if pos is not None: - rewind_body(body, pos) - elif getattr(body, 'tell', None) is not None: - try: - pos = body.tell() - except (IOError, OSError): - # This differentiates from None, allowing us to catch - # a failed `tell()` later when trying to rewind the body. - pos = _FAILEDTELL - - return pos - - -def rewind_body(body, body_pos): - """ - Attempt to rewind body to a certain position. - Primarily used for request redirects and retries. - - :param body: - File-like object that supports seek. - - :param int pos: - Position to seek to in file. - """ - body_seek = getattr(body, 'seek', None) - if body_seek is not None and isinstance(body_pos, integer_types): - try: - body_seek(body_pos) - except (IOError, OSError): - raise UnrewindableBodyError("An error occured when rewinding request " - "body for redirect/retry.") - elif body_pos is _FAILEDTELL: - raise UnrewindableBodyError("Unable to record file position for rewinding " - "request body during a redirect/retry.") - else: - raise ValueError("body_pos must be of type integer, " - "instead it was %s." % type(body_pos)) diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/response.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/response.py deleted file mode 100644 index 67cf730..0000000 --- a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/response.py +++ /dev/null @@ -1,81 +0,0 @@ -from __future__ import absolute_import -from ..packages.six.moves import http_client as httplib - -from ..exceptions import HeaderParsingError - - -def is_fp_closed(obj): - """ - Checks whether a given file-like object is closed. - - :param obj: - The file-like object to check. - """ - - try: - # Check `isclosed()` first, in case Python3 doesn't set `closed`. - # GH Issue #928 - return obj.isclosed() - except AttributeError: - pass - - try: - # Check via the official file-like-object way. - return obj.closed - except AttributeError: - pass - - try: - # Check if the object is a container for another file-like object that - # gets released on exhaustion (e.g. HTTPResponse). - return obj.fp is None - except AttributeError: - pass - - raise ValueError("Unable to determine whether fp is closed.") - - -def assert_header_parsing(headers): - """ - Asserts whether all headers have been successfully parsed. - Extracts encountered errors from the result of parsing headers. - - Only works on Python 3. - - :param headers: Headers to verify. - :type headers: `httplib.HTTPMessage`. - - :raises urllib3.exceptions.HeaderParsingError: - If parsing errors are found. - """ - - # This will fail silently if we pass in the wrong kind of parameter. - # To make debugging easier add an explicit check. - if not isinstance(headers, httplib.HTTPMessage): - raise TypeError('expected httplib.Message, got {0}.'.format( - type(headers))) - - defects = getattr(headers, 'defects', None) - get_payload = getattr(headers, 'get_payload', None) - - unparsed_data = None - if get_payload: # Platform-specific: Python 3. - unparsed_data = get_payload() - - if defects or unparsed_data: - raise HeaderParsingError(defects=defects, unparsed_data=unparsed_data) - - -def is_response_to_head(response): - """ - Checks whether the request of a response has been a HEAD-request. - Handles the quirks of AppEngine. - - :param conn: - :type conn: :class:`httplib.HTTPResponse` - """ - # FIXME: Can we do this somehow without accessing private httplib _method? - method = response._method - if isinstance(method, int): # Platform-specific: Appengine - return method == 3 - return method.upper() == 'HEAD' diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/retry.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/retry.py deleted file mode 100644 index c9e7d28..0000000 --- a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/retry.py +++ /dev/null @@ -1,389 +0,0 @@ -from __future__ import absolute_import -import time -import logging -from collections import namedtuple -from itertools import takewhile -import email -import re - -from ..exceptions import ( - ConnectTimeoutError, - MaxRetryError, - ProtocolError, - ReadTimeoutError, - ResponseError, - InvalidHeader, -) -from ..packages import six - - -log = logging.getLogger(__name__) - -# Data structure for representing the metadata of requests that result in a retry. -RequestHistory = namedtuple('RequestHistory', ["method", "url", "error", - "status", "redirect_location"]) - - -class Retry(object): - """ Retry configuration. - - Each retry attempt will create a new Retry object with updated values, so - they can be safely reused. - - Retries can be defined as a default for a pool:: - - retries = Retry(connect=5, read=2, redirect=5) - http = PoolManager(retries=retries) - response = http.request('GET', 'http://example.com/') - - Or per-request (which overrides the default for the pool):: - - response = http.request('GET', 'http://example.com/', retries=Retry(10)) - - Retries can be disabled by passing ``False``:: - - response = http.request('GET', 'http://example.com/', retries=False) - - Errors will be wrapped in :class:`~urllib3.exceptions.MaxRetryError` unless - retries are disabled, in which case the causing exception will be raised. - - :param int total: - Total number of retries to allow. Takes precedence over other counts. - - Set to ``None`` to remove this constraint and fall back on other - counts. It's a good idea to set this to some sensibly-high value to - account for unexpected edge cases and avoid infinite retry loops. - - Set to ``0`` to fail on the first retry. - - Set to ``False`` to disable and imply ``raise_on_redirect=False``. - - :param int connect: - How many connection-related errors to retry on. - - These are errors raised before the request is sent to the remote server, - which we assume has not triggered the server to process the request. - - Set to ``0`` to fail on the first retry of this type. - - :param int read: - How many times to retry on read errors. - - These errors are raised after the request was sent to the server, so the - request may have side-effects. - - Set to ``0`` to fail on the first retry of this type. - - :param int redirect: - How many redirects to perform. Limit this to avoid infinite redirect - loops. - - A redirect is a HTTP response with a status code 301, 302, 303, 307 or - 308. - - Set to ``0`` to fail on the first retry of this type. - - Set to ``False`` to disable and imply ``raise_on_redirect=False``. - - :param iterable method_whitelist: - Set of uppercased HTTP method verbs that we should retry on. - - By default, we only retry on methods which are considered to be - idempotent (multiple requests with the same parameters end with the - same state). See :attr:`Retry.DEFAULT_METHOD_WHITELIST`. - - Set to a ``False`` value to retry on any verb. - - :param iterable status_forcelist: - A set of integer HTTP status codes that we should force a retry on. - A retry is initiated if the request method is in ``method_whitelist`` - and the response status code is in ``status_forcelist``. - - By default, this is disabled with ``None``. - - :param float backoff_factor: - A backoff factor to apply between attempts after the second try - (most errors are resolved immediately by a second try without a - delay). urllib3 will sleep for:: - - {backoff factor} * (2 ^ ({number of total retries} - 1)) - - seconds. If the backoff_factor is 0.1, then :func:`.sleep` will sleep - for [0.0s, 0.2s, 0.4s, ...] between retries. It will never be longer - than :attr:`Retry.BACKOFF_MAX`. - - By default, backoff is disabled (set to 0). - - :param bool raise_on_redirect: Whether, if the number of redirects is - exhausted, to raise a MaxRetryError, or to return a response with a - response code in the 3xx range. - - :param bool raise_on_status: Similar meaning to ``raise_on_redirect``: - whether we should raise an exception, or return a response, - if status falls in ``status_forcelist`` range and retries have - been exhausted. - - :param tuple history: The history of the request encountered during - each call to :meth:`~Retry.increment`. The list is in the order - the requests occurred. Each list item is of class :class:`RequestHistory`. - - :param bool respect_retry_after_header: - Whether to respect Retry-After header on status codes defined as - :attr:`Retry.RETRY_AFTER_STATUS_CODES` or not. - - """ - - DEFAULT_METHOD_WHITELIST = frozenset([ - 'HEAD', 'GET', 'PUT', 'DELETE', 'OPTIONS', 'TRACE']) - - RETRY_AFTER_STATUS_CODES = frozenset([413, 429, 503]) - - #: Maximum backoff time. - BACKOFF_MAX = 120 - - def __init__(self, total=10, connect=None, read=None, redirect=None, - method_whitelist=DEFAULT_METHOD_WHITELIST, status_forcelist=None, - backoff_factor=0, raise_on_redirect=True, raise_on_status=True, - history=None, respect_retry_after_header=True): - - self.total = total - self.connect = connect - self.read = read - - if redirect is False or total is False: - redirect = 0 - raise_on_redirect = False - - self.redirect = redirect - self.status_forcelist = status_forcelist or set() - self.method_whitelist = method_whitelist - self.backoff_factor = backoff_factor - self.raise_on_redirect = raise_on_redirect - self.raise_on_status = raise_on_status - self.history = history or tuple() - self.respect_retry_after_header = respect_retry_after_header - - def new(self, **kw): - params = dict( - total=self.total, - connect=self.connect, read=self.read, redirect=self.redirect, - method_whitelist=self.method_whitelist, - status_forcelist=self.status_forcelist, - backoff_factor=self.backoff_factor, - raise_on_redirect=self.raise_on_redirect, - raise_on_status=self.raise_on_status, - history=self.history, - ) - params.update(kw) - return type(self)(**params) - - @classmethod - def from_int(cls, retries, redirect=True, default=None): - """ Backwards-compatibility for the old retries format.""" - if retries is None: - retries = default if default is not None else cls.DEFAULT - - if isinstance(retries, Retry): - return retries - - redirect = bool(redirect) and None - new_retries = cls(retries, redirect=redirect) - log.debug("Converted retries value: %r -> %r", retries, new_retries) - return new_retries - - def get_backoff_time(self): - """ Formula for computing the current backoff - - :rtype: float - """ - # We want to consider only the last consecutive errors sequence (Ignore redirects). - consecutive_errors_len = len(list(takewhile(lambda x: x.redirect_location is None, - reversed(self.history)))) - if consecutive_errors_len <= 1: - return 0 - - backoff_value = self.backoff_factor * (2 ** (consecutive_errors_len - 1)) - return min(self.BACKOFF_MAX, backoff_value) - - def parse_retry_after(self, retry_after): - # Whitespace: https://tools.ietf.org/html/rfc7230#section-3.2.4 - if re.match(r"^\s*[0-9]+\s*$", retry_after): - seconds = int(retry_after) - else: - retry_date_tuple = email.utils.parsedate(retry_after) - if retry_date_tuple is None: - raise InvalidHeader("Invalid Retry-After header: %s" % retry_after) - retry_date = time.mktime(retry_date_tuple) - seconds = retry_date - time.time() - - if seconds < 0: - seconds = 0 - - return seconds - - def get_retry_after(self, response): - """ Get the value of Retry-After in seconds. """ - - retry_after = response.getheader("Retry-After") - - if retry_after is None: - return None - - return self.parse_retry_after(retry_after) - - def sleep_for_retry(self, response=None): - retry_after = self.get_retry_after(response) - if retry_after: - time.sleep(retry_after) - return True - - return False - - def _sleep_backoff(self): - backoff = self.get_backoff_time() - if backoff <= 0: - return - time.sleep(backoff) - - def sleep(self, response=None): - """ Sleep between retry attempts. - - This method will respect a server's ``Retry-After`` response header - and sleep the duration of the time requested. If that is not present, it - will use an exponential backoff. By default, the backoff factor is 0 and - this method will return immediately. - """ - - if response: - slept = self.sleep_for_retry(response) - if slept: - return - - self._sleep_backoff() - - def _is_connection_error(self, err): - """ Errors when we're fairly sure that the server did not receive the - request, so it should be safe to retry. - """ - return isinstance(err, ConnectTimeoutError) - - def _is_read_error(self, err): - """ Errors that occur after the request has been started, so we should - assume that the server began processing it. - """ - return isinstance(err, (ReadTimeoutError, ProtocolError)) - - def _is_method_retryable(self, method): - """ Checks if a given HTTP method should be retried upon, depending if - it is included on the method whitelist. - """ - if self.method_whitelist and method.upper() not in self.method_whitelist: - return False - - return True - - def is_retry(self, method, status_code, has_retry_after=False): - """ Is this method/status code retryable? (Based on whitelists and control - variables such as the number of total retries to allow, whether to - respect the Retry-After header, whether this header is present, and - whether the returned status code is on the list of status codes to - be retried upon on the presence of the aforementioned header) - """ - if not self._is_method_retryable(method): - return False - - if self.status_forcelist and status_code in self.status_forcelist: - return True - - return (self.total and self.respect_retry_after_header and - has_retry_after and (status_code in self.RETRY_AFTER_STATUS_CODES)) - - def is_exhausted(self): - """ Are we out of retries? """ - retry_counts = (self.total, self.connect, self.read, self.redirect) - retry_counts = list(filter(None, retry_counts)) - if not retry_counts: - return False - - return min(retry_counts) < 0 - - def increment(self, method=None, url=None, response=None, error=None, - _pool=None, _stacktrace=None): - """ Return a new Retry object with incremented retry counters. - - :param response: A response object, or None, if the server did not - return a response. - :type response: :class:`~urllib3.response.HTTPResponse` - :param Exception error: An error encountered during the request, or - None if the response was received successfully. - - :return: A new ``Retry`` object. - """ - if self.total is False and error: - # Disabled, indicate to re-raise the error. - raise six.reraise(type(error), error, _stacktrace) - - total = self.total - if total is not None: - total -= 1 - - connect = self.connect - read = self.read - redirect = self.redirect - cause = 'unknown' - status = None - redirect_location = None - - if error and self._is_connection_error(error): - # Connect retry? - if connect is False: - raise six.reraise(type(error), error, _stacktrace) - elif connect is not None: - connect -= 1 - - elif error and self._is_read_error(error): - # Read retry? - if read is False or not self._is_method_retryable(method): - raise six.reraise(type(error), error, _stacktrace) - elif read is not None: - read -= 1 - - elif response and response.get_redirect_location(): - # Redirect retry? - if redirect is not None: - redirect -= 1 - cause = 'too many redirects' - redirect_location = response.get_redirect_location() - status = response.status - - else: - # Incrementing because of a server error like a 500 in - # status_forcelist and a the given method is in the whitelist - cause = ResponseError.GENERIC_ERROR - if response and response.status: - cause = ResponseError.SPECIFIC_ERROR.format( - status_code=response.status) - status = response.status - - history = self.history + (RequestHistory(method, url, error, status, redirect_location),) - - new_retry = self.new( - total=total, - connect=connect, read=read, redirect=redirect, - history=history) - - if new_retry.is_exhausted(): - raise MaxRetryError(_pool, url, error or ResponseError(cause)) - - log.debug("Incremented Retry for (url='%s'): %r", url, new_retry) - - return new_retry - - def __repr__(self): - return ('{cls.__name__}(total={self.total}, connect={self.connect}, ' - 'read={self.read}, redirect={self.redirect})').format( - cls=type(self), self=self) - - -# For backwards compatibility (equivalent to pre-v1.9): -Retry.DEFAULT = Retry(3) diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/selectors.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/selectors.py deleted file mode 100644 index b381450..0000000 --- a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/selectors.py +++ /dev/null @@ -1,529 +0,0 @@ -# Backport of selectors.py from Python 3.5+ to support Python < 3.4 -# Also has the behavior specified in PEP 475 which is to retry syscalls -# in the case of an EINTR error. This module is required because selectors34 -# does not follow this behavior and instead returns that no dile descriptor -# events have occurred rather than retry the syscall. The decision to drop -# support for select.devpoll is made to maintain 100% test coverage. - -import errno -import math -import select -from collections import namedtuple - -try: - from collections.abc import Mapping -except ImportError: - from collections import Mapping - -import time -try: - monotonic = time.monotonic -except (AttributeError, ImportError): # Python 3.3< - monotonic = time.time - -EVENT_READ = (1 << 0) -EVENT_WRITE = (1 << 1) - -HAS_SELECT = True # Variable that shows whether the platform has a selector. -_SYSCALL_SENTINEL = object() # Sentinel in case a system call returns None. - - -class SelectorError(Exception): - def __init__(self, errcode): - super(SelectorError, self).__init__() - self.errno = errcode - - def __repr__(self): - return "<SelectorError errno={0}>".format(self.errno) - - def __str__(self): - return self.__repr__() - - -def _fileobj_to_fd(fileobj): - """ Return a file descriptor from a file object. If - given an integer will simply return that integer back. """ - if isinstance(fileobj, int): - fd = fileobj - else: - try: - fd = int(fileobj.fileno()) - except (AttributeError, TypeError, ValueError): - raise ValueError("Invalid file object: {0!r}".format(fileobj)) - if fd < 0: - raise ValueError("Invalid file descriptor: {0}".format(fd)) - return fd - - -def _syscall_wrapper(func, recalc_timeout, *args, **kwargs): - """ Wrapper function for syscalls that could fail due to EINTR. - All functions should be retried if there is time left in the timeout - in accordance with PEP 475. """ - timeout = kwargs.get("timeout", None) - if timeout is None: - expires = None - recalc_timeout = False - else: - timeout = float(timeout) - if timeout < 0.0: # Timeout less than 0 treated as no timeout. - expires = None - else: - expires = monotonic() + timeout - - args = list(args) - if recalc_timeout and "timeout" not in kwargs: - raise ValueError( - "Timeout must be in args or kwargs to be recalculated") - - result = _SYSCALL_SENTINEL - while result is _SYSCALL_SENTINEL: - try: - result = func(*args, **kwargs) - # OSError is thrown by select.select - # IOError is thrown by select.epoll.poll - # select.error is thrown by select.poll.poll - # Aren't we thankful for Python 3.x rework for exceptions? - except (OSError, IOError, select.error) as e: - # select.error wasn't a subclass of OSError in the past. - errcode = None - if hasattr(e, "errno"): - errcode = e.errno - elif hasattr(e, "args"): - errcode = e.args[0] - - # Also test for the Windows equivalent of EINTR. - is_interrupt = (errcode == errno.EINTR or (hasattr(errno, "WSAEINTR") and - errcode == errno.WSAEINTR)) - - if is_interrupt: - if expires is not None: - current_time = monotonic() - if current_time > expires: - raise OSError(errno=errno.ETIMEDOUT) - if recalc_timeout: - if "timeout" in kwargs: - kwargs["timeout"] = expires - current_time - continue - if errcode: - raise SelectorError(errcode) - else: - raise - return result - - -SelectorKey = namedtuple('SelectorKey', ['fileobj', 'fd', 'events', 'data']) - - -class _SelectorMapping(Mapping): - """ Mapping of file objects to selector keys """ - - def __init__(self, selector): - self._selector = selector - - def __len__(self): - return len(self._selector._fd_to_key) - - def __getitem__(self, fileobj): - try: - fd = self._selector._fileobj_lookup(fileobj) - return self._selector._fd_to_key[fd] - except KeyError: - raise KeyError("{0!r} is not registered.".format(fileobj)) - - def __iter__(self): - return iter(self._selector._fd_to_key) - - -class BaseSelector(object): - """ Abstract Selector class - - A selector supports registering file objects to be monitored - for specific I/O events. - - A file object is a file descriptor or any object with a - `fileno()` method. An arbitrary object can be attached to the - file object which can be used for example to store context info, - a callback, etc. - - A selector can use various implementations (select(), poll(), epoll(), - and kqueue()) depending on the platform. The 'DefaultSelector' class uses - the most efficient implementation for the current platform. - """ - def __init__(self): - # Maps file descriptors to keys. - self._fd_to_key = {} - - # Read-only mapping returned by get_map() - self._map = _SelectorMapping(self) - - def _fileobj_lookup(self, fileobj): - """ Return a file descriptor from a file object. - This wraps _fileobj_to_fd() to do an exhaustive - search in case the object is invalid but we still - have it in our map. Used by unregister() so we can - unregister an object that was previously registered - even if it is closed. It is also used by _SelectorMapping - """ - try: - return _fileobj_to_fd(fileobj) - except ValueError: - - # Search through all our mapped keys. - for key in self._fd_to_key.values(): - if key.fileobj is fileobj: - return key.fd - - # Raise ValueError after all. - raise - - def register(self, fileobj, events, data=None): - """ Register a file object for a set of events to monitor. """ - if (not events) or (events & ~(EVENT_READ | EVENT_WRITE)): - raise ValueError("Invalid events: {0!r}".format(events)) - - key = SelectorKey(fileobj, self._fileobj_lookup(fileobj), events, data) - - if key.fd in self._fd_to_key: - raise KeyError("{0!r} (FD {1}) is already registered" - .format(fileobj, key.fd)) - - self._fd_to_key[key.fd] = key - return key - - def unregister(self, fileobj): - """ Unregister a file object from being monitored. """ - try: - key = self._fd_to_key.pop(self._fileobj_lookup(fileobj)) - except KeyError: - raise KeyError("{0!r} is not registered".format(fileobj)) - return key - - def modify(self, fileobj, events, data=None): - """ Change a registered file object monitored events and data. """ - # NOTE: Some subclasses optimize this operation even further. - try: - key = self._fd_to_key[self._fileobj_lookup(fileobj)] - except KeyError: - raise KeyError("{0!r} is not registered".format(fileobj)) - - if events != key.events: - self.unregister(fileobj) - key = self.register(fileobj, events, data) - - elif data != key.data: - # Use a shortcut to update the data. - key = key._replace(data=data) - self._fd_to_key[key.fd] = key - - return key - - def select(self, timeout=None): - """ Perform the actual selection until some monitored file objects - are ready or the timeout expires. """ - raise NotImplementedError() - - def close(self): - """ Close the selector. This must be called to ensure that all - underlying resources are freed. """ - self._fd_to_key.clear() - self._map = None - - def get_key(self, fileobj): - """ Return the key associated with a registered file object. """ - mapping = self.get_map() - if mapping is None: - raise RuntimeError("Selector is closed") - try: - return mapping[fileobj] - except KeyError: - raise KeyError("{0!r} is not registered".format(fileobj)) - - def get_map(self): - """ Return a mapping of file objects to selector keys """ - return self._map - - def _key_from_fd(self, fd): - """ Return the key associated to a given file descriptor - Return None if it is not found. """ - try: - return self._fd_to_key[fd] - except KeyError: - return None - - def __enter__(self): - return self - - def __exit__(self, *args): - self.close() - - -# Almost all platforms have select.select() -if hasattr(select, "select"): - class SelectSelector(BaseSelector): - """ Select-based selector. """ - def __init__(self): - super(SelectSelector, self).__init__() - self._readers = set() - self._writers = set() - - def register(self, fileobj, events, data=None): - key = super(SelectSelector, self).register(fileobj, events, data) - if events & EVENT_READ: - self._readers.add(key.fd) - if events & EVENT_WRITE: - self._writers.add(key.fd) - return key - - def unregister(self, fileobj): - key = super(SelectSelector, self).unregister(fileobj) - self._readers.discard(key.fd) - self._writers.discard(key.fd) - return key - - def _select(self, r, w, timeout=None): - """ Wrapper for select.select because timeout is a positional arg """ - return select.select(r, w, [], timeout) - - def select(self, timeout=None): - # Selecting on empty lists on Windows errors out. - if not len(self._readers) and not len(self._writers): - return [] - - timeout = None if timeout is None else max(timeout, 0.0) - ready = [] - r, w, _ = _syscall_wrapper(self._select, True, self._readers, - self._writers, timeout) - r = set(r) - w = set(w) - for fd in r | w: - events = 0 - if fd in r: - events |= EVENT_READ - if fd in w: - events |= EVENT_WRITE - - key = self._key_from_fd(fd) - if key: - ready.append((key, events & key.events)) - return ready - - -if hasattr(select, "poll"): - class PollSelector(BaseSelector): - """ Poll-based selector """ - def __init__(self): - super(PollSelector, self).__init__() - self._poll = select.poll() - - def register(self, fileobj, events, data=None): - key = super(PollSelector, self).register(fileobj, events, data) - event_mask = 0 - if events & EVENT_READ: - event_mask |= select.POLLIN - if events & EVENT_WRITE: - event_mask |= select.POLLOUT - self._poll.register(key.fd, event_mask) - return key - - def unregister(self, fileobj): - key = super(PollSelector, self).unregister(fileobj) - self._poll.unregister(key.fd) - return key - - def _wrap_poll(self, timeout=None): - """ Wrapper function for select.poll.poll() so that - _syscall_wrapper can work with only seconds. """ - if timeout is not None: - if timeout <= 0: - timeout = 0 - else: - # select.poll.poll() has a resolution of 1 millisecond, - # round away from zero to wait *at least* timeout seconds. - timeout = math.ceil(timeout * 1e3) - - result = self._poll.poll(timeout) - return result - - def select(self, timeout=None): - ready = [] - fd_events = _syscall_wrapper(self._wrap_poll, True, timeout=timeout) - for fd, event_mask in fd_events: - events = 0 - if event_mask & ~select.POLLIN: - events |= EVENT_WRITE - if event_mask & ~select.POLLOUT: - events |= EVENT_READ - - key = self._key_from_fd(fd) - if key: - ready.append((key, events & key.events)) - - return ready - - -if hasattr(select, "epoll"): - class EpollSelector(BaseSelector): - """ Epoll-based selector """ - def __init__(self): - super(EpollSelector, self).__init__() - self._epoll = select.epoll() - - def fileno(self): - return self._epoll.fileno() - - def register(self, fileobj, events, data=None): - key = super(EpollSelector, self).register(fileobj, events, data) - events_mask = 0 - if events & EVENT_READ: - events_mask |= select.EPOLLIN - if events & EVENT_WRITE: - events_mask |= select.EPOLLOUT - _syscall_wrapper(self._epoll.register, False, key.fd, events_mask) - return key - - def unregister(self, fileobj): - key = super(EpollSelector, self).unregister(fileobj) - try: - _syscall_wrapper(self._epoll.unregister, False, key.fd) - except SelectorError: - # This can occur when the fd was closed since registry. - pass - return key - - def select(self, timeout=None): - if timeout is not None: - if timeout <= 0: - timeout = 0.0 - else: - # select.epoll.poll() has a resolution of 1 millisecond - # but luckily takes seconds so we don't need a wrapper - # like PollSelector. Just for better rounding. - timeout = math.ceil(timeout * 1e3) * 1e-3 - timeout = float(timeout) - else: - timeout = -1.0 # epoll.poll() must have a float. - - # We always want at least 1 to ensure that select can be called - # with no file descriptors registered. Otherwise will fail. - max_events = max(len(self._fd_to_key), 1) - - ready = [] - fd_events = _syscall_wrapper(self._epoll.poll, True, - timeout=timeout, - maxevents=max_events) - for fd, event_mask in fd_events: - events = 0 - if event_mask & ~select.EPOLLIN: - events |= EVENT_WRITE - if event_mask & ~select.EPOLLOUT: - events |= EVENT_READ - - key = self._key_from_fd(fd) - if key: - ready.append((key, events & key.events)) - return ready - - def close(self): - self._epoll.close() - super(EpollSelector, self).close() - - -if hasattr(select, "kqueue"): - class KqueueSelector(BaseSelector): - """ Kqueue / Kevent-based selector """ - def __init__(self): - super(KqueueSelector, self).__init__() - self._kqueue = select.kqueue() - - def fileno(self): - return self._kqueue.fileno() - - def register(self, fileobj, events, data=None): - key = super(KqueueSelector, self).register(fileobj, events, data) - if events & EVENT_READ: - kevent = select.kevent(key.fd, - select.KQ_FILTER_READ, - select.KQ_EV_ADD) - - _syscall_wrapper(self._kqueue.control, False, [kevent], 0, 0) - - if events & EVENT_WRITE: - kevent = select.kevent(key.fd, - select.KQ_FILTER_WRITE, - select.KQ_EV_ADD) - - _syscall_wrapper(self._kqueue.control, False, [kevent], 0, 0) - - return key - - def unregister(self, fileobj): - key = super(KqueueSelector, self).unregister(fileobj) - if key.events & EVENT_READ: - kevent = select.kevent(key.fd, - select.KQ_FILTER_READ, - select.KQ_EV_DELETE) - try: - _syscall_wrapper(self._kqueue.control, False, [kevent], 0, 0) - except SelectorError: - pass - if key.events & EVENT_WRITE: - kevent = select.kevent(key.fd, - select.KQ_FILTER_WRITE, - select.KQ_EV_DELETE) - try: - _syscall_wrapper(self._kqueue.control, False, [kevent], 0, 0) - except SelectorError: - pass - - return key - - def select(self, timeout=None): - if timeout is not None: - timeout = max(timeout, 0) - - max_events = len(self._fd_to_key) * 2 - ready_fds = {} - - kevent_list = _syscall_wrapper(self._kqueue.control, True, - None, max_events, timeout) - - for kevent in kevent_list: - fd = kevent.ident - event_mask = kevent.filter - events = 0 - if event_mask == select.KQ_FILTER_READ: - events |= EVENT_READ - if event_mask == select.KQ_FILTER_WRITE: - events |= EVENT_WRITE - - key = self._key_from_fd(fd) - if key: - if key.fd not in ready_fds: - ready_fds[key.fd] = (key, events & key.events) - else: - old_events = ready_fds[key.fd][1] - ready_fds[key.fd] = (key, (events | old_events) & key.events) - - return list(ready_fds.values()) - - def close(self): - self._kqueue.close() - super(KqueueSelector, self).close() - - -# Choose the best implementation, roughly: -# kqueue == epoll > poll > select. Devpoll not supported. (See above) -# select() also can't accept a FD > FD_SETSIZE (usually around 1024) -if 'KqueueSelector' in globals(): # Platform-specific: Mac OS and BSD - DefaultSelector = KqueueSelector -elif 'EpollSelector' in globals(): # Platform-specific: Linux - DefaultSelector = EpollSelector -elif 'PollSelector' in globals(): # Platform-specific: Linux - DefaultSelector = PollSelector -elif 'SelectSelector' in globals(): # Platform-specific: Windows - DefaultSelector = SelectSelector -else: # Platform-specific: AppEngine - def no_selector(_): - raise ValueError("Platform does not have a selector") - DefaultSelector = no_selector - HAS_SELECT = False diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/ssl_.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/ssl_.py deleted file mode 100644 index c4c55df..0000000 --- a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/ssl_.py +++ /dev/null @@ -1,336 +0,0 @@ -from __future__ import absolute_import -import errno -import warnings -import hmac - -from binascii import hexlify, unhexlify -from hashlib import md5, sha1, sha256 - -from ..exceptions import SSLError, InsecurePlatformWarning, SNIMissingWarning - - -SSLContext = None -HAS_SNI = False -IS_PYOPENSSL = False - -# Maps the length of a digest to a possible hash function producing this digest -HASHFUNC_MAP = { - 32: md5, - 40: sha1, - 64: sha256, -} - - -def _const_compare_digest_backport(a, b): - """ - Compare two digests of equal length in constant time. - - The digests must be of type str/bytes. - Returns True if the digests match, and False otherwise. - """ - result = abs(len(a) - len(b)) - for l, r in zip(bytearray(a), bytearray(b)): - result |= l ^ r - return result == 0 - - -_const_compare_digest = getattr(hmac, 'compare_digest', - _const_compare_digest_backport) - - -try: # Test for SSL features - import ssl - from ssl import wrap_socket, CERT_NONE, PROTOCOL_SSLv23 - from ssl import HAS_SNI # Has SNI? -except ImportError: - pass - - -try: - from ssl import OP_NO_SSLv2, OP_NO_SSLv3, OP_NO_COMPRESSION -except ImportError: - OP_NO_SSLv2, OP_NO_SSLv3 = 0x1000000, 0x2000000 - OP_NO_COMPRESSION = 0x20000 - -# A secure default. -# Sources for more information on TLS ciphers: -# -# - https://wiki.mozilla.org/Security/Server_Side_TLS -# - https://www.ssllabs.com/projects/best-practices/index.html -# - https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/ -# -# The general intent is: -# - Prefer cipher suites that offer perfect forward secrecy (DHE/ECDHE), -# - prefer ECDHE over DHE for better performance, -# - prefer any AES-GCM and ChaCha20 over any AES-CBC for better performance and -# security, -# - prefer AES-GCM over ChaCha20 because hardware-accelerated AES is common, -# - disable NULL authentication, MD5 MACs and DSS for security reasons. -DEFAULT_CIPHERS = ':'.join([ - 'ECDH+AESGCM', - 'ECDH+CHACHA20', - 'DH+AESGCM', - 'DH+CHACHA20', - 'ECDH+AES256', - 'DH+AES256', - 'ECDH+AES128', - 'DH+AES', - 'RSA+AESGCM', - 'RSA+AES', - '!aNULL', - '!eNULL', - '!MD5', -]) - -try: - from ssl import SSLContext # Modern SSL? -except ImportError: - import sys - - class SSLContext(object): # Platform-specific: Python 2 & 3.1 - supports_set_ciphers = ((2, 7) <= sys.version_info < (3,) or - (3, 2) <= sys.version_info) - - def __init__(self, protocol_version): - self.protocol = protocol_version - # Use default values from a real SSLContext - self.check_hostname = False - self.verify_mode = ssl.CERT_NONE - self.ca_certs = None - self.options = 0 - self.certfile = None - self.keyfile = None - self.ciphers = None - - def load_cert_chain(self, certfile, keyfile): - self.certfile = certfile - self.keyfile = keyfile - - def load_verify_locations(self, cafile=None, capath=None): - self.ca_certs = cafile - - if capath is not None: - raise SSLError("CA directories not supported in older Pythons") - - def set_ciphers(self, cipher_suite): - if not self.supports_set_ciphers: - raise TypeError( - 'Your version of Python does not support setting ' - 'a custom cipher suite. Please upgrade to Python ' - '2.7, 3.2, or later if you need this functionality.' - ) - self.ciphers = cipher_suite - - def wrap_socket(self, socket, server_hostname=None, server_side=False): - warnings.warn( - 'A true SSLContext object is not available. This prevents ' - 'urllib3 from configuring SSL appropriately and may cause ' - 'certain SSL connections to fail. You can upgrade to a newer ' - 'version of Python to solve this. For more information, see ' - 'https://urllib3.readthedocs.io/en/latest/advanced-usage.html' - '#ssl-warnings', - InsecurePlatformWarning - ) - kwargs = { - 'keyfile': self.keyfile, - 'certfile': self.certfile, - 'ca_certs': self.ca_certs, - 'cert_reqs': self.verify_mode, - 'ssl_version': self.protocol, - 'server_side': server_side, - } - if self.supports_set_ciphers: # Platform-specific: Python 2.7+ - return wrap_socket(socket, ciphers=self.ciphers, **kwargs) - else: # Platform-specific: Python 2.6 - return wrap_socket(socket, **kwargs) - - -def assert_fingerprint(cert, fingerprint): - """ - Checks if given fingerprint matches the supplied certificate. - - :param cert: - Certificate as bytes object. - :param fingerprint: - Fingerprint as string of hexdigits, can be interspersed by colons. - """ - - fingerprint = fingerprint.replace(':', '').lower() - digest_length = len(fingerprint) - hashfunc = HASHFUNC_MAP.get(digest_length) - if not hashfunc: - raise SSLError( - 'Fingerprint of invalid length: {0}'.format(fingerprint)) - - # We need encode() here for py32; works on py2 and p33. - fingerprint_bytes = unhexlify(fingerprint.encode()) - - cert_digest = hashfunc(cert).digest() - - if not _const_compare_digest(cert_digest, fingerprint_bytes): - raise SSLError('Fingerprints did not match. Expected "{0}", got "{1}".' - .format(fingerprint, hexlify(cert_digest))) - - -def resolve_cert_reqs(candidate): - """ - Resolves the argument to a numeric constant, which can be passed to - the wrap_socket function/method from the ssl module. - Defaults to :data:`ssl.CERT_NONE`. - If given a string it is assumed to be the name of the constant in the - :mod:`ssl` module or its abbrevation. - (So you can specify `REQUIRED` instead of `CERT_REQUIRED`. - If it's neither `None` nor a string we assume it is already the numeric - constant which can directly be passed to wrap_socket. - """ - if candidate is None: - return CERT_NONE - - if isinstance(candidate, str): - res = getattr(ssl, candidate, None) - if res is None: - res = getattr(ssl, 'CERT_' + candidate) - return res - - return candidate - - -def resolve_ssl_version(candidate): - """ - like resolve_cert_reqs - """ - if candidate is None: - return PROTOCOL_SSLv23 - - if isinstance(candidate, str): - res = getattr(ssl, candidate, None) - if res is None: - res = getattr(ssl, 'PROTOCOL_' + candidate) - return res - - return candidate - - -def create_urllib3_context(ssl_version=None, cert_reqs=None, - options=None, ciphers=None): - """All arguments have the same meaning as ``ssl_wrap_socket``. - - By default, this function does a lot of the same work that - ``ssl.create_default_context`` does on Python 3.4+. It: - - - Disables SSLv2, SSLv3, and compression - - Sets a restricted set of server ciphers - - If you wish to enable SSLv3, you can do:: - - from urllib3.util import ssl_ - context = ssl_.create_urllib3_context() - context.options &= ~ssl_.OP_NO_SSLv3 - - You can do the same to enable compression (substituting ``COMPRESSION`` - for ``SSLv3`` in the last line above). - - :param ssl_version: - The desired protocol version to use. This will default to - PROTOCOL_SSLv23 which will negotiate the highest protocol that both - the server and your installation of OpenSSL support. - :param cert_reqs: - Whether to require the certificate verification. This defaults to - ``ssl.CERT_REQUIRED``. - :param options: - Specific OpenSSL options. These default to ``ssl.OP_NO_SSLv2``, - ``ssl.OP_NO_SSLv3``, ``ssl.OP_NO_COMPRESSION``. - :param ciphers: - Which cipher suites to allow the server to select. - :returns: - Constructed SSLContext object with specified options - :rtype: SSLContext - """ - context = SSLContext(ssl_version or ssl.PROTOCOL_SSLv23) - - # Setting the default here, as we may have no ssl module on import - cert_reqs = ssl.CERT_REQUIRED if cert_reqs is None else cert_reqs - - if options is None: - options = 0 - # SSLv2 is easily broken and is considered harmful and dangerous - options |= OP_NO_SSLv2 - # SSLv3 has several problems and is now dangerous - options |= OP_NO_SSLv3 - # Disable compression to prevent CRIME attacks for OpenSSL 1.0+ - # (issue #309) - options |= OP_NO_COMPRESSION - - context.options |= options - - if getattr(context, 'supports_set_ciphers', True): # Platform-specific: Python 2.6 - context.set_ciphers(ciphers or DEFAULT_CIPHERS) - - context.verify_mode = cert_reqs - if getattr(context, 'check_hostname', None) is not None: # Platform-specific: Python 3.2 - # We do our own verification, including fingerprints and alternative - # hostnames. So disable it here - context.check_hostname = False - return context - - -def ssl_wrap_socket(sock, keyfile=None, certfile=None, cert_reqs=None, - ca_certs=None, server_hostname=None, - ssl_version=None, ciphers=None, ssl_context=None, - ca_cert_dir=None): - """ - All arguments except for server_hostname, ssl_context, and ca_cert_dir have - the same meaning as they do when using :func:`ssl.wrap_socket`. - - :param server_hostname: - When SNI is supported, the expected hostname of the certificate - :param ssl_context: - A pre-made :class:`SSLContext` object. If none is provided, one will - be created using :func:`create_urllib3_context`. - :param ciphers: - A string of ciphers we wish the client to support. This is not - supported on Python 2.6 as the ssl module does not support it. - :param ca_cert_dir: - A directory containing CA certificates in multiple separate files, as - supported by OpenSSL's -CApath flag or the capath argument to - SSLContext.load_verify_locations(). - """ - context = ssl_context - if context is None: - # Note: This branch of code and all the variables in it are no longer - # used by urllib3 itself. We should consider deprecating and removing - # this code. - context = create_urllib3_context(ssl_version, cert_reqs, - ciphers=ciphers) - - if ca_certs or ca_cert_dir: - try: - context.load_verify_locations(ca_certs, ca_cert_dir) - except IOError as e: # Platform-specific: Python 2.6, 2.7, 3.2 - raise SSLError(e) - # Py33 raises FileNotFoundError which subclasses OSError - # These are not equivalent unless we check the errno attribute - except OSError as e: # Platform-specific: Python 3.3 and beyond - if e.errno == errno.ENOENT: - raise SSLError(e) - raise - elif getattr(context, 'load_default_certs', None) is not None: - # try to load OS default certs; works well on Windows (require Python3.4+) - context.load_default_certs() - - if certfile: - context.load_cert_chain(certfile, keyfile) - if HAS_SNI: # Platform-specific: OpenSSL with enabled SNI - return context.wrap_socket(sock, server_hostname=server_hostname) - - warnings.warn( - 'An HTTPS request has been made, but the SNI (Subject Name ' - 'Indication) extension to TLS is not available on this platform. ' - 'This may cause the server to present an incorrect TLS ' - 'certificate, which can cause validation failures. You can upgrade to ' - 'a newer version of Python to solve this. For more information, see ' - 'https://urllib3.readthedocs.io/en/latest/advanced-usage.html' - '#ssl-warnings', - SNIMissingWarning - ) - return context.wrap_socket(sock) diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/timeout.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/timeout.py deleted file mode 100644 index cec817e..0000000 --- a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/timeout.py +++ /dev/null @@ -1,242 +0,0 @@ -from __future__ import absolute_import -# The default socket timeout, used by httplib to indicate that no timeout was -# specified by the user -from socket import _GLOBAL_DEFAULT_TIMEOUT -import time - -from ..exceptions import TimeoutStateError - -# A sentinel value to indicate that no timeout was specified by the user in -# urllib3 -_Default = object() - - -# Use time.monotonic if available. -current_time = getattr(time, "monotonic", time.time) - - -class Timeout(object): - """ Timeout configuration. - - Timeouts can be defined as a default for a pool:: - - timeout = Timeout(connect=2.0, read=7.0) - http = PoolManager(timeout=timeout) - response = http.request('GET', 'http://example.com/') - - Or per-request (which overrides the default for the pool):: - - response = http.request('GET', 'http://example.com/', timeout=Timeout(10)) - - Timeouts can be disabled by setting all the parameters to ``None``:: - - no_timeout = Timeout(connect=None, read=None) - response = http.request('GET', 'http://example.com/, timeout=no_timeout) - - - :param total: - This combines the connect and read timeouts into one; the read timeout - will be set to the time leftover from the connect attempt. In the - event that both a connect timeout and a total are specified, or a read - timeout and a total are specified, the shorter timeout will be applied. - - Defaults to None. - - :type total: integer, float, or None - - :param connect: - The maximum amount of time to wait for a connection attempt to a server - to succeed. Omitting the parameter will default the connect timeout to - the system default, probably `the global default timeout in socket.py - <http://hg.python.org/cpython/file/603b4d593758/Lib/socket.py#l535>`_. - None will set an infinite timeout for connection attempts. - - :type connect: integer, float, or None - - :param read: - The maximum amount of time to wait between consecutive - read operations for a response from the server. Omitting - the parameter will default the read timeout to the system - default, probably `the global default timeout in socket.py - <http://hg.python.org/cpython/file/603b4d593758/Lib/socket.py#l535>`_. - None will set an infinite timeout. - - :type read: integer, float, or None - - .. note:: - - Many factors can affect the total amount of time for urllib3 to return - an HTTP response. - - For example, Python's DNS resolver does not obey the timeout specified - on the socket. Other factors that can affect total request time include - high CPU load, high swap, the program running at a low priority level, - or other behaviors. - - In addition, the read and total timeouts only measure the time between - read operations on the socket connecting the client and the server, - not the total amount of time for the request to return a complete - response. For most requests, the timeout is raised because the server - has not sent the first byte in the specified time. This is not always - the case; if a server streams one byte every fifteen seconds, a timeout - of 20 seconds will not trigger, even though the request will take - several minutes to complete. - - If your goal is to cut off any request after a set amount of wall clock - time, consider having a second "watcher" thread to cut off a slow - request. - """ - - #: A sentinel object representing the default timeout value - DEFAULT_TIMEOUT = _GLOBAL_DEFAULT_TIMEOUT - - def __init__(self, total=None, connect=_Default, read=_Default): - self._connect = self._validate_timeout(connect, 'connect') - self._read = self._validate_timeout(read, 'read') - self.total = self._validate_timeout(total, 'total') - self._start_connect = None - - def __str__(self): - return '%s(connect=%r, read=%r, total=%r)' % ( - type(self).__name__, self._connect, self._read, self.total) - - @classmethod - def _validate_timeout(cls, value, name): - """ Check that a timeout attribute is valid. - - :param value: The timeout value to validate - :param name: The name of the timeout attribute to validate. This is - used to specify in error messages. - :return: The validated and casted version of the given value. - :raises ValueError: If it is a numeric value less than or equal to - zero, or the type is not an integer, float, or None. - """ - if value is _Default: - return cls.DEFAULT_TIMEOUT - - if value is None or value is cls.DEFAULT_TIMEOUT: - return value - - if isinstance(value, bool): - raise ValueError("Timeout cannot be a boolean value. It must " - "be an int, float or None.") - try: - float(value) - except (TypeError, ValueError): - raise ValueError("Timeout value %s was %s, but it must be an " - "int, float or None." % (name, value)) - - try: - if value <= 0: - raise ValueError("Attempted to set %s timeout to %s, but the " - "timeout cannot be set to a value less " - "than or equal to 0." % (name, value)) - except TypeError: # Python 3 - raise ValueError("Timeout value %s was %s, but it must be an " - "int, float or None." % (name, value)) - - return value - - @classmethod - def from_float(cls, timeout): - """ Create a new Timeout from a legacy timeout value. - - The timeout value used by httplib.py sets the same timeout on the - connect(), and recv() socket requests. This creates a :class:`Timeout` - object that sets the individual timeouts to the ``timeout`` value - passed to this function. - - :param timeout: The legacy timeout value. - :type timeout: integer, float, sentinel default object, or None - :return: Timeout object - :rtype: :class:`Timeout` - """ - return Timeout(read=timeout, connect=timeout) - - def clone(self): - """ Create a copy of the timeout object - - Timeout properties are stored per-pool but each request needs a fresh - Timeout object to ensure each one has its own start/stop configured. - - :return: a copy of the timeout object - :rtype: :class:`Timeout` - """ - # We can't use copy.deepcopy because that will also create a new object - # for _GLOBAL_DEFAULT_TIMEOUT, which socket.py uses as a sentinel to - # detect the user default. - return Timeout(connect=self._connect, read=self._read, - total=self.total) - - def start_connect(self): - """ Start the timeout clock, used during a connect() attempt - - :raises urllib3.exceptions.TimeoutStateError: if you attempt - to start a timer that has been started already. - """ - if self._start_connect is not None: - raise TimeoutStateError("Timeout timer has already been started.") - self._start_connect = current_time() - return self._start_connect - - def get_connect_duration(self): - """ Gets the time elapsed since the call to :meth:`start_connect`. - - :return: Elapsed time. - :rtype: float - :raises urllib3.exceptions.TimeoutStateError: if you attempt - to get duration for a timer that hasn't been started. - """ - if self._start_connect is None: - raise TimeoutStateError("Can't get connect duration for timer " - "that has not started.") - return current_time() - self._start_connect - - @property - def connect_timeout(self): - """ Get the value to use when setting a connection timeout. - - This will be a positive float or integer, the value None - (never timeout), or the default system timeout. - - :return: Connect timeout. - :rtype: int, float, :attr:`Timeout.DEFAULT_TIMEOUT` or None - """ - if self.total is None: - return self._connect - - if self._connect is None or self._connect is self.DEFAULT_TIMEOUT: - return self.total - - return min(self._connect, self.total) - - @property - def read_timeout(self): - """ Get the value for the read timeout. - - This assumes some time has elapsed in the connection timeout and - computes the read timeout appropriately. - - If self.total is set, the read timeout is dependent on the amount of - time taken by the connect timeout. If the connection time has not been - established, a :exc:`~urllib3.exceptions.TimeoutStateError` will be - raised. - - :return: Value to use for the read timeout. - :rtype: int, float, :attr:`Timeout.DEFAULT_TIMEOUT` or None - :raises urllib3.exceptions.TimeoutStateError: If :meth:`start_connect` - has not yet been called on this object. - """ - if (self.total is not None and - self.total is not self.DEFAULT_TIMEOUT and - self._read is not None and - self._read is not self.DEFAULT_TIMEOUT): - # In case the connect timeout has not yet been established. - if self._start_connect is None: - return self._read - return max(0, min(self.total - self.get_connect_duration(), - self._read)) - elif self.total is not None and self.total is not self.DEFAULT_TIMEOUT: - return max(0, self.total - self.get_connect_duration()) - else: - return self._read diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/url.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/url.py deleted file mode 100644 index 61a326e..0000000 --- a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/url.py +++ /dev/null @@ -1,226 +0,0 @@ -from __future__ import absolute_import -from collections import namedtuple - -from ..exceptions import LocationParseError - - -url_attrs = ['scheme', 'auth', 'host', 'port', 'path', 'query', 'fragment'] - - -class Url(namedtuple('Url', url_attrs)): - """ - Datastructure for representing an HTTP URL. Used as a return value for - :func:`parse_url`. Both the scheme and host are normalized as they are - both case-insensitive according to RFC 3986. - """ - __slots__ = () - - def __new__(cls, scheme=None, auth=None, host=None, port=None, path=None, - query=None, fragment=None): - if path and not path.startswith('/'): - path = '/' + path - if scheme: - scheme = scheme.lower() - if host: - host = host.lower() - return super(Url, cls).__new__(cls, scheme, auth, host, port, path, - query, fragment) - - @property - def hostname(self): - """For backwards-compatibility with urlparse. We're nice like that.""" - return self.host - - @property - def request_uri(self): - """Absolute path including the query string.""" - uri = self.path or '/' - - if self.query is not None: - uri += '?' + self.query - - return uri - - @property - def netloc(self): - """Network location including host and port""" - if self.port: - return '%s:%d' % (self.host, self.port) - return self.host - - @property - def url(self): - """ - Convert self into a url - - This function should more or less round-trip with :func:`.parse_url`. The - returned url may not be exactly the same as the url inputted to - :func:`.parse_url`, but it should be equivalent by the RFC (e.g., urls - with a blank port will have : removed). - - Example: :: - - >>> U = parse_url('http://google.com/mail/') - >>> U.url - 'http://google.com/mail/' - >>> Url('http', 'username:password', 'host.com', 80, - ... '/path', 'query', 'fragment').url - 'http://username:password@host.com:80/path?query#fragment' - """ - scheme, auth, host, port, path, query, fragment = self - url = '' - - # We use "is not None" we want things to happen with empty strings (or 0 port) - if scheme is not None: - url += scheme + '://' - if auth is not None: - url += auth + '@' - if host is not None: - url += host - if port is not None: - url += ':' + str(port) - if path is not None: - url += path - if query is not None: - url += '?' + query - if fragment is not None: - url += '#' + fragment - - return url - - def __str__(self): - return self.url - - -def split_first(s, delims): - """ - Given a string and an iterable of delimiters, split on the first found - delimiter. Return two split parts and the matched delimiter. - - If not found, then the first part is the full input string. - - Example:: - - >>> split_first('foo/bar?baz', '?/=') - ('foo', 'bar?baz', '/') - >>> split_first('foo/bar?baz', '123') - ('foo/bar?baz', '', None) - - Scales linearly with number of delims. Not ideal for large number of delims. - """ - min_idx = None - min_delim = None - for d in delims: - idx = s.find(d) - if idx < 0: - continue - - if min_idx is None or idx < min_idx: - min_idx = idx - min_delim = d - - if min_idx is None or min_idx < 0: - return s, '', None - - return s[:min_idx], s[min_idx + 1:], min_delim - - -def parse_url(url): - """ - Given a url, return a parsed :class:`.Url` namedtuple. Best-effort is - performed to parse incomplete urls. Fields not provided will be None. - - Partly backwards-compatible with :mod:`urlparse`. - - Example:: - - >>> parse_url('http://google.com/mail/') - Url(scheme='http', host='google.com', port=None, path='/mail/', ...) - >>> parse_url('google.com:80') - Url(scheme=None, host='google.com', port=80, path=None, ...) - >>> parse_url('/foo?bar') - Url(scheme=None, host=None, port=None, path='/foo', query='bar', ...) - """ - - # While this code has overlap with stdlib's urlparse, it is much - # simplified for our needs and less annoying. - # Additionally, this implementations does silly things to be optimal - # on CPython. - - if not url: - # Empty - return Url() - - scheme = None - auth = None - host = None - port = None - path = None - fragment = None - query = None - - # Scheme - if '://' in url: - scheme, url = url.split('://', 1) - - # Find the earliest Authority Terminator - # (http://tools.ietf.org/html/rfc3986#section-3.2) - url, path_, delim = split_first(url, ['/', '?', '#']) - - if delim: - # Reassemble the path - path = delim + path_ - - # Auth - if '@' in url: - # Last '@' denotes end of auth part - auth, url = url.rsplit('@', 1) - - # IPv6 - if url and url[0] == '[': - host, url = url.split(']', 1) - host += ']' - - # Port - if ':' in url: - _host, port = url.split(':', 1) - - if not host: - host = _host - - if port: - # If given, ports must be integers. No whitespace, no plus or - # minus prefixes, no non-integer digits such as ^2 (superscript). - if not port.isdigit(): - raise LocationParseError(url) - try: - port = int(port) - except ValueError: - raise LocationParseError(url) - else: - # Blank ports are cool, too. (rfc3986#section-3.2.3) - port = None - - elif not host and url: - host = url - - if not path: - return Url(scheme, auth, host, port, path, query, fragment) - - # Fragment - if '#' in path: - path, fragment = path.split('#', 1) - - # Query - if '?' in path: - path, query = path.split('?', 1) - - return Url(scheme, auth, host, port, path, query, fragment) - - -def get_host(url): - """ - Deprecated. Use :func:`parse_url` instead. - """ - p = parse_url(url) - return p.scheme or 'http', p.hostname, p.port diff --git a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/wait.py b/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/wait.py deleted file mode 100644 index cb396e5..0000000 --- a/venv/lib/python3.8/site-packages/telegram/vendor/ptb_urllib3/urllib3/util/wait.py +++ /dev/null @@ -1,40 +0,0 @@ -from .selectors import ( - HAS_SELECT, - DefaultSelector, - EVENT_READ, - EVENT_WRITE -) - - -def _wait_for_io_events(socks, events, timeout=None): - """ Waits for IO events to be available from a list of sockets - or optionally a single socket if passed in. Returns a list of - sockets that can be interacted with immediately. """ - if not HAS_SELECT: - raise ValueError('Platform does not have a selector') - if not isinstance(socks, list): - # Probably just a single socket. - if hasattr(socks, "fileno"): - socks = [socks] - # Otherwise it might be a non-list iterable. - else: - socks = list(socks) - with DefaultSelector() as selector: - for sock in socks: - selector.register(sock, events) - return [key[0].fileobj for key in - selector.select(timeout) if key[1] & events] - - -def wait_for_read(socks, timeout=None): - """ Waits for reading to be available from a list of sockets - or optionally a single socket if passed in. Returns a list of - sockets that can be read from immediately. """ - return _wait_for_io_events(socks, EVENT_READ, timeout) - - -def wait_for_write(socks, timeout=None): - """ Waits for writing to be available from a list of sockets - or optionally a single socket if passed in. Returns a list of - sockets that can be written to immediately. """ - return _wait_for_io_events(socks, EVENT_WRITE, timeout) diff --git a/venv/lib/python3.8/site-packages/telegram/version.py b/venv/lib/python3.8/site-packages/telegram/version.py deleted file mode 100644 index 47bf17d..0000000 --- a/venv/lib/python3.8/site-packages/telegram/version.py +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -# pylint: disable=C0114 - -from telegram import constants - -__version__ = '13.6' -bot_api_version = constants.BOT_API_VERSION # pylint: disable=C0103 diff --git a/venv/lib/python3.8/site-packages/telegram/voicechat.py b/venv/lib/python3.8/site-packages/telegram/voicechat.py deleted file mode 100644 index 4fb7b53..0000000 --- a/venv/lib/python3.8/site-packages/telegram/voicechat.py +++ /dev/null @@ -1,169 +0,0 @@ -#!/usr/bin/env python -# pylint: disable=R0903 -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains objects related to Telegram voice chats.""" - -import datetime as dtm -from typing import TYPE_CHECKING, Any, Optional, List - -from telegram import TelegramObject, User -from telegram.utils.helpers import from_timestamp, to_timestamp -from telegram.utils.types import JSONDict - -if TYPE_CHECKING: - from telegram import Bot - - -class VoiceChatStarted(TelegramObject): - """ - This object represents a service message about a voice - chat started in the chat. Currently holds no information. - - .. versionadded:: 13.4 - """ - - __slots__ = () - - def __init__(self, **_kwargs: Any): # skipcq: PTC-W0049 - pass - - -class VoiceChatEnded(TelegramObject): - """ - This object represents a service message about a - voice chat ended in the chat. - - Objects of this class are comparable in terms of equality. - Two objects of this class are considered equal, if their - :attr:`duration` are equal. - - .. versionadded:: 13.4 - - Args: - duration (:obj:`int`): Voice chat duration in seconds. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - duration (:obj:`int`): Voice chat duration in seconds. - - """ - - __slots__ = ('duration', '_id_attrs') - - def __init__(self, duration: int, **_kwargs: Any) -> None: - self.duration = int(duration) if duration is not None else None - self._id_attrs = (self.duration,) - - -class VoiceChatParticipantsInvited(TelegramObject): - """ - This object represents a service message about - new members invited to a voice chat. - - Objects of this class are comparable in terms of equality. - Two objects of this class are considered equal, if their - :attr:`users` are equal. - - .. versionadded:: 13.4 - - Args: - users (List[:class:`telegram.User`]): New members that - were invited to the voice chat. - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - users (List[:class:`telegram.User`]): New members that - were invited to the voice chat. - - """ - - __slots__ = ('users', '_id_attrs') - - def __init__(self, users: List[User], **_kwargs: Any) -> None: - self.users = users - self._id_attrs = (self.users,) - - def __hash__(self) -> int: - return hash(tuple(self.users)) - - @classmethod - def de_json( - cls, data: Optional[JSONDict], bot: 'Bot' - ) -> Optional['VoiceChatParticipantsInvited']: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data['users'] = User.de_list(data.get('users', []), bot) - return cls(**data) - - def to_dict(self) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict() - - data["users"] = [u.to_dict() for u in self.users] - return data - - -class VoiceChatScheduled(TelegramObject): - """This object represents a service message about a voice chat scheduled in the chat. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`start_date` are equal. - - Args: - start_date (:obj:`datetime.datetime`): Point in time (Unix timestamp) when the voice - chat is supposed to be started by a chat administrator - **kwargs (:obj:`dict`): Arbitrary keyword arguments. - - Attributes: - start_date (:obj:`datetime.datetime`): Point in time (Unix timestamp) when the voice - chat is supposed to be started by a chat administrator - - """ - - __slots__ = ('start_date', '_id_attrs') - - def __init__(self, start_date: dtm.datetime, **_kwargs: Any) -> None: - self.start_date = start_date - - self._id_attrs = (self.start_date,) - - @classmethod - def de_json(cls, data: Optional[JSONDict], bot: 'Bot') -> Optional['VoiceChatScheduled']: - """See :meth:`telegram.TelegramObject.de_json`.""" - data = cls._parse_data(data) - - if not data: - return None - - data['start_date'] = from_timestamp(data['start_date']) - - return cls(**data, bot=bot) - - def to_dict(self) -> JSONDict: - """See :meth:`telegram.TelegramObject.to_dict`.""" - data = super().to_dict() - - # Required - data['start_date'] = to_timestamp(self.start_date) - - return data diff --git a/venv/lib/python3.8/site-packages/telegram/webhookinfo.py b/venv/lib/python3.8/site-packages/telegram/webhookinfo.py deleted file mode 100644 index 0fc6741..0000000 --- a/venv/lib/python3.8/site-packages/telegram/webhookinfo.py +++ /dev/null @@ -1,110 +0,0 @@ -#!/usr/bin/env python -# -# A library that provides a Python interface to the Telegram Bot API -# Copyright (C) 2015-2021 -# Leandro Toledo de Souza <devs@python-telegram-bot.org> -# -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser Public License for more details. -# -# You should have received a copy of the GNU Lesser Public License -# along with this program. If not, see [http://www.gnu.org/licenses/]. -"""This module contains an object that represents a Telegram WebhookInfo.""" - -from typing import Any, List - -from telegram import TelegramObject - - -class WebhookInfo(TelegramObject): - """This object represents a Telegram WebhookInfo. - - Contains information about the current status of a webhook. - - Objects of this class are comparable in terms of equality. Two objects of this class are - considered equal, if their :attr:`url`, :attr:`has_custom_certificate`, - :attr:`pending_update_count`, :attr:`ip_address`, :attr:`last_error_date`, - :attr:`last_error_message`, :attr:`max_connections` and :attr:`allowed_updates` are equal. - - Args: - url (:obj:`str`): Webhook URL, may be empty if webhook is not set up. - has_custom_certificate (:obj:`bool`): :obj:`True`, if a custom certificate was provided for - webhook certificate checks. - pending_update_count (:obj:`int`): Number of updates awaiting delivery. - ip_address (:obj:`str`, optional): Currently used webhook IP address. - last_error_date (:obj:`int`, optional): Unix time for the most recent error that happened - when trying to deliver an update via webhook. - last_error_message (:obj:`str`, optional): Error message in human-readable format for the - most recent error that happened when trying to deliver an update via webhook. - max_connections (:obj:`int`, optional): Maximum allowed number of simultaneous HTTPS - connections to the webhook for update delivery. - allowed_updates (List[:obj:`str`], optional): A list of update types the bot is subscribed - to. Defaults to all update types, except :attr:`telegram.Update.chat_member`. - - Attributes: - url (:obj:`str`): Webhook URL. - has_custom_certificate (:obj:`bool`): If a custom certificate was provided for webhook. - pending_update_count (:obj:`int`): Number of updates awaiting delivery. - ip_address (:obj:`str`): Optional. Currently used webhook IP address. - last_error_date (:obj:`int`): Optional. Unix time for the most recent error that happened. - last_error_message (:obj:`str`): Optional. Error message in human-readable format. - max_connections (:obj:`int`): Optional. Maximum allowed number of simultaneous HTTPS - connections. - allowed_updates (List[:obj:`str`]): Optional. A list of update types the bot is subscribed - to. Defaults to all update types, except :attr:`telegram.Update.chat_member`. - - """ - - __slots__ = ( - 'allowed_updates', - 'url', - 'max_connections', - 'last_error_date', - 'ip_address', - 'last_error_message', - 'pending_update_count', - 'has_custom_certificate', - '_id_attrs', - ) - - def __init__( - self, - url: str, - has_custom_certificate: bool, - pending_update_count: int, - last_error_date: int = None, - last_error_message: str = None, - max_connections: int = None, - allowed_updates: List[str] = None, - ip_address: str = None, - **_kwargs: Any, - ): - # Required - self.url = url - self.has_custom_certificate = has_custom_certificate - self.pending_update_count = pending_update_count - - # Optional - self.ip_address = ip_address - self.last_error_date = last_error_date - self.last_error_message = last_error_message - self.max_connections = max_connections - self.allowed_updates = allowed_updates - - self._id_attrs = ( - self.url, - self.has_custom_certificate, - self.pending_update_count, - self.ip_address, - self.last_error_date, - self.last_error_message, - self.max_connections, - self.allowed_updates, - ) diff --git a/venv/lib/python3.8/site-packages/tornado-6.1.dist-info/INSTALLER b/venv/lib/python3.8/site-packages/tornado-6.1.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.8/site-packages/tornado-6.1.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.8/site-packages/tornado-6.1.dist-info/LICENSE b/venv/lib/python3.8/site-packages/tornado-6.1.dist-info/LICENSE deleted file mode 100644 index d645695..0000000 --- a/venv/lib/python3.8/site-packages/tornado-6.1.dist-info/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - 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/venv/lib/python3.8/site-packages/tornado-6.1.dist-info/METADATA b/venv/lib/python3.8/site-packages/tornado-6.1.dist-info/METADATA deleted file mode 100644 index 98ff7b2..0000000 --- a/venv/lib/python3.8/site-packages/tornado-6.1.dist-info/METADATA +++ /dev/null @@ -1,70 +0,0 @@ -Metadata-Version: 2.1 -Name: tornado -Version: 6.1 -Summary: Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed. -Home-page: http://www.tornadoweb.org/ -Author: Facebook -Author-email: python-tornado@googlegroups.com -License: http://www.apache.org/licenses/LICENSE-2.0 -Platform: UNKNOWN -Classifier: License :: OSI Approved :: Apache Software License -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: Programming Language :: Python :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Requires-Python: >= 3.5 - -Tornado Web Server -================== - -.. image:: https://badges.gitter.im/Join%20Chat.svg - :alt: Join the chat at https://gitter.im/tornadoweb/tornado - :target: https://gitter.im/tornadoweb/tornado?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge - -`Tornado <http://www.tornadoweb.org>`_ is a Python web framework and -asynchronous networking library, originally developed at `FriendFeed -<http://friendfeed.com>`_. By using non-blocking network I/O, Tornado -can scale to tens of thousands of open connections, making it ideal for -`long polling <http://en.wikipedia.org/wiki/Push_technology#Long_Polling>`_, -`WebSockets <http://en.wikipedia.org/wiki/WebSocket>`_, and other -applications that require a long-lived connection to each user. - -Hello, world ------------- - -Here is a simple "Hello, world" example web app for Tornado: - -.. code-block:: python - - import tornado.ioloop - import tornado.web - - class MainHandler(tornado.web.RequestHandler): - def get(self): - self.write("Hello, world") - - def make_app(): - return tornado.web.Application([ - (r"/", MainHandler), - ]) - - if __name__ == "__main__": - app = make_app() - app.listen(8888) - tornado.ioloop.IOLoop.current().start() - -This example does not use any of Tornado's asynchronous features; for -that see this `simple chat room -<https://github.com/tornadoweb/tornado/tree/stable/demos/chat>`_. - -Documentation -------------- - -Documentation and links to additional resources are available at -https://www.tornadoweb.org - - diff --git a/venv/lib/python3.8/site-packages/tornado-6.1.dist-info/RECORD b/venv/lib/python3.8/site-packages/tornado-6.1.dist-info/RECORD deleted file mode 100644 index 1f330ba..0000000 --- a/venv/lib/python3.8/site-packages/tornado-6.1.dist-info/RECORD +++ /dev/null @@ -1,165 +0,0 @@ -tornado-6.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -tornado-6.1.dist-info/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358 -tornado-6.1.dist-info/METADATA,sha256=Wb23YO89rBkEgjfDwACNao8i7DcDIEBkVdV-cxmxER4,2435 -tornado-6.1.dist-info/RECORD,, -tornado-6.1.dist-info/WHEEL,sha256=3Rn77v1cOIQWUJHbJxwJJ4HycjuBQ6DIO-hbFDX-kLU,111 -tornado-6.1.dist-info/top_level.txt,sha256=5QAK1MeNpWgYdqWoU8iYlDuGB8j6NDPgx-uSUHTe0A4,8 -tornado/__init__.py,sha256=ME8HXlhSOfaX_8S2iYiSI1Nx9PMWK6HwsHfQDg20XpU,1018 -tornado/__pycache__/__init__.cpython-38.pyc,, -tornado/__pycache__/_locale_data.cpython-38.pyc,, -tornado/__pycache__/auth.cpython-38.pyc,, -tornado/__pycache__/autoreload.cpython-38.pyc,, -tornado/__pycache__/concurrent.cpython-38.pyc,, -tornado/__pycache__/curl_httpclient.cpython-38.pyc,, -tornado/__pycache__/escape.cpython-38.pyc,, -tornado/__pycache__/gen.cpython-38.pyc,, -tornado/__pycache__/http1connection.cpython-38.pyc,, -tornado/__pycache__/httpclient.cpython-38.pyc,, -tornado/__pycache__/httpserver.cpython-38.pyc,, -tornado/__pycache__/httputil.cpython-38.pyc,, -tornado/__pycache__/ioloop.cpython-38.pyc,, -tornado/__pycache__/iostream.cpython-38.pyc,, -tornado/__pycache__/locale.cpython-38.pyc,, -tornado/__pycache__/locks.cpython-38.pyc,, -tornado/__pycache__/log.cpython-38.pyc,, -tornado/__pycache__/netutil.cpython-38.pyc,, -tornado/__pycache__/options.cpython-38.pyc,, -tornado/__pycache__/process.cpython-38.pyc,, -tornado/__pycache__/queues.cpython-38.pyc,, -tornado/__pycache__/routing.cpython-38.pyc,, -tornado/__pycache__/simple_httpclient.cpython-38.pyc,, -tornado/__pycache__/tcpclient.cpython-38.pyc,, -tornado/__pycache__/tcpserver.cpython-38.pyc,, -tornado/__pycache__/template.cpython-38.pyc,, -tornado/__pycache__/testing.cpython-38.pyc,, -tornado/__pycache__/util.cpython-38.pyc,, -tornado/__pycache__/web.cpython-38.pyc,, -tornado/__pycache__/websocket.cpython-38.pyc,, -tornado/__pycache__/wsgi.cpython-38.pyc,, -tornado/_locale_data.py,sha256=BZGn0sBZeHS2kYAvFovxiimi_KqE0suPPom__qb71xU,4627 -tornado/auth.py,sha256=vbESu6SFcFgFjg7VkDcWpgWgopwPQXLtX8DDt4fmTz4,46051 -tornado/autoreload.py,sha256=sa2V25zdcZu23lweS2Scqmesnocjk6OtbF7feVu4Jgs,13652 -tornado/concurrent.py,sha256=hrlfgWnZp7Mr7ajhgxSEMA6nHHRqyYoMiUrjpK1cVIg,8108 -tornado/curl_httpclient.py,sha256=Ab09r4AykyQ_67mQa0S4lpo9WiZOiMJlS-lkDQAkXt4,24575 -tornado/escape.py,sha256=7cX6o-FkZSjzhfTNDHVU6JbsopFBT6fj3fLuwqnWAtM,13267 -tornado/gen.py,sha256=dJXReNybfnhyfTjinyFeoYTb9jYgNu9QS-3aAXgZJd0,30957 -tornado/http1connection.py,sha256=FMmXb2i4Cnv7LHBLjK13lKXARYVqFDLqHBQesmmGeos,36098 -tornado/httpclient.py,sha256=fDKLM0VLSOz4weyBOhG8w-WPfu_yjbT5mw0Q0YxR5Rs,31919 -tornado/httpserver.py,sha256=iVlUMDBkpNTQuv9X4I3felK3UNUucbbXBCfQBRtmeRo,15555 -tornado/httputil.py,sha256=USDYnppIPGpegRG9zs-qe4mI5rI8H_ZJg3G8xza6Vxs,35933 -tornado/ioloop.py,sha256=WJaCrx9ko_Z1Bzu3DDGhOfqs6Ns1uye0fAWCtMix_bs,35342 -tornado/iostream.py,sha256=H6qMORR3IbipBYPF76z61iwIqBDMSPQddtmt1SFnsWA,65451 -tornado/locale.py,sha256=YNu0cGa3LRj1AMH4Vmt5aZRG3lnoF4QvNDN95VnU4FQ,20972 -tornado/locks.py,sha256=fd6yuFK2O-hRyIms3NivsNUukhHRdPruUxiMw_LHDrQ,17414 -tornado/log.py,sha256=tC6hmAoQlncodapgPYGb_1lBlNSVnfAb5KCkIu4u0NM,12414 -tornado/netutil.py,sha256=YgFsZdMK8SfE55TU6qL_W0oivMYKnA0AfZka1sMEIUU,22912 -tornado/options.py,sha256=zvjDcUzXtzNvi3yKzyik7ZIiar_gqW4Uh2WJZrZ6pyU,25601 -tornado/platform/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -tornado/platform/__pycache__/__init__.cpython-38.pyc,, -tornado/platform/__pycache__/asyncio.cpython-38.pyc,, -tornado/platform/__pycache__/caresresolver.cpython-38.pyc,, -tornado/platform/__pycache__/twisted.cpython-38.pyc,, -tornado/platform/asyncio.py,sha256=syfpMNVTgBmdWazk7WTdGXF6Hc5BQie7aPu4GGW4mP0,23216 -tornado/platform/caresresolver.py,sha256=RXQuJsh6gyyWyKDwZRHZlNo_tM8J5IR7x46DtGnxwSI,3318 -tornado/platform/twisted.py,sha256=8bLmfn3TOQAS9wM0cGinxEITSnq2sT1pJClPkf3YR0I,5477 -tornado/process.py,sha256=wD09DPERk8-Ri2gqlMcSmkV5eKRl_c8-t8MLoTt6QK0,12789 -tornado/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -tornado/queues.py,sha256=8cL7JF7oFdlh2N1y0z6P0uwYOHOBTYOaCKWOGLY5cbY,12289 -tornado/routing.py,sha256=fEUpBPHKRd4PCp4LH1XKHspkqEG2jkIE_9hvJr3MEiA,25082 -tornado/simple_httpclient.py,sha256=Y4WSJLGV8HMaCWbKg_E1HZS2XGsse-Ln9LuAXLdl0Ys,27578 -tornado/speedups.cpython-38-x86_64-linux-gnu.so,sha256=otG3p4_6gbGdHih9HZ8EWX_OIZ7IVuNi9GiOipU34jI,29256 -tornado/tcpclient.py,sha256=SUIG3JY4a3WpSPC3eAIdSWrxUSowtHGSIjDqf3fhUko,12076 -tornado/tcpserver.py,sha256=rqyRL-d4pWRyqEa4i25dfR_0e4ts5JoTb6rN9M71TE4,13242 -tornado/template.py,sha256=32e-gIEbeaq1ucchTo1d6_gCY4J0HLqnX_lRhrFkYtA,37798 -tornado/test/__main__.py,sha256=lOtaUbVN3C_tg0kzkGGXFmhMuZjJtKnpTE8XbiDNgNQ,335 -tornado/test/__pycache__/__main__.cpython-38.pyc,, -tornado/test/__pycache__/asyncio_test.cpython-38.pyc,, -tornado/test/__pycache__/auth_test.cpython-38.pyc,, -tornado/test/__pycache__/autoreload_test.cpython-38.pyc,, -tornado/test/__pycache__/concurrent_test.cpython-38.pyc,, -tornado/test/__pycache__/curl_httpclient_test.cpython-38.pyc,, -tornado/test/__pycache__/escape_test.cpython-38.pyc,, -tornado/test/__pycache__/gen_test.cpython-38.pyc,, -tornado/test/__pycache__/http1connection_test.cpython-38.pyc,, -tornado/test/__pycache__/httpclient_test.cpython-38.pyc,, -tornado/test/__pycache__/httpserver_test.cpython-38.pyc,, -tornado/test/__pycache__/httputil_test.cpython-38.pyc,, -tornado/test/__pycache__/import_test.cpython-38.pyc,, -tornado/test/__pycache__/ioloop_test.cpython-38.pyc,, -tornado/test/__pycache__/iostream_test.cpython-38.pyc,, -tornado/test/__pycache__/locale_test.cpython-38.pyc,, -tornado/test/__pycache__/locks_test.cpython-38.pyc,, -tornado/test/__pycache__/log_test.cpython-38.pyc,, -tornado/test/__pycache__/netutil_test.cpython-38.pyc,, -tornado/test/__pycache__/options_test.cpython-38.pyc,, -tornado/test/__pycache__/process_test.cpython-38.pyc,, -tornado/test/__pycache__/queues_test.cpython-38.pyc,, -tornado/test/__pycache__/resolve_test_helper.cpython-38.pyc,, -tornado/test/__pycache__/routing_test.cpython-38.pyc,, -tornado/test/__pycache__/runtests.cpython-38.pyc,, -tornado/test/__pycache__/simple_httpclient_test.cpython-38.pyc,, -tornado/test/__pycache__/tcpclient_test.cpython-38.pyc,, -tornado/test/__pycache__/tcpserver_test.cpython-38.pyc,, -tornado/test/__pycache__/template_test.cpython-38.pyc,, -tornado/test/__pycache__/testing_test.cpython-38.pyc,, -tornado/test/__pycache__/twisted_test.cpython-38.pyc,, -tornado/test/__pycache__/util.cpython-38.pyc,, -tornado/test/__pycache__/util_test.cpython-38.pyc,, -tornado/test/__pycache__/web_test.cpython-38.pyc,, -tornado/test/__pycache__/websocket_test.cpython-38.pyc,, -tornado/test/__pycache__/wsgi_test.cpython-38.pyc,, -tornado/test/asyncio_test.py,sha256=ewtMKAwHWLWXLiX09aMPs8RZRyEG5sTNNu0sfbLsqy4,7155 -tornado/test/auth_test.py,sha256=tSgcX3PDivsrVSsPj5Cdh7WCtXOQPstHo_1P4vZ2gxk,23437 -tornado/test/autoreload_test.py,sha256=x0O26S2ZVjmRWCrF-loHyDUPkVMlHBkgviIUW6wmN6c,3948 -tornado/test/concurrent_test.py,sha256=vsggGoKCfnurb0OBQ-s69qLIg8Yws38ue5LrqoYcFaA,6051 -tornado/test/csv_translations/fr_FR.csv,sha256=0UsMzfh1cw3yQdhS7pCmRfQoAkbqWpgzzodpZqp7ttM,18 -tornado/test/curl_httpclient_test.py,sha256=hVXuIq32IdBz8_UOOuurUQGbfMgLpJb11ghF_wk7l4Q,4303 -tornado/test/escape_test.py,sha256=j81UHAlYotJHIOO1GOWoe83x1xJ8resUDt-4OkhQYLw,12372 -tornado/test/gen_test.py,sha256=AWHy4-d2khnOc3gEgl_beOWlfhAPGrxS8CtRGQ3Qz8s,33838 -tornado/test/gettext_translations/fr_FR/LC_MESSAGES/tornado_test.mo,sha256=fl0ZVZIlNwwU9lPx29pgZ4X-HfyEVYphJu7UWtll7jo,665 -tornado/test/gettext_translations/fr_FR/LC_MESSAGES/tornado_test.po,sha256=Clw6HyQUcopGV25qw3pvw3gn1ZqZRYrovsi8PQTQAnM,1049 -tornado/test/http1connection_test.py,sha256=lLav_POwDPx6NN_pMvfWWSFwKpbJ-so17UnuISWOXvQ,1950 -tornado/test/httpclient_test.py,sha256=puttXWYmGNA2SoYoPH-FAqzfZdcmXqxtNHpedENvI9c,34231 -tornado/test/httpserver_test.py,sha256=QWtPbREhgnaNVWwSeY8y7u9rH-FeiS6vKpmEnwMREds,46492 -tornado/test/httputil_test.py,sha256=6w4tQ1cSKmjxNUbTXoy-E0Ii7nhR2-y2bAUvQGnc7ZA,19053 -tornado/test/import_test.py,sha256=5oit2hRJ5QI2Wm92AZLdUn6ZwZrbzehYIuKvQl9ibAs,1980 -tornado/test/ioloop_test.py,sha256=c6JME_atMWzYjGnVF8VCRzJNuCDyvJSW_Vn8ocHXRyw,25653 -tornado/test/iostream_test.py,sha256=jP17mO8ESHRtC2-Co6vuVkYXglISyTJPvZ6wmoqgrUg,46328 -tornado/test/locale_test.py,sha256=bK7oN8SAn5eoThwR-4_Pp7IlZbxrsnzsYTbbm5g68fU,5756 -tornado/test/locks_test.py,sha256=nGyZUEW7r2FMnfLqihSzv6F_WlxZoSWyKDKa-cnqF-g,17010 -tornado/test/log_test.py,sha256=ebpF2dhhv4HNiXRTn37nLgsOZEypiuol4Pz-j5wKKqM,9504 -tornado/test/netutil_test.py,sha256=7Qz1EfJv5qaSzo9mUB-ROXOv1kXcNJfYoPsVYXL8l-s,7907 -tornado/test/options_test.cfg,sha256=SpUupk-MfXBMhLENqXmD-K5a2Mp888REqfICQupcgqc,69 -tornado/test/options_test.py,sha256=NLsVXpd1tym9GIBJoM90r3szF0MR8UGDFlSXx1v-OQ0,11821 -tornado/test/options_test_types.cfg,sha256=GeR43v-UuSfW7kkUfh6NavPrmOkdYkJr2v7-yTaqaDk,266 -tornado/test/options_test_types_str.cfg,sha256=2R1Gn7q4rt8kKvqvp2h1qC8IXZ8XrlyNVj3i7Jte-Us,150 -tornado/test/process_test.py,sha256=JXs0fVkyco-cAC7GTlCcLEkqykssfgoMk1paTSIEjso,11455 -tornado/test/queues_test.py,sha256=EGTV1_BMK3gTjlrFEyqQE1FE2WM9CPA6D7Nj20J2i7c,13981 -tornado/test/resolve_test_helper.py,sha256=bOZMi_3fgv71k-PNxKGFl2Nn4J8odfJjxtK7AdE33-8,411 -tornado/test/routing_test.py,sha256=YWZGtYp2UVj2Vf-e1KYdhXz35MgD0zwNXLy7ISYO0Q0,8827 -tornado/test/runtests.py,sha256=PdQ6jO23wDdkTmznODn7RUuQ2IEq2eJh1vmfAkuf1v4,8348 -tornado/test/simple_httpclient_test.py,sha256=PnWuu60nGJdnvkNW8mp0s1Ye_Lc8sLoZIvt90QG1708,30943 -tornado/test/static/dir/index.html,sha256=tBwBanUSjISUy0BVan_QNKkYdLau8qs__P0G9oAiP78,18 -tornado/test/static/robots.txt,sha256=Mx6pCQ2wyfb1l72YQP1bFxgw9uCzuhyyTfqR8Mla7cE,26 -tornado/test/static/sample.xml,sha256=7LeTf16BWDucipsUaZZK7oDxtKEMDH9sFtsNR1G6pME,666 -tornado/test/static/sample.xml.bz2,sha256=2Ql5ccWnaSpDdTyioino7Bw_dcGFkG_RQO5Lm5cfT6A,285 -tornado/test/static/sample.xml.gz,sha256=_App0wKpn31lZVA9P_rslytPm4ei5GvNPVKh55r7l28,264 -tornado/test/static_foo.txt,sha256=DdAKABzHb8kunGrAvUoTLnHlgdTN-6_PjH1irVmokm8,95 -tornado/test/tcpclient_test.py,sha256=n0-7_UxSS2x23nA6LmgDp-SHyX2AQhThtbvZhLYB9SU,16814 -tornado/test/tcpserver_test.py,sha256=uj4CB8VSzfNt3_t9jpblshMtTJVxPBGeYZb95rY21ns,6482 -tornado/test/template_test.py,sha256=YqgHoSxi69DMdLWNoULti5ZnH4ocI238HnEbeT0xzew,18668 -tornado/test/templates/utf8.html,sha256=9d1eiaw5KCjUTCbRRIl_RLSy0LCJXaO-bzVF2L_32fM,7 -tornado/test/test.crt,sha256=mRu1xBsBK6Z2cAh1IdwIF3tBsfOGz1kyAfWtXIEdHCI,1224 -tornado/test/test.key,sha256=Lgz56gA7gSXUbTTfiHAGFyZSXePBDPrJZlPRPu8ApeY,1704 -tornado/test/testing_test.py,sha256=_Z_fK7z8TU07TFZHFcSeD3Vk0tn-8RM72Q8_oxJgGx0,10711 -tornado/test/twisted_test.py,sha256=MD5aJ5A_Cf5UUr1fM9LLlBkf0SzPQ8z-CDjdUAE0-NM,8510 -tornado/test/util.py,sha256=LoAdDDLZai4L45le4bMSkBq2drQegm3CKdLYOkOPwYQ,3654 -tornado/test/util_test.py,sha256=-Nw4I5uIi756SFht3R9r8YjcZdTr5EC6qUX-dCuoYxc,9781 -tornado/test/web_test.py,sha256=CaRWjuRqSn4DZxY5FJA_uNoAXlB_1TJvSTbgEuiP6UU,115864 -tornado/test/websocket_test.py,sha256=LxmxrkAkALTV7_LuauJcCvoKm64szRyphWRCg14erLU,27976 -tornado/test/wsgi_test.py,sha256=fioTIRCajhhTcrCeR6jARQI7k33ajvk_a9gnI3N-Kds,657 -tornado/testing.py,sha256=Q1HL_TzcTgx8zdMTiIQSzT1uZhKDdSNqCc4dkqt4S1s,30623 -tornado/util.py,sha256=QO2_cK1kJEpf_1GfSIu-YXxYifkp-m_ArATW3pshdeY,16702 -tornado/web.py,sha256=bloqhSKzXTLflu_x2uCDzEJ7LzOJb7JZAoWCSQgQyD0,138140 -tornado/websocket.py,sha256=Dm8HScBGJSdPuo0YYnJV5UuRvRVneFgO1l1Bn1xL-t8,61476 -tornado/wsgi.py,sha256=yGtcp-400vnLKK5YyUz0a2G4cH32-NFkIWW_OSnSBYk,7807 diff --git a/venv/lib/python3.8/site-packages/tornado-6.1.dist-info/WHEEL b/venv/lib/python3.8/site-packages/tornado-6.1.dist-info/WHEEL deleted file mode 100644 index 3f8f773..0000000 --- a/venv/lib/python3.8/site-packages/tornado-6.1.dist-info/WHEEL +++ /dev/null @@ -1,5 +0,0 @@ -Wheel-Version: 1.0 -Generator: bdist_wheel (0.35.1) -Root-Is-Purelib: false -Tag: cp38-cp38-manylinux2010_x86_64 - diff --git a/venv/lib/python3.8/site-packages/tornado-6.1.dist-info/top_level.txt b/venv/lib/python3.8/site-packages/tornado-6.1.dist-info/top_level.txt deleted file mode 100644 index c3368df..0000000 --- a/venv/lib/python3.8/site-packages/tornado-6.1.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -tornado diff --git a/venv/lib/python3.8/site-packages/tornado/__init__.py b/venv/lib/python3.8/site-packages/tornado/__init__.py deleted file mode 100644 index a5f45e5..0000000 --- a/venv/lib/python3.8/site-packages/tornado/__init__.py +++ /dev/null @@ -1,26 +0,0 @@ -# -# Copyright 2009 Facebook -# -# 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. - -"""The Tornado web server and tools.""" - -# version is a human-readable version number. - -# version_info is a four-tuple for programmatic comparison. The first -# three numbers are the components of the version number. The fourth -# is zero for an official release, positive for a development branch, -# or negative for a release candidate or beta (after the base version -# number has been incremented) -version = "6.1" -version_info = (6, 1, 0, 0) diff --git a/venv/lib/python3.8/site-packages/tornado/_locale_data.py b/venv/lib/python3.8/site-packages/tornado/_locale_data.py deleted file mode 100644 index c706230..0000000 --- a/venv/lib/python3.8/site-packages/tornado/_locale_data.py +++ /dev/null @@ -1,80 +0,0 @@ -# Copyright 2012 Facebook -# -# 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. - -"""Data used by the tornado.locale module.""" - -LOCALE_NAMES = { - "af_ZA": {"name_en": u"Afrikaans", "name": u"Afrikaans"}, - "am_ET": {"name_en": u"Amharic", "name": u"አማርኛ"}, - "ar_AR": {"name_en": u"Arabic", "name": u"العربية"}, - "bg_BG": {"name_en": u"Bulgarian", "name": u"Български"}, - "bn_IN": {"name_en": u"Bengali", "name": u"বাংলা"}, - "bs_BA": {"name_en": u"Bosnian", "name": u"Bosanski"}, - "ca_ES": {"name_en": u"Catalan", "name": u"Català"}, - "cs_CZ": {"name_en": u"Czech", "name": u"Čeština"}, - "cy_GB": {"name_en": u"Welsh", "name": u"Cymraeg"}, - "da_DK": {"name_en": u"Danish", "name": u"Dansk"}, - "de_DE": {"name_en": u"German", "name": u"Deutsch"}, - "el_GR": {"name_en": u"Greek", "name": u"Ελληνικά"}, - "en_GB": {"name_en": u"English (UK)", "name": u"English (UK)"}, - "en_US": {"name_en": u"English (US)", "name": u"English (US)"}, - "es_ES": {"name_en": u"Spanish (Spain)", "name": u"Español (España)"}, - "es_LA": {"name_en": u"Spanish", "name": u"Español"}, - "et_EE": {"name_en": u"Estonian", "name": u"Eesti"}, - "eu_ES": {"name_en": u"Basque", "name": u"Euskara"}, - "fa_IR": {"name_en": u"Persian", "name": u"فارسی"}, - "fi_FI": {"name_en": u"Finnish", "name": u"Suomi"}, - "fr_CA": {"name_en": u"French (Canada)", "name": u"Français (Canada)"}, - "fr_FR": {"name_en": u"French", "name": u"Français"}, - "ga_IE": {"name_en": u"Irish", "name": u"Gaeilge"}, - "gl_ES": {"name_en": u"Galician", "name": u"Galego"}, - "he_IL": {"name_en": u"Hebrew", "name": u"עברית"}, - "hi_IN": {"name_en": u"Hindi", "name": u"हिन्दी"}, - "hr_HR": {"name_en": u"Croatian", "name": u"Hrvatski"}, - "hu_HU": {"name_en": u"Hungarian", "name": u"Magyar"}, - "id_ID": {"name_en": u"Indonesian", "name": u"Bahasa Indonesia"}, - "is_IS": {"name_en": u"Icelandic", "name": u"Íslenska"}, - "it_IT": {"name_en": u"Italian", "name": u"Italiano"}, - "ja_JP": {"name_en": u"Japanese", "name": u"日本語"}, - "ko_KR": {"name_en": u"Korean", "name": u"한국어"}, - "lt_LT": {"name_en": u"Lithuanian", "name": u"Lietuvių"}, - "lv_LV": {"name_en": u"Latvian", "name": u"Latviešu"}, - "mk_MK": {"name_en": u"Macedonian", "name": u"Македонски"}, - "ml_IN": {"name_en": u"Malayalam", "name": u"മലയാളം"}, - "ms_MY": {"name_en": u"Malay", "name": u"Bahasa Melayu"}, - "nb_NO": {"name_en": u"Norwegian (bokmal)", "name": u"Norsk (bokmål)"}, - "nl_NL": {"name_en": u"Dutch", "name": u"Nederlands"}, - "nn_NO": {"name_en": u"Norwegian (nynorsk)", "name": u"Norsk (nynorsk)"}, - "pa_IN": {"name_en": u"Punjabi", "name": u"ਪੰਜਾਬੀ"}, - "pl_PL": {"name_en": u"Polish", "name": u"Polski"}, - "pt_BR": {"name_en": u"Portuguese (Brazil)", "name": u"Português (Brasil)"}, - "pt_PT": {"name_en": u"Portuguese (Portugal)", "name": u"Português (Portugal)"}, - "ro_RO": {"name_en": u"Romanian", "name": u"Română"}, - "ru_RU": {"name_en": u"Russian", "name": u"Русский"}, - "sk_SK": {"name_en": u"Slovak", "name": u"Slovenčina"}, - "sl_SI": {"name_en": u"Slovenian", "name": u"Slovenščina"}, - "sq_AL": {"name_en": u"Albanian", "name": u"Shqip"}, - "sr_RS": {"name_en": u"Serbian", "name": u"Српски"}, - "sv_SE": {"name_en": u"Swedish", "name": u"Svenska"}, - "sw_KE": {"name_en": u"Swahili", "name": u"Kiswahili"}, - "ta_IN": {"name_en": u"Tamil", "name": u"தமிழ்"}, - "te_IN": {"name_en": u"Telugu", "name": u"తెలుగు"}, - "th_TH": {"name_en": u"Thai", "name": u"ภาษาไทย"}, - "tl_PH": {"name_en": u"Filipino", "name": u"Filipino"}, - "tr_TR": {"name_en": u"Turkish", "name": u"Türkçe"}, - "uk_UA": {"name_en": u"Ukraini ", "name": u"Українська"}, - "vi_VN": {"name_en": u"Vietnamese", "name": u"Tiếng Việt"}, - "zh_CN": {"name_en": u"Chinese (Simplified)", "name": u"中文(简体)"}, - "zh_TW": {"name_en": u"Chinese (Traditional)", "name": u"中文(繁體)"}, -} diff --git a/venv/lib/python3.8/site-packages/tornado/auth.py b/venv/lib/python3.8/site-packages/tornado/auth.py deleted file mode 100644 index 5f1068c..0000000 --- a/venv/lib/python3.8/site-packages/tornado/auth.py +++ /dev/null @@ -1,1187 +0,0 @@ -# -# Copyright 2009 Facebook -# -# 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. - -"""This module contains implementations of various third-party -authentication schemes. - -All the classes in this file are class mixins designed to be used with -the `tornado.web.RequestHandler` class. They are used in two ways: - -* On a login handler, use methods such as ``authenticate_redirect()``, - ``authorize_redirect()``, and ``get_authenticated_user()`` to - establish the user's identity and store authentication tokens to your - database and/or cookies. -* In non-login handlers, use methods such as ``facebook_request()`` - or ``twitter_request()`` to use the authentication tokens to make - requests to the respective services. - -They all take slightly different arguments due to the fact all these -services implement authentication and authorization slightly differently. -See the individual service classes below for complete documentation. - -Example usage for Google OAuth: - -.. testcode:: - - class GoogleOAuth2LoginHandler(tornado.web.RequestHandler, - tornado.auth.GoogleOAuth2Mixin): - async def get(self): - if self.get_argument('code', False): - user = await self.get_authenticated_user( - redirect_uri='http://your.site.com/auth/google', - code=self.get_argument('code')) - # Save the user with e.g. set_secure_cookie - else: - self.authorize_redirect( - redirect_uri='http://your.site.com/auth/google', - client_id=self.settings['google_oauth']['key'], - scope=['profile', 'email'], - response_type='code', - extra_params={'approval_prompt': 'auto'}) - -.. testoutput:: - :hide: - -""" - -import base64 -import binascii -import hashlib -import hmac -import time -import urllib.parse -import uuid - -from tornado import httpclient -from tornado import escape -from tornado.httputil import url_concat -from tornado.util import unicode_type -from tornado.web import RequestHandler - -from typing import List, Any, Dict, cast, Iterable, Union, Optional - - -class AuthError(Exception): - pass - - -class OpenIdMixin(object): - """Abstract implementation of OpenID and Attribute Exchange. - - Class attributes: - - * ``_OPENID_ENDPOINT``: the identity provider's URI. - """ - - def authenticate_redirect( - self, - callback_uri: Optional[str] = None, - ax_attrs: List[str] = ["name", "email", "language", "username"], - ) -> None: - """Redirects to the authentication URL for this service. - - After authentication, the service will redirect back to the given - callback URI with additional parameters including ``openid.mode``. - - We request the given attributes for the authenticated user by - default (name, email, language, and username). If you don't need - all those attributes for your app, you can request fewer with - the ax_attrs keyword argument. - - .. versionchanged:: 6.0 - - The ``callback`` argument was removed and this method no - longer returns an awaitable object. It is now an ordinary - synchronous function. - """ - handler = cast(RequestHandler, self) - callback_uri = callback_uri or handler.request.uri - assert callback_uri is not None - args = self._openid_args(callback_uri, ax_attrs=ax_attrs) - endpoint = self._OPENID_ENDPOINT # type: ignore - handler.redirect(endpoint + "?" + urllib.parse.urlencode(args)) - - async def get_authenticated_user( - self, http_client: Optional[httpclient.AsyncHTTPClient] = None - ) -> Dict[str, Any]: - """Fetches the authenticated user data upon redirect. - - This method should be called by the handler that receives the - redirect from the `authenticate_redirect()` method (which is - often the same as the one that calls it; in that case you would - call `get_authenticated_user` if the ``openid.mode`` parameter - is present and `authenticate_redirect` if it is not). - - The result of this method will generally be used to set a cookie. - - .. versionchanged:: 6.0 - - The ``callback`` argument was removed. Use the returned - awaitable object instead. - """ - handler = cast(RequestHandler, self) - # Verify the OpenID response via direct request to the OP - args = dict( - (k, v[-1]) for k, v in handler.request.arguments.items() - ) # type: Dict[str, Union[str, bytes]] - args["openid.mode"] = u"check_authentication" - url = self._OPENID_ENDPOINT # type: ignore - if http_client is None: - http_client = self.get_auth_http_client() - resp = await http_client.fetch( - url, method="POST", body=urllib.parse.urlencode(args) - ) - return self._on_authentication_verified(resp) - - def _openid_args( - self, - callback_uri: str, - ax_attrs: Iterable[str] = [], - oauth_scope: Optional[str] = None, - ) -> Dict[str, str]: - handler = cast(RequestHandler, self) - url = urllib.parse.urljoin(handler.request.full_url(), callback_uri) - args = { - "openid.ns": "http://specs.openid.net/auth/2.0", - "openid.claimed_id": "http://specs.openid.net/auth/2.0/identifier_select", - "openid.identity": "http://specs.openid.net/auth/2.0/identifier_select", - "openid.return_to": url, - "openid.realm": urllib.parse.urljoin(url, "/"), - "openid.mode": "checkid_setup", - } - if ax_attrs: - args.update( - { - "openid.ns.ax": "http://openid.net/srv/ax/1.0", - "openid.ax.mode": "fetch_request", - } - ) - ax_attrs = set(ax_attrs) - required = [] # type: List[str] - if "name" in ax_attrs: - ax_attrs -= set(["name", "firstname", "fullname", "lastname"]) - required += ["firstname", "fullname", "lastname"] - args.update( - { - "openid.ax.type.firstname": "http://axschema.org/namePerson/first", - "openid.ax.type.fullname": "http://axschema.org/namePerson", - "openid.ax.type.lastname": "http://axschema.org/namePerson/last", - } - ) - known_attrs = { - "email": "http://axschema.org/contact/email", - "language": "http://axschema.org/pref/language", - "username": "http://axschema.org/namePerson/friendly", - } - for name in ax_attrs: - args["openid.ax.type." + name] = known_attrs[name] - required.append(name) - args["openid.ax.required"] = ",".join(required) - if oauth_scope: - args.update( - { - "openid.ns.oauth": "http://specs.openid.net/extensions/oauth/1.0", - "openid.oauth.consumer": handler.request.host.split(":")[0], - "openid.oauth.scope": oauth_scope, - } - ) - return args - - def _on_authentication_verified( - self, response: httpclient.HTTPResponse - ) -> Dict[str, Any]: - handler = cast(RequestHandler, self) - if b"is_valid:true" not in response.body: - raise AuthError("Invalid OpenID response: %r" % response.body) - - # Make sure we got back at least an email from attribute exchange - ax_ns = None - for key in handler.request.arguments: - if ( - key.startswith("openid.ns.") - and handler.get_argument(key) == u"http://openid.net/srv/ax/1.0" - ): - ax_ns = key[10:] - break - - def get_ax_arg(uri: str) -> str: - if not ax_ns: - return u"" - prefix = "openid." + ax_ns + ".type." - ax_name = None - for name in handler.request.arguments.keys(): - if handler.get_argument(name) == uri and name.startswith(prefix): - part = name[len(prefix) :] - ax_name = "openid." + ax_ns + ".value." + part - break - if not ax_name: - return u"" - return handler.get_argument(ax_name, u"") - - email = get_ax_arg("http://axschema.org/contact/email") - name = get_ax_arg("http://axschema.org/namePerson") - first_name = get_ax_arg("http://axschema.org/namePerson/first") - last_name = get_ax_arg("http://axschema.org/namePerson/last") - username = get_ax_arg("http://axschema.org/namePerson/friendly") - locale = get_ax_arg("http://axschema.org/pref/language").lower() - user = dict() - name_parts = [] - if first_name: - user["first_name"] = first_name - name_parts.append(first_name) - if last_name: - user["last_name"] = last_name - name_parts.append(last_name) - if name: - user["name"] = name - elif name_parts: - user["name"] = u" ".join(name_parts) - elif email: - user["name"] = email.split("@")[0] - if email: - user["email"] = email - if locale: - user["locale"] = locale - if username: - user["username"] = username - claimed_id = handler.get_argument("openid.claimed_id", None) - if claimed_id: - user["claimed_id"] = claimed_id - return user - - def get_auth_http_client(self) -> httpclient.AsyncHTTPClient: - """Returns the `.AsyncHTTPClient` instance to be used for auth requests. - - May be overridden by subclasses to use an HTTP client other than - the default. - """ - return httpclient.AsyncHTTPClient() - - -class OAuthMixin(object): - """Abstract implementation of OAuth 1.0 and 1.0a. - - See `TwitterMixin` below for an example implementation. - - Class attributes: - - * ``_OAUTH_AUTHORIZE_URL``: The service's OAuth authorization url. - * ``_OAUTH_ACCESS_TOKEN_URL``: The service's OAuth access token url. - * ``_OAUTH_VERSION``: May be either "1.0" or "1.0a". - * ``_OAUTH_NO_CALLBACKS``: Set this to True if the service requires - advance registration of callbacks. - - Subclasses must also override the `_oauth_get_user_future` and - `_oauth_consumer_token` methods. - """ - - async def authorize_redirect( - self, - callback_uri: Optional[str] = None, - extra_params: Optional[Dict[str, Any]] = None, - http_client: Optional[httpclient.AsyncHTTPClient] = None, - ) -> None: - """Redirects the user to obtain OAuth authorization for this service. - - The ``callback_uri`` may be omitted if you have previously - registered a callback URI with the third-party service. For - some services, you must use a previously-registered callback - URI and cannot specify a callback via this method. - - This method sets a cookie called ``_oauth_request_token`` which is - subsequently used (and cleared) in `get_authenticated_user` for - security purposes. - - This method is asynchronous and must be called with ``await`` - or ``yield`` (This is different from other ``auth*_redirect`` - methods defined in this module). It calls - `.RequestHandler.finish` for you so you should not write any - other response after it returns. - - .. versionchanged:: 3.1 - Now returns a `.Future` and takes an optional callback, for - compatibility with `.gen.coroutine`. - - .. versionchanged:: 6.0 - - The ``callback`` argument was removed. Use the returned - awaitable object instead. - - """ - if callback_uri and getattr(self, "_OAUTH_NO_CALLBACKS", False): - raise Exception("This service does not support oauth_callback") - if http_client is None: - http_client = self.get_auth_http_client() - assert http_client is not None - if getattr(self, "_OAUTH_VERSION", "1.0a") == "1.0a": - response = await http_client.fetch( - self._oauth_request_token_url( - callback_uri=callback_uri, extra_params=extra_params - ) - ) - else: - response = await http_client.fetch(self._oauth_request_token_url()) - url = self._OAUTH_AUTHORIZE_URL # type: ignore - self._on_request_token(url, callback_uri, response) - - async def get_authenticated_user( - self, http_client: Optional[httpclient.AsyncHTTPClient] = None - ) -> Dict[str, Any]: - """Gets the OAuth authorized user and access token. - - This method should be called from the handler for your - OAuth callback URL to complete the registration process. We run the - callback with the authenticated user dictionary. This dictionary - will contain an ``access_key`` which can be used to make authorized - requests to this service on behalf of the user. The dictionary will - also contain other fields such as ``name``, depending on the service - used. - - .. versionchanged:: 6.0 - - The ``callback`` argument was removed. Use the returned - awaitable object instead. - """ - handler = cast(RequestHandler, self) - request_key = escape.utf8(handler.get_argument("oauth_token")) - oauth_verifier = handler.get_argument("oauth_verifier", None) - request_cookie = handler.get_cookie("_oauth_request_token") - if not request_cookie: - raise AuthError("Missing OAuth request token cookie") - handler.clear_cookie("_oauth_request_token") - cookie_key, cookie_secret = [ - base64.b64decode(escape.utf8(i)) for i in request_cookie.split("|") - ] - if cookie_key != request_key: - raise AuthError("Request token does not match cookie") - token = dict( - key=cookie_key, secret=cookie_secret - ) # type: Dict[str, Union[str, bytes]] - if oauth_verifier: - token["verifier"] = oauth_verifier - if http_client is None: - http_client = self.get_auth_http_client() - assert http_client is not None - response = await http_client.fetch(self._oauth_access_token_url(token)) - access_token = _oauth_parse_response(response.body) - user = await self._oauth_get_user_future(access_token) - if not user: - raise AuthError("Error getting user") - user["access_token"] = access_token - return user - - def _oauth_request_token_url( - self, - callback_uri: Optional[str] = None, - extra_params: Optional[Dict[str, Any]] = None, - ) -> str: - handler = cast(RequestHandler, self) - consumer_token = self._oauth_consumer_token() - url = self._OAUTH_REQUEST_TOKEN_URL # type: ignore - args = dict( - oauth_consumer_key=escape.to_basestring(consumer_token["key"]), - oauth_signature_method="HMAC-SHA1", - oauth_timestamp=str(int(time.time())), - oauth_nonce=escape.to_basestring(binascii.b2a_hex(uuid.uuid4().bytes)), - oauth_version="1.0", - ) - if getattr(self, "_OAUTH_VERSION", "1.0a") == "1.0a": - if callback_uri == "oob": - args["oauth_callback"] = "oob" - elif callback_uri: - args["oauth_callback"] = urllib.parse.urljoin( - handler.request.full_url(), callback_uri - ) - if extra_params: - args.update(extra_params) - signature = _oauth10a_signature(consumer_token, "GET", url, args) - else: - signature = _oauth_signature(consumer_token, "GET", url, args) - - args["oauth_signature"] = signature - return url + "?" + urllib.parse.urlencode(args) - - def _on_request_token( - self, - authorize_url: str, - callback_uri: Optional[str], - response: httpclient.HTTPResponse, - ) -> None: - handler = cast(RequestHandler, self) - request_token = _oauth_parse_response(response.body) - data = ( - base64.b64encode(escape.utf8(request_token["key"])) - + b"|" - + base64.b64encode(escape.utf8(request_token["secret"])) - ) - handler.set_cookie("_oauth_request_token", data) - args = dict(oauth_token=request_token["key"]) - if callback_uri == "oob": - handler.finish(authorize_url + "?" + urllib.parse.urlencode(args)) - return - elif callback_uri: - args["oauth_callback"] = urllib.parse.urljoin( - handler.request.full_url(), callback_uri - ) - handler.redirect(authorize_url + "?" + urllib.parse.urlencode(args)) - - def _oauth_access_token_url(self, request_token: Dict[str, Any]) -> str: - consumer_token = self._oauth_consumer_token() - url = self._OAUTH_ACCESS_TOKEN_URL # type: ignore - args = dict( - oauth_consumer_key=escape.to_basestring(consumer_token["key"]), - oauth_token=escape.to_basestring(request_token["key"]), - oauth_signature_method="HMAC-SHA1", - oauth_timestamp=str(int(time.time())), - oauth_nonce=escape.to_basestring(binascii.b2a_hex(uuid.uuid4().bytes)), - oauth_version="1.0", - ) - if "verifier" in request_token: - args["oauth_verifier"] = request_token["verifier"] - - if getattr(self, "_OAUTH_VERSION", "1.0a") == "1.0a": - signature = _oauth10a_signature( - consumer_token, "GET", url, args, request_token - ) - else: - signature = _oauth_signature( - consumer_token, "GET", url, args, request_token - ) - - args["oauth_signature"] = signature - return url + "?" + urllib.parse.urlencode(args) - - def _oauth_consumer_token(self) -> Dict[str, Any]: - """Subclasses must override this to return their OAuth consumer keys. - - The return value should be a `dict` with keys ``key`` and ``secret``. - """ - raise NotImplementedError() - - async def _oauth_get_user_future( - self, access_token: Dict[str, Any] - ) -> Dict[str, Any]: - """Subclasses must override this to get basic information about the - user. - - Should be a coroutine whose result is a dictionary - containing information about the user, which may have been - retrieved by using ``access_token`` to make a request to the - service. - - The access token will be added to the returned dictionary to make - the result of `get_authenticated_user`. - - .. versionchanged:: 5.1 - - Subclasses may also define this method with ``async def``. - - .. versionchanged:: 6.0 - - A synchronous fallback to ``_oauth_get_user`` was removed. - """ - raise NotImplementedError() - - def _oauth_request_parameters( - self, - url: str, - access_token: Dict[str, Any], - parameters: Dict[str, Any] = {}, - method: str = "GET", - ) -> Dict[str, Any]: - """Returns the OAuth parameters as a dict for the given request. - - parameters should include all POST arguments and query string arguments - that will be sent with the request. - """ - consumer_token = self._oauth_consumer_token() - base_args = dict( - oauth_consumer_key=escape.to_basestring(consumer_token["key"]), - oauth_token=escape.to_basestring(access_token["key"]), - oauth_signature_method="HMAC-SHA1", - oauth_timestamp=str(int(time.time())), - oauth_nonce=escape.to_basestring(binascii.b2a_hex(uuid.uuid4().bytes)), - oauth_version="1.0", - ) - args = {} - args.update(base_args) - args.update(parameters) - if getattr(self, "_OAUTH_VERSION", "1.0a") == "1.0a": - signature = _oauth10a_signature( - consumer_token, method, url, args, access_token - ) - else: - signature = _oauth_signature( - consumer_token, method, url, args, access_token - ) - base_args["oauth_signature"] = escape.to_basestring(signature) - return base_args - - def get_auth_http_client(self) -> httpclient.AsyncHTTPClient: - """Returns the `.AsyncHTTPClient` instance to be used for auth requests. - - May be overridden by subclasses to use an HTTP client other than - the default. - """ - return httpclient.AsyncHTTPClient() - - -class OAuth2Mixin(object): - """Abstract implementation of OAuth 2.0. - - See `FacebookGraphMixin` or `GoogleOAuth2Mixin` below for example - implementations. - - Class attributes: - - * ``_OAUTH_AUTHORIZE_URL``: The service's authorization url. - * ``_OAUTH_ACCESS_TOKEN_URL``: The service's access token url. - """ - - def authorize_redirect( - self, - redirect_uri: Optional[str] = None, - client_id: Optional[str] = None, - client_secret: Optional[str] = None, - extra_params: Optional[Dict[str, Any]] = None, - scope: Optional[List[str]] = None, - response_type: str = "code", - ) -> None: - """Redirects the user to obtain OAuth authorization for this service. - - Some providers require that you register a redirect URL with - your application instead of passing one via this method. You - should call this method to log the user in, and then call - ``get_authenticated_user`` in the handler for your - redirect URL to complete the authorization process. - - .. versionchanged:: 6.0 - - The ``callback`` argument and returned awaitable were removed; - this is now an ordinary synchronous function. - """ - handler = cast(RequestHandler, self) - args = {"response_type": response_type} - if redirect_uri is not None: - args["redirect_uri"] = redirect_uri - if client_id is not None: - args["client_id"] = client_id - if extra_params: - args.update(extra_params) - if scope: - args["scope"] = " ".join(scope) - url = self._OAUTH_AUTHORIZE_URL # type: ignore - handler.redirect(url_concat(url, args)) - - def _oauth_request_token_url( - self, - redirect_uri: Optional[str] = None, - client_id: Optional[str] = None, - client_secret: Optional[str] = None, - code: Optional[str] = None, - extra_params: Optional[Dict[str, Any]] = None, - ) -> str: - url = self._OAUTH_ACCESS_TOKEN_URL # type: ignore - args = {} # type: Dict[str, str] - if redirect_uri is not None: - args["redirect_uri"] = redirect_uri - if code is not None: - args["code"] = code - if client_id is not None: - args["client_id"] = client_id - if client_secret is not None: - args["client_secret"] = client_secret - if extra_params: - args.update(extra_params) - return url_concat(url, args) - - async def oauth2_request( - self, - url: str, - access_token: Optional[str] = None, - post_args: Optional[Dict[str, Any]] = None, - **args: Any - ) -> Any: - """Fetches the given URL auth an OAuth2 access token. - - If the request is a POST, ``post_args`` should be provided. Query - string arguments should be given as keyword arguments. - - Example usage: - - ..testcode:: - - class MainHandler(tornado.web.RequestHandler, - tornado.auth.FacebookGraphMixin): - @tornado.web.authenticated - async def get(self): - new_entry = await self.oauth2_request( - "https://graph.facebook.com/me/feed", - post_args={"message": "I am posting from my Tornado application!"}, - access_token=self.current_user["access_token"]) - - if not new_entry: - # Call failed; perhaps missing permission? - self.authorize_redirect() - return - self.finish("Posted a message!") - - .. testoutput:: - :hide: - - .. versionadded:: 4.3 - - .. versionchanged::: 6.0 - - The ``callback`` argument was removed. Use the returned awaitable object instead. - """ - all_args = {} - if access_token: - all_args["access_token"] = access_token - all_args.update(args) - - if all_args: - url += "?" + urllib.parse.urlencode(all_args) - http = self.get_auth_http_client() - if post_args is not None: - response = await http.fetch( - url, method="POST", body=urllib.parse.urlencode(post_args) - ) - else: - response = await http.fetch(url) - return escape.json_decode(response.body) - - def get_auth_http_client(self) -> httpclient.AsyncHTTPClient: - """Returns the `.AsyncHTTPClient` instance to be used for auth requests. - - May be overridden by subclasses to use an HTTP client other than - the default. - - .. versionadded:: 4.3 - """ - return httpclient.AsyncHTTPClient() - - -class TwitterMixin(OAuthMixin): - """Twitter OAuth authentication. - - To authenticate with Twitter, register your application with - Twitter at http://twitter.com/apps. Then copy your Consumer Key - and Consumer Secret to the application - `~tornado.web.Application.settings` ``twitter_consumer_key`` and - ``twitter_consumer_secret``. Use this mixin on the handler for the - URL you registered as your application's callback URL. - - When your application is set up, you can use this mixin like this - to authenticate the user with Twitter and get access to their stream: - - .. testcode:: - - class TwitterLoginHandler(tornado.web.RequestHandler, - tornado.auth.TwitterMixin): - async def get(self): - if self.get_argument("oauth_token", None): - user = await self.get_authenticated_user() - # Save the user using e.g. set_secure_cookie() - else: - await self.authorize_redirect() - - .. testoutput:: - :hide: - - The user object returned by `~OAuthMixin.get_authenticated_user` - includes the attributes ``username``, ``name``, ``access_token``, - and all of the custom Twitter user attributes described at - https://dev.twitter.com/docs/api/1.1/get/users/show - """ - - _OAUTH_REQUEST_TOKEN_URL = "https://api.twitter.com/oauth/request_token" - _OAUTH_ACCESS_TOKEN_URL = "https://api.twitter.com/oauth/access_token" - _OAUTH_AUTHORIZE_URL = "https://api.twitter.com/oauth/authorize" - _OAUTH_AUTHENTICATE_URL = "https://api.twitter.com/oauth/authenticate" - _OAUTH_NO_CALLBACKS = False - _TWITTER_BASE_URL = "https://api.twitter.com/1.1" - - async def authenticate_redirect(self, callback_uri: Optional[str] = None) -> None: - """Just like `~OAuthMixin.authorize_redirect`, but - auto-redirects if authorized. - - This is generally the right interface to use if you are using - Twitter for single-sign on. - - .. versionchanged:: 3.1 - Now returns a `.Future` and takes an optional callback, for - compatibility with `.gen.coroutine`. - - .. versionchanged:: 6.0 - - The ``callback`` argument was removed. Use the returned - awaitable object instead. - """ - http = self.get_auth_http_client() - response = await http.fetch( - self._oauth_request_token_url(callback_uri=callback_uri) - ) - self._on_request_token(self._OAUTH_AUTHENTICATE_URL, None, response) - - async def twitter_request( - self, - path: str, - access_token: Dict[str, Any], - post_args: Optional[Dict[str, Any]] = None, - **args: Any - ) -> Any: - """Fetches the given API path, e.g., ``statuses/user_timeline/btaylor`` - - The path should not include the format or API version number. - (we automatically use JSON format and API version 1). - - If the request is a POST, ``post_args`` should be provided. Query - string arguments should be given as keyword arguments. - - All the Twitter methods are documented at http://dev.twitter.com/ - - Many methods require an OAuth access token which you can - obtain through `~OAuthMixin.authorize_redirect` and - `~OAuthMixin.get_authenticated_user`. The user returned through that - process includes an 'access_token' attribute that can be used - to make authenticated requests via this method. Example - usage: - - .. testcode:: - - class MainHandler(tornado.web.RequestHandler, - tornado.auth.TwitterMixin): - @tornado.web.authenticated - async def get(self): - new_entry = await self.twitter_request( - "/statuses/update", - post_args={"status": "Testing Tornado Web Server"}, - access_token=self.current_user["access_token"]) - if not new_entry: - # Call failed; perhaps missing permission? - await self.authorize_redirect() - return - self.finish("Posted a message!") - - .. testoutput:: - :hide: - - .. versionchanged:: 6.0 - - The ``callback`` argument was removed. Use the returned - awaitable object instead. - """ - if path.startswith("http:") or path.startswith("https:"): - # Raw urls are useful for e.g. search which doesn't follow the - # usual pattern: http://search.twitter.com/search.json - url = path - else: - url = self._TWITTER_BASE_URL + path + ".json" - # Add the OAuth resource request signature if we have credentials - if access_token: - all_args = {} - all_args.update(args) - all_args.update(post_args or {}) - method = "POST" if post_args is not None else "GET" - oauth = self._oauth_request_parameters( - url, access_token, all_args, method=method - ) - args.update(oauth) - if args: - url += "?" + urllib.parse.urlencode(args) - http = self.get_auth_http_client() - if post_args is not None: - response = await http.fetch( - url, method="POST", body=urllib.parse.urlencode(post_args) - ) - else: - response = await http.fetch(url) - return escape.json_decode(response.body) - - def _oauth_consumer_token(self) -> Dict[str, Any]: - handler = cast(RequestHandler, self) - handler.require_setting("twitter_consumer_key", "Twitter OAuth") - handler.require_setting("twitter_consumer_secret", "Twitter OAuth") - return dict( - key=handler.settings["twitter_consumer_key"], - secret=handler.settings["twitter_consumer_secret"], - ) - - async def _oauth_get_user_future( - self, access_token: Dict[str, Any] - ) -> Dict[str, Any]: - user = await self.twitter_request( - "/account/verify_credentials", access_token=access_token - ) - if user: - user["username"] = user["screen_name"] - return user - - -class GoogleOAuth2Mixin(OAuth2Mixin): - """Google authentication using OAuth2. - - In order to use, register your application with Google and copy the - relevant parameters to your application settings. - - * Go to the Google Dev Console at http://console.developers.google.com - * Select a project, or create a new one. - * In the sidebar on the left, select APIs & Auth. - * In the list of APIs, find the Google+ API service and set it to ON. - * In the sidebar on the left, select Credentials. - * In the OAuth section of the page, select Create New Client ID. - * Set the Redirect URI to point to your auth handler - * Copy the "Client secret" and "Client ID" to the application settings as - ``{"google_oauth": {"key": CLIENT_ID, "secret": CLIENT_SECRET}}`` - - .. versionadded:: 3.2 - """ - - _OAUTH_AUTHORIZE_URL = "https://accounts.google.com/o/oauth2/v2/auth" - _OAUTH_ACCESS_TOKEN_URL = "https://www.googleapis.com/oauth2/v4/token" - _OAUTH_USERINFO_URL = "https://www.googleapis.com/oauth2/v1/userinfo" - _OAUTH_NO_CALLBACKS = False - _OAUTH_SETTINGS_KEY = "google_oauth" - - async def get_authenticated_user( - self, redirect_uri: str, code: str - ) -> Dict[str, Any]: - """Handles the login for the Google user, returning an access token. - - The result is a dictionary containing an ``access_token`` field - ([among others](https://developers.google.com/identity/protocols/OAuth2WebServer#handlingtheresponse)). - Unlike other ``get_authenticated_user`` methods in this package, - this method does not return any additional information about the user. - The returned access token can be used with `OAuth2Mixin.oauth2_request` - to request additional information (perhaps from - ``https://www.googleapis.com/oauth2/v2/userinfo``) - - Example usage: - - .. testcode:: - - class GoogleOAuth2LoginHandler(tornado.web.RequestHandler, - tornado.auth.GoogleOAuth2Mixin): - async def get(self): - if self.get_argument('code', False): - access = await self.get_authenticated_user( - redirect_uri='http://your.site.com/auth/google', - code=self.get_argument('code')) - user = await self.oauth2_request( - "https://www.googleapis.com/oauth2/v1/userinfo", - access_token=access["access_token"]) - # Save the user and access token with - # e.g. set_secure_cookie. - else: - self.authorize_redirect( - redirect_uri='http://your.site.com/auth/google', - client_id=self.settings['google_oauth']['key'], - scope=['profile', 'email'], - response_type='code', - extra_params={'approval_prompt': 'auto'}) - - .. testoutput:: - :hide: - - .. versionchanged:: 6.0 - - The ``callback`` argument was removed. Use the returned awaitable object instead. - """ # noqa: E501 - handler = cast(RequestHandler, self) - http = self.get_auth_http_client() - body = urllib.parse.urlencode( - { - "redirect_uri": redirect_uri, - "code": code, - "client_id": handler.settings[self._OAUTH_SETTINGS_KEY]["key"], - "client_secret": handler.settings[self._OAUTH_SETTINGS_KEY]["secret"], - "grant_type": "authorization_code", - } - ) - - response = await http.fetch( - self._OAUTH_ACCESS_TOKEN_URL, - method="POST", - headers={"Content-Type": "application/x-www-form-urlencoded"}, - body=body, - ) - return escape.json_decode(response.body) - - -class FacebookGraphMixin(OAuth2Mixin): - """Facebook authentication using the new Graph API and OAuth2.""" - - _OAUTH_ACCESS_TOKEN_URL = "https://graph.facebook.com/oauth/access_token?" - _OAUTH_AUTHORIZE_URL = "https://www.facebook.com/dialog/oauth?" - _OAUTH_NO_CALLBACKS = False - _FACEBOOK_BASE_URL = "https://graph.facebook.com" - - async def get_authenticated_user( - self, - redirect_uri: str, - client_id: str, - client_secret: str, - code: str, - extra_fields: Optional[Dict[str, Any]] = None, - ) -> Optional[Dict[str, Any]]: - """Handles the login for the Facebook user, returning a user object. - - Example usage: - - .. testcode:: - - class FacebookGraphLoginHandler(tornado.web.RequestHandler, - tornado.auth.FacebookGraphMixin): - async def get(self): - if self.get_argument("code", False): - user = await self.get_authenticated_user( - redirect_uri='/auth/facebookgraph/', - client_id=self.settings["facebook_api_key"], - client_secret=self.settings["facebook_secret"], - code=self.get_argument("code")) - # Save the user with e.g. set_secure_cookie - else: - self.authorize_redirect( - redirect_uri='/auth/facebookgraph/', - client_id=self.settings["facebook_api_key"], - extra_params={"scope": "read_stream,offline_access"}) - - .. testoutput:: - :hide: - - This method returns a dictionary which may contain the following fields: - - * ``access_token``, a string which may be passed to `facebook_request` - * ``session_expires``, an integer encoded as a string representing - the time until the access token expires in seconds. This field should - be used like ``int(user['session_expires'])``; in a future version of - Tornado it will change from a string to an integer. - * ``id``, ``name``, ``first_name``, ``last_name``, ``locale``, ``picture``, - ``link``, plus any fields named in the ``extra_fields`` argument. These - fields are copied from the Facebook graph API - `user object <https://developers.facebook.com/docs/graph-api/reference/user>`_ - - .. versionchanged:: 4.5 - The ``session_expires`` field was updated to support changes made to the - Facebook API in March 2017. - - .. versionchanged:: 6.0 - - The ``callback`` argument was removed. Use the returned awaitable object instead. - """ - http = self.get_auth_http_client() - args = { - "redirect_uri": redirect_uri, - "code": code, - "client_id": client_id, - "client_secret": client_secret, - } - - fields = set( - ["id", "name", "first_name", "last_name", "locale", "picture", "link"] - ) - if extra_fields: - fields.update(extra_fields) - - response = await http.fetch( - self._oauth_request_token_url(**args) # type: ignore - ) - args = escape.json_decode(response.body) - session = { - "access_token": args.get("access_token"), - "expires_in": args.get("expires_in"), - } - assert session["access_token"] is not None - - user = await self.facebook_request( - path="/me", - access_token=session["access_token"], - appsecret_proof=hmac.new( - key=client_secret.encode("utf8"), - msg=session["access_token"].encode("utf8"), - digestmod=hashlib.sha256, - ).hexdigest(), - fields=",".join(fields), - ) - - if user is None: - return None - - fieldmap = {} - for field in fields: - fieldmap[field] = user.get(field) - - # session_expires is converted to str for compatibility with - # older versions in which the server used url-encoding and - # this code simply returned the string verbatim. - # This should change in Tornado 5.0. - fieldmap.update( - { - "access_token": session["access_token"], - "session_expires": str(session.get("expires_in")), - } - ) - return fieldmap - - async def facebook_request( - self, - path: str, - access_token: Optional[str] = None, - post_args: Optional[Dict[str, Any]] = None, - **args: Any - ) -> Any: - """Fetches the given relative API path, e.g., "/btaylor/picture" - - If the request is a POST, ``post_args`` should be provided. Query - string arguments should be given as keyword arguments. - - An introduction to the Facebook Graph API can be found at - http://developers.facebook.com/docs/api - - Many methods require an OAuth access token which you can - obtain through `~OAuth2Mixin.authorize_redirect` and - `get_authenticated_user`. The user returned through that - process includes an ``access_token`` attribute that can be - used to make authenticated requests via this method. - - Example usage: - - .. testcode:: - - class MainHandler(tornado.web.RequestHandler, - tornado.auth.FacebookGraphMixin): - @tornado.web.authenticated - async def get(self): - new_entry = await self.facebook_request( - "/me/feed", - post_args={"message": "I am posting from my Tornado application!"}, - access_token=self.current_user["access_token"]) - - if not new_entry: - # Call failed; perhaps missing permission? - self.authorize_redirect() - return - self.finish("Posted a message!") - - .. testoutput:: - :hide: - - The given path is relative to ``self._FACEBOOK_BASE_URL``, - by default "https://graph.facebook.com". - - This method is a wrapper around `OAuth2Mixin.oauth2_request`; - the only difference is that this method takes a relative path, - while ``oauth2_request`` takes a complete url. - - .. versionchanged:: 3.1 - Added the ability to override ``self._FACEBOOK_BASE_URL``. - - .. versionchanged:: 6.0 - - The ``callback`` argument was removed. Use the returned awaitable object instead. - """ - url = self._FACEBOOK_BASE_URL + path - return await self.oauth2_request( - url, access_token=access_token, post_args=post_args, **args - ) - - -def _oauth_signature( - consumer_token: Dict[str, Any], - method: str, - url: str, - parameters: Dict[str, Any] = {}, - token: Optional[Dict[str, Any]] = None, -) -> bytes: - """Calculates the HMAC-SHA1 OAuth signature for the given request. - - See http://oauth.net/core/1.0/#signing_process - """ - parts = urllib.parse.urlparse(url) - scheme, netloc, path = parts[:3] - normalized_url = scheme.lower() + "://" + netloc.lower() + path - - base_elems = [] - base_elems.append(method.upper()) - base_elems.append(normalized_url) - base_elems.append( - "&".join( - "%s=%s" % (k, _oauth_escape(str(v))) for k, v in sorted(parameters.items()) - ) - ) - base_string = "&".join(_oauth_escape(e) for e in base_elems) - - key_elems = [escape.utf8(consumer_token["secret"])] - key_elems.append(escape.utf8(token["secret"] if token else "")) - key = b"&".join(key_elems) - - hash = hmac.new(key, escape.utf8(base_string), hashlib.sha1) - return binascii.b2a_base64(hash.digest())[:-1] - - -def _oauth10a_signature( - consumer_token: Dict[str, Any], - method: str, - url: str, - parameters: Dict[str, Any] = {}, - token: Optional[Dict[str, Any]] = None, -) -> bytes: - """Calculates the HMAC-SHA1 OAuth 1.0a signature for the given request. - - See http://oauth.net/core/1.0a/#signing_process - """ - parts = urllib.parse.urlparse(url) - scheme, netloc, path = parts[:3] - normalized_url = scheme.lower() + "://" + netloc.lower() + path - - base_elems = [] - base_elems.append(method.upper()) - base_elems.append(normalized_url) - base_elems.append( - "&".join( - "%s=%s" % (k, _oauth_escape(str(v))) for k, v in sorted(parameters.items()) - ) - ) - - base_string = "&".join(_oauth_escape(e) for e in base_elems) - key_elems = [escape.utf8(urllib.parse.quote(consumer_token["secret"], safe="~"))] - key_elems.append( - escape.utf8(urllib.parse.quote(token["secret"], safe="~") if token else "") - ) - key = b"&".join(key_elems) - - hash = hmac.new(key, escape.utf8(base_string), hashlib.sha1) - return binascii.b2a_base64(hash.digest())[:-1] - - -def _oauth_escape(val: Union[str, bytes]) -> str: - if isinstance(val, unicode_type): - val = val.encode("utf-8") - return urllib.parse.quote(val, safe="~") - - -def _oauth_parse_response(body: bytes) -> Dict[str, Any]: - # I can't find an officially-defined encoding for oauth responses and - # have never seen anyone use non-ascii. Leave the response in a byte - # string for python 2, and use utf8 on python 3. - body_str = escape.native_str(body) - p = urllib.parse.parse_qs(body_str, keep_blank_values=False) - token = dict(key=p["oauth_token"][0], secret=p["oauth_token_secret"][0]) - - # Add the extra parameters the Provider included to the token - special = ("oauth_token", "oauth_token_secret") - token.update((k, p[k][0]) for k in p if k not in special) - return token diff --git a/venv/lib/python3.8/site-packages/tornado/autoreload.py b/venv/lib/python3.8/site-packages/tornado/autoreload.py deleted file mode 100644 index 3299a3b..0000000 --- a/venv/lib/python3.8/site-packages/tornado/autoreload.py +++ /dev/null @@ -1,363 +0,0 @@ -# -# Copyright 2009 Facebook -# -# 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. - -"""Automatically restart the server when a source file is modified. - -Most applications should not access this module directly. Instead, -pass the keyword argument ``autoreload=True`` to the -`tornado.web.Application` constructor (or ``debug=True``, which -enables this setting and several others). This will enable autoreload -mode as well as checking for changes to templates and static -resources. Note that restarting is a destructive operation and any -requests in progress will be aborted when the process restarts. (If -you want to disable autoreload while using other debug-mode features, -pass both ``debug=True`` and ``autoreload=False``). - -This module can also be used as a command-line wrapper around scripts -such as unit test runners. See the `main` method for details. - -The command-line wrapper and Application debug modes can be used together. -This combination is encouraged as the wrapper catches syntax errors and -other import-time failures, while debug mode catches changes once -the server has started. - -This module will not work correctly when `.HTTPServer`'s multi-process -mode is used. - -Reloading loses any Python interpreter command-line arguments (e.g. ``-u``) -because it re-executes Python using ``sys.executable`` and ``sys.argv``. -Additionally, modifying these variables will cause reloading to behave -incorrectly. - -""" - -import os -import sys - -# sys.path handling -# ----------------- -# -# If a module is run with "python -m", the current directory (i.e. "") -# is automatically prepended to sys.path, but not if it is run as -# "path/to/file.py". The processing for "-m" rewrites the former to -# the latter, so subsequent executions won't have the same path as the -# original. -# -# Conversely, when run as path/to/file.py, the directory containing -# file.py gets added to the path, which can cause confusion as imports -# may become relative in spite of the future import. -# -# We address the former problem by reconstructing the original command -# line (Python >= 3.4) or by setting the $PYTHONPATH environment -# variable (Python < 3.4) before re-execution so the new process will -# see the correct path. We attempt to address the latter problem when -# tornado.autoreload is run as __main__. - -if __name__ == "__main__": - # This sys.path manipulation must come before our imports (as much - # as possible - if we introduced a tornado.sys or tornado.os - # module we'd be in trouble), or else our imports would become - # relative again despite the future import. - # - # There is a separate __main__ block at the end of the file to call main(). - if sys.path[0] == os.path.dirname(__file__): - del sys.path[0] - -import functools -import logging -import os -import pkgutil # type: ignore -import sys -import traceback -import types -import subprocess -import weakref - -from tornado import ioloop -from tornado.log import gen_log -from tornado import process -from tornado.util import exec_in - -try: - import signal -except ImportError: - signal = None # type: ignore - -import typing -from typing import Callable, Dict - -if typing.TYPE_CHECKING: - from typing import List, Optional, Union # noqa: F401 - -# os.execv is broken on Windows and can't properly parse command line -# arguments and executable name if they contain whitespaces. subprocess -# fixes that behavior. -_has_execv = sys.platform != "win32" - -_watched_files = set() -_reload_hooks = [] -_reload_attempted = False -_io_loops = weakref.WeakKeyDictionary() # type: ignore -_autoreload_is_main = False -_original_argv = None # type: Optional[List[str]] -_original_spec = None - - -def start(check_time: int = 500) -> None: - """Begins watching source files for changes. - - .. versionchanged:: 5.0 - The ``io_loop`` argument (deprecated since version 4.1) has been removed. - """ - io_loop = ioloop.IOLoop.current() - if io_loop in _io_loops: - return - _io_loops[io_loop] = True - if len(_io_loops) > 1: - gen_log.warning("tornado.autoreload started more than once in the same process") - modify_times = {} # type: Dict[str, float] - callback = functools.partial(_reload_on_update, modify_times) - scheduler = ioloop.PeriodicCallback(callback, check_time) - scheduler.start() - - -def wait() -> None: - """Wait for a watched file to change, then restart the process. - - Intended to be used at the end of scripts like unit test runners, - to run the tests again after any source file changes (but see also - the command-line interface in `main`) - """ - io_loop = ioloop.IOLoop() - io_loop.add_callback(start) - io_loop.start() - - -def watch(filename: str) -> None: - """Add a file to the watch list. - - All imported modules are watched by default. - """ - _watched_files.add(filename) - - -def add_reload_hook(fn: Callable[[], None]) -> None: - """Add a function to be called before reloading the process. - - Note that for open file and socket handles it is generally - preferable to set the ``FD_CLOEXEC`` flag (using `fcntl` or - `os.set_inheritable`) instead of using a reload hook to close them. - """ - _reload_hooks.append(fn) - - -def _reload_on_update(modify_times: Dict[str, float]) -> None: - if _reload_attempted: - # We already tried to reload and it didn't work, so don't try again. - return - if process.task_id() is not None: - # We're in a child process created by fork_processes. If child - # processes restarted themselves, they'd all restart and then - # all call fork_processes again. - return - for module in list(sys.modules.values()): - # Some modules play games with sys.modules (e.g. email/__init__.py - # in the standard library), and occasionally this can cause strange - # failures in getattr. Just ignore anything that's not an ordinary - # module. - if not isinstance(module, types.ModuleType): - continue - path = getattr(module, "__file__", None) - if not path: - continue - if path.endswith(".pyc") or path.endswith(".pyo"): - path = path[:-1] - _check_file(modify_times, path) - for path in _watched_files: - _check_file(modify_times, path) - - -def _check_file(modify_times: Dict[str, float], path: str) -> None: - try: - modified = os.stat(path).st_mtime - except Exception: - return - if path not in modify_times: - modify_times[path] = modified - return - if modify_times[path] != modified: - gen_log.info("%s modified; restarting server", path) - _reload() - - -def _reload() -> None: - global _reload_attempted - _reload_attempted = True - for fn in _reload_hooks: - fn() - if hasattr(signal, "setitimer"): - # Clear the alarm signal set by - # ioloop.set_blocking_log_threshold so it doesn't fire - # after the exec. - signal.setitimer(signal.ITIMER_REAL, 0, 0) - # sys.path fixes: see comments at top of file. If __main__.__spec__ - # exists, we were invoked with -m and the effective path is about to - # change on re-exec. Reconstruct the original command line to - # ensure that the new process sees the same path we did. If - # __spec__ is not available (Python < 3.4), check instead if - # sys.path[0] is an empty string and add the current directory to - # $PYTHONPATH. - if _autoreload_is_main: - assert _original_argv is not None - spec = _original_spec - argv = _original_argv - else: - spec = getattr(sys.modules["__main__"], "__spec__", None) - argv = sys.argv - if spec: - argv = ["-m", spec.name] + argv[1:] - else: - path_prefix = "." + os.pathsep - if sys.path[0] == "" and not os.environ.get("PYTHONPATH", "").startswith( - path_prefix - ): - os.environ["PYTHONPATH"] = path_prefix + os.environ.get("PYTHONPATH", "") - if not _has_execv: - subprocess.Popen([sys.executable] + argv) - os._exit(0) - else: - try: - os.execv(sys.executable, [sys.executable] + argv) - except OSError: - # Mac OS X versions prior to 10.6 do not support execv in - # a process that contains multiple threads. Instead of - # re-executing in the current process, start a new one - # and cause the current process to exit. This isn't - # ideal since the new process is detached from the parent - # terminal and thus cannot easily be killed with ctrl-C, - # but it's better than not being able to autoreload at - # all. - # Unfortunately the errno returned in this case does not - # appear to be consistent, so we can't easily check for - # this error specifically. - os.spawnv( - os.P_NOWAIT, sys.executable, [sys.executable] + argv # type: ignore - ) - # At this point the IOLoop has been closed and finally - # blocks will experience errors if we allow the stack to - # unwind, so just exit uncleanly. - os._exit(0) - - -_USAGE = """\ -Usage: - python -m tornado.autoreload -m module.to.run [args...] - python -m tornado.autoreload path/to/script.py [args...] -""" - - -def main() -> None: - """Command-line wrapper to re-run a script whenever its source changes. - - Scripts may be specified by filename or module name:: - - python -m tornado.autoreload -m tornado.test.runtests - python -m tornado.autoreload tornado/test/runtests.py - - Running a script with this wrapper is similar to calling - `tornado.autoreload.wait` at the end of the script, but this wrapper - can catch import-time problems like syntax errors that would otherwise - prevent the script from reaching its call to `wait`. - """ - # Remember that we were launched with autoreload as main. - # The main module can be tricky; set the variables both in our globals - # (which may be __main__) and the real importable version. - import tornado.autoreload - - global _autoreload_is_main - global _original_argv, _original_spec - tornado.autoreload._autoreload_is_main = _autoreload_is_main = True - original_argv = sys.argv - tornado.autoreload._original_argv = _original_argv = original_argv - original_spec = getattr(sys.modules["__main__"], "__spec__", None) - tornado.autoreload._original_spec = _original_spec = original_spec - sys.argv = sys.argv[:] - if len(sys.argv) >= 3 and sys.argv[1] == "-m": - mode = "module" - module = sys.argv[2] - del sys.argv[1:3] - elif len(sys.argv) >= 2: - mode = "script" - script = sys.argv[1] - sys.argv = sys.argv[1:] - else: - print(_USAGE, file=sys.stderr) - sys.exit(1) - - try: - if mode == "module": - import runpy - - runpy.run_module(module, run_name="__main__", alter_sys=True) - elif mode == "script": - with open(script) as f: - # Execute the script in our namespace instead of creating - # a new one so that something that tries to import __main__ - # (e.g. the unittest module) will see names defined in the - # script instead of just those defined in this module. - global __file__ - __file__ = script - # If __package__ is defined, imports may be incorrectly - # interpreted as relative to this module. - global __package__ - del __package__ - exec_in(f.read(), globals(), globals()) - except SystemExit as e: - logging.basicConfig() - gen_log.info("Script exited with status %s", e.code) - except Exception as e: - logging.basicConfig() - gen_log.warning("Script exited with uncaught exception", exc_info=True) - # If an exception occurred at import time, the file with the error - # never made it into sys.modules and so we won't know to watch it. - # Just to make sure we've covered everything, walk the stack trace - # from the exception and watch every file. - for (filename, lineno, name, line) in traceback.extract_tb(sys.exc_info()[2]): - watch(filename) - if isinstance(e, SyntaxError): - # SyntaxErrors are special: their innermost stack frame is fake - # so extract_tb won't see it and we have to get the filename - # from the exception object. - watch(e.filename) - else: - logging.basicConfig() - gen_log.info("Script exited normally") - # restore sys.argv so subsequent executions will include autoreload - sys.argv = original_argv - - if mode == "module": - # runpy did a fake import of the module as __main__, but now it's - # no longer in sys.modules. Figure out where it is and watch it. - loader = pkgutil.get_loader(module) - if loader is not None: - watch(loader.get_filename()) # type: ignore - - wait() - - -if __name__ == "__main__": - # See also the other __main__ block at the top of the file, which modifies - # sys.path before our imports - main() diff --git a/venv/lib/python3.8/site-packages/tornado/concurrent.py b/venv/lib/python3.8/site-packages/tornado/concurrent.py deleted file mode 100644 index 7638fcf..0000000 --- a/venv/lib/python3.8/site-packages/tornado/concurrent.py +++ /dev/null @@ -1,263 +0,0 @@ -# -# Copyright 2012 Facebook -# -# 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. -"""Utilities for working with ``Future`` objects. - -Tornado previously provided its own ``Future`` class, but now uses -`asyncio.Future`. This module contains utility functions for working -with `asyncio.Future` in a way that is backwards-compatible with -Tornado's old ``Future`` implementation. - -While this module is an important part of Tornado's internal -implementation, applications rarely need to interact with it -directly. - -""" - -import asyncio -from concurrent import futures -import functools -import sys -import types - -from tornado.log import app_log - -import typing -from typing import Any, Callable, Optional, Tuple, Union - -_T = typing.TypeVar("_T") - - -class ReturnValueIgnoredError(Exception): - # No longer used; was previously used by @return_future - pass - - -Future = asyncio.Future - -FUTURES = (futures.Future, Future) - - -def is_future(x: Any) -> bool: - return isinstance(x, FUTURES) - - -class DummyExecutor(futures.Executor): - def submit( - self, fn: Callable[..., _T], *args: Any, **kwargs: Any - ) -> "futures.Future[_T]": - future = futures.Future() # type: futures.Future[_T] - try: - future_set_result_unless_cancelled(future, fn(*args, **kwargs)) - except Exception: - future_set_exc_info(future, sys.exc_info()) - return future - - def shutdown(self, wait: bool = True) -> None: - pass - - -dummy_executor = DummyExecutor() - - -def run_on_executor(*args: Any, **kwargs: Any) -> Callable: - """Decorator to run a synchronous method asynchronously on an executor. - - Returns a future. - - The executor to be used is determined by the ``executor`` - attributes of ``self``. To use a different attribute name, pass a - keyword argument to the decorator:: - - @run_on_executor(executor='_thread_pool') - def foo(self): - pass - - This decorator should not be confused with the similarly-named - `.IOLoop.run_in_executor`. In general, using ``run_in_executor`` - when *calling* a blocking method is recommended instead of using - this decorator when *defining* a method. If compatibility with older - versions of Tornado is required, consider defining an executor - and using ``executor.submit()`` at the call site. - - .. versionchanged:: 4.2 - Added keyword arguments to use alternative attributes. - - .. versionchanged:: 5.0 - Always uses the current IOLoop instead of ``self.io_loop``. - - .. versionchanged:: 5.1 - Returns a `.Future` compatible with ``await`` instead of a - `concurrent.futures.Future`. - - .. deprecated:: 5.1 - - The ``callback`` argument is deprecated and will be removed in - 6.0. The decorator itself is discouraged in new code but will - not be removed in 6.0. - - .. versionchanged:: 6.0 - - The ``callback`` argument was removed. - """ - # Fully type-checking decorators is tricky, and this one is - # discouraged anyway so it doesn't have all the generic magic. - def run_on_executor_decorator(fn: Callable) -> Callable[..., Future]: - executor = kwargs.get("executor", "executor") - - @functools.wraps(fn) - def wrapper(self: Any, *args: Any, **kwargs: Any) -> Future: - async_future = Future() # type: Future - conc_future = getattr(self, executor).submit(fn, self, *args, **kwargs) - chain_future(conc_future, async_future) - return async_future - - return wrapper - - if args and kwargs: - raise ValueError("cannot combine positional and keyword args") - if len(args) == 1: - return run_on_executor_decorator(args[0]) - elif len(args) != 0: - raise ValueError("expected 1 argument, got %d", len(args)) - return run_on_executor_decorator - - -_NO_RESULT = object() - - -def chain_future(a: "Future[_T]", b: "Future[_T]") -> None: - """Chain two futures together so that when one completes, so does the other. - - The result (success or failure) of ``a`` will be copied to ``b``, unless - ``b`` has already been completed or cancelled by the time ``a`` finishes. - - .. versionchanged:: 5.0 - - Now accepts both Tornado/asyncio `Future` objects and - `concurrent.futures.Future`. - - """ - - def copy(future: "Future[_T]") -> None: - assert future is a - if b.done(): - return - if hasattr(a, "exc_info") and a.exc_info() is not None: # type: ignore - future_set_exc_info(b, a.exc_info()) # type: ignore - elif a.exception() is not None: - b.set_exception(a.exception()) - else: - b.set_result(a.result()) - - if isinstance(a, Future): - future_add_done_callback(a, copy) - else: - # concurrent.futures.Future - from tornado.ioloop import IOLoop - - IOLoop.current().add_future(a, copy) - - -def future_set_result_unless_cancelled( - future: "Union[futures.Future[_T], Future[_T]]", value: _T -) -> None: - """Set the given ``value`` as the `Future`'s result, if not cancelled. - - Avoids ``asyncio.InvalidStateError`` when calling ``set_result()`` on - a cancelled `asyncio.Future`. - - .. versionadded:: 5.0 - """ - if not future.cancelled(): - future.set_result(value) - - -def future_set_exception_unless_cancelled( - future: "Union[futures.Future[_T], Future[_T]]", exc: BaseException -) -> None: - """Set the given ``exc`` as the `Future`'s exception. - - If the Future is already canceled, logs the exception instead. If - this logging is not desired, the caller should explicitly check - the state of the Future and call ``Future.set_exception`` instead of - this wrapper. - - Avoids ``asyncio.InvalidStateError`` when calling ``set_exception()`` on - a cancelled `asyncio.Future`. - - .. versionadded:: 6.0 - - """ - if not future.cancelled(): - future.set_exception(exc) - else: - app_log.error("Exception after Future was cancelled", exc_info=exc) - - -def future_set_exc_info( - future: "Union[futures.Future[_T], Future[_T]]", - exc_info: Tuple[ - Optional[type], Optional[BaseException], Optional[types.TracebackType] - ], -) -> None: - """Set the given ``exc_info`` as the `Future`'s exception. - - Understands both `asyncio.Future` and the extensions in older - versions of Tornado to enable better tracebacks on Python 2. - - .. versionadded:: 5.0 - - .. versionchanged:: 6.0 - - If the future is already cancelled, this function is a no-op. - (previously ``asyncio.InvalidStateError`` would be raised) - - """ - if exc_info[1] is None: - raise Exception("future_set_exc_info called with no exception") - future_set_exception_unless_cancelled(future, exc_info[1]) - - -@typing.overload -def future_add_done_callback( - future: "futures.Future[_T]", callback: Callable[["futures.Future[_T]"], None] -) -> None: - pass - - -@typing.overload # noqa: F811 -def future_add_done_callback( - future: "Future[_T]", callback: Callable[["Future[_T]"], None] -) -> None: - pass - - -def future_add_done_callback( # noqa: F811 - future: "Union[futures.Future[_T], Future[_T]]", callback: Callable[..., None] -) -> None: - """Arrange to call ``callback`` when ``future`` is complete. - - ``callback`` is invoked with one argument, the ``future``. - - If ``future`` is already done, ``callback`` is invoked immediately. - This may differ from the behavior of ``Future.add_done_callback``, - which makes no such guarantee. - - .. versionadded:: 5.0 - """ - if future.done(): - callback(future) - else: - future.add_done_callback(callback) diff --git a/venv/lib/python3.8/site-packages/tornado/curl_httpclient.py b/venv/lib/python3.8/site-packages/tornado/curl_httpclient.py deleted file mode 100644 index 6553999..0000000 --- a/venv/lib/python3.8/site-packages/tornado/curl_httpclient.py +++ /dev/null @@ -1,583 +0,0 @@ -# -# Copyright 2009 Facebook -# -# 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. - -"""Non-blocking HTTP client implementation using pycurl.""" - -import collections -import functools -import logging -import pycurl -import threading -import time -from io import BytesIO - -from tornado import httputil -from tornado import ioloop - -from tornado.escape import utf8, native_str -from tornado.httpclient import ( - HTTPRequest, - HTTPResponse, - HTTPError, - AsyncHTTPClient, - main, -) -from tornado.log import app_log - -from typing import Dict, Any, Callable, Union, Tuple, Optional -import typing - -if typing.TYPE_CHECKING: - from typing import Deque # noqa: F401 - -curl_log = logging.getLogger("tornado.curl_httpclient") - - -class CurlAsyncHTTPClient(AsyncHTTPClient): - def initialize( # type: ignore - self, max_clients: int = 10, defaults: Optional[Dict[str, Any]] = None - ) -> None: - super().initialize(defaults=defaults) - # Typeshed is incomplete for CurlMulti, so just use Any for now. - self._multi = pycurl.CurlMulti() # type: Any - self._multi.setopt(pycurl.M_TIMERFUNCTION, self._set_timeout) - self._multi.setopt(pycurl.M_SOCKETFUNCTION, self._handle_socket) - self._curls = [self._curl_create() for i in range(max_clients)] - self._free_list = self._curls[:] - self._requests = ( - collections.deque() - ) # type: Deque[Tuple[HTTPRequest, Callable[[HTTPResponse], None], float]] - self._fds = {} # type: Dict[int, int] - self._timeout = None # type: Optional[object] - - # libcurl has bugs that sometimes cause it to not report all - # relevant file descriptors and timeouts to TIMERFUNCTION/ - # SOCKETFUNCTION. Mitigate the effects of such bugs by - # forcing a periodic scan of all active requests. - self._force_timeout_callback = ioloop.PeriodicCallback( - self._handle_force_timeout, 1000 - ) - self._force_timeout_callback.start() - - # Work around a bug in libcurl 7.29.0: Some fields in the curl - # multi object are initialized lazily, and its destructor will - # segfault if it is destroyed without having been used. Add - # and remove a dummy handle to make sure everything is - # initialized. - dummy_curl_handle = pycurl.Curl() - self._multi.add_handle(dummy_curl_handle) - self._multi.remove_handle(dummy_curl_handle) - - def close(self) -> None: - self._force_timeout_callback.stop() - if self._timeout is not None: - self.io_loop.remove_timeout(self._timeout) - for curl in self._curls: - curl.close() - self._multi.close() - super().close() - - # Set below properties to None to reduce the reference count of current - # instance, because those properties hold some methods of current - # instance that will case circular reference. - self._force_timeout_callback = None # type: ignore - self._multi = None - - def fetch_impl( - self, request: HTTPRequest, callback: Callable[[HTTPResponse], None] - ) -> None: - self._requests.append((request, callback, self.io_loop.time())) - self._process_queue() - self._set_timeout(0) - - def _handle_socket(self, event: int, fd: int, multi: Any, data: bytes) -> None: - """Called by libcurl when it wants to change the file descriptors - it cares about. - """ - event_map = { - pycurl.POLL_NONE: ioloop.IOLoop.NONE, - pycurl.POLL_IN: ioloop.IOLoop.READ, - pycurl.POLL_OUT: ioloop.IOLoop.WRITE, - pycurl.POLL_INOUT: ioloop.IOLoop.READ | ioloop.IOLoop.WRITE, - } - if event == pycurl.POLL_REMOVE: - if fd in self._fds: - self.io_loop.remove_handler(fd) - del self._fds[fd] - else: - ioloop_event = event_map[event] - # libcurl sometimes closes a socket and then opens a new - # one using the same FD without giving us a POLL_NONE in - # between. This is a problem with the epoll IOLoop, - # because the kernel can tell when a socket is closed and - # removes it from the epoll automatically, causing future - # update_handler calls to fail. Since we can't tell when - # this has happened, always use remove and re-add - # instead of update. - if fd in self._fds: - self.io_loop.remove_handler(fd) - self.io_loop.add_handler(fd, self._handle_events, ioloop_event) - self._fds[fd] = ioloop_event - - def _set_timeout(self, msecs: int) -> None: - """Called by libcurl to schedule a timeout.""" - if self._timeout is not None: - self.io_loop.remove_timeout(self._timeout) - self._timeout = self.io_loop.add_timeout( - self.io_loop.time() + msecs / 1000.0, self._handle_timeout - ) - - def _handle_events(self, fd: int, events: int) -> None: - """Called by IOLoop when there is activity on one of our - file descriptors. - """ - action = 0 - if events & ioloop.IOLoop.READ: - action |= pycurl.CSELECT_IN - if events & ioloop.IOLoop.WRITE: - action |= pycurl.CSELECT_OUT - while True: - try: - ret, num_handles = self._multi.socket_action(fd, action) - except pycurl.error as e: - ret = e.args[0] - if ret != pycurl.E_CALL_MULTI_PERFORM: - break - self._finish_pending_requests() - - def _handle_timeout(self) -> None: - """Called by IOLoop when the requested timeout has passed.""" - self._timeout = None - while True: - try: - ret, num_handles = self._multi.socket_action(pycurl.SOCKET_TIMEOUT, 0) - except pycurl.error as e: - ret = e.args[0] - if ret != pycurl.E_CALL_MULTI_PERFORM: - break - self._finish_pending_requests() - - # In theory, we shouldn't have to do this because curl will - # call _set_timeout whenever the timeout changes. However, - # sometimes after _handle_timeout we will need to reschedule - # immediately even though nothing has changed from curl's - # perspective. This is because when socket_action is - # called with SOCKET_TIMEOUT, libcurl decides internally which - # timeouts need to be processed by using a monotonic clock - # (where available) while tornado uses python's time.time() - # to decide when timeouts have occurred. When those clocks - # disagree on elapsed time (as they will whenever there is an - # NTP adjustment), tornado might call _handle_timeout before - # libcurl is ready. After each timeout, resync the scheduled - # timeout with libcurl's current state. - new_timeout = self._multi.timeout() - if new_timeout >= 0: - self._set_timeout(new_timeout) - - def _handle_force_timeout(self) -> None: - """Called by IOLoop periodically to ask libcurl to process any - events it may have forgotten about. - """ - while True: - try: - ret, num_handles = self._multi.socket_all() - except pycurl.error as e: - ret = e.args[0] - if ret != pycurl.E_CALL_MULTI_PERFORM: - break - self._finish_pending_requests() - - def _finish_pending_requests(self) -> None: - """Process any requests that were completed by the last - call to multi.socket_action. - """ - while True: - num_q, ok_list, err_list = self._multi.info_read() - for curl in ok_list: - self._finish(curl) - for curl, errnum, errmsg in err_list: - self._finish(curl, errnum, errmsg) - if num_q == 0: - break - self._process_queue() - - def _process_queue(self) -> None: - while True: - started = 0 - while self._free_list and self._requests: - started += 1 - curl = self._free_list.pop() - (request, callback, queue_start_time) = self._requests.popleft() - # TODO: Don't smuggle extra data on an attribute of the Curl object. - curl.info = { # type: ignore - "headers": httputil.HTTPHeaders(), - "buffer": BytesIO(), - "request": request, - "callback": callback, - "queue_start_time": queue_start_time, - "curl_start_time": time.time(), - "curl_start_ioloop_time": self.io_loop.current().time(), - } - try: - self._curl_setup_request( - curl, - request, - curl.info["buffer"], # type: ignore - curl.info["headers"], # type: ignore - ) - except Exception as e: - # If there was an error in setup, pass it on - # to the callback. Note that allowing the - # error to escape here will appear to work - # most of the time since we are still in the - # caller's original stack frame, but when - # _process_queue() is called from - # _finish_pending_requests the exceptions have - # nowhere to go. - self._free_list.append(curl) - callback(HTTPResponse(request=request, code=599, error=e)) - else: - self._multi.add_handle(curl) - - if not started: - break - - def _finish( - self, - curl: pycurl.Curl, - curl_error: Optional[int] = None, - curl_message: Optional[str] = None, - ) -> None: - info = curl.info # type: ignore - curl.info = None # type: ignore - self._multi.remove_handle(curl) - self._free_list.append(curl) - buffer = info["buffer"] - if curl_error: - assert curl_message is not None - error = CurlError(curl_error, curl_message) # type: Optional[CurlError] - assert error is not None - code = error.code - effective_url = None - buffer.close() - buffer = None - else: - error = None - code = curl.getinfo(pycurl.HTTP_CODE) - effective_url = curl.getinfo(pycurl.EFFECTIVE_URL) - buffer.seek(0) - # the various curl timings are documented at - # http://curl.haxx.se/libcurl/c/curl_easy_getinfo.html - time_info = dict( - queue=info["curl_start_ioloop_time"] - info["queue_start_time"], - namelookup=curl.getinfo(pycurl.NAMELOOKUP_TIME), - connect=curl.getinfo(pycurl.CONNECT_TIME), - appconnect=curl.getinfo(pycurl.APPCONNECT_TIME), - pretransfer=curl.getinfo(pycurl.PRETRANSFER_TIME), - starttransfer=curl.getinfo(pycurl.STARTTRANSFER_TIME), - total=curl.getinfo(pycurl.TOTAL_TIME), - redirect=curl.getinfo(pycurl.REDIRECT_TIME), - ) - try: - info["callback"]( - HTTPResponse( - request=info["request"], - code=code, - headers=info["headers"], - buffer=buffer, - effective_url=effective_url, - error=error, - reason=info["headers"].get("X-Http-Reason", None), - request_time=self.io_loop.time() - info["curl_start_ioloop_time"], - start_time=info["curl_start_time"], - time_info=time_info, - ) - ) - except Exception: - self.handle_callback_exception(info["callback"]) - - def handle_callback_exception(self, callback: Any) -> None: - app_log.error("Exception in callback %r", callback, exc_info=True) - - def _curl_create(self) -> pycurl.Curl: - curl = pycurl.Curl() - if curl_log.isEnabledFor(logging.DEBUG): - curl.setopt(pycurl.VERBOSE, 1) - curl.setopt(pycurl.DEBUGFUNCTION, self._curl_debug) - if hasattr( - pycurl, "PROTOCOLS" - ): # PROTOCOLS first appeared in pycurl 7.19.5 (2014-07-12) - curl.setopt(pycurl.PROTOCOLS, pycurl.PROTO_HTTP | pycurl.PROTO_HTTPS) - curl.setopt(pycurl.REDIR_PROTOCOLS, pycurl.PROTO_HTTP | pycurl.PROTO_HTTPS) - return curl - - def _curl_setup_request( - self, - curl: pycurl.Curl, - request: HTTPRequest, - buffer: BytesIO, - headers: httputil.HTTPHeaders, - ) -> None: - curl.setopt(pycurl.URL, native_str(request.url)) - - # libcurl's magic "Expect: 100-continue" behavior causes delays - # with servers that don't support it (which include, among others, - # Google's OpenID endpoint). Additionally, this behavior has - # a bug in conjunction with the curl_multi_socket_action API - # (https://sourceforge.net/tracker/?func=detail&atid=100976&aid=3039744&group_id=976), - # which increases the delays. It's more trouble than it's worth, - # so just turn off the feature (yes, setting Expect: to an empty - # value is the official way to disable this) - if "Expect" not in request.headers: - request.headers["Expect"] = "" - - # libcurl adds Pragma: no-cache by default; disable that too - if "Pragma" not in request.headers: - request.headers["Pragma"] = "" - - curl.setopt( - pycurl.HTTPHEADER, - [ - "%s: %s" % (native_str(k), native_str(v)) - for k, v in request.headers.get_all() - ], - ) - - curl.setopt( - pycurl.HEADERFUNCTION, - functools.partial( - self._curl_header_callback, headers, request.header_callback - ), - ) - if request.streaming_callback: - - def write_function(b: Union[bytes, bytearray]) -> int: - assert request.streaming_callback is not None - self.io_loop.add_callback(request.streaming_callback, b) - return len(b) - - else: - write_function = buffer.write - curl.setopt(pycurl.WRITEFUNCTION, write_function) - curl.setopt(pycurl.FOLLOWLOCATION, request.follow_redirects) - curl.setopt(pycurl.MAXREDIRS, request.max_redirects) - assert request.connect_timeout is not None - curl.setopt(pycurl.CONNECTTIMEOUT_MS, int(1000 * request.connect_timeout)) - assert request.request_timeout is not None - curl.setopt(pycurl.TIMEOUT_MS, int(1000 * request.request_timeout)) - if request.user_agent: - curl.setopt(pycurl.USERAGENT, native_str(request.user_agent)) - else: - curl.setopt(pycurl.USERAGENT, "Mozilla/5.0 (compatible; pycurl)") - if request.network_interface: - curl.setopt(pycurl.INTERFACE, request.network_interface) - if request.decompress_response: - curl.setopt(pycurl.ENCODING, "gzip,deflate") - else: - curl.setopt(pycurl.ENCODING, None) - if request.proxy_host and request.proxy_port: - curl.setopt(pycurl.PROXY, request.proxy_host) - curl.setopt(pycurl.PROXYPORT, request.proxy_port) - if request.proxy_username: - assert request.proxy_password is not None - credentials = httputil.encode_username_password( - request.proxy_username, request.proxy_password - ) - curl.setopt(pycurl.PROXYUSERPWD, credentials) - - if request.proxy_auth_mode is None or request.proxy_auth_mode == "basic": - curl.setopt(pycurl.PROXYAUTH, pycurl.HTTPAUTH_BASIC) - elif request.proxy_auth_mode == "digest": - curl.setopt(pycurl.PROXYAUTH, pycurl.HTTPAUTH_DIGEST) - else: - raise ValueError( - "Unsupported proxy_auth_mode %s" % request.proxy_auth_mode - ) - else: - try: - curl.unsetopt(pycurl.PROXY) - except TypeError: # not supported, disable proxy - curl.setopt(pycurl.PROXY, "") - curl.unsetopt(pycurl.PROXYUSERPWD) - if request.validate_cert: - curl.setopt(pycurl.SSL_VERIFYPEER, 1) - curl.setopt(pycurl.SSL_VERIFYHOST, 2) - else: - curl.setopt(pycurl.SSL_VERIFYPEER, 0) - curl.setopt(pycurl.SSL_VERIFYHOST, 0) - if request.ca_certs is not None: - curl.setopt(pycurl.CAINFO, request.ca_certs) - else: - # There is no way to restore pycurl.CAINFO to its default value - # (Using unsetopt makes it reject all certificates). - # I don't see any way to read the default value from python so it - # can be restored later. We'll have to just leave CAINFO untouched - # if no ca_certs file was specified, and require that if any - # request uses a custom ca_certs file, they all must. - pass - - if request.allow_ipv6 is False: - # Curl behaves reasonably when DNS resolution gives an ipv6 address - # that we can't reach, so allow ipv6 unless the user asks to disable. - curl.setopt(pycurl.IPRESOLVE, pycurl.IPRESOLVE_V4) - else: - curl.setopt(pycurl.IPRESOLVE, pycurl.IPRESOLVE_WHATEVER) - - # Set the request method through curl's irritating interface which makes - # up names for almost every single method - curl_options = { - "GET": pycurl.HTTPGET, - "POST": pycurl.POST, - "PUT": pycurl.UPLOAD, - "HEAD": pycurl.NOBODY, - } - custom_methods = set(["DELETE", "OPTIONS", "PATCH"]) - for o in curl_options.values(): - curl.setopt(o, False) - if request.method in curl_options: - curl.unsetopt(pycurl.CUSTOMREQUEST) - curl.setopt(curl_options[request.method], True) - elif request.allow_nonstandard_methods or request.method in custom_methods: - curl.setopt(pycurl.CUSTOMREQUEST, request.method) - else: - raise KeyError("unknown method " + request.method) - - body_expected = request.method in ("POST", "PATCH", "PUT") - body_present = request.body is not None - if not request.allow_nonstandard_methods: - # Some HTTP methods nearly always have bodies while others - # almost never do. Fail in this case unless the user has - # opted out of sanity checks with allow_nonstandard_methods. - if (body_expected and not body_present) or ( - body_present and not body_expected - ): - raise ValueError( - "Body must %sbe None for method %s (unless " - "allow_nonstandard_methods is true)" - % ("not " if body_expected else "", request.method) - ) - - if body_expected or body_present: - if request.method == "GET": - # Even with `allow_nonstandard_methods` we disallow - # GET with a body (because libcurl doesn't allow it - # unless we use CUSTOMREQUEST). While the spec doesn't - # forbid clients from sending a body, it arguably - # disallows the server from doing anything with them. - raise ValueError("Body must be None for GET request") - request_buffer = BytesIO(utf8(request.body or "")) - - def ioctl(cmd: int) -> None: - if cmd == curl.IOCMD_RESTARTREAD: # type: ignore - request_buffer.seek(0) - - curl.setopt(pycurl.READFUNCTION, request_buffer.read) - curl.setopt(pycurl.IOCTLFUNCTION, ioctl) - if request.method == "POST": - curl.setopt(pycurl.POSTFIELDSIZE, len(request.body or "")) - else: - curl.setopt(pycurl.UPLOAD, True) - curl.setopt(pycurl.INFILESIZE, len(request.body or "")) - - if request.auth_username is not None: - assert request.auth_password is not None - if request.auth_mode is None or request.auth_mode == "basic": - curl.setopt(pycurl.HTTPAUTH, pycurl.HTTPAUTH_BASIC) - elif request.auth_mode == "digest": - curl.setopt(pycurl.HTTPAUTH, pycurl.HTTPAUTH_DIGEST) - else: - raise ValueError("Unsupported auth_mode %s" % request.auth_mode) - - userpwd = httputil.encode_username_password( - request.auth_username, request.auth_password - ) - curl.setopt(pycurl.USERPWD, userpwd) - curl_log.debug( - "%s %s (username: %r)", - request.method, - request.url, - request.auth_username, - ) - else: - curl.unsetopt(pycurl.USERPWD) - curl_log.debug("%s %s", request.method, request.url) - - if request.client_cert is not None: - curl.setopt(pycurl.SSLCERT, request.client_cert) - - if request.client_key is not None: - curl.setopt(pycurl.SSLKEY, request.client_key) - - if request.ssl_options is not None: - raise ValueError("ssl_options not supported in curl_httpclient") - - if threading.active_count() > 1: - # libcurl/pycurl is not thread-safe by default. When multiple threads - # are used, signals should be disabled. This has the side effect - # of disabling DNS timeouts in some environments (when libcurl is - # not linked against ares), so we don't do it when there is only one - # thread. Applications that use many short-lived threads may need - # to set NOSIGNAL manually in a prepare_curl_callback since - # there may not be any other threads running at the time we call - # threading.activeCount. - curl.setopt(pycurl.NOSIGNAL, 1) - if request.prepare_curl_callback is not None: - request.prepare_curl_callback(curl) - - def _curl_header_callback( - self, - headers: httputil.HTTPHeaders, - header_callback: Callable[[str], None], - header_line_bytes: bytes, - ) -> None: - header_line = native_str(header_line_bytes.decode("latin1")) - if header_callback is not None: - self.io_loop.add_callback(header_callback, header_line) - # header_line as returned by curl includes the end-of-line characters. - # whitespace at the start should be preserved to allow multi-line headers - header_line = header_line.rstrip() - if header_line.startswith("HTTP/"): - headers.clear() - try: - (__, __, reason) = httputil.parse_response_start_line(header_line) - header_line = "X-Http-Reason: %s" % reason - except httputil.HTTPInputError: - return - if not header_line: - return - headers.parse_line(header_line) - - def _curl_debug(self, debug_type: int, debug_msg: str) -> None: - debug_types = ("I", "<", ">", "<", ">") - if debug_type == 0: - debug_msg = native_str(debug_msg) - curl_log.debug("%s", debug_msg.strip()) - elif debug_type in (1, 2): - debug_msg = native_str(debug_msg) - for line in debug_msg.splitlines(): - curl_log.debug("%s %s", debug_types[debug_type], line) - elif debug_type == 4: - curl_log.debug("%s %r", debug_types[debug_type], debug_msg) - - -class CurlError(HTTPError): - def __init__(self, errno: int, message: str) -> None: - HTTPError.__init__(self, 599, message) - self.errno = errno - - -if __name__ == "__main__": - AsyncHTTPClient.configure(CurlAsyncHTTPClient) - main() diff --git a/venv/lib/python3.8/site-packages/tornado/escape.py b/venv/lib/python3.8/site-packages/tornado/escape.py deleted file mode 100644 index 3cf7ff2..0000000 --- a/venv/lib/python3.8/site-packages/tornado/escape.py +++ /dev/null @@ -1,402 +0,0 @@ -# -# Copyright 2009 Facebook -# -# 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. - -"""Escaping/unescaping methods for HTML, JSON, URLs, and others. - -Also includes a few other miscellaneous string manipulation functions that -have crept in over time. -""" - -import html.entities -import json -import re -import urllib.parse - -from tornado.util import unicode_type - -import typing -from typing import Union, Any, Optional, Dict, List, Callable - - -_XHTML_ESCAPE_RE = re.compile("[&<>\"']") -_XHTML_ESCAPE_DICT = { - "&": "&amp;", - "<": "&lt;", - ">": "&gt;", - '"': "&quot;", - "'": "&#39;", -} - - -def xhtml_escape(value: Union[str, bytes]) -> str: - """Escapes a string so it is valid within HTML or XML. - - Escapes the characters ``<``, ``>``, ``"``, ``'``, and ``&``. - When used in attribute values the escaped strings must be enclosed - in quotes. - - .. versionchanged:: 3.2 - - Added the single quote to the list of escaped characters. - """ - return _XHTML_ESCAPE_RE.sub( - lambda match: _XHTML_ESCAPE_DICT[match.group(0)], to_basestring(value) - ) - - -def xhtml_unescape(value: Union[str, bytes]) -> str: - """Un-escapes an XML-escaped string.""" - return re.sub(r"&(#?)(\w+?);", _convert_entity, _unicode(value)) - - -# The fact that json_encode wraps json.dumps is an implementation detail. -# Please see https://github.com/tornadoweb/tornado/pull/706 -# before sending a pull request that adds **kwargs to this function. -def json_encode(value: Any) -> str: - """JSON-encodes the given Python object.""" - # JSON permits but does not require forward slashes to be escaped. - # This is useful when json data is emitted in a <script> tag - # in HTML, as it prevents </script> tags from prematurely terminating - # the JavaScript. Some json libraries do this escaping by default, - # although python's standard library does not, so we do it here. - # http://stackoverflow.com/questions/1580647/json-why-are-forward-slashes-escaped - return json.dumps(value).replace("</", "<\\/") - - -def json_decode(value: Union[str, bytes]) -> Any: - """Returns Python objects for the given JSON string. - - Supports both `str` and `bytes` inputs. - """ - return json.loads(to_basestring(value)) - - -def squeeze(value: str) -> str: - """Replace all sequences of whitespace chars with a single space.""" - return re.sub(r"[\x00-\x20]+", " ", value).strip() - - -def url_escape(value: Union[str, bytes], plus: bool = True) -> str: - """Returns a URL-encoded version of the given value. - - If ``plus`` is true (the default), spaces will be represented - as "+" instead of "%20". This is appropriate for query strings - but not for the path component of a URL. Note that this default - is the reverse of Python's urllib module. - - .. versionadded:: 3.1 - The ``plus`` argument - """ - quote = urllib.parse.quote_plus if plus else urllib.parse.quote - return quote(utf8(value)) - - -@typing.overload -def url_unescape(value: Union[str, bytes], encoding: None, plus: bool = True) -> bytes: - pass - - -@typing.overload # noqa: F811 -def url_unescape( - value: Union[str, bytes], encoding: str = "utf-8", plus: bool = True -) -> str: - pass - - -def url_unescape( # noqa: F811 - value: Union[str, bytes], encoding: Optional[str] = "utf-8", plus: bool = True -) -> Union[str, bytes]: - """Decodes the given value from a URL. - - The argument may be either a byte or unicode string. - - If encoding is None, the result will be a byte string. Otherwise, - the result is a unicode string in the specified encoding. - - If ``plus`` is true (the default), plus signs will be interpreted - as spaces (literal plus signs must be represented as "%2B"). This - is appropriate for query strings and form-encoded values but not - for the path component of a URL. Note that this default is the - reverse of Python's urllib module. - - .. versionadded:: 3.1 - The ``plus`` argument - """ - if encoding is None: - if plus: - # unquote_to_bytes doesn't have a _plus variant - value = to_basestring(value).replace("+", " ") - return urllib.parse.unquote_to_bytes(value) - else: - unquote = urllib.parse.unquote_plus if plus else urllib.parse.unquote - return unquote(to_basestring(value), encoding=encoding) - - -def parse_qs_bytes( - qs: Union[str, bytes], keep_blank_values: bool = False, strict_parsing: bool = False -) -> Dict[str, List[bytes]]: - """Parses a query string like urlparse.parse_qs, - but takes bytes and returns the values as byte strings. - - Keys still become type str (interpreted as latin1 in python3!) - because it's too painful to keep them as byte strings in - python3 and in practice they're nearly always ascii anyway. - """ - # This is gross, but python3 doesn't give us another way. - # Latin1 is the universal donor of character encodings. - if isinstance(qs, bytes): - qs = qs.decode("latin1") - result = urllib.parse.parse_qs( - qs, keep_blank_values, strict_parsing, encoding="latin1", errors="strict" - ) - encoded = {} - for k, v in result.items(): - encoded[k] = [i.encode("latin1") for i in v] - return encoded - - -_UTF8_TYPES = (bytes, type(None)) - - -@typing.overload -def utf8(value: bytes) -> bytes: - pass - - -@typing.overload # noqa: F811 -def utf8(value: str) -> bytes: - pass - - -@typing.overload # noqa: F811 -def utf8(value: None) -> None: - pass - - -def utf8(value: Union[None, str, bytes]) -> Optional[bytes]: # noqa: F811 - """Converts a string argument to a byte string. - - If the argument is already a byte string or None, it is returned unchanged. - Otherwise it must be a unicode string and is encoded as utf8. - """ - if isinstance(value, _UTF8_TYPES): - return value - if not isinstance(value, unicode_type): - raise TypeError("Expected bytes, unicode, or None; got %r" % type(value)) - return value.encode("utf-8") - - -_TO_UNICODE_TYPES = (unicode_type, type(None)) - - -@typing.overload -def to_unicode(value: str) -> str: - pass - - -@typing.overload # noqa: F811 -def to_unicode(value: bytes) -> str: - pass - - -@typing.overload # noqa: F811 -def to_unicode(value: None) -> None: - pass - - -def to_unicode(value: Union[None, str, bytes]) -> Optional[str]: # noqa: F811 - """Converts a string argument to a unicode string. - - If the argument is already a unicode string or None, it is returned - unchanged. Otherwise it must be a byte string and is decoded as utf8. - """ - if isinstance(value, _TO_UNICODE_TYPES): - return value - if not isinstance(value, bytes): - raise TypeError("Expected bytes, unicode, or None; got %r" % type(value)) - return value.decode("utf-8") - - -# to_unicode was previously named _unicode not because it was private, -# but to avoid conflicts with the built-in unicode() function/type -_unicode = to_unicode - -# When dealing with the standard library across python 2 and 3 it is -# sometimes useful to have a direct conversion to the native string type -native_str = to_unicode -to_basestring = to_unicode - - -def recursive_unicode(obj: Any) -> Any: - """Walks a simple data structure, converting byte strings to unicode. - - Supports lists, tuples, and dictionaries. - """ - if isinstance(obj, dict): - return dict( - (recursive_unicode(k), recursive_unicode(v)) for (k, v) in obj.items() - ) - elif isinstance(obj, list): - return list(recursive_unicode(i) for i in obj) - elif isinstance(obj, tuple): - return tuple(recursive_unicode(i) for i in obj) - elif isinstance(obj, bytes): - return to_unicode(obj) - else: - return obj - - -# I originally used the regex from -# http://daringfireball.net/2010/07/improved_regex_for_matching_urls -# but it gets all exponential on certain patterns (such as too many trailing -# dots), causing the regex matcher to never return. -# This regex should avoid those problems. -# Use to_unicode instead of tornado.util.u - we don't want backslashes getting -# processed as escapes. -_URL_RE = re.compile( - to_unicode( - r"""\b((?:([\w-]+):(/{1,3})|www[.])(?:(?:(?:[^\s&()]|&amp;|&quot;)*(?:[^!"#$%&'()*+,.:;<=>?@\[\]^`{|}~\s]))|(?:\((?:[^\s&()]|&amp;|&quot;)*\)))+)""" # noqa: E501 - ) -) - - -def linkify( - text: Union[str, bytes], - shorten: bool = False, - extra_params: Union[str, Callable[[str], str]] = "", - require_protocol: bool = False, - permitted_protocols: List[str] = ["http", "https"], -) -> str: - """Converts plain text into HTML with links. - - For example: ``linkify("Hello http://tornadoweb.org!")`` would return - ``Hello <a href="http://tornadoweb.org">http://tornadoweb.org</a>!`` - - Parameters: - - * ``shorten``: Long urls will be shortened for display. - - * ``extra_params``: Extra text to include in the link tag, or a callable - taking the link as an argument and returning the extra text - e.g. ``linkify(text, extra_params='rel="nofollow" class="external"')``, - or:: - - def extra_params_cb(url): - if url.startswith("http://example.com"): - return 'class="internal"' - else: - return 'class="external" rel="nofollow"' - linkify(text, extra_params=extra_params_cb) - - * ``require_protocol``: Only linkify urls which include a protocol. If - this is False, urls such as www.facebook.com will also be linkified. - - * ``permitted_protocols``: List (or set) of protocols which should be - linkified, e.g. ``linkify(text, permitted_protocols=["http", "ftp", - "mailto"])``. It is very unsafe to include protocols such as - ``javascript``. - """ - if extra_params and not callable(extra_params): - extra_params = " " + extra_params.strip() - - def make_link(m: typing.Match) -> str: - url = m.group(1) - proto = m.group(2) - if require_protocol and not proto: - return url # not protocol, no linkify - - if proto and proto not in permitted_protocols: - return url # bad protocol, no linkify - - href = m.group(1) - if not proto: - href = "http://" + href # no proto specified, use http - - if callable(extra_params): - params = " " + extra_params(href).strip() - else: - params = extra_params - - # clip long urls. max_len is just an approximation - max_len = 30 - if shorten and len(url) > max_len: - before_clip = url - if proto: - proto_len = len(proto) + 1 + len(m.group(3) or "") # +1 for : - else: - proto_len = 0 - - parts = url[proto_len:].split("/") - if len(parts) > 1: - # Grab the whole host part plus the first bit of the path - # The path is usually not that interesting once shortened - # (no more slug, etc), so it really just provides a little - # extra indication of shortening. - url = ( - url[:proto_len] - + parts[0] - + "/" - + parts[1][:8].split("?")[0].split(".")[0] - ) - - if len(url) > max_len * 1.5: # still too long - url = url[:max_len] - - if url != before_clip: - amp = url.rfind("&") - # avoid splitting html char entities - if amp > max_len - 5: - url = url[:amp] - url += "..." - - if len(url) >= len(before_clip): - url = before_clip - else: - # full url is visible on mouse-over (for those who don't - # have a status bar, such as Safari by default) - params += ' title="%s"' % href - - return u'<a href="%s"%s>%s</a>' % (href, params, url) - - # First HTML-escape so that our strings are all safe. - # The regex is modified to avoid character entites other than &amp; so - # that we won't pick up &quot;, etc. - text = _unicode(xhtml_escape(text)) - return _URL_RE.sub(make_link, text) - - -def _convert_entity(m: typing.Match) -> str: - if m.group(1) == "#": - try: - if m.group(2)[:1].lower() == "x": - return chr(int(m.group(2)[1:], 16)) - else: - return chr(int(m.group(2))) - except ValueError: - return "&#%s;" % m.group(2) - try: - return _HTML_UNICODE_MAP[m.group(2)] - except KeyError: - return "&%s;" % m.group(2) - - -def _build_unicode_map() -> Dict[str, str]: - unicode_map = {} - for name, value in html.entities.name2codepoint.items(): - unicode_map[name] = chr(value) - return unicode_map - - -_HTML_UNICODE_MAP = _build_unicode_map() diff --git a/venv/lib/python3.8/site-packages/tornado/gen.py b/venv/lib/python3.8/site-packages/tornado/gen.py deleted file mode 100644 index cab9689..0000000 --- a/venv/lib/python3.8/site-packages/tornado/gen.py +++ /dev/null @@ -1,872 +0,0 @@ -"""``tornado.gen`` implements generator-based coroutines. - -.. note:: - - The "decorator and generator" approach in this module is a - precursor to native coroutines (using ``async def`` and ``await``) - which were introduced in Python 3.5. Applications that do not - require compatibility with older versions of Python should use - native coroutines instead. Some parts of this module are still - useful with native coroutines, notably `multi`, `sleep`, - `WaitIterator`, and `with_timeout`. Some of these functions have - counterparts in the `asyncio` module which may be used as well, - although the two may not necessarily be 100% compatible. - -Coroutines provide an easier way to work in an asynchronous -environment than chaining callbacks. Code using coroutines is -technically asynchronous, but it is written as a single generator -instead of a collection of separate functions. - -For example, here's a coroutine-based handler: - -.. testcode:: - - class GenAsyncHandler(RequestHandler): - @gen.coroutine - def get(self): - http_client = AsyncHTTPClient() - response = yield http_client.fetch("http://example.com") - do_something_with_response(response) - self.render("template.html") - -.. testoutput:: - :hide: - -Asynchronous functions in Tornado return an ``Awaitable`` or `.Future`; -yielding this object returns its result. - -You can also yield a list or dict of other yieldable objects, which -will be started at the same time and run in parallel; a list or dict -of results will be returned when they are all finished: - -.. testcode:: - - @gen.coroutine - def get(self): - http_client = AsyncHTTPClient() - response1, response2 = yield [http_client.fetch(url1), - http_client.fetch(url2)] - response_dict = yield dict(response3=http_client.fetch(url3), - response4=http_client.fetch(url4)) - response3 = response_dict['response3'] - response4 = response_dict['response4'] - -.. testoutput:: - :hide: - -If ``tornado.platform.twisted`` is imported, it is also possible to -yield Twisted's ``Deferred`` objects. See the `convert_yielded` -function to extend this mechanism. - -.. versionchanged:: 3.2 - Dict support added. - -.. versionchanged:: 4.1 - Support added for yielding ``asyncio`` Futures and Twisted Deferreds - via ``singledispatch``. - -""" -import asyncio -import builtins -import collections -from collections.abc import Generator -import concurrent.futures -import datetime -import functools -from functools import singledispatch -from inspect import isawaitable -import sys -import types - -from tornado.concurrent import ( - Future, - is_future, - chain_future, - future_set_exc_info, - future_add_done_callback, - future_set_result_unless_cancelled, -) -from tornado.ioloop import IOLoop -from tornado.log import app_log -from tornado.util import TimeoutError - -try: - import contextvars -except ImportError: - contextvars = None # type: ignore - -import typing -from typing import Union, Any, Callable, List, Type, Tuple, Awaitable, Dict, overload - -if typing.TYPE_CHECKING: - from typing import Sequence, Deque, Optional, Set, Iterable # noqa: F401 - -_T = typing.TypeVar("_T") - -_Yieldable = Union[ - None, Awaitable, List[Awaitable], Dict[Any, Awaitable], concurrent.futures.Future -] - - -class KeyReuseError(Exception): - pass - - -class UnknownKeyError(Exception): - pass - - -class LeakedCallbackError(Exception): - pass - - -class BadYieldError(Exception): - pass - - -class ReturnValueIgnoredError(Exception): - pass - - -def _value_from_stopiteration(e: Union[StopIteration, "Return"]) -> Any: - try: - # StopIteration has a value attribute beginning in py33. - # So does our Return class. - return e.value - except AttributeError: - pass - try: - # Cython backports coroutine functionality by putting the value in - # e.args[0]. - return e.args[0] - except (AttributeError, IndexError): - return None - - -def _create_future() -> Future: - future = Future() # type: Future - # Fixup asyncio debug info by removing extraneous stack entries - source_traceback = getattr(future, "_source_traceback", ()) - while source_traceback: - # Each traceback entry is equivalent to a - # (filename, self.lineno, self.name, self.line) tuple - filename = source_traceback[-1][0] - if filename == __file__: - del source_traceback[-1] - else: - break - return future - - -def _fake_ctx_run(f: Callable[..., _T], *args: Any, **kw: Any) -> _T: - return f(*args, **kw) - - -@overload -def coroutine( - func: Callable[..., "Generator[Any, Any, _T]"] -) -> Callable[..., "Future[_T]"]: - ... - - -@overload -def coroutine(func: Callable[..., _T]) -> Callable[..., "Future[_T]"]: - ... - - -def coroutine( - func: Union[Callable[..., "Generator[Any, Any, _T]"], Callable[..., _T]] -) -> Callable[..., "Future[_T]"]: - """Decorator for asynchronous generators. - - For compatibility with older versions of Python, coroutines may - also "return" by raising the special exception `Return(value) - <Return>`. - - Functions with this decorator return a `.Future`. - - .. warning:: - - When exceptions occur inside a coroutine, the exception - information will be stored in the `.Future` object. You must - examine the result of the `.Future` object, or the exception - may go unnoticed by your code. This means yielding the function - if called from another coroutine, using something like - `.IOLoop.run_sync` for top-level calls, or passing the `.Future` - to `.IOLoop.add_future`. - - .. versionchanged:: 6.0 - - The ``callback`` argument was removed. Use the returned - awaitable object instead. - - """ - - @functools.wraps(func) - def wrapper(*args, **kwargs): - # type: (*Any, **Any) -> Future[_T] - # This function is type-annotated with a comment to work around - # https://bitbucket.org/pypy/pypy/issues/2868/segfault-with-args-type-annotation-in - future = _create_future() - if contextvars is not None: - ctx_run = contextvars.copy_context().run # type: Callable - else: - ctx_run = _fake_ctx_run - try: - result = ctx_run(func, *args, **kwargs) - except (Return, StopIteration) as e: - result = _value_from_stopiteration(e) - except Exception: - future_set_exc_info(future, sys.exc_info()) - try: - return future - finally: - # Avoid circular references - future = None # type: ignore - else: - if isinstance(result, Generator): - # Inline the first iteration of Runner.run. This lets us - # avoid the cost of creating a Runner when the coroutine - # never actually yields, which in turn allows us to - # use "optional" coroutines in critical path code without - # performance penalty for the synchronous case. - try: - yielded = ctx_run(next, result) - except (StopIteration, Return) as e: - future_set_result_unless_cancelled( - future, _value_from_stopiteration(e) - ) - except Exception: - future_set_exc_info(future, sys.exc_info()) - else: - # Provide strong references to Runner objects as long - # as their result future objects also have strong - # references (typically from the parent coroutine's - # Runner). This keeps the coroutine's Runner alive. - # We do this by exploiting the public API - # add_done_callback() instead of putting a private - # attribute on the Future. - # (GitHub issues #1769, #2229). - runner = Runner(ctx_run, result, future, yielded) - future.add_done_callback(lambda _: runner) - yielded = None - try: - return future - finally: - # Subtle memory optimization: if next() raised an exception, - # the future's exc_info contains a traceback which - # includes this stack frame. This creates a cycle, - # which will be collected at the next full GC but has - # been shown to greatly increase memory usage of - # benchmarks (relative to the refcount-based scheme - # used in the absence of cycles). We can avoid the - # cycle by clearing the local variable after we return it. - future = None # type: ignore - future_set_result_unless_cancelled(future, result) - return future - - wrapper.__wrapped__ = func # type: ignore - wrapper.__tornado_coroutine__ = True # type: ignore - return wrapper - - -def is_coroutine_function(func: Any) -> bool: - """Return whether *func* is a coroutine function, i.e. a function - wrapped with `~.gen.coroutine`. - - .. versionadded:: 4.5 - """ - return getattr(func, "__tornado_coroutine__", False) - - -class Return(Exception): - """Special exception to return a value from a `coroutine`. - - If this exception is raised, its value argument is used as the - result of the coroutine:: - - @gen.coroutine - def fetch_json(url): - response = yield AsyncHTTPClient().fetch(url) - raise gen.Return(json_decode(response.body)) - - In Python 3.3, this exception is no longer necessary: the ``return`` - statement can be used directly to return a value (previously - ``yield`` and ``return`` with a value could not be combined in the - same function). - - By analogy with the return statement, the value argument is optional, - but it is never necessary to ``raise gen.Return()``. The ``return`` - statement can be used with no arguments instead. - """ - - def __init__(self, value: Any = None) -> None: - super().__init__() - self.value = value - # Cython recognizes subclasses of StopIteration with a .args tuple. - self.args = (value,) - - -class WaitIterator(object): - """Provides an iterator to yield the results of awaitables as they finish. - - Yielding a set of awaitables like this: - - ``results = yield [awaitable1, awaitable2]`` - - pauses the coroutine until both ``awaitable1`` and ``awaitable2`` - return, and then restarts the coroutine with the results of both - awaitables. If either awaitable raises an exception, the - expression will raise that exception and all the results will be - lost. - - If you need to get the result of each awaitable as soon as possible, - or if you need the result of some awaitables even if others produce - errors, you can use ``WaitIterator``:: - - wait_iterator = gen.WaitIterator(awaitable1, awaitable2) - while not wait_iterator.done(): - try: - result = yield wait_iterator.next() - except Exception as e: - print("Error {} from {}".format(e, wait_iterator.current_future)) - else: - print("Result {} received from {} at {}".format( - result, wait_iterator.current_future, - wait_iterator.current_index)) - - Because results are returned as soon as they are available the - output from the iterator *will not be in the same order as the - input arguments*. If you need to know which future produced the - current result, you can use the attributes - ``WaitIterator.current_future``, or ``WaitIterator.current_index`` - to get the index of the awaitable from the input list. (if keyword - arguments were used in the construction of the `WaitIterator`, - ``current_index`` will use the corresponding keyword). - - On Python 3.5, `WaitIterator` implements the async iterator - protocol, so it can be used with the ``async for`` statement (note - that in this version the entire iteration is aborted if any value - raises an exception, while the previous example can continue past - individual errors):: - - async for result in gen.WaitIterator(future1, future2): - print("Result {} received from {} at {}".format( - result, wait_iterator.current_future, - wait_iterator.current_index)) - - .. versionadded:: 4.1 - - .. versionchanged:: 4.3 - Added ``async for`` support in Python 3.5. - - """ - - _unfinished = {} # type: Dict[Future, Union[int, str]] - - def __init__(self, *args: Future, **kwargs: Future) -> None: - if args and kwargs: - raise ValueError("You must provide args or kwargs, not both") - - if kwargs: - self._unfinished = dict((f, k) for (k, f) in kwargs.items()) - futures = list(kwargs.values()) # type: Sequence[Future] - else: - self._unfinished = dict((f, i) for (i, f) in enumerate(args)) - futures = args - - self._finished = collections.deque() # type: Deque[Future] - self.current_index = None # type: Optional[Union[str, int]] - self.current_future = None # type: Optional[Future] - self._running_future = None # type: Optional[Future] - - for future in futures: - future_add_done_callback(future, self._done_callback) - - def done(self) -> bool: - """Returns True if this iterator has no more results.""" - if self._finished or self._unfinished: - return False - # Clear the 'current' values when iteration is done. - self.current_index = self.current_future = None - return True - - def next(self) -> Future: - """Returns a `.Future` that will yield the next available result. - - Note that this `.Future` will not be the same object as any of - the inputs. - """ - self._running_future = Future() - - if self._finished: - self._return_result(self._finished.popleft()) - - return self._running_future - - def _done_callback(self, done: Future) -> None: - if self._running_future and not self._running_future.done(): - self._return_result(done) - else: - self._finished.append(done) - - def _return_result(self, done: Future) -> None: - """Called set the returned future's state that of the future - we yielded, and set the current future for the iterator. - """ - if self._running_future is None: - raise Exception("no future is running") - chain_future(done, self._running_future) - - self.current_future = done - self.current_index = self._unfinished.pop(done) - - def __aiter__(self) -> typing.AsyncIterator: - return self - - def __anext__(self) -> Future: - if self.done(): - # Lookup by name to silence pyflakes on older versions. - raise getattr(builtins, "StopAsyncIteration")() - return self.next() - - -def multi( - children: Union[List[_Yieldable], Dict[Any, _Yieldable]], - quiet_exceptions: "Union[Type[Exception], Tuple[Type[Exception], ...]]" = (), -) -> "Union[Future[List], Future[Dict]]": - """Runs multiple asynchronous operations in parallel. - - ``children`` may either be a list or a dict whose values are - yieldable objects. ``multi()`` returns a new yieldable - object that resolves to a parallel structure containing their - results. If ``children`` is a list, the result is a list of - results in the same order; if it is a dict, the result is a dict - with the same keys. - - That is, ``results = yield multi(list_of_futures)`` is equivalent - to:: - - results = [] - for future in list_of_futures: - results.append(yield future) - - If any children raise exceptions, ``multi()`` will raise the first - one. All others will be logged, unless they are of types - contained in the ``quiet_exceptions`` argument. - - In a ``yield``-based coroutine, it is not normally necessary to - call this function directly, since the coroutine runner will - do it automatically when a list or dict is yielded. However, - it is necessary in ``await``-based coroutines, or to pass - the ``quiet_exceptions`` argument. - - This function is available under the names ``multi()`` and ``Multi()`` - for historical reasons. - - Cancelling a `.Future` returned by ``multi()`` does not cancel its - children. `asyncio.gather` is similar to ``multi()``, but it does - cancel its children. - - .. versionchanged:: 4.2 - If multiple yieldables fail, any exceptions after the first - (which is raised) will be logged. Added the ``quiet_exceptions`` - argument to suppress this logging for selected exception types. - - .. versionchanged:: 4.3 - Replaced the class ``Multi`` and the function ``multi_future`` - with a unified function ``multi``. Added support for yieldables - other than ``YieldPoint`` and `.Future`. - - """ - return multi_future(children, quiet_exceptions=quiet_exceptions) - - -Multi = multi - - -def multi_future( - children: Union[List[_Yieldable], Dict[Any, _Yieldable]], - quiet_exceptions: "Union[Type[Exception], Tuple[Type[Exception], ...]]" = (), -) -> "Union[Future[List], Future[Dict]]": - """Wait for multiple asynchronous futures in parallel. - - Since Tornado 6.0, this function is exactly the same as `multi`. - - .. versionadded:: 4.0 - - .. versionchanged:: 4.2 - If multiple ``Futures`` fail, any exceptions after the first (which is - raised) will be logged. Added the ``quiet_exceptions`` - argument to suppress this logging for selected exception types. - - .. deprecated:: 4.3 - Use `multi` instead. - """ - if isinstance(children, dict): - keys = list(children.keys()) # type: Optional[List] - children_seq = children.values() # type: Iterable - else: - keys = None - children_seq = children - children_futs = list(map(convert_yielded, children_seq)) - assert all(is_future(i) or isinstance(i, _NullFuture) for i in children_futs) - unfinished_children = set(children_futs) - - future = _create_future() - if not children_futs: - future_set_result_unless_cancelled(future, {} if keys is not None else []) - - def callback(fut: Future) -> None: - unfinished_children.remove(fut) - if not unfinished_children: - result_list = [] - for f in children_futs: - try: - result_list.append(f.result()) - except Exception as e: - if future.done(): - if not isinstance(e, quiet_exceptions): - app_log.error( - "Multiple exceptions in yield list", exc_info=True - ) - else: - future_set_exc_info(future, sys.exc_info()) - if not future.done(): - if keys is not None: - future_set_result_unless_cancelled( - future, dict(zip(keys, result_list)) - ) - else: - future_set_result_unless_cancelled(future, result_list) - - listening = set() # type: Set[Future] - for f in children_futs: - if f not in listening: - listening.add(f) - future_add_done_callback(f, callback) - return future - - -def maybe_future(x: Any) -> Future: - """Converts ``x`` into a `.Future`. - - If ``x`` is already a `.Future`, it is simply returned; otherwise - it is wrapped in a new `.Future`. This is suitable for use as - ``result = yield gen.maybe_future(f())`` when you don't know whether - ``f()`` returns a `.Future` or not. - - .. deprecated:: 4.3 - This function only handles ``Futures``, not other yieldable objects. - Instead of `maybe_future`, check for the non-future result types - you expect (often just ``None``), and ``yield`` anything unknown. - """ - if is_future(x): - return x - else: - fut = _create_future() - fut.set_result(x) - return fut - - -def with_timeout( - timeout: Union[float, datetime.timedelta], - future: _Yieldable, - quiet_exceptions: "Union[Type[Exception], Tuple[Type[Exception], ...]]" = (), -) -> Future: - """Wraps a `.Future` (or other yieldable object) in a timeout. - - Raises `tornado.util.TimeoutError` if the input future does not - complete before ``timeout``, which may be specified in any form - allowed by `.IOLoop.add_timeout` (i.e. a `datetime.timedelta` or - an absolute time relative to `.IOLoop.time`) - - If the wrapped `.Future` fails after it has timed out, the exception - will be logged unless it is either of a type contained in - ``quiet_exceptions`` (which may be an exception type or a sequence of - types), or an ``asyncio.CancelledError``. - - The wrapped `.Future` is not canceled when the timeout expires, - permitting it to be reused. `asyncio.wait_for` is similar to this - function but it does cancel the wrapped `.Future` on timeout. - - .. versionadded:: 4.0 - - .. versionchanged:: 4.1 - Added the ``quiet_exceptions`` argument and the logging of unhandled - exceptions. - - .. versionchanged:: 4.4 - Added support for yieldable objects other than `.Future`. - - .. versionchanged:: 6.0.3 - ``asyncio.CancelledError`` is now always considered "quiet". - - """ - # It's tempting to optimize this by cancelling the input future on timeout - # instead of creating a new one, but A) we can't know if we are the only - # one waiting on the input future, so cancelling it might disrupt other - # callers and B) concurrent futures can only be cancelled while they are - # in the queue, so cancellation cannot reliably bound our waiting time. - future_converted = convert_yielded(future) - result = _create_future() - chain_future(future_converted, result) - io_loop = IOLoop.current() - - def error_callback(future: Future) -> None: - try: - future.result() - except asyncio.CancelledError: - pass - except Exception as e: - if not isinstance(e, quiet_exceptions): - app_log.error( - "Exception in Future %r after timeout", future, exc_info=True - ) - - def timeout_callback() -> None: - if not result.done(): - result.set_exception(TimeoutError("Timeout")) - # In case the wrapped future goes on to fail, log it. - future_add_done_callback(future_converted, error_callback) - - timeout_handle = io_loop.add_timeout(timeout, timeout_callback) - if isinstance(future_converted, Future): - # We know this future will resolve on the IOLoop, so we don't - # need the extra thread-safety of IOLoop.add_future (and we also - # don't care about StackContext here. - future_add_done_callback( - future_converted, lambda future: io_loop.remove_timeout(timeout_handle) - ) - else: - # concurrent.futures.Futures may resolve on any thread, so we - # need to route them back to the IOLoop. - io_loop.add_future( - future_converted, lambda future: io_loop.remove_timeout(timeout_handle) - ) - return result - - -def sleep(duration: float) -> "Future[None]": - """Return a `.Future` that resolves after the given number of seconds. - - When used with ``yield`` in a coroutine, this is a non-blocking - analogue to `time.sleep` (which should not be used in coroutines - because it is blocking):: - - yield gen.sleep(0.5) - - Note that calling this function on its own does nothing; you must - wait on the `.Future` it returns (usually by yielding it). - - .. versionadded:: 4.1 - """ - f = _create_future() - IOLoop.current().call_later( - duration, lambda: future_set_result_unless_cancelled(f, None) - ) - return f - - -class _NullFuture(object): - """_NullFuture resembles a Future that finished with a result of None. - - It's not actually a `Future` to avoid depending on a particular event loop. - Handled as a special case in the coroutine runner. - - We lie and tell the type checker that a _NullFuture is a Future so - we don't have to leak _NullFuture into lots of public APIs. But - this means that the type checker can't warn us when we're passing - a _NullFuture into a code path that doesn't understand what to do - with it. - """ - - def result(self) -> None: - return None - - def done(self) -> bool: - return True - - -# _null_future is used as a dummy value in the coroutine runner. It differs -# from moment in that moment always adds a delay of one IOLoop iteration -# while _null_future is processed as soon as possible. -_null_future = typing.cast(Future, _NullFuture()) - -moment = typing.cast(Future, _NullFuture()) -moment.__doc__ = """A special object which may be yielded to allow the IOLoop to run for -one iteration. - -This is not needed in normal use but it can be helpful in long-running -coroutines that are likely to yield Futures that are ready instantly. - -Usage: ``yield gen.moment`` - -In native coroutines, the equivalent of ``yield gen.moment`` is -``await asyncio.sleep(0)``. - -.. versionadded:: 4.0 - -.. deprecated:: 4.5 - ``yield None`` (or ``yield`` with no argument) is now equivalent to - ``yield gen.moment``. -""" - - -class Runner(object): - """Internal implementation of `tornado.gen.coroutine`. - - Maintains information about pending callbacks and their results. - - The results of the generator are stored in ``result_future`` (a - `.Future`) - """ - - def __init__( - self, - ctx_run: Callable, - gen: "Generator[_Yieldable, Any, _T]", - result_future: "Future[_T]", - first_yielded: _Yieldable, - ) -> None: - self.ctx_run = ctx_run - self.gen = gen - self.result_future = result_future - self.future = _null_future # type: Union[None, Future] - self.running = False - self.finished = False - self.io_loop = IOLoop.current() - if self.handle_yield(first_yielded): - gen = result_future = first_yielded = None # type: ignore - self.ctx_run(self.run) - - def run(self) -> None: - """Starts or resumes the generator, running until it reaches a - yield point that is not ready. - """ - if self.running or self.finished: - return - try: - self.running = True - while True: - future = self.future - if future is None: - raise Exception("No pending future") - if not future.done(): - return - self.future = None - try: - exc_info = None - - try: - value = future.result() - except Exception: - exc_info = sys.exc_info() - future = None - - if exc_info is not None: - try: - yielded = self.gen.throw(*exc_info) # type: ignore - finally: - # Break up a reference to itself - # for faster GC on CPython. - exc_info = None - else: - yielded = self.gen.send(value) - - except (StopIteration, Return) as e: - self.finished = True - self.future = _null_future - future_set_result_unless_cancelled( - self.result_future, _value_from_stopiteration(e) - ) - self.result_future = None # type: ignore - return - except Exception: - self.finished = True - self.future = _null_future - future_set_exc_info(self.result_future, sys.exc_info()) - self.result_future = None # type: ignore - return - if not self.handle_yield(yielded): - return - yielded = None - finally: - self.running = False - - def handle_yield(self, yielded: _Yieldable) -> bool: - try: - self.future = convert_yielded(yielded) - except BadYieldError: - self.future = Future() - future_set_exc_info(self.future, sys.exc_info()) - - if self.future is moment: - self.io_loop.add_callback(self.ctx_run, self.run) - return False - elif self.future is None: - raise Exception("no pending future") - elif not self.future.done(): - - def inner(f: Any) -> None: - # Break a reference cycle to speed GC. - f = None # noqa: F841 - self.ctx_run(self.run) - - self.io_loop.add_future(self.future, inner) - return False - return True - - def handle_exception( - self, typ: Type[Exception], value: Exception, tb: types.TracebackType - ) -> bool: - if not self.running and not self.finished: - self.future = Future() - future_set_exc_info(self.future, (typ, value, tb)) - self.ctx_run(self.run) - return True - else: - return False - - -# Convert Awaitables into Futures. -try: - _wrap_awaitable = asyncio.ensure_future -except AttributeError: - # asyncio.ensure_future was introduced in Python 3.4.4, but - # Debian jessie still ships with 3.4.2 so try the old name. - _wrap_awaitable = getattr(asyncio, "async") - - -def convert_yielded(yielded: _Yieldable) -> Future: - """Convert a yielded object into a `.Future`. - - The default implementation accepts lists, dictionaries, and - Futures. This has the side effect of starting any coroutines that - did not start themselves, similar to `asyncio.ensure_future`. - - If the `~functools.singledispatch` library is available, this function - may be extended to support additional types. For example:: - - @convert_yielded.register(asyncio.Future) - def _(asyncio_future): - return tornado.platform.asyncio.to_tornado_future(asyncio_future) - - .. versionadded:: 4.1 - - """ - if yielded is None or yielded is moment: - return moment - elif yielded is _null_future: - return _null_future - elif isinstance(yielded, (list, dict)): - return multi(yielded) # type: ignore - elif is_future(yielded): - return typing.cast(Future, yielded) - elif isawaitable(yielded): - return _wrap_awaitable(yielded) # type: ignore - else: - raise BadYieldError("yielded unknown object %r" % (yielded,)) - - -convert_yielded = singledispatch(convert_yielded) diff --git a/venv/lib/python3.8/site-packages/tornado/http1connection.py b/venv/lib/python3.8/site-packages/tornado/http1connection.py deleted file mode 100644 index 835027b..0000000 --- a/venv/lib/python3.8/site-packages/tornado/http1connection.py +++ /dev/null @@ -1,842 +0,0 @@ -# -# Copyright 2014 Facebook -# -# 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. - -"""Client and server implementations of HTTP/1.x. - -.. versionadded:: 4.0 -""" - -import asyncio -import logging -import re -import types - -from tornado.concurrent import ( - Future, - future_add_done_callback, - future_set_result_unless_cancelled, -) -from tornado.escape import native_str, utf8 -from tornado import gen -from tornado import httputil -from tornado import iostream -from tornado.log import gen_log, app_log -from tornado.util import GzipDecompressor - - -from typing import cast, Optional, Type, Awaitable, Callable, Union, Tuple - - -class _QuietException(Exception): - def __init__(self) -> None: - pass - - -class _ExceptionLoggingContext(object): - """Used with the ``with`` statement when calling delegate methods to - log any exceptions with the given logger. Any exceptions caught are - converted to _QuietException - """ - - def __init__(self, logger: logging.Logger) -> None: - self.logger = logger - - def __enter__(self) -> None: - pass - - def __exit__( - self, - typ: "Optional[Type[BaseException]]", - value: Optional[BaseException], - tb: types.TracebackType, - ) -> None: - if value is not None: - assert typ is not None - self.logger.error("Uncaught exception", exc_info=(typ, value, tb)) - raise _QuietException - - -class HTTP1ConnectionParameters(object): - """Parameters for `.HTTP1Connection` and `.HTTP1ServerConnection`. - """ - - def __init__( - self, - no_keep_alive: bool = False, - chunk_size: Optional[int] = None, - max_header_size: Optional[int] = None, - header_timeout: Optional[float] = None, - max_body_size: Optional[int] = None, - body_timeout: Optional[float] = None, - decompress: bool = False, - ) -> None: - """ - :arg bool no_keep_alive: If true, always close the connection after - one request. - :arg int chunk_size: how much data to read into memory at once - :arg int max_header_size: maximum amount of data for HTTP headers - :arg float header_timeout: how long to wait for all headers (seconds) - :arg int max_body_size: maximum amount of data for body - :arg float body_timeout: how long to wait while reading body (seconds) - :arg bool decompress: if true, decode incoming - ``Content-Encoding: gzip`` - """ - self.no_keep_alive = no_keep_alive - self.chunk_size = chunk_size or 65536 - self.max_header_size = max_header_size or 65536 - self.header_timeout = header_timeout - self.max_body_size = max_body_size - self.body_timeout = body_timeout - self.decompress = decompress - - -class HTTP1Connection(httputil.HTTPConnection): - """Implements the HTTP/1.x protocol. - - This class can be on its own for clients, or via `HTTP1ServerConnection` - for servers. - """ - - def __init__( - self, - stream: iostream.IOStream, - is_client: bool, - params: Optional[HTTP1ConnectionParameters] = None, - context: Optional[object] = None, - ) -> None: - """ - :arg stream: an `.IOStream` - :arg bool is_client: client or server - :arg params: a `.HTTP1ConnectionParameters` instance or ``None`` - :arg context: an opaque application-defined object that can be accessed - as ``connection.context``. - """ - self.is_client = is_client - self.stream = stream - if params is None: - params = HTTP1ConnectionParameters() - self.params = params - self.context = context - self.no_keep_alive = params.no_keep_alive - # The body limits can be altered by the delegate, so save them - # here instead of just referencing self.params later. - self._max_body_size = self.params.max_body_size or self.stream.max_buffer_size - self._body_timeout = self.params.body_timeout - # _write_finished is set to True when finish() has been called, - # i.e. there will be no more data sent. Data may still be in the - # stream's write buffer. - self._write_finished = False - # True when we have read the entire incoming body. - self._read_finished = False - # _finish_future resolves when all data has been written and flushed - # to the IOStream. - self._finish_future = Future() # type: Future[None] - # If true, the connection should be closed after this request - # (after the response has been written in the server side, - # and after it has been read in the client) - self._disconnect_on_finish = False - self._clear_callbacks() - # Save the start lines after we read or write them; they - # affect later processing (e.g. 304 responses and HEAD methods - # have content-length but no bodies) - self._request_start_line = None # type: Optional[httputil.RequestStartLine] - self._response_start_line = None # type: Optional[httputil.ResponseStartLine] - self._request_headers = None # type: Optional[httputil.HTTPHeaders] - # True if we are writing output with chunked encoding. - self._chunking_output = False - # While reading a body with a content-length, this is the - # amount left to read. - self._expected_content_remaining = None # type: Optional[int] - # A Future for our outgoing writes, returned by IOStream.write. - self._pending_write = None # type: Optional[Future[None]] - - def read_response(self, delegate: httputil.HTTPMessageDelegate) -> Awaitable[bool]: - """Read a single HTTP response. - - Typical client-mode usage is to write a request using `write_headers`, - `write`, and `finish`, and then call ``read_response``. - - :arg delegate: a `.HTTPMessageDelegate` - - Returns a `.Future` that resolves to a bool after the full response has - been read. The result is true if the stream is still open. - """ - if self.params.decompress: - delegate = _GzipMessageDelegate(delegate, self.params.chunk_size) - return self._read_message(delegate) - - async def _read_message(self, delegate: httputil.HTTPMessageDelegate) -> bool: - need_delegate_close = False - try: - header_future = self.stream.read_until_regex( - b"\r?\n\r?\n", max_bytes=self.params.max_header_size - ) - if self.params.header_timeout is None: - header_data = await header_future - else: - try: - header_data = await gen.with_timeout( - self.stream.io_loop.time() + self.params.header_timeout, - header_future, - quiet_exceptions=iostream.StreamClosedError, - ) - except gen.TimeoutError: - self.close() - return False - start_line_str, headers = self._parse_headers(header_data) - if self.is_client: - resp_start_line = httputil.parse_response_start_line(start_line_str) - self._response_start_line = resp_start_line - start_line = ( - resp_start_line - ) # type: Union[httputil.RequestStartLine, httputil.ResponseStartLine] - # TODO: this will need to change to support client-side keepalive - self._disconnect_on_finish = False - else: - req_start_line = httputil.parse_request_start_line(start_line_str) - self._request_start_line = req_start_line - self._request_headers = headers - start_line = req_start_line - self._disconnect_on_finish = not self._can_keep_alive( - req_start_line, headers - ) - need_delegate_close = True - with _ExceptionLoggingContext(app_log): - header_recv_future = delegate.headers_received(start_line, headers) - if header_recv_future is not None: - await header_recv_future - if self.stream is None: - # We've been detached. - need_delegate_close = False - return False - skip_body = False - if self.is_client: - assert isinstance(start_line, httputil.ResponseStartLine) - if ( - self._request_start_line is not None - and self._request_start_line.method == "HEAD" - ): - skip_body = True - code = start_line.code - if code == 304: - # 304 responses may include the content-length header - # but do not actually have a body. - # http://tools.ietf.org/html/rfc7230#section-3.3 - skip_body = True - if 100 <= code < 200: - # 1xx responses should never indicate the presence of - # a body. - if "Content-Length" in headers or "Transfer-Encoding" in headers: - raise httputil.HTTPInputError( - "Response code %d cannot have body" % code - ) - # TODO: client delegates will get headers_received twice - # in the case of a 100-continue. Document or change? - await self._read_message(delegate) - else: - if headers.get("Expect") == "100-continue" and not self._write_finished: - self.stream.write(b"HTTP/1.1 100 (Continue)\r\n\r\n") - if not skip_body: - body_future = self._read_body( - resp_start_line.code if self.is_client else 0, headers, delegate - ) - if body_future is not None: - if self._body_timeout is None: - await body_future - else: - try: - await gen.with_timeout( - self.stream.io_loop.time() + self._body_timeout, - body_future, - quiet_exceptions=iostream.StreamClosedError, - ) - except gen.TimeoutError: - gen_log.info("Timeout reading body from %s", self.context) - self.stream.close() - return False - self._read_finished = True - if not self._write_finished or self.is_client: - need_delegate_close = False - with _ExceptionLoggingContext(app_log): - delegate.finish() - # If we're waiting for the application to produce an asynchronous - # response, and we're not detached, register a close callback - # on the stream (we didn't need one while we were reading) - if ( - not self._finish_future.done() - and self.stream is not None - and not self.stream.closed() - ): - self.stream.set_close_callback(self._on_connection_close) - await self._finish_future - if self.is_client and self._disconnect_on_finish: - self.close() - if self.stream is None: - return False - except httputil.HTTPInputError as e: - gen_log.info("Malformed HTTP message from %s: %s", self.context, e) - if not self.is_client: - await self.stream.write(b"HTTP/1.1 400 Bad Request\r\n\r\n") - self.close() - return False - finally: - if need_delegate_close: - with _ExceptionLoggingContext(app_log): - delegate.on_connection_close() - header_future = None # type: ignore - self._clear_callbacks() - return True - - def _clear_callbacks(self) -> None: - """Clears the callback attributes. - - This allows the request handler to be garbage collected more - quickly in CPython by breaking up reference cycles. - """ - self._write_callback = None - self._write_future = None # type: Optional[Future[None]] - self._close_callback = None # type: Optional[Callable[[], None]] - if self.stream is not None: - self.stream.set_close_callback(None) - - def set_close_callback(self, callback: Optional[Callable[[], None]]) -> None: - """Sets a callback that will be run when the connection is closed. - - Note that this callback is slightly different from - `.HTTPMessageDelegate.on_connection_close`: The - `.HTTPMessageDelegate` method is called when the connection is - closed while receiving a message. This callback is used when - there is not an active delegate (for example, on the server - side this callback is used if the client closes the connection - after sending its request but before receiving all the - response. - """ - self._close_callback = callback - - def _on_connection_close(self) -> None: - # Note that this callback is only registered on the IOStream - # when we have finished reading the request and are waiting for - # the application to produce its response. - if self._close_callback is not None: - callback = self._close_callback - self._close_callback = None - callback() - if not self._finish_future.done(): - future_set_result_unless_cancelled(self._finish_future, None) - self._clear_callbacks() - - def close(self) -> None: - if self.stream is not None: - self.stream.close() - self._clear_callbacks() - if not self._finish_future.done(): - future_set_result_unless_cancelled(self._finish_future, None) - - def detach(self) -> iostream.IOStream: - """Take control of the underlying stream. - - Returns the underlying `.IOStream` object and stops all further - HTTP processing. May only be called during - `.HTTPMessageDelegate.headers_received`. Intended for implementing - protocols like websockets that tunnel over an HTTP handshake. - """ - self._clear_callbacks() - stream = self.stream - self.stream = None # type: ignore - if not self._finish_future.done(): - future_set_result_unless_cancelled(self._finish_future, None) - return stream - - def set_body_timeout(self, timeout: float) -> None: - """Sets the body timeout for a single request. - - Overrides the value from `.HTTP1ConnectionParameters`. - """ - self._body_timeout = timeout - - def set_max_body_size(self, max_body_size: int) -> None: - """Sets the body size limit for a single request. - - Overrides the value from `.HTTP1ConnectionParameters`. - """ - self._max_body_size = max_body_size - - def write_headers( - self, - start_line: Union[httputil.RequestStartLine, httputil.ResponseStartLine], - headers: httputil.HTTPHeaders, - chunk: Optional[bytes] = None, - ) -> "Future[None]": - """Implements `.HTTPConnection.write_headers`.""" - lines = [] - if self.is_client: - assert isinstance(start_line, httputil.RequestStartLine) - self._request_start_line = start_line - lines.append(utf8("%s %s HTTP/1.1" % (start_line[0], start_line[1]))) - # Client requests with a non-empty body must have either a - # Content-Length or a Transfer-Encoding. - self._chunking_output = ( - start_line.method in ("POST", "PUT", "PATCH") - and "Content-Length" not in headers - and ( - "Transfer-Encoding" not in headers - or headers["Transfer-Encoding"] == "chunked" - ) - ) - else: - assert isinstance(start_line, httputil.ResponseStartLine) - assert self._request_start_line is not None - assert self._request_headers is not None - self._response_start_line = start_line - lines.append(utf8("HTTP/1.1 %d %s" % (start_line[1], start_line[2]))) - self._chunking_output = ( - # TODO: should this use - # self._request_start_line.version or - # start_line.version? - self._request_start_line.version == "HTTP/1.1" - # Omit payload header field for HEAD request. - and self._request_start_line.method != "HEAD" - # 1xx, 204 and 304 responses have no body (not even a zero-length - # body), and so should not have either Content-Length or - # Transfer-Encoding headers. - and start_line.code not in (204, 304) - and (start_line.code < 100 or start_line.code >= 200) - # No need to chunk the output if a Content-Length is specified. - and "Content-Length" not in headers - # Applications are discouraged from touching Transfer-Encoding, - # but if they do, leave it alone. - and "Transfer-Encoding" not in headers - ) - # If connection to a 1.1 client will be closed, inform client - if ( - self._request_start_line.version == "HTTP/1.1" - and self._disconnect_on_finish - ): - headers["Connection"] = "close" - # If a 1.0 client asked for keep-alive, add the header. - if ( - self._request_start_line.version == "HTTP/1.0" - and self._request_headers.get("Connection", "").lower() == "keep-alive" - ): - headers["Connection"] = "Keep-Alive" - if self._chunking_output: - headers["Transfer-Encoding"] = "chunked" - if not self.is_client and ( - self._request_start_line.method == "HEAD" - or cast(httputil.ResponseStartLine, start_line).code == 304 - ): - self._expected_content_remaining = 0 - elif "Content-Length" in headers: - self._expected_content_remaining = int(headers["Content-Length"]) - else: - self._expected_content_remaining = None - # TODO: headers are supposed to be of type str, but we still have some - # cases that let bytes slip through. Remove these native_str calls when those - # are fixed. - header_lines = ( - native_str(n) + ": " + native_str(v) for n, v in headers.get_all() - ) - lines.extend(line.encode("latin1") for line in header_lines) - for line in lines: - if b"\n" in line: - raise ValueError("Newline in header: " + repr(line)) - future = None - if self.stream.closed(): - future = self._write_future = Future() - future.set_exception(iostream.StreamClosedError()) - future.exception() - else: - future = self._write_future = Future() - data = b"\r\n".join(lines) + b"\r\n\r\n" - if chunk: - data += self._format_chunk(chunk) - self._pending_write = self.stream.write(data) - future_add_done_callback(self._pending_write, self._on_write_complete) - return future - - def _format_chunk(self, chunk: bytes) -> bytes: - if self._expected_content_remaining is not None: - self._expected_content_remaining -= len(chunk) - if self._expected_content_remaining < 0: - # Close the stream now to stop further framing errors. - self.stream.close() - raise httputil.HTTPOutputError( - "Tried to write more data than Content-Length" - ) - if self._chunking_output and chunk: - # Don't write out empty chunks because that means END-OF-STREAM - # with chunked encoding - return utf8("%x" % len(chunk)) + b"\r\n" + chunk + b"\r\n" - else: - return chunk - - def write(self, chunk: bytes) -> "Future[None]": - """Implements `.HTTPConnection.write`. - - For backwards compatibility it is allowed but deprecated to - skip `write_headers` and instead call `write()` with a - pre-encoded header block. - """ - future = None - if self.stream.closed(): - future = self._write_future = Future() - self._write_future.set_exception(iostream.StreamClosedError()) - self._write_future.exception() - else: - future = self._write_future = Future() - self._pending_write = self.stream.write(self._format_chunk(chunk)) - future_add_done_callback(self._pending_write, self._on_write_complete) - return future - - def finish(self) -> None: - """Implements `.HTTPConnection.finish`.""" - if ( - self._expected_content_remaining is not None - and self._expected_content_remaining != 0 - and not self.stream.closed() - ): - self.stream.close() - raise httputil.HTTPOutputError( - "Tried to write %d bytes less than Content-Length" - % self._expected_content_remaining - ) - if self._chunking_output: - if not self.stream.closed(): - self._pending_write = self.stream.write(b"0\r\n\r\n") - self._pending_write.add_done_callback(self._on_write_complete) - self._write_finished = True - # If the app finished the request while we're still reading, - # divert any remaining data away from the delegate and - # close the connection when we're done sending our response. - # Closing the connection is the only way to avoid reading the - # whole input body. - if not self._read_finished: - self._disconnect_on_finish = True - # No more data is coming, so instruct TCP to send any remaining - # data immediately instead of waiting for a full packet or ack. - self.stream.set_nodelay(True) - if self._pending_write is None: - self._finish_request(None) - else: - future_add_done_callback(self._pending_write, self._finish_request) - - def _on_write_complete(self, future: "Future[None]") -> None: - exc = future.exception() - if exc is not None and not isinstance(exc, iostream.StreamClosedError): - future.result() - if self._write_callback is not None: - callback = self._write_callback - self._write_callback = None - self.stream.io_loop.add_callback(callback) - if self._write_future is not None: - future = self._write_future - self._write_future = None - future_set_result_unless_cancelled(future, None) - - def _can_keep_alive( - self, start_line: httputil.RequestStartLine, headers: httputil.HTTPHeaders - ) -> bool: - if self.params.no_keep_alive: - return False - connection_header = headers.get("Connection") - if connection_header is not None: - connection_header = connection_header.lower() - if start_line.version == "HTTP/1.1": - return connection_header != "close" - elif ( - "Content-Length" in headers - or headers.get("Transfer-Encoding", "").lower() == "chunked" - or getattr(start_line, "method", None) in ("HEAD", "GET") - ): - # start_line may be a request or response start line; only - # the former has a method attribute. - return connection_header == "keep-alive" - return False - - def _finish_request(self, future: "Optional[Future[None]]") -> None: - self._clear_callbacks() - if not self.is_client and self._disconnect_on_finish: - self.close() - return - # Turn Nagle's algorithm back on, leaving the stream in its - # default state for the next request. - self.stream.set_nodelay(False) - if not self._finish_future.done(): - future_set_result_unless_cancelled(self._finish_future, None) - - def _parse_headers(self, data: bytes) -> Tuple[str, httputil.HTTPHeaders]: - # The lstrip removes newlines that some implementations sometimes - # insert between messages of a reused connection. Per RFC 7230, - # we SHOULD ignore at least one empty line before the request. - # http://tools.ietf.org/html/rfc7230#section-3.5 - data_str = native_str(data.decode("latin1")).lstrip("\r\n") - # RFC 7230 section allows for both CRLF and bare LF. - eol = data_str.find("\n") - start_line = data_str[:eol].rstrip("\r") - headers = httputil.HTTPHeaders.parse(data_str[eol:]) - return start_line, headers - - def _read_body( - self, - code: int, - headers: httputil.HTTPHeaders, - delegate: httputil.HTTPMessageDelegate, - ) -> Optional[Awaitable[None]]: - if "Content-Length" in headers: - if "Transfer-Encoding" in headers: - # Response cannot contain both Content-Length and - # Transfer-Encoding headers. - # http://tools.ietf.org/html/rfc7230#section-3.3.3 - raise httputil.HTTPInputError( - "Response with both Transfer-Encoding and Content-Length" - ) - if "," in headers["Content-Length"]: - # Proxies sometimes cause Content-Length headers to get - # duplicated. If all the values are identical then we can - # use them but if they differ it's an error. - pieces = re.split(r",\s*", headers["Content-Length"]) - if any(i != pieces[0] for i in pieces): - raise httputil.HTTPInputError( - "Multiple unequal Content-Lengths: %r" - % headers["Content-Length"] - ) - headers["Content-Length"] = pieces[0] - - try: - content_length = int(headers["Content-Length"]) # type: Optional[int] - except ValueError: - # Handles non-integer Content-Length value. - raise httputil.HTTPInputError( - "Only integer Content-Length is allowed: %s" - % headers["Content-Length"] - ) - - if cast(int, content_length) > self._max_body_size: - raise httputil.HTTPInputError("Content-Length too long") - else: - content_length = None - - if code == 204: - # This response code is not allowed to have a non-empty body, - # and has an implicit length of zero instead of read-until-close. - # http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.3 - if "Transfer-Encoding" in headers or content_length not in (None, 0): - raise httputil.HTTPInputError( - "Response with code %d should not have body" % code - ) - content_length = 0 - - if content_length is not None: - return self._read_fixed_body(content_length, delegate) - if headers.get("Transfer-Encoding", "").lower() == "chunked": - return self._read_chunked_body(delegate) - if self.is_client: - return self._read_body_until_close(delegate) - return None - - async def _read_fixed_body( - self, content_length: int, delegate: httputil.HTTPMessageDelegate - ) -> None: - while content_length > 0: - body = await self.stream.read_bytes( - min(self.params.chunk_size, content_length), partial=True - ) - content_length -= len(body) - if not self._write_finished or self.is_client: - with _ExceptionLoggingContext(app_log): - ret = delegate.data_received(body) - if ret is not None: - await ret - - async def _read_chunked_body(self, delegate: httputil.HTTPMessageDelegate) -> None: - # TODO: "chunk extensions" http://tools.ietf.org/html/rfc2616#section-3.6.1 - total_size = 0 - while True: - chunk_len_str = await self.stream.read_until(b"\r\n", max_bytes=64) - chunk_len = int(chunk_len_str.strip(), 16) - if chunk_len == 0: - crlf = await self.stream.read_bytes(2) - if crlf != b"\r\n": - raise httputil.HTTPInputError( - "improperly terminated chunked request" - ) - return - total_size += chunk_len - if total_size > self._max_body_size: - raise httputil.HTTPInputError("chunked body too large") - bytes_to_read = chunk_len - while bytes_to_read: - chunk = await self.stream.read_bytes( - min(bytes_to_read, self.params.chunk_size), partial=True - ) - bytes_to_read -= len(chunk) - if not self._write_finished or self.is_client: - with _ExceptionLoggingContext(app_log): - ret = delegate.data_received(chunk) - if ret is not None: - await ret - # chunk ends with \r\n - crlf = await self.stream.read_bytes(2) - assert crlf == b"\r\n" - - async def _read_body_until_close( - self, delegate: httputil.HTTPMessageDelegate - ) -> None: - body = await self.stream.read_until_close() - if not self._write_finished or self.is_client: - with _ExceptionLoggingContext(app_log): - ret = delegate.data_received(body) - if ret is not None: - await ret - - -class _GzipMessageDelegate(httputil.HTTPMessageDelegate): - """Wraps an `HTTPMessageDelegate` to decode ``Content-Encoding: gzip``. - """ - - def __init__(self, delegate: httputil.HTTPMessageDelegate, chunk_size: int) -> None: - self._delegate = delegate - self._chunk_size = chunk_size - self._decompressor = None # type: Optional[GzipDecompressor] - - def headers_received( - self, - start_line: Union[httputil.RequestStartLine, httputil.ResponseStartLine], - headers: httputil.HTTPHeaders, - ) -> Optional[Awaitable[None]]: - if headers.get("Content-Encoding") == "gzip": - self._decompressor = GzipDecompressor() - # Downstream delegates will only see uncompressed data, - # so rename the content-encoding header. - # (but note that curl_httpclient doesn't do this). - headers.add("X-Consumed-Content-Encoding", headers["Content-Encoding"]) - del headers["Content-Encoding"] - return self._delegate.headers_received(start_line, headers) - - async def data_received(self, chunk: bytes) -> None: - if self._decompressor: - compressed_data = chunk - while compressed_data: - decompressed = self._decompressor.decompress( - compressed_data, self._chunk_size - ) - if decompressed: - ret = self._delegate.data_received(decompressed) - if ret is not None: - await ret - compressed_data = self._decompressor.unconsumed_tail - if compressed_data and not decompressed: - raise httputil.HTTPInputError( - "encountered unconsumed gzip data without making progress" - ) - else: - ret = self._delegate.data_received(chunk) - if ret is not None: - await ret - - def finish(self) -> None: - if self._decompressor is not None: - tail = self._decompressor.flush() - if tail: - # The tail should always be empty: decompress returned - # all that it can in data_received and the only - # purpose of the flush call is to detect errors such - # as truncated input. If we did legitimately get a new - # chunk at this point we'd need to change the - # interface to make finish() a coroutine. - raise ValueError( - "decompressor.flush returned data; possible truncated input" - ) - return self._delegate.finish() - - def on_connection_close(self) -> None: - return self._delegate.on_connection_close() - - -class HTTP1ServerConnection(object): - """An HTTP/1.x server.""" - - def __init__( - self, - stream: iostream.IOStream, - params: Optional[HTTP1ConnectionParameters] = None, - context: Optional[object] = None, - ) -> None: - """ - :arg stream: an `.IOStream` - :arg params: a `.HTTP1ConnectionParameters` or None - :arg context: an opaque application-defined object that is accessible - as ``connection.context`` - """ - self.stream = stream - if params is None: - params = HTTP1ConnectionParameters() - self.params = params - self.context = context - self._serving_future = None # type: Optional[Future[None]] - - async def close(self) -> None: - """Closes the connection. - - Returns a `.Future` that resolves after the serving loop has exited. - """ - self.stream.close() - # Block until the serving loop is done, but ignore any exceptions - # (start_serving is already responsible for logging them). - assert self._serving_future is not None - try: - await self._serving_future - except Exception: - pass - - def start_serving(self, delegate: httputil.HTTPServerConnectionDelegate) -> None: - """Starts serving requests on this connection. - - :arg delegate: a `.HTTPServerConnectionDelegate` - """ - assert isinstance(delegate, httputil.HTTPServerConnectionDelegate) - fut = gen.convert_yielded(self._server_request_loop(delegate)) - self._serving_future = fut - # Register the future on the IOLoop so its errors get logged. - self.stream.io_loop.add_future(fut, lambda f: f.result()) - - async def _server_request_loop( - self, delegate: httputil.HTTPServerConnectionDelegate - ) -> None: - try: - while True: - conn = HTTP1Connection(self.stream, False, self.params, self.context) - request_delegate = delegate.start_request(self, conn) - try: - ret = await conn.read_response(request_delegate) - except ( - iostream.StreamClosedError, - iostream.UnsatisfiableReadError, - asyncio.CancelledError, - ): - return - except _QuietException: - # This exception was already logged. - conn.close() - return - except Exception: - gen_log.error("Uncaught exception", exc_info=True) - conn.close() - return - if not ret: - return - await asyncio.sleep(0) - finally: - delegate.on_close(self) diff --git a/venv/lib/python3.8/site-packages/tornado/httpclient.py b/venv/lib/python3.8/site-packages/tornado/httpclient.py deleted file mode 100644 index 3011c37..0000000 --- a/venv/lib/python3.8/site-packages/tornado/httpclient.py +++ /dev/null @@ -1,790 +0,0 @@ -"""Blocking and non-blocking HTTP client interfaces. - -This module defines a common interface shared by two implementations, -``simple_httpclient`` and ``curl_httpclient``. Applications may either -instantiate their chosen implementation class directly or use the -`AsyncHTTPClient` class from this module, which selects an implementation -that can be overridden with the `AsyncHTTPClient.configure` method. - -The default implementation is ``simple_httpclient``, and this is expected -to be suitable for most users' needs. However, some applications may wish -to switch to ``curl_httpclient`` for reasons such as the following: - -* ``curl_httpclient`` has some features not found in ``simple_httpclient``, - including support for HTTP proxies and the ability to use a specified - network interface. - -* ``curl_httpclient`` is more likely to be compatible with sites that are - not-quite-compliant with the HTTP spec, or sites that use little-exercised - features of HTTP. - -* ``curl_httpclient`` is faster. - -Note that if you are using ``curl_httpclient``, it is highly -recommended that you use a recent version of ``libcurl`` and -``pycurl``. Currently the minimum supported version of libcurl is -7.22.0, and the minimum version of pycurl is 7.18.2. It is highly -recommended that your ``libcurl`` installation is built with -asynchronous DNS resolver (threaded or c-ares), otherwise you may -encounter various problems with request timeouts (for more -information, see -http://curl.haxx.se/libcurl/c/curl_easy_setopt.html#CURLOPTCONNECTTIMEOUTMS -and comments in curl_httpclient.py). - -To select ``curl_httpclient``, call `AsyncHTTPClient.configure` at startup:: - - AsyncHTTPClient.configure("tornado.curl_httpclient.CurlAsyncHTTPClient") -""" - -import datetime -import functools -from io import BytesIO -import ssl -import time -import weakref - -from tornado.concurrent import ( - Future, - future_set_result_unless_cancelled, - future_set_exception_unless_cancelled, -) -from tornado.escape import utf8, native_str -from tornado import gen, httputil -from tornado.ioloop import IOLoop -from tornado.util import Configurable - -from typing import Type, Any, Union, Dict, Callable, Optional, cast - - -class HTTPClient(object): - """A blocking HTTP client. - - This interface is provided to make it easier to share code between - synchronous and asynchronous applications. Applications that are - running an `.IOLoop` must use `AsyncHTTPClient` instead. - - Typical usage looks like this:: - - http_client = httpclient.HTTPClient() - try: - response = http_client.fetch("http://www.google.com/") - print(response.body) - except httpclient.HTTPError as e: - # HTTPError is raised for non-200 responses; the response - # can be found in e.response. - print("Error: " + str(e)) - except Exception as e: - # Other errors are possible, such as IOError. - print("Error: " + str(e)) - http_client.close() - - .. versionchanged:: 5.0 - - Due to limitations in `asyncio`, it is no longer possible to - use the synchronous ``HTTPClient`` while an `.IOLoop` is running. - Use `AsyncHTTPClient` instead. - - """ - - def __init__( - self, - async_client_class: "Optional[Type[AsyncHTTPClient]]" = None, - **kwargs: Any - ) -> None: - # Initialize self._closed at the beginning of the constructor - # so that an exception raised here doesn't lead to confusing - # failures in __del__. - self._closed = True - self._io_loop = IOLoop(make_current=False) - if async_client_class is None: - async_client_class = AsyncHTTPClient - - # Create the client while our IOLoop is "current", without - # clobbering the thread's real current IOLoop (if any). - async def make_client() -> "AsyncHTTPClient": - await gen.sleep(0) - assert async_client_class is not None - return async_client_class(**kwargs) - - self._async_client = self._io_loop.run_sync(make_client) - self._closed = False - - def __del__(self) -> None: - self.close() - - def close(self) -> None: - """Closes the HTTPClient, freeing any resources used.""" - if not self._closed: - self._async_client.close() - self._io_loop.close() - self._closed = True - - def fetch( - self, request: Union["HTTPRequest", str], **kwargs: Any - ) -> "HTTPResponse": - """Executes a request, returning an `HTTPResponse`. - - The request may be either a string URL or an `HTTPRequest` object. - If it is a string, we construct an `HTTPRequest` using any additional - kwargs: ``HTTPRequest(request, **kwargs)`` - - If an error occurs during the fetch, we raise an `HTTPError` unless - the ``raise_error`` keyword argument is set to False. - """ - response = self._io_loop.run_sync( - functools.partial(self._async_client.fetch, request, **kwargs) - ) - return response - - -class AsyncHTTPClient(Configurable): - """An non-blocking HTTP client. - - Example usage:: - - async def f(): - http_client = AsyncHTTPClient() - try: - response = await http_client.fetch("http://www.google.com") - except Exception as e: - print("Error: %s" % e) - else: - print(response.body) - - The constructor for this class is magic in several respects: It - actually creates an instance of an implementation-specific - subclass, and instances are reused as a kind of pseudo-singleton - (one per `.IOLoop`). The keyword argument ``force_instance=True`` - can be used to suppress this singleton behavior. Unless - ``force_instance=True`` is used, no arguments should be passed to - the `AsyncHTTPClient` constructor. The implementation subclass as - well as arguments to its constructor can be set with the static - method `configure()` - - All `AsyncHTTPClient` implementations support a ``defaults`` - keyword argument, which can be used to set default values for - `HTTPRequest` attributes. For example:: - - AsyncHTTPClient.configure( - None, defaults=dict(user_agent="MyUserAgent")) - # or with force_instance: - client = AsyncHTTPClient(force_instance=True, - defaults=dict(user_agent="MyUserAgent")) - - .. versionchanged:: 5.0 - The ``io_loop`` argument (deprecated since version 4.1) has been removed. - - """ - - _instance_cache = None # type: Dict[IOLoop, AsyncHTTPClient] - - @classmethod - def configurable_base(cls) -> Type[Configurable]: - return AsyncHTTPClient - - @classmethod - def configurable_default(cls) -> Type[Configurable]: - from tornado.simple_httpclient import SimpleAsyncHTTPClient - - return SimpleAsyncHTTPClient - - @classmethod - def _async_clients(cls) -> Dict[IOLoop, "AsyncHTTPClient"]: - attr_name = "_async_client_dict_" + cls.__name__ - if not hasattr(cls, attr_name): - setattr(cls, attr_name, weakref.WeakKeyDictionary()) - return getattr(cls, attr_name) - - def __new__(cls, force_instance: bool = False, **kwargs: Any) -> "AsyncHTTPClient": - io_loop = IOLoop.current() - if force_instance: - instance_cache = None - else: - instance_cache = cls._async_clients() - if instance_cache is not None and io_loop in instance_cache: - return instance_cache[io_loop] - instance = super(AsyncHTTPClient, cls).__new__(cls, **kwargs) # type: ignore - # Make sure the instance knows which cache to remove itself from. - # It can't simply call _async_clients() because we may be in - # __new__(AsyncHTTPClient) but instance.__class__ may be - # SimpleAsyncHTTPClient. - instance._instance_cache = instance_cache - if instance_cache is not None: - instance_cache[instance.io_loop] = instance - return instance - - def initialize(self, defaults: Optional[Dict[str, Any]] = None) -> None: - self.io_loop = IOLoop.current() - self.defaults = dict(HTTPRequest._DEFAULTS) - if defaults is not None: - self.defaults.update(defaults) - self._closed = False - - def close(self) -> None: - """Destroys this HTTP client, freeing any file descriptors used. - - This method is **not needed in normal use** due to the way - that `AsyncHTTPClient` objects are transparently reused. - ``close()`` is generally only necessary when either the - `.IOLoop` is also being closed, or the ``force_instance=True`` - argument was used when creating the `AsyncHTTPClient`. - - No other methods may be called on the `AsyncHTTPClient` after - ``close()``. - - """ - if self._closed: - return - self._closed = True - if self._instance_cache is not None: - cached_val = self._instance_cache.pop(self.io_loop, None) - # If there's an object other than self in the instance - # cache for our IOLoop, something has gotten mixed up. A - # value of None appears to be possible when this is called - # from a destructor (HTTPClient.__del__) as the weakref - # gets cleared before the destructor runs. - if cached_val is not None and cached_val is not self: - raise RuntimeError("inconsistent AsyncHTTPClient cache") - - def fetch( - self, - request: Union[str, "HTTPRequest"], - raise_error: bool = True, - **kwargs: Any - ) -> "Future[HTTPResponse]": - """Executes a request, asynchronously returning an `HTTPResponse`. - - The request may be either a string URL or an `HTTPRequest` object. - If it is a string, we construct an `HTTPRequest` using any additional - kwargs: ``HTTPRequest(request, **kwargs)`` - - This method returns a `.Future` whose result is an - `HTTPResponse`. By default, the ``Future`` will raise an - `HTTPError` if the request returned a non-200 response code - (other errors may also be raised if the server could not be - contacted). Instead, if ``raise_error`` is set to False, the - response will always be returned regardless of the response - code. - - If a ``callback`` is given, it will be invoked with the `HTTPResponse`. - In the callback interface, `HTTPError` is not automatically raised. - Instead, you must check the response's ``error`` attribute or - call its `~HTTPResponse.rethrow` method. - - .. versionchanged:: 6.0 - - The ``callback`` argument was removed. Use the returned - `.Future` instead. - - The ``raise_error=False`` argument only affects the - `HTTPError` raised when a non-200 response code is used, - instead of suppressing all errors. - """ - if self._closed: - raise RuntimeError("fetch() called on closed AsyncHTTPClient") - if not isinstance(request, HTTPRequest): - request = HTTPRequest(url=request, **kwargs) - else: - if kwargs: - raise ValueError( - "kwargs can't be used if request is an HTTPRequest object" - ) - # We may modify this (to add Host, Accept-Encoding, etc), - # so make sure we don't modify the caller's object. This is also - # where normal dicts get converted to HTTPHeaders objects. - request.headers = httputil.HTTPHeaders(request.headers) - request_proxy = _RequestProxy(request, self.defaults) - future = Future() # type: Future[HTTPResponse] - - def handle_response(response: "HTTPResponse") -> None: - if response.error: - if raise_error or not response._error_is_response_code: - future_set_exception_unless_cancelled(future, response.error) - return - future_set_result_unless_cancelled(future, response) - - self.fetch_impl(cast(HTTPRequest, request_proxy), handle_response) - return future - - def fetch_impl( - self, request: "HTTPRequest", callback: Callable[["HTTPResponse"], None] - ) -> None: - raise NotImplementedError() - - @classmethod - def configure( - cls, impl: "Union[None, str, Type[Configurable]]", **kwargs: Any - ) -> None: - """Configures the `AsyncHTTPClient` subclass to use. - - ``AsyncHTTPClient()`` actually creates an instance of a subclass. - This method may be called with either a class object or the - fully-qualified name of such a class (or ``None`` to use the default, - ``SimpleAsyncHTTPClient``) - - If additional keyword arguments are given, they will be passed - to the constructor of each subclass instance created. The - keyword argument ``max_clients`` determines the maximum number - of simultaneous `~AsyncHTTPClient.fetch()` operations that can - execute in parallel on each `.IOLoop`. Additional arguments - may be supported depending on the implementation class in use. - - Example:: - - AsyncHTTPClient.configure("tornado.curl_httpclient.CurlAsyncHTTPClient") - """ - super(AsyncHTTPClient, cls).configure(impl, **kwargs) - - -class HTTPRequest(object): - """HTTP client request object.""" - - _headers = None # type: Union[Dict[str, str], httputil.HTTPHeaders] - - # Default values for HTTPRequest parameters. - # Merged with the values on the request object by AsyncHTTPClient - # implementations. - _DEFAULTS = dict( - connect_timeout=20.0, - request_timeout=20.0, - follow_redirects=True, - max_redirects=5, - decompress_response=True, - proxy_password="", - allow_nonstandard_methods=False, - validate_cert=True, - ) - - def __init__( - self, - url: str, - method: str = "GET", - headers: Optional[Union[Dict[str, str], httputil.HTTPHeaders]] = None, - body: Optional[Union[bytes, str]] = None, - auth_username: Optional[str] = None, - auth_password: Optional[str] = None, - auth_mode: Optional[str] = None, - connect_timeout: Optional[float] = None, - request_timeout: Optional[float] = None, - if_modified_since: Optional[Union[float, datetime.datetime]] = None, - follow_redirects: Optional[bool] = None, - max_redirects: Optional[int] = None, - user_agent: Optional[str] = None, - use_gzip: Optional[bool] = None, - network_interface: Optional[str] = None, - streaming_callback: Optional[Callable[[bytes], None]] = None, - header_callback: Optional[Callable[[str], None]] = None, - prepare_curl_callback: Optional[Callable[[Any], None]] = None, - proxy_host: Optional[str] = None, - proxy_port: Optional[int] = None, - proxy_username: Optional[str] = None, - proxy_password: Optional[str] = None, - proxy_auth_mode: Optional[str] = None, - allow_nonstandard_methods: Optional[bool] = None, - validate_cert: Optional[bool] = None, - ca_certs: Optional[str] = None, - allow_ipv6: Optional[bool] = None, - client_key: Optional[str] = None, - client_cert: Optional[str] = None, - body_producer: Optional[ - Callable[[Callable[[bytes], None]], "Future[None]"] - ] = None, - expect_100_continue: bool = False, - decompress_response: Optional[bool] = None, - ssl_options: Optional[Union[Dict[str, Any], ssl.SSLContext]] = None, - ) -> None: - r"""All parameters except ``url`` are optional. - - :arg str url: URL to fetch - :arg str method: HTTP method, e.g. "GET" or "POST" - :arg headers: Additional HTTP headers to pass on the request - :type headers: `~tornado.httputil.HTTPHeaders` or `dict` - :arg body: HTTP request body as a string (byte or unicode; if unicode - the utf-8 encoding will be used) - :type body: `str` or `bytes` - :arg collections.abc.Callable body_producer: Callable used for - lazy/asynchronous request bodies. - It is called with one argument, a ``write`` function, and should - return a `.Future`. It should call the write function with new - data as it becomes available. The write function returns a - `.Future` which can be used for flow control. - Only one of ``body`` and ``body_producer`` may - be specified. ``body_producer`` is not supported on - ``curl_httpclient``. When using ``body_producer`` it is recommended - to pass a ``Content-Length`` in the headers as otherwise chunked - encoding will be used, and many servers do not support chunked - encoding on requests. New in Tornado 4.0 - :arg str auth_username: Username for HTTP authentication - :arg str auth_password: Password for HTTP authentication - :arg str auth_mode: Authentication mode; default is "basic". - Allowed values are implementation-defined; ``curl_httpclient`` - supports "basic" and "digest"; ``simple_httpclient`` only supports - "basic" - :arg float connect_timeout: Timeout for initial connection in seconds, - default 20 seconds (0 means no timeout) - :arg float request_timeout: Timeout for entire request in seconds, - default 20 seconds (0 means no timeout) - :arg if_modified_since: Timestamp for ``If-Modified-Since`` header - :type if_modified_since: `datetime` or `float` - :arg bool follow_redirects: Should redirects be followed automatically - or return the 3xx response? Default True. - :arg int max_redirects: Limit for ``follow_redirects``, default 5. - :arg str user_agent: String to send as ``User-Agent`` header - :arg bool decompress_response: Request a compressed response from - the server and decompress it after downloading. Default is True. - New in Tornado 4.0. - :arg bool use_gzip: Deprecated alias for ``decompress_response`` - since Tornado 4.0. - :arg str network_interface: Network interface or source IP to use for request. - See ``curl_httpclient`` note below. - :arg collections.abc.Callable streaming_callback: If set, ``streaming_callback`` will - be run with each chunk of data as it is received, and - ``HTTPResponse.body`` and ``HTTPResponse.buffer`` will be empty in - the final response. - :arg collections.abc.Callable header_callback: If set, ``header_callback`` will - be run with each header line as it is received (including the - first line, e.g. ``HTTP/1.0 200 OK\r\n``, and a final line - containing only ``\r\n``. All lines include the trailing newline - characters). ``HTTPResponse.headers`` will be empty in the final - response. This is most useful in conjunction with - ``streaming_callback``, because it's the only way to get access to - header data while the request is in progress. - :arg collections.abc.Callable prepare_curl_callback: If set, will be called with - a ``pycurl.Curl`` object to allow the application to make additional - ``setopt`` calls. - :arg str proxy_host: HTTP proxy hostname. To use proxies, - ``proxy_host`` and ``proxy_port`` must be set; ``proxy_username``, - ``proxy_pass`` and ``proxy_auth_mode`` are optional. Proxies are - currently only supported with ``curl_httpclient``. - :arg int proxy_port: HTTP proxy port - :arg str proxy_username: HTTP proxy username - :arg str proxy_password: HTTP proxy password - :arg str proxy_auth_mode: HTTP proxy Authentication mode; - default is "basic". supports "basic" and "digest" - :arg bool allow_nonstandard_methods: Allow unknown values for ``method`` - argument? Default is False. - :arg bool validate_cert: For HTTPS requests, validate the server's - certificate? Default is True. - :arg str ca_certs: filename of CA certificates in PEM format, - or None to use defaults. See note below when used with - ``curl_httpclient``. - :arg str client_key: Filename for client SSL key, if any. See - note below when used with ``curl_httpclient``. - :arg str client_cert: Filename for client SSL certificate, if any. - See note below when used with ``curl_httpclient``. - :arg ssl.SSLContext ssl_options: `ssl.SSLContext` object for use in - ``simple_httpclient`` (unsupported by ``curl_httpclient``). - Overrides ``validate_cert``, ``ca_certs``, ``client_key``, - and ``client_cert``. - :arg bool allow_ipv6: Use IPv6 when available? Default is True. - :arg bool expect_100_continue: If true, send the - ``Expect: 100-continue`` header and wait for a continue response - before sending the request body. Only supported with - ``simple_httpclient``. - - .. note:: - - When using ``curl_httpclient`` certain options may be - inherited by subsequent fetches because ``pycurl`` does - not allow them to be cleanly reset. This applies to the - ``ca_certs``, ``client_key``, ``client_cert``, and - ``network_interface`` arguments. If you use these - options, you should pass them on every request (you don't - have to always use the same values, but it's not possible - to mix requests that specify these options with ones that - use the defaults). - - .. versionadded:: 3.1 - The ``auth_mode`` argument. - - .. versionadded:: 4.0 - The ``body_producer`` and ``expect_100_continue`` arguments. - - .. versionadded:: 4.2 - The ``ssl_options`` argument. - - .. versionadded:: 4.5 - The ``proxy_auth_mode`` argument. - """ - # Note that some of these attributes go through property setters - # defined below. - self.headers = headers # type: ignore - if if_modified_since: - self.headers["If-Modified-Since"] = httputil.format_timestamp( - if_modified_since - ) - self.proxy_host = proxy_host - self.proxy_port = proxy_port - self.proxy_username = proxy_username - self.proxy_password = proxy_password - self.proxy_auth_mode = proxy_auth_mode - self.url = url - self.method = method - self.body = body # type: ignore - self.body_producer = body_producer - self.auth_username = auth_username - self.auth_password = auth_password - self.auth_mode = auth_mode - self.connect_timeout = connect_timeout - self.request_timeout = request_timeout - self.follow_redirects = follow_redirects - self.max_redirects = max_redirects - self.user_agent = user_agent - if decompress_response is not None: - self.decompress_response = decompress_response # type: Optional[bool] - else: - self.decompress_response = use_gzip - self.network_interface = network_interface - self.streaming_callback = streaming_callback - self.header_callback = header_callback - self.prepare_curl_callback = prepare_curl_callback - self.allow_nonstandard_methods = allow_nonstandard_methods - self.validate_cert = validate_cert - self.ca_certs = ca_certs - self.allow_ipv6 = allow_ipv6 - self.client_key = client_key - self.client_cert = client_cert - self.ssl_options = ssl_options - self.expect_100_continue = expect_100_continue - self.start_time = time.time() - - @property - def headers(self) -> httputil.HTTPHeaders: - # TODO: headers may actually be a plain dict until fairly late in - # the process (AsyncHTTPClient.fetch), but practically speaking, - # whenever the property is used they're already HTTPHeaders. - return self._headers # type: ignore - - @headers.setter - def headers(self, value: Union[Dict[str, str], httputil.HTTPHeaders]) -> None: - if value is None: - self._headers = httputil.HTTPHeaders() - else: - self._headers = value # type: ignore - - @property - def body(self) -> bytes: - return self._body - - @body.setter - def body(self, value: Union[bytes, str]) -> None: - self._body = utf8(value) - - -class HTTPResponse(object): - """HTTP Response object. - - Attributes: - - * ``request``: HTTPRequest object - - * ``code``: numeric HTTP status code, e.g. 200 or 404 - - * ``reason``: human-readable reason phrase describing the status code - - * ``headers``: `tornado.httputil.HTTPHeaders` object - - * ``effective_url``: final location of the resource after following any - redirects - - * ``buffer``: ``cStringIO`` object for response body - - * ``body``: response body as bytes (created on demand from ``self.buffer``) - - * ``error``: Exception object, if any - - * ``request_time``: seconds from request start to finish. Includes all - network operations from DNS resolution to receiving the last byte of - data. Does not include time spent in the queue (due to the - ``max_clients`` option). If redirects were followed, only includes - the final request. - - * ``start_time``: Time at which the HTTP operation started, based on - `time.time` (not the monotonic clock used by `.IOLoop.time`). May - be ``None`` if the request timed out while in the queue. - - * ``time_info``: dictionary of diagnostic timing information from the - request. Available data are subject to change, but currently uses timings - available from http://curl.haxx.se/libcurl/c/curl_easy_getinfo.html, - plus ``queue``, which is the delay (if any) introduced by waiting for - a slot under `AsyncHTTPClient`'s ``max_clients`` setting. - - .. versionadded:: 5.1 - - Added the ``start_time`` attribute. - - .. versionchanged:: 5.1 - - The ``request_time`` attribute previously included time spent in the queue - for ``simple_httpclient``, but not in ``curl_httpclient``. Now queueing time - is excluded in both implementations. ``request_time`` is now more accurate for - ``curl_httpclient`` because it uses a monotonic clock when available. - """ - - # I'm not sure why these don't get type-inferred from the references in __init__. - error = None # type: Optional[BaseException] - _error_is_response_code = False - request = None # type: HTTPRequest - - def __init__( - self, - request: HTTPRequest, - code: int, - headers: Optional[httputil.HTTPHeaders] = None, - buffer: Optional[BytesIO] = None, - effective_url: Optional[str] = None, - error: Optional[BaseException] = None, - request_time: Optional[float] = None, - time_info: Optional[Dict[str, float]] = None, - reason: Optional[str] = None, - start_time: Optional[float] = None, - ) -> None: - if isinstance(request, _RequestProxy): - self.request = request.request - else: - self.request = request - self.code = code - self.reason = reason or httputil.responses.get(code, "Unknown") - if headers is not None: - self.headers = headers - else: - self.headers = httputil.HTTPHeaders() - self.buffer = buffer - self._body = None # type: Optional[bytes] - if effective_url is None: - self.effective_url = request.url - else: - self.effective_url = effective_url - self._error_is_response_code = False - if error is None: - if self.code < 200 or self.code >= 300: - self._error_is_response_code = True - self.error = HTTPError(self.code, message=self.reason, response=self) - else: - self.error = None - else: - self.error = error - self.start_time = start_time - self.request_time = request_time - self.time_info = time_info or {} - - @property - def body(self) -> bytes: - if self.buffer is None: - return b"" - elif self._body is None: - self._body = self.buffer.getvalue() - - return self._body - - def rethrow(self) -> None: - """If there was an error on the request, raise an `HTTPError`.""" - if self.error: - raise self.error - - def __repr__(self) -> str: - args = ",".join("%s=%r" % i for i in sorted(self.__dict__.items())) - return "%s(%s)" % (self.__class__.__name__, args) - - -class HTTPClientError(Exception): - """Exception thrown for an unsuccessful HTTP request. - - Attributes: - - * ``code`` - HTTP error integer error code, e.g. 404. Error code 599 is - used when no HTTP response was received, e.g. for a timeout. - - * ``response`` - `HTTPResponse` object, if any. - - Note that if ``follow_redirects`` is False, redirects become HTTPErrors, - and you can look at ``error.response.headers['Location']`` to see the - destination of the redirect. - - .. versionchanged:: 5.1 - - Renamed from ``HTTPError`` to ``HTTPClientError`` to avoid collisions with - `tornado.web.HTTPError`. The name ``tornado.httpclient.HTTPError`` remains - as an alias. - """ - - def __init__( - self, - code: int, - message: Optional[str] = None, - response: Optional[HTTPResponse] = None, - ) -> None: - self.code = code - self.message = message or httputil.responses.get(code, "Unknown") - self.response = response - super().__init__(code, message, response) - - def __str__(self) -> str: - return "HTTP %d: %s" % (self.code, self.message) - - # There is a cyclic reference between self and self.response, - # which breaks the default __repr__ implementation. - # (especially on pypy, which doesn't have the same recursion - # detection as cpython). - __repr__ = __str__ - - -HTTPError = HTTPClientError - - -class _RequestProxy(object): - """Combines an object with a dictionary of defaults. - - Used internally by AsyncHTTPClient implementations. - """ - - def __init__( - self, request: HTTPRequest, defaults: Optional[Dict[str, Any]] - ) -> None: - self.request = request - self.defaults = defaults - - def __getattr__(self, name: str) -> Any: - request_attr = getattr(self.request, name) - if request_attr is not None: - return request_attr - elif self.defaults is not None: - return self.defaults.get(name, None) - else: - return None - - -def main() -> None: - from tornado.options import define, options, parse_command_line - - define("print_headers", type=bool, default=False) - define("print_body", type=bool, default=True) - define("follow_redirects", type=bool, default=True) - define("validate_cert", type=bool, default=True) - define("proxy_host", type=str) - define("proxy_port", type=int) - args = parse_command_line() - client = HTTPClient() - for arg in args: - try: - response = client.fetch( - arg, - follow_redirects=options.follow_redirects, - validate_cert=options.validate_cert, - proxy_host=options.proxy_host, - proxy_port=options.proxy_port, - ) - except HTTPError as e: - if e.response is not None: - response = e.response - else: - raise - if options.print_headers: - print(response.headers) - if options.print_body: - print(native_str(response.body)) - client.close() - - -if __name__ == "__main__": - main() diff --git a/venv/lib/python3.8/site-packages/tornado/httpserver.py b/venv/lib/python3.8/site-packages/tornado/httpserver.py deleted file mode 100644 index cd4a468..0000000 --- a/venv/lib/python3.8/site-packages/tornado/httpserver.py +++ /dev/null @@ -1,398 +0,0 @@ -# -# Copyright 2009 Facebook -# -# 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. - -"""A non-blocking, single-threaded HTTP server. - -Typical applications have little direct interaction with the `HTTPServer` -class except to start a server at the beginning of the process -(and even that is often done indirectly via `tornado.web.Application.listen`). - -.. versionchanged:: 4.0 - - The ``HTTPRequest`` class that used to live in this module has been moved - to `tornado.httputil.HTTPServerRequest`. The old name remains as an alias. -""" - -import socket -import ssl - -from tornado.escape import native_str -from tornado.http1connection import HTTP1ServerConnection, HTTP1ConnectionParameters -from tornado import httputil -from tornado import iostream -from tornado import netutil -from tornado.tcpserver import TCPServer -from tornado.util import Configurable - -import typing -from typing import Union, Any, Dict, Callable, List, Type, Tuple, Optional, Awaitable - -if typing.TYPE_CHECKING: - from typing import Set # noqa: F401 - - -class HTTPServer(TCPServer, Configurable, httputil.HTTPServerConnectionDelegate): - r"""A non-blocking, single-threaded HTTP server. - - A server is defined by a subclass of `.HTTPServerConnectionDelegate`, - or, for backwards compatibility, a callback that takes an - `.HTTPServerRequest` as an argument. The delegate is usually a - `tornado.web.Application`. - - `HTTPServer` supports keep-alive connections by default - (automatically for HTTP/1.1, or for HTTP/1.0 when the client - requests ``Connection: keep-alive``). - - If ``xheaders`` is ``True``, we support the - ``X-Real-Ip``/``X-Forwarded-For`` and - ``X-Scheme``/``X-Forwarded-Proto`` headers, which override the - remote IP and URI scheme/protocol for all requests. These headers - are useful when running Tornado behind a reverse proxy or load - balancer. The ``protocol`` argument can also be set to ``https`` - if Tornado is run behind an SSL-decoding proxy that does not set one of - the supported ``xheaders``. - - By default, when parsing the ``X-Forwarded-For`` header, Tornado will - select the last (i.e., the closest) address on the list of hosts as the - remote host IP address. To select the next server in the chain, a list of - trusted downstream hosts may be passed as the ``trusted_downstream`` - argument. These hosts will be skipped when parsing the ``X-Forwarded-For`` - header. - - To make this server serve SSL traffic, send the ``ssl_options`` keyword - argument with an `ssl.SSLContext` object. For compatibility with older - versions of Python ``ssl_options`` may also be a dictionary of keyword - arguments for the `ssl.wrap_socket` method.:: - - ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) - ssl_ctx.load_cert_chain(os.path.join(data_dir, "mydomain.crt"), - os.path.join(data_dir, "mydomain.key")) - HTTPServer(application, ssl_options=ssl_ctx) - - `HTTPServer` initialization follows one of three patterns (the - initialization methods are defined on `tornado.tcpserver.TCPServer`): - - 1. `~tornado.tcpserver.TCPServer.listen`: simple single-process:: - - server = HTTPServer(app) - server.listen(8888) - IOLoop.current().start() - - In many cases, `tornado.web.Application.listen` can be used to avoid - the need to explicitly create the `HTTPServer`. - - 2. `~tornado.tcpserver.TCPServer.bind`/`~tornado.tcpserver.TCPServer.start`: - simple multi-process:: - - server = HTTPServer(app) - server.bind(8888) - server.start(0) # Forks multiple sub-processes - IOLoop.current().start() - - When using this interface, an `.IOLoop` must *not* be passed - to the `HTTPServer` constructor. `~.TCPServer.start` will always start - the server on the default singleton `.IOLoop`. - - 3. `~tornado.tcpserver.TCPServer.add_sockets`: advanced multi-process:: - - sockets = tornado.netutil.bind_sockets(8888) - tornado.process.fork_processes(0) - server = HTTPServer(app) - server.add_sockets(sockets) - IOLoop.current().start() - - The `~.TCPServer.add_sockets` interface is more complicated, - but it can be used with `tornado.process.fork_processes` to - give you more flexibility in when the fork happens. - `~.TCPServer.add_sockets` can also be used in single-process - servers if you want to create your listening sockets in some - way other than `tornado.netutil.bind_sockets`. - - .. versionchanged:: 4.0 - Added ``decompress_request``, ``chunk_size``, ``max_header_size``, - ``idle_connection_timeout``, ``body_timeout``, ``max_body_size`` - arguments. Added support for `.HTTPServerConnectionDelegate` - instances as ``request_callback``. - - .. versionchanged:: 4.1 - `.HTTPServerConnectionDelegate.start_request` is now called with - two arguments ``(server_conn, request_conn)`` (in accordance with the - documentation) instead of one ``(request_conn)``. - - .. versionchanged:: 4.2 - `HTTPServer` is now a subclass of `tornado.util.Configurable`. - - .. versionchanged:: 4.5 - Added the ``trusted_downstream`` argument. - - .. versionchanged:: 5.0 - The ``io_loop`` argument has been removed. - """ - - def __init__(self, *args: Any, **kwargs: Any) -> None: - # Ignore args to __init__; real initialization belongs in - # initialize since we're Configurable. (there's something - # weird in initialization order between this class, - # Configurable, and TCPServer so we can't leave __init__ out - # completely) - pass - - def initialize( - self, - request_callback: Union[ - httputil.HTTPServerConnectionDelegate, - Callable[[httputil.HTTPServerRequest], None], - ], - no_keep_alive: bool = False, - xheaders: bool = False, - ssl_options: Optional[Union[Dict[str, Any], ssl.SSLContext]] = None, - protocol: Optional[str] = None, - decompress_request: bool = False, - chunk_size: Optional[int] = None, - max_header_size: Optional[int] = None, - idle_connection_timeout: Optional[float] = None, - body_timeout: Optional[float] = None, - max_body_size: Optional[int] = None, - max_buffer_size: Optional[int] = None, - trusted_downstream: Optional[List[str]] = None, - ) -> None: - # This method's signature is not extracted with autodoc - # because we want its arguments to appear on the class - # constructor. When changing this signature, also update the - # copy in httpserver.rst. - self.request_callback = request_callback - self.xheaders = xheaders - self.protocol = protocol - self.conn_params = HTTP1ConnectionParameters( - decompress=decompress_request, - chunk_size=chunk_size, - max_header_size=max_header_size, - header_timeout=idle_connection_timeout or 3600, - max_body_size=max_body_size, - body_timeout=body_timeout, - no_keep_alive=no_keep_alive, - ) - TCPServer.__init__( - self, - ssl_options=ssl_options, - max_buffer_size=max_buffer_size, - read_chunk_size=chunk_size, - ) - self._connections = set() # type: Set[HTTP1ServerConnection] - self.trusted_downstream = trusted_downstream - - @classmethod - def configurable_base(cls) -> Type[Configurable]: - return HTTPServer - - @classmethod - def configurable_default(cls) -> Type[Configurable]: - return HTTPServer - - async def close_all_connections(self) -> None: - """Close all open connections and asynchronously wait for them to finish. - - This method is used in combination with `~.TCPServer.stop` to - support clean shutdowns (especially for unittests). Typical - usage would call ``stop()`` first to stop accepting new - connections, then ``await close_all_connections()`` to wait for - existing connections to finish. - - This method does not currently close open websocket connections. - - Note that this method is a coroutine and must be called with ``await``. - - """ - while self._connections: - # Peek at an arbitrary element of the set - conn = next(iter(self._connections)) - await conn.close() - - def handle_stream(self, stream: iostream.IOStream, address: Tuple) -> None: - context = _HTTPRequestContext( - stream, address, self.protocol, self.trusted_downstream - ) - conn = HTTP1ServerConnection(stream, self.conn_params, context) - self._connections.add(conn) - conn.start_serving(self) - - def start_request( - self, server_conn: object, request_conn: httputil.HTTPConnection - ) -> httputil.HTTPMessageDelegate: - if isinstance(self.request_callback, httputil.HTTPServerConnectionDelegate): - delegate = self.request_callback.start_request(server_conn, request_conn) - else: - delegate = _CallableAdapter(self.request_callback, request_conn) - - if self.xheaders: - delegate = _ProxyAdapter(delegate, request_conn) - - return delegate - - def on_close(self, server_conn: object) -> None: - self._connections.remove(typing.cast(HTTP1ServerConnection, server_conn)) - - -class _CallableAdapter(httputil.HTTPMessageDelegate): - def __init__( - self, - request_callback: Callable[[httputil.HTTPServerRequest], None], - request_conn: httputil.HTTPConnection, - ) -> None: - self.connection = request_conn - self.request_callback = request_callback - self.request = None # type: Optional[httputil.HTTPServerRequest] - self.delegate = None - self._chunks = [] # type: List[bytes] - - def headers_received( - self, - start_line: Union[httputil.RequestStartLine, httputil.ResponseStartLine], - headers: httputil.HTTPHeaders, - ) -> Optional[Awaitable[None]]: - self.request = httputil.HTTPServerRequest( - connection=self.connection, - start_line=typing.cast(httputil.RequestStartLine, start_line), - headers=headers, - ) - return None - - def data_received(self, chunk: bytes) -> Optional[Awaitable[None]]: - self._chunks.append(chunk) - return None - - def finish(self) -> None: - assert self.request is not None - self.request.body = b"".join(self._chunks) - self.request._parse_body() - self.request_callback(self.request) - - def on_connection_close(self) -> None: - del self._chunks - - -class _HTTPRequestContext(object): - def __init__( - self, - stream: iostream.IOStream, - address: Tuple, - protocol: Optional[str], - trusted_downstream: Optional[List[str]] = None, - ) -> None: - self.address = address - # Save the socket's address family now so we know how to - # interpret self.address even after the stream is closed - # and its socket attribute replaced with None. - if stream.socket is not None: - self.address_family = stream.socket.family - else: - self.address_family = None - # In HTTPServerRequest we want an IP, not a full socket address. - if ( - self.address_family in (socket.AF_INET, socket.AF_INET6) - and address is not None - ): - self.remote_ip = address[0] - else: - # Unix (or other) socket; fake the remote address. - self.remote_ip = "0.0.0.0" - if protocol: - self.protocol = protocol - elif isinstance(stream, iostream.SSLIOStream): - self.protocol = "https" - else: - self.protocol = "http" - self._orig_remote_ip = self.remote_ip - self._orig_protocol = self.protocol - self.trusted_downstream = set(trusted_downstream or []) - - def __str__(self) -> str: - if self.address_family in (socket.AF_INET, socket.AF_INET6): - return self.remote_ip - elif isinstance(self.address, bytes): - # Python 3 with the -bb option warns about str(bytes), - # so convert it explicitly. - # Unix socket addresses are str on mac but bytes on linux. - return native_str(self.address) - else: - return str(self.address) - - def _apply_xheaders(self, headers: httputil.HTTPHeaders) -> None: - """Rewrite the ``remote_ip`` and ``protocol`` fields.""" - # Squid uses X-Forwarded-For, others use X-Real-Ip - ip = headers.get("X-Forwarded-For", self.remote_ip) - # Skip trusted downstream hosts in X-Forwarded-For list - for ip in (cand.strip() for cand in reversed(ip.split(","))): - if ip not in self.trusted_downstream: - break - ip = headers.get("X-Real-Ip", ip) - if netutil.is_valid_ip(ip): - self.remote_ip = ip - # AWS uses X-Forwarded-Proto - proto_header = headers.get( - "X-Scheme", headers.get("X-Forwarded-Proto", self.protocol) - ) - if proto_header: - # use only the last proto entry if there is more than one - # TODO: support trusting multiple layers of proxied protocol - proto_header = proto_header.split(",")[-1].strip() - if proto_header in ("http", "https"): - self.protocol = proto_header - - def _unapply_xheaders(self) -> None: - """Undo changes from `_apply_xheaders`. - - Xheaders are per-request so they should not leak to the next - request on the same connection. - """ - self.remote_ip = self._orig_remote_ip - self.protocol = self._orig_protocol - - -class _ProxyAdapter(httputil.HTTPMessageDelegate): - def __init__( - self, - delegate: httputil.HTTPMessageDelegate, - request_conn: httputil.HTTPConnection, - ) -> None: - self.connection = request_conn - self.delegate = delegate - - def headers_received( - self, - start_line: Union[httputil.RequestStartLine, httputil.ResponseStartLine], - headers: httputil.HTTPHeaders, - ) -> Optional[Awaitable[None]]: - # TODO: either make context an official part of the - # HTTPConnection interface or figure out some other way to do this. - self.connection.context._apply_xheaders(headers) # type: ignore - return self.delegate.headers_received(start_line, headers) - - def data_received(self, chunk: bytes) -> Optional[Awaitable[None]]: - return self.delegate.data_received(chunk) - - def finish(self) -> None: - self.delegate.finish() - self._cleanup() - - def on_connection_close(self) -> None: - self.delegate.on_connection_close() - self._cleanup() - - def _cleanup(self) -> None: - self.connection.context._unapply_xheaders() # type: ignore - - -HTTPRequest = httputil.HTTPServerRequest diff --git a/venv/lib/python3.8/site-packages/tornado/httputil.py b/venv/lib/python3.8/site-packages/tornado/httputil.py deleted file mode 100644 index bd32cd0..0000000 --- a/venv/lib/python3.8/site-packages/tornado/httputil.py +++ /dev/null @@ -1,1133 +0,0 @@ -# -# Copyright 2009 Facebook -# -# 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. - -"""HTTP utility code shared by clients and servers. - -This module also defines the `HTTPServerRequest` class which is exposed -via `tornado.web.RequestHandler.request`. -""" - -import calendar -import collections -import copy -import datetime -import email.utils -from functools import lru_cache -from http.client import responses -import http.cookies -import re -from ssl import SSLError -import time -import unicodedata -from urllib.parse import urlencode, urlparse, urlunparse, parse_qsl - -from tornado.escape import native_str, parse_qs_bytes, utf8 -from tornado.log import gen_log -from tornado.util import ObjectDict, unicode_type - - -# responses is unused in this file, but we re-export it to other files. -# Reference it so pyflakes doesn't complain. -responses - -import typing -from typing import ( - Tuple, - Iterable, - List, - Mapping, - Iterator, - Dict, - Union, - Optional, - Awaitable, - Generator, - AnyStr, -) - -if typing.TYPE_CHECKING: - from typing import Deque # noqa: F401 - from asyncio import Future # noqa: F401 - import unittest # noqa: F401 - - -@lru_cache(1000) -def _normalize_header(name: str) -> str: - """Map a header name to Http-Header-Case. - - >>> _normalize_header("coNtent-TYPE") - 'Content-Type' - """ - return "-".join([w.capitalize() for w in name.split("-")]) - - -class HTTPHeaders(collections.abc.MutableMapping): - """A dictionary that maintains ``Http-Header-Case`` for all keys. - - Supports multiple values per key via a pair of new methods, - `add()` and `get_list()`. The regular dictionary interface - returns a single value per key, with multiple values joined by a - comma. - - >>> h = HTTPHeaders({"content-type": "text/html"}) - >>> list(h.keys()) - ['Content-Type'] - >>> h["Content-Type"] - 'text/html' - - >>> h.add("Set-Cookie", "A=B") - >>> h.add("Set-Cookie", "C=D") - >>> h["set-cookie"] - 'A=B,C=D' - >>> h.get_list("set-cookie") - ['A=B', 'C=D'] - - >>> for (k,v) in sorted(h.get_all()): - ... print('%s: %s' % (k,v)) - ... - Content-Type: text/html - Set-Cookie: A=B - Set-Cookie: C=D - """ - - @typing.overload - def __init__(self, __arg: Mapping[str, List[str]]) -> None: - pass - - @typing.overload # noqa: F811 - def __init__(self, __arg: Mapping[str, str]) -> None: - pass - - @typing.overload # noqa: F811 - def __init__(self, *args: Tuple[str, str]) -> None: - pass - - @typing.overload # noqa: F811 - def __init__(self, **kwargs: str) -> None: - pass - - def __init__(self, *args: typing.Any, **kwargs: str) -> None: # noqa: F811 - self._dict = {} # type: typing.Dict[str, str] - self._as_list = {} # type: typing.Dict[str, typing.List[str]] - self._last_key = None # type: Optional[str] - if len(args) == 1 and len(kwargs) == 0 and isinstance(args[0], HTTPHeaders): - # Copy constructor - for k, v in args[0].get_all(): - self.add(k, v) - else: - # Dict-style initialization - self.update(*args, **kwargs) - - # new public methods - - def add(self, name: str, value: str) -> None: - """Adds a new value for the given key.""" - norm_name = _normalize_header(name) - self._last_key = norm_name - if norm_name in self: - self._dict[norm_name] = ( - native_str(self[norm_name]) + "," + native_str(value) - ) - self._as_list[norm_name].append(value) - else: - self[norm_name] = value - - def get_list(self, name: str) -> List[str]: - """Returns all values for the given header as a list.""" - norm_name = _normalize_header(name) - return self._as_list.get(norm_name, []) - - def get_all(self) -> Iterable[Tuple[str, str]]: - """Returns an iterable of all (name, value) pairs. - - If a header has multiple values, multiple pairs will be - returned with the same name. - """ - for name, values in self._as_list.items(): - for value in values: - yield (name, value) - - def parse_line(self, line: str) -> None: - """Updates the dictionary with a single header line. - - >>> h = HTTPHeaders() - >>> h.parse_line("Content-Type: text/html") - >>> h.get('content-type') - 'text/html' - """ - if line[0].isspace(): - # continuation of a multi-line header - if self._last_key is None: - raise HTTPInputError("first header line cannot start with whitespace") - new_part = " " + line.lstrip() - self._as_list[self._last_key][-1] += new_part - self._dict[self._last_key] += new_part - else: - try: - name, value = line.split(":", 1) - except ValueError: - raise HTTPInputError("no colon in header line") - self.add(name, value.strip()) - - @classmethod - def parse(cls, headers: str) -> "HTTPHeaders": - """Returns a dictionary from HTTP header text. - - >>> h = HTTPHeaders.parse("Content-Type: text/html\\r\\nContent-Length: 42\\r\\n") - >>> sorted(h.items()) - [('Content-Length', '42'), ('Content-Type', 'text/html')] - - .. versionchanged:: 5.1 - - Raises `HTTPInputError` on malformed headers instead of a - mix of `KeyError`, and `ValueError`. - - """ - h = cls() - # RFC 7230 section 3.5: a recipient MAY recognize a single LF as a line - # terminator and ignore any preceding CR. - for line in headers.split("\n"): - if line.endswith("\r"): - line = line[:-1] - if line: - h.parse_line(line) - return h - - # MutableMapping abstract method implementations. - - def __setitem__(self, name: str, value: str) -> None: - norm_name = _normalize_header(name) - self._dict[norm_name] = value - self._as_list[norm_name] = [value] - - def __getitem__(self, name: str) -> str: - return self._dict[_normalize_header(name)] - - def __delitem__(self, name: str) -> None: - norm_name = _normalize_header(name) - del self._dict[norm_name] - del self._as_list[norm_name] - - def __len__(self) -> int: - return len(self._dict) - - def __iter__(self) -> Iterator[typing.Any]: - return iter(self._dict) - - def copy(self) -> "HTTPHeaders": - # defined in dict but not in MutableMapping. - return HTTPHeaders(self) - - # Use our overridden copy method for the copy.copy module. - # This makes shallow copies one level deeper, but preserves - # the appearance that HTTPHeaders is a single container. - __copy__ = copy - - def __str__(self) -> str: - lines = [] - for name, value in self.get_all(): - lines.append("%s: %s\n" % (name, value)) - return "".join(lines) - - __unicode__ = __str__ - - -class HTTPServerRequest(object): - """A single HTTP request. - - All attributes are type `str` unless otherwise noted. - - .. attribute:: method - - HTTP request method, e.g. "GET" or "POST" - - .. attribute:: uri - - The requested uri. - - .. attribute:: path - - The path portion of `uri` - - .. attribute:: query - - The query portion of `uri` - - .. attribute:: version - - HTTP version specified in request, e.g. "HTTP/1.1" - - .. attribute:: headers - - `.HTTPHeaders` dictionary-like object for request headers. Acts like - a case-insensitive dictionary with additional methods for repeated - headers. - - .. attribute:: body - - Request body, if present, as a byte string. - - .. attribute:: remote_ip - - Client's IP address as a string. If ``HTTPServer.xheaders`` is set, - will pass along the real IP address provided by a load balancer - in the ``X-Real-Ip`` or ``X-Forwarded-For`` header. - - .. versionchanged:: 3.1 - The list format of ``X-Forwarded-For`` is now supported. - - .. attribute:: protocol - - The protocol used, either "http" or "https". If ``HTTPServer.xheaders`` - is set, will pass along the protocol used by a load balancer if - reported via an ``X-Scheme`` header. - - .. attribute:: host - - The requested hostname, usually taken from the ``Host`` header. - - .. attribute:: arguments - - GET/POST arguments are available in the arguments property, which - maps arguments names to lists of values (to support multiple values - for individual names). Names are of type `str`, while arguments - are byte strings. Note that this is different from - `.RequestHandler.get_argument`, which returns argument values as - unicode strings. - - .. attribute:: query_arguments - - Same format as ``arguments``, but contains only arguments extracted - from the query string. - - .. versionadded:: 3.2 - - .. attribute:: body_arguments - - Same format as ``arguments``, but contains only arguments extracted - from the request body. - - .. versionadded:: 3.2 - - .. attribute:: files - - File uploads are available in the files property, which maps file - names to lists of `.HTTPFile`. - - .. attribute:: connection - - An HTTP request is attached to a single HTTP connection, which can - be accessed through the "connection" attribute. Since connections - are typically kept open in HTTP/1.1, multiple requests can be handled - sequentially on a single connection. - - .. versionchanged:: 4.0 - Moved from ``tornado.httpserver.HTTPRequest``. - """ - - path = None # type: str - query = None # type: str - - # HACK: Used for stream_request_body - _body_future = None # type: Future[None] - - def __init__( - self, - method: Optional[str] = None, - uri: Optional[str] = None, - version: str = "HTTP/1.0", - headers: Optional[HTTPHeaders] = None, - body: Optional[bytes] = None, - host: Optional[str] = None, - files: Optional[Dict[str, List["HTTPFile"]]] = None, - connection: Optional["HTTPConnection"] = None, - start_line: Optional["RequestStartLine"] = None, - server_connection: Optional[object] = None, - ) -> None: - if start_line is not None: - method, uri, version = start_line - self.method = method - self.uri = uri - self.version = version - self.headers = headers or HTTPHeaders() - self.body = body or b"" - - # set remote IP and protocol - context = getattr(connection, "context", None) - self.remote_ip = getattr(context, "remote_ip", None) - self.protocol = getattr(context, "protocol", "http") - - self.host = host or self.headers.get("Host") or "127.0.0.1" - self.host_name = split_host_and_port(self.host.lower())[0] - self.files = files or {} - self.connection = connection - self.server_connection = server_connection - self._start_time = time.time() - self._finish_time = None - - if uri is not None: - self.path, sep, self.query = uri.partition("?") - self.arguments = parse_qs_bytes(self.query, keep_blank_values=True) - self.query_arguments = copy.deepcopy(self.arguments) - self.body_arguments = {} # type: Dict[str, List[bytes]] - - @property - def cookies(self) -> Dict[str, http.cookies.Morsel]: - """A dictionary of ``http.cookies.Morsel`` objects.""" - if not hasattr(self, "_cookies"): - self._cookies = ( - http.cookies.SimpleCookie() - ) # type: http.cookies.SimpleCookie - if "Cookie" in self.headers: - try: - parsed = parse_cookie(self.headers["Cookie"]) - except Exception: - pass - else: - for k, v in parsed.items(): - try: - self._cookies[k] = v - except Exception: - # SimpleCookie imposes some restrictions on keys; - # parse_cookie does not. Discard any cookies - # with disallowed keys. - pass - return self._cookies - - def full_url(self) -> str: - """Reconstructs the full URL for this request.""" - return self.protocol + "://" + self.host + self.uri - - def request_time(self) -> float: - """Returns the amount of time it took for this request to execute.""" - if self._finish_time is None: - return time.time() - self._start_time - else: - return self._finish_time - self._start_time - - def get_ssl_certificate( - self, binary_form: bool = False - ) -> Union[None, Dict, bytes]: - """Returns the client's SSL certificate, if any. - - To use client certificates, the HTTPServer's - `ssl.SSLContext.verify_mode` field must be set, e.g.:: - - ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) - ssl_ctx.load_cert_chain("foo.crt", "foo.key") - ssl_ctx.load_verify_locations("cacerts.pem") - ssl_ctx.verify_mode = ssl.CERT_REQUIRED - server = HTTPServer(app, ssl_options=ssl_ctx) - - By default, the return value is a dictionary (or None, if no - client certificate is present). If ``binary_form`` is true, a - DER-encoded form of the certificate is returned instead. See - SSLSocket.getpeercert() in the standard library for more - details. - http://docs.python.org/library/ssl.html#sslsocket-objects - """ - try: - if self.connection is None: - return None - # TODO: add a method to HTTPConnection for this so it can work with HTTP/2 - return self.connection.stream.socket.getpeercert( # type: ignore - binary_form=binary_form - ) - except SSLError: - return None - - def _parse_body(self) -> None: - parse_body_arguments( - self.headers.get("Content-Type", ""), - self.body, - self.body_arguments, - self.files, - self.headers, - ) - - for k, v in self.body_arguments.items(): - self.arguments.setdefault(k, []).extend(v) - - def __repr__(self) -> str: - attrs = ("protocol", "host", "method", "uri", "version", "remote_ip") - args = ", ".join(["%s=%r" % (n, getattr(self, n)) for n in attrs]) - return "%s(%s)" % (self.__class__.__name__, args) - - -class HTTPInputError(Exception): - """Exception class for malformed HTTP requests or responses - from remote sources. - - .. versionadded:: 4.0 - """ - - pass - - -class HTTPOutputError(Exception): - """Exception class for errors in HTTP output. - - .. versionadded:: 4.0 - """ - - pass - - -class HTTPServerConnectionDelegate(object): - """Implement this interface to handle requests from `.HTTPServer`. - - .. versionadded:: 4.0 - """ - - def start_request( - self, server_conn: object, request_conn: "HTTPConnection" - ) -> "HTTPMessageDelegate": - """This method is called by the server when a new request has started. - - :arg server_conn: is an opaque object representing the long-lived - (e.g. tcp-level) connection. - :arg request_conn: is a `.HTTPConnection` object for a single - request/response exchange. - - This method should return a `.HTTPMessageDelegate`. - """ - raise NotImplementedError() - - def on_close(self, server_conn: object) -> None: - """This method is called when a connection has been closed. - - :arg server_conn: is a server connection that has previously been - passed to ``start_request``. - """ - pass - - -class HTTPMessageDelegate(object): - """Implement this interface to handle an HTTP request or response. - - .. versionadded:: 4.0 - """ - - # TODO: genericize this class to avoid exposing the Union. - def headers_received( - self, - start_line: Union["RequestStartLine", "ResponseStartLine"], - headers: HTTPHeaders, - ) -> Optional[Awaitable[None]]: - """Called when the HTTP headers have been received and parsed. - - :arg start_line: a `.RequestStartLine` or `.ResponseStartLine` - depending on whether this is a client or server message. - :arg headers: a `.HTTPHeaders` instance. - - Some `.HTTPConnection` methods can only be called during - ``headers_received``. - - May return a `.Future`; if it does the body will not be read - until it is done. - """ - pass - - def data_received(self, chunk: bytes) -> Optional[Awaitable[None]]: - """Called when a chunk of data has been received. - - May return a `.Future` for flow control. - """ - pass - - def finish(self) -> None: - """Called after the last chunk of data has been received.""" - pass - - def on_connection_close(self) -> None: - """Called if the connection is closed without finishing the request. - - If ``headers_received`` is called, either ``finish`` or - ``on_connection_close`` will be called, but not both. - """ - pass - - -class HTTPConnection(object): - """Applications use this interface to write their responses. - - .. versionadded:: 4.0 - """ - - def write_headers( - self, - start_line: Union["RequestStartLine", "ResponseStartLine"], - headers: HTTPHeaders, - chunk: Optional[bytes] = None, - ) -> "Future[None]": - """Write an HTTP header block. - - :arg start_line: a `.RequestStartLine` or `.ResponseStartLine`. - :arg headers: a `.HTTPHeaders` instance. - :arg chunk: the first (optional) chunk of data. This is an optimization - so that small responses can be written in the same call as their - headers. - - The ``version`` field of ``start_line`` is ignored. - - Returns a future for flow control. - - .. versionchanged:: 6.0 - - The ``callback`` argument was removed. - """ - raise NotImplementedError() - - def write(self, chunk: bytes) -> "Future[None]": - """Writes a chunk of body data. - - Returns a future for flow control. - - .. versionchanged:: 6.0 - - The ``callback`` argument was removed. - """ - raise NotImplementedError() - - def finish(self) -> None: - """Indicates that the last body data has been written. - """ - raise NotImplementedError() - - -def url_concat( - url: str, - args: Union[ - None, Dict[str, str], List[Tuple[str, str]], Tuple[Tuple[str, str], ...] - ], -) -> str: - """Concatenate url and arguments regardless of whether - url has existing query parameters. - - ``args`` may be either a dictionary or a list of key-value pairs - (the latter allows for multiple values with the same key. - - >>> url_concat("http://example.com/foo", dict(c="d")) - 'http://example.com/foo?c=d' - >>> url_concat("http://example.com/foo?a=b", dict(c="d")) - 'http://example.com/foo?a=b&c=d' - >>> url_concat("http://example.com/foo?a=b", [("c", "d"), ("c", "d2")]) - 'http://example.com/foo?a=b&c=d&c=d2' - """ - if args is None: - return url - parsed_url = urlparse(url) - if isinstance(args, dict): - parsed_query = parse_qsl(parsed_url.query, keep_blank_values=True) - parsed_query.extend(args.items()) - elif isinstance(args, list) or isinstance(args, tuple): - parsed_query = parse_qsl(parsed_url.query, keep_blank_values=True) - parsed_query.extend(args) - else: - err = "'args' parameter should be dict, list or tuple. Not {0}".format( - type(args) - ) - raise TypeError(err) - final_query = urlencode(parsed_query) - url = urlunparse( - ( - parsed_url[0], - parsed_url[1], - parsed_url[2], - parsed_url[3], - final_query, - parsed_url[5], - ) - ) - return url - - -class HTTPFile(ObjectDict): - """Represents a file uploaded via a form. - - For backwards compatibility, its instance attributes are also - accessible as dictionary keys. - - * ``filename`` - * ``body`` - * ``content_type`` - """ - - pass - - -def _parse_request_range( - range_header: str, -) -> Optional[Tuple[Optional[int], Optional[int]]]: - """Parses a Range header. - - Returns either ``None`` or tuple ``(start, end)``. - Note that while the HTTP headers use inclusive byte positions, - this method returns indexes suitable for use in slices. - - >>> start, end = _parse_request_range("bytes=1-2") - >>> start, end - (1, 3) - >>> [0, 1, 2, 3, 4][start:end] - [1, 2] - >>> _parse_request_range("bytes=6-") - (6, None) - >>> _parse_request_range("bytes=-6") - (-6, None) - >>> _parse_request_range("bytes=-0") - (None, 0) - >>> _parse_request_range("bytes=") - (None, None) - >>> _parse_request_range("foo=42") - >>> _parse_request_range("bytes=1-2,6-10") - - Note: only supports one range (ex, ``bytes=1-2,6-10`` is not allowed). - - See [0] for the details of the range header. - - [0]: http://greenbytes.de/tech/webdav/draft-ietf-httpbis-p5-range-latest.html#byte.ranges - """ - unit, _, value = range_header.partition("=") - unit, value = unit.strip(), value.strip() - if unit != "bytes": - return None - start_b, _, end_b = value.partition("-") - try: - start = _int_or_none(start_b) - end = _int_or_none(end_b) - except ValueError: - return None - if end is not None: - if start is None: - if end != 0: - start = -end - end = None - else: - end += 1 - return (start, end) - - -def _get_content_range(start: Optional[int], end: Optional[int], total: int) -> str: - """Returns a suitable Content-Range header: - - >>> print(_get_content_range(None, 1, 4)) - bytes 0-0/4 - >>> print(_get_content_range(1, 3, 4)) - bytes 1-2/4 - >>> print(_get_content_range(None, None, 4)) - bytes 0-3/4 - """ - start = start or 0 - end = (end or total) - 1 - return "bytes %s-%s/%s" % (start, end, total) - - -def _int_or_none(val: str) -> Optional[int]: - val = val.strip() - if val == "": - return None - return int(val) - - -def parse_body_arguments( - content_type: str, - body: bytes, - arguments: Dict[str, List[bytes]], - files: Dict[str, List[HTTPFile]], - headers: Optional[HTTPHeaders] = None, -) -> None: - """Parses a form request body. - - Supports ``application/x-www-form-urlencoded`` and - ``multipart/form-data``. The ``content_type`` parameter should be - a string and ``body`` should be a byte string. The ``arguments`` - and ``files`` parameters are dictionaries that will be updated - with the parsed contents. - """ - if content_type.startswith("application/x-www-form-urlencoded"): - if headers and "Content-Encoding" in headers: - gen_log.warning( - "Unsupported Content-Encoding: %s", headers["Content-Encoding"] - ) - return - try: - # real charset decoding will happen in RequestHandler.decode_argument() - uri_arguments = parse_qs_bytes(body, keep_blank_values=True) - except Exception as e: - gen_log.warning("Invalid x-www-form-urlencoded body: %s", e) - uri_arguments = {} - for name, values in uri_arguments.items(): - if values: - arguments.setdefault(name, []).extend(values) - elif content_type.startswith("multipart/form-data"): - if headers and "Content-Encoding" in headers: - gen_log.warning( - "Unsupported Content-Encoding: %s", headers["Content-Encoding"] - ) - return - try: - fields = content_type.split(";") - for field in fields: - k, sep, v = field.strip().partition("=") - if k == "boundary" and v: - parse_multipart_form_data(utf8(v), body, arguments, files) - break - else: - raise ValueError("multipart boundary not found") - except Exception as e: - gen_log.warning("Invalid multipart/form-data: %s", e) - - -def parse_multipart_form_data( - boundary: bytes, - data: bytes, - arguments: Dict[str, List[bytes]], - files: Dict[str, List[HTTPFile]], -) -> None: - """Parses a ``multipart/form-data`` body. - - The ``boundary`` and ``data`` parameters are both byte strings. - The dictionaries given in the arguments and files parameters - will be updated with the contents of the body. - - .. versionchanged:: 5.1 - - Now recognizes non-ASCII filenames in RFC 2231/5987 - (``filename*=``) format. - """ - # The standard allows for the boundary to be quoted in the header, - # although it's rare (it happens at least for google app engine - # xmpp). I think we're also supposed to handle backslash-escapes - # here but I'll save that until we see a client that uses them - # in the wild. - if boundary.startswith(b'"') and boundary.endswith(b'"'): - boundary = boundary[1:-1] - final_boundary_index = data.rfind(b"--" + boundary + b"--") - if final_boundary_index == -1: - gen_log.warning("Invalid multipart/form-data: no final boundary") - return - parts = data[:final_boundary_index].split(b"--" + boundary + b"\r\n") - for part in parts: - if not part: - continue - eoh = part.find(b"\r\n\r\n") - if eoh == -1: - gen_log.warning("multipart/form-data missing headers") - continue - headers = HTTPHeaders.parse(part[:eoh].decode("utf-8")) - disp_header = headers.get("Content-Disposition", "") - disposition, disp_params = _parse_header(disp_header) - if disposition != "form-data" or not part.endswith(b"\r\n"): - gen_log.warning("Invalid multipart/form-data") - continue - value = part[eoh + 4 : -2] - if not disp_params.get("name"): - gen_log.warning("multipart/form-data value missing name") - continue - name = disp_params["name"] - if disp_params.get("filename"): - ctype = headers.get("Content-Type", "application/unknown") - files.setdefault(name, []).append( - HTTPFile( - filename=disp_params["filename"], body=value, content_type=ctype - ) - ) - else: - arguments.setdefault(name, []).append(value) - - -def format_timestamp( - ts: Union[int, float, tuple, time.struct_time, datetime.datetime] -) -> str: - """Formats a timestamp in the format used by HTTP. - - The argument may be a numeric timestamp as returned by `time.time`, - a time tuple as returned by `time.gmtime`, or a `datetime.datetime` - object. - - >>> format_timestamp(1359312200) - 'Sun, 27 Jan 2013 18:43:20 GMT' - """ - if isinstance(ts, (int, float)): - time_num = ts - elif isinstance(ts, (tuple, time.struct_time)): - time_num = calendar.timegm(ts) - elif isinstance(ts, datetime.datetime): - time_num = calendar.timegm(ts.utctimetuple()) - else: - raise TypeError("unknown timestamp type: %r" % ts) - return email.utils.formatdate(time_num, usegmt=True) - - -RequestStartLine = collections.namedtuple( - "RequestStartLine", ["method", "path", "version"] -) - - -_http_version_re = re.compile(r"^HTTP/1\.[0-9]$") - - -def parse_request_start_line(line: str) -> RequestStartLine: - """Returns a (method, path, version) tuple for an HTTP 1.x request line. - - The response is a `collections.namedtuple`. - - >>> parse_request_start_line("GET /foo HTTP/1.1") - RequestStartLine(method='GET', path='/foo', version='HTTP/1.1') - """ - try: - method, path, version = line.split(" ") - except ValueError: - # https://tools.ietf.org/html/rfc7230#section-3.1.1 - # invalid request-line SHOULD respond with a 400 (Bad Request) - raise HTTPInputError("Malformed HTTP request line") - if not _http_version_re.match(version): - raise HTTPInputError( - "Malformed HTTP version in HTTP Request-Line: %r" % version - ) - return RequestStartLine(method, path, version) - - -ResponseStartLine = collections.namedtuple( - "ResponseStartLine", ["version", "code", "reason"] -) - - -_http_response_line_re = re.compile(r"(HTTP/1.[0-9]) ([0-9]+) ([^\r]*)") - - -def parse_response_start_line(line: str) -> ResponseStartLine: - """Returns a (version, code, reason) tuple for an HTTP 1.x response line. - - The response is a `collections.namedtuple`. - - >>> parse_response_start_line("HTTP/1.1 200 OK") - ResponseStartLine(version='HTTP/1.1', code=200, reason='OK') - """ - line = native_str(line) - match = _http_response_line_re.match(line) - if not match: - raise HTTPInputError("Error parsing response start line") - return ResponseStartLine(match.group(1), int(match.group(2)), match.group(3)) - - -# _parseparam and _parse_header are copied and modified from python2.7's cgi.py -# The original 2.7 version of this code did not correctly support some -# combinations of semicolons and double quotes. -# It has also been modified to support valueless parameters as seen in -# websocket extension negotiations, and to support non-ascii values in -# RFC 2231/5987 format. - - -def _parseparam(s: str) -> Generator[str, None, None]: - while s[:1] == ";": - s = s[1:] - end = s.find(";") - while end > 0 and (s.count('"', 0, end) - s.count('\\"', 0, end)) % 2: - end = s.find(";", end + 1) - if end < 0: - end = len(s) - f = s[:end] - yield f.strip() - s = s[end:] - - -def _parse_header(line: str) -> Tuple[str, Dict[str, str]]: - r"""Parse a Content-type like header. - - Return the main content-type and a dictionary of options. - - >>> d = "form-data; foo=\"b\\\\a\\\"r\"; file*=utf-8''T%C3%A4st" - >>> ct, d = _parse_header(d) - >>> ct - 'form-data' - >>> d['file'] == r'T\u00e4st'.encode('ascii').decode('unicode_escape') - True - >>> d['foo'] - 'b\\a"r' - """ - parts = _parseparam(";" + line) - key = next(parts) - # decode_params treats first argument special, but we already stripped key - params = [("Dummy", "value")] - for p in parts: - i = p.find("=") - if i >= 0: - name = p[:i].strip().lower() - value = p[i + 1 :].strip() - params.append((name, native_str(value))) - decoded_params = email.utils.decode_params(params) - decoded_params.pop(0) # get rid of the dummy again - pdict = {} - for name, decoded_value in decoded_params: - value = email.utils.collapse_rfc2231_value(decoded_value) - if len(value) >= 2 and value[0] == '"' and value[-1] == '"': - value = value[1:-1] - pdict[name] = value - return key, pdict - - -def _encode_header(key: str, pdict: Dict[str, str]) -> str: - """Inverse of _parse_header. - - >>> _encode_header('permessage-deflate', - ... {'client_max_window_bits': 15, 'client_no_context_takeover': None}) - 'permessage-deflate; client_max_window_bits=15; client_no_context_takeover' - """ - if not pdict: - return key - out = [key] - # Sort the parameters just to make it easy to test. - for k, v in sorted(pdict.items()): - if v is None: - out.append(k) - else: - # TODO: quote if necessary. - out.append("%s=%s" % (k, v)) - return "; ".join(out) - - -def encode_username_password( - username: Union[str, bytes], password: Union[str, bytes] -) -> bytes: - """Encodes a username/password pair in the format used by HTTP auth. - - The return value is a byte string in the form ``username:password``. - - .. versionadded:: 5.1 - """ - if isinstance(username, unicode_type): - username = unicodedata.normalize("NFC", username) - if isinstance(password, unicode_type): - password = unicodedata.normalize("NFC", password) - return utf8(username) + b":" + utf8(password) - - -def doctests(): - # type: () -> unittest.TestSuite - import doctest - - return doctest.DocTestSuite() - - -_netloc_re = re.compile(r"^(.+):(\d+)$") - - -def split_host_and_port(netloc: str) -> Tuple[str, Optional[int]]: - """Returns ``(host, port)`` tuple from ``netloc``. - - Returned ``port`` will be ``None`` if not present. - - .. versionadded:: 4.1 - """ - match = _netloc_re.match(netloc) - if match: - host = match.group(1) - port = int(match.group(2)) # type: Optional[int] - else: - host = netloc - port = None - return (host, port) - - -def qs_to_qsl(qs: Dict[str, List[AnyStr]]) -> Iterable[Tuple[str, AnyStr]]: - """Generator converting a result of ``parse_qs`` back to name-value pairs. - - .. versionadded:: 5.0 - """ - for k, vs in qs.items(): - for v in vs: - yield (k, v) - - -_OctalPatt = re.compile(r"\\[0-3][0-7][0-7]") -_QuotePatt = re.compile(r"[\\].") -_nulljoin = "".join - - -def _unquote_cookie(s: str) -> str: - """Handle double quotes and escaping in cookie values. - - This method is copied verbatim from the Python 3.5 standard - library (http.cookies._unquote) so we don't have to depend on - non-public interfaces. - """ - # If there aren't any doublequotes, - # then there can't be any special characters. See RFC 2109. - if s is None or len(s) < 2: - return s - if s[0] != '"' or s[-1] != '"': - return s - - # We have to assume that we must decode this string. - # Down to work. - - # Remove the "s - s = s[1:-1] - - # Check for special sequences. Examples: - # \012 --> \n - # \" --> " - # - i = 0 - n = len(s) - res = [] - while 0 <= i < n: - o_match = _OctalPatt.search(s, i) - q_match = _QuotePatt.search(s, i) - if not o_match and not q_match: # Neither matched - res.append(s[i:]) - break - # else: - j = k = -1 - if o_match: - j = o_match.start(0) - if q_match: - k = q_match.start(0) - if q_match and (not o_match or k < j): # QuotePatt matched - res.append(s[i:k]) - res.append(s[k + 1]) - i = k + 2 - else: # OctalPatt matched - res.append(s[i:j]) - res.append(chr(int(s[j + 1 : j + 4], 8))) - i = j + 4 - return _nulljoin(res) - - -def parse_cookie(cookie: str) -> Dict[str, str]: - """Parse a ``Cookie`` HTTP header into a dict of name/value pairs. - - This function attempts to mimic browser cookie parsing behavior; - it specifically does not follow any of the cookie-related RFCs - (because browsers don't either). - - The algorithm used is identical to that used by Django version 1.9.10. - - .. versionadded:: 4.4.2 - """ - cookiedict = {} - for chunk in cookie.split(str(";")): - if str("=") in chunk: - key, val = chunk.split(str("="), 1) - else: - # Assume an empty name per - # https://bugzilla.mozilla.org/show_bug.cgi?id=169091 - key, val = str(""), chunk - key, val = key.strip(), val.strip() - if key or val: - # unquote using Python's algorithm. - cookiedict[key] = _unquote_cookie(val) - return cookiedict diff --git a/venv/lib/python3.8/site-packages/tornado/ioloop.py b/venv/lib/python3.8/site-packages/tornado/ioloop.py deleted file mode 100644 index 2cf8844..0000000 --- a/venv/lib/python3.8/site-packages/tornado/ioloop.py +++ /dev/null @@ -1,944 +0,0 @@ -# -# Copyright 2009 Facebook -# -# 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. - -"""An I/O event loop for non-blocking sockets. - -In Tornado 6.0, `.IOLoop` is a wrapper around the `asyncio` event -loop, with a slightly different interface for historical reasons. -Applications can use either the `.IOLoop` interface or the underlying -`asyncio` event loop directly (unless compatibility with older -versions of Tornado is desired, in which case `.IOLoop` must be used). - -Typical applications will use a single `IOLoop` object, accessed via -`IOLoop.current` class method. The `IOLoop.start` method (or -equivalently, `asyncio.AbstractEventLoop.run_forever`) should usually -be called at the end of the ``main()`` function. Atypical applications -may use more than one `IOLoop`, such as one `IOLoop` per thread, or -per `unittest` case. - -""" - -import asyncio -import concurrent.futures -import datetime -import functools -import logging -import numbers -import os -import sys -import time -import math -import random - -from tornado.concurrent import ( - Future, - is_future, - chain_future, - future_set_exc_info, - future_add_done_callback, -) -from tornado.log import app_log -from tornado.util import Configurable, TimeoutError, import_object - -import typing -from typing import Union, Any, Type, Optional, Callable, TypeVar, Tuple, Awaitable - -if typing.TYPE_CHECKING: - from typing import Dict, List # noqa: F401 - - from typing_extensions import Protocol -else: - Protocol = object - - -class _Selectable(Protocol): - def fileno(self) -> int: - pass - - def close(self) -> None: - pass - - -_T = TypeVar("_T") -_S = TypeVar("_S", bound=_Selectable) - - -class IOLoop(Configurable): - """An I/O event loop. - - As of Tornado 6.0, `IOLoop` is a wrapper around the `asyncio` event - loop. - - Example usage for a simple TCP server: - - .. testcode:: - - import errno - import functools - import socket - - import tornado.ioloop - from tornado.iostream import IOStream - - async def handle_connection(connection, address): - stream = IOStream(connection) - message = await stream.read_until_close() - print("message from client:", message.decode().strip()) - - def connection_ready(sock, fd, events): - while True: - try: - connection, address = sock.accept() - except BlockingIOError: - return - connection.setblocking(0) - io_loop = tornado.ioloop.IOLoop.current() - io_loop.spawn_callback(handle_connection, connection, address) - - if __name__ == '__main__': - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - sock.setblocking(0) - sock.bind(("", 8888)) - sock.listen(128) - - io_loop = tornado.ioloop.IOLoop.current() - callback = functools.partial(connection_ready, sock) - io_loop.add_handler(sock.fileno(), callback, io_loop.READ) - io_loop.start() - - .. testoutput:: - :hide: - - By default, a newly-constructed `IOLoop` becomes the thread's current - `IOLoop`, unless there already is a current `IOLoop`. This behavior - can be controlled with the ``make_current`` argument to the `IOLoop` - constructor: if ``make_current=True``, the new `IOLoop` will always - try to become current and it raises an error if there is already a - current instance. If ``make_current=False``, the new `IOLoop` will - not try to become current. - - In general, an `IOLoop` cannot survive a fork or be shared across - processes in any way. When multiple processes are being used, each - process should create its own `IOLoop`, which also implies that - any objects which depend on the `IOLoop` (such as - `.AsyncHTTPClient`) must also be created in the child processes. - As a guideline, anything that starts processes (including the - `tornado.process` and `multiprocessing` modules) should do so as - early as possible, ideally the first thing the application does - after loading its configuration in ``main()``. - - .. versionchanged:: 4.2 - Added the ``make_current`` keyword argument to the `IOLoop` - constructor. - - .. versionchanged:: 5.0 - - Uses the `asyncio` event loop by default. The - ``IOLoop.configure`` method cannot be used on Python 3 except - to redundantly specify the `asyncio` event loop. - - """ - - # These constants were originally based on constants from the epoll module. - NONE = 0 - READ = 0x001 - WRITE = 0x004 - ERROR = 0x018 - - # In Python 3, _ioloop_for_asyncio maps from asyncio loops to IOLoops. - _ioloop_for_asyncio = dict() # type: Dict[asyncio.AbstractEventLoop, IOLoop] - - @classmethod - def configure( - cls, impl: "Union[None, str, Type[Configurable]]", **kwargs: Any - ) -> None: - if asyncio is not None: - from tornado.platform.asyncio import BaseAsyncIOLoop - - if isinstance(impl, str): - impl = import_object(impl) - if isinstance(impl, type) and not issubclass(impl, BaseAsyncIOLoop): - raise RuntimeError( - "only AsyncIOLoop is allowed when asyncio is available" - ) - super(IOLoop, cls).configure(impl, **kwargs) - - @staticmethod - def instance() -> "IOLoop": - """Deprecated alias for `IOLoop.current()`. - - .. versionchanged:: 5.0 - - Previously, this method returned a global singleton - `IOLoop`, in contrast with the per-thread `IOLoop` returned - by `current()`. In nearly all cases the two were the same - (when they differed, it was generally used from non-Tornado - threads to communicate back to the main thread's `IOLoop`). - This distinction is not present in `asyncio`, so in order - to facilitate integration with that package `instance()` - was changed to be an alias to `current()`. Applications - using the cross-thread communications aspect of - `instance()` should instead set their own global variable - to point to the `IOLoop` they want to use. - - .. deprecated:: 5.0 - """ - return IOLoop.current() - - def install(self) -> None: - """Deprecated alias for `make_current()`. - - .. versionchanged:: 5.0 - - Previously, this method would set this `IOLoop` as the - global singleton used by `IOLoop.instance()`. Now that - `instance()` is an alias for `current()`, `install()` - is an alias for `make_current()`. - - .. deprecated:: 5.0 - """ - self.make_current() - - @staticmethod - def clear_instance() -> None: - """Deprecated alias for `clear_current()`. - - .. versionchanged:: 5.0 - - Previously, this method would clear the `IOLoop` used as - the global singleton by `IOLoop.instance()`. Now that - `instance()` is an alias for `current()`, - `clear_instance()` is an alias for `clear_current()`. - - .. deprecated:: 5.0 - - """ - IOLoop.clear_current() - - @typing.overload - @staticmethod - def current() -> "IOLoop": - pass - - @typing.overload - @staticmethod - def current(instance: bool = True) -> Optional["IOLoop"]: # noqa: F811 - pass - - @staticmethod - def current(instance: bool = True) -> Optional["IOLoop"]: # noqa: F811 - """Returns the current thread's `IOLoop`. - - If an `IOLoop` is currently running or has been marked as - current by `make_current`, returns that instance. If there is - no current `IOLoop` and ``instance`` is true, creates one. - - .. versionchanged:: 4.1 - Added ``instance`` argument to control the fallback to - `IOLoop.instance()`. - .. versionchanged:: 5.0 - On Python 3, control of the current `IOLoop` is delegated - to `asyncio`, with this and other methods as pass-through accessors. - The ``instance`` argument now controls whether an `IOLoop` - is created automatically when there is none, instead of - whether we fall back to `IOLoop.instance()` (which is now - an alias for this method). ``instance=False`` is deprecated, - since even if we do not create an `IOLoop`, this method - may initialize the asyncio loop. - """ - try: - loop = asyncio.get_event_loop() - except (RuntimeError, AssertionError): - if not instance: - return None - raise - try: - return IOLoop._ioloop_for_asyncio[loop] - except KeyError: - if instance: - from tornado.platform.asyncio import AsyncIOMainLoop - - current = AsyncIOMainLoop(make_current=True) # type: Optional[IOLoop] - else: - current = None - return current - - def make_current(self) -> None: - """Makes this the `IOLoop` for the current thread. - - An `IOLoop` automatically becomes current for its thread - when it is started, but it is sometimes useful to call - `make_current` explicitly before starting the `IOLoop`, - so that code run at startup time can find the right - instance. - - .. versionchanged:: 4.1 - An `IOLoop` created while there is no current `IOLoop` - will automatically become current. - - .. versionchanged:: 5.0 - This method also sets the current `asyncio` event loop. - """ - # The asyncio event loops override this method. - raise NotImplementedError() - - @staticmethod - def clear_current() -> None: - """Clears the `IOLoop` for the current thread. - - Intended primarily for use by test frameworks in between tests. - - .. versionchanged:: 5.0 - This method also clears the current `asyncio` event loop. - """ - old = IOLoop.current(instance=False) - if old is not None: - old._clear_current_hook() - if asyncio is None: - IOLoop._current.instance = None - - def _clear_current_hook(self) -> None: - """Instance method called when an IOLoop ceases to be current. - - May be overridden by subclasses as a counterpart to make_current. - """ - pass - - @classmethod - def configurable_base(cls) -> Type[Configurable]: - return IOLoop - - @classmethod - def configurable_default(cls) -> Type[Configurable]: - from tornado.platform.asyncio import AsyncIOLoop - - return AsyncIOLoop - - def initialize(self, make_current: Optional[bool] = None) -> None: - if make_current is None: - if IOLoop.current(instance=False) is None: - self.make_current() - elif make_current: - current = IOLoop.current(instance=False) - # AsyncIO loops can already be current by this point. - if current is not None and current is not self: - raise RuntimeError("current IOLoop already exists") - self.make_current() - - def close(self, all_fds: bool = False) -> None: - """Closes the `IOLoop`, freeing any resources used. - - If ``all_fds`` is true, all file descriptors registered on the - IOLoop will be closed (not just the ones created by the - `IOLoop` itself). - - Many applications will only use a single `IOLoop` that runs for the - entire lifetime of the process. In that case closing the `IOLoop` - is not necessary since everything will be cleaned up when the - process exits. `IOLoop.close` is provided mainly for scenarios - such as unit tests, which create and destroy a large number of - ``IOLoops``. - - An `IOLoop` must be completely stopped before it can be closed. This - means that `IOLoop.stop()` must be called *and* `IOLoop.start()` must - be allowed to return before attempting to call `IOLoop.close()`. - Therefore the call to `close` will usually appear just after - the call to `start` rather than near the call to `stop`. - - .. versionchanged:: 3.1 - If the `IOLoop` implementation supports non-integer objects - for "file descriptors", those objects will have their - ``close`` method when ``all_fds`` is true. - """ - raise NotImplementedError() - - @typing.overload - def add_handler( - self, fd: int, handler: Callable[[int, int], None], events: int - ) -> None: - pass - - @typing.overload # noqa: F811 - def add_handler( - self, fd: _S, handler: Callable[[_S, int], None], events: int - ) -> None: - pass - - def add_handler( # noqa: F811 - self, fd: Union[int, _Selectable], handler: Callable[..., None], events: int - ) -> None: - """Registers the given handler to receive the given events for ``fd``. - - The ``fd`` argument may either be an integer file descriptor or - a file-like object with a ``fileno()`` and ``close()`` method. - - The ``events`` argument is a bitwise or of the constants - ``IOLoop.READ``, ``IOLoop.WRITE``, and ``IOLoop.ERROR``. - - When an event occurs, ``handler(fd, events)`` will be run. - - .. versionchanged:: 4.0 - Added the ability to pass file-like objects in addition to - raw file descriptors. - """ - raise NotImplementedError() - - def update_handler(self, fd: Union[int, _Selectable], events: int) -> None: - """Changes the events we listen for ``fd``. - - .. versionchanged:: 4.0 - Added the ability to pass file-like objects in addition to - raw file descriptors. - """ - raise NotImplementedError() - - def remove_handler(self, fd: Union[int, _Selectable]) -> None: - """Stop listening for events on ``fd``. - - .. versionchanged:: 4.0 - Added the ability to pass file-like objects in addition to - raw file descriptors. - """ - raise NotImplementedError() - - def start(self) -> None: - """Starts the I/O loop. - - The loop will run until one of the callbacks calls `stop()`, which - will make the loop stop after the current event iteration completes. - """ - raise NotImplementedError() - - def _setup_logging(self) -> None: - """The IOLoop catches and logs exceptions, so it's - important that log output be visible. However, python's - default behavior for non-root loggers (prior to python - 3.2) is to print an unhelpful "no handlers could be - found" message rather than the actual log entry, so we - must explicitly configure logging if we've made it this - far without anything. - - This method should be called from start() in subclasses. - """ - if not any( - [ - logging.getLogger().handlers, - logging.getLogger("tornado").handlers, - logging.getLogger("tornado.application").handlers, - ] - ): - logging.basicConfig() - - def stop(self) -> None: - """Stop the I/O loop. - - If the event loop is not currently running, the next call to `start()` - will return immediately. - - Note that even after `stop` has been called, the `IOLoop` is not - completely stopped until `IOLoop.start` has also returned. - Some work that was scheduled before the call to `stop` may still - be run before the `IOLoop` shuts down. - """ - raise NotImplementedError() - - def run_sync(self, func: Callable, timeout: Optional[float] = None) -> Any: - """Starts the `IOLoop`, runs the given function, and stops the loop. - - The function must return either an awaitable object or - ``None``. If the function returns an awaitable object, the - `IOLoop` will run until the awaitable is resolved (and - `run_sync()` will return the awaitable's result). If it raises - an exception, the `IOLoop` will stop and the exception will be - re-raised to the caller. - - The keyword-only argument ``timeout`` may be used to set - a maximum duration for the function. If the timeout expires, - a `tornado.util.TimeoutError` is raised. - - This method is useful to allow asynchronous calls in a - ``main()`` function:: - - async def main(): - # do stuff... - - if __name__ == '__main__': - IOLoop.current().run_sync(main) - - .. versionchanged:: 4.3 - Returning a non-``None``, non-awaitable value is now an error. - - .. versionchanged:: 5.0 - If a timeout occurs, the ``func`` coroutine will be cancelled. - - """ - future_cell = [None] # type: List[Optional[Future]] - - def run() -> None: - try: - result = func() - if result is not None: - from tornado.gen import convert_yielded - - result = convert_yielded(result) - except Exception: - fut = Future() # type: Future[Any] - future_cell[0] = fut - future_set_exc_info(fut, sys.exc_info()) - else: - if is_future(result): - future_cell[0] = result - else: - fut = Future() - future_cell[0] = fut - fut.set_result(result) - assert future_cell[0] is not None - self.add_future(future_cell[0], lambda future: self.stop()) - - self.add_callback(run) - if timeout is not None: - - def timeout_callback() -> None: - # If we can cancel the future, do so and wait on it. If not, - # Just stop the loop and return with the task still pending. - # (If we neither cancel nor wait for the task, a warning - # will be logged). - assert future_cell[0] is not None - if not future_cell[0].cancel(): - self.stop() - - timeout_handle = self.add_timeout(self.time() + timeout, timeout_callback) - self.start() - if timeout is not None: - self.remove_timeout(timeout_handle) - assert future_cell[0] is not None - if future_cell[0].cancelled() or not future_cell[0].done(): - raise TimeoutError("Operation timed out after %s seconds" % timeout) - return future_cell[0].result() - - def time(self) -> float: - """Returns the current time according to the `IOLoop`'s clock. - - The return value is a floating-point number relative to an - unspecified time in the past. - - Historically, the IOLoop could be customized to use e.g. - `time.monotonic` instead of `time.time`, but this is not - currently supported and so this method is equivalent to - `time.time`. - - """ - return time.time() - - def add_timeout( - self, - deadline: Union[float, datetime.timedelta], - callback: Callable[..., None], - *args: Any, - **kwargs: Any - ) -> object: - """Runs the ``callback`` at the time ``deadline`` from the I/O loop. - - Returns an opaque handle that may be passed to - `remove_timeout` to cancel. - - ``deadline`` may be a number denoting a time (on the same - scale as `IOLoop.time`, normally `time.time`), or a - `datetime.timedelta` object for a deadline relative to the - current time. Since Tornado 4.0, `call_later` is a more - convenient alternative for the relative case since it does not - require a timedelta object. - - Note that it is not safe to call `add_timeout` from other threads. - Instead, you must use `add_callback` to transfer control to the - `IOLoop`'s thread, and then call `add_timeout` from there. - - Subclasses of IOLoop must implement either `add_timeout` or - `call_at`; the default implementations of each will call - the other. `call_at` is usually easier to implement, but - subclasses that wish to maintain compatibility with Tornado - versions prior to 4.0 must use `add_timeout` instead. - - .. versionchanged:: 4.0 - Now passes through ``*args`` and ``**kwargs`` to the callback. - """ - if isinstance(deadline, numbers.Real): - return self.call_at(deadline, callback, *args, **kwargs) - elif isinstance(deadline, datetime.timedelta): - return self.call_at( - self.time() + deadline.total_seconds(), callback, *args, **kwargs - ) - else: - raise TypeError("Unsupported deadline %r" % deadline) - - def call_later( - self, delay: float, callback: Callable[..., None], *args: Any, **kwargs: Any - ) -> object: - """Runs the ``callback`` after ``delay`` seconds have passed. - - Returns an opaque handle that may be passed to `remove_timeout` - to cancel. Note that unlike the `asyncio` method of the same - name, the returned object does not have a ``cancel()`` method. - - See `add_timeout` for comments on thread-safety and subclassing. - - .. versionadded:: 4.0 - """ - return self.call_at(self.time() + delay, callback, *args, **kwargs) - - def call_at( - self, when: float, callback: Callable[..., None], *args: Any, **kwargs: Any - ) -> object: - """Runs the ``callback`` at the absolute time designated by ``when``. - - ``when`` must be a number using the same reference point as - `IOLoop.time`. - - Returns an opaque handle that may be passed to `remove_timeout` - to cancel. Note that unlike the `asyncio` method of the same - name, the returned object does not have a ``cancel()`` method. - - See `add_timeout` for comments on thread-safety and subclassing. - - .. versionadded:: 4.0 - """ - return self.add_timeout(when, callback, *args, **kwargs) - - def remove_timeout(self, timeout: object) -> None: - """Cancels a pending timeout. - - The argument is a handle as returned by `add_timeout`. It is - safe to call `remove_timeout` even if the callback has already - been run. - """ - raise NotImplementedError() - - def add_callback(self, callback: Callable, *args: Any, **kwargs: Any) -> None: - """Calls the given callback on the next I/O loop iteration. - - It is safe to call this method from any thread at any time, - except from a signal handler. Note that this is the **only** - method in `IOLoop` that makes this thread-safety guarantee; all - other interaction with the `IOLoop` must be done from that - `IOLoop`'s thread. `add_callback()` may be used to transfer - control from other threads to the `IOLoop`'s thread. - - To add a callback from a signal handler, see - `add_callback_from_signal`. - """ - raise NotImplementedError() - - def add_callback_from_signal( - self, callback: Callable, *args: Any, **kwargs: Any - ) -> None: - """Calls the given callback on the next I/O loop iteration. - - Safe for use from a Python signal handler; should not be used - otherwise. - """ - raise NotImplementedError() - - def spawn_callback(self, callback: Callable, *args: Any, **kwargs: Any) -> None: - """Calls the given callback on the next IOLoop iteration. - - As of Tornado 6.0, this method is equivalent to `add_callback`. - - .. versionadded:: 4.0 - """ - self.add_callback(callback, *args, **kwargs) - - def add_future( - self, - future: "Union[Future[_T], concurrent.futures.Future[_T]]", - callback: Callable[["Future[_T]"], None], - ) -> None: - """Schedules a callback on the ``IOLoop`` when the given - `.Future` is finished. - - The callback is invoked with one argument, the - `.Future`. - - This method only accepts `.Future` objects and not other - awaitables (unlike most of Tornado where the two are - interchangeable). - """ - if isinstance(future, Future): - # Note that we specifically do not want the inline behavior of - # tornado.concurrent.future_add_done_callback. We always want - # this callback scheduled on the next IOLoop iteration (which - # asyncio.Future always does). - # - # Wrap the callback in self._run_callback so we control - # the error logging (i.e. it goes to tornado.log.app_log - # instead of asyncio's log). - future.add_done_callback( - lambda f: self._run_callback(functools.partial(callback, future)) - ) - else: - assert is_future(future) - # For concurrent futures, we use self.add_callback, so - # it's fine if future_add_done_callback inlines that call. - future_add_done_callback( - future, lambda f: self.add_callback(callback, future) - ) - - def run_in_executor( - self, - executor: Optional[concurrent.futures.Executor], - func: Callable[..., _T], - *args: Any - ) -> Awaitable[_T]: - """Runs a function in a ``concurrent.futures.Executor``. If - ``executor`` is ``None``, the IO loop's default executor will be used. - - Use `functools.partial` to pass keyword arguments to ``func``. - - .. versionadded:: 5.0 - """ - if executor is None: - if not hasattr(self, "_executor"): - from tornado.process import cpu_count - - self._executor = concurrent.futures.ThreadPoolExecutor( - max_workers=(cpu_count() * 5) - ) # type: concurrent.futures.Executor - executor = self._executor - c_future = executor.submit(func, *args) - # Concurrent Futures are not usable with await. Wrap this in a - # Tornado Future instead, using self.add_future for thread-safety. - t_future = Future() # type: Future[_T] - self.add_future(c_future, lambda f: chain_future(f, t_future)) - return t_future - - def set_default_executor(self, executor: concurrent.futures.Executor) -> None: - """Sets the default executor to use with :meth:`run_in_executor`. - - .. versionadded:: 5.0 - """ - self._executor = executor - - def _run_callback(self, callback: Callable[[], Any]) -> None: - """Runs a callback with error handling. - - .. versionchanged:: 6.0 - - CancelledErrors are no longer logged. - """ - try: - ret = callback() - if ret is not None: - from tornado import gen - - # Functions that return Futures typically swallow all - # exceptions and store them in the Future. If a Future - # makes it out to the IOLoop, ensure its exception (if any) - # gets logged too. - try: - ret = gen.convert_yielded(ret) - except gen.BadYieldError: - # It's not unusual for add_callback to be used with - # methods returning a non-None and non-yieldable - # result, which should just be ignored. - pass - else: - self.add_future(ret, self._discard_future_result) - except asyncio.CancelledError: - pass - except Exception: - app_log.error("Exception in callback %r", callback, exc_info=True) - - def _discard_future_result(self, future: Future) -> None: - """Avoid unhandled-exception warnings from spawned coroutines.""" - future.result() - - def split_fd( - self, fd: Union[int, _Selectable] - ) -> Tuple[int, Union[int, _Selectable]]: - # """Returns an (fd, obj) pair from an ``fd`` parameter. - - # We accept both raw file descriptors and file-like objects as - # input to `add_handler` and related methods. When a file-like - # object is passed, we must retain the object itself so we can - # close it correctly when the `IOLoop` shuts down, but the - # poller interfaces favor file descriptors (they will accept - # file-like objects and call ``fileno()`` for you, but they - # always return the descriptor itself). - - # This method is provided for use by `IOLoop` subclasses and should - # not generally be used by application code. - - # .. versionadded:: 4.0 - # """ - if isinstance(fd, int): - return fd, fd - return fd.fileno(), fd - - def close_fd(self, fd: Union[int, _Selectable]) -> None: - # """Utility method to close an ``fd``. - - # If ``fd`` is a file-like object, we close it directly; otherwise - # we use `os.close`. - - # This method is provided for use by `IOLoop` subclasses (in - # implementations of ``IOLoop.close(all_fds=True)`` and should - # not generally be used by application code. - - # .. versionadded:: 4.0 - # """ - try: - if isinstance(fd, int): - os.close(fd) - else: - fd.close() - except OSError: - pass - - -class _Timeout(object): - """An IOLoop timeout, a UNIX timestamp and a callback""" - - # Reduce memory overhead when there are lots of pending callbacks - __slots__ = ["deadline", "callback", "tdeadline"] - - def __init__( - self, deadline: float, callback: Callable[[], None], io_loop: IOLoop - ) -> None: - if not isinstance(deadline, numbers.Real): - raise TypeError("Unsupported deadline %r" % deadline) - self.deadline = deadline - self.callback = callback - self.tdeadline = ( - deadline, - next(io_loop._timeout_counter), - ) # type: Tuple[float, int] - - # Comparison methods to sort by deadline, with object id as a tiebreaker - # to guarantee a consistent ordering. The heapq module uses __le__ - # in python2.5, and __lt__ in 2.6+ (sort() and most other comparisons - # use __lt__). - def __lt__(self, other: "_Timeout") -> bool: - return self.tdeadline < other.tdeadline - - def __le__(self, other: "_Timeout") -> bool: - return self.tdeadline <= other.tdeadline - - -class PeriodicCallback(object): - """Schedules the given callback to be called periodically. - - The callback is called every ``callback_time`` milliseconds. - Note that the timeout is given in milliseconds, while most other - time-related functions in Tornado use seconds. - - If ``jitter`` is specified, each callback time will be randomly selected - within a window of ``jitter * callback_time`` milliseconds. - Jitter can be used to reduce alignment of events with similar periods. - A jitter of 0.1 means allowing a 10% variation in callback time. - The window is centered on ``callback_time`` so the total number of calls - within a given interval should not be significantly affected by adding - jitter. - - If the callback runs for longer than ``callback_time`` milliseconds, - subsequent invocations will be skipped to get back on schedule. - - `start` must be called after the `PeriodicCallback` is created. - - .. versionchanged:: 5.0 - The ``io_loop`` argument (deprecated since version 4.1) has been removed. - - .. versionchanged:: 5.1 - The ``jitter`` argument is added. - """ - - def __init__( - self, callback: Callable[[], None], callback_time: float, jitter: float = 0 - ) -> None: - self.callback = callback - if callback_time <= 0: - raise ValueError("Periodic callback must have a positive callback_time") - self.callback_time = callback_time - self.jitter = jitter - self._running = False - self._timeout = None # type: object - - def start(self) -> None: - """Starts the timer.""" - # Looking up the IOLoop here allows to first instantiate the - # PeriodicCallback in another thread, then start it using - # IOLoop.add_callback(). - self.io_loop = IOLoop.current() - self._running = True - self._next_timeout = self.io_loop.time() - self._schedule_next() - - def stop(self) -> None: - """Stops the timer.""" - self._running = False - if self._timeout is not None: - self.io_loop.remove_timeout(self._timeout) - self._timeout = None - - def is_running(self) -> bool: - """Returns ``True`` if this `.PeriodicCallback` has been started. - - .. versionadded:: 4.1 - """ - return self._running - - def _run(self) -> None: - if not self._running: - return - try: - return self.callback() - except Exception: - app_log.error("Exception in callback %r", self.callback, exc_info=True) - finally: - self._schedule_next() - - def _schedule_next(self) -> None: - if self._running: - self._update_next(self.io_loop.time()) - self._timeout = self.io_loop.add_timeout(self._next_timeout, self._run) - - def _update_next(self, current_time: float) -> None: - callback_time_sec = self.callback_time / 1000.0 - if self.jitter: - # apply jitter fraction - callback_time_sec *= 1 + (self.jitter * (random.random() - 0.5)) - if self._next_timeout <= current_time: - # The period should be measured from the start of one call - # to the start of the next. If one call takes too long, - # skip cycles to get back to a multiple of the original - # schedule. - self._next_timeout += ( - math.floor((current_time - self._next_timeout) / callback_time_sec) + 1 - ) * callback_time_sec - else: - # If the clock moved backwards, ensure we advance the next - # timeout instead of recomputing the same value again. - # This may result in long gaps between callbacks if the - # clock jumps backwards by a lot, but the far more common - # scenario is a small NTP adjustment that should just be - # ignored. - # - # Note that on some systems if time.time() runs slower - # than time.monotonic() (most common on windows), we - # effectively experience a small backwards time jump on - # every iteration because PeriodicCallback uses - # time.time() while asyncio schedules callbacks using - # time.monotonic(). - # https://github.com/tornadoweb/tornado/issues/2333 - self._next_timeout += callback_time_sec diff --git a/venv/lib/python3.8/site-packages/tornado/iostream.py b/venv/lib/python3.8/site-packages/tornado/iostream.py deleted file mode 100644 index 19c5485..0000000 --- a/venv/lib/python3.8/site-packages/tornado/iostream.py +++ /dev/null @@ -1,1660 +0,0 @@ -# -# Copyright 2009 Facebook -# -# 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. - -"""Utility classes to write to and read from non-blocking files and sockets. - -Contents: - -* `BaseIOStream`: Generic interface for reading and writing. -* `IOStream`: Implementation of BaseIOStream using non-blocking sockets. -* `SSLIOStream`: SSL-aware version of IOStream. -* `PipeIOStream`: Pipe-based IOStream implementation. -""" - -import asyncio -import collections -import errno -import io -import numbers -import os -import socket -import ssl -import sys -import re - -from tornado.concurrent import Future, future_set_result_unless_cancelled -from tornado import ioloop -from tornado.log import gen_log -from tornado.netutil import ssl_wrap_socket, _client_ssl_defaults, _server_ssl_defaults -from tornado.util import errno_from_exception - -import typing -from typing import ( - Union, - Optional, - Awaitable, - Callable, - Pattern, - Any, - Dict, - TypeVar, - Tuple, -) -from types import TracebackType - -if typing.TYPE_CHECKING: - from typing import Deque, List, Type # noqa: F401 - -_IOStreamType = TypeVar("_IOStreamType", bound="IOStream") - -# These errnos indicate that a connection has been abruptly terminated. -# They should be caught and handled less noisily than other errors. -_ERRNO_CONNRESET = (errno.ECONNRESET, errno.ECONNABORTED, errno.EPIPE, errno.ETIMEDOUT) - -if hasattr(errno, "WSAECONNRESET"): - _ERRNO_CONNRESET += ( # type: ignore - errno.WSAECONNRESET, # type: ignore - errno.WSAECONNABORTED, # type: ignore - errno.WSAETIMEDOUT, # type: ignore - ) - -if sys.platform == "darwin": - # OSX appears to have a race condition that causes send(2) to return - # EPROTOTYPE if called while a socket is being torn down: - # http://erickt.github.io/blog/2014/11/19/adventures-in-debugging-a-potential-osx-kernel-bug/ - # Since the socket is being closed anyway, treat this as an ECONNRESET - # instead of an unexpected error. - _ERRNO_CONNRESET += (errno.EPROTOTYPE,) # type: ignore - -_WINDOWS = sys.platform.startswith("win") - - -class StreamClosedError(IOError): - """Exception raised by `IOStream` methods when the stream is closed. - - Note that the close callback is scheduled to run *after* other - callbacks on the stream (to allow for buffered data to be processed), - so you may see this error before you see the close callback. - - The ``real_error`` attribute contains the underlying error that caused - the stream to close (if any). - - .. versionchanged:: 4.3 - Added the ``real_error`` attribute. - """ - - def __init__(self, real_error: Optional[BaseException] = None) -> None: - super().__init__("Stream is closed") - self.real_error = real_error - - -class UnsatisfiableReadError(Exception): - """Exception raised when a read cannot be satisfied. - - Raised by ``read_until`` and ``read_until_regex`` with a ``max_bytes`` - argument. - """ - - pass - - -class StreamBufferFullError(Exception): - """Exception raised by `IOStream` methods when the buffer is full. - """ - - -class _StreamBuffer(object): - """ - A specialized buffer that tries to avoid copies when large pieces - of data are encountered. - """ - - def __init__(self) -> None: - # A sequence of (False, bytearray) and (True, memoryview) objects - self._buffers = ( - collections.deque() - ) # type: Deque[Tuple[bool, Union[bytearray, memoryview]]] - # Position in the first buffer - self._first_pos = 0 - self._size = 0 - - def __len__(self) -> int: - return self._size - - # Data above this size will be appended separately instead - # of extending an existing bytearray - _large_buf_threshold = 2048 - - def append(self, data: Union[bytes, bytearray, memoryview]) -> None: - """ - Append the given piece of data (should be a buffer-compatible object). - """ - size = len(data) - if size > self._large_buf_threshold: - if not isinstance(data, memoryview): - data = memoryview(data) - self._buffers.append((True, data)) - elif size > 0: - if self._buffers: - is_memview, b = self._buffers[-1] - new_buf = is_memview or len(b) >= self._large_buf_threshold - else: - new_buf = True - if new_buf: - self._buffers.append((False, bytearray(data))) - else: - b += data # type: ignore - - self._size += size - - def peek(self, size: int) -> memoryview: - """ - Get a view over at most ``size`` bytes (possibly fewer) at the - current buffer position. - """ - assert size > 0 - try: - is_memview, b = self._buffers[0] - except IndexError: - return memoryview(b"") - - pos = self._first_pos - if is_memview: - return typing.cast(memoryview, b[pos : pos + size]) - else: - return memoryview(b)[pos : pos + size] - - def advance(self, size: int) -> None: - """ - Advance the current buffer position by ``size`` bytes. - """ - assert 0 < size <= self._size - self._size -= size - pos = self._first_pos - - buffers = self._buffers - while buffers and size > 0: - is_large, b = buffers[0] - b_remain = len(b) - size - pos - if b_remain <= 0: - buffers.popleft() - size -= len(b) - pos - pos = 0 - elif is_large: - pos += size - size = 0 - else: - # Amortized O(1) shrink for Python 2 - pos += size - if len(b) <= 2 * pos: - del typing.cast(bytearray, b)[:pos] - pos = 0 - size = 0 - - assert size == 0 - self._first_pos = pos - - -class BaseIOStream(object): - """A utility class to write to and read from a non-blocking file or socket. - - We support a non-blocking ``write()`` and a family of ``read_*()`` - methods. When the operation completes, the ``Awaitable`` will resolve - with the data read (or ``None`` for ``write()``). All outstanding - ``Awaitables`` will resolve with a `StreamClosedError` when the - stream is closed; `.BaseIOStream.set_close_callback` can also be used - to be notified of a closed stream. - - When a stream is closed due to an error, the IOStream's ``error`` - attribute contains the exception object. - - Subclasses must implement `fileno`, `close_fd`, `write_to_fd`, - `read_from_fd`, and optionally `get_fd_error`. - - """ - - def __init__( - self, - max_buffer_size: Optional[int] = None, - read_chunk_size: Optional[int] = None, - max_write_buffer_size: Optional[int] = None, - ) -> None: - """`BaseIOStream` constructor. - - :arg max_buffer_size: Maximum amount of incoming data to buffer; - defaults to 100MB. - :arg read_chunk_size: Amount of data to read at one time from the - underlying transport; defaults to 64KB. - :arg max_write_buffer_size: Amount of outgoing data to buffer; - defaults to unlimited. - - .. versionchanged:: 4.0 - Add the ``max_write_buffer_size`` parameter. Changed default - ``read_chunk_size`` to 64KB. - .. versionchanged:: 5.0 - The ``io_loop`` argument (deprecated since version 4.1) has been - removed. - """ - self.io_loop = ioloop.IOLoop.current() - self.max_buffer_size = max_buffer_size or 104857600 - # A chunk size that is too close to max_buffer_size can cause - # spurious failures. - self.read_chunk_size = min(read_chunk_size or 65536, self.max_buffer_size // 2) - self.max_write_buffer_size = max_write_buffer_size - self.error = None # type: Optional[BaseException] - self._read_buffer = bytearray() - self._read_buffer_pos = 0 - self._read_buffer_size = 0 - self._user_read_buffer = False - self._after_user_read_buffer = None # type: Optional[bytearray] - self._write_buffer = _StreamBuffer() - self._total_write_index = 0 - self._total_write_done_index = 0 - self._read_delimiter = None # type: Optional[bytes] - self._read_regex = None # type: Optional[Pattern] - self._read_max_bytes = None # type: Optional[int] - self._read_bytes = None # type: Optional[int] - self._read_partial = False - self._read_until_close = False - self._read_future = None # type: Optional[Future] - self._write_futures = ( - collections.deque() - ) # type: Deque[Tuple[int, Future[None]]] - self._close_callback = None # type: Optional[Callable[[], None]] - self._connect_future = None # type: Optional[Future[IOStream]] - # _ssl_connect_future should be defined in SSLIOStream - # but it's here so we can clean it up in _signal_closed - # TODO: refactor that so subclasses can add additional futures - # to be cancelled. - self._ssl_connect_future = None # type: Optional[Future[SSLIOStream]] - self._connecting = False - self._state = None # type: Optional[int] - self._closed = False - - def fileno(self) -> Union[int, ioloop._Selectable]: - """Returns the file descriptor for this stream.""" - raise NotImplementedError() - - def close_fd(self) -> None: - """Closes the file underlying this stream. - - ``close_fd`` is called by `BaseIOStream` and should not be called - elsewhere; other users should call `close` instead. - """ - raise NotImplementedError() - - def write_to_fd(self, data: memoryview) -> int: - """Attempts to write ``data`` to the underlying file. - - Returns the number of bytes written. - """ - raise NotImplementedError() - - def read_from_fd(self, buf: Union[bytearray, memoryview]) -> Optional[int]: - """Attempts to read from the underlying file. - - Reads up to ``len(buf)`` bytes, storing them in the buffer. - Returns the number of bytes read. Returns None if there was - nothing to read (the socket returned `~errno.EWOULDBLOCK` or - equivalent), and zero on EOF. - - .. versionchanged:: 5.0 - - Interface redesigned to take a buffer and return a number - of bytes instead of a freshly-allocated object. - """ - raise NotImplementedError() - - def get_fd_error(self) -> Optional[Exception]: - """Returns information about any error on the underlying file. - - This method is called after the `.IOLoop` has signaled an error on the - file descriptor, and should return an Exception (such as `socket.error` - with additional information, or None if no such information is - available. - """ - return None - - def read_until_regex( - self, regex: bytes, max_bytes: Optional[int] = None - ) -> Awaitable[bytes]: - """Asynchronously read until we have matched the given regex. - - The result includes the data that matches the regex and anything - that came before it. - - If ``max_bytes`` is not None, the connection will be closed - if more than ``max_bytes`` bytes have been read and the regex is - not satisfied. - - .. versionchanged:: 4.0 - Added the ``max_bytes`` argument. The ``callback`` argument is - now optional and a `.Future` will be returned if it is omitted. - - .. versionchanged:: 6.0 - - The ``callback`` argument was removed. Use the returned - `.Future` instead. - - """ - future = self._start_read() - self._read_regex = re.compile(regex) - self._read_max_bytes = max_bytes - try: - self._try_inline_read() - except UnsatisfiableReadError as e: - # Handle this the same way as in _handle_events. - gen_log.info("Unsatisfiable read, closing connection: %s" % e) - self.close(exc_info=e) - return future - except: - # Ensure that the future doesn't log an error because its - # failure was never examined. - future.add_done_callback(lambda f: f.exception()) - raise - return future - - def read_until( - self, delimiter: bytes, max_bytes: Optional[int] = None - ) -> Awaitable[bytes]: - """Asynchronously read until we have found the given delimiter. - - The result includes all the data read including the delimiter. - - If ``max_bytes`` is not None, the connection will be closed - if more than ``max_bytes`` bytes have been read and the delimiter - is not found. - - .. versionchanged:: 4.0 - Added the ``max_bytes`` argument. The ``callback`` argument is - now optional and a `.Future` will be returned if it is omitted. - - .. versionchanged:: 6.0 - - The ``callback`` argument was removed. Use the returned - `.Future` instead. - """ - future = self._start_read() - self._read_delimiter = delimiter - self._read_max_bytes = max_bytes - try: - self._try_inline_read() - except UnsatisfiableReadError as e: - # Handle this the same way as in _handle_events. - gen_log.info("Unsatisfiable read, closing connection: %s" % e) - self.close(exc_info=e) - return future - except: - future.add_done_callback(lambda f: f.exception()) - raise - return future - - def read_bytes(self, num_bytes: int, partial: bool = False) -> Awaitable[bytes]: - """Asynchronously read a number of bytes. - - If ``partial`` is true, data is returned as soon as we have - any bytes to return (but never more than ``num_bytes``) - - .. versionchanged:: 4.0 - Added the ``partial`` argument. The callback argument is now - optional and a `.Future` will be returned if it is omitted. - - .. versionchanged:: 6.0 - - The ``callback`` and ``streaming_callback`` arguments have - been removed. Use the returned `.Future` (and - ``partial=True`` for ``streaming_callback``) instead. - - """ - future = self._start_read() - assert isinstance(num_bytes, numbers.Integral) - self._read_bytes = num_bytes - self._read_partial = partial - try: - self._try_inline_read() - except: - future.add_done_callback(lambda f: f.exception()) - raise - return future - - def read_into(self, buf: bytearray, partial: bool = False) -> Awaitable[int]: - """Asynchronously read a number of bytes. - - ``buf`` must be a writable buffer into which data will be read. - - If ``partial`` is true, the callback is run as soon as any bytes - have been read. Otherwise, it is run when the ``buf`` has been - entirely filled with read data. - - .. versionadded:: 5.0 - - .. versionchanged:: 6.0 - - The ``callback`` argument was removed. Use the returned - `.Future` instead. - - """ - future = self._start_read() - - # First copy data already in read buffer - available_bytes = self._read_buffer_size - n = len(buf) - if available_bytes >= n: - end = self._read_buffer_pos + n - buf[:] = memoryview(self._read_buffer)[self._read_buffer_pos : end] - del self._read_buffer[:end] - self._after_user_read_buffer = self._read_buffer - elif available_bytes > 0: - buf[:available_bytes] = memoryview(self._read_buffer)[ - self._read_buffer_pos : - ] - - # Set up the supplied buffer as our temporary read buffer. - # The original (if it had any data remaining) has been - # saved for later. - self._user_read_buffer = True - self._read_buffer = buf - self._read_buffer_pos = 0 - self._read_buffer_size = available_bytes - self._read_bytes = n - self._read_partial = partial - - try: - self._try_inline_read() - except: - future.add_done_callback(lambda f: f.exception()) - raise - return future - - def read_until_close(self) -> Awaitable[bytes]: - """Asynchronously reads all data from the socket until it is closed. - - This will buffer all available data until ``max_buffer_size`` - is reached. If flow control or cancellation are desired, use a - loop with `read_bytes(partial=True) <.read_bytes>` instead. - - .. versionchanged:: 4.0 - The callback argument is now optional and a `.Future` will - be returned if it is omitted. - - .. versionchanged:: 6.0 - - The ``callback`` and ``streaming_callback`` arguments have - been removed. Use the returned `.Future` (and `read_bytes` - with ``partial=True`` for ``streaming_callback``) instead. - - """ - future = self._start_read() - if self.closed(): - self._finish_read(self._read_buffer_size, False) - return future - self._read_until_close = True - try: - self._try_inline_read() - except: - future.add_done_callback(lambda f: f.exception()) - raise - return future - - def write(self, data: Union[bytes, memoryview]) -> "Future[None]": - """Asynchronously write the given data to this stream. - - This method returns a `.Future` that resolves (with a result - of ``None``) when the write has been completed. - - The ``data`` argument may be of type `bytes` or `memoryview`. - - .. versionchanged:: 4.0 - Now returns a `.Future` if no callback is given. - - .. versionchanged:: 4.5 - Added support for `memoryview` arguments. - - .. versionchanged:: 6.0 - - The ``callback`` argument was removed. Use the returned - `.Future` instead. - - """ - self._check_closed() - if data: - if ( - self.max_write_buffer_size is not None - and len(self._write_buffer) + len(data) > self.max_write_buffer_size - ): - raise StreamBufferFullError("Reached maximum write buffer size") - self._write_buffer.append(data) - self._total_write_index += len(data) - future = Future() # type: Future[None] - future.add_done_callback(lambda f: f.exception()) - self._write_futures.append((self._total_write_index, future)) - if not self._connecting: - self._handle_write() - if self._write_buffer: - self._add_io_state(self.io_loop.WRITE) - self._maybe_add_error_listener() - return future - - def set_close_callback(self, callback: Optional[Callable[[], None]]) -> None: - """Call the given callback when the stream is closed. - - This mostly is not necessary for applications that use the - `.Future` interface; all outstanding ``Futures`` will resolve - with a `StreamClosedError` when the stream is closed. However, - it is still useful as a way to signal that the stream has been - closed while no other read or write is in progress. - - Unlike other callback-based interfaces, ``set_close_callback`` - was not removed in Tornado 6.0. - """ - self._close_callback = callback - self._maybe_add_error_listener() - - def close( - self, - exc_info: Union[ - None, - bool, - BaseException, - Tuple[ - "Optional[Type[BaseException]]", - Optional[BaseException], - Optional[TracebackType], - ], - ] = False, - ) -> None: - """Close this stream. - - If ``exc_info`` is true, set the ``error`` attribute to the current - exception from `sys.exc_info` (or if ``exc_info`` is a tuple, - use that instead of `sys.exc_info`). - """ - if not self.closed(): - if exc_info: - if isinstance(exc_info, tuple): - self.error = exc_info[1] - elif isinstance(exc_info, BaseException): - self.error = exc_info - else: - exc_info = sys.exc_info() - if any(exc_info): - self.error = exc_info[1] - if self._read_until_close: - self._read_until_close = False - self._finish_read(self._read_buffer_size, False) - elif self._read_future is not None: - # resolve reads that are pending and ready to complete - try: - pos = self._find_read_pos() - except UnsatisfiableReadError: - pass - else: - if pos is not None: - self._read_from_buffer(pos) - if self._state is not None: - self.io_loop.remove_handler(self.fileno()) - self._state = None - self.close_fd() - self._closed = True - self._signal_closed() - - def _signal_closed(self) -> None: - futures = [] # type: List[Future] - if self._read_future is not None: - futures.append(self._read_future) - self._read_future = None - futures += [future for _, future in self._write_futures] - self._write_futures.clear() - if self._connect_future is not None: - futures.append(self._connect_future) - self._connect_future = None - for future in futures: - if not future.done(): - future.set_exception(StreamClosedError(real_error=self.error)) - # Reference the exception to silence warnings. Annoyingly, - # this raises if the future was cancelled, but just - # returns any other error. - try: - future.exception() - except asyncio.CancelledError: - pass - if self._ssl_connect_future is not None: - # _ssl_connect_future expects to see the real exception (typically - # an ssl.SSLError), not just StreamClosedError. - if not self._ssl_connect_future.done(): - if self.error is not None: - self._ssl_connect_future.set_exception(self.error) - else: - self._ssl_connect_future.set_exception(StreamClosedError()) - self._ssl_connect_future.exception() - self._ssl_connect_future = None - if self._close_callback is not None: - cb = self._close_callback - self._close_callback = None - self.io_loop.add_callback(cb) - # Clear the buffers so they can be cleared immediately even - # if the IOStream object is kept alive by a reference cycle. - # TODO: Clear the read buffer too; it currently breaks some tests. - self._write_buffer = None # type: ignore - - def reading(self) -> bool: - """Returns ``True`` if we are currently reading from the stream.""" - return self._read_future is not None - - def writing(self) -> bool: - """Returns ``True`` if we are currently writing to the stream.""" - return bool(self._write_buffer) - - def closed(self) -> bool: - """Returns ``True`` if the stream has been closed.""" - return self._closed - - def set_nodelay(self, value: bool) -> None: - """Sets the no-delay flag for this stream. - - By default, data written to TCP streams may be held for a time - to make the most efficient use of bandwidth (according to - Nagle's algorithm). The no-delay flag requests that data be - written as soon as possible, even if doing so would consume - additional bandwidth. - - This flag is currently defined only for TCP-based ``IOStreams``. - - .. versionadded:: 3.1 - """ - pass - - def _handle_connect(self) -> None: - raise NotImplementedError() - - def _handle_events(self, fd: Union[int, ioloop._Selectable], events: int) -> None: - if self.closed(): - gen_log.warning("Got events for closed stream %s", fd) - return - try: - if self._connecting: - # Most IOLoops will report a write failed connect - # with the WRITE event, but SelectIOLoop reports a - # READ as well so we must check for connecting before - # either. - self._handle_connect() - if self.closed(): - return - if events & self.io_loop.READ: - self._handle_read() - if self.closed(): - return - if events & self.io_loop.WRITE: - self._handle_write() - if self.closed(): - return - if events & self.io_loop.ERROR: - self.error = self.get_fd_error() - # We may have queued up a user callback in _handle_read or - # _handle_write, so don't close the IOStream until those - # callbacks have had a chance to run. - self.io_loop.add_callback(self.close) - return - state = self.io_loop.ERROR - if self.reading(): - state |= self.io_loop.READ - if self.writing(): - state |= self.io_loop.WRITE - if state == self.io_loop.ERROR and self._read_buffer_size == 0: - # If the connection is idle, listen for reads too so - # we can tell if the connection is closed. If there is - # data in the read buffer we won't run the close callback - # yet anyway, so we don't need to listen in this case. - state |= self.io_loop.READ - if state != self._state: - assert ( - self._state is not None - ), "shouldn't happen: _handle_events without self._state" - self._state = state - self.io_loop.update_handler(self.fileno(), self._state) - except UnsatisfiableReadError as e: - gen_log.info("Unsatisfiable read, closing connection: %s" % e) - self.close(exc_info=e) - except Exception as e: - gen_log.error("Uncaught exception, closing connection.", exc_info=True) - self.close(exc_info=e) - raise - - def _read_to_buffer_loop(self) -> Optional[int]: - # This method is called from _handle_read and _try_inline_read. - if self._read_bytes is not None: - target_bytes = self._read_bytes # type: Optional[int] - elif self._read_max_bytes is not None: - target_bytes = self._read_max_bytes - elif self.reading(): - # For read_until without max_bytes, or - # read_until_close, read as much as we can before - # scanning for the delimiter. - target_bytes = None - else: - target_bytes = 0 - next_find_pos = 0 - while not self.closed(): - # Read from the socket until we get EWOULDBLOCK or equivalent. - # SSL sockets do some internal buffering, and if the data is - # sitting in the SSL object's buffer select() and friends - # can't see it; the only way to find out if it's there is to - # try to read it. - if self._read_to_buffer() == 0: - break - - # If we've read all the bytes we can use, break out of - # this loop. - - # If we've reached target_bytes, we know we're done. - if target_bytes is not None and self._read_buffer_size >= target_bytes: - break - - # Otherwise, we need to call the more expensive find_read_pos. - # It's inefficient to do this on every read, so instead - # do it on the first read and whenever the read buffer - # size has doubled. - if self._read_buffer_size >= next_find_pos: - pos = self._find_read_pos() - if pos is not None: - return pos - next_find_pos = self._read_buffer_size * 2 - return self._find_read_pos() - - def _handle_read(self) -> None: - try: - pos = self._read_to_buffer_loop() - except UnsatisfiableReadError: - raise - except asyncio.CancelledError: - raise - except Exception as e: - gen_log.warning("error on read: %s" % e) - self.close(exc_info=e) - return - if pos is not None: - self._read_from_buffer(pos) - - def _start_read(self) -> Future: - if self._read_future is not None: - # It is an error to start a read while a prior read is unresolved. - # However, if the prior read is unresolved because the stream was - # closed without satisfying it, it's better to raise - # StreamClosedError instead of AssertionError. In particular, this - # situation occurs in harmless situations in http1connection.py and - # an AssertionError would be logged noisily. - # - # On the other hand, it is legal to start a new read while the - # stream is closed, in case the read can be satisfied from the - # read buffer. So we only want to check the closed status of the - # stream if we need to decide what kind of error to raise for - # "already reading". - # - # These conditions have proven difficult to test; we have no - # unittests that reliably verify this behavior so be careful - # when making changes here. See #2651 and #2719. - self._check_closed() - assert self._read_future is None, "Already reading" - self._read_future = Future() - return self._read_future - - def _finish_read(self, size: int, streaming: bool) -> None: - if self._user_read_buffer: - self._read_buffer = self._after_user_read_buffer or bytearray() - self._after_user_read_buffer = None - self._read_buffer_pos = 0 - self._read_buffer_size = len(self._read_buffer) - self._user_read_buffer = False - result = size # type: Union[int, bytes] - else: - result = self._consume(size) - if self._read_future is not None: - future = self._read_future - self._read_future = None - future_set_result_unless_cancelled(future, result) - self._maybe_add_error_listener() - - def _try_inline_read(self) -> None: - """Attempt to complete the current read operation from buffered data. - - If the read can be completed without blocking, schedules the - read callback on the next IOLoop iteration; otherwise starts - listening for reads on the socket. - """ - # See if we've already got the data from a previous read - pos = self._find_read_pos() - if pos is not None: - self._read_from_buffer(pos) - return - self._check_closed() - pos = self._read_to_buffer_loop() - if pos is not None: - self._read_from_buffer(pos) - return - # We couldn't satisfy the read inline, so make sure we're - # listening for new data unless the stream is closed. - if not self.closed(): - self._add_io_state(ioloop.IOLoop.READ) - - def _read_to_buffer(self) -> Optional[int]: - """Reads from the socket and appends the result to the read buffer. - - Returns the number of bytes read. Returns 0 if there is nothing - to read (i.e. the read returns EWOULDBLOCK or equivalent). On - error closes the socket and raises an exception. - """ - try: - while True: - try: - if self._user_read_buffer: - buf = memoryview(self._read_buffer)[ - self._read_buffer_size : - ] # type: Union[memoryview, bytearray] - else: - buf = bytearray(self.read_chunk_size) - bytes_read = self.read_from_fd(buf) - except (socket.error, IOError, OSError) as e: - # ssl.SSLError is a subclass of socket.error - if self._is_connreset(e): - # Treat ECONNRESET as a connection close rather than - # an error to minimize log spam (the exception will - # be available on self.error for apps that care). - self.close(exc_info=e) - return None - self.close(exc_info=e) - raise - break - if bytes_read is None: - return 0 - elif bytes_read == 0: - self.close() - return 0 - if not self._user_read_buffer: - self._read_buffer += memoryview(buf)[:bytes_read] - self._read_buffer_size += bytes_read - finally: - # Break the reference to buf so we don't waste a chunk's worth of - # memory in case an exception hangs on to our stack frame. - del buf - if self._read_buffer_size > self.max_buffer_size: - gen_log.error("Reached maximum read buffer size") - self.close() - raise StreamBufferFullError("Reached maximum read buffer size") - return bytes_read - - def _read_from_buffer(self, pos: int) -> None: - """Attempts to complete the currently-pending read from the buffer. - - The argument is either a position in the read buffer or None, - as returned by _find_read_pos. - """ - self._read_bytes = self._read_delimiter = self._read_regex = None - self._read_partial = False - self._finish_read(pos, False) - - def _find_read_pos(self) -> Optional[int]: - """Attempts to find a position in the read buffer that satisfies - the currently-pending read. - - Returns a position in the buffer if the current read can be satisfied, - or None if it cannot. - """ - if self._read_bytes is not None and ( - self._read_buffer_size >= self._read_bytes - or (self._read_partial and self._read_buffer_size > 0) - ): - num_bytes = min(self._read_bytes, self._read_buffer_size) - return num_bytes - elif self._read_delimiter is not None: - # Multi-byte delimiters (e.g. '\r\n') may straddle two - # chunks in the read buffer, so we can't easily find them - # without collapsing the buffer. However, since protocols - # using delimited reads (as opposed to reads of a known - # length) tend to be "line" oriented, the delimiter is likely - # to be in the first few chunks. Merge the buffer gradually - # since large merges are relatively expensive and get undone in - # _consume(). - if self._read_buffer: - loc = self._read_buffer.find( - self._read_delimiter, self._read_buffer_pos - ) - if loc != -1: - loc -= self._read_buffer_pos - delimiter_len = len(self._read_delimiter) - self._check_max_bytes(self._read_delimiter, loc + delimiter_len) - return loc + delimiter_len - self._check_max_bytes(self._read_delimiter, self._read_buffer_size) - elif self._read_regex is not None: - if self._read_buffer: - m = self._read_regex.search(self._read_buffer, self._read_buffer_pos) - if m is not None: - loc = m.end() - self._read_buffer_pos - self._check_max_bytes(self._read_regex, loc) - return loc - self._check_max_bytes(self._read_regex, self._read_buffer_size) - return None - - def _check_max_bytes(self, delimiter: Union[bytes, Pattern], size: int) -> None: - if self._read_max_bytes is not None and size > self._read_max_bytes: - raise UnsatisfiableReadError( - "delimiter %r not found within %d bytes" - % (delimiter, self._read_max_bytes) - ) - - def _handle_write(self) -> None: - while True: - size = len(self._write_buffer) - if not size: - break - assert size > 0 - try: - if _WINDOWS: - # On windows, socket.send blows up if given a - # write buffer that's too large, instead of just - # returning the number of bytes it was able to - # process. Therefore we must not call socket.send - # with more than 128KB at a time. - size = 128 * 1024 - - num_bytes = self.write_to_fd(self._write_buffer.peek(size)) - if num_bytes == 0: - break - self._write_buffer.advance(num_bytes) - self._total_write_done_index += num_bytes - except BlockingIOError: - break - except (socket.error, IOError, OSError) as e: - if not self._is_connreset(e): - # Broken pipe errors are usually caused by connection - # reset, and its better to not log EPIPE errors to - # minimize log spam - gen_log.warning("Write error on %s: %s", self.fileno(), e) - self.close(exc_info=e) - return - - while self._write_futures: - index, future = self._write_futures[0] - if index > self._total_write_done_index: - break - self._write_futures.popleft() - future_set_result_unless_cancelled(future, None) - - def _consume(self, loc: int) -> bytes: - # Consume loc bytes from the read buffer and return them - if loc == 0: - return b"" - assert loc <= self._read_buffer_size - # Slice the bytearray buffer into bytes, without intermediate copying - b = ( - memoryview(self._read_buffer)[ - self._read_buffer_pos : self._read_buffer_pos + loc - ] - ).tobytes() - self._read_buffer_pos += loc - self._read_buffer_size -= loc - # Amortized O(1) shrink - # (this heuristic is implemented natively in Python 3.4+ - # but is replicated here for Python 2) - if self._read_buffer_pos > self._read_buffer_size: - del self._read_buffer[: self._read_buffer_pos] - self._read_buffer_pos = 0 - return b - - def _check_closed(self) -> None: - if self.closed(): - raise StreamClosedError(real_error=self.error) - - def _maybe_add_error_listener(self) -> None: - # This method is part of an optimization: to detect a connection that - # is closed when we're not actively reading or writing, we must listen - # for read events. However, it is inefficient to do this when the - # connection is first established because we are going to read or write - # immediately anyway. Instead, we insert checks at various times to - # see if the connection is idle and add the read listener then. - if self._state is None or self._state == ioloop.IOLoop.ERROR: - if ( - not self.closed() - and self._read_buffer_size == 0 - and self._close_callback is not None - ): - self._add_io_state(ioloop.IOLoop.READ) - - def _add_io_state(self, state: int) -> None: - """Adds `state` (IOLoop.{READ,WRITE} flags) to our event handler. - - Implementation notes: Reads and writes have a fast path and a - slow path. The fast path reads synchronously from socket - buffers, while the slow path uses `_add_io_state` to schedule - an IOLoop callback. - - To detect closed connections, we must have called - `_add_io_state` at some point, but we want to delay this as - much as possible so we don't have to set an `IOLoop.ERROR` - listener that will be overwritten by the next slow-path - operation. If a sequence of fast-path ops do not end in a - slow-path op, (e.g. for an @asynchronous long-poll request), - we must add the error handler. - - TODO: reevaluate this now that callbacks are gone. - - """ - if self.closed(): - # connection has been closed, so there can be no future events - return - if self._state is None: - self._state = ioloop.IOLoop.ERROR | state - self.io_loop.add_handler(self.fileno(), self._handle_events, self._state) - elif not self._state & state: - self._state = self._state | state - self.io_loop.update_handler(self.fileno(), self._state) - - def _is_connreset(self, exc: BaseException) -> bool: - """Return ``True`` if exc is ECONNRESET or equivalent. - - May be overridden in subclasses. - """ - return ( - isinstance(exc, (socket.error, IOError)) - and errno_from_exception(exc) in _ERRNO_CONNRESET - ) - - -class IOStream(BaseIOStream): - r"""Socket-based `IOStream` implementation. - - This class supports the read and write methods from `BaseIOStream` - plus a `connect` method. - - The ``socket`` parameter may either be connected or unconnected. - For server operations the socket is the result of calling - `socket.accept <socket.socket.accept>`. For client operations the - socket is created with `socket.socket`, and may either be - connected before passing it to the `IOStream` or connected with - `IOStream.connect`. - - A very simple (and broken) HTTP client using this class: - - .. testcode:: - - import tornado.ioloop - import tornado.iostream - import socket - - async def main(): - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) - stream = tornado.iostream.IOStream(s) - await stream.connect(("friendfeed.com", 80)) - await stream.write(b"GET / HTTP/1.0\r\nHost: friendfeed.com\r\n\r\n") - header_data = await stream.read_until(b"\r\n\r\n") - headers = {} - for line in header_data.split(b"\r\n"): - parts = line.split(b":") - if len(parts) == 2: - headers[parts[0].strip()] = parts[1].strip() - body_data = await stream.read_bytes(int(headers[b"Content-Length"])) - print(body_data) - stream.close() - - if __name__ == '__main__': - tornado.ioloop.IOLoop.current().run_sync(main) - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) - stream = tornado.iostream.IOStream(s) - stream.connect(("friendfeed.com", 80), send_request) - tornado.ioloop.IOLoop.current().start() - - .. testoutput:: - :hide: - - """ - - def __init__(self, socket: socket.socket, *args: Any, **kwargs: Any) -> None: - self.socket = socket - self.socket.setblocking(False) - super().__init__(*args, **kwargs) - - def fileno(self) -> Union[int, ioloop._Selectable]: - return self.socket - - def close_fd(self) -> None: - self.socket.close() - self.socket = None # type: ignore - - def get_fd_error(self) -> Optional[Exception]: - errno = self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR) - return socket.error(errno, os.strerror(errno)) - - def read_from_fd(self, buf: Union[bytearray, memoryview]) -> Optional[int]: - try: - return self.socket.recv_into(buf, len(buf)) - except BlockingIOError: - return None - finally: - del buf - - def write_to_fd(self, data: memoryview) -> int: - try: - return self.socket.send(data) # type: ignore - finally: - # Avoid keeping to data, which can be a memoryview. - # See https://github.com/tornadoweb/tornado/pull/2008 - del data - - def connect( - self: _IOStreamType, address: Any, server_hostname: Optional[str] = None - ) -> "Future[_IOStreamType]": - """Connects the socket to a remote address without blocking. - - May only be called if the socket passed to the constructor was - not previously connected. The address parameter is in the - same format as for `socket.connect <socket.socket.connect>` for - the type of socket passed to the IOStream constructor, - e.g. an ``(ip, port)`` tuple. Hostnames are accepted here, - but will be resolved synchronously and block the IOLoop. - If you have a hostname instead of an IP address, the `.TCPClient` - class is recommended instead of calling this method directly. - `.TCPClient` will do asynchronous DNS resolution and handle - both IPv4 and IPv6. - - If ``callback`` is specified, it will be called with no - arguments when the connection is completed; if not this method - returns a `.Future` (whose result after a successful - connection will be the stream itself). - - In SSL mode, the ``server_hostname`` parameter will be used - for certificate validation (unless disabled in the - ``ssl_options``) and SNI (if supported; requires Python - 2.7.9+). - - Note that it is safe to call `IOStream.write - <BaseIOStream.write>` while the connection is pending, in - which case the data will be written as soon as the connection - is ready. Calling `IOStream` read methods before the socket is - connected works on some platforms but is non-portable. - - .. versionchanged:: 4.0 - If no callback is given, returns a `.Future`. - - .. versionchanged:: 4.2 - SSL certificates are validated by default; pass - ``ssl_options=dict(cert_reqs=ssl.CERT_NONE)`` or a - suitably-configured `ssl.SSLContext` to the - `SSLIOStream` constructor to disable. - - .. versionchanged:: 6.0 - - The ``callback`` argument was removed. Use the returned - `.Future` instead. - - """ - self._connecting = True - future = Future() # type: Future[_IOStreamType] - self._connect_future = typing.cast("Future[IOStream]", future) - try: - self.socket.connect(address) - except BlockingIOError: - # In non-blocking mode we expect connect() to raise an - # exception with EINPROGRESS or EWOULDBLOCK. - pass - except socket.error as e: - # On freebsd, other errors such as ECONNREFUSED may be - # returned immediately when attempting to connect to - # localhost, so handle them the same way as an error - # reported later in _handle_connect. - if future is None: - gen_log.warning("Connect error on fd %s: %s", self.socket.fileno(), e) - self.close(exc_info=e) - return future - self._add_io_state(self.io_loop.WRITE) - return future - - def start_tls( - self, - server_side: bool, - ssl_options: Optional[Union[Dict[str, Any], ssl.SSLContext]] = None, - server_hostname: Optional[str] = None, - ) -> Awaitable["SSLIOStream"]: - """Convert this `IOStream` to an `SSLIOStream`. - - This enables protocols that begin in clear-text mode and - switch to SSL after some initial negotiation (such as the - ``STARTTLS`` extension to SMTP and IMAP). - - This method cannot be used if there are outstanding reads - or writes on the stream, or if there is any data in the - IOStream's buffer (data in the operating system's socket - buffer is allowed). This means it must generally be used - immediately after reading or writing the last clear-text - data. It can also be used immediately after connecting, - before any reads or writes. - - The ``ssl_options`` argument may be either an `ssl.SSLContext` - object or a dictionary of keyword arguments for the - `ssl.wrap_socket` function. The ``server_hostname`` argument - will be used for certificate validation unless disabled - in the ``ssl_options``. - - This method returns a `.Future` whose result is the new - `SSLIOStream`. After this method has been called, - any other operation on the original stream is undefined. - - If a close callback is defined on this stream, it will be - transferred to the new stream. - - .. versionadded:: 4.0 - - .. versionchanged:: 4.2 - SSL certificates are validated by default; pass - ``ssl_options=dict(cert_reqs=ssl.CERT_NONE)`` or a - suitably-configured `ssl.SSLContext` to disable. - """ - if ( - self._read_future - or self._write_futures - or self._connect_future - or self._closed - or self._read_buffer - or self._write_buffer - ): - raise ValueError("IOStream is not idle; cannot convert to SSL") - if ssl_options is None: - if server_side: - ssl_options = _server_ssl_defaults - else: - ssl_options = _client_ssl_defaults - - socket = self.socket - self.io_loop.remove_handler(socket) - self.socket = None # type: ignore - socket = ssl_wrap_socket( - socket, - ssl_options, - server_hostname=server_hostname, - server_side=server_side, - do_handshake_on_connect=False, - ) - orig_close_callback = self._close_callback - self._close_callback = None - - future = Future() # type: Future[SSLIOStream] - ssl_stream = SSLIOStream(socket, ssl_options=ssl_options) - ssl_stream.set_close_callback(orig_close_callback) - ssl_stream._ssl_connect_future = future - ssl_stream.max_buffer_size = self.max_buffer_size - ssl_stream.read_chunk_size = self.read_chunk_size - return future - - def _handle_connect(self) -> None: - try: - err = self.socket.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR) - except socket.error as e: - # Hurd doesn't allow SO_ERROR for loopback sockets because all - # errors for such sockets are reported synchronously. - if errno_from_exception(e) == errno.ENOPROTOOPT: - err = 0 - if err != 0: - self.error = socket.error(err, os.strerror(err)) - # IOLoop implementations may vary: some of them return - # an error state before the socket becomes writable, so - # in that case a connection failure would be handled by the - # error path in _handle_events instead of here. - if self._connect_future is None: - gen_log.warning( - "Connect error on fd %s: %s", - self.socket.fileno(), - errno.errorcode[err], - ) - self.close() - return - if self._connect_future is not None: - future = self._connect_future - self._connect_future = None - future_set_result_unless_cancelled(future, self) - self._connecting = False - - def set_nodelay(self, value: bool) -> None: - if self.socket is not None and self.socket.family in ( - socket.AF_INET, - socket.AF_INET6, - ): - try: - self.socket.setsockopt( - socket.IPPROTO_TCP, socket.TCP_NODELAY, 1 if value else 0 - ) - except socket.error as e: - # Sometimes setsockopt will fail if the socket is closed - # at the wrong time. This can happen with HTTPServer - # resetting the value to ``False`` between requests. - if e.errno != errno.EINVAL and not self._is_connreset(e): - raise - - -class SSLIOStream(IOStream): - """A utility class to write to and read from a non-blocking SSL socket. - - If the socket passed to the constructor is already connected, - it should be wrapped with:: - - ssl.wrap_socket(sock, do_handshake_on_connect=False, **kwargs) - - before constructing the `SSLIOStream`. Unconnected sockets will be - wrapped when `IOStream.connect` is finished. - """ - - socket = None # type: ssl.SSLSocket - - def __init__(self, *args: Any, **kwargs: Any) -> None: - """The ``ssl_options`` keyword argument may either be an - `ssl.SSLContext` object or a dictionary of keywords arguments - for `ssl.wrap_socket` - """ - self._ssl_options = kwargs.pop("ssl_options", _client_ssl_defaults) - super().__init__(*args, **kwargs) - self._ssl_accepting = True - self._handshake_reading = False - self._handshake_writing = False - self._server_hostname = None # type: Optional[str] - - # If the socket is already connected, attempt to start the handshake. - try: - self.socket.getpeername() - except socket.error: - pass - else: - # Indirectly start the handshake, which will run on the next - # IOLoop iteration and then the real IO state will be set in - # _handle_events. - self._add_io_state(self.io_loop.WRITE) - - def reading(self) -> bool: - return self._handshake_reading or super().reading() - - def writing(self) -> bool: - return self._handshake_writing or super().writing() - - def _do_ssl_handshake(self) -> None: - # Based on code from test_ssl.py in the python stdlib - try: - self._handshake_reading = False - self._handshake_writing = False - self.socket.do_handshake() - except ssl.SSLError as err: - if err.args[0] == ssl.SSL_ERROR_WANT_READ: - self._handshake_reading = True - return - elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE: - self._handshake_writing = True - return - elif err.args[0] in (ssl.SSL_ERROR_EOF, ssl.SSL_ERROR_ZERO_RETURN): - return self.close(exc_info=err) - elif err.args[0] == ssl.SSL_ERROR_SSL: - try: - peer = self.socket.getpeername() - except Exception: - peer = "(not connected)" - gen_log.warning( - "SSL Error on %s %s: %s", self.socket.fileno(), peer, err - ) - return self.close(exc_info=err) - raise - except ssl.CertificateError as err: - # CertificateError can happen during handshake (hostname - # verification) and should be passed to user. Starting - # in Python 3.7, this error is a subclass of SSLError - # and will be handled by the previous block instead. - return self.close(exc_info=err) - except socket.error as err: - # Some port scans (e.g. nmap in -sT mode) have been known - # to cause do_handshake to raise EBADF and ENOTCONN, so make - # those errors quiet as well. - # https://groups.google.com/forum/?fromgroups#!topic/python-tornado/ApucKJat1_0 - # Errno 0 is also possible in some cases (nc -z). - # https://github.com/tornadoweb/tornado/issues/2504 - if self._is_connreset(err) or err.args[0] in ( - 0, - errno.EBADF, - errno.ENOTCONN, - ): - return self.close(exc_info=err) - raise - except AttributeError as err: - # On Linux, if the connection was reset before the call to - # wrap_socket, do_handshake will fail with an - # AttributeError. - return self.close(exc_info=err) - else: - self._ssl_accepting = False - if not self._verify_cert(self.socket.getpeercert()): - self.close() - return - self._finish_ssl_connect() - - def _finish_ssl_connect(self) -> None: - if self._ssl_connect_future is not None: - future = self._ssl_connect_future - self._ssl_connect_future = None - future_set_result_unless_cancelled(future, self) - - def _verify_cert(self, peercert: Any) -> bool: - """Returns ``True`` if peercert is valid according to the configured - validation mode and hostname. - - The ssl handshake already tested the certificate for a valid - CA signature; the only thing that remains is to check - the hostname. - """ - if isinstance(self._ssl_options, dict): - verify_mode = self._ssl_options.get("cert_reqs", ssl.CERT_NONE) - elif isinstance(self._ssl_options, ssl.SSLContext): - verify_mode = self._ssl_options.verify_mode - assert verify_mode in (ssl.CERT_NONE, ssl.CERT_REQUIRED, ssl.CERT_OPTIONAL) - if verify_mode == ssl.CERT_NONE or self._server_hostname is None: - return True - cert = self.socket.getpeercert() - if cert is None and verify_mode == ssl.CERT_REQUIRED: - gen_log.warning("No SSL certificate given") - return False - try: - ssl.match_hostname(peercert, self._server_hostname) - except ssl.CertificateError as e: - gen_log.warning("Invalid SSL certificate: %s" % e) - return False - else: - return True - - def _handle_read(self) -> None: - if self._ssl_accepting: - self._do_ssl_handshake() - return - super()._handle_read() - - def _handle_write(self) -> None: - if self._ssl_accepting: - self._do_ssl_handshake() - return - super()._handle_write() - - def connect( - self, address: Tuple, server_hostname: Optional[str] = None - ) -> "Future[SSLIOStream]": - self._server_hostname = server_hostname - # Ignore the result of connect(). If it fails, - # wait_for_handshake will raise an error too. This is - # necessary for the old semantics of the connect callback - # (which takes no arguments). In 6.0 this can be refactored to - # be a regular coroutine. - # TODO: This is trickier than it looks, since if write() - # is called with a connect() pending, we want the connect - # to resolve before the write. Or do we care about this? - # (There's a test for it, but I think in practice users - # either wait for the connect before performing a write or - # they don't care about the connect Future at all) - fut = super().connect(address) - fut.add_done_callback(lambda f: f.exception()) - return self.wait_for_handshake() - - def _handle_connect(self) -> None: - # Call the superclass method to check for errors. - super()._handle_connect() - if self.closed(): - return - # When the connection is complete, wrap the socket for SSL - # traffic. Note that we do this by overriding _handle_connect - # instead of by passing a callback to super().connect because - # user callbacks are enqueued asynchronously on the IOLoop, - # but since _handle_events calls _handle_connect immediately - # followed by _handle_write we need this to be synchronous. - # - # The IOLoop will get confused if we swap out self.socket while the - # fd is registered, so remove it now and re-register after - # wrap_socket(). - self.io_loop.remove_handler(self.socket) - old_state = self._state - assert old_state is not None - self._state = None - self.socket = ssl_wrap_socket( - self.socket, - self._ssl_options, - server_hostname=self._server_hostname, - do_handshake_on_connect=False, - ) - self._add_io_state(old_state) - - def wait_for_handshake(self) -> "Future[SSLIOStream]": - """Wait for the initial SSL handshake to complete. - - If a ``callback`` is given, it will be called with no - arguments once the handshake is complete; otherwise this - method returns a `.Future` which will resolve to the - stream itself after the handshake is complete. - - Once the handshake is complete, information such as - the peer's certificate and NPN/ALPN selections may be - accessed on ``self.socket``. - - This method is intended for use on server-side streams - or after using `IOStream.start_tls`; it should not be used - with `IOStream.connect` (which already waits for the - handshake to complete). It may only be called once per stream. - - .. versionadded:: 4.2 - - .. versionchanged:: 6.0 - - The ``callback`` argument was removed. Use the returned - `.Future` instead. - - """ - if self._ssl_connect_future is not None: - raise RuntimeError("Already waiting") - future = self._ssl_connect_future = Future() - if not self._ssl_accepting: - self._finish_ssl_connect() - return future - - def write_to_fd(self, data: memoryview) -> int: - try: - return self.socket.send(data) # type: ignore - except ssl.SSLError as e: - if e.args[0] == ssl.SSL_ERROR_WANT_WRITE: - # In Python 3.5+, SSLSocket.send raises a WANT_WRITE error if - # the socket is not writeable; we need to transform this into - # an EWOULDBLOCK socket.error or a zero return value, - # either of which will be recognized by the caller of this - # method. Prior to Python 3.5, an unwriteable socket would - # simply return 0 bytes written. - return 0 - raise - finally: - # Avoid keeping to data, which can be a memoryview. - # See https://github.com/tornadoweb/tornado/pull/2008 - del data - - def read_from_fd(self, buf: Union[bytearray, memoryview]) -> Optional[int]: - try: - if self._ssl_accepting: - # If the handshake hasn't finished yet, there can't be anything - # to read (attempting to read may or may not raise an exception - # depending on the SSL version) - return None - try: - return self.socket.recv_into(buf, len(buf)) - except ssl.SSLError as e: - # SSLError is a subclass of socket.error, so this except - # block must come first. - if e.args[0] == ssl.SSL_ERROR_WANT_READ: - return None - else: - raise - except BlockingIOError: - return None - finally: - del buf - - def _is_connreset(self, e: BaseException) -> bool: - if isinstance(e, ssl.SSLError) and e.args[0] == ssl.SSL_ERROR_EOF: - return True - return super()._is_connreset(e) - - -class PipeIOStream(BaseIOStream): - """Pipe-based `IOStream` implementation. - - The constructor takes an integer file descriptor (such as one returned - by `os.pipe`) rather than an open file object. Pipes are generally - one-way, so a `PipeIOStream` can be used for reading or writing but not - both. - - ``PipeIOStream`` is only available on Unix-based platforms. - """ - - def __init__(self, fd: int, *args: Any, **kwargs: Any) -> None: - self.fd = fd - self._fio = io.FileIO(self.fd, "r+") - os.set_blocking(fd, False) - super().__init__(*args, **kwargs) - - def fileno(self) -> int: - return self.fd - - def close_fd(self) -> None: - self._fio.close() - - def write_to_fd(self, data: memoryview) -> int: - try: - return os.write(self.fd, data) # type: ignore - finally: - # Avoid keeping to data, which can be a memoryview. - # See https://github.com/tornadoweb/tornado/pull/2008 - del data - - def read_from_fd(self, buf: Union[bytearray, memoryview]) -> Optional[int]: - try: - return self._fio.readinto(buf) # type: ignore - except (IOError, OSError) as e: - if errno_from_exception(e) == errno.EBADF: - # If the writing half of a pipe is closed, select will - # report it as readable but reads will fail with EBADF. - self.close(exc_info=e) - return None - else: - raise - finally: - del buf - - -def doctests() -> Any: - import doctest - - return doctest.DocTestSuite() diff --git a/venv/lib/python3.8/site-packages/tornado/locale.py b/venv/lib/python3.8/site-packages/tornado/locale.py deleted file mode 100644 index adb1f77..0000000 --- a/venv/lib/python3.8/site-packages/tornado/locale.py +++ /dev/null @@ -1,581 +0,0 @@ -# Copyright 2009 Facebook -# -# 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. - -"""Translation methods for generating localized strings. - -To load a locale and generate a translated string:: - - user_locale = tornado.locale.get("es_LA") - print(user_locale.translate("Sign out")) - -`tornado.locale.get()` returns the closest matching locale, not necessarily the -specific locale you requested. You can support pluralization with -additional arguments to `~Locale.translate()`, e.g.:: - - people = [...] - message = user_locale.translate( - "%(list)s is online", "%(list)s are online", len(people)) - print(message % {"list": user_locale.list(people)}) - -The first string is chosen if ``len(people) == 1``, otherwise the second -string is chosen. - -Applications should call one of `load_translations` (which uses a simple -CSV format) or `load_gettext_translations` (which uses the ``.mo`` format -supported by `gettext` and related tools). If neither method is called, -the `Locale.translate` method will simply return the original string. -""" - -import codecs -import csv -import datetime -import gettext -import os -import re - -from tornado import escape -from tornado.log import gen_log - -from tornado._locale_data import LOCALE_NAMES - -from typing import Iterable, Any, Union, Dict, Optional - -_default_locale = "en_US" -_translations = {} # type: Dict[str, Any] -_supported_locales = frozenset([_default_locale]) -_use_gettext = False -CONTEXT_SEPARATOR = "\x04" - - -def get(*locale_codes: str) -> "Locale": - """Returns the closest match for the given locale codes. - - We iterate over all given locale codes in order. If we have a tight - or a loose match for the code (e.g., "en" for "en_US"), we return - the locale. Otherwise we move to the next code in the list. - - By default we return ``en_US`` if no translations are found for any of - the specified locales. You can change the default locale with - `set_default_locale()`. - """ - return Locale.get_closest(*locale_codes) - - -def set_default_locale(code: str) -> None: - """Sets the default locale. - - The default locale is assumed to be the language used for all strings - in the system. The translations loaded from disk are mappings from - the default locale to the destination locale. Consequently, you don't - need to create a translation file for the default locale. - """ - global _default_locale - global _supported_locales - _default_locale = code - _supported_locales = frozenset(list(_translations.keys()) + [_default_locale]) - - -def load_translations(directory: str, encoding: Optional[str] = None) -> None: - """Loads translations from CSV files in a directory. - - Translations are strings with optional Python-style named placeholders - (e.g., ``My name is %(name)s``) and their associated translations. - - The directory should have translation files of the form ``LOCALE.csv``, - e.g. ``es_GT.csv``. The CSV files should have two or three columns: string, - translation, and an optional plural indicator. Plural indicators should - be one of "plural" or "singular". A given string can have both singular - and plural forms. For example ``%(name)s liked this`` may have a - different verb conjugation depending on whether %(name)s is one - name or a list of names. There should be two rows in the CSV file for - that string, one with plural indicator "singular", and one "plural". - For strings with no verbs that would change on translation, simply - use "unknown" or the empty string (or don't include the column at all). - - The file is read using the `csv` module in the default "excel" dialect. - In this format there should not be spaces after the commas. - - If no ``encoding`` parameter is given, the encoding will be - detected automatically (among UTF-8 and UTF-16) if the file - contains a byte-order marker (BOM), defaulting to UTF-8 if no BOM - is present. - - Example translation ``es_LA.csv``:: - - "I love you","Te amo" - "%(name)s liked this","A %(name)s les gustó esto","plural" - "%(name)s liked this","A %(name)s le gustó esto","singular" - - .. versionchanged:: 4.3 - Added ``encoding`` parameter. Added support for BOM-based encoding - detection, UTF-16, and UTF-8-with-BOM. - """ - global _translations - global _supported_locales - _translations = {} - for path in os.listdir(directory): - if not path.endswith(".csv"): - continue - locale, extension = path.split(".") - if not re.match("[a-z]+(_[A-Z]+)?$", locale): - gen_log.error( - "Unrecognized locale %r (path: %s)", - locale, - os.path.join(directory, path), - ) - continue - full_path = os.path.join(directory, path) - if encoding is None: - # Try to autodetect encoding based on the BOM. - with open(full_path, "rb") as bf: - data = bf.read(len(codecs.BOM_UTF16_LE)) - if data in (codecs.BOM_UTF16_LE, codecs.BOM_UTF16_BE): - encoding = "utf-16" - else: - # utf-8-sig is "utf-8 with optional BOM". It's discouraged - # in most cases but is common with CSV files because Excel - # cannot read utf-8 files without a BOM. - encoding = "utf-8-sig" - # python 3: csv.reader requires a file open in text mode. - # Specify an encoding to avoid dependence on $LANG environment variable. - with open(full_path, encoding=encoding) as f: - _translations[locale] = {} - for i, row in enumerate(csv.reader(f)): - if not row or len(row) < 2: - continue - row = [escape.to_unicode(c).strip() for c in row] - english, translation = row[:2] - if len(row) > 2: - plural = row[2] or "unknown" - else: - plural = "unknown" - if plural not in ("plural", "singular", "unknown"): - gen_log.error( - "Unrecognized plural indicator %r in %s line %d", - plural, - path, - i + 1, - ) - continue - _translations[locale].setdefault(plural, {})[english] = translation - _supported_locales = frozenset(list(_translations.keys()) + [_default_locale]) - gen_log.debug("Supported locales: %s", sorted(_supported_locales)) - - -def load_gettext_translations(directory: str, domain: str) -> None: - """Loads translations from `gettext`'s locale tree - - Locale tree is similar to system's ``/usr/share/locale``, like:: - - {directory}/{lang}/LC_MESSAGES/{domain}.mo - - Three steps are required to have your app translated: - - 1. Generate POT translation file:: - - xgettext --language=Python --keyword=_:1,2 -d mydomain file1.py file2.html etc - - 2. Merge against existing POT file:: - - msgmerge old.po mydomain.po > new.po - - 3. Compile:: - - msgfmt mydomain.po -o {directory}/pt_BR/LC_MESSAGES/mydomain.mo - """ - global _translations - global _supported_locales - global _use_gettext - _translations = {} - for lang in os.listdir(directory): - if lang.startswith("."): - continue # skip .svn, etc - if os.path.isfile(os.path.join(directory, lang)): - continue - try: - os.stat(os.path.join(directory, lang, "LC_MESSAGES", domain + ".mo")) - _translations[lang] = gettext.translation( - domain, directory, languages=[lang] - ) - except Exception as e: - gen_log.error("Cannot load translation for '%s': %s", lang, str(e)) - continue - _supported_locales = frozenset(list(_translations.keys()) + [_default_locale]) - _use_gettext = True - gen_log.debug("Supported locales: %s", sorted(_supported_locales)) - - -def get_supported_locales() -> Iterable[str]: - """Returns a list of all the supported locale codes.""" - return _supported_locales - - -class Locale(object): - """Object representing a locale. - - After calling one of `load_translations` or `load_gettext_translations`, - call `get` or `get_closest` to get a Locale object. - """ - - _cache = {} # type: Dict[str, Locale] - - @classmethod - def get_closest(cls, *locale_codes: str) -> "Locale": - """Returns the closest match for the given locale code.""" - for code in locale_codes: - if not code: - continue - code = code.replace("-", "_") - parts = code.split("_") - if len(parts) > 2: - continue - elif len(parts) == 2: - code = parts[0].lower() + "_" + parts[1].upper() - if code in _supported_locales: - return cls.get(code) - if parts[0].lower() in _supported_locales: - return cls.get(parts[0].lower()) - return cls.get(_default_locale) - - @classmethod - def get(cls, code: str) -> "Locale": - """Returns the Locale for the given locale code. - - If it is not supported, we raise an exception. - """ - if code not in cls._cache: - assert code in _supported_locales - translations = _translations.get(code, None) - if translations is None: - locale = CSVLocale(code, {}) # type: Locale - elif _use_gettext: - locale = GettextLocale(code, translations) - else: - locale = CSVLocale(code, translations) - cls._cache[code] = locale - return cls._cache[code] - - def __init__(self, code: str) -> None: - self.code = code - self.name = LOCALE_NAMES.get(code, {}).get("name", u"Unknown") - self.rtl = False - for prefix in ["fa", "ar", "he"]: - if self.code.startswith(prefix): - self.rtl = True - break - - # Initialize strings for date formatting - _ = self.translate - self._months = [ - _("January"), - _("February"), - _("March"), - _("April"), - _("May"), - _("June"), - _("July"), - _("August"), - _("September"), - _("October"), - _("November"), - _("December"), - ] - self._weekdays = [ - _("Monday"), - _("Tuesday"), - _("Wednesday"), - _("Thursday"), - _("Friday"), - _("Saturday"), - _("Sunday"), - ] - - def translate( - self, - message: str, - plural_message: Optional[str] = None, - count: Optional[int] = None, - ) -> str: - """Returns the translation for the given message for this locale. - - If ``plural_message`` is given, you must also provide - ``count``. We return ``plural_message`` when ``count != 1``, - and we return the singular form for the given message when - ``count == 1``. - """ - raise NotImplementedError() - - def pgettext( - self, - context: str, - message: str, - plural_message: Optional[str] = None, - count: Optional[int] = None, - ) -> str: - raise NotImplementedError() - - def format_date( - self, - date: Union[int, float, datetime.datetime], - gmt_offset: int = 0, - relative: bool = True, - shorter: bool = False, - full_format: bool = False, - ) -> str: - """Formats the given date (which should be GMT). - - By default, we return a relative time (e.g., "2 minutes ago"). You - can return an absolute date string with ``relative=False``. - - You can force a full format date ("July 10, 1980") with - ``full_format=True``. - - This method is primarily intended for dates in the past. - For dates in the future, we fall back to full format. - """ - if isinstance(date, (int, float)): - date = datetime.datetime.utcfromtimestamp(date) - now = datetime.datetime.utcnow() - if date > now: - if relative and (date - now).seconds < 60: - # Due to click skew, things are some things slightly - # in the future. Round timestamps in the immediate - # future down to now in relative mode. - date = now - else: - # Otherwise, future dates always use the full format. - full_format = True - local_date = date - datetime.timedelta(minutes=gmt_offset) - local_now = now - datetime.timedelta(minutes=gmt_offset) - local_yesterday = local_now - datetime.timedelta(hours=24) - difference = now - date - seconds = difference.seconds - days = difference.days - - _ = self.translate - format = None - if not full_format: - if relative and days == 0: - if seconds < 50: - return _("1 second ago", "%(seconds)d seconds ago", seconds) % { - "seconds": seconds - } - - if seconds < 50 * 60: - minutes = round(seconds / 60.0) - return _("1 minute ago", "%(minutes)d minutes ago", minutes) % { - "minutes": minutes - } - - hours = round(seconds / (60.0 * 60)) - return _("1 hour ago", "%(hours)d hours ago", hours) % {"hours": hours} - - if days == 0: - format = _("%(time)s") - elif days == 1 and local_date.day == local_yesterday.day and relative: - format = _("yesterday") if shorter else _("yesterday at %(time)s") - elif days < 5: - format = _("%(weekday)s") if shorter else _("%(weekday)s at %(time)s") - elif days < 334: # 11mo, since confusing for same month last year - format = ( - _("%(month_name)s %(day)s") - if shorter - else _("%(month_name)s %(day)s at %(time)s") - ) - - if format is None: - format = ( - _("%(month_name)s %(day)s, %(year)s") - if shorter - else _("%(month_name)s %(day)s, %(year)s at %(time)s") - ) - - tfhour_clock = self.code not in ("en", "en_US", "zh_CN") - if tfhour_clock: - str_time = "%d:%02d" % (local_date.hour, local_date.minute) - elif self.code == "zh_CN": - str_time = "%s%d:%02d" % ( - (u"\u4e0a\u5348", u"\u4e0b\u5348")[local_date.hour >= 12], - local_date.hour % 12 or 12, - local_date.minute, - ) - else: - str_time = "%d:%02d %s" % ( - local_date.hour % 12 or 12, - local_date.minute, - ("am", "pm")[local_date.hour >= 12], - ) - - return format % { - "month_name": self._months[local_date.month - 1], - "weekday": self._weekdays[local_date.weekday()], - "day": str(local_date.day), - "year": str(local_date.year), - "time": str_time, - } - - def format_day( - self, date: datetime.datetime, gmt_offset: int = 0, dow: bool = True - ) -> bool: - """Formats the given date as a day of week. - - Example: "Monday, January 22". You can remove the day of week with - ``dow=False``. - """ - local_date = date - datetime.timedelta(minutes=gmt_offset) - _ = self.translate - if dow: - return _("%(weekday)s, %(month_name)s %(day)s") % { - "month_name": self._months[local_date.month - 1], - "weekday": self._weekdays[local_date.weekday()], - "day": str(local_date.day), - } - else: - return _("%(month_name)s %(day)s") % { - "month_name": self._months[local_date.month - 1], - "day": str(local_date.day), - } - - def list(self, parts: Any) -> str: - """Returns a comma-separated list for the given list of parts. - - The format is, e.g., "A, B and C", "A and B" or just "A" for lists - of size 1. - """ - _ = self.translate - if len(parts) == 0: - return "" - if len(parts) == 1: - return parts[0] - comma = u" \u0648 " if self.code.startswith("fa") else u", " - return _("%(commas)s and %(last)s") % { - "commas": comma.join(parts[:-1]), - "last": parts[len(parts) - 1], - } - - def friendly_number(self, value: int) -> str: - """Returns a comma-separated number for the given integer.""" - if self.code not in ("en", "en_US"): - return str(value) - s = str(value) - parts = [] - while s: - parts.append(s[-3:]) - s = s[:-3] - return ",".join(reversed(parts)) - - -class CSVLocale(Locale): - """Locale implementation using tornado's CSV translation format.""" - - def __init__(self, code: str, translations: Dict[str, Dict[str, str]]) -> None: - self.translations = translations - super().__init__(code) - - def translate( - self, - message: str, - plural_message: Optional[str] = None, - count: Optional[int] = None, - ) -> str: - if plural_message is not None: - assert count is not None - if count != 1: - message = plural_message - message_dict = self.translations.get("plural", {}) - else: - message_dict = self.translations.get("singular", {}) - else: - message_dict = self.translations.get("unknown", {}) - return message_dict.get(message, message) - - def pgettext( - self, - context: str, - message: str, - plural_message: Optional[str] = None, - count: Optional[int] = None, - ) -> str: - if self.translations: - gen_log.warning("pgettext is not supported by CSVLocale") - return self.translate(message, plural_message, count) - - -class GettextLocale(Locale): - """Locale implementation using the `gettext` module.""" - - def __init__(self, code: str, translations: gettext.NullTranslations) -> None: - self.ngettext = translations.ngettext - self.gettext = translations.gettext - # self.gettext must exist before __init__ is called, since it - # calls into self.translate - super().__init__(code) - - def translate( - self, - message: str, - plural_message: Optional[str] = None, - count: Optional[int] = None, - ) -> str: - if plural_message is not None: - assert count is not None - return self.ngettext(message, plural_message, count) - else: - return self.gettext(message) - - def pgettext( - self, - context: str, - message: str, - plural_message: Optional[str] = None, - count: Optional[int] = None, - ) -> str: - """Allows to set context for translation, accepts plural forms. - - Usage example:: - - pgettext("law", "right") - pgettext("good", "right") - - Plural message example:: - - pgettext("organization", "club", "clubs", len(clubs)) - pgettext("stick", "club", "clubs", len(clubs)) - - To generate POT file with context, add following options to step 1 - of `load_gettext_translations` sequence:: - - xgettext [basic options] --keyword=pgettext:1c,2 --keyword=pgettext:1c,2,3 - - .. versionadded:: 4.2 - """ - if plural_message is not None: - assert count is not None - msgs_with_ctxt = ( - "%s%s%s" % (context, CONTEXT_SEPARATOR, message), - "%s%s%s" % (context, CONTEXT_SEPARATOR, plural_message), - count, - ) - result = self.ngettext(*msgs_with_ctxt) - if CONTEXT_SEPARATOR in result: - # Translation not found - result = self.ngettext(message, plural_message, count) - return result - else: - msg_with_ctxt = "%s%s%s" % (context, CONTEXT_SEPARATOR, message) - result = self.gettext(msg_with_ctxt) - if CONTEXT_SEPARATOR in result: - # Translation not found - result = message - return result diff --git a/venv/lib/python3.8/site-packages/tornado/locks.py b/venv/lib/python3.8/site-packages/tornado/locks.py deleted file mode 100644 index 0898eba..0000000 --- a/venv/lib/python3.8/site-packages/tornado/locks.py +++ /dev/null @@ -1,571 +0,0 @@ -# Copyright 2015 The Tornado Authors -# -# 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. - -import collections -import datetime -import types - -from tornado import gen, ioloop -from tornado.concurrent import Future, future_set_result_unless_cancelled - -from typing import Union, Optional, Type, Any, Awaitable -import typing - -if typing.TYPE_CHECKING: - from typing import Deque, Set # noqa: F401 - -__all__ = ["Condition", "Event", "Semaphore", "BoundedSemaphore", "Lock"] - - -class _TimeoutGarbageCollector(object): - """Base class for objects that periodically clean up timed-out waiters. - - Avoids memory leak in a common pattern like: - - while True: - yield condition.wait(short_timeout) - print('looping....') - """ - - def __init__(self) -> None: - self._waiters = collections.deque() # type: Deque[Future] - self._timeouts = 0 - - def _garbage_collect(self) -> None: - # Occasionally clear timed-out waiters. - self._timeouts += 1 - if self._timeouts > 100: - self._timeouts = 0 - self._waiters = collections.deque(w for w in self._waiters if not w.done()) - - -class Condition(_TimeoutGarbageCollector): - """A condition allows one or more coroutines to wait until notified. - - Like a standard `threading.Condition`, but does not need an underlying lock - that is acquired and released. - - With a `Condition`, coroutines can wait to be notified by other coroutines: - - .. testcode:: - - from tornado import gen - from tornado.ioloop import IOLoop - from tornado.locks import Condition - - condition = Condition() - - async def waiter(): - print("I'll wait right here") - await condition.wait() - print("I'm done waiting") - - async def notifier(): - print("About to notify") - condition.notify() - print("Done notifying") - - async def runner(): - # Wait for waiter() and notifier() in parallel - await gen.multi([waiter(), notifier()]) - - IOLoop.current().run_sync(runner) - - .. testoutput:: - - I'll wait right here - About to notify - Done notifying - I'm done waiting - - `wait` takes an optional ``timeout`` argument, which is either an absolute - timestamp:: - - io_loop = IOLoop.current() - - # Wait up to 1 second for a notification. - await condition.wait(timeout=io_loop.time() + 1) - - ...or a `datetime.timedelta` for a timeout relative to the current time:: - - # Wait up to 1 second. - await condition.wait(timeout=datetime.timedelta(seconds=1)) - - The method returns False if there's no notification before the deadline. - - .. versionchanged:: 5.0 - Previously, waiters could be notified synchronously from within - `notify`. Now, the notification will always be received on the - next iteration of the `.IOLoop`. - """ - - def __init__(self) -> None: - super().__init__() - self.io_loop = ioloop.IOLoop.current() - - def __repr__(self) -> str: - result = "<%s" % (self.__class__.__name__,) - if self._waiters: - result += " waiters[%s]" % len(self._waiters) - return result + ">" - - def wait( - self, timeout: Optional[Union[float, datetime.timedelta]] = None - ) -> Awaitable[bool]: - """Wait for `.notify`. - - Returns a `.Future` that resolves ``True`` if the condition is notified, - or ``False`` after a timeout. - """ - waiter = Future() # type: Future[bool] - self._waiters.append(waiter) - if timeout: - - def on_timeout() -> None: - if not waiter.done(): - future_set_result_unless_cancelled(waiter, False) - self._garbage_collect() - - io_loop = ioloop.IOLoop.current() - timeout_handle = io_loop.add_timeout(timeout, on_timeout) - waiter.add_done_callback(lambda _: io_loop.remove_timeout(timeout_handle)) - return waiter - - def notify(self, n: int = 1) -> None: - """Wake ``n`` waiters.""" - waiters = [] # Waiters we plan to run right now. - while n and self._waiters: - waiter = self._waiters.popleft() - if not waiter.done(): # Might have timed out. - n -= 1 - waiters.append(waiter) - - for waiter in waiters: - future_set_result_unless_cancelled(waiter, True) - - def notify_all(self) -> None: - """Wake all waiters.""" - self.notify(len(self._waiters)) - - -class Event(object): - """An event blocks coroutines until its internal flag is set to True. - - Similar to `threading.Event`. - - A coroutine can wait for an event to be set. Once it is set, calls to - ``yield event.wait()`` will not block unless the event has been cleared: - - .. testcode:: - - from tornado import gen - from tornado.ioloop import IOLoop - from tornado.locks import Event - - event = Event() - - async def waiter(): - print("Waiting for event") - await event.wait() - print("Not waiting this time") - await event.wait() - print("Done") - - async def setter(): - print("About to set the event") - event.set() - - async def runner(): - await gen.multi([waiter(), setter()]) - - IOLoop.current().run_sync(runner) - - .. testoutput:: - - Waiting for event - About to set the event - Not waiting this time - Done - """ - - def __init__(self) -> None: - self._value = False - self._waiters = set() # type: Set[Future[None]] - - def __repr__(self) -> str: - return "<%s %s>" % ( - self.__class__.__name__, - "set" if self.is_set() else "clear", - ) - - def is_set(self) -> bool: - """Return ``True`` if the internal flag is true.""" - return self._value - - def set(self) -> None: - """Set the internal flag to ``True``. All waiters are awakened. - - Calling `.wait` once the flag is set will not block. - """ - if not self._value: - self._value = True - - for fut in self._waiters: - if not fut.done(): - fut.set_result(None) - - def clear(self) -> None: - """Reset the internal flag to ``False``. - - Calls to `.wait` will block until `.set` is called. - """ - self._value = False - - def wait( - self, timeout: Optional[Union[float, datetime.timedelta]] = None - ) -> Awaitable[None]: - """Block until the internal flag is true. - - Returns an awaitable, which raises `tornado.util.TimeoutError` after a - timeout. - """ - fut = Future() # type: Future[None] - if self._value: - fut.set_result(None) - return fut - self._waiters.add(fut) - fut.add_done_callback(lambda fut: self._waiters.remove(fut)) - if timeout is None: - return fut - else: - timeout_fut = gen.with_timeout(timeout, fut) - # This is a slightly clumsy workaround for the fact that - # gen.with_timeout doesn't cancel its futures. Cancelling - # fut will remove it from the waiters list. - timeout_fut.add_done_callback( - lambda tf: fut.cancel() if not fut.done() else None - ) - return timeout_fut - - -class _ReleasingContextManager(object): - """Releases a Lock or Semaphore at the end of a "with" statement. - - with (yield semaphore.acquire()): - pass - - # Now semaphore.release() has been called. - """ - - def __init__(self, obj: Any) -> None: - self._obj = obj - - def __enter__(self) -> None: - pass - - def __exit__( - self, - exc_type: "Optional[Type[BaseException]]", - exc_val: Optional[BaseException], - exc_tb: Optional[types.TracebackType], - ) -> None: - self._obj.release() - - -class Semaphore(_TimeoutGarbageCollector): - """A lock that can be acquired a fixed number of times before blocking. - - A Semaphore manages a counter representing the number of `.release` calls - minus the number of `.acquire` calls, plus an initial value. The `.acquire` - method blocks if necessary until it can return without making the counter - negative. - - Semaphores limit access to a shared resource. To allow access for two - workers at a time: - - .. testsetup:: semaphore - - from collections import deque - - from tornado import gen - from tornado.ioloop import IOLoop - from tornado.concurrent import Future - - # Ensure reliable doctest output: resolve Futures one at a time. - futures_q = deque([Future() for _ in range(3)]) - - async def simulator(futures): - for f in futures: - # simulate the asynchronous passage of time - await gen.sleep(0) - await gen.sleep(0) - f.set_result(None) - - IOLoop.current().add_callback(simulator, list(futures_q)) - - def use_some_resource(): - return futures_q.popleft() - - .. testcode:: semaphore - - from tornado import gen - from tornado.ioloop import IOLoop - from tornado.locks import Semaphore - - sem = Semaphore(2) - - async def worker(worker_id): - await sem.acquire() - try: - print("Worker %d is working" % worker_id) - await use_some_resource() - finally: - print("Worker %d is done" % worker_id) - sem.release() - - async def runner(): - # Join all workers. - await gen.multi([worker(i) for i in range(3)]) - - IOLoop.current().run_sync(runner) - - .. testoutput:: semaphore - - Worker 0 is working - Worker 1 is working - Worker 0 is done - Worker 2 is working - Worker 1 is done - Worker 2 is done - - Workers 0 and 1 are allowed to run concurrently, but worker 2 waits until - the semaphore has been released once, by worker 0. - - The semaphore can be used as an async context manager:: - - async def worker(worker_id): - async with sem: - print("Worker %d is working" % worker_id) - await use_some_resource() - - # Now the semaphore has been released. - print("Worker %d is done" % worker_id) - - For compatibility with older versions of Python, `.acquire` is a - context manager, so ``worker`` could also be written as:: - - @gen.coroutine - def worker(worker_id): - with (yield sem.acquire()): - print("Worker %d is working" % worker_id) - yield use_some_resource() - - # Now the semaphore has been released. - print("Worker %d is done" % worker_id) - - .. versionchanged:: 4.3 - Added ``async with`` support in Python 3.5. - - """ - - def __init__(self, value: int = 1) -> None: - super().__init__() - if value < 0: - raise ValueError("semaphore initial value must be >= 0") - - self._value = value - - def __repr__(self) -> str: - res = super().__repr__() - extra = ( - "locked" if self._value == 0 else "unlocked,value:{0}".format(self._value) - ) - if self._waiters: - extra = "{0},waiters:{1}".format(extra, len(self._waiters)) - return "<{0} [{1}]>".format(res[1:-1], extra) - - def release(self) -> None: - """Increment the counter and wake one waiter.""" - self._value += 1 - while self._waiters: - waiter = self._waiters.popleft() - if not waiter.done(): - self._value -= 1 - - # If the waiter is a coroutine paused at - # - # with (yield semaphore.acquire()): - # - # then the context manager's __exit__ calls release() at the end - # of the "with" block. - waiter.set_result(_ReleasingContextManager(self)) - break - - def acquire( - self, timeout: Optional[Union[float, datetime.timedelta]] = None - ) -> Awaitable[_ReleasingContextManager]: - """Decrement the counter. Returns an awaitable. - - Block if the counter is zero and wait for a `.release`. The awaitable - raises `.TimeoutError` after the deadline. - """ - waiter = Future() # type: Future[_ReleasingContextManager] - if self._value > 0: - self._value -= 1 - waiter.set_result(_ReleasingContextManager(self)) - else: - self._waiters.append(waiter) - if timeout: - - def on_timeout() -> None: - if not waiter.done(): - waiter.set_exception(gen.TimeoutError()) - self._garbage_collect() - - io_loop = ioloop.IOLoop.current() - timeout_handle = io_loop.add_timeout(timeout, on_timeout) - waiter.add_done_callback( - lambda _: io_loop.remove_timeout(timeout_handle) - ) - return waiter - - def __enter__(self) -> None: - raise RuntimeError("Use 'async with' instead of 'with' for Semaphore") - - def __exit__( - self, - typ: "Optional[Type[BaseException]]", - value: Optional[BaseException], - traceback: Optional[types.TracebackType], - ) -> None: - self.__enter__() - - async def __aenter__(self) -> None: - await self.acquire() - - async def __aexit__( - self, - typ: "Optional[Type[BaseException]]", - value: Optional[BaseException], - tb: Optional[types.TracebackType], - ) -> None: - self.release() - - -class BoundedSemaphore(Semaphore): - """A semaphore that prevents release() being called too many times. - - If `.release` would increment the semaphore's value past the initial - value, it raises `ValueError`. Semaphores are mostly used to guard - resources with limited capacity, so a semaphore released too many times - is a sign of a bug. - """ - - def __init__(self, value: int = 1) -> None: - super().__init__(value=value) - self._initial_value = value - - def release(self) -> None: - """Increment the counter and wake one waiter.""" - if self._value >= self._initial_value: - raise ValueError("Semaphore released too many times") - super().release() - - -class Lock(object): - """A lock for coroutines. - - A Lock begins unlocked, and `acquire` locks it immediately. While it is - locked, a coroutine that yields `acquire` waits until another coroutine - calls `release`. - - Releasing an unlocked lock raises `RuntimeError`. - - A Lock can be used as an async context manager with the ``async - with`` statement: - - >>> from tornado import locks - >>> lock = locks.Lock() - >>> - >>> async def f(): - ... async with lock: - ... # Do something holding the lock. - ... pass - ... - ... # Now the lock is released. - - For compatibility with older versions of Python, the `.acquire` - method asynchronously returns a regular context manager: - - >>> async def f2(): - ... with (yield lock.acquire()): - ... # Do something holding the lock. - ... pass - ... - ... # Now the lock is released. - - .. versionchanged:: 4.3 - Added ``async with`` support in Python 3.5. - - """ - - def __init__(self) -> None: - self._block = BoundedSemaphore(value=1) - - def __repr__(self) -> str: - return "<%s _block=%s>" % (self.__class__.__name__, self._block) - - def acquire( - self, timeout: Optional[Union[float, datetime.timedelta]] = None - ) -> Awaitable[_ReleasingContextManager]: - """Attempt to lock. Returns an awaitable. - - Returns an awaitable, which raises `tornado.util.TimeoutError` after a - timeout. - """ - return self._block.acquire(timeout) - - def release(self) -> None: - """Unlock. - - The first coroutine in line waiting for `acquire` gets the lock. - - If not locked, raise a `RuntimeError`. - """ - try: - self._block.release() - except ValueError: - raise RuntimeError("release unlocked lock") - - def __enter__(self) -> None: - raise RuntimeError("Use `async with` instead of `with` for Lock") - - def __exit__( - self, - typ: "Optional[Type[BaseException]]", - value: Optional[BaseException], - tb: Optional[types.TracebackType], - ) -> None: - self.__enter__() - - async def __aenter__(self) -> None: - await self.acquire() - - async def __aexit__( - self, - typ: "Optional[Type[BaseException]]", - value: Optional[BaseException], - tb: Optional[types.TracebackType], - ) -> None: - self.release() diff --git a/venv/lib/python3.8/site-packages/tornado/log.py b/venv/lib/python3.8/site-packages/tornado/log.py deleted file mode 100644 index 810a037..0000000 --- a/venv/lib/python3.8/site-packages/tornado/log.py +++ /dev/null @@ -1,339 +0,0 @@ -# -# Copyright 2012 Facebook -# -# 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. -"""Logging support for Tornado. - -Tornado uses three logger streams: - -* ``tornado.access``: Per-request logging for Tornado's HTTP servers (and - potentially other servers in the future) -* ``tornado.application``: Logging of errors from application code (i.e. - uncaught exceptions from callbacks) -* ``tornado.general``: General-purpose logging, including any errors - or warnings from Tornado itself. - -These streams may be configured independently using the standard library's -`logging` module. For example, you may wish to send ``tornado.access`` logs -to a separate file for analysis. -""" -import logging -import logging.handlers -import sys - -from tornado.escape import _unicode -from tornado.util import unicode_type, basestring_type - -try: - import colorama # type: ignore -except ImportError: - colorama = None - -try: - import curses -except ImportError: - curses = None # type: ignore - -from typing import Dict, Any, cast, Optional - -# Logger objects for internal tornado use -access_log = logging.getLogger("tornado.access") -app_log = logging.getLogger("tornado.application") -gen_log = logging.getLogger("tornado.general") - - -def _stderr_supports_color() -> bool: - try: - if hasattr(sys.stderr, "isatty") and sys.stderr.isatty(): - if curses: - curses.setupterm() - if curses.tigetnum("colors") > 0: - return True - elif colorama: - if sys.stderr is getattr( - colorama.initialise, "wrapped_stderr", object() - ): - return True - except Exception: - # Very broad exception handling because it's always better to - # fall back to non-colored logs than to break at startup. - pass - return False - - -def _safe_unicode(s: Any) -> str: - try: - return _unicode(s) - except UnicodeDecodeError: - return repr(s) - - -class LogFormatter(logging.Formatter): - """Log formatter used in Tornado. - - Key features of this formatter are: - - * Color support when logging to a terminal that supports it. - * Timestamps on every log line. - * Robust against str/bytes encoding problems. - - This formatter is enabled automatically by - `tornado.options.parse_command_line` or `tornado.options.parse_config_file` - (unless ``--logging=none`` is used). - - Color support on Windows versions that do not support ANSI color codes is - enabled by use of the colorama__ library. Applications that wish to use - this must first initialize colorama with a call to ``colorama.init``. - See the colorama documentation for details. - - __ https://pypi.python.org/pypi/colorama - - .. versionchanged:: 4.5 - Added support for ``colorama``. Changed the constructor - signature to be compatible with `logging.config.dictConfig`. - """ - - DEFAULT_FORMAT = "%(color)s[%(levelname)1.1s %(asctime)s %(module)s:%(lineno)d]%(end_color)s %(message)s" # noqa: E501 - DEFAULT_DATE_FORMAT = "%y%m%d %H:%M:%S" - DEFAULT_COLORS = { - logging.DEBUG: 4, # Blue - logging.INFO: 2, # Green - logging.WARNING: 3, # Yellow - logging.ERROR: 1, # Red - logging.CRITICAL: 5, # Magenta - } - - def __init__( - self, - fmt: str = DEFAULT_FORMAT, - datefmt: str = DEFAULT_DATE_FORMAT, - style: str = "%", - color: bool = True, - colors: Dict[int, int] = DEFAULT_COLORS, - ) -> None: - r""" - :arg bool color: Enables color support. - :arg str fmt: Log message format. - It will be applied to the attributes dict of log records. The - text between ``%(color)s`` and ``%(end_color)s`` will be colored - depending on the level if color support is on. - :arg dict colors: color mappings from logging level to terminal color - code - :arg str datefmt: Datetime format. - Used for formatting ``(asctime)`` placeholder in ``prefix_fmt``. - - .. versionchanged:: 3.2 - - Added ``fmt`` and ``datefmt`` arguments. - """ - logging.Formatter.__init__(self, datefmt=datefmt) - self._fmt = fmt - - self._colors = {} # type: Dict[int, str] - if color and _stderr_supports_color(): - if curses is not None: - fg_color = curses.tigetstr("setaf") or curses.tigetstr("setf") or b"" - - for levelno, code in colors.items(): - # Convert the terminal control characters from - # bytes to unicode strings for easier use with the - # logging module. - self._colors[levelno] = unicode_type( - curses.tparm(fg_color, code), "ascii" - ) - self._normal = unicode_type(curses.tigetstr("sgr0"), "ascii") - else: - # If curses is not present (currently we'll only get here for - # colorama on windows), assume hard-coded ANSI color codes. - for levelno, code in colors.items(): - self._colors[levelno] = "\033[2;3%dm" % code - self._normal = "\033[0m" - else: - self._normal = "" - - def format(self, record: Any) -> str: - try: - message = record.getMessage() - assert isinstance(message, basestring_type) # guaranteed by logging - # Encoding notes: The logging module prefers to work with character - # strings, but only enforces that log messages are instances of - # basestring. In python 2, non-ascii bytestrings will make - # their way through the logging framework until they blow up with - # an unhelpful decoding error (with this formatter it happens - # when we attach the prefix, but there are other opportunities for - # exceptions further along in the framework). - # - # If a byte string makes it this far, convert it to unicode to - # ensure it will make it out to the logs. Use repr() as a fallback - # to ensure that all byte strings can be converted successfully, - # but don't do it by default so we don't add extra quotes to ascii - # bytestrings. This is a bit of a hacky place to do this, but - # it's worth it since the encoding errors that would otherwise - # result are so useless (and tornado is fond of using utf8-encoded - # byte strings wherever possible). - record.message = _safe_unicode(message) - except Exception as e: - record.message = "Bad message (%r): %r" % (e, record.__dict__) - - record.asctime = self.formatTime(record, cast(str, self.datefmt)) - - if record.levelno in self._colors: - record.color = self._colors[record.levelno] - record.end_color = self._normal - else: - record.color = record.end_color = "" - - formatted = self._fmt % record.__dict__ - - if record.exc_info: - if not record.exc_text: - record.exc_text = self.formatException(record.exc_info) - if record.exc_text: - # exc_text contains multiple lines. We need to _safe_unicode - # each line separately so that non-utf8 bytes don't cause - # all the newlines to turn into '\n'. - lines = [formatted.rstrip()] - lines.extend(_safe_unicode(ln) for ln in record.exc_text.split("\n")) - formatted = "\n".join(lines) - return formatted.replace("\n", "\n ") - - -def enable_pretty_logging( - options: Any = None, logger: Optional[logging.Logger] = None -) -> None: - """Turns on formatted logging output as configured. - - This is called automatically by `tornado.options.parse_command_line` - and `tornado.options.parse_config_file`. - """ - if options is None: - import tornado.options - - options = tornado.options.options - if options.logging is None or options.logging.lower() == "none": - return - if logger is None: - logger = logging.getLogger() - logger.setLevel(getattr(logging, options.logging.upper())) - if options.log_file_prefix: - rotate_mode = options.log_rotate_mode - if rotate_mode == "size": - channel = logging.handlers.RotatingFileHandler( - filename=options.log_file_prefix, - maxBytes=options.log_file_max_size, - backupCount=options.log_file_num_backups, - encoding="utf-8", - ) # type: logging.Handler - elif rotate_mode == "time": - channel = logging.handlers.TimedRotatingFileHandler( - filename=options.log_file_prefix, - when=options.log_rotate_when, - interval=options.log_rotate_interval, - backupCount=options.log_file_num_backups, - encoding="utf-8", - ) - else: - error_message = ( - "The value of log_rotate_mode option should be " - + '"size" or "time", not "%s".' % rotate_mode - ) - raise ValueError(error_message) - channel.setFormatter(LogFormatter(color=False)) - logger.addHandler(channel) - - if options.log_to_stderr or (options.log_to_stderr is None and not logger.handlers): - # Set up color if we are in a tty and curses is installed - channel = logging.StreamHandler() - channel.setFormatter(LogFormatter()) - logger.addHandler(channel) - - -def define_logging_options(options: Any = None) -> None: - """Add logging-related flags to ``options``. - - These options are present automatically on the default options instance; - this method is only necessary if you have created your own `.OptionParser`. - - .. versionadded:: 4.2 - This function existed in prior versions but was broken and undocumented until 4.2. - """ - if options is None: - # late import to prevent cycle - import tornado.options - - options = tornado.options.options - options.define( - "logging", - default="info", - help=( - "Set the Python log level. If 'none', tornado won't touch the " - "logging configuration." - ), - metavar="debug|info|warning|error|none", - ) - options.define( - "log_to_stderr", - type=bool, - default=None, - help=( - "Send log output to stderr (colorized if possible). " - "By default use stderr if --log_file_prefix is not set and " - "no other logging is configured." - ), - ) - options.define( - "log_file_prefix", - type=str, - default=None, - metavar="PATH", - help=( - "Path prefix for log files. " - "Note that if you are running multiple tornado processes, " - "log_file_prefix must be different for each of them (e.g. " - "include the port number)" - ), - ) - options.define( - "log_file_max_size", - type=int, - default=100 * 1000 * 1000, - help="max size of log files before rollover", - ) - options.define( - "log_file_num_backups", type=int, default=10, help="number of log files to keep" - ) - - options.define( - "log_rotate_when", - type=str, - default="midnight", - help=( - "specify the type of TimedRotatingFileHandler interval " - "other options:('S', 'M', 'H', 'D', 'W0'-'W6')" - ), - ) - options.define( - "log_rotate_interval", - type=int, - default=1, - help="The interval value of timed rotating", - ) - - options.define( - "log_rotate_mode", - type=str, - default="size", - help="The mode of rotating files(time or size)", - ) - - options.add_parse_callback(lambda: enable_pretty_logging(options)) diff --git a/venv/lib/python3.8/site-packages/tornado/netutil.py b/venv/lib/python3.8/site-packages/tornado/netutil.py deleted file mode 100644 index 868d3e9..0000000 --- a/venv/lib/python3.8/site-packages/tornado/netutil.py +++ /dev/null @@ -1,617 +0,0 @@ -# -# Copyright 2011 Facebook -# -# 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. - -"""Miscellaneous network utility code.""" - -import concurrent.futures -import errno -import os -import sys -import socket -import ssl -import stat - -from tornado.concurrent import dummy_executor, run_on_executor -from tornado.ioloop import IOLoop -from tornado.util import Configurable, errno_from_exception - -from typing import List, Callable, Any, Type, Dict, Union, Tuple, Awaitable, Optional - -# Note that the naming of ssl.Purpose is confusing; the purpose -# of a context is to authentiate the opposite side of the connection. -_client_ssl_defaults = ssl.create_default_context(ssl.Purpose.SERVER_AUTH) -_server_ssl_defaults = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) -if hasattr(ssl, "OP_NO_COMPRESSION"): - # See netutil.ssl_options_to_context - _client_ssl_defaults.options |= ssl.OP_NO_COMPRESSION - _server_ssl_defaults.options |= ssl.OP_NO_COMPRESSION - -# ThreadedResolver runs getaddrinfo on a thread. If the hostname is unicode, -# getaddrinfo attempts to import encodings.idna. If this is done at -# module-import time, the import lock is already held by the main thread, -# leading to deadlock. Avoid it by caching the idna encoder on the main -# thread now. -u"foo".encode("idna") - -# For undiagnosed reasons, 'latin1' codec may also need to be preloaded. -u"foo".encode("latin1") - -# Default backlog used when calling sock.listen() -_DEFAULT_BACKLOG = 128 - - -def bind_sockets( - port: int, - address: Optional[str] = None, - family: socket.AddressFamily = socket.AF_UNSPEC, - backlog: int = _DEFAULT_BACKLOG, - flags: Optional[int] = None, - reuse_port: bool = False, -) -> List[socket.socket]: - """Creates listening sockets bound to the given port and address. - - Returns a list of socket objects (multiple sockets are returned if - the given address maps to multiple IP addresses, which is most common - for mixed IPv4 and IPv6 use). - - Address may be either an IP address or hostname. If it's a hostname, - the server will listen on all IP addresses associated with the - name. Address may be an empty string or None to listen on all - available interfaces. Family may be set to either `socket.AF_INET` - or `socket.AF_INET6` to restrict to IPv4 or IPv6 addresses, otherwise - both will be used if available. - - The ``backlog`` argument has the same meaning as for - `socket.listen() <socket.socket.listen>`. - - ``flags`` is a bitmask of AI_* flags to `~socket.getaddrinfo`, like - ``socket.AI_PASSIVE | socket.AI_NUMERICHOST``. - - ``reuse_port`` option sets ``SO_REUSEPORT`` option for every socket - in the list. If your platform doesn't support this option ValueError will - be raised. - """ - if reuse_port and not hasattr(socket, "SO_REUSEPORT"): - raise ValueError("the platform doesn't support SO_REUSEPORT") - - sockets = [] - if address == "": - address = None - if not socket.has_ipv6 and family == socket.AF_UNSPEC: - # Python can be compiled with --disable-ipv6, which causes - # operations on AF_INET6 sockets to fail, but does not - # automatically exclude those results from getaddrinfo - # results. - # http://bugs.python.org/issue16208 - family = socket.AF_INET - if flags is None: - flags = socket.AI_PASSIVE - bound_port = None - unique_addresses = set() # type: set - for res in sorted( - socket.getaddrinfo(address, port, family, socket.SOCK_STREAM, 0, flags), - key=lambda x: x[0], - ): - if res in unique_addresses: - continue - - unique_addresses.add(res) - - af, socktype, proto, canonname, sockaddr = res - if ( - sys.platform == "darwin" - and address == "localhost" - and af == socket.AF_INET6 - and sockaddr[3] != 0 - ): - # Mac OS X includes a link-local address fe80::1%lo0 in the - # getaddrinfo results for 'localhost'. However, the firewall - # doesn't understand that this is a local address and will - # prompt for access (often repeatedly, due to an apparent - # bug in its ability to remember granting access to an - # application). Skip these addresses. - continue - try: - sock = socket.socket(af, socktype, proto) - except socket.error as e: - if errno_from_exception(e) == errno.EAFNOSUPPORT: - continue - raise - if os.name != "nt": - try: - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - except socket.error as e: - if errno_from_exception(e) != errno.ENOPROTOOPT: - # Hurd doesn't support SO_REUSEADDR. - raise - if reuse_port: - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1) - if af == socket.AF_INET6: - # On linux, ipv6 sockets accept ipv4 too by default, - # but this makes it impossible to bind to both - # 0.0.0.0 in ipv4 and :: in ipv6. On other systems, - # separate sockets *must* be used to listen for both ipv4 - # and ipv6. For consistency, always disable ipv4 on our - # ipv6 sockets and use a separate ipv4 socket when needed. - # - # Python 2.x on windows doesn't have IPPROTO_IPV6. - if hasattr(socket, "IPPROTO_IPV6"): - sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 1) - - # automatic port allocation with port=None - # should bind on the same port on IPv4 and IPv6 - host, requested_port = sockaddr[:2] - if requested_port == 0 and bound_port is not None: - sockaddr = tuple([host, bound_port] + list(sockaddr[2:])) - - sock.setblocking(False) - try: - sock.bind(sockaddr) - except OSError as e: - if ( - errno_from_exception(e) == errno.EADDRNOTAVAIL - and address == "localhost" - and sockaddr[0] == "::1" - ): - # On some systems (most notably docker with default - # configurations), ipv6 is partially disabled: - # socket.has_ipv6 is true, we can create AF_INET6 - # sockets, and getaddrinfo("localhost", ..., - # AF_PASSIVE) resolves to ::1, but we get an error - # when binding. - # - # Swallow the error, but only for this specific case. - # If EADDRNOTAVAIL occurs in other situations, it - # might be a real problem like a typo in a - # configuration. - sock.close() - continue - else: - raise - bound_port = sock.getsockname()[1] - sock.listen(backlog) - sockets.append(sock) - return sockets - - -if hasattr(socket, "AF_UNIX"): - - def bind_unix_socket( - file: str, mode: int = 0o600, backlog: int = _DEFAULT_BACKLOG - ) -> socket.socket: - """Creates a listening unix socket. - - If a socket with the given name already exists, it will be deleted. - If any other file with that name exists, an exception will be - raised. - - Returns a socket object (not a list of socket objects like - `bind_sockets`) - """ - sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) - try: - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - except socket.error as e: - if errno_from_exception(e) != errno.ENOPROTOOPT: - # Hurd doesn't support SO_REUSEADDR - raise - sock.setblocking(False) - try: - st = os.stat(file) - except FileNotFoundError: - pass - else: - if stat.S_ISSOCK(st.st_mode): - os.remove(file) - else: - raise ValueError("File %s exists and is not a socket", file) - sock.bind(file) - os.chmod(file, mode) - sock.listen(backlog) - return sock - - -def add_accept_handler( - sock: socket.socket, callback: Callable[[socket.socket, Any], None] -) -> Callable[[], None]: - """Adds an `.IOLoop` event handler to accept new connections on ``sock``. - - When a connection is accepted, ``callback(connection, address)`` will - be run (``connection`` is a socket object, and ``address`` is the - address of the other end of the connection). Note that this signature - is different from the ``callback(fd, events)`` signature used for - `.IOLoop` handlers. - - A callable is returned which, when called, will remove the `.IOLoop` - event handler and stop processing further incoming connections. - - .. versionchanged:: 5.0 - The ``io_loop`` argument (deprecated since version 4.1) has been removed. - - .. versionchanged:: 5.0 - A callable is returned (``None`` was returned before). - """ - io_loop = IOLoop.current() - removed = [False] - - def accept_handler(fd: socket.socket, events: int) -> None: - # More connections may come in while we're handling callbacks; - # to prevent starvation of other tasks we must limit the number - # of connections we accept at a time. Ideally we would accept - # up to the number of connections that were waiting when we - # entered this method, but this information is not available - # (and rearranging this method to call accept() as many times - # as possible before running any callbacks would have adverse - # effects on load balancing in multiprocess configurations). - # Instead, we use the (default) listen backlog as a rough - # heuristic for the number of connections we can reasonably - # accept at once. - for i in range(_DEFAULT_BACKLOG): - if removed[0]: - # The socket was probably closed - return - try: - connection, address = sock.accept() - except BlockingIOError: - # EWOULDBLOCK indicates we have accepted every - # connection that is available. - return - except ConnectionAbortedError: - # ECONNABORTED indicates that there was a connection - # but it was closed while still in the accept queue. - # (observed on FreeBSD). - continue - callback(connection, address) - - def remove_handler() -> None: - io_loop.remove_handler(sock) - removed[0] = True - - io_loop.add_handler(sock, accept_handler, IOLoop.READ) - return remove_handler - - -def is_valid_ip(ip: str) -> bool: - """Returns ``True`` if the given string is a well-formed IP address. - - Supports IPv4 and IPv6. - """ - if not ip or "\x00" in ip: - # getaddrinfo resolves empty strings to localhost, and truncates - # on zero bytes. - return False - try: - res = socket.getaddrinfo( - ip, 0, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_NUMERICHOST - ) - return bool(res) - except socket.gaierror as e: - if e.args[0] == socket.EAI_NONAME: - return False - raise - return True - - -class Resolver(Configurable): - """Configurable asynchronous DNS resolver interface. - - By default, a blocking implementation is used (which simply calls - `socket.getaddrinfo`). An alternative implementation can be - chosen with the `Resolver.configure <.Configurable.configure>` - class method:: - - Resolver.configure('tornado.netutil.ThreadedResolver') - - The implementations of this interface included with Tornado are - - * `tornado.netutil.DefaultExecutorResolver` - * `tornado.netutil.BlockingResolver` (deprecated) - * `tornado.netutil.ThreadedResolver` (deprecated) - * `tornado.netutil.OverrideResolver` - * `tornado.platform.twisted.TwistedResolver` - * `tornado.platform.caresresolver.CaresResolver` - - .. versionchanged:: 5.0 - The default implementation has changed from `BlockingResolver` to - `DefaultExecutorResolver`. - """ - - @classmethod - def configurable_base(cls) -> Type["Resolver"]: - return Resolver - - @classmethod - def configurable_default(cls) -> Type["Resolver"]: - return DefaultExecutorResolver - - def resolve( - self, host: str, port: int, family: socket.AddressFamily = socket.AF_UNSPEC - ) -> Awaitable[List[Tuple[int, Any]]]: - """Resolves an address. - - The ``host`` argument is a string which may be a hostname or a - literal IP address. - - Returns a `.Future` whose result is a list of (family, - address) pairs, where address is a tuple suitable to pass to - `socket.connect <socket.socket.connect>` (i.e. a ``(host, - port)`` pair for IPv4; additional fields may be present for - IPv6). If a ``callback`` is passed, it will be run with the - result as an argument when it is complete. - - :raises IOError: if the address cannot be resolved. - - .. versionchanged:: 4.4 - Standardized all implementations to raise `IOError`. - - .. versionchanged:: 6.0 The ``callback`` argument was removed. - Use the returned awaitable object instead. - - """ - raise NotImplementedError() - - def close(self) -> None: - """Closes the `Resolver`, freeing any resources used. - - .. versionadded:: 3.1 - - """ - pass - - -def _resolve_addr( - host: str, port: int, family: socket.AddressFamily = socket.AF_UNSPEC -) -> List[Tuple[int, Any]]: - # On Solaris, getaddrinfo fails if the given port is not found - # in /etc/services and no socket type is given, so we must pass - # one here. The socket type used here doesn't seem to actually - # matter (we discard the one we get back in the results), - # so the addresses we return should still be usable with SOCK_DGRAM. - addrinfo = socket.getaddrinfo(host, port, family, socket.SOCK_STREAM) - results = [] - for fam, socktype, proto, canonname, address in addrinfo: - results.append((fam, address)) - return results # type: ignore - - -class DefaultExecutorResolver(Resolver): - """Resolver implementation using `.IOLoop.run_in_executor`. - - .. versionadded:: 5.0 - """ - - async def resolve( - self, host: str, port: int, family: socket.AddressFamily = socket.AF_UNSPEC - ) -> List[Tuple[int, Any]]: - result = await IOLoop.current().run_in_executor( - None, _resolve_addr, host, port, family - ) - return result - - -class ExecutorResolver(Resolver): - """Resolver implementation using a `concurrent.futures.Executor`. - - Use this instead of `ThreadedResolver` when you require additional - control over the executor being used. - - The executor will be shut down when the resolver is closed unless - ``close_resolver=False``; use this if you want to reuse the same - executor elsewhere. - - .. versionchanged:: 5.0 - The ``io_loop`` argument (deprecated since version 4.1) has been removed. - - .. deprecated:: 5.0 - The default `Resolver` now uses `.IOLoop.run_in_executor`; use that instead - of this class. - """ - - def initialize( - self, - executor: Optional[concurrent.futures.Executor] = None, - close_executor: bool = True, - ) -> None: - self.io_loop = IOLoop.current() - if executor is not None: - self.executor = executor - self.close_executor = close_executor - else: - self.executor = dummy_executor - self.close_executor = False - - def close(self) -> None: - if self.close_executor: - self.executor.shutdown() - self.executor = None # type: ignore - - @run_on_executor - def resolve( - self, host: str, port: int, family: socket.AddressFamily = socket.AF_UNSPEC - ) -> List[Tuple[int, Any]]: - return _resolve_addr(host, port, family) - - -class BlockingResolver(ExecutorResolver): - """Default `Resolver` implementation, using `socket.getaddrinfo`. - - The `.IOLoop` will be blocked during the resolution, although the - callback will not be run until the next `.IOLoop` iteration. - - .. deprecated:: 5.0 - The default `Resolver` now uses `.IOLoop.run_in_executor`; use that instead - of this class. - """ - - def initialize(self) -> None: # type: ignore - super().initialize() - - -class ThreadedResolver(ExecutorResolver): - """Multithreaded non-blocking `Resolver` implementation. - - Requires the `concurrent.futures` package to be installed - (available in the standard library since Python 3.2, - installable with ``pip install futures`` in older versions). - - The thread pool size can be configured with:: - - Resolver.configure('tornado.netutil.ThreadedResolver', - num_threads=10) - - .. versionchanged:: 3.1 - All ``ThreadedResolvers`` share a single thread pool, whose - size is set by the first one to be created. - - .. deprecated:: 5.0 - The default `Resolver` now uses `.IOLoop.run_in_executor`; use that instead - of this class. - """ - - _threadpool = None # type: ignore - _threadpool_pid = None # type: int - - def initialize(self, num_threads: int = 10) -> None: # type: ignore - threadpool = ThreadedResolver._create_threadpool(num_threads) - super().initialize(executor=threadpool, close_executor=False) - - @classmethod - def _create_threadpool( - cls, num_threads: int - ) -> concurrent.futures.ThreadPoolExecutor: - pid = os.getpid() - if cls._threadpool_pid != pid: - # Threads cannot survive after a fork, so if our pid isn't what it - # was when we created the pool then delete it. - cls._threadpool = None - if cls._threadpool is None: - cls._threadpool = concurrent.futures.ThreadPoolExecutor(num_threads) - cls._threadpool_pid = pid - return cls._threadpool - - -class OverrideResolver(Resolver): - """Wraps a resolver with a mapping of overrides. - - This can be used to make local DNS changes (e.g. for testing) - without modifying system-wide settings. - - The mapping can be in three formats:: - - { - # Hostname to host or ip - "example.com": "127.0.1.1", - - # Host+port to host+port - ("login.example.com", 443): ("localhost", 1443), - - # Host+port+address family to host+port - ("login.example.com", 443, socket.AF_INET6): ("::1", 1443), - } - - .. versionchanged:: 5.0 - Added support for host-port-family triplets. - """ - - def initialize(self, resolver: Resolver, mapping: dict) -> None: - self.resolver = resolver - self.mapping = mapping - - def close(self) -> None: - self.resolver.close() - - def resolve( - self, host: str, port: int, family: socket.AddressFamily = socket.AF_UNSPEC - ) -> Awaitable[List[Tuple[int, Any]]]: - if (host, port, family) in self.mapping: - host, port = self.mapping[(host, port, family)] - elif (host, port) in self.mapping: - host, port = self.mapping[(host, port)] - elif host in self.mapping: - host = self.mapping[host] - return self.resolver.resolve(host, port, family) - - -# These are the keyword arguments to ssl.wrap_socket that must be translated -# to their SSLContext equivalents (the other arguments are still passed -# to SSLContext.wrap_socket). -_SSL_CONTEXT_KEYWORDS = frozenset( - ["ssl_version", "certfile", "keyfile", "cert_reqs", "ca_certs", "ciphers"] -) - - -def ssl_options_to_context( - ssl_options: Union[Dict[str, Any], ssl.SSLContext] -) -> ssl.SSLContext: - """Try to convert an ``ssl_options`` dictionary to an - `~ssl.SSLContext` object. - - The ``ssl_options`` dictionary contains keywords to be passed to - `ssl.wrap_socket`. In Python 2.7.9+, `ssl.SSLContext` objects can - be used instead. This function converts the dict form to its - `~ssl.SSLContext` equivalent, and may be used when a component which - accepts both forms needs to upgrade to the `~ssl.SSLContext` version - to use features like SNI or NPN. - """ - if isinstance(ssl_options, ssl.SSLContext): - return ssl_options - assert isinstance(ssl_options, dict) - assert all(k in _SSL_CONTEXT_KEYWORDS for k in ssl_options), ssl_options - # Can't use create_default_context since this interface doesn't - # tell us client vs server. - context = ssl.SSLContext(ssl_options.get("ssl_version", ssl.PROTOCOL_SSLv23)) - if "certfile" in ssl_options: - context.load_cert_chain( - ssl_options["certfile"], ssl_options.get("keyfile", None) - ) - if "cert_reqs" in ssl_options: - context.verify_mode = ssl_options["cert_reqs"] - if "ca_certs" in ssl_options: - context.load_verify_locations(ssl_options["ca_certs"]) - if "ciphers" in ssl_options: - context.set_ciphers(ssl_options["ciphers"]) - if hasattr(ssl, "OP_NO_COMPRESSION"): - # Disable TLS compression to avoid CRIME and related attacks. - # This constant depends on openssl version 1.0. - # TODO: Do we need to do this ourselves or can we trust - # the defaults? - context.options |= ssl.OP_NO_COMPRESSION - return context - - -def ssl_wrap_socket( - socket: socket.socket, - ssl_options: Union[Dict[str, Any], ssl.SSLContext], - server_hostname: Optional[str] = None, - **kwargs: Any -) -> ssl.SSLSocket: - """Returns an ``ssl.SSLSocket`` wrapping the given socket. - - ``ssl_options`` may be either an `ssl.SSLContext` object or a - dictionary (as accepted by `ssl_options_to_context`). Additional - keyword arguments are passed to ``wrap_socket`` (either the - `~ssl.SSLContext` method or the `ssl` module function as - appropriate). - """ - context = ssl_options_to_context(ssl_options) - if ssl.HAS_SNI: - # In python 3.4, wrap_socket only accepts the server_hostname - # argument if HAS_SNI is true. - # TODO: add a unittest (python added server-side SNI support in 3.4) - # In the meantime it can be manually tested with - # python3 -m tornado.httpclient https://sni.velox.ch - return context.wrap_socket(socket, server_hostname=server_hostname, **kwargs) - else: - return context.wrap_socket(socket, **kwargs) diff --git a/venv/lib/python3.8/site-packages/tornado/options.py b/venv/lib/python3.8/site-packages/tornado/options.py deleted file mode 100644 index f0b89a9..0000000 --- a/venv/lib/python3.8/site-packages/tornado/options.py +++ /dev/null @@ -1,735 +0,0 @@ -# -# Copyright 2009 Facebook -# -# 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. - -"""A command line parsing module that lets modules define their own options. - -This module is inspired by Google's `gflags -<https://github.com/google/python-gflags>`_. The primary difference -with libraries such as `argparse` is that a global registry is used so -that options may be defined in any module (it also enables -`tornado.log` by default). The rest of Tornado does not depend on this -module, so feel free to use `argparse` or other configuration -libraries if you prefer them. - -Options must be defined with `tornado.options.define` before use, -generally at the top level of a module. The options are then -accessible as attributes of `tornado.options.options`:: - - # myapp/db.py - from tornado.options import define, options - - define("mysql_host", default="127.0.0.1:3306", help="Main user DB") - define("memcache_hosts", default="127.0.0.1:11011", multiple=True, - help="Main user memcache servers") - - def connect(): - db = database.Connection(options.mysql_host) - ... - - # myapp/server.py - from tornado.options import define, options - - define("port", default=8080, help="port to listen on") - - def start_server(): - app = make_app() - app.listen(options.port) - -The ``main()`` method of your application does not need to be aware of all of -the options used throughout your program; they are all automatically loaded -when the modules are loaded. However, all modules that define options -must have been imported before the command line is parsed. - -Your ``main()`` method can parse the command line or parse a config file with -either `parse_command_line` or `parse_config_file`:: - - import myapp.db, myapp.server - import tornado.options - - if __name__ == '__main__': - tornado.options.parse_command_line() - # or - tornado.options.parse_config_file("/etc/server.conf") - -.. note:: - - When using multiple ``parse_*`` functions, pass ``final=False`` to all - but the last one, or side effects may occur twice (in particular, - this can result in log messages being doubled). - -`tornado.options.options` is a singleton instance of `OptionParser`, and -the top-level functions in this module (`define`, `parse_command_line`, etc) -simply call methods on it. You may create additional `OptionParser` -instances to define isolated sets of options, such as for subcommands. - -.. note:: - - By default, several options are defined that will configure the - standard `logging` module when `parse_command_line` or `parse_config_file` - are called. If you want Tornado to leave the logging configuration - alone so you can manage it yourself, either pass ``--logging=none`` - on the command line or do the following to disable it in code:: - - from tornado.options import options, parse_command_line - options.logging = None - parse_command_line() - -.. versionchanged:: 4.3 - Dashes and underscores are fully interchangeable in option names; - options can be defined, set, and read with any mix of the two. - Dashes are typical for command-line usage while config files require - underscores. -""" - -import datetime -import numbers -import re -import sys -import os -import textwrap - -from tornado.escape import _unicode, native_str -from tornado.log import define_logging_options -from tornado.util import basestring_type, exec_in - -from typing import ( - Any, - Iterator, - Iterable, - Tuple, - Set, - Dict, - Callable, - List, - TextIO, - Optional, -) - - -class Error(Exception): - """Exception raised by errors in the options module.""" - - pass - - -class OptionParser(object): - """A collection of options, a dictionary with object-like access. - - Normally accessed via static functions in the `tornado.options` module, - which reference a global instance. - """ - - def __init__(self) -> None: - # we have to use self.__dict__ because we override setattr. - self.__dict__["_options"] = {} - self.__dict__["_parse_callbacks"] = [] - self.define( - "help", - type=bool, - help="show this help information", - callback=self._help_callback, - ) - - def _normalize_name(self, name: str) -> str: - return name.replace("_", "-") - - def __getattr__(self, name: str) -> Any: - name = self._normalize_name(name) - if isinstance(self._options.get(name), _Option): - return self._options[name].value() - raise AttributeError("Unrecognized option %r" % name) - - def __setattr__(self, name: str, value: Any) -> None: - name = self._normalize_name(name) - if isinstance(self._options.get(name), _Option): - return self._options[name].set(value) - raise AttributeError("Unrecognized option %r" % name) - - def __iter__(self) -> Iterator: - return (opt.name for opt in self._options.values()) - - def __contains__(self, name: str) -> bool: - name = self._normalize_name(name) - return name in self._options - - def __getitem__(self, name: str) -> Any: - return self.__getattr__(name) - - def __setitem__(self, name: str, value: Any) -> None: - return self.__setattr__(name, value) - - def items(self) -> Iterable[Tuple[str, Any]]: - """An iterable of (name, value) pairs. - - .. versionadded:: 3.1 - """ - return [(opt.name, opt.value()) for name, opt in self._options.items()] - - def groups(self) -> Set[str]: - """The set of option-groups created by ``define``. - - .. versionadded:: 3.1 - """ - return set(opt.group_name for opt in self._options.values()) - - def group_dict(self, group: str) -> Dict[str, Any]: - """The names and values of options in a group. - - Useful for copying options into Application settings:: - - from tornado.options import define, parse_command_line, options - - define('template_path', group='application') - define('static_path', group='application') - - parse_command_line() - - application = Application( - handlers, **options.group_dict('application')) - - .. versionadded:: 3.1 - """ - return dict( - (opt.name, opt.value()) - for name, opt in self._options.items() - if not group or group == opt.group_name - ) - - def as_dict(self) -> Dict[str, Any]: - """The names and values of all options. - - .. versionadded:: 3.1 - """ - return dict((opt.name, opt.value()) for name, opt in self._options.items()) - - def define( - self, - name: str, - default: Any = None, - type: Optional[type] = None, - help: Optional[str] = None, - metavar: Optional[str] = None, - multiple: bool = False, - group: Optional[str] = None, - callback: Optional[Callable[[Any], None]] = None, - ) -> None: - """Defines a new command line option. - - ``type`` can be any of `str`, `int`, `float`, `bool`, - `~datetime.datetime`, or `~datetime.timedelta`. If no ``type`` - is given but a ``default`` is, ``type`` is the type of - ``default``. Otherwise, ``type`` defaults to `str`. - - If ``multiple`` is True, the option value is a list of ``type`` - instead of an instance of ``type``. - - ``help`` and ``metavar`` are used to construct the - automatically generated command line help string. The help - message is formatted like:: - - --name=METAVAR help string - - ``group`` is used to group the defined options in logical - groups. By default, command line options are grouped by the - file in which they are defined. - - Command line option names must be unique globally. - - If a ``callback`` is given, it will be run with the new value whenever - the option is changed. This can be used to combine command-line - and file-based options:: - - define("config", type=str, help="path to config file", - callback=lambda path: parse_config_file(path, final=False)) - - With this definition, options in the file specified by ``--config`` will - override options set earlier on the command line, but can be overridden - by later flags. - - """ - normalized = self._normalize_name(name) - if normalized in self._options: - raise Error( - "Option %r already defined in %s" - % (normalized, self._options[normalized].file_name) - ) - frame = sys._getframe(0) - options_file = frame.f_code.co_filename - - # Can be called directly, or through top level define() fn, in which - # case, step up above that frame to look for real caller. - if ( - frame.f_back.f_code.co_filename == options_file - and frame.f_back.f_code.co_name == "define" - ): - frame = frame.f_back - - file_name = frame.f_back.f_code.co_filename - if file_name == options_file: - file_name = "" - if type is None: - if not multiple and default is not None: - type = default.__class__ - else: - type = str - if group: - group_name = group # type: Optional[str] - else: - group_name = file_name - option = _Option( - name, - file_name=file_name, - default=default, - type=type, - help=help, - metavar=metavar, - multiple=multiple, - group_name=group_name, - callback=callback, - ) - self._options[normalized] = option - - def parse_command_line( - self, args: Optional[List[str]] = None, final: bool = True - ) -> List[str]: - """Parses all options given on the command line (defaults to - `sys.argv`). - - Options look like ``--option=value`` and are parsed according - to their ``type``. For boolean options, ``--option`` is - equivalent to ``--option=true`` - - If the option has ``multiple=True``, comma-separated values - are accepted. For multi-value integer options, the syntax - ``x:y`` is also accepted and equivalent to ``range(x, y)``. - - Note that ``args[0]`` is ignored since it is the program name - in `sys.argv`. - - We return a list of all arguments that are not parsed as options. - - If ``final`` is ``False``, parse callbacks will not be run. - This is useful for applications that wish to combine configurations - from multiple sources. - - """ - if args is None: - args = sys.argv - remaining = [] # type: List[str] - for i in range(1, len(args)): - # All things after the last option are command line arguments - if not args[i].startswith("-"): - remaining = args[i:] - break - if args[i] == "--": - remaining = args[i + 1 :] - break - arg = args[i].lstrip("-") - name, equals, value = arg.partition("=") - name = self._normalize_name(name) - if name not in self._options: - self.print_help() - raise Error("Unrecognized command line option: %r" % name) - option = self._options[name] - if not equals: - if option.type == bool: - value = "true" - else: - raise Error("Option %r requires a value" % name) - option.parse(value) - - if final: - self.run_parse_callbacks() - - return remaining - - def parse_config_file(self, path: str, final: bool = True) -> None: - """Parses and loads the config file at the given path. - - The config file contains Python code that will be executed (so - it is **not safe** to use untrusted config files). Anything in - the global namespace that matches a defined option will be - used to set that option's value. - - Options may either be the specified type for the option or - strings (in which case they will be parsed the same way as in - `.parse_command_line`) - - Example (using the options defined in the top-level docs of - this module):: - - port = 80 - mysql_host = 'mydb.example.com:3306' - # Both lists and comma-separated strings are allowed for - # multiple=True. - memcache_hosts = ['cache1.example.com:11011', - 'cache2.example.com:11011'] - memcache_hosts = 'cache1.example.com:11011,cache2.example.com:11011' - - If ``final`` is ``False``, parse callbacks will not be run. - This is useful for applications that wish to combine configurations - from multiple sources. - - .. note:: - - `tornado.options` is primarily a command-line library. - Config file support is provided for applications that wish - to use it, but applications that prefer config files may - wish to look at other libraries instead. - - .. versionchanged:: 4.1 - Config files are now always interpreted as utf-8 instead of - the system default encoding. - - .. versionchanged:: 4.4 - The special variable ``__file__`` is available inside config - files, specifying the absolute path to the config file itself. - - .. versionchanged:: 5.1 - Added the ability to set options via strings in config files. - - """ - config = {"__file__": os.path.abspath(path)} - with open(path, "rb") as f: - exec_in(native_str(f.read()), config, config) - for name in config: - normalized = self._normalize_name(name) - if normalized in self._options: - option = self._options[normalized] - if option.multiple: - if not isinstance(config[name], (list, str)): - raise Error( - "Option %r is required to be a list of %s " - "or a comma-separated string" - % (option.name, option.type.__name__) - ) - - if type(config[name]) == str and option.type != str: - option.parse(config[name]) - else: - option.set(config[name]) - - if final: - self.run_parse_callbacks() - - def print_help(self, file: Optional[TextIO] = None) -> None: - """Prints all the command line options to stderr (or another file).""" - if file is None: - file = sys.stderr - print("Usage: %s [OPTIONS]" % sys.argv[0], file=file) - print("\nOptions:\n", file=file) - by_group = {} # type: Dict[str, List[_Option]] - for option in self._options.values(): - by_group.setdefault(option.group_name, []).append(option) - - for filename, o in sorted(by_group.items()): - if filename: - print("\n%s options:\n" % os.path.normpath(filename), file=file) - o.sort(key=lambda option: option.name) - for option in o: - # Always print names with dashes in a CLI context. - prefix = self._normalize_name(option.name) - if option.metavar: - prefix += "=" + option.metavar - description = option.help or "" - if option.default is not None and option.default != "": - description += " (default %s)" % option.default - lines = textwrap.wrap(description, 79 - 35) - if len(prefix) > 30 or len(lines) == 0: - lines.insert(0, "") - print(" --%-30s %s" % (prefix, lines[0]), file=file) - for line in lines[1:]: - print("%-34s %s" % (" ", line), file=file) - print(file=file) - - def _help_callback(self, value: bool) -> None: - if value: - self.print_help() - sys.exit(0) - - def add_parse_callback(self, callback: Callable[[], None]) -> None: - """Adds a parse callback, to be invoked when option parsing is done.""" - self._parse_callbacks.append(callback) - - def run_parse_callbacks(self) -> None: - for callback in self._parse_callbacks: - callback() - - def mockable(self) -> "_Mockable": - """Returns a wrapper around self that is compatible with - `mock.patch <unittest.mock.patch>`. - - The `mock.patch <unittest.mock.patch>` function (included in - the standard library `unittest.mock` package since Python 3.3, - or in the third-party ``mock`` package for older versions of - Python) is incompatible with objects like ``options`` that - override ``__getattr__`` and ``__setattr__``. This function - returns an object that can be used with `mock.patch.object - <unittest.mock.patch.object>` to modify option values:: - - with mock.patch.object(options.mockable(), 'name', value): - assert options.name == value - """ - return _Mockable(self) - - -class _Mockable(object): - """`mock.patch` compatible wrapper for `OptionParser`. - - As of ``mock`` version 1.0.1, when an object uses ``__getattr__`` - hooks instead of ``__dict__``, ``patch.__exit__`` tries to delete - the attribute it set instead of setting a new one (assuming that - the object does not capture ``__setattr__``, so the patch - created a new attribute in ``__dict__``). - - _Mockable's getattr and setattr pass through to the underlying - OptionParser, and delattr undoes the effect of a previous setattr. - """ - - def __init__(self, options: OptionParser) -> None: - # Modify __dict__ directly to bypass __setattr__ - self.__dict__["_options"] = options - self.__dict__["_originals"] = {} - - def __getattr__(self, name: str) -> Any: - return getattr(self._options, name) - - def __setattr__(self, name: str, value: Any) -> None: - assert name not in self._originals, "don't reuse mockable objects" - self._originals[name] = getattr(self._options, name) - setattr(self._options, name, value) - - def __delattr__(self, name: str) -> None: - setattr(self._options, name, self._originals.pop(name)) - - -class _Option(object): - # This class could almost be made generic, but the way the types - # interact with the multiple argument makes this tricky. (default - # and the callback use List[T], but type is still Type[T]). - UNSET = object() - - def __init__( - self, - name: str, - default: Any = None, - type: Optional[type] = None, - help: Optional[str] = None, - metavar: Optional[str] = None, - multiple: bool = False, - file_name: Optional[str] = None, - group_name: Optional[str] = None, - callback: Optional[Callable[[Any], None]] = None, - ) -> None: - if default is None and multiple: - default = [] - self.name = name - if type is None: - raise ValueError("type must not be None") - self.type = type - self.help = help - self.metavar = metavar - self.multiple = multiple - self.file_name = file_name - self.group_name = group_name - self.callback = callback - self.default = default - self._value = _Option.UNSET # type: Any - - def value(self) -> Any: - return self.default if self._value is _Option.UNSET else self._value - - def parse(self, value: str) -> Any: - _parse = { - datetime.datetime: self._parse_datetime, - datetime.timedelta: self._parse_timedelta, - bool: self._parse_bool, - basestring_type: self._parse_string, - }.get( - self.type, self.type - ) # type: Callable[[str], Any] - if self.multiple: - self._value = [] - for part in value.split(","): - if issubclass(self.type, numbers.Integral): - # allow ranges of the form X:Y (inclusive at both ends) - lo_str, _, hi_str = part.partition(":") - lo = _parse(lo_str) - hi = _parse(hi_str) if hi_str else lo - self._value.extend(range(lo, hi + 1)) - else: - self._value.append(_parse(part)) - else: - self._value = _parse(value) - if self.callback is not None: - self.callback(self._value) - return self.value() - - def set(self, value: Any) -> None: - if self.multiple: - if not isinstance(value, list): - raise Error( - "Option %r is required to be a list of %s" - % (self.name, self.type.__name__) - ) - for item in value: - if item is not None and not isinstance(item, self.type): - raise Error( - "Option %r is required to be a list of %s" - % (self.name, self.type.__name__) - ) - else: - if value is not None and not isinstance(value, self.type): - raise Error( - "Option %r is required to be a %s (%s given)" - % (self.name, self.type.__name__, type(value)) - ) - self._value = value - if self.callback is not None: - self.callback(self._value) - - # Supported date/time formats in our options - _DATETIME_FORMATS = [ - "%a %b %d %H:%M:%S %Y", - "%Y-%m-%d %H:%M:%S", - "%Y-%m-%d %H:%M", - "%Y-%m-%dT%H:%M", - "%Y%m%d %H:%M:%S", - "%Y%m%d %H:%M", - "%Y-%m-%d", - "%Y%m%d", - "%H:%M:%S", - "%H:%M", - ] - - def _parse_datetime(self, value: str) -> datetime.datetime: - for format in self._DATETIME_FORMATS: - try: - return datetime.datetime.strptime(value, format) - except ValueError: - pass - raise Error("Unrecognized date/time format: %r" % value) - - _TIMEDELTA_ABBREV_DICT = { - "h": "hours", - "m": "minutes", - "min": "minutes", - "s": "seconds", - "sec": "seconds", - "ms": "milliseconds", - "us": "microseconds", - "d": "days", - "w": "weeks", - } - - _FLOAT_PATTERN = r"[-+]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][-+]?\d+)?" - - _TIMEDELTA_PATTERN = re.compile( - r"\s*(%s)\s*(\w*)\s*" % _FLOAT_PATTERN, re.IGNORECASE - ) - - def _parse_timedelta(self, value: str) -> datetime.timedelta: - try: - sum = datetime.timedelta() - start = 0 - while start < len(value): - m = self._TIMEDELTA_PATTERN.match(value, start) - if not m: - raise Exception() - num = float(m.group(1)) - units = m.group(2) or "seconds" - units = self._TIMEDELTA_ABBREV_DICT.get(units, units) - sum += datetime.timedelta(**{units: num}) - start = m.end() - return sum - except Exception: - raise - - def _parse_bool(self, value: str) -> bool: - return value.lower() not in ("false", "0", "f") - - def _parse_string(self, value: str) -> str: - return _unicode(value) - - -options = OptionParser() -"""Global options object. - -All defined options are available as attributes on this object. -""" - - -def define( - name: str, - default: Any = None, - type: Optional[type] = None, - help: Optional[str] = None, - metavar: Optional[str] = None, - multiple: bool = False, - group: Optional[str] = None, - callback: Optional[Callable[[Any], None]] = None, -) -> None: - """Defines an option in the global namespace. - - See `OptionParser.define`. - """ - return options.define( - name, - default=default, - type=type, - help=help, - metavar=metavar, - multiple=multiple, - group=group, - callback=callback, - ) - - -def parse_command_line( - args: Optional[List[str]] = None, final: bool = True -) -> List[str]: - """Parses global options from the command line. - - See `OptionParser.parse_command_line`. - """ - return options.parse_command_line(args, final=final) - - -def parse_config_file(path: str, final: bool = True) -> None: - """Parses global options from a config file. - - See `OptionParser.parse_config_file`. - """ - return options.parse_config_file(path, final=final) - - -def print_help(file: Optional[TextIO] = None) -> None: - """Prints all the command line options to stderr (or another file). - - See `OptionParser.print_help`. - """ - return options.print_help(file) - - -def add_parse_callback(callback: Callable[[], None]) -> None: - """Adds a parse callback, to be invoked when option parsing is done. - - See `OptionParser.add_parse_callback` - """ - options.add_parse_callback(callback) - - -# Default options -define_logging_options(options) diff --git a/venv/lib/python3.8/site-packages/tornado/platform/__init__.py b/venv/lib/python3.8/site-packages/tornado/platform/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.8/site-packages/tornado/platform/asyncio.py b/venv/lib/python3.8/site-packages/tornado/platform/asyncio.py deleted file mode 100644 index 012948b..0000000 --- a/venv/lib/python3.8/site-packages/tornado/platform/asyncio.py +++ /dev/null @@ -1,611 +0,0 @@ -"""Bridges between the `asyncio` module and Tornado IOLoop. - -.. versionadded:: 3.2 - -This module integrates Tornado with the ``asyncio`` module introduced -in Python 3.4. This makes it possible to combine the two libraries on -the same event loop. - -.. deprecated:: 5.0 - - While the code in this module is still used, it is now enabled - automatically when `asyncio` is available, so applications should - no longer need to refer to this module directly. - -.. note:: - - Tornado is designed to use a selector-based event loop. On Windows, - where a proactor-based event loop has been the default since Python 3.8, - a selector event loop is emulated by running ``select`` on a separate thread. - Configuring ``asyncio`` to use a selector event loop may improve performance - of Tornado (but may reduce performance of other ``asyncio``-based libraries - in the same process). -""" - -import asyncio -import atexit -import concurrent.futures -import errno -import functools -import select -import socket -import sys -import threading -import typing -from tornado.gen import convert_yielded -from tornado.ioloop import IOLoop, _Selectable - -from typing import Any, TypeVar, Awaitable, Callable, Union, Optional, List, Tuple, Dict - -if typing.TYPE_CHECKING: - from typing import Set # noqa: F401 - from typing_extensions import Protocol - - class _HasFileno(Protocol): - def fileno(self) -> int: - pass - - _FileDescriptorLike = Union[int, _HasFileno] - -_T = TypeVar("_T") - - -# Collection of selector thread event loops to shut down on exit. -_selector_loops = set() # type: Set[AddThreadSelectorEventLoop] - - -def _atexit_callback() -> None: - for loop in _selector_loops: - with loop._select_cond: - loop._closing_selector = True - loop._select_cond.notify() - try: - loop._waker_w.send(b"a") - except BlockingIOError: - pass - # If we don't join our (daemon) thread here, we may get a deadlock - # during interpreter shutdown. I don't really understand why. This - # deadlock happens every time in CI (both travis and appveyor) but - # I've never been able to reproduce locally. - loop._thread.join() - _selector_loops.clear() - - -atexit.register(_atexit_callback) - - -class BaseAsyncIOLoop(IOLoop): - def initialize( # type: ignore - self, asyncio_loop: asyncio.AbstractEventLoop, **kwargs: Any - ) -> None: - # asyncio_loop is always the real underlying IOLoop. This is used in - # ioloop.py to maintain the asyncio-to-ioloop mappings. - self.asyncio_loop = asyncio_loop - # selector_loop is an event loop that implements the add_reader family of - # methods. Usually the same as asyncio_loop but differs on platforms such - # as windows where the default event loop does not implement these methods. - self.selector_loop = asyncio_loop - if hasattr(asyncio, "ProactorEventLoop") and isinstance( - asyncio_loop, asyncio.ProactorEventLoop # type: ignore - ): - # Ignore this line for mypy because the abstract method checker - # doesn't understand dynamic proxies. - self.selector_loop = AddThreadSelectorEventLoop(asyncio_loop) # type: ignore - # Maps fd to (fileobj, handler function) pair (as in IOLoop.add_handler) - self.handlers = {} # type: Dict[int, Tuple[Union[int, _Selectable], Callable]] - # Set of fds listening for reads/writes - self.readers = set() # type: Set[int] - self.writers = set() # type: Set[int] - self.closing = False - # If an asyncio loop was closed through an asyncio interface - # instead of IOLoop.close(), we'd never hear about it and may - # have left a dangling reference in our map. In case an - # application (or, more likely, a test suite) creates and - # destroys a lot of event loops in this way, check here to - # ensure that we don't have a lot of dead loops building up in - # the map. - # - # TODO(bdarnell): consider making self.asyncio_loop a weakref - # for AsyncIOMainLoop and make _ioloop_for_asyncio a - # WeakKeyDictionary. - for loop in list(IOLoop._ioloop_for_asyncio): - if loop.is_closed(): - del IOLoop._ioloop_for_asyncio[loop] - IOLoop._ioloop_for_asyncio[asyncio_loop] = self - - self._thread_identity = 0 - - super().initialize(**kwargs) - - def assign_thread_identity() -> None: - self._thread_identity = threading.get_ident() - - self.add_callback(assign_thread_identity) - - def close(self, all_fds: bool = False) -> None: - self.closing = True - for fd in list(self.handlers): - fileobj, handler_func = self.handlers[fd] - self.remove_handler(fd) - if all_fds: - self.close_fd(fileobj) - # Remove the mapping before closing the asyncio loop. If this - # happened in the other order, we could race against another - # initialize() call which would see the closed asyncio loop, - # assume it was closed from the asyncio side, and do this - # cleanup for us, leading to a KeyError. - del IOLoop._ioloop_for_asyncio[self.asyncio_loop] - if self.selector_loop is not self.asyncio_loop: - self.selector_loop.close() - self.asyncio_loop.close() - - def add_handler( - self, fd: Union[int, _Selectable], handler: Callable[..., None], events: int - ) -> None: - fd, fileobj = self.split_fd(fd) - if fd in self.handlers: - raise ValueError("fd %s added twice" % fd) - self.handlers[fd] = (fileobj, handler) - if events & IOLoop.READ: - self.selector_loop.add_reader(fd, self._handle_events, fd, IOLoop.READ) - self.readers.add(fd) - if events & IOLoop.WRITE: - self.selector_loop.add_writer(fd, self._handle_events, fd, IOLoop.WRITE) - self.writers.add(fd) - - def update_handler(self, fd: Union[int, _Selectable], events: int) -> None: - fd, fileobj = self.split_fd(fd) - if events & IOLoop.READ: - if fd not in self.readers: - self.selector_loop.add_reader(fd, self._handle_events, fd, IOLoop.READ) - self.readers.add(fd) - else: - if fd in self.readers: - self.selector_loop.remove_reader(fd) - self.readers.remove(fd) - if events & IOLoop.WRITE: - if fd not in self.writers: - self.selector_loop.add_writer(fd, self._handle_events, fd, IOLoop.WRITE) - self.writers.add(fd) - else: - if fd in self.writers: - self.selector_loop.remove_writer(fd) - self.writers.remove(fd) - - def remove_handler(self, fd: Union[int, _Selectable]) -> None: - fd, fileobj = self.split_fd(fd) - if fd not in self.handlers: - return - if fd in self.readers: - self.selector_loop.remove_reader(fd) - self.readers.remove(fd) - if fd in self.writers: - self.selector_loop.remove_writer(fd) - self.writers.remove(fd) - del self.handlers[fd] - - def _handle_events(self, fd: int, events: int) -> None: - fileobj, handler_func = self.handlers[fd] - handler_func(fileobj, events) - - def start(self) -> None: - try: - old_loop = asyncio.get_event_loop() - except (RuntimeError, AssertionError): - old_loop = None # type: ignore - try: - self._setup_logging() - asyncio.set_event_loop(self.asyncio_loop) - self.asyncio_loop.run_forever() - finally: - asyncio.set_event_loop(old_loop) - - def stop(self) -> None: - self.asyncio_loop.stop() - - def call_at( - self, when: float, callback: Callable[..., None], *args: Any, **kwargs: Any - ) -> object: - # asyncio.call_at supports *args but not **kwargs, so bind them here. - # We do not synchronize self.time and asyncio_loop.time, so - # convert from absolute to relative. - return self.asyncio_loop.call_later( - max(0, when - self.time()), - self._run_callback, - functools.partial(callback, *args, **kwargs), - ) - - def remove_timeout(self, timeout: object) -> None: - timeout.cancel() # type: ignore - - def add_callback(self, callback: Callable, *args: Any, **kwargs: Any) -> None: - if threading.get_ident() == self._thread_identity: - call_soon = self.asyncio_loop.call_soon - else: - call_soon = self.asyncio_loop.call_soon_threadsafe - try: - call_soon(self._run_callback, functools.partial(callback, *args, **kwargs)) - except RuntimeError: - # "Event loop is closed". Swallow the exception for - # consistency with PollIOLoop (and logical consistency - # with the fact that we can't guarantee that an - # add_callback that completes without error will - # eventually execute). - pass - except AttributeError: - # ProactorEventLoop may raise this instead of RuntimeError - # if call_soon_threadsafe races with a call to close(). - # Swallow it too for consistency. - pass - - def add_callback_from_signal( - self, callback: Callable, *args: Any, **kwargs: Any - ) -> None: - try: - self.asyncio_loop.call_soon_threadsafe( - self._run_callback, functools.partial(callback, *args, **kwargs) - ) - except RuntimeError: - pass - - def run_in_executor( - self, - executor: Optional[concurrent.futures.Executor], - func: Callable[..., _T], - *args: Any - ) -> Awaitable[_T]: - return self.asyncio_loop.run_in_executor(executor, func, *args) - - def set_default_executor(self, executor: concurrent.futures.Executor) -> None: - return self.asyncio_loop.set_default_executor(executor) - - -class AsyncIOMainLoop(BaseAsyncIOLoop): - """``AsyncIOMainLoop`` creates an `.IOLoop` that corresponds to the - current ``asyncio`` event loop (i.e. the one returned by - ``asyncio.get_event_loop()``). - - .. deprecated:: 5.0 - - Now used automatically when appropriate; it is no longer necessary - to refer to this class directly. - - .. versionchanged:: 5.0 - - Closing an `AsyncIOMainLoop` now closes the underlying asyncio loop. - """ - - def initialize(self, **kwargs: Any) -> None: # type: ignore - super().initialize(asyncio.get_event_loop(), **kwargs) - - def make_current(self) -> None: - # AsyncIOMainLoop already refers to the current asyncio loop so - # nothing to do here. - pass - - -class AsyncIOLoop(BaseAsyncIOLoop): - """``AsyncIOLoop`` is an `.IOLoop` that runs on an ``asyncio`` event loop. - This class follows the usual Tornado semantics for creating new - ``IOLoops``; these loops are not necessarily related to the - ``asyncio`` default event loop. - - Each ``AsyncIOLoop`` creates a new ``asyncio.EventLoop``; this object - can be accessed with the ``asyncio_loop`` attribute. - - .. versionchanged:: 5.0 - - When an ``AsyncIOLoop`` becomes the current `.IOLoop`, it also sets - the current `asyncio` event loop. - - .. deprecated:: 5.0 - - Now used automatically when appropriate; it is no longer necessary - to refer to this class directly. - """ - - def initialize(self, **kwargs: Any) -> None: # type: ignore - self.is_current = False - loop = asyncio.new_event_loop() - try: - super().initialize(loop, **kwargs) - except Exception: - # If initialize() does not succeed (taking ownership of the loop), - # we have to close it. - loop.close() - raise - - def close(self, all_fds: bool = False) -> None: - if self.is_current: - self.clear_current() - super().close(all_fds=all_fds) - - def make_current(self) -> None: - if not self.is_current: - try: - self.old_asyncio = asyncio.get_event_loop() - except (RuntimeError, AssertionError): - self.old_asyncio = None # type: ignore - self.is_current = True - asyncio.set_event_loop(self.asyncio_loop) - - def _clear_current_hook(self) -> None: - if self.is_current: - asyncio.set_event_loop(self.old_asyncio) - self.is_current = False - - -def to_tornado_future(asyncio_future: asyncio.Future) -> asyncio.Future: - """Convert an `asyncio.Future` to a `tornado.concurrent.Future`. - - .. versionadded:: 4.1 - - .. deprecated:: 5.0 - Tornado ``Futures`` have been merged with `asyncio.Future`, - so this method is now a no-op. - """ - return asyncio_future - - -def to_asyncio_future(tornado_future: asyncio.Future) -> asyncio.Future: - """Convert a Tornado yieldable object to an `asyncio.Future`. - - .. versionadded:: 4.1 - - .. versionchanged:: 4.3 - Now accepts any yieldable object, not just - `tornado.concurrent.Future`. - - .. deprecated:: 5.0 - Tornado ``Futures`` have been merged with `asyncio.Future`, - so this method is now equivalent to `tornado.gen.convert_yielded`. - """ - return convert_yielded(tornado_future) - - -if sys.platform == "win32" and hasattr(asyncio, "WindowsSelectorEventLoopPolicy"): - # "Any thread" and "selector" should be orthogonal, but there's not a clean - # interface for composing policies so pick the right base. - _BasePolicy = asyncio.WindowsSelectorEventLoopPolicy # type: ignore -else: - _BasePolicy = asyncio.DefaultEventLoopPolicy - - -class AnyThreadEventLoopPolicy(_BasePolicy): # type: ignore - """Event loop policy that allows loop creation on any thread. - - The default `asyncio` event loop policy only automatically creates - event loops in the main threads. Other threads must create event - loops explicitly or `asyncio.get_event_loop` (and therefore - `.IOLoop.current`) will fail. Installing this policy allows event - loops to be created automatically on any thread, matching the - behavior of Tornado versions prior to 5.0 (or 5.0 on Python 2). - - Usage:: - - asyncio.set_event_loop_policy(AnyThreadEventLoopPolicy()) - - .. versionadded:: 5.0 - - """ - - def get_event_loop(self) -> asyncio.AbstractEventLoop: - try: - return super().get_event_loop() - except (RuntimeError, AssertionError): - # This was an AssertionError in Python 3.4.2 (which ships with Debian Jessie) - # and changed to a RuntimeError in 3.4.3. - # "There is no current event loop in thread %r" - loop = self.new_event_loop() - self.set_event_loop(loop) - return loop - - -class AddThreadSelectorEventLoop(asyncio.AbstractEventLoop): - """Wrap an event loop to add implementations of the ``add_reader`` method family. - - Instances of this class start a second thread to run a selector. - This thread is completely hidden from the user; all callbacks are - run on the wrapped event loop's thread. - - This class is used automatically by Tornado; applications should not need - to refer to it directly. - - It is safe to wrap any event loop with this class, although it only makes sense - for event loops that do not implement the ``add_reader`` family of methods - themselves (i.e. ``WindowsProactorEventLoop``) - - Closing the ``AddThreadSelectorEventLoop`` also closes the wrapped event loop. - - """ - - # This class is a __getattribute__-based proxy. All attributes other than those - # in this set are proxied through to the underlying loop. - MY_ATTRIBUTES = { - "_consume_waker", - "_select_cond", - "_select_args", - "_closing_selector", - "_thread", - "_handle_event", - "_readers", - "_real_loop", - "_start_select", - "_run_select", - "_handle_select", - "_wake_selector", - "_waker_r", - "_waker_w", - "_writers", - "add_reader", - "add_writer", - "close", - "remove_reader", - "remove_writer", - } - - def __getattribute__(self, name: str) -> Any: - if name in AddThreadSelectorEventLoop.MY_ATTRIBUTES: - return super().__getattribute__(name) - return getattr(self._real_loop, name) - - def __init__(self, real_loop: asyncio.AbstractEventLoop) -> None: - self._real_loop = real_loop - - # Create a thread to run the select system call. We manage this thread - # manually so we can trigger a clean shutdown from an atexit hook. Note - # that due to the order of operations at shutdown, only daemon threads - # can be shut down in this way (non-daemon threads would require the - # introduction of a new hook: https://bugs.python.org/issue41962) - self._select_cond = threading.Condition() - self._select_args = ( - None - ) # type: Optional[Tuple[List[_FileDescriptorLike], List[_FileDescriptorLike]]] - self._closing_selector = False - self._thread = threading.Thread( - name="Tornado selector", daemon=True, target=self._run_select, - ) - self._thread.start() - # Start the select loop once the loop is started. - self._real_loop.call_soon(self._start_select) - - self._readers = {} # type: Dict[_FileDescriptorLike, Callable] - self._writers = {} # type: Dict[_FileDescriptorLike, Callable] - - # Writing to _waker_w will wake up the selector thread, which - # watches for _waker_r to be readable. - self._waker_r, self._waker_w = socket.socketpair() - self._waker_r.setblocking(False) - self._waker_w.setblocking(False) - _selector_loops.add(self) - self.add_reader(self._waker_r, self._consume_waker) - - def __del__(self) -> None: - # If the top-level application code uses asyncio interfaces to - # start and stop the event loop, no objects created in Tornado - # can get a clean shutdown notification. If we're just left to - # be GC'd, we must explicitly close our sockets to avoid - # logging warnings. - _selector_loops.discard(self) - self._waker_r.close() - self._waker_w.close() - - def close(self) -> None: - with self._select_cond: - self._closing_selector = True - self._select_cond.notify() - self._wake_selector() - self._thread.join() - _selector_loops.discard(self) - self._waker_r.close() - self._waker_w.close() - self._real_loop.close() - - def _wake_selector(self) -> None: - try: - self._waker_w.send(b"a") - except BlockingIOError: - pass - - def _consume_waker(self) -> None: - try: - self._waker_r.recv(1024) - except BlockingIOError: - pass - - def _start_select(self) -> None: - # Capture reader and writer sets here in the event loop - # thread to avoid any problems with concurrent - # modification while the select loop uses them. - with self._select_cond: - assert self._select_args is None - self._select_args = (list(self._readers.keys()), list(self._writers.keys())) - self._select_cond.notify() - - def _run_select(self) -> None: - while True: - with self._select_cond: - while self._select_args is None and not self._closing_selector: - self._select_cond.wait() - if self._closing_selector: - return - assert self._select_args is not None - to_read, to_write = self._select_args - self._select_args = None - - # We use the simpler interface of the select module instead of - # the more stateful interface in the selectors module because - # this class is only intended for use on windows, where - # select.select is the only option. The selector interface - # does not have well-documented thread-safety semantics that - # we can rely on so ensuring proper synchronization would be - # tricky. - try: - # On windows, selecting on a socket for write will not - # return the socket when there is an error (but selecting - # for reads works). Also select for errors when selecting - # for writes, and merge the results. - # - # This pattern is also used in - # https://github.com/python/cpython/blob/v3.8.0/Lib/selectors.py#L312-L317 - rs, ws, xs = select.select(to_read, to_write, to_write) - ws = ws + xs - except OSError as e: - # After remove_reader or remove_writer is called, the file - # descriptor may subsequently be closed on the event loop - # thread. It's possible that this select thread hasn't - # gotten into the select system call by the time that - # happens in which case (at least on macOS), select may - # raise a "bad file descriptor" error. If we get that - # error, check and see if we're also being woken up by - # polling the waker alone. If we are, just return to the - # event loop and we'll get the updated set of file - # descriptors on the next iteration. Otherwise, raise the - # original error. - if e.errno == getattr(errno, "WSAENOTSOCK", errno.EBADF): - rs, _, _ = select.select([self._waker_r.fileno()], [], [], 0) - if rs: - ws = [] - else: - raise - else: - raise - self._real_loop.call_soon_threadsafe(self._handle_select, rs, ws) - - def _handle_select( - self, rs: List["_FileDescriptorLike"], ws: List["_FileDescriptorLike"] - ) -> None: - for r in rs: - self._handle_event(r, self._readers) - for w in ws: - self._handle_event(w, self._writers) - self._start_select() - - def _handle_event( - self, fd: "_FileDescriptorLike", cb_map: Dict["_FileDescriptorLike", Callable], - ) -> None: - try: - callback = cb_map[fd] - except KeyError: - return - callback() - - def add_reader( - self, fd: "_FileDescriptorLike", callback: Callable[..., None], *args: Any - ) -> None: - self._readers[fd] = functools.partial(callback, *args) - self._wake_selector() - - def add_writer( - self, fd: "_FileDescriptorLike", callback: Callable[..., None], *args: Any - ) -> None: - self._writers[fd] = functools.partial(callback, *args) - self._wake_selector() - - def remove_reader(self, fd: "_FileDescriptorLike") -> None: - del self._readers[fd] - self._wake_selector() - - def remove_writer(self, fd: "_FileDescriptorLike") -> None: - del self._writers[fd] - self._wake_selector() diff --git a/venv/lib/python3.8/site-packages/tornado/platform/caresresolver.py b/venv/lib/python3.8/site-packages/tornado/platform/caresresolver.py deleted file mode 100644 index e2c5009..0000000 --- a/venv/lib/python3.8/site-packages/tornado/platform/caresresolver.py +++ /dev/null @@ -1,89 +0,0 @@ -import pycares # type: ignore -import socket - -from tornado.concurrent import Future -from tornado import gen -from tornado.ioloop import IOLoop -from tornado.netutil import Resolver, is_valid_ip - -import typing - -if typing.TYPE_CHECKING: - from typing import Generator, Any, List, Tuple, Dict # noqa: F401 - - -class CaresResolver(Resolver): - """Name resolver based on the c-ares library. - - This is a non-blocking and non-threaded resolver. It may not produce - the same results as the system resolver, but can be used for non-blocking - resolution when threads cannot be used. - - c-ares fails to resolve some names when ``family`` is ``AF_UNSPEC``, - so it is only recommended for use in ``AF_INET`` (i.e. IPv4). This is - the default for ``tornado.simple_httpclient``, but other libraries - may default to ``AF_UNSPEC``. - - .. versionchanged:: 5.0 - The ``io_loop`` argument (deprecated since version 4.1) has been removed. - """ - - def initialize(self) -> None: - self.io_loop = IOLoop.current() - self.channel = pycares.Channel(sock_state_cb=self._sock_state_cb) - self.fds = {} # type: Dict[int, int] - - def _sock_state_cb(self, fd: int, readable: bool, writable: bool) -> None: - state = (IOLoop.READ if readable else 0) | (IOLoop.WRITE if writable else 0) - if not state: - self.io_loop.remove_handler(fd) - del self.fds[fd] - elif fd in self.fds: - self.io_loop.update_handler(fd, state) - self.fds[fd] = state - else: - self.io_loop.add_handler(fd, self._handle_events, state) - self.fds[fd] = state - - def _handle_events(self, fd: int, events: int) -> None: - read_fd = pycares.ARES_SOCKET_BAD - write_fd = pycares.ARES_SOCKET_BAD - if events & IOLoop.READ: - read_fd = fd - if events & IOLoop.WRITE: - write_fd = fd - self.channel.process_fd(read_fd, write_fd) - - @gen.coroutine - def resolve( - self, host: str, port: int, family: int = 0 - ) -> "Generator[Any, Any, List[Tuple[int, Any]]]": - if is_valid_ip(host): - addresses = [host] - else: - # gethostbyname doesn't take callback as a kwarg - fut = Future() # type: Future[Tuple[Any, Any]] - self.channel.gethostbyname( - host, family, lambda result, error: fut.set_result((result, error)) - ) - result, error = yield fut - if error: - raise IOError( - "C-Ares returned error %s: %s while resolving %s" - % (error, pycares.errno.strerror(error), host) - ) - addresses = result.addresses - addrinfo = [] - for address in addresses: - if "." in address: - address_family = socket.AF_INET - elif ":" in address: - address_family = socket.AF_INET6 - else: - address_family = socket.AF_UNSPEC - if family != socket.AF_UNSPEC and family != address_family: - raise IOError( - "Requested socket family %d but got %d" % (family, address_family) - ) - addrinfo.append((typing.cast(int, address_family), (address, port))) - return addrinfo diff --git a/venv/lib/python3.8/site-packages/tornado/platform/twisted.py b/venv/lib/python3.8/site-packages/tornado/platform/twisted.py deleted file mode 100644 index 0987a84..0000000 --- a/venv/lib/python3.8/site-packages/tornado/platform/twisted.py +++ /dev/null @@ -1,146 +0,0 @@ -# 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. -"""Bridges between the Twisted package and Tornado. -""" - -import socket -import sys - -import twisted.internet.abstract # type: ignore -import twisted.internet.asyncioreactor # type: ignore -from twisted.internet.defer import Deferred # type: ignore -from twisted.python import failure # type: ignore -import twisted.names.cache # type: ignore -import twisted.names.client # type: ignore -import twisted.names.hosts # type: ignore -import twisted.names.resolve # type: ignore - - -from tornado.concurrent import Future, future_set_exc_info -from tornado.escape import utf8 -from tornado import gen -from tornado.netutil import Resolver - -import typing - -if typing.TYPE_CHECKING: - from typing import Generator, Any, List, Tuple # noqa: F401 - - -class TwistedResolver(Resolver): - """Twisted-based asynchronous resolver. - - This is a non-blocking and non-threaded resolver. It is - recommended only when threads cannot be used, since it has - limitations compared to the standard ``getaddrinfo``-based - `~tornado.netutil.Resolver` and - `~tornado.netutil.DefaultExecutorResolver`. Specifically, it returns at - most one result, and arguments other than ``host`` and ``family`` - are ignored. It may fail to resolve when ``family`` is not - ``socket.AF_UNSPEC``. - - Requires Twisted 12.1 or newer. - - .. versionchanged:: 5.0 - The ``io_loop`` argument (deprecated since version 4.1) has been removed. - """ - - def initialize(self) -> None: - # partial copy of twisted.names.client.createResolver, which doesn't - # allow for a reactor to be passed in. - self.reactor = twisted.internet.asyncioreactor.AsyncioSelectorReactor() - - host_resolver = twisted.names.hosts.Resolver("/etc/hosts") - cache_resolver = twisted.names.cache.CacheResolver(reactor=self.reactor) - real_resolver = twisted.names.client.Resolver( - "/etc/resolv.conf", reactor=self.reactor - ) - self.resolver = twisted.names.resolve.ResolverChain( - [host_resolver, cache_resolver, real_resolver] - ) - - @gen.coroutine - def resolve( - self, host: str, port: int, family: int = 0 - ) -> "Generator[Any, Any, List[Tuple[int, Any]]]": - # getHostByName doesn't accept IP addresses, so if the input - # looks like an IP address just return it immediately. - if twisted.internet.abstract.isIPAddress(host): - resolved = host - resolved_family = socket.AF_INET - elif twisted.internet.abstract.isIPv6Address(host): - resolved = host - resolved_family = socket.AF_INET6 - else: - deferred = self.resolver.getHostByName(utf8(host)) - fut = Future() # type: Future[Any] - deferred.addBoth(fut.set_result) - resolved = yield fut - if isinstance(resolved, failure.Failure): - try: - resolved.raiseException() - except twisted.names.error.DomainError as e: - raise IOError(e) - elif twisted.internet.abstract.isIPAddress(resolved): - resolved_family = socket.AF_INET - elif twisted.internet.abstract.isIPv6Address(resolved): - resolved_family = socket.AF_INET6 - else: - resolved_family = socket.AF_UNSPEC - if family != socket.AF_UNSPEC and family != resolved_family: - raise Exception( - "Requested socket family %d but got %d" % (family, resolved_family) - ) - result = [(typing.cast(int, resolved_family), (resolved, port))] - return result - - -def install() -> None: - """Install ``AsyncioSelectorReactor`` as the default Twisted reactor. - - .. deprecated:: 5.1 - - This function is provided for backwards compatibility; code - that does not require compatibility with older versions of - Tornado should use - ``twisted.internet.asyncioreactor.install()`` directly. - - .. versionchanged:: 6.0.3 - - In Tornado 5.x and before, this function installed a reactor - based on the Tornado ``IOLoop``. When that reactor - implementation was removed in Tornado 6.0.0, this function was - removed as well. It was restored in Tornado 6.0.3 using the - ``asyncio`` reactor instead. - - """ - from twisted.internet.asyncioreactor import install - - install() - - -if hasattr(gen.convert_yielded, "register"): - - @gen.convert_yielded.register(Deferred) # type: ignore - def _(d: Deferred) -> Future: - f = Future() # type: Future[Any] - - def errback(failure: failure.Failure) -> None: - try: - failure.raiseException() - # Should never happen, but just in case - raise Exception("errback called without error") - except: - future_set_exc_info(f, sys.exc_info()) - - d.addCallbacks(f.set_result, errback) - return f diff --git a/venv/lib/python3.8/site-packages/tornado/process.py b/venv/lib/python3.8/site-packages/tornado/process.py deleted file mode 100644 index 26428fe..0000000 --- a/venv/lib/python3.8/site-packages/tornado/process.py +++ /dev/null @@ -1,373 +0,0 @@ -# -# Copyright 2011 Facebook -# -# 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. - -"""Utilities for working with multiple processes, including both forking -the server into multiple processes and managing subprocesses. -""" - -import os -import multiprocessing -import signal -import subprocess -import sys -import time - -from binascii import hexlify - -from tornado.concurrent import ( - Future, - future_set_result_unless_cancelled, - future_set_exception_unless_cancelled, -) -from tornado import ioloop -from tornado.iostream import PipeIOStream -from tornado.log import gen_log - -import typing -from typing import Optional, Any, Callable - -if typing.TYPE_CHECKING: - from typing import List # noqa: F401 - -# Re-export this exception for convenience. -CalledProcessError = subprocess.CalledProcessError - - -def cpu_count() -> int: - """Returns the number of processors on this machine.""" - if multiprocessing is None: - return 1 - try: - return multiprocessing.cpu_count() - except NotImplementedError: - pass - try: - return os.sysconf("SC_NPROCESSORS_CONF") # type: ignore - except (AttributeError, ValueError): - pass - gen_log.error("Could not detect number of processors; assuming 1") - return 1 - - -def _reseed_random() -> None: - if "random" not in sys.modules: - return - import random - - # If os.urandom is available, this method does the same thing as - # random.seed (at least as of python 2.6). If os.urandom is not - # available, we mix in the pid in addition to a timestamp. - try: - seed = int(hexlify(os.urandom(16)), 16) - except NotImplementedError: - seed = int(time.time() * 1000) ^ os.getpid() - random.seed(seed) - - -_task_id = None - - -def fork_processes( - num_processes: Optional[int], max_restarts: Optional[int] = None -) -> int: - """Starts multiple worker processes. - - If ``num_processes`` is None or <= 0, we detect the number of cores - available on this machine and fork that number of child - processes. If ``num_processes`` is given and > 0, we fork that - specific number of sub-processes. - - Since we use processes and not threads, there is no shared memory - between any server code. - - Note that multiple processes are not compatible with the autoreload - module (or the ``autoreload=True`` option to `tornado.web.Application` - which defaults to True when ``debug=True``). - When using multiple processes, no IOLoops can be created or - referenced until after the call to ``fork_processes``. - - In each child process, ``fork_processes`` returns its *task id*, a - number between 0 and ``num_processes``. Processes that exit - abnormally (due to a signal or non-zero exit status) are restarted - with the same id (up to ``max_restarts`` times). In the parent - process, ``fork_processes`` calls ``sys.exit(0)`` after all child - processes have exited normally. - - max_restarts defaults to 100. - - Availability: Unix - """ - if sys.platform == "win32": - # The exact form of this condition matters to mypy; it understands - # if but not assert in this context. - raise Exception("fork not available on windows") - if max_restarts is None: - max_restarts = 100 - - global _task_id - assert _task_id is None - if num_processes is None or num_processes <= 0: - num_processes = cpu_count() - gen_log.info("Starting %d processes", num_processes) - children = {} - - def start_child(i: int) -> Optional[int]: - pid = os.fork() - if pid == 0: - # child process - _reseed_random() - global _task_id - _task_id = i - return i - else: - children[pid] = i - return None - - for i in range(num_processes): - id = start_child(i) - if id is not None: - return id - num_restarts = 0 - while children: - pid, status = os.wait() - if pid not in children: - continue - id = children.pop(pid) - if os.WIFSIGNALED(status): - gen_log.warning( - "child %d (pid %d) killed by signal %d, restarting", - id, - pid, - os.WTERMSIG(status), - ) - elif os.WEXITSTATUS(status) != 0: - gen_log.warning( - "child %d (pid %d) exited with status %d, restarting", - id, - pid, - os.WEXITSTATUS(status), - ) - else: - gen_log.info("child %d (pid %d) exited normally", id, pid) - continue - num_restarts += 1 - if num_restarts > max_restarts: - raise RuntimeError("Too many child restarts, giving up") - new_id = start_child(id) - if new_id is not None: - return new_id - # All child processes exited cleanly, so exit the master process - # instead of just returning to right after the call to - # fork_processes (which will probably just start up another IOLoop - # unless the caller checks the return value). - sys.exit(0) - - -def task_id() -> Optional[int]: - """Returns the current task id, if any. - - Returns None if this process was not created by `fork_processes`. - """ - global _task_id - return _task_id - - -class Subprocess(object): - """Wraps ``subprocess.Popen`` with IOStream support. - - The constructor is the same as ``subprocess.Popen`` with the following - additions: - - * ``stdin``, ``stdout``, and ``stderr`` may have the value - ``tornado.process.Subprocess.STREAM``, which will make the corresponding - attribute of the resulting Subprocess a `.PipeIOStream`. If this option - is used, the caller is responsible for closing the streams when done - with them. - - The ``Subprocess.STREAM`` option and the ``set_exit_callback`` and - ``wait_for_exit`` methods do not work on Windows. There is - therefore no reason to use this class instead of - ``subprocess.Popen`` on that platform. - - .. versionchanged:: 5.0 - The ``io_loop`` argument (deprecated since version 4.1) has been removed. - - """ - - STREAM = object() - - _initialized = False - _waiting = {} # type: ignore - _old_sigchld = None - - def __init__(self, *args: Any, **kwargs: Any) -> None: - self.io_loop = ioloop.IOLoop.current() - # All FDs we create should be closed on error; those in to_close - # should be closed in the parent process on success. - pipe_fds = [] # type: List[int] - to_close = [] # type: List[int] - if kwargs.get("stdin") is Subprocess.STREAM: - in_r, in_w = os.pipe() - kwargs["stdin"] = in_r - pipe_fds.extend((in_r, in_w)) - to_close.append(in_r) - self.stdin = PipeIOStream(in_w) - if kwargs.get("stdout") is Subprocess.STREAM: - out_r, out_w = os.pipe() - kwargs["stdout"] = out_w - pipe_fds.extend((out_r, out_w)) - to_close.append(out_w) - self.stdout = PipeIOStream(out_r) - if kwargs.get("stderr") is Subprocess.STREAM: - err_r, err_w = os.pipe() - kwargs["stderr"] = err_w - pipe_fds.extend((err_r, err_w)) - to_close.append(err_w) - self.stderr = PipeIOStream(err_r) - try: - self.proc = subprocess.Popen(*args, **kwargs) - except: - for fd in pipe_fds: - os.close(fd) - raise - for fd in to_close: - os.close(fd) - self.pid = self.proc.pid - for attr in ["stdin", "stdout", "stderr"]: - if not hasattr(self, attr): # don't clobber streams set above - setattr(self, attr, getattr(self.proc, attr)) - self._exit_callback = None # type: Optional[Callable[[int], None]] - self.returncode = None # type: Optional[int] - - def set_exit_callback(self, callback: Callable[[int], None]) -> None: - """Runs ``callback`` when this process exits. - - The callback takes one argument, the return code of the process. - - This method uses a ``SIGCHLD`` handler, which is a global setting - and may conflict if you have other libraries trying to handle the - same signal. If you are using more than one ``IOLoop`` it may - be necessary to call `Subprocess.initialize` first to designate - one ``IOLoop`` to run the signal handlers. - - In many cases a close callback on the stdout or stderr streams - can be used as an alternative to an exit callback if the - signal handler is causing a problem. - - Availability: Unix - """ - self._exit_callback = callback - Subprocess.initialize() - Subprocess._waiting[self.pid] = self - Subprocess._try_cleanup_process(self.pid) - - def wait_for_exit(self, raise_error: bool = True) -> "Future[int]": - """Returns a `.Future` which resolves when the process exits. - - Usage:: - - ret = yield proc.wait_for_exit() - - This is a coroutine-friendly alternative to `set_exit_callback` - (and a replacement for the blocking `subprocess.Popen.wait`). - - By default, raises `subprocess.CalledProcessError` if the process - has a non-zero exit status. Use ``wait_for_exit(raise_error=False)`` - to suppress this behavior and return the exit status without raising. - - .. versionadded:: 4.2 - - Availability: Unix - """ - future = Future() # type: Future[int] - - def callback(ret: int) -> None: - if ret != 0 and raise_error: - # Unfortunately we don't have the original args any more. - future_set_exception_unless_cancelled( - future, CalledProcessError(ret, "unknown") - ) - else: - future_set_result_unless_cancelled(future, ret) - - self.set_exit_callback(callback) - return future - - @classmethod - def initialize(cls) -> None: - """Initializes the ``SIGCHLD`` handler. - - The signal handler is run on an `.IOLoop` to avoid locking issues. - Note that the `.IOLoop` used for signal handling need not be the - same one used by individual Subprocess objects (as long as the - ``IOLoops`` are each running in separate threads). - - .. versionchanged:: 5.0 - The ``io_loop`` argument (deprecated since version 4.1) has been - removed. - - Availability: Unix - """ - if cls._initialized: - return - io_loop = ioloop.IOLoop.current() - cls._old_sigchld = signal.signal( - signal.SIGCHLD, - lambda sig, frame: io_loop.add_callback_from_signal(cls._cleanup), - ) - cls._initialized = True - - @classmethod - def uninitialize(cls) -> None: - """Removes the ``SIGCHLD`` handler.""" - if not cls._initialized: - return - signal.signal(signal.SIGCHLD, cls._old_sigchld) - cls._initialized = False - - @classmethod - def _cleanup(cls) -> None: - for pid in list(cls._waiting.keys()): # make a copy - cls._try_cleanup_process(pid) - - @classmethod - def _try_cleanup_process(cls, pid: int) -> None: - try: - ret_pid, status = os.waitpid(pid, os.WNOHANG) # type: ignore - except ChildProcessError: - return - if ret_pid == 0: - return - assert ret_pid == pid - subproc = cls._waiting.pop(pid) - subproc.io_loop.add_callback_from_signal(subproc._set_returncode, status) - - def _set_returncode(self, status: int) -> None: - if sys.platform == "win32": - self.returncode = -1 - else: - if os.WIFSIGNALED(status): - self.returncode = -os.WTERMSIG(status) - else: - assert os.WIFEXITED(status) - self.returncode = os.WEXITSTATUS(status) - # We've taken over wait() duty from the subprocess.Popen - # object. If we don't inform it of the process's return code, - # it will log a warning at destruction in python 3.6+. - self.proc.returncode = self.returncode - if self._exit_callback: - callback = self._exit_callback - self._exit_callback = None - callback(self.returncode) diff --git a/venv/lib/python3.8/site-packages/tornado/py.typed b/venv/lib/python3.8/site-packages/tornado/py.typed deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.8/site-packages/tornado/queues.py b/venv/lib/python3.8/site-packages/tornado/queues.py deleted file mode 100644 index 1e87f62..0000000 --- a/venv/lib/python3.8/site-packages/tornado/queues.py +++ /dev/null @@ -1,414 +0,0 @@ -# Copyright 2015 The Tornado Authors -# -# 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. - -"""Asynchronous queues for coroutines. These classes are very similar -to those provided in the standard library's `asyncio package -<https://docs.python.org/3/library/asyncio-queue.html>`_. - -.. warning:: - - Unlike the standard library's `queue` module, the classes defined here - are *not* thread-safe. To use these queues from another thread, - use `.IOLoop.add_callback` to transfer control to the `.IOLoop` thread - before calling any queue methods. - -""" - -import collections -import datetime -import heapq - -from tornado import gen, ioloop -from tornado.concurrent import Future, future_set_result_unless_cancelled -from tornado.locks import Event - -from typing import Union, TypeVar, Generic, Awaitable, Optional -import typing - -if typing.TYPE_CHECKING: - from typing import Deque, Tuple, Any # noqa: F401 - -_T = TypeVar("_T") - -__all__ = ["Queue", "PriorityQueue", "LifoQueue", "QueueFull", "QueueEmpty"] - - -class QueueEmpty(Exception): - """Raised by `.Queue.get_nowait` when the queue has no items.""" - - pass - - -class QueueFull(Exception): - """Raised by `.Queue.put_nowait` when a queue is at its maximum size.""" - - pass - - -def _set_timeout( - future: Future, timeout: Union[None, float, datetime.timedelta] -) -> None: - if timeout: - - def on_timeout() -> None: - if not future.done(): - future.set_exception(gen.TimeoutError()) - - io_loop = ioloop.IOLoop.current() - timeout_handle = io_loop.add_timeout(timeout, on_timeout) - future.add_done_callback(lambda _: io_loop.remove_timeout(timeout_handle)) - - -class _QueueIterator(Generic[_T]): - def __init__(self, q: "Queue[_T]") -> None: - self.q = q - - def __anext__(self) -> Awaitable[_T]: - return self.q.get() - - -class Queue(Generic[_T]): - """Coordinate producer and consumer coroutines. - - If maxsize is 0 (the default) the queue size is unbounded. - - .. testcode:: - - from tornado import gen - from tornado.ioloop import IOLoop - from tornado.queues import Queue - - q = Queue(maxsize=2) - - async def consumer(): - async for item in q: - try: - print('Doing work on %s' % item) - await gen.sleep(0.01) - finally: - q.task_done() - - async def producer(): - for item in range(5): - await q.put(item) - print('Put %s' % item) - - async def main(): - # Start consumer without waiting (since it never finishes). - IOLoop.current().spawn_callback(consumer) - await producer() # Wait for producer to put all tasks. - await q.join() # Wait for consumer to finish all tasks. - print('Done') - - IOLoop.current().run_sync(main) - - .. testoutput:: - - Put 0 - Put 1 - Doing work on 0 - Put 2 - Doing work on 1 - Put 3 - Doing work on 2 - Put 4 - Doing work on 3 - Doing work on 4 - Done - - - In versions of Python without native coroutines (before 3.5), - ``consumer()`` could be written as:: - - @gen.coroutine - def consumer(): - while True: - item = yield q.get() - try: - print('Doing work on %s' % item) - yield gen.sleep(0.01) - finally: - q.task_done() - - .. versionchanged:: 4.3 - Added ``async for`` support in Python 3.5. - - """ - - # Exact type depends on subclass. Could be another generic - # parameter and use protocols to be more precise here. - _queue = None # type: Any - - def __init__(self, maxsize: int = 0) -> None: - if maxsize is None: - raise TypeError("maxsize can't be None") - - if maxsize < 0: - raise ValueError("maxsize can't be negative") - - self._maxsize = maxsize - self._init() - self._getters = collections.deque([]) # type: Deque[Future[_T]] - self._putters = collections.deque([]) # type: Deque[Tuple[_T, Future[None]]] - self._unfinished_tasks = 0 - self._finished = Event() - self._finished.set() - - @property - def maxsize(self) -> int: - """Number of items allowed in the queue.""" - return self._maxsize - - def qsize(self) -> int: - """Number of items in the queue.""" - return len(self._queue) - - def empty(self) -> bool: - return not self._queue - - def full(self) -> bool: - if self.maxsize == 0: - return False - else: - return self.qsize() >= self.maxsize - - def put( - self, item: _T, timeout: Optional[Union[float, datetime.timedelta]] = None - ) -> "Future[None]": - """Put an item into the queue, perhaps waiting until there is room. - - Returns a Future, which raises `tornado.util.TimeoutError` after a - timeout. - - ``timeout`` may be a number denoting a time (on the same - scale as `tornado.ioloop.IOLoop.time`, normally `time.time`), or a - `datetime.timedelta` object for a deadline relative to the - current time. - """ - future = Future() # type: Future[None] - try: - self.put_nowait(item) - except QueueFull: - self._putters.append((item, future)) - _set_timeout(future, timeout) - else: - future.set_result(None) - return future - - def put_nowait(self, item: _T) -> None: - """Put an item into the queue without blocking. - - If no free slot is immediately available, raise `QueueFull`. - """ - self._consume_expired() - if self._getters: - assert self.empty(), "queue non-empty, why are getters waiting?" - getter = self._getters.popleft() - self.__put_internal(item) - future_set_result_unless_cancelled(getter, self._get()) - elif self.full(): - raise QueueFull - else: - self.__put_internal(item) - - def get( - self, timeout: Optional[Union[float, datetime.timedelta]] = None - ) -> Awaitable[_T]: - """Remove and return an item from the queue. - - Returns an awaitable which resolves once an item is available, or raises - `tornado.util.TimeoutError` after a timeout. - - ``timeout`` may be a number denoting a time (on the same - scale as `tornado.ioloop.IOLoop.time`, normally `time.time`), or a - `datetime.timedelta` object for a deadline relative to the - current time. - - .. note:: - - The ``timeout`` argument of this method differs from that - of the standard library's `queue.Queue.get`. That method - interprets numeric values as relative timeouts; this one - interprets them as absolute deadlines and requires - ``timedelta`` objects for relative timeouts (consistent - with other timeouts in Tornado). - - """ - future = Future() # type: Future[_T] - try: - future.set_result(self.get_nowait()) - except QueueEmpty: - self._getters.append(future) - _set_timeout(future, timeout) - return future - - def get_nowait(self) -> _T: - """Remove and return an item from the queue without blocking. - - Return an item if one is immediately available, else raise - `QueueEmpty`. - """ - self._consume_expired() - if self._putters: - assert self.full(), "queue not full, why are putters waiting?" - item, putter = self._putters.popleft() - self.__put_internal(item) - future_set_result_unless_cancelled(putter, None) - return self._get() - elif self.qsize(): - return self._get() - else: - raise QueueEmpty - - def task_done(self) -> None: - """Indicate that a formerly enqueued task is complete. - - Used by queue consumers. For each `.get` used to fetch a task, a - subsequent call to `.task_done` tells the queue that the processing - on the task is complete. - - If a `.join` is blocking, it resumes when all items have been - processed; that is, when every `.put` is matched by a `.task_done`. - - Raises `ValueError` if called more times than `.put`. - """ - if self._unfinished_tasks <= 0: - raise ValueError("task_done() called too many times") - self._unfinished_tasks -= 1 - if self._unfinished_tasks == 0: - self._finished.set() - - def join( - self, timeout: Optional[Union[float, datetime.timedelta]] = None - ) -> Awaitable[None]: - """Block until all items in the queue are processed. - - Returns an awaitable, which raises `tornado.util.TimeoutError` after a - timeout. - """ - return self._finished.wait(timeout) - - def __aiter__(self) -> _QueueIterator[_T]: - return _QueueIterator(self) - - # These three are overridable in subclasses. - def _init(self) -> None: - self._queue = collections.deque() - - def _get(self) -> _T: - return self._queue.popleft() - - def _put(self, item: _T) -> None: - self._queue.append(item) - - # End of the overridable methods. - - def __put_internal(self, item: _T) -> None: - self._unfinished_tasks += 1 - self._finished.clear() - self._put(item) - - def _consume_expired(self) -> None: - # Remove timed-out waiters. - while self._putters and self._putters[0][1].done(): - self._putters.popleft() - - while self._getters and self._getters[0].done(): - self._getters.popleft() - - def __repr__(self) -> str: - return "<%s at %s %s>" % (type(self).__name__, hex(id(self)), self._format()) - - def __str__(self) -> str: - return "<%s %s>" % (type(self).__name__, self._format()) - - def _format(self) -> str: - result = "maxsize=%r" % (self.maxsize,) - if getattr(self, "_queue", None): - result += " queue=%r" % self._queue - if self._getters: - result += " getters[%s]" % len(self._getters) - if self._putters: - result += " putters[%s]" % len(self._putters) - if self._unfinished_tasks: - result += " tasks=%s" % self._unfinished_tasks - return result - - -class PriorityQueue(Queue): - """A `.Queue` that retrieves entries in priority order, lowest first. - - Entries are typically tuples like ``(priority number, data)``. - - .. testcode:: - - from tornado.queues import PriorityQueue - - q = PriorityQueue() - q.put((1, 'medium-priority item')) - q.put((0, 'high-priority item')) - q.put((10, 'low-priority item')) - - print(q.get_nowait()) - print(q.get_nowait()) - print(q.get_nowait()) - - .. testoutput:: - - (0, 'high-priority item') - (1, 'medium-priority item') - (10, 'low-priority item') - """ - - def _init(self) -> None: - self._queue = [] - - def _put(self, item: _T) -> None: - heapq.heappush(self._queue, item) - - def _get(self) -> _T: - return heapq.heappop(self._queue) - - -class LifoQueue(Queue): - """A `.Queue` that retrieves the most recently put items first. - - .. testcode:: - - from tornado.queues import LifoQueue - - q = LifoQueue() - q.put(3) - q.put(2) - q.put(1) - - print(q.get_nowait()) - print(q.get_nowait()) - print(q.get_nowait()) - - .. testoutput:: - - 1 - 2 - 3 - """ - - def _init(self) -> None: - self._queue = [] - - def _put(self, item: _T) -> None: - self._queue.append(item) - - def _get(self) -> _T: - return self._queue.pop() diff --git a/venv/lib/python3.8/site-packages/tornado/routing.py b/venv/lib/python3.8/site-packages/tornado/routing.py deleted file mode 100644 index a145d71..0000000 --- a/venv/lib/python3.8/site-packages/tornado/routing.py +++ /dev/null @@ -1,717 +0,0 @@ -# Copyright 2015 The Tornado Authors -# -# 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. - -"""Flexible routing implementation. - -Tornado routes HTTP requests to appropriate handlers using `Router` -class implementations. The `tornado.web.Application` class is a -`Router` implementation and may be used directly, or the classes in -this module may be used for additional flexibility. The `RuleRouter` -class can match on more criteria than `.Application`, or the `Router` -interface can be subclassed for maximum customization. - -`Router` interface extends `~.httputil.HTTPServerConnectionDelegate` -to provide additional routing capabilities. This also means that any -`Router` implementation can be used directly as a ``request_callback`` -for `~.httpserver.HTTPServer` constructor. - -`Router` subclass must implement a ``find_handler`` method to provide -a suitable `~.httputil.HTTPMessageDelegate` instance to handle the -request: - -.. code-block:: python - - class CustomRouter(Router): - def find_handler(self, request, **kwargs): - # some routing logic providing a suitable HTTPMessageDelegate instance - return MessageDelegate(request.connection) - - class MessageDelegate(HTTPMessageDelegate): - def __init__(self, connection): - self.connection = connection - - def finish(self): - self.connection.write_headers( - ResponseStartLine("HTTP/1.1", 200, "OK"), - HTTPHeaders({"Content-Length": "2"}), - b"OK") - self.connection.finish() - - router = CustomRouter() - server = HTTPServer(router) - -The main responsibility of `Router` implementation is to provide a -mapping from a request to `~.httputil.HTTPMessageDelegate` instance -that will handle this request. In the example above we can see that -routing is possible even without instantiating an `~.web.Application`. - -For routing to `~.web.RequestHandler` implementations we need an -`~.web.Application` instance. `~.web.Application.get_handler_delegate` -provides a convenient way to create `~.httputil.HTTPMessageDelegate` -for a given request and `~.web.RequestHandler`. - -Here is a simple example of how we can we route to -`~.web.RequestHandler` subclasses by HTTP method: - -.. code-block:: python - - resources = {} - - class GetResource(RequestHandler): - def get(self, path): - if path not in resources: - raise HTTPError(404) - - self.finish(resources[path]) - - class PostResource(RequestHandler): - def post(self, path): - resources[path] = self.request.body - - class HTTPMethodRouter(Router): - def __init__(self, app): - self.app = app - - def find_handler(self, request, **kwargs): - handler = GetResource if request.method == "GET" else PostResource - return self.app.get_handler_delegate(request, handler, path_args=[request.path]) - - router = HTTPMethodRouter(Application()) - server = HTTPServer(router) - -`ReversibleRouter` interface adds the ability to distinguish between -the routes and reverse them to the original urls using route's name -and additional arguments. `~.web.Application` is itself an -implementation of `ReversibleRouter` class. - -`RuleRouter` and `ReversibleRuleRouter` are implementations of -`Router` and `ReversibleRouter` interfaces and can be used for -creating rule-based routing configurations. - -Rules are instances of `Rule` class. They contain a `Matcher`, which -provides the logic for determining whether the rule is a match for a -particular request and a target, which can be one of the following. - -1) An instance of `~.httputil.HTTPServerConnectionDelegate`: - -.. code-block:: python - - router = RuleRouter([ - Rule(PathMatches("/handler"), ConnectionDelegate()), - # ... more rules - ]) - - class ConnectionDelegate(HTTPServerConnectionDelegate): - def start_request(self, server_conn, request_conn): - return MessageDelegate(request_conn) - -2) A callable accepting a single argument of `~.httputil.HTTPServerRequest` type: - -.. code-block:: python - - router = RuleRouter([ - Rule(PathMatches("/callable"), request_callable) - ]) - - def request_callable(request): - request.write(b"HTTP/1.1 200 OK\\r\\nContent-Length: 2\\r\\n\\r\\nOK") - request.finish() - -3) Another `Router` instance: - -.. code-block:: python - - router = RuleRouter([ - Rule(PathMatches("/router.*"), CustomRouter()) - ]) - -Of course a nested `RuleRouter` or a `~.web.Application` is allowed: - -.. code-block:: python - - router = RuleRouter([ - Rule(HostMatches("example.com"), RuleRouter([ - Rule(PathMatches("/app1/.*"), Application([(r"/app1/handler", Handler)])), - ])) - ]) - - server = HTTPServer(router) - -In the example below `RuleRouter` is used to route between applications: - -.. code-block:: python - - app1 = Application([ - (r"/app1/handler", Handler1), - # other handlers ... - ]) - - app2 = Application([ - (r"/app2/handler", Handler2), - # other handlers ... - ]) - - router = RuleRouter([ - Rule(PathMatches("/app1.*"), app1), - Rule(PathMatches("/app2.*"), app2) - ]) - - server = HTTPServer(router) - -For more information on application-level routing see docs for `~.web.Application`. - -.. versionadded:: 4.5 - -""" - -import re -from functools import partial - -from tornado import httputil -from tornado.httpserver import _CallableAdapter -from tornado.escape import url_escape, url_unescape, utf8 -from tornado.log import app_log -from tornado.util import basestring_type, import_object, re_unescape, unicode_type - -from typing import Any, Union, Optional, Awaitable, List, Dict, Pattern, Tuple, overload - - -class Router(httputil.HTTPServerConnectionDelegate): - """Abstract router interface.""" - - def find_handler( - self, request: httputil.HTTPServerRequest, **kwargs: Any - ) -> Optional[httputil.HTTPMessageDelegate]: - """Must be implemented to return an appropriate instance of `~.httputil.HTTPMessageDelegate` - that can serve the request. - Routing implementations may pass additional kwargs to extend the routing logic. - - :arg httputil.HTTPServerRequest request: current HTTP request. - :arg kwargs: additional keyword arguments passed by routing implementation. - :returns: an instance of `~.httputil.HTTPMessageDelegate` that will be used to - process the request. - """ - raise NotImplementedError() - - def start_request( - self, server_conn: object, request_conn: httputil.HTTPConnection - ) -> httputil.HTTPMessageDelegate: - return _RoutingDelegate(self, server_conn, request_conn) - - -class ReversibleRouter(Router): - """Abstract router interface for routers that can handle named routes - and support reversing them to original urls. - """ - - def reverse_url(self, name: str, *args: Any) -> Optional[str]: - """Returns url string for a given route name and arguments - or ``None`` if no match is found. - - :arg str name: route name. - :arg args: url parameters. - :returns: parametrized url string for a given route name (or ``None``). - """ - raise NotImplementedError() - - -class _RoutingDelegate(httputil.HTTPMessageDelegate): - def __init__( - self, router: Router, server_conn: object, request_conn: httputil.HTTPConnection - ) -> None: - self.server_conn = server_conn - self.request_conn = request_conn - self.delegate = None # type: Optional[httputil.HTTPMessageDelegate] - self.router = router # type: Router - - def headers_received( - self, - start_line: Union[httputil.RequestStartLine, httputil.ResponseStartLine], - headers: httputil.HTTPHeaders, - ) -> Optional[Awaitable[None]]: - assert isinstance(start_line, httputil.RequestStartLine) - request = httputil.HTTPServerRequest( - connection=self.request_conn, - server_connection=self.server_conn, - start_line=start_line, - headers=headers, - ) - - self.delegate = self.router.find_handler(request) - if self.delegate is None: - app_log.debug( - "Delegate for %s %s request not found", - start_line.method, - start_line.path, - ) - self.delegate = _DefaultMessageDelegate(self.request_conn) - - return self.delegate.headers_received(start_line, headers) - - def data_received(self, chunk: bytes) -> Optional[Awaitable[None]]: - assert self.delegate is not None - return self.delegate.data_received(chunk) - - def finish(self) -> None: - assert self.delegate is not None - self.delegate.finish() - - def on_connection_close(self) -> None: - assert self.delegate is not None - self.delegate.on_connection_close() - - -class _DefaultMessageDelegate(httputil.HTTPMessageDelegate): - def __init__(self, connection: httputil.HTTPConnection) -> None: - self.connection = connection - - def finish(self) -> None: - self.connection.write_headers( - httputil.ResponseStartLine("HTTP/1.1", 404, "Not Found"), - httputil.HTTPHeaders(), - ) - self.connection.finish() - - -# _RuleList can either contain pre-constructed Rules or a sequence of -# arguments to be passed to the Rule constructor. -_RuleList = List[ - Union[ - "Rule", - List[Any], # Can't do detailed typechecking of lists. - Tuple[Union[str, "Matcher"], Any], - Tuple[Union[str, "Matcher"], Any, Dict[str, Any]], - Tuple[Union[str, "Matcher"], Any, Dict[str, Any], str], - ] -] - - -class RuleRouter(Router): - """Rule-based router implementation.""" - - def __init__(self, rules: Optional[_RuleList] = None) -> None: - """Constructs a router from an ordered list of rules:: - - RuleRouter([ - Rule(PathMatches("/handler"), Target), - # ... more rules - ]) - - You can also omit explicit `Rule` constructor and use tuples of arguments:: - - RuleRouter([ - (PathMatches("/handler"), Target), - ]) - - `PathMatches` is a default matcher, so the example above can be simplified:: - - RuleRouter([ - ("/handler", Target), - ]) - - In the examples above, ``Target`` can be a nested `Router` instance, an instance of - `~.httputil.HTTPServerConnectionDelegate` or an old-style callable, - accepting a request argument. - - :arg rules: a list of `Rule` instances or tuples of `Rule` - constructor arguments. - """ - self.rules = [] # type: List[Rule] - if rules: - self.add_rules(rules) - - def add_rules(self, rules: _RuleList) -> None: - """Appends new rules to the router. - - :arg rules: a list of Rule instances (or tuples of arguments, which are - passed to Rule constructor). - """ - for rule in rules: - if isinstance(rule, (tuple, list)): - assert len(rule) in (2, 3, 4) - if isinstance(rule[0], basestring_type): - rule = Rule(PathMatches(rule[0]), *rule[1:]) - else: - rule = Rule(*rule) - - self.rules.append(self.process_rule(rule)) - - def process_rule(self, rule: "Rule") -> "Rule": - """Override this method for additional preprocessing of each rule. - - :arg Rule rule: a rule to be processed. - :returns: the same or modified Rule instance. - """ - return rule - - def find_handler( - self, request: httputil.HTTPServerRequest, **kwargs: Any - ) -> Optional[httputil.HTTPMessageDelegate]: - for rule in self.rules: - target_params = rule.matcher.match(request) - if target_params is not None: - if rule.target_kwargs: - target_params["target_kwargs"] = rule.target_kwargs - - delegate = self.get_target_delegate( - rule.target, request, **target_params - ) - - if delegate is not None: - return delegate - - return None - - def get_target_delegate( - self, target: Any, request: httputil.HTTPServerRequest, **target_params: Any - ) -> Optional[httputil.HTTPMessageDelegate]: - """Returns an instance of `~.httputil.HTTPMessageDelegate` for a - Rule's target. This method is called by `~.find_handler` and can be - extended to provide additional target types. - - :arg target: a Rule's target. - :arg httputil.HTTPServerRequest request: current request. - :arg target_params: additional parameters that can be useful - for `~.httputil.HTTPMessageDelegate` creation. - """ - if isinstance(target, Router): - return target.find_handler(request, **target_params) - - elif isinstance(target, httputil.HTTPServerConnectionDelegate): - assert request.connection is not None - return target.start_request(request.server_connection, request.connection) - - elif callable(target): - assert request.connection is not None - return _CallableAdapter( - partial(target, **target_params), request.connection - ) - - return None - - -class ReversibleRuleRouter(ReversibleRouter, RuleRouter): - """A rule-based router that implements ``reverse_url`` method. - - Each rule added to this router may have a ``name`` attribute that can be - used to reconstruct an original uri. The actual reconstruction takes place - in a rule's matcher (see `Matcher.reverse`). - """ - - def __init__(self, rules: Optional[_RuleList] = None) -> None: - self.named_rules = {} # type: Dict[str, Any] - super().__init__(rules) - - def process_rule(self, rule: "Rule") -> "Rule": - rule = super().process_rule(rule) - - if rule.name: - if rule.name in self.named_rules: - app_log.warning( - "Multiple handlers named %s; replacing previous value", rule.name - ) - self.named_rules[rule.name] = rule - - return rule - - def reverse_url(self, name: str, *args: Any) -> Optional[str]: - if name in self.named_rules: - return self.named_rules[name].matcher.reverse(*args) - - for rule in self.rules: - if isinstance(rule.target, ReversibleRouter): - reversed_url = rule.target.reverse_url(name, *args) - if reversed_url is not None: - return reversed_url - - return None - - -class Rule(object): - """A routing rule.""" - - def __init__( - self, - matcher: "Matcher", - target: Any, - target_kwargs: Optional[Dict[str, Any]] = None, - name: Optional[str] = None, - ) -> None: - """Constructs a Rule instance. - - :arg Matcher matcher: a `Matcher` instance used for determining - whether the rule should be considered a match for a specific - request. - :arg target: a Rule's target (typically a ``RequestHandler`` or - `~.httputil.HTTPServerConnectionDelegate` subclass or even a nested `Router`, - depending on routing implementation). - :arg dict target_kwargs: a dict of parameters that can be useful - at the moment of target instantiation (for example, ``status_code`` - for a ``RequestHandler`` subclass). They end up in - ``target_params['target_kwargs']`` of `RuleRouter.get_target_delegate` - method. - :arg str name: the name of the rule that can be used to find it - in `ReversibleRouter.reverse_url` implementation. - """ - if isinstance(target, str): - # import the Module and instantiate the class - # Must be a fully qualified name (module.ClassName) - target = import_object(target) - - self.matcher = matcher # type: Matcher - self.target = target - self.target_kwargs = target_kwargs if target_kwargs else {} - self.name = name - - def reverse(self, *args: Any) -> Optional[str]: - return self.matcher.reverse(*args) - - def __repr__(self) -> str: - return "%s(%r, %s, kwargs=%r, name=%r)" % ( - self.__class__.__name__, - self.matcher, - self.target, - self.target_kwargs, - self.name, - ) - - -class Matcher(object): - """Represents a matcher for request features.""" - - def match(self, request: httputil.HTTPServerRequest) -> Optional[Dict[str, Any]]: - """Matches current instance against the request. - - :arg httputil.HTTPServerRequest request: current HTTP request - :returns: a dict of parameters to be passed to the target handler - (for example, ``handler_kwargs``, ``path_args``, ``path_kwargs`` - can be passed for proper `~.web.RequestHandler` instantiation). - An empty dict is a valid (and common) return value to indicate a match - when the argument-passing features are not used. - ``None`` must be returned to indicate that there is no match.""" - raise NotImplementedError() - - def reverse(self, *args: Any) -> Optional[str]: - """Reconstructs full url from matcher instance and additional arguments.""" - return None - - -class AnyMatches(Matcher): - """Matches any request.""" - - def match(self, request: httputil.HTTPServerRequest) -> Optional[Dict[str, Any]]: - return {} - - -class HostMatches(Matcher): - """Matches requests from hosts specified by ``host_pattern`` regex.""" - - def __init__(self, host_pattern: Union[str, Pattern]) -> None: - if isinstance(host_pattern, basestring_type): - if not host_pattern.endswith("$"): - host_pattern += "$" - self.host_pattern = re.compile(host_pattern) - else: - self.host_pattern = host_pattern - - def match(self, request: httputil.HTTPServerRequest) -> Optional[Dict[str, Any]]: - if self.host_pattern.match(request.host_name): - return {} - - return None - - -class DefaultHostMatches(Matcher): - """Matches requests from host that is equal to application's default_host. - Always returns no match if ``X-Real-Ip`` header is present. - """ - - def __init__(self, application: Any, host_pattern: Pattern) -> None: - self.application = application - self.host_pattern = host_pattern - - def match(self, request: httputil.HTTPServerRequest) -> Optional[Dict[str, Any]]: - # Look for default host if not behind load balancer (for debugging) - if "X-Real-Ip" not in request.headers: - if self.host_pattern.match(self.application.default_host): - return {} - return None - - -class PathMatches(Matcher): - """Matches requests with paths specified by ``path_pattern`` regex.""" - - def __init__(self, path_pattern: Union[str, Pattern]) -> None: - if isinstance(path_pattern, basestring_type): - if not path_pattern.endswith("$"): - path_pattern += "$" - self.regex = re.compile(path_pattern) - else: - self.regex = path_pattern - - assert len(self.regex.groupindex) in (0, self.regex.groups), ( - "groups in url regexes must either be all named or all " - "positional: %r" % self.regex.pattern - ) - - self._path, self._group_count = self._find_groups() - - def match(self, request: httputil.HTTPServerRequest) -> Optional[Dict[str, Any]]: - match = self.regex.match(request.path) - if match is None: - return None - if not self.regex.groups: - return {} - - path_args = [] # type: List[bytes] - path_kwargs = {} # type: Dict[str, bytes] - - # Pass matched groups to the handler. Since - # match.groups() includes both named and - # unnamed groups, we want to use either groups - # or groupdict but not both. - if self.regex.groupindex: - path_kwargs = dict( - (str(k), _unquote_or_none(v)) for (k, v) in match.groupdict().items() - ) - else: - path_args = [_unquote_or_none(s) for s in match.groups()] - - return dict(path_args=path_args, path_kwargs=path_kwargs) - - def reverse(self, *args: Any) -> Optional[str]: - if self._path is None: - raise ValueError("Cannot reverse url regex " + self.regex.pattern) - assert len(args) == self._group_count, ( - "required number of arguments " "not found" - ) - if not len(args): - return self._path - converted_args = [] - for a in args: - if not isinstance(a, (unicode_type, bytes)): - a = str(a) - converted_args.append(url_escape(utf8(a), plus=False)) - return self._path % tuple(converted_args) - - def _find_groups(self) -> Tuple[Optional[str], Optional[int]]: - """Returns a tuple (reverse string, group count) for a url. - - For example: Given the url pattern /([0-9]{4})/([a-z-]+)/, this method - would return ('/%s/%s/', 2). - """ - pattern = self.regex.pattern - if pattern.startswith("^"): - pattern = pattern[1:] - if pattern.endswith("$"): - pattern = pattern[:-1] - - if self.regex.groups != pattern.count("("): - # The pattern is too complicated for our simplistic matching, - # so we can't support reversing it. - return None, None - - pieces = [] - for fragment in pattern.split("("): - if ")" in fragment: - paren_loc = fragment.index(")") - if paren_loc >= 0: - try: - unescaped_fragment = re_unescape(fragment[paren_loc + 1 :]) - except ValueError: - # If we can't unescape part of it, we can't - # reverse this url. - return (None, None) - pieces.append("%s" + unescaped_fragment) - else: - try: - unescaped_fragment = re_unescape(fragment) - except ValueError: - # If we can't unescape part of it, we can't - # reverse this url. - return (None, None) - pieces.append(unescaped_fragment) - - return "".join(pieces), self.regex.groups - - -class URLSpec(Rule): - """Specifies mappings between URLs and handlers. - - .. versionchanged: 4.5 - `URLSpec` is now a subclass of a `Rule` with `PathMatches` matcher and is preserved for - backwards compatibility. - """ - - def __init__( - self, - pattern: Union[str, Pattern], - handler: Any, - kwargs: Optional[Dict[str, Any]] = None, - name: Optional[str] = None, - ) -> None: - """Parameters: - - * ``pattern``: Regular expression to be matched. Any capturing - groups in the regex will be passed in to the handler's - get/post/etc methods as arguments (by keyword if named, by - position if unnamed. Named and unnamed capturing groups - may not be mixed in the same rule). - - * ``handler``: `~.web.RequestHandler` subclass to be invoked. - - * ``kwargs`` (optional): A dictionary of additional arguments - to be passed to the handler's constructor. - - * ``name`` (optional): A name for this handler. Used by - `~.web.Application.reverse_url`. - - """ - matcher = PathMatches(pattern) - super().__init__(matcher, handler, kwargs, name) - - self.regex = matcher.regex - self.handler_class = self.target - self.kwargs = kwargs - - def __repr__(self) -> str: - return "%s(%r, %s, kwargs=%r, name=%r)" % ( - self.__class__.__name__, - self.regex.pattern, - self.handler_class, - self.kwargs, - self.name, - ) - - -@overload -def _unquote_or_none(s: str) -> bytes: - pass - - -@overload # noqa: F811 -def _unquote_or_none(s: None) -> None: - pass - - -def _unquote_or_none(s: Optional[str]) -> Optional[bytes]: # noqa: F811 - """None-safe wrapper around url_unescape to handle unmatched optional - groups correctly. - - Note that args are passed as bytes so the handler can decide what - encoding to use. - """ - if s is None: - return s - return url_unescape(s, encoding=None, plus=False) diff --git a/venv/lib/python3.8/site-packages/tornado/simple_httpclient.py b/venv/lib/python3.8/site-packages/tornado/simple_httpclient.py deleted file mode 100644 index f99f391..0000000 --- a/venv/lib/python3.8/site-packages/tornado/simple_httpclient.py +++ /dev/null @@ -1,699 +0,0 @@ -from tornado.escape import _unicode -from tornado import gen, version -from tornado.httpclient import ( - HTTPResponse, - HTTPError, - AsyncHTTPClient, - main, - _RequestProxy, - HTTPRequest, -) -from tornado import httputil -from tornado.http1connection import HTTP1Connection, HTTP1ConnectionParameters -from tornado.ioloop import IOLoop -from tornado.iostream import StreamClosedError, IOStream -from tornado.netutil import ( - Resolver, - OverrideResolver, - _client_ssl_defaults, - is_valid_ip, -) -from tornado.log import gen_log -from tornado.tcpclient import TCPClient - -import base64 -import collections -import copy -import functools -import re -import socket -import ssl -import sys -import time -from io import BytesIO -import urllib.parse - -from typing import Dict, Any, Callable, Optional, Type, Union -from types import TracebackType -import typing - -if typing.TYPE_CHECKING: - from typing import Deque, Tuple, List # noqa: F401 - - -class HTTPTimeoutError(HTTPError): - """Error raised by SimpleAsyncHTTPClient on timeout. - - For historical reasons, this is a subclass of `.HTTPClientError` - which simulates a response code of 599. - - .. versionadded:: 5.1 - """ - - def __init__(self, message: str) -> None: - super().__init__(599, message=message) - - def __str__(self) -> str: - return self.message or "Timeout" - - -class HTTPStreamClosedError(HTTPError): - """Error raised by SimpleAsyncHTTPClient when the underlying stream is closed. - - When a more specific exception is available (such as `ConnectionResetError`), - it may be raised instead of this one. - - For historical reasons, this is a subclass of `.HTTPClientError` - which simulates a response code of 599. - - .. versionadded:: 5.1 - """ - - def __init__(self, message: str) -> None: - super().__init__(599, message=message) - - def __str__(self) -> str: - return self.message or "Stream closed" - - -class SimpleAsyncHTTPClient(AsyncHTTPClient): - """Non-blocking HTTP client with no external dependencies. - - This class implements an HTTP 1.1 client on top of Tornado's IOStreams. - Some features found in the curl-based AsyncHTTPClient are not yet - supported. In particular, proxies are not supported, connections - are not reused, and callers cannot select the network interface to be - used. - """ - - def initialize( # type: ignore - self, - max_clients: int = 10, - hostname_mapping: Optional[Dict[str, str]] = None, - max_buffer_size: int = 104857600, - resolver: Optional[Resolver] = None, - defaults: Optional[Dict[str, Any]] = None, - max_header_size: Optional[int] = None, - max_body_size: Optional[int] = None, - ) -> None: - """Creates a AsyncHTTPClient. - - Only a single AsyncHTTPClient instance exists per IOLoop - in order to provide limitations on the number of pending connections. - ``force_instance=True`` may be used to suppress this behavior. - - Note that because of this implicit reuse, unless ``force_instance`` - is used, only the first call to the constructor actually uses - its arguments. It is recommended to use the ``configure`` method - instead of the constructor to ensure that arguments take effect. - - ``max_clients`` is the number of concurrent requests that can be - in progress; when this limit is reached additional requests will be - queued. Note that time spent waiting in this queue still counts - against the ``request_timeout``. - - ``hostname_mapping`` is a dictionary mapping hostnames to IP addresses. - It can be used to make local DNS changes when modifying system-wide - settings like ``/etc/hosts`` is not possible or desirable (e.g. in - unittests). - - ``max_buffer_size`` (default 100MB) is the number of bytes - that can be read into memory at once. ``max_body_size`` - (defaults to ``max_buffer_size``) is the largest response body - that the client will accept. Without a - ``streaming_callback``, the smaller of these two limits - applies; with a ``streaming_callback`` only ``max_body_size`` - does. - - .. versionchanged:: 4.2 - Added the ``max_body_size`` argument. - """ - super().initialize(defaults=defaults) - self.max_clients = max_clients - self.queue = ( - collections.deque() - ) # type: Deque[Tuple[object, HTTPRequest, Callable[[HTTPResponse], None]]] - self.active = ( - {} - ) # type: Dict[object, Tuple[HTTPRequest, Callable[[HTTPResponse], None]]] - self.waiting = ( - {} - ) # type: Dict[object, Tuple[HTTPRequest, Callable[[HTTPResponse], None], object]] - self.max_buffer_size = max_buffer_size - self.max_header_size = max_header_size - self.max_body_size = max_body_size - # TCPClient could create a Resolver for us, but we have to do it - # ourselves to support hostname_mapping. - if resolver: - self.resolver = resolver - self.own_resolver = False - else: - self.resolver = Resolver() - self.own_resolver = True - if hostname_mapping is not None: - self.resolver = OverrideResolver( - resolver=self.resolver, mapping=hostname_mapping - ) - self.tcp_client = TCPClient(resolver=self.resolver) - - def close(self) -> None: - super().close() - if self.own_resolver: - self.resolver.close() - self.tcp_client.close() - - def fetch_impl( - self, request: HTTPRequest, callback: Callable[[HTTPResponse], None] - ) -> None: - key = object() - self.queue.append((key, request, callback)) - assert request.connect_timeout is not None - assert request.request_timeout is not None - timeout_handle = None - if len(self.active) >= self.max_clients: - timeout = ( - min(request.connect_timeout, request.request_timeout) - or request.connect_timeout - or request.request_timeout - ) # min but skip zero - if timeout: - timeout_handle = self.io_loop.add_timeout( - self.io_loop.time() + timeout, - functools.partial(self._on_timeout, key, "in request queue"), - ) - self.waiting[key] = (request, callback, timeout_handle) - self._process_queue() - if self.queue: - gen_log.debug( - "max_clients limit reached, request queued. " - "%d active, %d queued requests." % (len(self.active), len(self.queue)) - ) - - def _process_queue(self) -> None: - while self.queue and len(self.active) < self.max_clients: - key, request, callback = self.queue.popleft() - if key not in self.waiting: - continue - self._remove_timeout(key) - self.active[key] = (request, callback) - release_callback = functools.partial(self._release_fetch, key) - self._handle_request(request, release_callback, callback) - - def _connection_class(self) -> type: - return _HTTPConnection - - def _handle_request( - self, - request: HTTPRequest, - release_callback: Callable[[], None], - final_callback: Callable[[HTTPResponse], None], - ) -> None: - self._connection_class()( - self, - request, - release_callback, - final_callback, - self.max_buffer_size, - self.tcp_client, - self.max_header_size, - self.max_body_size, - ) - - def _release_fetch(self, key: object) -> None: - del self.active[key] - self._process_queue() - - def _remove_timeout(self, key: object) -> None: - if key in self.waiting: - request, callback, timeout_handle = self.waiting[key] - if timeout_handle is not None: - self.io_loop.remove_timeout(timeout_handle) - del self.waiting[key] - - def _on_timeout(self, key: object, info: Optional[str] = None) -> None: - """Timeout callback of request. - - Construct a timeout HTTPResponse when a timeout occurs. - - :arg object key: A simple object to mark the request. - :info string key: More detailed timeout information. - """ - request, callback, timeout_handle = self.waiting[key] - self.queue.remove((key, request, callback)) - - error_message = "Timeout {0}".format(info) if info else "Timeout" - timeout_response = HTTPResponse( - request, - 599, - error=HTTPTimeoutError(error_message), - request_time=self.io_loop.time() - request.start_time, - ) - self.io_loop.add_callback(callback, timeout_response) - del self.waiting[key] - - -class _HTTPConnection(httputil.HTTPMessageDelegate): - _SUPPORTED_METHODS = set( - ["GET", "HEAD", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"] - ) - - def __init__( - self, - client: Optional[SimpleAsyncHTTPClient], - request: HTTPRequest, - release_callback: Callable[[], None], - final_callback: Callable[[HTTPResponse], None], - max_buffer_size: int, - tcp_client: TCPClient, - max_header_size: int, - max_body_size: int, - ) -> None: - self.io_loop = IOLoop.current() - self.start_time = self.io_loop.time() - self.start_wall_time = time.time() - self.client = client - self.request = request - self.release_callback = release_callback - self.final_callback = final_callback - self.max_buffer_size = max_buffer_size - self.tcp_client = tcp_client - self.max_header_size = max_header_size - self.max_body_size = max_body_size - self.code = None # type: Optional[int] - self.headers = None # type: Optional[httputil.HTTPHeaders] - self.chunks = [] # type: List[bytes] - self._decompressor = None - # Timeout handle returned by IOLoop.add_timeout - self._timeout = None # type: object - self._sockaddr = None - IOLoop.current().add_future( - gen.convert_yielded(self.run()), lambda f: f.result() - ) - - async def run(self) -> None: - try: - self.parsed = urllib.parse.urlsplit(_unicode(self.request.url)) - if self.parsed.scheme not in ("http", "https"): - raise ValueError("Unsupported url scheme: %s" % self.request.url) - # urlsplit results have hostname and port results, but they - # didn't support ipv6 literals until python 2.7. - netloc = self.parsed.netloc - if "@" in netloc: - userpass, _, netloc = netloc.rpartition("@") - host, port = httputil.split_host_and_port(netloc) - if port is None: - port = 443 if self.parsed.scheme == "https" else 80 - if re.match(r"^\[.*\]$", host): - # raw ipv6 addresses in urls are enclosed in brackets - host = host[1:-1] - self.parsed_hostname = host # save final host for _on_connect - - if self.request.allow_ipv6 is False: - af = socket.AF_INET - else: - af = socket.AF_UNSPEC - - ssl_options = self._get_ssl_options(self.parsed.scheme) - - source_ip = None - if self.request.network_interface: - if is_valid_ip(self.request.network_interface): - source_ip = self.request.network_interface - else: - raise ValueError( - "Unrecognized IPv4 or IPv6 address for network_interface, got %r" - % (self.request.network_interface,) - ) - - timeout = ( - min(self.request.connect_timeout, self.request.request_timeout) - or self.request.connect_timeout - or self.request.request_timeout - ) # min but skip zero - if timeout: - self._timeout = self.io_loop.add_timeout( - self.start_time + timeout, - functools.partial(self._on_timeout, "while connecting"), - ) - stream = await self.tcp_client.connect( - host, - port, - af=af, - ssl_options=ssl_options, - max_buffer_size=self.max_buffer_size, - source_ip=source_ip, - ) - - if self.final_callback is None: - # final_callback is cleared if we've hit our timeout. - stream.close() - return - self.stream = stream - self.stream.set_close_callback(self.on_connection_close) - self._remove_timeout() - if self.final_callback is None: - return - if self.request.request_timeout: - self._timeout = self.io_loop.add_timeout( - self.start_time + self.request.request_timeout, - functools.partial(self._on_timeout, "during request"), - ) - if ( - self.request.method not in self._SUPPORTED_METHODS - and not self.request.allow_nonstandard_methods - ): - raise KeyError("unknown method %s" % self.request.method) - for key in ( - "proxy_host", - "proxy_port", - "proxy_username", - "proxy_password", - "proxy_auth_mode", - ): - if getattr(self.request, key, None): - raise NotImplementedError("%s not supported" % key) - if "Connection" not in self.request.headers: - self.request.headers["Connection"] = "close" - if "Host" not in self.request.headers: - if "@" in self.parsed.netloc: - self.request.headers["Host"] = self.parsed.netloc.rpartition("@")[ - -1 - ] - else: - self.request.headers["Host"] = self.parsed.netloc - username, password = None, None - if self.parsed.username is not None: - username, password = self.parsed.username, self.parsed.password - elif self.request.auth_username is not None: - username = self.request.auth_username - password = self.request.auth_password or "" - if username is not None: - assert password is not None - if self.request.auth_mode not in (None, "basic"): - raise ValueError("unsupported auth_mode %s", self.request.auth_mode) - self.request.headers["Authorization"] = "Basic " + _unicode( - base64.b64encode( - httputil.encode_username_password(username, password) - ) - ) - if self.request.user_agent: - self.request.headers["User-Agent"] = self.request.user_agent - elif self.request.headers.get("User-Agent") is None: - self.request.headers["User-Agent"] = "Tornado/{}".format(version) - if not self.request.allow_nonstandard_methods: - # Some HTTP methods nearly always have bodies while others - # almost never do. Fail in this case unless the user has - # opted out of sanity checks with allow_nonstandard_methods. - body_expected = self.request.method in ("POST", "PATCH", "PUT") - body_present = ( - self.request.body is not None - or self.request.body_producer is not None - ) - if (body_expected and not body_present) or ( - body_present and not body_expected - ): - raise ValueError( - "Body must %sbe None for method %s (unless " - "allow_nonstandard_methods is true)" - % ("not " if body_expected else "", self.request.method) - ) - if self.request.expect_100_continue: - self.request.headers["Expect"] = "100-continue" - if self.request.body is not None: - # When body_producer is used the caller is responsible for - # setting Content-Length (or else chunked encoding will be used). - self.request.headers["Content-Length"] = str(len(self.request.body)) - if ( - self.request.method == "POST" - and "Content-Type" not in self.request.headers - ): - self.request.headers[ - "Content-Type" - ] = "application/x-www-form-urlencoded" - if self.request.decompress_response: - self.request.headers["Accept-Encoding"] = "gzip" - req_path = (self.parsed.path or "/") + ( - ("?" + self.parsed.query) if self.parsed.query else "" - ) - self.connection = self._create_connection(stream) - start_line = httputil.RequestStartLine(self.request.method, req_path, "") - self.connection.write_headers(start_line, self.request.headers) - if self.request.expect_100_continue: - await self.connection.read_response(self) - else: - await self._write_body(True) - except Exception: - if not self._handle_exception(*sys.exc_info()): - raise - - def _get_ssl_options( - self, scheme: str - ) -> Union[None, Dict[str, Any], ssl.SSLContext]: - if scheme == "https": - if self.request.ssl_options is not None: - return self.request.ssl_options - # If we are using the defaults, don't construct a - # new SSLContext. - if ( - self.request.validate_cert - and self.request.ca_certs is None - and self.request.client_cert is None - and self.request.client_key is None - ): - return _client_ssl_defaults - ssl_ctx = ssl.create_default_context( - ssl.Purpose.SERVER_AUTH, cafile=self.request.ca_certs - ) - if not self.request.validate_cert: - ssl_ctx.check_hostname = False - ssl_ctx.verify_mode = ssl.CERT_NONE - if self.request.client_cert is not None: - ssl_ctx.load_cert_chain( - self.request.client_cert, self.request.client_key - ) - if hasattr(ssl, "OP_NO_COMPRESSION"): - # See netutil.ssl_options_to_context - ssl_ctx.options |= ssl.OP_NO_COMPRESSION - return ssl_ctx - return None - - def _on_timeout(self, info: Optional[str] = None) -> None: - """Timeout callback of _HTTPConnection instance. - - Raise a `HTTPTimeoutError` when a timeout occurs. - - :info string key: More detailed timeout information. - """ - self._timeout = None - error_message = "Timeout {0}".format(info) if info else "Timeout" - if self.final_callback is not None: - self._handle_exception( - HTTPTimeoutError, HTTPTimeoutError(error_message), None - ) - - def _remove_timeout(self) -> None: - if self._timeout is not None: - self.io_loop.remove_timeout(self._timeout) - self._timeout = None - - def _create_connection(self, stream: IOStream) -> HTTP1Connection: - stream.set_nodelay(True) - connection = HTTP1Connection( - stream, - True, - HTTP1ConnectionParameters( - no_keep_alive=True, - max_header_size=self.max_header_size, - max_body_size=self.max_body_size, - decompress=bool(self.request.decompress_response), - ), - self._sockaddr, - ) - return connection - - async def _write_body(self, start_read: bool) -> None: - if self.request.body is not None: - self.connection.write(self.request.body) - elif self.request.body_producer is not None: - fut = self.request.body_producer(self.connection.write) - if fut is not None: - await fut - self.connection.finish() - if start_read: - try: - await self.connection.read_response(self) - except StreamClosedError: - if not self._handle_exception(*sys.exc_info()): - raise - - def _release(self) -> None: - if self.release_callback is not None: - release_callback = self.release_callback - self.release_callback = None # type: ignore - release_callback() - - def _run_callback(self, response: HTTPResponse) -> None: - self._release() - if self.final_callback is not None: - final_callback = self.final_callback - self.final_callback = None # type: ignore - self.io_loop.add_callback(final_callback, response) - - def _handle_exception( - self, - typ: "Optional[Type[BaseException]]", - value: Optional[BaseException], - tb: Optional[TracebackType], - ) -> bool: - if self.final_callback: - self._remove_timeout() - if isinstance(value, StreamClosedError): - if value.real_error is None: - value = HTTPStreamClosedError("Stream closed") - else: - value = value.real_error - self._run_callback( - HTTPResponse( - self.request, - 599, - error=value, - request_time=self.io_loop.time() - self.start_time, - start_time=self.start_wall_time, - ) - ) - - if hasattr(self, "stream"): - # TODO: this may cause a StreamClosedError to be raised - # by the connection's Future. Should we cancel the - # connection more gracefully? - self.stream.close() - return True - else: - # If our callback has already been called, we are probably - # catching an exception that is not caused by us but rather - # some child of our callback. Rather than drop it on the floor, - # pass it along, unless it's just the stream being closed. - return isinstance(value, StreamClosedError) - - def on_connection_close(self) -> None: - if self.final_callback is not None: - message = "Connection closed" - if self.stream.error: - raise self.stream.error - try: - raise HTTPStreamClosedError(message) - except HTTPStreamClosedError: - self._handle_exception(*sys.exc_info()) - - async def headers_received( - self, - first_line: Union[httputil.ResponseStartLine, httputil.RequestStartLine], - headers: httputil.HTTPHeaders, - ) -> None: - assert isinstance(first_line, httputil.ResponseStartLine) - if self.request.expect_100_continue and first_line.code == 100: - await self._write_body(False) - return - self.code = first_line.code - self.reason = first_line.reason - self.headers = headers - - if self._should_follow_redirect(): - return - - if self.request.header_callback is not None: - # Reassemble the start line. - self.request.header_callback("%s %s %s\r\n" % first_line) - for k, v in self.headers.get_all(): - self.request.header_callback("%s: %s\r\n" % (k, v)) - self.request.header_callback("\r\n") - - def _should_follow_redirect(self) -> bool: - if self.request.follow_redirects: - assert self.request.max_redirects is not None - return ( - self.code in (301, 302, 303, 307, 308) - and self.request.max_redirects > 0 - and self.headers is not None - and self.headers.get("Location") is not None - ) - return False - - def finish(self) -> None: - assert self.code is not None - data = b"".join(self.chunks) - self._remove_timeout() - original_request = getattr(self.request, "original_request", self.request) - if self._should_follow_redirect(): - assert isinstance(self.request, _RequestProxy) - new_request = copy.copy(self.request.request) - new_request.url = urllib.parse.urljoin( - self.request.url, self.headers["Location"] - ) - new_request.max_redirects = self.request.max_redirects - 1 - del new_request.headers["Host"] - # https://tools.ietf.org/html/rfc7231#section-6.4 - # - # The original HTTP spec said that after a 301 or 302 - # redirect, the request method should be preserved. - # However, browsers implemented this by changing the - # method to GET, and the behavior stuck. 303 redirects - # always specified this POST-to-GET behavior, arguably - # for *all* methods, but libcurl < 7.70 only does this - # for POST, while libcurl >= 7.70 does it for other methods. - if (self.code == 303 and self.request.method != "HEAD") or ( - self.code in (301, 302) and self.request.method == "POST" - ): - new_request.method = "GET" - new_request.body = None - for h in [ - "Content-Length", - "Content-Type", - "Content-Encoding", - "Transfer-Encoding", - ]: - try: - del self.request.headers[h] - except KeyError: - pass - new_request.original_request = original_request - final_callback = self.final_callback - self.final_callback = None - self._release() - fut = self.client.fetch(new_request, raise_error=False) - fut.add_done_callback(lambda f: final_callback(f.result())) - self._on_end_request() - return - if self.request.streaming_callback: - buffer = BytesIO() - else: - buffer = BytesIO(data) # TODO: don't require one big string? - response = HTTPResponse( - original_request, - self.code, - reason=getattr(self, "reason", None), - headers=self.headers, - request_time=self.io_loop.time() - self.start_time, - start_time=self.start_wall_time, - buffer=buffer, - effective_url=self.request.url, - ) - self._run_callback(response) - self._on_end_request() - - def _on_end_request(self) -> None: - self.stream.close() - - def data_received(self, chunk: bytes) -> None: - if self._should_follow_redirect(): - # We're going to follow a redirect so just discard the body. - return - if self.request.streaming_callback is not None: - self.request.streaming_callback(chunk) - else: - self.chunks.append(chunk) - - -if __name__ == "__main__": - AsyncHTTPClient.configure(SimpleAsyncHTTPClient) - main() diff --git a/venv/lib/python3.8/site-packages/tornado/speedups.cpython-38-x86_64-linux-gnu.so b/venv/lib/python3.8/site-packages/tornado/speedups.cpython-38-x86_64-linux-gnu.so deleted file mode 100755 index 407a15c07fa53ac76d792189c3f5131ef559f16f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29256 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 BvEKjy diff --git a/venv/lib/python3.8/site-packages/tornado/tcpclient.py b/venv/lib/python3.8/site-packages/tornado/tcpclient.py deleted file mode 100644 index e2d682e..0000000 --- a/venv/lib/python3.8/site-packages/tornado/tcpclient.py +++ /dev/null @@ -1,328 +0,0 @@ -# -# Copyright 2014 Facebook -# -# 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. - -"""A non-blocking TCP connection factory. -""" - -import functools -import socket -import numbers -import datetime -import ssl - -from tornado.concurrent import Future, future_add_done_callback -from tornado.ioloop import IOLoop -from tornado.iostream import IOStream -from tornado import gen -from tornado.netutil import Resolver -from tornado.gen import TimeoutError - -from typing import Any, Union, Dict, Tuple, List, Callable, Iterator, Optional, Set - -_INITIAL_CONNECT_TIMEOUT = 0.3 - - -class _Connector(object): - """A stateless implementation of the "Happy Eyeballs" algorithm. - - "Happy Eyeballs" is documented in RFC6555 as the recommended practice - for when both IPv4 and IPv6 addresses are available. - - In this implementation, we partition the addresses by family, and - make the first connection attempt to whichever address was - returned first by ``getaddrinfo``. If that connection fails or - times out, we begin a connection in parallel to the first address - of the other family. If there are additional failures we retry - with other addresses, keeping one connection attempt per family - in flight at a time. - - http://tools.ietf.org/html/rfc6555 - - """ - - def __init__( - self, - addrinfo: List[Tuple], - connect: Callable[ - [socket.AddressFamily, Tuple], Tuple[IOStream, "Future[IOStream]"] - ], - ) -> None: - self.io_loop = IOLoop.current() - self.connect = connect - - self.future = ( - Future() - ) # type: Future[Tuple[socket.AddressFamily, Any, IOStream]] - self.timeout = None # type: Optional[object] - self.connect_timeout = None # type: Optional[object] - self.last_error = None # type: Optional[Exception] - self.remaining = len(addrinfo) - self.primary_addrs, self.secondary_addrs = self.split(addrinfo) - self.streams = set() # type: Set[IOStream] - - @staticmethod - def split( - addrinfo: List[Tuple], - ) -> Tuple[ - List[Tuple[socket.AddressFamily, Tuple]], - List[Tuple[socket.AddressFamily, Tuple]], - ]: - """Partition the ``addrinfo`` list by address family. - - Returns two lists. The first list contains the first entry from - ``addrinfo`` and all others with the same family, and the - second list contains all other addresses (normally one list will - be AF_INET and the other AF_INET6, although non-standard resolvers - may return additional families). - """ - primary = [] - secondary = [] - primary_af = addrinfo[0][0] - for af, addr in addrinfo: - if af == primary_af: - primary.append((af, addr)) - else: - secondary.append((af, addr)) - return primary, secondary - - def start( - self, - timeout: float = _INITIAL_CONNECT_TIMEOUT, - connect_timeout: Optional[Union[float, datetime.timedelta]] = None, - ) -> "Future[Tuple[socket.AddressFamily, Any, IOStream]]": - self.try_connect(iter(self.primary_addrs)) - self.set_timeout(timeout) - if connect_timeout is not None: - self.set_connect_timeout(connect_timeout) - return self.future - - def try_connect(self, addrs: Iterator[Tuple[socket.AddressFamily, Tuple]]) -> None: - try: - af, addr = next(addrs) - except StopIteration: - # We've reached the end of our queue, but the other queue - # might still be working. Send a final error on the future - # only when both queues are finished. - if self.remaining == 0 and not self.future.done(): - self.future.set_exception( - self.last_error or IOError("connection failed") - ) - return - stream, future = self.connect(af, addr) - self.streams.add(stream) - future_add_done_callback( - future, functools.partial(self.on_connect_done, addrs, af, addr) - ) - - def on_connect_done( - self, - addrs: Iterator[Tuple[socket.AddressFamily, Tuple]], - af: socket.AddressFamily, - addr: Tuple, - future: "Future[IOStream]", - ) -> None: - self.remaining -= 1 - try: - stream = future.result() - except Exception as e: - if self.future.done(): - return - # Error: try again (but remember what happened so we have an - # error to raise in the end) - self.last_error = e - self.try_connect(addrs) - if self.timeout is not None: - # If the first attempt failed, don't wait for the - # timeout to try an address from the secondary queue. - self.io_loop.remove_timeout(self.timeout) - self.on_timeout() - return - self.clear_timeouts() - if self.future.done(): - # This is a late arrival; just drop it. - stream.close() - else: - self.streams.discard(stream) - self.future.set_result((af, addr, stream)) - self.close_streams() - - def set_timeout(self, timeout: float) -> None: - self.timeout = self.io_loop.add_timeout( - self.io_loop.time() + timeout, self.on_timeout - ) - - def on_timeout(self) -> None: - self.timeout = None - if not self.future.done(): - self.try_connect(iter(self.secondary_addrs)) - - def clear_timeout(self) -> None: - if self.timeout is not None: - self.io_loop.remove_timeout(self.timeout) - - def set_connect_timeout( - self, connect_timeout: Union[float, datetime.timedelta] - ) -> None: - self.connect_timeout = self.io_loop.add_timeout( - connect_timeout, self.on_connect_timeout - ) - - def on_connect_timeout(self) -> None: - if not self.future.done(): - self.future.set_exception(TimeoutError()) - self.close_streams() - - def clear_timeouts(self) -> None: - if self.timeout is not None: - self.io_loop.remove_timeout(self.timeout) - if self.connect_timeout is not None: - self.io_loop.remove_timeout(self.connect_timeout) - - def close_streams(self) -> None: - for stream in self.streams: - stream.close() - - -class TCPClient(object): - """A non-blocking TCP connection factory. - - .. versionchanged:: 5.0 - The ``io_loop`` argument (deprecated since version 4.1) has been removed. - """ - - def __init__(self, resolver: Optional[Resolver] = None) -> None: - if resolver is not None: - self.resolver = resolver - self._own_resolver = False - else: - self.resolver = Resolver() - self._own_resolver = True - - def close(self) -> None: - if self._own_resolver: - self.resolver.close() - - async def connect( - self, - host: str, - port: int, - af: socket.AddressFamily = socket.AF_UNSPEC, - ssl_options: Optional[Union[Dict[str, Any], ssl.SSLContext]] = None, - max_buffer_size: Optional[int] = None, - source_ip: Optional[str] = None, - source_port: Optional[int] = None, - timeout: Optional[Union[float, datetime.timedelta]] = None, - ) -> IOStream: - """Connect to the given host and port. - - Asynchronously returns an `.IOStream` (or `.SSLIOStream` if - ``ssl_options`` is not None). - - Using the ``source_ip`` kwarg, one can specify the source - IP address to use when establishing the connection. - In case the user needs to resolve and - use a specific interface, it has to be handled outside - of Tornado as this depends very much on the platform. - - Raises `TimeoutError` if the input future does not complete before - ``timeout``, which may be specified in any form allowed by - `.IOLoop.add_timeout` (i.e. a `datetime.timedelta` or an absolute time - relative to `.IOLoop.time`) - - Similarly, when the user requires a certain source port, it can - be specified using the ``source_port`` arg. - - .. versionchanged:: 4.5 - Added the ``source_ip`` and ``source_port`` arguments. - - .. versionchanged:: 5.0 - Added the ``timeout`` argument. - """ - if timeout is not None: - if isinstance(timeout, numbers.Real): - timeout = IOLoop.current().time() + timeout - elif isinstance(timeout, datetime.timedelta): - timeout = IOLoop.current().time() + timeout.total_seconds() - else: - raise TypeError("Unsupported timeout %r" % timeout) - if timeout is not None: - addrinfo = await gen.with_timeout( - timeout, self.resolver.resolve(host, port, af) - ) - else: - addrinfo = await self.resolver.resolve(host, port, af) - connector = _Connector( - addrinfo, - functools.partial( - self._create_stream, - max_buffer_size, - source_ip=source_ip, - source_port=source_port, - ), - ) - af, addr, stream = await connector.start(connect_timeout=timeout) - # TODO: For better performance we could cache the (af, addr) - # information here and re-use it on subsequent connections to - # the same host. (http://tools.ietf.org/html/rfc6555#section-4.2) - if ssl_options is not None: - if timeout is not None: - stream = await gen.with_timeout( - timeout, - stream.start_tls( - False, ssl_options=ssl_options, server_hostname=host - ), - ) - else: - stream = await stream.start_tls( - False, ssl_options=ssl_options, server_hostname=host - ) - return stream - - def _create_stream( - self, - max_buffer_size: int, - af: socket.AddressFamily, - addr: Tuple, - source_ip: Optional[str] = None, - source_port: Optional[int] = None, - ) -> Tuple[IOStream, "Future[IOStream]"]: - # Always connect in plaintext; we'll convert to ssl if necessary - # after one connection has completed. - source_port_bind = source_port if isinstance(source_port, int) else 0 - source_ip_bind = source_ip - if source_port_bind and not source_ip: - # User required a specific port, but did not specify - # a certain source IP, will bind to the default loopback. - source_ip_bind = "::1" if af == socket.AF_INET6 else "127.0.0.1" - # Trying to use the same address family as the requested af socket: - # - 127.0.0.1 for IPv4 - # - ::1 for IPv6 - socket_obj = socket.socket(af) - if source_port_bind or source_ip_bind: - # If the user requires binding also to a specific IP/port. - try: - socket_obj.bind((source_ip_bind, source_port_bind)) - except socket.error: - socket_obj.close() - # Fail loudly if unable to use the IP/port. - raise - try: - stream = IOStream(socket_obj, max_buffer_size=max_buffer_size) - except socket.error as e: - fu = Future() # type: Future[IOStream] - fu.set_exception(e) - return stream, fu - else: - return stream, stream.connect(addr) diff --git a/venv/lib/python3.8/site-packages/tornado/tcpserver.py b/venv/lib/python3.8/site-packages/tornado/tcpserver.py deleted file mode 100644 index 476ffc9..0000000 --- a/venv/lib/python3.8/site-packages/tornado/tcpserver.py +++ /dev/null @@ -1,334 +0,0 @@ -# -# Copyright 2011 Facebook -# -# 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. - -"""A non-blocking, single-threaded TCP server.""" - -import errno -import os -import socket -import ssl - -from tornado import gen -from tornado.log import app_log -from tornado.ioloop import IOLoop -from tornado.iostream import IOStream, SSLIOStream -from tornado.netutil import bind_sockets, add_accept_handler, ssl_wrap_socket -from tornado import process -from tornado.util import errno_from_exception - -import typing -from typing import Union, Dict, Any, Iterable, Optional, Awaitable - -if typing.TYPE_CHECKING: - from typing import Callable, List # noqa: F401 - - -class TCPServer(object): - r"""A non-blocking, single-threaded TCP server. - - To use `TCPServer`, define a subclass which overrides the `handle_stream` - method. For example, a simple echo server could be defined like this:: - - from tornado.tcpserver import TCPServer - from tornado.iostream import StreamClosedError - from tornado import gen - - class EchoServer(TCPServer): - async def handle_stream(self, stream, address): - while True: - try: - data = await stream.read_until(b"\n") - await stream.write(data) - except StreamClosedError: - break - - To make this server serve SSL traffic, send the ``ssl_options`` keyword - argument with an `ssl.SSLContext` object. For compatibility with older - versions of Python ``ssl_options`` may also be a dictionary of keyword - arguments for the `ssl.wrap_socket` method.:: - - ssl_ctx = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH) - ssl_ctx.load_cert_chain(os.path.join(data_dir, "mydomain.crt"), - os.path.join(data_dir, "mydomain.key")) - TCPServer(ssl_options=ssl_ctx) - - `TCPServer` initialization follows one of three patterns: - - 1. `listen`: simple single-process:: - - server = TCPServer() - server.listen(8888) - IOLoop.current().start() - - 2. `bind`/`start`: simple multi-process:: - - server = TCPServer() - server.bind(8888) - server.start(0) # Forks multiple sub-processes - IOLoop.current().start() - - When using this interface, an `.IOLoop` must *not* be passed - to the `TCPServer` constructor. `start` will always start - the server on the default singleton `.IOLoop`. - - 3. `add_sockets`: advanced multi-process:: - - sockets = bind_sockets(8888) - tornado.process.fork_processes(0) - server = TCPServer() - server.add_sockets(sockets) - IOLoop.current().start() - - The `add_sockets` interface is more complicated, but it can be - used with `tornado.process.fork_processes` to give you more - flexibility in when the fork happens. `add_sockets` can - also be used in single-process servers if you want to create - your listening sockets in some way other than - `~tornado.netutil.bind_sockets`. - - .. versionadded:: 3.1 - The ``max_buffer_size`` argument. - - .. versionchanged:: 5.0 - The ``io_loop`` argument has been removed. - """ - - def __init__( - self, - ssl_options: Optional[Union[Dict[str, Any], ssl.SSLContext]] = None, - max_buffer_size: Optional[int] = None, - read_chunk_size: Optional[int] = None, - ) -> None: - self.ssl_options = ssl_options - self._sockets = {} # type: Dict[int, socket.socket] - self._handlers = {} # type: Dict[int, Callable[[], None]] - self._pending_sockets = [] # type: List[socket.socket] - self._started = False - self._stopped = False - self.max_buffer_size = max_buffer_size - self.read_chunk_size = read_chunk_size - - # Verify the SSL options. Otherwise we don't get errors until clients - # connect. This doesn't verify that the keys are legitimate, but - # the SSL module doesn't do that until there is a connected socket - # which seems like too much work - if self.ssl_options is not None and isinstance(self.ssl_options, dict): - # Only certfile is required: it can contain both keys - if "certfile" not in self.ssl_options: - raise KeyError('missing key "certfile" in ssl_options') - - if not os.path.exists(self.ssl_options["certfile"]): - raise ValueError( - 'certfile "%s" does not exist' % self.ssl_options["certfile"] - ) - if "keyfile" in self.ssl_options and not os.path.exists( - self.ssl_options["keyfile"] - ): - raise ValueError( - 'keyfile "%s" does not exist' % self.ssl_options["keyfile"] - ) - - def listen(self, port: int, address: str = "") -> None: - """Starts accepting connections on the given port. - - This method may be called more than once to listen on multiple ports. - `listen` takes effect immediately; it is not necessary to call - `TCPServer.start` afterwards. It is, however, necessary to start - the `.IOLoop`. - """ - sockets = bind_sockets(port, address=address) - self.add_sockets(sockets) - - def add_sockets(self, sockets: Iterable[socket.socket]) -> None: - """Makes this server start accepting connections on the given sockets. - - The ``sockets`` parameter is a list of socket objects such as - those returned by `~tornado.netutil.bind_sockets`. - `add_sockets` is typically used in combination with that - method and `tornado.process.fork_processes` to provide greater - control over the initialization of a multi-process server. - """ - for sock in sockets: - self._sockets[sock.fileno()] = sock - self._handlers[sock.fileno()] = add_accept_handler( - sock, self._handle_connection - ) - - def add_socket(self, socket: socket.socket) -> None: - """Singular version of `add_sockets`. Takes a single socket object.""" - self.add_sockets([socket]) - - def bind( - self, - port: int, - address: Optional[str] = None, - family: socket.AddressFamily = socket.AF_UNSPEC, - backlog: int = 128, - reuse_port: bool = False, - ) -> None: - """Binds this server to the given port on the given address. - - To start the server, call `start`. If you want to run this server - in a single process, you can call `listen` as a shortcut to the - sequence of `bind` and `start` calls. - - Address may be either an IP address or hostname. If it's a hostname, - the server will listen on all IP addresses associated with the - name. Address may be an empty string or None to listen on all - available interfaces. Family may be set to either `socket.AF_INET` - or `socket.AF_INET6` to restrict to IPv4 or IPv6 addresses, otherwise - both will be used if available. - - The ``backlog`` argument has the same meaning as for - `socket.listen <socket.socket.listen>`. The ``reuse_port`` argument - has the same meaning as for `.bind_sockets`. - - This method may be called multiple times prior to `start` to listen - on multiple ports or interfaces. - - .. versionchanged:: 4.4 - Added the ``reuse_port`` argument. - """ - sockets = bind_sockets( - port, address=address, family=family, backlog=backlog, reuse_port=reuse_port - ) - if self._started: - self.add_sockets(sockets) - else: - self._pending_sockets.extend(sockets) - - def start( - self, num_processes: Optional[int] = 1, max_restarts: Optional[int] = None - ) -> None: - """Starts this server in the `.IOLoop`. - - By default, we run the server in this process and do not fork any - additional child process. - - If num_processes is ``None`` or <= 0, we detect the number of cores - available on this machine and fork that number of child - processes. If num_processes is given and > 1, we fork that - specific number of sub-processes. - - Since we use processes and not threads, there is no shared memory - between any server code. - - Note that multiple processes are not compatible with the autoreload - module (or the ``autoreload=True`` option to `tornado.web.Application` - which defaults to True when ``debug=True``). - When using multiple processes, no IOLoops can be created or - referenced until after the call to ``TCPServer.start(n)``. - - Values of ``num_processes`` other than 1 are not supported on Windows. - - The ``max_restarts`` argument is passed to `.fork_processes`. - - .. versionchanged:: 6.0 - - Added ``max_restarts`` argument. - """ - assert not self._started - self._started = True - if num_processes != 1: - process.fork_processes(num_processes, max_restarts) - sockets = self._pending_sockets - self._pending_sockets = [] - self.add_sockets(sockets) - - def stop(self) -> None: - """Stops listening for new connections. - - Requests currently in progress may still continue after the - server is stopped. - """ - if self._stopped: - return - self._stopped = True - for fd, sock in self._sockets.items(): - assert sock.fileno() == fd - # Unregister socket from IOLoop - self._handlers.pop(fd)() - sock.close() - - def handle_stream( - self, stream: IOStream, address: tuple - ) -> Optional[Awaitable[None]]: - """Override to handle a new `.IOStream` from an incoming connection. - - This method may be a coroutine; if so any exceptions it raises - asynchronously will be logged. Accepting of incoming connections - will not be blocked by this coroutine. - - If this `TCPServer` is configured for SSL, ``handle_stream`` - may be called before the SSL handshake has completed. Use - `.SSLIOStream.wait_for_handshake` if you need to verify the client's - certificate or use NPN/ALPN. - - .. versionchanged:: 4.2 - Added the option for this method to be a coroutine. - """ - raise NotImplementedError() - - def _handle_connection(self, connection: socket.socket, address: Any) -> None: - if self.ssl_options is not None: - assert ssl, "Python 2.6+ and OpenSSL required for SSL" - try: - connection = ssl_wrap_socket( - connection, - self.ssl_options, - server_side=True, - do_handshake_on_connect=False, - ) - except ssl.SSLError as err: - if err.args[0] == ssl.SSL_ERROR_EOF: - return connection.close() - else: - raise - except socket.error as err: - # If the connection is closed immediately after it is created - # (as in a port scan), we can get one of several errors. - # wrap_socket makes an internal call to getpeername, - # which may return either EINVAL (Mac OS X) or ENOTCONN - # (Linux). If it returns ENOTCONN, this error is - # silently swallowed by the ssl module, so we need to - # catch another error later on (AttributeError in - # SSLIOStream._do_ssl_handshake). - # To test this behavior, try nmap with the -sT flag. - # https://github.com/tornadoweb/tornado/pull/750 - if errno_from_exception(err) in (errno.ECONNABORTED, errno.EINVAL): - return connection.close() - else: - raise - try: - if self.ssl_options is not None: - stream = SSLIOStream( - connection, - max_buffer_size=self.max_buffer_size, - read_chunk_size=self.read_chunk_size, - ) # type: IOStream - else: - stream = IOStream( - connection, - max_buffer_size=self.max_buffer_size, - read_chunk_size=self.read_chunk_size, - ) - - future = self.handle_stream(stream, address) - if future is not None: - IOLoop.current().add_future( - gen.convert_yielded(future), lambda f: f.result() - ) - except Exception: - app_log.error("Error in connection callback", exc_info=True) diff --git a/venv/lib/python3.8/site-packages/tornado/template.py b/venv/lib/python3.8/site-packages/tornado/template.py deleted file mode 100644 index 2e6e0a2..0000000 --- a/venv/lib/python3.8/site-packages/tornado/template.py +++ /dev/null @@ -1,1048 +0,0 @@ -# -# Copyright 2009 Facebook -# -# 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. - -"""A simple template system that compiles templates to Python code. - -Basic usage looks like:: - - t = template.Template("<html>{{ myvalue }}</html>") - print(t.generate(myvalue="XXX")) - -`Loader` is a class that loads templates from a root directory and caches -the compiled templates:: - - loader = template.Loader("/home/btaylor") - print(loader.load("test.html").generate(myvalue="XXX")) - -We compile all templates to raw Python. Error-reporting is currently... uh, -interesting. Syntax for the templates:: - - ### base.html - <html> - <head> - <title>{% block title %}Default title{% end %}</title> - </head> - <body> - <ul> - {% for student in students %} - {% block student %} - <li>{{ escape(student.name) }}</li> - {% end %} - {% end %} - </ul> - </body> - </html> - - ### bold.html - {% extends "base.html" %} - - {% block title %}A bolder title{% end %} - - {% block student %} - <li><span style="bold">{{ escape(student.name) }}</span></li> - {% end %} - -Unlike most other template systems, we do not put any restrictions on the -expressions you can include in your statements. ``if`` and ``for`` blocks get -translated exactly into Python, so you can do complex expressions like:: - - {% for student in [p for p in people if p.student and p.age > 23] %} - <li>{{ escape(student.name) }}</li> - {% end %} - -Translating directly to Python means you can apply functions to expressions -easily, like the ``escape()`` function in the examples above. You can pass -functions in to your template just like any other variable -(In a `.RequestHandler`, override `.RequestHandler.get_template_namespace`):: - - ### Python code - def add(x, y): - return x + y - template.execute(add=add) - - ### The template - {{ add(1, 2) }} - -We provide the functions `escape() <.xhtml_escape>`, `.url_escape()`, -`.json_encode()`, and `.squeeze()` to all templates by default. - -Typical applications do not create `Template` or `Loader` instances by -hand, but instead use the `~.RequestHandler.render` and -`~.RequestHandler.render_string` methods of -`tornado.web.RequestHandler`, which load templates automatically based -on the ``template_path`` `.Application` setting. - -Variable names beginning with ``_tt_`` are reserved by the template -system and should not be used by application code. - -Syntax Reference ----------------- - -Template expressions are surrounded by double curly braces: ``{{ ... }}``. -The contents may be any python expression, which will be escaped according -to the current autoescape setting and inserted into the output. Other -template directives use ``{% %}``. - -To comment out a section so that it is omitted from the output, surround it -with ``{# ... #}``. - - -To include a literal ``{{``, ``{%``, or ``{#`` in the output, escape them as -``{{!``, ``{%!``, and ``{#!``, respectively. - - -``{% apply *function* %}...{% end %}`` - Applies a function to the output of all template code between ``apply`` - and ``end``:: - - {% apply linkify %}{{name}} said: {{message}}{% end %} - - Note that as an implementation detail apply blocks are implemented - as nested functions and thus may interact strangely with variables - set via ``{% set %}``, or the use of ``{% break %}`` or ``{% continue %}`` - within loops. - -``{% autoescape *function* %}`` - Sets the autoescape mode for the current file. This does not affect - other files, even those referenced by ``{% include %}``. Note that - autoescaping can also be configured globally, at the `.Application` - or `Loader`.:: - - {% autoescape xhtml_escape %} - {% autoescape None %} - -``{% block *name* %}...{% end %}`` - Indicates a named, replaceable block for use with ``{% extends %}``. - Blocks in the parent template will be replaced with the contents of - the same-named block in a child template.:: - - <!-- base.html --> - <title>{% block title %}Default title{% end %}</title> - - <!-- mypage.html --> - {% extends "base.html" %} - {% block title %}My page title{% end %} - -``{% comment ... %}`` - A comment which will be removed from the template output. Note that - there is no ``{% end %}`` tag; the comment goes from the word ``comment`` - to the closing ``%}`` tag. - -``{% extends *filename* %}`` - Inherit from another template. Templates that use ``extends`` should - contain one or more ``block`` tags to replace content from the parent - template. Anything in the child template not contained in a ``block`` - tag will be ignored. For an example, see the ``{% block %}`` tag. - -``{% for *var* in *expr* %}...{% end %}`` - Same as the python ``for`` statement. ``{% break %}`` and - ``{% continue %}`` may be used inside the loop. - -``{% from *x* import *y* %}`` - Same as the python ``import`` statement. - -``{% if *condition* %}...{% elif *condition* %}...{% else %}...{% end %}`` - Conditional statement - outputs the first section whose condition is - true. (The ``elif`` and ``else`` sections are optional) - -``{% import *module* %}`` - Same as the python ``import`` statement. - -``{% include *filename* %}`` - Includes another template file. The included file can see all the local - variables as if it were copied directly to the point of the ``include`` - directive (the ``{% autoescape %}`` directive is an exception). - Alternately, ``{% module Template(filename, **kwargs) %}`` may be used - to include another template with an isolated namespace. - -``{% module *expr* %}`` - Renders a `~tornado.web.UIModule`. The output of the ``UIModule`` is - not escaped:: - - {% module Template("foo.html", arg=42) %} - - ``UIModules`` are a feature of the `tornado.web.RequestHandler` - class (and specifically its ``render`` method) and will not work - when the template system is used on its own in other contexts. - -``{% raw *expr* %}`` - Outputs the result of the given expression without autoescaping. - -``{% set *x* = *y* %}`` - Sets a local variable. - -``{% try %}...{% except %}...{% else %}...{% finally %}...{% end %}`` - Same as the python ``try`` statement. - -``{% while *condition* %}... {% end %}`` - Same as the python ``while`` statement. ``{% break %}`` and - ``{% continue %}`` may be used inside the loop. - -``{% whitespace *mode* %}`` - Sets the whitespace mode for the remainder of the current file - (or until the next ``{% whitespace %}`` directive). See - `filter_whitespace` for available options. New in Tornado 4.3. -""" - -import datetime -from io import StringIO -import linecache -import os.path -import posixpath -import re -import threading - -from tornado import escape -from tornado.log import app_log -from tornado.util import ObjectDict, exec_in, unicode_type - -from typing import Any, Union, Callable, List, Dict, Iterable, Optional, TextIO -import typing - -if typing.TYPE_CHECKING: - from typing import Tuple, ContextManager # noqa: F401 - -_DEFAULT_AUTOESCAPE = "xhtml_escape" - - -class _UnsetMarker: - pass - - -_UNSET = _UnsetMarker() - - -def filter_whitespace(mode: str, text: str) -> str: - """Transform whitespace in ``text`` according to ``mode``. - - Available modes are: - - * ``all``: Return all whitespace unmodified. - * ``single``: Collapse consecutive whitespace with a single whitespace - character, preserving newlines. - * ``oneline``: Collapse all runs of whitespace into a single space - character, removing all newlines in the process. - - .. versionadded:: 4.3 - """ - if mode == "all": - return text - elif mode == "single": - text = re.sub(r"([\t ]+)", " ", text) - text = re.sub(r"(\s*\n\s*)", "\n", text) - return text - elif mode == "oneline": - return re.sub(r"(\s+)", " ", text) - else: - raise Exception("invalid whitespace mode %s" % mode) - - -class Template(object): - """A compiled template. - - We compile into Python from the given template_string. You can generate - the template from variables with generate(). - """ - - # note that the constructor's signature is not extracted with - # autodoc because _UNSET looks like garbage. When changing - # this signature update website/sphinx/template.rst too. - def __init__( - self, - template_string: Union[str, bytes], - name: str = "<string>", - loader: Optional["BaseLoader"] = None, - compress_whitespace: Union[bool, _UnsetMarker] = _UNSET, - autoescape: Optional[Union[str, _UnsetMarker]] = _UNSET, - whitespace: Optional[str] = None, - ) -> None: - """Construct a Template. - - :arg str template_string: the contents of the template file. - :arg str name: the filename from which the template was loaded - (used for error message). - :arg tornado.template.BaseLoader loader: the `~tornado.template.BaseLoader` responsible - for this template, used to resolve ``{% include %}`` and ``{% extend %}`` directives. - :arg bool compress_whitespace: Deprecated since Tornado 4.3. - Equivalent to ``whitespace="single"`` if true and - ``whitespace="all"`` if false. - :arg str autoescape: The name of a function in the template - namespace, or ``None`` to disable escaping by default. - :arg str whitespace: A string specifying treatment of whitespace; - see `filter_whitespace` for options. - - .. versionchanged:: 4.3 - Added ``whitespace`` parameter; deprecated ``compress_whitespace``. - """ - self.name = escape.native_str(name) - - if compress_whitespace is not _UNSET: - # Convert deprecated compress_whitespace (bool) to whitespace (str). - if whitespace is not None: - raise Exception("cannot set both whitespace and compress_whitespace") - whitespace = "single" if compress_whitespace else "all" - if whitespace is None: - if loader and loader.whitespace: - whitespace = loader.whitespace - else: - # Whitespace defaults by filename. - if name.endswith(".html") or name.endswith(".js"): - whitespace = "single" - else: - whitespace = "all" - # Validate the whitespace setting. - assert whitespace is not None - filter_whitespace(whitespace, "") - - if not isinstance(autoescape, _UnsetMarker): - self.autoescape = autoescape # type: Optional[str] - elif loader: - self.autoescape = loader.autoescape - else: - self.autoescape = _DEFAULT_AUTOESCAPE - - self.namespace = loader.namespace if loader else {} - reader = _TemplateReader(name, escape.native_str(template_string), whitespace) - self.file = _File(self, _parse(reader, self)) - self.code = self._generate_python(loader) - self.loader = loader - try: - # Under python2.5, the fake filename used here must match - # the module name used in __name__ below. - # The dont_inherit flag prevents template.py's future imports - # from being applied to the generated code. - self.compiled = compile( - escape.to_unicode(self.code), - "%s.generated.py" % self.name.replace(".", "_"), - "exec", - dont_inherit=True, - ) - except Exception: - formatted_code = _format_code(self.code).rstrip() - app_log.error("%s code:\n%s", self.name, formatted_code) - raise - - def generate(self, **kwargs: Any) -> bytes: - """Generate this template with the given arguments.""" - namespace = { - "escape": escape.xhtml_escape, - "xhtml_escape": escape.xhtml_escape, - "url_escape": escape.url_escape, - "json_encode": escape.json_encode, - "squeeze": escape.squeeze, - "linkify": escape.linkify, - "datetime": datetime, - "_tt_utf8": escape.utf8, # for internal use - "_tt_string_types": (unicode_type, bytes), - # __name__ and __loader__ allow the traceback mechanism to find - # the generated source code. - "__name__": self.name.replace(".", "_"), - "__loader__": ObjectDict(get_source=lambda name: self.code), - } - namespace.update(self.namespace) - namespace.update(kwargs) - exec_in(self.compiled, namespace) - execute = typing.cast(Callable[[], bytes], namespace["_tt_execute"]) - # Clear the traceback module's cache of source data now that - # we've generated a new template (mainly for this module's - # unittests, where different tests reuse the same name). - linecache.clearcache() - return execute() - - def _generate_python(self, loader: Optional["BaseLoader"]) -> str: - buffer = StringIO() - try: - # named_blocks maps from names to _NamedBlock objects - named_blocks = {} # type: Dict[str, _NamedBlock] - ancestors = self._get_ancestors(loader) - ancestors.reverse() - for ancestor in ancestors: - ancestor.find_named_blocks(loader, named_blocks) - writer = _CodeWriter(buffer, named_blocks, loader, ancestors[0].template) - ancestors[0].generate(writer) - return buffer.getvalue() - finally: - buffer.close() - - def _get_ancestors(self, loader: Optional["BaseLoader"]) -> List["_File"]: - ancestors = [self.file] - for chunk in self.file.body.chunks: - if isinstance(chunk, _ExtendsBlock): - if not loader: - raise ParseError( - "{% extends %} block found, but no " "template loader" - ) - template = loader.load(chunk.name, self.name) - ancestors.extend(template._get_ancestors(loader)) - return ancestors - - -class BaseLoader(object): - """Base class for template loaders. - - You must use a template loader to use template constructs like - ``{% extends %}`` and ``{% include %}``. The loader caches all - templates after they are loaded the first time. - """ - - def __init__( - self, - autoescape: str = _DEFAULT_AUTOESCAPE, - namespace: Optional[Dict[str, Any]] = None, - whitespace: Optional[str] = None, - ) -> None: - """Construct a template loader. - - :arg str autoescape: The name of a function in the template - namespace, such as "xhtml_escape", or ``None`` to disable - autoescaping by default. - :arg dict namespace: A dictionary to be added to the default template - namespace, or ``None``. - :arg str whitespace: A string specifying default behavior for - whitespace in templates; see `filter_whitespace` for options. - Default is "single" for files ending in ".html" and ".js" and - "all" for other files. - - .. versionchanged:: 4.3 - Added ``whitespace`` parameter. - """ - self.autoescape = autoescape - self.namespace = namespace or {} - self.whitespace = whitespace - self.templates = {} # type: Dict[str, Template] - # self.lock protects self.templates. It's a reentrant lock - # because templates may load other templates via `include` or - # `extends`. Note that thanks to the GIL this code would be safe - # even without the lock, but could lead to wasted work as multiple - # threads tried to compile the same template simultaneously. - self.lock = threading.RLock() - - def reset(self) -> None: - """Resets the cache of compiled templates.""" - with self.lock: - self.templates = {} - - def resolve_path(self, name: str, parent_path: Optional[str] = None) -> str: - """Converts a possibly-relative path to absolute (used internally).""" - raise NotImplementedError() - - def load(self, name: str, parent_path: Optional[str] = None) -> Template: - """Loads a template.""" - name = self.resolve_path(name, parent_path=parent_path) - with self.lock: - if name not in self.templates: - self.templates[name] = self._create_template(name) - return self.templates[name] - - def _create_template(self, name: str) -> Template: - raise NotImplementedError() - - -class Loader(BaseLoader): - """A template loader that loads from a single root directory. - """ - - def __init__(self, root_directory: str, **kwargs: Any) -> None: - super().__init__(**kwargs) - self.root = os.path.abspath(root_directory) - - def resolve_path(self, name: str, parent_path: Optional[str] = None) -> str: - if ( - parent_path - and not parent_path.startswith("<") - and not parent_path.startswith("/") - and not name.startswith("/") - ): - current_path = os.path.join(self.root, parent_path) - file_dir = os.path.dirname(os.path.abspath(current_path)) - relative_path = os.path.abspath(os.path.join(file_dir, name)) - if relative_path.startswith(self.root): - name = relative_path[len(self.root) + 1 :] - return name - - def _create_template(self, name: str) -> Template: - path = os.path.join(self.root, name) - with open(path, "rb") as f: - template = Template(f.read(), name=name, loader=self) - return template - - -class DictLoader(BaseLoader): - """A template loader that loads from a dictionary.""" - - def __init__(self, dict: Dict[str, str], **kwargs: Any) -> None: - super().__init__(**kwargs) - self.dict = dict - - def resolve_path(self, name: str, parent_path: Optional[str] = None) -> str: - if ( - parent_path - and not parent_path.startswith("<") - and not parent_path.startswith("/") - and not name.startswith("/") - ): - file_dir = posixpath.dirname(parent_path) - name = posixpath.normpath(posixpath.join(file_dir, name)) - return name - - def _create_template(self, name: str) -> Template: - return Template(self.dict[name], name=name, loader=self) - - -class _Node(object): - def each_child(self) -> Iterable["_Node"]: - return () - - def generate(self, writer: "_CodeWriter") -> None: - raise NotImplementedError() - - def find_named_blocks( - self, loader: Optional[BaseLoader], named_blocks: Dict[str, "_NamedBlock"] - ) -> None: - for child in self.each_child(): - child.find_named_blocks(loader, named_blocks) - - -class _File(_Node): - def __init__(self, template: Template, body: "_ChunkList") -> None: - self.template = template - self.body = body - self.line = 0 - - def generate(self, writer: "_CodeWriter") -> None: - writer.write_line("def _tt_execute():", self.line) - with writer.indent(): - writer.write_line("_tt_buffer = []", self.line) - writer.write_line("_tt_append = _tt_buffer.append", self.line) - self.body.generate(writer) - writer.write_line("return _tt_utf8('').join(_tt_buffer)", self.line) - - def each_child(self) -> Iterable["_Node"]: - return (self.body,) - - -class _ChunkList(_Node): - def __init__(self, chunks: List[_Node]) -> None: - self.chunks = chunks - - def generate(self, writer: "_CodeWriter") -> None: - for chunk in self.chunks: - chunk.generate(writer) - - def each_child(self) -> Iterable["_Node"]: - return self.chunks - - -class _NamedBlock(_Node): - def __init__(self, name: str, body: _Node, template: Template, line: int) -> None: - self.name = name - self.body = body - self.template = template - self.line = line - - def each_child(self) -> Iterable["_Node"]: - return (self.body,) - - def generate(self, writer: "_CodeWriter") -> None: - block = writer.named_blocks[self.name] - with writer.include(block.template, self.line): - block.body.generate(writer) - - def find_named_blocks( - self, loader: Optional[BaseLoader], named_blocks: Dict[str, "_NamedBlock"] - ) -> None: - named_blocks[self.name] = self - _Node.find_named_blocks(self, loader, named_blocks) - - -class _ExtendsBlock(_Node): - def __init__(self, name: str) -> None: - self.name = name - - -class _IncludeBlock(_Node): - def __init__(self, name: str, reader: "_TemplateReader", line: int) -> None: - self.name = name - self.template_name = reader.name - self.line = line - - def find_named_blocks( - self, loader: Optional[BaseLoader], named_blocks: Dict[str, _NamedBlock] - ) -> None: - assert loader is not None - included = loader.load(self.name, self.template_name) - included.file.find_named_blocks(loader, named_blocks) - - def generate(self, writer: "_CodeWriter") -> None: - assert writer.loader is not None - included = writer.loader.load(self.name, self.template_name) - with writer.include(included, self.line): - included.file.body.generate(writer) - - -class _ApplyBlock(_Node): - def __init__(self, method: str, line: int, body: _Node) -> None: - self.method = method - self.line = line - self.body = body - - def each_child(self) -> Iterable["_Node"]: - return (self.body,) - - def generate(self, writer: "_CodeWriter") -> None: - method_name = "_tt_apply%d" % writer.apply_counter - writer.apply_counter += 1 - writer.write_line("def %s():" % method_name, self.line) - with writer.indent(): - writer.write_line("_tt_buffer = []", self.line) - writer.write_line("_tt_append = _tt_buffer.append", self.line) - self.body.generate(writer) - writer.write_line("return _tt_utf8('').join(_tt_buffer)", self.line) - writer.write_line( - "_tt_append(_tt_utf8(%s(%s())))" % (self.method, method_name), self.line - ) - - -class _ControlBlock(_Node): - def __init__(self, statement: str, line: int, body: _Node) -> None: - self.statement = statement - self.line = line - self.body = body - - def each_child(self) -> Iterable[_Node]: - return (self.body,) - - def generate(self, writer: "_CodeWriter") -> None: - writer.write_line("%s:" % self.statement, self.line) - with writer.indent(): - self.body.generate(writer) - # Just in case the body was empty - writer.write_line("pass", self.line) - - -class _IntermediateControlBlock(_Node): - def __init__(self, statement: str, line: int) -> None: - self.statement = statement - self.line = line - - def generate(self, writer: "_CodeWriter") -> None: - # In case the previous block was empty - writer.write_line("pass", self.line) - writer.write_line("%s:" % self.statement, self.line, writer.indent_size() - 1) - - -class _Statement(_Node): - def __init__(self, statement: str, line: int) -> None: - self.statement = statement - self.line = line - - def generate(self, writer: "_CodeWriter") -> None: - writer.write_line(self.statement, self.line) - - -class _Expression(_Node): - def __init__(self, expression: str, line: int, raw: bool = False) -> None: - self.expression = expression - self.line = line - self.raw = raw - - def generate(self, writer: "_CodeWriter") -> None: - writer.write_line("_tt_tmp = %s" % self.expression, self.line) - writer.write_line( - "if isinstance(_tt_tmp, _tt_string_types):" " _tt_tmp = _tt_utf8(_tt_tmp)", - self.line, - ) - writer.write_line("else: _tt_tmp = _tt_utf8(str(_tt_tmp))", self.line) - if not self.raw and writer.current_template.autoescape is not None: - # In python3 functions like xhtml_escape return unicode, - # so we have to convert to utf8 again. - writer.write_line( - "_tt_tmp = _tt_utf8(%s(_tt_tmp))" % writer.current_template.autoescape, - self.line, - ) - writer.write_line("_tt_append(_tt_tmp)", self.line) - - -class _Module(_Expression): - def __init__(self, expression: str, line: int) -> None: - super().__init__("_tt_modules." + expression, line, raw=True) - - -class _Text(_Node): - def __init__(self, value: str, line: int, whitespace: str) -> None: - self.value = value - self.line = line - self.whitespace = whitespace - - def generate(self, writer: "_CodeWriter") -> None: - value = self.value - - # Compress whitespace if requested, with a crude heuristic to avoid - # altering preformatted whitespace. - if "<pre>" not in value: - value = filter_whitespace(self.whitespace, value) - - if value: - writer.write_line("_tt_append(%r)" % escape.utf8(value), self.line) - - -class ParseError(Exception): - """Raised for template syntax errors. - - ``ParseError`` instances have ``filename`` and ``lineno`` attributes - indicating the position of the error. - - .. versionchanged:: 4.3 - Added ``filename`` and ``lineno`` attributes. - """ - - def __init__( - self, message: str, filename: Optional[str] = None, lineno: int = 0 - ) -> None: - self.message = message - # The names "filename" and "lineno" are chosen for consistency - # with python SyntaxError. - self.filename = filename - self.lineno = lineno - - def __str__(self) -> str: - return "%s at %s:%d" % (self.message, self.filename, self.lineno) - - -class _CodeWriter(object): - def __init__( - self, - file: TextIO, - named_blocks: Dict[str, _NamedBlock], - loader: Optional[BaseLoader], - current_template: Template, - ) -> None: - self.file = file - self.named_blocks = named_blocks - self.loader = loader - self.current_template = current_template - self.apply_counter = 0 - self.include_stack = [] # type: List[Tuple[Template, int]] - self._indent = 0 - - def indent_size(self) -> int: - return self._indent - - def indent(self) -> "ContextManager": - class Indenter(object): - def __enter__(_) -> "_CodeWriter": - self._indent += 1 - return self - - def __exit__(_, *args: Any) -> None: - assert self._indent > 0 - self._indent -= 1 - - return Indenter() - - def include(self, template: Template, line: int) -> "ContextManager": - self.include_stack.append((self.current_template, line)) - self.current_template = template - - class IncludeTemplate(object): - def __enter__(_) -> "_CodeWriter": - return self - - def __exit__(_, *args: Any) -> None: - self.current_template = self.include_stack.pop()[0] - - return IncludeTemplate() - - def write_line( - self, line: str, line_number: int, indent: Optional[int] = None - ) -> None: - if indent is None: - indent = self._indent - line_comment = " # %s:%d" % (self.current_template.name, line_number) - if self.include_stack: - ancestors = [ - "%s:%d" % (tmpl.name, lineno) for (tmpl, lineno) in self.include_stack - ] - line_comment += " (via %s)" % ", ".join(reversed(ancestors)) - print(" " * indent + line + line_comment, file=self.file) - - -class _TemplateReader(object): - def __init__(self, name: str, text: str, whitespace: str) -> None: - self.name = name - self.text = text - self.whitespace = whitespace - self.line = 1 - self.pos = 0 - - def find(self, needle: str, start: int = 0, end: Optional[int] = None) -> int: - assert start >= 0, start - pos = self.pos - start += pos - if end is None: - index = self.text.find(needle, start) - else: - end += pos - assert end >= start - index = self.text.find(needle, start, end) - if index != -1: - index -= pos - return index - - def consume(self, count: Optional[int] = None) -> str: - if count is None: - count = len(self.text) - self.pos - newpos = self.pos + count - self.line += self.text.count("\n", self.pos, newpos) - s = self.text[self.pos : newpos] - self.pos = newpos - return s - - def remaining(self) -> int: - return len(self.text) - self.pos - - def __len__(self) -> int: - return self.remaining() - - def __getitem__(self, key: Union[int, slice]) -> str: - if isinstance(key, slice): - size = len(self) - start, stop, step = key.indices(size) - if start is None: - start = self.pos - else: - start += self.pos - if stop is not None: - stop += self.pos - return self.text[slice(start, stop, step)] - elif key < 0: - return self.text[key] - else: - return self.text[self.pos + key] - - def __str__(self) -> str: - return self.text[self.pos :] - - def raise_parse_error(self, msg: str) -> None: - raise ParseError(msg, self.name, self.line) - - -def _format_code(code: str) -> str: - lines = code.splitlines() - format = "%%%dd %%s\n" % len(repr(len(lines) + 1)) - return "".join([format % (i + 1, line) for (i, line) in enumerate(lines)]) - - -def _parse( - reader: _TemplateReader, - template: Template, - in_block: Optional[str] = None, - in_loop: Optional[str] = None, -) -> _ChunkList: - body = _ChunkList([]) - while True: - # Find next template directive - curly = 0 - while True: - curly = reader.find("{", curly) - if curly == -1 or curly + 1 == reader.remaining(): - # EOF - if in_block: - reader.raise_parse_error( - "Missing {%% end %%} block for %s" % in_block - ) - body.chunks.append( - _Text(reader.consume(), reader.line, reader.whitespace) - ) - return body - # If the first curly brace is not the start of a special token, - # start searching from the character after it - if reader[curly + 1] not in ("{", "%", "#"): - curly += 1 - continue - # When there are more than 2 curlies in a row, use the - # innermost ones. This is useful when generating languages - # like latex where curlies are also meaningful - if ( - curly + 2 < reader.remaining() - and reader[curly + 1] == "{" - and reader[curly + 2] == "{" - ): - curly += 1 - continue - break - - # Append any text before the special token - if curly > 0: - cons = reader.consume(curly) - body.chunks.append(_Text(cons, reader.line, reader.whitespace)) - - start_brace = reader.consume(2) - line = reader.line - - # Template directives may be escaped as "{{!" or "{%!". - # In this case output the braces and consume the "!". - # This is especially useful in conjunction with jquery templates, - # which also use double braces. - if reader.remaining() and reader[0] == "!": - reader.consume(1) - body.chunks.append(_Text(start_brace, line, reader.whitespace)) - continue - - # Comment - if start_brace == "{#": - end = reader.find("#}") - if end == -1: - reader.raise_parse_error("Missing end comment #}") - contents = reader.consume(end).strip() - reader.consume(2) - continue - - # Expression - if start_brace == "{{": - end = reader.find("}}") - if end == -1: - reader.raise_parse_error("Missing end expression }}") - contents = reader.consume(end).strip() - reader.consume(2) - if not contents: - reader.raise_parse_error("Empty expression") - body.chunks.append(_Expression(contents, line)) - continue - - # Block - assert start_brace == "{%", start_brace - end = reader.find("%}") - if end == -1: - reader.raise_parse_error("Missing end block %}") - contents = reader.consume(end).strip() - reader.consume(2) - if not contents: - reader.raise_parse_error("Empty block tag ({% %})") - - operator, space, suffix = contents.partition(" ") - suffix = suffix.strip() - - # Intermediate ("else", "elif", etc) blocks - intermediate_blocks = { - "else": set(["if", "for", "while", "try"]), - "elif": set(["if"]), - "except": set(["try"]), - "finally": set(["try"]), - } - allowed_parents = intermediate_blocks.get(operator) - if allowed_parents is not None: - if not in_block: - reader.raise_parse_error( - "%s outside %s block" % (operator, allowed_parents) - ) - if in_block not in allowed_parents: - reader.raise_parse_error( - "%s block cannot be attached to %s block" % (operator, in_block) - ) - body.chunks.append(_IntermediateControlBlock(contents, line)) - continue - - # End tag - elif operator == "end": - if not in_block: - reader.raise_parse_error("Extra {% end %} block") - return body - - elif operator in ( - "extends", - "include", - "set", - "import", - "from", - "comment", - "autoescape", - "whitespace", - "raw", - "module", - ): - if operator == "comment": - continue - if operator == "extends": - suffix = suffix.strip('"').strip("'") - if not suffix: - reader.raise_parse_error("extends missing file path") - block = _ExtendsBlock(suffix) # type: _Node - elif operator in ("import", "from"): - if not suffix: - reader.raise_parse_error("import missing statement") - block = _Statement(contents, line) - elif operator == "include": - suffix = suffix.strip('"').strip("'") - if not suffix: - reader.raise_parse_error("include missing file path") - block = _IncludeBlock(suffix, reader, line) - elif operator == "set": - if not suffix: - reader.raise_parse_error("set missing statement") - block = _Statement(suffix, line) - elif operator == "autoescape": - fn = suffix.strip() # type: Optional[str] - if fn == "None": - fn = None - template.autoescape = fn - continue - elif operator == "whitespace": - mode = suffix.strip() - # Validate the selected mode - filter_whitespace(mode, "") - reader.whitespace = mode - continue - elif operator == "raw": - block = _Expression(suffix, line, raw=True) - elif operator == "module": - block = _Module(suffix, line) - body.chunks.append(block) - continue - - elif operator in ("apply", "block", "try", "if", "for", "while"): - # parse inner body recursively - if operator in ("for", "while"): - block_body = _parse(reader, template, operator, operator) - elif operator == "apply": - # apply creates a nested function so syntactically it's not - # in the loop. - block_body = _parse(reader, template, operator, None) - else: - block_body = _parse(reader, template, operator, in_loop) - - if operator == "apply": - if not suffix: - reader.raise_parse_error("apply missing method name") - block = _ApplyBlock(suffix, line, block_body) - elif operator == "block": - if not suffix: - reader.raise_parse_error("block missing name") - block = _NamedBlock(suffix, block_body, template, line) - else: - block = _ControlBlock(contents, line, block_body) - body.chunks.append(block) - continue - - elif operator in ("break", "continue"): - if not in_loop: - reader.raise_parse_error( - "%s outside %s block" % (operator, set(["for", "while"])) - ) - body.chunks.append(_Statement(contents, line)) - continue - - else: - reader.raise_parse_error("unknown operator: %r" % operator) diff --git a/venv/lib/python3.8/site-packages/tornado/test/__main__.py b/venv/lib/python3.8/site-packages/tornado/test/__main__.py deleted file mode 100644 index 430c895..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/__main__.py +++ /dev/null @@ -1,12 +0,0 @@ -"""Shim to allow python -m tornado.test. - -This only works in python 2.7+. -""" -from tornado.test.runtests import all, main - -# tornado.testing.main autodiscovery relies on 'all' being present in -# the main module, so import it here even though it is not used directly. -# The following line prevents a pyflakes warning. -all = all - -main() diff --git a/venv/lib/python3.8/site-packages/tornado/test/asyncio_test.py b/venv/lib/python3.8/site-packages/tornado/test/asyncio_test.py deleted file mode 100644 index 3f9f338..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/asyncio_test.py +++ /dev/null @@ -1,190 +0,0 @@ -# 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. - -import asyncio -import unittest - -from concurrent.futures import ThreadPoolExecutor -from tornado import gen -from tornado.ioloop import IOLoop -from tornado.platform.asyncio import ( - AsyncIOLoop, - to_asyncio_future, - AnyThreadEventLoopPolicy, -) -from tornado.testing import AsyncTestCase, gen_test - - -class AsyncIOLoopTest(AsyncTestCase): - def get_new_ioloop(self): - io_loop = AsyncIOLoop() - return io_loop - - def test_asyncio_callback(self): - # Basic test that the asyncio loop is set up correctly. - asyncio.get_event_loop().call_soon(self.stop) - self.wait() - - @gen_test - def test_asyncio_future(self): - # Test that we can yield an asyncio future from a tornado coroutine. - # Without 'yield from', we must wrap coroutines in ensure_future, - # which was introduced during Python 3.4, deprecating the prior "async". - if hasattr(asyncio, "ensure_future"): - ensure_future = asyncio.ensure_future - else: - # async is a reserved word in Python 3.7 - ensure_future = getattr(asyncio, "async") - - x = yield ensure_future( - asyncio.get_event_loop().run_in_executor(None, lambda: 42) - ) - self.assertEqual(x, 42) - - @gen_test - def test_asyncio_yield_from(self): - @gen.coroutine - def f(): - event_loop = asyncio.get_event_loop() - x = yield from event_loop.run_in_executor(None, lambda: 42) - return x - - result = yield f() - self.assertEqual(result, 42) - - def test_asyncio_adapter(self): - # This test demonstrates that when using the asyncio coroutine - # runner (i.e. run_until_complete), the to_asyncio_future - # adapter is needed. No adapter is needed in the other direction, - # as demonstrated by other tests in the package. - @gen.coroutine - def tornado_coroutine(): - yield gen.moment - raise gen.Return(42) - - async def native_coroutine_without_adapter(): - return await tornado_coroutine() - - async def native_coroutine_with_adapter(): - return await to_asyncio_future(tornado_coroutine()) - - # Use the adapter, but two degrees from the tornado coroutine. - async def native_coroutine_with_adapter2(): - return await to_asyncio_future(native_coroutine_without_adapter()) - - # Tornado supports native coroutines both with and without adapters - self.assertEqual(self.io_loop.run_sync(native_coroutine_without_adapter), 42) - self.assertEqual(self.io_loop.run_sync(native_coroutine_with_adapter), 42) - self.assertEqual(self.io_loop.run_sync(native_coroutine_with_adapter2), 42) - - # Asyncio only supports coroutines that yield asyncio-compatible - # Futures (which our Future is since 5.0). - self.assertEqual( - asyncio.get_event_loop().run_until_complete( - native_coroutine_without_adapter() - ), - 42, - ) - self.assertEqual( - asyncio.get_event_loop().run_until_complete( - native_coroutine_with_adapter() - ), - 42, - ) - self.assertEqual( - asyncio.get_event_loop().run_until_complete( - native_coroutine_with_adapter2() - ), - 42, - ) - - -class LeakTest(unittest.TestCase): - def setUp(self): - # Trigger a cleanup of the mapping so we start with a clean slate. - AsyncIOLoop().close() - # If we don't clean up after ourselves other tests may fail on - # py34. - self.orig_policy = asyncio.get_event_loop_policy() - asyncio.set_event_loop_policy(asyncio.DefaultEventLoopPolicy()) - - def tearDown(self): - asyncio.get_event_loop().close() - asyncio.set_event_loop_policy(self.orig_policy) - - def test_ioloop_close_leak(self): - orig_count = len(IOLoop._ioloop_for_asyncio) - for i in range(10): - # Create and close an AsyncIOLoop using Tornado interfaces. - loop = AsyncIOLoop() - loop.close() - new_count = len(IOLoop._ioloop_for_asyncio) - orig_count - self.assertEqual(new_count, 0) - - def test_asyncio_close_leak(self): - orig_count = len(IOLoop._ioloop_for_asyncio) - for i in range(10): - # Create and close an AsyncIOMainLoop using asyncio interfaces. - loop = asyncio.new_event_loop() - loop.call_soon(IOLoop.current) - loop.call_soon(loop.stop) - loop.run_forever() - loop.close() - new_count = len(IOLoop._ioloop_for_asyncio) - orig_count - # Because the cleanup is run on new loop creation, we have one - # dangling entry in the map (but only one). - self.assertEqual(new_count, 1) - - -class AnyThreadEventLoopPolicyTest(unittest.TestCase): - def setUp(self): - self.orig_policy = asyncio.get_event_loop_policy() - self.executor = ThreadPoolExecutor(1) - - def tearDown(self): - asyncio.set_event_loop_policy(self.orig_policy) - self.executor.shutdown() - - def get_event_loop_on_thread(self): - def get_and_close_event_loop(): - """Get the event loop. Close it if one is returned. - - Returns the (closed) event loop. This is a silly thing - to do and leaves the thread in a broken state, but it's - enough for this test. Closing the loop avoids resource - leak warnings. - """ - loop = asyncio.get_event_loop() - loop.close() - return loop - - future = self.executor.submit(get_and_close_event_loop) - return future.result() - - def run_policy_test(self, accessor, expected_type): - # With the default policy, non-main threads don't get an event - # loop. - self.assertRaises( - (RuntimeError, AssertionError), self.executor.submit(accessor).result - ) - # Set the policy and we can get a loop. - asyncio.set_event_loop_policy(AnyThreadEventLoopPolicy()) - self.assertIsInstance(self.executor.submit(accessor).result(), expected_type) - # Clean up to silence leak warnings. Always use asyncio since - # IOLoop doesn't (currently) close the underlying loop. - self.executor.submit(lambda: asyncio.get_event_loop().close()).result() # type: ignore - - def test_asyncio_accessor(self): - self.run_policy_test(asyncio.get_event_loop, asyncio.AbstractEventLoop) - - def test_tornado_accessor(self): - self.run_policy_test(IOLoop.current, IOLoop) diff --git a/venv/lib/python3.8/site-packages/tornado/test/auth_test.py b/venv/lib/python3.8/site-packages/tornado/test/auth_test.py deleted file mode 100644 index 8de863e..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/auth_test.py +++ /dev/null @@ -1,609 +0,0 @@ -# These tests do not currently do much to verify the correct implementation -# of the openid/oauth protocols, they just exercise the major code paths -# and ensure that it doesn't blow up (e.g. with unicode/bytes issues in -# python 3) - -import unittest - -from tornado.auth import ( - OpenIdMixin, - OAuthMixin, - OAuth2Mixin, - GoogleOAuth2Mixin, - FacebookGraphMixin, - TwitterMixin, -) -from tornado.escape import json_decode -from tornado import gen -from tornado.httpclient import HTTPClientError -from tornado.httputil import url_concat -from tornado.log import app_log -from tornado.testing import AsyncHTTPTestCase, ExpectLog -from tornado.web import RequestHandler, Application, HTTPError - -try: - from unittest import mock -except ImportError: - mock = None # type: ignore - - -class OpenIdClientLoginHandler(RequestHandler, OpenIdMixin): - def initialize(self, test): - self._OPENID_ENDPOINT = test.get_url("/openid/server/authenticate") - - @gen.coroutine - def get(self): - if self.get_argument("openid.mode", None): - user = yield self.get_authenticated_user( - http_client=self.settings["http_client"] - ) - if user is None: - raise Exception("user is None") - self.finish(user) - return - res = self.authenticate_redirect() # type: ignore - assert res is None - - -class OpenIdServerAuthenticateHandler(RequestHandler): - def post(self): - if self.get_argument("openid.mode") != "check_authentication": - raise Exception("incorrect openid.mode %r") - self.write("is_valid:true") - - -class OAuth1ClientLoginHandler(RequestHandler, OAuthMixin): - def initialize(self, test, version): - self._OAUTH_VERSION = version - self._OAUTH_REQUEST_TOKEN_URL = test.get_url("/oauth1/server/request_token") - self._OAUTH_AUTHORIZE_URL = test.get_url("/oauth1/server/authorize") - self._OAUTH_ACCESS_TOKEN_URL = test.get_url("/oauth1/server/access_token") - - def _oauth_consumer_token(self): - return dict(key="asdf", secret="qwer") - - @gen.coroutine - def get(self): - if self.get_argument("oauth_token", None): - user = yield self.get_authenticated_user( - http_client=self.settings["http_client"] - ) - if user is None: - raise Exception("user is None") - self.finish(user) - return - yield self.authorize_redirect(http_client=self.settings["http_client"]) - - @gen.coroutine - def _oauth_get_user_future(self, access_token): - if self.get_argument("fail_in_get_user", None): - raise Exception("failing in get_user") - if access_token != dict(key="uiop", secret="5678"): - raise Exception("incorrect access token %r" % access_token) - return dict(email="foo@example.com") - - -class OAuth1ClientLoginCoroutineHandler(OAuth1ClientLoginHandler): - """Replaces OAuth1ClientLoginCoroutineHandler's get() with a coroutine.""" - - @gen.coroutine - def get(self): - if self.get_argument("oauth_token", None): - # Ensure that any exceptions are set on the returned Future, - # not simply thrown into the surrounding StackContext. - try: - yield self.get_authenticated_user() - except Exception as e: - self.set_status(503) - self.write("got exception: %s" % e) - else: - yield self.authorize_redirect() - - -class OAuth1ClientRequestParametersHandler(RequestHandler, OAuthMixin): - def initialize(self, version): - self._OAUTH_VERSION = version - - def _oauth_consumer_token(self): - return dict(key="asdf", secret="qwer") - - def get(self): - params = self._oauth_request_parameters( - "http://www.example.com/api/asdf", - dict(key="uiop", secret="5678"), - parameters=dict(foo="bar"), - ) - self.write(params) - - -class OAuth1ServerRequestTokenHandler(RequestHandler): - def get(self): - self.write("oauth_token=zxcv&oauth_token_secret=1234") - - -class OAuth1ServerAccessTokenHandler(RequestHandler): - def get(self): - self.write("oauth_token=uiop&oauth_token_secret=5678") - - -class OAuth2ClientLoginHandler(RequestHandler, OAuth2Mixin): - def initialize(self, test): - self._OAUTH_AUTHORIZE_URL = test.get_url("/oauth2/server/authorize") - - def get(self): - res = self.authorize_redirect() # type: ignore - assert res is None - - -class FacebookClientLoginHandler(RequestHandler, FacebookGraphMixin): - def initialize(self, test): - self._OAUTH_AUTHORIZE_URL = test.get_url("/facebook/server/authorize") - self._OAUTH_ACCESS_TOKEN_URL = test.get_url("/facebook/server/access_token") - self._FACEBOOK_BASE_URL = test.get_url("/facebook/server") - - @gen.coroutine - def get(self): - if self.get_argument("code", None): - user = yield self.get_authenticated_user( - redirect_uri=self.request.full_url(), - client_id=self.settings["facebook_api_key"], - client_secret=self.settings["facebook_secret"], - code=self.get_argument("code"), - ) - self.write(user) - else: - self.authorize_redirect( - redirect_uri=self.request.full_url(), - client_id=self.settings["facebook_api_key"], - extra_params={"scope": "read_stream,offline_access"}, - ) - - -class FacebookServerAccessTokenHandler(RequestHandler): - def get(self): - self.write(dict(access_token="asdf", expires_in=3600)) - - -class FacebookServerMeHandler(RequestHandler): - def get(self): - self.write("{}") - - -class TwitterClientHandler(RequestHandler, TwitterMixin): - def initialize(self, test): - self._OAUTH_REQUEST_TOKEN_URL = test.get_url("/oauth1/server/request_token") - self._OAUTH_ACCESS_TOKEN_URL = test.get_url("/twitter/server/access_token") - self._OAUTH_AUTHORIZE_URL = test.get_url("/oauth1/server/authorize") - self._OAUTH_AUTHENTICATE_URL = test.get_url("/twitter/server/authenticate") - self._TWITTER_BASE_URL = test.get_url("/twitter/api") - - def get_auth_http_client(self): - return self.settings["http_client"] - - -class TwitterClientLoginHandler(TwitterClientHandler): - @gen.coroutine - def get(self): - if self.get_argument("oauth_token", None): - user = yield self.get_authenticated_user() - if user is None: - raise Exception("user is None") - self.finish(user) - return - yield self.authorize_redirect() - - -class TwitterClientAuthenticateHandler(TwitterClientHandler): - # Like TwitterClientLoginHandler, but uses authenticate_redirect - # instead of authorize_redirect. - @gen.coroutine - def get(self): - if self.get_argument("oauth_token", None): - user = yield self.get_authenticated_user() - if user is None: - raise Exception("user is None") - self.finish(user) - return - yield self.authenticate_redirect() - - -class TwitterClientLoginGenCoroutineHandler(TwitterClientHandler): - @gen.coroutine - def get(self): - if self.get_argument("oauth_token", None): - user = yield self.get_authenticated_user() - self.finish(user) - else: - # New style: with @gen.coroutine the result must be yielded - # or else the request will be auto-finished too soon. - yield self.authorize_redirect() - - -class TwitterClientShowUserHandler(TwitterClientHandler): - @gen.coroutine - def get(self): - # TODO: would be nice to go through the login flow instead of - # cheating with a hard-coded access token. - try: - response = yield self.twitter_request( - "/users/show/%s" % self.get_argument("name"), - access_token=dict(key="hjkl", secret="vbnm"), - ) - except HTTPClientError: - # TODO(bdarnell): Should we catch HTTP errors and - # transform some of them (like 403s) into AuthError? - self.set_status(500) - self.finish("error from twitter request") - else: - self.finish(response) - - -class TwitterServerAccessTokenHandler(RequestHandler): - def get(self): - self.write("oauth_token=hjkl&oauth_token_secret=vbnm&screen_name=foo") - - -class TwitterServerShowUserHandler(RequestHandler): - def get(self, screen_name): - if screen_name == "error": - raise HTTPError(500) - assert "oauth_nonce" in self.request.arguments - assert "oauth_timestamp" in self.request.arguments - assert "oauth_signature" in self.request.arguments - assert self.get_argument("oauth_consumer_key") == "test_twitter_consumer_key" - assert self.get_argument("oauth_signature_method") == "HMAC-SHA1" - assert self.get_argument("oauth_version") == "1.0" - assert self.get_argument("oauth_token") == "hjkl" - self.write(dict(screen_name=screen_name, name=screen_name.capitalize())) - - -class TwitterServerVerifyCredentialsHandler(RequestHandler): - def get(self): - assert "oauth_nonce" in self.request.arguments - assert "oauth_timestamp" in self.request.arguments - assert "oauth_signature" in self.request.arguments - assert self.get_argument("oauth_consumer_key") == "test_twitter_consumer_key" - assert self.get_argument("oauth_signature_method") == "HMAC-SHA1" - assert self.get_argument("oauth_version") == "1.0" - assert self.get_argument("oauth_token") == "hjkl" - self.write(dict(screen_name="foo", name="Foo")) - - -class AuthTest(AsyncHTTPTestCase): - def get_app(self): - return Application( - [ - # test endpoints - ("/openid/client/login", OpenIdClientLoginHandler, dict(test=self)), - ( - "/oauth10/client/login", - OAuth1ClientLoginHandler, - dict(test=self, version="1.0"), - ), - ( - "/oauth10/client/request_params", - OAuth1ClientRequestParametersHandler, - dict(version="1.0"), - ), - ( - "/oauth10a/client/login", - OAuth1ClientLoginHandler, - dict(test=self, version="1.0a"), - ), - ( - "/oauth10a/client/login_coroutine", - OAuth1ClientLoginCoroutineHandler, - dict(test=self, version="1.0a"), - ), - ( - "/oauth10a/client/request_params", - OAuth1ClientRequestParametersHandler, - dict(version="1.0a"), - ), - ("/oauth2/client/login", OAuth2ClientLoginHandler, dict(test=self)), - ("/facebook/client/login", FacebookClientLoginHandler, dict(test=self)), - ("/twitter/client/login", TwitterClientLoginHandler, dict(test=self)), - ( - "/twitter/client/authenticate", - TwitterClientAuthenticateHandler, - dict(test=self), - ), - ( - "/twitter/client/login_gen_coroutine", - TwitterClientLoginGenCoroutineHandler, - dict(test=self), - ), - ( - "/twitter/client/show_user", - TwitterClientShowUserHandler, - dict(test=self), - ), - # simulated servers - ("/openid/server/authenticate", OpenIdServerAuthenticateHandler), - ("/oauth1/server/request_token", OAuth1ServerRequestTokenHandler), - ("/oauth1/server/access_token", OAuth1ServerAccessTokenHandler), - ("/facebook/server/access_token", FacebookServerAccessTokenHandler), - ("/facebook/server/me", FacebookServerMeHandler), - ("/twitter/server/access_token", TwitterServerAccessTokenHandler), - (r"/twitter/api/users/show/(.*)\.json", TwitterServerShowUserHandler), - ( - r"/twitter/api/account/verify_credentials\.json", - TwitterServerVerifyCredentialsHandler, - ), - ], - http_client=self.http_client, - twitter_consumer_key="test_twitter_consumer_key", - twitter_consumer_secret="test_twitter_consumer_secret", - facebook_api_key="test_facebook_api_key", - facebook_secret="test_facebook_secret", - ) - - def test_openid_redirect(self): - response = self.fetch("/openid/client/login", follow_redirects=False) - self.assertEqual(response.code, 302) - self.assertTrue("/openid/server/authenticate?" in response.headers["Location"]) - - def test_openid_get_user(self): - response = self.fetch( - "/openid/client/login?openid.mode=blah" - "&openid.ns.ax=http://openid.net/srv/ax/1.0" - "&openid.ax.type.email=http://axschema.org/contact/email" - "&openid.ax.value.email=foo@example.com" - ) - response.rethrow() - parsed = json_decode(response.body) - self.assertEqual(parsed["email"], "foo@example.com") - - def test_oauth10_redirect(self): - response = self.fetch("/oauth10/client/login", follow_redirects=False) - self.assertEqual(response.code, 302) - self.assertTrue( - response.headers["Location"].endswith( - "/oauth1/server/authorize?oauth_token=zxcv" - ) - ) - # the cookie is base64('zxcv')|base64('1234') - self.assertTrue( - '_oauth_request_token="enhjdg==|MTIzNA=="' - in response.headers["Set-Cookie"], - response.headers["Set-Cookie"], - ) - - def test_oauth10_get_user(self): - response = self.fetch( - "/oauth10/client/login?oauth_token=zxcv", - headers={"Cookie": "_oauth_request_token=enhjdg==|MTIzNA=="}, - ) - response.rethrow() - parsed = json_decode(response.body) - self.assertEqual(parsed["email"], "foo@example.com") - self.assertEqual(parsed["access_token"], dict(key="uiop", secret="5678")) - - def test_oauth10_request_parameters(self): - response = self.fetch("/oauth10/client/request_params") - response.rethrow() - parsed = json_decode(response.body) - self.assertEqual(parsed["oauth_consumer_key"], "asdf") - self.assertEqual(parsed["oauth_token"], "uiop") - self.assertTrue("oauth_nonce" in parsed) - self.assertTrue("oauth_signature" in parsed) - - def test_oauth10a_redirect(self): - response = self.fetch("/oauth10a/client/login", follow_redirects=False) - self.assertEqual(response.code, 302) - self.assertTrue( - response.headers["Location"].endswith( - "/oauth1/server/authorize?oauth_token=zxcv" - ) - ) - # the cookie is base64('zxcv')|base64('1234') - self.assertTrue( - '_oauth_request_token="enhjdg==|MTIzNA=="' - in response.headers["Set-Cookie"], - response.headers["Set-Cookie"], - ) - - @unittest.skipIf(mock is None, "mock package not present") - def test_oauth10a_redirect_error(self): - with mock.patch.object(OAuth1ServerRequestTokenHandler, "get") as get: - get.side_effect = Exception("boom") - with ExpectLog(app_log, "Uncaught exception"): - response = self.fetch("/oauth10a/client/login", follow_redirects=False) - self.assertEqual(response.code, 500) - - def test_oauth10a_get_user(self): - response = self.fetch( - "/oauth10a/client/login?oauth_token=zxcv", - headers={"Cookie": "_oauth_request_token=enhjdg==|MTIzNA=="}, - ) - response.rethrow() - parsed = json_decode(response.body) - self.assertEqual(parsed["email"], "foo@example.com") - self.assertEqual(parsed["access_token"], dict(key="uiop", secret="5678")) - - def test_oauth10a_request_parameters(self): - response = self.fetch("/oauth10a/client/request_params") - response.rethrow() - parsed = json_decode(response.body) - self.assertEqual(parsed["oauth_consumer_key"], "asdf") - self.assertEqual(parsed["oauth_token"], "uiop") - self.assertTrue("oauth_nonce" in parsed) - self.assertTrue("oauth_signature" in parsed) - - def test_oauth10a_get_user_coroutine_exception(self): - response = self.fetch( - "/oauth10a/client/login_coroutine?oauth_token=zxcv&fail_in_get_user=true", - headers={"Cookie": "_oauth_request_token=enhjdg==|MTIzNA=="}, - ) - self.assertEqual(response.code, 503) - - def test_oauth2_redirect(self): - response = self.fetch("/oauth2/client/login", follow_redirects=False) - self.assertEqual(response.code, 302) - self.assertTrue("/oauth2/server/authorize?" in response.headers["Location"]) - - def test_facebook_login(self): - response = self.fetch("/facebook/client/login", follow_redirects=False) - self.assertEqual(response.code, 302) - self.assertTrue("/facebook/server/authorize?" in response.headers["Location"]) - response = self.fetch( - "/facebook/client/login?code=1234", follow_redirects=False - ) - self.assertEqual(response.code, 200) - user = json_decode(response.body) - self.assertEqual(user["access_token"], "asdf") - self.assertEqual(user["session_expires"], "3600") - - def base_twitter_redirect(self, url): - # Same as test_oauth10a_redirect - response = self.fetch(url, follow_redirects=False) - self.assertEqual(response.code, 302) - self.assertTrue( - response.headers["Location"].endswith( - "/oauth1/server/authorize?oauth_token=zxcv" - ) - ) - # the cookie is base64('zxcv')|base64('1234') - self.assertTrue( - '_oauth_request_token="enhjdg==|MTIzNA=="' - in response.headers["Set-Cookie"], - response.headers["Set-Cookie"], - ) - - def test_twitter_redirect(self): - self.base_twitter_redirect("/twitter/client/login") - - def test_twitter_redirect_gen_coroutine(self): - self.base_twitter_redirect("/twitter/client/login_gen_coroutine") - - def test_twitter_authenticate_redirect(self): - response = self.fetch("/twitter/client/authenticate", follow_redirects=False) - self.assertEqual(response.code, 302) - self.assertTrue( - response.headers["Location"].endswith( - "/twitter/server/authenticate?oauth_token=zxcv" - ), - response.headers["Location"], - ) - # the cookie is base64('zxcv')|base64('1234') - self.assertTrue( - '_oauth_request_token="enhjdg==|MTIzNA=="' - in response.headers["Set-Cookie"], - response.headers["Set-Cookie"], - ) - - def test_twitter_get_user(self): - response = self.fetch( - "/twitter/client/login?oauth_token=zxcv", - headers={"Cookie": "_oauth_request_token=enhjdg==|MTIzNA=="}, - ) - response.rethrow() - parsed = json_decode(response.body) - self.assertEqual( - parsed, - { - u"access_token": { - u"key": u"hjkl", - u"screen_name": u"foo", - u"secret": u"vbnm", - }, - u"name": u"Foo", - u"screen_name": u"foo", - u"username": u"foo", - }, - ) - - def test_twitter_show_user(self): - response = self.fetch("/twitter/client/show_user?name=somebody") - response.rethrow() - self.assertEqual( - json_decode(response.body), {"name": "Somebody", "screen_name": "somebody"} - ) - - def test_twitter_show_user_error(self): - response = self.fetch("/twitter/client/show_user?name=error") - self.assertEqual(response.code, 500) - self.assertEqual(response.body, b"error from twitter request") - - -class GoogleLoginHandler(RequestHandler, GoogleOAuth2Mixin): - def initialize(self, test): - self.test = test - self._OAUTH_REDIRECT_URI = test.get_url("/client/login") - self._OAUTH_AUTHORIZE_URL = test.get_url("/google/oauth2/authorize") - self._OAUTH_ACCESS_TOKEN_URL = test.get_url("/google/oauth2/token") - - @gen.coroutine - def get(self): - code = self.get_argument("code", None) - if code is not None: - # retrieve authenticate google user - access = yield self.get_authenticated_user(self._OAUTH_REDIRECT_URI, code) - user = yield self.oauth2_request( - self.test.get_url("/google/oauth2/userinfo"), - access_token=access["access_token"], - ) - # return the user and access token as json - user["access_token"] = access["access_token"] - self.write(user) - else: - self.authorize_redirect( - redirect_uri=self._OAUTH_REDIRECT_URI, - client_id=self.settings["google_oauth"]["key"], - client_secret=self.settings["google_oauth"]["secret"], - scope=["profile", "email"], - response_type="code", - extra_params={"prompt": "select_account"}, - ) - - -class GoogleOAuth2AuthorizeHandler(RequestHandler): - def get(self): - # issue a fake auth code and redirect to redirect_uri - code = "fake-authorization-code" - self.redirect(url_concat(self.get_argument("redirect_uri"), dict(code=code))) - - -class GoogleOAuth2TokenHandler(RequestHandler): - def post(self): - assert self.get_argument("code") == "fake-authorization-code" - # issue a fake token - self.finish( - {"access_token": "fake-access-token", "expires_in": "never-expires"} - ) - - -class GoogleOAuth2UserinfoHandler(RequestHandler): - def get(self): - assert self.get_argument("access_token") == "fake-access-token" - # return a fake user - self.finish({"name": "Foo", "email": "foo@example.com"}) - - -class GoogleOAuth2Test(AsyncHTTPTestCase): - def get_app(self): - return Application( - [ - # test endpoints - ("/client/login", GoogleLoginHandler, dict(test=self)), - # simulated google authorization server endpoints - ("/google/oauth2/authorize", GoogleOAuth2AuthorizeHandler), - ("/google/oauth2/token", GoogleOAuth2TokenHandler), - ("/google/oauth2/userinfo", GoogleOAuth2UserinfoHandler), - ], - google_oauth={ - "key": "fake_google_client_id", - "secret": "fake_google_client_secret", - }, - ) - - def test_google_login(self): - response = self.fetch("/client/login") - self.assertDictEqual( - { - u"name": u"Foo", - u"email": u"foo@example.com", - u"access_token": u"fake-access-token", - }, - json_decode(response.body), - ) diff --git a/venv/lib/python3.8/site-packages/tornado/test/autoreload_test.py b/venv/lib/python3.8/site-packages/tornado/test/autoreload_test.py deleted file mode 100644 index be481e1..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/autoreload_test.py +++ /dev/null @@ -1,127 +0,0 @@ -import os -import shutil -import subprocess -from subprocess import Popen -import sys -from tempfile import mkdtemp -import time -import unittest - - -class AutoreloadTest(unittest.TestCase): - def setUp(self): - self.path = mkdtemp() - - def tearDown(self): - try: - shutil.rmtree(self.path) - except OSError: - # Windows disallows deleting files that are in use by - # another process, and even though we've waited for our - # child process below, it appears that its lock on these - # files is not guaranteed to be released by this point. - # Sleep and try again (once). - time.sleep(1) - shutil.rmtree(self.path) - - def test_reload_module(self): - main = """\ -import os -import sys - -from tornado import autoreload - -# This import will fail if path is not set up correctly -import testapp - -print('Starting') -if 'TESTAPP_STARTED' not in os.environ: - os.environ['TESTAPP_STARTED'] = '1' - sys.stdout.flush() - autoreload._reload() -""" - - # Create temporary test application - os.mkdir(os.path.join(self.path, "testapp")) - open(os.path.join(self.path, "testapp/__init__.py"), "w").close() - with open(os.path.join(self.path, "testapp/__main__.py"), "w") as f: - f.write(main) - - # Make sure the tornado module under test is available to the test - # application - pythonpath = os.getcwd() - if "PYTHONPATH" in os.environ: - pythonpath += os.pathsep + os.environ["PYTHONPATH"] - - p = Popen( - [sys.executable, "-m", "testapp"], - stdout=subprocess.PIPE, - cwd=self.path, - env=dict(os.environ, PYTHONPATH=pythonpath), - universal_newlines=True, - ) - out = p.communicate()[0] - self.assertEqual(out, "Starting\nStarting\n") - - def test_reload_wrapper_preservation(self): - # This test verifies that when `python -m tornado.autoreload` - # is used on an application that also has an internal - # autoreload, the reload wrapper is preserved on restart. - main = """\ -import os -import sys - -# This import will fail if path is not set up correctly -import testapp - -if 'tornado.autoreload' not in sys.modules: - raise Exception('started without autoreload wrapper') - -import tornado.autoreload - -print('Starting') -sys.stdout.flush() -if 'TESTAPP_STARTED' not in os.environ: - os.environ['TESTAPP_STARTED'] = '1' - # Simulate an internal autoreload (one not caused - # by the wrapper). - tornado.autoreload._reload() -else: - # Exit directly so autoreload doesn't catch it. - os._exit(0) -""" - - # Create temporary test application - os.mkdir(os.path.join(self.path, "testapp")) - init_file = os.path.join(self.path, "testapp", "__init__.py") - open(init_file, "w").close() - main_file = os.path.join(self.path, "testapp", "__main__.py") - with open(main_file, "w") as f: - f.write(main) - - # Make sure the tornado module under test is available to the test - # application - pythonpath = os.getcwd() - if "PYTHONPATH" in os.environ: - pythonpath += os.pathsep + os.environ["PYTHONPATH"] - - autoreload_proc = Popen( - [sys.executable, "-m", "tornado.autoreload", "-m", "testapp"], - stdout=subprocess.PIPE, - cwd=self.path, - env=dict(os.environ, PYTHONPATH=pythonpath), - universal_newlines=True, - ) - - # This timeout needs to be fairly generous for pypy due to jit - # warmup costs. - for i in range(40): - if autoreload_proc.poll() is not None: - break - time.sleep(0.1) - else: - autoreload_proc.kill() - raise Exception("subprocess failed to terminate") - - out = autoreload_proc.communicate()[0] - self.assertEqual(out, "Starting\n" * 2) diff --git a/venv/lib/python3.8/site-packages/tornado/test/concurrent_test.py b/venv/lib/python3.8/site-packages/tornado/test/concurrent_test.py deleted file mode 100644 index b121c69..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/concurrent_test.py +++ /dev/null @@ -1,212 +0,0 @@ -# -# Copyright 2012 Facebook -# -# 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. -from concurrent import futures -import logging -import re -import socket -import typing -import unittest - -from tornado.concurrent import ( - Future, - run_on_executor, - future_set_result_unless_cancelled, -) -from tornado.escape import utf8, to_unicode -from tornado import gen -from tornado.iostream import IOStream -from tornado.tcpserver import TCPServer -from tornado.testing import AsyncTestCase, bind_unused_port, gen_test - - -class MiscFutureTest(AsyncTestCase): - def test_future_set_result_unless_cancelled(self): - fut = Future() # type: Future[int] - future_set_result_unless_cancelled(fut, 42) - self.assertEqual(fut.result(), 42) - self.assertFalse(fut.cancelled()) - - fut = Future() - fut.cancel() - is_cancelled = fut.cancelled() - future_set_result_unless_cancelled(fut, 42) - self.assertEqual(fut.cancelled(), is_cancelled) - if not is_cancelled: - self.assertEqual(fut.result(), 42) - - -# The following series of classes demonstrate and test various styles -# of use, with and without generators and futures. - - -class CapServer(TCPServer): - @gen.coroutine - def handle_stream(self, stream, address): - data = yield stream.read_until(b"\n") - data = to_unicode(data) - if data == data.upper(): - stream.write(b"error\talready capitalized\n") - else: - # data already has \n - stream.write(utf8("ok\t%s" % data.upper())) - stream.close() - - -class CapError(Exception): - pass - - -class BaseCapClient(object): - def __init__(self, port): - self.port = port - - def process_response(self, data): - m = re.match("(.*)\t(.*)\n", to_unicode(data)) - if m is None: - raise Exception("did not match") - status, message = m.groups() - if status == "ok": - return message - else: - raise CapError(message) - - -class GeneratorCapClient(BaseCapClient): - @gen.coroutine - def capitalize(self, request_data): - logging.debug("capitalize") - stream = IOStream(socket.socket()) - logging.debug("connecting") - yield stream.connect(("127.0.0.1", self.port)) - stream.write(utf8(request_data + "\n")) - logging.debug("reading") - data = yield stream.read_until(b"\n") - logging.debug("returning") - stream.close() - raise gen.Return(self.process_response(data)) - - -class ClientTestMixin(object): - client_class = None # type: typing.Callable - - def setUp(self): - super().setUp() # type: ignore - self.server = CapServer() - sock, port = bind_unused_port() - self.server.add_sockets([sock]) - self.client = self.client_class(port=port) - - def tearDown(self): - self.server.stop() - super().tearDown() # type: ignore - - def test_future(self: typing.Any): - future = self.client.capitalize("hello") - self.io_loop.add_future(future, self.stop) - self.wait() - self.assertEqual(future.result(), "HELLO") - - def test_future_error(self: typing.Any): - future = self.client.capitalize("HELLO") - self.io_loop.add_future(future, self.stop) - self.wait() - self.assertRaisesRegexp(CapError, "already capitalized", future.result) # type: ignore - - def test_generator(self: typing.Any): - @gen.coroutine - def f(): - result = yield self.client.capitalize("hello") - self.assertEqual(result, "HELLO") - - self.io_loop.run_sync(f) - - def test_generator_error(self: typing.Any): - @gen.coroutine - def f(): - with self.assertRaisesRegexp(CapError, "already capitalized"): - yield self.client.capitalize("HELLO") - - self.io_loop.run_sync(f) - - -class GeneratorClientTest(ClientTestMixin, AsyncTestCase): - client_class = GeneratorCapClient - - -class RunOnExecutorTest(AsyncTestCase): - @gen_test - def test_no_calling(self): - class Object(object): - def __init__(self): - self.executor = futures.thread.ThreadPoolExecutor(1) - - @run_on_executor - def f(self): - return 42 - - o = Object() - answer = yield o.f() - self.assertEqual(answer, 42) - - @gen_test - def test_call_with_no_args(self): - class Object(object): - def __init__(self): - self.executor = futures.thread.ThreadPoolExecutor(1) - - @run_on_executor() - def f(self): - return 42 - - o = Object() - answer = yield o.f() - self.assertEqual(answer, 42) - - @gen_test - def test_call_with_executor(self): - class Object(object): - def __init__(self): - self.__executor = futures.thread.ThreadPoolExecutor(1) - - @run_on_executor(executor="_Object__executor") - def f(self): - return 42 - - o = Object() - answer = yield o.f() - self.assertEqual(answer, 42) - - @gen_test - def test_async_await(self): - class Object(object): - def __init__(self): - self.executor = futures.thread.ThreadPoolExecutor(1) - - @run_on_executor() - def f(self): - return 42 - - o = Object() - - async def f(): - answer = await o.f() - return answer - - result = yield f() - self.assertEqual(result, 42) - - -if __name__ == "__main__": - unittest.main() diff --git a/venv/lib/python3.8/site-packages/tornado/test/csv_translations/fr_FR.csv b/venv/lib/python3.8/site-packages/tornado/test/csv_translations/fr_FR.csv deleted file mode 100644 index 6321b6e..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/csv_translations/fr_FR.csv +++ /dev/null @@ -1 +0,0 @@ -"school","école" diff --git a/venv/lib/python3.8/site-packages/tornado/test/curl_httpclient_test.py b/venv/lib/python3.8/site-packages/tornado/test/curl_httpclient_test.py deleted file mode 100644 index 99af293..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/curl_httpclient_test.py +++ /dev/null @@ -1,129 +0,0 @@ -from hashlib import md5 -import unittest - -from tornado.escape import utf8 -from tornado.testing import AsyncHTTPTestCase -from tornado.test import httpclient_test -from tornado.web import Application, RequestHandler - - -try: - import pycurl -except ImportError: - pycurl = None # type: ignore - -if pycurl is not None: - from tornado.curl_httpclient import CurlAsyncHTTPClient - - -@unittest.skipIf(pycurl is None, "pycurl module not present") -class CurlHTTPClientCommonTestCase(httpclient_test.HTTPClientCommonTestCase): - def get_http_client(self): - client = CurlAsyncHTTPClient(defaults=dict(allow_ipv6=False)) - # make sure AsyncHTTPClient magic doesn't give us the wrong class - self.assertTrue(isinstance(client, CurlAsyncHTTPClient)) - return client - - -class DigestAuthHandler(RequestHandler): - def initialize(self, username, password): - self.username = username - self.password = password - - def get(self): - realm = "test" - opaque = "asdf" - # Real implementations would use a random nonce. - nonce = "1234" - - auth_header = self.request.headers.get("Authorization", None) - if auth_header is not None: - auth_mode, params = auth_header.split(" ", 1) - assert auth_mode == "Digest" - param_dict = {} - for pair in params.split(","): - k, v = pair.strip().split("=", 1) - if v[0] == '"' and v[-1] == '"': - v = v[1:-1] - param_dict[k] = v - assert param_dict["realm"] == realm - assert param_dict["opaque"] == opaque - assert param_dict["nonce"] == nonce - assert param_dict["username"] == self.username - assert param_dict["uri"] == self.request.path - h1 = md5( - utf8("%s:%s:%s" % (self.username, realm, self.password)) - ).hexdigest() - h2 = md5( - utf8("%s:%s" % (self.request.method, self.request.path)) - ).hexdigest() - digest = md5(utf8("%s:%s:%s" % (h1, nonce, h2))).hexdigest() - if digest == param_dict["response"]: - self.write("ok") - else: - self.write("fail") - else: - self.set_status(401) - self.set_header( - "WWW-Authenticate", - 'Digest realm="%s", nonce="%s", opaque="%s"' % (realm, nonce, opaque), - ) - - -class CustomReasonHandler(RequestHandler): - def get(self): - self.set_status(200, "Custom reason") - - -class CustomFailReasonHandler(RequestHandler): - def get(self): - self.set_status(400, "Custom reason") - - -@unittest.skipIf(pycurl is None, "pycurl module not present") -class CurlHTTPClientTestCase(AsyncHTTPTestCase): - def setUp(self): - super().setUp() - self.http_client = self.create_client() - - def get_app(self): - return Application( - [ - ("/digest", DigestAuthHandler, {"username": "foo", "password": "bar"}), - ( - "/digest_non_ascii", - DigestAuthHandler, - {"username": "foo", "password": "barユ£"}, - ), - ("/custom_reason", CustomReasonHandler), - ("/custom_fail_reason", CustomFailReasonHandler), - ] - ) - - def create_client(self, **kwargs): - return CurlAsyncHTTPClient( - force_instance=True, defaults=dict(allow_ipv6=False), **kwargs - ) - - def test_digest_auth(self): - response = self.fetch( - "/digest", auth_mode="digest", auth_username="foo", auth_password="bar" - ) - self.assertEqual(response.body, b"ok") - - def test_custom_reason(self): - response = self.fetch("/custom_reason") - self.assertEqual(response.reason, "Custom reason") - - def test_fail_custom_reason(self): - response = self.fetch("/custom_fail_reason") - self.assertEqual(str(response.error), "HTTP 400: Custom reason") - - def test_digest_auth_non_ascii(self): - response = self.fetch( - "/digest_non_ascii", - auth_mode="digest", - auth_username="foo", - auth_password="barユ£", - ) - self.assertEqual(response.body, b"ok") diff --git a/venv/lib/python3.8/site-packages/tornado/test/escape_test.py b/venv/lib/python3.8/site-packages/tornado/test/escape_test.py deleted file mode 100644 index d8f95e4..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/escape_test.py +++ /dev/null @@ -1,322 +0,0 @@ -import unittest - -import tornado.escape -from tornado.escape import ( - utf8, - xhtml_escape, - xhtml_unescape, - url_escape, - url_unescape, - to_unicode, - json_decode, - json_encode, - squeeze, - recursive_unicode, -) -from tornado.util import unicode_type - -from typing import List, Tuple, Union, Dict, Any # noqa: F401 - -linkify_tests = [ - # (input, linkify_kwargs, expected_output) - ( - "hello http://world.com/!", - {}, - u'hello <a href="http://world.com/">http://world.com/</a>!', - ), - ( - "hello http://world.com/with?param=true&stuff=yes", - {}, - u'hello <a href="http://world.com/with?param=true&amp;stuff=yes">http://world.com/with?param=true&amp;stuff=yes</a>', # noqa: E501 - ), - # an opened paren followed by many chars killed Gruber's regex - ( - "http://url.com/w(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - {}, - u'<a href="http://url.com/w">http://url.com/w</a>(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', # noqa: E501 - ), - # as did too many dots at the end - ( - "http://url.com/withmany.......................................", - {}, - u'<a href="http://url.com/withmany">http://url.com/withmany</a>.......................................', # noqa: E501 - ), - ( - "http://url.com/withmany((((((((((((((((((((((((((((((((((a)", - {}, - u'<a href="http://url.com/withmany">http://url.com/withmany</a>((((((((((((((((((((((((((((((((((a)', # noqa: E501 - ), - # some examples from http://daringfireball.net/2009/11/liberal_regex_for_matching_urls - # plus a fex extras (such as multiple parentheses). - ( - "http://foo.com/blah_blah", - {}, - u'<a href="http://foo.com/blah_blah">http://foo.com/blah_blah</a>', - ), - ( - "http://foo.com/blah_blah/", - {}, - u'<a href="http://foo.com/blah_blah/">http://foo.com/blah_blah/</a>', - ), - ( - "(Something like http://foo.com/blah_blah)", - {}, - u'(Something like <a href="http://foo.com/blah_blah">http://foo.com/blah_blah</a>)', - ), - ( - "http://foo.com/blah_blah_(wikipedia)", - {}, - u'<a href="http://foo.com/blah_blah_(wikipedia)">http://foo.com/blah_blah_(wikipedia)</a>', - ), - ( - "http://foo.com/blah_(blah)_(wikipedia)_blah", - {}, - u'<a href="http://foo.com/blah_(blah)_(wikipedia)_blah">http://foo.com/blah_(blah)_(wikipedia)_blah</a>', # noqa: E501 - ), - ( - "(Something like http://foo.com/blah_blah_(wikipedia))", - {}, - u'(Something like <a href="http://foo.com/blah_blah_(wikipedia)">http://foo.com/blah_blah_(wikipedia)</a>)', # noqa: E501 - ), - ( - "http://foo.com/blah_blah.", - {}, - u'<a href="http://foo.com/blah_blah">http://foo.com/blah_blah</a>.', - ), - ( - "http://foo.com/blah_blah/.", - {}, - u'<a href="http://foo.com/blah_blah/">http://foo.com/blah_blah/</a>.', - ), - ( - "<http://foo.com/blah_blah>", - {}, - u'&lt;<a href="http://foo.com/blah_blah">http://foo.com/blah_blah</a>&gt;', - ), - ( - "<http://foo.com/blah_blah/>", - {}, - u'&lt;<a href="http://foo.com/blah_blah/">http://foo.com/blah_blah/</a>&gt;', - ), - ( - "http://foo.com/blah_blah,", - {}, - u'<a href="http://foo.com/blah_blah">http://foo.com/blah_blah</a>,', - ), - ( - "http://www.example.com/wpstyle/?p=364.", - {}, - u'<a href="http://www.example.com/wpstyle/?p=364">http://www.example.com/wpstyle/?p=364</a>.', # noqa: E501 - ), - ( - "rdar://1234", - {"permitted_protocols": ["http", "rdar"]}, - u'<a href="rdar://1234">rdar://1234</a>', - ), - ( - "rdar:/1234", - {"permitted_protocols": ["rdar"]}, - u'<a href="rdar:/1234">rdar:/1234</a>', - ), - ( - "http://userid:password@example.com:8080", - {}, - u'<a href="http://userid:password@example.com:8080">http://userid:password@example.com:8080</a>', # noqa: E501 - ), - ( - "http://userid@example.com", - {}, - u'<a href="http://userid@example.com">http://userid@example.com</a>', - ), - ( - "http://userid@example.com:8080", - {}, - u'<a href="http://userid@example.com:8080">http://userid@example.com:8080</a>', - ), - ( - "http://userid:password@example.com", - {}, - u'<a href="http://userid:password@example.com">http://userid:password@example.com</a>', - ), - ( - "message://%3c330e7f8409726r6a4ba78dkf1fd71420c1bf6ff@mail.gmail.com%3e", - {"permitted_protocols": ["http", "message"]}, - u'<a href="message://%3c330e7f8409726r6a4ba78dkf1fd71420c1bf6ff@mail.gmail.com%3e">' - u"message://%3c330e7f8409726r6a4ba78dkf1fd71420c1bf6ff@mail.gmail.com%3e</a>", - ), - ( - u"http://\u27a1.ws/\u4a39", - {}, - u'<a href="http://\u27a1.ws/\u4a39">http://\u27a1.ws/\u4a39</a>', - ), - ( - "<tag>http://example.com</tag>", - {}, - u'&lt;tag&gt;<a href="http://example.com">http://example.com</a>&lt;/tag&gt;', - ), - ( - "Just a www.example.com link.", - {}, - u'Just a <a href="http://www.example.com">www.example.com</a> link.', - ), - ( - "Just a www.example.com link.", - {"require_protocol": True}, - u"Just a www.example.com link.", - ), - ( - "A http://reallylong.com/link/that/exceedsthelenglimit.html", - {"require_protocol": True, "shorten": True}, - u'A <a href="http://reallylong.com/link/that/exceedsthelenglimit.html"' - u' title="http://reallylong.com/link/that/exceedsthelenglimit.html">http://reallylong.com/link...</a>', # noqa: E501 - ), - ( - "A http://reallylongdomainnamethatwillbetoolong.com/hi!", - {"shorten": True}, - u'A <a href="http://reallylongdomainnamethatwillbetoolong.com/hi"' - u' title="http://reallylongdomainnamethatwillbetoolong.com/hi">http://reallylongdomainnametha...</a>!', # noqa: E501 - ), - ( - "A file:///passwords.txt and http://web.com link", - {}, - u'A file:///passwords.txt and <a href="http://web.com">http://web.com</a> link', - ), - ( - "A file:///passwords.txt and http://web.com link", - {"permitted_protocols": ["file"]}, - u'A <a href="file:///passwords.txt">file:///passwords.txt</a> and http://web.com link', - ), - ( - "www.external-link.com", - {"extra_params": 'rel="nofollow" class="external"'}, - u'<a href="http://www.external-link.com" rel="nofollow" class="external">www.external-link.com</a>', # noqa: E501 - ), - ( - "www.external-link.com and www.internal-link.com/blogs extra", - { - "extra_params": lambda href: 'class="internal"' - if href.startswith("http://www.internal-link.com") - else 'rel="nofollow" class="external"' - }, - u'<a href="http://www.external-link.com" rel="nofollow" class="external">www.external-link.com</a>' # noqa: E501 - u' and <a href="http://www.internal-link.com/blogs" class="internal">www.internal-link.com/blogs</a> extra', # noqa: E501 - ), - ( - "www.external-link.com", - {"extra_params": lambda href: ' rel="nofollow" class="external" '}, - u'<a href="http://www.external-link.com" rel="nofollow" class="external">www.external-link.com</a>', # noqa: E501 - ), -] # type: List[Tuple[Union[str, bytes], Dict[str, Any], str]] - - -class EscapeTestCase(unittest.TestCase): - def test_linkify(self): - for text, kwargs, html in linkify_tests: - linked = tornado.escape.linkify(text, **kwargs) - self.assertEqual(linked, html) - - def test_xhtml_escape(self): - tests = [ - ("<foo>", "&lt;foo&gt;"), - (u"<foo>", u"&lt;foo&gt;"), - (b"<foo>", b"&lt;foo&gt;"), - ("<>&\"'", "&lt;&gt;&amp;&quot;&#39;"), - ("&amp;", "&amp;amp;"), - (u"<\u00e9>", u"&lt;\u00e9&gt;"), - (b"<\xc3\xa9>", b"&lt;\xc3\xa9&gt;"), - ] # type: List[Tuple[Union[str, bytes], Union[str, bytes]]] - for unescaped, escaped in tests: - self.assertEqual(utf8(xhtml_escape(unescaped)), utf8(escaped)) - self.assertEqual(utf8(unescaped), utf8(xhtml_unescape(escaped))) - - def test_xhtml_unescape_numeric(self): - tests = [ - ("foo&#32;bar", "foo bar"), - ("foo&#x20;bar", "foo bar"), - ("foo&#X20;bar", "foo bar"), - ("foo&#xabc;bar", u"foo\u0abcbar"), - ("foo&#xyz;bar", "foo&#xyz;bar"), # invalid encoding - ("foo&#;bar", "foo&#;bar"), # invalid encoding - ("foo&#x;bar", "foo&#x;bar"), # invalid encoding - ] - for escaped, unescaped in tests: - self.assertEqual(unescaped, xhtml_unescape(escaped)) - - def test_url_escape_unicode(self): - tests = [ - # byte strings are passed through as-is - (u"\u00e9".encode("utf8"), "%C3%A9"), - (u"\u00e9".encode("latin1"), "%E9"), - # unicode strings become utf8 - (u"\u00e9", "%C3%A9"), - ] # type: List[Tuple[Union[str, bytes], str]] - for unescaped, escaped in tests: - self.assertEqual(url_escape(unescaped), escaped) - - def test_url_unescape_unicode(self): - tests = [ - ("%C3%A9", u"\u00e9", "utf8"), - ("%C3%A9", u"\u00c3\u00a9", "latin1"), - ("%C3%A9", utf8(u"\u00e9"), None), - ] - for escaped, unescaped, encoding in tests: - # input strings to url_unescape should only contain ascii - # characters, but make sure the function accepts both byte - # and unicode strings. - self.assertEqual(url_unescape(to_unicode(escaped), encoding), unescaped) - self.assertEqual(url_unescape(utf8(escaped), encoding), unescaped) - - def test_url_escape_quote_plus(self): - unescaped = "+ #%" - plus_escaped = "%2B+%23%25" - escaped = "%2B%20%23%25" - self.assertEqual(url_escape(unescaped), plus_escaped) - self.assertEqual(url_escape(unescaped, plus=False), escaped) - self.assertEqual(url_unescape(plus_escaped), unescaped) - self.assertEqual(url_unescape(escaped, plus=False), unescaped) - self.assertEqual(url_unescape(plus_escaped, encoding=None), utf8(unescaped)) - self.assertEqual( - url_unescape(escaped, encoding=None, plus=False), utf8(unescaped) - ) - - def test_escape_return_types(self): - # On python2 the escape methods should generally return the same - # type as their argument - self.assertEqual(type(xhtml_escape("foo")), str) - self.assertEqual(type(xhtml_escape(u"foo")), unicode_type) - - def test_json_decode(self): - # json_decode accepts both bytes and unicode, but strings it returns - # are always unicode. - self.assertEqual(json_decode(b'"foo"'), u"foo") - self.assertEqual(json_decode(u'"foo"'), u"foo") - - # Non-ascii bytes are interpreted as utf8 - self.assertEqual(json_decode(utf8(u'"\u00e9"')), u"\u00e9") - - def test_json_encode(self): - # json deals with strings, not bytes. On python 2 byte strings will - # convert automatically if they are utf8; on python 3 byte strings - # are not allowed. - self.assertEqual(json_decode(json_encode(u"\u00e9")), u"\u00e9") - if bytes is str: - self.assertEqual(json_decode(json_encode(utf8(u"\u00e9"))), u"\u00e9") - self.assertRaises(UnicodeDecodeError, json_encode, b"\xe9") - - def test_squeeze(self): - self.assertEqual( - squeeze(u"sequences of whitespace chars"), - u"sequences of whitespace chars", - ) - - def test_recursive_unicode(self): - tests = { - "dict": {b"foo": b"bar"}, - "list": [b"foo", b"bar"], - "tuple": (b"foo", b"bar"), - "bytes": b"foo", - } - self.assertEqual(recursive_unicode(tests["dict"]), {u"foo": u"bar"}) - self.assertEqual(recursive_unicode(tests["list"]), [u"foo", u"bar"]) - self.assertEqual(recursive_unicode(tests["tuple"]), (u"foo", u"bar")) - self.assertEqual(recursive_unicode(tests["bytes"]), u"foo") diff --git a/venv/lib/python3.8/site-packages/tornado/test/gen_test.py b/venv/lib/python3.8/site-packages/tornado/test/gen_test.py deleted file mode 100644 index 73c3387..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/gen_test.py +++ /dev/null @@ -1,1119 +0,0 @@ -import asyncio -from concurrent import futures -import gc -import datetime -import platform -import sys -import time -import weakref -import unittest - -from tornado.concurrent import Future -from tornado.log import app_log -from tornado.testing import AsyncHTTPTestCase, AsyncTestCase, ExpectLog, gen_test -from tornado.test.util import skipOnTravis, skipNotCPython -from tornado.web import Application, RequestHandler, HTTPError - -from tornado import gen - -try: - import contextvars -except ImportError: - contextvars = None # type: ignore - -import typing - -if typing.TYPE_CHECKING: - from typing import List, Optional # noqa: F401 - - -class GenBasicTest(AsyncTestCase): - @gen.coroutine - def delay(self, iterations, arg): - """Returns arg after a number of IOLoop iterations.""" - for i in range(iterations): - yield gen.moment - raise gen.Return(arg) - - @gen.coroutine - def async_future(self, result): - yield gen.moment - return result - - @gen.coroutine - def async_exception(self, e): - yield gen.moment - raise e - - @gen.coroutine - def add_one_async(self, x): - yield gen.moment - raise gen.Return(x + 1) - - def test_no_yield(self): - @gen.coroutine - def f(): - pass - - self.io_loop.run_sync(f) - - def test_exception_phase1(self): - @gen.coroutine - def f(): - 1 / 0 - - self.assertRaises(ZeroDivisionError, self.io_loop.run_sync, f) - - def test_exception_phase2(self): - @gen.coroutine - def f(): - yield gen.moment - 1 / 0 - - self.assertRaises(ZeroDivisionError, self.io_loop.run_sync, f) - - def test_bogus_yield(self): - @gen.coroutine - def f(): - yield 42 - - self.assertRaises(gen.BadYieldError, self.io_loop.run_sync, f) - - def test_bogus_yield_tuple(self): - @gen.coroutine - def f(): - yield (1, 2) - - self.assertRaises(gen.BadYieldError, self.io_loop.run_sync, f) - - def test_reuse(self): - @gen.coroutine - def f(): - yield gen.moment - - self.io_loop.run_sync(f) - self.io_loop.run_sync(f) - - def test_none(self): - @gen.coroutine - def f(): - yield None - - self.io_loop.run_sync(f) - - def test_multi(self): - @gen.coroutine - def f(): - results = yield [self.add_one_async(1), self.add_one_async(2)] - self.assertEqual(results, [2, 3]) - - self.io_loop.run_sync(f) - - def test_multi_dict(self): - @gen.coroutine - def f(): - results = yield dict(foo=self.add_one_async(1), bar=self.add_one_async(2)) - self.assertEqual(results, dict(foo=2, bar=3)) - - self.io_loop.run_sync(f) - - def test_multi_delayed(self): - @gen.coroutine - def f(): - # callbacks run at different times - responses = yield gen.multi_future( - [self.delay(3, "v1"), self.delay(1, "v2")] - ) - self.assertEqual(responses, ["v1", "v2"]) - - self.io_loop.run_sync(f) - - def test_multi_dict_delayed(self): - @gen.coroutine - def f(): - # callbacks run at different times - responses = yield gen.multi_future( - dict(foo=self.delay(3, "v1"), bar=self.delay(1, "v2")) - ) - self.assertEqual(responses, dict(foo="v1", bar="v2")) - - self.io_loop.run_sync(f) - - @skipOnTravis - @gen_test - def test_multi_performance(self): - # Yielding a list used to have quadratic performance; make - # sure a large list stays reasonable. On my laptop a list of - # 2000 used to take 1.8s, now it takes 0.12. - start = time.time() - yield [gen.moment for i in range(2000)] - end = time.time() - self.assertLess(end - start, 1.0) - - @gen_test - def test_multi_empty(self): - # Empty lists or dicts should return the same type. - x = yield [] - self.assertTrue(isinstance(x, list)) - y = yield {} - self.assertTrue(isinstance(y, dict)) - - @gen_test - def test_future(self): - result = yield self.async_future(1) - self.assertEqual(result, 1) - - @gen_test - def test_multi_future(self): - results = yield [self.async_future(1), self.async_future(2)] - self.assertEqual(results, [1, 2]) - - @gen_test - def test_multi_future_duplicate(self): - # Note that this doesn't work with native corotines, only with - # decorated coroutines. - f = self.async_future(2) - results = yield [self.async_future(1), f, self.async_future(3), f] - self.assertEqual(results, [1, 2, 3, 2]) - - @gen_test - def test_multi_dict_future(self): - results = yield dict(foo=self.async_future(1), bar=self.async_future(2)) - self.assertEqual(results, dict(foo=1, bar=2)) - - @gen_test - def test_multi_exceptions(self): - with ExpectLog(app_log, "Multiple exceptions in yield list"): - with self.assertRaises(RuntimeError) as cm: - yield gen.Multi( - [ - self.async_exception(RuntimeError("error 1")), - self.async_exception(RuntimeError("error 2")), - ] - ) - self.assertEqual(str(cm.exception), "error 1") - - # With only one exception, no error is logged. - with self.assertRaises(RuntimeError): - yield gen.Multi( - [self.async_exception(RuntimeError("error 1")), self.async_future(2)] - ) - - # Exception logging may be explicitly quieted. - with self.assertRaises(RuntimeError): - yield gen.Multi( - [ - self.async_exception(RuntimeError("error 1")), - self.async_exception(RuntimeError("error 2")), - ], - quiet_exceptions=RuntimeError, - ) - - @gen_test - def test_multi_future_exceptions(self): - with ExpectLog(app_log, "Multiple exceptions in yield list"): - with self.assertRaises(RuntimeError) as cm: - yield [ - self.async_exception(RuntimeError("error 1")), - self.async_exception(RuntimeError("error 2")), - ] - self.assertEqual(str(cm.exception), "error 1") - - # With only one exception, no error is logged. - with self.assertRaises(RuntimeError): - yield [self.async_exception(RuntimeError("error 1")), self.async_future(2)] - - # Exception logging may be explicitly quieted. - with self.assertRaises(RuntimeError): - yield gen.multi_future( - [ - self.async_exception(RuntimeError("error 1")), - self.async_exception(RuntimeError("error 2")), - ], - quiet_exceptions=RuntimeError, - ) - - def test_sync_raise_return(self): - @gen.coroutine - def f(): - raise gen.Return() - - self.io_loop.run_sync(f) - - def test_async_raise_return(self): - @gen.coroutine - def f(): - yield gen.moment - raise gen.Return() - - self.io_loop.run_sync(f) - - def test_sync_raise_return_value(self): - @gen.coroutine - def f(): - raise gen.Return(42) - - self.assertEqual(42, self.io_loop.run_sync(f)) - - def test_sync_raise_return_value_tuple(self): - @gen.coroutine - def f(): - raise gen.Return((1, 2)) - - self.assertEqual((1, 2), self.io_loop.run_sync(f)) - - def test_async_raise_return_value(self): - @gen.coroutine - def f(): - yield gen.moment - raise gen.Return(42) - - self.assertEqual(42, self.io_loop.run_sync(f)) - - def test_async_raise_return_value_tuple(self): - @gen.coroutine - def f(): - yield gen.moment - raise gen.Return((1, 2)) - - self.assertEqual((1, 2), self.io_loop.run_sync(f)) - - -class GenCoroutineTest(AsyncTestCase): - def setUp(self): - # Stray StopIteration exceptions can lead to tests exiting prematurely, - # so we need explicit checks here to make sure the tests run all - # the way through. - self.finished = False - super().setUp() - - def tearDown(self): - super().tearDown() - assert self.finished - - def test_attributes(self): - self.finished = True - - def f(): - yield gen.moment - - coro = gen.coroutine(f) - self.assertEqual(coro.__name__, f.__name__) - self.assertEqual(coro.__module__, f.__module__) - self.assertIs(coro.__wrapped__, f) # type: ignore - - def test_is_coroutine_function(self): - self.finished = True - - def f(): - yield gen.moment - - coro = gen.coroutine(f) - self.assertFalse(gen.is_coroutine_function(f)) - self.assertTrue(gen.is_coroutine_function(coro)) - self.assertFalse(gen.is_coroutine_function(coro())) - - @gen_test - def test_sync_gen_return(self): - @gen.coroutine - def f(): - raise gen.Return(42) - - result = yield f() - self.assertEqual(result, 42) - self.finished = True - - @gen_test - def test_async_gen_return(self): - @gen.coroutine - def f(): - yield gen.moment - raise gen.Return(42) - - result = yield f() - self.assertEqual(result, 42) - self.finished = True - - @gen_test - def test_sync_return(self): - @gen.coroutine - def f(): - return 42 - - result = yield f() - self.assertEqual(result, 42) - self.finished = True - - @gen_test - def test_async_return(self): - @gen.coroutine - def f(): - yield gen.moment - return 42 - - result = yield f() - self.assertEqual(result, 42) - self.finished = True - - @gen_test - def test_async_early_return(self): - # A yield statement exists but is not executed, which means - # this function "returns" via an exception. This exception - # doesn't happen before the exception handling is set up. - @gen.coroutine - def f(): - if True: - return 42 - yield gen.Task(self.io_loop.add_callback) - - result = yield f() - self.assertEqual(result, 42) - self.finished = True - - @gen_test - def test_async_await(self): - @gen.coroutine - def f1(): - yield gen.moment - raise gen.Return(42) - - # This test verifies that an async function can await a - # yield-based gen.coroutine, and that a gen.coroutine - # (the test method itself) can yield an async function. - async def f2(): - result = await f1() - return result - - result = yield f2() - self.assertEqual(result, 42) - self.finished = True - - @gen_test - def test_asyncio_sleep_zero(self): - # asyncio.sleep(0) turns into a special case (equivalent to - # `yield None`) - async def f(): - import asyncio - - await asyncio.sleep(0) - return 42 - - result = yield f() - self.assertEqual(result, 42) - self.finished = True - - @gen_test - def test_async_await_mixed_multi_native_future(self): - @gen.coroutine - def f1(): - yield gen.moment - - async def f2(): - await f1() - return 42 - - @gen.coroutine - def f3(): - yield gen.moment - raise gen.Return(43) - - results = yield [f2(), f3()] - self.assertEqual(results, [42, 43]) - self.finished = True - - @gen_test - def test_async_with_timeout(self): - async def f1(): - return 42 - - result = yield gen.with_timeout(datetime.timedelta(hours=1), f1()) - self.assertEqual(result, 42) - self.finished = True - - @gen_test - def test_sync_return_no_value(self): - @gen.coroutine - def f(): - return - - result = yield f() - self.assertEqual(result, None) - self.finished = True - - @gen_test - def test_async_return_no_value(self): - # Without a return value we don't need python 3.3. - @gen.coroutine - def f(): - yield gen.moment - return - - result = yield f() - self.assertEqual(result, None) - self.finished = True - - @gen_test - def test_sync_raise(self): - @gen.coroutine - def f(): - 1 / 0 - - # The exception is raised when the future is yielded - # (or equivalently when its result method is called), - # not when the function itself is called). - future = f() - with self.assertRaises(ZeroDivisionError): - yield future - self.finished = True - - @gen_test - def test_async_raise(self): - @gen.coroutine - def f(): - yield gen.moment - 1 / 0 - - future = f() - with self.assertRaises(ZeroDivisionError): - yield future - self.finished = True - - @gen_test - def test_replace_yieldpoint_exception(self): - # Test exception handling: a coroutine can catch one exception - # raised by a yield point and raise a different one. - @gen.coroutine - def f1(): - 1 / 0 - - @gen.coroutine - def f2(): - try: - yield f1() - except ZeroDivisionError: - raise KeyError() - - future = f2() - with self.assertRaises(KeyError): - yield future - self.finished = True - - @gen_test - def test_swallow_yieldpoint_exception(self): - # Test exception handling: a coroutine can catch an exception - # raised by a yield point and not raise a different one. - @gen.coroutine - def f1(): - 1 / 0 - - @gen.coroutine - def f2(): - try: - yield f1() - except ZeroDivisionError: - raise gen.Return(42) - - result = yield f2() - self.assertEqual(result, 42) - self.finished = True - - @gen_test - def test_moment(self): - calls = [] - - @gen.coroutine - def f(name, yieldable): - for i in range(5): - calls.append(name) - yield yieldable - - # First, confirm the behavior without moment: each coroutine - # monopolizes the event loop until it finishes. - immediate = Future() # type: Future[None] - immediate.set_result(None) - yield [f("a", immediate), f("b", immediate)] - self.assertEqual("".join(calls), "aaaaabbbbb") - - # With moment, they take turns. - calls = [] - yield [f("a", gen.moment), f("b", gen.moment)] - self.assertEqual("".join(calls), "ababababab") - self.finished = True - - calls = [] - yield [f("a", gen.moment), f("b", immediate)] - self.assertEqual("".join(calls), "abbbbbaaaa") - - @gen_test - def test_sleep(self): - yield gen.sleep(0.01) - self.finished = True - - @gen_test - def test_py3_leak_exception_context(self): - class LeakedException(Exception): - pass - - @gen.coroutine - def inner(iteration): - raise LeakedException(iteration) - - try: - yield inner(1) - except LeakedException as e: - self.assertEqual(str(e), "1") - self.assertIsNone(e.__context__) - - try: - yield inner(2) - except LeakedException as e: - self.assertEqual(str(e), "2") - self.assertIsNone(e.__context__) - - self.finished = True - - @skipNotCPython - @unittest.skipIf( - (3,) < sys.version_info < (3, 6), "asyncio.Future has reference cycles" - ) - def test_coroutine_refcounting(self): - # On CPython, tasks and their arguments should be released immediately - # without waiting for garbage collection. - @gen.coroutine - def inner(): - class Foo(object): - pass - - local_var = Foo() - self.local_ref = weakref.ref(local_var) - - def dummy(): - pass - - yield gen.coroutine(dummy)() - raise ValueError("Some error") - - @gen.coroutine - def inner2(): - try: - yield inner() - except ValueError: - pass - - self.io_loop.run_sync(inner2, timeout=3) - - self.assertIs(self.local_ref(), None) - self.finished = True - - def test_asyncio_future_debug_info(self): - self.finished = True - # Enable debug mode - asyncio_loop = asyncio.get_event_loop() - self.addCleanup(asyncio_loop.set_debug, asyncio_loop.get_debug()) - asyncio_loop.set_debug(True) - - def f(): - yield gen.moment - - coro = gen.coroutine(f)() - self.assertIsInstance(coro, asyncio.Future) - # We expect the coroutine repr() to show the place where - # it was instantiated - expected = "created at %s:%d" % (__file__, f.__code__.co_firstlineno + 3) - actual = repr(coro) - self.assertIn(expected, actual) - - @gen_test - def test_asyncio_gather(self): - # This demonstrates that tornado coroutines can be understood - # by asyncio (This failed prior to Tornado 5.0). - @gen.coroutine - def f(): - yield gen.moment - raise gen.Return(1) - - ret = yield asyncio.gather(f(), f()) - self.assertEqual(ret, [1, 1]) - self.finished = True - - -class GenCoroutineSequenceHandler(RequestHandler): - @gen.coroutine - def get(self): - yield gen.moment - self.write("1") - yield gen.moment - self.write("2") - yield gen.moment - self.finish("3") - - -class GenCoroutineUnfinishedSequenceHandler(RequestHandler): - @gen.coroutine - def get(self): - yield gen.moment - self.write("1") - yield gen.moment - self.write("2") - yield gen.moment - # just write, don't finish - self.write("3") - - -# "Undecorated" here refers to the absence of @asynchronous. -class UndecoratedCoroutinesHandler(RequestHandler): - @gen.coroutine - def prepare(self): - self.chunks = [] # type: List[str] - yield gen.moment - self.chunks.append("1") - - @gen.coroutine - def get(self): - self.chunks.append("2") - yield gen.moment - self.chunks.append("3") - yield gen.moment - self.write("".join(self.chunks)) - - -class AsyncPrepareErrorHandler(RequestHandler): - @gen.coroutine - def prepare(self): - yield gen.moment - raise HTTPError(403) - - def get(self): - self.finish("ok") - - -class NativeCoroutineHandler(RequestHandler): - async def get(self): - await asyncio.sleep(0) - self.write("ok") - - -class GenWebTest(AsyncHTTPTestCase): - def get_app(self): - return Application( - [ - ("/coroutine_sequence", GenCoroutineSequenceHandler), - ( - "/coroutine_unfinished_sequence", - GenCoroutineUnfinishedSequenceHandler, - ), - ("/undecorated_coroutine", UndecoratedCoroutinesHandler), - ("/async_prepare_error", AsyncPrepareErrorHandler), - ("/native_coroutine", NativeCoroutineHandler), - ] - ) - - def test_coroutine_sequence_handler(self): - response = self.fetch("/coroutine_sequence") - self.assertEqual(response.body, b"123") - - def test_coroutine_unfinished_sequence_handler(self): - response = self.fetch("/coroutine_unfinished_sequence") - self.assertEqual(response.body, b"123") - - def test_undecorated_coroutines(self): - response = self.fetch("/undecorated_coroutine") - self.assertEqual(response.body, b"123") - - def test_async_prepare_error_handler(self): - response = self.fetch("/async_prepare_error") - self.assertEqual(response.code, 403) - - def test_native_coroutine_handler(self): - response = self.fetch("/native_coroutine") - self.assertEqual(response.code, 200) - self.assertEqual(response.body, b"ok") - - -class WithTimeoutTest(AsyncTestCase): - @gen_test - def test_timeout(self): - with self.assertRaises(gen.TimeoutError): - yield gen.with_timeout(datetime.timedelta(seconds=0.1), Future()) - - @gen_test - def test_completes_before_timeout(self): - future = Future() # type: Future[str] - self.io_loop.add_timeout( - datetime.timedelta(seconds=0.1), lambda: future.set_result("asdf") - ) - result = yield gen.with_timeout(datetime.timedelta(seconds=3600), future) - self.assertEqual(result, "asdf") - - @gen_test - def test_fails_before_timeout(self): - future = Future() # type: Future[str] - self.io_loop.add_timeout( - datetime.timedelta(seconds=0.1), - lambda: future.set_exception(ZeroDivisionError()), - ) - with self.assertRaises(ZeroDivisionError): - yield gen.with_timeout(datetime.timedelta(seconds=3600), future) - - @gen_test - def test_already_resolved(self): - future = Future() # type: Future[str] - future.set_result("asdf") - result = yield gen.with_timeout(datetime.timedelta(seconds=3600), future) - self.assertEqual(result, "asdf") - - @gen_test - def test_timeout_concurrent_future(self): - # A concurrent future that does not resolve before the timeout. - with futures.ThreadPoolExecutor(1) as executor: - with self.assertRaises(gen.TimeoutError): - yield gen.with_timeout( - self.io_loop.time(), executor.submit(time.sleep, 0.1) - ) - - @gen_test - def test_completed_concurrent_future(self): - # A concurrent future that is resolved before we even submit it - # to with_timeout. - with futures.ThreadPoolExecutor(1) as executor: - - def dummy(): - pass - - f = executor.submit(dummy) - f.result() # wait for completion - yield gen.with_timeout(datetime.timedelta(seconds=3600), f) - - @gen_test - def test_normal_concurrent_future(self): - # A conccurrent future that resolves while waiting for the timeout. - with futures.ThreadPoolExecutor(1) as executor: - yield gen.with_timeout( - datetime.timedelta(seconds=3600), - executor.submit(lambda: time.sleep(0.01)), - ) - - -class WaitIteratorTest(AsyncTestCase): - @gen_test - def test_empty_iterator(self): - g = gen.WaitIterator() - self.assertTrue(g.done(), "empty generator iterated") - - with self.assertRaises(ValueError): - g = gen.WaitIterator(Future(), bar=Future()) - - self.assertEqual(g.current_index, None, "bad nil current index") - self.assertEqual(g.current_future, None, "bad nil current future") - - @gen_test - def test_already_done(self): - f1 = Future() # type: Future[int] - f2 = Future() # type: Future[int] - f3 = Future() # type: Future[int] - f1.set_result(24) - f2.set_result(42) - f3.set_result(84) - - g = gen.WaitIterator(f1, f2, f3) - i = 0 - while not g.done(): - r = yield g.next() - # Order is not guaranteed, but the current implementation - # preserves ordering of already-done Futures. - if i == 0: - self.assertEqual(g.current_index, 0) - self.assertIs(g.current_future, f1) - self.assertEqual(r, 24) - elif i == 1: - self.assertEqual(g.current_index, 1) - self.assertIs(g.current_future, f2) - self.assertEqual(r, 42) - elif i == 2: - self.assertEqual(g.current_index, 2) - self.assertIs(g.current_future, f3) - self.assertEqual(r, 84) - i += 1 - - self.assertEqual(g.current_index, None, "bad nil current index") - self.assertEqual(g.current_future, None, "bad nil current future") - - dg = gen.WaitIterator(f1=f1, f2=f2) - - while not dg.done(): - dr = yield dg.next() - if dg.current_index == "f1": - self.assertTrue( - dg.current_future == f1 and dr == 24, - "WaitIterator dict status incorrect", - ) - elif dg.current_index == "f2": - self.assertTrue( - dg.current_future == f2 and dr == 42, - "WaitIterator dict status incorrect", - ) - else: - self.fail("got bad WaitIterator index {}".format(dg.current_index)) - - i += 1 - - self.assertEqual(dg.current_index, None, "bad nil current index") - self.assertEqual(dg.current_future, None, "bad nil current future") - - def finish_coroutines(self, iteration, futures): - if iteration == 3: - futures[2].set_result(24) - elif iteration == 5: - futures[0].set_exception(ZeroDivisionError()) - elif iteration == 8: - futures[1].set_result(42) - futures[3].set_result(84) - - if iteration < 8: - self.io_loop.add_callback(self.finish_coroutines, iteration + 1, futures) - - @gen_test - def test_iterator(self): - futures = [Future(), Future(), Future(), Future()] # type: List[Future[int]] - - self.finish_coroutines(0, futures) - - g = gen.WaitIterator(*futures) - - i = 0 - while not g.done(): - try: - r = yield g.next() - except ZeroDivisionError: - self.assertIs(g.current_future, futures[0], "exception future invalid") - else: - if i == 0: - self.assertEqual(r, 24, "iterator value incorrect") - self.assertEqual(g.current_index, 2, "wrong index") - elif i == 2: - self.assertEqual(r, 42, "iterator value incorrect") - self.assertEqual(g.current_index, 1, "wrong index") - elif i == 3: - self.assertEqual(r, 84, "iterator value incorrect") - self.assertEqual(g.current_index, 3, "wrong index") - i += 1 - - @gen_test - def test_iterator_async_await(self): - # Recreate the previous test with py35 syntax. It's a little clunky - # because of the way the previous test handles an exception on - # a single iteration. - futures = [Future(), Future(), Future(), Future()] # type: List[Future[int]] - self.finish_coroutines(0, futures) - self.finished = False - - async def f(): - i = 0 - g = gen.WaitIterator(*futures) - try: - async for r in g: - if i == 0: - self.assertEqual(r, 24, "iterator value incorrect") - self.assertEqual(g.current_index, 2, "wrong index") - else: - raise Exception("expected exception on iteration 1") - i += 1 - except ZeroDivisionError: - i += 1 - async for r in g: - if i == 2: - self.assertEqual(r, 42, "iterator value incorrect") - self.assertEqual(g.current_index, 1, "wrong index") - elif i == 3: - self.assertEqual(r, 84, "iterator value incorrect") - self.assertEqual(g.current_index, 3, "wrong index") - else: - raise Exception("didn't expect iteration %d" % i) - i += 1 - self.finished = True - - yield f() - self.assertTrue(self.finished) - - @gen_test - def test_no_ref(self): - # In this usage, there is no direct hard reference to the - # WaitIterator itself, only the Future it returns. Since - # WaitIterator uses weak references internally to improve GC - # performance, this used to cause problems. - yield gen.with_timeout( - datetime.timedelta(seconds=0.1), gen.WaitIterator(gen.sleep(0)).next() - ) - - -class RunnerGCTest(AsyncTestCase): - def is_pypy3(self): - return platform.python_implementation() == "PyPy" and sys.version_info > (3,) - - @gen_test - def test_gc(self): - # GitHub issue 1769: Runner objects can get GCed unexpectedly - # while their future is alive. - weakref_scope = [None] # type: List[Optional[weakref.ReferenceType]] - - def callback(): - gc.collect(2) - weakref_scope[0]().set_result(123) # type: ignore - - @gen.coroutine - def tester(): - fut = Future() # type: Future[int] - weakref_scope[0] = weakref.ref(fut) - self.io_loop.add_callback(callback) - yield fut - - yield gen.with_timeout(datetime.timedelta(seconds=0.2), tester()) - - def test_gc_infinite_coro(self): - # GitHub issue 2229: suspended coroutines should be GCed when - # their loop is closed, even if they're involved in a reference - # cycle. - loop = self.get_new_ioloop() - result = [] # type: List[Optional[bool]] - wfut = [] - - @gen.coroutine - def infinite_coro(): - try: - while True: - yield gen.sleep(1e-3) - result.append(True) - finally: - # coroutine finalizer - result.append(None) - - @gen.coroutine - def do_something(): - fut = infinite_coro() - fut._refcycle = fut # type: ignore - wfut.append(weakref.ref(fut)) - yield gen.sleep(0.2) - - loop.run_sync(do_something) - loop.close() - gc.collect() - # Future was collected - self.assertIs(wfut[0](), None) - # At least one wakeup - self.assertGreaterEqual(len(result), 2) - if not self.is_pypy3(): - # coroutine finalizer was called (not on PyPy3 apparently) - self.assertIs(result[-1], None) - - def test_gc_infinite_async_await(self): - # Same as test_gc_infinite_coro, but with a `async def` function - import asyncio - - async def infinite_coro(result): - try: - while True: - await gen.sleep(1e-3) - result.append(True) - finally: - # coroutine finalizer - result.append(None) - - loop = self.get_new_ioloop() - result = [] # type: List[Optional[bool]] - wfut = [] - - @gen.coroutine - def do_something(): - fut = asyncio.get_event_loop().create_task(infinite_coro(result)) - fut._refcycle = fut # type: ignore - wfut.append(weakref.ref(fut)) - yield gen.sleep(0.2) - - loop.run_sync(do_something) - with ExpectLog("asyncio", "Task was destroyed but it is pending"): - loop.close() - gc.collect() - # Future was collected - self.assertIs(wfut[0](), None) - # At least one wakeup and one finally - self.assertGreaterEqual(len(result), 2) - if not self.is_pypy3(): - # coroutine finalizer was called (not on PyPy3 apparently) - self.assertIs(result[-1], None) - - def test_multi_moment(self): - # Test gen.multi with moment - # now that it's not a real Future - @gen.coroutine - def wait_a_moment(): - result = yield gen.multi([gen.moment, gen.moment]) - raise gen.Return(result) - - loop = self.get_new_ioloop() - result = loop.run_sync(wait_a_moment) - self.assertEqual(result, [None, None]) - - -if contextvars is not None: - ctx_var = contextvars.ContextVar("ctx_var") # type: contextvars.ContextVar[int] - - -@unittest.skipIf(contextvars is None, "contextvars module not present") -class ContextVarsTest(AsyncTestCase): - async def native_root(self, x): - ctx_var.set(x) - await self.inner(x) - - @gen.coroutine - def gen_root(self, x): - ctx_var.set(x) - yield - yield self.inner(x) - - async def inner(self, x): - self.assertEqual(ctx_var.get(), x) - await self.gen_inner(x) - self.assertEqual(ctx_var.get(), x) - - # IOLoop.run_in_executor doesn't automatically copy context - ctx = contextvars.copy_context() - await self.io_loop.run_in_executor(None, lambda: ctx.run(self.thread_inner, x)) - self.assertEqual(ctx_var.get(), x) - - # Neither does asyncio's run_in_executor. - await asyncio.get_event_loop().run_in_executor( - None, lambda: ctx.run(self.thread_inner, x) - ) - self.assertEqual(ctx_var.get(), x) - - @gen.coroutine - def gen_inner(self, x): - self.assertEqual(ctx_var.get(), x) - yield - self.assertEqual(ctx_var.get(), x) - - def thread_inner(self, x): - self.assertEqual(ctx_var.get(), x) - - @gen_test - def test_propagate(self): - # Verify that context vars get propagated across various - # combinations of native and decorated coroutines. - yield [ - self.native_root(1), - self.native_root(2), - self.gen_root(3), - self.gen_root(4), - ] - - @gen_test - def test_reset(self): - token = ctx_var.set(1) - yield - # reset asserts that we are still at the same level of the context tree, - # so we must make sure that we maintain that property across yield. - ctx_var.reset(token) - - -if __name__ == "__main__": - unittest.main() diff --git a/venv/lib/python3.8/site-packages/tornado/test/gettext_translations/fr_FR/LC_MESSAGES/tornado_test.mo b/venv/lib/python3.8/site-packages/tornado/test/gettext_translations/fr_FR/LC_MESSAGES/tornado_test.mo deleted file mode 100644 index a97bf9c57460ecfc27761accf90d712ea5cebb44..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 665 zcmYk3PjAyO7{(2hf8hd1hzkcFL6b*PG%=;?w5-jxh@`2~Zqm59iI;kKc4a#Z&~AJN zz5pk7=gei_VK?{)d<I^Jit<XoJWujIj^D(;9(TSVs5`(jAO#)(7l5m8fCpRx_kr)g zQ{V^S)?5P*fuF$X4TOG!-UW_tB6JUwf<AIRP?x^|eFFL!6ypEt7C6^;1ufKR9YVL4 zifW~*j^_2;B0<lWPU)IT{)t+yWTzC(47rOzrkpD!kg>dc_y6;;R;R4AB&o;|(*{<B zcpMGhMEfy5ii=5-kGz5{l(r-@HLu8SQyVf>A@;`klngX$w<1GoS%|xSutEHQbYJ5j z2>p#U|CR4UkQD4acQ0S&j^n5xSx$x#KFGr?S$mt0VlSn}lBuTB2x^rM@!nyY;!%{v zcq`7LB;ARI!y=wcwjnC(hSrQs89fVe8jbc3-N;*Mx+C~H{DoBpM$M8eUVUG%?t23z zEt9a_#|6x7*$4Y_At;wUT+XRB%=R05LN-@9H`WQ$B$lPBxU56GIpfwFi$+sH_LM#| zA(o5w*7UnQ{MYuMOT3MP7d;ONhG(2fr<GP5PL1LAgak9KG3e^DRD!k1tFKnMtiiL^ G8uSP9S*+y% diff --git a/venv/lib/python3.8/site-packages/tornado/test/gettext_translations/fr_FR/LC_MESSAGES/tornado_test.po b/venv/lib/python3.8/site-packages/tornado/test/gettext_translations/fr_FR/LC_MESSAGES/tornado_test.po deleted file mode 100644 index 88d72c8..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/gettext_translations/fr_FR/LC_MESSAGES/tornado_test.po +++ /dev/null @@ -1,47 +0,0 @@ -# SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. -# -#, fuzzy -msgid "" -msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2015-01-27 11:05+0300\n" -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" -"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" -"Language-Team: LANGUAGE <LL@li.org>\n" -"Language: \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" - -#: extract_me.py:11 -msgid "school" -msgstr "école" - -#: extract_me.py:12 -msgctxt "law" -msgid "right" -msgstr "le droit" - -#: extract_me.py:13 -msgctxt "good" -msgid "right" -msgstr "le bien" - -#: extract_me.py:14 -msgctxt "organization" -msgid "club" -msgid_plural "clubs" -msgstr[0] "le club" -msgstr[1] "les clubs" - -#: extract_me.py:15 -msgctxt "stick" -msgid "club" -msgid_plural "clubs" -msgstr[0] "le bâton" -msgstr[1] "les bâtons" diff --git a/venv/lib/python3.8/site-packages/tornado/test/http1connection_test.py b/venv/lib/python3.8/site-packages/tornado/test/http1connection_test.py deleted file mode 100644 index d21d506..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/http1connection_test.py +++ /dev/null @@ -1,61 +0,0 @@ -import socket -import typing - -from tornado.http1connection import HTTP1Connection -from tornado.httputil import HTTPMessageDelegate -from tornado.iostream import IOStream -from tornado.locks import Event -from tornado.netutil import add_accept_handler -from tornado.testing import AsyncTestCase, bind_unused_port, gen_test - - -class HTTP1ConnectionTest(AsyncTestCase): - code = None # type: typing.Optional[int] - - def setUp(self): - super().setUp() - self.asyncSetUp() - - @gen_test - def asyncSetUp(self): - listener, port = bind_unused_port() - event = Event() - - def accept_callback(conn, addr): - self.server_stream = IOStream(conn) - self.addCleanup(self.server_stream.close) - event.set() - - add_accept_handler(listener, accept_callback) - self.client_stream = IOStream(socket.socket()) - self.addCleanup(self.client_stream.close) - yield [self.client_stream.connect(("127.0.0.1", port)), event.wait()] - self.io_loop.remove_handler(listener) - listener.close() - - @gen_test - def test_http10_no_content_length(self): - # Regression test for a bug in which can_keep_alive would crash - # for an HTTP/1.0 (not 1.1) response with no content-length. - conn = HTTP1Connection(self.client_stream, True) - self.server_stream.write(b"HTTP/1.0 200 Not Modified\r\n\r\nhello") - self.server_stream.close() - - event = Event() - test = self - body = [] - - class Delegate(HTTPMessageDelegate): - def headers_received(self, start_line, headers): - test.code = start_line.code - - def data_received(self, data): - body.append(data) - - def finish(self): - event.set() - - yield conn.read_response(Delegate()) - yield event.wait() - self.assertEqual(self.code, 200) - self.assertEqual(b"".join(body), b"hello") diff --git a/venv/lib/python3.8/site-packages/tornado/test/httpclient_test.py b/venv/lib/python3.8/site-packages/tornado/test/httpclient_test.py deleted file mode 100644 index fd9a978..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/httpclient_test.py +++ /dev/null @@ -1,898 +0,0 @@ -import base64 -import binascii -from contextlib import closing -import copy -import gzip -import threading -import datetime -from io import BytesIO -import subprocess -import sys -import time -import typing # noqa: F401 -import unicodedata -import unittest - -from tornado.escape import utf8, native_str, to_unicode -from tornado import gen -from tornado.httpclient import ( - HTTPRequest, - HTTPResponse, - _RequestProxy, - HTTPError, - HTTPClient, -) -from tornado.httpserver import HTTPServer -from tornado.ioloop import IOLoop -from tornado.iostream import IOStream -from tornado.log import gen_log, app_log -from tornado import netutil -from tornado.testing import AsyncHTTPTestCase, bind_unused_port, gen_test, ExpectLog -from tornado.test.util import skipOnTravis -from tornado.web import Application, RequestHandler, url -from tornado.httputil import format_timestamp, HTTPHeaders - - -class HelloWorldHandler(RequestHandler): - def get(self): - name = self.get_argument("name", "world") - self.set_header("Content-Type", "text/plain") - self.finish("Hello %s!" % name) - - -class PostHandler(RequestHandler): - def post(self): - self.finish( - "Post arg1: %s, arg2: %s" - % (self.get_argument("arg1"), self.get_argument("arg2")) - ) - - -class PutHandler(RequestHandler): - def put(self): - self.write("Put body: ") - self.write(self.request.body) - - -class RedirectHandler(RequestHandler): - def prepare(self): - self.write("redirects can have bodies too") - self.redirect( - self.get_argument("url"), status=int(self.get_argument("status", "302")) - ) - - -class RedirectWithoutLocationHandler(RequestHandler): - def prepare(self): - # For testing error handling of a redirect with no location header. - self.set_status(301) - self.finish() - - -class ChunkHandler(RequestHandler): - @gen.coroutine - def get(self): - self.write("asdf") - self.flush() - # Wait a bit to ensure the chunks are sent and received separately. - yield gen.sleep(0.01) - self.write("qwer") - - -class AuthHandler(RequestHandler): - def get(self): - self.finish(self.request.headers["Authorization"]) - - -class CountdownHandler(RequestHandler): - def get(self, count): - count = int(count) - if count > 0: - self.redirect(self.reverse_url("countdown", count - 1)) - else: - self.write("Zero") - - -class EchoPostHandler(RequestHandler): - def post(self): - self.write(self.request.body) - - -class UserAgentHandler(RequestHandler): - def get(self): - self.write(self.request.headers.get("User-Agent", "User agent not set")) - - -class ContentLength304Handler(RequestHandler): - def get(self): - self.set_status(304) - self.set_header("Content-Length", 42) - - def _clear_representation_headers(self): - # Tornado strips content-length from 304 responses, but here we - # want to simulate servers that include the headers anyway. - pass - - -class PatchHandler(RequestHandler): - def patch(self): - "Return the request payload - so we can check it is being kept" - self.write(self.request.body) - - -class AllMethodsHandler(RequestHandler): - SUPPORTED_METHODS = RequestHandler.SUPPORTED_METHODS + ("OTHER",) # type: ignore - - def method(self): - assert self.request.method is not None - self.write(self.request.method) - - get = head = post = put = delete = options = patch = other = method # type: ignore - - -class SetHeaderHandler(RequestHandler): - def get(self): - # Use get_arguments for keys to get strings, but - # request.arguments for values to get bytes. - for k, v in zip(self.get_arguments("k"), self.request.arguments["v"]): - self.set_header(k, v) - - -class InvalidGzipHandler(RequestHandler): - def get(self): - # set Content-Encoding manually to avoid automatic gzip encoding - self.set_header("Content-Type", "text/plain") - self.set_header("Content-Encoding", "gzip") - # Triggering the potential bug seems to depend on input length. - # This length is taken from the bad-response example reported in - # https://github.com/tornadoweb/tornado/pull/2875 (uncompressed). - body = "".join("Hello World {}\n".format(i) for i in range(9000))[:149051] - body = gzip.compress(body.encode(), compresslevel=6) + b"\00" - self.write(body) - - -# These tests end up getting run redundantly: once here with the default -# HTTPClient implementation, and then again in each implementation's own -# test suite. - - -class HTTPClientCommonTestCase(AsyncHTTPTestCase): - def get_app(self): - return Application( - [ - url("/hello", HelloWorldHandler), - url("/post", PostHandler), - url("/put", PutHandler), - url("/redirect", RedirectHandler), - url("/redirect_without_location", RedirectWithoutLocationHandler), - url("/chunk", ChunkHandler), - url("/auth", AuthHandler), - url("/countdown/([0-9]+)", CountdownHandler, name="countdown"), - url("/echopost", EchoPostHandler), - url("/user_agent", UserAgentHandler), - url("/304_with_content_length", ContentLength304Handler), - url("/all_methods", AllMethodsHandler), - url("/patch", PatchHandler), - url("/set_header", SetHeaderHandler), - url("/invalid_gzip", InvalidGzipHandler), - ], - gzip=True, - ) - - def test_patch_receives_payload(self): - body = b"some patch data" - response = self.fetch("/patch", method="PATCH", body=body) - self.assertEqual(response.code, 200) - self.assertEqual(response.body, body) - - @skipOnTravis - def test_hello_world(self): - response = self.fetch("/hello") - self.assertEqual(response.code, 200) - self.assertEqual(response.headers["Content-Type"], "text/plain") - self.assertEqual(response.body, b"Hello world!") - assert response.request_time is not None - self.assertEqual(int(response.request_time), 0) - - response = self.fetch("/hello?name=Ben") - self.assertEqual(response.body, b"Hello Ben!") - - def test_streaming_callback(self): - # streaming_callback is also tested in test_chunked - chunks = [] # type: typing.List[bytes] - response = self.fetch("/hello", streaming_callback=chunks.append) - # with streaming_callback, data goes to the callback and not response.body - self.assertEqual(chunks, [b"Hello world!"]) - self.assertFalse(response.body) - - def test_post(self): - response = self.fetch("/post", method="POST", body="arg1=foo&arg2=bar") - self.assertEqual(response.code, 200) - self.assertEqual(response.body, b"Post arg1: foo, arg2: bar") - - def test_chunked(self): - response = self.fetch("/chunk") - self.assertEqual(response.body, b"asdfqwer") - - chunks = [] # type: typing.List[bytes] - response = self.fetch("/chunk", streaming_callback=chunks.append) - self.assertEqual(chunks, [b"asdf", b"qwer"]) - self.assertFalse(response.body) - - def test_chunked_close(self): - # test case in which chunks spread read-callback processing - # over several ioloop iterations, but the connection is already closed. - sock, port = bind_unused_port() - with closing(sock): - - @gen.coroutine - def accept_callback(conn, address): - # fake an HTTP server using chunked encoding where the final chunks - # and connection close all happen at once - stream = IOStream(conn) - request_data = yield stream.read_until(b"\r\n\r\n") - if b"HTTP/1." not in request_data: - self.skipTest("requires HTTP/1.x") - yield stream.write( - b"""\ -HTTP/1.1 200 OK -Transfer-Encoding: chunked - -1 -1 -1 -2 -0 - -""".replace( - b"\n", b"\r\n" - ) - ) - stream.close() - - netutil.add_accept_handler(sock, accept_callback) # type: ignore - resp = self.fetch("http://127.0.0.1:%d/" % port) - resp.rethrow() - self.assertEqual(resp.body, b"12") - self.io_loop.remove_handler(sock.fileno()) - - def test_basic_auth(self): - # This test data appears in section 2 of RFC 7617. - self.assertEqual( - self.fetch( - "/auth", auth_username="Aladdin", auth_password="open sesame" - ).body, - b"Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==", - ) - - def test_basic_auth_explicit_mode(self): - self.assertEqual( - self.fetch( - "/auth", - auth_username="Aladdin", - auth_password="open sesame", - auth_mode="basic", - ).body, - b"Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==", - ) - - def test_basic_auth_unicode(self): - # This test data appears in section 2.1 of RFC 7617. - self.assertEqual( - self.fetch("/auth", auth_username="test", auth_password="123£").body, - b"Basic dGVzdDoxMjPCow==", - ) - - # The standard mandates NFC. Give it a decomposed username - # and ensure it is normalized to composed form. - username = unicodedata.normalize("NFD", u"josé") - self.assertEqual( - self.fetch("/auth", auth_username=username, auth_password="səcrət").body, - b"Basic am9zw6k6c8mZY3LJmXQ=", - ) - - def test_unsupported_auth_mode(self): - # curl and simple clients handle errors a bit differently; the - # important thing is that they don't fall back to basic auth - # on an unknown mode. - with ExpectLog(gen_log, "uncaught exception", required=False): - with self.assertRaises((ValueError, HTTPError)): # type: ignore - self.fetch( - "/auth", - auth_username="Aladdin", - auth_password="open sesame", - auth_mode="asdf", - raise_error=True, - ) - - def test_follow_redirect(self): - response = self.fetch("/countdown/2", follow_redirects=False) - self.assertEqual(302, response.code) - self.assertTrue(response.headers["Location"].endswith("/countdown/1")) - - response = self.fetch("/countdown/2") - self.assertEqual(200, response.code) - self.assertTrue(response.effective_url.endswith("/countdown/0")) - self.assertEqual(b"Zero", response.body) - - def test_redirect_without_location(self): - response = self.fetch("/redirect_without_location", follow_redirects=True) - # If there is no location header, the redirect response should - # just be returned as-is. (This should arguably raise an - # error, but libcurl doesn't treat this as an error, so we - # don't either). - self.assertEqual(301, response.code) - - def test_redirect_put_with_body(self): - response = self.fetch( - "/redirect?url=/put&status=307", method="PUT", body="hello" - ) - self.assertEqual(response.body, b"Put body: hello") - - def test_redirect_put_without_body(self): - # This "without body" edge case is similar to what happens with body_producer. - response = self.fetch( - "/redirect?url=/put&status=307", - method="PUT", - allow_nonstandard_methods=True, - ) - self.assertEqual(response.body, b"Put body: ") - - def test_method_after_redirect(self): - # Legacy redirect codes (301, 302) convert POST requests to GET. - for status in [301, 302, 303]: - url = "/redirect?url=/all_methods&status=%d" % status - resp = self.fetch(url, method="POST", body=b"") - self.assertEqual(b"GET", resp.body) - - # Other methods are left alone, except for 303 redirect, depending on client - for method in ["GET", "OPTIONS", "PUT", "DELETE"]: - resp = self.fetch(url, method=method, allow_nonstandard_methods=True) - if status in [301, 302]: - self.assertEqual(utf8(method), resp.body) - else: - self.assertIn(resp.body, [utf8(method), b"GET"]) - - # HEAD is different so check it separately. - resp = self.fetch(url, method="HEAD") - self.assertEqual(200, resp.code) - self.assertEqual(b"", resp.body) - - # Newer redirects always preserve the original method. - for status in [307, 308]: - url = "/redirect?url=/all_methods&status=307" - for method in ["GET", "OPTIONS", "POST", "PUT", "DELETE"]: - resp = self.fetch(url, method=method, allow_nonstandard_methods=True) - self.assertEqual(method, to_unicode(resp.body)) - resp = self.fetch(url, method="HEAD") - self.assertEqual(200, resp.code) - self.assertEqual(b"", resp.body) - - def test_credentials_in_url(self): - url = self.get_url("/auth").replace("http://", "http://me:secret@") - response = self.fetch(url) - self.assertEqual(b"Basic " + base64.b64encode(b"me:secret"), response.body) - - def test_body_encoding(self): - unicode_body = u"\xe9" - byte_body = binascii.a2b_hex(b"e9") - - # unicode string in body gets converted to utf8 - response = self.fetch( - "/echopost", - method="POST", - body=unicode_body, - headers={"Content-Type": "application/blah"}, - ) - self.assertEqual(response.headers["Content-Length"], "2") - self.assertEqual(response.body, utf8(unicode_body)) - - # byte strings pass through directly - response = self.fetch( - "/echopost", - method="POST", - body=byte_body, - headers={"Content-Type": "application/blah"}, - ) - self.assertEqual(response.headers["Content-Length"], "1") - self.assertEqual(response.body, byte_body) - - # Mixing unicode in headers and byte string bodies shouldn't - # break anything - response = self.fetch( - "/echopost", - method="POST", - body=byte_body, - headers={"Content-Type": "application/blah"}, - user_agent=u"foo", - ) - self.assertEqual(response.headers["Content-Length"], "1") - self.assertEqual(response.body, byte_body) - - def test_types(self): - response = self.fetch("/hello") - self.assertEqual(type(response.body), bytes) - self.assertEqual(type(response.headers["Content-Type"]), str) - self.assertEqual(type(response.code), int) - self.assertEqual(type(response.effective_url), str) - - def test_gzip(self): - # All the tests in this file should be using gzip, but this test - # ensures that it is in fact getting compressed, and also tests - # the httpclient's decompress=False option. - # Setting Accept-Encoding manually bypasses the client's - # decompression so we can see the raw data. - response = self.fetch( - "/chunk", decompress_response=False, headers={"Accept-Encoding": "gzip"} - ) - self.assertEqual(response.headers["Content-Encoding"], "gzip") - self.assertNotEqual(response.body, b"asdfqwer") - # Our test data gets bigger when gzipped. Oops. :) - # Chunked encoding bypasses the MIN_LENGTH check. - self.assertEqual(len(response.body), 34) - f = gzip.GzipFile(mode="r", fileobj=response.buffer) - self.assertEqual(f.read(), b"asdfqwer") - - def test_invalid_gzip(self): - # test if client hangs on tricky invalid gzip - # curl/simple httpclient have different behavior (exception, logging) - with ExpectLog( - app_log, "(Uncaught exception|Exception in callback)", required=False - ): - try: - response = self.fetch("/invalid_gzip") - self.assertEqual(response.code, 200) - self.assertEqual(response.body[:14], b"Hello World 0\n") - except HTTPError: - pass # acceptable - - def test_header_callback(self): - first_line = [] - headers = {} - chunks = [] - - def header_callback(header_line): - if header_line.startswith("HTTP/1.1 101"): - # Upgrading to HTTP/2 - pass - elif header_line.startswith("HTTP/"): - first_line.append(header_line) - elif header_line != "\r\n": - k, v = header_line.split(":", 1) - headers[k.lower()] = v.strip() - - def streaming_callback(chunk): - # All header callbacks are run before any streaming callbacks, - # so the header data is available to process the data as it - # comes in. - self.assertEqual(headers["content-type"], "text/html; charset=UTF-8") - chunks.append(chunk) - - self.fetch( - "/chunk", - header_callback=header_callback, - streaming_callback=streaming_callback, - ) - self.assertEqual(len(first_line), 1, first_line) - self.assertRegexpMatches(first_line[0], "HTTP/[0-9]\\.[0-9] 200.*\r\n") - self.assertEqual(chunks, [b"asdf", b"qwer"]) - - @gen_test - def test_configure_defaults(self): - defaults = dict(user_agent="TestDefaultUserAgent", allow_ipv6=False) - # Construct a new instance of the configured client class - client = self.http_client.__class__(force_instance=True, defaults=defaults) - try: - response = yield client.fetch(self.get_url("/user_agent")) - self.assertEqual(response.body, b"TestDefaultUserAgent") - finally: - client.close() - - def test_header_types(self): - # Header values may be passed as character or utf8 byte strings, - # in a plain dictionary or an HTTPHeaders object. - # Keys must always be the native str type. - # All combinations should have the same results on the wire. - for value in [u"MyUserAgent", b"MyUserAgent"]: - for container in [dict, HTTPHeaders]: - headers = container() - headers["User-Agent"] = value - resp = self.fetch("/user_agent", headers=headers) - self.assertEqual( - resp.body, - b"MyUserAgent", - "response=%r, value=%r, container=%r" - % (resp.body, value, container), - ) - - def test_multi_line_headers(self): - # Multi-line http headers are rare but rfc-allowed - # http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 - sock, port = bind_unused_port() - with closing(sock): - - @gen.coroutine - def accept_callback(conn, address): - stream = IOStream(conn) - request_data = yield stream.read_until(b"\r\n\r\n") - if b"HTTP/1." not in request_data: - self.skipTest("requires HTTP/1.x") - yield stream.write( - b"""\ -HTTP/1.1 200 OK -X-XSS-Protection: 1; -\tmode=block - -""".replace( - b"\n", b"\r\n" - ) - ) - stream.close() - - netutil.add_accept_handler(sock, accept_callback) # type: ignore - try: - resp = self.fetch("http://127.0.0.1:%d/" % port) - resp.rethrow() - self.assertEqual(resp.headers["X-XSS-Protection"], "1; mode=block") - finally: - self.io_loop.remove_handler(sock.fileno()) - - def test_304_with_content_length(self): - # According to the spec 304 responses SHOULD NOT include - # Content-Length or other entity headers, but some servers do it - # anyway. - # http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5 - response = self.fetch("/304_with_content_length") - self.assertEqual(response.code, 304) - self.assertEqual(response.headers["Content-Length"], "42") - - @gen_test - def test_future_interface(self): - response = yield self.http_client.fetch(self.get_url("/hello")) - self.assertEqual(response.body, b"Hello world!") - - @gen_test - def test_future_http_error(self): - with self.assertRaises(HTTPError) as context: - yield self.http_client.fetch(self.get_url("/notfound")) - assert context.exception is not None - assert context.exception.response is not None - self.assertEqual(context.exception.code, 404) - self.assertEqual(context.exception.response.code, 404) - - @gen_test - def test_future_http_error_no_raise(self): - response = yield self.http_client.fetch( - self.get_url("/notfound"), raise_error=False - ) - self.assertEqual(response.code, 404) - - @gen_test - def test_reuse_request_from_response(self): - # The response.request attribute should be an HTTPRequest, not - # a _RequestProxy. - # This test uses self.http_client.fetch because self.fetch calls - # self.get_url on the input unconditionally. - url = self.get_url("/hello") - response = yield self.http_client.fetch(url) - self.assertEqual(response.request.url, url) - self.assertTrue(isinstance(response.request, HTTPRequest)) - response2 = yield self.http_client.fetch(response.request) - self.assertEqual(response2.body, b"Hello world!") - - @gen_test - def test_bind_source_ip(self): - url = self.get_url("/hello") - request = HTTPRequest(url, network_interface="127.0.0.1") - response = yield self.http_client.fetch(request) - self.assertEqual(response.code, 200) - - with self.assertRaises((ValueError, HTTPError)) as context: # type: ignore - request = HTTPRequest(url, network_interface="not-interface-or-ip") - yield self.http_client.fetch(request) - self.assertIn("not-interface-or-ip", str(context.exception)) - - def test_all_methods(self): - for method in ["GET", "DELETE", "OPTIONS"]: - response = self.fetch("/all_methods", method=method) - self.assertEqual(response.body, utf8(method)) - for method in ["POST", "PUT", "PATCH"]: - response = self.fetch("/all_methods", method=method, body=b"") - self.assertEqual(response.body, utf8(method)) - response = self.fetch("/all_methods", method="HEAD") - self.assertEqual(response.body, b"") - response = self.fetch( - "/all_methods", method="OTHER", allow_nonstandard_methods=True - ) - self.assertEqual(response.body, b"OTHER") - - def test_body_sanity_checks(self): - # These methods require a body. - for method in ("POST", "PUT", "PATCH"): - with self.assertRaises(ValueError) as context: - self.fetch("/all_methods", method=method, raise_error=True) - self.assertIn("must not be None", str(context.exception)) - - resp = self.fetch( - "/all_methods", method=method, allow_nonstandard_methods=True - ) - self.assertEqual(resp.code, 200) - - # These methods don't allow a body. - for method in ("GET", "DELETE", "OPTIONS"): - with self.assertRaises(ValueError) as context: - self.fetch( - "/all_methods", method=method, body=b"asdf", raise_error=True - ) - self.assertIn("must be None", str(context.exception)) - - # In most cases this can be overridden, but curl_httpclient - # does not allow body with a GET at all. - if method != "GET": - self.fetch( - "/all_methods", - method=method, - body=b"asdf", - allow_nonstandard_methods=True, - raise_error=True, - ) - self.assertEqual(resp.code, 200) - - # This test causes odd failures with the combination of - # curl_httpclient (at least with the version of libcurl available - # on ubuntu 12.04), TwistedIOLoop, and epoll. For POST (but not PUT), - # curl decides the response came back too soon and closes the connection - # to start again. It does this *before* telling the socket callback to - # unregister the FD. Some IOLoop implementations have special kernel - # integration to discover this immediately. Tornado's IOLoops - # ignore errors on remove_handler to accommodate this behavior, but - # Twisted's reactor does not. The removeReader call fails and so - # do all future removeAll calls (which our tests do at cleanup). - # - # def test_post_307(self): - # response = self.fetch("/redirect?status=307&url=/post", - # method="POST", body=b"arg1=foo&arg2=bar") - # self.assertEqual(response.body, b"Post arg1: foo, arg2: bar") - - def test_put_307(self): - response = self.fetch( - "/redirect?status=307&url=/put", method="PUT", body=b"hello" - ) - response.rethrow() - self.assertEqual(response.body, b"Put body: hello") - - def test_non_ascii_header(self): - # Non-ascii headers are sent as latin1. - response = self.fetch("/set_header?k=foo&v=%E9") - response.rethrow() - self.assertEqual(response.headers["Foo"], native_str(u"\u00e9")) - - def test_response_times(self): - # A few simple sanity checks of the response time fields to - # make sure they're using the right basis (between the - # wall-time and monotonic clocks). - start_time = time.time() - response = self.fetch("/hello") - response.rethrow() - self.assertGreaterEqual(response.request_time, 0) - self.assertLess(response.request_time, 1.0) - # A very crude check to make sure that start_time is based on - # wall time and not the monotonic clock. - assert response.start_time is not None - self.assertLess(abs(response.start_time - start_time), 1.0) - - for k, v in response.time_info.items(): - self.assertTrue(0 <= v < 1.0, "time_info[%s] out of bounds: %s" % (k, v)) - - def test_zero_timeout(self): - response = self.fetch("/hello", connect_timeout=0) - self.assertEqual(response.code, 200) - - response = self.fetch("/hello", request_timeout=0) - self.assertEqual(response.code, 200) - - response = self.fetch("/hello", connect_timeout=0, request_timeout=0) - self.assertEqual(response.code, 200) - - @gen_test - def test_error_after_cancel(self): - fut = self.http_client.fetch(self.get_url("/404")) - self.assertTrue(fut.cancel()) - with ExpectLog(app_log, "Exception after Future was cancelled") as el: - # We can't wait on the cancelled Future any more, so just - # let the IOLoop run until the exception gets logged (or - # not, in which case we exit the loop and ExpectLog will - # raise). - for i in range(100): - yield gen.sleep(0.01) - if el.logged_stack: - break - - -class RequestProxyTest(unittest.TestCase): - def test_request_set(self): - proxy = _RequestProxy( - HTTPRequest("http://example.com/", user_agent="foo"), dict() - ) - self.assertEqual(proxy.user_agent, "foo") - - def test_default_set(self): - proxy = _RequestProxy( - HTTPRequest("http://example.com/"), dict(network_interface="foo") - ) - self.assertEqual(proxy.network_interface, "foo") - - def test_both_set(self): - proxy = _RequestProxy( - HTTPRequest("http://example.com/", proxy_host="foo"), dict(proxy_host="bar") - ) - self.assertEqual(proxy.proxy_host, "foo") - - def test_neither_set(self): - proxy = _RequestProxy(HTTPRequest("http://example.com/"), dict()) - self.assertIs(proxy.auth_username, None) - - def test_bad_attribute(self): - proxy = _RequestProxy(HTTPRequest("http://example.com/"), dict()) - with self.assertRaises(AttributeError): - proxy.foo - - def test_defaults_none(self): - proxy = _RequestProxy(HTTPRequest("http://example.com/"), None) - self.assertIs(proxy.auth_username, None) - - -class HTTPResponseTestCase(unittest.TestCase): - def test_str(self): - response = HTTPResponse( # type: ignore - HTTPRequest("http://example.com"), 200, buffer=BytesIO() - ) - s = str(response) - self.assertTrue(s.startswith("HTTPResponse(")) - self.assertIn("code=200", s) - - -class SyncHTTPClientTest(unittest.TestCase): - def setUp(self): - self.server_ioloop = IOLoop() - event = threading.Event() - - @gen.coroutine - def init_server(): - sock, self.port = bind_unused_port() - app = Application([("/", HelloWorldHandler)]) - self.server = HTTPServer(app) - self.server.add_socket(sock) - event.set() - - def start(): - self.server_ioloop.run_sync(init_server) - self.server_ioloop.start() - - self.server_thread = threading.Thread(target=start) - self.server_thread.start() - event.wait() - - self.http_client = HTTPClient() - - def tearDown(self): - def stop_server(): - self.server.stop() - # Delay the shutdown of the IOLoop by several iterations because - # the server may still have some cleanup work left when - # the client finishes with the response (this is noticeable - # with http/2, which leaves a Future with an unexamined - # StreamClosedError on the loop). - - @gen.coroutine - def slow_stop(): - yield self.server.close_all_connections() - # The number of iterations is difficult to predict. Typically, - # one is sufficient, although sometimes it needs more. - for i in range(5): - yield - self.server_ioloop.stop() - - self.server_ioloop.add_callback(slow_stop) - - self.server_ioloop.add_callback(stop_server) - self.server_thread.join() - self.http_client.close() - self.server_ioloop.close(all_fds=True) - - def get_url(self, path): - return "http://127.0.0.1:%d%s" % (self.port, path) - - def test_sync_client(self): - response = self.http_client.fetch(self.get_url("/")) - self.assertEqual(b"Hello world!", response.body) - - def test_sync_client_error(self): - # Synchronous HTTPClient raises errors directly; no need for - # response.rethrow() - with self.assertRaises(HTTPError) as assertion: - self.http_client.fetch(self.get_url("/notfound")) - self.assertEqual(assertion.exception.code, 404) - - -class SyncHTTPClientSubprocessTest(unittest.TestCase): - def test_destructor_log(self): - # Regression test for - # https://github.com/tornadoweb/tornado/issues/2539 - # - # In the past, the following program would log an - # "inconsistent AsyncHTTPClient cache" error from a destructor - # when the process is shutting down. The shutdown process is - # subtle and I don't fully understand it; the failure does not - # manifest if that lambda isn't there or is a simpler object - # like an int (nor does it manifest in the tornado test suite - # as a whole, which is why we use this subprocess). - proc = subprocess.run( - [ - sys.executable, - "-c", - "from tornado.httpclient import HTTPClient; f = lambda: None; c = HTTPClient()", - ], - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - check=True, - timeout=5, - ) - if proc.stdout: - print("STDOUT:") - print(to_unicode(proc.stdout)) - if proc.stdout: - self.fail("subprocess produced unexpected output") - - -class HTTPRequestTestCase(unittest.TestCase): - def test_headers(self): - request = HTTPRequest("http://example.com", headers={"foo": "bar"}) - self.assertEqual(request.headers, {"foo": "bar"}) - - def test_headers_setter(self): - request = HTTPRequest("http://example.com") - request.headers = {"bar": "baz"} # type: ignore - self.assertEqual(request.headers, {"bar": "baz"}) - - def test_null_headers_setter(self): - request = HTTPRequest("http://example.com") - request.headers = None # type: ignore - self.assertEqual(request.headers, {}) - - def test_body(self): - request = HTTPRequest("http://example.com", body="foo") - self.assertEqual(request.body, utf8("foo")) - - def test_body_setter(self): - request = HTTPRequest("http://example.com") - request.body = "foo" # type: ignore - self.assertEqual(request.body, utf8("foo")) - - def test_if_modified_since(self): - http_date = datetime.datetime.utcnow() - request = HTTPRequest("http://example.com", if_modified_since=http_date) - self.assertEqual( - request.headers, {"If-Modified-Since": format_timestamp(http_date)} - ) - - -class HTTPErrorTestCase(unittest.TestCase): - def test_copy(self): - e = HTTPError(403) - e2 = copy.copy(e) - self.assertIsNot(e, e2) - self.assertEqual(e.code, e2.code) - - def test_plain_error(self): - e = HTTPError(403) - self.assertEqual(str(e), "HTTP 403: Forbidden") - self.assertEqual(repr(e), "HTTP 403: Forbidden") - - def test_error_with_response(self): - resp = HTTPResponse(HTTPRequest("http://example.com/"), 403) - with self.assertRaises(HTTPError) as cm: - resp.rethrow() - e = cm.exception - self.assertEqual(str(e), "HTTP 403: Forbidden") - self.assertEqual(repr(e), "HTTP 403: Forbidden") diff --git a/venv/lib/python3.8/site-packages/tornado/test/httpserver_test.py b/venv/lib/python3.8/site-packages/tornado/test/httpserver_test.py deleted file mode 100644 index 614dec7..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/httpserver_test.py +++ /dev/null @@ -1,1339 +0,0 @@ -from tornado import gen, netutil -from tornado.escape import ( - json_decode, - json_encode, - utf8, - _unicode, - recursive_unicode, - native_str, -) -from tornado.http1connection import HTTP1Connection -from tornado.httpclient import HTTPError -from tornado.httpserver import HTTPServer -from tornado.httputil import ( - HTTPHeaders, - HTTPMessageDelegate, - HTTPServerConnectionDelegate, - ResponseStartLine, -) -from tornado.iostream import IOStream -from tornado.locks import Event -from tornado.log import gen_log -from tornado.netutil import ssl_options_to_context -from tornado.simple_httpclient import SimpleAsyncHTTPClient -from tornado.testing import ( - AsyncHTTPTestCase, - AsyncHTTPSTestCase, - AsyncTestCase, - ExpectLog, - gen_test, -) -from tornado.test.util import skipOnTravis -from tornado.web import Application, RequestHandler, stream_request_body - -from contextlib import closing -import datetime -import gzip -import logging -import os -import shutil -import socket -import ssl -import sys -import tempfile -import unittest -import urllib.parse -from io import BytesIO - -import typing - -if typing.TYPE_CHECKING: - from typing import Dict, List # noqa: F401 - - -async def read_stream_body(stream): - """Reads an HTTP response from `stream` and returns a tuple of its - start_line, headers and body.""" - chunks = [] - - class Delegate(HTTPMessageDelegate): - def headers_received(self, start_line, headers): - self.headers = headers - self.start_line = start_line - - def data_received(self, chunk): - chunks.append(chunk) - - def finish(self): - conn.detach() # type: ignore - - conn = HTTP1Connection(stream, True) - delegate = Delegate() - await conn.read_response(delegate) - return delegate.start_line, delegate.headers, b"".join(chunks) - - -class HandlerBaseTestCase(AsyncHTTPTestCase): - Handler = None - - def get_app(self): - return Application([("/", self.__class__.Handler)]) - - def fetch_json(self, *args, **kwargs): - response = self.fetch(*args, **kwargs) - response.rethrow() - return json_decode(response.body) - - -class HelloWorldRequestHandler(RequestHandler): - def initialize(self, protocol="http"): - self.expected_protocol = protocol - - def get(self): - if self.request.protocol != self.expected_protocol: - raise Exception("unexpected protocol") - self.finish("Hello world") - - def post(self): - self.finish("Got %d bytes in POST" % len(self.request.body)) - - -# In pre-1.0 versions of openssl, SSLv23 clients always send SSLv2 -# ClientHello messages, which are rejected by SSLv3 and TLSv1 -# servers. Note that while the OPENSSL_VERSION_INFO was formally -# introduced in python3.2, it was present but undocumented in -# python 2.7 -skipIfOldSSL = unittest.skipIf( - getattr(ssl, "OPENSSL_VERSION_INFO", (0, 0)) < (1, 0), - "old version of ssl module and/or openssl", -) - - -class BaseSSLTest(AsyncHTTPSTestCase): - def get_app(self): - return Application([("/", HelloWorldRequestHandler, dict(protocol="https"))]) - - -class SSLTestMixin(object): - def get_ssl_options(self): - return dict( - ssl_version=self.get_ssl_version(), - **AsyncHTTPSTestCase.default_ssl_options() - ) - - def get_ssl_version(self): - raise NotImplementedError() - - def test_ssl(self: typing.Any): - response = self.fetch("/") - self.assertEqual(response.body, b"Hello world") - - def test_large_post(self: typing.Any): - response = self.fetch("/", method="POST", body="A" * 5000) - self.assertEqual(response.body, b"Got 5000 bytes in POST") - - def test_non_ssl_request(self: typing.Any): - # Make sure the server closes the connection when it gets a non-ssl - # connection, rather than waiting for a timeout or otherwise - # misbehaving. - with ExpectLog(gen_log, "(SSL Error|uncaught exception)"): - with ExpectLog(gen_log, "Uncaught exception", required=False): - with self.assertRaises((IOError, HTTPError)): # type: ignore - self.fetch( - self.get_url("/").replace("https:", "http:"), - request_timeout=3600, - connect_timeout=3600, - raise_error=True, - ) - - def test_error_logging(self: typing.Any): - # No stack traces are logged for SSL errors. - with ExpectLog(gen_log, "SSL Error") as expect_log: - with self.assertRaises((IOError, HTTPError)): # type: ignore - self.fetch( - self.get_url("/").replace("https:", "http:"), raise_error=True - ) - self.assertFalse(expect_log.logged_stack) - - -# Python's SSL implementation differs significantly between versions. -# For example, SSLv3 and TLSv1 throw an exception if you try to read -# from the socket before the handshake is complete, but the default -# of SSLv23 allows it. - - -class SSLv23Test(BaseSSLTest, SSLTestMixin): - def get_ssl_version(self): - return ssl.PROTOCOL_SSLv23 - - -@skipIfOldSSL -class SSLv3Test(BaseSSLTest, SSLTestMixin): - def get_ssl_version(self): - return ssl.PROTOCOL_SSLv3 - - -@skipIfOldSSL -class TLSv1Test(BaseSSLTest, SSLTestMixin): - def get_ssl_version(self): - return ssl.PROTOCOL_TLSv1 - - -class SSLContextTest(BaseSSLTest, SSLTestMixin): - def get_ssl_options(self): - context = ssl_options_to_context(AsyncHTTPSTestCase.get_ssl_options(self)) - assert isinstance(context, ssl.SSLContext) - return context - - -class BadSSLOptionsTest(unittest.TestCase): - def test_missing_arguments(self): - application = Application() - self.assertRaises( - KeyError, - HTTPServer, - application, - ssl_options={"keyfile": "/__missing__.crt"}, - ) - - def test_missing_key(self): - """A missing SSL key should cause an immediate exception.""" - - application = Application() - module_dir = os.path.dirname(__file__) - existing_certificate = os.path.join(module_dir, "test.crt") - existing_key = os.path.join(module_dir, "test.key") - - self.assertRaises( - (ValueError, IOError), - HTTPServer, - application, - ssl_options={"certfile": "/__mising__.crt"}, - ) - self.assertRaises( - (ValueError, IOError), - HTTPServer, - application, - ssl_options={ - "certfile": existing_certificate, - "keyfile": "/__missing__.key", - }, - ) - - # This actually works because both files exist - HTTPServer( - application, - ssl_options={"certfile": existing_certificate, "keyfile": existing_key}, - ) - - -class MultipartTestHandler(RequestHandler): - def post(self): - self.finish( - { - "header": self.request.headers["X-Header-Encoding-Test"], - "argument": self.get_argument("argument"), - "filename": self.request.files["files"][0].filename, - "filebody": _unicode(self.request.files["files"][0]["body"]), - } - ) - - -# This test is also called from wsgi_test -class HTTPConnectionTest(AsyncHTTPTestCase): - def get_handlers(self): - return [ - ("/multipart", MultipartTestHandler), - ("/hello", HelloWorldRequestHandler), - ] - - def get_app(self): - return Application(self.get_handlers()) - - def raw_fetch(self, headers, body, newline=b"\r\n"): - with closing(IOStream(socket.socket())) as stream: - self.io_loop.run_sync( - lambda: stream.connect(("127.0.0.1", self.get_http_port())) - ) - stream.write( - newline.join(headers + [utf8("Content-Length: %d" % len(body))]) - + newline - + newline - + body - ) - start_line, headers, body = self.io_loop.run_sync( - lambda: read_stream_body(stream) - ) - return body - - def test_multipart_form(self): - # Encodings here are tricky: Headers are latin1, bodies can be - # anything (we use utf8 by default). - response = self.raw_fetch( - [ - b"POST /multipart HTTP/1.0", - b"Content-Type: multipart/form-data; boundary=1234567890", - b"X-Header-encoding-test: \xe9", - ], - b"\r\n".join( - [ - b"Content-Disposition: form-data; name=argument", - b"", - u"\u00e1".encode("utf-8"), - b"--1234567890", - u'Content-Disposition: form-data; name="files"; filename="\u00f3"'.encode( - "utf8" - ), - b"", - u"\u00fa".encode("utf-8"), - b"--1234567890--", - b"", - ] - ), - ) - data = json_decode(response) - self.assertEqual(u"\u00e9", data["header"]) - self.assertEqual(u"\u00e1", data["argument"]) - self.assertEqual(u"\u00f3", data["filename"]) - self.assertEqual(u"\u00fa", data["filebody"]) - - def test_newlines(self): - # We support both CRLF and bare LF as line separators. - for newline in (b"\r\n", b"\n"): - response = self.raw_fetch([b"GET /hello HTTP/1.0"], b"", newline=newline) - self.assertEqual(response, b"Hello world") - - @gen_test - def test_100_continue(self): - # Run through a 100-continue interaction by hand: - # When given Expect: 100-continue, we get a 100 response after the - # headers, and then the real response after the body. - stream = IOStream(socket.socket()) - yield stream.connect(("127.0.0.1", self.get_http_port())) - yield stream.write( - b"\r\n".join( - [ - b"POST /hello HTTP/1.1", - b"Content-Length: 1024", - b"Expect: 100-continue", - b"Connection: close", - b"\r\n", - ] - ) - ) - data = yield stream.read_until(b"\r\n\r\n") - self.assertTrue(data.startswith(b"HTTP/1.1 100 "), data) - stream.write(b"a" * 1024) - first_line = yield stream.read_until(b"\r\n") - self.assertTrue(first_line.startswith(b"HTTP/1.1 200"), first_line) - header_data = yield stream.read_until(b"\r\n\r\n") - headers = HTTPHeaders.parse(native_str(header_data.decode("latin1"))) - body = yield stream.read_bytes(int(headers["Content-Length"])) - self.assertEqual(body, b"Got 1024 bytes in POST") - stream.close() - - -class EchoHandler(RequestHandler): - def get(self): - self.write(recursive_unicode(self.request.arguments)) - - def post(self): - self.write(recursive_unicode(self.request.arguments)) - - -class TypeCheckHandler(RequestHandler): - def prepare(self): - self.errors = {} # type: Dict[str, str] - fields = [ - ("method", str), - ("uri", str), - ("version", str), - ("remote_ip", str), - ("protocol", str), - ("host", str), - ("path", str), - ("query", str), - ] - for field, expected_type in fields: - self.check_type(field, getattr(self.request, field), expected_type) - - self.check_type("header_key", list(self.request.headers.keys())[0], str) - self.check_type("header_value", list(self.request.headers.values())[0], str) - - self.check_type("cookie_key", list(self.request.cookies.keys())[0], str) - self.check_type( - "cookie_value", list(self.request.cookies.values())[0].value, str - ) - # secure cookies - - self.check_type("arg_key", list(self.request.arguments.keys())[0], str) - self.check_type("arg_value", list(self.request.arguments.values())[0][0], bytes) - - def post(self): - self.check_type("body", self.request.body, bytes) - self.write(self.errors) - - def get(self): - self.write(self.errors) - - def check_type(self, name, obj, expected_type): - actual_type = type(obj) - if expected_type != actual_type: - self.errors[name] = "expected %s, got %s" % (expected_type, actual_type) - - -class PostEchoHandler(RequestHandler): - def post(self, *path_args): - self.write(dict(echo=self.get_argument("data"))) - - -class PostEchoGBKHandler(PostEchoHandler): - def decode_argument(self, value, name=None): - try: - return value.decode("gbk") - except Exception: - raise HTTPError(400, "invalid gbk bytes: %r" % value) - - -class HTTPServerTest(AsyncHTTPTestCase): - def get_app(self): - return Application( - [ - ("/echo", EchoHandler), - ("/typecheck", TypeCheckHandler), - ("//doubleslash", EchoHandler), - ("/post_utf8", PostEchoHandler), - ("/post_gbk", PostEchoGBKHandler), - ] - ) - - def test_query_string_encoding(self): - response = self.fetch("/echo?foo=%C3%A9") - data = json_decode(response.body) - self.assertEqual(data, {u"foo": [u"\u00e9"]}) - - def test_empty_query_string(self): - response = self.fetch("/echo?foo=&foo=") - data = json_decode(response.body) - self.assertEqual(data, {u"foo": [u"", u""]}) - - def test_empty_post_parameters(self): - response = self.fetch("/echo", method="POST", body="foo=&bar=") - data = json_decode(response.body) - self.assertEqual(data, {u"foo": [u""], u"bar": [u""]}) - - def test_types(self): - headers = {"Cookie": "foo=bar"} - response = self.fetch("/typecheck?foo=bar", headers=headers) - data = json_decode(response.body) - self.assertEqual(data, {}) - - response = self.fetch( - "/typecheck", method="POST", body="foo=bar", headers=headers - ) - data = json_decode(response.body) - self.assertEqual(data, {}) - - def test_double_slash(self): - # urlparse.urlsplit (which tornado.httpserver used to use - # incorrectly) would parse paths beginning with "//" as - # protocol-relative urls. - response = self.fetch("//doubleslash") - self.assertEqual(200, response.code) - self.assertEqual(json_decode(response.body), {}) - - def test_post_encodings(self): - headers = {"Content-Type": "application/x-www-form-urlencoded"} - uni_text = "chinese: \u5f20\u4e09" - for enc in ("utf8", "gbk"): - for quote in (True, False): - with self.subTest(enc=enc, quote=quote): - bin_text = uni_text.encode(enc) - if quote: - bin_text = urllib.parse.quote(bin_text).encode("ascii") - response = self.fetch( - "/post_" + enc, - method="POST", - headers=headers, - body=(b"data=" + bin_text), - ) - self.assertEqual(json_decode(response.body), {"echo": uni_text}) - - -class HTTPServerRawTest(AsyncHTTPTestCase): - def get_app(self): - return Application([("/echo", EchoHandler)]) - - def setUp(self): - super().setUp() - self.stream = IOStream(socket.socket()) - self.io_loop.run_sync( - lambda: self.stream.connect(("127.0.0.1", self.get_http_port())) - ) - - def tearDown(self): - self.stream.close() - super().tearDown() - - def test_empty_request(self): - self.stream.close() - self.io_loop.add_timeout(datetime.timedelta(seconds=0.001), self.stop) - self.wait() - - def test_malformed_first_line_response(self): - with ExpectLog(gen_log, ".*Malformed HTTP request line", level=logging.INFO): - self.stream.write(b"asdf\r\n\r\n") - start_line, headers, response = self.io_loop.run_sync( - lambda: read_stream_body(self.stream) - ) - self.assertEqual("HTTP/1.1", start_line.version) - self.assertEqual(400, start_line.code) - self.assertEqual("Bad Request", start_line.reason) - - def test_malformed_first_line_log(self): - with ExpectLog(gen_log, ".*Malformed HTTP request line", level=logging.INFO): - self.stream.write(b"asdf\r\n\r\n") - # TODO: need an async version of ExpectLog so we don't need - # hard-coded timeouts here. - self.io_loop.add_timeout(datetime.timedelta(seconds=0.05), self.stop) - self.wait() - - def test_malformed_headers(self): - with ExpectLog( - gen_log, - ".*Malformed HTTP message.*no colon in header line", - level=logging.INFO, - ): - self.stream.write(b"GET / HTTP/1.0\r\nasdf\r\n\r\n") - self.io_loop.add_timeout(datetime.timedelta(seconds=0.05), self.stop) - self.wait() - - def test_chunked_request_body(self): - # Chunked requests are not widely supported and we don't have a way - # to generate them in AsyncHTTPClient, but HTTPServer will read them. - self.stream.write( - b"""\ -POST /echo HTTP/1.1 -Transfer-Encoding: chunked -Content-Type: application/x-www-form-urlencoded - -4 -foo= -3 -bar -0 - -""".replace( - b"\n", b"\r\n" - ) - ) - start_line, headers, response = self.io_loop.run_sync( - lambda: read_stream_body(self.stream) - ) - self.assertEqual(json_decode(response), {u"foo": [u"bar"]}) - - def test_chunked_request_uppercase(self): - # As per RFC 2616 section 3.6, "Transfer-Encoding" header's value is - # case-insensitive. - self.stream.write( - b"""\ -POST /echo HTTP/1.1 -Transfer-Encoding: Chunked -Content-Type: application/x-www-form-urlencoded - -4 -foo= -3 -bar -0 - -""".replace( - b"\n", b"\r\n" - ) - ) - start_line, headers, response = self.io_loop.run_sync( - lambda: read_stream_body(self.stream) - ) - self.assertEqual(json_decode(response), {u"foo": [u"bar"]}) - - @gen_test - def test_invalid_content_length(self): - with ExpectLog( - gen_log, ".*Only integer Content-Length is allowed", level=logging.INFO - ): - self.stream.write( - b"""\ -POST /echo HTTP/1.1 -Content-Length: foo - -bar - -""".replace( - b"\n", b"\r\n" - ) - ) - yield self.stream.read_until_close() - - -class XHeaderTest(HandlerBaseTestCase): - class Handler(RequestHandler): - def get(self): - self.set_header("request-version", self.request.version) - self.write( - dict( - remote_ip=self.request.remote_ip, - remote_protocol=self.request.protocol, - ) - ) - - def get_httpserver_options(self): - return dict(xheaders=True, trusted_downstream=["5.5.5.5"]) - - def test_ip_headers(self): - self.assertEqual(self.fetch_json("/")["remote_ip"], "127.0.0.1") - - valid_ipv4 = {"X-Real-IP": "4.4.4.4"} - self.assertEqual( - self.fetch_json("/", headers=valid_ipv4)["remote_ip"], "4.4.4.4" - ) - - valid_ipv4_list = {"X-Forwarded-For": "127.0.0.1, 4.4.4.4"} - self.assertEqual( - self.fetch_json("/", headers=valid_ipv4_list)["remote_ip"], "4.4.4.4" - ) - - valid_ipv6 = {"X-Real-IP": "2620:0:1cfe:face:b00c::3"} - self.assertEqual( - self.fetch_json("/", headers=valid_ipv6)["remote_ip"], - "2620:0:1cfe:face:b00c::3", - ) - - valid_ipv6_list = {"X-Forwarded-For": "::1, 2620:0:1cfe:face:b00c::3"} - self.assertEqual( - self.fetch_json("/", headers=valid_ipv6_list)["remote_ip"], - "2620:0:1cfe:face:b00c::3", - ) - - invalid_chars = {"X-Real-IP": "4.4.4.4<script>"} - self.assertEqual( - self.fetch_json("/", headers=invalid_chars)["remote_ip"], "127.0.0.1" - ) - - invalid_chars_list = {"X-Forwarded-For": "4.4.4.4, 5.5.5.5<script>"} - self.assertEqual( - self.fetch_json("/", headers=invalid_chars_list)["remote_ip"], "127.0.0.1" - ) - - invalid_host = {"X-Real-IP": "www.google.com"} - self.assertEqual( - self.fetch_json("/", headers=invalid_host)["remote_ip"], "127.0.0.1" - ) - - def test_trusted_downstream(self): - valid_ipv4_list = {"X-Forwarded-For": "127.0.0.1, 4.4.4.4, 5.5.5.5"} - resp = self.fetch("/", headers=valid_ipv4_list) - if resp.headers["request-version"].startswith("HTTP/2"): - # This is a hack - there's nothing that fundamentally requires http/1 - # here but tornado_http2 doesn't support it yet. - self.skipTest("requires HTTP/1.x") - result = json_decode(resp.body) - self.assertEqual(result["remote_ip"], "4.4.4.4") - - def test_scheme_headers(self): - self.assertEqual(self.fetch_json("/")["remote_protocol"], "http") - - https_scheme = {"X-Scheme": "https"} - self.assertEqual( - self.fetch_json("/", headers=https_scheme)["remote_protocol"], "https" - ) - - https_forwarded = {"X-Forwarded-Proto": "https"} - self.assertEqual( - self.fetch_json("/", headers=https_forwarded)["remote_protocol"], "https" - ) - - https_multi_forwarded = {"X-Forwarded-Proto": "https , http"} - self.assertEqual( - self.fetch_json("/", headers=https_multi_forwarded)["remote_protocol"], - "http", - ) - - http_multi_forwarded = {"X-Forwarded-Proto": "http,https"} - self.assertEqual( - self.fetch_json("/", headers=http_multi_forwarded)["remote_protocol"], - "https", - ) - - bad_forwarded = {"X-Forwarded-Proto": "unknown"} - self.assertEqual( - self.fetch_json("/", headers=bad_forwarded)["remote_protocol"], "http" - ) - - -class SSLXHeaderTest(AsyncHTTPSTestCase, HandlerBaseTestCase): - def get_app(self): - return Application([("/", XHeaderTest.Handler)]) - - def get_httpserver_options(self): - output = super().get_httpserver_options() - output["xheaders"] = True - return output - - def test_request_without_xprotocol(self): - self.assertEqual(self.fetch_json("/")["remote_protocol"], "https") - - http_scheme = {"X-Scheme": "http"} - self.assertEqual( - self.fetch_json("/", headers=http_scheme)["remote_protocol"], "http" - ) - - bad_scheme = {"X-Scheme": "unknown"} - self.assertEqual( - self.fetch_json("/", headers=bad_scheme)["remote_protocol"], "https" - ) - - -class ManualProtocolTest(HandlerBaseTestCase): - class Handler(RequestHandler): - def get(self): - self.write(dict(protocol=self.request.protocol)) - - def get_httpserver_options(self): - return dict(protocol="https") - - def test_manual_protocol(self): - self.assertEqual(self.fetch_json("/")["protocol"], "https") - - -@unittest.skipIf( - not hasattr(socket, "AF_UNIX") or sys.platform == "cygwin", - "unix sockets not supported on this platform", -) -class UnixSocketTest(AsyncTestCase): - """HTTPServers can listen on Unix sockets too. - - Why would you want to do this? Nginx can proxy to backends listening - on unix sockets, for one thing (and managing a namespace for unix - sockets can be easier than managing a bunch of TCP port numbers). - - Unfortunately, there's no way to specify a unix socket in a url for - an HTTP client, so we have to test this by hand. - """ - - def setUp(self): - super().setUp() - self.tmpdir = tempfile.mkdtemp() - self.sockfile = os.path.join(self.tmpdir, "test.sock") - sock = netutil.bind_unix_socket(self.sockfile) - app = Application([("/hello", HelloWorldRequestHandler)]) - self.server = HTTPServer(app) - self.server.add_socket(sock) - self.stream = IOStream(socket.socket(socket.AF_UNIX)) - self.io_loop.run_sync(lambda: self.stream.connect(self.sockfile)) - - def tearDown(self): - self.stream.close() - self.io_loop.run_sync(self.server.close_all_connections) - self.server.stop() - shutil.rmtree(self.tmpdir) - super().tearDown() - - @gen_test - def test_unix_socket(self): - self.stream.write(b"GET /hello HTTP/1.0\r\n\r\n") - response = yield self.stream.read_until(b"\r\n") - self.assertEqual(response, b"HTTP/1.1 200 OK\r\n") - header_data = yield self.stream.read_until(b"\r\n\r\n") - headers = HTTPHeaders.parse(header_data.decode("latin1")) - body = yield self.stream.read_bytes(int(headers["Content-Length"])) - self.assertEqual(body, b"Hello world") - - @gen_test - def test_unix_socket_bad_request(self): - # Unix sockets don't have remote addresses so they just return an - # empty string. - with ExpectLog(gen_log, "Malformed HTTP message from"): - self.stream.write(b"garbage\r\n\r\n") - response = yield self.stream.read_until_close() - self.assertEqual(response, b"HTTP/1.1 400 Bad Request\r\n\r\n") - - -class KeepAliveTest(AsyncHTTPTestCase): - """Tests various scenarios for HTTP 1.1 keep-alive support. - - These tests don't use AsyncHTTPClient because we want to control - connection reuse and closing. - """ - - def get_app(self): - class HelloHandler(RequestHandler): - def get(self): - self.finish("Hello world") - - def post(self): - self.finish("Hello world") - - class LargeHandler(RequestHandler): - def get(self): - # 512KB should be bigger than the socket buffers so it will - # be written out in chunks. - self.write("".join(chr(i % 256) * 1024 for i in range(512))) - - class TransferEncodingChunkedHandler(RequestHandler): - @gen.coroutine - def head(self): - self.write("Hello world") - yield self.flush() - - class FinishOnCloseHandler(RequestHandler): - def initialize(self, cleanup_event): - self.cleanup_event = cleanup_event - - @gen.coroutine - def get(self): - self.flush() - yield self.cleanup_event.wait() - - def on_connection_close(self): - # This is not very realistic, but finishing the request - # from the close callback has the right timing to mimic - # some errors seen in the wild. - self.finish("closed") - - self.cleanup_event = Event() - return Application( - [ - ("/", HelloHandler), - ("/large", LargeHandler), - ("/chunked", TransferEncodingChunkedHandler), - ( - "/finish_on_close", - FinishOnCloseHandler, - dict(cleanup_event=self.cleanup_event), - ), - ] - ) - - def setUp(self): - super().setUp() - self.http_version = b"HTTP/1.1" - - def tearDown(self): - # We just closed the client side of the socket; let the IOLoop run - # once to make sure the server side got the message. - self.io_loop.add_timeout(datetime.timedelta(seconds=0.001), self.stop) - self.wait() - - if hasattr(self, "stream"): - self.stream.close() - super().tearDown() - - # The next few methods are a crude manual http client - @gen.coroutine - def connect(self): - self.stream = IOStream(socket.socket()) - yield self.stream.connect(("127.0.0.1", self.get_http_port())) - - @gen.coroutine - def read_headers(self): - first_line = yield self.stream.read_until(b"\r\n") - self.assertTrue(first_line.startswith(b"HTTP/1.1 200"), first_line) - header_bytes = yield self.stream.read_until(b"\r\n\r\n") - headers = HTTPHeaders.parse(header_bytes.decode("latin1")) - raise gen.Return(headers) - - @gen.coroutine - def read_response(self): - self.headers = yield self.read_headers() - body = yield self.stream.read_bytes(int(self.headers["Content-Length"])) - self.assertEqual(b"Hello world", body) - - def close(self): - self.stream.close() - del self.stream - - @gen_test - def test_two_requests(self): - yield self.connect() - self.stream.write(b"GET / HTTP/1.1\r\n\r\n") - yield self.read_response() - self.stream.write(b"GET / HTTP/1.1\r\n\r\n") - yield self.read_response() - self.close() - - @gen_test - def test_request_close(self): - yield self.connect() - self.stream.write(b"GET / HTTP/1.1\r\nConnection: close\r\n\r\n") - yield self.read_response() - data = yield self.stream.read_until_close() - self.assertTrue(not data) - self.assertEqual(self.headers["Connection"], "close") - self.close() - - # keepalive is supported for http 1.0 too, but it's opt-in - @gen_test - def test_http10(self): - self.http_version = b"HTTP/1.0" - yield self.connect() - self.stream.write(b"GET / HTTP/1.0\r\n\r\n") - yield self.read_response() - data = yield self.stream.read_until_close() - self.assertTrue(not data) - self.assertTrue("Connection" not in self.headers) - self.close() - - @gen_test - def test_http10_keepalive(self): - self.http_version = b"HTTP/1.0" - yield self.connect() - self.stream.write(b"GET / HTTP/1.0\r\nConnection: keep-alive\r\n\r\n") - yield self.read_response() - self.assertEqual(self.headers["Connection"], "Keep-Alive") - self.stream.write(b"GET / HTTP/1.0\r\nConnection: keep-alive\r\n\r\n") - yield self.read_response() - self.assertEqual(self.headers["Connection"], "Keep-Alive") - self.close() - - @gen_test - def test_http10_keepalive_extra_crlf(self): - self.http_version = b"HTTP/1.0" - yield self.connect() - self.stream.write(b"GET / HTTP/1.0\r\nConnection: keep-alive\r\n\r\n\r\n") - yield self.read_response() - self.assertEqual(self.headers["Connection"], "Keep-Alive") - self.stream.write(b"GET / HTTP/1.0\r\nConnection: keep-alive\r\n\r\n") - yield self.read_response() - self.assertEqual(self.headers["Connection"], "Keep-Alive") - self.close() - - @gen_test - def test_pipelined_requests(self): - yield self.connect() - self.stream.write(b"GET / HTTP/1.1\r\n\r\nGET / HTTP/1.1\r\n\r\n") - yield self.read_response() - yield self.read_response() - self.close() - - @gen_test - def test_pipelined_cancel(self): - yield self.connect() - self.stream.write(b"GET / HTTP/1.1\r\n\r\nGET / HTTP/1.1\r\n\r\n") - # only read once - yield self.read_response() - self.close() - - @gen_test - def test_cancel_during_download(self): - yield self.connect() - self.stream.write(b"GET /large HTTP/1.1\r\n\r\n") - yield self.read_headers() - yield self.stream.read_bytes(1024) - self.close() - - @gen_test - def test_finish_while_closed(self): - yield self.connect() - self.stream.write(b"GET /finish_on_close HTTP/1.1\r\n\r\n") - yield self.read_headers() - self.close() - # Let the hanging coroutine clean up after itself - self.cleanup_event.set() - - @gen_test - def test_keepalive_chunked(self): - self.http_version = b"HTTP/1.0" - yield self.connect() - self.stream.write( - b"POST / HTTP/1.0\r\n" - b"Connection: keep-alive\r\n" - b"Transfer-Encoding: chunked\r\n" - b"\r\n" - b"0\r\n" - b"\r\n" - ) - yield self.read_response() - self.assertEqual(self.headers["Connection"], "Keep-Alive") - self.stream.write(b"GET / HTTP/1.0\r\nConnection: keep-alive\r\n\r\n") - yield self.read_response() - self.assertEqual(self.headers["Connection"], "Keep-Alive") - self.close() - - @gen_test - def test_keepalive_chunked_head_no_body(self): - yield self.connect() - self.stream.write(b"HEAD /chunked HTTP/1.1\r\n\r\n") - yield self.read_headers() - - self.stream.write(b"HEAD /chunked HTTP/1.1\r\n\r\n") - yield self.read_headers() - self.close() - - -class GzipBaseTest(AsyncHTTPTestCase): - def get_app(self): - return Application([("/", EchoHandler)]) - - def post_gzip(self, body): - bytesio = BytesIO() - gzip_file = gzip.GzipFile(mode="w", fileobj=bytesio) - gzip_file.write(utf8(body)) - gzip_file.close() - compressed_body = bytesio.getvalue() - return self.fetch( - "/", - method="POST", - body=compressed_body, - headers={"Content-Encoding": "gzip"}, - ) - - def test_uncompressed(self): - response = self.fetch("/", method="POST", body="foo=bar") - self.assertEqual(json_decode(response.body), {u"foo": [u"bar"]}) - - -class GzipTest(GzipBaseTest, AsyncHTTPTestCase): - def get_httpserver_options(self): - return dict(decompress_request=True) - - def test_gzip(self): - response = self.post_gzip("foo=bar") - self.assertEqual(json_decode(response.body), {u"foo": [u"bar"]}) - - -class GzipUnsupportedTest(GzipBaseTest, AsyncHTTPTestCase): - def test_gzip_unsupported(self): - # Gzip support is opt-in; without it the server fails to parse - # the body (but parsing form bodies is currently just a log message, - # not a fatal error). - with ExpectLog(gen_log, "Unsupported Content-Encoding"): - response = self.post_gzip("foo=bar") - self.assertEqual(json_decode(response.body), {}) - - -class StreamingChunkSizeTest(AsyncHTTPTestCase): - # 50 characters long, and repetitive so it can be compressed. - BODY = b"01234567890123456789012345678901234567890123456789" - CHUNK_SIZE = 16 - - def get_http_client(self): - # body_producer doesn't work on curl_httpclient, so override the - # configured AsyncHTTPClient implementation. - return SimpleAsyncHTTPClient() - - def get_httpserver_options(self): - return dict(chunk_size=self.CHUNK_SIZE, decompress_request=True) - - class MessageDelegate(HTTPMessageDelegate): - def __init__(self, connection): - self.connection = connection - - def headers_received(self, start_line, headers): - self.chunk_lengths = [] # type: List[int] - - def data_received(self, chunk): - self.chunk_lengths.append(len(chunk)) - - def finish(self): - response_body = utf8(json_encode(self.chunk_lengths)) - self.connection.write_headers( - ResponseStartLine("HTTP/1.1", 200, "OK"), - HTTPHeaders({"Content-Length": str(len(response_body))}), - ) - self.connection.write(response_body) - self.connection.finish() - - def get_app(self): - class App(HTTPServerConnectionDelegate): - def start_request(self, server_conn, request_conn): - return StreamingChunkSizeTest.MessageDelegate(request_conn) - - return App() - - def fetch_chunk_sizes(self, **kwargs): - response = self.fetch("/", method="POST", **kwargs) - response.rethrow() - chunks = json_decode(response.body) - self.assertEqual(len(self.BODY), sum(chunks)) - for chunk_size in chunks: - self.assertLessEqual( - chunk_size, self.CHUNK_SIZE, "oversized chunk: " + str(chunks) - ) - self.assertGreater(chunk_size, 0, "empty chunk: " + str(chunks)) - return chunks - - def compress(self, body): - bytesio = BytesIO() - gzfile = gzip.GzipFile(mode="w", fileobj=bytesio) - gzfile.write(body) - gzfile.close() - compressed = bytesio.getvalue() - if len(compressed) >= len(body): - raise Exception("body did not shrink when compressed") - return compressed - - def test_regular_body(self): - chunks = self.fetch_chunk_sizes(body=self.BODY) - # Without compression we know exactly what to expect. - self.assertEqual([16, 16, 16, 2], chunks) - - def test_compressed_body(self): - self.fetch_chunk_sizes( - body=self.compress(self.BODY), headers={"Content-Encoding": "gzip"} - ) - # Compression creates irregular boundaries so the assertions - # in fetch_chunk_sizes are as specific as we can get. - - def test_chunked_body(self): - def body_producer(write): - write(self.BODY[:20]) - write(self.BODY[20:]) - - chunks = self.fetch_chunk_sizes(body_producer=body_producer) - # HTTP chunk boundaries translate to application-visible breaks - self.assertEqual([16, 4, 16, 14], chunks) - - def test_chunked_compressed(self): - compressed = self.compress(self.BODY) - self.assertGreater(len(compressed), 20) - - def body_producer(write): - write(compressed[:20]) - write(compressed[20:]) - - self.fetch_chunk_sizes( - body_producer=body_producer, headers={"Content-Encoding": "gzip"} - ) - - -class MaxHeaderSizeTest(AsyncHTTPTestCase): - def get_app(self): - return Application([("/", HelloWorldRequestHandler)]) - - def get_httpserver_options(self): - return dict(max_header_size=1024) - - def test_small_headers(self): - response = self.fetch("/", headers={"X-Filler": "a" * 100}) - response.rethrow() - self.assertEqual(response.body, b"Hello world") - - def test_large_headers(self): - with ExpectLog(gen_log, "Unsatisfiable read", required=False): - try: - self.fetch("/", headers={"X-Filler": "a" * 1000}, raise_error=True) - self.fail("did not raise expected exception") - except HTTPError as e: - # 431 is "Request Header Fields Too Large", defined in RFC - # 6585. However, many implementations just close the - # connection in this case, resulting in a missing response. - if e.response is not None: - self.assertIn(e.response.code, (431, 599)) - - -@skipOnTravis -class IdleTimeoutTest(AsyncHTTPTestCase): - def get_app(self): - return Application([("/", HelloWorldRequestHandler)]) - - def get_httpserver_options(self): - return dict(idle_connection_timeout=0.1) - - def setUp(self): - super().setUp() - self.streams = [] # type: List[IOStream] - - def tearDown(self): - super().tearDown() - for stream in self.streams: - stream.close() - - @gen.coroutine - def connect(self): - stream = IOStream(socket.socket()) - yield stream.connect(("127.0.0.1", self.get_http_port())) - self.streams.append(stream) - raise gen.Return(stream) - - @gen_test - def test_unused_connection(self): - stream = yield self.connect() - event = Event() - stream.set_close_callback(event.set) - yield event.wait() - - @gen_test - def test_idle_after_use(self): - stream = yield self.connect() - event = Event() - stream.set_close_callback(event.set) - - # Use the connection twice to make sure keep-alives are working - for i in range(2): - stream.write(b"GET / HTTP/1.1\r\n\r\n") - yield stream.read_until(b"\r\n\r\n") - data = yield stream.read_bytes(11) - self.assertEqual(data, b"Hello world") - - # Now let the timeout trigger and close the connection. - yield event.wait() - - -class BodyLimitsTest(AsyncHTTPTestCase): - def get_app(self): - class BufferedHandler(RequestHandler): - def put(self): - self.write(str(len(self.request.body))) - - @stream_request_body - class StreamingHandler(RequestHandler): - def initialize(self): - self.bytes_read = 0 - - def prepare(self): - conn = typing.cast(HTTP1Connection, self.request.connection) - if "expected_size" in self.request.arguments: - conn.set_max_body_size(int(self.get_argument("expected_size"))) - if "body_timeout" in self.request.arguments: - conn.set_body_timeout(float(self.get_argument("body_timeout"))) - - def data_received(self, data): - self.bytes_read += len(data) - - def put(self): - self.write(str(self.bytes_read)) - - return Application( - [("/buffered", BufferedHandler), ("/streaming", StreamingHandler)] - ) - - def get_httpserver_options(self): - return dict(body_timeout=3600, max_body_size=4096) - - def get_http_client(self): - # body_producer doesn't work on curl_httpclient, so override the - # configured AsyncHTTPClient implementation. - return SimpleAsyncHTTPClient() - - def test_small_body(self): - response = self.fetch("/buffered", method="PUT", body=b"a" * 4096) - self.assertEqual(response.body, b"4096") - response = self.fetch("/streaming", method="PUT", body=b"a" * 4096) - self.assertEqual(response.body, b"4096") - - def test_large_body_buffered(self): - with ExpectLog(gen_log, ".*Content-Length too long", level=logging.INFO): - response = self.fetch("/buffered", method="PUT", body=b"a" * 10240) - self.assertEqual(response.code, 400) - - @unittest.skipIf(os.name == "nt", "flaky on windows") - def test_large_body_buffered_chunked(self): - # This test is flaky on windows for unknown reasons. - with ExpectLog(gen_log, ".*chunked body too large", level=logging.INFO): - response = self.fetch( - "/buffered", - method="PUT", - body_producer=lambda write: write(b"a" * 10240), - ) - self.assertEqual(response.code, 400) - - def test_large_body_streaming(self): - with ExpectLog(gen_log, ".*Content-Length too long", level=logging.INFO): - response = self.fetch("/streaming", method="PUT", body=b"a" * 10240) - self.assertEqual(response.code, 400) - - @unittest.skipIf(os.name == "nt", "flaky on windows") - def test_large_body_streaming_chunked(self): - with ExpectLog(gen_log, ".*chunked body too large", level=logging.INFO): - response = self.fetch( - "/streaming", - method="PUT", - body_producer=lambda write: write(b"a" * 10240), - ) - self.assertEqual(response.code, 400) - - def test_large_body_streaming_override(self): - response = self.fetch( - "/streaming?expected_size=10240", method="PUT", body=b"a" * 10240 - ) - self.assertEqual(response.body, b"10240") - - def test_large_body_streaming_chunked_override(self): - response = self.fetch( - "/streaming?expected_size=10240", - method="PUT", - body_producer=lambda write: write(b"a" * 10240), - ) - self.assertEqual(response.body, b"10240") - - @gen_test - def test_timeout(self): - stream = IOStream(socket.socket()) - try: - yield stream.connect(("127.0.0.1", self.get_http_port())) - # Use a raw stream because AsyncHTTPClient won't let us read a - # response without finishing a body. - stream.write( - b"PUT /streaming?body_timeout=0.1 HTTP/1.0\r\n" - b"Content-Length: 42\r\n\r\n" - ) - with ExpectLog(gen_log, "Timeout reading body", level=logging.INFO): - response = yield stream.read_until_close() - self.assertEqual(response, b"") - finally: - stream.close() - - @gen_test - def test_body_size_override_reset(self): - # The max_body_size override is reset between requests. - stream = IOStream(socket.socket()) - try: - yield stream.connect(("127.0.0.1", self.get_http_port())) - # Use a raw stream so we can make sure it's all on one connection. - stream.write( - b"PUT /streaming?expected_size=10240 HTTP/1.1\r\n" - b"Content-Length: 10240\r\n\r\n" - ) - stream.write(b"a" * 10240) - start_line, headers, response = yield read_stream_body(stream) - self.assertEqual(response, b"10240") - # Without the ?expected_size parameter, we get the old default value - stream.write( - b"PUT /streaming HTTP/1.1\r\n" b"Content-Length: 10240\r\n\r\n" - ) - with ExpectLog(gen_log, ".*Content-Length too long", level=logging.INFO): - data = yield stream.read_until_close() - self.assertEqual(data, b"HTTP/1.1 400 Bad Request\r\n\r\n") - finally: - stream.close() - - -class LegacyInterfaceTest(AsyncHTTPTestCase): - def get_app(self): - # The old request_callback interface does not implement the - # delegate interface, and writes its response via request.write - # instead of request.connection.write_headers. - def handle_request(request): - self.http1 = request.version.startswith("HTTP/1.") - if not self.http1: - # This test will be skipped if we're using HTTP/2, - # so just close it out cleanly using the modern interface. - request.connection.write_headers( - ResponseStartLine("", 200, "OK"), HTTPHeaders() - ) - request.connection.finish() - return - message = b"Hello world" - request.connection.write( - utf8("HTTP/1.1 200 OK\r\n" "Content-Length: %d\r\n\r\n" % len(message)) - ) - request.connection.write(message) - request.connection.finish() - - return handle_request - - def test_legacy_interface(self): - response = self.fetch("/") - if not self.http1: - self.skipTest("requires HTTP/1.x") - self.assertEqual(response.body, b"Hello world") diff --git a/venv/lib/python3.8/site-packages/tornado/test/httputil_test.py b/venv/lib/python3.8/site-packages/tornado/test/httputil_test.py deleted file mode 100644 index 0fad403..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/httputil_test.py +++ /dev/null @@ -1,521 +0,0 @@ -from tornado.httputil import ( - url_concat, - parse_multipart_form_data, - HTTPHeaders, - format_timestamp, - HTTPServerRequest, - parse_request_start_line, - parse_cookie, - qs_to_qsl, - HTTPInputError, - HTTPFile, -) -from tornado.escape import utf8, native_str -from tornado.log import gen_log -from tornado.testing import ExpectLog - -import copy -import datetime -import logging -import pickle -import time -import urllib.parse -import unittest - -from typing import Tuple, Dict, List - - -def form_data_args() -> Tuple[Dict[str, List[bytes]], Dict[str, List[HTTPFile]]]: - """Return two empty dicts suitable for use with parse_multipart_form_data. - - mypy insists on type annotations for dict literals, so this lets us avoid - the verbose types throughout this test. - """ - return {}, {} - - -class TestUrlConcat(unittest.TestCase): - def test_url_concat_no_query_params(self): - url = url_concat("https://localhost/path", [("y", "y"), ("z", "z")]) - self.assertEqual(url, "https://localhost/path?y=y&z=z") - - def test_url_concat_encode_args(self): - url = url_concat("https://localhost/path", [("y", "/y"), ("z", "z")]) - self.assertEqual(url, "https://localhost/path?y=%2Fy&z=z") - - def test_url_concat_trailing_q(self): - url = url_concat("https://localhost/path?", [("y", "y"), ("z", "z")]) - self.assertEqual(url, "https://localhost/path?y=y&z=z") - - def test_url_concat_q_with_no_trailing_amp(self): - url = url_concat("https://localhost/path?x", [("y", "y"), ("z", "z")]) - self.assertEqual(url, "https://localhost/path?x=&y=y&z=z") - - def test_url_concat_trailing_amp(self): - url = url_concat("https://localhost/path?x&", [("y", "y"), ("z", "z")]) - self.assertEqual(url, "https://localhost/path?x=&y=y&z=z") - - def test_url_concat_mult_params(self): - url = url_concat("https://localhost/path?a=1&b=2", [("y", "y"), ("z", "z")]) - self.assertEqual(url, "https://localhost/path?a=1&b=2&y=y&z=z") - - def test_url_concat_no_params(self): - url = url_concat("https://localhost/path?r=1&t=2", []) - self.assertEqual(url, "https://localhost/path?r=1&t=2") - - def test_url_concat_none_params(self): - url = url_concat("https://localhost/path?r=1&t=2", None) - self.assertEqual(url, "https://localhost/path?r=1&t=2") - - def test_url_concat_with_frag(self): - url = url_concat("https://localhost/path#tab", [("y", "y")]) - self.assertEqual(url, "https://localhost/path?y=y#tab") - - def test_url_concat_multi_same_params(self): - url = url_concat("https://localhost/path", [("y", "y1"), ("y", "y2")]) - self.assertEqual(url, "https://localhost/path?y=y1&y=y2") - - def test_url_concat_multi_same_query_params(self): - url = url_concat("https://localhost/path?r=1&r=2", [("y", "y")]) - self.assertEqual(url, "https://localhost/path?r=1&r=2&y=y") - - def test_url_concat_dict_params(self): - url = url_concat("https://localhost/path", dict(y="y")) - self.assertEqual(url, "https://localhost/path?y=y") - - -class QsParseTest(unittest.TestCase): - def test_parsing(self): - qsstring = "a=1&b=2&a=3" - qs = urllib.parse.parse_qs(qsstring) - qsl = list(qs_to_qsl(qs)) - self.assertIn(("a", "1"), qsl) - self.assertIn(("a", "3"), qsl) - self.assertIn(("b", "2"), qsl) - - -class MultipartFormDataTest(unittest.TestCase): - def test_file_upload(self): - data = b"""\ ---1234 -Content-Disposition: form-data; name="files"; filename="ab.txt" - -Foo ---1234--""".replace( - b"\n", b"\r\n" - ) - args, files = form_data_args() - parse_multipart_form_data(b"1234", data, args, files) - file = files["files"][0] - self.assertEqual(file["filename"], "ab.txt") - self.assertEqual(file["body"], b"Foo") - - def test_unquoted_names(self): - # quotes are optional unless special characters are present - data = b"""\ ---1234 -Content-Disposition: form-data; name=files; filename=ab.txt - -Foo ---1234--""".replace( - b"\n", b"\r\n" - ) - args, files = form_data_args() - parse_multipart_form_data(b"1234", data, args, files) - file = files["files"][0] - self.assertEqual(file["filename"], "ab.txt") - self.assertEqual(file["body"], b"Foo") - - def test_special_filenames(self): - filenames = [ - "a;b.txt", - 'a"b.txt', - 'a";b.txt', - 'a;"b.txt', - 'a";";.txt', - 'a\\"b.txt', - "a\\b.txt", - ] - for filename in filenames: - logging.debug("trying filename %r", filename) - str_data = """\ ---1234 -Content-Disposition: form-data; name="files"; filename="%s" - -Foo ---1234--""" % filename.replace( - "\\", "\\\\" - ).replace( - '"', '\\"' - ) - data = utf8(str_data.replace("\n", "\r\n")) - args, files = form_data_args() - parse_multipart_form_data(b"1234", data, args, files) - file = files["files"][0] - self.assertEqual(file["filename"], filename) - self.assertEqual(file["body"], b"Foo") - - def test_non_ascii_filename(self): - data = b"""\ ---1234 -Content-Disposition: form-data; name="files"; filename="ab.txt"; filename*=UTF-8''%C3%A1b.txt - -Foo ---1234--""".replace( - b"\n", b"\r\n" - ) - args, files = form_data_args() - parse_multipart_form_data(b"1234", data, args, files) - file = files["files"][0] - self.assertEqual(file["filename"], u"áb.txt") - self.assertEqual(file["body"], b"Foo") - - def test_boundary_starts_and_ends_with_quotes(self): - data = b"""\ ---1234 -Content-Disposition: form-data; name="files"; filename="ab.txt" - -Foo ---1234--""".replace( - b"\n", b"\r\n" - ) - args, files = form_data_args() - parse_multipart_form_data(b'"1234"', data, args, files) - file = files["files"][0] - self.assertEqual(file["filename"], "ab.txt") - self.assertEqual(file["body"], b"Foo") - - def test_missing_headers(self): - data = b"""\ ---1234 - -Foo ---1234--""".replace( - b"\n", b"\r\n" - ) - args, files = form_data_args() - with ExpectLog(gen_log, "multipart/form-data missing headers"): - parse_multipart_form_data(b"1234", data, args, files) - self.assertEqual(files, {}) - - def test_invalid_content_disposition(self): - data = b"""\ ---1234 -Content-Disposition: invalid; name="files"; filename="ab.txt" - -Foo ---1234--""".replace( - b"\n", b"\r\n" - ) - args, files = form_data_args() - with ExpectLog(gen_log, "Invalid multipart/form-data"): - parse_multipart_form_data(b"1234", data, args, files) - self.assertEqual(files, {}) - - def test_line_does_not_end_with_correct_line_break(self): - data = b"""\ ---1234 -Content-Disposition: form-data; name="files"; filename="ab.txt" - -Foo--1234--""".replace( - b"\n", b"\r\n" - ) - args, files = form_data_args() - with ExpectLog(gen_log, "Invalid multipart/form-data"): - parse_multipart_form_data(b"1234", data, args, files) - self.assertEqual(files, {}) - - def test_content_disposition_header_without_name_parameter(self): - data = b"""\ ---1234 -Content-Disposition: form-data; filename="ab.txt" - -Foo ---1234--""".replace( - b"\n", b"\r\n" - ) - args, files = form_data_args() - with ExpectLog(gen_log, "multipart/form-data value missing name"): - parse_multipart_form_data(b"1234", data, args, files) - self.assertEqual(files, {}) - - def test_data_after_final_boundary(self): - # The spec requires that data after the final boundary be ignored. - # http://www.w3.org/Protocols/rfc1341/7_2_Multipart.html - # In practice, some libraries include an extra CRLF after the boundary. - data = b"""\ ---1234 -Content-Disposition: form-data; name="files"; filename="ab.txt" - -Foo ---1234-- -""".replace( - b"\n", b"\r\n" - ) - args, files = form_data_args() - parse_multipart_form_data(b"1234", data, args, files) - file = files["files"][0] - self.assertEqual(file["filename"], "ab.txt") - self.assertEqual(file["body"], b"Foo") - - -class HTTPHeadersTest(unittest.TestCase): - def test_multi_line(self): - # Lines beginning with whitespace are appended to the previous line - # with any leading whitespace replaced by a single space. - # Note that while multi-line headers are a part of the HTTP spec, - # their use is strongly discouraged. - data = """\ -Foo: bar - baz -Asdf: qwer -\tzxcv -Foo: even - more - lines -""".replace( - "\n", "\r\n" - ) - headers = HTTPHeaders.parse(data) - self.assertEqual(headers["asdf"], "qwer zxcv") - self.assertEqual(headers.get_list("asdf"), ["qwer zxcv"]) - self.assertEqual(headers["Foo"], "bar baz,even more lines") - self.assertEqual(headers.get_list("foo"), ["bar baz", "even more lines"]) - self.assertEqual( - sorted(list(headers.get_all())), - [("Asdf", "qwer zxcv"), ("Foo", "bar baz"), ("Foo", "even more lines")], - ) - - def test_malformed_continuation(self): - # If the first line starts with whitespace, it's a - # continuation line with nothing to continue, so reject it - # (with a proper error). - data = " Foo: bar" - self.assertRaises(HTTPInputError, HTTPHeaders.parse, data) - - def test_unicode_newlines(self): - # Ensure that only \r\n is recognized as a header separator, and not - # the other newline-like unicode characters. - # Characters that are likely to be problematic can be found in - # http://unicode.org/standard/reports/tr13/tr13-5.html - # and cpython's unicodeobject.c (which defines the implementation - # of unicode_type.splitlines(), and uses a different list than TR13). - newlines = [ - u"\u001b", # VERTICAL TAB - u"\u001c", # FILE SEPARATOR - u"\u001d", # GROUP SEPARATOR - u"\u001e", # RECORD SEPARATOR - u"\u0085", # NEXT LINE - u"\u2028", # LINE SEPARATOR - u"\u2029", # PARAGRAPH SEPARATOR - ] - for newline in newlines: - # Try the utf8 and latin1 representations of each newline - for encoding in ["utf8", "latin1"]: - try: - try: - encoded = newline.encode(encoding) - except UnicodeEncodeError: - # Some chars cannot be represented in latin1 - continue - data = b"Cookie: foo=" + encoded + b"bar" - # parse() wants a native_str, so decode through latin1 - # in the same way the real parser does. - headers = HTTPHeaders.parse(native_str(data.decode("latin1"))) - expected = [ - ( - "Cookie", - "foo=" + native_str(encoded.decode("latin1")) + "bar", - ) - ] - self.assertEqual(expected, list(headers.get_all())) - except Exception: - gen_log.warning("failed while trying %r in %s", newline, encoding) - raise - - def test_optional_cr(self): - # Both CRLF and LF should be accepted as separators. CR should not be - # part of the data when followed by LF, but it is a normal char - # otherwise (or should bare CR be an error?) - headers = HTTPHeaders.parse("CRLF: crlf\r\nLF: lf\nCR: cr\rMore: more\r\n") - self.assertEqual( - sorted(headers.get_all()), - [("Cr", "cr\rMore: more"), ("Crlf", "crlf"), ("Lf", "lf")], - ) - - def test_copy(self): - all_pairs = [("A", "1"), ("A", "2"), ("B", "c")] - h1 = HTTPHeaders() - for k, v in all_pairs: - h1.add(k, v) - h2 = h1.copy() - h3 = copy.copy(h1) - h4 = copy.deepcopy(h1) - for headers in [h1, h2, h3, h4]: - # All the copies are identical, no matter how they were - # constructed. - self.assertEqual(list(sorted(headers.get_all())), all_pairs) - for headers in [h2, h3, h4]: - # Neither the dict or its member lists are reused. - self.assertIsNot(headers, h1) - self.assertIsNot(headers.get_list("A"), h1.get_list("A")) - - def test_pickle_roundtrip(self): - headers = HTTPHeaders() - headers.add("Set-Cookie", "a=b") - headers.add("Set-Cookie", "c=d") - headers.add("Content-Type", "text/html") - pickled = pickle.dumps(headers) - unpickled = pickle.loads(pickled) - self.assertEqual(sorted(headers.get_all()), sorted(unpickled.get_all())) - self.assertEqual(sorted(headers.items()), sorted(unpickled.items())) - - def test_setdefault(self): - headers = HTTPHeaders() - headers["foo"] = "bar" - # If a value is present, setdefault returns it without changes. - self.assertEqual(headers.setdefault("foo", "baz"), "bar") - self.assertEqual(headers["foo"], "bar") - # If a value is not present, setdefault sets it for future use. - self.assertEqual(headers.setdefault("quux", "xyzzy"), "xyzzy") - self.assertEqual(headers["quux"], "xyzzy") - self.assertEqual(sorted(headers.get_all()), [("Foo", "bar"), ("Quux", "xyzzy")]) - - def test_string(self): - headers = HTTPHeaders() - headers.add("Foo", "1") - headers.add("Foo", "2") - headers.add("Foo", "3") - headers2 = HTTPHeaders.parse(str(headers)) - self.assertEqual(headers, headers2) - - -class FormatTimestampTest(unittest.TestCase): - # Make sure that all the input types are supported. - TIMESTAMP = 1359312200.503611 - EXPECTED = "Sun, 27 Jan 2013 18:43:20 GMT" - - def check(self, value): - self.assertEqual(format_timestamp(value), self.EXPECTED) - - def test_unix_time_float(self): - self.check(self.TIMESTAMP) - - def test_unix_time_int(self): - self.check(int(self.TIMESTAMP)) - - def test_struct_time(self): - self.check(time.gmtime(self.TIMESTAMP)) - - def test_time_tuple(self): - tup = tuple(time.gmtime(self.TIMESTAMP)) - self.assertEqual(9, len(tup)) - self.check(tup) - - def test_datetime(self): - self.check(datetime.datetime.utcfromtimestamp(self.TIMESTAMP)) - - -# HTTPServerRequest is mainly tested incidentally to the server itself, -# but this tests the parts of the class that can be tested in isolation. -class HTTPServerRequestTest(unittest.TestCase): - def test_default_constructor(self): - # All parameters are formally optional, but uri is required - # (and has been for some time). This test ensures that no - # more required parameters slip in. - HTTPServerRequest(uri="/") - - def test_body_is_a_byte_string(self): - requets = HTTPServerRequest(uri="/") - self.assertIsInstance(requets.body, bytes) - - def test_repr_does_not_contain_headers(self): - request = HTTPServerRequest( - uri="/", headers=HTTPHeaders({"Canary": ["Coal Mine"]}) - ) - self.assertTrue("Canary" not in repr(request)) - - -class ParseRequestStartLineTest(unittest.TestCase): - METHOD = "GET" - PATH = "/foo" - VERSION = "HTTP/1.1" - - def test_parse_request_start_line(self): - start_line = " ".join([self.METHOD, self.PATH, self.VERSION]) - parsed_start_line = parse_request_start_line(start_line) - self.assertEqual(parsed_start_line.method, self.METHOD) - self.assertEqual(parsed_start_line.path, self.PATH) - self.assertEqual(parsed_start_line.version, self.VERSION) - - -class ParseCookieTest(unittest.TestCase): - # These tests copied from Django: - # https://github.com/django/django/pull/6277/commits/da810901ada1cae9fc1f018f879f11a7fb467b28 - def test_python_cookies(self): - """ - Test cases copied from Python's Lib/test/test_http_cookies.py - """ - self.assertEqual( - parse_cookie("chips=ahoy; vienna=finger"), - {"chips": "ahoy", "vienna": "finger"}, - ) - # Here parse_cookie() differs from Python's cookie parsing in that it - # treats all semicolons as delimiters, even within quotes. - self.assertEqual( - parse_cookie('keebler="E=mc2; L=\\"Loves\\"; fudge=\\012;"'), - {"keebler": '"E=mc2', "L": '\\"Loves\\"', "fudge": "\\012", "": '"'}, - ) - # Illegal cookies that have an '=' char in an unquoted value. - self.assertEqual(parse_cookie("keebler=E=mc2"), {"keebler": "E=mc2"}) - # Cookies with ':' character in their name. - self.assertEqual( - parse_cookie("key:term=value:term"), {"key:term": "value:term"} - ) - # Cookies with '[' and ']'. - self.assertEqual( - parse_cookie("a=b; c=[; d=r; f=h"), {"a": "b", "c": "[", "d": "r", "f": "h"} - ) - - def test_cookie_edgecases(self): - # Cookies that RFC6265 allows. - self.assertEqual( - parse_cookie("a=b; Domain=example.com"), {"a": "b", "Domain": "example.com"} - ) - # parse_cookie() has historically kept only the last cookie with the - # same name. - self.assertEqual(parse_cookie("a=b; h=i; a=c"), {"a": "c", "h": "i"}) - - def test_invalid_cookies(self): - """ - Cookie strings that go against RFC6265 but browsers will send if set - via document.cookie. - """ - # Chunks without an equals sign appear as unnamed values per - # https://bugzilla.mozilla.org/show_bug.cgi?id=169091 - self.assertIn( - "django_language", - parse_cookie("abc=def; unnamed; django_language=en").keys(), - ) - # Even a double quote may be an unamed value. - self.assertEqual(parse_cookie('a=b; "; c=d'), {"a": "b", "": '"', "c": "d"}) - # Spaces in names and values, and an equals sign in values. - self.assertEqual( - parse_cookie("a b c=d e = f; gh=i"), {"a b c": "d e = f", "gh": "i"} - ) - # More characters the spec forbids. - self.assertEqual( - parse_cookie('a b,c<>@:/[]?{}=d " =e,f g'), - {"a b,c<>@:/[]?{}": 'd " =e,f g'}, - ) - # Unicode characters. The spec only allows ASCII. - self.assertEqual( - parse_cookie("saint=André Bessette"), - {"saint": native_str("André Bessette")}, - ) - # Browsers don't send extra whitespace or semicolons in Cookie headers, - # but parse_cookie() should parse whitespace the same way - # document.cookie parses whitespace. - self.assertEqual( - parse_cookie(" = b ; ; = ; c = ; "), {"": "b", "c": ""} - ) diff --git a/venv/lib/python3.8/site-packages/tornado/test/import_test.py b/venv/lib/python3.8/site-packages/tornado/test/import_test.py deleted file mode 100644 index 23450fb..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/import_test.py +++ /dev/null @@ -1,66 +0,0 @@ -# flake8: noqa -import subprocess -import sys -import unittest - -_import_everything = b""" -# The event loop is not fork-safe, and it's easy to initialize an asyncio.Future -# at startup, which in turn creates the default event loop and prevents forking. -# Explicitly disallow the default event loop so that an error will be raised -# if something tries to touch it. -import asyncio -asyncio.set_event_loop(None) - -import tornado.auth -import tornado.autoreload -import tornado.concurrent -import tornado.escape -import tornado.gen -import tornado.http1connection -import tornado.httpclient -import tornado.httpserver -import tornado.httputil -import tornado.ioloop -import tornado.iostream -import tornado.locale -import tornado.log -import tornado.netutil -import tornado.options -import tornado.process -import tornado.simple_httpclient -import tornado.tcpserver -import tornado.tcpclient -import tornado.template -import tornado.testing -import tornado.util -import tornado.web -import tornado.websocket -import tornado.wsgi - -try: - import pycurl -except ImportError: - pass -else: - import tornado.curl_httpclient -""" - - -class ImportTest(unittest.TestCase): - def test_import_everything(self): - # Test that all Tornado modules can be imported without side effects, - # specifically without initializing the default asyncio event loop. - # Since we can't tell which modules may have already beein imported - # in our process, do it in a subprocess for a clean slate. - proc = subprocess.Popen([sys.executable], stdin=subprocess.PIPE) - proc.communicate(_import_everything) - self.assertEqual(proc.returncode, 0) - - def test_import_aliases(self): - # Ensure we don't delete formerly-documented aliases accidentally. - import tornado.ioloop - import tornado.gen - import tornado.util - - self.assertIs(tornado.ioloop.TimeoutError, tornado.util.TimeoutError) - self.assertIs(tornado.gen.TimeoutError, tornado.util.TimeoutError) diff --git a/venv/lib/python3.8/site-packages/tornado/test/ioloop_test.py b/venv/lib/python3.8/site-packages/tornado/test/ioloop_test.py deleted file mode 100644 index 16848b3..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/ioloop_test.py +++ /dev/null @@ -1,725 +0,0 @@ -from concurrent.futures import ThreadPoolExecutor -from concurrent import futures -import contextlib -import datetime -import functools -import socket -import subprocess -import sys -import threading -import time -import types -from unittest import mock -import unittest - -from tornado.escape import native_str -from tornado import gen -from tornado.ioloop import IOLoop, TimeoutError, PeriodicCallback -from tornado.log import app_log -from tornado.testing import AsyncTestCase, bind_unused_port, ExpectLog, gen_test -from tornado.test.util import skipIfNonUnix, skipOnTravis - -import typing - -if typing.TYPE_CHECKING: - from typing import List # noqa: F401 - - -class TestIOLoop(AsyncTestCase): - def test_add_callback_return_sequence(self): - # A callback returning {} or [] shouldn't spin the CPU, see Issue #1803. - self.calls = 0 - - loop = self.io_loop - test = self - old_add_callback = loop.add_callback - - def add_callback(self, callback, *args, **kwargs): - test.calls += 1 - old_add_callback(callback, *args, **kwargs) - - loop.add_callback = types.MethodType(add_callback, loop) # type: ignore - loop.add_callback(lambda: {}) # type: ignore - loop.add_callback(lambda: []) # type: ignore - loop.add_timeout(datetime.timedelta(milliseconds=50), loop.stop) - loop.start() - self.assertLess(self.calls, 10) - - @skipOnTravis - def test_add_callback_wakeup(self): - # Make sure that add_callback from inside a running IOLoop - # wakes up the IOLoop immediately instead of waiting for a timeout. - def callback(): - self.called = True - self.stop() - - def schedule_callback(): - self.called = False - self.io_loop.add_callback(callback) - # Store away the time so we can check if we woke up immediately - self.start_time = time.time() - - self.io_loop.add_timeout(self.io_loop.time(), schedule_callback) - self.wait() - self.assertAlmostEqual(time.time(), self.start_time, places=2) - self.assertTrue(self.called) - - @skipOnTravis - def test_add_callback_wakeup_other_thread(self): - def target(): - # sleep a bit to let the ioloop go into its poll loop - time.sleep(0.01) - self.stop_time = time.time() - self.io_loop.add_callback(self.stop) - - thread = threading.Thread(target=target) - self.io_loop.add_callback(thread.start) - self.wait() - delta = time.time() - self.stop_time - self.assertLess(delta, 0.1) - thread.join() - - def test_add_timeout_timedelta(self): - self.io_loop.add_timeout(datetime.timedelta(microseconds=1), self.stop) - self.wait() - - def test_multiple_add(self): - sock, port = bind_unused_port() - try: - self.io_loop.add_handler( - sock.fileno(), lambda fd, events: None, IOLoop.READ - ) - # Attempting to add the same handler twice fails - # (with a platform-dependent exception) - self.assertRaises( - Exception, - self.io_loop.add_handler, - sock.fileno(), - lambda fd, events: None, - IOLoop.READ, - ) - finally: - self.io_loop.remove_handler(sock.fileno()) - sock.close() - - def test_remove_without_add(self): - # remove_handler should not throw an exception if called on an fd - # was never added. - sock, port = bind_unused_port() - try: - self.io_loop.remove_handler(sock.fileno()) - finally: - sock.close() - - def test_add_callback_from_signal(self): - # cheat a little bit and just run this normally, since we can't - # easily simulate the races that happen with real signal handlers - self.io_loop.add_callback_from_signal(self.stop) - self.wait() - - def test_add_callback_from_signal_other_thread(self): - # Very crude test, just to make sure that we cover this case. - # This also happens to be the first test where we run an IOLoop in - # a non-main thread. - other_ioloop = IOLoop() - thread = threading.Thread(target=other_ioloop.start) - thread.start() - other_ioloop.add_callback_from_signal(other_ioloop.stop) - thread.join() - other_ioloop.close() - - def test_add_callback_while_closing(self): - # add_callback should not fail if it races with another thread - # closing the IOLoop. The callbacks are dropped silently - # without executing. - closing = threading.Event() - - def target(): - other_ioloop.add_callback(other_ioloop.stop) - other_ioloop.start() - closing.set() - other_ioloop.close(all_fds=True) - - other_ioloop = IOLoop() - thread = threading.Thread(target=target) - thread.start() - closing.wait() - for i in range(1000): - other_ioloop.add_callback(lambda: None) - - @skipIfNonUnix # just because socketpair is so convenient - def test_read_while_writeable(self): - # Ensure that write events don't come in while we're waiting for - # a read and haven't asked for writeability. (the reverse is - # difficult to test for) - client, server = socket.socketpair() - try: - - def handler(fd, events): - self.assertEqual(events, IOLoop.READ) - self.stop() - - self.io_loop.add_handler(client.fileno(), handler, IOLoop.READ) - self.io_loop.add_timeout( - self.io_loop.time() + 0.01, functools.partial(server.send, b"asdf") # type: ignore - ) - self.wait() - self.io_loop.remove_handler(client.fileno()) - finally: - client.close() - server.close() - - def test_remove_timeout_after_fire(self): - # It is not an error to call remove_timeout after it has run. - handle = self.io_loop.add_timeout(self.io_loop.time(), self.stop) - self.wait() - self.io_loop.remove_timeout(handle) - - def test_remove_timeout_cleanup(self): - # Add and remove enough callbacks to trigger cleanup. - # Not a very thorough test, but it ensures that the cleanup code - # gets executed and doesn't blow up. This test is only really useful - # on PollIOLoop subclasses, but it should run silently on any - # implementation. - for i in range(2000): - timeout = self.io_loop.add_timeout(self.io_loop.time() + 3600, lambda: None) - self.io_loop.remove_timeout(timeout) - # HACK: wait two IOLoop iterations for the GC to happen. - self.io_loop.add_callback(lambda: self.io_loop.add_callback(self.stop)) - self.wait() - - def test_remove_timeout_from_timeout(self): - calls = [False, False] - - # Schedule several callbacks and wait for them all to come due at once. - # t2 should be cancelled by t1, even though it is already scheduled to - # be run before the ioloop even looks at it. - now = self.io_loop.time() - - def t1(): - calls[0] = True - self.io_loop.remove_timeout(t2_handle) - - self.io_loop.add_timeout(now + 0.01, t1) - - def t2(): - calls[1] = True - - t2_handle = self.io_loop.add_timeout(now + 0.02, t2) - self.io_loop.add_timeout(now + 0.03, self.stop) - time.sleep(0.03) - self.wait() - self.assertEqual(calls, [True, False]) - - def test_timeout_with_arguments(self): - # This tests that all the timeout methods pass through *args correctly. - results = [] # type: List[int] - self.io_loop.add_timeout(self.io_loop.time(), results.append, 1) - self.io_loop.add_timeout(datetime.timedelta(seconds=0), results.append, 2) - self.io_loop.call_at(self.io_loop.time(), results.append, 3) - self.io_loop.call_later(0, results.append, 4) - self.io_loop.call_later(0, self.stop) - self.wait() - # The asyncio event loop does not guarantee the order of these - # callbacks. - self.assertEqual(sorted(results), [1, 2, 3, 4]) - - def test_add_timeout_return(self): - # All the timeout methods return non-None handles that can be - # passed to remove_timeout. - handle = self.io_loop.add_timeout(self.io_loop.time(), lambda: None) - self.assertFalse(handle is None) - self.io_loop.remove_timeout(handle) - - def test_call_at_return(self): - handle = self.io_loop.call_at(self.io_loop.time(), lambda: None) - self.assertFalse(handle is None) - self.io_loop.remove_timeout(handle) - - def test_call_later_return(self): - handle = self.io_loop.call_later(0, lambda: None) - self.assertFalse(handle is None) - self.io_loop.remove_timeout(handle) - - def test_close_file_object(self): - """When a file object is used instead of a numeric file descriptor, - the object should be closed (by IOLoop.close(all_fds=True), - not just the fd. - """ - # Use a socket since they are supported by IOLoop on all platforms. - # Unfortunately, sockets don't support the .closed attribute for - # inspecting their close status, so we must use a wrapper. - class SocketWrapper(object): - def __init__(self, sockobj): - self.sockobj = sockobj - self.closed = False - - def fileno(self): - return self.sockobj.fileno() - - def close(self): - self.closed = True - self.sockobj.close() - - sockobj, port = bind_unused_port() - socket_wrapper = SocketWrapper(sockobj) - io_loop = IOLoop() - io_loop.add_handler(socket_wrapper, lambda fd, events: None, IOLoop.READ) - io_loop.close(all_fds=True) - self.assertTrue(socket_wrapper.closed) - - def test_handler_callback_file_object(self): - """The handler callback receives the same fd object it passed in.""" - server_sock, port = bind_unused_port() - fds = [] - - def handle_connection(fd, events): - fds.append(fd) - conn, addr = server_sock.accept() - conn.close() - self.stop() - - self.io_loop.add_handler(server_sock, handle_connection, IOLoop.READ) - with contextlib.closing(socket.socket()) as client_sock: - client_sock.connect(("127.0.0.1", port)) - self.wait() - self.io_loop.remove_handler(server_sock) - self.io_loop.add_handler(server_sock.fileno(), handle_connection, IOLoop.READ) - with contextlib.closing(socket.socket()) as client_sock: - client_sock.connect(("127.0.0.1", port)) - self.wait() - self.assertIs(fds[0], server_sock) - self.assertEqual(fds[1], server_sock.fileno()) - self.io_loop.remove_handler(server_sock.fileno()) - server_sock.close() - - def test_mixed_fd_fileobj(self): - server_sock, port = bind_unused_port() - - def f(fd, events): - pass - - self.io_loop.add_handler(server_sock, f, IOLoop.READ) - with self.assertRaises(Exception): - # The exact error is unspecified - some implementations use - # IOError, others use ValueError. - self.io_loop.add_handler(server_sock.fileno(), f, IOLoop.READ) - self.io_loop.remove_handler(server_sock.fileno()) - server_sock.close() - - def test_reentrant(self): - """Calling start() twice should raise an error, not deadlock.""" - returned_from_start = [False] - got_exception = [False] - - def callback(): - try: - self.io_loop.start() - returned_from_start[0] = True - except Exception: - got_exception[0] = True - self.stop() - - self.io_loop.add_callback(callback) - self.wait() - self.assertTrue(got_exception[0]) - self.assertFalse(returned_from_start[0]) - - def test_exception_logging(self): - """Uncaught exceptions get logged by the IOLoop.""" - self.io_loop.add_callback(lambda: 1 / 0) - self.io_loop.add_callback(self.stop) - with ExpectLog(app_log, "Exception in callback"): - self.wait() - - def test_exception_logging_future(self): - """The IOLoop examines exceptions from Futures and logs them.""" - - @gen.coroutine - def callback(): - self.io_loop.add_callback(self.stop) - 1 / 0 - - self.io_loop.add_callback(callback) - with ExpectLog(app_log, "Exception in callback"): - self.wait() - - def test_exception_logging_native_coro(self): - """The IOLoop examines exceptions from awaitables and logs them.""" - - async def callback(): - # Stop the IOLoop two iterations after raising an exception - # to give the exception time to be logged. - self.io_loop.add_callback(self.io_loop.add_callback, self.stop) - 1 / 0 - - self.io_loop.add_callback(callback) - with ExpectLog(app_log, "Exception in callback"): - self.wait() - - def test_spawn_callback(self): - # Both add_callback and spawn_callback run directly on the IOLoop, - # so their errors are logged without stopping the test. - self.io_loop.add_callback(lambda: 1 / 0) - self.io_loop.add_callback(self.stop) - with ExpectLog(app_log, "Exception in callback"): - self.wait() - # A spawned callback is run directly on the IOLoop, so it will be - # logged without stopping the test. - self.io_loop.spawn_callback(lambda: 1 / 0) - self.io_loop.add_callback(self.stop) - with ExpectLog(app_log, "Exception in callback"): - self.wait() - - @skipIfNonUnix - def test_remove_handler_from_handler(self): - # Create two sockets with simultaneous read events. - client, server = socket.socketpair() - try: - client.send(b"abc") - server.send(b"abc") - - # After reading from one fd, remove the other from the IOLoop. - chunks = [] - - def handle_read(fd, events): - chunks.append(fd.recv(1024)) - if fd is client: - self.io_loop.remove_handler(server) - else: - self.io_loop.remove_handler(client) - - self.io_loop.add_handler(client, handle_read, self.io_loop.READ) - self.io_loop.add_handler(server, handle_read, self.io_loop.READ) - self.io_loop.call_later(0.1, self.stop) - self.wait() - - # Only one fd was read; the other was cleanly removed. - self.assertEqual(chunks, [b"abc"]) - finally: - client.close() - server.close() - - @skipIfNonUnix - @gen_test - def test_init_close_race(self): - # Regression test for #2367 - # - # Skipped on windows because of what looks like a bug in the - # proactor event loop when started and stopped on non-main - # threads. - def f(): - for i in range(10): - loop = IOLoop() - loop.close() - - yield gen.multi([self.io_loop.run_in_executor(None, f) for i in range(2)]) - - -# Deliberately not a subclass of AsyncTestCase so the IOLoop isn't -# automatically set as current. -class TestIOLoopCurrent(unittest.TestCase): - def setUp(self): - self.io_loop = None # type: typing.Optional[IOLoop] - IOLoop.clear_current() - - def tearDown(self): - if self.io_loop is not None: - self.io_loop.close() - - def test_default_current(self): - self.io_loop = IOLoop() - # The first IOLoop with default arguments is made current. - self.assertIs(self.io_loop, IOLoop.current()) - # A second IOLoop can be created but is not made current. - io_loop2 = IOLoop() - self.assertIs(self.io_loop, IOLoop.current()) - io_loop2.close() - - def test_non_current(self): - self.io_loop = IOLoop(make_current=False) - # The new IOLoop is not initially made current. - self.assertIsNone(IOLoop.current(instance=False)) - # Starting the IOLoop makes it current, and stopping the loop - # makes it non-current. This process is repeatable. - for i in range(3): - - def f(): - self.current_io_loop = IOLoop.current() - assert self.io_loop is not None - self.io_loop.stop() - - self.io_loop.add_callback(f) - self.io_loop.start() - self.assertIs(self.current_io_loop, self.io_loop) - # Now that the loop is stopped, it is no longer current. - self.assertIsNone(IOLoop.current(instance=False)) - - def test_force_current(self): - self.io_loop = IOLoop(make_current=True) - self.assertIs(self.io_loop, IOLoop.current()) - with self.assertRaises(RuntimeError): - # A second make_current=True construction cannot succeed. - IOLoop(make_current=True) - # current() was not affected by the failed construction. - self.assertIs(self.io_loop, IOLoop.current()) - - -class TestIOLoopCurrentAsync(AsyncTestCase): - @gen_test - def test_clear_without_current(self): - # If there is no current IOLoop, clear_current is a no-op (but - # should not fail). Use a thread so we see the threading.Local - # in a pristine state. - with ThreadPoolExecutor(1) as e: - yield e.submit(IOLoop.clear_current) - - -class TestIOLoopFutures(AsyncTestCase): - def test_add_future_threads(self): - with futures.ThreadPoolExecutor(1) as pool: - - def dummy(): - pass - - self.io_loop.add_future( - pool.submit(dummy), lambda future: self.stop(future) - ) - future = self.wait() - self.assertTrue(future.done()) - self.assertTrue(future.result() is None) - - @gen_test - def test_run_in_executor_gen(self): - event1 = threading.Event() - event2 = threading.Event() - - def sync_func(self_event, other_event): - self_event.set() - other_event.wait() - # Note that return value doesn't actually do anything, - # it is just passed through to our final assertion to - # make sure it is passed through properly. - return self_event - - # Run two synchronous functions, which would deadlock if not - # run in parallel. - res = yield [ - IOLoop.current().run_in_executor(None, sync_func, event1, event2), - IOLoop.current().run_in_executor(None, sync_func, event2, event1), - ] - - self.assertEqual([event1, event2], res) - - @gen_test - def test_run_in_executor_native(self): - event1 = threading.Event() - event2 = threading.Event() - - def sync_func(self_event, other_event): - self_event.set() - other_event.wait() - return self_event - - # Go through an async wrapper to ensure that the result of - # run_in_executor works with await and not just gen.coroutine - # (simply passing the underlying concurrent future would do that). - async def async_wrapper(self_event, other_event): - return await IOLoop.current().run_in_executor( - None, sync_func, self_event, other_event - ) - - res = yield [async_wrapper(event1, event2), async_wrapper(event2, event1)] - - self.assertEqual([event1, event2], res) - - @gen_test - def test_set_default_executor(self): - count = [0] - - class MyExecutor(futures.ThreadPoolExecutor): - def submit(self, func, *args): - count[0] += 1 - return super().submit(func, *args) - - event = threading.Event() - - def sync_func(): - event.set() - - executor = MyExecutor(1) - loop = IOLoop.current() - loop.set_default_executor(executor) - yield loop.run_in_executor(None, sync_func) - self.assertEqual(1, count[0]) - self.assertTrue(event.is_set()) - - -class TestIOLoopRunSync(unittest.TestCase): - def setUp(self): - self.io_loop = IOLoop() - - def tearDown(self): - self.io_loop.close() - - def test_sync_result(self): - with self.assertRaises(gen.BadYieldError): - self.io_loop.run_sync(lambda: 42) - - def test_sync_exception(self): - with self.assertRaises(ZeroDivisionError): - self.io_loop.run_sync(lambda: 1 / 0) - - def test_async_result(self): - @gen.coroutine - def f(): - yield gen.moment - raise gen.Return(42) - - self.assertEqual(self.io_loop.run_sync(f), 42) - - def test_async_exception(self): - @gen.coroutine - def f(): - yield gen.moment - 1 / 0 - - with self.assertRaises(ZeroDivisionError): - self.io_loop.run_sync(f) - - def test_current(self): - def f(): - self.assertIs(IOLoop.current(), self.io_loop) - - self.io_loop.run_sync(f) - - def test_timeout(self): - @gen.coroutine - def f(): - yield gen.sleep(1) - - self.assertRaises(TimeoutError, self.io_loop.run_sync, f, timeout=0.01) - - def test_native_coroutine(self): - @gen.coroutine - def f1(): - yield gen.moment - - async def f2(): - await f1() - - self.io_loop.run_sync(f2) - - -class TestPeriodicCallbackMath(unittest.TestCase): - def simulate_calls(self, pc, durations): - """Simulate a series of calls to the PeriodicCallback. - - Pass a list of call durations in seconds (negative values - work to simulate clock adjustments during the call, or more or - less equivalently, between calls). This method returns the - times at which each call would be made. - """ - calls = [] - now = 1000 - pc._next_timeout = now - for d in durations: - pc._update_next(now) - calls.append(pc._next_timeout) - now = pc._next_timeout + d - return calls - - def dummy(self): - pass - - def test_basic(self): - pc = PeriodicCallback(self.dummy, 10000) - self.assertEqual( - self.simulate_calls(pc, [0] * 5), [1010, 1020, 1030, 1040, 1050] - ) - - def test_overrun(self): - # If a call runs for too long, we skip entire cycles to get - # back on schedule. - call_durations = [9, 9, 10, 11, 20, 20, 35, 35, 0, 0, 0] - expected = [ - 1010, - 1020, - 1030, # first 3 calls on schedule - 1050, - 1070, # next 2 delayed one cycle - 1100, - 1130, # next 2 delayed 2 cycles - 1170, - 1210, # next 2 delayed 3 cycles - 1220, - 1230, # then back on schedule. - ] - - pc = PeriodicCallback(self.dummy, 10000) - self.assertEqual(self.simulate_calls(pc, call_durations), expected) - - def test_clock_backwards(self): - pc = PeriodicCallback(self.dummy, 10000) - # Backwards jumps are ignored, potentially resulting in a - # slightly slow schedule (although we assume that when - # time.time() and time.monotonic() are different, time.time() - # is getting adjusted by NTP and is therefore more accurate) - self.assertEqual( - self.simulate_calls(pc, [-2, -1, -3, -2, 0]), [1010, 1020, 1030, 1040, 1050] - ) - - # For big jumps, we should perhaps alter the schedule, but we - # don't currently. This trace shows that we run callbacks - # every 10s of time.time(), but the first and second calls are - # 110s of real time apart because the backwards jump is - # ignored. - self.assertEqual(self.simulate_calls(pc, [-100, 0, 0]), [1010, 1020, 1030]) - - def test_jitter(self): - random_times = [0.5, 1, 0, 0.75] - expected = [1010, 1022.5, 1030, 1041.25] - call_durations = [0] * len(random_times) - pc = PeriodicCallback(self.dummy, 10000, jitter=0.5) - - def mock_random(): - return random_times.pop(0) - - with mock.patch("random.random", mock_random): - self.assertEqual(self.simulate_calls(pc, call_durations), expected) - - -class TestIOLoopConfiguration(unittest.TestCase): - def run_python(self, *statements): - stmt_list = [ - "from tornado.ioloop import IOLoop", - "classname = lambda x: x.__class__.__name__", - ] + list(statements) - args = [sys.executable, "-c", "; ".join(stmt_list)] - return native_str(subprocess.check_output(args)).strip() - - def test_default(self): - # When asyncio is available, it is used by default. - cls = self.run_python("print(classname(IOLoop.current()))") - self.assertEqual(cls, "AsyncIOMainLoop") - cls = self.run_python("print(classname(IOLoop()))") - self.assertEqual(cls, "AsyncIOLoop") - - def test_asyncio(self): - cls = self.run_python( - 'IOLoop.configure("tornado.platform.asyncio.AsyncIOLoop")', - "print(classname(IOLoop.current()))", - ) - self.assertEqual(cls, "AsyncIOMainLoop") - - def test_asyncio_main(self): - cls = self.run_python( - "from tornado.platform.asyncio import AsyncIOMainLoop", - "AsyncIOMainLoop().install()", - "print(classname(IOLoop.current()))", - ) - self.assertEqual(cls, "AsyncIOMainLoop") - - -if __name__ == "__main__": - unittest.main() diff --git a/venv/lib/python3.8/site-packages/tornado/test/iostream_test.py b/venv/lib/python3.8/site-packages/tornado/test/iostream_test.py deleted file mode 100644 index a43aa64..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/iostream_test.py +++ /dev/null @@ -1,1282 +0,0 @@ -from tornado.concurrent import Future -from tornado import gen -from tornado import netutil -from tornado.ioloop import IOLoop -from tornado.iostream import ( - IOStream, - SSLIOStream, - PipeIOStream, - StreamClosedError, - _StreamBuffer, -) -from tornado.httputil import HTTPHeaders -from tornado.locks import Condition, Event -from tornado.log import gen_log -from tornado.netutil import ssl_wrap_socket -from tornado.platform.asyncio import AddThreadSelectorEventLoop -from tornado.tcpserver import TCPServer -from tornado.testing import ( - AsyncHTTPTestCase, - AsyncHTTPSTestCase, - AsyncTestCase, - bind_unused_port, - ExpectLog, - gen_test, -) -from tornado.test.util import skipIfNonUnix, refusing_port, skipPypy3V58 -from tornado.web import RequestHandler, Application -import asyncio -import errno -import hashlib -import logging -import os -import platform -import random -import socket -import ssl -import typing -from unittest import mock -import unittest - - -def _server_ssl_options(): - return dict( - certfile=os.path.join(os.path.dirname(__file__), "test.crt"), - keyfile=os.path.join(os.path.dirname(__file__), "test.key"), - ) - - -class HelloHandler(RequestHandler): - def get(self): - self.write("Hello") - - -class TestIOStreamWebMixin(object): - def _make_client_iostream(self): - raise NotImplementedError() - - def get_app(self): - return Application([("/", HelloHandler)]) - - def test_connection_closed(self: typing.Any): - # When a server sends a response and then closes the connection, - # the client must be allowed to read the data before the IOStream - # closes itself. Epoll reports closed connections with a separate - # EPOLLRDHUP event delivered at the same time as the read event, - # while kqueue reports them as a second read/write event with an EOF - # flag. - response = self.fetch("/", headers={"Connection": "close"}) - response.rethrow() - - @gen_test - def test_read_until_close(self: typing.Any): - stream = self._make_client_iostream() - yield stream.connect(("127.0.0.1", self.get_http_port())) - stream.write(b"GET / HTTP/1.0\r\n\r\n") - - data = yield stream.read_until_close() - self.assertTrue(data.startswith(b"HTTP/1.1 200")) - self.assertTrue(data.endswith(b"Hello")) - - @gen_test - def test_read_zero_bytes(self: typing.Any): - self.stream = self._make_client_iostream() - yield self.stream.connect(("127.0.0.1", self.get_http_port())) - self.stream.write(b"GET / HTTP/1.0\r\n\r\n") - - # normal read - data = yield self.stream.read_bytes(9) - self.assertEqual(data, b"HTTP/1.1 ") - - # zero bytes - data = yield self.stream.read_bytes(0) - self.assertEqual(data, b"") - - # another normal read - data = yield self.stream.read_bytes(3) - self.assertEqual(data, b"200") - - self.stream.close() - - @gen_test - def test_write_while_connecting(self: typing.Any): - stream = self._make_client_iostream() - connect_fut = stream.connect(("127.0.0.1", self.get_http_port())) - # unlike the previous tests, try to write before the connection - # is complete. - write_fut = stream.write(b"GET / HTTP/1.0\r\nConnection: close\r\n\r\n") - self.assertFalse(connect_fut.done()) - - # connect will always complete before write. - it = gen.WaitIterator(connect_fut, write_fut) - resolved_order = [] - while not it.done(): - yield it.next() - resolved_order.append(it.current_future) - self.assertEqual(resolved_order, [connect_fut, write_fut]) - - data = yield stream.read_until_close() - self.assertTrue(data.endswith(b"Hello")) - - stream.close() - - @gen_test - def test_future_interface(self: typing.Any): - """Basic test of IOStream's ability to return Futures.""" - stream = self._make_client_iostream() - connect_result = yield stream.connect(("127.0.0.1", self.get_http_port())) - self.assertIs(connect_result, stream) - yield stream.write(b"GET / HTTP/1.0\r\n\r\n") - first_line = yield stream.read_until(b"\r\n") - self.assertEqual(first_line, b"HTTP/1.1 200 OK\r\n") - # callback=None is equivalent to no callback. - header_data = yield stream.read_until(b"\r\n\r\n") - headers = HTTPHeaders.parse(header_data.decode("latin1")) - content_length = int(headers["Content-Length"]) - body = yield stream.read_bytes(content_length) - self.assertEqual(body, b"Hello") - stream.close() - - @gen_test - def test_future_close_while_reading(self: typing.Any): - stream = self._make_client_iostream() - yield stream.connect(("127.0.0.1", self.get_http_port())) - yield stream.write(b"GET / HTTP/1.0\r\n\r\n") - with self.assertRaises(StreamClosedError): - yield stream.read_bytes(1024 * 1024) - stream.close() - - @gen_test - def test_future_read_until_close(self: typing.Any): - # Ensure that the data comes through before the StreamClosedError. - stream = self._make_client_iostream() - yield stream.connect(("127.0.0.1", self.get_http_port())) - yield stream.write(b"GET / HTTP/1.0\r\nConnection: close\r\n\r\n") - yield stream.read_until(b"\r\n\r\n") - body = yield stream.read_until_close() - self.assertEqual(body, b"Hello") - - # Nothing else to read; the error comes immediately without waiting - # for yield. - with self.assertRaises(StreamClosedError): - stream.read_bytes(1) - - -class TestReadWriteMixin(object): - # Tests where one stream reads and the other writes. - # These should work for BaseIOStream implementations. - - def make_iostream_pair(self, **kwargs): - raise NotImplementedError - - def iostream_pair(self, **kwargs): - """Like make_iostream_pair, but called by ``async with``. - - In py37 this becomes simpler with contextlib.asynccontextmanager. - """ - - class IOStreamPairContext: - def __init__(self, test, kwargs): - self.test = test - self.kwargs = kwargs - - async def __aenter__(self): - self.pair = await self.test.make_iostream_pair(**self.kwargs) - return self.pair - - async def __aexit__(self, typ, value, tb): - for s in self.pair: - s.close() - - return IOStreamPairContext(self, kwargs) - - @gen_test - def test_write_zero_bytes(self): - # Attempting to write zero bytes should run the callback without - # going into an infinite loop. - rs, ws = yield self.make_iostream_pair() - yield ws.write(b"") - ws.close() - rs.close() - - @gen_test - def test_future_delayed_close_callback(self: typing.Any): - # Same as test_delayed_close_callback, but with the future interface. - rs, ws = yield self.make_iostream_pair() - - try: - ws.write(b"12") - chunks = [] - chunks.append((yield rs.read_bytes(1))) - ws.close() - chunks.append((yield rs.read_bytes(1))) - self.assertEqual(chunks, [b"1", b"2"]) - finally: - ws.close() - rs.close() - - @gen_test - def test_close_buffered_data(self: typing.Any): - # Similar to the previous test, but with data stored in the OS's - # socket buffers instead of the IOStream's read buffer. Out-of-band - # close notifications must be delayed until all data has been - # drained into the IOStream buffer. (epoll used to use out-of-band - # close events with EPOLLRDHUP, but no longer) - # - # This depends on the read_chunk_size being smaller than the - # OS socket buffer, so make it small. - rs, ws = yield self.make_iostream_pair(read_chunk_size=256) - try: - ws.write(b"A" * 512) - data = yield rs.read_bytes(256) - self.assertEqual(b"A" * 256, data) - ws.close() - # Allow the close to propagate to the `rs` side of the - # connection. Using add_callback instead of add_timeout - # doesn't seem to work, even with multiple iterations - yield gen.sleep(0.01) - data = yield rs.read_bytes(256) - self.assertEqual(b"A" * 256, data) - finally: - ws.close() - rs.close() - - @gen_test - def test_read_until_close_after_close(self: typing.Any): - # Similar to test_delayed_close_callback, but read_until_close takes - # a separate code path so test it separately. - rs, ws = yield self.make_iostream_pair() - try: - ws.write(b"1234") - # Read one byte to make sure the client has received the data. - # It won't run the close callback as long as there is more buffered - # data that could satisfy a later read. - data = yield rs.read_bytes(1) - ws.close() - self.assertEqual(data, b"1") - data = yield rs.read_until_close() - self.assertEqual(data, b"234") - finally: - ws.close() - rs.close() - - @gen_test - def test_large_read_until(self: typing.Any): - # Performance test: read_until used to have a quadratic component - # so a read_until of 4MB would take 8 seconds; now it takes 0.25 - # seconds. - rs, ws = yield self.make_iostream_pair() - try: - # This test fails on pypy with ssl. I think it's because - # pypy's gc defeats moves objects, breaking the - # "frozen write buffer" assumption. - if ( - isinstance(rs, SSLIOStream) - and platform.python_implementation() == "PyPy" - ): - raise unittest.SkipTest("pypy gc causes problems with openssl") - NUM_KB = 4096 - for i in range(NUM_KB): - ws.write(b"A" * 1024) - ws.write(b"\r\n") - data = yield rs.read_until(b"\r\n") - self.assertEqual(len(data), NUM_KB * 1024 + 2) - finally: - ws.close() - rs.close() - - @gen_test - async def test_read_until_with_close_after_second_packet(self): - # This is a regression test for a regression in Tornado 6.0 - # (maybe 6.0.3?) reported in - # https://github.com/tornadoweb/tornado/issues/2717 - # - # The data arrives in two chunks; the stream is closed at the - # same time that the second chunk is received. If the second - # chunk is larger than the first, it works, but when this bug - # existed it would fail if the second chunk were smaller than - # the first. This is due to the optimization that the - # read_until condition is only checked when the buffer doubles - # in size - async with self.iostream_pair() as (rs, ws): - rf = asyncio.ensure_future(rs.read_until(b"done")) - # We need to wait for the read_until to actually start. On - # windows that's tricky because the selector runs in - # another thread; sleeping is the simplest way. - await asyncio.sleep(0.1) - await ws.write(b"x" * 2048) - ws.write(b"done") - ws.close() - await rf - - @gen_test - async def test_read_until_unsatisfied_after_close(self: typing.Any): - # If a stream is closed while reading, it raises - # StreamClosedError instead of UnsatisfiableReadError (the - # latter should only be raised when byte limits are reached). - # The particular scenario tested here comes from #2717. - async with self.iostream_pair() as (rs, ws): - rf = asyncio.ensure_future(rs.read_until(b"done")) - await ws.write(b"x" * 2048) - ws.write(b"foo") - ws.close() - with self.assertRaises(StreamClosedError): - await rf - - @gen_test - def test_close_callback_with_pending_read(self: typing.Any): - # Regression test for a bug that was introduced in 2.3 - # where the IOStream._close_callback would never be called - # if there were pending reads. - OK = b"OK\r\n" - rs, ws = yield self.make_iostream_pair() - event = Event() - rs.set_close_callback(event.set) - try: - ws.write(OK) - res = yield rs.read_until(b"\r\n") - self.assertEqual(res, OK) - - ws.close() - rs.read_until(b"\r\n") - # If _close_callback (self.stop) is not called, - # an AssertionError: Async operation timed out after 5 seconds - # will be raised. - yield event.wait() - finally: - ws.close() - rs.close() - - @gen_test - def test_future_close_callback(self: typing.Any): - # Regression test for interaction between the Future read interfaces - # and IOStream._maybe_add_error_listener. - rs, ws = yield self.make_iostream_pair() - closed = [False] - cond = Condition() - - def close_callback(): - closed[0] = True - cond.notify() - - rs.set_close_callback(close_callback) - try: - ws.write(b"a") - res = yield rs.read_bytes(1) - self.assertEqual(res, b"a") - self.assertFalse(closed[0]) - ws.close() - yield cond.wait() - self.assertTrue(closed[0]) - finally: - rs.close() - ws.close() - - @gen_test - def test_write_memoryview(self: typing.Any): - rs, ws = yield self.make_iostream_pair() - try: - fut = rs.read_bytes(4) - ws.write(memoryview(b"hello")) - data = yield fut - self.assertEqual(data, b"hell") - finally: - ws.close() - rs.close() - - @gen_test - def test_read_bytes_partial(self: typing.Any): - rs, ws = yield self.make_iostream_pair() - try: - # Ask for more than is available with partial=True - fut = rs.read_bytes(50, partial=True) - ws.write(b"hello") - data = yield fut - self.assertEqual(data, b"hello") - - # Ask for less than what is available; num_bytes is still - # respected. - fut = rs.read_bytes(3, partial=True) - ws.write(b"world") - data = yield fut - self.assertEqual(data, b"wor") - - # Partial reads won't return an empty string, but read_bytes(0) - # will. - data = yield rs.read_bytes(0, partial=True) - self.assertEqual(data, b"") - finally: - ws.close() - rs.close() - - @gen_test - def test_read_until_max_bytes(self: typing.Any): - rs, ws = yield self.make_iostream_pair() - closed = Event() - rs.set_close_callback(closed.set) - try: - # Extra room under the limit - fut = rs.read_until(b"def", max_bytes=50) - ws.write(b"abcdef") - data = yield fut - self.assertEqual(data, b"abcdef") - - # Just enough space - fut = rs.read_until(b"def", max_bytes=6) - ws.write(b"abcdef") - data = yield fut - self.assertEqual(data, b"abcdef") - - # Not enough space, but we don't know it until all we can do is - # log a warning and close the connection. - with ExpectLog(gen_log, "Unsatisfiable read", level=logging.INFO): - fut = rs.read_until(b"def", max_bytes=5) - ws.write(b"123456") - yield closed.wait() - finally: - ws.close() - rs.close() - - @gen_test - def test_read_until_max_bytes_inline(self: typing.Any): - rs, ws = yield self.make_iostream_pair() - closed = Event() - rs.set_close_callback(closed.set) - try: - # Similar to the error case in the previous test, but the - # ws writes first so rs reads are satisfied - # inline. For consistency with the out-of-line case, we - # do not raise the error synchronously. - ws.write(b"123456") - with ExpectLog(gen_log, "Unsatisfiable read", level=logging.INFO): - with self.assertRaises(StreamClosedError): - yield rs.read_until(b"def", max_bytes=5) - yield closed.wait() - finally: - ws.close() - rs.close() - - @gen_test - def test_read_until_max_bytes_ignores_extra(self: typing.Any): - rs, ws = yield self.make_iostream_pair() - closed = Event() - rs.set_close_callback(closed.set) - try: - # Even though data that matches arrives the same packet that - # puts us over the limit, we fail the request because it was not - # found within the limit. - ws.write(b"abcdef") - with ExpectLog(gen_log, "Unsatisfiable read", level=logging.INFO): - rs.read_until(b"def", max_bytes=5) - yield closed.wait() - finally: - ws.close() - rs.close() - - @gen_test - def test_read_until_regex_max_bytes(self: typing.Any): - rs, ws = yield self.make_iostream_pair() - closed = Event() - rs.set_close_callback(closed.set) - try: - # Extra room under the limit - fut = rs.read_until_regex(b"def", max_bytes=50) - ws.write(b"abcdef") - data = yield fut - self.assertEqual(data, b"abcdef") - - # Just enough space - fut = rs.read_until_regex(b"def", max_bytes=6) - ws.write(b"abcdef") - data = yield fut - self.assertEqual(data, b"abcdef") - - # Not enough space, but we don't know it until all we can do is - # log a warning and close the connection. - with ExpectLog(gen_log, "Unsatisfiable read", level=logging.INFO): - rs.read_until_regex(b"def", max_bytes=5) - ws.write(b"123456") - yield closed.wait() - finally: - ws.close() - rs.close() - - @gen_test - def test_read_until_regex_max_bytes_inline(self: typing.Any): - rs, ws = yield self.make_iostream_pair() - closed = Event() - rs.set_close_callback(closed.set) - try: - # Similar to the error case in the previous test, but the - # ws writes first so rs reads are satisfied - # inline. For consistency with the out-of-line case, we - # do not raise the error synchronously. - ws.write(b"123456") - with ExpectLog(gen_log, "Unsatisfiable read", level=logging.INFO): - rs.read_until_regex(b"def", max_bytes=5) - yield closed.wait() - finally: - ws.close() - rs.close() - - @gen_test - def test_read_until_regex_max_bytes_ignores_extra(self): - rs, ws = yield self.make_iostream_pair() - closed = Event() - rs.set_close_callback(closed.set) - try: - # Even though data that matches arrives the same packet that - # puts us over the limit, we fail the request because it was not - # found within the limit. - ws.write(b"abcdef") - with ExpectLog(gen_log, "Unsatisfiable read", level=logging.INFO): - rs.read_until_regex(b"def", max_bytes=5) - yield closed.wait() - finally: - ws.close() - rs.close() - - @gen_test - def test_small_reads_from_large_buffer(self: typing.Any): - # 10KB buffer size, 100KB available to read. - # Read 1KB at a time and make sure that the buffer is not eagerly - # filled. - rs, ws = yield self.make_iostream_pair(max_buffer_size=10 * 1024) - try: - ws.write(b"a" * 1024 * 100) - for i in range(100): - data = yield rs.read_bytes(1024) - self.assertEqual(data, b"a" * 1024) - finally: - ws.close() - rs.close() - - @gen_test - def test_small_read_untils_from_large_buffer(self: typing.Any): - # 10KB buffer size, 100KB available to read. - # Read 1KB at a time and make sure that the buffer is not eagerly - # filled. - rs, ws = yield self.make_iostream_pair(max_buffer_size=10 * 1024) - try: - ws.write((b"a" * 1023 + b"\n") * 100) - for i in range(100): - data = yield rs.read_until(b"\n", max_bytes=4096) - self.assertEqual(data, b"a" * 1023 + b"\n") - finally: - ws.close() - rs.close() - - @gen_test - def test_flow_control(self): - MB = 1024 * 1024 - rs, ws = yield self.make_iostream_pair(max_buffer_size=5 * MB) - try: - # Client writes more than the rs will accept. - ws.write(b"a" * 10 * MB) - # The rs pauses while reading. - yield rs.read_bytes(MB) - yield gen.sleep(0.1) - # The ws's writes have been blocked; the rs can - # continue to read gradually. - for i in range(9): - yield rs.read_bytes(MB) - finally: - rs.close() - ws.close() - - @gen_test - def test_read_into(self: typing.Any): - rs, ws = yield self.make_iostream_pair() - - def sleep_some(): - self.io_loop.run_sync(lambda: gen.sleep(0.05)) - - try: - buf = bytearray(10) - fut = rs.read_into(buf) - ws.write(b"hello") - yield gen.sleep(0.05) - self.assertTrue(rs.reading()) - ws.write(b"world!!") - data = yield fut - self.assertFalse(rs.reading()) - self.assertEqual(data, 10) - self.assertEqual(bytes(buf), b"helloworld") - - # Existing buffer is fed into user buffer - fut = rs.read_into(buf) - yield gen.sleep(0.05) - self.assertTrue(rs.reading()) - ws.write(b"1234567890") - data = yield fut - self.assertFalse(rs.reading()) - self.assertEqual(data, 10) - self.assertEqual(bytes(buf), b"!!12345678") - - # Existing buffer can satisfy read immediately - buf = bytearray(4) - ws.write(b"abcdefghi") - data = yield rs.read_into(buf) - self.assertEqual(data, 4) - self.assertEqual(bytes(buf), b"90ab") - - data = yield rs.read_bytes(7) - self.assertEqual(data, b"cdefghi") - finally: - ws.close() - rs.close() - - @gen_test - def test_read_into_partial(self: typing.Any): - rs, ws = yield self.make_iostream_pair() - - try: - # Partial read - buf = bytearray(10) - fut = rs.read_into(buf, partial=True) - ws.write(b"hello") - data = yield fut - self.assertFalse(rs.reading()) - self.assertEqual(data, 5) - self.assertEqual(bytes(buf), b"hello\0\0\0\0\0") - - # Full read despite partial=True - ws.write(b"world!1234567890") - data = yield rs.read_into(buf, partial=True) - self.assertEqual(data, 10) - self.assertEqual(bytes(buf), b"world!1234") - - # Existing buffer can satisfy read immediately - data = yield rs.read_into(buf, partial=True) - self.assertEqual(data, 6) - self.assertEqual(bytes(buf), b"5678901234") - - finally: - ws.close() - rs.close() - - @gen_test - def test_read_into_zero_bytes(self: typing.Any): - rs, ws = yield self.make_iostream_pair() - try: - buf = bytearray() - fut = rs.read_into(buf) - self.assertEqual(fut.result(), 0) - finally: - ws.close() - rs.close() - - @gen_test - def test_many_mixed_reads(self): - # Stress buffer handling when going back and forth between - # read_bytes() (using an internal buffer) and read_into() - # (using a user-allocated buffer). - r = random.Random(42) - nbytes = 1000000 - rs, ws = yield self.make_iostream_pair() - - produce_hash = hashlib.sha1() - consume_hash = hashlib.sha1() - - @gen.coroutine - def produce(): - remaining = nbytes - while remaining > 0: - size = r.randint(1, min(1000, remaining)) - data = os.urandom(size) - produce_hash.update(data) - yield ws.write(data) - remaining -= size - assert remaining == 0 - - @gen.coroutine - def consume(): - remaining = nbytes - while remaining > 0: - if r.random() > 0.5: - # read_bytes() - size = r.randint(1, min(1000, remaining)) - data = yield rs.read_bytes(size) - consume_hash.update(data) - remaining -= size - else: - # read_into() - size = r.randint(1, min(1000, remaining)) - buf = bytearray(size) - n = yield rs.read_into(buf) - assert n == size - consume_hash.update(buf) - remaining -= size - assert remaining == 0 - - try: - yield [produce(), consume()] - assert produce_hash.hexdigest() == consume_hash.hexdigest() - finally: - ws.close() - rs.close() - - -class TestIOStreamMixin(TestReadWriteMixin): - def _make_server_iostream(self, connection, **kwargs): - raise NotImplementedError() - - def _make_client_iostream(self, connection, **kwargs): - raise NotImplementedError() - - @gen.coroutine - def make_iostream_pair(self: typing.Any, **kwargs): - listener, port = bind_unused_port() - server_stream_fut = Future() # type: Future[IOStream] - - def accept_callback(connection, address): - server_stream_fut.set_result( - self._make_server_iostream(connection, **kwargs) - ) - - netutil.add_accept_handler(listener, accept_callback) - client_stream = self._make_client_iostream(socket.socket(), **kwargs) - connect_fut = client_stream.connect(("127.0.0.1", port)) - server_stream, client_stream = yield [server_stream_fut, connect_fut] - self.io_loop.remove_handler(listener.fileno()) - listener.close() - raise gen.Return((server_stream, client_stream)) - - @gen_test - def test_connection_refused(self: typing.Any): - # When a connection is refused, the connect callback should not - # be run. (The kqueue IOLoop used to behave differently from the - # epoll IOLoop in this respect) - cleanup_func, port = refusing_port() - self.addCleanup(cleanup_func) - stream = IOStream(socket.socket()) - - stream.set_close_callback(self.stop) - # log messages vary by platform and ioloop implementation - with ExpectLog(gen_log, ".*", required=False): - with self.assertRaises(StreamClosedError): - yield stream.connect(("127.0.0.1", port)) - - self.assertTrue(isinstance(stream.error, ConnectionRefusedError), stream.error) - - @gen_test - def test_gaierror(self: typing.Any): - # Test that IOStream sets its exc_info on getaddrinfo error. - # It's difficult to reliably trigger a getaddrinfo error; - # some resolvers own't even return errors for malformed names, - # so we mock it instead. If IOStream changes to call a Resolver - # before sock.connect, the mock target will need to change too. - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) - stream = IOStream(s) - stream.set_close_callback(self.stop) - with mock.patch( - "socket.socket.connect", side_effect=socket.gaierror(errno.EIO, "boom") - ): - with self.assertRaises(StreamClosedError): - yield stream.connect(("localhost", 80)) - self.assertTrue(isinstance(stream.error, socket.gaierror)) - - @gen_test - def test_read_until_close_with_error(self: typing.Any): - server, client = yield self.make_iostream_pair() - try: - with mock.patch( - "tornado.iostream.BaseIOStream._try_inline_read", - side_effect=IOError("boom"), - ): - with self.assertRaisesRegexp(IOError, "boom"): - client.read_until_close() - finally: - server.close() - client.close() - - @skipIfNonUnix - @skipPypy3V58 - @gen_test - def test_inline_read_error(self: typing.Any): - # An error on an inline read is raised without logging (on the - # assumption that it will eventually be noticed or logged further - # up the stack). - # - # This test is posix-only because windows os.close() doesn't work - # on socket FDs, but we can't close the socket object normally - # because we won't get the error we want if the socket knows - # it's closed. - # - # This test is also disabled when the - # AddThreadSelectorEventLoop is used, because a race between - # this thread closing the socket and the selector thread - # calling the select system call can make this test flaky. - # This event loop implementation is normally only used on - # windows, making this check redundant with skipIfNonUnix, but - # we sometimes enable it on other platforms for testing. - io_loop = IOLoop.current() - if isinstance(io_loop.selector_loop, AddThreadSelectorEventLoop): - self.skipTest("AddThreadSelectorEventLoop not supported") - server, client = yield self.make_iostream_pair() - try: - os.close(server.socket.fileno()) - with self.assertRaises(socket.error): - server.read_bytes(1) - finally: - server.close() - client.close() - - @skipPypy3V58 - @gen_test - def test_async_read_error_logging(self): - # Socket errors on asynchronous reads should be logged (but only - # once). - server, client = yield self.make_iostream_pair() - closed = Event() - server.set_close_callback(closed.set) - try: - # Start a read that will be fulfilled asynchronously. - server.read_bytes(1) - client.write(b"a") - # Stub out read_from_fd to make it fail. - - def fake_read_from_fd(): - os.close(server.socket.fileno()) - server.__class__.read_from_fd(server) - - server.read_from_fd = fake_read_from_fd - # This log message is from _handle_read (not read_from_fd). - with ExpectLog(gen_log, "error on read"): - yield closed.wait() - finally: - server.close() - client.close() - - @gen_test - def test_future_write(self): - """ - Test that write() Futures are never orphaned. - """ - # Run concurrent writers that will write enough bytes so as to - # clog the socket buffer and accumulate bytes in our write buffer. - m, n = 5000, 1000 - nproducers = 10 - total_bytes = m * n * nproducers - server, client = yield self.make_iostream_pair(max_buffer_size=total_bytes) - - @gen.coroutine - def produce(): - data = b"x" * m - for i in range(n): - yield server.write(data) - - @gen.coroutine - def consume(): - nread = 0 - while nread < total_bytes: - res = yield client.read_bytes(m) - nread += len(res) - - try: - yield [produce() for i in range(nproducers)] + [consume()] - finally: - server.close() - client.close() - - -class TestIOStreamWebHTTP(TestIOStreamWebMixin, AsyncHTTPTestCase): - def _make_client_iostream(self): - return IOStream(socket.socket()) - - -class TestIOStreamWebHTTPS(TestIOStreamWebMixin, AsyncHTTPSTestCase): - def _make_client_iostream(self): - return SSLIOStream(socket.socket(), ssl_options=dict(cert_reqs=ssl.CERT_NONE)) - - -class TestIOStream(TestIOStreamMixin, AsyncTestCase): - def _make_server_iostream(self, connection, **kwargs): - return IOStream(connection, **kwargs) - - def _make_client_iostream(self, connection, **kwargs): - return IOStream(connection, **kwargs) - - -class TestIOStreamSSL(TestIOStreamMixin, AsyncTestCase): - def _make_server_iostream(self, connection, **kwargs): - connection = ssl.wrap_socket( - connection, - server_side=True, - do_handshake_on_connect=False, - **_server_ssl_options() - ) - return SSLIOStream(connection, **kwargs) - - def _make_client_iostream(self, connection, **kwargs): - return SSLIOStream( - connection, ssl_options=dict(cert_reqs=ssl.CERT_NONE), **kwargs - ) - - -# This will run some tests that are basically redundant but it's the -# simplest way to make sure that it works to pass an SSLContext -# instead of an ssl_options dict to the SSLIOStream constructor. -class TestIOStreamSSLContext(TestIOStreamMixin, AsyncTestCase): - def _make_server_iostream(self, connection, **kwargs): - context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) - context.load_cert_chain( - os.path.join(os.path.dirname(__file__), "test.crt"), - os.path.join(os.path.dirname(__file__), "test.key"), - ) - connection = ssl_wrap_socket( - connection, context, server_side=True, do_handshake_on_connect=False - ) - return SSLIOStream(connection, **kwargs) - - def _make_client_iostream(self, connection, **kwargs): - context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) - return SSLIOStream(connection, ssl_options=context, **kwargs) - - -class TestIOStreamStartTLS(AsyncTestCase): - def setUp(self): - try: - super().setUp() - self.listener, self.port = bind_unused_port() - self.server_stream = None - self.server_accepted = Future() # type: Future[None] - netutil.add_accept_handler(self.listener, self.accept) - self.client_stream = IOStream( - socket.socket() - ) # type: typing.Optional[IOStream] - self.io_loop.add_future( - self.client_stream.connect(("127.0.0.1", self.port)), self.stop - ) - self.wait() - self.io_loop.add_future(self.server_accepted, self.stop) - self.wait() - except Exception as e: - print(e) - raise - - def tearDown(self): - if self.server_stream is not None: - self.server_stream.close() - if self.client_stream is not None: - self.client_stream.close() - self.io_loop.remove_handler(self.listener.fileno()) - self.listener.close() - super().tearDown() - - def accept(self, connection, address): - if self.server_stream is not None: - self.fail("should only get one connection") - self.server_stream = IOStream(connection) - self.server_accepted.set_result(None) - - @gen.coroutine - def client_send_line(self, line): - assert self.client_stream is not None - self.client_stream.write(line) - assert self.server_stream is not None - recv_line = yield self.server_stream.read_until(b"\r\n") - self.assertEqual(line, recv_line) - - @gen.coroutine - def server_send_line(self, line): - assert self.server_stream is not None - self.server_stream.write(line) - assert self.client_stream is not None - recv_line = yield self.client_stream.read_until(b"\r\n") - self.assertEqual(line, recv_line) - - def client_start_tls(self, ssl_options=None, server_hostname=None): - assert self.client_stream is not None - client_stream = self.client_stream - self.client_stream = None - return client_stream.start_tls(False, ssl_options, server_hostname) - - def server_start_tls(self, ssl_options=None): - assert self.server_stream is not None - server_stream = self.server_stream - self.server_stream = None - return server_stream.start_tls(True, ssl_options) - - @gen_test - def test_start_tls_smtp(self): - # This flow is simplified from RFC 3207 section 5. - # We don't really need all of this, but it helps to make sure - # that after realistic back-and-forth traffic the buffers end up - # in a sane state. - yield self.server_send_line(b"220 mail.example.com ready\r\n") - yield self.client_send_line(b"EHLO mail.example.com\r\n") - yield self.server_send_line(b"250-mail.example.com welcome\r\n") - yield self.server_send_line(b"250 STARTTLS\r\n") - yield self.client_send_line(b"STARTTLS\r\n") - yield self.server_send_line(b"220 Go ahead\r\n") - client_future = self.client_start_tls(dict(cert_reqs=ssl.CERT_NONE)) - server_future = self.server_start_tls(_server_ssl_options()) - self.client_stream = yield client_future - self.server_stream = yield server_future - self.assertTrue(isinstance(self.client_stream, SSLIOStream)) - self.assertTrue(isinstance(self.server_stream, SSLIOStream)) - yield self.client_send_line(b"EHLO mail.example.com\r\n") - yield self.server_send_line(b"250 mail.example.com welcome\r\n") - - @gen_test - def test_handshake_fail(self): - server_future = self.server_start_tls(_server_ssl_options()) - # Certificates are verified with the default configuration. - with ExpectLog(gen_log, "SSL Error"): - client_future = self.client_start_tls(server_hostname="localhost") - with self.assertRaises(ssl.SSLError): - yield client_future - with self.assertRaises((ssl.SSLError, socket.error)): - yield server_future - - @gen_test - def test_check_hostname(self): - # Test that server_hostname parameter to start_tls is being used. - # The check_hostname functionality is only available in python 2.7 and - # up and in python 3.4 and up. - server_future = self.server_start_tls(_server_ssl_options()) - with ExpectLog(gen_log, "SSL Error"): - client_future = self.client_start_tls( - ssl.create_default_context(), server_hostname="127.0.0.1" - ) - with self.assertRaises(ssl.SSLError): - # The client fails to connect with an SSL error. - yield client_future - with self.assertRaises(Exception): - # The server fails to connect, but the exact error is unspecified. - yield server_future - - -class WaitForHandshakeTest(AsyncTestCase): - @gen.coroutine - def connect_to_server(self, server_cls): - server = client = None - try: - sock, port = bind_unused_port() - server = server_cls(ssl_options=_server_ssl_options()) - server.add_socket(sock) - - ssl_ctx = ssl.create_default_context(ssl.Purpose.SERVER_AUTH) - ssl_ctx.check_hostname = False - ssl_ctx.verify_mode = ssl.CERT_NONE - # These tests fail with ConnectionAbortedErrors with TLS - # 1.3 on windows python 3.7.4 (which includes an upgrade - # to openssl 1.1.c. Other platforms might be affected with - # newer openssl too). Disable it until we figure out - # what's up. - ssl_ctx.options |= getattr(ssl, "OP_NO_TLSv1_3", 0) - client = SSLIOStream(socket.socket(), ssl_options=ssl_ctx) - yield client.connect(("127.0.0.1", port)) - self.assertIsNotNone(client.socket.cipher()) - finally: - if server is not None: - server.stop() - if client is not None: - client.close() - - @gen_test - def test_wait_for_handshake_future(self): - test = self - handshake_future = Future() # type: Future[None] - - class TestServer(TCPServer): - def handle_stream(self, stream, address): - test.assertIsNone(stream.socket.cipher()) - test.io_loop.spawn_callback(self.handle_connection, stream) - - @gen.coroutine - def handle_connection(self, stream): - yield stream.wait_for_handshake() - handshake_future.set_result(None) - - yield self.connect_to_server(TestServer) - yield handshake_future - - @gen_test - def test_wait_for_handshake_already_waiting_error(self): - test = self - handshake_future = Future() # type: Future[None] - - class TestServer(TCPServer): - @gen.coroutine - def handle_stream(self, stream, address): - fut = stream.wait_for_handshake() - test.assertRaises(RuntimeError, stream.wait_for_handshake) - yield fut - - handshake_future.set_result(None) - - yield self.connect_to_server(TestServer) - yield handshake_future - - @gen_test - def test_wait_for_handshake_already_connected(self): - handshake_future = Future() # type: Future[None] - - class TestServer(TCPServer): - @gen.coroutine - def handle_stream(self, stream, address): - yield stream.wait_for_handshake() - yield stream.wait_for_handshake() - handshake_future.set_result(None) - - yield self.connect_to_server(TestServer) - yield handshake_future - - -@skipIfNonUnix -class TestPipeIOStream(TestReadWriteMixin, AsyncTestCase): - @gen.coroutine - def make_iostream_pair(self, **kwargs): - r, w = os.pipe() - - return PipeIOStream(r, **kwargs), PipeIOStream(w, **kwargs) - - @gen_test - def test_pipe_iostream(self): - rs, ws = yield self.make_iostream_pair() - - ws.write(b"hel") - ws.write(b"lo world") - - data = yield rs.read_until(b" ") - self.assertEqual(data, b"hello ") - - data = yield rs.read_bytes(3) - self.assertEqual(data, b"wor") - - ws.close() - - data = yield rs.read_until_close() - self.assertEqual(data, b"ld") - - rs.close() - - @gen_test - def test_pipe_iostream_big_write(self): - rs, ws = yield self.make_iostream_pair() - - NUM_BYTES = 1048576 - - # Write 1MB of data, which should fill the buffer - ws.write(b"1" * NUM_BYTES) - - data = yield rs.read_bytes(NUM_BYTES) - self.assertEqual(data, b"1" * NUM_BYTES) - - ws.close() - rs.close() - - -class TestStreamBuffer(unittest.TestCase): - """ - Unit tests for the private _StreamBuffer class. - """ - - def setUp(self): - self.random = random.Random(42) - - def to_bytes(self, b): - if isinstance(b, (bytes, bytearray)): - return bytes(b) - elif isinstance(b, memoryview): - return b.tobytes() # For py2 - else: - raise TypeError(b) - - def make_streambuffer(self, large_buf_threshold=10): - buf = _StreamBuffer() - assert buf._large_buf_threshold - buf._large_buf_threshold = large_buf_threshold - return buf - - def check_peek(self, buf, expected): - size = 1 - while size < 2 * len(expected): - got = self.to_bytes(buf.peek(size)) - self.assertTrue(got) # Not empty - self.assertLessEqual(len(got), size) - self.assertTrue(expected.startswith(got), (expected, got)) - size = (size * 3 + 1) // 2 - - def check_append_all_then_skip_all(self, buf, objs, input_type): - self.assertEqual(len(buf), 0) - - expected = b"" - - for o in objs: - expected += o - buf.append(input_type(o)) - self.assertEqual(len(buf), len(expected)) - self.check_peek(buf, expected) - - while expected: - n = self.random.randrange(1, len(expected) + 1) - expected = expected[n:] - buf.advance(n) - self.assertEqual(len(buf), len(expected)) - self.check_peek(buf, expected) - - self.assertEqual(len(buf), 0) - - def test_small(self): - objs = [b"12", b"345", b"67", b"89a", b"bcde", b"fgh", b"ijklmn"] - - buf = self.make_streambuffer() - self.check_append_all_then_skip_all(buf, objs, bytes) - - buf = self.make_streambuffer() - self.check_append_all_then_skip_all(buf, objs, bytearray) - - buf = self.make_streambuffer() - self.check_append_all_then_skip_all(buf, objs, memoryview) - - # Test internal algorithm - buf = self.make_streambuffer(10) - for i in range(9): - buf.append(b"x") - self.assertEqual(len(buf._buffers), 1) - for i in range(9): - buf.append(b"x") - self.assertEqual(len(buf._buffers), 2) - buf.advance(10) - self.assertEqual(len(buf._buffers), 1) - buf.advance(8) - self.assertEqual(len(buf._buffers), 0) - self.assertEqual(len(buf), 0) - - def test_large(self): - objs = [ - b"12" * 5, - b"345" * 2, - b"67" * 20, - b"89a" * 12, - b"bcde" * 1, - b"fgh" * 7, - b"ijklmn" * 2, - ] - - buf = self.make_streambuffer() - self.check_append_all_then_skip_all(buf, objs, bytes) - - buf = self.make_streambuffer() - self.check_append_all_then_skip_all(buf, objs, bytearray) - - buf = self.make_streambuffer() - self.check_append_all_then_skip_all(buf, objs, memoryview) - - # Test internal algorithm - buf = self.make_streambuffer(10) - for i in range(3): - buf.append(b"x" * 11) - self.assertEqual(len(buf._buffers), 3) - buf.append(b"y") - self.assertEqual(len(buf._buffers), 4) - buf.append(b"z") - self.assertEqual(len(buf._buffers), 4) - buf.advance(33) - self.assertEqual(len(buf._buffers), 1) - buf.advance(2) - self.assertEqual(len(buf._buffers), 0) - self.assertEqual(len(buf), 0) diff --git a/venv/lib/python3.8/site-packages/tornado/test/locale_test.py b/venv/lib/python3.8/site-packages/tornado/test/locale_test.py deleted file mode 100644 index a12dc98..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/locale_test.py +++ /dev/null @@ -1,151 +0,0 @@ -import datetime -import os -import shutil -import tempfile -import unittest - -import tornado.locale -from tornado.escape import utf8, to_unicode -from tornado.util import unicode_type - - -class TranslationLoaderTest(unittest.TestCase): - # TODO: less hacky way to get isolated tests - SAVE_VARS = ["_translations", "_supported_locales", "_use_gettext"] - - def clear_locale_cache(self): - tornado.locale.Locale._cache = {} - - def setUp(self): - self.saved = {} # type: dict - for var in TranslationLoaderTest.SAVE_VARS: - self.saved[var] = getattr(tornado.locale, var) - self.clear_locale_cache() - - def tearDown(self): - for k, v in self.saved.items(): - setattr(tornado.locale, k, v) - self.clear_locale_cache() - - def test_csv(self): - tornado.locale.load_translations( - os.path.join(os.path.dirname(__file__), "csv_translations") - ) - locale = tornado.locale.get("fr_FR") - self.assertTrue(isinstance(locale, tornado.locale.CSVLocale)) - self.assertEqual(locale.translate("school"), u"\u00e9cole") - - def test_csv_bom(self): - with open( - os.path.join(os.path.dirname(__file__), "csv_translations", "fr_FR.csv"), - "rb", - ) as f: - char_data = to_unicode(f.read()) - # Re-encode our input data (which is utf-8 without BOM) in - # encodings that use the BOM and ensure that we can still load - # it. Note that utf-16-le and utf-16-be do not write a BOM, - # so we only test whichver variant is native to our platform. - for encoding in ["utf-8-sig", "utf-16"]: - tmpdir = tempfile.mkdtemp() - try: - with open(os.path.join(tmpdir, "fr_FR.csv"), "wb") as f: - f.write(char_data.encode(encoding)) - tornado.locale.load_translations(tmpdir) - locale = tornado.locale.get("fr_FR") - self.assertIsInstance(locale, tornado.locale.CSVLocale) - self.assertEqual(locale.translate("school"), u"\u00e9cole") - finally: - shutil.rmtree(tmpdir) - - def test_gettext(self): - tornado.locale.load_gettext_translations( - os.path.join(os.path.dirname(__file__), "gettext_translations"), - "tornado_test", - ) - locale = tornado.locale.get("fr_FR") - self.assertTrue(isinstance(locale, tornado.locale.GettextLocale)) - self.assertEqual(locale.translate("school"), u"\u00e9cole") - self.assertEqual(locale.pgettext("law", "right"), u"le droit") - self.assertEqual(locale.pgettext("good", "right"), u"le bien") - self.assertEqual( - locale.pgettext("organization", "club", "clubs", 1), u"le club" - ) - self.assertEqual( - locale.pgettext("organization", "club", "clubs", 2), u"les clubs" - ) - self.assertEqual(locale.pgettext("stick", "club", "clubs", 1), u"le b\xe2ton") - self.assertEqual(locale.pgettext("stick", "club", "clubs", 2), u"les b\xe2tons") - - -class LocaleDataTest(unittest.TestCase): - def test_non_ascii_name(self): - name = tornado.locale.LOCALE_NAMES["es_LA"]["name"] - self.assertTrue(isinstance(name, unicode_type)) - self.assertEqual(name, u"Espa\u00f1ol") - self.assertEqual(utf8(name), b"Espa\xc3\xb1ol") - - -class EnglishTest(unittest.TestCase): - def test_format_date(self): - locale = tornado.locale.get("en_US") - date = datetime.datetime(2013, 4, 28, 18, 35) - self.assertEqual( - locale.format_date(date, full_format=True), "April 28, 2013 at 6:35 pm" - ) - - now = datetime.datetime.utcnow() - - self.assertEqual( - locale.format_date(now - datetime.timedelta(seconds=2), full_format=False), - "2 seconds ago", - ) - self.assertEqual( - locale.format_date(now - datetime.timedelta(minutes=2), full_format=False), - "2 minutes ago", - ) - self.assertEqual( - locale.format_date(now - datetime.timedelta(hours=2), full_format=False), - "2 hours ago", - ) - - self.assertEqual( - locale.format_date( - now - datetime.timedelta(days=1), full_format=False, shorter=True - ), - "yesterday", - ) - - date = now - datetime.timedelta(days=2) - self.assertEqual( - locale.format_date(date, full_format=False, shorter=True), - locale._weekdays[date.weekday()], - ) - - date = now - datetime.timedelta(days=300) - self.assertEqual( - locale.format_date(date, full_format=False, shorter=True), - "%s %d" % (locale._months[date.month - 1], date.day), - ) - - date = now - datetime.timedelta(days=500) - self.assertEqual( - locale.format_date(date, full_format=False, shorter=True), - "%s %d, %d" % (locale._months[date.month - 1], date.day, date.year), - ) - - def test_friendly_number(self): - locale = tornado.locale.get("en_US") - self.assertEqual(locale.friendly_number(1000000), "1,000,000") - - def test_list(self): - locale = tornado.locale.get("en_US") - self.assertEqual(locale.list([]), "") - self.assertEqual(locale.list(["A"]), "A") - self.assertEqual(locale.list(["A", "B"]), "A and B") - self.assertEqual(locale.list(["A", "B", "C"]), "A, B and C") - - def test_format_day(self): - locale = tornado.locale.get("en_US") - date = datetime.datetime(2013, 4, 28, 18, 35) - self.assertEqual(locale.format_day(date=date, dow=True), "Sunday, April 28") - self.assertEqual(locale.format_day(date=date, dow=False), "April 28") diff --git a/venv/lib/python3.8/site-packages/tornado/test/locks_test.py b/venv/lib/python3.8/site-packages/tornado/test/locks_test.py deleted file mode 100644 index 23e1c52..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/locks_test.py +++ /dev/null @@ -1,535 +0,0 @@ -# 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. - -import asyncio -from datetime import timedelta -import typing # noqa: F401 -import unittest - -from tornado import gen, locks -from tornado.gen import TimeoutError -from tornado.testing import gen_test, AsyncTestCase - - -class ConditionTest(AsyncTestCase): - def setUp(self): - super().setUp() - self.history = [] # type: typing.List[typing.Union[int, str]] - - def record_done(self, future, key): - """Record the resolution of a Future returned by Condition.wait.""" - - def callback(_): - if not future.result(): - # wait() resolved to False, meaning it timed out. - self.history.append("timeout") - else: - self.history.append(key) - - future.add_done_callback(callback) - - def loop_briefly(self): - """Run all queued callbacks on the IOLoop. - - In these tests, this method is used after calling notify() to - preserve the pre-5.0 behavior in which callbacks ran - synchronously. - """ - self.io_loop.add_callback(self.stop) - self.wait() - - def test_repr(self): - c = locks.Condition() - self.assertIn("Condition", repr(c)) - self.assertNotIn("waiters", repr(c)) - c.wait() - self.assertIn("waiters", repr(c)) - - @gen_test - def test_notify(self): - c = locks.Condition() - self.io_loop.call_later(0.01, c.notify) - yield c.wait() - - def test_notify_1(self): - c = locks.Condition() - self.record_done(c.wait(), "wait1") - self.record_done(c.wait(), "wait2") - c.notify(1) - self.loop_briefly() - self.history.append("notify1") - c.notify(1) - self.loop_briefly() - self.history.append("notify2") - self.assertEqual(["wait1", "notify1", "wait2", "notify2"], self.history) - - def test_notify_n(self): - c = locks.Condition() - for i in range(6): - self.record_done(c.wait(), i) - - c.notify(3) - self.loop_briefly() - - # Callbacks execute in the order they were registered. - self.assertEqual(list(range(3)), self.history) - c.notify(1) - self.loop_briefly() - self.assertEqual(list(range(4)), self.history) - c.notify(2) - self.loop_briefly() - self.assertEqual(list(range(6)), self.history) - - def test_notify_all(self): - c = locks.Condition() - for i in range(4): - self.record_done(c.wait(), i) - - c.notify_all() - self.loop_briefly() - self.history.append("notify_all") - - # Callbacks execute in the order they were registered. - self.assertEqual(list(range(4)) + ["notify_all"], self.history) # type: ignore - - @gen_test - def test_wait_timeout(self): - c = locks.Condition() - wait = c.wait(timedelta(seconds=0.01)) - self.io_loop.call_later(0.02, c.notify) # Too late. - yield gen.sleep(0.03) - self.assertFalse((yield wait)) - - @gen_test - def test_wait_timeout_preempted(self): - c = locks.Condition() - - # This fires before the wait times out. - self.io_loop.call_later(0.01, c.notify) - wait = c.wait(timedelta(seconds=0.02)) - yield gen.sleep(0.03) - yield wait # No TimeoutError. - - @gen_test - def test_notify_n_with_timeout(self): - # Register callbacks 0, 1, 2, and 3. Callback 1 has a timeout. - # Wait for that timeout to expire, then do notify(2) and make - # sure everyone runs. Verifies that a timed-out callback does - # not count against the 'n' argument to notify(). - c = locks.Condition() - self.record_done(c.wait(), 0) - self.record_done(c.wait(timedelta(seconds=0.01)), 1) - self.record_done(c.wait(), 2) - self.record_done(c.wait(), 3) - - # Wait for callback 1 to time out. - yield gen.sleep(0.02) - self.assertEqual(["timeout"], self.history) - - c.notify(2) - yield gen.sleep(0.01) - self.assertEqual(["timeout", 0, 2], self.history) - self.assertEqual(["timeout", 0, 2], self.history) - c.notify() - yield - self.assertEqual(["timeout", 0, 2, 3], self.history) - - @gen_test - def test_notify_all_with_timeout(self): - c = locks.Condition() - self.record_done(c.wait(), 0) - self.record_done(c.wait(timedelta(seconds=0.01)), 1) - self.record_done(c.wait(), 2) - - # Wait for callback 1 to time out. - yield gen.sleep(0.02) - self.assertEqual(["timeout"], self.history) - - c.notify_all() - yield - self.assertEqual(["timeout", 0, 2], self.history) - - @gen_test - def test_nested_notify(self): - # Ensure no notifications lost, even if notify() is reentered by a - # waiter calling notify(). - c = locks.Condition() - - # Three waiters. - futures = [asyncio.ensure_future(c.wait()) for _ in range(3)] - - # First and second futures resolved. Second future reenters notify(), - # resolving third future. - futures[1].add_done_callback(lambda _: c.notify()) - c.notify(2) - yield - self.assertTrue(all(f.done() for f in futures)) - - @gen_test - def test_garbage_collection(self): - # Test that timed-out waiters are occasionally cleaned from the queue. - c = locks.Condition() - for _ in range(101): - c.wait(timedelta(seconds=0.01)) - - future = asyncio.ensure_future(c.wait()) - self.assertEqual(102, len(c._waiters)) - - # Let first 101 waiters time out, triggering a collection. - yield gen.sleep(0.02) - self.assertEqual(1, len(c._waiters)) - - # Final waiter is still active. - self.assertFalse(future.done()) - c.notify() - self.assertTrue(future.done()) - - -class EventTest(AsyncTestCase): - def test_repr(self): - event = locks.Event() - self.assertTrue("clear" in str(event)) - self.assertFalse("set" in str(event)) - event.set() - self.assertFalse("clear" in str(event)) - self.assertTrue("set" in str(event)) - - def test_event(self): - e = locks.Event() - future_0 = asyncio.ensure_future(e.wait()) - e.set() - future_1 = asyncio.ensure_future(e.wait()) - e.clear() - future_2 = asyncio.ensure_future(e.wait()) - - self.assertTrue(future_0.done()) - self.assertTrue(future_1.done()) - self.assertFalse(future_2.done()) - - @gen_test - def test_event_timeout(self): - e = locks.Event() - with self.assertRaises(TimeoutError): - yield e.wait(timedelta(seconds=0.01)) - - # After a timed-out waiter, normal operation works. - self.io_loop.add_timeout(timedelta(seconds=0.01), e.set) - yield e.wait(timedelta(seconds=1)) - - def test_event_set_multiple(self): - e = locks.Event() - e.set() - e.set() - self.assertTrue(e.is_set()) - - def test_event_wait_clear(self): - e = locks.Event() - f0 = asyncio.ensure_future(e.wait()) - e.clear() - f1 = asyncio.ensure_future(e.wait()) - e.set() - self.assertTrue(f0.done()) - self.assertTrue(f1.done()) - - -class SemaphoreTest(AsyncTestCase): - def test_negative_value(self): - self.assertRaises(ValueError, locks.Semaphore, value=-1) - - def test_repr(self): - sem = locks.Semaphore() - self.assertIn("Semaphore", repr(sem)) - self.assertIn("unlocked,value:1", repr(sem)) - sem.acquire() - self.assertIn("locked", repr(sem)) - self.assertNotIn("waiters", repr(sem)) - sem.acquire() - self.assertIn("waiters", repr(sem)) - - def test_acquire(self): - sem = locks.Semaphore() - f0 = asyncio.ensure_future(sem.acquire()) - self.assertTrue(f0.done()) - - # Wait for release(). - f1 = asyncio.ensure_future(sem.acquire()) - self.assertFalse(f1.done()) - f2 = asyncio.ensure_future(sem.acquire()) - sem.release() - self.assertTrue(f1.done()) - self.assertFalse(f2.done()) - sem.release() - self.assertTrue(f2.done()) - - sem.release() - # Now acquire() is instant. - self.assertTrue(asyncio.ensure_future(sem.acquire()).done()) - self.assertEqual(0, len(sem._waiters)) - - @gen_test - def test_acquire_timeout(self): - sem = locks.Semaphore(2) - yield sem.acquire() - yield sem.acquire() - acquire = sem.acquire(timedelta(seconds=0.01)) - self.io_loop.call_later(0.02, sem.release) # Too late. - yield gen.sleep(0.3) - with self.assertRaises(gen.TimeoutError): - yield acquire - - sem.acquire() - f = asyncio.ensure_future(sem.acquire()) - self.assertFalse(f.done()) - sem.release() - self.assertTrue(f.done()) - - @gen_test - def test_acquire_timeout_preempted(self): - sem = locks.Semaphore(1) - yield sem.acquire() - - # This fires before the wait times out. - self.io_loop.call_later(0.01, sem.release) - acquire = sem.acquire(timedelta(seconds=0.02)) - yield gen.sleep(0.03) - yield acquire # No TimeoutError. - - def test_release_unacquired(self): - # Unbounded releases are allowed, and increment the semaphore's value. - sem = locks.Semaphore() - sem.release() - sem.release() - - # Now the counter is 3. We can acquire three times before blocking. - self.assertTrue(asyncio.ensure_future(sem.acquire()).done()) - self.assertTrue(asyncio.ensure_future(sem.acquire()).done()) - self.assertTrue(asyncio.ensure_future(sem.acquire()).done()) - self.assertFalse(asyncio.ensure_future(sem.acquire()).done()) - - @gen_test - def test_garbage_collection(self): - # Test that timed-out waiters are occasionally cleaned from the queue. - sem = locks.Semaphore(value=0) - futures = [ - asyncio.ensure_future(sem.acquire(timedelta(seconds=0.01))) - for _ in range(101) - ] - - future = asyncio.ensure_future(sem.acquire()) - self.assertEqual(102, len(sem._waiters)) - - # Let first 101 waiters time out, triggering a collection. - yield gen.sleep(0.02) - self.assertEqual(1, len(sem._waiters)) - - # Final waiter is still active. - self.assertFalse(future.done()) - sem.release() - self.assertTrue(future.done()) - - # Prevent "Future exception was never retrieved" messages. - for future in futures: - self.assertRaises(TimeoutError, future.result) - - -class SemaphoreContextManagerTest(AsyncTestCase): - @gen_test - def test_context_manager(self): - sem = locks.Semaphore() - with (yield sem.acquire()) as yielded: - self.assertTrue(yielded is None) - - # Semaphore was released and can be acquired again. - self.assertTrue(asyncio.ensure_future(sem.acquire()).done()) - - @gen_test - def test_context_manager_async_await(self): - # Repeat the above test using 'async with'. - sem = locks.Semaphore() - - async def f(): - async with sem as yielded: - self.assertTrue(yielded is None) - - yield f() - - # Semaphore was released and can be acquired again. - self.assertTrue(asyncio.ensure_future(sem.acquire()).done()) - - @gen_test - def test_context_manager_exception(self): - sem = locks.Semaphore() - with self.assertRaises(ZeroDivisionError): - with (yield sem.acquire()): - 1 / 0 - - # Semaphore was released and can be acquired again. - self.assertTrue(asyncio.ensure_future(sem.acquire()).done()) - - @gen_test - def test_context_manager_timeout(self): - sem = locks.Semaphore() - with (yield sem.acquire(timedelta(seconds=0.01))): - pass - - # Semaphore was released and can be acquired again. - self.assertTrue(asyncio.ensure_future(sem.acquire()).done()) - - @gen_test - def test_context_manager_timeout_error(self): - sem = locks.Semaphore(value=0) - with self.assertRaises(gen.TimeoutError): - with (yield sem.acquire(timedelta(seconds=0.01))): - pass - - # Counter is still 0. - self.assertFalse(asyncio.ensure_future(sem.acquire()).done()) - - @gen_test - def test_context_manager_contended(self): - sem = locks.Semaphore() - history = [] - - @gen.coroutine - def f(index): - with (yield sem.acquire()): - history.append("acquired %d" % index) - yield gen.sleep(0.01) - history.append("release %d" % index) - - yield [f(i) for i in range(2)] - - expected_history = [] - for i in range(2): - expected_history.extend(["acquired %d" % i, "release %d" % i]) - - self.assertEqual(expected_history, history) - - @gen_test - def test_yield_sem(self): - # Ensure we catch a "with (yield sem)", which should be - # "with (yield sem.acquire())". - with self.assertRaises(gen.BadYieldError): - with (yield locks.Semaphore()): - pass - - def test_context_manager_misuse(self): - # Ensure we catch a "with sem", which should be - # "with (yield sem.acquire())". - with self.assertRaises(RuntimeError): - with locks.Semaphore(): - pass - - -class BoundedSemaphoreTest(AsyncTestCase): - def test_release_unacquired(self): - sem = locks.BoundedSemaphore() - self.assertRaises(ValueError, sem.release) - # Value is 0. - sem.acquire() - # Block on acquire(). - future = asyncio.ensure_future(sem.acquire()) - self.assertFalse(future.done()) - sem.release() - self.assertTrue(future.done()) - # Value is 1. - sem.release() - self.assertRaises(ValueError, sem.release) - - -class LockTests(AsyncTestCase): - def test_repr(self): - lock = locks.Lock() - # No errors. - repr(lock) - lock.acquire() - repr(lock) - - def test_acquire_release(self): - lock = locks.Lock() - self.assertTrue(asyncio.ensure_future(lock.acquire()).done()) - future = asyncio.ensure_future(lock.acquire()) - self.assertFalse(future.done()) - lock.release() - self.assertTrue(future.done()) - - @gen_test - def test_acquire_fifo(self): - lock = locks.Lock() - self.assertTrue(asyncio.ensure_future(lock.acquire()).done()) - N = 5 - history = [] - - @gen.coroutine - def f(idx): - with (yield lock.acquire()): - history.append(idx) - - futures = [f(i) for i in range(N)] - self.assertFalse(any(future.done() for future in futures)) - lock.release() - yield futures - self.assertEqual(list(range(N)), history) - - @gen_test - def test_acquire_fifo_async_with(self): - # Repeat the above test using `async with lock:` - # instead of `with (yield lock.acquire()):`. - lock = locks.Lock() - self.assertTrue(asyncio.ensure_future(lock.acquire()).done()) - N = 5 - history = [] - - async def f(idx): - async with lock: - history.append(idx) - - futures = [f(i) for i in range(N)] - lock.release() - yield futures - self.assertEqual(list(range(N)), history) - - @gen_test - def test_acquire_timeout(self): - lock = locks.Lock() - lock.acquire() - with self.assertRaises(gen.TimeoutError): - yield lock.acquire(timeout=timedelta(seconds=0.01)) - - # Still locked. - self.assertFalse(asyncio.ensure_future(lock.acquire()).done()) - - def test_multi_release(self): - lock = locks.Lock() - self.assertRaises(RuntimeError, lock.release) - lock.acquire() - lock.release() - self.assertRaises(RuntimeError, lock.release) - - @gen_test - def test_yield_lock(self): - # Ensure we catch a "with (yield lock)", which should be - # "with (yield lock.acquire())". - with self.assertRaises(gen.BadYieldError): - with (yield locks.Lock()): - pass - - def test_context_manager_misuse(self): - # Ensure we catch a "with lock", which should be - # "with (yield lock.acquire())". - with self.assertRaises(RuntimeError): - with locks.Lock(): - pass - - -if __name__ == "__main__": - unittest.main() diff --git a/venv/lib/python3.8/site-packages/tornado/test/log_test.py b/venv/lib/python3.8/site-packages/tornado/test/log_test.py deleted file mode 100644 index 8450e50..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/log_test.py +++ /dev/null @@ -1,245 +0,0 @@ -# -# Copyright 2012 Facebook -# -# 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. -import contextlib -import glob -import logging -import os -import re -import subprocess -import sys -import tempfile -import unittest -import warnings - -from tornado.escape import utf8 -from tornado.log import LogFormatter, define_logging_options, enable_pretty_logging -from tornado.options import OptionParser -from tornado.util import basestring_type - - -@contextlib.contextmanager -def ignore_bytes_warning(): - with warnings.catch_warnings(): - warnings.simplefilter("ignore", category=BytesWarning) - yield - - -class LogFormatterTest(unittest.TestCase): - # Matches the output of a single logging call (which may be multiple lines - # if a traceback was included, so we use the DOTALL option) - LINE_RE = re.compile( - b"(?s)\x01\\[E [0-9]{6} [0-9]{2}:[0-9]{2}:[0-9]{2} log_test:[0-9]+\\]\x02 (.*)" - ) - - def setUp(self): - self.formatter = LogFormatter(color=False) - # Fake color support. We can't guarantee anything about the $TERM - # variable when the tests are run, so just patch in some values - # for testing. (testing with color off fails to expose some potential - # encoding issues from the control characters) - self.formatter._colors = {logging.ERROR: u"\u0001"} - self.formatter._normal = u"\u0002" - # construct a Logger directly to bypass getLogger's caching - self.logger = logging.Logger("LogFormatterTest") - self.logger.propagate = False - self.tempdir = tempfile.mkdtemp() - self.filename = os.path.join(self.tempdir, "log.out") - self.handler = self.make_handler(self.filename) - self.handler.setFormatter(self.formatter) - self.logger.addHandler(self.handler) - - def tearDown(self): - self.handler.close() - os.unlink(self.filename) - os.rmdir(self.tempdir) - - def make_handler(self, filename): - # Base case: default setup without explicit encoding. - # In python 2, supports arbitrary byte strings and unicode objects - # that contain only ascii. In python 3, supports ascii-only unicode - # strings (but byte strings will be repr'd automatically). - return logging.FileHandler(filename) - - def get_output(self): - with open(self.filename, "rb") as f: - line = f.read().strip() - m = LogFormatterTest.LINE_RE.match(line) - if m: - return m.group(1) - else: - raise Exception("output didn't match regex: %r" % line) - - def test_basic_logging(self): - self.logger.error("foo") - self.assertEqual(self.get_output(), b"foo") - - def test_bytes_logging(self): - with ignore_bytes_warning(): - # This will be "\xe9" on python 2 or "b'\xe9'" on python 3 - self.logger.error(b"\xe9") - self.assertEqual(self.get_output(), utf8(repr(b"\xe9"))) - - def test_utf8_logging(self): - with ignore_bytes_warning(): - self.logger.error(u"\u00e9".encode("utf8")) - if issubclass(bytes, basestring_type): - # on python 2, utf8 byte strings (and by extension ascii byte - # strings) are passed through as-is. - self.assertEqual(self.get_output(), utf8(u"\u00e9")) - else: - # on python 3, byte strings always get repr'd even if - # they're ascii-only, so this degenerates into another - # copy of test_bytes_logging. - self.assertEqual(self.get_output(), utf8(repr(utf8(u"\u00e9")))) - - def test_bytes_exception_logging(self): - try: - raise Exception(b"\xe9") - except Exception: - self.logger.exception("caught exception") - # This will be "Exception: \xe9" on python 2 or - # "Exception: b'\xe9'" on python 3. - output = self.get_output() - self.assertRegexpMatches(output, br"Exception.*\\xe9") - # The traceback contains newlines, which should not have been escaped. - self.assertNotIn(br"\n", output) - - -class UnicodeLogFormatterTest(LogFormatterTest): - def make_handler(self, filename): - # Adding an explicit encoding configuration allows non-ascii unicode - # strings in both python 2 and 3, without changing the behavior - # for byte strings. - return logging.FileHandler(filename, encoding="utf8") - - def test_unicode_logging(self): - self.logger.error(u"\u00e9") - self.assertEqual(self.get_output(), utf8(u"\u00e9")) - - -class EnablePrettyLoggingTest(unittest.TestCase): - def setUp(self): - super().setUp() - self.options = OptionParser() - define_logging_options(self.options) - self.logger = logging.Logger("tornado.test.log_test.EnablePrettyLoggingTest") - self.logger.propagate = False - - def test_log_file(self): - tmpdir = tempfile.mkdtemp() - try: - self.options.log_file_prefix = tmpdir + "/test_log" - enable_pretty_logging(options=self.options, logger=self.logger) - self.assertEqual(1, len(self.logger.handlers)) - self.logger.error("hello") - self.logger.handlers[0].flush() - filenames = glob.glob(tmpdir + "/test_log*") - self.assertEqual(1, len(filenames)) - with open(filenames[0]) as f: - self.assertRegexpMatches(f.read(), r"^\[E [^]]*\] hello$") - finally: - for handler in self.logger.handlers: - handler.flush() - handler.close() - for filename in glob.glob(tmpdir + "/test_log*"): - os.unlink(filename) - os.rmdir(tmpdir) - - def test_log_file_with_timed_rotating(self): - tmpdir = tempfile.mkdtemp() - try: - self.options.log_file_prefix = tmpdir + "/test_log" - self.options.log_rotate_mode = "time" - enable_pretty_logging(options=self.options, logger=self.logger) - self.logger.error("hello") - self.logger.handlers[0].flush() - filenames = glob.glob(tmpdir + "/test_log*") - self.assertEqual(1, len(filenames)) - with open(filenames[0]) as f: - self.assertRegexpMatches(f.read(), r"^\[E [^]]*\] hello$") - finally: - for handler in self.logger.handlers: - handler.flush() - handler.close() - for filename in glob.glob(tmpdir + "/test_log*"): - os.unlink(filename) - os.rmdir(tmpdir) - - def test_wrong_rotate_mode_value(self): - try: - self.options.log_file_prefix = "some_path" - self.options.log_rotate_mode = "wrong_mode" - self.assertRaises( - ValueError, - enable_pretty_logging, - options=self.options, - logger=self.logger, - ) - finally: - for handler in self.logger.handlers: - handler.flush() - handler.close() - - -class LoggingOptionTest(unittest.TestCase): - """Test the ability to enable and disable Tornado's logging hooks.""" - - def logs_present(self, statement, args=None): - # Each test may manipulate and/or parse the options and then logs - # a line at the 'info' level. This level is ignored in the - # logging module by default, but Tornado turns it on by default - # so it is the easiest way to tell whether tornado's logging hooks - # ran. - IMPORT = "from tornado.options import options, parse_command_line" - LOG_INFO = 'import logging; logging.info("hello")' - program = ";".join([IMPORT, statement, LOG_INFO]) - proc = subprocess.Popen( - [sys.executable, "-c", program] + (args or []), - stdout=subprocess.PIPE, - stderr=subprocess.STDOUT, - ) - stdout, stderr = proc.communicate() - self.assertEqual(proc.returncode, 0, "process failed: %r" % stdout) - return b"hello" in stdout - - def test_default(self): - self.assertFalse(self.logs_present("pass")) - - def test_tornado_default(self): - self.assertTrue(self.logs_present("parse_command_line()")) - - def test_disable_command_line(self): - self.assertFalse(self.logs_present("parse_command_line()", ["--logging=none"])) - - def test_disable_command_line_case_insensitive(self): - self.assertFalse(self.logs_present("parse_command_line()", ["--logging=None"])) - - def test_disable_code_string(self): - self.assertFalse( - self.logs_present('options.logging = "none"; parse_command_line()') - ) - - def test_disable_code_none(self): - self.assertFalse( - self.logs_present("options.logging = None; parse_command_line()") - ) - - def test_disable_override(self): - # command line trumps code defaults - self.assertTrue( - self.logs_present( - "options.logging = None; parse_command_line()", ["--logging=info"] - ) - ) diff --git a/venv/lib/python3.8/site-packages/tornado/test/netutil_test.py b/venv/lib/python3.8/site-packages/tornado/test/netutil_test.py deleted file mode 100644 index f36b7c2..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/netutil_test.py +++ /dev/null @@ -1,233 +0,0 @@ -import errno -import os -import signal -import socket -from subprocess import Popen -import sys -import time -import unittest - -from tornado.netutil import ( - BlockingResolver, - OverrideResolver, - ThreadedResolver, - is_valid_ip, - bind_sockets, -) -from tornado.testing import AsyncTestCase, gen_test, bind_unused_port -from tornado.test.util import skipIfNoNetwork - -import typing - -if typing.TYPE_CHECKING: - from typing import List # noqa: F401 - -try: - import pycares # type: ignore -except ImportError: - pycares = None -else: - from tornado.platform.caresresolver import CaresResolver - -try: - import twisted # type: ignore - import twisted.names # type: ignore -except ImportError: - twisted = None -else: - from tornado.platform.twisted import TwistedResolver - - -class _ResolverTestMixin(object): - resolver = None # type: typing.Any - - @gen_test - def test_localhost(self: typing.Any): - addrinfo = yield self.resolver.resolve("localhost", 80, socket.AF_UNSPEC) - self.assertIn((socket.AF_INET, ("127.0.0.1", 80)), addrinfo) - - -# It is impossible to quickly and consistently generate an error in name -# resolution, so test this case separately, using mocks as needed. -class _ResolverErrorTestMixin(object): - resolver = None # type: typing.Any - - @gen_test - def test_bad_host(self: typing.Any): - with self.assertRaises(IOError): - yield self.resolver.resolve("an invalid domain", 80, socket.AF_UNSPEC) - - -def _failing_getaddrinfo(*args): - """Dummy implementation of getaddrinfo for use in mocks""" - raise socket.gaierror(errno.EIO, "mock: lookup failed") - - -@skipIfNoNetwork -class BlockingResolverTest(AsyncTestCase, _ResolverTestMixin): - def setUp(self): - super().setUp() - self.resolver = BlockingResolver() - - -# getaddrinfo-based tests need mocking to reliably generate errors; -# some configurations are slow to produce errors and take longer than -# our default timeout. -class BlockingResolverErrorTest(AsyncTestCase, _ResolverErrorTestMixin): - def setUp(self): - super().setUp() - self.resolver = BlockingResolver() - self.real_getaddrinfo = socket.getaddrinfo - socket.getaddrinfo = _failing_getaddrinfo - - def tearDown(self): - socket.getaddrinfo = self.real_getaddrinfo - super().tearDown() - - -class OverrideResolverTest(AsyncTestCase, _ResolverTestMixin): - def setUp(self): - super().setUp() - mapping = { - ("google.com", 80): ("1.2.3.4", 80), - ("google.com", 80, socket.AF_INET): ("1.2.3.4", 80), - ("google.com", 80, socket.AF_INET6): ( - "2a02:6b8:7c:40c:c51e:495f:e23a:3", - 80, - ), - } - self.resolver = OverrideResolver(BlockingResolver(), mapping) - - @gen_test - def test_resolve_multiaddr(self): - result = yield self.resolver.resolve("google.com", 80, socket.AF_INET) - self.assertIn((socket.AF_INET, ("1.2.3.4", 80)), result) - - result = yield self.resolver.resolve("google.com", 80, socket.AF_INET6) - self.assertIn( - (socket.AF_INET6, ("2a02:6b8:7c:40c:c51e:495f:e23a:3", 80, 0, 0)), result - ) - - -@skipIfNoNetwork -class ThreadedResolverTest(AsyncTestCase, _ResolverTestMixin): - def setUp(self): - super().setUp() - self.resolver = ThreadedResolver() - - def tearDown(self): - self.resolver.close() - super().tearDown() - - -class ThreadedResolverErrorTest(AsyncTestCase, _ResolverErrorTestMixin): - def setUp(self): - super().setUp() - self.resolver = BlockingResolver() - self.real_getaddrinfo = socket.getaddrinfo - socket.getaddrinfo = _failing_getaddrinfo - - def tearDown(self): - socket.getaddrinfo = self.real_getaddrinfo - super().tearDown() - - -@skipIfNoNetwork -@unittest.skipIf(sys.platform == "win32", "preexec_fn not available on win32") -class ThreadedResolverImportTest(unittest.TestCase): - def test_import(self): - TIMEOUT = 5 - - # Test for a deadlock when importing a module that runs the - # ThreadedResolver at import-time. See resolve_test.py for - # full explanation. - command = [sys.executable, "-c", "import tornado.test.resolve_test_helper"] - - start = time.time() - popen = Popen(command, preexec_fn=lambda: signal.alarm(TIMEOUT)) - while time.time() - start < TIMEOUT: - return_code = popen.poll() - if return_code is not None: - self.assertEqual(0, return_code) - return # Success. - time.sleep(0.05) - - self.fail("import timed out") - - -# We do not test errors with CaresResolver: -# Some DNS-hijacking ISPs (e.g. Time Warner) return non-empty results -# with an NXDOMAIN status code. Most resolvers treat this as an error; -# C-ares returns the results, making the "bad_host" tests unreliable. -# C-ares will try to resolve even malformed names, such as the -# name with spaces used in this test. -@skipIfNoNetwork -@unittest.skipIf(pycares is None, "pycares module not present") -@unittest.skipIf(sys.platform == "win32", "pycares doesn't return loopback on windows") -@unittest.skipIf(sys.platform == "darwin", "pycares doesn't return 127.0.0.1 on darwin") -class CaresResolverTest(AsyncTestCase, _ResolverTestMixin): - def setUp(self): - super().setUp() - self.resolver = CaresResolver() - - -# TwistedResolver produces consistent errors in our test cases so we -# could test the regular and error cases in the same class. However, -# in the error cases it appears that cleanup of socket objects is -# handled asynchronously and occasionally results in "unclosed socket" -# warnings if not given time to shut down (and there is no way to -# explicitly shut it down). This makes the test flaky, so we do not -# test error cases here. -@skipIfNoNetwork -@unittest.skipIf(twisted is None, "twisted module not present") -@unittest.skipIf( - getattr(twisted, "__version__", "0.0") < "12.1", "old version of twisted" -) -@unittest.skipIf(sys.platform == "win32", "twisted resolver hangs on windows") -class TwistedResolverTest(AsyncTestCase, _ResolverTestMixin): - def setUp(self): - super().setUp() - self.resolver = TwistedResolver() - - -class IsValidIPTest(unittest.TestCase): - def test_is_valid_ip(self): - self.assertTrue(is_valid_ip("127.0.0.1")) - self.assertTrue(is_valid_ip("4.4.4.4")) - self.assertTrue(is_valid_ip("::1")) - self.assertTrue(is_valid_ip("2620:0:1cfe:face:b00c::3")) - self.assertTrue(not is_valid_ip("www.google.com")) - self.assertTrue(not is_valid_ip("localhost")) - self.assertTrue(not is_valid_ip("4.4.4.4<")) - self.assertTrue(not is_valid_ip(" 127.0.0.1")) - self.assertTrue(not is_valid_ip("")) - self.assertTrue(not is_valid_ip(" ")) - self.assertTrue(not is_valid_ip("\n")) - self.assertTrue(not is_valid_ip("\x00")) - - -class TestPortAllocation(unittest.TestCase): - def test_same_port_allocation(self): - if "TRAVIS" in os.environ: - self.skipTest("dual-stack servers often have port conflicts on travis") - sockets = bind_sockets(0, "localhost") - try: - port = sockets[0].getsockname()[1] - self.assertTrue(all(s.getsockname()[1] == port for s in sockets[1:])) - finally: - for sock in sockets: - sock.close() - - @unittest.skipIf( - not hasattr(socket, "SO_REUSEPORT"), "SO_REUSEPORT is not supported" - ) - def test_reuse_port(self): - sockets = [] # type: List[socket.socket] - socket, port = bind_unused_port(reuse_port=True) - try: - sockets = bind_sockets(port, "127.0.0.1", reuse_port=True) - self.assertTrue(all(s.getsockname()[1] == port for s in sockets)) - finally: - socket.close() - for sock in sockets: - sock.close() diff --git a/venv/lib/python3.8/site-packages/tornado/test/options_test.cfg b/venv/lib/python3.8/site-packages/tornado/test/options_test.cfg deleted file mode 100644 index 4ead46a..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/options_test.cfg +++ /dev/null @@ -1,7 +0,0 @@ -port=443 -port=443 -username='李康' - -foo_bar='a' - -my_path = __file__ diff --git a/venv/lib/python3.8/site-packages/tornado/test/options_test.py b/venv/lib/python3.8/site-packages/tornado/test/options_test.py deleted file mode 100644 index 6aedbec..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/options_test.py +++ /dev/null @@ -1,328 +0,0 @@ -import datetime -from io import StringIO -import os -import sys -from unittest import mock -import unittest - -from tornado.options import OptionParser, Error -from tornado.util import basestring_type -from tornado.test.util import subTest - -import typing - -if typing.TYPE_CHECKING: - from typing import List # noqa: F401 - - -class Email(object): - def __init__(self, value): - if isinstance(value, str) and "@" in value: - self._value = value - else: - raise ValueError() - - @property - def value(self): - return self._value - - -class OptionsTest(unittest.TestCase): - def test_parse_command_line(self): - options = OptionParser() - options.define("port", default=80) - options.parse_command_line(["main.py", "--port=443"]) - self.assertEqual(options.port, 443) - - def test_parse_config_file(self): - options = OptionParser() - options.define("port", default=80) - options.define("username", default="foo") - options.define("my_path") - config_path = os.path.join( - os.path.dirname(os.path.abspath(__file__)), "options_test.cfg" - ) - options.parse_config_file(config_path) - self.assertEqual(options.port, 443) - self.assertEqual(options.username, "李康") - self.assertEqual(options.my_path, config_path) - - def test_parse_callbacks(self): - options = OptionParser() - self.called = False - - def callback(): - self.called = True - - options.add_parse_callback(callback) - - # non-final parse doesn't run callbacks - options.parse_command_line(["main.py"], final=False) - self.assertFalse(self.called) - - # final parse does - options.parse_command_line(["main.py"]) - self.assertTrue(self.called) - - # callbacks can be run more than once on the same options - # object if there are multiple final parses - self.called = False - options.parse_command_line(["main.py"]) - self.assertTrue(self.called) - - def test_help(self): - options = OptionParser() - try: - orig_stderr = sys.stderr - sys.stderr = StringIO() - with self.assertRaises(SystemExit): - options.parse_command_line(["main.py", "--help"]) - usage = sys.stderr.getvalue() - finally: - sys.stderr = orig_stderr - self.assertIn("Usage:", usage) - - def test_subcommand(self): - base_options = OptionParser() - base_options.define("verbose", default=False) - sub_options = OptionParser() - sub_options.define("foo", type=str) - rest = base_options.parse_command_line( - ["main.py", "--verbose", "subcommand", "--foo=bar"] - ) - self.assertEqual(rest, ["subcommand", "--foo=bar"]) - self.assertTrue(base_options.verbose) - rest2 = sub_options.parse_command_line(rest) - self.assertEqual(rest2, []) - self.assertEqual(sub_options.foo, "bar") - - # the two option sets are distinct - try: - orig_stderr = sys.stderr - sys.stderr = StringIO() - with self.assertRaises(Error): - sub_options.parse_command_line(["subcommand", "--verbose"]) - finally: - sys.stderr = orig_stderr - - def test_setattr(self): - options = OptionParser() - options.define("foo", default=1, type=int) - options.foo = 2 - self.assertEqual(options.foo, 2) - - def test_setattr_type_check(self): - # setattr requires that options be the right type and doesn't - # parse from string formats. - options = OptionParser() - options.define("foo", default=1, type=int) - with self.assertRaises(Error): - options.foo = "2" - - def test_setattr_with_callback(self): - values = [] # type: List[int] - options = OptionParser() - options.define("foo", default=1, type=int, callback=values.append) - options.foo = 2 - self.assertEqual(values, [2]) - - def _sample_options(self): - options = OptionParser() - options.define("a", default=1) - options.define("b", default=2) - return options - - def test_iter(self): - options = self._sample_options() - # OptionParsers always define 'help'. - self.assertEqual(set(["a", "b", "help"]), set(iter(options))) - - def test_getitem(self): - options = self._sample_options() - self.assertEqual(1, options["a"]) - - def test_setitem(self): - options = OptionParser() - options.define("foo", default=1, type=int) - options["foo"] = 2 - self.assertEqual(options["foo"], 2) - - def test_items(self): - options = self._sample_options() - # OptionParsers always define 'help'. - expected = [("a", 1), ("b", 2), ("help", options.help)] - actual = sorted(options.items()) - self.assertEqual(expected, actual) - - def test_as_dict(self): - options = self._sample_options() - expected = {"a": 1, "b": 2, "help": options.help} - self.assertEqual(expected, options.as_dict()) - - def test_group_dict(self): - options = OptionParser() - options.define("a", default=1) - options.define("b", group="b_group", default=2) - - frame = sys._getframe(0) - this_file = frame.f_code.co_filename - self.assertEqual(set(["b_group", "", this_file]), options.groups()) - - b_group_dict = options.group_dict("b_group") - self.assertEqual({"b": 2}, b_group_dict) - - self.assertEqual({}, options.group_dict("nonexistent")) - - def test_mock_patch(self): - # ensure that our setattr hooks don't interfere with mock.patch - options = OptionParser() - options.define("foo", default=1) - options.parse_command_line(["main.py", "--foo=2"]) - self.assertEqual(options.foo, 2) - - with mock.patch.object(options.mockable(), "foo", 3): - self.assertEqual(options.foo, 3) - self.assertEqual(options.foo, 2) - - # Try nested patches mixed with explicit sets - with mock.patch.object(options.mockable(), "foo", 4): - self.assertEqual(options.foo, 4) - options.foo = 5 - self.assertEqual(options.foo, 5) - with mock.patch.object(options.mockable(), "foo", 6): - self.assertEqual(options.foo, 6) - self.assertEqual(options.foo, 5) - self.assertEqual(options.foo, 2) - - def _define_options(self): - options = OptionParser() - options.define("str", type=str) - options.define("basestring", type=basestring_type) - options.define("int", type=int) - options.define("float", type=float) - options.define("datetime", type=datetime.datetime) - options.define("timedelta", type=datetime.timedelta) - options.define("email", type=Email) - options.define("list-of-int", type=int, multiple=True) - return options - - def _check_options_values(self, options): - self.assertEqual(options.str, "asdf") - self.assertEqual(options.basestring, "qwer") - self.assertEqual(options.int, 42) - self.assertEqual(options.float, 1.5) - self.assertEqual(options.datetime, datetime.datetime(2013, 4, 28, 5, 16)) - self.assertEqual(options.timedelta, datetime.timedelta(seconds=45)) - self.assertEqual(options.email.value, "tornado@web.com") - self.assertTrue(isinstance(options.email, Email)) - self.assertEqual(options.list_of_int, [1, 2, 3]) - - def test_types(self): - options = self._define_options() - options.parse_command_line( - [ - "main.py", - "--str=asdf", - "--basestring=qwer", - "--int=42", - "--float=1.5", - "--datetime=2013-04-28 05:16", - "--timedelta=45s", - "--email=tornado@web.com", - "--list-of-int=1,2,3", - ] - ) - self._check_options_values(options) - - def test_types_with_conf_file(self): - for config_file_name in ( - "options_test_types.cfg", - "options_test_types_str.cfg", - ): - options = self._define_options() - options.parse_config_file( - os.path.join(os.path.dirname(__file__), config_file_name) - ) - self._check_options_values(options) - - def test_multiple_string(self): - options = OptionParser() - options.define("foo", type=str, multiple=True) - options.parse_command_line(["main.py", "--foo=a,b,c"]) - self.assertEqual(options.foo, ["a", "b", "c"]) - - def test_multiple_int(self): - options = OptionParser() - options.define("foo", type=int, multiple=True) - options.parse_command_line(["main.py", "--foo=1,3,5:7"]) - self.assertEqual(options.foo, [1, 3, 5, 6, 7]) - - def test_error_redefine(self): - options = OptionParser() - options.define("foo") - with self.assertRaises(Error) as cm: - options.define("foo") - self.assertRegexpMatches(str(cm.exception), "Option.*foo.*already defined") - - def test_error_redefine_underscore(self): - # Ensure that the dash/underscore normalization doesn't - # interfere with the redefinition error. - tests = [ - ("foo-bar", "foo-bar"), - ("foo_bar", "foo_bar"), - ("foo-bar", "foo_bar"), - ("foo_bar", "foo-bar"), - ] - for a, b in tests: - with subTest(self, a=a, b=b): - options = OptionParser() - options.define(a) - with self.assertRaises(Error) as cm: - options.define(b) - self.assertRegexpMatches( - str(cm.exception), "Option.*foo.bar.*already defined" - ) - - def test_dash_underscore_cli(self): - # Dashes and underscores should be interchangeable. - for defined_name in ["foo-bar", "foo_bar"]: - for flag in ["--foo-bar=a", "--foo_bar=a"]: - options = OptionParser() - options.define(defined_name) - options.parse_command_line(["main.py", flag]) - # Attr-style access always uses underscores. - self.assertEqual(options.foo_bar, "a") - # Dict-style access allows both. - self.assertEqual(options["foo-bar"], "a") - self.assertEqual(options["foo_bar"], "a") - - def test_dash_underscore_file(self): - # No matter how an option was defined, it can be set with underscores - # in a config file. - for defined_name in ["foo-bar", "foo_bar"]: - options = OptionParser() - options.define(defined_name) - options.parse_config_file( - os.path.join(os.path.dirname(__file__), "options_test.cfg") - ) - self.assertEqual(options.foo_bar, "a") - - def test_dash_underscore_introspection(self): - # Original names are preserved in introspection APIs. - options = OptionParser() - options.define("with-dash", group="g") - options.define("with_underscore", group="g") - all_options = ["help", "with-dash", "with_underscore"] - self.assertEqual(sorted(options), all_options) - self.assertEqual(sorted(k for (k, v) in options.items()), all_options) - self.assertEqual(sorted(options.as_dict().keys()), all_options) - - self.assertEqual( - sorted(options.group_dict("g")), ["with-dash", "with_underscore"] - ) - - # --help shows CLI-style names with dashes. - buf = StringIO() - options.print_help(buf) - self.assertIn("--with-dash", buf.getvalue()) - self.assertIn("--with-underscore", buf.getvalue()) diff --git a/venv/lib/python3.8/site-packages/tornado/test/options_test_types.cfg b/venv/lib/python3.8/site-packages/tornado/test/options_test_types.cfg deleted file mode 100644 index e1d53cb..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/options_test_types.cfg +++ /dev/null @@ -1,11 +0,0 @@ -from datetime import datetime, timedelta -from tornado.test.options_test import Email - -str = 'asdf' -basestring = 'qwer' -int = 42 -float = 1.5 -datetime = datetime(2013, 4, 28, 5, 16) -timedelta = timedelta(0, 45) -email = Email('tornado@web.com') -list_of_int = [1, 2, 3] diff --git a/venv/lib/python3.8/site-packages/tornado/test/options_test_types_str.cfg b/venv/lib/python3.8/site-packages/tornado/test/options_test_types_str.cfg deleted file mode 100644 index 25dfbc2..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/options_test_types_str.cfg +++ /dev/null @@ -1,8 +0,0 @@ -str = 'asdf' -basestring = 'qwer' -int = 42 -float = 1.5 -datetime = '2013-04-28 05:16' -timedelta = '45s' -email = 'tornado@web.com' -list_of_int = '1,2,3' diff --git a/venv/lib/python3.8/site-packages/tornado/test/process_test.py b/venv/lib/python3.8/site-packages/tornado/test/process_test.py deleted file mode 100644 index 6ff8efd..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/process_test.py +++ /dev/null @@ -1,274 +0,0 @@ -import asyncio -import logging -import os -import signal -import subprocess -import sys -import time -import unittest - -from tornado.httpclient import HTTPClient, HTTPError -from tornado.httpserver import HTTPServer -from tornado.ioloop import IOLoop -from tornado.log import gen_log -from tornado.process import fork_processes, task_id, Subprocess -from tornado.simple_httpclient import SimpleAsyncHTTPClient -from tornado.testing import bind_unused_port, ExpectLog, AsyncTestCase, gen_test -from tornado.test.util import skipIfNonUnix -from tornado.web import RequestHandler, Application - - -# Not using AsyncHTTPTestCase because we need control over the IOLoop. -@skipIfNonUnix -class ProcessTest(unittest.TestCase): - def get_app(self): - class ProcessHandler(RequestHandler): - def get(self): - if self.get_argument("exit", None): - # must use os._exit instead of sys.exit so unittest's - # exception handler doesn't catch it - os._exit(int(self.get_argument("exit"))) - if self.get_argument("signal", None): - os.kill(os.getpid(), int(self.get_argument("signal"))) - self.write(str(os.getpid())) - - return Application([("/", ProcessHandler)]) - - def tearDown(self): - if task_id() is not None: - # We're in a child process, and probably got to this point - # via an uncaught exception. If we return now, both - # processes will continue with the rest of the test suite. - # Exit now so the parent process will restart the child - # (since we don't have a clean way to signal failure to - # the parent that won't restart) - logging.error("aborting child process from tearDown") - logging.shutdown() - os._exit(1) - # In the surviving process, clear the alarm we set earlier - signal.alarm(0) - super().tearDown() - - def test_multi_process(self): - # This test doesn't work on twisted because we use the global - # reactor and don't restore it to a sane state after the fork - # (asyncio has the same issue, but we have a special case in - # place for it). - with ExpectLog( - gen_log, "(Starting .* processes|child .* exited|uncaught exception)" - ): - sock, port = bind_unused_port() - - def get_url(path): - return "http://127.0.0.1:%d%s" % (port, path) - - # ensure that none of these processes live too long - signal.alarm(5) # master process - try: - id = fork_processes(3, max_restarts=3) - self.assertTrue(id is not None) - signal.alarm(5) # child processes - except SystemExit as e: - # if we exit cleanly from fork_processes, all the child processes - # finished with status 0 - self.assertEqual(e.code, 0) - self.assertTrue(task_id() is None) - sock.close() - return - try: - if asyncio is not None: - # Reset the global asyncio event loop, which was put into - # a broken state by the fork. - asyncio.set_event_loop(asyncio.new_event_loop()) - if id in (0, 1): - self.assertEqual(id, task_id()) - server = HTTPServer(self.get_app()) - server.add_sockets([sock]) - IOLoop.current().start() - elif id == 2: - self.assertEqual(id, task_id()) - sock.close() - # Always use SimpleAsyncHTTPClient here; the curl - # version appears to get confused sometimes if the - # connection gets closed before it's had a chance to - # switch from writing mode to reading mode. - client = HTTPClient(SimpleAsyncHTTPClient) - - def fetch(url, fail_ok=False): - try: - return client.fetch(get_url(url)) - except HTTPError as e: - if not (fail_ok and e.code == 599): - raise - - # Make two processes exit abnormally - fetch("/?exit=2", fail_ok=True) - fetch("/?exit=3", fail_ok=True) - - # They've been restarted, so a new fetch will work - int(fetch("/").body) - - # Now the same with signals - # Disabled because on the mac a process dying with a signal - # can trigger an "Application exited abnormally; send error - # report to Apple?" prompt. - # fetch("/?signal=%d" % signal.SIGTERM, fail_ok=True) - # fetch("/?signal=%d" % signal.SIGABRT, fail_ok=True) - # int(fetch("/").body) - - # Now kill them normally so they won't be restarted - fetch("/?exit=0", fail_ok=True) - # One process left; watch it's pid change - pid = int(fetch("/").body) - fetch("/?exit=4", fail_ok=True) - pid2 = int(fetch("/").body) - self.assertNotEqual(pid, pid2) - - # Kill the last one so we shut down cleanly - fetch("/?exit=0", fail_ok=True) - - os._exit(0) - except Exception: - logging.error("exception in child process %d", id, exc_info=True) - raise - - -@skipIfNonUnix -class SubprocessTest(AsyncTestCase): - def term_and_wait(self, subproc): - subproc.proc.terminate() - subproc.proc.wait() - - @gen_test - def test_subprocess(self): - if IOLoop.configured_class().__name__.endswith("LayeredTwistedIOLoop"): - # This test fails non-deterministically with LayeredTwistedIOLoop. - # (the read_until('\n') returns '\n' instead of 'hello\n') - # This probably indicates a problem with either TornadoReactor - # or TwistedIOLoop, but I haven't been able to track it down - # and for now this is just causing spurious travis-ci failures. - raise unittest.SkipTest( - "Subprocess tests not compatible with " "LayeredTwistedIOLoop" - ) - subproc = Subprocess( - [sys.executable, "-u", "-i"], - stdin=Subprocess.STREAM, - stdout=Subprocess.STREAM, - stderr=subprocess.STDOUT, - ) - self.addCleanup(lambda: self.term_and_wait(subproc)) - self.addCleanup(subproc.stdout.close) - self.addCleanup(subproc.stdin.close) - yield subproc.stdout.read_until(b">>> ") - subproc.stdin.write(b"print('hello')\n") - data = yield subproc.stdout.read_until(b"\n") - self.assertEqual(data, b"hello\n") - - yield subproc.stdout.read_until(b">>> ") - subproc.stdin.write(b"raise SystemExit\n") - data = yield subproc.stdout.read_until_close() - self.assertEqual(data, b"") - - @gen_test - def test_close_stdin(self): - # Close the parent's stdin handle and see that the child recognizes it. - subproc = Subprocess( - [sys.executable, "-u", "-i"], - stdin=Subprocess.STREAM, - stdout=Subprocess.STREAM, - stderr=subprocess.STDOUT, - ) - self.addCleanup(lambda: self.term_and_wait(subproc)) - yield subproc.stdout.read_until(b">>> ") - subproc.stdin.close() - data = yield subproc.stdout.read_until_close() - self.assertEqual(data, b"\n") - - @gen_test - def test_stderr(self): - # This test is mysteriously flaky on twisted: it succeeds, but logs - # an error of EBADF on closing a file descriptor. - subproc = Subprocess( - [sys.executable, "-u", "-c", r"import sys; sys.stderr.write('hello\n')"], - stderr=Subprocess.STREAM, - ) - self.addCleanup(lambda: self.term_and_wait(subproc)) - data = yield subproc.stderr.read_until(b"\n") - self.assertEqual(data, b"hello\n") - # More mysterious EBADF: This fails if done with self.addCleanup instead of here. - subproc.stderr.close() - - def test_sigchild(self): - Subprocess.initialize() - self.addCleanup(Subprocess.uninitialize) - subproc = Subprocess([sys.executable, "-c", "pass"]) - subproc.set_exit_callback(self.stop) - ret = self.wait() - self.assertEqual(ret, 0) - self.assertEqual(subproc.returncode, ret) - - @gen_test - def test_sigchild_future(self): - Subprocess.initialize() - self.addCleanup(Subprocess.uninitialize) - subproc = Subprocess([sys.executable, "-c", "pass"]) - ret = yield subproc.wait_for_exit() - self.assertEqual(ret, 0) - self.assertEqual(subproc.returncode, ret) - - def test_sigchild_signal(self): - Subprocess.initialize() - self.addCleanup(Subprocess.uninitialize) - subproc = Subprocess( - [sys.executable, "-c", "import time; time.sleep(30)"], - stdout=Subprocess.STREAM, - ) - self.addCleanup(subproc.stdout.close) - subproc.set_exit_callback(self.stop) - - # For unclear reasons, killing a process too soon after - # creating it can result in an exit status corresponding to - # SIGKILL instead of the actual signal involved. This has been - # observed on macOS 10.15 with Python 3.8 installed via brew, - # but not with the system-installed Python 3.7. - time.sleep(0.1) - - os.kill(subproc.pid, signal.SIGTERM) - try: - ret = self.wait() - except AssertionError: - # We failed to get the termination signal. This test is - # occasionally flaky on pypy, so try to get a little more - # information: did the process close its stdout - # (indicating that the problem is in the parent process's - # signal handling) or did the child process somehow fail - # to terminate? - fut = subproc.stdout.read_until_close() - fut.add_done_callback(lambda f: self.stop()) # type: ignore - try: - self.wait() - except AssertionError: - raise AssertionError("subprocess failed to terminate") - else: - raise AssertionError( - "subprocess closed stdout but failed to " "get termination signal" - ) - self.assertEqual(subproc.returncode, ret) - self.assertEqual(ret, -signal.SIGTERM) - - @gen_test - def test_wait_for_exit_raise(self): - Subprocess.initialize() - self.addCleanup(Subprocess.uninitialize) - subproc = Subprocess([sys.executable, "-c", "import sys; sys.exit(1)"]) - with self.assertRaises(subprocess.CalledProcessError) as cm: - yield subproc.wait_for_exit() - self.assertEqual(cm.exception.returncode, 1) - - @gen_test - def test_wait_for_exit_raise_disabled(self): - Subprocess.initialize() - self.addCleanup(Subprocess.uninitialize) - subproc = Subprocess([sys.executable, "-c", "import sys; sys.exit(1)"]) - ret = yield subproc.wait_for_exit(raise_error=False) - self.assertEqual(ret, 1) diff --git a/venv/lib/python3.8/site-packages/tornado/test/queues_test.py b/venv/lib/python3.8/site-packages/tornado/test/queues_test.py deleted file mode 100644 index 98a29a8..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/queues_test.py +++ /dev/null @@ -1,431 +0,0 @@ -# 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. - -import asyncio -from datetime import timedelta -from random import random -import unittest - -from tornado import gen, queues -from tornado.gen import TimeoutError -from tornado.testing import gen_test, AsyncTestCase - - -class QueueBasicTest(AsyncTestCase): - def test_repr_and_str(self): - q = queues.Queue(maxsize=1) # type: queues.Queue[None] - self.assertIn(hex(id(q)), repr(q)) - self.assertNotIn(hex(id(q)), str(q)) - q.get() - - for q_str in repr(q), str(q): - self.assertTrue(q_str.startswith("<Queue")) - self.assertIn("maxsize=1", q_str) - self.assertIn("getters[1]", q_str) - self.assertNotIn("putters", q_str) - self.assertNotIn("tasks", q_str) - - q.put(None) - q.put(None) - # Now the queue is full, this putter blocks. - q.put(None) - - for q_str in repr(q), str(q): - self.assertNotIn("getters", q_str) - self.assertIn("putters[1]", q_str) - self.assertIn("tasks=2", q_str) - - def test_order(self): - q = queues.Queue() # type: queues.Queue[int] - for i in [1, 3, 2]: - q.put_nowait(i) - - items = [q.get_nowait() for _ in range(3)] - self.assertEqual([1, 3, 2], items) - - @gen_test - def test_maxsize(self): - self.assertRaises(TypeError, queues.Queue, maxsize=None) - self.assertRaises(ValueError, queues.Queue, maxsize=-1) - - q = queues.Queue(maxsize=2) # type: queues.Queue[int] - self.assertTrue(q.empty()) - self.assertFalse(q.full()) - self.assertEqual(2, q.maxsize) - self.assertTrue(q.put(0).done()) - self.assertTrue(q.put(1).done()) - self.assertFalse(q.empty()) - self.assertTrue(q.full()) - put2 = q.put(2) - self.assertFalse(put2.done()) - self.assertEqual(0, (yield q.get())) # Make room. - self.assertTrue(put2.done()) - self.assertFalse(q.empty()) - self.assertTrue(q.full()) - - -class QueueGetTest(AsyncTestCase): - @gen_test - def test_blocking_get(self): - q = queues.Queue() # type: queues.Queue[int] - q.put_nowait(0) - self.assertEqual(0, (yield q.get())) - - def test_nonblocking_get(self): - q = queues.Queue() # type: queues.Queue[int] - q.put_nowait(0) - self.assertEqual(0, q.get_nowait()) - - def test_nonblocking_get_exception(self): - q = queues.Queue() # type: queues.Queue[int] - self.assertRaises(queues.QueueEmpty, q.get_nowait) - - @gen_test - def test_get_with_putters(self): - q = queues.Queue(1) # type: queues.Queue[int] - q.put_nowait(0) - put = q.put(1) - self.assertEqual(0, (yield q.get())) - self.assertIsNone((yield put)) - - @gen_test - def test_blocking_get_wait(self): - q = queues.Queue() # type: queues.Queue[int] - q.put(0) - self.io_loop.call_later(0.01, q.put_nowait, 1) - self.io_loop.call_later(0.02, q.put_nowait, 2) - self.assertEqual(0, (yield q.get(timeout=timedelta(seconds=1)))) - self.assertEqual(1, (yield q.get(timeout=timedelta(seconds=1)))) - - @gen_test - def test_get_timeout(self): - q = queues.Queue() # type: queues.Queue[int] - get_timeout = q.get(timeout=timedelta(seconds=0.01)) - get = q.get() - with self.assertRaises(TimeoutError): - yield get_timeout - - q.put_nowait(0) - self.assertEqual(0, (yield get)) - - @gen_test - def test_get_timeout_preempted(self): - q = queues.Queue() # type: queues.Queue[int] - get = q.get(timeout=timedelta(seconds=0.01)) - q.put(0) - yield gen.sleep(0.02) - self.assertEqual(0, (yield get)) - - @gen_test - def test_get_clears_timed_out_putters(self): - q = queues.Queue(1) # type: queues.Queue[int] - # First putter succeeds, remainder block. - putters = [q.put(i, timedelta(seconds=0.01)) for i in range(10)] - put = q.put(10) - self.assertEqual(10, len(q._putters)) - yield gen.sleep(0.02) - self.assertEqual(10, len(q._putters)) - self.assertFalse(put.done()) # Final waiter is still active. - q.put(11) - self.assertEqual(0, (yield q.get())) # get() clears the waiters. - self.assertEqual(1, len(q._putters)) - for putter in putters[1:]: - self.assertRaises(TimeoutError, putter.result) - - @gen_test - def test_get_clears_timed_out_getters(self): - q = queues.Queue() # type: queues.Queue[int] - getters = [ - asyncio.ensure_future(q.get(timedelta(seconds=0.01))) for _ in range(10) - ] - get = asyncio.ensure_future(q.get()) - self.assertEqual(11, len(q._getters)) - yield gen.sleep(0.02) - self.assertEqual(11, len(q._getters)) - self.assertFalse(get.done()) # Final waiter is still active. - q.get() # get() clears the waiters. - self.assertEqual(2, len(q._getters)) - for getter in getters: - self.assertRaises(TimeoutError, getter.result) - - @gen_test - def test_async_for(self): - q = queues.Queue() # type: queues.Queue[int] - for i in range(5): - q.put(i) - - async def f(): - results = [] - async for i in q: - results.append(i) - if i == 4: - return results - - results = yield f() - self.assertEqual(results, list(range(5))) - - -class QueuePutTest(AsyncTestCase): - @gen_test - def test_blocking_put(self): - q = queues.Queue() # type: queues.Queue[int] - q.put(0) - self.assertEqual(0, q.get_nowait()) - - def test_nonblocking_put_exception(self): - q = queues.Queue(1) # type: queues.Queue[int] - q.put(0) - self.assertRaises(queues.QueueFull, q.put_nowait, 1) - - @gen_test - def test_put_with_getters(self): - q = queues.Queue() # type: queues.Queue[int] - get0 = q.get() - get1 = q.get() - yield q.put(0) - self.assertEqual(0, (yield get0)) - yield q.put(1) - self.assertEqual(1, (yield get1)) - - @gen_test - def test_nonblocking_put_with_getters(self): - q = queues.Queue() # type: queues.Queue[int] - get0 = q.get() - get1 = q.get() - q.put_nowait(0) - # put_nowait does *not* immediately unblock getters. - yield gen.moment - self.assertEqual(0, (yield get0)) - q.put_nowait(1) - yield gen.moment - self.assertEqual(1, (yield get1)) - - @gen_test - def test_blocking_put_wait(self): - q = queues.Queue(1) # type: queues.Queue[int] - q.put_nowait(0) - - def get_and_discard(): - q.get() - - self.io_loop.call_later(0.01, get_and_discard) - self.io_loop.call_later(0.02, get_and_discard) - futures = [q.put(0), q.put(1)] - self.assertFalse(any(f.done() for f in futures)) - yield futures - - @gen_test - def test_put_timeout(self): - q = queues.Queue(1) # type: queues.Queue[int] - q.put_nowait(0) # Now it's full. - put_timeout = q.put(1, timeout=timedelta(seconds=0.01)) - put = q.put(2) - with self.assertRaises(TimeoutError): - yield put_timeout - - self.assertEqual(0, q.get_nowait()) - # 1 was never put in the queue. - self.assertEqual(2, (yield q.get())) - - # Final get() unblocked this putter. - yield put - - @gen_test - def test_put_timeout_preempted(self): - q = queues.Queue(1) # type: queues.Queue[int] - q.put_nowait(0) - put = q.put(1, timeout=timedelta(seconds=0.01)) - q.get() - yield gen.sleep(0.02) - yield put # No TimeoutError. - - @gen_test - def test_put_clears_timed_out_putters(self): - q = queues.Queue(1) # type: queues.Queue[int] - # First putter succeeds, remainder block. - putters = [q.put(i, timedelta(seconds=0.01)) for i in range(10)] - put = q.put(10) - self.assertEqual(10, len(q._putters)) - yield gen.sleep(0.02) - self.assertEqual(10, len(q._putters)) - self.assertFalse(put.done()) # Final waiter is still active. - q.put(11) # put() clears the waiters. - self.assertEqual(2, len(q._putters)) - for putter in putters[1:]: - self.assertRaises(TimeoutError, putter.result) - - @gen_test - def test_put_clears_timed_out_getters(self): - q = queues.Queue() # type: queues.Queue[int] - getters = [ - asyncio.ensure_future(q.get(timedelta(seconds=0.01))) for _ in range(10) - ] - get = asyncio.ensure_future(q.get()) - q.get() - self.assertEqual(12, len(q._getters)) - yield gen.sleep(0.02) - self.assertEqual(12, len(q._getters)) - self.assertFalse(get.done()) # Final waiters still active. - q.put(0) # put() clears the waiters. - self.assertEqual(1, len(q._getters)) - self.assertEqual(0, (yield get)) - for getter in getters: - self.assertRaises(TimeoutError, getter.result) - - @gen_test - def test_float_maxsize(self): - # If a float is passed for maxsize, a reasonable limit should - # be enforced, instead of being treated as unlimited. - # It happens to be rounded up. - # http://bugs.python.org/issue21723 - q = queues.Queue(maxsize=1.3) # type: ignore - self.assertTrue(q.empty()) - self.assertFalse(q.full()) - q.put_nowait(0) - q.put_nowait(1) - self.assertFalse(q.empty()) - self.assertTrue(q.full()) - self.assertRaises(queues.QueueFull, q.put_nowait, 2) - self.assertEqual(0, q.get_nowait()) - self.assertFalse(q.empty()) - self.assertFalse(q.full()) - - yield q.put(2) - put = q.put(3) - self.assertFalse(put.done()) - self.assertEqual(1, (yield q.get())) - yield put - self.assertTrue(q.full()) - - -class QueueJoinTest(AsyncTestCase): - queue_class = queues.Queue - - def test_task_done_underflow(self): - q = self.queue_class() # type: queues.Queue - self.assertRaises(ValueError, q.task_done) - - @gen_test - def test_task_done(self): - q = self.queue_class() # type: queues.Queue - for i in range(100): - q.put_nowait(i) - - self.accumulator = 0 - - @gen.coroutine - def worker(): - while True: - item = yield q.get() - self.accumulator += item - q.task_done() - yield gen.sleep(random() * 0.01) - - # Two coroutines share work. - worker() - worker() - yield q.join() - self.assertEqual(sum(range(100)), self.accumulator) - - @gen_test - def test_task_done_delay(self): - # Verify it is task_done(), not get(), that unblocks join(). - q = self.queue_class() # type: queues.Queue - q.put_nowait(0) - join = asyncio.ensure_future(q.join()) - self.assertFalse(join.done()) - yield q.get() - self.assertFalse(join.done()) - yield gen.moment - self.assertFalse(join.done()) - q.task_done() - self.assertTrue(join.done()) - - @gen_test - def test_join_empty_queue(self): - q = self.queue_class() # type: queues.Queue - yield q.join() - yield q.join() - - @gen_test - def test_join_timeout(self): - q = self.queue_class() # type: queues.Queue - q.put(0) - with self.assertRaises(TimeoutError): - yield q.join(timeout=timedelta(seconds=0.01)) - - -class PriorityQueueJoinTest(QueueJoinTest): - queue_class = queues.PriorityQueue - - @gen_test - def test_order(self): - q = self.queue_class(maxsize=2) - q.put_nowait((1, "a")) - q.put_nowait((0, "b")) - self.assertTrue(q.full()) - q.put((3, "c")) - q.put((2, "d")) - self.assertEqual((0, "b"), q.get_nowait()) - self.assertEqual((1, "a"), (yield q.get())) - self.assertEqual((2, "d"), q.get_nowait()) - self.assertEqual((3, "c"), (yield q.get())) - self.assertTrue(q.empty()) - - -class LifoQueueJoinTest(QueueJoinTest): - queue_class = queues.LifoQueue - - @gen_test - def test_order(self): - q = self.queue_class(maxsize=2) - q.put_nowait(1) - q.put_nowait(0) - self.assertTrue(q.full()) - q.put(3) - q.put(2) - self.assertEqual(3, q.get_nowait()) - self.assertEqual(2, (yield q.get())) - self.assertEqual(0, q.get_nowait()) - self.assertEqual(1, (yield q.get())) - self.assertTrue(q.empty()) - - -class ProducerConsumerTest(AsyncTestCase): - @gen_test - def test_producer_consumer(self): - q = queues.Queue(maxsize=3) # type: queues.Queue[int] - history = [] - - # We don't yield between get() and task_done(), so get() must wait for - # the next tick. Otherwise we'd immediately call task_done and unblock - # join() before q.put() resumes, and we'd only process the first four - # items. - @gen.coroutine - def consumer(): - while True: - history.append((yield q.get())) - q.task_done() - - @gen.coroutine - def producer(): - for item in range(10): - yield q.put(item) - - consumer() - yield producer() - yield q.join() - self.assertEqual(list(range(10)), history) - - -if __name__ == "__main__": - unittest.main() diff --git a/venv/lib/python3.8/site-packages/tornado/test/resolve_test_helper.py b/venv/lib/python3.8/site-packages/tornado/test/resolve_test_helper.py deleted file mode 100644 index 491737f..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/resolve_test_helper.py +++ /dev/null @@ -1,10 +0,0 @@ -from tornado.ioloop import IOLoop -from tornado.netutil import ThreadedResolver - -# When this module is imported, it runs getaddrinfo on a thread. Since -# the hostname is unicode, getaddrinfo attempts to import encodings.idna -# but blocks on the import lock. Verify that ThreadedResolver avoids -# this deadlock. - -resolver = ThreadedResolver() -IOLoop.current().run_sync(lambda: resolver.resolve(u"localhost", 80)) diff --git a/venv/lib/python3.8/site-packages/tornado/test/routing_test.py b/venv/lib/python3.8/site-packages/tornado/test/routing_test.py deleted file mode 100644 index 6e02697..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/routing_test.py +++ /dev/null @@ -1,276 +0,0 @@ -# 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. - -from tornado.httputil import ( - HTTPHeaders, - HTTPMessageDelegate, - HTTPServerConnectionDelegate, - ResponseStartLine, -) -from tornado.routing import ( - HostMatches, - PathMatches, - ReversibleRouter, - Router, - Rule, - RuleRouter, -) -from tornado.testing import AsyncHTTPTestCase -from tornado.web import Application, HTTPError, RequestHandler -from tornado.wsgi import WSGIContainer - -import typing # noqa: F401 - - -class BasicRouter(Router): - def find_handler(self, request, **kwargs): - class MessageDelegate(HTTPMessageDelegate): - def __init__(self, connection): - self.connection = connection - - def finish(self): - self.connection.write_headers( - ResponseStartLine("HTTP/1.1", 200, "OK"), - HTTPHeaders({"Content-Length": "2"}), - b"OK", - ) - self.connection.finish() - - return MessageDelegate(request.connection) - - -class BasicRouterTestCase(AsyncHTTPTestCase): - def get_app(self): - return BasicRouter() - - def test_basic_router(self): - response = self.fetch("/any_request") - self.assertEqual(response.body, b"OK") - - -resources = {} # type: typing.Dict[str, bytes] - - -class GetResource(RequestHandler): - def get(self, path): - if path not in resources: - raise HTTPError(404) - - self.finish(resources[path]) - - -class PostResource(RequestHandler): - def post(self, path): - resources[path] = self.request.body - - -class HTTPMethodRouter(Router): - def __init__(self, app): - self.app = app - - def find_handler(self, request, **kwargs): - handler = GetResource if request.method == "GET" else PostResource - return self.app.get_handler_delegate(request, handler, path_args=[request.path]) - - -class HTTPMethodRouterTestCase(AsyncHTTPTestCase): - def get_app(self): - return HTTPMethodRouter(Application()) - - def test_http_method_router(self): - response = self.fetch("/post_resource", method="POST", body="data") - self.assertEqual(response.code, 200) - - response = self.fetch("/get_resource") - self.assertEqual(response.code, 404) - - response = self.fetch("/post_resource") - self.assertEqual(response.code, 200) - self.assertEqual(response.body, b"data") - - -def _get_named_handler(handler_name): - class Handler(RequestHandler): - def get(self, *args, **kwargs): - if self.application.settings.get("app_name") is not None: - self.write(self.application.settings["app_name"] + ": ") - - self.finish(handler_name + ": " + self.reverse_url(handler_name)) - - return Handler - - -FirstHandler = _get_named_handler("first_handler") -SecondHandler = _get_named_handler("second_handler") - - -class CustomRouter(ReversibleRouter): - def __init__(self): - super().__init__() - self.routes = {} # type: typing.Dict[str, typing.Any] - - def add_routes(self, routes): - self.routes.update(routes) - - def find_handler(self, request, **kwargs): - if request.path in self.routes: - app, handler = self.routes[request.path] - return app.get_handler_delegate(request, handler) - - def reverse_url(self, name, *args): - handler_path = "/" + name - return handler_path if handler_path in self.routes else None - - -class CustomRouterTestCase(AsyncHTTPTestCase): - def get_app(self): - router = CustomRouter() - - class CustomApplication(Application): - def reverse_url(self, name, *args): - return router.reverse_url(name, *args) - - app1 = CustomApplication(app_name="app1") - app2 = CustomApplication(app_name="app2") - - router.add_routes( - { - "/first_handler": (app1, FirstHandler), - "/second_handler": (app2, SecondHandler), - "/first_handler_second_app": (app2, FirstHandler), - } - ) - - return router - - def test_custom_router(self): - response = self.fetch("/first_handler") - self.assertEqual(response.body, b"app1: first_handler: /first_handler") - response = self.fetch("/second_handler") - self.assertEqual(response.body, b"app2: second_handler: /second_handler") - response = self.fetch("/first_handler_second_app") - self.assertEqual(response.body, b"app2: first_handler: /first_handler") - - -class ConnectionDelegate(HTTPServerConnectionDelegate): - def start_request(self, server_conn, request_conn): - class MessageDelegate(HTTPMessageDelegate): - def __init__(self, connection): - self.connection = connection - - def finish(self): - response_body = b"OK" - self.connection.write_headers( - ResponseStartLine("HTTP/1.1", 200, "OK"), - HTTPHeaders({"Content-Length": str(len(response_body))}), - ) - self.connection.write(response_body) - self.connection.finish() - - return MessageDelegate(request_conn) - - -class RuleRouterTest(AsyncHTTPTestCase): - def get_app(self): - app = Application() - - def request_callable(request): - request.connection.write_headers( - ResponseStartLine("HTTP/1.1", 200, "OK"), - HTTPHeaders({"Content-Length": "2"}), - ) - request.connection.write(b"OK") - request.connection.finish() - - router = CustomRouter() - router.add_routes( - {"/nested_handler": (app, _get_named_handler("nested_handler"))} - ) - - app.add_handlers( - ".*", - [ - ( - HostMatches("www.example.com"), - [ - ( - PathMatches("/first_handler"), - "tornado.test.routing_test.SecondHandler", - {}, - "second_handler", - ) - ], - ), - Rule(PathMatches("/.*handler"), router), - Rule(PathMatches("/first_handler"), FirstHandler, name="first_handler"), - Rule(PathMatches("/request_callable"), request_callable), - ("/connection_delegate", ConnectionDelegate()), - ], - ) - - return app - - def test_rule_based_router(self): - response = self.fetch("/first_handler") - self.assertEqual(response.body, b"first_handler: /first_handler") - - response = self.fetch("/first_handler", headers={"Host": "www.example.com"}) - self.assertEqual(response.body, b"second_handler: /first_handler") - - response = self.fetch("/nested_handler") - self.assertEqual(response.body, b"nested_handler: /nested_handler") - - response = self.fetch("/nested_not_found_handler") - self.assertEqual(response.code, 404) - - response = self.fetch("/connection_delegate") - self.assertEqual(response.body, b"OK") - - response = self.fetch("/request_callable") - self.assertEqual(response.body, b"OK") - - response = self.fetch("/404") - self.assertEqual(response.code, 404) - - -class WSGIContainerTestCase(AsyncHTTPTestCase): - def get_app(self): - wsgi_app = WSGIContainer(self.wsgi_app) - - class Handler(RequestHandler): - def get(self, *args, **kwargs): - self.finish(self.reverse_url("tornado")) - - return RuleRouter( - [ - ( - PathMatches("/tornado.*"), - Application([(r"/tornado/test", Handler, {}, "tornado")]), - ), - (PathMatches("/wsgi"), wsgi_app), - ] - ) - - def wsgi_app(self, environ, start_response): - start_response("200 OK", []) - return [b"WSGI"] - - def test_wsgi_container(self): - response = self.fetch("/tornado/test") - self.assertEqual(response.body, b"/tornado/test") - - response = self.fetch("/wsgi") - self.assertEqual(response.body, b"WSGI") - - def test_delegate_not_found(self): - response = self.fetch("/404") - self.assertEqual(response.code, 404) diff --git a/venv/lib/python3.8/site-packages/tornado/test/runtests.py b/venv/lib/python3.8/site-packages/tornado/test/runtests.py deleted file mode 100644 index 6075b1e..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/runtests.py +++ /dev/null @@ -1,241 +0,0 @@ -from functools import reduce -import gc -import io -import locale # system locale module, not tornado.locale -import logging -import operator -import textwrap -import sys -import unittest -import warnings - -from tornado.httpclient import AsyncHTTPClient -from tornado.httpserver import HTTPServer -from tornado.netutil import Resolver -from tornado.options import define, add_parse_callback, options - - -TEST_MODULES = [ - "tornado.httputil.doctests", - "tornado.iostream.doctests", - "tornado.util.doctests", - "tornado.test.asyncio_test", - "tornado.test.auth_test", - "tornado.test.autoreload_test", - "tornado.test.concurrent_test", - "tornado.test.curl_httpclient_test", - "tornado.test.escape_test", - "tornado.test.gen_test", - "tornado.test.http1connection_test", - "tornado.test.httpclient_test", - "tornado.test.httpserver_test", - "tornado.test.httputil_test", - "tornado.test.import_test", - "tornado.test.ioloop_test", - "tornado.test.iostream_test", - "tornado.test.locale_test", - "tornado.test.locks_test", - "tornado.test.netutil_test", - "tornado.test.log_test", - "tornado.test.options_test", - "tornado.test.process_test", - "tornado.test.queues_test", - "tornado.test.routing_test", - "tornado.test.simple_httpclient_test", - "tornado.test.tcpclient_test", - "tornado.test.tcpserver_test", - "tornado.test.template_test", - "tornado.test.testing_test", - "tornado.test.twisted_test", - "tornado.test.util_test", - "tornado.test.web_test", - "tornado.test.websocket_test", - "tornado.test.wsgi_test", -] - - -def all(): - return unittest.defaultTestLoader.loadTestsFromNames(TEST_MODULES) - - -def test_runner_factory(stderr): - class TornadoTextTestRunner(unittest.TextTestRunner): - def __init__(self, *args, **kwargs): - kwargs["stream"] = stderr - super().__init__(*args, **kwargs) - - def run(self, test): - result = super().run(test) - if result.skipped: - skip_reasons = set(reason for (test, reason) in result.skipped) - self.stream.write( # type: ignore - textwrap.fill( - "Some tests were skipped because: %s" - % ", ".join(sorted(skip_reasons)) - ) - ) - self.stream.write("\n") # type: ignore - return result - - return TornadoTextTestRunner - - -class LogCounter(logging.Filter): - """Counts the number of WARNING or higher log records.""" - - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.info_count = self.warning_count = self.error_count = 0 - - def filter(self, record): - if record.levelno >= logging.ERROR: - self.error_count += 1 - elif record.levelno >= logging.WARNING: - self.warning_count += 1 - elif record.levelno >= logging.INFO: - self.info_count += 1 - return True - - -class CountingStderr(io.IOBase): - def __init__(self, real): - self.real = real - self.byte_count = 0 - - def write(self, data): - self.byte_count += len(data) - return self.real.write(data) - - def flush(self): - return self.real.flush() - - -def main(): - # Be strict about most warnings (This is set in our test running - # scripts to catch import-time warnings, but set it again here to - # be sure). This also turns on warnings that are ignored by - # default, including DeprecationWarnings and python 3.2's - # ResourceWarnings. - warnings.filterwarnings("error") - # setuptools sometimes gives ImportWarnings about things that are on - # sys.path even if they're not being used. - warnings.filterwarnings("ignore", category=ImportWarning) - # Tornado generally shouldn't use anything deprecated, but some of - # our dependencies do (last match wins). - warnings.filterwarnings("ignore", category=DeprecationWarning) - warnings.filterwarnings("error", category=DeprecationWarning, module=r"tornado\..*") - warnings.filterwarnings("ignore", category=PendingDeprecationWarning) - warnings.filterwarnings( - "error", category=PendingDeprecationWarning, module=r"tornado\..*" - ) - # The unittest module is aggressive about deprecating redundant methods, - # leaving some without non-deprecated spellings that work on both - # 2.7 and 3.2 - warnings.filterwarnings( - "ignore", category=DeprecationWarning, message="Please use assert.* instead" - ) - warnings.filterwarnings( - "ignore", - category=PendingDeprecationWarning, - message="Please use assert.* instead", - ) - # Twisted 15.0.0 triggers some warnings on py3 with -bb. - warnings.filterwarnings("ignore", category=BytesWarning, module=r"twisted\..*") - if (3,) < sys.version_info < (3, 6): - # Prior to 3.6, async ResourceWarnings were rather noisy - # and even - # `python3.4 -W error -c 'import asyncio; asyncio.get_event_loop()'` - # would generate a warning. - warnings.filterwarnings( - "ignore", category=ResourceWarning, module=r"asyncio\..*" - ) - # This deprecation warning is introduced in Python 3.8 and is - # triggered by pycurl. Unforunately, because it is raised in the C - # layer it can't be filtered by module and we must match the - # message text instead (Tornado's C module uses PY_SSIZE_T_CLEAN - # so it's not at risk of running into this issue). - warnings.filterwarnings( - "ignore", - category=DeprecationWarning, - message="PY_SSIZE_T_CLEAN will be required", - ) - - logging.getLogger("tornado.access").setLevel(logging.CRITICAL) - - define( - "httpclient", - type=str, - default=None, - callback=lambda s: AsyncHTTPClient.configure( - s, defaults=dict(allow_ipv6=False) - ), - ) - define("httpserver", type=str, default=None, callback=HTTPServer.configure) - define("resolver", type=str, default=None, callback=Resolver.configure) - define( - "debug_gc", - type=str, - multiple=True, - help="A comma-separated list of gc module debug constants, " - "e.g. DEBUG_STATS or DEBUG_COLLECTABLE,DEBUG_OBJECTS", - callback=lambda values: gc.set_debug( - reduce(operator.or_, (getattr(gc, v) for v in values)) - ), - ) - define( - "fail-if-logs", - default=True, - help="If true, fail the tests if any log output is produced (unless captured by ExpectLog)", - ) - - def set_locale(x): - locale.setlocale(locale.LC_ALL, x) - - define("locale", type=str, default=None, callback=set_locale) - - log_counter = LogCounter() - add_parse_callback(lambda: logging.getLogger().handlers[0].addFilter(log_counter)) - - # Certain errors (especially "unclosed resource" errors raised in - # destructors) go directly to stderr instead of logging. Count - # anything written by anything but the test runner as an error. - orig_stderr = sys.stderr - counting_stderr = CountingStderr(orig_stderr) - sys.stderr = counting_stderr # type: ignore - - import tornado.testing - - kwargs = {} - - # HACK: unittest.main will make its own changes to the warning - # configuration, which may conflict with the settings above - # or command-line flags like -bb. Passing warnings=False - # suppresses this behavior, although this looks like an implementation - # detail. http://bugs.python.org/issue15626 - kwargs["warnings"] = False - - kwargs["testRunner"] = test_runner_factory(orig_stderr) - try: - tornado.testing.main(**kwargs) - finally: - # The tests should run clean; consider it a failure if they - # logged anything at info level or above. - if ( - log_counter.info_count > 0 - or log_counter.warning_count > 0 - or log_counter.error_count > 0 - or counting_stderr.byte_count > 0 - ): - logging.error( - "logged %d infos, %d warnings, %d errors, and %d bytes to stderr", - log_counter.info_count, - log_counter.warning_count, - log_counter.error_count, - counting_stderr.byte_count, - ) - if options.fail_if_logs: - sys.exit(1) - - -if __name__ == "__main__": - main() diff --git a/venv/lib/python3.8/site-packages/tornado/test/simple_httpclient_test.py b/venv/lib/python3.8/site-packages/tornado/test/simple_httpclient_test.py deleted file mode 100644 index eadd4ed..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/simple_httpclient_test.py +++ /dev/null @@ -1,834 +0,0 @@ -import collections -from contextlib import closing -import errno -import logging -import os -import re -import socket -import ssl -import sys -import typing # noqa: F401 - -from tornado.escape import to_unicode, utf8 -from tornado import gen, version -from tornado.httpclient import AsyncHTTPClient -from tornado.httputil import HTTPHeaders, ResponseStartLine -from tornado.ioloop import IOLoop -from tornado.iostream import UnsatisfiableReadError -from tornado.locks import Event -from tornado.log import gen_log -from tornado.netutil import Resolver, bind_sockets -from tornado.simple_httpclient import ( - SimpleAsyncHTTPClient, - HTTPStreamClosedError, - HTTPTimeoutError, -) -from tornado.test.httpclient_test import ( - ChunkHandler, - CountdownHandler, - HelloWorldHandler, - RedirectHandler, - UserAgentHandler, -) -from tornado.test import httpclient_test -from tornado.testing import ( - AsyncHTTPTestCase, - AsyncHTTPSTestCase, - AsyncTestCase, - ExpectLog, - gen_test, -) -from tornado.test.util import skipOnTravis, skipIfNoIPv6, refusing_port -from tornado.web import RequestHandler, Application, url, stream_request_body - - -class SimpleHTTPClientCommonTestCase(httpclient_test.HTTPClientCommonTestCase): - def get_http_client(self): - client = SimpleAsyncHTTPClient(force_instance=True) - self.assertTrue(isinstance(client, SimpleAsyncHTTPClient)) - return client - - -class TriggerHandler(RequestHandler): - def initialize(self, queue, wake_callback): - self.queue = queue - self.wake_callback = wake_callback - - @gen.coroutine - def get(self): - logging.debug("queuing trigger") - event = Event() - self.queue.append(event.set) - if self.get_argument("wake", "true") == "true": - self.wake_callback() - yield event.wait() - - -class ContentLengthHandler(RequestHandler): - def get(self): - self.stream = self.detach() - IOLoop.current().spawn_callback(self.write_response) - - @gen.coroutine - def write_response(self): - yield self.stream.write( - utf8( - "HTTP/1.0 200 OK\r\nContent-Length: %s\r\n\r\nok" - % self.get_argument("value") - ) - ) - self.stream.close() - - -class HeadHandler(RequestHandler): - def head(self): - self.set_header("Content-Length", "7") - - -class OptionsHandler(RequestHandler): - def options(self): - self.set_header("Access-Control-Allow-Origin", "*") - self.write("ok") - - -class NoContentHandler(RequestHandler): - def get(self): - self.set_status(204) - self.finish() - - -class SeeOtherPostHandler(RequestHandler): - def post(self): - redirect_code = int(self.request.body) - assert redirect_code in (302, 303), "unexpected body %r" % self.request.body - self.set_header("Location", "/see_other_get") - self.set_status(redirect_code) - - -class SeeOtherGetHandler(RequestHandler): - def get(self): - if self.request.body: - raise Exception("unexpected body %r" % self.request.body) - self.write("ok") - - -class HostEchoHandler(RequestHandler): - def get(self): - self.write(self.request.headers["Host"]) - - -class NoContentLengthHandler(RequestHandler): - def get(self): - if self.request.version.startswith("HTTP/1"): - # Emulate the old HTTP/1.0 behavior of returning a body with no - # content-length. Tornado handles content-length at the framework - # level so we have to go around it. - stream = self.detach() - stream.write(b"HTTP/1.0 200 OK\r\n\r\n" b"hello") - stream.close() - else: - self.finish("HTTP/1 required") - - -class EchoPostHandler(RequestHandler): - def post(self): - self.write(self.request.body) - - -@stream_request_body -class RespondInPrepareHandler(RequestHandler): - def prepare(self): - self.set_status(403) - self.finish("forbidden") - - -class SimpleHTTPClientTestMixin(object): - def create_client(self, **kwargs): - raise NotImplementedError() - - def get_app(self: typing.Any): - # callable objects to finish pending /trigger requests - self.triggers = ( - collections.deque() - ) # type: typing.Deque[typing.Callable[[], None]] - return Application( - [ - url( - "/trigger", - TriggerHandler, - dict(queue=self.triggers, wake_callback=self.stop), - ), - url("/chunk", ChunkHandler), - url("/countdown/([0-9]+)", CountdownHandler, name="countdown"), - url("/hello", HelloWorldHandler), - url("/content_length", ContentLengthHandler), - url("/head", HeadHandler), - url("/options", OptionsHandler), - url("/no_content", NoContentHandler), - url("/see_other_post", SeeOtherPostHandler), - url("/see_other_get", SeeOtherGetHandler), - url("/host_echo", HostEchoHandler), - url("/no_content_length", NoContentLengthHandler), - url("/echo_post", EchoPostHandler), - url("/respond_in_prepare", RespondInPrepareHandler), - url("/redirect", RedirectHandler), - url("/user_agent", UserAgentHandler), - ], - gzip=True, - ) - - def test_singleton(self: typing.Any): - # Class "constructor" reuses objects on the same IOLoop - self.assertTrue(SimpleAsyncHTTPClient() is SimpleAsyncHTTPClient()) - # unless force_instance is used - self.assertTrue( - SimpleAsyncHTTPClient() is not SimpleAsyncHTTPClient(force_instance=True) - ) - # different IOLoops use different objects - with closing(IOLoop()) as io_loop2: - - async def make_client(): - await gen.sleep(0) - return SimpleAsyncHTTPClient() - - client1 = self.io_loop.run_sync(make_client) - client2 = io_loop2.run_sync(make_client) - self.assertTrue(client1 is not client2) - - def test_connection_limit(self: typing.Any): - with closing(self.create_client(max_clients=2)) as client: - self.assertEqual(client.max_clients, 2) - seen = [] - # Send 4 requests. Two can be sent immediately, while the others - # will be queued - for i in range(4): - - def cb(fut, i=i): - seen.append(i) - self.stop() - - client.fetch(self.get_url("/trigger")).add_done_callback(cb) - self.wait(condition=lambda: len(self.triggers) == 2) - self.assertEqual(len(client.queue), 2) - - # Finish the first two requests and let the next two through - self.triggers.popleft()() - self.triggers.popleft()() - self.wait(condition=lambda: (len(self.triggers) == 2 and len(seen) == 2)) - self.assertEqual(set(seen), set([0, 1])) - self.assertEqual(len(client.queue), 0) - - # Finish all the pending requests - self.triggers.popleft()() - self.triggers.popleft()() - self.wait(condition=lambda: len(seen) == 4) - self.assertEqual(set(seen), set([0, 1, 2, 3])) - self.assertEqual(len(self.triggers), 0) - - @gen_test - def test_redirect_connection_limit(self: typing.Any): - # following redirects should not consume additional connections - with closing(self.create_client(max_clients=1)) as client: - response = yield client.fetch(self.get_url("/countdown/3"), max_redirects=3) - response.rethrow() - - def test_max_redirects(self: typing.Any): - response = self.fetch("/countdown/5", max_redirects=3) - self.assertEqual(302, response.code) - # We requested 5, followed three redirects for 4, 3, 2, then the last - # unfollowed redirect is to 1. - self.assertTrue(response.request.url.endswith("/countdown/5")) - self.assertTrue(response.effective_url.endswith("/countdown/2")) - self.assertTrue(response.headers["Location"].endswith("/countdown/1")) - - def test_header_reuse(self: typing.Any): - # Apps may reuse a headers object if they are only passing in constant - # headers like user-agent. The header object should not be modified. - headers = HTTPHeaders({"User-Agent": "Foo"}) - self.fetch("/hello", headers=headers) - self.assertEqual(list(headers.get_all()), [("User-Agent", "Foo")]) - - def test_default_user_agent(self: typing.Any): - response = self.fetch("/user_agent", method="GET") - self.assertEqual(200, response.code) - self.assertEqual(response.body.decode(), "Tornado/{}".format(version)) - - def test_see_other_redirect(self: typing.Any): - for code in (302, 303): - response = self.fetch("/see_other_post", method="POST", body="%d" % code) - self.assertEqual(200, response.code) - self.assertTrue(response.request.url.endswith("/see_other_post")) - self.assertTrue(response.effective_url.endswith("/see_other_get")) - # request is the original request, is a POST still - self.assertEqual("POST", response.request.method) - - @skipOnTravis - @gen_test - def test_connect_timeout(self: typing.Any): - timeout = 0.1 - - cleanup_event = Event() - test = self - - class TimeoutResolver(Resolver): - async def resolve(self, *args, **kwargs): - await cleanup_event.wait() - # Return something valid so the test doesn't raise during shutdown. - return [(socket.AF_INET, ("127.0.0.1", test.get_http_port()))] - - with closing(self.create_client(resolver=TimeoutResolver())) as client: - with self.assertRaises(HTTPTimeoutError): - yield client.fetch( - self.get_url("/hello"), - connect_timeout=timeout, - request_timeout=3600, - raise_error=True, - ) - - # Let the hanging coroutine clean up after itself. We need to - # wait more than a single IOLoop iteration for the SSL case, - # which logs errors on unexpected EOF. - cleanup_event.set() - yield gen.sleep(0.2) - - @skipOnTravis - def test_request_timeout(self: typing.Any): - timeout = 0.1 - if os.name == "nt": - timeout = 0.5 - - with self.assertRaises(HTTPTimeoutError): - self.fetch("/trigger?wake=false", request_timeout=timeout, raise_error=True) - # trigger the hanging request to let it clean up after itself - self.triggers.popleft()() - self.io_loop.run_sync(lambda: gen.sleep(0)) - - @skipIfNoIPv6 - def test_ipv6(self: typing.Any): - [sock] = bind_sockets(0, "::1", family=socket.AF_INET6) - port = sock.getsockname()[1] - self.http_server.add_socket(sock) - url = "%s://[::1]:%d/hello" % (self.get_protocol(), port) - - # ipv6 is currently enabled by default but can be disabled - with self.assertRaises(Exception): - self.fetch(url, allow_ipv6=False, raise_error=True) - - response = self.fetch(url) - self.assertEqual(response.body, b"Hello world!") - - def test_multiple_content_length_accepted(self: typing.Any): - response = self.fetch("/content_length?value=2,2") - self.assertEqual(response.body, b"ok") - response = self.fetch("/content_length?value=2,%202,2") - self.assertEqual(response.body, b"ok") - - with ExpectLog( - gen_log, ".*Multiple unequal Content-Lengths", level=logging.INFO - ): - with self.assertRaises(HTTPStreamClosedError): - self.fetch("/content_length?value=2,4", raise_error=True) - with self.assertRaises(HTTPStreamClosedError): - self.fetch("/content_length?value=2,%202,3", raise_error=True) - - def test_head_request(self: typing.Any): - response = self.fetch("/head", method="HEAD") - self.assertEqual(response.code, 200) - self.assertEqual(response.headers["content-length"], "7") - self.assertFalse(response.body) - - def test_options_request(self: typing.Any): - response = self.fetch("/options", method="OPTIONS") - self.assertEqual(response.code, 200) - self.assertEqual(response.headers["content-length"], "2") - self.assertEqual(response.headers["access-control-allow-origin"], "*") - self.assertEqual(response.body, b"ok") - - def test_no_content(self: typing.Any): - response = self.fetch("/no_content") - self.assertEqual(response.code, 204) - # 204 status shouldn't have a content-length - # - # Tests with a content-length header are included below - # in HTTP204NoContentTestCase. - self.assertNotIn("Content-Length", response.headers) - - def test_host_header(self: typing.Any): - host_re = re.compile(b"^127.0.0.1:[0-9]+$") - response = self.fetch("/host_echo") - self.assertTrue(host_re.match(response.body)) - - url = self.get_url("/host_echo").replace("http://", "http://me:secret@") - response = self.fetch(url) - self.assertTrue(host_re.match(response.body), response.body) - - def test_connection_refused(self: typing.Any): - cleanup_func, port = refusing_port() - self.addCleanup(cleanup_func) - with ExpectLog(gen_log, ".*", required=False): - with self.assertRaises(socket.error) as cm: - self.fetch("http://127.0.0.1:%d/" % port, raise_error=True) - - if sys.platform != "cygwin": - # cygwin returns EPERM instead of ECONNREFUSED here - contains_errno = str(errno.ECONNREFUSED) in str(cm.exception) - if not contains_errno and hasattr(errno, "WSAECONNREFUSED"): - contains_errno = str(errno.WSAECONNREFUSED) in str( # type: ignore - cm.exception - ) - self.assertTrue(contains_errno, cm.exception) - # This is usually "Connection refused". - # On windows, strerror is broken and returns "Unknown error". - expected_message = os.strerror(errno.ECONNREFUSED) - self.assertTrue(expected_message in str(cm.exception), cm.exception) - - def test_queue_timeout(self: typing.Any): - with closing(self.create_client(max_clients=1)) as client: - # Wait for the trigger request to block, not complete. - fut1 = client.fetch(self.get_url("/trigger"), request_timeout=10) - self.wait() - with self.assertRaises(HTTPTimeoutError) as cm: - self.io_loop.run_sync( - lambda: client.fetch( - self.get_url("/hello"), connect_timeout=0.1, raise_error=True - ) - ) - - self.assertEqual(str(cm.exception), "Timeout in request queue") - self.triggers.popleft()() - self.io_loop.run_sync(lambda: fut1) - - def test_no_content_length(self: typing.Any): - response = self.fetch("/no_content_length") - if response.body == b"HTTP/1 required": - self.skipTest("requires HTTP/1.x") - else: - self.assertEqual(b"hello", response.body) - - def sync_body_producer(self, write): - write(b"1234") - write(b"5678") - - @gen.coroutine - def async_body_producer(self, write): - yield write(b"1234") - yield gen.moment - yield write(b"5678") - - def test_sync_body_producer_chunked(self: typing.Any): - response = self.fetch( - "/echo_post", method="POST", body_producer=self.sync_body_producer - ) - response.rethrow() - self.assertEqual(response.body, b"12345678") - - def test_sync_body_producer_content_length(self: typing.Any): - response = self.fetch( - "/echo_post", - method="POST", - body_producer=self.sync_body_producer, - headers={"Content-Length": "8"}, - ) - response.rethrow() - self.assertEqual(response.body, b"12345678") - - def test_async_body_producer_chunked(self: typing.Any): - response = self.fetch( - "/echo_post", method="POST", body_producer=self.async_body_producer - ) - response.rethrow() - self.assertEqual(response.body, b"12345678") - - def test_async_body_producer_content_length(self: typing.Any): - response = self.fetch( - "/echo_post", - method="POST", - body_producer=self.async_body_producer, - headers={"Content-Length": "8"}, - ) - response.rethrow() - self.assertEqual(response.body, b"12345678") - - def test_native_body_producer_chunked(self: typing.Any): - async def body_producer(write): - await write(b"1234") - import asyncio - - await asyncio.sleep(0) - await write(b"5678") - - response = self.fetch("/echo_post", method="POST", body_producer=body_producer) - response.rethrow() - self.assertEqual(response.body, b"12345678") - - def test_native_body_producer_content_length(self: typing.Any): - async def body_producer(write): - await write(b"1234") - import asyncio - - await asyncio.sleep(0) - await write(b"5678") - - response = self.fetch( - "/echo_post", - method="POST", - body_producer=body_producer, - headers={"Content-Length": "8"}, - ) - response.rethrow() - self.assertEqual(response.body, b"12345678") - - def test_100_continue(self: typing.Any): - response = self.fetch( - "/echo_post", method="POST", body=b"1234", expect_100_continue=True - ) - self.assertEqual(response.body, b"1234") - - def test_100_continue_early_response(self: typing.Any): - def body_producer(write): - raise Exception("should not be called") - - response = self.fetch( - "/respond_in_prepare", - method="POST", - body_producer=body_producer, - expect_100_continue=True, - ) - self.assertEqual(response.code, 403) - - def test_streaming_follow_redirects(self: typing.Any): - # When following redirects, header and streaming callbacks - # should only be called for the final result. - # TODO(bdarnell): this test belongs in httpclient_test instead of - # simple_httpclient_test, but it fails with the version of libcurl - # available on travis-ci. Move it when that has been upgraded - # or we have a better framework to skip tests based on curl version. - headers = [] # type: typing.List[str] - chunk_bytes = [] # type: typing.List[bytes] - self.fetch( - "/redirect?url=/hello", - header_callback=headers.append, - streaming_callback=chunk_bytes.append, - ) - chunks = list(map(to_unicode, chunk_bytes)) - self.assertEqual(chunks, ["Hello world!"]) - # Make sure we only got one set of headers. - num_start_lines = len([h for h in headers if h.startswith("HTTP/")]) - self.assertEqual(num_start_lines, 1) - - -class SimpleHTTPClientTestCase(SimpleHTTPClientTestMixin, AsyncHTTPTestCase): - def setUp(self): - super().setUp() - self.http_client = self.create_client() - - def create_client(self, **kwargs): - return SimpleAsyncHTTPClient(force_instance=True, **kwargs) - - -class SimpleHTTPSClientTestCase(SimpleHTTPClientTestMixin, AsyncHTTPSTestCase): - def setUp(self): - super().setUp() - self.http_client = self.create_client() - - def create_client(self, **kwargs): - return SimpleAsyncHTTPClient( - force_instance=True, defaults=dict(validate_cert=False), **kwargs - ) - - def test_ssl_options(self): - resp = self.fetch("/hello", ssl_options={}) - self.assertEqual(resp.body, b"Hello world!") - - def test_ssl_context(self): - resp = self.fetch("/hello", ssl_options=ssl.SSLContext(ssl.PROTOCOL_SSLv23)) - self.assertEqual(resp.body, b"Hello world!") - - def test_ssl_options_handshake_fail(self): - with ExpectLog(gen_log, "SSL Error|Uncaught exception", required=False): - with self.assertRaises(ssl.SSLError): - self.fetch( - "/hello", - ssl_options=dict(cert_reqs=ssl.CERT_REQUIRED), - raise_error=True, - ) - - def test_ssl_context_handshake_fail(self): - with ExpectLog(gen_log, "SSL Error|Uncaught exception"): - ctx = ssl.SSLContext(ssl.PROTOCOL_SSLv23) - ctx.verify_mode = ssl.CERT_REQUIRED - with self.assertRaises(ssl.SSLError): - self.fetch("/hello", ssl_options=ctx, raise_error=True) - - def test_error_logging(self): - # No stack traces are logged for SSL errors (in this case, - # failure to validate the testing self-signed cert). - # The SSLError is exposed through ssl.SSLError. - with ExpectLog(gen_log, ".*") as expect_log: - with self.assertRaises(ssl.SSLError): - self.fetch("/", validate_cert=True, raise_error=True) - self.assertFalse(expect_log.logged_stack) - - -class CreateAsyncHTTPClientTestCase(AsyncTestCase): - def setUp(self): - super().setUp() - self.saved = AsyncHTTPClient._save_configuration() - - def tearDown(self): - AsyncHTTPClient._restore_configuration(self.saved) - super().tearDown() - - def test_max_clients(self): - AsyncHTTPClient.configure(SimpleAsyncHTTPClient) - with closing(AsyncHTTPClient(force_instance=True)) as client: - self.assertEqual(client.max_clients, 10) # type: ignore - with closing(AsyncHTTPClient(max_clients=11, force_instance=True)) as client: - self.assertEqual(client.max_clients, 11) # type: ignore - - # Now configure max_clients statically and try overriding it - # with each way max_clients can be passed - AsyncHTTPClient.configure(SimpleAsyncHTTPClient, max_clients=12) - with closing(AsyncHTTPClient(force_instance=True)) as client: - self.assertEqual(client.max_clients, 12) # type: ignore - with closing(AsyncHTTPClient(max_clients=13, force_instance=True)) as client: - self.assertEqual(client.max_clients, 13) # type: ignore - with closing(AsyncHTTPClient(max_clients=14, force_instance=True)) as client: - self.assertEqual(client.max_clients, 14) # type: ignore - - -class HTTP100ContinueTestCase(AsyncHTTPTestCase): - def respond_100(self, request): - self.http1 = request.version.startswith("HTTP/1.") - if not self.http1: - request.connection.write_headers( - ResponseStartLine("", 200, "OK"), HTTPHeaders() - ) - request.connection.finish() - return - self.request = request - fut = self.request.connection.stream.write(b"HTTP/1.1 100 CONTINUE\r\n\r\n") - fut.add_done_callback(self.respond_200) - - def respond_200(self, fut): - fut.result() - fut = self.request.connection.stream.write( - b"HTTP/1.1 200 OK\r\nContent-Length: 1\r\n\r\nA" - ) - fut.add_done_callback(lambda f: self.request.connection.stream.close()) - - def get_app(self): - # Not a full Application, but works as an HTTPServer callback - return self.respond_100 - - def test_100_continue(self): - res = self.fetch("/") - if not self.http1: - self.skipTest("requires HTTP/1.x") - self.assertEqual(res.body, b"A") - - -class HTTP204NoContentTestCase(AsyncHTTPTestCase): - def respond_204(self, request): - self.http1 = request.version.startswith("HTTP/1.") - if not self.http1: - # Close the request cleanly in HTTP/2; it will be skipped anyway. - request.connection.write_headers( - ResponseStartLine("", 200, "OK"), HTTPHeaders() - ) - request.connection.finish() - return - - # A 204 response never has a body, even if doesn't have a content-length - # (which would otherwise mean read-until-close). We simulate here a - # server that sends no content length and does not close the connection. - # - # Tests of a 204 response with no Content-Length header are included - # in SimpleHTTPClientTestMixin. - stream = request.connection.detach() - stream.write(b"HTTP/1.1 204 No content\r\n") - if request.arguments.get("error", [False])[-1]: - stream.write(b"Content-Length: 5\r\n") - else: - stream.write(b"Content-Length: 0\r\n") - stream.write(b"\r\n") - stream.close() - - def get_app(self): - return self.respond_204 - - def test_204_no_content(self): - resp = self.fetch("/") - if not self.http1: - self.skipTest("requires HTTP/1.x") - self.assertEqual(resp.code, 204) - self.assertEqual(resp.body, b"") - - def test_204_invalid_content_length(self): - # 204 status with non-zero content length is malformed - with ExpectLog( - gen_log, ".*Response with code 204 should not have body", level=logging.INFO - ): - with self.assertRaises(HTTPStreamClosedError): - self.fetch("/?error=1", raise_error=True) - if not self.http1: - self.skipTest("requires HTTP/1.x") - if self.http_client.configured_class != SimpleAsyncHTTPClient: - self.skipTest("curl client accepts invalid headers") - - -class HostnameMappingTestCase(AsyncHTTPTestCase): - def setUp(self): - super().setUp() - self.http_client = SimpleAsyncHTTPClient( - hostname_mapping={ - "www.example.com": "127.0.0.1", - ("foo.example.com", 8000): ("127.0.0.1", self.get_http_port()), - } - ) - - def get_app(self): - return Application([url("/hello", HelloWorldHandler)]) - - def test_hostname_mapping(self): - response = self.fetch("http://www.example.com:%d/hello" % self.get_http_port()) - response.rethrow() - self.assertEqual(response.body, b"Hello world!") - - def test_port_mapping(self): - response = self.fetch("http://foo.example.com:8000/hello") - response.rethrow() - self.assertEqual(response.body, b"Hello world!") - - -class ResolveTimeoutTestCase(AsyncHTTPTestCase): - def setUp(self): - self.cleanup_event = Event() - test = self - - # Dummy Resolver subclass that never finishes. - class BadResolver(Resolver): - @gen.coroutine - def resolve(self, *args, **kwargs): - yield test.cleanup_event.wait() - # Return something valid so the test doesn't raise during cleanup. - return [(socket.AF_INET, ("127.0.0.1", test.get_http_port()))] - - super().setUp() - self.http_client = SimpleAsyncHTTPClient(resolver=BadResolver()) - - def get_app(self): - return Application([url("/hello", HelloWorldHandler)]) - - def test_resolve_timeout(self): - with self.assertRaises(HTTPTimeoutError): - self.fetch("/hello", connect_timeout=0.1, raise_error=True) - - # Let the hanging coroutine clean up after itself - self.cleanup_event.set() - self.io_loop.run_sync(lambda: gen.sleep(0)) - - -class MaxHeaderSizeTest(AsyncHTTPTestCase): - def get_app(self): - class SmallHeaders(RequestHandler): - def get(self): - self.set_header("X-Filler", "a" * 100) - self.write("ok") - - class LargeHeaders(RequestHandler): - def get(self): - self.set_header("X-Filler", "a" * 1000) - self.write("ok") - - return Application([("/small", SmallHeaders), ("/large", LargeHeaders)]) - - def get_http_client(self): - return SimpleAsyncHTTPClient(max_header_size=1024) - - def test_small_headers(self): - response = self.fetch("/small") - response.rethrow() - self.assertEqual(response.body, b"ok") - - def test_large_headers(self): - with ExpectLog(gen_log, "Unsatisfiable read", level=logging.INFO): - with self.assertRaises(UnsatisfiableReadError): - self.fetch("/large", raise_error=True) - - -class MaxBodySizeTest(AsyncHTTPTestCase): - def get_app(self): - class SmallBody(RequestHandler): - def get(self): - self.write("a" * 1024 * 64) - - class LargeBody(RequestHandler): - def get(self): - self.write("a" * 1024 * 100) - - return Application([("/small", SmallBody), ("/large", LargeBody)]) - - def get_http_client(self): - return SimpleAsyncHTTPClient(max_body_size=1024 * 64) - - def test_small_body(self): - response = self.fetch("/small") - response.rethrow() - self.assertEqual(response.body, b"a" * 1024 * 64) - - def test_large_body(self): - with ExpectLog( - gen_log, - "Malformed HTTP message from None: Content-Length too long", - level=logging.INFO, - ): - with self.assertRaises(HTTPStreamClosedError): - self.fetch("/large", raise_error=True) - - -class MaxBufferSizeTest(AsyncHTTPTestCase): - def get_app(self): - class LargeBody(RequestHandler): - def get(self): - self.write("a" * 1024 * 100) - - return Application([("/large", LargeBody)]) - - def get_http_client(self): - # 100KB body with 64KB buffer - return SimpleAsyncHTTPClient( - max_body_size=1024 * 100, max_buffer_size=1024 * 64 - ) - - def test_large_body(self): - response = self.fetch("/large") - response.rethrow() - self.assertEqual(response.body, b"a" * 1024 * 100) - - -class ChunkedWithContentLengthTest(AsyncHTTPTestCase): - def get_app(self): - class ChunkedWithContentLength(RequestHandler): - def get(self): - # Add an invalid Transfer-Encoding to the response - self.set_header("Transfer-Encoding", "chunked") - self.write("Hello world") - - return Application([("/chunkwithcl", ChunkedWithContentLength)]) - - def get_http_client(self): - return SimpleAsyncHTTPClient() - - def test_chunked_with_content_length(self): - # Make sure the invalid headers are detected - with ExpectLog( - gen_log, - ( - "Malformed HTTP message from None: Response " - "with both Transfer-Encoding and Content-Length" - ), - level=logging.INFO, - ): - with self.assertRaises(HTTPStreamClosedError): - self.fetch("/chunkwithcl", raise_error=True) diff --git a/venv/lib/python3.8/site-packages/tornado/test/static/dir/index.html b/venv/lib/python3.8/site-packages/tornado/test/static/dir/index.html deleted file mode 100644 index e1cd9d8..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/static/dir/index.html +++ /dev/null @@ -1 +0,0 @@ -this is the index diff --git a/venv/lib/python3.8/site-packages/tornado/test/static/robots.txt b/venv/lib/python3.8/site-packages/tornado/test/static/robots.txt deleted file mode 100644 index 1f53798..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/static/robots.txt +++ /dev/null @@ -1,2 +0,0 @@ -User-agent: * -Disallow: / diff --git a/venv/lib/python3.8/site-packages/tornado/test/static/sample.xml b/venv/lib/python3.8/site-packages/tornado/test/static/sample.xml deleted file mode 100644 index 35ea0e2..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/static/sample.xml +++ /dev/null @@ -1,23 +0,0 @@ -<?xml version="1.0"?> -<data> - <country name="Liechtenstein"> - <rank>1</rank> - <year>2008</year> - <gdppc>141100</gdppc> - <neighbor name="Austria" direction="E"/> - <neighbor name="Switzerland" direction="W"/> - </country> - <country name="Singapore"> - <rank>4</rank> - <year>2011</year> - <gdppc>59900</gdppc> - <neighbor name="Malaysia" direction="N"/> - </country> - <country name="Panama"> - <rank>68</rank> - <year>2011</year> - <gdppc>13600</gdppc> - <neighbor name="Costa Rica" direction="W"/> - <neighbor name="Colombia" direction="E"/> - </country> -</data> diff --git a/venv/lib/python3.8/site-packages/tornado/test/static/sample.xml.bz2 b/venv/lib/python3.8/site-packages/tornado/test/static/sample.xml.bz2 deleted file mode 100644 index 44dc6633324307e6834e0346eefe7874f1061b3c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 285 zcmV+&0pk8bT4*^jL0KkKS>2RqRsaBWUw}jqPyzpEss~trKJVY~FaaAOiqz214H^I% z0000Osgq4W22C{aKmY&%6sD6y5NWB9VFOJD)Ow86kS3)_1!n}|LR|HTBj$IEaP;31 z;m?&8&W5YRNP|^vgqR)$6TyPAz={Y#J+F>qV@u_3X_IFvAew0?Adx~wsED2oK~j1d z-KD{_6*6^@hl~aM+AfjHIv)IM9(sq^pDoGwIjGX>W=iEN5}~e;HI7*(MABi>RJAzL zl(zbRufD<kpF(U-x(3>J^oW2kvO_M=BGjH?&w$~(5cVe7_6)<4!L249=C)Z<+{6ys jF<YlyL~hWNVj8i5^YPfofWTmB&&Ax4P81|JWf~QLEi;1B diff --git a/venv/lib/python3.8/site-packages/tornado/test/static/sample.xml.gz b/venv/lib/python3.8/site-packages/tornado/test/static/sample.xml.gz deleted file mode 100644 index c0fd5e6fd3c3a42dd2c9ec81e9a3ca424ef35b24..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 264 zcmV+j0r&nNiwFqEjJZ_;19M?*aBO8Rcx`L|m6Fd+!!QiS?|X_U4?q$a(<Wt^5aKov zVh7G%YIPB<QzhA-^7KsYP=U2l@x@N;Px*dH^y*X=?0_LUPfM<DBwv|{&LDxAuybhZ z_mo1-2ufV?wL`m0NHL)!-i|b50qDahEt=eI*9gJfN;%h}DZ5UdRh2brs+5#kw5zU5 z=<?mxhs&`K`<Q|Q&N3I!rpD_N7sG<h(WOre1yJ@&^!_c<;sVx-xp9<3<pW+JPKOYc z8bG{XEJhGMLjiUCgZMJe?JJx!Tv?sX|Ls-X%|>{A^f3W@a~AsVwqH~Day#^dKlrq0 OKi?O$L>^X}0ssI%#(xO_ diff --git a/venv/lib/python3.8/site-packages/tornado/test/static_foo.txt b/venv/lib/python3.8/site-packages/tornado/test/static_foo.txt deleted file mode 100644 index bdb44f3..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/static_foo.txt +++ /dev/null @@ -1,2 +0,0 @@ -This file should not be served by StaticFileHandler even though -its name starts with "static". diff --git a/venv/lib/python3.8/site-packages/tornado/test/tcpclient_test.py b/venv/lib/python3.8/site-packages/tornado/test/tcpclient_test.py deleted file mode 100644 index 75f4818..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/tcpclient_test.py +++ /dev/null @@ -1,438 +0,0 @@ -# -# Copyright 2014 Facebook -# -# 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. -from contextlib import closing -import getpass -import os -import socket -import unittest - -from tornado.concurrent import Future -from tornado.netutil import bind_sockets, Resolver -from tornado.queues import Queue -from tornado.tcpclient import TCPClient, _Connector -from tornado.tcpserver import TCPServer -from tornado.testing import AsyncTestCase, gen_test -from tornado.test.util import skipIfNoIPv6, refusing_port, skipIfNonUnix -from tornado.gen import TimeoutError - -import typing - -if typing.TYPE_CHECKING: - from tornado.iostream import IOStream # noqa: F401 - from typing import List, Dict, Tuple # noqa: F401 - -# Fake address families for testing. Used in place of AF_INET -# and AF_INET6 because some installations do not have AF_INET6. -AF1, AF2 = 1, 2 - - -class TestTCPServer(TCPServer): - def __init__(self, family): - super().__init__() - self.streams = [] # type: List[IOStream] - self.queue = Queue() # type: Queue[IOStream] - sockets = bind_sockets(0, "localhost", family) - self.add_sockets(sockets) - self.port = sockets[0].getsockname()[1] - - def handle_stream(self, stream, address): - self.streams.append(stream) - self.queue.put(stream) - - def stop(self): - super().stop() - for stream in self.streams: - stream.close() - - -class TCPClientTest(AsyncTestCase): - def setUp(self): - super().setUp() - self.server = None - self.client = TCPClient() - - def start_server(self, family): - if family == socket.AF_UNSPEC and "TRAVIS" in os.environ: - self.skipTest("dual-stack servers often have port conflicts on travis") - self.server = TestTCPServer(family) - return self.server.port - - def stop_server(self): - if self.server is not None: - self.server.stop() - self.server = None - - def tearDown(self): - self.client.close() - self.stop_server() - super().tearDown() - - def skipIfLocalhostV4(self): - # The port used here doesn't matter, but some systems require it - # to be non-zero if we do not also pass AI_PASSIVE. - addrinfo = self.io_loop.run_sync(lambda: Resolver().resolve("localhost", 80)) - families = set(addr[0] for addr in addrinfo) - if socket.AF_INET6 not in families: - self.skipTest("localhost does not resolve to ipv6") - - @gen_test - def do_test_connect(self, family, host, source_ip=None, source_port=None): - port = self.start_server(family) - stream = yield self.client.connect( - host, port, source_ip=source_ip, source_port=source_port - ) - assert self.server is not None - server_stream = yield self.server.queue.get() - with closing(stream): - stream.write(b"hello") - data = yield server_stream.read_bytes(5) - self.assertEqual(data, b"hello") - - def test_connect_ipv4_ipv4(self): - self.do_test_connect(socket.AF_INET, "127.0.0.1") - - def test_connect_ipv4_dual(self): - self.do_test_connect(socket.AF_INET, "localhost") - - @skipIfNoIPv6 - def test_connect_ipv6_ipv6(self): - self.skipIfLocalhostV4() - self.do_test_connect(socket.AF_INET6, "::1") - - @skipIfNoIPv6 - def test_connect_ipv6_dual(self): - self.skipIfLocalhostV4() - if Resolver.configured_class().__name__.endswith("TwistedResolver"): - self.skipTest("TwistedResolver does not support multiple addresses") - self.do_test_connect(socket.AF_INET6, "localhost") - - def test_connect_unspec_ipv4(self): - self.do_test_connect(socket.AF_UNSPEC, "127.0.0.1") - - @skipIfNoIPv6 - def test_connect_unspec_ipv6(self): - self.skipIfLocalhostV4() - self.do_test_connect(socket.AF_UNSPEC, "::1") - - def test_connect_unspec_dual(self): - self.do_test_connect(socket.AF_UNSPEC, "localhost") - - @gen_test - def test_refused_ipv4(self): - cleanup_func, port = refusing_port() - self.addCleanup(cleanup_func) - with self.assertRaises(IOError): - yield self.client.connect("127.0.0.1", port) - - def test_source_ip_fail(self): - """Fail when trying to use the source IP Address '8.8.8.8'. - """ - self.assertRaises( - socket.error, - self.do_test_connect, - socket.AF_INET, - "127.0.0.1", - source_ip="8.8.8.8", - ) - - def test_source_ip_success(self): - """Success when trying to use the source IP Address '127.0.0.1'. - """ - self.do_test_connect(socket.AF_INET, "127.0.0.1", source_ip="127.0.0.1") - - @skipIfNonUnix - def test_source_port_fail(self): - """Fail when trying to use source port 1. - """ - if getpass.getuser() == "root": - # Root can use any port so we can't easily force this to fail. - # This is mainly relevant for docker. - self.skipTest("running as root") - self.assertRaises( - socket.error, - self.do_test_connect, - socket.AF_INET, - "127.0.0.1", - source_port=1, - ) - - @gen_test - def test_connect_timeout(self): - timeout = 0.05 - - class TimeoutResolver(Resolver): - def resolve(self, *args, **kwargs): - return Future() # never completes - - with self.assertRaises(TimeoutError): - yield TCPClient(resolver=TimeoutResolver()).connect( - "1.2.3.4", 12345, timeout=timeout - ) - - -class TestConnectorSplit(unittest.TestCase): - def test_one_family(self): - # These addresses aren't in the right format, but split doesn't care. - primary, secondary = _Connector.split([(AF1, "a"), (AF1, "b")]) - self.assertEqual(primary, [(AF1, "a"), (AF1, "b")]) - self.assertEqual(secondary, []) - - def test_mixed(self): - primary, secondary = _Connector.split( - [(AF1, "a"), (AF2, "b"), (AF1, "c"), (AF2, "d")] - ) - self.assertEqual(primary, [(AF1, "a"), (AF1, "c")]) - self.assertEqual(secondary, [(AF2, "b"), (AF2, "d")]) - - -class ConnectorTest(AsyncTestCase): - class FakeStream(object): - def __init__(self): - self.closed = False - - def close(self): - self.closed = True - - def setUp(self): - super().setUp() - self.connect_futures = ( - {} - ) # type: Dict[Tuple[int, typing.Any], Future[ConnectorTest.FakeStream]] - self.streams = {} # type: Dict[typing.Any, ConnectorTest.FakeStream] - self.addrinfo = [(AF1, "a"), (AF1, "b"), (AF2, "c"), (AF2, "d")] - - def tearDown(self): - # Unless explicitly checked (and popped) in the test, we shouldn't - # be closing any streams - for stream in self.streams.values(): - self.assertFalse(stream.closed) - super().tearDown() - - def create_stream(self, af, addr): - stream = ConnectorTest.FakeStream() - self.streams[addr] = stream - future = Future() # type: Future[ConnectorTest.FakeStream] - self.connect_futures[(af, addr)] = future - return stream, future - - def assert_pending(self, *keys): - self.assertEqual(sorted(self.connect_futures.keys()), sorted(keys)) - - def resolve_connect(self, af, addr, success): - future = self.connect_futures.pop((af, addr)) - if success: - future.set_result(self.streams[addr]) - else: - self.streams.pop(addr) - future.set_exception(IOError()) - # Run the loop to allow callbacks to be run. - self.io_loop.add_callback(self.stop) - self.wait() - - def assert_connector_streams_closed(self, conn): - for stream in conn.streams: - self.assertTrue(stream.closed) - - def start_connect(self, addrinfo): - conn = _Connector(addrinfo, self.create_stream) - # Give it a huge timeout; we'll trigger timeouts manually. - future = conn.start(3600, connect_timeout=self.io_loop.time() + 3600) - return conn, future - - def test_immediate_success(self): - conn, future = self.start_connect(self.addrinfo) - self.assertEqual(list(self.connect_futures.keys()), [(AF1, "a")]) - self.resolve_connect(AF1, "a", True) - self.assertEqual(future.result(), (AF1, "a", self.streams["a"])) - - def test_immediate_failure(self): - # Fail with just one address. - conn, future = self.start_connect([(AF1, "a")]) - self.assert_pending((AF1, "a")) - self.resolve_connect(AF1, "a", False) - self.assertRaises(IOError, future.result) - - def test_one_family_second_try(self): - conn, future = self.start_connect([(AF1, "a"), (AF1, "b")]) - self.assert_pending((AF1, "a")) - self.resolve_connect(AF1, "a", False) - self.assert_pending((AF1, "b")) - self.resolve_connect(AF1, "b", True) - self.assertEqual(future.result(), (AF1, "b", self.streams["b"])) - - def test_one_family_second_try_failure(self): - conn, future = self.start_connect([(AF1, "a"), (AF1, "b")]) - self.assert_pending((AF1, "a")) - self.resolve_connect(AF1, "a", False) - self.assert_pending((AF1, "b")) - self.resolve_connect(AF1, "b", False) - self.assertRaises(IOError, future.result) - - def test_one_family_second_try_timeout(self): - conn, future = self.start_connect([(AF1, "a"), (AF1, "b")]) - self.assert_pending((AF1, "a")) - # trigger the timeout while the first lookup is pending; - # nothing happens. - conn.on_timeout() - self.assert_pending((AF1, "a")) - self.resolve_connect(AF1, "a", False) - self.assert_pending((AF1, "b")) - self.resolve_connect(AF1, "b", True) - self.assertEqual(future.result(), (AF1, "b", self.streams["b"])) - - def test_two_families_immediate_failure(self): - conn, future = self.start_connect(self.addrinfo) - self.assert_pending((AF1, "a")) - self.resolve_connect(AF1, "a", False) - self.assert_pending((AF1, "b"), (AF2, "c")) - self.resolve_connect(AF1, "b", False) - self.resolve_connect(AF2, "c", True) - self.assertEqual(future.result(), (AF2, "c", self.streams["c"])) - - def test_two_families_timeout(self): - conn, future = self.start_connect(self.addrinfo) - self.assert_pending((AF1, "a")) - conn.on_timeout() - self.assert_pending((AF1, "a"), (AF2, "c")) - self.resolve_connect(AF2, "c", True) - self.assertEqual(future.result(), (AF2, "c", self.streams["c"])) - # resolving 'a' after the connection has completed doesn't start 'b' - self.resolve_connect(AF1, "a", False) - self.assert_pending() - - def test_success_after_timeout(self): - conn, future = self.start_connect(self.addrinfo) - self.assert_pending((AF1, "a")) - conn.on_timeout() - self.assert_pending((AF1, "a"), (AF2, "c")) - self.resolve_connect(AF1, "a", True) - self.assertEqual(future.result(), (AF1, "a", self.streams["a"])) - # resolving 'c' after completion closes the connection. - self.resolve_connect(AF2, "c", True) - self.assertTrue(self.streams.pop("c").closed) - - def test_all_fail(self): - conn, future = self.start_connect(self.addrinfo) - self.assert_pending((AF1, "a")) - conn.on_timeout() - self.assert_pending((AF1, "a"), (AF2, "c")) - self.resolve_connect(AF2, "c", False) - self.assert_pending((AF1, "a"), (AF2, "d")) - self.resolve_connect(AF2, "d", False) - # one queue is now empty - self.assert_pending((AF1, "a")) - self.resolve_connect(AF1, "a", False) - self.assert_pending((AF1, "b")) - self.assertFalse(future.done()) - self.resolve_connect(AF1, "b", False) - self.assertRaises(IOError, future.result) - - def test_one_family_timeout_after_connect_timeout(self): - conn, future = self.start_connect([(AF1, "a"), (AF1, "b")]) - self.assert_pending((AF1, "a")) - conn.on_connect_timeout() - # the connector will close all streams on connect timeout, we - # should explicitly pop the connect_future. - self.connect_futures.pop((AF1, "a")) - self.assertTrue(self.streams.pop("a").closed) - conn.on_timeout() - # if the future is set with TimeoutError, we will not iterate next - # possible address. - self.assert_pending() - self.assertEqual(len(conn.streams), 1) - self.assert_connector_streams_closed(conn) - self.assertRaises(TimeoutError, future.result) - - def test_one_family_success_before_connect_timeout(self): - conn, future = self.start_connect([(AF1, "a"), (AF1, "b")]) - self.assert_pending((AF1, "a")) - self.resolve_connect(AF1, "a", True) - conn.on_connect_timeout() - self.assert_pending() - self.assertEqual(self.streams["a"].closed, False) - # success stream will be pop - self.assertEqual(len(conn.streams), 0) - # streams in connector should be closed after connect timeout - self.assert_connector_streams_closed(conn) - self.assertEqual(future.result(), (AF1, "a", self.streams["a"])) - - def test_one_family_second_try_after_connect_timeout(self): - conn, future = self.start_connect([(AF1, "a"), (AF1, "b")]) - self.assert_pending((AF1, "a")) - self.resolve_connect(AF1, "a", False) - self.assert_pending((AF1, "b")) - conn.on_connect_timeout() - self.connect_futures.pop((AF1, "b")) - self.assertTrue(self.streams.pop("b").closed) - self.assert_pending() - self.assertEqual(len(conn.streams), 2) - self.assert_connector_streams_closed(conn) - self.assertRaises(TimeoutError, future.result) - - def test_one_family_second_try_failure_before_connect_timeout(self): - conn, future = self.start_connect([(AF1, "a"), (AF1, "b")]) - self.assert_pending((AF1, "a")) - self.resolve_connect(AF1, "a", False) - self.assert_pending((AF1, "b")) - self.resolve_connect(AF1, "b", False) - conn.on_connect_timeout() - self.assert_pending() - self.assertEqual(len(conn.streams), 2) - self.assert_connector_streams_closed(conn) - self.assertRaises(IOError, future.result) - - def test_two_family_timeout_before_connect_timeout(self): - conn, future = self.start_connect(self.addrinfo) - self.assert_pending((AF1, "a")) - conn.on_timeout() - self.assert_pending((AF1, "a"), (AF2, "c")) - conn.on_connect_timeout() - self.connect_futures.pop((AF1, "a")) - self.assertTrue(self.streams.pop("a").closed) - self.connect_futures.pop((AF2, "c")) - self.assertTrue(self.streams.pop("c").closed) - self.assert_pending() - self.assertEqual(len(conn.streams), 2) - self.assert_connector_streams_closed(conn) - self.assertRaises(TimeoutError, future.result) - - def test_two_family_success_after_timeout(self): - conn, future = self.start_connect(self.addrinfo) - self.assert_pending((AF1, "a")) - conn.on_timeout() - self.assert_pending((AF1, "a"), (AF2, "c")) - self.resolve_connect(AF1, "a", True) - # if one of streams succeed, connector will close all other streams - self.connect_futures.pop((AF2, "c")) - self.assertTrue(self.streams.pop("c").closed) - self.assert_pending() - self.assertEqual(len(conn.streams), 1) - self.assert_connector_streams_closed(conn) - self.assertEqual(future.result(), (AF1, "a", self.streams["a"])) - - def test_two_family_timeout_after_connect_timeout(self): - conn, future = self.start_connect(self.addrinfo) - self.assert_pending((AF1, "a")) - conn.on_connect_timeout() - self.connect_futures.pop((AF1, "a")) - self.assertTrue(self.streams.pop("a").closed) - self.assert_pending() - conn.on_timeout() - # if the future is set with TimeoutError, connector will not - # trigger secondary address. - self.assert_pending() - self.assertEqual(len(conn.streams), 1) - self.assert_connector_streams_closed(conn) - self.assertRaises(TimeoutError, future.result) diff --git a/venv/lib/python3.8/site-packages/tornado/test/tcpserver_test.py b/venv/lib/python3.8/site-packages/tornado/test/tcpserver_test.py deleted file mode 100644 index 7c75acf..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/tcpserver_test.py +++ /dev/null @@ -1,192 +0,0 @@ -import socket -import subprocess -import sys -import textwrap -import unittest - -from tornado.escape import utf8, to_unicode -from tornado import gen -from tornado.iostream import IOStream -from tornado.log import app_log -from tornado.tcpserver import TCPServer -from tornado.test.util import skipIfNonUnix -from tornado.testing import AsyncTestCase, ExpectLog, bind_unused_port, gen_test - - -class TCPServerTest(AsyncTestCase): - @gen_test - def test_handle_stream_coroutine_logging(self): - # handle_stream may be a coroutine and any exception in its - # Future will be logged. - class TestServer(TCPServer): - @gen.coroutine - def handle_stream(self, stream, address): - yield stream.read_bytes(len(b"hello")) - stream.close() - 1 / 0 - - server = client = None - try: - sock, port = bind_unused_port() - server = TestServer() - server.add_socket(sock) - client = IOStream(socket.socket()) - with ExpectLog(app_log, "Exception in callback"): - yield client.connect(("localhost", port)) - yield client.write(b"hello") - yield client.read_until_close() - yield gen.moment - finally: - if server is not None: - server.stop() - if client is not None: - client.close() - - @gen_test - def test_handle_stream_native_coroutine(self): - # handle_stream may be a native coroutine. - - class TestServer(TCPServer): - async def handle_stream(self, stream, address): - stream.write(b"data") - stream.close() - - sock, port = bind_unused_port() - server = TestServer() - server.add_socket(sock) - client = IOStream(socket.socket()) - yield client.connect(("localhost", port)) - result = yield client.read_until_close() - self.assertEqual(result, b"data") - server.stop() - client.close() - - def test_stop_twice(self): - sock, port = bind_unused_port() - server = TCPServer() - server.add_socket(sock) - server.stop() - server.stop() - - @gen_test - def test_stop_in_callback(self): - # Issue #2069: calling server.stop() in a loop callback should not - # raise EBADF when the loop handles other server connection - # requests in the same loop iteration - - class TestServer(TCPServer): - @gen.coroutine - def handle_stream(self, stream, address): - server.stop() # type: ignore - yield stream.read_until_close() - - sock, port = bind_unused_port() - server = TestServer() - server.add_socket(sock) - server_addr = ("localhost", port) - N = 40 - clients = [IOStream(socket.socket()) for i in range(N)] - connected_clients = [] - - @gen.coroutine - def connect(c): - try: - yield c.connect(server_addr) - except EnvironmentError: - pass - else: - connected_clients.append(c) - - yield [connect(c) for c in clients] - - self.assertGreater(len(connected_clients), 0, "all clients failed connecting") - try: - if len(connected_clients) == N: - # Ideally we'd make the test deterministic, but we're testing - # for a race condition in combination with the system's TCP stack... - self.skipTest( - "at least one client should fail connecting " - "for the test to be meaningful" - ) - finally: - for c in connected_clients: - c.close() - - # Here tearDown() would re-raise the EBADF encountered in the IO loop - - -@skipIfNonUnix -class TestMultiprocess(unittest.TestCase): - # These tests verify that the two multiprocess examples from the - # TCPServer docs work. Both tests start a server with three worker - # processes, each of which prints its task id to stdout (a single - # byte, so we don't have to worry about atomicity of the shared - # stdout stream) and then exits. - def run_subproc(self, code): - proc = subprocess.Popen( - sys.executable, stdin=subprocess.PIPE, stdout=subprocess.PIPE - ) - proc.stdin.write(utf8(code)) - proc.stdin.close() - proc.wait() - stdout = proc.stdout.read() - proc.stdout.close() - if proc.returncode != 0: - raise RuntimeError( - "Process returned %d. stdout=%r" % (proc.returncode, stdout) - ) - return to_unicode(stdout) - - def test_single(self): - # As a sanity check, run the single-process version through this test - # harness too. - code = textwrap.dedent( - """ - from tornado.ioloop import IOLoop - from tornado.tcpserver import TCPServer - - server = TCPServer() - server.listen(0, address='127.0.0.1') - IOLoop.current().run_sync(lambda: None) - print('012', end='') - """ - ) - out = self.run_subproc(code) - self.assertEqual("".join(sorted(out)), "012") - - def test_simple(self): - code = textwrap.dedent( - """ - from tornado.ioloop import IOLoop - from tornado.process import task_id - from tornado.tcpserver import TCPServer - - server = TCPServer() - server.bind(0, address='127.0.0.1') - server.start(3) - IOLoop.current().run_sync(lambda: None) - print(task_id(), end='') - """ - ) - out = self.run_subproc(code) - self.assertEqual("".join(sorted(out)), "012") - - def test_advanced(self): - code = textwrap.dedent( - """ - from tornado.ioloop import IOLoop - from tornado.netutil import bind_sockets - from tornado.process import fork_processes, task_id - from tornado.ioloop import IOLoop - from tornado.tcpserver import TCPServer - - sockets = bind_sockets(0, address='127.0.0.1') - fork_processes(3) - server = TCPServer() - server.add_sockets(sockets) - IOLoop.current().run_sync(lambda: None) - print(task_id(), end='') - """ - ) - out = self.run_subproc(code) - self.assertEqual("".join(sorted(out)), "012") diff --git a/venv/lib/python3.8/site-packages/tornado/test/template_test.py b/venv/lib/python3.8/site-packages/tornado/test/template_test.py deleted file mode 100644 index f71f037..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/template_test.py +++ /dev/null @@ -1,536 +0,0 @@ -import os -import traceback -import unittest - -from tornado.escape import utf8, native_str, to_unicode -from tornado.template import Template, DictLoader, ParseError, Loader -from tornado.util import ObjectDict - -import typing # noqa: F401 - - -class TemplateTest(unittest.TestCase): - def test_simple(self): - template = Template("Hello {{ name }}!") - self.assertEqual(template.generate(name="Ben"), b"Hello Ben!") - - def test_bytes(self): - template = Template("Hello {{ name }}!") - self.assertEqual(template.generate(name=utf8("Ben")), b"Hello Ben!") - - def test_expressions(self): - template = Template("2 + 2 = {{ 2 + 2 }}") - self.assertEqual(template.generate(), b"2 + 2 = 4") - - def test_comment(self): - template = Template("Hello{# TODO i18n #} {{ name }}!") - self.assertEqual(template.generate(name=utf8("Ben")), b"Hello Ben!") - - def test_include(self): - loader = DictLoader( - { - "index.html": '{% include "header.html" %}\nbody text', - "header.html": "header text", - } - ) - self.assertEqual( - loader.load("index.html").generate(), b"header text\nbody text" - ) - - def test_extends(self): - loader = DictLoader( - { - "base.html": """\ -<title>{% block title %}default title{% end %}</title> -<body>{% block body %}default body{% end %}</body> -""", - "page.html": """\ -{% extends "base.html" %} -{% block title %}page title{% end %} -{% block body %}page body{% end %} -""", - } - ) - self.assertEqual( - loader.load("page.html").generate(), - b"<title>page title</title>\n<body>page body</body>\n", - ) - - def test_relative_load(self): - loader = DictLoader( - { - "a/1.html": "{% include '2.html' %}", - "a/2.html": "{% include '../b/3.html' %}", - "b/3.html": "ok", - } - ) - self.assertEqual(loader.load("a/1.html").generate(), b"ok") - - def test_escaping(self): - self.assertRaises(ParseError, lambda: Template("{{")) - self.assertRaises(ParseError, lambda: Template("{%")) - self.assertEqual(Template("{{!").generate(), b"{{") - self.assertEqual(Template("{%!").generate(), b"{%") - self.assertEqual(Template("{#!").generate(), b"{#") - self.assertEqual( - Template("{{ 'expr' }} {{!jquery expr}}").generate(), - b"expr {{jquery expr}}", - ) - - def test_unicode_template(self): - template = Template(utf8(u"\u00e9")) - self.assertEqual(template.generate(), utf8(u"\u00e9")) - - def test_unicode_literal_expression(self): - # Unicode literals should be usable in templates. Note that this - # test simulates unicode characters appearing directly in the - # template file (with utf8 encoding), i.e. \u escapes would not - # be used in the template file itself. - template = Template(utf8(u'{{ "\u00e9" }}')) - self.assertEqual(template.generate(), utf8(u"\u00e9")) - - def test_custom_namespace(self): - loader = DictLoader( - {"test.html": "{{ inc(5) }}"}, namespace={"inc": lambda x: x + 1} - ) - self.assertEqual(loader.load("test.html").generate(), b"6") - - def test_apply(self): - def upper(s): - return s.upper() - - template = Template(utf8("{% apply upper %}foo{% end %}")) - self.assertEqual(template.generate(upper=upper), b"FOO") - - def test_unicode_apply(self): - def upper(s): - return to_unicode(s).upper() - - template = Template(utf8(u"{% apply upper %}foo \u00e9{% end %}")) - self.assertEqual(template.generate(upper=upper), utf8(u"FOO \u00c9")) - - def test_bytes_apply(self): - def upper(s): - return utf8(to_unicode(s).upper()) - - template = Template(utf8(u"{% apply upper %}foo \u00e9{% end %}")) - self.assertEqual(template.generate(upper=upper), utf8(u"FOO \u00c9")) - - def test_if(self): - template = Template(utf8("{% if x > 4 %}yes{% else %}no{% end %}")) - self.assertEqual(template.generate(x=5), b"yes") - self.assertEqual(template.generate(x=3), b"no") - - def test_if_empty_body(self): - template = Template(utf8("{% if True %}{% else %}{% end %}")) - self.assertEqual(template.generate(), b"") - - def test_try(self): - template = Template( - utf8( - """{% try %} -try{% set y = 1/x %} -{% except %}-except -{% else %}-else -{% finally %}-finally -{% end %}""" - ) - ) - self.assertEqual(template.generate(x=1), b"\ntry\n-else\n-finally\n") - self.assertEqual(template.generate(x=0), b"\ntry-except\n-finally\n") - - def test_comment_directive(self): - template = Template(utf8("{% comment blah blah %}foo")) - self.assertEqual(template.generate(), b"foo") - - def test_break_continue(self): - template = Template( - utf8( - """\ -{% for i in range(10) %} - {% if i == 2 %} - {% continue %} - {% end %} - {{ i }} - {% if i == 6 %} - {% break %} - {% end %} -{% end %}""" - ) - ) - result = template.generate() - # remove extraneous whitespace - result = b"".join(result.split()) - self.assertEqual(result, b"013456") - - def test_break_outside_loop(self): - try: - Template(utf8("{% break %}")) - raise Exception("Did not get expected exception") - except ParseError: - pass - - def test_break_in_apply(self): - # This test verifies current behavior, although of course it would - # be nice if apply didn't cause seemingly unrelated breakage - try: - Template( - utf8("{% for i in [] %}{% apply foo %}{% break %}{% end %}{% end %}") - ) - raise Exception("Did not get expected exception") - except ParseError: - pass - - @unittest.skip("no testable future imports") - def test_no_inherit_future(self): - # TODO(bdarnell): make a test like this for one of the future - # imports available in python 3. Unfortunately they're harder - # to use in a template than division was. - - # This file has from __future__ import division... - self.assertEqual(1 / 2, 0.5) - # ...but the template doesn't - template = Template("{{ 1 / 2 }}") - self.assertEqual(template.generate(), "0") - - def test_non_ascii_name(self): - loader = DictLoader({u"t\u00e9st.html": "hello"}) - self.assertEqual(loader.load(u"t\u00e9st.html").generate(), b"hello") - - -class StackTraceTest(unittest.TestCase): - def test_error_line_number_expression(self): - loader = DictLoader( - { - "test.html": """one -two{{1/0}} -three - """ - } - ) - try: - loader.load("test.html").generate() - self.fail("did not get expected exception") - except ZeroDivisionError: - self.assertTrue("# test.html:2" in traceback.format_exc()) - - def test_error_line_number_directive(self): - loader = DictLoader( - { - "test.html": """one -two{%if 1/0%} -three{%end%} - """ - } - ) - try: - loader.load("test.html").generate() - self.fail("did not get expected exception") - except ZeroDivisionError: - self.assertTrue("# test.html:2" in traceback.format_exc()) - - def test_error_line_number_module(self): - loader = None # type: typing.Optional[DictLoader] - - def load_generate(path, **kwargs): - assert loader is not None - return loader.load(path).generate(**kwargs) - - loader = DictLoader( - {"base.html": "{% module Template('sub.html') %}", "sub.html": "{{1/0}}"}, - namespace={"_tt_modules": ObjectDict(Template=load_generate)}, - ) - try: - loader.load("base.html").generate() - self.fail("did not get expected exception") - except ZeroDivisionError: - exc_stack = traceback.format_exc() - self.assertTrue("# base.html:1" in exc_stack) - self.assertTrue("# sub.html:1" in exc_stack) - - def test_error_line_number_include(self): - loader = DictLoader( - {"base.html": "{% include 'sub.html' %}", "sub.html": "{{1/0}}"} - ) - try: - loader.load("base.html").generate() - self.fail("did not get expected exception") - except ZeroDivisionError: - self.assertTrue("# sub.html:1 (via base.html:1)" in traceback.format_exc()) - - def test_error_line_number_extends_base_error(self): - loader = DictLoader( - {"base.html": "{{1/0}}", "sub.html": "{% extends 'base.html' %}"} - ) - try: - loader.load("sub.html").generate() - self.fail("did not get expected exception") - except ZeroDivisionError: - exc_stack = traceback.format_exc() - self.assertTrue("# base.html:1" in exc_stack) - - def test_error_line_number_extends_sub_error(self): - loader = DictLoader( - { - "base.html": "{% block 'block' %}{% end %}", - "sub.html": """ -{% extends 'base.html' %} -{% block 'block' %} -{{1/0}} -{% end %} - """, - } - ) - try: - loader.load("sub.html").generate() - self.fail("did not get expected exception") - except ZeroDivisionError: - self.assertTrue("# sub.html:4 (via base.html:1)" in traceback.format_exc()) - - def test_multi_includes(self): - loader = DictLoader( - { - "a.html": "{% include 'b.html' %}", - "b.html": "{% include 'c.html' %}", - "c.html": "{{1/0}}", - } - ) - try: - loader.load("a.html").generate() - self.fail("did not get expected exception") - except ZeroDivisionError: - self.assertTrue( - "# c.html:1 (via b.html:1, a.html:1)" in traceback.format_exc() - ) - - -class ParseErrorDetailTest(unittest.TestCase): - def test_details(self): - loader = DictLoader({"foo.html": "\n\n{{"}) - with self.assertRaises(ParseError) as cm: - loader.load("foo.html") - self.assertEqual("Missing end expression }} at foo.html:3", str(cm.exception)) - self.assertEqual("foo.html", cm.exception.filename) - self.assertEqual(3, cm.exception.lineno) - - def test_custom_parse_error(self): - # Make sure that ParseErrors remain compatible with their - # pre-4.3 signature. - self.assertEqual("asdf at None:0", str(ParseError("asdf"))) - - -class AutoEscapeTest(unittest.TestCase): - def setUp(self): - self.templates = { - "escaped.html": "{% autoescape xhtml_escape %}{{ name }}", - "unescaped.html": "{% autoescape None %}{{ name }}", - "default.html": "{{ name }}", - "include.html": """\ -escaped: {% include 'escaped.html' %} -unescaped: {% include 'unescaped.html' %} -default: {% include 'default.html' %} -""", - "escaped_block.html": """\ -{% autoescape xhtml_escape %}\ -{% block name %}base: {{ name }}{% end %}""", - "unescaped_block.html": """\ -{% autoescape None %}\ -{% block name %}base: {{ name }}{% end %}""", - # Extend a base template with different autoescape policy, - # with and without overriding the base's blocks - "escaped_extends_unescaped.html": """\ -{% autoescape xhtml_escape %}\ -{% extends "unescaped_block.html" %}""", - "escaped_overrides_unescaped.html": """\ -{% autoescape xhtml_escape %}\ -{% extends "unescaped_block.html" %}\ -{% block name %}extended: {{ name }}{% end %}""", - "unescaped_extends_escaped.html": """\ -{% autoescape None %}\ -{% extends "escaped_block.html" %}""", - "unescaped_overrides_escaped.html": """\ -{% autoescape None %}\ -{% extends "escaped_block.html" %}\ -{% block name %}extended: {{ name }}{% end %}""", - "raw_expression.html": """\ -{% autoescape xhtml_escape %}\ -expr: {{ name }} -raw: {% raw name %}""", - } - - def test_default_off(self): - loader = DictLoader(self.templates, autoescape=None) - name = "Bobby <table>s" - self.assertEqual( - loader.load("escaped.html").generate(name=name), b"Bobby &lt;table&gt;s" - ) - self.assertEqual( - loader.load("unescaped.html").generate(name=name), b"Bobby <table>s" - ) - self.assertEqual( - loader.load("default.html").generate(name=name), b"Bobby <table>s" - ) - - self.assertEqual( - loader.load("include.html").generate(name=name), - b"escaped: Bobby &lt;table&gt;s\n" - b"unescaped: Bobby <table>s\n" - b"default: Bobby <table>s\n", - ) - - def test_default_on(self): - loader = DictLoader(self.templates, autoescape="xhtml_escape") - name = "Bobby <table>s" - self.assertEqual( - loader.load("escaped.html").generate(name=name), b"Bobby &lt;table&gt;s" - ) - self.assertEqual( - loader.load("unescaped.html").generate(name=name), b"Bobby <table>s" - ) - self.assertEqual( - loader.load("default.html").generate(name=name), b"Bobby &lt;table&gt;s" - ) - - self.assertEqual( - loader.load("include.html").generate(name=name), - b"escaped: Bobby &lt;table&gt;s\n" - b"unescaped: Bobby <table>s\n" - b"default: Bobby &lt;table&gt;s\n", - ) - - def test_unextended_block(self): - loader = DictLoader(self.templates) - name = "<script>" - self.assertEqual( - loader.load("escaped_block.html").generate(name=name), - b"base: &lt;script&gt;", - ) - self.assertEqual( - loader.load("unescaped_block.html").generate(name=name), b"base: <script>" - ) - - def test_extended_block(self): - loader = DictLoader(self.templates) - - def render(name): - return loader.load(name).generate(name="<script>") - - self.assertEqual(render("escaped_extends_unescaped.html"), b"base: <script>") - self.assertEqual( - render("escaped_overrides_unescaped.html"), b"extended: &lt;script&gt;" - ) - - self.assertEqual( - render("unescaped_extends_escaped.html"), b"base: &lt;script&gt;" - ) - self.assertEqual( - render("unescaped_overrides_escaped.html"), b"extended: <script>" - ) - - def test_raw_expression(self): - loader = DictLoader(self.templates) - - def render(name): - return loader.load(name).generate(name='<>&"') - - self.assertEqual( - render("raw_expression.html"), b"expr: &lt;&gt;&amp;&quot;\n" b'raw: <>&"' - ) - - def test_custom_escape(self): - loader = DictLoader({"foo.py": "{% autoescape py_escape %}s = {{ name }}\n"}) - - def py_escape(s): - self.assertEqual(type(s), bytes) - return repr(native_str(s)) - - def render(template, name): - return loader.load(template).generate(py_escape=py_escape, name=name) - - self.assertEqual(render("foo.py", "<html>"), b"s = '<html>'\n") - self.assertEqual(render("foo.py", "';sys.exit()"), b"""s = "';sys.exit()"\n""") - self.assertEqual( - render("foo.py", ["not a string"]), b"""s = "['not a string']"\n""" - ) - - def test_manual_minimize_whitespace(self): - # Whitespace including newlines is allowed within template tags - # and directives, and this is one way to avoid long lines while - # keeping extra whitespace out of the rendered output. - loader = DictLoader( - { - "foo.txt": """\ -{% for i in items - %}{% if i > 0 %}, {% end %}{# - #}{{i - }}{% end -%}""" - } - ) - self.assertEqual( - loader.load("foo.txt").generate(items=range(5)), b"0, 1, 2, 3, 4" - ) - - def test_whitespace_by_filename(self): - # Default whitespace handling depends on the template filename. - loader = DictLoader( - { - "foo.html": " \n\t\n asdf\t ", - "bar.js": " \n\n\n\t qwer ", - "baz.txt": "\t zxcv\n\n", - "include.html": " {% include baz.txt %} \n ", - "include.txt": "\t\t{% include foo.html %} ", - } - ) - - # HTML and JS files have whitespace compressed by default. - self.assertEqual(loader.load("foo.html").generate(), b"\nasdf ") - self.assertEqual(loader.load("bar.js").generate(), b"\nqwer ") - # TXT files do not. - self.assertEqual(loader.load("baz.txt").generate(), b"\t zxcv\n\n") - - # Each file maintains its own status even when included in - # a file of the other type. - self.assertEqual(loader.load("include.html").generate(), b" \t zxcv\n\n\n") - self.assertEqual(loader.load("include.txt").generate(), b"\t\t\nasdf ") - - def test_whitespace_by_loader(self): - templates = {"foo.html": "\t\tfoo\n\n", "bar.txt": "\t\tbar\n\n"} - loader = DictLoader(templates, whitespace="all") - self.assertEqual(loader.load("foo.html").generate(), b"\t\tfoo\n\n") - self.assertEqual(loader.load("bar.txt").generate(), b"\t\tbar\n\n") - - loader = DictLoader(templates, whitespace="single") - self.assertEqual(loader.load("foo.html").generate(), b" foo\n") - self.assertEqual(loader.load("bar.txt").generate(), b" bar\n") - - loader = DictLoader(templates, whitespace="oneline") - self.assertEqual(loader.load("foo.html").generate(), b" foo ") - self.assertEqual(loader.load("bar.txt").generate(), b" bar ") - - def test_whitespace_directive(self): - loader = DictLoader( - { - "foo.html": """\ -{% whitespace oneline %} - {% for i in range(3) %} - {{ i }} - {% end %} -{% whitespace all %} - pre\tformatted -""" - } - ) - self.assertEqual( - loader.load("foo.html").generate(), b" 0 1 2 \n pre\tformatted\n" - ) - - -class TemplateLoaderTest(unittest.TestCase): - def setUp(self): - self.loader = Loader(os.path.join(os.path.dirname(__file__), "templates")) - - def test_utf8_in_file(self): - tmpl = self.loader.load("utf8.html") - result = tmpl.generate() - self.assertEqual(to_unicode(result).strip(), u"H\u00e9llo") diff --git a/venv/lib/python3.8/site-packages/tornado/test/templates/utf8.html b/venv/lib/python3.8/site-packages/tornado/test/templates/utf8.html deleted file mode 100644 index c5253df..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/templates/utf8.html +++ /dev/null @@ -1 +0,0 @@ -Héllo diff --git a/venv/lib/python3.8/site-packages/tornado/test/test.crt b/venv/lib/python3.8/site-packages/tornado/test/test.crt deleted file mode 100644 index ffc49b0..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/test.crt +++ /dev/null @@ -1,20 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDWzCCAkOgAwIBAgIUV4spou0CenmvKqa7Hml/MC+JKiAwDQYJKoZIhvcNAQEL -BQAwPTELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExGTAXBgNVBAoM -EFRvcm5hZG8gV2ViIFRlc3QwHhcNMTgwOTI5MTM1NjQ1WhcNMjgwOTI2MTM1NjQ1 -WjA9MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEZMBcGA1UECgwQ -VG9ybmFkbyBXZWIgVGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB -AKT0LdyI8tW5uwP3ahE8BFSz+j3SsKBDv/0cKvqxVVE6sLEST2s3HjArZvIIG5sb -iBkWDrqnZ6UKDvB4jlobLGAkepxDbrxHWxK53n0C28XXGLqJQ01TlTZ5rpjttMeg -5SKNjHbxpOvpUwwQS4br4WjZKKyTGiXpFkFUty+tYVU35/U2yyvreWHmzpHx/25t -H7O2RBARVwJYKOGPtlH62lQjpIWfVfklY4Ip8Hjl3B6rBxPyBULmVQw0qgoZn648 -oa4oLjs0wnYBz01gVjNMDHej52SsB/ieH7W1TxFMzqOlcvHh41uFbQJPgcXsruSS -9Z4twzSWkUp2vk/C//4Sz38CAwEAAaNTMFEwHQYDVR0OBBYEFLf8fQ5+u8sDWAd3 -r5ZjZ5MmDWJeMB8GA1UdIwQYMBaAFLf8fQ5+u8sDWAd3r5ZjZ5MmDWJeMA8GA1Ud -EwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBADkkm3pIb9IeqVNmQ2uhQOgw -UwyToTYUHNTb/Nm5lzBTBqC8gbXAS24RQ30AB/7G115Uxeo+YMKfITxm/CgR+vhF -F59/YrzwXj+G8bdbuVl/UbB6f9RSp+Zo93rUZAtPWr77gxLUrcwSRzzDwxFjC2nC -6eigbkvt1OQY775RwnFAt7HKPclE0Out+cGJIboJuO1f3r57ZdyFH0GzbZEff/7K -atGXohijWJjYvU4mk0KFHORZrcBpsv9cfkFbmgVmiRwxRJ1tLauHM3Ne+VfqYE5M -4rTStSyz3ASqVKJ2iFMQueNR/tUOuDlfRt+0nhJMuYSSkW+KTgnwyOGU9cv+mxA= ------END CERTIFICATE----- diff --git a/venv/lib/python3.8/site-packages/tornado/test/test.key b/venv/lib/python3.8/site-packages/tornado/test/test.key deleted file mode 100644 index 7cb7d8d..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/test.key +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCk9C3ciPLVubsD -92oRPARUs/o90rCgQ7/9HCr6sVVROrCxEk9rNx4wK2byCBubG4gZFg66p2elCg7w -eI5aGyxgJHqcQ268R1sSud59AtvF1xi6iUNNU5U2ea6Y7bTHoOUijYx28aTr6VMM -EEuG6+Fo2Siskxol6RZBVLcvrWFVN+f1Nssr63lh5s6R8f9ubR+ztkQQEVcCWCjh -j7ZR+tpUI6SFn1X5JWOCKfB45dweqwcT8gVC5lUMNKoKGZ+uPKGuKC47NMJ2Ac9N -YFYzTAx3o+dkrAf4nh+1tU8RTM6jpXLx4eNbhW0CT4HF7K7kkvWeLcM0lpFKdr5P -wv/+Es9/AgMBAAECggEABi6AaXtYXloPgB6NgwfUwbfc8OQsalUfpMShd7OdluW0 -KW6eO05de0ClIvzay/1EJGyHMMeFQtIVrT1XWFkcWJ4FWkXMqJGkABenFtg8lDVz -X8o1E3jGZrw4ptKBq9mDvL/BO9PiclTUH+ecbPn6AIvi0lTQ7grGIryiAM9mjmLy -jpCwoutF2LD4RPNg8vqWe/Z1rQw5lp8FOHhRwPooHHeoq1bSrp8dqvVAwAam7Mmf -uFgI8jrNycPgr2cwEEtbq2TQ625MhVnCpwT+kErmAStfbXXuqv1X1ZZgiNxf+61C -OL0bhPRVIHmmjiK/5qHRuN4Q5u9/Yp2SJ4W5xadSQQKBgQDR7dnOlYYQiaoPJeD/ -7jcLVJbWwbr7bE19O/QpYAtkA/FtGlKr+hQxPhK6OYp+in8eHf+ga/NSAjCWRBoh -MNAVCJtiirHo2tFsLFOmlJpGL9n3sX8UnkJN90oHfWrzJ8BZnXaSw2eOuyw8LLj+ -Q+ISl6Go8/xfsuy3EDv4AP1wCwKBgQDJJ4vEV3Kr+bc6N/xeu+G0oHvRAWwuQpcx -9D+XpnqbJbFDnWKNE7oGsDCs8Qjr0CdFUN1pm1ppITDZ5N1cWuDg/47ZAXqEK6D1 -z13S7O0oQPlnsPL7mHs2Vl73muAaBPAojFvceHHfccr7Z94BXqKsiyfaWz6kclT/ -Nl4JTdsC3QKBgQCeYgozL2J/da2lUhnIXcyPstk+29kbueFYu/QBh2HwqnzqqLJ4 -5+t2H3P3plQUFp/DdDSZrvhcBiTsKiNgqThEtkKtfSCvIvBf4a2W/4TJsW6MzxCm -2KQDuK/UqM4Y+APKWN/N6Lln2VWNbNyBkWuuRVKFatccyJyJnSjxeqW7cwKBgGyN -idCYPIrwROAHLItXKvOWE5t0ABRq3TsZC2RkdA/b5HCPs4pclexcEriRjvXrK/Yt -MH94Ve8b+UftSUQ4ytjBMS6MrLg87y0YDhLwxv8NKUq65DXAUOW+8JsAmmWQOqY3 -MK+m1BT4TMklgVoN3w3sPsKIsSJ/jLz5cv/kYweFAoGAG4iWU1378tI2Ts/Fngsv -7eoWhoda77Y9D0Yoy20aN9VdMHzIYCBOubtRPEuwgaReNwbUBWap01J63yY/fF3K -8PTz6covjoOJqxQJOvM7nM0CsJawG9ccw3YXyd9KgRIdSt6ooEhb7N8W2EXYoKl3 -g1i2t41Q/SC3HUGC5mJjpO8= ------END PRIVATE KEY----- diff --git a/venv/lib/python3.8/site-packages/tornado/test/testing_test.py b/venv/lib/python3.8/site-packages/tornado/test/testing_test.py deleted file mode 100644 index 37cb246..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/testing_test.py +++ /dev/null @@ -1,353 +0,0 @@ -from tornado import gen, ioloop -from tornado.httpserver import HTTPServer -from tornado.locks import Event -from tornado.testing import AsyncHTTPTestCase, AsyncTestCase, bind_unused_port, gen_test -from tornado.web import Application -import asyncio -import contextlib -import gc -import os -import platform -import traceback -import unittest -import warnings - - -@contextlib.contextmanager -def set_environ(name, value): - old_value = os.environ.get(name) - os.environ[name] = value - - try: - yield - finally: - if old_value is None: - del os.environ[name] - else: - os.environ[name] = old_value - - -class AsyncTestCaseTest(AsyncTestCase): - def test_wait_timeout(self): - time = self.io_loop.time - - # Accept default 5-second timeout, no error - self.io_loop.add_timeout(time() + 0.01, self.stop) - self.wait() - - # Timeout passed to wait() - self.io_loop.add_timeout(time() + 1, self.stop) - with self.assertRaises(self.failureException): - self.wait(timeout=0.01) - - # Timeout set with environment variable - self.io_loop.add_timeout(time() + 1, self.stop) - with set_environ("ASYNC_TEST_TIMEOUT", "0.01"): - with self.assertRaises(self.failureException): - self.wait() - - def test_subsequent_wait_calls(self): - """ - This test makes sure that a second call to wait() - clears the first timeout. - """ - # The first wait ends with time left on the clock - self.io_loop.add_timeout(self.io_loop.time() + 0.00, self.stop) - self.wait(timeout=0.1) - # The second wait has enough time for itself but would fail if the - # first wait's deadline were still in effect. - self.io_loop.add_timeout(self.io_loop.time() + 0.2, self.stop) - self.wait(timeout=0.4) - - -class LeakTest(AsyncTestCase): - def tearDown(self): - super().tearDown() - # Trigger a gc to make warnings more deterministic. - gc.collect() - - def test_leaked_coroutine(self): - # This test verifies that "leaked" coroutines are shut down - # without triggering warnings like "task was destroyed but it - # is pending". If this test were to fail, it would fail - # because runtests.py detected unexpected output to stderr. - event = Event() - - async def callback(): - try: - await event.wait() - except asyncio.CancelledError: - pass - - self.io_loop.add_callback(callback) - self.io_loop.add_callback(self.stop) - self.wait() - - -class AsyncHTTPTestCaseTest(AsyncHTTPTestCase): - def setUp(self): - super().setUp() - # Bind a second port. - sock, port = bind_unused_port() - app = Application() - server = HTTPServer(app, **self.get_httpserver_options()) - server.add_socket(sock) - self.second_port = port - self.second_server = server - - def get_app(self): - return Application() - - def test_fetch_segment(self): - path = "/path" - response = self.fetch(path) - self.assertEqual(response.request.url, self.get_url(path)) - - def test_fetch_full_http_url(self): - # Ensure that self.fetch() recognizes absolute urls and does - # not transform them into references to our main test server. - path = "http://localhost:%d/path" % self.second_port - - response = self.fetch(path) - self.assertEqual(response.request.url, path) - - def tearDown(self): - self.second_server.stop() - super().tearDown() - - -class AsyncTestCaseWrapperTest(unittest.TestCase): - def test_undecorated_generator(self): - class Test(AsyncTestCase): - def test_gen(self): - yield - - test = Test("test_gen") - result = unittest.TestResult() - test.run(result) - self.assertEqual(len(result.errors), 1) - self.assertIn("should be decorated", result.errors[0][1]) - - @unittest.skipIf( - platform.python_implementation() == "PyPy", - "pypy destructor warnings cannot be silenced", - ) - def test_undecorated_coroutine(self): - class Test(AsyncTestCase): - async def test_coro(self): - pass - - test = Test("test_coro") - result = unittest.TestResult() - - # Silence "RuntimeWarning: coroutine 'test_coro' was never awaited". - with warnings.catch_warnings(): - warnings.simplefilter("ignore") - test.run(result) - - self.assertEqual(len(result.errors), 1) - self.assertIn("should be decorated", result.errors[0][1]) - - def test_undecorated_generator_with_skip(self): - class Test(AsyncTestCase): - @unittest.skip("don't run this") - def test_gen(self): - yield - - test = Test("test_gen") - result = unittest.TestResult() - test.run(result) - self.assertEqual(len(result.errors), 0) - self.assertEqual(len(result.skipped), 1) - - def test_other_return(self): - class Test(AsyncTestCase): - def test_other_return(self): - return 42 - - test = Test("test_other_return") - result = unittest.TestResult() - test.run(result) - self.assertEqual(len(result.errors), 1) - self.assertIn("Return value from test method ignored", result.errors[0][1]) - - -class SetUpTearDownTest(unittest.TestCase): - def test_set_up_tear_down(self): - """ - This test makes sure that AsyncTestCase calls super methods for - setUp and tearDown. - - InheritBoth is a subclass of both AsyncTestCase and - SetUpTearDown, with the ordering so that the super of - AsyncTestCase will be SetUpTearDown. - """ - events = [] - result = unittest.TestResult() - - class SetUpTearDown(unittest.TestCase): - def setUp(self): - events.append("setUp") - - def tearDown(self): - events.append("tearDown") - - class InheritBoth(AsyncTestCase, SetUpTearDown): - def test(self): - events.append("test") - - InheritBoth("test").run(result) - expected = ["setUp", "test", "tearDown"] - self.assertEqual(expected, events) - - -class AsyncHTTPTestCaseSetUpTearDownTest(unittest.TestCase): - def test_tear_down_releases_app_and_http_server(self): - result = unittest.TestResult() - - class SetUpTearDown(AsyncHTTPTestCase): - def get_app(self): - return Application() - - def test(self): - self.assertTrue(hasattr(self, "_app")) - self.assertTrue(hasattr(self, "http_server")) - - test = SetUpTearDown("test") - test.run(result) - self.assertFalse(hasattr(test, "_app")) - self.assertFalse(hasattr(test, "http_server")) - - -class GenTest(AsyncTestCase): - def setUp(self): - super().setUp() - self.finished = False - - def tearDown(self): - self.assertTrue(self.finished) - super().tearDown() - - @gen_test - def test_sync(self): - self.finished = True - - @gen_test - def test_async(self): - yield gen.moment - self.finished = True - - def test_timeout(self): - # Set a short timeout and exceed it. - @gen_test(timeout=0.1) - def test(self): - yield gen.sleep(1) - - # This can't use assertRaises because we need to inspect the - # exc_info triple (and not just the exception object) - try: - test(self) - self.fail("did not get expected exception") - except ioloop.TimeoutError: - # The stack trace should blame the add_timeout line, not just - # unrelated IOLoop/testing internals. - self.assertIn("gen.sleep(1)", traceback.format_exc()) - - self.finished = True - - def test_no_timeout(self): - # A test that does not exceed its timeout should succeed. - @gen_test(timeout=1) - def test(self): - yield gen.sleep(0.1) - - test(self) - self.finished = True - - def test_timeout_environment_variable(self): - @gen_test(timeout=0.5) - def test_long_timeout(self): - yield gen.sleep(0.25) - - # Uses provided timeout of 0.5 seconds, doesn't time out. - with set_environ("ASYNC_TEST_TIMEOUT", "0.1"): - test_long_timeout(self) - - self.finished = True - - def test_no_timeout_environment_variable(self): - @gen_test(timeout=0.01) - def test_short_timeout(self): - yield gen.sleep(1) - - # Uses environment-variable timeout of 0.1, times out. - with set_environ("ASYNC_TEST_TIMEOUT", "0.1"): - with self.assertRaises(ioloop.TimeoutError): - test_short_timeout(self) - - self.finished = True - - def test_with_method_args(self): - @gen_test - def test_with_args(self, *args): - self.assertEqual(args, ("test",)) - yield gen.moment - - test_with_args(self, "test") - self.finished = True - - def test_with_method_kwargs(self): - @gen_test - def test_with_kwargs(self, **kwargs): - self.assertDictEqual(kwargs, {"test": "test"}) - yield gen.moment - - test_with_kwargs(self, test="test") - self.finished = True - - def test_native_coroutine(self): - @gen_test - async def test(self): - self.finished = True - - test(self) - - def test_native_coroutine_timeout(self): - # Set a short timeout and exceed it. - @gen_test(timeout=0.1) - async def test(self): - await gen.sleep(1) - - try: - test(self) - self.fail("did not get expected exception") - except ioloop.TimeoutError: - self.finished = True - - -class GetNewIOLoopTest(AsyncTestCase): - def get_new_ioloop(self): - # Use the current loop instead of creating a new one here. - return ioloop.IOLoop.current() - - def setUp(self): - # This simulates the effect of an asyncio test harness like - # pytest-asyncio. - self.orig_loop = asyncio.get_event_loop() - self.new_loop = asyncio.new_event_loop() - asyncio.set_event_loop(self.new_loop) - super().setUp() - - def tearDown(self): - super().tearDown() - # AsyncTestCase must not affect the existing asyncio loop. - self.assertFalse(asyncio.get_event_loop().is_closed()) - asyncio.set_event_loop(self.orig_loop) - self.new_loop.close() - - def test_loop(self): - self.assertIs(self.io_loop.asyncio_loop, self.new_loop) # type: ignore - - -if __name__ == "__main__": - unittest.main() diff --git a/venv/lib/python3.8/site-packages/tornado/test/twisted_test.py b/venv/lib/python3.8/site-packages/tornado/test/twisted_test.py deleted file mode 100644 index 661953d..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/twisted_test.py +++ /dev/null @@ -1,247 +0,0 @@ -# Author: Ovidiu Predescu -# Date: July 2011 -# -# 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. - -import asyncio -import logging -import signal -import unittest -import warnings - -from tornado.escape import utf8 -from tornado import gen -from tornado.httpclient import AsyncHTTPClient -from tornado.httpserver import HTTPServer -from tornado.ioloop import IOLoop -from tornado.testing import bind_unused_port, AsyncTestCase, gen_test -from tornado.web import RequestHandler, Application - -try: - from twisted.internet.defer import ( # type: ignore - Deferred, - inlineCallbacks, - returnValue, - ) - from twisted.internet.protocol import Protocol # type: ignore - from twisted.internet.asyncioreactor import AsyncioSelectorReactor # type: ignore - from twisted.web.client import Agent, readBody # type: ignore - from twisted.web.resource import Resource # type: ignore - from twisted.web.server import Site # type: ignore - - have_twisted = True -except ImportError: - have_twisted = False -else: - # Not used directly but needed for `yield deferred` to work. - import tornado.platform.twisted # noqa: F401 - -skipIfNoTwisted = unittest.skipUnless(have_twisted, "twisted module not present") - - -def save_signal_handlers(): - saved = {} - signals = [signal.SIGINT, signal.SIGTERM] - if hasattr(signal, "SIGCHLD"): - signals.append(signal.SIGCHLD) - for sig in signals: - saved[sig] = signal.getsignal(sig) - if "twisted" in repr(saved): - # This indicates we're not cleaning up after ourselves properly. - raise Exception("twisted signal handlers already installed") - return saved - - -def restore_signal_handlers(saved): - for sig, handler in saved.items(): - signal.signal(sig, handler) - - -# Test various combinations of twisted and tornado http servers, -# http clients, and event loop interfaces. - - -@skipIfNoTwisted -class CompatibilityTests(unittest.TestCase): - def setUp(self): - self.saved_signals = save_signal_handlers() - self.saved_policy = asyncio.get_event_loop_policy() - if hasattr(asyncio, "WindowsSelectorEventLoopPolicy"): - # Twisted requires a selector event loop, even if Tornado is - # doing its own tricks in AsyncIOLoop to support proactors. - # Setting an AddThreadSelectorEventLoop exposes various edge - # cases so just use a regular selector. - asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) # type: ignore - self.io_loop = IOLoop() - self.io_loop.make_current() - self.reactor = AsyncioSelectorReactor() - - def tearDown(self): - self.reactor.disconnectAll() - self.io_loop.clear_current() - self.io_loop.close(all_fds=True) - asyncio.set_event_loop_policy(self.saved_policy) - restore_signal_handlers(self.saved_signals) - - def start_twisted_server(self): - class HelloResource(Resource): - isLeaf = True - - def render_GET(self, request): - return b"Hello from twisted!" - - site = Site(HelloResource()) - port = self.reactor.listenTCP(0, site, interface="127.0.0.1") - self.twisted_port = port.getHost().port - - def start_tornado_server(self): - class HelloHandler(RequestHandler): - def get(self): - self.write("Hello from tornado!") - - app = Application([("/", HelloHandler)], log_function=lambda x: None) - server = HTTPServer(app) - sock, self.tornado_port = bind_unused_port() - server.add_sockets([sock]) - - def run_reactor(self): - # In theory, we can run the event loop through Tornado, - # Twisted, or asyncio interfaces. However, since we're trying - # to avoid installing anything as the global event loop, only - # the twisted interface gets everything wired up correectly - # without extra hacks. This method is a part of a - # no-longer-used generalization that allowed us to test - # different combinations. - self.stop_loop = self.reactor.stop - self.stop = self.reactor.stop - self.reactor.run() - - def tornado_fetch(self, url, runner): - client = AsyncHTTPClient() - fut = asyncio.ensure_future(client.fetch(url)) - fut.add_done_callback(lambda f: self.stop_loop()) - runner() - return fut.result() - - def twisted_fetch(self, url, runner): - # http://twistedmatrix.com/documents/current/web/howto/client.html - chunks = [] - client = Agent(self.reactor) - d = client.request(b"GET", utf8(url)) - - class Accumulator(Protocol): - def __init__(self, finished): - self.finished = finished - - def dataReceived(self, data): - chunks.append(data) - - def connectionLost(self, reason): - self.finished.callback(None) - - def callback(response): - finished = Deferred() - response.deliverBody(Accumulator(finished)) - return finished - - d.addCallback(callback) - - def shutdown(failure): - if hasattr(self, "stop_loop"): - self.stop_loop() - elif failure is not None: - # loop hasn't been initialized yet; try our best to - # get an error message out. (the runner() interaction - # should probably be refactored). - try: - failure.raiseException() - except: - logging.error("exception before starting loop", exc_info=True) - - d.addBoth(shutdown) - runner() - self.assertTrue(chunks) - return b"".join(chunks) - - def twisted_coroutine_fetch(self, url, runner): - body = [None] - - @gen.coroutine - def f(): - # This is simpler than the non-coroutine version, but it cheats - # by reading the body in one blob instead of streaming it with - # a Protocol. - client = Agent(self.reactor) - response = yield client.request(b"GET", utf8(url)) - with warnings.catch_warnings(): - # readBody has a buggy DeprecationWarning in Twisted 15.0: - # https://twistedmatrix.com/trac/changeset/43379 - warnings.simplefilter("ignore", category=DeprecationWarning) - body[0] = yield readBody(response) - self.stop_loop() - - self.io_loop.add_callback(f) - runner() - return body[0] - - def testTwistedServerTornadoClientReactor(self): - self.start_twisted_server() - response = self.tornado_fetch( - "http://127.0.0.1:%d" % self.twisted_port, self.run_reactor - ) - self.assertEqual(response.body, b"Hello from twisted!") - - def testTornadoServerTwistedClientReactor(self): - self.start_tornado_server() - response = self.twisted_fetch( - "http://127.0.0.1:%d" % self.tornado_port, self.run_reactor - ) - self.assertEqual(response, b"Hello from tornado!") - - def testTornadoServerTwistedCoroutineClientReactor(self): - self.start_tornado_server() - response = self.twisted_coroutine_fetch( - "http://127.0.0.1:%d" % self.tornado_port, self.run_reactor - ) - self.assertEqual(response, b"Hello from tornado!") - - -@skipIfNoTwisted -class ConvertDeferredTest(AsyncTestCase): - @gen_test - def test_success(self): - @inlineCallbacks - def fn(): - if False: - # inlineCallbacks doesn't work with regular functions; - # must have a yield even if it's unreachable. - yield - returnValue(42) - - res = yield fn() - self.assertEqual(res, 42) - - @gen_test - def test_failure(self): - @inlineCallbacks - def fn(): - if False: - yield - 1 / 0 - - with self.assertRaises(ZeroDivisionError): - yield fn() - - -if __name__ == "__main__": - unittest.main() diff --git a/venv/lib/python3.8/site-packages/tornado/test/util.py b/venv/lib/python3.8/site-packages/tornado/test/util.py deleted file mode 100644 index bcb9bbd..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/util.py +++ /dev/null @@ -1,114 +0,0 @@ -import contextlib -import os -import platform -import socket -import sys -import textwrap -import typing # noqa: F401 -import unittest -import warnings - -from tornado.testing import bind_unused_port - -skipIfNonUnix = unittest.skipIf( - os.name != "posix" or sys.platform == "cygwin", "non-unix platform" -) - -# travis-ci.org runs our tests in an overworked virtual machine, which makes -# timing-related tests unreliable. -skipOnTravis = unittest.skipIf( - "TRAVIS" in os.environ, "timing tests unreliable on travis" -) - -# Set the environment variable NO_NETWORK=1 to disable any tests that -# depend on an external network. -skipIfNoNetwork = unittest.skipIf("NO_NETWORK" in os.environ, "network access disabled") - -skipNotCPython = unittest.skipIf( - platform.python_implementation() != "CPython", "Not CPython implementation" -) - -# Used for tests affected by -# https://bitbucket.org/pypy/pypy/issues/2616/incomplete-error-handling-in -# TODO: remove this after pypy3 5.8 is obsolete. -skipPypy3V58 = unittest.skipIf( - platform.python_implementation() == "PyPy" - and sys.version_info > (3,) - and sys.pypy_version_info < (5, 9), # type: ignore - "pypy3 5.8 has buggy ssl module", -) - - -def _detect_ipv6(): - if not socket.has_ipv6: - # socket.has_ipv6 check reports whether ipv6 was present at compile - # time. It's usually true even when ipv6 doesn't work for other reasons. - return False - sock = None - try: - sock = socket.socket(socket.AF_INET6) - sock.bind(("::1", 0)) - except socket.error: - return False - finally: - if sock is not None: - sock.close() - return True - - -skipIfNoIPv6 = unittest.skipIf(not _detect_ipv6(), "ipv6 support not present") - - -def refusing_port(): - """Returns a local port number that will refuse all connections. - - Return value is (cleanup_func, port); the cleanup function - must be called to free the port to be reused. - """ - # On travis-ci, port numbers are reassigned frequently. To avoid - # collisions with other tests, we use an open client-side socket's - # ephemeral port number to ensure that nothing can listen on that - # port. - server_socket, port = bind_unused_port() - server_socket.setblocking(True) - client_socket = socket.socket() - client_socket.connect(("127.0.0.1", port)) - conn, client_addr = server_socket.accept() - conn.close() - server_socket.close() - return (client_socket.close, client_addr[1]) - - -def exec_test(caller_globals, caller_locals, s): - """Execute ``s`` in a given context and return the result namespace. - - Used to define functions for tests in particular python - versions that would be syntax errors in older versions. - """ - # Flatten the real global and local namespace into our fake - # globals: it's all global from the perspective of code defined - # in s. - global_namespace = dict(caller_globals, **caller_locals) # type: ignore - local_namespace = {} # type: typing.Dict[str, typing.Any] - exec(textwrap.dedent(s), global_namespace, local_namespace) - return local_namespace - - -def subTest(test, *args, **kwargs): - """Compatibility shim for unittest.TestCase.subTest. - - Usage: ``with tornado.test.util.subTest(self, x=x):`` - """ - try: - subTest = test.subTest # py34+ - except AttributeError: - subTest = contextlib.contextmanager(lambda *a, **kw: (yield)) - return subTest(*args, **kwargs) - - -@contextlib.contextmanager -def ignore_deprecation(): - """Context manager to ignore deprecation warnings.""" - with warnings.catch_warnings(): - warnings.simplefilter("ignore", DeprecationWarning) - yield diff --git a/venv/lib/python3.8/site-packages/tornado/test/util_test.py b/venv/lib/python3.8/site-packages/tornado/test/util_test.py deleted file mode 100644 index 0cbc13c..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/util_test.py +++ /dev/null @@ -1,308 +0,0 @@ -from io import StringIO -import re -import sys -import datetime -import unittest - -import tornado.escape -from tornado.escape import utf8 -from tornado.util import ( - raise_exc_info, - Configurable, - exec_in, - ArgReplacer, - timedelta_to_seconds, - import_object, - re_unescape, - is_finalizing, -) - -import typing -from typing import cast - -if typing.TYPE_CHECKING: - from typing import Dict, Any # noqa: F401 - - -class RaiseExcInfoTest(unittest.TestCase): - def test_two_arg_exception(self): - # This test would fail on python 3 if raise_exc_info were simply - # a three-argument raise statement, because TwoArgException - # doesn't have a "copy constructor" - class TwoArgException(Exception): - def __init__(self, a, b): - super().__init__() - self.a, self.b = a, b - - try: - raise TwoArgException(1, 2) - except TwoArgException: - exc_info = sys.exc_info() - try: - raise_exc_info(exc_info) - self.fail("didn't get expected exception") - except TwoArgException as e: - self.assertIs(e, exc_info[1]) - - -class TestConfigurable(Configurable): - @classmethod - def configurable_base(cls): - return TestConfigurable - - @classmethod - def configurable_default(cls): - return TestConfig1 - - -class TestConfig1(TestConfigurable): - def initialize(self, pos_arg=None, a=None): - self.a = a - self.pos_arg = pos_arg - - -class TestConfig2(TestConfigurable): - def initialize(self, pos_arg=None, b=None): - self.b = b - self.pos_arg = pos_arg - - -class TestConfig3(TestConfigurable): - # TestConfig3 is a configuration option that is itself configurable. - @classmethod - def configurable_base(cls): - return TestConfig3 - - @classmethod - def configurable_default(cls): - return TestConfig3A - - -class TestConfig3A(TestConfig3): - def initialize(self, a=None): - self.a = a - - -class TestConfig3B(TestConfig3): - def initialize(self, b=None): - self.b = b - - -class ConfigurableTest(unittest.TestCase): - def setUp(self): - self.saved = TestConfigurable._save_configuration() - self.saved3 = TestConfig3._save_configuration() - - def tearDown(self): - TestConfigurable._restore_configuration(self.saved) - TestConfig3._restore_configuration(self.saved3) - - def checkSubclasses(self): - # no matter how the class is configured, it should always be - # possible to instantiate the subclasses directly - self.assertIsInstance(TestConfig1(), TestConfig1) - self.assertIsInstance(TestConfig2(), TestConfig2) - - obj = TestConfig1(a=1) - self.assertEqual(obj.a, 1) - obj2 = TestConfig2(b=2) - self.assertEqual(obj2.b, 2) - - def test_default(self): - # In these tests we combine a typing.cast to satisfy mypy with - # a runtime type-assertion. Without the cast, mypy would only - # let us access attributes of the base class. - obj = cast(TestConfig1, TestConfigurable()) - self.assertIsInstance(obj, TestConfig1) - self.assertIs(obj.a, None) - - obj = cast(TestConfig1, TestConfigurable(a=1)) - self.assertIsInstance(obj, TestConfig1) - self.assertEqual(obj.a, 1) - - self.checkSubclasses() - - def test_config_class(self): - TestConfigurable.configure(TestConfig2) - obj = cast(TestConfig2, TestConfigurable()) - self.assertIsInstance(obj, TestConfig2) - self.assertIs(obj.b, None) - - obj = cast(TestConfig2, TestConfigurable(b=2)) - self.assertIsInstance(obj, TestConfig2) - self.assertEqual(obj.b, 2) - - self.checkSubclasses() - - def test_config_str(self): - TestConfigurable.configure("tornado.test.util_test.TestConfig2") - obj = cast(TestConfig2, TestConfigurable()) - self.assertIsInstance(obj, TestConfig2) - self.assertIs(obj.b, None) - - obj = cast(TestConfig2, TestConfigurable(b=2)) - self.assertIsInstance(obj, TestConfig2) - self.assertEqual(obj.b, 2) - - self.checkSubclasses() - - def test_config_args(self): - TestConfigurable.configure(None, a=3) - obj = cast(TestConfig1, TestConfigurable()) - self.assertIsInstance(obj, TestConfig1) - self.assertEqual(obj.a, 3) - - obj = cast(TestConfig1, TestConfigurable(42, a=4)) - self.assertIsInstance(obj, TestConfig1) - self.assertEqual(obj.a, 4) - self.assertEqual(obj.pos_arg, 42) - - self.checkSubclasses() - # args bound in configure don't apply when using the subclass directly - obj = TestConfig1() - self.assertIs(obj.a, None) - - def test_config_class_args(self): - TestConfigurable.configure(TestConfig2, b=5) - obj = cast(TestConfig2, TestConfigurable()) - self.assertIsInstance(obj, TestConfig2) - self.assertEqual(obj.b, 5) - - obj = cast(TestConfig2, TestConfigurable(42, b=6)) - self.assertIsInstance(obj, TestConfig2) - self.assertEqual(obj.b, 6) - self.assertEqual(obj.pos_arg, 42) - - self.checkSubclasses() - # args bound in configure don't apply when using the subclass directly - obj = TestConfig2() - self.assertIs(obj.b, None) - - def test_config_multi_level(self): - TestConfigurable.configure(TestConfig3, a=1) - obj = cast(TestConfig3A, TestConfigurable()) - self.assertIsInstance(obj, TestConfig3A) - self.assertEqual(obj.a, 1) - - TestConfigurable.configure(TestConfig3) - TestConfig3.configure(TestConfig3B, b=2) - obj2 = cast(TestConfig3B, TestConfigurable()) - self.assertIsInstance(obj2, TestConfig3B) - self.assertEqual(obj2.b, 2) - - def test_config_inner_level(self): - # The inner level can be used even when the outer level - # doesn't point to it. - obj = TestConfig3() - self.assertIsInstance(obj, TestConfig3A) - - TestConfig3.configure(TestConfig3B) - obj = TestConfig3() - self.assertIsInstance(obj, TestConfig3B) - - # Configuring the base doesn't configure the inner. - obj2 = TestConfigurable() - self.assertIsInstance(obj2, TestConfig1) - TestConfigurable.configure(TestConfig2) - - obj3 = TestConfigurable() - self.assertIsInstance(obj3, TestConfig2) - - obj = TestConfig3() - self.assertIsInstance(obj, TestConfig3B) - - -class UnicodeLiteralTest(unittest.TestCase): - def test_unicode_escapes(self): - self.assertEqual(utf8(u"\u00e9"), b"\xc3\xa9") - - -class ExecInTest(unittest.TestCase): - # TODO(bdarnell): make a version of this test for one of the new - # future imports available in python 3. - @unittest.skip("no testable future imports") - def test_no_inherit_future(self): - # This file has from __future__ import print_function... - f = StringIO() - print("hello", file=f) - # ...but the template doesn't - exec_in('print >> f, "world"', dict(f=f)) - self.assertEqual(f.getvalue(), "hello\nworld\n") - - -class ArgReplacerTest(unittest.TestCase): - def setUp(self): - def function(x, y, callback=None, z=None): - pass - - self.replacer = ArgReplacer(function, "callback") - - def test_omitted(self): - args = (1, 2) - kwargs = dict() # type: Dict[str, Any] - self.assertIs(self.replacer.get_old_value(args, kwargs), None) - self.assertEqual( - self.replacer.replace("new", args, kwargs), - (None, (1, 2), dict(callback="new")), - ) - - def test_position(self): - args = (1, 2, "old", 3) - kwargs = dict() # type: Dict[str, Any] - self.assertEqual(self.replacer.get_old_value(args, kwargs), "old") - self.assertEqual( - self.replacer.replace("new", args, kwargs), - ("old", [1, 2, "new", 3], dict()), - ) - - def test_keyword(self): - args = (1,) - kwargs = dict(y=2, callback="old", z=3) - self.assertEqual(self.replacer.get_old_value(args, kwargs), "old") - self.assertEqual( - self.replacer.replace("new", args, kwargs), - ("old", (1,), dict(y=2, callback="new", z=3)), - ) - - -class TimedeltaToSecondsTest(unittest.TestCase): - def test_timedelta_to_seconds(self): - time_delta = datetime.timedelta(hours=1) - self.assertEqual(timedelta_to_seconds(time_delta), 3600.0) - - -class ImportObjectTest(unittest.TestCase): - def test_import_member(self): - self.assertIs(import_object("tornado.escape.utf8"), utf8) - - def test_import_member_unicode(self): - self.assertIs(import_object(u"tornado.escape.utf8"), utf8) - - def test_import_module(self): - self.assertIs(import_object("tornado.escape"), tornado.escape) - - def test_import_module_unicode(self): - # The internal implementation of __import__ differs depending on - # whether the thing being imported is a module or not. - # This variant requires a byte string in python 2. - self.assertIs(import_object(u"tornado.escape"), tornado.escape) - - -class ReUnescapeTest(unittest.TestCase): - def test_re_unescape(self): - test_strings = ("/favicon.ico", "index.html", "Hello, World!", "!$@#%;") - for string in test_strings: - self.assertEqual(string, re_unescape(re.escape(string))) - - def test_re_unescape_raises_error_on_invalid_input(self): - with self.assertRaises(ValueError): - re_unescape("\\d") - with self.assertRaises(ValueError): - re_unescape("\\b") - with self.assertRaises(ValueError): - re_unescape("\\Z") - - -class IsFinalizingTest(unittest.TestCase): - def test_basic(self): - self.assertFalse(is_finalizing()) diff --git a/venv/lib/python3.8/site-packages/tornado/test/web_test.py b/venv/lib/python3.8/site-packages/tornado/test/web_test.py deleted file mode 100644 index 5490ba2..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/web_test.py +++ /dev/null @@ -1,3156 +0,0 @@ -from tornado.concurrent import Future -from tornado import gen -from tornado.escape import ( - json_decode, - utf8, - to_unicode, - recursive_unicode, - native_str, - to_basestring, -) -from tornado.httpclient import HTTPClientError -from tornado.httputil import format_timestamp -from tornado.iostream import IOStream -from tornado import locale -from tornado.locks import Event -from tornado.log import app_log, gen_log -from tornado.simple_httpclient import SimpleAsyncHTTPClient -from tornado.template import DictLoader -from tornado.testing import AsyncHTTPTestCase, AsyncTestCase, ExpectLog, gen_test -from tornado.util import ObjectDict, unicode_type -from tornado.web import ( - Application, - RequestHandler, - StaticFileHandler, - RedirectHandler as WebRedirectHandler, - HTTPError, - MissingArgumentError, - ErrorHandler, - authenticated, - url, - _create_signature_v1, - create_signed_value, - decode_signed_value, - get_signature_key_version, - UIModule, - Finish, - stream_request_body, - removeslash, - addslash, - GZipContentEncoding, -) - -import binascii -import contextlib -import copy -import datetime -import email.utils -import gzip -from io import BytesIO -import itertools -import logging -import os -import re -import socket -import typing # noqa: F401 -import unittest -import urllib.parse - - -def relpath(*a): - return os.path.join(os.path.dirname(__file__), *a) - - -class WebTestCase(AsyncHTTPTestCase): - """Base class for web tests that also supports WSGI mode. - - Override get_handlers and get_app_kwargs instead of get_app. - This class is deprecated since WSGI mode is no longer supported. - """ - - def get_app(self): - self.app = Application(self.get_handlers(), **self.get_app_kwargs()) - return self.app - - def get_handlers(self): - raise NotImplementedError() - - def get_app_kwargs(self): - return {} - - -class SimpleHandlerTestCase(WebTestCase): - """Simplified base class for tests that work with a single handler class. - - To use, define a nested class named ``Handler``. - """ - - Handler = None - - def get_handlers(self): - return [("/", self.Handler)] - - -class HelloHandler(RequestHandler): - def get(self): - self.write("hello") - - -class CookieTestRequestHandler(RequestHandler): - # stub out enough methods to make the secure_cookie functions work - def __init__(self, cookie_secret="0123456789", key_version=None): - # don't call super.__init__ - self._cookies = {} # type: typing.Dict[str, bytes] - if key_version is None: - self.application = ObjectDict( # type: ignore - settings=dict(cookie_secret=cookie_secret) - ) - else: - self.application = ObjectDict( # type: ignore - settings=dict(cookie_secret=cookie_secret, key_version=key_version) - ) - - def get_cookie(self, name): - return self._cookies.get(name) - - def set_cookie(self, name, value, expires_days=None): - self._cookies[name] = value - - -# See SignedValueTest below for more. -class SecureCookieV1Test(unittest.TestCase): - def test_round_trip(self): - handler = CookieTestRequestHandler() - handler.set_secure_cookie("foo", b"bar", version=1) - self.assertEqual(handler.get_secure_cookie("foo", min_version=1), b"bar") - - def test_cookie_tampering_future_timestamp(self): - handler = CookieTestRequestHandler() - # this string base64-encodes to '12345678' - handler.set_secure_cookie("foo", binascii.a2b_hex(b"d76df8e7aefc"), version=1) - cookie = handler._cookies["foo"] - match = re.match(br"12345678\|([0-9]+)\|([0-9a-f]+)", cookie) - assert match is not None - timestamp = match.group(1) - sig = match.group(2) - self.assertEqual( - _create_signature_v1( - handler.application.settings["cookie_secret"], - "foo", - "12345678", - timestamp, - ), - sig, - ) - # shifting digits from payload to timestamp doesn't alter signature - # (this is not desirable behavior, just confirming that that's how it - # works) - self.assertEqual( - _create_signature_v1( - handler.application.settings["cookie_secret"], - "foo", - "1234", - b"5678" + timestamp, - ), - sig, - ) - # tamper with the cookie - handler._cookies["foo"] = utf8( - "1234|5678%s|%s" % (to_basestring(timestamp), to_basestring(sig)) - ) - # it gets rejected - with ExpectLog(gen_log, "Cookie timestamp in future"): - self.assertTrue(handler.get_secure_cookie("foo", min_version=1) is None) - - def test_arbitrary_bytes(self): - # Secure cookies accept arbitrary data (which is base64 encoded). - # Note that normal cookies accept only a subset of ascii. - handler = CookieTestRequestHandler() - handler.set_secure_cookie("foo", b"\xe9", version=1) - self.assertEqual(handler.get_secure_cookie("foo", min_version=1), b"\xe9") - - -# See SignedValueTest below for more. -class SecureCookieV2Test(unittest.TestCase): - KEY_VERSIONS = {0: "ajklasdf0ojaisdf", 1: "aslkjasaolwkjsdf"} - - def test_round_trip(self): - handler = CookieTestRequestHandler() - handler.set_secure_cookie("foo", b"bar", version=2) - self.assertEqual(handler.get_secure_cookie("foo", min_version=2), b"bar") - - def test_key_version_roundtrip(self): - handler = CookieTestRequestHandler( - cookie_secret=self.KEY_VERSIONS, key_version=0 - ) - handler.set_secure_cookie("foo", b"bar") - self.assertEqual(handler.get_secure_cookie("foo"), b"bar") - - def test_key_version_roundtrip_differing_version(self): - handler = CookieTestRequestHandler( - cookie_secret=self.KEY_VERSIONS, key_version=1 - ) - handler.set_secure_cookie("foo", b"bar") - self.assertEqual(handler.get_secure_cookie("foo"), b"bar") - - def test_key_version_increment_version(self): - handler = CookieTestRequestHandler( - cookie_secret=self.KEY_VERSIONS, key_version=0 - ) - handler.set_secure_cookie("foo", b"bar") - new_handler = CookieTestRequestHandler( - cookie_secret=self.KEY_VERSIONS, key_version=1 - ) - new_handler._cookies = handler._cookies - self.assertEqual(new_handler.get_secure_cookie("foo"), b"bar") - - def test_key_version_invalidate_version(self): - handler = CookieTestRequestHandler( - cookie_secret=self.KEY_VERSIONS, key_version=0 - ) - handler.set_secure_cookie("foo", b"bar") - new_key_versions = self.KEY_VERSIONS.copy() - new_key_versions.pop(0) - new_handler = CookieTestRequestHandler( - cookie_secret=new_key_versions, key_version=1 - ) - new_handler._cookies = handler._cookies - self.assertEqual(new_handler.get_secure_cookie("foo"), None) - - -class FinalReturnTest(WebTestCase): - final_return = None # type: Future - - def get_handlers(self): - test = self - - class FinishHandler(RequestHandler): - @gen.coroutine - def get(self): - test.final_return = self.finish() - yield test.final_return - - @gen.coroutine - def post(self): - self.write("hello,") - yield self.flush() - test.final_return = self.finish("world") - yield test.final_return - - class RenderHandler(RequestHandler): - def create_template_loader(self, path): - return DictLoader({"foo.html": "hi"}) - - @gen.coroutine - def get(self): - test.final_return = self.render("foo.html") - - return [("/finish", FinishHandler), ("/render", RenderHandler)] - - def get_app_kwargs(self): - return dict(template_path="FinalReturnTest") - - def test_finish_method_return_future(self): - response = self.fetch(self.get_url("/finish")) - self.assertEqual(response.code, 200) - self.assertIsInstance(self.final_return, Future) - self.assertTrue(self.final_return.done()) - - response = self.fetch(self.get_url("/finish"), method="POST", body=b"") - self.assertEqual(response.code, 200) - self.assertIsInstance(self.final_return, Future) - self.assertTrue(self.final_return.done()) - - def test_render_method_return_future(self): - response = self.fetch(self.get_url("/render")) - self.assertEqual(response.code, 200) - self.assertIsInstance(self.final_return, Future) - - -class CookieTest(WebTestCase): - def get_handlers(self): - class SetCookieHandler(RequestHandler): - def get(self): - # Try setting cookies with different argument types - # to ensure that everything gets encoded correctly - self.set_cookie("str", "asdf") - self.set_cookie("unicode", u"qwer") - self.set_cookie("bytes", b"zxcv") - - class GetCookieHandler(RequestHandler): - def get(self): - cookie = self.get_cookie("foo", "default") - assert cookie is not None - self.write(cookie) - - class SetCookieDomainHandler(RequestHandler): - def get(self): - # unicode domain and path arguments shouldn't break things - # either (see bug #285) - self.set_cookie("unicode_args", "blah", domain=u"foo.com", path=u"/foo") - - class SetCookieSpecialCharHandler(RequestHandler): - def get(self): - self.set_cookie("equals", "a=b") - self.set_cookie("semicolon", "a;b") - self.set_cookie("quote", 'a"b') - - class SetCookieOverwriteHandler(RequestHandler): - def get(self): - self.set_cookie("a", "b", domain="example.com") - self.set_cookie("c", "d", domain="example.com") - # A second call with the same name clobbers the first. - # Attributes from the first call are not carried over. - self.set_cookie("a", "e") - - class SetCookieMaxAgeHandler(RequestHandler): - def get(self): - self.set_cookie("foo", "bar", max_age=10) - - class SetCookieExpiresDaysHandler(RequestHandler): - def get(self): - self.set_cookie("foo", "bar", expires_days=10) - - class SetCookieFalsyFlags(RequestHandler): - def get(self): - self.set_cookie("a", "1", secure=True) - self.set_cookie("b", "1", secure=False) - self.set_cookie("c", "1", httponly=True) - self.set_cookie("d", "1", httponly=False) - - return [ - ("/set", SetCookieHandler), - ("/get", GetCookieHandler), - ("/set_domain", SetCookieDomainHandler), - ("/special_char", SetCookieSpecialCharHandler), - ("/set_overwrite", SetCookieOverwriteHandler), - ("/set_max_age", SetCookieMaxAgeHandler), - ("/set_expires_days", SetCookieExpiresDaysHandler), - ("/set_falsy_flags", SetCookieFalsyFlags), - ] - - def test_set_cookie(self): - response = self.fetch("/set") - self.assertEqual( - sorted(response.headers.get_list("Set-Cookie")), - ["bytes=zxcv; Path=/", "str=asdf; Path=/", "unicode=qwer; Path=/"], - ) - - def test_get_cookie(self): - response = self.fetch("/get", headers={"Cookie": "foo=bar"}) - self.assertEqual(response.body, b"bar") - - response = self.fetch("/get", headers={"Cookie": 'foo="bar"'}) - self.assertEqual(response.body, b"bar") - - response = self.fetch("/get", headers={"Cookie": "/=exception;"}) - self.assertEqual(response.body, b"default") - - def test_set_cookie_domain(self): - response = self.fetch("/set_domain") - self.assertEqual( - response.headers.get_list("Set-Cookie"), - ["unicode_args=blah; Domain=foo.com; Path=/foo"], - ) - - def test_cookie_special_char(self): - response = self.fetch("/special_char") - headers = sorted(response.headers.get_list("Set-Cookie")) - self.assertEqual(len(headers), 3) - self.assertEqual(headers[0], 'equals="a=b"; Path=/') - self.assertEqual(headers[1], 'quote="a\\"b"; Path=/') - # python 2.7 octal-escapes the semicolon; older versions leave it alone - self.assertTrue( - headers[2] in ('semicolon="a;b"; Path=/', 'semicolon="a\\073b"; Path=/'), - headers[2], - ) - - data = [ - ("foo=a=b", "a=b"), - ('foo="a=b"', "a=b"), - ('foo="a;b"', '"a'), # even quoted, ";" is a delimiter - ("foo=a\\073b", "a\\073b"), # escapes only decoded in quotes - ('foo="a\\073b"', "a;b"), - ('foo="a\\"b"', 'a"b'), - ] - for header, expected in data: - logging.debug("trying %r", header) - response = self.fetch("/get", headers={"Cookie": header}) - self.assertEqual(response.body, utf8(expected)) - - def test_set_cookie_overwrite(self): - response = self.fetch("/set_overwrite") - headers = response.headers.get_list("Set-Cookie") - self.assertEqual( - sorted(headers), ["a=e; Path=/", "c=d; Domain=example.com; Path=/"] - ) - - def test_set_cookie_max_age(self): - response = self.fetch("/set_max_age") - headers = response.headers.get_list("Set-Cookie") - self.assertEqual(sorted(headers), ["foo=bar; Max-Age=10; Path=/"]) - - def test_set_cookie_expires_days(self): - response = self.fetch("/set_expires_days") - header = response.headers.get("Set-Cookie") - assert header is not None - match = re.match("foo=bar; expires=(?P<expires>.+); Path=/", header) - assert match is not None - - expires = datetime.datetime.utcnow() + datetime.timedelta(days=10) - parsed = email.utils.parsedate(match.groupdict()["expires"]) - assert parsed is not None - header_expires = datetime.datetime(*parsed[:6]) - self.assertTrue(abs((expires - header_expires).total_seconds()) < 10) - - def test_set_cookie_false_flags(self): - response = self.fetch("/set_falsy_flags") - headers = sorted(response.headers.get_list("Set-Cookie")) - # The secure and httponly headers are capitalized in py35 and - # lowercase in older versions. - self.assertEqual(headers[0].lower(), "a=1; path=/; secure") - self.assertEqual(headers[1].lower(), "b=1; path=/") - self.assertEqual(headers[2].lower(), "c=1; httponly; path=/") - self.assertEqual(headers[3].lower(), "d=1; path=/") - - -class AuthRedirectRequestHandler(RequestHandler): - def initialize(self, login_url): - self.login_url = login_url - - def get_login_url(self): - return self.login_url - - @authenticated - def get(self): - # we'll never actually get here because the test doesn't follow redirects - self.send_error(500) - - -class AuthRedirectTest(WebTestCase): - def get_handlers(self): - return [ - ("/relative", AuthRedirectRequestHandler, dict(login_url="/login")), - ( - "/absolute", - AuthRedirectRequestHandler, - dict(login_url="http://example.com/login"), - ), - ] - - def test_relative_auth_redirect(self): - response = self.fetch(self.get_url("/relative"), follow_redirects=False) - self.assertEqual(response.code, 302) - self.assertEqual(response.headers["Location"], "/login?next=%2Frelative") - - def test_absolute_auth_redirect(self): - response = self.fetch(self.get_url("/absolute"), follow_redirects=False) - self.assertEqual(response.code, 302) - self.assertTrue( - re.match( - r"http://example.com/login\?next=http%3A%2F%2F127.0.0.1%3A[0-9]+%2Fabsolute", - response.headers["Location"], - ), - response.headers["Location"], - ) - - -class ConnectionCloseHandler(RequestHandler): - def initialize(self, test): - self.test = test - - @gen.coroutine - def get(self): - self.test.on_handler_waiting() - yield self.test.cleanup_event.wait() - - def on_connection_close(self): - self.test.on_connection_close() - - -class ConnectionCloseTest(WebTestCase): - def get_handlers(self): - self.cleanup_event = Event() - return [("/", ConnectionCloseHandler, dict(test=self))] - - def test_connection_close(self): - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) - s.connect(("127.0.0.1", self.get_http_port())) - self.stream = IOStream(s) - self.stream.write(b"GET / HTTP/1.0\r\n\r\n") - self.wait() - # Let the hanging coroutine clean up after itself - self.cleanup_event.set() - self.io_loop.run_sync(lambda: gen.sleep(0)) - - def on_handler_waiting(self): - logging.debug("handler waiting") - self.stream.close() - - def on_connection_close(self): - logging.debug("connection closed") - self.stop() - - -class EchoHandler(RequestHandler): - def get(self, *path_args): - # Type checks: web.py interfaces convert argument values to - # unicode strings (by default, but see also decode_argument). - # In httpserver.py (i.e. self.request.arguments), they're left - # as bytes. Keys are always native strings. - for key in self.request.arguments: - if type(key) != str: - raise Exception("incorrect type for key: %r" % type(key)) - for bvalue in self.request.arguments[key]: - if type(bvalue) != bytes: - raise Exception("incorrect type for value: %r" % type(bvalue)) - for svalue in self.get_arguments(key): - if type(svalue) != unicode_type: - raise Exception("incorrect type for value: %r" % type(svalue)) - for arg in path_args: - if type(arg) != unicode_type: - raise Exception("incorrect type for path arg: %r" % type(arg)) - self.write( - dict( - path=self.request.path, - path_args=path_args, - args=recursive_unicode(self.request.arguments), - ) - ) - - -class RequestEncodingTest(WebTestCase): - def get_handlers(self): - return [("/group/(.*)", EchoHandler), ("/slashes/([^/]*)/([^/]*)", EchoHandler)] - - def fetch_json(self, path): - return json_decode(self.fetch(path).body) - - def test_group_question_mark(self): - # Ensure that url-encoded question marks are handled properly - self.assertEqual( - self.fetch_json("/group/%3F"), - dict(path="/group/%3F", path_args=["?"], args={}), - ) - self.assertEqual( - self.fetch_json("/group/%3F?%3F=%3F"), - dict(path="/group/%3F", path_args=["?"], args={"?": ["?"]}), - ) - - def test_group_encoding(self): - # Path components and query arguments should be decoded the same way - self.assertEqual( - self.fetch_json("/group/%C3%A9?arg=%C3%A9"), - { - u"path": u"/group/%C3%A9", - u"path_args": [u"\u00e9"], - u"args": {u"arg": [u"\u00e9"]}, - }, - ) - - def test_slashes(self): - # Slashes may be escaped to appear as a single "directory" in the path, - # but they are then unescaped when passed to the get() method. - self.assertEqual( - self.fetch_json("/slashes/foo/bar"), - dict(path="/slashes/foo/bar", path_args=["foo", "bar"], args={}), - ) - self.assertEqual( - self.fetch_json("/slashes/a%2Fb/c%2Fd"), - dict(path="/slashes/a%2Fb/c%2Fd", path_args=["a/b", "c/d"], args={}), - ) - - def test_error(self): - # Percent signs (encoded as %25) should not mess up printf-style - # messages in logs - with ExpectLog(gen_log, ".*Invalid unicode"): - self.fetch("/group/?arg=%25%e9") - - -class TypeCheckHandler(RequestHandler): - def prepare(self): - self.errors = {} # type: typing.Dict[str, str] - - self.check_type("status", self.get_status(), int) - - # get_argument is an exception from the general rule of using - # type str for non-body data mainly for historical reasons. - self.check_type("argument", self.get_argument("foo"), unicode_type) - self.check_type("cookie_key", list(self.cookies.keys())[0], str) - self.check_type("cookie_value", list(self.cookies.values())[0].value, str) - - # Secure cookies return bytes because they can contain arbitrary - # data, but regular cookies are native strings. - if list(self.cookies.keys()) != ["asdf"]: - raise Exception( - "unexpected values for cookie keys: %r" % self.cookies.keys() - ) - self.check_type("get_secure_cookie", self.get_secure_cookie("asdf"), bytes) - self.check_type("get_cookie", self.get_cookie("asdf"), str) - - self.check_type("xsrf_token", self.xsrf_token, bytes) - self.check_type("xsrf_form_html", self.xsrf_form_html(), str) - - self.check_type("reverse_url", self.reverse_url("typecheck", "foo"), str) - - self.check_type("request_summary", self._request_summary(), str) - - def get(self, path_component): - # path_component uses type unicode instead of str for consistency - # with get_argument() - self.check_type("path_component", path_component, unicode_type) - self.write(self.errors) - - def post(self, path_component): - self.check_type("path_component", path_component, unicode_type) - self.write(self.errors) - - def check_type(self, name, obj, expected_type): - actual_type = type(obj) - if expected_type != actual_type: - self.errors[name] = "expected %s, got %s" % (expected_type, actual_type) - - -class DecodeArgHandler(RequestHandler): - def decode_argument(self, value, name=None): - if type(value) != bytes: - raise Exception("unexpected type for value: %r" % type(value)) - # use self.request.arguments directly to avoid recursion - if "encoding" in self.request.arguments: - return value.decode(to_unicode(self.request.arguments["encoding"][0])) - else: - return value - - def get(self, arg): - def describe(s): - if type(s) == bytes: - return ["bytes", native_str(binascii.b2a_hex(s))] - elif type(s) == unicode_type: - return ["unicode", s] - raise Exception("unknown type") - - self.write({"path": describe(arg), "query": describe(self.get_argument("foo"))}) - - -class LinkifyHandler(RequestHandler): - def get(self): - self.render("linkify.html", message="http://example.com") - - -class UIModuleResourceHandler(RequestHandler): - def get(self): - self.render("page.html", entries=[1, 2]) - - -class OptionalPathHandler(RequestHandler): - def get(self, path): - self.write({"path": path}) - - -class MultiHeaderHandler(RequestHandler): - def get(self): - self.set_header("x-overwrite", "1") - self.set_header("X-Overwrite", 2) - self.add_header("x-multi", 3) - self.add_header("X-Multi", "4") - - -class RedirectHandler(RequestHandler): - def get(self): - if self.get_argument("permanent", None) is not None: - self.redirect("/", permanent=bool(int(self.get_argument("permanent")))) - elif self.get_argument("status", None) is not None: - self.redirect("/", status=int(self.get_argument("status"))) - else: - raise Exception("didn't get permanent or status arguments") - - -class EmptyFlushCallbackHandler(RequestHandler): - @gen.coroutine - def get(self): - # Ensure that the flush callback is run whether or not there - # was any output. The gen.Task and direct yield forms are - # equivalent. - yield self.flush() # "empty" flush, but writes headers - yield self.flush() # empty flush - self.write("o") - yield self.flush() # flushes the "o" - yield self.flush() # empty flush - self.finish("k") - - -class HeaderInjectionHandler(RequestHandler): - def get(self): - try: - self.set_header("X-Foo", "foo\r\nX-Bar: baz") - raise Exception("Didn't get expected exception") - except ValueError as e: - if "Unsafe header value" in str(e): - self.finish(b"ok") - else: - raise - - -class GetArgumentHandler(RequestHandler): - def prepare(self): - if self.get_argument("source", None) == "query": - method = self.get_query_argument - elif self.get_argument("source", None) == "body": - method = self.get_body_argument - else: - method = self.get_argument # type: ignore - self.finish(method("foo", "default")) - - -class GetArgumentsHandler(RequestHandler): - def prepare(self): - self.finish( - dict( - default=self.get_arguments("foo"), - query=self.get_query_arguments("foo"), - body=self.get_body_arguments("foo"), - ) - ) - - -# This test was shared with wsgi_test.py; now the name is meaningless. -class WSGISafeWebTest(WebTestCase): - COOKIE_SECRET = "WebTest.COOKIE_SECRET" - - def get_app_kwargs(self): - loader = DictLoader( - { - "linkify.html": "{% module linkify(message) %}", - "page.html": """\ -<html><head></head><body> -{% for e in entries %} -{% module Template("entry.html", entry=e) %} -{% end %} -</body></html>""", - "entry.html": """\ -{{ set_resources(embedded_css=".entry { margin-bottom: 1em; }", - embedded_javascript="js_embed()", - css_files=["/base.css", "/foo.css"], - javascript_files="/common.js", - html_head="<meta>", - html_body='<script src="/analytics.js"/>') }} -<div class="entry">...</div>""", - } - ) - return dict( - template_loader=loader, - autoescape="xhtml_escape", - cookie_secret=self.COOKIE_SECRET, - ) - - def tearDown(self): - super().tearDown() - RequestHandler._template_loaders.clear() - - def get_handlers(self): - urls = [ - url("/typecheck/(.*)", TypeCheckHandler, name="typecheck"), - url("/decode_arg/(.*)", DecodeArgHandler, name="decode_arg"), - url("/decode_arg_kw/(?P<arg>.*)", DecodeArgHandler), - url("/linkify", LinkifyHandler), - url("/uimodule_resources", UIModuleResourceHandler), - url("/optional_path/(.+)?", OptionalPathHandler), - url("/multi_header", MultiHeaderHandler), - url("/redirect", RedirectHandler), - url( - "/web_redirect_permanent", - WebRedirectHandler, - {"url": "/web_redirect_newpath"}, - ), - url( - "/web_redirect", - WebRedirectHandler, - {"url": "/web_redirect_newpath", "permanent": False}, - ), - url( - "//web_redirect_double_slash", - WebRedirectHandler, - {"url": "/web_redirect_newpath"}, - ), - url("/header_injection", HeaderInjectionHandler), - url("/get_argument", GetArgumentHandler), - url("/get_arguments", GetArgumentsHandler), - ] - return urls - - def fetch_json(self, *args, **kwargs): - response = self.fetch(*args, **kwargs) - response.rethrow() - return json_decode(response.body) - - def test_types(self): - cookie_value = to_unicode( - create_signed_value(self.COOKIE_SECRET, "asdf", "qwer") - ) - response = self.fetch( - "/typecheck/asdf?foo=bar", headers={"Cookie": "asdf=" + cookie_value} - ) - data = json_decode(response.body) - self.assertEqual(data, {}) - - response = self.fetch( - "/typecheck/asdf?foo=bar", - method="POST", - headers={"Cookie": "asdf=" + cookie_value}, - body="foo=bar", - ) - - def test_decode_argument(self): - # These urls all decode to the same thing - urls = [ - "/decode_arg/%C3%A9?foo=%C3%A9&encoding=utf-8", - "/decode_arg/%E9?foo=%E9&encoding=latin1", - "/decode_arg_kw/%E9?foo=%E9&encoding=latin1", - ] - for req_url in urls: - response = self.fetch(req_url) - response.rethrow() - data = json_decode(response.body) - self.assertEqual( - data, - {u"path": [u"unicode", u"\u00e9"], u"query": [u"unicode", u"\u00e9"]}, - ) - - response = self.fetch("/decode_arg/%C3%A9?foo=%C3%A9") - response.rethrow() - data = json_decode(response.body) - self.assertEqual( - data, {u"path": [u"bytes", u"c3a9"], u"query": [u"bytes", u"c3a9"]} - ) - - def test_decode_argument_invalid_unicode(self): - # test that invalid unicode in URLs causes 400, not 500 - with ExpectLog(gen_log, ".*Invalid unicode.*"): - response = self.fetch("/typecheck/invalid%FF") - self.assertEqual(response.code, 400) - response = self.fetch("/typecheck/invalid?foo=%FF") - self.assertEqual(response.code, 400) - - def test_decode_argument_plus(self): - # These urls are all equivalent. - urls = [ - "/decode_arg/1%20%2B%201?foo=1%20%2B%201&encoding=utf-8", - "/decode_arg/1%20+%201?foo=1+%2B+1&encoding=utf-8", - ] - for req_url in urls: - response = self.fetch(req_url) - response.rethrow() - data = json_decode(response.body) - self.assertEqual( - data, - {u"path": [u"unicode", u"1 + 1"], u"query": [u"unicode", u"1 + 1"]}, - ) - - def test_reverse_url(self): - self.assertEqual(self.app.reverse_url("decode_arg", "foo"), "/decode_arg/foo") - self.assertEqual(self.app.reverse_url("decode_arg", 42), "/decode_arg/42") - self.assertEqual(self.app.reverse_url("decode_arg", b"\xe9"), "/decode_arg/%E9") - self.assertEqual( - self.app.reverse_url("decode_arg", u"\u00e9"), "/decode_arg/%C3%A9" - ) - self.assertEqual( - self.app.reverse_url("decode_arg", "1 + 1"), "/decode_arg/1%20%2B%201" - ) - - def test_uimodule_unescaped(self): - response = self.fetch("/linkify") - self.assertEqual( - response.body, b'<a href="http://example.com">http://example.com</a>' - ) - - def test_uimodule_resources(self): - response = self.fetch("/uimodule_resources") - self.assertEqual( - response.body, - b"""\ -<html><head><link href="/base.css" type="text/css" rel="stylesheet"/><link href="/foo.css" type="text/css" rel="stylesheet"/> -<style type="text/css"> -.entry { margin-bottom: 1em; } -</style> -<meta> -</head><body> - - -<div class="entry">...</div> - - -<div class="entry">...</div> - -<script src="/common.js" type="text/javascript"></script> -<script type="text/javascript"> -//<![CDATA[ -js_embed() -//]]> -</script> -<script src="/analytics.js"/> -</body></html>""", # noqa: E501 - ) - - def test_optional_path(self): - self.assertEqual(self.fetch_json("/optional_path/foo"), {u"path": u"foo"}) - self.assertEqual(self.fetch_json("/optional_path/"), {u"path": None}) - - def test_multi_header(self): - response = self.fetch("/multi_header") - self.assertEqual(response.headers["x-overwrite"], "2") - self.assertEqual(response.headers.get_list("x-multi"), ["3", "4"]) - - def test_redirect(self): - response = self.fetch("/redirect?permanent=1", follow_redirects=False) - self.assertEqual(response.code, 301) - response = self.fetch("/redirect?permanent=0", follow_redirects=False) - self.assertEqual(response.code, 302) - response = self.fetch("/redirect?status=307", follow_redirects=False) - self.assertEqual(response.code, 307) - - def test_web_redirect(self): - response = self.fetch("/web_redirect_permanent", follow_redirects=False) - self.assertEqual(response.code, 301) - self.assertEqual(response.headers["Location"], "/web_redirect_newpath") - response = self.fetch("/web_redirect", follow_redirects=False) - self.assertEqual(response.code, 302) - self.assertEqual(response.headers["Location"], "/web_redirect_newpath") - - def test_web_redirect_double_slash(self): - response = self.fetch("//web_redirect_double_slash", follow_redirects=False) - self.assertEqual(response.code, 301) - self.assertEqual(response.headers["Location"], "/web_redirect_newpath") - - def test_header_injection(self): - response = self.fetch("/header_injection") - self.assertEqual(response.body, b"ok") - - def test_get_argument(self): - response = self.fetch("/get_argument?foo=bar") - self.assertEqual(response.body, b"bar") - response = self.fetch("/get_argument?foo=") - self.assertEqual(response.body, b"") - response = self.fetch("/get_argument") - self.assertEqual(response.body, b"default") - - # Test merging of query and body arguments. - # In singular form, body arguments take precedence over query arguments. - body = urllib.parse.urlencode(dict(foo="hello")) - response = self.fetch("/get_argument?foo=bar", method="POST", body=body) - self.assertEqual(response.body, b"hello") - # In plural methods they are merged. - response = self.fetch("/get_arguments?foo=bar", method="POST", body=body) - self.assertEqual( - json_decode(response.body), - dict(default=["bar", "hello"], query=["bar"], body=["hello"]), - ) - - def test_get_query_arguments(self): - # send as a post so we can ensure the separation between query - # string and body arguments. - body = urllib.parse.urlencode(dict(foo="hello")) - response = self.fetch( - "/get_argument?source=query&foo=bar", method="POST", body=body - ) - self.assertEqual(response.body, b"bar") - response = self.fetch( - "/get_argument?source=query&foo=", method="POST", body=body - ) - self.assertEqual(response.body, b"") - response = self.fetch("/get_argument?source=query", method="POST", body=body) - self.assertEqual(response.body, b"default") - - def test_get_body_arguments(self): - body = urllib.parse.urlencode(dict(foo="bar")) - response = self.fetch( - "/get_argument?source=body&foo=hello", method="POST", body=body - ) - self.assertEqual(response.body, b"bar") - - body = urllib.parse.urlencode(dict(foo="")) - response = self.fetch( - "/get_argument?source=body&foo=hello", method="POST", body=body - ) - self.assertEqual(response.body, b"") - - body = urllib.parse.urlencode(dict()) - response = self.fetch( - "/get_argument?source=body&foo=hello", method="POST", body=body - ) - self.assertEqual(response.body, b"default") - - def test_no_gzip(self): - response = self.fetch("/get_argument") - self.assertNotIn("Accept-Encoding", response.headers.get("Vary", "")) - self.assertNotIn("gzip", response.headers.get("Content-Encoding", "")) - - -class NonWSGIWebTests(WebTestCase): - def get_handlers(self): - return [("/empty_flush", EmptyFlushCallbackHandler)] - - def test_empty_flush(self): - response = self.fetch("/empty_flush") - self.assertEqual(response.body, b"ok") - - -class ErrorResponseTest(WebTestCase): - def get_handlers(self): - class DefaultHandler(RequestHandler): - def get(self): - if self.get_argument("status", None): - raise HTTPError(int(self.get_argument("status"))) - 1 / 0 - - class WriteErrorHandler(RequestHandler): - def get(self): - if self.get_argument("status", None): - self.send_error(int(self.get_argument("status"))) - else: - 1 / 0 - - def write_error(self, status_code, **kwargs): - self.set_header("Content-Type", "text/plain") - if "exc_info" in kwargs: - self.write("Exception: %s" % kwargs["exc_info"][0].__name__) - else: - self.write("Status: %d" % status_code) - - class FailedWriteErrorHandler(RequestHandler): - def get(self): - 1 / 0 - - def write_error(self, status_code, **kwargs): - raise Exception("exception in write_error") - - return [ - url("/default", DefaultHandler), - url("/write_error", WriteErrorHandler), - url("/failed_write_error", FailedWriteErrorHandler), - ] - - def test_default(self): - with ExpectLog(app_log, "Uncaught exception"): - response = self.fetch("/default") - self.assertEqual(response.code, 500) - self.assertTrue(b"500: Internal Server Error" in response.body) - - response = self.fetch("/default?status=503") - self.assertEqual(response.code, 503) - self.assertTrue(b"503: Service Unavailable" in response.body) - - response = self.fetch("/default?status=435") - self.assertEqual(response.code, 435) - self.assertTrue(b"435: Unknown" in response.body) - - def test_write_error(self): - with ExpectLog(app_log, "Uncaught exception"): - response = self.fetch("/write_error") - self.assertEqual(response.code, 500) - self.assertEqual(b"Exception: ZeroDivisionError", response.body) - - response = self.fetch("/write_error?status=503") - self.assertEqual(response.code, 503) - self.assertEqual(b"Status: 503", response.body) - - def test_failed_write_error(self): - with ExpectLog(app_log, "Uncaught exception"): - response = self.fetch("/failed_write_error") - self.assertEqual(response.code, 500) - self.assertEqual(b"", response.body) - - -class StaticFileTest(WebTestCase): - # The expected SHA-512 hash of robots.txt, used in tests that call - # StaticFileHandler.get_version - robots_txt_hash = ( - b"63a36e950e134b5217e33c763e88840c10a07d80e6057d92b9ac97508de7fb1f" - b"a6f0e9b7531e169657165ea764e8963399cb6d921ffe6078425aaafe54c04563" - ) - static_dir = os.path.join(os.path.dirname(__file__), "static") - - def get_handlers(self): - class StaticUrlHandler(RequestHandler): - def get(self, path): - with_v = int(self.get_argument("include_version", "1")) - self.write(self.static_url(path, include_version=with_v)) - - class AbsoluteStaticUrlHandler(StaticUrlHandler): - include_host = True - - class OverrideStaticUrlHandler(RequestHandler): - def get(self, path): - do_include = bool(self.get_argument("include_host")) - self.include_host = not do_include - - regular_url = self.static_url(path) - override_url = self.static_url(path, include_host=do_include) - if override_url == regular_url: - return self.write(str(False)) - - protocol = self.request.protocol + "://" - protocol_length = len(protocol) - check_regular = regular_url.find(protocol, 0, protocol_length) - check_override = override_url.find(protocol, 0, protocol_length) - - if do_include: - result = check_override == 0 and check_regular == -1 - else: - result = check_override == -1 and check_regular == 0 - self.write(str(result)) - - return [ - ("/static_url/(.*)", StaticUrlHandler), - ("/abs_static_url/(.*)", AbsoluteStaticUrlHandler), - ("/override_static_url/(.*)", OverrideStaticUrlHandler), - ("/root_static/(.*)", StaticFileHandler, dict(path="/")), - ] - - def get_app_kwargs(self): - return dict(static_path=relpath("static")) - - def test_static_files(self): - response = self.fetch("/robots.txt") - self.assertTrue(b"Disallow: /" in response.body) - - response = self.fetch("/static/robots.txt") - self.assertTrue(b"Disallow: /" in response.body) - self.assertEqual(response.headers.get("Content-Type"), "text/plain") - - def test_static_compressed_files(self): - response = self.fetch("/static/sample.xml.gz") - self.assertEqual(response.headers.get("Content-Type"), "application/gzip") - response = self.fetch("/static/sample.xml.bz2") - self.assertEqual( - response.headers.get("Content-Type"), "application/octet-stream" - ) - # make sure the uncompressed file still has the correct type - response = self.fetch("/static/sample.xml") - self.assertTrue( - response.headers.get("Content-Type") in set(("text/xml", "application/xml")) - ) - - def test_static_url(self): - response = self.fetch("/static_url/robots.txt") - self.assertEqual(response.body, b"/static/robots.txt?v=" + self.robots_txt_hash) - - def test_absolute_static_url(self): - response = self.fetch("/abs_static_url/robots.txt") - self.assertEqual( - response.body, - (utf8(self.get_url("/")) + b"static/robots.txt?v=" + self.robots_txt_hash), - ) - - def test_relative_version_exclusion(self): - response = self.fetch("/static_url/robots.txt?include_version=0") - self.assertEqual(response.body, b"/static/robots.txt") - - def test_absolute_version_exclusion(self): - response = self.fetch("/abs_static_url/robots.txt?include_version=0") - self.assertEqual(response.body, utf8(self.get_url("/") + "static/robots.txt")) - - def test_include_host_override(self): - self._trigger_include_host_check(False) - self._trigger_include_host_check(True) - - def _trigger_include_host_check(self, include_host): - path = "/override_static_url/robots.txt?include_host=%s" - response = self.fetch(path % int(include_host)) - self.assertEqual(response.body, utf8(str(True))) - - def get_and_head(self, *args, **kwargs): - """Performs a GET and HEAD request and returns the GET response. - - Fails if any ``Content-*`` headers returned by the two requests - differ. - """ - head_response = self.fetch(*args, method="HEAD", **kwargs) - get_response = self.fetch(*args, method="GET", **kwargs) - content_headers = set() - for h in itertools.chain(head_response.headers, get_response.headers): - if h.startswith("Content-"): - content_headers.add(h) - for h in content_headers: - self.assertEqual( - head_response.headers.get(h), - get_response.headers.get(h), - "%s differs between GET (%s) and HEAD (%s)" - % (h, head_response.headers.get(h), get_response.headers.get(h)), - ) - return get_response - - def test_static_304_if_modified_since(self): - response1 = self.get_and_head("/static/robots.txt") - response2 = self.get_and_head( - "/static/robots.txt", - headers={"If-Modified-Since": response1.headers["Last-Modified"]}, - ) - self.assertEqual(response2.code, 304) - self.assertTrue("Content-Length" not in response2.headers) - - def test_static_304_if_none_match(self): - response1 = self.get_and_head("/static/robots.txt") - response2 = self.get_and_head( - "/static/robots.txt", headers={"If-None-Match": response1.headers["Etag"]} - ) - self.assertEqual(response2.code, 304) - - def test_static_304_etag_modified_bug(self): - response1 = self.get_and_head("/static/robots.txt") - response2 = self.get_and_head( - "/static/robots.txt", - headers={ - "If-None-Match": '"MISMATCH"', - "If-Modified-Since": response1.headers["Last-Modified"], - }, - ) - self.assertEqual(response2.code, 200) - - def test_static_if_modified_since_pre_epoch(self): - # On windows, the functions that work with time_t do not accept - # negative values, and at least one client (processing.js) seems - # to use if-modified-since 1/1/1960 as a cache-busting technique. - response = self.get_and_head( - "/static/robots.txt", - headers={"If-Modified-Since": "Fri, 01 Jan 1960 00:00:00 GMT"}, - ) - self.assertEqual(response.code, 200) - - def test_static_if_modified_since_time_zone(self): - # Instead of the value from Last-Modified, make requests with times - # chosen just before and after the known modification time - # of the file to ensure that the right time zone is being used - # when parsing If-Modified-Since. - stat = os.stat(relpath("static/robots.txt")) - - response = self.get_and_head( - "/static/robots.txt", - headers={"If-Modified-Since": format_timestamp(stat.st_mtime - 1)}, - ) - self.assertEqual(response.code, 200) - response = self.get_and_head( - "/static/robots.txt", - headers={"If-Modified-Since": format_timestamp(stat.st_mtime + 1)}, - ) - self.assertEqual(response.code, 304) - - def test_static_etag(self): - response = self.get_and_head("/static/robots.txt") - self.assertEqual( - utf8(response.headers.get("Etag")), b'"' + self.robots_txt_hash + b'"' - ) - - def test_static_with_range(self): - response = self.get_and_head( - "/static/robots.txt", headers={"Range": "bytes=0-9"} - ) - self.assertEqual(response.code, 206) - self.assertEqual(response.body, b"User-agent") - self.assertEqual( - utf8(response.headers.get("Etag")), b'"' + self.robots_txt_hash + b'"' - ) - self.assertEqual(response.headers.get("Content-Length"), "10") - self.assertEqual(response.headers.get("Content-Range"), "bytes 0-9/26") - - def test_static_with_range_full_file(self): - response = self.get_and_head( - "/static/robots.txt", headers={"Range": "bytes=0-"} - ) - # Note: Chrome refuses to play audio if it gets an HTTP 206 in response - # to ``Range: bytes=0-`` :( - self.assertEqual(response.code, 200) - robots_file_path = os.path.join(self.static_dir, "robots.txt") - with open(robots_file_path) as f: - self.assertEqual(response.body, utf8(f.read())) - self.assertEqual(response.headers.get("Content-Length"), "26") - self.assertEqual(response.headers.get("Content-Range"), None) - - def test_static_with_range_full_past_end(self): - response = self.get_and_head( - "/static/robots.txt", headers={"Range": "bytes=0-10000000"} - ) - self.assertEqual(response.code, 200) - robots_file_path = os.path.join(self.static_dir, "robots.txt") - with open(robots_file_path) as f: - self.assertEqual(response.body, utf8(f.read())) - self.assertEqual(response.headers.get("Content-Length"), "26") - self.assertEqual(response.headers.get("Content-Range"), None) - - def test_static_with_range_partial_past_end(self): - response = self.get_and_head( - "/static/robots.txt", headers={"Range": "bytes=1-10000000"} - ) - self.assertEqual(response.code, 206) - robots_file_path = os.path.join(self.static_dir, "robots.txt") - with open(robots_file_path) as f: - self.assertEqual(response.body, utf8(f.read()[1:])) - self.assertEqual(response.headers.get("Content-Length"), "25") - self.assertEqual(response.headers.get("Content-Range"), "bytes 1-25/26") - - def test_static_with_range_end_edge(self): - response = self.get_and_head( - "/static/robots.txt", headers={"Range": "bytes=22-"} - ) - self.assertEqual(response.body, b": /\n") - self.assertEqual(response.headers.get("Content-Length"), "4") - self.assertEqual(response.headers.get("Content-Range"), "bytes 22-25/26") - - def test_static_with_range_neg_end(self): - response = self.get_and_head( - "/static/robots.txt", headers={"Range": "bytes=-4"} - ) - self.assertEqual(response.body, b": /\n") - self.assertEqual(response.headers.get("Content-Length"), "4") - self.assertEqual(response.headers.get("Content-Range"), "bytes 22-25/26") - - def test_static_with_range_neg_past_start(self): - response = self.get_and_head( - "/static/robots.txt", headers={"Range": "bytes=-1000000"} - ) - self.assertEqual(response.code, 200) - robots_file_path = os.path.join(self.static_dir, "robots.txt") - with open(robots_file_path) as f: - self.assertEqual(response.body, utf8(f.read())) - self.assertEqual(response.headers.get("Content-Length"), "26") - self.assertEqual(response.headers.get("Content-Range"), None) - - def test_static_invalid_range(self): - response = self.get_and_head("/static/robots.txt", headers={"Range": "asdf"}) - self.assertEqual(response.code, 200) - - def test_static_unsatisfiable_range_zero_suffix(self): - response = self.get_and_head( - "/static/robots.txt", headers={"Range": "bytes=-0"} - ) - self.assertEqual(response.headers.get("Content-Range"), "bytes */26") - self.assertEqual(response.code, 416) - - def test_static_unsatisfiable_range_invalid_start(self): - response = self.get_and_head( - "/static/robots.txt", headers={"Range": "bytes=26"} - ) - self.assertEqual(response.code, 416) - self.assertEqual(response.headers.get("Content-Range"), "bytes */26") - - def test_static_unsatisfiable_range_end_less_than_start(self): - response = self.get_and_head( - "/static/robots.txt", headers={"Range": "bytes=10-3"} - ) - self.assertEqual(response.code, 416) - self.assertEqual(response.headers.get("Content-Range"), "bytes */26") - - def test_static_head(self): - response = self.fetch("/static/robots.txt", method="HEAD") - self.assertEqual(response.code, 200) - # No body was returned, but we did get the right content length. - self.assertEqual(response.body, b"") - self.assertEqual(response.headers["Content-Length"], "26") - self.assertEqual( - utf8(response.headers["Etag"]), b'"' + self.robots_txt_hash + b'"' - ) - - def test_static_head_range(self): - response = self.fetch( - "/static/robots.txt", method="HEAD", headers={"Range": "bytes=1-4"} - ) - self.assertEqual(response.code, 206) - self.assertEqual(response.body, b"") - self.assertEqual(response.headers["Content-Length"], "4") - self.assertEqual( - utf8(response.headers["Etag"]), b'"' + self.robots_txt_hash + b'"' - ) - - def test_static_range_if_none_match(self): - response = self.get_and_head( - "/static/robots.txt", - headers={ - "Range": "bytes=1-4", - "If-None-Match": b'"' + self.robots_txt_hash + b'"', - }, - ) - self.assertEqual(response.code, 304) - self.assertEqual(response.body, b"") - self.assertTrue("Content-Length" not in response.headers) - self.assertEqual( - utf8(response.headers["Etag"]), b'"' + self.robots_txt_hash + b'"' - ) - - def test_static_404(self): - response = self.get_and_head("/static/blarg") - self.assertEqual(response.code, 404) - - def test_path_traversal_protection(self): - # curl_httpclient processes ".." on the client side, so we - # must test this with simple_httpclient. - self.http_client.close() - self.http_client = SimpleAsyncHTTPClient() - with ExpectLog(gen_log, ".*not in root static directory"): - response = self.get_and_head("/static/../static_foo.txt") - # Attempted path traversal should result in 403, not 200 - # (which means the check failed and the file was served) - # or 404 (which means that the file didn't exist and - # is probably a packaging error). - self.assertEqual(response.code, 403) - - @unittest.skipIf(os.name != "posix", "non-posix OS") - def test_root_static_path(self): - # Sometimes people set the StaticFileHandler's path to '/' - # to disable Tornado's path validation (in conjunction with - # their own validation in get_absolute_path). Make sure - # that the stricter validation in 4.2.1 doesn't break them. - path = os.path.join( - os.path.dirname(os.path.abspath(__file__)), "static/robots.txt" - ) - response = self.get_and_head("/root_static" + urllib.parse.quote(path)) - self.assertEqual(response.code, 200) - - -class StaticDefaultFilenameTest(WebTestCase): - def get_app_kwargs(self): - return dict( - static_path=relpath("static"), - static_handler_args=dict(default_filename="index.html"), - ) - - def get_handlers(self): - return [] - - def test_static_default_filename(self): - response = self.fetch("/static/dir/", follow_redirects=False) - self.assertEqual(response.code, 200) - self.assertEqual(b"this is the index\n", response.body) - - def test_static_default_redirect(self): - response = self.fetch("/static/dir", follow_redirects=False) - self.assertEqual(response.code, 301) - self.assertTrue(response.headers["Location"].endswith("/static/dir/")) - - -class StaticFileWithPathTest(WebTestCase): - def get_app_kwargs(self): - return dict( - static_path=relpath("static"), - static_handler_args=dict(default_filename="index.html"), - ) - - def get_handlers(self): - return [("/foo/(.*)", StaticFileHandler, {"path": relpath("templates/")})] - - def test_serve(self): - response = self.fetch("/foo/utf8.html") - self.assertEqual(response.body, b"H\xc3\xa9llo\n") - - -class CustomStaticFileTest(WebTestCase): - def get_handlers(self): - class MyStaticFileHandler(StaticFileHandler): - @classmethod - def make_static_url(cls, settings, path): - version_hash = cls.get_version(settings, path) - extension_index = path.rindex(".") - before_version = path[:extension_index] - after_version = path[(extension_index + 1) :] - return "/static/%s.%s.%s" % ( - before_version, - version_hash, - after_version, - ) - - def parse_url_path(self, url_path): - extension_index = url_path.rindex(".") - version_index = url_path.rindex(".", 0, extension_index) - return "%s%s" % (url_path[:version_index], url_path[extension_index:]) - - @classmethod - def get_absolute_path(cls, settings, path): - return "CustomStaticFileTest:" + path - - def validate_absolute_path(self, root, absolute_path): - return absolute_path - - @classmethod - def get_content(self, path, start=None, end=None): - assert start is None and end is None - if path == "CustomStaticFileTest:foo.txt": - return b"bar" - raise Exception("unexpected path %r" % path) - - def get_content_size(self): - if self.absolute_path == "CustomStaticFileTest:foo.txt": - return 3 - raise Exception("unexpected path %r" % self.absolute_path) - - def get_modified_time(self): - return None - - @classmethod - def get_version(cls, settings, path): - return "42" - - class StaticUrlHandler(RequestHandler): - def get(self, path): - self.write(self.static_url(path)) - - self.static_handler_class = MyStaticFileHandler - - return [("/static_url/(.*)", StaticUrlHandler)] - - def get_app_kwargs(self): - return dict(static_path="dummy", static_handler_class=self.static_handler_class) - - def test_serve(self): - response = self.fetch("/static/foo.42.txt") - self.assertEqual(response.body, b"bar") - - def test_static_url(self): - with ExpectLog(gen_log, "Could not open static file", required=False): - response = self.fetch("/static_url/foo.txt") - self.assertEqual(response.body, b"/static/foo.42.txt") - - -class HostMatchingTest(WebTestCase): - class Handler(RequestHandler): - def initialize(self, reply): - self.reply = reply - - def get(self): - self.write(self.reply) - - def get_handlers(self): - return [("/foo", HostMatchingTest.Handler, {"reply": "wildcard"})] - - def test_host_matching(self): - self.app.add_handlers( - "www.example.com", [("/foo", HostMatchingTest.Handler, {"reply": "[0]"})] - ) - self.app.add_handlers( - r"www\.example\.com", [("/bar", HostMatchingTest.Handler, {"reply": "[1]"})] - ) - self.app.add_handlers( - "www.example.com", [("/baz", HostMatchingTest.Handler, {"reply": "[2]"})] - ) - self.app.add_handlers( - "www.e.*e.com", [("/baz", HostMatchingTest.Handler, {"reply": "[3]"})] - ) - - response = self.fetch("/foo") - self.assertEqual(response.body, b"wildcard") - response = self.fetch("/bar") - self.assertEqual(response.code, 404) - response = self.fetch("/baz") - self.assertEqual(response.code, 404) - - response = self.fetch("/foo", headers={"Host": "www.example.com"}) - self.assertEqual(response.body, b"[0]") - response = self.fetch("/bar", headers={"Host": "www.example.com"}) - self.assertEqual(response.body, b"[1]") - response = self.fetch("/baz", headers={"Host": "www.example.com"}) - self.assertEqual(response.body, b"[2]") - response = self.fetch("/baz", headers={"Host": "www.exe.com"}) - self.assertEqual(response.body, b"[3]") - - -class DefaultHostMatchingTest(WebTestCase): - def get_handlers(self): - return [] - - def get_app_kwargs(self): - return {"default_host": "www.example.com"} - - def test_default_host_matching(self): - self.app.add_handlers( - "www.example.com", [("/foo", HostMatchingTest.Handler, {"reply": "[0]"})] - ) - self.app.add_handlers( - r"www\.example\.com", [("/bar", HostMatchingTest.Handler, {"reply": "[1]"})] - ) - self.app.add_handlers( - "www.test.com", [("/baz", HostMatchingTest.Handler, {"reply": "[2]"})] - ) - - response = self.fetch("/foo") - self.assertEqual(response.body, b"[0]") - response = self.fetch("/bar") - self.assertEqual(response.body, b"[1]") - response = self.fetch("/baz") - self.assertEqual(response.code, 404) - - response = self.fetch("/foo", headers={"X-Real-Ip": "127.0.0.1"}) - self.assertEqual(response.code, 404) - - self.app.default_host = "www.test.com" - - response = self.fetch("/baz") - self.assertEqual(response.body, b"[2]") - - -class NamedURLSpecGroupsTest(WebTestCase): - def get_handlers(self): - class EchoHandler(RequestHandler): - def get(self, path): - self.write(path) - - return [ - ("/str/(?P<path>.*)", EchoHandler), - (u"/unicode/(?P<path>.*)", EchoHandler), - ] - - def test_named_urlspec_groups(self): - response = self.fetch("/str/foo") - self.assertEqual(response.body, b"foo") - - response = self.fetch("/unicode/bar") - self.assertEqual(response.body, b"bar") - - -class ClearHeaderTest(SimpleHandlerTestCase): - class Handler(RequestHandler): - def get(self): - self.set_header("h1", "foo") - self.set_header("h2", "bar") - self.clear_header("h1") - self.clear_header("nonexistent") - - def test_clear_header(self): - response = self.fetch("/") - self.assertTrue("h1" not in response.headers) - self.assertEqual(response.headers["h2"], "bar") - - -class Header204Test(SimpleHandlerTestCase): - class Handler(RequestHandler): - def get(self): - self.set_status(204) - self.finish() - - def test_204_headers(self): - response = self.fetch("/") - self.assertEqual(response.code, 204) - self.assertNotIn("Content-Length", response.headers) - self.assertNotIn("Transfer-Encoding", response.headers) - - -class Header304Test(SimpleHandlerTestCase): - class Handler(RequestHandler): - def get(self): - self.set_header("Content-Language", "en_US") - self.write("hello") - - def test_304_headers(self): - response1 = self.fetch("/") - self.assertEqual(response1.headers["Content-Length"], "5") - self.assertEqual(response1.headers["Content-Language"], "en_US") - - response2 = self.fetch( - "/", headers={"If-None-Match": response1.headers["Etag"]} - ) - self.assertEqual(response2.code, 304) - self.assertTrue("Content-Length" not in response2.headers) - self.assertTrue("Content-Language" not in response2.headers) - # Not an entity header, but should not be added to 304s by chunking - self.assertTrue("Transfer-Encoding" not in response2.headers) - - -class StatusReasonTest(SimpleHandlerTestCase): - class Handler(RequestHandler): - def get(self): - reason = self.request.arguments.get("reason", []) - self.set_status( - int(self.get_argument("code")), - reason=to_unicode(reason[0]) if reason else None, - ) - - def get_http_client(self): - # simple_httpclient only: curl doesn't expose the reason string - return SimpleAsyncHTTPClient() - - def test_status(self): - response = self.fetch("/?code=304") - self.assertEqual(response.code, 304) - self.assertEqual(response.reason, "Not Modified") - response = self.fetch("/?code=304&reason=Foo") - self.assertEqual(response.code, 304) - self.assertEqual(response.reason, "Foo") - response = self.fetch("/?code=682&reason=Bar") - self.assertEqual(response.code, 682) - self.assertEqual(response.reason, "Bar") - response = self.fetch("/?code=682") - self.assertEqual(response.code, 682) - self.assertEqual(response.reason, "Unknown") - - -class DateHeaderTest(SimpleHandlerTestCase): - class Handler(RequestHandler): - def get(self): - self.write("hello") - - def test_date_header(self): - response = self.fetch("/") - parsed = email.utils.parsedate(response.headers["Date"]) - assert parsed is not None - header_date = datetime.datetime(*parsed[:6]) - self.assertTrue( - header_date - datetime.datetime.utcnow() < datetime.timedelta(seconds=2) - ) - - -class RaiseWithReasonTest(SimpleHandlerTestCase): - class Handler(RequestHandler): - def get(self): - raise HTTPError(682, reason="Foo") - - def get_http_client(self): - # simple_httpclient only: curl doesn't expose the reason string - return SimpleAsyncHTTPClient() - - def test_raise_with_reason(self): - response = self.fetch("/") - self.assertEqual(response.code, 682) - self.assertEqual(response.reason, "Foo") - self.assertIn(b"682: Foo", response.body) - - def test_httperror_str(self): - self.assertEqual(str(HTTPError(682, reason="Foo")), "HTTP 682: Foo") - - def test_httperror_str_from_httputil(self): - self.assertEqual(str(HTTPError(682)), "HTTP 682: Unknown") - - -class ErrorHandlerXSRFTest(WebTestCase): - def get_handlers(self): - # note that if the handlers list is empty we get the default_host - # redirect fallback instead of a 404, so test with both an - # explicitly defined error handler and an implicit 404. - return [("/error", ErrorHandler, dict(status_code=417))] - - def get_app_kwargs(self): - return dict(xsrf_cookies=True) - - def test_error_xsrf(self): - response = self.fetch("/error", method="POST", body="") - self.assertEqual(response.code, 417) - - def test_404_xsrf(self): - response = self.fetch("/404", method="POST", body="") - self.assertEqual(response.code, 404) - - -class GzipTestCase(SimpleHandlerTestCase): - class Handler(RequestHandler): - def get(self): - for v in self.get_arguments("vary"): - self.add_header("Vary", v) - # Must write at least MIN_LENGTH bytes to activate compression. - self.write("hello world" + ("!" * GZipContentEncoding.MIN_LENGTH)) - - def get_app_kwargs(self): - return dict( - gzip=True, static_path=os.path.join(os.path.dirname(__file__), "static") - ) - - def assert_compressed(self, response): - # simple_httpclient renames the content-encoding header; - # curl_httpclient doesn't. - self.assertEqual( - response.headers.get( - "Content-Encoding", response.headers.get("X-Consumed-Content-Encoding") - ), - "gzip", - ) - - def test_gzip(self): - response = self.fetch("/") - self.assert_compressed(response) - self.assertEqual(response.headers["Vary"], "Accept-Encoding") - - def test_gzip_static(self): - # The streaming responses in StaticFileHandler have subtle - # interactions with the gzip output so test this case separately. - response = self.fetch("/robots.txt") - self.assert_compressed(response) - self.assertEqual(response.headers["Vary"], "Accept-Encoding") - - def test_gzip_not_requested(self): - response = self.fetch("/", use_gzip=False) - self.assertNotIn("Content-Encoding", response.headers) - self.assertEqual(response.headers["Vary"], "Accept-Encoding") - - def test_vary_already_present(self): - response = self.fetch("/?vary=Accept-Language") - self.assert_compressed(response) - self.assertEqual( - [s.strip() for s in response.headers["Vary"].split(",")], - ["Accept-Language", "Accept-Encoding"], - ) - - def test_vary_already_present_multiple(self): - # Regression test for https://github.com/tornadoweb/tornado/issues/1670 - response = self.fetch("/?vary=Accept-Language&vary=Cookie") - self.assert_compressed(response) - self.assertEqual( - [s.strip() for s in response.headers["Vary"].split(",")], - ["Accept-Language", "Cookie", "Accept-Encoding"], - ) - - -class PathArgsInPrepareTest(WebTestCase): - class Handler(RequestHandler): - def prepare(self): - self.write(dict(args=self.path_args, kwargs=self.path_kwargs)) - - def get(self, path): - assert path == "foo" - self.finish() - - def get_handlers(self): - return [("/pos/(.*)", self.Handler), ("/kw/(?P<path>.*)", self.Handler)] - - def test_pos(self): - response = self.fetch("/pos/foo") - response.rethrow() - data = json_decode(response.body) - self.assertEqual(data, {"args": ["foo"], "kwargs": {}}) - - def test_kw(self): - response = self.fetch("/kw/foo") - response.rethrow() - data = json_decode(response.body) - self.assertEqual(data, {"args": [], "kwargs": {"path": "foo"}}) - - -class ClearAllCookiesTest(SimpleHandlerTestCase): - class Handler(RequestHandler): - def get(self): - self.clear_all_cookies() - self.write("ok") - - def test_clear_all_cookies(self): - response = self.fetch("/", headers={"Cookie": "foo=bar; baz=xyzzy"}) - set_cookies = sorted(response.headers.get_list("Set-Cookie")) - # Python 3.5 sends 'baz="";'; older versions use 'baz=;' - self.assertTrue( - set_cookies[0].startswith("baz=;") or set_cookies[0].startswith('baz="";') - ) - self.assertTrue( - set_cookies[1].startswith("foo=;") or set_cookies[1].startswith('foo="";') - ) - - -class PermissionError(Exception): - pass - - -class ExceptionHandlerTest(SimpleHandlerTestCase): - class Handler(RequestHandler): - def get(self): - exc = self.get_argument("exc") - if exc == "http": - raise HTTPError(410, "no longer here") - elif exc == "zero": - 1 / 0 - elif exc == "permission": - raise PermissionError("not allowed") - - def write_error(self, status_code, **kwargs): - if "exc_info" in kwargs: - typ, value, tb = kwargs["exc_info"] - if isinstance(value, PermissionError): - self.set_status(403) - self.write("PermissionError") - return - RequestHandler.write_error(self, status_code, **kwargs) - - def log_exception(self, typ, value, tb): - if isinstance(value, PermissionError): - app_log.warning("custom logging for PermissionError: %s", value.args[0]) - else: - RequestHandler.log_exception(self, typ, value, tb) - - def test_http_error(self): - # HTTPErrors are logged as warnings with no stack trace. - # TODO: extend ExpectLog to test this more precisely - with ExpectLog(gen_log, ".*no longer here"): - response = self.fetch("/?exc=http") - self.assertEqual(response.code, 410) - - def test_unknown_error(self): - # Unknown errors are logged as errors with a stack trace. - with ExpectLog(app_log, "Uncaught exception"): - response = self.fetch("/?exc=zero") - self.assertEqual(response.code, 500) - - def test_known_error(self): - # log_exception can override logging behavior, and write_error - # can override the response. - with ExpectLog(app_log, "custom logging for PermissionError: not allowed"): - response = self.fetch("/?exc=permission") - self.assertEqual(response.code, 403) - - -class BuggyLoggingTest(SimpleHandlerTestCase): - class Handler(RequestHandler): - def get(self): - 1 / 0 - - def log_exception(self, typ, value, tb): - 1 / 0 - - def test_buggy_log_exception(self): - # Something gets logged even though the application's - # logger is broken. - with ExpectLog(app_log, ".*"): - self.fetch("/") - - -class UIMethodUIModuleTest(SimpleHandlerTestCase): - """Test that UI methods and modules are created correctly and - associated with the handler. - """ - - class Handler(RequestHandler): - def get(self): - self.render("foo.html") - - def value(self): - return self.get_argument("value") - - def get_app_kwargs(self): - def my_ui_method(handler, x): - return "In my_ui_method(%s) with handler value %s." % (x, handler.value()) - - class MyModule(UIModule): - def render(self, x): - return "In MyModule(%s) with handler value %s." % ( - x, - typing.cast(UIMethodUIModuleTest.Handler, self.handler).value(), - ) - - loader = DictLoader( - {"foo.html": "{{ my_ui_method(42) }} {% module MyModule(123) %}"} - ) - return dict( - template_loader=loader, - ui_methods={"my_ui_method": my_ui_method}, - ui_modules={"MyModule": MyModule}, - ) - - def tearDown(self): - super().tearDown() - # TODO: fix template loader caching so this isn't necessary. - RequestHandler._template_loaders.clear() - - def test_ui_method(self): - response = self.fetch("/?value=asdf") - self.assertEqual( - response.body, - b"In my_ui_method(42) with handler value asdf. " - b"In MyModule(123) with handler value asdf.", - ) - - -class GetArgumentErrorTest(SimpleHandlerTestCase): - class Handler(RequestHandler): - def get(self): - try: - self.get_argument("foo") - self.write({}) - except MissingArgumentError as e: - self.write({"arg_name": e.arg_name, "log_message": e.log_message}) - - def test_catch_error(self): - response = self.fetch("/") - self.assertEqual( - json_decode(response.body), - {"arg_name": "foo", "log_message": "Missing argument foo"}, - ) - - -class SetLazyPropertiesTest(SimpleHandlerTestCase): - class Handler(RequestHandler): - def prepare(self): - self.current_user = "Ben" - self.locale = locale.get("en_US") - - def get_user_locale(self): - raise NotImplementedError() - - def get_current_user(self): - raise NotImplementedError() - - def get(self): - self.write("Hello %s (%s)" % (self.current_user, self.locale.code)) - - def test_set_properties(self): - # Ensure that current_user can be assigned to normally for apps - # that want to forgo the lazy get_current_user property - response = self.fetch("/") - self.assertEqual(response.body, b"Hello Ben (en_US)") - - -class GetCurrentUserTest(WebTestCase): - def get_app_kwargs(self): - class WithoutUserModule(UIModule): - def render(self): - return "" - - class WithUserModule(UIModule): - def render(self): - return str(self.current_user) - - loader = DictLoader( - { - "without_user.html": "", - "with_user.html": "{{ current_user }}", - "without_user_module.html": "{% module WithoutUserModule() %}", - "with_user_module.html": "{% module WithUserModule() %}", - } - ) - return dict( - template_loader=loader, - ui_modules={ - "WithUserModule": WithUserModule, - "WithoutUserModule": WithoutUserModule, - }, - ) - - def tearDown(self): - super().tearDown() - RequestHandler._template_loaders.clear() - - def get_handlers(self): - class CurrentUserHandler(RequestHandler): - def prepare(self): - self.has_loaded_current_user = False - - def get_current_user(self): - self.has_loaded_current_user = True - return "" - - class WithoutUserHandler(CurrentUserHandler): - def get(self): - self.render_string("without_user.html") - self.finish(str(self.has_loaded_current_user)) - - class WithUserHandler(CurrentUserHandler): - def get(self): - self.render_string("with_user.html") - self.finish(str(self.has_loaded_current_user)) - - class CurrentUserModuleHandler(CurrentUserHandler): - def get_template_namespace(self): - # If RequestHandler.get_template_namespace is called, then - # get_current_user is evaluated. Until #820 is fixed, this - # is a small hack to circumvent the issue. - return self.ui - - class WithoutUserModuleHandler(CurrentUserModuleHandler): - def get(self): - self.render_string("without_user_module.html") - self.finish(str(self.has_loaded_current_user)) - - class WithUserModuleHandler(CurrentUserModuleHandler): - def get(self): - self.render_string("with_user_module.html") - self.finish(str(self.has_loaded_current_user)) - - return [ - ("/without_user", WithoutUserHandler), - ("/with_user", WithUserHandler), - ("/without_user_module", WithoutUserModuleHandler), - ("/with_user_module", WithUserModuleHandler), - ] - - @unittest.skip("needs fix") - def test_get_current_user_is_lazy(self): - # TODO: Make this test pass. See #820. - response = self.fetch("/without_user") - self.assertEqual(response.body, b"False") - - def test_get_current_user_works(self): - response = self.fetch("/with_user") - self.assertEqual(response.body, b"True") - - def test_get_current_user_from_ui_module_is_lazy(self): - response = self.fetch("/without_user_module") - self.assertEqual(response.body, b"False") - - def test_get_current_user_from_ui_module_works(self): - response = self.fetch("/with_user_module") - self.assertEqual(response.body, b"True") - - -class UnimplementedHTTPMethodsTest(SimpleHandlerTestCase): - class Handler(RequestHandler): - pass - - def test_unimplemented_standard_methods(self): - for method in ["HEAD", "GET", "DELETE", "OPTIONS"]: - response = self.fetch("/", method=method) - self.assertEqual(response.code, 405) - for method in ["POST", "PUT"]: - response = self.fetch("/", method=method, body=b"") - self.assertEqual(response.code, 405) - - -class UnimplementedNonStandardMethodsTest(SimpleHandlerTestCase): - class Handler(RequestHandler): - def other(self): - # Even though this method exists, it won't get called automatically - # because it is not in SUPPORTED_METHODS. - self.write("other") - - def test_unimplemented_patch(self): - # PATCH is recently standardized; Tornado supports it by default - # but wsgiref.validate doesn't like it. - response = self.fetch("/", method="PATCH", body=b"") - self.assertEqual(response.code, 405) - - def test_unimplemented_other(self): - response = self.fetch("/", method="OTHER", allow_nonstandard_methods=True) - self.assertEqual(response.code, 405) - - -class AllHTTPMethodsTest(SimpleHandlerTestCase): - class Handler(RequestHandler): - def method(self): - assert self.request.method is not None - self.write(self.request.method) - - get = delete = options = post = put = method # type: ignore - - def test_standard_methods(self): - response = self.fetch("/", method="HEAD") - self.assertEqual(response.body, b"") - for method in ["GET", "DELETE", "OPTIONS"]: - response = self.fetch("/", method=method) - self.assertEqual(response.body, utf8(method)) - for method in ["POST", "PUT"]: - response = self.fetch("/", method=method, body=b"") - self.assertEqual(response.body, utf8(method)) - - -class PatchMethodTest(SimpleHandlerTestCase): - class Handler(RequestHandler): - SUPPORTED_METHODS = RequestHandler.SUPPORTED_METHODS + ( # type: ignore - "OTHER", - ) - - def patch(self): - self.write("patch") - - def other(self): - self.write("other") - - def test_patch(self): - response = self.fetch("/", method="PATCH", body=b"") - self.assertEqual(response.body, b"patch") - - def test_other(self): - response = self.fetch("/", method="OTHER", allow_nonstandard_methods=True) - self.assertEqual(response.body, b"other") - - -class FinishInPrepareTest(SimpleHandlerTestCase): - class Handler(RequestHandler): - def prepare(self): - self.finish("done") - - def get(self): - # It's difficult to assert for certain that a method did not - # or will not be called in an asynchronous context, but this - # will be logged noisily if it is reached. - raise Exception("should not reach this method") - - def test_finish_in_prepare(self): - response = self.fetch("/") - self.assertEqual(response.body, b"done") - - -class Default404Test(WebTestCase): - def get_handlers(self): - # If there are no handlers at all a default redirect handler gets added. - return [("/foo", RequestHandler)] - - def test_404(self): - response = self.fetch("/") - self.assertEqual(response.code, 404) - self.assertEqual( - response.body, - b"<html><title>404: Not Found</title>" - b"<body>404: Not Found</body></html>", - ) - - -class Custom404Test(WebTestCase): - def get_handlers(self): - return [("/foo", RequestHandler)] - - def get_app_kwargs(self): - class Custom404Handler(RequestHandler): - def get(self): - self.set_status(404) - self.write("custom 404 response") - - return dict(default_handler_class=Custom404Handler) - - def test_404(self): - response = self.fetch("/") - self.assertEqual(response.code, 404) - self.assertEqual(response.body, b"custom 404 response") - - -class DefaultHandlerArgumentsTest(WebTestCase): - def get_handlers(self): - return [("/foo", RequestHandler)] - - def get_app_kwargs(self): - return dict( - default_handler_class=ErrorHandler, - default_handler_args=dict(status_code=403), - ) - - def test_403(self): - response = self.fetch("/") - self.assertEqual(response.code, 403) - - -class HandlerByNameTest(WebTestCase): - def get_handlers(self): - # All three are equivalent. - return [ - ("/hello1", HelloHandler), - ("/hello2", "tornado.test.web_test.HelloHandler"), - url("/hello3", "tornado.test.web_test.HelloHandler"), - ] - - def test_handler_by_name(self): - resp = self.fetch("/hello1") - self.assertEqual(resp.body, b"hello") - resp = self.fetch("/hello2") - self.assertEqual(resp.body, b"hello") - resp = self.fetch("/hello3") - self.assertEqual(resp.body, b"hello") - - -class StreamingRequestBodyTest(WebTestCase): - def get_handlers(self): - @stream_request_body - class StreamingBodyHandler(RequestHandler): - def initialize(self, test): - self.test = test - - def prepare(self): - self.test.prepared.set_result(None) - - def data_received(self, data): - self.test.data.set_result(data) - - def get(self): - self.test.finished.set_result(None) - self.write({}) - - @stream_request_body - class EarlyReturnHandler(RequestHandler): - def prepare(self): - # If we finish the response in prepare, it won't continue to - # the (non-existent) data_received. - raise HTTPError(401) - - @stream_request_body - class CloseDetectionHandler(RequestHandler): - def initialize(self, test): - self.test = test - - def on_connection_close(self): - super().on_connection_close() - self.test.close_future.set_result(None) - - return [ - ("/stream_body", StreamingBodyHandler, dict(test=self)), - ("/early_return", EarlyReturnHandler), - ("/close_detection", CloseDetectionHandler, dict(test=self)), - ] - - def connect(self, url, connection_close): - # Use a raw connection so we can control the sending of data. - s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, 0) - s.connect(("127.0.0.1", self.get_http_port())) - stream = IOStream(s) - stream.write(b"GET " + url + b" HTTP/1.1\r\n") - if connection_close: - stream.write(b"Connection: close\r\n") - stream.write(b"Transfer-Encoding: chunked\r\n\r\n") - return stream - - @gen_test - def test_streaming_body(self): - self.prepared = Future() # type: Future[None] - self.data = Future() # type: Future[bytes] - self.finished = Future() # type: Future[None] - - stream = self.connect(b"/stream_body", connection_close=True) - yield self.prepared - stream.write(b"4\r\nasdf\r\n") - # Ensure the first chunk is received before we send the second. - data = yield self.data - self.assertEqual(data, b"asdf") - self.data = Future() - stream.write(b"4\r\nqwer\r\n") - data = yield self.data - self.assertEqual(data, b"qwer") - stream.write(b"0\r\n\r\n") - yield self.finished - data = yield stream.read_until_close() - # This would ideally use an HTTP1Connection to read the response. - self.assertTrue(data.endswith(b"{}")) - stream.close() - - @gen_test - def test_early_return(self): - stream = self.connect(b"/early_return", connection_close=False) - data = yield stream.read_until_close() - self.assertTrue(data.startswith(b"HTTP/1.1 401")) - - @gen_test - def test_early_return_with_data(self): - stream = self.connect(b"/early_return", connection_close=False) - stream.write(b"4\r\nasdf\r\n") - data = yield stream.read_until_close() - self.assertTrue(data.startswith(b"HTTP/1.1 401")) - - @gen_test - def test_close_during_upload(self): - self.close_future = Future() # type: Future[None] - stream = self.connect(b"/close_detection", connection_close=False) - stream.close() - yield self.close_future - - -# Each method in this handler returns a yieldable object and yields to the -# IOLoop so the future is not immediately ready. Ensure that the -# yieldables are respected and no method is called before the previous -# one has completed. -@stream_request_body -class BaseFlowControlHandler(RequestHandler): - def initialize(self, test): - self.test = test - self.method = None - self.methods = [] # type: typing.List[str] - - @contextlib.contextmanager - def in_method(self, method): - if self.method is not None: - self.test.fail("entered method %s while in %s" % (method, self.method)) - self.method = method - self.methods.append(method) - try: - yield - finally: - self.method = None - - @gen.coroutine - def prepare(self): - # Note that asynchronous prepare() does not block data_received, - # so we don't use in_method here. - self.methods.append("prepare") - yield gen.moment - - @gen.coroutine - def post(self): - with self.in_method("post"): - yield gen.moment - self.write(dict(methods=self.methods)) - - -class BaseStreamingRequestFlowControlTest(object): - def get_httpserver_options(self): - # Use a small chunk size so flow control is relevant even though - # all the data arrives at once. - return dict(chunk_size=10, decompress_request=True) - - def get_http_client(self): - # simple_httpclient only: curl doesn't support body_producer. - return SimpleAsyncHTTPClient() - - # Test all the slightly different code paths for fixed, chunked, etc bodies. - def test_flow_control_fixed_body(self: typing.Any): - response = self.fetch("/", body="abcdefghijklmnopqrstuvwxyz", method="POST") - response.rethrow() - self.assertEqual( - json_decode(response.body), - dict( - methods=[ - "prepare", - "data_received", - "data_received", - "data_received", - "post", - ] - ), - ) - - def test_flow_control_chunked_body(self: typing.Any): - chunks = [b"abcd", b"efgh", b"ijkl"] - - @gen.coroutine - def body_producer(write): - for i in chunks: - yield write(i) - - response = self.fetch("/", body_producer=body_producer, method="POST") - response.rethrow() - self.assertEqual( - json_decode(response.body), - dict( - methods=[ - "prepare", - "data_received", - "data_received", - "data_received", - "post", - ] - ), - ) - - def test_flow_control_compressed_body(self: typing.Any): - bytesio = BytesIO() - gzip_file = gzip.GzipFile(mode="w", fileobj=bytesio) - gzip_file.write(b"abcdefghijklmnopqrstuvwxyz") - gzip_file.close() - compressed_body = bytesio.getvalue() - response = self.fetch( - "/", - body=compressed_body, - method="POST", - headers={"Content-Encoding": "gzip"}, - ) - response.rethrow() - self.assertEqual( - json_decode(response.body), - dict( - methods=[ - "prepare", - "data_received", - "data_received", - "data_received", - "post", - ] - ), - ) - - -class DecoratedStreamingRequestFlowControlTest( - BaseStreamingRequestFlowControlTest, WebTestCase -): - def get_handlers(self): - class DecoratedFlowControlHandler(BaseFlowControlHandler): - @gen.coroutine - def data_received(self, data): - with self.in_method("data_received"): - yield gen.moment - - return [("/", DecoratedFlowControlHandler, dict(test=self))] - - -class NativeStreamingRequestFlowControlTest( - BaseStreamingRequestFlowControlTest, WebTestCase -): - def get_handlers(self): - class NativeFlowControlHandler(BaseFlowControlHandler): - async def data_received(self, data): - with self.in_method("data_received"): - import asyncio - - await asyncio.sleep(0) - - return [("/", NativeFlowControlHandler, dict(test=self))] - - -class IncorrectContentLengthTest(SimpleHandlerTestCase): - def get_handlers(self): - test = self - self.server_error = None - - # Manually set a content-length that doesn't match the actual content. - class TooHigh(RequestHandler): - def get(self): - self.set_header("Content-Length", "42") - try: - self.finish("ok") - except Exception as e: - test.server_error = e - raise - - class TooLow(RequestHandler): - def get(self): - self.set_header("Content-Length", "2") - try: - self.finish("hello") - except Exception as e: - test.server_error = e - raise - - return [("/high", TooHigh), ("/low", TooLow)] - - def test_content_length_too_high(self): - # When the content-length is too high, the connection is simply - # closed without completing the response. An error is logged on - # the server. - with ExpectLog(app_log, "(Uncaught exception|Exception in callback)"): - with ExpectLog( - gen_log, - "(Cannot send error response after headers written" - "|Failed to flush partial response)", - ): - with self.assertRaises(HTTPClientError): - self.fetch("/high", raise_error=True) - self.assertEqual( - str(self.server_error), "Tried to write 40 bytes less than Content-Length" - ) - - def test_content_length_too_low(self): - # When the content-length is too low, the connection is closed - # without writing the last chunk, so the client never sees the request - # complete (which would be a framing error). - with ExpectLog(app_log, "(Uncaught exception|Exception in callback)"): - with ExpectLog( - gen_log, - "(Cannot send error response after headers written" - "|Failed to flush partial response)", - ): - with self.assertRaises(HTTPClientError): - self.fetch("/low", raise_error=True) - self.assertEqual( - str(self.server_error), "Tried to write more data than Content-Length" - ) - - -class ClientCloseTest(SimpleHandlerTestCase): - class Handler(RequestHandler): - def get(self): - if self.request.version.startswith("HTTP/1"): - # Simulate a connection closed by the client during - # request processing. The client will see an error, but the - # server should respond gracefully (without logging errors - # because we were unable to write out as many bytes as - # Content-Length said we would) - self.request.connection.stream.close() # type: ignore - self.write("hello") - else: - # TODO: add a HTTP2-compatible version of this test. - self.write("requires HTTP/1.x") - - def test_client_close(self): - with self.assertRaises((HTTPClientError, unittest.SkipTest)): # type: ignore - response = self.fetch("/", raise_error=True) - if response.body == b"requires HTTP/1.x": - self.skipTest("requires HTTP/1.x") - self.assertEqual(response.code, 599) - - -class SignedValueTest(unittest.TestCase): - SECRET = "It's a secret to everybody" - SECRET_DICT = {0: "asdfbasdf", 1: "12312312", 2: "2342342"} - - def past(self): - return self.present() - 86400 * 32 - - def present(self): - return 1300000000 - - def test_known_values(self): - signed_v1 = create_signed_value( - SignedValueTest.SECRET, "key", "value", version=1, clock=self.present - ) - self.assertEqual( - signed_v1, b"dmFsdWU=|1300000000|31c934969f53e48164c50768b40cbd7e2daaaa4f" - ) - - signed_v2 = create_signed_value( - SignedValueTest.SECRET, "key", "value", version=2, clock=self.present - ) - self.assertEqual( - signed_v2, - b"2|1:0|10:1300000000|3:key|8:dmFsdWU=|" - b"3d4e60b996ff9c5d5788e333a0cba6f238a22c6c0f94788870e1a9ecd482e152", - ) - - signed_default = create_signed_value( - SignedValueTest.SECRET, "key", "value", clock=self.present - ) - self.assertEqual(signed_default, signed_v2) - - decoded_v1 = decode_signed_value( - SignedValueTest.SECRET, "key", signed_v1, min_version=1, clock=self.present - ) - self.assertEqual(decoded_v1, b"value") - - decoded_v2 = decode_signed_value( - SignedValueTest.SECRET, "key", signed_v2, min_version=2, clock=self.present - ) - self.assertEqual(decoded_v2, b"value") - - def test_name_swap(self): - signed1 = create_signed_value( - SignedValueTest.SECRET, "key1", "value", clock=self.present - ) - signed2 = create_signed_value( - SignedValueTest.SECRET, "key2", "value", clock=self.present - ) - # Try decoding each string with the other's "name" - decoded1 = decode_signed_value( - SignedValueTest.SECRET, "key2", signed1, clock=self.present - ) - self.assertIs(decoded1, None) - decoded2 = decode_signed_value( - SignedValueTest.SECRET, "key1", signed2, clock=self.present - ) - self.assertIs(decoded2, None) - - def test_expired(self): - signed = create_signed_value( - SignedValueTest.SECRET, "key1", "value", clock=self.past - ) - decoded_past = decode_signed_value( - SignedValueTest.SECRET, "key1", signed, clock=self.past - ) - self.assertEqual(decoded_past, b"value") - decoded_present = decode_signed_value( - SignedValueTest.SECRET, "key1", signed, clock=self.present - ) - self.assertIs(decoded_present, None) - - def test_payload_tampering(self): - # These cookies are variants of the one in test_known_values. - sig = "3d4e60b996ff9c5d5788e333a0cba6f238a22c6c0f94788870e1a9ecd482e152" - - def validate(prefix): - return b"value" == decode_signed_value( - SignedValueTest.SECRET, "key", prefix + sig, clock=self.present - ) - - self.assertTrue(validate("2|1:0|10:1300000000|3:key|8:dmFsdWU=|")) - # Change key version - self.assertFalse(validate("2|1:1|10:1300000000|3:key|8:dmFsdWU=|")) - # length mismatch (field too short) - self.assertFalse(validate("2|1:0|10:130000000|3:key|8:dmFsdWU=|")) - # length mismatch (field too long) - self.assertFalse(validate("2|1:0|10:1300000000|3:keey|8:dmFsdWU=|")) - - def test_signature_tampering(self): - prefix = "2|1:0|10:1300000000|3:key|8:dmFsdWU=|" - - def validate(sig): - return b"value" == decode_signed_value( - SignedValueTest.SECRET, "key", prefix + sig, clock=self.present - ) - - self.assertTrue( - validate("3d4e60b996ff9c5d5788e333a0cba6f238a22c6c0f94788870e1a9ecd482e152") - ) - # All zeros - self.assertFalse(validate("0" * 32)) - # Change one character - self.assertFalse( - validate("4d4e60b996ff9c5d5788e333a0cba6f238a22c6c0f94788870e1a9ecd482e152") - ) - # Change another character - self.assertFalse( - validate("3d4e60b996ff9c5d5788e333a0cba6f238a22c6c0f94788870e1a9ecd482e153") - ) - # Truncate - self.assertFalse( - validate("3d4e60b996ff9c5d5788e333a0cba6f238a22c6c0f94788870e1a9ecd482e15") - ) - # Lengthen - self.assertFalse( - validate( - "3d4e60b996ff9c5d5788e333a0cba6f238a22c6c0f94788870e1a9ecd482e1538" - ) - ) - - def test_non_ascii(self): - value = b"\xe9" - signed = create_signed_value( - SignedValueTest.SECRET, "key", value, clock=self.present - ) - decoded = decode_signed_value( - SignedValueTest.SECRET, "key", signed, clock=self.present - ) - self.assertEqual(value, decoded) - - def test_key_versioning_read_write_default_key(self): - value = b"\xe9" - signed = create_signed_value( - SignedValueTest.SECRET_DICT, "key", value, clock=self.present, key_version=0 - ) - decoded = decode_signed_value( - SignedValueTest.SECRET_DICT, "key", signed, clock=self.present - ) - self.assertEqual(value, decoded) - - def test_key_versioning_read_write_non_default_key(self): - value = b"\xe9" - signed = create_signed_value( - SignedValueTest.SECRET_DICT, "key", value, clock=self.present, key_version=1 - ) - decoded = decode_signed_value( - SignedValueTest.SECRET_DICT, "key", signed, clock=self.present - ) - self.assertEqual(value, decoded) - - def test_key_versioning_invalid_key(self): - value = b"\xe9" - signed = create_signed_value( - SignedValueTest.SECRET_DICT, "key", value, clock=self.present, key_version=0 - ) - newkeys = SignedValueTest.SECRET_DICT.copy() - newkeys.pop(0) - decoded = decode_signed_value(newkeys, "key", signed, clock=self.present) - self.assertEqual(None, decoded) - - def test_key_version_retrieval(self): - value = b"\xe9" - signed = create_signed_value( - SignedValueTest.SECRET_DICT, "key", value, clock=self.present, key_version=1 - ) - key_version = get_signature_key_version(signed) - self.assertEqual(1, key_version) - - -class XSRFTest(SimpleHandlerTestCase): - class Handler(RequestHandler): - def get(self): - version = int(self.get_argument("version", "2")) - # This would be a bad idea in a real app, but in this test - # it's fine. - self.settings["xsrf_cookie_version"] = version - self.write(self.xsrf_token) - - def post(self): - self.write("ok") - - def get_app_kwargs(self): - return dict(xsrf_cookies=True) - - def setUp(self): - super().setUp() - self.xsrf_token = self.get_token() - - def get_token(self, old_token=None, version=None): - if old_token is not None: - headers = self.cookie_headers(old_token) - else: - headers = None - response = self.fetch( - "/" if version is None else ("/?version=%d" % version), headers=headers - ) - response.rethrow() - return native_str(response.body) - - def cookie_headers(self, token=None): - if token is None: - token = self.xsrf_token - return {"Cookie": "_xsrf=" + token} - - def test_xsrf_fail_no_token(self): - with ExpectLog(gen_log, ".*'_xsrf' argument missing"): - response = self.fetch("/", method="POST", body=b"") - self.assertEqual(response.code, 403) - - def test_xsrf_fail_body_no_cookie(self): - with ExpectLog(gen_log, ".*XSRF cookie does not match POST"): - response = self.fetch( - "/", - method="POST", - body=urllib.parse.urlencode(dict(_xsrf=self.xsrf_token)), - ) - self.assertEqual(response.code, 403) - - def test_xsrf_fail_argument_invalid_format(self): - with ExpectLog(gen_log, ".*'_xsrf' argument has invalid format"): - response = self.fetch( - "/", - method="POST", - headers=self.cookie_headers(), - body=urllib.parse.urlencode(dict(_xsrf="3|")), - ) - self.assertEqual(response.code, 403) - - def test_xsrf_fail_cookie_invalid_format(self): - with ExpectLog(gen_log, ".*XSRF cookie does not match POST"): - response = self.fetch( - "/", - method="POST", - headers=self.cookie_headers(token="3|"), - body=urllib.parse.urlencode(dict(_xsrf=self.xsrf_token)), - ) - self.assertEqual(response.code, 403) - - def test_xsrf_fail_cookie_no_body(self): - with ExpectLog(gen_log, ".*'_xsrf' argument missing"): - response = self.fetch( - "/", method="POST", body=b"", headers=self.cookie_headers() - ) - self.assertEqual(response.code, 403) - - def test_xsrf_success_short_token(self): - response = self.fetch( - "/", - method="POST", - body=urllib.parse.urlencode(dict(_xsrf="deadbeef")), - headers=self.cookie_headers(token="deadbeef"), - ) - self.assertEqual(response.code, 200) - - def test_xsrf_success_non_hex_token(self): - response = self.fetch( - "/", - method="POST", - body=urllib.parse.urlencode(dict(_xsrf="xoxo")), - headers=self.cookie_headers(token="xoxo"), - ) - self.assertEqual(response.code, 200) - - def test_xsrf_success_post_body(self): - response = self.fetch( - "/", - method="POST", - body=urllib.parse.urlencode(dict(_xsrf=self.xsrf_token)), - headers=self.cookie_headers(), - ) - self.assertEqual(response.code, 200) - - def test_xsrf_success_query_string(self): - response = self.fetch( - "/?" + urllib.parse.urlencode(dict(_xsrf=self.xsrf_token)), - method="POST", - body=b"", - headers=self.cookie_headers(), - ) - self.assertEqual(response.code, 200) - - def test_xsrf_success_header(self): - response = self.fetch( - "/", - method="POST", - body=b"", - headers=dict( - {"X-Xsrftoken": self.xsrf_token}, # type: ignore - **self.cookie_headers() - ), - ) - self.assertEqual(response.code, 200) - - def test_distinct_tokens(self): - # Every request gets a distinct token. - NUM_TOKENS = 10 - tokens = set() - for i in range(NUM_TOKENS): - tokens.add(self.get_token()) - self.assertEqual(len(tokens), NUM_TOKENS) - - def test_cross_user(self): - token2 = self.get_token() - # Each token can be used to authenticate its own request. - for token in (self.xsrf_token, token2): - response = self.fetch( - "/", - method="POST", - body=urllib.parse.urlencode(dict(_xsrf=token)), - headers=self.cookie_headers(token), - ) - self.assertEqual(response.code, 200) - # Sending one in the cookie and the other in the body is not allowed. - for cookie_token, body_token in ( - (self.xsrf_token, token2), - (token2, self.xsrf_token), - ): - with ExpectLog(gen_log, ".*XSRF cookie does not match POST"): - response = self.fetch( - "/", - method="POST", - body=urllib.parse.urlencode(dict(_xsrf=body_token)), - headers=self.cookie_headers(cookie_token), - ) - self.assertEqual(response.code, 403) - - def test_refresh_token(self): - token = self.xsrf_token - tokens_seen = set([token]) - # A user's token is stable over time. Refreshing the page in one tab - # might update the cookie while an older tab still has the old cookie - # in its DOM. Simulate this scenario by passing a constant token - # in the body and re-querying for the token. - for i in range(5): - token = self.get_token(token) - # Tokens are encoded uniquely each time - tokens_seen.add(token) - response = self.fetch( - "/", - method="POST", - body=urllib.parse.urlencode(dict(_xsrf=self.xsrf_token)), - headers=self.cookie_headers(token), - ) - self.assertEqual(response.code, 200) - self.assertEqual(len(tokens_seen), 6) - - def test_versioning(self): - # Version 1 still produces distinct tokens per request. - self.assertNotEqual(self.get_token(version=1), self.get_token(version=1)) - - # Refreshed v1 tokens are all identical. - v1_token = self.get_token(version=1) - for i in range(5): - self.assertEqual(self.get_token(v1_token, version=1), v1_token) - - # Upgrade to a v2 version of the same token - v2_token = self.get_token(v1_token) - self.assertNotEqual(v1_token, v2_token) - # Each v1 token can map to many v2 tokens. - self.assertNotEqual(v2_token, self.get_token(v1_token)) - - # The tokens are cross-compatible. - for cookie_token, body_token in ((v1_token, v2_token), (v2_token, v1_token)): - response = self.fetch( - "/", - method="POST", - body=urllib.parse.urlencode(dict(_xsrf=body_token)), - headers=self.cookie_headers(cookie_token), - ) - self.assertEqual(response.code, 200) - - -class XSRFCookieKwargsTest(SimpleHandlerTestCase): - class Handler(RequestHandler): - def get(self): - self.write(self.xsrf_token) - - def get_app_kwargs(self): - return dict( - xsrf_cookies=True, xsrf_cookie_kwargs=dict(httponly=True, expires_days=2) - ) - - def test_xsrf_httponly(self): - response = self.fetch("/") - self.assertIn("httponly;", response.headers["Set-Cookie"].lower()) - self.assertIn("expires=", response.headers["Set-Cookie"].lower()) - header = response.headers.get("Set-Cookie") - assert header is not None - match = re.match(".*; expires=(?P<expires>.+);.*", header) - assert match is not None - - expires = datetime.datetime.utcnow() + datetime.timedelta(days=2) - parsed = email.utils.parsedate(match.groupdict()["expires"]) - assert parsed is not None - header_expires = datetime.datetime(*parsed[:6]) - self.assertTrue(abs((expires - header_expires).total_seconds()) < 10) - - -class FinishExceptionTest(SimpleHandlerTestCase): - class Handler(RequestHandler): - def get(self): - self.set_status(401) - self.set_header("WWW-Authenticate", 'Basic realm="something"') - if self.get_argument("finish_value", ""): - raise Finish("authentication required") - else: - self.write("authentication required") - raise Finish() - - def test_finish_exception(self): - for u in ["/", "/?finish_value=1"]: - response = self.fetch(u) - self.assertEqual(response.code, 401) - self.assertEqual( - 'Basic realm="something"', response.headers.get("WWW-Authenticate") - ) - self.assertEqual(b"authentication required", response.body) - - -class DecoratorTest(WebTestCase): - def get_handlers(self): - class RemoveSlashHandler(RequestHandler): - @removeslash - def get(self): - pass - - class AddSlashHandler(RequestHandler): - @addslash - def get(self): - pass - - return [("/removeslash/", RemoveSlashHandler), ("/addslash", AddSlashHandler)] - - def test_removeslash(self): - response = self.fetch("/removeslash/", follow_redirects=False) - self.assertEqual(response.code, 301) - self.assertEqual(response.headers["Location"], "/removeslash") - - response = self.fetch("/removeslash/?foo=bar", follow_redirects=False) - self.assertEqual(response.code, 301) - self.assertEqual(response.headers["Location"], "/removeslash?foo=bar") - - def test_addslash(self): - response = self.fetch("/addslash", follow_redirects=False) - self.assertEqual(response.code, 301) - self.assertEqual(response.headers["Location"], "/addslash/") - - response = self.fetch("/addslash?foo=bar", follow_redirects=False) - self.assertEqual(response.code, 301) - self.assertEqual(response.headers["Location"], "/addslash/?foo=bar") - - -class CacheTest(WebTestCase): - def get_handlers(self): - class EtagHandler(RequestHandler): - def get(self, computed_etag): - self.write(computed_etag) - - def compute_etag(self): - return self._write_buffer[0] - - return [("/etag/(.*)", EtagHandler)] - - def test_wildcard_etag(self): - computed_etag = '"xyzzy"' - etags = "*" - self._test_etag(computed_etag, etags, 304) - - def test_strong_etag_match(self): - computed_etag = '"xyzzy"' - etags = '"xyzzy"' - self._test_etag(computed_etag, etags, 304) - - def test_multiple_strong_etag_match(self): - computed_etag = '"xyzzy1"' - etags = '"xyzzy1", "xyzzy2"' - self._test_etag(computed_etag, etags, 304) - - def test_strong_etag_not_match(self): - computed_etag = '"xyzzy"' - etags = '"xyzzy1"' - self._test_etag(computed_etag, etags, 200) - - def test_multiple_strong_etag_not_match(self): - computed_etag = '"xyzzy"' - etags = '"xyzzy1", "xyzzy2"' - self._test_etag(computed_etag, etags, 200) - - def test_weak_etag_match(self): - computed_etag = '"xyzzy1"' - etags = 'W/"xyzzy1"' - self._test_etag(computed_etag, etags, 304) - - def test_multiple_weak_etag_match(self): - computed_etag = '"xyzzy2"' - etags = 'W/"xyzzy1", W/"xyzzy2"' - self._test_etag(computed_etag, etags, 304) - - def test_weak_etag_not_match(self): - computed_etag = '"xyzzy2"' - etags = 'W/"xyzzy1"' - self._test_etag(computed_etag, etags, 200) - - def test_multiple_weak_etag_not_match(self): - computed_etag = '"xyzzy3"' - etags = 'W/"xyzzy1", W/"xyzzy2"' - self._test_etag(computed_etag, etags, 200) - - def _test_etag(self, computed_etag, etags, status_code): - response = self.fetch( - "/etag/" + computed_etag, headers={"If-None-Match": etags} - ) - self.assertEqual(response.code, status_code) - - -class RequestSummaryTest(SimpleHandlerTestCase): - class Handler(RequestHandler): - def get(self): - # remote_ip is optional, although it's set by - # both HTTPServer and WSGIAdapter. - # Clobber it to make sure it doesn't break logging. - self.request.remote_ip = None - self.finish(self._request_summary()) - - def test_missing_remote_ip(self): - resp = self.fetch("/") - self.assertEqual(resp.body, b"GET / (None)") - - -class HTTPErrorTest(unittest.TestCase): - def test_copy(self): - e = HTTPError(403, reason="Go away") - e2 = copy.copy(e) - self.assertIsNot(e, e2) - self.assertEqual(e.status_code, e2.status_code) - self.assertEqual(e.reason, e2.reason) - - -class ApplicationTest(AsyncTestCase): - def test_listen(self): - app = Application([]) - server = app.listen(0, address="127.0.0.1") - server.stop() - - -class URLSpecReverseTest(unittest.TestCase): - def test_reverse(self): - self.assertEqual("/favicon.ico", url(r"/favicon\.ico", None).reverse()) - self.assertEqual("/favicon.ico", url(r"^/favicon\.ico$", None).reverse()) - - def test_non_reversible(self): - # URLSpecs are non-reversible if they include non-constant - # regex features outside capturing groups. Currently, this is - # only strictly enforced for backslash-escaped character - # classes. - paths = [r"^/api/v\d+/foo/(\w+)$"] - for path in paths: - # A URLSpec can still be created even if it cannot be reversed. - url_spec = url(path, None) - try: - result = url_spec.reverse() - self.fail( - "did not get expected exception when reversing %s. " - "result: %s" % (path, result) - ) - except ValueError: - pass - - def test_reverse_arguments(self): - self.assertEqual( - "/api/v1/foo/bar", url(r"^/api/v1/foo/(\w+)$", None).reverse("bar") - ) - self.assertEqual( - "/api.v1/foo/5/icon.png", - url(r"/api\.v1/foo/([0-9]+)/icon\.png", None).reverse(5), - ) - - -class RedirectHandlerTest(WebTestCase): - def get_handlers(self): - return [ - ("/src", WebRedirectHandler, {"url": "/dst"}), - ("/src2", WebRedirectHandler, {"url": "/dst2?foo=bar"}), - (r"/(.*?)/(.*?)/(.*)", WebRedirectHandler, {"url": "/{1}/{0}/{2}"}), - ] - - def test_basic_redirect(self): - response = self.fetch("/src", follow_redirects=False) - self.assertEqual(response.code, 301) - self.assertEqual(response.headers["Location"], "/dst") - - def test_redirect_with_argument(self): - response = self.fetch("/src?foo=bar", follow_redirects=False) - self.assertEqual(response.code, 301) - self.assertEqual(response.headers["Location"], "/dst?foo=bar") - - def test_redirect_with_appending_argument(self): - response = self.fetch("/src2?foo2=bar2", follow_redirects=False) - self.assertEqual(response.code, 301) - self.assertEqual(response.headers["Location"], "/dst2?foo=bar&foo2=bar2") - - def test_redirect_pattern(self): - response = self.fetch("/a/b/c", follow_redirects=False) - self.assertEqual(response.code, 301) - self.assertEqual(response.headers["Location"], "/b/a/c") diff --git a/venv/lib/python3.8/site-packages/tornado/test/websocket_test.py b/venv/lib/python3.8/site-packages/tornado/test/websocket_test.py deleted file mode 100644 index befe06d..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/websocket_test.py +++ /dev/null @@ -1,840 +0,0 @@ -import asyncio -import functools -import traceback -import typing -import unittest - -from tornado.concurrent import Future -from tornado import gen -from tornado.httpclient import HTTPError, HTTPRequest -from tornado.locks import Event -from tornado.log import gen_log, app_log -from tornado.simple_httpclient import SimpleAsyncHTTPClient -from tornado.template import DictLoader -from tornado.testing import AsyncHTTPTestCase, gen_test, bind_unused_port, ExpectLog -from tornado.web import Application, RequestHandler - -try: - import tornado.websocket # noqa: F401 - from tornado.util import _websocket_mask_python -except ImportError: - # The unittest module presents misleading errors on ImportError - # (it acts as if websocket_test could not be found, hiding the underlying - # error). If we get an ImportError here (which could happen due to - # TORNADO_EXTENSION=1), print some extra information before failing. - traceback.print_exc() - raise - -from tornado.websocket import ( - WebSocketHandler, - websocket_connect, - WebSocketError, - WebSocketClosedError, -) - -try: - from tornado import speedups -except ImportError: - speedups = None # type: ignore - - -class TestWebSocketHandler(WebSocketHandler): - """Base class for testing handlers that exposes the on_close event. - - This allows for tests to see the close code and reason on the - server side. - - """ - - def initialize(self, close_future=None, compression_options=None): - self.close_future = close_future - self.compression_options = compression_options - - def get_compression_options(self): - return self.compression_options - - def on_close(self): - if self.close_future is not None: - self.close_future.set_result((self.close_code, self.close_reason)) - - -class EchoHandler(TestWebSocketHandler): - @gen.coroutine - def on_message(self, message): - try: - yield self.write_message(message, isinstance(message, bytes)) - except asyncio.CancelledError: - pass - except WebSocketClosedError: - pass - - -class ErrorInOnMessageHandler(TestWebSocketHandler): - def on_message(self, message): - 1 / 0 - - -class HeaderHandler(TestWebSocketHandler): - def open(self): - methods_to_test = [ - functools.partial(self.write, "This should not work"), - functools.partial(self.redirect, "http://localhost/elsewhere"), - functools.partial(self.set_header, "X-Test", ""), - functools.partial(self.set_cookie, "Chocolate", "Chip"), - functools.partial(self.set_status, 503), - self.flush, - self.finish, - ] - for method in methods_to_test: - try: - # In a websocket context, many RequestHandler methods - # raise RuntimeErrors. - method() # type: ignore - raise Exception("did not get expected exception") - except RuntimeError: - pass - self.write_message(self.request.headers.get("X-Test", "")) - - -class HeaderEchoHandler(TestWebSocketHandler): - def set_default_headers(self): - self.set_header("X-Extra-Response-Header", "Extra-Response-Value") - - def prepare(self): - for k, v in self.request.headers.get_all(): - if k.lower().startswith("x-test"): - self.set_header(k, v) - - -class NonWebSocketHandler(RequestHandler): - def get(self): - self.write("ok") - - -class RedirectHandler(RequestHandler): - def get(self): - self.redirect("/echo") - - -class CloseReasonHandler(TestWebSocketHandler): - def open(self): - self.on_close_called = False - self.close(1001, "goodbye") - - -class AsyncPrepareHandler(TestWebSocketHandler): - @gen.coroutine - def prepare(self): - yield gen.moment - - def on_message(self, message): - self.write_message(message) - - -class PathArgsHandler(TestWebSocketHandler): - def open(self, arg): - self.write_message(arg) - - -class CoroutineOnMessageHandler(TestWebSocketHandler): - def initialize(self, **kwargs): - super().initialize(**kwargs) - self.sleeping = 0 - - @gen.coroutine - def on_message(self, message): - if self.sleeping > 0: - self.write_message("another coroutine is already sleeping") - self.sleeping += 1 - yield gen.sleep(0.01) - self.sleeping -= 1 - self.write_message(message) - - -class RenderMessageHandler(TestWebSocketHandler): - def on_message(self, message): - self.write_message(self.render_string("message.html", message=message)) - - -class SubprotocolHandler(TestWebSocketHandler): - def initialize(self, **kwargs): - super().initialize(**kwargs) - self.select_subprotocol_called = False - - def select_subprotocol(self, subprotocols): - if self.select_subprotocol_called: - raise Exception("select_subprotocol called twice") - self.select_subprotocol_called = True - if "goodproto" in subprotocols: - return "goodproto" - return None - - def open(self): - if not self.select_subprotocol_called: - raise Exception("select_subprotocol not called") - self.write_message("subprotocol=%s" % self.selected_subprotocol) - - -class OpenCoroutineHandler(TestWebSocketHandler): - def initialize(self, test, **kwargs): - super().initialize(**kwargs) - self.test = test - self.open_finished = False - - @gen.coroutine - def open(self): - yield self.test.message_sent.wait() - yield gen.sleep(0.010) - self.open_finished = True - - def on_message(self, message): - if not self.open_finished: - raise Exception("on_message called before open finished") - self.write_message("ok") - - -class ErrorInOpenHandler(TestWebSocketHandler): - def open(self): - raise Exception("boom") - - -class ErrorInAsyncOpenHandler(TestWebSocketHandler): - async def open(self): - await asyncio.sleep(0) - raise Exception("boom") - - -class NoDelayHandler(TestWebSocketHandler): - def open(self): - self.set_nodelay(True) - self.write_message("hello") - - -class WebSocketBaseTestCase(AsyncHTTPTestCase): - @gen.coroutine - def ws_connect(self, path, **kwargs): - ws = yield websocket_connect( - "ws://127.0.0.1:%d%s" % (self.get_http_port(), path), **kwargs - ) - raise gen.Return(ws) - - -class WebSocketTest(WebSocketBaseTestCase): - def get_app(self): - self.close_future = Future() # type: Future[None] - return Application( - [ - ("/echo", EchoHandler, dict(close_future=self.close_future)), - ("/non_ws", NonWebSocketHandler), - ("/redirect", RedirectHandler), - ("/header", HeaderHandler, dict(close_future=self.close_future)), - ( - "/header_echo", - HeaderEchoHandler, - dict(close_future=self.close_future), - ), - ( - "/close_reason", - CloseReasonHandler, - dict(close_future=self.close_future), - ), - ( - "/error_in_on_message", - ErrorInOnMessageHandler, - dict(close_future=self.close_future), - ), - ( - "/async_prepare", - AsyncPrepareHandler, - dict(close_future=self.close_future), - ), - ( - "/path_args/(.*)", - PathArgsHandler, - dict(close_future=self.close_future), - ), - ( - "/coroutine", - CoroutineOnMessageHandler, - dict(close_future=self.close_future), - ), - ("/render", RenderMessageHandler, dict(close_future=self.close_future)), - ( - "/subprotocol", - SubprotocolHandler, - dict(close_future=self.close_future), - ), - ( - "/open_coroutine", - OpenCoroutineHandler, - dict(close_future=self.close_future, test=self), - ), - ("/error_in_open", ErrorInOpenHandler), - ("/error_in_async_open", ErrorInAsyncOpenHandler), - ("/nodelay", NoDelayHandler), - ], - template_loader=DictLoader({"message.html": "<b>{{ message }}</b>"}), - ) - - def get_http_client(self): - # These tests require HTTP/1; force the use of SimpleAsyncHTTPClient. - return SimpleAsyncHTTPClient() - - def tearDown(self): - super().tearDown() - RequestHandler._template_loaders.clear() - - def test_http_request(self): - # WS server, HTTP client. - response = self.fetch("/echo") - self.assertEqual(response.code, 400) - - def test_missing_websocket_key(self): - response = self.fetch( - "/echo", - headers={ - "Connection": "Upgrade", - "Upgrade": "WebSocket", - "Sec-WebSocket-Version": "13", - }, - ) - self.assertEqual(response.code, 400) - - def test_bad_websocket_version(self): - response = self.fetch( - "/echo", - headers={ - "Connection": "Upgrade", - "Upgrade": "WebSocket", - "Sec-WebSocket-Version": "12", - }, - ) - self.assertEqual(response.code, 426) - - @gen_test - def test_websocket_gen(self): - ws = yield self.ws_connect("/echo") - yield ws.write_message("hello") - response = yield ws.read_message() - self.assertEqual(response, "hello") - - def test_websocket_callbacks(self): - websocket_connect( - "ws://127.0.0.1:%d/echo" % self.get_http_port(), callback=self.stop - ) - ws = self.wait().result() - ws.write_message("hello") - ws.read_message(self.stop) - response = self.wait().result() - self.assertEqual(response, "hello") - self.close_future.add_done_callback(lambda f: self.stop()) - ws.close() - self.wait() - - @gen_test - def test_binary_message(self): - ws = yield self.ws_connect("/echo") - ws.write_message(b"hello \xe9", binary=True) - response = yield ws.read_message() - self.assertEqual(response, b"hello \xe9") - - @gen_test - def test_unicode_message(self): - ws = yield self.ws_connect("/echo") - ws.write_message(u"hello \u00e9") - response = yield ws.read_message() - self.assertEqual(response, u"hello \u00e9") - - @gen_test - def test_render_message(self): - ws = yield self.ws_connect("/render") - ws.write_message("hello") - response = yield ws.read_message() - self.assertEqual(response, "<b>hello</b>") - - @gen_test - def test_error_in_on_message(self): - ws = yield self.ws_connect("/error_in_on_message") - ws.write_message("hello") - with ExpectLog(app_log, "Uncaught exception"): - response = yield ws.read_message() - self.assertIs(response, None) - - @gen_test - def test_websocket_http_fail(self): - with self.assertRaises(HTTPError) as cm: - yield self.ws_connect("/notfound") - self.assertEqual(cm.exception.code, 404) - - @gen_test - def test_websocket_http_success(self): - with self.assertRaises(WebSocketError): - yield self.ws_connect("/non_ws") - - @gen_test - def test_websocket_http_redirect(self): - with self.assertRaises(HTTPError): - yield self.ws_connect("/redirect") - - @gen_test - def test_websocket_network_fail(self): - sock, port = bind_unused_port() - sock.close() - with self.assertRaises(IOError): - with ExpectLog(gen_log, ".*"): - yield websocket_connect( - "ws://127.0.0.1:%d/" % port, connect_timeout=3600 - ) - - @gen_test - def test_websocket_close_buffered_data(self): - ws = yield websocket_connect("ws://127.0.0.1:%d/echo" % self.get_http_port()) - ws.write_message("hello") - ws.write_message("world") - # Close the underlying stream. - ws.stream.close() - - @gen_test - def test_websocket_headers(self): - # Ensure that arbitrary headers can be passed through websocket_connect. - ws = yield websocket_connect( - HTTPRequest( - "ws://127.0.0.1:%d/header" % self.get_http_port(), - headers={"X-Test": "hello"}, - ) - ) - response = yield ws.read_message() - self.assertEqual(response, "hello") - - @gen_test - def test_websocket_header_echo(self): - # Ensure that headers can be returned in the response. - # Specifically, that arbitrary headers passed through websocket_connect - # can be returned. - ws = yield websocket_connect( - HTTPRequest( - "ws://127.0.0.1:%d/header_echo" % self.get_http_port(), - headers={"X-Test-Hello": "hello"}, - ) - ) - self.assertEqual(ws.headers.get("X-Test-Hello"), "hello") - self.assertEqual( - ws.headers.get("X-Extra-Response-Header"), "Extra-Response-Value" - ) - - @gen_test - def test_server_close_reason(self): - ws = yield self.ws_connect("/close_reason") - msg = yield ws.read_message() - # A message of None means the other side closed the connection. - self.assertIs(msg, None) - self.assertEqual(ws.close_code, 1001) - self.assertEqual(ws.close_reason, "goodbye") - # The on_close callback is called no matter which side closed. - code, reason = yield self.close_future - # The client echoed the close code it received to the server, - # so the server's close code (returned via close_future) is - # the same. - self.assertEqual(code, 1001) - - @gen_test - def test_client_close_reason(self): - ws = yield self.ws_connect("/echo") - ws.close(1001, "goodbye") - code, reason = yield self.close_future - self.assertEqual(code, 1001) - self.assertEqual(reason, "goodbye") - - @gen_test - def test_write_after_close(self): - ws = yield self.ws_connect("/close_reason") - msg = yield ws.read_message() - self.assertIs(msg, None) - with self.assertRaises(WebSocketClosedError): - ws.write_message("hello") - - @gen_test - def test_async_prepare(self): - # Previously, an async prepare method triggered a bug that would - # result in a timeout on test shutdown (and a memory leak). - ws = yield self.ws_connect("/async_prepare") - ws.write_message("hello") - res = yield ws.read_message() - self.assertEqual(res, "hello") - - @gen_test - def test_path_args(self): - ws = yield self.ws_connect("/path_args/hello") - res = yield ws.read_message() - self.assertEqual(res, "hello") - - @gen_test - def test_coroutine(self): - ws = yield self.ws_connect("/coroutine") - # Send both messages immediately, coroutine must process one at a time. - yield ws.write_message("hello1") - yield ws.write_message("hello2") - res = yield ws.read_message() - self.assertEqual(res, "hello1") - res = yield ws.read_message() - self.assertEqual(res, "hello2") - - @gen_test - def test_check_origin_valid_no_path(self): - port = self.get_http_port() - - url = "ws://127.0.0.1:%d/echo" % port - headers = {"Origin": "http://127.0.0.1:%d" % port} - - ws = yield websocket_connect(HTTPRequest(url, headers=headers)) - ws.write_message("hello") - response = yield ws.read_message() - self.assertEqual(response, "hello") - - @gen_test - def test_check_origin_valid_with_path(self): - port = self.get_http_port() - - url = "ws://127.0.0.1:%d/echo" % port - headers = {"Origin": "http://127.0.0.1:%d/something" % port} - - ws = yield websocket_connect(HTTPRequest(url, headers=headers)) - ws.write_message("hello") - response = yield ws.read_message() - self.assertEqual(response, "hello") - - @gen_test - def test_check_origin_invalid_partial_url(self): - port = self.get_http_port() - - url = "ws://127.0.0.1:%d/echo" % port - headers = {"Origin": "127.0.0.1:%d" % port} - - with self.assertRaises(HTTPError) as cm: - yield websocket_connect(HTTPRequest(url, headers=headers)) - self.assertEqual(cm.exception.code, 403) - - @gen_test - def test_check_origin_invalid(self): - port = self.get_http_port() - - url = "ws://127.0.0.1:%d/echo" % port - # Host is 127.0.0.1, which should not be accessible from some other - # domain - headers = {"Origin": "http://somewhereelse.com"} - - with self.assertRaises(HTTPError) as cm: - yield websocket_connect(HTTPRequest(url, headers=headers)) - - self.assertEqual(cm.exception.code, 403) - - @gen_test - def test_check_origin_invalid_subdomains(self): - port = self.get_http_port() - - url = "ws://localhost:%d/echo" % port - # Subdomains should be disallowed by default. If we could pass a - # resolver to websocket_connect we could test sibling domains as well. - headers = {"Origin": "http://subtenant.localhost"} - - with self.assertRaises(HTTPError) as cm: - yield websocket_connect(HTTPRequest(url, headers=headers)) - - self.assertEqual(cm.exception.code, 403) - - @gen_test - def test_subprotocols(self): - ws = yield self.ws_connect( - "/subprotocol", subprotocols=["badproto", "goodproto"] - ) - self.assertEqual(ws.selected_subprotocol, "goodproto") - res = yield ws.read_message() - self.assertEqual(res, "subprotocol=goodproto") - - @gen_test - def test_subprotocols_not_offered(self): - ws = yield self.ws_connect("/subprotocol") - self.assertIs(ws.selected_subprotocol, None) - res = yield ws.read_message() - self.assertEqual(res, "subprotocol=None") - - @gen_test - def test_open_coroutine(self): - self.message_sent = Event() - ws = yield self.ws_connect("/open_coroutine") - yield ws.write_message("hello") - self.message_sent.set() - res = yield ws.read_message() - self.assertEqual(res, "ok") - - @gen_test - def test_error_in_open(self): - with ExpectLog(app_log, "Uncaught exception"): - ws = yield self.ws_connect("/error_in_open") - res = yield ws.read_message() - self.assertIsNone(res) - - @gen_test - def test_error_in_async_open(self): - with ExpectLog(app_log, "Uncaught exception"): - ws = yield self.ws_connect("/error_in_async_open") - res = yield ws.read_message() - self.assertIsNone(res) - - @gen_test - def test_nodelay(self): - ws = yield self.ws_connect("/nodelay") - res = yield ws.read_message() - self.assertEqual(res, "hello") - - -class NativeCoroutineOnMessageHandler(TestWebSocketHandler): - def initialize(self, **kwargs): - super().initialize(**kwargs) - self.sleeping = 0 - - async def on_message(self, message): - if self.sleeping > 0: - self.write_message("another coroutine is already sleeping") - self.sleeping += 1 - await gen.sleep(0.01) - self.sleeping -= 1 - self.write_message(message) - - -class WebSocketNativeCoroutineTest(WebSocketBaseTestCase): - def get_app(self): - return Application([("/native", NativeCoroutineOnMessageHandler)]) - - @gen_test - def test_native_coroutine(self): - ws = yield self.ws_connect("/native") - # Send both messages immediately, coroutine must process one at a time. - yield ws.write_message("hello1") - yield ws.write_message("hello2") - res = yield ws.read_message() - self.assertEqual(res, "hello1") - res = yield ws.read_message() - self.assertEqual(res, "hello2") - - -class CompressionTestMixin(object): - MESSAGE = "Hello world. Testing 123 123" - - def get_app(self): - class LimitedHandler(TestWebSocketHandler): - @property - def max_message_size(self): - return 1024 - - def on_message(self, message): - self.write_message(str(len(message))) - - return Application( - [ - ( - "/echo", - EchoHandler, - dict(compression_options=self.get_server_compression_options()), - ), - ( - "/limited", - LimitedHandler, - dict(compression_options=self.get_server_compression_options()), - ), - ] - ) - - def get_server_compression_options(self): - return None - - def get_client_compression_options(self): - return None - - def verify_wire_bytes(self, bytes_in: int, bytes_out: int) -> None: - raise NotImplementedError() - - @gen_test - def test_message_sizes(self: typing.Any): - ws = yield self.ws_connect( - "/echo", compression_options=self.get_client_compression_options() - ) - # Send the same message three times so we can measure the - # effect of the context_takeover options. - for i in range(3): - ws.write_message(self.MESSAGE) - response = yield ws.read_message() - self.assertEqual(response, self.MESSAGE) - self.assertEqual(ws.protocol._message_bytes_out, len(self.MESSAGE) * 3) - self.assertEqual(ws.protocol._message_bytes_in, len(self.MESSAGE) * 3) - self.verify_wire_bytes(ws.protocol._wire_bytes_in, ws.protocol._wire_bytes_out) - - @gen_test - def test_size_limit(self: typing.Any): - ws = yield self.ws_connect( - "/limited", compression_options=self.get_client_compression_options() - ) - # Small messages pass through. - ws.write_message("a" * 128) - response = yield ws.read_message() - self.assertEqual(response, "128") - # This message is too big after decompression, but it compresses - # down to a size that will pass the initial checks. - ws.write_message("a" * 2048) - response = yield ws.read_message() - self.assertIsNone(response) - - -class UncompressedTestMixin(CompressionTestMixin): - """Specialization of CompressionTestMixin when we expect no compression.""" - - def verify_wire_bytes(self: typing.Any, bytes_in, bytes_out): - # Bytes out includes the 4-byte mask key per message. - self.assertEqual(bytes_out, 3 * (len(self.MESSAGE) + 6)) - self.assertEqual(bytes_in, 3 * (len(self.MESSAGE) + 2)) - - -class NoCompressionTest(UncompressedTestMixin, WebSocketBaseTestCase): - pass - - -# If only one side tries to compress, the extension is not negotiated. -class ServerOnlyCompressionTest(UncompressedTestMixin, WebSocketBaseTestCase): - def get_server_compression_options(self): - return {} - - -class ClientOnlyCompressionTest(UncompressedTestMixin, WebSocketBaseTestCase): - def get_client_compression_options(self): - return {} - - -class DefaultCompressionTest(CompressionTestMixin, WebSocketBaseTestCase): - def get_server_compression_options(self): - return {} - - def get_client_compression_options(self): - return {} - - def verify_wire_bytes(self, bytes_in, bytes_out): - self.assertLess(bytes_out, 3 * (len(self.MESSAGE) + 6)) - self.assertLess(bytes_in, 3 * (len(self.MESSAGE) + 2)) - # Bytes out includes the 4 bytes mask key per message. - self.assertEqual(bytes_out, bytes_in + 12) - - -class MaskFunctionMixin(object): - # Subclasses should define self.mask(mask, data) - def mask(self, mask: bytes, data: bytes) -> bytes: - raise NotImplementedError() - - def test_mask(self: typing.Any): - self.assertEqual(self.mask(b"abcd", b""), b"") - self.assertEqual(self.mask(b"abcd", b"b"), b"\x03") - self.assertEqual(self.mask(b"abcd", b"54321"), b"TVPVP") - self.assertEqual(self.mask(b"ZXCV", b"98765432"), b"c`t`olpd") - # Include test cases with \x00 bytes (to ensure that the C - # extension isn't depending on null-terminated strings) and - # bytes with the high bit set (to smoke out signedness issues). - self.assertEqual( - self.mask(b"\x00\x01\x02\x03", b"\xff\xfb\xfd\xfc\xfe\xfa"), - b"\xff\xfa\xff\xff\xfe\xfb", - ) - self.assertEqual( - self.mask(b"\xff\xfb\xfd\xfc", b"\x00\x01\x02\x03\x04\x05"), - b"\xff\xfa\xff\xff\xfb\xfe", - ) - - -class PythonMaskFunctionTest(MaskFunctionMixin, unittest.TestCase): - def mask(self, mask, data): - return _websocket_mask_python(mask, data) - - -@unittest.skipIf(speedups is None, "tornado.speedups module not present") -class CythonMaskFunctionTest(MaskFunctionMixin, unittest.TestCase): - def mask(self, mask, data): - return speedups.websocket_mask(mask, data) - - -class ServerPeriodicPingTest(WebSocketBaseTestCase): - def get_app(self): - class PingHandler(TestWebSocketHandler): - def on_pong(self, data): - self.write_message("got pong") - - return Application([("/", PingHandler)], websocket_ping_interval=0.01) - - @gen_test - def test_server_ping(self): - ws = yield self.ws_connect("/") - for i in range(3): - response = yield ws.read_message() - self.assertEqual(response, "got pong") - # TODO: test that the connection gets closed if ping responses stop. - - -class ClientPeriodicPingTest(WebSocketBaseTestCase): - def get_app(self): - class PingHandler(TestWebSocketHandler): - def on_ping(self, data): - self.write_message("got ping") - - return Application([("/", PingHandler)]) - - @gen_test - def test_client_ping(self): - ws = yield self.ws_connect("/", ping_interval=0.01) - for i in range(3): - response = yield ws.read_message() - self.assertEqual(response, "got ping") - # TODO: test that the connection gets closed if ping responses stop. - - -class ManualPingTest(WebSocketBaseTestCase): - def get_app(self): - class PingHandler(TestWebSocketHandler): - def on_ping(self, data): - self.write_message(data, binary=isinstance(data, bytes)) - - return Application([("/", PingHandler)]) - - @gen_test - def test_manual_ping(self): - ws = yield self.ws_connect("/") - - self.assertRaises(ValueError, ws.ping, "a" * 126) - - ws.ping("hello") - resp = yield ws.read_message() - # on_ping always sees bytes. - self.assertEqual(resp, b"hello") - - ws.ping(b"binary hello") - resp = yield ws.read_message() - self.assertEqual(resp, b"binary hello") - - -class MaxMessageSizeTest(WebSocketBaseTestCase): - def get_app(self): - return Application([("/", EchoHandler)], websocket_max_message_size=1024) - - @gen_test - def test_large_message(self): - ws = yield self.ws_connect("/") - - # Write a message that is allowed. - msg = "a" * 1024 - ws.write_message(msg) - resp = yield ws.read_message() - self.assertEqual(resp, msg) - - # Write a message that is too large. - ws.write_message(msg + "b") - resp = yield ws.read_message() - # A message of None means the other side closed the connection. - self.assertIs(resp, None) - self.assertEqual(ws.close_code, 1009) - self.assertEqual(ws.close_reason, "message too big") - # TODO: Needs tests of messages split over multiple - # continuation frames. diff --git a/venv/lib/python3.8/site-packages/tornado/test/wsgi_test.py b/venv/lib/python3.8/site-packages/tornado/test/wsgi_test.py deleted file mode 100644 index f98da5b..0000000 --- a/venv/lib/python3.8/site-packages/tornado/test/wsgi_test.py +++ /dev/null @@ -1,20 +0,0 @@ -from wsgiref.validate import validator - -from tornado.testing import AsyncHTTPTestCase -from tornado.wsgi import WSGIContainer - - -class WSGIContainerTest(AsyncHTTPTestCase): - # TODO: Now that WSGIAdapter is gone, this is a pretty weak test. - def wsgi_app(self, environ, start_response): - status = "200 OK" - response_headers = [("Content-Type", "text/plain")] - start_response(status, response_headers) - return [b"Hello world!"] - - def get_app(self): - return WSGIContainer(validator(self.wsgi_app)) - - def test_simple(self): - response = self.fetch("/") - self.assertEqual(response.body, b"Hello world!") diff --git a/venv/lib/python3.8/site-packages/tornado/testing.py b/venv/lib/python3.8/site-packages/tornado/testing.py deleted file mode 100644 index 3351b92..0000000 --- a/venv/lib/python3.8/site-packages/tornado/testing.py +++ /dev/null @@ -1,818 +0,0 @@ -"""Support classes for automated testing. - -* `AsyncTestCase` and `AsyncHTTPTestCase`: Subclasses of unittest.TestCase - with additional support for testing asynchronous (`.IOLoop`-based) code. - -* `ExpectLog`: Make test logs less spammy. - -* `main()`: A simple test runner (wrapper around unittest.main()) with support - for the tornado.autoreload module to rerun the tests when code changes. -""" - -import asyncio -from collections.abc import Generator -import functools -import inspect -import logging -import os -import re -import signal -import socket -import sys -import unittest - -from tornado import gen -from tornado.httpclient import AsyncHTTPClient, HTTPResponse -from tornado.httpserver import HTTPServer -from tornado.ioloop import IOLoop, TimeoutError -from tornado import netutil -from tornado.platform.asyncio import AsyncIOMainLoop -from tornado.process import Subprocess -from tornado.log import app_log -from tornado.util import raise_exc_info, basestring_type -from tornado.web import Application - -import typing -from typing import Tuple, Any, Callable, Type, Dict, Union, Optional -from types import TracebackType - -if typing.TYPE_CHECKING: - # Coroutine wasn't added to typing until 3.5.3, so only import it - # when mypy is running and use forward references. - from typing import Coroutine # noqa: F401 - - _ExcInfoTuple = Tuple[ - Optional[Type[BaseException]], Optional[BaseException], Optional[TracebackType] - ] - - -_NON_OWNED_IOLOOPS = AsyncIOMainLoop - - -def bind_unused_port(reuse_port: bool = False) -> Tuple[socket.socket, int]: - """Binds a server socket to an available port on localhost. - - Returns a tuple (socket, port). - - .. versionchanged:: 4.4 - Always binds to ``127.0.0.1`` without resolving the name - ``localhost``. - """ - sock = netutil.bind_sockets( - 0, "127.0.0.1", family=socket.AF_INET, reuse_port=reuse_port - )[0] - port = sock.getsockname()[1] - return sock, port - - -def get_async_test_timeout() -> float: - """Get the global timeout setting for async tests. - - Returns a float, the timeout in seconds. - - .. versionadded:: 3.1 - """ - env = os.environ.get("ASYNC_TEST_TIMEOUT") - if env is not None: - try: - return float(env) - except ValueError: - pass - return 5 - - -class _TestMethodWrapper(object): - """Wraps a test method to raise an error if it returns a value. - - This is mainly used to detect undecorated generators (if a test - method yields it must use a decorator to consume the generator), - but will also detect other kinds of return values (these are not - necessarily errors, but we alert anyway since there is no good - reason to return a value from a test). - """ - - def __init__(self, orig_method: Callable) -> None: - self.orig_method = orig_method - - def __call__(self, *args: Any, **kwargs: Any) -> None: - result = self.orig_method(*args, **kwargs) - if isinstance(result, Generator) or inspect.iscoroutine(result): - raise TypeError( - "Generator and coroutine test methods should be" - " decorated with tornado.testing.gen_test" - ) - elif result is not None: - raise ValueError("Return value from test method ignored: %r" % result) - - def __getattr__(self, name: str) -> Any: - """Proxy all unknown attributes to the original method. - - This is important for some of the decorators in the `unittest` - module, such as `unittest.skipIf`. - """ - return getattr(self.orig_method, name) - - -class AsyncTestCase(unittest.TestCase): - """`~unittest.TestCase` subclass for testing `.IOLoop`-based - asynchronous code. - - The unittest framework is synchronous, so the test must be - complete by the time the test method returns. This means that - asynchronous code cannot be used in quite the same way as usual - and must be adapted to fit. To write your tests with coroutines, - decorate your test methods with `tornado.testing.gen_test` instead - of `tornado.gen.coroutine`. - - This class also provides the (deprecated) `stop()` and `wait()` - methods for a more manual style of testing. The test method itself - must call ``self.wait()``, and asynchronous callbacks should call - ``self.stop()`` to signal completion. - - By default, a new `.IOLoop` is constructed for each test and is available - as ``self.io_loop``. If the code being tested requires a - global `.IOLoop`, subclasses should override `get_new_ioloop` to return it. - - The `.IOLoop`'s ``start`` and ``stop`` methods should not be - called directly. Instead, use `self.stop <stop>` and `self.wait - <wait>`. Arguments passed to ``self.stop`` are returned from - ``self.wait``. It is possible to have multiple ``wait``/``stop`` - cycles in the same test. - - Example:: - - # This test uses coroutine style. - class MyTestCase(AsyncTestCase): - @tornado.testing.gen_test - def test_http_fetch(self): - client = AsyncHTTPClient() - response = yield client.fetch("http://www.tornadoweb.org") - # Test contents of response - self.assertIn("FriendFeed", response.body) - - # This test uses argument passing between self.stop and self.wait. - class MyTestCase2(AsyncTestCase): - def test_http_fetch(self): - client = AsyncHTTPClient() - client.fetch("http://www.tornadoweb.org/", self.stop) - response = self.wait() - # Test contents of response - self.assertIn("FriendFeed", response.body) - """ - - def __init__(self, methodName: str = "runTest") -> None: - super().__init__(methodName) - self.__stopped = False - self.__running = False - self.__failure = None # type: Optional[_ExcInfoTuple] - self.__stop_args = None # type: Any - self.__timeout = None # type: Optional[object] - - # It's easy to forget the @gen_test decorator, but if you do - # the test will silently be ignored because nothing will consume - # the generator. Replace the test method with a wrapper that will - # make sure it's not an undecorated generator. - setattr(self, methodName, _TestMethodWrapper(getattr(self, methodName))) - - # Not used in this class itself, but used by @gen_test - self._test_generator = None # type: Optional[Union[Generator, Coroutine]] - - def setUp(self) -> None: - super().setUp() - self.io_loop = self.get_new_ioloop() - self.io_loop.make_current() - - def tearDown(self) -> None: - # Native coroutines tend to produce warnings if they're not - # allowed to run to completion. It's difficult to ensure that - # this always happens in tests, so cancel any tasks that are - # still pending by the time we get here. - asyncio_loop = self.io_loop.asyncio_loop # type: ignore - if hasattr(asyncio, "all_tasks"): # py37 - tasks = asyncio.all_tasks(asyncio_loop) # type: ignore - else: - tasks = asyncio.Task.all_tasks(asyncio_loop) - # Tasks that are done may still appear here and may contain - # non-cancellation exceptions, so filter them out. - tasks = [t for t in tasks if not t.done()] - for t in tasks: - t.cancel() - # Allow the tasks to run and finalize themselves (which means - # raising a CancelledError inside the coroutine). This may - # just transform the "task was destroyed but it is pending" - # warning into a "uncaught CancelledError" warning, but - # catching CancelledErrors in coroutines that may leak is - # simpler than ensuring that no coroutines leak. - if tasks: - done, pending = self.io_loop.run_sync(lambda: asyncio.wait(tasks)) - assert not pending - # If any task failed with anything but a CancelledError, raise it. - for f in done: - try: - f.result() - except asyncio.CancelledError: - pass - - # Clean up Subprocess, so it can be used again with a new ioloop. - Subprocess.uninitialize() - self.io_loop.clear_current() - if not isinstance(self.io_loop, _NON_OWNED_IOLOOPS): - # Try to clean up any file descriptors left open in the ioloop. - # This avoids leaks, especially when tests are run repeatedly - # in the same process with autoreload (because curl does not - # set FD_CLOEXEC on its file descriptors) - self.io_loop.close(all_fds=True) - super().tearDown() - # In case an exception escaped or the StackContext caught an exception - # when there wasn't a wait() to re-raise it, do so here. - # This is our last chance to raise an exception in a way that the - # unittest machinery understands. - self.__rethrow() - - def get_new_ioloop(self) -> IOLoop: - """Returns the `.IOLoop` to use for this test. - - By default, a new `.IOLoop` is created for each test. - Subclasses may override this method to return - `.IOLoop.current()` if it is not appropriate to use a new - `.IOLoop` in each tests (for example, if there are global - singletons using the default `.IOLoop`) or if a per-test event - loop is being provided by another system (such as - ``pytest-asyncio``). - """ - return IOLoop() - - def _handle_exception( - self, typ: Type[Exception], value: Exception, tb: TracebackType - ) -> bool: - if self.__failure is None: - self.__failure = (typ, value, tb) - else: - app_log.error( - "multiple unhandled exceptions in test", exc_info=(typ, value, tb) - ) - self.stop() - return True - - def __rethrow(self) -> None: - if self.__failure is not None: - failure = self.__failure - self.__failure = None - raise_exc_info(failure) - - def run( - self, result: Optional[unittest.TestResult] = None - ) -> Optional[unittest.TestResult]: - ret = super().run(result) - # As a last resort, if an exception escaped super.run() and wasn't - # re-raised in tearDown, raise it here. This will cause the - # unittest run to fail messily, but that's better than silently - # ignoring an error. - self.__rethrow() - return ret - - def stop(self, _arg: Any = None, **kwargs: Any) -> None: - """Stops the `.IOLoop`, causing one pending (or future) call to `wait()` - to return. - - Keyword arguments or a single positional argument passed to `stop()` are - saved and will be returned by `wait()`. - - .. deprecated:: 5.1 - - `stop` and `wait` are deprecated; use ``@gen_test`` instead. - """ - assert _arg is None or not kwargs - self.__stop_args = kwargs or _arg - if self.__running: - self.io_loop.stop() - self.__running = False - self.__stopped = True - - def wait( - self, - condition: Optional[Callable[..., bool]] = None, - timeout: Optional[float] = None, - ) -> Any: - """Runs the `.IOLoop` until stop is called or timeout has passed. - - In the event of a timeout, an exception will be thrown. The - default timeout is 5 seconds; it may be overridden with a - ``timeout`` keyword argument or globally with the - ``ASYNC_TEST_TIMEOUT`` environment variable. - - If ``condition`` is not ``None``, the `.IOLoop` will be restarted - after `stop()` until ``condition()`` returns ``True``. - - .. versionchanged:: 3.1 - Added the ``ASYNC_TEST_TIMEOUT`` environment variable. - - .. deprecated:: 5.1 - - `stop` and `wait` are deprecated; use ``@gen_test`` instead. - """ - if timeout is None: - timeout = get_async_test_timeout() - - if not self.__stopped: - if timeout: - - def timeout_func() -> None: - try: - raise self.failureException( - "Async operation timed out after %s seconds" % timeout - ) - except Exception: - self.__failure = sys.exc_info() - self.stop() - - self.__timeout = self.io_loop.add_timeout( - self.io_loop.time() + timeout, timeout_func - ) - while True: - self.__running = True - self.io_loop.start() - if self.__failure is not None or condition is None or condition(): - break - if self.__timeout is not None: - self.io_loop.remove_timeout(self.__timeout) - self.__timeout = None - assert self.__stopped - self.__stopped = False - self.__rethrow() - result = self.__stop_args - self.__stop_args = None - return result - - -class AsyncHTTPTestCase(AsyncTestCase): - """A test case that starts up an HTTP server. - - Subclasses must override `get_app()`, which returns the - `tornado.web.Application` (or other `.HTTPServer` callback) to be tested. - Tests will typically use the provided ``self.http_client`` to fetch - URLs from this server. - - Example, assuming the "Hello, world" example from the user guide is in - ``hello.py``:: - - import hello - - class TestHelloApp(AsyncHTTPTestCase): - def get_app(self): - return hello.make_app() - - def test_homepage(self): - response = self.fetch('/') - self.assertEqual(response.code, 200) - self.assertEqual(response.body, 'Hello, world') - - That call to ``self.fetch()`` is equivalent to :: - - self.http_client.fetch(self.get_url('/'), self.stop) - response = self.wait() - - which illustrates how AsyncTestCase can turn an asynchronous operation, - like ``http_client.fetch()``, into a synchronous operation. If you need - to do other asynchronous operations in tests, you'll probably need to use - ``stop()`` and ``wait()`` yourself. - """ - - def setUp(self) -> None: - super().setUp() - sock, port = bind_unused_port() - self.__port = port - - self.http_client = self.get_http_client() - self._app = self.get_app() - self.http_server = self.get_http_server() - self.http_server.add_sockets([sock]) - - def get_http_client(self) -> AsyncHTTPClient: - return AsyncHTTPClient() - - def get_http_server(self) -> HTTPServer: - return HTTPServer(self._app, **self.get_httpserver_options()) - - def get_app(self) -> Application: - """Should be overridden by subclasses to return a - `tornado.web.Application` or other `.HTTPServer` callback. - """ - raise NotImplementedError() - - def fetch( - self, path: str, raise_error: bool = False, **kwargs: Any - ) -> HTTPResponse: - """Convenience method to synchronously fetch a URL. - - The given path will be appended to the local server's host and - port. Any additional keyword arguments will be passed directly to - `.AsyncHTTPClient.fetch` (and so could be used to pass - ``method="POST"``, ``body="..."``, etc). - - If the path begins with http:// or https://, it will be treated as a - full URL and will be fetched as-is. - - If ``raise_error`` is ``True``, a `tornado.httpclient.HTTPError` will - be raised if the response code is not 200. This is the same behavior - as the ``raise_error`` argument to `.AsyncHTTPClient.fetch`, but - the default is ``False`` here (it's ``True`` in `.AsyncHTTPClient`) - because tests often need to deal with non-200 response codes. - - .. versionchanged:: 5.0 - Added support for absolute URLs. - - .. versionchanged:: 5.1 - - Added the ``raise_error`` argument. - - .. deprecated:: 5.1 - - This method currently turns any exception into an - `.HTTPResponse` with status code 599. In Tornado 6.0, - errors other than `tornado.httpclient.HTTPError` will be - passed through, and ``raise_error=False`` will only - suppress errors that would be raised due to non-200 - response codes. - - """ - if path.lower().startswith(("http://", "https://")): - url = path - else: - url = self.get_url(path) - return self.io_loop.run_sync( - lambda: self.http_client.fetch(url, raise_error=raise_error, **kwargs), - timeout=get_async_test_timeout(), - ) - - def get_httpserver_options(self) -> Dict[str, Any]: - """May be overridden by subclasses to return additional - keyword arguments for the server. - """ - return {} - - def get_http_port(self) -> int: - """Returns the port used by the server. - - A new port is chosen for each test. - """ - return self.__port - - def get_protocol(self) -> str: - return "http" - - def get_url(self, path: str) -> str: - """Returns an absolute url for the given path on the test server.""" - return "%s://127.0.0.1:%s%s" % (self.get_protocol(), self.get_http_port(), path) - - def tearDown(self) -> None: - self.http_server.stop() - self.io_loop.run_sync( - self.http_server.close_all_connections, timeout=get_async_test_timeout() - ) - self.http_client.close() - del self.http_server - del self._app - super().tearDown() - - -class AsyncHTTPSTestCase(AsyncHTTPTestCase): - """A test case that starts an HTTPS server. - - Interface is generally the same as `AsyncHTTPTestCase`. - """ - - def get_http_client(self) -> AsyncHTTPClient: - return AsyncHTTPClient(force_instance=True, defaults=dict(validate_cert=False)) - - def get_httpserver_options(self) -> Dict[str, Any]: - return dict(ssl_options=self.get_ssl_options()) - - def get_ssl_options(self) -> Dict[str, Any]: - """May be overridden by subclasses to select SSL options. - - By default includes a self-signed testing certificate. - """ - return AsyncHTTPSTestCase.default_ssl_options() - - @staticmethod - def default_ssl_options() -> Dict[str, Any]: - # Testing keys were generated with: - # openssl req -new -keyout tornado/test/test.key \ - # -out tornado/test/test.crt -nodes -days 3650 -x509 - module_dir = os.path.dirname(__file__) - return dict( - certfile=os.path.join(module_dir, "test", "test.crt"), - keyfile=os.path.join(module_dir, "test", "test.key"), - ) - - def get_protocol(self) -> str: - return "https" - - -@typing.overload -def gen_test( - *, timeout: Optional[float] = None -) -> Callable[[Callable[..., Union[Generator, "Coroutine"]]], Callable[..., None]]: - pass - - -@typing.overload # noqa: F811 -def gen_test(func: Callable[..., Union[Generator, "Coroutine"]]) -> Callable[..., None]: - pass - - -def gen_test( # noqa: F811 - func: Optional[Callable[..., Union[Generator, "Coroutine"]]] = None, - timeout: Optional[float] = None, -) -> Union[ - Callable[..., None], - Callable[[Callable[..., Union[Generator, "Coroutine"]]], Callable[..., None]], -]: - """Testing equivalent of ``@gen.coroutine``, to be applied to test methods. - - ``@gen.coroutine`` cannot be used on tests because the `.IOLoop` is not - already running. ``@gen_test`` should be applied to test methods - on subclasses of `AsyncTestCase`. - - Example:: - - class MyTest(AsyncHTTPTestCase): - @gen_test - def test_something(self): - response = yield self.http_client.fetch(self.get_url('/')) - - By default, ``@gen_test`` times out after 5 seconds. The timeout may be - overridden globally with the ``ASYNC_TEST_TIMEOUT`` environment variable, - or for each test with the ``timeout`` keyword argument:: - - class MyTest(AsyncHTTPTestCase): - @gen_test(timeout=10) - def test_something_slow(self): - response = yield self.http_client.fetch(self.get_url('/')) - - Note that ``@gen_test`` is incompatible with `AsyncTestCase.stop`, - `AsyncTestCase.wait`, and `AsyncHTTPTestCase.fetch`. Use ``yield - self.http_client.fetch(self.get_url())`` as shown above instead. - - .. versionadded:: 3.1 - The ``timeout`` argument and ``ASYNC_TEST_TIMEOUT`` environment - variable. - - .. versionchanged:: 4.0 - The wrapper now passes along ``*args, **kwargs`` so it can be used - on functions with arguments. - - """ - if timeout is None: - timeout = get_async_test_timeout() - - def wrap(f: Callable[..., Union[Generator, "Coroutine"]]) -> Callable[..., None]: - # Stack up several decorators to allow us to access the generator - # object itself. In the innermost wrapper, we capture the generator - # and save it in an attribute of self. Next, we run the wrapped - # function through @gen.coroutine. Finally, the coroutine is - # wrapped again to make it synchronous with run_sync. - # - # This is a good case study arguing for either some sort of - # extensibility in the gen decorators or cancellation support. - @functools.wraps(f) - def pre_coroutine(self, *args, **kwargs): - # type: (AsyncTestCase, *Any, **Any) -> Union[Generator, Coroutine] - # Type comments used to avoid pypy3 bug. - result = f(self, *args, **kwargs) - if isinstance(result, Generator) or inspect.iscoroutine(result): - self._test_generator = result - else: - self._test_generator = None - return result - - if inspect.iscoroutinefunction(f): - coro = pre_coroutine - else: - coro = gen.coroutine(pre_coroutine) - - @functools.wraps(coro) - def post_coroutine(self, *args, **kwargs): - # type: (AsyncTestCase, *Any, **Any) -> None - try: - return self.io_loop.run_sync( - functools.partial(coro, self, *args, **kwargs), timeout=timeout - ) - except TimeoutError as e: - # run_sync raises an error with an unhelpful traceback. - # If the underlying generator is still running, we can throw the - # exception back into it so the stack trace is replaced by the - # point where the test is stopped. The only reason the generator - # would not be running would be if it were cancelled, which means - # a native coroutine, so we can rely on the cr_running attribute. - if self._test_generator is not None and getattr( - self._test_generator, "cr_running", True - ): - self._test_generator.throw(type(e), e) - # In case the test contains an overly broad except - # clause, we may get back here. - # Coroutine was stopped or didn't raise a useful stack trace, - # so re-raise the original exception which is better than nothing. - raise - - return post_coroutine - - if func is not None: - # Used like: - # @gen_test - # def f(self): - # pass - return wrap(func) - else: - # Used like @gen_test(timeout=10) - return wrap - - -# Without this attribute, nosetests will try to run gen_test as a test -# anywhere it is imported. -gen_test.__test__ = False # type: ignore - - -class ExpectLog(logging.Filter): - """Context manager to capture and suppress expected log output. - - Useful to make tests of error conditions less noisy, while still - leaving unexpected log entries visible. *Not thread safe.* - - The attribute ``logged_stack`` is set to ``True`` if any exception - stack trace was logged. - - Usage:: - - with ExpectLog('tornado.application', "Uncaught exception"): - error_response = self.fetch("/some_page") - - .. versionchanged:: 4.3 - Added the ``logged_stack`` attribute. - """ - - def __init__( - self, - logger: Union[logging.Logger, basestring_type], - regex: str, - required: bool = True, - level: Optional[int] = None, - ) -> None: - """Constructs an ExpectLog context manager. - - :param logger: Logger object (or name of logger) to watch. Pass - an empty string to watch the root logger. - :param regex: Regular expression to match. Any log entries on - the specified logger that match this regex will be suppressed. - :param required: If true, an exception will be raised if the end of - the ``with`` statement is reached without matching any log entries. - :param level: A constant from the ``logging`` module indicating the - expected log level. If this parameter is provided, only log messages - at this level will be considered to match. Additionally, the - supplied ``logger`` will have its level adjusted if necessary - (for the duration of the ``ExpectLog`` to enable the expected - message. - - .. versionchanged:: 6.1 - Added the ``level`` parameter. - """ - if isinstance(logger, basestring_type): - logger = logging.getLogger(logger) - self.logger = logger - self.regex = re.compile(regex) - self.required = required - self.matched = False - self.logged_stack = False - self.level = level - self.orig_level = None # type: Optional[int] - - def filter(self, record: logging.LogRecord) -> bool: - if record.exc_info: - self.logged_stack = True - message = record.getMessage() - if self.regex.match(message): - if self.level is not None and record.levelno != self.level: - app_log.warning( - "Got expected log message %r at unexpected level (%s vs %s)" - % (message, logging.getLevelName(self.level), record.levelname) - ) - return True - self.matched = True - return False - return True - - def __enter__(self) -> "ExpectLog": - if self.level is not None and self.level < self.logger.getEffectiveLevel(): - self.orig_level = self.logger.level - self.logger.setLevel(self.level) - self.logger.addFilter(self) - return self - - def __exit__( - self, - typ: "Optional[Type[BaseException]]", - value: Optional[BaseException], - tb: Optional[TracebackType], - ) -> None: - if self.orig_level is not None: - self.logger.setLevel(self.orig_level) - self.logger.removeFilter(self) - if not typ and self.required and not self.matched: - raise Exception("did not get expected log message") - - -def main(**kwargs: Any) -> None: - """A simple test runner. - - This test runner is essentially equivalent to `unittest.main` from - the standard library, but adds support for Tornado-style option - parsing and log formatting. It is *not* necessary to use this - `main` function to run tests using `AsyncTestCase`; these tests - are self-contained and can run with any test runner. - - The easiest way to run a test is via the command line:: - - python -m tornado.testing tornado.test.web_test - - See the standard library ``unittest`` module for ways in which - tests can be specified. - - Projects with many tests may wish to define a test script like - ``tornado/test/runtests.py``. This script should define a method - ``all()`` which returns a test suite and then call - `tornado.testing.main()`. Note that even when a test script is - used, the ``all()`` test suite may be overridden by naming a - single test on the command line:: - - # Runs all tests - python -m tornado.test.runtests - # Runs one test - python -m tornado.test.runtests tornado.test.web_test - - Additional keyword arguments passed through to ``unittest.main()``. - For example, use ``tornado.testing.main(verbosity=2)`` - to show many test details as they are run. - See http://docs.python.org/library/unittest.html#unittest.main - for full argument list. - - .. versionchanged:: 5.0 - - This function produces no output of its own; only that produced - by the `unittest` module (previously it would add a PASS or FAIL - log message). - """ - from tornado.options import define, options, parse_command_line - - define( - "exception_on_interrupt", - type=bool, - default=True, - help=( - "If true (default), ctrl-c raises a KeyboardInterrupt " - "exception. This prints a stack trace but cannot interrupt " - "certain operations. If false, the process is more reliably " - "killed, but does not print a stack trace." - ), - ) - - # support the same options as unittest's command-line interface - define("verbose", type=bool) - define("quiet", type=bool) - define("failfast", type=bool) - define("catch", type=bool) - define("buffer", type=bool) - - argv = [sys.argv[0]] + parse_command_line(sys.argv) - - if not options.exception_on_interrupt: - signal.signal(signal.SIGINT, signal.SIG_DFL) - - if options.verbose is not None: - kwargs["verbosity"] = 2 - if options.quiet is not None: - kwargs["verbosity"] = 0 - if options.failfast is not None: - kwargs["failfast"] = True - if options.catch is not None: - kwargs["catchbreak"] = True - if options.buffer is not None: - kwargs["buffer"] = True - - if __name__ == "__main__" and len(argv) == 1: - print("No tests specified", file=sys.stderr) - sys.exit(1) - # In order to be able to run tests by their fully-qualified name - # on the command line without importing all tests here, - # module must be set to None. Python 3.2's unittest.main ignores - # defaultTest if no module is given (it tries to do its own - # test discovery, which is incompatible with auto2to3), so don't - # set module if we're not asking for a specific test. - if len(argv) > 1: - unittest.main(module=None, argv=argv, **kwargs) # type: ignore - else: - unittest.main(defaultTest="all", argv=argv, **kwargs) - - -if __name__ == "__main__": - main() diff --git a/venv/lib/python3.8/site-packages/tornado/util.py b/venv/lib/python3.8/site-packages/tornado/util.py deleted file mode 100644 index 77c5f94..0000000 --- a/venv/lib/python3.8/site-packages/tornado/util.py +++ /dev/null @@ -1,474 +0,0 @@ -"""Miscellaneous utility functions and classes. - -This module is used internally by Tornado. It is not necessarily expected -that the functions and classes defined here will be useful to other -applications, but they are documented here in case they are. - -The one public-facing part of this module is the `Configurable` class -and its `~Configurable.configure` method, which becomes a part of the -interface of its subclasses, including `.AsyncHTTPClient`, `.IOLoop`, -and `.Resolver`. -""" - -import array -import atexit -from inspect import getfullargspec -import os -import re -import typing -import zlib - -from typing import ( - Any, - Optional, - Dict, - Mapping, - List, - Tuple, - Match, - Callable, - Type, - Sequence, -) - -if typing.TYPE_CHECKING: - # Additional imports only used in type comments. - # This lets us make these imports lazy. - import datetime # noqa: F401 - from types import TracebackType # noqa: F401 - from typing import Union # noqa: F401 - import unittest # noqa: F401 - -# Aliases for types that are spelled differently in different Python -# versions. bytes_type is deprecated and no longer used in Tornado -# itself but is left in case anyone outside Tornado is using it. -bytes_type = bytes -unicode_type = str -basestring_type = str - -try: - from sys import is_finalizing -except ImportError: - # Emulate it - def _get_emulated_is_finalizing() -> Callable[[], bool]: - L = [] # type: List[None] - atexit.register(lambda: L.append(None)) - - def is_finalizing() -> bool: - # Not referencing any globals here - return L != [] - - return is_finalizing - - is_finalizing = _get_emulated_is_finalizing() - - -class TimeoutError(Exception): - """Exception raised by `.with_timeout` and `.IOLoop.run_sync`. - - .. versionchanged:: 5.0: - Unified ``tornado.gen.TimeoutError`` and - ``tornado.ioloop.TimeoutError`` as ``tornado.util.TimeoutError``. - Both former names remain as aliases. - """ - - -class ObjectDict(Dict[str, Any]): - """Makes a dictionary behave like an object, with attribute-style access. - """ - - def __getattr__(self, name: str) -> Any: - try: - return self[name] - except KeyError: - raise AttributeError(name) - - def __setattr__(self, name: str, value: Any) -> None: - self[name] = value - - -class GzipDecompressor(object): - """Streaming gzip decompressor. - - The interface is like that of `zlib.decompressobj` (without some of the - optional arguments, but it understands gzip headers and checksums. - """ - - def __init__(self) -> None: - # Magic parameter makes zlib module understand gzip header - # http://stackoverflow.com/questions/1838699/how-can-i-decompress-a-gzip-stream-with-zlib - # This works on cpython and pypy, but not jython. - self.decompressobj = zlib.decompressobj(16 + zlib.MAX_WBITS) - - def decompress(self, value: bytes, max_length: int = 0) -> bytes: - """Decompress a chunk, returning newly-available data. - - Some data may be buffered for later processing; `flush` must - be called when there is no more input data to ensure that - all data was processed. - - If ``max_length`` is given, some input data may be left over - in ``unconsumed_tail``; you must retrieve this value and pass - it back to a future call to `decompress` if it is not empty. - """ - return self.decompressobj.decompress(value, max_length) - - @property - def unconsumed_tail(self) -> bytes: - """Returns the unconsumed portion left over - """ - return self.decompressobj.unconsumed_tail - - def flush(self) -> bytes: - """Return any remaining buffered data not yet returned by decompress. - - Also checks for errors such as truncated input. - No other methods may be called on this object after `flush`. - """ - return self.decompressobj.flush() - - -def import_object(name: str) -> Any: - """Imports an object by name. - - ``import_object('x')`` is equivalent to ``import x``. - ``import_object('x.y.z')`` is equivalent to ``from x.y import z``. - - >>> import tornado.escape - >>> import_object('tornado.escape') is tornado.escape - True - >>> import_object('tornado.escape.utf8') is tornado.escape.utf8 - True - >>> import_object('tornado') is tornado - True - >>> import_object('tornado.missing_module') - Traceback (most recent call last): - ... - ImportError: No module named missing_module - """ - if name.count(".") == 0: - return __import__(name) - - parts = name.split(".") - obj = __import__(".".join(parts[:-1]), fromlist=[parts[-1]]) - try: - return getattr(obj, parts[-1]) - except AttributeError: - raise ImportError("No module named %s" % parts[-1]) - - -def exec_in( - code: Any, glob: Dict[str, Any], loc: Optional[Optional[Mapping[str, Any]]] = None -) -> None: - if isinstance(code, str): - # exec(string) inherits the caller's future imports; compile - # the string first to prevent that. - code = compile(code, "<string>", "exec", dont_inherit=True) - exec(code, glob, loc) - - -def raise_exc_info( - exc_info, # type: Tuple[Optional[type], Optional[BaseException], Optional[TracebackType]] -): - # type: (...) -> typing.NoReturn - # - # This function's type annotation must use comments instead of - # real annotations because typing.NoReturn does not exist in - # python 3.5's typing module. The formatting is funky because this - # is apparently what flake8 wants. - try: - if exc_info[1] is not None: - raise exc_info[1].with_traceback(exc_info[2]) - else: - raise TypeError("raise_exc_info called with no exception") - finally: - # Clear the traceback reference from our stack frame to - # minimize circular references that slow down GC. - exc_info = (None, None, None) - - -def errno_from_exception(e: BaseException) -> Optional[int]: - """Provides the errno from an Exception object. - - There are cases that the errno attribute was not set so we pull - the errno out of the args but if someone instantiates an Exception - without any args you will get a tuple error. So this function - abstracts all that behavior to give you a safe way to get the - errno. - """ - - if hasattr(e, "errno"): - return e.errno # type: ignore - elif e.args: - return e.args[0] - else: - return None - - -_alphanum = frozenset("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") - - -def _re_unescape_replacement(match: Match[str]) -> str: - group = match.group(1) - if group[0] in _alphanum: - raise ValueError("cannot unescape '\\\\%s'" % group[0]) - return group - - -_re_unescape_pattern = re.compile(r"\\(.)", re.DOTALL) - - -def re_unescape(s: str) -> str: - r"""Unescape a string escaped by `re.escape`. - - May raise ``ValueError`` for regular expressions which could not - have been produced by `re.escape` (for example, strings containing - ``\d`` cannot be unescaped). - - .. versionadded:: 4.4 - """ - return _re_unescape_pattern.sub(_re_unescape_replacement, s) - - -class Configurable(object): - """Base class for configurable interfaces. - - A configurable interface is an (abstract) class whose constructor - acts as a factory function for one of its implementation subclasses. - The implementation subclass as well as optional keyword arguments to - its initializer can be set globally at runtime with `configure`. - - By using the constructor as the factory method, the interface - looks like a normal class, `isinstance` works as usual, etc. This - pattern is most useful when the choice of implementation is likely - to be a global decision (e.g. when `~select.epoll` is available, - always use it instead of `~select.select`), or when a - previously-monolithic class has been split into specialized - subclasses. - - Configurable subclasses must define the class methods - `configurable_base` and `configurable_default`, and use the instance - method `initialize` instead of ``__init__``. - - .. versionchanged:: 5.0 - - It is now possible for configuration to be specified at - multiple levels of a class hierarchy. - - """ - - # Type annotations on this class are mostly done with comments - # because they need to refer to Configurable, which isn't defined - # until after the class definition block. These can use regular - # annotations when our minimum python version is 3.7. - # - # There may be a clever way to use generics here to get more - # precise types (i.e. for a particular Configurable subclass T, - # all the types are subclasses of T, not just Configurable). - __impl_class = None # type: Optional[Type[Configurable]] - __impl_kwargs = None # type: Dict[str, Any] - - def __new__(cls, *args: Any, **kwargs: Any) -> Any: - base = cls.configurable_base() - init_kwargs = {} # type: Dict[str, Any] - if cls is base: - impl = cls.configured_class() - if base.__impl_kwargs: - init_kwargs.update(base.__impl_kwargs) - else: - impl = cls - init_kwargs.update(kwargs) - if impl.configurable_base() is not base: - # The impl class is itself configurable, so recurse. - return impl(*args, **init_kwargs) - instance = super(Configurable, cls).__new__(impl) - # initialize vs __init__ chosen for compatibility with AsyncHTTPClient - # singleton magic. If we get rid of that we can switch to __init__ - # here too. - instance.initialize(*args, **init_kwargs) - return instance - - @classmethod - def configurable_base(cls): - # type: () -> Type[Configurable] - """Returns the base class of a configurable hierarchy. - - This will normally return the class in which it is defined. - (which is *not* necessarily the same as the ``cls`` classmethod - parameter). - - """ - raise NotImplementedError() - - @classmethod - def configurable_default(cls): - # type: () -> Type[Configurable] - """Returns the implementation class to be used if none is configured.""" - raise NotImplementedError() - - def _initialize(self) -> None: - pass - - initialize = _initialize # type: Callable[..., None] - """Initialize a `Configurable` subclass instance. - - Configurable classes should use `initialize` instead of ``__init__``. - - .. versionchanged:: 4.2 - Now accepts positional arguments in addition to keyword arguments. - """ - - @classmethod - def configure(cls, impl, **kwargs): - # type: (Union[None, str, Type[Configurable]], Any) -> None - """Sets the class to use when the base class is instantiated. - - Keyword arguments will be saved and added to the arguments passed - to the constructor. This can be used to set global defaults for - some parameters. - """ - base = cls.configurable_base() - if isinstance(impl, str): - impl = typing.cast(Type[Configurable], import_object(impl)) - if impl is not None and not issubclass(impl, cls): - raise ValueError("Invalid subclass of %s" % cls) - base.__impl_class = impl - base.__impl_kwargs = kwargs - - @classmethod - def configured_class(cls): - # type: () -> Type[Configurable] - """Returns the currently configured class.""" - base = cls.configurable_base() - # Manually mangle the private name to see whether this base - # has been configured (and not another base higher in the - # hierarchy). - if base.__dict__.get("_Configurable__impl_class") is None: - base.__impl_class = cls.configurable_default() - if base.__impl_class is not None: - return base.__impl_class - else: - # Should be impossible, but mypy wants an explicit check. - raise ValueError("configured class not found") - - @classmethod - def _save_configuration(cls): - # type: () -> Tuple[Optional[Type[Configurable]], Dict[str, Any]] - base = cls.configurable_base() - return (base.__impl_class, base.__impl_kwargs) - - @classmethod - def _restore_configuration(cls, saved): - # type: (Tuple[Optional[Type[Configurable]], Dict[str, Any]]) -> None - base = cls.configurable_base() - base.__impl_class = saved[0] - base.__impl_kwargs = saved[1] - - -class ArgReplacer(object): - """Replaces one value in an ``args, kwargs`` pair. - - Inspects the function signature to find an argument by name - whether it is passed by position or keyword. For use in decorators - and similar wrappers. - """ - - def __init__(self, func: Callable, name: str) -> None: - self.name = name - try: - self.arg_pos = self._getargnames(func).index(name) # type: Optional[int] - except ValueError: - # Not a positional parameter - self.arg_pos = None - - def _getargnames(self, func: Callable) -> List[str]: - try: - return getfullargspec(func).args - except TypeError: - if hasattr(func, "func_code"): - # Cython-generated code has all the attributes needed - # by inspect.getfullargspec, but the inspect module only - # works with ordinary functions. Inline the portion of - # getfullargspec that we need here. Note that for static - # functions the @cython.binding(True) decorator must - # be used (for methods it works out of the box). - code = func.func_code # type: ignore - return code.co_varnames[: code.co_argcount] - raise - - def get_old_value( - self, args: Sequence[Any], kwargs: Dict[str, Any], default: Any = None - ) -> Any: - """Returns the old value of the named argument without replacing it. - - Returns ``default`` if the argument is not present. - """ - if self.arg_pos is not None and len(args) > self.arg_pos: - return args[self.arg_pos] - else: - return kwargs.get(self.name, default) - - def replace( - self, new_value: Any, args: Sequence[Any], kwargs: Dict[str, Any] - ) -> Tuple[Any, Sequence[Any], Dict[str, Any]]: - """Replace the named argument in ``args, kwargs`` with ``new_value``. - - Returns ``(old_value, args, kwargs)``. The returned ``args`` and - ``kwargs`` objects may not be the same as the input objects, or - the input objects may be mutated. - - If the named argument was not found, ``new_value`` will be added - to ``kwargs`` and None will be returned as ``old_value``. - """ - if self.arg_pos is not None and len(args) > self.arg_pos: - # The arg to replace is passed positionally - old_value = args[self.arg_pos] - args = list(args) # *args is normally a tuple - args[self.arg_pos] = new_value - else: - # The arg to replace is either omitted or passed by keyword. - old_value = kwargs.get(self.name) - kwargs[self.name] = new_value - return old_value, args, kwargs - - -def timedelta_to_seconds(td): - # type: (datetime.timedelta) -> float - """Equivalent to ``td.total_seconds()`` (introduced in Python 2.7).""" - return td.total_seconds() - - -def _websocket_mask_python(mask: bytes, data: bytes) -> bytes: - """Websocket masking function. - - `mask` is a `bytes` object of length 4; `data` is a `bytes` object of any length. - Returns a `bytes` object of the same length as `data` with the mask applied - as specified in section 5.3 of RFC 6455. - - This pure-python implementation may be replaced by an optimized version when available. - """ - mask_arr = array.array("B", mask) - unmasked_arr = array.array("B", data) - for i in range(len(data)): - unmasked_arr[i] = unmasked_arr[i] ^ mask_arr[i % 4] - return unmasked_arr.tobytes() - - -if os.environ.get("TORNADO_NO_EXTENSION") or os.environ.get("TORNADO_EXTENSION") == "0": - # These environment variables exist to make it easier to do performance - # comparisons; they are not guaranteed to remain supported in the future. - _websocket_mask = _websocket_mask_python -else: - try: - from tornado.speedups import websocket_mask as _websocket_mask - except ImportError: - if os.environ.get("TORNADO_EXTENSION") == "1": - raise - _websocket_mask = _websocket_mask_python - - -def doctests(): - # type: () -> unittest.TestSuite - import doctest - - return doctest.DocTestSuite() diff --git a/venv/lib/python3.8/site-packages/tornado/web.py b/venv/lib/python3.8/site-packages/tornado/web.py deleted file mode 100644 index 546e6ec..0000000 --- a/venv/lib/python3.8/site-packages/tornado/web.py +++ /dev/null @@ -1,3588 +0,0 @@ -# -# Copyright 2009 Facebook -# -# 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. - -"""``tornado.web`` provides a simple web framework with asynchronous -features that allow it to scale to large numbers of open connections, -making it ideal for `long polling -<http://en.wikipedia.org/wiki/Push_technology#Long_polling>`_. - -Here is a simple "Hello, world" example app: - -.. testcode:: - - import tornado.ioloop - import tornado.web - - class MainHandler(tornado.web.RequestHandler): - def get(self): - self.write("Hello, world") - - if __name__ == "__main__": - application = tornado.web.Application([ - (r"/", MainHandler), - ]) - application.listen(8888) - tornado.ioloop.IOLoop.current().start() - -.. testoutput:: - :hide: - - -See the :doc:`guide` for additional information. - -Thread-safety notes -------------------- - -In general, methods on `RequestHandler` and elsewhere in Tornado are -not thread-safe. In particular, methods such as -`~RequestHandler.write()`, `~RequestHandler.finish()`, and -`~RequestHandler.flush()` must only be called from the main thread. If -you use multiple threads it is important to use `.IOLoop.add_callback` -to transfer control back to the main thread before finishing the -request, or to limit your use of other threads to -`.IOLoop.run_in_executor` and ensure that your callbacks running in -the executor do not refer to Tornado objects. - -""" - -import base64 -import binascii -import datetime -import email.utils -import functools -import gzip -import hashlib -import hmac -import http.cookies -from inspect import isclass -from io import BytesIO -import mimetypes -import numbers -import os.path -import re -import sys -import threading -import time -import tornado -import traceback -import types -import urllib.parse -from urllib.parse import urlencode - -from tornado.concurrent import Future, future_set_result_unless_cancelled -from tornado import escape -from tornado import gen -from tornado.httpserver import HTTPServer -from tornado import httputil -from tornado import iostream -import tornado.locale -from tornado import locale -from tornado.log import access_log, app_log, gen_log -from tornado import template -from tornado.escape import utf8, _unicode -from tornado.routing import ( - AnyMatches, - DefaultHostMatches, - HostMatches, - ReversibleRouter, - Rule, - ReversibleRuleRouter, - URLSpec, - _RuleList, -) -from tornado.util import ObjectDict, unicode_type, _websocket_mask - -url = URLSpec - -from typing import ( - Dict, - Any, - Union, - Optional, - Awaitable, - Tuple, - List, - Callable, - Iterable, - Generator, - Type, - cast, - overload, -) -from types import TracebackType -import typing - -if typing.TYPE_CHECKING: - from typing import Set # noqa: F401 - - -# The following types are accepted by RequestHandler.set_header -# and related methods. -_HeaderTypes = Union[bytes, unicode_type, int, numbers.Integral, datetime.datetime] - -_CookieSecretTypes = Union[str, bytes, Dict[int, str], Dict[int, bytes]] - - -MIN_SUPPORTED_SIGNED_VALUE_VERSION = 1 -"""The oldest signed value version supported by this version of Tornado. - -Signed values older than this version cannot be decoded. - -.. versionadded:: 3.2.1 -""" - -MAX_SUPPORTED_SIGNED_VALUE_VERSION = 2 -"""The newest signed value version supported by this version of Tornado. - -Signed values newer than this version cannot be decoded. - -.. versionadded:: 3.2.1 -""" - -DEFAULT_SIGNED_VALUE_VERSION = 2 -"""The signed value version produced by `.RequestHandler.create_signed_value`. - -May be overridden by passing a ``version`` keyword argument. - -.. versionadded:: 3.2.1 -""" - -DEFAULT_SIGNED_VALUE_MIN_VERSION = 1 -"""The oldest signed value accepted by `.RequestHandler.get_secure_cookie`. - -May be overridden by passing a ``min_version`` keyword argument. - -.. versionadded:: 3.2.1 -""" - - -class _ArgDefaultMarker: - pass - - -_ARG_DEFAULT = _ArgDefaultMarker() - - -class RequestHandler(object): - """Base class for HTTP request handlers. - - Subclasses must define at least one of the methods defined in the - "Entry points" section below. - - Applications should not construct `RequestHandler` objects - directly and subclasses should not override ``__init__`` (override - `~RequestHandler.initialize` instead). - - """ - - SUPPORTED_METHODS = ("GET", "HEAD", "POST", "DELETE", "PATCH", "PUT", "OPTIONS") - - _template_loaders = {} # type: Dict[str, template.BaseLoader] - _template_loader_lock = threading.Lock() - _remove_control_chars_regex = re.compile(r"[\x00-\x08\x0e-\x1f]") - - _stream_request_body = False - - # Will be set in _execute. - _transforms = None # type: List[OutputTransform] - path_args = None # type: List[str] - path_kwargs = None # type: Dict[str, str] - - def __init__( - self, - application: "Application", - request: httputil.HTTPServerRequest, - **kwargs: Any - ) -> None: - super().__init__() - - self.application = application - self.request = request - self._headers_written = False - self._finished = False - self._auto_finish = True - self._prepared_future = None - self.ui = ObjectDict( - (n, self._ui_method(m)) for n, m in application.ui_methods.items() - ) - # UIModules are available as both `modules` and `_tt_modules` in the - # template namespace. Historically only `modules` was available - # but could be clobbered by user additions to the namespace. - # The template {% module %} directive looks in `_tt_modules` to avoid - # possible conflicts. - self.ui["_tt_modules"] = _UIModuleNamespace(self, application.ui_modules) - self.ui["modules"] = self.ui["_tt_modules"] - self.clear() - assert self.request.connection is not None - # TODO: need to add set_close_callback to HTTPConnection interface - self.request.connection.set_close_callback( # type: ignore - self.on_connection_close - ) - self.initialize(**kwargs) # type: ignore - - def _initialize(self) -> None: - pass - - initialize = _initialize # type: Callable[..., None] - """Hook for subclass initialization. Called for each request. - - A dictionary passed as the third argument of a ``URLSpec`` will be - supplied as keyword arguments to ``initialize()``. - - Example:: - - class ProfileHandler(RequestHandler): - def initialize(self, database): - self.database = database - - def get(self, username): - ... - - app = Application([ - (r'/user/(.*)', ProfileHandler, dict(database=database)), - ]) - """ - - @property - def settings(self) -> Dict[str, Any]: - """An alias for `self.application.settings <Application.settings>`.""" - return self.application.settings - - def _unimplemented_method(self, *args: str, **kwargs: str) -> None: - raise HTTPError(405) - - head = _unimplemented_method # type: Callable[..., Optional[Awaitable[None]]] - get = _unimplemented_method # type: Callable[..., Optional[Awaitable[None]]] - post = _unimplemented_method # type: Callable[..., Optional[Awaitable[None]]] - delete = _unimplemented_method # type: Callable[..., Optional[Awaitable[None]]] - patch = _unimplemented_method # type: Callable[..., Optional[Awaitable[None]]] - put = _unimplemented_method # type: Callable[..., Optional[Awaitable[None]]] - options = _unimplemented_method # type: Callable[..., Optional[Awaitable[None]]] - - def prepare(self) -> Optional[Awaitable[None]]: - """Called at the beginning of a request before `get`/`post`/etc. - - Override this method to perform common initialization regardless - of the request method. - - Asynchronous support: Use ``async def`` or decorate this method with - `.gen.coroutine` to make it asynchronous. - If this method returns an ``Awaitable`` execution will not proceed - until the ``Awaitable`` is done. - - .. versionadded:: 3.1 - Asynchronous support. - """ - pass - - def on_finish(self) -> None: - """Called after the end of a request. - - Override this method to perform cleanup, logging, etc. - This method is a counterpart to `prepare`. ``on_finish`` may - not produce any output, as it is called after the response - has been sent to the client. - """ - pass - - def on_connection_close(self) -> None: - """Called in async handlers if the client closed the connection. - - Override this to clean up resources associated with - long-lived connections. Note that this method is called only if - the connection was closed during asynchronous processing; if you - need to do cleanup after every request override `on_finish` - instead. - - Proxies may keep a connection open for a time (perhaps - indefinitely) after the client has gone away, so this method - may not be called promptly after the end user closes their - connection. - """ - if _has_stream_request_body(self.__class__): - if not self.request._body_future.done(): - self.request._body_future.set_exception(iostream.StreamClosedError()) - self.request._body_future.exception() - - def clear(self) -> None: - """Resets all headers and content for this response.""" - self._headers = httputil.HTTPHeaders( - { - "Server": "TornadoServer/%s" % tornado.version, - "Content-Type": "text/html; charset=UTF-8", - "Date": httputil.format_timestamp(time.time()), - } - ) - self.set_default_headers() - self._write_buffer = [] # type: List[bytes] - self._status_code = 200 - self._reason = httputil.responses[200] - - def set_default_headers(self) -> None: - """Override this to set HTTP headers at the beginning of the request. - - For example, this is the place to set a custom ``Server`` header. - Note that setting such headers in the normal flow of request - processing may not do what you want, since headers may be reset - during error handling. - """ - pass - - def set_status(self, status_code: int, reason: Optional[str] = None) -> None: - """Sets the status code for our response. - - :arg int status_code: Response status code. - :arg str reason: Human-readable reason phrase describing the status - code. If ``None``, it will be filled in from - `http.client.responses` or "Unknown". - - .. versionchanged:: 5.0 - - No longer validates that the response code is in - `http.client.responses`. - """ - self._status_code = status_code - if reason is not None: - self._reason = escape.native_str(reason) - else: - self._reason = httputil.responses.get(status_code, "Unknown") - - def get_status(self) -> int: - """Returns the status code for our response.""" - return self._status_code - - def set_header(self, name: str, value: _HeaderTypes) -> None: - """Sets the given response header name and value. - - All header values are converted to strings (`datetime` objects - are formatted according to the HTTP specification for the - ``Date`` header). - - """ - self._headers[name] = self._convert_header_value(value) - - def add_header(self, name: str, value: _HeaderTypes) -> None: - """Adds the given response header and value. - - Unlike `set_header`, `add_header` may be called multiple times - to return multiple values for the same header. - """ - self._headers.add(name, self._convert_header_value(value)) - - def clear_header(self, name: str) -> None: - """Clears an outgoing header, undoing a previous `set_header` call. - - Note that this method does not apply to multi-valued headers - set by `add_header`. - """ - if name in self._headers: - del self._headers[name] - - _INVALID_HEADER_CHAR_RE = re.compile(r"[\x00-\x1f]") - - def _convert_header_value(self, value: _HeaderTypes) -> str: - # Convert the input value to a str. This type check is a bit - # subtle: The bytes case only executes on python 3, and the - # unicode case only executes on python 2, because the other - # cases are covered by the first match for str. - if isinstance(value, str): - retval = value - elif isinstance(value, bytes): # py3 - # Non-ascii characters in headers are not well supported, - # but if you pass bytes, use latin1 so they pass through as-is. - retval = value.decode("latin1") - elif isinstance(value, unicode_type): # py2 - # TODO: This is inconsistent with the use of latin1 above, - # but it's been that way for a long time. Should it change? - retval = escape.utf8(value) - elif isinstance(value, numbers.Integral): - # return immediately since we know the converted value will be safe - return str(value) - elif isinstance(value, datetime.datetime): - return httputil.format_timestamp(value) - else: - raise TypeError("Unsupported header value %r" % value) - # If \n is allowed into the header, it is possible to inject - # additional headers or split the request. - if RequestHandler._INVALID_HEADER_CHAR_RE.search(retval): - raise ValueError("Unsafe header value %r", retval) - return retval - - @overload - def get_argument(self, name: str, default: str, strip: bool = True) -> str: - pass - - @overload - def get_argument( # noqa: F811 - self, name: str, default: _ArgDefaultMarker = _ARG_DEFAULT, strip: bool = True - ) -> str: - pass - - @overload - def get_argument( # noqa: F811 - self, name: str, default: None, strip: bool = True - ) -> Optional[str]: - pass - - def get_argument( # noqa: F811 - self, - name: str, - default: Union[None, str, _ArgDefaultMarker] = _ARG_DEFAULT, - strip: bool = True, - ) -> Optional[str]: - """Returns the value of the argument with the given name. - - If default is not provided, the argument is considered to be - required, and we raise a `MissingArgumentError` if it is missing. - - If the argument appears in the request more than once, we return the - last value. - - This method searches both the query and body arguments. - """ - return self._get_argument(name, default, self.request.arguments, strip) - - def get_arguments(self, name: str, strip: bool = True) -> List[str]: - """Returns a list of the arguments with the given name. - - If the argument is not present, returns an empty list. - - This method searches both the query and body arguments. - """ - - # Make sure `get_arguments` isn't accidentally being called with a - # positional argument that's assumed to be a default (like in - # `get_argument`.) - assert isinstance(strip, bool) - - return self._get_arguments(name, self.request.arguments, strip) - - def get_body_argument( - self, - name: str, - default: Union[None, str, _ArgDefaultMarker] = _ARG_DEFAULT, - strip: bool = True, - ) -> Optional[str]: - """Returns the value of the argument with the given name - from the request body. - - If default is not provided, the argument is considered to be - required, and we raise a `MissingArgumentError` if it is missing. - - If the argument appears in the url more than once, we return the - last value. - - .. versionadded:: 3.2 - """ - return self._get_argument(name, default, self.request.body_arguments, strip) - - def get_body_arguments(self, name: str, strip: bool = True) -> List[str]: - """Returns a list of the body arguments with the given name. - - If the argument is not present, returns an empty list. - - .. versionadded:: 3.2 - """ - return self._get_arguments(name, self.request.body_arguments, strip) - - def get_query_argument( - self, - name: str, - default: Union[None, str, _ArgDefaultMarker] = _ARG_DEFAULT, - strip: bool = True, - ) -> Optional[str]: - """Returns the value of the argument with the given name - from the request query string. - - If default is not provided, the argument is considered to be - required, and we raise a `MissingArgumentError` if it is missing. - - If the argument appears in the url more than once, we return the - last value. - - .. versionadded:: 3.2 - """ - return self._get_argument(name, default, self.request.query_arguments, strip) - - def get_query_arguments(self, name: str, strip: bool = True) -> List[str]: - """Returns a list of the query arguments with the given name. - - If the argument is not present, returns an empty list. - - .. versionadded:: 3.2 - """ - return self._get_arguments(name, self.request.query_arguments, strip) - - def _get_argument( - self, - name: str, - default: Union[None, str, _ArgDefaultMarker], - source: Dict[str, List[bytes]], - strip: bool = True, - ) -> Optional[str]: - args = self._get_arguments(name, source, strip=strip) - if not args: - if isinstance(default, _ArgDefaultMarker): - raise MissingArgumentError(name) - return default - return args[-1] - - def _get_arguments( - self, name: str, source: Dict[str, List[bytes]], strip: bool = True - ) -> List[str]: - values = [] - for v in source.get(name, []): - s = self.decode_argument(v, name=name) - if isinstance(s, unicode_type): - # Get rid of any weird control chars (unless decoding gave - # us bytes, in which case leave it alone) - s = RequestHandler._remove_control_chars_regex.sub(" ", s) - if strip: - s = s.strip() - values.append(s) - return values - - def decode_argument(self, value: bytes, name: Optional[str] = None) -> str: - """Decodes an argument from the request. - - The argument has been percent-decoded and is now a byte string. - By default, this method decodes the argument as utf-8 and returns - a unicode string, but this may be overridden in subclasses. - - This method is used as a filter for both `get_argument()` and for - values extracted from the url and passed to `get()`/`post()`/etc. - - The name of the argument is provided if known, but may be None - (e.g. for unnamed groups in the url regex). - """ - try: - return _unicode(value) - except UnicodeDecodeError: - raise HTTPError( - 400, "Invalid unicode in %s: %r" % (name or "url", value[:40]) - ) - - @property - def cookies(self) -> Dict[str, http.cookies.Morsel]: - """An alias for - `self.request.cookies <.httputil.HTTPServerRequest.cookies>`.""" - return self.request.cookies - - def get_cookie(self, name: str, default: Optional[str] = None) -> Optional[str]: - """Returns the value of the request cookie with the given name. - - If the named cookie is not present, returns ``default``. - - This method only returns cookies that were present in the request. - It does not see the outgoing cookies set by `set_cookie` in this - handler. - """ - if self.request.cookies is not None and name in self.request.cookies: - return self.request.cookies[name].value - return default - - def set_cookie( - self, - name: str, - value: Union[str, bytes], - domain: Optional[str] = None, - expires: Optional[Union[float, Tuple, datetime.datetime]] = None, - path: str = "/", - expires_days: Optional[float] = None, - **kwargs: Any - ) -> None: - """Sets an outgoing cookie name/value with the given options. - - Newly-set cookies are not immediately visible via `get_cookie`; - they are not present until the next request. - - expires may be a numeric timestamp as returned by `time.time`, - a time tuple as returned by `time.gmtime`, or a - `datetime.datetime` object. - - Additional keyword arguments are set on the cookies.Morsel - directly. - See https://docs.python.org/3/library/http.cookies.html#http.cookies.Morsel - for available attributes. - """ - # The cookie library only accepts type str, in both python 2 and 3 - name = escape.native_str(name) - value = escape.native_str(value) - if re.search(r"[\x00-\x20]", name + value): - # Don't let us accidentally inject bad stuff - raise ValueError("Invalid cookie %r: %r" % (name, value)) - if not hasattr(self, "_new_cookie"): - self._new_cookie = ( - http.cookies.SimpleCookie() - ) # type: http.cookies.SimpleCookie - if name in self._new_cookie: - del self._new_cookie[name] - self._new_cookie[name] = value - morsel = self._new_cookie[name] - if domain: - morsel["domain"] = domain - if expires_days is not None and not expires: - expires = datetime.datetime.utcnow() + datetime.timedelta(days=expires_days) - if expires: - morsel["expires"] = httputil.format_timestamp(expires) - if path: - morsel["path"] = path - for k, v in kwargs.items(): - if k == "max_age": - k = "max-age" - - # skip falsy values for httponly and secure flags because - # SimpleCookie sets them regardless - if k in ["httponly", "secure"] and not v: - continue - - morsel[k] = v - - def clear_cookie( - self, name: str, path: str = "/", domain: Optional[str] = None - ) -> None: - """Deletes the cookie with the given name. - - Due to limitations of the cookie protocol, you must pass the same - path and domain to clear a cookie as were used when that cookie - was set (but there is no way to find out on the server side - which values were used for a given cookie). - - Similar to `set_cookie`, the effect of this method will not be - seen until the following request. - """ - expires = datetime.datetime.utcnow() - datetime.timedelta(days=365) - self.set_cookie(name, value="", path=path, expires=expires, domain=domain) - - def clear_all_cookies(self, path: str = "/", domain: Optional[str] = None) -> None: - """Deletes all the cookies the user sent with this request. - - See `clear_cookie` for more information on the path and domain - parameters. - - Similar to `set_cookie`, the effect of this method will not be - seen until the following request. - - .. versionchanged:: 3.2 - - Added the ``path`` and ``domain`` parameters. - """ - for name in self.request.cookies: - self.clear_cookie(name, path=path, domain=domain) - - def set_secure_cookie( - self, - name: str, - value: Union[str, bytes], - expires_days: Optional[float] = 30, - version: Optional[int] = None, - **kwargs: Any - ) -> None: - """Signs and timestamps a cookie so it cannot be forged. - - You must specify the ``cookie_secret`` setting in your Application - to use this method. It should be a long, random sequence of bytes - to be used as the HMAC secret for the signature. - - To read a cookie set with this method, use `get_secure_cookie()`. - - Note that the ``expires_days`` parameter sets the lifetime of the - cookie in the browser, but is independent of the ``max_age_days`` - parameter to `get_secure_cookie`. - A value of None limits the lifetime to the current browser session. - - Secure cookies may contain arbitrary byte values, not just unicode - strings (unlike regular cookies) - - Similar to `set_cookie`, the effect of this method will not be - seen until the following request. - - .. versionchanged:: 3.2.1 - - Added the ``version`` argument. Introduced cookie version 2 - and made it the default. - """ - self.set_cookie( - name, - self.create_signed_value(name, value, version=version), - expires_days=expires_days, - **kwargs - ) - - def create_signed_value( - self, name: str, value: Union[str, bytes], version: Optional[int] = None - ) -> bytes: - """Signs and timestamps a string so it cannot be forged. - - Normally used via set_secure_cookie, but provided as a separate - method for non-cookie uses. To decode a value not stored - as a cookie use the optional value argument to get_secure_cookie. - - .. versionchanged:: 3.2.1 - - Added the ``version`` argument. Introduced cookie version 2 - and made it the default. - """ - self.require_setting("cookie_secret", "secure cookies") - secret = self.application.settings["cookie_secret"] - key_version = None - if isinstance(secret, dict): - if self.application.settings.get("key_version") is None: - raise Exception("key_version setting must be used for secret_key dicts") - key_version = self.application.settings["key_version"] - - return create_signed_value( - secret, name, value, version=version, key_version=key_version - ) - - def get_secure_cookie( - self, - name: str, - value: Optional[str] = None, - max_age_days: float = 31, - min_version: Optional[int] = None, - ) -> Optional[bytes]: - """Returns the given signed cookie if it validates, or None. - - The decoded cookie value is returned as a byte string (unlike - `get_cookie`). - - Similar to `get_cookie`, this method only returns cookies that - were present in the request. It does not see outgoing cookies set by - `set_secure_cookie` in this handler. - - .. versionchanged:: 3.2.1 - - Added the ``min_version`` argument. Introduced cookie version 2; - both versions 1 and 2 are accepted by default. - """ - self.require_setting("cookie_secret", "secure cookies") - if value is None: - value = self.get_cookie(name) - return decode_signed_value( - self.application.settings["cookie_secret"], - name, - value, - max_age_days=max_age_days, - min_version=min_version, - ) - - def get_secure_cookie_key_version( - self, name: str, value: Optional[str] = None - ) -> Optional[int]: - """Returns the signing key version of the secure cookie. - - The version is returned as int. - """ - self.require_setting("cookie_secret", "secure cookies") - if value is None: - value = self.get_cookie(name) - if value is None: - return None - return get_signature_key_version(value) - - def redirect( - self, url: str, permanent: bool = False, status: Optional[int] = None - ) -> None: - """Sends a redirect to the given (optionally relative) URL. - - If the ``status`` argument is specified, that value is used as the - HTTP status code; otherwise either 301 (permanent) or 302 - (temporary) is chosen based on the ``permanent`` argument. - The default is 302 (temporary). - """ - if self._headers_written: - raise Exception("Cannot redirect after headers have been written") - if status is None: - status = 301 if permanent else 302 - else: - assert isinstance(status, int) and 300 <= status <= 399 - self.set_status(status) - self.set_header("Location", utf8(url)) - self.finish() - - def write(self, chunk: Union[str, bytes, dict]) -> None: - """Writes the given chunk to the output buffer. - - To write the output to the network, use the `flush()` method below. - - If the given chunk is a dictionary, we write it as JSON and set - the Content-Type of the response to be ``application/json``. - (if you want to send JSON as a different ``Content-Type``, call - ``set_header`` *after* calling ``write()``). - - Note that lists are not converted to JSON because of a potential - cross-site security vulnerability. All JSON output should be - wrapped in a dictionary. More details at - http://haacked.com/archive/2009/06/25/json-hijacking.aspx/ and - https://github.com/facebook/tornado/issues/1009 - """ - if self._finished: - raise RuntimeError("Cannot write() after finish()") - if not isinstance(chunk, (bytes, unicode_type, dict)): - message = "write() only accepts bytes, unicode, and dict objects" - if isinstance(chunk, list): - message += ( - ". Lists not accepted for security reasons; see " - + "http://www.tornadoweb.org/en/stable/web.html#tornado.web.RequestHandler.write" # noqa: E501 - ) - raise TypeError(message) - if isinstance(chunk, dict): - chunk = escape.json_encode(chunk) - self.set_header("Content-Type", "application/json; charset=UTF-8") - chunk = utf8(chunk) - self._write_buffer.append(chunk) - - def render(self, template_name: str, **kwargs: Any) -> "Future[None]": - """Renders the template with the given arguments as the response. - - ``render()`` calls ``finish()``, so no other output methods can be called - after it. - - Returns a `.Future` with the same semantics as the one returned by `finish`. - Awaiting this `.Future` is optional. - - .. versionchanged:: 5.1 - - Now returns a `.Future` instead of ``None``. - """ - if self._finished: - raise RuntimeError("Cannot render() after finish()") - html = self.render_string(template_name, **kwargs) - - # Insert the additional JS and CSS added by the modules on the page - js_embed = [] - js_files = [] - css_embed = [] - css_files = [] - html_heads = [] - html_bodies = [] - for module in getattr(self, "_active_modules", {}).values(): - embed_part = module.embedded_javascript() - if embed_part: - js_embed.append(utf8(embed_part)) - file_part = module.javascript_files() - if file_part: - if isinstance(file_part, (unicode_type, bytes)): - js_files.append(_unicode(file_part)) - else: - js_files.extend(file_part) - embed_part = module.embedded_css() - if embed_part: - css_embed.append(utf8(embed_part)) - file_part = module.css_files() - if file_part: - if isinstance(file_part, (unicode_type, bytes)): - css_files.append(_unicode(file_part)) - else: - css_files.extend(file_part) - head_part = module.html_head() - if head_part: - html_heads.append(utf8(head_part)) - body_part = module.html_body() - if body_part: - html_bodies.append(utf8(body_part)) - - if js_files: - # Maintain order of JavaScript files given by modules - js = self.render_linked_js(js_files) - sloc = html.rindex(b"</body>") - html = html[:sloc] + utf8(js) + b"\n" + html[sloc:] - if js_embed: - js_bytes = self.render_embed_js(js_embed) - sloc = html.rindex(b"</body>") - html = html[:sloc] + js_bytes + b"\n" + html[sloc:] - if css_files: - css = self.render_linked_css(css_files) - hloc = html.index(b"</head>") - html = html[:hloc] + utf8(css) + b"\n" + html[hloc:] - if css_embed: - css_bytes = self.render_embed_css(css_embed) - hloc = html.index(b"</head>") - html = html[:hloc] + css_bytes + b"\n" + html[hloc:] - if html_heads: - hloc = html.index(b"</head>") - html = html[:hloc] + b"".join(html_heads) + b"\n" + html[hloc:] - if html_bodies: - hloc = html.index(b"</body>") - html = html[:hloc] + b"".join(html_bodies) + b"\n" + html[hloc:] - return self.finish(html) - - def render_linked_js(self, js_files: Iterable[str]) -> str: - """Default method used to render the final js links for the - rendered webpage. - - Override this method in a sub-classed controller to change the output. - """ - paths = [] - unique_paths = set() # type: Set[str] - - for path in js_files: - if not is_absolute(path): - path = self.static_url(path) - if path not in unique_paths: - paths.append(path) - unique_paths.add(path) - - return "".join( - '<script src="' - + escape.xhtml_escape(p) - + '" type="text/javascript"></script>' - for p in paths - ) - - def render_embed_js(self, js_embed: Iterable[bytes]) -> bytes: - """Default method used to render the final embedded js for the - rendered webpage. - - Override this method in a sub-classed controller to change the output. - """ - return ( - b'<script type="text/javascript">\n//<![CDATA[\n' - + b"\n".join(js_embed) - + b"\n//]]>\n</script>" - ) - - def render_linked_css(self, css_files: Iterable[str]) -> str: - """Default method used to render the final css links for the - rendered webpage. - - Override this method in a sub-classed controller to change the output. - """ - paths = [] - unique_paths = set() # type: Set[str] - - for path in css_files: - if not is_absolute(path): - path = self.static_url(path) - if path not in unique_paths: - paths.append(path) - unique_paths.add(path) - - return "".join( - '<link href="' + escape.xhtml_escape(p) + '" ' - 'type="text/css" rel="stylesheet"/>' - for p in paths - ) - - def render_embed_css(self, css_embed: Iterable[bytes]) -> bytes: - """Default method used to render the final embedded css for the - rendered webpage. - - Override this method in a sub-classed controller to change the output. - """ - return b'<style type="text/css">\n' + b"\n".join(css_embed) + b"\n</style>" - - def render_string(self, template_name: str, **kwargs: Any) -> bytes: - """Generate the given template with the given arguments. - - We return the generated byte string (in utf8). To generate and - write a template as a response, use render() above. - """ - # If no template_path is specified, use the path of the calling file - template_path = self.get_template_path() - if not template_path: - frame = sys._getframe(0) - web_file = frame.f_code.co_filename - while frame.f_code.co_filename == web_file: - frame = frame.f_back - assert frame.f_code.co_filename is not None - template_path = os.path.dirname(frame.f_code.co_filename) - with RequestHandler._template_loader_lock: - if template_path not in RequestHandler._template_loaders: - loader = self.create_template_loader(template_path) - RequestHandler._template_loaders[template_path] = loader - else: - loader = RequestHandler._template_loaders[template_path] - t = loader.load(template_name) - namespace = self.get_template_namespace() - namespace.update(kwargs) - return t.generate(**namespace) - - def get_template_namespace(self) -> Dict[str, Any]: - """Returns a dictionary to be used as the default template namespace. - - May be overridden by subclasses to add or modify values. - - The results of this method will be combined with additional - defaults in the `tornado.template` module and keyword arguments - to `render` or `render_string`. - """ - namespace = dict( - handler=self, - request=self.request, - current_user=self.current_user, - locale=self.locale, - _=self.locale.translate, - pgettext=self.locale.pgettext, - static_url=self.static_url, - xsrf_form_html=self.xsrf_form_html, - reverse_url=self.reverse_url, - ) - namespace.update(self.ui) - return namespace - - def create_template_loader(self, template_path: str) -> template.BaseLoader: - """Returns a new template loader for the given path. - - May be overridden by subclasses. By default returns a - directory-based loader on the given path, using the - ``autoescape`` and ``template_whitespace`` application - settings. If a ``template_loader`` application setting is - supplied, uses that instead. - """ - settings = self.application.settings - if "template_loader" in settings: - return settings["template_loader"] - kwargs = {} - if "autoescape" in settings: - # autoescape=None means "no escaping", so we have to be sure - # to only pass this kwarg if the user asked for it. - kwargs["autoescape"] = settings["autoescape"] - if "template_whitespace" in settings: - kwargs["whitespace"] = settings["template_whitespace"] - return template.Loader(template_path, **kwargs) - - def flush(self, include_footers: bool = False) -> "Future[None]": - """Flushes the current output buffer to the network. - - .. versionchanged:: 4.0 - Now returns a `.Future` if no callback is given. - - .. versionchanged:: 6.0 - - The ``callback`` argument was removed. - """ - assert self.request.connection is not None - chunk = b"".join(self._write_buffer) - self._write_buffer = [] - if not self._headers_written: - self._headers_written = True - for transform in self._transforms: - assert chunk is not None - ( - self._status_code, - self._headers, - chunk, - ) = transform.transform_first_chunk( - self._status_code, self._headers, chunk, include_footers - ) - # Ignore the chunk and only write the headers for HEAD requests - if self.request.method == "HEAD": - chunk = b"" - - # Finalize the cookie headers (which have been stored in a side - # object so an outgoing cookie could be overwritten before it - # is sent). - if hasattr(self, "_new_cookie"): - for cookie in self._new_cookie.values(): - self.add_header("Set-Cookie", cookie.OutputString(None)) - - start_line = httputil.ResponseStartLine("", self._status_code, self._reason) - return self.request.connection.write_headers( - start_line, self._headers, chunk - ) - else: - for transform in self._transforms: - chunk = transform.transform_chunk(chunk, include_footers) - # Ignore the chunk and only write the headers for HEAD requests - if self.request.method != "HEAD": - return self.request.connection.write(chunk) - else: - future = Future() # type: Future[None] - future.set_result(None) - return future - - def finish(self, chunk: Optional[Union[str, bytes, dict]] = None) -> "Future[None]": - """Finishes this response, ending the HTTP request. - - Passing a ``chunk`` to ``finish()`` is equivalent to passing that - chunk to ``write()`` and then calling ``finish()`` with no arguments. - - Returns a `.Future` which may optionally be awaited to track the sending - of the response to the client. This `.Future` resolves when all the response - data has been sent, and raises an error if the connection is closed before all - data can be sent. - - .. versionchanged:: 5.1 - - Now returns a `.Future` instead of ``None``. - """ - if self._finished: - raise RuntimeError("finish() called twice") - - if chunk is not None: - self.write(chunk) - - # Automatically support ETags and add the Content-Length header if - # we have not flushed any content yet. - if not self._headers_written: - if ( - self._status_code == 200 - and self.request.method in ("GET", "HEAD") - and "Etag" not in self._headers - ): - self.set_etag_header() - if self.check_etag_header(): - self._write_buffer = [] - self.set_status(304) - if self._status_code in (204, 304) or (100 <= self._status_code < 200): - assert not self._write_buffer, ( - "Cannot send body with %s" % self._status_code - ) - self._clear_representation_headers() - elif "Content-Length" not in self._headers: - content_length = sum(len(part) for part in self._write_buffer) - self.set_header("Content-Length", content_length) - - assert self.request.connection is not None - # Now that the request is finished, clear the callback we - # set on the HTTPConnection (which would otherwise prevent the - # garbage collection of the RequestHandler when there - # are keepalive connections) - self.request.connection.set_close_callback(None) # type: ignore - - future = self.flush(include_footers=True) - self.request.connection.finish() - self._log() - self._finished = True - self.on_finish() - self._break_cycles() - return future - - def detach(self) -> iostream.IOStream: - """Take control of the underlying stream. - - Returns the underlying `.IOStream` object and stops all - further HTTP processing. Intended for implementing protocols - like websockets that tunnel over an HTTP handshake. - - This method is only supported when HTTP/1.1 is used. - - .. versionadded:: 5.1 - """ - self._finished = True - # TODO: add detach to HTTPConnection? - return self.request.connection.detach() # type: ignore - - def _break_cycles(self) -> None: - # Break up a reference cycle between this handler and the - # _ui_module closures to allow for faster GC on CPython. - self.ui = None # type: ignore - - def send_error(self, status_code: int = 500, **kwargs: Any) -> None: - """Sends the given HTTP error code to the browser. - - If `flush()` has already been called, it is not possible to send - an error, so this method will simply terminate the response. - If output has been written but not yet flushed, it will be discarded - and replaced with the error page. - - Override `write_error()` to customize the error page that is returned. - Additional keyword arguments are passed through to `write_error`. - """ - if self._headers_written: - gen_log.error("Cannot send error response after headers written") - if not self._finished: - # If we get an error between writing headers and finishing, - # we are unlikely to be able to finish due to a - # Content-Length mismatch. Try anyway to release the - # socket. - try: - self.finish() - except Exception: - gen_log.error("Failed to flush partial response", exc_info=True) - return - self.clear() - - reason = kwargs.get("reason") - if "exc_info" in kwargs: - exception = kwargs["exc_info"][1] - if isinstance(exception, HTTPError) and exception.reason: - reason = exception.reason - self.set_status(status_code, reason=reason) - try: - self.write_error(status_code, **kwargs) - except Exception: - app_log.error("Uncaught exception in write_error", exc_info=True) - if not self._finished: - self.finish() - - def write_error(self, status_code: int, **kwargs: Any) -> None: - """Override to implement custom error pages. - - ``write_error`` may call `write`, `render`, `set_header`, etc - to produce output as usual. - - If this error was caused by an uncaught exception (including - HTTPError), an ``exc_info`` triple will be available as - ``kwargs["exc_info"]``. Note that this exception may not be - the "current" exception for purposes of methods like - ``sys.exc_info()`` or ``traceback.format_exc``. - """ - if self.settings.get("serve_traceback") and "exc_info" in kwargs: - # in debug mode, try to send a traceback - self.set_header("Content-Type", "text/plain") - for line in traceback.format_exception(*kwargs["exc_info"]): - self.write(line) - self.finish() - else: - self.finish( - "<html><title>%(code)d: %(message)s</title>" - "<body>%(code)d: %(message)s</body></html>" - % {"code": status_code, "message": self._reason} - ) - - @property - def locale(self) -> tornado.locale.Locale: - """The locale for the current session. - - Determined by either `get_user_locale`, which you can override to - set the locale based on, e.g., a user preference stored in a - database, or `get_browser_locale`, which uses the ``Accept-Language`` - header. - - .. versionchanged: 4.1 - Added a property setter. - """ - if not hasattr(self, "_locale"): - loc = self.get_user_locale() - if loc is not None: - self._locale = loc - else: - self._locale = self.get_browser_locale() - assert self._locale - return self._locale - - @locale.setter - def locale(self, value: tornado.locale.Locale) -> None: - self._locale = value - - def get_user_locale(self) -> Optional[tornado.locale.Locale]: - """Override to determine the locale from the authenticated user. - - If None is returned, we fall back to `get_browser_locale()`. - - This method should return a `tornado.locale.Locale` object, - most likely obtained via a call like ``tornado.locale.get("en")`` - """ - return None - - def get_browser_locale(self, default: str = "en_US") -> tornado.locale.Locale: - """Determines the user's locale from ``Accept-Language`` header. - - See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4 - """ - if "Accept-Language" in self.request.headers: - languages = self.request.headers["Accept-Language"].split(",") - locales = [] - for language in languages: - parts = language.strip().split(";") - if len(parts) > 1 and parts[1].startswith("q="): - try: - score = float(parts[1][2:]) - except (ValueError, TypeError): - score = 0.0 - else: - score = 1.0 - locales.append((parts[0], score)) - if locales: - locales.sort(key=lambda pair: pair[1], reverse=True) - codes = [loc[0] for loc in locales] - return locale.get(*codes) - return locale.get(default) - - @property - def current_user(self) -> Any: - """The authenticated user for this request. - - This is set in one of two ways: - - * A subclass may override `get_current_user()`, which will be called - automatically the first time ``self.current_user`` is accessed. - `get_current_user()` will only be called once per request, - and is cached for future access:: - - def get_current_user(self): - user_cookie = self.get_secure_cookie("user") - if user_cookie: - return json.loads(user_cookie) - return None - - * It may be set as a normal variable, typically from an overridden - `prepare()`:: - - @gen.coroutine - def prepare(self): - user_id_cookie = self.get_secure_cookie("user_id") - if user_id_cookie: - self.current_user = yield load_user(user_id_cookie) - - Note that `prepare()` may be a coroutine while `get_current_user()` - may not, so the latter form is necessary if loading the user requires - asynchronous operations. - - The user object may be any type of the application's choosing. - """ - if not hasattr(self, "_current_user"): - self._current_user = self.get_current_user() - return self._current_user - - @current_user.setter - def current_user(self, value: Any) -> None: - self._current_user = value - - def get_current_user(self) -> Any: - """Override to determine the current user from, e.g., a cookie. - - This method may not be a coroutine. - """ - return None - - def get_login_url(self) -> str: - """Override to customize the login URL based on the request. - - By default, we use the ``login_url`` application setting. - """ - self.require_setting("login_url", "@tornado.web.authenticated") - return self.application.settings["login_url"] - - def get_template_path(self) -> Optional[str]: - """Override to customize template path for each handler. - - By default, we use the ``template_path`` application setting. - Return None to load templates relative to the calling file. - """ - return self.application.settings.get("template_path") - - @property - def xsrf_token(self) -> bytes: - """The XSRF-prevention token for the current user/session. - - To prevent cross-site request forgery, we set an '_xsrf' cookie - and include the same '_xsrf' value as an argument with all POST - requests. If the two do not match, we reject the form submission - as a potential forgery. - - See http://en.wikipedia.org/wiki/Cross-site_request_forgery - - This property is of type `bytes`, but it contains only ASCII - characters. If a character string is required, there is no - need to base64-encode it; just decode the byte string as - UTF-8. - - .. versionchanged:: 3.2.2 - The xsrf token will now be have a random mask applied in every - request, which makes it safe to include the token in pages - that are compressed. See http://breachattack.com for more - information on the issue fixed by this change. Old (version 1) - cookies will be converted to version 2 when this method is called - unless the ``xsrf_cookie_version`` `Application` setting is - set to 1. - - .. versionchanged:: 4.3 - The ``xsrf_cookie_kwargs`` `Application` setting may be - used to supply additional cookie options (which will be - passed directly to `set_cookie`). For example, - ``xsrf_cookie_kwargs=dict(httponly=True, secure=True)`` - will set the ``secure`` and ``httponly`` flags on the - ``_xsrf`` cookie. - """ - if not hasattr(self, "_xsrf_token"): - version, token, timestamp = self._get_raw_xsrf_token() - output_version = self.settings.get("xsrf_cookie_version", 2) - cookie_kwargs = self.settings.get("xsrf_cookie_kwargs", {}) - if output_version == 1: - self._xsrf_token = binascii.b2a_hex(token) - elif output_version == 2: - mask = os.urandom(4) - self._xsrf_token = b"|".join( - [ - b"2", - binascii.b2a_hex(mask), - binascii.b2a_hex(_websocket_mask(mask, token)), - utf8(str(int(timestamp))), - ] - ) - else: - raise ValueError("unknown xsrf cookie version %d", output_version) - if version is None: - if self.current_user and "expires_days" not in cookie_kwargs: - cookie_kwargs["expires_days"] = 30 - self.set_cookie("_xsrf", self._xsrf_token, **cookie_kwargs) - return self._xsrf_token - - def _get_raw_xsrf_token(self) -> Tuple[Optional[int], bytes, float]: - """Read or generate the xsrf token in its raw form. - - The raw_xsrf_token is a tuple containing: - - * version: the version of the cookie from which this token was read, - or None if we generated a new token in this request. - * token: the raw token data; random (non-ascii) bytes. - * timestamp: the time this token was generated (will not be accurate - for version 1 cookies) - """ - if not hasattr(self, "_raw_xsrf_token"): - cookie = self.get_cookie("_xsrf") - if cookie: - version, token, timestamp = self._decode_xsrf_token(cookie) - else: - version, token, timestamp = None, None, None - if token is None: - version = None - token = os.urandom(16) - timestamp = time.time() - assert token is not None - assert timestamp is not None - self._raw_xsrf_token = (version, token, timestamp) - return self._raw_xsrf_token - - def _decode_xsrf_token( - self, cookie: str - ) -> Tuple[Optional[int], Optional[bytes], Optional[float]]: - """Convert a cookie string into a the tuple form returned by - _get_raw_xsrf_token. - """ - - try: - m = _signed_value_version_re.match(utf8(cookie)) - - if m: - version = int(m.group(1)) - if version == 2: - _, mask_str, masked_token, timestamp_str = cookie.split("|") - - mask = binascii.a2b_hex(utf8(mask_str)) - token = _websocket_mask(mask, binascii.a2b_hex(utf8(masked_token))) - timestamp = int(timestamp_str) - return version, token, timestamp - else: - # Treat unknown versions as not present instead of failing. - raise Exception("Unknown xsrf cookie version") - else: - version = 1 - try: - token = binascii.a2b_hex(utf8(cookie)) - except (binascii.Error, TypeError): - token = utf8(cookie) - # We don't have a usable timestamp in older versions. - timestamp = int(time.time()) - return (version, token, timestamp) - except Exception: - # Catch exceptions and return nothing instead of failing. - gen_log.debug("Uncaught exception in _decode_xsrf_token", exc_info=True) - return None, None, None - - def check_xsrf_cookie(self) -> None: - """Verifies that the ``_xsrf`` cookie matches the ``_xsrf`` argument. - - To prevent cross-site request forgery, we set an ``_xsrf`` - cookie and include the same value as a non-cookie - field with all ``POST`` requests. If the two do not match, we - reject the form submission as a potential forgery. - - The ``_xsrf`` value may be set as either a form field named ``_xsrf`` - or in a custom HTTP header named ``X-XSRFToken`` or ``X-CSRFToken`` - (the latter is accepted for compatibility with Django). - - See http://en.wikipedia.org/wiki/Cross-site_request_forgery - - .. versionchanged:: 3.2.2 - Added support for cookie version 2. Both versions 1 and 2 are - supported. - """ - # Prior to release 1.1.1, this check was ignored if the HTTP header - # ``X-Requested-With: XMLHTTPRequest`` was present. This exception - # has been shown to be insecure and has been removed. For more - # information please see - # http://www.djangoproject.com/weblog/2011/feb/08/security/ - # http://weblog.rubyonrails.org/2011/2/8/csrf-protection-bypass-in-ruby-on-rails - token = ( - self.get_argument("_xsrf", None) - or self.request.headers.get("X-Xsrftoken") - or self.request.headers.get("X-Csrftoken") - ) - if not token: - raise HTTPError(403, "'_xsrf' argument missing from POST") - _, token, _ = self._decode_xsrf_token(token) - _, expected_token, _ = self._get_raw_xsrf_token() - if not token: - raise HTTPError(403, "'_xsrf' argument has invalid format") - if not hmac.compare_digest(utf8(token), utf8(expected_token)): - raise HTTPError(403, "XSRF cookie does not match POST argument") - - def xsrf_form_html(self) -> str: - """An HTML ``<input/>`` element to be included with all POST forms. - - It defines the ``_xsrf`` input value, which we check on all POST - requests to prevent cross-site request forgery. If you have set - the ``xsrf_cookies`` application setting, you must include this - HTML within all of your HTML forms. - - In a template, this method should be called with ``{% module - xsrf_form_html() %}`` - - See `check_xsrf_cookie()` above for more information. - """ - return ( - '<input type="hidden" name="_xsrf" value="' - + escape.xhtml_escape(self.xsrf_token) - + '"/>' - ) - - def static_url( - self, path: str, include_host: Optional[bool] = None, **kwargs: Any - ) -> str: - """Returns a static URL for the given relative static file path. - - This method requires you set the ``static_path`` setting in your - application (which specifies the root directory of your static - files). - - This method returns a versioned url (by default appending - ``?v=<signature>``), which allows the static files to be - cached indefinitely. This can be disabled by passing - ``include_version=False`` (in the default implementation; - other static file implementations are not required to support - this, but they may support other options). - - By default this method returns URLs relative to the current - host, but if ``include_host`` is true the URL returned will be - absolute. If this handler has an ``include_host`` attribute, - that value will be used as the default for all `static_url` - calls that do not pass ``include_host`` as a keyword argument. - - """ - self.require_setting("static_path", "static_url") - get_url = self.settings.get( - "static_handler_class", StaticFileHandler - ).make_static_url - - if include_host is None: - include_host = getattr(self, "include_host", False) - - if include_host: - base = self.request.protocol + "://" + self.request.host - else: - base = "" - - return base + get_url(self.settings, path, **kwargs) - - def require_setting(self, name: str, feature: str = "this feature") -> None: - """Raises an exception if the given app setting is not defined.""" - if not self.application.settings.get(name): - raise Exception( - "You must define the '%s' setting in your " - "application to use %s" % (name, feature) - ) - - def reverse_url(self, name: str, *args: Any) -> str: - """Alias for `Application.reverse_url`.""" - return self.application.reverse_url(name, *args) - - def compute_etag(self) -> Optional[str]: - """Computes the etag header to be used for this request. - - By default uses a hash of the content written so far. - - May be overridden to provide custom etag implementations, - or may return None to disable tornado's default etag support. - """ - hasher = hashlib.sha1() - for part in self._write_buffer: - hasher.update(part) - return '"%s"' % hasher.hexdigest() - - def set_etag_header(self) -> None: - """Sets the response's Etag header using ``self.compute_etag()``. - - Note: no header will be set if ``compute_etag()`` returns ``None``. - - This method is called automatically when the request is finished. - """ - etag = self.compute_etag() - if etag is not None: - self.set_header("Etag", etag) - - def check_etag_header(self) -> bool: - """Checks the ``Etag`` header against requests's ``If-None-Match``. - - Returns ``True`` if the request's Etag matches and a 304 should be - returned. For example:: - - self.set_etag_header() - if self.check_etag_header(): - self.set_status(304) - return - - This method is called automatically when the request is finished, - but may be called earlier for applications that override - `compute_etag` and want to do an early check for ``If-None-Match`` - before completing the request. The ``Etag`` header should be set - (perhaps with `set_etag_header`) before calling this method. - """ - computed_etag = utf8(self._headers.get("Etag", "")) - # Find all weak and strong etag values from If-None-Match header - # because RFC 7232 allows multiple etag values in a single header. - etags = re.findall( - br'\*|(?:W/)?"[^"]*"', utf8(self.request.headers.get("If-None-Match", "")) - ) - if not computed_etag or not etags: - return False - - match = False - if etags[0] == b"*": - match = True - else: - # Use a weak comparison when comparing entity-tags. - def val(x: bytes) -> bytes: - return x[2:] if x.startswith(b"W/") else x - - for etag in etags: - if val(etag) == val(computed_etag): - match = True - break - return match - - async def _execute( - self, transforms: List["OutputTransform"], *args: bytes, **kwargs: bytes - ) -> None: - """Executes this request with the given output transforms.""" - self._transforms = transforms - try: - if self.request.method not in self.SUPPORTED_METHODS: - raise HTTPError(405) - self.path_args = [self.decode_argument(arg) for arg in args] - self.path_kwargs = dict( - (k, self.decode_argument(v, name=k)) for (k, v) in kwargs.items() - ) - # If XSRF cookies are turned on, reject form submissions without - # the proper cookie - if self.request.method not in ( - "GET", - "HEAD", - "OPTIONS", - ) and self.application.settings.get("xsrf_cookies"): - self.check_xsrf_cookie() - - result = self.prepare() - if result is not None: - result = await result - if self._prepared_future is not None: - # Tell the Application we've finished with prepare() - # and are ready for the body to arrive. - future_set_result_unless_cancelled(self._prepared_future, None) - if self._finished: - return - - if _has_stream_request_body(self.__class__): - # In streaming mode request.body is a Future that signals - # the body has been completely received. The Future has no - # result; the data has been passed to self.data_received - # instead. - try: - await self.request._body_future - except iostream.StreamClosedError: - return - - method = getattr(self, self.request.method.lower()) - result = method(*self.path_args, **self.path_kwargs) - if result is not None: - result = await result - if self._auto_finish and not self._finished: - self.finish() - except Exception as e: - try: - self._handle_request_exception(e) - except Exception: - app_log.error("Exception in exception handler", exc_info=True) - finally: - # Unset result to avoid circular references - result = None - if self._prepared_future is not None and not self._prepared_future.done(): - # In case we failed before setting _prepared_future, do it - # now (to unblock the HTTP server). Note that this is not - # in a finally block to avoid GC issues prior to Python 3.4. - self._prepared_future.set_result(None) - - def data_received(self, chunk: bytes) -> Optional[Awaitable[None]]: - """Implement this method to handle streamed request data. - - Requires the `.stream_request_body` decorator. - - May be a coroutine for flow control. - """ - raise NotImplementedError() - - def _log(self) -> None: - """Logs the current request. - - Sort of deprecated since this functionality was moved to the - Application, but left in place for the benefit of existing apps - that have overridden this method. - """ - self.application.log_request(self) - - def _request_summary(self) -> str: - return "%s %s (%s)" % ( - self.request.method, - self.request.uri, - self.request.remote_ip, - ) - - def _handle_request_exception(self, e: BaseException) -> None: - if isinstance(e, Finish): - # Not an error; just finish the request without logging. - if not self._finished: - self.finish(*e.args) - return - try: - self.log_exception(*sys.exc_info()) - except Exception: - # An error here should still get a best-effort send_error() - # to avoid leaking the connection. - app_log.error("Error in exception logger", exc_info=True) - if self._finished: - # Extra errors after the request has been finished should - # be logged, but there is no reason to continue to try and - # send a response. - return - if isinstance(e, HTTPError): - self.send_error(e.status_code, exc_info=sys.exc_info()) - else: - self.send_error(500, exc_info=sys.exc_info()) - - def log_exception( - self, - typ: "Optional[Type[BaseException]]", - value: Optional[BaseException], - tb: Optional[TracebackType], - ) -> None: - """Override to customize logging of uncaught exceptions. - - By default logs instances of `HTTPError` as warnings without - stack traces (on the ``tornado.general`` logger), and all - other exceptions as errors with stack traces (on the - ``tornado.application`` logger). - - .. versionadded:: 3.1 - """ - if isinstance(value, HTTPError): - if value.log_message: - format = "%d %s: " + value.log_message - args = [value.status_code, self._request_summary()] + list(value.args) - gen_log.warning(format, *args) - else: - app_log.error( - "Uncaught exception %s\n%r", - self._request_summary(), - self.request, - exc_info=(typ, value, tb), # type: ignore - ) - - def _ui_module(self, name: str, module: Type["UIModule"]) -> Callable[..., str]: - def render(*args, **kwargs) -> str: # type: ignore - if not hasattr(self, "_active_modules"): - self._active_modules = {} # type: Dict[str, UIModule] - if name not in self._active_modules: - self._active_modules[name] = module(self) - rendered = self._active_modules[name].render(*args, **kwargs) - return rendered - - return render - - def _ui_method(self, method: Callable[..., str]) -> Callable[..., str]: - return lambda *args, **kwargs: method(self, *args, **kwargs) - - def _clear_representation_headers(self) -> None: - # 304 responses should not contain representation metadata - # headers (defined in - # https://tools.ietf.org/html/rfc7231#section-3.1) - # not explicitly allowed by - # https://tools.ietf.org/html/rfc7232#section-4.1 - headers = ["Content-Encoding", "Content-Language", "Content-Type"] - for h in headers: - self.clear_header(h) - - -def stream_request_body(cls: Type[RequestHandler]) -> Type[RequestHandler]: - """Apply to `RequestHandler` subclasses to enable streaming body support. - - This decorator implies the following changes: - - * `.HTTPServerRequest.body` is undefined, and body arguments will not - be included in `RequestHandler.get_argument`. - * `RequestHandler.prepare` is called when the request headers have been - read instead of after the entire body has been read. - * The subclass must define a method ``data_received(self, data):``, which - will be called zero or more times as data is available. Note that - if the request has an empty body, ``data_received`` may not be called. - * ``prepare`` and ``data_received`` may return Futures (such as via - ``@gen.coroutine``, in which case the next method will not be called - until those futures have completed. - * The regular HTTP method (``post``, ``put``, etc) will be called after - the entire body has been read. - - See the `file receiver demo <https://github.com/tornadoweb/tornado/tree/master/demos/file_upload/>`_ - for example usage. - """ # noqa: E501 - if not issubclass(cls, RequestHandler): - raise TypeError("expected subclass of RequestHandler, got %r", cls) - cls._stream_request_body = True - return cls - - -def _has_stream_request_body(cls: Type[RequestHandler]) -> bool: - if not issubclass(cls, RequestHandler): - raise TypeError("expected subclass of RequestHandler, got %r", cls) - return cls._stream_request_body - - -def removeslash( - method: Callable[..., Optional[Awaitable[None]]] -) -> Callable[..., Optional[Awaitable[None]]]: - """Use this decorator to remove trailing slashes from the request path. - - For example, a request to ``/foo/`` would redirect to ``/foo`` with this - decorator. Your request handler mapping should use a regular expression - like ``r'/foo/*'`` in conjunction with using the decorator. - """ - - @functools.wraps(method) - def wrapper( # type: ignore - self: RequestHandler, *args, **kwargs - ) -> Optional[Awaitable[None]]: - if self.request.path.endswith("/"): - if self.request.method in ("GET", "HEAD"): - uri = self.request.path.rstrip("/") - if uri: # don't try to redirect '/' to '' - if self.request.query: - uri += "?" + self.request.query - self.redirect(uri, permanent=True) - return None - else: - raise HTTPError(404) - return method(self, *args, **kwargs) - - return wrapper - - -def addslash( - method: Callable[..., Optional[Awaitable[None]]] -) -> Callable[..., Optional[Awaitable[None]]]: - """Use this decorator to add a missing trailing slash to the request path. - - For example, a request to ``/foo`` would redirect to ``/foo/`` with this - decorator. Your request handler mapping should use a regular expression - like ``r'/foo/?'`` in conjunction with using the decorator. - """ - - @functools.wraps(method) - def wrapper( # type: ignore - self: RequestHandler, *args, **kwargs - ) -> Optional[Awaitable[None]]: - if not self.request.path.endswith("/"): - if self.request.method in ("GET", "HEAD"): - uri = self.request.path + "/" - if self.request.query: - uri += "?" + self.request.query - self.redirect(uri, permanent=True) - return None - raise HTTPError(404) - return method(self, *args, **kwargs) - - return wrapper - - -class _ApplicationRouter(ReversibleRuleRouter): - """Routing implementation used internally by `Application`. - - Provides a binding between `Application` and `RequestHandler`. - This implementation extends `~.routing.ReversibleRuleRouter` in a couple of ways: - * it allows to use `RequestHandler` subclasses as `~.routing.Rule` target and - * it allows to use a list/tuple of rules as `~.routing.Rule` target. - ``process_rule`` implementation will substitute this list with an appropriate - `_ApplicationRouter` instance. - """ - - def __init__( - self, application: "Application", rules: Optional[_RuleList] = None - ) -> None: - assert isinstance(application, Application) - self.application = application - super().__init__(rules) - - def process_rule(self, rule: Rule) -> Rule: - rule = super().process_rule(rule) - - if isinstance(rule.target, (list, tuple)): - rule.target = _ApplicationRouter( - self.application, rule.target # type: ignore - ) - - return rule - - def get_target_delegate( - self, target: Any, request: httputil.HTTPServerRequest, **target_params: Any - ) -> Optional[httputil.HTTPMessageDelegate]: - if isclass(target) and issubclass(target, RequestHandler): - return self.application.get_handler_delegate( - request, target, **target_params - ) - - return super().get_target_delegate(target, request, **target_params) - - -class Application(ReversibleRouter): - r"""A collection of request handlers that make up a web application. - - Instances of this class are callable and can be passed directly to - HTTPServer to serve the application:: - - application = web.Application([ - (r"/", MainPageHandler), - ]) - http_server = httpserver.HTTPServer(application) - http_server.listen(8080) - ioloop.IOLoop.current().start() - - The constructor for this class takes in a list of `~.routing.Rule` - objects or tuples of values corresponding to the arguments of - `~.routing.Rule` constructor: ``(matcher, target, [target_kwargs], [name])``, - the values in square brackets being optional. The default matcher is - `~.routing.PathMatches`, so ``(regexp, target)`` tuples can also be used - instead of ``(PathMatches(regexp), target)``. - - A common routing target is a `RequestHandler` subclass, but you can also - use lists of rules as a target, which create a nested routing configuration:: - - application = web.Application([ - (HostMatches("example.com"), [ - (r"/", MainPageHandler), - (r"/feed", FeedHandler), - ]), - ]) - - In addition to this you can use nested `~.routing.Router` instances, - `~.httputil.HTTPMessageDelegate` subclasses and callables as routing targets - (see `~.routing` module docs for more information). - - When we receive requests, we iterate over the list in order and - instantiate an instance of the first request class whose regexp - matches the request path. The request class can be specified as - either a class object or a (fully-qualified) name. - - A dictionary may be passed as the third element (``target_kwargs``) - of the tuple, which will be used as keyword arguments to the handler's - constructor and `~RequestHandler.initialize` method. This pattern - is used for the `StaticFileHandler` in this example (note that a - `StaticFileHandler` can be installed automatically with the - static_path setting described below):: - - application = web.Application([ - (r"/static/(.*)", web.StaticFileHandler, {"path": "/var/www"}), - ]) - - We support virtual hosts with the `add_handlers` method, which takes in - a host regular expression as the first argument:: - - application.add_handlers(r"www\.myhost\.com", [ - (r"/article/([0-9]+)", ArticleHandler), - ]) - - If there's no match for the current request's host, then ``default_host`` - parameter value is matched against host regular expressions. - - - .. warning:: - - Applications that do not use TLS may be vulnerable to :ref:`DNS - rebinding <dnsrebinding>` attacks. This attack is especially - relevant to applications that only listen on ``127.0.0.1`` or - other private networks. Appropriate host patterns must be used - (instead of the default of ``r'.*'``) to prevent this risk. The - ``default_host`` argument must not be used in applications that - may be vulnerable to DNS rebinding. - - You can serve static files by sending the ``static_path`` setting - as a keyword argument. We will serve those files from the - ``/static/`` URI (this is configurable with the - ``static_url_prefix`` setting), and we will serve ``/favicon.ico`` - and ``/robots.txt`` from the same directory. A custom subclass of - `StaticFileHandler` can be specified with the - ``static_handler_class`` setting. - - .. versionchanged:: 4.5 - Integration with the new `tornado.routing` module. - - """ - - def __init__( - self, - handlers: Optional[_RuleList] = None, - default_host: Optional[str] = None, - transforms: Optional[List[Type["OutputTransform"]]] = None, - **settings: Any - ) -> None: - if transforms is None: - self.transforms = [] # type: List[Type[OutputTransform]] - if settings.get("compress_response") or settings.get("gzip"): - self.transforms.append(GZipContentEncoding) - else: - self.transforms = transforms - self.default_host = default_host - self.settings = settings - self.ui_modules = { - "linkify": _linkify, - "xsrf_form_html": _xsrf_form_html, - "Template": TemplateModule, - } - self.ui_methods = {} # type: Dict[str, Callable[..., str]] - self._load_ui_modules(settings.get("ui_modules", {})) - self._load_ui_methods(settings.get("ui_methods", {})) - if self.settings.get("static_path"): - path = self.settings["static_path"] - handlers = list(handlers or []) - static_url_prefix = settings.get("static_url_prefix", "/static/") - static_handler_class = settings.get( - "static_handler_class", StaticFileHandler - ) - static_handler_args = settings.get("static_handler_args", {}) - static_handler_args["path"] = path - for pattern in [ - re.escape(static_url_prefix) + r"(.*)", - r"/(favicon\.ico)", - r"/(robots\.txt)", - ]: - handlers.insert(0, (pattern, static_handler_class, static_handler_args)) - - if self.settings.get("debug"): - self.settings.setdefault("autoreload", True) - self.settings.setdefault("compiled_template_cache", False) - self.settings.setdefault("static_hash_cache", False) - self.settings.setdefault("serve_traceback", True) - - self.wildcard_router = _ApplicationRouter(self, handlers) - self.default_router = _ApplicationRouter( - self, [Rule(AnyMatches(), self.wildcard_router)] - ) - - # Automatically reload modified modules - if self.settings.get("autoreload"): - from tornado import autoreload - - autoreload.start() - - def listen(self, port: int, address: str = "", **kwargs: Any) -> HTTPServer: - """Starts an HTTP server for this application on the given port. - - This is a convenience alias for creating an `.HTTPServer` - object and calling its listen method. Keyword arguments not - supported by `HTTPServer.listen <.TCPServer.listen>` are passed to the - `.HTTPServer` constructor. For advanced uses - (e.g. multi-process mode), do not use this method; create an - `.HTTPServer` and call its - `.TCPServer.bind`/`.TCPServer.start` methods directly. - - Note that after calling this method you still need to call - ``IOLoop.current().start()`` to start the server. - - Returns the `.HTTPServer` object. - - .. versionchanged:: 4.3 - Now returns the `.HTTPServer` object. - """ - server = HTTPServer(self, **kwargs) - server.listen(port, address) - return server - - def add_handlers(self, host_pattern: str, host_handlers: _RuleList) -> None: - """Appends the given handlers to our handler list. - - Host patterns are processed sequentially in the order they were - added. All matching patterns will be considered. - """ - host_matcher = HostMatches(host_pattern) - rule = Rule(host_matcher, _ApplicationRouter(self, host_handlers)) - - self.default_router.rules.insert(-1, rule) - - if self.default_host is not None: - self.wildcard_router.add_rules( - [(DefaultHostMatches(self, host_matcher.host_pattern), host_handlers)] - ) - - def add_transform(self, transform_class: Type["OutputTransform"]) -> None: - self.transforms.append(transform_class) - - def _load_ui_methods(self, methods: Any) -> None: - if isinstance(methods, types.ModuleType): - self._load_ui_methods(dict((n, getattr(methods, n)) for n in dir(methods))) - elif isinstance(methods, list): - for m in methods: - self._load_ui_methods(m) - else: - for name, fn in methods.items(): - if ( - not name.startswith("_") - and hasattr(fn, "__call__") - and name[0].lower() == name[0] - ): - self.ui_methods[name] = fn - - def _load_ui_modules(self, modules: Any) -> None: - if isinstance(modules, types.ModuleType): - self._load_ui_modules(dict((n, getattr(modules, n)) for n in dir(modules))) - elif isinstance(modules, list): - for m in modules: - self._load_ui_modules(m) - else: - assert isinstance(modules, dict) - for name, cls in modules.items(): - try: - if issubclass(cls, UIModule): - self.ui_modules[name] = cls - except TypeError: - pass - - def __call__( - self, request: httputil.HTTPServerRequest - ) -> Optional[Awaitable[None]]: - # Legacy HTTPServer interface - dispatcher = self.find_handler(request) - return dispatcher.execute() - - def find_handler( - self, request: httputil.HTTPServerRequest, **kwargs: Any - ) -> "_HandlerDelegate": - route = self.default_router.find_handler(request) - if route is not None: - return cast("_HandlerDelegate", route) - - if self.settings.get("default_handler_class"): - return self.get_handler_delegate( - request, - self.settings["default_handler_class"], - self.settings.get("default_handler_args", {}), - ) - - return self.get_handler_delegate(request, ErrorHandler, {"status_code": 404}) - - def get_handler_delegate( - self, - request: httputil.HTTPServerRequest, - target_class: Type[RequestHandler], - target_kwargs: Optional[Dict[str, Any]] = None, - path_args: Optional[List[bytes]] = None, - path_kwargs: Optional[Dict[str, bytes]] = None, - ) -> "_HandlerDelegate": - """Returns `~.httputil.HTTPMessageDelegate` that can serve a request - for application and `RequestHandler` subclass. - - :arg httputil.HTTPServerRequest request: current HTTP request. - :arg RequestHandler target_class: a `RequestHandler` class. - :arg dict target_kwargs: keyword arguments for ``target_class`` constructor. - :arg list path_args: positional arguments for ``target_class`` HTTP method that - will be executed while handling a request (``get``, ``post`` or any other). - :arg dict path_kwargs: keyword arguments for ``target_class`` HTTP method. - """ - return _HandlerDelegate( - self, request, target_class, target_kwargs, path_args, path_kwargs - ) - - def reverse_url(self, name: str, *args: Any) -> str: - """Returns a URL path for handler named ``name`` - - The handler must be added to the application as a named `URLSpec`. - - Args will be substituted for capturing groups in the `URLSpec` regex. - They will be converted to strings if necessary, encoded as utf8, - and url-escaped. - """ - reversed_url = self.default_router.reverse_url(name, *args) - if reversed_url is not None: - return reversed_url - - raise KeyError("%s not found in named urls" % name) - - def log_request(self, handler: RequestHandler) -> None: - """Writes a completed HTTP request to the logs. - - By default writes to the python root logger. To change - this behavior either subclass Application and override this method, - or pass a function in the application settings dictionary as - ``log_function``. - """ - if "log_function" in self.settings: - self.settings["log_function"](handler) - return - if handler.get_status() < 400: - log_method = access_log.info - elif handler.get_status() < 500: - log_method = access_log.warning - else: - log_method = access_log.error - request_time = 1000.0 * handler.request.request_time() - log_method( - "%d %s %.2fms", - handler.get_status(), - handler._request_summary(), - request_time, - ) - - -class _HandlerDelegate(httputil.HTTPMessageDelegate): - def __init__( - self, - application: Application, - request: httputil.HTTPServerRequest, - handler_class: Type[RequestHandler], - handler_kwargs: Optional[Dict[str, Any]], - path_args: Optional[List[bytes]], - path_kwargs: Optional[Dict[str, bytes]], - ) -> None: - self.application = application - self.connection = request.connection - self.request = request - self.handler_class = handler_class - self.handler_kwargs = handler_kwargs or {} - self.path_args = path_args or [] - self.path_kwargs = path_kwargs or {} - self.chunks = [] # type: List[bytes] - self.stream_request_body = _has_stream_request_body(self.handler_class) - - def headers_received( - self, - start_line: Union[httputil.RequestStartLine, httputil.ResponseStartLine], - headers: httputil.HTTPHeaders, - ) -> Optional[Awaitable[None]]: - if self.stream_request_body: - self.request._body_future = Future() - return self.execute() - return None - - def data_received(self, data: bytes) -> Optional[Awaitable[None]]: - if self.stream_request_body: - return self.handler.data_received(data) - else: - self.chunks.append(data) - return None - - def finish(self) -> None: - if self.stream_request_body: - future_set_result_unless_cancelled(self.request._body_future, None) - else: - self.request.body = b"".join(self.chunks) - self.request._parse_body() - self.execute() - - def on_connection_close(self) -> None: - if self.stream_request_body: - self.handler.on_connection_close() - else: - self.chunks = None # type: ignore - - def execute(self) -> Optional[Awaitable[None]]: - # If template cache is disabled (usually in the debug mode), - # re-compile templates and reload static files on every - # request so you don't need to restart to see changes - if not self.application.settings.get("compiled_template_cache", True): - with RequestHandler._template_loader_lock: - for loader in RequestHandler._template_loaders.values(): - loader.reset() - if not self.application.settings.get("static_hash_cache", True): - StaticFileHandler.reset() - - self.handler = self.handler_class( - self.application, self.request, **self.handler_kwargs - ) - transforms = [t(self.request) for t in self.application.transforms] - - if self.stream_request_body: - self.handler._prepared_future = Future() - # Note that if an exception escapes handler._execute it will be - # trapped in the Future it returns (which we are ignoring here, - # leaving it to be logged when the Future is GC'd). - # However, that shouldn't happen because _execute has a blanket - # except handler, and we cannot easily access the IOLoop here to - # call add_future (because of the requirement to remain compatible - # with WSGI) - fut = gen.convert_yielded( - self.handler._execute(transforms, *self.path_args, **self.path_kwargs) - ) - fut.add_done_callback(lambda f: f.result()) - # If we are streaming the request body, then execute() is finished - # when the handler has prepared to receive the body. If not, - # it doesn't matter when execute() finishes (so we return None) - return self.handler._prepared_future - - -class HTTPError(Exception): - """An exception that will turn into an HTTP error response. - - Raising an `HTTPError` is a convenient alternative to calling - `RequestHandler.send_error` since it automatically ends the - current function. - - To customize the response sent with an `HTTPError`, override - `RequestHandler.write_error`. - - :arg int status_code: HTTP status code. Must be listed in - `httplib.responses <http.client.responses>` unless the ``reason`` - keyword argument is given. - :arg str log_message: Message to be written to the log for this error - (will not be shown to the user unless the `Application` is in debug - mode). May contain ``%s``-style placeholders, which will be filled - in with remaining positional parameters. - :arg str reason: Keyword-only argument. The HTTP "reason" phrase - to pass in the status line along with ``status_code``. Normally - determined automatically from ``status_code``, but can be used - to use a non-standard numeric code. - """ - - def __init__( - self, - status_code: int = 500, - log_message: Optional[str] = None, - *args: Any, - **kwargs: Any - ) -> None: - self.status_code = status_code - self.log_message = log_message - self.args = args - self.reason = kwargs.get("reason", None) - if log_message and not args: - self.log_message = log_message.replace("%", "%%") - - def __str__(self) -> str: - message = "HTTP %d: %s" % ( - self.status_code, - self.reason or httputil.responses.get(self.status_code, "Unknown"), - ) - if self.log_message: - return message + " (" + (self.log_message % self.args) + ")" - else: - return message - - -class Finish(Exception): - """An exception that ends the request without producing an error response. - - When `Finish` is raised in a `RequestHandler`, the request will - end (calling `RequestHandler.finish` if it hasn't already been - called), but the error-handling methods (including - `RequestHandler.write_error`) will not be called. - - If `Finish()` was created with no arguments, the pending response - will be sent as-is. If `Finish()` was given an argument, that - argument will be passed to `RequestHandler.finish()`. - - This can be a more convenient way to implement custom error pages - than overriding ``write_error`` (especially in library code):: - - if self.current_user is None: - self.set_status(401) - self.set_header('WWW-Authenticate', 'Basic realm="something"') - raise Finish() - - .. versionchanged:: 4.3 - Arguments passed to ``Finish()`` will be passed on to - `RequestHandler.finish`. - """ - - pass - - -class MissingArgumentError(HTTPError): - """Exception raised by `RequestHandler.get_argument`. - - This is a subclass of `HTTPError`, so if it is uncaught a 400 response - code will be used instead of 500 (and a stack trace will not be logged). - - .. versionadded:: 3.1 - """ - - def __init__(self, arg_name: str) -> None: - super().__init__(400, "Missing argument %s" % arg_name) - self.arg_name = arg_name - - -class ErrorHandler(RequestHandler): - """Generates an error response with ``status_code`` for all requests.""" - - def initialize(self, status_code: int) -> None: - self.set_status(status_code) - - def prepare(self) -> None: - raise HTTPError(self._status_code) - - def check_xsrf_cookie(self) -> None: - # POSTs to an ErrorHandler don't actually have side effects, - # so we don't need to check the xsrf token. This allows POSTs - # to the wrong url to return a 404 instead of 403. - pass - - -class RedirectHandler(RequestHandler): - """Redirects the client to the given URL for all GET requests. - - You should provide the keyword argument ``url`` to the handler, e.g.:: - - application = web.Application([ - (r"/oldpath", web.RedirectHandler, {"url": "/newpath"}), - ]) - - `RedirectHandler` supports regular expression substitutions. E.g., to - swap the first and second parts of a path while preserving the remainder:: - - application = web.Application([ - (r"/(.*?)/(.*?)/(.*)", web.RedirectHandler, {"url": "/{1}/{0}/{2}"}), - ]) - - The final URL is formatted with `str.format` and the substrings that match - the capturing groups. In the above example, a request to "/a/b/c" would be - formatted like:: - - str.format("/{1}/{0}/{2}", "a", "b", "c") # -> "/b/a/c" - - Use Python's :ref:`format string syntax <formatstrings>` to customize how - values are substituted. - - .. versionchanged:: 4.5 - Added support for substitutions into the destination URL. - - .. versionchanged:: 5.0 - If any query arguments are present, they will be copied to the - destination URL. - """ - - def initialize(self, url: str, permanent: bool = True) -> None: - self._url = url - self._permanent = permanent - - def get(self, *args: Any, **kwargs: Any) -> None: - to_url = self._url.format(*args, **kwargs) - if self.request.query_arguments: - # TODO: figure out typing for the next line. - to_url = httputil.url_concat( - to_url, - list(httputil.qs_to_qsl(self.request.query_arguments)), # type: ignore - ) - self.redirect(to_url, permanent=self._permanent) - - -class StaticFileHandler(RequestHandler): - """A simple handler that can serve static content from a directory. - - A `StaticFileHandler` is configured automatically if you pass the - ``static_path`` keyword argument to `Application`. This handler - can be customized with the ``static_url_prefix``, ``static_handler_class``, - and ``static_handler_args`` settings. - - To map an additional path to this handler for a static data directory - you would add a line to your application like:: - - application = web.Application([ - (r"/content/(.*)", web.StaticFileHandler, {"path": "/var/www"}), - ]) - - The handler constructor requires a ``path`` argument, which specifies the - local root directory of the content to be served. - - Note that a capture group in the regex is required to parse the value for - the ``path`` argument to the get() method (different than the constructor - argument above); see `URLSpec` for details. - - To serve a file like ``index.html`` automatically when a directory is - requested, set ``static_handler_args=dict(default_filename="index.html")`` - in your application settings, or add ``default_filename`` as an initializer - argument for your ``StaticFileHandler``. - - To maximize the effectiveness of browser caching, this class supports - versioned urls (by default using the argument ``?v=``). If a version - is given, we instruct the browser to cache this file indefinitely. - `make_static_url` (also available as `RequestHandler.static_url`) can - be used to construct a versioned url. - - This handler is intended primarily for use in development and light-duty - file serving; for heavy traffic it will be more efficient to use - a dedicated static file server (such as nginx or Apache). We support - the HTTP ``Accept-Ranges`` mechanism to return partial content (because - some browsers require this functionality to be present to seek in - HTML5 audio or video). - - **Subclassing notes** - - This class is designed to be extensible by subclassing, but because - of the way static urls are generated with class methods rather than - instance methods, the inheritance patterns are somewhat unusual. - Be sure to use the ``@classmethod`` decorator when overriding a - class method. Instance methods may use the attributes ``self.path`` - ``self.absolute_path``, and ``self.modified``. - - Subclasses should only override methods discussed in this section; - overriding other methods is error-prone. Overriding - ``StaticFileHandler.get`` is particularly problematic due to the - tight coupling with ``compute_etag`` and other methods. - - To change the way static urls are generated (e.g. to match the behavior - of another server or CDN), override `make_static_url`, `parse_url_path`, - `get_cache_time`, and/or `get_version`. - - To replace all interaction with the filesystem (e.g. to serve - static content from a database), override `get_content`, - `get_content_size`, `get_modified_time`, `get_absolute_path`, and - `validate_absolute_path`. - - .. versionchanged:: 3.1 - Many of the methods for subclasses were added in Tornado 3.1. - """ - - CACHE_MAX_AGE = 86400 * 365 * 10 # 10 years - - _static_hashes = {} # type: Dict[str, Optional[str]] - _lock = threading.Lock() # protects _static_hashes - - def initialize(self, path: str, default_filename: Optional[str] = None) -> None: - self.root = path - self.default_filename = default_filename - - @classmethod - def reset(cls) -> None: - with cls._lock: - cls._static_hashes = {} - - def head(self, path: str) -> Awaitable[None]: - return self.get(path, include_body=False) - - async def get(self, path: str, include_body: bool = True) -> None: - # Set up our path instance variables. - self.path = self.parse_url_path(path) - del path # make sure we don't refer to path instead of self.path again - absolute_path = self.get_absolute_path(self.root, self.path) - self.absolute_path = self.validate_absolute_path(self.root, absolute_path) - if self.absolute_path is None: - return - - self.modified = self.get_modified_time() - self.set_headers() - - if self.should_return_304(): - self.set_status(304) - return - - request_range = None - range_header = self.request.headers.get("Range") - if range_header: - # As per RFC 2616 14.16, if an invalid Range header is specified, - # the request will be treated as if the header didn't exist. - request_range = httputil._parse_request_range(range_header) - - size = self.get_content_size() - if request_range: - start, end = request_range - if start is not None and start < 0: - start += size - if start < 0: - start = 0 - if ( - start is not None - and (start >= size or (end is not None and start >= end)) - ) or end == 0: - # As per RFC 2616 14.35.1, a range is not satisfiable only: if - # the first requested byte is equal to or greater than the - # content, or when a suffix with length 0 is specified. - # https://tools.ietf.org/html/rfc7233#section-2.1 - # A byte-range-spec is invalid if the last-byte-pos value is present - # and less than the first-byte-pos. - self.set_status(416) # Range Not Satisfiable - self.set_header("Content-Type", "text/plain") - self.set_header("Content-Range", "bytes */%s" % (size,)) - return - if end is not None and end > size: - # Clients sometimes blindly use a large range to limit their - # download size; cap the endpoint at the actual file size. - end = size - # Note: only return HTTP 206 if less than the entire range has been - # requested. Not only is this semantically correct, but Chrome - # refuses to play audio if it gets an HTTP 206 in response to - # ``Range: bytes=0-``. - if size != (end or size) - (start or 0): - self.set_status(206) # Partial Content - self.set_header( - "Content-Range", httputil._get_content_range(start, end, size) - ) - else: - start = end = None - - if start is not None and end is not None: - content_length = end - start - elif end is not None: - content_length = end - elif start is not None: - content_length = size - start - else: - content_length = size - self.set_header("Content-Length", content_length) - - if include_body: - content = self.get_content(self.absolute_path, start, end) - if isinstance(content, bytes): - content = [content] - for chunk in content: - try: - self.write(chunk) - await self.flush() - except iostream.StreamClosedError: - return - else: - assert self.request.method == "HEAD" - - def compute_etag(self) -> Optional[str]: - """Sets the ``Etag`` header based on static url version. - - This allows efficient ``If-None-Match`` checks against cached - versions, and sends the correct ``Etag`` for a partial response - (i.e. the same ``Etag`` as the full file). - - .. versionadded:: 3.1 - """ - assert self.absolute_path is not None - version_hash = self._get_cached_version(self.absolute_path) - if not version_hash: - return None - return '"%s"' % (version_hash,) - - def set_headers(self) -> None: - """Sets the content and caching headers on the response. - - .. versionadded:: 3.1 - """ - self.set_header("Accept-Ranges", "bytes") - self.set_etag_header() - - if self.modified is not None: - self.set_header("Last-Modified", self.modified) - - content_type = self.get_content_type() - if content_type: - self.set_header("Content-Type", content_type) - - cache_time = self.get_cache_time(self.path, self.modified, content_type) - if cache_time > 0: - self.set_header( - "Expires", - datetime.datetime.utcnow() + datetime.timedelta(seconds=cache_time), - ) - self.set_header("Cache-Control", "max-age=" + str(cache_time)) - - self.set_extra_headers(self.path) - - def should_return_304(self) -> bool: - """Returns True if the headers indicate that we should return 304. - - .. versionadded:: 3.1 - """ - # If client sent If-None-Match, use it, ignore If-Modified-Since - if self.request.headers.get("If-None-Match"): - return self.check_etag_header() - - # Check the If-Modified-Since, and don't send the result if the - # content has not been modified - ims_value = self.request.headers.get("If-Modified-Since") - if ims_value is not None: - date_tuple = email.utils.parsedate(ims_value) - if date_tuple is not None: - if_since = datetime.datetime(*date_tuple[:6]) - assert self.modified is not None - if if_since >= self.modified: - return True - - return False - - @classmethod - def get_absolute_path(cls, root: str, path: str) -> str: - """Returns the absolute location of ``path`` relative to ``root``. - - ``root`` is the path configured for this `StaticFileHandler` - (in most cases the ``static_path`` `Application` setting). - - This class method may be overridden in subclasses. By default - it returns a filesystem path, but other strings may be used - as long as they are unique and understood by the subclass's - overridden `get_content`. - - .. versionadded:: 3.1 - """ - abspath = os.path.abspath(os.path.join(root, path)) - return abspath - - def validate_absolute_path(self, root: str, absolute_path: str) -> Optional[str]: - """Validate and return the absolute path. - - ``root`` is the configured path for the `StaticFileHandler`, - and ``path`` is the result of `get_absolute_path` - - This is an instance method called during request processing, - so it may raise `HTTPError` or use methods like - `RequestHandler.redirect` (return None after redirecting to - halt further processing). This is where 404 errors for missing files - are generated. - - This method may modify the path before returning it, but note that - any such modifications will not be understood by `make_static_url`. - - In instance methods, this method's result is available as - ``self.absolute_path``. - - .. versionadded:: 3.1 - """ - # os.path.abspath strips a trailing /. - # We must add it back to `root` so that we only match files - # in a directory named `root` instead of files starting with - # that prefix. - root = os.path.abspath(root) - if not root.endswith(os.path.sep): - # abspath always removes a trailing slash, except when - # root is '/'. This is an unusual case, but several projects - # have independently discovered this technique to disable - # Tornado's path validation and (hopefully) do their own, - # so we need to support it. - root += os.path.sep - # The trailing slash also needs to be temporarily added back - # the requested path so a request to root/ will match. - if not (absolute_path + os.path.sep).startswith(root): - raise HTTPError(403, "%s is not in root static directory", self.path) - if os.path.isdir(absolute_path) and self.default_filename is not None: - # need to look at the request.path here for when path is empty - # but there is some prefix to the path that was already - # trimmed by the routing - if not self.request.path.endswith("/"): - self.redirect(self.request.path + "/", permanent=True) - return None - absolute_path = os.path.join(absolute_path, self.default_filename) - if not os.path.exists(absolute_path): - raise HTTPError(404) - if not os.path.isfile(absolute_path): - raise HTTPError(403, "%s is not a file", self.path) - return absolute_path - - @classmethod - def get_content( - cls, abspath: str, start: Optional[int] = None, end: Optional[int] = None - ) -> Generator[bytes, None, None]: - """Retrieve the content of the requested resource which is located - at the given absolute path. - - This class method may be overridden by subclasses. Note that its - signature is different from other overridable class methods - (no ``settings`` argument); this is deliberate to ensure that - ``abspath`` is able to stand on its own as a cache key. - - This method should either return a byte string or an iterator - of byte strings. The latter is preferred for large files - as it helps reduce memory fragmentation. - - .. versionadded:: 3.1 - """ - with open(abspath, "rb") as file: - if start is not None: - file.seek(start) - if end is not None: - remaining = end - (start or 0) # type: Optional[int] - else: - remaining = None - while True: - chunk_size = 64 * 1024 - if remaining is not None and remaining < chunk_size: - chunk_size = remaining - chunk = file.read(chunk_size) - if chunk: - if remaining is not None: - remaining -= len(chunk) - yield chunk - else: - if remaining is not None: - assert remaining == 0 - return - - @classmethod - def get_content_version(cls, abspath: str) -> str: - """Returns a version string for the resource at the given path. - - This class method may be overridden by subclasses. The - default implementation is a SHA-512 hash of the file's contents. - - .. versionadded:: 3.1 - """ - data = cls.get_content(abspath) - hasher = hashlib.sha512() - if isinstance(data, bytes): - hasher.update(data) - else: - for chunk in data: - hasher.update(chunk) - return hasher.hexdigest() - - def _stat(self) -> os.stat_result: - assert self.absolute_path is not None - if not hasattr(self, "_stat_result"): - self._stat_result = os.stat(self.absolute_path) - return self._stat_result - - def get_content_size(self) -> int: - """Retrieve the total size of the resource at the given path. - - This method may be overridden by subclasses. - - .. versionadded:: 3.1 - - .. versionchanged:: 4.0 - This method is now always called, instead of only when - partial results are requested. - """ - stat_result = self._stat() - return stat_result.st_size - - def get_modified_time(self) -> Optional[datetime.datetime]: - """Returns the time that ``self.absolute_path`` was last modified. - - May be overridden in subclasses. Should return a `~datetime.datetime` - object or None. - - .. versionadded:: 3.1 - """ - stat_result = self._stat() - # NOTE: Historically, this used stat_result[stat.ST_MTIME], - # which truncates the fractional portion of the timestamp. It - # was changed from that form to stat_result.st_mtime to - # satisfy mypy (which disallows the bracket operator), but the - # latter form returns a float instead of an int. For - # consistency with the past (and because we have a unit test - # that relies on this), we truncate the float here, although - # I'm not sure that's the right thing to do. - modified = datetime.datetime.utcfromtimestamp(int(stat_result.st_mtime)) - return modified - - def get_content_type(self) -> str: - """Returns the ``Content-Type`` header to be used for this request. - - .. versionadded:: 3.1 - """ - assert self.absolute_path is not None - mime_type, encoding = mimetypes.guess_type(self.absolute_path) - # per RFC 6713, use the appropriate type for a gzip compressed file - if encoding == "gzip": - return "application/gzip" - # As of 2015-07-21 there is no bzip2 encoding defined at - # http://www.iana.org/assignments/media-types/media-types.xhtml - # So for that (and any other encoding), use octet-stream. - elif encoding is not None: - return "application/octet-stream" - elif mime_type is not None: - return mime_type - # if mime_type not detected, use application/octet-stream - else: - return "application/octet-stream" - - def set_extra_headers(self, path: str) -> None: - """For subclass to add extra headers to the response""" - pass - - def get_cache_time( - self, path: str, modified: Optional[datetime.datetime], mime_type: str - ) -> int: - """Override to customize cache control behavior. - - Return a positive number of seconds to make the result - cacheable for that amount of time or 0 to mark resource as - cacheable for an unspecified amount of time (subject to - browser heuristics). - - By default returns cache expiry of 10 years for resources requested - with ``v`` argument. - """ - return self.CACHE_MAX_AGE if "v" in self.request.arguments else 0 - - @classmethod - def make_static_url( - cls, settings: Dict[str, Any], path: str, include_version: bool = True - ) -> str: - """Constructs a versioned url for the given path. - - This method may be overridden in subclasses (but note that it - is a class method rather than an instance method). Subclasses - are only required to implement the signature - ``make_static_url(cls, settings, path)``; other keyword - arguments may be passed through `~RequestHandler.static_url` - but are not standard. - - ``settings`` is the `Application.settings` dictionary. ``path`` - is the static path being requested. The url returned should be - relative to the current host. - - ``include_version`` determines whether the generated URL should - include the query string containing the version hash of the - file corresponding to the given ``path``. - - """ - url = settings.get("static_url_prefix", "/static/") + path - if not include_version: - return url - - version_hash = cls.get_version(settings, path) - if not version_hash: - return url - - return "%s?v=%s" % (url, version_hash) - - def parse_url_path(self, url_path: str) -> str: - """Converts a static URL path into a filesystem path. - - ``url_path`` is the path component of the URL with - ``static_url_prefix`` removed. The return value should be - filesystem path relative to ``static_path``. - - This is the inverse of `make_static_url`. - """ - if os.path.sep != "/": - url_path = url_path.replace("/", os.path.sep) - return url_path - - @classmethod - def get_version(cls, settings: Dict[str, Any], path: str) -> Optional[str]: - """Generate the version string to be used in static URLs. - - ``settings`` is the `Application.settings` dictionary and ``path`` - is the relative location of the requested asset on the filesystem. - The returned value should be a string, or ``None`` if no version - could be determined. - - .. versionchanged:: 3.1 - This method was previously recommended for subclasses to override; - `get_content_version` is now preferred as it allows the base - class to handle caching of the result. - """ - abs_path = cls.get_absolute_path(settings["static_path"], path) - return cls._get_cached_version(abs_path) - - @classmethod - def _get_cached_version(cls, abs_path: str) -> Optional[str]: - with cls._lock: - hashes = cls._static_hashes - if abs_path not in hashes: - try: - hashes[abs_path] = cls.get_content_version(abs_path) - except Exception: - gen_log.error("Could not open static file %r", abs_path) - hashes[abs_path] = None - hsh = hashes.get(abs_path) - if hsh: - return hsh - return None - - -class FallbackHandler(RequestHandler): - """A `RequestHandler` that wraps another HTTP server callback. - - The fallback is a callable object that accepts an - `~.httputil.HTTPServerRequest`, such as an `Application` or - `tornado.wsgi.WSGIContainer`. This is most useful to use both - Tornado ``RequestHandlers`` and WSGI in the same server. Typical - usage:: - - wsgi_app = tornado.wsgi.WSGIContainer( - django.core.handlers.wsgi.WSGIHandler()) - application = tornado.web.Application([ - (r"/foo", FooHandler), - (r".*", FallbackHandler, dict(fallback=wsgi_app), - ]) - """ - - def initialize( - self, fallback: Callable[[httputil.HTTPServerRequest], None] - ) -> None: - self.fallback = fallback - - def prepare(self) -> None: - self.fallback(self.request) - self._finished = True - self.on_finish() - - -class OutputTransform(object): - """A transform modifies the result of an HTTP request (e.g., GZip encoding) - - Applications are not expected to create their own OutputTransforms - or interact with them directly; the framework chooses which transforms - (if any) to apply. - """ - - def __init__(self, request: httputil.HTTPServerRequest) -> None: - pass - - def transform_first_chunk( - self, - status_code: int, - headers: httputil.HTTPHeaders, - chunk: bytes, - finishing: bool, - ) -> Tuple[int, httputil.HTTPHeaders, bytes]: - return status_code, headers, chunk - - def transform_chunk(self, chunk: bytes, finishing: bool) -> bytes: - return chunk - - -class GZipContentEncoding(OutputTransform): - """Applies the gzip content encoding to the response. - - See http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.11 - - .. versionchanged:: 4.0 - Now compresses all mime types beginning with ``text/``, instead - of just a whitelist. (the whitelist is still used for certain - non-text mime types). - """ - - # Whitelist of compressible mime types (in addition to any types - # beginning with "text/"). - CONTENT_TYPES = set( - [ - "application/javascript", - "application/x-javascript", - "application/xml", - "application/atom+xml", - "application/json", - "application/xhtml+xml", - "image/svg+xml", - ] - ) - # Python's GzipFile defaults to level 9, while most other gzip - # tools (including gzip itself) default to 6, which is probably a - # better CPU/size tradeoff. - GZIP_LEVEL = 6 - # Responses that are too short are unlikely to benefit from gzipping - # after considering the "Content-Encoding: gzip" header and the header - # inside the gzip encoding. - # Note that responses written in multiple chunks will be compressed - # regardless of size. - MIN_LENGTH = 1024 - - def __init__(self, request: httputil.HTTPServerRequest) -> None: - self._gzipping = "gzip" in request.headers.get("Accept-Encoding", "") - - def _compressible_type(self, ctype: str) -> bool: - return ctype.startswith("text/") or ctype in self.CONTENT_TYPES - - def transform_first_chunk( - self, - status_code: int, - headers: httputil.HTTPHeaders, - chunk: bytes, - finishing: bool, - ) -> Tuple[int, httputil.HTTPHeaders, bytes]: - # TODO: can/should this type be inherited from the superclass? - if "Vary" in headers: - headers["Vary"] += ", Accept-Encoding" - else: - headers["Vary"] = "Accept-Encoding" - if self._gzipping: - ctype = _unicode(headers.get("Content-Type", "")).split(";")[0] - self._gzipping = ( - self._compressible_type(ctype) - and (not finishing or len(chunk) >= self.MIN_LENGTH) - and ("Content-Encoding" not in headers) - ) - if self._gzipping: - headers["Content-Encoding"] = "gzip" - self._gzip_value = BytesIO() - self._gzip_file = gzip.GzipFile( - mode="w", fileobj=self._gzip_value, compresslevel=self.GZIP_LEVEL - ) - chunk = self.transform_chunk(chunk, finishing) - if "Content-Length" in headers: - # The original content length is no longer correct. - # If this is the last (and only) chunk, we can set the new - # content-length; otherwise we remove it and fall back to - # chunked encoding. - if finishing: - headers["Content-Length"] = str(len(chunk)) - else: - del headers["Content-Length"] - return status_code, headers, chunk - - def transform_chunk(self, chunk: bytes, finishing: bool) -> bytes: - if self._gzipping: - self._gzip_file.write(chunk) - if finishing: - self._gzip_file.close() - else: - self._gzip_file.flush() - chunk = self._gzip_value.getvalue() - self._gzip_value.truncate(0) - self._gzip_value.seek(0) - return chunk - - -def authenticated( - method: Callable[..., Optional[Awaitable[None]]] -) -> Callable[..., Optional[Awaitable[None]]]: - """Decorate methods with this to require that the user be logged in. - - If the user is not logged in, they will be redirected to the configured - `login url <RequestHandler.get_login_url>`. - - If you configure a login url with a query parameter, Tornado will - assume you know what you're doing and use it as-is. If not, it - will add a `next` parameter so the login page knows where to send - you once you're logged in. - """ - - @functools.wraps(method) - def wrapper( # type: ignore - self: RequestHandler, *args, **kwargs - ) -> Optional[Awaitable[None]]: - if not self.current_user: - if self.request.method in ("GET", "HEAD"): - url = self.get_login_url() - if "?" not in url: - if urllib.parse.urlsplit(url).scheme: - # if login url is absolute, make next absolute too - next_url = self.request.full_url() - else: - assert self.request.uri is not None - next_url = self.request.uri - url += "?" + urlencode(dict(next=next_url)) - self.redirect(url) - return None - raise HTTPError(403) - return method(self, *args, **kwargs) - - return wrapper - - -class UIModule(object): - """A re-usable, modular UI unit on a page. - - UI modules often execute additional queries, and they can include - additional CSS and JavaScript that will be included in the output - page, which is automatically inserted on page render. - - Subclasses of UIModule must override the `render` method. - """ - - def __init__(self, handler: RequestHandler) -> None: - self.handler = handler - self.request = handler.request - self.ui = handler.ui - self.locale = handler.locale - - @property - def current_user(self) -> Any: - return self.handler.current_user - - def render(self, *args: Any, **kwargs: Any) -> str: - """Override in subclasses to return this module's output.""" - raise NotImplementedError() - - def embedded_javascript(self) -> Optional[str]: - """Override to return a JavaScript string - to be embedded in the page.""" - return None - - def javascript_files(self) -> Optional[Iterable[str]]: - """Override to return a list of JavaScript files needed by this module. - - If the return values are relative paths, they will be passed to - `RequestHandler.static_url`; otherwise they will be used as-is. - """ - return None - - def embedded_css(self) -> Optional[str]: - """Override to return a CSS string - that will be embedded in the page.""" - return None - - def css_files(self) -> Optional[Iterable[str]]: - """Override to returns a list of CSS files required by this module. - - If the return values are relative paths, they will be passed to - `RequestHandler.static_url`; otherwise they will be used as-is. - """ - return None - - def html_head(self) -> Optional[str]: - """Override to return an HTML string that will be put in the <head/> - element. - """ - return None - - def html_body(self) -> Optional[str]: - """Override to return an HTML string that will be put at the end of - the <body/> element. - """ - return None - - def render_string(self, path: str, **kwargs: Any) -> bytes: - """Renders a template and returns it as a string.""" - return self.handler.render_string(path, **kwargs) - - -class _linkify(UIModule): - def render(self, text: str, **kwargs: Any) -> str: # type: ignore - return escape.linkify(text, **kwargs) - - -class _xsrf_form_html(UIModule): - def render(self) -> str: # type: ignore - return self.handler.xsrf_form_html() - - -class TemplateModule(UIModule): - """UIModule that simply renders the given template. - - {% module Template("foo.html") %} is similar to {% include "foo.html" %}, - but the module version gets its own namespace (with kwargs passed to - Template()) instead of inheriting the outer template's namespace. - - Templates rendered through this module also get access to UIModule's - automatic JavaScript/CSS features. Simply call set_resources - inside the template and give it keyword arguments corresponding to - the methods on UIModule: {{ set_resources(js_files=static_url("my.js")) }} - Note that these resources are output once per template file, not once - per instantiation of the template, so they must not depend on - any arguments to the template. - """ - - def __init__(self, handler: RequestHandler) -> None: - super().__init__(handler) - # keep resources in both a list and a dict to preserve order - self._resource_list = [] # type: List[Dict[str, Any]] - self._resource_dict = {} # type: Dict[str, Dict[str, Any]] - - def render(self, path: str, **kwargs: Any) -> bytes: # type: ignore - def set_resources(**kwargs) -> str: # type: ignore - if path not in self._resource_dict: - self._resource_list.append(kwargs) - self._resource_dict[path] = kwargs - else: - if self._resource_dict[path] != kwargs: - raise ValueError( - "set_resources called with different " - "resources for the same template" - ) - return "" - - return self.render_string(path, set_resources=set_resources, **kwargs) - - def _get_resources(self, key: str) -> Iterable[str]: - return (r[key] for r in self._resource_list if key in r) - - def embedded_javascript(self) -> str: - return "\n".join(self._get_resources("embedded_javascript")) - - def javascript_files(self) -> Iterable[str]: - result = [] - for f in self._get_resources("javascript_files"): - if isinstance(f, (unicode_type, bytes)): - result.append(f) - else: - result.extend(f) - return result - - def embedded_css(self) -> str: - return "\n".join(self._get_resources("embedded_css")) - - def css_files(self) -> Iterable[str]: - result = [] - for f in self._get_resources("css_files"): - if isinstance(f, (unicode_type, bytes)): - result.append(f) - else: - result.extend(f) - return result - - def html_head(self) -> str: - return "".join(self._get_resources("html_head")) - - def html_body(self) -> str: - return "".join(self._get_resources("html_body")) - - -class _UIModuleNamespace(object): - """Lazy namespace which creates UIModule proxies bound to a handler.""" - - def __init__( - self, handler: RequestHandler, ui_modules: Dict[str, Type[UIModule]] - ) -> None: - self.handler = handler - self.ui_modules = ui_modules - - def __getitem__(self, key: str) -> Callable[..., str]: - return self.handler._ui_module(key, self.ui_modules[key]) - - def __getattr__(self, key: str) -> Callable[..., str]: - try: - return self[key] - except KeyError as e: - raise AttributeError(str(e)) - - -def create_signed_value( - secret: _CookieSecretTypes, - name: str, - value: Union[str, bytes], - version: Optional[int] = None, - clock: Optional[Callable[[], float]] = None, - key_version: Optional[int] = None, -) -> bytes: - if version is None: - version = DEFAULT_SIGNED_VALUE_VERSION - if clock is None: - clock = time.time - - timestamp = utf8(str(int(clock()))) - value = base64.b64encode(utf8(value)) - if version == 1: - assert not isinstance(secret, dict) - signature = _create_signature_v1(secret, name, value, timestamp) - value = b"|".join([value, timestamp, signature]) - return value - elif version == 2: - # The v2 format consists of a version number and a series of - # length-prefixed fields "%d:%s", the last of which is a - # signature, all separated by pipes. All numbers are in - # decimal format with no leading zeros. The signature is an - # HMAC-SHA256 of the whole string up to that point, including - # the final pipe. - # - # The fields are: - # - format version (i.e. 2; no length prefix) - # - key version (integer, default is 0) - # - timestamp (integer seconds since epoch) - # - name (not encoded; assumed to be ~alphanumeric) - # - value (base64-encoded) - # - signature (hex-encoded; no length prefix) - def format_field(s: Union[str, bytes]) -> bytes: - return utf8("%d:" % len(s)) + utf8(s) - - to_sign = b"|".join( - [ - b"2", - format_field(str(key_version or 0)), - format_field(timestamp), - format_field(name), - format_field(value), - b"", - ] - ) - - if isinstance(secret, dict): - assert ( - key_version is not None - ), "Key version must be set when sign key dict is used" - assert version >= 2, "Version must be at least 2 for key version support" - secret = secret[key_version] - - signature = _create_signature_v2(secret, to_sign) - return to_sign + signature - else: - raise ValueError("Unsupported version %d" % version) - - -# A leading version number in decimal -# with no leading zeros, followed by a pipe. -_signed_value_version_re = re.compile(br"^([1-9][0-9]*)\|(.*)$") - - -def _get_version(value: bytes) -> int: - # Figures out what version value is. Version 1 did not include an - # explicit version field and started with arbitrary base64 data, - # which makes this tricky. - m = _signed_value_version_re.match(value) - if m is None: - version = 1 - else: - try: - version = int(m.group(1)) - if version > 999: - # Certain payloads from the version-less v1 format may - # be parsed as valid integers. Due to base64 padding - # restrictions, this can only happen for numbers whose - # length is a multiple of 4, so we can treat all - # numbers up to 999 as versions, and for the rest we - # fall back to v1 format. - version = 1 - except ValueError: - version = 1 - return version - - -def decode_signed_value( - secret: _CookieSecretTypes, - name: str, - value: Union[None, str, bytes], - max_age_days: float = 31, - clock: Optional[Callable[[], float]] = None, - min_version: Optional[int] = None, -) -> Optional[bytes]: - if clock is None: - clock = time.time - if min_version is None: - min_version = DEFAULT_SIGNED_VALUE_MIN_VERSION - if min_version > 2: - raise ValueError("Unsupported min_version %d" % min_version) - if not value: - return None - - value = utf8(value) - version = _get_version(value) - - if version < min_version: - return None - if version == 1: - assert not isinstance(secret, dict) - return _decode_signed_value_v1(secret, name, value, max_age_days, clock) - elif version == 2: - return _decode_signed_value_v2(secret, name, value, max_age_days, clock) - else: - return None - - -def _decode_signed_value_v1( - secret: Union[str, bytes], - name: str, - value: bytes, - max_age_days: float, - clock: Callable[[], float], -) -> Optional[bytes]: - parts = utf8(value).split(b"|") - if len(parts) != 3: - return None - signature = _create_signature_v1(secret, name, parts[0], parts[1]) - if not hmac.compare_digest(parts[2], signature): - gen_log.warning("Invalid cookie signature %r", value) - return None - timestamp = int(parts[1]) - if timestamp < clock() - max_age_days * 86400: - gen_log.warning("Expired cookie %r", value) - return None - if timestamp > clock() + 31 * 86400: - # _cookie_signature does not hash a delimiter between the - # parts of the cookie, so an attacker could transfer trailing - # digits from the payload to the timestamp without altering the - # signature. For backwards compatibility, sanity-check timestamp - # here instead of modifying _cookie_signature. - gen_log.warning("Cookie timestamp in future; possible tampering %r", value) - return None - if parts[1].startswith(b"0"): - gen_log.warning("Tampered cookie %r", value) - return None - try: - return base64.b64decode(parts[0]) - except Exception: - return None - - -def _decode_fields_v2(value: bytes) -> Tuple[int, bytes, bytes, bytes, bytes]: - def _consume_field(s: bytes) -> Tuple[bytes, bytes]: - length, _, rest = s.partition(b":") - n = int(length) - field_value = rest[:n] - # In python 3, indexing bytes returns small integers; we must - # use a slice to get a byte string as in python 2. - if rest[n : n + 1] != b"|": - raise ValueError("malformed v2 signed value field") - rest = rest[n + 1 :] - return field_value, rest - - rest = value[2:] # remove version number - key_version, rest = _consume_field(rest) - timestamp, rest = _consume_field(rest) - name_field, rest = _consume_field(rest) - value_field, passed_sig = _consume_field(rest) - return int(key_version), timestamp, name_field, value_field, passed_sig - - -def _decode_signed_value_v2( - secret: _CookieSecretTypes, - name: str, - value: bytes, - max_age_days: float, - clock: Callable[[], float], -) -> Optional[bytes]: - try: - ( - key_version, - timestamp_bytes, - name_field, - value_field, - passed_sig, - ) = _decode_fields_v2(value) - except ValueError: - return None - signed_string = value[: -len(passed_sig)] - - if isinstance(secret, dict): - try: - secret = secret[key_version] - except KeyError: - return None - - expected_sig = _create_signature_v2(secret, signed_string) - if not hmac.compare_digest(passed_sig, expected_sig): - return None - if name_field != utf8(name): - return None - timestamp = int(timestamp_bytes) - if timestamp < clock() - max_age_days * 86400: - # The signature has expired. - return None - try: - return base64.b64decode(value_field) - except Exception: - return None - - -def get_signature_key_version(value: Union[str, bytes]) -> Optional[int]: - value = utf8(value) - version = _get_version(value) - if version < 2: - return None - try: - key_version, _, _, _, _ = _decode_fields_v2(value) - except ValueError: - return None - - return key_version - - -def _create_signature_v1(secret: Union[str, bytes], *parts: Union[str, bytes]) -> bytes: - hash = hmac.new(utf8(secret), digestmod=hashlib.sha1) - for part in parts: - hash.update(utf8(part)) - return utf8(hash.hexdigest()) - - -def _create_signature_v2(secret: Union[str, bytes], s: bytes) -> bytes: - hash = hmac.new(utf8(secret), digestmod=hashlib.sha256) - hash.update(utf8(s)) - return utf8(hash.hexdigest()) - - -def is_absolute(path: str) -> bool: - return any(path.startswith(x) for x in ["/", "http:", "https:"]) diff --git a/venv/lib/python3.8/site-packages/tornado/websocket.py b/venv/lib/python3.8/site-packages/tornado/websocket.py deleted file mode 100644 index eef49e7..0000000 --- a/venv/lib/python3.8/site-packages/tornado/websocket.py +++ /dev/null @@ -1,1666 +0,0 @@ -"""Implementation of the WebSocket protocol. - -`WebSockets <http://dev.w3.org/html5/websockets/>`_ allow for bidirectional -communication between the browser and server. - -WebSockets are supported in the current versions of all major browsers, -although older versions that do not support WebSockets are still in use -(refer to http://caniuse.com/websockets for details). - -This module implements the final version of the WebSocket protocol as -defined in `RFC 6455 <http://tools.ietf.org/html/rfc6455>`_. Certain -browser versions (notably Safari 5.x) implemented an earlier draft of -the protocol (known as "draft 76") and are not compatible with this module. - -.. versionchanged:: 4.0 - Removed support for the draft 76 protocol version. -""" - -import abc -import asyncio -import base64 -import hashlib -import os -import sys -import struct -import tornado.escape -import tornado.web -from urllib.parse import urlparse -import zlib - -from tornado.concurrent import Future, future_set_result_unless_cancelled -from tornado.escape import utf8, native_str, to_unicode -from tornado import gen, httpclient, httputil -from tornado.ioloop import IOLoop, PeriodicCallback -from tornado.iostream import StreamClosedError, IOStream -from tornado.log import gen_log, app_log -from tornado import simple_httpclient -from tornado.queues import Queue -from tornado.tcpclient import TCPClient -from tornado.util import _websocket_mask - -from typing import ( - TYPE_CHECKING, - cast, - Any, - Optional, - Dict, - Union, - List, - Awaitable, - Callable, - Tuple, - Type, -) -from types import TracebackType - -if TYPE_CHECKING: - from typing_extensions import Protocol - - # The zlib compressor types aren't actually exposed anywhere - # publicly, so declare protocols for the portions we use. - class _Compressor(Protocol): - def compress(self, data: bytes) -> bytes: - pass - - def flush(self, mode: int) -> bytes: - pass - - class _Decompressor(Protocol): - unconsumed_tail = b"" # type: bytes - - def decompress(self, data: bytes, max_length: int) -> bytes: - pass - - class _WebSocketDelegate(Protocol): - # The common base interface implemented by WebSocketHandler on - # the server side and WebSocketClientConnection on the client - # side. - def on_ws_connection_close( - self, close_code: Optional[int] = None, close_reason: Optional[str] = None - ) -> None: - pass - - def on_message(self, message: Union[str, bytes]) -> Optional["Awaitable[None]"]: - pass - - def on_ping(self, data: bytes) -> None: - pass - - def on_pong(self, data: bytes) -> None: - pass - - def log_exception( - self, - typ: Optional[Type[BaseException]], - value: Optional[BaseException], - tb: Optional[TracebackType], - ) -> None: - pass - - -_default_max_message_size = 10 * 1024 * 1024 - - -class WebSocketError(Exception): - pass - - -class WebSocketClosedError(WebSocketError): - """Raised by operations on a closed connection. - - .. versionadded:: 3.2 - """ - - pass - - -class _DecompressTooLargeError(Exception): - pass - - -class _WebSocketParams(object): - def __init__( - self, - ping_interval: Optional[float] = None, - ping_timeout: Optional[float] = None, - max_message_size: int = _default_max_message_size, - compression_options: Optional[Dict[str, Any]] = None, - ) -> None: - self.ping_interval = ping_interval - self.ping_timeout = ping_timeout - self.max_message_size = max_message_size - self.compression_options = compression_options - - -class WebSocketHandler(tornado.web.RequestHandler): - """Subclass this class to create a basic WebSocket handler. - - Override `on_message` to handle incoming messages, and use - `write_message` to send messages to the client. You can also - override `open` and `on_close` to handle opened and closed - connections. - - Custom upgrade response headers can be sent by overriding - `~tornado.web.RequestHandler.set_default_headers` or - `~tornado.web.RequestHandler.prepare`. - - See http://dev.w3.org/html5/websockets/ for details on the - JavaScript interface. The protocol is specified at - http://tools.ietf.org/html/rfc6455. - - Here is an example WebSocket handler that echos back all received messages - back to the client: - - .. testcode:: - - class EchoWebSocket(tornado.websocket.WebSocketHandler): - def open(self): - print("WebSocket opened") - - def on_message(self, message): - self.write_message(u"You said: " + message) - - def on_close(self): - print("WebSocket closed") - - .. testoutput:: - :hide: - - WebSockets are not standard HTTP connections. The "handshake" is - HTTP, but after the handshake, the protocol is - message-based. Consequently, most of the Tornado HTTP facilities - are not available in handlers of this type. The only communication - methods available to you are `write_message()`, `ping()`, and - `close()`. Likewise, your request handler class should implement - `open()` method rather than ``get()`` or ``post()``. - - If you map the handler above to ``/websocket`` in your application, you can - invoke it in JavaScript with:: - - var ws = new WebSocket("ws://localhost:8888/websocket"); - ws.onopen = function() { - ws.send("Hello, world"); - }; - ws.onmessage = function (evt) { - alert(evt.data); - }; - - This script pops up an alert box that says "You said: Hello, world". - - Web browsers allow any site to open a websocket connection to any other, - instead of using the same-origin policy that governs other network - access from JavaScript. This can be surprising and is a potential - security hole, so since Tornado 4.0 `WebSocketHandler` requires - applications that wish to receive cross-origin websockets to opt in - by overriding the `~WebSocketHandler.check_origin` method (see that - method's docs for details). Failure to do so is the most likely - cause of 403 errors when making a websocket connection. - - When using a secure websocket connection (``wss://``) with a self-signed - certificate, the connection from a browser may fail because it wants - to show the "accept this certificate" dialog but has nowhere to show it. - You must first visit a regular HTML page using the same certificate - to accept it before the websocket connection will succeed. - - If the application setting ``websocket_ping_interval`` has a non-zero - value, a ping will be sent periodically, and the connection will be - closed if a response is not received before the ``websocket_ping_timeout``. - - Messages larger than the ``websocket_max_message_size`` application setting - (default 10MiB) will not be accepted. - - .. versionchanged:: 4.5 - Added ``websocket_ping_interval``, ``websocket_ping_timeout``, and - ``websocket_max_message_size``. - """ - - def __init__( - self, - application: tornado.web.Application, - request: httputil.HTTPServerRequest, - **kwargs: Any - ) -> None: - super().__init__(application, request, **kwargs) - self.ws_connection = None # type: Optional[WebSocketProtocol] - self.close_code = None # type: Optional[int] - self.close_reason = None # type: Optional[str] - self.stream = None # type: Optional[IOStream] - self._on_close_called = False - - async def get(self, *args: Any, **kwargs: Any) -> None: - self.open_args = args - self.open_kwargs = kwargs - - # Upgrade header should be present and should be equal to WebSocket - if self.request.headers.get("Upgrade", "").lower() != "websocket": - self.set_status(400) - log_msg = 'Can "Upgrade" only to "WebSocket".' - self.finish(log_msg) - gen_log.debug(log_msg) - return - - # Connection header should be upgrade. - # Some proxy servers/load balancers - # might mess with it. - headers = self.request.headers - connection = map( - lambda s: s.strip().lower(), headers.get("Connection", "").split(",") - ) - if "upgrade" not in connection: - self.set_status(400) - log_msg = '"Connection" must be "Upgrade".' - self.finish(log_msg) - gen_log.debug(log_msg) - return - - # Handle WebSocket Origin naming convention differences - # The difference between version 8 and 13 is that in 8 the - # client sends a "Sec-Websocket-Origin" header and in 13 it's - # simply "Origin". - if "Origin" in self.request.headers: - origin = self.request.headers.get("Origin") - else: - origin = self.request.headers.get("Sec-Websocket-Origin", None) - - # If there was an origin header, check to make sure it matches - # according to check_origin. When the origin is None, we assume it - # did not come from a browser and that it can be passed on. - if origin is not None and not self.check_origin(origin): - self.set_status(403) - log_msg = "Cross origin websockets not allowed" - self.finish(log_msg) - gen_log.debug(log_msg) - return - - self.ws_connection = self.get_websocket_protocol() - if self.ws_connection: - await self.ws_connection.accept_connection(self) - else: - self.set_status(426, "Upgrade Required") - self.set_header("Sec-WebSocket-Version", "7, 8, 13") - - @property - def ping_interval(self) -> Optional[float]: - """The interval for websocket keep-alive pings. - - Set websocket_ping_interval = 0 to disable pings. - """ - return self.settings.get("websocket_ping_interval", None) - - @property - def ping_timeout(self) -> Optional[float]: - """If no ping is received in this many seconds, - close the websocket connection (VPNs, etc. can fail to cleanly close ws connections). - Default is max of 3 pings or 30 seconds. - """ - return self.settings.get("websocket_ping_timeout", None) - - @property - def max_message_size(self) -> int: - """Maximum allowed message size. - - If the remote peer sends a message larger than this, the connection - will be closed. - - Default is 10MiB. - """ - return self.settings.get( - "websocket_max_message_size", _default_max_message_size - ) - - def write_message( - self, message: Union[bytes, str, Dict[str, Any]], binary: bool = False - ) -> "Future[None]": - """Sends the given message to the client of this Web Socket. - - The message may be either a string or a dict (which will be - encoded as json). If the ``binary`` argument is false, the - message will be sent as utf8; in binary mode any byte string - is allowed. - - If the connection is already closed, raises `WebSocketClosedError`. - Returns a `.Future` which can be used for flow control. - - .. versionchanged:: 3.2 - `WebSocketClosedError` was added (previously a closed connection - would raise an `AttributeError`) - - .. versionchanged:: 4.3 - Returns a `.Future` which can be used for flow control. - - .. versionchanged:: 5.0 - Consistently raises `WebSocketClosedError`. Previously could - sometimes raise `.StreamClosedError`. - """ - if self.ws_connection is None or self.ws_connection.is_closing(): - raise WebSocketClosedError() - if isinstance(message, dict): - message = tornado.escape.json_encode(message) - return self.ws_connection.write_message(message, binary=binary) - - def select_subprotocol(self, subprotocols: List[str]) -> Optional[str]: - """Override to implement subprotocol negotiation. - - ``subprotocols`` is a list of strings identifying the - subprotocols proposed by the client. This method may be - overridden to return one of those strings to select it, or - ``None`` to not select a subprotocol. - - Failure to select a subprotocol does not automatically abort - the connection, although clients may close the connection if - none of their proposed subprotocols was selected. - - The list may be empty, in which case this method must return - None. This method is always called exactly once even if no - subprotocols were proposed so that the handler can be advised - of this fact. - - .. versionchanged:: 5.1 - - Previously, this method was called with a list containing - an empty string instead of an empty list if no subprotocols - were proposed by the client. - """ - return None - - @property - def selected_subprotocol(self) -> Optional[str]: - """The subprotocol returned by `select_subprotocol`. - - .. versionadded:: 5.1 - """ - assert self.ws_connection is not None - return self.ws_connection.selected_subprotocol - - def get_compression_options(self) -> Optional[Dict[str, Any]]: - """Override to return compression options for the connection. - - If this method returns None (the default), compression will - be disabled. If it returns a dict (even an empty one), it - will be enabled. The contents of the dict may be used to - control the following compression options: - - ``compression_level`` specifies the compression level. - - ``mem_level`` specifies the amount of memory used for the internal compression state. - - These parameters are documented in details here: - https://docs.python.org/3.6/library/zlib.html#zlib.compressobj - - .. versionadded:: 4.1 - - .. versionchanged:: 4.5 - - Added ``compression_level`` and ``mem_level``. - """ - # TODO: Add wbits option. - return None - - def open(self, *args: str, **kwargs: str) -> Optional[Awaitable[None]]: - """Invoked when a new WebSocket is opened. - - The arguments to `open` are extracted from the `tornado.web.URLSpec` - regular expression, just like the arguments to - `tornado.web.RequestHandler.get`. - - `open` may be a coroutine. `on_message` will not be called until - `open` has returned. - - .. versionchanged:: 5.1 - - ``open`` may be a coroutine. - """ - pass - - def on_message(self, message: Union[str, bytes]) -> Optional[Awaitable[None]]: - """Handle incoming messages on the WebSocket - - This method must be overridden. - - .. versionchanged:: 4.5 - - ``on_message`` can be a coroutine. - """ - raise NotImplementedError - - def ping(self, data: Union[str, bytes] = b"") -> None: - """Send ping frame to the remote end. - - The data argument allows a small amount of data (up to 125 - bytes) to be sent as a part of the ping message. Note that not - all websocket implementations expose this data to - applications. - - Consider using the ``websocket_ping_interval`` application - setting instead of sending pings manually. - - .. versionchanged:: 5.1 - - The data argument is now optional. - - """ - data = utf8(data) - if self.ws_connection is None or self.ws_connection.is_closing(): - raise WebSocketClosedError() - self.ws_connection.write_ping(data) - - def on_pong(self, data: bytes) -> None: - """Invoked when the response to a ping frame is received.""" - pass - - def on_ping(self, data: bytes) -> None: - """Invoked when the a ping frame is received.""" - pass - - def on_close(self) -> None: - """Invoked when the WebSocket is closed. - - If the connection was closed cleanly and a status code or reason - phrase was supplied, these values will be available as the attributes - ``self.close_code`` and ``self.close_reason``. - - .. versionchanged:: 4.0 - - Added ``close_code`` and ``close_reason`` attributes. - """ - pass - - def close(self, code: Optional[int] = None, reason: Optional[str] = None) -> None: - """Closes this Web Socket. - - Once the close handshake is successful the socket will be closed. - - ``code`` may be a numeric status code, taken from the values - defined in `RFC 6455 section 7.4.1 - <https://tools.ietf.org/html/rfc6455#section-7.4.1>`_. - ``reason`` may be a textual message about why the connection is - closing. These values are made available to the client, but are - not otherwise interpreted by the websocket protocol. - - .. versionchanged:: 4.0 - - Added the ``code`` and ``reason`` arguments. - """ - if self.ws_connection: - self.ws_connection.close(code, reason) - self.ws_connection = None - - def check_origin(self, origin: str) -> bool: - """Override to enable support for allowing alternate origins. - - The ``origin`` argument is the value of the ``Origin`` HTTP - header, the url responsible for initiating this request. This - method is not called for clients that do not send this header; - such requests are always allowed (because all browsers that - implement WebSockets support this header, and non-browser - clients do not have the same cross-site security concerns). - - Should return ``True`` to accept the request or ``False`` to - reject it. By default, rejects all requests with an origin on - a host other than this one. - - This is a security protection against cross site scripting attacks on - browsers, since WebSockets are allowed to bypass the usual same-origin - policies and don't use CORS headers. - - .. warning:: - - This is an important security measure; don't disable it - without understanding the security implications. In - particular, if your authentication is cookie-based, you - must either restrict the origins allowed by - ``check_origin()`` or implement your own XSRF-like - protection for websocket connections. See `these - <https://www.christian-schneider.net/CrossSiteWebSocketHijacking.html>`_ - `articles - <https://devcenter.heroku.com/articles/websocket-security>`_ - for more. - - To accept all cross-origin traffic (which was the default prior to - Tornado 4.0), simply override this method to always return ``True``:: - - def check_origin(self, origin): - return True - - To allow connections from any subdomain of your site, you might - do something like:: - - def check_origin(self, origin): - parsed_origin = urllib.parse.urlparse(origin) - return parsed_origin.netloc.endswith(".mydomain.com") - - .. versionadded:: 4.0 - - """ - parsed_origin = urlparse(origin) - origin = parsed_origin.netloc - origin = origin.lower() - - host = self.request.headers.get("Host") - - # Check to see that origin matches host directly, including ports - return origin == host - - def set_nodelay(self, value: bool) -> None: - """Set the no-delay flag for this stream. - - By default, small messages may be delayed and/or combined to minimize - the number of packets sent. This can sometimes cause 200-500ms delays - due to the interaction between Nagle's algorithm and TCP delayed - ACKs. To reduce this delay (at the expense of possibly increasing - bandwidth usage), call ``self.set_nodelay(True)`` once the websocket - connection is established. - - See `.BaseIOStream.set_nodelay` for additional details. - - .. versionadded:: 3.1 - """ - assert self.ws_connection is not None - self.ws_connection.set_nodelay(value) - - def on_connection_close(self) -> None: - if self.ws_connection: - self.ws_connection.on_connection_close() - self.ws_connection = None - if not self._on_close_called: - self._on_close_called = True - self.on_close() - self._break_cycles() - - def on_ws_connection_close( - self, close_code: Optional[int] = None, close_reason: Optional[str] = None - ) -> None: - self.close_code = close_code - self.close_reason = close_reason - self.on_connection_close() - - def _break_cycles(self) -> None: - # WebSocketHandlers call finish() early, but we don't want to - # break up reference cycles (which makes it impossible to call - # self.render_string) until after we've really closed the - # connection (if it was established in the first place, - # indicated by status code 101). - if self.get_status() != 101 or self._on_close_called: - super()._break_cycles() - - def send_error(self, *args: Any, **kwargs: Any) -> None: - if self.stream is None: - super().send_error(*args, **kwargs) - else: - # If we get an uncaught exception during the handshake, - # we have no choice but to abruptly close the connection. - # TODO: for uncaught exceptions after the handshake, - # we can close the connection more gracefully. - self.stream.close() - - def get_websocket_protocol(self) -> Optional["WebSocketProtocol"]: - websocket_version = self.request.headers.get("Sec-WebSocket-Version") - if websocket_version in ("7", "8", "13"): - params = _WebSocketParams( - ping_interval=self.ping_interval, - ping_timeout=self.ping_timeout, - max_message_size=self.max_message_size, - compression_options=self.get_compression_options(), - ) - return WebSocketProtocol13(self, False, params) - return None - - def _detach_stream(self) -> IOStream: - # disable non-WS methods - for method in [ - "write", - "redirect", - "set_header", - "set_cookie", - "set_status", - "flush", - "finish", - ]: - setattr(self, method, _raise_not_supported_for_websockets) - return self.detach() - - -def _raise_not_supported_for_websockets(*args: Any, **kwargs: Any) -> None: - raise RuntimeError("Method not supported for Web Sockets") - - -class WebSocketProtocol(abc.ABC): - """Base class for WebSocket protocol versions. - """ - - def __init__(self, handler: "_WebSocketDelegate") -> None: - self.handler = handler - self.stream = None # type: Optional[IOStream] - self.client_terminated = False - self.server_terminated = False - - def _run_callback( - self, callback: Callable, *args: Any, **kwargs: Any - ) -> "Optional[Future[Any]]": - """Runs the given callback with exception handling. - - If the callback is a coroutine, returns its Future. On error, aborts the - websocket connection and returns None. - """ - try: - result = callback(*args, **kwargs) - except Exception: - self.handler.log_exception(*sys.exc_info()) - self._abort() - return None - else: - if result is not None: - result = gen.convert_yielded(result) - assert self.stream is not None - self.stream.io_loop.add_future(result, lambda f: f.result()) - return result - - def on_connection_close(self) -> None: - self._abort() - - def _abort(self) -> None: - """Instantly aborts the WebSocket connection by closing the socket""" - self.client_terminated = True - self.server_terminated = True - if self.stream is not None: - self.stream.close() # forcibly tear down the connection - self.close() # let the subclass cleanup - - @abc.abstractmethod - def close(self, code: Optional[int] = None, reason: Optional[str] = None) -> None: - raise NotImplementedError() - - @abc.abstractmethod - def is_closing(self) -> bool: - raise NotImplementedError() - - @abc.abstractmethod - async def accept_connection(self, handler: WebSocketHandler) -> None: - raise NotImplementedError() - - @abc.abstractmethod - def write_message( - self, message: Union[str, bytes], binary: bool = False - ) -> "Future[None]": - raise NotImplementedError() - - @property - @abc.abstractmethod - def selected_subprotocol(self) -> Optional[str]: - raise NotImplementedError() - - @abc.abstractmethod - def write_ping(self, data: bytes) -> None: - raise NotImplementedError() - - # The entry points below are used by WebSocketClientConnection, - # which was introduced after we only supported a single version of - # WebSocketProtocol. The WebSocketProtocol/WebSocketProtocol13 - # boundary is currently pretty ad-hoc. - @abc.abstractmethod - def _process_server_headers( - self, key: Union[str, bytes], headers: httputil.HTTPHeaders - ) -> None: - raise NotImplementedError() - - @abc.abstractmethod - def start_pinging(self) -> None: - raise NotImplementedError() - - @abc.abstractmethod - async def _receive_frame_loop(self) -> None: - raise NotImplementedError() - - @abc.abstractmethod - def set_nodelay(self, x: bool) -> None: - raise NotImplementedError() - - -class _PerMessageDeflateCompressor(object): - def __init__( - self, - persistent: bool, - max_wbits: Optional[int], - compression_options: Optional[Dict[str, Any]] = None, - ) -> None: - if max_wbits is None: - max_wbits = zlib.MAX_WBITS - # There is no symbolic constant for the minimum wbits value. - if not (8 <= max_wbits <= zlib.MAX_WBITS): - raise ValueError( - "Invalid max_wbits value %r; allowed range 8-%d", - max_wbits, - zlib.MAX_WBITS, - ) - self._max_wbits = max_wbits - - if ( - compression_options is None - or "compression_level" not in compression_options - ): - self._compression_level = tornado.web.GZipContentEncoding.GZIP_LEVEL - else: - self._compression_level = compression_options["compression_level"] - - if compression_options is None or "mem_level" not in compression_options: - self._mem_level = 8 - else: - self._mem_level = compression_options["mem_level"] - - if persistent: - self._compressor = self._create_compressor() # type: Optional[_Compressor] - else: - self._compressor = None - - def _create_compressor(self) -> "_Compressor": - return zlib.compressobj( - self._compression_level, zlib.DEFLATED, -self._max_wbits, self._mem_level - ) - - def compress(self, data: bytes) -> bytes: - compressor = self._compressor or self._create_compressor() - data = compressor.compress(data) + compressor.flush(zlib.Z_SYNC_FLUSH) - assert data.endswith(b"\x00\x00\xff\xff") - return data[:-4] - - -class _PerMessageDeflateDecompressor(object): - def __init__( - self, - persistent: bool, - max_wbits: Optional[int], - max_message_size: int, - compression_options: Optional[Dict[str, Any]] = None, - ) -> None: - self._max_message_size = max_message_size - if max_wbits is None: - max_wbits = zlib.MAX_WBITS - if not (8 <= max_wbits <= zlib.MAX_WBITS): - raise ValueError( - "Invalid max_wbits value %r; allowed range 8-%d", - max_wbits, - zlib.MAX_WBITS, - ) - self._max_wbits = max_wbits - if persistent: - self._decompressor = ( - self._create_decompressor() - ) # type: Optional[_Decompressor] - else: - self._decompressor = None - - def _create_decompressor(self) -> "_Decompressor": - return zlib.decompressobj(-self._max_wbits) - - def decompress(self, data: bytes) -> bytes: - decompressor = self._decompressor or self._create_decompressor() - result = decompressor.decompress( - data + b"\x00\x00\xff\xff", self._max_message_size - ) - if decompressor.unconsumed_tail: - raise _DecompressTooLargeError() - return result - - -class WebSocketProtocol13(WebSocketProtocol): - """Implementation of the WebSocket protocol from RFC 6455. - - This class supports versions 7 and 8 of the protocol in addition to the - final version 13. - """ - - # Bit masks for the first byte of a frame. - FIN = 0x80 - RSV1 = 0x40 - RSV2 = 0x20 - RSV3 = 0x10 - RSV_MASK = RSV1 | RSV2 | RSV3 - OPCODE_MASK = 0x0F - - stream = None # type: IOStream - - def __init__( - self, - handler: "_WebSocketDelegate", - mask_outgoing: bool, - params: _WebSocketParams, - ) -> None: - WebSocketProtocol.__init__(self, handler) - self.mask_outgoing = mask_outgoing - self.params = params - self._final_frame = False - self._frame_opcode = None - self._masked_frame = None - self._frame_mask = None # type: Optional[bytes] - self._frame_length = None - self._fragmented_message_buffer = None # type: Optional[bytes] - self._fragmented_message_opcode = None - self._waiting = None # type: object - self._compression_options = params.compression_options - self._decompressor = None # type: Optional[_PerMessageDeflateDecompressor] - self._compressor = None # type: Optional[_PerMessageDeflateCompressor] - self._frame_compressed = None # type: Optional[bool] - # The total uncompressed size of all messages received or sent. - # Unicode messages are encoded to utf8. - # Only for testing; subject to change. - self._message_bytes_in = 0 - self._message_bytes_out = 0 - # The total size of all packets received or sent. Includes - # the effect of compression, frame overhead, and control frames. - self._wire_bytes_in = 0 - self._wire_bytes_out = 0 - self.ping_callback = None # type: Optional[PeriodicCallback] - self.last_ping = 0.0 - self.last_pong = 0.0 - self.close_code = None # type: Optional[int] - self.close_reason = None # type: Optional[str] - - # Use a property for this to satisfy the abc. - @property - def selected_subprotocol(self) -> Optional[str]: - return self._selected_subprotocol - - @selected_subprotocol.setter - def selected_subprotocol(self, value: Optional[str]) -> None: - self._selected_subprotocol = value - - async def accept_connection(self, handler: WebSocketHandler) -> None: - try: - self._handle_websocket_headers(handler) - except ValueError: - handler.set_status(400) - log_msg = "Missing/Invalid WebSocket headers" - handler.finish(log_msg) - gen_log.debug(log_msg) - return - - try: - await self._accept_connection(handler) - except asyncio.CancelledError: - self._abort() - return - except ValueError: - gen_log.debug("Malformed WebSocket request received", exc_info=True) - self._abort() - return - - def _handle_websocket_headers(self, handler: WebSocketHandler) -> None: - """Verifies all invariant- and required headers - - If a header is missing or have an incorrect value ValueError will be - raised - """ - fields = ("Host", "Sec-Websocket-Key", "Sec-Websocket-Version") - if not all(map(lambda f: handler.request.headers.get(f), fields)): - raise ValueError("Missing/Invalid WebSocket headers") - - @staticmethod - def compute_accept_value(key: Union[str, bytes]) -> str: - """Computes the value for the Sec-WebSocket-Accept header, - given the value for Sec-WebSocket-Key. - """ - sha1 = hashlib.sha1() - sha1.update(utf8(key)) - sha1.update(b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11") # Magic value - return native_str(base64.b64encode(sha1.digest())) - - def _challenge_response(self, handler: WebSocketHandler) -> str: - return WebSocketProtocol13.compute_accept_value( - cast(str, handler.request.headers.get("Sec-Websocket-Key")) - ) - - async def _accept_connection(self, handler: WebSocketHandler) -> None: - subprotocol_header = handler.request.headers.get("Sec-WebSocket-Protocol") - if subprotocol_header: - subprotocols = [s.strip() for s in subprotocol_header.split(",")] - else: - subprotocols = [] - self.selected_subprotocol = handler.select_subprotocol(subprotocols) - if self.selected_subprotocol: - assert self.selected_subprotocol in subprotocols - handler.set_header("Sec-WebSocket-Protocol", self.selected_subprotocol) - - extensions = self._parse_extensions_header(handler.request.headers) - for ext in extensions: - if ext[0] == "permessage-deflate" and self._compression_options is not None: - # TODO: negotiate parameters if compression_options - # specifies limits. - self._create_compressors("server", ext[1], self._compression_options) - if ( - "client_max_window_bits" in ext[1] - and ext[1]["client_max_window_bits"] is None - ): - # Don't echo an offered client_max_window_bits - # parameter with no value. - del ext[1]["client_max_window_bits"] - handler.set_header( - "Sec-WebSocket-Extensions", - httputil._encode_header("permessage-deflate", ext[1]), - ) - break - - handler.clear_header("Content-Type") - handler.set_status(101) - handler.set_header("Upgrade", "websocket") - handler.set_header("Connection", "Upgrade") - handler.set_header("Sec-WebSocket-Accept", self._challenge_response(handler)) - handler.finish() - - self.stream = handler._detach_stream() - - self.start_pinging() - try: - open_result = handler.open(*handler.open_args, **handler.open_kwargs) - if open_result is not None: - await open_result - except Exception: - handler.log_exception(*sys.exc_info()) - self._abort() - return - - await self._receive_frame_loop() - - def _parse_extensions_header( - self, headers: httputil.HTTPHeaders - ) -> List[Tuple[str, Dict[str, str]]]: - extensions = headers.get("Sec-WebSocket-Extensions", "") - if extensions: - return [httputil._parse_header(e.strip()) for e in extensions.split(",")] - return [] - - def _process_server_headers( - self, key: Union[str, bytes], headers: httputil.HTTPHeaders - ) -> None: - """Process the headers sent by the server to this client connection. - - 'key' is the websocket handshake challenge/response key. - """ - assert headers["Upgrade"].lower() == "websocket" - assert headers["Connection"].lower() == "upgrade" - accept = self.compute_accept_value(key) - assert headers["Sec-Websocket-Accept"] == accept - - extensions = self._parse_extensions_header(headers) - for ext in extensions: - if ext[0] == "permessage-deflate" and self._compression_options is not None: - self._create_compressors("client", ext[1]) - else: - raise ValueError("unsupported extension %r", ext) - - self.selected_subprotocol = headers.get("Sec-WebSocket-Protocol", None) - - def _get_compressor_options( - self, - side: str, - agreed_parameters: Dict[str, Any], - compression_options: Optional[Dict[str, Any]] = None, - ) -> Dict[str, Any]: - """Converts a websocket agreed_parameters set to keyword arguments - for our compressor objects. - """ - options = dict( - persistent=(side + "_no_context_takeover") not in agreed_parameters - ) # type: Dict[str, Any] - wbits_header = agreed_parameters.get(side + "_max_window_bits", None) - if wbits_header is None: - options["max_wbits"] = zlib.MAX_WBITS - else: - options["max_wbits"] = int(wbits_header) - options["compression_options"] = compression_options - return options - - def _create_compressors( - self, - side: str, - agreed_parameters: Dict[str, Any], - compression_options: Optional[Dict[str, Any]] = None, - ) -> None: - # TODO: handle invalid parameters gracefully - allowed_keys = set( - [ - "server_no_context_takeover", - "client_no_context_takeover", - "server_max_window_bits", - "client_max_window_bits", - ] - ) - for key in agreed_parameters: - if key not in allowed_keys: - raise ValueError("unsupported compression parameter %r" % key) - other_side = "client" if (side == "server") else "server" - self._compressor = _PerMessageDeflateCompressor( - **self._get_compressor_options(side, agreed_parameters, compression_options) - ) - self._decompressor = _PerMessageDeflateDecompressor( - max_message_size=self.params.max_message_size, - **self._get_compressor_options( - other_side, agreed_parameters, compression_options - ) - ) - - def _write_frame( - self, fin: bool, opcode: int, data: bytes, flags: int = 0 - ) -> "Future[None]": - data_len = len(data) - if opcode & 0x8: - # All control frames MUST have a payload length of 125 - # bytes or less and MUST NOT be fragmented. - if not fin: - raise ValueError("control frames may not be fragmented") - if data_len > 125: - raise ValueError("control frame payloads may not exceed 125 bytes") - if fin: - finbit = self.FIN - else: - finbit = 0 - frame = struct.pack("B", finbit | opcode | flags) - if self.mask_outgoing: - mask_bit = 0x80 - else: - mask_bit = 0 - if data_len < 126: - frame += struct.pack("B", data_len | mask_bit) - elif data_len <= 0xFFFF: - frame += struct.pack("!BH", 126 | mask_bit, data_len) - else: - frame += struct.pack("!BQ", 127 | mask_bit, data_len) - if self.mask_outgoing: - mask = os.urandom(4) - data = mask + _websocket_mask(mask, data) - frame += data - self._wire_bytes_out += len(frame) - return self.stream.write(frame) - - def write_message( - self, message: Union[str, bytes], binary: bool = False - ) -> "Future[None]": - """Sends the given message to the client of this Web Socket.""" - if binary: - opcode = 0x2 - else: - opcode = 0x1 - message = tornado.escape.utf8(message) - assert isinstance(message, bytes) - self._message_bytes_out += len(message) - flags = 0 - if self._compressor: - message = self._compressor.compress(message) - flags |= self.RSV1 - # For historical reasons, write methods in Tornado operate in a semi-synchronous - # mode in which awaiting the Future they return is optional (But errors can - # still be raised). This requires us to go through an awkward dance here - # to transform the errors that may be returned while presenting the same - # semi-synchronous interface. - try: - fut = self._write_frame(True, opcode, message, flags=flags) - except StreamClosedError: - raise WebSocketClosedError() - - async def wrapper() -> None: - try: - await fut - except StreamClosedError: - raise WebSocketClosedError() - - return asyncio.ensure_future(wrapper()) - - def write_ping(self, data: bytes) -> None: - """Send ping frame.""" - assert isinstance(data, bytes) - self._write_frame(True, 0x9, data) - - async def _receive_frame_loop(self) -> None: - try: - while not self.client_terminated: - await self._receive_frame() - except StreamClosedError: - self._abort() - self.handler.on_ws_connection_close(self.close_code, self.close_reason) - - async def _read_bytes(self, n: int) -> bytes: - data = await self.stream.read_bytes(n) - self._wire_bytes_in += n - return data - - async def _receive_frame(self) -> None: - # Read the frame header. - data = await self._read_bytes(2) - header, mask_payloadlen = struct.unpack("BB", data) - is_final_frame = header & self.FIN - reserved_bits = header & self.RSV_MASK - opcode = header & self.OPCODE_MASK - opcode_is_control = opcode & 0x8 - if self._decompressor is not None and opcode != 0: - # Compression flag is present in the first frame's header, - # but we can't decompress until we have all the frames of - # the message. - self._frame_compressed = bool(reserved_bits & self.RSV1) - reserved_bits &= ~self.RSV1 - if reserved_bits: - # client is using as-yet-undefined extensions; abort - self._abort() - return - is_masked = bool(mask_payloadlen & 0x80) - payloadlen = mask_payloadlen & 0x7F - - # Parse and validate the length. - if opcode_is_control and payloadlen >= 126: - # control frames must have payload < 126 - self._abort() - return - if payloadlen < 126: - self._frame_length = payloadlen - elif payloadlen == 126: - data = await self._read_bytes(2) - payloadlen = struct.unpack("!H", data)[0] - elif payloadlen == 127: - data = await self._read_bytes(8) - payloadlen = struct.unpack("!Q", data)[0] - new_len = payloadlen - if self._fragmented_message_buffer is not None: - new_len += len(self._fragmented_message_buffer) - if new_len > self.params.max_message_size: - self.close(1009, "message too big") - self._abort() - return - - # Read the payload, unmasking if necessary. - if is_masked: - self._frame_mask = await self._read_bytes(4) - data = await self._read_bytes(payloadlen) - if is_masked: - assert self._frame_mask is not None - data = _websocket_mask(self._frame_mask, data) - - # Decide what to do with this frame. - if opcode_is_control: - # control frames may be interleaved with a series of fragmented - # data frames, so control frames must not interact with - # self._fragmented_* - if not is_final_frame: - # control frames must not be fragmented - self._abort() - return - elif opcode == 0: # continuation frame - if self._fragmented_message_buffer is None: - # nothing to continue - self._abort() - return - self._fragmented_message_buffer += data - if is_final_frame: - opcode = self._fragmented_message_opcode - data = self._fragmented_message_buffer - self._fragmented_message_buffer = None - else: # start of new data message - if self._fragmented_message_buffer is not None: - # can't start new message until the old one is finished - self._abort() - return - if not is_final_frame: - self._fragmented_message_opcode = opcode - self._fragmented_message_buffer = data - - if is_final_frame: - handled_future = self._handle_message(opcode, data) - if handled_future is not None: - await handled_future - - def _handle_message(self, opcode: int, data: bytes) -> "Optional[Future[None]]": - """Execute on_message, returning its Future if it is a coroutine.""" - if self.client_terminated: - return None - - if self._frame_compressed: - assert self._decompressor is not None - try: - data = self._decompressor.decompress(data) - except _DecompressTooLargeError: - self.close(1009, "message too big after decompression") - self._abort() - return None - - if opcode == 0x1: - # UTF-8 data - self._message_bytes_in += len(data) - try: - decoded = data.decode("utf-8") - except UnicodeDecodeError: - self._abort() - return None - return self._run_callback(self.handler.on_message, decoded) - elif opcode == 0x2: - # Binary data - self._message_bytes_in += len(data) - return self._run_callback(self.handler.on_message, data) - elif opcode == 0x8: - # Close - self.client_terminated = True - if len(data) >= 2: - self.close_code = struct.unpack(">H", data[:2])[0] - if len(data) > 2: - self.close_reason = to_unicode(data[2:]) - # Echo the received close code, if any (RFC 6455 section 5.5.1). - self.close(self.close_code) - elif opcode == 0x9: - # Ping - try: - self._write_frame(True, 0xA, data) - except StreamClosedError: - self._abort() - self._run_callback(self.handler.on_ping, data) - elif opcode == 0xA: - # Pong - self.last_pong = IOLoop.current().time() - return self._run_callback(self.handler.on_pong, data) - else: - self._abort() - return None - - def close(self, code: Optional[int] = None, reason: Optional[str] = None) -> None: - """Closes the WebSocket connection.""" - if not self.server_terminated: - if not self.stream.closed(): - if code is None and reason is not None: - code = 1000 # "normal closure" status code - if code is None: - close_data = b"" - else: - close_data = struct.pack(">H", code) - if reason is not None: - close_data += utf8(reason) - try: - self._write_frame(True, 0x8, close_data) - except StreamClosedError: - self._abort() - self.server_terminated = True - if self.client_terminated: - if self._waiting is not None: - self.stream.io_loop.remove_timeout(self._waiting) - self._waiting = None - self.stream.close() - elif self._waiting is None: - # Give the client a few seconds to complete a clean shutdown, - # otherwise just close the connection. - self._waiting = self.stream.io_loop.add_timeout( - self.stream.io_loop.time() + 5, self._abort - ) - if self.ping_callback: - self.ping_callback.stop() - self.ping_callback = None - - def is_closing(self) -> bool: - """Return ``True`` if this connection is closing. - - The connection is considered closing if either side has - initiated its closing handshake or if the stream has been - shut down uncleanly. - """ - return self.stream.closed() or self.client_terminated or self.server_terminated - - @property - def ping_interval(self) -> Optional[float]: - interval = self.params.ping_interval - if interval is not None: - return interval - return 0 - - @property - def ping_timeout(self) -> Optional[float]: - timeout = self.params.ping_timeout - if timeout is not None: - return timeout - assert self.ping_interval is not None - return max(3 * self.ping_interval, 30) - - def start_pinging(self) -> None: - """Start sending periodic pings to keep the connection alive""" - assert self.ping_interval is not None - if self.ping_interval > 0: - self.last_ping = self.last_pong = IOLoop.current().time() - self.ping_callback = PeriodicCallback( - self.periodic_ping, self.ping_interval * 1000 - ) - self.ping_callback.start() - - def periodic_ping(self) -> None: - """Send a ping to keep the websocket alive - - Called periodically if the websocket_ping_interval is set and non-zero. - """ - if self.is_closing() and self.ping_callback is not None: - self.ping_callback.stop() - return - - # Check for timeout on pong. Make sure that we really have - # sent a recent ping in case the machine with both server and - # client has been suspended since the last ping. - now = IOLoop.current().time() - since_last_pong = now - self.last_pong - since_last_ping = now - self.last_ping - assert self.ping_interval is not None - assert self.ping_timeout is not None - if ( - since_last_ping < 2 * self.ping_interval - and since_last_pong > self.ping_timeout - ): - self.close() - return - - self.write_ping(b"") - self.last_ping = now - - def set_nodelay(self, x: bool) -> None: - self.stream.set_nodelay(x) - - -class WebSocketClientConnection(simple_httpclient._HTTPConnection): - """WebSocket client connection. - - This class should not be instantiated directly; use the - `websocket_connect` function instead. - """ - - protocol = None # type: WebSocketProtocol - - def __init__( - self, - request: httpclient.HTTPRequest, - on_message_callback: Optional[Callable[[Union[None, str, bytes]], None]] = None, - compression_options: Optional[Dict[str, Any]] = None, - ping_interval: Optional[float] = None, - ping_timeout: Optional[float] = None, - max_message_size: int = _default_max_message_size, - subprotocols: Optional[List[str]] = [], - ) -> None: - self.connect_future = Future() # type: Future[WebSocketClientConnection] - self.read_queue = Queue(1) # type: Queue[Union[None, str, bytes]] - self.key = base64.b64encode(os.urandom(16)) - self._on_message_callback = on_message_callback - self.close_code = None # type: Optional[int] - self.close_reason = None # type: Optional[str] - self.params = _WebSocketParams( - ping_interval=ping_interval, - ping_timeout=ping_timeout, - max_message_size=max_message_size, - compression_options=compression_options, - ) - - scheme, sep, rest = request.url.partition(":") - scheme = {"ws": "http", "wss": "https"}[scheme] - request.url = scheme + sep + rest - request.headers.update( - { - "Upgrade": "websocket", - "Connection": "Upgrade", - "Sec-WebSocket-Key": self.key, - "Sec-WebSocket-Version": "13", - } - ) - if subprotocols is not None: - request.headers["Sec-WebSocket-Protocol"] = ",".join(subprotocols) - if compression_options is not None: - # Always offer to let the server set our max_wbits (and even though - # we don't offer it, we will accept a client_no_context_takeover - # from the server). - # TODO: set server parameters for deflate extension - # if requested in self.compression_options. - request.headers[ - "Sec-WebSocket-Extensions" - ] = "permessage-deflate; client_max_window_bits" - - # Websocket connection is currently unable to follow redirects - request.follow_redirects = False - - self.tcp_client = TCPClient() - super().__init__( - None, - request, - lambda: None, - self._on_http_response, - 104857600, - self.tcp_client, - 65536, - 104857600, - ) - - def close(self, code: Optional[int] = None, reason: Optional[str] = None) -> None: - """Closes the websocket connection. - - ``code`` and ``reason`` are documented under - `WebSocketHandler.close`. - - .. versionadded:: 3.2 - - .. versionchanged:: 4.0 - - Added the ``code`` and ``reason`` arguments. - """ - if self.protocol is not None: - self.protocol.close(code, reason) - self.protocol = None # type: ignore - - def on_connection_close(self) -> None: - if not self.connect_future.done(): - self.connect_future.set_exception(StreamClosedError()) - self._on_message(None) - self.tcp_client.close() - super().on_connection_close() - - def on_ws_connection_close( - self, close_code: Optional[int] = None, close_reason: Optional[str] = None - ) -> None: - self.close_code = close_code - self.close_reason = close_reason - self.on_connection_close() - - def _on_http_response(self, response: httpclient.HTTPResponse) -> None: - if not self.connect_future.done(): - if response.error: - self.connect_future.set_exception(response.error) - else: - self.connect_future.set_exception( - WebSocketError("Non-websocket response") - ) - - async def headers_received( - self, - start_line: Union[httputil.RequestStartLine, httputil.ResponseStartLine], - headers: httputil.HTTPHeaders, - ) -> None: - assert isinstance(start_line, httputil.ResponseStartLine) - if start_line.code != 101: - await super().headers_received(start_line, headers) - return - - if self._timeout is not None: - self.io_loop.remove_timeout(self._timeout) - self._timeout = None - - self.headers = headers - self.protocol = self.get_websocket_protocol() - self.protocol._process_server_headers(self.key, self.headers) - self.protocol.stream = self.connection.detach() - - IOLoop.current().add_callback(self.protocol._receive_frame_loop) - self.protocol.start_pinging() - - # Once we've taken over the connection, clear the final callback - # we set on the http request. This deactivates the error handling - # in simple_httpclient that would otherwise interfere with our - # ability to see exceptions. - self.final_callback = None # type: ignore - - future_set_result_unless_cancelled(self.connect_future, self) - - def write_message( - self, message: Union[str, bytes], binary: bool = False - ) -> "Future[None]": - """Sends a message to the WebSocket server. - - If the stream is closed, raises `WebSocketClosedError`. - Returns a `.Future` which can be used for flow control. - - .. versionchanged:: 5.0 - Exception raised on a closed stream changed from `.StreamClosedError` - to `WebSocketClosedError`. - """ - return self.protocol.write_message(message, binary=binary) - - def read_message( - self, - callback: Optional[Callable[["Future[Union[None, str, bytes]]"], None]] = None, - ) -> Awaitable[Union[None, str, bytes]]: - """Reads a message from the WebSocket server. - - If on_message_callback was specified at WebSocket - initialization, this function will never return messages - - Returns a future whose result is the message, or None - if the connection is closed. If a callback argument - is given it will be called with the future when it is - ready. - """ - - awaitable = self.read_queue.get() - if callback is not None: - self.io_loop.add_future(asyncio.ensure_future(awaitable), callback) - return awaitable - - def on_message(self, message: Union[str, bytes]) -> Optional[Awaitable[None]]: - return self._on_message(message) - - def _on_message( - self, message: Union[None, str, bytes] - ) -> Optional[Awaitable[None]]: - if self._on_message_callback: - self._on_message_callback(message) - return None - else: - return self.read_queue.put(message) - - def ping(self, data: bytes = b"") -> None: - """Send ping frame to the remote end. - - The data argument allows a small amount of data (up to 125 - bytes) to be sent as a part of the ping message. Note that not - all websocket implementations expose this data to - applications. - - Consider using the ``ping_interval`` argument to - `websocket_connect` instead of sending pings manually. - - .. versionadded:: 5.1 - - """ - data = utf8(data) - if self.protocol is None: - raise WebSocketClosedError() - self.protocol.write_ping(data) - - def on_pong(self, data: bytes) -> None: - pass - - def on_ping(self, data: bytes) -> None: - pass - - def get_websocket_protocol(self) -> WebSocketProtocol: - return WebSocketProtocol13(self, mask_outgoing=True, params=self.params) - - @property - def selected_subprotocol(self) -> Optional[str]: - """The subprotocol selected by the server. - - .. versionadded:: 5.1 - """ - return self.protocol.selected_subprotocol - - def log_exception( - self, - typ: "Optional[Type[BaseException]]", - value: Optional[BaseException], - tb: Optional[TracebackType], - ) -> None: - assert typ is not None - assert value is not None - app_log.error("Uncaught exception %s", value, exc_info=(typ, value, tb)) - - -def websocket_connect( - url: Union[str, httpclient.HTTPRequest], - callback: Optional[Callable[["Future[WebSocketClientConnection]"], None]] = None, - connect_timeout: Optional[float] = None, - on_message_callback: Optional[Callable[[Union[None, str, bytes]], None]] = None, - compression_options: Optional[Dict[str, Any]] = None, - ping_interval: Optional[float] = None, - ping_timeout: Optional[float] = None, - max_message_size: int = _default_max_message_size, - subprotocols: Optional[List[str]] = None, -) -> "Awaitable[WebSocketClientConnection]": - """Client-side websocket support. - - Takes a url and returns a Future whose result is a - `WebSocketClientConnection`. - - ``compression_options`` is interpreted in the same way as the - return value of `.WebSocketHandler.get_compression_options`. - - The connection supports two styles of operation. In the coroutine - style, the application typically calls - `~.WebSocketClientConnection.read_message` in a loop:: - - conn = yield websocket_connect(url) - while True: - msg = yield conn.read_message() - if msg is None: break - # Do something with msg - - In the callback style, pass an ``on_message_callback`` to - ``websocket_connect``. In both styles, a message of ``None`` - indicates that the connection has been closed. - - ``subprotocols`` may be a list of strings specifying proposed - subprotocols. The selected protocol may be found on the - ``selected_subprotocol`` attribute of the connection object - when the connection is complete. - - .. versionchanged:: 3.2 - Also accepts ``HTTPRequest`` objects in place of urls. - - .. versionchanged:: 4.1 - Added ``compression_options`` and ``on_message_callback``. - - .. versionchanged:: 4.5 - Added the ``ping_interval``, ``ping_timeout``, and ``max_message_size`` - arguments, which have the same meaning as in `WebSocketHandler`. - - .. versionchanged:: 5.0 - The ``io_loop`` argument (deprecated since version 4.1) has been removed. - - .. versionchanged:: 5.1 - Added the ``subprotocols`` argument. - """ - if isinstance(url, httpclient.HTTPRequest): - assert connect_timeout is None - request = url - # Copy and convert the headers dict/object (see comments in - # AsyncHTTPClient.fetch) - request.headers = httputil.HTTPHeaders(request.headers) - else: - request = httpclient.HTTPRequest(url, connect_timeout=connect_timeout) - request = cast( - httpclient.HTTPRequest, - httpclient._RequestProxy(request, httpclient.HTTPRequest._DEFAULTS), - ) - conn = WebSocketClientConnection( - request, - on_message_callback=on_message_callback, - compression_options=compression_options, - ping_interval=ping_interval, - ping_timeout=ping_timeout, - max_message_size=max_message_size, - subprotocols=subprotocols, - ) - if callback is not None: - IOLoop.current().add_future(conn.connect_future, callback) - return conn.connect_future diff --git a/venv/lib/python3.8/site-packages/tornado/wsgi.py b/venv/lib/python3.8/site-packages/tornado/wsgi.py deleted file mode 100644 index 77124aa..0000000 --- a/venv/lib/python3.8/site-packages/tornado/wsgi.py +++ /dev/null @@ -1,199 +0,0 @@ -# -# Copyright 2009 Facebook -# -# 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. - -"""WSGI support for the Tornado web framework. - -WSGI is the Python standard for web servers, and allows for interoperability -between Tornado and other Python web frameworks and servers. - -This module provides WSGI support via the `WSGIContainer` class, which -makes it possible to run applications using other WSGI frameworks on -the Tornado HTTP server. The reverse is not supported; the Tornado -`.Application` and `.RequestHandler` classes are designed for use with -the Tornado `.HTTPServer` and cannot be used in a generic WSGI -container. - -""" - -import sys -from io import BytesIO -import tornado - -from tornado import escape -from tornado import httputil -from tornado.log import access_log - -from typing import List, Tuple, Optional, Callable, Any, Dict, Text -from types import TracebackType -import typing - -if typing.TYPE_CHECKING: - from typing import Type # noqa: F401 - from wsgiref.types import WSGIApplication as WSGIAppType # noqa: F401 - - -# PEP 3333 specifies that WSGI on python 3 generally deals with byte strings -# that are smuggled inside objects of type unicode (via the latin1 encoding). -# This function is like those in the tornado.escape module, but defined -# here to minimize the temptation to use it in non-wsgi contexts. -def to_wsgi_str(s: bytes) -> str: - assert isinstance(s, bytes) - return s.decode("latin1") - - -class WSGIContainer(object): - r"""Makes a WSGI-compatible function runnable on Tornado's HTTP server. - - .. warning:: - - WSGI is a *synchronous* interface, while Tornado's concurrency model - is based on single-threaded asynchronous execution. This means that - running a WSGI app with Tornado's `WSGIContainer` is *less scalable* - than running the same app in a multi-threaded WSGI server like - ``gunicorn`` or ``uwsgi``. Use `WSGIContainer` only when there are - benefits to combining Tornado and WSGI in the same process that - outweigh the reduced scalability. - - Wrap a WSGI function in a `WSGIContainer` and pass it to `.HTTPServer` to - run it. For example:: - - def simple_app(environ, start_response): - status = "200 OK" - response_headers = [("Content-type", "text/plain")] - start_response(status, response_headers) - return ["Hello world!\n"] - - container = tornado.wsgi.WSGIContainer(simple_app) - http_server = tornado.httpserver.HTTPServer(container) - http_server.listen(8888) - tornado.ioloop.IOLoop.current().start() - - This class is intended to let other frameworks (Django, web.py, etc) - run on the Tornado HTTP server and I/O loop. - - The `tornado.web.FallbackHandler` class is often useful for mixing - Tornado and WSGI apps in the same server. See - https://github.com/bdarnell/django-tornado-demo for a complete example. - """ - - def __init__(self, wsgi_application: "WSGIAppType") -> None: - self.wsgi_application = wsgi_application - - def __call__(self, request: httputil.HTTPServerRequest) -> None: - data = {} # type: Dict[str, Any] - response = [] # type: List[bytes] - - def start_response( - status: str, - headers: List[Tuple[str, str]], - exc_info: Optional[ - Tuple[ - "Optional[Type[BaseException]]", - Optional[BaseException], - Optional[TracebackType], - ] - ] = None, - ) -> Callable[[bytes], Any]: - data["status"] = status - data["headers"] = headers - return response.append - - app_response = self.wsgi_application( - WSGIContainer.environ(request), start_response - ) - try: - response.extend(app_response) - body = b"".join(response) - finally: - if hasattr(app_response, "close"): - app_response.close() # type: ignore - if not data: - raise Exception("WSGI app did not call start_response") - - status_code_str, reason = data["status"].split(" ", 1) - status_code = int(status_code_str) - headers = data["headers"] # type: List[Tuple[str, str]] - header_set = set(k.lower() for (k, v) in headers) - body = escape.utf8(body) - if status_code != 304: - if "content-length" not in header_set: - headers.append(("Content-Length", str(len(body)))) - if "content-type" not in header_set: - headers.append(("Content-Type", "text/html; charset=UTF-8")) - if "server" not in header_set: - headers.append(("Server", "TornadoServer/%s" % tornado.version)) - - start_line = httputil.ResponseStartLine("HTTP/1.1", status_code, reason) - header_obj = httputil.HTTPHeaders() - for key, value in headers: - header_obj.add(key, value) - assert request.connection is not None - request.connection.write_headers(start_line, header_obj, chunk=body) - request.connection.finish() - self._log(status_code, request) - - @staticmethod - def environ(request: httputil.HTTPServerRequest) -> Dict[Text, Any]: - """Converts a `tornado.httputil.HTTPServerRequest` to a WSGI environment. - """ - hostport = request.host.split(":") - if len(hostport) == 2: - host = hostport[0] - port = int(hostport[1]) - else: - host = request.host - port = 443 if request.protocol == "https" else 80 - environ = { - "REQUEST_METHOD": request.method, - "SCRIPT_NAME": "", - "PATH_INFO": to_wsgi_str( - escape.url_unescape(request.path, encoding=None, plus=False) - ), - "QUERY_STRING": request.query, - "REMOTE_ADDR": request.remote_ip, - "SERVER_NAME": host, - "SERVER_PORT": str(port), - "SERVER_PROTOCOL": request.version, - "wsgi.version": (1, 0), - "wsgi.url_scheme": request.protocol, - "wsgi.input": BytesIO(escape.utf8(request.body)), - "wsgi.errors": sys.stderr, - "wsgi.multithread": False, - "wsgi.multiprocess": True, - "wsgi.run_once": False, - } - if "Content-Type" in request.headers: - environ["CONTENT_TYPE"] = request.headers.pop("Content-Type") - if "Content-Length" in request.headers: - environ["CONTENT_LENGTH"] = request.headers.pop("Content-Length") - for key, value in request.headers.items(): - environ["HTTP_" + key.replace("-", "_").upper()] = value - return environ - - def _log(self, status_code: int, request: httputil.HTTPServerRequest) -> None: - if status_code < 400: - log_method = access_log.info - elif status_code < 500: - log_method = access_log.warning - else: - log_method = access_log.error - request_time = 1000.0 * request.request_time() - assert request.method is not None - assert request.uri is not None - summary = request.method + " " + request.uri + " (" + request.remote_ip + ")" - log_method("%d %s %.2fms", status_code, summary, request_time) - - -HTTPRequest = httputil.HTTPServerRequest diff --git a/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/INSTALLER b/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/LICENSE.txt b/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/LICENSE.txt deleted file mode 100644 index 9be1d2f..0000000 --- a/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/LICENSE.txt +++ /dev/null @@ -1,19 +0,0 @@ -Copyright 2011-2017 Lennart Regebro - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/METADATA b/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/METADATA deleted file mode 100644 index 7bafd42..0000000 --- a/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/METADATA +++ /dev/null @@ -1,326 +0,0 @@ -Metadata-Version: 2.1 -Name: tzlocal -Version: 2.1 -Summary: tzinfo object for the local timezone -Home-page: https://github.com/regebro/tzlocal -Author: Lennart Regebro -Author-email: regebro@gmail.com -License: MIT -Keywords: timezone pytz -Platform: UNKNOWN -Classifier: Development Status :: 5 - Production/Stable -Classifier: License :: OSI Approved :: MIT License -Classifier: Operating System :: Microsoft :: Windows -Classifier: Operating System :: Unix -Classifier: Operating System :: MacOS :: MacOS X -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 -Requires-Dist: pytz - -tzlocal -======= - -This Python module returns a ``tzinfo`` object with the local timezone information under Unix and Win-32. -It requires ``pytz``, and returns ``pytz`` ``tzinfo`` objects. - -This module attempts to fix a glaring hole in ``pytz``, that there is no way to -get the local timezone information, unless you know the zoneinfo name, and -under several Linux distros that's hard or impossible to figure out. - -Also, with Windows different timezone system using pytz isn't of much use -unless you separately configure the zoneinfo timezone name. - -With ``tzlocal`` you only need to call ``get_localzone()`` and you will get a -``tzinfo`` object with the local time zone info. On some Unices you will still -not get to know what the timezone name is, but you don't need that when you -have the tzinfo file. However, if the timezone name is readily available it -will be used. - - -Supported systems ------------------ - -These are the systems that are in theory supported: - - * Windows 2000 and later - - * Any unix-like system with a ``/etc/localtime`` or ``/usr/local/etc/localtime`` - -If you have one of the above systems and it does not work, it's a bug. -Please report it. - -Please note that if you getting a time zone called ``local``, this is not a bug, it's -actually the main feature of ``tzlocal``, that even if your system does NOT have a configuration file -with the zoneinfo name of your time zone, it will still work. - -You can also use ``tzlocal`` to get the name of your local timezone, but only if your system is -configured to make that possible. ``tzlocal`` looks for the timezone name in ``/etc/timezone``, ``/var/db/zoneinfo``, -``/etc/sysconfig/clock`` and ``/etc/conf.d/clock``. If your ``/etc/localtime`` is a symlink it can also extract the -name from that symlink. - -If you need the name of your local time zone, then please make sure your system is properly configured to allow that. -If it isn't configured, tzlocal will default to UTC. - -Usage ------ - -Load the local timezone: - - >>> from tzlocal import get_localzone - >>> tz = get_localzone() - >>> tz - <DstTzInfo 'Europe/Warsaw' WMT+1:24:00 STD> - -Create a local datetime: - - >>> from datetime import datetime - >>> dt = tz.localize(datetime(2015, 4, 10, 7, 22)) - >>> dt - datetime.datetime(2015, 4, 10, 7, 22, tzinfo=<DstTzInfo 'Europe/Warsaw' CEST+2:00:00 DST>) - -Lookup another timezone with `pytz`: - - >>> import pytz - >>> eastern = pytz.timezone('US/Eastern') - -Convert the datetime: - - >>> dt.astimezone(eastern) - datetime.datetime(2015, 4, 10, 1, 22, tzinfo=<DstTzInfo 'US/Eastern' EDT-1 day, 20:00:00 DST>) - - -Maintainer ----------- - -* Lennart Regebro, regebro@gmail.com - -Contributors ------------- - -* Marc Van Olmen -* Benjamen Meyer -* Manuel Ebert -* Xiaokun Zhu -* Cameris -* Edward Betts -* McK KIM -* Cris Ewing -* Ayala Shachar -* Lev Maximov -* Jakub Wilk -* John Quarles -* Preston Landers -* Victor Torres -* Jean Jordaan -* Zackary Welch -* Mickaël Schoentgen -* Gabriel Corona - -(Sorry if I forgot someone) - -License -------- - -* MIT https://opensource.org/licenses/MIT - - -Changes -======= - -2.1 (2020-05-08) ----------------- - -- No changes. - - -2.1b1 (2020-02-08) ------------------- - -- The is_dst flag is wrong for Europe/Dublin on some Unix releases. - I changed to another way of determining if DST is in effect or not. - -- Added support for Python 3.7 and 3.8. Dropped 3.5 although it still works. - - -2.0.0 (2019-07-23) ------------------- - -- No differences since 2.0.0b3 - -Major differences since 1.5.1 -............................. - -- When no time zone configuration can be find, tzlocal now return UTC. - This is a major difference from 1.x, where an exception would be raised. - This change is because Docker images often have no configuration at all, - and the unix utilities will then default to UTC, so we follow that. - -- If tzlocal on Unix finds a timezone name in a /etc config file, then - tzlocal now verifies that the timezone it fouds has the same offset as - the local computer is configured with. If it doesn't, something is - configured incorrectly. (Victor Torres, regebro) - -- Get timezone via Termux `getprop` wrapper on Android. It's not officially - supported because we can't test it, but at least we make an effort. - (Jean Jordaan) - -Minor differences and bug fixes -............................... - -- Skip comment lines when parsing /etc/timezone. (Edward Betts) - -- Don't load timezone from current directory. (Gabriel Corona) - -- Now verifies that the config files actually contain something before - reading them. (Zackary Welch, regebro) - -- Got rid of a BytesWarning (Mickaël Schoentgen) - -- Now handles if config file paths exists, but are directories. - -- Moved tests out from distributions - -- Support wheels - - -1.5.1 (2017-12-01) ------------------- - -- 1.5 had a bug that slipped through testing, fixed that, - increased test coverage. - - -1.5 (2017-11-30) ----------------- - -- No longer treats macOS as special, but as a unix. - -- get_windows_info.py is renamed to update_windows_mappings.py - -- Windows mappings now also contain mappings from deprecated zoneinfo names. - (Preston-Landers, regebro) - - -1.4 (2017-04-18) ----------------- - -- I use MIT on my other projects, so relicensing. - - -1.4b1 (2017-04-14) ------------------- - -- Dropping support for Python versions nobody uses (2.5, 3.1, 3.2), adding 3.6 - Python 3.1 and 3.2 still works, 2.5 has been broken for some time. - -- Ayalash's OS X fix didn't work on Python 2.7, fixed that. - - -1.3.2 (2017-04-12) ------------------- - -- Ensure closing of subprocess on OS X (ayalash) - -- Removed unused imports (jwilk) - -- Closes stdout and stderr to get rid of ResourceWarnings (johnwquarles) - -- Updated Windows timezones (axil) - - -1.3 (2016-10-15) ----------------- - -- #34: Added support for /var/db/zoneinfo - - -1.2.2 (2016-03-02) ------------------- - -- #30: Fixed a bug on OS X. - - -1.2.1 (2016-02-28) ------------------- - -- Tests failed if TZ was set in the environment. (EdwardBetts) - -- Replaces os.popen() with subprocess.Popen() for OS X to - handle when systemsetup doesn't exist. (mckabi, cewing) - - -1.2 (2015-06-14) ----------------- - -- Systemd stores no time zone name, forcing us to look at the name of the file - that localtime symlinks to. (cameris) - - -1.1.2 (2014-10-18) ------------------- - -- Timezones that has 3 items did not work on Mac OS X. - (Marc Van Olmen) - -- Now doesn't fail if the TZ environment variable isn't an Olsen time zone. - -- Some timezones on Windows can apparently be empty (perhaps the are deleted). - Now these are ignored. - (Xiaokun Zhu) - - -1.1.1 (2014-01-29) ------------------- - -- I forgot to add Etc/UTC as an alias for Etc/GMT. - - -1.1 (2014-01-28) ----------------- - -- Adding better support for OS X. - -- Added support to map from tzdata/Olsen names to Windows names. - (Thanks to Benjamen Meyer). - - -1.0 (2013-05-29) ----------------- - -- Fixed some more cases where spaces needs replacing with underscores. - -- Better handling of misconfigured /etc/timezone. - -- Better error message on Windows if we can't find a timezone at all. - - -0.3 (2012-09-13) ----------------- - -- Windows 7 support. - -- Python 2.5 supported; because it only needed a __future__ import. - -- Python 3.3 tested, it worked. - -- Got rid of relative imports, because I don't actually like them, - so I don't know why I used them in the first place. - -- For each Windows zone, use the default zoneinfo zone, not the last one. - - -0.2 (2012-09-12) ----------------- - -- Python 3 support. - - -0.1 (2012-09-11) ----------------- - -- Initial release. - - diff --git a/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/RECORD b/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/RECORD deleted file mode 100644 index 5d4aa54..0000000 --- a/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/RECORD +++ /dev/null @@ -1,17 +0,0 @@ -tzlocal-2.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -tzlocal-2.1.dist-info/LICENSE.txt,sha256=2ZqyCa6xaq0sJckP_YPBqYHikP__dqQgoqsD4D8EG4w,1060 -tzlocal-2.1.dist-info/METADATA,sha256=CFvLexLJNXCk-hBmflVJxv7P2Izms0iDeVubwshTF1g,8227 -tzlocal-2.1.dist-info/RECORD,, -tzlocal-2.1.dist-info/WHEEL,sha256=aSdOKpzTGLLkKenfdFGiq92od_Dmr98YfEe8iw7iZoo,110 -tzlocal-2.1.dist-info/top_level.txt,sha256=QR6vZWP520waETnkotApPQPyVh9VnjoYPoAVHLK1DrE,8 -tzlocal-2.1.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1 -tzlocal/__init__.py,sha256=zOXBN5IP3Nc1gNiL8aVwHAhXAYTFfkTSDJ6VdjmifCQ,168 -tzlocal/__pycache__/__init__.cpython-38.pyc,, -tzlocal/__pycache__/unix.cpython-38.pyc,, -tzlocal/__pycache__/utils.cpython-38.pyc,, -tzlocal/__pycache__/win32.cpython-38.pyc,, -tzlocal/__pycache__/windows_tz.cpython-38.pyc,, -tzlocal/unix.py,sha256=7dFkjHfqNz4k9F_-PseJaKHCy8uHLKYckbIydpMGXo0,6062 -tzlocal/utils.py,sha256=FYqtaomESB2nQWR8cJalSLoQ9uq7QE0Sx0Hhud1kpTM,1692 -tzlocal/win32.py,sha256=GlvUX_yS1OGEkGmHvW_A3GR5Arxr6lrn0DetVcRanKg,3265 -tzlocal/windows_tz.py,sha256=J-5L3_TUGPiyg69GhqxFnAHhiHsjrZKfkgR1WbofaLk,31441 diff --git a/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/WHEEL b/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/WHEEL deleted file mode 100644 index 131c7a8..0000000 --- a/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/WHEEL +++ /dev/null @@ -1,6 +0,0 @@ -Wheel-Version: 1.0 -Generator: bdist_wheel (0.33.0) -Root-Is-Purelib: true -Tag: py2-none-any -Tag: py3-none-any - diff --git a/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/top_level.txt b/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/top_level.txt deleted file mode 100644 index cd5e9b1..0000000 --- a/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -tzlocal diff --git a/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/zip-safe b/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/zip-safe deleted file mode 100644 index 8b13789..0000000 --- a/venv/lib/python3.8/site-packages/tzlocal-2.1.dist-info/zip-safe +++ /dev/null @@ -1 +0,0 @@ - diff --git a/venv/lib/python3.8/site-packages/tzlocal/__init__.py b/venv/lib/python3.8/site-packages/tzlocal/__init__.py deleted file mode 100644 index c8196d6..0000000 --- a/venv/lib/python3.8/site-packages/tzlocal/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -import sys -if sys.platform == 'win32': - from tzlocal.win32 import get_localzone, reload_localzone -else: - from tzlocal.unix import get_localzone, reload_localzone diff --git a/venv/lib/python3.8/site-packages/tzlocal/unix.py b/venv/lib/python3.8/site-packages/tzlocal/unix.py deleted file mode 100644 index 8574965..0000000 --- a/venv/lib/python3.8/site-packages/tzlocal/unix.py +++ /dev/null @@ -1,174 +0,0 @@ -import os -import pytz -import re -import warnings - -from tzlocal import utils - -_cache_tz = None - - -def _tz_from_env(tzenv): - if tzenv[0] == ':': - tzenv = tzenv[1:] - - # TZ specifies a file - if os.path.isabs(tzenv) and os.path.exists(tzenv): - with open(tzenv, 'rb') as tzfile: - return pytz.tzfile.build_tzinfo('local', tzfile) - - # TZ specifies a zoneinfo zone. - try: - tz = pytz.timezone(tzenv) - # That worked, so we return this: - return tz - except pytz.UnknownTimeZoneError: - raise pytz.UnknownTimeZoneError( - "tzlocal() does not support non-zoneinfo timezones like %s. \n" - "Please use a timezone in the form of Continent/City") - - -def _try_tz_from_env(): - tzenv = os.environ.get('TZ') - if tzenv: - try: - return _tz_from_env(tzenv) - except pytz.UnknownTimeZoneError: - pass - - -def _get_localzone(_root='/'): - """Tries to find the local timezone configuration. - - This method prefers finding the timezone name and passing that to pytz, - over passing in the localtime file, as in the later case the zoneinfo - name is unknown. - - The parameter _root makes the function look for files like /etc/localtime - beneath the _root directory. This is primarily used by the tests. - In normal usage you call the function without parameters.""" - - tzenv = _try_tz_from_env() - if tzenv: - return tzenv - - # Are we under Termux on Android? - if os.path.exists('/system/bin/getprop'): - import subprocess - androidtz = subprocess.check_output(['getprop', 'persist.sys.timezone']).strip().decode() - return pytz.timezone(androidtz) - - # Now look for distribution specific configuration files - # that contain the timezone name. - for configfile in ('etc/timezone', 'var/db/zoneinfo'): - tzpath = os.path.join(_root, configfile) - try: - with open(tzpath, 'rb') as tzfile: - data = tzfile.read() - - # Issue #3 was that /etc/timezone was a zoneinfo file. - # That's a misconfiguration, but we need to handle it gracefully: - if data[:5] == b'TZif2': - continue - - etctz = data.strip().decode() - if not etctz: - # Empty file, skip - continue - for etctz in data.decode().splitlines(): - # Get rid of host definitions and comments: - if ' ' in etctz: - etctz, dummy = etctz.split(' ', 1) - if '#' in etctz: - etctz, dummy = etctz.split('#', 1) - if not etctz: - continue - tz = pytz.timezone(etctz.replace(' ', '_')) - if _root == '/': - # We are using a file in etc to name the timezone. - # Verify that the timezone specified there is actually used: - utils.assert_tz_offset(tz) - return tz - - except IOError: - # File doesn't exist or is a directory - continue - - # CentOS has a ZONE setting in /etc/sysconfig/clock, - # OpenSUSE has a TIMEZONE setting in /etc/sysconfig/clock and - # Gentoo has a TIMEZONE setting in /etc/conf.d/clock - # We look through these files for a timezone: - - zone_re = re.compile(r'\s*ZONE\s*=\s*\"') - timezone_re = re.compile(r'\s*TIMEZONE\s*=\s*\"') - end_re = re.compile('\"') - - for filename in ('etc/sysconfig/clock', 'etc/conf.d/clock'): - tzpath = os.path.join(_root, filename) - try: - with open(tzpath, 'rt') as tzfile: - data = tzfile.readlines() - - for line in data: - # Look for the ZONE= setting. - match = zone_re.match(line) - if match is None: - # No ZONE= setting. Look for the TIMEZONE= setting. - match = timezone_re.match(line) - if match is not None: - # Some setting existed - line = line[match.end():] - etctz = line[:end_re.search(line).start()] - - # We found a timezone - tz = pytz.timezone(etctz.replace(' ', '_')) - if _root == '/': - # We are using a file in etc to name the timezone. - # Verify that the timezone specified there is actually used: - utils.assert_tz_offset(tz) - return tz - - except IOError: - # File doesn't exist or is a directory - continue - - # systemd distributions use symlinks that include the zone name, - # see manpage of localtime(5) and timedatectl(1) - tzpath = os.path.join(_root, 'etc/localtime') - if os.path.exists(tzpath) and os.path.islink(tzpath): - tzpath = os.path.realpath(tzpath) - start = tzpath.find("/")+1 - while start != 0: - tzpath = tzpath[start:] - try: - return pytz.timezone(tzpath) - except pytz.UnknownTimeZoneError: - pass - start = tzpath.find("/")+1 - - # No explicit setting existed. Use localtime - for filename in ('etc/localtime', 'usr/local/etc/localtime'): - tzpath = os.path.join(_root, filename) - - if not os.path.exists(tzpath): - continue - with open(tzpath, 'rb') as tzfile: - return pytz.tzfile.build_tzinfo('local', tzfile) - - warnings.warn('Can not find any timezone configuration, defaulting to UTC.') - return pytz.utc - -def get_localzone(): - """Get the computers configured local timezone, if any.""" - global _cache_tz - if _cache_tz is None: - _cache_tz = _get_localzone() - - return _cache_tz - - -def reload_localzone(): - """Reload the cached localzone. You need to call this if the timezone has changed.""" - global _cache_tz - _cache_tz = _get_localzone() - return _cache_tz diff --git a/venv/lib/python3.8/site-packages/tzlocal/utils.py b/venv/lib/python3.8/site-packages/tzlocal/utils.py deleted file mode 100644 index 5a67799..0000000 --- a/venv/lib/python3.8/site-packages/tzlocal/utils.py +++ /dev/null @@ -1,46 +0,0 @@ -# -*- coding: utf-8 -*- -import time -import datetime -import calendar - - -def get_system_offset(): - """Get system's timezone offset using built-in library time. - - For the Timezone constants (altzone, daylight, timezone, and tzname), the - value is determined by the timezone rules in effect at module load time or - the last time tzset() is called and may be incorrect for times in the past. - - To keep compatibility with Windows, we're always importing time module here. - """ - - localtime = calendar.timegm(time.localtime()) - gmtime = calendar.timegm(time.gmtime()) - offset = gmtime - localtime - # We could get the localtime and gmtime on either side of a second switch - # so we check that the difference is less than one minute, because nobody - # has that small DST differences. - if abs(offset - time.altzone) < 60: - return -time.altzone - else: - return -time.timezone - - -def get_tz_offset(tz): - """Get timezone's offset using built-in function datetime.utcoffset().""" - return int(datetime.datetime.now(tz).utcoffset().total_seconds()) - - -def assert_tz_offset(tz): - """Assert that system's timezone offset equals to the timezone offset found. - - If they don't match, we probably have a misconfiguration, for example, an - incorrect timezone set in /etc/timezone file in systemd distributions.""" - tz_offset = get_tz_offset(tz) - system_offset = get_system_offset() - if tz_offset != system_offset: - msg = ('Timezone offset does not match system offset: {0} != {1}. ' - 'Please, check your config files.').format( - tz_offset, system_offset - ) - raise ValueError(msg) diff --git a/venv/lib/python3.8/site-packages/tzlocal/win32.py b/venv/lib/python3.8/site-packages/tzlocal/win32.py deleted file mode 100644 index fcc42a2..0000000 --- a/venv/lib/python3.8/site-packages/tzlocal/win32.py +++ /dev/null @@ -1,104 +0,0 @@ -try: - import _winreg as winreg -except ImportError: - import winreg - -import pytz - -from tzlocal.windows_tz import win_tz -from tzlocal import utils - -_cache_tz = None - - -def valuestodict(key): - """Convert a registry key's values to a dictionary.""" - dict = {} - size = winreg.QueryInfoKey(key)[1] - for i in range(size): - data = winreg.EnumValue(key, i) - dict[data[0]] = data[1] - return dict - - -def get_localzone_name(): - # Windows is special. It has unique time zone names (in several - # meanings of the word) available, but unfortunately, they can be - # translated to the language of the operating system, so we need to - # do a backwards lookup, by going through all time zones and see which - # one matches. - handle = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE) - - TZLOCALKEYNAME = r"SYSTEM\CurrentControlSet\Control\TimeZoneInformation" - localtz = winreg.OpenKey(handle, TZLOCALKEYNAME) - keyvalues = valuestodict(localtz) - localtz.Close() - - if 'TimeZoneKeyName' in keyvalues: - # Windows 7 (and Vista?) - - # For some reason this returns a string with loads of NUL bytes at - # least on some systems. I don't know if this is a bug somewhere, I - # just work around it. - tzkeyname = keyvalues['TimeZoneKeyName'].split('\x00', 1)[0] - else: - # Windows 2000 or XP - - # This is the localized name: - tzwin = keyvalues['StandardName'] - - # Open the list of timezones to look up the real name: - TZKEYNAME = r"SOFTWARE\Microsoft\Windows NT\CurrentVersion\Time Zones" - tzkey = winreg.OpenKey(handle, TZKEYNAME) - - # Now, match this value to Time Zone information - tzkeyname = None - for i in range(winreg.QueryInfoKey(tzkey)[0]): - subkey = winreg.EnumKey(tzkey, i) - sub = winreg.OpenKey(tzkey, subkey) - data = valuestodict(sub) - sub.Close() - try: - if data['Std'] == tzwin: - tzkeyname = subkey - break - except KeyError: - # This timezone didn't have proper configuration. - # Ignore it. - pass - - tzkey.Close() - handle.Close() - - if tzkeyname is None: - raise LookupError('Can not find Windows timezone configuration') - - timezone = win_tz.get(tzkeyname) - if timezone is None: - # Nope, that didn't work. Try adding "Standard Time", - # it seems to work a lot of times: - timezone = win_tz.get(tzkeyname + " Standard Time") - - # Return what we have. - if timezone is None: - raise pytz.UnknownTimeZoneError('Can not find timezone ' + tzkeyname) - - return timezone - - -def get_localzone(): - """Returns the zoneinfo-based tzinfo object that matches the Windows-configured timezone.""" - global _cache_tz - if _cache_tz is None: - _cache_tz = pytz.timezone(get_localzone_name()) - - utils.assert_tz_offset(_cache_tz) - return _cache_tz - - -def reload_localzone(): - """Reload the cached localzone. You need to call this if the timezone has changed.""" - global _cache_tz - _cache_tz = pytz.timezone(get_localzone_name()) - utils.assert_tz_offset(_cache_tz) - return _cache_tz diff --git a/venv/lib/python3.8/site-packages/tzlocal/windows_tz.py b/venv/lib/python3.8/site-packages/tzlocal/windows_tz.py deleted file mode 100644 index 86ba807..0000000 --- a/venv/lib/python3.8/site-packages/tzlocal/windows_tz.py +++ /dev/null @@ -1,697 +0,0 @@ -# This file is autogenerated by the update_windows_mapping.py script -# Do not edit. -win_tz = {'AUS Central Standard Time': 'Australia/Darwin', - 'AUS Eastern Standard Time': 'Australia/Sydney', - 'Afghanistan Standard Time': 'Asia/Kabul', - 'Alaskan Standard Time': 'America/Anchorage', - 'Aleutian Standard Time': 'America/Adak', - 'Altai Standard Time': 'Asia/Barnaul', - 'Arab Standard Time': 'Asia/Riyadh', - 'Arabian Standard Time': 'Asia/Dubai', - 'Arabic Standard Time': 'Asia/Baghdad', - 'Argentina Standard Time': 'America/Buenos_Aires', - 'Astrakhan Standard Time': 'Europe/Astrakhan', - 'Atlantic Standard Time': 'America/Halifax', - 'Aus Central W. Standard Time': 'Australia/Eucla', - 'Azerbaijan Standard Time': 'Asia/Baku', - 'Azores Standard Time': 'Atlantic/Azores', - 'Bahia Standard Time': 'America/Bahia', - 'Bangladesh Standard Time': 'Asia/Dhaka', - 'Belarus Standard Time': 'Europe/Minsk', - 'Bougainville Standard Time': 'Pacific/Bougainville', - 'Canada Central Standard Time': 'America/Regina', - 'Cape Verde Standard Time': 'Atlantic/Cape_Verde', - 'Caucasus Standard Time': 'Asia/Yerevan', - 'Cen. Australia Standard Time': 'Australia/Adelaide', - 'Central America Standard Time': 'America/Guatemala', - 'Central Asia Standard Time': 'Asia/Almaty', - 'Central Brazilian Standard Time': 'America/Cuiaba', - 'Central Europe Standard Time': 'Europe/Budapest', - 'Central European Standard Time': 'Europe/Warsaw', - 'Central Pacific Standard Time': 'Pacific/Guadalcanal', - 'Central Standard Time': 'America/Chicago', - 'Central Standard Time (Mexico)': 'America/Mexico_City', - 'Chatham Islands Standard Time': 'Pacific/Chatham', - 'China Standard Time': 'Asia/Shanghai', - 'Cuba Standard Time': 'America/Havana', - 'Dateline Standard Time': 'Etc/GMT+12', - 'E. Africa Standard Time': 'Africa/Nairobi', - 'E. Australia Standard Time': 'Australia/Brisbane', - 'E. Europe Standard Time': 'Europe/Chisinau', - 'E. South America Standard Time': 'America/Sao_Paulo', - 'Easter Island Standard Time': 'Pacific/Easter', - 'Eastern Standard Time': 'America/New_York', - 'Eastern Standard Time (Mexico)': 'America/Cancun', - 'Egypt Standard Time': 'Africa/Cairo', - 'Ekaterinburg Standard Time': 'Asia/Yekaterinburg', - 'FLE Standard Time': 'Europe/Kiev', - 'Fiji Standard Time': 'Pacific/Fiji', - 'GMT Standard Time': 'Europe/London', - 'GTB Standard Time': 'Europe/Bucharest', - 'Georgian Standard Time': 'Asia/Tbilisi', - 'Greenland Standard Time': 'America/Godthab', - 'Greenwich Standard Time': 'Atlantic/Reykjavik', - 'Haiti Standard Time': 'America/Port-au-Prince', - 'Hawaiian Standard Time': 'Pacific/Honolulu', - 'India Standard Time': 'Asia/Calcutta', - 'Iran Standard Time': 'Asia/Tehran', - 'Israel Standard Time': 'Asia/Jerusalem', - 'Jordan Standard Time': 'Asia/Amman', - 'Kaliningrad Standard Time': 'Europe/Kaliningrad', - 'Korea Standard Time': 'Asia/Seoul', - 'Libya Standard Time': 'Africa/Tripoli', - 'Line Islands Standard Time': 'Pacific/Kiritimati', - 'Lord Howe Standard Time': 'Australia/Lord_Howe', - 'Magadan Standard Time': 'Asia/Magadan', - 'Magallanes Standard Time': 'America/Punta_Arenas', - 'Marquesas Standard Time': 'Pacific/Marquesas', - 'Mauritius Standard Time': 'Indian/Mauritius', - 'Middle East Standard Time': 'Asia/Beirut', - 'Montevideo Standard Time': 'America/Montevideo', - 'Morocco Standard Time': 'Africa/Casablanca', - 'Mountain Standard Time': 'America/Denver', - 'Mountain Standard Time (Mexico)': 'America/Chihuahua', - 'Myanmar Standard Time': 'Asia/Rangoon', - 'N. Central Asia Standard Time': 'Asia/Novosibirsk', - 'Namibia Standard Time': 'Africa/Windhoek', - 'Nepal Standard Time': 'Asia/Katmandu', - 'New Zealand Standard Time': 'Pacific/Auckland', - 'Newfoundland Standard Time': 'America/St_Johns', - 'Norfolk Standard Time': 'Pacific/Norfolk', - 'North Asia East Standard Time': 'Asia/Irkutsk', - 'North Asia Standard Time': 'Asia/Krasnoyarsk', - 'North Korea Standard Time': 'Asia/Pyongyang', - 'Omsk Standard Time': 'Asia/Omsk', - 'Pacific SA Standard Time': 'America/Santiago', - 'Pacific Standard Time': 'America/Los_Angeles', - 'Pacific Standard Time (Mexico)': 'America/Tijuana', - 'Pakistan Standard Time': 'Asia/Karachi', - 'Paraguay Standard Time': 'America/Asuncion', - 'Qyzylorda Standard Time': 'Asia/Qyzylorda', - 'Romance Standard Time': 'Europe/Paris', - 'Russia Time Zone 10': 'Asia/Srednekolymsk', - 'Russia Time Zone 11': 'Asia/Kamchatka', - 'Russia Time Zone 3': 'Europe/Samara', - 'Russian Standard Time': 'Europe/Moscow', - 'SA Eastern Standard Time': 'America/Cayenne', - 'SA Pacific Standard Time': 'America/Bogota', - 'SA Western Standard Time': 'America/La_Paz', - 'SE Asia Standard Time': 'Asia/Bangkok', - 'Saint Pierre Standard Time': 'America/Miquelon', - 'Sakhalin Standard Time': 'Asia/Sakhalin', - 'Samoa Standard Time': 'Pacific/Apia', - 'Sao Tome Standard Time': 'Africa/Sao_Tome', - 'Saratov Standard Time': 'Europe/Saratov', - 'Singapore Standard Time': 'Asia/Singapore', - 'South Africa Standard Time': 'Africa/Johannesburg', - 'Sri Lanka Standard Time': 'Asia/Colombo', - 'Sudan Standard Time': 'Africa/Khartoum', - 'Syria Standard Time': 'Asia/Damascus', - 'Taipei Standard Time': 'Asia/Taipei', - 'Tasmania Standard Time': 'Australia/Hobart', - 'Tocantins Standard Time': 'America/Araguaina', - 'Tokyo Standard Time': 'Asia/Tokyo', - 'Tomsk Standard Time': 'Asia/Tomsk', - 'Tonga Standard Time': 'Pacific/Tongatapu', - 'Transbaikal Standard Time': 'Asia/Chita', - 'Turkey Standard Time': 'Europe/Istanbul', - 'Turks And Caicos Standard Time': 'America/Grand_Turk', - 'US Eastern Standard Time': 'America/Indianapolis', - 'US Mountain Standard Time': 'America/Phoenix', - 'UTC': 'Etc/GMT', - 'UTC+12': 'Etc/GMT-12', - 'UTC+13': 'Etc/GMT-13', - 'UTC-02': 'Etc/GMT+2', - 'UTC-08': 'Etc/GMT+8', - 'UTC-09': 'Etc/GMT+9', - 'UTC-11': 'Etc/GMT+11', - 'Ulaanbaatar Standard Time': 'Asia/Ulaanbaatar', - 'Venezuela Standard Time': 'America/Caracas', - 'Vladivostok Standard Time': 'Asia/Vladivostok', - 'Volgograd Standard Time': 'Europe/Volgograd', - 'W. Australia Standard Time': 'Australia/Perth', - 'W. Central Africa Standard Time': 'Africa/Lagos', - 'W. Europe Standard Time': 'Europe/Berlin', - 'W. Mongolia Standard Time': 'Asia/Hovd', - 'West Asia Standard Time': 'Asia/Tashkent', - 'West Bank Standard Time': 'Asia/Hebron', - 'West Pacific Standard Time': 'Pacific/Port_Moresby', - 'Yakutsk Standard Time': 'Asia/Yakutsk'} - -# Old name for the win_tz variable: -tz_names = win_tz - -tz_win = {'Africa/Abidjan': 'Greenwich Standard Time', - 'Africa/Accra': 'Greenwich Standard Time', - 'Africa/Addis_Ababa': 'E. Africa Standard Time', - 'Africa/Algiers': 'W. Central Africa Standard Time', - 'Africa/Asmera': 'E. Africa Standard Time', - 'Africa/Bamako': 'Greenwich Standard Time', - 'Africa/Bangui': 'W. Central Africa Standard Time', - 'Africa/Banjul': 'Greenwich Standard Time', - 'Africa/Bissau': 'Greenwich Standard Time', - 'Africa/Blantyre': 'South Africa Standard Time', - 'Africa/Brazzaville': 'W. Central Africa Standard Time', - 'Africa/Bujumbura': 'South Africa Standard Time', - 'Africa/Cairo': 'Egypt Standard Time', - 'Africa/Casablanca': 'Morocco Standard Time', - 'Africa/Ceuta': 'Romance Standard Time', - 'Africa/Conakry': 'Greenwich Standard Time', - 'Africa/Dakar': 'Greenwich Standard Time', - 'Africa/Dar_es_Salaam': 'E. Africa Standard Time', - 'Africa/Djibouti': 'E. Africa Standard Time', - 'Africa/Douala': 'W. Central Africa Standard Time', - 'Africa/El_Aaiun': 'Morocco Standard Time', - 'Africa/Freetown': 'Greenwich Standard Time', - 'Africa/Gaborone': 'South Africa Standard Time', - 'Africa/Harare': 'South Africa Standard Time', - 'Africa/Johannesburg': 'South Africa Standard Time', - 'Africa/Juba': 'E. Africa Standard Time', - 'Africa/Kampala': 'E. Africa Standard Time', - 'Africa/Khartoum': 'Sudan Standard Time', - 'Africa/Kigali': 'South Africa Standard Time', - 'Africa/Kinshasa': 'W. Central Africa Standard Time', - 'Africa/Lagos': 'W. Central Africa Standard Time', - 'Africa/Libreville': 'W. Central Africa Standard Time', - 'Africa/Lome': 'Greenwich Standard Time', - 'Africa/Luanda': 'W. Central Africa Standard Time', - 'Africa/Lubumbashi': 'South Africa Standard Time', - 'Africa/Lusaka': 'South Africa Standard Time', - 'Africa/Malabo': 'W. Central Africa Standard Time', - 'Africa/Maputo': 'South Africa Standard Time', - 'Africa/Maseru': 'South Africa Standard Time', - 'Africa/Mbabane': 'South Africa Standard Time', - 'Africa/Mogadishu': 'E. Africa Standard Time', - 'Africa/Monrovia': 'Greenwich Standard Time', - 'Africa/Nairobi': 'E. Africa Standard Time', - 'Africa/Ndjamena': 'W. Central Africa Standard Time', - 'Africa/Niamey': 'W. Central Africa Standard Time', - 'Africa/Nouakchott': 'Greenwich Standard Time', - 'Africa/Ouagadougou': 'Greenwich Standard Time', - 'Africa/Porto-Novo': 'W. Central Africa Standard Time', - 'Africa/Sao_Tome': 'Sao Tome Standard Time', - 'Africa/Timbuktu': 'Greenwich Standard Time', - 'Africa/Tripoli': 'Libya Standard Time', - 'Africa/Tunis': 'W. Central Africa Standard Time', - 'Africa/Windhoek': 'Namibia Standard Time', - 'America/Adak': 'Aleutian Standard Time', - 'America/Anchorage': 'Alaskan Standard Time', - 'America/Anguilla': 'SA Western Standard Time', - 'America/Antigua': 'SA Western Standard Time', - 'America/Araguaina': 'Tocantins Standard Time', - 'America/Argentina/La_Rioja': 'Argentina Standard Time', - 'America/Argentina/Rio_Gallegos': 'Argentina Standard Time', - 'America/Argentina/Salta': 'Argentina Standard Time', - 'America/Argentina/San_Juan': 'Argentina Standard Time', - 'America/Argentina/San_Luis': 'Argentina Standard Time', - 'America/Argentina/Tucuman': 'Argentina Standard Time', - 'America/Argentina/Ushuaia': 'Argentina Standard Time', - 'America/Aruba': 'SA Western Standard Time', - 'America/Asuncion': 'Paraguay Standard Time', - 'America/Atka': 'Aleutian Standard Time', - 'America/Bahia': 'Bahia Standard Time', - 'America/Bahia_Banderas': 'Central Standard Time (Mexico)', - 'America/Barbados': 'SA Western Standard Time', - 'America/Belem': 'SA Eastern Standard Time', - 'America/Belize': 'Central America Standard Time', - 'America/Blanc-Sablon': 'SA Western Standard Time', - 'America/Boa_Vista': 'SA Western Standard Time', - 'America/Bogota': 'SA Pacific Standard Time', - 'America/Boise': 'Mountain Standard Time', - 'America/Buenos_Aires': 'Argentina Standard Time', - 'America/Cambridge_Bay': 'Mountain Standard Time', - 'America/Campo_Grande': 'Central Brazilian Standard Time', - 'America/Cancun': 'Eastern Standard Time (Mexico)', - 'America/Caracas': 'Venezuela Standard Time', - 'America/Catamarca': 'Argentina Standard Time', - 'America/Cayenne': 'SA Eastern Standard Time', - 'America/Cayman': 'SA Pacific Standard Time', - 'America/Chicago': 'Central Standard Time', - 'America/Chihuahua': 'Mountain Standard Time (Mexico)', - 'America/Coral_Harbour': 'SA Pacific Standard Time', - 'America/Cordoba': 'Argentina Standard Time', - 'America/Costa_Rica': 'Central America Standard Time', - 'America/Creston': 'US Mountain Standard Time', - 'America/Cuiaba': 'Central Brazilian Standard Time', - 'America/Curacao': 'SA Western Standard Time', - 'America/Danmarkshavn': 'UTC', - 'America/Dawson': 'Pacific Standard Time', - 'America/Dawson_Creek': 'US Mountain Standard Time', - 'America/Denver': 'Mountain Standard Time', - 'America/Detroit': 'Eastern Standard Time', - 'America/Dominica': 'SA Western Standard Time', - 'America/Edmonton': 'Mountain Standard Time', - 'America/Eirunepe': 'SA Pacific Standard Time', - 'America/El_Salvador': 'Central America Standard Time', - 'America/Ensenada': 'Pacific Standard Time (Mexico)', - 'America/Fort_Nelson': 'US Mountain Standard Time', - 'America/Fortaleza': 'SA Eastern Standard Time', - 'America/Glace_Bay': 'Atlantic Standard Time', - 'America/Godthab': 'Greenland Standard Time', - 'America/Goose_Bay': 'Atlantic Standard Time', - 'America/Grand_Turk': 'Turks And Caicos Standard Time', - 'America/Grenada': 'SA Western Standard Time', - 'America/Guadeloupe': 'SA Western Standard Time', - 'America/Guatemala': 'Central America Standard Time', - 'America/Guayaquil': 'SA Pacific Standard Time', - 'America/Guyana': 'SA Western Standard Time', - 'America/Halifax': 'Atlantic Standard Time', - 'America/Havana': 'Cuba Standard Time', - 'America/Hermosillo': 'US Mountain Standard Time', - 'America/Indiana/Knox': 'Central Standard Time', - 'America/Indiana/Marengo': 'US Eastern Standard Time', - 'America/Indiana/Petersburg': 'Eastern Standard Time', - 'America/Indiana/Tell_City': 'Central Standard Time', - 'America/Indiana/Vevay': 'US Eastern Standard Time', - 'America/Indiana/Vincennes': 'Eastern Standard Time', - 'America/Indiana/Winamac': 'Eastern Standard Time', - 'America/Indianapolis': 'US Eastern Standard Time', - 'America/Inuvik': 'Mountain Standard Time', - 'America/Iqaluit': 'Eastern Standard Time', - 'America/Jamaica': 'SA Pacific Standard Time', - 'America/Jujuy': 'Argentina Standard Time', - 'America/Juneau': 'Alaskan Standard Time', - 'America/Kentucky/Monticello': 'Eastern Standard Time', - 'America/Knox_IN': 'Central Standard Time', - 'America/Kralendijk': 'SA Western Standard Time', - 'America/La_Paz': 'SA Western Standard Time', - 'America/Lima': 'SA Pacific Standard Time', - 'America/Los_Angeles': 'Pacific Standard Time', - 'America/Louisville': 'Eastern Standard Time', - 'America/Lower_Princes': 'SA Western Standard Time', - 'America/Maceio': 'SA Eastern Standard Time', - 'America/Managua': 'Central America Standard Time', - 'America/Manaus': 'SA Western Standard Time', - 'America/Marigot': 'SA Western Standard Time', - 'America/Martinique': 'SA Western Standard Time', - 'America/Matamoros': 'Central Standard Time', - 'America/Mazatlan': 'Mountain Standard Time (Mexico)', - 'America/Mendoza': 'Argentina Standard Time', - 'America/Menominee': 'Central Standard Time', - 'America/Merida': 'Central Standard Time (Mexico)', - 'America/Metlakatla': 'Alaskan Standard Time', - 'America/Mexico_City': 'Central Standard Time (Mexico)', - 'America/Miquelon': 'Saint Pierre Standard Time', - 'America/Moncton': 'Atlantic Standard Time', - 'America/Monterrey': 'Central Standard Time (Mexico)', - 'America/Montevideo': 'Montevideo Standard Time', - 'America/Montreal': 'Eastern Standard Time', - 'America/Montserrat': 'SA Western Standard Time', - 'America/Nassau': 'Eastern Standard Time', - 'America/New_York': 'Eastern Standard Time', - 'America/Nipigon': 'Eastern Standard Time', - 'America/Nome': 'Alaskan Standard Time', - 'America/Noronha': 'UTC-02', - 'America/North_Dakota/Beulah': 'Central Standard Time', - 'America/North_Dakota/Center': 'Central Standard Time', - 'America/North_Dakota/New_Salem': 'Central Standard Time', - 'America/Ojinaga': 'Mountain Standard Time', - 'America/Panama': 'SA Pacific Standard Time', - 'America/Pangnirtung': 'Eastern Standard Time', - 'America/Paramaribo': 'SA Eastern Standard Time', - 'America/Phoenix': 'US Mountain Standard Time', - 'America/Port-au-Prince': 'Haiti Standard Time', - 'America/Port_of_Spain': 'SA Western Standard Time', - 'America/Porto_Acre': 'SA Pacific Standard Time', - 'America/Porto_Velho': 'SA Western Standard Time', - 'America/Puerto_Rico': 'SA Western Standard Time', - 'America/Punta_Arenas': 'Magallanes Standard Time', - 'America/Rainy_River': 'Central Standard Time', - 'America/Rankin_Inlet': 'Central Standard Time', - 'America/Recife': 'SA Eastern Standard Time', - 'America/Regina': 'Canada Central Standard Time', - 'America/Resolute': 'Central Standard Time', - 'America/Rio_Branco': 'SA Pacific Standard Time', - 'America/Santa_Isabel': 'Pacific Standard Time (Mexico)', - 'America/Santarem': 'SA Eastern Standard Time', - 'America/Santiago': 'Pacific SA Standard Time', - 'America/Santo_Domingo': 'SA Western Standard Time', - 'America/Sao_Paulo': 'E. South America Standard Time', - 'America/Scoresbysund': 'Azores Standard Time', - 'America/Shiprock': 'Mountain Standard Time', - 'America/Sitka': 'Alaskan Standard Time', - 'America/St_Barthelemy': 'SA Western Standard Time', - 'America/St_Johns': 'Newfoundland Standard Time', - 'America/St_Kitts': 'SA Western Standard Time', - 'America/St_Lucia': 'SA Western Standard Time', - 'America/St_Thomas': 'SA Western Standard Time', - 'America/St_Vincent': 'SA Western Standard Time', - 'America/Swift_Current': 'Canada Central Standard Time', - 'America/Tegucigalpa': 'Central America Standard Time', - 'America/Thule': 'Atlantic Standard Time', - 'America/Thunder_Bay': 'Eastern Standard Time', - 'America/Tijuana': 'Pacific Standard Time (Mexico)', - 'America/Toronto': 'Eastern Standard Time', - 'America/Tortola': 'SA Western Standard Time', - 'America/Vancouver': 'Pacific Standard Time', - 'America/Virgin': 'SA Western Standard Time', - 'America/Whitehorse': 'Pacific Standard Time', - 'America/Winnipeg': 'Central Standard Time', - 'America/Yakutat': 'Alaskan Standard Time', - 'America/Yellowknife': 'Mountain Standard Time', - 'Antarctica/Casey': 'Singapore Standard Time', - 'Antarctica/Davis': 'SE Asia Standard Time', - 'Antarctica/DumontDUrville': 'West Pacific Standard Time', - 'Antarctica/Macquarie': 'Central Pacific Standard Time', - 'Antarctica/Mawson': 'West Asia Standard Time', - 'Antarctica/McMurdo': 'New Zealand Standard Time', - 'Antarctica/Palmer': 'SA Eastern Standard Time', - 'Antarctica/Rothera': 'SA Eastern Standard Time', - 'Antarctica/South_Pole': 'New Zealand Standard Time', - 'Antarctica/Syowa': 'E. Africa Standard Time', - 'Antarctica/Vostok': 'Central Asia Standard Time', - 'Arctic/Longyearbyen': 'W. Europe Standard Time', - 'Asia/Aden': 'Arab Standard Time', - 'Asia/Almaty': 'Central Asia Standard Time', - 'Asia/Amman': 'Jordan Standard Time', - 'Asia/Anadyr': 'Russia Time Zone 11', - 'Asia/Aqtau': 'West Asia Standard Time', - 'Asia/Aqtobe': 'West Asia Standard Time', - 'Asia/Ashgabat': 'West Asia Standard Time', - 'Asia/Ashkhabad': 'West Asia Standard Time', - 'Asia/Atyrau': 'West Asia Standard Time', - 'Asia/Baghdad': 'Arabic Standard Time', - 'Asia/Bahrain': 'Arab Standard Time', - 'Asia/Baku': 'Azerbaijan Standard Time', - 'Asia/Bangkok': 'SE Asia Standard Time', - 'Asia/Barnaul': 'Altai Standard Time', - 'Asia/Beirut': 'Middle East Standard Time', - 'Asia/Bishkek': 'Central Asia Standard Time', - 'Asia/Brunei': 'Singapore Standard Time', - 'Asia/Calcutta': 'India Standard Time', - 'Asia/Chita': 'Transbaikal Standard Time', - 'Asia/Choibalsan': 'Ulaanbaatar Standard Time', - 'Asia/Chongqing': 'China Standard Time', - 'Asia/Chungking': 'China Standard Time', - 'Asia/Colombo': 'Sri Lanka Standard Time', - 'Asia/Dacca': 'Bangladesh Standard Time', - 'Asia/Damascus': 'Syria Standard Time', - 'Asia/Dhaka': 'Bangladesh Standard Time', - 'Asia/Dili': 'Tokyo Standard Time', - 'Asia/Dubai': 'Arabian Standard Time', - 'Asia/Dushanbe': 'West Asia Standard Time', - 'Asia/Famagusta': 'GTB Standard Time', - 'Asia/Gaza': 'West Bank Standard Time', - 'Asia/Harbin': 'China Standard Time', - 'Asia/Hebron': 'West Bank Standard Time', - 'Asia/Hong_Kong': 'China Standard Time', - 'Asia/Hovd': 'W. Mongolia Standard Time', - 'Asia/Irkutsk': 'North Asia East Standard Time', - 'Asia/Jakarta': 'SE Asia Standard Time', - 'Asia/Jayapura': 'Tokyo Standard Time', - 'Asia/Jerusalem': 'Israel Standard Time', - 'Asia/Kabul': 'Afghanistan Standard Time', - 'Asia/Kamchatka': 'Russia Time Zone 11', - 'Asia/Karachi': 'Pakistan Standard Time', - 'Asia/Kashgar': 'Central Asia Standard Time', - 'Asia/Katmandu': 'Nepal Standard Time', - 'Asia/Khandyga': 'Yakutsk Standard Time', - 'Asia/Krasnoyarsk': 'North Asia Standard Time', - 'Asia/Kuala_Lumpur': 'Singapore Standard Time', - 'Asia/Kuching': 'Singapore Standard Time', - 'Asia/Kuwait': 'Arab Standard Time', - 'Asia/Macao': 'China Standard Time', - 'Asia/Macau': 'China Standard Time', - 'Asia/Magadan': 'Magadan Standard Time', - 'Asia/Makassar': 'Singapore Standard Time', - 'Asia/Manila': 'Singapore Standard Time', - 'Asia/Muscat': 'Arabian Standard Time', - 'Asia/Nicosia': 'GTB Standard Time', - 'Asia/Novokuznetsk': 'North Asia Standard Time', - 'Asia/Novosibirsk': 'N. Central Asia Standard Time', - 'Asia/Omsk': 'Omsk Standard Time', - 'Asia/Oral': 'West Asia Standard Time', - 'Asia/Phnom_Penh': 'SE Asia Standard Time', - 'Asia/Pontianak': 'SE Asia Standard Time', - 'Asia/Pyongyang': 'North Korea Standard Time', - 'Asia/Qatar': 'Arab Standard Time', - 'Asia/Qostanay': 'Central Asia Standard Time', - 'Asia/Qyzylorda': 'Qyzylorda Standard Time', - 'Asia/Rangoon': 'Myanmar Standard Time', - 'Asia/Riyadh': 'Arab Standard Time', - 'Asia/Saigon': 'SE Asia Standard Time', - 'Asia/Sakhalin': 'Sakhalin Standard Time', - 'Asia/Samarkand': 'West Asia Standard Time', - 'Asia/Seoul': 'Korea Standard Time', - 'Asia/Shanghai': 'China Standard Time', - 'Asia/Singapore': 'Singapore Standard Time', - 'Asia/Srednekolymsk': 'Russia Time Zone 10', - 'Asia/Taipei': 'Taipei Standard Time', - 'Asia/Tashkent': 'West Asia Standard Time', - 'Asia/Tbilisi': 'Georgian Standard Time', - 'Asia/Tehran': 'Iran Standard Time', - 'Asia/Tel_Aviv': 'Israel Standard Time', - 'Asia/Thimbu': 'Bangladesh Standard Time', - 'Asia/Thimphu': 'Bangladesh Standard Time', - 'Asia/Tokyo': 'Tokyo Standard Time', - 'Asia/Tomsk': 'Tomsk Standard Time', - 'Asia/Ujung_Pandang': 'Singapore Standard Time', - 'Asia/Ulaanbaatar': 'Ulaanbaatar Standard Time', - 'Asia/Ulan_Bator': 'Ulaanbaatar Standard Time', - 'Asia/Urumqi': 'Central Asia Standard Time', - 'Asia/Ust-Nera': 'Vladivostok Standard Time', - 'Asia/Vientiane': 'SE Asia Standard Time', - 'Asia/Vladivostok': 'Vladivostok Standard Time', - 'Asia/Yakutsk': 'Yakutsk Standard Time', - 'Asia/Yekaterinburg': 'Ekaterinburg Standard Time', - 'Asia/Yerevan': 'Caucasus Standard Time', - 'Atlantic/Azores': 'Azores Standard Time', - 'Atlantic/Bermuda': 'Atlantic Standard Time', - 'Atlantic/Canary': 'GMT Standard Time', - 'Atlantic/Cape_Verde': 'Cape Verde Standard Time', - 'Atlantic/Faeroe': 'GMT Standard Time', - 'Atlantic/Jan_Mayen': 'W. Europe Standard Time', - 'Atlantic/Madeira': 'GMT Standard Time', - 'Atlantic/Reykjavik': 'Greenwich Standard Time', - 'Atlantic/South_Georgia': 'UTC-02', - 'Atlantic/St_Helena': 'Greenwich Standard Time', - 'Atlantic/Stanley': 'SA Eastern Standard Time', - 'Australia/ACT': 'AUS Eastern Standard Time', - 'Australia/Adelaide': 'Cen. Australia Standard Time', - 'Australia/Brisbane': 'E. Australia Standard Time', - 'Australia/Broken_Hill': 'Cen. Australia Standard Time', - 'Australia/Canberra': 'AUS Eastern Standard Time', - 'Australia/Currie': 'Tasmania Standard Time', - 'Australia/Darwin': 'AUS Central Standard Time', - 'Australia/Eucla': 'Aus Central W. Standard Time', - 'Australia/Hobart': 'Tasmania Standard Time', - 'Australia/LHI': 'Lord Howe Standard Time', - 'Australia/Lindeman': 'E. Australia Standard Time', - 'Australia/Lord_Howe': 'Lord Howe Standard Time', - 'Australia/Melbourne': 'AUS Eastern Standard Time', - 'Australia/NSW': 'AUS Eastern Standard Time', - 'Australia/North': 'AUS Central Standard Time', - 'Australia/Perth': 'W. Australia Standard Time', - 'Australia/Queensland': 'E. Australia Standard Time', - 'Australia/South': 'Cen. Australia Standard Time', - 'Australia/Sydney': 'AUS Eastern Standard Time', - 'Australia/Tasmania': 'Tasmania Standard Time', - 'Australia/Victoria': 'AUS Eastern Standard Time', - 'Australia/West': 'W. Australia Standard Time', - 'Australia/Yancowinna': 'Cen. Australia Standard Time', - 'Brazil/Acre': 'SA Pacific Standard Time', - 'Brazil/DeNoronha': 'UTC-02', - 'Brazil/East': 'E. South America Standard Time', - 'Brazil/West': 'SA Western Standard Time', - 'CST6CDT': 'Central Standard Time', - 'Canada/Atlantic': 'Atlantic Standard Time', - 'Canada/Central': 'Central Standard Time', - 'Canada/Eastern': 'Eastern Standard Time', - 'Canada/Mountain': 'Mountain Standard Time', - 'Canada/Newfoundland': 'Newfoundland Standard Time', - 'Canada/Pacific': 'Pacific Standard Time', - 'Canada/Saskatchewan': 'Canada Central Standard Time', - 'Canada/Yukon': 'Pacific Standard Time', - 'Chile/Continental': 'Pacific SA Standard Time', - 'Chile/EasterIsland': 'Easter Island Standard Time', - 'Cuba': 'Cuba Standard Time', - 'EST5EDT': 'Eastern Standard Time', - 'Egypt': 'Egypt Standard Time', - 'Eire': 'GMT Standard Time', - 'Etc/GMT': 'UTC', - 'Etc/GMT+1': 'Cape Verde Standard Time', - 'Etc/GMT+10': 'Hawaiian Standard Time', - 'Etc/GMT+11': 'UTC-11', - 'Etc/GMT+12': 'Dateline Standard Time', - 'Etc/GMT+2': 'UTC-02', - 'Etc/GMT+3': 'SA Eastern Standard Time', - 'Etc/GMT+4': 'SA Western Standard Time', - 'Etc/GMT+5': 'SA Pacific Standard Time', - 'Etc/GMT+6': 'Central America Standard Time', - 'Etc/GMT+7': 'US Mountain Standard Time', - 'Etc/GMT+8': 'UTC-08', - 'Etc/GMT+9': 'UTC-09', - 'Etc/GMT-1': 'W. Central Africa Standard Time', - 'Etc/GMT-10': 'West Pacific Standard Time', - 'Etc/GMT-11': 'Central Pacific Standard Time', - 'Etc/GMT-12': 'UTC+12', - 'Etc/GMT-13': 'UTC+13', - 'Etc/GMT-14': 'Line Islands Standard Time', - 'Etc/GMT-2': 'South Africa Standard Time', - 'Etc/GMT-3': 'E. Africa Standard Time', - 'Etc/GMT-4': 'Arabian Standard Time', - 'Etc/GMT-5': 'West Asia Standard Time', - 'Etc/GMT-6': 'Central Asia Standard Time', - 'Etc/GMT-7': 'SE Asia Standard Time', - 'Etc/GMT-8': 'Singapore Standard Time', - 'Etc/GMT-9': 'Tokyo Standard Time', - 'Etc/UCT': 'UTC', - 'Etc/UTC': 'UTC', - 'Europe/Amsterdam': 'W. Europe Standard Time', - 'Europe/Andorra': 'W. Europe Standard Time', - 'Europe/Astrakhan': 'Astrakhan Standard Time', - 'Europe/Athens': 'GTB Standard Time', - 'Europe/Belfast': 'GMT Standard Time', - 'Europe/Belgrade': 'Central Europe Standard Time', - 'Europe/Berlin': 'W. Europe Standard Time', - 'Europe/Bratislava': 'Central Europe Standard Time', - 'Europe/Brussels': 'Romance Standard Time', - 'Europe/Bucharest': 'GTB Standard Time', - 'Europe/Budapest': 'Central Europe Standard Time', - 'Europe/Busingen': 'W. Europe Standard Time', - 'Europe/Chisinau': 'E. Europe Standard Time', - 'Europe/Copenhagen': 'Romance Standard Time', - 'Europe/Dublin': 'GMT Standard Time', - 'Europe/Gibraltar': 'W. Europe Standard Time', - 'Europe/Guernsey': 'GMT Standard Time', - 'Europe/Helsinki': 'FLE Standard Time', - 'Europe/Isle_of_Man': 'GMT Standard Time', - 'Europe/Istanbul': 'Turkey Standard Time', - 'Europe/Jersey': 'GMT Standard Time', - 'Europe/Kaliningrad': 'Kaliningrad Standard Time', - 'Europe/Kiev': 'FLE Standard Time', - 'Europe/Kirov': 'Russian Standard Time', - 'Europe/Lisbon': 'GMT Standard Time', - 'Europe/Ljubljana': 'Central Europe Standard Time', - 'Europe/London': 'GMT Standard Time', - 'Europe/Luxembourg': 'W. Europe Standard Time', - 'Europe/Madrid': 'Romance Standard Time', - 'Europe/Malta': 'W. Europe Standard Time', - 'Europe/Mariehamn': 'FLE Standard Time', - 'Europe/Minsk': 'Belarus Standard Time', - 'Europe/Monaco': 'W. Europe Standard Time', - 'Europe/Moscow': 'Russian Standard Time', - 'Europe/Oslo': 'W. Europe Standard Time', - 'Europe/Paris': 'Romance Standard Time', - 'Europe/Podgorica': 'Central Europe Standard Time', - 'Europe/Prague': 'Central Europe Standard Time', - 'Europe/Riga': 'FLE Standard Time', - 'Europe/Rome': 'W. Europe Standard Time', - 'Europe/Samara': 'Russia Time Zone 3', - 'Europe/San_Marino': 'W. Europe Standard Time', - 'Europe/Sarajevo': 'Central European Standard Time', - 'Europe/Saratov': 'Saratov Standard Time', - 'Europe/Simferopol': 'Russian Standard Time', - 'Europe/Skopje': 'Central European Standard Time', - 'Europe/Sofia': 'FLE Standard Time', - 'Europe/Stockholm': 'W. Europe Standard Time', - 'Europe/Tallinn': 'FLE Standard Time', - 'Europe/Tirane': 'Central Europe Standard Time', - 'Europe/Tiraspol': 'E. Europe Standard Time', - 'Europe/Ulyanovsk': 'Astrakhan Standard Time', - 'Europe/Uzhgorod': 'FLE Standard Time', - 'Europe/Vaduz': 'W. Europe Standard Time', - 'Europe/Vatican': 'W. Europe Standard Time', - 'Europe/Vienna': 'W. Europe Standard Time', - 'Europe/Vilnius': 'FLE Standard Time', - 'Europe/Volgograd': 'Volgograd Standard Time', - 'Europe/Warsaw': 'Central European Standard Time', - 'Europe/Zagreb': 'Central European Standard Time', - 'Europe/Zaporozhye': 'FLE Standard Time', - 'Europe/Zurich': 'W. Europe Standard Time', - 'GB': 'GMT Standard Time', - 'GB-Eire': 'GMT Standard Time', - 'GMT+0': 'UTC', - 'GMT-0': 'UTC', - 'GMT0': 'UTC', - 'Greenwich': 'UTC', - 'Hongkong': 'China Standard Time', - 'Iceland': 'Greenwich Standard Time', - 'Indian/Antananarivo': 'E. Africa Standard Time', - 'Indian/Chagos': 'Central Asia Standard Time', - 'Indian/Christmas': 'SE Asia Standard Time', - 'Indian/Cocos': 'Myanmar Standard Time', - 'Indian/Comoro': 'E. Africa Standard Time', - 'Indian/Kerguelen': 'West Asia Standard Time', - 'Indian/Mahe': 'Mauritius Standard Time', - 'Indian/Maldives': 'West Asia Standard Time', - 'Indian/Mauritius': 'Mauritius Standard Time', - 'Indian/Mayotte': 'E. Africa Standard Time', - 'Indian/Reunion': 'Mauritius Standard Time', - 'Iran': 'Iran Standard Time', - 'Israel': 'Israel Standard Time', - 'Jamaica': 'SA Pacific Standard Time', - 'Japan': 'Tokyo Standard Time', - 'Kwajalein': 'UTC+12', - 'Libya': 'Libya Standard Time', - 'MST7MDT': 'Mountain Standard Time', - 'Mexico/BajaNorte': 'Pacific Standard Time (Mexico)', - 'Mexico/BajaSur': 'Mountain Standard Time (Mexico)', - 'Mexico/General': 'Central Standard Time (Mexico)', - 'NZ': 'New Zealand Standard Time', - 'NZ-CHAT': 'Chatham Islands Standard Time', - 'Navajo': 'Mountain Standard Time', - 'PRC': 'China Standard Time', - 'PST8PDT': 'Pacific Standard Time', - 'Pacific/Apia': 'Samoa Standard Time', - 'Pacific/Auckland': 'New Zealand Standard Time', - 'Pacific/Bougainville': 'Bougainville Standard Time', - 'Pacific/Chatham': 'Chatham Islands Standard Time', - 'Pacific/Easter': 'Easter Island Standard Time', - 'Pacific/Efate': 'Central Pacific Standard Time', - 'Pacific/Enderbury': 'UTC+13', - 'Pacific/Fakaofo': 'UTC+13', - 'Pacific/Fiji': 'Fiji Standard Time', - 'Pacific/Funafuti': 'UTC+12', - 'Pacific/Galapagos': 'Central America Standard Time', - 'Pacific/Gambier': 'UTC-09', - 'Pacific/Guadalcanal': 'Central Pacific Standard Time', - 'Pacific/Guam': 'West Pacific Standard Time', - 'Pacific/Honolulu': 'Hawaiian Standard Time', - 'Pacific/Johnston': 'Hawaiian Standard Time', - 'Pacific/Kiritimati': 'Line Islands Standard Time', - 'Pacific/Kosrae': 'Central Pacific Standard Time', - 'Pacific/Kwajalein': 'UTC+12', - 'Pacific/Majuro': 'UTC+12', - 'Pacific/Marquesas': 'Marquesas Standard Time', - 'Pacific/Midway': 'UTC-11', - 'Pacific/Nauru': 'UTC+12', - 'Pacific/Niue': 'UTC-11', - 'Pacific/Norfolk': 'Norfolk Standard Time', - 'Pacific/Noumea': 'Central Pacific Standard Time', - 'Pacific/Pago_Pago': 'UTC-11', - 'Pacific/Palau': 'Tokyo Standard Time', - 'Pacific/Pitcairn': 'UTC-08', - 'Pacific/Ponape': 'Central Pacific Standard Time', - 'Pacific/Port_Moresby': 'West Pacific Standard Time', - 'Pacific/Rarotonga': 'Hawaiian Standard Time', - 'Pacific/Saipan': 'West Pacific Standard Time', - 'Pacific/Samoa': 'UTC-11', - 'Pacific/Tahiti': 'Hawaiian Standard Time', - 'Pacific/Tarawa': 'UTC+12', - 'Pacific/Tongatapu': 'Tonga Standard Time', - 'Pacific/Truk': 'West Pacific Standard Time', - 'Pacific/Wake': 'UTC+12', - 'Pacific/Wallis': 'UTC+12', - 'Poland': 'Central European Standard Time', - 'Portugal': 'GMT Standard Time', - 'ROC': 'Taipei Standard Time', - 'ROK': 'Korea Standard Time', - 'Singapore': 'Singapore Standard Time', - 'Turkey': 'Turkey Standard Time', - 'UCT': 'UTC', - 'US/Alaska': 'Alaskan Standard Time', - 'US/Aleutian': 'Aleutian Standard Time', - 'US/Arizona': 'US Mountain Standard Time', - 'US/Central': 'Central Standard Time', - 'US/Eastern': 'Eastern Standard Time', - 'US/Hawaii': 'Hawaiian Standard Time', - 'US/Indiana-Starke': 'Central Standard Time', - 'US/Michigan': 'Eastern Standard Time', - 'US/Mountain': 'Mountain Standard Time', - 'US/Pacific': 'Pacific Standard Time', - 'US/Samoa': 'UTC-11', - 'UTC': 'UTC', - 'Universal': 'UTC', - 'W-SU': 'Russian Standard Time', - 'Zulu': 'UTC'} diff --git a/venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/INSTALLER b/venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/INSTALLER deleted file mode 100644 index a1b589e..0000000 --- a/venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/INSTALLER +++ /dev/null @@ -1 +0,0 @@ -pip diff --git a/venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/LICENSE.txt b/venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/LICENSE.txt deleted file mode 100644 index 429a176..0000000 --- a/venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/LICENSE.txt +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2008-2020 Andrey Petrov and contributors (see CONTRIBUTORS.txt) - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/METADATA b/venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/METADATA deleted file mode 100644 index af99541..0000000 --- a/venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/METADATA +++ /dev/null @@ -1,1388 +0,0 @@ -Metadata-Version: 2.1 -Name: urllib3 -Version: 1.26.6 -Summary: HTTP library with thread-safe connection pooling, file post, and more. -Home-page: https://urllib3.readthedocs.io/ -Author: Andrey Petrov -Author-email: andrey.petrov@shazow.net -License: MIT -Project-URL: Documentation, https://urllib3.readthedocs.io/ -Project-URL: Code, https://github.com/urllib3/urllib3 -Project-URL: Issue tracker, https://github.com/urllib3/urllib3/issues -Keywords: urllib httplib threadsafe filepost http https ssl pooling -Platform: UNKNOWN -Classifier: Environment :: Web Environment -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: MIT License -Classifier: Operating System :: OS Independent -Classifier: Programming Language :: Python -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.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 :: Implementation :: CPython -Classifier: Programming Language :: Python :: Implementation :: PyPy -Classifier: Topic :: Internet :: WWW/HTTP -Classifier: Topic :: Software Development :: Libraries -Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4 -Description-Content-Type: text/x-rst -License-File: LICENSE.txt -Provides-Extra: brotli -Requires-Dist: brotlipy (>=0.6.0) ; extra == 'brotli' -Provides-Extra: secure -Requires-Dist: pyOpenSSL (>=0.14) ; extra == 'secure' -Requires-Dist: cryptography (>=1.3.4) ; extra == 'secure' -Requires-Dist: idna (>=2.0.0) ; extra == 'secure' -Requires-Dist: certifi ; extra == 'secure' -Requires-Dist: ipaddress ; (python_version == "2.7") and extra == 'secure' -Provides-Extra: socks -Requires-Dist: PySocks (!=1.5.7,<2.0,>=1.5.6) ; extra == 'socks' - - -urllib3 is a powerful, *user-friendly* HTTP client for Python. Much of the -Python ecosystem already uses urllib3 and you should too. -urllib3 brings many critical features that are missing from the Python -standard libraries: - -- Thread safety. -- Connection pooling. -- Client-side SSL/TLS verification. -- File uploads with multipart encoding. -- Helpers for retrying requests and dealing with HTTP redirects. -- Support for gzip, deflate, and brotli encoding. -- Proxy support for HTTP and SOCKS. -- 100% test coverage. - -urllib3 is powerful and easy to use: - -.. code-block:: python - - >>> import urllib3 - >>> http = urllib3.PoolManager() - >>> r = http.request('GET', 'http://httpbin.org/robots.txt') - >>> r.status - 200 - >>> r.data - 'User-agent: *\nDisallow: /deny\n' - - -Installing ----------- - -urllib3 can be installed with `pip <https://pip.pypa.io>`_:: - - $ python -m pip install urllib3 - -Alternatively, you can grab the latest source code from `GitHub <https://github.com/urllib3/urllib3>`_:: - - $ git clone git://github.com/urllib3/urllib3.git - $ python setup.py install - - -Documentation -------------- - -urllib3 has usage and reference documentation at `urllib3.readthedocs.io <https://urllib3.readthedocs.io>`_. - - -Contributing ------------- - -urllib3 happily accepts contributions. Please see our -`contributing documentation <https://urllib3.readthedocs.io/en/latest/contributing.html>`_ -for some tips on getting started. - - -Security Disclosures --------------------- - -To report a security vulnerability, please use the -`Tidelift security contact <https://tidelift.com/security>`_. -Tidelift will coordinate the fix and disclosure with maintainers. - - -Maintainers ------------ - -- `@sethmlarson <https://github.com/sethmlarson>`__ (Seth M. Larson) -- `@pquentin <https://github.com/pquentin>`__ (Quentin Pradet) -- `@theacodes <https://github.com/theacodes>`__ (Thea Flowers) -- `@haikuginger <https://github.com/haikuginger>`__ (Jess Shapiro) -- `@lukasa <https://github.com/lukasa>`__ (Cory Benfield) -- `@sigmavirus24 <https://github.com/sigmavirus24>`__ (Ian Stapleton Cordasco) -- `@shazow <https://github.com/shazow>`__ (Andrey Petrov) - -👋 - - -Sponsorship ------------ - -If your company benefits from this library, please consider `sponsoring its -development <https://urllib3.readthedocs.io/en/latest/sponsors.html>`_. - - -For Enterprise --------------- - -.. |tideliftlogo| image:: https://nedbatchelder.com/pix/Tidelift_Logos_RGB_Tidelift_Shorthand_On-White_small.png - :width: 75 - :alt: Tidelift - -.. list-table:: - :widths: 10 100 - - * - |tideliftlogo| - - Professional support for urllib3 is available as part of the `Tidelift - Subscription`_. Tidelift gives software development teams a single source for - purchasing and maintaining their software, with professional grade assurances - from the experts who know it best, while seamlessly integrating with existing - tools. - -.. _Tidelift Subscription: https://tidelift.com/subscription/pkg/pypi-urllib3?utm_source=pypi-urllib3&utm_medium=referral&utm_campaign=readme - - -Changes -======= - -1.26.6 (2021-06-25) -------------------- - -* Deprecated the ``urllib3.contrib.ntlmpool`` module. urllib3 is not able to support - it properly due to `reasons listed in this issue <https://github.com/urllib3/urllib3/issues/2282>`_. - If you are a user of this module please leave a comment. -* Changed ``HTTPConnection.request_chunked()`` to not erroneously emit multiple - ``Transfer-Encoding`` headers in the case that one is already specified. -* Fixed typo in deprecation message to recommend ``Retry.DEFAULT_ALLOWED_METHODS``. - - -1.26.5 (2021-05-26) -------------------- - -* Fixed deprecation warnings emitted in Python 3.10. -* Updated vendored ``six`` library to 1.16.0. -* Improved performance of URL parser when splitting - the authority component. - - -1.26.4 (2021-03-15) -------------------- - -* Changed behavior of the default ``SSLContext`` when connecting to HTTPS proxy - during HTTPS requests. The default ``SSLContext`` now sets ``check_hostname=True``. - - -1.26.3 (2021-01-26) -------------------- - -* Fixed bytes and string comparison issue with headers (Pull #2141) - -* Changed ``ProxySchemeUnknown`` error message to be - more actionable if the user supplies a proxy URL without - a scheme. (Pull #2107) - - -1.26.2 (2020-11-12) -------------------- - -* Fixed an issue where ``wrap_socket`` and ``CERT_REQUIRED`` wouldn't - be imported properly on Python 2.7.8 and earlier (Pull #2052) - - -1.26.1 (2020-11-11) -------------------- - -* Fixed an issue where two ``User-Agent`` headers would be sent if a - ``User-Agent`` header key is passed as ``bytes`` (Pull #2047) - - -1.26.0 (2020-11-10) -------------------- - -* **NOTE: urllib3 v2.0 will drop support for Python 2**. - `Read more in the v2.0 Roadmap <https://urllib3.readthedocs.io/en/latest/v2-roadmap.html>`_. - -* Added support for HTTPS proxies contacting HTTPS servers (Pull #1923, Pull #1806) - -* Deprecated negotiating TLSv1 and TLSv1.1 by default. Users that - still wish to use TLS earlier than 1.2 without a deprecation warning - should opt-in explicitly by setting ``ssl_version=ssl.PROTOCOL_TLSv1_1`` (Pull #2002) - **Starting in urllib3 v2.0: Connections that receive a ``DeprecationWarning`` will fail** - -* Deprecated ``Retry`` options ``Retry.DEFAULT_METHOD_WHITELIST``, ``Retry.DEFAULT_REDIRECT_HEADERS_BLACKLIST`` - and ``Retry(method_whitelist=...)`` in favor of ``Retry.DEFAULT_ALLOWED_METHODS``, - ``Retry.DEFAULT_REMOVE_HEADERS_ON_REDIRECT``, and ``Retry(allowed_methods=...)`` - (Pull #2000) **Starting in urllib3 v2.0: Deprecated options will be removed** - -* Added default ``User-Agent`` header to every request (Pull #1750) - -* Added ``urllib3.util.SKIP_HEADER`` for skipping ``User-Agent``, ``Accept-Encoding``, - and ``Host`` headers from being automatically emitted with requests (Pull #2018) - -* Collapse ``transfer-encoding: chunked`` request data and framing into - the same ``socket.send()`` call (Pull #1906) - -* Send ``http/1.1`` ALPN identifier with every TLS handshake by default (Pull #1894) - -* Properly terminate SecureTransport connections when CA verification fails (Pull #1977) - -* Don't emit an ``SNIMissingWarning`` when passing ``server_hostname=None`` - to SecureTransport (Pull #1903) - -* Disabled requesting TLSv1.2 session tickets as they weren't being used by urllib3 (Pull #1970) - -* Suppress ``BrokenPipeError`` when writing request body after the server - has closed the socket (Pull #1524) - -* Wrap ``ssl.SSLError`` that can be raised from reading a socket (e.g. "bad MAC") - into an ``urllib3.exceptions.SSLError`` (Pull #1939) - - -1.25.11 (2020-10-19) --------------------- - -* Fix retry backoff time parsed from ``Retry-After`` header when given - in the HTTP date format. The HTTP date was parsed as the local timezone - rather than accounting for the timezone in the HTTP date (typically - UTC) (Pull #1932, Pull #1935, Pull #1938, Pull #1949) - -* Fix issue where an error would be raised when the ``SSLKEYLOGFILE`` - environment variable was set to the empty string. Now ``SSLContext.keylog_file`` - is not set in this situation (Pull #2016) - - -1.25.10 (2020-07-22) --------------------- - -* Added support for ``SSLKEYLOGFILE`` environment variable for - logging TLS session keys with use with programs like - Wireshark for decrypting captured web traffic (Pull #1867) - -* Fixed loading of SecureTransport libraries on macOS Big Sur - due to the new dynamic linker cache (Pull #1905) - -* Collapse chunked request bodies data and framing into one - call to ``send()`` to reduce the number of TCP packets by 2-4x (Pull #1906) - -* Don't insert ``None`` into ``ConnectionPool`` if the pool - was empty when requesting a connection (Pull #1866) - -* Avoid ``hasattr`` call in ``BrotliDecoder.decompress()`` (Pull #1858) - - -1.25.9 (2020-04-16) -------------------- - -* Added ``InvalidProxyConfigurationWarning`` which is raised when - erroneously specifying an HTTPS proxy URL. urllib3 doesn't currently - support connecting to HTTPS proxies but will soon be able to - and we would like users to migrate properly without much breakage. - - See `this GitHub issue <https://github.com/urllib3/urllib3/issues/1850>`_ - for more information on how to fix your proxy config. (Pull #1851) - -* Drain connection after ``PoolManager`` redirect (Pull #1817) - -* Ensure ``load_verify_locations`` raises ``SSLError`` for all backends (Pull #1812) - -* Rename ``VerifiedHTTPSConnection`` to ``HTTPSConnection`` (Pull #1805) - -* Allow the CA certificate data to be passed as a string (Pull #1804) - -* Raise ``ValueError`` if method contains control characters (Pull #1800) - -* Add ``__repr__`` to ``Timeout`` (Pull #1795) - - -1.25.8 (2020-01-20) -------------------- - -* Drop support for EOL Python 3.4 (Pull #1774) - -* Optimize _encode_invalid_chars (Pull #1787) - - -1.25.7 (2019-11-11) -------------------- - -* Preserve ``chunked`` parameter on retries (Pull #1715, Pull #1734) - -* Allow unset ``SERVER_SOFTWARE`` in App Engine (Pull #1704, Issue #1470) - -* Fix issue where URL fragment was sent within the request target. (Pull #1732) - -* Fix issue where an empty query section in a URL would fail to parse. (Pull #1732) - -* Remove TLS 1.3 support in SecureTransport due to Apple removing support (Pull #1703) - - -1.25.6 (2019-09-24) -------------------- - -* Fix issue where tilde (``~``) characters were incorrectly - percent-encoded in the path. (Pull #1692) - - -1.25.5 (2019-09-19) -------------------- - -* Add mitigation for BPO-37428 affecting Python <3.7.4 and OpenSSL 1.1.1+ which - caused certificate verification to be enabled when using ``cert_reqs=CERT_NONE``. - (Issue #1682) - - -1.25.4 (2019-09-19) -------------------- - -* Propagate Retry-After header settings to subsequent retries. (Pull #1607) - -* Fix edge case where Retry-After header was still respected even when - explicitly opted out of. (Pull #1607) - -* Remove dependency on ``rfc3986`` for URL parsing. - -* Fix issue where URLs containing invalid characters within ``Url.auth`` would - raise an exception instead of percent-encoding those characters. - -* Add support for ``HTTPResponse.auto_close = False`` which makes HTTP responses - work well with BufferedReaders and other ``io`` module features. (Pull #1652) - -* Percent-encode invalid characters in URL for ``HTTPConnectionPool.request()`` (Pull #1673) - - -1.25.3 (2019-05-23) -------------------- - -* Change ``HTTPSConnection`` to load system CA certificates - when ``ca_certs``, ``ca_cert_dir``, and ``ssl_context`` are - unspecified. (Pull #1608, Issue #1603) - -* Upgrade bundled rfc3986 to v1.3.2. (Pull #1609, Issue #1605) - - -1.25.2 (2019-04-28) -------------------- - -* Change ``is_ipaddress`` to not detect IPvFuture addresses. (Pull #1583) - -* Change ``parse_url`` to percent-encode invalid characters within the - path, query, and target components. (Pull #1586) - - -1.25.1 (2019-04-24) -------------------- - -* Add support for Google's ``Brotli`` package. (Pull #1572, Pull #1579) - -* Upgrade bundled rfc3986 to v1.3.1 (Pull #1578) - - -1.25 (2019-04-22) ------------------ - -* Require and validate certificates by default when using HTTPS (Pull #1507) - -* Upgraded ``urllib3.utils.parse_url()`` to be RFC 3986 compliant. (Pull #1487) - -* Added support for ``key_password`` for ``HTTPSConnectionPool`` to use - encrypted ``key_file`` without creating your own ``SSLContext`` object. (Pull #1489) - -* Add TLSv1.3 support to CPython, pyOpenSSL, and SecureTransport ``SSLContext`` - implementations. (Pull #1496) - -* Switched the default multipart header encoder from RFC 2231 to HTML 5 working draft. (Issue #303, Pull #1492) - -* Fixed issue where OpenSSL would block if an encrypted client private key was - given and no password was given. Instead an ``SSLError`` is raised. (Pull #1489) - -* Added support for Brotli content encoding. It is enabled automatically if - ``brotlipy`` package is installed which can be requested with - ``urllib3[brotli]`` extra. (Pull #1532) - -* Drop ciphers using DSS key exchange from default TLS cipher suites. - Improve default ciphers when using SecureTransport. (Pull #1496) - -* Implemented a more efficient ``HTTPResponse.__iter__()`` method. (Issue #1483) - -1.24.3 (2019-05-01) -------------------- - -* Apply fix for CVE-2019-9740. (Pull #1591) - -1.24.2 (2019-04-17) -------------------- - -* Don't load system certificates by default when any other ``ca_certs``, ``ca_certs_dir`` or - ``ssl_context`` parameters are specified. - -* Remove Authorization header regardless of case when redirecting to cross-site. (Issue #1510) - -* Add support for IPv6 addresses in subjectAltName section of certificates. (Issue #1269) - - -1.24.1 (2018-11-02) -------------------- - -* Remove quadratic behavior within ``GzipDecoder.decompress()`` (Issue #1467) - -* Restored functionality of ``ciphers`` parameter for ``create_urllib3_context()``. (Issue #1462) - - -1.24 (2018-10-16) ------------------ - -* Allow key_server_hostname to be specified when initializing a PoolManager to allow custom SNI to be overridden. (Pull #1449) - -* Test against Python 3.7 on AppVeyor. (Pull #1453) - -* Early-out ipv6 checks when running on App Engine. (Pull #1450) - -* Change ambiguous description of backoff_factor (Pull #1436) - -* Add ability to handle multiple Content-Encodings (Issue #1441 and Pull #1442) - -* Skip DNS names that can't be idna-decoded when using pyOpenSSL (Issue #1405). - -* Add a server_hostname parameter to HTTPSConnection which allows for - overriding the SNI hostname sent in the handshake. (Pull #1397) - -* Drop support for EOL Python 2.6 (Pull #1429 and Pull #1430) - -* Fixed bug where responses with header Content-Type: message/* erroneously - raised HeaderParsingError, resulting in a warning being logged. (Pull #1439) - -* Move urllib3 to src/urllib3 (Pull #1409) - - -1.23 (2018-06-04) ------------------ - -* Allow providing a list of headers to strip from requests when redirecting - to a different host. Defaults to the ``Authorization`` header. Different - headers can be set via ``Retry.remove_headers_on_redirect``. (Issue #1316) - -* Fix ``util.selectors._fileobj_to_fd`` to accept ``long`` (Issue #1247). - -* Dropped Python 3.3 support. (Pull #1242) - -* Put the connection back in the pool when calling stream() or read_chunked() on - a chunked HEAD response. (Issue #1234) - -* Fixed pyOpenSSL-specific ssl client authentication issue when clients - attempted to auth via certificate + chain (Issue #1060) - -* Add the port to the connectionpool connect print (Pull #1251) - -* Don't use the ``uuid`` module to create multipart data boundaries. (Pull #1380) - -* ``read_chunked()`` on a closed response returns no chunks. (Issue #1088) - -* Add Python 2.6 support to ``contrib.securetransport`` (Pull #1359) - -* Added support for auth info in url for SOCKS proxy (Pull #1363) - - -1.22 (2017-07-20) ------------------ - -* Fixed missing brackets in ``HTTP CONNECT`` when connecting to IPv6 address via - IPv6 proxy. (Issue #1222) - -* Made the connection pool retry on ``SSLError``. The original ``SSLError`` - is available on ``MaxRetryError.reason``. (Issue #1112) - -* Drain and release connection before recursing on retry/redirect. Fixes - deadlocks with a blocking connectionpool. (Issue #1167) - -* Fixed compatibility for cookiejar. (Issue #1229) - -* pyopenssl: Use vendored version of ``six``. (Issue #1231) - - -1.21.1 (2017-05-02) -------------------- - -* Fixed SecureTransport issue that would cause long delays in response body - delivery. (Pull #1154) - -* Fixed regression in 1.21 that threw exceptions when users passed the - ``socket_options`` flag to the ``PoolManager``. (Issue #1165) - -* Fixed regression in 1.21 that threw exceptions when users passed the - ``assert_hostname`` or ``assert_fingerprint`` flag to the ``PoolManager``. - (Pull #1157) - - -1.21 (2017-04-25) ------------------ - -* Improved performance of certain selector system calls on Python 3.5 and - later. (Pull #1095) - -* Resolved issue where the PyOpenSSL backend would not wrap SysCallError - exceptions appropriately when sending data. (Pull #1125) - -* Selectors now detects a monkey-patched select module after import for modules - that patch the select module like eventlet, greenlet. (Pull #1128) - -* Reduced memory consumption when streaming zlib-compressed responses - (as opposed to raw deflate streams). (Pull #1129) - -* Connection pools now use the entire request context when constructing the - pool key. (Pull #1016) - -* ``PoolManager.connection_from_*`` methods now accept a new keyword argument, - ``pool_kwargs``, which are merged with the existing ``connection_pool_kw``. - (Pull #1016) - -* Add retry counter for ``status_forcelist``. (Issue #1147) - -* Added ``contrib`` module for using SecureTransport on macOS: - ``urllib3.contrib.securetransport``. (Pull #1122) - -* urllib3 now only normalizes the case of ``http://`` and ``https://`` schemes: - for schemes it does not recognise, it assumes they are case-sensitive and - leaves them unchanged. - (Issue #1080) - - -1.20 (2017-01-19) ------------------ - -* Added support for waiting for I/O using selectors other than select, - improving urllib3's behaviour with large numbers of concurrent connections. - (Pull #1001) - -* Updated the date for the system clock check. (Issue #1005) - -* ConnectionPools now correctly consider hostnames to be case-insensitive. - (Issue #1032) - -* Outdated versions of PyOpenSSL now cause the PyOpenSSL contrib module - to fail when it is injected, rather than at first use. (Pull #1063) - -* Outdated versions of cryptography now cause the PyOpenSSL contrib module - to fail when it is injected, rather than at first use. (Issue #1044) - -* Automatically attempt to rewind a file-like body object when a request is - retried or redirected. (Pull #1039) - -* Fix some bugs that occur when modules incautiously patch the queue module. - (Pull #1061) - -* Prevent retries from occurring on read timeouts for which the request method - was not in the method whitelist. (Issue #1059) - -* Changed the PyOpenSSL contrib module to lazily load idna to avoid - unnecessarily bloating the memory of programs that don't need it. (Pull - #1076) - -* Add support for IPv6 literals with zone identifiers. (Pull #1013) - -* Added support for socks5h:// and socks4a:// schemes when working with SOCKS - proxies, and controlled remote DNS appropriately. (Issue #1035) - - -1.19.1 (2016-11-16) -------------------- - -* Fixed AppEngine import that didn't function on Python 3.5. (Pull #1025) - - -1.19 (2016-11-03) ------------------ - -* urllib3 now respects Retry-After headers on 413, 429, and 503 responses when - using the default retry logic. (Pull #955) - -* Remove markers from setup.py to assist ancient setuptools versions. (Issue - #986) - -* Disallow superscripts and other integerish things in URL ports. (Issue #989) - -* Allow urllib3's HTTPResponse.stream() method to continue to work with - non-httplib underlying FPs. (Pull #990) - -* Empty filenames in multipart headers are now emitted as such, rather than - being suppressed. (Issue #1015) - -* Prefer user-supplied Host headers on chunked uploads. (Issue #1009) - - -1.18.1 (2016-10-27) -------------------- - -* CVE-2016-9015. Users who are using urllib3 version 1.17 or 1.18 along with - PyOpenSSL injection and OpenSSL 1.1.0 *must* upgrade to this version. This - release fixes a vulnerability whereby urllib3 in the above configuration - would silently fail to validate TLS certificates due to erroneously setting - invalid flags in OpenSSL's ``SSL_CTX_set_verify`` function. These erroneous - flags do not cause a problem in OpenSSL versions before 1.1.0, which - interprets the presence of any flag as requesting certificate validation. - - There is no PR for this patch, as it was prepared for simultaneous disclosure - and release. The master branch received the same fix in Pull #1010. - - -1.18 (2016-09-26) ------------------ - -* Fixed incorrect message for IncompleteRead exception. (Pull #973) - -* Accept ``iPAddress`` subject alternative name fields in TLS certificates. - (Issue #258) - -* Fixed consistency of ``HTTPResponse.closed`` between Python 2 and 3. - (Issue #977) - -* Fixed handling of wildcard certificates when using PyOpenSSL. (Issue #979) - - -1.17 (2016-09-06) ------------------ - -* Accept ``SSLContext`` objects for use in SSL/TLS negotiation. (Issue #835) - -* ConnectionPool debug log now includes scheme, host, and port. (Issue #897) - -* Substantially refactored documentation. (Issue #887) - -* Used URLFetch default timeout on AppEngine, rather than hardcoding our own. - (Issue #858) - -* Normalize the scheme and host in the URL parser (Issue #833) - -* ``HTTPResponse`` contains the last ``Retry`` object, which now also - contains retries history. (Issue #848) - -* Timeout can no longer be set as boolean, and must be greater than zero. - (Pull #924) - -* Removed pyasn1 and ndg-httpsclient from dependencies used for PyOpenSSL. We - now use cryptography and idna, both of which are already dependencies of - PyOpenSSL. (Pull #930) - -* Fixed infinite loop in ``stream`` when amt=None. (Issue #928) - -* Try to use the operating system's certificates when we are using an - ``SSLContext``. (Pull #941) - -* Updated cipher suite list to allow ChaCha20+Poly1305. AES-GCM is preferred to - ChaCha20, but ChaCha20 is then preferred to everything else. (Pull #947) - -* Updated cipher suite list to remove 3DES-based cipher suites. (Pull #958) - -* Removed the cipher suite fallback to allow HIGH ciphers. (Pull #958) - -* Implemented ``length_remaining`` to determine remaining content - to be read. (Pull #949) - -* Implemented ``enforce_content_length`` to enable exceptions when - incomplete data chunks are received. (Pull #949) - -* Dropped connection start, dropped connection reset, redirect, forced retry, - and new HTTPS connection log levels to DEBUG, from INFO. (Pull #967) - - -1.16 (2016-06-11) ------------------ - -* Disable IPv6 DNS when IPv6 connections are not possible. (Issue #840) - -* Provide ``key_fn_by_scheme`` pool keying mechanism that can be - overridden. (Issue #830) - -* Normalize scheme and host to lowercase for pool keys, and include - ``source_address``. (Issue #830) - -* Cleaner exception chain in Python 3 for ``_make_request``. - (Issue #861) - -* Fixed installing ``urllib3[socks]`` extra. (Issue #864) - -* Fixed signature of ``ConnectionPool.close`` so it can actually safely be - called by subclasses. (Issue #873) - -* Retain ``release_conn`` state across retries. (Issues #651, #866) - -* Add customizable ``HTTPConnectionPool.ResponseCls``, which defaults to - ``HTTPResponse`` but can be replaced with a subclass. (Issue #879) - - -1.15.1 (2016-04-11) -------------------- - -* Fix packaging to include backports module. (Issue #841) - - -1.15 (2016-04-06) ------------------ - -* Added Retry(raise_on_status=False). (Issue #720) - -* Always use setuptools, no more distutils fallback. (Issue #785) - -* Dropped support for Python 3.2. (Issue #786) - -* Chunked transfer encoding when requesting with ``chunked=True``. - (Issue #790) - -* Fixed regression with IPv6 port parsing. (Issue #801) - -* Append SNIMissingWarning messages to allow users to specify it in - the PYTHONWARNINGS environment variable. (Issue #816) - -* Handle unicode headers in Py2. (Issue #818) - -* Log certificate when there is a hostname mismatch. (Issue #820) - -* Preserve order of request/response headers. (Issue #821) - - -1.14 (2015-12-29) ------------------ - -* contrib: SOCKS proxy support! (Issue #762) - -* Fixed AppEngine handling of transfer-encoding header and bug - in Timeout defaults checking. (Issue #763) - - -1.13.1 (2015-12-18) -------------------- - -* Fixed regression in IPv6 + SSL for match_hostname. (Issue #761) - - -1.13 (2015-12-14) ------------------ - -* Fixed ``pip install urllib3[secure]`` on modern pip. (Issue #706) - -* pyopenssl: Fixed SSL3_WRITE_PENDING error. (Issue #717) - -* pyopenssl: Support for TLSv1.1 and TLSv1.2. (Issue #696) - -* Close connections more defensively on exception. (Issue #734) - -* Adjusted ``read_chunked`` to handle gzipped, chunk-encoded bodies without - repeatedly flushing the decoder, to function better on Jython. (Issue #743) - -* Accept ``ca_cert_dir`` for SSL-related PoolManager configuration. (Issue #758) - - -1.12 (2015-09-03) ------------------ - -* Rely on ``six`` for importing ``httplib`` to work around - conflicts with other Python 3 shims. (Issue #688) - -* Add support for directories of certificate authorities, as supported by - OpenSSL. (Issue #701) - -* New exception: ``NewConnectionError``, raised when we fail to establish - a new connection, usually ``ECONNREFUSED`` socket error. - - -1.11 (2015-07-21) ------------------ - -* When ``ca_certs`` is given, ``cert_reqs`` defaults to - ``'CERT_REQUIRED'``. (Issue #650) - -* ``pip install urllib3[secure]`` will install Certifi and - PyOpenSSL as dependencies. (Issue #678) - -* Made ``HTTPHeaderDict`` usable as a ``headers`` input value - (Issues #632, #679) - -* Added `urllib3.contrib.appengine <https://urllib3.readthedocs.io/en/latest/contrib.html#google-app-engine>`_ - which has an ``AppEngineManager`` for using ``URLFetch`` in a - Google AppEngine environment. (Issue #664) - -* Dev: Added test suite for AppEngine. (Issue #631) - -* Fix performance regression when using PyOpenSSL. (Issue #626) - -* Passing incorrect scheme (e.g. ``foo://``) will raise - ``ValueError`` instead of ``AssertionError`` (backwards - compatible for now, but please migrate). (Issue #640) - -* Fix pools not getting replenished when an error occurs during a - request using ``release_conn=False``. (Issue #644) - -* Fix pool-default headers not applying for url-encoded requests - like GET. (Issue #657) - -* log.warning in Python 3 when headers are skipped due to parsing - errors. (Issue #642) - -* Close and discard connections if an error occurs during read. - (Issue #660) - -* Fix host parsing for IPv6 proxies. (Issue #668) - -* Separate warning type SubjectAltNameWarning, now issued once - per host. (Issue #671) - -* Fix ``httplib.IncompleteRead`` not getting converted to - ``ProtocolError`` when using ``HTTPResponse.stream()`` - (Issue #674) - -1.10.4 (2015-05-03) -------------------- - -* Migrate tests to Tornado 4. (Issue #594) - -* Append default warning configuration rather than overwrite. - (Issue #603) - -* Fix streaming decoding regression. (Issue #595) - -* Fix chunked requests losing state across keep-alive connections. - (Issue #599) - -* Fix hanging when chunked HEAD response has no body. (Issue #605) - - -1.10.3 (2015-04-21) -------------------- - -* Emit ``InsecurePlatformWarning`` when SSLContext object is missing. - (Issue #558) - -* Fix regression of duplicate header keys being discarded. - (Issue #563) - -* ``Response.stream()`` returns a generator for chunked responses. - (Issue #560) - -* Set upper-bound timeout when waiting for a socket in PyOpenSSL. - (Issue #585) - -* Work on platforms without `ssl` module for plain HTTP requests. - (Issue #587) - -* Stop relying on the stdlib's default cipher list. (Issue #588) - - -1.10.2 (2015-02-25) -------------------- - -* Fix file descriptor leakage on retries. (Issue #548) - -* Removed RC4 from default cipher list. (Issue #551) - -* Header performance improvements. (Issue #544) - -* Fix PoolManager not obeying redirect retry settings. (Issue #553) - - -1.10.1 (2015-02-10) -------------------- - -* Pools can be used as context managers. (Issue #545) - -* Don't re-use connections which experienced an SSLError. (Issue #529) - -* Don't fail when gzip decoding an empty stream. (Issue #535) - -* Add sha256 support for fingerprint verification. (Issue #540) - -* Fixed handling of header values containing commas. (Issue #533) - - -1.10 (2014-12-14) ------------------ - -* Disabled SSLv3. (Issue #473) - -* Add ``Url.url`` property to return the composed url string. (Issue #394) - -* Fixed PyOpenSSL + gevent ``WantWriteError``. (Issue #412) - -* ``MaxRetryError.reason`` will always be an exception, not string. - (Issue #481) - -* Fixed SSL-related timeouts not being detected as timeouts. (Issue #492) - -* Py3: Use ``ssl.create_default_context()`` when available. (Issue #473) - -* Emit ``InsecureRequestWarning`` for *every* insecure HTTPS request. - (Issue #496) - -* Emit ``SecurityWarning`` when certificate has no ``subjectAltName``. - (Issue #499) - -* Close and discard sockets which experienced SSL-related errors. - (Issue #501) - -* Handle ``body`` param in ``.request(...)``. (Issue #513) - -* Respect timeout with HTTPS proxy. (Issue #505) - -* PyOpenSSL: Handle ZeroReturnError exception. (Issue #520) - - -1.9.1 (2014-09-13) ------------------- - -* Apply socket arguments before binding. (Issue #427) - -* More careful checks if fp-like object is closed. (Issue #435) - -* Fixed packaging issues of some development-related files not - getting included. (Issue #440) - -* Allow performing *only* fingerprint verification. (Issue #444) - -* Emit ``SecurityWarning`` if system clock is waaay off. (Issue #445) - -* Fixed PyOpenSSL compatibility with PyPy. (Issue #450) - -* Fixed ``BrokenPipeError`` and ``ConnectionError`` handling in Py3. - (Issue #443) - - - -1.9 (2014-07-04) ----------------- - -* Shuffled around development-related files. If you're maintaining a distro - package of urllib3, you may need to tweak things. (Issue #415) - -* Unverified HTTPS requests will trigger a warning on the first request. See - our new `security documentation - <https://urllib3.readthedocs.io/en/latest/security.html>`_ for details. - (Issue #426) - -* New retry logic and ``urllib3.util.retry.Retry`` configuration object. - (Issue #326) - -* All raised exceptions should now wrapped in a - ``urllib3.exceptions.HTTPException``-extending exception. (Issue #326) - -* All errors during a retry-enabled request should be wrapped in - ``urllib3.exceptions.MaxRetryError``, including timeout-related exceptions - which were previously exempt. Underlying error is accessible from the - ``.reason`` property. (Issue #326) - -* ``urllib3.exceptions.ConnectionError`` renamed to - ``urllib3.exceptions.ProtocolError``. (Issue #326) - -* Errors during response read (such as IncompleteRead) are now wrapped in - ``urllib3.exceptions.ProtocolError``. (Issue #418) - -* Requesting an empty host will raise ``urllib3.exceptions.LocationValueError``. - (Issue #417) - -* Catch read timeouts over SSL connections as - ``urllib3.exceptions.ReadTimeoutError``. (Issue #419) - -* Apply socket arguments before connecting. (Issue #427) - - -1.8.3 (2014-06-23) ------------------- - -* Fix TLS verification when using a proxy in Python 3.4.1. (Issue #385) - -* Add ``disable_cache`` option to ``urllib3.util.make_headers``. (Issue #393) - -* Wrap ``socket.timeout`` exception with - ``urllib3.exceptions.ReadTimeoutError``. (Issue #399) - -* Fixed proxy-related bug where connections were being reused incorrectly. - (Issues #366, #369) - -* Added ``socket_options`` keyword parameter which allows to define - ``setsockopt`` configuration of new sockets. (Issue #397) - -* Removed ``HTTPConnection.tcp_nodelay`` in favor of - ``HTTPConnection.default_socket_options``. (Issue #397) - -* Fixed ``TypeError`` bug in Python 2.6.4. (Issue #411) - - -1.8.2 (2014-04-17) ------------------- - -* Fix ``urllib3.util`` not being included in the package. - - -1.8.1 (2014-04-17) ------------------- - -* Fix AppEngine bug of HTTPS requests going out as HTTP. (Issue #356) - -* Don't install ``dummyserver`` into ``site-packages`` as it's only needed - for the test suite. (Issue #362) - -* Added support for specifying ``source_address``. (Issue #352) - - -1.8 (2014-03-04) ----------------- - -* Improved url parsing in ``urllib3.util.parse_url`` (properly parse '@' in - username, and blank ports like 'hostname:'). - -* New ``urllib3.connection`` module which contains all the HTTPConnection - objects. - -* Several ``urllib3.util.Timeout``-related fixes. Also changed constructor - signature to a more sensible order. [Backwards incompatible] - (Issues #252, #262, #263) - -* Use ``backports.ssl_match_hostname`` if it's installed. (Issue #274) - -* Added ``.tell()`` method to ``urllib3.response.HTTPResponse`` which - returns the number of bytes read so far. (Issue #277) - -* Support for platforms without threading. (Issue #289) - -* Expand default-port comparison in ``HTTPConnectionPool.is_same_host`` - to allow a pool with no specified port to be considered equal to to an - HTTP/HTTPS url with port 80/443 explicitly provided. (Issue #305) - -* Improved default SSL/TLS settings to avoid vulnerabilities. - (Issue #309) - -* Fixed ``urllib3.poolmanager.ProxyManager`` not retrying on connect errors. - (Issue #310) - -* Disable Nagle's Algorithm on the socket for non-proxies. A subset of requests - will send the entire HTTP request ~200 milliseconds faster; however, some of - the resulting TCP packets will be smaller. (Issue #254) - -* Increased maximum number of SubjectAltNames in ``urllib3.contrib.pyopenssl`` - from the default 64 to 1024 in a single certificate. (Issue #318) - -* Headers are now passed and stored as a custom - ``urllib3.collections_.HTTPHeaderDict`` object rather than a plain ``dict``. - (Issue #329, #333) - -* Headers no longer lose their case on Python 3. (Issue #236) - -* ``urllib3.contrib.pyopenssl`` now uses the operating system's default CA - certificates on inject. (Issue #332) - -* Requests with ``retries=False`` will immediately raise any exceptions without - wrapping them in ``MaxRetryError``. (Issue #348) - -* Fixed open socket leak with SSL-related failures. (Issue #344, #348) - - -1.7.1 (2013-09-25) ------------------- - -* Added granular timeout support with new ``urllib3.util.Timeout`` class. - (Issue #231) - -* Fixed Python 3.4 support. (Issue #238) - - -1.7 (2013-08-14) ----------------- - -* More exceptions are now pickle-able, with tests. (Issue #174) - -* Fixed redirecting with relative URLs in Location header. (Issue #178) - -* Support for relative urls in ``Location: ...`` header. (Issue #179) - -* ``urllib3.response.HTTPResponse`` now inherits from ``io.IOBase`` for bonus - file-like functionality. (Issue #187) - -* Passing ``assert_hostname=False`` when creating a HTTPSConnectionPool will - skip hostname verification for SSL connections. (Issue #194) - -* New method ``urllib3.response.HTTPResponse.stream(...)`` which acts as a - generator wrapped around ``.read(...)``. (Issue #198) - -* IPv6 url parsing enforces brackets around the hostname. (Issue #199) - -* Fixed thread race condition in - ``urllib3.poolmanager.PoolManager.connection_from_host(...)`` (Issue #204) - -* ``ProxyManager`` requests now include non-default port in ``Host: ...`` - header. (Issue #217) - -* Added HTTPS proxy support in ``ProxyManager``. (Issue #170 #139) - -* New ``RequestField`` object can be passed to the ``fields=...`` param which - can specify headers. (Issue #220) - -* Raise ``urllib3.exceptions.ProxyError`` when connecting to proxy fails. - (Issue #221) - -* Use international headers when posting file names. (Issue #119) - -* Improved IPv6 support. (Issue #203) - - -1.6 (2013-04-25) ----------------- - -* Contrib: Optional SNI support for Py2 using PyOpenSSL. (Issue #156) - -* ``ProxyManager`` automatically adds ``Host: ...`` header if not given. - -* Improved SSL-related code. ``cert_req`` now optionally takes a string like - "REQUIRED" or "NONE". Same with ``ssl_version`` takes strings like "SSLv23" - The string values reflect the suffix of the respective constant variable. - (Issue #130) - -* Vendored ``socksipy`` now based on Anorov's fork which handles unexpectedly - closed proxy connections and larger read buffers. (Issue #135) - -* Ensure the connection is closed if no data is received, fixes connection leak - on some platforms. (Issue #133) - -* Added SNI support for SSL/TLS connections on Py32+. (Issue #89) - -* Tests fixed to be compatible with Py26 again. (Issue #125) - -* Added ability to choose SSL version by passing an ``ssl.PROTOCOL_*`` constant - to the ``ssl_version`` parameter of ``HTTPSConnectionPool``. (Issue #109) - -* Allow an explicit content type to be specified when encoding file fields. - (Issue #126) - -* Exceptions are now pickleable, with tests. (Issue #101) - -* Fixed default headers not getting passed in some cases. (Issue #99) - -* Treat "content-encoding" header value as case-insensitive, per RFC 2616 - Section 3.5. (Issue #110) - -* "Connection Refused" SocketErrors will get retried rather than raised. - (Issue #92) - -* Updated vendored ``six``, no longer overrides the global ``six`` module - namespace. (Issue #113) - -* ``urllib3.exceptions.MaxRetryError`` contains a ``reason`` property holding - the exception that prompted the final retry. If ``reason is None`` then it - was due to a redirect. (Issue #92, #114) - -* Fixed ``PoolManager.urlopen()`` from not redirecting more than once. - (Issue #149) - -* Don't assume ``Content-Type: text/plain`` for multi-part encoding parameters - that are not files. (Issue #111) - -* Pass `strict` param down to ``httplib.HTTPConnection``. (Issue #122) - -* Added mechanism to verify SSL certificates by fingerprint (md5, sha1) or - against an arbitrary hostname (when connecting by IP or for misconfigured - servers). (Issue #140) - -* Streaming decompression support. (Issue #159) - - -1.5 (2012-08-02) ----------------- - -* Added ``urllib3.add_stderr_logger()`` for quickly enabling STDERR debug - logging in urllib3. - -* Native full URL parsing (including auth, path, query, fragment) available in - ``urllib3.util.parse_url(url)``. - -* Built-in redirect will switch method to 'GET' if status code is 303. - (Issue #11) - -* ``urllib3.PoolManager`` strips the scheme and host before sending the request - uri. (Issue #8) - -* New ``urllib3.exceptions.DecodeError`` exception for when automatic decoding, - based on the Content-Type header, fails. - -* Fixed bug with pool depletion and leaking connections (Issue #76). Added - explicit connection closing on pool eviction. Added - ``urllib3.PoolManager.clear()``. - -* 99% -> 100% unit test coverage. - - -1.4 (2012-06-16) ----------------- - -* Minor AppEngine-related fixes. - -* Switched from ``mimetools.choose_boundary`` to ``uuid.uuid4()``. - -* Improved url parsing. (Issue #73) - -* IPv6 url support. (Issue #72) - - -1.3 (2012-03-25) ----------------- - -* Removed pre-1.0 deprecated API. - -* Refactored helpers into a ``urllib3.util`` submodule. - -* Fixed multipart encoding to support list-of-tuples for keys with multiple - values. (Issue #48) - -* Fixed multiple Set-Cookie headers in response not getting merged properly in - Python 3. (Issue #53) - -* AppEngine support with Py27. (Issue #61) - -* Minor ``encode_multipart_formdata`` fixes related to Python 3 strings vs - bytes. - - -1.2.2 (2012-02-06) ------------------- - -* Fixed packaging bug of not shipping ``test-requirements.txt``. (Issue #47) - - -1.2.1 (2012-02-05) ------------------- - -* Fixed another bug related to when ``ssl`` module is not available. (Issue #41) - -* Location parsing errors now raise ``urllib3.exceptions.LocationParseError`` - which inherits from ``ValueError``. - - -1.2 (2012-01-29) ----------------- - -* Added Python 3 support (tested on 3.2.2) - -* Dropped Python 2.5 support (tested on 2.6.7, 2.7.2) - -* Use ``select.poll`` instead of ``select.select`` for platforms that support - it. - -* Use ``Queue.LifoQueue`` instead of ``Queue.Queue`` for more aggressive - connection reusing. Configurable by overriding ``ConnectionPool.QueueCls``. - -* Fixed ``ImportError`` during install when ``ssl`` module is not available. - (Issue #41) - -* Fixed ``PoolManager`` redirects between schemes (such as HTTP -> HTTPS) not - completing properly. (Issue #28, uncovered by Issue #10 in v1.1) - -* Ported ``dummyserver`` to use ``tornado`` instead of ``webob`` + - ``eventlet``. Removed extraneous unsupported dummyserver testing backends. - Added socket-level tests. - -* More tests. Achievement Unlocked: 99% Coverage. - - -1.1 (2012-01-07) ----------------- - -* Refactored ``dummyserver`` to its own root namespace module (used for - testing). - -* Added hostname verification for ``VerifiedHTTPSConnection`` by vendoring in - Py32's ``ssl_match_hostname``. (Issue #25) - -* Fixed cross-host HTTP redirects when using ``PoolManager``. (Issue #10) - -* Fixed ``decode_content`` being ignored when set through ``urlopen``. (Issue - #27) - -* Fixed timeout-related bugs. (Issues #17, #23) - - -1.0.2 (2011-11-04) ------------------- - -* Fixed typo in ``VerifiedHTTPSConnection`` which would only present as a bug if - you're using the object manually. (Thanks pyos) - -* Made RecentlyUsedContainer (and consequently PoolManager) more thread-safe by - wrapping the access log in a mutex. (Thanks @christer) - -* Made RecentlyUsedContainer more dict-like (corrected ``__delitem__`` and - ``__getitem__`` behaviour), with tests. Shouldn't affect core urllib3 code. - - -1.0.1 (2011-10-10) ------------------- - -* Fixed a bug where the same connection would get returned into the pool twice, - causing extraneous "HttpConnectionPool is full" log warnings. - - -1.0 (2011-10-08) ----------------- - -* Added ``PoolManager`` with LRU expiration of connections (tested and - documented). -* Added ``ProxyManager`` (needs tests, docs, and confirmation that it works - with HTTPS proxies). -* Added optional partial-read support for responses when - ``preload_content=False``. You can now make requests and just read the headers - without loading the content. -* Made response decoding optional (default on, same as before). -* Added optional explicit boundary string for ``encode_multipart_formdata``. -* Convenience request methods are now inherited from ``RequestMethods``. Old - helpers like ``get_url`` and ``post_url`` should be abandoned in favour of - the new ``request(method, url, ...)``. -* Refactored code to be even more decoupled, reusable, and extendable. -* License header added to ``.py`` files. -* Embiggened the documentation: Lots of Sphinx-friendly docstrings in the code - and docs in ``docs/`` and on https://urllib3.readthedocs.io/. -* Embettered all the things! -* Started writing this file. - - -0.4.1 (2011-07-17) ------------------- - -* Minor bug fixes, code cleanup. - - -0.4 (2011-03-01) ----------------- - -* Better unicode support. -* Added ``VerifiedHTTPSConnection``. -* Added ``NTLMConnectionPool`` in contrib. -* Minor improvements. - - -0.3.1 (2010-07-13) ------------------- - -* Added ``assert_host_name`` optional parameter. Now compatible with proxies. - - -0.3 (2009-12-10) ----------------- - -* Added HTTPS support. -* Minor bug fixes. -* Refactored, broken backwards compatibility with 0.2. -* API to be treated as stable from this version forward. - - -0.2 (2008-11-17) ----------------- - -* Added unit tests. -* Bug fixes. - - -0.1 (2008-11-16) ----------------- - -* First release. - - diff --git a/venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/RECORD b/venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/RECORD deleted file mode 100644 index 712b755..0000000 --- a/venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/RECORD +++ /dev/null @@ -1,84 +0,0 @@ -urllib3-1.26.6.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 -urllib3-1.26.6.dist-info/LICENSE.txt,sha256=w3vxhuJ8-dvpYZ5V7f486nswCRzrPaY8fay-Dm13kHs,1115 -urllib3-1.26.6.dist-info/METADATA,sha256=GTqag0OUj9vLryU3xGQO2LJGvkatmJYgTZxnWYT8fpc,44267 -urllib3-1.26.6.dist-info/RECORD,, -urllib3-1.26.6.dist-info/WHEEL,sha256=Z-nyYpwrcSqxfdux5Mbn_DQ525iP7J2DG3JgGvOYyTQ,110 -urllib3-1.26.6.dist-info/top_level.txt,sha256=EMiXL2sKrTcmrMxIHTqdc3ET54pQI2Y072LexFEemvo,8 -urllib3/__init__.py,sha256=j3yzHIbmW7CS-IKQJ9-PPQf_YKO8EOAey_rMW0UR7us,2763 -urllib3/__pycache__/__init__.cpython-38.pyc,, -urllib3/__pycache__/_collections.cpython-38.pyc,, -urllib3/__pycache__/_version.cpython-38.pyc,, -urllib3/__pycache__/connection.cpython-38.pyc,, -urllib3/__pycache__/connectionpool.cpython-38.pyc,, -urllib3/__pycache__/exceptions.cpython-38.pyc,, -urllib3/__pycache__/fields.cpython-38.pyc,, -urllib3/__pycache__/filepost.cpython-38.pyc,, -urllib3/__pycache__/poolmanager.cpython-38.pyc,, -urllib3/__pycache__/request.cpython-38.pyc,, -urllib3/__pycache__/response.cpython-38.pyc,, -urllib3/_collections.py,sha256=Rp1mVyBgc_UlAcp6M3at1skJBXR5J43NawRTvW2g_XY,10811 -urllib3/_version.py,sha256=6fJAIPnJkT0m9wzVjHrFcq5wYt65dStDpaRcjj5ugoo,63 -urllib3/connection.py,sha256=kAlubwsW33FUSUroPSVHMF_Zzv-uzX_BwUFMXX9Pt8c,18754 -urllib3/connectionpool.py,sha256=jXNmm4y3LJWYgteNeGcYJx8-0k7bzKRU__AVTXzaIak,37131 -urllib3/contrib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -urllib3/contrib/__pycache__/__init__.cpython-38.pyc,, -urllib3/contrib/__pycache__/_appengine_environ.cpython-38.pyc,, -urllib3/contrib/__pycache__/appengine.cpython-38.pyc,, -urllib3/contrib/__pycache__/ntlmpool.cpython-38.pyc,, -urllib3/contrib/__pycache__/pyopenssl.cpython-38.pyc,, -urllib3/contrib/__pycache__/securetransport.cpython-38.pyc,, -urllib3/contrib/__pycache__/socks.cpython-38.pyc,, -urllib3/contrib/_appengine_environ.py,sha256=bDbyOEhW2CKLJcQqAKAyrEHN-aklsyHFKq6vF8ZFsmk,957 -urllib3/contrib/_securetransport/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -urllib3/contrib/_securetransport/__pycache__/__init__.cpython-38.pyc,, -urllib3/contrib/_securetransport/__pycache__/bindings.cpython-38.pyc,, -urllib3/contrib/_securetransport/__pycache__/low_level.cpython-38.pyc,, -urllib3/contrib/_securetransport/bindings.py,sha256=E1_7ScsgOchfxneozbAueK7ziCwF35fna4DuDCYJ9_o,17637 -urllib3/contrib/_securetransport/low_level.py,sha256=lgIdsSycqfB0Xm5BiJzXGeIKT7ybCQMFPJAgkcwPa1s,13908 -urllib3/contrib/appengine.py,sha256=jz515jZYBDFTnhR4zqfeaCo6JdDgAQqYbqzHK9sDkfw,11010 -urllib3/contrib/ntlmpool.py,sha256=ej9gGvfAb2Gt00lafFp45SIoRz-QwrQ4WChm6gQmAlM,4538 -urllib3/contrib/pyopenssl.py,sha256=YIMyTiXiLPV_QfFw3PjZ31mGqJmM5EzxIjhSLxZ7VUM,16874 -urllib3/contrib/securetransport.py,sha256=izdx43gFoUGFSgxasZlOCL42FaM4vSsAVTmhO0EH1vM,34417 -urllib3/contrib/socks.py,sha256=aRi9eWXo9ZEb95XUxef4Z21CFlnnjbEiAo9HOseoMt4,7097 -urllib3/exceptions.py,sha256=0Mnno3KHTNfXRfY7638NufOPkUb6mXOm-Lqj-4x2w8A,8217 -urllib3/fields.py,sha256=kvLDCg_JmH1lLjUUEY_FLS8UhY7hBvDPuVETbY8mdrM,8579 -urllib3/filepost.py,sha256=5b_qqgRHVlL7uLtdAYBzBh-GHmU5AfJVt_2N0XS3PeY,2440 -urllib3/packages/__init__.py,sha256=h4BLhD4tLaBx1adaDtKXfupsgqY0wWLXb_f1_yVlV6A,108 -urllib3/packages/__pycache__/__init__.cpython-38.pyc,, -urllib3/packages/__pycache__/six.cpython-38.pyc,, -urllib3/packages/backports/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 -urllib3/packages/backports/__pycache__/__init__.cpython-38.pyc,, -urllib3/packages/backports/__pycache__/makefile.cpython-38.pyc,, -urllib3/packages/backports/makefile.py,sha256=nbzt3i0agPVP07jqqgjhaYjMmuAi_W5E0EywZivVO8E,1417 -urllib3/packages/six.py,sha256=1LVW7ljqRirFlfExjwl-v1B7vSAUNTmzGMs-qays2zg,34666 -urllib3/packages/ssl_match_hostname/__init__.py,sha256=ZVMwCkHx-py8ERsxxM3Il-MiREZktV-8iLBmCfRRHI4,927 -urllib3/packages/ssl_match_hostname/__pycache__/__init__.cpython-38.pyc,, -urllib3/packages/ssl_match_hostname/__pycache__/_implementation.cpython-38.pyc,, -urllib3/packages/ssl_match_hostname/_implementation.py,sha256=6dZ-q074g7XhsJ27MFCgkct8iVNZB3sMZvKhf-KUVy0,5679 -urllib3/poolmanager.py,sha256=whzlX6UTEgODMOCy0ZDMUONRBCz5wyIM8Z9opXAY-Lk,19763 -urllib3/request.py,sha256=ZFSIqX0C6WizixecChZ3_okyu7BEv0lZu1VT0s6h4SM,5985 -urllib3/response.py,sha256=hGhGBh7TkEkh_IQg5C1W_xuPNrgIKv5BUXPyE-q0LuE,28203 -urllib3/util/__init__.py,sha256=JEmSmmqqLyaw8P51gUImZh8Gwg9i1zSe-DoqAitn2nc,1155 -urllib3/util/__pycache__/__init__.cpython-38.pyc,, -urllib3/util/__pycache__/connection.cpython-38.pyc,, -urllib3/util/__pycache__/proxy.cpython-38.pyc,, -urllib3/util/__pycache__/queue.cpython-38.pyc,, -urllib3/util/__pycache__/request.cpython-38.pyc,, -urllib3/util/__pycache__/response.cpython-38.pyc,, -urllib3/util/__pycache__/retry.cpython-38.pyc,, -urllib3/util/__pycache__/ssl_.cpython-38.pyc,, -urllib3/util/__pycache__/ssltransport.cpython-38.pyc,, -urllib3/util/__pycache__/timeout.cpython-38.pyc,, -urllib3/util/__pycache__/url.cpython-38.pyc,, -urllib3/util/__pycache__/wait.cpython-38.pyc,, -urllib3/util/connection.py,sha256=Z9JufD13VNcga6RTW1wRIULbWdxsPE0WCUi5VTebALA,4908 -urllib3/util/proxy.py,sha256=FGipAEnvZteyldXNjce4DEB7YzwU-a5lep8y5S0qHQg,1604 -urllib3/util/queue.py,sha256=nRgX8_eX-_VkvxoX096QWoz8Ps0QHUAExILCY_7PncM,498 -urllib3/util/request.py,sha256=NnzaEKQ1Pauw5MFMV6HmgEMHITf0Aua9fQuzi2uZzGc,4123 -urllib3/util/response.py,sha256=GJpg3Egi9qaJXRwBh5wv-MNuRWan5BIu40oReoxWP28,3510 -urllib3/util/retry.py,sha256=tOWfZpLsuc7Vbk5nWpMwkHdMoXCp90IAvH4xtjSDRqQ,21391 -urllib3/util/ssl_.py,sha256=c0sYiSC6272r6uPkxQpo5rYPP9QC1eR6oI7004gYqZo,17165 -urllib3/util/ssltransport.py,sha256=3bLBqYPryT9UMGbx5iRgMgb2sj7VEKp5pmRD1g8d6VI,6907 -urllib3/util/timeout.py,sha256=QSbBUNOB9yh6AnDn61SrLQ0hg5oz0I9-uXEG91AJuIg,10003 -urllib3/util/url.py,sha256=au9jkUMnVr9Qp_9kg4HfZx9q9ur6yXQ4u5M17In-UKY,14030 -urllib3/util/wait.py,sha256=3MUKRSAUJDB2tgco7qRUskW0zXGAWYvRRE4Q1_6xlLs,5404 diff --git a/venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/WHEEL b/venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/WHEEL deleted file mode 100644 index 01b8fc7..0000000 --- a/venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/WHEEL +++ /dev/null @@ -1,6 +0,0 @@ -Wheel-Version: 1.0 -Generator: bdist_wheel (0.36.2) -Root-Is-Purelib: true -Tag: py2-none-any -Tag: py3-none-any - diff --git a/venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/top_level.txt b/venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/top_level.txt deleted file mode 100644 index a42590b..0000000 --- a/venv/lib/python3.8/site-packages/urllib3-1.26.6.dist-info/top_level.txt +++ /dev/null @@ -1 +0,0 @@ -urllib3 diff --git a/venv/lib/python3.8/site-packages/urllib3/__init__.py b/venv/lib/python3.8/site-packages/urllib3/__init__.py deleted file mode 100644 index fe86b59..0000000 --- a/venv/lib/python3.8/site-packages/urllib3/__init__.py +++ /dev/null @@ -1,85 +0,0 @@ -""" -Python HTTP library with thread-safe connection pooling, file post support, user friendly, and more -""" -from __future__ import absolute_import - -# Set default logging handler to avoid "No handler found" warnings. -import logging -import warnings -from logging import NullHandler - -from . import exceptions -from ._version import __version__ -from .connectionpool import HTTPConnectionPool, HTTPSConnectionPool, connection_from_url -from .filepost import encode_multipart_formdata -from .poolmanager import PoolManager, ProxyManager, proxy_from_url -from .response import HTTPResponse -from .util.request import make_headers -from .util.retry import Retry -from .util.timeout import Timeout -from .util.url import get_host - -__author__ = "Andrey Petrov (andrey.petrov@shazow.net)" -__license__ = "MIT" -__version__ = __version__ - -__all__ = ( - "HTTPConnectionPool", - "HTTPSConnectionPool", - "PoolManager", - "ProxyManager", - "HTTPResponse", - "Retry", - "Timeout", - "add_stderr_logger", - "connection_from_url", - "disable_warnings", - "encode_multipart_formdata", - "get_host", - "make_headers", - "proxy_from_url", -) - -logging.getLogger(__name__).addHandler(NullHandler()) - - -def add_stderr_logger(level=logging.DEBUG): - """ - Helper for quickly adding a StreamHandler to the logger. Useful for - debugging. - - Returns the handler after adding it. - """ - # This method needs to be in this __init__.py to get the __name__ correct - # even if urllib3 is vendored within another package. - logger = logging.getLogger(__name__) - handler = logging.StreamHandler() - handler.setFormatter(logging.Formatter("%(asctime)s %(levelname)s %(message)s")) - logger.addHandler(handler) - logger.setLevel(level) - logger.debug("Added a stderr logging handler to logger: %s", __name__) - return handler - - -# ... Clean up. -del NullHandler - - -# All warning filters *must* be appended unless you're really certain that they -# shouldn't be: otherwise, it's very hard for users to use most Python -# mechanisms to silence them. -# SecurityWarning's always go off by default. -warnings.simplefilter("always", exceptions.SecurityWarning, append=True) -# SubjectAltNameWarning's should go off once per host -warnings.simplefilter("default", exceptions.SubjectAltNameWarning, append=True) -# InsecurePlatformWarning's don't vary between requests, so we keep it default. -warnings.simplefilter("default", exceptions.InsecurePlatformWarning, append=True) -# SNIMissingWarnings should go off only once. -warnings.simplefilter("default", exceptions.SNIMissingWarning, append=True) - - -def disable_warnings(category=exceptions.HTTPWarning): - """ - Helper for quickly disabling all urllib3 warnings. - """ - warnings.simplefilter("ignore", category) diff --git a/venv/lib/python3.8/site-packages/urllib3/_collections.py b/venv/lib/python3.8/site-packages/urllib3/_collections.py deleted file mode 100644 index da9857e..0000000 --- a/venv/lib/python3.8/site-packages/urllib3/_collections.py +++ /dev/null @@ -1,337 +0,0 @@ -from __future__ import absolute_import - -try: - from collections.abc import Mapping, MutableMapping -except ImportError: - from collections import Mapping, MutableMapping -try: - from threading import RLock -except ImportError: # Platform-specific: No threads available - - class RLock: - def __enter__(self): - pass - - def __exit__(self, exc_type, exc_value, traceback): - pass - - -from collections import OrderedDict - -from .exceptions import InvalidHeader -from .packages import six -from .packages.six import iterkeys, itervalues - -__all__ = ["RecentlyUsedContainer", "HTTPHeaderDict"] - - -_Null = object() - - -class RecentlyUsedContainer(MutableMapping): - """ - Provides a thread-safe dict-like container which maintains up to - ``maxsize`` keys while throwing away the least-recently-used keys beyond - ``maxsize``. - - :param maxsize: - Maximum number of recent elements to retain. - - :param dispose_func: - Every time an item is evicted from the container, - ``dispose_func(value)`` is called. Callback which will get called - """ - - ContainerCls = OrderedDict - - def __init__(self, maxsize=10, dispose_func=None): - self._maxsize = maxsize - self.dispose_func = dispose_func - - self._container = self.ContainerCls() - self.lock = RLock() - - def __getitem__(self, key): - # Re-insert the item, moving it to the end of the eviction line. - with self.lock: - item = self._container.pop(key) - self._container[key] = item - return item - - def __setitem__(self, key, value): - evicted_value = _Null - with self.lock: - # Possibly evict the existing value of 'key' - evicted_value = self._container.get(key, _Null) - self._container[key] = value - - # If we didn't evict an existing value, we might have to evict the - # least recently used item from the beginning of the container. - if len(self._container) > self._maxsize: - _key, evicted_value = self._container.popitem(last=False) - - if self.dispose_func and evicted_value is not _Null: - self.dispose_func(evicted_value) - - def __delitem__(self, key): - with self.lock: - value = self._container.pop(key) - - if self.dispose_func: - self.dispose_func(value) - - def __len__(self): - with self.lock: - return len(self._container) - - def __iter__(self): - raise NotImplementedError( - "Iteration over this class is unlikely to be threadsafe." - ) - - def clear(self): - with self.lock: - # Copy pointers to all values, then wipe the mapping - values = list(itervalues(self._container)) - self._container.clear() - - if self.dispose_func: - for value in values: - self.dispose_func(value) - - def keys(self): - with self.lock: - return list(iterkeys(self._container)) - - -class HTTPHeaderDict(MutableMapping): - """ - :param headers: - An iterable of field-value pairs. Must not contain multiple field names - when compared case-insensitively. - - :param kwargs: - Additional field-value pairs to pass in to ``dict.update``. - - A ``dict`` like container for storing HTTP Headers. - - Field names are stored and compared case-insensitively in compliance with - RFC 7230. Iteration provides the first case-sensitive key seen for each - case-insensitive pair. - - Using ``__setitem__`` syntax overwrites fields that compare equal - case-insensitively in order to maintain ``dict``'s api. For fields that - compare equal, instead create a new ``HTTPHeaderDict`` and use ``.add`` - in a loop. - - If multiple fields that are equal case-insensitively are passed to the - constructor or ``.update``, the behavior is undefined and some will be - lost. - - >>> headers = HTTPHeaderDict() - >>> headers.add('Set-Cookie', 'foo=bar') - >>> headers.add('set-cookie', 'baz=quxx') - >>> headers['content-length'] = '7' - >>> headers['SET-cookie'] - 'foo=bar, baz=quxx' - >>> headers['Content-Length'] - '7' - """ - - def __init__(self, headers=None, **kwargs): - super(HTTPHeaderDict, self).__init__() - self._container = OrderedDict() - if headers is not None: - if isinstance(headers, HTTPHeaderDict): - self._copy_from(headers) - else: - self.extend(headers) - if kwargs: - self.extend(kwargs) - - def __setitem__(self, key, val): - self._container[key.lower()] = [key, val] - return self._container[key.lower()] - - def __getitem__(self, key): - val = self._container[key.lower()] - return ", ".join(val[1:]) - - def __delitem__(self, key): - del self._container[key.lower()] - - def __contains__(self, key): - return key.lower() in self._container - - def __eq__(self, other): - if not isinstance(other, Mapping) and not hasattr(other, "keys"): - return False - if not isinstance(other, type(self)): - other = type(self)(other) - return dict((k.lower(), v) for k, v in self.itermerged()) == dict( - (k.lower(), v) for k, v in other.itermerged() - ) - - def __ne__(self, other): - return not self.__eq__(other) - - if six.PY2: # Python 2 - iterkeys = MutableMapping.iterkeys - itervalues = MutableMapping.itervalues - - __marker = object() - - def __len__(self): - return len(self._container) - - def __iter__(self): - # Only provide the originally cased names - for vals in self._container.values(): - yield vals[0] - - def pop(self, key, default=__marker): - """D.pop(k[,d]) -> v, remove specified key and return the corresponding value. - If key is not found, d is returned if given, otherwise KeyError is raised. - """ - # Using the MutableMapping function directly fails due to the private marker. - # Using ordinary dict.pop would expose the internal structures. - # So let's reinvent the wheel. - try: - value = self[key] - except KeyError: - if default is self.__marker: - raise - return default - else: - del self[key] - return value - - def discard(self, key): - try: - del self[key] - except KeyError: - pass - - def add(self, key, val): - """Adds a (name, value) pair, doesn't overwrite the value if it already - exists. - - >>> headers = HTTPHeaderDict(foo='bar') - >>> headers.add('Foo', 'baz') - >>> headers['foo'] - 'bar, baz' - """ - key_lower = key.lower() - new_vals = [key, val] - # Keep the common case aka no item present as fast as possible - vals = self._container.setdefault(key_lower, new_vals) - if new_vals is not vals: - vals.append(val) - - def extend(self, *args, **kwargs): - """Generic import function for any type of header-like object. - Adapted version of MutableMapping.update in order to insert items - with self.add instead of self.__setitem__ - """ - if len(args) > 1: - raise TypeError( - "extend() takes at most 1 positional " - "arguments ({0} given)".format(len(args)) - ) - other = args[0] if len(args) >= 1 else () - - if isinstance(other, HTTPHeaderDict): - for key, val in other.iteritems(): - self.add(key, val) - elif isinstance(other, Mapping): - for key in other: - self.add(key, other[key]) - elif hasattr(other, "keys"): - for key in other.keys(): - self.add(key, other[key]) - else: - for key, value in other: - self.add(key, value) - - for key, value in kwargs.items(): - self.add(key, value) - - def getlist(self, key, default=__marker): - """Returns a list of all the values for the named field. Returns an - empty list if the key doesn't exist.""" - try: - vals = self._container[key.lower()] - except KeyError: - if default is self.__marker: - return [] - return default - else: - return vals[1:] - - # Backwards compatibility for httplib - getheaders = getlist - getallmatchingheaders = getlist - iget = getlist - - # Backwards compatibility for http.cookiejar - get_all = getlist - - def __repr__(self): - return "%s(%s)" % (type(self).__name__, dict(self.itermerged())) - - def _copy_from(self, other): - for key in other: - val = other.getlist(key) - if isinstance(val, list): - # Don't need to convert tuples - val = list(val) - self._container[key.lower()] = [key] + val - - def copy(self): - clone = type(self)() - clone._copy_from(self) - return clone - - def iteritems(self): - """Iterate over all header lines, including duplicate ones.""" - for key in self: - vals = self._container[key.lower()] - for val in vals[1:]: - yield vals[0], val - - def itermerged(self): - """Iterate over all headers, merging duplicate ones together.""" - for key in self: - val = self._container[key.lower()] - yield val[0], ", ".join(val[1:]) - - def items(self): - return list(self.iteritems()) - - @classmethod - def from_httplib(cls, message): # Python 2 - """Read headers from a Python 2 httplib message object.""" - # python2.7 does not expose a proper API for exporting multiheaders - # efficiently. This function re-reads raw lines from the message - # object and extracts the multiheaders properly. - obs_fold_continued_leaders = (" ", "\t") - headers = [] - - for line in message.headers: - if line.startswith(obs_fold_continued_leaders): - if not headers: - # We received a header line that starts with OWS as described - # in RFC-7230 S3.2.4. This indicates a multiline header, but - # there exists no previous header to which we can attach it. - raise InvalidHeader( - "Header continuation with no previous header: %s" % line - ) - else: - key, value = headers[-1] - headers[-1] = (key, value + " " + line.strip()) - continue - - key, value = line.split(":", 1) - headers.append((key, value.strip())) - - return cls(headers) diff --git a/venv/lib/python3.8/site-packages/urllib3/_version.py b/venv/lib/python3.8/site-packages/urllib3/_version.py deleted file mode 100644 index e8ebee9..0000000 --- a/venv/lib/python3.8/site-packages/urllib3/_version.py +++ /dev/null @@ -1,2 +0,0 @@ -# This file is protected via CODEOWNERS -__version__ = "1.26.6" diff --git a/venv/lib/python3.8/site-packages/urllib3/connection.py b/venv/lib/python3.8/site-packages/urllib3/connection.py deleted file mode 100644 index 4c99665..0000000 --- a/venv/lib/python3.8/site-packages/urllib3/connection.py +++ /dev/null @@ -1,539 +0,0 @@ -from __future__ import absolute_import - -import datetime -import logging -import os -import re -import socket -import warnings -from socket import error as SocketError -from socket import timeout as SocketTimeout - -from .packages import six -from .packages.six.moves.http_client import HTTPConnection as _HTTPConnection -from .packages.six.moves.http_client import HTTPException # noqa: F401 -from .util.proxy import create_proxy_ssl_context - -try: # Compiled with SSL? - import ssl - - BaseSSLError = ssl.SSLError -except (ImportError, AttributeError): # Platform-specific: No SSL. - ssl = None - - class BaseSSLError(BaseException): - pass - - -try: - # Python 3: not a no-op, we're adding this to the namespace so it can be imported. - ConnectionError = ConnectionError -except NameError: - # Python 2 - class ConnectionError(Exception): - pass - - -try: # Python 3: - # Not a no-op, we're adding this to the namespace so it can be imported. - BrokenPipeError = BrokenPipeError -except NameError: # Python 2: - - class BrokenPipeError(Exception): - pass - - -from ._collections import HTTPHeaderDict # noqa (historical, removed in v2) -from ._version import __version__ -from .exceptions import ( - ConnectTimeoutError, - NewConnectionError, - SubjectAltNameWarning, - SystemTimeWarning, -) -from .packages.ssl_match_hostname import CertificateError, match_hostname -from .util import SKIP_HEADER, SKIPPABLE_HEADERS, connection -from .util.ssl_ import ( - assert_fingerprint, - create_urllib3_context, - resolve_cert_reqs, - resolve_ssl_version, - ssl_wrap_socket, -) - -log = logging.getLogger(__name__) - -port_by_scheme = {"http": 80, "https": 443} - -# When it comes time to update this value as a part of regular maintenance -# (ie test_recent_date is failing) update it to ~6 months before the current date. -RECENT_DATE = datetime.date(2020, 7, 1) - -_CONTAINS_CONTROL_CHAR_RE = re.compile(r"[^-!#$%&'*+.^_`|~0-9a-zA-Z]") - - -class HTTPConnection(_HTTPConnection, object): - """ - Based on :class:`http.client.HTTPConnection` but provides an extra constructor - backwards-compatibility layer between older and newer Pythons. - - Additional keyword parameters are used to configure attributes of the connection. - Accepted parameters include: - - - ``strict``: See the documentation on :class:`urllib3.connectionpool.HTTPConnectionPool` - - ``source_address``: Set the source address for the current connection. - - ``socket_options``: Set specific options on the underlying socket. If not specified, then - defaults are loaded from ``HTTPConnection.default_socket_options`` which includes disabling - Nagle's algorithm (sets TCP_NODELAY to 1) unless the connection is behind a proxy. - - For example, if you wish to enable TCP Keep Alive in addition to the defaults, - you might pass: - - .. code-block:: python - - HTTPConnection.default_socket_options + [ - (socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1), - ] - - Or you may want to disable the defaults by passing an empty list (e.g., ``[]``). - """ - - default_port = port_by_scheme["http"] - - #: Disable Nagle's algorithm by default. - #: ``[(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)]`` - default_socket_options = [(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)] - - #: Whether this connection verifies the host's certificate. - is_verified = False - - def __init__(self, *args, **kw): - if not six.PY2: - kw.pop("strict", None) - - # Pre-set source_address. - self.source_address = kw.get("source_address") - - #: The socket options provided by the user. If no options are - #: provided, we use the default options. - self.socket_options = kw.pop("socket_options", self.default_socket_options) - - # Proxy options provided by the user. - self.proxy = kw.pop("proxy", None) - self.proxy_config = kw.pop("proxy_config", None) - - _HTTPConnection.__init__(self, *args, **kw) - - @property - def host(self): - """ - Getter method to remove any trailing dots that indicate the hostname is an FQDN. - - In general, SSL certificates don't include the trailing dot indicating a - fully-qualified domain name, and thus, they don't validate properly when - checked against a domain name that includes the dot. In addition, some - servers may not expect to receive the trailing dot when provided. - - However, the hostname with trailing dot is critical to DNS resolution; doing a - lookup with the trailing dot will properly only resolve the appropriate FQDN, - whereas a lookup without a trailing dot will search the system's search domain - list. Thus, it's important to keep the original host around for use only in - those cases where it's appropriate (i.e., when doing DNS lookup to establish the - actual TCP connection across which we're going to send HTTP requests). - """ - return self._dns_host.rstrip(".") - - @host.setter - def host(self, value): - """ - Setter for the `host` property. - - We assume that only urllib3 uses the _dns_host attribute; httplib itself - only uses `host`, and it seems reasonable that other libraries follow suit. - """ - self._dns_host = value - - def _new_conn(self): - """Establish a socket connection and set nodelay settings on it. - - :return: New socket connection. - """ - extra_kw = {} - if self.source_address: - extra_kw["source_address"] = self.source_address - - if self.socket_options: - extra_kw["socket_options"] = self.socket_options - - try: - conn = connection.create_connection( - (self._dns_host, self.port), self.timeout, **extra_kw - ) - - except SocketTimeout: - raise ConnectTimeoutError( - self, - "Connection to %s timed out. (connect timeout=%s)" - % (self.host, self.timeout), - ) - - except SocketError as e: - raise NewConnectionError( - self, "Failed to establish a new connection: %s" % e - ) - - return conn - - def _is_using_tunnel(self): - # Google App Engine's httplib does not define _tunnel_host - return getattr(self, "_tunnel_host", None) - - def _prepare_conn(self, conn): - self.sock = conn - if self._is_using_tunnel(): - # TODO: Fix tunnel so it doesn't depend on self.sock state. - self._tunnel() - # Mark this connection as not reusable - self.auto_open = 0 - - def connect(self): - conn = self._new_conn() - self._prepare_conn(conn) - - def putrequest(self, method, url, *args, **kwargs): - """ """ - # Empty docstring because the indentation of CPython's implementation - # is broken but we don't want this method in our documentation. - match = _CONTAINS_CONTROL_CHAR_RE.search(method) - if match: - raise ValueError( - "Method cannot contain non-token characters %r (found at least %r)" - % (method, match.group()) - ) - - return _HTTPConnection.putrequest(self, method, url, *args, **kwargs) - - def putheader(self, header, *values): - """ """ - if not any(isinstance(v, str) and v == SKIP_HEADER for v in values): - _HTTPConnection.putheader(self, header, *values) - elif six.ensure_str(header.lower()) not in SKIPPABLE_HEADERS: - raise ValueError( - "urllib3.util.SKIP_HEADER only supports '%s'" - % ("', '".join(map(str.title, sorted(SKIPPABLE_HEADERS))),) - ) - - def request(self, method, url, body=None, headers=None): - if headers is None: - headers = {} - else: - # Avoid modifying the headers passed into .request() - headers = headers.copy() - if "user-agent" not in (six.ensure_str(k.lower()) for k in headers): - headers["User-Agent"] = _get_default_user_agent() - super(HTTPConnection, self).request(method, url, body=body, headers=headers) - - def request_chunked(self, method, url, body=None, headers=None): - """ - Alternative to the common request method, which sends the - body with chunked encoding and not as one block - """ - headers = headers or {} - header_keys = set([six.ensure_str(k.lower()) for k in headers]) - skip_accept_encoding = "accept-encoding" in header_keys - skip_host = "host" in header_keys - self.putrequest( - method, url, skip_accept_encoding=skip_accept_encoding, skip_host=skip_host - ) - if "user-agent" not in header_keys: - self.putheader("User-Agent", _get_default_user_agent()) - for header, value in headers.items(): - self.putheader(header, value) - if "transfer-encoding" not in header_keys: - self.putheader("Transfer-Encoding", "chunked") - self.endheaders() - - if body is not None: - stringish_types = six.string_types + (bytes,) - if isinstance(body, stringish_types): - body = (body,) - for chunk in body: - if not chunk: - continue - if not isinstance(chunk, bytes): - chunk = chunk.encode("utf8") - len_str = hex(len(chunk))[2:] - to_send = bytearray(len_str.encode()) - to_send += b"\r\n" - to_send += chunk - to_send += b"\r\n" - self.send(to_send) - - # After the if clause, to always have a closed body - self.send(b"0\r\n\r\n") - - -class HTTPSConnection(HTTPConnection): - """ - Many of the parameters to this constructor are passed to the underlying SSL - socket by means of :py:func:`urllib3.util.ssl_wrap_socket`. - """ - - default_port = port_by_scheme["https"] - - cert_reqs = None - ca_certs = None - ca_cert_dir = None - ca_cert_data = None - ssl_version = None - assert_fingerprint = None - tls_in_tls_required = False - - def __init__( - self, - host, - port=None, - key_file=None, - cert_file=None, - key_password=None, - strict=None, - timeout=socket._GLOBAL_DEFAULT_TIMEOUT, - ssl_context=None, - server_hostname=None, - **kw - ): - - HTTPConnection.__init__(self, host, port, strict=strict, timeout=timeout, **kw) - - self.key_file = key_file - self.cert_file = cert_file - self.key_password = key_password - self.ssl_context = ssl_context - self.server_hostname = server_hostname - - # Required property for Google AppEngine 1.9.0 which otherwise causes - # HTTPS requests to go out as HTTP. (See Issue #356) - self._protocol = "https" - - def set_cert( - self, - key_file=None, - cert_file=None, - cert_reqs=None, - key_password=None, - ca_certs=None, - assert_hostname=None, - assert_fingerprint=None, - ca_cert_dir=None, - ca_cert_data=None, - ): - """ - This method should only be called once, before the connection is used. - """ - # If cert_reqs is not provided we'll assume CERT_REQUIRED unless we also - # have an SSLContext object in which case we'll use its verify_mode. - if cert_reqs is None: - if self.ssl_context is not None: - cert_reqs = self.ssl_context.verify_mode - else: - cert_reqs = resolve_cert_reqs(None) - - self.key_file = key_file - self.cert_file = cert_file - self.cert_reqs = cert_reqs - self.key_password = key_password - self.assert_hostname = assert_hostname - self.assert_fingerprint = assert_fingerprint - self.ca_certs = ca_certs and os.path.expanduser(ca_certs) - self.ca_cert_dir = ca_cert_dir and os.path.expanduser(ca_cert_dir) - self.ca_cert_data = ca_cert_data - - def connect(self): - # Add certificate verification - conn = self._new_conn() - hostname = self.host - tls_in_tls = False - - if self._is_using_tunnel(): - if self.tls_in_tls_required: - conn = self._connect_tls_proxy(hostname, conn) - tls_in_tls = True - - self.sock = conn - - # Calls self._set_hostport(), so self.host is - # self._tunnel_host below. - self._tunnel() - # Mark this connection as not reusable - self.auto_open = 0 - - # Override the host with the one we're requesting data from. - hostname = self._tunnel_host - - server_hostname = hostname - if self.server_hostname is not None: - server_hostname = self.server_hostname - - is_time_off = datetime.date.today() < RECENT_DATE - if is_time_off: - warnings.warn( - ( - "System time is way off (before {0}). This will probably " - "lead to SSL verification errors" - ).format(RECENT_DATE), - SystemTimeWarning, - ) - - # Wrap socket using verification with the root certs in - # trusted_root_certs - default_ssl_context = False - if self.ssl_context is None: - default_ssl_context = True - self.ssl_context = create_urllib3_context( - ssl_version=resolve_ssl_version(self.ssl_version), - cert_reqs=resolve_cert_reqs(self.cert_reqs), - ) - - context = self.ssl_context - context.verify_mode = resolve_cert_reqs(self.cert_reqs) - - # Try to load OS default certs if none are given. - # Works well on Windows (requires Python3.4+) - if ( - not self.ca_certs - and not self.ca_cert_dir - and not self.ca_cert_data - and default_ssl_context - and hasattr(context, "load_default_certs") - ): - context.load_default_certs() - - self.sock = ssl_wrap_socket( - sock=conn, - keyfile=self.key_file, - certfile=self.cert_file, - key_password=self.key_password, - ca_certs=self.ca_certs, - ca_cert_dir=self.ca_cert_dir, - ca_cert_data=self.ca_cert_data, - server_hostname=server_hostname, - ssl_context=context, - tls_in_tls=tls_in_tls, - ) - - # If we're using all defaults and the connection - # is TLSv1 or TLSv1.1 we throw a DeprecationWarning - # for the host. - if ( - default_ssl_context - and self.ssl_version is None - and hasattr(self.sock, "version") - and self.sock.version() in {"TLSv1", "TLSv1.1"} - ): - warnings.warn( - "Negotiating TLSv1/TLSv1.1 by default is deprecated " - "and will be disabled in urllib3 v2.0.0. Connecting to " - "'%s' with '%s' can be enabled by explicitly opting-in " - "with 'ssl_version'" % (self.host, self.sock.version()), - DeprecationWarning, - ) - - if self.assert_fingerprint: - assert_fingerprint( - self.sock.getpeercert(binary_form=True), self.assert_fingerprint - ) - elif ( - context.verify_mode != ssl.CERT_NONE - and not getattr(context, "check_hostname", False) - and self.assert_hostname is not False - ): - # While urllib3 attempts to always turn off hostname matching from - # the TLS library, this cannot always be done. So we check whether - # the TLS Library still thinks it's matching hostnames. - cert = self.sock.getpeercert() - if not cert.get("subjectAltName", ()): - warnings.warn( - ( - "Certificate for {0} has no `subjectAltName`, falling back to check for a " - "`commonName` for now. This feature is being removed by major browsers and " - "deprecated by RFC 2818. (See https://github.com/urllib3/urllib3/issues/497 " - "for details.)".format(hostname) - ), - SubjectAltNameWarning, - ) - _match_hostname(cert, self.assert_hostname or server_hostname) - - self.is_verified = ( - context.verify_mode == ssl.CERT_REQUIRED - or self.assert_fingerprint is not None - ) - - def _connect_tls_proxy(self, hostname, conn): - """ - Establish a TLS connection to the proxy using the provided SSL context. - """ - proxy_config = self.proxy_config - ssl_context = proxy_config.ssl_context - if ssl_context: - # If the user provided a proxy context, we assume CA and client - # certificates have already been set - return ssl_wrap_socket( - sock=conn, - server_hostname=hostname, - ssl_context=ssl_context, - ) - - ssl_context = create_proxy_ssl_context( - self.ssl_version, - self.cert_reqs, - self.ca_certs, - self.ca_cert_dir, - self.ca_cert_data, - ) - # By default urllib3's SSLContext disables `check_hostname` and uses - # a custom check. For proxies we're good with relying on the default - # verification. - ssl_context.check_hostname = True - - # If no cert was provided, use only the default options for server - # certificate validation - return ssl_wrap_socket( - sock=conn, - ca_certs=self.ca_certs, - ca_cert_dir=self.ca_cert_dir, - ca_cert_data=self.ca_cert_data, - server_hostname=hostname, - ssl_context=ssl_context, - ) - - -def _match_hostname(cert, asserted_hostname): - try: - match_hostname(cert, asserted_hostname) - except CertificateError as e: - log.warning( - "Certificate did not match expected hostname: %s. Certificate: %s", - asserted_hostname, - cert, - ) - # Add cert to exception and reraise so client code can inspect - # the cert when catching the exception, if they want to - e._peer_cert = cert - raise - - -def _get_default_user_agent(): - return "python-urllib3/%s" % __version__ - - -class DummyConnection(object): - """Used to detect a failed ConnectionCls import.""" - - pass - - -if not ssl: - HTTPSConnection = DummyConnection # noqa: F811 - - -VerifiedHTTPSConnection = HTTPSConnection diff --git a/venv/lib/python3.8/site-packages/urllib3/connectionpool.py b/venv/lib/python3.8/site-packages/urllib3/connectionpool.py deleted file mode 100644 index 459bbe0..0000000 --- a/venv/lib/python3.8/site-packages/urllib3/connectionpool.py +++ /dev/null @@ -1,1067 +0,0 @@ -from __future__ import absolute_import - -import errno -import logging -import socket -import sys -import warnings -from socket import error as SocketError -from socket import timeout as SocketTimeout - -from .connection import ( - BaseSSLError, - BrokenPipeError, - DummyConnection, - HTTPConnection, - HTTPException, - HTTPSConnection, - VerifiedHTTPSConnection, - port_by_scheme, -) -from .exceptions import ( - ClosedPoolError, - EmptyPoolError, - HeaderParsingError, - HostChangedError, - InsecureRequestWarning, - LocationValueError, - MaxRetryError, - NewConnectionError, - ProtocolError, - ProxyError, - ReadTimeoutError, - SSLError, - TimeoutError, -) -from .packages import six -from .packages.six.moves import queue -from .packages.ssl_match_hostname import CertificateError -from .request import RequestMethods -from .response import HTTPResponse -from .util.connection import is_connection_dropped -from .util.proxy import connection_requires_http_tunnel -from .util.queue import LifoQueue -from .util.request import set_file_position -from .util.response import assert_header_parsing -from .util.retry import Retry -from .util.timeout import Timeout -from .util.url import Url, _encode_target -from .util.url import _normalize_host as normalize_host -from .util.url import get_host, parse_url - -xrange = six.moves.xrange - -log = logging.getLogger(__name__) - -_Default = object() - - -# Pool objects -class ConnectionPool(object): - """ - Base class for all connection pools, such as - :class:`.HTTPConnectionPool` and :class:`.HTTPSConnectionPool`. - - .. note:: - ConnectionPool.urlopen() does not normalize or percent-encode target URIs - which is useful if your target server doesn't support percent-encoded - target URIs. - """ - - scheme = None - QueueCls = LifoQueue - - def __init__(self, host, port=None): - if not host: - raise LocationValueError("No host specified.") - - self.host = _normalize_host(host, scheme=self.scheme) - self._proxy_host = host.lower() - self.port = port - - def __str__(self): - return "%s(host=%r, port=%r)" % (type(self).__name__, self.host, self.port) - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_val, exc_tb): - self.close() - # Return False to re-raise any potential exceptions - return False - - def close(self): - """ - Close all pooled connections and disable the pool. - """ - pass - - -# This is taken from http://hg.python.org/cpython/file/7aaba721ebc0/Lib/socket.py#l252 -_blocking_errnos = {errno.EAGAIN, errno.EWOULDBLOCK} - - -class HTTPConnectionPool(ConnectionPool, RequestMethods): - """ - Thread-safe connection pool for one host. - - :param host: - Host used for this HTTP Connection (e.g. "localhost"), passed into - :class:`http.client.HTTPConnection`. - - :param port: - Port used for this HTTP Connection (None is equivalent to 80), passed - into :class:`http.client.HTTPConnection`. - - :param strict: - Causes BadStatusLine to be raised if the status line can't be parsed - as a valid HTTP/1.0 or 1.1 status line, passed into - :class:`http.client.HTTPConnection`. - - .. note:: - Only works in Python 2. This parameter is ignored in Python 3. - - :param timeout: - Socket timeout in seconds for each individual connection. This can - be a float or integer, which sets the timeout for the HTTP request, - or an instance of :class:`urllib3.util.Timeout` which gives you more - fine-grained control over request timeouts. After the constructor has - been parsed, this is always a `urllib3.util.Timeout` object. - - :param maxsize: - Number of connections to save that can be reused. More than 1 is useful - in multithreaded situations. If ``block`` is set to False, more - connections will be created but they will not be saved once they've - been used. - - :param block: - If set to True, no more than ``maxsize`` connections will be used at - a time. When no free connections are available, the call will block - until a connection has been released. This is a useful side effect for - particular multithreaded situations where one does not want to use more - than maxsize connections per host to prevent flooding. - - :param headers: - Headers to include with all requests, unless other headers are given - explicitly. - - :param retries: - Retry configuration to use by default with requests in this pool. - - :param _proxy: - Parsed proxy URL, should not be used directly, instead, see - :class:`urllib3.ProxyManager` - - :param _proxy_headers: - A dictionary with proxy headers, should not be used directly, - instead, see :class:`urllib3.ProxyManager` - - :param \\**conn_kw: - Additional parameters are used to create fresh :class:`urllib3.connection.HTTPConnection`, - :class:`urllib3.connection.HTTPSConnection` instances. - """ - - scheme = "http" - ConnectionCls = HTTPConnection - ResponseCls = HTTPResponse - - def __init__( - self, - host, - port=None, - strict=False, - timeout=Timeout.DEFAULT_TIMEOUT, - maxsize=1, - block=False, - headers=None, - retries=None, - _proxy=None, - _proxy_headers=None, - _proxy_config=None, - **conn_kw - ): - ConnectionPool.__init__(self, host, port) - RequestMethods.__init__(self, headers) - - self.strict = strict - - if not isinstance(timeout, Timeout): - timeout = Timeout.from_float(timeout) - - if retries is None: - retries = Retry.DEFAULT - - self.timeout = timeout - self.retries = retries - - self.pool = self.QueueCls(maxsize) - self.block = block - - self.proxy = _proxy - self.proxy_headers = _proxy_headers or {} - self.proxy_config = _proxy_config - - # Fill the queue up so that doing get() on it will block properly - for _ in xrange(maxsize): - self.pool.put(None) - - # These are mostly for testing and debugging purposes. - self.num_connections = 0 - self.num_requests = 0 - self.conn_kw = conn_kw - - if self.proxy: - # Enable Nagle's algorithm for proxies, to avoid packet fragmentation. - # We cannot know if the user has added default socket options, so we cannot replace the - # list. - self.conn_kw.setdefault("socket_options", []) - - self.conn_kw["proxy"] = self.proxy - self.conn_kw["proxy_config"] = self.proxy_config - - def _new_conn(self): - """ - Return a fresh :class:`HTTPConnection`. - """ - self.num_connections += 1 - log.debug( - "Starting new HTTP connection (%d): %s:%s", - self.num_connections, - self.host, - self.port or "80", - ) - - conn = self.ConnectionCls( - host=self.host, - port=self.port, - timeout=self.timeout.connect_timeout, - strict=self.strict, - **self.conn_kw - ) - return conn - - def _get_conn(self, timeout=None): - """ - Get a connection. Will return a pooled connection if one is available. - - If no connections are available and :prop:`.block` is ``False``, then a - fresh connection is returned. - - :param timeout: - Seconds to wait before giving up and raising - :class:`urllib3.exceptions.EmptyPoolError` if the pool is empty and - :prop:`.block` is ``True``. - """ - conn = None - try: - conn = self.pool.get(block=self.block, timeout=timeout) - - except AttributeError: # self.pool is None - raise ClosedPoolError(self, "Pool is closed.") - - except queue.Empty: - if self.block: - raise EmptyPoolError( - self, - "Pool reached maximum size and no more connections are allowed.", - ) - pass # Oh well, we'll create a new connection then - - # If this is a persistent connection, check if it got disconnected - if conn and is_connection_dropped(conn): - log.debug("Resetting dropped connection: %s", self.host) - conn.close() - if getattr(conn, "auto_open", 1) == 0: - # This is a proxied connection that has been mutated by - # http.client._tunnel() and cannot be reused (since it would - # attempt to bypass the proxy) - conn = None - - return conn or self._new_conn() - - def _put_conn(self, conn): - """ - Put a connection back into the pool. - - :param conn: - Connection object for the current host and port as returned by - :meth:`._new_conn` or :meth:`._get_conn`. - - If the pool is already full, the connection is closed and discarded - because we exceeded maxsize. If connections are discarded frequently, - then maxsize should be increased. - - If the pool is closed, then the connection will be closed and discarded. - """ - try: - self.pool.put(conn, block=False) - return # Everything is dandy, done. - except AttributeError: - # self.pool is None. - pass - except queue.Full: - # This should never happen if self.block == True - log.warning("Connection pool is full, discarding connection: %s", self.host) - - # Connection never got put back into the pool, close it. - if conn: - conn.close() - - def _validate_conn(self, conn): - """ - Called right before a request is made, after the socket is created. - """ - pass - - def _prepare_proxy(self, conn): - # Nothing to do for HTTP connections. - pass - - def _get_timeout(self, timeout): - """Helper that always returns a :class:`urllib3.util.Timeout`""" - if timeout is _Default: - return self.timeout.clone() - - if isinstance(timeout, Timeout): - return timeout.clone() - else: - # User passed us an int/float. This is for backwards compatibility, - # can be removed later - return Timeout.from_float(timeout) - - def _raise_timeout(self, err, url, timeout_value): - """Is the error actually a timeout? Will raise a ReadTimeout or pass""" - - if isinstance(err, SocketTimeout): - raise ReadTimeoutError( - self, url, "Read timed out. (read timeout=%s)" % timeout_value - ) - - # See the above comment about EAGAIN in Python 3. In Python 2 we have - # to specifically catch it and throw the timeout error - if hasattr(err, "errno") and err.errno in _blocking_errnos: - raise ReadTimeoutError( - self, url, "Read timed out. (read timeout=%s)" % timeout_value - ) - - # Catch possible read timeouts thrown as SSL errors. If not the - # case, rethrow the original. We need to do this because of: - # http://bugs.python.org/issue10272 - if "timed out" in str(err) or "did not complete (read)" in str( - err - ): # Python < 2.7.4 - raise ReadTimeoutError( - self, url, "Read timed out. (read timeout=%s)" % timeout_value - ) - - def _make_request( - self, conn, method, url, timeout=_Default, chunked=False, **httplib_request_kw - ): - """ - Perform a request on a given urllib connection object taken from our - pool. - - :param conn: - a connection from one of our connection pools - - :param timeout: - Socket timeout in seconds for the request. This can be a - float or integer, which will set the same timeout value for - the socket connect and the socket read, or an instance of - :class:`urllib3.util.Timeout`, which gives you more fine-grained - control over your timeouts. - """ - self.num_requests += 1 - - timeout_obj = self._get_timeout(timeout) - timeout_obj.start_connect() - conn.timeout = timeout_obj.connect_timeout - - # Trigger any extra validation we need to do. - try: - self._validate_conn(conn) - except (SocketTimeout, BaseSSLError) as e: - # Py2 raises this as a BaseSSLError, Py3 raises it as socket timeout. - self._raise_timeout(err=e, url=url, timeout_value=conn.timeout) - raise - - # conn.request() calls http.client.*.request, not the method in - # urllib3.request. It also calls makefile (recv) on the socket. - try: - if chunked: - conn.request_chunked(method, url, **httplib_request_kw) - else: - conn.request(method, url, **httplib_request_kw) - - # We are swallowing BrokenPipeError (errno.EPIPE) since the server is - # legitimately able to close the connection after sending a valid response. - # With this behaviour, the received response is still readable. - except BrokenPipeError: - # Python 3 - pass - except IOError as e: - # Python 2 and macOS/Linux - # EPIPE and ESHUTDOWN are BrokenPipeError on Python 2, and EPROTOTYPE is needed on macOS - # https://erickt.github.io/blog/2014/11/19/adventures-in-debugging-a-potential-osx-kernel-bug/ - if e.errno not in { - errno.EPIPE, - errno.ESHUTDOWN, - errno.EPROTOTYPE, - }: - raise - - # Reset the timeout for the recv() on the socket - read_timeout = timeout_obj.read_timeout - - # App Engine doesn't have a sock attr - if getattr(conn, "sock", None): - # In Python 3 socket.py will catch EAGAIN and return None when you - # try and read into the file pointer created by http.client, which - # instead raises a BadStatusLine exception. Instead of catching - # the exception and assuming all BadStatusLine exceptions are read - # timeouts, check for a zero timeout before making the request. - if read_timeout == 0: - raise ReadTimeoutError( - self, url, "Read timed out. (read timeout=%s)" % read_timeout - ) - if read_timeout is Timeout.DEFAULT_TIMEOUT: - conn.sock.settimeout(socket.getdefaulttimeout()) - else: # None or a value - conn.sock.settimeout(read_timeout) - - # Receive the response from the server - try: - try: - # Python 2.7, use buffering of HTTP responses - httplib_response = conn.getresponse(buffering=True) - except TypeError: - # Python 3 - try: - httplib_response = conn.getresponse() - except BaseException as e: - # Remove the TypeError from the exception chain in - # Python 3 (including for exceptions like SystemExit). - # Otherwise it looks like a bug in the code. - six.raise_from(e, None) - except (SocketTimeout, BaseSSLError, SocketError) as e: - self._raise_timeout(err=e, url=url, timeout_value=read_timeout) - raise - - # AppEngine doesn't have a version attr. - http_version = getattr(conn, "_http_vsn_str", "HTTP/?") - log.debug( - '%s://%s:%s "%s %s %s" %s %s', - self.scheme, - self.host, - self.port, - method, - url, - http_version, - httplib_response.status, - httplib_response.length, - ) - - try: - assert_header_parsing(httplib_response.msg) - except (HeaderParsingError, TypeError) as hpe: # Platform-specific: Python 3 - log.warning( - "Failed to parse headers (url=%s): %s", - self._absolute_url(url), - hpe, - exc_info=True, - ) - - return httplib_response - - def _absolute_url(self, path): - return Url(scheme=self.scheme, host=self.host, port=self.port, path=path).url - - def close(self): - """ - Close all pooled connections and disable the pool. - """ - if self.pool is None: - return - # Disable access to the pool - old_pool, self.pool = self.pool, None - - try: - while True: - conn = old_pool.get(block=False) - if conn: - conn.close() - - except queue.Empty: - pass # Done. - - def is_same_host(self, url): - """ - Check if the given ``url`` is a member of the same host as this - connection pool. - """ - if url.startswith("/"): - return True - - # TODO: Add optional support for socket.gethostbyname checking. - scheme, host, port = get_host(url) - if host is not None: - host = _normalize_host(host, scheme=scheme) - - # Use explicit default port for comparison when none is given - if self.port and not port: - port = port_by_scheme.get(scheme) - elif not self.port and port == port_by_scheme.get(scheme): - port = None - - return (scheme, host, port) == (self.scheme, self.host, self.port) - - def urlopen( - self, - method, - url, - body=None, - headers=None, - retries=None, - redirect=True, - assert_same_host=True, - timeout=_Default, - pool_timeout=None, - release_conn=None, - chunked=False, - body_pos=None, - **response_kw - ): - """ - Get a connection from the pool and perform an HTTP request. This is the - lowest level call for making a request, so you'll need to specify all - the raw details. - - .. note:: - - More commonly, it's appropriate to use a convenience method provided - by :class:`.RequestMethods`, such as :meth:`request`. - - .. note:: - - `release_conn` will only behave as expected if - `preload_content=False` because we want to make - `preload_content=False` the default behaviour someday soon without - breaking backwards compatibility. - - :param method: - HTTP request method (such as GET, POST, PUT, etc.) - - :param url: - The URL to perform the request on. - - :param body: - Data to send in the request body, either :class:`str`, :class:`bytes`, - an iterable of :class:`str`/:class:`bytes`, or a file-like object. - - :param headers: - Dictionary of custom headers to send, such as User-Agent, - If-None-Match, etc. If None, pool headers are used. If provided, - these headers completely replace any pool-specific headers. - - :param retries: - Configure the number of retries to allow before raising a - :class:`~urllib3.exceptions.MaxRetryError` exception. - - Pass ``None`` to retry until you receive a response. Pass a - :class:`~urllib3.util.retry.Retry` object for fine-grained control - over different types of retries. - Pass an integer number to retry connection errors that many times, - but no other types of errors. Pass zero to never retry. - - If ``False``, then retries are disabled and any exception is raised - immediately. Also, instead of raising a MaxRetryError on redirects, - the redirect response will be returned. - - :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int. - - :param redirect: - If True, automatically handle redirects (status codes 301, 302, - 303, 307, 308). Each redirect counts as a retry. Disabling retries - will disable redirect, too. - - :param assert_same_host: - If ``True``, will make sure that the host of the pool requests is - consistent else will raise HostChangedError. When ``False``, you can - use the pool on an HTTP proxy and request foreign hosts. - - :param timeout: - If specified, overrides the default timeout for this one - request. It may be a float (in seconds) or an instance of - :class:`urllib3.util.Timeout`. - - :param pool_timeout: - If set and the pool is set to block=True, then this method will - block for ``pool_timeout`` seconds and raise EmptyPoolError if no - connection is available within the time period. - - :param release_conn: - If False, then the urlopen call will not release the connection - back into the pool once a response is received (but will release if - you read the entire contents of the response such as when - `preload_content=True`). This is useful if you're not preloading - the response's content immediately. You will need to call - ``r.release_conn()`` on the response ``r`` to return the connection - back into the pool. If None, it takes the value of - ``response_kw.get('preload_content', True)``. - - :param chunked: - If True, urllib3 will send the body using chunked transfer - encoding. Otherwise, urllib3 will send the body using the standard - content-length form. Defaults to False. - - :param int body_pos: - Position to seek to in file-like body in the event of a retry or - redirect. Typically this won't need to be set because urllib3 will - auto-populate the value when needed. - - :param \\**response_kw: - Additional parameters are passed to - :meth:`urllib3.response.HTTPResponse.from_httplib` - """ - - parsed_url = parse_url(url) - destination_scheme = parsed_url.scheme - - if headers is None: - headers = self.headers - - if not isinstance(retries, Retry): - retries = Retry.from_int(retries, redirect=redirect, default=self.retries) - - if release_conn is None: - release_conn = response_kw.get("preload_content", True) - - # Check host - if assert_same_host and not self.is_same_host(url): - raise HostChangedError(self, url, retries) - - # Ensure that the URL we're connecting to is properly encoded - if url.startswith("/"): - url = six.ensure_str(_encode_target(url)) - else: - url = six.ensure_str(parsed_url.url) - - conn = None - - # Track whether `conn` needs to be released before - # returning/raising/recursing. Update this variable if necessary, and - # leave `release_conn` constant throughout the function. That way, if - # the function recurses, the original value of `release_conn` will be - # passed down into the recursive call, and its value will be respected. - # - # See issue #651 [1] for details. - # - # [1] <https://github.com/urllib3/urllib3/issues/651> - release_this_conn = release_conn - - http_tunnel_required = connection_requires_http_tunnel( - self.proxy, self.proxy_config, destination_scheme - ) - - # Merge the proxy headers. Only done when not using HTTP CONNECT. We - # have to copy the headers dict so we can safely change it without those - # changes being reflected in anyone else's copy. - if not http_tunnel_required: - headers = headers.copy() - headers.update(self.proxy_headers) - - # Must keep the exception bound to a separate variable or else Python 3 - # complains about UnboundLocalError. - err = None - - # Keep track of whether we cleanly exited the except block. This - # ensures we do proper cleanup in finally. - clean_exit = False - - # Rewind body position, if needed. Record current position - # for future rewinds in the event of a redirect/retry. - body_pos = set_file_position(body, body_pos) - - try: - # Request a connection from the queue. - timeout_obj = self._get_timeout(timeout) - conn = self._get_conn(timeout=pool_timeout) - - conn.timeout = timeout_obj.connect_timeout - - is_new_proxy_conn = self.proxy is not None and not getattr( - conn, "sock", None - ) - if is_new_proxy_conn and http_tunnel_required: - self._prepare_proxy(conn) - - # Make the request on the httplib connection object. - httplib_response = self._make_request( - conn, - method, - url, - timeout=timeout_obj, - body=body, - headers=headers, - chunked=chunked, - ) - - # If we're going to release the connection in ``finally:``, then - # the response doesn't need to know about the connection. Otherwise - # it will also try to release it and we'll have a double-release - # mess. - response_conn = conn if not release_conn else None - - # Pass method to Response for length checking - response_kw["request_method"] = method - - # Import httplib's response into our own wrapper object - response = self.ResponseCls.from_httplib( - httplib_response, - pool=self, - connection=response_conn, - retries=retries, - **response_kw - ) - - # Everything went great! - clean_exit = True - - except EmptyPoolError: - # Didn't get a connection from the pool, no need to clean up - clean_exit = True - release_this_conn = False - raise - - except ( - TimeoutError, - HTTPException, - SocketError, - ProtocolError, - BaseSSLError, - SSLError, - CertificateError, - ) as e: - # Discard the connection for these exceptions. It will be - # replaced during the next _get_conn() call. - clean_exit = False - if isinstance(e, (BaseSSLError, CertificateError)): - e = SSLError(e) - elif isinstance(e, (SocketError, NewConnectionError)) and self.proxy: - e = ProxyError("Cannot connect to proxy.", e) - elif isinstance(e, (SocketError, HTTPException)): - e = ProtocolError("Connection aborted.", e) - - retries = retries.increment( - method, url, error=e, _pool=self, _stacktrace=sys.exc_info()[2] - ) - retries.sleep() - - # Keep track of the error for the retry warning. - err = e - - finally: - if not clean_exit: - # We hit some kind of exception, handled or otherwise. We need - # to throw the connection away unless explicitly told not to. - # Close the connection, set the variable to None, and make sure - # we put the None back in the pool to avoid leaking it. - conn = conn and conn.close() - release_this_conn = True - - if release_this_conn: - # Put the connection back to be reused. If the connection is - # expired then it will be None, which will get replaced with a - # fresh connection during _get_conn. - self._put_conn(conn) - - if not conn: - # Try again - log.warning( - "Retrying (%r) after connection broken by '%r': %s", retries, err, url - ) - return self.urlopen( - method, - url, - body, - headers, - retries, - redirect, - assert_same_host, - timeout=timeout, - pool_timeout=pool_timeout, - release_conn=release_conn, - chunked=chunked, - body_pos=body_pos, - **response_kw - ) - - # Handle redirect? - redirect_location = redirect and response.get_redirect_location() - if redirect_location: - if response.status == 303: - method = "GET" - - try: - retries = retries.increment(method, url, response=response, _pool=self) - except MaxRetryError: - if retries.raise_on_redirect: - response.drain_conn() - raise - return response - - response.drain_conn() - retries.sleep_for_retry(response) - log.debug("Redirecting %s -> %s", url, redirect_location) - return self.urlopen( - method, - redirect_location, - body, - headers, - retries=retries, - redirect=redirect, - assert_same_host=assert_same_host, - timeout=timeout, - pool_timeout=pool_timeout, - release_conn=release_conn, - chunked=chunked, - body_pos=body_pos, - **response_kw - ) - - # Check if we should retry the HTTP response. - has_retry_after = bool(response.getheader("Retry-After")) - if retries.is_retry(method, response.status, has_retry_after): - try: - retries = retries.increment(method, url, response=response, _pool=self) - except MaxRetryError: - if retries.raise_on_status: - response.drain_conn() - raise - return response - - response.drain_conn() - retries.sleep(response) - log.debug("Retry: %s", url) - return self.urlopen( - method, - url, - body, - headers, - retries=retries, - redirect=redirect, - assert_same_host=assert_same_host, - timeout=timeout, - pool_timeout=pool_timeout, - release_conn=release_conn, - chunked=chunked, - body_pos=body_pos, - **response_kw - ) - - return response - - -class HTTPSConnectionPool(HTTPConnectionPool): - """ - Same as :class:`.HTTPConnectionPool`, but HTTPS. - - :class:`.HTTPSConnection` uses one of ``assert_fingerprint``, - ``assert_hostname`` and ``host`` in this order to verify connections. - If ``assert_hostname`` is False, no verification is done. - - The ``key_file``, ``cert_file``, ``cert_reqs``, ``ca_certs``, - ``ca_cert_dir``, ``ssl_version``, ``key_password`` are only used if :mod:`ssl` - is available and are fed into :meth:`urllib3.util.ssl_wrap_socket` to upgrade - the connection socket into an SSL socket. - """ - - scheme = "https" - ConnectionCls = HTTPSConnection - - def __init__( - self, - host, - port=None, - strict=False, - timeout=Timeout.DEFAULT_TIMEOUT, - maxsize=1, - block=False, - headers=None, - retries=None, - _proxy=None, - _proxy_headers=None, - key_file=None, - cert_file=None, - cert_reqs=None, - key_password=None, - ca_certs=None, - ssl_version=None, - assert_hostname=None, - assert_fingerprint=None, - ca_cert_dir=None, - **conn_kw - ): - - HTTPConnectionPool.__init__( - self, - host, - port, - strict, - timeout, - maxsize, - block, - headers, - retries, - _proxy, - _proxy_headers, - **conn_kw - ) - - self.key_file = key_file - self.cert_file = cert_file - self.cert_reqs = cert_reqs - self.key_password = key_password - self.ca_certs = ca_certs - self.ca_cert_dir = ca_cert_dir - self.ssl_version = ssl_version - self.assert_hostname = assert_hostname - self.assert_fingerprint = assert_fingerprint - - def _prepare_conn(self, conn): - """ - Prepare the ``connection`` for :meth:`urllib3.util.ssl_wrap_socket` - and establish the tunnel if proxy is used. - """ - - if isinstance(conn, VerifiedHTTPSConnection): - conn.set_cert( - key_file=self.key_file, - key_password=self.key_password, - cert_file=self.cert_file, - cert_reqs=self.cert_reqs, - ca_certs=self.ca_certs, - ca_cert_dir=self.ca_cert_dir, - assert_hostname=self.assert_hostname, - assert_fingerprint=self.assert_fingerprint, - ) - conn.ssl_version = self.ssl_version - return conn - - def _prepare_proxy(self, conn): - """ - Establishes a tunnel connection through HTTP CONNECT. - - Tunnel connection is established early because otherwise httplib would - improperly set Host: header to proxy's IP:port. - """ - - conn.set_tunnel(self._proxy_host, self.port, self.proxy_headers) - - if self.proxy.scheme == "https": - conn.tls_in_tls_required = True - - conn.connect() - - def _new_conn(self): - """ - Return a fresh :class:`http.client.HTTPSConnection`. - """ - self.num_connections += 1 - log.debug( - "Starting new HTTPS connection (%d): %s:%s", - self.num_connections, - self.host, - self.port or "443", - ) - - if not self.ConnectionCls or self.ConnectionCls is DummyConnection: - raise SSLError( - "Can't connect to HTTPS URL because the SSL module is not available." - ) - - actual_host = self.host - actual_port = self.port - if self.proxy is not None: - actual_host = self.proxy.host - actual_port = self.proxy.port - - conn = self.ConnectionCls( - host=actual_host, - port=actual_port, - timeout=self.timeout.connect_timeout, - strict=self.strict, - cert_file=self.cert_file, - key_file=self.key_file, - key_password=self.key_password, - **self.conn_kw - ) - - return self._prepare_conn(conn) - - def _validate_conn(self, conn): - """ - Called right before a request is made, after the socket is created. - """ - super(HTTPSConnectionPool, self)._validate_conn(conn) - - # Force connect early to allow us to validate the connection. - if not getattr(conn, "sock", None): # AppEngine might not have `.sock` - conn.connect() - - if not conn.is_verified: - warnings.warn( - ( - "Unverified HTTPS request is being made to host '%s'. " - "Adding certificate verification is strongly advised. See: " - "https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html" - "#ssl-warnings" % conn.host - ), - InsecureRequestWarning, - ) - - -def connection_from_url(url, **kw): - """ - Given a url, return an :class:`.ConnectionPool` instance of its host. - - This is a shortcut for not having to parse out the scheme, host, and port - of the url before creating an :class:`.ConnectionPool` instance. - - :param url: - Absolute URL string that must include the scheme. Port is optional. - - :param \\**kw: - Passes additional parameters to the constructor of the appropriate - :class:`.ConnectionPool`. Useful for specifying things like - timeout, maxsize, headers, etc. - - Example:: - - >>> conn = connection_from_url('http://google.com/') - >>> r = conn.request('GET', '/') - """ - scheme, host, port = get_host(url) - port = port or port_by_scheme.get(scheme, 80) - if scheme == "https": - return HTTPSConnectionPool(host, port=port, **kw) - else: - return HTTPConnectionPool(host, port=port, **kw) - - -def _normalize_host(host, scheme): - """ - Normalize hosts for comparisons and use with sockets. - """ - - host = normalize_host(host, scheme) - - # httplib doesn't like it when we include brackets in IPv6 addresses - # Specifically, if we include brackets but also pass the port then - # httplib crazily doubles up the square brackets on the Host header. - # Instead, we need to make sure we never pass ``None`` as the port. - # However, for backward compatibility reasons we can't actually - # *assert* that. See http://bugs.python.org/issue28539 - if host.startswith("[") and host.endswith("]"): - host = host[1:-1] - return host diff --git a/venv/lib/python3.8/site-packages/urllib3/contrib/__init__.py b/venv/lib/python3.8/site-packages/urllib3/contrib/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.8/site-packages/urllib3/contrib/_appengine_environ.py b/venv/lib/python3.8/site-packages/urllib3/contrib/_appengine_environ.py deleted file mode 100644 index 8765b90..0000000 --- a/venv/lib/python3.8/site-packages/urllib3/contrib/_appengine_environ.py +++ /dev/null @@ -1,36 +0,0 @@ -""" -This module provides means to detect the App Engine environment. -""" - -import os - - -def is_appengine(): - return is_local_appengine() or is_prod_appengine() - - -def is_appengine_sandbox(): - """Reports if the app is running in the first generation sandbox. - - The second generation runtimes are technically still in a sandbox, but it - is much less restrictive, so generally you shouldn't need to check for it. - see https://cloud.google.com/appengine/docs/standard/runtimes - """ - return is_appengine() and os.environ["APPENGINE_RUNTIME"] == "python27" - - -def is_local_appengine(): - return "APPENGINE_RUNTIME" in os.environ and os.environ.get( - "SERVER_SOFTWARE", "" - ).startswith("Development/") - - -def is_prod_appengine(): - return "APPENGINE_RUNTIME" in os.environ and os.environ.get( - "SERVER_SOFTWARE", "" - ).startswith("Google App Engine/") - - -def is_prod_appengine_mvms(): - """Deprecated.""" - return False diff --git a/venv/lib/python3.8/site-packages/urllib3/contrib/_securetransport/__init__.py b/venv/lib/python3.8/site-packages/urllib3/contrib/_securetransport/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.8/site-packages/urllib3/contrib/_securetransport/bindings.py b/venv/lib/python3.8/site-packages/urllib3/contrib/_securetransport/bindings.py deleted file mode 100644 index 11524d4..0000000 --- a/venv/lib/python3.8/site-packages/urllib3/contrib/_securetransport/bindings.py +++ /dev/null @@ -1,519 +0,0 @@ -""" -This module uses ctypes to bind a whole bunch of functions and constants from -SecureTransport. The goal here is to provide the low-level API to -SecureTransport. These are essentially the C-level functions and constants, and -they're pretty gross to work with. - -This code is a bastardised version of the code found in Will Bond's oscrypto -library. An enormous debt is owed to him for blazing this trail for us. For -that reason, this code should be considered to be covered both by urllib3's -license and by oscrypto's: - - Copyright (c) 2015-2016 Will Bond <will@wbond.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. -""" -from __future__ import absolute_import - -import platform -from ctypes import ( - CDLL, - CFUNCTYPE, - POINTER, - c_bool, - c_byte, - c_char_p, - c_int32, - c_long, - c_size_t, - c_uint32, - c_ulong, - c_void_p, -) -from ctypes.util import find_library - -from urllib3.packages.six import raise_from - -if platform.system() != "Darwin": - raise ImportError("Only macOS is supported") - -version = platform.mac_ver()[0] -version_info = tuple(map(int, version.split("."))) -if version_info < (10, 8): - raise OSError( - "Only OS X 10.8 and newer are supported, not %s.%s" - % (version_info[0], version_info[1]) - ) - - -def load_cdll(name, macos10_16_path): - """Loads a CDLL by name, falling back to known path on 10.16+""" - try: - # Big Sur is technically 11 but we use 10.16 due to the Big Sur - # beta being labeled as 10.16. - if version_info >= (10, 16): - path = macos10_16_path - else: - path = find_library(name) - if not path: - raise OSError # Caught and reraised as 'ImportError' - return CDLL(path, use_errno=True) - except OSError: - raise_from(ImportError("The library %s failed to load" % name), None) - - -Security = load_cdll( - "Security", "/System/Library/Frameworks/Security.framework/Security" -) -CoreFoundation = load_cdll( - "CoreFoundation", - "/System/Library/Frameworks/CoreFoundation.framework/CoreFoundation", -) - - -Boolean = c_bool -CFIndex = c_long -CFStringEncoding = c_uint32 -CFData = c_void_p -CFString = c_void_p -CFArray = c_void_p -CFMutableArray = c_void_p -CFDictionary = c_void_p -CFError = c_void_p -CFType = c_void_p -CFTypeID = c_ulong - -CFTypeRef = POINTER(CFType) -CFAllocatorRef = c_void_p - -OSStatus = c_int32 - -CFDataRef = POINTER(CFData) -CFStringRef = POINTER(CFString) -CFArrayRef = POINTER(CFArray) -CFMutableArrayRef = POINTER(CFMutableArray) -CFDictionaryRef = POINTER(CFDictionary) -CFArrayCallBacks = c_void_p -CFDictionaryKeyCallBacks = c_void_p -CFDictionaryValueCallBacks = c_void_p - -SecCertificateRef = POINTER(c_void_p) -SecExternalFormat = c_uint32 -SecExternalItemType = c_uint32 -SecIdentityRef = POINTER(c_void_p) -SecItemImportExportFlags = c_uint32 -SecItemImportExportKeyParameters = c_void_p -SecKeychainRef = POINTER(c_void_p) -SSLProtocol = c_uint32 -SSLCipherSuite = c_uint32 -SSLContextRef = POINTER(c_void_p) -SecTrustRef = POINTER(c_void_p) -SSLConnectionRef = c_uint32 -SecTrustResultType = c_uint32 -SecTrustOptionFlags = c_uint32 -SSLProtocolSide = c_uint32 -SSLConnectionType = c_uint32 -SSLSessionOption = c_uint32 - - -try: - Security.SecItemImport.argtypes = [ - CFDataRef, - CFStringRef, - POINTER(SecExternalFormat), - POINTER(SecExternalItemType), - SecItemImportExportFlags, - POINTER(SecItemImportExportKeyParameters), - SecKeychainRef, - POINTER(CFArrayRef), - ] - Security.SecItemImport.restype = OSStatus - - Security.SecCertificateGetTypeID.argtypes = [] - Security.SecCertificateGetTypeID.restype = CFTypeID - - Security.SecIdentityGetTypeID.argtypes = [] - Security.SecIdentityGetTypeID.restype = CFTypeID - - Security.SecKeyGetTypeID.argtypes = [] - Security.SecKeyGetTypeID.restype = CFTypeID - - Security.SecCertificateCreateWithData.argtypes = [CFAllocatorRef, CFDataRef] - Security.SecCertificateCreateWithData.restype = SecCertificateRef - - Security.SecCertificateCopyData.argtypes = [SecCertificateRef] - Security.SecCertificateCopyData.restype = CFDataRef - - Security.SecCopyErrorMessageString.argtypes = [OSStatus, c_void_p] - Security.SecCopyErrorMessageString.restype = CFStringRef - - Security.SecIdentityCreateWithCertificate.argtypes = [ - CFTypeRef, - SecCertificateRef, - POINTER(SecIdentityRef), - ] - Security.SecIdentityCreateWithCertificate.restype = OSStatus - - Security.SecKeychainCreate.argtypes = [ - c_char_p, - c_uint32, - c_void_p, - Boolean, - c_void_p, - POINTER(SecKeychainRef), - ] - Security.SecKeychainCreate.restype = OSStatus - - Security.SecKeychainDelete.argtypes = [SecKeychainRef] - Security.SecKeychainDelete.restype = OSStatus - - Security.SecPKCS12Import.argtypes = [ - CFDataRef, - CFDictionaryRef, - POINTER(CFArrayRef), - ] - Security.SecPKCS12Import.restype = OSStatus - - SSLReadFunc = CFUNCTYPE(OSStatus, SSLConnectionRef, c_void_p, POINTER(c_size_t)) - SSLWriteFunc = CFUNCTYPE( - OSStatus, SSLConnectionRef, POINTER(c_byte), POINTER(c_size_t) - ) - - Security.SSLSetIOFuncs.argtypes = [SSLContextRef, SSLReadFunc, SSLWriteFunc] - Security.SSLSetIOFuncs.restype = OSStatus - - Security.SSLSetPeerID.argtypes = [SSLContextRef, c_char_p, c_size_t] - Security.SSLSetPeerID.restype = OSStatus - - Security.SSLSetCertificate.argtypes = [SSLContextRef, CFArrayRef] - Security.SSLSetCertificate.restype = OSStatus - - Security.SSLSetCertificateAuthorities.argtypes = [SSLContextRef, CFTypeRef, Boolean] - Security.SSLSetCertificateAuthorities.restype = OSStatus - - Security.SSLSetConnection.argtypes = [SSLContextRef, SSLConnectionRef] - Security.SSLSetConnection.restype = OSStatus - - Security.SSLSetPeerDomainName.argtypes = [SSLContextRef, c_char_p, c_size_t] - Security.SSLSetPeerDomainName.restype = OSStatus - - Security.SSLHandshake.argtypes = [SSLContextRef] - Security.SSLHandshake.restype = OSStatus - - Security.SSLRead.argtypes = [SSLContextRef, c_char_p, c_size_t, POINTER(c_size_t)] - Security.SSLRead.restype = OSStatus - - Security.SSLWrite.argtypes = [SSLContextRef, c_char_p, c_size_t, POINTER(c_size_t)] - Security.SSLWrite.restype = OSStatus - - Security.SSLClose.argtypes = [SSLContextRef] - Security.SSLClose.restype = OSStatus - - Security.SSLGetNumberSupportedCiphers.argtypes = [SSLContextRef, POINTER(c_size_t)] - Security.SSLGetNumberSupportedCiphers.restype = OSStatus - - Security.SSLGetSupportedCiphers.argtypes = [ - SSLContextRef, - POINTER(SSLCipherSuite), - POINTER(c_size_t), - ] - Security.SSLGetSupportedCiphers.restype = OSStatus - - Security.SSLSetEnabledCiphers.argtypes = [ - SSLContextRef, - POINTER(SSLCipherSuite), - c_size_t, - ] - Security.SSLSetEnabledCiphers.restype = OSStatus - - Security.SSLGetNumberEnabledCiphers.argtype = [SSLContextRef, POINTER(c_size_t)] - Security.SSLGetNumberEnabledCiphers.restype = OSStatus - - Security.SSLGetEnabledCiphers.argtypes = [ - SSLContextRef, - POINTER(SSLCipherSuite), - POINTER(c_size_t), - ] - Security.SSLGetEnabledCiphers.restype = OSStatus - - Security.SSLGetNegotiatedCipher.argtypes = [SSLContextRef, POINTER(SSLCipherSuite)] - Security.SSLGetNegotiatedCipher.restype = OSStatus - - Security.SSLGetNegotiatedProtocolVersion.argtypes = [ - SSLContextRef, - POINTER(SSLProtocol), - ] - Security.SSLGetNegotiatedProtocolVersion.restype = OSStatus - - Security.SSLCopyPeerTrust.argtypes = [SSLContextRef, POINTER(SecTrustRef)] - Security.SSLCopyPeerTrust.restype = OSStatus - - Security.SecTrustSetAnchorCertificates.argtypes = [SecTrustRef, CFArrayRef] - Security.SecTrustSetAnchorCertificates.restype = OSStatus - - Security.SecTrustSetAnchorCertificatesOnly.argstypes = [SecTrustRef, Boolean] - Security.SecTrustSetAnchorCertificatesOnly.restype = OSStatus - - Security.SecTrustEvaluate.argtypes = [SecTrustRef, POINTER(SecTrustResultType)] - Security.SecTrustEvaluate.restype = OSStatus - - Security.SecTrustGetCertificateCount.argtypes = [SecTrustRef] - Security.SecTrustGetCertificateCount.restype = CFIndex - - Security.SecTrustGetCertificateAtIndex.argtypes = [SecTrustRef, CFIndex] - Security.SecTrustGetCertificateAtIndex.restype = SecCertificateRef - - Security.SSLCreateContext.argtypes = [ - CFAllocatorRef, - SSLProtocolSide, - SSLConnectionType, - ] - Security.SSLCreateContext.restype = SSLContextRef - - Security.SSLSetSessionOption.argtypes = [SSLContextRef, SSLSessionOption, Boolean] - Security.SSLSetSessionOption.restype = OSStatus - - Security.SSLSetProtocolVersionMin.argtypes = [SSLContextRef, SSLProtocol] - Security.SSLSetProtocolVersionMin.restype = OSStatus - - Security.SSLSetProtocolVersionMax.argtypes = [SSLContextRef, SSLProtocol] - Security.SSLSetProtocolVersionMax.restype = OSStatus - - try: - Security.SSLSetALPNProtocols.argtypes = [SSLContextRef, CFArrayRef] - Security.SSLSetALPNProtocols.restype = OSStatus - except AttributeError: - # Supported only in 10.12+ - pass - - Security.SecCopyErrorMessageString.argtypes = [OSStatus, c_void_p] - Security.SecCopyErrorMessageString.restype = CFStringRef - - Security.SSLReadFunc = SSLReadFunc - Security.SSLWriteFunc = SSLWriteFunc - Security.SSLContextRef = SSLContextRef - Security.SSLProtocol = SSLProtocol - Security.SSLCipherSuite = SSLCipherSuite - Security.SecIdentityRef = SecIdentityRef - Security.SecKeychainRef = SecKeychainRef - Security.SecTrustRef = SecTrustRef - Security.SecTrustResultType = SecTrustResultType - Security.SecExternalFormat = SecExternalFormat - Security.OSStatus = OSStatus - - Security.kSecImportExportPassphrase = CFStringRef.in_dll( - Security, "kSecImportExportPassphrase" - ) - Security.kSecImportItemIdentity = CFStringRef.in_dll( - Security, "kSecImportItemIdentity" - ) - - # CoreFoundation time! - CoreFoundation.CFRetain.argtypes = [CFTypeRef] - CoreFoundation.CFRetain.restype = CFTypeRef - - CoreFoundation.CFRelease.argtypes = [CFTypeRef] - CoreFoundation.CFRelease.restype = None - - CoreFoundation.CFGetTypeID.argtypes = [CFTypeRef] - CoreFoundation.CFGetTypeID.restype = CFTypeID - - CoreFoundation.CFStringCreateWithCString.argtypes = [ - CFAllocatorRef, - c_char_p, - CFStringEncoding, - ] - CoreFoundation.CFStringCreateWithCString.restype = CFStringRef - - CoreFoundation.CFStringGetCStringPtr.argtypes = [CFStringRef, CFStringEncoding] - CoreFoundation.CFStringGetCStringPtr.restype = c_char_p - - CoreFoundation.CFStringGetCString.argtypes = [ - CFStringRef, - c_char_p, - CFIndex, - CFStringEncoding, - ] - CoreFoundation.CFStringGetCString.restype = c_bool - - CoreFoundation.CFDataCreate.argtypes = [CFAllocatorRef, c_char_p, CFIndex] - CoreFoundation.CFDataCreate.restype = CFDataRef - - CoreFoundation.CFDataGetLength.argtypes = [CFDataRef] - CoreFoundation.CFDataGetLength.restype = CFIndex - - CoreFoundation.CFDataGetBytePtr.argtypes = [CFDataRef] - CoreFoundation.CFDataGetBytePtr.restype = c_void_p - - CoreFoundation.CFDictionaryCreate.argtypes = [ - CFAllocatorRef, - POINTER(CFTypeRef), - POINTER(CFTypeRef), - CFIndex, - CFDictionaryKeyCallBacks, - CFDictionaryValueCallBacks, - ] - CoreFoundation.CFDictionaryCreate.restype = CFDictionaryRef - - CoreFoundation.CFDictionaryGetValue.argtypes = [CFDictionaryRef, CFTypeRef] - CoreFoundation.CFDictionaryGetValue.restype = CFTypeRef - - CoreFoundation.CFArrayCreate.argtypes = [ - CFAllocatorRef, - POINTER(CFTypeRef), - CFIndex, - CFArrayCallBacks, - ] - CoreFoundation.CFArrayCreate.restype = CFArrayRef - - CoreFoundation.CFArrayCreateMutable.argtypes = [ - CFAllocatorRef, - CFIndex, - CFArrayCallBacks, - ] - CoreFoundation.CFArrayCreateMutable.restype = CFMutableArrayRef - - CoreFoundation.CFArrayAppendValue.argtypes = [CFMutableArrayRef, c_void_p] - CoreFoundation.CFArrayAppendValue.restype = None - - CoreFoundation.CFArrayGetCount.argtypes = [CFArrayRef] - CoreFoundation.CFArrayGetCount.restype = CFIndex - - CoreFoundation.CFArrayGetValueAtIndex.argtypes = [CFArrayRef, CFIndex] - CoreFoundation.CFArrayGetValueAtIndex.restype = c_void_p - - CoreFoundation.kCFAllocatorDefault = CFAllocatorRef.in_dll( - CoreFoundation, "kCFAllocatorDefault" - ) - CoreFoundation.kCFTypeArrayCallBacks = c_void_p.in_dll( - CoreFoundation, "kCFTypeArrayCallBacks" - ) - CoreFoundation.kCFTypeDictionaryKeyCallBacks = c_void_p.in_dll( - CoreFoundation, "kCFTypeDictionaryKeyCallBacks" - ) - CoreFoundation.kCFTypeDictionaryValueCallBacks = c_void_p.in_dll( - CoreFoundation, "kCFTypeDictionaryValueCallBacks" - ) - - CoreFoundation.CFTypeRef = CFTypeRef - CoreFoundation.CFArrayRef = CFArrayRef - CoreFoundation.CFStringRef = CFStringRef - CoreFoundation.CFDictionaryRef = CFDictionaryRef - -except (AttributeError): - raise ImportError("Error initializing ctypes") - - -class CFConst(object): - """ - A class object that acts as essentially a namespace for CoreFoundation - constants. - """ - - kCFStringEncodingUTF8 = CFStringEncoding(0x08000100) - - -class SecurityConst(object): - """ - A class object that acts as essentially a namespace for Security constants. - """ - - kSSLSessionOptionBreakOnServerAuth = 0 - - kSSLProtocol2 = 1 - kSSLProtocol3 = 2 - kTLSProtocol1 = 4 - kTLSProtocol11 = 7 - kTLSProtocol12 = 8 - # SecureTransport does not support TLS 1.3 even if there's a constant for it - kTLSProtocol13 = 10 - kTLSProtocolMaxSupported = 999 - - kSSLClientSide = 1 - kSSLStreamType = 0 - - kSecFormatPEMSequence = 10 - - kSecTrustResultInvalid = 0 - kSecTrustResultProceed = 1 - # This gap is present on purpose: this was kSecTrustResultConfirm, which - # is deprecated. - kSecTrustResultDeny = 3 - kSecTrustResultUnspecified = 4 - kSecTrustResultRecoverableTrustFailure = 5 - kSecTrustResultFatalTrustFailure = 6 - kSecTrustResultOtherError = 7 - - errSSLProtocol = -9800 - errSSLWouldBlock = -9803 - errSSLClosedGraceful = -9805 - errSSLClosedNoNotify = -9816 - errSSLClosedAbort = -9806 - - errSSLXCertChainInvalid = -9807 - errSSLCrypto = -9809 - errSSLInternal = -9810 - errSSLCertExpired = -9814 - errSSLCertNotYetValid = -9815 - errSSLUnknownRootCert = -9812 - errSSLNoRootCert = -9813 - errSSLHostNameMismatch = -9843 - errSSLPeerHandshakeFail = -9824 - errSSLPeerUserCancelled = -9839 - errSSLWeakPeerEphemeralDHKey = -9850 - errSSLServerAuthCompleted = -9841 - errSSLRecordOverflow = -9847 - - errSecVerifyFailed = -67808 - errSecNoTrustSettings = -25263 - errSecItemNotFound = -25300 - errSecInvalidTrustSettings = -25262 - - # Cipher suites. We only pick the ones our default cipher string allows. - # Source: https://developer.apple.com/documentation/security/1550981-ssl_cipher_suite_values - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 = 0xC02C - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 = 0xC030 - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 = 0xC02B - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = 0xC02F - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCCA9 - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 = 0xCCA8 - TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 = 0x009F - TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 = 0x009E - TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 = 0xC024 - TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 = 0xC028 - TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA = 0xC00A - TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = 0xC014 - TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 = 0x006B - TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0x0039 - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 = 0xC023 - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = 0xC027 - TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA = 0xC009 - TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = 0xC013 - TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 = 0x0067 - TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0x0033 - TLS_RSA_WITH_AES_256_GCM_SHA384 = 0x009D - TLS_RSA_WITH_AES_128_GCM_SHA256 = 0x009C - TLS_RSA_WITH_AES_256_CBC_SHA256 = 0x003D - TLS_RSA_WITH_AES_128_CBC_SHA256 = 0x003C - TLS_RSA_WITH_AES_256_CBC_SHA = 0x0035 - TLS_RSA_WITH_AES_128_CBC_SHA = 0x002F - TLS_AES_128_GCM_SHA256 = 0x1301 - TLS_AES_256_GCM_SHA384 = 0x1302 - TLS_AES_128_CCM_8_SHA256 = 0x1305 - TLS_AES_128_CCM_SHA256 = 0x1304 diff --git a/venv/lib/python3.8/site-packages/urllib3/contrib/_securetransport/low_level.py b/venv/lib/python3.8/site-packages/urllib3/contrib/_securetransport/low_level.py deleted file mode 100644 index ed81201..0000000 --- a/venv/lib/python3.8/site-packages/urllib3/contrib/_securetransport/low_level.py +++ /dev/null @@ -1,396 +0,0 @@ -""" -Low-level helpers for the SecureTransport bindings. - -These are Python functions that are not directly related to the high-level APIs -but are necessary to get them to work. They include a whole bunch of low-level -CoreFoundation messing about and memory management. The concerns in this module -are almost entirely about trying to avoid memory leaks and providing -appropriate and useful assistance to the higher-level code. -""" -import base64 -import ctypes -import itertools -import os -import re -import ssl -import struct -import tempfile - -from .bindings import CFConst, CoreFoundation, Security - -# This regular expression is used to grab PEM data out of a PEM bundle. -_PEM_CERTS_RE = re.compile( - b"-----BEGIN CERTIFICATE-----\n(.*?)\n-----END CERTIFICATE-----", re.DOTALL -) - - -def _cf_data_from_bytes(bytestring): - """ - Given a bytestring, create a CFData object from it. This CFData object must - be CFReleased by the caller. - """ - return CoreFoundation.CFDataCreate( - CoreFoundation.kCFAllocatorDefault, bytestring, len(bytestring) - ) - - -def _cf_dictionary_from_tuples(tuples): - """ - Given a list of Python tuples, create an associated CFDictionary. - """ - dictionary_size = len(tuples) - - # We need to get the dictionary keys and values out in the same order. - keys = (t[0] for t in tuples) - values = (t[1] for t in tuples) - cf_keys = (CoreFoundation.CFTypeRef * dictionary_size)(*keys) - cf_values = (CoreFoundation.CFTypeRef * dictionary_size)(*values) - - return CoreFoundation.CFDictionaryCreate( - CoreFoundation.kCFAllocatorDefault, - cf_keys, - cf_values, - dictionary_size, - CoreFoundation.kCFTypeDictionaryKeyCallBacks, - CoreFoundation.kCFTypeDictionaryValueCallBacks, - ) - - -def _cfstr(py_bstr): - """ - Given a Python binary data, create a CFString. - The string must be CFReleased by the caller. - """ - c_str = ctypes.c_char_p(py_bstr) - cf_str = CoreFoundation.CFStringCreateWithCString( - CoreFoundation.kCFAllocatorDefault, - c_str, - CFConst.kCFStringEncodingUTF8, - ) - return cf_str - - -def _create_cfstring_array(lst): - """ - Given a list of Python binary data, create an associated CFMutableArray. - The array must be CFReleased by the caller. - - Raises an ssl.SSLError on failure. - """ - cf_arr = None - try: - cf_arr = CoreFoundation.CFArrayCreateMutable( - CoreFoundation.kCFAllocatorDefault, - 0, - ctypes.byref(CoreFoundation.kCFTypeArrayCallBacks), - ) - if not cf_arr: - raise MemoryError("Unable to allocate memory!") - for item in lst: - cf_str = _cfstr(item) - if not cf_str: - raise MemoryError("Unable to allocate memory!") - try: - CoreFoundation.CFArrayAppendValue(cf_arr, cf_str) - finally: - CoreFoundation.CFRelease(cf_str) - except BaseException as e: - if cf_arr: - CoreFoundation.CFRelease(cf_arr) - raise ssl.SSLError("Unable to allocate array: %s" % (e,)) - return cf_arr - - -def _cf_string_to_unicode(value): - """ - Creates a Unicode string from a CFString object. Used entirely for error - reporting. - - Yes, it annoys me quite a lot that this function is this complex. - """ - value_as_void_p = ctypes.cast(value, ctypes.POINTER(ctypes.c_void_p)) - - string = CoreFoundation.CFStringGetCStringPtr( - value_as_void_p, CFConst.kCFStringEncodingUTF8 - ) - if string is None: - buffer = ctypes.create_string_buffer(1024) - result = CoreFoundation.CFStringGetCString( - value_as_void_p, buffer, 1024, CFConst.kCFStringEncodingUTF8 - ) - if not result: - raise OSError("Error copying C string from CFStringRef") - string = buffer.value - if string is not None: - string = string.decode("utf-8") - return string - - -def _assert_no_error(error, exception_class=None): - """ - Checks the return code and throws an exception if there is an error to - report - """ - if error == 0: - return - - cf_error_string = Security.SecCopyErrorMessageString(error, None) - output = _cf_string_to_unicode(cf_error_string) - CoreFoundation.CFRelease(cf_error_string) - - if output is None or output == u"": - output = u"OSStatus %s" % error - - if exception_class is None: - exception_class = ssl.SSLError - - raise exception_class(output) - - -def _cert_array_from_pem(pem_bundle): - """ - Given a bundle of certs in PEM format, turns them into a CFArray of certs - that can be used to validate a cert chain. - """ - # Normalize the PEM bundle's line endings. - pem_bundle = pem_bundle.replace(b"\r\n", b"\n") - - der_certs = [ - base64.b64decode(match.group(1)) for match in _PEM_CERTS_RE.finditer(pem_bundle) - ] - if not der_certs: - raise ssl.SSLError("No root certificates specified") - - cert_array = CoreFoundation.CFArrayCreateMutable( - CoreFoundation.kCFAllocatorDefault, - 0, - ctypes.byref(CoreFoundation.kCFTypeArrayCallBacks), - ) - if not cert_array: - raise ssl.SSLError("Unable to allocate memory!") - - try: - for der_bytes in der_certs: - certdata = _cf_data_from_bytes(der_bytes) - if not certdata: - raise ssl.SSLError("Unable to allocate memory!") - cert = Security.SecCertificateCreateWithData( - CoreFoundation.kCFAllocatorDefault, certdata - ) - CoreFoundation.CFRelease(certdata) - if not cert: - raise ssl.SSLError("Unable to build cert object!") - - CoreFoundation.CFArrayAppendValue(cert_array, cert) - CoreFoundation.CFRelease(cert) - except Exception: - # We need to free the array before the exception bubbles further. - # We only want to do that if an error occurs: otherwise, the caller - # should free. - CoreFoundation.CFRelease(cert_array) - - return cert_array - - -def _is_cert(item): - """ - Returns True if a given CFTypeRef is a certificate. - """ - expected = Security.SecCertificateGetTypeID() - return CoreFoundation.CFGetTypeID(item) == expected - - -def _is_identity(item): - """ - Returns True if a given CFTypeRef is an identity. - """ - expected = Security.SecIdentityGetTypeID() - return CoreFoundation.CFGetTypeID(item) == expected - - -def _temporary_keychain(): - """ - This function creates a temporary Mac keychain that we can use to work with - credentials. This keychain uses a one-time password and a temporary file to - store the data. We expect to have one keychain per socket. The returned - SecKeychainRef must be freed by the caller, including calling - SecKeychainDelete. - - Returns a tuple of the SecKeychainRef and the path to the temporary - directory that contains it. - """ - # Unfortunately, SecKeychainCreate requires a path to a keychain. This - # means we cannot use mkstemp to use a generic temporary file. Instead, - # we're going to create a temporary directory and a filename to use there. - # This filename will be 8 random bytes expanded into base64. We also need - # some random bytes to password-protect the keychain we're creating, so we - # ask for 40 random bytes. - random_bytes = os.urandom(40) - filename = base64.b16encode(random_bytes[:8]).decode("utf-8") - password = base64.b16encode(random_bytes[8:]) # Must be valid UTF-8 - tempdirectory = tempfile.mkdtemp() - - keychain_path = os.path.join(tempdirectory, filename).encode("utf-8") - - # We now want to create the keychain itself. - keychain = Security.SecKeychainRef() - status = Security.SecKeychainCreate( - keychain_path, len(password), password, False, None, ctypes.byref(keychain) - ) - _assert_no_error(status) - - # Having created the keychain, we want to pass it off to the caller. - return keychain, tempdirectory - - -def _load_items_from_file(keychain, path): - """ - Given a single file, loads all the trust objects from it into arrays and - the keychain. - Returns a tuple of lists: the first list is a list of identities, the - second a list of certs. - """ - certificates = [] - identities = [] - result_array = None - - with open(path, "rb") as f: - raw_filedata = f.read() - - try: - filedata = CoreFoundation.CFDataCreate( - CoreFoundation.kCFAllocatorDefault, raw_filedata, len(raw_filedata) - ) - result_array = CoreFoundation.CFArrayRef() - result = Security.SecItemImport( - filedata, # cert data - None, # Filename, leaving it out for now - None, # What the type of the file is, we don't care - None, # what's in the file, we don't care - 0, # import flags - None, # key params, can include passphrase in the future - keychain, # The keychain to insert into - ctypes.byref(result_array), # Results - ) - _assert_no_error(result) - - # A CFArray is not very useful to us as an intermediary - # representation, so we are going to extract the objects we want - # and then free the array. We don't need to keep hold of keys: the - # keychain already has them! - result_count = CoreFoundation.CFArrayGetCount(result_array) - for index in range(result_count): - item = CoreFoundation.CFArrayGetValueAtIndex(result_array, index) - item = ctypes.cast(item, CoreFoundation.CFTypeRef) - - if _is_cert(item): - CoreFoundation.CFRetain(item) - certificates.append(item) - elif _is_identity(item): - CoreFoundation.CFRetain(item) - identities.append(item) - finally: - if result_array: - CoreFoundation.CFRelease(result_array) - - CoreFoundation.CFRelease(filedata) - - return (identities, certificates) - - -def _load_client_cert_chain(keychain, *paths): - """ - Load certificates and maybe keys from a number of files. Has the end goal - of returning a CFArray containing one SecIdentityRef, and then zero or more - SecCertificateRef objects, suitable for use as a client certificate trust - chain. - """ - # Ok, the strategy. - # - # This relies on knowing that macOS will not give you a SecIdentityRef - # unless you have imported a key into a keychain. This is a somewhat - # artificial limitation of macOS (for example, it doesn't necessarily - # affect iOS), but there is nothing inside Security.framework that lets you - # get a SecIdentityRef without having a key in a keychain. - # - # So the policy here is we take all the files and iterate them in order. - # Each one will use SecItemImport to have one or more objects loaded from - # it. We will also point at a keychain that macOS can use to work with the - # private key. - # - # Once we have all the objects, we'll check what we actually have. If we - # already have a SecIdentityRef in hand, fab: we'll use that. Otherwise, - # we'll take the first certificate (which we assume to be our leaf) and - # ask the keychain to give us a SecIdentityRef with that cert's associated - # key. - # - # We'll then return a CFArray containing the trust chain: one - # SecIdentityRef and then zero-or-more SecCertificateRef objects. The - # responsibility for freeing this CFArray will be with the caller. This - # CFArray must remain alive for the entire connection, so in practice it - # will be stored with a single SSLSocket, along with the reference to the - # keychain. - certificates = [] - identities = [] - - # Filter out bad paths. - paths = (path for path in paths if path) - - try: - for file_path in paths: - new_identities, new_certs = _load_items_from_file(keychain, file_path) - identities.extend(new_identities) - certificates.extend(new_certs) - - # Ok, we have everything. The question is: do we have an identity? If - # not, we want to grab one from the first cert we have. - if not identities: - new_identity = Security.SecIdentityRef() - status = Security.SecIdentityCreateWithCertificate( - keychain, certificates[0], ctypes.byref(new_identity) - ) - _assert_no_error(status) - identities.append(new_identity) - - # We now want to release the original certificate, as we no longer - # need it. - CoreFoundation.CFRelease(certificates.pop(0)) - - # We now need to build a new CFArray that holds the trust chain. - trust_chain = CoreFoundation.CFArrayCreateMutable( - CoreFoundation.kCFAllocatorDefault, - 0, - ctypes.byref(CoreFoundation.kCFTypeArrayCallBacks), - ) - for item in itertools.chain(identities, certificates): - # ArrayAppendValue does a CFRetain on the item. That's fine, - # because the finally block will release our other refs to them. - CoreFoundation.CFArrayAppendValue(trust_chain, item) - - return trust_chain - finally: - for obj in itertools.chain(identities, certificates): - CoreFoundation.CFRelease(obj) - - -TLS_PROTOCOL_VERSIONS = { - "SSLv2": (0, 2), - "SSLv3": (3, 0), - "TLSv1": (3, 1), - "TLSv1.1": (3, 2), - "TLSv1.2": (3, 3), -} - - -def _build_tls_unknown_ca_alert(version): - """ - Builds a TLS alert record for an unknown CA. - """ - ver_maj, ver_min = TLS_PROTOCOL_VERSIONS[version] - severity_fatal = 0x02 - description_unknown_ca = 0x30 - msg = struct.pack(">BB", severity_fatal, description_unknown_ca) - msg_len = len(msg) - record_type_alert = 0x15 - record = struct.pack(">BBBH", record_type_alert, ver_maj, ver_min, msg_len) + msg - return record diff --git a/venv/lib/python3.8/site-packages/urllib3/contrib/appengine.py b/venv/lib/python3.8/site-packages/urllib3/contrib/appengine.py deleted file mode 100644 index f91bdd6..0000000 --- a/venv/lib/python3.8/site-packages/urllib3/contrib/appengine.py +++ /dev/null @@ -1,314 +0,0 @@ -""" -This module provides a pool manager that uses Google App Engine's -`URLFetch Service <https://cloud.google.com/appengine/docs/python/urlfetch>`_. - -Example usage:: - - from urllib3 import PoolManager - from urllib3.contrib.appengine import AppEngineManager, is_appengine_sandbox - - if is_appengine_sandbox(): - # AppEngineManager uses AppEngine's URLFetch API behind the scenes - http = AppEngineManager() - else: - # PoolManager uses a socket-level API behind the scenes - http = PoolManager() - - r = http.request('GET', 'https://google.com/') - -There are `limitations <https://cloud.google.com/appengine/docs/python/\ -urlfetch/#Python_Quotas_and_limits>`_ to the URLFetch service and it may not be -the best choice for your application. There are three options for using -urllib3 on Google App Engine: - -1. You can use :class:`AppEngineManager` with URLFetch. URLFetch is - cost-effective in many circumstances as long as your usage is within the - limitations. -2. You can use a normal :class:`~urllib3.PoolManager` by enabling sockets. - Sockets also have `limitations and restrictions - <https://cloud.google.com/appengine/docs/python/sockets/\ - #limitations-and-restrictions>`_ and have a lower free quota than URLFetch. - To use sockets, be sure to specify the following in your ``app.yaml``:: - - env_variables: - GAE_USE_SOCKETS_HTTPLIB : 'true' - -3. If you are using `App Engine Flexible -<https://cloud.google.com/appengine/docs/flexible/>`_, you can use the standard -:class:`PoolManager` without any configuration or special environment variables. -""" - -from __future__ import absolute_import - -import io -import logging -import warnings - -from ..exceptions import ( - HTTPError, - HTTPWarning, - MaxRetryError, - ProtocolError, - SSLError, - TimeoutError, -) -from ..packages.six.moves.urllib.parse import urljoin -from ..request import RequestMethods -from ..response import HTTPResponse -from ..util.retry import Retry -from ..util.timeout import Timeout -from . import _appengine_environ - -try: - from google.appengine.api import urlfetch -except ImportError: - urlfetch = None - - -log = logging.getLogger(__name__) - - -class AppEnginePlatformWarning(HTTPWarning): - pass - - -class AppEnginePlatformError(HTTPError): - pass - - -class AppEngineManager(RequestMethods): - """ - Connection manager for Google App Engine sandbox applications. - - This manager uses the URLFetch service directly instead of using the - emulated httplib, and is subject to URLFetch limitations as described in - the App Engine documentation `here - <https://cloud.google.com/appengine/docs/python/urlfetch>`_. - - Notably it will raise an :class:`AppEnginePlatformError` if: - * URLFetch is not available. - * If you attempt to use this on App Engine Flexible, as full socket - support is available. - * If a request size is more than 10 megabytes. - * If a response size is more than 32 megabytes. - * If you use an unsupported request method such as OPTIONS. - - Beyond those cases, it will raise normal urllib3 errors. - """ - - def __init__( - self, - headers=None, - retries=None, - validate_certificate=True, - urlfetch_retries=True, - ): - if not urlfetch: - raise AppEnginePlatformError( - "URLFetch is not available in this environment." - ) - - warnings.warn( - "urllib3 is using URLFetch on Google App Engine sandbox instead " - "of sockets. To use sockets directly instead of URLFetch see " - "https://urllib3.readthedocs.io/en/1.26.x/reference/urllib3.contrib.html.", - AppEnginePlatformWarning, - ) - - RequestMethods.__init__(self, headers) - self.validate_certificate = validate_certificate - self.urlfetch_retries = urlfetch_retries - - self.retries = retries or Retry.DEFAULT - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_val, exc_tb): - # Return False to re-raise any potential exceptions - return False - - def urlopen( - self, - method, - url, - body=None, - headers=None, - retries=None, - redirect=True, - timeout=Timeout.DEFAULT_TIMEOUT, - **response_kw - ): - - retries = self._get_retries(retries, redirect) - - try: - follow_redirects = redirect and retries.redirect != 0 and retries.total - response = urlfetch.fetch( - url, - payload=body, - method=method, - headers=headers or {}, - allow_truncated=False, - follow_redirects=self.urlfetch_retries and follow_redirects, - deadline=self._get_absolute_timeout(timeout), - validate_certificate=self.validate_certificate, - ) - except urlfetch.DeadlineExceededError as e: - raise TimeoutError(self, e) - - except urlfetch.InvalidURLError as e: - if "too large" in str(e): - raise AppEnginePlatformError( - "URLFetch request too large, URLFetch only " - "supports requests up to 10mb in size.", - e, - ) - raise ProtocolError(e) - - except urlfetch.DownloadError as e: - if "Too many redirects" in str(e): - raise MaxRetryError(self, url, reason=e) - raise ProtocolError(e) - - except urlfetch.ResponseTooLargeError as e: - raise AppEnginePlatformError( - "URLFetch response too large, URLFetch only supports" - "responses up to 32mb in size.", - e, - ) - - except urlfetch.SSLCertificateError as e: - raise SSLError(e) - - except urlfetch.InvalidMethodError as e: - raise AppEnginePlatformError( - "URLFetch does not support method: %s" % method, e - ) - - http_response = self._urlfetch_response_to_http_response( - response, retries=retries, **response_kw - ) - - # Handle redirect? - redirect_location = redirect and http_response.get_redirect_location() - if redirect_location: - # Check for redirect response - if self.urlfetch_retries and retries.raise_on_redirect: - raise MaxRetryError(self, url, "too many redirects") - else: - if http_response.status == 303: - method = "GET" - - try: - retries = retries.increment( - method, url, response=http_response, _pool=self - ) - except MaxRetryError: - if retries.raise_on_redirect: - raise MaxRetryError(self, url, "too many redirects") - return http_response - - retries.sleep_for_retry(http_response) - log.debug("Redirecting %s -> %s", url, redirect_location) - redirect_url = urljoin(url, redirect_location) - return self.urlopen( - method, - redirect_url, - body, - headers, - retries=retries, - redirect=redirect, - timeout=timeout, - **response_kw - ) - - # Check if we should retry the HTTP response. - has_retry_after = bool(http_response.getheader("Retry-After")) - if retries.is_retry(method, http_response.status, has_retry_after): - retries = retries.increment(method, url, response=http_response, _pool=self) - log.debug("Retry: %s", url) - retries.sleep(http_response) - return self.urlopen( - method, - url, - body=body, - headers=headers, - retries=retries, - redirect=redirect, - timeout=timeout, - **response_kw - ) - - return http_response - - def _urlfetch_response_to_http_response(self, urlfetch_resp, **response_kw): - - if is_prod_appengine(): - # Production GAE handles deflate encoding automatically, but does - # not remove the encoding header. - content_encoding = urlfetch_resp.headers.get("content-encoding") - - if content_encoding == "deflate": - del urlfetch_resp.headers["content-encoding"] - - transfer_encoding = urlfetch_resp.headers.get("transfer-encoding") - # We have a full response's content, - # so let's make sure we don't report ourselves as chunked data. - if transfer_encoding == "chunked": - encodings = transfer_encoding.split(",") - encodings.remove("chunked") - urlfetch_resp.headers["transfer-encoding"] = ",".join(encodings) - - original_response = HTTPResponse( - # In order for decoding to work, we must present the content as - # a file-like object. - body=io.BytesIO(urlfetch_resp.content), - msg=urlfetch_resp.header_msg, - headers=urlfetch_resp.headers, - status=urlfetch_resp.status_code, - **response_kw - ) - - return HTTPResponse( - body=io.BytesIO(urlfetch_resp.content), - headers=urlfetch_resp.headers, - status=urlfetch_resp.status_code, - original_response=original_response, - **response_kw - ) - - def _get_absolute_timeout(self, timeout): - if timeout is Timeout.DEFAULT_TIMEOUT: - return None # Defer to URLFetch's default. - if isinstance(timeout, Timeout): - if timeout._read is not None or timeout._connect is not None: - warnings.warn( - "URLFetch does not support granular timeout settings, " - "reverting to total or default URLFetch timeout.", - AppEnginePlatformWarning, - ) - return timeout.total - return timeout - - def _get_retries(self, retries, redirect): - if not isinstance(retries, Retry): - retries = Retry.from_int(retries, redirect=redirect, default=self.retries) - - if retries.connect or retries.read or retries.redirect: - warnings.warn( - "URLFetch only supports total retries and does not " - "recognize connect, read, or redirect retry parameters.", - AppEnginePlatformWarning, - ) - - return retries - - -# Alias methods from _appengine_environ to maintain public API interface. - -is_appengine = _appengine_environ.is_appengine -is_appengine_sandbox = _appengine_environ.is_appengine_sandbox -is_local_appengine = _appengine_environ.is_local_appengine -is_prod_appengine = _appengine_environ.is_prod_appengine -is_prod_appengine_mvms = _appengine_environ.is_prod_appengine_mvms diff --git a/venv/lib/python3.8/site-packages/urllib3/contrib/ntlmpool.py b/venv/lib/python3.8/site-packages/urllib3/contrib/ntlmpool.py deleted file mode 100644 index 41a8fd1..0000000 --- a/venv/lib/python3.8/site-packages/urllib3/contrib/ntlmpool.py +++ /dev/null @@ -1,130 +0,0 @@ -""" -NTLM authenticating pool, contributed by erikcederstran - -Issue #10, see: http://code.google.com/p/urllib3/issues/detail?id=10 -""" -from __future__ import absolute_import - -import warnings -from logging import getLogger - -from ntlm import ntlm - -from .. import HTTPSConnectionPool -from ..packages.six.moves.http_client import HTTPSConnection - -warnings.warn( - "The 'urllib3.contrib.ntlmpool' module is deprecated and will be removed " - "in urllib3 v2.0 release, urllib3 is not able to support it properly due " - "to reasons listed in issue: https://github.com/urllib3/urllib3/issues/2282. " - "If you are a user of this module please comment in the mentioned issue.", - DeprecationWarning, -) - -log = getLogger(__name__) - - -class NTLMConnectionPool(HTTPSConnectionPool): - """ - Implements an NTLM authentication version of an urllib3 connection pool - """ - - scheme = "https" - - def __init__(self, user, pw, authurl, *args, **kwargs): - """ - authurl is a random URL on the server that is protected by NTLM. - user is the Windows user, probably in the DOMAIN\\username format. - pw is the password for the user. - """ - super(NTLMConnectionPool, self).__init__(*args, **kwargs) - self.authurl = authurl - self.rawuser = user - user_parts = user.split("\\", 1) - self.domain = user_parts[0].upper() - self.user = user_parts[1] - self.pw = pw - - def _new_conn(self): - # Performs the NTLM handshake that secures the connection. The socket - # must be kept open while requests are performed. - self.num_connections += 1 - log.debug( - "Starting NTLM HTTPS connection no. %d: https://%s%s", - self.num_connections, - self.host, - self.authurl, - ) - - headers = {"Connection": "Keep-Alive"} - req_header = "Authorization" - resp_header = "www-authenticate" - - conn = HTTPSConnection(host=self.host, port=self.port) - - # Send negotiation message - headers[req_header] = "NTLM %s" % ntlm.create_NTLM_NEGOTIATE_MESSAGE( - self.rawuser - ) - log.debug("Request headers: %s", headers) - conn.request("GET", self.authurl, None, headers) - res = conn.getresponse() - reshdr = dict(res.getheaders()) - log.debug("Response status: %s %s", res.status, res.reason) - log.debug("Response headers: %s", reshdr) - log.debug("Response data: %s [...]", res.read(100)) - - # Remove the reference to the socket, so that it can not be closed by - # the response object (we want to keep the socket open) - res.fp = None - - # Server should respond with a challenge message - auth_header_values = reshdr[resp_header].split(", ") - auth_header_value = None - for s in auth_header_values: - if s[:5] == "NTLM ": - auth_header_value = s[5:] - if auth_header_value is None: - raise Exception( - "Unexpected %s response header: %s" % (resp_header, reshdr[resp_header]) - ) - - # Send authentication message - ServerChallenge, NegotiateFlags = ntlm.parse_NTLM_CHALLENGE_MESSAGE( - auth_header_value - ) - auth_msg = ntlm.create_NTLM_AUTHENTICATE_MESSAGE( - ServerChallenge, self.user, self.domain, self.pw, NegotiateFlags - ) - headers[req_header] = "NTLM %s" % auth_msg - log.debug("Request headers: %s", headers) - conn.request("GET", self.authurl, None, headers) - res = conn.getresponse() - log.debug("Response status: %s %s", res.status, res.reason) - log.debug("Response headers: %s", dict(res.getheaders())) - log.debug("Response data: %s [...]", res.read()[:100]) - if res.status != 200: - if res.status == 401: - raise Exception("Server rejected request: wrong username or password") - raise Exception("Wrong server response: %s %s" % (res.status, res.reason)) - - res.fp = None - log.debug("Connection established") - return conn - - def urlopen( - self, - method, - url, - body=None, - headers=None, - retries=3, - redirect=True, - assert_same_host=True, - ): - if headers is None: - headers = {} - headers["Connection"] = "Keep-Alive" - return super(NTLMConnectionPool, self).urlopen( - method, url, body, headers, retries, redirect, assert_same_host - ) diff --git a/venv/lib/python3.8/site-packages/urllib3/contrib/pyopenssl.py b/venv/lib/python3.8/site-packages/urllib3/contrib/pyopenssl.py deleted file mode 100644 index def83af..0000000 --- a/venv/lib/python3.8/site-packages/urllib3/contrib/pyopenssl.py +++ /dev/null @@ -1,511 +0,0 @@ -""" -TLS with SNI_-support for Python 2. Follow these instructions if you would -like to verify TLS certificates in Python 2. Note, the default libraries do -*not* do certificate checking; you need to do additional work to validate -certificates yourself. - -This needs the following packages installed: - -* `pyOpenSSL`_ (tested with 16.0.0) -* `cryptography`_ (minimum 1.3.4, from pyopenssl) -* `idna`_ (minimum 2.0, from cryptography) - -However, pyopenssl depends on cryptography, which depends on idna, so while we -use all three directly here we end up having relatively few packages required. - -You can install them with the following command: - -.. code-block:: bash - - $ python -m pip install pyopenssl cryptography idna - -To activate certificate checking, call -:func:`~urllib3.contrib.pyopenssl.inject_into_urllib3` from your Python code -before you begin making HTTP requests. This can be done in a ``sitecustomize`` -module, or at any other time before your application begins using ``urllib3``, -like this: - -.. code-block:: python - - try: - import urllib3.contrib.pyopenssl - urllib3.contrib.pyopenssl.inject_into_urllib3() - except ImportError: - pass - -Now you can use :mod:`urllib3` as you normally would, and it will support SNI -when the required modules are installed. - -Activating this module also has the positive side effect of disabling SSL/TLS -compression in Python 2 (see `CRIME attack`_). - -.. _sni: https://en.wikipedia.org/wiki/Server_Name_Indication -.. _crime attack: https://en.wikipedia.org/wiki/CRIME_(security_exploit) -.. _pyopenssl: https://www.pyopenssl.org -.. _cryptography: https://cryptography.io -.. _idna: https://github.com/kjd/idna -""" -from __future__ import absolute_import - -import OpenSSL.SSL -from cryptography import x509 -from cryptography.hazmat.backends.openssl import backend as openssl_backend -from cryptography.hazmat.backends.openssl.x509 import _Certificate - -try: - from cryptography.x509 import UnsupportedExtension -except ImportError: - # UnsupportedExtension is gone in cryptography >= 2.1.0 - class UnsupportedExtension(Exception): - pass - - -from io import BytesIO -from socket import error as SocketError -from socket import timeout - -try: # Platform-specific: Python 2 - from socket import _fileobject -except ImportError: # Platform-specific: Python 3 - _fileobject = None - from ..packages.backports.makefile import backport_makefile - -import logging -import ssl -import sys - -from .. import util -from ..packages import six -from ..util.ssl_ import PROTOCOL_TLS_CLIENT - -__all__ = ["inject_into_urllib3", "extract_from_urllib3"] - -# SNI always works. -HAS_SNI = True - -# Map from urllib3 to PyOpenSSL compatible parameter-values. -_openssl_versions = { - util.PROTOCOL_TLS: OpenSSL.SSL.SSLv23_METHOD, - PROTOCOL_TLS_CLIENT: OpenSSL.SSL.SSLv23_METHOD, - ssl.PROTOCOL_TLSv1: OpenSSL.SSL.TLSv1_METHOD, -} - -if hasattr(ssl, "PROTOCOL_SSLv3") and hasattr(OpenSSL.SSL, "SSLv3_METHOD"): - _openssl_versions[ssl.PROTOCOL_SSLv3] = OpenSSL.SSL.SSLv3_METHOD - -if hasattr(ssl, "PROTOCOL_TLSv1_1") and hasattr(OpenSSL.SSL, "TLSv1_1_METHOD"): - _openssl_versions[ssl.PROTOCOL_TLSv1_1] = OpenSSL.SSL.TLSv1_1_METHOD - -if hasattr(ssl, "PROTOCOL_TLSv1_2") and hasattr(OpenSSL.SSL, "TLSv1_2_METHOD"): - _openssl_versions[ssl.PROTOCOL_TLSv1_2] = OpenSSL.SSL.TLSv1_2_METHOD - - -_stdlib_to_openssl_verify = { - ssl.CERT_NONE: OpenSSL.SSL.VERIFY_NONE, - ssl.CERT_OPTIONAL: OpenSSL.SSL.VERIFY_PEER, - ssl.CERT_REQUIRED: OpenSSL.SSL.VERIFY_PEER - + OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT, -} -_openssl_to_stdlib_verify = dict((v, k) for k, v in _stdlib_to_openssl_verify.items()) - -# OpenSSL will only write 16K at a time -SSL_WRITE_BLOCKSIZE = 16384 - -orig_util_HAS_SNI = util.HAS_SNI -orig_util_SSLContext = util.ssl_.SSLContext - - -log = logging.getLogger(__name__) - - -def inject_into_urllib3(): - "Monkey-patch urllib3 with PyOpenSSL-backed SSL-support." - - _validate_dependencies_met() - - util.SSLContext = PyOpenSSLContext - util.ssl_.SSLContext = PyOpenSSLContext - util.HAS_SNI = HAS_SNI - util.ssl_.HAS_SNI = HAS_SNI - util.IS_PYOPENSSL = True - util.ssl_.IS_PYOPENSSL = True - - -def extract_from_urllib3(): - "Undo monkey-patching by :func:`inject_into_urllib3`." - - util.SSLContext = orig_util_SSLContext - util.ssl_.SSLContext = orig_util_SSLContext - util.HAS_SNI = orig_util_HAS_SNI - util.ssl_.HAS_SNI = orig_util_HAS_SNI - util.IS_PYOPENSSL = False - util.ssl_.IS_PYOPENSSL = False - - -def _validate_dependencies_met(): - """ - Verifies that PyOpenSSL's package-level dependencies have been met. - Throws `ImportError` if they are not met. - """ - # Method added in `cryptography==1.1`; not available in older versions - from cryptography.x509.extensions import Extensions - - if getattr(Extensions, "get_extension_for_class", None) is None: - raise ImportError( - "'cryptography' module missing required functionality. " - "Try upgrading to v1.3.4 or newer." - ) - - # pyOpenSSL 0.14 and above use cryptography for OpenSSL bindings. The _x509 - # attribute is only present on those versions. - from OpenSSL.crypto import X509 - - x509 = X509() - if getattr(x509, "_x509", None) is None: - raise ImportError( - "'pyOpenSSL' module missing required functionality. " - "Try upgrading to v0.14 or newer." - ) - - -def _dnsname_to_stdlib(name): - """ - Converts a dNSName SubjectAlternativeName field to the form used by the - standard library on the given Python version. - - Cryptography produces a dNSName as a unicode string that was idna-decoded - from ASCII bytes. We need to idna-encode that string to get it back, and - then on Python 3 we also need to convert to unicode via UTF-8 (the stdlib - uses PyUnicode_FromStringAndSize on it, which decodes via UTF-8). - - If the name cannot be idna-encoded then we return None signalling that - the name given should be skipped. - """ - - def idna_encode(name): - """ - Borrowed wholesale from the Python Cryptography Project. It turns out - that we can't just safely call `idna.encode`: it can explode for - wildcard names. This avoids that problem. - """ - import idna - - try: - for prefix in [u"*.", u"."]: - if name.startswith(prefix): - name = name[len(prefix) :] - return prefix.encode("ascii") + idna.encode(name) - return idna.encode(name) - except idna.core.IDNAError: - return None - - # Don't send IPv6 addresses through the IDNA encoder. - if ":" in name: - return name - - name = idna_encode(name) - if name is None: - return None - elif sys.version_info >= (3, 0): - name = name.decode("utf-8") - return name - - -def get_subj_alt_name(peer_cert): - """ - Given an PyOpenSSL certificate, provides all the subject alternative names. - """ - # Pass the cert to cryptography, which has much better APIs for this. - if hasattr(peer_cert, "to_cryptography"): - cert = peer_cert.to_cryptography() - else: - # This is technically using private APIs, but should work across all - # relevant versions before PyOpenSSL got a proper API for this. - cert = _Certificate(openssl_backend, peer_cert._x509) - - # We want to find the SAN extension. Ask Cryptography to locate it (it's - # faster than looping in Python) - try: - ext = cert.extensions.get_extension_for_class(x509.SubjectAlternativeName).value - except x509.ExtensionNotFound: - # No such extension, return the empty list. - return [] - except ( - x509.DuplicateExtension, - UnsupportedExtension, - x509.UnsupportedGeneralNameType, - UnicodeError, - ) as e: - # A problem has been found with the quality of the certificate. Assume - # no SAN field is present. - log.warning( - "A problem was encountered with the certificate that prevented " - "urllib3 from finding the SubjectAlternativeName field. This can " - "affect certificate validation. The error was %s", - e, - ) - return [] - - # We want to return dNSName and iPAddress fields. We need to cast the IPs - # back to strings because the match_hostname function wants them as - # strings. - # Sadly the DNS names need to be idna encoded and then, on Python 3, UTF-8 - # decoded. This is pretty frustrating, but that's what the standard library - # does with certificates, and so we need to attempt to do the same. - # We also want to skip over names which cannot be idna encoded. - names = [ - ("DNS", name) - for name in map(_dnsname_to_stdlib, ext.get_values_for_type(x509.DNSName)) - if name is not None - ] - names.extend( - ("IP Address", str(name)) for name in ext.get_values_for_type(x509.IPAddress) - ) - - return names - - -class WrappedSocket(object): - """API-compatibility wrapper for Python OpenSSL's Connection-class. - - Note: _makefile_refs, _drop() and _reuse() are needed for the garbage - collector of pypy. - """ - - def __init__(self, connection, socket, suppress_ragged_eofs=True): - self.connection = connection - self.socket = socket - self.suppress_ragged_eofs = suppress_ragged_eofs - self._makefile_refs = 0 - self._closed = False - - def fileno(self): - return self.socket.fileno() - - # Copy-pasted from Python 3.5 source code - def _decref_socketios(self): - if self._makefile_refs > 0: - self._makefile_refs -= 1 - if self._closed: - self.close() - - def recv(self, *args, **kwargs): - try: - data = self.connection.recv(*args, **kwargs) - except OpenSSL.SSL.SysCallError as e: - if self.suppress_ragged_eofs and e.args == (-1, "Unexpected EOF"): - return b"" - else: - raise SocketError(str(e)) - except OpenSSL.SSL.ZeroReturnError: - if self.connection.get_shutdown() == OpenSSL.SSL.RECEIVED_SHUTDOWN: - return b"" - else: - raise - except OpenSSL.SSL.WantReadError: - if not util.wait_for_read(self.socket, self.socket.gettimeout()): - raise timeout("The read operation timed out") - else: - return self.recv(*args, **kwargs) - - # TLS 1.3 post-handshake authentication - except OpenSSL.SSL.Error as e: - raise ssl.SSLError("read error: %r" % e) - else: - return data - - def recv_into(self, *args, **kwargs): - try: - return self.connection.recv_into(*args, **kwargs) - except OpenSSL.SSL.SysCallError as e: - if self.suppress_ragged_eofs and e.args == (-1, "Unexpected EOF"): - return 0 - else: - raise SocketError(str(e)) - except OpenSSL.SSL.ZeroReturnError: - if self.connection.get_shutdown() == OpenSSL.SSL.RECEIVED_SHUTDOWN: - return 0 - else: - raise - except OpenSSL.SSL.WantReadError: - if not util.wait_for_read(self.socket, self.socket.gettimeout()): - raise timeout("The read operation timed out") - else: - return self.recv_into(*args, **kwargs) - - # TLS 1.3 post-handshake authentication - except OpenSSL.SSL.Error as e: - raise ssl.SSLError("read error: %r" % e) - - def settimeout(self, timeout): - return self.socket.settimeout(timeout) - - def _send_until_done(self, data): - while True: - try: - return self.connection.send(data) - except OpenSSL.SSL.WantWriteError: - if not util.wait_for_write(self.socket, self.socket.gettimeout()): - raise timeout() - continue - except OpenSSL.SSL.SysCallError as e: - raise SocketError(str(e)) - - def sendall(self, data): - total_sent = 0 - while total_sent < len(data): - sent = self._send_until_done( - data[total_sent : total_sent + SSL_WRITE_BLOCKSIZE] - ) - total_sent += sent - - def shutdown(self): - # FIXME rethrow compatible exceptions should we ever use this - self.connection.shutdown() - - def close(self): - if self._makefile_refs < 1: - try: - self._closed = True - return self.connection.close() - except OpenSSL.SSL.Error: - return - else: - self._makefile_refs -= 1 - - def getpeercert(self, binary_form=False): - x509 = self.connection.get_peer_certificate() - - if not x509: - return x509 - - if binary_form: - return OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_ASN1, x509) - - return { - "subject": ((("commonName", x509.get_subject().CN),),), - "subjectAltName": get_subj_alt_name(x509), - } - - def version(self): - return self.connection.get_protocol_version_name() - - def _reuse(self): - self._makefile_refs += 1 - - def _drop(self): - if self._makefile_refs < 1: - self.close() - else: - self._makefile_refs -= 1 - - -if _fileobject: # Platform-specific: Python 2 - - def makefile(self, mode, bufsize=-1): - self._makefile_refs += 1 - return _fileobject(self, mode, bufsize, close=True) - - -else: # Platform-specific: Python 3 - makefile = backport_makefile - -WrappedSocket.makefile = makefile - - -class PyOpenSSLContext(object): - """ - I am a wrapper class for the PyOpenSSL ``Context`` object. I am responsible - for translating the interface of the standard library ``SSLContext`` object - to calls into PyOpenSSL. - """ - - def __init__(self, protocol): - self.protocol = _openssl_versions[protocol] - self._ctx = OpenSSL.SSL.Context(self.protocol) - self._options = 0 - self.check_hostname = False - - @property - def options(self): - return self._options - - @options.setter - def options(self, value): - self._options = value - self._ctx.set_options(value) - - @property - def verify_mode(self): - return _openssl_to_stdlib_verify[self._ctx.get_verify_mode()] - - @verify_mode.setter - def verify_mode(self, value): - self._ctx.set_verify(_stdlib_to_openssl_verify[value], _verify_callback) - - def set_default_verify_paths(self): - self._ctx.set_default_verify_paths() - - def set_ciphers(self, ciphers): - if isinstance(ciphers, six.text_type): - ciphers = ciphers.encode("utf-8") - self._ctx.set_cipher_list(ciphers) - - def load_verify_locations(self, cafile=None, capath=None, cadata=None): - if cafile is not None: - cafile = cafile.encode("utf-8") - if capath is not None: - capath = capath.encode("utf-8") - try: - self._ctx.load_verify_locations(cafile, capath) - if cadata is not None: - self._ctx.load_verify_locations(BytesIO(cadata)) - except OpenSSL.SSL.Error as e: - raise ssl.SSLError("unable to load trusted certificates: %r" % e) - - def load_cert_chain(self, certfile, keyfile=None, password=None): - self._ctx.use_certificate_chain_file(certfile) - if password is not None: - if not isinstance(password, six.binary_type): - password = password.encode("utf-8") - self._ctx.set_passwd_cb(lambda *_: password) - self._ctx.use_privatekey_file(keyfile or certfile) - - def set_alpn_protocols(self, protocols): - protocols = [six.ensure_binary(p) for p in protocols] - return self._ctx.set_alpn_protos(protocols) - - def wrap_socket( - self, - sock, - server_side=False, - do_handshake_on_connect=True, - suppress_ragged_eofs=True, - server_hostname=None, - ): - cnx = OpenSSL.SSL.Connection(self._ctx, sock) - - if isinstance(server_hostname, six.text_type): # Platform-specific: Python 3 - server_hostname = server_hostname.encode("utf-8") - - if server_hostname is not None: - cnx.set_tlsext_host_name(server_hostname) - - cnx.set_connect_state() - - while True: - try: - cnx.do_handshake() - except OpenSSL.SSL.WantReadError: - if not util.wait_for_read(sock, sock.gettimeout()): - raise timeout("select timed out") - continue - except OpenSSL.SSL.Error as e: - raise ssl.SSLError("bad handshake: %r" % e) - break - - return WrappedSocket(cnx, sock) - - -def _verify_callback(cnx, x509, err_no, err_depth, return_code): - return err_no == 0 diff --git a/venv/lib/python3.8/site-packages/urllib3/contrib/securetransport.py b/venv/lib/python3.8/site-packages/urllib3/contrib/securetransport.py deleted file mode 100644 index 554c015..0000000 --- a/venv/lib/python3.8/site-packages/urllib3/contrib/securetransport.py +++ /dev/null @@ -1,922 +0,0 @@ -""" -SecureTranport support for urllib3 via ctypes. - -This makes platform-native TLS available to urllib3 users on macOS without the -use of a compiler. This is an important feature because the Python Package -Index is moving to become a TLSv1.2-or-higher server, and the default OpenSSL -that ships with macOS is not capable of doing TLSv1.2. The only way to resolve -this is to give macOS users an alternative solution to the problem, and that -solution is to use SecureTransport. - -We use ctypes here because this solution must not require a compiler. That's -because pip is not allowed to require a compiler either. - -This is not intended to be a seriously long-term solution to this problem. -The hope is that PEP 543 will eventually solve this issue for us, at which -point we can retire this contrib module. But in the short term, we need to -solve the impending tire fire that is Python on Mac without this kind of -contrib module. So...here we are. - -To use this module, simply import and inject it:: - - import urllib3.contrib.securetransport - urllib3.contrib.securetransport.inject_into_urllib3() - -Happy TLSing! - -This code is a bastardised version of the code found in Will Bond's oscrypto -library. An enormous debt is owed to him for blazing this trail for us. For -that reason, this code should be considered to be covered both by urllib3's -license and by oscrypto's: - -.. code-block:: - - Copyright (c) 2015-2016 Will Bond <will@wbond.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. -""" -from __future__ import absolute_import - -import contextlib -import ctypes -import errno -import os.path -import shutil -import socket -import ssl -import struct -import threading -import weakref - -import six - -from .. import util -from ..util.ssl_ import PROTOCOL_TLS_CLIENT -from ._securetransport.bindings import CoreFoundation, Security, SecurityConst -from ._securetransport.low_level import ( - _assert_no_error, - _build_tls_unknown_ca_alert, - _cert_array_from_pem, - _create_cfstring_array, - _load_client_cert_chain, - _temporary_keychain, -) - -try: # Platform-specific: Python 2 - from socket import _fileobject -except ImportError: # Platform-specific: Python 3 - _fileobject = None - from ..packages.backports.makefile import backport_makefile - -__all__ = ["inject_into_urllib3", "extract_from_urllib3"] - -# SNI always works -HAS_SNI = True - -orig_util_HAS_SNI = util.HAS_SNI -orig_util_SSLContext = util.ssl_.SSLContext - -# This dictionary is used by the read callback to obtain a handle to the -# calling wrapped socket. This is a pretty silly approach, but for now it'll -# do. I feel like I should be able to smuggle a handle to the wrapped socket -# directly in the SSLConnectionRef, but for now this approach will work I -# guess. -# -# We need to lock around this structure for inserts, but we don't do it for -# reads/writes in the callbacks. The reasoning here goes as follows: -# -# 1. It is not possible to call into the callbacks before the dictionary is -# populated, so once in the callback the id must be in the dictionary. -# 2. The callbacks don't mutate the dictionary, they only read from it, and -# so cannot conflict with any of the insertions. -# -# This is good: if we had to lock in the callbacks we'd drastically slow down -# the performance of this code. -_connection_refs = weakref.WeakValueDictionary() -_connection_ref_lock = threading.Lock() - -# Limit writes to 16kB. This is OpenSSL's limit, but we'll cargo-cult it over -# for no better reason than we need *a* limit, and this one is right there. -SSL_WRITE_BLOCKSIZE = 16384 - -# This is our equivalent of util.ssl_.DEFAULT_CIPHERS, but expanded out to -# individual cipher suites. We need to do this because this is how -# SecureTransport wants them. -CIPHER_SUITES = [ - SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, - SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, - SecurityConst.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, - SecurityConst.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, - SecurityConst.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, - SecurityConst.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, - SecurityConst.TLS_DHE_RSA_WITH_AES_256_GCM_SHA384, - SecurityConst.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, - SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384, - SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, - SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, - SecurityConst.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, - SecurityConst.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384, - SecurityConst.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, - SecurityConst.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, - SecurityConst.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, - SecurityConst.TLS_DHE_RSA_WITH_AES_256_CBC_SHA256, - SecurityConst.TLS_DHE_RSA_WITH_AES_256_CBC_SHA, - SecurityConst.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, - SecurityConst.TLS_DHE_RSA_WITH_AES_128_CBC_SHA, - SecurityConst.TLS_AES_256_GCM_SHA384, - SecurityConst.TLS_AES_128_GCM_SHA256, - SecurityConst.TLS_RSA_WITH_AES_256_GCM_SHA384, - SecurityConst.TLS_RSA_WITH_AES_128_GCM_SHA256, - SecurityConst.TLS_AES_128_CCM_8_SHA256, - SecurityConst.TLS_AES_128_CCM_SHA256, - SecurityConst.TLS_RSA_WITH_AES_256_CBC_SHA256, - SecurityConst.TLS_RSA_WITH_AES_128_CBC_SHA256, - SecurityConst.TLS_RSA_WITH_AES_256_CBC_SHA, - SecurityConst.TLS_RSA_WITH_AES_128_CBC_SHA, -] - -# Basically this is simple: for PROTOCOL_SSLv23 we turn it into a low of -# TLSv1 and a high of TLSv1.2. For everything else, we pin to that version. -# TLSv1 to 1.2 are supported on macOS 10.8+ -_protocol_to_min_max = { - util.PROTOCOL_TLS: (SecurityConst.kTLSProtocol1, SecurityConst.kTLSProtocol12), - PROTOCOL_TLS_CLIENT: (SecurityConst.kTLSProtocol1, SecurityConst.kTLSProtocol12), -} - -if hasattr(ssl, "PROTOCOL_SSLv2"): - _protocol_to_min_max[ssl.PROTOCOL_SSLv2] = ( - SecurityConst.kSSLProtocol2, - SecurityConst.kSSLProtocol2, - ) -if hasattr(ssl, "PROTOCOL_SSLv3"): - _protocol_to_min_max[ssl.PROTOCOL_SSLv3] = ( - SecurityConst.kSSLProtocol3, - SecurityConst.kSSLProtocol3, - ) -if hasattr(ssl, "PROTOCOL_TLSv1"): - _protocol_to_min_max[ssl.PROTOCOL_TLSv1] = ( - SecurityConst.kTLSProtocol1, - SecurityConst.kTLSProtocol1, - ) -if hasattr(ssl, "PROTOCOL_TLSv1_1"): - _protocol_to_min_max[ssl.PROTOCOL_TLSv1_1] = ( - SecurityConst.kTLSProtocol11, - SecurityConst.kTLSProtocol11, - ) -if hasattr(ssl, "PROTOCOL_TLSv1_2"): - _protocol_to_min_max[ssl.PROTOCOL_TLSv1_2] = ( - SecurityConst.kTLSProtocol12, - SecurityConst.kTLSProtocol12, - ) - - -def inject_into_urllib3(): - """ - Monkey-patch urllib3 with SecureTransport-backed SSL-support. - """ - util.SSLContext = SecureTransportContext - util.ssl_.SSLContext = SecureTransportContext - util.HAS_SNI = HAS_SNI - util.ssl_.HAS_SNI = HAS_SNI - util.IS_SECURETRANSPORT = True - util.ssl_.IS_SECURETRANSPORT = True - - -def extract_from_urllib3(): - """ - Undo monkey-patching by :func:`inject_into_urllib3`. - """ - util.SSLContext = orig_util_SSLContext - util.ssl_.SSLContext = orig_util_SSLContext - util.HAS_SNI = orig_util_HAS_SNI - util.ssl_.HAS_SNI = orig_util_HAS_SNI - util.IS_SECURETRANSPORT = False - util.ssl_.IS_SECURETRANSPORT = False - - -def _read_callback(connection_id, data_buffer, data_length_pointer): - """ - SecureTransport read callback. This is called by ST to request that data - be returned from the socket. - """ - wrapped_socket = None - try: - wrapped_socket = _connection_refs.get(connection_id) - if wrapped_socket is None: - return SecurityConst.errSSLInternal - base_socket = wrapped_socket.socket - - requested_length = data_length_pointer[0] - - timeout = wrapped_socket.gettimeout() - error = None - read_count = 0 - - try: - while read_count < requested_length: - if timeout is None or timeout >= 0: - if not util.wait_for_read(base_socket, timeout): - raise socket.error(errno.EAGAIN, "timed out") - - remaining = requested_length - read_count - buffer = (ctypes.c_char * remaining).from_address( - data_buffer + read_count - ) - chunk_size = base_socket.recv_into(buffer, remaining) - read_count += chunk_size - if not chunk_size: - if not read_count: - return SecurityConst.errSSLClosedGraceful - break - except (socket.error) as e: - error = e.errno - - if error is not None and error != errno.EAGAIN: - data_length_pointer[0] = read_count - if error == errno.ECONNRESET or error == errno.EPIPE: - return SecurityConst.errSSLClosedAbort - raise - - data_length_pointer[0] = read_count - - if read_count != requested_length: - return SecurityConst.errSSLWouldBlock - - return 0 - except Exception as e: - if wrapped_socket is not None: - wrapped_socket._exception = e - return SecurityConst.errSSLInternal - - -def _write_callback(connection_id, data_buffer, data_length_pointer): - """ - SecureTransport write callback. This is called by ST to request that data - actually be sent on the network. - """ - wrapped_socket = None - try: - wrapped_socket = _connection_refs.get(connection_id) - if wrapped_socket is None: - return SecurityConst.errSSLInternal - base_socket = wrapped_socket.socket - - bytes_to_write = data_length_pointer[0] - data = ctypes.string_at(data_buffer, bytes_to_write) - - timeout = wrapped_socket.gettimeout() - error = None - sent = 0 - - try: - while sent < bytes_to_write: - if timeout is None or timeout >= 0: - if not util.wait_for_write(base_socket, timeout): - raise socket.error(errno.EAGAIN, "timed out") - chunk_sent = base_socket.send(data) - sent += chunk_sent - - # This has some needless copying here, but I'm not sure there's - # much value in optimising this data path. - data = data[chunk_sent:] - except (socket.error) as e: - error = e.errno - - if error is not None and error != errno.EAGAIN: - data_length_pointer[0] = sent - if error == errno.ECONNRESET or error == errno.EPIPE: - return SecurityConst.errSSLClosedAbort - raise - - data_length_pointer[0] = sent - - if sent != bytes_to_write: - return SecurityConst.errSSLWouldBlock - - return 0 - except Exception as e: - if wrapped_socket is not None: - wrapped_socket._exception = e - return SecurityConst.errSSLInternal - - -# We need to keep these two objects references alive: if they get GC'd while -# in use then SecureTransport could attempt to call a function that is in freed -# memory. That would be...uh...bad. Yeah, that's the word. Bad. -_read_callback_pointer = Security.SSLReadFunc(_read_callback) -_write_callback_pointer = Security.SSLWriteFunc(_write_callback) - - -class WrappedSocket(object): - """ - API-compatibility wrapper for Python's OpenSSL wrapped socket object. - - Note: _makefile_refs, _drop(), and _reuse() are needed for the garbage - collector of PyPy. - """ - - def __init__(self, socket): - self.socket = socket - self.context = None - self._makefile_refs = 0 - self._closed = False - self._exception = None - self._keychain = None - self._keychain_dir = None - self._client_cert_chain = None - - # We save off the previously-configured timeout and then set it to - # zero. This is done because we use select and friends to handle the - # timeouts, but if we leave the timeout set on the lower socket then - # Python will "kindly" call select on that socket again for us. Avoid - # that by forcing the timeout to zero. - self._timeout = self.socket.gettimeout() - self.socket.settimeout(0) - - @contextlib.contextmanager - def _raise_on_error(self): - """ - A context manager that can be used to wrap calls that do I/O from - SecureTransport. If any of the I/O callbacks hit an exception, this - context manager will correctly propagate the exception after the fact. - This avoids silently swallowing those exceptions. - - It also correctly forces the socket closed. - """ - self._exception = None - - # We explicitly don't catch around this yield because in the unlikely - # event that an exception was hit in the block we don't want to swallow - # it. - yield - if self._exception is not None: - exception, self._exception = self._exception, None - self.close() - raise exception - - def _set_ciphers(self): - """ - Sets up the allowed ciphers. By default this matches the set in - util.ssl_.DEFAULT_CIPHERS, at least as supported by macOS. This is done - custom and doesn't allow changing at this time, mostly because parsing - OpenSSL cipher strings is going to be a freaking nightmare. - """ - ciphers = (Security.SSLCipherSuite * len(CIPHER_SUITES))(*CIPHER_SUITES) - result = Security.SSLSetEnabledCiphers( - self.context, ciphers, len(CIPHER_SUITES) - ) - _assert_no_error(result) - - def _set_alpn_protocols(self, protocols): - """ - Sets up the ALPN protocols on the context. - """ - if not protocols: - return - protocols_arr = _create_cfstring_array(protocols) - try: - result = Security.SSLSetALPNProtocols(self.context, protocols_arr) - _assert_no_error(result) - finally: - CoreFoundation.CFRelease(protocols_arr) - - def _custom_validate(self, verify, trust_bundle): - """ - Called when we have set custom validation. We do this in two cases: - first, when cert validation is entirely disabled; and second, when - using a custom trust DB. - Raises an SSLError if the connection is not trusted. - """ - # If we disabled cert validation, just say: cool. - if not verify: - return - - successes = ( - SecurityConst.kSecTrustResultUnspecified, - SecurityConst.kSecTrustResultProceed, - ) - try: - trust_result = self._evaluate_trust(trust_bundle) - if trust_result in successes: - return - reason = "error code: %d" % (trust_result,) - except Exception as e: - # Do not trust on error - reason = "exception: %r" % (e,) - - # SecureTransport does not send an alert nor shuts down the connection. - rec = _build_tls_unknown_ca_alert(self.version()) - self.socket.sendall(rec) - # close the connection immediately - # l_onoff = 1, activate linger - # l_linger = 0, linger for 0 seoncds - opts = struct.pack("ii", 1, 0) - self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, opts) - self.close() - raise ssl.SSLError("certificate verify failed, %s" % reason) - - def _evaluate_trust(self, trust_bundle): - # We want data in memory, so load it up. - if os.path.isfile(trust_bundle): - with open(trust_bundle, "rb") as f: - trust_bundle = f.read() - - cert_array = None - trust = Security.SecTrustRef() - - try: - # Get a CFArray that contains the certs we want. - cert_array = _cert_array_from_pem(trust_bundle) - - # Ok, now the hard part. We want to get the SecTrustRef that ST has - # created for this connection, shove our CAs into it, tell ST to - # ignore everything else it knows, and then ask if it can build a - # chain. This is a buuuunch of code. - result = Security.SSLCopyPeerTrust(self.context, ctypes.byref(trust)) - _assert_no_error(result) - if not trust: - raise ssl.SSLError("Failed to copy trust reference") - - result = Security.SecTrustSetAnchorCertificates(trust, cert_array) - _assert_no_error(result) - - result = Security.SecTrustSetAnchorCertificatesOnly(trust, True) - _assert_no_error(result) - - trust_result = Security.SecTrustResultType() - result = Security.SecTrustEvaluate(trust, ctypes.byref(trust_result)) - _assert_no_error(result) - finally: - if trust: - CoreFoundation.CFRelease(trust) - - if cert_array is not None: - CoreFoundation.CFRelease(cert_array) - - return trust_result.value - - def handshake( - self, - server_hostname, - verify, - trust_bundle, - min_version, - max_version, - client_cert, - client_key, - client_key_passphrase, - alpn_protocols, - ): - """ - Actually performs the TLS handshake. This is run automatically by - wrapped socket, and shouldn't be needed in user code. - """ - # First, we do the initial bits of connection setup. We need to create - # a context, set its I/O funcs, and set the connection reference. - self.context = Security.SSLCreateContext( - None, SecurityConst.kSSLClientSide, SecurityConst.kSSLStreamType - ) - result = Security.SSLSetIOFuncs( - self.context, _read_callback_pointer, _write_callback_pointer - ) - _assert_no_error(result) - - # Here we need to compute the handle to use. We do this by taking the - # id of self modulo 2**31 - 1. If this is already in the dictionary, we - # just keep incrementing by one until we find a free space. - with _connection_ref_lock: - handle = id(self) % 2147483647 - while handle in _connection_refs: - handle = (handle + 1) % 2147483647 - _connection_refs[handle] = self - - result = Security.SSLSetConnection(self.context, handle) - _assert_no_error(result) - - # If we have a server hostname, we should set that too. - if server_hostname: - if not isinstance(server_hostname, bytes): - server_hostname = server_hostname.encode("utf-8") - - result = Security.SSLSetPeerDomainName( - self.context, server_hostname, len(server_hostname) - ) - _assert_no_error(result) - - # Setup the ciphers. - self._set_ciphers() - - # Setup the ALPN protocols. - self._set_alpn_protocols(alpn_protocols) - - # Set the minimum and maximum TLS versions. - result = Security.SSLSetProtocolVersionMin(self.context, min_version) - _assert_no_error(result) - - result = Security.SSLSetProtocolVersionMax(self.context, max_version) - _assert_no_error(result) - - # If there's a trust DB, we need to use it. We do that by telling - # SecureTransport to break on server auth. We also do that if we don't - # want to validate the certs at all: we just won't actually do any - # authing in that case. - if not verify or trust_bundle is not None: - result = Security.SSLSetSessionOption( - self.context, SecurityConst.kSSLSessionOptionBreakOnServerAuth, True - ) - _assert_no_error(result) - - # If there's a client cert, we need to use it. - if client_cert: - self._keychain, self._keychain_dir = _temporary_keychain() - self._client_cert_chain = _load_client_cert_chain( - self._keychain, client_cert, client_key - ) - result = Security.SSLSetCertificate(self.context, self._client_cert_chain) - _assert_no_error(result) - - while True: - with self._raise_on_error(): - result = Security.SSLHandshake(self.context) - - if result == SecurityConst.errSSLWouldBlock: - raise socket.timeout("handshake timed out") - elif result == SecurityConst.errSSLServerAuthCompleted: - self._custom_validate(verify, trust_bundle) - continue - else: - _assert_no_error(result) - break - - def fileno(self): - return self.socket.fileno() - - # Copy-pasted from Python 3.5 source code - def _decref_socketios(self): - if self._makefile_refs > 0: - self._makefile_refs -= 1 - if self._closed: - self.close() - - def recv(self, bufsiz): - buffer = ctypes.create_string_buffer(bufsiz) - bytes_read = self.recv_into(buffer, bufsiz) - data = buffer[:bytes_read] - return data - - def recv_into(self, buffer, nbytes=None): - # Read short on EOF. - if self._closed: - return 0 - - if nbytes is None: - nbytes = len(buffer) - - buffer = (ctypes.c_char * nbytes).from_buffer(buffer) - processed_bytes = ctypes.c_size_t(0) - - with self._raise_on_error(): - result = Security.SSLRead( - self.context, buffer, nbytes, ctypes.byref(processed_bytes) - ) - - # There are some result codes that we want to treat as "not always - # errors". Specifically, those are errSSLWouldBlock, - # errSSLClosedGraceful, and errSSLClosedNoNotify. - if result == SecurityConst.errSSLWouldBlock: - # If we didn't process any bytes, then this was just a time out. - # However, we can get errSSLWouldBlock in situations when we *did* - # read some data, and in those cases we should just read "short" - # and return. - if processed_bytes.value == 0: - # Timed out, no data read. - raise socket.timeout("recv timed out") - elif result in ( - SecurityConst.errSSLClosedGraceful, - SecurityConst.errSSLClosedNoNotify, - ): - # The remote peer has closed this connection. We should do so as - # well. Note that we don't actually return here because in - # principle this could actually be fired along with return data. - # It's unlikely though. - self.close() - else: - _assert_no_error(result) - - # Ok, we read and probably succeeded. We should return whatever data - # was actually read. - return processed_bytes.value - - def settimeout(self, timeout): - self._timeout = timeout - - def gettimeout(self): - return self._timeout - - def send(self, data): - processed_bytes = ctypes.c_size_t(0) - - with self._raise_on_error(): - result = Security.SSLWrite( - self.context, data, len(data), ctypes.byref(processed_bytes) - ) - - if result == SecurityConst.errSSLWouldBlock and processed_bytes.value == 0: - # Timed out - raise socket.timeout("send timed out") - else: - _assert_no_error(result) - - # We sent, and probably succeeded. Tell them how much we sent. - return processed_bytes.value - - def sendall(self, data): - total_sent = 0 - while total_sent < len(data): - sent = self.send(data[total_sent : total_sent + SSL_WRITE_BLOCKSIZE]) - total_sent += sent - - def shutdown(self): - with self._raise_on_error(): - Security.SSLClose(self.context) - - def close(self): - # TODO: should I do clean shutdown here? Do I have to? - if self._makefile_refs < 1: - self._closed = True - if self.context: - CoreFoundation.CFRelease(self.context) - self.context = None - if self._client_cert_chain: - CoreFoundation.CFRelease(self._client_cert_chain) - self._client_cert_chain = None - if self._keychain: - Security.SecKeychainDelete(self._keychain) - CoreFoundation.CFRelease(self._keychain) - shutil.rmtree(self._keychain_dir) - self._keychain = self._keychain_dir = None - return self.socket.close() - else: - self._makefile_refs -= 1 - - def getpeercert(self, binary_form=False): - # Urgh, annoying. - # - # Here's how we do this: - # - # 1. Call SSLCopyPeerTrust to get hold of the trust object for this - # connection. - # 2. Call SecTrustGetCertificateAtIndex for index 0 to get the leaf. - # 3. To get the CN, call SecCertificateCopyCommonName and process that - # string so that it's of the appropriate type. - # 4. To get the SAN, we need to do something a bit more complex: - # a. Call SecCertificateCopyValues to get the data, requesting - # kSecOIDSubjectAltName. - # b. Mess about with this dictionary to try to get the SANs out. - # - # This is gross. Really gross. It's going to be a few hundred LoC extra - # just to repeat something that SecureTransport can *already do*. So my - # operating assumption at this time is that what we want to do is - # instead to just flag to urllib3 that it shouldn't do its own hostname - # validation when using SecureTransport. - if not binary_form: - raise ValueError("SecureTransport only supports dumping binary certs") - trust = Security.SecTrustRef() - certdata = None - der_bytes = None - - try: - # Grab the trust store. - result = Security.SSLCopyPeerTrust(self.context, ctypes.byref(trust)) - _assert_no_error(result) - if not trust: - # Probably we haven't done the handshake yet. No biggie. - return None - - cert_count = Security.SecTrustGetCertificateCount(trust) - if not cert_count: - # Also a case that might happen if we haven't handshaked. - # Handshook? Handshaken? - return None - - leaf = Security.SecTrustGetCertificateAtIndex(trust, 0) - assert leaf - - # Ok, now we want the DER bytes. - certdata = Security.SecCertificateCopyData(leaf) - assert certdata - - data_length = CoreFoundation.CFDataGetLength(certdata) - data_buffer = CoreFoundation.CFDataGetBytePtr(certdata) - der_bytes = ctypes.string_at(data_buffer, data_length) - finally: - if certdata: - CoreFoundation.CFRelease(certdata) - if trust: - CoreFoundation.CFRelease(trust) - - return der_bytes - - def version(self): - protocol = Security.SSLProtocol() - result = Security.SSLGetNegotiatedProtocolVersion( - self.context, ctypes.byref(protocol) - ) - _assert_no_error(result) - if protocol.value == SecurityConst.kTLSProtocol13: - raise ssl.SSLError("SecureTransport does not support TLS 1.3") - elif protocol.value == SecurityConst.kTLSProtocol12: - return "TLSv1.2" - elif protocol.value == SecurityConst.kTLSProtocol11: - return "TLSv1.1" - elif protocol.value == SecurityConst.kTLSProtocol1: - return "TLSv1" - elif protocol.value == SecurityConst.kSSLProtocol3: - return "SSLv3" - elif protocol.value == SecurityConst.kSSLProtocol2: - return "SSLv2" - else: - raise ssl.SSLError("Unknown TLS version: %r" % protocol) - - def _reuse(self): - self._makefile_refs += 1 - - def _drop(self): - if self._makefile_refs < 1: - self.close() - else: - self._makefile_refs -= 1 - - -if _fileobject: # Platform-specific: Python 2 - - def makefile(self, mode, bufsize=-1): - self._makefile_refs += 1 - return _fileobject(self, mode, bufsize, close=True) - - -else: # Platform-specific: Python 3 - - def makefile(self, mode="r", buffering=None, *args, **kwargs): - # We disable buffering with SecureTransport because it conflicts with - # the buffering that ST does internally (see issue #1153 for more). - buffering = 0 - return backport_makefile(self, mode, buffering, *args, **kwargs) - - -WrappedSocket.makefile = makefile - - -class SecureTransportContext(object): - """ - I am a wrapper class for the SecureTransport library, to translate the - interface of the standard library ``SSLContext`` object to calls into - SecureTransport. - """ - - def __init__(self, protocol): - self._min_version, self._max_version = _protocol_to_min_max[protocol] - self._options = 0 - self._verify = False - self._trust_bundle = None - self._client_cert = None - self._client_key = None - self._client_key_passphrase = None - self._alpn_protocols = None - - @property - def check_hostname(self): - """ - SecureTransport cannot have its hostname checking disabled. For more, - see the comment on getpeercert() in this file. - """ - return True - - @check_hostname.setter - def check_hostname(self, value): - """ - SecureTransport cannot have its hostname checking disabled. For more, - see the comment on getpeercert() in this file. - """ - pass - - @property - def options(self): - # TODO: Well, crap. - # - # So this is the bit of the code that is the most likely to cause us - # trouble. Essentially we need to enumerate all of the SSL options that - # users might want to use and try to see if we can sensibly translate - # them, or whether we should just ignore them. - return self._options - - @options.setter - def options(self, value): - # TODO: Update in line with above. - self._options = value - - @property - def verify_mode(self): - return ssl.CERT_REQUIRED if self._verify else ssl.CERT_NONE - - @verify_mode.setter - def verify_mode(self, value): - self._verify = True if value == ssl.CERT_REQUIRED else False - - def set_default_verify_paths(self): - # So, this has to do something a bit weird. Specifically, what it does - # is nothing. - # - # This means that, if we had previously had load_verify_locations - # called, this does not undo that. We need to do that because it turns - # out that the rest of the urllib3 code will attempt to load the - # default verify paths if it hasn't been told about any paths, even if - # the context itself was sometime earlier. We resolve that by just - # ignoring it. - pass - - def load_default_certs(self): - return self.set_default_verify_paths() - - def set_ciphers(self, ciphers): - # For now, we just require the default cipher string. - if ciphers != util.ssl_.DEFAULT_CIPHERS: - raise ValueError("SecureTransport doesn't support custom cipher strings") - - def load_verify_locations(self, cafile=None, capath=None, cadata=None): - # OK, we only really support cadata and cafile. - if capath is not None: - raise ValueError("SecureTransport does not support cert directories") - - # Raise if cafile does not exist. - if cafile is not None: - with open(cafile): - pass - - self._trust_bundle = cafile or cadata - - def load_cert_chain(self, certfile, keyfile=None, password=None): - self._client_cert = certfile - self._client_key = keyfile - self._client_cert_passphrase = password - - def set_alpn_protocols(self, protocols): - """ - Sets the ALPN protocols that will later be set on the context. - - Raises a NotImplementedError if ALPN is not supported. - """ - if not hasattr(Security, "SSLSetALPNProtocols"): - raise NotImplementedError( - "SecureTransport supports ALPN only in macOS 10.12+" - ) - self._alpn_protocols = [six.ensure_binary(p) for p in protocols] - - def wrap_socket( - self, - sock, - server_side=False, - do_handshake_on_connect=True, - suppress_ragged_eofs=True, - server_hostname=None, - ): - # So, what do we do here? Firstly, we assert some properties. This is a - # stripped down shim, so there is some functionality we don't support. - # See PEP 543 for the real deal. - assert not server_side - assert do_handshake_on_connect - assert suppress_ragged_eofs - - # Ok, we're good to go. Now we want to create the wrapped socket object - # and store it in the appropriate place. - wrapped_socket = WrappedSocket(sock) - - # Now we can handshake - wrapped_socket.handshake( - server_hostname, - self._verify, - self._trust_bundle, - self._min_version, - self._max_version, - self._client_cert, - self._client_key, - self._client_key_passphrase, - self._alpn_protocols, - ) - return wrapped_socket diff --git a/venv/lib/python3.8/site-packages/urllib3/contrib/socks.py b/venv/lib/python3.8/site-packages/urllib3/contrib/socks.py deleted file mode 100644 index c326e80..0000000 --- a/venv/lib/python3.8/site-packages/urllib3/contrib/socks.py +++ /dev/null @@ -1,216 +0,0 @@ -# -*- coding: utf-8 -*- -""" -This module contains provisional support for SOCKS proxies from within -urllib3. This module supports SOCKS4, SOCKS4A (an extension of SOCKS4), and -SOCKS5. To enable its functionality, either install PySocks or install this -module with the ``socks`` extra. - -The SOCKS implementation supports the full range of urllib3 features. It also -supports the following SOCKS features: - -- SOCKS4A (``proxy_url='socks4a://...``) -- SOCKS4 (``proxy_url='socks4://...``) -- SOCKS5 with remote DNS (``proxy_url='socks5h://...``) -- SOCKS5 with local DNS (``proxy_url='socks5://...``) -- Usernames and passwords for the SOCKS proxy - -.. note:: - It is recommended to use ``socks5h://`` or ``socks4a://`` schemes in - your ``proxy_url`` to ensure that DNS resolution is done from the remote - server instead of client-side when connecting to a domain name. - -SOCKS4 supports IPv4 and domain names with the SOCKS4A extension. SOCKS5 -supports IPv4, IPv6, and domain names. - -When connecting to a SOCKS4 proxy the ``username`` portion of the ``proxy_url`` -will be sent as the ``userid`` section of the SOCKS request: - -.. code-block:: python - - proxy_url="socks4a://<userid>@proxy-host" - -When connecting to a SOCKS5 proxy the ``username`` and ``password`` portion -of the ``proxy_url`` will be sent as the username/password to authenticate -with the proxy: - -.. code-block:: python - - proxy_url="socks5h://<username>:<password>@proxy-host" - -""" -from __future__ import absolute_import - -try: - import socks -except ImportError: - import warnings - - from ..exceptions import DependencyWarning - - warnings.warn( - ( - "SOCKS support in urllib3 requires the installation of optional " - "dependencies: specifically, PySocks. For more information, see " - "https://urllib3.readthedocs.io/en/1.26.x/contrib.html#socks-proxies" - ), - DependencyWarning, - ) - raise - -from socket import error as SocketError -from socket import timeout as SocketTimeout - -from ..connection import HTTPConnection, HTTPSConnection -from ..connectionpool import HTTPConnectionPool, HTTPSConnectionPool -from ..exceptions import ConnectTimeoutError, NewConnectionError -from ..poolmanager import PoolManager -from ..util.url import parse_url - -try: - import ssl -except ImportError: - ssl = None - - -class SOCKSConnection(HTTPConnection): - """ - A plain-text HTTP connection that connects via a SOCKS proxy. - """ - - def __init__(self, *args, **kwargs): - self._socks_options = kwargs.pop("_socks_options") - super(SOCKSConnection, self).__init__(*args, **kwargs) - - def _new_conn(self): - """ - Establish a new connection via the SOCKS proxy. - """ - extra_kw = {} - if self.source_address: - extra_kw["source_address"] = self.source_address - - if self.socket_options: - extra_kw["socket_options"] = self.socket_options - - try: - conn = socks.create_connection( - (self.host, self.port), - proxy_type=self._socks_options["socks_version"], - proxy_addr=self._socks_options["proxy_host"], - proxy_port=self._socks_options["proxy_port"], - proxy_username=self._socks_options["username"], - proxy_password=self._socks_options["password"], - proxy_rdns=self._socks_options["rdns"], - timeout=self.timeout, - **extra_kw - ) - - except SocketTimeout: - raise ConnectTimeoutError( - self, - "Connection to %s timed out. (connect timeout=%s)" - % (self.host, self.timeout), - ) - - except socks.ProxyError as e: - # This is fragile as hell, but it seems to be the only way to raise - # useful errors here. - if e.socket_err: - error = e.socket_err - if isinstance(error, SocketTimeout): - raise ConnectTimeoutError( - self, - "Connection to %s timed out. (connect timeout=%s)" - % (self.host, self.timeout), - ) - else: - raise NewConnectionError( - self, "Failed to establish a new connection: %s" % error - ) - else: - raise NewConnectionError( - self, "Failed to establish a new connection: %s" % e - ) - - except SocketError as e: # Defensive: PySocks should catch all these. - raise NewConnectionError( - self, "Failed to establish a new connection: %s" % e - ) - - return conn - - -# We don't need to duplicate the Verified/Unverified distinction from -# urllib3/connection.py here because the HTTPSConnection will already have been -# correctly set to either the Verified or Unverified form by that module. This -# means the SOCKSHTTPSConnection will automatically be the correct type. -class SOCKSHTTPSConnection(SOCKSConnection, HTTPSConnection): - pass - - -class SOCKSHTTPConnectionPool(HTTPConnectionPool): - ConnectionCls = SOCKSConnection - - -class SOCKSHTTPSConnectionPool(HTTPSConnectionPool): - ConnectionCls = SOCKSHTTPSConnection - - -class SOCKSProxyManager(PoolManager): - """ - A version of the urllib3 ProxyManager that routes connections via the - defined SOCKS proxy. - """ - - pool_classes_by_scheme = { - "http": SOCKSHTTPConnectionPool, - "https": SOCKSHTTPSConnectionPool, - } - - def __init__( - self, - proxy_url, - username=None, - password=None, - num_pools=10, - headers=None, - **connection_pool_kw - ): - parsed = parse_url(proxy_url) - - if username is None and password is None and parsed.auth is not None: - split = parsed.auth.split(":") - if len(split) == 2: - username, password = split - if parsed.scheme == "socks5": - socks_version = socks.PROXY_TYPE_SOCKS5 - rdns = False - elif parsed.scheme == "socks5h": - socks_version = socks.PROXY_TYPE_SOCKS5 - rdns = True - elif parsed.scheme == "socks4": - socks_version = socks.PROXY_TYPE_SOCKS4 - rdns = False - elif parsed.scheme == "socks4a": - socks_version = socks.PROXY_TYPE_SOCKS4 - rdns = True - else: - raise ValueError("Unable to determine SOCKS version from %s" % proxy_url) - - self.proxy_url = proxy_url - - socks_options = { - "socks_version": socks_version, - "proxy_host": parsed.host, - "proxy_port": parsed.port, - "username": username, - "password": password, - "rdns": rdns, - } - connection_pool_kw["_socks_options"] = socks_options - - super(SOCKSProxyManager, self).__init__( - num_pools, headers, **connection_pool_kw - ) - - self.pool_classes_by_scheme = SOCKSProxyManager.pool_classes_by_scheme diff --git a/venv/lib/python3.8/site-packages/urllib3/exceptions.py b/venv/lib/python3.8/site-packages/urllib3/exceptions.py deleted file mode 100644 index cba6f3f..0000000 --- a/venv/lib/python3.8/site-packages/urllib3/exceptions.py +++ /dev/null @@ -1,323 +0,0 @@ -from __future__ import absolute_import - -from .packages.six.moves.http_client import IncompleteRead as httplib_IncompleteRead - -# Base Exceptions - - -class HTTPError(Exception): - """Base exception used by this module.""" - - pass - - -class HTTPWarning(Warning): - """Base warning used by this module.""" - - pass - - -class PoolError(HTTPError): - """Base exception for errors caused within a pool.""" - - def __init__(self, pool, message): - self.pool = pool - HTTPError.__init__(self, "%s: %s" % (pool, message)) - - def __reduce__(self): - # For pickling purposes. - return self.__class__, (None, None) - - -class RequestError(PoolError): - """Base exception for PoolErrors that have associated URLs.""" - - def __init__(self, pool, url, message): - self.url = url - PoolError.__init__(self, pool, message) - - def __reduce__(self): - # For pickling purposes. - return self.__class__, (None, self.url, None) - - -class SSLError(HTTPError): - """Raised when SSL certificate fails in an HTTPS connection.""" - - pass - - -class ProxyError(HTTPError): - """Raised when the connection to a proxy fails.""" - - def __init__(self, message, error, *args): - super(ProxyError, self).__init__(message, error, *args) - self.original_error = error - - -class DecodeError(HTTPError): - """Raised when automatic decoding based on Content-Type fails.""" - - pass - - -class ProtocolError(HTTPError): - """Raised when something unexpected happens mid-request/response.""" - - pass - - -#: Renamed to ProtocolError but aliased for backwards compatibility. -ConnectionError = ProtocolError - - -# Leaf Exceptions - - -class MaxRetryError(RequestError): - """Raised when the maximum number of retries is exceeded. - - :param pool: The connection pool - :type pool: :class:`~urllib3.connectionpool.HTTPConnectionPool` - :param string url: The requested Url - :param exceptions.Exception reason: The underlying error - - """ - - def __init__(self, pool, url, reason=None): - self.reason = reason - - message = "Max retries exceeded with url: %s (Caused by %r)" % (url, reason) - - RequestError.__init__(self, pool, url, message) - - -class HostChangedError(RequestError): - """Raised when an existing pool gets a request for a foreign host.""" - - def __init__(self, pool, url, retries=3): - message = "Tried to open a foreign host with url: %s" % url - RequestError.__init__(self, pool, url, message) - self.retries = retries - - -class TimeoutStateError(HTTPError): - """Raised when passing an invalid state to a timeout""" - - pass - - -class TimeoutError(HTTPError): - """Raised when a socket timeout error occurs. - - Catching this error will catch both :exc:`ReadTimeoutErrors - <ReadTimeoutError>` and :exc:`ConnectTimeoutErrors <ConnectTimeoutError>`. - """ - - pass - - -class ReadTimeoutError(TimeoutError, RequestError): - """Raised when a socket timeout occurs while receiving data from a server""" - - pass - - -# This timeout error does not have a URL attached and needs to inherit from the -# base HTTPError -class ConnectTimeoutError(TimeoutError): - """Raised when a socket timeout occurs while connecting to a server""" - - pass - - -class NewConnectionError(ConnectTimeoutError, PoolError): - """Raised when we fail to establish a new connection. Usually ECONNREFUSED.""" - - pass - - -class EmptyPoolError(PoolError): - """Raised when a pool runs out of connections and no more are allowed.""" - - pass - - -class ClosedPoolError(PoolError): - """Raised when a request enters a pool after the pool has been closed.""" - - pass - - -class LocationValueError(ValueError, HTTPError): - """Raised when there is something wrong with a given URL input.""" - - pass - - -class LocationParseError(LocationValueError): - """Raised when get_host or similar fails to parse the URL input.""" - - def __init__(self, location): - message = "Failed to parse: %s" % location - HTTPError.__init__(self, message) - - self.location = location - - -class URLSchemeUnknown(LocationValueError): - """Raised when a URL input has an unsupported scheme.""" - - def __init__(self, scheme): - message = "Not supported URL scheme %s" % scheme - super(URLSchemeUnknown, self).__init__(message) - - self.scheme = scheme - - -class ResponseError(HTTPError): - """Used as a container for an error reason supplied in a MaxRetryError.""" - - GENERIC_ERROR = "too many error responses" - SPECIFIC_ERROR = "too many {status_code} error responses" - - -class SecurityWarning(HTTPWarning): - """Warned when performing security reducing actions""" - - pass - - -class SubjectAltNameWarning(SecurityWarning): - """Warned when connecting to a host with a certificate missing a SAN.""" - - pass - - -class InsecureRequestWarning(SecurityWarning): - """Warned when making an unverified HTTPS request.""" - - pass - - -class SystemTimeWarning(SecurityWarning): - """Warned when system time is suspected to be wrong""" - - pass - - -class InsecurePlatformWarning(SecurityWarning): - """Warned when certain TLS/SSL configuration is not available on a platform.""" - - pass - - -class SNIMissingWarning(HTTPWarning): - """Warned when making a HTTPS request without SNI available.""" - - pass - - -class DependencyWarning(HTTPWarning): - """ - Warned when an attempt is made to import a module with missing optional - dependencies. - """ - - pass - - -class ResponseNotChunked(ProtocolError, ValueError): - """Response needs to be chunked in order to read it as chunks.""" - - pass - - -class BodyNotHttplibCompatible(HTTPError): - """ - Body should be :class:`http.client.HTTPResponse` like - (have an fp attribute which returns raw chunks) for read_chunked(). - """ - - pass - - -class IncompleteRead(HTTPError, httplib_IncompleteRead): - """ - Response length doesn't match expected Content-Length - - Subclass of :class:`http.client.IncompleteRead` to allow int value - for ``partial`` to avoid creating large objects on streamed reads. - """ - - def __init__(self, partial, expected): - super(IncompleteRead, self).__init__(partial, expected) - - def __repr__(self): - return "IncompleteRead(%i bytes read, %i more expected)" % ( - self.partial, - self.expected, - ) - - -class InvalidChunkLength(HTTPError, httplib_IncompleteRead): - """Invalid chunk length in a chunked response.""" - - def __init__(self, response, length): - super(InvalidChunkLength, self).__init__( - response.tell(), response.length_remaining - ) - self.response = response - self.length = length - - def __repr__(self): - return "InvalidChunkLength(got length %r, %i bytes read)" % ( - self.length, - self.partial, - ) - - -class InvalidHeader(HTTPError): - """The header provided was somehow invalid.""" - - pass - - -class ProxySchemeUnknown(AssertionError, URLSchemeUnknown): - """ProxyManager does not support the supplied scheme""" - - # TODO(t-8ch): Stop inheriting from AssertionError in v2.0. - - def __init__(self, scheme): - # 'localhost' is here because our URL parser parses - # localhost:8080 -> scheme=localhost, remove if we fix this. - if scheme == "localhost": - scheme = None - if scheme is None: - message = "Proxy URL had no scheme, should start with http:// or https://" - else: - message = ( - "Proxy URL had unsupported scheme %s, should use http:// or https://" - % scheme - ) - super(ProxySchemeUnknown, self).__init__(message) - - -class ProxySchemeUnsupported(ValueError): - """Fetching HTTPS resources through HTTPS proxies is unsupported""" - - pass - - -class HeaderParsingError(HTTPError): - """Raised by assert_header_parsing, but we convert it to a log.warning statement.""" - - def __init__(self, defects, unparsed_data): - message = "%s, unparsed data: %r" % (defects or "Unknown", unparsed_data) - super(HeaderParsingError, self).__init__(message) - - -class UnrewindableBodyError(HTTPError): - """urllib3 encountered an error when trying to rewind a body""" - - pass diff --git a/venv/lib/python3.8/site-packages/urllib3/fields.py b/venv/lib/python3.8/site-packages/urllib3/fields.py deleted file mode 100644 index 9d630f4..0000000 --- a/venv/lib/python3.8/site-packages/urllib3/fields.py +++ /dev/null @@ -1,274 +0,0 @@ -from __future__ import absolute_import - -import email.utils -import mimetypes -import re - -from .packages import six - - -def guess_content_type(filename, default="application/octet-stream"): - """ - Guess the "Content-Type" of a file. - - :param filename: - The filename to guess the "Content-Type" of using :mod:`mimetypes`. - :param default: - If no "Content-Type" can be guessed, default to `default`. - """ - if filename: - return mimetypes.guess_type(filename)[0] or default - return default - - -def format_header_param_rfc2231(name, value): - """ - Helper function to format and quote a single header parameter using the - strategy defined in RFC 2231. - - Particularly useful for header parameters which might contain - non-ASCII values, like file names. This follows - `RFC 2388 Section 4.4 <https://tools.ietf.org/html/rfc2388#section-4.4>`_. - - :param name: - The name of the parameter, a string expected to be ASCII only. - :param value: - The value of the parameter, provided as ``bytes`` or `str``. - :ret: - An RFC-2231-formatted unicode string. - """ - if isinstance(value, six.binary_type): - value = value.decode("utf-8") - - if not any(ch in value for ch in '"\\\r\n'): - result = u'%s="%s"' % (name, value) - try: - result.encode("ascii") - except (UnicodeEncodeError, UnicodeDecodeError): - pass - else: - return result - - if six.PY2: # Python 2: - value = value.encode("utf-8") - - # encode_rfc2231 accepts an encoded string and returns an ascii-encoded - # string in Python 2 but accepts and returns unicode strings in Python 3 - value = email.utils.encode_rfc2231(value, "utf-8") - value = "%s*=%s" % (name, value) - - if six.PY2: # Python 2: - value = value.decode("utf-8") - - return value - - -_HTML5_REPLACEMENTS = { - u"\u0022": u"%22", - # Replace "\" with "\\". - u"\u005C": u"\u005C\u005C", -} - -# All control characters from 0x00 to 0x1F *except* 0x1B. -_HTML5_REPLACEMENTS.update( - { - six.unichr(cc): u"%{:02X}".format(cc) - for cc in range(0x00, 0x1F + 1) - if cc not in (0x1B,) - } -) - - -def _replace_multiple(value, needles_and_replacements): - def replacer(match): - return needles_and_replacements[match.group(0)] - - pattern = re.compile( - r"|".join([re.escape(needle) for needle in needles_and_replacements.keys()]) - ) - - result = pattern.sub(replacer, value) - - return result - - -def format_header_param_html5(name, value): - """ - Helper function to format and quote a single header parameter using the - HTML5 strategy. - - Particularly useful for header parameters which might contain - non-ASCII values, like file names. This follows the `HTML5 Working Draft - Section 4.10.22.7`_ and matches the behavior of curl and modern browsers. - - .. _HTML5 Working Draft Section 4.10.22.7: - https://w3c.github.io/html/sec-forms.html#multipart-form-data - - :param name: - The name of the parameter, a string expected to be ASCII only. - :param value: - The value of the parameter, provided as ``bytes`` or `str``. - :ret: - A unicode string, stripped of troublesome characters. - """ - if isinstance(value, six.binary_type): - value = value.decode("utf-8") - - value = _replace_multiple(value, _HTML5_REPLACEMENTS) - - return u'%s="%s"' % (name, value) - - -# For backwards-compatibility. -format_header_param = format_header_param_html5 - - -class RequestField(object): - """ - A data container for request body parameters. - - :param name: - The name of this request field. Must be unicode. - :param data: - The data/value body. - :param filename: - An optional filename of the request field. Must be unicode. - :param headers: - An optional dict-like object of headers to initially use for the field. - :param header_formatter: - An optional callable that is used to encode and format the headers. By - default, this is :func:`format_header_param_html5`. - """ - - def __init__( - self, - name, - data, - filename=None, - headers=None, - header_formatter=format_header_param_html5, - ): - self._name = name - self._filename = filename - self.data = data - self.headers = {} - if headers: - self.headers = dict(headers) - self.header_formatter = header_formatter - - @classmethod - def from_tuples(cls, fieldname, value, header_formatter=format_header_param_html5): - """ - A :class:`~urllib3.fields.RequestField` factory from old-style tuple parameters. - - Supports constructing :class:`~urllib3.fields.RequestField` from - parameter of key/value strings AND key/filetuple. A filetuple is a - (filename, data, MIME type) tuple where the MIME type is optional. - For example:: - - 'foo': 'bar', - 'fakefile': ('foofile.txt', 'contents of foofile'), - 'realfile': ('barfile.txt', open('realfile').read()), - 'typedfile': ('bazfile.bin', open('bazfile').read(), 'image/jpeg'), - 'nonamefile': 'contents of nonamefile field', - - Field names and filenames must be unicode. - """ - if isinstance(value, tuple): - if len(value) == 3: - filename, data, content_type = value - else: - filename, data = value - content_type = guess_content_type(filename) - else: - filename = None - content_type = None - data = value - - request_param = cls( - fieldname, data, filename=filename, header_formatter=header_formatter - ) - request_param.make_multipart(content_type=content_type) - - return request_param - - def _render_part(self, name, value): - """ - Overridable helper function to format a single header parameter. By - default, this calls ``self.header_formatter``. - - :param name: - The name of the parameter, a string expected to be ASCII only. - :param value: - The value of the parameter, provided as a unicode string. - """ - - return self.header_formatter(name, value) - - def _render_parts(self, header_parts): - """ - Helper function to format and quote a single header. - - Useful for single headers that are composed of multiple items. E.g., - 'Content-Disposition' fields. - - :param header_parts: - A sequence of (k, v) tuples or a :class:`dict` of (k, v) to format - as `k1="v1"; k2="v2"; ...`. - """ - parts = [] - iterable = header_parts - if isinstance(header_parts, dict): - iterable = header_parts.items() - - for name, value in iterable: - if value is not None: - parts.append(self._render_part(name, value)) - - return u"; ".join(parts) - - def render_headers(self): - """ - Renders the headers for this request field. - """ - lines = [] - - sort_keys = ["Content-Disposition", "Content-Type", "Content-Location"] - for sort_key in sort_keys: - if self.headers.get(sort_key, False): - lines.append(u"%s: %s" % (sort_key, self.headers[sort_key])) - - for header_name, header_value in self.headers.items(): - if header_name not in sort_keys: - if header_value: - lines.append(u"%s: %s" % (header_name, header_value)) - - lines.append(u"\r\n") - return u"\r\n".join(lines) - - def make_multipart( - self, content_disposition=None, content_type=None, content_location=None - ): - """ - Makes this request field into a multipart request field. - - This method overrides "Content-Disposition", "Content-Type" and - "Content-Location" headers to the request parameter. - - :param content_type: - The 'Content-Type' of the request body. - :param content_location: - The 'Content-Location' of the request body. - - """ - self.headers["Content-Disposition"] = content_disposition or u"form-data" - self.headers["Content-Disposition"] += u"; ".join( - [ - u"", - self._render_parts( - ((u"name", self._name), (u"filename", self._filename)) - ), - ] - ) - self.headers["Content-Type"] = content_type - self.headers["Content-Location"] = content_location diff --git a/venv/lib/python3.8/site-packages/urllib3/filepost.py b/venv/lib/python3.8/site-packages/urllib3/filepost.py deleted file mode 100644 index 36c9252..0000000 --- a/venv/lib/python3.8/site-packages/urllib3/filepost.py +++ /dev/null @@ -1,98 +0,0 @@ -from __future__ import absolute_import - -import binascii -import codecs -import os -from io import BytesIO - -from .fields import RequestField -from .packages import six -from .packages.six import b - -writer = codecs.lookup("utf-8")[3] - - -def choose_boundary(): - """ - Our embarrassingly-simple replacement for mimetools.choose_boundary. - """ - boundary = binascii.hexlify(os.urandom(16)) - if not six.PY2: - boundary = boundary.decode("ascii") - return boundary - - -def iter_field_objects(fields): - """ - Iterate over fields. - - Supports list of (k, v) tuples and dicts, and lists of - :class:`~urllib3.fields.RequestField`. - - """ - if isinstance(fields, dict): - i = six.iteritems(fields) - else: - i = iter(fields) - - for field in i: - if isinstance(field, RequestField): - yield field - else: - yield RequestField.from_tuples(*field) - - -def iter_fields(fields): - """ - .. deprecated:: 1.6 - - Iterate over fields. - - The addition of :class:`~urllib3.fields.RequestField` makes this function - obsolete. Instead, use :func:`iter_field_objects`, which returns - :class:`~urllib3.fields.RequestField` objects. - - Supports list of (k, v) tuples and dicts. - """ - if isinstance(fields, dict): - return ((k, v) for k, v in six.iteritems(fields)) - - return ((k, v) for k, v in fields) - - -def encode_multipart_formdata(fields, boundary=None): - """ - Encode a dictionary of ``fields`` using the multipart/form-data MIME format. - - :param fields: - Dictionary of fields or list of (key, :class:`~urllib3.fields.RequestField`). - - :param boundary: - If not specified, then a random boundary will be generated using - :func:`urllib3.filepost.choose_boundary`. - """ - body = BytesIO() - if boundary is None: - boundary = choose_boundary() - - for field in iter_field_objects(fields): - body.write(b("--%s\r\n" % (boundary))) - - writer(body).write(field.render_headers()) - data = field.data - - if isinstance(data, int): - data = str(data) # Backwards compatibility - - if isinstance(data, six.text_type): - writer(body).write(data) - else: - body.write(data) - - body.write(b"\r\n") - - body.write(b("--%s--\r\n" % (boundary))) - - content_type = str("multipart/form-data; boundary=%s" % boundary) - - return body.getvalue(), content_type diff --git a/venv/lib/python3.8/site-packages/urllib3/packages/__init__.py b/venv/lib/python3.8/site-packages/urllib3/packages/__init__.py deleted file mode 100644 index fce4caa..0000000 --- a/venv/lib/python3.8/site-packages/urllib3/packages/__init__.py +++ /dev/null @@ -1,5 +0,0 @@ -from __future__ import absolute_import - -from . import ssl_match_hostname - -__all__ = ("ssl_match_hostname",) diff --git a/venv/lib/python3.8/site-packages/urllib3/packages/backports/__init__.py b/venv/lib/python3.8/site-packages/urllib3/packages/backports/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/venv/lib/python3.8/site-packages/urllib3/packages/backports/makefile.py b/venv/lib/python3.8/site-packages/urllib3/packages/backports/makefile.py deleted file mode 100644 index b8fb215..0000000 --- a/venv/lib/python3.8/site-packages/urllib3/packages/backports/makefile.py +++ /dev/null @@ -1,51 +0,0 @@ -# -*- coding: utf-8 -*- -""" -backports.makefile -~~~~~~~~~~~~~~~~~~ - -Backports the Python 3 ``socket.makefile`` method for use with anything that -wants to create a "fake" socket object. -""" -import io -from socket import SocketIO - - -def backport_makefile( - self, mode="r", buffering=None, encoding=None, errors=None, newline=None -): - """ - Backport of ``socket.makefile`` from Python 3.5. - """ - if not set(mode) <= {"r", "w", "b"}: - raise ValueError("invalid mode %r (only r, w, b allowed)" % (mode,)) - writing = "w" in mode - reading = "r" in mode or not writing - assert reading or writing - binary = "b" in mode - rawmode = "" - if reading: - rawmode += "r" - if writing: - rawmode += "w" - raw = SocketIO(self, rawmode) - self._makefile_refs += 1 - if buffering is None: - buffering = -1 - if buffering < 0: - buffering = io.DEFAULT_BUFFER_SIZE - if buffering == 0: - if not binary: - raise ValueError("unbuffered streams must be binary") - return raw - if reading and writing: - buffer = io.BufferedRWPair(raw, raw, buffering) - elif reading: - buffer = io.BufferedReader(raw, buffering) - else: - assert writing - buffer = io.BufferedWriter(raw, buffering) - if binary: - return buffer - text = io.TextIOWrapper(buffer, encoding, errors, newline) - text.mode = mode - return text diff --git a/venv/lib/python3.8/site-packages/urllib3/packages/six.py b/venv/lib/python3.8/site-packages/urllib3/packages/six.py deleted file mode 100644 index ba50acb..0000000 --- a/venv/lib/python3.8/site-packages/urllib3/packages/six.py +++ /dev/null @@ -1,1077 +0,0 @@ -# Copyright (c) 2010-2020 Benjamin Peterson -# -# 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. - -"""Utilities for writing code that runs on Python 2 and 3""" - -from __future__ import absolute_import - -import functools -import itertools -import operator -import sys -import types - -__author__ = "Benjamin Peterson <benjamin@python.org>" -__version__ = "1.16.0" - - -# Useful for very coarse version differentiation. -PY2 = sys.version_info[0] == 2 -PY3 = sys.version_info[0] == 3 -PY34 = sys.version_info[0:2] >= (3, 4) - -if PY3: - string_types = (str,) - integer_types = (int,) - class_types = (type,) - text_type = str - binary_type = bytes - - MAXSIZE = sys.maxsize -else: - string_types = (basestring,) - integer_types = (int, long) - class_types = (type, types.ClassType) - text_type = unicode - binary_type = str - - if sys.platform.startswith("java"): - # Jython always uses 32 bits. - MAXSIZE = int((1 << 31) - 1) - else: - # It's possible to have sizeof(long) != sizeof(Py_ssize_t). - class X(object): - def __len__(self): - return 1 << 31 - - try: - len(X()) - except OverflowError: - # 32-bit - MAXSIZE = int((1 << 31) - 1) - else: - # 64-bit - MAXSIZE = int((1 << 63) - 1) - del X - -if PY34: - from importlib.util import spec_from_loader -else: - spec_from_loader = None - - -def _add_doc(func, doc): - """Add documentation to a function.""" - func.__doc__ = doc - - -def _import_module(name): - """Import module, returning the module after the last dot.""" - __import__(name) - return sys.modules[name] - - -class _LazyDescr(object): - def __init__(self, name): - self.name = name - - def __get__(self, obj, tp): - result = self._resolve() - setattr(obj, self.name, result) # Invokes __set__. - try: - # This is a bit ugly, but it avoids running this again by - # removing this descriptor. - delattr(obj.__class__, self.name) - except AttributeError: - pass - return result - - -class MovedModule(_LazyDescr): - def __init__(self, name, old, new=None): - super(MovedModule, self).__init__(name) - if PY3: - if new is None: - new = name - self.mod = new - else: - self.mod = old - - def _resolve(self): - return _import_module(self.mod) - - def __getattr__(self, attr): - _module = self._resolve() - value = getattr(_module, attr) - setattr(self, attr, value) - return value - - -class _LazyModule(types.ModuleType): - def __init__(self, name): - super(_LazyModule, self).__init__(name) - self.__doc__ = self.__class__.__doc__ - - def __dir__(self): - attrs = ["__doc__", "__name__"] - attrs += [attr.name for attr in self._moved_attributes] - return attrs - - # Subclasses should override this - _moved_attributes = [] - - -class MovedAttribute(_LazyDescr): - def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None): - super(MovedAttribute, self).__init__(name) - if PY3: - if new_mod is None: - new_mod = name - self.mod = new_mod - if new_attr is None: - if old_attr is None: - new_attr = name - else: - new_attr = old_attr - self.attr = new_attr - else: - self.mod = old_mod - if old_attr is None: - old_attr = name - self.attr = old_attr - - def _resolve(self): - module = _import_module(self.mod) - return getattr(module, self.attr) - - -class _SixMetaPathImporter(object): - - """ - A meta path importer to import six.moves and its submodules. - - This class implements a PEP302 finder and loader. It should be compatible - with Python 2.5 and all existing versions of Python3 - """ - - def __init__(self, six_module_name): - self.name = six_module_name - self.known_modules = {} - - def _add_module(self, mod, *fullnames): - for fullname in fullnames: - self.known_modules[self.name + "." + fullname] = mod - - def _get_module(self, fullname): - return self.known_modules[self.name + "." + fullname] - - def find_module(self, fullname, path=None): - if fullname in self.known_modules: - return self - return None - - def find_spec(self, fullname, path, target=None): - if fullname in self.known_modules: - return spec_from_loader(fullname, self) - return None - - def __get_module(self, fullname): - try: - return self.known_modules[fullname] - except KeyError: - raise ImportError("This loader does not know module " + fullname) - - def load_module(self, fullname): - try: - # in case of a reload - return sys.modules[fullname] - except KeyError: - pass - mod = self.__get_module(fullname) - if isinstance(mod, MovedModule): - mod = mod._resolve() - else: - mod.__loader__ = self - sys.modules[fullname] = mod - return mod - - def is_package(self, fullname): - """ - Return true, if the named module is a package. - - We need this method to get correct spec objects with - Python 3.4 (see PEP451) - """ - return hasattr(self.__get_module(fullname), "__path__") - - def get_code(self, fullname): - """Return None - - Required, if is_package is implemented""" - self.__get_module(fullname) # eventually raises ImportError - return None - - get_source = get_code # same as get_code - - def create_module(self, spec): - return self.load_module(spec.name) - - def exec_module(self, module): - pass - - -_importer = _SixMetaPathImporter(__name__) - - -class _MovedItems(_LazyModule): - - """Lazy loading of moved objects""" - - __path__ = [] # mark as package - - -_moved_attributes = [ - MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"), - MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"), - MovedAttribute( - "filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse" - ), - MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"), - MovedAttribute("intern", "__builtin__", "sys"), - MovedAttribute("map", "itertools", "builtins", "imap", "map"), - MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"), - MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"), - MovedAttribute("getoutput", "commands", "subprocess"), - MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"), - MovedAttribute( - "reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload" - ), - MovedAttribute("reduce", "__builtin__", "functools"), - MovedAttribute("shlex_quote", "pipes", "shlex", "quote"), - MovedAttribute("StringIO", "StringIO", "io"), - MovedAttribute("UserDict", "UserDict", "collections"), - MovedAttribute("UserList", "UserList", "collections"), - MovedAttribute("UserString", "UserString", "collections"), - MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"), - MovedAttribute("zip", "itertools", "builtins", "izip", "zip"), - MovedAttribute( - "zip_longest", "itertools", "itertools", "izip_longest", "zip_longest" - ), - MovedModule("builtins", "__builtin__"), - MovedModule("configparser", "ConfigParser"), - MovedModule( - "collections_abc", - "collections", - "collections.abc" if sys.version_info >= (3, 3) else "collections", - ), - MovedModule("copyreg", "copy_reg"), - MovedModule("dbm_gnu", "gdbm", "dbm.gnu"), - MovedModule("dbm_ndbm", "dbm", "dbm.ndbm"), - MovedModule( - "_dummy_thread", - "dummy_thread", - "_dummy_thread" if sys.version_info < (3, 9) else "_thread", - ), - MovedModule("http_cookiejar", "cookielib", "http.cookiejar"), - MovedModule("http_cookies", "Cookie", "http.cookies"), - MovedModule("html_entities", "htmlentitydefs", "html.entities"), - MovedModule("html_parser", "HTMLParser", "html.parser"), - MovedModule("http_client", "httplib", "http.client"), - MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"), - MovedModule("email_mime_image", "email.MIMEImage", "email.mime.image"), - MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"), - MovedModule( - "email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart" - ), - MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"), - MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"), - MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"), - MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"), - MovedModule("cPickle", "cPickle", "pickle"), - MovedModule("queue", "Queue"), - MovedModule("reprlib", "repr"), - MovedModule("socketserver", "SocketServer"), - MovedModule("_thread", "thread", "_thread"), - MovedModule("tkinter", "Tkinter"), - MovedModule("tkinter_dialog", "Dialog", "tkinter.dialog"), - MovedModule("tkinter_filedialog", "FileDialog", "tkinter.filedialog"), - MovedModule("tkinter_scrolledtext", "ScrolledText", "tkinter.scrolledtext"), - MovedModule("tkinter_simpledialog", "SimpleDialog", "tkinter.simpledialog"), - MovedModule("tkinter_tix", "Tix", "tkinter.tix"), - MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"), - MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"), - MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"), - MovedModule("tkinter_colorchooser", "tkColorChooser", "tkinter.colorchooser"), - MovedModule("tkinter_commondialog", "tkCommonDialog", "tkinter.commondialog"), - MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"), - MovedModule("tkinter_font", "tkFont", "tkinter.font"), - MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"), - MovedModule("tkinter_tksimpledialog", "tkSimpleDialog", "tkinter.simpledialog"), - MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"), - MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"), - MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"), - MovedModule("urllib_robotparser", "robotparser", "urllib.robotparser"), - MovedModule("xmlrpc_client", "xmlrpclib", "xmlrpc.client"), - MovedModule("xmlrpc_server", "SimpleXMLRPCServer", "xmlrpc.server"), -] -# Add windows specific modules. -if sys.platform == "win32": - _moved_attributes += [ - MovedModule("winreg", "_winreg"), - ] - -for attr in _moved_attributes: - setattr(_MovedItems, attr.name, attr) - if isinstance(attr, MovedModule): - _importer._add_module(attr, "moves." + attr.name) -del attr - -_MovedItems._moved_attributes = _moved_attributes - -moves = _MovedItems(__name__ + ".moves") -_importer._add_module(moves, "moves") - - -class Module_six_moves_urllib_parse(_LazyModule): - - """Lazy loading of moved objects in six.moves.urllib_parse""" - - -_urllib_parse_moved_attributes = [ - MovedAttribute("ParseResult", "urlparse", "urllib.parse"), - MovedAttribute("SplitResult", "urlparse", "urllib.parse"), - MovedAttribute("parse_qs", "urlparse", "urllib.parse"), - MovedAttribute("parse_qsl", "urlparse", "urllib.parse"), - MovedAttribute("urldefrag", "urlparse", "urllib.parse"), - MovedAttribute("urljoin", "urlparse", "urllib.parse"), - MovedAttribute("urlparse", "urlparse", "urllib.parse"), - MovedAttribute("urlsplit", "urlparse", "urllib.parse"), - MovedAttribute("urlunparse", "urlparse", "urllib.parse"), - MovedAttribute("urlunsplit", "urlparse", "urllib.parse"), - MovedAttribute("quote", "urllib", "urllib.parse"), - MovedAttribute("quote_plus", "urllib", "urllib.parse"), - MovedAttribute("unquote", "urllib", "urllib.parse"), - MovedAttribute("unquote_plus", "urllib", "urllib.parse"), - MovedAttribute( - "unquote_to_bytes", "urllib", "urllib.parse", "unquote", "unquote_to_bytes" - ), - MovedAttribute("urlencode", "urllib", "urllib.parse"), - MovedAttribute("splitquery", "urllib", "urllib.parse"), - MovedAttribute("splittag", "urllib", "urllib.parse"), - MovedAttribute("splituser", "urllib", "urllib.parse"), - MovedAttribute("splitvalue", "urllib", "urllib.parse"), - MovedAttribute("uses_fragment", "urlparse", "urllib.parse"), - MovedAttribute("uses_netloc", "urlparse", "urllib.parse"), - MovedAttribute("uses_params", "urlparse", "urllib.parse"), - MovedAttribute("uses_query", "urlparse", "urllib.parse"), - MovedAttribute("uses_relative", "urlparse", "urllib.parse"), -] -for attr in _urllib_parse_moved_attributes: - setattr(Module_six_moves_urllib_parse, attr.name, attr) -del attr - -Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes - -_importer._add_module( - Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"), - "moves.urllib_parse", - "moves.urllib.parse", -) - - -class Module_six_moves_urllib_error(_LazyModule): - - """Lazy loading of moved objects in six.moves.urllib_error""" - - -_urllib_error_moved_attributes = [ - MovedAttribute("URLError", "urllib2", "urllib.error"), - MovedAttribute("HTTPError", "urllib2", "urllib.error"), - MovedAttribute("ContentTooShortError", "urllib", "urllib.error"), -] -for attr in _urllib_error_moved_attributes: - setattr(Module_six_moves_urllib_error, attr.name, attr) -del attr - -Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes - -_importer._add_module( - Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"), - "moves.urllib_error", - "moves.urllib.error", -) - - -class Module_six_moves_urllib_request(_LazyModule): - - """Lazy loading of moved objects in six.moves.urllib_request""" - - -_urllib_request_moved_attributes = [ - MovedAttribute("urlopen", "urllib2", "urllib.request"), - MovedAttribute("install_opener", "urllib2", "urllib.request"), - MovedAttribute("build_opener", "urllib2", "urllib.request"), - MovedAttribute("pathname2url", "urllib", "urllib.request"), - MovedAttribute("url2pathname", "urllib", "urllib.request"), - MovedAttribute("getproxies", "urllib", "urllib.request"), - MovedAttribute("Request", "urllib2", "urllib.request"), - MovedAttribute("OpenerDirector", "urllib2", "urllib.request"), - MovedAttribute("HTTPDefaultErrorHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPRedirectHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPCookieProcessor", "urllib2", "urllib.request"), - MovedAttribute("ProxyHandler", "urllib2", "urllib.request"), - MovedAttribute("BaseHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPPasswordMgr", "urllib2", "urllib.request"), - MovedAttribute("HTTPPasswordMgrWithDefaultRealm", "urllib2", "urllib.request"), - MovedAttribute("AbstractBasicAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPBasicAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("ProxyBasicAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("AbstractDigestAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPDigestAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("ProxyDigestAuthHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPSHandler", "urllib2", "urllib.request"), - MovedAttribute("FileHandler", "urllib2", "urllib.request"), - MovedAttribute("FTPHandler", "urllib2", "urllib.request"), - MovedAttribute("CacheFTPHandler", "urllib2", "urllib.request"), - MovedAttribute("UnknownHandler", "urllib2", "urllib.request"), - MovedAttribute("HTTPErrorProcessor", "urllib2", "urllib.request"), - MovedAttribute("urlretrieve", "urllib", "urllib.request"), - MovedAttribute("urlcleanup", "urllib", "urllib.request"), - MovedAttribute("URLopener", "urllib", "urllib.request"), - MovedAttribute("FancyURLopener", "urllib", "urllib.request"), - MovedAttribute("proxy_bypass", "urllib", "urllib.request"), - MovedAttribute("parse_http_list", "urllib2", "urllib.request"), - MovedAttribute("parse_keqv_list", "urllib2", "urllib.request"), -] -for attr in _urllib_request_moved_attributes: - setattr(Module_six_moves_urllib_request, attr.name, attr) -del attr - -Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes - -_importer._add_module( - Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"), - "moves.urllib_request", - "moves.urllib.request", -) - - -class Module_six_moves_urllib_response(_LazyModule): - - """Lazy loading of moved objects in six.moves.urllib_response""" - - -_urllib_response_moved_attributes = [ - MovedAttribute("addbase", "urllib", "urllib.response"), - MovedAttribute("addclosehook", "urllib", "urllib.response"), - MovedAttribute("addinfo", "urllib", "urllib.response"), - MovedAttribute("addinfourl", "urllib", "urllib.response"), -] -for attr in _urllib_response_moved_attributes: - setattr(Module_six_moves_urllib_response, attr.name, attr) -del attr - -Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes - -_importer._add_module( - Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"), - "moves.urllib_response", - "moves.urllib.response", -) - - -class Module_six_moves_urllib_robotparser(_LazyModule): - - """Lazy loading of moved objects in six.moves.urllib_robotparser""" - - -_urllib_robotparser_moved_attributes = [ - MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"), -] -for attr in _urllib_robotparser_moved_attributes: - setattr(Module_six_moves_urllib_robotparser, attr.name, attr) -del attr - -Module_six_moves_urllib_robotparser._moved_attributes = ( - _urllib_robotparser_moved_attributes -) - -_importer._add_module( - Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"), - "moves.urllib_robotparser", - "moves.urllib.robotparser", -) - - -class Module_six_moves_urllib(types.ModuleType): - - """Create a six.moves.urllib namespace that resembles the Python 3 namespace""" - - __path__ = [] # mark as package - parse = _importer._get_module("moves.urllib_parse") - error = _importer._get_module("moves.urllib_error") - request = _importer._get_module("moves.urllib_request") - response = _importer._get_module("moves.urllib_response") - robotparser = _importer._get_module("moves.urllib_robotparser") - - def __dir__(self): - return ["parse", "error", "request", "response", "robotparser"] - - -_importer._add_module( - Module_six_moves_urllib(__name__ + ".moves.urllib"), "moves.urllib" -) - - -def add_move(move): - """Add an item to six.moves.""" - setattr(_MovedItems, move.name, move) - - -def remove_move(name): - """Remove item from six.moves.""" - try: - delattr(_MovedItems, name) - except AttributeError: - try: - del moves.__dict__[name] - except KeyError: - raise AttributeError("no such move, %r" % (name,)) - - -if PY3: - _meth_func = "__func__" - _meth_self = "__self__" - - _func_closure = "__closure__" - _func_code = "__code__" - _func_defaults = "__defaults__" - _func_globals = "__globals__" -else: - _meth_func = "im_func" - _meth_self = "im_self" - - _func_closure = "func_closure" - _func_code = "func_code" - _func_defaults = "func_defaults" - _func_globals = "func_globals" - - -try: - advance_iterator = next -except NameError: - - def advance_iterator(it): - return it.next() - - -next = advance_iterator - - -try: - callable = callable -except NameError: - - def callable(obj): - return any("__call__" in klass.__dict__ for klass in type(obj).__mro__) - - -if PY3: - - def get_unbound_function(unbound): - return unbound - - create_bound_method = types.MethodType - - def create_unbound_method(func, cls): - return func - - Iterator = object -else: - - def get_unbound_function(unbound): - return unbound.im_func - - def create_bound_method(func, obj): - return types.MethodType(func, obj, obj.__class__) - - def create_unbound_method(func, cls): - return types.MethodType(func, None, cls) - - class Iterator(object): - def next(self): - return type(self).__next__(self) - - callable = callable -_add_doc( - get_unbound_function, """Get the function out of a possibly unbound function""" -) - - -get_method_function = operator.attrgetter(_meth_func) -get_method_self = operator.attrgetter(_meth_self) -get_function_closure = operator.attrgetter(_func_closure) -get_function_code = operator.attrgetter(_func_code) -get_function_defaults = operator.attrgetter(_func_defaults) -get_function_globals = operator.attrgetter(_func_globals) - - -if PY3: - - def iterkeys(d, **kw): - return iter(d.keys(**kw)) - - def itervalues(d, **kw): - return iter(d.values(**kw)) - - def iteritems(d, **kw): - return iter(d.items(**kw)) - - def iterlists(d, **kw): - return iter(d.lists(**kw)) - - viewkeys = operator.methodcaller("keys") - - viewvalues = operator.methodcaller("values") - - viewitems = operator.methodcaller("items") -else: - - def iterkeys(d, **kw): - return d.iterkeys(**kw) - - def itervalues(d, **kw): - return d.itervalues(**kw) - - def iteritems(d, **kw): - return d.iteritems(**kw) - - def iterlists(d, **kw): - return d.iterlists(**kw) - - viewkeys = operator.methodcaller("viewkeys") - - viewvalues = operator.methodcaller("viewvalues") - - viewitems = operator.methodcaller("viewitems") - -_add_doc(iterkeys, "Return an iterator over the keys of a dictionary.") -_add_doc(itervalues, "Return an iterator over the values of a dictionary.") -_add_doc(iteritems, "Return an iterator over the (key, value) pairs of a dictionary.") -_add_doc( - iterlists, "Return an iterator over the (key, [values]) pairs of a dictionary." -) - - -if PY3: - - def b(s): - return s.encode("latin-1") - - def u(s): - return s - - unichr = chr - import struct - - int2byte = struct.Struct(">B").pack - del struct - byte2int = operator.itemgetter(0) - indexbytes = operator.getitem - iterbytes = iter - import io - - StringIO = io.StringIO - BytesIO = io.BytesIO - del io - _assertCountEqual = "assertCountEqual" - if sys.version_info[1] <= 1: - _assertRaisesRegex = "assertRaisesRegexp" - _assertRegex = "assertRegexpMatches" - _assertNotRegex = "assertNotRegexpMatches" - else: - _assertRaisesRegex = "assertRaisesRegex" - _assertRegex = "assertRegex" - _assertNotRegex = "assertNotRegex" -else: - - def b(s): - return s - - # Workaround for standalone backslash - - def u(s): - return unicode(s.replace(r"\\", r"\\\\"), "unicode_escape") - - unichr = unichr - int2byte = chr - - def byte2int(bs): - return ord(bs[0]) - - def indexbytes(buf, i): - return ord(buf[i]) - - iterbytes = functools.partial(itertools.imap, ord) - import StringIO - - StringIO = BytesIO = StringIO.StringIO - _assertCountEqual = "assertItemsEqual" - _assertRaisesRegex = "assertRaisesRegexp" - _assertRegex = "assertRegexpMatches" - _assertNotRegex = "assertNotRegexpMatches" -_add_doc(b, """Byte literal""") -_add_doc(u, """Text literal""") - - -def assertCountEqual(self, *args, **kwargs): - return getattr(self, _assertCountEqual)(*args, **kwargs) - - -def assertRaisesRegex(self, *args, **kwargs): - return getattr(self, _assertRaisesRegex)(*args, **kwargs) - - -def assertRegex(self, *args, **kwargs): - return getattr(self, _assertRegex)(*args, **kwargs) - - -def assertNotRegex(self, *args, **kwargs): - return getattr(self, _assertNotRegex)(*args, **kwargs) - - -if PY3: - exec_ = getattr(moves.builtins, "exec") - - def reraise(tp, value, tb=None): - try: - if value is None: - value = tp() - if value.__traceback__ is not tb: - raise value.with_traceback(tb) - raise value - finally: - value = None - tb = None - - -else: - - def exec_(_code_, _globs_=None, _locs_=None): - """Execute code in a namespace.""" - if _globs_ is None: - frame = sys._getframe(1) - _globs_ = frame.f_globals - if _locs_ is None: - _locs_ = frame.f_locals - del frame - elif _locs_ is None: - _locs_ = _globs_ - exec ("""exec _code_ in _globs_, _locs_""") - - exec_( - """def reraise(tp, value, tb=None): - try: - raise tp, value, tb - finally: - tb = None -""" - ) - - -if sys.version_info[:2] > (3,): - exec_( - """def raise_from(value, from_value): - try: - raise value from from_value - finally: - value = None -""" - ) -else: - - def raise_from(value, from_value): - raise value - - -print_ = getattr(moves.builtins, "print", None) -if print_ is None: - - def print_(*args, **kwargs): - """The new-style print function for Python 2.4 and 2.5.""" - fp = kwargs.pop("file", sys.stdout) - if fp is None: - return - - def write(data): - if not isinstance(data, basestring): - data = str(data) - # If the file has an encoding, encode unicode with it. - if ( - isinstance(fp, file) - and isinstance(data, unicode) - and fp.encoding is not None - ): - errors = getattr(fp, "errors", None) - if errors is None: - errors = "strict" - data = data.encode(fp.encoding, errors) - fp.write(data) - - want_unicode = False - sep = kwargs.pop("sep", None) - if sep is not None: - if isinstance(sep, unicode): - want_unicode = True - elif not isinstance(sep, str): - raise TypeError("sep must be None or a string") - end = kwargs.pop("end", None) - if end is not None: - if isinstance(end, unicode): - want_unicode = True - elif not isinstance(end, str): - raise TypeError("end must be None or a string") - if kwargs: - raise TypeError("invalid keyword arguments to print()") - if not want_unicode: - for arg in args: - if isinstance(arg, unicode): - want_unicode = True - break - if want_unicode: - newline = unicode("\n") - space = unicode(" ") - else: - newline = "\n" - space = " " - if sep is None: - sep = space - if end is None: - end = newline - for i, arg in enumerate(args): - if i: - write(sep) - write(arg) - write(end) - - -if sys.version_info[:2] < (3, 3): - _print = print_ - - def print_(*args, **kwargs): - fp = kwargs.get("file", sys.stdout) - flush = kwargs.pop("flush", False) - _print(*args, **kwargs) - if flush and fp is not None: - fp.flush() - - -_add_doc(reraise, """Reraise an exception.""") - -if sys.version_info[0:2] < (3, 4): - # This does exactly the same what the :func:`py3:functools.update_wrapper` - # function does on Python versions after 3.2. It sets the ``__wrapped__`` - # attribute on ``wrapper`` object and it doesn't raise an error if any of - # the attributes mentioned in ``assigned`` and ``updated`` are missing on - # ``wrapped`` object. - def _update_wrapper( - wrapper, - wrapped, - assigned=functools.WRAPPER_ASSIGNMENTS, - updated=functools.WRAPPER_UPDATES, - ): - for attr in assigned: - try: - value = getattr(wrapped, attr) - except AttributeError: - continue - else: - setattr(wrapper, attr, value) - for attr in updated: - getattr(wrapper, attr).update(getattr(wrapped, attr, {})) - wrapper.__wrapped__ = wrapped - return wrapper - - _update_wrapper.__doc__ = functools.update_wrapper.__doc__ - - def wraps( - wrapped, - assigned=functools.WRAPPER_ASSIGNMENTS, - updated=functools.WRAPPER_UPDATES, - ): - return functools.partial( - _update_wrapper, wrapped=wrapped, assigned=assigned, updated=updated - ) - - wraps.__doc__ = functools.wraps.__doc__ - -else: - wraps = functools.wraps - - -def with_metaclass(meta, *bases): - """Create a base class with a metaclass.""" - # This requires a bit of explanation: the basic idea is to make a dummy - # metaclass for one level of class instantiation that replaces itself with - # the actual metaclass. - class metaclass(type): - def __new__(cls, name, this_bases, d): - if sys.version_info[:2] >= (3, 7): - # This version introduced PEP 560 that requires a bit - # of extra care (we mimic what is done by __build_class__). - resolved_bases = types.resolve_bases(bases) - if resolved_bases is not bases: - d["__orig_bases__"] = bases - else: - resolved_bases = bases - return meta(name, resolved_bases, d) - - @classmethod - def __prepare__(cls, name, this_bases): - return meta.__prepare__(name, bases) - - return type.__new__(metaclass, "temporary_class", (), {}) - - -def add_metaclass(metaclass): - """Class decorator for creating a class with a metaclass.""" - - def wrapper(cls): - orig_vars = cls.__dict__.copy() - slots = orig_vars.get("__slots__") - if slots is not None: - if isinstance(slots, str): - slots = [slots] - for slots_var in slots: - orig_vars.pop(slots_var) - orig_vars.pop("__dict__", None) - orig_vars.pop("__weakref__", None) - if hasattr(cls, "__qualname__"): - orig_vars["__qualname__"] = cls.__qualname__ - return metaclass(cls.__name__, cls.__bases__, orig_vars) - - return wrapper - - -def ensure_binary(s, encoding="utf-8", errors="strict"): - """Coerce **s** to six.binary_type. - - For Python 2: - - `unicode` -> encoded to `str` - - `str` -> `str` - - For Python 3: - - `str` -> encoded to `bytes` - - `bytes` -> `bytes` - """ - if isinstance(s, binary_type): - return s - if isinstance(s, text_type): - return s.encode(encoding, errors) - raise TypeError("not expecting type '%s'" % type(s)) - - -def ensure_str(s, encoding="utf-8", errors="strict"): - """Coerce *s* to `str`. - - For Python 2: - - `unicode` -> encoded to `str` - - `str` -> `str` - - For Python 3: - - `str` -> `str` - - `bytes` -> decoded to `str` - """ - # Optimization: Fast return for the common case. - if type(s) is str: - return s - if PY2 and isinstance(s, text_type): - return s.encode(encoding, errors) - elif PY3 and isinstance(s, binary_type): - return s.decode(encoding, errors) - elif not isinstance(s, (text_type, binary_type)): - raise TypeError("not expecting type '%s'" % type(s)) - return s - - -def ensure_text(s, encoding="utf-8", errors="strict"): - """Coerce *s* to six.text_type. - - For Python 2: - - `unicode` -> `unicode` - - `str` -> `unicode` - - For Python 3: - - `str` -> `str` - - `bytes` -> decoded to `str` - """ - if isinstance(s, binary_type): - return s.decode(encoding, errors) - elif isinstance(s, text_type): - return s - else: - raise TypeError("not expecting type '%s'" % type(s)) - - -def python_2_unicode_compatible(klass): - """ - A class decorator that defines __unicode__ and __str__ methods under Python 2. - Under Python 3 it does nothing. - - To support Python 2 and 3 with a single code base, define a __str__ method - returning text and apply this decorator to the class. - """ - if PY2: - if "__str__" not in klass.__dict__: - raise ValueError( - "@python_2_unicode_compatible cannot be applied " - "to %s because it doesn't define __str__()." % klass.__name__ - ) - klass.__unicode__ = klass.__str__ - klass.__str__ = lambda self: self.__unicode__().encode("utf-8") - return klass - - -# Complete the moves implementation. -# This code is at the end of this module to speed up module loading. -# Turn this module into a package. -__path__ = [] # required for PEP 302 and PEP 451 -__package__ = __name__ # see PEP 366 @ReservedAssignment -if globals().get("__spec__") is not None: - __spec__.submodule_search_locations = [] # PEP 451 @UndefinedVariable -# Remove other six meta path importers, since they cause problems. This can -# happen if six is removed from sys.modules and then reloaded. (Setuptools does -# this for some reason.) -if sys.meta_path: - for i, importer in enumerate(sys.meta_path): - # Here's some real nastiness: Another "instance" of the six module might - # be floating around. Therefore, we can't use isinstance() to check for - # the six meta path importer, since the other six instance will have - # inserted an importer with different class. - if ( - type(importer).__name__ == "_SixMetaPathImporter" - and importer.name == __name__ - ): - del sys.meta_path[i] - break - del i, importer -# Finally, add the importer to the meta path import hook. -sys.meta_path.append(_importer) diff --git a/venv/lib/python3.8/site-packages/urllib3/packages/ssl_match_hostname/__init__.py b/venv/lib/python3.8/site-packages/urllib3/packages/ssl_match_hostname/__init__.py deleted file mode 100644 index ef3fde5..0000000 --- a/venv/lib/python3.8/site-packages/urllib3/packages/ssl_match_hostname/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -import sys - -try: - # Our match_hostname function is the same as 3.10's, so we only want to - # import the match_hostname function if it's at least that good. - # We also fallback on Python 3.10+ because our code doesn't emit - # deprecation warnings and is the same as Python 3.10 otherwise. - if sys.version_info < (3, 5) or sys.version_info >= (3, 10): - raise ImportError("Fallback to vendored code") - - from ssl import CertificateError, match_hostname -except ImportError: - try: - # Backport of the function from a pypi module - from backports.ssl_match_hostname import ( # type: ignore - CertificateError, - match_hostname, - ) - except ImportError: - # Our vendored copy - from ._implementation import CertificateError, match_hostname # type: ignore - -# Not needed, but documenting what we provide. -__all__ = ("CertificateError", "match_hostname") diff --git a/venv/lib/python3.8/site-packages/urllib3/packages/ssl_match_hostname/_implementation.py b/venv/lib/python3.8/site-packages/urllib3/packages/ssl_match_hostname/_implementation.py deleted file mode 100644 index 689208d..0000000 --- a/venv/lib/python3.8/site-packages/urllib3/packages/ssl_match_hostname/_implementation.py +++ /dev/null @@ -1,160 +0,0 @@ -"""The match_hostname() function from Python 3.3.3, essential when using SSL.""" - -# Note: This file is under the PSF license as the code comes from the python -# stdlib. http://docs.python.org/3/license.html - -import re -import sys - -# ipaddress has been backported to 2.6+ in pypi. If it is installed on the -# system, use it to handle IPAddress ServerAltnames (this was added in -# python-3.5) otherwise only do DNS matching. This allows -# backports.ssl_match_hostname to continue to be used in Python 2.7. -try: - import ipaddress -except ImportError: - ipaddress = None - -__version__ = "3.5.0.1" - - -class CertificateError(ValueError): - pass - - -def _dnsname_match(dn, hostname, max_wildcards=1): - """Matching according to RFC 6125, section 6.4.3 - - http://tools.ietf.org/html/rfc6125#section-6.4.3 - """ - pats = [] - if not dn: - return False - - # Ported from python3-syntax: - # leftmost, *remainder = dn.split(r'.') - parts = dn.split(r".") - leftmost = parts[0] - remainder = parts[1:] - - wildcards = leftmost.count("*") - if wildcards > max_wildcards: - # Issue #17980: avoid denials of service by refusing more - # than one wildcard per fragment. A survey of established - # policy among SSL implementations showed it to be a - # reasonable choice. - raise CertificateError( - "too many wildcards in certificate DNS name: " + repr(dn) - ) - - # speed up common case w/o wildcards - if not wildcards: - return dn.lower() == hostname.lower() - - # RFC 6125, section 6.4.3, subitem 1. - # The client SHOULD NOT attempt to match a presented identifier in which - # the wildcard character comprises a label other than the left-most label. - if leftmost == "*": - # When '*' is a fragment by itself, it matches a non-empty dotless - # fragment. - pats.append("[^.]+") - elif leftmost.startswith("xn--") or hostname.startswith("xn--"): - # RFC 6125, section 6.4.3, subitem 3. - # The client SHOULD NOT attempt to match a presented identifier - # where the wildcard character is embedded within an A-label or - # U-label of an internationalized domain name. - pats.append(re.escape(leftmost)) - else: - # Otherwise, '*' matches any dotless string, e.g. www* - pats.append(re.escape(leftmost).replace(r"\*", "[^.]*")) - - # add the remaining fragments, ignore any wildcards - for frag in remainder: - pats.append(re.escape(frag)) - - pat = re.compile(r"\A" + r"\.".join(pats) + r"\Z", re.IGNORECASE) - return pat.match(hostname) - - -def _to_unicode(obj): - if isinstance(obj, str) and sys.version_info < (3,): - obj = unicode(obj, encoding="ascii", errors="strict") - return obj - - -def _ipaddress_match(ipname, host_ip): - """Exact matching of IP addresses. - - RFC 6125 explicitly doesn't define an algorithm for this - (section 1.7.2 - "Out of Scope"). - """ - # OpenSSL may add a trailing newline to a subjectAltName's IP address - # Divergence from upstream: ipaddress can't handle byte str - ip = ipaddress.ip_address(_to_unicode(ipname).rstrip()) - return ip == host_ip - - -def match_hostname(cert, hostname): - """Verify that *cert* (in decoded format as returned by - SSLSocket.getpeercert()) matches the *hostname*. RFC 2818 and RFC 6125 - rules are followed, but IP addresses are not accepted for *hostname*. - - CertificateError is raised on failure. On success, the function - returns nothing. - """ - if not cert: - raise ValueError( - "empty or no certificate, match_hostname needs a " - "SSL socket or SSL context with either " - "CERT_OPTIONAL or CERT_REQUIRED" - ) - try: - # Divergence from upstream: ipaddress can't handle byte str - host_ip = ipaddress.ip_address(_to_unicode(hostname)) - except ValueError: - # Not an IP address (common case) - host_ip = None - except UnicodeError: - # Divergence from upstream: Have to deal with ipaddress not taking - # byte strings. addresses should be all ascii, so we consider it not - # an ipaddress in this case - host_ip = None - except AttributeError: - # Divergence from upstream: Make ipaddress library optional - if ipaddress is None: - host_ip = None - else: - raise - dnsnames = [] - san = cert.get("subjectAltName", ()) - for key, value in san: - if key == "DNS": - if host_ip is None and _dnsname_match(value, hostname): - return - dnsnames.append(value) - elif key == "IP Address": - if host_ip is not None and _ipaddress_match(value, host_ip): - return - dnsnames.append(value) - if not dnsnames: - # The subject is only checked when there is no dNSName entry - # in subjectAltName - for sub in cert.get("subject", ()): - for key, value in sub: - # XXX according to RFC 2818, the most specific Common Name - # must be used. - if key == "commonName": - if _dnsname_match(value, hostname): - return - dnsnames.append(value) - if len(dnsnames) > 1: - raise CertificateError( - "hostname %r " - "doesn't match either of %s" % (hostname, ", ".join(map(repr, dnsnames))) - ) - elif len(dnsnames) == 1: - raise CertificateError("hostname %r doesn't match %r" % (hostname, dnsnames[0])) - else: - raise CertificateError( - "no appropriate commonName or subjectAltName fields were found" - ) diff --git a/venv/lib/python3.8/site-packages/urllib3/poolmanager.py b/venv/lib/python3.8/site-packages/urllib3/poolmanager.py deleted file mode 100644 index 3a31a28..0000000 --- a/venv/lib/python3.8/site-packages/urllib3/poolmanager.py +++ /dev/null @@ -1,536 +0,0 @@ -from __future__ import absolute_import - -import collections -import functools -import logging - -from ._collections import RecentlyUsedContainer -from .connectionpool import HTTPConnectionPool, HTTPSConnectionPool, port_by_scheme -from .exceptions import ( - LocationValueError, - MaxRetryError, - ProxySchemeUnknown, - ProxySchemeUnsupported, - URLSchemeUnknown, -) -from .packages import six -from .packages.six.moves.urllib.parse import urljoin -from .request import RequestMethods -from .util.proxy import connection_requires_http_tunnel -from .util.retry import Retry -from .util.url import parse_url - -__all__ = ["PoolManager", "ProxyManager", "proxy_from_url"] - - -log = logging.getLogger(__name__) - -SSL_KEYWORDS = ( - "key_file", - "cert_file", - "cert_reqs", - "ca_certs", - "ssl_version", - "ca_cert_dir", - "ssl_context", - "key_password", -) - -# All known keyword arguments that could be provided to the pool manager, its -# pools, or the underlying connections. This is used to construct a pool key. -_key_fields = ( - "key_scheme", # str - "key_host", # str - "key_port", # int - "key_timeout", # int or float or Timeout - "key_retries", # int or Retry - "key_strict", # bool - "key_block", # bool - "key_source_address", # str - "key_key_file", # str - "key_key_password", # str - "key_cert_file", # str - "key_cert_reqs", # str - "key_ca_certs", # str - "key_ssl_version", # str - "key_ca_cert_dir", # str - "key_ssl_context", # instance of ssl.SSLContext or urllib3.util.ssl_.SSLContext - "key_maxsize", # int - "key_headers", # dict - "key__proxy", # parsed proxy url - "key__proxy_headers", # dict - "key__proxy_config", # class - "key_socket_options", # list of (level (int), optname (int), value (int or str)) tuples - "key__socks_options", # dict - "key_assert_hostname", # bool or string - "key_assert_fingerprint", # str - "key_server_hostname", # str -) - -#: The namedtuple class used to construct keys for the connection pool. -#: All custom key schemes should include the fields in this key at a minimum. -PoolKey = collections.namedtuple("PoolKey", _key_fields) - -_proxy_config_fields = ("ssl_context", "use_forwarding_for_https") -ProxyConfig = collections.namedtuple("ProxyConfig", _proxy_config_fields) - - -def _default_key_normalizer(key_class, request_context): - """ - Create a pool key out of a request context dictionary. - - According to RFC 3986, both the scheme and host are case-insensitive. - Therefore, this function normalizes both before constructing the pool - key for an HTTPS request. If you wish to change this behaviour, provide - alternate callables to ``key_fn_by_scheme``. - - :param key_class: - The class to use when constructing the key. This should be a namedtuple - with the ``scheme`` and ``host`` keys at a minimum. - :type key_class: namedtuple - :param request_context: - A dictionary-like object that contain the context for a request. - :type request_context: dict - - :return: A namedtuple that can be used as a connection pool key. - :rtype: PoolKey - """ - # Since we mutate the dictionary, make a copy first - context = request_context.copy() - context["scheme"] = context["scheme"].lower() - context["host"] = context["host"].lower() - - # These are both dictionaries and need to be transformed into frozensets - for key in ("headers", "_proxy_headers", "_socks_options"): - if key in context and context[key] is not None: - context[key] = frozenset(context[key].items()) - - # The socket_options key may be a list and needs to be transformed into a - # tuple. - socket_opts = context.get("socket_options") - if socket_opts is not None: - context["socket_options"] = tuple(socket_opts) - - # Map the kwargs to the names in the namedtuple - this is necessary since - # namedtuples can't have fields starting with '_'. - for key in list(context.keys()): - context["key_" + key] = context.pop(key) - - # Default to ``None`` for keys missing from the context - for field in key_class._fields: - if field not in context: - context[field] = None - - return key_class(**context) - - -#: A dictionary that maps a scheme to a callable that creates a pool key. -#: This can be used to alter the way pool keys are constructed, if desired. -#: Each PoolManager makes a copy of this dictionary so they can be configured -#: globally here, or individually on the instance. -key_fn_by_scheme = { - "http": functools.partial(_default_key_normalizer, PoolKey), - "https": functools.partial(_default_key_normalizer, PoolKey), -} - -pool_classes_by_scheme = {"http": HTTPConnectionPool, "https": HTTPSConnectionPool} - - -class PoolManager(RequestMethods): - """ - Allows for arbitrary requests while transparently keeping track of - necessary connection pools for you. - - :param num_pools: - Number of connection pools to cache before discarding the least - recently used pool. - - :param headers: - Headers to include with all requests, unless other headers are given - explicitly. - - :param \\**connection_pool_kw: - Additional parameters are used to create fresh - :class:`urllib3.connectionpool.ConnectionPool` instances. - - Example:: - - >>> manager = PoolManager(num_pools=2) - >>> r = manager.request('GET', 'http://google.com/') - >>> r = manager.request('GET', 'http://google.com/mail') - >>> r = manager.request('GET', 'http://yahoo.com/') - >>> len(manager.pools) - 2 - - """ - - proxy = None - proxy_config = None - - def __init__(self, num_pools=10, headers=None, **connection_pool_kw): - RequestMethods.__init__(self, headers) - self.connection_pool_kw = connection_pool_kw - self.pools = RecentlyUsedContainer(num_pools, dispose_func=lambda p: p.close()) - - # Locally set the pool classes and keys so other PoolManagers can - # override them. - self.pool_classes_by_scheme = pool_classes_by_scheme - self.key_fn_by_scheme = key_fn_by_scheme.copy() - - def __enter__(self): - return self - - def __exit__(self, exc_type, exc_val, exc_tb): - self.clear() - # Return False to re-raise any potential exceptions - return False - - def _new_pool(self, scheme, host, port, request_context=None): - """ - Create a new :class:`urllib3.connectionpool.ConnectionPool` based on host, port, scheme, and - any additional pool keyword arguments. - - If ``request_context`` is provided, it is provided as keyword arguments - to the pool class used. This method is used to actually create the - connection pools handed out by :meth:`connection_from_url` and - companion methods. It is intended to be overridden for customization. - """ - pool_cls = self.pool_classes_by_scheme[scheme] - if request_context is None: - request_context = self.connection_pool_kw.copy() - - # Although the context has everything necessary to create the pool, - # this function has historically only used the scheme, host, and port - # in the positional args. When an API change is acceptable these can - # be removed. - for key in ("scheme", "host", "port"): - request_context.pop(key, None) - - if scheme == "http": - for kw in SSL_KEYWORDS: - request_context.pop(kw, None) - - return pool_cls(host, port, **request_context) - - def clear(self): - """ - Empty our store of pools and direct them all to close. - - This will not affect in-flight connections, but they will not be - re-used after completion. - """ - self.pools.clear() - - def connection_from_host(self, host, port=None, scheme="http", pool_kwargs=None): - """ - Get a :class:`urllib3.connectionpool.ConnectionPool` based on the host, port, and scheme. - - If ``port`` isn't given, it will be derived from the ``scheme`` using - ``urllib3.connectionpool.port_by_scheme``. If ``pool_kwargs`` is - provided, it is merged with the instance's ``connection_pool_kw`` - variable and used to create the new connection pool, if one is - needed. - """ - - if not host: - raise LocationValueError("No host specified.") - - request_context = self._merge_pool_kwargs(pool_kwargs) - request_context["scheme"] = scheme or "http" - if not port: - port = port_by_scheme.get(request_context["scheme"].lower(), 80) - request_context["port"] = port - request_context["host"] = host - - return self.connection_from_context(request_context) - - def connection_from_context(self, request_context): - """ - Get a :class:`urllib3.connectionpool.ConnectionPool` based on the request context. - - ``request_context`` must at least contain the ``scheme`` key and its - value must be a key in ``key_fn_by_scheme`` instance variable. - """ - scheme = request_context["scheme"].lower() - pool_key_constructor = self.key_fn_by_scheme.get(scheme) - if not pool_key_constructor: - raise URLSchemeUnknown(scheme) - pool_key = pool_key_constructor(request_context) - - return self.connection_from_pool_key(pool_key, request_context=request_context) - - def connection_from_pool_key(self, pool_key, request_context=None): - """ - Get a :class:`urllib3.connectionpool.ConnectionPool` based on the provided pool key. - - ``pool_key`` should be a namedtuple that only contains immutable - objects. At a minimum it must have the ``scheme``, ``host``, and - ``port`` fields. - """ - with self.pools.lock: - # If the scheme, host, or port doesn't match existing open - # connections, open a new ConnectionPool. - pool = self.pools.get(pool_key) - if pool: - return pool - - # Make a fresh ConnectionPool of the desired type - scheme = request_context["scheme"] - host = request_context["host"] - port = request_context["port"] - pool = self._new_pool(scheme, host, port, request_context=request_context) - self.pools[pool_key] = pool - - return pool - - def connection_from_url(self, url, pool_kwargs=None): - """ - Similar to :func:`urllib3.connectionpool.connection_from_url`. - - If ``pool_kwargs`` is not provided and a new pool needs to be - constructed, ``self.connection_pool_kw`` is used to initialize - the :class:`urllib3.connectionpool.ConnectionPool`. If ``pool_kwargs`` - is provided, it is used instead. Note that if a new pool does not - need to be created for the request, the provided ``pool_kwargs`` are - not used. - """ - u = parse_url(url) - return self.connection_from_host( - u.host, port=u.port, scheme=u.scheme, pool_kwargs=pool_kwargs - ) - - def _merge_pool_kwargs(self, override): - """ - Merge a dictionary of override values for self.connection_pool_kw. - - This does not modify self.connection_pool_kw and returns a new dict. - Any keys in the override dictionary with a value of ``None`` are - removed from the merged dictionary. - """ - base_pool_kwargs = self.connection_pool_kw.copy() - if override: - for key, value in override.items(): - if value is None: - try: - del base_pool_kwargs[key] - except KeyError: - pass - else: - base_pool_kwargs[key] = value - return base_pool_kwargs - - def _proxy_requires_url_absolute_form(self, parsed_url): - """ - Indicates if the proxy requires the complete destination URL in the - request. Normally this is only needed when not using an HTTP CONNECT - tunnel. - """ - if self.proxy is None: - return False - - return not connection_requires_http_tunnel( - self.proxy, self.proxy_config, parsed_url.scheme - ) - - def _validate_proxy_scheme_url_selection(self, url_scheme): - """ - Validates that were not attempting to do TLS in TLS connections on - Python2 or with unsupported SSL implementations. - """ - if self.proxy is None or url_scheme != "https": - return - - if self.proxy.scheme != "https": - return - - if six.PY2 and not self.proxy_config.use_forwarding_for_https: - raise ProxySchemeUnsupported( - "Contacting HTTPS destinations through HTTPS proxies " - "'via CONNECT tunnels' is not supported in Python 2" - ) - - def urlopen(self, method, url, redirect=True, **kw): - """ - Same as :meth:`urllib3.HTTPConnectionPool.urlopen` - with custom cross-host redirect logic and only sends the request-uri - portion of the ``url``. - - The given ``url`` parameter must be absolute, such that an appropriate - :class:`urllib3.connectionpool.ConnectionPool` can be chosen for it. - """ - u = parse_url(url) - self._validate_proxy_scheme_url_selection(u.scheme) - - conn = self.connection_from_host(u.host, port=u.port, scheme=u.scheme) - - kw["assert_same_host"] = False - kw["redirect"] = False - - if "headers" not in kw: - kw["headers"] = self.headers.copy() - - if self._proxy_requires_url_absolute_form(u): - response = conn.urlopen(method, url, **kw) - else: - response = conn.urlopen(method, u.request_uri, **kw) - - redirect_location = redirect and response.get_redirect_location() - if not redirect_location: - return response - - # Support relative URLs for redirecting. - redirect_location = urljoin(url, redirect_location) - - # RFC 7231, Section 6.4.4 - if response.status == 303: - method = "GET" - - retries = kw.get("retries") - if not isinstance(retries, Retry): - retries = Retry.from_int(retries, redirect=redirect) - - # Strip headers marked as unsafe to forward to the redirected location. - # Check remove_headers_on_redirect to avoid a potential network call within - # conn.is_same_host() which may use socket.gethostbyname() in the future. - if retries.remove_headers_on_redirect and not conn.is_same_host( - redirect_location - ): - headers = list(six.iterkeys(kw["headers"])) - for header in headers: - if header.lower() in retries.remove_headers_on_redirect: - kw["headers"].pop(header, None) - - try: - retries = retries.increment(method, url, response=response, _pool=conn) - except MaxRetryError: - if retries.raise_on_redirect: - response.drain_conn() - raise - return response - - kw["retries"] = retries - kw["redirect"] = redirect - - log.info("Redirecting %s -> %s", url, redirect_location) - - response.drain_conn() - return self.urlopen(method, redirect_location, **kw) - - -class ProxyManager(PoolManager): - """ - Behaves just like :class:`PoolManager`, but sends all requests through - the defined proxy, using the CONNECT method for HTTPS URLs. - - :param proxy_url: - The URL of the proxy to be used. - - :param proxy_headers: - A dictionary containing headers that will be sent to the proxy. In case - of HTTP they are being sent with each request, while in the - HTTPS/CONNECT case they are sent only once. Could be used for proxy - authentication. - - :param proxy_ssl_context: - The proxy SSL context is used to establish the TLS connection to the - proxy when using HTTPS proxies. - - :param use_forwarding_for_https: - (Defaults to False) If set to True will forward requests to the HTTPS - proxy to be made on behalf of the client instead of creating a TLS - tunnel via the CONNECT method. **Enabling this flag means that request - and response headers and content will be visible from the HTTPS proxy** - whereas tunneling keeps request and response headers and content - private. IP address, target hostname, SNI, and port are always visible - to an HTTPS proxy even when this flag is disabled. - - Example: - >>> proxy = urllib3.ProxyManager('http://localhost:3128/') - >>> r1 = proxy.request('GET', 'http://google.com/') - >>> r2 = proxy.request('GET', 'http://httpbin.org/') - >>> len(proxy.pools) - 1 - >>> r3 = proxy.request('GET', 'https://httpbin.org/') - >>> r4 = proxy.request('GET', 'https://twitter.com/') - >>> len(proxy.pools) - 3 - - """ - - def __init__( - self, - proxy_url, - num_pools=10, - headers=None, - proxy_headers=None, - proxy_ssl_context=None, - use_forwarding_for_https=False, - **connection_pool_kw - ): - - if isinstance(proxy_url, HTTPConnectionPool): - proxy_url = "%s://%s:%i" % ( - proxy_url.scheme, - proxy_url.host, - proxy_url.port, - ) - proxy = parse_url(proxy_url) - - if proxy.scheme not in ("http", "https"): - raise ProxySchemeUnknown(proxy.scheme) - - if not proxy.port: - port = port_by_scheme.get(proxy.scheme, 80) - proxy = proxy._replace(port=port) - - self.proxy = proxy - self.proxy_headers = proxy_headers or {} - self.proxy_ssl_context = proxy_ssl_context - self.proxy_config = ProxyConfig(proxy_ssl_context, use_forwarding_for_https) - - connection_pool_kw["_proxy"] = self.proxy - connection_pool_kw["_proxy_headers"] = self.proxy_headers - connection_pool_kw["_proxy_config"] = self.proxy_config - - super(ProxyManager, self).__init__(num_pools, headers, **connection_pool_kw) - - def connection_from_host(self, host, port=None, scheme="http", pool_kwargs=None): - if scheme == "https": - return super(ProxyManager, self).connection_from_host( - host, port, scheme, pool_kwargs=pool_kwargs - ) - - return super(ProxyManager, self).connection_from_host( - self.proxy.host, self.proxy.port, self.proxy.scheme, pool_kwargs=pool_kwargs - ) - - def _set_proxy_headers(self, url, headers=None): - """ - Sets headers needed by proxies: specifically, the Accept and Host - headers. Only sets headers not provided by the user. - """ - headers_ = {"Accept": "*/*"} - - netloc = parse_url(url).netloc - if netloc: - headers_["Host"] = netloc - - if headers: - headers_.update(headers) - return headers_ - - def urlopen(self, method, url, redirect=True, **kw): - "Same as HTTP(S)ConnectionPool.urlopen, ``url`` must be absolute." - u = parse_url(url) - if not connection_requires_http_tunnel(self.proxy, self.proxy_config, u.scheme): - # For connections using HTTP CONNECT, httplib sets the necessary - # headers on the CONNECT to the proxy. If we're not using CONNECT, - # we'll definitely need to set 'Host' at the very least. - headers = kw.get("headers", self.headers) - kw["headers"] = self._set_proxy_headers(url, headers) - - return super(ProxyManager, self).urlopen(method, url, redirect=redirect, **kw) - - -def proxy_from_url(url, **kw): - return ProxyManager(proxy_url=url, **kw) diff --git a/venv/lib/python3.8/site-packages/urllib3/request.py b/venv/lib/python3.8/site-packages/urllib3/request.py deleted file mode 100644 index 398386a..0000000 --- a/venv/lib/python3.8/site-packages/urllib3/request.py +++ /dev/null @@ -1,170 +0,0 @@ -from __future__ import absolute_import - -from .filepost import encode_multipart_formdata -from .packages.six.moves.urllib.parse import urlencode - -__all__ = ["RequestMethods"] - - -class RequestMethods(object): - """ - Convenience mixin for classes who implement a :meth:`urlopen` method, such - as :class:`urllib3.HTTPConnectionPool` and - :class:`urllib3.PoolManager`. - - Provides behavior for making common types of HTTP request methods and - decides which type of request field encoding to use. - - Specifically, - - :meth:`.request_encode_url` is for sending requests whose fields are - encoded in the URL (such as GET, HEAD, DELETE). - - :meth:`.request_encode_body` is for sending requests whose fields are - encoded in the *body* of the request using multipart or www-form-urlencoded - (such as for POST, PUT, PATCH). - - :meth:`.request` is for making any kind of request, it will look up the - appropriate encoding format and use one of the above two methods to make - the request. - - Initializer parameters: - - :param headers: - Headers to include with all requests, unless other headers are given - explicitly. - """ - - _encode_url_methods = {"DELETE", "GET", "HEAD", "OPTIONS"} - - def __init__(self, headers=None): - self.headers = headers or {} - - def urlopen( - self, - method, - url, - body=None, - headers=None, - encode_multipart=True, - multipart_boundary=None, - **kw - ): # Abstract - raise NotImplementedError( - "Classes extending RequestMethods must implement " - "their own ``urlopen`` method." - ) - - def request(self, method, url, fields=None, headers=None, **urlopen_kw): - """ - Make a request using :meth:`urlopen` with the appropriate encoding of - ``fields`` based on the ``method`` used. - - This is a convenience method that requires the least amount of manual - effort. It can be used in most situations, while still having the - option to drop down to more specific methods when necessary, such as - :meth:`request_encode_url`, :meth:`request_encode_body`, - or even the lowest level :meth:`urlopen`. - """ - method = method.upper() - - urlopen_kw["request_url"] = url - - if method in self._encode_url_methods: - return self.request_encode_url( - method, url, fields=fields, headers=headers, **urlopen_kw - ) - else: - return self.request_encode_body( - method, url, fields=fields, headers=headers, **urlopen_kw - ) - - def request_encode_url(self, method, url, fields=None, headers=None, **urlopen_kw): - """ - Make a request using :meth:`urlopen` with the ``fields`` encoded in - the url. This is useful for request methods like GET, HEAD, DELETE, etc. - """ - if headers is None: - headers = self.headers - - extra_kw = {"headers": headers} - extra_kw.update(urlopen_kw) - - if fields: - url += "?" + urlencode(fields) - - return self.urlopen(method, url, **extra_kw) - - def request_encode_body( - self, - method, - url, - fields=None, - headers=None, - encode_multipart=True, - multipart_boundary=None, - **urlopen_kw - ): - """ - Make a request using :meth:`urlopen` with the ``fields`` encoded in - the body. This is useful for request methods like POST, PUT, PATCH, etc. - - When ``encode_multipart=True`` (default), then - :func:`urllib3.encode_multipart_formdata` is used to encode - the payload with the appropriate content type. Otherwise - :func:`urllib.parse.urlencode` is used with the - 'application/x-www-form-urlencoded' content type. - - Multipart encoding must be used when posting files, and it's reasonably - safe to use it in other times too. However, it may break request - signing, such as with OAuth. - - Supports an optional ``fields`` parameter of key/value strings AND - key/filetuple. A filetuple is a (filename, data, MIME type) tuple where - the MIME type is optional. For example:: - - fields = { - 'foo': 'bar', - 'fakefile': ('foofile.txt', 'contents of foofile'), - 'realfile': ('barfile.txt', open('realfile').read()), - 'typedfile': ('bazfile.bin', open('bazfile').read(), - 'image/jpeg'), - 'nonamefile': 'contents of nonamefile field', - } - - When uploading a file, providing a filename (the first parameter of the - tuple) is optional but recommended to best mimic behavior of browsers. - - Note that if ``headers`` are supplied, the 'Content-Type' header will - be overwritten because it depends on the dynamic random boundary string - which is used to compose the body of the request. The random boundary - string can be explicitly set with the ``multipart_boundary`` parameter. - """ - if headers is None: - headers = self.headers - - extra_kw = {"headers": {}} - - if fields: - if "body" in urlopen_kw: - raise TypeError( - "request got values for both 'fields' and 'body', can only specify one." - ) - - if encode_multipart: - body, content_type = encode_multipart_formdata( - fields, boundary=multipart_boundary - ) - else: - body, content_type = ( - urlencode(fields), - "application/x-www-form-urlencoded", - ) - - extra_kw["body"] = body - extra_kw["headers"] = {"Content-Type": content_type} - - extra_kw["headers"].update(headers) - extra_kw.update(urlopen_kw) - - return self.urlopen(method, url, **extra_kw) diff --git a/venv/lib/python3.8/site-packages/urllib3/response.py b/venv/lib/python3.8/site-packages/urllib3/response.py deleted file mode 100644 index 38693f4..0000000 --- a/venv/lib/python3.8/site-packages/urllib3/response.py +++ /dev/null @@ -1,821 +0,0 @@ -from __future__ import absolute_import - -import io -import logging -import zlib -from contextlib import contextmanager -from socket import error as SocketError -from socket import timeout as SocketTimeout - -try: - import brotli -except ImportError: - brotli = None - -from ._collections import HTTPHeaderDict -from .connection import BaseSSLError, HTTPException -from .exceptions import ( - BodyNotHttplibCompatible, - DecodeError, - HTTPError, - IncompleteRead, - InvalidChunkLength, - InvalidHeader, - ProtocolError, - ReadTimeoutError, - ResponseNotChunked, - SSLError, -) -from .packages import six -from .util.response import is_fp_closed, is_response_to_head - -log = logging.getLogger(__name__) - - -class DeflateDecoder(object): - def __init__(self): - self._first_try = True - self._data = b"" - self._obj = zlib.decompressobj() - - def __getattr__(self, name): - return getattr(self._obj, name) - - def decompress(self, data): - if not data: - return data - - if not self._first_try: - return self._obj.decompress(data) - - self._data += data - try: - decompressed = self._obj.decompress(data) - if decompressed: - self._first_try = False - self._data = None - return decompressed - except zlib.error: - self._first_try = False - self._obj = zlib.decompressobj(-zlib.MAX_WBITS) - try: - return self.decompress(self._data) - finally: - self._data = None - - -class GzipDecoderState(object): - - FIRST_MEMBER = 0 - OTHER_MEMBERS = 1 - SWALLOW_DATA = 2 - - -class GzipDecoder(object): - def __init__(self): - self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS) - self._state = GzipDecoderState.FIRST_MEMBER - - def __getattr__(self, name): - return getattr(self._obj, name) - - def decompress(self, data): - ret = bytearray() - if self._state == GzipDecoderState.SWALLOW_DATA or not data: - return bytes(ret) - while True: - try: - ret += self._obj.decompress(data) - except zlib.error: - previous_state = self._state - # Ignore data after the first error - self._state = GzipDecoderState.SWALLOW_DATA - if previous_state == GzipDecoderState.OTHER_MEMBERS: - # Allow trailing garbage acceptable in other gzip clients - return bytes(ret) - raise - data = self._obj.unused_data - if not data: - return bytes(ret) - self._state = GzipDecoderState.OTHER_MEMBERS - self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS) - - -if brotli is not None: - - class BrotliDecoder(object): - # Supports both 'brotlipy' and 'Brotli' packages - # since they share an import name. The top branches - # are for 'brotlipy' and bottom branches for 'Brotli' - def __init__(self): - self._obj = brotli.Decompressor() - if hasattr(self._obj, "decompress"): - self.decompress = self._obj.decompress - else: - self.decompress = self._obj.process - - def flush(self): - if hasattr(self._obj, "flush"): - return self._obj.flush() - return b"" - - -class MultiDecoder(object): - """ - From RFC7231: - If one or more encodings have been applied to a representation, the - sender that applied the encodings MUST generate a Content-Encoding - header field that lists the content codings in the order in which - they were applied. - """ - - def __init__(self, modes): - self._decoders = [_get_decoder(m.strip()) for m in modes.split(",")] - - def flush(self): - return self._decoders[0].flush() - - def decompress(self, data): - for d in reversed(self._decoders): - data = d.decompress(data) - return data - - -def _get_decoder(mode): - if "," in mode: - return MultiDecoder(mode) - - if mode == "gzip": - return GzipDecoder() - - if brotli is not None and mode == "br": - return BrotliDecoder() - - return DeflateDecoder() - - -class HTTPResponse(io.IOBase): - """ - HTTP Response container. - - Backwards-compatible with :class:`http.client.HTTPResponse` but the response ``body`` is - loaded and decoded on-demand when the ``data`` property is accessed. This - class is also compatible with the Python standard library's :mod:`io` - module, and can hence be treated as a readable object in the context of that - framework. - - Extra parameters for behaviour not present in :class:`http.client.HTTPResponse`: - - :param preload_content: - If True, the response's body will be preloaded during construction. - - :param decode_content: - If True, will attempt to decode the body based on the - 'content-encoding' header. - - :param original_response: - When this HTTPResponse wrapper is generated from an :class:`http.client.HTTPResponse` - object, it's convenient to include the original for debug purposes. It's - otherwise unused. - - :param retries: - The retries contains the last :class:`~urllib3.util.retry.Retry` that - was used during the request. - - :param enforce_content_length: - Enforce content length checking. Body returned by server must match - value of Content-Length header, if present. Otherwise, raise error. - """ - - CONTENT_DECODERS = ["gzip", "deflate"] - if brotli is not None: - CONTENT_DECODERS += ["br"] - REDIRECT_STATUSES = [301, 302, 303, 307, 308] - - def __init__( - self, - body="", - headers=None, - status=0, - version=0, - reason=None, - strict=0, - preload_content=True, - decode_content=True, - original_response=None, - pool=None, - connection=None, - msg=None, - retries=None, - enforce_content_length=False, - request_method=None, - request_url=None, - auto_close=True, - ): - - if isinstance(headers, HTTPHeaderDict): - self.headers = headers - else: - self.headers = HTTPHeaderDict(headers) - self.status = status - self.version = version - self.reason = reason - self.strict = strict - self.decode_content = decode_content - self.retries = retries - self.enforce_content_length = enforce_content_length - self.auto_close = auto_close - - self._decoder = None - self._body = None - self._fp = None - self._original_response = original_response - self._fp_bytes_read = 0 - self.msg = msg - self._request_url = request_url - - if body and isinstance(body, (six.string_types, bytes)): - self._body = body - - self._pool = pool - self._connection = connection - - if hasattr(body, "read"): - self._fp = body - - # Are we using the chunked-style of transfer encoding? - self.chunked = False - self.chunk_left = None - tr_enc = self.headers.get("transfer-encoding", "").lower() - # Don't incur the penalty of creating a list and then discarding it - encodings = (enc.strip() for enc in tr_enc.split(",")) - if "chunked" in encodings: - self.chunked = True - - # Determine length of response - self.length_remaining = self._init_length(request_method) - - # If requested, preload the body. - if preload_content and not self._body: - self._body = self.read(decode_content=decode_content) - - def get_redirect_location(self): - """ - Should we redirect and where to? - - :returns: Truthy redirect location string if we got a redirect status - code and valid location. ``None`` if redirect status and no - location. ``False`` if not a redirect status code. - """ - if self.status in self.REDIRECT_STATUSES: - return self.headers.get("location") - - return False - - def release_conn(self): - if not self._pool or not self._connection: - return - - self._pool._put_conn(self._connection) - self._connection = None - - def drain_conn(self): - """ - Read and discard any remaining HTTP response data in the response connection. - - Unread data in the HTTPResponse connection blocks the connection from being released back to the pool. - """ - try: - self.read() - except (HTTPError, SocketError, BaseSSLError, HTTPException): - pass - - @property - def data(self): - # For backwards-compat with earlier urllib3 0.4 and earlier. - if self._body: - return self._body - - if self._fp: - return self.read(cache_content=True) - - @property - def connection(self): - return self._connection - - def isclosed(self): - return is_fp_closed(self._fp) - - def tell(self): - """ - Obtain the number of bytes pulled over the wire so far. May differ from - the amount of content returned by :meth:``urllib3.response.HTTPResponse.read`` - if bytes are encoded on the wire (e.g, compressed). - """ - return self._fp_bytes_read - - def _init_length(self, request_method): - """ - Set initial length value for Response content if available. - """ - length = self.headers.get("content-length") - - if length is not None: - if self.chunked: - # This Response will fail with an IncompleteRead if it can't be - # received as chunked. This method falls back to attempt reading - # the response before raising an exception. - log.warning( - "Received response with both Content-Length and " - "Transfer-Encoding set. This is expressly forbidden " - "by RFC 7230 sec 3.3.2. Ignoring Content-Length and " - "attempting to process response as Transfer-Encoding: " - "chunked." - ) - return None - - try: - # RFC 7230 section 3.3.2 specifies multiple content lengths can - # be sent in a single Content-Length header - # (e.g. Content-Length: 42, 42). This line ensures the values - # are all valid ints and that as long as the `set` length is 1, - # all values are the same. Otherwise, the header is invalid. - lengths = set([int(val) for val in length.split(",")]) - if len(lengths) > 1: - raise InvalidHeader( - "Content-Length contained multiple " - "unmatching values (%s)" % length - ) - length = lengths.pop() - except ValueError: - length = None - else: - if length < 0: - length = None - - # Convert status to int for comparison - # In some cases, httplib returns a status of "_UNKNOWN" - try: - status = int(self.status) - except ValueError: - status = 0 - - # Check for responses that shouldn't include a body - if status in (204, 304) or 100 <= status < 200 or request_method == "HEAD": - length = 0 - - return length - - def _init_decoder(self): - """ - Set-up the _decoder attribute if necessary. - """ - # Note: content-encoding value should be case-insensitive, per RFC 7230 - # Section 3.2 - content_encoding = self.headers.get("content-encoding", "").lower() - if self._decoder is None: - if content_encoding in self.CONTENT_DECODERS: - self._decoder = _get_decoder(content_encoding) - elif "," in content_encoding: - encodings = [ - e.strip() - for e in content_encoding.split(",") - if e.strip() in self.CONTENT_DECODERS - ] - if len(encodings): - self._decoder = _get_decoder(content_encoding) - - DECODER_ERROR_CLASSES = (IOError, zlib.error) - if brotli is not None: - DECODER_ERROR_CLASSES += (brotli.error,) - - def _decode(self, data, decode_content, flush_decoder): - """ - Decode the data passed in and potentially flush the decoder. - """ - if not decode_content: - return data - - try: - if self._decoder: - data = self._decoder.decompress(data) - except self.DECODER_ERROR_CLASSES as e: - content_encoding = self.headers.get("content-encoding", "").lower() - raise DecodeError( - "Received response with content-encoding: %s, but " - "failed to decode it." % content_encoding, - e, - ) - if flush_decoder: - data += self._flush_decoder() - - return data - - def _flush_decoder(self): - """ - Flushes the decoder. Should only be called if the decoder is actually - being used. - """ - if self._decoder: - buf = self._decoder.decompress(b"") - return buf + self._decoder.flush() - - return b"" - - @contextmanager - def _error_catcher(self): - """ - Catch low-level python exceptions, instead re-raising urllib3 - variants, so that low-level exceptions are not leaked in the - high-level api. - - On exit, release the connection back to the pool. - """ - clean_exit = False - - try: - try: - yield - - except SocketTimeout: - # FIXME: Ideally we'd like to include the url in the ReadTimeoutError but - # there is yet no clean way to get at it from this context. - raise ReadTimeoutError(self._pool, None, "Read timed out.") - - except BaseSSLError as e: - # FIXME: Is there a better way to differentiate between SSLErrors? - if "read operation timed out" not in str(e): - # SSL errors related to framing/MAC get wrapped and reraised here - raise SSLError(e) - - raise ReadTimeoutError(self._pool, None, "Read timed out.") - - except (HTTPException, SocketError) as e: - # This includes IncompleteRead. - raise ProtocolError("Connection broken: %r" % e, e) - - # If no exception is thrown, we should avoid cleaning up - # unnecessarily. - clean_exit = True - finally: - # If we didn't terminate cleanly, we need to throw away our - # connection. - if not clean_exit: - # The response may not be closed but we're not going to use it - # anymore so close it now to ensure that the connection is - # released back to the pool. - if self._original_response: - self._original_response.close() - - # Closing the response may not actually be sufficient to close - # everything, so if we have a hold of the connection close that - # too. - if self._connection: - self._connection.close() - - # If we hold the original response but it's closed now, we should - # return the connection back to the pool. - if self._original_response and self._original_response.isclosed(): - self.release_conn() - - def read(self, amt=None, decode_content=None, cache_content=False): - """ - Similar to :meth:`http.client.HTTPResponse.read`, but with two additional - parameters: ``decode_content`` and ``cache_content``. - - :param amt: - How much of the content to read. If specified, caching is skipped - because it doesn't make sense to cache partial content as the full - response. - - :param decode_content: - If True, will attempt to decode the body based on the - 'content-encoding' header. - - :param cache_content: - If True, will save the returned data such that the same result is - returned despite of the state of the underlying file object. This - is useful if you want the ``.data`` property to continue working - after having ``.read()`` the file object. (Overridden if ``amt`` is - set.) - """ - self._init_decoder() - if decode_content is None: - decode_content = self.decode_content - - if self._fp is None: - return - - flush_decoder = False - fp_closed = getattr(self._fp, "closed", False) - - with self._error_catcher(): - if amt is None: - # cStringIO doesn't like amt=None - data = self._fp.read() if not fp_closed else b"" - flush_decoder = True - else: - cache_content = False - data = self._fp.read(amt) if not fp_closed else b"" - if ( - amt != 0 and not data - ): # Platform-specific: Buggy versions of Python. - # Close the connection when no data is returned - # - # This is redundant to what httplib/http.client _should_ - # already do. However, versions of python released before - # December 15, 2012 (http://bugs.python.org/issue16298) do - # not properly close the connection in all cases. There is - # no harm in redundantly calling close. - self._fp.close() - flush_decoder = True - if self.enforce_content_length and self.length_remaining not in ( - 0, - None, - ): - # This is an edge case that httplib failed to cover due - # to concerns of backward compatibility. We're - # addressing it here to make sure IncompleteRead is - # raised during streaming, so all calls with incorrect - # Content-Length are caught. - raise IncompleteRead(self._fp_bytes_read, self.length_remaining) - - if data: - self._fp_bytes_read += len(data) - if self.length_remaining is not None: - self.length_remaining -= len(data) - - data = self._decode(data, decode_content, flush_decoder) - - if cache_content: - self._body = data - - return data - - def stream(self, amt=2 ** 16, decode_content=None): - """ - A generator wrapper for the read() method. A call will block until - ``amt`` bytes have been read from the connection or until the - connection is closed. - - :param amt: - How much of the content to read. The generator will return up to - much data per iteration, but may return less. This is particularly - likely when using compressed data. However, the empty string will - never be returned. - - :param decode_content: - If True, will attempt to decode the body based on the - 'content-encoding' header. - """ - if self.chunked and self.supports_chunked_reads(): - for line in self.read_chunked(amt, decode_content=decode_content): - yield line - else: - while not is_fp_closed(self._fp): - data = self.read(amt=amt, decode_content=decode_content) - - if data: - yield data - - @classmethod - def from_httplib(ResponseCls, r, **response_kw): - """ - Given an :class:`http.client.HTTPResponse` instance ``r``, return a - corresponding :class:`urllib3.response.HTTPResponse` object. - - Remaining parameters are passed to the HTTPResponse constructor, along - with ``original_response=r``. - """ - headers = r.msg - - if not isinstance(headers, HTTPHeaderDict): - if six.PY2: - # Python 2.7 - headers = HTTPHeaderDict.from_httplib(headers) - else: - headers = HTTPHeaderDict(headers.items()) - - # HTTPResponse objects in Python 3 don't have a .strict attribute - strict = getattr(r, "strict", 0) - resp = ResponseCls( - body=r, - headers=headers, - status=r.status, - version=r.version, - reason=r.reason, - strict=strict, - original_response=r, - **response_kw - ) - return resp - - # Backwards-compatibility methods for http.client.HTTPResponse - def getheaders(self): - return self.headers - - def getheader(self, name, default=None): - return self.headers.get(name, default) - - # Backwards compatibility for http.cookiejar - def info(self): - return self.headers - - # Overrides from io.IOBase - def close(self): - if not self.closed: - self._fp.close() - - if self._connection: - self._connection.close() - - if not self.auto_close: - io.IOBase.close(self) - - @property - def closed(self): - if not self.auto_close: - return io.IOBase.closed.__get__(self) - elif self._fp is None: - return True - elif hasattr(self._fp, "isclosed"): - return self._fp.isclosed() - elif hasattr(self._fp, "closed"): - return self._fp.closed - else: - return True - - def fileno(self): - if self._fp is None: - raise IOError("HTTPResponse has no file to get a fileno from") - elif hasattr(self._fp, "fileno"): - return self._fp.fileno() - else: - raise IOError( - "The file-like object this HTTPResponse is wrapped " - "around has no file descriptor" - ) - - def flush(self): - if ( - self._fp is not None - and hasattr(self._fp, "flush") - and not getattr(self._fp, "closed", False) - ): - return self._fp.flush() - - def readable(self): - # This method is required for `io` module compatibility. - return True - - def readinto(self, b): - # This method is required for `io` module compatibility. - temp = self.read(len(b)) - if len(temp) == 0: - return 0 - else: - b[: len(temp)] = temp - return len(temp) - - def supports_chunked_reads(self): - """ - Checks if the underlying file-like object looks like a - :class:`http.client.HTTPResponse` object. We do this by testing for - the fp attribute. If it is present we assume it returns raw chunks as - processed by read_chunked(). - """ - return hasattr(self._fp, "fp") - - def _update_chunk_length(self): - # First, we'll figure out length of a chunk and then - # we'll try to read it from socket. - if self.chunk_left is not None: - return - line = self._fp.fp.readline() - line = line.split(b";", 1)[0] - try: - self.chunk_left = int(line, 16) - except ValueError: - # Invalid chunked protocol response, abort. - self.close() - raise InvalidChunkLength(self, line) - - def _handle_chunk(self, amt): - returned_chunk = None - if amt is None: - chunk = self._fp._safe_read(self.chunk_left) - returned_chunk = chunk - self._fp._safe_read(2) # Toss the CRLF at the end of the chunk. - self.chunk_left = None - elif amt < self.chunk_left: - value = self._fp._safe_read(amt) - self.chunk_left = self.chunk_left - amt - returned_chunk = value - elif amt == self.chunk_left: - value = self._fp._safe_read(amt) - self._fp._safe_read(2) # Toss the CRLF at the end of the chunk. - self.chunk_left = None - returned_chunk = value - else: # amt > self.chunk_left - returned_chunk = self._fp._safe_read(self.chunk_left) - self._fp._safe_read(2) # Toss the CRLF at the end of the chunk. - self.chunk_left = None - return returned_chunk - - def read_chunked(self, amt=None, decode_content=None): - """ - Similar to :meth:`HTTPResponse.read`, but with an additional - parameter: ``decode_content``. - - :param amt: - How much of the content to read. If specified, caching is skipped - because it doesn't make sense to cache partial content as the full - response. - - :param decode_content: - If True, will attempt to decode the body based on the - 'content-encoding' header. - """ - self._init_decoder() - # FIXME: Rewrite this method and make it a class with a better structured logic. - if not self.chunked: - raise ResponseNotChunked( - "Response is not chunked. " - "Header 'transfer-encoding: chunked' is missing." - ) - if not self.supports_chunked_reads(): - raise BodyNotHttplibCompatible( - "Body should be http.client.HTTPResponse like. " - "It should have have an fp attribute which returns raw chunks." - ) - - with self._error_catcher(): - # Don't bother reading the body of a HEAD request. - if self._original_response and is_response_to_head(self._original_response): - self._original_response.close() - return - - # If a response is already read and closed - # then return immediately. - if self._fp.fp is None: - return - - while True: - self._update_chunk_length() - if self.chunk_left == 0: - break - chunk = self._handle_chunk(amt) - decoded = self._decode( - chunk, decode_content=decode_content, flush_decoder=False - ) - if decoded: - yield decoded - - if decode_content: - # On CPython and PyPy, we should never need to flush the - # decoder. However, on Jython we *might* need to, so - # lets defensively do it anyway. - decoded = self._flush_decoder() - if decoded: # Platform-specific: Jython. - yield decoded - - # Chunk content ends with \r\n: discard it. - while True: - line = self._fp.fp.readline() - if not line: - # Some sites may not end with '\r\n'. - break - if line == b"\r\n": - break - - # We read everything; close the "file". - if self._original_response: - self._original_response.close() - - def geturl(self): - """ - Returns the URL that was the source of this response. - If the request that generated this response redirected, this method - will return the final redirect location. - """ - if self.retries is not None and len(self.retries.history): - return self.retries.history[-1].redirect_location - else: - return self._request_url - - def __iter__(self): - buffer = [] - for chunk in self.stream(decode_content=True): - if b"\n" in chunk: - chunk = chunk.split(b"\n") - yield b"".join(buffer) + chunk[0] + b"\n" - for x in chunk[1:-1]: - yield x + b"\n" - if chunk[-1]: - buffer = [chunk[-1]] - else: - buffer = [] - else: - buffer.append(chunk) - if buffer: - yield b"".join(buffer) diff --git a/venv/lib/python3.8/site-packages/urllib3/util/__init__.py b/venv/lib/python3.8/site-packages/urllib3/util/__init__.py deleted file mode 100644 index 4547fc5..0000000 --- a/venv/lib/python3.8/site-packages/urllib3/util/__init__.py +++ /dev/null @@ -1,49 +0,0 @@ -from __future__ import absolute_import - -# For backwards compatibility, provide imports that used to be here. -from .connection import is_connection_dropped -from .request import SKIP_HEADER, SKIPPABLE_HEADERS, make_headers -from .response import is_fp_closed -from .retry import Retry -from .ssl_ import ( - ALPN_PROTOCOLS, - HAS_SNI, - IS_PYOPENSSL, - IS_SECURETRANSPORT, - PROTOCOL_TLS, - SSLContext, - assert_fingerprint, - resolve_cert_reqs, - resolve_ssl_version, - ssl_wrap_socket, -) -from .timeout import Timeout, current_time -from .url import Url, get_host, parse_url, split_first -from .wait import wait_for_read, wait_for_write - -__all__ = ( - "HAS_SNI", - "IS_PYOPENSSL", - "IS_SECURETRANSPORT", - "SSLContext", - "PROTOCOL_TLS", - "ALPN_PROTOCOLS", - "Retry", - "Timeout", - "Url", - "assert_fingerprint", - "current_time", - "is_connection_dropped", - "is_fp_closed", - "get_host", - "parse_url", - "make_headers", - "resolve_cert_reqs", - "resolve_ssl_version", - "split_first", - "ssl_wrap_socket", - "wait_for_read", - "wait_for_write", - "SKIP_HEADER", - "SKIPPABLE_HEADERS", -) diff --git a/venv/lib/python3.8/site-packages/urllib3/util/connection.py b/venv/lib/python3.8/site-packages/urllib3/util/connection.py deleted file mode 100644 index bdc240c..0000000 --- a/venv/lib/python3.8/site-packages/urllib3/util/connection.py +++ /dev/null @@ -1,150 +0,0 @@ -from __future__ import absolute_import - -import socket - -from urllib3.exceptions import LocationParseError - -from ..contrib import _appengine_environ -from ..packages import six -from .wait import NoWayToWaitForSocketError, wait_for_read - - -def is_connection_dropped(conn): # Platform-specific - """ - Returns True if the connection is dropped and should be closed. - - :param conn: - :class:`http.client.HTTPConnection` object. - - Note: For platforms like AppEngine, this will always return ``False`` to - let the platform handle connection recycling transparently for us. - """ - sock = getattr(conn, "sock", False) - if sock is False: # Platform-specific: AppEngine - return False - if sock is None: # Connection already closed (such as by httplib). - return True - try: - # Returns True if readable, which here means it's been dropped - return wait_for_read(sock, timeout=0.0) - except NoWayToWaitForSocketError: # Platform-specific: AppEngine - return False - - -# This function is copied from socket.py in the Python 2.7 standard -# library test suite. Added to its signature is only `socket_options`. -# One additional modification is that we avoid binding to IPv6 servers -# discovered in DNS if the system doesn't have IPv6 functionality. -def create_connection( - address, - timeout=socket._GLOBAL_DEFAULT_TIMEOUT, - source_address=None, - socket_options=None, -): - """Connect to *address* and return the socket object. - - Convenience function. Connect to *address* (a 2-tuple ``(host, - port)``) and return the socket object. Passing the optional - *timeout* parameter will set the timeout on the socket instance - before attempting to connect. If no *timeout* is supplied, the - global default timeout setting returned by :func:`socket.getdefaulttimeout` - is used. If *source_address* is set it must be a tuple of (host, port) - for the socket to bind as a source address before making the connection. - An host of '' or port 0 tells the OS to use the default. - """ - - host, port = address - if host.startswith("["): - host = host.strip("[]") - err = None - - # Using the value from allowed_gai_family() in the context of getaddrinfo lets - # us select whether to work with IPv4 DNS records, IPv6 records, or both. - # The original create_connection function always returns all records. - family = allowed_gai_family() - - try: - host.encode("idna") - except UnicodeError: - return six.raise_from( - LocationParseError(u"'%s', label empty or too long" % host), None - ) - - for res in socket.getaddrinfo(host, port, family, socket.SOCK_STREAM): - af, socktype, proto, canonname, sa = res - sock = None - try: - sock = socket.socket(af, socktype, proto) - - # If provided, set socket level options before connecting. - _set_socket_options(sock, socket_options) - - if timeout is not socket._GLOBAL_DEFAULT_TIMEOUT: - sock.settimeout(timeout) - if source_address: - sock.bind(source_address) - sock.connect(sa) - return sock - - except socket.error as e: - err = e - if sock is not None: - sock.close() - sock = None - - if err is not None: - raise err - - raise socket.error("getaddrinfo returns an empty list") - - -def _set_socket_options(sock, options): - if options is None: - return - - for opt in options: - sock.setsockopt(*opt) - - -def allowed_gai_family(): - """This function is designed to work in the context of - getaddrinfo, where family=socket.AF_UNSPEC is the default and - will perform a DNS search for both IPv6 and IPv4 records.""" - - family = socket.AF_INET - if HAS_IPV6: - family = socket.AF_UNSPEC - return family - - -def _has_ipv6(host): - """Returns True if the system can bind an IPv6 address.""" - sock = None - has_ipv6 = False - - # App Engine doesn't support IPV6 sockets and actually has a quota on the - # number of sockets that can be used, so just early out here instead of - # creating a socket needlessly. - # See https://github.com/urllib3/urllib3/issues/1446 - if _appengine_environ.is_appengine_sandbox(): - return False - - if socket.has_ipv6: - # has_ipv6 returns true if cPython was compiled with IPv6 support. - # It does not tell us if the system has IPv6 support enabled. To - # determine that we must bind to an IPv6 address. - # https://github.com/urllib3/urllib3/pull/611 - # https://bugs.python.org/issue658327 - try: - sock = socket.socket(socket.AF_INET6) - sock.bind((host, 0)) - has_ipv6 = True - except Exception: - pass - - if sock: - sock.close() - return has_ipv6 - - -HAS_IPV6 = _has_ipv6("::1") diff --git a/venv/lib/python3.8/site-packages/urllib3/util/proxy.py b/venv/lib/python3.8/site-packages/urllib3/util/proxy.py deleted file mode 100644 index 34f884d..0000000 --- a/venv/lib/python3.8/site-packages/urllib3/util/proxy.py +++ /dev/null @@ -1,56 +0,0 @@ -from .ssl_ import create_urllib3_context, resolve_cert_reqs, resolve_ssl_version - - -def connection_requires_http_tunnel( - proxy_url=None, proxy_config=None, destination_scheme=None -): - """ - Returns True if the connection requires an HTTP CONNECT through the proxy. - - :param URL proxy_url: - URL of the proxy. - :param ProxyConfig proxy_config: - Proxy configuration from poolmanager.py - :param str destination_scheme: - The scheme of the destination. (i.e https, http, etc) - """ - # If we're not using a proxy, no way to use a tunnel. - if proxy_url is None: - return False - - # HTTP destinations never require tunneling, we always forward. - if destination_scheme == "http": - return False - - # Support for forwarding with HTTPS proxies and HTTPS destinations. - if ( - proxy_url.scheme == "https" - and proxy_config - and proxy_config.use_forwarding_for_https - ): - return False - - # Otherwise always use a tunnel. - return True - - -def create_proxy_ssl_context( - ssl_version, cert_reqs, ca_certs=None, ca_cert_dir=None, ca_cert_data=None -): - """ - Generates a default proxy ssl context if one hasn't been provided by the - user. - """ - ssl_context = create_urllib3_context( - ssl_version=resolve_ssl_version(ssl_version), - cert_reqs=resolve_cert_reqs(cert_reqs), - ) - if ( - not ca_certs - and not ca_cert_dir - and not ca_cert_data - and hasattr(ssl_context, "load_default_certs") - ): - ssl_context.load_default_certs() - - return ssl_context diff --git a/venv/lib/python3.8/site-packages/urllib3/util/queue.py b/venv/lib/python3.8/site-packages/urllib3/util/queue.py deleted file mode 100644 index 4178410..0000000 --- a/venv/lib/python3.8/site-packages/urllib3/util/queue.py +++ /dev/null @@ -1,22 +0,0 @@ -import collections - -from ..packages import six -from ..packages.six.moves import queue - -if six.PY2: - # Queue is imported for side effects on MS Windows. See issue #229. - import Queue as _unused_module_Queue # noqa: F401 - - -class LifoQueue(queue.Queue): - def _init(self, _): - self.queue = collections.deque() - - def _qsize(self, len=len): - return len(self.queue) - - def _put(self, item): - self.queue.append(item) - - def _get(self): - return self.queue.pop() diff --git a/venv/lib/python3.8/site-packages/urllib3/util/request.py b/venv/lib/python3.8/site-packages/urllib3/util/request.py deleted file mode 100644 index 2510338..0000000 --- a/venv/lib/python3.8/site-packages/urllib3/util/request.py +++ /dev/null @@ -1,143 +0,0 @@ -from __future__ import absolute_import - -from base64 import b64encode - -from ..exceptions import UnrewindableBodyError -from ..packages.six import b, integer_types - -# Pass as a value within ``headers`` to skip -# emitting some HTTP headers that are added automatically. -# The only headers that are supported are ``Accept-Encoding``, -# ``Host``, and ``User-Agent``. -SKIP_HEADER = "@@@SKIP_HEADER@@@" -SKIPPABLE_HEADERS = frozenset(["accept-encoding", "host", "user-agent"]) - -ACCEPT_ENCODING = "gzip,deflate" -try: - import brotli as _unused_module_brotli # noqa: F401 -except ImportError: - pass -else: - ACCEPT_ENCODING += ",br" - -_FAILEDTELL = object() - - -def make_headers( - keep_alive=None, - accept_encoding=None, - user_agent=None, - basic_auth=None, - proxy_basic_auth=None, - disable_cache=None, -): - """ - Shortcuts for generating request headers. - - :param keep_alive: - If ``True``, adds 'connection: keep-alive' header. - - :param accept_encoding: - Can be a boolean, list, or string. - ``True`` translates to 'gzip,deflate'. - List will get joined by comma. - String will be used as provided. - - :param user_agent: - String representing the user-agent you want, such as - "python-urllib3/0.6" - - :param basic_auth: - Colon-separated username:password string for 'authorization: basic ...' - auth header. - - :param proxy_basic_auth: - Colon-separated username:password string for 'proxy-authorization: basic ...' - auth header. - - :param disable_cache: - If ``True``, adds 'cache-control: no-cache' header. - - Example:: - - >>> make_headers(keep_alive=True, user_agent="Batman/1.0") - {'connection': 'keep-alive', 'user-agent': 'Batman/1.0'} - >>> make_headers(accept_encoding=True) - {'accept-encoding': 'gzip,deflate'} - """ - headers = {} - if accept_encoding: - if isinstance(accept_encoding, str): - pass - elif isinstance(accept_encoding, list): - accept_encoding = ",".join(accept_encoding) - else: - accept_encoding = ACCEPT_ENCODING - headers["accept-encoding"] = accept_encoding - - if user_agent: - headers["user-agent"] = user_agent - - if keep_alive: - headers["connection"] = "keep-alive" - - if basic_auth: - headers["authorization"] = "Basic " + b64encode(b(basic_auth)).decode("utf-8") - - if proxy_basic_auth: - headers["proxy-authorization"] = "Basic " + b64encode( - b(proxy_basic_auth) - ).decode("utf-8") - - if disable_cache: - headers["cache-control"] = "no-cache" - - return headers - - -def set_file_position(body, pos): - """ - If a position is provided, move file to that point. - Otherwise, we'll attempt to record a position for future use. - """ - if pos is not None: - rewind_body(body, pos) - elif getattr(body, "tell", None) is not None: - try: - pos = body.tell() - except (IOError, OSError): - # This differentiates from None, allowing us to catch - # a failed `tell()` later when trying to rewind the body. - pos = _FAILEDTELL - - return pos - - -def rewind_body(body, body_pos): - """ - Attempt to rewind body to a certain position. - Primarily used for request redirects and retries. - - :param body: - File-like object that supports seek. - - :param int pos: - Position to seek to in file. - """ - body_seek = getattr(body, "seek", None) - if body_seek is not None and isinstance(body_pos, integer_types): - try: - body_seek(body_pos) - except (IOError, OSError): - raise UnrewindableBodyError( - "An error occurred when rewinding request body for redirect/retry." - ) - elif body_pos is _FAILEDTELL: - raise UnrewindableBodyError( - "Unable to record file position for rewinding " - "request body during a redirect/retry." - ) - else: - raise ValueError( - "body_pos must be of type integer, instead it was %s." % type(body_pos) - ) diff --git a/venv/lib/python3.8/site-packages/urllib3/util/response.py b/venv/lib/python3.8/site-packages/urllib3/util/response.py deleted file mode 100644 index 5ea609c..0000000 --- a/venv/lib/python3.8/site-packages/urllib3/util/response.py +++ /dev/null @@ -1,107 +0,0 @@ -from __future__ import absolute_import - -from email.errors import MultipartInvariantViolationDefect, StartBoundaryNotFoundDefect - -from ..exceptions import HeaderParsingError -from ..packages.six.moves import http_client as httplib - - -def is_fp_closed(obj): - """ - Checks whether a given file-like object is closed. - - :param obj: - The file-like object to check. - """ - - try: - # Check `isclosed()` first, in case Python3 doesn't set `closed`. - # GH Issue #928 - return obj.isclosed() - except AttributeError: - pass - - try: - # Check via the official file-like-object way. - return obj.closed - except AttributeError: - pass - - try: - # Check if the object is a container for another file-like object that - # gets released on exhaustion (e.g. HTTPResponse). - return obj.fp is None - except AttributeError: - pass - - raise ValueError("Unable to determine whether fp is closed.") - - -def assert_header_parsing(headers): - """ - Asserts whether all headers have been successfully parsed. - Extracts encountered errors from the result of parsing headers. - - Only works on Python 3. - - :param http.client.HTTPMessage headers: Headers to verify. - - :raises urllib3.exceptions.HeaderParsingError: - If parsing errors are found. - """ - - # This will fail silently if we pass in the wrong kind of parameter. - # To make debugging easier add an explicit check. - if not isinstance(headers, httplib.HTTPMessage): - raise TypeError("expected httplib.Message, got {0}.".format(type(headers))) - - defects = getattr(headers, "defects", None) - get_payload = getattr(headers, "get_payload", None) - - unparsed_data = None - if get_payload: - # get_payload is actually email.message.Message.get_payload; - # we're only interested in the result if it's not a multipart message - if not headers.is_multipart(): - payload = get_payload() - - if isinstance(payload, (bytes, str)): - unparsed_data = payload - if defects: - # httplib is assuming a response body is available - # when parsing headers even when httplib only sends - # header data to parse_headers() This results in - # defects on multipart responses in particular. - # See: https://github.com/urllib3/urllib3/issues/800 - - # So we ignore the following defects: - # - StartBoundaryNotFoundDefect: - # The claimed start boundary was never found. - # - MultipartInvariantViolationDefect: - # A message claimed to be a multipart but no subparts were found. - defects = [ - defect - for defect in defects - if not isinstance( - defect, (StartBoundaryNotFoundDefect, MultipartInvariantViolationDefect) - ) - ] - - if defects or unparsed_data: - raise HeaderParsingError(defects=defects, unparsed_data=unparsed_data) - - -def is_response_to_head(response): - """ - Checks whether the request of a response has been a HEAD-request. - Handles the quirks of AppEngine. - - :param http.client.HTTPResponse response: - Response to check if the originating request - used 'HEAD' as a method. - """ - # FIXME: Can we do this somehow without accessing private httplib _method? - method = response._method - if isinstance(method, int): # Platform-specific: Appengine - return method == 3 - return method.upper() == "HEAD" diff --git a/venv/lib/python3.8/site-packages/urllib3/util/retry.py b/venv/lib/python3.8/site-packages/urllib3/util/retry.py deleted file mode 100644 index c7dc42f..0000000 --- a/venv/lib/python3.8/site-packages/urllib3/util/retry.py +++ /dev/null @@ -1,602 +0,0 @@ -from __future__ import absolute_import - -import email -import logging -import re -import time -import warnings -from collections import namedtuple -from itertools import takewhile - -from ..exceptions import ( - ConnectTimeoutError, - InvalidHeader, - MaxRetryError, - ProtocolError, - ProxyError, - ReadTimeoutError, - ResponseError, -) -from ..packages import six - -log = logging.getLogger(__name__) - - -# Data structure for representing the metadata of requests that result in a retry. -RequestHistory = namedtuple( - "RequestHistory", ["method", "url", "error", "status", "redirect_location"] -) - - -# TODO: In v2 we can remove this sentinel and metaclass with deprecated options. -_Default = object() - - -class _RetryMeta(type): - @property - def DEFAULT_METHOD_WHITELIST(cls): - warnings.warn( - "Using 'Retry.DEFAULT_METHOD_WHITELIST' is deprecated and " - "will be removed in v2.0. Use 'Retry.DEFAULT_ALLOWED_METHODS' instead", - DeprecationWarning, - ) - return cls.DEFAULT_ALLOWED_METHODS - - @DEFAULT_METHOD_WHITELIST.setter - def DEFAULT_METHOD_WHITELIST(cls, value): - warnings.warn( - "Using 'Retry.DEFAULT_METHOD_WHITELIST' is deprecated and " - "will be removed in v2.0. Use 'Retry.DEFAULT_ALLOWED_METHODS' instead", - DeprecationWarning, - ) - cls.DEFAULT_ALLOWED_METHODS = value - - @property - def DEFAULT_REDIRECT_HEADERS_BLACKLIST(cls): - warnings.warn( - "Using 'Retry.DEFAULT_REDIRECT_HEADERS_BLACKLIST' is deprecated and " - "will be removed in v2.0. Use 'Retry.DEFAULT_REMOVE_HEADERS_ON_REDIRECT' instead", - DeprecationWarning, - ) - return cls.DEFAULT_REMOVE_HEADERS_ON_REDIRECT - - @DEFAULT_REDIRECT_HEADERS_BLACKLIST.setter - def DEFAULT_REDIRECT_HEADERS_BLACKLIST(cls, value): - warnings.warn( - "Using 'Retry.DEFAULT_REDIRECT_HEADERS_BLACKLIST' is deprecated and " - "will be removed in v2.0. Use 'Retry.DEFAULT_REMOVE_HEADERS_ON_REDIRECT' instead", - DeprecationWarning, - ) - cls.DEFAULT_REMOVE_HEADERS_ON_REDIRECT = value - - -@six.add_metaclass(_RetryMeta) -class Retry(object): - """Retry configuration. - - Each retry attempt will create a new Retry object with updated values, so - they can be safely reused. - - Retries can be defined as a default for a pool:: - - retries = Retry(connect=5, read=2, redirect=5) - http = PoolManager(retries=retries) - response = http.request('GET', 'http://example.com/') - - Or per-request (which overrides the default for the pool):: - - response = http.request('GET', 'http://example.com/', retries=Retry(10)) - - Retries can be disabled by passing ``False``:: - - response = http.request('GET', 'http://example.com/', retries=False) - - Errors will be wrapped in :class:`~urllib3.exceptions.MaxRetryError` unless - retries are disabled, in which case the causing exception will be raised. - - :param int total: - Total number of retries to allow. Takes precedence over other counts. - - Set to ``None`` to remove this constraint and fall back on other - counts. - - Set to ``0`` to fail on the first retry. - - Set to ``False`` to disable and imply ``raise_on_redirect=False``. - - :param int connect: - How many connection-related errors to retry on. - - These are errors raised before the request is sent to the remote server, - which we assume has not triggered the server to process the request. - - Set to ``0`` to fail on the first retry of this type. - - :param int read: - How many times to retry on read errors. - - These errors are raised after the request was sent to the server, so the - request may have side-effects. - - Set to ``0`` to fail on the first retry of this type. - - :param int redirect: - How many redirects to perform. Limit this to avoid infinite redirect - loops. - - A redirect is a HTTP response with a status code 301, 302, 303, 307 or - 308. - - Set to ``0`` to fail on the first retry of this type. - - Set to ``False`` to disable and imply ``raise_on_redirect=False``. - - :param int status: - How many times to retry on bad status codes. - - These are retries made on responses, where status code matches - ``status_forcelist``. - - Set to ``0`` to fail on the first retry of this type. - - :param int other: - How many times to retry on other errors. - - Other errors are errors that are not connect, read, redirect or status errors. - These errors might be raised after the request was sent to the server, so the - request might have side-effects. - - Set to ``0`` to fail on the first retry of this type. - - If ``total`` is not set, it's a good idea to set this to 0 to account - for unexpected edge cases and avoid infinite retry loops. - - :param iterable allowed_methods: - Set of uppercased HTTP method verbs that we should retry on. - - By default, we only retry on methods which are considered to be - idempotent (multiple requests with the same parameters end with the - same state). See :attr:`Retry.DEFAULT_ALLOWED_METHODS`. - - Set to a ``False`` value to retry on any verb. - - .. warning:: - - Previously this parameter was named ``method_whitelist``, that - usage is deprecated in v1.26.0 and will be removed in v2.0. - - :param iterable status_forcelist: - A set of integer HTTP status codes that we should force a retry on. - A retry is initiated if the request method is in ``allowed_methods`` - and the response status code is in ``status_forcelist``. - - By default, this is disabled with ``None``. - - :param float backoff_factor: - A backoff factor to apply between attempts after the second try - (most errors are resolved immediately by a second try without a - delay). urllib3 will sleep for:: - - {backoff factor} * (2 ** ({number of total retries} - 1)) - - seconds. If the backoff_factor is 0.1, then :func:`.sleep` will sleep - for [0.0s, 0.2s, 0.4s, ...] between retries. It will never be longer - than :attr:`Retry.BACKOFF_MAX`. - - By default, backoff is disabled (set to 0). - - :param bool raise_on_redirect: Whether, if the number of redirects is - exhausted, to raise a MaxRetryError, or to return a response with a - response code in the 3xx range. - - :param bool raise_on_status: Similar meaning to ``raise_on_redirect``: - whether we should raise an exception, or return a response, - if status falls in ``status_forcelist`` range and retries have - been exhausted. - - :param tuple history: The history of the request encountered during - each call to :meth:`~Retry.increment`. The list is in the order - the requests occurred. Each list item is of class :class:`RequestHistory`. - - :param bool respect_retry_after_header: - Whether to respect Retry-After header on status codes defined as - :attr:`Retry.RETRY_AFTER_STATUS_CODES` or not. - - :param iterable remove_headers_on_redirect: - Sequence of headers to remove from the request when a response - indicating a redirect is returned before firing off the redirected - request. - """ - - #: Default methods to be used for ``allowed_methods`` - DEFAULT_ALLOWED_METHODS = frozenset( - ["HEAD", "GET", "PUT", "DELETE", "OPTIONS", "TRACE"] - ) - - #: Default status codes to be used for ``status_forcelist`` - RETRY_AFTER_STATUS_CODES = frozenset([413, 429, 503]) - - #: Default headers to be used for ``remove_headers_on_redirect`` - DEFAULT_REMOVE_HEADERS_ON_REDIRECT = frozenset(["Authorization"]) - - #: Maximum backoff time. - BACKOFF_MAX = 120 - - def __init__( - self, - total=10, - connect=None, - read=None, - redirect=None, - status=None, - other=None, - allowed_methods=_Default, - status_forcelist=None, - backoff_factor=0, - raise_on_redirect=True, - raise_on_status=True, - history=None, - respect_retry_after_header=True, - remove_headers_on_redirect=_Default, - # TODO: Deprecated, remove in v2.0 - method_whitelist=_Default, - ): - - if method_whitelist is not _Default: - if allowed_methods is not _Default: - raise ValueError( - "Using both 'allowed_methods' and " - "'method_whitelist' together is not allowed. " - "Instead only use 'allowed_methods'" - ) - warnings.warn( - "Using 'method_whitelist' with Retry is deprecated and " - "will be removed in v2.0. Use 'allowed_methods' instead", - DeprecationWarning, - stacklevel=2, - ) - allowed_methods = method_whitelist - if allowed_methods is _Default: - allowed_methods = self.DEFAULT_ALLOWED_METHODS - if remove_headers_on_redirect is _Default: - remove_headers_on_redirect = self.DEFAULT_REMOVE_HEADERS_ON_REDIRECT - - self.total = total - self.connect = connect - self.read = read - self.status = status - self.other = other - - if redirect is False or total is False: - redirect = 0 - raise_on_redirect = False - - self.redirect = redirect - self.status_forcelist = status_forcelist or set() - self.allowed_methods = allowed_methods - self.backoff_factor = backoff_factor - self.raise_on_redirect = raise_on_redirect - self.raise_on_status = raise_on_status - self.history = history or tuple() - self.respect_retry_after_header = respect_retry_after_header - self.remove_headers_on_redirect = frozenset( - [h.lower() for h in remove_headers_on_redirect] - ) - - def new(self, **kw): - params = dict( - total=self.total, - connect=self.connect, - read=self.read, - redirect=self.redirect, - status=self.status, - other=self.other, - status_forcelist=self.status_forcelist, - backoff_factor=self.backoff_factor, - raise_on_redirect=self.raise_on_redirect, - raise_on_status=self.raise_on_status, - history=self.history, - remove_headers_on_redirect=self.remove_headers_on_redirect, - respect_retry_after_header=self.respect_retry_after_header, - ) - - # TODO: If already given in **kw we use what's given to us - # If not given we need to figure out what to pass. We decide - # based on whether our class has the 'method_whitelist' property - # and if so we pass the deprecated 'method_whitelist' otherwise - # we use 'allowed_methods'. Remove in v2.0 - if "method_whitelist" not in kw and "allowed_methods" not in kw: - if "method_whitelist" in self.__dict__: - warnings.warn( - "Using 'method_whitelist' with Retry is deprecated and " - "will be removed in v2.0. Use 'allowed_methods' instead", - DeprecationWarning, - ) - params["method_whitelist"] = self.allowed_methods - else: - params["allowed_methods"] = self.allowed_methods - - params.update(kw) - return type(self)(**params) - - @classmethod - def from_int(cls, retries, redirect=True, default=None): - """Backwards-compatibility for the old retries format.""" - if retries is None: - retries = default if default is not None else cls.DEFAULT - - if isinstance(retries, Retry): - return retries - - redirect = bool(redirect) and None - new_retries = cls(retries, redirect=redirect) - log.debug("Converted retries value: %r -> %r", retries, new_retries) - return new_retries - - def get_backoff_time(self): - """Formula for computing the current backoff - - :rtype: float - """ - # We want to consider only the last consecutive errors sequence (Ignore redirects). - consecutive_errors_len = len( - list( - takewhile(lambda x: x.redirect_location is None, reversed(self.history)) - ) - ) - if consecutive_errors_len <= 1: - return 0 - - backoff_value = self.backoff_factor * (2 ** (consecutive_errors_len - 1)) - return min(self.BACKOFF_MAX, backoff_value) - - def parse_retry_after(self, retry_after): - # Whitespace: https://tools.ietf.org/html/rfc7230#section-3.2.4 - if re.match(r"^\s*[0-9]+\s*$", retry_after): - seconds = int(retry_after) - else: - retry_date_tuple = email.utils.parsedate_tz(retry_after) - if retry_date_tuple is None: - raise InvalidHeader("Invalid Retry-After header: %s" % retry_after) - if retry_date_tuple[9] is None: # Python 2 - # Assume UTC if no timezone was specified - # On Python2.7, parsedate_tz returns None for a timezone offset - # instead of 0 if no timezone is given, where mktime_tz treats - # a None timezone offset as local time. - retry_date_tuple = retry_date_tuple[:9] + (0,) + retry_date_tuple[10:] - - retry_date = email.utils.mktime_tz(retry_date_tuple) - seconds = retry_date - time.time() - - if seconds < 0: - seconds = 0 - - return seconds - - def get_retry_after(self, response): - """Get the value of Retry-After in seconds.""" - - retry_after = response.getheader("Retry-After") - - if retry_after is None: - return None - - return self.parse_retry_after(retry_after) - - def sleep_for_retry(self, response=None): - retry_after = self.get_retry_after(response) - if retry_after: - time.sleep(retry_after) - return True - - return False - - def _sleep_backoff(self): - backoff = self.get_backoff_time() - if backoff <= 0: - return - time.sleep(backoff) - - def sleep(self, response=None): - """Sleep between retry attempts. - - This method will respect a server's ``Retry-After`` response header - and sleep the duration of the time requested. If that is not present, it - will use an exponential backoff. By default, the backoff factor is 0 and - this method will return immediately. - """ - - if self.respect_retry_after_header and response: - slept = self.sleep_for_retry(response) - if slept: - return - - self._sleep_backoff() - - def _is_connection_error(self, err): - """Errors when we're fairly sure that the server did not receive the - request, so it should be safe to retry. - """ - if isinstance(err, ProxyError): - err = err.original_error - return isinstance(err, ConnectTimeoutError) - - def _is_read_error(self, err): - """Errors that occur after the request has been started, so we should - assume that the server began processing it. - """ - return isinstance(err, (ReadTimeoutError, ProtocolError)) - - def _is_method_retryable(self, method): - """Checks if a given HTTP method should be retried upon, depending if - it is included in the allowed_methods - """ - # TODO: For now favor if the Retry implementation sets its own method_whitelist - # property outside of our constructor to avoid breaking custom implementations. - if "method_whitelist" in self.__dict__: - warnings.warn( - "Using 'method_whitelist' with Retry is deprecated and " - "will be removed in v2.0. Use 'allowed_methods' instead", - DeprecationWarning, - ) - allowed_methods = self.method_whitelist - else: - allowed_methods = self.allowed_methods - - if allowed_methods and method.upper() not in allowed_methods: - return False - return True - - def is_retry(self, method, status_code, has_retry_after=False): - """Is this method/status code retryable? (Based on allowlists and control - variables such as the number of total retries to allow, whether to - respect the Retry-After header, whether this header is present, and - whether the returned status code is on the list of status codes to - be retried upon on the presence of the aforementioned header) - """ - if not self._is_method_retryable(method): - return False - - if self.status_forcelist and status_code in self.status_forcelist: - return True - - return ( - self.total - and self.respect_retry_after_header - and has_retry_after - and (status_code in self.RETRY_AFTER_STATUS_CODES) - ) - - def is_exhausted(self): - """Are we out of retries?""" - retry_counts = ( - self.total, - self.connect, - self.read, - self.redirect, - self.status, - self.other, - ) - retry_counts = list(filter(None, retry_counts)) - if not retry_counts: - return False - - return min(retry_counts) < 0 - - def increment( - self, - method=None, - url=None, - response=None, - error=None, - _pool=None, - _stacktrace=None, - ): - """Return a new Retry object with incremented retry counters. - - :param response: A response object, or None, if the server did not - return a response. - :type response: :class:`~urllib3.response.HTTPResponse` - :param Exception error: An error encountered during the request, or - None if the response was received successfully. - - :return: A new ``Retry`` object. - """ - if self.total is False and error: - # Disabled, indicate to re-raise the error. - raise six.reraise(type(error), error, _stacktrace) - - total = self.total - if total is not None: - total -= 1 - - connect = self.connect - read = self.read - redirect = self.redirect - status_count = self.status - other = self.other - cause = "unknown" - status = None - redirect_location = None - - if error and self._is_connection_error(error): - # Connect retry? - if connect is False: - raise six.reraise(type(error), error, _stacktrace) - elif connect is not None: - connect -= 1 - - elif error and self._is_read_error(error): - # Read retry? - if read is False or not self._is_method_retryable(method): - raise six.reraise(type(error), error, _stacktrace) - elif read is not None: - read -= 1 - - elif error: - # Other retry? - if other is not None: - other -= 1 - - elif response and response.get_redirect_location(): - # Redirect retry? - if redirect is not None: - redirect -= 1 - cause = "too many redirects" - redirect_location = response.get_redirect_location() - status = response.status - - else: - # Incrementing because of a server error like a 500 in - # status_forcelist and the given method is in the allowed_methods - cause = ResponseError.GENERIC_ERROR - if response and response.status: - if status_count is not None: - status_count -= 1 - cause = ResponseError.SPECIFIC_ERROR.format(status_code=response.status) - status = response.status - - history = self.history + ( - RequestHistory(method, url, error, status, redirect_location), - ) - - new_retry = self.new( - total=total, - connect=connect, - read=read, - redirect=redirect, - status=status_count, - other=other, - history=history, - ) - - if new_retry.is_exhausted(): - raise MaxRetryError(_pool, url, error or ResponseError(cause)) - - log.debug("Incremented Retry for (url='%s'): %r", url, new_retry) - - return new_retry - - def __repr__(self): - return ( - "{cls.__name__}(total={self.total}, connect={self.connect}, " - "read={self.read}, redirect={self.redirect}, status={self.status})" - ).format(cls=type(self), self=self) - - def __getattr__(self, item): - if item == "method_whitelist": - # TODO: Remove this deprecated alias in v2.0 - warnings.warn( - "Using 'method_whitelist' with Retry is deprecated and " - "will be removed in v2.0. Use 'allowed_methods' instead", - DeprecationWarning, - ) - return self.allowed_methods - try: - return getattr(super(Retry, self), item) - except AttributeError: - return getattr(Retry, item) - - -# For backwards compatibility (equivalent to pre-v1.9): -Retry.DEFAULT = Retry(3) diff --git a/venv/lib/python3.8/site-packages/urllib3/util/ssl_.py b/venv/lib/python3.8/site-packages/urllib3/util/ssl_.py deleted file mode 100644 index 8f86781..0000000 --- a/venv/lib/python3.8/site-packages/urllib3/util/ssl_.py +++ /dev/null @@ -1,495 +0,0 @@ -from __future__ import absolute_import - -import hmac -import os -import sys -import warnings -from binascii import hexlify, unhexlify -from hashlib import md5, sha1, sha256 - -from ..exceptions import ( - InsecurePlatformWarning, - ProxySchemeUnsupported, - SNIMissingWarning, - SSLError, -) -from ..packages import six -from .url import BRACELESS_IPV6_ADDRZ_RE, IPV4_RE - -SSLContext = None -SSLTransport = None -HAS_SNI = False -IS_PYOPENSSL = False -IS_SECURETRANSPORT = False -ALPN_PROTOCOLS = ["http/1.1"] - -# Maps the length of a digest to a possible hash function producing this digest -HASHFUNC_MAP = {32: md5, 40: sha1, 64: sha256} - - -def _const_compare_digest_backport(a, b): - """ - Compare two digests of equal length in constant time. - - The digests must be of type str/bytes. - Returns True if the digests match, and False otherwise. - """ - result = abs(len(a) - len(b)) - for left, right in zip(bytearray(a), bytearray(b)): - result |= left ^ right - return result == 0 - - -_const_compare_digest = getattr(hmac, "compare_digest", _const_compare_digest_backport) - -try: # Test for SSL features - import ssl - from ssl import CERT_REQUIRED, wrap_socket -except ImportError: - pass - -try: - from ssl import HAS_SNI # Has SNI? -except ImportError: - pass - -try: - from .ssltransport import SSLTransport -except ImportError: - pass - - -try: # Platform-specific: Python 3.6 - from ssl import PROTOCOL_TLS - - PROTOCOL_SSLv23 = PROTOCOL_TLS -except ImportError: - try: - from ssl import PROTOCOL_SSLv23 as PROTOCOL_TLS - - PROTOCOL_SSLv23 = PROTOCOL_TLS - except ImportError: - PROTOCOL_SSLv23 = PROTOCOL_TLS = 2 - -try: - from ssl import PROTOCOL_TLS_CLIENT -except ImportError: - PROTOCOL_TLS_CLIENT = PROTOCOL_TLS - - -try: - from ssl import OP_NO_COMPRESSION, OP_NO_SSLv2, OP_NO_SSLv3 -except ImportError: - OP_NO_SSLv2, OP_NO_SSLv3 = 0x1000000, 0x2000000 - OP_NO_COMPRESSION = 0x20000 - - -try: # OP_NO_TICKET was added in Python 3.6 - from ssl import OP_NO_TICKET -except ImportError: - OP_NO_TICKET = 0x4000 - - -# A secure default. -# Sources for more information on TLS ciphers: -# -# - https://wiki.mozilla.org/Security/Server_Side_TLS -# - https://www.ssllabs.com/projects/best-practices/index.html -# - https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/ -# -# The general intent is: -# - prefer cipher suites that offer perfect forward secrecy (DHE/ECDHE), -# - prefer ECDHE over DHE for better performance, -# - prefer any AES-GCM and ChaCha20 over any AES-CBC for better performance and -# security, -# - prefer AES-GCM over ChaCha20 because hardware-accelerated AES is common, -# - disable NULL authentication, MD5 MACs, DSS, and other -# insecure ciphers for security reasons. -# - NOTE: TLS 1.3 cipher suites are managed through a different interface -# not exposed by CPython (yet!) and are enabled by default if they're available. -DEFAULT_CIPHERS = ":".join( - [ - "ECDHE+AESGCM", - "ECDHE+CHACHA20", - "DHE+AESGCM", - "DHE+CHACHA20", - "ECDH+AESGCM", - "DH+AESGCM", - "ECDH+AES", - "DH+AES", - "RSA+AESGCM", - "RSA+AES", - "!aNULL", - "!eNULL", - "!MD5", - "!DSS", - ] -) - -try: - from ssl import SSLContext # Modern SSL? -except ImportError: - - class SSLContext(object): # Platform-specific: Python 2 - def __init__(self, protocol_version): - self.protocol = protocol_version - # Use default values from a real SSLContext - self.check_hostname = False - self.verify_mode = ssl.CERT_NONE - self.ca_certs = None - self.options = 0 - self.certfile = None - self.keyfile = None - self.ciphers = None - - def load_cert_chain(self, certfile, keyfile): - self.certfile = certfile - self.keyfile = keyfile - - def load_verify_locations(self, cafile=None, capath=None, cadata=None): - self.ca_certs = cafile - - if capath is not None: - raise SSLError("CA directories not supported in older Pythons") - - if cadata is not None: - raise SSLError("CA data not supported in older Pythons") - - def set_ciphers(self, cipher_suite): - self.ciphers = cipher_suite - - def wrap_socket(self, socket, server_hostname=None, server_side=False): - warnings.warn( - "A true SSLContext object is not available. This prevents " - "urllib3 from configuring SSL appropriately and may cause " - "certain SSL connections to fail. You can upgrade to a newer " - "version of Python to solve this. For more information, see " - "https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html" - "#ssl-warnings", - InsecurePlatformWarning, - ) - kwargs = { - "keyfile": self.keyfile, - "certfile": self.certfile, - "ca_certs": self.ca_certs, - "cert_reqs": self.verify_mode, - "ssl_version": self.protocol, - "server_side": server_side, - } - return wrap_socket(socket, ciphers=self.ciphers, **kwargs) - - -def assert_fingerprint(cert, fingerprint): - """ - Checks if given fingerprint matches the supplied certificate. - - :param cert: - Certificate as bytes object. - :param fingerprint: - Fingerprint as string of hexdigits, can be interspersed by colons. - """ - - fingerprint = fingerprint.replace(":", "").lower() - digest_length = len(fingerprint) - hashfunc = HASHFUNC_MAP.get(digest_length) - if not hashfunc: - raise SSLError("Fingerprint of invalid length: {0}".format(fingerprint)) - - # We need encode() here for py32; works on py2 and p33. - fingerprint_bytes = unhexlify(fingerprint.encode()) - - cert_digest = hashfunc(cert).digest() - - if not _const_compare_digest(cert_digest, fingerprint_bytes): - raise SSLError( - 'Fingerprints did not match. Expected "{0}", got "{1}".'.format( - fingerprint, hexlify(cert_digest) - ) - ) - - -def resolve_cert_reqs(candidate): - """ - Resolves the argument to a numeric constant, which can be passed to - the wrap_socket function/method from the ssl module. - Defaults to :data:`ssl.CERT_REQUIRED`. - If given a string it is assumed to be the name of the constant in the - :mod:`ssl` module or its abbreviation. - (So you can specify `REQUIRED` instead of `CERT_REQUIRED`. - If it's neither `None` nor a string we assume it is already the numeric - constant which can directly be passed to wrap_socket. - """ - if candidate is None: - return CERT_REQUIRED - - if isinstance(candidate, str): - res = getattr(ssl, candidate, None) - if res is None: - res = getattr(ssl, "CERT_" + candidate) - return res - - return candidate - - -def resolve_ssl_version(candidate): - """ - like resolve_cert_reqs - """ - if candidate is None: - return PROTOCOL_TLS - - if isinstance(candidate, str): - res = getattr(ssl, candidate, None) - if res is None: - res = getattr(ssl, "PROTOCOL_" + candidate) - return res - - return candidate - - -def create_urllib3_context( - ssl_version=None, cert_reqs=None, options=None, ciphers=None -): - """All arguments have the same meaning as ``ssl_wrap_socket``. - - By default, this function does a lot of the same work that - ``ssl.create_default_context`` does on Python 3.4+. It: - - - Disables SSLv2, SSLv3, and compression - - Sets a restricted set of server ciphers - - If you wish to enable SSLv3, you can do:: - - from urllib3.util import ssl_ - context = ssl_.create_urllib3_context() - context.options &= ~ssl_.OP_NO_SSLv3 - - You can do the same to enable compression (substituting ``COMPRESSION`` - for ``SSLv3`` in the last line above). - - :param ssl_version: - The desired protocol version to use. This will default to - PROTOCOL_SSLv23 which will negotiate the highest protocol that both - the server and your installation of OpenSSL support. - :param cert_reqs: - Whether to require the certificate verification. This defaults to - ``ssl.CERT_REQUIRED``. - :param options: - Specific OpenSSL options. These default to ``ssl.OP_NO_SSLv2``, - ``ssl.OP_NO_SSLv3``, ``ssl.OP_NO_COMPRESSION``, and ``ssl.OP_NO_TICKET``. - :param ciphers: - Which cipher suites to allow the server to select. - :returns: - Constructed SSLContext object with specified options - :rtype: SSLContext - """ - # PROTOCOL_TLS is deprecated in Python 3.10 - if not ssl_version or ssl_version == PROTOCOL_TLS: - ssl_version = PROTOCOL_TLS_CLIENT - - context = SSLContext(ssl_version) - - context.set_ciphers(ciphers or DEFAULT_CIPHERS) - - # Setting the default here, as we may have no ssl module on import - cert_reqs = ssl.CERT_REQUIRED if cert_reqs is None else cert_reqs - - if options is None: - options = 0 - # SSLv2 is easily broken and is considered harmful and dangerous - options |= OP_NO_SSLv2 - # SSLv3 has several problems and is now dangerous - options |= OP_NO_SSLv3 - # Disable compression to prevent CRIME attacks for OpenSSL 1.0+ - # (issue #309) - options |= OP_NO_COMPRESSION - # TLSv1.2 only. Unless set explicitly, do not request tickets. - # This may save some bandwidth on wire, and although the ticket is encrypted, - # there is a risk associated with it being on wire, - # if the server is not rotating its ticketing keys properly. - options |= OP_NO_TICKET - - context.options |= options - - # Enable post-handshake authentication for TLS 1.3, see GH #1634. PHA is - # necessary for conditional client cert authentication with TLS 1.3. - # The attribute is None for OpenSSL <= 1.1.0 or does not exist in older - # versions of Python. We only enable on Python 3.7.4+ or if certificate - # verification is enabled to work around Python issue #37428 - # See: https://bugs.python.org/issue37428 - if (cert_reqs == ssl.CERT_REQUIRED or sys.version_info >= (3, 7, 4)) and getattr( - context, "post_handshake_auth", None - ) is not None: - context.post_handshake_auth = True - - def disable_check_hostname(): - if ( - getattr(context, "check_hostname", None) is not None - ): # Platform-specific: Python 3.2 - # We do our own verification, including fingerprints and alternative - # hostnames. So disable it here - context.check_hostname = False - - # The order of the below lines setting verify_mode and check_hostname - # matter due to safe-guards SSLContext has to prevent an SSLContext with - # check_hostname=True, verify_mode=NONE/OPTIONAL. This is made even more - # complex because we don't know whether PROTOCOL_TLS_CLIENT will be used - # or not so we don't know the initial state of the freshly created SSLContext. - if cert_reqs == ssl.CERT_REQUIRED: - context.verify_mode = cert_reqs - disable_check_hostname() - else: - disable_check_hostname() - context.verify_mode = cert_reqs - - # Enable logging of TLS session keys via defacto standard environment variable - # 'SSLKEYLOGFILE', if the feature is available (Python 3.8+). Skip empty values. - if hasattr(context, "keylog_filename"): - sslkeylogfile = os.environ.get("SSLKEYLOGFILE") - if sslkeylogfile: - context.keylog_filename = sslkeylogfile - - return context - - -def ssl_wrap_socket( - sock, - keyfile=None, - certfile=None, - cert_reqs=None, - ca_certs=None, - server_hostname=None, - ssl_version=None, - ciphers=None, - ssl_context=None, - ca_cert_dir=None, - key_password=None, - ca_cert_data=None, - tls_in_tls=False, -): - """ - All arguments except for server_hostname, ssl_context, and ca_cert_dir have - the same meaning as they do when using :func:`ssl.wrap_socket`. - - :param server_hostname: - When SNI is supported, the expected hostname of the certificate - :param ssl_context: - A pre-made :class:`SSLContext` object. If none is provided, one will - be created using :func:`create_urllib3_context`. - :param ciphers: - A string of ciphers we wish the client to support. - :param ca_cert_dir: - A directory containing CA certificates in multiple separate files, as - supported by OpenSSL's -CApath flag or the capath argument to - SSLContext.load_verify_locations(). - :param key_password: - Optional password if the keyfile is encrypted. - :param ca_cert_data: - Optional string containing CA certificates in PEM format suitable for - passing as the cadata parameter to SSLContext.load_verify_locations() - :param tls_in_tls: - Use SSLTransport to wrap the existing socket. - """ - context = ssl_context - if context is None: - # Note: This branch of code and all the variables in it are no longer - # used by urllib3 itself. We should consider deprecating and removing - # this code. - context = create_urllib3_context(ssl_version, cert_reqs, ciphers=ciphers) - - if ca_certs or ca_cert_dir or ca_cert_data: - try: - context.load_verify_locations(ca_certs, ca_cert_dir, ca_cert_data) - except (IOError, OSError) as e: - raise SSLError(e) - - elif ssl_context is None and hasattr(context, "load_default_certs"): - # try to load OS default certs; works well on Windows (require Python3.4+) - context.load_default_certs() - - # Attempt to detect if we get the goofy behavior of the - # keyfile being encrypted and OpenSSL asking for the - # passphrase via the terminal and instead error out. - if keyfile and key_password is None and _is_key_file_encrypted(keyfile): - raise SSLError("Client private key is encrypted, password is required") - - if certfile: - if key_password is None: - context.load_cert_chain(certfile, keyfile) - else: - context.load_cert_chain(certfile, keyfile, key_password) - - try: - if hasattr(context, "set_alpn_protocols"): - context.set_alpn_protocols(ALPN_PROTOCOLS) - except NotImplementedError: # Defensive: in CI, we always have set_alpn_protocols - pass - - # If we detect server_hostname is an IP address then the SNI - # extension should not be used according to RFC3546 Section 3.1 - use_sni_hostname = server_hostname and not is_ipaddress(server_hostname) - # SecureTransport uses server_hostname in certificate verification. - send_sni = (use_sni_hostname and HAS_SNI) or ( - IS_SECURETRANSPORT and server_hostname - ) - # Do not warn the user if server_hostname is an invalid SNI hostname. - if not HAS_SNI and use_sni_hostname: - warnings.warn( - "An HTTPS request has been made, but the SNI (Server Name " - "Indication) extension to TLS is not available on this platform. " - "This may cause the server to present an incorrect TLS " - "certificate, which can cause validation failures. You can upgrade to " - "a newer version of Python to solve this. For more information, see " - "https://urllib3.readthedocs.io/en/1.26.x/advanced-usage.html" - "#ssl-warnings", - SNIMissingWarning, - ) - - if send_sni: - ssl_sock = _ssl_wrap_socket_impl( - sock, context, tls_in_tls, server_hostname=server_hostname - ) - else: - ssl_sock = _ssl_wrap_socket_impl(sock, context, tls_in_tls) - return ssl_sock - - -def is_ipaddress(hostname): - """Detects whether the hostname given is an IPv4 or IPv6 address. - Also detects IPv6 addresses with Zone IDs. - - :param str hostname: Hostname to examine. - :return: True if the hostname is an IP address, False otherwise. - """ - if not six.PY2 and isinstance(hostname, bytes): - # IDN A-label bytes are ASCII compatible. - hostname = hostname.decode("ascii") - return bool(IPV4_RE.match(hostname) or BRACELESS_IPV6_ADDRZ_RE.match(hostname)) - - -def _is_key_file_encrypted(key_file): - """Detects if a key file is encrypted or not.""" - with open(key_file, "r") as f: - for line in f: - # Look for Proc-Type: 4,ENCRYPTED - if "ENCRYPTED" in line: - return True - - return False - - -def _ssl_wrap_socket_impl(sock, ssl_context, tls_in_tls, server_hostname=None): - if tls_in_tls: - if not SSLTransport: - # Import error, ssl is not available. - raise ProxySchemeUnsupported( - "TLS in TLS requires support for the 'ssl' module" - ) - - SSLTransport._validate_ssl_context_for_tls_in_tls(ssl_context) - return SSLTransport(sock, ssl_context, server_hostname) - - if server_hostname: - return ssl_context.wrap_socket(sock, server_hostname=server_hostname) - else: - return ssl_context.wrap_socket(sock) diff --git a/venv/lib/python3.8/site-packages/urllib3/util/ssltransport.py b/venv/lib/python3.8/site-packages/urllib3/util/ssltransport.py deleted file mode 100644 index c2186bc..0000000 --- a/venv/lib/python3.8/site-packages/urllib3/util/ssltransport.py +++ /dev/null @@ -1,221 +0,0 @@ -import io -import socket -import ssl - -from urllib3.exceptions import ProxySchemeUnsupported -from urllib3.packages import six - -SSL_BLOCKSIZE = 16384 - - -class SSLTransport: - """ - The SSLTransport wraps an existing socket and establishes an SSL connection. - - Contrary to Python's implementation of SSLSocket, it allows you to chain - multiple TLS connections together. It's particularly useful if you need to - implement TLS within TLS. - - The class supports most of the socket API operations. - """ - - @staticmethod - def _validate_ssl_context_for_tls_in_tls(ssl_context): - """ - Raises a ProxySchemeUnsupported if the provided ssl_context can't be used - for TLS in TLS. - - The only requirement is that the ssl_context provides the 'wrap_bio' - methods. - """ - - if not hasattr(ssl_context, "wrap_bio"): - if six.PY2: - raise ProxySchemeUnsupported( - "TLS in TLS requires SSLContext.wrap_bio() which isn't " - "supported on Python 2" - ) - else: - raise ProxySchemeUnsupported( - "TLS in TLS requires SSLContext.wrap_bio() which isn't " - "available on non-native SSLContext" - ) - - def __init__( - self, socket, ssl_context, server_hostname=None, suppress_ragged_eofs=True - ): - """ - Create an SSLTransport around socket using the provided ssl_context. - """ - self.incoming = ssl.MemoryBIO() - self.outgoing = ssl.MemoryBIO() - - self.suppress_ragged_eofs = suppress_ragged_eofs - self.socket = socket - - self.sslobj = ssl_context.wrap_bio( - self.incoming, self.outgoing, server_hostname=server_hostname - ) - - # Perform initial handshake. - self._ssl_io_loop(self.sslobj.do_handshake) - - def __enter__(self): - return self - - def __exit__(self, *_): - self.close() - - def fileno(self): - return self.socket.fileno() - - def read(self, len=1024, buffer=None): - return self._wrap_ssl_read(len, buffer) - - def recv(self, len=1024, flags=0): - if flags != 0: - raise ValueError("non-zero flags not allowed in calls to recv") - return self._wrap_ssl_read(len) - - def recv_into(self, buffer, nbytes=None, flags=0): - if flags != 0: - raise ValueError("non-zero flags not allowed in calls to recv_into") - if buffer and (nbytes is None): - nbytes = len(buffer) - elif nbytes is None: - nbytes = 1024 - return self.read(nbytes, buffer) - - def sendall(self, data, flags=0): - if flags != 0: - raise ValueError("non-zero flags not allowed in calls to sendall") - count = 0 - with memoryview(data) as view, view.cast("B") as byte_view: - amount = len(byte_view) - while count < amount: - v = self.send(byte_view[count:]) - count += v - - def send(self, data, flags=0): - if flags != 0: - raise ValueError("non-zero flags not allowed in calls to send") - response = self._ssl_io_loop(self.sslobj.write, data) - return response - - def makefile( - self, mode="r", buffering=None, encoding=None, errors=None, newline=None - ): - """ - Python's httpclient uses makefile and buffered io when reading HTTP - messages and we need to support it. - - This is unfortunately a copy and paste of socket.py makefile with small - changes to point to the socket directly. - """ - if not set(mode) <= {"r", "w", "b"}: - raise ValueError("invalid mode %r (only r, w, b allowed)" % (mode,)) - - writing = "w" in mode - reading = "r" in mode or not writing - assert reading or writing - binary = "b" in mode - rawmode = "" - if reading: - rawmode += "r" - if writing: - rawmode += "w" - raw = socket.SocketIO(self, rawmode) - self.socket._io_refs += 1 - if buffering is None: - buffering = -1 - if buffering < 0: - buffering = io.DEFAULT_BUFFER_SIZE - if buffering == 0: - if not binary: - raise ValueError("unbuffered streams must be binary") - return raw - if reading and writing: - buffer = io.BufferedRWPair(raw, raw, buffering) - elif reading: - buffer = io.BufferedReader(raw, buffering) - else: - assert writing - buffer = io.BufferedWriter(raw, buffering) - if binary: - return buffer - text = io.TextIOWrapper(buffer, encoding, errors, newline) - text.mode = mode - return text - - def unwrap(self): - self._ssl_io_loop(self.sslobj.unwrap) - - def close(self): - self.socket.close() - - def getpeercert(self, binary_form=False): - return self.sslobj.getpeercert(binary_form) - - def version(self): - return self.sslobj.version() - - def cipher(self): - return self.sslobj.cipher() - - def selected_alpn_protocol(self): - return self.sslobj.selected_alpn_protocol() - - def selected_npn_protocol(self): - return self.sslobj.selected_npn_protocol() - - def shared_ciphers(self): - return self.sslobj.shared_ciphers() - - def compression(self): - return self.sslobj.compression() - - def settimeout(self, value): - self.socket.settimeout(value) - - def gettimeout(self): - return self.socket.gettimeout() - - def _decref_socketios(self): - self.socket._decref_socketios() - - def _wrap_ssl_read(self, len, buffer=None): - try: - return self._ssl_io_loop(self.sslobj.read, len, buffer) - except ssl.SSLError as e: - if e.errno == ssl.SSL_ERROR_EOF and self.suppress_ragged_eofs: - return 0 # eof, return 0. - else: - raise - - def _ssl_io_loop(self, func, *args): - """Performs an I/O loop between incoming/outgoing and the socket.""" - should_loop = True - ret = None - - while should_loop: - errno = None - try: - ret = func(*args) - except ssl.SSLError as e: - if e.errno not in (ssl.SSL_ERROR_WANT_READ, ssl.SSL_ERROR_WANT_WRITE): - # WANT_READ, and WANT_WRITE are expected, others are not. - raise e - errno = e.errno - - buf = self.outgoing.read() - self.socket.sendall(buf) - - if errno is None: - should_loop = False - elif errno == ssl.SSL_ERROR_WANT_READ: - buf = self.socket.recv(SSL_BLOCKSIZE) - if buf: - self.incoming.write(buf) - else: - self.incoming.write_eof() - return ret diff --git a/venv/lib/python3.8/site-packages/urllib3/util/timeout.py b/venv/lib/python3.8/site-packages/urllib3/util/timeout.py deleted file mode 100644 index ff69593..0000000 --- a/venv/lib/python3.8/site-packages/urllib3/util/timeout.py +++ /dev/null @@ -1,268 +0,0 @@ -from __future__ import absolute_import - -import time - -# The default socket timeout, used by httplib to indicate that no timeout was -# specified by the user -from socket import _GLOBAL_DEFAULT_TIMEOUT - -from ..exceptions import TimeoutStateError - -# A sentinel value to indicate that no timeout was specified by the user in -# urllib3 -_Default = object() - - -# Use time.monotonic if available. -current_time = getattr(time, "monotonic", time.time) - - -class Timeout(object): - """Timeout configuration. - - Timeouts can be defined as a default for a pool: - - .. code-block:: python - - timeout = Timeout(connect=2.0, read=7.0) - http = PoolManager(timeout=timeout) - response = http.request('GET', 'http://example.com/') - - Or per-request (which overrides the default for the pool): - - .. code-block:: python - - response = http.request('GET', 'http://example.com/', timeout=Timeout(10)) - - Timeouts can be disabled by setting all the parameters to ``None``: - - .. code-block:: python - - no_timeout = Timeout(connect=None, read=None) - response = http.request('GET', 'http://example.com/, timeout=no_timeout) - - - :param total: - This combines the connect and read timeouts into one; the read timeout - will be set to the time leftover from the connect attempt. In the - event that both a connect timeout and a total are specified, or a read - timeout and a total are specified, the shorter timeout will be applied. - - Defaults to None. - - :type total: int, float, or None - - :param connect: - The maximum amount of time (in seconds) to wait for a connection - attempt to a server to succeed. Omitting the parameter will default the - connect timeout to the system default, probably `the global default - timeout in socket.py - <http://hg.python.org/cpython/file/603b4d593758/Lib/socket.py#l535>`_. - None will set an infinite timeout for connection attempts. - - :type connect: int, float, or None - - :param read: - The maximum amount of time (in seconds) to wait between consecutive - read operations for a response from the server. Omitting the parameter - will default the read timeout to the system default, probably `the - global default timeout in socket.py - <http://hg.python.org/cpython/file/603b4d593758/Lib/socket.py#l535>`_. - None will set an infinite timeout. - - :type read: int, float, or None - - .. note:: - - Many factors can affect the total amount of time for urllib3 to return - an HTTP response. - - For example, Python's DNS resolver does not obey the timeout specified - on the socket. Other factors that can affect total request time include - high CPU load, high swap, the program running at a low priority level, - or other behaviors. - - In addition, the read and total timeouts only measure the time between - read operations on the socket connecting the client and the server, - not the total amount of time for the request to return a complete - response. For most requests, the timeout is raised because the server - has not sent the first byte in the specified time. This is not always - the case; if a server streams one byte every fifteen seconds, a timeout - of 20 seconds will not trigger, even though the request will take - several minutes to complete. - - If your goal is to cut off any request after a set amount of wall clock - time, consider having a second "watcher" thread to cut off a slow - request. - """ - - #: A sentinel object representing the default timeout value - DEFAULT_TIMEOUT = _GLOBAL_DEFAULT_TIMEOUT - - def __init__(self, total=None, connect=_Default, read=_Default): - self._connect = self._validate_timeout(connect, "connect") - self._read = self._validate_timeout(read, "read") - self.total = self._validate_timeout(total, "total") - self._start_connect = None - - def __repr__(self): - return "%s(connect=%r, read=%r, total=%r)" % ( - type(self).__name__, - self._connect, - self._read, - self.total, - ) - - # __str__ provided for backwards compatibility - __str__ = __repr__ - - @classmethod - def _validate_timeout(cls, value, name): - """Check that a timeout attribute is valid. - - :param value: The timeout value to validate - :param name: The name of the timeout attribute to validate. This is - used to specify in error messages. - :return: The validated and casted version of the given value. - :raises ValueError: If it is a numeric value less than or equal to - zero, or the type is not an integer, float, or None. - """ - if value is _Default: - return cls.DEFAULT_TIMEOUT - - if value is None or value is cls.DEFAULT_TIMEOUT: - return value - - if isinstance(value, bool): - raise ValueError( - "Timeout cannot be a boolean value. It must " - "be an int, float or None." - ) - try: - float(value) - except (TypeError, ValueError): - raise ValueError( - "Timeout value %s was %s, but it must be an " - "int, float or None." % (name, value) - ) - - try: - if value <= 0: - raise ValueError( - "Attempted to set %s timeout to %s, but the " - "timeout cannot be set to a value less " - "than or equal to 0." % (name, value) - ) - except TypeError: - # Python 3 - raise ValueError( - "Timeout value %s was %s, but it must be an " - "int, float or None." % (name, value) - ) - - return value - - @classmethod - def from_float(cls, timeout): - """Create a new Timeout from a legacy timeout value. - - The timeout value used by httplib.py sets the same timeout on the - connect(), and recv() socket requests. This creates a :class:`Timeout` - object that sets the individual timeouts to the ``timeout`` value - passed to this function. - - :param timeout: The legacy timeout value. - :type timeout: integer, float, sentinel default object, or None - :return: Timeout object - :rtype: :class:`Timeout` - """ - return Timeout(read=timeout, connect=timeout) - - def clone(self): - """Create a copy of the timeout object - - Timeout properties are stored per-pool but each request needs a fresh - Timeout object to ensure each one has its own start/stop configured. - - :return: a copy of the timeout object - :rtype: :class:`Timeout` - """ - # We can't use copy.deepcopy because that will also create a new object - # for _GLOBAL_DEFAULT_TIMEOUT, which socket.py uses as a sentinel to - # detect the user default. - return Timeout(connect=self._connect, read=self._read, total=self.total) - - def start_connect(self): - """Start the timeout clock, used during a connect() attempt - - :raises urllib3.exceptions.TimeoutStateError: if you attempt - to start a timer that has been started already. - """ - if self._start_connect is not None: - raise TimeoutStateError("Timeout timer has already been started.") - self._start_connect = current_time() - return self._start_connect - - def get_connect_duration(self): - """Gets the time elapsed since the call to :meth:`start_connect`. - - :return: Elapsed time in seconds. - :rtype: float - :raises urllib3.exceptions.TimeoutStateError: if you attempt - to get duration for a timer that hasn't been started. - """ - if self._start_connect is None: - raise TimeoutStateError( - "Can't get connect duration for timer that has not started." - ) - return current_time() - self._start_connect - - @property - def connect_timeout(self): - """Get the value to use when setting a connection timeout. - - This will be a positive float or integer, the value None - (never timeout), or the default system timeout. - - :return: Connect timeout. - :rtype: int, float, :attr:`Timeout.DEFAULT_TIMEOUT` or None - """ - if self.total is None: - return self._connect - - if self._connect is None or self._connect is self.DEFAULT_TIMEOUT: - return self.total - - return min(self._connect, self.total) - - @property - def read_timeout(self): - """Get the value for the read timeout. - - This assumes some time has elapsed in the connection timeout and - computes the read timeout appropriately. - - If self.total is set, the read timeout is dependent on the amount of - time taken by the connect timeout. If the connection time has not been - established, a :exc:`~urllib3.exceptions.TimeoutStateError` will be - raised. - - :return: Value to use for the read timeout. - :rtype: int, float, :attr:`Timeout.DEFAULT_TIMEOUT` or None - :raises urllib3.exceptions.TimeoutStateError: If :meth:`start_connect` - has not yet been called on this object. - """ - if ( - self.total is not None - and self.total is not self.DEFAULT_TIMEOUT - and self._read is not None - and self._read is not self.DEFAULT_TIMEOUT - ): - # In case the connect timeout has not yet been established. - if self._start_connect is None: - return self._read - return max(0, min(self.total - self.get_connect_duration(), self._read)) - elif self.total is not None and self.total is not self.DEFAULT_TIMEOUT: - return max(0, self.total - self.get_connect_duration()) - else: - return self._read diff --git a/venv/lib/python3.8/site-packages/urllib3/util/url.py b/venv/lib/python3.8/site-packages/urllib3/util/url.py deleted file mode 100644 index 81a03da..0000000 --- a/venv/lib/python3.8/site-packages/urllib3/util/url.py +++ /dev/null @@ -1,432 +0,0 @@ -from __future__ import absolute_import - -import re -from collections import namedtuple - -from ..exceptions import LocationParseError -from ..packages import six - -url_attrs = ["scheme", "auth", "host", "port", "path", "query", "fragment"] - -# We only want to normalize urls with an HTTP(S) scheme. -# urllib3 infers URLs without a scheme (None) to be http. -NORMALIZABLE_SCHEMES = ("http", "https", None) - -# Almost all of these patterns were derived from the -# 'rfc3986' module: https://github.com/python-hyper/rfc3986 -PERCENT_RE = re.compile(r"%[a-fA-F0-9]{2}") -SCHEME_RE = re.compile(r"^(?:[a-zA-Z][a-zA-Z0-9+-]*:|/)") -URI_RE = re.compile( - r"^(?:([a-zA-Z][a-zA-Z0-9+.-]*):)?" - r"(?://([^\\/?#]*))?" - r"([^?#]*)" - r"(?:\?([^#]*))?" - r"(?:#(.*))?$", - re.UNICODE | re.DOTALL, -) - -IPV4_PAT = r"(?:[0-9]{1,3}\.){3}[0-9]{1,3}" -HEX_PAT = "[0-9A-Fa-f]{1,4}" -LS32_PAT = "(?:{hex}:{hex}|{ipv4})".format(hex=HEX_PAT, ipv4=IPV4_PAT) -_subs = {"hex": HEX_PAT, "ls32": LS32_PAT} -_variations = [ - # 6( h16 ":" ) ls32 - "(?:%(hex)s:){6}%(ls32)s", - # "::" 5( h16 ":" ) ls32 - "::(?:%(hex)s:){5}%(ls32)s", - # [ h16 ] "::" 4( h16 ":" ) ls32 - "(?:%(hex)s)?::(?:%(hex)s:){4}%(ls32)s", - # [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32 - "(?:(?:%(hex)s:)?%(hex)s)?::(?:%(hex)s:){3}%(ls32)s", - # [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32 - "(?:(?:%(hex)s:){0,2}%(hex)s)?::(?:%(hex)s:){2}%(ls32)s", - # [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32 - "(?:(?:%(hex)s:){0,3}%(hex)s)?::%(hex)s:%(ls32)s", - # [ *4( h16 ":" ) h16 ] "::" ls32 - "(?:(?:%(hex)s:){0,4}%(hex)s)?::%(ls32)s", - # [ *5( h16 ":" ) h16 ] "::" h16 - "(?:(?:%(hex)s:){0,5}%(hex)s)?::%(hex)s", - # [ *6( h16 ":" ) h16 ] "::" - "(?:(?:%(hex)s:){0,6}%(hex)s)?::", -] - -UNRESERVED_PAT = r"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._!\-~" -IPV6_PAT = "(?:" + "|".join([x % _subs for x in _variations]) + ")" -ZONE_ID_PAT = "(?:%25|%)(?:[" + UNRESERVED_PAT + "]|%[a-fA-F0-9]{2})+" -IPV6_ADDRZ_PAT = r"\[" + IPV6_PAT + r"(?:" + ZONE_ID_PAT + r")?\]" -REG_NAME_PAT = r"(?:[^\[\]%:/?#]|%[a-fA-F0-9]{2})*" -TARGET_RE = re.compile(r"^(/[^?#]*)(?:\?([^#]*))?(?:#.*)?$") - -IPV4_RE = re.compile("^" + IPV4_PAT + "$") -IPV6_RE = re.compile("^" + IPV6_PAT + "$") -IPV6_ADDRZ_RE = re.compile("^" + IPV6_ADDRZ_PAT + "$") -BRACELESS_IPV6_ADDRZ_RE = re.compile("^" + IPV6_ADDRZ_PAT[2:-2] + "$") -ZONE_ID_RE = re.compile("(" + ZONE_ID_PAT + r")\]$") - -_HOST_PORT_PAT = ("^(%s|%s|%s)(?::([0-9]{0,5}))?$") % ( - REG_NAME_PAT, - IPV4_PAT, - IPV6_ADDRZ_PAT, -) -_HOST_PORT_RE = re.compile(_HOST_PORT_PAT, re.UNICODE | re.DOTALL) - -UNRESERVED_CHARS = set( - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-~" -) -SUB_DELIM_CHARS = set("!$&'()*+,;=") -USERINFO_CHARS = UNRESERVED_CHARS | SUB_DELIM_CHARS | {":"} -PATH_CHARS = USERINFO_CHARS | {"@", "/"} -QUERY_CHARS = FRAGMENT_CHARS = PATH_CHARS | {"?"} - - -class Url(namedtuple("Url", url_attrs)): - """ - Data structure for representing an HTTP URL. Used as a return value for - :func:`parse_url`. Both the scheme and host are normalized as they are - both case-insensitive according to RFC 3986. - """ - - __slots__ = () - - def __new__( - cls, - scheme=None, - auth=None, - host=None, - port=None, - path=None, - query=None, - fragment=None, - ): - if path and not path.startswith("/"): - path = "/" + path - if scheme is not None: - scheme = scheme.lower() - return super(Url, cls).__new__( - cls, scheme, auth, host, port, path, query, fragment - ) - - @property - def hostname(self): - """For backwards-compatibility with urlparse. We're nice like that.""" - return self.host - - @property - def request_uri(self): - """Absolute path including the query string.""" - uri = self.path or "/" - - if self.query is not None: - uri += "?" + self.query - - return uri - - @property - def netloc(self): - """Network location including host and port""" - if self.port: - return "%s:%d" % (self.host, self.port) - return self.host - - @property - def url(self): - """ - Convert self into a url - - This function should more or less round-trip with :func:`.parse_url`. The - returned url may not be exactly the same as the url inputted to - :func:`.parse_url`, but it should be equivalent by the RFC (e.g., urls - with a blank port will have : removed). - - Example: :: - - >>> U = parse_url('http://google.com/mail/') - >>> U.url - 'http://google.com/mail/' - >>> Url('http', 'username:password', 'host.com', 80, - ... '/path', 'query', 'fragment').url - 'http://username:password@host.com:80/path?query#fragment' - """ - scheme, auth, host, port, path, query, fragment = self - url = u"" - - # We use "is not None" we want things to happen with empty strings (or 0 port) - if scheme is not None: - url += scheme + u"://" - if auth is not None: - url += auth + u"@" - if host is not None: - url += host - if port is not None: - url += u":" + str(port) - if path is not None: - url += path - if query is not None: - url += u"?" + query - if fragment is not None: - url += u"#" + fragment - - return url - - def __str__(self): - return self.url - - -def split_first(s, delims): - """ - .. deprecated:: 1.25 - - Given a string and an iterable of delimiters, split on the first found - delimiter. Return two split parts and the matched delimiter. - - If not found, then the first part is the full input string. - - Example:: - - >>> split_first('foo/bar?baz', '?/=') - ('foo', 'bar?baz', '/') - >>> split_first('foo/bar?baz', '123') - ('foo/bar?baz', '', None) - - Scales linearly with number of delims. Not ideal for large number of delims. - """ - min_idx = None - min_delim = None - for d in delims: - idx = s.find(d) - if idx < 0: - continue - - if min_idx is None or idx < min_idx: - min_idx = idx - min_delim = d - - if min_idx is None or min_idx < 0: - return s, "", None - - return s[:min_idx], s[min_idx + 1 :], min_delim - - -def _encode_invalid_chars(component, allowed_chars, encoding="utf-8"): - """Percent-encodes a URI component without reapplying - onto an already percent-encoded component. - """ - if component is None: - return component - - component = six.ensure_text(component) - - # Normalize existing percent-encoded bytes. - # Try to see if the component we're encoding is already percent-encoded - # so we can skip all '%' characters but still encode all others. - component, percent_encodings = PERCENT_RE.subn( - lambda match: match.group(0).upper(), component - ) - - uri_bytes = component.encode("utf-8", "surrogatepass") - is_percent_encoded = percent_encodings == uri_bytes.count(b"%") - encoded_component = bytearray() - - for i in range(0, len(uri_bytes)): - # Will return a single character bytestring on both Python 2 & 3 - byte = uri_bytes[i : i + 1] - byte_ord = ord(byte) - if (is_percent_encoded and byte == b"%") or ( - byte_ord < 128 and byte.decode() in allowed_chars - ): - encoded_component += byte - continue - encoded_component.extend(b"%" + (hex(byte_ord)[2:].encode().zfill(2).upper())) - - return encoded_component.decode(encoding) - - -def _remove_path_dot_segments(path): - # See http://tools.ietf.org/html/rfc3986#section-5.2.4 for pseudo-code - segments = path.split("/") # Turn the path into a list of segments - output = [] # Initialize the variable to use to store output - - for segment in segments: - # '.' is the current directory, so ignore it, it is superfluous - if segment == ".": - continue - # Anything other than '..', should be appended to the output - elif segment != "..": - output.append(segment) - # In this case segment == '..', if we can, we should pop the last - # element - elif output: - output.pop() - - # If the path starts with '/' and the output is empty or the first string - # is non-empty - if path.startswith("/") and (not output or output[0]): - output.insert(0, "") - - # If the path starts with '/.' or '/..' ensure we add one more empty - # string to add a trailing '/' - if path.endswith(("/.", "/..")): - output.append("") - - return "/".join(output) - - -def _normalize_host(host, scheme): - if host: - if isinstance(host, six.binary_type): - host = six.ensure_str(host) - - if scheme in NORMALIZABLE_SCHEMES: - is_ipv6 = IPV6_ADDRZ_RE.match(host) - if is_ipv6: - match = ZONE_ID_RE.search(host) - if match: - start, end = match.span(1) - zone_id = host[start:end] - - if zone_id.startswith("%25") and zone_id != "%25": - zone_id = zone_id[3:] - else: - zone_id = zone_id[1:] - zone_id = "%" + _encode_invalid_chars(zone_id, UNRESERVED_CHARS) - return host[:start].lower() + zone_id + host[end:] - else: - return host.lower() - elif not IPV4_RE.match(host): - return six.ensure_str( - b".".join([_idna_encode(label) for label in host.split(".")]) - ) - return host - - -def _idna_encode(name): - if name and any([ord(x) > 128 for x in name]): - try: - import idna - except ImportError: - six.raise_from( - LocationParseError("Unable to parse URL without the 'idna' module"), - None, - ) - try: - return idna.encode(name.lower(), strict=True, std3_rules=True) - except idna.IDNAError: - six.raise_from( - LocationParseError(u"Name '%s' is not a valid IDNA label" % name), None - ) - return name.lower().encode("ascii") - - -def _encode_target(target): - """Percent-encodes a request target so that there are no invalid characters""" - path, query = TARGET_RE.match(target).groups() - target = _encode_invalid_chars(path, PATH_CHARS) - query = _encode_invalid_chars(query, QUERY_CHARS) - if query is not None: - target += "?" + query - return target - - -def parse_url(url): - """ - Given a url, return a parsed :class:`.Url` namedtuple. Best-effort is - performed to parse incomplete urls. Fields not provided will be None. - This parser is RFC 3986 compliant. - - The parser logic and helper functions are based heavily on - work done in the ``rfc3986`` module. - - :param str url: URL to parse into a :class:`.Url` namedtuple. - - Partly backwards-compatible with :mod:`urlparse`. - - Example:: - - >>> parse_url('http://google.com/mail/') - Url(scheme='http', host='google.com', port=None, path='/mail/', ...) - >>> parse_url('google.com:80') - Url(scheme=None, host='google.com', port=80, path=None, ...) - >>> parse_url('/foo?bar') - Url(scheme=None, host=None, port=None, path='/foo', query='bar', ...) - """ - if not url: - # Empty - return Url() - - source_url = url - if not SCHEME_RE.search(url): - url = "//" + url - - try: - scheme, authority, path, query, fragment = URI_RE.match(url).groups() - normalize_uri = scheme is None or scheme.lower() in NORMALIZABLE_SCHEMES - - if scheme: - scheme = scheme.lower() - - if authority: - auth, _, host_port = authority.rpartition("@") - auth = auth or None - host, port = _HOST_PORT_RE.match(host_port).groups() - if auth and normalize_uri: - auth = _encode_invalid_chars(auth, USERINFO_CHARS) - if port == "": - port = None - else: - auth, host, port = None, None, None - - if port is not None: - port = int(port) - if not (0 <= port <= 65535): - raise LocationParseError(url) - - host = _normalize_host(host, scheme) - - if normalize_uri and path: - path = _remove_path_dot_segments(path) - path = _encode_invalid_chars(path, PATH_CHARS) - if normalize_uri and query: - query = _encode_invalid_chars(query, QUERY_CHARS) - if normalize_uri and fragment: - fragment = _encode_invalid_chars(fragment, FRAGMENT_CHARS) - - except (ValueError, AttributeError): - return six.raise_from(LocationParseError(source_url), None) - - # For the sake of backwards compatibility we put empty - # string values for path if there are any defined values - # beyond the path in the URL. - # TODO: Remove this when we break backwards compatibility. - if not path: - if query is not None or fragment is not None: - path = "" - else: - path = None - - # Ensure that each part of the URL is a `str` for - # backwards compatibility. - if isinstance(url, six.text_type): - ensure_func = six.ensure_text - else: - ensure_func = six.ensure_str - - def ensure_type(x): - return x if x is None else ensure_func(x) - - return Url( - scheme=ensure_type(scheme), - auth=ensure_type(auth), - host=ensure_type(host), - port=port, - path=ensure_type(path), - query=ensure_type(query), - fragment=ensure_type(fragment), - ) - - -def get_host(url): - """ - Deprecated. Use :func:`parse_url` instead. - """ - p = parse_url(url) - return p.scheme or "http", p.hostname, p.port diff --git a/venv/lib/python3.8/site-packages/urllib3/util/wait.py b/venv/lib/python3.8/site-packages/urllib3/util/wait.py deleted file mode 100644 index c280646..0000000 --- a/venv/lib/python3.8/site-packages/urllib3/util/wait.py +++ /dev/null @@ -1,153 +0,0 @@ -import errno -import select -import sys -from functools import partial - -try: - from time import monotonic -except ImportError: - from time import time as monotonic - -__all__ = ["NoWayToWaitForSocketError", "wait_for_read", "wait_for_write"] - - -class NoWayToWaitForSocketError(Exception): - pass - - -# How should we wait on sockets? -# -# There are two types of APIs you can use for waiting on sockets: the fancy -# modern stateful APIs like epoll/kqueue, and the older stateless APIs like -# select/poll. The stateful APIs are more efficient when you have a lots of -# sockets to keep track of, because you can set them up once and then use them -# lots of times. But we only ever want to wait on a single socket at a time -# and don't want to keep track of state, so the stateless APIs are actually -# more efficient. So we want to use select() or poll(). -# -# Now, how do we choose between select() and poll()? On traditional Unixes, -# select() has a strange calling convention that makes it slow, or fail -# altogether, for high-numbered file descriptors. The point of poll() is to fix -# that, so on Unixes, we prefer poll(). -# -# On Windows, there is no poll() (or at least Python doesn't provide a wrapper -# for it), but that's OK, because on Windows, select() doesn't have this -# strange calling convention; plain select() works fine. -# -# So: on Windows we use select(), and everywhere else we use poll(). We also -# fall back to select() in case poll() is somehow broken or missing. - -if sys.version_info >= (3, 5): - # Modern Python, that retries syscalls by default - def _retry_on_intr(fn, timeout): - return fn(timeout) - - -else: - # Old and broken Pythons. - def _retry_on_intr(fn, timeout): - if timeout is None: - deadline = float("inf") - else: - deadline = monotonic() + timeout - - while True: - try: - return fn(timeout) - # OSError for 3 <= pyver < 3.5, select.error for pyver <= 2.7 - except (OSError, select.error) as e: - # 'e.args[0]' incantation works for both OSError and select.error - if e.args[0] != errno.EINTR: - raise - else: - timeout = deadline - monotonic() - if timeout < 0: - timeout = 0 - if timeout == float("inf"): - timeout = None - continue - - -def select_wait_for_socket(sock, read=False, write=False, timeout=None): - if not read and not write: - raise RuntimeError("must specify at least one of read=True, write=True") - rcheck = [] - wcheck = [] - if read: - rcheck.append(sock) - if write: - wcheck.append(sock) - # When doing a non-blocking connect, most systems signal success by - # marking the socket writable. Windows, though, signals success by marked - # it as "exceptional". We paper over the difference by checking the write - # sockets for both conditions. (The stdlib selectors module does the same - # thing.) - fn = partial(select.select, rcheck, wcheck, wcheck) - rready, wready, xready = _retry_on_intr(fn, timeout) - return bool(rready or wready or xready) - - -def poll_wait_for_socket(sock, read=False, write=False, timeout=None): - if not read and not write: - raise RuntimeError("must specify at least one of read=True, write=True") - mask = 0 - if read: - mask |= select.POLLIN - if write: - mask |= select.POLLOUT - poll_obj = select.poll() - poll_obj.register(sock, mask) - - # For some reason, poll() takes timeout in milliseconds - def do_poll(t): - if t is not None: - t *= 1000 - return poll_obj.poll(t) - - return bool(_retry_on_intr(do_poll, timeout)) - - -def null_wait_for_socket(*args, **kwargs): - raise NoWayToWaitForSocketError("no select-equivalent available") - - -def _have_working_poll(): - # Apparently some systems have a select.poll that fails as soon as you try - # to use it, either due to strange configuration or broken monkeypatching - # from libraries like eventlet/greenlet. - try: - poll_obj = select.poll() - _retry_on_intr(poll_obj.poll, 0) - except (AttributeError, OSError): - return False - else: - return True - - -def wait_for_socket(*args, **kwargs): - # We delay choosing which implementation to use until the first time we're - # called. We could do it at import time, but then we might make the wrong - # decision if someone goes wild with monkeypatching select.poll after - # we're imported. - global wait_for_socket - if _have_working_poll(): - wait_for_socket = poll_wait_for_socket - elif hasattr(select, "select"): - wait_for_socket = select_wait_for_socket - else: # Platform-specific: Appengine. - wait_for_socket = null_wait_for_socket - return wait_for_socket(*args, **kwargs) - - -def wait_for_read(sock, timeout=None): - """Waits for reading to be available on a given socket. - Returns True if the socket is readable, or False if the timeout expired. - """ - return wait_for_socket(sock, read=True, timeout=timeout) - - -def wait_for_write(sock, timeout=None): - """Waits for writing to be available on a given socket. - Returns True if the socket is readable, or False if the timeout expired. - """ - return wait_for_socket(sock, write=True, timeout=timeout) diff --git a/venv/lib64 b/venv/lib64 deleted file mode 120000 index 7951405..0000000 --- a/venv/lib64 +++ /dev/null @@ -1 +0,0 @@ -lib \ No newline at end of file diff --git a/venv/pyvenv.cfg b/venv/pyvenv.cfg deleted file mode 100644 index 5d5aef2..0000000 --- a/venv/pyvenv.cfg +++ /dev/null @@ -1,3 +0,0 @@ -home = /usr/bin -include-system-site-packages = false -version = 3.8.6 diff --git a/venv/share/python-wheels/CacheControl-0.12.6-py2.py3-none-any.whl b/venv/share/python-wheels/CacheControl-0.12.6-py2.py3-none-any.whl deleted file mode 100644 index 4924d956ad131cbe41250e2e7bdce3e42be2335e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23290 zcma&NW3XsTvn{yxvTfVi%X`_jZQHhO+qP}nwr%t6@7{PFea`C_w|`X3i20+GH8Mwz ztdf-g0!9V^000L_1L=?@n)3-jLjV9^!36-I`1@Bt&%o43z{c9q-o}!Kp7u8bEeoxo znS&#ZnYFPE9iNh-sEoV<t)r`>Q5r`Kk(m9+*C(>kHU{Hr2x`dFpm#l<rF}*hSGrxG zp;A3%2kzKJC2@)A8GaTSUn~XhH2($lAvl{TJbqQ?Hi+T0H}F})DVmz$Oy*%Mg4|H~ zr0eGa-WZS8wPlV<j#o9QkN1r@^IX&Qx$K#xynEL|RC*=l#+g;~V$rj?J%iWB)!Ly| zb88N#B<kAz`L%udBc<ol8=8(!5ouc+la>uu0cntR!-DvRHP1NQp04Krjz>|%vNL)o zvlffPHs}h4)>+?0)EU@R(>P0jGSWs+)`OQ*0cjJgQuCv8g+NV<riEil7c*z88pe(Z zTwP=y!$!dOIm116mf`bqD!U<BUBU}XaZThjEoKWNcjz~F$D+W=C*SkT&$?2znaI;} z+ia?yqG}bz6FHqnmWs8BQ<mcv%CN~qIbP=mF3q-KN%cd!C@7;LRLh;a#sm>&1!>h3 zt>tKiGRxMP_3WDD#&-C8hw&(`r1n#FL#IGCUOg60<U>&@r>DFyRULv*$R*43c2xQl zZPawkit{BsO9AI@Xz^lGCF0jxNNiS`u~o<81VP8`@b0GmqIJ3|rd#+_agK0l12-zj zntgtNYi`5f3115p;e6e+*<nYGCaa;uN{rjw)3h^b#t^*be7j}$lo-QviZW4h(DfHV ze7;7CRC?8L5N!tLPFTjvK@mX*^I2Kf5KVII-ZE`9rG0V<`kD>3WzJR<#O6@R<vfad z{ar@KTT6+;zS>zc^X1Y-S+bYgM%3AbzMPQECf8c}R!6jH1d*rBXryc$(xCV<!MgPI zToo+GmU@wgn+V=&$kcHVZ53JJMl|prr=+vRu<b{d$JhSgD6>pe&k-a#=4f@2He>_` zn{!L;cY>V*lg=#-hMzcbeYf*KMD~P@4AL<L)<>~c7lKqrF4lctzCkh?54F^6$#@rB znwWNu9n73-J2p$bsF%*o*K`s(a$K$OWiuIcY3&BPpAA#~dL{IRwTsIr<{*N&qqc0{ z1UfDY0?gNkIaDBxvPyP4qdw4MtgRy@LlHoLo9!+IvOzYE7nYiZ_1VFp1io<ODk{<F zjg_^ox;@>~u|woUB%62KA0+m>05rI)`_=5%)PQJ#cE^ehCphlo&b5(gqlaPZsHgYb z?Tl&epImAFn~2%vPhSnOjN!&ga}=(glc)IpLYnQgx{2}g+<Uri*^)s^lI=6G$F5S1 z%??W|oxE4l42<UlL6J7~t?*0COfX!>B2!>84*-}2FH02SBFV9JOc@iT?8>^e^ChOi zKtCMHjHy)<m5G{omMASB_!=0!3rR0olee@BP3nq(?_p*O#&L=kX)K%tkC@=Hx~jKD z`WO&C9`w!P_}s@4)(AfuPtTve+DlM)$s?IJo9@r4l<<~Ub`CorRU*ix#2l8mMh>T; zSZ>~E0)n}+fj?_l<KgH4rMgZma8xHk4p_Lbh=B#3JlINb%W2kDQVNmlST+;kMs8LU zm%)?gXMCG(o2&7Lg~^L%#QwYa7hp+n_;rme0QZshd(AfaPtn}A!JhM`_F{!a+v?(L z!EzB&jO6lJEfIcn;X3))(dUW*gx^9AFlzR))mo=9_w|4seIs(rYi_HyOWmhXH})EZ zOTJ;gg}@eygGKEHEzao8YWHoTj?qaYo56A&q+Ic)5sM0~H@P@1DTXIdjG~N~PGVaD zuH8#pcfVTVgTdSoyy$h!*f4R)$s9aivBr;Xsal%;bg&v1Sgh6AG!be!Q?SlR(tA-0 zu42AVN?B3_k$?=yR8nM73)PT&v!3UaF5>$2SUM7L9Zxp-9z=b-@fd~px+~0%9=LBs zC|{2{QVcMT7v$w}E7tlm`sgub{=#ODVC$Z!W+#`gn0B586##4Gho6SZ0~4zUkYS-9 zZY`E>6PlV=9IMjQx7%K|OjF?q_llVZhnt@z$mLW#?*!qL$=~Ua)8wbHJ^cetPJ^0W zoCR2Vx6(#unX(}FK}y*-eQ6Jj$j@=E;HO4^k=q7?LTFDD3lk1o0LXq1`Yw9fz`CaP zNVRsnv=njmgojnMqlI)2@SZsUZ#z(MHyHetR7<@-IDhL@n|K*ycKLBh!=a;rzE)8? z*CvP7T!*DE*P-k4T_LLhLMEY_1>fN+cXQ`$_L|oY@a%wO|036a=Ic3|wOR_LPWh{I zkt&Ch*8M`e(O*B0RVfa$YjGP2&w^P0NVNozE@ilCr9a+U>ghA!t(1;K0r>!?n~685 zQ`k`A$C9{hT)g~wzWRf7&X3H>sYtxTMhhckMoA5gRwcz+fc;U4MIq%Oq-~b6HJg&P z*;r{&n*@bgshZ-P;aTrgECV0F0|Sh|iM0@LRpr_&KgZ{;h;URUuCbXWzlFcsE@l*Y zf=HG|42+(*xKkC2U8StJ&zx+H){if$NCJ<3JBr}xYy;SlNp7o`WN#5!FUUxvf}%}F z0+Uq|N_Q{`IQp9A8V#d2$O3^<F0gEjwa^Xdm&?xy!zN#9Ry!r%b4F{4sX&lOLboGT z4*O%0t+#gS>NE-xV9`m)AWF?OsR@#6G*Lt~Km(~q-{YE$kJ#<c#SPrEqUqjIeS3Tt z&1N?}=dt>Ub<*c+p~Zy-MS+FZND?(C_!3^z2tlhm8~LMkUCaGq@SqHh#UdT`nsY2% znRAx53R2Gro=~37E{?`5Np|l-wP|g9=-QWs=i#~%FIX=+R_Jik+*U=5RuY=*b+w1n zO{r9M^~ydHMG|q2St=QA8;g{LNueOeiT8VeyZ=$=&%VRuc4L5LwS)!Ml8ZadnFCBk z8R1*+ja7zNU!mO9diVq>Z>{o5wRob|Bq4V%kQPA#JUv0O$^`a1oRyj5zLU(VJAMBs zoG5y)CCwS#xLV<?u9=t`d`YaJ?d!DI%4x!IO;CKH;c%?DHfAH}T#bU+cAp@h4<GV- zsb9{fcpae%Z^XqssbHS9|DREcno2fU<tN~YrH_-FR@96@(ZxdVIa&+?qy-c$bhg7- z;k!nvA3-gk<>YP=P2d}jAya-n(!3=Aj@e$|#Re-S3xsAhAuRnT=00Xc!#wL<1%N>B zo&?37UugijWwvM->c1UvBy^Rcu3m`u=kPf#V@N9#VEI?jkK&YZk#*zKO3vWUy9RIQ z5jIm_e%ql5axj?R-y3^#v~{p&m17=`FTwbgv1d)as7GbFCeMrtd^#{PLFfa?DI?n1 zB_wORRSb07B`Sm0SeF7fdsOIoXwjL{aaM|frtfOHC%S$tv*{`EH^sF)Hdl#O_AzJq zz9H)8{kH6V&=7uToU5{?EU`9_-p*9lyK4D82gSg4NX~44=4*85KT%y3H*c2j!7l!> zg4LzcGP6^6c*0Z2Y*K%Ga?=UOeJ_};F6`r(<#@bpd>W5E;CBr*y{kgQKQ)82Bw@e* z&fg_?@J(?$>vBd}(3n({4oWz4F_kcjM2|YpjD%PpFcpBIh4B}v$UkB_@qB@NLnsAI z3r_BZ(8AUrTKKzFla$6OmG`9%8%pz{(e8wB{g*MpRO_vZqjDy;`u$`iF`#P_Y@M3L zxt9lqiQC4kn(lD!n}R&jZ(_`q6tD~i&Cu*|Npdv^@r$T~yiJP=^i#drdO_)nY@Q|w zJM;KKQaCUtHECa5j7+<(jay9pBr)rATb1=VQvKYWnl(=kJk0WM(VWPl>1zz*8lBO+ z0AZ8xtPM$A@l$C<g@-@@`s4{}C`p*@aW#);S}Y(2-tSl==V_q!XYvQzfu+8c`qyCb z#=bkH9RAc(vN85fyFWE>W{xHRA(xotn`+2<!PTtsdoH%&Ki@Aq0m8~A5#sRI(I9t~ z_3`SG<MntAMvJ(X8Zm-cOAvirzf|SU#c`n{pw85<3~@W`B#W7bIE*=djm9PJ{LzXt z?#6-#$#xAnfpuCLIHuDRFW*4bVAjcKXJ(m0ZAq>(zfi<%=AxkH{4V8+rAyLq$U!$O z?k?P5tbfLXnTNtu+-2#A;U8X!<II`~<n!~EQJ&Ix-PB-HDA5#&PAySQJie$|)b!P( zWZdOE%w4)$6_|Qi!{J77RX06tJu@#k{1o$aLRHy@p`%n%nK*S`w0V+dFlQ|9s(|@g zj!Y@qWSw<v6lF;tZ)hQ&F-0;)zHz*5$2)Rco%<!M=3enAqgzdXKm@EXDwnFuU^xa= zLlDZrr%VP`SU;Ur2t!<y(A`4sR7DYZa>MmYnv9$CH>Zz_B6=5aEKBiAjeD;V-#*5e znN&kPH@^X9R8nW_?Qqn*zhQi!*m#C`s&stb-O9|40<U1lX$)z*JrS<tI;f`2o?T!F zXiu&EajV{$Ij4pDQ*s~x@^ax2=&b7Kr!rIoP6!v0zpd(T6`6pGfZJuGM;XU5#q>x2 z{Q3hJInnHG%V9iZfy8Jn(ZsIgk;f5D;Tt2wezXA7;Ya&N|BFsjK37VEw#fyko{%5F z?MNfjy0WU=t6Z!nn8e&f!UJu}tBh1wC<eEtGZZFkY-f|XiB>0>12lJWk5LS%Yo~_f zQ~AryiWd(F7d`I0nm7HT>!>jdC<8LdM_haSl1N9rL+Q&Q*H$~52hOaiDMtvr$%k>@ zE`8||hXdCbWw<r1H}UCx6scdJO{J3_2uAd5+0xjHYTjllRQ8{_0$19S+NZ{#AF)4B z@rd(L_N|=H*B)d{SLze;T2#>EeMee+_OSY43~m!~8LgvZYD4-`=A&w@G=ql=XF;*l zf5sE#l8n={SqyC?G3`k>e;z)36kh@&;T^fh2N;t^Z^you;`5suZT#yOr%=<+_~1@~ ztdP)?A28p0EP}c~(+otJnD3QVWq7O&At)65V#o%U_FkXVgHx`N2IMiJ9CgjaL&t-X zoVx?N6D3X#=`lcz+36!eHlTga<xkTq|9ti3B`X~a^8g7t0|MTQ^yVfrNi@HiF4$em zzd|=a;r<zg;>R}HFDAUTq22Mf|CFDuuQy_sG;X++^iJl@S|l0UlXMJuYIVI$oMt(P z#j{EXaBpQ?nfVfzTf_3-3bnJS*U>WXZTfLao~|0`dlwm3%P%kRJOE&mB{j3Os@19~ z>^yx2F7f&1(;fuUWvF}e3BFWGSUCE;{#?n?Y%_!I&=w|0O_S_O$_?brSGU&Fre(U{ zS&{{(171nt*z$Q^TM>tq4F(s|k*+aTx#{jo>r5;49+IJedy-uvGuAOR#d61el8x(} zv@70V6$z4yOw_j#;flAM68Tb>=ZRYm*eebjcs_Wlt6PX@XjsW1Pl5M~C3YqvD-vUJ zFK`cxy#`Y8jJznt)y&XhGtQ+C-xjRzVUVoO=NTufNq?tJ;RzMCx(@hs3MTXsR8$PH zK9b8)ywdy0@2qGfA^~Uwi`SGKndmYAc({takfIz0BPBBjw+|W6sK8B?Pcuo`v=q<F zhx>RnCz^Ft7aG5niy<qsoE!afQ849^cKcgw$TFdQYt)Tw<=oLqW)KGRi&A4*V28&i zW|>bm`8`b8FLMIj?v$|=Ct?b$os?+@`JT8G!ef!D_M~nu$V$&~HnjKj@tAopIO7$8 zTsOjO#gj1-b&V+*MVdQy)Y5sP7FU;mE;+<98=byg@`|y<Ik3VoXH~O-)(lpD!t!Ru zk&qFM&c~q3CBE$3>n5stX=BVX{x!0Y+*`@UDEC+2JRc9{6%j{+dk*)ahOB>b<+iXf zdK+!RM$_y2DZ(FH4-;~jZpw^)TVchej;gf@A9{K}L9nHno`_C6xUw_xDsIo0Jss}P z5jvljy^+fS9?#bko$vjWp6??YpSP_LpO4#ucOBV(s4EwePmBJ5008{J|9{jKNihK- zX$7JGs4H3uGB)e<$UP?toOb3#kxpDz9chEe76j4Q3d6sNgIyu*kTdGNKf2IP*QNOR zn|E$*0tR7f3b>koU7vfndb+;8pWW?Eu+CQb^})`jqAj%bMdDs}{_bUQCsFzX*8_xY zX>wgqN`ElsZleXaEMOtr;1hJ9`qant8(Ubg4QSDd8CMFrk8i05@Hb)am4K1Q23`TA zc_V*9o)G2@?4EoSXb4tmr%O{+EF7jvj!ZF}5<Zu`?=ZhbzM7lB<TY8`up-VX?izF_ zSKm<Zau!hJaLC;9Ai{y{Ru<O%?epeZLKg+R=lKZI*_r|1J;uNo^E2;`aX544OV*PW zHgj_6%ZYDFHm$`15~PEtGm-0p)1dC$OXAbk7E=J_9B)vthET$FkyD9Jg04`=!)igH zS#c{YRR*$88aq5x6rScv8<eoXSa)6Gs80-`x^<Hao$<K6md_2KdY5`G2=t9c7uQ=e z|BVNd7L<TiWy?Ff39%cV?Hy_d-X`1G7oJ1(I~8n^<~fZ5wje}M{0!j{#iVN3i5j$q zA5TLRXr?Un3P-Gj?i;LkC}$MWcY|yvH6JDX1tAh=6yKp(vzX8~Fx23Yya4GkKT%mS zuRkkgA3{syvL*=?XMNCU;Py~0GCSEcNjw92>OA3^p(J0OT+m-1TOvp65J!hne#<=b zgsmh8`O1i!t64{#QE2Uhc%L$=UoyBLJ|J#PF){%X!_bF{(Ic)`N^GEyBQU;v874y> zMh$6td2HRWzkqW7`;%CGl(SzNG0h@q1YLph3#}c6B*u?IPM$!5Brf}0FfdaTKIMT5 zN(tu25?JK4lj5x-C9wgzO&rh%J6psD;GYLsV<W;Y1qc9u0~`Q=^na8IrGymu1o;&C zl9V>=H(21kMpP_w3{9wKlO59P3mU5rq?zO_S?$k7U_`6Q2Z4J5a}~e5&~im1s!iDE z1Hgu}8#*{W`cxkC;k6@w_%90QC?sD&I#3`LT2bFHYoeZ)6)RhE9wH!oW>BN#`>*9y zJ#<tUGI*tJ%Oq4WpiqCTXWd4)v4RfN6ITJX(us>6FGvsC<RJbulKO}PqC9vNRt(of zN$m}fV;}dk7reL_DDo>);H!CWIJDJ~WK3W;6`=3f^lWZ(ZP(MaZeVJ(HqH<S-#BdQ z4_{O5QK&pkwpRx_*ptNN`}D&o7b}-?QFq=(1uzA*&<F2`)&F`Fwkc$0=ZAO*UE5m% zXqRE?y+&nhEw`{>Q4Rd5ImZX2o*cIc8iHld-B~gXg2Ss_{S#CE1jMMN8})c1)aYR$ zPL&85*fwh<-~^udfm2pCU}jI9?ZXyt=SH2~!<Bw_Z94q%>!5FO(cCcAEJoQtV|Zlb z@L^zp>q8ian5NzC0zW85A$||qJ6-$U;k%ei(=kNMrS;GTy{JA8M9${>PPwo)9%WeD z$N621J%?W?3p>*G-p+m6hdW3I00^X50sX0R&Ienay3pf{S{qb`Y5e4KYgUaZ8a)Hn z+mh{)E;7;~mJ<5z0a-%Hz9m@|C0Zh3u|u6SqYvMqg#u%i?x{cdG^g#?<VC45`c5+E z>aRFb%KgcplDnX<cQ<B~_r@s415II*nk!`Oi~E&H$gG+Y@!3PwXL0qPn~*wzG+#wj zS*(k`%HD-r=L;dlqPoW8M4++{n6}7@y1cuc_$a3gGYD9%S2p@JxJfP(%VRw%Y|F6_ z5g3dlo>_JgA`unCy4`g4VYujy-9(ft_(e%EI*IriUrVrfWnGf{5*DS1d;l`#Qx|Mp zat9GC9{MgTdfxXY3g!Y{%GXOmS^vu!;bWO-<i|^)g2UooJ5<bc@kP|MxOMp<!H*EX zYUO2ew!{`7828`!0lf5AW1e)YV-#!o0s3tr*zz*{TV}fpmW!m9TW18B3Qsb^e2ce~ z7z)bh+C>O*##UTCJ{ba|Qle5t%N^PWl5Fu#Qk3#K*>SCk^X2AQV5BH3%t>%dXuGEk zrj1Z(9^&b^Qi!*3l&K7j$3@y{jNq8EW|(*bsH83v<i`xy8?Z&#U^F=5qPqa0U*YU! z`<29Tt54$<H`g(pjp*u&#5lC^?0z4ia~>Llb~WCi!bWds|Ah8N=6Rq0UuZLf0ss*I zkI<GE5|EJ>3|bhA&lg7r+4bUrQcQ@2ro9GCOXNca@q_V`BrF)aT-Z79mP1I^va=96 z^uIAY_F;f5us~#Xib=m$fj@NG2J7?a(A{DtHapHyzIvO@o|;}=k>~;8bi#6NvgJas z0|}3DO5vj`m~2YaL+0xi(&;P>&!LX)=;JC%F1MdaO>?1fJ#(p86bP`e$;ICr4rf1x z=+bgP$KQiO9oE|*I~|L7f46rOdJtwCq|IF7a!VNKd!)8Qy5=<KVFyQ4snm-@ML$&C zuXr)JEA(UXPiQ}3(S}PdRo)UzKUFqOXp)9}aWk$@@+5GT;l!hl&ef?cHXryFOSr&) z#C_Q^647i_GG5ud)8&Eo;s!RAJ(p$>ZgkD}EW(WRyR3LV(eVCbwSK<joLLZ9$s|(k zE;s#P6n5i0drj95@77-1eq;B=?T+s2>;8M8Q<4<9`3lYP5M=7`@%}gPw_DpE-fRoq z+uOob=(+-zM0>$b><3)8UeWaY?(`KyUbmGKxfj7|BclTO34(MH9-qRg@L8uE-;&;v zt%BWX`-Ot!CXW0FdeKhlA_-aC<hKJi2J@x5V+2YI`J}56-OGvdSvddKP-|8QvIng7 z#%8Kmi;!Mbf48%#oseRu6!gWiRh-Lh4sj$D$|Q!$X<SwcH!O!-`8Ih1{eEBchWBcg zEf*P(85WKytN}q{$c9`PR8rFO=r!dA55F-Ck}gGoV#%;YUF?UdcMs7%i{BPAbL>qn zHIl{c2ATn%ow*mBs0tpunAxULdR)Ptl#MazK<V$w!eW^&K64R0U?0QNuXf3vco5T# zRi2sFMpMDMg{;}>fQj0gH4OBy{j7U0Km9%o(w#u}S#CeJ9-K7`$7nV=EX7WqHz(hW zz2!3XC3y<YW(y8iSZ@L?*Mq!%ng~h<^LuYz&<mj82r+fkPYV9sD1}>c?$T_G8;+^t zfILB7=4*x4btbu(bNZX7y1zR5DJ8{lEF==?c|9c`evqKg1|vSheh!C1Txa+_x#}#O zDR2sdn{amBn(TOy9E|&VIr2j;0~a`j0sX)Hcx;Hpej1^U2Km1_RhwfRPYvIbAQ*V9 zkxHPI2gY5h^&%NoT8d)OV7%Aeb{hH8BE{Z3ISTf(@UBSmxW^R&gMbuR(3tFt8-)rm z3v5qW@<if?4MKmNhX6|;N=gjYw)p(|Cx&}V7F2cqV%Pd_Bl;gPtRgBTBndSmDm66+ zBSAwsJvq}LPrt~xYcDe;K_gB*MprK{Dn3R{8%76KCO1nz%g8dvIDZH^K0`P6M7<0{ zP9r`wCRr~}PC+Sk1SuxjB2Qk*G(R;lBe5hkSrHh9P9)g+FZyuBu3ZTCcU~}m8`b|f zKSvu|9ZMr;Bg_9VVF_u;X;G=^87hkLnLWUN^{f7xe^>dpKiXda0O)_e2LGvE8vJ+l zl1@j*%-YORM~Bwd%_@cuvY#Ga=;hB)ED*5Mp0sQ@6yJ<&Fk4fe6{)0rL<?&ZMeFHv z&r1l8`URww1j+~TW&jqTgnxz%F^oEcI9Dx^Ed=-h7-Ee$5vOlfN3$bYiaIXR<E757 zT`u~4kZIzw`Vw<AhJ@At#G_JX5Qn%S4-w|<6I7n$baYqk74(F~uuXhwfzWE&S08qh ze9tdqL}))lt*0N!-?w1|R#+(@D0QE6HXVPI|CK=;u)4Fq{9WDp-wfhERoj2A(7?*@ z@9Ml1`l2)F;kzDCXuEuo>s~~$n>&;|R)v*VJ({Ug;VX0%JWk8M-lIoY2(}tELru0j z-MnK?&6;6{OhfoG^2i-IIbQ30MRbtKOvvWSuA#G-PcK(XwWq+PiBAPixdykrEVt12 z1#sOKaqd@XbUkBIK=`oige&a_Dl>J;uD5C>b#E=m5lc_^h&gu|CLBx3x6%BwMHggm zAiVoki<}=`?*=AH(g{qA-fLT@yqRWBd8Kj;y2@Jw%WoXGrk2dU0LZyqYpTX38ceQe zIw*q!O_+<zUFJ|BN<nvUw*WcXQx?n@d-|HdEJ|&Ihs<Ky4;U8&|9TIaiQg<UYSZgh zq#fv$<Ba>AJsngoY6n)KKTr<8gwirr*CW>r$81IF*aj4^O33AMtoBWT2AnFzoG(ES z2H;;R?ClINBGFHpIp@iq@2|viQBJ)f#7WXsmp8t`f_2P1;u$Hd%4PL992^}<h0w}0 z0&4Q3i#ySD7G2;eGw>GSBcZ&ThXoK1ObB(M%BC!^+9${Dq1CI@e$wqOmO`@f_Uae; zDItmBUgv+L$x-SvDL+l)*Rw*&p4#j2E~#upUuH+0yx#HL=#X|$-0Tw@9N7y;@H~EK zL4XTFSYrc*T=TRqD;NZYDvFrQ0V#ww!sW-|GZT$6kB~3+;r{6Y@B!)7LO}okK#>3d z(Efc;^bGZE9gXb&o|Pt5Ih((f-20^l9~(LWN<eg$3*}ZIrFhHNiku$J3)%F{5-Cq8 zs&Kz`;QQlRGz^i1{S22BKU5Gm#^uG!g;PBfvxuf41$2`CHO5OLMVSHvv|FrBgZf!L zD>b-BoqqYSb3Y2iN|o$k!ujK^3-3bkL4HY@ih}Qj|D}_&-wXZv$g~md4PX3Xuzjp6 z)^@qmY*@W;^X~qRNZRX3Az~;$aWmC4WIEH*aQ%GCe~;*#j8<r<suXSr;!;j2*lKlW zVn(NVf?31c_4P{cqxREeuaIiBAs@b}Rw%9w!5w<^i{0}N9*a*YCaD34syBT`mGuZC z0dNqbNByiXs_72vY(f}OqdGd(_@cBYS)PkA!%y%<0ESn$8)ruhEw=Rx>Od+<e~WW= z^*#Krnn?;Zp}AAvO=xsuD$?i5ffag&a6hKqko}=PRz>)2r1uf){8LX!vt$|`F8tUE zA<BJ^=*wj^bq+tjWN8XaEP8tP1ld2aL@aJNa(a*5xB^_Apv)D1zM$un4w)AYwq7vK za8m$R_HEENKKYo#9w>i4{B>0YOR#z;SE;=E2W6QXAYDNCWmj_nvJucH-`8m#X6+Zx zb~-5+O4nP1Omvxfg~~f+v&g0(vo!^nqI^_iG@fYRC>ZENdm?P>-Vxz|fyxP2yVC%( z!5~_smcMj_(s$behgT-B8<pQZSO_Nx>$r_T%i1tunwOeb?N=cGj2i#u3Jzl~2v>g< z7kV;H#C_bP&m_mgK=l3N%s%R>q{n_gp7hQ&U|yjVAlOtl<@Lxh*J)MT&d&msUrxn$ zxL<!NC_pT796JWwXTdy1B6Pc=QaD5`SZE<yAXd3=&TXj7V2szsWJ_~V{Ny-!onxku z;)HYB0mX4A!s!{TNF3i19L%qM6hOB@lswZA8!z|W3<D`D)<1m2`0ZxXH7=}HN`s2z z7RFc!N&2ayrb@*Dsb;d~LV66-0SA2eWW)vnJshavj2Kd2l&!`^Mh5BZ8{sFvDJ1{o zmszOdxm#FIMGM5oB=S8Wu{<-wFe=4yu-AsLzB1PrQ-;%(y{T%g!8y%xd37b@;9<S0 zqFaKhW`8Kdo2#)I$YuGaM}8DdRAe4!PPXgB9~QBX;Vp>5;k&*OTDU83z(f~lOV$tl ztWNX{&7S$Il~pM;^DCSV5TfGuY$8_c{p1{5B&R;_Et#StIP3|SaQ_vRB&#WD?A(KU z(6f6)m@do0Awss{yQI0lRmkchBvTr>PnYZhqj)Gx!8nJ?75uU2R=9g1<M3h-poc#h z^tEg>IQcNr1eQ@`?jlZjB)@2bJVC5K{aw2!h8X#+b!+@tdZ^Y#sILgi)TQs%*7mnA ziQ2$9WHl!7ZFLT>syR8%SDBJaVDBDi4T^)Q0A{R<8c0z&yf84T+jYhDc@eX<N_<TN zuqjc$WN!v39RdE#r@rvi<i<uvE`hX8><Z$m^|ZesV;oz3NI#-Yl0GVCWJ*r!QT|4} z37pAS)mRBr7EWJPV6|NCw8-sNRvq{#gu?c#yB}=oGw>1=II0JGD-vs?g&A9=Mu|g7 zPvkMoieqsRN*C_o;92%!WBSH#lO6Q;`_<(b*&>CVCVC;AG|~E4Sv>gMsnNH=&&<)s z)(TVpb!PR7MhLp}xG68Jw^O3^up64WkLPz%Ya(?&-DB4R`O!;3{`rUe3v|pE55ez_ z3-sn!Z=A<O{}uS}o2cU^RE|0D&0U;|o{!W5j_83I7<%h#VY}=WQQGLS912efqjXKK zVOiJq7Ip28&RI<x_voA7j{-I+Dys5zZg3HVH{4+*uj8Wy!87VoL%1llpo#%Ur9}qw z!UQt~NOrHTMQ$&N>9SsiE;4QOPneZo{{QB0!}^_441c3M$=^H-<=@Wxze4_B*PSId zVI4pZ-}ynMoXIQx<}3Q=(J53>i0d(0(?e_%9cxX33i)WKBbceTNc;i_+}YUKIMXQ2 zl>?u=?DcGiM;2kT$2#x%m*j%F<!qeY2LghGsA*KwCAD7|z8~zbB2>9$@Zl}y)z{eo zmheayhR32&S1}w<2R~Bg<Y&L#p^5@{el-jt&e6~qGYRf@@@0MiylqgALeBgu72CmV zFxx+T>7lg`jbC@+?|*>t?)3>r{<wkU%saoTz(k=!{M_)V;fcIQuGwE&e3DsPM*7g` zZ}Tc)n3R^&q6Wt(-W#86aY|vPBzpu+$<k%0Mm7?U6;R>5=F6O5r3;_?XE2QeW4~iV zZ*D%P<P8|wzxU9qI@9#f^VAKxC$jB0WAuz=u>1XaZ#0EabvO0O07Tu#`e%g1=xL>A z{kyr!e;eNa=O#P+zd54>)%c9kti;5mSd`3vIH=O-B+V!trJOBLI9mV+aw5w8Jrq*g zd@p5$yaGdnToR~XpzPAW3F_xG-5A8*#QG0B006=NWlUo;OCz2CZR8{stN+C3?`xgD zHat?7V8liZFktXn7AaqVGMK`(`FwI<b#|dj5_$YGHr)3E7ZG_I<xTx>{V<X335OXR znf&sk=E~h-@*!i=&kBYH&5Cd}*LsdA3)E%CQQq}5v|+pP1wi#R4(nZiRQ9rX<%)XX zEo-~|2x~W%26rD8gVzp3lFGy``KU?SCS`X}8H&Z^DpwHez8jCe^RJ56g$I+>KM~a{ z*LGvecv}PdEEz_z4THSvrlN{43~Oe31mky|f=?33DwF|27JIm<@kiNLt&NkE$Ic4@ zG=X}K=3|lig<%jAfzTYA1oMZFha^7qr*RB->}@?-HP+lS{=Zrr?L6L|qrG0}QgUdm zSEUn4Cfdl;M(0r36e3eFU7JmAi6fb(@258)*FXQ9Oi4g=q+F+ledtQUl#RY@f58-X z{^n(0f91s#1RdIBZ$Jhdv#^F9AZkTT{1bMb6#*9K&BKGJg7xGvR9H_vvRHw`_)(5* zZ!zkpK0q`NDNw;HrYQAU_NqJzHoTEF-IEKM1!dkkN&kzxCA3?>k8x&VTVN0gV!CQ6 zjvxHw!mz1ZeP^@s=7iv4fo&b9>ce8}I%slnI`>Tn;V%5bN(N#WL4%-e8?Wy5+WqPI z`N7UZdt2QDtZkkaik5ikl(&;_n}Ph7*@zK7Sl^MRT^cfJX}_UaPH*-4X^1eh;(1+7 zKu|(Zdj_h!&m%~O#hM!PaC;*=oO*pTwN#toj%mnRc={cn(IHz<;I#95s433mfo+(X zpbGI;Ou4bBUSKwuQF_T~V0>CFzu2T`)Os1{CG0FT#f`45qWzg*^Ph>*h>2VXO&_~v z7GL)uKk8v>r=dkvxo{sjC@Q6P7&Bg@Vp*v)n2RM3KI>-B5vx(;Qu7pkVDKH+_Mu(@ zKcns#c<X^`p-;1n6{bE+%L0<D2}U0V0m5sRhat<@Q$6LKarhGPx@;!HNOvD8X*uEQ zZH1Zx?mP1b7<mpu1$D{*!*SFuFkqzToyJ0G{;PE@067;0{E|)Mm0To(AgTCL4(r^> zlr0TXCQL>59Xh!%PJiy6{UX0U224W9X_=+7jD>}`aOba?J@#UHJ~jR{4jnyVcLW-e z=^wvbCl2KITehS4aX%Ig;U~!8eB38kvS&CtET1Kz2Pj%IDm#n9FWv$rINqbJV#oep zU|>!Q(TRJc-F+_Nqjy<$O+pPJC)~69hqk8}E7mi+&DK8X5xwG^a1R1Zi1RkwIWf!1 z7abFf&QX_37}0R5h`=CA79)hsDp58(AU@b5a~w2LM{H)gW!}SEi_!gvTAMNc4eE;~ zVB5R$Efq^l>-MLY`)P)-xuKqq0m#4Roh+Yxg+gdy+(OBt6X@5WNXjuCtjAlz`pam` zyIQIKjB9>yZX=4rvj&y`*^vvyhm3@U;ls%o+>K6r4}H9$9fQYJ)dDLnKOw|Yl!s-b zCP<?jZ>}PLE>-Lll(1Q9QSSq0Gu#0T3rFyYj2j)g!#lJb)GD}pZ_5R|9B**TC}p5( za<}^VVscJHcqoRzq+0(v)Z&~y@WJ~vt*U2bH7zZT8%UE513R+>v8{$_z-@ORnOZCp z_!}lQfwhK%85wOBWe*>U?+K0l%e=ZO0G{q_^ybI@d1M9TBg*TpMkl9@)!aJbH3Jbh zI2%^td7c7WH^_@zw<+igfYQF;De{*1>`u99V0Ft8{te5z`mUJ}|3QCzch^LFkjX)C z;Qju}^xn&M*6GWQGKL$LG16cRw~XwEI+Kr^=ay!A!yDPJ+qnPMo6{B;>qM&;h}7I~ z1dZW@u?;(EVxN8yPs)P($7;@z9&a&)RX|k+3*KAk6%HF4(A6AEyIxGekv->al+cPc z`>2%&TZ-y<A?I=RrR?tD`o{!=MX-EauLDyf%aF*BICA7b9Mkt3$@{6b18!D0B}@ro zC<h)FftDI4+6+DD6kwaCB|BvcEcYihkH|70AmM_L`19kL^!c=vJCWk{L5LM9<RROm zr}2D?2QbhT$20n4<_-9ZaL04hDz3@;`Su&^pRo%Ouk20dFF}y}OArYEFLA`)=<h}C z|0j?*$^W(<poiXkf@Dd6X?5rIqrRFi6Y!f3rd%kK6=D!%7xU2>cQynQWfD8wx)ZIF zxdXS_h~Xr))UX{PAPt_*!fr!PJZH>hjJ%9iouBZSRyXjO9qy%Y=i;hvRS|ei1`?;Z zfI;xoKQV<=B2nuh2eD_r914eu-e@L#^a9GqB!-z7<I6Ir&5@_N@$HoLzOxw+C65Y9 zDrKY>P^PphgUO7<tNYanO-pdaqu(2qeL*1DZM^at#UbSoCsavG{utPjDJ1&dww*oU z_%zBg=%B<??Vr*X4W&r~m`;SXBmW&2UEWShD?Wnbp0}N~Qr_)rZDPcg&V<04xn=zl z?cEFPCCNA#1cZL$XM`r`H;A9QnfjKjvvMm0ZZg6nG>{%=w397ZF<74-%jnXSv{e2+ zw~Ln=9q1w{(*aI2Hp_@%<qRMYseQ?MKLZcXvCBp!IaSHq)x<t(UE%Xj^VmFMRe}CB zPsra|FY5nc9vdrLJ;%QUE=rb5W`G`k>x)WSf2KcpFjNs$QE7{4q#Is=%w*a`^oMJO zi9jgdoKf}ep)1Cte}oL^y-AV_Ir=w~Qhg=@e@^I8pqDH<bTn*2??qrYJ<<=!w*-SQ zYQWo&RRD(|a0Y>tk4lh9Kc~?okmcoW5+#m*gZc9oK~7C%4oHLH=@=T$nPN8|Holr2 zjyt@+pWq#xV%|e`%xq#pZce}IQ$DJHxFO|bt$KqD2Q99849BX=<Px>Q?_<G%_Ald} zoonMuW1AL~>uEXSK_P;}cB!U_#JQc6JxUFz4ZZL_HNLCj6{1M>nq-W|GUn`E@+NGg ze#S%sw)>uoo;6&$NIJ5H+P8lxm$7x0d|-dc(VxG}4D<iox&L~HVENz5g@%>G1`Fa} zX5?2uW>B7FIx=?To^9t*wlM8VYsPN2?tR;a85&5u=sAawYxQ*e{c%MLfQV0_X6BJD zHif3^=jG$vCoJdqXh*ZEej!DRb`p6~QJ(CsMc!OyPQ%b#X}(O}hr3HrG1P;V*C-xM zm`VYKJ#cT{6n`|nwcM{&#EE7!Y~fO4L=c_qq(m=gn?@Fu+@}A06ucsCs2S1reKi_s zuA<OxEx)yxkK;9z)JmH~p0s$c-5FQboDiQ_(i?{pLRWq3=T#<1<3{Ua0rt6zyC@<e zG8$I8R%Ae-2Jw}gJ@nu<2K75fCOX>t(-ua+Jg!iwF0L)~;xvV=`|W7|vEpE3h72vC zW`9AUb!20P)YjzzN^9t+U*hAEP5Rab_%WKHj_GnHLw)$x#@=pl7mVQ>7msQfgLa*K z6=|VYi$-}ruFCfzek{Ig+md(oKF({ZoaE#73dQ5@g-)A9L=eQM4iEuZf84cTrF8cS zS$Xk-0tjNowxRN^9KI+Uz+_K(Q~LC#ygEI~|95Rx;V!$@Lh2xA%+#*BZ@D;XMhNSS zO^NgNRK)eYk;_|o$LBukQQWa6g|K-?xww{!8!ToiYEQVLOTJrFrG*@w8)a&BDq`+p z5hG^tvQmOcWF>)t?x0aoLNZ1>Z`;gCeWE*ejD{LT99@a=_K}Mc#pRQxX}5d|-UVoO zqp{)!fw;p~shheH{~Qsa3F}3v`a<VrB}4XZa@7!JFjCrR-^S_Os9^&X{@zy5Kzmgm z`3)%X>{|PhqG$%4{qGkHKEQ99*wC4o>Eg@J%b~=s-U>9688YG2AN(p5z)Px&!i_~Y zwI!j<WAkzLiDvUxSZxd&!GiC*0gXiib*NB4-TQDlkPajbNIo`S=QGK>8G4IPzt28~ z)I7th!h#j66zU9#*(uhTvQ<;HB)iA%$(Beu#Uxftj8;&UD!m&wZLUyizG%H86H5J= z(2r@NEBBOV!aj&@^>v)y*ynbfr5!E?9BY)E-o;a<b5Ohns{1hLOd}2R?@?5EVMb+j zW?Mr@qR_cvW({!ouG?dS!GKb$0$Ea(T{DQ)BwrtjDet6AvJ=q*u&g?jnt12>r-?QM zh_jG827@^jxqAzeiPzzU%`0GLKe+WbUFlp&jxF&U2UM-hY~kA$q?MCzagptN<V1E# zkILm&)YR+LHFf@5QnRWK1uL|1n7GBknpI$w+d9d`@d9TRWw;~G1m^IYY|U#PKin7! zRw`Wu6_iSfAZ=2mE_SU8LY}IWvz=+3PEKXv_l6$QlfKK+-5ADh#5s@%0##{@;F>W< zHqcMb8)2^r0#KOXG5h8~<j!r0%1Yy5DZN;TsDeS=)OlSE8Mp;zI+RqsyTMsVO*_&Q z<EP88KB0ogO4JwKC-6Vn=v`*0ZIU^diW46|qDxB$&$mfS(1{HqK0jB`oKh#toxQ=A zDEldFgkh7FB*F`~Bt>~^N*@g2qzSzix+SKG+v4cadQHow2!4(gWRS7M@Y%u%^n`1& zM>B%DWUO{J_;x^8@kT_^?tE3tiJyR&#$6JtpATa6of~^aY3>fr7s=2N7w#OJ0o&Ha z$dbO2pv3Rp?hD%6pbj8MV9zpjU&YlG?xL%`lf+07#wa2yRG|du@)>^%(|+CTq_p%g zk{usoe*6vgVAh(>4xBJ9#*bIOK`mQMhl#)kg%6oY2elOa_$?jpJD0{{iKxae7?5H( z0?k|+Gss?`3cDSUzw=$>5f+2BSo>E!auY&@xSB4DR-(7KEXgi-_E4W|z0p<XoWu}J z$V9R#0BmOP&-4NVKYMc8fY5=s$f}(&@t84)%?#+Y_?Zd3tRLE^ik@kK6R)1Y1j0Bz z;oK|~__{)i37NrF__f0PDu$92l>3~%0KjW{@F1tgPT6S`@oTs89S32Z10XbA)?pT% z?wiZ6M;}<pAIVo|#u|yXr(_gbX3@uOCD=3f1bS-n_KlSa#=Ob`nVjMS5iyN^twz;z z1T+qMd9D>XBAp6wKx4e?hNZ*QGOKJmPQYtevii0OIwN9s(Om-UHscRh%9Q?=vRNO2 zm!@4?E3t+$o(Uu0%>1gZ!eJCix$W*ZzrbA*s{);=wa=4DtdPO${UWx_r4-CsWreVU z7{WtGIyys8unj6m)2kTalJ_;Au!jIa@W1h>1+RR|A4u&|k9dscssw3=V3!-0h=iBL zXm4kD;1sdKM$<xoe1e)uWLzj~`QhUV1{O|p+jWAFZx|iApTFu`q?gc@GF13b)(-}e zbVbiuDJ)>_LDPEmWpFts1vsfE7bN}FeY6qy1x;8wj&v1A4l?N{uUufKD76)Y7ukty zf(>a9v5+WAX~WIih55w*GO%7>S~WeUYDWK|%{!$G=o7{Y2U!PolZ+$F!D(X=qB15? z<IeWXoFkzc`WUqjJZ!F~4}#eyMiD{7xygI9-Bc<%hKq5Iug(*2=?|0z?^`9z?8{_8 zkqU*LFvtpttf#+@aC(y)H_Hjx1Q>u-+>4X|Y0F$O34UDfvc#p?EI-*IS5lbpD~>!F zw#aBP698;@8_E<?0*Rqr3|TVc@>y{8yp&=elwIO-_EWThk<_lyZaV>qJthNk7*#Hb zPlmvK9Sukqmw@p@1Ow+AnthO%UmoC|&1QXwoo+6_DRCc{8b@ESpmTLrPT==CHx39Q zcp{+$D9`}?vzI~*r&T)$o$gCtb3Q@wy??oyC3Q8diY3B(H3?ieweJ<e%Q!#rD_+ft zKu5Rb#?hm@(xA5pXES@-@AuB9TKn}yW>tDpMtndsnqbG^h^f$9*h>VhG&AUuG#2<l zsZ0Q0W&P^wQBb!1gAdjlx>XTyy~TQ98i8R;Nb^uX0$Zyt9p*OBlo<y_8n}GKZ{EW; z&Cb)yp+*;^Txdn8ZW4pQGAQ%oaRwClWH3W{2HeteG<dw<B}xGH1disgMX?aVp-y@r z?EJNTX1v8)LO=`lkw2>8dpeLu@*iH*O=&kFdIq;tKo%8HYLEf-;(6`9JKSj}_7t)o zykC~79&)v)j{p;%O1A*N8NiOG-Z=;okMJFD=D1ela2MAPNOssED~ot}N2i;NnKe!3 zCA!zsQ41ACd!1QUiNXLL$Wk+1H$^#N&h04e!;OxO8W|JY)>14thp_!N#CW9J({%Gq zvjqm1;&L=Fp1aoLQ&nHECvlYmpUh+K>05D%VLCqb)?F7ctA16lZYc9x0NHndK$caJ zxF=}+29%!%bN~j2iMQ60;FNIf6}{`-z?^i`tzWQ&t6v3*a!TEG8JkEFlTovydkN8O z%v$)(y?eEpOVRP=>^KTgIB~f$3^=|Rv#sF{{4m+=ujcLi`dP1G8AH@lY=nRL7J;tf ztl>c@vU<Lee^V4x87wBJJY{}0VIml(^IrI(<c!C)(8o+j^apHNB>s7<Tk=P;f1ZPB z(_n>+A$$kmHatOHHW%MKjE1IEy%t1xteXHh>DXUE4rG_IHmk&MO%^{O8*Frl=@kYP zY*F8KW0<!rTl6`<u(vPF;!)dIgctnw0~25CTIi4fIX_rh$r$k$(2UlGtBJ~q0ta=7 zQZ~oLMYJphZfA7+4nWJ2XlbyF-v!6+3-{^O)iG(i_B8#|<n|r}=QEG$$9YB!@0oKe z|8!C|iV|rGBITZp`gv9s^T#ha)z(c7;tSB%3-uw7M)$AIHpUs*hlOR!5=%Lw4Xu+4 zj(6{xtrse*7$gDSmo;&YSY1*AmG{p6DBoF>{kb`%=(QGf*ew-Cv`d(_Mn1h0lbYHM z0|csLNzayYa1Ujm(=`nEHdsLia!_;a>UBi*pl;jI-(T4RU)?AQ^G!}oFpLLCFM?Tm z>|cHGgJG9y5~;BC?h(>1)GZ~cEX_{Ht(@|iJXZmYx9Hp@v!3=bPr>9@Da@JFwwTVg zwQi#rxT$=Usa+^XkTO+uw|95$x0pb+W<3Ix)N|yuY%IRbAGRO|<kcq6dk7ECf;pSM z;da#cf9PdHA0PoY6V1&M%p1hvT|wDpz4T~bLd!VX`e>u;gkR3WV0BeWW!4kGTmw=Z z{d3f<9rl~6etRZClRklMK9+5g${WQhIdWo1CL5JZZ2^;B(xpIK>mTM4&2v~?VkxBW z^9_(Wt#y=rlmuZtPu|325q`FgNfucon(-_;z=%LAy0*e+lL6!7IdEc1ueLO&`b^y& zFf^j@Q`1MnUNb6`xNSxK;R1t|tbe&I<G8{b=-HO!+}hq4cHu_Hr9)pQOYpMDm-qQ; zFDSt@m}nL(YifcryackX?h+DF%u<F)7N$`oX?_}B9@*iep|vUa$l6=z=5|ZteA$?( zS(Cwjwk!e#Aeb>OR@3zJ=8iz0!FyGfYtSaJK;H8AZf5afT`IH?pI80?NM=m$1IzO9 z;M{f5POo+WtFOLJkAfg1EnKr{icP;z-v1LlTI{`8IeH!^?Q+XEMcSi70i!{*H{)qx z2e(h3qk73xiCJf#cnI=QS#y=wE&QOm_GBjEOg2bL-uCqc*UeN2u+zW5t@9C`QBD0i zj`_~%P)KsIRu1?EEh}izw(u)+CSCua?+w=&8i@PbKlFv2v4qj8@Zbm)4mpu)@^=^H z!yT4dq!|_{1}<4oUw74l?P}mTQAHh6gq@w$si=R7E3onO%8SI+LJ-p$UF5ST8@&KX zwsP#oY2nqpo8f4NB-zG#Rfv-`{NMKyXT1q`Ah-mwWR#9e&PZHl>jIHvFt@8kyqfAQ zH0RA`?<5>p$igzXv_5M*8rxMIoD)O{t2a=wsV&dnNMUkly*oLlf5DWLQ+=}T+&<sj z!#<>|0<KNDSn$Kg+<A&nXT^yvC4#Lt;53`ERU=Z7K`>~+(E#QNjbvJ+{_H+X)Xt`e z_XC#Y>fQ&~wk9jn{&j8SlZTz$e^Y1eX7`M!Bs@YF>%I$tyuaEm#K#s=Jb;NE)Hhrq zIdxt<Wy&r_YC%++nVya@bPhX~M|`@nw5)iWFv(K3uf`JVPA~V1F)@Ezf2`KXuX=u7 zRY@Ic1XP9NeW2%rG1HcxY@KJ39#Svqdf_^R{1RZi(&E?ihEoT7#N#wnvJHqJx{Qi+ zRp5`D;WZ!B#T+QL0JpS2XbaGu5wp%Y26x6@X^>*W)I{1!cScsv{hp4<Qb7!jn7?8Z z*OJ_nu>wUvTQ7Khwov>P@~3p9QSjt)!Ldhkpx4$Zu~_Lia~0GhlfoNeyoEn;(8XR! z@FNcLYL&UnyXg^s^|Iq}=t<b0?DG=Tu2-gJtWVkjj;BY5AA@vOUx+U0!CKlav!LpH z$w=ja(*!*z19-Om4vG%EVI)iMJuIHZzt8qjgTg}+dOdG8fAn_QS-gUs9gRr!HZ}s0 zr>AG8$=};$^+@`zNp6_h6)<7h2{3ZJdAOTuyjdB}t2i;d<5#il9(n#LygbZ(W4`~@ z#Eu{U0I>coAN;4V;$p97Yx`gNL6>r$^#Kcf*9R5ow4N1yQUn+1ErAqPF7F)j7NEx| zDxgplbv4C*>MGwK-FcR3&H*6dfKLQ<ReKq%Hrvo!z&mkwhV9!Sf;`wrBRM*#5kbwA z!tV0R%HlUUQAaa;Ph25MHQn{n7a<^fO`5b1KQcIkXY|3bklwb;6z1-j181|CTl0PR zl)sUB?AeN!TX8^?nK4p0%b=BDqz3k~k>O!!IK->O7kz)FiLSqohRP73_SE4b5+!lV z4ZV~NVNC0;cMQ@B-A{!w=A%V?J|ciq7U@#z3eFmz2lz0G0<ibuC-(K>2ALSsD?6}% zi)28A$qEd<MR$Y?U}KP%f61;P2`=L9R@7@I2zB|dfLTvs2`%C<W<H3`Q&vgAOqZUB z)+sgd@J2w*=p%CXl(ps6GffxPYYH__aVhrX9I`!$Y2Vk9OOW$!IFzVdY>b$$p@O&Q z$lP0#ow|MFkP)!S*_I!uopYEDJ(fEMKn6RoI#Vi|kDSIf#V)#neI-U1WY8K)X6A(o zj^i%=CL}}&WWet#{UbMunPl|$mfZhp<SxUS{?|W%6C*~8fTYsW4bt6GN{<E+MmN%- zfTO#+LBKIuLQ-iMNQ1Nj0us_7XXl*jTpV}K`ThUfgI#;_y0$&o_x|3W`+Y+Rzv(jN zz7Af<TfW7h{Xv*eb>=5Sen~B55nMwfybiE-Bi?+;6ZgF{Pxio~p3T9~FLqxplwTdt zvzw6K7Mw*hXwT!yPqI$AO;a?3sz)Fa$3oqQTb4<b(gG$mBo6Ztc~AjL;n&AwrXORn zCF4qIVm&#usH<p?RfrS$RdZm`bkQ90IAmYI8Bq(w+zWsxWQqEfCI0Lf8Wo5^^qhuw z)9*+9V6IBt6r+-F=Hl+a%?@7~Eve~ko0HH#jTP38t;?ekI@ZJaJQP8(Qv5W*ME;}i z=P1_rWr4HpQpk+31g761_eAus-*S;+m&1s|TT6Oyu^y#*MA^8X{&2+h=I1ml-zs~D zxY*T|B@G9LPb`sZdUH0`3}au0#hrBpM)r!$_}hJ&KX4?W<qQ?UK<}OHWIPYrgr!;y zMdMYz_7s6EY!a2gtLDAamOmX{`%?@DyU6sjy@~V<O2&w(p6_!dI5H5wN#*4DF5KC0 z9;NE~&fxvo@rmoG=;#EvAjIg0qv=2-^DVB~J@2-nqdh_N?qa%T4*Ny}LE_CHp^~nu z!~wd_7?)SVrQ&vCdB%pEWlW55&O-EFI6QWXBipY5*sx<6u6e7&m=piQ77rt*nMn;j zllj3O!x{UOFV?SCSE*w=gN$(}w&XesK?4~lVjV4+@Dsm%ikK(-0|WV?!pAl`_-Qk3 z9~FGaf)uES4>B5!F4I#U5;|3Y0)b|WN0}=$_+23FoFJ{<TF6Bc<eKEbbr(MQ^P~8B zWdF~(sVC$YN|=<h1WsmcO&nY)zw;)3<Nx`Wk<8?1`W`VT^$jtQ_#YidTWe1@#I_T# zl{=zeo1$-oIEy7g%u223kf%r(!K}*qqBjeSCQGCzovL43vfzZImZ#$@*fElR<~&;V zR!)GGFlwx08K$}45R6?YgOX+Kk}VZqg<Ho>k0A>3nV}LEB32&jXC<uK{Q)Ck9MDlH zGlPz0h4ObH_;L=+hp(}%H0YrrA%z9yneR~3_p*VkV<u4<nMZM2QgSz>JGW7nHc`JX z3U7foo*j6;?WT%u@=mI3DxvP`FKqFntEQ69LX)}*BUWs3yV7s&!(4Gxij5t*Lr4?l z^%G}gKhi&l^jzJ%&zUILmEl^P11@Wjqy06mptuP`dFEI4E-}G{hddabY*8})$RL6L zxk{ygx?Jt0;&ZEpSn@?D=ti<xcqG&x5Ua!5e8iezMg$nS`7BBhUBg>Mk@<D;Re(-} zgQN}s@14#>iqHEQz)p6JiWR_SnXLr3yCKqdWPz#Q=jU5C9aUF#{zN)XKzB4G#=C^5 zNFShHR;TDw?b-6yipZL+Q2u*DeA*%C0Y|FO<&mvWP${i5+xfY$XzVxJI_AWDe3|U{ zD&C?nR)HecDTgSMuZ{G?Gx5uC>S_h1RfsjboxBAkk*D$4HaaxUk4zF=4m$A13e=qs zGqNfpm|p3Q1PN#5XFr_RYFA8mrpt;6YQfsOA{?5;KyjcKzH&L-7hGxSGP32!g|RUx z1GiGf_GIngTQgD$+#(}QM5xnyJVFLjOrzs=Mh~)|vHZk#EfCX_MlohcFls67S0BeB zx^ZnqCrD#jkc`%kvHunlRwGdO3=1((f<-#g`XNdW&6Mc~b!Ngs2|WJX?Z<S0+76j3 z-NorbAMCx#@l{GeA_^y8j}094e3d*1P}AGBX8NwlPguCWz2ar2|H_8o*Wchsnnva* z^yRb>)p~uPP6t<$;fwUvgvxOe=4G<f!i2^TJ{TP;UuON>nszJq)1rI$TqMz>9&UQ) z+r8e#^p)eW(7%3aZi;2Lpl}SysW&Vt$R#?`eLNXrMI?3BQ_yk+dv)kJ-Z&$C3=i_; zn6$t>yFj&G$Y0lS;l!w84uyfbs#+&)G)gKiz>a4rBWs6+gb_T|5pvK|GlgWm@P=UC z{NUs)SEpAkjERxExx|lwn>vpn?E5aS8s^xm_Q<2?-hAwtRFw$G5Z5ZpN$Sc0en~cW zEk|MaBI5@)54ZxXO(_hhW!TaC=z>u<G(*lqvKE^K$4_<NP$sf&ZGwtOqdlGqE&-|r zem{&=Pgu4n8B<VnSB1S+2(*9P<iX$1O)y58uF^agt3_Z@NUHHZer5W6)~HF3ZSxG% z{wG#Ob=J)}Kqya137(*fwvTB$5t&ii7tf;?x=zY)lG+PjrNS0^@Pw$0nB_iE^QvUK z5Pa4oOo#(GR0ouoVWenbR_k0SCt7B;n#GhqKVQ?%hUoO=4X{ZXaoxtM<EFP<ew&iI zs(@xSR<=HR+D)rL%s%_PnDLvu^V_ya3k|yj95Skt^mqK{$4rvw{zdg1c_V>-U=w2( zs%C!hsX#QD&P)aho6_+iNU@r7e##1}qPGB;rmsoYFz?$^oeMmNS7j9qya1$Sv<#1I z_F<0<x6Zu~m32RMk`xIa^04GOcqN_z+FQu8?f0{3ydV<f?+<cDG|BKPxWt--a7^DX zMf=T5%gy!NKT2DAdrk2~XrEGEle=+@AoNE2&?xaxC}3;+0+l~Nx4C0SRoreKZgj?2 z8<dOFD&Ir}`Q*J8&}0CEgCm+gC)P{urQfq`<Y7*06ggXkldKqTrgthn+BYsvNrqym zACwH#c0O5s@uKhZ^ohp!Bn02qA1g-BSge}5vi+NU#T$5=q`i<S&fpIQ`p5(@t}q`S ze7ElfpDmqB9AsJZbUjeuiYBCGeZwRvf_%8Uw0@Y=<F~MJUP94OcgIPxkg&3`U%>8l z`pyaRiRrT}h%o`8DojO`g%rq@p}Vyk*unwqYyJ0$SVJS{jYiVIJhQGr7LJz4%$S&b zULL{$)A@icX4~kI*A~&NkRun)gh=I)UB>>PpCWC_U;4bDwpgEH6&a;+uN-|Q2Q`wi z*-rPS!WYbpFUvGlac-}TMvh}{;pGvjWN}%QN%-5d?<KTB)~enC1y`}GYp3m)D`&F2 z1<l{EPQxGgS`k`@Ie;o}J_Ri;UjKSj3Ib+nPaLh)hC7c){>YJRaHyM0uA*<fUU+9R zfMW<V37k;t^KomZJJ=>)WT$4JaHwlt6SwLXm)9Z9R#JhXVR(GD!>MmmVan)<_BFX- zkj*bFRZYk<{0trmvNGW~)~p&wv4$Sx!kj_E!#ivzq1{+xV6LIb)7K=!CeA9*cdZgd zOg~8GY6f^u7x<bu=kT!G_&VRPht4tx1P%{+H8cHKd9`c6Sv;<`wI>E*Cqr5L9_@dA z_-#+{V!!nxF@`F$FX8!tJ{n5bI)zWrS0dJ(`xO)tE{D?1xfZiyxm_36KQVkXRar*` z=O)n^NJwe~M0nNf866)JI-Cg1P+WwtnT~&u48b#GLaotvS>5@46-wq8-sTA#Wizd_ zQd&s$oU@ni?}}gUYBk$!z49RK;aLdI2a>+gC8gvf0zQ|wJBy~}fYJ?8Zn)H$m0bt! z$rhfz)jO!!YSBAoOMX0{`Hsb<L~(VkK`~1w!=_BaG8T90NtK$b1u1~#r@c!+xN`C$ z!?;Aj5;}Dq`Gb1NiKGv-oCYH7GrDxr*otkf@NyY!sPuTkbeNCS2eohlw><Sm{L+?p zAgB&k-J@}g<y&%wgb+jDq&C-7>~0J_x0->3LxS`%zZLmB_F#D<S9my%4h7)RTPOF4 zK+)}Xl8vlgepL-#OA|^cych7qR|Yfe3jj??bv6X(wphnRhLRoqoJF~(ISeTKNqoHR zI8$(%v>67tXckr4!SEF(G6kupwN<WUvvi`QOY-H@7LUkt9DBUL<yg0)rMF%hmIG^? zyv0ltV4WLcaGAlEH8f92Wc659qKo72<~!2x3gg#~XE5GW5qBHc?kJ81&PnaMmKDH( zR;2#IM$gr|6a(|fwI2E0kF2qI>P4}KoqE7-V(4{`)GL`B{6OsBKH&gspjxO7>7&Fq z(ywUaSVi)whSxn1%cFF%Ikb`lpG$9lP*TMtzk2D&U9RfN+C8#AHSgpCv=)jhju1he z&ZR9!&rkz)Ke6{KGh`CyH_6DovErA+5IUkH$V7YH-@$-|7@SYq>LquQA%K!C73fB5 z#S<^dmfz2_ETbT9bk)P$_U;I1X3%yV@uV(+>*SONwLWmpS~KAWY<fANtIz5~5*%AC z*}Ve1^F7D#LP}xeYP%s|tb|M)b0Er5y16u<`)wn~gWP6UjY<=Pul&yjs+XcFftoR( zQ)_B$fh)$Ax6a4qERFilc8X+P;<CL_r`weC{1jGT<u}=N<2_*DJC&FkHGxZr*)UCU zA)?m7lFA?^WlsBs<-C)((W=`S6u@^+TMv`Io;{hWBWrL3Mof7?Rcbinf{IFH)$Xn? z-@8&8o@{GH^QnP>@pLtSLYk)KE1{I9cjg>-<r0SCwVPh#bM=9D&y;rEyFluag#=%{ za(2mhP|QgVJW2SDoG<(Rfy&ilmb(x&oN&y}Vvs10?I3CrGfM>&ikA-pvx6)%(Nv%7 z$Gh;VqWTBJnQ;{e#+zo+yf?UGJ8V^3)@dlt7j#U<j!rc72YtE~mN%gKr}ON<SpQiy z*Og_N4kL!;h4-dQ`0b(gV$5Ehq#lxCDjwK&3NMFK1n~GA!E0DthUgx@#H(Gt3$2{! zSaDmaNzPMX&C&$kG7O?X3q&!C86jn((2Rwiv*4}*H&7j<u6CNT*W<+`{a53sm8K+= zX{$TQERaCm8Gfjy#FwjbQ;tb!bV>2*U@BKEYqYYaDA@;}g<7)6x`N-?er**RL!IA? zST3<ObaTic0381>xL-~2=E5`A5`LNB(;RFD6MI$FC=YkDcN0y*(EQ0+x<s+R_y)QX zm|~sH+v516pWzqD7VzM*@f5$(#0egx3w5!H3vZ&6DljE^!;6zrQb$)4zCnaS!9?k% zHdR&p!&vp_s~W?~u3pCh%o9#lt!EZVo|xUdjMCefirYJm7)xd)juuh!<{#aQO&}(~ z(`)hXD_ms|Ii&~8+(v<FmoQd_FzVbk5`*PPUUIs_M{+5?`k7IKm6RN`C~k?AU!%d| zo|V3die^*lV2n{ywGr}OymP*vqlSIHo-=TUH#ATC_6)YZT30(*8O>oz-dy9MqIY@$ zJ;ii7y;aIf;v<y3&EIRq1z9t5n3K`IWl`<-dRl0?9Hpc;+6|L(!ZvwGSRR;KT;Qvf zRVG)M<u>fAMDmsXc1il=z@r@98Sp(=(Ig+xts)zr$(#Jh^d6P9io<vP0lZN>mQR>T z{!-#rkx{ka9<15qb21=^IZ9VHKE3N%&^57U!mPJG0X;_EruiynMSeT3gg_dW!>5<# zq?-*DY%lo?z{^Um3GU5576n2YY4(lyhxy$h5B&tQ386KG7*|Py6rVi3KBaP~_VDax zY8y@VT99?N@#mPAY^+&=Rb?Ps+8Z<6sgPONP^^?oNJXXuVk%EIuL4?CeeN}TcHLNj zuhk4?4)wW*^;j;kONgo-f{8{U&6B-&p1n<64A~4J&2D*-F(O~Tu|I{o$eI1QZ?KxG z_hn;Z<5cMKvFxERp@~L-vT|ep?6GnCi`6Xdm#8+gv8dD*S>08rILTJFLQ^I@<Z;xc zFR^oZ{R4SfZ!D*56*<0Pu9Go8omJbs#N)4Jp57g@LC**7k>8~DY?n1X4iYWpQldHZ zSB`xhd(kQfa|pQETAyQo;2!^7#dAGU<W{-ceIYHs$73amLWo9rmiInpS2(pP*_$j% z4v|~4i-FCkkX?1>m#%U<huaU%pSdtL96zT{X6vhseKYbBE#lfdht#}wOsiP-ebZ;u zoO+t!)d`Z<)CIpf^y|pOi#lsZ_4%ZaPZoew6e}yUuK2Z!zsy`VTsA|@VqfW-QFC3V zTj2Qw%f|f<lE40aYyazt`_FsjGKrRneMIpDL(Db(N2utowdVLtBJMR0-qJC9p$2V% z*ZW?VospamMaDcz#nSPPslP89f$>C{1A&iRuO|wqHVhl=ETzHW19U@K6B3Jy{ad@5 z`SRbxE_<qAW<_&P!-zON#Ej@Ru84?qJB~hG?kg%^VjA3N-*o!O0LNMEbAuuE5fu2f z@CpgF+TfVRNS1<B6N2Wv^4}Z+=q^9!Q`q0rAHiacNJ|8k(5Mn0H2|Ix<*!#Yc`u7y zXTGo;=A>)b6P)TWSySC%QBI7qF189cN-@rj$UvVH^P+ngPs`PGD@Ew^utoS}c=E(e zMEA$wGE*|R4Lih!x?Qgg5kW*nBSHV)D^wA`*FPS`A%B07`~NOfMP`wAhx`*oK`9O~ zMeJ++YxdtZi6FDcn;h=g$B3`=*X+OcIv|_K5%N0|4Ux+HYxAFha%2%X(0V6+Le%qr zE&e0kiVPwrQ18H()c+UwM;;X!MvkD~!5s+L>VE`Mkrm{a=be&IgRJ~B^ocAW=l|}6 z0Yup0kI!+J21G`Xb0~L6I1>``4-s+ugiIi(EbfRO%>Rw}BXfa_A;%}~Ftf-19s46p zfy^OK(cW=ood2EsbEX#ALmvCQ^Ax#}y?+gXA{)p9katEf&wm*IHV%pGAfJTXIUl8w zoIlS+kRjy$=pA$<j|BbEEk$;aZ@}-IIaMU*-*3l}8RSdQ9rI8JiMhKVX+6b2gl<q! Q?jxQ>h+eOZ?%&`24bo5WhyVZp diff --git a/venv/share/python-wheels/appdirs-1.4.4-py2.py3-none-any.whl b/venv/share/python-wheels/appdirs-1.4.4-py2.py3-none-any.whl deleted file mode 100644 index fab3a7b2758c2c31aa62a2454244e57f7fd43e43..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14131 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 XMnxHLh<{y!{9BO!>Tejfe;xfVe6*92 diff --git a/venv/share/python-wheels/certifi-2020.4.5.1-py2.py3-none-any.whl b/venv/share/python-wheels/certifi-2020.4.5.1-py2.py3-none-any.whl deleted file mode 100644 index c2220c20167c43c6e9d3a1b2f27ecaa53d1d13d1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 161630 zcma&MLzpgH%q{qq>y&NVwr$(CZQHhuQ?_l}K4shL@Ajnozdg7;$RvYgC(qhhdDh+v z(jcHH0000IkO|hMK)m1|jE)EZu;Bp!6#sdRO`TjU%`9n|7?>F7Sm;>k80kzbon2@x z?ab`y1yxlf<du}^Ts&M%Gr8l5C7s5;zfeqfF`3uH(ZZjH{TlIYoU(g(vm8TAR2!+f z@Fu3JNy;tG33AB=6DS2{g)V81AUPxu2x@Y6!AxfTK+luU&^1lwa*h%Z6-WL~dwd<@ zPw?yB*yO9{`__{A``t>hF0|ZSD4g3UdG##CW>r&do!ho9m%dmzG5LO8ZyedSw&(N6 zplv){+&KMxqVjouN7wf+CF|&5(Y41eCJVJ|T9Vqb<DY~-Fz^||^)8KGb;Iap)n#+u z1z)4oJs-G?J%^ZSnPdxAL*5F_ee`uLCToFHZGCd960U30v35!CVdZJp#N0E7Z-^;m z+6w-;V0ysGHF;Uh;4&d^NPcB2tBaYX!)jyZi}>N|S{6S25`3Ba-Bhi$6n|drn9nd& z(Ws$(rl9xERkt&D&2`y99W|f&i{HJ4N4slMUi;W70nTg!-FEM#Jw=RFMOHIIXER=< z#<p{AH@_jXwHvkAWj2l{qxW3f)GeHc--wMH^H^HJ<D(=--GC?>e#Q2(8=Eyl7dsoj z=61!vR?M>>QMTMtjr9E<o{*bqX4~~NMc8#Wy1#9-Y?q~h<ry_omM>P(#D@m9;Zzjt zQP4DeD%eI%wAe6fdDK;>!)_wI7Vo+6JnKf5J%XUK*lE){BgyoVu11^|dh<<~RHU6Q zn^iL!N|%kb7n%KfSW4K%dS2NxLYtOwuu4};<&;*Av0+bRlfM)DXM3dlY7ted@jkoj zy{%mNpXPZh>($C-Wty+&R_ytuk)o*lHt$B(PFI{oG_jBUc#J|K^03q@;ilZpLJb`E zj#jC+r#Sw4_{>QtT@883Rvaj&YwG!O<n9yO)7xNJtYwad&loa2Yn&Eo2MVII{e_L* z2jSkKdH0Ss({G}bk>^DS5?At8Hra$S`;%n5J7I<kFZ;g$!C`V*Z_SK6nIv~S+W1cH zJ*@m2M-Cgq*w^muw=7b63OwDYRZDpcIlU&w-z^KFMpcZajmxW8)=<L4<Bq(5WO`m} zLaevP1vC)t%4#l0(*f`k?44s(6LDa`?QV}U`7j6fD_h;t=KSzTvS1WS4Yfqv*4jo- z!-2us#1Tpgvi%3%FEZDCFgkqh!+PFZMsS>Pr%TnAD?Hyx_r}<)>Eozf?DI##ZuTtS zZ-Jc9ZS?%=SAe!;_Gojp6)JDv>2uOx3GHrX!_?$O!2^A-Liw-_>F&AYQ%{BVc9)H< ze&HKgHs(vRh<JzAPSh1v4g{V{sRbyxHvo3Y*9MiORAyomOWqtguexF5VufWmBoLP> zduH8SeX1^rEmqebp$^vYQpQ)o{5|thho&m{XOz{Nd6KeC4jXsLJ3g$kq2_&=As$SS zA7i^Lso-ghJvxxq$LDvT{t6sH=2-sSzV~Y;J*w@Ei`x-IgBWThC7&&^ncH<FflnZg zkZ_@Lh;svbG71AwVc^OJPkk!tjEx6}6jJQNkE05|nrUY%s~oe5Z9f%d>S;T56*hfw zF1YQvy`E%JlD2F~60~1*36Tm<(9p~Vc!+U2XtghTj^lF(^I5cTk}N6R)sor>Q;e2n zrclaliw>lZ(l5e^yHE)x`Vn=8)pSy*)jf-UXaw#W7*k~3@LYFT={<wKb<!?b35X0R z0ku{cF6}ICbHixWeCUvHiAx>Z4pZzR<4v-NURG|uEx>I{H#vo7mSDzmmD~yT=v~>l z2Wm?SgYZQ3WiYVhz`~;-clLS1o;<#zZfoJ}VmB+c-e|CIA<}iDWS^5^@TC!1$NHF- zwV@0p1sjsDrp%=gt)uW`zsRpx#tZDTaUtYAnQjR<jQxD)Hw_Q)Ql1|_^xBD5yBT+( z9Acg<E-d6zsSjfIH)P2H!r_YM=$)$NqEM=ub(;qlhG-T-n1wEckZc6Vvr&??m&tXA z&Mc}-)aV#F?ylQps&hyA#xFv`FU}Jd@TgpLgYn20?R6>Y2vItmaY9niqGgrk0$1Fx zb<o?SFDZVKQ4P#qIe{VxabGA0YBF3Fbikq#IngG-M!^*Wb3K56NSrmXZ)iSIZ=9^G zL|;GSW0&sfB0m5=a)uBbhKlcp!@g7NY5ol_-nrJNT!mU*eO}RW>uY0dRMjtZD5AGE zU>hlR8TkKHDQJU{OKapJba^P=-uqd;6?Ot%oROVg6$j4)eCBi4E1<QgfV!8d^Qq{( zF7=v&j0)LR6R~=hccJmENsNv)%7N+AM{Cvwlk8-lzk=T@=(&|q4q<y)1VX#TOr(Ep zNIE8^{=O{Mev&N&lH0nLN_E-mVusJDYNFGrr`rj0J*l!Or$2^w%u}`JQL(q0sV?i0 zqSC0=QeH5<7@kRH69Bw1A%t4kOMutaZ!C-Q{qIYO#^n>6TWO2hgnAw0$5Ez;6=)?P z7)Z*xHL$tVE6WC~$T#Q$1!GI4@fmhw37^lmKwVfAclt>WmQf5tO|`2iJM^Wo*kzy% zhEqY~ZfI}NG5bTU5vdeIDks=WJVAime@~gV1v7FxsRUoL+siG4L&cMOU8wW9o>CqB z^fK0GQIUa5Ps4{%>u$)*kv-ywqiX?8WZnZ$8}j~=cfXgn@GmMB2gi+_Nj<dNy$n1j zTBmlYUvDMWm)4ZU*1BV<G(3<i_$_0E?Oq%dPj(G$56fZ0^0d~=^fVi83GkI}xq9lz zeW&=Mh5Gxr+ViA&{Y$kL^+^#M-_|}yo2mj3{TSF0qb&<NRq?v1=n6Nr-mbS5vbD8q z|BxwDN%Ac-$mu%RWTnkZM7U4=K7zf1j=O*VIbZEI2iw$2TVt=dd(oad!&X%iz4zbR zW=jr~C|++yO_2%ItF6^arRYu*@%4k~5+)-s5T>b5;e5c`TDtsmm0$N_7#xR}!05N3 zJ*S`4ESWd3l+;8hPY`i<o0VKUOCGHYO)4=NO_0*VY6f4ZQ?}e45E1kjMER%)%-@!3 zAW|2IzFZ^|DYOgX9H*?S=73Xs2Ax{@JiTp4%MOuPF7aES!z4srLe<6KI7$$^Z>Ihg z(FIve>lN1lz2zRU5E3LSTmf*;_k%7s*{WJ2wrYxE8$GiQu&S68+U+X?Lj3xYRr-K3 z0R@!~=$KlJF1XSLs<GFvB>xr&cx>Xys*~Y_)-a9})$mXZk}}KB;V*iIZy6A`GhP`T z(M7nKtR5cB{J1;1xN`qu9Zjyl23B(A&b(^H=6a;fjSGJ{Gqe0L0#Q^$a&$~i)AOtv z>UB&}gRHZw0B!ZIGW6D^x1i^#mITk**YQg6_*~^MR26DTY<p_0k*FSE%?)@*GAd-W z>3`G~du(2)v7;)tGnU)U(K5VlV_bk{;y9vUHAW9GJqntttw~(8Eb``(`dq{AQE!{u zYdAXPFJU!rJUPAX2IhMZ$<q?^_sMlR*)=;$!Wjy@fu7x0rxlu+Ltc?~`u8E!BXamd zc{lHVPF38TT9*Y*G<P|ZJdezPw#bT%)EGPyjH!$H-&IBVmDEoX3=tebEoNDA^(ui8 zvjfv5*sqzUGE1+1sBqp=U6hFPB7z^hiVvgSY*!gqG<Pr>Bqxmr-;n0$)+sBvIy6by zHDlNDg7?}M;g@@tWUZ!zV=``q;Yv(ZtV2v%MjIArSypD4>CZC^&06O0F;CuGBnXwo zg*~my{N`n5+4pGPVHqTi-(1+KZp4)x<m=X{dw%3+ReF!(L6OMXV4BqKjuQYxP9v~4 zrSc}tWR{j3fdGssk~L9Nu{sm$p3ZgIz>NJqu*WVk!JW>P4tGN;0;-K}Ad<`i_A0o8 zXl4}Rom}^S>)<V2%mLw7Sbw)QQ4GUs*^>_39io1JUiX5<)Xbx$5N_hY?yDP<v}7h5 z@taJS@oco?MX*=?4DbSJC|*e6!9+u!Yh9b*bveqEv5at=aRZGfrtER*CYtqPBY@?3 zgrCB>t__{g8%q7%Lepl|&+cSpTR>||Yp}Xh!D{8Dq~ZCg;7y=U)ppLuFe&RT*<x;d z!G~Rh#!}g5>xvf|T}$N2oeL2R^pjVc(SF<3=1?xz5s%9#*GM_JtXtLzFr;GM=Q%1^ zxnCEadELO}L-f$HIBP$*DnI&?^l?Q~--V^8QdOTib6d85mSeJF{@YUp`@I^IUb@Xb z@6s&6mNnVbMlxrCY=&~{a@UD}?76-GB&O+A^(1dl%Wy~xsywckVZdZF0bNHJ!7Zpp z4pGuLn_B`)QkvY`#^72*8FG5d3nWL*$HU0u@2-N;1De2A_FCuFZz}i?bHY-#sgX~} z7%MilyZvr7b}`5#DMWHITPi~?sqlVnZckZ2r0Xo6tka1YPi7Nb$Ns=EBpkf2-sz;> z@Z5^W+Uq$j1c0(yG6FuYG5)0n9gQ2#iyY*j!Kf}Dd>MSVYWgJaQmK;l6jaoB2&*WO zw`((sk0P8Brz?@tlQ#A=rXzN1iZqBGY%%)e^b~a2Z6WAEW!y2n1l<?@3%na+YSB<x zQ*d2?{S2E@kV15*M|GW@0SC?G*>aA`Vu#~qzA)A9Du0OXCFMPiDSPAEly;_cwO#e< zE$wc|S6KIMRC*ITfeCF)F7t%vL{J{%Vt6EXHR93kX#dEQJ2T_*2Y>o;GN8vuuH5<1 zBVG-DL-$>3_8+P&5O_<)v^SzD14o`5&a$STr8>3KSAp=go{Zj^8Te<yFLV;pVysg; z&&!QBIm@-yl#(tr%;dnauAmc~Q6!V+RAP4f_=M(&k*w9YW;^Zh(b9Qn0uAS6iejo+ zRvw#)y$qHUDbMfYr@zW;a14SA-{cT;>iFHn&q`8JYqNb&<MIqz*0~`38Hg=1M%p9R zN1t_Q4|t}r1Pkkf>bg9?oyi|c<-mCI;gy58XRWaG8{{D+ENB-4OR0#-&{VhHklqyO z(<25<Ff%TO7_cpvfD5IwtZL5hfx<M^!%=<^5jSAq2l4)bG#2UBcZ(&*8>KgxCTKj) zacChN(|=_|clLC9K~7&vvyF|WTry@&cQSry0=dhi69+Ob;m_?JcPX=M7jXEt$-!Rj z%xiPsQi>bcK|2wS){XkQR{br%u4%J1Ljxb;lbS_;i+v6O913KXHn#P;btT<rFQDcA zKZ1J0AO=hg@BU#|>d8yTUpHTC`8pkzFkO0Lgc+GKJ*fpD0!3POhI(`?4|^*Lko2Hy z>D)X1FB@x8a0+3NqWW@mX6m=SJ(=B^6@DY~l<?0A8{}sC78clEc+U!n-P4X`TkPVY ziZLlh_Ts!rHZ$ViT1xzhtHB3lkwY(s&kYSr(M?Tj`4s60fe9pT#N?%tEMCQ4Aqh7i z>OL`-6?i(?x*TQ&3{krxjeSfqwMG1s<aJpebm{yNVzxKIU#?+9{vs+W;daN0xhmI& zzeU|u&BUaDW{4ymnX#!JW5DBe!lf+LC<Ga~6{J)6kaiVbhEk?^`nHW!VG;c2n-%fA zhnDE%onkzBrOm=P=VkGXcjg_V<cLjj=gzn%`Pzkxt^6=7);E>*s_-7afBdSTLfS{9 zT42r;hT|D?J8tw0L?;=`9?Anr#UJlw>iW}$g-}~Vm-&ePv!@f*gRty3L<)mw%QYY7 z7_<$RG*mghgmD|Usd_vELi)6Dn>-ALPMK@wa<`Bwll*m^COS(vr74@+ITs>kbb5c| z9`~fm3*Xz=+Lf&do20jx5(+<6d(#4-fki=ntZQQKCa-+HWo?C^wCY_kGmH+p<gJ#s zk26G02XAu<*j}paK?gCFm9CnNDSrlrKoN+QxxVObNBGKfsTw|?*8_dNuQ7W6*MqUE zA%35?Q~jTR>3u)P_WtiX;r^d@#UJ_#|3h54lzCnb0tNttK>vS;D>9P8qH@Zj|4Ura zRhGBkWI*XVRpxQDDvfdFwe89rMzJQ0!%-e(Bnk6?azx2)^!w~VKiiZQ5^CMMy$v3Q ztt;kj1-iNL_VDp|`#8Tpm|~x=2^@f%&p==57>L2U>1OO_^CDH{gzp2vu`$0Xu3$Kv z@Uqv1Ulq0%Yw{00)Oa3XVZ;#==>S=_WyO<)84z6Q17;-ZzZN$2-oh`2vT7DeE)>PO zg*#A+1rNur=yq?ZNr1;v&zCQQS0&(e3K$i#F4FWAp1vVZ996+x$J>DE<{cObTg?TD z84X`p9Y#D<*vZ9yxO>^&NbaFT@VOX6KHo3~e!v`>V0{tTGmB!)dCh&c#bHgWcs&hB z&!e+mLWXkoaU=Fvave5UcujfU*<lH$S`Y{g(-uv>DRnLPPc{$@e_Ssvu`Fwcqs~V0 z&*VaYj>Xqm>wp#$p6G2z8TXGT(z0uDr#G8)()GUu*6PtJ0E4;J?%{oJ6}t6C)`b?< zt#123FemZEceqFE!r$gN|HgNY`=Ev^)w!Tm#u51wnlwjrOgXI)d8!Gc9mwAl3!bAu zv&NkuZSW4~7r_%t{L`e+O(RH!a7l#B6DxQm*(xde0}4HStRzgfDnwkFCJ@9<HGtR_ zv#LW%&C?h<9<n=9kHSShOPa()k+Dd$VIm{gpcwk!h%Hy7b55j3{d>nc_l%>e2=&H{ zSD@2ClU-uxkMxi}Zd5+JBsC;uMmaVG7SA+*hS?`&SV3ZJgeyF`dKD>85lI7Oadl$X z^=}FFg7J$)Yn*3L4k^<*bPPk8>KnZil{7w(Qc;Oenlv%*LL?+d0wMj88d??h*9KJl ztef(^D?OzNrb7zYA16=TAMihMEKS}IA^snRJD~so(*Ki4C@ZQWC?cpLn5(vBcgTj| zd#WxI2rL;8G3k}ehA>|s=@t!sNg|fh9M32lOKV4=L`v!11ONR3=Xwv;C0ckfL3TQw z)A5KGJT8hbfq&NBNEVFfKZYj~i7DYCNQ<(in;Sd(#@R;@X{nnwXv>sgBV-7xBGem6 zIylHxk)vCwlS#V0RVQWbcy#cBWoMOaeRSonZKRaw04@rdI=9%|R6^rU@t|N}S9&^G zW}!q2{E^UjnFZ4U!&k_N0p%ft+Ur*SCr#)aM(XRirpN6*O<KFLA<2RVvnxL)8Ij)@ z*_^)^W@2iIBN$$7l{AY0*wce6Vm>ghvL<&pH>ea!ls6vKOV@HmgzCJQi;x$khAB8b zTpm8&pRZn<w!55~gr0vNs-=dAH3O+@Q#fq^j6}ffQA@0oQg@maZ~sO{AlVph&9!!3 zBBovrv-Dn|HCiUcBWHKO6%|=r;bV^!j_g^7x+AsZZh&!w@rQ$R{#gJecb);wOmj?# zfE0g5iCQ0L9PzUh*%Y(NSihCF7^vue&7y+m*OKAiX<)>w@bSCD@VmkAh{5o@L=Qe5 zrQgK5?H26T<GBmWPG*ensNZ{he1j%Azc<*iU;qjnddn(yf=W^#l$KUagC%A?v_~Tw z&U%D!bWMmF3na0wl{;kZi=nM9MT+1pF`ZKKXT577%OF&)mW@}=WTmm{Is-6Ie7S-K zK2LZTAoPwwoFza%2$|_Yi$j~OVgva{bxGm=NO&a<b#^`XUQhvD>>tg>=lH4Sm<gM8 zj^4ssbQ55FWWvm8%<%7Ilu&^dZUJz$CCPw|TBQ}+6w_!xFMi;UUFgTcupW<Tv}<b~ zt%AS;>r%;m18RKWPAG^7bL508M{f^bpeOUSyrHr6WJKU5y8&BWDqJK}eT8gtQr_gs z3Mzs*)O(z`|1R#Gs~}69eAZ)e^9$XI8dR<o>+L8ttIdUK1az6EgdewGX+)n#=rN*k zydAnv)<P)*r^V!xp3bJ1%p`5L$4{Rv)60TSYc@WHw>uk`{7Fi@{YAp}cOAYl`)n<* ztV4uKAG*6Js%C`h)0l+r7%l=7qJi}-EPIICxD|29Fcn=qY_(!HtG0Jvv%F>g62GSP zfyAh2+2<>cA2H~2n0Yh4?{?1jXoTray$xC<L++39NFqK1C+A(^L?~3=v+7~}qR?pB z1$4SpgqMh7_Gs!^aFff%1#WJxKATtMQqmi!OYEPQ*vJe!d3$WHIEQvYN+Z>mY424M zk#dM!yn&cE+bXZV-xmkcgjeh3&T~C0Qyog_D({uvf-k~)U-Fjm9k4bo|7)n+kPkM) z0j0xG4&7=*$4*Wek=>xS#Mn%tG?j40_0bz=TuZpQ6nYJ0VPlYE+Ew3AHHAd0-@g`6 zG$NlWsO#hQkC<52piz$wE-yDpUq?84ZNwhy$+dxY;(KtHoyE5T(g&11l*U*1|8o)v zPZx+^0097$AOHaI|7j8_i3-ariG<E`rWXmIgdKGIL(i)yHi9D8Q&*u8)JWoDX-e4$ z2<Z5I=lr=km&~~moBPboMjsN9{*Z&TJr{vo+ska2-52^Q4Lfbfud<S*L9~OE>cwg4 zr4934Ixr1)&!QCZ!sdi;F%)@9^Ox4gwEa!A%UZ=n^+P1DJTcUU9qdlwqC%^7xLc!O z=hpsn`vWO3B0%D!?D=x~@8jPk<%)Vua>%3=t)BC_Ry~`YCG_3ux|lC_;n`pNGbFe$ z?mL(i#5xN920IEr8z=~DIRS8AuM%;4{4QgI=dJb~Me|6sYf@?6$cj)O?m7&~F!``h zo+Hj-T8@6)GmeI4+Aeq2$aKQE_H#B~-|f-WS=@gYP4r7{w@cySb6=u>Wj35&XOnZ! z*-5ywj!B8606mEAR6Fp*cjknsss|@tR+}7IQn`ZgQWOq9zt?zZCkVmd?0J_HG;A^u zk5GTyyBQ7EWewj8WmlHdAu|m=7=y@XwT9y-lR8%(69yR2v$oDHzm&o0515pMH!b<} zvUA?^(KynhQumxI2zXoSIy6bJ{lDvZ5l)IPTU^{QD`R|&?l6Gg4PIAXPE=>dk9VxK zz5>pLsrxh7nGa?txRpW+qSiewcv;u#gakKIh_rFCn6J&TGCZST!(Bg+{|S};@+A%Z z{~%)bpAr3^prS4zDk=j#Cm}nt04q&PH9I}mq{OhyyzeAGBTXwsGeO^|Bq23HLl;R8 zQK>l3Fwe}kz`S?_H91GW@JzD`OF=6&Ga=KcL_tX<dkiHh)22jG!Lm3rH7C6yJ6#nL zi9syV{=adm?%2)Ce{}laGaLXw^?y2^i@k%sjj5Zd&HvgCrR8X;CS<0Lfd99MH(e^t zg8xMl_|K64pNRDO`j&Q<F8ca(4xV5GjBo)AkbwSN^@Q0lgW_U)Lkos$1%{Nf*PgB+ za-~NFoX2|!8@tLh>!CVpih%K|hOlf%Jq;>#GQJ4;P3W)x*<ymbhxOF|GClr(GTIti z+Wp@dW#bf~f*D}K_PnF!$)PWR!1=Dgy8=_NbPcp5iMoD_)W<%MvTo<n=R3{SBD${< z!E&=X>k<-D&451^Q`kpjOG96gH-t#17`{$Exar5NGQ|mHD-!wSmN2NTebRlPdoSq< zzm1e8xAsMu4=a2M;AhE(uT~T%EfF8NvgT?Q_2aTZyt$KU+r4BV;q-%kt8@H<;Qwb8 zqS>s?nySEnAyrTS(*LV(#)kjvF_g~1)ONZ@vnhMLm;7V4+`*+U2X3cngoolE4+FF$ zL12cy9RoZt?DXBaebMo8qwY(s?&o&g4HS1b6}b}R1N+x+CiF+XeoE_gve|3s+K+TC zo}q$n^wrOZ2TvzG&*$-%?}6{z9NU{y>(8Y%?Gt~W&S$+$(aqkqAJkyUrtdqx|IG*g z>OgWCqyVd&F({ZZh3Fxu@BoS=6N5|v1Kef>@VzM2jpiax_CGkXAX4s}b;L6`LN|sc z;so5_8zd8SC2pc!!{s<hcf!WvO5Dk-GlQP#JW)R!kmc}&I6`-q_UL=vsM`z=@gi=P zb+D(nKW;3I()_gn)#*@oxJb7aE@LA2hlQZ;hY=Ir1faVIcXR{phV3AaF%`IRH$-OX z2A2_xt-?vJ+pg^f;Y(c!+lfzc9`dAxZip2lZip6{H{%w#2q3xwv>@N7ANb^xQ7@tB zu*!)jd8{MulqFPA2-!SyY8In$P-AA3k;Z$!j!7$E#D(!eH@I=|`V-+2#;%J0T-=(` z?@JolF^v$VkDOB1>{m&$tEWt}W*XrCll<94;5{iU<?%<F?rvNWspN|K^Y}NL$-;5K zDTbe9!bc?aG=7VPSVy+vb8E6Njq;FPl4VN}$!3A2D}p#GNx6mo_Jb8TfQJ?kc%#>v z{zZ}f8pPuRf0lW1OHesvlPV@(@AN|<x5J;50rH$R0himRW(v&Hp;d=<Luqs`PUaY0 zLohWEUFKM^5ZCli54OhN&0XuA?`m?v==DosoEjD~HO%bmJ*q-73ZiqWwrilNbr>A4 zeHMQKvTLOS6~cd0z)U2CvyVGxkO8Yz8#t-FYWr8kyV6>rkEzv*;eoq0)jT}4OgRQy ziHe8G;ym*)a2HaB**j~3o$2lN%WzQqchJq!){&<7FPgb13egj?yy2F!YiT}G@Ki=k z=GR7#CA9ArKjE<D<clNm^+Q;Au{gRDDxQ7DlSr*c#rBGqck$`2Y1DG39vnpX#UMqR z<Wj<`*dM>3%`Vs3&uMzDE@)Ql^gKC1v5k8lyc3XeU7{nasCLoG<qQk*(_v3$#KZ3p zITttRO%Rj9lHP4?8a~xx!HCe~3OS?%WoKk-y_qj!;)y!#^EaPEv*-@qdsuX*REHU) zNCOruBdBvh+pG;QrY&qjopl*7`9_@!QjZc19dLOoni!%sTvtcm<&LDD>bcQfz_pTA z2uCuihHsxL=UcI388?o($)5|bu(;00;zfB38oHC`h8?<TS3_31uAT>NLT2J=!F}#D zjhE@*^bpaTbZ;sqis}OGizlkE#gw=~L`iyO@6$1}`OD#=j8R|Sm`lp)w?ogs6Qqe5 zjpTQQotP2@uL#sdS!R|K-nB~XpLGvmMGq8Fr%v8&Q@?<F(na}15^dDPNCYu!%Tmo3 z8;osT)_>~@wuGiO&pcDdX{!~UWIP-q`a?-@54oJj5F`97nyC-0tZV2Iu%cZ{V{e&A zbICqkq&OWs<(3a#7aaIWYC`je97mtsqx#85vZ~WN&~sL7vpQXB2*QK+Bgo;C{W^HU zi1GJGhoM{1Logh{J1<n?NTn+bWi2b%Oj4P45+3O8b)AY~niWy=dM%6PgRqOL90nWJ zcbq40soFLp4-VZQ@;TpizaJWlBC>CfLEztTEq(#m0G2+1lHV_*g1)gDf8T&T;<c_3 z`-A8b#Vj(3ATfo1>USdnE%<wi%W+a_5d{57@Cl?lhIe!^?i>Iz5A;%MtYHR<FH#@H zVY)zf!S;U;zy+b}gn+IJR4Ri2Gl1fvF3zoy1K3Bb7y$Yn7m6<R3%s|;K=kh$FA$Xf zE5u`=dN))iZp;mXQ@B`H%EkzwWf3>DIs%j6GAHp4)*4WDhnsm5;SgSz&{9No25gmi zM1N3459HGm=O085^lC*E?Ego<j38(Q=r@4gPe~Uf7rZV_3%cgUaKKml5fyK?S}Ail zl$EbA_7^Uf03g4o`j=lNsM9fDJd4T$kSZdA$`l}TbyjU!`bHPri<*}6S8v1dH<CyB z3)avNIOEFYxVE6FGHC1J9?|LfZAko0t78>N<*O2IyRPctx>rEo9tOfL22gN52vrdH zvp+D0;|)U(k+z*<^`WTE#*e!dYosrnx6t~oM=)~Y6a>yASN<s$MrrEOl3=M6IXFvq zgWEksi;ketNrGLyCE~H56`#}DJ9x-?m%PTPn5$D(c;sjmHuhjMvB7y3>Fv9#x7{81 z`f8$Wf*sNmZ@7}8WY4!L_*m<^_-^U6*b$!J*>(ZuYL<!;v;p@ia||DffhT<}rQ4*E z56OIdue^NXY~BVJb`0N(hJU_OJ^Xo2fDe1zJd7~c{^Qiq2X|N;8PVgz{^6z;4&jHg zk35h+-HhMjBVhVU3Ursldsy8bZtI4fFBZxVV&Q3vMIx)`b2lC4ajzSesSjt}i8(c+ zCafp%I1+0$%O~MCOXm~2#KRp$gPqgS)$goe>xWR>BiDBT$s@C`eJ5sEN)2vPJ3ici zRsateL}UB0h>lh&(|#7)5N5*?{Y>+A#655i7Y}DF&PRW%Fues*iYp&Wo?zR5G>6!( z3hDt8A2jAD+{Aep#{KwcroCKp`x{AhlIiISFIUTyZ#6Gru=J{0_m={?IyrC+bk1lk zf7B!epD9F@RR>)o%CW_V${%#>wxQvLggL)VJQM=l^(3yRB44k4TL{AAGR6??T%!Rp zJd7+l5zd;CrRHVgt+}}`Ovk?#OpQ-s=dx_O;-hk~M!k)kXY7$VglW9Q5!T#V{=E@# z`mpNK<|icQGP!IV`{8UycY5!YfeAf59p$1j8!3)3C#lO9E{yu=j7?(z(q?prh}fv> zLFZq2f57#Y?mwYVq7f1MD`q0{N7=p=$aezenC{526m?enC_*;e5Qc8}uowg}O53+U zAG2#e=|tVSiZH&d?DZ$@Hk0(ISSta>yyzBR)zyhJ_>Z(8nc9%HmkIhyFCxzSAYLhZ zW<rQCn<T2DCJ|l}qcycork+;sApYoWS)3#iX_Lp4Z&;gVAkdzM$hx4`?;zifCqq>c zeL7i15VQAC`K(%rXo|C_v2W-t_xEDTPE3J}7$AnPtDj#V#hV3wHGwa-f{iEJS5axM zJEoo1U&QY^ddMLLeZPzQeEkyfN76S8cgcVBzS%yW+g0!6kUxE%dHE83ZkE3@oPP2U z3K=ApIVKV*Mh;LT2pFUeDMc1gVip;Mk_utOeIyWy-4}uZ7eFmhW03l!2N0Ve-;p2= zU{Oc~SK5z*)ASQS1fUk(!G~>9qi!DU#F@At;L+}c0Uk!^hTJd`N-p9E+)$7T9%CU@ z;IZR-*4hHp07@VeFbZ=5#Xups;1=ern|TLXkptCrU`*`Lt^kc+^l=RV+zO8x(trvw zH<J4@lm#ug3J}yA3KXB5J|c*s?x3BDyQ0}}%M*M&XvL?7t-WC%F0z=<CYi$k8RgV( z#g#3@fBeIFG;t7HS|aMlH1E`#dDokHAfK`KHAHGX?1xJ~myO+4+LaH~6o0Gg)@`R7 zs({3R)K+|XL|nOZrO|$Es`VZpJWR`*Jc&^z>i9kd$@92FS~lxghAT2P6G=(ZfDG19 z&$+oYd|IRuGx@gn$cBzW<k6hoxyHj;P+L}=TSO6;r#H7mDb!1e9G&+GJYD)sxvb_I zbXEe3kN5Y0?(pf{V#OnH^Ax)KYFv!#==4k5D1kePdMT&Wk9#agqbtkUtD;3M%us!H z`=5UVe{-?l#>C&)?f1QY3w~!|ef**SbG7gCpB;k#NOb*BUMhJ%(B+<m6bJjth9`vO zX2xo<qL#;;q>0AXRP8;1C!Q5O5G^c-#!y*llIzf8!z#)RP@(h+i8LQQmI-j5X-NMl z$5|<ZM9||7Mwp9=Cy#S7<OLUX{vf77SuNnEE>A{p&Hp>-N3QS|DCWF6#_N<-L&+VT z?q0-u;h`$wk$xcoFOg0S*J;FKA8Y8DQdGTxm!Xytcvy!XMd-z~EumHy=ILv&Up_IN z&JMqq5pUqP9lcu6h>S;)rE$j=^=^GM4k6!rxnZTWT=@Blveb0+VB!_HX^+wH7D!)1 zgAPNkgb*y0I|+2iCzU}69py;6Jv1*;vS(Z)^*%J<a#==dcjJ(kgGY50To-u~?3&(N zLSAU+GM?9emu}`=c<#QA-H*%q6EeF<>c6|+{-jG|c8z@Pa&A(J<)uNF>*;Q}ZJLR; zfg-%Vd^M08(JUevrC*<(T=j=!e0yG$r)XMgE_UerIEy^k>X1?HZvY;|o10NBqZd8V z=v5cQCCUifWvfSiRYNH#PxJF#Lk@Mvv4dDNetWw2?sMphE@{hpH08Ks-7U0pGS696 z4nE#@X_d8b8;ti&V7-qJ5*?ddCf;^YVEIo**CMNr8dsN1sAUY2{4riiTKEA-sooYK zcdQn3UE2h$hM^^TTkxd$h>Q__kYfxc&GJlC{3;y5h2km=G{+<^(_UNqLSJI(Qhu?U zvHVLW$HHMu<lBB8`F^+N?knDV@f(fr7bMj2!yhQ&x0g}i%@OA}@k_D!n11co-S(rj zT|EBeJ)ZvHt5kB)-{(CZiU&pavy>|64*&NO9_sGfqr62D>33M_hdyVQ9P_>RWs$^n zVNHK`NI$v4J}K1(M)EN^es-TkhKU01H%gmi!Yabp{uEnS{S&CbL+A!cfFnXzsz%N$ z;+Ely_Qv0q2ce3zA$VfN10n>pK5B)R+)c1i35o$+;5S5T;!nTt9Rva2K9PY0%sXrw z!C~rg05vdGePfPAt{!9^9!O+uHxL45mL}{U0S$mRWRdIU{nl|oJuYnBE(lJ|EVltF zVh=dL=;>NJfU&ag2yHA?TV^i?;+_U1llsd@7wDlDSw#9cMgECfFig0AVMos>@61;{ z-z9LzN0eE5$cQE{lB(OkU{{@yOd~1nFDZ1s=gl7lS?nV2E$W9rg_rP2`nxL%`MLSZ zeT$RL{=_I{$80z<ZNI^zyk8J9puZcw-TVZIWv_;|AU5A;Fb0mm7W}?K2lp?|+%-`* zqsR}Jf1h*?F^fFPy4Y~Wr*YcB3-30np}725`u<xhX`dyvs}-3`;hT0%7|(PmA|kBt z0OkpX1o2{wpBJ<7xlco<=p<^Wck$R9=a;yH1<K!t%X0N)+K}J9okSpVflSWBhnWxp zTz{`WRO;aYySN$0MFHMmo^gx#vJFa}&zIv?E-5SJL=gs?ZCB;?l+65G>b(SX0bsrv z^j9Ules*u_Df<)@#bhRP&w~F__$^KEsWBF=wC2pm*cn*SoV+l_JFfLh2gO=dF6qx8 z;YS(V#FvUYZSYn2P!BsNX}z-f#cG)2VUnIc`<K2RCH;t++j(ZaOU7QVTe%#(fLrpu zXmn8^sy-ukqPh!aW|oZXukr$`ig6x&dQh$cjx><A5Z$mDCt)wFld;u18okk#sO{QC zz|PI3J9rD<Sd-=lJKwh={9*KTKOWV3m6u4kdHkg8uCJUc{BLQ$M)oCavlFc8X1`rJ zah{<aiC}xKVN55gH(s#HYG75*>hQul3@2?M^%|SDP4cnZl=GZu4+VIIKg03KU&DDx zShP>n44o0Z4?&y_B843i+OQc}Z+mCrxe5&_bm^NfC}#^-83zQ3+~5y7iR!tgcnwUK zL;LK91@h%$a&<V@6E+H|;d=B^th7!cUQV9qKB<Y7Jeqh5;R})e2tDIuw{Ry)B3Pp$ zzwa{^xBGajG)TVO#U7%QRXW@H6=ZXD>YF)7%ezJehP!$RpyAeQ`n|Bh_Wy%2JBv8W z+-9N@RjhO}W>4ORlwmR8q)m}nzS+w9`&h0)T4SE12SrQwFY1fzXq{?Y-YwpVA#zL* zm>c<E*FLeNlayxm1hd70sx0#WRV{S^GS?9uJR7pmPdXhX>;2J%1%8|&2M3F1nuMw^ zZ5UJO@OkoPE|8#coB)96`uWAtixdYBpI*G9h)wbIgk0y6&1AWqwKw%dR+LPgyv-_^ z%0pA`0j3QnA4tAP!F{I{O=bvb9%T}qZb;3hK$R%Ct^On1a&FTAvxoNUIyeBPs=f>l zNch4bn+fN<d%2$5TLF6eDgGdrySt6O`?J+|{mm<5j3KyBBJ>Sa3e*eqKDS>LVFsvH zq^24LDD62~oYb@cT>(SF0bCCIL@Wd192=$XF!V^dC2LQ30<RZMV7WnH%FkCa%g=Oi zZWO$5IiOZKfI@%4OA#G9+TIZWDdg%0_`QelkRPq^03gWS6M=d?4&Si_VViIQ?vRa< zBP-47cG+q?P`n!qn;wU#8d^z*gS)!ot*V>9Y<mh>Ga9YGsGs`6qxzzk>N8#eFv{J3 zaX$ZSLG+|))#tbyVAiP!<BEPW%Y30Aohpc~Kp0gDoKaqde}LJWk9g05f^<N-l&79+ zsJ`6{eDp`hYXnao)Ed+#ZE6hxx087kQ}OCZFrXe4D`>JjwxY$!y(9Yk#`NgZS|drT z{h}4r!+Ewt^j|SBA7%T800X*l{o6YU&<q?uVUXYU{CNP6ArLHFCjNjcaRj|LY@(Nn zsBa&e0xbcZq}S8VhCd;F=pIVz8<KdACH(lOTz4(9H)Is;k8a_!ntjV-gV+-7^LXk` zl-LsYjB0(YIj*;<8H&Y8a^t(y2?Skx#j<8+W6K)L=8Ad^{}sKt7zZz{ihs1v0zuCy z^t=?UCl{nYI%3wkqMFmzJ-u%1azIb)&gEo_zkiQQ(<~2zIoT>-8cv9ZlE~R`c)2NT zM{CoWPHro2HciNmmuRO)tDjKrJYjb=++IjTKBP(XIbbA7Gyz7mBWH&m0=<v;12cjc ztjTVZ>DziOTb)&x<(YY=JtK`MzMUt0l(@`!^Z2l#lA-t)<sl*TJA(p}%jOi6iux_J z&*-`=*1e<KHx@S_R8b}H#G802^N>f8i@U-2p*t|e%Gr~m6=8hhL5M(Zc(e|N1&x1j zKWfs8dN{C7=6l?OVSftZKkk_pdG~gQ`Dh+nr2$tvB^4B!3z^0UtdM|*EuH54>+~|s zP%)A7&th0oH=Rw`p?lTBh>2qOh+VmmDHosWwi46RB}jD6Qzx3I<sCd3Jg_+Nrworr zWp%{13#Vm9^O<2`(=8)eR>4!d_L^cqMVP=2jrt)Mvn?6_m`eP}kj!>xW|aL%sX(*0 z>qy<UBT~X4JE?n}?+rX`_!QT>KOl@odGO6*QB*YPA?1MwAwU_soI!MS-V!8U$WEkp zAWbmimRWK_g-ctiSD@`hWnZ~qrF5{*VS6Ykn~rQ)4BD$l^R8i&y|c5xU4M^AJ5;7S zZ3Fvjyu%RN{p1`9GbSjX%P@K55a;N>A0z1A-g51{fQ4WWFHh<3uXM!d*hBafgmOB| z8^IQ_jJ|&}ZCq*Eh^KS1vX2jzzQ3Txzx;5Yk+%MJugvv?eL^e+$c#qf`&HpG$kZ2r ztNumS-R_@A^-73(s0dCDz;T}l3x@8uSpbFrC@{%zgDX#x-T*`lghQmsYGMEq7=>7f z^$HdW1nk+~xf}uh5-TEfg&s^lVJBQlSr>|)C<#E5WM|>ttMqM%)L(pU!sK~AP)IgN zm6{kZIEV|o$xyWn<^X*}0|hSltK@EFzw;kkVZBPzOYeu}&rgFIm<jGhE9@}Z<yUpt zQ7#pl*zc7Tk?wri*H*=jHS&f7@CZbiXrfPNd#w!s<XQ3+pHVJ3^w|01WTf83QC4?$ zwH?}P@Fl^$!JVqYHB1(qAQd1Iug)77bo@lQVA{wef3BXfmk0LbmH(|&vE!}JL2^Az zZ3q}}rO`HI{vk1jAu+1|0uA2VK_8ki1f=(z#@x<-Mg`691q~=iO&ph&F{|-pzD`$% z!EGulQ_oX0QqG<&CKg)c?U3tNR{G09T#D|o)f2p)PBk`gOIzhw)zY30#H+Xck(W;o z^m=YtNvqyU7oZ0lw`e=JpxX-nAldJrb@}v3-$@*}{YmbrH@O6x6H#K5l#`;D*4C-$ zO$0&DyBzNmQ>-}0+qx139_8FV)Ia?|)Zx8#yINK&nOb}3KGMpho3q8^z=jHxr$gyK zu_bEYYc65=n}<wK5^%!JPQFiTi``I;cxeBs41j)*ky{H##Js<cGs;DaTDD#wK<qVo zbd7jMoNv-113o>cOpf7Ae;n!E;zJ&g2ZdwkJ^Nd`^yc7n;>WMBToy$;8bnwg(HlC? z7<j7iI9B0-T%@O@cQBNYgnX;L>|y4x%d@d<d^DDt1JwQra&dNBsHn8zuC|`>ep^nj zHcIWz>{;tmzXu-n!}CBLFJY`?`Z2aV1O<4GKN<a;2<hd^%F&BznY_#=q5auGwvZ0{ z@r40Zl4AR0u{zr8ZoK75bAK6kZ9(+&uqwn4Ig5mM9QivsOMP#1=rCto{V5va1)ez4 zHk|p?)A*(;`A1LYx#mX3dt8~NxM%xBI%!enAQO3(YcAnWtCW}I%d_Bp_Ml0zu^t!8 z4&rDDZf;yAo0)u!wlN8T6OQN9d{<*2uFg*R=uQuQoW@jyILB*?VhZv@t@k)9{S5JH zMVjk$@`n+EY`*+jV0be)dnkzkPeCja6Bi^}pVhwff}X+&Be<6tcElNxI};rWc@wH) z=_N^7c-482&q62>&(@|VcWwu8+>>m*$j19mzqcoGRf`knb^5nSMD+A^i?B{px}`P) z(kyHFPi+<rqQLXFo8r27{F{j9_@B=gmL3|2&CG-IKjyQZWxuwEpVpJ>_SMJsc@Ox8 z*ZS>~`cW@c<zE1IlE^-+DaqvR;v-w~Vg?z%cf$((&+T6b^T*_xZ+Y_vkYWLe91=sU z@6uA(64SdlbMpJFPuwwUG2AaWUgP^LpxFZIxH=e;?_3SIhB`Axi5};+2G+-{(Y2g5 zjPZ>#TZ%*d4X`&L1fU#EQs>F9FfD~!6uW**fM@>_D-a!#IvV1zwG@s4xkKYB*>YAR z#1T7cjSR8p5)47J;ND6q`5KEL!P<hu%0+;a!ag!7H_wN(m7})uK*LA223w9?o4>JT z+hF`U%tkAhB&oHpQImnMvw5GWhx*>D_PpC~@eJ(ufpeASeo!BrB5)LAP#>qpwB25{ z9f7p30z`@J2dk#LE-UWYP^YeC$ZM`Ex0(9<n@UvfWLrLg|7Y=!cB?*EP4COC&2?Qj zn5wMfDw;#0Qs~OXjCOCTVAeYwPE*47A0QiL)^0^3eni0g(C!b`k$PZvc=J8ArzQu@ zXwmNPf(D*T2s3JjR`14^f!pqd#G_844rjq@E~}Gmu+-(4hu8hfkGZPB!fo}h{oZsI z)=MjsItAy~!oKzcZ$ANt!&iB@)V_Whgv%v!3LN<fehB1;wHV6!j_e_O%^t3`*Z`z3 z?^dEn3l^c)BFLgw^$s7tj%3u^eWO9q*;+Yv&Uh?FhOI>mgt+C(r`q#osHqpt&}M8A z#vfF?oI}PD!Y`GE#7rq>oZPDSKl?ux-W}Lj)3|}}hS@t|!p2IGmCs&e4cfcjkyn`e z3V*z%xftdf{(^+oZzrFTc&8vBL8$ErcXZ$>O9mc}<0j-~NMuwx|9Jr(AdDYl+D;dj zU&qnW49rR>k#_1-Yx^<vT$j}m$w&EfJ^N%E&Gtf|qK3jdan!rOh#tpWbK-TR7XR)i z%tH@0ygxW2udRW7Z{B*^Y({ysl)S!qM3yM=ccY3H;T7AZF7;Ks3_be|sle(p7D15K zLo~ZDU3uN7WT@$%paC?6@%ih}!{Ou4zmV6t-I6S*vNW0^x{s?A{&H|E_%k=Qo4I0p zGb^G`dS@d80-t+o<e%ZCAdt6;qn1_&!~C^@Sh>UG-fK|{hy9hUHz_rruwc=&!*#`R z?GZZSyFs3P<q6;)w-x`?aS-1YDjAV|aTAp$V{(MuG6vAqNj<jfxmP>3uFDXn?k2$) zf!;VOf5{U;M?ClR^8#ikowywb@sz3y+ny;N@9mirEwLinugU>pcR7`V%EOdI*-<8{ zwkkADNp9zvz^6|DaM9ql(e`LA$+gu}v<ZI223v5Tz%}?a$ddr?`7pwy2qVlvi!Fu9 z{Ox87f&Q{{uRg)(0`X56=Ft7h?y1<G(KK3*aUEOWm@rASg{2;DHNur&T(eruy-)nd z9c^!qmunMdtHNUP;xp>yMrdExzbP)&W|izERe8{wWP0>fu4MOPq*My&g>mSc7vFfZ z9>3i#VKV|&Q1}MyKLboQffZxJRBhVM*~r@E3+Mj4i2R;D7yx|Ed;M2`U$mbf_b+MO zUee9q%6oVbz?kDjItfAPDoh7~PVtsNEC_ErIdz8eGIs~x&cHC7H+c!jn@prW_sIm* zFd!Gi=NhP<!$ge`A3#Cw#(?lP{=p3R3D8R3$8>6Gx9q2z-%9{6K*?6$uwmUQ7?lzz zc7NP3wtn1$zLx>tZ3#fIgz7b2_KQRAf^!uRqBM2>qI9~+-?0|qB2`(&^(cch?9<~q zd+SzBy(fc0+E{Y*O(!F#@*CnjA&+1ChQFii;}g6tk^Q~B;CDCf34K``_B36VF;xQl z?izm2pOlLG-8~QJCClcdD);BY%?jKcD$o0n0vAf{@=Xf7e0`obZ~XF}Tib)2E4n`O zjP4hJK~Hr$w#Nx86E5r)HH_K&NBte)?CLxnO4r3RQ`LT&%H-ft#;0!`<{Z7WLxZn_ z(O2+9w->QGo)^nta(a0%ZkHsC<F@g#&71$}Tcg%Zqp`{hSiGuyBHNMSoNruQa+7am z5Ewx<O{O|O%aZ^RGn~3Jv*p-X{l{(H%|c}bZCpV8DPio@0+><BrV>jIy1I!cOL#)~ z_ae_JWK&J6-9G4OZ7fd4=e89^+hX`PvX!5Ipm8P-DVx?h7{78RvplBf26P&BSKvV6 z_7!O724BWaPOe0)@`RHuNtiJtouCQ)ae2J@qn^o_D9EjYglIP&F>7j!LJ|+IL@&nW zC|vvqrftUD15HtU>dSF!wa(o(lO~1dQT%+Ta?N57RL)4xz2ss=jP*A}mF%;sb$)HM zZw7e@=^68Bb$@g1ap9zf+Y!3t@j2;ku851ueVm-aH#0A?p~Lxls@ot9!vPIbkA0X? z<jR^`-`Um%%m21VZluv>2CgHw)dVH|GdfeRP|n?^uG0F-(YV<=dd%T~O`M+EyfN=N z)IL9T`0u%9^N7&-dz1~&=cF2YBN5#_X;Oi7HcpMrpHhVWT7DH}V$FejJ#fDGRr<@t zd^>H^_?NZOfm?Il8$DrNTwS}tIo!^c8wI|9Mim{}H2X%A(RDl9n^(}}dC$mXhhiiZ zl1m&9=TUe6kR}g8PFpU?ZdeE_BzA2hBt*m6ML_?g-PNa$E)hb+f6ZJs`&#M-Ldi&B zua-r-je5-fSr=znzIbzQ_3*9zUhTn1D*M*ne?a&B38CL>`;~shqL4_^cucUU=PIru z7~1WS5;*d`+J@aL)S_A+5WraM6G1OHo_F755v$HZsJ;dyW$fo>$=3Z*g$W2V7{P|p z&$S5AXt4%f{oRwC2Iw_)WjgF!${1CV!!m>!s6}RhSD}m+uS9`wviX*q*5t7?j_NwP zh%#T<4wc(4@%mgE6DZxg->~)b9?|buQ)(=L9sExAr1?43?MZVzp<8<uIUSy6+4<|+ za}P7?1!p3Dxa$5QIM-8E6q5mvy2_aSGv<foO^XeG2we(Q&wn(}MpYwxu<Z4fGo{%+ zSWZfAF9<~&Kl{P3u4{eY{#Ch9`JIwd<4;m*ry{qji_e8!1<;r0$xeafXlqTvilVy> zuzC)!T;&+3g`L)*?^O33-_dV^EDjovN5;?6mvQSrVMV!c9)M@Nkw+m@y=EZF>+}Bm z>2{Dx?GFtzzI%Sp`A)j}D=}Uo1Na+jr;_VLJ;6fQ!()yGK^}%ZO7?x%JVPUSGjvKH z&5JlC(P!7=QC%kz>5;yF0y@YstiB+9isMbD1ShGYlx&%{?AR6(?B|1`B<)(KeuIBu zc9{(12lXMO$l~k00D-u%ESryJ+X4w6oUi~CRRPioAK=w<>i%Ae>@CUjE<s>3!-Gad zRVHt%e7r@X3Aa`gsFaI$WJ^do$59{r?G|E{9|gm^g%IO}ATu_|b7O;8xpkgeG2TfG zL}(!O7tJE&yA!_|JL*AbO<cG+(9$G|(EHct!SAeKDUVwBbfJ=kv5JHD4qSG*oEVR2 zI$20ZAKz|k@VfJ(%-9DF19tk_csI0D<YkuS{{lHc#=ndC;OnW*_z6#~N0W8VfXOFi zuDJ3MN>}7Sp?kU6;}82;_JY&J9&7JqQ{4Md%H*7n9gCyJWEoi}^M0T$Oq-q5F_Sz- zg_gnyd+~Y1f*-GE*f~#&m@Y?qGrM7GBoJ3HQh}6~G6h$H^ZTQ$`Krd~tUr~7@k-Gt zv9ddhjq^3BZ>i(7&+|*J4^h4`Lap0C_q^|>iCM7gbdepGNePV=dFo1^VftR+k4t^4 zRobRLcVc@BczeF{*`e=^_8)@S+KW29UZZd-ltU%Kt_%w>EqEo?09r?XHRN><tOo)6 zPaFSY-*^5Uq(eVodM2`}Th<fhrv1TSXLm2Y1h+MEjL%c`;V8k#Z|8Gc))zx^8ecIY zC<yL)U1s#Aw^A*!MI7gdN-l0aeN6$UfftjL3q)_Kz#W)n<L4I`AzFHxy6H8LsS7D% znb#5}I9ZOqf?$Z}4d$H?(WslD+A>QO$!GF#p|+-sQBq`xmJ_NMF(`yPXD;&{Vl{Wa zJ$7BjAI7J?WUj71*<m<64tpcjLLsdL`)(H--7K5lwP-1>!`XTX4iI(L7G9u!@w^(h zE>ev3r(i;F)ZJ%2WKD3T7_*S+xIIn{Dn4e7!#W=eao5U?Nym?bQ8X_Ny4=H}j~;ir z+N2ap_<|mK$0@nN_o?X-+LCX@MZPWf7LKCwHc7`>=&#!Lj_LJTK9&KbE9mu*OQz>) zF-c+fNrayox^Eic*7-B;AcMtbxRWn?2E1?Bt%JLo8a2t2YgCYq4s?4M$@6tao&w&W z(c;N)@}h5MU~X>$2_){kY?q9o^wBoUZj&7~7(FS{O;EWyKdA)+iN-c<+Uhu^>fNsc zxseNF%iL>g8ZQMhJ$?OA&m0bq2x25m^1QP_u63AQ_*WWD^bQgv{1CE*n;umrJzTaI zQna4*262-iM5jfJyN%L^h{X9;*bI{#+~(nWzMPwEdrkYHhQh;i$($$YA7|>)x%V0K z`Y8a9xjpLwJt&uL1LTve$>`=rJScB-t(2lAmTfWqcgYg^Z_%Y+_4=oT=?nUolnKMv ze6x^#Z(t`^)ygERnGM)TgswSXpoCui_%+QfqJBx4)?-|PHG7N-*DdKlN&~(FXbT*z zd2fKikj$G<MeDBiAl>2AYPGLv1pkCGp>IDP3)cugfv&zgU~VM3`T~G#(a7r11MUQd zUNg?)ckMd?J$h%mBkvCdu0*Blxh!h}I=%9x)zSaU6gDY*Q>N=*QKtRBLz&*&;J;EP z_n%Ux)mZ-!<v@5ZD|NEI6Xmxb%gR4y^ZgF6zY^uYoDKB-biSVrphUkrXNCVbXGK}h zS>Yj8=NDT#akELyXgp6Ac%hF;GL5kHAmY@ZB3HVS@+;nVZUaB+tyUuLEAHjEg9VXB zAZJldY;p-n?1^c~>*e&T<tw?>h1VaL;Z&kNvJ(-RMK2xhS3b!m^dU2A0#f(jEE$rd z4PYw>RU&z=Y2%B(-1>2pYvra#Kz{N>HJoAbNpqU&M{_#9p859lV$LKUC5L_dg4{5C zIIu%v>N)2e#wj1Pet6l3ai(0|iwa!a$aBpj<Vz|?R(8dG&9K6F4X>@;2Ga>@6Wr@9 z(!sO|-7fuRL1<yTj1+kyWO=&{boFp$wp4i@;#a)5I{LsGH_u;c6eWE*hR{*-8(R%t z4wDoouJxCr!ZXj#AI!MP8@tPz#v|Lx8ICv9xxgDay>tQ}Ja0>hn*ennB@6Xx1KLKu zjVoevR8(>^7?fg*>`*EA(js*dlyGK;1+1tC1Cc^YZZ0UC1+Gb9(7g3423@8q&G_?j zaI&%@9SR-_qu)M4^RdM?TB*?j?QmxYC<u~Nw<6yQbtWySZ*)-3vUmTrjFHG5^yjfN z303p-$~b7n714Xk3y=G@$F_CpZgbl_QkEe!TuV!Jr(Cl~1b`|_Z!LHhSa(ae8F=un zuU9nt)pH!2GsoZ|NpZ}Sa{EK1nx;TWbcYMb?Z%&KIGJ(i)FFP;)wxD7mKINodfTWR z2R?dR0i4aFS+e!nDVW#kf%2cO2da+VSJwmj=eCD|(ukXHUOKwj@~JByCdyo3W6AX6 z^5J?w-&yqktnr`Y2A=n)@XpuF0k9&;AvYD51x?sKthSGZB*&Jwwc|FUoI}SRggBVV z*14ve1&ZC<^0+cx#6|EeCGP2C+twR9$zGMcpSKYriF<J%TdBlbE%M8)HtOVvmamSZ z7j3UYfF1P{X9QTE`M62R%Ta$4Gbz3@Z%p>S70rd`m}SPYNCCqKM)5cO#eAtq`oshy zYal5jQmx<9$Hp2D>K1gHD2Hn{b@=4PMmCuJ^uXKl(ag(hcFDe<AB<qQk#=xUd4GLC zLAKp@7u}rBMo8(+^?8WZV-F7@cRXBD@g5zYFBVbqJIp_PM3`yhkzx#8GTnrmec(YR zVv*M7GSI^{ov_7oj`UM`COCdVjZ?#+E7Myx^wYRpp1J$Xyp0j7_{~L4`Gt1j0?C3s zFL>0PP_@h@R4fI?eJCYe`{LtJ*FK_bT;oKZ5v!P<eD<Ub2gVa8!P4ULtmzs;#v6Uk zM?-k|t+q`%Ly6j>ntHKvTws|w+Ej}iuSr&Hviyn1H?6`{lndI4QttZUU_)oV&@6|F zB{??3y%ZfDh8Ei|G_5)3Wue`MXp?HIYG{0P?R^?tj3b6~)WEYryYZYoL<Xm*!EjG} zTo^l#xl?C7vpecD!XAx+`{l%n_owa<ujZhbMKjz9?P~cJZQajj`!>3euCj;Y`FaX& zxruHT&9>cX8p`LRnAB${)-Fa4&TR?yWH|5nY13qi16QGbLSoa{6xV+}(UN7q%Q*Ph zL03dc3m6dps2}lTWjDXxC-^tJeiEp!b!+c$J(_<dWfEuJCK0}7N+#iI1_34%L@W1L zx5h<lX8n5ZUAP)X@vpb)#mL$fP@Vu^tssP26Y&A<ika0bBJnpDL)Jeeyw-w}m|oK# z@ZT}0m|9~GfJd!SmU!Jjh*GN?2FfXLF=jo`ZVkOe?@a*IN|}gsWo&CwMzDrw@Hb^b z-vkU4Ch(d^xt>k{+W+-20O~ts^7U5?iu#E`?e$U&q0c}8&yH6EJ5+19Jt{cO1Dqw0 z?Pblg`tHoQy}-t%=S+2o9d4@e7$Ny<JVf9mAw-eEm+5yd;di^q@~^TMDAdsdli@yh z*{#_K(0WBhS_{_jyS@D3UWudnPNn?jUg4^#EbCv*ydh`%F(!+6g1*nwFkt1o!}c;& zyv4KcNU-lJndwNqhvrp;fsa^<`d9rdLfkm+EkM2enwi0L1C`4@?nyQpI?8k*Y7B2$ z_T45z#r%LAfF3F&uV8WgF^j;zawhnHG;qL2`-|=I(2p4e1ba`79#5WVK24foUC+ZU zRI)LM$7{2Zxy_kiPb5utv86m5Rqq3c>jWv{Pulg0SROs2VV%o7a(T`0cpFdCZ1&A0 z1r%%_9#_8A$hOonyn7w&R4ts#C4n$?J7joJln3K-N6WcBaB|M4`?%Sbi(s_{g71CV z;YYC;Uxz*6`3$N^{NonIb(eHF<Yk&eD~~|jJf_D)W_1eV%;4SCDj&G5-Sn5%I+7dg z)h>>QFiWXDq&mp(m)g3C;2ThLt`laTk!3_*Pz$UY?A)9P`pm`@SRJbaeZ|sdZ)h@6 zAO`JL$9PZNxN`43=S@aOHIyvm@erjf=3}+yWV&)dFQ`UcNBkNIHuX5sw{IB)qrh{+ zPoa9~!HGv@Ast#zTl_^oDg0Qa3_Ctg`fqj+{Fqh=ecC<A`1Mqxy*@@Ii$8=Q(-d$1 z=~SZf<9%UD@4EgB577E@{J6W){^KE<i889kQG2oQLpaK+oWt>+B~LT6mahpj9kf2G zUo(w3FxZbzr2WTB_Vvi4KdlqcXZ(kkLYf`;ki2Yeo6e`E+m&5zTX9M~)=}rWYewtp zWMbTxHC16Pn=u*kKy>gf(6yQEOQPW`s@c%7WN^b4qs6A&n@9r}4lAW7k8xJBFvFf7 z=qnK`0eW(gX3<UyWOVQ__1tTuRhXS8rs|Mj%*Z?cymOq_Hv+$1T%oyyLTvM1npiN` zI_E9jy}ByQOcVkihQ_6bJv}L(wkt*DrHVzDmb^*}b!df0!eULp+Oo1G`|Nan&ht~` z)D}5g%Hh=(P=yNkO(J0AcnmBGn_o_uJ!*<a(0O`{n`GE@4+072W;m6{B_nxHMgrV* zhXU&^(+h*z`cg2C(q^6UVns=(&04q<?o)dPUif#8G1B{o9mGZZR~d@m+I<DvKMtGy zb(f!T{D0$RJ~98NOZ>P!pC(|GBpK#cm=CaYJ+F^kcj-~+n!o_VtI+|!!$T>)hHH>y zO-=;70R7FzzvR8K;(d}J0l)XzVJk}jodC$E<eJe4;2EY?*8@h@v1w*aJB)ton&4{^ z#X4@do@oo_z(i}TDnZuR*Scpv-9_;F14*w016*>AlD*R{$aKwmT<1)!`wPKU*8>9K z^}Iv!oeKff;9t2WFaQkhRQ$0$zwz~A`6cdef5LqpGELD}x#-iY&@I;<>{`05X^G## z_75A!zfY8dexE5P_A37^N>zP7@V_{~dsqF6`vB)}(^*g#b<y6t>Oab&cNw%6s(bq9 zGjO$^&cHQdhjBc|ct$g)1`hIEGcDDtHA2c~D&jPK%aHu136fWQJbms2nQa65ZsdP$ zfS-~rpnsNaF`zP1*=N$;E+kz?r*qz<qQ~8;&@=`WA(yT9gsK9+*&=&8U!ow7C(l&- z+W|hh@L?kq?PcBV60%3z*xy+(KA$*5cr^$KQ{0qE<$wwRai2A6WMQB*h&{c$esH_E zL})Z7t)T2q61}%e3aQS*%Z3HS)^1dq*wJ*%DbI221LW{v0e*F9`rJN|8`fsn^*N!7 zM-|mEzdmH?QdvZI34A>{c}sLf7@-|OGu^tDRMcmXw2>x1!ehVOV{s<>^BxwQQ(#{W zv=)o-F=Z2qpS614JmY5(_Cz$LgOl9ZYjl3JPYaqtiL4A{+TR|}A_F(#=5kN2O2Q@7 zM)EjzTOvB257*(6i~1(e`|+#ofGfNOcr(P_@bRL1%5n78yq`U|`yzPK29<|pe$A*| zA$eiBypSI8-Wa20g>Qhk7~4nS@rL5}^Q{ej?Jw(h?SEkTZ_*F}%`+Y!As+S$eilav za6aw*-LK?uodqjz9G2x&Wlw>>7MEoWm#qvl;@Ohtrs>5^(xD3FDi3R|g4QFRl)do) zjMMmwr?Pry8Ou_iT)EK$ZzA|NhayZvLdRY}MG45k7|SbBwz3fQGVo?r@4+2B^IUFR zkB9P{LkljptnGYRnjxR()?FMOxGI>Eo&hQXDysME4ax?;;E)KlT1EczI}+^=Ipkr+ z2QA@026$gpl8_MbbAL?;{`q4_+_26h0dJ*}c?$IH>&rw(s=pDVcb4(`HGO<bYVXzX zkHI*lJB0~mLdWnX%gIQbgZo(F#%tbeQ&o}s&t#e`@Ww1Sv!5M)ZV#;;9-b^d6`A{Y zRwn3kY5I3pCg^i%`nxMrmg!_y@vD&f<w4TF%@Ha(-Re>buAj%d9A9rxdRM%XsUE4M z+%P8|&Tb>VDxATqVl-Xe%jNw;-e^ymrOq2T)*m9ZrFlIa!qb_#rZhzHjQP526uTgB z*n7^s@2gXL-P%R0AJHQ@+}h|O*^zF*x8b2=27-b0jUc7EOj8RnplF}Fds9ue`q96$ zi^ga6Wup4?bMKPZ8l5r)KiEwj$+fU?qrIDSqmgKW<3=)u1n>;ix=I%9WE}wdWNvFJ zl}sA-oc9Dpa`JRI+^-k-erXngFNpr>D~}Yfw$^!@H0tf8JJ2L49$D<qZMv^>WncBL zT0UM50?>`udoU(wP*!~Xx~C++KStZRurP~K-GaC`x>lTz(DkmPo4<3I)X&uF9lZLP zs{M1u_uD?dqi;WjyHNU<+>Ll2e?*1r4wRH$k3m@DN$Bc{1kuX1KnWbZ_rStCH2fuZ z0}KfZR%<0n*Q`+d9XrFr_3VTYUH65c?{gbycy&?0)evSSTU4}5so!unnpn-6_<ayl zOs)Ncc;%HJDY0OlSiDYY-C*+On9;imC*G;BZ@Y-1-oHr!TUjEYr2(;K#zy$+*U;o& za<^_p0pi=C4LqmcetC}b_o+D_zl8vvpdWq>!4E6sAKt_dzipuUu8s7^uO!IS@`Gw= z@3We9K&uq&^UOog?X&Dnzf{rsww^(Mi)#It5c_Te{j@gyt!Njk^8qBQ&r`+1>?xpy zqt}cAzE_&t=;sEk+{yN7DDHB?<xb5>-DoytUU<QNAU1n0Bi+LUXvh2@V+BylJ(Anp z{zL^sMs&v_9qcBY3XIR%ZkyaT)Y!=FBs?+oAWPdk-Ueo{B?v%#o=dH6yjwLy+rDa> z{r-WBoqylHy4q5@?kKYj#l+c2C+48Q=q=T@8?7}&`WnSp$U#jL@xenPUzQ`_nOpbv zdfb0<x$dP>=|>kZCcC%|X-WG5-#a6YFiEf;a&xIA5;mXEhBX$tzi-?_p)&4y2q<H- z#6|=bW%ZoMbLCr|{zzRUJnK3Yx8io6U}-3Bl-m||T?D$dX9MwG3VaY+OvaKTI#iJ# zoCN*C+)qp>z2+;rX*P*FcO<#Rq;?3GtJM(3ma3oI0<xl!w8lvxGLo4?1LdkyEgEMj zs=;G)W<{-NGg&`9;$xI{ZRPj_haBSRKI%m7Da8U^I{C3ZUV?on80}TFFxWuD1mRFs zo|VQo_Zp4t<2jG#$3*ZLLL_cDpM@>q2`-PGGibY<bAfualHtB8>T-QF&W3)>&OU!# z_Rf6s%!J7A>H>N?_d;W`m!W3KF^9wF-6gC&^q3=q$~`@yCh2;cXHGkUugzryX@9ol zhoYvnfoAi?mjInxUMEFh`qGJ*a~Ez>yH}vurl>{UN5!IHFs#p-UKQLyalnU94sc4H z=Y6?3x3Tk$cFH4Q72T(E1pT}tm;Ydmf9%}-Ap)icxqPIr;<y}i)1o>7g;-kmjZU_L zh5N=;{DrHsUo`&KmXr=pF?ugB(9bK(-(6s!pI4Y~3(VuUOWQ|SO~8-R4NW1g>L1Nr zich08_#4kOyo;!Thi&9NRS509FJXAMKOKyhCCGei7jDkP{mao5)>X9S4rSXy+p-Cc zR*ZJ4lR3X&zHyl_OWD`y$vg;pH(T2r<;IvZ2v6N?c>eIz?DB#ad+^*sskFTxnhT~r zdC$^xEV5nnR!BHQ*u-YYy2B%`?UKWuWsIwcqB}=?>v_~1H2Xo`6GzB#F2^!BI7ko; zgXE>la_8`&J-#@r1-yjxXuqvsordeJaLuFR<{(^cQt_?8>MD32KpebzTG~r5eM81g zYOF3WxJ@N;-sCJE8oixAvPEXRGJ$);+d8DLZV5_kv88d8#}YyLsVzcAzzNkONd2l@ z)H6vUHW_-nf4JB!n+|wI@s_h07%+<|Ml(%w^s+hS_CvoIkZCDCcF7UP4$4iCACj~f zgyv>E_A?grFbto(+AFgl9~Ydwz&%WGTaFN4``F*OiX%XE$l|=PeY(R9;Wp;Ms|hzH zW4%ffay|@o`BJzk_Ui$wa(WpfJgj+FLbGvm_pT?{haS0T$qqT^dH1;7GE9CHnCtt= zT}_7rswntV^j+;VDKSb)@R6@DnX?x8dEfes*Dy1L2WN91&BsIaIGi=%jEpENH3t4P zUwczQkI&eatF6+Cr<%6;6U*A%Qzt06?U`<KUIK_t&J)FKj1tjb{Oodv{4QEKEBUd* zi|2+{Be?(fX&Lr!(6Zn3`7JHOe%u>G(Z5VYdM6HHZwAKT>#<pDt~9gmvPs{kO5*R_ zAu?SfQPHnY9zoJ|*AIff84<n4+nD!m9zd&tWZfhj!MpJNJ3O%WULU~vC}IuH(Zui0 z(xTsSw`ffx0>q1WQ^w#uViK-}U@|bZ{x3nT@i;I;jM@>w>b&9cx>cC^IQ}GjyMoBd z%+_EZvQ}ZlU(qu8Zt^^*IDgQx$ooG*%a)&L*_(=KKhiRjMK!_r-%iWazd_3c6|!N) zu@6gKYZuc@s0|e*slHT4KfFAoM+T!K;@@2Ja%(bCKf?TVk()t5jX=vXA%AcXo<FJo zkGMBmb`wjxMelivygVlq`-r}&h<!mPI)Nm5xT6Qr3j~6v-yqv7ZRc{PtLoozBGS%f zG(kv9n&WH6H-?$VG1~UX6)S@^8S|c$t1dqvBLO4#<4Q#md2WT|KnJqFB4W)g6?`O4 zPGVUPK*TWIz7%)GwA+q8T{-;r)DC1g9WGa1$(J6=T?{gWMQv7xY6rN2FX4T;U&jZL zJ>3`}t1SpHwW+v=7m(2|M}kr~PFK4@%_p1Y?d17-VhEw@Sb2&uoAzclez@n>q}U*w zCtz}N?o<V`a*y*eh3iL2(927&DlR^kSvWBoCpFSNWRWNHAb3g{^y<<SFflIl5T8w; z_Gg@^#~>gs+PDRFjjC+OFifY1kObTygg8bu$9qDkbJt<TUAEMTIG$4ZDM)6TCqOu+ z{z*W66|S2LYRDz2o3?(*EjOnR=eyi)ne4NY*$hK1;$|C8RXH7&l8s3!N_>w16XP#D zu_jeurUh0X9`djjmjjdq<Q5yt=5h^1qKm9SwaMgkmPi$Q#xTow&$5pTZUh{fcUAe? z3GI|c@YN4G#WE}$d|3VIrKp8^on^wwiU<!R?qubT>gJb@?2+h^mlw_lB77XO^SxzZ z!))b671F~BX6sNIfml2)1?sZbGySMm2WqWk3a+z#EY>ahgkFzhMbQ9SoTc%smnIe9 zsg)gip;RH_DMV4VJ~@(T4EqdE6pjB`4P>f)RKe%pbvxjb!X1NtDH~;sB>Ji(I@=$U z$;!Pp$I~I^(e(CxiL5#ERRQ=Y9nKQF1$=_g3f#@XFiEsm-*{KVz~HmOmas)WjRpdN zt3%sY_187I(=Vc~<);$+_H4HhesvyFX6NOTN%s@8c#a0{Ek^02f%{#Aj{O8;7M;)E zS4K15k(^(Z*0kn}!^)RF<QdjxAX@43SEAL&aP|+ix19vDg<`jrAc%r$)Xsxk?TIei z)2hN3|Dsr$^+pvO`tKIER$c1rU#4n)yV3E(wB+||fDdmzgI>42?)3UqH7w(46Nj@i zzvA;%o+#M2`$Yu-;u&@DpoQau<=~jRZ2>1i!fbPapv+p5qCR?(R6LpqXBNz#%iu1& zO0jKV^rja^QUfv6q7ZQy@@aj#-i2g_P><o^8XC9BK)Ruu6K8o|_y&ii;srlWEfo6s zwgpVaIn&NDa5&5Ge4J4pZ&jp}I|U}z>*Yzy)C6_qO>3aec5ai+*|PN7zAj{OpkGP5 zSe#{43$g9W>G36@xqgw4i(mOLHdA_q+Xlx&vgKRwH9Qo?Jl{kw@J;2hM!8^Omj_%^ zed`9X28<ZWJ{px?wDwLP?iij|pqH`MvPjv~8I2P<Z1BMS#O*t>Y)fm3!DHB6us)0F z8h-(t$MADNn9>@jPt+zAOnTxXUKQKhjD}<rE>PSzPw|*NV&k}6C?hPxhGE0|bx?hb z07_CU7pDxa5%Vw$c_jMLGo$c!i}(j#l12^@4?WHY%FkF3=RDhMg<7wRR!ntO#s^>( z-Dh@mX7Aoy!&6$AnxeBa1}V%ln2um@JBmtt9EdwCpn;J&w@gnWwvD8?xS}C=2b={0 zZ}QpqUZoaMP&Wy(I9(V}A<mC9#2A5aX?<{VX&6&;;M;OUz2|84%6ZU>SF+)PTxHd1 zzOPW*R1kXJ(mPXop+sPYkKV^}ac6zBTXxdi4#`}WaCSm;@<yztq1LIZ0H|T-Dk1yA zL4HDO?2Z}S@nid&WyZ_@HhA`;esPugCiVW7T;DsxY+KjQ=3D!Bk40G;`aZP%&rbgq z<^IjWpE}8(55m8t-M0`I5BB(Q3nN2pr)Z^b-PMHHhZlE#SG>#Ep`RP0BKX_PCESDF zl-fD*RI(QjcSpB3wF@Et1*W^84fbY}?JW6dFHrun3Yome@b^w}yiY4`r-5&}{Vt`4 z?&VDIJ%$*dd+Rzv_DC3dS2wqa7oqlXNb=pQCf*h@TMUl|dvke<yz#xU{f~q2&dwSu zl|NZypDN)nx1Tmu#p3vVG|Bt6sa`G6=1dUG?C-S7RU?|^Z}PD(%=8@%diQq?W+#b_ zK<r@OA<zzAI(IX_4aTeU#Z+gNyX|7<*cT4|kH-M#{`sx_?wtX@y0u^3+0VYGz^{!@ z*>yN#M-YZz#LFjb+)_g~P|o1<=wC;bXdg4VR3t#9$EWh-Iy~$`pH+goCWlMmch=4E z<#Dw|p?kf$juJa0PK8yt3vpxI2{a06U&c!r;FQ3gz^BSxJG<s44`-F!KzK9>7PqYH zwQz}kOK60eF`S%|bM5gOWhhAO13}NHkOI`<P{JO;N>rlt*Q+OQCt@OvQfChzWss;A zpKEb}H0)|IS#{3mlSh^KK@@Vw?~fXAvk_?k!QQrlhe)*vTGA9uLe$e&=!Q#UPWH<t zp0|zKI3uu_oP6Cl1q@{k)wyRy8F)R!aUn0Zr}0-(8Rvs`Jew{tKvVyKL+EH<l?rz^ zaEpCdX7lyiwB2>3sl7G^{8=0`vIwmGKwC}@?B44on{4brsl+TA++PEcZ|zy&Cz+UE zHoF3z?fUannh=Byvjd$7E#nW90F)Jyfw9&fr{|%D;p1zzM`uGv@ya4_t9x{P#SJE$ zOx!wCVDFLlLn7di7{J#H%cl>(x>IPQP}*a<+a`GkYPP-I%*uFah+ogdRL;V4C<rCs zrSeuU^RTvuHE9Avz1hp5!2o7H7#3eEh$*-(*>oD-5{~1z6?c{gj67Uw*?U>_=w;Ze zGnM{K269|#H2>0?Yam;ItaE45d@OMK2n{<Rx(RP?rpuvHo-f{AL{{%6b-9l}807$Y zP6XqFnMOrx9Y)b@M?g2yN>xt@Ikx7q*sSH-+sEiNNYM+tJt6bBUe5QK+Az+WRy=$z zE?u0?2sPF7nf`YM;*GXR9>EtUGWg3}`<FvM6;l3g-3P3Ex8@J{GdO`i?P>+cdj=ib zH+(pGi<hMPcsWY$`!SmQ3w+y#ZU4l#<DYl65MnQ!;PI|!1`>O_iUM~@l?`N&WN%<? zn6wM8L2m;Obe|5}=fZ*ww|=Frw(b4oz7$0EvP|@rZ{1D?-_kE+ygv<s?Z86pceNK< zc0*KXXDxwmt#Sm}`N|-+cjdNoHyDAiy%)AKqyNz`gp=N*+#if2M*Nh8Ok+Q7+Ja&7 zS76^*zwX+CwUY;2IsdMZ!SOG~3}LK_YCgNcuRKE3<-1Au7qHK5y`8%5CHR#r{QBwG zh95r`ZuGKzaqn;ZyL{4`OtmFnwY_-Xr43t3aQk*g->kCK;_GDlZySxuv}@d*c$sLe z8e;yCd&rS5sL4IhXVW53=g<N^ULWb#OS=o?qEj{#C^wT)d5DvH{&svtVtSB=L*@!9 zth>jjj2`-<SwW<*gl6nEBY?H$-99*@5}DwoxHp~q<h2b3jy48QfjZXl<z^OYo9g+U zv~PsmL9m0x>@XdkBu@+gV%E0V?&)?c-_-kw4rR-!z4)507;er=(+X&GrJ3SzyW8R_ zJ*MI&W~>v9y0yam9hfc;qPZzH7zS8mb{)%+*YR><U+5jWVny2#ZG?)a7XjsNW;3`e zjG&(3+o$5r-TV9rkd3#5MZ(R^bw!waJIdESw)6)h&{<?BVv}ADtxVsqUR$DZo5Q5~ zmC~!erFDT{h=1wdc)o0QlZ>A29mzD^`}~)F3-Fm1&=;jGCRp1PJ2jGRgF_7aQ_~jS zOvqY;P~HgMjfq-|3RwHWc?QFja_;$|(btimA4iFs0(8;c)rTqSxeBkQr_PdobWSh* zOt#yO9#4eE;qu`KARI46AsgRg57bxX_NuLt!Wku{_4U41(+PboV+frW@qs4jl~Z^; zVw0}95^}>Z69=5M2a17ZS;ll6OkI9Ss0X&3ASO#a{&CACkzpfG46bquPrV;<PB+x~ zK~IhiMt}+qm?fU9Te?<htFQa7gy6S`2`4}|GG6?+Di=I^Ho6`#u7eO-d`BNGG;VKf zncRcMUtz$1Sl)x~Yn$~zm6F0a){nxyzp!|_gyTe-i<83US*)sVerS~X+uOgZ2X*%$ zg!N0F>X&67X~V~miPS{j<U3!FZOQO;#s3$z^-loufA^WbLC}xSLjP4b93&u+q(G7c z5gdaskisdLB0&g7VFV$zUo(VK*yn~B(7yGfU&f1r9SLG`-{`mef{J(Oir*Q_?w1+- zD~3MT0DU7GiT~@%(9BM8eJhJ@u=K_F5&`#&Dn<4@2z!%rleZ|$FD)~pWY4+cH{9(^ z+_!J`t|yv)MZb9W@7ynhd@;>}cO)aD9kJlIn^gq9i5hP{2pI2<UF6%xV*||KpXJ5X zeOG>cpw!Kh^?_jSJ><VM$WN!(J7kYfk&9)3>?doAT`J{IDU`uHxo^!+G^$TyBx;q1 z*l&W>x!!Qa<V!$hKlI5%=OpK$OJ^2r-(&ZSagw!D|Lf}RyXt#rST(>|`38ZD?g7?* z<*#C5Z!NLEcVhZB()?04jNG}ifX30_JD*yu`F)VHR&C|6EgNKh=j8!^_xgV4<pF>9 z`hMr-0pGvApOdn`$;mvK!KqVd-~d7<YG)+yg&sSS@Gm_(KP4TCbdAhi7rn<<EJ+`_ zGUCA~;zY*eVNpYq?<4xd_1G(*_^=>Qb;SAk80U2BT=Z%XDWw+c6jjw%+R~5FTQ^7< z^nB#bZR^3FV%n-CkFZ1B0PeMY60tZn;Zs0fOsov1Ml_!!t{%Z)0m1YlOP;=5NchCB z!XY#I+8THy!0-}G8VLn@UR1C0O;3|a>e>a#he=V_$-kP(`GB;CyjYuviWD1vmG!H6 zP&CQ2Qa{kI$oH>$0LX@-Y3#C4br$nAViq}S!Gm$_p3*&!ZJZ0C9=$Z%cOxNg`PlS@ zJL;aAA5~FKHM;<=(_?uVh<S|l>RVEl`Mad}JoEDhla<w8H<qEjgrOOZ=J^l61->Az z@Jns-A1cMFe{Jue;Gs9UQLzG}jRCmZ3xtPWsB-U&KNjcP&f1+7obFmS5oG7b`Ito9 zKatG(E#U`}uTwV;A9FY3%Ww@(e}C&1^Cey6KP52$UqU<HzT8wsfK$TASB$Nhu#G#d zg3p+IQX2@BOS7Y&GgyWS_K1#3j{2+n5;r&prZAS!7YB1Oc?5?V?klG>&Mga5n19ag z@PdI(YNf7r=u*@54DB(b5H2tb?`7@s8iC$Nne<L}YsQ+$5s}O0A{UO4V9QjBGCzQi z=8{I(r237CJqSbWxS7>;%w;bRGd>4^q*Ge$)-f89P4i+yQOdMI>dKobpj^G&WW@+w zQMf)I<3VJmFlgzk6s{eN2gvPeEI@(RFYIy%gpsBKzj^j-aYxN%CAaXVQ7Q6v31bY@ zsCLZoF{m~2Zfsla?S|e$iuG<c;Bp{%^J)$<@?z&kC$qMdm+;2P;qOX+T>iJ2Cw~a- zA6yW}%OAp{eRh9pb$=ZHmgoJ(NX-A(6+a|H{&LDcmn|u1pDzLNeJnKycaTiqa0d}P zXEF@m@|nb2Z*y1Q{uIDrVwdC$-+q=zx*LCNc)npOv7LwS;%33yL~Hve0q&(k^4)q* zk`GbvzXCY&e!6haNYS@~3H6RIaC9%JZeakJ>{ZY$p@p^|qP@nsT^CJvhz_D1-s88P zI7Gc=OOm~mnkMhQ{cg4Oj{yEotDeO_l`Zd|$c5y<w>i`epgenTqVe%0@p|qHI=211 zgor)=DOk<V=WkT(B^Sem;rAYS`7RU+r!`vW<sZ4(AG569vZbF0u>bHSKUF^temypO z>tFHr&oR^16i)h<B^u28R=(be7}XRM{iy=}Qd#ob%ucJrWTp$J(ih8bS#t*L$?HF> zUH`?<?^|B0eVtX!z9hC99z%!D75F-L4wLJGg@8YZ_;@fU|Fwd?Q>->3WNwoXgg?r- z%hJHr_B?OSCwMxmAV(eP>Q>kc=MAlB&7wsa$We?*^^hn-KoeFLEL5)$;;9e`{`taZ zV2<;X3?F(8x+D1#x-g5ty`CT<BEe?wxmVcn%5mt!3NDWAJ!2{Ch<TumCe!&cx&^@Z zl6j7c%L5{fYd}lPt$<y{t}e8Gs&)MC2@LqMget0~&>O5Ygvj9bKv~Oiwr{rT0m1Y_ zX}r=>l;aNl7#x)o-KnjAn($@0P)Rf+&zOJ%s;Rx{%!@uQ*<1`~j_UKt+#Ue0$kS)Z zixzah@-B+Ts*4^8yDOywA76S`z<1-S%RP&>ASV22W<fjiz@RBQ#Ls#ZYWcFl`Ei8X zU^MTlBxoNq3!XJ+o<i>@{Jb9cc0%hUrEh-zh55Vh3-CK%n7{kJ0H4ny@U%+LUn7D) zqk&)JFDIW#;;dXdk>rOUXVB#m<MhhpdQ>u~N6kfjy|w<qOK9G~I!yLl^-6-Jqb<PY zLa5>vxQPC(?Klxm2Hk>=VWrv`w<YBlZ+u$1dx0j<mF2T*XPGieNY&lL0yZP!3YcoU zN{1{els+!N)AKZx8Rpf=YED6PjSscqWvA1v>S1inlOU9QPzfdJ(qHc^cWrNgST7EN zM%s&}@&ZSm+48gx5^m(8gy9R<X9t*D{rJhA*N0gIaI^tCc=Xj{;lI$D*MXRS9PL*x za)>RR2TBk0B%^aVueLDxc9w4Dh2S3y!*#uru%lypU8}8V!M;pM#n@*G=!vH_OA!rW z**jG-YV%<d-D5cU<nQ+e$Ka6`NfrNLCQ;tBRht#b@F!ya`S`yD!vB+({V4kW^_+i( z;th4tw=8M+mT17=GF!XnWb!7y1#csZc&ERi_^)PAgSRpS6zx+4A-LmZlJ0nmzo%I@ zMBIRPuiGNKJXnJ4`R|5~A@(ma_!VIe-6dGl;LVmp_7>oluM_xwB*6EP)PUN{y5xqg z*q(1E=(|PvCfEhRj>%h^9l`Hc^wtXB#aP2#n<B)wB>o?vnA_(VrsSWXxcy{jseq5! z(p-%!M9-tz?|kP~N+-SY;QSfFugQn2Dq23UZ5QnShHV}2!%1HYvl1u$Zc01@+Fio7 zoOs<J82*wH@8#m}j@>`M^>23${HM46?Hu6Wz4dLs%YNO0yuH(1>1(=+sKfn$yF$%K z&d4#R5+N~-ATv&oqGKCO#8nAWfK)FzJepoujAnTq%8tW%QYKpWuvRi?LW<%Y6N<=` ziIX0XIyFOkqJ1^F!(MdRxgCdXYm4Sv<v&LxJ;eU2?0s3+Eqn<@5+QxaWac}5nDydu zd?Z6h#7Wv`hS*XjRs<FZxYWp%o&;}@O%7p!WfL4-?&xjdrirQTI_U;q;E-cv^Q6jR z>2!yXh>&BZUO5R00zg5ny3Ch`eq77z3{R|Bvro>W@NPA=@InUB16pOIJvxSVLg_WE zFvay7S!@%q(H}GbIjE@_T7qC>dQFZFg@i1A$BBdnqgx$6810TiV>cB?nQv*~L1#SI zqT)%FME2(v<k2NkeI3CxpY+fU)(CoWEZ5f(wz5q5MMC1vNP@D#w3vNe4}5w8ei}NV zodfQ#LE)dS=dCH8G;l*wdHc}VgU>S7mfp5uO${L&cfPBBSfHqPdj3|)QS6=P^>Gdd z{BAt^D|iNeY5z<+@f9s%Fe(E(5QZSVu1?&Cv=;>?lyt3I%E~w)z?qPeRgIHv=jL); za0#%4u1zG|?7Wyz%zM&Zb3H68Vw`G`tgJ(GR<G8Jh9zN&F`NUE$Fq1HE%1aAK5ud0 zk)3-}w~rkx$LGQ|X?n<n9BL1Gf>LMryk+Y?Vu4QaO1R}LSHNq5@Gj^{3-w3DPReD< zvfFKJ$*W1kXUuWk4x`dC&J%U4LIR5X-7N%6>x@>m&tC`FhV0SowMSnvr`V&&YOs29 zx{B%Vl@xT$C|h|IRupI&51tCfNn4An*=UoAL6O3HfOEUb(!;nmnw=<PQjOzH3DW|( zF(;wUDU7R?BZs8}%97~``(4+q%a*WC$)l;0=I{Nbegxm&Kj|B^nn5uK%^!mPBch@( z2qPc?k|44DMZhS8Q4|G1D2QP=1`{BTlb<_SY!J8$T%tR=?GTLZrd1o*ZP1n?JG3Rx zo&-ne+fgd{6n0Z|S15;|UC(<<r-L_WQ|NoZ4}9x0;d?oIdkB9&M80*HcBzP8+F0T5 zX+>&JZ8r!{$X)1iSMp5v(Lfm8WjyyaZ!3%qXM<!{ASd6AR_twALA(>?7=3f(-%R=K z{*X6SJ^W|shiE76Kp%2XHxYw;XN;yf^ZCxBr6AD~>NB1qM<0Qo0L`*jepXrZo7_>O z!xX&x@$C%I@6DtBHfaBv<u0nZyI1h5dRJE!dMCL*ADe;e&spv%dTr?V{JNp3G8j+0 z7G_vORoML1p$Yh9()yb^;{YwU)$_8dZR51bF}*lYt!%g}@L6sV^15JP2p3n4!~-`q z`3UZqfe}SAvC&?eNmmD?<Qm8vB`L>edhP`aTjr>wgrhJEqJ=e=?r15J>mx_JMqbUu zGQkkx`4Tzwxo_A|4`jF4A=?MWj2sfNvNoP$=4mSEkg~5Cn~%{IG7(ScVL?NwF*n10 z+d11?8C8bx8kGfD^7)c@qBFWo!P5NGEXfO`3sWB)tNL+_Rw*9krzzX`nW&~lMNP`Q z3okY8Mw6w-0XQAUW>J-Kh+uk@(<t8O=98+2a5GQ%^pcM*p{7?{4N<T!?nK1Tu@P<g zvkZ-XAHcxf(GR1+^o{vs#+IUKVcTWB09^(5aI&u*ql%9Ef_P|dCmHL6G~l&3fUG=s zBg33tKsBJ(8s~-<>Eda$`q(;G358c<-%pCN45c!oBW1Um;p50PBFH0jswsiEAzOrX zJh6Z+^d3pWV|Azu_u1G%b54RO3O&XIyTpJaC+Wq*qcEcrd%I%I7IdL!Fgiy5^27{L z0Xzd58NA?A7I|8R`|>b0IVLB!5T>apv~frR>WU-!)%VW1hiJi)5aaBG#QCZBw^juB zOmWSEy^&W^6Q443p)~sPOf)y{YK&H922wni#xLrI{$1x1wq89=34a>%ftt-+1Kjq& zi%zJ$9M&06a=>`?rE+_3_Ia{0E?W$wW20J;v(@I`itNE2mVTWI1it!#sO#mZDh^v- z2*DWdE3Vec^}$;9W!(V!i=W7!qMBSOFhbNbGtC2Er7l={iypUq;k3Q!9G$oOW+5_} z-6&hYN$(*hHqBCgJyu2rgVd7D+?i0#UI8q}`t^h#&(g-!)=PvXss>&2ZF_O9&T~N3 zHBodtW+ERjpOrC&O~y8Q(bsn+Q5dyu(Lq`WJIJMSqVyI-A2(QD(vcxm<enew^-kUs z`RZm%3iRt_91+J|aP#iZ_ahe3&S+&!nlu<Yks;=E-GpR$uPTj%*Ful@4o;&gm0x3} z4iv!Ww=ZvAh$U^Lw@N`waysbX3D%P1krq8zH<j>J1}8U>%7G#7h8%b{m{_*kUT@)v z2juIOIp*DCLhsZZgh2^2NoMuFB)=p-uOV8jERM*AGx#KX8wx$~pys%{ZEb2ljTr&t z7HuDM9QMuQ$)LK!=(dm&sL!O!GpWCVsS#h!Ne{-{x<%->m3z_p#HbAPv@RfVfB?Qf z=elvFS2}-sVIueF^)53+?cUNxT<F6Jr&~lh&!G{Y0|7fL)y%S-86L#2^tVq7&~S%B z9c1O@@t&$PPT!i-`Sv(I843X(hssfy0@LDi={j2Bv0hpuXA8uV$1zwc)Nz4l+}X^d zEQv7{E)2G9HWE=KC+~4Rr@3aQwLxmOJ=GU&cwUinXGre(xs>Mpg`#%YtiUkb=GxFM zZYoQyE~yBk+*qHn%9~2+2iIO4Hygo`BKXuC=Hc-0iCaw57o33fN5mz-S>?DbubB|~ z*&NC+^|WWyRn;vvv@XIf%ORava0}O>2))ryw7E;>@xfaf4=tSfq${BFydk~beqTA0 zE3#q_i~gXuV~-^ML*hOL@h*Qp`W+V_-i}4vu}=sG|MkVbg<*elp&zIP1cadkL{JC{ z!5~HwBo0G3K~N~Qg=PeV!Wc+?s=`SU|BBuuHzM3a95C5Q(OXEgYhRIjNJWKv^&%kO zLJaWd#^u<1=I~uh0pooTF@DeTeJQYPQ5ux&^_Do@D<J!os6A3bcjNJ2gk?Kz?oBAz zP5_}jI3v?H2QS+1?Ta-z74MPOcIn+?6xs_VJJk)_pO~cfH7T?|B~I;h>}?qm@0Fb` z^u+#|PyJSP=sr{(Zrml!Fg^A33BO_vM+!%JzI?9CS^XTA?R5rQWj-n-sxDMbVC`Yp z7d7$kxN&Fx#UQ}jO><x5ycfNPa8%>Ai{pGH(2acH#NE5Zz%tA(`4iQ4xn+m^_w$Ee z%Okr1BL78s^P33z%Kv!m&QzZ{ll@z_{rz17|H*BCyX&0?@E7XVFNgpmm%A5?ztHYk z5J@7=4lZwW0TBW6wk!3Md7%s%Q%-rtT?-oSOS>}V{Caj?iexBT%9FC$!kv)*S}Kcz zA(iQJ0<TQo6{tB0j)yft%%yFgRDW2+#j3@$SvXfbC@(lgJztXy2RdR7lR*=oYONV! z0dlkkE;|6TK5=*M>ccGQ9gFNb;0Xr}+EZ7VT=P9=i|(QV@ki(=6vhlbj`O&{9hQL- ze$yf!1#B<M+UQt?w})i7^Q-2xL3-9A$jL$bXw57a$BUlCwb?Cg65^fK*r)XbJzATR zdh`g;))v(lIkud|06RtQOGG2?!GdM)I|BhP)dB9iBa6I(>{#jH?T8BwKIf?*#@9VW z0sizt`P7}{AMMQmhS5(ru1u7CK4*7+w7h52EkaDfh{UabvEuy8THw3IzhrZ_8BQXH z^GIH_B|^HgIv<g!4n6g$vq0=9&-^egP~0T;<C3l_YANSZt6(PL%PmgSR4N0jlOsn^ zp!cnQ=$uzmKlm|kGS5tbbS}y25}<N1XOju9iqs(Pku1<I;l)E$5onqr<f$>j-4aBS zmFG|sZgEIW@<9?&4QLLO7B>Ml>}N{foUmWPYK|5-CC{%A4TVFkw>Zj=)n#PIW3P%M zRBVyX%_rhvO0O?Kga=j2A}3wrE#w%-Wa16IW;tky_^F&O6+v+R(zSeips{&g{Re4s zy8a{)GWA|`0vuW}lpSce;|}88gcsOvQJK!XngA*0W5d<9fGBe$tp!nAXQer0-RX>< zXY${XxBP&ruMD{V9z6e(3;hK+f4s<#d^`%>K$F5KlEPpR1rY+JFo;B83P(2RL@^XW z@y|e$p!WKEK)o%r-_k=!u=nOS*xT}dG~K)M=$l8kArbs}En~+)avv?)PQ~AvLtkWv z!Z&)x_|7Ls!LQ8-INj-V)LUH%`4t^+e@1dA0qiQ(=>F^kxzp}o{N1?6cHa1or0++= zw-WYttJ`hw+D-AkEPnG4h;(0rynRBqYevKl!8r7fp!s-%=0^+R#&T0;cMPjPggka0 zvg3=Q@o6oC$^UPGCOwNE=o5dBJ|DESZzT!fW_~xU|4pj;dkv-Uj;R9wnW3n)v!%Wo zioU*ow!NqNofykt@?RXq%YBXaUW46%5C&foM<*X{Y@puxaP_X1NPIkmu)G_weGK*g zTPl?3ead-vOFR_QY@wvL6y?ey$!!UgipbBGsu~!8H8_>_FO7L;5$hOpFQKGu3@Pr$ zInHOFrX^lp2Q<uxW4fB-OMjjne~3;4;x(t1B7i2x?KHs=Ls2Do45lQTF{ZYUMg^u5 zlcGIAJQXblQ=~&{yFP9C%eL*v=LsZe{M3yAim=D{#qP-(oX7hv#dvC8L4xM$?E@3h zBJL@<T@QRIdD3LL#0}5ShrBO4H8uAxE<_D+g=fZ^=*>76SdCmxOn(W6>9B^X<uj@1 zEOnwjjten8Ocp#_JrOhN*s9Rwhyq#c5O+H}j{4LZMo~ms`(iW%8S-#3>F&bd_tCgR z$><*LrFxm<`3Lih3-GBQ#phJ^A0(@33cG1`r~~GCtV!is2(O8&2#Er1YZm9P{RSqR zPc8ki__MXYF5s)rNW(jce@V(=g!qQ1jNxjgkIaM;x0KrD<{kOr0c?OjK4VurP9`Hl z_w!SLqogsLn%#ggbnlVE=Bu?xwSQ4dmn-_2jHd3=9pS5u(QyWV_~qExgG|QG1%<BQ zy}sgCJPk)-%jN3O0UeCFr_zRH9b$BcZI$$JB8HX@;HXIQ3Ai?uRThD_g?v)ar4y<7 zn8$?4<C0xg2Oo51F90<GYFP*6QNk8U;uaku=jWZb!D;|JgZH4DF(%wRTw3PQ9iG!k zH#=Brn5UT!Xm=Wli7KCNRM{&>3yX0_<F!M;m>k1f39#F*iC|%hC8*N`u~?s8A2rPz zkEoDdT?V=+s9e>sgM7yhWAr}&O0mfDFNs~yM9Ck#{Xc-2|K&CR0-wLU-uFm~U>Jge zAV}aS1a65a1yKZy5(r2jC_<3X_7M3guRTWJ<_^iO0)s{SDC`b@$eWyw?V5ZMwj=6> zk6Ttsem>2My<6YOn_Y(>JM?1Ij$}c+Q|tDb-Zx`zyXuxhLL1mZJEX<Y26ew`3ZU-- zKDJBGM99ur-%?~0-&0cJZNasr%iC3wH(wroD;6T*9u5R=_3HRNrxoCDq93sjY2nHK z^c#Xhy9f3^0_kfnfcNkRkkb7tlI!+-lb_p`-7JsNtK!e~p@;ulKswCIH;tJ^{vO(- z?dMkFPiutO%WgEWv)WE}@f}Qk=_tT&5aqu2fKXpQ9h*b$Cl#}|gQ-cI9}cGc_n25c zz4bd)h?jcXU=;z*^?T8MU-XsF{!rNuS%~6?_hA3|BOCpq%K_-N_YoNUJRJ77vteqe zV(zsD4wOM)1~{sHm|`A(Tq3YCLjR=<SG(f$rri>|;Y4*^$-Z9aWVutU*C`d_m=6<? zO$WGYBY07CW#z#tn_{K2RpW9Y)-Bz9l`eK4`)BQvmomTRSFaKd2h|<mwJ^{*tXP>> zfft)Ib~>G%wzShmY_*WmqO7E*dy8795mEK0Hjq)N`+f5eK>BoQ`H^T%9O9LFgA70_ zvC8uj=4P{XVlOh1SBgzpPpkqXYk3`N6%3d>C<F0&+ujh<RZcGu>PR~t6aT^^K)x~# zbFuW1-L}o?gk8L%pz{+c!&};Mj!|-Gm7XgeY;Cd=?8lX7GOb}HIRpk4J!AksyqG79 zo-MOL4RZK89H!m3=<5>;hrhDVfluk@XZ|q5C3iSeA{`r^oVODFr0zaDao;<3?uMPf z-!A^;a2Xv5S>PgC5&_M+NPgx?_9BLom7+?W^wTR_;*!4Eq@a+<!{;66qNROu<Q=FP zD^<0gXqn{PS;AK!QHc<RG%Sk4O7d?ETsdN0=q1&5^{U~KM#8OjK6UkSm6|3i6olbW z$QD(H_X+5J0&;`8sMjD<b??4h(!$rhbs@+=z-j8Bc1f`cXOAxA^KBN~lY+dirBZ9W z?P8=cH8Tu&YeDIXe#BVs!48HS+>q{mIn(?pK^M_8O50rwq46fRWu2MgA(no@M+1*o zKQ09}0VaNMS>pgMFN_P+Qj|&2aIa}Eg;mRUGufOE$x&jW8op`-pY*a3H!YX0v?Nou zmUO`3Qa*WHLvV&tejjBG^8@-^<SY7(TPA1}Srd%UNAg9$;t#g{*+udIIY7q0-#qmL zGk-Yk2TueDrYK@VNdiL<irW4{uni-3n*<yqx4d)1NDTYbBnjFHWf;8U6`1a0#u&I$ zy`eWJ41C)<hQU6YjBZGYeQuZ#?B0%Fh}+mZ?b}Tf(zjY1@@9xZyEw&`{~_d?{T;k% z<k7#NUzKM!q$S^^^WA0}+6|N7_o#AA?ekvgd+vCHT<W{IuDu-|@5{EQOyAlX`y?{> zc5Qk~dVEph-RGLAe*{Ql@0#B~<SuTya+otMxXVN@t6VLdr<@Kx1<1W?{%1*2`BsvQ zh0`FNv<)<{JQnR`gD@*<>~-J&!v%evR@(m1$mB}hw7*Nkq*M0I=V-&Ra#cBL!!_x3 zvA>Nj@5lJv1L>vNU%KW$j90zk$kq4U&fM<i>ACs_Mb<Z|i|huIPgRfR(^mur_!;9Z z=+Acg&DfHpf3PL`9;N_VJ50DA-&jd=NA*?sX>iM)tGInfAFA4ggw}9r6w|YwS;c{C zRm7K-r+SpE+I;Zn1$eBOw7~B3sHr&zyM{8B%N<=S3Q1<Zc|ujh$}L{wgsVQc98gf( zOOdv%rK+IbUicokoGXmIi<EVSX+J(7mUH2jiz0bRclJDSu<9q)KIOAe6se(H5>9L7 z`yF-9IT1@56#}oKSNa8~A_Y0IueK^heR;WK->;^lO3e{-GBbg0=S2&i#Ho+U9Hsp8 zMSYEj<6@m=fMEOuGQ#0<valP)kw-m`Zdbv@DJQ5=Fn*40^^8IfA$gm=_Yb%xUe|(v zT)K#^TEGE8a=X>9vLB1eMGqELW5=1Uz;7_csyzLxyzlbG;PCq-@n=0P)o6x5C(fdX z!-vzk6y4*Cv9sJOZ{Lsy_$&0VccECq)67J@zGd2ihg=>9?zK|qd9Jg{U}BW2d|i_c zoQYFFQ9iSnIbL{4iDIUW(=H2;XfO>z&Gd_*<Izf{fg1)-_kc}EW{xmIb3GLC^+Z11 z2S87vPPc=<U^m<?@4UcZo?w#+T|H**D!lfr!SRA~_^frx3zfs8s#U!69g--zm%jo! zIXqUmo;C1(MIrx8MdXzer6niBSwD|vR6`tP_)=ZT%?K5bV;#ehdk?ulc210n0Wv3? z+CF1<BUdzrZVWNAtWVQ8tlvF(a3<+4^Uu&oec^mC!R78aAnq<N8wvYY=(WHlByC?` zC8|lBAnUbwp0@XR;O|))Dxs$k9n5N`b^Co;i@6wv9V-41+MSwA|M9>65OzuSKOdll zpCvAS^PCUn^QY^7sBR+YuHJ%SI7EUtwLuX1DKBf=lDB<#+l=>uB(x6)Z@Ekwytz~H z+dnVewI!l>Pp&BBbA%!HL~TP4@-1|Me1WL&o%d{)f9GGj<T~~)cBZ>T611yd>{Z3j z5oYfp#(Nr-P`j9EitU5V8|Wd)+nbNvn|@ouxZw=)ZZB@IwF`*`J3D%(K$CAaHoBwO z{xh^sIPHFX*xu)){!u^l^xP2!|3Da-K997>Um>?V%%25*pQv|g(oY3JGlr`*f_9Wa zvzryY#IFUQcdf6|kigYe3$7X<EEq9_-+W?5V!>?tbpF}P<0MGsHpJmn=u0o}r(<{K z^m7u(8QhOapoPTUmhimMX3O0~RsR|!zYC?l34DL6I!wKZr8k2fB|ciV_lK4KQpf#T zb<EyXM;3UO9W$PO9L#6h4kee%&)%lTQ+XrGPL7sG9_O;m@=H(pcEa8`%#~H>RxDOO z!bcJy@GT-`$Ss#?&8j8u{K0D-n!W2}By{NQt`JYED#oK7E$7*eQm&ROjshvW?N+$Q z4nP?8j3{m(!_p9JX<B~mc^Hxgaz>kY9v{<-pQ5Hn&trDL@(gi`ZaKtVQOb(F<cA2r zLzPs>X{Ghc(HV}+c<Z)I42Eh)H=hdY4Dhj#n?%1~n1ZL3RHF|i<V&j+<A;0L^FUJ5 z<Q6Wb%3)2Aj6a4YQdv@X9+l&$^W15vdKDg}N2=VPQ@`bHeS7I*@?<??`?bh1pw_)x zZFw_HHeq7=L~eG<%U0xrVK$AMY_~(%qGG=SW76ruT!tmI0;=Wh#AVna9s!k0Zpzb0 zPMnsU^6jej6Ixb7E+-+D+e6M!rZ6=54W4I}MdtIJ7u{#l#CPeAv>?0y>acnz>Y<G! zRyVOpxzmBFR<w(g_|U<!_gE~jvqbS4&YGpRTNY1BPJXZ>BrhhMT7Z*KUb@8MxTd(s zMb46RboL7R=C51Q+Lzo)-_WEECrP?McfND(9Zw%6EXqb)YSn821Oi6g6Ou$67j%P{ zPAmrf=sTx^kJ!US0?#~n@w!xH=tXxn4E#Wn!$>Ub%LQA?mkMOk7L>qjAdUx^EVG1r zbQfEIJ@g_JLN6nhdgMLqJm{}_`^EW>b>Kgo1s}UoKyQBHF?{>Iny$0h1W@&QWw|(d zNw0Jw_zBKE8uEhvrKY<t{%kF<FV?fKilrPmUrm}|vMS5n8{^#g_fYfsP7go03+Z0= z&7u%EBXSi9)Vf8P+h@LfMqj@F>;C<J7f6iHr?TF}FE+se6w^sEAZR2{Yb?Iolx@t} z(I8eEJtg2Fjh$e+UUDa$UQ5Dd9Bhn*Ftga<Qe|tjUI5E`h!%HxqE>ehSgLbEkMbq{ zfua{4D-`kGAQ_P<z87W*b<Q3Ivwe<K=~b?UqXq#6Tp;y0FNSGXV^==c(;N;ceYp-N zyhaf<CTZ`Is%3&(g#?PGjI(yoq^t$^CUk}emIcDOC-|WdjV00#Iy$~E_1KJKD%Ya{ z8@NL1rl3op-G|9>it$=_;?HwBO7SZ_JP*qR2v@7OQX0$U#0~{CoR^7@w}3|uX+@@v zsXI#83fk1IoYG;LlUL-&OJ(7${OaoV7ytyJ%vbp!hK%&^UD~$pd?2gTq#D{yL|@nY za^+(FbQe!fd(yxIdOF?KBOj_K?@~UtmypK=w=CPYmxWO|wypM&33v}19cyH>7eGd? z_1o|1$wGl`tJ9?($9`0T1qOL3FJc6s;6A(6^A-jZZfw&_Ih<2vr3*vbwth3K+`#Ny z|0q<Vd(%^JuE5K+R0idR`m4ux9dM5ED$ybVuKUDTG2~Lvrj&`d2`&;3W*(Xap0|xR zzecQyisXHOoH5$Ii~7_Ur{`e?e3fUKXQQ-2?{UM?^RCilg!l6H<WWrz!9~EX6nb*- zbAO+T%k-F_i9XQmWo6()K90aGBAFqn(Zvb34JuqOy$+IPSvq7rgQt|)HAzuFmH&fq z%_yoVdHlNp+drN4*O2YUGrkYnFaiV-5&<y;f(VSFFdX?TX4}Qn@qY!-p4Suco@8%7 zq|u&gN8nC(BCvNmn%rBv(C0DRmYfH{UgZ9wSD7R`i7E>Bj_*$0O7>`N_f|~z^gadm zI`<YELfbQhzlhnww{asH@8*bMxQA_Fu-D>4{LS!x54CN<7()CDh4*s$URnqD5RRhu zdG@`Xp6+D|@I8E&#QRNb;o}xlZt+|E&oSGy7i#ej&3DOsP1YGQh%-2RuKoTUc^!C* zzk}J2wdT{GG1)%8rGGa?OTSd_`zQ+7%Lk$8?|#dFMoJ%*Z+g*88dX;b)T(#o`{!db zp#Q|B|99^O_#vqK>~8)cZrk5P_FLTcx(Z@SX{ee;=#t*K+PaXhV?t_&_!5QP`HtJG zXuqDdf^s&Fq8g}9z-a~3Ma5cPJ)w`h<dheOpT(M^o&^@1E1S%8zFQmYNE>Hy5(?8u zG0%PC<H0F-B76XzN!&tBtPjU7A#@mQdKz+Y!B~#Ww(H?1HnR@cSf0`HKp?V(9A&Xn z?^XfoByJYT31~vvuDEmH-5}9)81~W0A}(oxb-H&&`^4Npj1a$4#MN(};JwTU55d6< zf6P>Ke?=mI)22ee?JK8DdYo!2a>vF$7jS8HYyw+PRcKYp=blv(E~|GQ;NYYX*I+RY z_9;*N5lCc}KX(fonnCyCPNj$j9J@R~?be}-?OtyoBjP5T)*+VnbihB29Cz2dFW@CQ zNZJvINRhjMS)XNOUK4k<=Ugslp4_nFhfcOT+U#Xo%y>9zz*?^#c7ufl>R~5eD0z04 z0kvha0lU)5!}C}SI^3;h;rZ@(h;8Bgs*QFF<>Y=L?%Y~)kC(_$uhmLVv(J*!A=E`c zG?_uaw4H`JMj!-aw%!lPT0TLDo5kapc;}$&rnb4ILMVvmh4OUJ7^>!VGM<KDrodf0 zJqHHK8I+X7u8yLlQenkK^p}*z+DUKPaGiVUext_~2A?&CsKQ+pGCVr@4?e^JtT>`8 zB1C!(V=u<hE@H{))_r=N5SP8+;>A#eAp@@te?_98lFk#-Lpk{ow*h<L_TR*9zzOHH zInkN%-h~%(JT)O0&D|Z(tL!gv+h=QmZ;SsXZsYzgZUf%l(*H%=2GHVF$P&5%3-F4{ z){J%?lS1_1LR8@ewGh;$$BDWORWOg2Cqob@?_o2JBs_%4$UDH1#i-PIs5jeqV*1LH z2~R|*Q|UB*`WVq@;011ZT<)m7MITGH-k#{isGOXWFZpAjfEWAlp%=9f6Q;L@%nUBi zdas@x1m)pYks(sYGvYeiy9i;WG>7PktC72SsKs%1apwlW3WCxPe*$4HzHPzV%Y?^E z)2Bk-iKSbv&-NUtb;(sVni@yub$n_~)U&S%TF%(D_W@~0_^1BVwv6IP7;d)04na9Q zPf%boR2?H#ecnLefS)Eg3`&&~i{4Xx=RThTPAEtq(5vkeNFA!#Ilhvzv~0qHtkERm z^6uO{&JV5(jYEuj)dT@`ZV%XjpinGN)riJA>~2XQ<o8B@O(=rP(ehSX)taaoHQ78A zvk#keu})Ze;zEGcQ|^MRE9a#Uh(xwJW_;6um>&CMHgHEpvu(6F7{l}FyrR=`RWxZm znHNnOgZqJfdY}|cadLC@=lnVy7<}$LnLh#-wR3qIrd0MQc8SllTK{CcBxn`A3is-O zRO3(Wg3a<pQLnv*`Q77mJ6(MI5qOn%0CGC7!Qlp{L3H4+i-c+hjonzPpR^0pYj`kK zMf6l<^Y9G0jK7oqfk?GA3K_wb!}9`+f@*=8*Zb(gQ4!HIR1pL@F<^90DCPQK9U5DQ zu7FwW_bqvZr2W!`xju?Icr1S-?Dw&B7aRB~kozw#^C1ZIo0s^3G65453Bx#sL0ce2 z;Rphw2!xOzjv_ckLfeDe|33@<wg?G+2Txy!@gTX^+xDOe*+Zxp{2CE%M-u#B;pc`w z2)sK6LD1elg2KJ66q0YD0QfDc4)6c%a<lQ?mf4<=dOyQ%jQuO};r8(EgZ&OnBWyQ! zOoE*Nu?3*Jnh>;ig?7Kl=q*wRy>-yv{)}+2*Z8*kNZz8gNw|lG5VhY>{8mrjUeRwT zpr?C#qc%QTLV~hD!31?<Zs8uhOz`yJ+s_&M-e;T%M`do`%4M1k+tasZ%+K09Tj<pS z-!HI4xeJ}svP-4>y*AIEd_zFJM?Vk_-%_`xx2UUyX=W9ur|d6;Lsj?Y(-#+O1>k2$ z^d0J3*Xm~x7j74E`R?)Cb_b*9%GkGgP~dm1u7AZb1m0HHkIYVvM=KSf=HY2&LguWs zASu<}BuNmREja5Ne)n;t;G=IJ)|#K6$QI$u3I)(ks1UiMg*ZPqXE@J&+`3GfQ_%El zrS8w5^H?|mx%+j5!X)jVC(B{<AfPTxGI)0y@FhDsS+MjX5*!uX?s2oICQ4-E!V-#_ zaj40f{s}YYQ#DI>+byKWtGe|ZM9i;f=0Si+C?QIi2i<2-R6pGs4zuO;!dxl~m<>zy z`CK;+S7=?tAS4Qv<Kf_w@fbrTamNq`C>h6^cnRcH9y^45b8QHxXx!7#9~=-rC-uSb zrUuDzPZ-DgNJ29apqw#tdWT>KRRZb@<sG_(AJ<@-$HM?lw;R(iFYWe~WC%+0jr#@h zp8jgH@{{H74}r~D+dd6`WEV&Fs@12^n8pX}H?oR-X&nNe@&-@coGxoTuKJboe7!e< zgFzHM>GB#Ph+=zbL9yu&ZoWYP&L-DTW{;)rmHHi1%mICzM(b?l2r0rzL6_FcB#HHq zU7Ey)%wTK+Z+)PdmYQ`UQ~(+hmhB3jX7-2j&_5rRvXsIxJF+KDbJVr48m9&c<+Y_E z?2SX<A)RVR@na&er3zPoR++%3Sa{1l^XsTun&z$<_%aCrv+@N(&ZU57z8IXU_B9@B zF!E@_kgFwvI^QBscfi^{VjbBSmzz8vp6u&ZdtKj+I$<)Fl<O%R4Dp;87J0ox$}#Pi zCKsSbp&tWJQ(mnF&?ZikypmP7I0+*}HE{iO4+aB2UlZr)Wa%ZlN;wqZcKQ3f!7&f! zG5G+QKY4v$9{5vA=STSYkg?^8sTj5+$Nwk#fB%3%5dY(c6aUvAr}ptj@CB^aB>v+$ zB!9F`wfqE_|3BWwH^BY;7QTm9oWfuV+F+D|L1h1f;W)hW{1JjA2neQ7kODu2*A1bf z;7zv(cVCVu*_%({+uS3F-Wu+~4x9nGmsg<A2jVE`O>lTuRgh$_V0;l8BGDb?P;zgp zQPf*@;H^E6M|+8b2>(U?svou+;=%hEz_xBf`DnY1clCsz_FBn?tq8uCU8wiiKnU+w zq~1L<ir5!~Z<W98=C@}}(RZH=-8*$;xQhf)|42#X--7V-pHjOTPuTXt*+lY^DfW2L zsNoU*N@}+^|0;X(LuEtMThEO_-}unjX;s$y#_3CePqcK*4O-zhMR8&H!1cQb-j3gS z^s9pCe&VDEYPTB_?@E2U(N-QKdi71>?A=(asYMb#Fd6rqTNb-oB?;7X3*tXIbilhs z*L=Ip@8I*hxwY@6?T{a*?YtS#RvuRGDs(Zew?6N``<?(lzbXIjdjkCYru@6_3Gnlq z@;mRz_nN-IKg{wC?Uf_4Q)4x1Qmz=BJFY78yrpu+>ls{61K@!9|6%UEwjI^dF2Q@A zBJb7J!kZkUFYrbf;RSbi2`7gH;^~{k-aG7$6LC&v{Z%<4<0vFygwUFwnctjeH)yae zd!OY@!%BLz_1K3ME4_Jk*DK}@f5jQf-U<!joszo?hNHQDZEL4=Gb9k^$mUMFWJis) ziwb3OIeI4bsltcAcdUEP5w!B?whyvIEdJFa`|}b}mU6ZvU|D(Y8i?E}Q5O2<8IdUJ zHoI!anvdX-W7LiIgS&nsPA}4>E}V5d9U1)gGIMM6r$!lo9qWmN+-AE=*eqXy#oaXc z&nBDb?4V{-#`WZ^Gp|_7TJtK6+GFcu@Qp8BqmRY1MKA7)!8ORdIvA=v6kqg$eTQF? z@=myJRPag27BD-Io2ox%{U$1r4bi_2N*?APaszhFvCywHdVgkA{^(fjP$7KSLpPez zizhra$IEqinlg#xs{ff>*!y^1;V7(2S<djBM=~sZNC*k(*&fafqg(8}9ne!aDnY3$ z^#whP^W9g{bF8SwW!Fy+^%)}PC5fN))?Rj$Gu;eD8g`SJgOfIncugXXl7f?RDDZ<y zsP5sFSxDyGcF1hv__L5+b|RK>Bn#b^%^3B>9-wKTg=FSM*|S$OY%Zk}9b7$%NlpcN zE{5cBsY;|U&6vIBB7HnQo<5<d1^LhsO6|8Ow7pJjQG|C<rkQ#gi2VE%P0BdRs@Iy8 zaEo4i{3!a3F}jqUEtmb-ipz6Fl@UD5L|aH#QZFK=7>hO?Zj+VXD42c;l$n|tW4lLr zRN9mm@mBdIug${aGI6<yGnwT+8*a~0P#q*j!v2l<ykLRGwf*p>m52Rn|45g-{kM7V z|N56qEa?8R`B!}ZvctFJ*DQwdd~3eK`VU+DX?*d2^Lc&*ApglZepdy+V2mPh93d%! zq+x<)C>SBZP$IrOL6HcI;KZl2oh$`<!NoeMKvE#eC|0rkvH(mQf?9c&7>EGMC0@xs z4O8#}<orw8PSIe#f=Pj*VO9c4C_w{OO_GDwP`b{}FRw1g!Es<2Q2c6g0;ngJAnm7$ zb#!nIl4y9%;nzXLCEI7#fsa*|c#TWe{twN(izP0xSGkG~BrAUh5J~ZO|D62yVG0aL zkksRA6~MeX{V8Theb}i%ZO-zY`g{a&2~%F5NalYfelC#Q#_fV}Yk%d7PU=_Uj1GxY z94-)idGFAC<l0tzaIh59ZiaUrE%trXViwQQtEqsJn|b2a?Vz^}--DnN=-R~3?8F^E zbOQ@8E&pyhnsyUm`2J{rB>3|bLf;(yL#B0BB@T(Y=@Pwu&ia2$`k{}k|BZFze-qQN z_>VEok0A}Xem~D{{EZ6;t{?QDT)=no)IYy~-+T-I>;i)82Yq`1|Awi-Q(JD?-QkQt zea9NtN3L5im6iHPJI;&RZG_Fv)`?&|)v@Xa+V(KrvT8a7@QLKF*GsdT>+OjM(qe)J z_%UzK%!WhCI|c94xKo2DV=5u>BJ5dLBdV(V!1hSE--UrIX%GKaPmhw^hQ}sTXUNTu zLbQY&F0<Q{3g>vatR;u1lI@cj<1`q>hTKI`uf5ShPRb**Q(O8<XHAzyL}|+qXKn09 zVY7q@lY`T5+1m}?TU2%0+_BSUURJsJ#XMQ&#vn-J8L{F_><hCS*_A!i@ix$nzqk{= z4LGrH>d;h9!gQ&Cm=6Wt%4RFI32ybd=h!sYXB)%k6{_76%={3H-HgCn$W)8)^dLNv z_k%B{2B|t$3H_I}+>dq<^wBR$zxB<vM=|oa@*JR5ICHTfWn<t(S`s4181;cvXlL+C zE-<qS#8v)Hs0?1NY`@+dJo%j5>xj6G^oC6aN0s@Bl3je%oT&bw>gcQ9DE$DcY0HhY zGVtD9c(Hg+Wu{MGM4yB|kcE}47bhi;6)%bwSdE4aVpHv&kTHw%ujf>FPZQ7M0oC^? zca8KJyJA{1JP##$IW#BBnnmbBa=3U!PC^rmv2o~IG#Wa#-5i!XW#*49UCCFTyC~SR zCrV9Ac)6*ByxF87P75IwK}3}}Hg_U6#u5TE19yG!p=$JI%=vhgbv||7i97r5r8t!e zCfu^aqd85j2saYRh3yUsMW%Z7B%f4w{(ABcR(eRwO(DkaH8|Z+8EZ*SIvay%%*8f2 z@w*N_D<iB=)}fbAQ4Haw?W7ZrwB-yG=w2vI=6-;mhYKme$n$wQAd;=@tYIXUZ!4vY zIZ(6olxz4?j04()j(w6j$_;IU89jKaYLJdU9II_2%`dyTN|xjb2Sz#T``um4lQR{X z*FR^U05759eVk-<w)^&p^X+oJtwF?(^pii|>^tMtFPr?J9>g#dg)iX;f)Xf2Q8bN_ zC`By62#%5@O`<S{emcLIf!PjVXuA5}p=;!ktu&7%7GZKwX+ZOJG!p%lFA+@v^V96D zrGW#AF1F5%<ZC&DLBRup0TB+BgZLv~wF%1d-^j0uB})L2A**!IN^nV5N(pdC!d62A z2F$;t85l-c4h%f;Fc8|L#QXUJ$_l<($*yCbWd<4)<!WL?<o~9AE9xjbK(XY?e^n3K z^VWf_!b^hi<yN?9(=moW*H>0Q>qRV!7yi+UIJ|rCv|ooqm{+!-&N~WC(6_THLi=Xy z69>*~$>Dz-#{>{g05Krz&1H`;yk+fQULZ_?MZm0z`-x)hSBZkNCm}x_;0a|t_sqJt zj>oriE8_U!&>DQ1uK8@b68hzM<?hi`MHtNG0hLsW_vo9C_opD#CJwjJ*yinn6^k<z zKe`PbS<k3_X>d6<Au7)}Cpxw>=IN8iAKSXP;4*n>YPp|K=6NPB3mW3B1z+UBwIH}M za(2TELYQR%lgYR2rZOdN-O#9YSvTYnw0;~@ffu)q^Q`>CURMv59H%9!&T4Xo#*m)u zZgTfst<zJpg!vCemJ(LGdp2fpPmCd}@gjz2*>+smrIlyeZ@PUEUnlgU$TdU>iJvGJ z?4m2ZaN2OiV~1qt^m*<cI?ZlV7-_bTen&gJo8g!>GbD4+VYTa%7JgKm3(?Kf^s!0d z=R^{^<icxNXi6m)KMNM$AY)(@9?s)uDd?2P?f!*3(R)1C)vUL`R|8lHA{(ig#H!2p zkBh8mu(tPu1M4sJ4WJ)M6?VNtrRQ1PmPGDiH(^`mhRq>~P12*ut~)3>VEQw!rau*= zMc)FW`AT`>-SH=Y-)^8c(;pvkJ~jP;zPkSW<bm<ExgiLH2j7mNaB;Ktfn2U;EAJA@ z_XZ3iW9$kOOood=Ta4H)+-Re(?|ja2A8uBdww<{d;cNunIBwI?E>YGFdmZUm@=odP z7Qzmf=OH&TX1`GvJmar+FunBRu05*9pib8<reqIYDZ6x{)xf?H(&_X-vdis4Ud~g~ zK?2b{cwKmI!+zg6XRR)*zJEP6vvw#=H*rt%4;MD-lv~{RbzDYr8TW=S<?OSMUwaqg z_b-)9NWI*MBO~OSZ5F-I6IwV+D4$xmf(<IXHTA8%k99_lWv+EQx>k45D;g8x=|Gq| zD36CsAfaxbuL2y80lo{3BptnQW5mXpxK1YJnuL4Ql^DN|x8wO~!8}!qf5QuQMW=7v z^Zp(Z{^5q-W8v40z8lu0fCdl=<nu5DCJ=(aQ4B?vl$>6Yagw2Eg85X;V8N_%HO>KO zg98HN0*_02i;y6@Uf>ZxO#-xw!CcJesz6u*AdXr&m<x0PYjSuMO2&aR-hxK>o0i?` z-<RPaRWH}68st~3OdJK0d0>DB2k%=_@&(_389@rV{R^a`@M?dKfXPy9)j}>)Km=Vr z0+IoeDF9LuH1C1UIs(otU$Hn@KHcwUHJ>XOer?Pzxzy=m)&A++nhdvB>3w~@eBPMf z{pVo#RdZ)SHR&Cz+;2?jzN_1Vo_hluwTi#llsBL;4@3$YWJxoDiNNmfo)PrpDgDVA z{hg}$({!omCQm_P#}nb0=VejYqsDl2w)GSVCk;B;`^&Sq6i#bsm^35dqsAQf%#*Wp zL|)D88I)48XRNF?q;aW_N?bf^y3AhQDWsWu0&OK_NQ~4@uMVx5^25HLLSHr>_?|$v zms5X$n@3w1gn_!2a&^ka)cU=y$J<6Gf+W+Rx>qIT{LCFS<n4jeMh>ZHQ#|O};l^AK zTyxz^<26$w7O6On4~rNNO)I$!&vWZ|y$UJafoQhjl@9c*i!0_5MTsEz^JY0P$3}r7 z$Sg&kqlDI$SoUUZJflL&kV$G|sBDjd?$Ye{yZ!0FVfEG5kVF6U^9@Y|`c31HRVrRu zO~;S=l5d{i!@jSvi}2M64<4Z^KL3#w-rv(A*fAn!Xk6Kx1Qf;z_A%d&%B`F4U1JFL zhZEjl@b?kgC2W7@Ls><?x5CTb@3{Q!j(bZM5mQ-iq(_8lcLSWRdzY7}%I2y%3zq+a z;y(Kq?zpvF9oaH*3V%c}RJlGtMg{p!Bv8|lep%KtX-}Rc^UnS3Whar`SkalJHwk|V zV9unho3^t9;i4j8a}f^>aoF?+3sT_Pik~)Z^NHKZV@jPIS>TG<zaG*{EIadDdg&(X zdEsKo4ozN=V<yoIvB#gyg)urvCE!j#j+d>NZ|(zco(OBZ^BEyIIA{z%_Z&WV?6W}d z)DZ^%K1kY@!1%~~lChGrX#|~2k=%K_I1egO$!dBv@`IaB*C3F3$-iz)yKIm{7@1fz zO6L92hqIJqlM*EA$k0;;m9#E&+;sDf2}@!ZJodvA%Uz#Kyd1=Wqdv49L8p$rE495k zZIg62mX4+5Dt2^2It%|85P8e61nV!@XdiE2|D~V0(@^9;0OLQ}!3RM8^~T?;=;0W# zz$8ZEG>S6|R5JLIPSONSFMrV(j*~b+eLBYQ=BvJdWVwz6P$&Qyf&>*}APbPK_BP0e z(fQ}%1|$h8;0vZM7*?+0Jj`0vUb4KL03tlVUT@VjNLP>pRJR;R{ZqdJ%w+>~l_OZ- zx_p!GDgT{dph~?!da-7<2m<QaAXiKQhmBeb*ySozgwX#k8L$<-8tlTv>fye&+CfR1 z{A~?e0U6QwWsJf0&f;?QwH9aZOGt$yY?HS8U%J}<Xp0W3lRUHW8{#alHu)<KB{)8) zl@|iFn`4_{PMg)D{lOm+xyev`RJz9<^NIyAF}Ugj-y9oeOb>SU>u9PtUDB|H<ItY8 znQgyx%9Y04dp;w2uRo^1y@2C4s4heA6gc3f_gZq(uM{{{=6*n5#jeHF;NCti&l#?R zX)SOy0CNu}5F<+DB}<Tlm*KE)4Nluu#4-1xaOzS_YYgW+%It?2gd}({vWFaz1~6QC zayu+5OS@cy-r)TYx?l0lHTdf)`k!*=K$jF2dHsaxb>loS$j`(yVBH8NyX{ycyMy;o zHq=9%E3DRMT5g~GX&3PEZMakCpcr#Wn&txG8z14e*99<9`6}nIONC)_@FfyP_-S;E zZDJAupLpXqDe~+;*`t>z(W7o@MI&oX!(P>tMAu_XLpE^_LaKO}nzBJ;wUfmp*>9fQ zrj+eq^SBoks-u`XCS4lfVp3=3bVf^Bbk!EaZifrBLG!^bI@(I%7aFQOoyzBZh-1B_ zKJmdiY3HZ>kOJXkiS_<^a5bU5I^>;2cJh364;x7EHocPGyyaTx7xQ|zEGF=ITZ;X} zGevr+6HG>UF^137jtixU!%T&U&arrdMK2>PsNV(ZO}}@{hd>`LTgy$Pf8W%$_0S6S zsTl*4bl9uMU(}RP%=QvOKUReQdVqk_-bi`02-@t1KvvLx$CAhTc+M4Pv`+LB!0}4k z51A%K&Ep$|pIPrZM`V8btw7%rF_$;L(!Xf4?=PpK+eRswXT*S=9?C(DAUC%ZLbR4x zZ>wFO;dv;SpyVYtF8e?zq&p*!MuS<7Ug@G&<x@)YdrKD8D@Sttoqa+o&u}L~$y_m{ z=`1ZCeS9<Miq#kN_bjaMvyIyB>3NjWv!+Jf!>n-2q^}7ByR(sPA!o{s^IetOst?gE zzTJy4havSTsA$@v#jKeRu_f*9)V;pzHD|R#2x}ap7jmD_m5M{N7P!rpTVm}lQ{_^m zo}C_`3f%NDv&UUCNXs*k%mH2cad3^34Z&tNVt*r?*^h}lUsfb?!{b&b;TB<VyK3@` zfJ+;5LuXR{*hlUeqfM@;r;~Vo)|_NGlv3zK6nUq+wPfv3Z2yfm`+Ix&U+%em0MxvH z1ER%u`1|ua_5WA@fB7E?>i?A;e&G5a?(92&N601VWsoHkMj0THyZl)&pCSknqe&V; zahh75__RE{_MjIKUQ%FS^_~FKMDn%5ih#l}LxOq1B^zA;^%pw16b=w}!QTv99eNi0 z#z0cMq@;KXBmx09Jp&AL5(oZ!!19(@E$EA1S?v)3s+XW($%~i$E@>>4tml~l(F@>u zO99&;WOedMR?WX9WS~}UUxorXKD-_*MZuW?JD>!-VL26m_rIsA6F^(yPJRLSfWFTu zt!2_9R-|KDH-dD=KQ9lTKFf%|bN2MQ0M3_`GkI}dicZK%4eO1{;|W7=j0Z3Y8TAiM z+*kgkx2j6ZTBHQ)x|98Y+e?1>#k&sr>bn;KAF}DYw(ycNuNm`~wlH`4@r<Frd&)na zG4yv&`A2j4-=x$+^HfOJkTDrm@f%Mq0n~%-+kq-J<=KVjafUL=5Or#rYAY;<lUD6p zCZDT*TUBG)wURBL5)I3P<H6}Ov7!h5stE_Dv`tN|$bP?vEPj-=swJ~$N&140kC(ld zBx*f3@-$mspv<Xrs&9BL?@yA{UML&$O7wYtu>00SZ!Ofx=EY^hjsB$P;n5w!u*c)6 zdo-vVI^4m_ZtV6cUl>X}ZtKjtU3>B7qb=vpE^^m<3F4}ocoz?d9UzaBA5eSm-qlO& zN#wdyrmBPNhsZeXlFI0_tvz2#1Q%Kwr&!KaG>pZeYeYQmuN>_prQ!<Xc%5#+(N*bP z8Ya>`WUqUdN@jkq!x4YJiH7<Ryss&B22yJK`)rsO$5**T05BP$=i<5>_+GzBtdZo# zX9DyP_bUZ@NqtY99o-O{(E%Mo(UR>SOyr>y)R9r<o?+(w9gDyG9{lC`d=2V|`FpNq z@ZE3WEyw<KkCnPL&wfD4TS=aWVTn<W;f*79eoj~!4Uwf2$A<zbmPoU9eH2%&2feP@ z0Of^_O@y9m(V`=4T)(RNev)SHG<I>|2#+y;sPz^)B5YPIz=;bx_DQn3L)U^)Y~py{ zvEGy&3wyd8OrkJ%I6t`Q)i;@~Ec^FYsnvMWDA2Z_CI!9EntU#}GLx2Q|0*tUcIXuS zcB;MdzJue7*d6Bap-EdkWVg4S^?HhNI%CT4gvMQ=(yfWzQLeaM@iSWc_jGn7_>~^9 z$CP@n{3i7;##utA>Sk$$li8VvkmqA;F}7kt7kO%vouuXMB)swyZFc$n61xauyoe=a zL4uP~pvL~Tp&v~ozQ!QotL2Kl{%$HQ^8A0EPXGO#{E$-r#SXqR+CvD6M(G7%DVSaW z7+t^?42q%1N)n?OjE0#{nPEWkXjN?jZnindjtLA5ijg$%y?tYQB?+h^FIhAC3vqyT zYrFvB0Kh>nUv1}C3BqN6OL|Pe>$n&RD$#VYLivi&zwF5(D<h3T0oE?ijjX193z{x@ zbCLs=J-Qm`g3j(bXqK)_c5u7|80aRezszzT=sHHWKzN>lb6WC!usQWR(B)4ctFFE} zx+rk*yml&^Nu2Moa?znyysOzAS5*t>*47>r$!4BAdOwhw{%%J7rY`UgGHTET`=U9h ze$A*Q8#eyX7`GaYnML2T>JQ@9@}wu?-x9Zue^4}le)k!F_YtArea7E?MCixQnAfb$ zRoVO3rE-97Q`t7FR_2LaVBEp(&phjRDLPPj;X05sxVPxiBl}j>xjVtJ%I1LE=Vs5r z9A_<2?HShEajx>hBR5#F+dX|D67T3~ifZW!Yfx4?JBB~n!=6+X8Q-Qn{p5o-y##mN zAo|ldquM4s-ziG>xJS40t$(ybL9!%Uf|HK!W9(}CW!V~zniIWO{K2?7^bJ|*`&)H1 z&%k_$twoj^&9u0_u!6n32D~n}R3J-iv)f#S4l3<hURHWW-W}(so9-g^mCu*1oRM*F zSn@^^lq*}aKBF15n`Cow;bez0>(a4O@0LFyStwY4OXaG?B3+$2(<l?fFz57^&UN7& z22AH#dGzNAlcl<z_^(iPi(T>h&aOjd-}-qUuYsAO^W}9rRmb69@AO?_`?kGwe)Rd< zdMft$`F8(l0sr55oR2mBH^=yPfnOGOgr+HqrVs?f5Q15jbC`w+f?yDYMlk}XG33*% zD$T%n4}pMj*@Ob*6hL4h!GO`SrY=h(g#zlzvQjR~?JpGjmaGLuL36KI8+yf?xZay< z_-agoF`#COli*JZgQn!NOBkrM{Ho8ms?nfp5(KKP_&P>K0^%;95wC?*dNmb8i&f=? z0?YrB8)mCB*s_oV$f5xhfTWHDX&$g4p@0}|`CIiDfd&iw(0y6pZ4Y@(Tj!?Wl2De4 zyOX@K`xW)~RR65KA_{N6M?iDokX-Z8K#vd2H!I_PSsBe|rnD~zh@j^@`<0REE$IgT z#U?!V;MNO79}L$ZY3F>b+0yd(ne}E1ElcK?@t!58DnB*|mjA~7&=&4bmL-bq0{+Zf z2^BIyxzrOUvu0;gaNeef=P%C@rYC_C>W>XfAPxAn^1Ce7%9kU0-_%wo!?jUnEDqWw zMvt({AM2gV0w;9DaMe*|BLRA&@V0w5Fn!16<P-}YvHVf>1&^6mh6at{R-^XCm4*3u z{{dPav@RMDKYN|z+-H6#KbBLWZ|kWqcr&xwoiPWDfc^HGOq`}{=4eOh@<!NkJKqXC z?HsEwF>rFKesPln1;OLdY$|N~8g69nU7x30ewD-<f~G<gOci^tk-66>Yk9xd`D%AZ zo8;JYY&y)Bp+upP!OZ8*)rYt}K3Ms5W*ie)R?{ZI@PR!}@s1g3XS$WoRLBXq$*^Z5 zsPhr^(qk9hC8)EXgX4+X>#nlsHh-P9<l08ds(mle=wO(6mlzoLfFp8OmW1IMd-<p_ z&v^Tqf|Dj!5H8Znoj)#_ca^rVYn^hel2EGOJvMvGK2Jwgk8IA-^!~D>A>{@~J!1^o z$$gE-3o<Ye&S8#zmeY|ro*4=aWpWztPUQ2<P(55ggMBZjBI4-HKU0CAKhamYkLKo9 zC-hzE9Za*k;V5s^RJ$B6_6U7T;rSy5kN7xl$A^;M_QdF06XfoV^T@%Em)&xki_I!K zx4FXYzMkQN0-VqE)i6)BGmOT59Z_|I*|CBL(lh1me%YW<IXn?hP)XZoQitB2`4@^# zT$krYpiK2}70A&?=NZn3*M-Yz7E>I2^Q@3aYIt!v($I51n0KBVY-*?s<<c9-EOohp z>t5?-+lO(zWbHxGW1b^#UOm^9CzmXlQsW-KoTNhn9nHXIsq}Q*S)F-3J65F}W$_t0 z@@d|et(U9r>|7+dt$3_jP7f~(8y_Ag;&s}yaeRWL8fWq8)tYB9IyaM>-&yC3Qr&Wu z>hOl6KJ9PvXd@?X8~Ie2J<v^gF#L!z;U^x~8no4^lCR)D2l6$msrm#6rXNq;>pYz9 zKPFM1zvWAc^#1a9<wqKH7Gad3a1>@R5=E#_mC}>7AGhEMk*-8h6p%ZS)j=|+SJ)x{ zjnW_yD)R+uK1D@Plq|qx?E<AZ0gx=gLH7^LpP-<)_$FUQyh-EYpklb}4Cts+zd*$$ zbxGIBTwtwLtOj8PXnN8(NO+c92<YabU@|wO091nFC=RkCe4We%24D!_|6nC}2~NT1 zDhV(>lYj#1Z&C3I*f$sctB&oS%J5O#zx;apsgA8+|EOadyGwuyXmx9oOki6vk=vmN z88|r@ljyzGV3yyg!GH9_P~r$!rjP&_H9`bhdC0O<jpmyo`j5|z<_|1Wr&T9$iSD5f zA93Dy&Pj+6Ddt?VS#;jn6(T#1>U*Bhr=9rIv<37RRX#P@D;hE+v#I!9b)@ctPF)X{ z*inw8M1_1Rxfq9RUTGqYNM7>(IO%fOJn1M6n;LhA6T@I9^R#g|s#WKax)*75CuT>_ z*s49xFGZgE7gX8V-qP3@o|Mh;=DpwmFO*AaR`P6Fv+NDeT?OyDK<v@ByHB^5>V&7- zx)3il@TYWyX0E&k$o6ust`WZg)q$9vm{`|G`yPbXgzU*l#mDZ&Z0#4;;_&l0;Rjz! z=L$d7Fls{x2ESz8&~^E`t!vsBqoxx2%pW||=hYI^94feXEKAAsb;k#fU5!W4l(qYr z5LGTkA?;qZw<_2TR$l9S%aB@gbJ*V<xvDv*+m-6Ap2jnB!S-h|WYhBNw8c19Y4c}@ zAV08;?RECRJMptpUj7hBOnW9UP8^|_eOKI);4#G6zj(8Jw01W7?QIP1V(6dV##Pm@ z+hMLD*4}FF{#R47qRfZ9?6R`F5y8#17ARS6{>hu|YrF1f8%5JAsD0fY&!}9G+dV66 zcP(OG17b)vi4ZYmhnJpud%`w-gwlX){cdlG&-%F=E>Cg>j80v7&G(JkJ(I{KwuquK zm?s>SW@6=N+#}2FSj`;ONqq*DSwaYWYn(mnM4}lPN1oR{^dWD8v8Mdn5{lGF(?0f` zi%b_9QCh(sBj%ckHXq#|4@e1*+=aXxNXfc#j4CsO?{n3|VKM)nDmx^K!{w|Wgiw?S zhIl6SNF$_b)E3>hqf3s^0NdTjr|b>!$G(0B=II=BdnZ$#+r6%rTX>HuHm3xlYf-Mj z9<Pag)=N0p=$y6NE|Ed_QfM(2;b)^f3j#gl<>t_4d>HcE>jO>?kBt}Wf5)_vf29lN ztW42wvo-6R7uK=RA93u@H~WHZpKkJ9$&bbe3dT^1#tDX`(Iq*=X&fUzukxW_FcMFI z5yt{DB(oY(t<9<>nF9{V80b_1@pfS5{43`y90T35bY;*0A`1;@D+{av@(l$txaA07 zsFMWgBANn54z^@=zfyr((l$5&=^P9L3|&%Fkd&@^q<~h#0D=tAbx(k76-fa)EWA=# z(;Sdumy@RuaLDB&Ea<l+lQ;vWNta|4%m1DHe)8fBlECwqBv4<LA@Dy=z{9KVSD(s& zTC*4#T=XRY+S^!r0<EMshWYsJlJ%WHx=@4~SR>wN9^TRw=p$eGI$@zs=EvZq^lk?7 z{c~TAzLp99lcR%!L+jE12I*vDoam?H*zs|{rA?E7D1QGMrkhfq50ltiot&I)bcreB zgOlVl;gms&V!VYS7E*?~h<SOS2_1zb=Q4!PvkPf-dfLuO*~wug!j!!0+!Tpfcb;sS z5uP=|pEe{*;a8YYTN$-lPqYsfdeWC{(dy6_r07F6im}d?fp+T&`805Fornf|ryg6Y z*gxc<qcKKgb*9rC`-VB}a&3xmzx;9%>a>Rj>~37V`i3=SiUcsRRZl(5WY>JJoWrY1 z^#~8B^^%!sb{rqF2-lxjx-6UVbb5v63`qlf5#a9P?)mw8%kNW?jh4^lx4U;bxUokY zc&3iW<8|5oQ8_2u8cR#zFtLiK%gjd5!S(x#{e^VWE@}7avj*0$`d85R3>6pUmAhHo zmy}R^$w93ZGdVntE;0r)yZs=YSOTc@x|MNdN9cGWzK~9UBbsp{#yr&SNoWk;@kH05 z3Z~A%|CLp?W9?@_KRRJadZZR3Le9If^3*sqT55kqNl8C&htJ|j=$%L!QscQkOODmX zrM6M~WLfO}^T@UgM|)SQsE@(%GS>Wna^X%d_Szgt$wo11D7@x0SMC|LzFV-Jis&30 z+2~qC%AN@0FzeSttZppaYtGdL#d%GmPm!EcrwMuSnLj}Xt0j7zQ}zjZ<j2h4`{kBh z(sh9yL;^M13$}T^(j$7b;F{@S<+|Vu%xvc8rrQm7^bDQ5?B)+47MCpH$yU`II?t~d zAB!xiXXO0_G3SwfZVhXqIlYb?ZsQ#=QB!aEWB)j35DSyJeBzE9T*N4eqWLDgA)D+F z<a|YTe0q7NbuHa5V-;7D1`jR#x-?UmN14qX;5vjt9SIFbv&5`A;=189;UOJ%iE0@{ z@MjRWAky*CSI05=mshk!cJ6>_)&KLa1@%{Lgkrx_-}RF|?@4_NeE*G|eZb*w-}@~x zqBKL0FikI@NMQs*GbBO47)&gy9kD!tQY4I1pUz|;YuW{`x&pwjYBg~LSds&!1d!Sh zAgKcd)b!u!=e5!Wrxw_PSD7WM0PU{j?<LDz^2-Htmke>iSz=|QWUKS@vik*&GvLtm z3z*Dckf<)3fdLT=q=z8gTV)%8{9*}Y637)Jmj?@2E?}P*?>ty+ZIvxK-~#Q$+D<Fh z40m}CyxMyGfl~GzWQD|6H76-MF|nU#H|lg?C92_u9o>IElTrN0K=FfFte2Sitxi~t ziH#nSw9C&qDpr9U+~W{5)>j{`WdWODDCY5LSF`8$BC4T=f$hT07dNZlF-D=4GAf8K zP-uN)o8)ih&L5sLB>V@_MCV|*#t5nQdltZ5ghUA*F?z%zm-FLrYQeGyrWp0pveGF| zqu1iq;NN>$<9Lh%PKR9gi~ZLxWdPm@pr1-^L*II(d`NENuD_?wSb7pnB&N|p!C=zs z&>VizK8>32YZQ-3U0#n8t3d86PI=$Ft1)qXnZCe;+@+@HQGM7YvCXe)En_-&c;S1T zO`84oh#us@xp5bG8q}UWLZ@1JwV12%j@l_2wL_iVsrBZB42vzl;~Jca`2jvW+pUK( zd4ae`pAQu@3dNy%8rYKD$7jz#_D)o`B$DU&ojA|T$jkE)F<asEyjm0PANbvY;|1SU zFwukIV@tKJfgY+zMIevs?{OL5CObS*P39pt<ERm~%@0juQP(A}Hf2LtGEK8SAn5I3 z&2_zF+=Fmy(gn^msGPIw=8)qv;te63<Y%0<8h_6r?NCbkwY;3+#(}x`iK+O#j_>An z6T<;)h4%H9lqCz@D@Q6?o4wr#kGUOsysYT+thm<_Kl+^~UAl72?M!YtmkY9}Cs=te z(b6@`i;cT|_)w@I8_}~S`<b6ot`6t1J@0$w&K${obVb{Uxoek+KG}^}q(ryd4<)gO zIkHIkmW_26>OEMM65nQBbT<0r+}h||Ty7LMakv<6k2PJ8!pl!`{?;nmk?V5$c-))< zt~>AU=tY6@?tohN%|1G2aWS6HvvYH+2|rG+*Y^2jj)|W4GBw~{gjw<C(2Nm@sc3rY zV-7L3(*-h5kKGdM5PdNlr<;OnQJaOg=vi~jP`GaIceQX74yX8x)WRt+5vO|*eS=+I zyF3s?9(uPsyBc!!J)MWc4Tg$)`XReo)k>q}6FT4$HP<B?8sDd5zL|`%>`07XXN6^L zpsqUV_Odz&;OF}xqu{d!o5@_5Eiuj#)pL$?H*^K!+nA=>0T;9bAxnGia-1XaS4`RE zhsLLt;3EyUzXaN&lsV|}Y*CfB5Dn#EM83wRMBG_vANSi`cXw^Yk<ZuZ8d?RXpB<)+ z<jJ@m`Y!Fq^ED=;7TS;TCFu9Usas-_SH}gIEx#`Fb!Sz0{EBXL9wK`*^fp4A*JsqU zd0vr=+f$=iW)PY^q#cH{uQ)-^PH`EW89TOHzp5+eH3o*$2hTANrrX^e;u1dKmh|Wq z4h>(Nc!+lVjo(7mrNqb@BR7w6xVk6bLed;=MKIXQ@LXu*hzhqulHN=suRC#X9v<nf zZZABlRW{F}P)%+r^MMb%c+MaCCOv?;Jm*nmWEyQ`sxn5WOm^q~xWVEv<})hA>ZA^z z5wp3;W=BHAqur4$zY|c|Qy%Id7wXswp?k1Nlq2c5QW>R@BwcT?{8;EN->N%_xY6=$ z$-*8!2c1y^Q~gPtw87~d(aMNXt`Yljc^wN!=#=0DW6vlMTT3+D*DD)|on*?2E>Ne` zZA=&1);3wD^<|e&=ryax4d+ai5fx^0gw;mMmKf?RE3$4!tw>-*6p|;rcJ`MGIt$JQ zogw*xoNi}y$q(ED3mSVQu^ex(+Q<(IW!10yo^+LCw3DB6OmC}xxOW>Rb?&joZ5hiG zp^(Y2TccW7Vkar~QUk*e(}zSRJcU~~+Pnxa&B9K-*I5F`i)xHxud3<oaEnf}y%C_J zX>U~ZfVnk%>-X@LuUeBlE4Ubse^}J8{y$*n?W(c~Lb5N99n13m#k1dsbH91#N38ba zOW#|6qX>+m6pAwl@oBpnS^LRL$OH5+8NlZ$GcY2PzD=dRP5-2TQwy5R)Tbd>nY?>^ zV<hMrFOeLeIHjNrzwBlSl7ON^2_|jIbwr2Cz%G|KiTTx(4^XFOz+N&O@RISBnw*qC zf4W$k=*Zj1F0qzEa=;9x^VLCh<un6>yf<5M3haR-!QSu!^aya^e)8K&g#|*e)0e`$ ztg?|L^(_B+QU3lzHM7<Bh9kaFLsoOS<LY(o!>!`g-y32_pgb;_ngipN-!S`NiLfC1 z%is+t(A$$a13k#Mrtvxk`^|Gd9vvJU`cIAyBp;wZcGT9h`Ej6B&A(bh{(yJf;~Egc z8G>Eii}jn=Y-<0e#z$MeQ~`SQk0MGZt<7`gw(N-W_1415@?#Qq%J#W=J;|a}lv~N# zkpFV+6PjvQ^>n)-*P6Au&7(;lA!brKSMXIpob;W@$En3k?wu{~9?j0?K`5}(=1%00 zlSlaMh3NgR*u5(4t`GOc24h|$n|RXYVTlEgB*CiHS(uHTDG(QaL2>`=7D$SajSX2W zwW;AL?EpkTyT9P{YM0^2E1m$W)jag`Avd?#(Ub(C_ldI`usiF5zefD7*Iiz#!$Ufb zPe?nfHvTZ%mOYE3L}7>EiHnwQKl+QlVQ`FHfH{2CHGG-oeZ5n<ouc{f_JCc-`3}=x zu=}@GrQdOqvajMp&<gYxZ*<JPb<_P+s%dy{b_&mMx3k$de_@infsZc@((41gQ4TrL zGwo^bygZ}1BeQ1F3>+7J!PNDTHX~!ZuI(k0EoTo}gGu>_!@T$^vIsJIn|5V<-@{Lz znJBNp<0jDZI%|a>$hM@a8T|S36jZ{rq&7g$3P+?Fd{k)qsi$KM;dnJ|q$a7BFR>+K zctQm+q^CoD(~zxm=lOhyQ*7rYWj5LQl6>nM<$i<1qU^4OPO6ZWBS-CJWP>LvoRGls zg=fx+Gx=&eJUOox@Z>=!_svAI+PpJWxDe9VD%>I4JhR3eq0_csLafod_N3b(xz}tj z<9HD*qwLZc!7gomEDn@8d*>>M8M4Ta+)34mAc+Hk6<QNw9^@D{gyu+2bbxolf8Rsl zfBj3wesn+psPWE@qW|^%D}So>_<!Q~f7i8PJ@)t22pVP(n4n08L1}^nz6}hG!!&`y z3_}q#O%Tkd+R`ZjzzM?vjAaa%Fj*jvpg}{JTCK3rmHd?Bfb0r?KJdC=98;|BSoG?T zN`Vm-3`j8mXabC>6wJWn=qi+i0=&hu6(aLr`F7!;?w<lRYoLGx3LR@F0F>_6Edj|a z15Nb>7Ks9ohZo#j9xR^)WdL!kKmkN9k8uoWR4iCYX6vvmP?7j86mG#h%p>_)jYy_P z%XP29A2{YzT*j%|D?hn;-`|*9-6sM?QqB5bGza~>O_7gMdHaZ7_+%{z_rc(TjIUHC zTor$MbEU6LCbf#br1h6J<~bxo{VGL?J5+cg`aY}=m|Mf&^@4!by2hJF*N2ZdzU**Z zOBr8U2L@(%3m|*yY<dl11!qt-T!9(-l_|vMo)FDwjvo?=Z-g}n9LeIjpWgf@64^@# z0Ye`gUj5svEpaa(i<kAy@94@Ev|MH7?>LyV=6pJITBLa9!2+UHo5xc>;;$YNZ#j3a zud#|x-Ok4wj*R9PQSY{#{1n~SDN)!RJ82m&2R-Vsmy6-Do!>#nd(xgtfkbe(%680N zzGPdj@q$+|yhH_S47a8fd4W(i7c)XVB}pcn<X0ZiM;E<RJw%L0BNIsY<>=fL7Q(^X z&+Me!lY#T_K_<<P_bYukM(C7E7**PuU0g?uSKZ@y+HXTh>!y3e+O5|Ho3hw!Td^*N z3ClATmJax-?Y25kJ#LOIN<&mvc~GSi3+Il?^>i_@IwW+vN8W}Dz89N)({TQbMw)G+ znsm+w^P!P_-wro}+EW)}CrVpxNowmQcws6(FN>Imjt{Fv{Ope%%zvaRL*F}?JH+cu z9=*!Q6?3|wvy`?1zBLqj_%STt$G5NmTH=CXa`yY+%uz*uVtNw4cSZR`hmC)z+RJ5= zKN9uDWH&;&+T=mJ9d~r-c~(xhrs;9e?2{bL(&EIsv#F)><$4}5^mxpelBmz2MvX+# zy2st_RP03+e=Gru$X=*KQ1Vu2Y!hmp7;~Q@baNC<B^oUbZ?C%`#j>ZDOYwx6VSKnw zriZE&XB&ruIK@eJFP4l?5sRBFKx}wqYF|FKT+M00Ow)T(V9z-%*w|jLj+xuA=Kk^G zq9STg`c?@iSh?3kh^ZK2N4^5N+TGykLEB^4eb{1p9Tu8=eGZR_tl4FOlwMc<AV@i= zo-eUQnwzb(VI1~;xLy+;m7)8kIpLXjn}`{wk<Ga}>NnXDhyT=R;@#i!N1umx45t38 zb`t-!WBs*f#7_>K6tVy~hQcI;(kOu=FuXh_5pv0L7kpp9e#vxU^3#qy{w{b3hEVY} zugpQ$d_iTbSR3bWh5Xg`0sowUwm>VGYsuDbI|c?~vUS=Nki94%*@V%ce_rB%4Ys@! zrdQny_=^$6PvD-c3egLu6EH|`mt;I4SBWX)-PCEpcffNi!5<oUqXW8Gx%z-2>rg9I zf>|Mg1hBq@3IqeTE#88GKbX4#i*|*6HI699?qGJJM>mXCBZrQp4#8)0H^OIP!hdZV z@ssxh^yYJr{Uh%OO<+%7fKA5!(&wOB@vDAMs%LRB1phlVi`f#E*ubm4RkIL3ndSY? zr5&6#^zCUcI~dLC9lT%kSGM_!TVfLl%Vq!mW84D$DsWlimd4=KkGLiMxJKXNHfYH} z`M2Kh%aSOvkpl2}u3@n1OFLW?SzZ;QiWSd8m{t8F=u62h)N*q=CR>Or((*iNd%-Sc zR+5+HP;+&6*VuJ0ZqM86E0Z^fh;4i9THrT{?yhKmtlIg=D1G-ZN$8SX9vkX9X9m}w zb}EAGtmIyz!}y@5&Gkgk+q*hl6le45g3lb1pl>abe&>+X4Hav!LZ4t8Nw!FRxRX0b z*jEmoE?-v_sqdd%1kqVyvtwMT6Ki5PF6Bx{mK}e$7$)L(?d+Q}-q3*>W6;jHf{#-S zMTFn?T$`!WmTf)$x!p!*kBaAU*@@wr?S9UDM$h^~6)KZItBC31$a#VeF}AziU~lK! zriMJu1bWKEXCCce#EWf<x+X>cZ&9Cqy&z)$+{}mmZ-c=9%(?s?B)-c45tLfuM1-JV zf&>Z(46_dIEZ_iCa~WpA4V<DrO#zpc6-j}P?6SVns~CQ^s@i7czbW$HB?_L$m(`a7 znH}~yZ>vPWN)58T9PF%MK;aY6j6utJZAD|CKaEgejRwm4tGof3F1!EL@J_ncPS<1< zUI%uTe6(E0h{{zCDJj6J52SN*P#*<l&TN%n$lhDg%i$LoN#DBBtF<&3+gY`B@!v`! zh&zx1PP;EC5wY@NfRmoQxo|hcy1p&!&973x+h@A{|HJk|)jx)qFQQ3*1Tpg)#4Kn6 z8!NWGSq4I1rhSC(1d|?r0x{sMp)U~gbvQ>Cr=KNhR0(vv!M}r96`f1oweu=f^DAsx z^2%Rg)3?wB{S$2Z2AXE*?-1YaH@esN&lHuOd7<3XzRx?T%I=$|@_Nu@)OWR8CxSFt zf_WnL<`nncbPdD$5<P<&Wrsbi8`tjs8u`7hi%L$ITN;Yu`IJ%WsdXelmbT(>WDY5N zmO@@v&1NLa-NBjh<ayfVB6~F9>|pHdw&6G2-A`b>gi>TfCiw2u2hZNU!3BHJQy25j z7RGE#hZYAuNpamtZeqp+X??i!vAbi%$(GXybzKHxPPd5SCGDU+(c;l=125RL3x+m? z(Z7ftMP4U%)VBOa750bHNic(ekJo6EvV-@!p)NEZ8##MK#z8n<rqK(Z@@$3M6ic)@ z)0{v(?Uc*4JVm`F%!ntRBS*T&L}FTTuaAx2K-M2R75)l_p${Csg|BNX^BGlm+f9w{ za(<}UZGndAPoBs6mq{S*!a}GPv^TbMPgz7ToX}ovqVo|1$DZe=NuRwVDdlvGVE(~e zm&e!LSnOErCXh3|(<L>8&io)e+|b@*{Ka?$gR|g(^(yz*yK%9P&(eZt)|j2tj!xU; zHMF-^{k%U9!nI4S0!bgxK-YRqD_YN;qa|n)Tzfx7EMd=nD$!U@FjN%aLY+>_@8rym z+x!*7sO!6Ett9f1%AlPuJ8C^$F4Uc;Z*iuLmd3E@wc9wa>R}!EOu4XJ@9hU?OsLCr zxn82%)1}Dpg;IEFKppkmT16a2xv{&@PUguR#T~M)xNRd2QSZ?+A0wtAo-&<{eV^s0 z?m6H6d(1k;Nr;!9bMCNmr^04UBWyz6Ba;2|(BkiuR?)vG>r(#%W##|Y@&8F#`Mb=M zh5_fBTyjqgqY;<{`VYtwMZh#gAQXd>2!rCE>L|V$0q69}Vaoxl4a)&dZOIz3b)FZv z@xq`BOD$nQ^0^9szKRs$Kp+BG{bC>>pz^iw3j?kku}T;c2%v)lDMS*KuNRC@e?@Ww zr<ATEPWY-4fr3Icxf0e%1k{ef#sy$_Qw(UkF5w2b&N?keU0z~R&?H7yDmu_wT&Ie` zO!GQL^?Myf{sv--`m2uOvQEP;duH(`b<>0;4i_jP`EiVX$vnGHGta+KQU(=e=)I(j z{gaY1s3=4KNl6)0l%e7yWqT_rW2@f3_gzVOiDtwF;eIYDe;xn&hb3iz{Lqq?{^OGJ zm$2xcmXtxb1Q|7l0{vU=b(LKMXTY=$=RP=&Wlt=svK$vq<Q^6zf8XA$hhk3BiDGtw z*=mdvWIE)Y5h@VwWZKdJd*|%Soo;mu+qrtJ__C4hPNG_BXB1_h8`w>yP!Pu*f0z#e zT0iupg$7L@QvOwv3?iHom3HBiqbz&WhHV(}B%}VO%nE&0XZ@aL6_jR>J3)DG?^jqz z%8^@g>Wvs20)suv5YNATcA!bfq8V$*HgCvo7$)hN&q@99yd)>J9u-3IoNN7Zn~{&U z!~HPVsouyQbhW9j&&Ns8chzO8vZ7EFvr<Q^O`cuv+?nS?z=gfXOPgbFXlW0p;c$OA zTxXrQ#}b$=(0Z;M-F{IwyQv;%e@U(!yV?DH>pH(bJ&W7@W8UW1LOg%h1&;oY-Rl1D zIJKV)>i+DszQZBV#v~}5!f=?z2^wJ*6e2N-KuH{jF@!=%`g5{1y*kDLxp)L5fOrlB zAC_#9&en3}DmH=OfQ=2RjLhc(_#}XXC1b@1z^Ylmf<l2T{j#&=?}PxQ$>mAxO^kv9 zrn%{=xWAH*KEok&mF`{e16hlx%Py8o79{|qdO0y5DVPA@0iyjSpbP=UKN@_Bj0PDl zRRUfQy^a$zFkl&_G{}D!09&$V?Dx6t1I#3m@>gLB?k2{(yd-O)Al#mfc)Ur<Ph{)& z-1hmIP3-@KC*6{^{X<W>uX*5-i!$FCx&>+1qRYSMZ&WP)jPCto!uyMSm-!^$JwOKM ze<ZwC&;_p~SZ%dF($Q}WZSS7+%>`AZH`swxk!W)zUry;hSv8A)L3;O_-m&!aH}L^> z&|je)7~J{NKSjPhdhkdN%fEZ`>uA{@5Y9i%fuYZm;0YD6!%gH&b2uSWm~N3{Qu9WQ zbiCE%h25zpNwigLsj~zzkDxiGOHx%nhiBR+vk$X_Q4JY+P?CcjD04&K8(ZnE%Gxx@ zZsL`47s`9%q#dh!s6Yxz8l^;ssw9c<f!hb0Tdi1oqbP_7Whwp+hu+A~eRs@m#mHhs zBhG~-&iK=?<$j|;x=x`?ne+G~+#b=Lb{IJwqYpWu1ftQ1q|!@|B)jXmAE|J5b9cnS zp0^LemWQU6aueEehEqh|aA-Z$)M%A04O_FLgFD<N<#6c|;#kF3FQypvQ9YHB8vCnb zG(qxEg|yy#&`o0k)+kY4zWR?~n=Pm}9c6(CUzs!P$B@1aVRB~M`s?u5Yq=|*A7%j1 zA9?P|u*~y!88DW)Q8c*aMm~^IewOYd6nfmjko=Gj+aU_`R!8$oT(dw=bL7TI+Ksrt z9?znrZd-V|$~P6Y5_-R{<eTqu)g3CP=3(%D_>GIeJw@}U-miDwyxzWVQiy2w?nSqn z+P#mYK_4?|`Sx;g#iH~lJs2Nn#pojijx$C6Y$<!6d3K*Q4&B*(r^`7-Xbu+9)5F`h zj8I|OOK*_Ja$iK-bF=AQLM;}#h3@C>*`mfJbnb_OzG>GDbT8~l%@VE+;zYP9Jfh28 zn9Nf|KX8vj;znFnRW3R!$n_!aADk~#MrzE{KHDSF#+o7grD&SaU$#!rIZrzkbI#02 zlX0F6LnX&D8oX)0t*czhZnB1QgJGZ1i+i{ngxifnHxM@|Ba%OJBAQ3U+l|#GKH%rg z_IZ`B&l%2#+{VeF7!Sf_pVXWED91|zeY>EE9WtuoK&@k2WrhZ(*}FBy&DG(Nl{Yks z@}qPlPWDthWW$J%=T_K`NT^ou^U1}koRvGg(<}_443v*b5ht3>q2n(}{dXja{{#10 z{2v4`)c*k|;Q#IC`Co7X#=niaNDRR-Fz$`h2!RnWNs<JHAPh|qzyp{jaTq3$&!R3Y z0drtWXjQBQck)9rad}X#e=pGwvL@3g5E}V3>RMjO*D11mRbhltP&iluHhQ%{U~&*+ zWhH1>pgE8}&KRIbLV}+5FQP7z0gdW>okj;?)2hyrtu}rL2Kpb_s>K3Y78y7;zOvbt zxC&6#7*NK@R*A^vRf+(W2Xr0aTTWsL$f)1j4jn<?dAxp!x^!IFsQ7596{E(JdTyfP ze*Yx<|37GA`})7s#MXXSlgxla67szZ@XunBA1=z!e{uo8{Rsc)0)p!Y{U;aj{ag6w z7Z6-O=;H$ZwN$0s2mOWihfC9q_;4_f#Z6P0ZKZUO?4KElHT6x$_Nv(lr?4jjBS~b5 z2zH%UaL>ea>&GApQ@fA(CHU(rLzd@T3v(CjSwN+}16}bWt0oWh%uuk}4W5I<T_aCV zv0yQcIE~xxm(IA*U-7;E#2FX*%o_LaIO9T}S>yh(Gp=rgP*Y-$OGh<>OK3Ho<4e$W zCsG*!<&p2JBNc1NK5xj;QQ)dBlFoR6#5{!WO4>X-PUEuoyg`J0X6HwKZ{N(AHtp1! z!;WcKEKS8Duh`_(28;l0WL#nSzJu!jr|!L$97WqM(Q~e%5BG#(MtIW^bAT5JkZ?i} zbAtCqfH1oH4XVoOs_LvZ-~aEJ*d1L}nFzfCW$In)aclX2V91`|5fgN)*V9cJ>ibDs z)+Q0xE{l<qflOB#(?Q&Pv|~r*;&}w0JpJ!n2b4A}f1`W9S%3R~zJQU~R?+|XP53`g z5W=9*Z~o7c_{0BM;%J<<zoF)<XTbZ3=VW|Cr1i;ZW$s7YL8ROk{<QS|KmKf4@PGMg zzVkcy53c0Lv^<8Q@UFxH;n1gzUm^B($s^tZmdG3S-g7~FpEtaBTy3Db!59+m*%6Zb zysI1Ed$~4D#oovYy_W>hcgmc4tB?izgb}zc|F%8|-s+jV$L_BLmp5?6p<Q4ld=HpM z?=~^y?ee#+6@z;ZdIY}#INs;jA!=_%*gLkNxAPITBXsm0ZQ8DB7jAy{w4rY&K#Kg^ zw1=>#J*IDsU!rOA14h&OXRV)GjMRJ|xo>fjEZwX>biSBf=c~Du?wzSZME}0LuX1~E z&M%V-52*=zpi=M%pmO%d#P;(h3eTD7UNa7X(QwIvrs{o1C}%?JB{uuC#0`AZxX-&x z8K-`zjSah5fhAIfzcNf%3(wf3TOD4q5K&VDrUs8KQ)6%pAo|m*ep6*$)Pmoz)SfS# zw0yBm*pKakF<*~uI0|&HA5%Z3V1Fl56>eLp40)n3dv^^~4SRQ|`zmd<>`<u!0leKG zKh|5syl5{P`k1#@DkBSq3m%e}F**fY>tL7<SDB|?UjDk@&X>$O@OeK(x$D=wKE$$= z@7{g=F7LOQo_TF>@7fEH_-G15y_5JrDDQuM)qf@Exv)kY5||Pg7S|?LQDMw;R|Gp1 zuct><CCWUuZMvP;_F72lsi3&t0xE&@6JZ>u7jw<n1a1~eo>bpsJ8tEUx1)~ghzp5I z{J71>Q|G>1JRm|%3?yT|NBs++J-RsZ==``7nG9bW!qLfADP$GC9)ylN4oX2m_{KhD zgJX%{=J<Ym8|m_dFj!9w7;vMZDvHXR?&(Yq5d+mC%MpjlW6t^z^y-ffH(^Dy$Pw?> z8z^xW>1Vdy+sA`Umf8>jNr~p<^@>gH>DWYwMF-tShtSDR{@qy*glIUzL97MJtD8q6 zfgN7MU3w)0)TM5x1qK*-><=~*(VTTsx(aGyN22jgJJ45CZvtA}{gKYO(t;ZedeP?h z6?>MWcjLg*kxqI3pLEZ?u3b|eS@@~3)yxnt`v|LmO&vH0bAMg7KaWQuo1KR@leW&L zGs8=aAA49$GPz)6Kro4zc!th>f-^dMv6bTpB`n#RuvDh5q)^UjIf*#xT1B5GUEW%w z?~WJS3#|;RVHP;BWECn>CJ(}D8wXWUFMO$LenIqC>Ks*F{B*%&5Qfr&1XFti=&evC zZiYNGIU6q)2)2uLZm{mWo-Jo_*9n1+uStwj0+EdxO}nYe?4ZpQ<ay|fThT`5Ejx<w zGr7p*3l@N<QUp`)VCSUqwQbKcJ)O&VtC>J`c_EG>M<=kWEvTIQo{0wv_iaV175_zh ziPk=0;9iL6c^YG?IVA?`$IHdl%0Pcco<rMCr>JLtb|0cedXxJaj3Tlq&mjJd1@Gwl z<8M*iZ-MdlcjY%x-2B{-{pm?RTk`%_7W!t<`?rhy=t8*v2YqT%PlS8YAAAd(VZmO% zCZhLjFSxh0Z80YHj+aq*$4T<@^7saUdw(>%7bhraZ*|-CI?=bV8L>-Phwtg*Eympe zGT5OzdPmLBucXrU;zszEx<=n-x^F85;;jU;0qhpeZ+N>=2IOr)6yy7)ZqOgS?G`r1 z5g_l@KjiIB6zmm?-TDyP`|t>8i~9do17_XJ<HWa?JD!$vr}&d-!d`}8{GYPw7r^59 zSY_r9&6k^v7@2$5Q%}6Dd$N50cMF`J+rLlM9Om;^@iLB;tqmBny{EW*y9sQe*aj_w z>tLnlpg%Wtt$)lzsjK!z&2-VAc9$02ivim~Yj3tzmt9NE`Kb}mD(B@?(BTJD5N;ai zIszz(#s={D7EwCJ7K$!eP#aZH@V&~GA3&e~)h+F9dBBgY-}^N8uSS=oFQZH8KDxBM z+3L;1;ElIE3QTDf2km84!LE(BKE|jZY>bzbdk>w`%Ymm&vA@DkUep)Sdt`dWKfoNP znNcUr4tQSdB)7+Aas-JuA|@)b5*C!M%NAU;KF5KJ9~y;~j@gN~gP}Z=6iGB2#!!wK zr>hNk*wevP;=ZJv1&X6wO_ze5Z-{vfE9}k=Dx;@ztR16UUzykJ63^<1xjtCejh-Yo z@j$00I(63%-4^q**K;683f$9reXVTV&GRZIq`5z)$UKTTR1_3-p=6bdJvkSoePSEH zjG#ee=7!A2_M*a`whGsKV&?(e3w-9K0(4(J$FI8=Yg|+wJ-IHQDXlNxv$*k(8?=a= z!=sT&IBF6&H)_soH&Xj7sr9ZnDXx%d6bn{o(%d54lhH305)J20VlD8w-L(dY_1!z8 zxnBpfn{>x#;&|k>hwZ0yy1cw}j#XjuDE4qaFf9=g`4E<abI;AkNcOIHT><QdV<_3< z3B-!mhXjfn7x3BCI9;sld7BRg(XQ8}P#x5QNO%O7lMJHqMQQm5RXFYh;E!$N$~h~S z<cwsbeC%I3<Xb}znUZYkWCz1bn3u<E71s&mY;-ITx9e1OVKEGeKLfFbonMu6JVkeJ zgo24Y1xFUCp`Jj9hf^Cy7quy)!>2$yKG)jS9(H<Y<<u=MC87B^z~Iqy2}!%#?!GK6 zH%;#3=>|XU3<0+wNIb70_Puq}?%ebXTMFh2eK2X>d@-`hhaw}`kwnw;^+i)mn)Xb( z>n?^YZMe%vXb&hzghVSgZ#;B*$M@o`^H}T|u+$vD%SOekje1h+UISC^%*HCKA~vCY z=Hl|TYw#~xBxIpg+wgXBn|w^fLCaIH&_~j3i~diZU|&bkwnf-hx4Y)totd;^o@kV~ z!>c67S-P<|#voRhl21=5D<*7IRuf=7AEO4gmtb0q-Py3JlNr18>wrPh^jw&YASFo| z(WlD|XVu3eN1RbmEfyDDGEFz^!}6GQmZIih!m~O2tY>Mr^oDa3T)n03`=rlBax^W% zn|(VVBEuGsrD=jE^wr%-iU1_9PAZSYE~Og=*G7x6Rezazx8T+7i7&Y(N)QhY_N8*T zr|WCwBM>P%tZwS;+!px^q)o8}Kjl5m-SKYHN$e8`=tMh0=WsA*V@F7iB4c(IL%Y4e zM2(!AX^zA^oRgC6Tm?Ab2#e+pKa5B@-7znar<v4>W}P<T`N|G?K&XdTd3P;pg<lT? z7Hvi};L$!CceYs+V3L<5Tsy%wYT+djlz~TJWo*BMK6McYp_7O6BNn1yvEc^uP(i?~ z^H3d9)5taLQr1Agr}3lCO(quE5PAd%9R;iiQ5$>Eq^KbUmVM0SJ-Hr2dZ<q2Jf*_( zUit-Ry_#w&0Sy{^b0miw+R;wo<H-HCvEYaex1S^;pjmsqoM)L0eXY~6($)<mhplbv zTtgK>4gw3f1hYkC_86m&aGLKA?`FTKSE(;%`jGBzkPmu!u*lmgw>Rl}ySZI32A-x* z7xNLH5f51BuF7z)o<oyqkq~znR3X}n(intkKP>g+9OhbtZ8f-~q27njWTDiWt8x5r zrvFVH=+ri8x&8U=+79D4Y6WfN?1x8wVt4=iSszsH7ti>azkRCePVS8vdrgCScV&DT zF@L);ZhUR~f+BbN7KZz{T=+S6+p{tL@7qc+xEC})YR`K>*xOAC-5WjNWM^;)x=YXo z@IC_(>_l+;;uqX4dG|kVtPMfFTCsp{6`By->12rSc^?pd*Gll62X4GFe#`Xka=g%6 zA{Tr&LB8#|B64SN8<~W_okj-m-xfF2ola!m^!r%)@VT_D@pB4+9~R)pR>o`!>ZlK3 ztdRs}+H)&gFc^RIBM9K19#4VqINI`+pS@Jh-qQlRqWhwKk-Ggj25OeH?#+cCR|9;1 zIseJk0N-EE4_EUKCjfvwpU_`PbbMAdT{cDATUmLn=mKdlw1==`dZvinG*6}i!|et~ z330#9jg5FBM0YP8C~kdr3pG9K%WY3m3fSisUsv1h1q3OFobEN+)y>TvgWTeMGQB!* zuJvfqD#CLN_y)MXDvOODz5mR>VUVl4gdY=CLo*eQh3N$;C7GVnJc*81;WU`OUAwU< z5Cu>BSE(y9z;n^yZff;~$SbuvN!jC(Jv{6fbr##zE21adZKYil8+8?(RKgM=y--a~ zCV49pN(yM28#s<BdoLb(JTR=*D1%=jAwlXivZ(G2BI{T!9JZ;D=@?HV;$xlu<OK-S z@%oqn56m|1Fi5u0qNUKZ4oiJbr9sI){FYaDmbpLY6TYSsIN-B<!t$9#&)4<=t_*J1 zGm&Rh6{qgN0yWP|1;1{rYI@4clf~dpAQ)e<P$wk`d7f?$=Q(uGAjZUe_dv;UXIRP? zPMFC<kr06B^0p$}=U9ggboS(<v0C2UkM;Z*O7-enN7)ywdI_Vjx8rO)$psCYJ=nT3 z0fiL<w7JSeTz1Rn1E$n*F3~yyce4U6VTMYFdu$m~#;5G|nGLYQ;2TVsDT#?Q{>q*s zc>ws#+6X&5@G=``0!xsxHyPgHOp@JT9b4m)**9ajY9~|+6q`4R8`J29N=g3H&L7<c zNK|n-;E6Mu;Z)({6J?MbH0I$1TKQ4Ijn;b+P+nOf>L)gpaa@HsE-Ei4mjTy}O9FH~ zdCtEX95mzb*~jmq_r902G_-I2vfug5Z=Yx6ztq!z&Jz6R%Y4fb{CSBVK;=^n7UC_N ziteH%6ufV{B)D4>Ch#82$LNkF`{)|HSFU0F^Crb$PlZ#-UbRlhz06J^dzemzZ(GIa zYo;N9_T)Q`?YV+&lZT*h3bTLKU`h4_MI7%5cq-m2_!|mAZ@b1FY^ZlD{d<^i2Rvd& z!RXyD50bk`3;G5UG})07i}p0ap0MzDjD+xgIQ;JrCD^m|)wgDOhW=dr)%__GaJD(V z2R_1PHdAx67G`$~<o|l6?%N<<s50#rK-kBlZTMD1ce(mn`F(f1Z6Wqvcm6W=X6;>o z>8x=!tZ{GA*L6Pze1A|C(jWE8%1-|-2XW?C`Rv}AY%lJ9r2c`=#@qfVPS3OW&96$c zJV%4V`u4R+Zy(Szc11P*AH&bSmmTl%qcc{Wu_ncmhZm4Tt!?;LQ!;^pK#3_CY$+U( zq}R5v^k4<aH5m{h<>1b6k2h#dr1^NCg(hMg2c0Dn$f)OYoyE&MY4y_H1d3L~OMlCU z#}RLoLy3(ht;)rV3w*1<8yn_=b-1qQHD5Eqy4(OY>S^()Jl(Dq-PhrWc<Lj?Gx%w! z$+$%odh1-JXZRGS^NkH8VYH1)g!Ad-H>;I)6kwkbh|wXz0=?yErU&~t@Gy(qJp($6 z$NqXD=%p@h&s7>kaApm%(<RSd7mar5xNUNPR71`QkGmsrqxRRj=2>wG!G>=qH70R{ zx0c+c!{VBcbkLbJ>%i~;Q%LZ#CHuMoLPpw${Ko;bAF|WVG1DyKTxFw<gOgCy5B9(& z-hHIdcP}3Br)IpboqK<3-1~(U6+oZa?811p@`#+%Du&F|Mnq8Ni<Q<ek6nqgc8nuT zlzj0Nq2!5`A8V&N6Zbm1EV9(VIq-wT+~O+x(pxOr2TeEki+e$5c{qSdEy|Dp3maYF zrU*NnKqVbQO;`qp?}<Xnbl{HJ;dFp|slQbN>flX!K>PTHi)g1`GMM6mg}4c{^0d#> z&8OYehpIY0958u3E|Sv&dLY{YHCL|~LeUmg3%!yNM<blNcIaGer<?5IcMw|1%v_rT za~!K4Jce6za!(GI1OvKjw^pcOasFLbv&@L9(hlfjPY4IPINi9Eya@G`Qkxvquv5&H zAP!Y&telxkP%yOy=w>AA7b3=TjlV=|CXGH$AEkc|QEDFc?GT5*#sAZMZSc^3i#lKs zq&ArOcEYY*{u40$>nDG}(O*CD2V_D)2qhqxAaIDn2ogn!Pba%J96_nK<2<sff}rRg zQ;^7eZi?J1!^B&53xD@X1)ukJZI}_g?R@tkuJFBB@-_|u-_U~W<6gwuc4~`~sCSb- z_#PZ1<6nRkvV}a!-rK*exOe3HdrLeV?w7IQnEyu3INTHF;aiO}e%q34S4iS}4CcR$ zMdJ6I+3q?Sz5CSO(_%Z4{(Whg-LtLJ`43YoRX*smaWP(`_lxo}`vF|QSLFKZ^70=+ z$ri*wor}m*xM9;b`EvP1S05G7Q~BKqqCMJ3w_68I-_LHpJL)Yy*}G_g?=DZK4OjOa ztPVh?QtleQV@j}MZS)7?!K&phyHl2GWpBg-F1yv^i~e@-`}_MRw+H;y{r!{M1ODp% z{>kkDk@YXMzAg<~9JQj49wK~BQhl1PKpEk+Jmp^JXmjsv$X94|;=oSu;4j97$aoC4 z_3G?TcSnfWwdFF{8nYZJwy$5uF$BV(@rf(ZChf6Q7I=M}oD;0X8D>q_+U`V9QoST( zGd^2yf!%|!8dsL3J~OMLqdRH?i9~N?hdb#`jJ6V!-Ok=%WyiG9(GwolxOzwqvtYLh zeWtsmftqo-+4JQd&yjS*8UoPJwp@fpwHc-;9*<7!Szc@d>`puvTf|FH?^Wn79JbXq z^uJj_E+^|c)zE2)`Y~XEEt07i{p1n14UtR@J6?N9mM%AvxIJwBq(@ZH@sATGwpSv} zp4cEKV3fKq9jw#i{Dgo*Z-3SLx-con9Da#*pPF8QZ{qgVq{LD<GD!6Ds$Rn<WU`k` zY##NwA3&d@lP@`8l@~eMNxwT6_~hi^OT5VQ!WKKG2Ga$#H|g7NUikHcrPLYptF-NY zbuy@9u`=G(0htf$ai)$l*jAp(ugcMX-D_0GxVck^iF}e7P%AGR5<ro9Vl2TiLwkO7 z>m*M3)E-$xdt9IGQ$L|eUl~~(4^Ng$?$Yt1HUt_Cu~-68^i0u8w}+q&&%W+b*%@y$ z-9}$LwDR0>JkUZ^CCo`^)`M~^3G<fUC2LL^G#Lm21ICp%UfVl;YuJXDrC5BK%;^D# z;-K=^3&^^W8#9xZT-szk9|a*h*i^5bPB+w~e4GdY_*%mvEYIu<gjZWx)iJ`|I56QC zvhlk{uBlhx@YX$e<x_$bR*Qpvv|a6Nd1SF*BXCkR$atU-;|K7a12duu=GB#Q<=)v3 zgyRxZuF{5e{`mm-+u`aRm|cGO#{T}hKZ>~q^791uf3m>05$w;;_@&ntfl(-o@8X@G zD_Dovj-bICi#Ox~v3Cpe+l6r#p!WAbEqtqd?PAoQH+V((KGFPT3T=-X!F{fIL&a@v z6npy~LwjZtep`6#<|5b|-tpi4U&(fc!8>;ezvrllJ+BDAm0Nb>5NN+b^6iDWEw{Z= z^v*8A@s9K$@%xu@_Ac=0?^@X#C)n*nqP;<TJGgsN{=I_reV1!2<3D+ANw>^m&wtw5 z_hygT;x?>cKFo#}^=`n+<krIQeZ==RiD$voF4Tp8(Z)x5kS)JDT?yKbK<IZ5sy{rq zJ@&QLs+`pqkE+&pEz8B1W5BnA1*57aJ)gdbo<v`bmY44$yl<smb9=J28~%ORg`I!6 zh2qPDUjy2o9{UmUfWO2%b*`e0!I&n^h3QVGgwL;e9v}4^%!kgHpA-@>Qkh$b^SRND zL{^8Vc@WaH3^MyMsHq*zfd-XeJVDA?y`}}Io^kvR5w4wO4EB5t7LcA|mAwcuSa-Ry zQ1PMjS_Cbd%E}XF3=eBK)Q%3lke-up)4in2T_m8V0;Wc~mh~2_T)pmc43w444a|ej z?kz<6lWrp?E4@6iRax=yK(WMhv?=<sfyN<c&p2jvMeBs<D*|*KO)morcKE3q%7d;H za*E#)<*A#dFBa8>_0lLfC(-d>2$#cC;v2HJ>6@wXtm^O{aPRZ`Mxv1sHvPD#lG(UU zHLMVv^Ga`G={)qSA3STWL<D%LYaz{kl(z&v#kODI;15Mb={TFnp#_xEF8dPF5B0^* zDI!OVC;2OVOIl|XU7Kk8+#go@HBp#n1BP7_RZ7dcziz*nzIdj?*IG|?q|`Xg!q1NG zEh;%J9QrthaCA<|h>wvX?O|*PX0-!~LdA^ma>1199-MoU?}EW5-4SDr;prL0f!cnR z#mKp~7xeYAvze^g<3RXxb$PsG_6*<&6B+G#L++h>X4>f#5gN@!OmTqtAd0NB934nF z<WJfCo_GEh%wVdF8>)zCuV~WmKpjd+oDzki=OdfV!|}EDHyyo}_ibY(wYwP*nUX`K zD@~k!<1Gn8F4RlzD_U&pI2-_VA@R$4H?xwvT-H^L)hbgK6DP*;7ElMCNNw2)z!p9! z7Z8?p&mj7;i#au_Ut`#v0EeTJe+*Cbb8P!O@}u9P_>Wv;xaS&$ys!PPZ<BbJ67#Fy zSV{Pe#$g;mL7e;vrT#1He1O$|yv7gHLm*1P1PW6Gyep6)B>CxpHi5iFDABiTRJd22 zeB^iPEgTlU{UmoGXL1Ls5Zn;$bBW4#`%x0?ZOYrZ@!L8wME7_OefL1^@bWf|+#){^ zd_xnlw<RUN8WjT3y<Ljjp>tmgO7<_dSaQQGGT9f}zKF=ZrbfM$vv&;<cvqv`&~!uL z?K+TPpDRbe{c8%`zb4*!P!#+<{@YF{QP}t0<N5()l6{y7VtTHo@M)fBw!fRn2HtkX zH+9hqhW-edF7`g{ORc_RWZvHB^rKWq@ny={>%tn!fbb+wUVVFuXzgRsI#`Jk&%<ir zzBG=8FWk3C5PFAMoVo$p?Tb|d$FIN!NZ$^s0{>I)^Jb~GH0$)&{wuE9MKbm|<kEHa z<|aG+LH^8z->F*BzsutmF0KLWRd4CD4a7EFmW`ZYv_gW_mp*GnI;W|W13&L}Uk#Vp zFNVv~Zn(Sw8+Wei=LMe%g7hT_Jy9zB<T!hbC}7MuiLUUMzV^HYKh`x{qO;tgywP>e zEuKb`VKHgAV&fLkq!&{;+6E>nceUYBSl3k`^askmqgRHa3g-6eCd`;-vu0<-^6h|Q zuF7-Nz%E=TLD5pQd=N)2J0;XZ;J_hHL_ndW(QzT1Epf-cN$jKWUE=z}1xZ!4<tUd$ zbc9fT#6lB8ITSqB33#mo13Vh^3&L_hqp6uG&{P!q3x!C5?5tMAm{yBi7Vhyl@vP?E zS6UG5Wb`*M<%cdhYHmMt5-F+247lTDIz1RTL4t~49-?ch2Ml?FSDd~Uk2B`i2P|8+ zNXS{GuHq=aRu#%q9dW6z!xIjGnyht7=T&4WDei@$5?M~g{4(eX4Q`Ql0VR;^!9z(N z@##FOLUS*rHr&FbzzkQJT><Z?yF#bpM?P`Ed+w;l0YA@6a`)=dMJr!s85q`%)C0t8 z>G6o}Pq)b%s6G4FChrR$;Dh0=cy+|DhDee39F`B4gp99|2>HV^TPgqblo@tZHaI%2 zux~WNX)2ZEIiCXRbhLo8L@v&4vR3_EkAiXzx`fb4TaxR;nNlXIS@Q=M-2`$`@l#aL zu|zT6YmO_?e8%%60Jv5%Iam4>>XmwA6WP2x59v{y?9`rKl?KTeGqwlk<XoJRs&5;; zT6`HrnBqz2_ALW0=Jh0kW+B9Oc#x&}`BBS6Pm?O029=S%X9ki=yE`-3Q~JM1Apc<H zX;iQH*=q($UmM~UsdPA=v=f(grSf8#?&|{S_9C$=iNW^AWm02rr`nTPSCu8d8x5Bj zA=iGe`BZAJ1NL3zr%mO<>vIlYO!z|&R>A0}5~XdL$>@_xdpa`#G)vPS%~bop!T!MZ zubwg!EuyrmGf!G1=_vhjT%&2^>*L!3679}R1<>M52lIX+Pw$;y8@;7fnqFuw{6*q? z+jyCXYOghjg!k>oh(n63I2rwzqR!3ELrUGub-WkcRH+eiSU6?Dps}n9cNH&dr8dbO z1x<Kn_(!Ug6yVnwSyPwss9v4+;Fah5%RsF(PV?y~!_IVA+}pxpOLlRf<MB}%1XQa1 z1k0|O%b)@QlESh4LL1x1=k_em`gxRj)N^b6B}n`PKH#AgUx*$*?CF-R1r}STdCf5% zzxr1TB_ZItI<HH#6z7iVCE>{1nS80%`O(Yp9Vv^og@a%o&s^nub%&u9cPJGV6Dqdq zIryfV0OB7xD@7BzLN!FWXoTi4p+=b7heIIY<wDtuys>rTNJ)xp@ALj5zm(@GrL8M? z!b-r5trfwQVX$BHIYXLJ5vq1DNzyC8M?;@n!bIU>R1YPctHNM(6D@Fq%hF)pXWdf( zkZ6kVhYY7DjiS7nUwB8uh%(GE;sGIdBkWIcWLu5iAo&d*DMYTxtE;wn%UVTvQvoj& z<}^srBd;#Q<Z>Dxul;q%nPG?#BRZV~s(wbQ-;S*@_$DclO*ys6@#&fHK>$<09E}7c zpf-l@t6&i3<x!4!l=bp?y*s>d>Tjh>nnJa`FBeT@Tm5=^UC$PGW-sb74_|-|vZ?TT z^?31|!-roy?M}I8o<u2Ua+Owd@!+ICN$|v(v?e~g98>5glZ?d4vnW$%fI?AooFB<s z=tqZ#YCmB|2x{!gH|Y5)!~f8Qb)$;XD{i{@f9;;Bm;Wt!ymsY(GyfO;bM4_TPWvE? zf1L6?1Ee4V!x0e2Pzppy3PvG}!Y~BKNt~h}6x?{>r{(aC`UT+I;Ogxz8u@#T00Z}K zsEr#U)Xt~iWan8p@jLN3CEOk-$UTn_V|#6V*BB?>j#}8eZ3}wmDZ;%lK!tm@WA|K5 z_M-NO2GE~1d$66&h2h@pPQ9t$_8bu2b1f0|o@ozup17x8g7*~MI}-!Hzu2oA?|Jf# z-cs+PIP&hT-yO)%T{Rc_`{sCZPft_de8hEHVG(Ehy}1*|Y&|*(v@~_{sb&w2{%nvc z*e~AxiW_^gykg!u!KxTR64Wis{UME^vSoz>o`cPvi4_41{xN!8@UK1Jf8iwb%josj zV_dpwF9~uA8vVJ(@vmR`<As6!m3M0Q51E||BK?_L@S#J4R;X_eU<jqau;itRngcIP zYJZ5USQoE(cs-NVZK06(5MkCUeCUIr<#E{!_T_PEWSKs*m45-2D6Ol@$ulqfcpckw zIKoA3-2K!)pQzLLl$%&~&WMB0>#E<oS5PBC+++-{=MvxGCqSuP!-W_7@LHpAU`b^< zvLgj*(No2tV+{HVo>TFK2?jw7AXr0rM7#-(EEej*_QD-_`j>O9UWd!e5-MBhlIG4{ zSx#_+&M<H~E#*sA^3%&|w!P_Q`k-#tdcZ=K0lua|=YW;Hk@KAkE=OHfZhB*$=LrqX z;W`vbSuWPa3JXG0nL|v=1`lbT%4OW`agzFV6!Gf;kbC<^;t82CO-GzXY25g5CS6~7 zB!JALQCTWrkvtY`HaH7JA;)dxC``+o>h-|mpbqqkT~bzVw2`O4lSqIgb{Z3rOcT%Z zHz2SNwI+n)dBv;AxY&Un9<%I`oI&xCO#G?=OriO0d#_5)N!@C8tcfeyspZ68AHqO$ zl?@PBYVf(k6iWsvMzhNeYBSZzi+<Xq0%Un{0Q=^FQjcl|qmF-a!3Gjuet?Kj3t8w1 zpF}nt7}ijugCXTvFJ7?T=Exq8B8dTX;i1LBL3x4G^^pZk6`P|awFdz^*@L50>C>T^ zv(6<ge1w}r&SBA&(^Tz1B?fkv55P&ykR$Z;IU;^Cc2JRi>JWTf3V$#=cw=_2jbF_l zm50>dA{*afIJkNOUQN-vLSxV{)ms_IH<{96nW7L*DsO*$xDG#kxb|crXWDMMo9!*? zOGUPbZdPvc76-_MQhD8%5Ro4ZSa?O^t&4NU-W3)!lM%NVE45$gqQ4mCs|i7=UP=M> zM1CJh*@7{s^27?<7F%5htAdpg_66N7vhy51RV{tH0(#ySTmY429REw$mnn9Xg@{r4 z_x2xqy8wR{9Rx#9$6GSL5u<#%Vv4w6J#>r2S@<mX1$^nKXV5O49kZj<oa^az#w($L zlc${}qC{%$w&A^us_)O!jp_udZ#Fb1)JrTm0Z{pRBiRvaHj8wbZbG7{YEcPjFWVL} z1XL2Fe#x(WnO;wXEite3=nlyvFP}mh_!tiObNyKI=IQfQqe^rc7rb-1jR(@0pNKQd zeIhNhD_@?$giSs9$gCr+pH<vR7SDXmEg)-8P`Eo!&dqV9xzf`uKVi1A;t=sX6?9&Q z0|JJ67Hna{RD(5^y-Gc2V}oFa6sl%G;qFfVa=}pri34|TiGzmb$x}1Tm)|JaL1&f> zd*OMRFA6yzc&)hI@pxThyiAk_YXP@)iZlI+`BtJdP4-{{OHl8*Oq?D~7K>Q?dc{+Q zVVR02A&q%+VLwZ@UEtUd;!-RDCA$O~jny$&_nw^S#-L%%UDjRP-=YMcGDXC_xY~?! z_nC>r$8@;{E3G_|E6l=!8~}FVJZtVTJ`2Z^@Gvno5Hh-a<;9}xtP{&_pGVQ<_4UR; z$4lo618P7AVzQ-lbQAIj=#45={Pk88%Z0XDuQMpoY7+e(JB*Zzr{i`Y({ihiyjBPE z6+VnF`4SrmWR_z~AArVJN$aF+TdSEu>Ws=Habr3>H?^i~NSqBh->Qo#sq$0d1fdFd zJVIU}&*?ATDpmuauP&oGT6%L!?$X@dXW4tV>+y-SoU24U3f<6=#WLzzzk(y{Z@(1( zqBWAu{5pvH;kP#Vjcw~X?!)*?4eEb>k#fBJZ<_s$^|uF-J-PQ81^iFf_~3_s_xvCF zP@uQ!FpQEY32uy$fY47R4zT#$B^mDm!I=L$81LK;d|M1`tSos~!=SfYJ+jO5e##Pe zN4a<M(GTBst>9~(ZsUa8@r~|ntaBrD+l%<*??k*emr(xiVZ3WB{vvUR?=QCz&EzdI zypg>q*$oGf_a%YvMCL|oQF!N?D8659MDD$wdw*xVXA{wQFN<w#bvwAd<lYh*?FrHC z+YtOamUyyWEX!E&AAKn2>$Xeb<=_+kr#`OV3G#pAXg5pXRQ^lJh*?zJa)feE&q-|d z@*F#Lk=q*9w`asMnI{^nci-rqD1d-;dXG#Mt^-wJ{Uw|DRk`ikiD!#9cm3P<;)W{g z*3K67ms+F<pc=z0el$fcGNZ2y_x)lYEb(m7%}1F{;<a`=C*MUJ0ZF9l?Z6bgpQKeE zr84EKB;p^#n{Sz*RV_;B59Q%qvHy>Q8{VQnr!H@*t<L(FD?IV9PIDb&LrgtApR~#| znF5G5^xH@)xV<5zcap1Jg<&7s{E`gOvcS2mUR|w$!+*_zd^@jG4QU4WFNslspDSjg z)`-Tb>t&<c;*0h^>W+LVaNBKuzgTLo7^4(?w?S+8QSD20INMIzR&UfafZgqTYTTdX z!uHoO1$zAANR)nK*TCP?Yj&d5an{x+?UXGZoN_zywWF9FVJ&hf044{`I7tV&KkIhi z6_+)01KfE9o>`L=RC2-{rk=?v<!Ac-6!N8aJJb~hvOiXdB|m`MnO?<Pb2y>X{pzq{ zW*QT^y#vt;O{>Drd_tArJN@*oF<(|!hwE8AZ~G!cK@lWi9pIj4uQi?`H$Hr}9~AdS zi}obO2@(wJeAG`Va;+_zI;n=h3;6(z*A_b5AB)bPBFZxWEY*%1>{XVNLC?4*n-cZH z#9mEo8C|AS4&)j|(R!2z_*x<<7T>j4)`|1|G9rAMD1gTcr?9*9wtDT^yH{$OgpG)6 zusQ@Aq1p8X^yrBj<(UV2qjkgmv`)$M42xQ$*C6HtW_0MhbW*SCKJXuhr}%m)s>^|i zu#|(RN*sqHdf>CwY#1^gPK_W1v~3vI(@;UARRMNoM6#Zog`7qE*kFjJm5yCCrMPd< zJu_(4?SUZ(R6T=p8u@q9GdVnl=fN3F-@pgp0Kwhj72PO|Zrr0(Tk5zAH8#86V-Y-1 zm@dYzNa`Suyo-7_P4lXQbCtmH<*bDZ1~?_?Y1kQARB`N&1}4jomDZn253LS~((3`5 zsro9WSFn$#$H7*{>Q-mb)0LqjP_hD8eVn;7DTK-_F%`>IThCbXoUTn1W?ccIX);Q1 z!BgkMMW!Man(jnutGby7YEfq!&D<7y1_u&Vmkj2=NnlD$uoqaIbmr6V>1Mjo?LCPq zF&y`k^~1q52aY&Hhf_lzYE}|S%d_-zEG*@m#&0o}NSaLsez6QJ(cjJo{``bGO9Qh^ z1O6XvFu>0{%)i}WfS-4mf4ji|KkqRAc7yrqd6u)R&K7VfA38;R!o}wTUe_<2KHWC{ zS>xz+Pc{SZY%|-=XZkyJuatLA;y20AFEhDFx!tocZdg#i>qTEv7QioayfSU}s|3vt z6(d<9#)EqopB8B<D9Z5U7>^!{n9L4vl@Fi;`?3E_xaSR)aC)PGt9nIp8@~_BwF^Z^ z@#hk((i8GfuD)xe>LJxR<I+hKD*%{_5nYE;VWzF>(Rn1HSDfYoJf^}?R>@uwbQyU{ zec&nL#U>rRSPpR+*oM=IkIM)FY2`N$oFRQieNi1alOow%OuaaF996O<M0VFiJKsg> zSWE>?<z}-!!Q;(7NHAPi{s|CT30Lvam(l`B`~IOkx3Ii7A;VXN3)O^5d803fK1>cN zfm5eJ9#g2}IN|bG?oF@3KxZ<<!NAUpBQaf`L9QH|oP!=LE8;j$x^0l0ziy(}vZa3& z4rjH{0#%J=1&mz|S2<vrf~D8UmDFlRe462u__T243`MC0D$0u?%quCjLw@^^b3Kxr z{btexEdUS3gGY4{7z>GAg!5Axm2k)fRvbH;WE+{FTlK!Xj1P+hzQXg1k<NKjZ@*01 z(YGg1V;O3ASr4En$C9!LYFM>K&_VurrN>#XjH@CKLc&%O6?4(Ws+6JGKC}_LJSMT} zIo)~XRSj`5kYu?#+BQKoHHcqBKc0Q=K(PwkPp8SqdsZaLR2=E+QhLwYIb+)%f7etP zI#9Ho8!2!RLtc&7D~T#1(pNX~H7w<=4@W({^>?>oQ;1O7B<IeqII*rCSaC#X5L%p8 zdPz7Bh`>VsmtAkaeGu?({b&E2`~PPv{Mh&Qt7iZ@K*hiR*nf_p5C%a6fk4~eB#Ba= zcD_+>-k-elyCC#C815}(A+%>y_bI3N&6UBuc^llvpg!gO8$aL9jpMg&*xOzj!FJM5 zQoE)}_#VgF{Vl`2TMeduPw-to&EKMoU-5nj*}K%XRZwJS>U*l1*t_MnONH=#4r_}6 zV04!}BjCN4U}O2<Tg8+J_7{WSa-?LkUl#H9zTPdY<GrbVi$6mDZ+X9I?Yv+7uK&Ez zz(aFO%<JVBynp!rA@BdL3*0(=wAZl=2l(Q~QR?mTzHi!N!7p9l+&71^x4Vd1sEhW8 z2PUGv_yzbl`28F6Z{8Q+vp447yf46KZ_K}WUx3fvn7@8sepHA7{#qi2OK#(}ymTXM z1iA$ukIb0WiU#s-b(2r{5=X$<%`ciWi)xOY+)0xeWkXTUU&3&uoV0pDQ7stPgK=B$ z$-VF|p(cc(twwOvPj^ir0FeOkF?^0Kx$xZ#KPAIHKJQ&nHg~sUBs4eb^N4aLTFBF_ zTMej9b(YXTPnJRVdWC`4l3iUzDnK<PUbUdq?vdp*h90^i<oxW?66LwC*|fKBrb~47 z<P_;4K>dd#5~or?fhf8%$CSAZQe@+7tZN3OsyKW<%Hgw?%%h^##YBnj_8}bIV{xvf z%oVU^H1x|oDOM3UwYfS?XCsrSO4Cx>I>FnIG4jv%_AIjc+`eKcew0jN2F^jpFHUlz z#McEnTf_YViZCEWh&^-L&kG|H9pdCCu?%q+yTkyir{goUeOw6@uxXGJ?c)noia`rO zAkGEcZElepu*z^WJBSV{l!0BY==@6Ie%!^X{3+wLsKg}IPm}nvz^*j<!))Dy7N@Ht za)zP|iGd(42QOdDOk;#{Ktn9HU#Dn3*^pU0T8XHOa6&XV^)5|~1n~1Hn!?Fin^h0u z>`L_jE)M=xb@BmJh<q*&_c=2cSm7c1woIf^V%I!N59xvLp6zMWVauczss&rBy>vV! zXTa=<gt_fo1t_W}_zHYOIoh%rN|NS<2Z(GFWjRI&Vn!P0Y<$EeTk0Cy(5-4ZZfH~B z#g0n3me+3*F{$v_XC1xbm&4!c_k9rn!<ZNwKEl&DSpnDe{S&gu+tXqS`*|-|2K_=) z3r0G5s&sPFpUww<c)~+uhKI@YTX4{GKMEiiH~XDZ|Ei&AT}mk1*m?(eEZv6it&&6y z3LCi!8a>@&fo<oxy~35rw#{Z^{NZPOciPVbzMNPt{9EaFU){D?dzVHILG>k}+KUfV z=G&aCsoOi9|6?)0H5p4O`KM}zv#ftin_^#kk>~HY|GUBYr-VYz0<6x-ujtxAcd&T< z3%>tB_ksVE@Bh4|{lWJoR!R^qF7v`;JVQKU%>9w@6SB0Lf9yyuTV(lEHZbo$g0=Dh zyUk|)*+<vJ32exiP>0PQbd3?0(MwbpBBR;G6QRNU18&5$j0_#mk<y)OV#Bz%FW?Rx z97W8P*^aNZJW%uHrBIQ>maPtf0SaFPZ&h#ON%7lzCu#;hw@iOO4w1LfK;yUo$#Pzv zu~8;);z(-`KDjEYFKN~tMCxiwek6Bu4`+idK=SK&B)AHx6+XGAR_D>m?FIO-no@-z zuv~eePRv0+G5(cedi_y>S2LaH8iK;kmJ2&8mccD<*x9-lccw_nGqtV};AStlzrUic z;N!7Bos!nB4-expZbww@G?lM-^>T`0lB5~Ir(1D%8n)VQ_Tbg#)Ce#imER2|M;s6k z!?S1J8~5z;EUy&zd^{c}2fnuDLGB-#iH1$qiw6+Hge{uIA1BDBE&zQcJijAJRVQ0I z6{z}>H^W&jo2Eg{t8{yWuX^RJehbGuvKg0a@mlJ0B8ZH1#QLEHR8Z**y(5F<EXL+h zNVAG!-HIG41J2JxJSSHbb%;QXe5>#3lvuYlv0Qdu?UP5-7??=btT;VD*BHqcY|^J= zgIjT6GvL@xB})vW>u}vNiAC`k#OcJQNjuJkXB`;)fqMW*rSof1HEX%cnX)z}i=Zm2 zAu#VLv4g<H1;i7WHsY(*)i`mxZQD_*@rvFZnSW0A+ut}piq@Z<mEunf2HW?Ud(+0J zS_uEerM?9K|8SY_LxE3acQz)C_+NeKH@Y9=Z`-A4PpBioK4-F#dgN^nOzqPqpY#5= zy`LZKLnZK+nNV`C9Bh1h?-oIS$KiM8{oSq+!f&zvXn!d(_?1gB_O_1-_Ltrbl7l^r z2+6k`BD#;%?2|C>&JhaQn~ssU!oyw%i1!c$^Y^eJev3a)Z)ajZ+(nfkYHu@%{+9Q1 z%ib08fd3Fl_*5>DWzyH5O`8Co`?4i(&$Jj&*iHYYpyt2p!3Zt3(ux2vzz{aFK(rUJ zpxuuo5y0EgWW3W*<(FLcH~T$)RzB40*X$Im48KECZ2o8&1bkJguYNFC`cY>QdymZg zXcCC1yOz)P2l(a^=&C<v(%vS4^p`O~U6=SdVs@va0LC)aP-p&Yh7I87&e|@0Llv!b zouyKZb{0RJ1sCBIfW}VMu`jg!n@Gg6_dUM5t?5N=4VX;7z7L;zNO|U;jR4iJvo}Ad zraqs&QK-dDi{((2Ahk@gc)lVjU%9w><^UcK1c_If3u-M`dy|_rc~Gq$SPvG25!PK^ z5;N%bfdPppb?vSSRL;`2V~97eM_c*?95=2Oxin_qr|MuiaKz(X;Yt>!xW|Wn;SP`U zA<u4)ghG{>a6N&(pYh?+GO|t>&Ab9!qS9Wz(Qc<2wRSc{C9#HVNk^{0>GpL2DM(}} z^n87eQKDw#fuMUEH%+&$3|YTrfLNML!LFT-xdnpHc<Qy6b7+T;xQb4_A2$VkzJ$b* zOB`WBh^jtU!7bHFqh&{)MFSYQaXuH+bBOaWrv<8^EDVOU(Usw&a*5mrktN3Tx-87V zUFoJbEg|%6|Aq2jW^VxcZ%hyW&hrouxQCzVq3*3YOdNfRv4y9kiZ+}c<6qC-upSIS z7?jj^z;Qy(O@zZ`c9+P6GfBd(o*RP{?uV0BbPB}<&Xc%C(()R)jD^!1aiC@Bd4;PX zik|>ACNWQr7JtIe#wgwoefT^tVqYqBlU|#)f%;Cv4n3w(!+_fN#zH)qr?AqxJNMb@ zfmFKmbt;Xc!GW;MotTqG6L+a<&vin`c<(c3??(DpzG&r6f%v2D-ZWASFz#FsR?z~m zXuXsZY9DFk(U8cIfzvy@p7je0;YB3aq|+4l*YzA15WzmL=L8}#EZ%NmxWOWKy#UIU zo~$#13~_R?@Pe<w&Sr+&F^O!6J4oTNLGRl=#nh-fL#fIfkH8)L1Z&r**5)Ar=u_sW z>V@Fh3;H)I!+nx(ziR&g>;5>`io>jFt2WJlr6%;>x9oQc#Q$u`zlGBX-y0!GXqSfD z#fRQ`Go0Eb5w`zBf0v1iqkXV6*&yq4&7lq0pzv)-7`_KjgFPFEe32T$c9?~u9qp30 z&cpU<5xQ&6fyoBBziP64%M6FXj;P676mQpqfcA<$^>!iH;2VZ^b-V4FLu41li=zEi zw-<}zw=XaGmT`dIg?3~|-CafE?Z}v5e+#F`4yS|jw{TkgcfqM_(Zx47Jqa4<?vadh z8$6b=Jx6PU`fY~Rd3W`jIpChW`AGJhZ+|>z_pATRlJ6hGEATVE{sFJ#KY~}_XMFt= zyqfkb%^&c(?8?h~v8oD0J-vyy0`Ns_+MQFj`}srdXctzdKj=jD!;^l7Tj1~T_V3^p z_=2~{IO|uEYL6t{3zLIU66`@3`ZyyrEI8s8_Kah4zFPJ(x35U+)B)1A{?SlVpivAt zdP&`Ff-ypRMbgx*2peV9fq<RX8iK6Ga`P2t!gPzSV}B<dxic6ux4j#sWDsz=ct=by zpXM>Ug;mIkNqP@&O@GSMQ?x;~sbIr+HOt|ul^Rl;^JNk5%`ppZn(97|8gQD&;`w?+ zhvS0La+XCZS*Imakc7PYS*g`wZ*$FE)s9ak4+U?#fa9Ie63^n$j)*iMs@gcJP;kEF z&aJD@!;v|5Doi1qv?TKBiVCE05T6h8_A+YEGTNtBICBM$H!nx+5d=<NV9TQ}F+!u) zG<v~Cf}9U?QeOEVW?lbtkKxm-s@b7|E#|nKptgn2Z5!e}0}aieni&4TTiS4vwz6hz zs^pTWvjdx1jUA<qeSh+82}Ai^Z`k%+*uZeIQPMIVO>8E4>(+Mc4q)hxL1(9CCozPQ zpFLz)&^mk;vdzgk#x-`kP$>>^$`b+5B05TaOSdyd*wffQUlR`^m0=CAPKn`33{%o* zT8+LVf^&&RthHwWYs-b<Qs$bZ0NEVvN7^6t3`7Xesyv}IrBjH4FX?cR1gL7RxGx=+ zl|+*ze&NlDxF-E+VODr!J;yW9DM!7UZ|CXKx@Y>VPd5W)O<@5kfjUK{Gn}jJ8qsH( zRmcUI6xJ~W_BGOJ5>W}KKtQc_Zqa}bqGP-ewlJ+RV%a}IUTQy+S9yDwJz-1FOXf7- ze*m{1DtiB4;qHIm`hN!Cf4cVHA~8hlb)&rrE!nF<yWxEJHlIg#@I%5qJdEFdINP^A z{3#M|D7%G{WU>duyXsN2kFUny+bQR5;Dh^n$!u3<Am0%uxerF{8n($VkQl@FwKhVq zF#!KPf=d#6-0Gvd&i{tT8wOM0P7%Un|2u$o_n&>j0^DB=LUv-YAu&wtfFHii^5S=M zT(m{;e~-k(F6A)Be~ZL5_kR<KFE1MVK;kVL`2mT)(-!>qs0{p7)cXyUz4Vu;4E$Bp z`%h3A_#T!&N9AF@d}M`R@{gzt-&P>n?sI#y{&htB&(tV1TfGeW<6sjx6`)=P9WJ?W zSx&E`^1{fJhrtfG4CytoUWkvls7sZwd(MM<HPfjgP0sxYXUDSA(V+2-(X2Zz3*)P+ z=+GrN29g=oFhDMy)8|h(Vyymk9BOoV;3v<0`o-v0QgymbWYx;rY@=5{JL&ce$1x+O zID%rdlR;;|8Yr%`rsg)fbf}Id(Tr4I^v%SbFe3?AS0yb+m-<wlL4!JANXJxxu3Qya zth;9t1DTP@iRfM0S2sR_`%`0aoYOC;N>L}A5c<Nrdo_tOpnVh7&YLp|Wx2BAvcMZc zVk`l?7MNab?3;EtDP))rd7w5>W&84xobq;B1UrmuCKXVdy;-%A%=S-e6#rpFEXYej zYljCwN8x;a<x<;cquISy-V?dMQlrowJ|DqNbXn@eTU7}NW-MD1m`8-8tF<Q$W=2Nw zs1yl9-`^l9XoD<guh%V><z5E~9A+~*t<7yZX7Q@s8DNTWGkD4WFLm#=<fyiF3E%S+ z`?5RuzazXk5q$x|I|<<=?(hg9Bw>Vk`esp;wX14pZS$S(_@kpDvNDyJC6jB6Ip>&T zBFt0X8#K1Jn^&*5Ns)UPlhvLxmgm<yPhYh|cB!^IDuz2xwp^7dKObM{0=>o|PVK2b z#o3|OXW%?oAS&aZM!KTZV_NO-w{1)Kvd^BEhqo|QqSCl>OvgBz`CAHIMd6rxmvlGL z3X#w|m3_<b1NGh4ZBHV}=~U6kE=FnHiRf1#U9I_w8BU9dYIvK^`vyW@7_OgrlB$;I zG6(rCxZ>tv8eu%pdkif?TFqvod189`<{o_`c*xzyl}J4<yi@NjsB^B=-*=<PftusX zNZPN0?G?a)*yHzK{A@h&_fGldG4bi)KTNr!5C$hnmZn*XK!Jb6r#f)vi)U^Gq#D^~ z@5e*{*`m$HkKD{^8RDyiBmP_mz8<p1vhik;PLKdH*#v}|Sptl0fw3U+?=%6DZ7Ku! z3I^?9oB2EaD;+rgAt>K$43jU*KsGohz{xA9BVXp|WSh);!+vserNAkG&(Vhc?3UvO z#)`=1gp`BTMD$<6rwg{q%K2s>k>ZKGa{p&{9zS(KItf1+NNgigzdB_DPrf}O-8UVe z|78IEcjHk7fe-ociy~p0j0#5S2r-6&vRoAfQuhVb#1WW799$7GL9MUeKyCa2YTq8) zR`SPbxBqY@(8p5#u#$gb$Ih1hF&vZjaXO>?)i9J%o(bHN_}fV{j9$}DZm@I*{54O< z>9$6uQcj7lG!_Q^2q_aK%Te~~9gIAWm_EK>$vWR=Bkqz*mCv2u>&K+E5`Xu!Tgs!% zDuW$O4b8ZIF_#vKBSd13t-ojBh|GEWsdn^<@~QxTQm|m|h65bduvv`h<#A1552kC0 z&MZ!v6fZq;>x-DFt#*IKu9OY!o`Z**Px1MIy<<1OZP0@%A4ThYq4?3ztR1eLVEVzF zFKIHJ=bCa*XjYyi=ILw9%O<;yxVw~fFWlgLGM=7Nj-z=GQnH%ebIl(z(8DOxru=@B zNR<uR{?$VMXkK*=)zUMJ>(&!}6Lf`hBx(MMA8r#KWsm5y`Niy@W+IMcc=z9X7pv7j zj)MI&ECL^M=+n_|(zRnb`>-UOwHsR&H6FovzOxy24Fj=pdLF^uGt;d5wG5rTqg-AI zIHA>h?!oRWjz#_XYSl3Dx|A{zYS1Lm|82RG^rA0MY4LJYKG3Iv??S7B-tj_QF8gQ= z-w$>pTwiBI*3L-t$jLWtn3-m+7>;@oCv<2pyh9X4#@$79ulY)}uJ0ZS8Rsy2hxsgb z{?*o*%X>O7t+%{d?Tw7Dt9LkJ2e=qcrV)qL^=YD^$^=Mk5{Oj^Yynv$?#_1<28Qho zu3^_{$dfnfSe_(t&&yje^e91YW#`q($;%KhU`I@9>)uUa&tCRWQ$G)39C&T{&h?lJ zn3&<3BB3PAL3zWgR*ceXcR1$<=I{3<eGdR%r=G7H=--BzKRM+yi242SA0UP$X`I0r zjK)BlI!%+GdK7`N9wf+#u8^>9+U#Z}L~MmRCiypkZYF%`*3G>Ja{1>C=`7gSu`QJe zMu%^q6KGT-L68RQ?JzLrG~KeUYhd-I1_@?({3=32B9OiX5ETIgT%#{~v)o%xTh9kA zNI1X_G6h{s>*dzltRM&Mlt>UMt_zO0L@Bb(GDkAdi?p7SBir1Mzc$<Z8Desg5f7)u zyF19|lRy4XL(I47+fhI^e}tG~{xbFBdx+T{`#%pcKd$7TKuoW?ra2`;M4q|`lbpw4 zs22S0xre|jw8rp*lNesuCR}%G0v&NDzr62+BPv&XhAtX1y4@_6nc6KAmF=piHSq*J zSp`~`57rt=O6V*9L`kpc@(y=KN3~5Ip}89*@eo0`z17~^Oik6qRBD)Pt~m8V%@#L$ z?D(|See`N7FSSyv)2nrK>TZie9Gs2!^>p{0lL6VHGs$dTj*l~km)!1{VZ=(GClx&= zZ!9>+Y(v_LY~?ZLqb3DEB%)DSntk@%T`0IGL@krd2x#$MSR3ibyY0)FB&;u~ZjC-w z#3hXMaPuB2uB~1{q{&Io!zn6ScjZVlsk~woj<K4~TW>tJj?$dJO;c(yMEVnm;isKL zl1nt+sVig~&Y0Dl?J2G}8_0hIG2cAbIki4_Wk|hDgGKv$d|%vsW7xAKV$IXqb?;XO z!{RZ%x%mO=1$FQwFS0xmvvIMYNeg#Ne>5JsFrLsJHwRQ>?UgV{j<-BTq&cb+-$|kW zyxyM60NEF0!r%m<>RXB05`|(85ekhpXV{zeI>FJi;%>_vE(ewMBJ02_kHzh+hPiZB zGCzcj;<1aZ>cnQA*2~ixinWF0VM-ccc%X$59^ekA3&<V0!sC+NhAJ*{HIwS;;Xis} zfFAY0wo^skB*99ghS0Dz0AsR(U!E-DOli#DsIc|fT`0YaR)+W5F_y%9dQ`b`3JC_9 z@a!GxR~O%f&w|hj=C;Nx2Q=a&M^g9;b}Oa?entJ8?f!cZb8NHwb-4d+eEHS!pMlHQ zW4}ihnqhGoU<yLx1WsZrs()(ZN`U<t*{su7<{u?M8;&EJJbV+ofDGU!24~hd<n!Pq zWwuxc2Z2e30K2<2N{CU=X1WGF6b|f0=r10u6u>cT3v<@{V804p=&k=0&p|6JPJ`Lp zYxIF^<E_?p0&pRLSZ2KkN&w%x74^WdkZcpYXTT$61;iD4R&2vafJz{nxplnaK%MiK zRwpNr2%4#H$P!;h@6^io{XqPTEG9q}`)BvNzuwP(AD<!c)*q0?PVRmmo&Ej~sN!<V zm%zpT9aX+O_H7l=-$#|tR{?!RmETvPs{3CeO0glzejDOZh}^^*IrQ>(u$|&58^SuV zi#o!ch<m$S7=@)Cg89N#qzEXYkKxS4+;EKU)v>DOs`UGY*Et)~WH!}RgRjy2;_Pp3 zKgjUS!}HRfTv>Z$nywwI-TqqIZ-d>}JLGk`(AUtKqt_!N+Yo}QDmzJuPv%#1wrZ6q zkU*P|Y*r7F7H8C}_W6Y~ug;8}suj|%5qqEDW~ak9rnOoJ>X>60X|o0^56<st#1H)r zrk^)F&<%V9dt!fG_EB`Fhu7s{nLQU$rdd4SFe1BQMnZ~dPde-8Z^?8dat{5uzNeU2 znszd1-aVC%#=y+|R2czvuv0DFEpOwg+x!LT4LqeG8aeE&6(zA_y*%e-Mx=buMdE%Y zU_0V&@8MV_{BRrY6?uBH;&tL)%|R@?ZrAMcXpkWvK2YexCsO(;P`7f&_E%WNknGKh zSS*zZlTkO>w<Fd*I_VIXm4PrFYpD)wsIUS%&`SyBM%3!#%g#nS5rW&LAGCbw*<kh^ z<vsM1$!R$)X<lQ}yN8XWGE!Va>CVyjhISxwKnQ9Wd8L|E|8`s7fDz|3N)<YOAp-VJ zoi)W22%EG!VGf^rPF|#1A<Ic^^PEs4Xpc5x;A(hBPetTk$X#s9*}Mdy5QlHC>Pw!5 zpN@Xi+j7sUI*v*QI}?dseq(%$xM%1vN=SV(3htl|5!_02qjv+ngQ?f+0b2{!HFv$g z|LA}FqpU{5*LU_}s{QTGdO`bKiHEqdpi?wef5#gh`rSbH$Bd)EeH*H|_y}TOZUjZ@ z%WL50w|PCP9a2YLIAM^kqU5ViWr;nb-aEoiheACW%%!wcqcCwvd?TE1`(=qJN$)t> z(R45Ku^*c&OVkf@jlX)55wM$k)qT`@7V5K$^VX!Rz>4r=Pf-lqA+~kB7P(Ix=bit| zm+;Y_GM*#OZBFtKa|q_-{S=GJ+EaV<!lIFRsbI=(_lY1)uyOb9XUSS)evQaqD>rg5 zYv8fNqjSbxAlQ(puOTFNy1o*(w^EX-VdQX-D90eJ@fqEdm`Yi3LgA?>)y^jy3Kdl? zYwlXmJ9;Q55K`64Udpq(9U%dU*!-aEIsHl~;$y!r*UivVbeI@X^^ENgNB!w*VrYd2 zFAg5m6dN`)5O?_oU*p+ks3-m+9yw2(-YsLzyZZWY7ko#ESR_3jd*((Icc1SAe;&kJ zJ@gFwG$m+&(S>sGQ|dNna&}`(By*d9GlaLvH|md$R&TbE^zC)w$jhi;oJ^NpwR=c~ zIz1KW@(AjMzafPTFD>6z&5oxX9rwAkZu(a}-{40dw!u6cZ1!jv?{#;7QDe4yEy4Q9 zj~GbSBlIOvNP$gl<Oy!WF4KtB?T|_RK6j^A&13uK$!29%`eC@gyP}2%+^Mp?F(0A> zbn4|)vRXxgZK-}NqGovUGTBOZ6Nm>%@?|@Uh&%-I{>52GY)6k#h5MCMx(HnDs0`Ax zJvMOlLq3fc`=5A#d`4`<{r(@5q0i3w6G8-z{~_Ea5ER1*7NHpmUH`+VPe~D&*@6HI zHIm$hPojWeuq+5&*8m*FL0WZXJS%a^)-XK%T$;py>6<Ha*&=9=g#{dn0$yut1P`p^ z5@35D5rE);(JwKmj{-%}uav%^GY<uF;C!3ixrW<dFk22J!)x45Z3f2a<~O%S<?H%a z%0;ul{61$k%ef4M)xhC60?B1^^DSW*K%Z6;h2eiiiufHMMVH|BjINf{*Dl#*wLR{O ziwa25QX%X9X^toN$D%0omsI3;xA~Qdq(2ZMz(k-ADx!+MU@u!g-DC>fWLCGy0_`5v z3G~w;fGB}}x{t?9(c4Ot(2q4r`%B}!ZR-Np|9H2rcKlywo}cX?{L+l#D;l~D*HpAR z4r(-Zc*#c0G2Oabl9d=$hoi0XeBrf)ZF6d2T{+ISOo@o45D_3mmq;s4sH3J)bLk~Z zU@Xl(O!x(_{o|`byV0TEws(fF2RZ8A#;v-yd?{r5Vq46Cg}M&u$XkAuhp-w1WH9hb zblEo|P^X70`Ex{isaux&`dpdTGM|WNU+eR|0zS+?jV5uTcCM+B7g5UzPbMb_(VOJZ zhz^bdcl^FViFY{x;20Q83H>~olCL<OFN&|veZ{%aYB+(vaTRyo=Lh8~@lngHFHp-W z=bhg{(IYOVeTtAm>7t{*lNYy|uJAG!H^w6IGf9^+lVc^(h$|FpVTl|)FNG;&yv;#J zsZd@gY$LJzXy++Ld>)JEkqiQO2#?PTdFe6&JHY)#vEorTvwt%97YHcU9b?-+vh*Wg z2j*lP{+HKWm#lyMpv>4Bjlt}VuP6REp7EOm<7XqI|7&;oW_9$dJAA(pVl+z=pLRE| zJ6*QPG6@9a=}_jYCX=8*c*n3{;^MmFAUWtprazzSu|{fZ9Jt1K>sM@ZJ6}&-qdAlX zTj3f6uCZUVjbp?k@L=>slS%!X{go^e_-`^`4a}E{8VSNYV%yYcV$+dgK&u&V2}=|K zp)A-Fw{coT1a?UV2e(N#2Tw4dga$&*HTqqjCX@YTs&N2fkk{d3?-O{@<v#6dR(|r+ zsCg4I9d%T{Df(+azSmTEKE2mCv%X;E5M$Fj+-AA|q1(+6CsKfbZXpej&*n#duVI+h z5UuzSgUH^d^#Hrn*LY6$Z>mVvsgk~vdk1EBd^OT6){Ru1fyU8VO#JIWkgZAi<1r|x zc=)HLWZM<QtGVYsy7xjqAfMUYN8<Spa+L!5>fF(o`>*DJ)B4v5o{j>x^dDp?&ln>L z`|KkT@B%!aNbveW>WBPts)di&<I9eGs>AORpkPqSX9-Z~S3@U>UC%ynof_YQCaF0Z zjnaV#NRFqUy@sMY7VY{DZ57D#;r1!$_sb>2;sTbDidzHE>Kyr5DGPNP-B09HNMS3C zlT(!pQn-#YR}WQUXr3}m$UPrph9Zv>8vDU33$A&)ys*ksi7?a{M$_oIiyK`~1b)Wh z{gq0MGF80r?Yy#V@;!*>-)DQd_r6m}MERmwQ@FKNshP}#l_5i(QvKGv)%CXukss_n z-v!+n?t+FEdn9g6=;mp-yFY6;p?qUI!GsAStI->b2K<36ya(;oq=*cZV|8!%Y`BM{ zg%!3yl6QdE>s=r&Id*s{_7aNZgCv~J<-LhgLNVt`_p~$lL|wyIL;Dmpr1N6}^!UZi z=4Vv-!3x|~(+)TI9dl#5vqi^){XXcTg@h>kH315JmI3`V0jfuj)-ev8i`^eP_KJwt z^oo)*)G4J%uw&AW4XYv*^>$iu@IA3V?W@Ykvpu0z$brrTAti0UyLRn9vi<p<90U(h zasyIX0EJUvz|vE&@$l6$W#J1U{|X*E(!&wGg^Biv-W^mb)wZ^a=A3fsn<bjdJ-aiI z#-5Zaepsh+!k5XpDaQR~CQhO&wqPBZMRuZ^vQea8sPojs4~>kfu*b{xt?>c#x<LNJ zT9Sh!%e^|;@#FozB5u%xZ+9pUg-z^&(Y!u*9S-Z_<aC`d8TL!RVu1v6q;E_rgy5H^ zSwlSj6>GH6I4^d{??u;emG|tty-)6%M<WHQyv9%c;-Yy+koW#ZFusDj^Z55c)eTl; z`$?bp18}Xd=W=SmS^otf(EDFsXH)%zn*YINK49@LFY%W{l7agM0}59w|IS&UmWa2J z$ZL48A`6-UsRU@~+pIlk_EThBfe6@#&_E!W;v4BtKvol@0H0r>X+^O0>&oOKWYcf3 z8(iZ5CYWCjNlv#_WhekXbSno&8PGWb>yH?)|21eKDWLI0G63$tFd78`Ow59%f?kFU zs7uIAw+ZHK(OYN&W^4W>GG+i7?}xt{lAQm99-hC54)kHiu`fo=7bVR{q=VtD8~E?a zena5WZxgUgXLDfs5+&><5AqR<|2B;3&(ZM%>^8S(Q%Gh@Fc;{HZ8Y~4?L740dgKar zpDy>a)k6Pdxu2~T`qgsRP3%`z)BG1NJP~-|0btvYd7~3g?%<KHbpvy+C#RISl1iB% zu)U1-PNIdwZ}!X$XnZZ5Gh&_9BP^|qJ(I+BQ`Zs2G$*?ZmC`k@X{+k-xT`gvKbDsW zev`!@%1QPvMX4+Tdy*PER|>mR`J{&x1=8`ek!$eKr*f(;Y4v2M{o{%`Jm1^nc_5DE zTk{LYFi<^iqdK4xWw-u+DVIG~<k=ZI<zwhCT^qwEh1F_lSK<?_W!05Oa7CJrgmS6x zwLm;1cX!fwOl8%1>JBa6?iiTfEl_*LoJ*m_dTOE%@(|hBsW`_5WxiMJ)mh7yTXKSr zZ*_;ZGwdC&OJUJP%j^pH(yVVkga?xo=69ori7RoME*$+j$;3_huy5ExD2|Xn34s0% zu$^89sk>JxWdv{SnAMITpQ>sv1oz=9Pl0~;gV}hB$Q>;oKc;PdjbDnum0on^?ORKY zwu_P4-4XWJ-NQEbXMLaTAyaI%+m3ya)P>85dVlXPC(=J23}%_J;w<h4&7OppoF_|^ zmz;JWRaCDJ^KR%`KCL_GoW(ZHTCea)_`2#-l&W$qPc{3X4(#4~c&97uYp>l&lqn}B zis4=-bX(#}LUsy;2~b^@tk8Pi;o?sE;nqJ$l2)4M96Sz77VO^rak2L=|KcKX4r3@8 z<hrQV`XDe1oeS><in^zANh}Js4(o>pCREiet=bMIM92=rbHS~hy!V!zw%Q#kS^G!Q z%$E|m7R!8|@>>X9){rT5j5D$<GI^n9kD0Wk9mieM9ZXW7=~VS@Cq`-icJk`*zZ`LY zFu%l8zd7?7RNcGZ_J@D{e}*e;k(rYv!-hdXML0Aczyh#l&tcyq+5drSeQN{w(*yrf z@=qmON+<>Srxg^|kZKLaVhjXnDFqM&l-4ky+ep_q>vIn)a+@*5Bme_fkO5H_z9pR) zkZ4La@gll)k|*oqn<do>I0?N*Y`==~(5;g`*|JpI71wwTj7ug#VvE@(C!i59v`x0* zT<e1r0^sip7UR^{7!cdWNv?5Uv?axm&BiLH{u0YlfMqrO7m|NI{Rtd&PY`R!+?yYv zP~suJ;36LZid}ek4dSnUjqn6_COTI-i9bg}kcaueT5(gOZzhIkfA|g@HdI-Iw(t7p zym=ddC2-5Zf1Dw~ReyePJpYu4b87B~Mgv8%BpYF^H5Q#Akcd+yiv%%Myhd#{!VGH! z>YaWVf84oBZPmbX3Iu0gy>8JpsI8!n=xr0+0|5M+EpK1+^qdbJe0}oT12y^g{Uo7I zTRnyF!W+|058hUX)ogSR)%kIL3)Q|{aGXq7hoZ4_HkQ37x6l&TaQcK{*d;Ja=jbuN zOyUZ>w*@^H=9#>PjZQ}W3pLJ>9dh=V#)184_V1ldh)>^yeC~`}!$~Ue&I{8x5k&li zH-!0G-l7x}l>Z8&7!RM`tEPseYNO{f^?I(~-#b()ZZ=d}{A-Q+WKKvGQX$Xo0vi;T z5m&vH-nHegTb!83_pv<P<ZMsJms3lXxv$?MrIGsJ06nTEuZ?n4=3;l<P2Bl@5RR(( zlAm?Euw)ojZzi7Nv$8{V@z5WN@<O%y#PoJ@k2=l>MWbbp4#G%1Dq8y_O7rfQ<t>SO zNw0HS^I^%@szL~4(m{u#sMEr7{4>D&V|ws+ssjBas5cKUOKgo=>XOXOyTaJtj66I% z61uLtz46k{SgSkFAj=+%GNn%mN*>xIRIRhfaMSBzHS8|8hUw0`$9!Kp!@-!@+9?Xd z%?%$*$g;ve7P^BLPbHQe&k6Ln6}jxfha3E!;4&W;kFI!L^U>ja!}AX2&&yTuY57Ud zXBR6dHoFb`+W~9QG`ZYM2I_ZMb$vKRE9<a6-WBV}zqojab^o%m1`c0lt7AOs)i)<u zyw4}Pa(!BRok+xiZ-O*KsCV15g;BHouFb7`;784lR$KD!<vYuN>|cdzT<bweocrk= zIY?Gu?EUSZ)sa)wQ?i4csyXrA&3Mumyomg?(jUwDAwF_FWi`0t+6RLF?LbW2{}=bA zc2Z<ba*cl5M}1UBP4x4G#ozwNx)=Or{};j_C`wcRrT)(^xYWM0Yxmo6i0f<8{e05S z&x&mLt?c_}_wU_q9LImHfRwC9{Hw|O-8*Zew$19_{zvjZ5qzhCA78_|2(js}eboQq zdLOIHx}O5U|A(K(2XcRT3g092e_=R{pd`&=1kJ9L31Ly3r7(&lNp$^+5e$Y9TR`~- z90vg;35;7nms<*2_twaCjVI9@w8SS{Tf!RCW%xEL=<}Eq+Y~kUW&}fSW{|+%a%+~O zX`nJiVsH(RJ*B|)*1!>HJF$OfzluqjZ7MXKgGv{*mA~+<3mzkY2q?og(P|20qgf76 zK1VkY&wvHx8uU^a5D=~R$i7U<WWln4E6yfDV%fix@Axb1@WMCwj!j=XmSXJ^FP+Eb zHHr+2i=W4-dmdtzpY74i@4D<Bu6dK1Fd(Za5P?}4atWp~zKh$~NPFu#`)+Kcx-So4 z-ihaI?vHDTnP7%@dz#J~Lw*~s%x;}}VNfrs#G}yV4t&MTZ&&>Of@_RAn&a0K=P3w- zv`!s<n|PNjkGFxRIJ7xFo=+9XlNxujPWLRfeqU}TZhP)=nYVe*D@iav=tt+={rPg% zrZlKaNEQ8Iy(_X_WKm_%DEM85Hn5&CaDhC7wnb?O&*mg7;Klrsc;;`uutvqwN0n~e z!s|8OUjHA>udbJ10?YPT<&l<KN87NO?^qS|by5>;3g7JEW_x|E@!fh}oZs)he*eiR zQKo=&kpzP|Plo%&bJJQbz2n>_UEuEDcnk`jR#-=%M^N#vv0PUxMcXb2{dC32a=GQ> zL_-Se5c5%WbA#iT-)9X1x&|(44^Vvf5d#nF<Sqfz(r*1MRQh_6pWZ_K%R3{X-~)9E zNMvPIWvZA3^x69lEU{Br>cDuLWD$=5cE37d%O}t5ZO;-u(%;Zu34lR}+0BOH!ur{M z2I`5hIJQL23}G!APo5x#yy_#V6FX#Y^XI*CF>l-}4!rPmyGo~gZ)4N_q&+NNAjp{V zjqLTTdg3WIX<gker#nRKi{o%Js`x?U(mr#ej5-M~D;HX&4PV;qPHTjB_o-vwANifL zhMGcjxar|UYrAfW*09>lNy`YlG7ZA>i&q~C-AGtKJeq(|-pAT*us59_bVoj=Md`TM z`hnTemYuvcjBTwHvTL41G#ie_k$d-LE8K_|Ezr)Q>Q`A_KVo>6-D@Ng*-F3`T&?kT zNDf#-HcOl&Ob^wvk;iF_9t>jlym-1CUmqA(qjn>R)UY#zu0Ym>UGLmXh@^u#@G>Hr z&}d(0DM1fHsn*YT@sSY_Z96b|hZpaDbzVPQ7li-uul1(_EcAT^_7ghxgR=Nx9*mRz zz@J{Qs|h|ra*2Q*&-e3uLB@Ri>U5|SV_NYDUvyyVrO4$z!PzFiulU;Bk3Wsm<R8%Y zyUU+$E&_-CI7*Xy%GWf2KHH}LVwd_MXn=l9?el7|GE4S`s)JDbRycE6eF#y%-F0V? zUWA)gOLTw@FwFUVicItc+MUtk67f7CIPRNyU(4r+-=2J+SWBzh=X%m;#Y$maFmXxs zj?dSls;z_z?Yk9mHFbj=zM#rrmo)LXYr=&u>5{tG)iWLYU846Cp5D)fY-eQ*GpQDp zBmQt`Zj9oGX&w*d44s}k+OhnshNJ0`S2r5D)U`Hi7<MDx!;}bhtc1Q&d+JqvBZjXp zcn!y|%xI4~s~jAND+bt=<5oRV<V*))4o8@{TbVP0hjeYpeD#*y7v=^J36A$qBPx8U zI;!PUknIwiYN*k$`l5N1*X&Rv>eTps9D?0lJ)S9I4ci1#RR4ZzU&-n^Yp%&}+!|qI z_w}2oNq;+KT^6-T`J38wD=8X4R-*fwmiP@@x!B6x{>hnuPW|hb)%5?r*6_jQ{+svz z%k&J5Z|yfLONv3}WTihe3o`dBD+A*l6Tq9O444|E<iC^8X<eQHl{7_yvc!5evR#H{ zfUP*SO`jxDU|b$0+k8s~$ejoV7&Lqcn*La7NB~(Qa=;}c0`%+vGbI+34x(+M(8|#= z6y$7T79?p_5{Hmr5g5JM9BzJx5ev%iBn$W;L2PQJ2)HxR=wHz~(FEQ|)BR7<GhZlN z{Zr24gsKyC68QZGg*zZ+9m`V<au%w%?!dtbD0(Ut(3w5&glDV1fPPJ2G|*T8kx^(% z!!+g>MBe{Yq4v1(SbR7Uq-q#U-O3T4mwAn`!SIU!eM0LGD^Uc7LH-g3(tN=RVCJ^~ zqLprm6LR@d9XJX0HZ4e;zRJJ1LOf(u;$jIm)cn%8x;<#R-yR!_(EDkaN9vfKJ=$ND zPLR0tpDyiht!$-$5a2aGm`1n~X9~mz1Hm2H?_wFGt=89RWh|lW_u%`Lt=!h9wq5}9 z%j9l7fPF=RpPs3*zK8)kd^l9thzOj)r|qr&Byj|NnmN*Imphol^Bo=FyKpf=4~F;S z%NJ>DxSYybDv#BI8Kihzp!9OLyv!9WR@bj0N-AyQ;GRV|kC#LCsfyb0?QpF{D=rlF zUZj445MI7FH9?kI;;2D+wo(Kbi82y7!|@?KNZj#RKgru=|F$UVjw}k@I~T2Sr-()s zNoV2UoOQEO7*QfN9TXRfdap8z-HF&m?CyrDXNXcQg3VS>NgRp%)@qZgV22kg%lf60 zZg?Kk12gj{yM74}O&+M|be=9xEWf+={Uc5h<MH+;yQhtvpziwzo7u1EHqEuJXv@tz zL{C;)38X{5&dw2%L_xtVs<VSr*Yo$7yIZ{`JI9lu)>KEPDK}MSJzFLG;lyy@ukM~N ze_8C{y06USb5`<vO8ec(DxK>g+w1ldBGba<_s79@yz%sfm1O*S>hZ-fCKv3vnQW4Z zlZwJz0}OBE*H4Ub_iw4o$wdLkHLf-5f&8}v?T-V+-w(9y;mdJ<6zV`<-I#J3uh+k^ zemK&)Syt)Zxe<vqQC8SKZbecb#eykE?r<)zet%BQs~(lzqrgDp7$UD9YieQ^;a;6~ zuaRE4>{7ymn=Cd4zh@VGJle6qRsKmHsz7`^?=4H_;gu>226A7#+r%o>9EQ5l#Gt=n zdx9G!N3T0JS%{fLwf@NMpE){mFs7?fFo;B`jf=Is9|;YmYIi<4p(#COVRuj2#Y3xb z*RJ7~9%Ni(bwS=&6%02Bvu9&dGj^6)vdn8HeTGZs4zilp?$KBjOYHbQe3g=+A5D_6 z=-EiZW)R<=cjhaEncEt-)SXUs%+7S_>UubEj&oL_nhw(Yv$i^6A)I0#hZdF}y!T0C zGve=SgOfh0uiXZ)S<`=C%J`y-`#8Y)*YjW8zjg?YlMIO=EJgpU82*p0^i4<nr&swN zyD5xD8G@i`jKJ2f2#GMC7F$^07mTC;I+3l)kH(-Tl7A`7Z&pe1rUuTbe@CA?9p+mJ zCB`=sBnqTXFlH0*Zkd?%x5PFU5Gd?oP!~z)ZA|ov%)c5KLXx0qmqNf*z!VZ{O95@z z4Ll}3dX3kMA~BdgNNvB(W3cRabD)T#O|FoGXSZGrRDW_{Hw+Az{<7F2ZIU|bn{Yt& z$H%Eg43S_yH;9OqpL(nu-=2huGr#&NnY@QSK}x`M%u)S1vO?gW`~?T80+3rVhh$Ik z#+4Z%b1~6_;H@Bg!>r}^N(?uS*@|2stMgnzX{*SCSyw+7VxX<Q|AEfJZ8m`=Z?yvQ zhpWVokNvRxO%eT{EFY{M`cIY*RuBD?uC6B&i%;i%GY-32HiOaAtvBSkL%y$DZM+r4 zzEhJ2U+!*kpbQ?j!%yf#8LtBBAlX$HhzgC4ad_L`o?L+Xj2f%W86u*YQB8d!RO@uT z12f$)isv17Qm9H8oYUf01Acrf%FS1BCnNWqoIkH(%6ejNAPWoWI$m5~$hDWkx_X3O zMOuQM66C45R_6XdEjiDMXwIEeU5Jp<ob(|tq-T6+aqT&)JE+(vOE6OSwU|<VNz@rz zoa~ldPr_MR%yFoC<VD9R8y0AO@x`ludRM36SRGRiy*%3(YA06>D8;;<-s`&>GY_rH zizro;(QO~g-Qk~bh|oKiy0Lb{H*oz(vZH*)9#gTtY8M+KSH|%Yo|q=WyqcUVVKj&v zc~Vs44Wk_GMn;oP%1bN;%k`BeUAdUU6j^Mv5px_c35qkO7IXb9-?WlNUS~=jrZuFe z!izjVs^-Wp%T7MNWyXIQL8k6oWpEIY@LaT(*kZ~cU4lnSV5NnD-*;?BmzISGPygL& zj@S$oGm5XH^E?u#y>c}@zw|`H#ttT$i(}YZgao}QQ*M|mx@2~aPKhj>Uw$fiR>Zd} zN9eDihW3OO6eDRX{)l*Fi%2ki&B-1%h%RoRe5IHk6L6NqJ%S_Wc#3#7jrN|&2ZlBD z{yq=$ZV<^zqNx46_wZ&AhU2dC9~drXHyWyr`ZW4j`s8|3XYaFo4A2JoR`#k)S^Tl= zB^j5i(5eky-swxTK-p4`wRzifRc!yNt4kTbPTb&&QF?Hm*I(5`cg-_7?xAaL(FbMk z&9=I?dhUl7uwQk6eJzo#M3yt44A+%W-rpT>R)fPOy&e-U6t8zoDs<t-xK_%bO6vA} zrKp8VzR(n*<;oat0&+sGGy+wfRT)?7-pLsp(=jJ5b@6(sh!$F?*HcXsA%~Kvog`Ra zWB!&FyKAHe0n7?;gyq5l1&^dmF1$6v9C2S@8XmaOO<)<pJX=0hr+U;U9oP1eJ{NC~ zjIi>$i^waF9I@zK6F%ga$VrMDPWNYoQY-veMMIAnta3N9L@8`VEMu&lZwKSq(7p$s z>pVv}i*r@^hTPZ+dXDvee{va4Z}x>^9gU9Xu#-ePhbP5#f=kT>uhk_oCj82wF}KbU zGLO3#v5WS^JfER6va;vUrFPf3!jwxih}e7(;TSGa^`hMF#QVs;(tSiJ`=fJi12RT* zq3?Qzz;+aTxIuaHR_e3zz+M(JB?ggdswfjt_uOl)ZA9JfHet(d@XU@w8~n11hro_s z`@8ni3B#aIkWQT0CswILA+}vGAxc~>b(Rl3lhh2yo1CG+eK8oy@yK}^Q4blX;#GLx zEm@7ky$6N+Mbl{CxHV+GW6hq3>%&`tZ?+@b_Bp#BR;t+yha8c^H=oU~w4rv<6crSG zR(6`^LB`yjwAsTmaXLk<uq;xUN=NDC@aNrFWLS4Wj#WL`r`BZOqkM5`E%e0%wv_c= ze&j+%b9{x@l2}fN_ontoW2Ok>LC=!fnpEsFFgB-xelF|c?~7<Q$;(QrjO+ah+7b@l zw}+&o^V=t~&wp^vH;v~XfBQXM!zqNsDFVT15@%TiCvb#VsT<2MEKQOWPNN7(;-4`% zeDl7_HkBt8gUT360P!Y80?`b*`Bq~HsB%&CuNuPe82Gc`%r>h5-}oP3d%!!Ip+HIn z!?rQZTk0eyLFxyXV<Rg&`~`zsX;-|pzq9Ptkw$_w03|33N_oge2+7ShhGKx8^o#Z7 zN*#f7W&(P@5bWz@xOE+XUS^wv=XMsI{-s<d1Pt!>O)g{06WsS#fz&J$i*~ufT;?M9 zTn;KhKWS(byAm%ZfB7i(9KUM&0gExC0DXe?h41>+4M?1<Fa2788;POq{cdvkm6(B2 ziwc^-X4AF5+I^{C8pK>MaBaDun;FZ`=^{j(WMPdhzh;XB^h=8xs1mty-ACtB9SULs znf&9UeCB?)T-lR;x16+pk;njf4CoJu4AZwWlAx_r$R~BNs^`0ZFdTNzPkZW>z=dia zpRY75nY(@REEwVrFFA7_!rMjg`=!43aG?8-$Zh1(h&ac*k>>tb368Zqu9wR#DLs;{ z*x;QlXDq*#3UqaqL}==pLN-o7w{VW_cWw4=jzaN_uDkkX_x=u^-ht)yb4r?FBOe7T z5wRk_D`izdZ|Amu9Ulqd4`e}=ykm?}a>1L+;Pu_`&U14YztC1UbIDZSrX=pNJ$$xE z!JyC1v~Un|@|YVU-H<GT)hW4hYMm+AP`5JGIK<LFaO2)$mSqrUM-qa_xKSom>6bMe zE^l_tLx<KaiJd_)=1qUxl=PLE!bBAQVOl)->7E<x6pDA`g9^Co8h)@?fxh!t$+x71 zV~XJYFL;N78?nwV{n>WBvMl<EqP3gw=*n>UJ;4Ei49D<(PTKiy_=s4mmy3~P!yIyy zp$5sXTND)XvfCjjw9>&u7U8Vh4@~tKz1=()*e#7m80L+Lk*MaR20IgWi(HA5V7W2O z)$(WTh<nX>ya&({3Gn;InP*<}VePP=ug&wkzR^C>5!O4E<lFdILXsa2XyB^O%{H$@ zr+aO5=ESHw5)jI(Gi=jBmyUBO+Fi`_vH(Btw#^<H|5`r_#1b$idxm712SIt{^X4V_ z2bvNTItfK6M_u#*?~jZ!`Rapt_7Axt0`y?;0~f+`uWF2Wxhwt(X#(xwJXRx5{o(Ce z`8<>bBSBTj=QvE|tg#!Ee7KMbZ0p2{5IM4Q{Nr2l`}%ZyrY+slhel18{8C?e>b&gb zM7Ko?3bTIwP+RA^?bYQX{{2D*Kg`dl>weqU;4AiBy5QqCobz8SgQFCVV?U=H{_)8l zSoMn&e`wPC)C!E+lo;5*zvTDVczlh@*FAlW&`Eal?TUc{lOVu1*yp7If(7V6Z=TQT z){e0LNYGnCf&qSzD>5aU?aGRA2?Y=f#XzSV%l-n2*a)OA)*~<y<RIv6ZfVSd7HO8) zY?rsby(9(WNkKJ&0r!h3(9#EFrwIT(&~vaUQddkuGSCi<ZcmV4{xX>mfNd6$e=iOE zA*|h$n}?rJ=in}4y6)rMhpykV8=p*M3Cy?Sy%`}7f;p|>!(vv+qzYX2Rpnqxh=yio zz67(cAsd^vZ_Mk@5F`Q%<=Lt@!d!~cL_dsMet2wz-0DXNa&OF}xLo|vEiH+^-_7>T z{@@lXwp|u;QE|{Y4Sm--y-&~ecmeZ2MXTHX7t|l&==#gN`cD%#tz0?3bDn2UIE<Jj zdvwt#a|g3f;s<fbN$F+{Ly8ut(Lz)?m6CU*6+71}of>g1N~z8&ZjWfMD~H4{;+=!J zqp*MAPJFJHaboDVqz||`hWXKl4B~+0!?9sQs=XW=mkBW^Rok1QMO{D$&px-OlCn-a zGld@keDLtxs~O2RNfnm&EDE7ICOgUCx2P@0Rw0W78t-87F8d9q881FLuc#^U4^2De zgJGT+r{*t_#m}>ep^35*f||44W`~r|V^>;-!&@A7XHGis3!X^o%iF))SF-C2FDqPr zswm+twuo>0xx17sZHJJ3Pp{`DFCO)|>-+jCu^!bTZtrwKMk<dcKlmt0wT71Ec{H}M zfMBlsx)#g18<_gWLs6Sp!}=l19~~ht)qP)Q;V~mhN<X3kAE#G%M5^cbQaH|+2=q~~ z+Sp8mx}2m3n$#`ib+~wX?2<k|UVPllsL&>PW9Q;kmG#oGi%#=3@0=sa_hXyuS2%y; z(*1OgLRRx4;|fWqvf*#f9U9E28=DIuEA2U^pLdR#(Frw<dotpD{j|@GoB%^WyuW(j z7yiaquTr_~IumcolLH-h?sYk8<&9O?5PP4!*BYMaJ!ez=+43!dk&eX012Ze*b4>Q; zfkUfS*5B4+xF+Mnf>;Mw|2!?KQ3WS`E9VKlUYMN4L!~oe8ja)AV9HfCTbFyM_*q8V zimF}9w9*MTn2ykoEgQcG<-gAbn0GFP`Rnarpr_}uK*KvVN0uTUYrOCa&BY%#mn~-| zavsW*5F5Y7L#>jArjIcvXf#6<^cc_elYTyx(=IDleBA{YJbCev8t$W_rJ^BCbUPgh z3hN*aLx#km-qYdGKWM}hqYT+0uQ{7m#zLiMJ2trXZFfN$Dxz8~sxLlG^I4QHR(?%* z4;|`ZtSwR`5K(<}N~feT>(X&>VmWWmwD-C7=@ch<1*L?Ej?6<CjYl%#?SL)T@caS6 zd3R0Hn(Y=;e$$TFl3XGXj1#?fZ@MI@w$SuznY8Jf>U{NfGel<Bw|e6~=Ep6}X-H2( z`n<=;8H=!<Dr2#hrQWXLOH+=!SN*yemsDtO<}PVpn##{3ne3P*YwcOpCwRahL3Q?q z%D49Ap^k^4j#xMpyFo{NYJEwSLMsZ)G0)V27t!4u2u7|^Z?<KtH&xGw*Fg&7s2)Y) zLVu6aE?B7uRt^2RGha0KdM!9|UO!~4tq`{gS0B{))Y#YZpyuu_AdlIwAr&6Hpm{!V z8{XMc)<tM-W6>cb0vfJtiPUD($DewdtuJ*jq=qB#k$kx5aTXm3OQ#{SXPNja@5i7Z z-PpMVa(G?DmwoPzlr}n3cJh&XGQ+JSWZIoeC^S4hU&j}zo4e<ZEg}3UMQ$+8DsmiJ zy&CA-!`Zu2nj|`$<?X)2igdq2lPDQwM0>Knc6-h4Es`VF&~L{Dx}azj9Mm^4;kQ>B z+xvc>z1fW4=ZZGX7pv8Zz<+W7U9yD#CuHewocuXi!v8i|T3N>$cB9*{Lok(MV@eqV zR1<6T3rZW=W^hLXsce>f?rs+W*+ou+uN3vQT7pm@Qbq~TAro)amh}Q_xW2~V@n*{k zZuKj7yDSBlTd5T|6ayV9SOgLSL<+vrF=(P8HXDPLdx0rf*f!sS0QX*Fcp?F6-}T2R z+swV=ZQeTuSXR8LH~t?XOMi&hzavXkfgYrv$kLa`{;!iI^S?=!^mDX-dVzO1_)JZu zX(h^L^NN`hj}6>D>U|YkoRiXN%moUKIbz?fpQTs(avQG(OAyC2E?$RQVpu&PX7@uR ziGI@Mi%I0ShlCjC1Ape{$H*qQ2w8aYa8K70+3tMrjZVgygGnY9ufuWFxi^wNujQ3U z{jPerJ0pR$B|E6Y;o;8h`(kt~)Gv)76q0iH5yxeF0j{%>&hP2FloYM*+`HbV(&IH+ z({ygU^X{r$us8kIdAxs@*zpV@g7!jdv=ff<5?9SNTEyXCbB$yX#CRCP@Nsb{4V|UZ zx_Mppw5EkEDxoj=B4u?lfp$3Oa))7JU5j$q(1*Fea<Kcz#^%GSM{km(#SJ=xacu>g z5)x&{M~1!8W@iqg$DAR(6qdzoAJh(QUo#aoGq#Tl*YgV5HC#;IDKvw_>|Tk&mZopT z^v>9ap82~dzh52q0xjx@#0Rx9*qb9?Wzr9&_nwqU*`9k_EsW%#QAj~wBJoNWrAdlX z^~ClMWh#w0u-*=IKt203dVYv$uq+?$r;5>p+MdrXV_lj@LleRSV{3!2A9!#*+k0Na zQJK*^En#OK7a*LNBvXoI1asQ(edNy1bth-s_lQsJb$OCGZE4GbU#}rtnBpJ};p}P3 z{g?;C^Ar?ENN0r!E0=YjtaK;P`q|>EOOF-;dVN)t%<z$ae{@Wowz?P^l6mkA&NSMw z61#n8MEE}^OJYVW`L2#(n&^h{4Y>tPYVrPXl;6TXB}?3%t03F;#G9#cm%H#LD&IsG zxFagZ9(3uQz8`_~I;qyYJa48kACHCJuveap`xv`=-3q=wlsNXxc7?&T(+k!PU03A$ zGr5Zw^QymE@)g69CYs}f5_@`Js>`DwZ$A9GvWfmQPiF^G<+j`HRbDq?c~H6Rm5isS zyUbE+DNVjO#a<C-mRAx{F6W0C?)OvA)F|Gl4^L!m3{o^>B<%~1>+$`jt*b|;Rz@P( zMzs7`h>C}v((sJq*XB^(>r<r6wIJ>DeQCq!Rp}z=KsvY*?3+GZ8a=4b!E<o4n>otk z@qFn@?)hq&@Nm*mQgXSdD6TS<oDpXwS9{(%Om7Im@yL;OZLjSaBf2GfYD~~bd#EZW zqVIXCW|(#=(Q+P_go0H}cVZOlE0JmZa>1zqO7E7Q-T3-O<b?9ro8=J5=z}@zB(u95 zir{j3U5_`5UfjCy<rZZgw>uYH1xHsG%DjotEmlt!FTzyM3-XB(ZX{>!P?7a_Cq5n& z<6+S492~7US#Gcpy&`ShNqp>_h_=-i1Pb8?(LBdP;f1b|mvJjPaCN(#Raa5Mw|Nh} zI+YDnIKEx~$qI<S6j5z(49q@csy5yNG|+6FS-PC%tag}Qf^ZbF?69cJ4K?MS+Ut46 z2YuVq!=*V7<qAqj;zi}-g}4=>_AiLo74*PP7K*vE7t{CGtB)vG8TfWu-jj9RKX=Ly zCjY?w;=kOi&YUdyO|BntRDYo@UpdTS{q;u+u-Nn)JLt0Cr+UfvSlLP*-;Vk^t0V&l z|7?))fAvn^>MMV8m%p^nNTMy5gMdsGu}$M-F(6-ADNLS$q63x#KPI3R1${xEw;YpO zr2+#qDEVUPn{3ASIPl1ziGR}wNI!vos7=3uqM-F@<z*@Q3oe$YpzyJBycFMtcM?FP zlW&C;d>iM2Y&QUYdlazWL$>+aDZAMrXP~x1XQ1x0-k9DD??Le;1x-}g%J2TVhB9u( zQp2CvXM7!>{S)aqiQWY13-|nBJ!)<D-?bS_adWDZhM%LeRjbn0=kmN@{z`Px{<4Ch zvT*5FPrS~Qemwcx;1VDm3D4?x9mA%nNOtebei!;y4K%GvEVI{3Fny4@4;uBIxfIZI za`VCUurGES=2z!FAY$44Ha>rTf9L5zfA;+T&eMbb?D_rK)BEt}fd0y$gR}Q+8Xm{X zReNhXU1Uwv<uM*=RzUQ-#ex{oC@B1@`ZX2bYddxAS!es>F*%-`KE1m9!IH~H;+^Yz z)UT7zv7tJ`9C<k4^H~^o(8-wHV<5L~hgk17S7>N)I4O)MKe8GnFP`-jY-io_(!7fz z{4l{L_1rtl?6GG-5*-36UuWz(cO>>Q7vE~Aq-=4u^pdM4wK*2oBlhCDy}RH<C|!?8 znB#$>Oz<R+&qb345(+b}^UbnAu*>-fE2b}4%gt7)XT#EIb-yZPgdKDWoiz(lLW=AU ze$hB=fMh~@u6q*_8_tYHyLe5?h2<Lzc}|W6=TzUR(*bEcNxS#c)S_p9NAYyY2&Y|8 zOw{thU!XrDFrR8Me(>jTP>9>5*a4IGQK`RV>DY3!?7esNVg40?S^14$;qNu}XR+om zLxDjJHyyiZWDaw&JbJ~Ra5Fnr&vu-5!f?LdURuN^Xo*Ki(`XEtJP9>Y@ZuB-J1K-v z*^wOb{?=?eo4x2+v(&yT`>`Pxti{C%KX=m8S==FcDs0!z?2z??SM1(=gpUD^KvZ#m z)5il!jzRV;DcwVr;6^BBsvWT*ecd(NM>78j+XA(B=F7>H>GFsu%4y_KG(Wo#i`sDE zu2dp;MIFr8$1HARR#DYkZY(Clo1qcP2lM(aZkb$>Q8%1gK{`>nXB`IhUPBq1U5{ZT zFGuxm?a|lmiA8eHjYN$ec!STcGY_YX$krF*bb3DMqjDu;O0k8&xn?}^gxu#*cuKYx z{1bOsQT)l&2_RRSeJ}iU062jo`Yu~h>VEBRS$7-$&|mx?UFlnk@1I}g2dG3b95nbc z6is0Wg0Uz=qbx=dILa^#!LI*EhWd2w7=dplt_*0npi^LsL2PKWLK;JW){Yf~vKVMM z*8`}}0X1O(9LJlsVFgzP0ha_dARHLg(ln?wVI;Urw3*Y=F#zafMZjMrH}K6@HjY4{ zhrmEViXnkQV!Z(<IN?Ciz<%+8WI-h;*<7_&LIBJiNuX3fHvncyaGUiyD@6dxh!}iB z|D~){<N%-!-vHJ2Re^jc$No6-=KN?b1g_kj|4rU|H9d-D(Sq;%ihftj72fn42roc@ z@G&oVD?osR`Sk-zQ(4)WT~&APn3##EtWQFiBMF_o_C9;9^&da!Pg4T)b5jCuT0ck} z=5t^;>c?5~!^rf^EpVOnXikXXsoDQQK)i9Cdhx&YVrHgo|4NtY6M5o?{X?nYOZUT% z!9=D_Uyg;TH$-hv9!{fPB%j?5&c{KXRlomri(FSLdOJEB0M$B}wqIGb;?IN-hyPKG zl4TmkUOzseAF692?je1D(noHyg?lg!5oh~>s?4$s#hZU-+kWU92RUSq$ZK$C?!fn= zj+xJV{$uH+X863BL%5-1czgw}{Y#N6;MYNvl_ZrNQPokNbAmRR#u4vPVRZ_u9s)7C z%2T4sp>ypONMElT51w3@?uj~-t4K{%>w;l#yynkB6E{9op7y9l#G08U7YloAgUY>& zw+Nr@{(S?Yc529~T;{8^67Y2mZ%kp69Nc8*u~9mB=;yfKBpvfsaCuPR*&BWQx_E@) z=lA^^0$l!0ZDIB3vSoft_&ugxUXRShP$3Lumtu5Dsdjb1+;L|L@nAhP>yQd`jKt`{ zI46KQ-N>?#t%v%MPYaz`hdXvbx$K>vi_FjS<qW?HlB-TVQnDU*KJ~ZGpEMm-BU9Bl z0J=EvI;0x3VAtSbX`brF`ANK7q%tHpydo_$R<vdmLtgn7M05WzT8}^N5y1bH<0hl5 zZbdwuVm$+!5sqZWHS3<ILCif+xlfOBvWK^m%KpeQRWCn~M%n$O(slNaGMg>Zv-;zX z+>bk6=r22d*{}YOJ`3QFMvFI$skHVi8gT+4uRG(@i{PJov`gWWSuH+Z*nDU;Lyqph z|1uaBix&h3cvGx+?R`u~z;0X^T5<<&AeeiyR7Eotu9xbG)}TobF?OfgPwe_s8>!b@ z%R48}gT{^t`}_~mCQCUWDv`qEL~lM&r4kbiw5yE^vT;LB#LTm9hB_S3gb^N{&l-Wg zY}gBU-5ZUyA2R31t9uF*My+b^7JxBkCVZb;O-2wf!E>0^&jXtb*r0B4S;-@m=2R}Z zKuP<`^b8c~QrSoaD}xpDHe#KkaV3o<S-f}4Z_KmzQvylyZHwRLI>gjUSH5VH=QkiY z7ui?0UY2cr9>;`yP;jkgY7z_X5`cd{O0)l)W!iV^Uw_I?4@Ts__P|H&p>^NklXo8Z z=udI^pC0=y694z({><e-aPXJSe}@3or?CP5c*>x}!I`8!TFA)9>Fih=_{b<C$#=7~ zpA%Q|<ER-Oy6niO+YdpGbeQ}cy$3hwqp<-~M;@AeT(q(5&@#@z-^5w;6SG6~!@G<R z)3iNp#^Fyh$43PjLqAej*oV`B9}5*JdRTf>>2XMUNJ<`p9^q%{;gD<oFiZ~vQ0U+B z-ymZiad!D0XW5IdZ@=nqRypve7-aH*YT7e5f74%IIOVGf{I}%o53#8|A3J)`c-gTb z<9oOSqR*-WeU$B)qrYJffAh`yqBn8-Ff#1<#;TBJ6^Gu$`tvs6SHt=zqXK?4tY44n zpD-D<+j<`<+&odxW7Y9nd3J5il{IS+Lh5~jXQq4JXqGegTh*q^%(DBgVcpH91lz~s z+<Bf;+pETFg=}}OF!X%L%*It@7-2aM)M`g&VJXW!8-;=CE?&K@p&6dq6O^@D%2#hN zM4)w+d)IGwu`&heVlh20-0sEjwppt8%;s#yx=8z!39NU$i=R07=6yL^6h%~o_cfre ztK+FGbpwSLBx+87C4yyRE~4=qK$RnGdM$%-5k?hg_@~ooz43U9=l(uD)X<V|S2h#P z6MDH5TYoBA`}uOj6C>zTS<hr2E|x&!Tp6~Q*#qaIO<++Y^Z4l^9WjlY#0S0sVy}pD zmJ8$|;aMSe@DP7zGG1u2J79%-WQ)LG*1L5i+%Z$8YH0B`vCA!62Y=OMR2R74DB@oj z@JoAP#z>-~N}{An0^Nyto=E{731$(q-CKdpK7KeAkO<V8-mzNozT9nJr4U%Ff{r`z z?l_t)ThjdHCbL)dYYpPqrmj2M**7qsC*{Ehk`Ct4Xl>B<+xK|QgrV|&Sy<gRc^&?< z3;bcN07vjwaQayK7%^r8XPAyX3A%eIoY1(kQb>ZtuiyfKU&<%gEAWiBkH{mSz{Zq( zX@Je*W0*WueSQlNxq17Ey-m(OzlA$i#gG4_cl{8kPaeFn60#$v?9Su4$liEH?n~zG z_?*EEiqfmxDY8}h0gJe%D$cB?Z3%>Nw#C|*^L}Ko+2u6QJXEOIsRiNl1k*&T>sK+A z(@-m`Hpm)7VDDNfo<QY}@>CB39dfo2;^NcK<sHJ~DBsPsbG?`B3=LK(EjgWrdp2yf zP*?D51sJsWXTh@@f>6&F^a^Yj`>7cg>dTyySP*kw)l7(s5l3Z<xkj~hk+sTS@vWIQ zLfG>H0Wn+NBf?mPXLKb2U2-4c+&$RzVm*Y*D;xc~LHokPgj>){a<N5PiH(!~4orw= z?LA|r^0T5|#mOojh!4nJF+-=Pxmh^2ju#_p2El9127<Ozclrm)4!;kYob!JwR{!?! zzYf=55B-mb{YwvnJ*LI@k$}P<pA$Iw)QHhTfpX72u`e11A0yQLLG)|FC50a?|9e<I zD!$mqkrX`S6ZY7dh5t@IvXgsWx@WLidN3XjX$I=!@q+wr**`rD752D|e{>kgkDWJ( zA0c`_av$5C5W^qUO!(6v8KuW%cEFG!$9WIEOY}&f55fR?MEgBU-d{>Sk(~VNh;1AZ zd;L?y27ei`dHSD6>}y4L-(sU=|BZ-kI{t5>wmoZX@Ke;bXW-cQtD*hfkpaIO+V4m9 z=g1BGSM^G{T?*EmU*!o=ub11~o4Jj^%D3E7d7s_Wyl;V~%4MoxZp~fZ9{wI!?nujI za}cjrr0R3}&Cb+t<;N2hV6y$1NOh^<E<atPT)!kL2q2aY`IA^|X4?}*p<8_ULJPuW z`O$Hw9Dk{XA239v5?847k{hd>gGLyw1}5)&(h~qr!&3Ql$wM}pF5(NJqLW3q{*t4c z5L<WADzfK*zRb#8Tq8tF4MGvJKmza%Y6{$#Ku=(gzU%PofQZ5%7QB8r-3l1npw|+< zad5Q#ynB!74PoCkR#26AbIH+r7v5#M-XjtabK@jlS)V1Rdk)Ja(M?tpTzUsrp1$Gv zCmZ49bN?Dr1cM+E3Gp8y_uZHe(nS8ZR;sm|UDiv<tzDpu>pSjxN}JLU5VfWK^-A@H zL5%N_+u0-ceUIE?CkfpCk11Me3<Q1#4z;g9Xx6~hzzC5s<?${28LyA%7pUFzKW?-} zt-f@+9D(@gegR@cZH|J?X9LI`kJnF>cKpv{m8CI-BPsLp%>d~L`=8r+H1^02m=;z2 zScBOgH_3zg>Yjm(;o+#ng}HfUE=B!CcIgj|GGhY%G+bC)qYL#NfOyD9gCz4mjXGMU zLi>pwa`j*b_O=hccmYS;{|%k-kW~N)ZwmG6-7arr$a%J?5c)~iyVSl%Lvi+d0C}+s zr26$GZJ7<SqlsmMtr$*BBRu%fm<U2v-Yeb7_6}950MTwmjX>9hi<2!KK@4ce>r{zc zK{ov`P$X$J?tARahL;{#LXJ;0BJ>VM^aw0%wGQ4GBB<Rp<OC}g$z0=s%l#!J-j;cA z<I&pmg0I0U)sq2<uJ24IM9?YLfG)4JHVIN}ObAq|p1LvMnUyV~4S}Uk1yE90jFYGH zz?K1r-sD$8YnKqZNUe7fwCZ+AAhFV)(X&cgtkDw=W=fw?kl^V7S7&~|JDz#@+Zk`6 zoaqS-+7L^5s?PgbJ>-}3o~ae3SMk{{(W3Bo=<oX((f?x0vCO{&QxiU-?&o><KgR#@ zvn$bG?EBqY=%@YuRLKT00!A<p2VsOl5QK!GU#<hg_)(JHbKfI?ehSPG@v$?<j+FKA zn*G#{!H*U+_-pCuJ+Z~1qbi+#G@g_6$Zg>dXAb{JL?1dw*pbYlpU%7^@Ds<XE%Cc` z;1oWxcQpLC*CwAPJn*Bqgngnv^f74wk8poTOj8FDFv$+RN+|ne*U&*)z>#BNI{ehE zspN?E8F?r^fPZPO#)n6+fxh?T$+UdkXW!Rcj(qj&AT525guoZ4Ax%+Db>_a5uSIU| zFY$v1_o-k{7lPu4*RK0(+`hdJR;Ex|^|eR$dgkYE20ILE+?j7Xd|CJ8rLVHn+&($Q z%k7Y#w(L#)(xbQMAb;LC+dnPm+Tgfw8*P3SJFqUbydINPyw5SogIj<<UhMW4j~AMD zpLbvJiY|ghd*9S0xg$t(Utj-frC?Xm5f-H1*(F@Q6q2Q*kbJmpmK|x(mn7u9J2dfn zbeWM`3TUysI3CWN@JX<5ER%5!iajUHWw-E*%yCPV9^K}r5ac-A7N~cwj{79}4z&B= zg_;QH?mfcYGF-+v(uwD3>_(6-ao;gpvJy^DkLuN}23aZ8eXzP)P9G^2J=1)(WWtC@ zzyhz2AyJo}*g7obAJDX?u7t@1acvAa%KKzUhmU$bC(5h7k(x}Mvc}Uv^zMZb6QzJ* z<sja@NifYhUf?Ff!^Z_lZY#vwCkVd_%*eTqN?2nHpO#zxP-62+WUfOlWLso=Lce;a zqDE__@zs=rQ`)>fu6WD@E=KwV%oW=CIqzA0e}6hTsac${Y@+d6&7L)lYPbQ0fICBW z7Md&cYS8;Fb5Cj6(c0aGHne@+#ZlkpOdpiodBf&g*ASmu6*I(`v|T9(21JSul2<-5 zk?yvv<u}t(6d1>2oFS>C7`}|6fv)(f<;d`=N}Rp9QTuvn!2|~z70Q5-`CQ#~{ndqr zTd}o?2VP=>*ydYGtxKD<?q!`HK|T!}M~v;G7#?9zUpj0Nr`)z#pgaeyn^p`{2ow^Z zXu75vLo8wwVx`B)&vNfwo7W;Lf}up3!CB5VZVG{dv9g`r%n@i6^`@I?IabCUYVq~S zJqXb2Izz!rzBp$X8)uxS6E)p81}<rto(r^NZ&^fZFWrKG;pto)WQI9^A-vIGTYtgY zUzjQV%AxN7HNbxph@65J9f*rfrD_i4&uObMx8IX_;|2Z)(pA1Tx-#^|-&0Ap4J=*C zA4JeHF)kqeW6VW3WvAXN&(AYRU|03#Umv^*Oc&!`w$QXsbx5mtS8P~Q8O2l~F8jAP z(9q`JBHvl}uqbp71U|J|l@ZG;HS)OipBW%@z12@80b7nUnj-%+Zig5MR>*4UwFE;I z^1VEDV?b;tt=`e6dNxP!alcV&&-Qf$H1DK%v2X551ZbofRdi-4kdV{FJOxcyj?^?1 zi^UTsiWf%eN(O{kI!Y%~@NKT~YY3du=B{*8&OP5G<uWd@FmXv5J2Y8Y7dCDy;gV2& zW-@kpRi?HBhWDUqY;1*R9*V*Su=r_N(|mcqa+ImdLU<`paN2(qP9C07`j)reV<KxY zqKWr;tCoi-auY({_=Il49kl@M{XH>RAei_z%{pt}PRdC1K~yu^O>BG|C)js0yj*D! zaI(G$iEww;O93GZ2)!l=0rIV|Zmdsi@YbK)@doN6hjSDH!8Vgh`%k<=3;)fZeS}lj zfZ||0Z@bn#MICp7NOk}OEZ5^b6C1lhoh94H_qaKpldv<=^V7cGNtiC1lVR`ABdd+* zszs>&;)&)7Ig7|`1UB{7;4XQs`l*?l3qOUo++Gyb@sol?g%`&K#oIQDmnu<-N}XiZ z!$ms2JvOjhU*rNP=sI!(@-{9Nd3DolEHphREzVxrUMy>eI0e%vl2dR-wuqS^^QkxY zBI|oCR{p*M)#c)tv=kh|kjLYr8BV`S$HSi$rvB@m-xZ|3?e(W}1qqWFxZ@&}KuMg! zN${7_k9*3$BZ-5ikRFBn9b16Z!J&kqL%ESiKFw+HQ6eDWe}nL^YZu6IC=njb0TA}7 zg=7cYVSfr|N2P*-j*7z3q(*-1I^tusA4hj2_IrNkp*IO0Jka#xca?k~PLv+l3Zf3~ z!Va}|+>;Q;Zpnvr0mBE*+W`>t88-aISMsATl|YB;)j@jLhw_*3NCdabg^9k`E+lWf zA$_f#`y2f$di88nf7mqv^gPRlF0#|e%-!jhpX{29JJ>J=sJW^E&X@0%1oP{*aRz>D z39!F;&wflc?D=M?h`J?TRIR^w&wk&ga?-+8v;lmpj9d;`Y$&)Jb`$Pc#`rp8bC-D* zZEpH9%8Jvz>ggRl2i&m@aDHx&bB+eIzm0ez;2FNozWwxu_2dP84|)_EG;c)TbNvUg zkeRvZ7xSuTj|t5t$4Yo_={1vozsOvz9-R+}Q>nvdNOD{bdpc8%7!!II1A%beUFT+b zWgHWC_c==@Emsi|gwOIxd%|p|+)dx@00AyLJ*_}fSg9^n6q>+Qy-?{wqpo+At)zVD za4T&EZe1=0SUD}pSxM~`OxdhjPXmpp4_l6TI(=hqJ$UV$gbl;Ri@b-C-dt#6-~O9h zwd+-AJ3Phd8g0P)^F@RxD-Fc}NHjTL`MZ;y*w>c#k2c|H#YM{j1H;*{1MqRC$^ML{ zgnBXFlkqgcsh-K|Nk$BdDQ5t@N)F|ya%^sA)4Xw58KkG%MH1<O<cF|}=MW`@8%IA` z!F}!6L!;*5d1K{ta2G5Uff~<*vg@`6rV)<CJ^g|9d=eHcB}fW$%_96+FSRllp;9%r zZqa)pS`8yXt}48oQ361(T*H9nu=)*no=ZJf&UEweHsZA?p#mqRsxBkQF1UJzZ^|pi zH2w_T9RGoAIHapL;DNX%ru28EXii|}X>QSyuRMZJ(6zf`HHTysHc6Awfmm5)7g5%q ztT77WX|kv5y$^xd>+5jZgS4P(`-CP_KA6=~z4GT`Gl=T$_BX*#q9QSdXX*xU$x#bF z8x55AVcP2r@UlnGpij#*v=CCCV^q0~w`I>hB=c&(cp#~C9~%Q5d_z3@?YthP%Q2oa z!<T^XOa2DO#TN5cxgUB7Hu@I@55Dpd{}8Hw2aje10++8Nw|ObxA$3~x$%ERI9~VVj z^Bu3$>bni@yIPf0+{;H~P-V!^g@CVDVv0ihex(T3w)lb-KCHpY!`c4aUufM6!m5xh zZfnSc0q6B(Fe_3k20g#6-=I0>OO0#Cd%ntqG_PI7>85Aenp%L91uou+jW({TSe>Xt z(LMgA?!7+_591xz-{%0nWOCCH@AOCY-DN*DO#%2p;`?&Ez%%%THfh>07>E`PI+~f4 z7HT@!-z6;=v_vyCE!f9j_V^3LIRk!n$eErNRN6Ooq`5yQXXZs;Xxh&A18*Rm=5&6X zATW-<^S<Bym*Z%_nD;aB{(eTfJ2nI})6fD+`}1)^?#C<I$6x<Au|U!h&Ae$LrUAm( zudrV!{hU$Vudok!A9`pok7FeJ0mU)0&|tUY#QTZ(V+6r5(tW@EEqr+){0yC=75dAG z?gk@#-hx4cH0#qUO)oUd(V9WSG-uOSgZ{k5<1H98uO4S^zFwg_&YaN9OtT%W%=DWU zV>+1`gub9(KO>b+^8Ey#4{@XCKk22LejSP?_*o$QB9Z?6hEm|A3E*angu{=3dU^1k zxbHhpD*vUgMx4#t{#%&uhfF>f3a0SqrMu6qTw=|BYd=DFY4+QE0zwyk8;8`f(7+L* zzWpDX)dFGvT_AE1di`e<szcR*C%wMZ{(hZncwcU1j^o%J;Tp^5KtuTc3;bP^&K}m~ zc%l1qd$zUqzDGUm@(>Ao?t<x}Ye}#9QF3iS7=kf2XYS~2X<LKrlOA9RkTa>r2`20w z?%%=id<0OUlB%pj`}^w7bf}rSb>(}9RH>yb@f<l_GXHW1BZACrKwd9>z*%Qy3ZUm> z(fs{pyxW@XQ$x8a{R6WpE^XdH*l~lQIp>qX?OEg|5q4>2?CAl}>Y2NG>YfDPf?(kZ zQ9P~!<<5kUQtf4+*(9femrAk`;xznLqR$u-W`m|GDy-6;1>Vj{7Q>bqcNmV=Abptz zS%%&%hcPjx+gsN-6LO<v>wa3~W^5CKmKQ-ru11ly&0_?n7N1(kn5A52#Fnqm?;5@I zzK<A^JzR8!Ddw~nVU11D)=0|<E?i{1=*bnYEVy(<fJh6+<X~xs1*byp(Ls-IPF>%i zN^PLdG>pfba|QT>BAg`K3)72C{?1+KfuWqKU<DxITi@UBD(7Ep_jxT}c6*<b&FoL$ z!rj+Y2%{J3c*T4hbk?_Oo=D5=>ZQ)z7Km}9fdX1+cw8MF@^URs(L%vNFNW}Z=2xQ2 z9^L}KCf^g}>HL_3p%-&mY}e<(Ly5N2!UG9%@@1@Bz57rVH-di%{<|sZ{Z~}6GL_D! zj0mzAF<O*Vc)l>(^`y*OJ|VAChdNjUdfjo2B@7h(UOR&Uz61_gW7*G{SKi<v>H0{| zWs%8(lcRC|vqXL3pE==vq0RizP5gJgZ~yLre{#G1^Fe=7LWA*N@};wnPCStwhUw{H z$9^cY5Xe`GG6f!3{;-434t5Lmn}yT(D2t-xky0EAXXx?&1Ua&e{c%bjROS6Kh8?S> z5OP#l57n3K-#GR=rCRE61^ROJ?Bm;xC5K^roE&SpByl7)RCd&96YOX*J`~QPV}$4- zV|L^m8S+tRi;k)>_^A%#pQFI^-%#|Iwb>63c>S(Be_<8$mkPD^PeNi2A1}ax|GyVD z9dl1W62>Z_qvQ7v_`j&)51qjAH({}ZHv>3)a@1qL@=)d<T86(SA{7m*RXl5zgsPkN zV<NI>mW=_QPGFw<$(P>T=PPOEzS+{xjlCx&o?)Yt0dmVRdw(;#0T}43W$pfg$kO5W zS}bIGhhV!2FK_?BkKe6rLGDk<3Gf%$$;>2g2}d_B>binJF|8H3s|d+6;lh_z&UgR< zmz!y~iosnWt};g<mcgFov%<J~#L<e@==WAyZxc~q@cMSb_w^Qx*6TWRVm;kA0Hl@7 z)&pmN{o8tCME^n#YE?sa)phx~Ao$VuUxMPAt7~p=I^b$}^3R^7BTjbBE(M@6^Rtu7 z2OlA?vsuIB?P?n68DA&gkikYJD1;$>XMT{w^U3$@S%8HI(R&Sa`+eRQflVqPahOKt zeTu>j^$0<D#@;4~p@Q7g+L^4)?OYM!vY3w+gyJG%zdy3eHQJ~BGKv8dzjn3TWpmH- zCBHQfrC55?4pwi0xOkZpj+`C~Y??acUa#!wg$B=6@8b(p#Y;WGz<M1^*i-dBGef$o z&lZN3`3o--UVZA0+J+`HR+TgcH2v^l4z`|}Fl`hyuJ9NIml9|~<+f4J3pU4~5Jdg! zB0R4i{<tal?P_;L(AL>V-k^({rO;%E=39NjFTd1aR>>n@2Ri!Pud;J~L$1kqgRYw% z9Z{&fgC`c+jA-L74XKn-K)HTxz1l)79r<a77d;;mWk+lbyJaute#5m>U%5+LS86gV z*`1IT>775$%BAL`SsvQgiF~h5(j^(A0{J=i)76S%4tV<aN`0PQ#AEbI;<}t4TTx4^ z^pq268w+hctHK8D@3FovVu2wFisx7_-I({xOOx~fP>VM+ONrU9?mpeB&XV=(&gdUi z=Du}N1Ly7cd}wdGGs)}Ziiy`uNqzBA!<|Dsk9nb`z(v&JTmhgpr%F!@o|VSng%L%U z9eWAOMey(}bjIA6P9-=ETqY+<6|voZpTByy<{rlL-ap3{P>Np5qZ0>-bUN7C>1;m} z^~A2P*yJx4?g~GeK1L+%U0J6_dQJ0!LJ)psiIa^kxXS|~{?@hIe7@?aN;;`vjg3Ps zn+;zbifQ{dl#m93@;AwKm+8fMY2fh8h-I6$2&JoafGNQiC75%^!pW8P*qe7j{dUaH zsTJWyS-fPFy2OcoS~s*t0tRW69CfmLYuv~LBThhDHYr8&rq7&HIDf5*=OPAJTG%<j zmd;FazR4SXK_3!H){r<EGA$yoS;^{jiw(B`Aj}9$R#~LhD2J!}fEl^BgiA%g(1Fm* zs?MkMT~cs}-(Y!Ib(+er<er+F1Bm%A*9Gv+thoJNYBFIWPUkr13kkPhDE@FqJX`50 z@+32RjB{`fUTI&J62X!7i{+lkqeLwiXh&tpmof{7F_Hy(i`8x1;r8Zf4VI;+Jyj-T ziBxN%aPOl9o7Nf%Z#URvMt}BKtODi`q6%6iIk6N3q^%ZRUm4lXhw^q=6cwk1>lv&3 z8g){9S#TpsoJ_}@;!1MFmbx1d3Zh|_VJ|syucYH^IZep+^zq41Hw%eO3|eg3L6lUt zWL7!rT!(tfUF(`#I-H-6bx*`2gHiuM2e_3sWq9w}bO^sgnfFmj{o#e5(a+yI<U8*9 z<?er4rlu$mg(w^+Pza<z2qY*R-8aD`0Yd~q;v@)R*e`Yb5#p#;qMxoXh&;6WsT~*L zUlB|UA6hM6DbCox(O;{{pvZxFq60mBY!9)c1B{9e34Js@H1;X@qrR6N|3}bI&pC0F zdXe9iW)Bl&>S!v@(xXV6kw-5$K^$j<k)viDehiV1r|{vxxFaa|1HTT(<n+LM2geIP zByA|<)1?j{>*zba3Xy-4e{HsSJ4y=c<r_LOY1uvTPZm+?Xi2xnC4N7ZE%1L?rUkT( zvsFg=R_s&`;%(^iRs`>P>Vx}%#jC1(V>Xe{6gEt~4xg|CZUA5LMxIpMSHf|;?C1ym zc;m44{Dp8V{drqOBdTf4Tz=48KE>Y24&0^p9qk<*K8O~VeXZXdEH3w_QT+kI?hFj5 zzfp<#rAUl=J>hFMOQF7n_rS?|ga;fmG(8=8OA%$|VmE=kp!%CQ6Blcqaqk|tvk_$m zGM&6fCbrK?aW5r~Nz-$t5y61~;?ip#DTvgaX|AZynHw%km_747bH@2tyx-zr7$`m< zI7FEJ=XoNqL4?^8gzu+0c|bs5O4UI%1I4K0)}U5_*8N85=%hWwr=<%+l4_N1PjpBL zv`8hWY0#VpRXoy3#Bu`8l~)iBLp-gECM2p{J&M+gNU~W9>$NuJ68C95iefWakrG}& z5w2O{Hk7u`sk(j{0TNOtlGz}_ow1vDqxrG8@A;{QvP6tni`Xe6RKBi$D7{WtM6JZ6 z;C%|-iEQ<SYyAL{Y3}X|or{`w=G%B8+!IZK4`Tne3D2!WNG%|~I>~PLMtCr@EnU2q zUVXAG*nbLQ3fv0fe&SIURYh5pHmkA`tFgjOJG!5+apQG*k{^?mNe@*W<rl$%1<kf{ z=T@aHsV`vMLoK<5`EWVc5iDM8qsH`ZvR={D!qZ~Cydcneh{f(~zR#$6ahJ`BjJFpB zItp&0K%XZ>Zu>AJMM-LTVsoE~@v3@S>TDum#%_8J@q%emWH2)9v`v=|xgi(j0lly* zk&VFEaQ6mMdv~&Cu3%$pz7kw7z5U5JhqgwtNkqD$&6G0a^YuG@?J(7x1(|saut!`C zARN?7pI@anp@~^J1W?v@DeGw8_+k1+Q@?AyyL{!0>AxmeTXO}~D6QyFg*{zX^M+IV zdh(~-;(j1w0^iw~UlGy!WyX65tEqi<IiFdJ6{@-h>rw}eHX^18>9oi8tW-AJphq4x zK(gFT9D|q?+s}CO&gYBBco|!ZP>Lksqwr?wai%hn0*TZ*SBS_(bh@8jxkwPnJQe^H zrdCld9lF0QZS&xQUt$!eE~$>Us{t8!4s*#nFbPz%mUcL^O&}{Bg+uxFkRhuAEThlk zhoaR+=JwH9dbsatVcN$NJnD1KTTSKHJ<iWbM?dJ*?@=~_sgkkKC7CrQO#mOx)9|#h zmLH<rM!!AV*Y?lV5%4}>hbFF!KpMQe=#d$z?inR_QbftXQ<On9G-e3EKwV?;dw+S@ z*ObrJrBrn~sq;I9>L={VC-**%QD{o{WM_S0{E!C<y~q5~X$-h}O2BPxShK;sD`eel z_@v!mse2lzg{`kjrh{FlG19t2%-mjyuDx0ESPiV^KT2g!R@4&#yq))ucu0Sda6w%c zESa0W_givAE=GZbI=Eg5W5lU=9&@=IjK>DeVrh<>pTJKub%BW_wfg<K3D<{zPlWXR zV7RyxFd;=QlqD`VyOipS2{}wSZEp(=O|!mbuj-}rv!TW<AS!3hX>{C&J%e248~=8O zqA4^%vuf7Io7Q=mi0Ie$o~d2m?_k1K2zo^ZoaRBfI16yU!U#SUL8;x1_Y!V!`WRi8 zw^wGx*HOHpQJq^7iPz|(>D2WMo&%^CT{m+4e?VOS->g@@LzO?X#lJfZ?l9-r<9~mF z5R~n^ag6XUrfkY%1D2JKe_3hWc1>69aCj*H^-ljKmfItpKF{d?@!2i?A4i4g+l9VT z*XwXx_Y0}%P^Vk@GY9_vEra?_r~mH*`Vrj`2d+a27{mz>fiV=puwNm$=wpL;wE7`O zgME}72#NTpxRBxDTexF1B>dP>Q#;`MHKh+a7S<03#E;wc4xjM!C^S)@K7B0ys2C?7 z=WOId%=-}Nu^q|%PDJ?_Np?U&_`?%SJ{^nu*!DB-+p*+WWRE{A!|(&(V(>$7KtBfC zJ4i$hKY}#;5EH47ofP(=^J9ll4if(rk`wO7B0KwsBUAXuPc1J*EA$^_`%k?qkN%?v z(Y&h$dF=e@L1gKGi5^pNAh|s#oW6;<XrMhgqQ|w!j^a4yVy?^u2zLOs1XLg0nH`Kx zuLxe=;iDN3KDs0Zjl>mw`hc25SauLr=f<7j+Y(*mimtzoU{po>IJ47!P}=vUjC};i zhj*{-CmRB<?|&w>D~<^P!Dl#sB1iQR{FBq;moCWd;N5GVZpa$^qEsktz=xE-ec$+} z59sfFKEQwbfd0<s1N^rS=<j?!z<>LI{?6y~k4&Y|w|%Z>#}qrKba)KEoNXUq(Az6} zQY1y)uOaSK#`eJO=Zsw*cUcdNmm@Lvn^lW<@SPM!0vF_ZRxn51M7Y(XMFd!^m`~Em zi|zeZKfuV)gn*4EC>qN?#0I)xh4)(P%07*Q_zr)=S%@G5yI!t+RJV5?FsK_nJO#<c z@eOYXh3|XBRLg>D%x;@-y;)zl3(^->FuYlDtt}N74vucD*uKGl>wqV8%DG0G<K=Oy zPCF9974`)VGhUF+^M*Ft)f7(5SQ3PKGl*`Km5NvR%@*|{2^53{Y6$K6jciFDO~JJ{ zm{4=z_}$(doqou;>Ihdw9#|yvAre!=G^k}Kud{Y+N-cQDB9L9sJy)S)otju#b<ahe zU?Wn;6f}U`X&F!Kxpd8wL)6mg6~dj`IdTI=r~4-8?)aL3go`sg5D;X|IqAvTEQFM) zeSSugE4;(<vAryOJ_*|}p`@J>3Wv;0h8j1|5$v{5RbVRd#?osnW`lP#b}yDQoh2S{ z&$w0y71R~~+-T$3Pew2D=kvR^>1Xxig<B=~m?@ILrcAQ4L+V$;6pshhM7M}tHw?OG zxZa<x^5SM*Yx|Z}@$hZEZ*9Rh#dA6n3u2#?tpx_YkEcB*d%SmZBBP9*DY~3l9l0_^ zaC`O;oL_xB%USD`57g}mw#3^G*@u0foVu_*z$RZvkYf)^udu{k4Q!F;1+;%}Ds>?$ zn2=>qUhEyS<AA&lr;Q`-IEUGP*HlV*>CsrXM$7L%CQt9$>zh!mN$IS{_@|~){GMMA zpcN%NT04*|o!|sgI#J7w8um7_sfC_J(`&jUU~(C<8-1<00wrwRr?K{Q6)q+qT6FRf zH1c`#p(z_I--{klo+#_%5ssaSCz!_b`&S`r7oS^{^9!e6XB$(Cb9M8sPahCwFQ>WS zx@W+RijI5A0-_*wZuD1sIzesX`=$;ycb9`XOYcr}7~z&l*pNZV;cJ6pfFQJsNrHr9 zs=`RO(b?7ETbExSE_Fg<G_v8I+fkZ%5nrSWUCXoKBR7sID)8yPWEufZLL{a#P4jnL z85|C>=d=sq@^!LNl363|LOb)u*5_n^8xW2kv>!ffO3rV{!e)?r1>Uk9&i5R%7>WgZ z5saJ1_2opQPTUi?y~IiLR1JuIRTZ;Z$@zTGGU4fFK@`pxE|qYAFWuIqD<y(7rsZ<f zg!2tdGO?meP)aP82^joL;%=#M&eZ{{C&lEQDeK7F@HR_nfOXF!3>=}9j#!410zUNa zF0QOUUt_h1U4vrBsVT!nQLv-By@1^y!$@wi3o5rRtOK-6Uf@y0MWn|sv3bS1{Mle9 zxjci22a)(z6+uzI-m&olVO^drj9j_XZSJA0fv27YR@4B=vf}Uu0$yKdCPbp}gy2MB zZFifLwRbBPW+GA&9BUln5gY8ZQV+lOZ_K=8WCCc)`6OX60#+@q8~ZIwSkVo?4G}aa zQ@c-ss00#55X<yG5PteEf`st@Z32t`3$FAx1Qy}H6j(f#WTRuvHboEq3LYQa6c9Y* z5~1)AQ`)g3L3}7I*}w7d*Pxa<Fe{vV)=kNyZS?T;NRM?>B0VaJJCH@-gR!$i%{V(A zB;?29<G0Qr(4k+wBT<6<s9KN*kM_`$A`Wq<{pqp1oE%N1*vHM3{D>;X$w2@@v16$= zia!P<AMI-p{S;q68W-@6ZsGs`3M@)L3oIVaR^b0<1Qw-#B(V7Os4ntO#a5?Y=;`+o ztFwlL3&*GJ1fZYy?E$r$*gfCc6(QMJ3GPh$3jMPz>2vYS<A8{mco00%JAs!>oJhrd zyRYFv&qa9w_|C$EftHrWsPfd(UUq$^YU-tdd3U4F{QH%3u?}Jlh};*fH0|ranTlFv zRwLq$Tmn#WwY(u-np)ydNZ5)`9h%=;pN`J>^mrW~C-f~`-U~(SA?S6=s#_EFca~%= zTngV$plYwVj$5h9zu!d-JsW3Y&1-J(=GM?o#y@oN!IY)>ELnbn)Q4@~*2^L|?oFgw zBnp68g2+76)>y{g=i+&T9THjw`K^iT>CWwFuxdS6hS0V@33{%jf<JNH<ca^Q1QySL zd#7PqeC$9#9xBaS{p5-&>g)2KYHWW9EULz>^o=n~Zp8{{V=$d;I6alu4)u9=BVnRF zJ%`$?(E;yC-bS|RdDHsrexvGp-=FfL3BeP+L-|stFTm@)6w=Ax9vg#)TTrGr$VsT_ z2dNTW(V>+c74aJ_dutuzmyfb9lLf1~G8_4~7&tQ^aotg1ex4VX#-hPXry@$cnNQ0` z%<4<0ni{g%G%@kKn3kxCg0YG8&;yj-jw3`kkVD=xQ>DH%-+e^rH#B#-^-i8r$tk0; z$!4#p627AEOs+nxcIeePoV+HiOgDxZLj$O`6CE-x^Vyzsd2Hkg^hdm5GqsYQ@Lgx0 zw{y$95><PLAXC4d)wZ0r+YaI^Z7>@hVD9OS!}-_zx6K<5+QZa+jag~(iAgXBeJBw7 z_MaIN|9#i*6p3H$_9waojv^#MpcFwu2m;|K_{)x^Fg@6qhql9K)hdh+4{9tqmg4q^ zw}-nuHbv3Vy|h2Ze%-Njlv_T<668}X0po+OaF91Y%87@q0&%R&q4;ryV+Z_WoEZNb z{;jGoa;y$U>1QnsJ&q4Ql+g$|#)ctBh@(DS2@?P6+`Wf8@*`D&eA<|fWxS7)@DZ!Y zL-jaAk1!tYu^s)(pqCs$uQ~lemtb|pFPCiG{$ri$Q_0a;E>)TNJ6*ytyrTvB>qIU% z^_LZ|gPG1PKhq=<f!cl)P6W7F-Us!aCV?DlavE!+>c;%oo%DxHAv-T(MaSQ@m3W&6 zBSg)=nkqKI*Ty2XIs)BK^oV1mKYMHM!R?pQg1?C#PGP;gXzd84dh7jL?E!87aSGS@ z^qgAM3h9$jr`TH_GICGG^g8R(KDx*f3Q^ZuJxdA|#r*1*DTP1Y1BMPN;IO!1t0x+g zJpxzU3&dFbw9neIlSQM$!lS^{uGjb5d_$rcKCKn@PDJJTtmtP9Ur)e2;EO#tp4eP{ zQgD|ewB)c3>V)sD%0~fO0;s;YYvl&HD3fv2lv9z2{Aip-MDuF{KxJZdLJpChSCOIZ z(L`WSRGRYY`rSHYMSXVbhQ0+a@4`=MAmJTkoV7OH1X5%tPyyl|-lun8Y%H>4-w2=B zlm)f-aJm?;D!-Z=67i1(a}s$$rAVBWj8j@tahf8}NZu%cw41+&kIZ6-pCUrr8+*ob z^=1D?n9Zq~hhZiJcZ;O29r3_lw!~l4h8eiA&zqc>1P}KvuQxjekv0}8lYbFsl4!%+ z<JNKCD<A3rEzF9ca{Imii?}8HDW3*@k~MfFn-w)&DO_tIQCL){1(vI>v*IXu_VV5q zv$gf9!icegZbU#<z&psc5Zd0v8>0K^RMa?kEuPz3(in`6Ae35KU*2)sKB~v7aKm}c zVwfZKZBJm&SgiwW&ku<i6;ihO@|cJd9_g+qFWE2@R^W&?^6`#B0i4rSrUpa5DP9?9 zbF<-5gkyaSJVKGbXat2#g99}^&#HH19&DQ+4D&pr&Xjo&OokK=JzJ9Z%cr$8j_Ny4 z1s2*7W`X8W;IS{rsPQiFf{Q}BQp124+geCXR(hnbt9WTS3O|`)uPM<IBLebZ&aX_< zO<8#Z*CF=xXB@!BM2%L$7{dkk8Du@@wK?h+F~!s5Z-*k|)j45Oj^EompnnO6#Qpc} zU)_R#3QPasux}yimxuhB(MN#j(LI90IF3^=1`-Gk6A*|HIEZ5yio+;KkOT~Z$Uas4 zawTG)&!dl7B9a{q9LPrs;cyy4KazeQv7tTJL6Rc}3Zq}fuRSB$Lq{4OdIuDK(Cm(U z@3RQ7Z;Z&J<&}hvjYqEaMS=I@!ifK_r{u`P@M9e$`H&3>{E!md6Ttlf`;{p8BbARG zZ7GL3Z*<rb9SVokvCy#pcQ^}UN3RU>iG7Do5qd0P>|;8D@?XX;-amRK!17!CvQxgu zlqWa}_Pf&N7}6NEn}Wy=g8y8ZI0yyvo&9q}Flz7z8G+8?cpi$Npa?$Z!OJ0d3kI(7 z2}9r5dKT~eu+tyCt+{$<M0NY#eY=MwY1va2L}Se(zJb8c8&xj<Nw!GVevn+aatmW7 zF6H{}7r$fR55r@0pF+RsGB`i(^xZp2V!7Ph)PK}*o4*^{s9x<FaTk!0SN>&*SLA}! zTv&5DGdaMVCi@f%)|0Bgiv(Ado5<+N>4Md#$wZTp;3s*u2j_*J#{yr@dH)m$7Gxie z#DJBX0)sZpHrYIM?LN}E81C<wc+#>k;6{v|i_H~7gvxP)jl6jyH~bU_Di+`N>G!Ge z`_BcyNiTcNcsxt6h@v@KxEZdG>3}k~m@!L#!*pm2uHgBiTN~wZGT7#AwMLigJ_X*p z0zmZ{dp3HQd3!9+8|%%3Jfoh9dv{WjPSU!px-W}~xEKvHs1WISgxd{PEul}JpI#5x z#dMzn35#=8_6K;69l@)gz-G?12a>5AXtSl&y#z`)H#ttX1&?xb<{EE{rk2~O1Hx!V zANaj)CccCpElmgEYb8xnyLIaGO%~Pu@!XrO_Jd~&zUpTxL8fkX4)K(O>e<8qGJ05j z*@HIcEJz>(k@(DX3-&XffZs*Xbv*vMtUBrDr>E5V(;9Mym|B*3xf!K=7J%z3@~Ggs zxeWSNrCJi8dpQMpMbHHz$^bh+#J^7B@0g<umaMCv=Ho>c&$@Om*OKz@`LcTV2`I8C zSRz3IQ`=B$C@WVQ*SR`VQ72%Nw{r0uc2Bs85aB6OJ9CzZ2;E9Zjn^tMe!T%!4b~@! zs2K%Y1>A2Hy9poO;CXbNPsquB+2@5dm$c-hh>NnePF`uGn@<Ftg$I3`fbCMfdpq0g z`R^+r{76ayepW!}u*@YPyyR}eU<M?~!v;y@{M@SlsZ99QrhA`-m<o3hkJQ^i^pH$k zr?c*n>V4su1Y)nxmoRvcX**`0SA7~9?otNU?KT<D+XYaqP}<U#Sm?WZmqunmL1u%- zjp_IAv^5gzgfP?a09jX5eT49oHdUKqeoAmL6ixyIF{@hV7q9oFh6s8WR=1K0;#Sws zmdsPzun-%~T+qoZsXiFhs5%p)KIzv+q2NntYrxYRFXFW|ZV;)=5{K)qRlM<dvIa<7 zw7g$R$p=+;jPvV7$2+{+v)*PClZ&9UiFwBW|B_EGT;=?;dE}*LQt4#DtPrKA2h!T_ zp=2Wc<bY^d*K>737JO;JWa$=xgIY(J-#`R=7`!2)lrAZy-<9>jG>*nEfo@^_^Tw!~ zzs1?5PI>A!_-cVvrd*{(Fv!T7G#w0(g$@oUT3%r88R=QxhB#5wT^FsyYZ6<nW_5N% zBAm*Yu{8wa)Z+%#FY5+o;k=w{K)W***;qRc7T7*lO4-`aZ%LEa-VD2eE{lp%_mhYT zzL7woY;2skLnMoRCz0$vwF(IGEB!WX{062mLDLUQcO^SIbrM4Q3_&Y|KR!CwvV40O zJo%iCIMvdGnjtQfgl^FTPYA^caoIDBm?&&K<)a74+h?}%dLJU25qDRNT${=pjFG&6 z6yfv@dTk;@m8FNzPe5Cc!nK<3lQilNT&l@ys6p+J--)1Z9yg~@<?Ck7FIkE=|K_p( z^Qa2`pF>r@KkT=t3jPUIAruH<I7l4E2NbrWDgs6EPYHn9Vb;EVhg%?wlQ2ra*l$D> z!jEqc`Dw|BzSOXjqcE^zs6EGr;E!!%csw|O)vv1pAa#(R@DF*2jE?`3_^4E4*pZVH z*dbm3!e7OfQ|Ks1XV|}E^4|#lJ5-f@B$%TEj~%X);nC1>w1^OgUIO@W+m1foMu#CK zaa6kZYwzdXFT8`qBsto5!SrY>K|hSC9dkwKfy*Fre~<qdRhfJY%KVEdgApP}9KCK+ z)UVN;-1Gk@P*wS#sOrYrn7YY-MpfT7{$Gr$q<@U6ilKB@+N@#+&CllRjSVMdkPxwa zOnecPd<Hz9WNW9+OIRXX@gQU5HRSE(xPO!DJv}6g{_P4KKAjiR$tc$m3q`?-JIAPE zrVXkKwCGT+$;;otl&>yvXTH~V&Di^-IoidO<x_SQQM?Vakf%aI!sW1;?D{^Q6zp}P z)&~${g5ifg%U{?PL({6f!c!-0=RO}ByYyN<7oC;Jq1;%j+nFuUYze&>r(+jE@8Ng? zZp0IXP?|a6-ry2C?>*?J8eZPoDbH{HsZ+~&{}$^6#PFLJE$ZV&@WP`Y2>$lKO#=ct z>a6AR9y;|grgY(aA1WO3m*qaj*^pt(W4N(icIBMcsc}I4b`4?m3AyJ*pCUQ|D?kbl z*7y!Kh0Y>Oz2eFjjR@JJi4;vN<=6FHFp#cXc{<g~#=b9)7J5lRr$AadYS$+q#e$Dj zY!yJB_<-?I2n(mLZ2`QfIDDF#9X*;{MiUm<PZVo$acZ4uet^9zTKST*0c2_z<K2Bh z!Ij`hPDR-^oc39K3dcQ(mWmsyLf9r|Y01A{tR!V7xYnj~-O-PZB547<HQN-B9Z$|x zZWwPCU-ox<H3B%i4#P=m?ZzMIt{eG_g}p)P@?Ilp>CSmn6_mXq4L}6t*0?)_J=YMW zoutL3p?YM<&|Hefj0~JYm0?3Uj&mB9r_lkdRyXopvYNG;Rs<lvpv+*+4)nhYRS{|O zPMYW0zb&#$hD}0DE8hyy!h-(=RmozOvlM&ruw{N{!-$qT>Imzbg`m^DNLFPH9>|nD zU;Afo3<$0$R!c#x>fty*hl9AMD@3gslBdXd*t7Gxe;5Ayp%B^hx=yoTS#!^#wOclY zdZ*7_A&5_1ygrhXc>#v5tPH5YvL|uv9aVc;(EPsBfghUVO<!2`B{Jsuj1oF$O4ZeE zRRwn8hnudnYJfrrxaS}c{3><)9I=fF_2@3`K!sW`SYk<bO=+oi<lDRSQ)#uIw3rS? zRAGfug@k6HEzrE7hsI9D4&@fUSwyBWWm@cgZlJFO>QQ5qZ;AV~L`K=;KlT>Avn;N< zQV2pOb}|Q?oYUktcKv9sKH-RM=i%P%<^Lbdz1Oy**b*)H&R3jwMqlAgy<vqBAgq8l zyb}lk5`wR9AS>%sWo4GVr$^_=u?><Ii!Br}BVxvkxAc)B7h}dUBnI8$WBE=$KOW(` zCwXCtW`4l+_O3`Ckc`nMKi|pu<RVt`DdRh?-8C;8UWMU5UMHGD3o_cE@_K!FYz^`x z`OY8KV1oMG>Qf4&v8><BOcZSmhu>2Ew1X?$)Y3=<742x~t>3nVzKApHy-#%DhO(|e zMc>Kkc-3!u0jS)i9>W{I2DcWqsVk18c07#l(qCb_yLKOkWZt&0fwvPi&AP(e-?Ea$ zmB-g`7GxSAdB(B_O>A9DmuroUlBz42hq`Z*mxQWyMNpP`_C-Au{<$K4X>5RdkyvM@ zs`e3Kz|9^IYlXs!Lmy>!&Pdsnqd^>Xtw~9t7!0(Y!qGOeTg#&zsQq(Ph5j>C_2ZZQ z5LKbypsEcpK{P}XFib)loZ3@U1WIrC3P)g^L=h6f5EvyPibhZxr@l)t*kMn)ms_HA zFV+)ZDiiPyhp1z61cd%Xle>85!Cw7-{}Z*Nt}mq44PHgmQM)<lvl;ml3LR50jx<(w z^o}R_(YBOrXZ{hYqV_S3`;5nISLocHx}ALoMEL&mwwavTvuPx<b8`12S-zhh&JRKD zL(UUA=2GoCo%CMzNvS<&M$mf;6!xbBr+$a3F7I2+R8@zd!wHUzo*W?lp;2~J{@xJ& ze}Jl%-=V5~NC5IJs`};N{}@$ie;ZY;%Z!;JMm|L)>$K{jdUbe;gjE_5ijY6H1)M(j zQ=dFXa?p{^ANuO^8lqK-!D4b8^(6LIk6-0pI}vNHq_}|u^1?w*woET=Q1ureJ~Xm# zt&8^PNU;pC{5A2|q(k<oR9vU2sN1d{t<K!zmL|@cJ*YRMy*1XbS^m8G7T}V`ha7KC z6v&`BxDV?oWyGUVNY}tvH&V;Dw|9)h@hp_WrK6vz{8&l`=aPq`k6;1}5zM4gGcYv; zolcJ;@==FuCHOU5J56U$84H)db$eU9KVmd%FOM_GLhyT_NWroU3lJsdTz|kEl+%7R z$@h#kApt&;Apa1tJS1?TUAihFgb8&$z8#dOwi4ZqMJiP1p)ERQXz4A6NgUz4$n=~O z7IHbd8-&4owYc29n!HsPioa<{9_6FmO^hWFP)_3a3a96F2D0V#*=~S-hS=)jOmdXY z^;M{cY`){q8yY=%E?6;kVX&&bLD4Je?i9ypWf&1CW-WJMw4arh;w^j4nbash=&rk% zEH|Z8FJ<WY=jSw}<|JG#;c=Cwast(B2%YXE|Iq@O?E!BsGRAx9URFye#cS!JLALKv zbYED+f@Y*EyhO(3a*zjQV}$X~d6Y-ozow+3ogouoFkh!~P!k8A9cx04&+MrYK#x8J z(_jiXJ3B-gu=E?cn`CxUKGK{J7z-j~Y@*f`1eVlDU{dv;e?zVF4^h>p%+0r2Kbhvb zoaZR??UyNEx;<s_2dIj-O2ms`;gNbyiqyIzo?nD1CBr8VZkI=&j~9IduG4TO)DS)~ z?_0A(l{2CJ2T;%LH33Dt(FgBc5BCWTpWcHhQ5bCr=b7OSi9Fg)Qj6z&7V<=vSlWGR z;LTsz*VxH`=(6R~U2ciG+S7?ia5?BHjeJMvt2x=6D&Edf{)mD}>$vp&)?PJpTUEXM zbf$yf-f!UX@t@2Ib1KAXAWE_c*&*#zFdhHi62w5$GW3x;#vRf%3qSg1QM~ef$-~A^ zKj%O!fY*r)HY=HMr|c@<-EI~}Hg;YipPFfl=-q|pUwqQHZ^gRyPjosNcs+>8DYX6T z_=v6m#MGyk6u9w3-W6~evWw@u;^0JZJPti8aC<~8u|=Rx-RE(xV!0$(W&7B%iujqC zAO}#DcV1r9VR$j+n31B`JaoKjXuUHt&RnTI&CeCdw|pZR(wp)NmfP-#Md@0;yvBEc z(nL!bnTu4IH80wChohB`J6KbT7yRu_Mc7MJ&Nf<^#GtroeAQ^sj!}s)hcog{L4Yq4 z8G<SwlFl~8Q24dpY?6cqRHeRNNC#=8-P)pW@q32aSP*VOy3+CWlh?@|E$P7Z{^<2f zLzf!y2~#U<Lh+W`5}V>Ap1s7POO1(TYbZCStifo<uH+uvz|yrr&Vx9efMvT~Z#O=; zoo`<4Iu?!6pt3=Z;laZ!v>@01^YN5MuupIRhBfrp$CFe=wYLKOhuMw|S^6KD{{nl? zUv$fVepK#~opU+Q^Z!Y=W65^x|0Iw0+hHaDcClYZm;894-!M0El)_Prf(eMipbc`- zC`Di>grWqpfiH}Pa15ruhrV{ebd2iU@eI1Bf+%D!!tE_U<UUR;J6gauAVlRq(dl>5 z*9O+GLz`y<J{vOHB}St?ql7`bybhM{kSv1^+y(6-p)|THo8#$EX#NBAwE;rtm=78g zN0&OfEAddtPP^G&xu1aE8{4-hY<tV2z3PY`UFk5kR}EuiFAZY!@gLtCnWA_Hnfom8 z?LzQBWxCvVp}UUwW!xu+Yl$%hcnEGG26^HKe1PolNpA4${o8S$p1TU3#%f=<C8efW z=X)2qJN3~l>>FPH3I|;_9E1YLM5O&mx8q5#0HG(%-etJH;-E>0ZfSpv0OeRVL3KE3 zy+#)9!Y}RX*7`G*)6r(*pmOeQ>deor>&3ha?fi1AX7Ar}ZT|MQf4ytqpKSZ<u6K$J z@Ygste26c_+pQ@iX<E5iofSMkGR?CYpd(<{j6Dg(qX(>l%q4Er74_*V@@VBc)N(No zZ^iYw)i|A9m}Ps0d7B?yxMI?jB?%B$il^Of{yWutsKhIZem`T8)2^7Q-A52z=4-LE zNGS?)T&3v5Tv$6-K`Xupm_SQCAQUyjT$n`NqUIE3kd`2gEXb3h<6F+RX7AR%A4rwI zX#~mQ>(cp5@8$Mz!o8BB?hFurQ0v_rTWD20UpR6~?)@!s#uI$KTHG6Zki_+cgzcN5 zjcahpm*#oiC6g3s<@K2eUO-SAn@v?vOB}kwd{8}PzOuMDv6oNskn{3P&{jR7<K;SF zrxu-!ZrS{h)!m)*(VY$K9Gkz#&^-T!p$V|8W6aPKZ#{o`=~MA0?%;a^5%)Ff;6Gq! zE>F*^jjIfpH@sJf6c#dyD(mnK_2@a{i!=(Os%e{-abDuwblfVsZMS%)F1DmSkyWog zO9T(J3_!Kg&cVP?3q_FB7Tqi7Gqgqd3_YzWLaT;%ozN<lCLejL&}9oSF11~a+y`ba z*tx5KdpjG}IWR35oY?G*Wzo`}!2;D4*jaAp=i{!v?T)#Xqf9Ip!AbZySV0ovYR9`l zD-E#tQoW{zP44UJBvQ%`Lc%9j{eGg5czr3Ps<3>sYKxd|H$BEbM@Xw5ZP?z{`O0%| zz|iUUTQxw{X1XWpoP<Te&_1<2i{K~EEEte@%>sQx>s*^r@X2x+385JlOrxJG^8=7e zeT_A$rGrP0|D6%oKXyOp|4pa(7Z>|;r-=U6DPs7pN={QS1W`DSk|<0g6iQ(<zTr+B zLkN=o?hI`5;CpUf5QUG5&zEFGx)*oQY@aio9btcz9?iMmr_bd0-cS%7!@%}AB-Gy5 zn;d?2I|xC$ILhYK(&R`8P`kt3oD>S};wV3GieD-?N6`pNc46$z3qoIBM(hP7IR2T@ zxw+POuifmKlx_9BCPf@7F!)}vis7Sw1KzI@J2bt~J#F!4PLZ>Ar<frBb&7--fhC$h zE}mkkCtXq5k>nYbEsE_ky?uH&o6oFYJPYt|9OCX-fPdo<ch3Us8G?W65cgdJ|HdKi zy9WN5L)7N<5c^A>z?Z+O%(8_$6sF0@g<dg?8RFzJT4#S+H`{)@zVy+{dW(ZZF~7XI z6J@3f2nTm12f_}^@pO(Yzqzbh=x{xv`{ref#k!2S56Inq7`0QXRnwi{TEH7jntN#v zayPQdVbTOFo4MZnz=XHhk>b!ye=DQvw13%20N?Wxo0GUe7o^9+LUbch*9n!+5<-{k zp(($)p#WyqyA5VFOwHVTSrnOev~ARb9IB`>lwVT+lI3zYuei7bA)X0}5_&_+e?EL? z8212B>X3#r6DsS5)1(=3Pt1(pl-lUKYI<s9yE=q4J<O&Pv&J$yG_qdJI4|(qEyFQ+ z14JLzQR|6K@3Pb1=_~uiZv9$9^IwG*|74-xS<&Av@@or<Av8*2o27&xjG)QQf*w%@ zN#hWTKnQ|w4}CYMn_;^pqN2TUjbl5h9Y^+AM;LKbsnb1gy60>U3O$B>*MO!++^|ba z(T9Kmv9s?<;&>6Uk2ogL9sNVZPA5!~V~BFTM+*`50|UC5&TYl*>(0D~cH^Gmdtd^i zdvLS8K1C1hEp$I+n(Y=g|01t&WPFn&yuglhFGB7l{>`M~(J|RL{t3_jG^(hNs3Q8s zfHLdw!Jmosj5ty~+aJm72>iQ^WNi7riYk~{`o$WhzqUr-DuYUUPWMZ~cV)1Hv0pQr zvHU{5|6)+xUyf<#Z<Rqk=Qq<Hh57UAvng?_{VF{@I)ZfQR5$x`4)tgbuYnkWJ~Gc_ zzoe%js}GSozYndGg>;M&rHr|+iQ#0~CCKI93jzHs8(<!?0qh|gutCn(n(Mm$AtS0? zB88jm&OcehqvVQ8r>(oY<S!XOPR5I>pGxC=2>dyo&+Yp<aOlG?n#Q{HRojub2T_8U zXu&db8{JEm1fPD?^fi(`?FWEAWOhpPV!>@*C&*EPbOZIr5gMRZZ=afHTusJghy5kE z6X7&4TND&r>8tEE0gYrP@I-`jC!dzrtA&VAULw+8J+MsA6rxGd%VQN!p;mXgzjP%| zVH7(}icQ+1XJ&nk-&SDa4AMEnB6W@Wv3KX`3Ts|4clJGTb6HJS->{)ixLMsrbM^C8 zDq2t^q*hJ_x&U1hc+19}8?8>ghO5Y$wAICY`LPw*vGif4MP3b+NBkr^ZG+^P)|cO; zErGw9w=BO&TRN5E%53EU_)CA`#fboi#wN|cuh-_gdCOyj=9%qO#d`BiSre<25^WLy zn>VDd+U;U@r~W;SgGht3kLsve%Z?F<o%t|ps_{BKTjcktx{hZ-(^dN=3(MxT-x#20 zB7&q~YYuP8Vybh#hL9o-QOrQ@&AHK3)1^~+QpOpU)EWsd<dnQf-<6GX=)?LM5Yy?= zp7>SMT~NzZy;R7$nuh3JW3WJYId#3yuEa{FCHiNVWNHFCe-zgd7b;dZ2L@2X*=Qs2 zEs!Fc<b<q_<yGKV4?bzGmHCBrb)F^eF3n7WE))|N1wB=ZiraLfSdo(f{bh@pbSTa} zHLve?zLL*PSH)gTpedgOXr4ja-|T%)H_%Mhi~bSe+l{z{VN0yKlivYt_#2u;-}g5E zCW`nc3;nV0`%Uz46fH4q^Lr2qZGI4;VUpP52y`DpNMR^}!Ps|$hg}{g-IHDTq1c$m z$2gp9Z`9hbIF#<biYE5#8omVt-*1>EkDlbs1yS_wWVWDV^L<2maKeaPx^eSV=rMCA zrT2k`yZ&{$^Wy332flA}cG1zlwz=K>=$77z^wdrW+rI7sL)pG(6gfsDqI>alXN*OA z&2!r@bj$|YqaFIEEjmJuPJk@mNoL#1>7TO1xa;0KmfU{veXQr*-d82-c^94u^9o0k znAE=u9?Jh!@bK6D-d^Vf{*B+;-5&67{NC>NfWP7QR!s_a4Q^?-hieV(vcV#tVuHYM zG9MI-fJS-v!k!p+8ZY@G+0=yqlasdk)|1kWA^Y?%3Q~N8(pHlr`|<{hXCUvfsRIck zm}j44(wR;`;nHv$tS(OG4I+osXhg9=G6mvI5Hkhjv!G8x?g??2+^YeE^jx22EqQ=4 z_;+hqyDtEK?F>eGlKX30e$witH<BjY^ggIs%BF&uD+2lFYZvzSC1RL4H02M#s0c;1 z^GRq1>*91gSG0a|vSt0T$O`#xD;YM+D6PQ|ThKOg_>-iKW_v|%%K*0133xE_Y}~?l zZf*Ug;O6ErJUhBfA9}THpYoZwmdgii>~n{n%CoOV-(oH(<{4^)dlLnWOXB~1qxo}7 z>(6!y`xjR8AFcE|v-!;`zp<Mb4&xAn;}lJjC<&1yNu!(H+^3U4FhRf=f_^{gLLGfR z$v)|H*YMBxbbXBNN&da-=!>uedXP5oAE~FM>27cLvF7QX``=8{_R=j**fTDNAjF>O zpnm4aZolr`yI)ETKZ+UfqkKRfG~N6dQ5NO9tt67&5|f9y-18{;PC$v`T?coMZJ^z- zQrQu&L^~&BJN*`>{LBnF;v$;<iK70L2h!|35VZQQ-3-Ur!wExnE|p<sbdRR6&wm>; z%zMmG{jXvM;fuV`VLQuTTeDvpdw-R5G5=1|rTSkbUH<x(_Z|NoBFPEw*)`grJTAiO zm1ipL+^nRgb{p#6AThcC)l`P_OX&L*4xVTftr1S1F;oBWo6-Bc8iS1oZ;brdLWZ&H zmZg+zTs+-a=VSA*oCBX8^Ln2EJL2w(_q&%o=|_X|+&J`bd+S%NcPv5J{s0rmQFA8X zok_;NR9(zDCM(_p7Mn?frJ2^(Cv(Qi0Xea3S7%_8FeAk=dK+(LrI1k<*nIT+mh5ub zR?F6dv)mIa1K_zA>JZ6{c=2oLrW7Mk#evDYo+Y1!emefN7&XR6Q-2Ojg~eyImZm`x zrrRSh7|jIgw03pEe6c<v(}4^Mia0;v8)rHfADOLHZ3&C<=hD$_YA8oO^<XTV8bWjJ zNQ1Z&!0BmZM-GQS+ajcqMj@BdSzB1}3ZGuA#Cp&TO^JOaML}A_q3<e4iM4*@_cCR0 z6(E#T+jfqMHe-g*cs;ygm&8@u=rI~)_{Oqt%GCG5*`B~zu_34xCt|&ZpOn6^46gyX zwRkgjLgiRpgg7Jf)5WVLW;AcybG&JRrMOYrDj@yfW)Li!zP?(OnV0W4Z%x7sfR`Gg zOeS3K%v?&b;;P#jW5YGvyC|g>tQ{^Po2EE1h@gI@S_*;$OSr%9g2)eA;;TSX1{Igm zlq0#P0GvyoG7I-My~pTvuAmbKH(uV^JoT_hahAc&_h72hcQAf#-YpAF0G+n|Sfcmy zKc(k>8<CNEUKf+{@o$!fE_inZGon?ogomha12XNuM3T!?B0kc`7tH@CLOc`aijmPe zJQr7Qq|u?{@l)8VZQLoDxS0m=)ZnGrd&P(Vwg(FV$W5IR1YtSWyaVIJ4IbdTgF*Gm znh^JrJRWx6i)oOrpuOFP4|VRI=c-ZYB?Uk`duj3wr`uFF>b+&Dsa(hz77^l?7i?x7 zT*>B>StPxMB1R0v)1!~=ZXjwjc5Vrfi%%7P%2=E0Saq^=sM;KS;k;^Pk_uneXVzTE zl?^XXvPg2}hM%8)j4NgwMtUSYBVeopH!I>rxipI4@jiDsW0n6DWJKiD>{hRlT$pKY zb!R6es;I0!j_<JT;tJyD>d-onaK@PzhNMU@n%3I_Zx+h^^SRCjKFE?eLoWu`Sx%HK zm*tGo(<c05r_DozSsfp69f17X2x$Xp#wFiJgEP;b;4CxJf)@g7ZkP<~BiquQ=hNrO zolkL9MwuPky;@dxTFwCM1*;V~$0s*c`IPR$j#zGxWE!9Y87Fglhr0KCHyJnLRCVl( zOj|wTkqGC@)fk{w28NSiw{f)Mt#E}NE`!5NgtITNv)b|%E}xbZ80mE~d5Gp>tx?|w z&VzOT>621do-PcWf_wUwy-IQ}_Jf;TGVJ|1eG`I4g%dWZXN+Q}D)U^hLaG}azt6S1 zeIzb!q};%qYk@-LZ_;2;{7gHk-9Cv@M{%9d3i~{<A660~M7o-}mB#CpLPGE_gEr34 z4Bq&UWix-Eb^G&^IOYdr-G98uSE%;q3;d>32EjB$Zy*gvNt{9;8bx>72#gXaj$qVY zI78uMjO*`U8yxR2D?SQJ8|*<3g_K=Zi`c0i`vikSVk=L7%C_Uw_X#BVo{3ElRg;L? zfzm$v71^s{dA_G%>HKI~r*<N69Pj9EA48jL@bE{l4LKU!;r;B}(!2cE(ZY@#V-~(7 zfA`KUa!*NbJCBd)PrDcywTI~VF<%xTk68)m4m+`UkBv7tx<$h1pSPMLJ8YwV8DC&J z>VPlPRL3Bb(-67Em&UpKU8;9JG{b=Mn~6^rB!A8;6MhN*3P)(tCA^8d#8=_m#0`~| z_g&B=slN<=0*)8%)1MG=3|o2$c_G@BD}Dx1mI=|i16kLDJo_u|?^oq6U=K3oM!z~P zy%`49b|IlKe>KBz`@RdivZ-%9VpQo<sreb^F*~HgfgR6%gY&RmIP9x#*q>b@@MqWf zXO{^4*){&zB?8~O#=kKf*8&L9wxOcGjnS+tIx4P^)ul=^=!8zoD8nT2$3ZEFP)qe{ zqm=0lNS;V48u%y0o+%&bSF|1(t0do)b*FNutT7d=@dOO7tu76rcz$=?#SkB|LZnan z)9CqlGEt&CuLMeR96+-c2*#w)SM)W<@24sMbX&+u^9+BhvT3;J*Qv&fL{ujb&-B+x zuO7G}H%Oxo!BBd@DI3`Lc|od^X4K)(w8*D#^AfXpR)iz8<eiTgT<7I}7rOU3=a-5= zBCtPysHAvYgd7M{T;?v%#(8#20R?DjydUfKX)%%1NUCS-UtsOLRI1M@<fLxza<&gE zxbmDE8nHu!0NA@e(#@*}2~_P#6Gw*0uzc$CMEeU5QiO*JEkTQIrq;L0hF;J6?V8Z< z=bKh;7jg!k*Aw(o(Oy5jh}YG;81L?3LULB6m9TuSA0&R4)s4eyuDlJbnRd+3CE5GR zPZ0eKqY|($n<*qfn70*eX3s1s1|&Th6?T82V_{Zqe`6Y?d(_S6PK5%0@mYv@Jul(M z?ITa-fES(T?z#7@0W2O%S?1eqGZX6b!kwQMg*`eZ6w?9Z&Rhn;5dkeQ-$o}(D?4E( zqBsY{M_eFRnnCloX+Fx+W7UYuea=kl%mx$|B)4%O)kvLIF)`X+!ZaPfr9p9io|dSu zo<K5ue0x$ZT|Ann3#*x#KS>UpsS1*;7jSjcXJ>&o;hSdoU!WeaW4#wagG`MQ{ac_) znV87B3P`<KwCP6*vi~gy1HY*Ue+L*IxR4n>up0>zfm<(RSsYhz8AaDR?R^Jk(YZdj zo58$0dQ@edwz=TSYSSP_)u@M{5MKJr@XRiKzl<>yTIWxxM`|>&fgO2I4ZzX_?AhUQ znXk~$3aP-3&t9I0PmYQGYja6s4R%lBs*(@7&FdhU?}614ZFhBig*H3@sWUz)S0@3v z%EBAo5K+(e8%DKOiB!fyVv;8EQf#a{%6Qnt6n>~Wrd|yqchlNMfcU9iZ)aAbD=4(< z>cPdxV{n#<*W4nYll%^ndLl!`L|f6n3`0}A%FnBOJcao-TF(&RUZrzUwhfw1keZ+S zQ+i)yGKuD@66eqR1aVVE5*EpY=ODypmr39U+xE5WyZmOjR3Lsx=Q3COo<loYbsIs* z_+><)+P?>*8O8YL@kBz1g>j1}O<i5yd`zefdwqMiHfb`TZW{Upy2>kKuXZTY;zMCp z?Gt`p0YO^wD{?;LJ(lQa36nV%fl`4j*85Eg7!Bvpasg~8tWO04nG(;=WLu(9IAevq zPigB5MS6zHhrn!^e{M_0Gk$lFMcUR{<0p@&(Jcl{que6cEVYM@Ntd&J!tw<j7LEMm z`2;l=C|6z@Ge&%aBcvr!bauau9di00klJ9&9e^|rkz$N+db@%VeB>xq&99GwqMQa# zApNPmtY#3YGFxDA^9B6l(ya+8U!u^;7l{RQ&k)(BPdfr3&l_y|%fQgJx5p2K)<1@I zPMQ7Zc&_Ez&VTf5njb^+4L<z0Ykh@@e`%fHc6?#@1`kOBBPkfdDUu>_8m35iJ5CTd zNo_y=2q)&*-v6|ryA2q|<c{%BbRT0tA_wfs54l!+$7?bEBS}3f-vQhgYVrouHZT|= zKc&!)2Z>}S2j}EYJ<blr*);mOuZ;RpStKKOHgZDm02ayjCaoyi`2g7=MuZ;It*Arh zc6$PK;8FtHD=sAV6P@hk8R|F^!}}2;-Qi?{?%aSR-T>{N;zV?(1W>=C1my6fU6*>f zpC4!P)9|&+Uw(uWt8ZGoJWu-wD`R~HQCx%H(}h(-Us*%H`H1|k0J%SwI2_dPEM5Jc z*(`sIAoy>il`4EZH#)n8=joz*x9sh^D+}9VQu<EX@pGw}@fVz^c%EZ<%2##Pzl9aQ z^ojimR{W#O1pdl({?TOuf8{#==rVyny3W6X7lEGvBO|n~uNNeb%+(61AD{Q*X|;35 zQDL({r0Q9*I%mTTm##(?p0sP!jr4e80rV<4V;YkBQdlaKM@AA+M%h9>5z%>w)B&U- z>09lM<z<0}@`jB0CM%3`eO(@@)&#($NN&(NaZYGwDky@eXR7OE1%(qQiP9UvS<rwD z%ledJXBDNjV1esx;7dE<V63bsK<uI5?VSxhin?$tmyjOIaFE;<E%@zbB?xVu(aVxK zSK`fv0W863G@VWc=pg9j5+i`8qcZ-H2`9p}YDklIuu+*u)qIhmp~J}N9I%#=uuc;? z?Wz|vZiDWcnF(}VwNZBfl72l;on=HxI@D**K}Sd8^;4-mNv&BYD^t9#0x{ZqV;XdB zuIKr*Dt0(%2#Ur{P5|3V_q-tP;UM%muL=QtQ$7sJHn2ILEn|dG2<^csHQE{W^@)W) zm+0v>7nH7;s%RY`co1+nQuj(jgx5tl^?Y+hOf@4uigx$cHJWd|Uq<|TDLd>{I9>9I zi%Hi;5ROkYxqTXmxi%Jvd9R+AGIs?L?!mbOZT%HmO+l_o2PKY`QA_sWm5Do<9?d*m zOQ4mm^RO%fT$c7dwE$1PRbNQa49%{+3G&PQ^xAY~?iSn;EK4}>1`zB!$Bq*LW|y1_ zKYqD*nE*%yUBj<?^_s%mv&pBg1&{64yc=<0s6@9oN|LZErMqu`A{UV3zrl;YDbTrS zd%8UzgFVu2VMswsaVa&(d^nCj#EZap`GY^gi{k3$40@$!kv7BootLg6;P$5rsDUBd zQ8ChJUWa3w!N_jnRkW{MCf&JulGX>S6AE$?b#s>O_|s0t>oJ$kt}Nx<REt6y54kKd zM%hp9gub7~{o>h=vwViVjB7&jPR+hBHiEZ>YD)j|tH(fY?`4OcP=IkNS5&+W-*jZ4 zb}vaC?ONp`|Ct5R{XSJIC4*FLSrHY8H`^2ndQ~}6#45`;iS-CjS4%uq>Pjr20Zn%? zFn#upfRD6OuN5{U14-#@f`95PYU2+*_MKRL(%LLgS)*==1ytse2+(KIb&!I6DSviS zipBS_=4ac#`O(`;>}d<}PN1JTx4?3@h;n$%{<PuECRj7T&dF5w&y{FruB6c=wnSu1 z=$&GVDLz3dx8RTS`r-y~;X}-KTTz6@xD5-rJLPB*0={%t1CFpw71#9TF)m43EexL0 zYZx!D?cO%e5NbW7PD+?7%_nd+)A034Ua3WdTlxe%Z8U$G+lMR6qRH{28Oi1ndiJV< z)%BZB6y#lw!f9nejJZr!SW=U1hW?Wla-VE17V!K<znQ9s-qds+y4S5Lp;EoY6V6LK zljn5MASr*jsoHrSnRn3%D=+CWg&{3$K@kgF2$g%%dTmL(Q0LU7k<Y0{UvMH<uWQ*| zO|A}3T4laqB$VHtjo)ig!itXx60(%$XP~Y>d{iRcS;y(C6@P+vr#5O${{y@zaNPej zy!g-7`aNF!gLQtBSwv6>Mkxd(5eTMfjDk0uh!gboD~6#oP2wa1qu6(eG||pq-zAFZ zLnt!ekzAhcXbs-=mG;q8$iYrQHn;_UzaV^YGn43`#3RQPtmxqOAG8^Q-0Q#_-prw$ z$hohY>?C<|I}h{&#E9iP!=8ZlwXpaAfy4nc^L?xN(KZJoJFOHuCUt$$u|$tYv4f%- zr#r~pUbQ`ki1xyAitI|x(Vo@(QzA{h6KTr-5@~$-6@I*@`$?6LH<5Z3@S5^FBFz^R z1^gSdxT7fG-=M`EMFHQyDA9zpzn)p#z~Y}~7XJ(s1OEms?w1Mt1GM;?%LIOOonLwW zKcM+XgJ?z1{QdxBFePBydb?B@ZD3>gOg99|!ZnG=w9^AE$kF&AH~fonT~f>q@(!J_ z>b$P++^xE<03MhQUc%fA66e#V^S!wlL%!~=k*_|4uy$ADbh&?=(F51qQBGCu)S3S? z&7Xz7_~|dyeUre<_6%!OIQJov3U>rG82HobbzA><fI0B(1oPAS%`H3YkG-3csTm|B zgd3-?&3$HB$t6JSrm?`fzMf_&HV*}H4O6x<??Xy?-@G#HW)8-w8fE2Utj*{`oM!U9 z+KN&wDyj`(L2`|6fTf2oIxvXXt7t{P-)v)ee^ljM1m)9cV(S@B`f`&Z$b<c;EdDyx z@e8NWu8M9msK5Tj{q=9V{roDc^8ftD!oD%s|9FwFmiiB#^&9()p#%wI6hdP(g3ttp zQ4odG5Q4ym4jxUC6is5}cP%sm?UoZEcRQVandJigM5jjpP8=k`Xz!fDzXZzJcP;d0 ziMRhaamcDbJFkB;ubV-S;9a_9i?``~FDJ#(PEyRWU7aq9ce@$KKN@(L?Jfd4W)&vL zZqM<faUeaW*Fe!Bwoe~so7^dln<LnVD&j|fL9*ANkYq135l6izKiUOI^bmqUexm+# z;313cqnm^5m(kT~T{V&tsH~22V^!Tbuz*@d{)VL{&n_=CfX4kiw)&&R7P7Z<ild9% zyUkV{M&!RkqM2zsGo)GCESO)pg}ns)Jom(jZt3e+5Ayqizj^G-$iZc^pF6Yhu&J8( z@B!Y@4w|FkFstU6vkpIwt^L)V0YBQ>U)>p?iOt?8@N4?w*FV%2ZX~=}Fv3d<aR{SF z#U%1e-GmZjG}{euH_Su<#Idh8JbDJ@-k-hPFyH<9$kV&|rn1@OmblZ56P1*>RW;A) z{<#vh`$`B+igZrf-V5N*^4Y%`wf5^-ZK6GA1S|qCLt*mMsK)OXs8J2|z#LCw9%qhw zo^1`I4_gQoj3&68Z1PF-JQo5HUm22bKit^|n(M>$7KkT}?E{IB>ht_T-s&ZL&2pg- zm8h(@*c+poYI1u*u$U<r|Ji1(7)lw~J0p<IZ>+=2|FPM^|8JNr{4bd;{5Nu*2ua~2 zjX?DF55gf5K?s6^2%3W6UFVa=$i4Lw`>xrd4<xyL?BRph3}<_aZ*P($_aq)l?TNm< zuM#<iM18+xz0(u1y{L>rdpSD7cA|8a?^;otIm?eTY*;T%cV#GyIGEJ&{!kSCz-+-s znL9p;=i7eJbWdwS`B4_nc5{egyYbuL?k<Iu?^MJbKkz5KcRi)YsMZMIvzIxsvnKa? zJ9PA~(%WAD6j(}oDl)QvF<XInS1>Mky<i{bx=c;-yNaCWZ^^a)$ZWy?|212`+uC0@ zTi;<_|C)4dL9TIsPqZJOdLtD|P@yi<<dIS@6SmkS0Cko>mxLwMD;D+evQFdT<B;#( zu7i~#F#i}iDRfL#LWh)C=k<}?QYW(BX6Rx$)nq_vysfTj?Gm>oo_~sV8|9tXI!>6D z>?2fv&eQxYRQ4Ob*EI`zTX{cO>QP$4qeWXXgC1A2gPY^N0KUh%W(=<v#`_DQg3qhC zvsjp8;0cMa4ziaFrb7LCVeQ++o7w`vVLWw;7vG5!qDG9ORN^xz<T*)IxQ5rK0gBsA zd3&UxOfKR|+XkhlociDl<@Iqp1Nh7f)gxk0<q3(|!v(b8YuGdBU$%qx6h+g2(rnnm z-|g!?>e8(Hl_5HMO}_i2Z*1YeTIj1i{PRVA%j1C{6oS6nlL^JU9oj-(=nw{mkAlaB zuc%}n4unHTObhRV!5aWWzpt~GQoCUx;=OqUhj+C-oZiFO9hz<S=MXJUpxt)u!Yv0~ zXYUiqwz&95eJRNi5<`2T20zA1#OS^XdPunJlpAW71jNzZj%M&)D>@`xcH@|*dz;FJ z<2JLncgE*C>1Z><d#2#%gGc_HU!Cqm9eDX_^#n$#D&zY-n9(=nWCL)1HQ<OVX3s^f zGVskJJbTL?8SdZXv-sM+zchQC)t^lV&nZrN7E53=Jk7yyX}#^cG6pxi32)eM&E?+E z@pV4*X7%)=1*L$r`(gED?29Rs*Pl({eEVi5pVRz$5Yj^vJsk>eA|#)!JCIbY5#FqO z(tgUgweE2(3>x?4#mqcce{@N|XwB@BfR|%@#rDUnem4w?{W)WMW%fUI@!-C&K(Xa< zH?Kf)9Y<g6hFG&3H>*T-xN3IoETec@`7ueZo|aWi`9RJTJtS(j%1XyBnG{I^(V@2+ zAUA<H8p!m4Uzs`)$%!A%_b7)&Bnj|^RygL9tYEC^28@9)_d(C&La7&Us@H}TpFZ$e zsVrfN`Ju1kh`?`1Ru&<8+r_O6i!wtqMJd2>&90a;)K0NBOuxvd2fT9OM@z*8P?bw~ zTl6U$yorS_LtkHwW_mMp`>8VxRh=4vaZin@7$fn!RgC8#<DyYI-EBp1FBU*AHW5fg z)LwH%$f4WpxREFMZ<D^>hlVt8^v!=7ymZ~y&^F%XVbSc{EgjJp8xD(B0JjNneVXxX zx58uaFC3>M<{~%JClTN?k$m2tlZpfpDGzseq;>kHDbvTr;qEmOpiTjVOH!$Okx8%e zcqZf?{fgoex1y->zSSvHrIpz0`G=!%{+wFsja#&;ZnHOLOOzFmfL^RUL^^8B-dVS3 zODSfbZ|w3;M4{BCSxg`6g+`o)fw_0Bh~1O&7xG>Q=s=?QDqVqCYse&#yz1iJ-x~iA zKZzs^UIIPGq9L8Oc<8e}`uYPyrV3o@*)=4*xmNmx@T%3H0Cw%7CkqqZ8fC)3XrZN= z;*AfLh7~Y4EP9J~qk5&ybT)2HhLCt#rtT>`joBil&II^wyFPEjC486;>@5YV)304D zA@P0LL%=tWrt#OwQ{NLj0RH;mLdzZUL2B;VYpHL^rM!^%rB4A_UtI5dx>CoObAi#6 zHf5cQ>=zi>G6GROosK=F1ZZRt3U46B#gpeXc~BN!yfDinsqnG}>C;rK@IEWF>zf#F zz!SRN!NOD^fxkMbfn2$Hso1%nd*D)a)uL%ERbQX#b29~IjfS`Uyrw5-s$ShYSuMU} z^A~ru7F;yAw<BjSKMdBGh4m8!$bF6mBKlNqIv58ycn8SM`LNrkswA)8S$a4hNFFZ~ zi-HWg8O2jOunEu2M1c2L_342kG?mwcf=<HmwPJ0UDkuhg&Y5=sdv5c#CWoO^?#2|< z`thZ;t91H)$!TNKlwuA_;B;f?p}sKCi_rTw-%YYYapQ&y{FVW)xJIux;T$|Z;5>vd z3dWSGMiHfn_6ueM)|>$-dRS&lI`S+F92MTt6t+|P$ws9501E+oh4E8uKiwT`-ELS* zPxqUstKaqj4Q&lGKt9Gynkp|4DQ41GE?s_C^zac~^me^FohS7dbc<E*7tp0+r<Wb3 zPH?WU)eBDR-ueVEHUx#w^n_Q^@80v2#urx9-CeXOj^`1~I7&xrLl=is#xWx*Oq!fs zUEiFGZwS2wz+PKbzT<Qxmf3WEj^j*L&UDd4HdlJn&5T#mQm3atlGa76P@&d?u}*80 zy~1}EIsv9A!OqDg$fOntO3oxJ^0F}n&F<{P&FD=lpFg+IpmeKIx(%su>l)0zWA70Y zcNR84V=O7(l5Pv;|9TAieY7KZzW|<pgS`IIGJlM_{=3AtsA~gV=y!`4$zG|5jux_v z+MB_0co&)28{4Qowj+;Lw+%FH!Cd@<ZeU{PqmbE-eD;_!-s8RP=j}xs&LMZY%$~lA zvmJOL^s#ojKkbJpGVB=oK*KwZ!;+ntL*qv^gxI6TUE<<^P#dD!u-68;vV#S)MV82+ z@Q3VDfcp{pAl@Vg+huQhPWNr$e_F&4lLK{CzeZiR`unIW_?M`wnU(n~>SF&Gby;5U zU*z?5(&Ro>a-W9m2)I_?_om+k(CS|f&RShYn)t1{F|Pf(bilLTaptcl2EIA-M|GI) z>zqni{4YHF9Xi{BR<B}h;H&iU9=OZD(^30b;G#GLF1SPBVsjoCm4a2?H1;~!z!ogS zmvc9wOxs}a`Jvbo{$dImQ_e&w`{y!pRD5h+F5xH&OVZvg{P^}N2IoSU=#B&2D!?k$ zxfu}G&LebM!^#<9)4eI72YWnNK9MFs>7+bG23}=$_{r?ed5)+awyA-pKzKT_K>*jz z491&}oi}qiKqX~9uAP{F!oDzdiL~%X?W?5|%k5|AM;}3N1AYDo7|{bmu4mEav(G%v zs*89cA5+TCQEF0V&sA?qt%>upF1+#X6h0kxiZGQ4!kWI$rwfeUfnF(1p7m4g`b_e* zd_Whq&7QfX#V}aii_RnsLc=Ae#|zI_h8CJ>7|B0ut0dsF@?)UJ<<}^Untu}Or<3C? z>h%s+v`RX7RH@9C=hrBzXZp!4V}&zxZ&0A+IzSW$X6lCnRIzM(H=GjY;tSXN#k+pe zvUy4?dQz=uwr+!4xB>L8gv>V*{`wkOj&Zrr=7dW`<Th{$V-Je)bLVyiM?{6(U>Kwc zly>>d_40vNofm6SAg@~>9&%xs#~mLAl-qHV`Fuk@kQB!C9lkXDjyv7ZrX;44SiDwA zBgS&*IF^&SP)aF=hjudYjHINWp3L)H22bwY$Pxg*Wvu9~Q3=2ASKY|Aza`ndO@2Ie zpWM<R<_(gM%qJMBN%}TqEAdl!MDXGgn>dBT73e=SGm~%aR`i~|j#zp>V*&OO?rhw8 zZ;fMSfnk15%<f5wZ*vsDY5jgi<2Q-fD={z%7j%_FJ(D@A-edQ=P;>k&$lqyA{yds< zTZF%+%je|{xG|E^W~J=Gq8c6QVyWz@l%=<*<1)%XrqVrBObS|G#X&{6icx5GNML3Z zizPk@gyLkdZuG+9MW>dih7J-@30>nW3-%B61t4i|+}Ql_wA)t#RT7TB)wpWQP^3cP zl)c!JKe<U1JDz)Ya3d5L(MfZ`S;wq3UC9RCSar`KpBgUJeR4Fd7#)&5g-_hR3H}_b za}ePBg!R==$cv_EJWNE`i5sr15WAei0rS=QoO8xf<LG{7)EGu|Es;OcW7c{9a!;)% zqsJ#YtOqjf&<lTC-gzy)4cz>kV?|v6?x|~@AP1r)2k&&CUY+$iQD@|Fc7mrzdqYnr zQ5W41N$<+jr04MZijsa6t}peOBN^~^0?c+>iDodDGFs`ygPnu+QQdWJ1KMOHs={zy zdkQaS&zBd_u?H1u;nij<obL%BM2z7+eWsz$$CE-M-lKShBOOm;+l+c5zFtCi!3|QW zo>fCKF@+JJ<Z|`PiLTd&90BJ$Arp5VyJaeGRm}y1tON^hNEC9Bcn1C9AzdQ_4BLT# zaZo&g*N0<$LTx=mvT0-&AUo4$(OBjc3C`7X;!819`GuLvf`p;zZD)`EvPS;Hd5f7+ zx$Mn0ihQ~tc_sSrl2L%@rCKk<EGBE&7Ut^`M4ivs1%F;mqIjN{%++!D3BR){Ga15p zDspl{Vl*UjC3l4;0m#?tU;fSvZh3<>UkDxCqiwSxslLjg9HU8%|32XxjP<u(_!U+C z@r!<gsZfNbC<KO3jK&BQLr@yRkv+Xd?TP{fh0+-ET^)fK-TTeRqh_~ZqwFY3rsz)@ zx<e?8-W$5MuQ+{llKmjhl^^<u*-q5J4v`h?C@SLkPZYLy?i0uCuU+yuJ4Qbwdm$8! zenRjcHKe6`6>>W-9q;41(t{yF#XH2>i=@zz^3V3-19^-O!=e2@8t*3{kD9`Evh9T% z^x8JDH?To_@-D-73QUy!-FXrwSBPA}Z2w%hUIZK7e`LNV$jY<o_jCm8Ez<qkY^B&6 zM2YX#lKMKN*_$i>nj-(;%8tT-FC(|j!bG+J=H@K{a{rZJ$uVv8XO@S#6FLyh*}zpT zuU|+WTS)esgEg!E-5mknZt1V==<mn?bS~RvSG=KNUO!Ve+6n@7dAi^=#O`US-yHxo z=f`H}=MzDACaQ*D?4`Lpu;xqnxRPTPCQPm2SU#a^HK=e_w&cnMkNj4v^yBq%0Wd2Q z?zNs;U41990l7GBlptuoFX-s3@>~g{@85I5r7j55XF76|hxcOU!2``_vgiRDx?@*G zFDmXrwdn&{G_``ckIS4BIPQ!SbFb%KNAII5x7j!p`qK@?w@*(X__{(o48-0;I3*ag zR8Ep|TI@U9`*KGG#`Y0Shd4hx6|kGplQG7Rcv9@N%5U>!tzKr+7*+*1(1{(e(MZ|s z0r{#Nbr04~7Rc(lvq(x&%VN?k?_oLc?r6x~*7s}ZZ(RCOP~0833-Atdyk5qdt8~OT zB`cOR425*KO<W3R_<+sY3hXHr5{U#^c({+zYMr%p(KAo6%~}P#v7y143i4niXY0y2 z!AWsu3?(eE<l7++D)OS6p_SRItT;6UHm|PomIQifx)FpbkV>m}3v%uXVVW;qplhDm z#antlh?TY-Gg7ZQTk#KveAU?rZ&IHeE(A+1FOMx|UUGm0^xy9%KWX!{0XwGnoYRqF z3O>8vm>dd?`!k26nk?z5P%uYtROISwcOnN9mgLd$4cy7aY2R%k^emP=I7v*?WhZ~7 zQuTSg#8<-DghOm-P}9lND$U6X(Rc3o;UK|yTyY(!&fbtY2K3F8t{;|#zK6JeD+Az~ z;jCY0_VIr8(hD?SN$Y8qp?AR_%#&b{SHoYBzL_XX3c|p`I#q)+&!FyaLzA0p)58S* z;Ec1&i1qtY;h+nv+H{{KfOu3y8%*Y1&$vRTOU~q+!Q4I)Bgs;A=4KZ*?=D7_kkyq9 zHEazaaJ<yytbrfuHBZ3BdTXTmj7Fj_igKI`$`Gzzrrt{;N#lBhP;kM?h6!P~OSy16 zi!j7MTunYaa4u;S=$QC1M@is&sz)YWs)YCiKD+6$J|IZElgJA;sr7auv(a@NNeZq` zL<L!bHFfnFT@(Q4zyv!l3~NzR(;jKdwJ)CJyB+QpjTLp<wq8)LcQ0TN7&f`n>5Oma z&6SZ;U<H;6+z|g=nQJPlNwIvYyAqo^XiD>Ax<HIpLiJO4+A@AeK34&&TtClVU<r@D zELv6r^$x(y@6k^lD|x%nR+7AL^e1@8%mzLO|5R#j|JrUGq32TF;Zyj&t^s|1-(8G6 z4UfjTJb^o02=atsGqq50(yT`NP$LH{7NcKk>{FMOLC4N=>w3Si-R1chn&%mxk;1R1 z87$8LR)wJ@xf$Z$6gPp)Qi01rn^G`LDkmTU{H34h`v7x5jK7N<MpU&Q;@}tW)y+gm z1@E9j<RQ?ycLP*!46?Xa>8w}P*sLKkQi6Ov4=M3jt;nczM$*x9PCeh0nfq)7&WsL2 z3hojNK%Sl-pD)h6HK|xSV;5&lo*&RWPoCNtq?MdkjeJ`^$W}yoCZvA=tgf&4UL_l{ zNv6l}H?h@Ud+qPx)em0x=Lid?$qn2R6o%3$O3>8z5Ee=vIW2rI+vNwnfIhUbcV29~ z*AwAm(tMKc9N8b_w6>@3xg>apG8<N-sYA~WJ1U9!E(EnpZ{s@vLXIKyduvs?4|B+W zG_h*~L_3T+%80w*_Q9e+h@Fu^!$%iCz7x1oc+a$L2VrQ>n^DA(!HSMqtI1E~LE@nC zz0WMgjuIrb(=w1hRd*G`oj(B)-$hs}6jFbHu=Kx)upYDebtKjz{uW`ml2^s&do7Fl zJwUB@QvDIiN?>i(mK|jQJIwmc!J5_o&aQy(ZR@Y@YDZc>8u{=o(n93kp?aZu6GA$0 zTO6OhoaKr=NFZw-qh>#~I_CO$6^EykA|)3ggDi5qSr499k=eVVLLXfoXXNq}@;>N- zOvtcpW9J31*cc)vo{%a!L#SyrBZ6Wstg1rXG8h7BQ}WbhcG-e+WR&F0U9Kk1nJ|lk z$)w$FAWlbVd4TZk#PJk#k}i=i56R1uRr8~YX>fbl`Wb%?T>)uS@mP(`K68EYqF^0; zxt0i=0_UPv+!h%kQH;Q{eU?;5ryVGw?YCg(&xIZe^zu#vK4R+)fhBbmP@%p?pH@r$ zU*_Ix*;O>%7QE*v>asiNz45Lh`T`F^Ac63Acq5DuPUz_mXqj|tRhrnRPe){BDVYL( zF{l1-d}fS+SpZg(iYUb899blVa^^TL+M|gJg9M)jrxT~FAj0_;WJ7;zPp>fS1Mr#4 z>%L#h0=BGx=!{q|T2n^PeXS@k5_^_0zE>#;o>(LLW0>lWfW8{Hp*bI()YM^@RqFbN zpdQV81DNgny0fT_k`K}GVm<c*fkcO1tBbI~0wcm7B^bX^s*9O~UsBC}<9tcPX1Sf+ zig5w?wUy_muSj!@5A}B2BO%HrGEzR!ldz6>BiTJUZQ1qa(asi6NHh||=(4tSdyY># z1kk+plW9yA8D&BjS}MUA!U~$1r_s>D#mG-37dgSze7zpvV@6<E8s5p{j5?cX?N<W4 zNK#z>J{Mb=D?3OYFx6+-=wfBt8LxFFXZq0E@oX|)b9Ib2cd}ETa5u_Bat1C0z=JSJ z8w51jE~3bd9Pu}i7VxtH92`@MZmK$S>f$7np3Uj{T*<2?Y5H%F7VwJ%?!Fs|If<FW zDuyEdbdZz*olAq5VR5e%SKWs2)CJx`s%+v0kFb5Ih*<*@+NY|NH>`K!Bt}1>n17C& zo0;Z#)ZwDGPMFWEo#|n!OK|ups^K@i$q`Yy;L}xHK(K@<cg}1LQfyn)u9=33P)U!t z=SrdU*;$9An{~Rq&p7!u%=yClnUTYJOjT@jDj2|y1kIHFTY|ljin(iz4F%WDnB++u zPFxq3vF=k?IS+1asmxUoL1a7mOgj3;3M;e>G;1qr0aq&dBZIKZ*k3NEnR~sYB+hi7 zzF`+>YDuUgPYjZY+taG&=>4Q6SwalSUOk{K8<RT?TiY^Cg`D!MREQeyvtcW~^8HJk z#`kDY6)!2X_si5@h9%*db}mSp*K=IR0nec6xyn4eXW=-z1TboLPq73wB~4zHTb}Yt z5@erz3F`6)3yHWE=kOJHuU^CTvLgU6ZU~Hn408Ya3KJZouz%0ygvTFl3d!B->}hM` zy9AFAE>Rarqcx#UP-@~^M2^TOVA>PPSrF8yu7&tPmBuR`IPau;uaiPW89XAT_kz23 z{yO!%Exl+N!|i)cA-zAp+>!<4$V?wlb2i_35=oEi8(jEMv9pQuLq@V3xuO$<NMG)W zzo0ihb+!o_aHt|{o_2(M0ca;fa(^AU%d78V>tt~PoZQDGyyP^|&L-wHOq9c{J9yah z98DA5gKP#Se;H|s-SmaQ{y{lEp*H>37k&J%@BM!cvCIEHrc!TN_OC<nGW+s_|L(F0 zYO*3~{%gvf?Fju}$^ZQ?6o#39{r1fN`d7Z=s_4t*-&y*vdCdORcg^-YB=`TfwS7a1 ze|cTM<#ORWB4jWE{Shj}<D*TOFdv66@^DXqlLJ7(*$0tf$F$fnXCEEy#u)t}Dx^PW zpw!1A;A3urMF(Od$q(Nv{j^ZCgJQL#v^YMlx<fi@M|D3Fg2J&61K~5-yTjF^GMFDH zAJb&`!Oz++vBOpB!_vx;<Dxs@JSN=Gqky<C2+t1ixx>I6tRkP;wtY><@a-Xz{AZ|8 zydJ1<`%dr|Z_P#5{-D=6ehB@`?*_MkgS#Zvtn<yYRdC!n{Q{{*Rcz*9!(aQw+Hc~) z3Su<j?W+i;N5H@r`VldQzPZG*yKnRBlpgI-Uq1$Av2Q2pd|7KZcGCrxP{m(v0(`y8 zG2PY1m|E=VE*#0s7Wt1R<T)fkogzkwF*`<bg)hjEed!Ntzx#3Xqu2Tk=`~4b?ct@V z1K)bYC|;P~FJ=)c5C39WCfrx!&0;$g-2lUO;4fuB_E1?q4kDjp^&cPDkDeFscOKY} zo)_?U9@vkb7w~r;*pHqU@Sh&o;g<GiW@*3|w=|wC&*6p=xE_I8NZKs-z~VuFR<3D1 zPiQM$Jmq|amWa<{<{g-U_PFK2h(I=AIe3yx;YD9gTU9_<@#@T|=UG;CvQf{w_DSE| zElGN`Sol6;qISIat^Zb(+(lIH&@7bU@qO+p^6VbYD`Q;WESkD+PA6W-JOdGnaVcsg zWoo~>O7e(bIj6$YOCvdBr3b8u=8VuOBKR!oHrs#AZ?oMz9;e^@OZ27sl#*OK4q^yC z_?A#FC=?@{7@A9V<tPXN90W|Ri|L;);o~Xdn=PL(@|pKUJi-gto}Z7GMNla?xtEu| zotrpe)+_fU@yFCn{S^l4$XkN@%fO{-43E)Fs6y+|s!y8r`t4ZQAC)t?`e(ieza0x3 zk}4!&j#~08p(0mtVinEr+^HSjtO5MYEiDV_v>78bv+1f1a=To0F_0h6wj#pH*R7{` zwHWIP0kwU9u2+q*F<u{T&>+#~**#H?OhkeH-ukDfRjd*{J+GO$5&>W5My$hX5htre z*FFTSd;TV&v|b%nGBy7;K{uqWBWMUpv|=rn<L9Kr=*W1#z;on8sBt^_<G?%xWJG0j z0g&84_tc20gre%a&2C4NS#UKDZLk#(bbv12CM5&%Od|T4@*;WZ<>bj37yE=SZ`=Yp zcD{FEU(ygC^KTAEX(cJ)E4av)Xd8WA(L1HiX-aGgm3RgWrSzk{%tABb`c-a~JyX8i z6I!z&L^PkA>#%7}bFqBt{T;d!j}yYYE*bt%V|<dBztc+li!oK?k$)cS5%hmA5c&UZ zaeotu><jxf6d@1-|L}Wggu!4EXAlHO5E8+TqSX((g5<}8A^lLj>BEry=mdVK<5+wI z^*#JE^oPWg{yR>7EI$Mv0zo?v!Qlf`FgsKrj$#sm9xo1t4|0^Ma_VR<($O(0e=ryK zTTwqjCop>44nFYEr*4KHOmdt!6wHa_Xc&^z0jH=BlbrmRpQhA7N!)+5e~|biIgWg| zO!UX0et&019Hhp5efgjIobup7RqVgZR2r-nowM8hQ>t<d-U97E63LhMm!J#$r>Of^ zf-dl%qV9hVy5e>O-QS1yzk*WU`^n#e?g0F!sQc5P>*%j<EF?g;)z?K35xsWaM$_*H zb?n=*9i<${)*_~V;0Y0|5_>RiJ}e_din}jmwDT8Fh*`fC>#6vrYtGoA=M?FVQ_k)8 zhdamZ4ld5<s|itQJp0F(81mNb9Xx##M1Qk=u-%J~%2LJs;U>q&0S@&{bx(Oyxm=RA zAw$nB_BS=E%*?TJKUh|;Z?typ{{8O15T_0oipUEe0V?hP&&;a${bF$TAuzatZgc2S zIpnr4{KsP=n!C;19yBX}MOBtlO?yjuGIk^iZ{H?~xOrHp(dlZ%mDeaZRr7hSZ0zXe z{WXk{V3g$`ygDy#0=UiW`bfYLCkX@R#cU6~BRf;4P|)LZqNWrsH3p<hN$S-3FV_-= zDnP`X$&3oo8U^6ql&)%DXN>*<_Y?Tc7@gCacs<iPyQ`1J6CM|Ca73vQozv-e+)sf; z6IPc^UY8{Ty|_GJF?8~5E}=w)i=trV@{%3cyr^k*GpgvOrEr|Zp0couPfaPLLw5>- zhOT|A>go}l50rKyPyVPv+1OR^;DDJzK5)F{FC~3%%PC>X<ut4%`>eug3psCdi|53t z@{G%WUE5gV+0PK{<zgQK#AVe*$Bq_tpGl6NY~R1vHvXp<`L1pJs|)<bt`4RMf<WmX z+e_d_iGL3R`-Y2tivHB6Nr1s0dujY*5gi}7Cynd}e;5F=4;|^~Tf|>SL81>E>If+4 z$LpFrVoH>J^giehJ1IZjMq@u43rRk5aUZV;{1cxJuQ}o{&D)m;<6rH54g;W%5#Etf zf4r{uloUxm+9%neiwu7_So@leSzO|iJ|Fz3KW$pnM*zUStBHuR_|$*s%PVl+@45j3 zVAtZR^Z2(x+|ESHN8E~q)$ZG|N9=f68voOd3Ve~+_-+a(2<%I+?uTBl>#5S|Y9rs= zBh<q^0@nroNDN<}e6YU10KMM#;%^7*KQ8glRtWsr68~(4z_G-?t_m#pzPA{nK<Av> zxts%Iz-Urq%g-0d!pJ*3`b8zZ_N~NsJZqK4lN&kcMe@*mS=V@-`8s3*{i)N{b6_x+ zf1CkZeb`R-6sU^IMoethtVyrgp6ZcTOsn4~^@R+>YyaSo@}{(XyV7a*jj4;`U3~J? z5daik?ykz|&Sc$&jW}V1V9XK-UKz67?r?$deqZv9JyEi%KoE&O_?#c^lWBu5+A1CZ zRfgeNuuk$&$Ou`faA9m&eXhv1G~#OWLVwY`{JG&1HtYPGdW+HclCRGgqfzZ`y#euI zK^VQZ-6Czi%QarWJVrdt^cE6ibwHW`T(dgQyt_la-f>Bxxphe|zK0o=>=YAFzE&B; zZov)&-ZbmqWJ)f2Dv1;0qDFBOA$1K0)7n&61%a0moTc}vahUwEXTz$zT!Dze5Fx+u zdp@&;6>e(R$oIP0lX{wyZ^#&TG~uz~y;x<Tpbg_b!P~3P?gn`G-a|hDkw$BU=a7jm z$4>{DT)iL8&Me8)g(W&p61*uhat^vsRYI`VT3KpyXL_x@or<V63c&6HxfMyKAmP+g z`=(6KN@(FzJ;wPo#$}H8qG~yh^vZ(WiBAQddQ~+M4LeRy#@q$2+I4DZJu|L74w}UU zr@2(aua?_BPt#C3&bBB1ZNd~C1H;#)oC>#?eIc%kg%FW)0TOTjqb+%2b;J{esd@O8 zaEJ(``kQ|rs;@hG$v<iAO&4W>^$O0ep$cO(gFORNJfQt}gSesJ)A1{He*blA3GVm) zPB?_`zl_@CDUY0nv$(9$zy+HPZhugO``+jPSl*ZCc6pZck`;C9U2{%+ptG2)*Q~ou z*SX@LMX9zok*zZEek0g@W}FIzm(i~-u?=K3G&!%UiC4^!B_peDb*t1n912=-?ZT@e zL{ms#FQyr(uRNboZorXZf}AU85BskSs4wryY5DEJ#)CaCaP;aJ5^^G(cZPO)E2bS| zn_^0((7Km2IA2J!1B-p%;V7KjArT<nik^j_#X$r1;q<W7hBRch_veG?<d)%hbd*Kn zkRTJKi3g3!3*MR^I&G=oCurD!E1?wc0*>i78$DyX@~y>QHb=5E`6hQ@*u7ukoqjr| z*o=jm`<(C;^hQO5CdMBr!T>LIG(?NBw->qXaHLO>XMyO8%8?XusmO~#<tFP)g63!X zCCsix^TeIZJM~=MMGBJwd__?`oLsI^P-kPny>LkNpUhN95m;3>QU`||w^gfKl$(tU zs0{PV<%C;~(!9m;Yyd>NrDwI=t^&_-53wSfc0$Yhtd5$o1APUTBRbiPT=lHF5No6t z*5Df2>P-|=^ZdvFXd%2yq^NI%%w*4!MWgrcaUvDkc5cHHLy+fyTSxQ+rfTN#+R7xh ze=RrDV6=?}Lx5#_mVe1E+Jq8|7g~qrCgQiRK}Fcu#Q5wkkbCNRw}|uEp<2pIh%1z` zuCpou1}-5$bnyc77wSSb#K<_jmY}De2(Gu<@9g`TO%qsogTY8*<NTN5*G0YA;=erg zmTB4cTkk^d3$5wf&-R@C%bTTs?$R$%O6=19IsU<F;(zR--{9GwT=2IR?G#1Q#Qyt0 zNP?zu1jkVnAsCdR8Iq)k9net(`NJWU=;I6)?@2szjKJ<ND5gHdB>Ge5CqDk_@G+~q zC(TIuLp%rP2b$WmdFsO(Pd`YEj6S+<^pRjk^l>F7`{1th0Ef{BbY(vqLLonja4>x| zD#%Ypo>NB>pL_&CNa7fZIaWyi8%2%^ME0pe;L-7({DUZW{CBvGA)mqk@|iuMJ|y`4 zAo-^j!_$H19=~|Br%$nPI(sdHR34$CmY0}cf7pK5)2QF0r<?GL*8*SaiVHV(=uFL? zMprt|ev{P*?ftkbIt5_03=+52H*qs*f4v-XYM~(ZIv;$?yYp`+e81rBi|r!tYu`n) z`h|sMd{|iG%Q#fv-ls3ti}tr;JH~rUkuJk8;I}L+L)ERX3Ed~nPW_u}G&j^G^qab> z?6>r~x$egu>&D4IjJb0te@kSK*UXln?)_K!_<m33+X>$<_|1k9_+^MV<-antxSuk# zerG|9av26FVt?1B$RCqur7RP3xqtx^t3)f}-ONd8#;8rBR=jiz2l*{igEW@vZ3zUJ z%)Lc^0p4s8NUhcyDA_yAk$h#^vDOBaaDToLX*66zl~NE&NZ^v2z)Z>!uDVy4dcBod zIr#u0AtppUI+VYJ3SB@rLqRbzVWT(Av%bR?P|-{$xM;p&&bKSQ1yXJ=>4H(9`1FlC zFjFaCw;hToL7G3%Zk965@zM=pZvA|69aGT-W`4pXg!g8bK;2D`$7jG4oT=D6aRnI0 z(WC-p!n=;;l_6w%oG%ww*V5tA4zTesZ%W0H5)L*t5-w`B8g+JA3fXzg^Ts>@9kqfx zi98mZjwyV{z~2Ti5OKBN?D^{e#+TuX;E!Xjz>kJ63=>j~*2wVTI)e7pN(o^(^Tldw z_z-?MX=}i7tjrrPhXcNhb+AA8B^Egy#IvmpWHWzY(s*XucTiH=TQlNkQ38ou`FVt6 zl176Bltp-lp-EVUoc0h>rK)kbDX-l{w?n%CeMOwg;NoCKjtrV|UR44pZhM%2d4XyR zpmt)}+EB_3dSu%b!$mQm`mW^fRtmf3GjrtB2q(FNAS_(ZUf<)-3lJ{O)uho*LsBY$ z!(ph18+x@T+(RcV<nY`1S*qkvSJ{RPM9fa&Tq$9eWy@(c6(t9vtJK&Du>(=Y4x_fA z&$7=ctZNmQ05LSkJ>LpXL2fbg@J{X7L5=yOdvrqcXC6k?1TYdrk1W@bAAEq#W9HKj z>_yL)t7AO6(<6X+lfqsT+jKbc3>3xgWU}J)zd<+-SxL3Nlp=Wc=)!BysP5P3U+O!K z_Neu4s^pz@)p6+d-|T<?o@x9K&i_s^{_VNHk+&i!7{_1?r*_OmlMI5R2!&D<hT{ZH zVKhnM7)DV9L8A<bGC%CcBgkh66FEjA4|V&GNd4iNgd7Sm)W=(Rk8FpGOSXr}pA|d~ zC#C3^h{W=*tYY*de;TJpfJ47{2Y-U%9^>}l6@Q$G)1L|MM;~`#CO!U*e)!Pvr<%P7 zLgHg<y#IrKl({nM2+r82ZojXe!H-)KAKj}%!!<kjF))5OX{Ol`x07SA;7<c&a`fYy z;ah-ouKgqBz?TcxXLkZGsJ|-DbNap`v-yXwF0g-hSLb)mMUJ@ss=D3l3OsFr_gGR? zEN=dz3T}Hmz#e1d86*&T#3RPiQkC@Cyy34Sh5E+(6%Zpbo$%yT+|7m==My~Yukr7Q zarS)$jJNsL-(S3kza9K`OqYJ|J<RF93R{}MF=rrYrQx#zu_5=I=7_fBF`1dQ?!3o5 zY+tT@zKgSN6{}QyD|#@tcbDXws}_KBXRhvtApO^R&tF^5*dh?-AT9=Ap8ZRZW#0C@ zm1wb6<8?qXEMQZ7J-;!uFUPfYGPAe_j*c{SO+e-#pRfpy@Rph<8^EqN6DbW%II;8! z*%931#=U+fW2``Xaw5zXk{9PYzc@oGuOPhAXD(c?DaOsoHNLC>R<PM1SjtR1pHMM6 ziyet*0T&DOh&S@?sTxcK7ko+MxNC?vaa|D5_88*~f~w#>NdU`5Ca(CV=QP;%dEz~# z+XZj!2hNKMpPrI?i$L$$?M6l4SY;$xQsW<SH<FP;q%i?-x6x=|ZoQs|F?ELoanO`4 zp0^t@wKq6WB-EQabW>Slt*T5YLt{^t1c?ajjoR*t0r+yyZo-P!O||?dNs^x_k^p~{ zBr#`cXf*lkpWjz^-}&|0hsu;7-|O}RzzBTnJx~4>XPH;%y%3a)^dTeIe!OF>4ueDc zRQC92b`aTmZ9>SnjL^2G;tw`l51DgL%vQ+4VJPWy;sT-fc$;kYB0!h88Mu{tD%KnA zJI&m1l@SB&3_s^w8|ac~FEY^i_mF}zN)SAA#h;VCLdcsthYx|I`s-RWE^|Fqw58(4 zB{h@lLM+zAVGohD!L8-5K!4xxX9AUX7BZg2Q}O*7bBwbS<WE;h7r(<(%e~AE4lbuM zVjES+sd~h9L$%ARDsMmv6T%}X^Rms#YZk%2ETh+H0jI5&`XZaB<f+xS{zeh`wATE6 zyFEw{G7R-Khx+?g0O!Sf@NdZRGv!*Iph`|oc{K%vG8^w{{TsdKqi8<2-+h_C3U?pr z+YytTu6k!v|1UdB%C2wvqRPfkG&)kcuc!XS+Wr5=`+P6&|NI`msrK)%lwl6xjYCTu zqcNB{cnlPY@6nS$P=X<uANPX4*tG0XFJ+F#?f##8!iHjp>)(-m;fMY=k{x;19_{iU zPpTb}>O%m<vLjx_`JtL|7)jHI*az~F^Vs9&o>-zE9gXAt$<b_J(4WcHene{XPe(Y7 zjtd>`)X8xs`LUnL$$w+X$3^-RfU!^No8uohYV^o0<LJm34;E^E_)YIoe!pf4AK4@P z=az-=5gDoPk<nDs*xV6hBhdHFfVROeHG}+vMhE=Gilz|$7!~)dr})+rmfbzP_>U%) z>B5!WI+BTH&-l8?bKgfW1deEUdha3YTa)<yDas@9jT8Q3gVFvX@d$j)E#r^Mw&G5z z^rhE%v@`A2g;SK-qU|H8w(Tbb!dqQG%4q_N>O%1bF1CYuWwGyjENmQo10h&1f=(Da zbk$Xv{ato!+QP50;8G6(cMtA+7=`1Fb3)JP<CfV|!t@dPdf{vYcdo^5e=^_F=Ir}Q zzxE%1pEe+F=Bj?rJ*Us}NIkgt!mhB67WXCeEo@I-PtPxu3ia<;6*8b-<HY2#fFR$} zvYfq8P9U}Jv(%LK+;2)k{C#>$ujddd?d+TzRh(n=F;R2aq-Z#^HzpHJe(V4ktVsPl zg1j|!x1;V4v-kCpD-V#2PZ`+r1@D*cFm&nq*fJI2z-hIer?<w2H)|3HTuzGxz9pyz zxg3v0NWgLL<_SL6!vPret*DIy%m`M9!?E=w6y0#<WKyJnd3FKTh(Lay>XX{a=h}oc z=XI;Lp<6GSrKv5kN(-T+U3Vfes4X;qO+xej82R%VeayBM@=s6%ZVQw{&r41+ZHAwU zn$p5&`U(b=-lofIyO+#MP7pi{+EQ}Cn_1j7%ADdg$ONu`BQ4M)7%X2%bqiqMy0xL+ zIlP|XkJDH_**QXjy9*gFH&W5+ga}k-SJ_I7tiFh_zrkn)j4#UMnrF&9u2&cHLM9(% zxlQqr0zIg<lO;=U?(Dq@-=z>(wz%|_M%l#`oC^V|7Z13EE)}a>WWS8<HKmN^Kg7Aw z?%L#XR&g(&N-L&jT<dr{35M?{*Gh2~ETYJlbuO|uU@w%(r;n8)YSNv<38h^B#=M&| z@3`9upEHrd(ft=#R&ULP^oU5RTlE_Frh5vD#NL1?EiT?YI$!3o1*_|6dh*<ISJ}t4 z-ai66znGKE%-$u<vF&~C%o162uH=dt*O3V!Ism)pW9!tfhbFqvfa*by6RtxO(zAU9 z1O`oiVqp#Zak%b=_O3~=<E6Obq_$k24#;gSZ1)$){v#y=_;50Qn*kW#85N4$2qSeT zV|s_2-pLzHKFBBiWtsjtn63^wnt%kono>{9TPS2GowRqnX!q}-$2K_8U$g5#M99N3 zlEShkp_lhfdDiSPygpK-QtoyR@NNftSaLSN_N?kL&foFb<K9o55w2w`oX}-v&jg_d zs)b)~(j8eQPI(nqf^Lu`Mj602aJYOE+{jYsoCXkYT|9}0vbIE`*^MuTJ*+;)8UCz4 z=$qarO^Xh+riWFKq}$p8Y3-dgEq(OYJH_0tX=!or7P5l-P`W4eP!LY@#oM{=@2wMG zvi<uvljq2ebbQhucN+q{`YkJ-9ZdU%{-|H%ASGuML`r#FUhmGp0`jKB@XNXw@!hAh zeCox4P+c{1%j^QxF~IhxZne93#jNwy4l?l8+Lc_!gJ_0o&UfU#-<>a&Z9GkE9EVlj zLb9!#ynPI8cOM7f3e9!95O2Lx_-+h0Jb3gcNVyA?E!vt}-l57D*<{dp?=dIkYrZi3 zn@2z<<3It|dLX7EGFA;CrBUr(W@Xn*xKtw&UK<;hN$vLN>@9Ix$V7ThjOJ--<NAz; z%Ttl*va11~J!@y9Ty8}kZnhtpiod<IB#a4y7f&TZJiK#oeoy;%&#y+xZKapj6jzDr z64}V1D?nUuNJNzxW%{Yi1>^ZZH<@jumC(wh%xQ~?3VwUPUIrmVY&rPvWlh^F^=5<d zF~$`jJUwEmZr8sICzY&evaU-0#U@djwfl>xOaEnMV-`J=@?UB<PSrFY2yXmT_77|Z zBg75?|IV2Q(EIP7Le2kEYxo93|Ka_A4N>7Aq0ggE@v*bs!R3z9b_|-tN5|o?Ec|o{ zX#6w35g#py<j1B7@JFB=CXc#IM1BSrnPYlzzi|BFHYDUnQ}^?R>_fHPFOQ)6n}1f9 z`S{f^=s}%@(fz*1kV%Xm{f>i`iyoIwzT7D}m=nkJWPa$Y5FdKPLCnpLQVtp&S|#Ym zqnr3tkFZ0Q_s`I$%pcOR(B&KY<k+8ZBp$yT`L_`D1qdI>%r6!$+<ga$vO6blNz_I4 z8$6?KvOC7|QRL9~Xke6~>`uq)LxK%ZrBjojZke=3e+(1usOqspvk%%#wl4_u{9Ct{ z*B*7i@3uAuTsE=%YT_Nj?eMe?4rZ*kzdm&6cy5P6Micm_IyxrrIs@Ke9rEdtbYB$6 zf%GeE({1PL$cyup1F?fzTm6i@7>6rLt*_sY)xSIs;MWi2pF9uX*AL{MJP+X459FUb z58&4i<k!#RuR_^9WD7i~-60w8=&P`bzKxp3bB}u6oerDl65Ds~W)1K}Gmw2V?1|W~ z@zMuP3tn_6vH-r-<Fk^ucL_z158u3176htYeWEMrQWFXhmah{yKEWOO$m8n?@n@JT z-m@`DQEkI}xMJ`7T6igRv$X1s*6tk-iq9Kzp+y+xDj{=D*2FLTIjDz==hx3rpGJ_p zvSyeeFo55{F4ySJIFFA!oYD8%sYI%4kXkmOZ)%vLC%%rbqxE*C{-)cKaE(;5_acfv z!6Xm#wVz5?Gl!@Xh6Kqnv;=eF^X@f{EiwCGxTZBKItFGx!q9Gl?4gB8jV7f;s%l)j z0K>m&)aPzCR^f}iJ}bftnD}Z%I$cN#q5BflRiKX;ffyQ0V)5s+T_!_&_lD03PXQ?M z!rurL^;5Y<6(`1nu_L>OYUYR}o6&S4n#<~Q3Kn~L;p#Ucmi3zizsy%&*Lp|-0TG@x zo4b@EQOPb&zaN?T@M(@DumV))6L#~0Yp9|54285SS@{iaH@OLej31+CF#tv>idn-m zdVd4Y%xgo^B$e*@-9m%n3f;U{1YTHwXawwWXG}OKnRc!WpDcBeT;+QYoO9KPBzeF| z7kdpiQy4_7dW*G1izogv%?wt>2!5tZo)2$Ui;DN?1;VZ?4Q(ApTLN$^G(^mrpNnv# z)M(F_%n3zk=?vN{%jm5RX6!m5d~YQ%{{tus{MDJ6U-zdH%k4J3J}thR0?D+WArC2y ziFcPBe>yY6DjpTP)_Ewoz^d&nm=e!uU={EucihyBnRr5`YX#3Q4}J=D&rP>d;Ism5 zB~U=hAVIC|1(s4hZ4bH%pjX%GqpPccj?1fCUO=Le67)1`HasV8qw}N#p@Jt2wsUex zWsTLFV#_<KO(6}xU#0#9H4(J*6TqCI6XQ7XyDm(v&a^DL!1&sXWf0jA-g+mj;%YRn zt<G}l>25^XNn=C=W+8A(LDU68BEOG`_gv7vCXJhe-_1T4tuwv|0bVsvx#Pf-EZZ4O z3wq@k*3Eo2PfL!TjJCt%2&id!lt;ItQ5uGq$2-8^i}d9ChZqdtWxP>}22)V+%=_1E zRcFz?-k0laxP$R($FwT}pQ+xpbcem@_O#KBQeJhOMoX{}XQL6yQYaExfhSqKitf^* zk}ph}hD(G%S&t5GOrU`=OlZP%J-Nf4uL&|*pP1V-v4{a2M@l+nHOW$41X|&I4{Su? zYZc;S9eHi0JES=fzk6}f5xg?zi?D(9a0e^-r7}`cvH~Q@wvi3lT66s3PA3NEYx*fn zw?!kfMO9rL2Oh~vp-O`3+UbgVkVW75$@F{wm4=!Tw3wN?JIrNVJ213|uNSK@EcdG% zom48UJ4FLBs*=&Cc5Q7u6<7EsW|T8P!b9={p1274P_dbZ%2FuukNYVxp6>PLm8i0V zT0itO7+6|nctFl*&hYk(gR*;)^#2wp`^|CY|1_NapI*m5fwaF{!=J)h8u=J^<A;k* z79aD_IdM!}@5mNT5AN&^Xb<^2^Z<%k{zF*H<Oc<pLJp=c^KolrKDJ*}`tjSQj?2f% z0X%n%OwtG5jH3hPl0SpB_!s^S@o`){<oS+)Y9czQy*my^h@&Wb(2bL$(ReuRBnQ5Y znNPzrIuJHV9F^7>Io^EO>?B9g_xLRIzcK7j2{!8iYwyFaVeM}TH9LeGegJ8OFLb|u z4rvbr2mD<KX9*nt4Z&S@1PA<6NNYKU@YNl{`ciQ{I5J;IGl(uEJG4E9c9NI=;mnvv zvGri)d^@%lQUB>>0>2FNq&MCCjD8+<P(@rrE|qtX+3CMpcK=!SuU8HHon?P2vixt0 zuYm5DtNE?^`kvI#dyPjQH`q8XK&5-=A;;@7ZVyh3`wl&63(%stdBl6aFbt%hk}mN+ zcrfPnWjg3^%s5y%#(&_&d}uKztpLodJQq7sz?b4BhOHcm_~~>5Q}ae^&)U7FCvS5+ z>sfnCd&PK{W?j)D!|ft*Xk(uCFgD<Qx7;WD(Jg1OTx{NXkcRZ~7&={j2b+wX%&-UF z$-U+_4>~gE{ZICOj}?lu27?EFroH=@q<7C|1@O2Qo>=kHotL|?pb$tT#hthhfAB>6 z&Wp(}Qmf+q@T#mRdjQSNX5}hN^m^HoAdeif9Op#CE;Hh$rew<8JmLBvg4+i9;Y+`$ zrn+*Ogs>^mQ@1_`_B`Umv)Fhek-N0jU78S5=&PkfkCkbXx=0jw+gMXeKdb!G^B%8R ze_ibBX31Yh9Q}_rS2tzPE}IVht@%S>{JzJ^&whUVUheB}pZ#6%>sM#~X0DP#X_{nE znj{&DfpLn2Nt~o$6vqe{M@R-H5d{6=J`R8EX!DP)Px{3Z4LgblS$b$?;pw6Kbx5hg z$AAX@<MPD5wZ`dZN`pC!%izyYC59Yj1SI`%CCOv1GWirhnDiql&wMUS|70I$$YbNr zJ~a>YqoaEC%CI9Wd=(IjjxHPeVRlBJdCQ{{hkZ2iKjL0UbZ~L@jXukcK3(#eU`g|% z^_To<c|wYgeH{5-p0HR|HQ$tQGcQJH$=6~=FMPHBaN27H?DrpK3Vu<1@9krI{_q`J z7yhD<<$hrse$B#xFMD{p#hAPPnvEi^uakqElw+$se0aR?0$<K*)GU1H(;LE$;l2nc z{Pv(%bJrgTd_8nN`4(Z0Jq+Fh#SHAJXW^i3o%)|h@tcj#!cI%-voFbJ?QhXT5F6XM zC*OuS13<U`hBc6e^(W;DOG5r`3H<49MFNx*l}rqc-__TAy@Y<R)L5Em6|}fRyacSh z)iKsqaxC8L=_%EaW!@r+&f&R#wVMP2u&vYcy+$y<%SWn)#6>LI`@&Uy_==oI8@Agu zuV3pz!Vk5G--Ir-g+^639K>3mbO4rsY>P<g)+uTSEb!-@)?!?rVW;tHm4m0LUtpm! zvej5sYeMLnrNJJYvGh^zVBG_3TDyqO1isg$hbR|2FSjj&pM}k-jiB%byR`-G>UWB} zhE&-?;@Qw@0X*$_frSm50&s*42beOR=hNa56^92+Vkpg+&NOwGPXsZ|_qL+jSIU~W zNoA<TU!-Nm7_!D*pu_JMsIEp)xdf<UO#!26NKrzky_9gKS*SU2X~kit2WwNvk<rSf z4@VQ2I!9voro5d6(71GjA2m0y%{@g4#h{*-r_^N834xL+I=#%0(`+KVPH@ZI?2{O! zQ4haZ1&+!#_B!CwNOM`wS?+6{Sh%>C!Jy+8F27!`b;>SWtb!TbCpS!&#N{oMGiQp} zOSogV_tx1RP?t2fKdKdxrkC+Fm3iDzgY;4-T%}qqWCC@l`mN>P=Yc6!Gwyp`FeAm| zaxq??@d^yeCSTyFzwv{LDN&R@={y=7Mh>9o<!aoqv3Lq*-$PIy<E6_Z{MkGqSh)wB zfWUYacsf*z1|#{J;Lh<VXpwD1hmGrB(SZ1IZvR^i2x5}DHlyN(V5N7le`z-E5ioNb z$6v>Yfgf1|xfT-)@wN?;U<zj?klTB4+V1L8mJnZk%%FO1q8sEgO?U?8xO|IJXRBcf z67cH<Qs-Ns!NkBWgS1IrnM<b7bkFz9g=G9ZNf{`20Vo#N_)dnh31D2dCt{OC%aIFr zuVtNkih4oUjfv(HBtJ&Injs$n+oi9#%L1W3G~91vHCoA~hBOT@q$xnJE4R5fV&3!B zsxRJ^vreV3@fb*Y?&^`}^Mbw3xnkEdztoDVcE<ZYDSV-s1aPs~w~C+i>j{*{#tW1f zf0X@NwFFf~@5#UPr`6um<`>?b`64yqOPSVVx4ef%nJMQ9*mvK%O>FzVxZ75g!z1)- zDN?Y<1v{N3umK@()L3<1rj(jN<CPJt2d`;nH3n_0DG$`fRcsz_w~d_vKRHn$R<kYK zmG}5k9+Kv2)PRE|cGD4qAuPm*Q?DG8l#juXJ-yuo=(h^vaICBCi%D#k97Ome^IkF% zo9;-2bG|>uX2)($1w%-)l;B$P<rTjV+U0}}uK~cVVi==R2;9Y1n3byicspm6k*2h- zqbuV;6Scuo4l!E=%OZ}45&o3Wv%#bYVqaOHwdA>T6fWsJaVbum*)ZKntQ<JppHz`R z``^j6@GT4X2aF2g8h=s+aw|mfy}nq2N`Y+OG+#v$ygDeea2(Q3xX6uQ;|dnGWZS6) z@4m?}F^WK7T@rpjB5daql{!5$nNR-WfYaswmG+qSUly+)gGB6}n6hg4uW!eGji&ze zo!^kt?|<~0$s(GdDH4Ne6h8d0=^a1q88Cs9G`a(+{RKt*aIPpr4_|2*Kho3````=Y zki0@Z4V@i;90?|MP;?3EXOxs3;t(JD$}zoz9!cl^_QRY9{m8we2PI|4I>bkyieV1T z(miM0|Bb>wflfy<{u!>_k=>56;Li~7j^jw`$ZB_RgrG-0drU2%2U`XH^nFO=7=b$6 zXsLr(vm?RybCE+1^^@Z>AN8&L&%J(%13IDeH|TWr!;7KI3A(WdCna@C`L6uPfkPL@ z-}5;R-30MVB67^LvZZX_5$Eil1ltxvo%;%0*3~o}y>RZ*3GgcJS8w`E)2^2z(X8)# z^5uM{dyZjRU0`3I1oSXbJiH$FyZ<f${rh)6ZVvqNroUs3_;?k{LoZtb0yfT=Ry|}C zmiOyz)m3UV+dKb|pP5o!tJrOy6w%F>iqI~P%}qT^iH(ZH94pBOv&aFCOYWZ5W4E%- z3A=M#2=mw5X0f5Ne-TY#m1;VL^Ra#tut^Q0p(4gb3A_3!sPUV91D+x!)75>(lgT;f z!p_^5*2A5pa^1Y>>_e8l4qK=NGY3=6k|-ojM`t^?-#mRSUlK5Jf**-{(kKcffhB%6 z2j?1f<Ezm|&NL%SNXYLu_Pm=8zn-Ek-G4daDWLAlkmM^E0vLtYhT~*x^9HA=irbqX z`HNny?+zjOeun8Ff63eMvR(sgy4smJOKViXrv_;ssmcRteh;QKM(jtk4BDhSS$%c5 zT1x4H;BT+fz1G6vJo*yWuHNXkJ#B@dlOP2`K1jhi18uzA-#0;S;a<MPZV&MqNj09X z!PG!gN)4T(u$^2U>?DKNK}BgFuRQPU>C!eyAW^`2CzNLJ(X{t!O@$tXOmYtCPCiwt zU~(pmA((GDh&Q9AbJQiS_TLKm8WXHSR{W9O09}($IQ4P|KKE`QYCeO73^q4BM+Jf< zgRfKX=AC3IoV^#nAhbIhv;m0{sO?M~^+18}wv8^%FbtbH2rlwXgVr3}xrde`Xf55o z?IXjJBg}E?6SIB<XPAf*3VzatXX@DmID>j3WKg#7J}0-L^8>wjuJ$RGqNsvn<QoDi z0(~ulKb8!Dzg#o8rpznHMDo<fDSGP|3oYJfPyvF|W735$*h*zhOc$J0UjuPJvDm@X z$GVi~N0~JpiQ6|EsYLozvDQmPFNb^zaBh!bJ97?OVoG_UNjB!5$j1BpA6yqXg3~Za zukA$;fKHN{mRPHP2bN`Syftq!phBqz^HsAkErz6*wi3j!)|I4AkBSUpaB9!D_`W$H z%^`s0zZ&6MZ3YdF0u355bPpLE8kOa=c8j3R7Z8K6085(%jr;ojMAc1w=*FcTE|MJR zz}Yom7j-fuKBp=!QV%bvPiS(gK?xh~S0i*qm2#y3nu9}^SSdBrrTvI{T*&){wsL@? z)OS;g!9+JZs;JAJv=gwb37A^#_T7-i`DvT^Lh5}#OxrB;Xe(UKlu=dqInhu9I6cm@ zvN)V}I4C}{IG*`lwpLONMqRn{6AR{P*ip!QV+|IpJTN#(h|m>1%cTfWw?G~eT|!?X zZP`OEDU#BKh8Ib_RACiyA}=aFAw{9#zvtxwN*ry!UNa|NVlWLT^;JIrvZpNDi459a z?$J1q;C8`UXb9O`6M0fU;ZWzqCf+_1X*SO52C}OJwqA|CN37V+4*;27n+_o<UGYp> zuQgiL*!~@OdY<iK60_x%K)-_)xyz{$bUkDbaJp|cV78dOG%*~&+^hZ5Bv;38M^RfG ziZxoI9oD&)Z|0pFmilQYvosipM?X2#ozSMF?-wh*?Ay}X-vMh7)h822meqQQq^BNk z5wtE~76_he+L50RL=PSqWED0J(=96UE}Q1KH;j!IsKElvGrgvu<>1dsY~6|-%FEfY zAJ^M8I#18PL4so2=-qd}QJ4R6=y!Fh|Mb4^xaxQB`At;{$Izo7MKcIV5(G_<G({gI zCj`Y13dLZUzzK}T$bE~#e<(4EeFj_de@EF-3(B)&T;_1GK596J-!w@dBi4Cxu!1u3 z#}cFIN4%3c3i}7x%09*akIWXFAH{z%JLJ3akCkDP9F?m>PAmI2^0OWTogKq2*=GTG zerSo&A8571sU4<8AAQjTJ8rWd#6HR_2>J2#`3RHl_c)YeKJL~@{ISd?j}Q1|sE7P> zN|X5k7VS5HWpnM8zlj#A*`B}`4zKRlwyDE-`+=?tuy2~g52`@d1Cf2L0?DR_lv&Hn zx^-WrZ>6Uf$HksR0>`lOuk5N{zf}31&8XS+t1I=PjD>&by6^AD){8Bkf!|lgei>fr zkIu&w_>U#7e*swgEzEB#`i%qir^Iyo8Nd?104(zWSbNMlpYTFaw9N2pAc+{IkT^K^ zr~tuBlsPp$gA`?OZQzm>mnW-E<#Z{`JvST&+ccg%xAa(i(+fp<hdRJqNL8g1kbLLJ zWOew>t5$5vh_o)!ASCZlucD94)!f;V@VsLtE+$iBNZPkUoS|U_REd>i<!KgYtpy`! zv|jDi5efy<H09#f_&j+J&?!6p6wi%PW-;E@PQtEb8<mz9k$`)d>y=Q5oAHL=tXR)J zJf-{JK7to_hM+{xBdG*We7Zi#+PM_KXOa%%0MifpE>y@FU@$51+YTZh4!^xC?b)z+ z%q-N|Q{z{XWbQ@6a5+~6VpCKmfJ~l)_P;%`5LfWBnJrKk`&My!szU+)sb$}fAOLXC zaDRgVR5N(14osa_y*ZgPFSW^wQcb())gR>xz`;6WO+KLOG%`cJl*c_v-ipGg^viP& z`k8#<jYg;sfrDgdz1PkRZ<_2g&-j&ff(kgqRp<G-Zh8Nzk~V==ik+*@>FJPBYCm}% z9Zs1Niq@-aVin=)dV<<<fu|@nk<}Ri11y9ai9Ldd<>STQXx-Z=cgC>m;P^_GiKGiT z1M1RCWnUQb>`RO0HK#bxXorE91?ZtUH&5=QyEbi3SH&vn`kCIZH-(Q--^G(u+RV3w z#7!Em#VI+p?Bl)Zq12PAN%{^z=%Wg5x@Cf;p!uh&kDAmkYUi$zII82$I&m)D$LQ;1 z2q_wt>$&UAH1ji=72^A21D=C#<#BIzeK^YaKzR0b&wFp?vdF|g4Jhbe3@GSd2q@?e z0t$`NG{KM<K_E0jWB49kV3MF2lz`zq-0ZJ06#HSueuN3)=r$+Wkyzs&r`y911U|YK zMDlMcIp{U$C+Ltr4k$!)B-B}cbeU7?>o_LyX;4s~AJOrlGj?<^h{Inb$&Vrc9`9k{ zCjkYCKjtdvr)ixWfeME|{R{NC%AUaQ@h<;#zYnwC{HP7=QEyM_Y3%qQ34XND4>?Na zh&zWK#V47M@MBUl{&ObKC!lP<4Jhy<K*|TL37{uu*K+@+&zkWE%)I{32bAsS0p(~L z|K`~LbU>;9PR|1Mx(!Wk_m>6~eq*)Srfuj{IM#)>Jy?d$tXijVD9TUeRICW9bBn6( z>F8OGOY<st%%qWejo+0x1Uwk3?MopWcTC?gB_o{J=Y2BwJewa4*doe6=AUkl;Vh<i zQK&mzJeUNEafW0vjb8vrs<pTMgBoC`<pYs44x+X-xPQLKRGs|LIF~p1elf>0Gjef@ zX6Jl>FD7~APIj;`8bEh5XqetZtnHdcEjXxFh83GgyW*R*qkqhEI<^xj^!~&Y=4mjS z<laU4N@*mIhs+Z|9p9cIE-yitJ`1gk)=)+%Czr(9eM?)?{LGVzPSMz%M$(bKf=ZD` zb!b^tT6$oc0dI(}TpyuN!DBg7w)Do$S%YB1vA7XL=y>5K@D<@y%Zji2LZ4me7LCuw zC!=K%{MZ8M3kARXsKaIIG0AO-p&hEz;p6;B>~8RsQA*6h&QA_?p>im?!QtDKueVz~ z4T4REHPAX+10vL-dKRfl%owVUyS?*Au*X-ej1%^TZ)i=NnGh$LGG&_!nBC1v2A@Pd zNc|h2^a(ZzpNQq=W{k-rhF&g<tT{-4j0G;;&B<IICQoY7oban#D$D+7(m%Gi=Rycc zNC5Pmt%r%6y1;!fHAVuR^}<RED#4zZF?V}D53)~ebJ@~?VsqketM7_K0K0bSc!>(Y zGcxBb4Z#)4dAFwB2$pCpF-!Rz#IpHMxx>JZ$ir+Q|BgF+TZJp9>sM3q*pmv`*Txx` zb9pgZ!1)8}T)!vQ!%(q1Y{7ewuMiz;nXn`;V9&A??+cF$?F}^woYmJ>lI;spm^b7Z zuT1k4FQHf5gw3%uqBuAs(HyZI$x1w0-z{`eq6tJHKiQJm2>`I@;QpkKeyZtd;G$u; ze^ji+^qWyX{Yv12urKu|1SWLbK2CdLf}CGjT0UO+nI`Wy;7%CN2UsjSSQ7)OTHox+ zlBHRyy;B%a(KH!k1a2|L@;U3f4wjy}lcPYjcOyi6TN{9yU%K99aQAvXZU|hw(kG*+ ziTAo+d*nQ}?cH7d;eIxdYh`s~2W6a0_bv7oHFVpG7Ko>|+3crkT1LSjye>uL7F)e5 zHz`g$)B*K8v#6Po9l%+v`>v@25qY6iAzvOXq%^?%v}ozfUA9=vQ;EizMj2YDANx{q zh8x_;cklJ2PM5^QSWk?-$c)bpeV9#7+}n{rAa~YluAGRh=?wqgU!JG=(JBU!pKbVk zZgFniwjG?{FBDY!knb4nNi1kWGF<NlC5ZtYg)`%=T|!d4(M@5>t}f`@jLUt8c4yRQ zakA!fJ*_t7H5t%dG2}cnRhewwo=9CpfFiZVS6`SGrTr?;vuSAkba@)IikvT}HEheV zchA-7eu1<!5J6=*-A{TFJYfp52wVY}+HD?&uDJ_@NT@YZWKo@*)}AJsm6%76H`x5L z<`qt*T(txR%rE4=y>}e#zmPGv0sK0i0(t$%i8b~YaS-+wa1iz*9JK$Bff<-0NtD5< z9sFQ>I=v^?FtaDw^!{Ul!G1XOaX94S2Zq@(MNS<+C8a;pdc=W){ug!cwdE+<ZHeCV z6m_rDExh^1=nK3N2w^30hZi1!5QwKge2R?xGqWOhRqegI&*>VK8WETeP)KXd<>myT z_PY)N#NLoCy8U`4B>^xeNdRQQ;%_o=+y4X&#zaUQocb~2f~H_qFsp)rk_h=bu8{Zq z3mAUR-kew&^48*b(_W_-08tSQIylmI+`om+7y_o90TWpC)(r_kYac>@ft2n3VGQ({ zL?0js+tAQo;UMk-{J%f_goBWab2&EGy*W=Inigr2pI%P+Yf~Rfe5L62w=ocaK+q2u zX#J-c=uiCI{}clO2n4+`(8_HG89z0seKu@up`60PD$DWBrKbZfquFD#%Q+c|WV$|V zR;NH;;#4~NBO_n&<$7=6EXKEQGjSWt%e?lnZ{E7iZlkxt_7ldI@?>1II+)8Lc#tLZ zPbe+E@Ja*pcsws$k7I+t%N!xi3$coFB;oU~eVF-CV+BrT3vml0&rY|bSeaD=#NE&C zz}>H*EWLJ<e1lJ8oXUJ-5v?>C7Oz@-%uf5I)?RD<Y=@;7@JF%k%%1h6M`}RVm#r#C zdd?ERGye&t!!KWW{BIf${BIZ!{43+ZPy`LroAJOH3P;{z+av~lr73E27$}X?)R#<r zfM4j{MVk<B%6kd~RG@SAJqnh**@(Ae@OS%e{B_wgBLQaujf1jhLW1aK`wo+DT}U_v z&BR+=wpkbOLj;mz$UEX9x9{`sjK^jnhy*l*;ctQ?U>IP~dIp&I-pqg)4bpZXc4ELQ z{*D8;xGR1S&1G-pZO}l5f@wBj7vFUM+k;SV5{JJs9yBl>m*QvRLCcgV&b_tsx6ju& zzPN!Cel;HJf3xv`|GzUHN8vBJTaSmKD3c8Y8OQx7A5wVgQaI4B6jwk@0Y~V3Thv5l zN!etYBBN-bo-S#}^l`)8@5e~hZqmh$qJ5fMQEJAxX)+hwE@+IaAcGWijc4YmD{hB7 zhX6@Hw!iFDdAjD2xY-yYDw<h&cGKnX`z#goWu@xZEY<NeE^A*$<9b8eF!Y~OOyj}B z-<>(=&#dn`YsemN2zOo0WG1`G57=a`b+JE_1hT7Ccv#WEpI>WvIMg%5SFuS8NgzJy zM-y0`TlA-+2e0Q`U0Ab6SP`cd;qHmOqMgMsQSIZa$BVd_Y{Pj>X9zjG^bmb$Vr{HL zl2y;br5{$0B8M|Avj4yu>C^I|Ec+v$CrH?Q-|+=I+TT9u(@uST!cW2<46_+5j7Cv{ z!f@nWJ79phqA`lxFb;yi*!ByG;xt2`$d^(eC`h$~P7N5eIfNO2JR7(GDzO=WIba6& zO~j5x|DwK@0zuNZt{Dk(Ebv>RjDDL3!0m~G77+YBj7ySW>Hz*|m|(zQE|&d{2_Ap* zzGonJgEGMEz;F4GkA@MD@nJx103kseEBa=6-+tI$VHDiw25^#hTS)pgk>s08egkpL z8xSRbDFq_ECl$!=V8`QIvcceo*gpEZrk+z`$bEPT_7f$3O^jy$GRELa-jA{%o26Nh z^cyM5C;yr9jbRb6B^pxo!vWvuG{3WH3hMXHR%2xm!!=&p&)8>UEA-RGl9PY2poZ^? zXM?jonc$DE;^W`dX<q~f>7|%`gAbcMn9n~RV57_P+DPN4ar-JU1pPKMbWEk1qV2|P z=WBN~PHIMYXovB8^|bwLM$FtCB20pcXwdQ%!>F;3mIl#c%GK<<5gj>WKVNIf-@Cz> zjcDLKDc;o7*jCi2oYFSgX@Q$I&@H=CHdmla8PC_sacZ<?tdgyW%?A|cM~RJ>8wQiT zBrh&5D<*S`pNjiph(a@z;DkV;;oOpGxnrY0Vnhi0701u=!7&cvLkgT6E?AjA6Za^+ z3=fL(=#%JY>a%f&&RxZ^g)V(XO9*<(FZ6oy_U>tUju&A+pTq@;o`(hruu!*>k{yE= z891~nHolABoY(Q$g;yPiR>6+cColJS!#HgJ2s-KUGH%sw`|C5NlA-~XpvcoZ^i?C- zW9n*ZpZAnsb+Th!*Z^Wkx31ucPSAM4?3FPt>`@{rV`t5T>~xoh%PoH5orb!+og5l& z=v~INg*5j^GA@Y*Dv9|lp7~ST)z5&UavSL=LF?OsX5{6L<K6zyKF#QSJCCcTu!Td9 zYC}EM9jo?Aw7FhE4EG_PM&qk*tkRdG!<`(m=9=zm%eSrNNhzV8qU><as~y@5s3N+C z8MGswu={JhgXrpHiwXS<9Hv@p+M6PIZ$zk)N_`Mqi~C-xUXB`_UA^iZ;^HRHBc`1Z zUJ(kx&Cn9M5RbhcE`&T2yb&a2f10+S+1vIymcf%-)XY5|y)!=5hlyYUy|{%L@RytG zHr6^e3Urfh-xbaBFrV|#`%N9^WAH|CSkc^Yiy_3Dub(*RFoOy0Zq^0%zJZ&8%SDN^ zVxG0HX{gw6tQe&JVqU?8d&X!DN0>(F&Gz+IzKKbLUw+d=`z!zaUgmG;&dVkJAWyV2 zMh8lBp`G}k$6xqc_e<U-&syc2*KK%;gZ!Fa-u|X%y78q+`<RcFyFfCLDUHSP##qN# zp)O2YYW!@Qi>{azChSJZWsU8NxdF4wbKci@d14@L4cIux!$;ExNG{YNFC==a9u>5& z42KspuW8O@HrR0^F^Q{epHhYBA3njZ-92(msFWr|^w(37<45GaV0nhWTHZ<Hk??4S zdv<knrVInqW&irDV^)5u$ZmR2hL3GGr!r98$!guT+}U49qGjfznF{!z-0<jjr5ML2 zWIm>~@Dg|HaAVaexbCV4qwNC*Q(=OLq5Hk5I^OfR{yDlB{@^h>NiuOoP0XAW|8c4( zqT%30@T03W({mN6V#pxpXMbk>bGn020~Juaob-Gr>%k$7xzmW%ie_Os-+P$4^Y>!q z-(;yx!sO7iPd3er?QhR4>IF+rdq@-6By9%UUGl@dXA=@;Q;ZZ-TT`v(c{t*Uq}x5! z+1}woR_B1;ZI;v0N%|ffw8M}>>(Cx{?#_+&O*u{X`qVd%ea28t=GWAd3l4I2skCz? z;!b}vlx`gfq(Y7GDXe$oY-Nz{bdDKE!nxERHX)vcVa8`)NK3lASArE&mF%?=9_Y`T z<ODTbMXVU@4Dme3!{PqiK?}p5ACKYYG?pAS-0|sY<{m3U&FG@XF+H2-*F;<7y~hx> zcyY#xy5~tt<WZ#TLwzNoPBWPSXDgiTcLY87uc?syWJV8@?1kD%30h4QaQ0?2bG^Jw zHlK&#Z{s@G<5ZVD{Ba1I=?};F!*TRK4qXNC7NF^?!m;?{e{7&`n3{LPhdT{b@k;;T zin?gVwEp9n{^6z-VEZeJ>JN4Z$44<V;U5QZ%Cw#Pc?Hw^Umq9wzVd4eNsV-<(iL3e z+a3G@A^-n)f1haeAKlweA@^6XG>HKqr4cY<3Mf>vH??5)X0wmp<bTOqNEdl)1%1ue ziy<J#MdF}4H;qB|Yzxa%z*i3vV%R&sx1mNj0TeDN4HiohFcB61t`>>E1(RY7q}V<L zj*|CeEdC}0jxZ3m<KdfPFaaaA>APMDz%U6?b!i9?>xO5y%K*w@5{!gx>wt710JDFo zpL+$c6rTP)K>H^K!Vg{;_*W@dNnN0S)9c2r04Mde?Q5WU=AcY@J^N$mN+A0C466xW z@n0cY6M@6=;d$wy=yI$#2#RhSyx{zpq74X!O+Bch^txWa@Tm5<I-H(dG$gusK!DEk zJx%jPNjDsL-W=gKj`^3ZU(W~v#=E|04Gr4@1PIpMGq|cxhHtI3#|<px!SDixwV=;| zD&4nztExTA8@Jn+9*M)b?)J}vXYe?~FAMkJF+I$GL4YXG_(r2|tm0yn-fRjga&&#r z_zW9h68DE~hPwIIAHXxTp=Zx4#jC-65cqS8ak5drNSpWb>JfUp1>2itc<OAi->CN2 z+S}ffA-vQzq>5S}$@L>f{ZUndT9xcNMBn_6_wYRC)<wI4>EyUUZrk%CaqDl7#{ve& z_aj5wGcUT!4xikR+UJ`D#&zYo3D1vhfw$zqG1#seT>Adw&;0Q|L9Q#JhG2arD;~b& z^Nw$CIDq^7s~op~uFHeR8Gl|Ft@6zYaPIqW3>uvN0ipkZZQ%-er=XBA1D#W`8{m&8 zQWi$3c27L4+9j>p4|rs$X{~dP)wAOiw>#mDg+K5YO{yhPyqp2j?<eHAv)S^N*Xi|$ zDC=_{9ZG4bBm7~a2m4?Sk+{-IBE%G0Fze2_uTRcrNEJrZ;{YA8Ii8;+!tR#KI=tXV ze0i`e;~roAkr8Pl-%s*NKX;`_GPixx7BA`2DnrJisite_1-gc@HA$OGobiXY-e7D4 z&S-@@I1Kx0uB*5y&;p4b5W4m}W2OYUJLjrvd4436b+CsDM_u(@DDeYY-?<UR9;aBB zVQN`S=Ij_FF`X-h$#p8dTbAf-@Mdz6glCU>Ag3&zL9BL^@s#R!>2i{OCQbPX=LPOw zDY{5L9bwv+W@IM}4=-O7$fxsvB=7edP`F`RzT4xO_$u$zt&tY}GBShGbQ)Y7dT~rr zA468ZaoC%3cL}y3L<7wZMRtQ&CEYnjj@(r_BlLWHU1)PWYWfku?o;CFm(pPv#pvf9 z+(^N)<0bQORx!(YmDwDfGH8n#34CXe82yUt<IQyG;~-HP7Ei?^C{0B3%>h5%jC+7F zbdHk4&<6K07<Pe44fhF$>U9?6p%<1uB<zcdk7RnQOVmy=idFriaob@p9&vmxIQi<` zI~Gsb6-vSr2I2bhs2HM4@#Rl_wM*|vYX^<h>TAZBi{YK<Ud1o;87}XH-Ruq+CCs-; zE0Dc3$J*GflxOhS21~Ki;|a5^-+9eI^Y-b&%{^UQ?&_&a|3TlXEb#0HO)%@Z${#lI zDJdv>>{0$hFt?W<miPl4W!kEH{ew6E=l`R-!ms(N|CR+m(ZSb?{RjgX7-ndOAqkkm zVFZPduayf)4D^U5%v*XM2eU!Mn*)QuKz<qw9nl~sjnn@^GSJ@h8>JgCb4`N`5&a&9 z2B~li-~{YlR-@m97%2m;K$2j+?V1$+eZ4=^6=xv9wSkEQe#<CgZ(fW9Wc}$7q}bti z0TBIcgkmy~(~2U1XMn~b3Mzr$`joIY;|2<n>p;wQLmGd{tRWR3#e#j8u2nOux$K{u zLblzPQ`pxZ00IOMf(7G1P=5Z*PaV9(w>&~oMf>Ddac;rB<BPTIct;M1)mXmoIU?h1 zjw9H7+VP|pi{XpbWZ2(?Kmk=g7brHMF8h|pdY{B|&e8cG_5YTOhatliLE;_ctd^ty zEgA2s>$ZJ!!xdus-A}jt>m5V?^p=0UW9V<+va0f5`MVDW`26kg__xE$MHUT>Gi}`9 zL`frRHIC*S?ELJ7TvZ0W-84S)gXYu~Jay4ZNa#r&bFGoBC3{|4=IlG-E0cy1e$AUz zk}qy4clUS_{glja=b}}a$Eei@{;3beg)1SqZ8y9yF<p%=bS3f!679|VX-utQ+?-sw zPj~F;0K?649|}I8{QH5w-S)%r+6dVeD?<klXC4hT4x=(_#5Cc1cce&S&)`=kZik`I z9)Ww$hWa`e=B2&qR&iSOmpzFJCK+N0-DC67RK7S;`b9S|`H*Uscp%~zelVpaN3$Sn z3hh3-uB9>ji#Rve`^cqHdn3@+>l?`Ml<c&BO58+8j}{N@GQtAcpzyW2s=K63Y}Zfx z)Hzb<F1(G6cT!O;53S|Ga)FGXP%z0hisH&F%d9@Ala4QQ&xq7XH*G>D(M5R7bn|lR zxjot#e4S4w)#m$iLE_4z?oQB}kA_WV^=T-WEKZ|i$ldC-=Mp<J4n%+*diAC}8b2wx zHZ<ttGufY&xxP1(Zp4^eK{^IIxt_R&7^Dv31Ol3AeO$g&L*^+BwlP}ecS}dXDV#SG zQwLk@E;vJhwZbCHDG!yhl1}<+>%>Y43_DQv1D#Tf@Us%{Y!ttDEbFRzJGQho>GRz2 z^pWuoY57c@aqigdqs)2r9Oa{x1<TCD!3CxxzrGMAT9;|fdIaq|B)2fP?uIk{%oWmA zQd23xntR?>JoID3@=w(rQ`fdX+;N?Xu)C}$p=9dCY1Hsm+dqN^=r0S?Uo<QO`oe9u z?f6*^_4Lx6^^Ox>W3XP)`RbiVF-1yGZgB<M?WAtcwCSkdOHD~0TC15TlL^MFehmtD z4H`(W6Gq~^2r-|GLJa7oPx{Bw)jfM(E0@WR_m@sdX?L1ZuDIPU=GBMgN>@mKbT9ax zfOxZU5*0&i<}jE{M5S_I9$Snc1HI>t6yuyvbd-%=92{F6P7aR^!74?+#^QB;BExI@ z95gk4g*T|vysm3%9MQ8B%YA&F>(>+_<w;kP-D!S3*Hk9-$!z#!H{Iwneqn7o->{8# zR$toddNn#H+s`a1Quol!?9;^AvpOh;10k4)SehArmt^~cr96TVqY`;<hVpKF=Fk>h zkkdWVnai49@8_l1QEA?U2e<5IW!<qa5^kq_NfCx${ISR4=zt`lWZgYZkZ84o(3o)w z<f&d6n?K#zHLb1_Gk3XN+q<x$7y2sgtk%MVi_ubJKu;=l>D}Sd9OSs<I3I$UhfayS zMUTkjGg=|E%cY{^Hj2?Cr^Y+6JEJBhU55;_?Pv+BlyIf<-nFe7iH5rcU2I%j*DO=+ zw`RPqjVce%y?8Sd?ZywU`l&aAvcoVtD8*t`uWZ(Yf*|Vf({-GA8Saov_q(`)^;ms1 zjy^S=?E=DOv9X=$o=<KVvc2Zr>(}d<6wOtU+T8asF``bsayyyn=9v-_xzN>+I`lrn zjHo+x!lA&d^Q>SIOyBzW3FrTyboj<Vd^dd1iKPQ*LHHl<T+QbW=QTdk21rHxk)(gv z|5JYpMttA>Z^?-CxAbcN+b;4w+4JQEei1VyP#ni$h5%(qn8fL?<tH|@MSy~1@<vE7 z{MI~r)15`=yX`v$YJV67cxrIs>wbw0jF*G4BMP*I$27?MfQscC8KNY}v;b}C@GW8Z zPS<S6Zv%Yr?-D%;4l0^V49?uv-GE*C=2(jnK(9kG@1dx-*hEMHV3>tKq<TA;#sLFc zjDwaBpau125&lr7*d7olNC6p(zfANP0M9Mo`z18?c#kMWSy_q=z8nu%<?1s}0exyR zSndyf66`E{vNUZ0{>`whS^VJeQUvy4UC+cVI*Yl5eke#lKtkeMX)yXGs~|*}ntNEi zCbIvCU!1EKTor7fNU!F}aN_N9AGsZYBRnW>{WTGf&$#$muVOplCyKStis!rFS${)Z zDD#3oYK!*!WT4@oyPsS>*V%Z}_H5v=6wy!Z>$mi^8^4To+g9=%)c;9>L;Rt0BR9Aj zaFj`pt1E6W^y6{4dDcJQBY<h&x2Oqh@d=7$<lncbN=E|7O+;@!3p@{GFZT+<_|&z4 zzKy@9KfZz1_f*R9mTV{dEUf(#aQ^8{{9s9Y^Ra<07Wi+aU7*jr%M&NDI@NjYrVYl@ zDwdQV?nrYlExz2Vg5oKYiSTSQm8ygCN6&FQOYMsUvL8D43J6nv;iFKNt6cb<atJ~$ zy`}|R>>DkBPfdFuBOmXrkVY&n<*nhRVZF2GF&`S!J6xQ_%~y0TO139&f(=c-6YaF@ zSj8nP5*ZJ{Ve%q}f{}DT?#-?YR#+3qJJL5P#AwuRRtVmlV!ifH;RDUhN?fT}*qxl> z<<YMwxuQ*9A9KqceTCQfKwgsLbY3P3<$XxJ;<sEsGo5m}!n%en;^lrWA}VMDbjMz^ z>lr@z@mY8*+&Rv#N}rjFoEuWWlF7Ln&d{x8Bkf4-4r({R@_pVb_X5*3Lg*f~F#n_l z{Zrb7Y9882>GqJ2nhPJLhu2{YTFh8IGoF=?^5Nzr^I7WH?+1T%EcCaj=B|H|Xn6D5 zLLWIA?}}*hN!*bq<p$dx(>-jy3ObG$jDR?9(Z}QDFI+@;gLaUJM(FV4bE1NtP@z4+ zThxkqlQzLO%-gHl(~QU6&5xyHa8Lv8E-J?M<vFC6g}hHCrF(}&6O`<tzYye=K~=i5 z3o47Lb6Bi6(U{aLGjl!H82H>6ypOQ=icsY+2`r@5xU3LjdGH&b9|SvKi~xFdZEMsW zst6>1m+tO!jI2PD(UoaX+1N+fL#sP763bh>%-Lg?Jf7|?JzmE)A(QekLOR061oK1# ztjd_{!Ef@kl@7bp7Bk<1xpj~V2^Fr20Ttd%Sk=kZ1_z_ORC9!9nH-_D-YZIl)3{o# zwKbl4S3jSmp3u4Kzv%qY{}aytzvCkRq4WQ#FA1d(gk*36ff0t;UP$I^)#7*WQAUG? zo)7j?Ff~T}E2co7A{xG1mnlG-kAt4+FMWSR|0{Zv?#FNC#0^Lg#9Ig%15Mlr3cNm^ z0(XqzU}2z~h=PvE_;(aBFa?rH>01hUyE<syj^5pz7|084cm-oXGi8{*`y(T;k$LMc z;_u6ENMwT!peyq&wj6)xU!~yMF_^RdOY(nx<#~=vzvptaP|03fyl}SuG<@~W<$(D2 zlNkp3CUwaDzz(|EsNmDbFOtAI--<v6k9_li4kvsnD?#daeZ+_Ng9mccw|W%v)~8Zs zyWVbla`~TRstjdw;m~&nDSofP03E0L7oDn~+KYblk<d57dq7M92G1VfWgknxoN57I z|1!$shw3AcLSDffwTc>R4Wy~6U;9P>F%E)0fzW>z2SJ}e=s$~t{{1HY2?zZ>Ei34o zm{qIF6o0sDg{GaYWX$ob6P!COM}c+r7(+aWM~@#&G^^-TdFgC>fK}sUbvwxN?`e{t z$JfM1l$^hMxp6{u)^m$EcLE+_&Rk2X`mC8_Wj}52p3J1r!^?qac=}P@A!Nrate!8u zPLLX#305Jziifj3`J?u$WkgOBdi8rnrQB;6Ihgt2;1jzb-E}dOyV67G>t37t!5mM_ zE-Xq$TUK>UtDg3gDbQVOw*7}N;FC~A>g8$M`-wKMYe&V=aEg%j012iUUAzW&P3<xU z#lfo6IGOg(XCig?qYm@Y13N}|o#&+}6^p1!VQ+I1Mj<GygnbHyE2$gLtD+;ZSd9a+ z?=hZCi**B>I$J6MAuMWMWSFdKs3Y{tXq#JX>P?I5^2+%jLD+oSxta4kB}{zAF)}vg zIx8~eRuK1c(dC;&2%gW!a`3>3=ZaEZvP)N_p*ApENHh&~=M%LHU&=AquX#^ar}-Wm z=SFWrM|C=43M%X=jn*l3^4pa~C8@<OzECbz9Wf90Xh1o$UPO)2_i=<<14?F!!Q&@} zS^eh?IV`sn$$Y1MM2PBNH3Z%7_(wh**k-s{H;oQ3s3}eMBoXpyp9y1V$_5>EmmDRI z&g*WEvc$G$wll|Sx18^Uob01E-ZQLo(6NQWm*fV~M_9W%g8Iyx3RVblrqtOfi~BvD zubUU<56pzOT=76BPL{~^bg_O0RnU*93eE7FC6it|yrNUEFb&TJ#C4vpgZd{>^?5Ax z)xrM+R6)O03(yFu&1dQ{?QiCIqhX6>)}4OmhV#oDM%h7cB+Q!^C^^I<&6d~HA1>$4 zIiTEOgZ(vg5s`TbFT{O!E{kiMu-PzTS=(2A7L8)S)6B8B_m>@HoMSKa3yZ&ZI#tHy zf^hbR*LLl6q?ny+Sf%=KtX1E`mC-CXygw6D-Sq@Z1y6KtbqG)$N<wxsPnY#-2UkMh zzC6|_$}3~(m)*KxT_|;2zEiu5w8#7MY)IDb`zNDa7sS3myt+N(nZq1%32xk7r4vkd zvGPLf#8uDM$;!HX)G3_-#D%6}-K-r&Im>$AVY{lmhESj|k>DB{w;n03r0rf>=97A1 z*PUtI)g!ihJe%dZbiu;4y{|rK!wE`kw};Qq;^Ady2u*mY@ldas8NEz#_FTn@XqlsB z7tb4&JO$x?dX4*-rR9Q;%X)w1(wEHftUZPva;Kmp8DdZUE|NAe$`89jAGWaXP2JgV zcE!G0h-T=8y1Sw3)!S}QX<m6nA&KMG3*R0F406)BB}FzJ$xu_<L(Ew4`jCp!5S|Gl z_g+Qep_`d*eah$?JMM2hw|!ua;*#7SPj=uScBE4xa041AB2--GHeGHKHF`#E8EnzG zN`H`<cK;*@RTAnpX{>zGpZA!Rbay#ldx+Q|wtcY7gDSem_<}~L+gP#d>+}rU&gEoT z{Q2Z{)7*zw7bXs^mSX6#bBwXv3y3s9$TVyJ9IlH0J9AY3U5oz-o{GQbq!<FHQ5<FP z4Uf_!N-*@7#5yPik~Sy?%5QK8n#ngLNX2j7XA&f%n0GTdVDzW{MSk59Ptb2|(hN+` z0K!5FoJYPHm@^n;pO811AfPFT-jhBNNLx`Gm`#4y5+4Feoeg+K$Tt>)<Sk+q6JVl{ z!N6Yd8iOAG4LB!n*;6D0aCbw(bPD>L(iDsUZa2q#P$p9EX9Tnef0>d}K}u@=Atj|c zye`r4^#P{RzD!BQ{}-mDq?Pr*i;(}6k^+SFAocQ5v_uU-oj>5Gx*7<mS*pahnk8nG z`FupWIS=Ol3!(YN;Ji<0ZvF(#ZSNx$_xGjFg;Tj>?MJZdk~WGqK*V?yb}SFq!^5V- zGTgkwWj)~*qV#fU+J>FxiQ#(vtTbb<?!q2>2+taBM8Q4HCJS+$#*(^H^oZOlSEC8Z zXS%zk_JJwofg_jpR&hv>He`-si{xb*wmSULN0nFQ-(Z%2F!v^jmy6ZhV;I->$Csog z(+0bQsGyd7MPnpBpIbtxY{oao;9;}Qy*)H>55F`CHz%l@?bPddUAd{XXtx(ZK^Vic zIr1?*M{a%Q2|F%9cWYMcVU-U{d+OubN;j@iZ@x(Ep*ete*^4)FW4xnUQoK}StuE-? z)!pXNb80=Q^|-w|`ffQco41lKL;I+=NIDBtrwk-0csOJumE31j`gP@Qzpy5YZB-(x zjHt+g)3ZGhX#7s7i6*?2YzF<@GyWeQ{3j_<0GOb!n$d4x5NdtOqH`{eTsVJj=vIkQ z=?TTf)0?~f%R*p&9UX59EIUV&1aFctxrF;^e%+5__^^p%iE+dZdEnE2s)Fr{C1i_> zLabtp=SaM9lR^z#;R}b;z6m1i@Jb`ZaSbKGICJ8!wl0W-Kw#s=>;ry96;`582qHnZ zn3ssx`BW$Kg<fBo+>rBYGLpko8`phTUC;U%ZAny-SA@M`-r<4xl{wx;FQ)aHfT6Kd zi~fSR3Vazi9LNwa^-LOEcYKsG?QI`=K_~D;v6XO0?}sVo4!eiS5>+Fjbx3n6bk>62 zO=hK(WVd_lGGRsatM2e+*r{%_eb`Qw4o^aUlAh^B5nC<Ro9%tqMd`HRzjFaSwEczn zC$%TX(f?=MHQy#*zm^{V!*<xs8H4WK&4>2g@ZSH6@BS|>^y#Pn?jk>WaGItF5{FR+ zFy>(h4C7yR57Q*5(E#TNgXWzK0iC$v`~Uc(v=oEn4Ircg^JQNrmZ*P)5$NQB->y6j zL1Pa^fh-lWxl{PfXcvM4Q<VHGWI#s|&VW9j&CLCV8jk?YL}Uo^RA>q$C88A6rP8<X zdW-;2LBA*HfS4o+id9q!wgXAY1hf+o*;~9a1SKcHXOw|4UgSOUMlyfdB!mGbBl`S3 zv6Q}E5xj(~(N|w4mNMa&CZYHEYsnhlizvQbr?RvfHv3WMe|zs_a|oMrlEFak7Kwdx zT9Cjp@BUoifMS_>ebe^dB3<_R>2MG4wo{^vQ20CR(WkS9z7#y)+`R|?SR2|LvKz0a zYY-nIk>dAl(0gOa(O=9Ho5lu4zJU_Smwo(tF&0tyhzEf~=HT1&?LWaS|GSgAGX&(_ zDZBYcZQlOf-s(A}xEMVB=|ejYIU0I%d_s})ZGi7*2mB|Eb5+t@>kEeD-;dRusuLC( zLl!@+!;=~V{M-;PJeu0<hVReM-dstiMr~-35+z)2ScpZheXyNn?Rlxk^<X@nYYo5T z_{H?6{Y!en?Dgptyzh2_otReC<}Mswp!@BqPBKwknr68$<DG3OIx>dUO3DXpmh=gg zR4QTxiGwYn+HORDn3NjS`!!lGP0T|)fy(|_VNyUCH>m-uC(q93isWL^-Dyy@-~dN$ zS1kKH?NalF1>$mljR|+!)lP0<5P3aU#_P%8kH9}FbI^-@w@`-;rn2pQGF6h6FHdzP zl%y(dybUk2#f0~&ujqA{q~{IV*K~a^?d!`BOJ9SdhEoJnTXv^wF!mP1-rAXGq?vbL zr9QOsW|#-n*yFb5UhaE+kf5u81sPZR<Gpp0OD@EPelSNPqh4#R-&?XRUa03q%rKwM zWW#l2=bewuB#}17jtnM3+VRC6I*E${Yxgn*E#E#TZB6bo+Ebf@deud33m@yJ$tSwo z3GnGEDY$y0$=hl^E`AJo4jvycI*g05W%Y}l7}15$b`Op)QE&B-y^vM&K1ieizr_sc z@XsQ@qIbIPwfpH=&`{u?BkbuN3+F2Cc`xh>zkku%<JGRk+236T^SR-cf<~4{aN?f^ zeQVVU9oy^Dp7v(dKs%#f8f@q8OS`>^WI*m;Ysyw@toKddMh_V~4f5SPF1+fhntkRg ze2heL*~hz>kM0Fz>^5ioTLj}K99t>f(<d`ubH)DPQ)R(w7TTQM-wH>3v>>Uobv3w< zm5#8;TWP^udd8~_r|K`0sj{^Y1_1yt(BDQdxyY(qZr6NEX+0b(H)6hKvJb`manTM) zS0ROI-05h<SYdlJheSPFr_1fm=#Ab7G4-$uds@hL=W$V$)qWGwshDsvq=ZR>Q?kd+ z^UDmQyG(He%As*Ax@Gae#9iQJMR^lWvn=&q+Mc}d^)$UAJS9|n%tz>ycefW0uY<mq z@}OE0Lqg*Cyc;vNv@<6O_j7P1(DKQ;vdoV4gqWH@nXGptB&xFa(4DaHKr3CQD3cp= zn}dr>2}9+QWPG}Y)vF%YblM@M%N5k!6R=LQCsn;IiCx~)!GfW9VoME6;zuvsZ-vj^ zcl0XIQ<e{8p`M=T!+}F$JV@ikI_>CN&E7Yc?q$j5{kbPo4p2xgJ8W7?V>x5$T%4AC zceMN=DaSKW?tJNlmC^K2BTH9yu?O#QRW7EQgemTlSDPt?6pXt0L8Yq+>9+Ym5%;6^ z+<d`)O0e<HAvNVa@@swx905anmTl?USq1%YysXG({;tr0$q=nsHLi5d($vpqyL+XV zN`G{>y?|)yDPl(Spo#iJG9Q?Bh4IR*GeW%Y%S*95CaBftv6G&DnDfuen%$7Bvv{J2 zZ&TcqG&NH)dGP0n#bNR_AGq=w@T7mvu|&S3)nm$_?s_dAjn@j(3vFR7C*+KOBt6H| zu3MmD^gMN0<vcGoo1|0GjA(r6Ddec0r-`MV+Z9q{bmr;{rLBxxDSXdy#6_e2L1pr9 zfia+h_}>Bzf49&-f`;27KS4vBAt)515e#K06d`f+>*P)fr~y(ORPm_n-QtshGT#RA z0F}wRT?nB-<qiw~MgK<83j^qjioqHv{uWWh-;xp0n=l~)sEi>%pLdGB+l*4s)eWN? z_WKPq#NMO`Q3UFgfMywfQ@?~@MTP{qBIeD2K!<PEm=sK#0bT|aERBbt^L^V3RKGs% z0BDiDTcX~g6@OiG<VyfHZq9dTn50qmqNVOk<};sPRRBQN5(Z}SCs+tjA@pB?g#Z;o z{}osWP$BdMER-zR_yrc`%TZw0pJCz0Ht4?s3*RH!{}osWP$BfUU?E6BtzWaqK;LO( zM1Q*bg4h=Z+SYWp`2oEywCcnxWO>63UN?)_amcc22#$LwbzKa4a8V&Dz|~`%w<O*e z9#Rh1ZrIV%cnVj^xxyk<#Mnsb;ZaTum}6elk_Y>_I{TFI*x&h64)JNj?Vd*kCXc1D zy@fyX7wh)zV$8(qi7<}y)$>{RM@3ZA^7z?14E;KB^lL>Yf5=k23hmKy-7-HoyWP2h zW9vp5@cV-X{khTjcY=!hmP9JMmxa?c;?L<0mUa&9LRGRph-|UKMUw5oh*gU#CW;b> zU3uh)mJqB*5|@;C&(&F>UL?O$XYKT$qbuk0eYJyf7G8;SSdOGg^~qT;=W6V0WQRXl zg_my+xLx|F-e<(Qum7=e7X81DxNY=ro9O?-a=#ktzqizn=9)xt8bv9b!7&2eUNGWI zF23|l){7w^XN`oQtzt8^#M_u=Z$rI>)5wRMZnD|jFU|E9EN`|Pq}@@F_fFt{VJJ`{ z%5Y#i!K_aLGUQuezlHG>V7UR|IZzt<ow-IoDfq~DLSgd(^jl~#dNa-dqGA%*ZR#yt zL?U3yCw%vfL~j}$Gy^ez@}4RJv3&|ScQzNmARsCK*X^Ma3Fd&A?*fdfKV19Ob?Ef; zWeeE6S@2);(7tO}fcWh*5AA!w<#vl#(fXF$1MQHCBQqfT3ryGdkynV%=M%79D#$;# z+-7k<0`o1%o{yg$j64CN{ppG_kIihIKgnW16C?ER7RdLQ>W}&N+^fOxjrvJ+3^YwZ zN*y;`YdyZx?A8l<Zxp_7{OS4r&f`J<(ewSC$AkW(=leU42mNl4=&L!Rat&(BRL*WJ zTpngEqs{XU8E|%VPc@T8B%{07jAG^OcE1EuUSC2Jxt#8T#f!2)yl$Mv?aTOfu~>Vc zE-hPbrX_>S^mJN0O0F8XS=xyjnXYZEyG&k1jLWDwz9{3oto@Z#FOr5mWi)edzQ?nV zKzqeY2;q@}Me8AZB^FhPa@XpZerFz!bgr_lT3*$$8~D?DI!Ue>%)4$y(6ekkMI6(I zA(0qJak6JMjn)%+4ko!j<wuNz`>S}y`dxphXj2KRYe(j$Pu&xmNm!{l1;xDM$V16F zR~rh0?0$>lQ=LEbmnhsky_<^hi3vnk5ZEp}E~g`1!EX3c?Ae$L`Yy@LX7*d7za6cZ zg(4=n@tks>h7u*CV@`M|L20xXjP>Pwd>(ITix=J1Vc~Qi+>Yp=B+QX_q@2bs_x@!; za!=oMg~1=FgQI5AFiNrd@g%~fE~W>vEKwy{^P4-QFLlpdswT&p%>`g<^*T+Q<wK|Q zA-<Kl%*t1XkZSZ?pIEjp3Xy+wwlbM%jIT}`-p{yrmZ|drJ+f?y5XFOS&$q@fp*}zR zPSkY;Ubtgv#puEIqalvrBN_PH7KYdJol`g3H0Pd@MNU4Qo|DI46^^?+oC)%Ts*w0d zAIry@NWQ{h4QGb=EW&QhsrRYA8MT$~2#<E6y@6HA5vO<e=b5XzEFi-xWN>SuZ{HPJ z^Dn^|?Jw%%%v|D6;e$68_)Wh>_7Tbdo4<y*>Q4`6JeV0ugzMP4$4-&mG+kT%++Vvp z^Auv9{NpLaA;t<>ElgGv4*I)>|HGjp?hK7MrSm<amBX%DG?@x+vE&6eWViFTxbvRU zwoBd_^Kg3Z?8B8Q3#NeYzO~^y(!CXX0&*Hmxjg;LF7CH?@UXLI8eJ0R{$L)+T*Y-p zwaayX>vVs^KiT0p9^BJYSW*Qm+dgD-DArkVi83s{XQ`T_jPdg2Qg$3|GIn}np3#0X zPFa5ClUP_4RL&>iz_E$#9kYG)@C=Az?s7}C7m`Y!p{WvD?~tLM?sMjJPn(#zHtD3L z{);sAiaOv9Q;ow(+xMd=tfu6w&^}7K*Kv?bM5M>(WMkagHUxHi%*d<U9jfI}<GXb9 z1|tx-SgTDZzp|srk3B3so67^LYo<<wmEv7*N{QLs+vDjHCy(6i&jLMDcu4d5>oD45 zFP{!<>>dO0A>q@7^BX=D8|aWxve(GucscFo`4toA<z5T4_o~=)eRbD!*o+r=xm74; zoAj%wt-0u%q_ugHK$F7(vZ7<dBLkH=W=-Gj^PVB2oUkU?-DlO1+QaNoL7e81t{ks7 zU8uNcsl_<_lo>1;L<^etu_TYedBE(#;S#KB8tZDWX?^8jU!|{#aavi1-}mAXxz)xs z&AW-WXS5|0Cf~k;ki&?k$6u1yY#0*V2rPRuj~;p`cG%4JcB6~-{zZ6geM=v_%a4y% zyhPo2VQ#aA@Gu262Y-PP%SF$^%6N~)-46>@uud5{qfbfFm6XTi-txPD!k+qfVcI_l z@c*-G{Zr`pOPG%#fX;CHdy^D_69j?M#8<eHU;s))(Kr7J_8zcC0CbFD5EO5}MhvLl zY)~)TKq34kZp33i)IuO2yiO3%?}5IdBZ31!7n7j%0(&=#fDQ`e-L_1EwaMT0aBTMz zqM)J!Xr&XtB?Cs)W3VNqz#T>eK&3#1`^_ao(_k)q!-~XPFC%$VMdR;E6d*v10c{NS zo?Ztk-}GOG`86mR-0t6Tqs}++d5Ioe;QcwwU;j^p`CIh;`X1&Z{|@tQ|N6HpKwpRY zuKK4?A9`;rx&8l%3J`1v>Sw4w{8#~!{Nis`fxZa$p+B+49y-S+_^Z5sK4+L!@)u{) zF3)#)WYhgYzGgbAp34JkxC&VrEaa<EytnrmtKYb5y~Z(jePOp<fEcU9(YdOi;+aE4 zCi7>-+Zl+duGt#w13gC$k6SfC=avh(3Ej~Ld44@u?GSzu?n}?ZWxAwrC*RjFe*}_@ zqL)Kd?}8KbJA#p4!~HYer$j<Ic{m*JJW_d46vX{>fr#pNbH%@g``;L5E&f1Myms6@ zd&E8k(Cc9j+R2<x*F-*Z!#F0)bBBavEI$>~SiAAMoP>S01lZNgfk5Py<_!Tu)mPrQ zMvy}{!e|;wMU-JUGwW(A21RP_tC71c7T6n(fUZ+;9kd%+65Ng}nr?}me^RRdpnP?T zyaj|CKm6kT_}eFi_5b+8CVyq`_|Gixovq{RBYq~zMktCTNrYl3499T>C=6{z8OC6Q zL>L02zSOMCfJxng;uHrVH?Ys|Oe|oKeGAV4(V;hk>|6HjYt1?s3~`X}3C-wj`9cIt zc_8n;IOKhWgaD~r8hIyOvA4$E7WgB-Gs`hZ+HTj)(swEt266pnsKErv<|96gI}EHm zmVD#2MH!Gyh~K%0?N+v9@He*yAQpS81Bb~wIgtIG!u&6yz^0vs6pI_{jQh1?Mtj@; z6U(dt!g^N_^9_A}gzNlbTt2B;J+yA4e_I*u&3{#17jb3nPwr~I`XH5sBI(!%n@#)o zPUHK|Z~MMkS1^0=DGJQaA8fPM0{yhH<P5`MXC?ne^|d5QBs0bJytv^x`Ob(92(fjC zbB?9xZjT^-vW^{odW3D~=RS7%b>F|s<IrE~5ow-6DyKv6Y)8rHsnaPw@+TR#t#Ql; zTZNYC5uFaCFo~P-Sez=t_Wfa8<x#y2OB8Bw9KQC8YkIbIqr@SRkwHefY;xVs=O(0r zf_!pvqZhH(^xUV}78mA}%7*&lG%ND7Mu$-%b#6!Rc0b4+kI7fj%tq(%lx;(`7Xb>7 zF>_J}X>20D((agHMbdN99!4HE%CjLz@?K8*ZkIPlYqNUSBH330)*|Fx%?=N3hV=H? zJ~fky{8Qm5FGFNwe2<2&1eJEUc{fgnJKUe5we~uPLoue*58BFXUjLG*XT_Nzgf~bA zfyvihk6NouFP`<NPBORpsk3WI+GFkVcw~lZDR$u+zRc7aH6g@kbB8M2@d8y;l#b7` zxJAj@4LNeJE-zez(eBK6#Z!9u4L%iyZ(Eh+*CtsmZgFm4!aU~>g`Te{<XqzUsfZX6 zMx$!oki8k)q>{mqq_Jz<Iz&f{cP}n0nHXbclR($F*ICZY@7f*J?YEC|KD~JTcnk9S zK3Z2Y*#4VOEV7T=@Swt>cuh74a_^efOWN`-a~7YXxNz38Hs%7nh0flBn*Q^?3(q%H zHBNB0&kRl>ZZW+&r_F(#El*eatIHg9UTmfMY=zgEAWqqNEsg#P4Z*_OmwFPqIJij8 z5=7y?)Sj`ptBw(sPneucuj^<(u9jEiY!ItQq6$)bi*?)Q8mEwvXIDu!=!5ur{!||S zn*a4r{dv$wDf}nphbdyuWwo4&ZpsQ|S<lO!+rQ+*?Sx+mWSt564-WpVc2WMiJjkQM z)V_X%+L0AIP3nnywQff$9zyLziV2Q1=j+{{x|5pFY&Y1^5TD~+kj;{FMJ~>6j<G@v z<OifKIfJFr%hp1;_9-^S$spwdK}3SfNFG*`@-a;0Uc=!uG^@88t^C%dnP{yEVGJY! z5yU*Y`XU^H#x#!RsHQ@xWW$wPkEp)^r^8SmRi2o`<4}A1mvA|n3H@Y5L9`qCp_kCp zyRvcv^Hbp`WhgFQf_V0AIif^!rj{<|q*o)Q42~=9?vjkVd$sucp!4tN{jGmKGbk2> ze%=whJz;z`pS4|!l<B&+;;TfnW^o;I0zVo?y(8&E`{D-79o=#{7<eUyj?%ACrzHKd z1*;jZtICtO%CCI5%df|!!B{TQsK;(%_l1Y;^FtIK7XA{SCMI5ETH+A6+`w{c1{8N> zCa!5vEblZ&Y7`P1y{pn!_ofyoLQ!0EzGCO~>Ag^+Nu`u-)!mA?>hqk9P|q@ko$cMp zWlIizokV>n*N-MR4^H4OuWHptzwk{`XT1|)IH??o*W=MQ+Guz%%kBwjnkS}*T$pww zM<jigsgKQ2bFdbs>#2IGx)d@CT|P}yi>oI`FvLroT5J1ih<VmhHbhsna`tz+?j0Qx zz8bZuAVHN73FCX`W%tm8Ot<~s>_l6A9gDe%J^#kGC{oqhET3_Rxb;hP=R5kUceYE6 zNUmS_CKWh;(0Y#j`*6%u9asG0tUBo-ef`A8FY^E$ng8o^--fR~4wky9O+JEIu}!*R zOp{+A+JD=kpRnyO7W@&u;W$j=7*3EV0%J6R(+Exijt+R+MBo^S5GX->SwIgNph>cY z&*)oin0e!$j0XLbBm;05^Hw$@X#n$3>`Mrj!T_z&_?x5y2XSqbf?#(8Y|%Te1+^U# zl;Sre2nygC2#B{`*zX`5=&gi7P>jT&6BETj^?U<wpbQVc!|D{2e3A%^@sb&+-5~GU z4+>OM0H6fq9Rv`Nj4;65u|?Sg0VvrJ=3jL3myvY{3h3$X6T(@l)1QR{6$*z3Ye)3Z z6);KuN!)~cfJhYjAruuH;olXQ4G$?kT)Tnys8d%gwut5v>ILq$9k80&4TC^YV}Di~ zr0wTt+#c)ATy_S3{RB_h=Lz2zbhvNGZ2qp0qF66Zu)gu59)XB}P|c=mZCKR);72V# zw|U#PV`#|myYK>iue?-8^@oJOL7bC|;~#4W^*0-#&MNzf3+vOi-LoA|jxc|M0{Jtx z_orYBfMe9J3@4wp{8P|{`8?tKf<Njad@G<Q0>Hb5a-Bu?s(j05@T_%}4!9_?yeeFC zR&>qUnvLrzz7;fjlF1Qo3n=yOrF2gQpLZiK+us?ss^)ntTKaL<@B=3#Iy<aNm8jbE zDlS2(oD({ETFqV4)eC-xdepSwvh~Jmf?t;6EFf%jbmLPvMlot1kG)D-$6d&rSK00m zYxc^Y=MABE%xYbKmn{D&|Lv%;H<%}(?YZ21WQQW9TxhtyU{8KOyLOnb9LLK1aq+m1 zh1p+nJcbam>>OC?tc^*(#j!p_P<s1fUq)%1lJq)9SLUL5y=}VNdhtTO^6hi2#hh_& z5bbd0aB-*Y9P?4JrO2YIwM8R&xo@h9e{^Lk9hfB2>ZP>1eZgdTSBA2}ro7n(?mj*g zRLW4J%AL+EqkC(^{QcnAbw13R4d%w=uFLE6k8ctx>F_M#bo@it`ClXAzkSyCF!<kR z{2cm{1Wh3n!E7%i0dFtJW=t81plAd}NsyI<nJ?pC8U<!2%|P&*puot0^kW99##?B~ zP@w+@!GX!5(0|cim$QK~Is^CyQWC7R#n7Ae#bb~o#EJKL(R+Rk1{N`S3sHd>8T(gC z|1SOw-?T(;rQFRtA{ZEW11eS@W%n55Dz_MUvzgd?erz+`TTl&>p()6w0!oD#*xuyL z%?WhcBT#N<-lRy>U#de%XAsN5hwsKSs?vV(9*V$XqrvdnWUny(C#vfWeF~iNl{(bF z4du-UY?OHh=u)fS)mA{(4Kxn<t12!AWUc?E0NM<tZX@6pKf+Y6{C98pu~c6_$G#ui zpdVsi<v(*b(2uwCS9kN(^gs0L`2V-*e^j&%x-yx!gcvDI-+8AY^?R75yA0)b7x=|> z+QK|T1IqT#4yBg6-lvxiU-X^xM8~W(ZydVp;`0TYb_9Jt^-u1gUGC}KyFYRDmFc}M z$5-Zgftm|7^EEYuhX`KkUJ*RlGIksEw$1Xz-9~4((tIFf?b+%z$56V+bxsbE<Hp|M zuPFtsUOBt5&Zk{*n5f}&w%hZ7?`DqTQzMi4Io`nDJ$OW1Wj>PIPP_FIyP|U%I^N*` zpP=j&)pxes)l*J~n(b1ZK^FYz*Lm~8mAj$0mvd`Qt=~AOx?;MaL@#saoMwGtXZ8_8 z&n#5N)gK4$W@WgWy9VmOFQGT6#c4wN^>CV1bMEkV`U{WyirIy{sA63k9}dN-!=a!X z=<B}Xc9)V#kp<hep|YFSY_tfX_EY%jL{B7FY;w6CCLGrv@kJ`?^8l0Uz4FE$TDhh& zHb{MVO0|7t`Sm`SPUPNO>?MpMM-i|&^ysTBF;vU5-srQvUydi!+3^Ufn<iw(3_6?0 z|J&SqEjw-{QKIkoihjH|aAyc_I$|DR2yaMu@(q^oAYlme^%tP3s;i_@m()EGGtw!Q z4hU@QgF|Mn%v`yWQBSbLlUxfsgE8D*1w&&?A1^4;(Bx%|vdWfiyeA2S*Qm3oyKbPR zL2~o=5FUDl{N-&n(ZFI|gD#iALp)5O@zl1iO!r_<&FhhmuV$$uuAZ)te@=QSIzOnZ z$$|jy^@dk&Rz3Up3cW|uo#KT**`8%gipKkK)<bjD>!kIDPo2Ob40pRYz1+92o3T6u zpuYYfW&Ov7{9pJ-;H!hgRjOCobEra(Hn(Z}UTkkluAJDxewIx8t)ZVUe1MxUdQ@&{ z0D?)&3|qUtAL|>n%SV@81G~=D*BLg0Rhn+7TdFZf3%L|g-5lM|s^h^xf){IMG<2e_ zYG|5I{aQU4pWQGhp<JT4+C}!Z=`^drlrsh*44IX~sgrwV@9$tH?m%$4WpRMMNpyH; zQ-{FMWagG&g5kvvOS8tH3gfk$1~Ei<YQjBuTQ4j@a=Nk3{dBj0$0{^Seg-KDm&oVb zNox?Eh^46$2<GAKEptn8x{Jgs-YEaMI**(Ftf436w<=^N910}Vh@bq5sLE`N%DlE( z@_Ex>yik(NWHpF<(a~clL^u`i(T+E$HYDuqJ`p~Y1_Zyyewcz>FGT~vdCad1hg6!F zVh?Dcq?>hrvzNikrKB$1bBh?V_rlmx*v)=_b>(Msx<3FukrxOtZ!&I#%<eHp^JEkQ zs%&^WA$Q_sOhRX)f+Fy@&Mcv1d%iA88Zxne?#JM*1EB5tkMz6*gji;IShei^RWAjd zv}(=aSYk}KcV~lOteh_|GYUc7wy)w`XYI6c$+`jpfiTvE?VdN#O)?ttr=nxpS?5yq zY0uLmzmCO}g1b@INb+>ISh*euwT8NA2nI5s0sBf*7jxxBj^&-vcc%Ud4Ho4aIi=&x z6&I>4#x7X0s&#R3`PVwQ5YyXJaeHh=G7rERz1)<Obd4t*Hdife#JurOl6Zp>PtsmB zCkXJfdi-@F;lBV4@*e@GUtRS_;Dr1PI1vzzlLQGJ^LR0gq*02XaTJCTeE$ajX-6N1 z9o5nuQ5@Pz*fFmTjSjKM9X^HWfqstRl*AXV9Toi)IPHMz$mJ79UjKkRA4c8|zV?G? zb|_KB<WYz?DiWXGd6YVW(=7fc_Gk6nBmbWqRKVk=9~CNsJYX5}DKVq?5#>T3T`Da7 zOtYho@t-?5JBAD6N3Z_T`X7Fp3qLpBL(Uzs?V#%rHHZE);8edheB}jQ=}w`bt<m;> z1~|$8R{^J=%O?E^aN<q$jWi&*4FbQrp7|a|LW_z{kkFKvcwz5s&Qw*X_6E53b8NF{ z&Tnkgxw+kLtuTUE*PACTX&&yBfFt9tcZs?d()|R+ZT8TF>5Vh?$wAczAeQ!x;OmZ5 z+&V?W9B&#t--G(%wt;=RM-#0{ov=%>q9_XuxH@2v&~~Fz(I?iY*$D{V%%pP!ce=c& zk&RW`^yP-~qmU-%wZHO|(L<G%*Y`^jJ1W{`%{^_B6q`#@hFCKJ`jo7!U{bs+RV75R zb5`BviVHBT%Pd@M5}~(2O(<2C!-l!Ryf$IFBD|$>1fpv&0hh^tWVDs@u%KOdP)8<V zPK=TZRSBQ3+p|lR(*(Oz@`$FeBK4|!%+CEqJM$<voecwxdhtN?!g`35sKOmS6NFSw zvF={0YjVr=w~XTHwz+ck$kcJ`LvlP1@vy~?BK8EV0@Q8m68<&dOIO4gZ|j%1z7BC= zZiC(5Z__du2upO2aq|=pY-~Ht5uufr`#Skq_bPz}w|u#$Up9)dawM1fc&eJp8hvj} z=qvY-l((2FsZm|PXjNZOzX+D;k#`VDN7x%Ipmo$xBvEgwr+STtI`j-rfw#w6Mp_|C zq||5E6~ugyHXFwv>}TQ>=*bm51DjfRf`Dq{UXPee#Bs6W8NS43TaWoI7lUTSyGl!Z zM}@<Q;^OnI%TBJRio)drxe8;hIc-+JIR9?~PSfe6mW7!)c&j3y(mh|Urz~-bT>lMl z((X@yQt#;LNlqLlj#$h+ms15xF2}vV+j%rj8ofY;ods~_FtVV-G=T{-<Aj-+ITM=D zgqfM)4>L2vgn7cu%*@Qpocu{HTXp-kc5myRU6x!f`*X``$!<$(r3{5ZPJK5>q|i7m zAIw<k&4rm<jok&g;!P|S9rW)x#j)&YQBWR=b3ltbO6KPsggss@xZ<FuaQn71hMLW< z6(=Uv6H+I!1A;q2ipg{c`B~x10a`pa;7(0hm?=hAM9Ye;*6G>SYTeOlM0O5k|5twl zBIwHs{DHMyipI_!!GCwkS(`shjx1g^A2SMZ*{$};hopq5$;98DB-r@m%Ckp)21ZSX zO@HJH!JEP}8s8pQ@Zy0l!l3s3#(uU;Is`4EkqzoV1kil5)Wm`l$R5FXw#wo@hHzd* zjqpt!q9_!XPNe2$(BqLf(_bok0muEXqSKLwL(EM7#ryAEOUsSx&JBIds*9dr0Z6_W zEnoD}MMrhW+ne(el&*9owG9W_*cT&s8i<2S+k*m44({;b$H)ze^#eO$ybP|4NRtwf z6080fo7<|q+C`cv8)shGVI_1~{<w%8C{|W_10`WJH<)~i+X3Ra$w=;GJ#4=tkj%7i zTM5+#md`KahW@#Yv(^sMs!SEh7Ae1Y$y8|yzOnIldupVlx}aEydL>Pje)lyvBa7CC zeHHhV%kEo2gGUmm-R~Ypcq-#_<FtSTRvwljZQR#>zarff6B{41ZJO59V@sIprHkq2 zzu}AiW@VL~#-Gnd(S$E6(~5d^7!&@6<cs?HKlS1V8fVWkV%ATzRYero3%#&lVmNZ* z+f?O`yGT?#0+GS%<KYp(<zh$@enA=FOr`it{=j)IYoG)e^o#o-Y!JT@!ntIo$Uf5v zSr~u*((#nw)-h?a6yYuu&!$v9_!6FoTqvOEIR}LDIsXn@F(eo4F%8!%6o-s3c+)i7 zT@sHqGQcDR|0nIcq<!%H%#D3P-nOBR77TvLiJ;ZYjHN`cM6W=2Oxp*w_7vg1Z`(7e zo$#V*yQZvtp&Nq`{K$()tIn%;>xXSX5qKd808#l~*S~1bbGr*vZpg;B3o8Ad>qi>R zTWA+Ac$zVx&1bU?wxACdWZ!QVQx<Y>>-o#W0vhzA4-J)2ZdnyGlw`a`bO){<4S&UR z(|f8TTDPVeTFoIOonpquokzmwPS8WcsI<U5G1^Pqx)L$SXvC>63W@D{9xE;Dx<4#5 zs2%tXMb(*Mz^~hb^?qyWjEMkFtI>zLs-wVlaV9iI5yPTIihvZ_xpObhmru?akv?}_ zZ|_rsj?j}6ac4d-%8*9uL8T(Df^5QJzfiBtnoS_cD|_W^z#%>6Ta$y>?jG-k;=@yi zx->{*EJZO-43Tr`ym{g_RwvfO(de|0n>GJzZAdS`m{<M2e+=3fb4@T0ws^iJmStF) zCb69nGcDqMK^n(=BuuOR$6N6(=zZRc7$$1>d*d2)YPUWPDHTrMNWl2F1OY+?pW`fV zR%I6+LBXM+PezfQII-dr5n{*)M8&#|b<wsU5+94sM|C9m=yK%SX;~g9)?SHu$f2Af zre_vhA}*^P8^zsY7V}#U<$F_U`nJ+A0XSx8XF8sJfGci<H#{vQ{-IM-DzXRJ$WsZ5 zUySCy4b@WsmdAZ4{v1)50;am#IT2!v{Qfg3X8Ta%Om%tG?-z-?hS3Bb`GJp4E^ZFC z#uov-&Z<wfwCc0!@sv99_?6(>=VKaF7K5CHLdCi(Dz3Nqu$boO$F0o?k8bY)%9|gm z)FB9A))~IM>JjBmq`LN@8uxoadu8a2DM#Oj-P+hSo@lc`25sH<bXqf1>+;bsLtfEU zkM-@#{KUMqW-lJL(it-BBTE$M>kZoJ2^=(b#<n}C4$>0=thyIAozz7}x>dP?AjMiN zW!p=E39Zb>x7c9sR7kWf_YQPtM&SLIilO3tf2Yq6yEz(h#D`iWX!=efYd}Qqscpx} z;-BOZb99#cPlGq2s8L~#xMrJOL?GZ@>6zgf*2J>1$iOn1?R5Qg^#H}*JqM}PR#3<< z6WytwW7ZKdbgx-6uL~`@atnl0Z#@RYSW>eP9i()L{d!&;8jJ{roc;-Dh(csSxs1Xe zPPwoTif@zr!;o*47pxzYet216PLDr|f+Ps2fQi@4r$-nO+|$cG7{DHJp5_%MOj-P7 z<4@aXE%0s$9BSY_%em`vB^k!muR{e|jQ5?U-ke!tDLhP(YXPR)VXljEJZ_bKzZOI= z$j7{DpJz0l$<-@-@{r2HlD^do@pxgEz=su$XFt8S9$nW8&5!}jFk1{7$!^F}UGfv+ z+^y!Aw}tk2z_1GboE7%#QyTT=k11VfdHjv^+M~UxEho6@h-RjzY6Qrm*H|kf@@<-_ zp4I)WR=8)|_+1Id6U;~IH{5|84yha4AtwS&U&3@5n!fo;20H7U&EWNj^j8ik@ejNc ztB0f~ThFQ<0$RxJZ*oGjU4I=u<=>9tH$8}io0@Lz))0BrBpqi{D_S_JEwa9;wzm8+ zR<h+cg0{C`Dwc+={5u*3_ovyzGP8=#EZ3q)f`e3yy*<+}v?3m<ova+pBR7cr0Y*tW zOTK9I!!HOP&i`*uj3&>+FMZKsXG;(Tj~13C_ry&sPc&KTBDBDw_TQ;%CJ(Mpc)<;g z)K!`S@P}n|dY2lmMuy!?Vxsp(pgK=(5eH+8BVjzn74@I@F7oXo?F01ToXnMm4Yt@x z^=t20+<`9+huz{mEm9L)k1tr;@;YqFoSzsw#?tjFew0aHjn_GWo*2qmhtKL48^Y8| zHtg7IP)W+*FqTNltldiVel?(qTJ{G$4dXy|R9SCtGgh}-qHxw6Sw!Wd!Rsm{r5FW_ z=8pI5#aSV|3Gx=GKQ7>IW-5x8a-#3Gs^HwTj9c1Qiq~-0$V}x0{W{nC=#MHLR?a%W zxu~m_Zy9C$7*gY}P}1uvuSS1(@Wz&^S`(mPrewCh+2XO3O~i;pp(Q_16N#{NNC=bu zkTD=E!Z`Mlx@OZ0v<g-IM*B5WDR)akw)?xEF4(0M89!86Gd8c)Tzm*MOXe<Y`GsfF zR@|)*>o09eh@Zm)f{p7S6nCf@N6Wv_=9qgIPtr^}eqZjgGziyy4GxkEJZ;;i!5?5D z5@537v%P?145LvIh4rB~Gnbk(jjErolUrrVlcIK86t+0f*>l*6iF@nR0)Jk}T_JQP zEpRNgWt_Y#K5|Y5w|ew_qZX8P82xB3Ot8Ofgi0A;)hx=-8gA`_PN;D|&dhE_nV$Ax z9bEdT5=RC~ErS03y-26i##udt8LW-R(R$Cq#h-chrbKi99(7m~5!ol|_qGSMJwK|B za?4BZx0pwWe=D|L$ml6Lu;O6Zao=O`DSGnLs#Ws9?zx~tw2rEP4Wo#u9Q1hs$4r_u z3Z4lFBDUQpIu_k=Bj)9>m9T~|bx+XbW7BR&8q031#{i2}3s;%zS+H~Ym>YB)H$}Wo zK}1}$=|X#5BU)X-n}A@Jc_CzjI^=CwK}5x{!rYp6e1QQz(iCG(V29nuq*_n4-Grd1 zXn-;_*SpnvL+mN$jjtI6YY^Fv6L_hU*lU>jGUB0Z(KdndQv<dFZDG?Ei#As3?=A5C zRIWK!Yy$|Q%_qAduB!uqy+1nA(V2>GxGyb)SGwSfVHqCbTj$o-e@hQlKC2y{P`mH( z=I>miW=suOKMO_c?x~uZ7$dXlI_+Ki(amRPbl{0jR}I~LR^^2YQ<VP_g*JAttwRP% zpn$Y7i!b-}YvoApHqR<~Lf&1&LpU;Xa3?EkZk?8a8N>r=mOEhV^(XqT7U#T6b5u-f zRPQy`)F=6=6y}4NhBEva=oX0k;q<13P=YsugMRd8^j(|I7FA0;%G^=rv7p6TsvXue zNU8J<JLcmr<)|M`!?2s~&&<P5WNx<BQ{aRHNr6<gi{9q4H4S~qNIh<kG|wm)5orHQ z-#IM|h>HGLRo&Vv5NO+l?uS5Tgdiph+k+6lAja>Ic!rR>^4qe(xPHeC4b07n@$*CK zCC|p6Q3R&VIg~h^H<R)(OBs12jz-^fjwrUt#O06_edlZSB{^ofM&LR19S-SB`vZ-C zk2UX)hh1=<pfSqNC%h7ZAM}xdY<EogqY>KSxwtO`IF3^!AhP)wM6}yi^(Q(uE|6c* z3^;|~Qn+vLfPv2^yi7?SG`F{n+(sgCV~h0i{oHox5l{1SYy-5aJ&ilVxeap=QP3wi z^+SE_ttnKB>v==>djgr)_XLoFcvXqEp=QSlz+K7_hsUAq%t8w1RF-Q&{X5nXAAjHS zhqm<<!v)l{4^P+X#1^p_UyJ2>mZ@_H`uWGcosL<~+F$6oFcGKi0>j98q@b;fLrBkW z0nAqLK$Mi$?>p*f6vt$Zri<#H4sch*i(8Y9b5-mai2mUM#*$-kV=VE;7uMi?V(mny zB<i-;&JvtdLN_V(6FbqnlPQ+62WtE9HLSfI2`PHhG>saG&^!El+nnew3f-dYV2LL) zVT6p*v3#Rk%BQc^1RH_9MEl*3B{(&j^yczDmvApyY6a#k7hRwc!U=F#1zN#%@U*m7 zNmoHTBORm9tTeO!m4Ax0I5(_tLP*<Osb??%=(1~yF)EO36Py_up#9T6V=eXcxuW*X z9Y21^@ePfi-prNyJldhlav)BuTX{(S%<pZOOP-g)dcm%Ce9-{QzGT_!FJy<48Kp7d z0&Rc`f<Khw3ds87Aa`k^b;&rd$<(gcqEqOcYEj6>1ryK+dg{aw`zOXrx0BlD$>X;~ zSdbG_G7GNPX)+G4F=f^|q;V9%2rmZ;b{f|es4JyF&N-|d#YYG9gi=iVX|87i?s%n~ zb(d)cu@_>HbD?_Vufe)9?ws=?=YmFq4%)JYQCB8)h+xPY8=YO#eshddrYA8t`<1%j z5=ULFrr4<;?v6Io8wL??$1FV#-ViheuCpQtQEMRGdhfr?#f+~o%dC$-e87xH$xo-f zR|oOhlX+QldpbopS~x}!<!k#LIvljpXnPuHkc<QtAAN|xNPCjHpQys73~-aKV>^^f z^X{okw7VAGd_SFB)@=()ra>$$b|5}qS+DbEB16v|uS&y2s5%p@ywu`J>#OmRhLt5x zmHkjlCi}ocm?=O_nD#UUp9?HZ`2`H`l<tb|Z`bG=^EqhH8Il_>HGzryRcJR$%gU9` zt6(WRlf?sxsgn2@Z*Xo_UIIt&Br`Px9(*X!<SH_u1N!?vVH;mCde#-UR7kj;ysm1_ z*e06VRJ0R6W~`VI`}?o`-+##`Ip#x~)mQ-?4CrVzjPAS~P<G67tjLHBd(alMNlWQC zSc7^@p$@=4-y#0~xQ4@iU_&?;i}zLK`Z9a(oZ^3$6>v$Nq`{D#?Ld~D48W;74rmq8 zS77k!FY%#(iWdYXeD8?VaN>rhlCXE#pv3&Mw?wI)f5WoBm244kt+L2z`3lAznxce@ z$-J|vqz)E(Y;gMMtNmtmi@=6m(WCdcd`nWHgMUcTw{g0mB?f{G=Pe<EBiu2?E@nFw z^n5S3{SII4R}L{&=#VyXL5|qi-eNX^%(LSG%5)r*aS@w#7?%Jue7y7)4o}1Ro#KiG z2AURwuC)|9;?;r`i+lM5rY*R-T)3Q~9W{A8whQBy+~3cs_P3qM9A-04f|3}{vkeB3 z&EQdEnJHo%Lx<u9_5gjngJXlIKrI}5ZIl<A9@iu|mr}Q&uCzI0cj5h200m?mqER6Z zh9|t~Jat&(6K$zQA(G&$jpG?k&KucO90p=aS7ZTyFKP@saPidYgMptRy#Y63=eXU^ zMg1;DApjmuk!R3vdh1E^)0D<bOueh?HAKh*LarAJN*N7yhbOw1(SK7P9exKZ{F3pT zpJb*lK=V0(-wh%tdL31mz?h4dyUdWs1a@vu56wqq_{(cDjMN7&QW6kVIy#*=5<m9@ z%k^yp@&e|Yf6OZ}n0LJ7$;_GT&XD(GwV@u|>rqL#G{5!yv0rNZ@vwi;GLr(wKnw(@ zoX;)rre<0Z4=AfeoKJd%J_qg8+Xs#`OK79|Y<|6|_FND3p72}<7JN+D_b|DYI7cgf zl|!;fzp2W>eLX2&qs(6{P_G40nFr|tDx&n29UK6qm_CajdRl&AzA_TzEwXG*)=awW zrZD}Tv<<uR_mlmA$1dd008$RsV;{U!)!i&5&OAi;tK+gA*}`GzYB~6Bp(r1{?;1ks z+@|?Gy&1Mnzf%SO+OXb;k12|sBEm>AJ^kvGXLvgIvl-A!mJQoA3Cm>*ZIwU>1)wtA zbg^pMYXKj%ZW41!1$j=^dZX6y+kSDC+vv)ahxU@FV;1eK8feuBJv_bJIHeAk;5&}c zTU8v-NW9WF^DVJ-w-&O=`q@_ujf$n_RPTbs6FJd1+th7+fY@VKccBC0YBBrU9cLsI zy{u^kobC!Eu}9ZW`_}{ArI#jjvp@dY0+Bc$9NS&G*<foa)ZWhp17_6(PgD8<O0{Fo z{dS#hEu(AixUNY&nOtJmG?28%!%Dx(>D^-bW3J)klon;k<4QNF2_@-inifXO4p2w= z8yiA~7V6y-?noe6!W5KUeT|!r#gHv6v$FJ`fbhhj_mh^ypPUn@;4ik)4vfyeVMNG6 z5p9(g6m<1nCo3Y8poqm=3Iq^ZS4vh?xAO%D6#R9--To4)P41Fi$fw8IBXl<HbH$fk zXAG#%AZ(5YjT`J(9g@_f<Rk35A5_R%F1ap5n#>Hu<P+lShUW__6X;^tdtA4x%a7@$ zYC5j@Mk{C?*1qe72SAm9W9_N^h**d9D2x-avz37$iccRB`?N$bPGj4Vx`P#~jQq>0 zINXQa?H*T<DxRL~JJD0DE)Iv{d7*apjTw0latjn^ws?3FW9mf=f~361?dSgDY+A=B zX(i5PFf@RLQCC<maxfkMZdSTLS0-4^iX=rV&{B$si0EciI|dRu^e;(X-&ot`ww0g* z1>(Nr2%T)({PIO%_6*6)i(On34CKOZUoB;13rU6S;)K3v$=ZV*GQ}P>vfvR~A_C&{ zhvNFO9HqaV3O1l%T9TXn^01+*!F8!jo5t5<=;po;fLNB#k(TbJgsG)1d6TO8Nu)aW zj;yCPUaagF$w`NGqRSj%zm17a0xqX8qlufv4p0QSN5J06BSSgMhSrPsH{RoX4Jwa} z#+p6bLaI|Qh85|f?hp)SZ=HF3y9y(W`L|%|fJNXKh1rDnLM*_Wkg!OW^>J?y=c4U2 zTFj=20EYZq_{(KSPP;gsj<;zV|7rNANu0v@H=t})$71+A*Nw5aHyS6T>k@5rM}Iz+ zGQmWZyzs}3i?v1_j|zCGnJoP~mhK-%*L2#UI{K8$Nl{ru)2Gv-W6QL=M*Q=c3stb3 zq>vD!*!v3-226>1QNi0^umNlL+~G4aB<UnV^zk|qF|Z_B_{K2h-hq1oGMV+oO_s&f zv!l#Y5pg(32gJxA{o&kZunf0iGc4^xLyQfDlhmDLA|?ATOpT)y6%@lHLRr+cHPBk{ zeiJ<7kRk0+8o4I1SUJ?~_1%LVm9E*<inO()jJldgdAj-%ysBofv)kCieIqd6MQA$? zY+R6w)TBV2B&|Zj(E|EAiZ^&;)b@1v=O4XYbnaWEsHR%|_@BgY|I9A_7A#!K|LT|5 z(6KhB+0(sOtD?4U{@2*OOE<QZ{ZPBmf^q8dTa9NnH|ZRTNB@V}8pKofwOn{nNCWit z!KJr?Ez!3<|Lnqy1U9(-@5E<ps&BMcGq1l45vmVY8O-b4r<#GH2O-r|=&Gwb))kaa zbFgTPhhN_;hskS`BTdeoX|V+eW7JeKsKLghe-4z<vVy)_Ozi#$y%`azM_n2)v)b%q zgLa8D4*~7$YT%Hf-g^{!er2{y%I$+gty!}Z9ta0?=9%Ei*~M^^{AunD9n8#$+SO$7 z{WVTNIYl66b~qq8%hFiedkgcZFdI(`4;n$wzjm@+>3E^t4OS}na5!(S+iOuO1mJr~ zVegtdM2<-wRLO~NNBZ0;u-|lXexgG37oR~hOvhuqA5+Ct{lNEm-}<|*#`u;{=+j+C zC7;hI_8mejkFld~2OnKzS)mYc@=P>CD7U*GR~3;TV2%+F-ID!rd?wl-$05s~S$%zE z_*`;L)QYckLYNM~BE)Wa&aV^Sg-(YT=zFhK5N4P}<ZFH>r+%kI|Ah7Bo1{RjafRVa zwIufbd4vf1XP+o-``J(7$@4rTMu5t*%lk1+ydwwRoAIi%w<q!Kc=ke&vnaZHpOir~ zwhQbpP@=a|y9-QRb;|$rQ5|Ya)O-Kvr2Fy7@EPrhM<3s2W}yuUpm?Ouw#K!@T?`=C z?{~!vzB1_Cv|5C`?3@up;1iX+ZHIpCTZwYUQkSTE;izx(#5>ac_CfSS3i^skW_dd< z5pNA$`B~O(BS0`W@a!ts$PT(Odvur5<8$<)A+afucf6A=A=b2^@u8H&#~^b7p@S|x z8m&<I8oaL@NNc+tJ@4FJ`-(V^boJ|GkvC#1eLM<4_l)kjHcpkZXAF2gSFC~b(X8$8 zk#0OMHuB_SL1&E%BrMxUjn*6basn-B$|y&9(+Y}hpqF=urAgDx$j_S$=h4~V>6+lF z(kbBGch*#}CA8Qfpn9$C>5;U&;Vdafv=z&Xn#+x>dEK_6m2~ur&n-@!b1|+-8eT{F zbiSOUVF~1}nAU9|Wv-ddw06;6d5TmbI2AKC_VBGYGh|rwG9B2-Bj<>_d2)cmWJxW} zf0gBSUC5}4I0WXF!(cq^;yt)Q(Ezw@L5!4#l+YUr(U5R6AQqLXx0psm&Tf0akzw#! z;Ws)-q&QIX2dw<ees10iR&#-p@x%pX$>Wk`U+xDPqx&_m#&yM5Fv}Y}XLs_ESj~8u zsKzynZ!;%auYf|G{N~-Vb&Yvlr-B8eB>q8W5-Fao?6TQ`2ANGyTSmV@c)#llQ1b)2 zQ(Fz$348u&MVM4{1EtSP3%gzu-YlF82fyu9n9_Qc4>IthcdeC*=TFu7;XG0I=#b*U zE0{3msKx#p|BquSxFd0n@DW{P%iCq6AiS&YJ~EoT!SO=q11<wXWQwhL&HVRO!<4&z zUES)tupbxXi(wGoqcX<F8zk9*q-Xhc-VGJBdW5zQ4cXHka=K0XyNV1yuObrWaxqpO zS0uBHcSY;R<-kI%XlWvi2cP-v4qDa-EF0rI%-7W$@0;rU<ST;hUmhypM3wZ7HTUTu zYitWHfD-j!i_We749tMN<JBdm2l%iB&$ZQ!gB(f;qlPi`qj(3nFf@<D*r)cCW1l@O zg4~QVx^F+RAZlue5>z*~TmT`x$F9*(?_1kopKIiRBPc-EI#N|E$q%?*Mwno|%s}Gs zTqeB1u$-3OjimF=7*T!)suhVJ<b1!OK5lS+I48D{oSFeChXDoxYAo+j-l;(${ZheR znHIo2q&#R-`zM(;-GNdhqzrD8K>|Aa{+?fvpDK<)oOrsg`m93pJGY2j@B7E&5woO# z00Rj=q>qC1XjsY-;%omRXgQR37$`h4o6|k=1X7J4fDv5i)Pd-|3`T)tpzcW1?`V&f z^@61td&bUs;L~|i)I}G=*9<UGxV-H|*OWHbH>xqVt^qwwkVxcH4-$O*-K(9o9fTpm zKN>$fyy^0>L%sn&)L-@<V>ZA)C;k-z2CIR+hzvPP=yS9PzZedgBh7mDsppcNP1+<I zSLq?1{a9r0=mvkdT=W>s3i>_lFMDU{(hyhT>BLksX*7{hu)6GvrWJ@i2W!*Uf%lAA zfUodW*d{_jW3hAfzfkBL=m6TA+aO-h=|04(f%fdw=;z1VvOFF)nd*9Dd+Ic0^?XNf zBY<-2(>o||A8{l=SCm)ALHYg~fegQmq8dyE!Yy8g&Jvyq{+)j4vE>PB4kRasXGZ@A zL2`0)Siwv>%bR*ZRQ9G+rE0IJM0-cg(j#2}34no5@h+1?L;C8&$J!l4g`|%JE_(Dz zr&e>D>xeg5YwVLZbGvis(*gIh<9H`U?bG~k_xpF+pD@vVLtkUj#1&J0i6RH>VLpF^ z5WOr5@^anI!g!^&Y=mF@<n@off3yLh>>KX&2AB#0Go90X3?j~18a<JqU2tJ$B!mDl z->#<uWA|BxamkTBI1vevM{K}c9pT>7f_TLPQHH2@Lf$)YyEnFjhkMc@`RnE3xFnO_ zg!_ktFL@|y1J={LOp-2(d;sV}(Qo>Mr`<Nqa|-Q(f}WChV|v8=fnsO2y?=1><1xk0 zrq+t|)s#NWlh@wj_n|sXT97u50OkRRh)ZsJn0_<m2&!8Xm6v#kH<A5Kt<78lAZtTo zUBOik)yfS_St+i-uFnqq6Nep^E5o;sZJ+Zs3_yd(wwe}j0nv}J@tGXtndTV)UX1S- z?&=%WlraiR9dsJ&SqHou0C1jJ85U2Pho84*S^T!Dl!c=PlC{^UQxK|F=5b<fXM44P zD>=lyPx3*Eg#RUin&d`)?BCUmKvV<U1SAlcx5xU~Fx=QsB>Z8qw9BgUPq?48fdWk= z%-)=HL-=at$oVceWS|EZgI_p_0kt|!M&$3*=36Rgp8VOoQbswrmc+{^?=ag%F4%qy z<`mJ$E4KEdbaC_U-~#<?;H8cS?41#>Fg@j={$It>i{WHGPd9O+dry^|sqc|~1B<%% z>_>5pBF3R;<2q~bzw&=Z!d^_<>pp>O#Hp@2Py9Sn#-yHWGh26QYe4nT(kJ?T_9FdP z0kPixV=J*&f#C$XZaHGbVy#+*@uw*9L<Hux=%oTg{wMbbbSET8>mQG+$%KHsv!cf2 zT8^Rtwe~8Ajo*9v$VVA=djmR!u4@WxcqOC(QgPj-%;0N^S4Zm+(+5Ca<a}@oTXy5_ zJoND<iC*oIK85%GBz)6E3WEj*;}|<4bDf)h-&5n?lLy#LMTSM-fXnZPf4&bJ#_Il^ z;lH5w*GxBDT}#Aeb9J^W;z6BUwG^3jv|#{iDpy{Mh7?XDom)b^OULO&9lmIc#)LlH zP}WVDur4x<&Q0CDpf&BJCb%Kt+bX)PzytYRpr$<hx?)jCl%t+<bil1fk%_YcFOZ;} z^e1~<l&bG+A^|XwXm5<GvE)2hw@|;9^`86`q^TD}*^`q!@a>lqZ9;7WrQ2rGrwni^ z53ptWK7sy0*Lvh5_{14Bjn&ZS0VZN+_N4tC!jSV`S!@6wdGA<=Wv%B5F*c@_%Dv>% zbUv>H-5Urc>ofj2!~Sw-zL1kSFO>T>-n^Q!l0ue1s+ME|UBC|oXEd~=s6Bwxa6yXR zz=N`@;H7qd63yM;n7;>>`if>yns4M;;!6(A!SFUtOcc`-oI^ji4+9g5)QWVYkbg*- z)|k_-3t1SV6%ZdVgPGSQ`gFR}_Q#e_-Xc7FI3Kabv2Czg;LqFj)A7eK#jES}v)0}; zVobx;b`1*KE7-X>#XEH{9nluvCX>bXQ>W#dR_ECh+y3XI>${A(=acpb$Chym6cUjB zY48ld%yqp+=J!o$OE^=-fr9u?Gl&y9s=3BGl$wS`aUPL6jpuHl@)TCpXxp%BshT+Y zr2<0OEN}DW;`5&<oxn8XXM%5fv0_2y8mo(Z=-}nOduaJ2647er^#|h=GVwsXy$6R; zg<{vgot=LNx)z6hk-&k>!Hqpkw`sb%CIf#ZofSeW(iA2S)S{HTk+PHp<e|5_G7v$C z@dnVb{W<?g|0W(EAxFQIpn{ra3REO+e>P>GM>*fIqweCLpwD1@D>L;$%wj}a!_+r@ zve8u8IQdn6le`79dM88!!g{BYV!gnUui%X`6`P%lE%lf7e3E{sxgOJS{j8>WsY~c1 zsr6Cu0`Osf5`2?^z&*Z%R1KUwet#(M#Ay|1*@Y(70HeqYxROz1h0RBcRz?%<fi@2k zG>aE!iYHM_3`B<WE6G_Ez~bM2M0CmD&mRECFF>T`EpV7V7eOdOY{ml|mYE1l*_;=j zH*@<%J3-v0-MglCAG26O^3k3!F>JGxUQvM%g{ZD}@oBQh3Df{QuYHX|&OeEv&<ICf zH&EuL<B+-HsR*41_FffC=Mh)Jp7TEy@RCvF5Zl~_$%;Y_Hm$jUCo3d%q;ihK0w`Vk zpEe=yq;u7eQwPhQzf>&cnA??vyc&;p>H`Lr0os6YwZmgq@ZaZmUvpC%11Q^Gcr129 zqNeA(dDcR#pEKKz;q)TjdXg4MAZ(q_*uRad@u{ivM+XfbJy-_fOkY(@A31Nop>{Tj zw&4TI=p&AEXhR}#f$!z5=S_y)_CGO8w^TtKE@+YtQqNqo&!#r^@7#b?Tkmc);K0kH zJLkvOh0QO|dq^+8@9o51kJny_@9f(Vfp%a|+OLLNyVYj&&|{F#y_}nHq@LDDr#tsX z-~y3x6<QWmb+Qi;Kqf=I63VRV@tX_YA4~27`ir_FLX3W7*4vbBWw1kCd#`wV)2T_( zog#XDLcOtp_~So{smJn6oVcD_4<U!$#O%en0KGWa*WBz-Y-Y`={+IfYuyIimO15DH zZR9)QP}SB!E>mONEm53Acoa8zE$n1o9o=&G_aLjT6}Tc+L2G(qLa;wgVaw`ug#Bvf z#@e;sBG?58?W@vHa`g}9j`xz*43nTR3#wW`huaM5CGPiM?1TA==o5dff$a&+^^9Dz z<V7Uki}jp3A-<}56#&s4Du2`D4N`|ocYxYXAafP<%j;KdB|++w9KYWlMHLfLs(Sw1 zQQf}908HAGS0zZO%Ux#<y*;!JsgoW@3K|tq9@saw0w3!$Kn-$$c15ZXqS-JiHl)Vu z;;ek01s39~tv^zBwSy+#&@ev?oStCRf3`B{anwRT**nIX2fbwO>24Fv9W2b5%9oS` z2hEf+RXQD4RSjoRkrtk6d6brdKv)zQS}x>zjmyo~k`VPw5*O>N!jJZteFmkj2Amw1 z(pNPUF_#u4ACZi2?suTD-4=mOzMwhxMTRqIj#`T%l+YMunjRXVPkOhgL%F3$xPQlF zARbtgliTyt;Ct})RyKnTCnsvazbG>tk*{fjCI~$!s1kxBQcdy_cfUSK!&!`i%NcW2 zU7@_A8x_8H|6JDg&1oe0Tz~tp`P0p2W=I7I_ZnPIbp;Xpo~mwVLZ9)s8Ylv!*e)S< zw%w{9!uIEAnj={0zMkLBG2K=;84=zugjpFz8tLQ@!Sx~!@YL^L4s)YzHbHgutcR6@ zko=X0(wC6e>X4CoRV;dXa%cDmTk!Dn?n9dXK{AJOtI?+9IkjHAEhvG_k>=ixs|xJi zRF7%&gP1$7<l|SOPc!N=7i7NQJhuu3YnS}5vUA#E=N@UpsY`z-*C_a{`w8X%0=M-r z*J9SaH`SUa{cbYTv8pjx2QRSnTTxyqsw_h=0{+}60cYFThMN!*GWln?zZI1rib#yh zKb#8J&C000)%s9FHW`-&q+TTCZC2%`lj6-xVb&+9RLab!2Qlm7dS!M(;0ogQ{-~62 zyan!fgOi$pY;n5aE(R%)^tyG~MB^sZ&p<8>|A>TU8$T?EEO%+DXOJ@oaimcge&?R6 z^zb26;W{K6JUb6@)#iTi7Zg|Cd8x)e;Y<3l&aR;3)PHH3R~`b*ah?PDCu|4g36D>j zE+Q<flw@tiZWxv_wfwv|cy5A^o?@e~rGnbL&S96IGt|81_jnlAPiE6LH+8rJT>c7} z+O<PB?BMki_j>y;gDB^%^pVo#w3@bbfFXVFl$|jz9Xf-x4Ft!>B0+I@;VD)j!^xY^ z{G@bbAbkr)ZFrL3s6OHf9bTmd!l{Kch2+A}u4STGu-pp9Y?P5+zyDsJe&+X|40zVC zpJJ`H#cO+en|snJ)O?=%svnE<=+&Y25vJ9FQD){`5rTJKA^_~OthF1`mK)oU{r4C^ zXo&bwisNS&smFVc#Ir^5iNK-zN6v{Y18|BRU%~km=IoQH$eSheBj@?^9U83XS-_|L z7Vu?Wz5)Wf=(-9=1d52?C6*S?uD&09T6?~QYkl5!`p^!~Pz9l2$?Ys7*DCiT8X-dn zOGOsI;!(oHcl*ez=JC%#J-I!N34-1d#sAD1Y}nKDGDFRqm#920*?dRq>0O4FERvAN zCg#^LIeyOJs~9@T7Y`nSJ|!Cg-@UYF69ydOeg|ZG^OHCOyK{!Fg?D`yL#_`(guIP% z_6(;&{5jl1xi5A+(+Nl*$(-tkFTNaY@_S+L=LfuGT#iaO@&-f)v!5>gwtV}Vlzhv+ zG775m&-UAa3g+Rn#P#W>Cot3UJ@l_Yw9^N2D4gP327TzD_n*g;Hg`~*uQu4D%eI(+ ztrE6Pn+pL16Xkig*kIZRd}JuPzo*T992=!3h9APzE2)=_zmW7K@+0)?0L^2H@2wp7 z)Dc@n-%(sYUzev!5AZp}l^V{MCUr|^qfdR>-Uv-_KD-KcLhQjnby2?koop+w$->;= zLYbG)5t4A0_`qY~mpZfgSh)lHm;`_OuTfeF*tKaHoCr74QWz~!hydSJcpy5J0GrGA z0lra*P48&>RT-~!P*KRKxV}jtL7UYQPC05n6xmJdB>71!oUHHOjwo6BuNUw*rg6%& z>nS`)bm<p~d8XZ<5txswhAmiJL9v~Gq!6+iFbW4|v&`iE`-*>|O*Os#-Pu8x%9`hB zd~GDIUf98)0R^VP&uf$`3Qa?(;aE4RO=o`FW;c-P4T)Muj3gV{-#Cell_Iso*l3Ss ziIk%e6^G_*u4WTQ;d?-9558k7H14@_EV}4*8RUv9y<*2~Hz<+h!t_|Qnd`%3xhOe$ zrI(xseV(xo2##GX%BTC*0Ct9eytHJetXUhHsoZCs5-FB5Ue3e8<(KEc|09lReTzv| zI}#+7^j+@l7*44gZ$G{Nw1{p!zx*xJKOL*wLOw(!3_2q3sMdD=@(vH-X;2otmY6XV z^!wEV$*RoLIv@yxz>hz;t?7F9s%L_CSR@Ssj+`e$whI!*1hY1SFXmjLZ(ZfDc><J~ z?pWQfk(BVH=thFGa+cF#8jnEB-*!FMPKMd?g5$s%6E3*fix)o#g|7WKIORZJFcg8) zG^rGXs$VHmR}B+hL=4Janih7gOnmWLc){iO2bE+(34)rPql=nCpj6ci##LV)t;2$M z{J|`|P7oFbEF<EW6i|?DgTHx;huvA9*lVmQade<%YtI(5L{j=diMSgl3c{-jlu-la zHo30lRE6^XiZv(QExKfp!3XM{G`|o9huVBbmG~oUSFIK-+wI87c!@s^smeQ(6AhXV zjqy91#ycDeb#%^Q)^#B)H$+xk(=%*T)SNjxS_x)ug;M-Je;BcFM^&trXE1Yz$$y}K zn#Dh;Pnd?mEpU=cSEBGaGG@<b;5|JcEe+#~{YH?ew^Rp4<E>*&fwS-s7Tv!M8*Ey* zh|&e!R|;!1R~p}lnfGp5>U6AVu5jXmtpFl}BVX2XdQoYm24|`&>t>#Hw$wX-u(KiE zAui*{7NfZMmO(L`P8cxP5pt)0FXt8yO7TGTz<Zs$cAZv~$$ZD0%&_BxDm&NKrxuXJ zK$;yJmsygW)}z?UJQ&sy#$Oez#0rj5r7C*0_MJri2tS7Rgj;J{nHE|6cNy4ntT|lI z(^JP_LF={zqVuC<?DXWXYp-TD7*VpTRut84Mr{_Pf;?jmF%{YRJhg90!Yo}fs9hKn z35wn_<4;IQZPqdm7*1<R1*KrIkz>y~Mt>D$r#jzhms#SRG`(?EpcJjM+jTdwp>?2j zX3o~ntb`mhEJvsgNe3nCp!R9>r{EH-X)-DgeCdps)30O<&5@L!C|j&vI*n1^oH4X3 zWn9f1>Qab?y}}jqUA92!zmpsX(ubSy+KXYcpkBkmO<)?Wqci)+o*kU1%F5rGz7p`e zmx<OrpYJO}vYGm{f?k}Eq`dgL2VFZ{VHStykj%0j53smLxf?->^O!*)&URs@zkY)L zlmUl80|5bn0ZD^w``K$H-<t{w0)hw*0)q5))X><$$=t-8!O+&hnBLAkD89yKO%Oi# z$rDZ(+X}Oh*U1by*DyqWWLldmrzHIPM4qU0`EuHnK_NZ^4B@9dm^<+029t36dIyBK zDba_ww_sz(afDM%HR;>1H2%Wg#QQ7ir1zDS-tYw)GM4i$SuP(Kxgue{+9<36;+VuG z(eodb7*0VGB6QqTv;=9ssXYDhir4|JgSC9{i0C^I8RFSelSE#7K@CUt<))}zReT-r zXt=FIpxWVhL@)SwZWeKt7iV9PL7>bbi<9_`*WBi@PTT+$q&UTxMR3dm<=P-k|E!T` zrNLEA1x032FX{+0g+@g;O;~#2wZlo=4P@(&AcG-liWSLO@t&s2k(FO02@SfEp56D- znR7qk{UuFVmy2l{?or)^ERS@Av=7pY@<Zj62N`4!t$s8tcW^aWC$AEu&scUf35~^k zD!IdoF4!<t^~1+Y$ga8jUDzO@s{tC;1zffvHLE`=oBACv9rNfx*0LO{rYjuA&K?#H zLvf->ZqzSDqk9M!=jw24Rl&|oth)#&wRgHQpB6p_yr6G5e#(G?p@IJ^8%bvX0hq`j zAnXJnAXH!3_|K)l?;m^rH&f}D8JQXBS?Ss6ndpto9i8aRZA@$#gj7`|6_k|eo!p%M zlX@omFz*ir0wN6YpH%Iyd;Nc@vQi>q^2%cWjVeRg4K49SY=r{>A^)eKUvYsS`B#Ge zzf?If6(La}6`}tWRAf9?;`B?4e|%{%>AxYXvHlmNl9-5slIVW|yNl=4b-zG1UmMB4 z0atPU7oeJ?n3(K;^0bF8AHS0ORp>xKsQ-=Uj{CpxoNVoMt&Clat^V7yylhjc7y9A} zer>4##vS_?mqAz8+{WBVSNE$x|EFL?*SE__Ul-o}KL9?w{}Jp9V6AU%^IrjC8Eo|$ zs$d{}st_P3|0V%A{=Wc*`v1sRdOKt5{}kXqE1-WO3j87+!2YQX|E!LF%0NQ>;{>>` O_32A76`j5UkpBaaFa5>< diff --git a/venv/share/python-wheels/chardet-3.0.4-py2.py3-none-any.whl b/venv/share/python-wheels/chardet-3.0.4-py2.py3-none-any.whl deleted file mode 100644 index 455eac3a3a287330fc94c76a95e77db8f7847452..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 136755 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 ZvJ#*GB@IaU2l!(Fcn<7C03HN@{y(7kPj~<T diff --git a/venv/share/python-wheels/colorama-0.4.3-py2.py3-none-any.whl b/venv/share/python-wheels/colorama-0.4.3-py2.py3-none-any.whl deleted file mode 100644 index 6d5bdb900347b768aa0af39127a01a79356fc3de..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20362 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 E0P%w@F#rGn diff --git a/venv/share/python-wheels/contextlib2-0.6.0-py2.py3-none-any.whl b/venv/share/python-wheels/contextlib2-0.6.0-py2.py3-none-any.whl deleted file mode 100644 index 6f611c17fc58f2dccb4a961d89b020df697ad5f7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12457 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 O>Hk(EOz8i0_J07;-CUvo diff --git a/venv/share/python-wheels/distlib-0.3.0-py2.py3-none-any.whl b/venv/share/python-wheels/distlib-0.3.0-py2.py3-none-any.whl deleted file mode 100644 index 43c7867224814e8c142404b19a9ebeaafd17c2a9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 147296 zcmaI7Q<P{ix2;>QT4md|ZQHhOud;31wr$(CZ5wCpmvi^O+qwH84|6`GjkJ6jNqQfV zmjVVs1^@tn07wVzlqZ_^4Mal#0AR%h03iDJ*Vw|z+1kR8hMty*mY(*%zGy6LP3`Ce zRFuW#6qRV5-JDI*xnhYV97n&ukWF?lnASp3L!XCy8t|+gGrM^*9D<Bh8Ynw)$0w_Z zOU=*mv&jVFDEMatFR70p*u~-TtFv}Mjc0s7&J)kjG>m7nj^Yp$hAXDrz7Fxm`E+iq zbJcRaYe;>4ZY5dfn{O`U&#e_bx)-A}swg+lZCaL!Uo0INy+5zlk8E1na=E2Z*B>r! z94nqEy`JCE^n8m++uNCS?63++gKZlZB{yyPCgAq<y#{eSiz8QD(Ysi5Se<sjRw;DO z`!A!<!Ka%iSOZm&HiNSty<G}Pn_*R2o?I)1YFo9foKw45xZ5-^cFo}Gqw*Oy1Ai_U zAF#8HUslpMjmhd0Us+3Pqh@F^TbX#net0{VgigN%US@wcRB9~5o>$uE(hQW<t0|tz z={&R5Y|UJ<owrd&%qA=Fx;AlXc8p7F9y`Rrn2e!X?>)38i7+cktEXwL$0}7>x6f_o z)}=RhA{IJL$8e=}pKBVsgmUm2uyCRti_5sZ6h*1(5kx|-SYLLcGp1>yXJS`fujp9| zx%a|KmYS;&zu!aSveQj%I-e#9I`2mIwhWhSGt@ENBc@AoMavp_Q9;)o3j*Ep8i!5= zTB!&Z>SrvDI%~DrjHOm%-RGZYTuC#B;k6e!tb3*<7++FViBf`Zz6lZvv{Gd<sz-up zGck9=GhYvj2|8KM%e#kZQsVYkXlp1PQ%cd-?WnDDx1;}T4VPXmplCMSXLi1~mMR@+ zoVT!CEnk+Wc)M>#pI;g(h{$d6tY>U@#+XMEdD)Fc$;TrNNv;rV$llCX!*XqF7JIsj z;jM*Ep9IrZlND{ofN;1ZpD%^)Jh48#4TMBnWT|_NBGIwLXp*!eBRJVzSnGZe>>iqR zZEG?9#!DKyUj!j?CT?bujw`V}NwobXNOR_4JMa@2BBSxtNXwB<_=`&u+rhPqnS0~F zZfy|#+O_qTK|)84s}r$eA%`xj+vxDSX)f5Hg5J1(c@@nPOb~zEp5vED$74l+`Sv)E z3anLL#pz(u4|amJeXL?E1_W@s)2&1{#Lo4~TD!P0H#D3m5P@7xB_6Z6y53#CuYWdv zgq(zA_ksJ1#Cacx2ABP?mh+Yt7$el-T)F82$9vMXK00IaIAR<9{E@elIm7##Co6ax zIk)oVrzMd&(o|)M!qa>DoG?&Cvy)ywIdPHqK-VK*I%G|<b1w1JU8c3wX>FsI|3;dL z@scPk)~>l7afO)$j_X`(4npP$0JG?AjY3>3J-&e{XNHthRlk0*%sdq2k3*R`y=JC1 zS)0Hbt>X({3uAC8?JaNio_?uKT^aZ@!eYfVLD4FUg|p}x8&Y0h{k}vW3o5{ezEzTt z_cY2D=}+V3_1j-}1qLsDEcb5L^EI6s(fY>8<p8Ws1i74)%NpOr<uV+{%O68PFke2% zv5qwnfeuin@4^a4bt>Y7g$s)qROrQrtpc}_Zfhf>6t#h6HyL5#ZZmlmGIen-u;sqB zmS9|zvSdLVuvc&io(zXy-^2>=5aqbvVps4S!)qVnwP5ZjQB=I6DY+h^5Glh%u9)2# z=}#A-SAZRJp&Ur~BjN<3;V56Da~Av10Myw(s=%`DzGlDNa|U(ms8zJ=7w%UCVx>G( z+)>!-ir%8}&@S#AlRUZ=qR>golVBdXq||nshtryBd<w-R&V=bAu^s5vv%Gx|*qRUm z?vCJ1uW!MQiAzrA<n@L%aePPB+RV|(W?E>qUT@b-sN+h(HY-i<O)b2J`7tG9O%Y52 zIw)5~kxea9OYXyVkz2Ne>)&hbOu%z8)$Df|{rS#k66)unG&gqWu^p*;Gv-V&$TU%y zpU<mY7r^9ez?=n$%^AtwGg-q)u2?zaItL~M-XsV=1C<Xh(EuRFN<rLKBHJ!9y`Vf^ zt!?PAvu2&H#uecmy8r>VFh`Kbt$fi1$}Ly0+o_-}NMV1*0YOfKno*JsRCd4GPG_CE zsPIWj**|mT2!bfcb)n?1L4TRo4ueAIND~JW0b2;f`2hAIe%8pguJJ^*ezLqAdHsxs zRlKW%^Z@XYH3)A%Sa?4a@||2qeK53e=Tet+6>M?!c}2ser-i;=SvTLVfYwrvWvI}p z@B33JuLVjbrJfDn>85ad?_=?n-vRLAgyi_DFmUeYHJ80s2Bk>}*tJBJOG)c-soNA_ zn9rsXkJ-Jn1BGWrY<R3*3PhJWQoTBmU@P<d75H98$EAdP2-CyNAKWEsEcI(m+&&>$ z@v>0!NjmROX5&&U*=eVP5jv})fkvyAYAeL~q{6C{`WV_iN7<G`$<|`3vZPCbLakCm zal!ava3+z758#ObF4)Xg1hl4hV^NUndtXdACKun-LQ~Kx*y9j8hCE3mPa^?NPh8Ta zj>V}~Uea$#wodCW5M3;VN52zI@O-`r;>@hD-AA&&glrIOqE$)Jt|x`bCJm)OlnfGc zLvw?M(HCrmK&cQ^KF(I;4h;DB_mpu<AT7ItQs5=Ct<+p7SS+!}nJSm_DcRmfH*IYO z1qrD5G;|21_J-69$t{K`vId}$)U*F-UCvkH?)UN*?nT*r|G1$ep_^u_ho1XH^VBx^ z>#fM@(u$(cN@p~gnj2ynuX&W9&4Zo%$+o`rVJT!tj>c+<j(XiS4zAoaTUQOK_Y_Yg zUvCdbYmOwRZ?VR_E+K6F+sf-`Lxmr_4;?FPq<Mb3GFB%UP5!3F)8)2Irlw}~0Er@* zIM*VLjJBOsM#`*6nCsN%BhVw@xa;@8>1wAb(7Hy-3TyeV2hF(?Ol3LYd*7{1rbK^{ z!u3YPBq@KL>S~Q-lFk$%Zy&G@K_WaoL5kWW_6MAeh4X=n+?ogdz!;o3dY?7TIo*Ut z(VV`8ga&+RoUr}djKu0$;z(_9LXq)EoTM&h6WDyMlEqHHuz;@s@<*9}?v`Xdp&EbW z<pQa2zHI=<7)5OrJFMz6$mH_p>1`WoW{~(&k<UCW1_9C{iViyaQJm;~6V<P<4)97! zkC-;dE!VKQpa5z9G62_HAIMUpjfxdQi-ri6;WJA=i?VUP?Vb`qkWX)-axY*yKwh~$ z8ipo=GmezLO7!(B@xeSkw{<LORU)k5D*AD}DlW2qLVD>r+(q}$Ej_|k+AD(tnlKlm z<->!i4_A99XLbeV(Zn*0e>rFN^s8ocwp+^Vn9!FK6Z0QKU<Fk~2ZzKIUH8ht9)~1V zh+5k+kQUEM15X_~b2{!S39yVkZI2|k&lPq96~X5C)~A+g@v457Y`=Fz!+ZwozDF(5 z$ENveTgp;fBiWrSO@r%JhIuGP_9Jo@BQ!sgqkzep>i7kV0#8oK&sD5$wbt3)`lD06 zA{MiTlhfNSAl?Vz98FPQuWaX&9n-S}>_Pt<sF^)A8o}vVq-80`gAc)O;lm$_yScyT zl!Z;nwHaW9vzOC}b4c{43oJ;84S~~v7&;jLmMZeEgkFL`kialXA@ib(M-jBBEvOFu zUiB2EX=>F&nbW4qf_RJvA>6=KYzWmxoAQ`~nZ4lv8A&YIx)ghtc1hmVp>fiVDVw$j zoX3_hpX|E?OBDqyqfrYqXMD0kEkeQ)>JWePk`n!NUyea=#uB@iS>o;jey|J<%xP`< zHxCo@o?Fv4^8iWg#{70w1CGo9Z<luM^CKUN;(H7?vUtWi<AhdM3_n2l6g*pFGEc&E zdU4SaFn}R>q6SJbW=DMO)42{SsFBYH*62k#nB%$P;Z9JQUzOnvc!H_lZW&hq^|XAf zqs!iJEu4k389?Y2X2q5UvO!1<Tf+Wd`-tD4*WEx-RkKJ*_?sBe`>KWnP3egSyhf8H zTx+dZVXWmp{XBr`3Kx>N(2-E*n%Bm-oet6^%)?x!T!3ToNxK|6@uodk@Sr(vp{KAe ztAi(W29gz<s9G#~nH?;w^Qf&U^_G{)m@PaM)Z9O1JaKf%T28s>#w9&Pn@kNacrXi4 zn96&sow0%=tMS~~vq1v>K60wlT5nrg>`JBDVlio@>PaV;wM*K529!*D+(&uK_iIAa zuj@Fx2yU9@XKm+}rAJ>9UM{F=J1}&VDr%Ewu1j{$vW%8Y72TCE-z!n6#anE1&Q0R1 z8551I#Ixo|rpUL>cO7`g?rZaaq8c8RPjdP-^oK+sN@EIX`i$1&P_+bMTmq_O;6)8H z*+nqK#fd$w^e)vDL8rGofU;z~+zi~lf0fa@LE>0TUTZ!2Oau-v#w}zT8+ZkcFr$;Z z+U`c87XpkEf+Qv~CDUXR^6yt?ca`{sJI`WCI~<8{r8mH|?e-mlLcx0L98cN|&MmpE zJf2g60FYOThQa34$G%jdB5^`_kOJ)08PwzgF9YvZOrGSN%at>p0ty-qVHCu3cC1J6 zkcE<Bbi|XoQ%0XgwMB1D5C_l#%}1Ubp8_ts%mv&ijoPOcp?X7qfp(%y%<Idm^RDx- zo?(*mk_ZoVDX%lrV4)b@o6k|0ZLwX=<|o@+<POn1Bt6G4WNus<Q_d8xwklserT!Z5 z=GVR(7T-jVV?Y^^Nk8E_;+IA_8yv}A4ZF2D*gbM*Pft7l!JB%V@ar~|Ep<9{i&ceN z*LjzmIY5yC1Zysv@<cG9XU~zvUefTfP@{7E$`iWQmDW8o1^bNqg-SqNh<0q_e!1}^ zW4_j$RMeq@p6EZ;5paYx3}<wojL&Qv8`l^%l(8JsXrmcAT09Sqqvn`MQb;z<$YC|M zlg4x;;r@O6^i_ThjDmOOofu?F9=jX=SxzWuX|fAwSei!7I2V9B1GYgzPkF@r=(P&& z21_>*XJ&a&S(D?lHU2}P<R42mw7mcJtQnGegEXj!3FWMBAsIFiob1{Y)RQE2dPI)_ zYRX9;1-c3CccFNeQN{7ypP!;~IKl@k><R?*Al8?c!YtMDZocSnqxc5h2!+cr1|^7X za!^8eXGgmm;P|CD)6ihTDQ((#C+(BMpS?sfzAx<@`rPJrmo&qA0gGpo80gW)v^x7O zsj!X}upQ=L)u5+i+1LE*k}^|0*#99mp;1s#=yeFdE>CJ<ZBwUHThw*-0#fSxBcMA3 ztj}2g?i+HYmbiHQb@R2FtKDt^-Ki@|kd`jpotziMU!ZAgpi9gAu)8b|K?ky$%C+tL zvc4(_D<1+Oq9<Exs&?Dco!*sR<})lu0rxDwPG+iSZjR-F`z#;dHRVvU$tD)85S3(T zC&rUtJuUXFsmK?<61ZOyKKOF@TwlK!+1R+6OP&hvA4lv;L{==p>`~|u6n6ux<`s2W zhO3>a!)}^KAF(6c(90-YQ@}StR-5rbo5~j^YI76#<q|^ZE3B*>YJ04Zt$c0pThLY6 zL_`A61fHNRJv!NK1n_trcPT?T0!~V13E>zzs8xxZrkHM)x@9eyUjX;{W=S;XrYSOU zrw~h4ZaqK7aalO+nSRG0F>IaKu|4KawtC@gBR2$t`Aw;{BDBlr8@nPPpYjo|>Yp`< z?r_G`h7&mr-a*Q|i~K-b_Q!LHs_wLYKG?><c`mH)?CFGMKP2-Ffm}b*V%3W&3U!@1 z1x1!OZp_+svJO|DfG#D}ItQJ;L;9Mj)HSHmICo9Ek=6oMankyB)|rqAjn3Do`)@+| zh4*cA&GP2Bb;4Uz5xI|wok<>G|AGJ?<~0#lqem|9l9qfxO4W|2DSA6?;%4*P#~A{L zy{8#DOb=z|fW4^la%c7Wq%S?azcBdnY;R<j16=vJWHqnX>%JcE*C?Iu>;CA~AfMOU zsou{)YVXgno$vd0sPE@p;fJ35f9NWg($7l)KmY)OApg6rA}t{#BC90wU%HBplAPTJ zJ#z1<61Rh8ag+;>O=tQLvK2uLw$ca#aflnF19E1A&u2H<*@lduV9W09ZQu}0Z6Qw! z;LU}no0r?$$NByKB->oIe?RP88rouee-!Rb7egPb2Z;&?TrV)Twb@N!8U5k7hn)`G zijb9Pqi^t``g1=s1GcDeJMfYX3$6@wzrb=Y5CdV~wUCMDCSD<=Ws_iHz6j<m?7m_& zSSVIm*Wc#qI5<qTT)7fB6?`5?zY#&J0u6VesT;ER5oMe;+;!+Kp8nyGm2BXsk<j^- zA%sKu?QE=vyO*u?#BK_BuZvNn^K~Pj2aLgSmKXkA(+HNV*X(B-Y?hR=*HgdL99pYI zBuFPOS0cAXmm&T6*QDp|ZRSAAdH&!KEs?~VVwY0iM17Ia$F;&Di;^~2s!U|xbWV7v zXguxJb|_Jy@t*pmG2d81P21+bbfy!II=;6+n%$atpwPEk-8}Ctg14SXI#5D7RjnWJ zX2kAz_V=ircw6k}-*`?jA5^f#+7~oR*usB;6J`mIDW=rJPc@*m{P`NA!LsD3SGnS( z^xt89!nmV}ej4Sws0AqDFA0&jqXmv6S|mh%K%j<>6@^Gw1c}O1_ygD|`w?2BR<uc| zxEq4Uf_8@MkU7a_ND>&y(-sKVjim+Z6@vd|*HQ&qr+7M)iaVCsXKWP($Tue3Jneew z%pzM~#D~-|!_uKe$w5g|iqT2XSjK)-j9y8DGGZe`9HEJot8h8;aB4{Ns}tMKgGH1J zhA(2xG426b#B{6RQFJBBZ?p~+l30HV1w{fWlK7kp;h-#W_|!)#C>5ArYY?%sE{gZg z)TBn}c1a*#>>M#)fd54JIHJ6C0uTV;@E^kX|BEyzBcd!IETAlqtSl3|NDtrrsWt_N zKeN!_=eS`BRiJ1<)o|s)5?xwu@kOv{f#Sn+Xxkz$dxSXrxRdFgQ~#ZeNGYw(tq``c z4r%&O{T32JDbHCVYc~wq5%1(qbg_dDEd(kx61ejcF0f};npi^K!!8s&n!<FY^iWSZ zSuMNS!y%tQ+f<Clol-lF=DpD=-=EmR&L7R!jAsOjv7`e!8pS;twFRme>?oEH&16`O z)et{v4R)e+rn_QzF5BW%7J;|B`g@qKT!`Nz8u2K5O!v}oPJgXUkCKNo<Q>XzkxlB_ zRYc@6gVpfoBB(r8Ud0{?)H*=PJ8@HyvF`dz@^u{7#r~zrsK2{${#!_6U05|fK%|y= zJ%rJrYILyeAVy~_D%1lM>K2$y{P=k-b>n*B4{*QPsur#*?rK@b#8Y28Ml;QlkhHO` zVgrT<?`HjZ#7w6(FlHjCRg=vu(XWyV5X<j0>BFhg<0PCC)!2B>k+Pc8yKTdPYs0~} z@$i$bcb6hJXKg05cFc}msz_Kf7m5xnfS%DUH8@e*_Iv;Mt$0>4ZYFSx_C1XLt|<oI zd7`Z6+NG<U!4e&7C4?7G{~p0+=a?UT0}4gZ8_a)lK+$fLpY)G`PH+H#e=70+uSBdU zA|$6M?7cLeP@s+sw&%?QW$ciyu>=H|tRWA!4(~SwF%~7at16r-@z?An05p^C=WUkb zHRV+(Ih4<vulBM3m2U&(q7i^(Oz*rANW-B0@6R01)N%oL@!Ir)fArFqZBTY-!Ob}A zQ6DmX02rUGuabh3U7!Il4cl}l-wUQg)+@Rr^;Cwu1Ah}jXiB-&%~l3s`LVQI9ppZM z*d3b-R0uxwhg%>?`U~<K!BDL2D(!=%bo%$vw)kxE#rioVwAQM}fnhBY0T4d>{m8=y zDjnAO)x_+|9taa=3RP`OPt6cR20kJp@W>=Ao2>QHge0|4u)JT~kyb?pIeJFTu08_M z9s(Um{86kUJLJ$!|Ax#GJI(s@;f+0oQ#2dy+TsYoK{0{d74DKd;_K#srO;T-Yt#9G z{wdGuw^Pr{4PpIB7zqq*l93G{qNjH|0ALoFexQrVSFAoUmH|TQ)!zUNx^{b4;qC5H z`?(0R4#7iS@utSe@e9aB_?Y=6G8DM}+aI=+oZu`kxv+{{P>-r?oyCY+lzgy8o|ZPW z8#1WgctEPMS^+}x7mhL7o6P#i0~<zX-!%B!Ht@D9)ChHouyOi4O_)RY;YOd4TSV!l zI^$IY5O~W)UpyCgE^C@>nqYSZvitLa7mo2D19}jRjZMf%C5tnB56iZMb)^nKzyyP{ zRu)+IW*xewyEY{>iY<Ohg=vEF=7G<8qWJ#fb6V4K#M`%*vIiz%`X|%w617`*B|GZg zk{4qJ*^x_QU8)&~pLcZma9olgebs>O9TGiq*%Plc0_4H8S%w)6Y&)gk6Me*d(~rX0 z*<)>3Ob8{rEEKI&+Pr5nnI_pv(Nx7JN?fwJ)}v4X<rWz>FPHuO!>e7|k9cexQobTK zV=vO{a`UnA!PJ){h2so2L{5u-D*Rwy|D8wP4Zj8?u>x19*NmR5XC!f0&jeBSa#;3< zC^9Z4l#o4-^my)IbVx72m-SvSLoWTkk;_3!>|1dZR%uLkAGL;#e^)Suh-(D2kuRW# zqvUvehYKp_>%tP*hbJP*1wMN|&xZ&7DJlde99PHonvAH#4Y?1Rzg^qMWe~MK<|2yJ z5G4J-ow@FRM;!Emjk!X!k9SL;<|6hfVAnNSBnVEu8}rZ?;k+WgOf3#7RYUWn9xOjE z!ZoB^YA{gp$!D2MchldobFD*I;B4J?n9lo6mN8lM*8|X#gm*t-i160HAMQWlW-g1~ z$2C(6ZFBfSOx^-BpG|y|JEbsN!j(KNf0U=d84dCI?h-Ix?0?b%iU75T1d*TJmw)R~ z;*pvf>zZ*CrAOK+_oe=+Ucr>4#{d%1s?GRcDCWf)7Xi%6q`w{$@L=yNs=-i`jc703 zmh^E#>oPSn5>%;CLupC89}b&zJ3>XX9fvO$2PE98d+_{!?r5&CK?U9mQ$nGFsb(xS zbxZeLD~yYBfs~`JC(J}g8XNakifhdNs6qJMF2c%Os@*?v9>}0gUBdVr4W7x(vgnG4 z#KOv@w%1Tk+<X-u*r$Q9wllvs2KC_OQP_8k3(dv${*QgFuXIse?_VCX{nv2*mwcus zE+QfgH7hPNJr5&ALpd`w+o(vt#I)xqH!VdYNj*;2peQamPE8w52VSl)M?c5JI?uFl z1UWHFH~&n%0z*zCIXy1jph!+ZDRT@dA>FD-UdFsIJvl42EHhOZ6pl_L-1a{rQ^3fl zgZvi}#J@)JzeMJ2XRl{%;%Z|3U&ltNe<6&IOCJFJkIu%YCwq1NZQmmQPN7KuUuSfB zdKR`8&U$*Z_U^$7{j!7f(A}q0)Yo;W^_Edk${WE7Lq!%smwTEf)tg`&MUFgcKe(-z zbGAouYjm@-v*Qq?Y)Ildrq&1p{*U8Ap=I%y{R1pyj3VQEG+t>kx28zzxch_Z-T~^q z8Km$V6Gi4)Q+_!1;dibF3mRcMGkh8Fx?BCG8PWQP`2HzADdSggSHx5h^`ev6s!<S? z$Ap@r3VmW=HcaZ)E1lO5=iaUBBRJ&TCKn?JLdOw;QB=vqyW-VN;)rR3ZkSu(i}i{Y z#ha)(GLy;cVx!2JGa;{N@A*I)(RE3NoY{+6+TQUY`HLU&DzyhCf{JUYgAKjmVc5a+ z0U^!`m+)1I_d_ytF0A${S1=v@ad5C5$p)|{u^u$4?=<iwF^qiNpPeNJHg9^0l4Tfb zwBHxyg6A=Li2OU|*VL5D?eTc&dLuB9M=G)I5{53(5(jWa{ATMWVVC}1df!0*xrq|p zntcuan+3#wGxFb{qti1qFtW0@b9Dai^Fk8aFAK~7EqwbPp)dmv(tQukgMSZBp6S*Z zQl&HuyZpmL+dUn{U3iLqC|27TU+_ewG|c%CGdtKq%Pv48HC<S6&-kFfKvw1LH*79$ zn<ja-5Q99RLHX;Los*KH;=MSjUW$B3djsa~?lBVZk<yc*?Nj5ezM&xnG}A+wY?+op z2coJjX4~pT?$)a}z?u>{0CjO7;3-)PXQ0J;_50h^nO`Su`!e-Vp!yB`betJMVY`Ki z+Ofzr^^qq@FoOQ`KUl1dpfj2IH}Xkf004~t&f@<ay^V#F(LW-+mHKTr{}Fjf6$TQV zO~cTV69U9hB>)D3zK|~=H;6yRm~E~^EL70?c1yOda9OhEj3D#C!^1nSq~4|F*Obf{ z%4J@z>lJ~)YNDjRUgC6NPdui^)b@RMkNP4OWQT)O?VnwJ9%~PwXKh6(Fp)v%=NfkB z(x_?o_cCAxWI(yjW9<fy?N#nGbW}$=gqJm4`X=~mSzQd*@{&JY@>^AfidmedOKjKZ za%F7nI?_*HI-3xvN-qAE+b9dFnj@6NYqls(?5Mes?8fGj*whI^qFSW<v+c!vpfBxP zKPvw620aJ`5T1R1;4>s-U&BzS?)=i~v<fQ@WyP-ZvE;CMfgSF+frpyo_V0`tFgY#s z3w5XmpCu_1gs3sAr>%o{HIqF-;41=?YW4{vH-$83>p>7v^0(K5WprS+#f(Zov?&H- zJB@G5l5P=sZ4{Y-v0g6Up;_%zmpZnwhF(!^(G^p?l8Ka?iQ&cMVHN2ZUUtpJ{doC5 z?8VN+yorj-&xh^4=}_fvezAu|G~8^40Vzs^#N93)_jkw58s|B1YuADvAU<m_L}$p{ zYzKItFAlT80iEbm_D1CPPEcMv6!hI4%J#T#_I2ue|8of(81l@CVFLir83O=d{XZda zGIw#du>Oa^GPji-)_DBxGZiN?G%VZG&<YOfU)?j<m{rjzVynT}D_szO%mf+Bf_-Qv zxXGuTpVvw=KGTqdl|S}jylcdzogEb&J32h2C--cz(-oSh$1myU8`FoseR{I8a<bEr zmcC_=*Dh8GXiQEoN9XD9_BPX-LY_LwC*I8#c8wbuYAR|qjjXj3$fVt^D_`f&k*R!L zzUeKwT8YV4j|bCmcst!c-=lDLJKdvr23zCCjPGkFB0IQKB~)tc-3*x(VA?O>{2`>K z&ljA(LA$K(23Q|9*{iP0s?YsR&CN0%jt`4+d<cfPGtHn~D=Hi|f3ht0Eo?F?D%DWY z+8OHPL3>wB%{HOyW})MrPOU-r02&h$y;^H8R+OWCEMb3)GMmXVJ2v_copYO4MRAQM z!Fn&+WZEY;l0Q2tA_f=(J`$@h8w};kfh-y^!+AI?E(aTtfPEkI-;bkuXnlTH8;3t* z?RI<IU-yq+Pqw_uxI7K{YOi`&YAvoNJ8CY>4h!{6M34kamtR}0bWE)_zira5V+5A~ z0WL!;u>CexJ^_|mdccuk?DJ3~tH@EI-h3GPvxQ`pCwpa1M!c72J1wty4`a^EzJIM5 zOIeO$eT2gMPdhJ=zV&XO&;%j*x^_2Ja!_jZN#1D!9v&KX+Uq;7MrhSV|3JhQ>Y?GA z)P2g>dDyhNFK%?OL6iMGo)1NU&@Q5SUB4KqMF5DweJ%l$dJ5TR`XI<7-Az%kLBpS? z&$lK`B_pdOw89j6BBPs>bJt1c(t3!Qag%zb7X*KCcejQ$-|D2cyV}^&-9&uKfacfo zhs>PXI?8)q9#QtxN=#=6muW4>jKGkdP|FL1>8GTUpR<h(0K3z-H^meUv<{n^h8D-+ z-aYl?A__)ZaQ4ItvjkJWay3s;RZ*+5crIo^?Q^d40eH`zUg?E&q*$5FP*H{4!t@iS zcVN2=>?0uo{=pV%PT2<}vvaD`HOI*=E-n{`hXSz;nwsnfuxscthXAg9<{S7?ZiOMp z&-ekhXPbMp4_kb0-cI8mO_WipJuz*x-Dsz<ZnvqO&Gq@5UL-U7z4=3EC3})#4I}HV zeZ;l`08m#AW{|fBjR&AUgthP2<%iGhed27iZUaD-l}Q+ir0ac>bBeXIX8TCJMAjHI z&vt{RP1s%ixI#+rI08b8xd&pH2=78K9L6DHmzZj^tUWtD%J`d=Gp4wz0ZgezcA$M? zT0vjJ)Z1g!`?K6~eW9qM$f>;=ox<bs$h(%0i|l|Hb@o^QZ`MxNfGQ*UI8{}1eG!7q zT4QW4qfAjEm`DDH0zF}y(yHoHfSZJnEi?V`5hB#njDV$4gId7*XTY>KELcRC2tMd5 z=9_>~-g{_ErUsWqtqA=K5D0n+i!f&^!QGfU3gZ!Wy^%sjHv`Js*?kn1l_rb;KJtco zJqd2JUMcWp`HC_v8c`2m8l{X<vg#W;0xO#I@v3it^wr;h{`t@)q+fcux#2b+)aD24 ztV)%w#l{c+lR{4bKBc4)0@fZiTzr>Kx7YXiV>uH<xzGabtkLW~B4-xZuAh1~b4-&c zH=d<x+`OkRBYEoGqC0CwdL@qX)8vc1fo4$)2UO3<cw|}u-$J~PL1NI%G`)2i=itNz z>rP!~FiF0&@LO!zUJl}={qQ_@*Xx(jxEu>S@eifa#4Pp$q${*LL?;C2*hL9rc%g}H zpTZS&-@z}dNQ;f>C^<IS9>LhF`{KSMfgJ$l_ej#XSHFzke(E}V8(`%qIty<+xu`$j z@~RlIXk8I^r%<s44(13IL&elE(M5EDyXSTwup3F)d<38gtl!Wio1L%QBjBMYKf;%t zUNeBaq|vn949B+kcal-XnaGK3Wd!!UV6L>PC*q%^P>l)52#fU%RvTT%uKGz>^igBp z$V7ktn6l<sEcB!yRQGB`QKBE!<ATMHNyIJC4M<mNvV7TB?0xx6o@KMwgl#1>;_v%j z%;$Oz{R>Y9--l?QhbT7^4c0ckJUl}s;_^Xyq$AbDDr3^TzWpUXgg$u1T}b|x%jj=U zGb!;2f}UN}<p+mFT*wGgbNJ~zm$}^qLVbIFoe0}$+g61Yg}P<2+(R;B38cDsv1+s@ zu9A#Y-VosD#Pzdg6nQzc!T0j-tqsR)@rGO=MS7BaGbd2`#}3+j1*1*k046BlQeFaG z=J56o3w>GGPC`1n3@6C7lYk8lur(*l-noJ?jz2Hls%{#l*~wY}jXFbn0o*_f=^g&s zAOTR2{f)X9Ct-b`0-dnNXfW!k`eELCb3ui}t624Z^dx|%iq-nf9H#u%Z~}^!62^0h zX7DEf^l|8ZOUfohk-+FtW0V2F{Sk;lyiop4E@t5-lNDoXA$TX`V=3KetD$kYRj4kY z6|Zk^VUk&QIA^q#_K{LHZd~?96_f(}ef+9XcxnwVd0jM-j}Ln*_z+#Nklb~gt(VFa zg<mTFJoyR|VZ|{uS&kK=6~td`Eq^Ed`ni{?ReFsud0tK9Mk7aENm%l$SAKpthm2#d ztZ-n1wN;cMzYdsxx|1;q|G?olJE?USUmwI49<zUF#o-w(mDX1`V8^^@(`uhas0^fq zapvM|5E?h|DFmbGm1!V_-mr69Rxr4uiaaF<awR>cKgcV6NcEa)T6N>NrvLS9N^r5w zdVp+Fp6isGTa28FeEbL1+%lCN$Z3swzhcpcz+x(D<F%Z7;v|@-73b+xAoZ{cv=D1N z{+%VIgHzL(wE{Y>d}QH#y`L?YQXX=>j)9di?ys8lsoUEpHXC8nL(I{}CIo^PU}eMK z0xJcb5UBbQQ+^43Df`HW5h))k5P(w=4t3*o*Hu(jG$~?oo|sJ@`)QUGQ*8(H^CwH= zQKCe5<3o%JN@PwFS0xlHV1=Lx$+gS69__H|{0j!#>W#d)n!CY~{Q07jS8!)%jI@$= zVag`Zu%Rt#F6!1sY8yg2nuDFUq-Ou=X}|gvVr9~NeK^JYzT8(sq~{cW_;v`s)iJ<$ z0n$QX&Kvu8PjXx9)&l1yzCS!AMc#fuDY}555fvt^SPZ8#3LW;em|Ot}emiYs^OWDl zbwSl<RdTZzC^DD9`Z3VAM}Xz^@kb4Z@qs}Ekbv{_Bn?;MbuqC5SLP^B74vuf=2PRt zN3a5av`qL1;!Y*U;MeM$^L$GwAuZ3cV<(2A!?{pDxdTWg;~4$3G>9M^P+h0uqYeXo z1FNGDN(e`3R`4MmG>gWOLz%VBd5vUFBtbn?D_mo0QPSYIqlvPbhVc*hdNvK-(E6VY z^1%GM*J^vu)>g7J@PL89htU;FYo3x_AVoI@cUTL<c!PjT^=<HtNkb+H)m8TfIUPu2 zEbGz?-OBNCf#Ro=IpI*M$j2^DS7|##rXw->T7-n$-%<jmZD@0}VI7}*?tPdw(CpWJ zV)sT~pcviKSQ5MN8G(q(HR^uqF#*REl#Su8=r5%cQvp!6Xlc1)!CsA{;e4LwmW`>P zZ=g}tFemiyp#k7jL56B6=tjI?AJftZ+DD2Go7H_tDX4PyB`U~D{K3r?LAd*FlTe~h znXRBA>|#w=YS|dHjcMHq+dHtKmxp7$PHo1sq}|V9f@cn(1%QC)cUSB9K-Cg0>Wn!q zo@4?lhQhIs{uI>pbpYph?F+E+k_BFHKW6a&;X2Knmtpl>@4en)BS+)vge^vR*m#`t zkZg1Cj7I;$7E6F8)a~t+UB3iJ2TY&%VNDw)XmA=AG6p-6AS&*o{)}N*Ck?bQ+p9B& z?}0rdUb^DHgRyjwoy%&j!;V(+VMDJ@fkkjX9lg2dS<}J{C{~2w;Wp<h`_Jo~#MKK# z%=`V(cGYtFc-pl4b!zLv3^9HPkb_d_5oS9=W}Y%4GZG~!i-Bxr_;HHwbu%;aoS{K8 zjH4kI^G8j)tmv3`>rsOb7nBa)BeabP${m`CgLN~FMLbYGWJmZL6qQ*+J|f7eXV5`Z zk_g03*e}KfWL?5?*OQ8Yi0J2zD4E7(^8WMOX?)}+QdL;9))+U#3g%<0-voXHZ?xRw zW@sqoi$>6$tsrz9kG+`%0mEY6s|aR3!|*2#SW8V9rs;W!o9*T`{XJ=!V}+C*ZkHc3 zKt{l&$1HOrK-6(h%h;_0YO|@9W-7&FmEtH%C(vJ7b;~pqY*U{-c@}diXB$_ZR;#)` zY+g)95D>;%*m;eU9B8pM<IXW+YpokMYvBauaw}hJh(Mo%92!EEH?Mp`GNviQa=2TM zUwOwIO*HZLfv}Q=ZuHTHY27=+yi-`a0V+}Vfz*ct+C>}4fAYiZ5kFp4F96*Lv~qlv zwWh8p@PN3z-$!QwZ7!w|J((U$vXf*hq7Jxp9MpG4gHJ$R{**?T7XTVqC@HSOSO&4* zlA6ABT5US}t6xILMnBgQ87abrz_^L)K->bGy&SqOt?S<ZPmWR>VdRa1Fo7B|JhDR) z0e9#$SO#T<v|;OHLdF$!^JcNd1X16RQTNUjZ!uL>_trtkfpEFPzNY)4bIX2#PEX(% zpb)&ShnBJo@NAqOj~JXb9jX^tLyFP0C#>`h*PfZp*L(&}GY9Rkis2$4WIQNG!GmJo z!Om89b$uJT1eAMN6}O*i={$e$_@FCv?O+cvS{!E;KDFqKyT?>ql}3LQDD}qbowpuI zNo<CN+{pdhc0Xq82%yXTm=VK>`pM=XQfurmVh+w`FQ5P-K=}PbNzmCq4A$J#2rAYG z!S$<6kp3Ys8VMD<OaIK|j_8f^fDSDSyKz)HihUDRb5>!su$YGbhnMX@4rUEW!dH+C zQw7r!v0ANSogj=UR=h972Liy2T{p<UAUr?|*ETQ!13Dl+u9ZyazQ#6Vn4jX6!`8_q zaamBDRf1%lznN1__hD+s#S3ykv4G^BrW8pQ8*R&F=xYEBOEHYF){OrQPS?;VC*itp zQ)rHPrv$8Nj{}*c5vZbof2ekrPR`T)gY|h#V==SN7#jWeGrCrr`)lqfYQXF7II86! zD2JxtL}H$ewmq^09>v~Z8e|^xY2tON7hgJ-J?&&g{iz&(^u=JojpQ3UJyl+4D?Imv z1Lb(S7j4D$$_o`F9e-+hMBG(>=&=+h^>OgEM@aNGwxmKb)FP8F_FA&lq)I@!ArHze zn+m!TtZJVG0}81@tIQ~1V|zOF{%YeNlCQ9|88Xb0qs3C;L1xb8(IzBp;^pu(-5Y!O z?twTZII<=J6*-HyKFjrE5vfvxw!qJh50L&<%^5#p(R=$plmbw4@&k=&HQRryPg7tI zQR~V#cgx>t?0JG6_#2Ggdd`}x03bGiSv|v+wJu$Owy~FU&y*M?TJ_RQ5}n_Vr<!fc z6q|90hDKW1D`fjWBH>@!-`yiNnY_Waei*YG#WT;J&@gL+(ENm$QSbZ+Do`9&edhF# zYh4+Nd2)4u$lu&pU4RE&3KS?{61jsu;*M5=$pF(@s+qz_&&ekpokP|kaC+JkjeU7b z)T!bGp67Y`^a$Ev>n~H^eiBf!SpjGpS%|gnvhANT__0t6ro68}d>9Kx9@y@WFU?L) z$$F&~b5hC4uQ!*#yvE<Mr~Joc6b|HH1Thuq17XLoSv^tx0c~J`INn6-72C$9uD{0C z#Q;cSY}O&8H)X#LPbo;+5>YhCmR7~w4Df?60*FUvP#xyRPG+_W#t9{1xlQ`4qvUY? z%)$<zf`NfH=qja6{@mI037-Ow7tmj5{elF7HPADLYt^|!@__Uyb4I^~0mLvWm=<+G zesTRM3lC?q`ET=pur99P_-|Y6|B<-i62m|qpVbGB&p!2NBrjH7lmDnAd+}x9^kJr_ z|9F3hc|e_#Xnf|p|4GTrn-QA%eBZO;XBE}2!hde`7@;}}Hjn5Wogk&m24$f{{bvva z?{5lTH@!YM!sg}hTH79km{HdN-P%@Pa<tdG&K{fThF+GZolzEowvhp^obUosE6L)n zT8AC%_41wEa)%KHu#kJMo&+P;VRnl=cmLebmPSqc<NvlSQ9PNTH_y+G4+k0H$4cee zP0UKoGQIOf+=Ya_7pK*xZTTskz(Nb6CUs6`TG``YR|nI(2quG6VFs#K1)j&;D>=t$ zvSq|^2>_ij57dzH&ZZF0ZSSS~?Z|hE4v&muW`r<+n)=Lo<QNjNxmnA)&~!(GuRt^8 zU81S`U+a5>?+bEc)Q?K4K)soOe(-2l9b&~KVwkIr9njmO>>c`FnrC^)J)M_vqng1Q zP2t}-Hr_^bl2Sy-TTY2lFGGwnOJ+fcAazqvYD@83G|1IiwNb5ANxOA}9X_wF+F7g! zV~E<@bK__(2w>cNg4tzcNOIkg-+^w6U<njMahNR7SXWle1r%wy%{U@zKT95($3|5r z>GH^_AJ2J+&g-?6ck}zZKl!ou$$YHB0r|Z*ymy>yqCa1aLYW(fy(QSm&9h|8G2Zuu zgzHW)=5t_f(I&$XIzKI>%a`%NHSFl!>SUS5urhdG|JWnI+Dv#{_b8oPGNzPr8j4lD zT^$K{Mn?G7L`nQ++}6Jmg$u~q-l}i^f&vb;1HXM-AAF|P{ybqnqyrFrB`U%2p2Am~ zpV00W<Y>ipZC158WHKm%K+D~3ZQbYKS2%gd3`LqM6Gd88M<AY`)PYK(Uqq%EkBH5< zd1|L{1we1+>fr$T=Dt1s5;{NznK8DY8Zx1}4EI>xe{Dzdb^T0E4p*|>{(OB6dQNGz zH`RRyjL$J83bUlOw~G&GM>}n;A7??KDN%D8KN~$DG`1`A;DUuCX#fr5jp{QHJHb&u z<fJ-3uB%ySulEBUK5YRaIe_W2qu{8qV<Ns0jeF*Xq6spb9KjX8>rP`G{t3k-Vp~kC zAE;<q1@qSB&S;wKjq#_0=)6S~?YdfqdXpE{6x>pY&C?@}?;+o;y70QyT3+hDI5_P? z!maq5MmIxiCVTijyU~UF^~{kQ@Nn(-F=-#%1ZbIf1{=a1Pg;0i`5ut;GNo@Nt7Qgt zg%B@jz`ybCjM<O{$ht3L2Sz!yRAJ3W8ZXeJAT|=!LgsWrZNeKKVA32S>Dr@xs(`0G zy>Bnwg_~kz+T|;=1sQ$K>;*H%MmN4+V3m<twZ$MJ6(0efN_2m}0Cwc~+eur*DAIRC zI8+wIMLMj2)siZ*G-Ar)cH*Hh<OF8p?6Vk%=2=7+G}lja02kV=++2cg!)N(q+M(`x z3{Sf6uzO-}5xciV+=S$`u(hsJ38tL9Qe$Ct#+YIIw8Yk5277AK7uDw55sDypRv0M2 z>xSUX&D6`mhs70vEv97ZK!w}}_U3>9nXeiG)`9{aZ-ApTmD5h}%=>W@eOG2;6G<fX zuZro8HI6=0=}%2%#qgX6b)YEY!?Kx&5EEXJkDd!Yf;zen=m=}EJ)BZq)k?zOw1epN zZ0@PzQ`6K`9L?H5__s9LaJwVKM5=mUvy!hZ!0762CZSS!EFzWgKWI;6N4Od~44Wn5 zMg?h<RHfgp@ng90pXKyB&)3A6KL#UzNn0sYeKrPp^%UCwIWggw*~s8jG}j@VcmbSd z5M(g1wqUQGMM_91`M|Sx!=iCTPFkb~2!0Udea>N!kFJTnqJ;F7e`|#e&!IKJk3H1< z(#Zm2{J$tCAqfp6iaFLR3Ia3pd{4|%upw7*LS=6t$+}~P?irvWyXRrhTy&>(#3brX z>=@;@m#;GdJ@5Y9aX6SNx7#13OawYLH|w}+iLcZ&Iz|%LmD$HtTfOmbqJesi<cB^8 z-0U*dj6T>Q&J5KSG@YlwZl`++P6A`?Gs$(fqmaEmDyIa>tMLl#jV}$zeF?~x7FcJw zq<#9$hOWfp>4j)~jMd-mt(8*QNv@sb6zjtldKT4wM8H`4@WLUqyB*L00D2$Mkdr}& zaKq>h_G`EK`Oca3>5nRDyt17pfIXFlCF#LhK7M48{4QieMbXcp#l|JvQ|__t((^ma zeSf@nCw%jt_XrK7u19R#3XiEwgUL`)Xa6`L%XbDX6cgWjR`n1PInYsjOh6MyS!YjP zghB)?#zzSY%kq9{C8gN=e$kV>zYT7l{;TzXGa-iZ0E~5%hkTb1A5_0X8Uka-p^G<u z%4r!XW=HH#9ngXYEB;p2)M1$O|1PVCr+u|?re-<!<lo}vZ*>KwV*vF+th+laK=>Fg zw;Ad-x{9cRui<}vcVqKdl?}Pn=@VO$LLCDLV+K1CNae?Ve;I+sfAwg|q{->vJ1COO zxbVQv;I<@PG)K)GdVAJ|IFG;Q`ic|W(ph>Ooz&2F`6(q~Cy34{xBQLhmEu}%xx7bP zj5a^H*Z!pS;U<SUEk2~qs?pZlP7c*`zdAAzxzX(Q<j+$@0imDnIhfH4Z#)=IYO4$- zdk$!lyWoSa(G>zQn~%Og=bP^KC9o@XV=p>2aU>ZhgI$`wS`h6fKHITCV|SBmL8+>x z)qdaZ_(-j$d)i*+tL?f=UdcKgIhi-<eVvZ!+QNs!y)Y<aS<~Jey9Oy`+<%s7(JuGp zl46J{WoP1Vs-)Q1w<e-41dd95Qr~^zr%Mh`Kw4^{%5p4*ne3p=C5_7JcsF#r?UMNz zb65WwA@@Dk&VhUxpyC;SJ|!8tQo+Jj-?OsQFk%4gUC37>PgU!`s}wKziASP;Ci(an zKTjpp8>t=7x}+i<PK%pdiL%Dzg5a4Q&jjoSPTfPx=5~}Z`0>jybkClQjKULq7XUWR z`(0uOlw-PM+So1n3r3{K|IN$`4<nW}Q7K@IRA<*g*^zR)%j_K40FquhnQlSJ@lu0l zq!g$>x5WL8)15jgz35!AIx$k?I{E!{_J_YeQ=pp)z(0=PwD0mdva7fl%x+&OhAAtw zhI2_IhYvC%<*&?MSpV9zBU$M_Ubj@_ONL$thRyVyIP~tEM6^^?bk~R-z4cQA=5(qN zo3<;+hq_!sZiSh#k=%R}!QA~8HKzeobTG3K&zySS*{(t4(hJmg>zCt;OA9cm+GOvu zXTM=hB*Q!cUc(1&Bw{_u!qc99bV74|V9OW;wg5ZIMO{Ca@gn=INsN)_?0porp02!_ zndEoJ9l}qjS52#u<I&$Iki~3H#=1jzT(=zv{W~XsleKjsnXbdL`qRIIiK9?A;Jg8s z-54YHz@wn7!p{L=Ik|5i!n3D(h3B}cwoPiA>!fTpS0C`Ft4Bxyw?7dAUyfG}*~x<3 ziyKr!k*J?;8=zmZp<;|tJ8SZTqal%<5VrV^^Be%fF<tY{-rjPnKQ=0hP<h^2$F|6j zAHrA5wG~(3%U+Kqu5{D~oPt>xN<J)o^gGb78-NsQaeqlz=qS*)q+-qF*XUc<#hVEi zQ_IGUr%fe$P}K<)-d2FFL;{-#$hAZ4$m618AN*Cgbn{^FMqDm+2^^ao+3wuBGpyx4 z2NS62e2S>0BIwDdeUcWelc+M!XXSj-J8V75XTfxMi9|L^Q|A{QvIiDUIrS*SbKG4y zu&kOnhZj+#73Og+Se968gwJN!1UTwbi#=fpA8#5A4HU-g=IW|A!-Dy6DeOk2mrO#e zxf_ZJq;yPj+x}V)Xv{5pzml4NzyJOZ6WR_Hp!(&X3C;1Z!~*aC?LWFZ8QIyITA0xq znVMazOvYsL!*|W9MI~7o7Hv6AP$<I2vvO#lV&?g;99S^(SVvKxZZ2}K{JUJP86`y? zpWj?$P@=u5BOa1a;}p4Zl*4^cts^&1V8j}`1i%`~!TQ5#^37u~7jK;Q<sF_3?O;qf z)|NkbOQj5bBc6}KO3|(5ax86#laQ3&YopqOUCx`r2q${6e;Z<FlmYyd(YRkrsEXuK zg%tHlC|EUpocWbIG6aDRUyHmu%fpmQpVM&y;8hN}E#gtR0-g%iKt_qOa8SIA2<ajD z7<>&oCaZ;X0ykT>L1KI&VQ<v-vk1h;DlBj9=}%+WO1_XZsE*Xc8?>=t3ut_1T{Tw? zqS;dq5}Y1=$s`Bg1Ltwr0EX9QQUHm<<w_#)WkR=+Yz?#a7e+@?`ulg%RUOol4m8nY z{52GN^Y<N%IT7nlq;k1h$dp2qvt#GGci++d>wL9V_1YI*elVPV1Gt}$m!Cb}<U@Pg z8T3~|O)D2N;lKlNMbuR7cLgQIrJL0(Ag5zM8u|XzS816#_5sMLa~DiYAdq4c{xYT; ziqFxykI$oE)D^bO;o)|f_1nNn+x2NQYCuuYuB{zb-O<s;BQg@JJ`%RZ5DkbUuOuJ4 zbFG_lHTny0`mb=}8)Av<&%1A;=Z^6W7!@8y>ud>5$<_Q1+J9QsKkk=><^O6PPt5<L z^zpw{Z8-g3WbECyd2Bp4Src}@sp=FT;v|VV9klgksy9dLvsYG$UyRx<UaV^cCE|wD z2-`u<Q?H-@8F<hDi1-4V>#nzh7wa~}K<LnZ?zw>5W`$-%tWu{6j_uPEh72Cjaw{KJ z-Yu!7f8CwisndGd^s(r4ZR-|E%trqXGs>*7>maik%&c!VNuL-X6iWaEj$}3d4fO=a z8vz$^(5j<PZ|p9FD<uoH^Wos(#5fc>YhAf~b~R(71))*|T|n{^ZwRBE%<8Kr*C=|I z3<&wLvYMxqdIXw3X3F<1UT)30v^$WkqIqxzjTS&fl`6?GGvJMVAb5f{^6F7N`nzcb z&5L3#4AAi>r}lmmV;0g?Tn5}d=R|dv=fYFkTZ8<n-pVRb0(~^`&!&MH^F-&-u<%Pd zHCZJ2iA3AMPTjH_&dE*bfL9k}Ejy5d;6O8ruUuWCId3!Gkb%FJEl*)%y7r@XA4eLE zVapMfZD8@TT4hivS{;&8k3JFt?VIpzXY4P=*mhM603Qe41h;`JpQTEu12Ze^0J=cw zALNF<Mz}Yc++-2<==Lji4qlFr+Q9C`@yvg3c(cL?BLTty=U=hb*73mtS#Y61%Xj@| zO$`Q0vhGz>w;0lRr|4>Db+zkA<cE?TgQimq9LG<G{zUvG%-2u;(+`09@9`W$Z^&(* zVHm{Z!xJN%8Z?44ZGk^?)gM_CSEg4$gDnU*Kcn>-*h><TSokxOMhlGLM_l?;m^<qy zk59s|MXa1p;MbaFvLczU1krH2XB<jVVBwD|H@ok{H@<+>Z1U_}v&P3qD>O+uy{~h2 z7Kcsm-ri<+I@>0L)6;#+p5}95$49;JBI8_fb5Y{|17AR(zijkGz^rV6f|B{YF)%^~ z6fKJ0kf~pBIt%08pyn32PMSRuC^_y$ruRObmoXOraFGlQFb3nD=A|T0_4{oIyaLki z_^+ow9etR*`Q`B4K5Rj20nlZ(xWrAFL$ex1l7c6q%z4$S*LoSJQ(%kg`I=f!k{0#D z8buQSL6CEimN_UIEwvX>G6(sryG_H{6+Q=HIJ*ijIi41Yw8<pMMHWYe?*-nFy&M2j zSED8p3UroV{3e(|-4#&7jYhz-bAbQ&9>@_XCj;o=)dNBS`lG1E4Vm2&1R)%;@T&ed z5$HGFI|#)@6tEL3e}Fnk*k?8w@BMV}{$L#7UM(_T3{1+f&deT&geK)Z5u2B#BD$Sq zIjEpp*d6tInSvT>kcl;|;Ds;2z?dkR#pRsi@ZUr}19Ja;{ZKs{JQ4<KEE5h0%`bdb zOhdtcUk?C`bq<=^h-QHR6-anu>h9nqyfJk<(CXyl?#blj;P@SM&3Q0OR~hn7?w$YU zpZ)E(i)TL!&VR?*Bmv)MAUr0LV1+MXYthi6ZcWGPh?jVRumn)HzNbK#d#WB)I0sR| zSHkEjwPmHS>@gq|0B^M|Y8nHUexk6VQ<snM*mbKVPINnn%?byb0suCgk&+S`Y?|Sy zA-fLal4weewTIf<BFFe@#-W1YptshH>Y-d>(S)F|kZV@ma=uEhx#J|(l<H2>8zv7L zOlL-d7Qo~YDs;hs4x$8<J}e9sI`S>DryT3r+tvZptE!>yuz55qeCy!Vh=D=sM1(m9 z-k1UPf&o2SrqeHteUiG4>DJ&fPs_}IIcV-b^#cSeEZW<xB!AW8498roIl44vdto5$ zBnszBTh!HgtQFe^qMZ8Gmgw__+51gq)iPl~Ds1xc;ADJw^Z_=?dny9@pU0k(4X7;Q z33@4K+pjLn{*&=fM<=J%DEE*J$B@Z~qsjh}8hP))lY_U1pA1tr0lU32UZr3LxpnaA zVDEvxXv<Ej0pP2>J^T?j4#nb!G~sKLU&aR~+LWOu+N3Y1q9DhF?DV1J0(zhh3B0yL z$pN60kWW5i$Is}1(NTcqdj$fK#nBaKzX?zuL9v8>ze}wK0~Jr^pvSXR@|vU$((ed) z6=v*nJ@e;4($wJsTfsk#1n{a01mMd<WpNW8V2&$eJ<!;%J&K<m<RycTYD}HxRNdU* zA|4w+;2?Q&9p!1_1X4FQfON8<(b&l}(if|AT)}~DNFEj7^MF5y-+}jV*Xg_V?_}#0 zzas@y_YLrop=sc!!TL2E#s0Px3!O>0*1#W7I>y9j(ES2%p}E#<rA^eV%?pE)a}vM5 z{jRk&HX&&tKUkvL=w@vaHVs+Bq4%}eZm++xca-oWlv<X&CJ1Gbp$(K2O%qJQtl3{K zwM5g#P<(2YdUIN`!en>FKeRs<@c;m|p)zzcp`KR%?LVKVI=RWgM}LR~)OIP7A$sDA zu#9yuL=&m)PO7u1G3=AfQA4#|jU+%Fk*rMnx{11Ne4BWyISu^qkkJ^{h=Ev`;BR@r zN=RVb!0$=pA7wp?dT{xWv=w<GICKz+W}X2j3FD;d$(z(=`Id56Wk204!-9p=v@DpH ziVeOZ;>{y)bwKU?;Mhj=%IjG>R<V10yuW+8+Z!<0&ffp_OmfkScan;3Gz4x(&uSyE zJ2=TQsMAv`QxPZ~N+ZPQVSW=O2J(v>)^wBRSFi$GB<OQ^d$Rlf;Mb#*pL-U?R|8vi zvU_p&EzrG4*Fs?*VV&=yX&&Zx7!1%@z|*Jm;OV@_p0<EAKQ23_-m^CPF0^fQ-Dv8d zhvotqlGNc+Ux!PjG}<8|uZ$IP_*lr^tKK6~+=1&(p0z}EmrQV21MCDTnJ`MwqCk-A zQqX2$Bz1$t53C8YM#6*uNZS;g1p^K;Ji7hlFM!uh1``M9a||bzE1rO2jS3w%EM-qo zpf{TWWR~z71D<WY^w|l&1S1d3AkOD7k^~Jb6w%fTWj=<xM6`<H5d4xmSQm^KDgb1j zrSV*C2gR0XQ^Y{dHPN>JB)@IA$UXlo9Q|W=^xqfi-xs6*oLoE~oQr2W@P9veHc%u^ z;Sm7z(gEcB$+_>J!DxVSq5dU6&j#ns@f*(ZzjX}%-C*3uDD^qC)xVOos2|W1GF)Yb zB1kiy7zD=?nP}PZDA5A)j$<ra?DRwlUoOLfb1@4u-lN#fqDCPGXA*H(P~e7s`G)0y z56HH}2FpaiCxHOlrx1vk@AW;BjOuwFW&VIv)I&b|3gcJCDF>uLeS~8Ps8z$u1U5r0 zuGRODZP*?rwq9#Ytd>6e{N#y;#}NX$1<!$JKH~#a-dDC5D^{5Vq*S%<!B9{qW&lVb z*n2`TTpZCBeCjyQ5;6}TAt|loMRQ$I0%l)3lBF^kA5mB|k{R~;fyFTrXe{2@(ZIO5 z{wIz=ntLG)Kw3-B)5@*K<?uX9W0{;o--<e!;fXjBg|9YInfH~#|5)`S773XL&acO$ z8KVOwT1*F+Y6MY?A`6@|1!9UF<{+T2Ly%L56M{k$qCjgxfhv|jYnMw_hfUS+amHs6 zY~(CdZlRQiMapDQPC}{HONI=pD~75LjCX#`69p<F@6zZ3GFi%PvQ{)&p~5LpRvI?W zC+3d%-rn1HyFZTcwBGGkU-yoW<#)AxH%k=KAV~ab@PK{KUKl0?aJ9CFWt6Y(>2?Py zVsAxjRytU%q;Vj4m;<*<^B3iZDQoT4Ccmwu170+Qs{SOVbZ8Un0+Y)+V%uy)4*-`t zcS5Ef;5)%+5HG$WZWljjIBG+>*bxjhRKjrBAwyq?|Gfmo%yLB0IYc8blN;Uhc6syl z)WC*OA=NN)$TnMqaZI@jNxd`}&4l}Q!Hf!Atlfi8i%vT>cfow@Xz3T^=>g`>I_*Im za`tNb!a0*8nA=zd)&aPh34JM2o<HI^@nfG)2h=WMX`ob*S2g{`z_q^*%iVj{h{iwS z>jn`n3Q9*251y^ypfPWD;q0sVU-sQz$@B9E7l1h-@LYoHI&`H$sZaObSkk2mwzzuU zzsH>#wz(YAwrvq)&Gb0Ut3Pf0orcQe*Ww1+*}dWlm5m^7b5NH4{F4lcpNE+8!NI6c z6pVZO>ZlEBgnLD|`El&oBWyFU7t+g8)CwI`F&Hh$47?p4Tn4NsmGjP%b#ThoGv&sA z>j3nn6a|~-X@+7L947#AL!}=cJmz8C8uEx!zVCGV6fe)1$jUrQVGSY!t4`FRLNu$@ z_Bq3&kwE`21VsJoAp&a%R>JS<!ZN<~%wbi9BFeZB+B8%7_u9?W)}IK<Y!1E)$v`WP zhK<S%ca|*qwdZ{zN8m(Mu$4*!OZ%sR_GY`&)QvEdyPiRT>s49TWhlY|<Tn_LV0MMm zXc32(R>D=qX68{oQH1WvM<bn~@mpz}Aw@ehG*?Qt6KXS{S1(4FZ26ujzz3XqgJBa4 zEI}{Ps{$ZV62U->8T!rCOjLk99Q{L{_lk-=(DMwl3}_w5vyfrQ<D>E6CtMOzT2KcT z;xwGoP$ITC24h-JFDKC_uEJan0-$b|jBf^P^cNLAmV2ox^NvW0Bg)3suEZtk&?o`E zi|U#yi6S{K+eYCP`snPb=)pPanM_8~^nrmsEUdu!dJSfh6XJiLvmW!GiUC3+WkLOG z5)C8pX%yBz3>b88WOk=B-*PftQ)fpEm-lWZIa(Bi(A}GX1^n1Gd;a2IztMWG|No6X zO4#n<r=dy>q91qz_V6Xi94bY{Lx`i~ietSC$i-Uzy*H_&&qgDBD!3YopmL6@zUCT^ z+7MZQG-Ok72yd1=sSjC!qHv#@j9gPNt`f?Bfwax}tVnfCuUq<2rUN|4@lU%a2m78> zJNW2L{mc>wNt*mIq443f76bxZqiHCjnO<9kc%-zJ!te0S{=xW^&})k`qvM;y5AMDg zS9kP3{IK`#m;Hm|zc#u@Ry~pIJ3gXLUXb0*J>&Vorvuf%Z@Jl^L_0NhW$bO-_YY4z zGl}-tI#a5<&dO;FJGpy&DB!m|vnG#b_lB>v<oI_8Uq3c1O9eNr$ZxMN8yH1@t<dlD z0mI<)d7_K~@U8fw4PgE3*#+xUqZ<gcub)@x9~r2@aD^Sc#o%pLMQ?pOjhPnI#};-| z=zLYnS}gw2Yy7i<uTI~pBXao&-wBDJ5oyBos~t;i+v>P9z4^|SxmQ<BP=}9jrWf}Z zpbn*Zp8;B{;76FB_vI?7J(;1IW(WnRg?hYaB>dWYRYS1`It<LZr!72fiRiL3)kv(a ztTv#sCYy!-?Hvqd_|cRuQo-RML6WAnA=UgcU@6kP;B()o^wh<019STNGQ*=Mmpa;> zy3cNJZ$VCRJUZ~^Zo&iuwxGTWkiHnnHZiP_k^)dPN?@D#>4J?NXOVy*yoaiYa0f+( zV>v5OySNHtL1AS<s7+O}{qtw}^YdpEmWDN{D-0+$fU+C~4k+{MXwK&(nQx*vw$8&{ zo<OCHWu9Z$Qzy7>Y297kDwo-E*ShO&95k)QP(6*iKBjpNzVwRzq{AS=U{{hUQ}3TR z2y5Te%9`XOanooGRH(is&}j3_vJ3$GE86}^T4`W0)RTm!?neC!h*=k}v@N5O6kyi! zYh;dY5}*-aTmO<ow`g3$vR6Dz1g1=2k}3jYl*LwezS_Ryw;J59Q8G_&1YN~=AI{j( z7>L!wgy5>2Ety#1I4q+r6biIx*NTyyajj(H2$|@S@eNr>7^mqK9%q?JvI}Q5oT`Y| zx|~+8sl#y5_Z5ta%1VWpRhBKorcr~b3>+!4K44W98s~GSYAFP1Dw+AheKN{9$(dNf z!#gC?Wq8fMH9*0t79m#bNjE0Uxhm9z0by>yCwpy`3OaDQNs&~QnGzIUIw^}N78}Z6 z2%L*K^OUrdhBQ^Bc62mWA$uEztX;70s!M7OL;b-46R`x<<F@Y~9-O4}v^5y7fIYV! zY+Q7J!s?bsYzcB(-SrXsQD247&>IE=ep)7=4WtT)Ap|p~Rof`iF5Cs*JpvEcWgGUb zk)YD<NCQo4d4M@JkV0CZh~Tj(d0rg}ZdODl1!huHvC*uDY&yUu{DBLctA?)zbRQ7B z5L*-|Sv*~eM<oqZG&1FJdLu;(u3oAVi$g&*FUmw-5}-sMNt}{OcbZp5p}R3wYMrPU z>G6TNFryZWeGiM<2)3F_v-Z5goe0UQE423CllOQ$9o{#g+y`F`>n78-CEN|b_Oadl z47Bm0b8?M^7P1kYpA?O(a4OOmC|at045}9x1mWm+CLHfBS2AD1k-|B?lfG^%97Gr2 zjED|nKczRQAct&TVs*TEd|V*a3`ytm+i;a(02Hj$6<x>%*2&96T7$6H$;gZwqFyyX zk$yv+zo6_#(Tpjnqq8sUp(Zii8KUuqN24k*-3Nvrr+YcOnM)r?UsiQ_nXOyC_Gr3< zU_PeIS6Uc%8{zP}j^3FJqs9DX2Pbgkp!*eV7{`ixbR!j~B6rfCxMkHAJ0Ph5NgekI z*sc&@X&8@i9tDr6#sQ|9g7Co5wZ>7?ZO|H}Iy78RS;pGMCrucgeAm8QLT$EyXqLu$ zvNX0Ke6Dz&@K`HY3A>d3I;c@x{m;}x+bGO`9c%`#Y-CsAmoztEU`)dX98~u^@p5Oo zRLq9(9eeE}3@}rbY5ED+64u4p%NN1skbwa|yFxG{td5~m8bz@FJWbnW8hsu3mDNC4 zVxy{oXrRmxB0a2B>CqhyXrFMOouctw7dKJBnP>=w1zku`RwJ6lfaxoh*KvT7dM0FL z65%F*F)KwFg+@@ywC7j%7^DI=>X}eB=t8H~AY&6)Qm&?8(!&&Up2M_rBTs7Agu!m# z11ZBe67(xGWVjn1$8BWw$0)%9d#(Oaht507QlvezWAg;wpSZU-oEu&%$UP#AbMgHA z=J~n62^svy$QV8Vz^llKo&AlS7Z=YS0i%T~1|}_o4nJK9_1#!oENB2wRtG2}kLJ>M z!1aJTJ}a=8PGU<m<RbUPEL*A$*+tPGj!qA@C0)znx)6n9k%Ol(gA<<KvE3}A`b6Nu zPe{|>I7NIP*@B!I7$Q*dhOx@K&=t-wxh%s=yu29+Wz5bgh30@n4kYkA`o<tW+i0UP zw0pAmlO(3cRC$q<u&T5S038(dZ_90+qrZ;j%n|=I+nGS*zt3?DmPrAi&LQ2L=AfrT z3_*IpHK{?wSf?FgT^Fi=n&~j7rfXttC@N_oh`Y3?*J3<j<Nco{;i`&E@UMldX0VS~ zn1P;E2z-qt<}`E)9*tyv1X5z`fMC1XgdCSe7&$1S?^Iu0>RkjpL!(SaoupF34G@)H zk|CrZ&0PX!8p+(0GK_O(Z0**z+J~wU%XgjlOKo1_`eX)|2I5YtO{^_%kSZ#+=zv6e z_%1E0P~a!LBk-6#Q5Jzs@^snB;3P+#_e#;cEY8hqZ2_e3pO2ppV4MWd9{X_JE`G%P z>i+6o1<JI{<=ZQK7<x~s=O2=5avT3N;ikZSjfBI`ACq#l312Pg%u%(pGmafj-9H!q z^JMTysfV8j#F%{Jkx?OhEnhToR-<WFrrUjW{{Y?UWbU^poJ!)%>!~WM7mM!ffE93c zg~}yVSK?15z$qn-A|~c_lvm0e%8S&&bDbdv)+cDq_jUOLPX(qA{$54^9fc{7TdP~W z*siQVS9c@bq1-B0QcT^xmqKq2SVW6R-B;)c=AYIQ7ro0Ui7AMTrV&6YBeASTj0E1R zSVXf%gd-wFB<(PF-=a3P&?gCC+Pf^8$ry^vQ%WSk(yCsAh00L-WLhy=hNqA3y(z&Y zjHFQZYVXk-NVyTlct7KEsXXy;R+ulF({sa8IMSui`tWG{E#sE~QS{-7ioCYwj|7&5 zW?^1Lvoa2ITnxQ?2y-Ytjstk`FfXMWHvaLD04>9Oj&IZ(NJWE_yo-|ZmS(uJ9p3gF zk{k6rn(Soch;jrKvC14s#Wyj|F^ax<y=6ZM<7^o+|A&hGL<$o{Vzd!#jYOGjmbxLz zqubFp!7KCk*5+s{*w9%Sna05^W0i4EkkKk6ZlYvFFW6%K*5(xK3_S+cN^j_bQ@sk= z?dz?{7WmeONx@_Ma`1j@^K{5~F&mhmqR<KH5Vj^NS7z5&8vq&5qH-(2MobeZ65-H} zR~R)hDp>FqUs^(iS{Q_rWs+48d#HH}&YB8{<zPWCbgH0wt#TJL>YNnTwQ-R|3p;v? zRAN$Jt(8;`XovL}Zi8=Jg;ueA9R{KIQRz2;RGk*sZ-<RuIxj(+OQ_nvxB&MCy&;Qg zz?f>Y`<+G4@n)04VEaq;HZ>C&ISjUh$i#CZ<yB<lIfq8_{O=izgj0`ot+jbdf2pFQ zXs@HGqbnIxtSBbIW5y5q?9-=D=I!^U{P=-=I7Lz;8b_GB$cRG&fKG)9_I~U26?Qp3 z-XkUm9!4EZ?7St)QO#kQIVkq)w9H9fU@n(Nq(Uaqm#HX*+T$H+Q8cW)12asg=hC5d zLx|(tbiOkJqe5HWx`%H{%s~_bTs7LqK>Q56npKJg=IqUQfBk3-@{#0z9wq|)BUK#F zeB_1RF@nY|!Z5yAs%jd!211dN?~1_c`;zO16<se#eXF~n(d11Y?nmH8-oPLix*oCp z%>~8NNyPR{s@N^?bu@zRmyy_CCjtO43b?0>39>xJ<O3{rG%^50uU>C8h@eGll9br^ zc=tpS%nwb1VZEnfB&&3NeeenaU6IjV4QPW@7^{gEnoKYa`aSgcrnhZyT%V201jykV z96gq5g>6_&SshqUshwVfX9+yE;|mBRz8K-H=N*7Be^t@z*~a#TnU<pqbo!<!kXe=X zmJ^TEu#rAvI9cf}*A)`hPHf7ZK-Fh0l}W$61iNU;W&74<?=Q`5ckH^tz_IJE<XoYZ zk+A>;4OkVgb_3m#KxcQC_NyxDgHTPzjPWGrjhpt~+4(%Ucy9Qk(htS1s<_X>L6OU< zDU$W^YVWce<JQYH`o=Mnf-ZBGl{pA$E-;7Y!O4d*<3a{8Wo;-1UYS>zGc%x6^$i}& zpht#vY1fpbA>MkwyLUAHG}%8mes}cO_Xi(NC#Sn7KOT@27rZb46=@(XYs}Xu`#Z&K zNi>b(sJH_%q>K(}>=ot`L`aF^S%`5KJ3U-QWdyrSRV|V_2NIB2#*WUa%v|2+``U7F z7tXctm@O_<iEYdOsLwW>UDLfo)mermx?p>DF32vDm1yn8H{qSYd^no5g}#U+sX^Td z(wR@S{$T?|eXD!UL6@v(ix%p>mU2-RaB37FLLWt{?ZEcN0k}bgw9LjlKXMo81nh)| zvN8<MIitcOdWXS0ol!XvpEm%(ij`C7B1Io76v^*Y<E4wTNSpXzpC35}mw+O}B)sJL zBdUEDs1xyqh_^nbiPzO@Ue@=3{Kh=LjzHO{wvTF!v?|Y;xm9;AT*-r9b$~NO8yRn} z5$CdLdONf)G#llIuE-u=hSy-O<n0Jds{;8e-`dcOnSFP~@4i2#OhfUD;Q7Z$MAMk7 zefVx2o6p5F_j?)a4*-*1`1gMB?1#a3>*^OqVFFny>A3z5Gzxx5NA@Y0#i`(q+o+EV z-&rK?1)j_X*Wo-fJxcHDX#(iW?d?3f`lKwrN30}AZ8up?3X>W!Yn*G$y*yg0E@(`} zZLgK#^?hR#p5rDAs2&DmzJce=BFXdtWpvze87nHQFIPHi3NY5)%&n4-+!j(YBtU`G z!~scN%`+3w?OrYnlq<l|_h6eN6h#e;1QrManNj_qmbs(iE^CKO`{?ed!Jc`;!-J)G zK|9=88_?9F)jreF%=>rRaU~khNQFVs2?YW*5<fcnJ?jX6>cLi3I=*0(8U_Q$eCTC@ z5S1O!EP2_<b85xZ)qJP4{*aBMP{8+tpj}U|Sk7i$dFY4su?wUOr#u2GzWOD8JX}Qe zYrq52uO5aDPyyOk!ZqFbN22}p^VC%Dn5*lB0P>DveV@kfQX;+m6oY+N_{L#9sd@*h z3jT<lr#adC^kdj0P+D(=E*>W?xTBZ_Q)Kc@JhDG>x*6zZrHti+Nh57F(<rSWz1kR| z4NLKJy#9sn&Z*y;Q`I>&0;di@IACkj1m<EsjB~8QTY=XWL4a>Od-iJM!DCbBd(UQ3 z0*WFE$9t5@!LO4lxZom<K0A&;6Nb`qr@hj3^T)?~9kIH4F#i1%c|L5`d|BTgS*s-K zuOLr*tlA{Y$?R}gjd+2PoUs0ih)z-Hj7_WNTEDsvETlrcV>T+V0&*S}q4Bp5@O}DV zJo@#kQwMlvJON8N$5#?4;f=%edlF1tjII%aK(2UU?*q;4dr!qSqdWeDfMKGk_VePY zpeTgsQ8xpV>H<EdPmHY0eguXUC|b0d%&bH8zADtmFr>b!q~<zSfxPW%Iy>((usX}j z$7;tLLmH=H4ct=+A@d%$y0}t9ao(gc!KhdA87Jr+%Re_`TylA6MD@xr&;90H{IebU zuQiZho6ufQCQ7)eonQMuP)h>@6aWAK2mqM{yHG?zA46hU007i!0RS8T003lZb98KJ zVlQ7}VPk7>Z*p`mbYXI4X>4UKaCzOmeS6zBvN-y`KLuAlIhGPxYdJ4Xee2%iBu?t5 zj-AJLHtD9hDkae}H!`V1QgPhf{qA?(0OF05oV4fO^V4o)i3A1%U@({&3}!aBzx}hZ z8C7v{na-2J;&x;6kAe6+U)&by?5c{o&wJ7C&dzRh92aHuYFSosGEU~v4|DkaUo-W4 zFin1hdI$4)MD@z3NXn%6oJ<EBoABaIQe3BHndVs(rDYUdB}Fp6jb=rhRmrp;MVCdA zL{WYjO|If%mcWxLkD@rcjTT8!<{7}q$5otWX*P@ED4GC<SUjq(0A872RyT2xV2x=M zmt{UlV*ngY^U3l$$*Q<Y2?mZ6G~cbRpls({s&#tOUNlYOIbfI}Tqtp_;YK%Ub(JqG zfB`+Ligbby`&f1|UrrG#RV13H*D1FsU}Q+Jg=Lxa0S2PqkFN7+dWnA%>hfYao~Pwi zKbof4!gyK1!xA4(k__r$=l+@(QJKu=3?s$P@F*DA_IVhvxdo1U70Do$+{>G*{2FTj zjJkt3E0@b60|a2)sN59(D|3JbIQ%1-RQ!~hy3FVE{04eWcx2NQdt2_&Twg$ec$|Mu zsFzGeQI=QG3&sm)j4@-1kay)(4CE7y5icH9Km?`&pGse`^UE>NTvnwpQH#8wc5w(0 zE!7*Qxr?6;qw~|37w-<v4x^*<=*`*b-;Q1!zKA*p=Mg;U^rLr27eAf8y@;U5*}=)h zFVX4C=-}j+DEj&6<OR;t;rlmdhv(<f=~;C2`pxmt;fsEBbn^W8?Te$6S5fo~>Ykil zM8`+3k1hc6#c4#%3cRDkbASObqt}OL&wqj^2hWa<k1l?JF@1S-ae|QH8vu_EqUg=R z*~QWGx5o$YGkWv(?9J)<A-p(w0WeNZPmWGro<XCBuMbZy27v!b1W%*r@Ne)tI{)e5 z_?X*{4&Fki&HysNeSZ4pm$Rc+KV1NfpH7co9OCn5hk)?Gv*SZ<n>zgb_~7VuKYDTS z`ry?e*F6PjfC?66qyfgepAPvcG=BgX96Y}`Iz6E-K0iIVID_AP7=^Qo8p6Ay^F!$G z!P(I{pbs!!o}EHVIP6dj2lfQ(o*XhLoDzHLpa}kcdyZdmJPCsrhX=<1?;NX}#c}R0 z3n1{(=yF*ti)1v4(rcuYXi=nD1y3_tyBiywPUkF%rx6uL%DgGkDnTL#jtV4RT*p-u z7n7^>b5ahl_{PR)^cj{CR0pv8QRhF-lFupr{1131ZzBA_yPd)JgPji4h?l?@3aEfj zH6Q(TxwDfzLSEYScxex-O@V`9C93uxFW}c6u;SrxduMlh_i;4*Ztv0V-p(+3umcP_ z>b@+}egw~7CSxkri~a+lOg@+Cl)xaAqv@WpT|`fxK7RVd0{WPN{yn;ej&H-Dz-pQ& z*W+a|6L>`etG(pz(|+(dk51C$I=M}XK7N}!{p&|(DRT8`bdlcxAIqi#7_3cmzd51_ zD$R#7XXS0FzUKNHG+L?eNl|3E`cb9VNnNN|PINJ3Me2KzY;07;?cN5Ctvs6*3t+%E z(~acIBw18~(P2^K1($;Y&|@e8|DNO-fPfvT9F(`$^ECSu!L+|ivuS=)BAEf70xEhk z*olfbErD^J<P|`KflP3}Bd{A%b;K<q;p|7<gGx9*mFb5n_G;ueRipGG>JA?cAN61# z0**OOxNTse%p51cN0S1WI-mm_H@eE_Q`!X>(0TH_NPx!9Z?DHW>^R4O+M6Q%43siU zuuuGrO8b~U0Mt!X`aLy}C-HS+4C4YeXB;|Ob3%z~4({Vxna_!|K6EbP;w8KUE{$K0 zvdbL5rsYU#$qRzr`M9wG-2`G8sO6bLg%3L)qaUJ&)<lm+<7GOpQe41s8Oe`w1IRY9 z3hFl-qkNIz<ftbD`b~od`&1Hb;qNWnK?P?ju<;GT7z=f{v(jEyeha9Rx5tQk=hvN1 z6#8rub!1E2Wnq=ZlPW1To*kb)|M~pr?}t$J@o+a#X`W=W>I!$>MUhVu*vUZz8qf2| zr*h-$@cHT43#nd%x(}Sjt6e0MyqK07uTI{MVDCA4PRJr(DWb^0c@sF&ES*HNY)NB- z5)z0Xut^@hcPsw-Wd}YTv)Upr(=TSljpM_UR~J8xP7YopmcyMLuZ!35m-KphZ6F(y z0GR<vtLm@^{d|Y&xNOYoAYHsXdXE4eKVDfK=V?(Sm(Y<*V6)Q=80c3Qzq~o5o`<Fv zh1J<|j=LG)y>Vcc572{C{P^T&U3wUVPOPsBOCp^nYBl#Z&VPBW>+J^XmBM5Qz{c~R z&UE>Q!Sb3gqjHf<Q1qL^zB@^PPHPk&1*;NCy47AB)h#{_R-2|km{nffZoE8td8!LP z@e89;ahba<pfsdweHW?)i@Qo^%Y0e#XyXdN8l&UWlUG8O<IZu%r~)O3gy(rSBPueh z2qlg?KQ~pO!B$nyLEJp&HqJX1Vya5H0I?(y<lg`ELU-p&aKvaO4u;zxj0~gXO9lHp zY(7^YU;#gQ|LRy*pRKMwo9AN~OR0Q*dW_QJ$i(4&$E<vw1JMHib(`IIdwy|nHUcU4 z^}z+ya~G-6?(qAkPoplekDkbW#FKR0VF+tAR#M^3!TY*`&o$j{b{Fv%-Pnu6mj`c; zFY5Yr>)*bW&^G&rY$qVUBdqFn0dhoj1ro9XUoICU#qDjJzkTxtbb!MbBb={ulxu|Z z^rHj)P1s9+!yl(eSO_R2yi)s-T86>mYPIzv;U)b@I76_wyVClRyO3I|@zUvS1ja&% zUKPnwXo>))Z!*;Z@@&-c+J?q&yzbx{NT5CsYqwH+hE1dcB5U3HoyQ`G0PIGk=uy!0 z7g>LdP7Wejfg3~|i69rnO3EGZk~um&enHrD7IAfjk{$9Y^}S4gCu#2*#ruvsI-O-Y z#kVv5vqZ*7zv;^w_~CHHmzTiqVZz3@(bcrT{iaMR#tuiNMiCx&!)UrKn@yt`BiL}Z zydHzZ+9xYV4zpG8-VSS&-W!C(f=ek#y?y=c@T^AbpEN3+n1*OCx}4{6#Us_31fE?7 zp5Zv|0jBEr%=t~zKo2(l{f!*y8EBAb3M2atlIV3lO}OLz=yN<@CNyOEq>AT*Z)xg$ zboBC=_QjoixQkL@&5CUy1WUsD<B~geNlPlig1}s;;La1fAPXBJ0$@R4UtI8!U9c7} zuoN&YF6CfYi#-NN;DcOvXctB)WMkvv{O!?;D54UNc1)>s6G=D1x1g^jUy{j^tRNTX zuXKgoK!sO+g}+_AmkL9tf-?F79&gVM4_;_IBD+*f3oXCNV2{3d`|j-M;!q)Am1KjA zQS|Wr;d9-zRg@7-{#qtzu`%krsu6)%2qH2o^5p_b)`;xvHXx#k)`-A7tUyHSoEnJi zJPMBpG5{!PAhNR?Mnn}g5ZM{7K!odj+tN+56m75R?_yH_dRU;a=j8x-C9d^uC##To zPJnZ=9)5W8{FKbB`@oy3%k8HfLrFJYqSil4Dl+ZgmKB;xCOKN<yS;Dh>v;~i0h_v9 z&Ld?u{3hXPW13t7AJ4kL@L8|xM+)0MnzHhul-_qbo#%N5TPN%j!urvs6qBaDU7__n zi+RVY&@xUI`hlv-W*Quv0l`nYUNcmrNUCL#MdgP*M(1PnAnJ<7xs51x%U%x@_mj8B zj66t>i2OQ8w;{@1;cnSTF9_+&G@EuwM`b*LRu<7;_M`3Lp5Fecdmr`|AFZAYrb$D8 z1^=|$fGuvsyazFMi`(i7PbcVwjU*j%pxA&r^i7V|g)$w36sB4&QP^^z_JN-&Yg-C5 z&;vnnp5F{q2TL?pK_4eqMVDA%ukNe1_^A)tqhKfQ%6xR<a+0PbEYaCir-x@HogH}c zw5KbIN$zjB!5TI>^&xv<bd<pcoKAltL4`_nJ1IXC=|$$GUW^K%9sLV?pW?DE;%t_5 znUH{@hCR0%Km4#CJ$0Tv*az&V-SR^U<T(6jk!r^Chy$46N!biUiT$U25pMTwEh;q8 z*0ic6RnL+;(WJ1UednQ45{u-&m#}@8N_ImSW0`s-^2>tFF9ixoGJ>rfp0Thg%LLa( zpHIeOd|4_fXt@CJ0;K!&{{1e)*dF$J+rxnt?WIx)A_caqFq@I|NaAKDKuGcgYReKd z+Qr4~AUc4B9@7yf@4$!*%-uAd#1-ijfEDT!=>(-9fm5$9l;8AuV5IPq<xawNG)`yR zpqQr`iy~Q|tRM%o16WSso=4r?$4}f|s|B+Y0qp<<MNgyq_aiCe5LroD#l4;Tc_+GO zmgz@Xucw%!ET0~b8*)0Ix}h~W5BiI#nByYLq8~xmfBd8whk9+*E3ex@wFt!T8(bwO z0iw!cG>iS)v0-gS@87?V-htGdUW525G_X|y6<)=k(|lRbQ8Y~P42Jh}tz<Y*XksV% z5*Qw%cPc0mh69h^@QKP`nJwbUr*7vMn2S8(2lEaMDzLE)Yy6QC;-ZLeyS*j`(Kv49 zAk9Fgthze@JNi$c(1+iB*K<(&@kf(~m{pjMS{nrOk4ZeAj3!r~%H?(09WO5pP62O# z&ha1+Pff0p2^JE5ex2Y*!cdDI2P+s}UL)ZHy#fI%EVSreDz1wF7$U=?jppVm1<?$q z!O-*4O9dpYqMMk^gL8OAb6UbsCnc=e37XACC@_`$5~d$Y=(#RYhN<w-v3tJE=$P{) zd4JKP5#W9bMhrilWzZI)uR$=9%Cs>}L02wd>B_;9Y=fjSD|HSA6v_}p1q2^or8AI2 zp;xF|gLD<$BnBF|k*eW_Ep3?zE`YM`3_Y<~v??dF8S!F#fb-IID0cYh=`)~F!0y8y zeE*2+-6`_$@e@^K`1r}*<Kgbd9@EcVS{biyWgKorsMP6H-)>z<IA7eN&<he(w=5>G z8J3k2EBEn;(%k(Px9T8)`7+r;q;>?gk&M(&fTI`x(WR=FmUQmfXV)8?PN0FbAhTix zU+q~*b-n$4lYeploFW3cE(H_^!qi2vOl)od1BQI4m<&*3>JFdWAMWfvve^Oh%p8yJ zF73KhAF6$_o?>4~ry?fcqDjA>y?rT1Swmp*5w=Lr`LL@GWv^q{ErH(mVR3xE&Zk`^ z+e=l3iws~~vplYDusf%7R^58M2v67(<aJPjJC!X4wp_FUl64kf!s42CYIsi9)tuDb z`HMAk4tly+6N0+HABUnjGgt$yMx!c5!5emYdfn}c$*0c{U{mS|BkPKZN4?p$-#k0k zb;kCa7e{C6&D4JL{3rcpV!t_hd8*zlIz4zL*s)ziUPT>{rTbD3-;v(0>fPAyP|^Pv znRigiuUnHx3gWr(hU)0HzF2s?YQf`G3m&fok5@h(ubS|9)q=-q3m&H}c$^9zf4g`O zcvL1H^hiOxFy5Sccx;GTsHmxn|Ae##ECAa+*(nX(RhigPI8;=-UEF-(|7$M#wq$8v z`3KC?vJzoP>%E{Tqu;|v%`2F&fnV69UN0wNC@JuK+<R&3wcq0h)+FKlpS14+FNQxp zU&O`-@nQk1v5UZZUJ09X+QP950auo}nRPmYf8=S_#WFD7lX+Z{s|2%vL*+zL5Bswi zScG;i8R#KG-x02T_@zSeiXkXaHGo%1mK30H)eb5+RtZ-UgFpx@x`Q>rJhWgfGvtCa zL!^HxFR=j7=lL}%JLr|NF6{VooX!dOq^=CYCupwIU>oNsKVGj3UQX(OCUcmRSbQim zq-lV%Jx@O+id2KGnYIDHHGB4`Ns*SD2mbJSQQewgjqgqUNU)B84gv-FAwv~*dPl&O zs@Dem@bu+f@in%(7Qg}f%NoFK3r(0tmg6${?<I(8cZ5xTy6ASDO?5lYNxRcvtBsV5 z$e<Zzut1sO`1d7fHtiL;AEV>^<~aGB%#l93Y)`CFhnL%Pe9HqZc2Vd&A5N30U3CUU z3vGae&ryY<sGLic6&mHqYsWnQQ3gyL7{(sGi3C7AL8D473DXzcUq&Oen~z4_GMQh3 zCL3QT<o=x)@*nYOb&{t(up{oFnf!Eg_Tu#9_!nD;hdoi=zB|LW(ZBfDbJ$cb)Q^j^ zw<pi*djI}_4Sh7FwyU_r6WMN#mc-N1v!j!PvtK%nCQj)6YoB3qky_=3UJWkMH8N-K zxNhA;RKlM;dD5!~V=~Xnghs+>0xH(e0hUpo<V_wpJcI1H+630sWuU4Qs{ybGDG=;7 z>sMS+?@uFUsUCejr?+H9qqDA(41S<kPvZre+QvzBlO&nqpQiR2TMSlFCi%<zFMuD< zZ&l4KNv33Hyox_3M3B&1GVwD0J=q(0iIzf#iEf#6jT;cW2PBIiRnLA;7YJYse|N2I z2CaQ!&(<sBAcP^Cj>d^>t}*(l?$L2fS-~2sO%VJfUxKItV*scm^sR~)iJWXkNi`X0 ztC5U7VuGB3_zW9aX>H=jXcjWRy~}dzQ%})XqOa6lQo|j(V$qM4c0g3&V;-`oHmxNv z0=B5M=zY>(&1I(Ec<L^G>S{KBGgyUf81vhE8G~4684p!wQSjTkzvY?{4>J~EKp{nE zFSO~HgfLC2WK!>nSBX>IW8Mw@;n90j<X>*P^4RW6ji#!G2YTvh*D#1uuj$ATKl?PZ zbkgBW1TiZvf?w^IMsw<`!^s5q8Xx<;5KKfq!SvO8A4%(D7c*E|>fMfm7P7x7y>VvJ zJN<E{wln*^;|uj(EnS-(oPVFEWAA;F`@8#LHQp0#I|vkqe2J<HJDO`@w&SZ6)N!h_ zAI67ArkKck{Q7XW3#018QmPIPND&wh4UU-u^3c)j_pT4f*KPvUiScs%)~Ol)zWWt( z1GWC}sR5XGn3=UlbIOJxlhC~~lWRQI1q24q{=WMnQA`G~y7TB;pq_^S@i=)420QFB zO}`y;{fj^n;JdO^9Ttxt8hmpjnkIAEhm8Hjkhyq=>M+Dkk9Kg4DnH$8K%i@gI1W)d z?ZHNMr2IB`yB5)xjs7GH7@WUlhvVVb%XXlra{Q0(_kH8Vi^G@42N#Dgf}WI(pY0mJ z>x1{Bch8P4&hG}n!eI3J@b&2U@Nb95cLTCh&pA5El~v5$Hcz{L!1FIWg2xgA{HNRN z_3Y6ajl_D{`E}>vcfalqAO5;C+`<1k(E|hY1M<h;+5Pq5ci(j^gR0)}1|SBNI9uJ$ z0NA~IOs4n6{rdZdz3qp!oWB{Jy?j3W{_$>9#<wLNy<9KL3MH!O==^m1>C?yGZx8h; z)l2d~H%`R8KAD*DA!=IY0tOusiexd5(VK@4Ro4*5f!N-Wdz0AKN_Doyf<~As)flz! zhsHKy&@SyIWnaH_W)HXO2m9g$)7;=+pusA3d1R@Yf)%4zi3!IZOmiuZzH)#NwHR;r z0*B9%8<zS_q*7LYZ$+5KW<a`bS?$Q$VFXJ3ln-WTMC5%h`q2`K0^_dOsX;e%IA&J+ z7~ryU;-Jb~t$bXePLieu&uMrZ`5mP1+VB;XSE9z42uwjfM~hero8%>kw>NPyEmsg= zfLEKxNM>2Rv)*)w;jcwd=7cE1x|}b|t8Q=27Q8dDmg#An4|k(qZvo<muZCyrlR!cr zuE><sXMNiHaCaLm)u>d=@IvW$Sp@*$tiEAKo|^*A&IL+N^K_C{pc_u&vQn25$X3sw zp9cWpy_f-Bo$upx$Ex{p{-x#_*YR!CndkW@?NQ-5p_6MStqod^$cV8ffqe2vgRCLp zeKdkJ2n`b;{W(uTl`lTg`8|+d#$IIwU)_&><GtuNk?6?($<e?VR!U=FwMl5<VSfH4 zDgE|CMB#0GdT{<T+WB%RpI(E2zZNj$whGuw`1Bk<n3dvNP;?8bSR%JM!jn=6R?1G= zglG#+09duYzWg*zObIF^{x~~^A#NL6dli35GNum1Y48gEA@dVEbs!DJ^GezJJ#I0g z&Ubfv$a`vG#aY9wSkz}E9nv9q5a>p(zex(<p#}_+PY9^5t(d12{vn9zBy~BDXOVae zT5WoJEj@o?(-qbJ&*+hj)t5Ql_zl1WX@;D=THDiY(i;TU3$*#vZnMehfq*HZ(T#-^ zHd-STBm<c+2wh=4%0A1h@fkk({~1ENfd#HfwO+neGM@)l?HL<~Yx!u4Z(0H$B$Ji! z!zOh{`HKl}s+%j5<dX<z@O*#AZuLB=TAHlLR~RG^<(h}Ui~|JfKRFMN)9JKHHbZad z9KGc<<NR^obrNjxPO<CuE%D8sM#oFfb6K%wrZ&L`Vbx^<t|PwE&wRl=*X+nxMPt}G zNFdX84ECor_)p{HIcEu`pOjBF8EiFFOgU)gm!|tvNHvMbWs2$ua?om;VT>ceiFRIg zg}*dFm=M_Y_3-p%v&1P4_;%!~b|O%pwsmaC*rOE_C`~syR}nbR!HRHFo&la*$;~SV zfvSxld`vA2U5zc^&V?Y1O~3hAsip!N=M_`FQXBPUd6PUxW^Z&U)Ks;aHMKg!(>aNL zh<ts^9HdqAc{fM7pvBT?4z-b5nDJ*?Sual;ESH{ep-!3&@oE}ZaVNl4rlJ<%{F*N( zL1HkFp0XZ_`e#testbwIsj&?a)K^iIP!n<ueJU>Qvv{E$$;eVR=&D$p@l{d2Z@3m^ zS_Jhq^rU3lKa{FWrS{IV*ED&q-Jo&mHY4k-*E#y-11tCZ_xu_e_yXTaZPGInI!Y^> z&eBxt-jP~#?i`{;<boD$75}=w)mweEsm{~(>>;R6-<l4vg43#FwXAjeu6Ohhtl(B` ztrzo%&$o}O@&k;>P_gCHHlw;WP~~kl``zcq9-wD`zxsaI1Od-%T>OcPuP{0VHBd!l z22p83d-nI;uc9*az9CLwc%&#SL~SAh>lAy~7qS3#ZumQrS1C7c$W@?P;wieS9!EEM z@hL9yCDh?d4@Nvg5C!XFBoJ<)1E^-I%8V-C7w9fCau%@k(H@?A0D~~GtXnqyYvN)? zksF;Qz#=H}P}3cI#p>`}ZPr;M;*R4VAB&kC$X6fW40J;s2?9WJrCkp(GmmWOw@di` z@t+oK%mZW3%ony6{=Ul{Tz&FpkuGUCJ8M}0eK{@IvUO0m25b4UVz>Gd+^vfEre(KM zloQ;qpz2!J1waDPdkgi^6nX$i!=S-VhE;7FgWBKljUoDd^A2}sQP|dKZ9a@}e$XHT zQ!Qj|J)=>#)yx(8dZWT-o`ujr?KSq3$1y+*GE;h<?1BLkB~4^IuMZg78;MccSH^m8 z2m_64(L`+#Ek2bPr<7frNw6@sgyt#&9eMIm7IdUM!25x<d0lpd7(+p%C7m6c>>9Tx z)iKz%KBrUkjMHIg@Nyrm9d?$(%cW3cDLa^|=w4!9$=37B%MyLbZ~^prZ@{>Ju2#Pe zyJt{n^P?~JOWAOIPakDMBIaz;hQ=kVrPr@PTgQuv#F##sCSB73?K)ntC6~t#=Hd6G z$YnEh&S#<Q2(2q$d=Dc8V_64)2r74Lfwep5XU4ebw<r;qqfQcm>Wt@eA%ps(YN)|- z1b8V6L6=;g`l>=b#WbaXwPV&r6GvS`8h;?vA^mb-sNOzsX4f7a3zRv{s>lyDodj59 zTmN)D-9?Knqr4YjJruyx@E|b+5LL?+Zu!=*eL8@YBs;Vz#>vPKN47j%OfGE-3xwsJ zEV7ejK{}FHNAF;WO*we4IY{;1l^PdG1kO1Wkbn+qvC1t~j>i>h(p}qrv+LLqW42h- z`gwDMttLIieKaT9b_PQg3<zUf^*YVEOk<5eJORX%@>uAiYCpP$<~Hjhb{{W^!!Ce- z@`YZN`+8-3u({Sp4+xG8LcrVp_Qd=^Fz;fCT;W_+^G@Ig!(chR@7HYB5LMx6z&zg2 zhRJpDqb|&v(*^zWXUf3`M|p)O8?6$}#k%$|Zu9sCPH#<j152W2R2>UnaBKwxMxnhg zJ@hGbdq4Qf!t#Mv#<b*k^32ADzAA=4Pf4`!gdBWj`LtW-yP3MzCHMa8iz1~oZeQz@ z3uZV{-JX3P+R|IwR91<mNMCSIZ5Crp;Z4Q#R@*=$2^t@1Kz8^Mt<}5KBMQA!1qvwY z2;QPit1=YU)G8o)IB2-`bA6W2&eGO98E6wz#}mL3+^jcZd^L{P6~7Pd#pW()=`1aU z4e#!@ZGPR&cFnCQuA=L_tb#`xL_5yGl{vE#tOZYUIR*e*q33hn;FejH&hflTJk0PG z_g6Sec_C7c{(5RSYQg_y&c)fFWy3P;ewXeI^wzz$24~a{^Hz&c%(u;q(1Pk}_F>>= z1=I6wWltJ;_o_p-U?mY5lsUn5tZ}$>yUBqi(F@>~N2l*Zy<C<QX^4UVOo#eH6H^gA zgRvmHvPJjvG)qj{-yQ}iAAR{GRt1)CA$y^7b4b`9JKI*SU-dbz^1>v=Osy_c52n$f zZJaHl=>0WLSpP*^#5}1OqyNdZVyJdZRXWyMMy|R;vwbS;xfX1q0XIu-crei{U^|hm zdEUIXiB40QEQ-Kck>D#QPjs&hJ4D)P(^>WUBjL0X9+kU{kdKCG?7U0@7w~EDNT&6c zzY`a)23pIJwE>Rc_^b#D_%=qL1ECJ@8yeSN`sTVVn>9o{b0{lWS(sCbJVtP_QN<=b zv0Tm__lG7@q>0(Djg`blf`(yyvlq}NxHYBLV=1rKT;xyEivJw$a2H)0*;<lKlKs3K zoF5+kJUTzT_;%I%&*>LHWn^*T8u$i`HHKt}>*qTD(xuMs^bGCU+(Uz~pT9lxqz*O| z1=xnyF0|>atw?ZKL(mBIA_#5$-W;C1STRz7v2KT$lGlcXeUrbJHMimbqD}%kuFw$_ zz<jkgWae1!-hdfFAV{pXBH}m|kJ2hB{JUQio}?lvfE;qsp!zu}bc0)E8<YEk7@EH? zdkpTD0@Pt?rCpnvbnrNW4kE;7m+r|Y!DzX41Q-kk@9E_D5JN4(Y{hfyNEuTWv6MJX zsyLmOm}hQ@W2rE=_4Q~5-!l%giBVcq&^{D1^zf>f^o#~atPCmlv!r6E-Cp0QYriYI ze1p$;Axfyc0O+dnvZRCeXd<Ei8gI0ZM&&%0lv`bOz}!K-n8MCm;qTjH<s(!MA%|tq z^Fjr&S5TcG_8|b%<nwj>kG#NA_&v?=d!Qg27O<FMV!)q^_{&J*h7itV7YKqday^Z> z*oY5BsN#sSP*s>PQgerf>;L<mj<d>*;}x3(27IeLWlGBzLWq`SB8rsvrehiM*@GB3 z^riKPlKU`yHd;G&@+XfT>C!9?=!A)-T?Ggra#EXYqCQnb>C`Sc3zekk<X%y+pxB|! zFO?P8!5L}IF1*RPEir;DZV;50&8nlrDDD__WPPe2kai8Zv9D4XS>xzm;a4<G-lYmY zr7QBseCZUd2hcA&3zg*|^b4z%Vsvv;1-#%F>{sm9!Zj7FMK7e5T}>O-%@IWkH8>x; zKvDM9Q00-hH|*4vWk;eHW^IRBI8_j5##3#}Lz$wq=IW0AP%{Gn@Xvo!T_aV7Sy9Xf zN10K8mnpMFc68GGOoFUZcv8%MH<kLFzN0QoKL<7Y0Cs|p+6;1fvZ+F8RA7GNnr#g( zKrgU39xN3oy;iqf)n;D<Gx-_3RCu-_rL&8fh*=f;Is=)Dps`>qFsizXta{$J8nKu# z26^`7ALUQ?!@V-PSD@kK-sYDdDLOMDG8)mAKN`U|#9}n+>k;gyY$-5LNdXs1_Sddi z35y3(*12ama!)knRK6GqJFJlKDZLYxiRf$3o?j<66K&8&5sAaMlYa*vr!41QsmsD| zr^L)DG4o1DeimKAx6kXeFOkW)oiZXH>_rx*b_$W`V6;UMb?hQ~74F#t=JvcE$(k9v zeRs;t0%f#RvS;(&Krs?n_H1UWOa0qY8Yzn;_x2+yL@IHdiqgRE3B8ZT4gJ5mhwo-N zG?YLIPwB=ohOr<A^+x%-gksy*Nf`E3G7OdLV82r?;mZuf%A}mci=@+FWihq}J8V5A zeWW<>u8&DzY4Dt=W$0Y5<EZH{bY?2H=Gzb~438)en`{eR1RF>>VJoe5Lv?uemCeku z<ySURXL?)NNWH;1joeKgR`($o2UFY)jTsY8L#LXUq;kDQQs4}nL5<0yfe#%@vWZJ1 zG7@rHgn*_&E~^>CM~od{<k4I;0(y%=(LB%T?zUs(0BJy$zo}dCTEKu7p+(6VH9H^s z_99icXee<g=pJ)WDDagHK5RJ~$&6UDZqk2<(A?=XX!DyV6NAH>QyFm}$Vrn8&Y4r4 zn{~yJ+nwjwJZ>5p{l=L!N6!QpNKn@_nqNZ{>!TDxhcoE4pi>*f(VMK1SZW@&4yhO% zCPXS<yWZ(eQU#)OM&~M)_Nx<kU}!$PN^le3_VN4-&Eb;k&WRDKiOz(>_tTdPNpWpT z`*-Izs*J5txLU>l1K69})Mj*%l$F~2E+ttY=vk79gs)zFnIzO#$y2BE@)j~c1~|;U zZH!NvMF;24kB;<&)IGyiIKtl*|4|X~Gl^$zernr~q#QJexYv)mmLbQ;OlT~>o^NF7 z);1sY<>4-Yn>n^1d=9ka8Wpcp3NK@feFGy0|1k7Aya+<6($nhJKOLj&xY;tXTLT~k zMX%wIL+a8SIqQ@>$Tq0ptwkasMEawX|HVk3WL1*8i*K_OOCM65hHH$*7<{0CK^m<a zT(h4h)1rFFvY0gP-lR+CX0n-e=p1kVM7op#jmner6vq?7>_eQwgwjfes9f^AAbEGi za`}{L&G;@h%pp^uSTgaaD^y=be*o!42NY^WrQ`8Qu^vj#W3PDzVX&GfUM%sHzX%Hk zG8o~2r)5eBdnZX3O7(eE1MY<;0Vq6yj<HhU2DjZCV>+MHX41gBt&CCT=Gr*&=2c{4 zpPFH4_H?55E2DZpk_6A|NyvdXC~I!6wj@@seI2okA^sQHA=nQkwBvG;Y6W^ShYlFM zS!>h9k+yPOuO*&IH=)J#N0#$%_bHR&Q_EKF3AjNc7M|u}5lmQyYYxRBNi2rR(RBJB zKJ6uu+MF#q`rw*)B_!N0$!*V8vJZQ*ZM``=e0lVq62a+`d<rJz5jKDQusx&<dZ1l9 z?hp#Hl-q-XHQ5-pxev&8xlqq=bZD<H%UKG+!ktS1>{db3*KY#4jWgxk1W%3-X^A&8 zCk~Yc$({wPH8qIX5e3y%7SmqF!kc-4heo58;8dF&X>gp7CzhO>+*c{obXM{Pq9B{| ze)Pc_Jj|g<uAQ@_s>PxXY#2a{fiBu&PiobcgS4GqZJdjALc!LWyn&%(z<T9pcPuX( zAyydfu2n;AmaSFB`s@NqZW<}haKHC7WCko}g>w4h0JLYrltR~@k-7&Y+4oJkzO}Wb z+0?_`l`Yw|XLqb^kG63Vy8firN2aZnY&^wCp+@xa<2F;(M^{a^BCg$=mS}9(SN;3A zhf0DLTx-TP0DVa3X3P7qt*h^Sq=bKVgLH3o`{9#Elux#EZ|6z=>khWcFhY433F^bg z-?aqUXy<i{_!i`&X;=QX#ezb8L5f+)_4ra9x<;E*!O?hhJfPY#nitcili&8-U>e7M zWJFxh<YMOF@~+z`ydUgGb+`r)8S9`*lCIYoMXA>!+B8`^NU~w^odf5uxq-NL5!@MF z(@oGOpwxx%&>FjSV{T)~<LMfz|M_pnjG%3OoxxuRfBmmx==CvhFW1_j?Em&TGruDq z{ZTwPY16-p8EsPpN>AQ?!2NWs?*Y;8E=EQG`>U_OSaKvUBJRj)S_#OVt|07EO#`(M zzaI>@cXxK4)}sNGV9UoLdLca&)i789rScsGG2>Hmdjo5<&zdXXlok~DB5_q&_$Ud5 zxkH020y+}zm2|VUmSjYc)(Ggc7c&Vc3aOMVb9`%nqoAE-bTutVeom@=POL(yqCqq- z@(B)cx5s&SK)ntd$i^wjWA0rTtmF)Wtt$`GDgln}=#)XD302p8o3w~Oz+9pc_X4TY zTif5cNHFJV>D!$ditD8QX33HG>d{sH0Q`KM%+f3~lDP4p*aiUACi<Lrc8C5{{hApH z=vNN7RDq7kH+!5tH@;ARxzA!AD-yEBu)bNO(9f8I&N+#fvFE=Lo?D?fv?ob2ohK!Q znJ&@3%OQ2I>OAMXZh#yoSH|Y*!{V{nx2dRRPyTtOO;ABU*C0$wzg3^PuxA-vWP|vV zD&mia)Y~oi--BptpZ@(d+p<8=Env_7({|GVYs{r3w8ks~_bVyC^FBbn%N<rkBWom5 zlwPDgZQCIEsuN+%c|~gYU>_gwC_do(66VJAj<W5bA{ZA_PHoP+<eT^lCk^X}DF7{i zbb2t&E&HI6LyHJ8OPGK-r8**geT`@4hCOM$eY(crYd2~cvF5!xc#NrSWQHyAfsFn) zZq)%R)Y_Z1?o9K3jaQz~pMW-J__9ifYxa)h+f%V226HUS7B6WtFRXuWhV39;0>F-$ z-p`IKtbzSyzm}gvK!XVYJ8pVE8#qP^o8-%^>SEFY#J9BxCk<f7Px5CnBdt(nRZ4o) z@X^z~;o~PCEfk~_`<FCjD!0)HBn|A0<Ehr|O(gjCFi?WwACAuQO0ce2#oO5f#r<QO zo{5#jUsd;K2dh2(XcuA+)w&GydHBRBGqcMKpX?2HA30^jDODHReY7`x=mJvSsJhg{ zC!B`cDpjktSC*?Oz7tQ=v1I2SKK|~b_1<umQ-cL%_I9D%s^MBX^>&{;-rN0tb-kHe z@B8oe9`1g>vYz3As>TDV?LB<>-ABKmIGyT(521}mkBx%0fmYCf*L#l}sKnr!ryz9w z?K|=|5`&-?L)fAS91P@@TQ-VIwnbA+){)F(46vBaDftDkxhv}^qMp0`=s@`iqu{Nm zyUjz(n0RsWvJTF0|AJniBZc_2N>B31WVuLz15%K6+3J?r(#XEYzOa)-U4D{#E0l|s zYzvPROy;@E!o2;l8J%O&Kl0?gO0KEeJf`^7pdKWgniC+iw!nZ?^nt*@C=LAl&B58Z z!_xTH;KQd+97_~A+(%wqVJABDqrlNrW1cJRt*odGZx&J@o@luH(U+9)g9n$i*;uux zhE%mUhWdy)Qd`>ZB5X<Lb@(0?Tu9*(5b7kHkYtHhAK=nTsRh=O=X1jU(NnjxD6Ttv z?$OhSdyl?<>=uMcb?!vq{Sf)uHyZ3~pw_B9ORn?Js1Zz;*)+~7UQsG6fLfHPNsB^D zX$fy#CC1o7^m;2$A6U?8vs<1R@&$XIpvB2H`rzSWeZr$@ShhtprXV4oH)0``AK-Bi z{Hxx$0vbjFYZsj45(*1X@}oUwct~VY2|?{>o%m6~JHnPkGN?N7J-leGM)!GdA1H~B zggsTg=F<8}VAIfR(`}V5u=b+uS|kb#=71TI+?7(pC9eA|*?sT$VR*!tFLR9lPEH_2 zqOxSOs!_ZC!))RTCUu`@il_<m`wA$z$wMGvXM*jBqW0sdm(``7+(w(k8J%f;hB2gI z{YaJySh*Za+}1pbryz&{l>-qlp!+($K{<#Hyob?i&<z9*X0>6@sLJfAysguB@5z(l zAi@j;-lYz)VCyTJH)xCEt91C9l@~UN^aT_zK{8t57%&(dRK`Ns!e+F~O)6p$>S=C} zRtS&fR;kpen{+;}+a){{{D*_+tah$Mlb{NJ%?`27?XB8IX-=9IT*uLMu5xwZ6WHWc zW$vpoAtvqEmPa8Y<WNXwQQE8n)wh_?{l)hhbZz6|;KbsUid~y!OXQmM8dF8dSJ}8U z)xPWdfJKN{1sA)aT{g6b!TIU&!P(LINZzdM1==?QEqM;nUd8b;omZGOz+y4=%&Ye; zQ~!o%8a5#*EKH%`lvJOx{6-$pk~a}Tg2m-u$?Z*3bX^r$&c1CG=CU<MwgRRZRXy5D zOK6|dLf4Zd+vWM&H*ZeQE)HLWHcb#QKcx$s!<c-*w&$rZV#>LP%G5W%jns)YN6?`) z4N2gQwj4TJCi{hg;5(HA0HczBG0aU-2-4d8mJTQAN`gYfK9yLxC%T&(!gh&Ft-&>j zj6{Ftv&2U6HnaF<E8)i+=bU9Cy0h4J$+Sg42+xltioHzK1Q1(RmqEy-hS4@TnkUXv zB^A%b5S9D|%|f_gpa_{U&X;38;HfN22Hkr_=37K))F^eSfQhArrgYpNv#UsGMrC}h zW+O~tSa}dylwn?PFki*${ULO0FLx2xnt8q2M*_|H7L2c14+zR#53+Tv#d8g1S|(#L zUs7=ULb)F`9>l%Fgl3$~asn(1rWZH`so<U}jqFcJ!-ihmswipCMO(qrm8Z!(T);r_ zIpY;ThzQX=@pV}(pDonLg}fivRSWRr#`(pMqrvYE|4&rm>o~-8Yfms}hywcOs{4<3 z%--2or#%X~yQtu8xE_cHtM+X3^1oUP>+FLI30bph(Pu4Z`yfJ1lX6m|W4bh9j;HAz z(8Llb)?0m!+i+6;O}piRdGbR?tfg^z1$tt%NsB8<QBiUBms-Xm!)8~F2uW_JMA!w) zBegD%m~Gy(xWCBZuG5ftAtoRWwFurT>jv)AXg7(<cDy&7G~82p$w-0}T}I2&88Us| zoGX}k^Sr);&USTN-@J3PPX=cCEijXckwS^!mD+0q4Fqp5UT!~?D<xA*I2(bqF-dHf zl*+P5YqgxUZvrD(=;*LqoxWcqQDY_madZ&(5*Qk%gOoRDF3~b_LFp1>+|*Oe$Ltse zaZn~0>83j_I=@aIm`(}Z5C6}v*~bUHU$YJ!^jQZ>3_$YI`4J<{djy>tCY^^;)d2;% z=ni|7^dfZH4g#g*HKJ3PaYBN`O@axPx9}<%j+4afxyAefFr%c(lOuVDT`D@J@tZ8~ z+59%rD*sZBk)a<FFAd(R!5`m>9|F)qTmTy}DXD{r&X3Nb;m(ssPa>Gs9Uf?k6Ugvy z=pdb*)>s&{x^H=NkZ-0jQr2jjwf1%2>><~5z3<6iElbj<#WP@wzqp@-18AVNNsg;A zBXB9VcVIO4%wf7Wjqa8E_ezYQcrTJ*&wa<Ur8m%*)mXQ&wu())Qgxt9X%|-3d`ZZY zsLc@AFDI?YzymYqEDnjJIMCh;xX_srkf6peb<QI8+_*q9rik0Hb`T@fQDE_OVfFMP zSTp;uWcH2ebA_cQM~`|*0{8*_VriNJE}A9fk^mKH3cqDNc1GP^gQXMOONS0mvnm*z zTRF?16vA*&zS*TXmwWtx!n<Iq-UkZYc4S_2;Q7!T6<76yQm6j|eSpwcgozPZp2f2% z&Wd=7InY#5l<6X10n@qU{6^^Gq{3q^95&2vEEc-*(*T)_11R|tBb|{IjSd=r*pG&T z-G@k=V#ZNy8CMx@5@mh4)d8lMaZ<BlVdIK_cbB-RD%f^l!{Un&#MB%>p0}8+$=<*z z_zux3Fn(;I7#I#$&Bto33`di8R<y)Y5VV`bfp$qbMq}85#ng?#jJ8U9MyxTn@u^9U zWg_PGWKW@$+SQyuI|B0GpiJGQx#B0)UYf{)F{lD6$fK7>hsQ6@{bi!4xB)GCZJtGY zI&BcaRY<nGpS9z%&H#nlZ`_z=xIQY!H&4f_<K(Y0^ZakK>xd3vm<@s=KG0ML%7|u# z`4&2@S41}nqE<`n<NeQ29A&bd!O&hKwjExq06W7jj+}iFu<irdYE0b7C+&|wZf70j zc6{VSMzk^XBphor@xBZBMRkT8LaVhn-E`sNZszy3x;9*^Yr|mI?1KRzjfUfk_EU>h zhHBcw+#9oadB-=sxwh#$+N3>rK})2|V>_z}jk|et8SIPrB-U~sOKd(n+r)i4OIQm6 zi7%c{mb{Uo7|*EMCxHPFR<JtXm$<e&)%_oN+4ZF7RK_?Mq2FsCj5tj`kT%6gK;OgR z%2ytJw3tw>6)Tr<!|S%iu8Ja%yR^7&Kg>2vTM8rVc>K@}1Xdt1v^51w#|XAc2{l$d z*WV}US}UTCp9VLf3~ea3+A5}DX)}z5Ux$wZ(29{Nv>r+{^~!XI7f!mrrwcI`mX^J+ zd3J|Qv-|B6J8U?8R2YB2-hJU~C0`uA@WI_ZKMv@2c(>E<^ggZ{0)FygZ*TWwU)uXH z#9wVgF>E39H4YKh8IxfXv5O&yV^;=7%DvmTuFaj{_UjvwGK%DA-;aiFNm1VThnw$| zE)j70oahHt;eNF11;pUA2g2LJNw_({(Or%XIAX{;U8#r8Tt-~qT|Rd*ZGRKBIa@B1 znnh%*t~Ap2r^elhS>&31**|_!B%jlKX<ah20&BSD?*{7px*J7?UWKBU$qOlzqDK{_ zk<GXcFvNx)M;U5{%@HV9!IoR?NEi%%{RS{w;~(FMXr4_<XFx}N`}*18Sz`tKG@hE_ zN2!h;EUn#j10%0-U+*x?Y{-vV<BT!QcNmU+&C2xXbW7S(;8+XYghAG+LepsitzJ*H zX84}6k5&&fdW=Gk0;~E3!NsVTP<F1u9jWCDOO-8_;dSZFuLyKJN@5;2FSxlECGAU+ zj7vy=4uD;wqsH*n2U`7zF19$ljneuq7w7|p*LkQ2n$hda<*4MT7^RgZ^CyGZK(+An z;Um!Vex&SncfJ%)t**Qc?;L@%FO8L{QH2cPSN9D^RXrfA475a1R?6Yo;j6cx6tZ4m zR3}47OMTHcj2h@Iy{f@FxU5mJyuDth;`uMHor?49(>fK8PkwePPOjEM_4!XOs^j@u zEj~MTTf9vD*v+AuFOOcHy2DdDn>18bcB1;o%bb?v^E!0UmCp7R@_mg<ou^x@0vmO1 zi(pdi3pOB-BRFNqFp_0woB`qzB@OhRjSH2|qV!T?kC%A(V@2|p&t~+R(~Qx{Dl)U3 zsGH@{bvY}02=`&sMe{KIR^W={68@v4FMNgE0EZ?4%BxIn%sHT#(d~LXe3eW);_TbF z4b{LZagOYhQI(H?0M39BNoQGJBqI#NQM#BIh?JkwMH%t^Ky+Y{z__yL&EunHL{!wa z((v{bEQp29lg|lW8y>n90gD~vw<z{8v*qJS6nA4phG%CD6s|Fv+6*x0Vh&fD(jQ?? zdlYx`M{I@RuK@~A!4{ZrWvcwH$?2V3DtM#8Q)=m-3Su1D@uUS5JJeGN0EMSIm=1`; zRM<&T)o|5^ktz<gf!U#Yi-PRa?J*v?sHh0_DP2A8N)hwAcxWD1@ZBliI&msR$rC`5 zaRs9ah^@{9bV2E3E@R9Urrv8;edw<mCDudG#J6u{zVU!qF9VR8GLmp6O}s$4-@#}= z(xN<<nBVlnq5$cg6f@SYJTVuMJko)}eP~Sq!!7+tw*@q+K<Y&j$TxZlnjaEMcS(5; ziv%gNXL7XYHynbkLG&B;e+wBjyUIjc#TE>oi6iA2Ww8vshd}k?s~!ZXA8o~3bjgC$ z%}8B#Fp8S6IHMD^azm9SD&%37+{im1B~0Hcq^_IG@%WjMHQ@;j(2N7-ma!66@ozGx z)Imx{)W<`|6g^y$sg-OPzN&Vy4-$OWgeUh+rb&gFU@~-9tVhqdg#xmhZnq@*ve2?{ z!d;Q`S8+Bsy*Z(C1wC)Q(v83|$lWla@FY`hRqYh<jiXQa@$RUC3cLcN$8*WE({WtV z<eoA9v0sej%|AOB)4x-U@vtqXuMg<^4Sv5FcmDkWOZs8^WH>zi*=TkjA?ld_c{xCJ zX+X45cAY?p>Z4-?WI#GtQswm{e^jAXZ*sg21N!0jBVAx@m#7m&kLOi3$`=xssBhGB z3^w#U`BK$Y?Km?20jLhW%9&?rY_8&x)IXJjT9RZ0#ztI^m8r+|d?)7_4;Y2%3jni5 zLxHsDq@j;i$Qhl)Bih#!9FI#%oWh|TRhLO{v2BIP+|0`@-^`=SqYNWw>ck_~S*2{Y zjb2#{UG3TY#jLM(yLJHeo+#f;5T*dw4#pN0jbA1>ON?uW=SY0!PZOe+G1{RSqKM~3 z#RZgzA(EBZhG~&7njzA*=Ab$GL%U_8WjO^Z{?krG!t&v&$zip?7C>?MYKeBm0Ggt2 z{lg<=+@V5u)j91&OJa7(l1FxR4N}GHQZM7uIb?Mbo{cc-N!<bixtzx{>?`Ru0_X}a z&X1EM<IK?(5c}M;!Rp-f+0>a@-NdF!zOkaBGO1_zG|?%p1dI_(brMgmlv|vX&HW_D zJ|=d`!%|<10Cg>y)-&fBth_C*2wGKXaEem$8@k6NE#;V_0>|z4yz^*xZw+mqukmua zXfqO3#Tekw(epUDR6(!UnTl0JCwYnbw8d^Ry5uGjWx5HINUPDe=D;RHw!CY|7|{s8 zTtMn{MWD1AitP|J%?N%)hw&4>bYZk_G*0?xGX^Xoq8~p?h#1Do^1#QBMLsBMdXlE@ zOwB0j)T|*;txgft$2yj|nzzP4;4VZlXom;T8grEY6FYylSGM*<@N#YQaQkvvUU||_ z<3eXdI5TcQNVHSkny+c<{;W&>&ysn5Lq-lVZPZ~JRASgz0;<m`gDP3ECB6i1_l9+9 zQ!6+Gg)jS)h^#N)tGu7&bDq_{=IGVJI-5XREXVV7f|}g_B}yG7A}p7Sr08rL7_iGG zCaYyr84M*wfX@UFkjZ~95o@SBwriq>7*h=FbV4_al|GGI&azbd#Wk>lIw}C^%BOD* zPe!i~FMg71^s4)K$pTuSl}S$XCHFF~Ll&qZQeLev>8c@U9{pa`&cyE7)MFEEbTbEN zR!^YWBAKBcL^&c*`HAuL<#U|QabN`Am^LmF^>hpY=^ZY1qgPZR7_)=sQ%9{`VP}CQ zglC2OXNS*E&t7mq<oowO-NePL3|TcSD~6%K_qF<tQ?`(J0V;HXxmIFQ|B8H3q&Vp| zL0U`-akiE!8b?q+F81zkQ8z6U0=uH2?=lb!3MU4!*iiPi^bZdTu#q`X)@Sr<HtjbK zgxT*~O%Mo=+3)G11%dJJyIXD5$54H@vA&oIV(f>muLr$fTPt-IZ!>>|1?omD4i+di zm1+ev;c*ih2D5VeFx-TO!K&^LgFTM_y02$4XYwpDAi*_BOR>6CdI!q*mqQs82caf{ zFnDA39B9t)#P)bJz;j?YV-!1svJQ}&HM?buzf*tRjx<A9yBi@89W%{|Z0h>TTcZ^# zkYXa|OIN^I5ep}Ko)W3L#3wtzWn6>HX7n;eSsX8D(9U~bHc#B%45o&Cz&GX^v_)_% zfqhq}Y#6ghb9Y}pxrFHgxnm|S2E^U1DjyWE!1dwuQd`9u^<VX&m=hzu|Fc3XY!vt9 z6cKS2)0?^R82gJ?TSVrrmVx`x^LnY$lU|DueV2~Xs9Ms#>UmiF)On7qo;nhHhnOv2 z3*w}4L<UIQ%L%gI%jJB2+wpwj_sBWf+wTZLeA=&Rg^j?<C2`O9KT~yN0_iIdTc@z? zqy|9!6^j82>1;Sef6fvc<t-6{$H^tdKc1kM2rnw98d>~JUTZG_4E6axumZx@S9s=J z;=+6yd|k>EGzr6d1toBhHtZ&Rg0CkoK=sb#|Lbcf|6l(DlP^okKHLatoU6|_>Z1)? zvtqWtAC1oGn>T_ALt`vOYPI_w<VO|9gY$rLt4+Kpq)XPg1{Fj-1~yKu2Mbh3V&^$j z(X8GZft6vpjPs4v^ybge5+ufQ0$O8=${C+Aw5S%UK_e$dlVZ`LL|CGSsZa3T_28-C z|M%x`^|-G!-of#k{l4z-sS)Bc=I>j_)0M^UJf!eBP}+mqIps$A*N*$$hdsa^e5394 z0@ZKqu=N}t3|_%MFHO6%k|vI*mdFza>KKZpi4d0lu0SIU2ruXQgh*@d)^2XD^?)eS z+_Sox)fa=*Fp?*p=vtJa$;M%Y5(RTj2H_0Y(P_X`DpI%6LzKPO61UpyYPQH0uJ5x| zPwt`_;e~+UJV(?2k-pe?x~#wc;j)yfg=2u)^k=XPPx<;^%`*n;Fbx<<kI-wzupS=( z80)Zsb@Y&$Fh<Y*zWb)gzueZR{kD^WFTom44!`dXpuWQ^Tw<_(wT;!cF^;Zqjy@i` zg!t>q)#I;erc`H9w~JNwvf7Le=5wvLD8o5g(+z_x-pORL)%pY;Rn~-zlJOq>A;UqR z0K0-rU3~UCl*T{0H0neCK3&&<iNpqEy?3}qXqi%#fB%^Qg~hUOpD`#qt#a7iGt#ir zY&x#Q7+H3%0?SI}L3ET6CrP%Mq^g@7rZ!7UvdVD&IdNkxERN5{&Dy_H`(PT)naj^O zt_exc{*~xvc{^}Mb@KK&x^L#6yC3cL0_R2bX_ZsfQIsz+nCfz&&w6z>zHQ%_hf%O7 zY)wvHt<m;)cZZm@%0OcSZ@F|}pop0*mHpq_pIfr=wU18?(@N0S^Gtc|=X0%RbAfZY zTG~!3EBvva(^scob3<j~-oz*Q%2N~F8R;uIBC>JEMDvm^lGtt#{pjc9mQQ~1{0AA_ zlpw_lI;Kx3N=j{J0;6zHc~<94&;T((Hi!wFc%jffOCUHbuX%Zl6W1C2I>!Jti|s1k zo}zV9y9*m5QL|S2oPJafqLbava=r5RH)iLm|7;l}!Qvi=w4w1rlZp*i@ow?b^5?P) zFd8HNymAAv-6c3Yv2wI=yldzb)Wn_2T}f=75^<(fmnvG1YQmnHmUzb_N<-7_g~^@| z>G$yYCce2zq8m&{fHvwehKs8)_m>6LhHXtgo2LH{g(zZA5b^|a>~o>dW>g||W4CUu z@_C?h<_!^P$C@OHEcESD1TRv~f(g@eM6+S9kI=+WWk!%gp&3Ne3(t>q=Yw)<(4w!V zZRx8C>Z8?TDe1emL&uC?rmXI4lgbM_z=XsrT%Y3!3(D(9=CDY`+QqrcXXJS~xWweK z7!L^<2!Y~QlZy(3v_bSszC^xebB$?wd28i$5d^nN!<kdL9o+&1ydslUd@yhA-qR^L z`0(8haRmQO#%C)k7s({OO!*R!a$>L)5r?7ik>(wjAMWf{K%IB!@NLNHf|msQkOZVw zx=QU;ju&yA9Iflf{2|9*1OBsRI@h7$sH}{;Y!*#DhMMsNMe?c6VM2)?=we94y8?`& zS-=bkc`z>X`Lg1ul3Z1m5Ct)r^IXtNtGhCPVfL?Ha;94SYFd2m8}F2>F&VU{1+>$Z zmo>AjOUt)`%up9<m&u|ZS+{Zh;`4A8mXrLZ&yrU|SR13PdBI(%b)pE<Iou2Tx!F-_ ziPebLn-nxLdkY&U_Kj9-fnVqNy>I96fH9~LE2E;sMk{Zx@m5(Gl~*xG=?Cp0pMN$r z^Hp{i!v{Twouoq;bb9*0)pdss*~;UpAdgSg0Y`$sPxx@gsv4*n@E|s85U*3pG)azG zZhD{@;lIsu<+8e_m~RXU+8tSL^f<8aYH&U}IzKyn)y3j&*ny0XUb+Shc-A*zPLt2U z$cUbQIXPa}^)iZtk9HG$;b%sy+gDqbc+p~UwJ83wZ@&6Ke?A5SAyITdPJT%Z^PM7b zt_@TWro>jX|Jy4dhfU^%Tk~Vgh>zbI1jBl(biZWZUv^<be|*^S=!#@0$1BEby-Bl& zyW+zZ&u`+}GTQOWN*5%tn)ezT!uCJx1O^m8e#dGaWl*+BW-pG;LS*LTX$#lIJGw2E zt?R^oZJ4N*%I1Y@^)aRpmLQS|KJgZ=*~s&s+PY`nvG(geJ8nbJyk^aH8}g};QQqL7 zFI)Bll&u@~1dIg=%LAlAZzCAkyOH-=PHV9*-aAelX)pnJ;1!y=g=R(})Y9Yvxe%^1 zUIIh~{jZ@|;cWf!b1Lrm{gOPCCOgGP{yxZ4W~HoE?+l_+U(K#9ZXD}Q_y|~yrb>)< zGevQJaRZ~-HHNweOV{Q#Y}HgctPdIQ9Gm#eip3r9QAsVK7UDB2W(Gd9ug1rl`_LVJ zKVFWt+p92#=Djw4!2u1MJ7r|t1U5il&E2r@wm-MBWZ}fh__eumlcj)yBT0;uq!{OA zvX5pVH-HwVHbZY#JonBo)y;m+^?i%YP4i{NW*-4VH%7_Q+^4<8RY*Cgt|hXwG`+ya z#PY+t%mqgj$fDooWwbrt+D40>rO7R;#gd9HihR19G##qg_67Yopuu_*F1-p+QNe+@ z*j1uyGO8Y4rk?I^MO%SH5LB&mul(!1lHz9D>#oKK*IIKVSdS=XZgpH5EqK(1sR76H z=$Vx{Qb&M*%`OagxCfnk)Be3_r$O3sKSr0;D(HKp-D^WVEZo?bk<HBHzH3a$bo<`U zF8>qZKYRM0=Dyvd5cY$4J^_s!zI83e-utlk<fGB@hTp8U|2>FM|FY+Xl4$aM(oUz> z1gwoxEpQktrhQ(wf9&+Vtz}(G!jLlU;6+YezYVTu1S<l$)i5Ku7NjCUTQLaP`^-Mb zQ+;aKm#U-)n3oQwQ_p_noT8}5*Bm+}&Te&fNY}*F)!B-%NlfGp<37&uya;;>SXGlj z*v?~uS<B?pZs&o|i#kawr=TFYUyl=r|KnQ~qd*dDNECtibDmPR3yX`FNkzWrziALO zRK)XPkYvDVABbxYNV*|YUZK;c2~74UoGUiv#gi)?d|eFn0ui=`-+2BU*!C6^qszhq zP1e4#FfL|G%9B|~t74<*<O*{eS(w>X`>Z4BN+*2lCm;foEx`n&(63XAeXTX_j^-po z3_oNX$UepPViTxf*ldy$=YX5IKxb|Hq)j~>;FoS^S*pvGI8*hAr&(Eny3-Kd`~{}^ zo{*aGj^Xv)1Hc;3rf3QhWPLpA?)K>r8tG_H^?fSNslIsyKkkXAWIIG<D!)#~`4kpA ztsqqK#TIW)<-kw2qvpxFBpwbMu)kkd2^{PBeM00GEnRZEQ-c}G37?gTr^&Xi2)5OD zXIS?whHMjV>oJ&xUfs*L83xeI**aUh7q9LvCKtj5jWUfQZhx`5c0Q!n#wAd9noEXn z)voGj%and4nX-EkXVZxbGdH7|(%0iS)~-#V=o}xEKxhz*n-Vy`SLYT24|Y7q+gcw- z+g1uk#tBe_137T!E*nt50}by*QpTQgfVvJg(ZDv$=DKQq{v%ISw=Y5JvK|Y4)0<YA zSL3I}5G{f5A8Sa0@gBS(FvTE!A6yGlZ6|0-#Bmn+Z&KBlcbwQnCUPRRSoRGLzs)W~ zDi~ABTP=$mO|%FfIayP&mYlO^xx{KP8ap@2X%@XpvngIvRrY>R!)x4G>`+$A`nn0( ztK29sTg8}TMWOH$rA3i){w_&Lr6n%x^PP9_nv39tZ@%?yPc43Q3~4s~<d~Gwh%VB% z1DU9wPVoO#x5k@piW|J;NHTkGm71Aw*15ilO_X{}wEb)kJ1m82KRy#vo2J(G(y>*& zh6vT);-yo2CfQCpE`(6L(ZFao#U9l~n?g9~<xdGvCsjP3>rmCz)qZCHij~w2uz*9Z zWW_&mrBWRnP=c4-<i#iFq*`k?68ENx@|z4}f75ArI*|-@sa!o=U??(j5G|e5=u=ZQ zxdeuYr>`Z*`Pdoj$Qz1Y(wR?Hw{FS(xf&7pib2@8cO3SNe8A#4Unm#9*qAfPC_f4l z)>n8)m>r>T@aC$}t}r2qpbmCpA8<OxDJkaJr&>2r{Gja5<6`2-minlSFO!D&Vn*qe zaYS0VT0>!F(%;Fy+p!~0Z$>Y2Iqa)OXjCmtWcujGg5E!<XialTakVVS0|d5!%wKjw z7`1@H=^!=ueNG-`4Wz{f&k}S71D20UkU21+`5#~@On$XLkFUqmIEwe8cwmcjX7Pf7 z+qp5%6TE(1U@5(}^m?lAtYu+r9NIC;*z^G}a3~BH1CnoecudRG8du2J#qbJ{t;bp5 zhk}4Z;iYLXTUB^+Ww7~%!YY&vPj_1^8Kt5bp{#z4h7I?0y?YhZR-+NJL6>23Z{l-s zVc)#K6&vrE<mnscH6K?_FKaUKns-`)D~ng;^R%3c%T9EpT%gP&ytGtkV|<Ph@3k%q zN^fVvgBOb&82)&kXjWX?&1&-w#Vv7kvXGM%?*q5tT|ltsEn^Uo`?cYC)#c@5f}@or z*9S;m#cg1j%`sQVZ+h74gN!w#yuvZlq$S!r;%t(1)x?&S>*w$5(c(kOf7(1b>Z)AU zPJxyzR2Uq#w#LOQ5qI7AQ$i=sy#`e<V8B%`M_6$rz*<>`vgo$mq0rvUNK7N?xL)6@ z_|Y0CBlY^x-@L0BhuP<}$TKuhHL;5zs|bjWKAQ-$2sC32^a^M+64XP~#7PEt&6aMD z{1MDatPb58Y~R4M=Z{=FlU<j=t~+XXWvYf|EQ{%m{FD4_iTx?Q<nS?z->qP2s7R~Y zWVtSq83k&>YJEE)C_dWes|&23Q%oe5MFWudI3cd9nXqaII>?e~hQ_*}+VP6^U}H#H z$D5i4Xq=-xgAAG`YG%0$(UJXr#M5mKgpO)~3TkhqJGU4$->uoBirrp65{H?@{9fV@ zicP^M@lG6${{<|2l`YQnCKu&2(Q<=tJ+O>xYiF_BG;drWRghCe8A+%I6_UCl0}b!} zPJNT82Y*-xWJ|J7rvs;$_6*u41&Nsu)Q%3K@|yfVmmmYoFikIrN^wE=RMZLEBrYYy z8y*JG$qx$C0ceIA8b@6~vqw9y<|f;wWj)3<wvD8#W1HE~LLrNMO--_=Qdzl1!U>Bt zDi$IJQ**4jO<scsHGnOvJ`w~<jm$ypcL6*NDsb8KV1$|ZObJ6PkZo(qGErqYTdCr* z%qJ;Psm{A8Y~DPVom`=(Oy7Ywo`1rpd_dbb9pKan7EVXp+*8kGjw1Uza*kuO<sQ3Q zX|vcLu;ME2f`-dzadlg!lX&j#E1d9QYP1&?ZOv4`f$J9dn4{KMu4e36Jx2F@Dgvy% zN;B3Q)VZU&IAAjRP1o%nJE82jwIg|nQf-W}8m*Hk=?L3PRj)z`s2a<PpF9*Mxf9w6 z9*)uF!vz`{LMk`Cf;Xih8N*NPbGL5Hy4+M(X$Tsx3wZIh1Siv?L+lB~eguTEAl;io zma{&CQOPL`1D#FG<ec^?K^zQh8g{Pr__Qs_f#A9QW8}C(F`;<MM5|}J3Dve-ti8>$ z-4(iPpJs(-Z_V>78M`~dqD)84n8C}tKwHnVt422Yd?)aCm~yRot`C20*+n-X!pf>P zg4EMK^ClH(79D`%SinN<3l!Vv*x;8HvVAqd)a4z+n%9j#JN9mEq@hhmq<FeOddqjN zcpLhh#!}ziAA6i<L|Movav)a{DB_?byqj(mD_A;0E$kxcwWQySa<UIAkD+*;R<}mx z9koy!_how@ehtOR7^O^5YwoL_5rl6s8FqNRzZ!xH{-mpP*K%<Kb41%vFnc!LeDem< z=jWe<BWa0)Ebw1x8ljxyAb9<SG67`y;PCMM(fLJ_qHhg&==6HUh~GtsDf4A9(RXFs zpfdcHV;ZVeXylr8#Rkh8!W=xztP;BJ9Y`wYI9TAFH3=&~$LDG0)D60iqoz(sH$_}G zPguE=YE-$MHa^%^H+(E>V$@oqDq!gWm3F;1mUD=r4aLa6f;>dEx(HoO$&@;4U!;If zT&*Uk_2q*`e<p66@Dzt8c;Dn*+_6mUmU?ZvH*=&#XKCrH*6WWQrZ`(~X?YhRK4ES5 z!UHiIC9$lr3$q?;8Wu4g!lj%AYDci~EnYpSlIxDsX_cvQ{XW-8=5kT50odnsvNn&A zZQL1*ET48rD)Qekn(j!2dQN%|Fnva-Tr~*zkrP$(fHf@q21G!r`>%a{b?oJ{<DXmR z$}9f-r?VOnn)!@n7R@OsmW@y7O2w!p&(?bZ_LP%AdAB+5Do^YlACCAlEf-M4h5}Ls zJ0+RU!CkGM&eLo059(1Q3E1LM@VFKN1BR;fFnwor>bi?th6T=a86viT^nmv=nGQq& z6bh-`&G~K;=+<=C*$XYZQUFDTm@i7}>8bton<UXDL(+MY)H0oKAOd_G4LEf4)ZoEK zetrg)W|elCdDUr2z;@GOu3F<{N_~QCk)<yg^O4TW+2Z)oFmqTxbh;m~PTc8Stw!EC z>oebm$J9W{t=__Gn%xcloT+J~>QxsDLu`DRse~R9U4Xd`EctY*Z8PRh#tP(`JndY$ zUWtuZ8Mw@F(|V|zcCf|G)W5<AkdkFOmD`O#GxDHI&gwfZBYKyp=sBd8<vB&>ndTs8 z4^~g+%)H+T)KK5=B+B}*d&e7|GlRg)d%lebEX@nACIZW^Lttqjuv`ZLe?j|GGAGgq zT`R>8@;_~S(3|eEAI<K<@hC0^FbK81fnL|i%iZMqOCXrF(eyekudi6*C$yOAknt07 z??>9VSC5L>w&v;~QQUG+{Q8At&ej%TvgIBhhUT7z@7j@;Od;-1A4W5xHI5=1knS*w zzTf9J45KSGZxK4~P!@K|9B*V{RJ9#UkE(q=(->vCt@$-Jkafq`9-hvhWQoJcqilMu zp~bL-4y_jmFLvSFd_!BD+3AZq{jWIE8)0x&G9x)NljAwIgLo1AbX?eVT&!Z-&?07? zI-6jlspYyh0_oCL0S{ClfuWr1UE6-4@w6UMCxxKpOWvF*uhMP-R+CMM2isyL+%0Qh zF!A3Ce@Qd->M92#yxg?&<=%VcrDI3ZOxkkY)qe7|dwi&HFx!ZVTAWcdoBy-=M*W*B zj8%40PaadBrc{Z6;X1_Z5v>^@zq-{9XV`Rt6B}(`h;8r=ll4b-{T%NB{Pz-={Ob1C z0n52A1D2N+d39H1?QA;rY{*|3iv01%pZpxBRRxUdDw*TaxN_JsJRd^gW%b4@xAHUe zFP>w9J@U7;H!jL0h4<gB6t-vq<6H1(?j7e<g-&hg|FEzWjw5UI<=Ps%GA&CstWucF z3bQAIe6j!)xoYx?ILyjrA)Y|t6v8|gb$$DGhZP^w+(?emiex&flnHj1Z=ztx<ABt( z4qesF%eN1EipuZ;(-%!-ZpM3=4;z{jju1=LcbM&)D|IYJx!y1p4>{MDp}Dmh|4~!J z{5o($A*|ro(2UAnEDbKQZ`KI#0+9#|Z$6@U3N{-Oz(`mq^5yJGVpvycVJCworEi|+ zpR`2fdWNa#3sPvK&|u34l5g4Rvq4N@mt;GKZzJ!aF<_ZZ9B^|9zu^RQ#Uj|SAx@SR z-s(Z2vaiB4R-AjaAmMqd^sZ~tEtztWXHz=y6<|{ED<Yp0gO>>X7^jDho~a;i^xW$a z9WakZ@C`|0G_nL!bxi9ghc^>B_?fJnrpIUzRvqU>h1J<lTZ1#SHsA1NJ6QT$RW6O= z`DU#S#LD=HCm1@ip%q-!65&_Gm~XXHV%7n=lPmnrUlz9Y$PS;^Y{tYaFn{g9zl~-_ zhK5|%5xhfAhUYbQYPA|^#MuRVoJ`^+9p-CuyK`q60R00mAI9}jfE_T>4iDMb^R@b9 zZTtAKQ?47^vSrSvO_^YryE1tqS|qMDuGJyUHRf(ebKi2@#8F3S1zdO(V5)D}ha3kH z%b<Ip=am^+`YN7yNX0`yT~i`!J+zegHJ~!9YUYweWr0_rBqF*lXLb+X;Vok*JYLRb z6tk9Nn$-c;lA>ry6@xb`e%M!WQ2~gJ9tTf?MmaFReht&aas+EGG{AP;G^fk;byb1! zC9MQRKjKVupD`&-A9Ko1l5srwWPsLT_Zq{2xH$|$3-ch0^a+WI^*<e;HJYyZk_iR{ zHG!oTsRJd&`*CQpk;6N>_>IA+w)4wvz2GI|23}m?<kQ|^+Mkz1eKWF>Zf|VppG0*` z@iMwVB1dW|Jh#(DJNH5bT6ZuQ*nGKM!T_j{Hae@UEXB;6X0|Rk8@sw|BBmrdUvF8H z%4Q*Pp5>eUnxs`7L30IDIIGw3N`}xt%qSwY!PZ6}XyjUMAl9M>3s|BJS!6=d)WfO+ zZUN-}tpy^`O-8Ol;kaq1UuaU#Uq+k5;m*#Z-S5%M1mhbN<Y<=`ljSwvi74ez+o*m; zswV3*rfO2V+eOo5!FNMN5HUldbIKdKh|PPSnr&oWpojtYNv>lUuVj8}=`DJp$Xtin zv2WF)vSI1f@TP27a!y-nX}M+9ZHjzxr25>#g4Q(0QNv0Fs|h-Is&s^JT2C0m$QkRz ziarst0}$!%YdU8a{OHXs&}$a$4!&$`1T6)?hmtSifudX~%Z8%3j?!|Z?2kt5oq82f z)HkJWk><_uwdlG_9c2rs^F~h;MX-}2)hpn}c!7?hBT7Gw8@p<)Sd&CoS5-_SGgp?& zijBy08^-hijXRTLHoUQ+-2|nb4f!sMdO*+qUr<W}1QY-O00;n?1-npY+S2JSD*ynz zp#T680001FX>)XJX<{#9Z*6d4bS`jt?S1Qd+%}fre?0}J)ShBFCEBvPbJ2EX+L7gs zrW4C!$w_t;b%i2X5+fE_;l*;bC*QZPv9GsJvgZPT00>r<o#}6<_Z$7NtBSzE!8r%# zh68Y496US_ahYVr&5>xE#lh$J%ijLpzBn#d>ngjsZA5T95l<c;K0SbcJ`>+%MYI;@ z(a+f`gl6Alaaz=ABAQY(x2brwZf?s$oR^E{KB`jjqHK#KYBKl@KBSe1V7#KKvg@`f z;oD7>rpvTw5Y~B`if>MjPhOs%gw4A~L`5Qw&t6`<KK<&=#o6m~{1MviEvj-U=JQ3{ zv{gEvi)^_nD`<XQmwDTybN;@!Cx0(%^{GnLr+QuQ?KRc<XivbO`mxUU(syyXYQ!o1 za#B@gbtJ^TSXI%@GCC4P3FyB~E9wUA#Z0^`ixkFMAj}XR)iBq2RxHZP$5-Ny;^}aI zn#VcNqPRIdQ%I=qJOX{0H|tee!%){zo$^mpdfcS%8hQxN+9Cr+rX67JB%!{@^7H~5 zMzvVLXX<6neLlZ#v%JX)peMAEUuv_-aak;~n^#d)BO7bvBYa=c_ios5ejUYk)IpK; zwr#S!YtdFYbyCmO_bGmAi|+H!WmeFKdX;C5d`zD$V0m_}Kn3u%N`XS@TLAG(TQ)S~ zIeh{Eh5AtCPgYTLTSUv0N$LAjEuKL0DNeruLA@x;^IIhwQ$gq;F(-QjCrKAPZctB- zG-QyDtOjy6Q4zzFsp6K=gxC#yti!axN5PoZ<9MQ5z{J|Bkdp!MdnR+34o_UdJkgYS zo&M5-@X*}LRSJZC^ZFY(iLWm%Uh&64T2Py>qB@J8wax9<ur%{j_Iwr9^?g|--`;HN zZ*_Z}CRvrnjrwu8D+*&WN2Jq=$$_h_&O74yW{hK;OW-D@Zkq;pc5VLjZkboB*!l6_ z+O#F<`2|08g#G&B+i&C|&?Bi|>~WSk$V=9&K_+-1Rna|YhE>}DpY`Vsa@M3(Q<k}2 zwHYkch8G)u+TL~%<#pP1psy?_^A-?XRppJ+SxQ_<gz;f;Th@&slB3b6dp5>@FOOEp z?BwcC*c86O$XDZuI5_xH*bT;0F*e(T089hE$;;~~?=UjgNrz@u6Q1@G=`^|dt2wtS z4dZgT0wouW{~Cl3Cx60!em9ou1^<>&6W>Bp-7TbFc>X3b^z)HgdGsy3smgX098SfP z-qJ*Lrvjnu?WI8YEvi2&cTxKAwXf~rM<1LEXmWb?eHE=%T5S5d-lyDq%6wRP!#W8q z1s-hC;97{JO5U*4>CaTtJ=JfiTo<j1m7Iwf>pIIWn5u9GGobz~bFj7bZ`GFun2%JO z^6!JRr%S<}5;fbVXfn)}(wuaL#b+~JT^xeqg*GUy9@Xri1&vHgXX$SPkXNBQdK~pL z%kd71JS0t?!Ga_-H){56THVyl)QXk-OzHT}FQxwIWy+qUfaa)QNMgk?KnA@ZM@`D4 z^?9!Y8Ys>|40{lQ@1nfrkA@*Yoxa!kH}j;Z5rH{t&7@$R$2cvcck_FYxHzhkdUj}= zlW(yDC^r$sF{}Xm1aZUb7suk$!zX`$r453Op~9!(@585^zDBt?di02>7-ng+2+Qi` z5whV?wTQ9nzU+CxJ&hraNi?WVFRx4mUzCkV3fsg;W&WZwo!q^m{z(y%0t&{V;hW{@ zqFI)xQ>t_sWfbYmxDSK@Q~Bxe=&A##i3AN*cd%S-0iYj_Ei=?L{nDndjrhJet!waE z_76Y%;`7HxB6?e932>~)U@D@7Ri9RGAzl;LYd~|+)=2+l>DbbJh~uI{fGN}C3bZB* zlp>7Ogm@<EwtAbc5hkq4=sM5p+ca^&tjau#*CJY$FwFV+Hz>t91$z_^)?i!8dx#vf z28G}nycP#Ql}2@00Q6MEw<RDR+I)&Kut7Zu?kU6($PJLKSQ~WA3K4f5#q*cv0>$@8 zjKn7}?y3T*o){j(K3JU;aBWwxgqAQP5ko8{?jMyMP*<)7xFp33<S2*fSHVQgW_tao z-^`H*mIr)ouR*yi#bIc)zJMTHD#G)x&)$6VT)aHH5K#jSS43!bej?BcX$`HA0SRie zMTUy75cjuPd}{#2s9p;~d>d6!jOq$~tO^(a8d2oYb()J3T2?GP*av0$0EL<#hbDQH zyyMhC*j+LH{x&V}cXR<GEqExlSyQL^Vu~_D^Pu4iSob))wMfb)PwUzNrzO|=9rZzo zj#7~X<IBH>SDzS*F3k-rLlALTzV}&k8;su-2M6Hsg5lFV>pylUw3UTVL#M}YVxt4= z9{7?D@exRzF0a!h0SGt+kN{xdvjfRf7uFl~V1dmt7`Q5EIY)W+Hvo~8sQzd%4U-#O z^t6tnRT?M~PfXI+sY|~z6s`LVy-E}d&H6&KTzbt@k%l*+xWB)D_#vZ%f3eCV2+gbU zj}I|)L3scrY^}p6Nr;H7;Zb)g!GeH3yD31C3QNm$4pzzP6PK5^4@Wy7h@DI%pp_lr z0KU)0sItaChT{<3?EoQ7_@{p#qdf{w|NQdo^~v$G^OIi00*#H>2e~#e4884d1gJ4P zQ*T@L@6sw;ta0@>;vqJCC<2&ml433+K?(pcbe?!%`00AB`-5>fFXOwk32)K{^lXIy zg2_ZP8p-}p4g3%+5H6@EpC5isIYPC%y2-UUN(b;`QRb*olPS2t;1|6@Cc=WL<zrOS z;EI6H#5kIRbX0du46Ye6J_%S!v52y~1uBcP0+urXt3ezP;YC}}T6bt(<EZEag(m%6 z<AD@#>;{>;&OZxAtn&aLbnH4Drw-pl0hSB(<j8{8`x~K+u89u_6u)7r7D7r=3?j`) z!Eb|deDeBYe)j6(^z7xcZx9gu@cQK6-kiQZc|PhyP<oM$Q&xjonbCAm7=kfq$e%%H zKFgbz&=>?dFmwg7>@HnT#ako`E-&crBn%eVf(#8<dB@bq2985Zz`TNP@q@V8d!%Ni z7Bc~xxa?J}Tt$a!U(Oh%tSs_1=;{=BlAszV%L;Ovp%97W<vG$sfCj484j?3jMLFv^ z(hVLfH^`zilej-;53Sp4KWX;G4?q0S_wjMT^3ovN4<1#FA`4L>c~m_tJ8;Vu+JlGK z!kP=cZ45TEgGSQgM^Co@D6Xr&0q(26?NR^{WT0A2z^^~_t@fUCJJO5#fo~;_k}|D} zv2>2qiUnK!pzb$*Ac8JzL!-y`V;QXi^nj;&5|hcK=NXyE1JVB;*gvSY;H)r!2y3JN zFoX>(Az)8cf**@PKqoh-wLIwA3kt&ZGzYzUpOT$vi)4hh(+=LPO_*~EfUs}90%rrQ zAtp$`9Z3D5`<B>U^$kkG%QndR^D}XSsUKKpvFbo;nbgU$&6^C6;zeDPsgTi_GSpt6 zlm?iC7u3w>0lVZ6AKu+Z)lKd0X~4s9K2Ne3nuhHv0a6FDWsh8(ZB+E)NaRBZvyaV; z7?YvOJ;|psF@U%e=pbH#W3U7VWmeYVi}~4K#D56*^aFgFQo3)38C{#Mf6m?l-6E0} za6Y*Il>CrLyn1%=wf01%i-r0QVL5>nCS1WOs@2Bn4Z%fV=v2^FDgc|JC?XQ5GEChM zo<;`?v%H4C@)JV&3FjFBdufE;{6g^)B4xK?@3w}o8W!k|61Sw@W>o-cK$X8)kewJI zUZV+N7K5<{Q9=4w8H5l8dkR1uP}s=NG^z|daYO@8Q=s<6F`7AcAR|c)oR=CSBF{<& zDTFCl7fgf_&CCe+S(0QNktpNIP=7*jKQaAq49=sL6_~ULO|AGI{POa?HbAK+nE1ma z7>x_`U}PA0XfFzWG^a<wqG0)$cvAoYKq8W)@3Ok7q4k91NDt8U_Zk{(i&IfxvKsJ3 zC|1~V3eujAD<xr(6h`KgrU7NBrXnxPI}EPdm3#ywtRfUVD<cqL9J4^CvvnuAH;5I2 zBa>m4CC=L<m4w2!Rhq-Xe49#XGl0e|a1)|kgDVuug^%jE%2u63W(z%GXv=}gGMV(e zKARJIseA0YWCt|yaf$c$4ZuV{@8%RenfVvY6n_Q@!8Sd25P$TFh~B6(z|+(@2Pp|r zr>lvDB9<aRK--{(LGwJi&x)r{Mm}$|M|aUgcPQ@gHH8%&r^eC<T_Q{I10c{JeZu}s z6y{-8)EL%1o_0M9tQjLD)yWSRv`ABAUxWyiav2XHg5WVs@sl3l0rf|tiHB(R=vaWl zde&4xX11Z^r|CQJT`^`PmcY<yfn^_cKZ^qsxzF-kL>PyH|B92TZ)wLZtKv3m*beh> zqZL^y&<E+r1qI6(8l#8A2u(RSXmD4A)En(RmMT#KYhK(&a-sF218UaiCd?2Qib_HP zDHBd>!3@=p6LKDq+LGJw(HAXbIY)K?@5*}G_s`t+;uC`3AEyK4O%fF{1*s&z7VEMF zlA%k<w7{^t7I}7;YDq)-q`)9(+Dn^74NE}XE*9B4nKJ<9#4YB$f!uW|e#X#*Y(q&Z z1Z>Gc=8)DVMi=U)DaN`r2&x^@4z8sFW`z%DS_R@Sn2HW)H97pm)v3B*yawa-DUZK~ zQIZ6*W#85yN<dg5MaGMw_D4tL+jq!OJOLo5s=MEg^^~>TN%CuJ^(QrCVMdLX%HG=- z|DLU05Z1M<J41N_w=KHiT=$dkGtLYlrRe*odt6@jw`|4pWmi-I0!QI1ptk%<WnZ^Z z9W_lA7{5a-HJ@Wrwwlk!lVNvNL7iDZcc>ibV|VhdaS)Wh>=_Y5_iJD`GRW-l?6K@@ z7q1@M=^qW%&LAZ{2&Ug3!Y936@5~SbVgV|x^I;R`B`gD1rCXI5uv|&Y363c+KqzA} zfC+6Wkfz3fFuH;HIFvKV=B3#`=mZriSRtU$!02o+qC+;@A{%b#>!X7qha_8W7^qzr zDc@`s=l1^LhirD^{JcN{JGgtz_(d{?Q(G!)a&x=tRvSj>q;JQs*00uMQn+13s8=4i zrQ_MM4xNed&(Ygx?C<xlgooAB7|Ys_It5>d(RR0`6fmQOt4PPk>OsF)c3pGL(1-A0 zs6tf3>V}EIW1_9!nf|Co!VHQ^1Z*5BF7urC+jI`*Si#bAp`c?H#h{R+fKj#y&!@V- zox7;HW|K{y`X(Ro7KnPp-_%T=HCzduZqIA*&i)r)9HF04mmniRwI&58C!jb<CwFjP zVltK8P%6L?CX-Fg2{jPsV4}ApSao19dCz+VApcbw<(w1JkV>(DxeMeSI!#oa8j2T` z<$|RlB?V0?xLk29Lp_cU-xS$99AP_FM=}XP#Fv@oT8!{VtRVY8|LcEKXacb(h9(l8 zm1*vh80f7R`8<z`8`P=6@!9i}^OK8-n^cidd`)S0Crv_L;B(1Z9BH<ZwlILK-`$hz z)9MSWdwCt##_Gn$C<Evwj#2x>4R^IYUAq}5_7W92?-q_bnN}hgAaYJN+pa}c4ZzB; zA(rr~2-V0=0(+t8BE`*+RFShmm1#G*?a5rMWmmgk6pJzXNO!E4B!BKfJrWNF-ADXG zJUbGB>q6TB^NC4FUa%iR$Q?<r12K1CNhtCAuS!TK9bVq0MfNxCxF%@>L(UcEA8bl+ z>ao`CU!8qBe{=ETb53KmE7M$6%AJEJSvs#$XCHmU7+fCBu70c^2A2mv-iKG8Oh$$* z%we(5F-VGXnqN>>*$v`u`w*wg4EzEhq0<~40yY0Cj6*y7c}6>Z7+*%$W!vxua#lfX zdHAHO)-d8q7#D4dMB(!2@X3{q+f_BgXpV`GgOQbQqK-2$BK0&vM#C?r%fL^dmsjv) zKNliQE*O!*KRCoev${O^{PRD2(S1`7Njd&#f_BE&a1Lxh2M#2_Z~#SPaMzwIf^}?l zWH12Jm*kn7_Sc^=XXbX9=)Hb4R;@e^#jQABq%=QeYU<mv&AVKq+}GqT<SRtV(X7k1 zic`+-3vr5K{7aivxIV#pfq&hi7m8aAjB{5Fobet)je>U{tuZdd?@9mxW!e>rnzAx7 z@~1LHK%Ynh1$36tyKLDmDgAYy#nN3cHaPSIaV8pE5Y^h3p2#hdJgXb79$E{84*m<4 z;n1NYQg;}q+)|-Pl)yA>?3kvtJ?29BAY2QD8B2gK&$C^_GdyTk==K^O>jE5EZbf4e zRUuaC>frH{PoE;i7to&)<p_o+pn6qmyr!c%rV^5@rc-S|BXPb4r|caUjSyjRUyUk9 z7`QbJ2^ez~g~3N~f-)}Hs#9b&scj21z<P-%ok+Mcd+Gp<_9i<V*)KV$vm2_fQ`>wd zoiTIN;guQmp-c|5Ty7j8t);8eO;N-2tsrd@)SogOq>@?Yz=U8pIiH8Nsr0(dL%^)$ zIS^w`lz;~>bnP_(?OZymhnnEba^>U`!gO9%^SUWlfuo0dGsHi+TGR}kKwi%59H5;x zxGsA!qXFZ3Jho%^MOGwpmY=}UU4!`Si|10?)B>y~I`b!)Ea6OPX|gDG^a1UZM~qtk z*ulQ89p%#4OzAlkh*b-#<=Of1=_&c%SiLDLI%s4MFswLM3{VL4D?bp+xs26k^iBCg zz0-3Bk>Bv)JD$Ergz#@!BgBzfet`5ctEphxM~;56K(^>4QSLbQ_lxYo#_xZnRO|bH zs(u}ZTrn5Gqp60}PoJ_jFmwTSaCTMH{>7|wenJ!&(D8vmKyUU~_8pW&YrznSyT#P= zmn1MO*Vrze<k}%q$(0KfTrWevp*91Yl)Et3>235j1A7XLTxM}?<#RA|2g<y0N@pb@ zOh#^F;;1d|it@f&HC$5OvpsqS-rbN5@U(~=iTA&bl$hw4VWXSwCnEmsB1hSxQ=;B7 zI${~;ul`9Z&7lgh-^3I-;BJiRh&k3oTvg?Do-XB~_p!I%Fl#nIG}yzST@LxTKnCdF zLrIPH2@Fjp+~@ylVbc#el9)M0%k<%?h3SQ>V9HJY8fNsOYMrt|ISl=O`Si%%_;c;4 zjlWbl)YX4rg1b+#Skz~`O&ds1+^C0_<0gUuZ0c$4(ZwZAc9?XCHaFXXw+nj!d4~1z z*iR)k#z=ltjE4K-1(x%a#apbB1C;(*{PEyR@z2q6^*=<~#Gw<&<Jl_}T66Zv7rPsQ z`c39E_g$E9^aO8A2%b*G@1@wa1vdv0b%*mH!d1WTb&Irzmu}<W?#l|_Mp^M~wEBny zL=V=tyg3ZeR(cIu7LGb%g{5(EL6ycW5aKNw=M|mYo!dWgE^vUva&@_VQ0L^7L!FJo zFm&_(<FTzh&>y0JkdK$#rIZH-Y;<tj<(?QUDZ8jc-U5d)WN$oIAyC9yQJ#3Nh6ymy ztG{{cbyn59YKubVVQK%o*NV#g_$0J%OHTb!)v(ACZZoB<4Q=}bgPYaZg-&vGXl&i4 z)-?00e*+Zl#lsN(;k~|62c~8PYf+GA=IsP(2dm^ZK{OD9$QIAF3?rvQ94aC7cw)y9 z)?xs5EK_uz6M0kz6G6p|*J&K#;}U(1vH{ODT7h-1+qCY1lgx!saaks9jyJ)~kbSfp zZ&85u<5i<^ANLMYQpQ`rP>YQ)IQO{`2shaXB`UzK@IlEfz^s<zDY%6m|Bg8$!P~6S z#-X<o%^h&1A_H5$8LJA`w|J)83A!ht?kbG2ET9$vXbi5>Su%in0_p}PXO<XZ!57$D zyu3wV%!L&dTw_2xf^W0*-bhzqMvm?l%4wfg!KDlhSnG<jI-Ge5v3b;R77Dz^RePOh zF=cjQBkQ7zO#xdTI1zkYmQEtU5cNYmjK^6B0@{`4^7Lv<0vlLzj8e;zSc2n2TAm;R zWty*{0aimttZ-x^rwf8l3%*JzLQ8&MWldTuGS!@*OVT`L+eEcu<q8uEy1tlv01ZuI zU|>9UvkY#*H<F=mQ%<2xMyCM*b1e<mYt+-^T1fKQb<cACc8Jf3D2t)sX1@jXoJ_T7 z2zm4~Bay{=L79UM_j=~X{7y9$hzey6>L#G+AjdD?|9aK6+ZR!OAFW|{5SuirsnQOS za)~1o1e!jmCVg8je@WNu;*%bAfWS(?1ECv$pv{#e;i4`%jlL2ev=#b36M}LHV_aF! z_i-^uMLm|*PBtEM<*@W5k?8#(g}oFtO+N~BrGN(~Sy<H35(!}AR<|pz8fdRcHPQLN z2y?>=Oj;S8ZQ^1<s3z)EO~EbkcW`0ibVeV4qsUP8cNqv#-o_fBoGN7+@?p_9KhzAI zOymTsw8cqD-E|w)x9WHXRv(uzIbFcejhk&NKEeirBfHRKH9@^em}RX@u@01ouxwgV z*@FybJ>Q5Y0`ztNlk4419LVIWY=S&~{}@DzWM)3shWgjw{o$_@9jEuCmFMp}A7#+b z#FGYCf<-G63q$n#fl_r4=XhWkv%FM9`p{EjH9l7MPis(Fu`iV#t~_ZZlWqe<0S&!* z0T?&Hexb(1MZ)1$T&~tWdX8VF_Z?z<mXN&!iDUuKu`~K{NFcllk9Uj~HAfdKx(&mN zrc?ovPn|3PkdQC}FTImp1Y@9$qPtp?$Alm3`2bq;_%_R>vw!5WTK(;FiSYBEqvEC< z^GPc#fnK%strHg5q%fvW3{uCB(fmbJdY59lt0n^YndHp={jcU^O)<kVJ_y#=)(lq> z7W3Cz=C@&nR&t|1L6S5@_MIj$$SGd5b>H5}6Q;frNGS%alxN(|g$Pd177OaNi_on< zhA-JXY}Xv~K88=6)1rJ?W_Vr7njYE7eni!w5HJL1<6VWX(`ETKHMe3TQu9j?gRC-m z1q(;Kwva;~Ni9se0Rmhohn<@?v8*+zQ1qtecc<3N5?NJmpjJ5U6UP)AuOgL1dI&8Z zS|l;)mO*4f!qlhJLUxrE;%d?#PpiPd_5Zzm#o*F<^CRP9e4^$%Mc4POj8tePV}3pY zTQcBOld>k*y&@n^dEu>I=3&n`if_|7Hkiw*2RshMTLE9r#MAKiA9ND5pK*h62FDu8 zt__0M<Z~h6^&7Y7Twb>~b9pW@_4%0SxK@1ft2<{i4p-}OZzIkIHoV#4w40GK#GmGy zA$rb)(191s)W<e|{d*!^^U`Y)=#<nave^#l*s}@(<1~4W(Z!A#+5LU-{{4G(QyA_< zg&>{aD{>qjm&-@sK4z=5e)NaWKK=BIr;kKXeKFbF7hkDjWbjptfrE)md{AsrwG>1P zUF7=vDg5&X{O8jt)x4rMS*=%VyvX<!M<v`C9)f|Tb6RzqHLS0*A}*^H=3DSo5qJi) z=N?fj8N!DHa@^c<Wek%_rz<IEtiNqd7Za$YT`t%2-2e_?Gmoy3fvPvCr24xoy`S<$ zCGztr)+yu1t!NoH%`x>&j-X3r=9`{(AwM%IUE)<n6&^gr#YM*-uzx3%`{EhyEZ(M= zE=kx)qZ|O49`H;#&~h)-a(c)lL~X|FQx*G7t?-ExG0@5d+1(<<p#rBj2;GASug*3* ze3jiCoC%fkZZf<zg>vsed9%AN`HJ{?mEN>@RCUP_Je#}Mn;c!@l<U|#TAA4ti#&N& z+|`^;OUm{-ry4H2oP?5V4q!UrNW=G<3f^fX;-L1^(G8xrD8Lm<^VGhwOWuv*JO@`B zRzK3W=4=<h4;tKBuJMot)-3U+a+Kecz`@()!~}T)>YLD_A}5Zwsb)=8sR2iC=(u^6 z;+d?=SFcaLn~IkwKU_@3Urzq#Rk%4r)}4h(wq(krq)G{6(uYEvXE#NJ*PJ7Q4tE_* z+vhYNZ3EWfZKJwcu)FyP6k@rApAzTlK9z)r@#x^7wU($TsJhOY3NhTAVv{$8kgL<b z;)Kw4ijc?pWNp;&Eis23;!|;h)yT<MJm}!=P)Z`@x++UMS+zqonbRHjf%(77E4LZ_ z?ROGds3RcOe4+Q{5ymc;_;D)uU$o~}Lj&V_oQe0p_8qPHT%NqM1#R~jYfAE>8q6p; zV6=BdwoJ^YK{gfZiTLAe_N6G3%j{~lw%LydsyXG$Au)v}oU^FqPqg;9YU~D&Hb<&n zHc>~dS!p<Mae1<4ZF<_-NCL~uy}mI5M})~g;>}A8l6ps=@1##Hb66gUW&RJz6#nH= ztt189VDID0!>g`E2M$=RV%y7{^7<?vy;#&_TR(E%AtaWZmroSubwe-bJ1~mv7&HUx z*H<p%pVQ6*avskj0=Fnzjr`}-W+&NTRIvC#^IA$n=3e4Rb*B{tbCgaY=BgbTZI)ye za6)$nP}y&ywp8ezv?O)57)&Y{2?MJQLZ4&mX38In^d0lWVw{TY2Kq9`b^m@N{FQ}4 z_t`zi%M6mwC37g@TP737CEqN+cvw_P=AkWfz?huxi%=Df*s8xm)_5-xwYz-Mmwq__ zJwCj0XIP;*uhV4HER8mDrs|j9G~362@7X@S+BNisY0B7H9DGT}0k1ri*&cMZ>D(Xr z-_Uf2RK!9GzfR4w#G-_-!|PTscX+ZPyFBX8Z3j*Gk>*Zk4$Q|pTI=4%5~((W*2DR= zDXHcembLYrH6XN3bRk!QJJ7b1X_t9Rq;>+!78ttNV`g5#FYJZs%P@g2-<-ZUQ!dtm zZ3y~&fDC5XUszA+^6>4>7gwfvt(cQavJEGt1D!m?7H&(F`y-J~-(U=tu9JFiW1G%u z`X$ZLp5}9Z;=)AkaA4qqZ<ZnCJZ)s(LEUb_VGMf{U{gXPJaKC#bJsVpp0g)2V<ETF zq27b{om`qh;K2cB4r#N(j7XD`FRM&f<d7B8+fv~o$YxBj$-#lWsAz9#K(Wy?T0ttt zqSz7^K$&=xN3=KZS-Dbi4Gg2ynmLf#L>(OJvfJ^Mw_PfQ>8Nf}z(YgxLu=%oLfD7} zx7N5!wj)z*qPTueDDf5n*ZE=QjCi_*1#;`S#{$ECY#3XTeQ4}quF$lHJ#n_YOePOW zw(*D?45DSRjGKNeifAe%nhpWI;hWF&$c87_=!NMOyrBnxm(1va9(bg7b;Svpr5BE& zI9<R4x)FzxS?b*JlrEPt_YC#qPL9yazeC-1g0${IyQQRwTHCBXTzDNc*=_^SGqQ3g z@&J;aPbpVk2bzEan;a}{-G5rBn^5s&5*}g0yXk6kclM}5Q9^s6*0BloL$V!DcF1-} zwoc@oYbxjQ1gkvc9frbxIKe`sOYH;?60WG4V3H)z_)MKV37t8oYY^e-M<L3kP+fLL z1dr9o_E1zYGoyiA<GwGx#WG`j15>4o-tJTQ4NIWwcDdqh0X`BvqQW}+s1?`R%|y`K zH0f9|oB4R5dJ<laUANEUQ%jDQhp$B@<$w+SespJ8X57rPy__4DNy#y>_^Nj6wtb_j zCH3)xdoN|{UHQD@6#JFVeNd?D^cwR90|VRqD(i)H&iny0La9{{rZ>T43rqo_3|&_s zUFhPdOsxra8C7>A6MUa;uz9yx)sLxuLm@+OcR5Y2NN2yDsu-a=aEx4Z4pY;`ruC{U z=x_+{OS?K(mW1l<U%<ya&5I&TtI@m?(A@l&r;xX5G{f!i?QqL_bIq+@6Xn4ApV|fE z&d}<-P-f(dkkDJBnIZ4jTd`NCjr@Jb;y`4p(W&Du{Ej7tchdyILI}`Ggw4idMhv-A znMK!&*iL7=9<iri)k;w_+;#F+(cDzb&2s;tx$8bU`Lgn)nWTBKARgIY`$=s)GBS4$ zWXy+7WMqr31CVaM`8<ZI0mOqa)<dh`rGkjmJlvjG*%)M-!#)5lM<&@WkJ43$)4`g3 z?E0YE+?f}MRHinh!6P2HG6&|~7m}on(}A3vyfcmV*+o`xsR`Y^4Vq?^#dkTD4cnX} zcX}o+FFVip%J!ulgABHq?iD0!P)WC5Rs;GSa%yJn=X<P-hRceYGgCb&)2#-j%3;h@ z1nj4R`0CDHl{D0E$2v?*6cP<6j1l!MUo)#pF9*UoPl4rcsbA$2W<G5(9-lq$icQZi zp)IRQtSRj8ck)IJ7lF~Mku7LwBxS6a{?dYDjJx$B;OzqQ7IVU6i)F(TomdX*5gyhi zYI>e^GwkFjRolDc@fWRP$r^iI1=+0IQJc+h2l%*LuA(ZdG5b;i5!i1%drq$hp=yB| zFCT8)<99NDZTHsO#QFe%0)o4|63lj|pzj<T3vKv<?Oa|GIhoDyBa?!+Xbkm*{yO`# z@&_-8dB3VhSeNoex{>ng4q2(f_0T(I$EaQd&(+ZFJ(*D)^jR+>hDVl$ax^1MSE=V} zC8x~+Rp_!SDl1NSD;3*fG7eTZ7iNrnb5fN!-qacVKAg8v_?Rg)tWVg22{-rR($xYD zVKbPlQOFocwGW^U_41;mOOg~uc2Qbh-rQitDPK#eFBpsJl;48hQnrY6UzW%UsSh|i zeER(4<;CfX)05Zk3yUwKgTKwM@ZZM=U(Bx_{!YHa%X}@DF{t&H@g)H3Aj|i98AYb* zP7mLqB;&nO<CpY$1itu0UB;l_Eq5dyROpKsa3x9UIsnF!i*=6madLbekP6Lk*~oK< z_=Rd$QJEz8UOG9PzRa>#*H6m5{x!YBl5RDZht=sKDJ-nxqk%e^$bpmugYP3y*F17R zJan!=)O@8a9Z;N7&Xx<4ns$ZvcJo2Ctddx(ODypwE*OprQ|J|Yk$MYVEjO{%JNk?v z)r-)oRE@3y8t<aX*BtQe%STkFB#EZ3)u9{BBl+THmdEZ$qPQ*dMD318aRc_Un|{|G z@A0hp7<Y$bXdV01JoJ^|jYgwq=B)vyEte-*@#ZH-DQ`dHW^HTuJ2;El2t-43ilM~L zeFGB_L*Brp8PQ!hnq&*QVifO4KswU~DsBW}?VW25buTWeLR2;<G(7RH1VtAq^5Y5J zsb|xFYVhM5tby5@8^ph^&jm{K;QP#Q)R0e*NK$TU$Z;C{>r=1p5%3Q?e`m4Z-|fHo z{}03e4Y@Oi_rtrH9=?A#&v#+f--8F+>Aw^02kGvixvRVp(Eu&m2IWngm8RNO4L?+C zQ!Vg+YwdsRRf~W2%FU8@vxCD;Jh$5ZXYhJgHvJdp!43<Q;0KK}in~PV`G3k9B}jk2 zMf(2<<D7;&FCONu8!m2sPvZsaw9YxFphO<4R!J_pFqdxs2fuyM<~s3ZU$v^g9G|`X z4qw0f>e<D`$?KQSrPt%X2LJNvk9eJa_U=oJIj=sM96fr3Kk`|vFT;nE-<hW_zdw8Z zd=MC3oc-hdClmPJ*aLokHaz@~p})`R%jYLQ4EMS;di{9i40rnH(+vYApIGxDA)PBz zLf7iQx3gbhKE~pR{#WhBwhWHr#SJxq|2<89HIqr-r(&7i+=88ribjQBQD?aLEnf6O z2YpPk^Izx}+M&d3dlqvhDwxmtiRYy|)^QY;F7K;lIL$G0!#&w!sDq^r)cUb7fJIT} zZ&QhYTiaraKmNVu);fyD7gy4fspaiEI!_=IGIS%eig|4;=_<u=<8bnt;99;HZX7z5 z3zXNJ@w@ENv_0P8tckiCku#c-VR&g%(%;}QUki_e_>~l4f%iRz_@Z}g?`^j6Vlai3 zx<pED8Pn_Ky`6R}wpD+-%=V*jQMadI8|&ewLxj4`R5aIuU(}&qtQ1V}@N%yymY<p_ zuw%MZONp;|fN8Iqx8PuTPWp(x#SIlaHHEu4_@$|$IK`Kx&|MUSN`H2gdUMMB4MiiD zjqf@Hkmcuce_U%X^`bTe0csr6qD>i>dFTqhxeugPsPE*6q0l}S6#%gXmAdinr7YDV zGEI)mX=10Izp)%X7~M;8j@}fME;Q1J52_Kc*W=3gOJgM7_}}Fc4{!$)k60zP-vllB zRy2^p$5;L4`zz3UjYy^hxA&O0bnuaXC2EoxCU=lxCgp|~HclYfhBp3fxhz*<W*PRa zxNXOeS|oV%+`@5l`)<!Zw7dn055_K=N5ns-47A-m*k-z@zm3Y<{KNM}f`|}~cqpo( zH#-z99($HoKLk`lh}$Fiz%`BjsT7+hLX%;otLp-H!+8s(HZyp)bw<c-q;!9mqpt$C zS6b@7@dHe@%dL<=o~0x~c9Io@e|Hf+oviTb;>6wY-$CnI-=*iKc0g#a*m}J^##!Ou zCI^H-4qEgI89HjmyB|gv8s&5ZfUZ{v#kus>Xio#*-%0N>aePMguC2APZ{hBVpfhLg zi|8&%x!IAEE85tWmK?F&S>9{zw;HJIRH3rt6MIaAZtZo5%~rbZb`!1`<__WN<nV@Z zrHtR-A6E{q5!oO8tEb=DO>zv+fs-P?eG+{fIKrT}bh$wZ{%L#V#Lv<~3}7^@$&$`M zB~**#ZN-5&Y0EKx9{W{Y=VnPX-7uCmO&El)rpZ89_u1gwtJ_@wE&e=!mW!J5@OAXb zPlk<>k^tQ_;PJdAAfC&=lrR7(+PW#1o8n&3Au2bM8s!c09tyl=_W&=N%&|sy5z(8` zd(LajxMC!X@!>ddYv1Jp(yy3|J+c-nCMr)nwqc+KubqLyv5&3$;+S5Oj=neV-gn#f z_L)e2H>=!f2`;hnO?s$z>bMaGrK<YDE;+cHTn(fM<G}ygSG=|oXEAUvmELuy>%yt! zaA7$9)l#r{;He40D=NOcc2v(v5p6cHZ<;L6nss*tx_rZpDjZ-tiWLH6Mtc(CRX$sE zcr&E+EW!W3P)h>@6aWAK2mqM{yHIZ;i7fap003pj000vJ003lZb98KJVlQN2bYWs) zb7d}YdF_2`a~sK#;CKFtwiJp6Xb_sW9lWD&X^AtdSiMftcxHp60GmL8>|vuD)7>Bm z`}V(IKI;8wfSR$-j$4F1BG6S?Rasg2s?6-i+0o%qHg6VXeRZ5|`sL9d@t1?g2amI7 z&3fCGSJ!<udN$6!`0Vp9j^ICk$Ua<)?CrL{ZtCoPv+VDRR%G8cn|e|7Wm8X~=X)Wt zmoJ{3y?%c-?eF`ns2AC@H?Kdud-3P*KfHPO9)E;(2ag^-dVBUZ`|=OpWaVmIiIu2( z1_DnG4wh}R%4W0Wrr)$;Hp4be+h?1)gb9mTRraDSs_x)GKDaD8@y%E28@8Eu=3Cv1 z`@SkK)i2jYcWr&GnyV{7g8JI%p6jM7@7G0tt$ygX`q^L0HUA|iJ5_UhUUoRv+5KFs zaY2);6<xDw=c1D>=gkU$s`l^u76yOuMn1e1Z3n&7(<{->y7@KWXOewicbhf-Di(j? zR%dP7w6fz$^abogp?Z#9$sZ=!tFsTM&rd&`&c1!|^6d5LtFuY=!@r-My_|&)4zl>? z<=J<q&;B#)FqWfl`m)j^uZy-5vsV1FDO=jvNj5KF5sTTnZPudgx08(9)Wu57fJSC= z+0pS^Q7mTS9$|Nr?5>5)H(#H<|I0ggE?WBY2YlF$4-O7yv!beia!#`I9Jiz`FE_Xy z`6SE#4Ak<X?s{k;7VblP{5;Vn%g?T^UewEGpsW4pEl^PY5$1%1CR&)1q_`>U?o0Y@ zG-FiEVCrW-zJ2rV!+VWlXrHgQ3jlZ|S3Ui?g8>hoy?OQO^!4*-OQ5k8;8is}c>d!3 z2Ws~o8jbQ7uit+-efje2T^^;5{N35JH}9V3^w<CX{_OpSv*)?LH}L5FoA2K}J9`i9 z{7FO4_y2zS4!Vtb@E5PYeKR}z@dM6rN>eNWgD|s$c~x{>HhYE?GHNb=7W005Ok*J{ zz<*D(j+g{fQMM}9YrtNH80(0`7=Rfb*DmXuY+>y{=YU&?CGeKAF8kSR)QM^-hqK$@ z=LNJVi>mAd43d>d4E0=0kqZLfE4!?2+7-~pHfw5;Et@tIFu%;-`e_t6jyuH_07Cxu zU+&MihRDxXq6V%9ryrhu3*1i}=;h2SQM5yAd4>(L{#xR20ucKiky!SKtg`R2l9!vo zGJCOO(o-IA9L_ubWMJyWVnGw1(2gahf4W#?g|nqNYrPyZ+hgD>#fn-UleqHxz;N-k zl}l>N$gdmV&$U_Au|xa%=X2fTBP<NRgzX4jfNfZ7v8nnIb-5A10?$8=r$EZ0UeJ$Y zeHMHQil2&iVhxf7xGS6i+|I07x<t<;i~I`+6xz_rM*VhO&WUP4n$g_H)8XSWp`ItN zfyyTUb6#yg1dFSy6WYlX!2#Fqor9B+q~K{xvWA2s&4WQAF;?QLm~S&e2TGLgsYOQp zX5BXp{H7Nv#_oaxGN7#^GN84?_HQ~^LxC8Bb1hNU0&bhO6x}p?v81i<)?!{ROR-4E zLxnkH0swIl3~XWP7=eChH!yC0U3LZ?cV$(9Bxr7kbs!sSVU2Aqv5=C)^l|qY)^jHS z82k&m8L%r<hiKEKj+LZ%wFul>m&PRzQY(!zsPMr|EgUBZEpXk57JwRPV0}CA8Zxs# zQIcUCdn}<0H>r!uia1YXHmqC0GoxsYa(PrybP=-gK;Ux+p3iON=0!%fpmb3vlkB#r zHug!1&!1W`H2;xOtVZEPCy`;tp6KAGI|WEbEVl%Gx`m_b^WH#GFx0q2F#D&UTX@=* zqFT%xDj%BMe`0f63xLz~6b{uCz>nycB&V>!JkEX)SuFsez$svM^BX)PcOt(PFlhms z+W@U-bv`R9R84`CUy6AFd;m_I1&bQLEbGlZo}yl?x@;t-S5toQTwIn#{q+0GP2F!` zXIuEzcVk2_C>LN@*^suYs;qC|lwX&iV1P;jC%wUz*|Mwz@)X(_QQwwrQ=`T`wXh8n zKSBO!Z2@u|KKn@_w=C-gDXV(DQ~qfNooCp7M8d=A1n83eqD+M-7tAq0if|s_INXs2 z8RdBZ7x{9V!My2@Y1z#XQc;3pvF{)#Bmom-L5<p}UYI);DROn+qF|yvA$Whf)O;K? zvuE8-4ZcMkf=td@0*bI#6d5$~6jX@ru7n-2HSKYH5HM=H5_rH2NrzQvu#xt+1S6k^ z8k3Pv%D(&<g@Ie7>|MPM#BI2^I1=!q0Vrvvto`ZFO<D7vPQqcrZB`#Py*$!zMoITY zSxnv2^Tp34Fr1rc3jwNFy050JXbU7A%S{3d8BkGQjd(`WqMHHh6vb*Z9;1%IUv?uF zFrj=9Bg7tPu_xRY%nuT^Cpqgnc^olpFHaZZa&tAx$<dTO>A>3L!xZm?$7_m4#ZV)X zFTm>W=p@ZZ?Uo(PmY=9U9ze*zf=@_L1zkiHoMKd7B8PaCqugTq_#tP={}7mboZth0 zZ{#*ofP2Vg<k)%@TZX$ekoWU~#T=biWC5NQ3=3E{>rI7rhc*p~xHSw`kNfMQM-dA^ zVAXM50OqBXSh5H#eMTFzPGi<Y;~VTjAgw2a0`#Frh1E%*o>Z30)`B~#Dn+&&fR~-J zJ;=bCWKsWCf?R9_AOWz&>bFXBA%FP>hA-$94njE5P4M-43rc{!*hB(A)Z^cXYJmY< zHw#UyI4eArFufK<!DwD}6LLd=2G0)61nr^;dWa1Vi5?DR>%)x9MFIMBM+6B>7#`td zK*=TtN7)*sO-i66(anoBv;krOR$5NQ6rgUii;MgyzqkO+6@bn)%vP+cVs6nHv3qDd z!^W&e!inIsg`O-REqH2tbkGVXEgxHoB~G54Ncf0EFq!!HO}Vk_&FT`kjM?O4y<+Nd zjEbUJH9Ba}0aY)GcH#PN2>#_(E(iVfF*2hMBBR{^OK4C5tB*iqUc&-6E76v78$E;x z7!aUUq1L5860w$*-*4AK&c7r7eQbRa2ZKvgcw#8i?ESjHi-P1--~+}68W4*H-QTz| zaD?SH;$jnP9RxWNbX!3%$9jOGyB6qhM<gk9uD~uX*F(sH5BJ11FGStxH4~QUp^r(8 zDIb|^RCmYPOS2`cTMe+k>Sv!g=~^Z4n>+y{*u_Z(WN-MEG}_?-D}CqAVg5MIexKPY zwUJwBW$$gCzHOV^azVc8jBc)AAuNQ@{nI66nOwVBE3u^GizwHIgWLu!Bi9rc+W*uU zk2M~8*jpf>m3>krZuN|z$&NX|v;)G}Z!#$dRUkRpfAJd$Mb=atzilYN7^0`Acw#G@ z0ZS<|C&+EHYkXgR1&T!2J25CpwH*V;29J@obWf4p6Q}K$nt}^z=5g)DsB9K#eLzR( za#PP`n`*15omwx;7FGr3IWQa6(a2|8H`%Ib1q&-%645%5%ZmFoa0#(cj@)ay;ph~M ziwkr~fH;Gncsz971_VD$<dZ>)4loUfQNu>@Cs%nw-jXQys+v1tyU+gar$XI?+=y*< z!jp(oke+*R^PxVjz4~cq3)d^nd;4g`r=_RlHzm&g@%%H_p)g>SMaHC)wg0%fc{sL| zJKW10zqJ$;sWYf06J5rnt}TgQ1AlLzF)0VGYyn}6o(btpbf3uyNL|&4X*f=WrL~s2 zC7i0V=c|lML3bexzv=~FH}Vp@Uw8OHb(jn1{A*|^yO__Bvg>ewp6>sY;y@R+8l)Oh z9nQFlsuh#MXln9qNJ?<PWH~2vTWas1b|m8>U=E-lp$bnLG~Z_8R{{$2dVBWv=*zFZ z2EMVE-Z`j9+4KPe%&*C_>#!U+2s-wJF%|l6`*s_WzJX_7sZ8b1qx?yijh=MlJbRLj zTwBStAEgfZ7u-w=Y>Aw*0x#qJ2%Aw})<6QKJhP3pZBN<>{2zwi(~S~L&=_AnHw`sF zkCoDG!Zn<Z0uKxD=M_rB4{dQ<q9-5S`~vj!FTcv}3j3}Wna`pTU7hzHyzAmtFf^%7 z_VOMyn@*<z&ul2r3EN0>KUW>|2-A1nL9d(ak!t<unEgVb#UHo!6=#rgVXEMSzDK%+ zAh)gTlJHp1cvsdKB}CVbvCyH>I_`}ER458f-bq+(d9Y!*r#=z&G4}aXr)@ABA`Q71 zK3^lkNkYN<q-i>;AbK45s>hZ=t*F54zvU+hA@q&~TyI^y7y2fNJQ;Dfn{>HFPuR$H zze_bGzN^eBP&wVKiJ6S@x(OW$3*Zhc5s*E(@TH6<8pf%p*)u|1B)DkfFfFl|p<}lc zox~oBiK_-L6>y*-5iYSuhCPch1u~N$@zh`_McbG2O;xlScp%606Apw>-*87dQMB`G zec^=>5PoNtH6Tk(NCb;)H4pL*kR)UZC5Mwztz&C@I3sNpCz0WAKBv=5!uz`LC?F$h z&sC%FLP_hFDXAAU1focvIC<Jw=X-#I6!CIPuy@#PW{}%x#84`R4ue86ZXP%sCMb}| zg=EDHwd~Hr%dC4v8fPW7x+}J%_^mcw&ti!#we^Jwd?ljDJ0fEFCtj^fKP1io)E}6_ zX3nw0YO?gl<)#Enr7wZSF9b$NiF&@(v19hS-U|v~L(eVwxN)4Dy1AoZuS>ziS}?#P z1ejR>N9a2xFu3zPy{uUF1`iaIJoaXX8l33tXg2v6klZwtAYZDZ8!GJLQNFm)F_mD7 z>dP|Zi9mw{N(Oep{A%ghyKCBowM)!b=QqWb@U(}^Eo$MdJx|<8RMK5717n~JD#la2 zx=8$&n&iU*C4F9^pfDrSaZr|9NnICSz$CgkP$xT=OLOFHsvU?tv92K1pKb$bV5^5y z$E!#!$ojQH_@o(*&mS}S!g)G^RfxJPQ4(Yn*WH#~V>#`pztXF%@q9yp+EvY*9BrOv zPR|zQmFNOL0X-7;eOq+$5&!-e;~Yzlu*;UBz%csG(5>5F-u&7C9^0`bpmMY~Ky+wN zwxr3qGlRocHN|4KX{#=XG_fY%aZD>c`ZpD@q)AQ+R{%2PN=3?%N(9O-M7tV4`~KZa z+87G6+f68Tz?R+@GYfebti@66h<Z#&`ZFBCJ9Oi7NI%ePRl<@ID-1N&fpwl{82<>s zbYz#Y*Vk3C?aZAEDuvo|t5GL_J-Y@5l8ACrK5yGD(_}tzD0ZA$iqh$amk<d`wSu<g z7{--=ylY_Z<YmCI0sM&8KT?x@B(2`Wy4RJZTj~wh)`=!qj8NYTH>wA^kW|Dl4dO*o zRun|Rfxca!U(#bQ(9lYqP|73xG(%g?LiTFmuSP#|t-0@HthWu8WxM8+U?c;ZUrhT3 zL>8Q1dz!z{$%T25ExB4)lL-$~4-KZl8VJZFV@`Eqajm`M8&qJ0;#T7%ZMK_Q4Ia>^ z6Qmi;GPk?t$pH{)pE`omH$4RFKc6^;+c`Z5C?@@<j^Xr853vxppE`ow)sDnv`?s@O zn<J769VxbWO5ONt2`C#aHx(#fRW~LRRYMK*7kI|1i`59VOaf%{DRRY8YhXwr|1!F& zn!|+b0@fu{p{ehzL07OI8T}~FRCdH}5u8uOF)mGK$B@!-zhgao4aycfYWr)22QyFO zVzE(-$Td7N5;g6~QToyJ2t0?D*U<GBVqB&k)&P*+!9)(6?|J+2#~-CkK3X*k!B%2T z!I+|0Bwe+VZGuRzG5#%|H=By1cc`0^vQJt-_oh=hNMvISM`}6P!;jQI;rA)X^Ab3& ze>IUr5PK;OJV?qdgla2dz}HR>taB%?DvarZAMK3ecwi|OJyG^ao;c&j`d!Ma7L9z3 zdYkp^V}7upb?AC~2p!Rq;jH*9%fGgn!AV)S!^vdIrIVrX+JIKxs`Q<L??F8FG>Jk{ zw^c?D_3qO)%Vl|w8ccTnr2B~ai`U*9sPHmQcg_Q4@qgMLhD@qQPr5%1X-E?Z(GK^U zf##sBO0sNI99sy@u^s)fWX-oD%@-9(f)em*`Zb;b#%3A^22QgN<Rt)(16u+QZR5)Q zsFA!IGvfi#(?a$yeWeLlijkliY_=w%>RO`0TKH~pfvAI7j2OkrwM9R9G|HPC<p?2# z=!Ry?(KpSAQN~DO&8{V^I$4+)>Sx(qx~usuP(#B5iYed22lN?`1zx3KOZKkb70T#R zssedpkyOwyLltPy!a_&}Q5Z{Peo;n*^P{~Y<=IQ-Dvu&Tn`#nt#VQHLbNd+&kW0rS z<yul{`7)k}1GIe)7|z*TA?|V;O=Qj=>hMDs*AI0goz^?NNYZ3xUlQ+MT1q=sC!>(= zwRM&+o$^aerz!PJQ&bBdneOO0_-g3`M2t8gg?7dw@1eXpkv9O)Scha{+$P4A=s59< zF!01$m%0IG=ZHwz*E|E*B%Xk#B8>p-tB~yHs18iPWIWQPXUNmhGdU274U!tvp5#H0 zG38TDeA-*-I-!zDixj0UpTg?hyBvKwCmEA6ll~ALe}^vVYspEPCA-GCGb@eG#SOJ8 zs;j02d4%D-OEWul=MrA(7(Xh}7W=wsY70NOlAB&`d&|ioq3~K54r{U)=fND%smg(( zT&hdxrI7_Rk}9ti^fb-R?hAxP;iG&_Z^dg|T;$z#@p*o6kp#v~zWCxRY$U&Z`A7Z+ z|G{Tpf1{qQ7GKMF<zaANfBpqV^m3e-VrM{?)-@L&I)0QsU*-;8p3@y6lIk#|;Hiva z6~AJpw!ny#Ravv;b}2N9C)um#U+;j&xxoyMNKg@6pmcOh4vKhtNn%ru0g}_f6D#h) zaG94qW|9x(OLG(uUkNf;6)pq{FsO&{tGq-M29O*m0&dw<=!z#g%ujOP?sjc%PbV_S z3~%|gNF$!$4Zm++c`&9xhOXg6D|J=tP`%P%l&?*lGx=nkfcd05(VD(DaeZyTzmJG7 zN`JiNrPs~4kj@lc`NdMqF2DIo)L2eu#4X0t7KwR1x&+h%96`_WqMMgxB&_;L_oO2W zf#*7r;~4EGuGu76y{G1IjRA{%4v~u=CM2ejgWBQD9uR`1FC!aJ@n5jP&qqcJaFuVm z;P@<=9ft*0E>P7#y`Wb&czn!3Nx)dN2{J@Dg&lEz^1T2ArKTA9ID$6IO+|7V;jtiU zw@2-!&e)I9!MVZni)T8il;x5qCKWR;&y6cPM6@&Z=`@Q?#aW^s-6uLl_`$itJMx4% zdc#D5jdIy~Qx~^ISz)v*VTs8rfDKELiFLPr7CmK&$xK}HIFkQtT_Jky&Z*!>=ya!G zQd5R0x-c(0G*VB=ZvHs?Ah4!V0YrO53;y9+h${PR`o)(@BKxkEfiNe3^hDn7t~tmm z9lw73Tn!y&dk;Yghyx_}6RAPswo0D!tMZZE4-uF<$5hU2yLY<mC#A`HO7X)KV#^M* zAPt@uciPrLP-S~8K*9E!+EJb=ZU<1bcHoU}w$9*D!?i~^HHW93_sx1%iCa-&CAr)= z^{TnJ2V``kwddua9c$JCKmnZgGN;{HMgoR-Q*fHaVq~No)yVTm)#H%t`$mUu1%jd* zjdwc<wTCUbm*{JLf{~u^2Rqxs;iH~6W$`#O0JzBsJc41KbdPr523xn3bBszEa;hj( zNEO>L-UlvR5wl1`FW9N>-*1#9!Q{Zk6ME6gzltf4P%pE4)r0WJW6Nws#SJYTnr1?V znu>%o1~?^_6mw8?Luhoqo0cUyhp&TZ8nNS{q|!X4F2gfUxr-=7-W9M~6IJ1Hlz6J- z>qu2-Gt~I&7!vi?we&{ZM6x03#G5^9>3Mi&9+RUgqX-u1rsY5cRJ(A$tl}(-GSurI zqvAQ!-ObroskRnD@7=e!>`3=;o`?N$>)Ymz!Uu;}iJw*3kr5BO^;*?^E2(c$Ux`r# z`~`rGC)t<dc<~CRTq-ZqZIH(!L7vbIey^ZMJ3f|C-D-Jd2MZi|LAdUwWV(<O_0Wls zPxA?a=|m!E+V1IaVF#6yEWRQ5QF$LS?qL*L^*G_U?Nko7TQpL09~lR_$8`&rE8?sQ zqzxTLyLYGwhC^T&6=*+=9(kf`5Ecri6IfeNw-7Iulk$vuonhq%J15hLdlM8v2&T%W zs6t?JT*<FE75GMMd2tl7Ho$G%@`5{<jbGf+k-BZ-ia-i_Q@V4s(@pQR9^Bkwp|*mh zwe+<r7wZ%hADK(z<oEsBU9F-q^nb@){eQBBzh1S~6Lfc!rO7TTa0<LigH?V@&;wO{ zm4`0aRo=NMWoW{Xo^S5(sq~SwE=;Y#2a!n<o*|$8sAU-?4aCR*Sr~1(1^nlCQEl1X zDvhS4mk;4)PN-m=-AN>`-+VYb=4*)4w=X#A<r<}|R<@`<v~|QSwhywgsn9Q*$UiY& zqbrz3ttVtm5I1L82LW00Hnk<qf^aCK>`at1N{zk41|=Q27p-%*Xs&~Ub*U>AGXUND zk$-sLN@cfpsY?6)0~Ji^I!bC^q^C(NPw=q7tfjVD@6jDU$n4ZUot$`^ncNzc31mhz zh$Lske~7JdMMS7fk4bw5CS9HyD=)1eeYE#dc}B=mX1XPv=0Tb1W(BJ}1hgT*_)*C` zR@n)RRN2^tJ}xds#^#dxo3xv#hy)tEp|I`T`Vk?B=wx}PNrseegdkg-p1#Z3FmX8& zLlNt(z^Jray4}v&O+8r9mV`{_V-A6;Ydv$Z+hL6XTsHbCwa0gwoz}*LBrgSa^Ptf! z6ju7dixu1~Tt_cz3%Anquda5m*tNPFVm~zea>p{!W)`WqXmyX^x?3b_>`IIjO0bt{ zMrOi>Jir<}{x*fp01-iD&iFwRx;8i5IY<jlm8Xr1wa_}2k$u=?l+W?r08!8N&J091 zxsZv%S8s_GIKC>y+PL`q$c9IydFkh{HiPm))7C_*Fc?D*P|b#3CObOS;?~<a7Pf(Z zn`F7S$JwGG>v6s5+2q8-&IeIDDUQDU!#C016h6acHcphmnuknmp!}EY^Msh1S{Upc zK8O?&b#Tj0JNEx+zuh{`uie=y5}}*?<yw06qSZQSQWl9K`4P%TAwdsZF~>hXa7q8E zGM%pR4ProFqfF?igbQFooAN)+-N<6Lj16sdJ6$PPh?p0j8p(xvM4Z!*gr}zM08cS9 zz&@+~Qmm)36$Ptt+UGg3g@`es8(Afe(d+OKVfl>Q6zoaVm++l-G<Hg<)75t^9&VTJ z<+w5FZBWgz%o2=!i$2D8TG)<c>C$Z`R_lH{RyKoyRdzBAZJM2-z|}Qs>5@`D<!<VN zUCMB}++=B^!O0a!Y_iK7af<89k>qn+be<J+M5ruLf$`&D8!hTwhOTRHBZ44m);|g1 z<m7F!@Ia3;2?5JL5%PGV@|vk$hX%yQR@Iv;<`gSSKgOk(L5u4@-CtIHqC`<FJUn1p zXNl@)-Z^=QPcP+=i}~SHad*;k^#b>dy!IxgE>z;PvIx_4_8F?;^7pJ=`6VPAIY+oo zjKj1rlad51hf!3FL>aplcs7vVu_#Nrc@wLm6EczXY{83+Osg~Gk+ezjlN^a=S4;dj zp(fl|W)J|7N%nb=M_}eMRBIv<(CL5DqBsp!qK9r{0#Pg_aXh-k!;lT=cPD#c3P0&x zB<|*(U2BX`uoy@?oYUPkNPva*k?%;6bRA9HSKp#w-Z<v++=wkl%SmRB>5n<94_4Yq zzTSXnEiaLaufb@Pf1*oi&Ak1ZEMxi;y{0*xh@3JqvFxN3OGT9;nifo|byE}f*EQBc z-wKJ6!t#YJty+YEmz^EeeQ`sQ6a6wEVK#M7RXa%+Mmiy(Amyfpg^BGM<<*<q{ETw? zxv>6ii9tH_;-e!pM*(M78%ie|PqP=b0}JzGln}H~kkOl2Xwr9-{6kVy`R`nF$`J+R zf@zwbi;gOIDoJ0K=npO&9E5Y_D_RdV)tSF|k2s$TG$SX{*HekxqVAo$jnd9jDHf&{ zE5C@zi9dF4<2Wp8e_yjC@t8Q$^3{F;ly#0hR&POy-PZGq+@{2Itft6&atveOx7VGh zoB0GYqN{lOLf^Tdw_8$lOUWg0>3Il@=tJ2S<nwU2Z%p{eI(inB4VBZg-xcJ)CWv1X z@&L1oL7oGgkNW)~=GlPzJ<7$j-(+upiO<m-f|dD)9(fwlj0VU1?)gHy&CMPBqM2`W z=(59&j<KTi@rA#-Fb-cC|Mts!NF9}z+vHCG?f}Mg-DtlJOORNcfc$7*jvmf-?b_k~ z>^$V=fT=`e{3jm70dI(XB0tF+qE4Hoi{r7vLjc<|(sC=yrGT=ek|nE1KzTgDy2|c| zrhTO~beM3vSiLixraD&`K`W!i=*am2U$_8zpO*BafetgWj`JiN`DVNeUN@Da)SYF6 z@8EQIdvdxZo64j7r&<;>ra6R~j0HX{{OaBVm_u(ZPgxeS;(>XyU@V3+U8|2^aNSrV zjF9S&)829WlRs%WEQ$k+3-xk=slRu-V^bqW;a&l%;o`ohs5#_pfKa-2Bp4=CHEMs- zw%Cz#p07VNN241P#y@oGt#8EXfM1aZYcM$4@<|vrLuEBg#;S65M{mfeZYE!j6_{-C zG{3kwlC|Q6+;;n}Y%nJ)8Ny9(Omp?I|B(g*Ok9SBmtD}$F1VPHQ!5Qf-x;Q3%aIV% z01798$|fGJN?bTOWt_mn$aG5y45vCgW)GIh91YeibL8=*Rni|fVK*Sw>G6*`6Qzt7 z%Kmhcedg!eQ`s$lkpJa0@?V}XaUzpgiIPK{AANBg@OHmHneXZ}`TaltxOef;=w9V6 zOTsHVq!8kHm!fJ+#a52bjB~8qR`z{16^XC3gu-KK5y04#VSFjV3+jInM(i`Xl$sK| z-~enulfQJh-fw%q$)=`reQD?3>B^O8h`~&I=>nCZB#NQxe9kyKFz(h?RoTZ^t#+GB z`?Zt1ZcSZl(_Z!dUQXk#^db-UxnN~xf&4)-@}`w3Eof?1iiJ>C*+0^|Y2QJZHHV=2 zg4oq~21^l0QXN^Z%%LW!cjiQIgRHDmm9uWqIKM0Xy6@M=PoILt0?Vd1t52Ku>M7{R zqD61|Q`Cbo^{0BwWgVv~mz{v9FNinqu}ZOuRH@%5!D@GImB~GJ<uaWQm10HU)T??Q zm|~^PAij&5sFd__X@%_&ey>T<R&g(dna{)pPj&w-*9d{5AucZ7{>OJm_?{0~j?$9o zvP0=b(dv&>pMf@$-oeT#;$RSB=>WhK7NP{cfj6vh;DoHgNKkwe)T)h_OxTKKXpzSe z4sKXmZj#lL?AALBohp1-dp~ov!`iBH_<$mZ48l}7y!Bq?Y6*JxfuDJ89q$LHaOu}x z?2*Q$+on>vc!n{wI)x3S5cjJ(T2+ez&x|!6!*<n=w&JfokF(c8r~IPl_fjme3O+8x zj}-qkQ}+4mzBxg(Oc%2zH%L#6vXvsN=mEJ(I`2edD{2L)nqk3R2GuRJ>soa)g5ni6 z#gFEH_IsjLtyEMbWW2Eggt<tvsI>#<5Mdu4EAH1*;XTT+H?Olk0#>=$%*7%G&6||x zeEG%mv*1U$U&2fzyVV|!PI|0doRsq$b#BV%S`6psvFh>!&?~O>eXTBk3CM8<s}JfF zX5GA?I{y2;2@wIs?~&p~*yFX%;!xDvT=!euYbqKxZ?5XHQ{{H8F?dM>^BsB@Y%7Z= z?l%)^>(+jxcu9-c@NQ{8U7y}Oqe?+UUfZdVG-Y8Avb;}B6UkRO$hdgWLmb<47MT?G zM4F<`HJ`KGqBYvHNTsR#VtWBi)z4NkN`&Cu>}tpPFWn$_kx?$c#I84fGY+HROD;ol zkzcp=X&hz`789+@7I-n$#N=g-<GD=4Zpq<dOga&_C9Ao;c(YISw&dRRl~O|BFDab; zccXA1gbKQouT~90IU*5zkx3;|ThG2@4K#ABsBCD=K*Cg3rMV{h`8mee`9uTU<5j$B zCu3vV6cy=eFdOttCGuLMDmgxQu3UPEGK|OBw=aHtbq3mby{Oc?VLMfi=&$8k-QOVV z(gg+rFxU`g1OJqm5Z_PrU!qNfFv@&x==Gj_s4w2c{Y?m(qmFQgG$lMWTWe<_|1pom znhd3r%YXOS>*(3Wj|82X=ngs{(E4npfOsS^n0T!|X)@8uoew7>XLhg=Zy<*^P>fH6 zJMg<xKaoWwkDO$v!`S|$ql2G;AqSXD>W~+M3H$g-vZo!KDN>m*;pC)=kq1@O(wU(* z2b~r8WwNL4bJZv>r)Q>7U@T)eZtS5&6cog!_GV3w>1CiCOVX^52xXb7EP&n+8;=tb zNqie)PeYxt=%p1uS58e;a)FFIFVasoix8#>0+Vfa$AOu1zq6u()E;FI7n}iOsUsmF zm}c^?xDn*lZIEq!|DW~?SbmuuRU9HV?muY_hyRX>{{Js3Iv$Z91dM2+IHJwjS!%^j zd5I^wOtKmL??I8#awz3MAB<wg&ydBue>Ag4R1b@2PQ;4-R{467ZTWjA?-}cKN9vwq z2+vlFuVV;C_1TXg-fdb+&zU7aT%cu*F;|g%QA$x2qp0<6Rq7kb0mjp7aj#3`xeGG! z<<STzym;=5o?F15)c)YNJ$5=0(>l)&If@Yr-A<@^NJORWK1@jcecXrmv5jFYG)o$4 z3Pa>BOI0j+G=2Jr-%QId&mxzbe09;K=<m32uTy_00jZ!mVpfc?Q^PmjE5T$2-r*K{ z4C^B)FM4_ZP7!&D5-oDj^@B43)hEd>H6rNF@(va2CBMb3Z8ldNFS7(Ac^^DTD`#LT zGU`<`+KJ>IAPVKF8wdV3r-wtvT*{Cx$#xc+NJSV-bQsHEfa|a0&^r9U=(1KA!o$K3 zEH<CKmE9})zyxq93{U{<q54MgQx_K~{IKjS%~+RqmD3%dxxOvx4&#4m=3G$)7E-xk zL(}Yyrn|x5FfjV=q-I3k(iHlgx4rANQfQS~rhIW<L<H^^iSZBDth$?WEpMRz1=zg2 zDWW*|>C;32ytOR%O$7dDkabB8gn-h+{8nN|4!GVo62<GM>2Ie4LWZymwi{0Iav|ZG zeswTR#Mu3(427x19WnYDhs2!3qj(OQYT-7Etk1l1Rlhs)yS7+g$KSg8PKC_6Z`;hS zu#478oHsE@eoUp^O$QGCgU8q9nsdQS*}(!W?PBqBF~_De6l=is$V^`qYi3vO%N}$w zE97Zl8_4afic3+UT_DRWvVR;J&~sS>z3gP5pmuL4vs5gu$j&7&Ds<@Lg1!P!df965 z>Lpe2yCs)aw*iTQ#l=<p(0H1iR$Vh8UbMov2eDk1^O9b@)fNb;s3uyD3ix5`&hFyk z9%YqTFYE{~N6~dnORqP$LDz4|v$?ov5d_w_gVyKwAF)RKY0XO`A>+X=5L-=vVt8^% zFLy0!=`i7@yrW&FT5whMdh68vbM66gtErF=c?P!L)?Zx6j<`fqbW+YoC&_497@`B` zhM0QX;r0VBC2;mz8ga(_URsZI742J$#foF{D@(gH>*bhn`8cx~k;kSKqa8YhzE<b8 z;qvVbVVIko?Wrt(aA-F<R8ebmRBa`RU#eg=J=QVZ_$$7*v-@I-%!(?W#NPuj$fbeQ zhag6{(uKXAAtayM6aN^g>Fv<}K;y^u4#XNd`+?_2?!)~g+e%gwd5H$@MUgyjhxfEC z?r+;euauXDcSxfg2Ag;PDLa-mk+%_i@;32Aw*M>>Aw(SmJAo$Z<uY6tcW=VF|EMi8 zwZCKgc4Gy$SBY*{+*{^r1;5FG-WGm|cd{*(zqhsFdllRs(&p9+@sG7oGqPVnhU6&8 zHo_SuHXBT3Z6l59I<SXUheMqT%)zNHNBP%bBFE|tmL^<Dl13CE?%QUcbQ(7l<CI2k zl$+c6uWnZ>5!QiXgbm%zU?*#5BbPLEOF|bh^acmMC80mVTM`0U<874z3FM6zaVMX< z1oE~mDZY>2I1g4fi4Gf4&8EllOTZsF_S4LlX6j~4+De%|0ugTRor6Vb-g0aWz)HQ- z5^XXDZf*lZ^FhKxq^Va5jwBN3j5{58fjXcHf6B8%MpyQGD%wFS^@^x(E;VN4F;+-d zNRR+N4?5Bt$5nroi~UobN9QH(dwK~obUXk2_+$9O5}iBA9V|NNo7tjKbOrxI^Aa%& zrf5xfH796^y96Oi#ueG~Hy_mAYX(6UfYdRxZbi<W!==qC(Ekz)MvfQ^1_l7eA4Atj z=&5tGG7X7zx`I_Ytz`BYY49<9j&)5KdhNb}ikQRl7+vT%z6=M1dEo3XE{>}5MxdL& zE!^?BW3U$FE$DqoFc-V2rCH!drMx~`l#EVCbN<^;^&>a`g~=9<P?tDQQ-HRLmFU5$ z-q>%9_UmV4@hBgIyO!AT(NER6pd;YkVMNY5ju*WV!;$sDjUQSYJNYBL5<dD<M*p6( z=7oQM{0WoN28D>tAkAAIL-DRYX%9qnHb2!q7dC^8gRp=A+q4h3HTI9=>`#7vq8?lE zWS6M^7O)H5fzf=DJ$i0+c$98`c{OjUhO><q)GXL$;-_Vu4U>(7E<}>XQ6$LB%KT2u z>%W{w-p>|~Tf^+H$~jgvf+Ib2KlxU)=*h*KM$;?9Ug{EE8cwQ%RehV>3ln+yk2OyO zziJM98Y9*QjPDqukmHcHbo8vv^CsFU(FwrvB0j>Nz*KdcnzKLUOyIA1v0)!IzZ)_H zH!oX$$)9V|(_3FNiN5)EUhOK?ZrfeitKtS@7`kgxpR;+h-YS%9Zst}hFGBm7N-|8c z+Xpd1f^&XDr9{rH3|+t|h%J;te%c`V_3qe}fCz*Yt(se*i{Z2zHxH@D+5^-g2s*YW zjMEqu_B_Whog}ZkO~fUs!4zA*iMx0gzyZ|CeYrr<N(xRa@bm|M<9a2Qbm(~}MkP6Y zdd%M$Gp&16pgv*N0=@{IFr>@-xSNioKuoktqOVBrFn+9EJ|BT`){dEPP4HDcHG+Wi zq3klfcrOdZu?Sv)cEi_KOwoL?nHD_fP9*+9Dd^^<xilYl_~;d()c16&#FgO0rYJ17 zH5%{n;vP7u?;`K;mW(g1_PZMXC+Z`vlI<zXo_d{DY!7g4E8rzFnlE+iOw6S;!E)o! zenlm_B5rI=iEQ-7yxG>xB8_7QmW0Zxv5ujkUpxN+j*@7J)`uF!ranK<O_pA;3OTqJ z0p2S<6&)~MGkUk<jK7TdAKolR<w<a@Fm|1<$i&H;g3eqjD}%=haYW&FBON?QbRZr1 z>Xt<Yo?ULrYGD~6be~^h6etks9WyK^f7er6?2H~3@`1~hHC%_-*Q)na!uFI~KIA5e zlp~jeY(_5{!eun%$!+xHk<U!z|MQ7Eg2a#mO!c!}5ZuXfJ$NYAS6DU3VmwazDx}+m zJ1b0^RbUW@I#fIRKa4C&)G$BBB@{NKT@AV~#O*AMHRk&2zu0+TUKDLC4vS;j=+yy4 zxKsH9dSjw#Ip5bhRqQW}v_yP8*B7AF;{J$Vbh%Ut7bR@_w?+{X&~Y?#s@tc#DvEm2 zW=FD6JHP6<uC}|A3WKHLN9It&GwE=M7Trvui?#TG_@SX}LD|@d6+iph?WE#pW4Glc z7a^pQRq8Z^h69j+re@i!wY!`njEG`|pJb+po|?5F`gathN86u=(u_Y8;~?4$U(1QD z(m)IwqnipA%nBouI2AY((A5Bv%|ca9>W{L2I5{&Z<*(*>>Dfr(PVJ;Xr>q*~+996Y zDamd*LrHa+Zvefw0!*tbQBx>WN+`30CueqdsNG0XL9*OP)Z)+)`Fn|b)AHE6TgF87 z)uo`=8#O+^9T#o5J0Yv0@(WX>v{DjR)(ldbs?U5A2_vBngPcR<hN<c7Oc=?fE{Lm+ znD0v3`}&twJ25_my}MMpUt>AMUf(PlR4a&Bg4;Xlu27E(B9*D=u8BtiXTdmg9+QnY zgl1Kjz|;u%Wx8(cz#f>6c4fIjrQ6IY^ENh{kAYW>TC435k!T$nTj{yb*r11I^w}6! zCoM+WYrZlR>j?!B^!#!hR0v=uTrL%_qcMK2k%1BV-7ahE1WBQ|_y-&yH56W}|M&U% zjm{71HfU`zc}N8BI6ASLmEZ92*ct*V4)OD|mT?{NDTOD9+RF_BsKX}+8*2oqG-%rp zq>Ca?OFlfj0nO^F^8%YrF$NEIx}@Y5tg6~9I7X+qp*N&4?Jza`jQMv3D<o)aNZ?Zk zVz*hXFjnOx;{ge6x%?G_n&0B9E3cbM6;xD@7=x>YokXZ-EuZPKH}H@8$*NalX_oN7 z%tZZ#i9e~~ZG75><7frQ{=ZO50|XQR000O8nFYI0pQkR&GZg>;N>Ts-5C8xGWNCAB zY-wUIX>Md?crI{x?L2Fb+_tsf_gC=RHKa*q<wx3}ciX*y>uj0@9LHF%`+#fAXe7=I zvl>a4qINyK=zs5dkP`Kpo!G`j8bmO>8i_nSJnwTz>Y+IO;#4F>s`Aa5sLlHH_xR-G z;mJesqA2%TZMH^)FJ|J|lc!&azo<Oki#PF)s*Iq;OO?pHlBqC-Fk2~J@6EQz#hYSn z?qV&)w?&<&u~G00Zlo4543!(LR<$YM*G5aZles}yZ=@72FJD}|dUFw(4@Sg!Dqj5X z>iX*PPj9b(xO#&Rq1}nvm4!B98&}&*t=!M7*lb`5?q^ZCyJ}k-l{LTWRjG?aR?T}O zcja1T^2F%<*@=K_t&1JZM#~t9B5b>BdT=5?B(gN(k{(`YU1+aUTJLuI#Z=c5Y7@Dq z->AyK1TF|5P{_Vcid`8S*C_n%`ug>s;z}jYYqR|hXp%`i7gzFsYgw7Oz}K(is=6z5 z`u#@F375fD>#U4*CFf#Qt1Mj<rOXjb1)Rt?3$rg}HM8R*wcO}QoNQ&f0E(4ToBdq; zQ<aNULC-f*-%9;j7a#T~CrEqX?YUz@w2|f|Jqs6$Jl@I0Vs>)!&BeFR-@d$FT)z6| z;&0G6*cww-XOAD3`%*=P-q20Zw7a@^{_=Zl$B$2v4CX0b$H`5+k(VG%AHrhwqfE?< zIq=}Y1NwWtRh8hzT9#T?AYT;-UdcU$!mfhJtX7#6cgk!*a$jH0JsBoYb}&JsMa?L5 zvm(*fd%$oNoHp0>_Oe>QKl7agN)d+_G~xm}yh`J%zb}3hFoaaD#R6U`vsi?c%+_;c z)cLC-mv&12wD7uwwkpn4B|$r2B9)2rL`Ek~gEL@ryhAW&KnE$_UcD5>nx;iaMB;KS z@&fdrl!;m^nev>m-5L}UsUTD}Dn&Kuc{GX^;vT`6KnnaH;B<K1ZHKC`03)zgn_81; z2xn~zkhdL(X)aAxBy-@I+2a2&scJ4j<~0c6TE`n6iiA3J!?$46+V(+Qs2AQ)Klsao z5E)c1LXyK^ZsjrXNRO9}k=lJ-4Fi?m0wYosv7%C7%=TyEQ5A?sVu%hsDXo?+wyeZ3 z1LSnKQB`FN&@1H3c!N#3nR>q17BH*cOOkC=_pqp<RNm%wmcdl-f|-abQK|f<JKcxk zEld|jS?y6k<2o}y1CS97f&xMZub$1ZFW#UC0%d^Ac@GMhj2%!4Y#@r2n|oKV@J+=m z0AR=ggxO~RUX5w)Upj#aw>CWj&L%gDB+jz%9S98QB~Y^hh6V4@+NDKp&T-Ncc5?cH zzEW%II~(l_B8SMFiznll5|EaI<0^*N3KZmK@YcGWAKrK_r+*=pJ<9?{c!8!<C!lV- z9Y`H%%7kh8vovH0&}N|vsD$lAY*M+AI!=h8jky#ZEv{PIaHgfHb$&(wEtql3!Cuo1 z3BC_v2G2cGoS;168nj0QTo1(Q>ctBluj!HkwS8EgwP7^7{lawC(s0C99U$Qqw6-1u zh!ZC$kzE>*&ebJi3o#RFn48L60K1U94KxA*VO7eJ6%fCUGXYw36S0dci?YsQBP+37 zf^F95XqU@5{Br6BzZ!7MB}^vUEteEmK@Xkby<xfl5F7Q#F2>_*dx+S2qSB&?_%+Q) zIZ@`vWU*yK617Iu^#JtR_iNOcBw7$V7);o+u8siMa7_V77`SJ_geCUdx@Y~iL^Qu4 zJwRJUQAr;Q@_}AkH!bMUx`jr(s`yqOFJ5n;^<nXf#NUfr?CJ`mV`y9flYH3_zFzoZ z;>*EGu2BoohN89`6t$g%kSO)yjOUwJ<#SI0piyn}fDwV6jvB1N)-r`C4MLmBW9;Xa zvPA`~kWPR)Vl(ebhR35Jf(Kai0vn^B9MZi@Z(`3%${cw#r}rFa#I3E9F4#cd0>R2S z72#c10e}-20Z^dRk#_syxbUU{hp06mNVHZYSf1#Ys35&W#3THo4d)ikzr*ocxr^cy zRNcZ0TUBgf9p+z0$VNi1v9u~IcOBcm0jj`Lj?6&?V#s9UN!!n@A<sxXX9Ize%`EDQ zwMk-VbgNR(6$f${zq>bQ;<-4ZROW2?y?wT9;(kOEvIhVQ@|MXMcoPex#&mFl+_Vvq z$m`t-5Jvaz9Djp0sM_iP7)KjFA!wXF<{e00XjPRE7f85Cq`HL}laC?uRl^$$+;*xW zWH?C~jHo%!{YV4S5ST)BaFyOWwEoR|Q=}>}{@ZuK8HPI;IARJ)G5J35A_v0DSss}u zMJgBeX_!XJ$Q@uZ7w_Kt;fAG$?FETx+Vru1r%@ncnNLQ6BAx@oxA7x-+eZAYk{Ngi zItXF(s-7}}T<s9L&T}hXt{egm1sn{pn&cq%0(T5B3wQ!h*HRA^0*7bG%8HEw-$YMb zYRhPekUS6$XzLK5ec65%^?`A724}m%;Dj_HX2YvHm1V+!uRu?@$NGUPCshL6a4r+m z7Q%o+Wo;aIz|)`Y03)WSogioyLWxVr+Blvh)R=gt7}tfnt;(dh)^*RmS12EZ1SQ@G zB<v<I$`%BMImIv&A!v|BqNst7z+z!Ai!>UJvImx@6!9#=s{4`)MgVA4Z^GbF<x=O+ zirLIF;Ea5d6%}IMh$s5`N^SB^ZZj8H$+JM<CDpjFk@Elt^1d6nr}*Gd{pE_)2YIPX zjI|>_Ny3rH8WR>nA$GVipRu$-LTn`l-?H6h)YGBd(u}ybB6CM&0;dG@*8O4(MgTOV za9C7Txz#aPCFckjP%xdL@>Obe3nmrmCK|=FBp8hBh}%w`L>!zB_y&smL4cDj6^9|R ztOyb8G>rs}sdB;PlEenUqvfq>AkLKrm_)f6iXRU*fi1QK1)A`8j`dC)Vk|h4CO48Y z;Zl(SY&M*u_w2-LtlTWeH9py)3w!5k3RLWX$(Xu2U8k6!JPYVqUYr`U58nF`qhrT- zOxV0V@79*aAar{IPLcdzP~+dh(AWt$40yQa?>jZRjyxhR$hsjuJ*cbLBwL<aE4_Bk zPXccQg9LKr{b+ZS;=P|ZuHk)AMJSHZkA=!Z1M=b?tN<$NXXw;+CcYFw6jzBC`u0#u zA)rXMr#LT0FxI<5^DP9eadwIUYcOtwoWX*&>^(4P^h}yJv#$MA`E7AS%Qs*}p+8_r zvjOC01J@4^5v&*I)_ogFO;ipTEHFAcXb|h1mULL^75xBDlnUq9=Oo~?7J@4}dxk3z zZmXn2Qwb=rVmZ+0pzC~KS6VF3Q1v@%k9n)jS0J$18)=t2oRRU1Eh879XzelBT4$y^ z(;Kk{&xNT=atu@&r6|N2=ti#t$nAg}=tbwwP891QGVJo3z+?brx#W^2R(;6od?F~R z^>V`6+}y=_gYN(TI<NyqAUN}*o7b1GFXn@00Q^w1fBA-?W$Uz6V2s`&XvHCN54IOV zAdYA(-}}!1q3*M?2ZPGyqzqqt!K3-LiN8Y11hKh6_dsG==jeqXND*7ej6iOZ7+>8< zv5WVRwvv_a6*rPhg8$-@>Y&EzRZm-+_7srh2s<=@k~HUB``~CD<N(k-4;^1X{UW|~ z<!{d-n5XbA)_&e&o*fMy`Dww!?c7q-2mfpU{z%pmP?bk_8j_f>?J*l|)d>yx#a*mA zvwF$~v4dOhi8YU9#5b&)9_e6iUf~WM7uw|`qt2s(%Qw*F*Vys@HFk7EPOOTy(cv_x zPYN63RaIozykV%v0+<%s5l2>t>?mLxqC(V}SYTmyuQnvDO+eSrojyKm8oeCHJnc&Q z%H(kI!w*FECl1xY(-uLR%(P>8bRzz1usSzY{zR~CZWjZ2Qntwwm)}Hi43+`nViQ}P z3~Ml!DXmq3xS@zs->$d<)zHF_A?dM+pN*o1-Eo)4c~D`U4-NO;)&b#BQEL$L<E+$M zLK4(ZODs9Iwx``=@UtjqdM1(SI${(jjH<7L_dxg$Hmgn~cu>6SOnfDg6V1fACZ?)` z>GW{zm@P9zRB4@H{DUha2!1YP<e}8RAR0wjU{PTL%jF7xEWjMf%#Tm)L>fuvnK*fX z$=Ka!j06|bSZ3ibE}R}9rzs-wEeuXN+}|sNc?`q0dB$B)XXycGAVM%DQZtOz3*1g| zhn5Gj0P2e^kRs6RtLWLtB!9t9@aM5sV9TH``-cRrGF6-VALlj@!W#F5xq@cXzv=$* zYZ9Ip?`-k0g%sJ_72@i;wt_P(@7f{)BsR!?M7}9wfx>Q3>f&2)eN??VWndIs2HiMZ zW|bU5@5dZ%$ov_DjbWhC?ssa33G|A$JFUBDVhheh&IRvF^Vg2j-z`$L;T0CU*EE8M zVbg0CZRH1U;&W*mKl|O+!>;`NzTRn6mn0OuG~2BNor!=TuwCvIk^*3xDUyP=kX5$% z(|#jo_u-|x?St93{hRw<o0dG#sQuAT`+Z_y_V54pa{rb9h!U0=-h~00GSJiDP)Tmy zGI934rx7G=U5>ZX;oeV62Qd>`O$kVYty|-uU2KacR3F3JjXFCZ<ZjGacPQS*9O<3W zQicvPnEx(dKg>LGeUK*cQA>n2U`>mp#!cMq4i-Ohg}1n6_;5Jc0r4}8CI|Q(S{<K^ z7A+~p!_7mUd^+Ot@v=c$wRI6i7c2%}lYlyL!*a=_-<ln65*sDLf08p-5KZcED2O!B z0axyYSK!b!I&=r5HCTCn5y3VA%hFOYxHr(qKO)2+jG*UH!3Fz5C*NM6!7tjb+@k46 zTmIPw+TH&RC9#kIBh~&e5IAP3wcyTc0V%MHby}mw4<?2?^?0KJ7^N_9KB&RjGw`Ec zg6HAT^;#dcgpBZ~m_aP3@CK3ILQ3Nc7Hu$sxV1kI#X6t9Ak9b}T9O`Oc%Z=8uA3ZQ zRBf*Y{LmEoWcXZTa(F6uPgQTgU-}Ak%j;j)ppRaI?zOeMypB-Z&$brZS`lkOnxQ{~ z4LQbw{Dp=^3)0k>(RBQ3Fn-YnL)Q{DsJpgs2NuH~J^~~#try=yTqVbK|6qM#Dthr} zF6z9kFSylGJRNgfb=~XT-H_q0a`fHuCpl#A`h*pZ{-T6ChW2DGo*o$k@~l37ed3;# z344yIHBD)8m-m+@YMlY?AQ0j#np1kaDuL%7wAmKL%^}O<D#~;u_*UjhV%o+>4af$$ zVcP)4ZXC_=ykaYruL`}xJ({i<iyJp-(?{E-Nhh&QQExzPYpo$}%=T@7T<~Up#Ayfl zo6URRSEwQxId};Szmg4dHo0k_#QC1q?Pi|sL<3^y1<-!PO(~hW;r#4uUFXRe9>)Rd zYb9?bBwX-_H~!}xTY!q6#v1p6u5^q?A?>j+s;lD$n=C8tD$5KiTi2s0Yl;U1(wcU| zxQS5uO9Wus8Qb$<?L1La+EfE~Vab$g;qpVtn_npzIPN&Ax4PmD5km9<Ic9nw#cplJ zt%^|=DCPX~#kGs`hZ}yKnD*R8yT0l(6Y)~jeK|fJ-5E*niSYMqMGCPbh-FWr*7#{c zxM&;E+#<<c?D`9^c~fZ6_8r^#@X%Vya*4INV7Z*xQz$el_zMfG&%54?T2;0i9qCL+ zMY=I2x;=><qg+pjC%uc6;?eMs-wn^m;?)hvUKI{d!x7J23~Sf8MWu2+Hnf#W5n>!Y zXP(SP4yZboHf3MFIigN(IeShe)nICp;LFgzhqjtLx7}vFdSrL%-}L6~79|+2zn2L) zyDrdpZ~~E%3V=E(kP5r`&0}-qb^WV!TbuB3mNM1`$9qu~Y(?(aX0kPs9r1YR2<96F zkS^%5@iw}*W!u)_1b4P<o36|L5#~4rpRq3RG@jjK#GjpjP#^489^=Ofz$QM6KJ+>Q z%6F0vXW@*&`5L`{yjD57mu@+BU5*~(uped!@i<eLH=}2mx3sN_w$-o82$2ql24R&I z$xWsHiOJCKpZ@o=kuo*CJAFD*MvE~XdNK|(uXm#_K?fe#y2>fAe`B@}P_Zqt<A;we z4k|aHZTIfM3k%~V!+1ZO8iqivg&76hz7HMJ^OhuY8h8kJ>O4ee{+8@i*l!?C9`8mu zqE^!fyvNUO^DKZ7U!DsfCl56~3<$H`^>(09V;lQRejP}*g<DWM0I!h+z;7r*cEtPG z#FPA~tg@;#vho6i7;Nl&Xah87RyGC4D0kZ;lXhPLpvnfvcO@j8{{y1VCoPc|f24;; z#oGhq0&56kurE2<wM-faE)X3&aU>q4c>D#8+M|?q9#_MF{E-L|4@(r^81oFs2*tuV zATX>HK~UHg`Ewf=1$+ATyp@Bo<;D&O+#bc<hU}QiL>@K4=1x_F8$||qqNfQgj!Nf< ztdH;*JP^?y25OwDGy2B@>R*nCJiFNuKGUVawv6LEW|I+hY(6JM@M~&gr=-2v{lKRw zwppLCM4!WFyGckX7gMIKC%9#mVSo)|b9m-T-2e$uJZh1qU7HC<ki@oEw&`p<R<oyS ztL|=UcQCns__ixtu5WWtY^=*{0M!3Z$`Jtl<}EP(3KD+5$NMN!_=STo$cwo_M1cr$ zyA_Atl7ib5>@O^gi^c_Ybc-gG%+t~aeKe)u;{#ZAvRO_=UtJp89gO{%xfYg{0Iv!R z=7<+N>`Ku6*~jppB4Ovo$>b5k+*etl^?S0BGahv6ixbb&xHN7lk-y~x)S25V9OfO! zBdlS?UP})Ee%|No@na--gbP!*5=+$*Ke+W+Lx^0;>haUxe*M*xuf470u{J%q_P+Z> zvgLj^4Ul&?mcI0P8_S)()uqBun`&_T`%?`I7jWXc_a~huwC+PiMtVE!Pg8PL@1bv_ zDF&yff%vkS>NxMhz{Pjq7wAJ5v<D9m*qvgj;19GScmCi}^#IKIIQwsA{XM(mW37UT zLsPedJ-@RqBjn!SJWE7jo@9OE+(VfAiSiQ&@`nbeY5Ig6+-FBnYLrT>=d+$nH}mXI z3vcn!9HIH$Rz=F+I{SzIM{ZX&2$WZRHPm2NXGY<x$KKQ({BwV>)`c{AP;cXtqp01n zl=OEPz38MVxWx#vWD2qYT~8L;<3-k(UwO7VqGBfYm^(~5zCPB;)*5w)r0`2*_&vPX z6uMvE>{btK<IY$1x-v&CaMry1eZ~(wWXlA<zV`ts?|pL5!`i5w#IIU?6+Q8exAb#O zSJ`#oB0H(xba1<E0A9$ekc>v?4V*BbAU(iB#J>ShO9KQH000080GS25P*qVXEpsyf z0EEi`022TJ0Ay)%bZlv2FKlmPVRUbDb1ras?S1`s+cvh~@BS-Td$OWZnTg$x?WlG7 zGHE)^J8hax(s|wExH2VDGRG3Bl9U~F(*J$$7eD|6DLLuv>z=bbZ7fm11#oe3zi@GJ z6dd0_4rWD?<%@B!sprRE;G2V^gQMU{vEG*1;;Ih9C&S?M;mPSS{PS7xk1UV3!K?V6 z**bz^-)FNluhJx_i=e(rgBRQSs>p*^#k{_a%QX15*yKrEXYdX_q-798dwE@E(@kB# zw?&zzt2D0>)~hrPzJK=Q>GM}lqxx+f#CZ}t`SJPdm(Tw8)9W8!zQUJK?%*I>t&6e_ z7QbcdgLzr3f~*MS-QTu#T0Q$w75QgX<m&UXSS(<m>T6M{PwS$}-mc^NO1&u4gSy;~ z4+41PRee>aG2-bUeLG9nb?}VdKP}6m90$QsurA}pDjo-U0Ry~AOS5vaS*^Ac4I+pu z1D=%mZJA9Ecr=l!_f1yS@cJpW2q=`FXT=J7s|tmia{139%SQoxSjT0R(x*+{d_Kj& z<?#x>sZXcydPIF}J-=?!4V3(KQ`A^JPpetHhEEmDTE3Xn+jUxvg6Sq(CX-^F=4sgh z=)2diU%X6{tW0P1cQBbtoc=2KTU@2i>rqgrZ)*bG0qbQ7-Ky#l0VS-Df}dV~PoIW@ z7of9v3cyYD5upL<M%K3%fQ3=8im%g20<We1Dy?ILq3Zu2-$(k>v-~DrW(l<_l>pvS zPsJ>rU8TunT>@UpdW-0WIhf4KGyxjV;w2ysmdmD0C)F~puDpY-*2}D(%(G?6Q?^KJ zg!oTD*Mz&nP)k4wAQ4xO7Y>&~7!$zq1Zc7%M7&B%`23<Q-a-fSqFlj{e&d1)lTucV z3wuz($gnp*LHF1AHckG)rA%zxUZtr<$A96MQIJ&=rr2z{Ob-rl83G}ksr48E^zZ3i zIN{z-h6e}VJ%07w)0Y$c14YY}h#pW9mV;lyH@6=T&%*Qgc>eJCuNNN=2g8FW-#vc$ z>gj8@?3Zt<`?D)VL=B(L;QuhXKZHMj8H}*xv*E#auYdS{f^6pL^VgHt|NF&L8^!=B z^TAcUTE2_dFf%h^W)I$mSM~7g)e@Ti=IOVOfBOFQ<k|CYp8gD#2Um5yuEq}@thehd zD#`_Y7#tiV>6}m*FPB7iiW+Iu6|Up6=S7|lneiMR9v(2|*PAjApi*E~3aC<Wofo%x zFx>*P3^HJ_ZzHNShRKgtxc0}vYhcT;RDxno9NH{Z66|sCI9LK`EP>51%ywgu)vs)h z;9+(H?DSYuAig{cETqtHvt<U93O^b2hhv7dpRLkjQ=fejJseU|&3y6UK1%fn`#D+1 zv+H;PDC6RD5J}6WQH9HfgW0mE(!mgl9n4_4Re{5HLJuo)u>UyVnjqe8i}E^%OB84z z#ipADpfae6l@@xRM5obP=<hNGunxA4a2m>VP&HL?GKgKN)iwu#Nbm@dR14E+5z(8| z0LuI{-Q@Kq_%TnjGMf#f;2F$W@O{B#8C-!-5!rJjn5zPU@F1SfU@g|rWVWn=X*!EH z$SUiginkSYhL?CS7)X7X+G(-a0MCMD4HP)5H;8Adb5(4XNq`WrX35-nP)SWBHylj^ zH6rOQh{~#JlLkj8pM3t;&lyd)G;rBWQe-BRPad9zRl1zx8vS(?%-18-Qh@ucs>MhK zSq+;B2i*bjRuN@YL73&UqQpsEZikA1R-0v=t(U2btjd5ARs{(1Vj53jm=(}`uqa@W z;ZS~h`3$ff`~)MOXC*8at{v&xd3wvFkIO;7#j4lo7Uw%0ETv`OJ%de|4U7@Uijtzz zvvG^9>qex+IaIi4m70QXajoA1SgEGgYNx(puQ_u`13#%NXjkbNA%h&6t*By=5Yid& z!ht;o-G5P9LYQ9^0F(I!m?FFkhois+E#R->Dz57?l%WF-%XGbrXX%9Bxah=3%0_m{ z5U}QNCS6u(Clo?9^qniZ49dexqJ2r)uk-XiY7rbzU8|uJq!07OC+>^?>ApBs9Fi7C zQHI47^^F!YB!0yuk+PRux(beAse>#>J`&gbI<+K-!w#!rQ^ItBXa#i$e})c)gQ$+n zXz?2^5BfO$?NoiHzo75)cU5Nk+koe93L>D~w&10U1r<!+ru6srYAF>!i(hUM(AC^3 z>tsF{3098`!C1#II*^^D0DumEdzH<u0@8P?U|Vd0+Zd!9h>2BP&#oepy1><9;5q^e zR7c=?01DS27X#iBFXAk(YGRetMx!eQw^@C~{B@J(Xe%%v=Ay*<TMY*VlrOn0SR$bJ za33cG8<<|KCQUJUXgtnmDME;w(QbfK0wY~-Z%{jrry2ZH&aQ?s?)HEQoY9o<LFVqD zPb>@2pkYup!rOH4F-`)`lbQq+4U<WhgHAk=6~z4IY#{hG7rr7ee4ara(77`pS<;Sp zpbf_sC5fSpgTIML)I_~3ifbbCRZ*c)I79tKgf-w65WVeMxOvJZF{)BDgG$B=YlNSm zDWnqM$<;cYW%Depx}YI|*#-m}wEyDii(}|Yu>!px=vM(eCRu!WIasEPc(xr}UUmV? zm}*oHMVp5O0aK5JZLM0Qm>1g@&mu2^aW<j}89gwU|N7njK}iAWq9JA#rh(8v7pk-# zB^v4#b5CmAd=D(VhUr*UBLmiLN+Sn43Q%ihgES~(S_Z(4^5CBvn7vJfV*|F01tPnn zQs>OFX+u|691e|EpUq9PEF7X}oq=)$I3+`fIUou%>^QIWQj?$o2&W&`C{<FLlo)kj zz*XW|QQ%mMQtHzeNSr1ruC~aAu_s^>5MDs6Dl&8it@`BXEA$&l1zeuw3W)v}{u>(0 z5r@uYXhC)?KV`V&+du#^@3@L@V7_KV(21Y0%Cv%Y4IMadlpClFEHN)?vyV}_TG!if zxLc*MYzp-dbsErMVBxo5rKiJIQSMR%HXy9K&?z83ArsV7>{z=+bbe*|CbfPr>(y~} zJxO3n!l8i<!X$U0nT8n{8s#1n@dV4Y=V29Zc`l|YX!m56cTC4o@SnJb06RpZ0tMZ3 z^;O9XZWYA0@zy3IgG`2QuZd~6oi_MMM8(W{lg10-))V}2b>TKmy~?gPV&T|oR<kSm znd|F!%A*rbOkaor+U=;~4BR65R{WFmEqXzNMRo&oAeG4F11~|>Kqd@|4b0VgO`gLW zu-;INYB_|<+jMO;3b`;F(7g0J7B_6WP03HTBvu1l26^yiN~)bz1vs6_*ka9#l+ib` z`N?gzTq11bYN%3ZK&pVU3r$XkatL&uY7S~SDKNJg+olQ{@~9405o6KkMg6Q940)u& z!3#3Pn^7vGTa9zzur!ZPW)JoT9Ymm=z8P|iXO&Vb{_Ugq6H^`%Qe~|Vgpm{)iRfY( z5n~~tt;dXB6J!h6k!8FEDk>1MYd<nU!!b3JJ6OFUb-1>POm>c{g6R@%YIF}|x!KgX z4;+;^$66N#AlKZavKC_>zF!|TFtcHDZC1)8VR&BAQq77oC3~F72n}UF75yFP2i0pd z>tn7b@}<#2NQaqS6$Q}ox=iOON`7<_H5%`{O^nKu=AY!+bVgWqJld!<IcLqzPNZIj zb%fuW(uTQp7Q8ME$(&Uac4wbykP*oK3azrxv?ZmmY2|q9&~$XzLY5;%wQQ4y)l<u< z9+Ia$R4opLB{$YsOO*gL7)}~;SfhcgJk|qZGEtt^z_r@m31_e)-QkhZ$&to@!Jv5d zZNfU?J*qC{g~<j@W;6qC3!)peG=b2jAS?phW&~PGvIOK3`y~<|TSEI4=&NcxlSm}W zFhk$B&BQ}2m%fdW2{kwnA4PCeMZs^`dT8;u#!S<!i(QTL_y#PLDo|SkJP71K^a|dL zbpM()fdUt;FD?j1KRO@rB^&w5oyZPaAXJ6?Y?;;DAOuQk#4nW?iqe*{2$2?vmF-Z( zafTdU--*MyP83&am<N_}SkkGt)M?Ax2jCt->9z)KcIm{eB|m<|9d1|V&8H|y!R`zP zAa4Wq45DDUSF*$99y*&0y4=G-XoG#ZKgcfjYi$9_QfYPs)ox&qaDQCaXd01bg}{Kg zRefCBip4TKwFZzl#6>T!x~PKnZM&Bp{WCQGA_uTF&iSM+Gz*zz`MhY@!Cu27GZ<Ga z?lfeq9tZ~zQKF#hy@*&3I;?p|OhdcE4S8UFGuqxDbEuk?@medrd4RiwV304;p{*MO zW;0lSmdXVEVGKcin*Qr_TLp(WoWoIYD5yPbc*>zd-62iEAz<O~%SI6%vB%H=>z@{) z9Na)PHG&h?0Z)gnazayRZ~t<IA<6{L52wR}Heaxv2VxhA+@N3s+O3XP6$TWfCFu8a zP{BH7H_R#i9xaPobh$*JNS3uo+;p)x8|-1}+l%pDHP-YE`Xi~&*aY(CF)hq4M_FJI zB6qy$=?cbRY*MrR6WV29G%FkJ@p4g&fL0b@I01lFv?z<s+Ent|492O07$4bqFUo9z zxJHc!!&r>==`|7+emFlqxgdf6V6YpF2Eg+%RCJ-XbRoOfUVn?yr&wRH6)^)mI(cjb zN3;u9t!cM_k4*s77J+Qw!NjA!<L`i<#jBAUB+=gcZdJ%>m%-I6_iN1tU@dGyLF8k$ z9o-f<-3{pl{jcuj0M7th0pc+_&|hAbp01*zQ2J{reyFQy+0tJRcnMT#qMyRhWl3tO z+<D8*;bMcqaJZv0Ym%hL4F+fnigrDBHhw;cq$uvlgg57><BQ>t<k$^zFvbe)&Rq2L z<9F*9@lxt=G7QGr!z{)}meg%r;yzS3$T$#+nFRKV?G@j$Vq>|e9j4K14BeH<qatU* z>gY(tqqPh*-KvlIX_d)qO19YtTMV^!3v`UHy$oAC6$*E7H=8d*|EO#`2ml}LC~#CY z5zPB=4xG7qKO*Ux8`+se<VcebWKs0;VLfM^4O!YNfWhSeBd)vIsZgTH#4+f`<gK>Q zcXUwSvnT7sN3qY{tc*%GtYa^>Np%d?xgXP{TK`7IiO-#xCq735iSxp+P-LGKn&*A` zTHta#_rYa`L~=KJRu50~xy#tmt42`009vs)LN2J2p=Rgv8J>gII$?!x5Zt3;*a*Mb zWjjvTm5oKks6zXy%X=s8UeYba!EabH(=Ba+lm8bB9&*X*&?sbRp={{LZY}QA1_SK7 z8j4{#y_C?jI5<6~Sc4!m)!ZQ&0vKsGA{M~@|KJHbSC&ni*gM=O2D1&>%d77mpMLiF zh&>!XeDm23r-r3OLyH3$9=X2|Yxd;GujqY)-_CVuoA;8f31i`quj(p>9--u4C7<~s zl+cQm(gM%VZFHwCL{;ZR9De564g({92f`VDNS8544UC8ujrztW0c~w$c8!Zri-A`A zjHzo0Y}V)rP$AD0HLZiMuxRg^_=ze5X-e0O^+28j3O7|h(wZ^d@IyBF8^@bbo!t-; z?lEfw7yHW_55!fmOe*Rk7~z%=bFob0yxEJ>`UwRnik~Cbem&*rG~Js1B_T=<HW{sp zb;yFMnF3`&n?)4=v+P|RIi7nd4SS+DA<m_+y?#~+vAU|(@%TNqvB1-j{Gp=~NTiSv zk22i1F?y@5ZvCOzcM%>-l%#8MbR+Wz6si{v*D<)pIsEQn>*zE{A_<H_a35Ll#!mmu zlF~cF$!`75+c;i%13y5IqAIN=rYdYunAYKN7{y6qyJ`qOvZ*O8yJJ=JD>!ZzsO%x@ zcu0MY0XGO#0QDJ1Vsva?X6(qeVzVswy$W*RFgq+tyGuqNb+d+Gl9({#M~sd)_o^-N zHZO`GJc%9-2e<^+X?Yc|JHxo>;VO^L0;n|#z6wt9&qw(6li|SahJlSSdK)h<(T{L> zIl>*&;ue2DmI8WPwzu`Vz%4mOe-Z^hHZI0HgTieW7AUSy(l}NyrY-96rMXXhsW*sG ztAsJ37{0t@0Too6*;Tt;Yi4IEenE}n4pP1()5$qL6B?f_ZdTr5^O$z<-4k1En#KWJ z%NAALD^YHGTh?JGPRL7(g*lO2%_j-Emlt6fdE2oKH7SfXSrFc<hJ%p;I6~Q!hVpF~ zHRp5`BpnlQ)`b2jgQ|>d0~7FyR;#Kq3?2oifL}l`av@TTm8M1dBoZ1>Cm7wfVRuBq zfp~bN8Z{lj(&C-4N>@u373a3JxtT4i26M_iH6gNX=}6Zo)>KPgRqmQqC}O9hMxX4k zAicq0_;{VC(gdzK)m?TvU-uZOt}`4^n=~MJV@l8R_4^p%<P_Cx3Rg6ON4!GEqO6)U zzxLbFG(#%DuA?ivyVD+Yb)9hti^<{!y#TC7DLS|=fccZh;#y-Z@_SEQU)%l`r|W8? zFc5BywiGL4OL5oCVFW3zlOD{<YNR5#6i?cyRZFL$Q-54^glqFm*bIDZ@84pnT|1== zk)qDU6~z5$RcrK5DsXP@N2o_Le6>Q``lU9%TL*8-D1BR(v1e6F;3xl#x~qKj=uz6= zHz7{e^n?OS6<7Gz??d|TXjryhYsXX5EF>*}ioFob7Pq1kKe@MSUfw0;t7Ly#O_UB> z@h2}%wAI`&<h}@G$EK5WDHsOv^2HN%JVpLG=TlxAadsGYR0Ti(@cl7VYhtLKLn*;C z3TXv}xhS~{vp7for2>~|tyL7w5v(!}d=2T43ppM571?3L%~8DCCtW<p7f2PqfBzbm zxV4A1&)Ef6L$pqK@~Hxvd>MG_umd+b4qoWka*ibg)s+zqqW}bLW}TsmR5rBdgLmdo zF_3}k(b-duuJegL0A~NT=lM{L)c@{?O%-#@Ube`8KJ`vv!HpxCS;ZKZwV_1d*M=py z8ke*$O;40O7K0eghGs7GHj-bL5$0ur6>!8nl#T6hEIc^xuSD(_ZzX-={!AaS4|kgE zQZN#q1%5tff5nBrU?V)ZtajY`i!V8)g%oE_EAIv!T>$}jTa-y<)ln~jJ)d86RIE0u z6?%rudh*U`OFSK>Ar&exE#ce2<MVmJE3Z0#*p{D7r%aE6&y`{JDcaXFVpZz!8>mP5 z547jNEr1kE!^!fF!Q!)f1l*y!4Z!H2&u`N0G4TP|<qdMAVIvIx^VN^f?<x(k-k=Jw zDqy8f%Xthk1!N$+ghjChMQoMHVSxE2XTK%J5)wR$B2kB<QAPrFgK(siRqrkH8fjt- z=sm=VnN@?a{-+TX-J$*D8_;p}at5q{H~9BS5Bm_dh0GCp_8(y49Q03678njKZ;;<I zPoeF#T0ne!j{daCUzk0Xk1zpFI0RDw&q0Sn&^hO1Jl?i6VeCwV%4-$2*&VrX_m&>g zf#iIEi`x|e$!?*N>?=-^y9kox?jj`lP~nlZ%k=SO(Fzj9^gO!$d4nA<=Qg>vhSO%< z`wAY@qUq+ghLEbXxw0Rp@8<H&KzFnIPFBB1FOGn5+|r>O4*6DUT??(cHwdE=1gp}} zcVO!)&_}(7pC;%tgS`7aR@}FEiEDTpB&PkQp5kr`Q>v&1D4)DVnguAI+NFF1U$_*n zOYW<VG^AbZ)JkX`K13}k?n2~7h4-R#W0dc+7vux8FS#FeVUYE@BNx8A<z?crRd_EA z)nCh@iB_RKx{A*po$N<`AFJsFbyt4l4-d3`P{u*!^`;JW*0wNp99ZJ#OPh@l(mLlU zMS_9KlP2QvGx$J<>j&&ve?AgER7i!&RJI5zI)%o;`#NaflZy%F54X_JrCKd9&mr!+ z$62{ORuL~{x=7#hK|~HSQQPU_=s|C=z{5TFe0GHyQL_Acqz}4R^h?b=C=Cv;%5;7h zq#5z@Y_&?0EUr^%d5t@mNty_}!v2-J3IoDCU%?@;^}_}#ry6M*;nW{;`cB}1j<t+S z<<3fq4eFbu+F_0m7_9!v{(JT1SVjV3B*F8Z0uGU|O!Ec6lHJhsEuz0UF*3oC238_9 z#C`}}e?y7bFcaI?<HPXl7hl1<lSk*j9A4ZX9=;pMn^Sl*fH#A8^5PSC@d&ED$>Hq~ zK72g<`T$#L!NYSlHat9YW5I(LHoSunA$Iic(^l_3b9?u>1r2%zqvZs1!8`o(ivRq~ zv_7FUI(Di$sPGlOhHlWPI9uKM;PB$>5E?stbn)@f1=^h<h4Tb<pW5`h7n_7LKjj%} z<+OMjdY8jv>}xc$pUhBbqy5s8Cq!x9W{ibv#nJb+e{iLl7nTL)hygC4hT3=F!fioL zT!bfry9u7P%_pTh9fR{<;^W^Q9{=?(|KsD)gYlPVU;jsRbZ_$J&Aa0ZojQ;p{D+hD zQBMi7f_=<P!Dyw@@6qbQx}2_url2l>ZS(PZm?2+eP&_R*<jc-VmqU#BOk@fM|0>Iy z<VB#h(IM^{v^X$C8>Lby9X#W9VM+-?0Oy;Mx<uSo`vBZQs+13G4BC@(_&NjaakEAm z1Pnxn_SAjwX(D_?ru2ojvW-hY$UCD_J<Sh&=b}hbTMk#=aMcIKagj%JOeh7@V$iY^ z-=y}YnQSqZEF28n5h7uStnZ%;E|7)ums9i0C-lWPKK}hvv+!r;m(K@|?a51tEx4vZ z<g(_MPaMUz*XPihHz_UIXWR2?Fbuth!6Kf9%Xl?SV&DV8;NHD^r*F}V0XB4~R{q1` zurm;fG%Mb8fN@(HfBq|_{ZC0<!9j#q1??+iP)$i6oOq;G9L<s1Z~<PK*B+|j9aaS& zw^(I3^*E@{A6{U;5Ndj6d-VO9(<|DydL`?#-&^=ty9#-|vkp}?I#gwDqG<*phb>zH zhNPO6o4jiBE^^A_N>V-`7M?x$@k<PvB5sEA2TyX=sBKipkAg)}uto%**V%f2x*%<D zVDuMmdrK0wqP!-Pm(;KrRL^1qJ&UU=-5nfdqx+%ME1S#&Ng6MivEIaGhIOB?#5;bP zb8>9qMU_fciL#LrBsC%bn2c-*xEYKol{2}uR-_a)JY|3xtD%6*>2ypftfRlfKi{I% z!EHoPbk8J-b(nyz&t5VEMh=|Vf-&VEfA3TVtW7jNKA3M-6GR(~;_T$%d+$c7-`&l~ zvM6eIN3ty@q?YuIYsy@mQ+F;*peAG6wr$%scWm3X?d+IuZ0*>#ZQIs-bFSvhMgN9g ztNW>{3}jZBIX;xBW(j4RRR0VMIh9#8Wy(&94^-4>DTRo?VFf!fv^<Z0SZtps`jB4X z^yQfE$N2VEv+|~OJ%!eUmcCU=mRnLHJaz!rn_17bAA&=r_GxNde5z~B0eM8TXH)Q; z6?cg(v=r}U9hvoi&rS%NV&o4^oz)#pgCOA~zUPvvP`E(S3oTVTW0^;l`rc01z;$nN zMk}0KB^iOMRtu>KV!Lef{W(UeU1|DvQjf$(Iyc*Bo`a2Bg<!_Q;iSe!ODd4dZpc@_ zWQCn&#UA0Ad<-S1Qu?NFmzqbiYH|7kofe?o{sc9F92us&{K&{<O8N+4P1Q=hXMRXj z?!cvqw3%Q{f`etrF!+SP4Y$?rMA5`6rOWxF79h|lrX23w9~~_jS}9EWc|Y4=!;?eo z8#y*Z80}68lr+6KEf8xY7Is0fm-ZnI6_Tk^*!aj6P}_siz1o7SfEEnu9v*-@4p9Xm zf*E08>n4|HE#10KkhraxFjgdOFvlFZ71if)8Az#>|0kj%wzZ+bVl;xE6sTE8our-C z2(x|?@Ix)DB0;pH7xf=zeOLHHQZ-7mP|b0@xQVqkBao623|%rsBx*M2f*QI=-~69v z73K~43|q}`<|6#D+{h?<!lnu3MHgL<`z9|0z3<&7`zy1p`~l78B{?uSxc4r(>VUqA z5a2AieOzL8)}&~nR#FnOg2o{!hOWS8UUd?BWK+C!w>9GvRQ=B96tkJ7wj#Gm*ttEX ztOgNt7pnp4%A$4-vQjbKRM5g-@1oe`BG}Xq5lx=!UH|Puy7&RZoim{=*fXckOOt$r zKkALZ2Z(0&pzym=ohbzJ{WJb}UAfZe#sOzEkIlMj7PCh?eVc;D4La(jeUr{<_|NS9 z<eF@1hs?nD=jIwSUs2%qNl&--t}(*nGwd=wL<eh^vh0@Pp62~)alccYkG8TcrEZsu z5OG(|t`|OuJDjrZqm}h^oih_H&kqAQw`Kom9A=?GV88ULq^{d=syXdipNcaBe=0D> z8A2j#Ca<ZfiAG&v=V+pWLtCC0l1Dl|jc7D`A0UTmcvM<??yFJ(#SeKrHP!rb&vjjH zjUO5UfGDZJ!ne$1;S|F<l-tk_^VQmw5n9omFZqr;uM8^^+6{z|WdCe};OT(A0PjNk zYF>D;md;E=U)qS*&QQT)T+P6WTGNaHcE>+(91l@&!4q7l7E=(&Dz?v`W?N%tw(<24 zLqUEeBJ*k*Z>FxIvS)I2Osaj%Omf3p)WdpPm^zg4lBG07g<5{Jk1<7~Ten(lFdhDk z8i!s_!BMpn;21BX#zx3R6UwK37r1W9@$44n*rYp5|F2P3DT6P^W2-Ma{m8>b`IUdZ zG!*|w^+dXKf3jqTr9KVk_t4&a0@wF?>#gQWnWW0DI9kQ;t(sAcTq1T~Xevh`J+Vg= z*Y_sY;yWQwQzo2<r^`jXT7?XVr;l`UjK6;|21uZLxv$EmqgBX4J7@5<lcYK16Upof zdg55flCPLRd}$P0WS}35$CJf%Q1t#KF8F1LnjZ5wQ3TdK$^p`DyRaDX$6pJ*nooMh z2-)QOQq;Q39iE^}OJw!hoT90Z!{g+@WVvG2be|07;3gU0K5aIa0X`XbS?$O6S_NO( zTiR4cd;1N~^ERT@Hr113LFYilxlyl`(-=+_ON({fSFW;m7;CpGSkE$h%a#3&8|_qg zl-o)?(&n^Ng8{R`2Ho3D4?*!}!meqKdR^M8ujY3~3e`9imbITTn%epAkc*nS5Nv^A zn1cVR7Z758`_7EyOQ19=b8?`0*()1f6uS0zocer#am{02{yP>0%#G@rN@1C3p+eT~ z3ITMa8QbkVs45a`cou!i_F!Mx;-2!QcHPm;`s?d7OO(5bl(D|=>t`H0bA_p<4}Q#u z#WexJci@!HXT+B4A7`v`kC+T!a=bb@gy%OvATh9}mRkRtXW8*tXF3oe^2iRlpXuxa z?Qw-L%n1HcwS=N6n<eLrwg4OKO0{7|&7()kpbQJ#-X!VNj=C9ETkV6F`TISM9=c&= zJ@;<?RDQq@x99gEr(p6qvj(QM6v;iF$1YBGNDh!^VxGvE(F!N+6HZWjQNJ<}ceub7 zhGlI598ehezsjSh;qD*qT;mh8p$+D0V;09}YfG=_NzJdg;}NO*{!eJsik*EeK9%+G z)xh0yg$&oEDT>((`i%p`9%+X>!$9x%Ju6+id?U>CNm6cAS2<2df{@7ePKZvYWM7=| zGN(lwA>*2IDo&47b!iP14MR5_YKIv_KM|>SpFf@G1(x^f5uP50eQU*>@jN^VxjSFi z@(nM_lAQk;EKn!}P0qrRPc8@uOLE^?@yC>);|Z#E*w&9jyh{<}50mcU^|Zj;u>Y{a zeRU}MAF+I+cTjr#YZRw_&B*<>x$_Lyz2{2n)|h%qn|G^tcE9t<=5&pg@d4TeeDt|y zpvpU*^0y0RG*|Gey7W#Wjx2I81^)oRK`*$#us?s2Q3Azn1?N0|o%(t=D*fZ67pPkP zWYjKooT)89X3qHxaYkXT<CGvUCQfDG>y4E8tra(wXMNSqSH!)=&yPc)r~2cIwcajQ zS8ac}sDF|ONklPM%5*4GH2P<vY>m|Om8tPS@D|9nb#`ZCy;Epz(gYN+>-nu|Js0<% zg(0J@s(Y6OTZg_@kn&fC5y;i+lg)?oGA#CpPKJ=%I}_x?nGTvF7~A6D@)q9|Yg2*a zx;&Loyxsh?k%iPAwp$NkH}{Nfpjy-rl$=L`Fbnd)3i!R9&+rjSbUn8zl($g(cc5yN z^S0a;6#fuTA0Bq#dlcwRvNVQo6pdjme^TuPjMekFJ(y#~>ldC=5PgE)ijE&mj3H%% zlb5ZU2}|Nr^C#dg^1RU?FkReTePu{uz7mF=_WHWr-``aUF49Z=oJrSd_PIa*oxnfE z(f_xhE9no&ciw;w`YE(VNWtEM<uUa6Pk(00*`ISnc?af#!yGOlN9njd1AWZY<8VeG zQm_8Pbvwz<C0FNs<4oqESQKcq=5Qf4>J>byRr+gkFo=|nOhjP;c||ZEhfa1bK;<EB z0hR6umN}{L<4kzS$!U1GyVsp1q<jW+xRqdRz7NlvU2)-=u2L=CmT2tgTHC>JwxjV7 z6VF8x27({`e2;?h+1M|^$<@J%!kkJ$dh0s25{)zX*D!vO<Kh*RlO8N0p?#@U@+h;U zMB_z=ujZ~Ug-}NWV0WaPgeYGNPzEGduETRyVZ%T;iw9G9IGIZaf4!*FGKcHB+0{Jc zB_u_-$dr-O)EnG2%U^Y8mYmub)rE|zJIW$6<uulxM|P_mh0`m6-@oh;u`Wnz{EPDe z<(H~gY0%bfhyWZsik|2-zL1M|dnu?%zI0Dl8c_z=l0hFJ{e`6H8|Lk6Fc?}7thGNp zcC(yr9Sj`TR<L)dJb9LXd`Xi>d-N5HbJvo5+#>StS<dn1n*H{Uch@~bg}wq4zO>tY z+L&N<j;6@$yert}f3SIE-7}}AY%_rDUX*x_*P-fY1Ug*oR=?UM$0*onuff*ojOuQL z_~lN^|5d#E`qGBZ8+h1B*n{^=oP~7hi4x2k(B}2dk7Y(HLS=kUhl~B0!_Kx;t&r9y zc@2F8cfr2(-^&6Tm^w4f7C2FcwEpyN9VWn-jEg3h(dv`c|Ko@J35*zpl6kSUGL4KD zHNULH>i40Z?<Jd(pwws|1K<B=-^(D;|DI%0x_P9fQki~Pe%+iU``3Qu&O(lu^gj^5 zGUaS?;p5IOoBo`Sh{p}OfojI}z)Y=6V#O7A2%JakNF-9IV1F2HIv4JVcX-J20QK&C z>$9{;ANqPlja?;uqRDtGyDS43a?RxD{-t$Kx#^vCdM=3w+CFgR!4+XS8D1Qh{jwjl zNSnBZP-lF0x|%&%x_4Zm2{IrxD6eI4ylb|GFa&ebGu@cM2fKYnzDZH@MGA8vrK_8| zF@U3qbm!%emu!nq_rl6PYA!>JX_D1G^zOL1e^fyNdEps`v<%>onl!vY1}-R{khHv> z0j|cG)uV@LX1AK=fxk=^1-5)6dv22Yd{oO+rL#^O>$P_NRepg<ba+eDK8LK@fEmod z@aicn<<obRKTSUTIL)G@Ts0@oy#_5<g?EyG8N;GCcaD8NbUf2+vGxS%rKC$339^=^ zi?6&)ruE9Lx&b+YhjwdpR}2ams#jcAT7z4<jx&j@3Ko%TW$w`tgPv^?60h}q86&Db z>8`z1V5#fwTz7d-k^VCISUK_Oknd!wMbr0zf9=5fxv6k?S_B1&fPJpE?)9kQ)ONIE z*}Zls*@Su{Binw$Uo_e}0_KrhL@}|V9%a1<lBw8icfF}f4p`ez23iL{cRy3y_cXOl zT1-k9;?|dZflixyv}PStLfZSYJ&+nvY^>ipv0o`^yF(SDFYOBXGIm0-WH5lE)VbVu zCxz!G*soxr0f7^68)*K4(8tVRdrIC7nl!8#vUcpIIAc2*1cOv;lj4q8x9BP@EYKx- zX#LgMm!)o((gXe2!0WIW-UwsMH62}X^+_z@3}tUiYF>1kQjjlLK!`v@Q@mRNMis3m zb#94p<z@Qv%x{;xyIXuHEef}ii)P1(4ijbn3pKA7!5WIkV!b*u{j^gERhfEbUV3AD zbJ5R=<v<-RkS41%r|Pd`?sh?CMEboQApJLPJ2Kb4kW!Gq&Ep1FzicrCS!C67%4b0O zP9P4stPp^+O$~$p<~k}tcm~)#UB&F@Em+wp>by;{40P+4Nsb@C8cHq#9!QCJz!~#) z{}*nN(&+;9;&s6oIbKX8q#nf05!QOAoPjn4?Y3<I$<}zVR6&p7O>|*{G~Y(;U|zv$ z=gA5iW?**h8VyIQ;ZuR`K?2iLx~XdN<P`hn?%}~$37VQSeWGjkAwv<R-!_6i#T!)a z^H-seCf)*Qzz#l9Rlysa$-aMW7M1{`w_?L%hndNlT0Pq;jM%|zTS~ftlgUrXe7g^f z-o3A*G)=)oHJkYai5eIty+9U`SrvDkUa$BF352I2P}6d~Si_<-y7hN@k+BbmTiTS7 zr4ixM%$c54&N)um-t(mg6p2~0=Xx@KPSnMyo!R)bdsA-t*6*^laz~)sI3pQ1$XlbX z?A1qiqv@4tYV-w&7oSL~lW#uAOI%X$?f0}*=|vT@OW7XeIk!gIGyGg^pt0xnexo(J z9s%y3IrclLlX@^Rxb=x`l^R1wx@i?Ay;<G@Gy2%xFtuV@I}OkxrX<s?p(N#<bH^OQ z+}D2_m%YWs*$~LD^TmkyAXHrhs28j#{R!q*Jf1E8A2M~{KM17D|1+5z2JHzw?$6at zI+-T^@jkG?WAdKUW1y~`*-G@Lz*h3k7yQ{jKO$5#=<$9zd>o%FyODOEf{J>&JNufx zz8@YP<Xry7FI%1L&qiWZ$TJ!l-Cu<QqBx&_XB4d#_=0_r$uZhcox-mFvQqBNAkzb^ zCdQ{|Ywn)W=t2C8&1R9<9)BRX&jmWccIY}9NB)m&eQ?DMg@3P5OkJ7#Pu4DRD(>AX zY=TARl)P43GLo<w6f!D(Am(;P=D;S2%qv4h4Q1mjzmt0-7T=~B7Jb;4hO<gvCMJ?$ z-tGREV&bRdkSia*ltDqEiUXXLVg+57hE%{iqc$$*zuvT_JV56l@bpb_Qg$o#zXFD# zoaA!7dR}dmW@k{+K+rU6jgCI3TQMp4K@d$<FyufBCuIX1;c3l^6u@vM=}Qo+U2}4i zYJN~9O+KG<mCbj%5Pq1bl|?TI*hA9WM><V6c@a{<14Zu;gB^w2muvoB>!pyF=AAgT z3^l>CyskJg|LLc0F=q;2e#Hkh&pCh=Xr`}1ZfJ2Hz~7V#LvMLWisPk#n_g7LfN2&@ zzi7}&l|Cy;J4H>NSG-@X<B4x9nux-%k!lSyZ-vDG>blhBV4v@n4L7Yj8aB$L&imh# zL>Nd+kSTBy!NW|}j*Y?CZb-=mm$pbIW7UGFa@t$|UGTTR=Ee)}AX0&@=m&Xql$MVc z=#i#vO__)02&N|n#nj8l;mB9}(p3AG%a$^$yyn3~lx8fELPXN6CHv3Q^vp|Zt{C5l zC+oa(yzew|UU&IuJ>zRZJ`H);hD%NJdO}APw2K-7#q_gDN=V1ANUZpt58G(dzX8xp zbO^1L^*ArRB0+O~jM_;$oEyPY09SbscM|*SN)3ti&(y&b>c&*@V>!~N&rHsy4LYZN zXUhksgafK=`{!1>+JM1&<fzKwbLZ_#V;C?z7K;YJ1};Qt{t3imhylZ!8T_!`#^%yV zudK>#8YCUa$bH0|hf7dip^qf@8kmYV`@BR72dh-D#4{O}_A2xW6iu2(o$;1OBRN22 zH(+P2e18|DXF%6$J@1U=qb;SdfvUIk4Y9?n6k^b$$3VaGURPg)kOr>qKaZWhP8u_Y zZg@rpn{zouOoR0!FnG3?a0vGdFkBNE?>9_u<U%@Ck@+7a2mzpLRYaCy6Z|&^`>wdP zI^nFWA(xbkWjhuc&$HYv;=16dnQ$1g37>VBWFmwM_?fm1tf50%!*rs~5N7zm$z_m^ z*(;7y2h*vj9!8<Jat{(6#CJsc<boQ6CzUZWAN#B_RGj(_2WryFyh#9Kv(i;OK>sxF zFuZw7_JY7Pe)tQ0Nd{zhY)XEni~jzjfa;~hb~k2=6qlxM#GF-$ouX#7wLSX=leujI zCT^~GeL0?Nw$z+=`WduRxT>p2hQrHt!K$H~AOMP~X!kC>nP&+fm&f~Z2RlBV&UlR- z<nKzWv;;b@3!(Q|;K)4dzJ!g^CK~~+7&e6IaRZ-@KTPk?!>Rg3qE>kY`^Voum83B4 zId`S2$pTyd?sC6h{5o<>Do9j?R&K=1D(VfN{&=TxFXyK#PznHQoVmHvt?F*!Bluv( zP?!(XI}+-#{|Uh>gD34>3e`eEGJAwM6&~`0MG=A@{<ql<{@X@7uAmNfLX1bx&sHfN zsH=aVM)F%!fP1OpbG=d8yx1K_eUFOw_}>q4c@kGh7+-9<kFebXxs+Q65(GF&%ylM8 zQF))KiAdU@0W`P)k`8L$$Y*h7eZ@9Q6Emw`J4OhBaY|MKK*B6#=rhlrD$XUuW$Ki( z2kk(HVfxG8YTD`u`+JNV8sa9HU02`Bh=CCvBy7P3pWD?-deT;kb?l*`lT?fw^~qQ< zi)g<`AKPV~3yoRUO?i0~1$mr+Q1%n`{q||2zjlQe$Cu_iXr@a&M>9vb0jBWMKp%m_ z3!Gl_43<DhG0onP!PKo%eu!Tov$BYIA6=_4q(-x<K|J-tBhuEP#0alF>fGzF<gnYB z-OHa+VdfS$yKW!72r<(k@I2GQ+t~2_?I*J+TAsqh24)&@Vo)^A77&0I+d$-mr<BA| zKu8R~_an_Qc~`{BeVXD5JUYz)LxjhKI(W!3Fmh&+yc5gpyn5A*3}-Ek=wj5_wplMw zYH#!8<#p%8lJlU_5%HcrMKjkh@RHtw4pJs;LmS9RTHW*7$UkcmEq>_2J6Fz%gPy-l zxoox@ir9&Rf8)aMj6W`YNEF?b=UgVSvEjIKxwC9_NkV-@4qlbDG*xY0l#ZH4og-q) zO@ekyw~vVSY=Jm=53|@w@Eci>WBph9y&8PGFs~)Gx|MT<P|6X^2A&c259K1`J)zn? zMSZ=w{Rf+`79;<o>*V2j+P-6M0v0^~IyoLC7&vj8E@EpwnQC=xg>eWbZIsz>Ew>%B zRXbR@d=-N%qeH(Mdi5V^(x&#|C@KM(Lp%)(^%hBaVC?hsrdpC+5q<I80=3%nxNJA| zR|wYo*jsfIUBwfHkj1*@3~ry1*LZgVWnI_{$XA*;B&#U`egwsR3G;(okxO3S%|_NS z`Z62u0oc@6b>+W@DbN4f)d=9#&GS=rW?_rT<MsM?fU`kD25zMnXHpT&`8E>DDo>%< zkGjso5g1aSI15U|2JkD>zgK~nH?YqeeWS!`;~~9~%v)ukb<{RYR3mQ5{&p4?`7ui> zO1cB!lc9YFIw7iE?R+Q|ylu0-0KpN@U+ABtb<VL+{EMJM5WAj;B)bgZtWQY9aGN>) zk{{}5?492|ES7*f{z(&es{_5R@Y}u_Ix6#dew~rBmScMA?~4HluZ(gWe*BxAGRp6y z4bAO-NijfOF~NzCCUk8cf@I9G(RrV-V9k!UJ#NVSgU`0$t>>!jhFap8GV*EatjYGR z>KzsEr2u@N+FDkSxNn6cS2KQAbRs{PEfrAwJIzK=mP`zsUvwkkMD17FE7>)>x&Yv* zQUa5Sg?&T(amkZ2Zu451iT-5NEa_Caakxt4&{iqnE&%9%Gdi9Cb_?78>_?m2|C`aV zGqSfbH*<0QkI|XNwQ||yc<J;9M{x)*p=FL^ZR#u@88^kZxU}+(y(Zvoom3(tYXCr{ z5z*TK1pRk?fTZpci-+t06LNCMeS@8hLcF%kyv9k9DYhKuX3Y5CxVv!f5WH7HbgN!0 z*_c!OcWXOsj4u**yRz=B3@0Qen8tsq2XdNTi>40hrNmAKD`98WBZ@-?Q({DW|1oN1 z4qxp(9X))V2@2}x<r(bBW^#IdJe}_m!IzqH8=UAqR0H8@F`v@OoAwW-%BQ5trkm24 zGIvd+NLRRH<NfGUco@OhXc1c?NvND3!szmwGNG^R4ti5#<j}h?OTUYJG&?kEMdOV$ ziED|uJhG!VVHX(oz*yxu+vgqqL4a7)rOTXss`9AU%aTL5CG8QrdU7Pgn5<_?0kE9( znbtxgYqO$7UB#b@12vt7^b<i1u)%}0&erA}GRXpTF=nO>1IO<1^lj+Au^9#CcsZdO z9s5K2aDhHW-KPO0^25=iwv8G~lV(`Jls!ffWrPs@{pS&g4zmmhAx&)=84;(HKy0U> zOpdc|wfjvQ-7`7FJpwO|{rC6#<H!4*dxP`iMm8Vuy`Lj~O#!)H0srw!cZiCNrU85T zutP9+-kQ#6=+T@C0M)$WE1@g1KLrqIW_i@1ElOV`h^&9Z!3i7DEwE3Sg@lb@DO8sx zT<wHG-a*1p*ez+Ci;H}IdZm8#KYXTM{nq%Cz$SpQ9XZCuqj(Uk&1-zme^a91mUz?4 ztNYh~8F~fzq5XOIdbxPS<AW&Ph&Z895R+|bYDavCN+Z!W#-`Czc0JWR4}n7vsdhHg ztraK8=o2m1l6DzYlW<WB?px^If}sNIz>%WiNVN8y|JFL)=w(tCrNT8sQkbGd{h1cN z*MI`m0AWfD7B&<@WX^8{s#l06awJzQGh`?{`lKW|#L;Hm<s<ArA_KeP-UIDQ7S9w1 zYRh8M5BK^<#AV_RjkbphMFj~F=^N)s4Z{uU(C^agfh#srmiB2FAg~ci_@4#PZTeO2 z2-aKpQOJ}DXauRoc=fT1g36I@4@^lHeb2$M=V<aojERRl*)Lqz5+MtD9ClTe?6&-O zU7K4vC9<2JccG3Jg7g)b=Duxw>6Ho-Ye7cnil`9PpUQqM((lXC@#Ae?3!z@5#7wz3 z!dK`pqeVe}9{1HHBL`8c)>#&_e}4FVKOo}i?&eIF-<Rv%s6L5z<#1V^offmGzFn7* zao`N&^dQ#zM}^Lb2jSyRx0ms_3kQh&R9m;WF>7$dy85K7g%`-VdnC{pz5)e@z_K{T zrCZnpBa44V3{!|UYtBmMFMzF7V{%t48M&F5-nw6H<Nif~jQNbegJSp%>Wy;Ua>$={ z9@#Xf24yZ(3r@Jt$bE99$af(~OxDWA*BPEe-{JtoIQGB*SQYeZ<8O*w+?F2RYsb>T z=$N)_KRa^uPFE*y=uU+)Ie2z6H)_~?RfN0Px=x9DINC^qy9)HbLHM6@J2(n)3`1M9 z!d%ByNn)(y;@I~+oVAhv+H*uCcaBI{&It3A?NvZU`mdYlN^xu?x@b!JW9lG3;}1gg z$xh}vX*8Sjt}p+H2({;(LfAUT>wqE+bmUSHooldDT8;B<9~A$<h05JLaz|1~$pNFP z-Qj+zC_qJO=2S?f?G62#k5|tu44eFZHKO4hZg81kdm7;BuRcs2>&N9x*D!!{nUC9( z5XERaigtjW{bz+o<Mn7FKy6W5Y(zxYxBu4_Nl8@@KxeK<7qHQSl?Z;sFN&e%O_pJ$ z()>DtNJgG$e8DcG$$G+5-|)C~{&$B+rKa&Kdt$?tuexP%umN8wM+ZtRafM-3(H8bU z+|Ri>y7~pkdI)V^t<w#APHdqbsHae*V=>)lf$O(Hk@rtYB9AURof9TuNRcjJuMa8V zgO_N@ZAJz<TcmH)+etpcL)FG1^?~Vj91-D;pBxIA?4ck-LiJmra%oBqM|4_9&#n^n zSjdVGtE@He;uB(!TlKOWZIP9kNYZ5lb&6S;pkrmh3yK1_h71t=a$oGvJp{&Z3hOlb zsd1^TN2x|!h^HKf`VU9G=;g$jVS-J<LoAFe66_*o2WUubI$fx6Y%XZkjoi@r>*eU| zdw;kz-&6=@pZzA>_hTx?nA`t{4+FUzEDg11%wm?-a<-J}G4jwOK%Z^_e+_fXj?M=g zk=r~oL{UA=2?8u7JSf}r*tvX4KD|AwVB)!2S5AmzZ$Wc!rUV@3O&GjC5u|Cw|Ie7J zKO{z_##=16QRs4Yi0ptXdaWH(fmEP09|Rd*#bugq<?z3ne)PRBIi8|j=&h|_)hQQ* z8IZ(Pq<uznTohOm8Bge_TSr1B$izYw4%kp?-|#8&d>GTengrCCJu41fJa1HeqBh)p zVSi1bK1!u63)vunwJ=mSC;A4Co*>7-hGA&ybiQ;9u{BVGV!J|MXejWE7WleI3$=;7 zhb=sV;K&n10@;<u$jH@vIgsFbOhNh-R1U$_yknTm_-4fgqEG(ojX(rn=dd?_`<;+! zr=~M|jNp6Nu7S9luC2ID@?fgOF4lwaZ!ZTZe-^cmy)r&Jt8$c!QmE}=6J7HBt-r*T z;0K`#%s*Bj7nj9LjsBx1jPQe1xdf0PWUG%DzeoqoVh5}09G-!wBo68tL=n_WVB?kF zId~eh^vhv1S))TwVZ!&5x3fI8d$I6wJ2R3c)FcwtFQimkH`vzw!aMO*FICxk-?U7d zb`p=Ao~IA;<v8rWO>YOA{d7Z9MR)k5Ve_S*R{JjKAZdVK39YEndU9K88ZYi`@PD~? zqt)7c^iPjiEE>LrWQX^OLx-&qE1fJSAi!2h{waT>Hfw6#l$&Q^Y-)vIr?S2rE~dIj z@y?h~%t~5>bLS{z&s{46fUzK2#5lr{3I7CG9H+;IU*nJ*G9h^3x)1d+%1-rPK9ImX zbBn+RD-go=XdO671bXQ<alkj!><CCY^Qwth15l;N35nwQ7Y#P-&iUFyx<5V^a&6r^ zKW-_vu!aAC8|I4GE2nK+0j-dz2gI)H0HSS}{kRx8WmXKRDonk0MHJHxTIPhERP)-| z=0%_V3!R<5{GYGox3QS}&9o@v^V!N~%5p{gxI-oP=HN3EKpwE{6CLnyG8UYncr63| z)LGP{mJ3ZZ{G)R_hpoglhAc~#H)*f@lLEJ?d($@PoqoI#t66oV7pE3s@%d*n6$9Ii z)k1_HeDTy;R+5s3#oi+tm*zA2+U@(S^(N#c!gB03!;mn!d*P_tQ;+|qd&FcRUh{l^ zG0o3b{;a|t(+wz)HhPqCgp>2TAq;D^ILB||1v<U!3soCLCEy!8wxSs@h`!e!_sT_a z!#_0?aa}oHP5BuB011Pe-RyVhZHzsBmY`s#w+1cC0`|^kf_`Ud)oFw*BB{~nuB|zU zL8se<&W1_%0}n`hQi5n+7o=brdyn0H#aGpJw0&ivi*EdD%CHkdjk!;zr}`i(NuPHS z$K&?9S{Sbc9+6C_1Q|wZDKX|hmHe4Rx3aV*cSr^H?L2?)8ID#p=xvUM_UVj;62O=u z!fg~~VV3zSL^FuVN4t~;kLUc<9k;>AD5eWYgy!l*2-7}|GfA8j<47(Llg@0kM5qu2 z;|-=$`+ieH)P}T8Ho6Jz-b}hc8rU(RSX7#6;17TDi`aHXqwiLSpOMDe&XPv2_b9`h z4Nz#*sy^~yi&-JgJY+I1!^EJC2dq&EA*&KL12MC%MoSP>Bv{X4FKeI;T!oEYyEvjz z8-2U38r0@jx)`v(pQ}N6M`WZY9=;vClTF>1CRnOD+PVVDg+w`!!>sCM?1Sv)3!76g zCY+)FA}6rFkTgBV%tKR9%r5b<UD9aTs}x)WY5Xn8%7kKRSW)Yc+#R&lQ{u_nYcOm$ z=t_q$tjF5W;<S=8|J&!oC=Fn^6>|+;BbvfeBQG+74|<wWivOtIPx4-pV}Da=(g_~# zkH2tF<ldSC5o=Qqg~p(}i~sLq$HlT8+gtqAzn&XbJFb1K#HWuLU8?dl-en(s8+;D4 z(z+VSW6YmuJEK_aj~Fc@FzARP(kqa*TLDz0j^xNQi{DdJ56ob2B_N3saSLnRsQ2pu zb}$7_yr;tzO#zJRV&bXIPL?9lq4F6JA=Fcw>kzb7`6A-BX`}i(`ES+eSO|CeHM49V zCsI*d$~&?&lpAR9(T>-{h9Cj>ci!X`k1HFOZ$;uoJqaRHVX4OIi5&6K@@AnW-2Umm z^vLV(C6lk%ev2qhoHlWlUea$1@nz1;O)IRnMzhMuPK%JNf#Uc>dHoR<ft2PoRp@}@ z1~85TVX*(k@Of#w%0}ehqryYeEUH_Od-8)H2~sQT<}mVS$bu;VRw+Zsz8+Lp;P^km zN9-ujI_M$=eLTF7*W7Ye8=UaO4DE2_?QqY|lnT-T35$;2i*FnH>K*a?5mLfy)?fN3 z|Bw2GszHOyXR6X$l~>P}0Ihq*>3A%>6FzxKD`%TyO$tIGyYd{~k1rPZOA6GZ1@0Xk zbnR8u;@VBv_wL<zPqdpWtt|GCzZYSF^cs#(_~>4`NSOG0S!WtCKtuAv6&;zf%#rOh zTry2l@$Ne#oyri~@wH?Nx@0wO$V}(+nDlO!J5FWAl3Q13@GA!r&UMU|yO(~`TN$FQ zt5ym_&?i=@*ne$DWpuL(K`G(2nM$NbKA6@KV1Q#CbNlYU$WOE?{h_ZY#O;LT(Y)a{ zK-MQ?YsLo^-9*b<^)E?q1-xI@c@+9wym7)KG)&xBFXB}fD{tRPsIbFiZ|pk|Pr3Aq zqsknf5A^J%(mUrj$6&#UXu?-OKGCxEuN{t14d`N8)JNP)H(l~&_B*BBFM{`$JwwC1 zL3=!!!rUD|eT)B1Z^$pyj(mn~M~FWAhCNXknplgdkrLp}!-g)CDL<6<oLcM6t*EFt zoU0vtY@EkX|Kk|#mxTIPQPazFg$t;Q1NANa%TAoX3o)E<cuTV8P3eHkxFS^jvvBMT z?@pS{d*^)mSMB#p?~71}s`kZn0>UOM3E4ozvzxemWJVjVC9uUx^cc(tc~g$ZvB?T& zX2V!rv^%0RpZFeu6-T8`vZJR!Qvug&b8u0gddIa>WBXskLCXT+<PomdtOhkKgFS$j zN7jpp_nbDWsuBYw&Eshk&n=~H=8?DeCMZ-7{Z$Fou#5^rx7}?U=e#xQVrxJh6RClr zd_$BiAWIB)At~InW6Tv%%%j{v+%Hrw&ML+Pm0-VHd~|j3%X{a2Ur8^yxep&dARxNX zCJlBEi>d>jux^6~oZT{1Z9VHC<ieP|a+$rkPdVELKAFZ-LLK6&bEPa9N`{e<^G+o< znscwF0diz5tj}vbc2QpKYOR6_KO_=HTUF~2N|s(|nd0d)!mLfbfXUEa?ZmU6OE2L$ zfn;n}=iw3_CLaol*LE2Ht0t*ghdtCfole#c?8&{{ey$=vlig@9AwAO4&u`lmHAWqU z{aYB{_v+4sOM;ZK*58l9VGef9l}!&E?7;cpB>u9;>-p$o!v#67?NaYkX~o*Ib@y%~ zZ@^je7xI5UPPDc~nu9_B0g)mD0ipaqhGsh>XB)Hs@rQ(I+Bs};ApO)D^ixoo*2E{a z(rRG21<||I1Bv6Xoih=^s!0IsI9Mu@)QnBE0zPlvNL16ea1`j0X7O*o<42E<%1~7% zxG^W8t)>o+=xfPF$C<fPo;B`|ClcqiCG>N9eBD5P{fPsdh1-s@{Eyub>Jht4MVh#o zlQYptHFcVjgLNmvyo#ceT-GDG+3{BPf~ZCI`Hawd9b!Y<N{wx&LxuHMW0MduEt)1T zwe2~=m6$0l2pJs&^uAu+PY%m$bis6;U0qXkl}m#*K|J>w<oKM)!JSELDhV<dOs8eZ z6=`VF;q_QpEMOUglo-aAucEuS{jzlw9PdimY(*HhMlSPrW9eu4KPW3h+)H&=3l{x` zN5pu$D>(Wr=}+Z{4SOq2j`EU5bN~`o(45@wq5=()fDvH`q*1B@8el3L0F{<F>UJuv zAta@L_8(TcGS!FXgX8ExWpV3j42?`?<Z9DDE}$q;<ZB)?n6Q93l;+yBl4BZ0l%CpB z7O{)FlD2CTJ!Q~v-3X82WYfZ<tRn?w6vvl7kR6&!*2@)UD>bucP@O=7;YOy-EUVc< z<}R2gU9^O~@&;DP{jXFqap9^;s<G59fFV4<dRWdogKUpk#ZgZU55tN*d7X^-ZXcF} ztbS3~QdE3gqS41)f`|@@1RvNx(4rWOyDZIIx|zs9@pdljeD_>Ai_A>Cg`!FF5Bphk zQrGW<%pu~4WB+b8`sxtzJ~7u{Zjuww#CrKS|0I!9`W8P&{}K4P_g#$vR~~uFlA_B` zZt`sAb%ikqJjK>StOt{+Hc%wCiSVvl!+dzde7E&(&>?{%Jxpf&z$=BT;9W$+PL}Rp zfldaj<l;JDb2+%=$^>A2=Fk`cup*N1wM^W=_Gh5)*>@}xPOu@VCTr#q&%mzHi%|~Z zqJ#2*S-K&lxFV@`rUzu$e)rxMc8f+!G4A(+M(KtCoLXCbf2(!kz7_pML~7S*nV!AA zftVyj8DMA(@{E+u6a(IUemrI;5;x#CVDhX9p+23n$?@^YPK0n_{g(>9OG6VzH$n@= z0=(#}XAGD{a{wBd!$u?|aXy$=Nwg}}D(Zu7*-`uPUwn*tLYJ8O+*Cj4LLerykJc;~ zDs23c>X4I)>cvjK$Ntt;BvJBR^hjXdKlFtrdZ8>+C;FRxW^Kq%X>P3+S84zCa!>iA zGNW779kM+porlPqDpq%!`5HwhTy;mlOMvn_39A03gQPhcsF{T}CI}ZdptDXUBWRXo zwisvo$CHrhL)M1xT`=*9jpb$AoB44zmK8{S@{cOF`$Ghv>BG$WAH@ahtOZw4W5BzL zVj(jfOX|{@nsWBSft1X;+4rtcKuxYbRfX=k%<78GGL2q^dhc;5{-YnJkr2kjlCI?X zq=)zrf+0n%d1>T^x;M6V%6wt0=i{O#BIT;_=C~7+w%ntwtN_Nr5*<<U<0TcxvD(_E zc89=f#9*521Z&@&Kww65ou140li8BiZ5;9nP%3z0`|c;U$|B39iuV2m0(Z>{TD}*? zVU)?Aau|YFjzBG$dHok|g>=&7435egIG}QqA+e6+@5mQh0SP?V<!d;y<Zp$A_`_<8 zKe#=?<ZV%bK_Fs@bPK83*U8l8P+T42)-k-#Rq(M#om+E@yse<WD;`>4gj`RB6YA&* zUo4dxSP1nk!2A3B7?BOasL|AGPXyyb4h^H;(wjv_H#H>Gn4Q3?xw6sjcQk^L<F2*7 zcK3(}$WW>87XBbfygtFVCDJ#=VKJMrrnpO%AzCb|(!Y7I0*MQ*<qv_DJH3WNQ1zny zi|a<g)z_@#Xfaht*<^BJuvL)2sgOOJmWn8k?}ATcFo+I!bVFsg<gTf()d%El%pZ9x zzLQw%*dRY{Eo%M(ISIc7SDeK*Cm{%%<G}*~B{7c?p~oHz$y;WoO*N-Mb_!=#KVrhm zrO@kRNqRS<iqnPI?;b`FGATIRPm$@nr^eS$h$qM2!n$P1sHL<2k#0W>6Jn=2Ysb1P zY3`)b%#82$JCmCCh4{a(j8v{Q2q<zOAe!9&?>*bh)yUMy)#(2^r}+PKPL0L&e%2Wt zo+M4kRMt$t)Y@;a$fxS<QYhqIe^;)WSvuJ^rAwuiT>abpx`j0C;bu*}vNiDWJ6*N6 zb%qG(H)H~W0BS3qZ&GHfdMN7Jh|#z{KI^?7UwK(^e=7R3vpT%&hD*)}F>h+&fs(7= zbhhp1qn9=>?Y6#S#vY@uUd1xIQA9I3cOKes_Pif+K0ofd<!@PBJyne9kf4x&`1>?{ zzIll13w7O^$LHnzPitm9IE~&dzH+i0{LVou8~7hxN3}Kg3QP93sb+Q5j{GkB;eT4} zWoPYWJ5;kruVyA5Iu_5&t9Xy_`5RBnUsh}sn3Q{kAptsVy}7{0ek|s-j_NA$R6s_R zyLuB_Tr~JVoQ4@NnbCQdrFQOgb`AYKNd64YP8@yXe}gGHtwo@4>K<vv815AQpAEIr zFF$=fJ>cBqeD=+agMty1smUU%)8XN#!C3kvDp8@E^kw+3EI`q9^&h$>jTbH}8z8SY zcP#cNosAtvZPwU7FNLMM;&tL0yFf(iHB?6ClUXeX&y~wAL3wT*Hj6QzPvP5$#k4Dc zCpkG^I;Q07dq39B@KU@35dMIk6n|cR0d8NPR074eR>zg<_?P3S(YYUXe%XcQDGZ@k zU?gLX*(`~gpX?&5g6rnmDxPx{v-&plenh%GV5ED8sv`4t^N^w_j4sYvN6fpJ%B~#D zCU^RyR<js0+!l1Wq+?{JLp}H_!+M?m6E9Fc*qESCLkgn0#`iVO2TrqT^JR7IuiWEZ zXP8>igX{-D^^FWapv1TRk8b@2@05{O_H>Ld|1sN~ZI7{3Yp@4-`R2T{8}MQj!VdmJ zO_XcR1A4uC)<93lb|Yc#u=AQH*6?l54+}q^_cKQ>LAU4U!`+$e<$mYkdDZ#-{Zr{t z{2N}x-*nv%u__1+WKMn=;4}6CedL=`^T{AMlTor7W04l~jA{u6BrqIF19e&V_N>|4 z;!cpzA@J&1Hx2y;ysW{jV8h5t=aEFC;@SLwphbs&YQR)*eOtSFtZRivPsrd%EP+BF zA9t2A@Cdz%9*fXj71-CRLIP0%bfiCzhY7!tknT2bWp$FF*Oap!i<%LOtBi^T+C@|X zC~~1<0>O5nzc>jy(@hxU#(Z1RSNU(IEkI6=2{rnS<{FqoxOw3QO`n~WGq|?z>Me%F z<YQc4hlb$J?JK=;Qdr(ZT@2>cwpel|wBNq3@3Z`f4ThxKX9g_1mhT{(M!+mVAKjsP zymgJfPt*4{U!T|Fs?*w&IEaZJZf-h9v2$D}3)RX`-Y$+`?De?FQ$Q$Z%l*Z?YLJXL zhwqrbMm7%=Ax-c<vzQ{k<h)o_Cr{gs$dXhV-?Z<V95!Y??P5jk`ejN1&v{k+8X4!1 zT=kQ-wHnh$v2LVZLY-anxp@wEh4KcNkqJ8#+DM<LDF(lSv)}m#+#tGJ=Jbm(M?%Tv zC&hxu^NL!Xf8y~J#0t!SLI?b#F960E*~`41T;1V%YPt-1F&l=mnJfiT!S>DFosXCN z^`1gzAfJWIWDMAtf3PH%ZCgd;8))i;o~dM(IBHuKxZ)8e*L~AieLDhQpD+^tHc4UO z7F14E@h&L~jSm<U5DQ5wv4WT(!DT$f7~tZLZ7Jjf2f^tR1~tO6T1%E0LVBL<oq}Du z_LKMRPmx0<1lAzx_pXewSIa}3G~HW6yBbCnF1_vAm=WLU<LmysX3_k2!ULb4J{J!` znKW$KtK$zdukr}9Ej~Z*@{gpQUot39^WpQpNW*uH-{=X1NZAaW-La)r?L+|mc>idS z6+?IQbZOxI^P5L=Jr!$UuuQ5tV&Nv{XgNH*uf4skyu-ZZeY?@nxApsSpj|)l-i<&^ z5I#CUFR{s<i<#~fG#SylE1QapF6}6!HKpHSSDKT*pxdUJYaUU=`m0N8!mrU(xOEzn zZ4;s$#EcdS$wgYxUnuWZwNsp7d4N-}rfiH9aM}95$MZ>!hd%jjW`X%#VMCivZKZ|N z7QKf%QoYlraa+X|8yNo>oa#86vMhxWYesv;3K!624fP>oinU75%orK<a({fBU3*B@ zk4UPILvV-~&bNwN83rH5H<7ErpEK>P(b01CF`URP<SUV$5IEc8JHHeMfbm{S)$*J& zwE~~wq(hXr!*RIzC4kfm1N&k_tK!NxH(D2)X|!1;f%Gg`kU?-%>?dOp?Yn>}Yi-6( zIu2nPa5Xhp9dr?_+A421h62G=w{AT$&#Vt$&;Y+jUpq7LdlccV08zZ5h0!Ck1eO@F zK$Ce0qK|LGCv9!xNz;RaC8sEgJ2w(1r^F?(&Bz5Eo#sa$o#K+bzZWOv*tTwgOfbIK z$$KESEgNCW&!J{rV(K;kEj7x{aTVF59|Nr*i|<z`;!(gT20Q>su&`k>e=BY!r@*%z z4YiSn>0XFXRzPj|p?=$?O)EQT>X%6nJh*63AZUQ{fqCSD&RKc1x+s7e6dCY;gbBzF zDtWM}`2;&?>Z&btaL!ZxapR9JD7?Oxj!{)Tw8$N5-DPv<O97(PU^`UNjdVy|tZID2 zozu+ohtJ2O)J(YnbT0fo(X&5*c!lG@Cj*7ILAib%D<Gn?Q=!#Djn{O<3^&AvX#%#P z+_*J5N1_}2!IpXfd1To)#SPpk{mH@#kgxV&dL#Pi9`^N%`4nwA*jXz&%7BlgCV=h* zY5ai!+|h0==NLQ{?KYh8bdpa}Wa()d-W_~T&LHWXx*~%9iWtoEfS3=ZAeqBKeu?XC z*R!BdbaLG?272`~^;#8m7IgzU^I9uU;=qkC+o9u1H!H_#I8lKffn(XB(fao-4J}%j za_LSx2hKu_i6&j1TviL<8sQwm-X{8p&QRlJ+$lAKN-!++Z3};LG6NK@+Uk+K;Ui6( ztl4KL|ACtpYHRFBPA5+bRZk7sGl!WauzGiAqCHT+i8f%$Pavypt=qN!ecO<m;y@+L zf##mRrsO@75ai<L&zl1V(mAHIMwSI8r35d_8Z{Z(JTOD)Io%=snL1ms>Q3z`;va2C ztEviIvORue9e>$cZMOKA`<A`MlgOV}{wC3p|01V}7T}>ruO)L+&OgaHylcKC*iy!? ze)5>goBz_aQ{`Exr{P0TmUpi|=!CD+b*;<Q_R`^B>j}u!@gdlC&4KmM?5MN?+x#Bh zR9gT~KRGK~hvgbRD817zH^(=?av;Bfb)(G>p|hV8PUW%d_Af@*B7ZHu4)d+;AWykz z;jf#WwzuQBm|4rI7G;kylu&%ak!jRX5L*xavOQ^i>;zht^73|aKrrXpor@#kv+=2g zRI0=C(y1;*W$3O+AR-Vl?B?@za^zv}9*swxbu-!YWm-#qxEX?#WJtHS;81lb^XW=a zJxn|IY0d5MYZKJ3+YFE2mG}F>&$|#}-W~;3^iI6)hN9-IK362S&h>x1d0ry>%gw`s zSXNi&0FW%Bd_a<di;BGM<>v9de<_6)`8>0u^zHjh5Zb}Z%ekXHx&Vn#yxXrDTwP2F z(Zt6z^nJ+)na^*U-}R8_#m)}^@cUss3N^qw{-f<h6~K})F^tTEf&uRz{XFWPXQ(jo ze<-XC9VlfG;w_Bvvz%PU_ez;o{7<C^i$~4>3?qRmX^AneNt$WbdZc*{dpt~Y^#ee8 zfO%?+fsr8VE3cN4g=|Uk2Jf&6+fd-1IGMbx)}_~i-}p}yKiU9n;ht->1_klgkV|ZO z?<@zHK-VjVi3oJ5))OtE_>5>4Hpd|x^NA@I7@#duC($uNPQ&+)yu+}bWeO*=ekWlG zBtCmt9HbcTJdVR6^}jH@8j224?hrD|3>N_$9sjWvD~Kw!H_p0j&7h`!Q<bed<8w;r zV}`yPTz-}+svVd5*<R&(ju|{^OwB-csuK}umZg_ci~L?}odh>GhqeHgWO>spOYL;9 z(}ua3PGJ4X2G_pCWkIfa!H>oBGR$CM7FFRS_%RTk_^i-nuRll0%^PjSn)%ga&UpG8 zuiTTit9sze>~7r2Fg)sJ3}SUhFoeKi1_VkUi4KF2Q$De(MLoU{5!SXDErAgk4s~lm zMDs%Oh)BMm-{*r}swQg|QE$lpppp=5vhqKH`Tp#h6MCF)osGk646}KF)k6LIaiUax z0>Oe28G!Z&Md;n&1{`+OK@h`asFm>ruAe3nW{o>CA05m7C@Ib#Q=Z40@2|b*KFJh2 zER4Lo0{ScQCsTGEjuy@!YH$ip*}x`z<%{HJ+=3F-n*?u`o8}F-#c_4PYh=Z?2;Edq zK_It{G3EZ`aQw>^7>IVBA#WUum(UU3>MO+(>U<BVxJnse^gk+;I7oZYIpoD!w`4dr zSg&0Z#SrMJFfNztESFS`mF4jDek|J3HMSq!`sxE3;>x*O2Yt=ERg;U%KvPl1xr9>c zt?~$Ns621avVvA{X|2&dQoKT|0r2|y-uovHW!8Q+kXTzYk;(NgL|hUHns`VBP9#1d zDSv0mm;1SuR}NGlS067nzHVGB@D=fbk~#e+JGJ+j(r{O@T4IX<#IJ>&7WHeX>^Zzn zKY6n16@9w7MPekT8|Cg=aPshbNhE^b`B9p@7AG9Uk+Z<s6k(6ra9AOyM7}Zh1(7Vk z5Xxl($CE4H$&rcd>eI|9l8*{#;;R`1$JTnzjPRozGg8AFk<!J3o6~qkAuZaGd{qY{ zu4lvjFuXJTi6mSI(x<2sMS1pRzo+mTu7J%Z&rl(TLwVXGLd^H<)%4)&sPJTq!O2y! zol|PBYEb#X{R+qE98XAJq%H{ME@eq}He&=b48dg*v$SnoP|*lNfeB-0bDH~?SLi{! zU_=JYQ3$$+%W;<kByxIZ*Gxpt)PxNGstdEZF58OmytXRV+P}~hSvhOWa7Y_<1U3rP zX?gJ)VtO8x;Q=RLovyRNr-nl-uYyt1IMF(RbAnvAS!deRh}(3EqD0T0=#mXBT90-x zFt3F^thFXNGRL)ZO8^V<R~KXOU!R%cTI;4IJ4RTRlB<`D$$MLU_9-=KR}WQ5&mpmP zYkPUOdEI{9Tt2A6kaxG)zzNWTnbboMGJd5~Z&5qRUA?Ac0O(LL9JoJ!feF`K3&Rv~ z5rmXKviO`!d{T5&+)x}D(LuN+mol=3Vs`)5&L#+}zorP^Oh~WHiGDxK1giKQ-_SoF zg6#wSULLH>8H~mY?)rk2OE_-{CoAZ0e*5$STk?A(Ib#w)H0l2IEWVPAA8GZ_{=%AP zX9OB$(j7XH@)sMjoJhfTp<8B5UKIuKcFLs7mLdq_4QR;sm5xRdZ7>J8culj00!ptQ z`S7l*i><MU<M9@TEYJl&3vfWP>LKPQ=|!`Gk={;|2GZ1!+2IqKnY;ouPK~=SDMb&O zWwsFr<_*Q{Dg%8SB`${LY!fQBvB6FfOFw=f0rY^np5}s2u6WI3#_#pQZJjvcTVof; zQxbnNuvg3a?BT)mrOi0vjb<v2KY7QtDt?8Bgmu`fA^tb=`gWqmpU>1%Dql)H?zIz` zX=nOdi+!u}&ljfMULt|r>FwLcC-|;t;qM@*o~#3P=I1Q+VX7nYLf@4e93JqCg1Zi1 zazuxD)ZLV$wo?B}Z5Zp#dQ*01b&s_zw4?EaiE4&$VW5DlmRD@o2v)=^*bV=G{me<F z!{4F3DF&Ko17gTypC@$~$@x!ywMVl6g5|p(eh8<ofP_H<&Gr{Wkzya`ndvGRcK`bS z!__%$2?AtUG;Q0qot3t2+qP{xD{b4hZQHhut~F2H^A=wa>qeY?_rbTqdi?f6LZ7?F z>ByhiW*Jr)zk>}xs~v$_LiuAsu^Y)d5=_;1?o&`G1imKR#d7+>Dw?cFWu$As0t7L( z-h6#8Qj>qxRdqZ89UU~f)2(j$FU?L3Vgy6R&b-XiE3k+ttqe$E&zokWZf=6ULkxVv z0LGXyVNSpRGJ#H*4sD&rCnA+_@aK56fbxTF<e`^RC)(_Vh>8<+64VcM?%#C|ffOk} z04blx$Rxq@7#t^Q`?@;mn(ZNvXHWoTg}GTF137(SV5vvWvOhpj-~YaHc>omBzv0(O zSkX;fSu$z87pjtS5|lW2eW3V-&q28eb@I<Lk%<($yt7J9pYsn>2t0j{H?x8PqnqsD znM$^X-!7u^a^)IHnG_yVA!UTE-du6~J`D?Wvt>3ua0+ob{i07}{dwr~NUx+xzAH#i zp_qA4Q^_8~dAx;-jf0Epxq_h|#DmdItU>;~Q(Q&oY~^9RVa2JIMqG<fm@^ft-8ZT2 z)MM?VR%PqlM@swG+iVaD4(VYkcmW4Di3o03yu?BZID2uV`mknq*uNetr;yASxJ3Xh znP-n=9mXejP>SLn_%Acq*>W3d*7Rg_U&u``rb8QxyYZnb9jhF?-Iexm^qj8qAijML zJ+c&1RDg}*bAFrBZnEVb3$;SaqZuPx1H_1qe?TFa1w_v)53^o4C;PhujxZ-D)+45) z=_&E>C@-uj^E;AU_XH#XLcKAB=zT$O&dyPEcL1Jx+K^Y7t`5iakR~P7=cuVwTG@uU zo?1`)BJg=!np3^40bMyYv_u%!r5d)Jq~1Q15OcKlG95cvH1L-?gU5OPs+fWD3OhJS zo42V|Yz$}H9%NDAcvs>E7R7I)J!TZ&!2B5pFWW@R?lq#`xB}hZ1$Md)vJ*Eua4iN~ zw_hyGy&4;AG=MnV^<@3#y|43W&X>B5g6Ai4diA*fB6^%Qw5Mg+;}%on+LUu;*mq>! zw0bt_IS}smVBzHo6+^bs-=MJpw-9myaL=ium+&}aw+S`Xb5ISjf~O4Lk2<KEKMElr z?L8=4e{=qI*AJg{^`FC{38myP6)AwtW8;PaqIW_cM}}0P-V7rG*#Gf;PVqfHd#>&v zHp4c;AF!CK+>syswV_GMEd(-{uz!mbbxgcx2<`=v&|Es7t&5iP@9d0?{Ff+63T>98 zNU|F;&vCx#kv5_XSF~NRrFuw$ey~6|Z;vEc&C5^u5CSLVj9fj*a48{Qa<oG!^C^Tv zg4HOeoZyYZ!@{P-q%cfRCXOp(?5s;g=W!T7joVVoNM%{o;+!8E&!*(_b5~xMzEyv_ zFlM3?Q1m&69GxuEC=%w!Dd(EFlVk_ygJ}0k`3OADXHsZNenyUp3Y<bNSrFgKxkGVn z2nGM_D8$bu`IivAQY{<Jy5>y>`L2NoBp|xO$-lCM6UY%O4PV8e{!e!320yKQXeB%z z_htgD*I?f8&LU|rD=gh1wJoz;gBTbU*Qm-Qf>(ZoDlA|0Mk>Z*XVqnE;ROCh7+sd@ z@2zkY5Y_wvtJL}DZzS3J`GPk9`7#T|==DE}>x`yGq_1GUw}+yq>ERzzZj@HDEiTCH z<Q8Y+5*G|^1C2?>HrS`tfK(9q^NiO_UE3Cg%%N45Y_gqIN}FU$L@K1#RWwAU&)TU2 zimbgIHdESVw%Wd}*D(soV#fe~s#8Q$0$)yDw9aXYY$IsUMVJZ8wc<w2ZSaWQPc#IY zDhPrQ1I1YhQIy(8Nbqn+exi!B6}tyVQiKC<z>2gcqgA)gx?G}y_u@u84y-|B8M!1T z{#CY)y$wmEJfM_a+>S<12<ISa^z^uTre&fXT`o%SI4wE~5|<xU*uGQieTw9HE_JMU zT5(2rWaqpPHmC5A8(g0tt1J5_{DrDQY1&KJnOyCG`)02s`{PsEe&GB1H!Fx^%wu#z zyV1`z=+lh7&M!rDA(gIkY4qDQzfZTPxp9^^hT8SlLc2cwF0lvSyb3jqX4WKw%%lNA zWyJePbdOj6+qg}Y=7yUQTnv+QmcP;qO~Dn1v}Do%JFHG}_)6K~X?5!Y(g7mFB8$K& z$k%mdL_>@&S1k8h%Q(^E%g#9?+Fh`mCAl>AsO0j{EYEu7%#p!aqGRyth&`N@nD0%< z(5Q;Q7)M^1!0m!ILdx)fVHfp+XMRfZYTu0vkb8FN+6$m-ziGcUAMnqYrIrA86?iHT zHa*W`a=>Y?*M{&@@2*lL*se0A1)BwDN=Wj1nvo+^Ept*?aYFx#si)`N!`_qs!eK1j zjy{!fSJ!BgU9?KoVfAfKhOA!cj%!69uHC!m$8moY{+G=0;2NdQ)zRd9Z)r*A<U~r4 z8mLMW+hll9#JoId*pZ*?4xR&MX@`=Go(e_4mx;2XBsa!Dg{YfLi}2>i%rWtw1y%_A z$aPlnV5U(J$|iGt0kJLa%Ozs`%JDh+NRovzA1C{dgUWM<)~78!-zh#RUz|Zd@L6BV zC~E@9Z`_04tm|lBCx(wl4<cWQ(ZWZwhy6YH-e?7?Sa?tpH)pwHTWj}+=}dO;Q9ck+ z+}|dytSj!{+Bl@an<wLG<e!(x^ZBQ@y(ikh2q)c4PRSfL;3JF11&%Nm`zIvq-*{i1 z?|tFF!F~7|7le$lEQL!!&+4nD0MsEXEO?Qx_#%$i^ONVVjtI78<yvG0tHMB$I${wt z1r#q=ER&v*MU2Q2Uc(GJu!lqN<4h7D>3XueGJxlW=zQi)9ucn6Ybqho1!zvAOM2*) zhB=pfK7|p4>(#bos3?Zk-)qvJw}7Nn7XA~uJ7_K{3mU|w4iAI#=l!qet>Crr7R6jq zSLNRc!7sB2XxrK@;{+!um>D<-dpPJ-y;1!t*|Z0jL>RO(nI51`;uigi>r|0S8iLuK z)rOy6pK-Ios2uY>!VAi2tC^)~wo$W4G>=ic2YzGgL3%9u5yu|7nP3+~Y*s~MrQyen zAPDJXoYCHZL^H<1R+S0jq}polOu-362IQbR4I<$E-@4q#Pl-M5%)0{+3q<&B;SV6r zF!ZUI4CokM%ff^%Dewdf0X*|if%9KG2v?Mj+C1O)ftuR6@AUfhj=J+`{NbW23>4H; zX`@t@HX%7O@}cS2PDZp(ayt?4AlNRKQ0%>M=z5HGPmL*(zw&%8H66ITu45;Su_}zz zF3%BTn7as&?&ZTI61S6>C-5Y)f&O3jwq#+tWjwL>byg6des|9L(3brBIuvZ{tz~7P zEyzFCz)DTlcGsrS50ME^5d4&qbL;}eMfOHK=E*4TJUQ*TUXXqJ7bR`F$E_~9eW8<^ zVE&v<jJ#;`41sy5%K^>j1#HkVWg63_&gEeZxHLwRU6DhId6Gj2KL~o;CMFP2@cNY$ zCd{3ItXCQ*@!CmYxnDo9r>WC7p`3?L(83{+gec{R2o8V~6=lOw_ca@%cJ7a`qiyGl zDIY;BF7+Q^I+6L7eR9qnME|ygYD9X6dWF@t0P;d1g<-zOl|d!GuTvl{v<HS;0>yQ{ ziWfR@WkL`;%EvKeXjE9{Miv-=ZQ3%V+Bi_dI?V5HmxBrBc~Dg{A>l+SD!rpf*mn*- z2H7Bb*ywN(G%87y(dSDvmzl{X97wlo0pdTF36<37UwlOS&t4U%lAVl7u<Yb!*pH2= zn~{UgnyZegYN04%fU^yaqA<jOPFJ71VS8d}r)B;qzIkZ{&f3X)bm!m7+`k_ApXYp+ zSl{P_J!aNf`t$YWa@)q(x=CbqF*<_XWgW*Qh6&43mXY~7A9DAulQ=2rD)RwRcB0r7 zw0o7k_RHUv<v07RMCw?vgBamgjVGx(n3zRy`zLR9#hS8}LK`7QvH76${2s6aBF0&m z*YQMG=v&nt;eKT#aKY;Q<Hkrr@@27lIuM|PZ7pd%JkM+7r#XPW8f>hqto<t<!ji37 z%P40(N2jw1oz`}Txmj+fPw>-J@ZHWlp0*+16;il+(M+}&vGcAE!^7a7AC*eml6mev z%>oMt3n|WW*3^YO?dx}8w~%x`LwZ#3v~}9vMO@T1UGv)h$_FNnL~I_}#5^jj<C;EW z%9xqxyY-aj#nECd-Fv$rsrWNh(S<FT4e(X$-JbL8A?@P=mYad~j-xK<^8os(ONYeq zm7Fz`^zjG2qXRnFhR|y2k$MvielRN4qbPh+HJy)ZlHGoB3t)%xPhc^ipbn=VB7y~c z21U=)8k;N+-<vYIUMbJe_u#(YR?8OuTB}52fWp{5^Qe!!7p*S3u=R4dfgt`khs@7b zPE;uwHwh=8Z}7qZtI)Hls&j@x+85eiYHE%!e4HD}&u{X_jm_fx?dKzmy2?C<`s!mv zye)(BJ>t+5m<TQ3<SH?Z1dnYW?=N*ViJLm(sD!Dw5Zvz(@v%Pu`VkKjFs8pFS&A>2 zOUgJ45SgEetMT0{X|F<MO>uVLJAt;*vV0Tss44^Q(+Zw^^r_PCr}GuE)9Ht&Z1Y0E zQrsDE3G-|VbzX_^=DOYI%`GvuA;9f&HYF)7Yybjp=-7arUY`Mp?+k~(5E2d*V(+%x zz$aA=x1?Tp#>EP~eDsi5mlBB6KT}-TV~}C>Gu0!=E4K;#THK0hyEi(vQJZ7|&i)M! zSm=5H;nbQ}u~Hj8Y^Fb3q{UDp<h}oA3nneBqRp7}a(oG_80r0|y-0TWJ8AXqYu<e5 zVVAzV9!T7UjvHSI-Ov7T8A1F66Et8*h#U`A2VTR7CDdYbFJ*I3fL+hT;J~mqEse4S z!r%)C5%xEZK5c5+K*mb7Dqem<3ji^#>wcO&^irJH-f!*Q^fS4vW!(1)LQEjh=TPf9 z!X1nvCt|?g=w~eEbMn1q5cLt4cIy;t@;m*pmKig6u2yg+O$9QV$jbK<9^>9%%IEXY z%|P>s0E1Wi%rq>?swmwO#G192Jyo?AhRgT^@kVR|ES?%3(f2tS+kD0JYD(=%n@`3v z#c2HrMu~oj4nH!P#%M%9J+PlOWuzla2kk;D?3))_CI~24up7i7=gya8x9h^{_G(x_ zz|ua)AF8qjc}AxPJw<Nd-x?Lt*gEY`P%0|#Gah2hYYv;2dxe2^J~&Uw>TDd5A32{Q z+TE0O&{oB|wTe+6NE*oFdwh?+a?=AI!dNqfWYs-f#%?rZ5pZ7}!8~YTM#NW=*~LR` z*rGU*`<JR5wvWW%xjz2y{&PI0@(ZFFzHOiozD?U<eRx%)s#qN=O&6HJx$-Wb{4mp^ zSN#R4-SG<Bit<12eO5TUkYP0>E)BT!Qcm;vFpnqLm6Y>WH?jrUvl8-hO~$eGVL-)- zk*QH#83p`GHP#6{hJ3y(m1&=#V%L%Nt#&6YLqb1x+kWQUhTR6|`rHdgEzlEeZk{vw zMt<Utq)baWmFWr3?Xeo_$|n@8arNy$2FX!vclkU~`udou*pOdImwA+JLE>L+Ir@OF zA5JPBqhq)zh6h2F{LSQgABmfk+YEG|Jy(4*ndm2|^-Y~vSwvJ9@~%=<K=I13Q+!`- za&z3O&n?u<p_4!3YuVCEViCFm0)QiA261@ZvR~(Od-AMMpRRq}fSgX_8DK@-xGO}9 zfiaE!0`swiUdC5zqKrnIs@6SYon01+DI3;GJ8`DcjsEpicCB<IBjOg**>Z>Ld?%wv z+y$^=z)jsi*CmI4Vg8U#W|kdxdHZ7uX4_?{d1KB>KBxlwnz3sZ>~7tgeYwx;bu=VX zR?LRI<qkWP_JKUN@+$HhS%?wFdN`Gi9wG`xkXtN5p+1}>zw<`0I}3(_wQN=Md#AAf z%w`V`QMFq(A;xnqPq$0yMunR3rSA?Q`|x%M*JaTRjXy-}ByjugPHZoq|9x?q4NaAx z1Haw5pN(jLhde2zIQO`7N`7K{BNXw({u(3c*7?krurv`PZPzpYG9PPbff8rhm&&XM z8~oVBdgi{beLRP<5ODVCAH&^JJiz5?L5nm+nNM-JVxzW;5$$fV_%|)3S)g)OBQR4H z2uug@f}?EyX+hZ!*4tg?kT=Xa_E6*-p{$9%`;%rV&|=1i#6}{p_kA}0@0CWS{gj99 z?a?`swL5jude2YKn4sXT1uKdfx%y3rczMWK6##GpHi`VJN|7y5T?g^E;6uv_C8vJI z?Wdgi()rYDoM)FSpxU#{(O~ycBe8j?qK<t6pw2{L4q&gL?FlzY&{mbiI3F}pD~86D z-mR4z*18zmr-a(7GAtCA8xruGgbb3wRK8q^+5GCUPJDeA5~dj0pVungeLJr~i(N?d zxx#IGq^D24adN2YC62PmtDvT?EO()*u8-*#1J67!hS6WGnWYyLK^o|QdnBsW+43;y zU?u6v==9@j;6s@wU*seOj!5p{9K6rVm%f)$eAh)Ng}rxSM1AJLwkM9f8{`m#o9bsn zitmTpWl5znUr)A8=Q-dsP46cf4OGxubo$W;?6(!3t#9HZJaB4q1EA>@sy#P61IQO# z6=T!iAE^-R(TQT8K#w*>!j>dEpr^4yBZIZEfWQ?uuuc&D>!)Z|d>B?tf%daz|7tX& z!DDJx2P3y59+HN~LxSxkZe%m8bK^R$!m94)#PO=HncziZsw4}32VBcE_!4F2#BII% zv0wa)&;=nD<Y6>Z9td4Ar;~gqTTez~Rp4o$HyMi1^3cXnq4BC@a=k#0p+@3gg8dQL zDsd%is+u}-SRm{|w2ld-pUL1Fqt>pyd6Hdq8Fz;NG}3#(c4EqRC>?a8ijmc89H1f7 zf}%opSXAX+u2bE6LI04!2)KlWB_&nvMRy?yfucL72WL?27|thY#<)#YVcQ+8{HFK6 z;8g5(Fj5&b000~n007E=v9^vTPIfMiMkY@G$f;^guei-N#NXZAz!--*@8^n4DLsY` zn<N%WprUcYOcZlip?unnlNuUGr0&j{{T?r~Q1}E-_ii`Vz$!fE!F_H&5>`|6UA;P& zgb8mhGw|m2H)dYU7%`)l4vM(HTQ?|Cx^nCAsk3_8eSUt1zbPDi4OYIylNe(=lg(pR z2}~*s&B#}yg&U~<x=h(Fa?}F5Y2iF3{sx=b6H<*BbZM(Ny2yiW*-#U{5UEjIYC^pH zY+thD*X#~m2r%Z9UOkV(=kj&`GbBHb%B{X3oQY;utTmFX<1FPPNemqI&`^OskV=b? zq$?L3Xz*aAqf=`{H8;35)TwFIZx2je+bC>SKDc_xGc~q8)3tGNa=OrjbiR{G`LHfP zji}c8jcJ-VKA#xSO0ood#4yp0XVkh8$xKvGh!n>%x1dtxhmA+B8jeWTxJFP-H7ctz zzhKde5odv<Jx|P#fvvng(MTp{-S+b@&YKHI^FQa0fd=iSRa5t){<-lbcT9m!h(tMO z(p|kuDvJ_oMq?2b{*^l=K9U*+lcsknPb8@jX-Q{Xx`R5#Li!qq<uPq2LCi$=yrRFO z3M*?vt_oEjYsKLGs)?txUjkQP4o}5D2;-;>i7ICt+P$Se<VS&Z1g(jh7rd7te57d7 zVaeXdm@i^->d13TI$wgUfY*PfNMpY1+bXHgq>2RM(nKEPEJvLUW(@dSjeESlzuste z^PwYyS->N(WerT}Kii@ou_f`oId(rKrF-A)#cY-v;3+Gc;n$4iXF?sowxod4nyx@P z9j;cjHW#l-lH^gCGO7hRR)h0a5ybDtRuLp8@!95<VuYJU@DgjbP{dnj-*TujK`^A2 zzSj6IV&unz60@X^(Y3~O<FD~cnWy-+$oMxrIXj!-coI)&0;eRU)(h4ECY-~i1ks0e zQquY;2o51!eG=1-BxSe_QZwBya%_5imV&l`uhf4(o)RJYVH-PPS;$#nBJUsQYH_9* z7Yqt6DN}S?Le>WCaF=m4KgKLa#3L^b>of*^EN&9B06WOCgzU%PdfEyEVJYS!nd9y+ zskNEV`QSXGbI$*$=RAFslq8}((5l#74Ugzz60`0DY7-G??4qo`r-^tZM!WRDN-8Th z(>(-3Ct_>LVU+Z_Y&_vU&9<#@-x^_IT<Ru0=$0rKb;;tdrY;b*4Er>@50)q7KB8$$ z(s}NtFXDsP!;&B5$4M;K10`B9U79Mrs0t+52=?T^94C}MPA}QhbF8(ma`aKRlkf8< z$Z$vizDzrQDqf_4%mPEuL*d#Z1y=@8K2h`VVhoPeJgyGtW9y$)!y68M50rez71Tqj z@e4{uWuVL}Cy35v@9a++WH9OgA)OP`f|fsRK}5P5117(M1uWJT;ntBPP#XuENTQLl zApUL=xh%>U!O|E;2EFY?AtPjZ5Hqw01KqzvFt^tB_<{f8KGdztSzev?7IuKlc>uqu z<PG>lJ|q{tXc@>y<9x+;cSy|E)_elwiN4p(W|jKAv{|Aaug>d*s$5j8;MSr9lFp8e znWwaXWK)YH@Z*a)euCzt-GOvItOfeodfuf}qpCa-&>vy~aFvz-w;D#xC){I~#1ND5 zk(6S_=THPRQK$h|(u@~9c8@<y_kbu4=?<VYpBNSV#g;U!^GBh(_Yrz)wk8?_!oxv< z&G5<RSXC%82M=vI`~so9px>m`<eZTMXil*p@HQ<M*FEC!8l?*tr37Mn!Ss!RmrO7( z$54B9WP$aG!o5;R80qrfW9x!zE#0qU`N6`J$RMjR58T}xOBE8!aN=wR`eFW1@rd=d zbuk20LOmFllSRw!BLK|?i2WmeZCQ&GU{M$@kx*zjZRUeFmHqa%YUp(vcOb?{k~u0A z`Nl}adeX)=`GzQEjEfe0*;X9SHGhmLVSuYmM*B}WtYV5`bpj*Ql6GZe3D{+h7Lzdw z@KQ)X4?2RAL7@LG#xsD05YiS-Y8<Nf4m|G<+(tAifk*J&Rf>4UG&20oIJOGd(3-X0 z-R(*CK@9fU>?G}prj$;|k6|d+kgp7Bh~IqTcNUe9omW$Wp^0qEzM)dXLk2cLuY;0S zm&N)30q1WE?y&bW%iD?_90syTSzDvg{LwUDcr97okn>mw+#E@em#<hZLdBLDyh26W zJBlsCYqJ*J)qj>KT+y#d$Wh)JVrD?_VX&9dU)%RAM(UbuIM6McFG1F1F>EsEZ6BC` zwh2-sO`prb96IS!<UcCEu|RRyrenF5a6zSI>xem^LN`qp=s6gm%_10aD7<CbqSk;H zJ_kU9P|BZ;2LvUfb0%)zfu=aNK&hhl5wX`pz`!d9g(KHv9Xk>xHGctMalI*!QYiw3 z&{Cf;xkF2VN+-zJIr{g5ETD~M;>>X!k6Y|dW)#6y%R_3ki}?*L+L`A@)5LulLk<B& zlrp`eawXWQ*D((cD*_Cwv=6_68qq6`Q*cRd1Du!_a&gmA<~%y`o2pZ}v5SS14A!q7 z0{gh<2)sU1*ZQ3h1W8nccn>G#=iR|cBpw|!`}@}fS|F^|jKJbl+u7qwCMCG~(q6_3 z&9InuHC8m+Ms4uy%^lRK!>PPH-^w~Cv~T&!zyzSZX3gnE3rsB`-x?$q@b}x@*n;rF zy8xgtz<vf|a$o=rf$o5{wK)#UFoXvUTpfl8cuDN!)y@7Zb`>Os2Nn@OX>7a+_JSq2 zZ+?K|JdFH4Z}vht8oABdvJgxGn)%kmoT%v?I5tXY5n){Xi}Z~LM28$84;%-LR&6@9 zhcrU|<VP8tLA9=UHL6}5?ISj{+r4LK2QnMT-;w<<H!Pt&iwXt8Jtr>p@Q2(IMw6YH zyviu@T;;ybSaI*u6%>+l<j@Y`eP#ufXJjO@RHuZ^T*Ypv_6H25?C?ch4A~J!%f9}N z^Gr|W-mdVh1)6Z#IvTIR3vc_Yh|4ESJ2}HK2Q^5em2Zb(liM++xb-{(lt;Y<@y_O= z9}@R-f9yO&yM53Di7hv>&?J#>2vpZ+*<i!`*gZGo{)?vBA17c6F^x|C*yDrYhjE6t z2q8Ywc^6l`=Ecq>+#nqMqTJM)iA`*8Ny<5OxrW~Ow@}*+N;O*_4t2DSh~B`xHdrs= z&NiBfIo;_l!yLhOwodR366P20jy7#s%od4_f%wmEaR)nXp(x2<aulTL_pkaP*!l0@ ze4#HWGrnPuY^<N9k8km7ys}MNYBH=?fg5WBT+yi9+;FtlW+ES$-3`j@`A;xHcYD(v zk&wb%F=F;*Msq8-G2J1*ECH?BNIN3ACV%OgwPC$Zcnb;0Gfr$57_%OC4AcH$4r#|D zt>|z~GHj%y$JUr;fAIU}bZfF5rE?w6Onkdcr3zi$qXiaV?eZ~m=R%L8a$Y0)zdv^( zbKMcINOc_g&fN;JLj7r;XJdh4g^)K=8a1)5N50bxIvtN}(~H6}JZEp`X3RyH<2acv zDF7&*JLes(XnRu(7EialY<XrMZCiX)@DbPfp06-FIeF{XDz7oZ1bx}LHdjtV5&bkl zpxv@nd*1^L7oJFg=yEh@hQWEG8&`F$1m=cB@MzR4;WyoziLY&g209iO+v%mXz8#+r zaG0;Y5PkWvE<GHPWWV!LXjwBUJ!ufy=U_bT6)e4w&w&JBWHGM2XJ!3ys<R4g9p_Wi zad&+ffR9Ph52UBm8{YHeHv-<koF=>Vv2r>L?}e@_|Gv9R0$@@cXeqfp<Q4{f{iL<$ z=2lJad(U2&XR>*XBw;iJ!)SEj$n%^RvNE|DlMsV1g{+*6_h(k7(Y>023}U0a_-H;@ z({0+TJGQ$Y8A0q)`V+bNF7|d&hizo=CzhvNnZNJlobIf84vD|4EV^>8i2lm{Fs#xj zEMz^g9o;B}G8Zn2oOEd+0O_^rj=oS-`(PQl){$QWA+tw_>;gLe3Pq`QfhAyx?*0Bh z#ZQ2P(5Lplk=|7Bf4AtIj2tcOo&RsH=el;>6ixhnM?tn!0Wd^rx*|zc2^pVYQ<<dJ zP}Fc-@oI?!MG`_ngV1LLR*=@&F5K!K{q81jXK%mB0b~I7PtJnPQsmb!DJ|{oEOi(P z-Gy5xf-N+5nSg4?`3aZv6ze8_;hc8$XwsBA>3La;IwhwMyF2xIu}TKvaz*xzV8Rd8 z5r)ozz+*~hYCpO1Bww`{uw5wL0^=|{wMYmKh~C58y2}Es(<OQ|*BwLgt#+JY=T3mQ z40Up4^x<jmN`HG0Xdr-GzpR|x{0FGt+STrC?+Ib7YMq>iicm(eX=F&fSdzD=={`Tr z{?Vz{=R2NNPIlv<zYU&>3aRqF7MAOOLO&;iCaKf|sF^fp)hA5#CN$$#7{aRai)whJ zIPuh-5z#z?rkg0AgkZ1SMPrJbM5mkSm~hAIdjYo|20R1q0bFC+g^lNY#qkBgyA+6P zre_VIhr*mP;?-AR>O39qUcKC(2^cs`1mT70&NI8QP65H@&Fn8*&m4bW|BTvP-)x*b ze?K}wBl{D(_<5chCNrgP12~2CD))8jqk7}E<>%+c`&AF03|s=@ka6eWH!AX*n(M^} zDtI@|y~CK68}86MmZVg#{wPBbnrWU;3KVPrQN#l~G}6m=-Y63<EJb%zdt%7<st#(2 z1;k3!-Z<Cq_l-CCfC53g@I|9nMQkjU0L+H(`vs_bKsWkr1la1B+JDU^soQfF=X(SA zWEUz_LO}0EQYDZwJTE9w3J`hHW<2w&Aj|<-e79~N?jFzu!6B1!j{N$T=&BSr<P{9X zb+Ye*w;cpg)mDcm7hdQ;2HJbd7<GT!h97R>n7eb|H5++m9q@_wnkqo^$2Q`dWdqpN zn2x8S4%{?G66qI)`&9t3U<x$<k6~T<Fm6;zF_>5&ZQviU=}>&}DwAaBxf+UnYwU4W z?jS;fPJ+*|f}QuL?dj_)Lr;$M?o5B_<E$mfc*oP3UVNWJzf8oVYkK@#_}?qPpOx=1 z-tpO=)*X63$F7~}OSi?#&GqY}>*wKhT0j7pxEJ-Z7Rex_q!!%HOcol$8<h_Cs|svI zK=`Tt#J?APBLts~>tq0=862fWwgBVs56j=9r@6~?!i;WCqqvcv2vWWejoUALyzhB| z;co!WX8JStR0Lmyi8u9~G>IYP+OwDWDbJpSVb2~9aYTQ&<c(W<o>7SWOM!n2f|qM$ zsiW*cG@VD&0rt(bW*~6ts8kbmX8Ycw`1?9Z%O1NK{UBdb`9LyZz+#{h;!YHp0tu`5 zpbE7aHH-lvaJ%0Hw=S^(3P4EcArKvRf$oOhDfKh#i2H0hW&2Z7?DP*=e+UW%=s*RX zaIH{Bxtgztxv?373i^1EVaht31M+}f4>TSvIWv>y-$}|@ay81HGAEItP7Y@3_01!3 zT&K3k99f}on%<it5Nf_Y(dpExa~FcMg34KnA&VRkg9P;1NjB^R@*LT-{Qxs7R?l8h z2WQf-Aas2J0|0^NHIBFe5|lIvF(`8%0+*R_K-r1}`Hj61X`6>pdzu3?n3Hgh5cgv> z28o_Lt7CKn@u^5P{&i=Fs|vyrlV*xYkeD&6-MMqjwN3N0fWwSM*e2fuF=Pz`{<EJJ zV(gxP-r9E>^kg23F!73Qasg;zJhEUPet<FC<M!%;AyoOT1zkKF$bS#w854pXR_(sX z6Z8Q=3ZAXkqB(HpDk<ytavLg@Ux98Q0tOLA3;jURVW!E?oFFzZ7_6$XFT(p8rTR0# zVllI$@@gtI6l+iwfR75zXwCM5yaohuE~C!l^Z-m%LGFs4@QxJ%bg?33Nv(=RU3uUA z-nhpEFb}h1l-dEvFylF~W_Ifu>5`a61Y4Y>Af3;#dBGZQdbP9yJaP+(Cp-(#c;tYz z@X0G$iF#UydK!u2s6%}t81bxXpdwynV_eTqfPIvXJ<`CdX6~U}L7y>#sG&U=03~LZ z*%-c++nA=#4@8C1Aw&2I7@=>uB>RaSSjpY4A=7NruD&ITMpUZSh`Fg#b?Z1+nG^6I zu%~E{SbBxAOMrkI`d5b^q6J`^HnT_{KZ7aydk5{q=LPVpYB7h$OWRQs3@WrtWn3Gs z02_ey@P332P~7f0#=|sCbH6XK97c?zp!q*fZv?>#(lPHTB6QGmBlQ>BWq}!?aR+T3 zU6>}Grlm;No|O#Fm*EVCZP5k9Pr1wlQK+ut7YxUS7$r2Z>Jb-NCrqcAJTWK<3=p#3 zY4$WEIt;IL3*B=X`bj-@5{y<QZ;kY-&eL^l1wYD*bfGIKa_2P#2qF1G$HLJnoOxcS zN_p;&?!|p!0|i`oWCKSywmae4km3x(YEE#B^@bAHzM*aAD`wgD2YB(y4JcBZdtp?$ ziol9p@qp=Z90}kU3D_or{Cr{?*Pp9i86DtNJ!x^N1NYYfCvE`EL{Y$*ZTPvR@zlK| zX>*wCnO^lTrK&*yKFjtKTtBQUAJY;QK%^S#x9%(f#I*7h2e#^nMY&KSGsy^C7(j?J z7b8`+tr&p<z)q0Pk)hU0lJEBbiK&;lc)O~AbpvNegCJQg8F1O+Q<%_ClD>AiW|Pi9 z$w1WUb6FxbaFs>x4PnIDQ|h?RYv6)PwlS%SQ@M*2MWd4;s<Z32UJ|qyn%~w6-~rgs zFLG-iXT1zF+(#u=#rx8Js&@ir%gU{5PFy*&Y}mH?Cc{LzABK59<;GJeg>nd*WuqAu zu`_Z;dNd?n!kvrp0})iK{g8eCyKWcc9+$;;;nCF@AP*2b9ulG(=E>BnxQ2ndi(V#o zl^KJpVIzZz5dysi{@n40`wq<v#CMZ8=5c`L4)*(&R|VKnN}&xS;jOm_(K9Gzjws3u zrtlS#my8V-rqU*vxeGK98UQf;b;d}Lxnr=R{rDb_3dOa!vAbPLLjQG4v!^rujF-tj zQBSXY4L+N-p?O_w1BRRppNU6711g1;B8kK}Y~i>+OFu8mO?L(L{TC=iIQbu<(Ns5| zz!*(2V=RRk<EuHT|JJ)`{L0OK-ks8a2i?_)t4%hsHCPH0XIZB$RG3=OaOW7sR~e0( z;uS_A%g|Ej*r>4vmZb0N7#R~Q(C;f@@XyBf0Yw6_Bu_|c&Dpbs;m2p_zY~o<g!JQN z6RLq~;&=5%a{Og?$Sej#X6^L9@MP20k#)g`B-N6yc5e}dK_5J=DNHgPy{x)WO^wa| z+uO8Xwuz}OznboymUa$1e#sYL4_*9C-J7A?liqW=CK}Q{u)Pg`usYtEdA@vXRP-l2 zl*r#qvJ~xfw8+tKV)?K2`p8M{IPZ)8BJN8DV^cz75dIDbW6Bgoj=*c-Atsw~ZS77^ zw)T$fPF>||>qwDo3poI!fpdvlUHmW9AixY#w_z|M!tpr94v5nlmX^>G(`i}$IoRbf z1}A#Fxgdjn3Zy_i2N$QuefI2(;hK59Ci4(rVK|h}(mkr2e!!od`I}G#^Lt@oq`=$& zK=^_TTsS!#NWxJzfSkI=jua06G|2qaek>xqy5G;-Uqf5eRZy_DsK(86QZFA@o^GB_ zee|Tw&2cW*$JIu+)hn>@kDvANqgiA*k)TN9<eRTsKm1^~$Cs-D$Z10R+1y@^R}`CL zwql<`T3~AtkOVCL+*=rXR3DJRpomX^E`oN|4Pr3X0d`X3ibSPwS|>D7LL>>&3jW5S zNP1$(9hWduwte>ogd?uCG(bzhi-b!i2U3AZ2T_OA_Hf^XJQ#J0pyJGp6a2YpG0TG! zw7>j5evT6ZDD2?@Pm1w{K|TRxbY*0C$UhCuw4CShm;4zC91V;|00DFP02<lsOMqKF z3k{lUF6M1UhL%e^r5+h&1UNVjFwW@xiYn<If&{4?4@d<gFiKKMuC~-$T0;pHG#rEQ zrKc?QQ0*}Ec8Hz-u)6ynO1U}%)vv&Ngvtc-V~XOxjY(ZT=h*_B*>%POv58gIv?grs z2l6TEEV*a)NW$`>^%C9@H91gp9{}h3`+zS=J0jZWdJ!ZWi~uo!qZ>`yBMIpC40#p% z{=p@%h#1)f9H(UdHh2<{FAg&SE_G)zmJ!<BwzMAVV(bKSE0&1XDj^eHi2%-Hd34uZ zazx(0p`r>lrw+WQfFJ34L2dHP8v=nwNb@{1-AraJt%XnF2bioYR-4q*a@>j}HbmIa z<938302D^*CyE0$(ss-P*xs};G0&AD1edQipT&CmVC64H%mt0Qt9!DLMH*<|+cch7 znK@%rrCvl1by30)BA}j7*4dWs)si)M3)0FH%(>tiq}2Rk#P0N^i|Im#!Dkp>n}QdI zJB-s$Dp)_}>K3{q`*mOi$ZkG{XIwk~#;{%}61;cKI%gQQ7oNOUD_4W1B7uoy;!8&i zT;0{+^g^xjLXNKp;w?vGa?r}>IE$WsSQcgNN1<AY{9%8UspX?wqt+Nsz(rzzFEGQr zyk$xii|^~Cs*!eKR^;odz4VR0KlQ7vDVTYxbrlEYrykj=NZWt$=0J=Kw$rSxu-TOZ z8+5%*h(t}a%4M5eaaA(O04200!fJ>!!Kt&KGsXN_<jjIWR-yJq*5!^jYAFvEb>wQW zxbz`Fh!=NLu8;k+K1fs;R;oQ|yw_@IC10p|Mb>FxjQ#&CVx_%q7us0mE$&G+ubP1c zN$M{P!<dxAKrq5X*2b_N(Oo3hBus6Rw@5N;(t@M_@Qm9F5t!GAoPg2hix&F01}Ykv zWQ$M7HuQ9-7Cra)p5j1rVgm%_;kSUfeXt(*I}}v>;mH((Btd+t+8QP_JuJ@N4gLX7 zH+j_*lg?${=S-eUFNY~oNt={!JjhCeo-)r}-)sJTi*(fo4ymq`*N?NZ)`lA)+q*D= zql-LLoFA~b#i+HnV93jI2#0nrXJQ+N@(T|}sR3#f1G)>m=h*ds`YS~3sav9$jZ?Nw z9{>kK(&}XbBy>}JU<rB)v3T&U^ov2+FV#qQ^azCE7D`j#><^bKGg6+l2T9|UGg8%! zC7&=-WPdtVD#4+P>AKE9QW>ufqB0PT)C0sh$jdn76?o4+D}t=y!ffG*O&;7+5j9Cp z;=7zf`<Y+qgG!F5ip~kUPFt-VlCfUBAd_42u(Kti5!yu-?;gZdJd^i|rO;K!ghDE! zW%!F>L2IGMHqPDe3sp%b)3_Dq**+W762<iJaKFX|Y2~L7=Crn8B<9r7xdyTMg7Q0k zg_rcH8TX>1-p^bB-GZfn;*X<6X8MNr=i%OI((E9U&4GnmEEkh2uk<MF-Xn93t>=%a z-PBr@M4B0?XPruHnT0ZH5VbrNdIJIGc(kO^3sFI{m<dEmw;F%AP)FuCln1V*Qd34w zN1zHVp267$r~kj2PFjdksxzy9S*%{G32=4_<x3Y^%H8h|7aHbDi}9^sSYzEvaMElx zI7kJ#mENv$qi}?FD20#LnSC9W2}++h!&O(sjx%+wrHOJVo6%@-^>j4{*owegaUM$J zJdC=eHCGEO7xDBgJj(zWY%UgI>%szB5tCnKCps;k{Kjywk(gBb_QJyYP%AL7iqtHH zBNy5fZ9~3vSUi}0?F6?qbpexcW2moaDO5$FM01bPww><S0<=+^@=+EX!+<yYkSnxh z7!F)@hav$cKUN*BTVE=$hkBhl3Wq9vN><n-fAf}Ixo4SVrYor8zE|GAZl%e|q)1U& zUc1y^XTH@Wq{T?^4$KCdyz+yk0if?OK-7HAi)hPoqn099maqMmET9@acwbHBg=m=A zVM-=^Ia30KHDkw8L14ABctGR*`nP!VJXu_JYy{Z~g!UbO7bwK}VnT6u8=&^S9>~i} zh}@ixXSzzfiS|dz-(cG0rP#gZa3N$aZPW6{l>i@)b-G0Uw@PkWrq^Ijm-%saR3!oH z=M9&mca)|GRbN|6Mofmtyo`*k;9v2rr_oXA<M5U~%XC4p1I}U*0peou!t2R9GgP~a zm}}IE(1@#KPb)XC=GvRnJViA7rhA7BEh{xG(S(k#8J`_rCkoDsE5dUa?^Bgq`i+s= zWupzfu+i!rmlMvFsuz;R!gfb-ug4&`-fzZt>o+SA9TpIoxNU-A0iAp`zj0?N^W#g_ z)$zg`${=<SVWEXydCDR(Yvdh&1;Xn0enDV7gs4yz+*KW(TRCedzNsf-w(_Kx3jfks zJ|Cks5gpE%=Lp4h>_2fwUFus764e2(Z#EV5cbiKIH_+7ku~^e1s<g@qr*x77u{VYv zs!Mtx_kzN`0t|lD8?Jubq+7mkwh(`sFl2UR0Z@J4YUVArDf^DkQt7YeT~c&b&$We} z_?4_9sAq@uR7Vdk3E&w41;{a`M6l42W^d8m`XiZ9jfA8Z0gzT~Zr*%wTN-yBA1-yn zbsYaSgz;CE6CUk3u;l)Qj;^e|`s(78?2oG@h_xHi`)JIs|FK@N@qh64zH#M*Y04z^ zk3|y|ppBUEav6#Zq4QU+b*E7#4;fgS;(ft<AhX0(;D6+Xi$8<<LrvrD5;&*y)Ju2b z(4=p+s?;J~-rPC^!ca}m4DhJ*uPC=`9W+YMO$Gc^baKoB?WlhQ%)KIZ^qRH87JXYC zCoezz?h?GxApf&Kdo^@SdvA1PNb=nE4x;QKiAm1IK2^01IBQ<K5j@%T(sKLZvH6b* zgr{$kxXE`=_WU~WmeHcLrdi5T6|A*T9v0;CQgAJ-y(9>NEDVsyHfTHnh9uQ$1%$jS zg81Q|jU&tBApRM?70==^9$O#18%-Q@=d(Q&efkM`Vl8q$gW~)a^Cge70DnmVMk%Gw zD8=ePsdqvtjwRK|^^$Ot<l*d%`rZ{2qz6?A*>N~*pmz4>?&|k;;<A2Id-;Um@q?OK ze7{;2m>yBAvrloU=Q>WK!*+7r&_1w36CdyBlhVbzCb=&w*>Ar8r3@57hbheX004&1 z0RZ6ti!yL=wy^#O7!3RP_-(Q!{=2YHth+cABc!>`pI>IQnq_p{4y_D7>$7im#_6P_ znx->|P!k`d^j;eI9)bMb3rSi#dlze6NRTjK{>fRU^cmK+)?i*L-i@;LcAEs6*dcUp zyF9x={eEz=wvGGmjl7ip_FK3t@07Zrd27*5SZtiAU<yqy(m?OvUR~qo+>BleVHX{< ztZ{L2b8)<V46e_QQ}PBoV!vDKF557am#i19w^dYPdecW*2l{95cjcJkqid+OST}~X zjL|PAoy1n^qAwR$B`wA^L1wsS%)x7L*B-UzW>h5aMqPYx($^l(RwV46#ElnaOg{=5 z$XD9Qu(nTc#I*QsZA0u4<FgNozA%iR*x2*Sy<B!wxCQAmr>&kp(`>^|Kyf;zE-S-M zfEVu7QE~M}O?v3aG>GQUb63>bXzE#<HLY9Q{`i{TUOM;e?=9~vX>bnf@`7@4Kt!!y zF)9$mH{o)x^Yc!!xziYG+-7$5_ivP<87L216<KUd2r4YD0FYbYpK34{(apUY%x%$Z zbYXzGc;+4*d(XoKDN%XZvyePx&5~qq8AG-tvMd+m0K|*vC_h#e(etTrc(+?@a_F<d z;F*f><nF2QHGxGoM^9`vHXgS2jf<$l2h}c;ZB|ZHet9aC+JMU4ED(XKW}2F80z*%< zTId=+L#kw#x&-y|W_1+`V1WH*&i01X<AABbN<*fh@#LW$kBTfiu0l-c8v$$lsSHR0 zp&wn<_>9dFkx(pYq>;#5B9op)PLub@o(5P3usU=%H2PEK1n_S=4#&IYF<0L8a4++F zurbIE{zVSJK6}`ZPT1v5h=sS8FRqnN7j7mKeP93Z^E+uVsBqBO<S#mXr=*wIZQO3w z6}i}`?f$Ho-p>c<7vIP6^WEaEFYfPQQdC0O%g^+<+b8*srn=3Y)f4E?vei#UYHx~) z*G|`z6yWjLa9zbL{rhp|pj}og!^guj;nUO8+w@M44h1LQ-)t_>0JpbQ<J;@7!P_ju z!$+`)`$@a`z2V8}?OvGH-mfEkKHulkQ@*dwv(?$&Klr(N1nB@%BO@%G1pyO@8k)NU z{ttYRa+!d$4`#DD^Sz_$4C26a$o7~>{VpqX7f8A?PKk9E-{KD_X^D|zRO^FXVCzBy zS^Nb<s~20RB81dnt?Nd}+?6M@q5X{qB_5)*JeBvGDk?!Vl&u?8ImafN{=)Q-y3ltW zqJfv3*#e7$d5LFi4tJu4bXXH5@>~Qh;C~2wD)yL+AVH}GVf!>GfN-+F7)%;DX+iu6 z4U#48`+$82lz`k)S3Ep5j0ygtC1D4vv$FVs)eD&6pfJM8lLo#IIim~)<W3Vz=GVIL z8xr<TFy9nK<WcbglbxH&aZ7EE$AGE*oy_0Y5n=!!MHhiyHoJGxp*@jd!MN2{7XiUJ z5We@}j%swof_3d|&;Z;^5U+?|R?YzS%H{<E#TT~}*)It04;H~bgPaSzpdwJfg=5K+ zF%5h-&okJE!tf@+(RUwsywhmA3>SdM@{nLsKdjo`^FRih1%`*cS0Y3L;j3x%NRVwf zJ7j<u?8gfBYPKqXS!}e)8+t2z|M~$t@xrIQFLW1nI6E>`*g?uw#y`)E8@n<@YEB0R zEGt%G!iWisv*mhg4+i~Q@em@m6)N-Om*+cl<`wHH=Y{JESs})3wP6nZ+B2R5HUD+4 zGY{})ejFs((jFPV!#`qW1Tgfh*~6n3iGF`YIcP(!&*dI7Gr%aMLRPr67246LP&cRY zr1CNcWbk~N&w&+Opb^M(dpiW$%oYRQ`#53C6_SD#KP(_Z4F<Uv1rJ7}wzXU9U#|<H zmvyUsT5i{@@*|52Q#eB|6e<KZ9DaT^(vPAojF8KV==W@x#K0k-q(NubNMfgUw`VO* z4cAw%_R(opZ7h{w&T5wA(Bd&kl~e0&t2mKbZTD?>E5-Qh$4LqTn14lYzzXjMNUP4d z2kA{Z5X$Nk*4z6|j*#rh*$9m7<<V_NQ$3zPL60krBP{Qi3a|G&*FN}?e1C==)syoF z7!fFDVA+UJ+!kr3<Tc6MCU*Lxh*z`V;#*I?qZFSmzw#q)UZd+_gC%rX$qkHJ|D}F( zuN=0q#X`NCJjy>{ME@NMT73Ngn_C!F&^&+X7$^qNVk<8{@P)tGJUA45f|hq_gQ*(G z34nK`1EU4iYUz3jo+1KvD~JgrBr|`+E>QZ2Ad$OqLfYPAr130I0a<*x+pIYKL`Le^ zo5>B=b`o!c(+0$Co+k9xO=CMg$_|C*Lff+!<bWFOy1u30#B=ao1@1Z&y)U^I#)uN0 z7v6QH&ajCztxmV$jcp|`Q_p<xm{=083+C&xp=kDP00}dOnkvh{ZUq%J2X1x&h~_DM zTML@xur<{8p9#WKIHs>sLo8TeUDQ%;@VTi}f;F=^GRa|ud4)&EP`bO25CL_WC;048 zrFVnU<Au5sKT}{Qlp>8c3+GEW1deYEc>?*_OD%!4ge9+45cv3fvo^MwWq4fzQ(!+p z1f0d^AC36yu}H)JQ~;2?3H|4nFRLp_cEVuJAJ;o*Cb!DMCXk4O-id+yVwfe$0{*~J z*QR^N<NH)i=;!0yj4O8->8)uZgQ=;%XxQgt?XCma+1NeIN>B&b4>hhIEn0VOOF7DL zVyIEycwv1z9=a;i3}Td>LIImS30qyJY}7{E)J8!D%nEi{AgmCFDr}1S$T_!Ozprok zjnfL5vV-_7@okCtJ%PI5N8!>Aa1yGfc$qut$0-!MDas?@rj0spn3yTl>SusOOmD+k z+<n12desuIRO-|L?Q!@jOi4_uVrgiVuZDR>$?0kX=gok_PnF)&o8V1jaBCh*`YE5y zm!8q@2z>m|^L~{$Ni-G}4&#dkkt5JDF?H4Y<%UwYKp}xzGdOf}TOaa_Ph3R+5g8^N z6nQ2QRPOgp=HOZWT1Vt*_BNeJRnG5sEocMwO@R3tIkdNsKE}%Lu+p?)uF<4EfBh|# zwk^B9v0K73vn1bSY(D4aUB{0%#7&>73o8<DSk2`n_ataw7RjZp@Fr==@O>R-Cmt}2 ziI27qC*cz0nm8(Zf{<oY#0CENXw#9g6J;bDk~W6^5YjTdBB*YyF6K>L_4qJ4<;pKw zxc`hPvj{p5r2-evzRX2`QSegwlIRpxIZh4@Y$#nL#%zB`Zj?P@njUX#viq!?Xd75! z@7)>S^B3jD!h|Qn1`~Di7+n+Y*RZIWln3gU5z67bZOuK9)j#lnzGbr=pLu$=&KRr4 zfVHe)0)|~AvA(;CwLVlKR%Zhy)f1};SFp$_z`n%dva!zPHH3Q6ilqBVqRy{>&&Ly= z*A8S$91R!jtl|JS%Hh>FFc9Q~>nGE#;8(B=*ib}%rT{`9hBM6?DfTTle?)XzTt=Ud zk11blL*GAv1!&l(4F0{$wul%;gg@IsSSm@n|EK@2&`(Vz)b<GUTo%{qT5BCAh&qx; zM}w$xF+gD`mU7bH#UyOXM30R?TnUEz%KAc`KuX}McjibLR3-k-n<2|b>yGB`W#c|M zLtG2Hj(NcNv4Xp}4TtIsjL9K+P*HQOP4D5+q4Yaf7YpY%gD$l0Yi*0Q6kY{${`$GL zF-hM|8Dt=evit-al&^sw>7ree4Snr}g9|D@3`LG393mgF5|8YDt1^mv(vikdXaSct z!n>yii95=`qO#_2LXAogv_b&(N<a;r12ZVbb%1#lRsw_fDwzPgz$~Ja{8*l<8S$|l zm$>nz_#Kga)4tthosj?n6D_{PmIbiaI;29OJ}!$V#)#8pZl*hIq`T6pm<DRsSx%~# zSBaI<*cgarU%VKrm~Pc)YwM?rK#~sgQ&Pd8UL++Q(Q|^}u`wxmtcgzXXd3x9GMl+^ zT-Laws#!&Up)XV{r7ybLO%bTaLppwd54OK+oq|cr#6Ij2grBe3vmX}%gY{|Hxd_Xw z&hbY`+4-sq2*WTENfGNpY#L1%wL#xoMe@ZY96!0YukgKcJKgX0ZLhAsBog|~l;r;b zdO(H08L4Y?*8GY`jB_li5`*T-ESsV~A#DJ}<R*oO6k&w?*|dwxphy?x1fw)&S&G{N zDTQRlUF*tmRH66>D0*#JU5-wJzr#}=2kKmrw&)fj|KK#O@AEPwi5i6-{6nt0@&nTv z*bj)G*HuXbv4=o=KlZkC!IgMq-TG#?xqvx1MsYbAaM_r^2uEgpW49u2a#%odpdz^w zszO1H{SX0L21$z2{ft7vwAmDdX*HX-L#eVSFw!-!9>sqo{Bnd+1m*fw3iauiXd3-6 zT!w!7d^cnU$w<{`t}SI|U9Hc&ii+k;IYp`tztC%0D(-|d<Q-VUpi8x-8AEY0c8m_M z>4ev*;#QfHo;5)Q?z|Mr*2E;`P;}WCmx&k>(wQc0a`~9tW{(lfJq#r5M3u%1_+l97 zA;KCnQ2619{)s7AHyW4>s4d-4C=d~ghJr4hPkq54V|a-|cuHS<9EQEYKxowCDo{Hx zm^n*lU00Cfg*phFaaEzt{KY8v)X=JcJw;3-s8Y!F0fXsyi+%zo94(L0z1V7o+I4%i z^`GHDHoU<g&tO$;QNpDZ7Wv<&M~B1U3OE6k@5^*@i(;wBuG7gQQU^>z)_g!MN0uU3 zF*YG6st}L?*bx@xcPi8zKR*c&7+)V_^9EwZ;84+V2;I#}QkTPvaX2Ucd@RU`Pt;dK zSt8qUNcuyL9%DHqao%RLCbAS7VgNAL$WG@f{({t3VMUCj9f37Hx&^5&Be4)6jtM>T zS=K^771~Zili%xx63C5jk?p9st-fk<Rz&iv@cLbgUqA`TZlj%Huruh?eBxGqA5G@N zz+hOxv{F^T_aRk4btJTCHJQiioioa=<|T?>%~jbAeoSoLg~Z1kT2CAMQluFy*3$!> zBnG_qd4n5Br+l*HEzKJ~_h8ctgV8cgiV9wqrz&Dl6EF&)WBsnKe`+j4ca@|9dNtxO zOyn$pQZh;YR{$gswo&iWVvz}8%<oWd;I1?VyK7Y~ujHB>zZSP|((4%QX_Powapkmy z69JJi=YnsIzptTpN(PI6E#CfD3S(-&M;Ncg;D&%=^j!f3V*TiwBT!K@kl$1qtBIWx z9Ij63hVf3Pz;?_)(XDA|ijgUUyO`_QVh}X|8Xh(!mG$P8m0Xhbb#n~+16ZFoyMo*F z+C!sNN1Nf7S4Dd5QDY<<kDoUe1h~=NK3Y|4w}+-#i!z?eF!wid>|z?)PGoI-)g3~M z#n)L{reH`AC*p~$X<kc$wo{THd`c^x-A?hlPpCcSSuus;%nf*8qR`&*NvOD<0UBA< zP6sRTnA{*1Q-Q|he#+`N@G5-wApkFB9TO=(Myfb~TZ1foS}wsuVijn|z?W4yZAPy? zlL*3u8;Megq)>fjc@Ms#Y~z#_u-EEEFA%^7do?LQmhq{wDJr&ekZX@ob@>y_D}g!o zE&*whw@DJA7y~^E%tdWN;lmi8q16Kabn}^<GO*C%R7A^<4{9OTCdsUtE(-N)T20`q zAqxnyu%W40{5n*2HMS(5ks+h$07-%(T%rrz83vQ0(d`{E<KUHl?h7Goh;3eMMqPiA zP~9*v)#4-(SVQ~NvML@+0yvA$CKQCXcnT>=#%={%AXc<4_xG?AuNlB4uokrJ_Q5}N z%ttv;MYKXF--NtTMB#Ac0-%FX_f<`*G+O)UfVs=qv-;S;MAr^bvD>ZTBZXK2ojGXy zfvw2;cw51k&{2?U3_e^?R6K&6ENXOF@ZjYbg;Ig=7Eacxj)UNk92kMztwID4P11_V z4FO%52hF6;K{b*=6~blFEard`?_hl>LDV<xBl^=2x0@8bbhHu*VxbG4T^mI;NeiC3 z_^QNZ1_}a4XTd#`Pr>e-pd+bx40sDIn@M~$3I)LlZW!>w^*s&_X=X?vJUoUNZRO2P zz{M#tL>m!tc!oW`LB(5s8BBf-Buaw@=I@OeqlsMIpnHydFWdUoMdu$@8w|owm(Nxf zmcM1}*S51Y(seR=MqCl%LJ0K2c2MWIY^q|>X3t;^Q(WnQ-+J}C;NuA`A`MhD8(=R7 z{A`5R9Ulv$TDdOS?SZ0yQ3EUTPAXK<eBbypW(RMi3Jz>qHVz?G*$wky=ih!o6+5Yn zXJwB>1kp;7Jgpy-dQpzPO+hEIWwUsRhCY8YUxRhJsIw`_mR7S4=p{D;v$CqEkuGBO z=UCEilwSc*LdjYzaDpVLd4Or`Zx<-lBok0dS`9PJ$V1>ss(=VGSQ|R15_h;*W`TnU zYLpRs#8pFOhJGgoE>B#;Yy?rJH3L)cECXSgbNDpBC&K`1qcjzAiU7pjcIAoKUutW# zVqofX37Gf~U^cM#48Y7#=s+LXu?q_)1&9$`1uEoLLpoE}14@>W(SaUJu5hrh{$&NT zi0YbEF+LHyg3APGKiJx1wLm|!f<^t6?Z+$tgJW0&QarhhY|S!I#}Y9T!Ku)shS*`% ziuFjvMoN<l1ok5c;Rzm6&vser29jmu(ja9Q4>@X1ys)wCmpyp~U3nJk1FG{7HYTSk zlQUwxEvteBl${hHdPX};;q%(=CP*kp&G&p{(;zu%Ef;M&alICb4x18+EO=;(!y}?# zrD-L6_>s&|UktubuLMl>s+%a2YW^rZB{W&U{G@#=P&WAsS#=|9*qk|-hyzx#D?Uep zp)f6Npx2LED6^3HV9}kxs*1*qe~dISmY~iqDFNS6%trzVjbxlpAVwoO3K0ct^EuhY zu$(yPJG9p2sujuJT>E0M&{>TX@I*absgcW@A}?<hx;;@Z)Bu`-IY;))uo9YtqMlQW z&cIsSA=@AV>)ew!G>T8c0ackgyIvG&O#|7742F|7o`ZGH%8u|~1|crUlN(S%F&G(i z2h7_cgtfKVC=5vCLPEcH{IvBzUp`bhlc9xMOR_Zo)R;OeClw|Mu}ur%Au{Pooax2q zkF&1u*%%ybVfzFgCSL^itlu>PV3nr`Gmu1zD&hU5H9US#i4H;dnruL!Mq~NK1Z^12 zJ?sG5Q)JM?_U7WpF`gYX9slXt%*6h?%N#RI=u#4gdPr_qTYXx>5~QL$Z8WXPZ>dSD zqe`=N;{r&lrqN-XX^hciymH}O38#|fNA?rTQn;8>v@`0ZQ^yZB#atS9wPLE2MXIjW zBB++=jF3%T=IB|SrOoY-RSL^v(8PRV48-5OYVwB=RiH?J{8M_DvhfQ~6RWgEc1$PL zij*O0w;fRckoS~LM{EQkI55VG=>Tj;3k0xjXLoid2+U&x=!?Oy2`=SbhWc4ZestOM zj6w-eL?HF>yu<V68PM!W5u8|aMC2p=;)+!ZeEKVqVG#Tqjm7W6hGb!dI1TBkKR$&# zeegO`rKnhA#9t%=(;}T+PGQjnn7aX**@Aa=s?R?AY#8iRe})ecLGhP1lf6cYh|;mO zJaY;P+gRoeG3+*b1@E8adNs}3(Thw0c?}yjklkXojGCIS%{2;Da@MaxVUv4LZ!Kp( zz-V@hO?m70nt2LY-JtYYdY6wNJ!A?aUFuYz#n1AeGq$aVtc}Va?AI4@6*p;vepC_O zO5sY5K|U43?PT&2(uxLBwAi!ee+`&!F{YN*Dg>UxIxE))*03={5td@3R|n=57v$`q z{`)8QG*7QZZ~c40y<(v!+))piTGE&bfRy2dX7sff<K*@pj2UZZQS{6+kiuce`^H_~ zJXi>iA14P|!S^5zY$@+HI}UZ=Btt^<@^+A858Qa~?f%|(``;vQ-<-ZRTF~lA9@fTh zsK_%U({C8Ocwyo*ASjzc6Q@9zRSUPpW-?TdV)ty}$7;p2*GscnbQxBX5(6IVg)FEZ zrWMm@nq4lgqwoZgB3n~=opJjqNZW2U^=9>0y;hogTD`!QN-j}G2DLhZtp7lOEAx6) zyPm^1j#=76RB8>aK{7+1Fw3bDnTzWV6o<ACarym&gR@N46@Z>RForX6#mJbBM*|f# zcXBR3;h)}#qk=0;7b|<QIT=Ia1m3M}4d_vh=>+q23XuZ8|CStm=Mv40wBu-0O`kAq z7#lBHnnn0Jk$g(xs~sf9+=!r%^u&Yod22hXbwAP`l@Q)#(5ytT>@Z;e*p+lV({XKX zMb#B${SGRzplK}S4x-B!Lw6RNLfLZ8ujqeW6$Ng^*%VkgX_V=J2b&`oPrrI#aoJUm z=;&smWjSo3TyEr1bhL3UVP%@lTa0bKAIeauc~;+~b2|QERZo)nBdb{nCY?oSR*5>p zXqk*p-lwfBg<;fLTFdP|Fs<@h@R$jK3gfmu?i@zWU=3vh?DlkMN?vNL;4z^KjvE5% z;5UzoEvQTdmugW0)F{A+Xho5*=SbSrK6Zfy0Yd0a`Gx~HBkRV4p?W!$8ip9pt28f| z^U5t6)TNv);!vBa06r0s102XQt$+iki6+C)$=H=3>HG+`13l6x4G%=Xw|F(yYKiPF z#?r+Vl7!RxCW(%R+5pthaXn{UBFk#(X+UOK)L_UB$~YXjP-G+oKpTp*c6e}PNAnFK zm(9h2(AHuz2aXI&pZjCYc~^3ug17c5EN<1NB#)2`eUhh&I7rEI-iRzbrMX=LFVtZp zEB=aJis-G8fNj2{b}%Fb|79uol@;lt5T~#STP}74Ahy%c8S2d&aVK>)uSNd{{b{E) z=;7xYMFSD0xJ!!87aZm#$uram(sS}|$w$L@s1eA(KKs}O&0yq#yGUq}>r`T>Gla9( z<W)~xg-{iYG+r1n3j7Py{GJXQOd{)u-z#cK?vb^`?-jKKTggg-h+S8lr8h~?oJ{bj zvkDR7Cork@56@2iCpmEvEr((B<?-j(_b;OJ`(MXf@ym<B%f9Rc=go@|{Et;8uu!7L zh}B*WqVeu|e1YFyEU6ovk40_j%@^bI`>l(Y(Fp5(84ckbd=ozb5dOXxeAxpJP{(yI z{(k@D>!Z{Cfqt4v52<A@<%Dco!8o`NAPEvTuma;TZljzOvv&F~$v}pm0r!{3AuRwp z5Oi~d7w+@*_Ht!L8WW_Ojm7hMhLI{5mE!4>IVq;y@o|g^(^NYlC#Pe|Z>BBcLKB7; zk^{7tld9mOp0uV+sznKF%5G@*h-8_Oom9b;-vY?cB(*!IJBXi*f>(W8e*aYZuA=eM z4#|~Pr;1!bfT;9UqbO-!_}05U_J=s{|Cl<m(^^&^cXU;uE13gO+h3r4dO^-%IJj`9 zsjfsUQxd#-h!iKR$X?R1JF2B`!b;;yL^<N_h=_otgUJ-$N3<h7oaxLy*(MGSIF6@t z3t`v>fm5LyLp;!%t8kMz_|S-O5@ssUFz#|RArU@4r&bk2UcR-%ap=MgV}VF04h-iQ zq@zHIpqQgF_*-61t9vj@q1d~ly*KaP93Ox4=Ijk31n^|;cRqhihavI2{SY6N440d4 zn#GJG9_cJVhaK-W<!o}b6y8aec}EeIDU!}4NyLtiP7nUhwJU|D4@;z@z?9I!5Xw4i zf}2X{e_cykB2*Mlc0SAjG!~7*e}n^gwE{;1rQ=Bt&eQ`$<)=l{TEndmMCpf}HbQOU ztTMO@a|!AlMPJcYDF@7guvXh~{QSosnL~d3(Fxn^JBy&?REL+WqHjBvEpIx8I<Z6Z z(5z?4?96l|?p<0pQTQi{eg!KS_fA9K3Wb?#kb45!)#QBcVAY8sU)72l!VQLXPYe)* z<k<}=bRkPA*M7*}15hbs^e>dXPfMIIqO!CkDcK(79i&(yF$!SS>+!3m4_O?o?YgyS zXaiRFc}c6t@p=h0gsYh1QMfPf(;Cx$MBz7zZ$vcS<w8ZVNf+NPyEgUHz9z|?KnL6r zOK&rDAQ*>)ozAEO?F5wFCZL*`N5p)1e<%q82nd#QI*R0gp;Ja4?}lo+Q~i6$r8uPL z5Q&$ZLS`x<z9<>&P{<00lD>Fb*$rjIiJZLcP106kbx|7)=Bl#C(c%FHfs1fvR=|K# znjB>TfGfa)vtFdU#AtFTEv_qIfSVZ>!C+63m~b;T1U+U8{P9OnPJaARilk|c!T7*L zA~S=MFX7hKRw%^_z<C38s|iQhPiSZS#~(RD9D#Z3>(${wOjw6poHNVG=mK?L$dC?A z8{5W&VdUM{?))XD(mPdoCZMmwfV#qE>5#deg@O}MsP}UFDR>D*Uj`Cqc_5p&p(tEF z(hg#i-xKpMiPXf~p47w*r>4+bX^aHUFgNH16kzqpNN$N@PAKe{viY9lq4f-_;a4P} zxt8V$650?yN52StiEE)%edS~U26D;R0N<9Zj*00<adkUccBmuGwK^qPwGVB}3c46o z&56sLBKb%Q^=II^|4TI|Ysp8(7`q5cN@?1mxMD0>VDyMQt)?$W{9>ni{hEQRM@#Z8 zh+P?RTED@o+t3rzsI1*?4iO{&Gm3&7Bn}_bhUF6@m$m8|S89%y{`>$&lctviKiz(b za0TbiX;rI($0tYsy}x&s9KLzKpS(HzCK2h?O!q_>jnl24ceeg3xp*0k<E;z)nOvxc zF9t6LTkfWw|I-1B>FO-@9vlodj{oQE?a`qhgF4)rKSt-%^Z3j2>6hI-QpBH$JRlUw zFO;kST`%OU_1OvgoUuV3E9Nt_P>r+c8fp1bbpR=d$|_LD`-LY>SR4)@_=;MRqI{QA z-S%B@S)FZUd)>s4j|QE<q|=~M9HJ}5B%pMtsG4#jYJL>ivhY1bnvBtKkYC5UGmg%P zgpHS98FVIX6yq>dlff4O$7OVd29zUFH8bOJmdT#uteK?q%&Ad_=a=CyF#F>62R|kC zhf?hM=S|n0@}dJdE;)Il7&_U%&TcSubfS09<Pp7D2U+{7D;R;H`u^!aN5-1Dppa9R zNLXYid@_!PKx)mf>Wgd`Q&K>S{5A`oo!!F^So!y=I(xQ3c*}f>u1iumB**9Xfw~%R z`7DQViiB$s@cv@_!+A5nii1Ce1APglV~)TsG7)4nx8~=Y0D~#=_A!`cFeRs~E`hp* zCv6n7S@Tp}jKK5qTYQ$q*D<^}W|O+vLJtc&|3#@?Jasq==DX0MN-mI63XveZs;VG* z74HnV*SkCfyQIiDIM8WI%J*z)N|e>yq_kj=d9QoZ?+pqMiegJ7-^S**Wz+Khqx0~2 za~@L69fS7!6{YGVeTvehBa`k7@fE-hFLYlnW(CCiDi&EoTb=10*kP3Q$XW`!!(FPh zc-s92!8jJ%iwce?)cw{9p~mwf<g6$HhOW1XM{;91eBo}N{W|JeQfqVF0}&@a+1Oj& zJC!J$u-0>fU<KpOi!D1OY*C^WOQfis%fnEqlJA99r;zQ9YEtIW0@U+Kk=FLz2NI+c zccI!+S!Vj8K_o?8P+kvk{ZGWc_K9zu@}@w<t3da0X+|d;$c&V7o#44?y66!_30?t8 z`(A>fQL8KxEEg^6!e(O;C1_aToAUP6U`AI7OIHNOkSy?y-x4HLov}e^Cd}N_MYBlS zPnQG)o3B3okN^6QIQTYy;2|M1x6*<aHielB=H#MjL9EFpf*ZcVHP*QuEhm8{^-I0G zp-eHH-ME=^aB25;f}IvcFk=CpHGv^7+pROuLe0Gcx^}WP7(T^g*KD3|W3D8d|IG-m z4_yjX#04nDb~EO6k`q!mNG9zvrsJ$p!LmeB*nkyjBJ$vHNs$&R7U|byJ+nra<Vog% zYOLc92J>{;qPPtsnU9j_xMpbm5hThwf&VS=SGVj*mgO`)NUrCNAQFu8Fvz?%jLGTb zKTn`Ix)<@{;AVGw`~LnOh%nun!c<2EV0->J&$opR)_^IjTUn%+(WKGx3kZPEn{D_{ z6pD!rWC9*c>b98Ad41{BBCaT|GLCw1rTz`f>De=h`>Z%Zo{pqu9r8+F_x6HIZ#{2T zbfkmwJ9|XP_Vq``VeFxM!;HY_bR{m5&p`P=&%clrSi{Pa%l^@fd8#0XQkTL&Bqd;0 zMa8MPA+ZcfNS#uOG0=Q)4}@C7?4}gt%i5RLMnzdqmAuP2P;Vj+^^qob`N;d}B6J7y z7GjHt%Kc5272<iPO0hoU#+*>vS$}lj0hG%@^5bn-WgyLK?X0m-{tyH!b>^lGV#48I zf|eqb=~8Sb=_hXVcK?unn*prv<HnD59+-XIOqiu1DfrQy%4P~*fU3^v&>MAB=ilhu z%K&$Jcf3;G;|OQnRQe<4b$$l~4DGbR6mdbL;2x0ClW)=ks;b4au+Ivex!TzqJL9k! z{z-1#hOS#<_La$weU4o*RfJ2|2T)6*VfmEBNd|@MqyX!DX=o}ISk)eoQij@_JGitt zTZ+9P8BnN*YbO&d?HE8+66|AZyV!gD(v2O5YP3gW9x}f2g^uD!3ktQ`!;f*EnYp_c zk{N|>L+j5l=pm`RR7D3OMp!G=Map5;nD_Yu(62{KQv!pA#B?xUT*A2AY&VNbOk{H@ zrLTJ}w;}NCIJ!jDuf@?8RS#8Vo&?z)Z3lNnhr+AxIi9b+znRiK<Ejp4+%6fID@5tB zW*S#lT4Aef2b3#ljflPJDQfW%n%5ZJf_oLXl?}6DnfrknLkS~j3+9T`H1~Tq_}dL9 zC&GD7kC0nomeSYO!6_~K8YX#8C$hT=6o4xO0W1<2X$+u>3<TE)QWwG8DR~SK%2+4- z;K`WEP+nKmoTG6E>SCGh+<c@+N(I2S<^-*ro;M%m%;*|g=Y)x>S7cYMQCIP-5CT1H z+rz0RoPPcPidm(!_*V_FlPn=TtTZgp1gKFvB`^b{WihZ)wt7j9dZz|Wr+qKI`Q9^( zE#Y)UirIB(WDY_92ypkwaOTZ66UNe&ma<ej#3l1pa8EQaR0Ng`CWF1e195mnP8^N% z_xhNt0-G_y-F*?-4RD-&QaoohH`mS(=r}H8N<|WZuPep?PcDk_80_J|hYM8yNd?EP zGMU?qz=iIOKQ2yIGfWU}=r((#&AQ*$N>4lHkP6ez(qps<Cr@74JZp0+e!Pl`N~)(S zM?FmNM76=S-8(CPx<L1=7*rZj_LF$-PmuUI=Vzt+i{-ABPSEtN2%aJ5fH?8`9D1gX zzdmn<9j(!O;2$wT7bXi=He)OpEpt<1V>38q{YGq-;$35#LP0te`=_h2n>jiTtjkmD z;I5qWlZp3531&(oebMwB?|PZa8#%!eBAD9*z)+c}syxqt*#T^12n_il%Px69w|3d} zLCQ?8v&K0WPBz;#Q!LGJtp!?ZP>Ar-NNa$L2SRs`Z_OF7IK9ObB(caip;YuN(0p8t z&nAlQJCGX_GEwkJkhz>S!#3qAj%S1NtZ|x^$%MNjX`)jit8o93^*g_zFwF{`y~ei} z>$J(;{o`#C9Bk90t|LCE_DuAotMZ6EI%GZ>(Ocgv(Ne!gSZ2smV89s=YTbjccSx%x zTJLHRB0VbFlTme~vYgxcP+$#nG~`6riHBvim}M5x-(`;+=eE-E;i^^7dHW)z*0QES z`;{(kZErw~(M4)RisgM#6R5U#UYOKM7t=xg%dltFP_P1_WF9yMlXEW99l}>P8Y;ra zos{C?LNQ=G=JBcAI||KWB+6{v6G}*}lTtGEoK%&_+GYII_)y-K)qN>-W3IGR)o80} zWj<*#PqIoZrW^w%R6d7|1uQX+G#GJBKCow7S{;>q2gx_d7~?|dbxjN0RCuJ)?&7^k zURm6dl6o0l!_!oBBNc{Ei^HzsdPh%vvbDuYRtoH9Ru}|v98)AKj)~CtJ=KXSge_h{ zBytN&$0_EG=glnp{4Q6<ST9$FlqC9O#L)fH)!ecqc3xIa+OST!9_uv|8AJVmR{_P3 zN7m8G$+U_**Y*<6P{a{SZ{Nu?9w!yXMg_idPCPbkU6t1f(7%+IFj%_QCT<7qZf`?3 z@AKPyo=x*KuIlS;{Iz|S)<31?^Vff-a5w-}JW61A6;CyrgUSk4L82mDyIEXLvxkIE zA<<Tyem!Q>Vy<Xo+7;D3x)3eBj)0ht^jWMPUf1dT##|}7mmMJl>XD`55gl;GixVVs zO80;*GryDjdYY;Gux99;0@Duzl4<i6ikg!fpNz2%`ezJE*tdkrey>;Bei^(R1+Ofz z1EiG<sp+a+KlgwOa@;;uONKf1{HgX-Sv*RN)MkXAXfPRI#;)$wtzzU9k%he)S65az zQ6wq-asq4=RpBP(4T;ALlU0M<yUW3z&ip4rP1aGZ`lXCBoU^=)%!fnuQ^E3_xhL<p zNe&#@zP_;=MwRZ8rqfKLtVR?UE_XAuZ0s&DIn@I-)dMxvgXnZ`@AvneXNKN!i#rdl zf*-LcN1^j|n`}G4B5HN%Ix8u*79CE2mA$^&_>A;<=@QZ-*DNU`KdbJ%?*?Kd<|8Tq zexi9=?fk4uS<T=N=p1%yx94_sy+;(S7J1rrn?Y8nYMH`cyR%9Em}{U0&G6?)vzKIt z6GB99S59M(5O>lW>u0jv^>A7_nPIy1B%J2Fj{G(FCA7U!lZmAc{~m+pinkl4B7olp z;!-mVFj>IX7x4Elq|$4q*T75PUblh=Fo87feXG=Op`&_)=VhoLtr@Tb=tGHd$2lc% zGUBfYyPxwpWmJbh*FVFbOZantQ($b?o0Gk_2jA}}`+q;%Kg3YUQ%n&M#!x!G{+aH+ z!LOG;zn0(WUx3)>!@^Rs<|Y3NZOKs7g+Mfm#J@=wKaMw$;?C_*+$JY7{uxQF6)(}# z?%s{1!To%g+IJHqF;AD#t~VY@KX+sAjdKPUg}Xm<>|77rl7(rzc0LAyP|_vXeBx%6 znML?wzFbfv^jlk{-8I*4AjVcas4E1hAhr*MFlyX<A%@60Ps4-bhG(O}WQ}Qe>L(IB zBe}u7TMuE5f)Gn}CVH_7sLrSGZ$DgoYrGQ4M#Fknf3seTYC2plZSu0WNd&NNn>_3K zTY;DUR`eE{?DzOLghek~qwqK4F&kUv7ejaLIAtV;)$BpXT>qQT@xlU+M1Vdxc6(2T zcfPD<B*D^=UGgEi>#DrkP6qJzsH~cVF^?3uwrbZG7!5jLNs*v#hujRg>-Pw(R(kX= z=utOTpNO#{4bOMg-RJsEclg2V%9$Bm`|8iHKKryg;*Z7}2`#+SD+Q^Hmjt1l9a?|{ z@#NL6bjl#jiw6B6qJh`(1AAs>*$j85IAO0In8lz}Q<(ee&FS930Va<_sJO+sg^rmb zOZk#M+*F-mByHYWP%vLDDF6#bSX^O52LRZk!k_^NuN-bVXy_A?jsmp1fn@BxH;1~* zmjEFW6!k4*@}rk#hEzX$mp6%-AUqh@+DbsBoW$*&$ns7FmByWyePAh0VJxG&x;Pzp zWrTfEdQb}LP6N!s+Z-H;oIcKJuDpsx2{9+8+DfKcqBpb!B?XN<mHh1f8KqbMS<A0Z zv72-sJ%;Cr^yDI_>pm@Roi6AV<s9ru|9!P63OnqJ+cKx4{L~p1#}Z@g*{+*TPTU@E zow+Xh0RAkq#v>-IaCxJ5wLL{p;;-Rx6I`Y>DvTcv56)Oe#1-&6{PQ0F{52egXYl`V z*u~Eti@N6C<3cPdAZb1ves_5Ex5KbE(sV`{d`CN&EdBw%z1rDvcRl!>)JRaN5>LJu z2?(9<3l(&DCXEF!#e<$gDZ0KGkokr*xy(3btlnisI&bLRj`?DWn8^dAs=Eu!{vbDY z0GB(%&8}y(M4Ue#i8B5Y>4Q!JE{S#ITN5Gfxdjgf24zMLvI74^#u8z4-kX!hA`d`Y zvS?cL!lt(j2->DeIjJeiTHO*dsa-nZQyg-O@*0h)(=WNYb~yo^uk`JL>s4U@9BT|; z=y0mJC-0{|IPzSuhZ06xsg{9TXP@p)A=kQwO8IOt>&dXkZHTF7VMQ#11JtofPaE(H zZ^%lookV`>Y6H(Tk3w9BFnNRLmfmaQ(N{P4@=LR>%}#ev3L1!af)_zI*jsA$41(=I zQCEN7)8O+@r@`~*sO;V?^Ku|nSa(XMcu5w<p)ixmpC*wa`50&B4ky?4P2X;gjufhW zwE6POUHY#h&nD5fYf3-<yJ=S5+S;Z6meICLAcB&iY3nPJ4&n2+yU*Y6K0k#8fZklw zg;lDH1JBOMGXK#2*_-v*N+qofzkzqA38Yf}3h`p9b(~x@m`^YNf`90O3DkRZap%&Y zYY)&2%=T9Du|#Ui+%D*5fRcm26m;2%Z~Q$PUu&#1e$3bIv<~#DsM2=zeBt8T+G^UB z^umo=DDi3llhivv(#<7KSqZ0`mQT}~YVDwZ_idhK&b5g?diU@;h>~@tM4znjc8~JZ zlsS1?Nt1Gqb28k|QI_qv<LEk=MTKpWemc&Ilpx2NueX_)QuRe7gzxaLMRn;O+B`Yf zdz<|A-O<<f5%u$5qVW&EUA!2aqkA%;+Y*wK{k;z-r|3xZRT=-VeSSXt<>LIs`HNri z4?p<rq66^$;Pm~QGidU3|IDub!}y0^E?%7f_UrjC)bgKHDvJCXa3}X(g5Nr$LY+#* z$CtWSR3@RG)BWhdix(t;f2ro}t0DY(jekD<E!I+odAlexJ=ksIhc9je2;%w)LLzux z??ShLPa5<T(4%KBUOWqCm>W$V(Mk&t9Y%nr@76ZH--VmCu+-`J`*57)4IP!I`1%Z$ z>-rW9?eG`6gem+jd^&paxSc&*VicX{;#6=xxk=PRz*e!Oc4H2`(-Y;O?Pu1+j2N#R zWzkm-gu$mnt6f#E6GN?**0QHCC825gw&Dga2UnRIJz<05egi><Q26(i+(S4jgO)G; zjjw&DJ3;WLDXZud|BEhhkwn$SL*d&_dq%`<G?!-=-G+6V)#)^!q=oRZ6G%xCz|F|B zByjGs4TquIc()eE&O)r(@>lIp39ZB$Jqsru78K%wE^J)_QGAOFPVS(tJYKK#`MFhG zG6%ULJe~;WoSh<1YTS0E4)6J|;pon-iD5Uq35<Zi)yIAKVP?20H#Ts6ZA7dPolzw@ zj@t#Se?)K3&W=yt@)3IUy?mWEnf?qdeULuMP1TUQb4e2JJ($OwV3mar$`f4B2;80u zx)B##-eonWh-`vMSFPEm#^B+!nxVT8S3U&I{tF9GguyyRei>WOHKI(?WRh`)c~azM zTuZJZ_GJn?iUXjc<noN-d8XZ!$evn8N|=2Bt19^-^eK6bWm9^(DNV^QVf6T>SMr`7 z3-#y??OCgG;u3oft}s<4{4^Cs3gJH>#W+Es7S9y1@`Ga~GpEBK55#x01*%2s%x#$q zpUtE&X%_&mpb-aIU<Yk0RLC>X;o~nLfJIhhgK(<KyQP3dq2bfhca(17q4nJ*wHbU1 z6XSLK;JlGKq#S`BXFI$~>g*%!OE*Qlw|{a5O2q&BaB#B!jZ>rl1|Kh+!=uCf<rIRF z_jNi?c<3VhM-0nt##c9rp9G(N_s_ItXpPjjrvU&AWhSB#VtagYbau3N^e%y6xqJQT z6R{CPF){|m6Joe>6O5oSR|qn8Y!Z3!bmb}EZKm<r(J_n{7xyum)?!>y<W_^3bFeL~ zW<M9o@mmfV6JronlF3afj~jPmZ?cBlslJQc3`~~K2Z0F5;YWGb<La5=bV2}-iAkGi zk|NH_hF-%|2_G7ow{K39)5C)$V#g%FI0WSp5Kzk#T_~r7;L<56JK;`C{{bkQtevY! zUmZLy0bc|me$0h6Qn=xU6xhl&wh~F<jm7!`&GeH`Z>y%2YwJ{GMp*(t1S#4}_j>cv zplFPz&ZpIV8Hv^D^z8>=qi_Cp;zzryXx}ibf5@P5bO527M7FY`-#O`SUdVwP8q2wT z{u@6w+}J#uWiH7EPmEM6o<gP)q5m|)b7@6SFeQatl>3io;zzdt@k1F(Fi8oY8}CvX zr$MJHbjd(KRjDzE_c3^^7NO~!qr;6xH68}sVXYF}RUdL<=av%2WA65J(k=)Zb<l}% zPZ<JdOs7QToCb-S5!X1x!J7v78dJD5sPA89Hz^qDR2qZ-4S;|fXzUBz0~9g#Sa?Ww zf=X6$^d0Sg1DY5sE-x;VmtYz2pxz5~0=!V2XMFFouqYHI%iu%Vq*s}(+)`l^9;v&8 zJ1C!xsY?PKNz$oMRH81WiKip2L+5Ii$xT&Z$`pc%I<0mDRSZeIlslBC%vPtD9{*gu zsEA-WZ7LWQddr)$!kH-+?vC3UKR9V9krQ=a%$eFqF^eCsB-Zz11pUN0w{8|PFjISB z!TI6j9SKY;jg>~VP_u7XFh5chMK<M2F<|Y>F#T3j^`-M*r;aV6^-SdgEU$&SK^3f< zk(NFo=hLFhbJ@qf6{A-()@1c2{|(OQkSU)Pzea<u4Q7}f<eHcd1|+=#L^&FO*fEH* zhZHxu8_Y)eJ}tKn%B{1TY)b%qpHHW}3;ysZLOuu*h8ATdMW&El`|tn$DJAHqq(^vm zVFm?YDA8ggGBpC=+q3uYWONGWj1osc9v*)VF!Gj<0)gP@go(@<21N!#0S81Uh%ZXi z%*muGOihXqMSeOZMrh)qu;jC9l)+S|Mr=^<01pn;w+$VmFK=L=Dboho@>oln?pr9! zE*E(*B^J(57Lqi^6ea?e!~}<#TFhJGbge;ckv#%h$%WSR2x#qED=t!I`5a_smea<_ zf=4Kc#CHMt2~wTvDGc0XQLo_Xuv@BjJ6;y9^}oM=w{>#7Cvr%!IZQqVRAMQlDj2y@ zR=ck+$dRHI8U@koVelWKZynJLm&9^y1ZUR>gEo*~MQCl$`i}lLWNO+Rp^@APW?2gC zj@(ACcK8-;{mvJB?z*A~j(fIV92EjtIM<{f(=nm`MeJ2T02-p`;}Iw-Ka<5rrklp< z+8-m#Kbbho2=qsZ!~{930Wo|VJ<N)FK0&gmXZ@E73RcCd9w>ERh7U%1<c;p&5&OdM zO}+NC7F%uTptWEOT>o?rQ#VFh>o>z7ga02s+xaiKgyXSREJYJ0GMAENb4h*-EhV~9 zG#L3^S>9Bv>fEf>0bCRi8#<M3y&La%4#IFDio{F0?4g<KcXnDD1<VaP|Lfk%o=67= zt5^DMQilGc&pMG`0#s5TlNryK3#Qe~wg$tQOlP#d2ID=6`7{PpUXhh7sBwr$@Upgx zMS31YmphMxj|S_ox-t4fWD?_8vTu#uk$)D`s}Wv@@w>t+nBVZ-i|#$it=RkV(+EFn zO)D<wyZZH%RO(|?H}%=nJ?$6Ti#qo%T>hB@-?${5j#JFVRO-65$v5cWy<0rvvxc`J zCe=)Y>CTJvkz=xLhTKG_fV!JY7snEb{*X8@$uQa(Z}g;{LX3Ehpo=EO^|{>jh%zbb zub^9=1OU_o?GuuM?b$4BCk67LAx_qq6{4EIiki;yElp?|8K@TdrJ*Ua3_{W9N>~WR zvj}Va<48k;YgldFJN@1a2#J-8N8P!nGHX*zK3_05Y3@W0Su{<;c0-x~GT=WB-d6YM z5Fu}g%!xbA(t=fFQH-u`!PK-T`+G+x-|)_7tWt?XGpzGpm3*SYVS60iRc9B-0sRsN zU)=O&4y7EWGQ;DL?B)%%_&RwW;nVJVIxxsfz+PEPbiW&P`P&L}oQjxx4FVr^kX3*V z<ewEOdatn3G@weVkb|9k!RTo%$h)|DsMKXRKK&kjk4|zZ)LCgMQcZ@_tjK4W`z_oh zCjtgD3}s&^NneY%y4Nz<aF=SA#u?A3-E}H%NLQ@jkqim$nFbCXC<hhr)SKf2SjgfB zVPc|P-2uYk;Ss>BcoN!q84iL?$xu9He$&IuGd#oZCcp9q_Co0gZOXimm$KPHw!u8; zGwtYuBJv66M;GMom*F1qjV>JqO#U06_Q0=|{2R;iPIgJ(r1)ZFpXlK+z)@?|y_K{d z#$a7VR5stA51xy7B$ujd!R`qcSH(LaAp49P>*0lUW{fIz`RbcH@gvfpA=TL%C-~mD zt~+0!O-kA#v<nJ#K)sCh?DR{<#W`ptF1C_kI^Eq?&JBwiWa}sq#}chNLc{>aIVHrv z{J4GRhP*d%V^8TOZv3Lnfxp$1IdbJ3KzY@t#(2gbi--62nA0&AIp+Lh-7)9V)xC5n zRrgl>=sJT{2i^=Da_|7CcetKBR0L3r60HV3mnjfV@?bfZwv0hK_fh+37%O@pC0IeA zG~QSF^+IGKwSz~+m}_Nd>r8(j&vH{*#e~n*wXE{fwK;bA*e*EmRv(9XIpO6HzQ`B- z2aG1v1gAvT?<^xCEbztw9SPpr9CSJqSNG>qr++vfH%P?E{WQ{;Y$Bin?sUC~fsSP_ zi%vw9>!#EAr5XlNLANGTiV0t+Ru{&P%5*h|#u9YScT49KUUp$yeojL;LVkG@MgzVM zcbQ~S+b%W{swcVsty^R44`mZvf=dTue0#zB^Gs&=xsL7Y^hFHPGAmC$o^X56dp5tK zf#<Rpu{jw{EK*Noo0veqxWfYKJx0Md7Vy|()$Pf>(tyK%bGls<%rq?>k#I-opvD)W znKX-zf!g|rsK}{K#vNs-J#iHFy3vSCxgAkrMz=#X4%{vd#-JNZeu&Ky-U;Cy-D(%0 zD>n*>5rXVVLO1E(edHVV=AHzfrN~W5uVq3?p9haaOk}Km+4bpe`H>hFP#`T3wvth| z*`rUR(5BEBid^U&(59=zg61q=UM=RR?;0u_D8=G0owF;_)5>mX(pYqh6Y6%&KYR8} zUOKGgxk_>k)pxhIk@9Udsft+NWOlCNNH3enhK?VZ>9_CR1uMlbnWRFeB~^polZH7| zHrYrnx40vFWhnvf)kIglgpv-R#ih7bb;-2`^ooxvFUnG6!WY#t4iuWC^L8PV2jw*; z44DhpOz%YpbgRxK7%!YTcc>2kIx8d6Oq7N0iErj>b#Qp3z~~80l@>k>q)H|Nq<S-; zr+6(6+S&5zLDlC_bWfThNPsLSLt2I^q#YI#q7<+}lwWmjDoV;iI!|}@8Pz;IcSPq$ zD$)R(7CO+AC|&EiK?+r%Bb`pkj`4ajTs6v0A|nEc5qVwA9`CYyaERrc=wP28PVWw0 zk}Jn(jrCEc<>k)x_<TD`^1*aite&C+IQ1LbR&k+eb*_p<bEA>aHsJ9YvFoD5L|wDA zl=*@uv#Hlg!9+nFU&hBIH>fZ)N!v-<%Y)<n75-?()2ZZHwc1y>;@%)%;C-BD^bJ!- zz-ltm>`u-uK8i3Q(UcsGA%D?H)xMIK&UTMp{|@+oJHv-B2K?6!{CRwz=0=0BSUwxI ztS2%^Xf+=j#i9_8lcHJ_V#JTeaovGTFWb88N`THw*Cw8e!%Zc{y5&Ff{j2)@Z6GlY z<x3P#>`)X}pozOqgCY%%_m6|mc0QE?W;4*QkmFjEGIW~VZO^lLgMYSmpvLy5YJ9py zX<;@r1nVpYwgQ!ID~T^&^1a3)Z-l&*bmRX6P)h>@6aWAK2mqM{yHNIMC@fAH003WG z000sI003lZb98KJVlQ@Oa&u{KZZ2?n-8^e|+qRP5^(zp&IV59=kz}W7v~kkhtlOJC zt?LuJ-McI6>QW>mv!O_qq+}~~^V@f30FVGl$#x&NJ?o}6iN|0t7|aU;?z7&L9`lnR zj29!eD(1Z}u%xr!*=KK)bd!aPtAg2Y9X9L_hCTT8oLyXTcD5<5l9-(*^WxgeIQuGD z#er9ZN$f(;bI#c}@7|uAo}akIO~Jf4U~j)Wy?FobZ{J^h_x>CUp<QQhZ?E%inMQoc z<AQp#WX?P`kN8bEi#S{JEQeA+j^+LpG-GL&tiyl`R%x1K1)C=sJ3Be+9Ub+%otzh| zv`CUD@A=6x1(*m1$ItoFi;K|LV7i1rCtMPoC|N9^P`zfn)0t<<lDPs9ljV7lL91!8 zNqH_CtcoyF)v1@|e46o}R$)fd>U5@4FN&s9cFe}sX_76yDE!ES9|Rg!muZFHdId}~ zv$`Et{aD}dh39Xy4x*sF@wuF*)?5{}clbV*lq_*N$+9HFjtgE)1>LPlr-KCI8B9Y` z%7yB0sLY;DV{gf)Q>WAE_>q_AYztKT2QON2dUQsF1}wqFRhTpQ=f!MQbyExF;v!+o z6yTQdB~Uw={mA`7!V37DO{ZZT7SpMn^Jv~>xvat;EODn|0bv?B{_o;zYCE+?u#5%P ztG`rAYis9KTR?=vnumE9=Y<#h+@|(j222?7M!Sf|qJhI+v3{pSS;B4Ln|Wc**=bUg zdxQsqiWa<kP#3BS7RIn|^3{x}V>uP@DXgFWVOs45IZ#pnD`<m-bA~)kwGMl9EZ*v^ zDzq-3S|a0nahw#4h5%XcIHL{sIJ4MeW{jqzHRV5*i&P&)tU&{D(X1j5?DZ@*7wlNT zlJEL(G2c3z1cY-Czyxk`I1NTr{QfAv+=}sH`)C@*wnUk56YUsC#O6fIncPW@`+_wv zzAx0p{h$g>a#a-R=;_lS@pCsNz2hd?;%Ua`JmawGo`T}>mPx>)eIX41)RmWCO{W@a zqCjwW11qewwM8)|mGLy&+H>!5Zd;FG!|f?vhrwwNPN%Mtid{qU7{H-uD{Q@!=<_9L zzZ4|Nri2jY(=-DzkT__-*)BiMTI7e49z1ugN{~yXVG3F)n#D{(Jf0>oS4*}=36J8O zhq#m=mVD5E9_nFOYA9kz6`|;t9F{Ynj#HeOS0ow2`?;Kh_0k%#$Xm_=kFC4R@3M5n z*05{*N{d;qTHCxb+Ppk&Z3Gg-N4y#!?`m#BKi=NlXmy`v`)szs#r0NE(Pf$$bNq_E zI(92?pB{$eqxR;H%E5n8OIRp{EEk9+akODYQrcWzRPZbYwALCAkpY)0E(krA0GniF zteL7#H;>xXo?!o$rpDIUs^&qH(bh4U6sCh*+NR1Xo21+rdCL88z5xnIC`>6<)%9M+ zL}r){^~q=mqa@Gn!VPvZ?yfKxN#&Z?(4mcW%rbf~t3L3J!UZecD7l7B?TE!f6WWJq z_rQ+faURmT3UwalYEALSkHWk_Lw2GgpMi-C1`r?|7r8l!{n9QDX8(b|T(Hom&=hPX z$7qQ-Bq^*UilQA5)e5^j4)SXdF}CGCv7BZj*)U0oxB%3~UD~C6u%&rB*)L&$ON*d@ zAOpGugsim{MB~Q-lSrEoE?ts3t^LvMT15eyf!9LTXXr&G58B*axMJ`jPMTd`h5pqR zIM-nOOMe6m(2A3R#0mSrdCI~<R7e%m24)S-LBY(!8|0qxs5hK+*+sVETL%5F74QcL z3NnO1j)32^j)f>8&Q(aXc5m)ldmT5)#G{<IuOHY8S46!nv%Utd1}DSMxL2T8xCMx^ z=84j%u&S+a4<a=ukvm=Xl?PZideeS#y)*@8wrynp3YN3YCn4v;rmmVmT%w+q(ohbs zak=uL@aHY94chxx%Ac;hEdht;a^5A+x}CEB2oUj>s>6ul0jf7FJpo|e!b37jRU!#m z>8=ra7Zr$eAx44RBO=-8U(&z(S4&@gF5z7FzN)p>ob=jWSD3c0lp<W&Lr5iIm~=II zlnWjj*1S2?Tn$p$Hs~|k>dj<rb1L(llTgqBnpYH=T=sbbAj+(Hv+FWPm1Uz?BH37( zhufu^g`{{)vdgY0vc=+cn!9$pF$&nUBVMg%lkhDBk#>W*(_|rutSvS)zw!KHD#vQt z;yIXM%EZ+$L}y-i8PMz+$VgLJI_^*4pRRn+1g!hhYKU6L!K6M5(en58?MwfQjE6_c zfyTE7y8XFu`}2RJ+fP=FLK$Cb^#9`m0{?#36sG5}gWu?@KF<DlPqlM)a&~mopZ;+2 z{`}o{r_=W*Xp?e^qlU1anf1^0Yx^=dc;wI@`_hHq&J)MBz1!KXf1CLZmOIYtJ8i7Y zg5GwTfGU(-@IBz`2SGTn$6oK_o8JFk1`|X_dvjg`kk7~;COV`%o#NzRHEbo7o3{TF zN*YvfrHU3!q>x+I-SusOQ?mYRR@6xDHVJZ(C94#XS-Rp;ViT{HmE8a`)LuKJ*w!eR zL`x7hZk|SA0oJr7r8gLt;B=y#LjV}F6!Hz<#=XG=H&?$xUyeexBdG4^)0Ct1Csli% zCSWH32r4m+I#q|rmR$u_ApTMDiNd4N=R!y#2UNw+M=vIlb=Ottpg$T6MR}C?U{+T( zhZBV?fd}1);=W5lUt@PMwxp_wv8aOIfM}QS#^=GLTx@~iR>%VXcF>{@|5U*7MT1Tg z-3DAxp%u2Mg5M=%eAWO9N;RBkMZk81rJ<^MiO6nPj2uUOHEyeWj9^286S@L|lK%h< z#k0^?dL~D+{uRR$B0pJVUJ5QymwD?X3~F$s)ed$g$n7Ny!1MNtXwzl0RRJUTAeLc6 z(XJ4VlpHp1z{#*DI1u2C)%>K8LK=k|=0UiC`LviNG;N^NK&~9T*36@Jheq}5cj?jW zLL^p>gITSXMr?PfBP6c46@f3S!S+>@ZpLAW&>i4C8BOe>WiSt8047Ul_j~h#XZ6qp zu_)F8_tclO3E7;9*i)7V)=_WZR6Ky>R-L_mB^nyUQV>2`U8fpWK_Gn5an~_WQK~q( z26`nQm{*X)1IBkjp-Fv0u0cJhXl`3;D#qS7u!cG5T@BjEJ!uhvp|i9q(hPaT0$Zy0 zsx+m#nn0JVBNZ>n$u7xUGK{-~Q5T_i1tWmon#Se%;#7ozbS+i}dK*WR_78>|32xUL z&`}uVt3ndeE&Mu3f@*F9cc`sD#=JmlVUQWtWDhFc{+`~}?dxyez^FU)hUWXMR`1u| z-J|mT;=BL+ZUih0Yfo-yvXZv*-#i^#jg|J<GK|CJYRQW01j#ysX&Ts7E!C!o_?ky- ziGhzRZ;c{F)#M<zU<FL{6)j8CYU}Bratmtfr$-L=>y@zRIXdrPOGGI7KJqN#6jDR> zuJ6BnjB2iMtApd|3wdkhEan^|0yR1O5BGmi#lRo8Up{DSx6l5bTmvn@D+JSr0edMQ znd~0K1_1*y#fbC)_+97<>Va?j6F5=sk^9W;J7pvy2<K!@7a|6&wSiVuSYWr!Rjx0t zQ@-+jK&9-u&2YjWVcSZ|O$EJvg)t>owBf~_y+3(>^3C+(&DZDT02cO`B%w9KUq1fI z=r`<WYvTO6V<0iC7jNuBdZRQceQb(!)q)x1HkO7j5ppV4)V}GmjU0huUPWf#h<R@0 z>!#E>H^?lT20CRBQA)=fFraZ%3h8c|=vQt%#%|Cm-58?qW*n163M6k4Y3dY9{@r?v zRTF`K(3ut;+*p#Nm8Waz$5mR3sIY2>U8-hb)V$Qen&4jPRSTo)Sg+zgS&j25Rp({1 z5CluMvFe9Pszs~-|Dt)0UhpIAxhZKQGd_7oTt`^rP-d!o^0TJO%CQbC72mIbk>*w! zN(NMVS~#U?Lx7nA-u)I349w12>jtNkamw7SHGMbN!3HRf5n-t-#5|A(z`h1D)H;^} zxC*f%gxCUt30`z}5J!Y()Yuv&?jjH#uvCz0^asFYSK;$3X?FmUYT$s3F*@vwxaJM< z*uoqdH>n-*AWmv&RfgLP_S^+dCytuZt7ENYJ*w9ljjX8=eRa&r%Ep|dhy}6c{+NWZ zJx1vo3Y`<uS((vo(x4|YfhoPqSpsOMLEFV&gtjmLAJVpr(Eb^;HTRcE-zFFQg)n`! z6I1@vpUbb(r*7z}(tfu~0jSTTg3;7QmFeHkTWwIb9TC)Y_k(Dq!n?35)X5l50^fBM z>Vw69Cht6GMIJqPMRx4?hp$TG;O0*jxyN^kT;u3p7uNTa)%#mkY5%UFevNRKhjeBw zg|X`x)?k|jBABfj|5lB$Q(J(;diKqmw<mqQ1CS=m*6;naZBE<fOm|P)wr$(CIc-nd zw%t8#+qP}rKJk6$?DySwpPLaCRrN%yU#^u|nNLOKs()=}rfX;Om@3$4aB$QNT=3c4 zr0)Algm$fXGceUicDK^x0gkC2BHDpy>OR<<$sdfi2#Uu}+L8m<r@Rg_^=V2Gd^pFv zAv9{j(7KPMoQah5!0w=&iJi<=FHjC=o+Y#AgA)RSfVMHqb<w8FfYevz%{w~BvZnlE z0$CFfu|*TPR=SN?bZo%xd2Op>;<G~5bwW+8Ip!JEk<bVSit3cU)*iz)tWfGkQ_qDQ zE*B)KI1lZG89E@f#hWpgMs5>CQhGtr&UqR5#pj!@1QCGMi=tA&?km~&VIGbU!L-o> z?G+XV>P*_N_NX+TJgbZbtn5GDRdhOD2f3U_c?R=jE>NAvdf*S*=}pvkFXFid@pQDM zov+-Xtk85k66Cja+|;n^W%2?j<5!JgAQ0=BZagRcQ0%}sqBZfpaxD+9)9O;RR~o|j zcQdoSf2_toUT#QFZe(?@%*l90I&7RUG3(Hx<IE+trYjifDe{@Tc*G9BDVRsIS)8yV zh;EREZBi+rY?h8S+auD-tCKnDH)0kJ0~J>5Q}!OA2#<tQx8mpL$rhLu=V>Pjip}o? z!rW2QVVVO6aB2K$omv`K`GLLaVpL-%OB}B5?w=j}NrRUD_1A|P>d#J#0$oUrLd0ND zwv}>~Tn-)Flw_!bgf;=gIRD-j$ILjOu3`2~&#Fg<V}-767xko+NM~Fqs6M8;+^(8R zU9o1_PA9sGMI(xlri|K1PJ#0J#83lEK(`Br1wJvGKco5{&Oz)Fl1!n(#7caZ)VOqI z!c^s{<g9MJ8WAK4K_nik(9aUgT9)4#3s+h_X(uX&X|+I5h7+>{9+N6p{#^E&o2`o= zvYqo0ov4`<D7j&LeU9k1X=-XsHFt@z7U=|1#Usvm<4;g^P>dlL44*86_F76dVGSiX zQBzOA{+|zs+Kwo(l)N(#yL^_Z%CWlNKlH+<3LR&Ij@&3&%beBCJ%CXF*WuJPkc;j1 z9Y&rqvX|@WR&j~pn!ly`zR88g4xhwK!E0SK3eF>?z#7z2y!rYM_w*R}cja>wr2rzY zop>#J7;(z*Nmf#-qf|$UeOF3I#8~YPeu`*m<0{T53555!-?$>o>q>u%AvNn00*@!q zPtsxm+0_PpyskZ=Ib3dSZ>AENOzj%kb3<c*dO?--X=L*_tgV7d8T6n39z+LP+{}NI zyuFSVduw@%t{wdT5kbd+<$aB_ZGaV^I*o^o2Om7<?R?b9>PZtlqV7LaJR!RiFpWr` zU?Rv4Z*ou(4(jgT7$cd#P&f!5or%x*8sWFfL)D|R3tVAev&1`48qa>4J)skRx0U`5 z%k&!55vG>Hj4pbO=7i{(QFm}{FXpUj6T5;uL0y1*<!>^|ApBylpoWp^yi>mmP!eJl zC2&Jh?dU1&<NsRP%PQ(`tf%2RCQUvLN*#hw81S2`Pnh6~fXvUML^Pr4K)?~qYd7FK z9#Cs8-pjPo_(L)%z*`%W<NM2qoh08SuT!sV6o0k!9{Di56O{56ap-6jJ{JO5>V9Qf zoV^DbC!skq4v!VWanETm)HR;~R$aW7A}baA&AZv6!jUo}B5}WxsqQ@dWq%|mSR$r3 z_V#)qY>6+W$4?!)j;>Pg2N=-Vsdqn+?q?kON&tG+Igq61(Qd#VPaT>sO2rmmLn)#! zkm#9mXw2GL+I_G`Xn*G6pMWuaAe@5c7{CZa0P0N2JrBr@4d#uYN^_vr0E~`vDC+@G zF$1tKZ2KGZAXHo~n2X2R_#4!LRTRBPGO9eQZJ#9_M6!Sb3xR?=!=SeFlc#Sin5)Y+ z?uKDNCkG;2W*1^?2+#tL&-C|d9Qa$V{@v5F2A1YkoOjwQJx+ZA%sB^ywmSxFN4*3L z>(6*evJ$u*@89j{3XXK^i}vajx{F?cEqFuqknPxsr-v&GE9N&Ft_;61ZN)|API{?) zQ4_)_W<)W}Xv;9mHC4@~cHJ<q@UkWu#o$!F*+4lh<55HlG<}YpcP+(F$wA0PDRApg zX8m}bMGWMq_8mF;e(1$^ijT;6z8FmhV)ELa`snyDhtWnPJ<`kP?BA65;ETC|M@PbS z|ETG#?VS(wrNd^lbf!=nzUqH+b@Z(+t8J2dGl*87YC-h-#?Jnhk`*x_xkjIQQBe^( zb$d|r??8=j+AF48osA{Ev~Qh`KMVmGJ=OICdfc&~At#iHP!@tNu?z~dTXM~?tA|r4 zP*W2V@4JjS_q-Ch<%p|1-6Z*3t?Qt{@v@IV2iRo4ViLZo+^_FyKbStQ$@^HzzjF+D zF7bBr>eCb@*t@{;|52Beq6oJaB~0*dlq;UCFqLsw{sGY)A+Bs3D<fGxMT|Fe?WvQ0 zQ!++NlbC@S8cb}nWgO7C*4RB#3;PQDqTY*fv8`uw<;jYp3|Avr-*@A_E7`EI(mWiq zY<1bVs4H|fPjzlOk&+3J5Ax^U>nxvo#G0RCGZldNomSk-Jy5%yBaBGdpCfB?K=&ut zvMF!*%)nXYhb#yl{OL$AFdxMa>=XL{FD%Z}fCP>e%Kbk0E-*<Ophyo(TQNlpD?($7 z4^%hYKf=J9V9j%kLl;emUZJuhu!4+5IXqJucW+bzHOl}BFvJDIE_BD(x!YCB8#7j2 z=goJ|rZos?z?cTqW1|Tq2|noQm6Dag^Ym;40>zPiWAesXNkqJ!v2|HNvX|^mr!g@z z>#{5p$GDr3%=)7I<PA#^)~`n|_7G(JMM^G2hD6WI_(cN<!WZH?rJjZ=7`CY@g+iRn z4mY1^Nbeo5xZxgJ$!qjIf>1sfDapr-*=cz+%1XI|Fug$BA7!4Yaz?}R3?uGO!tzx` z;oYT+8e7UCkM#2#?J@YI8*4ZB7--U=rVj)6=rn`$Kytrh)_>=!Pu>-UMoJ@ptD^46 zRnO!ES2@YgE{iiuo~IKxP*y#Sv}H(QC?dp-21oI%)>b`l3bd=9dk=N%dB8wu(Uv64 zCP(McHOteE$sHSVVLwM(K-msH<0Pz%Zy+&yr6Lf5C9bo>#nY%xmW10#&wvaav6JH( zxyo(dC+2u)L{yY!l$u$|_-N~X*q4D>Q%<Q6OaeuPYN3Ly_|6+CV=|At;zF(yF{^IC z@iua%(UM}^h+KJmvD#a0+UQL9ROn2Ya^$9<<3eLKbtA0ty5LcV+`HiMUiZrbztOIY zZ~t|F35%MD!aRQ%JV%EDai!m^Xu<xMSUt*G%s7)ekWyx#<d2PJ?<LkqdFtoYo9}p; z2szNn`%P@(`AP?^sTQ+C4r;%r`hTvhS<v?)tSv9Bo<z}^(!LvfCn^+4Jw-koe7>+z zhwN1wWphi{sK~clA+uyiPPM2a{}t>=A%>lo>ioM+&Fw;Al4(6d$1hE#`0@6@1t8{^ zmE{QoU3^|kl}eUe`C-D5!Mpk>yZ-1wKT?)|wU$OucHSH*z9`$|@>X7t8JJl)0hcf* ze@lNTr}a~b9PA{fp>mB8oDJ>f$EE-N@7rdEW%t!Xhmk<4>5?|;pwhPlyaA4tiOVaK ztoNT@dA+3<iMxyBeT-ybU7Db?$G7nzcS_OERH|D@{BTp20zg4{CvL5tL^8sZ$vlHm zZq1rPccd{Zq`d>l+#_MoRFTxTe5RW>FIlWG;?#*!b=HMI$0v9{yE-$e9PhGEdt5Yu zwB31j4zar126!mX-;)C5-F%E3SyPKm2bB0j1dix7p`m=qWHX1N+lq-1S|7=5#D)2p z<qaJhq4NOOC9ab2_N>Q5qD8CnkFckis=@wE8V6gB4RYd6im#vtRkE)Q6*n4{>qq!b zm{W@cc(}Xm*h?ESUJD1xpLhpsUKO_!Rr-JGTW`G4y!!-j_O8yFo$XX#?NK*SnZk{1 z)YaX;mr0~Jn$u))u<sv{wOud6IncspRdJs^Xn+nlGbc=Vy$gWwpDqfX9H;MFk~kw| zjO&1ZiigNt-}2MmPVsc!deQL&6+92Q^7;+>;dwv%j|<>|xmlQac`zNBfR*jr3*Z;% zKJ2c=;<Hg8CE+ye?%JSzo-b$)m}oigz5nLbh(bh@Dmt|J^u9SCcH19T*@m`l8uwC% zF>*}%xzLDbn#jZP9k6GYLfW2kaFpmW%WU;j`68W7as_EhqenTt6j%r|Zmm_m&KzA) zq6-g3j;b`6^u|E6{Gn7Lyc<^UQW}l1IwTS&B3nhIGR$EB&960nvgxDIkH53WuB?+? zNWVLTaD}8h`xb|(H=cj%^S@VLyj3#iQpo@S&`baT@qZ{HyO<go{Yw)0oa<}trMYJF zox1t-AV!?zVEQbN`~HDFtnPG`)6>$VsbbfN0;;wpNfa-xHn;x$(ghCy8ACwI(bmy% zm}K%ZiQ;SR1s41kxcW5mBD!6SMQUc0%SLTncylK$V?9Ib(k-bfV(+H(#{UrHayW0W z3%`eF)0KzJto=cHS0|1$P`@fJOjLsLzI3dtGSH>Hva)uLW88S2iZ1Z+yGG$`v-lRS zCt?tWfQOk9$*xgiPtz!WXpks%pc7T#<H^zUcG_%j^^2;T9s7M|m)F-bxVy9U<<)ov zPpExoW1+^YT+_z#q@YkDdbK?@IiNStR-#-t`7ol)WDbs-5IfEAs;p8QRb%;58{f3z zxS*-c_*!-4;da<-9cyu#9m7g>wb0sM^g@AMf^~+K7TW#$^PJzxs;)%5-U`O#@7*%B zw1FGu7bS_~OpI<Aqsyr8bEjfPss9LhX`Hers_v0NXCZ%#n1(>_Q?!1)t0;gdByb7l zh&aXh#)`xSA3?)0j6T(@(gc*pBtaLlu^IP9+KuC0hkOKHkIi3)UskMs`1Cy$q=pnW z+vr!lvTW2$ZTO)BV?T>o-{}K-Zg@>Q)vLNUzIzqIB)m3GI<6pnv^H)ho2wV=o%hT3 z)s@oR3!gv#4g~|y&I?P(HN*uLQ5oN28RRkhU1rvYE0Mk~|I3qtpC>T>?r<XJh3mPA zf0txl`w&340na@-H~h#ba2@9lV*jkDXJ67NVdMZ4B{(vzm_yKVTDfZ9?OuG!#}E%} zhl^Ru*tN*}MKwjOz6nGsXyHibP7)%Px6q|Oh4?NQ!@I6Y2!kKLO|2q9Yug4WBCzhp ziFm#?RiC1y9`aZW^KK~>Fy=ze;o+%g1sjo=Nh;4$?}{6e4&4qH{kX676-Vse(Y>9c zr~T8-5&cwL*5OA~3W%UD>cMUEZ@wyiOe2DBs*+0J&*Uev4ZIC{3kXgdeDBmT6dw%= zC_SZcu0b1=C#%E3-uR=tbqVjU2ln~f`O(u-nxLJ0Nla<Ri9EbJ1#0{AfQNSJ{Bq?t zkNu9B#|ybhN&T!#u9hXX4{B60|4Oe*KRE}8>cgyG)~aC6@Y0!|fUZ^l@RwXjOxQpC z-N|8)Z?Oo(c+UfAvYkMplTq%+b}#7S3`o@!;Ra6@aE~P9Zan^k<X8-%GzF`(LcvT} zAO^*S`UgS``0?0C{ktSFyjR0DZ~&($r(kd(I!7eqH2AgX#p#G%lgrLWxD+gF%)=JZ zB0nB5$421C+3973>1!Pw{C4;I2RELv{ze9%eixgluQ6bUnSu9yK7~)P%X1FW!NiLJ ztlTws`+k*7BL+hCCBM_1TbBQ@=Gj)4w`b~T4~YiN7XcWW%)avSA%B{^#-HtXIpm3^ z!-I7ee!3@nzj(g`>TKazf;yUCa%Fx(!5CfK?9k!zUF>;{;eox7fZPT3iPPBu?y@DM zx#rf?8uw`eiOe&Fi|+Kfeb~Et?m5nRM0kVeygEBSCS;%^gwv6U-spV3kJ&8TpT&pI z!fk)<oIh&5+Dv|Q>0<qS_PXZoXhr}j2=DYYIz37(8<+%|hw9|~d>)N}(D~SXKMwd3 z`FtjTyhQLe;br|eT}H6k<h`%ydIg&#>$={RS*W7U>ho3(E*KI^=e|p=Dy1P30$EIQ zWy~DVZag#^NN~iMs!QdAM<S3lF!>%mI^zMyjz?3#$MPX0S?b5w#J5ALgbG%WGWkm^ zKu16oL(VIp0a`ue;NwH))kRi*&jOA<QyOY+suv6w<4+DmD<nlWf!62-_=Hj<jIY|F z+0Sou4s%c-Al8w*gy;kp*sPf63yHGTjWLj4UsH2r)`Br?bm6+QZYN<TSn>x1-(vYJ zx?VIep{H-Y9NwNrV4bVQN#_Z%XicD9)a`pt+zB{7$OSR90!5Ypb6KJ1YEDouPyYt} zov6NFomlv`gKwdDsJ7;3j^JJ0XP+ny`*q(^dLV=_Vhqy!@rcqHiX!VCEjmdI2T$UJ z6@3UCNtEx!Rm!wbj(OzWA_qPI6^1#>oFGod$7Og=aN61I8z>hD5CkHVH;B2Cqb~PH zLN|ghM4^U^hLCa}3sN_1zic0bCn{#Sb+wNKM`jU6o50s{jC6NQG+LCE7K>3Yd<#Sw zNTSg3ekOhQk_Pjw-!=N46{j9oU9cT{Af+_@9jO2V2OrNvCd=~&Bs1g-@2#AfhcEAy z>f^Wb<|8Z-xIJSxG@j=Zi>?D1iTv1i;uu$^0A0hlQO8fxrOc~uzT|bxK0jPl?t!z2 z0g1kHfHjn&wJ=Abb|WZu9?X#*xHlHuBVm4W#2s);Oo(qEOy12SNw;QwL%dKQy2*s> z8!<gV5=Hk4od=JH`8C>0JpRahSnAMTk7-?K@zgJj(u?Dp-J-dv4bjx7rb6-aOx2EL z^Lq4@Vx~)L!VDw;pH@wp1@G5Kchh%~Z37WM(Vs-54KEwS=;#!Emg~ftee-)%vWXhA z#?zUUreJ_<Ay+lS>Ln7C6o-#&rLi-zZ}8r&3=}1qT9<-|hl>6<47ZlZlU(y&s^tc? zLF-!<RCX{wOMK)kE|5yk^62JZE4N2>=lnL3>YZn?@rP;d6%87DjHnI$_6xbVS+#@X zRymZJzFVHN4Zz}~-%5RoZQ&O%$#C(*_qAP?uU|hwr*U0s^NsT3JI7&KzpXe#grY`E zykQUNunW)P5FH*Nf_G6JI@@oV+@{5;Yr<QeMaWiJ;U3k}#QVluQC0iyV%g~}W>b9@ z;D`j{4Fp=9^cJ%E6k;&9C=W0n&fWya<D3nWXe8lbp%CCJR3l|{Pkk_%nf!>Nd=xnf zsUCS4;(PSZDTYVYO{>R?_#G^1(gxZ71DZh#n{>-a%WyHCXaw8sDENwqp3YA?O;Bgt zg6y=xi<B1oRhy09WkU2l#F=Vhp4Z_;76{*bhgB>5BE*zQa0Qm@!W;r5ESkV;gzR<e zj)lxqiiMVgHfQxDt28A+H4rvI8n*PQcAopBp7TjurqG6EQkM|NQwfy2sUH)KAAG7{ zD?($X0tM(cUyLoxx!0krMn&5M0}NZ=!GkJJK)IH?MkJnD()!08P7DrG_klU#%dPNU zWY7w9K3zN26hxpAo2Q?-0$-<PH8X>?fi0~R)Nvz%xxh008_-0&%#XC}a%c;m_H>-1 z@>(A#?r}@G=2pKy&Z!Pr374^sCTaXNMhXOkaB%JF2fi0>amsw(34{r>)z&rZ9jVF= z@Cz<3bjfP}Omg@`Oz;L&Z7?gNH<{a?f?H-=x1|6CE=^1kby3cp%k<APQOq&N`ZWg= zQ}WOj{kRhwRamf;4YOqG5DTTT>IslxB26wHN?u@F{Fj+AC)cc0*Hv=x<;S{rR(0;@ z#Eon9e}X^#(zDlW5{HyuY3GSxPCd3pWK&I+iV~=(E>ly6@%eQqK^W;%fH<?}3&tn8 zLyB4=puNw+p4%ll5(ix8zz_$9)iUGYJBk`jRy~+aI*~?)HmGR4dmm2;{D~%iru=q1 z+ipJ6u*yirXi(H=SyS}uJU4vx*9|zCf;fLXFpUH}OF8FKm5$SVOF=?Yx>H)d2Lv%+ z5!uvgaXa!ZYe#}+U_+#I&bX4taKW&Ukz_@^o<7t~BMtvA`y~OQ)g9wpSLHDNhG;$p zO^1i<1uzWOkZ6y_g!TKV9Q@p7KKxOvguqeK18m>U&}z{%>8ZyAfg+*l^d|!yw>dG= z?ciRwMt&0|4fG*kB$e+JgdKMpG*sBU^>0WO3;`r9fpw7rz^3x@Z`}gKyy`AS46OKE z8^+(}=Dik&2uGK-+<BSHYsGJ4l<-)E+Xit`QRC3~9UH+7KE0-^R}Sio!{%({z`Nh3 zJp$1=JzwBYSe3Q?w#}kXZ1}#_FU3-m_v86`ZgI7A>%#6p+^?6(tn*J>=Cx%A3vCLm z3Nsu7spyI~fns;oEg(3CW8HeGdWhlH1gr#{+-;`9E5`}H1ko+b*j7VUNcqARd>^vJ z28ng&-2d()Yc~^SOY@-Bi9<{pK;Uux_MMt{jxNDxU^+9Y;uom|2jW(8ZaJ_B<Aexw za)0|T6Cy01cg6f>Q7}z?MD!H8c#yP<S3pRuH82kyx!4SgG&6T^QoFWZu!JJ-JAeQ9 zlSB#kP#>n?5GKDGq<}APHm^6XFNId$qW|~i8)nK9Qdug-1LLUh_Fn|x=2Fys={U0I zWDw(IO8Fe!h{UCAoq4b<SWM{r8IuN${4j(_J$e!7%g{otpevaQn)G`-%T&If5Y{tE zagEJ=2!4hJ@;Xyk{h}O1^6X(A+Au1LY0a%UGTS0rxgNkv3PVv;1H6McZDxA2Q?W7L z`3i*75saq@@Z02I!!&}-r8QrvP<6=7^e8$BxqP*~3xF%ic$vZj5YlU@n4bb_EC#yK z%{7F4m_vMWYbKQP%xdrPy@xh3+L*H;Q+39nnb<8@LcP@cduN3MrC2o`YQHa($#496 zr1yS=bN8g%1UI!U6-&Hp^pwY%`EGAUMe)(PKA&uzT?Hvnt|bXwZKpHE2=DG2ZG9>l zCITEldu^}iu}+GmUj*A(ZB}ivNNPZy+t!`(R#QYVbdtVj8}}domWb@N8bMo<8$se# z{L*0;GlmLvTn4zSB$HAH-bXK4O6f@Eq~(e?i^{_e=Hw3HeSGsO3})}BgdFX7nWlGA z2Z?3*rW4VC+>|c=4RaY|2_npG%YYq7k#{@vS^LS30W*bB8FoQD^wlXx*thK$BBJ!t zH*gAUs(_UK>Nr96mq9f%j0yhl(5_c!#k(%wp!(VyHc~ty<&|iD>dl3Uup^oWlWMUJ zALY}cDq^$BQzS7kB5nZsX=$)>12rm6yIt~v_jg!!A%wwP^%jcXyW>P$l?a4c4}n-1 zy7Hc--5d2fdsT||I}=kclib^9jyIh<lEwID+SDg>2|L86)-_I;U}BJnQ~6~lg-2q5 zf`ftmWJG~qbz+%yb_VT%U*wfoP;ME_z|F;`aQ)$Cr{f*XJht*BGQy-1th+0`4tUX= zQ`^>;g_4w-4bk?ilSE}b&?c+ePD)y5AX4g)HE0y=q>@^eA4dA5CTIAfQ6@BhB<3d7 zkz7>H*I`iwV-fB1jgNU?UFzVpnGf>`Ef)r7fU-x~N8y2{{>BQA&K*V^H?deRdcHg6 z$2C%GWYVOtYAD9<pMRhz1xrq2IM__Hod4}Lp8E5y_9T3b*e-lDLr#lQ2{u<7Xg@)Z zZ+^xy&HAEE67KGu9}UO-twG9PtNPj0uCjJ5EdqNAwAK;cQgz^Gt}xhYu##MTJdtx) z{KzRNQ*QW3!SV=O1qyGvagk^;%$hX;L$|i`)hZJ+`Eh;kZPbPT+}@V@*uzx~pWfiv zrFn!ouovR-Z9cAuO7v<hUUET9no+*D)^0dKfBr}~Gv-dVrXM9&{xDl_1@A``m}OqV zYCq;r_Oo_NHMf!{Rk!``B@_)``I)ME9hs&Nb}hP0>wL%yb6_|8LiPoR76i5sK^bKr z+_VM)606G7xr;Q)GmTo4wD>TyuDZxQzZMLT+#!shXv8>b2mYi16$Pk$3rCz5f<sBR zOSvH$PfAv~e=|b9z%HnNH^ffN*bS<eo;Sy)uz;lSygRr%+nO)yMR~J->FpUN>_~$D zVA*a<uK&H8KDwf8{JZVISO6|dx%zI+-!O#dvE5_#Y9oP(kz*TCi`>xXw+)2zfbVCA zs2lz)9vmH{^0!aMM~7u4X<rBtk^Q5T$UrVNzS0G!Z5RvQG(JaMFOmIvde!ouWa<6M zOAEydoEnsH%)_r^jwWM8+VANRS?Whql%oJE8i*$5T~g$x+MVlI2@B1h6Mrl^8Q-a= z_Y_op0{Zd_UGJGs(BI5bHi31A(Bo3|(L?LXe`NCuVqcf-H52%z9`NB>Ipw4*<^0qZ zm+PC|z5Vy2ACOLvUekG%G86^jqv#feXRAs^<}-mclZaKJ!W$eh0KUTd&1OMeF#{Z_ zC;4N2E5qAJn9=bDa^gg1n&;`eIBK(1VKCf9n7h`TCJt>I-(uiVYz@|u#6j<r)lO6( z@q^P_^h_0bwG2qJ9Td%LX`p#6I+HewzP*sAV4Gr*B+5OK>t?v6)>P&yuYscdOd*(B zZOF6AYZZ+lBD8L)C~2}lZ7wZsU-NjnLWZUrY_{0f>zvpPVQRo5tL_WE*^cMo>~Ko7 z=~`|T?@XV}`Gb!GS-Qr00B}(938fwtV7vELOYA&0i4QPsOS4VtVQTUDbPw_?nb5S7 zW>ldgYuRks)`0FHW{^RQdfWzi1A_Y41{vCPXDPlBm}9U2|J4D-J17MrP?A`MYzpU{ zI)$!o>}Rgz5lE>A9yH99+LvfA$7t`K!KZ^(eqXQ>6-iSRVJ7QdMs@ts*D7$MADbf1 z&;(C1mXGL`{v~mpQf`!wm#L?Ll45Kisc(W7IFP|<B?`|Q?-`8a)6>KcrUT0g4#yWN zRNRY#)={Sqm9p*fhxg?Vo;ZH8qF#1Z@Fu@CAKpo&L=(^ubt4{It`N^6d%5<uly32I z_Ev?UdE~9DR%|JMrZr<E^2BGh)+O0SZDnxL$+c`AFYrjV4)QBw?iEU~7{hHIxTpq} zu#VTgA;7VCSzM&zmu@2-A-yZz<30~mmm345%P%ApbGmh1a2SLKyz`!=*R8eg_nxKV z7~l?zjgKqBc;aI$<{Knp0~y;0*L~BcUI->69?xnpODl2o(_+<JQlTF#37ZyLeuda? zW49?C=5I4o6sYEr_9x7u2pctW(KCI_m60c2G_nD2PUv$!)GApMy~_y`v*N)&5;!Ha zRv}9YNJe5d2i)1g6`R_H)C(#iHi)WbBvtGkV^NZn;bo#S_zy>dS6Sr3ve)POKbW6W z{gmz_ypk(=M-Zf>A%Kp&rYc$LtFg|Qz7o_dG5NVkwQV(fkXCBFPTBivrEVn3Dq)*6 zmzwA0bPUp{o#ywD17bODX_T7NWNIPB_ZIs<T!qn6T-tC)*pJq=VDanYvWvednse6* z96p03H?&DeW=?W978#u5TVLShgq@TdNNx+`YXAA!nE%!X+wGt2fF)m3iowFr*6^rM z$l*&RG#aG?j}2fL23R(bTJ?NSa3o?ctS4d{cMt<^u|FT}I(JLnCq%(C-#HnE^K0!w z&euU(_T-KtUrb1&ntW!^`$aB`G>^9S1brZgR?}0=4DbI)q_IObuc-Nl-HDjj%`0&| z^!Wt_TNOM`_9b|NzL=;M8Af5oY)amIDlkqU^hA)0;#!u}MGT|aOnbX-B-|oX>_jom z){d)x67G?Gice7+%%X}HA%8TnEy6L*k7<nwZ+zE?-4BU$UEyNVkfTISrc|uT&`p3( zr<O=rnZc!8y!=<fa%~D^i}gq+YdGUdtt$29YU)yC{+pmU<(Os+>QgLmKQ5kx848eR z>HdaA5#Cl-zM>`mQ0V{^5103$kzx}G58J47QMnWE^f#IDNI1AYHy?|0)TwOum<z|l zoq!oT9SIh=30hD}%o=td`yRr8Qb==qk%Ux#YJ802fg);z$T$OZF|n5PKH#PmrO@cf za6PHSPHWDKp4j+NRf)~yg2avL%?0eSLG^W1yfkOTE#i){-AJHDQ`JMfh96PEnHebi zM;+yG20~nCB4rlMBr%iN44!-0$AqU?Kdky?sUooSZ%s3KD~bd<uw43CuWDvJP@lM* zf8{uA<I!bdr$A+Gd`n7*)kJ&f=nix4$bAeEI+oMh#FGE<wkpMEa{60-JusYtvZQ;q z%U0`W_th`n&)InEwSD~+rZ-g&l5UKL8Y4av$PS%qe|_Segn$%f)1PN)a1E>jh*7=f z-+nJF1RuH6Q{N#9uvOB2pDSOa9HO|%XDv4gnb8W0n;VnO2~)j<AE?VY=^tQRj17oH zt2YN{hoo>jqK-utCe5lLAAXo|krix_GL^Unm#Z2UsE>8UN<~Ve2%KEV)!<^t<9+^s zrL=Zd1$oienX&va@MKB7d`U7tzZ+mK7XGx30SOn55gu6{=%Gr+^iW$&NpyQ(2%0)k z5quB;^yJ0NG1V73N2n4Wz@1kFAF|T9O4^jl_ZtNX@v@4<1=-YlNfIW#71O1qk7D*a z`3s1Uuq2W*?!=Cvwsqlf<xlMyzZ^`;ZY0p#YpMwe`{)=<Kw5rA?~Lc(2wlge-{)9R zRLV;e9ti<_hG}y&`iWLjv6{K4_nqVHGGx-+W%Bb=cE!GZfjD-#M;5ixM`AK?kYvb; z-y~{=s_~$j%@S)Y?!#_<#)bY)NNB=}M${*`SAC2Y@Gd*>yjg8I17?tj9h8^8cuPN) zh=`WdI8_CE@W)A^ee(AaAdorXX~&Cd*lE4<@0Hib2ZLHNg&L4(81@L;l`aEzSa;le z7M3)9w_b3El9YnDoIiF&Sa4vy^{i3G&f<XVUs2U_i*bjc=n=P#idm3cx`7)AzI4*R zXO=IgMQwk=PR7K|W(p3^B}iH`%M#D=@p@uK>2V)?-N>7<Cb!)&VRv^P^1$OeS%&Oh zbOaQrJxr{i&U#)|_u?HAwm{|LY$%gvlCJmgK3Qr$(hL*cSetlbi<A(ghCsA+yd4<8 zO7;e<d6sLMAr>03U>rTSYm%iYdw5o|U7#GVt$09MVXsF_kndes6*-h}XS`ybg<g~l zOcijhugTT*{&ZSBT*M$uy)jA-8M{wdJO9cuZG*byA46uywE1Jt79gXMl6M0nzZO{M zM(tw$0~!GUky=YiXbGq5?u}BqOWS6#E}dm&4u5%<6Fk&rE-W7K;asFmduO*v@RQFp zHzyZ#i<a+r?UTclpegM@BluFCfhG9%cQoU&omGwl0b}K0&B06P6dq6^-r6Ef&bqa{ zykr7TsT9Kz7Q*~!W}}Z1-RtFSlMQEtmh~W>)WL~Ka>Wp7P$_aOt#~X`8R_Nb=du(P z;>f$MtodUAL4s8vF9DYC>o7g8wJ>75Mw5ZD7h--^&jyl0z&bx<Q?%@JEWB)NZjdv& zE{aQaidTkhLk<S~d+SB-0hkKj<|<|wqUC$P@@b57#2+Hi&k-ZY9_!3q+!5}8waORc zejgMV%W>PMAx=WgT`~IQU5dkl`;GjD>7571fkOvVDbc%Wk7D*Fu5u3Ku0)ZFw?cM^ z=1Fe*17|Qd5sfxHtExv<x6R0?wKI{T9b4(Da;jU6s+~LescUi16eM&<1B!$963j|} z_RCz9CI=m3f2KzYHBzolbv|R&WEI_RDPm5w7;xqow!Dd<4tHIaz4i1ZdwwedH)5B? z6Q9UpX~%q$Z24!DksLC_<GPRjignHmt@$E?#0Q4Pq|XWLA7dh=K)KExBXp_KREuWm zR66{Hf~+_b_3dX%PV&BIQ}0iu8P%$aL5L$Eh9rn0_3Y)-q<rLD%+Zdm=_b3b6F&!! zlAHNwwP+{cwk<ab6a4+`3`h3H+n>lJ3e&k@VAzeVz1N5r{Uzm=yl#%JXGI#(WRfqL z0{y*Aq!=*e%U6oHe;q;iRHu?Npj5wdqonPfXk)dil4l2S-(AL;q;Rt+Su{L+t{wk! zf);4H-M*qX39-4FI#O`(7^RJJnj0L%JPcm@PC9LNv9<!yIuGTuAO)F(wEMszmbqOQ znifB%6+((N0}mq>z*QQ$6{Uf$J}y*w{HOZKojiC6+qyn+1Isd+3|L84t2;8;7_6xb z&Lw-KnED*OzAAL7{6UhfaN#1iy=Nqf$pQP_qiS4xbl0>d7OoUyOS3Otys*wmBdTM8 zT@KVM#8nUb5qgsA@L}7aK09r#v7)ll8|EHDGPfTA;1mnddIo+Q^0?uhn@x&)TXeK^ zsg}LujzQJqB~JFIN+VlVVbS+RYkj%%I>G6+1U@5vU-2+_gKVQ;L>oHCd5n>I)^^#6 z1#ip@cVyX)Q%_#lGeYZo<|AH>)+MZju{)2<pCU5{tCm&pM+zE+o2=ei2#4{Gdx@Q0 z)34h{zhuomm%d0B&43+Pe>ISs0SkH{51q@wGl6KDa;=7vb?kW$&B7}nVmOmY?KwyV zV)H!QNS#wEn8DU^__R&;j7I68{9j7Y<f{3WLrFqmA<*{KKnVDM)X#H3e%BPD?!;BN zps24MM?HhQNtd56uKA)eb%jP);4!o+^3K0mdNM8V&;LBHLp*!>ri(J^mR7_G*8h`^ zeg-Y0Y3pi;<8H43%hs%qHF-4(g-%IJ_R6m)K!nb+*!`5HpfGo7#eK@jEAB1zGEGio ze5-&L7^O2kM2tew329yhcqYm1j=hh%)LdxHEo|<4#o>YtTN)E@UYEvIxSje$l4mZ2 zqIUE?-Z=Q-_m=Y0niYfYAQnHNUroS8Y+H1B^ffVgRU+{}VLrb^m_C=c?z7;uKmFmf z+cuV0F>LNL^>#i3*9|_a9y!;Ivj!GCm@b-m4AMHjtv4=cJs4h{ueUFIJYMfsJ+yz< z81gzOa1nyI541mI4aJk}&z^-I7;QvwU0e&5b`6wGp3%)UMItvt4btm;=)974L*XtO zCOdC_tQ>4&n~`?p6wVSBBi6@J3N*u92#Ps57QL}n00fU92(Xj4_r9(s8c@Y!?&qM& zemWyb=hm=iE)7k&=((<P{m7tP)3{80e)Ia?HI0`#{%XK-7TL1fnZmJ;W1Xnz_1MAC zv<z{ZcHw7t;X_!EYGY*N;TS8$n6FVy4}{_4rg;|pgL4B35&c{Dk|P|iamsS@ay&9v zTv${1;#aOtHded`5HrK+6uetK5Wefcp^;<^jh&nhTeV2zOM~jFh~f~jnK0+8k!KiP zL*PvMP#-y1<fvt5xhhpHhrdLcx$^W8t`8-&+<_W<fdy$KiY+g2*)IE$Ez5~*#dArN z0hK->1*rh|^>0+gKdpBZZBcvYh%VX->=mlVWY6|L<_aU7cmZ9Z?7ctsdIfoNT1N^U zd4;WfMQt!xpzrwtn{1~=>ig=`n5b=W6cKGi^9p;E1~5+*_~qF{0wyrGU5$95mekb9 zcAwQNsDdxF5PsH=uzj=_rA$H%q)#B=qc+{tU=GMJI5t<SrV<ZZ<2OtP#EXd#b0^s) zW?!OH8wuHm)s(k_gD=hzl0LBE!wEOO@fVvY-s_i$vhFz)4_(i)9tcIjg6IiT+m#r* znIbDC9<wh9XfqO^iOaX^B~C`NHq!nwPgKHVTOLu|pH1LP;!J3qRaS=PK1VS?N^E2( z*I@m)eay@INxwP6W>NbMV@TV!mbjGnwNI^W^JRdfyjrHy*a)75$(CDJ2shK0)auV| zsKtr~DYl`?Sj~CoJ~ova4R6CUNg>Y)Ei1Z)jSk^RvLmYvo)CAx2K(1*>5)Xg#sUTt zM2-nyxYt*zS}{^-a^h$S+3TeI*=5=xHg>sgI|nQCLE7J3@1B5f+3{`ssz<mI&(BDk zpcWP}$o#{Nuxvfe>Si~s*PICli+bO!Il?j>#Bqrc97qe!Np3-#uxE}1WwN-jEY)AV z`X?T*46VpDNWyt=;fMO?xDar_A~}Rfo1H&d6B8#Tx2BR-NE`TchsgGpAD|<10-Gm& zR+KFL#dj>6vv*G~(HxsQ`7+?vvM~ximFVXxfDfCT&x*s(_CgA9dn-LBAr8%1HJMgD z98t$*!P{;pKOHayAa;c3y&P08T~Pz{BrS%Teu{BVRu2@-HanxS<mP8RF-d3e?orWU zcs*7&Xq<a3xC>Z?NLb~%(T#?whW4v&coZgSl>M5aI3-Rdvhj)cUohP#O$Cla2ObMQ zbhXbdL0PdHX>x=}r_rs?jch&G$u4b?j^rMf<r4}BkxHV>tf1N}8M>*AQRlJ&iV3k3 zPU3fzU>Bvq&K~*$`I}yEh6!quan+?G;28Bs`~HoEjyr5eFR^I+vid`tL7R`jrGxY0 z{+<UA*{C9BQek0^OKJ<2z@&e@``WS1Nvf0?c5{B69k{HR3E-M6-7Bk7yK~lCf8t>I z@Eeyt@UIJSXk7RX1?+=6!^}jY6gC{X_3ulmiupr}#P4l;o7e#KMQLf$0VYB6Zg<2p zf!{_2(q4RA<D)#LZi)^<Ml=m&PPhhDr23O2yXNNtF&d<}Cgd9at+%rJFuYzVHTm-c z<{Fd0sXpPa;gkz`*rpIX1$JM`L=*5U4o-N2f<K)k3gx7$Q7UJ-Gc+>DR+B~a_+~^R z{B!Phx5XS^F7`+Bx~d85Lw$y2Kg%}DilIwoB1j5$6Z|arxWOts<*Sp0H+FO02HTg^ z@L9{EaFfv|*_emIDnPw#bKt%G@UT=WVkt%Z4MQhpAZtX?*`CFoJ37n|aS!fRIEe=a z%e;ScP}blEC6&rUY-GY_tAIqtxCP)c*<GDMu2*{M$iXFvFHj=Oj`(I%#4NmKkH5*% zL4u4HHO{Nh>qRrD^F&h<4EQ^5O7H3?raa2g4b{<KBGJBWy`S_DKyS!I`fQJ1W*a~* zjj)-n(TzZt<KSUox&3+Tv>Pw3fJSuL+ILCBk$5%f3*!i~RbRX*-aX}ee0^`ynI%<w z?rS(#0-gy>?;k(!&Y0So9JJ|*>hx|UUE6#F0`~<RH4@Zp85=f1gnenk(DMEvuau7u z<fs+W7-i}S!}+<Yp|vf?%lWZ+-loY(!bQ;tU=^#z)mOCESN@DWKG7HUpD~+DV5N^8 zeB@lIp|2|*`nKAFd0RjGr+b?&n=WdKT(Ilhy{fKO{$dLXveQznn8~LiHYb619;wGd zFE}|$Zw^?HUkdVtFA9g)0Hq{0p(Nkb_U?t1otq8Ru7V4m6!M~{yK{hVXN*esH<CU= zOHT=J3{gfoW%cPiVq_N6&F~bbYkQ}NNQ0Hu?-u5fP`U`Ar-;S2WidIZ@OBXwve0~y zIv_EW>|iwr%DjP{rsJ-xs`t&@L-e&MZU?U!a&ftmHVYSL=dUypFHc+NyR&&cN9U_| z%1eue24qF$gYiX<@;^&0S>IuEssa-Pr;EJIT*7EXkLeG%QVrA2ZawIjwtB*kf8)@X ze0?KVE$UlGg8Y^M^HJxl+{WS3Q9a(?!#LGL0Tq-{%rOkp{(b<{w43#<#apg%*EM=) z3;0~3v5wB3VUf%yf~*7(Fe(V@SIQbBAQh}lmU!AH00RjCV8H_bh`)aQcggqr*O8%_ zgQKOHJ}m>?4>|_Af1S~qSsUBX^C>Bc%E&9wIl4Oj9e65vKj#k&0PutU9jN+M&3^+* ziU|lwD+v7)a6i1HXaooV*!=<${M)^+eZC*|R~Y{dC?%xGC&;JB_jmUwTMTj%zDR8l z0Kiws|0(%?#OVK>CNCr)BQN-OR(H{?s?Ha|`fJ1e59wc?-D3TBmWrs5kmTP{a^G_3 zp}!E2UmNNFLPcW#ca)=zt&XLU^H;{<KXk<K_-L2bSGx&)bq31+LazLUq}S0gvo>?o z(fP_*{JT%YmnLt$UxvtEkpCT?>DTH1-|+N0`g#Tywl?;T|1VTkIK9!t7iJU$0Ql0Z z_)p3AGydv?{~Kjx=3wv-9_{FJO^M(D0Q80cz*h|aDfxaD1pkC_Fm-Y?`&T;V-$S!O z2UI+K`NQ_r=J@}?{Hy0qIsXyl=3roBZER*jXJBmdci4y9X<o@!7zd_*zohVZ{@<|w z+c80Yd;xtm0AS7x2=Eo?e@ea|i1t6R9QEvt%`A=nAw=VqnPYlt0H8ew0Qees|0(%? zSxtYD3~a1y^&J1f+=eKO=7}BvFdF>()$_jdm${*yqn^H=!#~xZRYW)T0}TKWm;e7V zWdH3zz8@J1(0{tz%-Yb%^&hHNlB1$^_yGU}j{d#+5Q@L7Eo}_+9Bu3!{sG`x$ZTTy zm6^NB_ICia=3f9SJ!>;#BZq%#fX1d!V-WDKIqa+PkpJ!c*FN8G$nt*z>@B_oSN_3) z1lA>R$giPHmGO56UhV&fy^*8dzZ&r$08#6K$i*-K06Y}{@UQv$-zDFVDdjJKy^({B zlf8k_Ke^y%C-AEIWopd-_YmOo{~|aT*qhlp{*%2tSU-iy*CpJ43;-bfyZWzvzTfZW zzwH0Z5c|76&A;vQ{pg<lGX6`g=I^8G?-|yA*_R^$|L6MocfPf(1lU(!{cCdh23Y($ La$x<M^#K0|KSYI- diff --git a/venv/share/python-wheels/distro-1.5.0-py2.py3-none-any.whl b/venv/share/python-wheels/distro-1.5.0-py2.py3-none-any.whl deleted file mode 100644 index 1dfd7ab92c26525274da9c4606544ae5265b5138..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19272 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 Z+zvgBpnLcIdIZ=$ZMLiE-b=sk{sQuGw7viU diff --git a/venv/share/python-wheels/html5lib-1.0.1-py2.py3-none-any.whl b/venv/share/python-wheels/html5lib-1.0.1-py2.py3-none-any.whl deleted file mode 100644 index a37d282b156463491f5f44cf073944e212a6c7b1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 115285 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%0A8AySY5A)uULcQ!$ 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 LB-H^rK%oBzItQ!z diff --git a/venv/share/python-wheels/idna-2.9-py2.py3-none-any.whl b/venv/share/python-wheels/idna-2.9-py2.py3-none-any.whl deleted file mode 100644 index 61a0f37c99fb834cefb81acad7d31f768de2870d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 62768 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 diff --git a/venv/share/python-wheels/ipaddr-2.2.0-py2.py3-none-any.whl b/venv/share/python-wheels/ipaddr-2.2.0-py2.py3-none-any.whl deleted file mode 100644 index 2c9dfd25b4e1252b1d6203e34ceee0baba494067..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19552 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 diff --git a/venv/share/python-wheels/lockfile-0.12.2-py2.py3-none-any.whl b/venv/share/python-wheels/lockfile-0.12.2-py2.py3-none-any.whl deleted file mode 100644 index 66fb5fe9de50c4145a1a097f87a142400ae85858..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17238 zcmajG1CXRa*0x=3+qOCFnYL|f+O}=mwrz9TwrzXb?r-*cWB=WqFW&vDDx;z*Dy}E% zi9C5u-g&2-BnT)f004jlq=9wFk<9u8U?2eiZ1?~G*`IGMZ44}o%`A=R80o(;(KFE- znmIVqnOPg#Fz_oYiODJ`(mT338l`c@kcit4f4rj_ZDBF5grJ8!40zWQSlVZFai`k_ z8Y<UQci@kXSCW>Po)TtJ@W)c|O$nUS9zb%4Are+)Zh;w2d4rxNoM5OMPG=s(BFPVy zPq@DC6O8g|Us>j;=6F?;`*>eVu+BDJoynbAD!6yeN2OO%ub)~qFBCnR+cSB+U9KKj zHMiz)NujUao?Y3O-&1=&ykO|~6p^>Jv1r@i6p#m5H_S_{Tl0<~?CN^<<9QTCEIDI# zvTCzAY=JLRX`l9<N1Z}UHjS|bsGzI|W!-r>6_7W<D>vUeR|wX$XjwR>bg^=^s$*@N zAk;<XF|7xDo-y6xW*I&%rT#Fas7rWaE3S#0qQ`Dw<_Z1e=~xgve&>Ij{#sM6HWPhV zYMV*bQ&Ov<dZ1+R$Wpa7amsSsL>n?0FDK|+$EVveEUCV07XxQDglYNht~pMET|r(o zNpCq)p~AL#YCW?mwZ0WT*I_(@FZJ`Gx}j4ro1h*CFY>Oal*>~=gr*KjIOKxuaVsi) zl0IrGX4(0Ik*$DhC$xB>sS^3)B_uX0&Dg5rew?V|W@u+af5AFk4cjezvN%Viw1Ed5 zY}GzLz%{pF;F!OKhIp=S%Iu({MvL80ayiCr_F>AIJYx`1Yp&h0ds3X~F-3(WIq2$x zC_Y~^MLNA|D2P4-dpj)SX}^f5gY~qmYmhEEc6W)sn%X|O1asAf)-q=^3Tk7p<YEp@ zqyBeB$4g6z;-30xGwa3Td0DcT+j`XLxxT!x><0I0`esM8X#|O<%}AtN9Lj*i649E> z)oc|!=cY!HhnpzDO336<5PcOz;d(Uacc-M&g|MxAw)^M4;3%_9HP2xb2G(c|vNlvC z2b(j?pRYvQ`zD>6noM7D68dgufyh4+)-%XQ71{5_TV04!9l6=}eEA0`=seU@v!&u) z@abaOIk&NMuIxB0^`f3SH=fhU7%1_z!<WotF=c)>*nO>=3e+oOHmsgsM6m`D#T~X~ z`zA1OTM%JC-_4?fXqHv}urulfKf>8OR5la^23&7-DN+n@a6Yls%&*N13?}f0qgK&~ zMXxWfcGd0bo{S!#CZgE9;(ww1_#J?OkafF~{hS&QE!gf@vF?PxbJV#yJY{q@WF7VJ zn!A-T#q*UbBXAutv-Iw(DV{OZSZR*N{p<K4zORsOE3IyP>@4?|p<AwGz>;k1RQ$fH zRCA-l(n=@qnLGpQF+oVQO=C0s0y`4|-?7LPl)?i5H}7SMMp`5_x`r)lf|6ZXw|ch7 zG7#v8N1ZXbVxl@;6VDc<?SohYr*|&pC1>)IcCJNR5%4+0YQa24)gps~H}4S>Tvk{0 zvcMPv#?OnnQ5>IpKg=HCN9XDJ)mwW3jwp2~`(o4mKA95U^8AC-4n&OvdNDDFEv}K% zX)u<DFPeyGwygjAD$ZCqCZJT;i4B3~Sl9svA09cdz>^nO8DS~S+Dck6at+63Jlx35 zYWyO2;_Q@v!);?F-moxv!Hm>@C;uEG34yS#kqvMgX}{ZSlm8ISV;k%_XKF8AShS@f zu^KENA<aywkku05#}KZQj~jia6hQnb>;R{3FITO75_4M*+|fHM&${ZiV!POV0&{Jz zS-9vM=35AAp)^p`UeMx<*{pusCgvEOG`tZk-$BkDZyK?n*m|9d*OFp*48ttOjO`@8 z8Q|KzxcM8XB|aF!4atj9*Ng)jpOV7C^BHIC@P?+P>3aveae>8ZolO(5wlfv`v=pNk zt<Vbg>x8r=RS+3izicH{7Oij%r8oOoPU!-^-!Dr?BJQJ!Cg1(2w-;Wc5MOu2nUQ_> z%?OpN5l5<i=COjjJRYT5e`X&&mP{br9}yhg<JCVX6)L8jXTSv^8U+xiVDccu>jAQC zRHUuNGHt?>b4sICTKaZdE0$@hoZ((EbC3vgGeo&uN@ty5T(bGw9r9WNRJJGIAt~w5 z(~Gl!OMfr7F<7R|%fFFR_fB2dgCYxXo+<jNGoI(R!J!e`)5XGt!xsSmxCMU|J858F zRllcMJz89hxO^bMDcaUXxdpst_9NQ%7yKRw{z$5&-5Z#@ajH$c2r|2PyP)IL(ZpP> zsGV(-$7rs@(U<Sg_4%xj(*&cCRLer_aFxIQ?QQm)*A94eK(T+4?>qJNoXJ`#h0&k} z>Rh17p{92~|JmrTpU18ohuyWX1w&v#s(+|f0?d#yRJGg}Z!P`s9`I7iz^RD357*7Y z7t|?YDEVbc+BPOp{y10tMn3CDVdYdL(P5*F6*8@?jzO=QVlDXNUYSiX<u0UchPpMI zn!VXrdEqA+8m)3Q)fv;H-ideyA;1F*LZFGg5O_uP$}B&}=XVkDh-_SAGhKd*K(}4Y z2<kYA9Gy4>BWZD`8qN>Zvf^HIidA|){-`2J0>-T<qKDIUP)8Q|%^tGd1ysEtBh3n` zHXTW9b}1O$fh5rAE4nKTtezkXBx?D<vQhRzHxM9~uVbbS{?x2?YW~NJ))G^}Akl<w zN1B`;_er+iKT}tx&`^Mjjzb2}YOcslP+X%)BB}um<Q~2EtFk`gH(%%12#-ppyNC7d z@m+Kq-HcpE8pqa2@6Ux6=N4227TUu}v|Nyj1Wm(4t?nF@_tteSw+q1ovUC;;4797x zu?S_(SwB@#ejO7C=jrU=Y0i*k_smzD*2agfepq-OtSR$B^kCwI4mHhgR>Wv0VaQ!o zdpKQ}N>^7e@1am7k>;4CQqZ@tNlTg(3UMBLzXrJbA9jB2Ib3Wt23S^0THq|YxYM0F zz*UqHzw}&NWr+6{%3rR9kCXG&sw`JaBx+9(^Ynmd6D1%r5+$pS<GvzTnK|w`$*#CF z_KhHjVfI+koidE67tZLKiK`=)#0uFyPl+#|Bn;IA#TOb5#Y+6dZUmpLQ8e4?72@~d zM|~~z%h`~qBUa^$IG-aI%Cq+WK0;Mf$pNqO06M<-c6{B6o)IXvQ0P5Nk41zskEV^u zaS$u=yOHKgNE>7+xm#2V^qO<fRDhp6ZxO&b(*wHDV5Mw<)T}OyqyNC#%c^9UXT75c z2=xAyp!5qU4Uk)Ai-D!_%@I#hS2^nPiF9w4kjpZLyfOh^U>Wl;P6Z!TH$JW86ydCE z;F=L>BlYQ<9flAmllkqfu{UR1$B(RX?1QmIIKQ$VS(8s1QCY6Z(<6fK4$Lf2`XKTu z$aZ!K$v@pH`n&BCRUm7uOF^4GD)c<G8B7_tD#gLmceLCSUEh{C^ppjf;#%&TtHdgM zS+jg!koEJvS@zs%irh8MR#{V*SR2S}WoqbMwtSm~Vd6NTWHrF>H9GJguda%lGt2k* zA@R11)1}%ny<K;3%v;E6Qh#)O-3iQdE0nDv;^Ud+c(i4F5|7*OcLg)Gqe>?*IgPR? zX}|X>&?U70Np&;ha!Os$m{gMvPCR`+nJ|OGh(5=Pf?OXk8GxmY^(RzOzr=Oo`2+a} z(F$1Ro!kpyMXbTJ33sX{sEt!9Z%ZB4mFL8w-H8$UE@Fad)>@TD<V|e#`zXj_z*i+X zI<<;(FZK-+w~X1f+!5S2gm`6M#91q;;F%1XVSmIW$=4voFQ5<bH7zJIPWEK$1*I== zc$y?^&k+Vm<G~%*q<wHRv+TGwZnE@|#jMS4R@UQ5_wjUU)jZtsvMRhpbD@f*uQH8k zc1H67!X^;e8<M!=C)0`w4?qC=lnLr+N!aaiHTS35Y+wf7uQ<bJY2fy!3j14urM{K= zR}k^WzT2go{<M>FG4@V7Uo{A3jwXPR3+(a@byU6JYWDbD7u)c!&!_DG5fzgN3B;>t zu-}#S@fuQN^#lz@3;33rF+w<tP`%thYVv0i_^=T$ry7@r_#Jjq#VmuI#+*PSaf#dC zwd0JtaS*|>T|<uHotFEL81y8{*U>dubu!vn*=EsOlIzURm9U$+sc5-AOSxkik~AH1 zFb#{l3)h+J9|_>*V6c^T*g9eahL+>FvZe$1{k&yWCN-ZoG&vMYv_zv*OVkpN&TAI5 zeD$cAceoC67k{q^PCl*T@gTWsn4YwrnwK2Bi+ehut8T$DP%EpBpExhrJjgJaGnaQ& zz<n%5rW9?k&p0-Uv89hSw2)4lq8OuIJKnSt9J;N{0*R=*SKQ0$Rx|FCfGUp2r|L3U zj>6Osg>v$%P(T#cPh}OtkrpL%w=g<YQ3W1fa|6jx@Nj+O@^MkZ>;jEtD}JhR?=j-v z!x}Y{Zm8!GFu;yV>TJCkikkB`j1Lqa%aBNwiO>7JJiV>RC)9BgL*8yrf-kiOu4S`p z7Z?KmtJeOgRqxcC%fkI3IS_!lR5%Deqc-xc0uzB3!j0l@tM*M*HsCzqX36MY*0D?} z{oX&nejiR=EPKmxhyYbEF<M(Ju`7A_eppN7+6cK1Bfxa%-u~YIywjB5mD-?fVjkvK z$QSTdq>*V|Syk?3F3tm7Vs0Yw{!i-5j8u3SCby<jG!|=IXOr3SRwvng40j2S5iIE| zr-tMcg^P`fCl5&%J)XRp7yY8Es8K8!0}82oe0#!@NJqT`nTtW!Ry&(JuB^#PM<{}c zyD{G`eVG!6eb*QjgjMYqiK#s_X&~^X(g_bFBSwyF8QcYRZ!=XI`}bVI%b!v|PmICe zV!vSGk>{f9Te%*uJSbQ$HO3XRX<)~C54HL2;q}9q+{WWFT1Q6J2lb`RN7P&C1`g&= zgJNmFk0r_{8K-Bn8QMr;+mms9-M#rJJq1J}I`WM5GbfGQjD9Z0=QlUn_}4E?qNkto zBb<O(p<pK8VZZ*e2<ie)GZ158y;WY3<+V11qEhsWp%_@)eSXjgPPszqSHOmG)HRa` z9Scfw?hfoulsrCQ!~!$^!59g)4(ofSaFSm6{i8Q8S$Thm7evSz82DDSCpVczviZey z-tJ1_8MXli|N97x0ItzqG4YKJ{kFgTyTVj`z0nUT<Axh4?_|EL1+vjyDaVk9R@a-v zDYi3s0;_}o_g3cR=?@9{RUH4#P&<oy9c}ZTrZ1=DsjB|oSJ5%`{PF_NeE^3XxtXO^ zt#(ae=gA{ziO(nh&jAo!rn(oO;0x7+`NQ|C_vIX|HZ$0cpCUx5X;NKDxq*E78rFJ0 z=~-^K7v&%sK$lZEH+>#gmnGokf+2-<WNM66ue-a_I@3zM2W6=c9^_UjjCD*+aoq7A z<l;If?26afMT6uc6ZLIGx#KM-ML#qYc;l7=c8kOMANL>X>gFRF8kTb?QxN@PNu5b3 zio{vm3)}-^uRv5iBhO3mwKB9hjB^>ow}k3{F-cYD^Nvx}q`%Uq@P>+5T?M>51rz%S zDJg|mAIfJbUFv=1cUCl#kO3MY;<coP$GZ#wcbBo}($qr`<P_$R_96Y675J$NX(lNf zmJ)gS2yf5kBr~oW!eck`F%)H%vm@Wn3no3%ZoY{RS|+q_j<``QpE+8|4!~i5P-`v; zZu9!YEb+@FzlN#!WsYOooiMlJMNC4ple282-jbF=c`VS>9@otVS?M{>g!Y`=AF=KR zXFMZO>PDC?doo9&ud*bg$?(LESUQi_;_DJIB!^gLV=}f&T{4$A2UZy7tY|gRo53rL zTV78)5;J2k_!xA##Fw3UT}M?fu8&&AKSvf)dMn!)<pTB2@$+I|l5jS-=kP3O%K0Z( zZiyIUw$Uf7H$A_eAbq#>FrkF&rq1ZI6;WF3s9GKOVPy0Zf>@mX713#jP<AR&#pC(3 ztHbj?%;591JABd4>-l`F^SPJu>+{gY=Vdd*=k2E8RY&eWl$CR-hXsFN06+lr|4&(w z5*HMfQ561%vZAdhYqQ3P`s-Mc%g($g(uv!uBW(cHf+!kSap)Uquq(73YDT^HTNlR3 znzVpG^Y-<1zyMrL0e3Ud)tQH@r|a|U>F?cf_L(ZbUig_*jQO_SNc^kLZ#``8WXj(W zeu3axnp_o>GVYJM+h`*!30jCW_yp~%J@m4C!xa%~16i<Q#g~Td<zM^-{EfKhQqag_ zouB~Pyip(_PZ;|eepew1JOrn-)1|2@76Dr|N46M2nULGwcSyh@U)@b`;))_}NC|HR ze-*ZqyLT{nDGMZWC}ehN0BK)tGYjYT=5b>+p^FO9^K2O9bkzX(7OQ`h^^tGeIGi=} zDeJ)smo>Tc>DV_Vo8Dp`1=_*WnZ$M8X+U@ODe+-*lO=$9mM<t+Q#j$O$f?99L035B zZl$2mthg1PCIi(c?FS-E6oJ-q8;pqHXm?%Wh))c$hINw*gYlTXw$C-NMwdn|80@uX z7xzoEz_ka8HjJQlWy>p~38@=_?QirBf(?$-4+4kiR~q;ttus1BTp_5S_-W!pstL8Q zV|7?fKi-BY@Ju<{WzJYh-4}T8P_8JF&jz_pT7GK8b7B;(DE<TSW^v(9P?&*31wry9 z0g|$0K7V%VUZj@DB`q=<uKJ*nz^%br)E^X6WbsUtsdL1uhEn`>@<D&**AjVphd2hb z@*CFa2V7-&=x1j9T&+6Vj6!Q4<lB@H{gQ!siGB%Vs^M|47^YrytX~p(rKAS>c!Fa~ z7h$rLVYJYu7f03|d-G^#-`+_zM!5Q9kkc%JhA|bXKQP+S$YT7c<Q0e{$>OrlgaR|g z5L51GV3gs$EI~z2I;mbdQW6_r+a!Q}aI-~y0RK6NmrxuoW&R9cBPalX_`k}7(!xso zLi|enNh;Dd`)r6^=c*HS1_So-_~EY$jS<38<TB6{(td;a#Z+VZ(s3H`_4_{C><c0L zVBuDtjFh*N6Z;bxaaYQyL81DuCAa*XoFy6WKQzNNCPz8iXqx0#U7eG3wh!1>%d0GQ zV;tOBh?A$56|G<vDc@JcEaNSkHWe<z(eb?<n$p?yVQQ2kCq3Di^PB3;h2k{POeXDM zo!5uPUcPhpY*RzGox2p5qpwYj>ha!uHp;!_M8SVM*#CL;&ek!H90U2#`R?^{Q$GQo zUXrB~1<9YHK{V4RV*GQ)O4HP+DE}psr@V{F_Pigf*<~^`WYOO`W2l2$>bK`FSM2C% zDO&^v;$wX$Soy_BufX3rovriDULW-DKSx3qpX4>%F|@E=cEQl>LT;SfJkvL|w6#BY z?M+HWubY1^u<l<4ZZ=aI3gF9QzQI%0SZ_s4`*@ZNB3ut1AEV1w&&DIDh#m2}vX<r< zyOoq%b>3(Mv3p-7%m^maX$RhCQ{$ET5r4-{PJqH5prOjACQryjk8`2vs+x$im7~7S zD^P>N<r|kkJs7Kmlj5vrK7|&>0s5Wgw^Y>ACs2C+Yt&7nLsyGFD~XOv!)>4$-WK$_ zOIjuefchw=qlrfRgR{2CkyVGWYJ6!}!mT{fY=k=KaRj@7!`)mk&}}_9l*lsfDo^M1 zL}R;OpyNe!G!@UW(zNSy;-K4;$LTHQA)P02B6yCQ%MA@1Q31m(nOoT$SHOU2(PE!V z4Z6L5mVzf<i|dDyhROh38O-1@|MHGhOAL%as3oTO1>J$r^wJ5QiDDF;LP*#BH-b1! z`ONHbQ0k&6@~kAR?dF5SP^c6tFjy|-bZm@!i~Mc4z9|%D0cn;PNxC4S-Ygu`{n#Rt z2vqMG73@foCEA$K0~~`LVmk14Y2IZ4p5kzGG8#Rn(m3&c<RG^1#i7-~<yE0{pqFEf zW{sP(5QH42w^@rF0&k7WqHVb|QQ(NInJt=<RCToIy{fY1v>Y>MF`Re_TR~9t=N9r> zdykORt&~CKag`^W<Jk~%sP`f`cxiRfCDa1v=)o7|ri%F`I+{Q`-&los?$`U~x;-R! z$sXoYjiv_KsB-pt`H?gu$Wws5JQ0T(r<u}i8Q@#zI<QGQ^!+T#=#~j{zqrp51BWVc z`2q-ME#yhHL|6nkG30`f<ql86l+9WKjPFptz_N-(w$akv3lfFP%o#OyC&NBlG*y1k z;D?ZzFfSr-C(t|Fc0=NJBYP~Sd5|M>y!1Me6j-334!8G@Ue5@7{o-%;xLljj(KUCy ze|UeBm#-&x0m+eUHyMq*R};#DAF2vq125zYLkW^>n&}c}Z=I@9E9Fv8^_66X7T6!# zS$6DaEnQ)AbHJ5puoNK3vJ{1i&Or-G*!F~<2;Wuye55h(2W|YB-7VVu!`pzOjuoe6 zD$2*KMUQ23hv;ki8teTN>_2CtJ!Byk%RecV{?Cj=_+Muu1z|y11tG8b(fE8mMDQIC zUKkEkWnbJQJ{o9=u=-F}B0h9U3G~&0lALZ1tATshiE#{{_cZZw#cbsCcW7XRST;!V z#Sxa{Sd4+~Qjsn$8iV<VJ!+PY5F?f0&how2xSN%pci~m5OV`B=5E8)wpBV}f@i^WP z3|sOv?1dSopAqx$bk6Fm(sy(@8I*Y1!}tt0gd!}G<0k_*`8U8n?@~9s5mD4k+Iz__ zk#M3W`x?QRe*2eo2N0K7-4>}=*uHDAU-j_Gp#K^SAK-P>t{&B<w?^Oe+R#bqi*^Me zKF2PO4rFM`aDq^W^zf;8iyRr<XjxuJY#c=}9OdK~PM(g-(+vZHU#Y(j+SF%nLGs%@ zOeFm*HeHU0L;}4c(`WwqrC50T9T$FiYxWfj&AmRV)QfG$dDM7(h!DOt30mfO$(DS+ zhPbz7)E=cr_E}siJ()~c<5NLPl$p+BZfm{78f~giXFHR&T%m?T|CX^b{hW|+`~_MR zPV$ULN|KS2Dw34{UWENVt-Wqhbra>G5yy1uhhByTy^UHtgvv9^UIb#KZh~f8S@mmQ zdIhX&)w2#>MKqHt?xDC1sSo25jZaIl01YaWJ!hF?4U)LRTH75&-wk!q5*~TzE)qp& z9=Eh|R7nN{9u(G=Y1?py-(#8`dI0Q=dwq%D#^~_J_eh)7-IH=2ke-eKWycJy^!n#F z{k(W6T0mPT+ncZf%kS<G7hR!RT@$WN$76|>8acLKS8!dL2AV2B(yxKtDqWk47tMy; zo(kvMqEztx7fMR$>+Bw?7$BWk%+qhMmN^Co?5#ypQWjH;1b^qvo|1Vroj)Vg`cEVH zuOn4eOjuY7W?D>oau!aKj(Tchx<P?)fqBPXc2bf~f_9XlUO`M^l$Jh>0isNPhH-|O zZI*fN0D5eiVfKM`367FZVsccfUV)N|TKW)LT&hKZvXo_Ra(r5HQF@{xFbtDKsP(U$ zeq$@Z!|<n1^ncoa&*`@M_VnfsHr5p?64SI{4FA(T#d-xfiDt%@Mll)XIeED;+Gqxe zNpWdf88C@N)TH7i;J+@%0>Wkp^XF23DhL3@pZ34+Fgn`U>R1{%8(IFN5*{Cwost=! z5I_8z=b)__;06r<c#{GE|JcX;Cyzl#$IRNyQAdZ~)@=~m!e+hsvBMi|mw4H}y2`m9 z9JUv?vct*`pgFq^@t8*ms*!KN7Jm}2g!}d8F-1fr?@c<D9swnc92astc&Cz6xB3!^ zR-QQd0A_J%{|Hk}I%>)yL9M(&YeZK6kUY845x!nD_aMbqqz3amt2Q*QX_mOf6lmbu zV<>+6)6=2|J-BOqEy;W(W_7yKidqkLy*&B%L;G6ao~$}m%J=~S2iQRxOQlkjuB~rF z(+qRRoPUaCFP!D*kea8W<gbpUa=yq$I3ZpvZ#w$;gWKD9Og)F-)NO#l=}M^vVZ=Vv zrDj)`SUs)5GokGejQ;nmnfg|mfwlS+G^Sc%mi!BZ$|g(8K!-7r9$jI%$PVUJQ{OO- zU4SQVx<9+YIC>w+d90GiMK+E$jifFB<@3UDx^NT^8u6sSTKHFiFj*@<zwF!selt66 zYF<@TBhA{inuqT_PkMry>rgc<c1ZiKrg2h03ywNu^Fq0?Gg<0xlkU_{-xQJyyjC;W zoqdU>Wtt^Q+o0w;0g^79)>bO!aLc7lSj=z8HS1$zteBliO^iU3->`HNpu`q2Yh?`g zo0cR3MEwq-Rg`ceF>xcP5QRJf_)Yx>Ay^#_U~8!JBR(B=NO?d=z+oA1L`OU@2%)kM zq*JPtl(7|Pu#_V!TMT*v87xn?VzD~e8Ndjc%1@)ciMuvQ0u(R$6*z>1@T`KYTKzN| zdUe1>x2WGJ!tg-e_9K?&+6I#kXf>+7Wq!}%dV<a)OpT2?e5r4$LU)@o>{7ud-tH?c zZz6WN7T;S=u~JkkqDDbidP?D6W9$5`L1?eGV!PQ>As%mX!BAwA3HHn5;|gOa19`>D z_}-qTk^e)N@*=iYBZ)5XOo(2*7L9#FBg+|pshyeFrimj>FQ$zr#I^yEva$Xu1|w=_ zXiXrd4U@sXlkg^lD~1jLS9<MgsZAnvgKq|+&S{u7V8RcL+n>Ve8yB?|Sk&;uTX}WG z&ggGt*A9%NMb_z6=_7Kt3vP(uXG6`~K*#xVQ<T7C@O-`|m<#tdiut_OeStiww0$QN zM?Qua5L*+5u3>HDegAm-@FRB6E0VN)-V?|^LY6_kwO%wSj8=jD1&$0d)`*yT!ICpK z{g#G$aG@m`up}-6Iz)Wd#ELoKg?g1gA;{#|_;k=SI6S%oM}BGh7~d(XPqtnuw0|oF z1RkW3&tWn`Mz%yz<%e7t$g&9FNF-5^H}i+uMV04*>F9IB&7z;_IY0=z&x;xBzZvqJ z^?wRj<}2C)=|m{y272mJ#Mj>>!-U-ou;56xmXYryc?8WA1v)TvVI2PGO);W)6BPR7 z<j#ljG7G$`6}=(9iELK9Qy@I=ru3g=Gdxz5Dl6z1_Zb)}D75|d=22w(7~CAx1*x*7 zZTCBuD>{H8j^e9!Pb1M(xJ<(nE$E?-Z^F-9h;8o3&0MG{vyZ>yw&Qt6KiDFc{kQ5| z7EDnMr?EC{`Y$m4f_*<c&!70wbI+L#6-Ipgi*9uMWn_}QD^UBW(AZ|P&x3SB_+3SO zC}&Seq4fra3?8ivs}WS$Jc+C$O&8&stwY8z@fhV)aHdb@SbEpFUYY1F7H2Yb<<Ncz z!i*}f_8NR}f-Ts3VSSI^RD7~XY9NToP@|eC$y$K1b=o4!L{J4jx-=(-*ymQ)l;PmS z;8?LZuEc^dOcT<~FboA}FrC>6+Ic!(NL)TXZ9)5v&3o*WY-L@%Uc}R;90C`%rebP8 z2*4O!3;{D=f-0uVYSIM8fm#JN0M1X)g-5tc_|k1*8E5#K!Gzz4PP^RPbW0F{4--+| z+{_pkQaaHqSR|>m)8a;M@IHEUS;zBRFBAc|l6IuwR9=P~ql)K@hu<vZM~Y}Yu>t`z zXW;zNLV0Bj--NyoFMSnaHZTJd%IqWcnAsv3nRifxIBg3+iuK!-REaM^?cKArQWmBr z>`vz;kW3oSyzbgSOnpv@fHpbw(->9S*lKNuSV^l%xs+BKo!)@JzT;Vq8&Rm$@OWP2 zeNMDk&$@ZqcJI1-Nsw|#o>MsR%44ExsUp+1D0Me<fXNO+ZNn2^JTZ0)_&`5IsL%z; zS%+k?XMuk5VJ{Qz1;Q?iC|Y8xmSw?yCnW=QiZV8FF+6~u{IwF%QRMTgXie&jE9!$Y zQ}8lq>*Gy^_w%MO#$`GeJ9b;6_k<7~%GL(4?FG2NlZ)}D=spn~+R4H)5M%=JSUl=5 z*M>{zyBnJW>$yli&>9?R(=81HqWWTrAUsID5#nHdd{EHB+A|?+IIA|KbJMp26|K}+ z9<9@E##UxB5v|$C6?{HaNf7ob!Z@48#ykT^C>Y=(EPT=*aPgsXh;?!#GDN{j{xWol zISWn`2x|D0g}cg!#%zdjnPUQ0Q7-e<y`|c=!Y!EYX@cq3YW=EY84DQ$xdy+Uu(Hya z6Lw>G@FA{w@W!X+Gj5*pd=YP3kYarv)eY-W$^^=o5%RiZbw5t-vK>F<`NF`AS{wMJ zXUVJSJ`tK?Cfu^#M4mo@Ly_so=`oz^%8NqXS{1zo&@pyI*$4JNV3&6MX7c6ShE^y@ zlC6R|Z$r7m@4Kb1UehV6$7RZu7#FfsYJ{TQ;y2;LaraEs4{7A}>=~&4>@oU3+fO~P zzI%ClH&8{HFi)s4zmwo;zogMQ@0$!w%k9fb@1kH1T<w9IbE1OB5$xQeod}__6g`j2 z1D(?1R^)z_9r6AU?bD()yYE{Sm}`ADKA#I|G+=B6@57NEWT$Clx=BTosn(tV5%%kV zG>8%ff51J0FmTe;eG(RtBr(NJwj^~FL`1=2ujbZ~>#MFqq&l4sZUmCo)5OqtiDEPq z(KRdNv!9LXtBlFqN!9A*-6y8s1S9&bsE2FoyCF@a!1eVqh_Mh5eQ|(AEHEXHJcsg2 zndx31yYC0?MJ^IlAWq*y|6mGVIWpXCPVGzP#}36o@~-w%;?3n9C8}HjgKr3rxbPD6 zV>~?F;JOmmr8L4Svg;g<9FErqEOv<d4*D26d#*;$VL(<=YM%w8YFlhlqvp0+mwl0n z#mtTx3EMLkI>Y-|+BS=)8J|esaNSh|Mjqr+nlfN6&HNb|(Ss9j9C!$mYf1P(<eM0} z1E6SwzrMgA+e5A`VD^Q#Tzl^T=wS)+4)OzjCx+4$kO0>js>}uO$czrrA^DUi<5bC3 z8$ZISCB~P#L!`uELZ)$teCCjTs~>jhd81>v`I11DaF}61<*iryHhTkx{^Yvgv{e+q zH~3a@qv2gvqbW5^R6SW5*J^tSntfpi`IaXpiRQJtyLjOLGMh9`#{vWe=7D+t{KYpL z_L_lV@&2BCe%x-Ay{suUyZ>_tLmnq2+!kP#Y?Sb)G-96aRVHQ;&&+Q`y0_VcSg<U3 zS!?|uE%rZmZJE`UBgc%tZ}6Y`3~AZ-k$sHD#YEVhkMi6f&cLy69i9NJJkh;jhU)Xe zuJK=hMM-Bkf*V6%F?xC{gI{6_*gdbfbFCN<#i}OZL_1$`lr-@t%D#TSX3vP6oPnI^ zT4Bz`lWqv!^K!?30sZHCm1gUff*1q<(E3xZV*Y!nYH4O|@z1*TPq~_;GH$)jh}d~f zgHG))R$4*+9lSOI-P9N0hKrpm>esBoh9u!ARv!J;EvXP+m6CO$pS}lgVqzkGD1jbZ z>}EtAWCq>2B4Ol9*MyqXyYPkJ@4j^doKd&HAG>~27#5CyaQ1*P&jG^OZlI;h7C>Qk zvF-lc+T!ybj^Uq>lm<5A<qaJ~yZ%<n0qLKltI-d_po7P_+w3veLjMC+kQ2nRNkGG# zlySriPbodcLRSRc6HJq=rE~({5Z-?#KZ65G>s`MNpa*ocX+_^eI|HmeM4-hE(olE* zEo1u|KPZm3cLA&e@r#OGP@G8IbY^K`-@ACSG~44hbDwpj;L;R&(lUup6+Ml5|3Y|| zaYh*x0rSW`Ho&%OE356-yCzjxJ72h6lqgwv-^Pc=qKeQaq1Fi^eeN%HT-+76IZ{F9 zy%)XGyhLzI0bf!-i1KZG%4Bu(V{_Q2Ps#u&E*0a;ci`&ww5C`c&7Tls9Z?Vc5#_Zw z_d!RG@GUagy}@M@SOXG$(sSy(l#w*iGMRb74|dE;Ol3`?8;9o=_wOc!64~jjX~%;` zP~9?6JtXT4NY1V=2t)~s3Onq(?T5pFg2qmkFe%g~J!8Ia#it8Z*aHf1={MguU|$w* ztq=?MEPgWWDzAr!yU)ld4qjPkGeZa*eC-wWK~**-PK8*cMOMp+Q7C_RHPU7izD^4* z&1&j2I!JF}I59oI0$K7VLt(4Nq0l9W@1_?0K$0E8wc@>b;Y(^RI45C+J_owMWPb#0 zq{!!W?n{vCr?^i)RCqDiP1vR1r(@1IRVt}i=Hls{>Ou^{SVIqf5x@ET;`-G9t6kT` zw;^&2UwCcnC0qqi9d)Xi6=l9?X{kPW?3-|EwTMr+lxq?2sGvj@!^m$~ndR2^NNsH= zZIkJelIL<JYh-sSsDiU}!kdQ@hLeSFu|f7cUOUN~q-eg=0hx5p|CCaTPegZY3jwBZ z{uGmZSi;5Yt1^WUcCUAH61~G76j$GkEnOzh&G&|?bQ+?MPY{p+%lf{yx#}_CBA)Hx zBqj20|KoH^b+mBk@3<l&@AP)~6IYn9007p%$CZ_Zp_%=^1y+&Dw#A>o@_y2>YYkkZ zb-lD83bJZsRBPdXW5n#Itm`zbD^iMIKKiwtWk_RZX#z7ZNqT(Mp|hQ(WUefjof2im zGVOr)pkfANX{NNOmi=~z3;kOYGtUsU30Y;KbDd`Xa)REnZAn2`UL3q0p8cgzCF5!0 z=KIW5c33!u!*eAq-uh*KH2lv!sL9fyDUy>Km!zZ06}Kvu@O<ULNWTziqDDcH9bMWk zyE8l7c?`<mylPjvL5M0NIX#SAld3AG+Q9-ctvh5#!eV-NT;DpWk86#bxgk2p$2--y zPQm+Yw|WOn$T&Hxs%n3Abp?gPGDN?3u#_JiOd7dI-}oUsRrcM8R5|yWP!vD{UGUTE z=8)-$Lj|55Lhe`$s^Ic-uqbe`Z%9h26ofaP0VG#wGa+g2pxY9(37weiDc_0$9pQ~p zJ!NbI(q*e%jqB6W(lCv8_?O1i>Tj+wyAByYadc_IQOm?l^iedq*;D(PVNp8Gcnyr( zvnZc5K@`*p(RS3Hmt?<ee0S<cPBkNTKV=^evw95bA-8RI&x$czd_7U#!^r_ql{N2u zpo0!c+Sl4b$D%>zkLg-L2R)jt-4aj9KbHoW&N{m57dtZevtrd*S!a+c=Dc-lXu6wj z4u8v76on9S49w7Enqx`m6C_cK|I+!w9MOZ9V{u?cK!@RdukYxvAt1;JE^VZ5M>=ZH z!dNXu-E+q4(+R30|9+L{i0eH8I>~j=U)Xu%3N=E-D-&0Ih>2WcFxIFFAqSET$E6Rf z?rn=eYS&>Gn73-BysY*+tqS|?yCyZ9wPR-4l_oAtf($jhnRh4s4pNEx$uTRlb!oi8 zyi@)m^Lz&w3T}Y4!c(}nx2_M|r1FMRrVUDYpPcEBE12ip^zzu0rR{F6!1FUcRb0yV z!nnwZQah$A_1$d*ajkZpJ%Na`YyX5S-m`)=`|qZ8-v=1RIVM$-m_ia*p7-C#VcjQb z9Jdf&10IF;6!$qC_3U-B4@!N!EO)sV786kgxrfjCE6_hX?T{v3*i}uc%?S)7Em?q_ z0u1_?uq_SA4vbCD<wTYZ8aNItb7BiBUk;*!S;G?=)`)g3Q+*|(Y4{8*FJ3v)hCwnU z4>pGKq7vU5_dm?#U>a>G=PKk3NX-gVwKe?}r>RUoc;;{!CJ6pB0}^uC(_upb0Am;c zz@OK@#2Q;O!+(!cwR7wJR<uu>dm>1PfE8`gQR9|DHY<PQdT|`W3|Qor4lwAEMxnt0 zvHX<6J=a-+JNS=v9zLCd7$(^{2Y7L9%kOEYkU+$WTm;h}ecaAB=OD?YO35)4mG!H= zF0D+M7j;Ea4oRKUhV=P|?zIq-80KwDw|07~K41OOG11*`&$~G{*De=Tl&eX!l6A&D zsS&pohimjoFQTrKrmXR10~O4`Y4nA9Hz{UBsq$&sc62f;8p@SB7CT05*|oqNV>`SI z^MXa{)KQD}Kh=9_<7*PV5#*H9py6n0sU7uF$4-Vhe`ImHS~?f$lC&T%SsM~dkdR-9 zn+CuPOPTSFeJ5nJUa3z%o}(2SJ33eGA<pekhE-u@xJ(Z_E<zsyP}$N(7|{!3*FpTb zK@TI=)eQ7D1oQ<i2&xdnw1T67hfM6Vx{SE+t5K>P84+MU@#Xe>`G`ee8x*6fIub7v zTiQOdzI?+wKy$r>^X0mBnaa&`#L;nbX5-HrrMRdV9oqqZIv5%$)bDcSo$Bh4F=$|+ zNPmQ`g0(3JI@k6gusE5}ZJHf|ZJQ*x@taqW%QQrfDhP}c+raV*SH|Z>!qK*Gl<-7A za$ZZ%q@hcuMO84hi@{8MA!6Uaj0*ODL`iO_P;1|8&?R=7MvhzAR;<Ra4^EWbWu81q zN5RUd`=?0^Fd<Ua#*Zt+{t7eUgxcOk0V2Ftr~vKs0~&y|9qRqw->z-TD0AyT#(HDG zJ^wSfp@EsA-%OPKO#}@XYmLBXip?IuQ(PDvAJ}t^10O5S1SMEscE^>aLQJ;CHQKm& zN~olz95%QoBpw(>y|-2==`A_U{8Vc=fUyZRo!Aig_oQq0o<+b^b|^Y>R-j7Z4P2oX zugF934zxVOw6@AHE8109xx%Mb7-kgQSRPrS`GW89AR!!ovyhO_TS6`U{p>p?RP&{R z{BVhU%dR#IWLJG~bR4=)thv%1qjhR5`4pAmYilaBLE1!me{WKPgoW*w=Oj9@Y*#~| z$=X_I4v5|5V5$wJ*Bt$CSn)+m-TTl2*gCwnj}QBSPC{`)0FN^2-b_dy2F-v-M2W{< zZ|$mOInB2WutYfM$a?>EL!yx!^V@prquAvrWlY2RixU#;PD0kO)fJP-BuM4ol(g=X zsaftV<#=U92n0)8+Ag3d)JGdu8?Zi}^njHgcFt<H{!SteX1W**-|`GLN6iB@*2BvA zmW%4;RL&CTle&rQCj@2!*%w@0Sp)t38U1!8v2S!NAmxj{RlC8y@|f>AK;WOTSLW0e zBt&a2#p*12veMR|mtx<?(8n#FUjbV!A)6D4lqh@Et$u&_jwCsLg-<Wu6kDNdgo6y~ z{}2jI-450zl#;@$%`4U7vfr>gVD4``Btlxig#GOiL?<9kihcljY*K5j6r;al)&fHb z-EqO^;H%<gGUUBVdq`C93pgsaF&2=j+&db~AYjESm}A7hYBLer^&)kPXKcxP(v(B2 zTQZFWw=Fk3wn^;pefRFgBT0~nQr-JLJr90$Srqe2bar`Nt)s|t;&`ojcIE{SJ4#EQ zWAb{hkzn<3!r5*TY~iw7!S<Tx!HCQAN;of@tpWe0n0=(Zt!6xbI-tvmSh<hNG4Hmj zx?<3TQ*-xm(tc*qZ{B<p0O7;mx2F2avIb<cJfr<wT><~xX48`A=d|iI30=2ODIFeF z7TOQR&`joF8~8LJnFF@Hr%KI%f1Yp&xhJ718h1|76I&}<Bge-g0|6GO(F4TrNLdrX zYWn1{Sv>I-V`jo^yU~A??nH-NG+*px3o<Y?vug-W9Vx#pFmqIns6nnxXz8wJc>-9X zWM%BwGTlc0`HCIgCkG135b_(OON;HSKP!{_w-$0uLeGL_aG4>S#c#a(u&xg(BW(78 z#_<wWRL_v3?u!$vzQ-m47SG<!?gIbS{9vMKtCPYQ?h_w5vToB{QdJ*s-QijGon9zq z;pYky?S<uCl;x0iYE42qj%5&(0%0&ZijzTK1Iy^2OkhT%QUWHF<M1yp{euq=ev~Ld z&Jx1Jde)hI{9_JH_68(U3HrkGI`up06e=gC5X{$&?hBna4fxnqWRdD}s=-D0#Z72e zBlb7@ZuCD030b^Afp%^{(cV4CNsy#B;)mm67!L$gA1zt0X9Qh9tq$TT7-{(7$&9{; zSpwHUufh3LknTYWnGl#QbD!qoJAShynWCo_*-cuyEU;3Uov=K^IgPfmV2ipYG*~_a zXj-M;397FlDX`#lxqKuYC#~4lMkh4Avr5<-37JlMLH4lcpt@)D;(gy0-O!YL)1ZeW zF%12BwCWi~_yP`(A^6nZhO$&D!v;%$`W@;vFB-}j@0nT6w}yel%^$UkZSviRC3hYP zmeJ++;K$)h;zz)2%y<sHb>CaelS>P`4-UH{SRha=UfH(y+huOi5{DoRkhCn5DSRdi z;XYdv$>bco9XOPgPt!Hs!(f`8%}o&2E=)a8heG=h;xsNp6?tkoO4UrR>-fp^!`<m` z8*<jKkVYB-iYmcW;*ITZv)bb491eXK5<sfA;xk@mJ0qL{5yeXfYiz<oTR|TK+me>J zx@~V=(F8g|ZxxqQOyTPuz=JNpn(T-|zHG-;M+gZ7&fu<#3#WK1_4UEZM1R~FWsHs` z#<YzMj$lp5M7*!&r*mqQIgT<Xu$rgfQzv1iGTp#kKZ+ckW~zfbhKBJB_AfUNFYkjU znm7FvT{xcqDknOEZn~hr004h9008^n%LxZNOEX8Kf2$}i)g)~;*buwVRS}_KC9BHU zCh1PrPH0L7gfjsA@~FV7=?}=o1FYh1U0>aT;qj%z-M9qqlt3g}cG(2SIPvP@^6|8q zi|xs=MuAB<M67v|WUf_27Ty$vy0TK=<iY$BW-0@n>6H*o+dME3ah(S3<@o^9-z{0% z3dr8ci(&(m>j@>s3DvNk%+4PIMhLu%p^@z=8ef2dvb;Ca2*R|#BE5y9kUj>;X7ras z!T4hx%28kLharl4Jw2y6gsKKxf8&2b7nRO1FX{^Y(%jSF=a8s7<ADRADdIoX4<p(N zgHD$Pt3)JI`IcoA2iz?&5`5+)aK9!5G`QDL`OSJ$sD&|os^kGDc=P?}Xy}K~TY)Y^ z5~W^H!}v3;8AJF}qCtIww<hIWfSV)Ly-1{*x&BBbJM6%v9*Y(xRql)doO;kYugdS_ zz1(^I3i;r&b%^2%k$Y1OGu1z$Y2;n6Ml+LHW5!B&;b8#N9VI>_Owy4SWvHA*y@G0{ zGJ?E;MXLtD25&NuF=w<-_>gR~Fc1HG_%A%-)QEC_Es|4MP3*8o1D5k1L1y+Jf;477 zCCLg?e1=zLXo5^e;-2JF4Y&!#S+w`EGo)2^`5FoI8ePD?Ui;kgnRFDfx;}_x;LV<s z_D?UA!}@thmK`-3y|)1hcn&2S=lqu|y8S1taUA`JP@eg;Y4}O9>kO=1%-m{bJVnS? zSW8)v?e-E!6(m=jaFYZU<h@9ava)tL((-LsOr;sr3Q$&V2Fw=mb`@Sz%5iBnQ^DF# zx9bKmD#A}6!CG+q=ThG5gJ>7uILIE7nG&Xz-7l>oO78ddFRB+gYNKQdn|^b*b>Eum zQ`v>mWSux$g|9Te$Wv&jn^po9Gg(g;{5kYPwak7*Niyj!F*6r!I?LixnGoiR!Y?bP zLe(Q-kfgXaK5R{xmLKgMHeJzWc<YoyS+mQ+&;r#K)qjwBaxx%BP9cmdD|KPC3)}sx z5~x?m6V-P$g$})90KXZWn7Z4d_9x6wU#@8OA0jCSIQrL=6eQi+Anmx>-Yq2p`(<Rz zYGQTDrc=W0z)@Xscc#>#Z4RZxBm^X)H6?>90A~s|-=b$I8)WU0)?wmBawx55lp0A{ z$e(m{0L7Uj-~I%on*$Dz=9+-1$b=o{{la4Fp~kqzeYls3EkX{R9prvGL=IX*zg9gn zJ(R4)INzsp^A#!+ymy^}O-$6^`gOm;Goly)t4GwbThY3v$0VC{y*pJ)`A5PI_Hy-x z#TKeh2AwguF;^_YuT3U<EZ)-t2c(z#?I?w)sd-_;T#84E`LLtsU9tHy(i+@~idV*V z$RuG@V47AmT*M4YV)Qaf4Mw_KXveeWGr>zrPMYT5oVa>mFt$!|=T3=m!DIR<JLQZc zOz&p#dQ+nbPD;_c0mo2C2#(8)Sq}EowP^U2kR6xdAeO`dZ7u}~BZ8hD>i({(0SQ;| z(juD?t&_!P^e6>V#!)7X6C2DfH6KT5n`_5cA6)~`OwP%i{$7NAKJ-eSmFUG;xnU&h z)xt+iO?j?xd(YaIlrQlp$M0LtwIz7nnJZr`m}FekzA48SKRR-TzrVa)zZ9%Kv9mEe z6^FpTa>TQTe|5i>$o^tDTb6k*B)Mdr=XSRI&IPMHkrVf1d-L+7<G<(2QD^lem7nR{ zMxe(E)&yc5M)%fB{N!HSm8<RP^>JZ^_67W(>#;Zzs8#Mi$_d9GMH1&fCQvu4|3{S6 zw3%l_^`5TbFvKR!4~!ZX2lE>MMP?)=|LrSxP)Jds%ue4dIQnaNSZ3pBPNt!J$!_Y9 zbGxlIDPD8ruKZh69~VUTrnr$Wnnw7L?p01fDQ8OiHdgl_Ww{vlc~d+?{f4J5HpY!K zwtG*~y0_J-9?-p)4VsYwIuh)%M_z1|Mop54yb^RV>$_=-|1!>x?nB^!i2EU|(EU^y z-y|{(GZH_3qr=?UPH(_vQv$o0F&RloeczbKgoX7j*DPf@*hQ*3Lr*0XP<8TCc^wfZ zg5!(yQWv`hMs5aPxgjX+WalL5cs&c`lW9W(d_c|p%D9Xz$fIJd{T*#5;YVfJOAh#5 zx)o9~8x_{-c%}#wx|oml7Z2#v7%!aaN-qc29z|P!IZ}R5adlj&QF)L=dG_pu*h=Z6 zT1v8V4TTsw;&lYaqy!Nw`EcFdFJu>Ro^3BBiSoK{gRLT>hja~6HSw+XzY;I!m`oAr zonTW?tl{a~`RLR?qE$nxf;F%SkpV$YhZl}E0Z^5y-?N<9Hr@&dWmXIxs55^BRb=ol zLL@MNR8vA;EGrEug$owJcr5+s(7uSYR}kx!%$-1_*)Rmj;tzf`8ZWkqF)Q8(t4%y! zkUm9ho?hCFk#B~F{DlY)5i^eM+05iyQ%Q&T_`Ju^C&3ofquST>))59LSrX9W&^#$V z;_MJF<AwMB;!c?DMabu8c%wavT=k?b9prqmn4qczTB5a?##+veR=5cu$^iXQ@gnBs zcxY%*$Pn%ZAW=++PZz>;FUjZ-->}l1Zq36IXP%c0daf)x4flFyLDvG|k>4asC0BJ< z`0YskdI*B6g)i<|7G`*a(7U`c|C>8}hD-)#KzokjfK^K;D~nEb^`SJwSP=Iq)>?wv zU|EFscaVT<?40s@Kqk7D>ayM$4XUXP(ekmVw4og`$F}K@C$6ZD2^8F`yKF55*nuge zAbs6WDFO(DPaA=2e#b8YXi1V)DvgyrC==&o)(5>rJh<wfUZNf(nCwd12>XxFtbMT~ zX|k9V?2?FJU*$aWtb~w5`y+E0U+9V!yHMj>5B$-nU!HAj*x9@;%fo;TGmS40IY}U3 zRFMDunEjv7`@fGuzkj^_vu^pXhwlGI{_QXSA0Plw=%?}LJpccW{5QAx-^jn+zW+iJ z{P`>YJMy32-@kc(`}O|CtNODY^1t)`$G!JA?Qc)jzi6s|rn3K?_J18#f5ZMZLH!GM z_g`WEv_$>Q``hL8FP=W`f9u?Tc%J@-{%v*o7qtH0p#N@s`kV0g4%EL0+JC%Q|GZ}m ze@*>=Q~uW5|3zt{{x{0s>igfAzs10RVRZg@(f+^A{HHYdH{|anz`r2XZ2t!Ne-;FP lbN<eR|KeP8{yXRY$%}H5VBr7wG2EZ$`kz#4#QTp={|9$s#W?@~ diff --git a/venv/share/python-wheels/msgpack-0.6.2-py2.py3-none-any.whl b/venv/share/python-wheels/msgpack-0.6.2-py2.py3-none-any.whl deleted file mode 100644 index b853ffd764257d3c2b9605da08994f921307cced..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 88193 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 K2*z4a0RI9Rx&<Tv diff --git a/venv/share/python-wheels/packaging-20.3-py2.py3-none-any.whl b/venv/share/python-wheels/packaging-20.3-py2.py3-none-any.whl deleted file mode 100644 index 904450446b9df9081bf92eef3f6b05ed07642990..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37509 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 diff --git a/venv/share/python-wheels/pep517-0.8.2-py2.py3-none-any.whl b/venv/share/python-wheels/pep517-0.8.2-py2.py3-none-any.whl deleted file mode 100644 index 1e63a69c59332682cc4ad0b8a8e7b894315a8795..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21951 zcmaI7Q<P>wx3!t5M5S$1+O}=mwr$(CZ9B8lw)v)Q+u3!-=<fe~r^o4wxY-wLuMvCC z6*Hb#Auk2`3k3)W2ofj*tW%z7-Y*Cp5eSGC4+x0x-&1=Ndlm*Z8hToGT1Hx93nyn9 z3tLk=Isp}BaXCdLT4#4>lMJpnA_>RQuTK<{ZA_-MFto6zA>T%PYsai^o=k^eW0gkA zPQ3BSYT`2Uvp+dx0`V05GlCb?hmh>z2!Cp_x512Oe1DxKouX?P&t@OSBPtA6PPu;` z;E(g^TwCX<<@wZ-`uW~Svdp(!pUa<FD|&V>#$;AgZk*Y)E|ol6Ix_lvTmcSkTHEuu zrO^QQ=hu#vkCfg|Z|Hh{C8Ql4%sO`1MWi9NO^cEnwtN%td-~pkxLzeuE3Oz_EIO=C z+u*AdI%oYCF=r6dEfcIks>mB5IS)QAMWiioDy@&MRYG-b+E&hK-7MVg8kjp~@D0%g zj2l7U=ZyC_ImXW`>72%74M{JorFGFWv{-FSyy4%xol8O|p90UbKkF*B7Gh5;9dqdh z%IY-~Pvmr7Icm0ME;-Iys3T^RmH1s7cr@F_Wwj4~#le}3q1)~}wI+$Msz__5X|2bq zR9UyqZ07*d8{3f!ou*@W(z;KzO<h8{_>I`O(GMl%+}?_!R1JtCVVA7W+cBBbv@tVr ztFD*ytVP_r;iXG0)kt4&VevT`rZ%0AlLVc&BfFc1OSYNnSRRqnrFo*|O}uDe0LQ{0 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 MTwh!0{Qc?w0FgceumAu6 diff --git a/venv/share/python-wheels/pip-20.1.1-py2.py3-none-any.whl b/venv/share/python-wheels/pip-20.1.1-py2.py3-none-any.whl deleted file mode 100644 index 4fbfb3da154999f6ed10a2ee353a137f38ba43f3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 285469 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 M111<sAQvM359hj$ga7~l diff --git a/venv/share/python-wheels/pkg_resources-0.0.0-py2.py3-none-any.whl b/venv/share/python-wheels/pkg_resources-0.0.0-py2.py3-none-any.whl deleted file mode 100644 index 1c5c09198a2f1bc1a07d5747c99b0e1fa50895f1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 122578 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 Hu7H05tAt4f diff --git a/venv/share/python-wheels/progress-1.5-py2.py3-none-any.whl b/venv/share/python-wheels/progress-1.5-py2.py3-none-any.whl deleted file mode 100644 index b795d93ed9a248550e59b5aea5dafd5a102b88ee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12812 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 E1FM$f;Q#;t diff --git a/venv/share/python-wheels/pyparsing-2.4.7-py2.py3-none-any.whl b/venv/share/python-wheels/pyparsing-2.4.7-py2.py3-none-any.whl deleted file mode 100644 index 375b386e2f819afef1ef45723008fb08015a929b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 72474 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 diff --git a/venv/share/python-wheels/requests-2.23.0-py2.py3-none-any.whl b/venv/share/python-wheels/requests-2.23.0-py2.py3-none-any.whl deleted file mode 100644 index 1d646c91dce75e74ac36152467fb32bc5194f347..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 63192 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 diff --git a/venv/share/python-wheels/resolvelib-0.3.0-py2.py3-none-any.whl b/venv/share/python-wheels/resolvelib-0.3.0-py2.py3-none-any.whl deleted file mode 100644 index 7b1a28acf42ef5cb214a5158b5d7331f892e778f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15663 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 D#pD5M diff --git a/venv/share/python-wheels/retrying-1.3.3-py2.py3-none-any.whl b/venv/share/python-wheels/retrying-1.3.3-py2.py3-none-any.whl deleted file mode 100644 index bcd789f8acca8d7cd17827b9c343fdbf38c1d163..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11621 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 Bz48D6 diff --git a/venv/share/python-wheels/setuptools-44.0.0-py2.py3-none-any.whl b/venv/share/python-wheels/setuptools-44.0.0-py2.py3-none-any.whl deleted file mode 100644 index e962ad5ec780971814cf1732e7957275b4778c2d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 472710 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%0D^DR3c2J)>d79?LQZ?iewk^+6H{Mfnt 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%0DvrH`b*o~p0=JY@)*QQle@4-K?Mr8Cvi-kAlV{zn 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 Btp5N2 diff --git a/venv/share/python-wheels/six-1.15.0-py2.py3-none-any.whl b/venv/share/python-wheels/six-1.15.0-py2.py3-none-any.whl deleted file mode 100644 index f8d49c6a103dc9788d2b288ac68c4cc87e084b3d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15549 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%0AFaC~KQ9}Siu(%fxy~wkEKB6YQcW)D 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 aSSkwAVE?7803iO^zyFb?s=5B_>VE+{=r3FV diff --git a/venv/share/python-wheels/toml-0.10.1-py2.py3-none-any.whl b/venv/share/python-wheels/toml-0.10.1-py2.py3-none-any.whl deleted file mode 100644 index bccd1ad7a2447014f69cfecaeda65562b8188f31..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20955 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 Q*C?_3DRw~k1pWQ&KkyWpx&QzG diff --git a/venv/share/python-wheels/urllib3-1.25.9-py2.py3-none-any.whl b/venv/share/python-wheels/urllib3-1.25.9-py2.py3-none-any.whl deleted file mode 100644 index 94fd9f7f0e383f3605fb607a060b8ed4d6a990ba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 123228 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 ZZ`qyKA|%><7Z3Qg3LZ2u90p?r@PDw(7$g7y diff --git a/venv/share/python-wheels/webencodings-0.5.1-py2.py3-none-any.whl b/venv/share/python-wheels/webencodings-0.5.1-py2.py3-none-any.whl deleted file mode 100644 index c4a86c103ffc06807cb1d3ff5579fc4afeba46cf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15749 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 Tfq<a@Txx%0Sm>Pp`1QX4IJ`|D diff --git a/venv/share/python-wheels/wheel-0.34.2-py2.py3-none-any.whl b/venv/share/python-wheels/wheel-0.34.2-py2.py3-none-any.whl deleted file mode 100644 index e6ac0091e21f4600b201b0929d99054c0f2e55d1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30875 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 Y67;WF?2iN*RDd#20D$GcqL%^w55=wCLjV8( From b1a28b9db698c127bf78f12416a279c238b2207d Mon Sep 17 00:00:00 2001 From: Adi Bozzhanov <kyoumabat@pop-os.localdomain> Date: Tue, 29 Jun 2021 03:24:33 +0100 Subject: [PATCH 09/17] feat: readme update --- README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/README.md b/README.md index fb195d0..e03d3b7 100644 --- a/README.md +++ b/README.md @@ -5,6 +5,21 @@ It can do all sorts of random things. Add it to your telegram group chat and some of the features will definitely brighten up your chatting experience. +# Getting Started + +From the main directory start the pipenv shell. + +`pipenv shell` + +Once in the shell, install dependencies. + +`pipenv install` + +Create `.env` file and set contents as following: +``` +BOT_TOKEN= // you token goes here +``` + # Contributing You can contribute to the pyuku bot in multiple ways. Generally, any sort of feature supported by a new command is very much pleased. From 3704897ca518b802ee2dd6d3a87ed59277593fec Mon Sep 17 00:00:00 2001 From: Adi Bozzhanov <kyoumabat@pop-os.localdomain> Date: Tue, 29 Jun 2021 03:26:18 +0100 Subject: [PATCH 10/17] feat: readme update --- README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index e03d3b7..d5dde6d 100644 --- a/README.md +++ b/README.md @@ -8,12 +8,14 @@ Add it to your telegram group chat and some of the features will definitely brig # Getting Started From the main directory start the pipenv shell. - -`pipenv shell` +``` +pipenv shell +``` Once in the shell, install dependencies. - -`pipenv install` +``` +pipenv install +``` Create `.env` file and set contents as following: ``` From 19fb910bb78acd42b35ac5836406ef1c23b658bb Mon Sep 17 00:00:00 2001 From: Adi Bozzhanov <kyoumabat@pop-os.localdomain> Date: Tue, 29 Jun 2021 03:26:53 +0100 Subject: [PATCH 11/17] feat: readme update --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d5dde6d..047007a 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ pipenv install Create `.env` file and set contents as following: ``` -BOT_TOKEN= // you token goes here +BOT_TOKEN= //your token goes here ``` # Contributing From c04d2924cb0496c81d45404fc784fc3d12d3e62e Mon Sep 17 00:00:00 2001 From: Adi Bozzhanov <kyoumabat@pop-os.localdomain> Date: Tue, 29 Jun 2021 03:40:46 +0100 Subject: [PATCH 12/17] feat: readme update --- README.md | 11 ++++++++++- src/run.py | 1 - 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 047007a..bc8377d 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ It can do all sorts of random things. Add it to your telegram group chat and some of the features will definitely brighten up your chatting experience. # Getting Started - +## Dependencies From the main directory start the pipenv shell. ``` pipenv shell @@ -17,11 +17,20 @@ Once in the shell, install dependencies. pipenv install ``` +## Environment Create `.env` file and set contents as following: ``` BOT_TOKEN= //your token goes here ``` +# Run + +From the `PyukuBot/src` directory +``` +pipenv run python3 run.py + +``` + # Contributing You can contribute to the pyuku bot in multiple ways. Generally, any sort of feature supported by a new command is very much pleased. diff --git a/src/run.py b/src/run.py index acf9839..139698c 100644 --- a/src/run.py +++ b/src/run.py @@ -2,7 +2,6 @@ import os from pyuku import Pyuku - if __name__ == "__main__": env = os.environ if "BOT_TOKEN" in env: From 9baa6379736fa57f9d64c3d54adbd66b162dac71 Mon Sep 17 00:00:00 2001 From: Adi <bozzhanov.at@gmail.com> Date: Tue, 29 Jun 2021 03:42:00 +0100 Subject: [PATCH 13/17] readme update --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index bc8377d..3ecf393 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,6 @@ BOT_TOKEN= //your token goes here From the `PyukuBot/src` directory ``` pipenv run python3 run.py - ``` # Contributing From 5824479bb42d6226bacfaef7239d261382d84ca6 Mon Sep 17 00:00:00 2001 From: Adi <bozzhanov.at@gmail.com> Date: Tue, 29 Jun 2021 03:42:29 +0100 Subject: [PATCH 14/17] readme update --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3ecf393..6208b81 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Create `.env` file and set contents as following: BOT_TOKEN= //your token goes here ``` -# Run +## Run From the `PyukuBot/src` directory ``` From faffd1c3d5ec725852ab5bb4cc8f4354c07a2574 Mon Sep 17 00:00:00 2001 From: Adi <bozzhanov.at@gmail.com> Date: Tue, 29 Jun 2021 03:44:02 +0100 Subject: [PATCH 15/17] feat: readme update --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6208b81..28e2d38 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ pipenv install ``` ## Environment -Create `.env` file and set contents as following: +`/PyukuBot/.env` file: ``` BOT_TOKEN= //your token goes here ``` From 4197cd08b43e276633b63de1c5b076d5924493e7 Mon Sep 17 00:00:00 2001 From: Adi <bozzhanov.at@gmail.com> Date: Tue, 29 Jun 2021 03:45:05 +0100 Subject: [PATCH 16/17] feat: readme update --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 28e2d38..b200f68 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ pipenv install ## Environment `/PyukuBot/.env` file: ``` -BOT_TOKEN= //your token goes here +BOT_TOKEN= /* put your token here for testing */ ``` ## Run From 752c2acdc85cccacfde1841d8a61be52488e6832 Mon Sep 17 00:00:00 2001 From: Adi Bozzhanov <bozzhanov.at@gmail.com> Date: Sat, 18 Sep 2021 19:19:19 +0100 Subject: [PATCH 17/17] stuff --- Pipfile | 2 +- Pipfile.lock | 44 ++++++++++++++++++++------------------------ 2 files changed, 21 insertions(+), 25 deletions(-) diff --git a/Pipfile b/Pipfile index 65f9554..a7632ab 100644 --- a/Pipfile +++ b/Pipfile @@ -10,4 +10,4 @@ requests = "*" [dev-packages] [requires] -python_version = "3.8" +python_version = "3.9" diff --git a/Pipfile.lock b/Pipfile.lock index ff0eb22..3990bb7 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,11 +1,11 @@ { "_meta": { "hash": { - "sha256": "77aaff997ff5dda7155bc4abafcf3ce732b8448ce27e814db976d194d7c05292" + "sha256": "60357ddbdb31438d647403628575c898327cf880391f35376d65b4809e986080" }, "pipfile-spec": 6, "requires": { - "python_version": "3.8" + "python_version": "3.9" }, "sources": [ { @@ -28,7 +28,6 @@ "sha256:2cc0b89715337ab6dbba85b5b50effe2b0c74e035d83ee8ed637cf52f12ae001", "sha256:61b5ed1e22a0924aed1d23b478f37e8d52549ff8a961de2909c69bf950020cff" ], - "markers": "python_version ~= '3.5'", "version": "==4.2.2" }, "certifi": { @@ -38,29 +37,29 @@ ], "version": "==2021.5.30" }, - "chardet": { + "charset-normalizer": { "hashes": [ - "sha256:0d6f53a15db4120f2b08c94f11e7d93d2c911ee118b6b30a04ec3ee8310179fa", - "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5" + "sha256:5d209c0a931f215cee683b6445e2d77677e7e75e159f78def0db09d68fafcaa6", + "sha256:5ec46d183433dcbd0ab716f2d7f29d8dee50505b3fdb40c6b985c7c4f5a3591f" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'", - "version": "==4.0.0" + "markers": "python_version >= '3'", + "version": "==2.0.6" }, "idna": { "hashes": [ - "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6", - "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0" + "sha256:14475042e284991034cb48e06f6851428fb14c4dc953acd9be9a5e95c7b6dd7a", + "sha256:467fbad99067910785144ce333826c71fb0e63a425657295239737f7ecd125f3" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", - "version": "==2.10" + "markers": "python_version >= '3'", + "version": "==3.2" }, "python-telegram-bot": { "hashes": [ - "sha256:37cfe8faba16fb68a8b5ab41a10e787c385f6296200c84256cc54d7c16334643", - "sha256:d4b3a8fd6a927bc6dc498fa00e8d6388570d089f5c015418c3b2b954e0719a7a" + "sha256:24df75459e335b96baffa6991679f844bd426978af5a69ca419a0ac43a40602c", + "sha256:3bf210862744068aa789d5110f8e3a00d98912ce50863384836440a18abf76b5" ], "index": "pypi", - "version": "==13.6" + "version": "==13.7" }, "pytz": { "hashes": [ @@ -71,18 +70,17 @@ }, "requests": { "hashes": [ - "sha256:27973dd4a904a4f13b263a19c866c13b92a39ed1c964655f025f3f8d3d75b804", - "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e" + "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24", + "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7" ], "index": "pypi", - "version": "==2.25.1" + "version": "==2.26.0" }, "six": { "hashes": [ "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926", "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'", "version": "==1.16.0" }, "tornado": { @@ -129,22 +127,20 @@ "sha256:fa2ba70284fa42c2a5ecb35e322e68823288a4251f9ba9cc77be04ae15eada68", "sha256:fba85b6cd9c39be262fcd23865652920832b61583de2a2ca907dbd8e8a8c81e5" ], - "markers": "python_version >= '3.5'", "version": "==6.1" }, "tzlocal": { "hashes": [ - "sha256:643c97c5294aedc737780a49d9df30889321cbe1204eac2c2ec6134035a92e44", - "sha256:e2cb6c6b5b604af38597403e9852872d7f534962ae2954c7f35efcb1ccacf4a4" + "sha256:c736f2540713deb5938d789ca7c3fc25391e9a20803f05b60ec64987cf086559", + "sha256:f4e6e36db50499e0d92f79b67361041f048e2609d166e93456b50746dc4aef12" ], - "version": "==2.1" + "version": "==3.0" }, "urllib3": { "hashes": [ "sha256:39fb8672126159acb139a7718dd10806104dec1e2f0f6c88aab05d17df10c8d4", "sha256:f57b4c16c62fa2760b7e3d97c35b255512fb6b59a259730f36ba32ce9f8e342f" ], - "markers": "python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4' and python_version < '4'", "version": "==1.26.6" } },